GIT 36f021b579d195cdc5fa6f3e2bab198b4bf70643 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

commit 215d06780d13fd7de629b02b61b7b7bf88ce5039
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Tue May 8 11:37:26 2007 +0200

    Fix sunrpc warning noise
    
    Commit c5a4dd8b7c15927a8fbff83171b57cad675a79b9 introduced the following
    compiler warnings:
    
    net/sunrpc/sched.c:766: warning: format '%u' expects type 'unsigned int', but argument 3 has type 'size_t'
    net/sunrpc/sched.c:785: warning: format '%u' expects type 'unsigned int', but argument 2 has type 'size_t'
    
      - Use %zu to format size_t
      - Kill 2 useless casts
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 74add80cbd7fe246c893b93ee75ac59acdd01dd4
Author: Roland McGrath <roland@redhat.com>
Date:   Tue May 8 11:19:38 2007 -0700

    Remove unused variable in get_unmapped_area
    
    Signed-off-by: Roland McGrath <roland@redhat.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit be3478ddb8a3902b588c840b42e166a0e64a87b3
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:40:22 2007 -0700

    sm501fb printk warning fixes
    
    drivers/video/sm501fb.c: In function 'sm501fb_cursor':
    drivers/video/sm501fb.c:992: warning: format '%08x' expects type 'unsigned int', but argument 3 has type 'long unsigned int'
    drivers/video/sm501fb.c:992: warning: format '%08x' expects type 'unsigned int', but argument 4 has type 'long unsigned int'
    
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 147394c8ece44be85d692cc92cc0d047e4d8fb69
Author: Andrei Konovalov <akonovalov@ru.mvista.com>
Date:   Tue May 8 00:40:18 2007 -0700

    xilinxfb: xilinx framebuffer device driver
    
    Add support for the video controller IP block included into Xilinx ML300 and
    ML403 reference designs.
    
    Signed-off-by: Andrei Konovalov <akonovalov@ru.mvista.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 435d56fcd45cdf32bfb4db5d4e1efe17f3da95b2
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:40:16 2007 -0700

    pm2fb: fix of jumps in pm2fb_probe
    
    This patch fixes incorrect targets of jumps when an error occurs in the
    pm2fb_probe.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 19c1a8b3122e7b2007cfd2836da2318816f324cc
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:40:14 2007 -0700

    skeletonfb: improvements
    
    This patch adds a macro to register PCI ids table and corrects type of
    xxxfb_fix variable to avoid modpost warnings.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4560daaf07ab68bef5e70355d1565b2e0a1a3bcf
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:40:12 2007 -0700

    pm2fb: removal of pm2fb_par fields
    
    This patch removes two redundant fields in the pm2fb_par structure.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4c7bf38699aed591b6624add40acfa71fe6d902c
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:40:10 2007 -0700

    skeletonfb: more corrections
    
    More corrections to skeletonfb.c file:
    - fixed types of more arguments
    - removed returned values in void functions
    - removed not existing fb_poll function
    - fixed closing comment typo
    - corrected misleading constant name ADDR
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Acked-By: James Simmons <jsimmons@infradead.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7e645ffd83f987c8650e9dd0f22a0c57296ed458
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:40:08 2007 -0700

    vga16fb: actually support widths in multiples of 8
    
    vga16fb does not just support 8-pixel wide rectangles, but rectangles with
    widths in multiples of 8.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2ae854777592856ad8ce4d4cdb6114804e2e28f6
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:40:06 2007 -0700

    vgacon: disallow console operations when in KD_GRAPHICS mode
    
    Reported by James Pearson as:
    
    	 boot to run level 3
    
    	 if not root, then make sure /dev/console is writeable
    
    	 login and type:
    
    	 setterm -blank 0
    
    	 start X
    
    	 type into an xterm:
    
    	 while true; do echo "" > /dev/console; usleep 100000; done
    
    	 while the above loop is running switch to the text console and back
    	 again (Ctrl-Alt-F1 then Ctrl-Alt-F7)
    
    	 ... and the screen will be shifting (and wrapping) to the left.
    
    This problem stems from continuously writing text to the system console (which
    is in KD_TEXT mode) while the foreground console is in KD_GRAPHICS
    mode. Somewhere along the way, console printing got confused and omitted the
    KD_GRAPHICS/KD_TEXT test.  Thus, vgacon attempted to scroll the screen of X,
    which causes X to shift.
    
    Fix by disallowing vgacon to touch the hardware when the vc is in KD_GRAPHICS
    mode. A definitive fix entails a full audit of the console code.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 32dd38030b3b4ca0aa18a5402059de27bf69ed6b
Author: Jan Engelhardt <jengelh@gmx.de>
Date:   Tue May 8 00:40:04 2007 -0700

    Use menuconfig objects II: video/logo
    
    Change Kconfig objects from "menu, config" into "menuconfig" so that the user
    can disable the whole feature without having to enter the menu first.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 87a7cc685a847800482db1fd74504b9b4b42264e
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:40:02 2007 -0700

    pm2fb: accelerated fillrect and copyarea
    
    This is a port of accelerated functions from 2.4 kernel.  Only fillrect and
    copyarea are accelerated.  Fillrect is not accelerated in 24-bit mode.
    
    [adaplas]
    Add appropriate flags
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 34ed25f50b347c7e1ff78f9308e025ddd57c2f20
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date:   Tue May 8 00:40:00 2007 -0700

    s3fb: updates
    
    Move s3fb_get_tilemax to svgalib.c as svga_get_tilemax, because it reports
    limitation of other code from svgalib (svga_settile, svga_tilecopy, ...)
    
    Limit font width to 8 pixels in 4 bpp mode.
    
    Signed-off-by: Ondrej Zajicek <santiago@crfreenet.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9a31f0f7679aeaf79c613feaa3f4170741ccb218
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:39:57 2007 -0700

    pm2fb: memclock setting corrections
    
    This patch disables a memory clock setting if a board has been initialized by
    BIOS.  This allows using the memory clock set by manufacturer of the board.
    
    This patch also sets default clock for 3dlabs Permedia 2V reference board's
    clock to 75MHz (BIOS setting for EONtronic Permedia 2Vboard), because the
    default 83MHz can be too high.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 76c7d3ffe3acddf5619bd796e0b8fa5dc6ecdb39
Author: krzysztof.h1@wp.pl <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:39:56 2007 -0700

    pm2fb: reset transparency settings
    
    This patch resets transparency settings when depth changes.  Otherwise the 16
    and 24-bit modes work incorrectly after switching from 32-bit mode.
    
    Signed-off-by: Krzysztof Helt < krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 167f07f1bc20ea1ab51d833deb0c18f5ab93618f
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:54 2007 -0700

    fbcon: check console-fb mapping in fbcon_get_requirement
    
    - Check the console-to-fb mapping in fbcon_get_requirement(), otherwise the
      value returned may not be valid for the driver.
    
    - Minor cleanup
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b1e7223f28b4ed5073d2029a3597bf514ff514f2
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:52 2007 -0700

    fbdev: clean up exit patch of fb_set_var
    
    Clean up exit patch of fb_set_var():
    
    - consolidate all return values into a single local variable
    - ensure that return values are valid error codes
    - fix fb_set_var() returning success when fb_check_caps() failed
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0959f0ca29244ae983b406fba313816a29244be7
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:39:50 2007 -0700

    drivers/video/sis/: remove more kernel 2.4 code
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Cc: Thomas Winischhofer <thomas@winischhofer.net>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c831c338f0ad299fcd1592c6e4f30657480f39af
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:39:49 2007 -0700

    use mutex instead of semaphore in virtual console driver
    
    The virtual console driver uses a semaphore as mutex.  Use the mutex API
    instead of the (binary) semaphore.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 159dde93692ef549a0b2012c9f25feb4df638c9c
Author: Ville Syrjala <syrjala@sci.fi>
Date:   Tue May 8 00:39:47 2007 -0700

    atyfb: halve XCLK with Mobility and 32bit memory
    
    Laptops with Rage Mobility and 32bit memory interface seem to require halved
    XCLK to operate correctly.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b4e124c138558a0cff51398ddff9a8e44ed0b529
Author: Ville Syrjala <syrjala@sci.fi>
Date:   Tue May 8 00:39:45 2007 -0700

    atyfb: reorganize clock init
    
    Reorganize atyfb clock init code so command line clock overrides are effective
    for all chips.  The old code would silently ignore some of the command line
    clock overrides with some chips.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 94f45bcd1c29e773b6bf189ef7b9a3437d016320
Author: Ville Syrjala <syrjala@sci.fi>
Date:   Tue May 8 00:39:44 2007 -0700

    atyfb: increase SPLL delay
    
    Wait 5 ms instead of 500 us for the SPLL to lock.  This matches the
    recommendation in mach64 programmer's guide.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2620c6e31735248ac26403558bd4279a8af619d8
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:42 2007 -0700

    nvidiafb: fix return value of nvidiafb_open()
    
    Fix return value of nvidiafb_open().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0449359f053829ec89c026b5fb80bbe7190a5fe8
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date:   Tue May 8 00:39:41 2007 -0700

    vga: vgastate fix
    
    1) sets 'palette access disabled' during read from AR10.
       This is usually documented as needed for access AR01-AR0F,
       but on ARK Logic card it is needed for AR10 (otherwise read
       returns some nonsence and save_vga_text() returns before do
       anything).
    
    2) do not restore AR10, because it was not changed during
    
    3) remove modification of misc reg:
            /* force graphics mode */
            vga_w(state->vgabase, VGA_MIS_W, misc | 1);
    
       as comment is misleading - LSB of misc reg does not set/reset graphics
       mode, but set color/mono adresses of CRT and some other regs.
       but these regs are not used during save/restore fonts.
       (it worked even when (misc | 1) was replaced by (misc & ~1) ).
    
    Signed-off-by: Ondrej Zajicek <santiago@crfreenet.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 56c7554938e5945b770365e326f0c3d031ca231f
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:39 2007 -0700

    s3fb: implement fb_get_caps
    
    Implement fb_get_caps().  This will allow the driver to tell upper layer that
    it can only support 256 8x16 bitmaps when in tileblitting mode
    (var->bits_per_pixel == 0);
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 38a3dc51852d8350b156ea909c5aa8767d71b005
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:37 2007 -0700

    fbdev: fbcon: check if mode can handle new screen
    
    Check if the mode can properly display the screen.  This will be needed by
    drivers where the capability is not constant with each mode.  The function
    fb_set_var() will query fbcon the requirement, then it will query the driver
    (via a new hook fb_get_caps()) its capability.  If the driver's capability
    cannot handle fbcon's requirement, then fb_set_var() will fail.
    
    For example, if a particular driver supports 2 modes where:
    
    mode1 = can only display 8x16 bitmaps
    mode2 = can display any bitmap
    
    then if current mode = mode2 and current font = 12x22
    
    fbset <mode1> /* mode1 cannot handle 12x22 */
    fbset will fail
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e15de77e74d429f14641ebe7a29ccd8aa6656f3c
Author: Dave Jones <davej@redhat.com>
Date:   Tue May 8 00:39:35 2007 -0700

    nvidiafb: prevent triggering of softlockup
    
    If the chip locks up, we get into a long polling loop,
    where the softlockup detector kicks in.
    See https://bugzilla.redhat.com/bugzilla/attachment.cgi?id=151878
    for an example.
    
    [adaplas]
    Chip lockup can occur at 3 points (flush, sync, and wait). Consolidate and
    allow the driver to go to safe mode cleanly.
    
    Signed-off-by: Dave Jones <davej@redhat.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d4a96b53125c3d31266c05f2a8432d956dd26141
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:39:33 2007 -0700

    pm2fb: pixclock setting restriction
    
    This patch adds restrictions to calculations of m, n and p factors
    which sets the pixclock for the Permedia 2V. I found during tests
    that synchronization is unstable if m (divisor) is bigger than
    half of the n (numerator). The patch disallows such settings
    combination.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e5d809d774fc8aa76899bde3235afb046728feed
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:39:32 2007 -0700

    pm2fb: Permedia 2V memory clock setting
    
    Permedia 2V uses its own registers to set a memory clock. The
    patch adds these registers and uses them in the set_memclock()
    function.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f1c15f938d810b5eb38c85a28e5e9d2af07d135a
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:39:30 2007 -0700

    pm2fb: 3dlabs Permedia 2V reference board added
    
    This patch adds support for 3dlabs Permedia reference board.
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d37363409bacd1142c6e49edfb3e1f8b153d47dc
Author: Alan Cox <alan@redhat.com>
Date:   Tue May 8 00:39:28 2007 -0700

    nvidiafb/rivafb: switch to pci_get refcounting
    
    Switch to pci_get refcounting APIs
    
    [adaplas]
    Fix a long-standing bug where the return value of
    pci_find_slot()/pci_get_bus_and_slot() is ignored.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dbe7e429fedb3fbc93b496cc1c3eb4fc28333ac0
Author: Alan Hourihane <alanh@fairlite.demon.co.uk>
Date:   Tue May 8 00:39:25 2007 -0700

    vmlfb: framebuffer driver for Intel Vermilion Range
    
    Add the Intel Vermilion Range framebuffer support.
    
    Signed-off-by: Alan Hourihane <alanh@tungstengraphics.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 249bdbbf0dbab5554a4bfe55639e324d4758da96
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date:   Tue May 8 00:39:24 2007 -0700

    s3fb: driver fixes
    
    This fixes broken fbcon on Virge VX in 24 bpp mode, and contains several
    other small updates.
    
    Signed-off-by: Ondrej Zajicek <santiago@crfreenet.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4941cb7a18fd84d4d8cd097d2beada3c79c8f781
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:22 2007 -0700

    fbdev: save the activate field before calling fb_check_var()
    
    Some drivers may reset the var->activate field on fb_check_var(). This can
    lead to undefined behavior. For example, doing fbset -a <option> with vga16fb
    will only modify the active console instead of modifying all.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 38b4982c6388ae9596f959e3d7fef91affbd181d
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:19 2007 -0700

    fbcon: check if the character count can be handled
    
    Fontmaps can be 256 or 512 in length. The only driver that can do tileblitting
    can only handle 256 characters.  Check for this when setting the font.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ff388ad05bc67163124ac74126bbc16faa2fb771
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:17 2007 -0700

    s3fb: implement fb_get_tilemax()
    
    Implement fb_get_tilemax(). It just returns 256.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 11f11d522f74965fce421a5a09ff0ab178139d36
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:16 2007 -0700

    fbdev: add tile operation to get the maximum length of the map
    
    Add a tile method, fb_get_tilemax(), that returns the maximum length of
    the tile map (or font map).  This is needed by s3fb which can only handle
    256 characters.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8db51668f5ef6ae31ed4e4f0c6e2976a190dfa11
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:14 2007 -0700

    s3fb: limit 8x16 rectangles when tileblitting is enabled
    
    If tileblitting is enabled (text mode), the hardware can only accept 8x16
    bitmaps. Advertise this to the upper layer. And to ensure that an appropriate
    font is always available, select an 8x16 font in Kconfig.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d60d2d8a423be91c5ad1a745c4e9dda9cea1b3c5
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:12 2007 -0700

    vga16fb: restrict to blit rectangles with widths of multiples of 8 pixels
    
    Advertise that vga16fb can only handle widths that are 8-pixel-multiple only
    (software limitation). To ensure that a legal font is available, SELECT an
    8x16 font in Kconfig.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2d2699d984924890f6dac8cf51c3b6311f56816c
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:11 2007 -0700

    fbcon: font setting should check limitation of driver
    
    fbcon_set_font() will now check if the new font dimensions can be drawn by the
    driver (by checking pixmap.blit_x and blit_y).  Similarly, add 2 new
    parameters to get_default_font(), font_w and font_h, to further aid in the
    font selection process.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bf26ad72a60c0009a99179b449a43daa6bf4b4f6
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:09 2007 -0700

    fbdev: advertise limitation of drawing engine
    
    A few drivers are not capable of blitting rectangles of any dimension.
    vga16fb can only blit 8-pixel wide rectangles, while s3fb (in tileblitting
    mode) can only blit 8x16 rectangles.  For example, loading a 12x22 font in
    vga16fb will result in a corrupt display.
    
    Advertise this limitation/capability in info->pixmap.blit_x and blit_y.  These
    fields are 32-bit arrays (font max is 32x32 only), ie, if bit 7 is set, then
    width/height of 7+1 is supported.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dc0e6e0544f1cb2af44e5d7a7e68acda05dec6fa
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:08 2007 -0700

    fbdev: consolidate common drawing functions into a header file
    
    Consolidate common drawing functions into a single header file.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 52102c07a68a26fe6f8926e6a8497b577655f18a
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:07 2007 -0700

    vfb: use fb_sys_read() and fb_sys_write()
    
    Since vfb's framebuffer is vmalloc'ed, use the fb_sys_read() and
    fb_sys_write().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28d4564bfd28e9fc9fe33695c431e3c3601faeb4
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:06 2007 -0700

    hecubafb: use fb_sys_read()
    
    Since hecubafb's framebuffer is vmalloc'ed, use fb_sys_read().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d9a05f18e00882d5c1fad400a90532754afba9bf
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:04 2007 -0700

    arcfb: use fb_sys_read()
    
    Since arcfb's framebuffer is vmalloc'ed, use the fb_sys_read().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 09aaf268eb1d22eee690d26a913f660e2081597f
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:03 2007 -0700

    fbdev: add fb_read/fb_write functions for framebuffers in system RAM
    
    The functions fb_read() and fb_write in fbmem.c assume that the framebuffer
    is in IO memory.  However, we have 3 drivers (hecubafb, arcfb, and vfb)
    where the framebuffer is allocated from system RAM (via vmalloc). Using
    __raw_read/__raw_write (fb_readl/fb_writel) for these drivers is
    illegal, especially in other platforms.
    
    Create file read and write methods for these types of drivers.  These are
    named fb_sys_read() and fb_sys_write().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3f9b0880e4a96b02bc0131451f2f6231cd90bd94
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:02 2007 -0700

    fbdev: pass struct fb_info to fb_read and fb_write
    
    It is unnecessary to pass struct file to fb_read() and fb_write() in struct
    fb_ops. For consistency with the other methods, pass struct fb_info instead.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Acked-by: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 87b4884935d387acc4c4418da6a75387bfcc24b9
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:01 2007 -0700

    vfb: use sys instead of cfb drawing functions
    
    Since vfb's framebuffer is vmalloc'ed, use the sys_* drawing functions
    instead of cfb_*.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d6774935b61f99024121107d4ebb9d11b58052e6
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:39:00 2007 -0700

    hecubafb: use sys instead of cfb drawing functions
    
    Since hecubafb's framebuffer is vmalloc'ed, use the sys_* drawing functions
    instead of cfb_*.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 922e6f9afa137ac69624389b1939e6c31b1abf2d
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:58 2007 -0700

    arcfb: use sys instead of cfb drawing functions
    
    Since arcfb's framebuffer is vmalloc'ed, use the sys_* drawing functions
    instead of cfb_*.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 68648ed1f58d98b8e8d994022e5e25331fbfe42a
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:57 2007 -0700

    fbdev: add drawing functions for framebuffers in system RAM
    
    The generic drawing functions (cfbimgblt, cfbcopyarea, cfbfillrect) assume
    that the framebuffer is in IO memory.  However, we have 3 drivers (hecubafb,
    arcfb, and vfb) where the framebuffer is allocated from system RAM (via
    vmalloc). Using _raw_read/write and family for these drivers (as used in
    the cfb* functions) is illegal, especially in other platforms.
    
    Create 3 new drawing functions, based almost entirely from the original
    except that the framebuffer memory is assumed to be in system RAM.
    These are named as sysimgblt, syscopyarea, and sysfillrect.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a42dc9d4804cc5e111952008492dae9d34c6a541
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:55 2007 -0700

    skeletonfb: documentation error fixes
    
    Documentation error fixes.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 55ff9780e7cedc9168dab4d42483c70011c53ace
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:53 2007 -0700

    vt: add documentation for new boot/sysfs options
    
    Add description to Documentation/kernel-parameters.txt on new options
    default_blue, default_grn, default_red, and default_utf8.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1f92fea9c63be2071e88fb600dcfb50af1a6d2ca
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:52 2007 -0700

    i810fb: fix incorrect frequency mask
    
    Fix a long-standing bug.  The mask used to detect a 100Mhz or 133Mhz chipset
    is incorrect. (The only side effect of this bug is that it will choose an
    incorrect watermark).
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28cdf76bf0bce757428f84161e3aa510028d47b4
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:50 2007 -0700

    hecubafb: kill sparse warnings
    
    The framebuffer memory is allocated from system RAM (vmalloc'ed).  Add __force
    annotations.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 75814d87a976cc12675024c0a03e3ac3369465a0
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:49 2007 -0700

    s3fb: add sparse annotations
    
    Add sparse annotations and use fb_read/fb_write and family to access the
    framebuffer.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d2e8d369cd92a8bb856ff530fa1e4c03b0e0ff55
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:47 2007 -0700

    arcfb: kill sparse warning
    
    The framebuffer memory is allocated from system RAM (vmalloc'ed). Add __force
    annotations.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 78494dd3442cf6ac5562f684c7073db2818d3afd
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:46 2007 -0700

    fbdev: add sparse annotations in svgalib.c
    
    Add sparse annotations and use fb_read/fb_write family to access the
    framebuffer.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 98a1153acdc2256f866599be701439577da77db3
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:44 2007 -0700

    fbdev: kill sparse warning in deferred IO
    
    Kill the following in fb_defio.c:
    
    drivers/video/fb_defio.c:40:43: warning: incorrect type in argument 1 (different address spaces)
    drivers/video/fb_defio.c:40:43:    expected void *addr
    drivers/video/fb_defio.c:40:43:    got char [noderef] *screen_base<asn:2>
    
    The framebuffer memory of these types of devices are allocated from system
    RAM.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 895bf69b8f24907f0efa11d8e84a7eac8e47bdac
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:43 2007 -0700

    rivafb: fix IO access
    
    Fix IO access, with the following sparse warnings:
    
    drivers/video/riva/fbdev.c:320:25: warning: dereference of noderef expression
    drivers/video/riva/fbdev.c:321:29: warning: dereference of noderef expression
    drivers/video/riva/fbdev.c:327:18: warning: dereference of noderef expression
    drivers/video/riva/fbdev.c:328:15: warning: dereference of noderef expression
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6cf059e1bb3c7aa56f2a4468136934863184ef51
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:41 2007 -0700

    nvidiafb: fix sparse warning
    
    Fix the following sparse warning:
    
    drivers/video/nvidia/nv_setup.c:659:20: warning: dereference of noderef expression
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 95d67bb1ca82dc8bd75304bda891e7ad81ecd935
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:40 2007 -0700

    fbcon: delay screen update when setting the mode of all consoles
    
    If the current framebuffer console is rotated (rotate != 0), doing an
    "fbset -a" will corrupt the current console.  Fix by updating the current
    console only after all non-visible consoles have been updated.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b2f594fd7adff7aae2d1664e72044926b0b906aa
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:38 2007 -0700

    fbdev: link vgastate.o using Kconfig
    
    Instead of directly linking vgastate.o by individual drivers, create a Kconfig
    option VGASTATE which can be 'SELECT'ed by individual drivers instead.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 22d832edcace45b26ced76efef6c863449e4e060
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:36 2007 -0700

    savagefb: VGA state save and restore
    
    Allow the saving and restoration of VGA text mode.  The state is saved on the
    first open and restored on the last close. Because of the VGA registers are
    linearly mapped to the MMIO space, MMIO access is used which is not limited to
    X86 platforms nor to the primary display device.
    
    An echo 0 > /sys/class/vtconsole/vtcon1/bind will convert the display from
    graphics to text mode.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f7829158bce2c8180bf7a1cb922cad812d3a2788
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:34 2007 -0700

    savagefb: rework i2c bit access
    
    Use already defined VGAwCR/VGArCR functions to access the i2c bus.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7dfe50b3aac2b3500139ab10a6e228d34fed9a49
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:33 2007 -0700

    nvidiafb: VGA state save and restore
    
    Allow the saving and restoration of VGA text mode.  The state is saved on the
    first open and restored on the last close.  Because of the non-linear mapping
    of the VGA registers to the MMIO space, this will be done only on X86
    platforms where the device is the primary display.
    
    An echo 0 > /sys/class/vtconsole/vtcon1/bind will convert the display from
    graphics to text mode.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 19f3d3a5546be431f3846d8a8581e7a2f169dba3
Author: Roland Stigge <stigge@antcom.de>
Date:   Tue May 8 00:38:31 2007 -0700

    epson1355fb.c: fix error handling code
    
    Fix error handling code
    
    Signed-off-by: Roland Stigge <stigge@antcom.de>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c930faaed551aac898c618a7df1d68901ff244f0
Author: Richard Knutsson <ricknu-0@student.ltu.se>
Date:   Tue May 8 00:38:29 2007 -0700

    cirrusfb: convert to generic boolean
    
    Convert to generic boolean.
    
    Signed-off-by: Richard Knutsson <ricknu-0@student.ltu.se>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 88b229c7f714e5385bbf5be031beb3866efeb272
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:38:27 2007 -0700

    VIDEO: add spaces on either side of the case "..." operator
    
    Following the programming advice laid down in the gcc manual, make
    sure the case "..." operator has spaces on either side.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 36cc535b852bd59d04c43fe8e4c05c7da46bc625
Author: Krzysztof Helt <krzysztof.h1@wp.pl>
Date:   Tue May 8 00:38:25 2007 -0700

    skeletonfb: various corrections
    
    This is mainly correction of types, typos and missing characters in the
    skeletonfb.c file found while trying to prepare a new fb driver.
    
    [adaplas]
    Additions on power management and fixes as per akpm
    
    Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e296927bcc910ffa9e171c0108a4bf74c0836553
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:24 2007 -0700

    nvidiafb: access CRT registers safely
    
    Use Read/WriteCrtc() to access CRTC registers in nv_i2c.c.  These are safer
      because it uses the correct CRTC base (0x3bx or 0x3dx).
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b9b2696de920e7366e2ce0cdc3b3b7fc11e44e99
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:23 2007 -0700

    nvidiafb: ensure that CRTC registers are accessible
    
    - Ensure that CRTC registers are accessible by unlocking them on set_par(),
      otherwise i2c reading will fail.
    
    - The function nvidia_vga_protect(), does not protect the VGA registers, but
      turns off the screen.  Rename it to nvidia_screen_off().
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0404384982b2f71eb00573c8f9da514106aca08c
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:22 2007 -0700

    rivafb: fixed reversed DDC ports
    
    Fixed reversed DDC port so assignments are congruent with nvidiafb's and X's
    nv driver.
    
    Signed-off-by: Antonino Daplas <adaplas@pol.net>
    Cc: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a65ff76ac8b24df49bbf4acc38918fb52d1033b0
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 00:38:20 2007 -0700

    rivafb/nvidiafb: Various cleanups
    
    Various cleanups to rivafb/nvidiafb's I2C code:
    * Drop useless par->bus.
    * Refactor I2C bus deletion code.
    * Drop useless variable initialization.
    * Remove unneeded include of <linux/i2c-id.h>.
    * Simplify +1/-1.
    * Add __devinit tags where possible.
    
    [adaplas]
    The varible initialization are not useless. However, rivafb must
    check if i2c bus are created properly before reading the EDID
    block.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5b358fe12f03a7822db6f376b608f996c664a952
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 00:38:18 2007 -0700

    rivafb: handle I2C bus creation failure
    
    I2C bus creation may fail, let rivafb handle that case properly.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1e73db2536695ef95458b0043234456eb42a8962
Author: Jean Delvare <khali@linux-fr>
Date:   Tue May 8 00:38:15 2007 -0700

    rivafb/nvidiafb: Enable hardware monitoring
    
    Let the hardware monitoring drivers probe the second rivafb/nvidiafb I2C bus
    for devices.
    
    Signed-off-by: Jean Delvare <khali@linux-fr>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 70802c60379fb843c485dfd4cab9e8f527d8fe81
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:14 2007 -0700

    fbdev: don't show logo if driver or fbcon are modular
    
    It was always intended for the logo to be drawn only if both fbcon and the
    driver that is mapped to it are both compiled statically.  Currently, if fbcon
    is loaded prior to the driver, the logo is not shown.  Reverse the order, and
    the code may attempt to draw the logo which is __initdata.  By accident, this
    bug is rarely seen because this method of loading the modules is not common
    and secondly, a code in fb_prepare_logo() that checks the height of the logo
    (now a random value) rarely succeeds.
    
    Fix by drawing the logo only if both fbcon and the driver are statically
    compiled.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Cc:  Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6314db4110ad79cc666faff2209ed2691259afd9
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:38:11 2007 -0700

    s3fb: fix PCI must_checks
    
    drivers/video/s3fb.c:1078: warning: ignoring return value of 'pci_enable_device', declared with attribute warn_unused_result
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 042f10ec6533e53181284c96d22ae051e49ac707
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:38:09 2007 -0700

    vt: expose system-wide UTF-8 default setting via sysfs
    
    Create a variable, default_utf8, that defines the system-wide default UTF-8
    setting.  This variable can be altered via sysfs. If the variable is properly
    set, this should mimimize breakage of UTF-8 encoded consoles when doing a
    reset or echo -e '\033c' and of newly opened/allocated consoles.
    
    This is based from patches by Jan Engelhardt and Paul LeoNerd Evans.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Cc: Jan Engelhardt <jengelh@linux01.gwdg.de>
    Cc: Paul LeoNerd Evans <leonerd@leonerd.org.uk>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d1e2306681ad3cbbe63a2bfcc37ac22a21b0f0eb
Author: Michal Januszewski <spock@gentoo.org>
Date:   Tue May 8 00:38:07 2007 -0700

    fbcon: don't draw cursor when it's disabled
    
    When the cursor and echo are disabled on the current console, pressing a
    key will cause a black rectangle to be painted in the cursor's position.
    Fix this by not touching the framebuffer in fbcon_cursor() when the
    cursor is off.
    
    Signed-off-by: Michal Januszewski <spock@gentoo.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 31990a9d2ed02cb7552e05bb8a99872df9fd04da
Author: WANG Cong <xiyou.wangcong@gmail.com>
Date:   Tue May 8 00:38:06 2007 -0700

    SIS USB2VGA Warning fix
    
    drivers/usb/misc/sisusbvga/sisusb_con.c:1436: warning: initialization from incompatible pointer type
    
    Signed-off-by: WANG Cong <xiyou.wangcong@gmail.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cf36a65b08969d3cff3c1c878b7e0fdf148379b7
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:38:05 2007 -0700

    vt-add-color-support-to-the-underline-and-italic-attributes-fix
    
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fa6ce9ab5fbcb4c276c48861584b70d387e787b3
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Tue May 8 00:38:04 2007 -0700

    vt: add color support to the "underline" and "italic" attributes
    
    Add color support to the "underline" and "italic" attributes as in
    OpenBSD/NetBSD-style (vt220) and xterm.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Acked-by: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1c2bbe6a11ec7d1de114acfc8a6bf2821b0224a5
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Tue May 8 00:38:03 2007 -0700

    vt: allow for the palette to be exposed and changed via sysfs
    
    Allow for the palette to be exposed and changed via sysfs.  A call to
    /usr/bin/reset will slurp the new definitions in for the current console.
    
    Already posted at http://lkml.org/lkml/2006/1/15/149
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2707cd016b12d5e64c4feefcb5740b65f0c46845
Author: Petr Vandrovec <vandrove@vc.cvut.cz>
Date:   Tue May 8 00:38:02 2007 -0700

    nvidiafb: Fix reversed DDC port
    
    After I added some debugging printks I've found that code became a bit
    confused because it believed that primary monitor is 1920x540, but later it
    found in CRTC0's registers that panel size is 1920x1200 (Windows also agree
    that 1920x1200 is primary monitor, and 1920x1080i secondary one).
    
    When I applied attached patch then my monitor became as happy as it was
    before I connected HDMI cable to secondary output.
    
    Signed-off-by: Petr Vandrovec <vandrove@vc.cvut.cz>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Cc: Dave Airlie <airlied@linux.ie>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dd1447134454b169d5ae353aceb93f2368db8547
Author: johan henriksson <jhn98032@gmail.com>
Date:   Tue May 8 00:37:59 2007 -0700

    radeonfb: Add support for Radeon xpress 200m
    
    Added support for radeon xpress 200m(rs480).  Note that the card doesn't
    like dynclk turned on.
    
    Signed-off-by: Johan Henriksson <jhn98032@gmail.com>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit abed5d15af4cf864b502b5b0402c7fb39c5c3371
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Tue May 8 00:37:57 2007 -0700

    fbdev: correct image offsets when rotating logo
    
    Correct the image offsets when rotating the logo.  Before image->dx and
    image->dy were always zero, so nobody ever noticed.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Acked-By: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 448d479747b85eb2e284c29622d31f5485db6819
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Tue May 8 00:37:56 2007 -0700

    fbdev: fb_do_show_logo() updates
    
    fb_do_show_logo() updates:
      - Use width and height of the passed image instead of the global variable
        fb_logo
      - Explicitly pass the number of logos to draw
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Acked-By: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 250038f5a7207796fb54aff3dc686d664659cf0c
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Tue May 8 00:37:53 2007 -0700

    fbdev: avoid vertical overflow when making space for the logo
    
    fbcon_prepare_logo(): Avoid vertical overflow when making space for the logo
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Acked-By: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 538c79248c0dc1a4a37d92254a571bd62f6eb7f2
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:37:51 2007 -0700

    remove unused header file: drivers/video/riva/nv4ref.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28b230ed71df88a3b2df58e3f177c3c7be1753b9
Author: James Simmons <jsimmons@infradead.org>
Date:   Tue May 8 00:37:50 2007 -0700

    tgafb accelerated code
    
    Add accelerated panning and accelerated color and mono image drawing.
    Please apply.
    
    Signed-off-by: James Simmons <jsimmons@infradead.org>
    Acked-by: Maciej W. Rozycki <macro@linux-mips.org>  (tested, too!)
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 86c6f7d08b2868ba7cc1ef509c76ee9e9266af40
Author: Maciej W. Rozycki <macro@linux-mips.org>
Date:   Tue May 8 00:37:48 2007 -0700

    tgafb: TURBOchannel support
    
    This is support for the TC variations of the TGA boards (properly known as
    SFB+ or Smart Frame Buffer Plus boards).  The 8-plane SFB+ board uses the
    Bt459 RAMDAC (unlike its PCI TGA counterpart, which uses the Bt485), so
    bits have been added to support this chip as well.
    
    Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: James Simmons <jsimmons@infradead.org>
    Acked-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9a268a629be4c15ed85c88a61d712d92aa943847
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:37:45 2007 -0700

    drivers/video/hecubafb.c: make 4 functions static
    
    This patch makes the following needlessly global functions static:
    - hcb_wait_for_ack()
    - hcb_wait_for_ack_clear()
    - apollo_send_data()
    - apollo_send_command()
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Cc: Jaya Kumar <jayakumar.lkml@gmail.com>
    Cc: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit aad09e51eeb6ec68029271642a7528ffc08fee81
Author: Jaya Kumar <jayakumar.lkml@gmail.com>
Date:   Tue May 8 00:37:43 2007 -0700

    fbdev: hecuba Framebuffer Driver
    
    This patch implements support for the E-Ink/hecuba display device.  It uses
    deferred IO support.
    
    [akpm@linux-foundation.org: linker section fixes]
    Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5e841b88d23d0ea0a6ee4e76c489899d4d23ce25
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Tue May 8 00:37:41 2007 -0700

    fb: fsync() method for deferred I/O flush.
    
    There are cases when we do not want to wait on the delay for automatically
    updating the "real" framebuffer, this implements a simple ->fsync() hook
    for explicitly flushing the deferred I/O work.  The ->page_mkwrite()
    handler will rearm the work queue normally.
    
    (akpm: nuke unneeded ifdefs, forward-delcare struct dentry)
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>
    Cc: Jaya Kumar <jayakumar.lkml@gmail.com>
    Acked-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7bf1ea33ad70cf49638092367d52859fbbc44fee
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:37:38 2007 -0700

    make fb_deferred_io_mkwrite() static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Cc: Jaya Kumar <jayakumar.lkml@gmail.com>
    Cc: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 60b59beafba875aef6d378078bce0baf2287ae14
Author: Jaya Kumar <jayakumar.lkml@gmail.com>
Date:   Tue May 8 00:37:37 2007 -0700

    fbdev: mm: Deferred IO support
    
    This implements deferred IO support in fbdev.  Deferred IO is a way to delay
    and repurpose IO.  This implementation is done using mm's page_mkwrite and
    page_mkclean hooks in order to detect, delay and then rewrite IO.  This
    functionality is used by hecubafb.
    
    [adaplas]
    This is useful for graphics hardware with no directly addressable/mappable
    framebuffer. Implementing this will allow the "framebuffer" to be accesible
    from user space via mmap().
    
    Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3a2842480bbef42c3c90e14c1f378360d8c20a0c
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:34 2007 -0700

    atyfb: kill dead code
    
    Coverity Bug 68, kill dead code.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 41988d6e601fc6addef40421c57763a846d8ab1c
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:31 2007 -0700

    neofb: fill transp->msb_right with the correct value
    
    Fill transp->msb_right with the correct value.  fbcon ignores this, but user
    apps may not.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c4270637ff379163d22721b897f0dc5592794c68
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:30 2007 -0700

    fbdev: fix obvious bug in show_pan()
    
    show_pan will display the value of the xoffset twice, instead of the xoffset
    and yoffset.  Fix.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 464bdd33e9baad9806c7adbd8dfc37081a55f27e
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:29 2007 -0700

    fbdev: ignore VESA modes if framebuffer is disabled
    
    If the option vga=<VESA graphics mode> is added to the boot parameter, it will
    activate graphics mode, but without any framebuffer support, the user is left
    with an unusable display.
    
    Change the behavior such that the user is instead prompted for another mode
    (ala vga=ask).
    
    NOTE: People can always use vbetool to set a graphics mode if this is really
    desired, but the number of people doing this approaches zero.
    
    Signed-off-by: Antonino Daplas <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 66fd14120edea89d353fac0649e9ec0045ec958f
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:27 2007 -0700

    nvidiafb: bring back generic ddc reading
    
    Make nvidiafb use fb_ddc_read().  This patch was submitted before but was
    reverted due to problems in a non-x86 platform.  This includes a fix for that
    where ddc reading is bypassed if there is no DDC bus (duh).
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 71c6efd9930bd87249d007120425341d1293303d
Author: Orczykowski, Juergen <juergen.orczykowski@siemens.com>
Date:   Tue May 8 00:37:25 2007 -0700

    intelfb: fix ring space calculation
    
    If there is less than RING_MIN_FREE available in the ring buffer,
    dinfo->ring_space is set to a big value forcing wait_ring to return.
    
    Fix by making ring space = 0 if ring space < RING_MIN_FREE.
    
    Signed-off-by: Dave Airlie <airlied@gmail.com>
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 33a9f640a2511155517d316e696654b84dd48654
Author: Antonino A. Daplas <adaplas@gmail.com>
Date:   Tue May 8 00:37:23 2007 -0700

    fbdev: add Ultrasharp UXGA to broken monitor database
    
    This particular monitor does not have a limits block and has only one set of
    monitor timings.  Fix by adding a limits block to the EDID and extend the
    horizontal sync frequency range to 30 kHz and 75 Khz.
    
    Signed-off-by: Antonino Daplas <adaplas@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3b769be9c0ae2355afdbf356863a87dc739be59c
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:37:21 2007 -0700

    make drivers/video/display/display-sysfs.c:display_class static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Cc: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2ee121631b9dd0291502ccac6f897907505faf8c
Author: James Simmons <jsimmons@infradead.org>
Date:   Tue May 8 00:37:15 2007 -0700

    fbdev: display class
    
    Add the new display class.  This is meant to unite the various solutions to
    display units ie acpi output device, auxdisplay and the defunct lcd class
    in the backlight directory.
    
    Signed-off-by: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 825d0a97f3b9031235b1ee77b1e22fec15c758ba
Author: Prarit Bhargava <prarit@redhat.com>
Date:   Tue May 8 00:37:10 2007 -0700

    change rivafb_remove to __devexit
    
    Change rivafb_remove to __deviexit to fix MODPOST warnings:
    
    WARNING: drivers/video/riva/rivafb.o - Section mismatch: reference to
    .exit.text:rivafb_remove from .data.rel.local after 'rivafb_driver' (at offset 0x28)
    
    Signed-off-by: Prarit Bhargava <prarit@redhat.com>
    Acked-by: James Simmons <jsimmons@infradead.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 125e1137cd2d93377028f521801d916729485733
Author: Witold Filipczyk <witekfl@poczta.onet.pl>
Date:   Tue May 8 00:37:07 2007 -0700

    aty128fb: fix blanking
    
    I have a problem with blanking. The soundcard uses speakers of the monitor.
    Sound is muted when the screen blanks due to a bug in aty128fb.c.
    
    Here is a fragment of linux/fb.h
    /* VESA Blanking Levels */
    #define VESA_NO_BLANKING        0
    #define VESA_VSYNC_SUSPEND      1
    #define VESA_HSYNC_SUSPEND      2
    #define VESA_POWERDOWN          3
    
    enum {
            /* screen: unblanked, hsync: on,  vsync: on */
            FB_BLANK_UNBLANK       = VESA_NO_BLANKING,
    
            /* screen: blanked,   hsync: on,  vsync: on */
            FB_BLANK_NORMAL        = VESA_NO_BLANKING + 1,
    
            /* screen: blanked,   hsync: on,  vsync: off */
            FB_BLANK_VSYNC_SUSPEND = VESA_VSYNC_SUSPEND + 1,
    
            /* screen: blanked,   hsync: off, vsync: on */
            FB_BLANK_HSYNC_SUSPEND = VESA_HSYNC_SUSPEND + 1,
    
            /* screen: blanked,   hsync: off, vsync: off */
            FB_BLANK_POWERDOWN     = VESA_POWERDOWN + 1
    };
    
    So FB_BLANK_NORMAL is 1, FB_BLANK_VSYNC_SUSPEND is 2,
    FB_BLANK_HSYNC_SUSPEND is 3, FB_BLANK_POWERDOWN is 4.
    And now:
    blank = FB_BLANK_NORMAL (1)
    blank & FB_BLANK_HSYNC_SUSPEND (1 & 3) is true,
    so normal blank caused hsync suspend and sound is muted.
    
    Cc: James Simmons <jsimmons@infradead.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c8e1693a4f63e317966f3dfe8f815eda95e26610
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:37:05 2007 -0700

    Char: cyclades, copyright and version changes
    
    - add copyright
    - move version one number upper and use MODULE_VERSION
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3137553d3f78f12a077459ee59e4b17f8db9f0cf
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:37:04 2007 -0700

    Char: cyclades, probe cleanup
    
    - add fail paths
    - merge 3 similar initializations into one (Z, Ze, Y)
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dd025c0c7a047b1be7dfaa4061368b4783d89ebb
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:37:02 2007 -0700

    Char: cyclades, dynamic ports
    
    and save thus approx. 160k of .bss
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f2462bfe558559c9fbc4ef60812d5df30ccb01f6
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:37:01 2007 -0700

    Char: cyclades, fix tty device unregister
    
    put_tty_driver after unregistering devices
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f742903424aae3fc7ea7079a3618d90634c0b301
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:59 2007 -0700

    Char: cyclades, conditions cleanup
    
    - 0 is not NULL
    - use unlikely to hit the icache in isr more likely
    - remove or comment empty if/else paths
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9fa1b3b185a802fa0b3f764ad468efd64e1b582e
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:57 2007 -0700

    Char: cyclades, remove locking macros
    
    and use locally stored card structure if possible
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6a0aa67b177a3d84f789f7f19c523d8c5e8bb5f8
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:55 2007 -0700

    Char: cyclades, remove unused timestamps
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3991428d9efc7185312196f82cc36e9df4a2ddb0
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:54 2007 -0700

    Char: cyclades, timers cleanup
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ce71b0ffd01b0917a74c03562aaa110a71a0ee29
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:53 2007 -0700

    Char: cyclades, fix blockmove
    
    tty has no longer flip buffers accessible externally. Fix it by moving the
    code to the tty_*flip* helpers.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2c7fea992104b5ca2b510d585a27b3ba018b795f
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:51 2007 -0700

    Char: cyclades, remove sleep_on
    
    convert to wait_* and completion
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 875b206b5f4971cc990a12e891f5519f0f6772a9
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:49 2007 -0700

    Char: cyclades, make info->card a pointer
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6d8248e850309c0f05beb5bdbfc89b7901bf3d85
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:47 2007 -0700

    Char: cyclades, get rid of phys addresses
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3046d50ea58676759453faeefccf57fbc9b72a90
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:46 2007 -0700

    Char: cyclades, simplify variables initialization
    
    - do not init static variables to 0
    - simplify cy_init_card -- use memset(0) and do not zero each element
      separately, also reorder init, so that same entries are inited at one
      place
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 31b4f0a118a7ade8444059ec898af8f07de206e9
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:44 2007 -0700

    Char: cyclades, mark cyy_init_card as __devinit, not __init
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 217191910c0286e0b3c7e3011630273695253da3
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:42 2007 -0700

    Char: cyclades, printk cleanups
    
    - add printk KERN_ levels to each printk
    - substitute printk with dev_* when device struct is available
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 80fada50ec10172ef655882701f1c8abadd87d57
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:41 2007 -0700

    Char: cyclades, irq is int
    
    don't fetch it to uchar
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 46039f8a64cd50bbf70ce54fefe148e75598391b
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:40 2007 -0700

    Char: cyclades, remove useless fileds from cyclades_card
    
    pde, ctl_phys and base_phys are useless -- they are never used.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b81cc310f1309f6090a5655af1fe5831ded53233
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:38 2007 -0700

    Char: cyclades, unexport struct cyclades_card
    
    Do not export internal card data to userspace. cytune doesn't use this
    anyway.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cff9494fadb09e851b66096e3fd6fc08721bd683
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:36 2007 -0700

    Char: cyclades, depends on PCI or ISA
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6747cd93f3ed6e60b4e851b5985d038ac0b88742
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:34 2007 -0700

    Char: cyclades, switch to pci probing
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c2ad4c75154d98c07d30493e4906e1cd0a9162a5
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:32 2007 -0700

    Char: cyclades, use IS_CYC_Z macro
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 73b52572ab2eda9ea904d61e82f88c9a0e7aff41
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:29 2007 -0700

    Char: isicom, use pr_debug
    
    isicom, use pr_debug
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9e40210272465e348eb9c2bb5ffe1d11c91bfa19
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:28 2007 -0700

    Char: mxser, schedule for removal
    
    mxser, schedule for removal
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f1e83c6c1e7b97ac11d88502c3e5b80cdac9a683
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:24 2007 -0700

    Char: cyclades, allow DEBUG_SHIRQ
    
    Test if base addr is non-null in ISR to prove the card has been correctly
    initialized.  This is needed for DEBUG_SHIRQ for example.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 85c93fa95b8fa8dabc6d14c77eb9a9c2e9753ecc
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:23 2007 -0700

    Char: cyclades, clear interrupts before releasing
    
    Without this patch, the driver sometimes causes "IRQXX: Nobody cares".  Fix it
    by turning off irqs when releasing.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6ad1ccc196f76833f41b187e01a28a024fe11f8b
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:22 2007 -0700

    Char: cyclades, tty_register_device separately for each device
    
    Do not register all tty devices at the init time, delay it for the time until
    some device is found.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9dacf3b2f0cc657a5621e7f6d67ed27ce598f405
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:20 2007 -0700

    Char: cyclades, cy_init error handling
    
    - do not panic if tty_register_driver fails
    - handle fail paths properly
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 14a55a6789d8409e58329310f9a18fc141deb4c2
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:18 2007 -0700

    Char: cyclades, remove some global vars
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f3851e73ecdd070bc379677ed7aad958446f26e7
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:16 2007 -0700

    Char: cyclades, init card struct immediately
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0809e2671d804f6caa8b3bd5e4de4b52f649cf73
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:14 2007 -0700

    Char: cyclades, move card entries init into function
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 58936d8d944e27b75c99b1c59cfeea3f253b03cb
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:13 2007 -0700

    Char: cyclades, create cy_pci_probe
    
    Move probing code to separate function for easy pci probing conversion.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2b1da41fb3eb41fab1e27cdcce7712b61ef45186
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:12 2007 -0700

    Char: cyclades, init Ze immediately
    
    There will be no other choice after introducing pci probing anyway.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 38d090932564140454e5a0bc915beca07d8a65a0
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:10 2007 -0700

    Char: cyclades, use pci_iomap/unmap
    
    fork remove code for pci -- move it to separate, new, function and don't care
    about pci in the former.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d407c78188c718c00e997ce7f8b8d45e92ee2dd6
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:36:09 2007 -0700

    Char: cyclades, create cy_init_Ze
    
    Move Ze init code into new cy_init_Ze, because we will need it in another
    place and it will make the code totally unreadable.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7e92b4fc345f5b6f57585fbe5ffdb0f24d7c9b26
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:36:07 2007 -0700

    x86, serial: convert legacy COM ports to platform devices
    
    Make x86 COM ports into platform devices and don't probe for them
    if we have PNP.
    
    This prevents double discovery, where a device was found both by
    the legacy probe and by 8250_pnp, e.g.,
    
        serial8250: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
        00:02: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
    
    This also means IRDA devices without a UART PNP ID will no longer be
    claimed by the serial driver, which might require changes in IRDA
    drivers and administration.
    
    In addition to this patch, you may need to configure a setserial init
    script, e.g., /etc/init.d/setserial, so it doesn't poke legacy UART
    stuff back in.  On Debian, "dpkg-reconfigure setserial" with the "kernel"
    option does this.
    
    To force the old legacy probe behavior even when we have PNPBIOS or
    ACPI, load the new legacy_serial module (or build 8250 static) with
    the "legacy_serial.force" option.
    
    [akpm@linux-foundation.org: fix makefiles]
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Keith Owens <kaos@ocs.com.au>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Matthieu CASTET <castet.matthieu@free.fr>
    Cc: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Matthew Garrett <mjg59@srcf.ucam.org>
    Cc: Ville Syrjala <syrjala@sci.fi>
    Cc: Russell King <rmk+serial@arm.linux.org.uk>
    Cc: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d0d4f69bb65a8c1c1430c577a583632709b874c6
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:36:05 2007 -0700

    smsc-ircc2: add PNP support
    
    Claim devices using PNP, unless the user explicitly specified device
    addresses.  This can be disabled with the "smsc-ircc2.nopnp" option.
    
    This removes the need for probing legacy addresses and helps untangle IR
    devices from serial8250 devices.
    
    Sometimes the SMC device is at a legacy COM port address but does not use the
    legacy COM IRQ.  In this case, claiming the device using PNP rather than 8250
    legacy probe means we can automatically use the correct IRQ rather than
    forcing the user to use "setserial" to set the IRQ manually.
    
    If the PNP claim doesn't work, make sure you don't have a setserial init
    script, e.g., /etc/init.d/setserial, configured to poke in legacy COM port
    resources for the IRDA device.  That causes the serial driver to claim
    resources needed by this driver.
    
    Based on this patch by Ville SyrjÃ¤lÃ¤:
        http://www.hpl.hp.com/personal/Jean_Tourrilhes/IrDA/ir260_smsc_pnp.diff
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Keith Owens <kaos@ocs.com.au>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Matthieu CASTET <castet.matthieu@free.fr>
    Cc: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Matthew Garrett <mjg59@srcf.ucam.org>
    Cc: Ville Syrjala <syrjala@sci.fi>
    Cc: Russell King <rmk+serial@arm.linux.org.uk>
    Acked-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 916f11c760fc1c835d3fe10bebc97a02e2ac6b41
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:36:02 2007 -0700

    smsc-ircc2: tidy up module parameter checking
    
    To determine whether the user specified a module parameter, use some #defines
    instead of checking for bare magic numbers.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Keith Owens <kaos@ocs.com.au>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Matthieu CASTET <castet.matthieu@free.fr>
    Cc: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Matthew Garrett <mjg59@srcf.ucam.org>
    Cc: Ville Syrjala <syrjala@sci.fi>
    Cc: Russell King <rmk+serial@arm.linux.org.uk>
    Cc: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a1e7e636fe9fff531a4fc42e65c8e8416fde5220
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:36:00 2007 -0700

    PNP: workaround HP BIOS defect that leaves SMCF010 device partly enabled
    
    Some HP/Compaq firmware reports via ACPI that the SMCF010 IR device is
    enabled, but in fact, it leaves the device partly disabled.
    
    HP nw8240 BIOS 68DTV Ver.  F.0F, released 9/15/2005 is one BIOS that has this
    problem.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Keith Owens <kaos@ocs.com.au>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Matthieu CASTET <castet.matthieu@free.fr>
    Cc: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Matthew Garrett <mjg59@srcf.ucam.org>
    Cc: Ville Syrjala <syrjala@sci.fi>
    Cc: Russell King <rmk+serial@arm.linux.org.uk>
    Cc: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8f81dd149806bc53c68c92f34d61f88427079039
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:35:54 2007 -0700

    PNP: notice whether we have PNP devices (PNPBIOS or PNPACPI)
    
    This series converts i386 and x86_64 legacy serial ports to be platform
    devices and prevents probing for them if we have PNP.
    
    This prevents double discovery, where a device was found both by the legacy
    probe and by 8250_pnp.
    
    This also prevents the serial driver from claiming IRDA devices (unless they
    have a UART PNP ID).  The serial legacy probe sometimes assumed the wrong IRQ,
    so the user had to use "setserial" to fix it.
    
    Removing the need for setserial to make IRDA devices work seems good, but it
    does break some things.  In particular, you may need to keep setserial from
    poking legacy UART stuff back in by doing something like "dpkg-reconfigure
    setserial" with the "kernel" option.  Otherwise, the setserial-discovered
    "UART" will claim resources and prevent the IRDA driver from loading.
    
    This patch:
    
    If we can discover devices using PNP, we can skip some legacy probes.  This
    flag ("pnp_platform_devices") indicates that PNPBIOS or PNPACPI is enabled and
    should tell us about builtin devices.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Keith Owens <kaos@ocs.com.au>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Matthieu CASTET <castet.matthieu@free.fr>
    Cc: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Matthew Garrett <mjg59@srcf.ucam.org>
    Cc: Ville Syrjala <syrjala@sci.fi>
    Cc: Russell King <rmk+serial@arm.linux.org.uk>
    Cc: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cab9bdd14dd7d8091b0aac7877ae9f29724eb741
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:35:51 2007 -0700

    Char: cyclades, remove useless casts
    
    cyclades, remove useless casts
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ad39c3004971173baeca80173e77022ee03eb9a1
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:35:49 2007 -0700

    Char: cyclades, remove volatiles
    
    cyclades, remove volatiles
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b70509066cba24067757f1422c899c43e433429d
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:35:48 2007 -0700

    Char: cyclades, timer cleanup
    
    cyclades, timer cleanup
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit db05c3b1ddaa06e658548f3d99e31a188b0b3bcc
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:35:46 2007 -0700

    Char: cyclades, cy_readX/writeX cleanup
    
    cyclades, cy_readX/writeX cleanup
    
    - cy_readX are placeholders for readX, remove it
    - move cy_writeX macros into do {} while(0) to be safe
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ffa68e79ffa952ec909b66505f004e7323316369
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:35:43 2007 -0700

    Char: cyclades, remove PAUSE
    
    cyclades, remove PAUSE
    
    PAUSE expands to do {} while (0), it's useless.
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b30fabadae2b3c1a65e3662be98f105d5718db70
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:39 2007 -0700

    Add IRQF_IRQPOLL flag on arm
    
    Add IRQF_IRQPOLL for each timer interrupt.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 57501c70747fd6d7b14f7863126e5a75d29613b1
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:36 2007 -0700

    Add IRQF_IRQPOLL flag on parisc
    
    Add IRQF_IRQPOLL to the timer interrupt on parisc.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: Grant Grundler <grundler@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e9485baed07561e516690671343622e5fcd73b48
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:34 2007 -0700

    Add IRQF_IRQPOLL flag on sh
    
    Add IRQF_IRQPOLL on each timer interrupt on SH2.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d217c265dc60ebfaa05ca003e9873476382de225
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:31 2007 -0700

    Add IRQF_IRQPOLL flag on IA64
    
    Add IRQF_IRQPOLL for the timer interrupt on IA64.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b34942fed0ada53ecd2d6bb27509319ec41e3e44
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:29 2007 -0700

    Add IRQF_IRQPOLL flag on i386
    
    Add IRQF_IRQPOLL to timer interrupts on i386.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: James Bottomley <James.Bottomley@steeleye.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e6d828f44655bb85e67fda79fd0028a56168e4e0
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:28 2007 -0700

    Add IRQF_IRQPOLL flag on x86_64
    
    Add IRQF_IRQPOLL for the timer interrupt on x86_64.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d85a60d85ea5b7c597508c1510c88e657773d378
Author: Bernhard Walle <bwalle@suse.de>
Date:   Tue May 8 00:35:24 2007 -0700

    Add IRQF_IRQPOLL flag (common code)
    
    irqpoll is broken on some architectures that don't use the IRQ 0 for the timer
    interrupt like IA64.  This patch adds a IRQF_IRQPOLL flag.
    
    Each architecture is handled in a separate pach.  As I left the irq == 0 as
    condition, this should not break existing architectures that use timer_irq ==
    0 and that I did't address with that patch (because I don't know).
    
    This patch:
    
    This patch adds a IRQF_IRQPOLL flag that the interrupt registration code could
    use for the interrupt it wants to use for IRQ polling.
    
    Because this must not be the timer interrupt, an additional flag was added
    instead of re-using the IRQF_TIMER constant.  Until all architectures will
    have an IRQF_IRQPOLL interrupt, irq == 0 will stay as alternative as it should
    not break anything.
    
    Also, note_interrupt() is called on CPU-specific interrupts to be used as
    interrupt source for IRQ polling.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: Grant Grundler <grundler@google.com>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 951744fea0aea9adbd7c8cacb3605f2d69a66f96
Author: Dmitriy Monakhov <dmonakhov@openvz.org>
Date:   Tue May 8 00:35:22 2007 -0700

    udf: possible null pointer dereference while load_partition
    
    sb_read may return NULL, let's explicitly check it.
    
    Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org>
    Cc: Jan Kara <jack@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 31170b6ad4ebe6c43c1cc3b8112274cf59474de0
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:35:21 2007 -0700

    udf: support files larger than 1G
    
    Make UDF work correctly for files larger than 1GB.  As no extent can be
    longer than (1<<30)-blocksize bytes, we have to create several extents if a
    big hole is being created.  As a side-effect, we now don't discard
    preallocated blocks when creating a hole.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 948b9b2c967c3bec6136b2dbb9e1c12f62e03efa
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:35:18 2007 -0700

    udf: add assertions
    
    Add a few assertions into udf_discard_prealloc() to check that the file is
    sane (mostly helps debugging further patches ;).
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3bf25cb40d899eeb5a471f497e56ddfe2c96c019
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:35:16 2007 -0700

    udf: use get_bh()
    
    Make UDF use get_bh() instead of directly accessing b_count and use
    brelse() instead of udf_release_data() which does just brelse()...
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ff116fc8d1d43927c7651b91d5aec41eb30c4429
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:35:14 2007 -0700

    UDF: introduce struct extent_position
    
    Introduce a structure extent_position to store a position of an extent and
    the corresponding buffer_head in one place.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 60448b1d6db4e82946ff9a2ac88df341f5fa87a2
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:35:13 2007 -0700

    udf: use sector_t and loff_t for file offsets
    
    Use sector_t and loff_t for file offsets in UDF filesystem.  Otherwise an
    overflow may occur for long files.  Also make inode_bmap() return offset in
    the extent in number of blocks instead of number of bytes - for most
    callers this is more convenient.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 277866a0e3a4f97e859f7a621f5b4f5359c9526c
Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date:   Tue May 8 00:35:12 2007 -0700

    nfs: fix congestion control: use atomic_longs
    
    Change the atomic_t in struct nfs_server to atomic_long_t in anticipation
    of machines that can handle 8+TB of (4K) pages under writeback.
    
    However I suspect other things in NFS will start going *bang* by then.
    
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 79df3c19aa601d264719b04e3a788a7b852f4859
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:35:10 2007 -0700

    no longer #include <asm/kdebug.h>
    
    Include the new linux/kdebug.h instead of asm/kdebug.h.
    
    Simply remove the asm/kdebug.h include if both had been included.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cc38682f356f95ca0e409679b76db46af6036460
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:35:08 2007 -0700

    Some grammatical fixups and additions to atomic.h kernel-doc content
    
    Tweak and add content for extractable documentation in asm-i386/atomic.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0ba34e197a45c1639aa56aea0399e97f827abb35
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:35:06 2007 -0700

    uml: pcap devices should get MACs from command line
    
    Allow a pcap device to be assigned a MAC on the command line.  They don't
    really need one, but it is handy to be able to do when your distro assigns a
    new ethernet device whenever it sees a new MAC.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7d98230a73c21b4d0cee9c3aca38190d215e0e39
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:35:04 2007 -0700

    uml: network and pcap cleanup
    
    Some network device cleanup.
    
    When setup_etheraddr found a globally valid MAC being assigned to an
    interface, it went ahead and used it rather than assigning a random MAC like
    the other cases do.  This isn't really an error like the others, but it seems
    consistent to make it behave the same.
    
    We were getting some duplicate kfree() in the error case in eth_configure
    because platform_device_unregister frees buffers that the error cases
    following tried to free again.
    
    The pcap initialization routine wasn't doing the proper printk of its
    information, causing a printk of the first part of that line to be
    unterminated by a newline.
    
    The pcap code had a bunch of style violations, which are now fixed.
    
    pcap_setup wasn't returning false when it detected an unrecognized
    option.
    
    The printks in pcap_user all got UM_KERN_BLAH prepended to their
    format strings.
    
    pcap_remove now checks for a non-NULL pcap structure before it calls
    pcap_close.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Acked-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a436ed9c5106b41606cbb55ab3b28389fe8ae04f
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:35:02 2007 -0700

    x86: create asm/cmpxchg.h
    
    i386:
    
      Rearrange the cmpxchg code to allow atomic.h to get it without needing to
      include system.h.  This kills warnings in the UML build from atomic.h about
      implicit declarations of cmpxchg symbols.  The i386 build presumably isn't
      seeing this because a separate inclusion of system.h is covering it over.
    
      The cmpxchg stuff is moved to asm-i386/cmpxchg.h, with an include left in
      system.h for the benefit of generic code which expects cmpxchg there.
    
      Meanwhile, atomic.h includes cmpxchg.h.
    
      This causes no noticable damage to the i386 build.
    
    x86_64:
    
      Move cmpxchg into its own header.  atomic.h already included system.h, so
      this is changed to include cmpxchg.h.
    
      This is purely cleanup - it's not fixing any warnings - so if the x86_64
      system.h isn't considered as cleanup-worthy as i386, then this can be
      dropped.
    
      It causes no noticable damage to the x86_64 build.
    
    uml:
    
      The i386 and x86_64 cmpxchg patches require an asm-um/cmpxchg.h for the
      UML build.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5dc12ddee93d63d7107cbbf70db23476d7b30e43
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:34:59 2007 -0700

    Remove tas()
    
    tas() has no users, so get rid of it.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: <linux-arch@vger.kernel.org>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c343c14aec1e70a51575e3c29391ee86ae7dbeb2
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:58 2007 -0700

    local_t: x86_64 extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 469b50b622a4f581fd38e3eaf8a94d453f01cc81
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:55 2007 -0700

    local_t: sparc64 cleanup
    
    sparc64 local_t cleanup : simply use asm-generic/local.h.
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: "David S. Miller" <davem@davemloft.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6d8944a0d7fa59e4db0d7b792e6138043ee0ad2c
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:53 2007 -0700

    local_t: powerpc extension
    
    [akpm@linux-foundation.org: build fixes]
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 14c846a4d8555d4645d502e3cd951f15ee7e3d55
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:51 2007 -0700

    local_t: parisc cleanup
    
    parisc architecture local_t cleanup : use asm-generic/local.h.
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7232311ef14c274d88871212a07557f18f4140d1
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:47 2007 -0700

    local_t: mips extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4431f46f5fe0e3b740dfaf09ba34f0b14688185e
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:46 2007 -0700

    local_t: ia64 extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a075227948636e10aa2cc2d8725fbbab27681d4a
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:44 2007 -0700

    local_t: i386 extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f43f7b46eb101f50950cfcead0cb0b7a9c4f6823
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:41 2007 -0700

    local_t: alpha extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5e97b9309baa76b476ec7e0d6e9c097edeb4142c
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:40 2007 -0700

    local_t: architecture independent extension
    
    This series extena and standardises local_t operations on each architecture,
    allowing a rich set of atomic operations to be done on per-cpu data with
    minimal performance impact.  On architectures where there seems to be no
    difference between the SMP and UP operation (same memory barriers, same
    LOCKing), local.h simply includes asm-generic/local.h, which removes
    duplicated code from the current kernel tree.
    
    This patch:
    
    local_t: architecture independent extension
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2856f5e31c1413bf6e4f1371e07e17078a5fee5e
Author: Mathieu Desnoyers <compudj@krystal.dyndns.org>
Date:   Tue May 8 00:34:38 2007 -0700

    atomic.h: atomic_add_unless as inline. Remove system.h atomic.h circular dependency
    
    atomic_add_unless as inline. Remove system.h atomic.h circular dependency.
    I agree (with Andi Kleen) this typeof is not needed and more error
    prone. All the original atomic.h code that uses cmpxchg (which includes
    the atomic_add_unless) uses defines instead of inline functions,
    probably to circumvent a circular dependency between system.h and
    atomic.h on powerpc (which my patch addresses). Therefore, it makes
    sense to use inline functions that will provide type checking.
    
    atomic_add_unless as inline. Remove system.h atomic.h circular dependency.
    Digging into the FRV architecture shows me that it is also affected by
    such a circular dependency. Here is the diff applying this against the
    rest of my atomic.h patches.
    
    It applies over the atomic.h standardization patches.
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 79d365a306c3af53d8a732fec79b76c0b285d816
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:36 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to x86_64
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2549c8589cc0550f0714d32720877d7af133ae40
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:34 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to sparc64
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: "David S. Miller" <davem@davemloft.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f46e477ed94f6407982690ef53dab7898834268f
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:27 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to powerpc
    
    [akpm@linux-foundation.org: build fixes]
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8ffe9d0bffa441de41d8543a984e552d49293641
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:26 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to parisc
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Matthew Wilcox <willy@debian.org>
    Acked-by: Grant Grundler <grundler@parisc-linux.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e12f644bd085ce64a6ecca4e466fcdc2c2df4c0f
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:24 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to mips
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 819791319becde19e32788a34cc2556aef9f9e6d
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:22 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to ia64
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e656e245d5adf19f3c431e7f7792659c204e32f2
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:20 2007 -0700

    atomic.h: i386 type safety fix
    
    Remove an explicit cast to an integer type for the result returned by cmpxchg.
     It is not per se a problem on the i386 architecture, because sizeof(int) ==
    sizeof(long), but whenever this code is cut'n'pasted to a accept passing an
    atomic64_t value as parameter to cmpxchg, xchg and add_unless, having 64 bits
    inputs casted to 32 bits.
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bb2382c3e4395ab595278cc7b92ac3f2eaf23f66
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:19 2007 -0700

    atomic.h: complete atomic_long operations in asm-generic
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e96e69942312314c061eb2fdd947a7a1211d62f8
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue May 8 00:34:18 2007 -0700

    atomic.h: add atomic64 cmpxchg, xchg and add_unless to alpha
    
    This series mainly adds support for missing 64 bits cmpxchg and 64 bits atomic
    add unless.  Therefore, principally 64 bits architectures are targeted by
    these patches.  It also adds the complete list of atomic operations on the
    atomic_long type.
    
    This patch:
    
    atomic.h: add atomic64 cmpxchg, xchg and add_unless to alpha
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bf8f6e5b3e51ee0c64c2d1350c70198ddc8ad3f7
Author: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Date:   Tue May 8 00:34:16 2007 -0700

    Kprobes: The ON/OFF knob thru debugfs
    
    This patch provides a debugfs knob to turn kprobes on/off
    
    o A new file /debug/kprobes/enabled indicates if kprobes is enabled or
      not (default enabled)
    o Echoing 0 to this file will disarm all installed probes
    o Any new probe registration when disabled will register the probe but
      not arm it. A message will be printed out in such a case.
    o When a value 1 is echoed to the file, all probes (including ones
      registered in the intervening period) will be enabled
    o Unregistration will happen irrespective of whether probes are globally
      enabled or not.
    o Update Documentation/kprobes.txt to reflect these changes. While there
      also update the doc to make it current.
    
    We are also looking at providing sysrq key support to tie to the disabling
    feature provided by this patch.
    
    [akpm@linux-foundation.org: Use bool like a bool!]
    [akpm@linux-foundation.org: add printk facility levels]
    [cornelia.huck@de.ibm.com: Add the missing arch_trampoline_kprobe() for s390]
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Srinivasa DS <srinivasa@in.ibm.com>
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4c4308cb93450989846ac49faeb6dab943e7657e
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:34:14 2007 -0700

    kprobes: kretprobes simplifications
    
     - consolidate duplicate code in all arch_prepare_kretprobe instances
       into common code
     - replace various odd helpers that use hlist_for_each_entry to get
       the first elemenet of a list with either a hlist_for_each_entry_save
       or an opencoded access to the first element in the caller
     - inline add_rp_inst into it's only remaining caller
     - use kretprobe_inst_table_head instead of opencoding it
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
    Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6f716acd5fa20ae6a35ab29ae37fa9189e839ed5
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:34:13 2007 -0700

    kprobes: codingstyle cleanups
    
    Remove superflous braces and fix indentation aswell as comments.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
    Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b0bb501651b467096723dcfcf4565d910a2aadf8
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:34:11 2007 -0700

    kprobes: use hlist_for_each_entry
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
    Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 41ac8df9d5b731a4dd8f1f4e5a9de6ef8768383d
Author: Marko Vrh <mvrh@freeshells.ch>
Date:   Tue May 8 00:34:09 2007 -0700

    rtc-cmos: make it load on PNPBIOS systems
    
    Replace CONFIG_PNPACPI with CONFIG_PNP, so it loads on ACPI-less PNPBIOS
    systems.
    
    Signed-off-by: Marko Vrh <mvrh@freeshells.ch>
    Acked-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f8245c26886c912627ebc49f714e4491261224c4
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:34:07 2007 -0700

    rtc: remove "RTC_ALM_SET mode" bugs
    
    This fixes a common glitch in how RTC drivers handle two "set alarm" modes,
    by getting rid of the surprising/hidden one that was rarely implemented
    correctly (and which could expose nonportable hardware-specific behavior).
    
    The glitch comes from the /dev/rtcX logic implementing the legacy
    RTC_ALM_SET (limited to 24 hours, needing RTC_AIE_ON) ioctl on top of the
    RTC driver call providing access to the newer RTC_WKALM_SET (without those
    limitations) by initializing the day/month/year fields to be invalid ...
    that second mode.
    
    Now, since few RTC drivers check those fields, and most hardware misbehaves
    when faced with invalid date fields, many RTC drivers will set bogus alarm
    times on those RTC_ALM_SET code paths.  (Several in-tree drivers have that
    issue, and I also noticed it with code reviews on several new RTC drivers.)
    
    This patch ensures that RTC drivers never see such invalid alarm fields, by
    moving some logic out of rtc-omap into the RTC_ALM_SET code and adding an
    explicit check (which will prevent the issue on other code paths).
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Scott Wood <scottwood@freescale.com>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 416ce32e704d778c283f2f86cadd836cd5d3696c
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:34:05 2007 -0700

    revert "rtc: Add rtc_merge_alarm()"
    
    David says "884b4aaaa242a2db8c8252796f0118164a680ab5 should be reverted.  It
    added an rtc_merge_alarm() call to the 2.6.20 kernel, which hasn't yet been
    used by any in-tree driver; this patch obviates the need for that call, and
    uses a more robust approach."
    
    Cc: Scott Wood <scottwood@freescale.com>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 19bfe37caa8184768ecc15269302f42036625259
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:34:03 2007 -0700

    workaround rtc-related acpi table bugs
    
    This works around a bug seen in some RTC-related ACPI table entries, and
    tweaks related diagnostics to follow the ACPI convention.
    
    The bug prevents misleading boot-time messages: platforms affected by this
    bug wrongly report they can support alarms up to one year in the future,
    when in fact the longest alarm is just 24 hours.  That will surprise anyone
    trying to use those extended alarms.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: Len Brown <lenb@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f5f72b46c349fefcfd4421b2213c6ffb324c5e56
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:34:02 2007 -0700

    ACPI wakeup hooks for rtc-cmos
    
    Remove /proc/acpi/alarm file when the rtc-cmos "wakealarm" file is available.
    Instead, provide hooks that rtc-cmos will use.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: Len Brown <lenb@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 87ac84f42a7a580d0dd72ae31d6a5eb4bfe04c6d
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:34:00 2007 -0700

    rtc-cmos wakeup interface
    
    I finally got around to testing the updated wakeup event hooks for rtc-cmos,
    and they follow in two patches:
    
     - Interface update ... when a simple enable_irq_wake() doesn't suffice,
       the platform data can hold suspend/resume callback hooks.
    
     - ACPI implementation ... provides callback hooks to do ACPI magic, and
       eliminate the legacy /proc/acpi/alarm file.
    
    The interface update could go into 2.6.21, but that's not essential; they
    will be NOPs on most PCs, without the ACPI stuff.
    
    I suspect the ACPI folk may have opinions about how to merge that second
    patch, and how to obsolete that legacy procfs file.  I'd like to see that
    merge into 2.6.22 if possible...
    
    As for how to kick it in ... two ways:
    
     - The appended "rtcwake" program; updated since the last time it was
       posted, it deals much better with timezones and DST.
    
     - Write the /sys/class/rtc/.../wakealarm file, then go to sleep.
    
    For some reason RTC wake from "swsusp" stopped working on a system where
    it previously worked; the alarm setting appears to get clobbered.  But
    on the bright side, RTC wake from "standby" worked on a system that had
    never been able to resume from that state before ... IDEACPI is my guess
    as to why it finally started to work.  It's the old "two steps forward,
    one step back" dance, I guess.
    
    - Dave
    
    /* gcc -Wall -Os -o rtcwake rtcwake.c */
    
    #include <stdio.h>
    #include <getopt.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <time.h>
    
    #include <sys/ioctl.h>
    #include <sys/time.h>
    #include <sys/types.h>
    
    #include <linux/rtc.h>
    
    /* constants from legacy PC/AT hardware */
    #define	RTC_PF	0x40
    #define	RTC_AF	0x20
    #define	RTC_UF	0x10
    
    /*
     * rtcwake -- enter a system sleep state until specified wakeup time.
     *
     * This uses cross-platform Linux interfaces to enter a system sleep state,
     * and leave it no later than a specified time.  It uses any RTC framework
     * driver that supports standard driver model wakeup flags.
     *
     * This is normally used like the old "apmsleep" utility, to wake from a
     * suspend state like ACPI S1 (standby) or S3 (suspend-to-RAM).  Most
     * platforms can implement those without analogues of BIOS, APM, or ACPI.
     *
     * On some systems, this can also be used like "nvram-wakeup", waking
     * from states like ACPI S4 (suspend to disk).  Not all systems have
     * persistent media that are appropriate for such suspend modes.
     *
     * The best way to set the system's RTC is so that it holds the current
     * time in UTC.  Use the "-l" flag to tell this program that the system
     * RTC uses a local timezone instead (maybe you dual-boot MS-Windows).
     */
    
    static char		*progname;
    
    #ifdef	DEBUG
    #define	VERSION	"1.0 dev (" __DATE__ " " __TIME__ ")"
    #else
    #define	VERSION	"0.9"
    #endif
    
    static unsigned		verbose;
    static int		rtc_is_utc = -1;
    
    static int may_wakeup(const char *devname)
    {
    	char	buf[128], *s;
    	FILE	*f;
    
    	snprintf(buf, sizeof buf, "/sys/class/rtc/%s/device/power/wakeup",
    			devname);
    	f = fopen(buf, "r");
    	if (!f) {
    		perror(buf);
    		return 0;
    	}
    	fgets(buf, sizeof buf, f);
    	fclose(f);
    
    	s = strchr(buf, '\n');
    	if (!s)
    		return 0;
    	*s = 0;
    
    	/* wakeup events could be disabled or not supported */
    	return strcmp(buf, "enabled") == 0;
    }
    
    /* all times should be in UTC */
    static time_t	sys_time;
    static time_t	rtc_time;
    
    static int get_basetimes(int fd)
    {
    	struct tm	tm;
    	struct rtc_time	rtc;
    
    	/* this process works in RTC time, except when working
    	 * with the system clock (which always uses UTC).
    	 */
    	if (rtc_is_utc)
    		setenv("TZ", "UTC", 1);
    	tzset();
    
    	/* read rtc and system clocks "at the same time", or as
    	 * precisely (+/- a second) as we can read them.
    	 */
    	if (ioctl(fd, RTC_RD_TIME, &rtc) < 0) {
    		perror("read rtc time");
    		return 0;
    	}
    	sys_time = time(0);
    	if (sys_time == (time_t)-1) {
    		perror("read system time");
    		return 0;
    	}
    
    	/* convert rtc_time to normal arithmetic-friendly form,
    	 * updating tm.tm_wday as used by asctime().
    	 */
    	memset(&tm, 0, sizeof tm);
    	tm.tm_sec = rtc.tm_sec;
    	tm.tm_min = rtc.tm_min;
    	tm.tm_hour = rtc.tm_hour;
    	tm.tm_mday = rtc.tm_mday;
    	tm.tm_mon = rtc.tm_mon;
    	tm.tm_year = rtc.tm_year;
    	tm.tm_isdst = rtc.tm_isdst;	/* stays unspecified? */
    	rtc_time = mktime(&tm);
    
    	if (rtc_time == (time_t)-1) {
    		perror("convert rtc time");
    		return 0;
    	}
    
    	if (verbose) {
    		if (!rtc_is_utc) {
    			printf("\ttzone   = %ld\n", timezone);
    			printf("\ttzname  = %s\n", tzname[daylight]);
    			gmtime_r(&rtc_time, &tm);
    		}
    		printf("\tsystime = %ld, (UTC) %s",
    				(long) sys_time, asctime(gmtime(&sys_time)));
    		printf("\trtctime = %ld, (UTC) %s",
    				(long) rtc_time, asctime(&tm));
    	}
    
    	return 1;
    }
    
    static int setup_alarm(int fd, time_t *wakeup)
    {
    	struct tm		*tm;
    	struct rtc_wkalrm	wake;
    
    	tm = gmtime(wakeup);
    
    	wake.time.tm_sec = tm->tm_sec;
    	wake.time.tm_min = tm->tm_min;
    	wake.time.tm_hour = tm->tm_hour;
    	wake.time.tm_mday = tm->tm_mday;
    	wake.time.tm_mon = tm->tm_mon;
    	wake.time.tm_year = tm->tm_year;
    	wake.time.tm_wday = tm->tm_wday;
    	wake.time.tm_yday = tm->tm_yday;
    	wake.time.tm_isdst = tm->tm_isdst;
    
    	/* many rtc alarms only support up to 24 hours from 'now' ... */
    	if ((rtc_time + (24 * 60 * 60)) > *wakeup) {
    		if (ioctl(fd, RTC_ALM_SET, &wake.time) < 0) {
    			perror("set rtc alarm");
    			return 0;
    		}
    		if (ioctl(fd, RTC_AIE_ON, 0) < 0) {
    			perror("enable rtc alarm");
    			return 0;
    		}
    
    	/* ... so use the "more than 24 hours" request only if we must */
    	} else {
    		/* avoid an extra AIE_ON call */
    		wake.enabled = 1;
    
    		if (ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
    			perror("set rtc wake alarm");
    			return 0;
    		}
    	}
    
    	return 1;
    }
    
    static void suspend_system(const char *suspend)
    {
    	FILE	*f = fopen("/sys/power/state", "w");
    
    	if (!f) {
    		perror("/sys/power/state");
    		return;
    	}
    
    	fprintf(f, "%s\n", suspend);
    	fflush(f);
    
    	/* this executes after wake from suspend */
    	fclose(f);
    }
    
    int main(int argc, char **argv)
    {
    	static char		*devname = "rtc0";
    	static unsigned		seconds = 0;
    	static char		*suspend = "standby";
    
    	int		t;
    	int		fd;
    	time_t		alarm = 0;
    
    	progname = strrchr(argv[0], '/');
    	if (progname)
    		progname++;
    	else
    		progname = argv[0];
    	if (chdir("/dev/") < 0) {
    		perror("chdir /dev");
    		return 1;
    	}
    
    	while ((t = getopt(argc, argv, "d:lm:s:t:uVv")) != EOF) {
    		switch (t) {
    
    		case 'd':
    			devname = optarg;
    			break;
    
    		case 'l':
    			rtc_is_utc = 0;
    			break;
    
    		/* what system power mode to use?  for now handle only
    		 * standardized mode names; eventually when systems define
    		 * their own state names, parse /sys/power/state.
    		 *
    		 * "on" is used just to test the RTC alarm mechanism,
    		 * bypassing all the wakeup-from-sleep infrastructure.
    		 */
    		case 'm':
    			if (strcmp(optarg, "standby") == 0
    					|| strcmp(optarg, "mem") == 0
    					|| strcmp(optarg, "disk") == 0
    					|| strcmp(optarg, "on") == 0
    					) {
    				suspend = optarg;
    				break;
    			}
    			printf("%s: unrecognized suspend state '%s'\n",
    					progname, optarg);
    			goto usage;
    
    		/* alarm time, seconds-to-sleep (relative) */
    		case 's':
    			t = atoi(optarg);
    			if (t < 0) {
    				printf("%s: illegal interval %s seconds\n",
    						progname, optarg);
    				goto usage;
    			}
    			seconds = t;
    			break;
    
    		/* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */
    		case 't':
    			t = atoi(optarg);
    			if (t < 0) {
    				printf("%s: illegal time_t value %s\n",
    						progname, optarg);
    				goto usage;
    			}
    			alarm = t;
    			break;
    
    		case 'u':
    			rtc_is_utc = 1;
    			break;
    
    		case 'v':
    			verbose++;
    			break;
    
    		case 'V':
    			printf("%s: version %s\n", progname, VERSION);
    			break;
    
    		default:
    usage:
    			printf("usage: %s [options]"
    				"\n\t"
    				"-d rtc0|rtc1|...\t(select rtc)"
    				"\n\t"
    				"-l\t\t\t(RTC uses local timezone)"
    				"\n\t"
    				"-m standby|mem|...\t(sleep mode)"
    				"\n\t"
    				"-s seconds\t\t(seconds to sleep)"
    				"\n\t"
    				"-t time_t\t\t(time to wake)"
    				"\n\t"
    				"-u\t\t\t(RTC uses UTC)"
    				"\n\t"
    				"-v\t\t\t(verbose messages)"
    				"\n\t"
    				"-V\t\t\t(show version)"
    				"\n",
    				progname);
    			return 1;
    		}
    	}
    
    	if (!alarm && !seconds) {
    		printf("%s: must provide wake time\n", progname);
    		goto usage;
    	}
    
    	/* REVISIT:  if /etc/adjtime exists, read it to see what
    	 * the util-linux version of hwclock assumes.
    	 */
    	if (rtc_is_utc == -1) {
    		printf("%s: assuming RTC uses UTC ...\n", progname);
    		rtc_is_utc = 1;
    	}
    
    	/* this RTC must exist and (if we'll sleep) be wakeup-enabled */
    	fd = open(devname, O_RDONLY);
    	if (fd < 0) {
    		perror(devname);
    		return 1;
    	}
    	if (strcmp(suspend, "on") != 0 && !may_wakeup(devname)) {
    		printf("%s: %s not enabled for wakeup events\n",
    				progname, devname);
    		return 1;
    	}
    
    	/* relative or absolute alarm time, normalized to time_t */
    	if (!get_basetimes(fd))
    		return 1;
    	if (verbose)
    		printf("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n",
    				alarm, sys_time, rtc_time, seconds);
    	if (alarm) {
    		if (alarm < sys_time) {
    			printf("%s: time doesn't go backward to %s",
    					progname, ctime(&alarm));
    			return 1;
    		}
    		alarm += sys_time - rtc_time;
    	} else
    		alarm = rtc_time + seconds + 1;
    	if (setup_alarm(fd, &alarm) < 0)
    		return 1;
    
    	sync();
    	printf("%s: wakeup from \"%s\" using %s at %s",
    			progname, suspend, devname,
    			ctime(&alarm));
    	fflush(stdout);
    	usleep(10 * 1000);
    
    	if (strcmp(suspend, "on") != 0)
    		suspend_system(suspend);
    	else {
    		unsigned long data;
    
    		do {
    			t = read(fd, &data, sizeof data);
    			if (t < 0) {
    				perror("rtc read");
    				break;
    			}
    			if (verbose)
    				printf("... %s: %03lx\n", devname, data);
    		} while (!(data & RTC_AF));
    	}
    
    	if (ioctl(fd, RTC_AIE_OFF, 0) < 0)
    		perror("disable rtc alarm interrupt");
    
    	close(fd);
    	return 0;
    }
    
    This patch:
    
    Make rtc-cmos do the relevant magic so this RTC can wake the system from a
    sleep state.  That magic comes in two basic flavors:
    
     - Straightforward:  enable_irq_wake(), the way it'd work on most SOC chips;
       or generally with system sleep states which don't disable core IRQ logic.
    
     - Roundabout, using non-IRQ platform hooks.  This is needed with ACPI and
       one almost-clone chip which uses a special wakeup-only alarm.  (That's
       the RTC used on Footbridge boards, FWIW, which don't do PM in Linux.)
    
    A separate patch implements those hooks for ACPI platforms, so that rtc_cmos
    can issue system wakeup events (and its sysfs "wakealarm" attribute works on
    at least some systems).
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: Len Brown <lenb@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9b5ef64a3a73757f1acdfb8565b5105115fc6e62
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Tue May 8 00:33:50 2007 -0700

    rtc: update vr41xx alarm handling
    
    - vr41xx_rtc_read_alarm() reports alarm enabled.
    - vr41xx_rtc_set_alarm() sets alarm disable/enable by rtc_wkalrm.enabled.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Acked-by: Alessandro Zummo <a.zummo@towertech.it>
    Acked-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 09a21e56dc3767ce444e21c1383d587b261af13c
Author: Alessandro Zummo <a.zummo@towertech.it>
Date:   Tue May 8 00:33:48 2007 -0700

    RTC Kconfig cleanup
    
    Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cb3a58d2acc042f62cde932add8e1f9ed508368d
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:46 2007 -0700

    rtc: update to class device removal patches
    
    Fix a goof in the revised classdev support for RTCs: make sure the /dev
    node info is ready before the device is registered, not after.  Otherwise
    the /sys/class/rtc/rtcN/dev attribute won't be created and then udev won't
    have the information it needs to create the /dev/rtcN node.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 61a7c36acb3da406d64c0da6288eab1c414a65ea
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:45 2007 -0700

    RTC: replace some newly-introduced macros with inlines
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7ca1d488ffe4817adaba61cc05b972782f7d3f91
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:42 2007 -0700

    rtc: suspend()/resume() restores system clock
    
    RTC class suspend/resume support, re-initializing the system clock on resume
    from the clock used to initialize it at boot time.
    
     - The reinit-on-resume is hooked to the existing RTC_HCTOSYS config
       option, on the grounds that a clock good enough for init must also
       be good enough for re-init.
    
     - Inlining a version of the code used by ARM, to save and restore the
       delta between a selected RTC and the current system wall-clock time.
    
     - Removes calls to that ARM code from AT91, OMAP1, and S3C RTCs.  This
       means that systems using those RTCs across suspend/resume will likely
       want to change their kernel configs to enable RTC_HCTOSYS.
    
       If HCTOSYS isn't using a second RTC (with battery?), this changes the
       system's initial date from Jan 1970 to the epoch this hardware uses:
       1998 for AT91, 2000 for OMAP1 (assuming no split power mode), etc.
    
    This goes on top of the patch series removing "struct class_device" usage
    from the RTC framework.  That's all needed for class suspend()/resume().
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cd9662094edf4173e87f0452e57e4eacc228f8ff
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:40 2007 -0700

    rtc: remove rest of class_device
    
    Finish converting the RTC framework so it no longer uses class_device.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7d9f99eccc8f94ace31030a2a7ff73cf5f8c12a0
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:38 2007 -0700

    rtc: simplified /proc/driver/rtc handling
    
    This simplifies the RTC procfs support by removing the class_interface that
    hooks it into the rtc core.  If it's configured, then sysfs support is now
    part of the RTC core, and is never a separate module.
    
    It also removes the class_interface hook, now that its last remaining user is
    gone.  (That API is usable only with a "struct class_device".)
    
    It's another step towards being able to remove "struct class_device".
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 446ecbd925dc580c9972049c926c17aa8d967fe4
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:33 2007 -0700

    rtc: simplified rtc sysfs attribute handling
    
    This simplifies the RTC sysfs support by removing the class_interface that
    hooks it into the rtc core.  If it's configured, then sysfs support is now
    part of the RTC core, and is never a separate module.
    
    It's another step towards being able to remove "struct class_device".
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ab6a2d70d18edc7a716ef3127b9e13382faec98c
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:30 2007 -0700

    rtc: rtc interfaces don't use class_device
    
    This patch removes class_device from the programming interface that the RTC
    framework exposes to the rest of the kernel.  Now an rtc_device is passed,
    which is more type-safe and streamlines all the relevant code.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5726fb2012f0d96153113ddb7f988a0daea587ce
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:33:27 2007 -0700

    rtc: remove /sys/class/rtc-dev/*
    
    This simplifies the /dev support by removing a superfluous class_device (the
    /sys/class/rtc-dev stuff) and the class_interface that hooks it into the rtc
    core.  Accordingly, if it's configured then /dev support is now part of the
    RTC core, and is never a separate module.
    
    It's another step towards being able to remove "struct class_device".
    
    [bunk@stusta.de: drivers/rtc/rtc-dev.c should #include "rtc-core.h"]
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
    Acked-By: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1c710c896eb461895d3c399e15bb5f20b39c9073
Author: Ulrich Drepper <drepper@redhat.com>
Date:   Tue May 8 00:33:25 2007 -0700

    utimensat implementation
    
    Implement utimensat(2) which is an extension to futimesat(2) in that it
    
    a) supports nano-second resolution for the timestamps
    b) allows to selectively ignore the atime/mtime value
    c) allows to selectively use the current time for either atime or mtime
    d) supports changing the atime/mtime of a symlink itself along the lines
       of the BSD lutimes(3) functions
    
    For this change the internally used do_utimes() functions was changed to
    accept a timespec time value and an additional flags parameter.
    
    Additionally the sys_utime function was changed to match compat_sys_utime
    which already use do_utimes instead of duplicating the work.
    
    Also, the completely missing futimensat() functionality is added.  We have
    such a function in glibc but we have to resort to using /proc/self/fd/* which
    not everybody likes (chroot etc).
    
    Test application (the syscall number will need per-arch editing):
    
    #include <errno.h>
    #include <fcntl.h>
    #include <time.h>
    #include <sys/time.h>
    #include <stddef.h>
    #include <syscall.h>
    
    #define __NR_utimensat 280
    
    #define UTIME_NOW       ((1l << 30) - 1l)
    #define UTIME_OMIT      ((1l << 30) - 2l)
    
    int
    main(void)
    {
      int status = 0;
    
      int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
      if (fd == -1)
        error (1, errno, "failed to create test file \"ttt\"");
    
      struct stat64 st1;
      if (fstat64 (fd, &st1) != 0)
        error (1, errno, "fstat failed");
    
      struct timespec t[2];
      t[0].tv_sec = 0;
      t[0].tv_nsec = 0;
      t[1].tv_sec = 0;
      t[1].tv_nsec = 0;
      if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
        error (1, errno, "utimensat failed");
    
      struct stat64 st2;
      if (fstat64 (fd, &st2) != 0)
        error (1, errno, "fstat failed");
    
      if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
        {
          puts ("atim not reset to zero");
          status = 1;
        }
      if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
        {
          puts ("mtim not reset to zero");
          status = 1;
        }
      if (status != 0)
        goto out;
    
      t[0] = st1.st_atim;
      t[1].tv_sec = 0;
      t[1].tv_nsec = UTIME_OMIT;
      if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
        error (1, errno, "utimensat failed");
    
      if (fstat64 (fd, &st2) != 0)
        error (1, errno, "fstat failed");
    
      if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
          || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
        {
          puts ("atim not set");
          status = 1;
        }
      if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
        {
          puts ("mtim changed from zero");
          status = 1;
        }
      if (status != 0)
        goto out;
    
      t[0].tv_sec = 0;
      t[0].tv_nsec = UTIME_OMIT;
      t[1] = st1.st_mtim;
      if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
        error (1, errno, "utimensat failed");
    
      if (fstat64 (fd, &st2) != 0)
        error (1, errno, "fstat failed");
    
      if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
          || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
        {
          puts ("mtim changed from original time");
          status = 1;
        }
      if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
          || st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
        {
          puts ("mtim not set");
          status = 1;
        }
      if (status != 0)
        goto out;
    
      sleep (2);
    
      t[0].tv_sec = 0;
      t[0].tv_nsec = UTIME_NOW;
      t[1].tv_sec = 0;
      t[1].tv_nsec = UTIME_NOW;
      if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
        error (1, errno, "utimensat failed");
    
      if (fstat64 (fd, &st2) != 0)
        error (1, errno, "fstat failed");
    
      struct timeval tv;
      gettimeofday(&tv,NULL);
    
      if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
          || st2.st_atim.tv_sec > tv.tv_sec)
        {
          puts ("atim not set to NOW");
          status = 1;
        }
      if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
          || st2.st_mtim.tv_sec > tv.tv_sec)
        {
          puts ("mtim not set to NOW");
          status = 1;
        }
    
      if (symlink ("ttt", "tttsym") != 0)
        error (1, errno, "cannot create symlink");
    
      t[0].tv_sec = 0;
      t[0].tv_nsec = 0;
      t[1].tv_sec = 0;
      t[1].tv_nsec = 0;
      if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0)
        error (1, errno, "utimensat failed");
    
      if (lstat64 ("tttsym", &st2) != 0)
        error (1, errno, "lstat failed");
    
      if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
        {
          puts ("symlink atim not reset to zero");
          status = 1;
        }
      if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
        {
          puts ("symlink mtim not reset to zero");
          status = 1;
        }
      if (status != 0)
        goto out;
    
      t[0].tv_sec = 1;
      t[0].tv_nsec = 0;
      t[1].tv_sec = 1;
      t[1].tv_nsec = 0;
      if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0)
        error (1, errno, "utimensat failed");
    
      if (fstat64 (fd, &st2) != 0)
        error (1, errno, "fstat failed");
    
      if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0)
        {
          puts ("atim not reset to one");
          status = 1;
        }
      if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0)
        {
          puts ("mtim not reset to one");
          status = 1;
        }
    
      if (status == 0)
         puts ("all OK");
    
     out:
      close (fd);
      unlink ("ttt");
      unlink ("tttsym");
    
      return status;
    }
    
    [akpm@linux-foundation.org: add missing i386 syscall table entry]
    Signed-off-by: Ulrich Drepper <drepper@redhat.com>
    Cc: Alexey Dobriyan <adobriyan@openvz.org>
    Cc: Michael Kerrisk <mtk-manpages@gmx.net>
    Cc: <linux-arch@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ade5fb818fb1861fd5f84619c761920ade762b5d
Author: Josh Triplett <josh@kernel.org>
Date:   Tue May 8 00:33:22 2007 -0700

    rcutorture: Remove redundant assignment to cur_ops in for loop
    
    The for loop in rcutorture_init uses the condition
    cur_ops = torture_ops[i], cur_ops
    but then makes the same assignment to cur_ops inside the loop.  Remove the
    redundant assignment inside the loop, and remove now-unnecessary braces.
    
    Signed-off-by: Josh Triplett <josh@kernel.org>
    Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c8e5b163101c5d716f08e90b686da620baa022f1
Author: Josh Triplett <josh@kernel.org>
Date:   Tue May 8 00:33:20 2007 -0700

    rcutorture: style cleanup: avoid != NULL in boolean tests
    
    Signed-off-by: Josh Triplett <josh@kernel.org>
    Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 788e770eb2d17212eafaeedde0be56e3444c6b9a
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Tue May 8 00:33:14 2007 -0700

    rcutorture: Use ARRAY_SIZE macro when appropriate
    
    Use ARRAY_SIZE macro already defined in kernel.h
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Cc: "Paul E. McKenney" <paulmck@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c3396620cace20639bdf380f893f4dccad090d91
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Tue May 8 00:33:09 2007 -0700

    sched: align rq to cacheline boundary
    
    Align the per cpu runqueue to the cacheline boundary.  This will minimize
    the number of cachelines touched during remote wakeup.
    
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: Ravikiran G Thirumalai <kiran@scalex86.org>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bd53f96ca54a21c07e7a0ae1886fa623d370b85f
Author: Dmitry Adamushko <dmitry.adamushko@gmail.com>
Date:   Tue May 8 00:33:06 2007 -0700

    sched: redundant reschedule when set_user_nice() boosts a prio of a task from the "expired" array
    
    - Make TASK_PREEMPTS_CURR(task, rq) return "true" only if the task's prio
      is higher than the current's one and the task is in the "active" array.
      This ensures we don't make redundant resched_task() calls when the task
      is in the "expired" array (as may happen now in set_user_prio(),
      rt_mutex_setprio() and pull_task() ) ;
    
    - generalise conditions for a call to resched_task() in set_user_nice(),
      rt_mutex_setprio() and sched_setscheduler()
    
    Signed-off-by: Dmitry Adamushko <dmitry.adamushko@gmail.com>
    Cc: Con Kolivas <kernel@kolivas.org>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4953198b6ce07b008b0f1c2edd41c9d027a118b4
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Tue May 8 00:33:01 2007 -0700

    sched: optimize siblings status check logic in wake_idle()
    
    When a logical cpu 'x' already has more than one process running, then most
    likely the siblings of that cpu 'x' must be busy.  Otherwise the idle
    siblings would have likely(in most of the scenarios) picked up the extra
    load making the load on 'x' atmost one.
    
    Use this logic to eliminate the siblings status check and minimize the cache
    misses encountered on a heavily loaded system.
    
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5517d86bea237c1d7078840182d9ebc0fe4c1afc
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue May 8 00:32:57 2007 -0700

    Speed up divides by cpu_power in scheduler
    
    I noticed expensive divides done in try_to_wakeup() and
    find_busiest_group() on a bi dual core Opteron machine (total of 4 cores),
    moderatly loaded (15.000 context switch per second)
    
    oprofile numbers :
    
    CPU: AMD64 processors, speed 2600.05 MHz (estimated)
    Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit
    mask of 0x00 (No unit mask) count 50000
    samples  %        symbol name
    ...
    613914    1.0498  try_to_wake_up
        834  0.0013 :ffffffff80227ae1:   div    %rcx
    77513  0.1191 :ffffffff80227ae4:   mov    %rax,%r11
    
    608893    1.0413  find_busiest_group
       1841  0.0031 :ffffffff802260bf:       div    %rdi
    140109  0.2394 :ffffffff802260c2:       test   %sil,%sil
    
    Some of these divides can use the reciprocal divides we introduced some
    time ago (currently used in slab AFAIK)
    
    We can assume a load will fit in a 32bits number, because with a
    SCHED_LOAD_SCALE=128 value, its still a theorical limit of 33554432
    
    When/if we reach this limit one day, probably cpus will have a fast
    hardware divide and we can zap the reciprocal divide trick.
    
    Ingo suggested to rename cpu_power to __cpu_power to make clear it should
    not be modified without changing its reciprocal value too.
    
    I did not convert the divide in cpu_avg_load_per_task(), because tracking
    nr_running changes may be not worth it ?  We could use a static table of 32
    reciprocal values but it would add a conditional branch and table lookup.
    
    [akpm@linux-foundation.org: !SMP build fix]
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 46cb4b7c88fa5517f64b5bee42939ea3614cddcb
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Tue May 8 00:32:51 2007 -0700

    sched: dynticks idle load balancing
    
    Fix the process idle load balancing in the presence of dynticks.  cpus for
    which ticks are stopped will sleep till the next event wakes it up.
    Potentially these sleeps can be for large durations and during which today,
    there is no periodic idle load balancing being done.
    
    This patch nominates an owner among the idle cpus, which does the idle load
    balancing on behalf of the other idle cpus.  And once all the cpus are
    completely idle, then we can stop this idle load balancing too.  Checks added
    in fast path are minimized.  Whenever there are busy cpus in the system, there
    will be an owner(idle cpu) doing the system wide idle load balancing.
    
    Open items:
    1. Intelligent owner selection (like an idle core in a busy package).
    2. Merge with rcu's nohz_cpu_mask?
    
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bdecea3a9282d529b54954f3f1e59877629baba1
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Tue May 8 00:32:48 2007 -0700

    sched: fix idle load balancing in softirqd context
    
    Periodic load balancing in recent kernels happen in the softirq.  In
    certain -rt configurations, these softirqs are handled in softirqd context.
     And hence the check for idle processor was always returning busy (as
    nr_running > 1).
    
    This patch captures the idle information at the tick and passes this info
    to softirq context through an element 'idle_at_tick' in rq.
    
    [kernel@kolivas.org: Fix reverse idle at tick logic]
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2bd7e20e0d24325b0799544bc8105cc57cc8e2aa
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Tue May 8 00:32:45 2007 -0700

    ISDN: Spinlock initializer cleanup
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: Karsten Keil <kkeil@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9ea6e5d8088096aeba29b6778c3d3d82fb495e9f
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:43 2007 -0700

    use mutex instead of semaphore in CAPI 2.0 interface
    
    The CAPI 2.0 interface uses a semaphore as mutex.  Use the mutex API instead
    of the (binary) semaphore.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Cc: Karsten Keil <kkeil@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a7e27d5dd396419dc6d6288db6a6d86cf3a94ba5
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Tue May 8 00:32:40 2007 -0700

    sanitize linux/isdn_divertif.h for userspace
    
    the isdn_divertif contains kernel-only references so I've wrapped them in
    __KERNEL__ and add proper #include statements.
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    Cc: Karsten Keil <kkeil@suse.de>
    Cc: David Woodhouse <dwmw2@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 635244c59c27d3b22c4523d2a951cf553195a966
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:38 2007 -0700

    fix spinlock usage in hysdn_log_close()
    
    Fix incorrect spinlock use in hysdn_log_close().  The function declared a
    spinlock on the stack and used it to 'protect' a shared driver structure.
    
    The patch simply removes the useless code.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Cc: Karsten Keil <kkeil@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 13af68ee335d4d26ef96a133abc94b2ef051be00
Author: Armin Schindler <armin@melware.de>
Date:   Tue May 8 00:32:36 2007 -0700

    drivers/isdn/hardware/eicon/: remove unused header files
    
    As pointed out by Robert P.  J.  Day, here is a patch to remove unused
    header files from Eicon/Dialogic ISDN driver.
    
    Signed-off-by: Armin Schindler <armin@melware.de>
    Acked-by: Karsten Keil <kkeil@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3a3a51d1f2efe10090cd779a66c4b3c8f57eaf9f
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:32:33 2007 -0700

    make drivers/isdn/capi/capiutil.c:cdebbuf_alloc() static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Karsten Keil <kkeil@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1a1c9bb433af252767ee90d6394d287afa30cf8b
Author: Jeff Layton <jlayton@redhat.com>
Date:   Tue May 8 00:32:31 2007 -0700

    inode numbering: change libfs sb creation routines to avoid collisions with their root inodes
    
    This patch makes it so that simple_fill_super and get_sb_pseudo assign their
    root inodes to be number 1.  It also fixes up a couple of callers of
    simple_fill_super that were passing in files arrays that had an index at
    number 1, and adds a warning for any caller that sends in such an array.
    
    It would have been nice to have made it so that it wasn't possible to make
    such a collision, but some callers need to be able to control what inode
    number their entries get, so I think this is the best that can be done.
    
    Signed-off-by: Jeff Layton <jlayton@redhat.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 866b04fccbf125cd39f2bdbcfeaa611d39a061a8
Author: Jeff Layton <jlayton@redhat.com>
Date:   Tue May 8 00:32:29 2007 -0700

    inode numbering: make static counters in new_inode and iunique be 32 bits
    
    The problems are:
    
    - on filesystems w/o permanent inode numbers, i_ino values can be larger
      than 32 bits, which can cause problems for some 32 bit userspace programs on
      a 64 bit kernel.  We can't do anything for filesystems that have actual
      >32-bit inode numbers, but on filesystems that generate i_ino values on the
      fly, we should try to have them fit in 32 bits.  We could trivially fix this
      by making the static counters in new_inode and iunique 32 bits, but...
    
    - many filesystems call new_inode and assume that the i_ino values they are
      given are unique.  They are not guaranteed to be so, since the static
      counter can wrap.  This problem is exacerbated by the fix for #1.
    
    - after allocating a new inode, some filesystems call iunique to try to get
      a unique i_ino value, but they don't actually add their inodes to the
      hashtable, and so they're still not guaranteed to be unique if that counter
      wraps.
    
    This patch set takes the simpler approach of simply using iunique and hashing
    the inodes afterward.  Christoph H.  previously mentioned that he thought that
    this approach may slow down lookups for filesystems that currently hash their
    inodes.
    
    The questions are:
    
    1) how much would this slow down lookups for these filesystems?
    2) is it enough to justify adding more infrastructure to avoid it?
    
    What might be best is to start with this approach and then only move to using
    IDR or some other scheme if these extra inodes in the hashtable prove to be
    problematic.
    
    I've done some cursory testing with this patch and the overhead of hashing and
    unhashing the inodes with pipefs is pretty low -- just a few seconds of system
    time added on to the creation and destruction of 10 million pipes (very
    similar to the overhead that the IDR approach would add).
    
    The hard thing to measure is what effect this has on other filesystems. I'm
    open to ways to try and gauge this.
    
    Again, I've only converted pipefs as an example. If this approach is
    acceptable then I'll start work on patches to convert other filesystems.
    
    With a pretty-much-worst-case microbenchmark provided by Eric Dumazet
    <dada1@cosmosbay.com>:
    
    hashing patch (pipebench):
    sys     1m15.329s
    sys     1m16.249s
    sys     1m17.169s
    
    unpatched (pipebench):
    sys     1m9.836s
    sys     1m12.541s
    sys     1m14.153s
    
    Which works out to 1.05642174294555027017.  So ~5-6% slowdown.
    
    This patch:
    
    When a 32-bit program that was not compiled with large file offsets does a
    stat and gets a st_ino value back that won't fit in the 32 bit field, glibc
    (correctly) generates an EOVERFLOW error.  We can't do anything about fs's
    with larger permanent inode numbers, but when we generate them on the fly, we
    ought to try and have them fit within a 32 bit field.
    
    This patch takes the first step toward this by making the static counters in
    these two functions be 32 bits.
    
    [jlayton@redhat.com: mention that it's only the case for 32bit, non-LFS stat]
    Signed-off-by: Jeff Layton <jlayton@redhat.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 63bd23591e6c3891d34e4c6dba7c6aa41b05caad
Author: Jan Nikitenko <jan.nikitenko@gmail.com>
Date:   Tue May 8 00:32:25 2007 -0700

    au1550 SPI controller driver
    
    Here is a driver for the Alchemy au1550 PSC (Programmable Serial
    Controller) in SPI master mode.
    
    It supports dma transfers using the Alchemy descriptor based dma controller
    for 4-8 bits per word SPI transfers.  For 9-24 bits per word transfers, pio
    irq based mode is used to avoid setup of dma channels from scratch on each
    number of bits per word change.
    
    Tested with au1550; this may also work on other MIPS Alchemy cpus, like
    au1200/au1210/au1250.  Used extensively with SD card connected via SPI;
    this handles 8.1MHz SPI clock transfers using dma without any problem (the
    highest SPI clock freq possible with au1550 running on 324MHz).
    
    The driver supports sharing of SPI bus by multiple devices.  All features
    of Alchemy SPI mode are supported (all SPI modes, msb/lsb first, bits per
    word in 4-24 range).
    
    As the SPI clock of the controller depends on main input clock that shall
    be configured externally, platform data structure for au1550 SPI controller
    driver contains mainclk_hz attribute to define the input clock rate.  From
    this value, dividers of the controller for SPI clock are set up for
    required frequency.
    
    Signed-off-by: Jan Nikitenko <jan.nikitenko@gmail.com>
    
    Whitespace and section fixups.  Remove partial workaround for platform
    setup bug in dma_mask setup; it couldn't work with multiple controllers.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 33e34dc6ee2cb2cf2d50e65c5b825d9ebb8b9e66
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:32:21 2007 -0700

    SPI kerneldoc
    
    Various documentation updates for the SPI infrastructure, to clarify things
    that may not have been clear, to cope with lack of editing, and fix
    omissions.
    
    Also, plug SPI into the kernel-api DocBook template, and fix all the
    resulting glitches in document generation.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 814a8d50eb1d88cedcef97567be53ee0d4512631
Author: Andrea Paterniani <a.paterniani@swapp-eng.it>
Date:   Tue May 8 00:32:15 2007 -0700

    /dev/spidevB.C interface
    
    Add a filesystem API for <linux/spi/spi.h> stack.  The initial version of
    this interface is purely synchronous.
    
    dbrownell@users.sourceforge.net:
    
     Cleaned up, bugfixed; much simplified; added preliminary documentation.
    
     Works with mdev given CONFIG_SYSFS_DEPRECATED; and presumably udev.
    
     Updated SPI_IOC_MESSAGE ioctl to full spi_message semantics, supporting
     groups of one or more transfers (each of which may be full duplex if
     desired).
    
     This is marked as EXPERIMENTAL with an explicit disclaimer that the API
     (notably the ioctls) is subject to change.
    
    Signed-off-by: Andrea Paterniani <a.paterniani@swapp-eng.it>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 735ce95e6b9a262d1fbc0ddb5620deb3a29d1067
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:32:13 2007 -0700

    minor spi_butterfly cleanup
    
    Simplify the spi_butterfly driver by removing incomplete/unused support for
    the second SPI bus, implemented by the USI controller.  This should make
    this a clearer example of how to write a parport bitbang driver.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fef92c30d48a9c610e35af6b218db03f770f3c65
Author: Josh Boyer <jwboyer@gmail.com>
Date:   Tue May 8 00:32:10 2007 -0700

    8250: Remove commented out irq cruft
    
    Remove some obviously old interrupt disable/enable code that has been
    commented out.
    
    Signed-off-by: Josh Boyer <jwboyer@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0e82d5b61841f2b9e2d31a4299ce09752c5d3288
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:08 2007 -0700

    use mutex instead of semaphore for misc char devices
    
    The misc character device driver uses a semaphore as mutex.  Use the mutex API
    instead of the (binary) semaphore.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6acc369a43ada9b829b3e1e4daef5c8a52a2d39a
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:05 2007 -0700

    use mutex instead of semaphore in hdaps driver
    
    The hdaps driver uses a semaphore as mutex.  Use the mutex API instead of the
    (binary) semaphore.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Cc: Robert Love <rlove@rlove.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d081d470446900473f2f32b9203827809b8134f0
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:02 2007 -0700

    use mutex instead of semaphore in TPM driver
    
    The TPM driver uses two semaphores as mutexes.  Use the mutex API instead of
    the (binary) semaphores.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Cc: Kylene Hall <kjhall@us.ibm.com>
    Cc: Marcel Selhorst <tpm@selhorst.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 69f545ea6aa9cf0a1b2e31b287e17f4cd9eb6d93
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue May 8 00:32:00 2007 -0700

    use mutex instead of semaphore in RocketPort driver
    
    The RocketPort driver uses a semaphore as mutex.  Use the mutex API instead of
    the (binary) semaphore.
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6bdb6b620e335d38ced8d5981e8f44778225c1d8
Author: Stas Sergeev <stsp@aknet.ru>
Date:   Tue May 8 00:31:58 2007 -0700

    export hrtimer_forward
    
    Other symbols of the hrtimers API are already exported.
    
    Signed-off-by: Stas Sergeev <stsp@aknet.ru>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b140f25108a8b11aa4903014814988549838b324
Author: Alexey Kuznetsov <alexey@openvz.org>
Date:   Tue May 8 00:31:57 2007 -0700

    Invalid return value of execve() resulting in oopses
    
    When elf loader fails to map executable (due to memory shortage or because
    binary is malformed), it can return 0.  Normally, this is invisible because
    process is killed with SIGKILL and it never returns to user space.
    
    But if exec() is called from kernel thread (hotplug, whatever)
    consequences are more interesting and vary depending on architecture.
    
    i386.   Nothing especially interesting, execve() just returns
            with "success"  :-)
    
    x86_64. Fake zero frame is used on way to caller, RSP/RIP are loaded
            with zeros, ergo... double fault.
    
    ia64.   Similar to i386, but r32...r95 are corrupted. Sometimes it
            oopses due to return to zero PC, sometimes it sees NaT in
            rXX and oopses due to NaT consumption.
    
    Signed-off-by: Alexey Kuznetsov <alexey@openvz.org>
    Signed-off-by: Kirill Korotaev <dev@openvz.org>
    Signed-off-by: Pavel Emelianov <xemul@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ce0be1273d1473a5a7b57bf0b4995b40c22d6b54
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Tue May 8 00:31:55 2007 -0700

    clockchips.h: kernel-doc fix
    
    Fix misnamed fields of 'struct clock_event_device' in the kernel-doc
    comment.  Convert the acronyms to uppercase, while at it...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 58235413b24d5e5245685b84a4efe1ebc95f7886
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:31:53 2007 -0700

    docbook: librs typo fixes
    
    librs docbook typo fixes.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit acd64b737567d88a907bb09d7e982ac5e6ad6a7b
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Tue May 8 00:31:51 2007 -0700

    hide spinlock in linux/quota.h behind __KERNEL__
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    Acked-by: Jan Kara <jack@ucw.cz>
    Cc: David Woodhouse <dwmw2@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6d4d8c0aa255c7b4bdf0fb693ec015b56204bbb3
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Tue May 8 00:31:49 2007 -0700

    Add taskstats.h to kbuild
    
    Add taskstats.h to include/linux/Kbuild, make headers_install would then
    pickup taskstats.h.  This needs to be done as taskstats.h is a user
    interface header.
    
    Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>
    Cc: Don Zickus <dzickus@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 62eb5b1f3bb842d4ea112a5dbae0ce94aab088c4
Author: Paul Fulghum <paulkf@microgate.com>
Date:   Tue May 8 00:31:48 2007 -0700

    synclink_gt use dynamic tty device registration
    
    Change synclink_gt driver to use dynamic tty device registration.
    
    Signed-off-by: Paul Fulghum <paulkf@microgate.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cef2cf07273d12ac3453d2baff096423f17b7403
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:31:45 2007 -0700

    Misc: add sensable phantom driver
    
    Add sensable phantom driver
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6f7f02e78a75a09195d963e0392b195bc2d55c5c
Author: David Rientjes <rientjes@google.com>
Date:   Tue May 8 00:31:43 2007 -0700

    cpusets: allow empty {cpus,mems}_allowed to be set for unpopulated cpuset
    
    You currently cannot remove all cpus or mems from cpus_allowed or
    mems_allowed of a cpuset.  We now allow both if there are no attached
    tasks.
    
    Acked-by: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Paul Menage <menage@google.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0c28f287aa57e065116731c1e44bedcbc14fd53f
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Tue May 8 00:31:41 2007 -0700

    procfs: use simple_read_from_buffer()
    
    Cleanup using simple_read_from_buffer() in procfs.
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 346339938ba9bcabd34e5fc8f4b0b0665c507a22
Author: Simon Horman <horms@verge.net.au>
Date:   Tue May 8 00:31:40 2007 -0700

    Update the list information for kexec and kdump
    
    There is a new list for kexec/kdump discussion.
    
    Signed-off-by: Simon Horman <horms@verge.net.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a2f72982e22b96862f8f15272732bd316d4db040
Author: dann frazier <dannf@hp.com>
Date:   Tue May 8 00:31:39 2007 -0700

    old buffer overflow in moxa driver
    
    I noticed that the moxa input checking security bug described by
    CVE-2005-0504 appears to remain unfixed upstream.
    
    The issue is described here:
      http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-0504
    
    Debian has been shipping the following patch from Andres Salomon.
    
    (akpm: it's a privileged operation)
    
    Signed-off-by: dann frazier <dannf@hp.com>
    Signed-off-by: Andres Salomon <dilinger@debian.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 83ae1b79c898838e16ac8cde69b39d22d36fb035
Author: Andreas Schwab <schwab@suse.de>
Date:   Tue May 8 00:31:38 2007 -0700

    Fix error handling in HDIO_GETGEO compat wrapper
    
    Don't clobber error from sys_ioctl in HDIO_GETGEO compat wrapper.
    
    Signed-off-by: Andreas Schwab <schwab@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a3e0975684337738997771416535d0e5d6fa27cd
Author: Zach Carter <linux@zachcarter.com>
Date:   Tue May 8 00:31:35 2007 -0700

    laptop-mode URL update
    
    Signed-off-by: Zach Carter <linux@zachcarter.com>
    Cc: Bart Samwel <bart@samwel.tk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8890ccf8feb65f18596b1de86fb806ad7182d382
Author: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
Date:   Tue May 8 00:31:32 2007 -0700

    doc: fix oops-tracing duplicate
    
    Remove duplicate 'U' entry -- fix mis-merge.
    
    Signed-off-by: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c007c06e3cccf6d80de7f97242da1c3146c431b2
Author: Stephen Mollett <molletts@yahoo.com>
Date:   Tue May 8 00:31:31 2007 -0700

    udf: decrement correct link count in udf_rmdir
    
    It appears that a minor thinko occurred in udf_rmdir and the
    (already-cleared) link count on the directory that is being removed was
    being decremented instead of the link count on its parent directory.  This
    gives rise to lots of kernel messages similar to:
    
    UDF-fs warning (device loop1): udf_rmdir: empty directory has nlink != 2 (8)
    
    when removing directory trees.  No other ill effects have been observed but
    I guess it could theoretically result in the link count overflowing on a
    very long-lived, much modified directory.
    
    Signed-off-by: Stephen Mollett <molletts@yahoo.com>
    Cc: Dave Hansen <haveblue@us.ibm.com>
    Cc: Jan Kara <jack@ucw.cz>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c483bab099cb89e92b7cad94a52fcdaf37e56657
Author: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Date:   Tue May 8 00:31:28 2007 -0700

    fat: fix VFAT compat ioctls on 64-bit systems
    
    If you compile and run the below test case in an msdos or vfat directory on
    an x86-64 system with -m32 you'll get garbage in the kernel_dirent struct
    followed by a SIGSEGV.
    
    The patch fixes this.
    
    Reported and initial fix by Bart Oldeman
    
    #include <sys/types.h>
    #include <sys/ioctl.h>
    #include <dirent.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    struct kernel_dirent {
             long            d_ino;
             long		d_off;
             unsigned short  d_reclen;
             char            d_name[256]; /* We must not include limits.h! */
    };
    #define VFAT_IOCTL_READDIR_BOTH  _IOR('r', 1, struct kernel_dirent [2])
    #define VFAT_IOCTL_READDIR_SHORT  _IOR('r', 2, struct kernel_dirent [2])
    
    int main(void)
    {
             int fd = open(".", O_RDONLY);
             struct kernel_dirent de[2];
    
             while (1) {
                     int i = ioctl(fd, VFAT_IOCTL_READDIR_BOTH, (long)de);
                     if (i == -1) break;
                     if (de[0].d_reclen == 0) break;
                     printf("SFN: reclen=%2d off=%d ino=%d, %-12s",
     		       de[0].d_reclen, de[0].d_off, de[0].d_ino, de[0].d_name);
     		if (de[1].d_reclen)
     		  printf("\tLFN: reclen=%2d off=%d ino=%d, %s",
     		    de[1].d_reclen, de[1].d_off, de[1].d_ino, de[1].d_name);
     		printf("\n");
             }
             return 0;
    }
    
    Signed-off-by: Bart Oldeman <bartoldeman@users.sourceforge.net>
    Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b247e8aaf2837715d31eb25828fa8b4eb0a659cd
Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Date:   Tue May 8 00:31:25 2007 -0700

    dma_declare_coherent_memory wrong allocation
    
    dma_declare_coherent_memory() allocates a bitmap 1 bit per page, it
    calculates the bitmap size based on size of long, but allocates bytes...
    Thanks to James Bottomley for clarifications and corrections.
    
    Signed-off-by: G. Liakhovetski <g.liakhovetski@gmx.de>
    Acked-by: James Bottomley <James.Bottomley@SteelEye.com>
    Cc: Mikael Starvik <starvik@axis.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f19b121e21c1b032f6c612d2b9b499151f7b661b
Author: akpm@linux-foundation.org <akpm@linux-foundation.org>
Date:   Tue May 8 00:31:22 2007 -0700

    Driver for the Maxim DS1WM, a 1-wire bus master ASIC core
    
    Cc: Matt Reimer <mreimer@vpop.net>
    
    [akpm@linux-foundation.org: kconfig update]
    Signed-off-by: Matt Reimer <mreimer@vpop.net>
    Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c1f858b763de570a4ab119ade7b24ccbc8fad23a
Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Date:   Tue May 8 00:31:20 2007 -0700

    w1: allow bus master to have reset and byte ops
    
    Signed-off-by: Matt Reimer <mreimer@vpop.net>
    Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 60ed34be8de04cc8082a163a665e01682c7bc937
Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Date:   Tue May 8 00:31:19 2007 -0700

    W1 printk format warning fix
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 794543a236074f49a8af89ef08ef6a753e4777e5
Author: Alistair John Strachan <s0348365@sms.ed.ac.uk>
Date:   Tue May 8 00:31:15 2007 -0700

    Move LOG_BUF_SHIFT to a more sensible place
    
    Several people have observed that perhaps LOG_BUF_SHIFT should be in a more
    obvious place than under DEBUG_KERNEL. Under some circumstances (such as the
    PARISC architecture), DEBUG_KERNEL can increase kernel size, which is an
    undesirable trade off for something as trivial as increasing the kernel log
    buffer size.
    
    Instead, move LOG_BUF_SHIFT into "General Setup", so that people are more
    likely to be able to change it such a circumstance that the default buffer
    size is insufficient.
    
    Signed-off-by: Alistair John Strachan <s0348365@sms.ed.ac.uk>
    Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 63f6564d351fb2e7222e43b6dd22737edf9f4a91
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:31:14 2007 -0700

    x86_64: kill 19000+ sparse warnings
    
    Eliminate 19439 (!!) sparse warnings like:
    include/linux/mm.h:321:22: warning: constant 0xffff810000000000 is so big it is unsigned long
    
    Eliminate 56 sparse warnings like:
    arch/x86_64/kernel/setup.c:248:16: warning: constant 0xffffffff80000000 is so big it is unsigned long
    
    Eliminate 5 sparse warnings like:
    arch/x86_64/kernel/module.c:49:13: warning: constant 0xfffffffffff00000 is so big it is unsigned long
    
    Eliminate 23 sparse warnings like:
    arch/x86_64/mm/init.c:551:37: warning: constant 0xffffc20000000000 is so big it is unsigned long
    
    Eliminate 6 sparse warnings like:
    arch/x86_64/kernel/module.c:49:13: warning: constant 0xffffffff88000000 is so big it is unsigned long
    
    Eliminate 23 sparse warnings like:
    arch/x86_64/mm/init.c:552:6: warning: constant 0xffffe1ffffffffff is so big it is unsigned long
    
    Eliminate 3 sparse warnings like:
    arch/x86_64/kernel/e820.c:186:17: warning: constant 0x3fffffffffff is so big it is long
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6df95fd7ad9a842c1688d2b83bdcb7c82e9c8630
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:31:11 2007 -0700

    consolidate asm/const.h to linux/const.h
    
    Make a global linux/const.h header file instead of having multiple,
    per-arch files, and convert current users of asm/const.h to use
    linux/const.h.
    
    Built on x86_64 and sparc64.
    
    [akpm@linux-foundation.org: fix include/asm-x86_64/Kbuild]
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8e39c933b1b7df501dbb68879fb1640e277b8a5c
Author: Parag Warudkar <pwarudkar@aol.com>
Date:   Tue May 8 00:31:09 2007 -0700

    tpm: fix sleep-in-spinlock
    
    flush_scheduled_work() can sleep, and we're calling it under spinlock.
    
    AFAICS, moving flush_scheduled_work before spin_lock() should not cause any
    problems.
    
    Reason being - The only thing that can race against tpm_release is tpm_open
    (tpm_release is called when last reference to the file is closed and only
    thing that can happen after that is tpm_open??) and tpm_open acquires
    driver_lock and more over it bails out with EBUSY if chip->num_opens is
    greater than 0.
    
    I also moved chip->num_pending-- to after deleting timer and setting data
    pending as it looks more correct for the paranoid although it probably doesn't
    matter as it is guarded by driver_lock.  None the less this change should not
    cause problems.
    
    While I was at it I noticed a missing NULL check in tpm_register_hardware
    which is fixed with this patch as well.
    
    Signed-off-by: Parag Warudkar <parag.warudkar@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 53ab97a1c1536015d4d6d900363ea96fece5ed97
Author: Jesper Juhl <jesper.juhl@gmail.com>
Date:   Tue May 8 00:31:06 2007 -0700

    Fix chapter reference in CodingStyle
    
    commit 226a6b84aaaf1fac7a5d41cf4e7387fd9ba895d5 renumbered Chapter 11 in
    Documentation/CodingStyle to Chapter 12, but it didn't update the reference
    to that chapter further down in the file.  This patch corrects the chapter
    reference.
    
    Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4f99ed67cc1cf5302ea18aa042d75641b61a0a1b
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:31:04 2007 -0700

    ext3: copy i_flags to inode flags on write
    
    Propagate flags such as S_APPEND, S_IMMUTABLE, etc.  from i_flags into
    ext2-specific i_flags.  Hence, when someone sets these flags via a different
    interface than ioctl, they are stored correctly.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28ec039c21839914389975b896160a815ffd8b83
Author: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Date:   Tue May 8 00:31:01 2007 -0700

    fat: don't use free_clusters for fat32
    
    It seems that the recent Windows changed specification, and it's
    undocumented.  Windows doesn't update ->free_clusters correctly.
    
    This patch doesn't use ->free_clusters by default.  (instead, add "usefree"
    for forcing to use it)
    
    Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
    Cc: Juergen Beisert <juergen127@kreuzholzen.de>
    Cc: Andreas Schwab <schwab@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4ff773bbde87f7f7dddc0f579ad53e077a6587b9
Author: Jarek Poplawski <jarkao2@o2.pl>
Date:   Tue May 8 00:31:00 2007 -0700

    lockdep: removed unused ip argument in mark_lock & mark_held_locks
    
    It looks like a remainder from designing...
    
    Signed-off-by: Jarek Poplawski <jarkao@o2.pl>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0bb5e19d63cc1b09aed8aef3a20926ac435bb8e7
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 00:30:57 2007 -0700

    Clean up mostly unused IOSPACE macros
    
    Most architectures defined three macros, MK_IOSPACE_PFN(), GET_IOSPACE()
    and GET_PFN() in pgtable.h.  However, the only callers of any of these
    macros are in Sparc specific code, either in arch/sparc, arch/sparc64 or
    drivers/sbus.
    
    This patch removes the redundant macros from all architectures except
    sparc and sparc64.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Cc: <linux-arch@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 53f049fa5f18730b61faaee582ea0e045fd44f49
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Tue May 8 00:30:54 2007 -0700

    kill warnings when building mandocs
    
    This patch shuts warnings of the sort:
    
    make -C /mnt/samsung_200/sam/kernel/trees/21-rc6/build \
    	KBUILD_SRC=/mnt/samsung_200/sam/kernel/trees/21-rc6 \
    	KBUILD_EXTMOD="" -f /mnt/samsung_200/sam/kernel/trees/21-rc6/Makefile mandocs
    make -f /mnt/samsung_200/sam/kernel/trees/21-rc6/scripts/Makefile.build obj=scripts/basic
    make -f /mnt/samsung_200/sam/kernel/trees/21-rc6/scripts/Makefile.build obj=Documentation/DocBook mandocs
      SRCTREE=/mnt/samsung_200/sam/kernel/trees/21-rc6/ /mnt/samsung_200/sam/kernel/trees/21-rc6/build/scripts/basic/docproc doc /mnt/samsung_200/sam/kernel/trees/21-rc6/Documentation/DocBook/wanbook.tmpl >Documentation/DocBook/wanbook.xml
      if grep -q refentry Documentation/DocBook/wanbook.xml; then xmlto man -m /mnt/samsung_200/sam/kernel/trees/21-rc6/Documentation/DocBook/stylesheet.xsl -o Documentation/DocBook/man Documentation/DocBook/wanbook.xml ; gzip -f Documentation/DocBook/man/*.9; fi
    Note: meta version: No productnumber or alternative     sppp_close
    Note: meta version: No refmiscinfo@class=version        sppp_close
    Note: Writing sppp_close.9
    Note: meta version: No productnumber or alternative     sppp_open
    Note: meta version: No refmiscinfo@class=version        sppp_open
    
    by adding a RefMiscInfo xml tag in the form of the current kernel version
    to the function, struct and enum definitions in files included by
    kernel-doc when building 'mandocs'.  However, the version string appears
    truncated on the manpage due to some constraints in the xml DTD for the man
    header, I believe, for the troff output is truncated too.
    
    Signed-off-by: Borislav Petkov <bbpetkov@yahoo.de>
    Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cc0a8fbb7ce00f65dc337dd91389b7151f44ed30
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:30:52 2007 -0700

    drivers/char: use __set_current_state()
    
    use __set_current_state(TASK_*) instead of current->state = TASK_*,
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5ab2f7e0fdd04148e08348701d6bd6a292ce2d26
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:30:51 2007 -0700

    reiserfs: use __set_current_state()
    
    use __set_current_state(TASK_*) instead of current->state = TASK_*, in
    fs/reiserfs
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: <reiserfs-dev@namesys.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 35bab756b49bd148760a3bbd3c907cd74754dbb4
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:30:49 2007 -0700

    The scheduled -EINVAL for invalid timevals in setitimer
    
    As scheduled, do_setitimer() now returns -EINVAL for invalid timeval.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b3561ea9462b33a0bf824b4ca19a1ae84db81210
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 00:30:46 2007 -0700

    Clean up mutex_trylock noise
    
    Ingo Molnar's semaphore to mutex conversions left some noise on a few
    trylock calls. Clean it up.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: David Woodhouse <dwmw2@infradead.org>
    Cc: Mauro Carvalho Chehab <mchehab@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 97f067846786d255888ccad14e2f38a1f63d8e9b
Author: Pavel Emelianov <xemul@sw.ru>
Date:   Tue May 8 00:30:42 2007 -0700

    jbd: check for error returned by kthread_create on creating journal thread
    
    If the thread failed to create the subsequent wait_event will hang forever.
    
    This is likely to happen if kernel hits max_threads limit.
    
    Will be critical for virtualization systems that limit the number of tasks
    and kernel memory usage within the container.
    
    (akpm: JBD should be converted fully to the kthread API: kthread_should_stop()
    and kthread_stop()).
    
    Cc: <linux-ext4@vger.kernel.org>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ee6f958291e2a768fd727e7a67badfff0b67711a
Author: Miklos Szeredi <mszeredi@suse.cz>
Date:   Tue May 8 00:30:40 2007 -0700

    check privileges before setting mount propagation
    
    There's a missing check for CAP_SYS_ADMIN in do_change_type().
    
    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2f1a2ccb9c0de632ab07193becf5f7121794f6ae
Author: Egmont Koblinger <egmont@uhulinux.hu>
Date:   Tue May 8 00:30:37 2007 -0700

    console UTF-8 fixes
    
    The UTF-8 part of the vt driver suffers from the following issues which are
    addressed in my patch:
    
    1) If there's no glyph found for a particular valid UTF-8 character, we try
       to display U+FFFD. However if this one is not found either, here's what
       the current kernel does:
    
       - First, if the Unicode value is less than the number of glyphs, use the
         glyph directly from that position of the glyph table. While it may be a
         good idea in the 8-bit world, it has absolutely no sense with Unicode
         in mind. For example, if a Latin-2 font is loaded and an application
         prints U+00FB ("u with circumflex", not present in Latin-2) then as a
         fallback solution the glyph from the 0xFB position of the Latin-2
         fontset (which is an "u with double accent" - a different character) is
         displayed.
    
       - Second, if this fallback fails too, a simple ASCII question mark is
         printed, which is visually undistinguishable from a real question mark.
    
       I changed the code to skip the first step (except if in non-UTF-8 mode),
       and changed the second step to print the question mark with inverse color
       attributes, so it is visually clear that it's not a real question mark,
       and resembles more to the common glyph of U+FFFD.
    
    2) The UTF-8 decoder is buggy in many ways:
    
       - Lone continuation bytes (section 3.1 of Markus Kuhn's UTF-8 stress
         test) are not caught, they are displayed as some "random" (taken
         directly form the font table, see above) glyphs instead the replacement
         character.
    
       - Incomplete sequences (sections 3.2 and 3.3 of the stress test) emit no
         replacement character, but rather cause the subsequent valid character
         to be displayed more times(!).
    
       - The decoder is not safe: overlong sequences are not caught currently,
         they are displayed as if these were valid representations. This may
         even have security impacts.
    
       - The decoder does not handle D800..DFFF and FFFE..FFFF specially, it
         just emits these code points and lets it be looked up in the glyph
         table. Since these are invalid code points, I replace them by U+FFFD
         and hence give no chance for them to be looked up in the glyph table.
         (Assuming no font ships glyphs for these code points, this change is
         not visible to the users since the glyph shown will be the same.)
    
       With my fixes to the decoder it now behaves exactly as Markus Kuhn's
       stress test recommends.
    
    3) It has no concept of double-width (CJK) characters. It's way beyond the
       scope of my patch to try to display them, but at least I think it's
       important for the cursor to jump two positions when printing such
       characters, since this is what applications (such as text editors)
       expect. Currently the cursor only jumps one position, and hence
       applications suffer from displaying and refreshing problems, and editing
       some English letters that are preceded by some CJK characters in the same
       line is a nightmare. With my patch an additional space is inserted after
       the CJK character has been printed (which usually means a replacement
       symbol of course). (If U+FFFD isn't availble and hence an inverse
       question mark is displayed in the first cell, I keep the inverted state
       for the space in the 2nd column so it's quite easy to see that they are
       tied together.)
    
    4) There is a small built-in table of zero-width spaces that are not to be
       printed but silently skipped. U+200A is included there, but it's not a
       zero-width character, so I remove it from there.
    
    Signed-off-by: Egmont Koblinger <egmont@uhulinux.hu>
    Cc: Jan Engelhardt <jengelh@linux01.gwdg.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e659ba4a0d2d471c0d73590f78e1a1b5a1eede48
Author: Oliver Neukum <oliver@neukum.org>
Date:   Tue May 8 00:30:34 2007 -0700

    CodingStyle: start flamewar about use of braces
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Cc: Tilman Schmidt <tilman@imap.cc>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28be5abb400e5e082f5225105fdc69337ec0c0b4
Author: Jan Kara <jack@suse.cz>
Date:   Tue May 8 00:30:33 2007 -0700

    ext3: copy i_flags to inode flags on write
    
    A patch that stores inode flags such as S_IMMUTABLE, S_APPEND, etc.  from
    i_flags to EXT3_I(inode)->i_flags when inode is written to disk.  The same
    thing is done on GETFLAGS ioctl.
    
    Quota code changes these flags on quota files (to make it harder for
    sysadmin to screw himself) and these changes were not correctly propagated
    into the filesystem (especially, lsattr did not show them and users were
    wondering...).
    
    Propagate flags such as S_APPEND, S_IMMUTABLE, etc.  from i_flags into
    ext3-specific i_flags.  Hence, when someone sets these flags via a
    different interface than ioctl, they are stored correctly.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Cc: <linux-ext4@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9926e4c74300c4b31dee007298c6475d33369df0
Author: Tom Alsberg <alsbergt@cs.huji.ac.il>
Date:   Tue May 8 00:30:31 2007 -0700

    CPU time limit patch / setrlimit(RLIMIT_CPU, 0) cheat fix
    
    As discovered here today, the change in Kernel 2.6.17 intended to inhibit
    users from setting RLIMIT_CPU to 0 (as that is equivalent to unlimited) by
    "cheating" and setting it to 1 in such a case, does not make a difference,
    as the check is done in the wrong place (too late), and only applies to the
    profiling code.
    
    On all systems I checked running kernels above 2.6.17, no matter what the
    hard and soft CPU time limits were before, a user could escape them by
    issuing in the shell (sh/bash/zsh) "ulimit -t 0", and then the user's
    process was not ever killed.
    
    Attached is a trivial patch to fix that.  Simply moving the check to a
    slightly earlier location (specifically, before the line that actually
    assigns the limit - *old_rlim = new_rlim), does the trick.
    
    Do note that at least the zsh (but not ash, dash, or bash) shell has the
    problem of "caching" the limits set by the ulimit command, so when running
    zsh the fix will not immediately be evident - after entering "ulimit -t 0",
    "ulimit -a" will show "-t: cpu time (seconds) 0", even though the actual
    limit as returned by getrlimit(...) will be 1.  It can be verified by
    opening a subshell (which will not have the values of the parent shell in
    cache) and checking in it, or just by running a CPU intensive command like
    "echo '65536^1048576' | bc" and verifying that it dumps core after one
    second.
    
    Regardless of whether that is a misfeature in the shell, perhaps it would
    be better to return -EINVAL from setrlimit in such a case instead of
    cheating and setting to 1, as that does not really reflect the actual state
    of the process anymore.  I do not however know what the ground for that
    decision was in the original 2.6.17 change, and whether there would be any
    "backward" compatibility issues, so I preferred not to touch that right
    now.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a4bb27d99ca2986e30180a0eb143865051b909db
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 8 00:30:28 2007 -0700

    serial_txx9: zap changelog from source code
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 07bafde351470e19168dfc6385ff417e832850c1
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 8 00:30:26 2007 -0700

    serial_txx9: Use assigned device numbers
    
    The serial_txx9 driver have abused device numbers (major 4, minor 128) if
    CONFIG_SERIAL_TXX9_STDSERIAL was not set.  This patch makes the driver use
    proper device numbers assigned for it (major 204, minor 196-203).  I
    suppose a typical user of this driver set CONFIG_SERIAL_TXX9_STDSERIAL to Y
    (i.e.  use "ttyS0"), so this patch would not cause big compatibility issue.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7f76c403751ab917b2ebed5663079a6b2956eebd
Author: Scott Wiersdorf <scott@bluehost.com>
Date:   Tue May 8 00:30:25 2007 -0700

    getdelays.c: fix overrun
    
    A patch for getdelays.c that fixes a buffer overrun when you set -w.
    
    Cc: <matt@bluehost.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d1ab824be43842ae7429ab1df37153e1cebb4d32
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 00:30:22 2007 -0700

    Document SPIN_LOCK_UNLOCKED/RW_LOCK_UNLOCKED deprecation
    
    Apparently it's not cool anymore to use SPIN/RW_LOCK_UNLOCKED.  There's
    some mention of this in Documentation/spinlocks.txt, but that only talks
    about dynamic initialisation.
    
    A comment in the code mentioning the preferred usage would be good IMHO.
    
    [akpm@linux-foundation.org: add reason for deprecation]
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b5e618181a927210f8be1d3d2249d31904ba358d
Author: Pavel Emelianov <xemul@sw.ru>
Date:   Tue May 8 00:30:19 2007 -0700

    Introduce a handy list_first_entry macro
    
    There are many places in the kernel where the construction like
    
       foo = list_entry(head->next, struct foo_struct, list);
    
    are used.
    The code might look more descriptive and neat if using the macro
    
       list_first_entry(head, type, member) \
                 list_entry((head)->next, type, member)
    
    Here is the macro itself and the examples of its usage in the generic code.
     If it will turn out to be useful, I can prepare the set of patches to
    inject in into arch-specific code, drivers, networking, etc.
    
    Signed-off-by: Pavel Emelianov <xemul@openvz.org>
    Signed-off-by: Kirill Korotaev <dev@openvz.org>
    Cc: Randy Dunlap <randy.dunlap@oracle.com>
    Cc: Andi Kleen <andi@firstfloor.org>
    Cc: Zach Brown <zach.brown@oracle.com>
    Cc: Davide Libenzi <davidel@xmailserver.org>
    Cc: John McCutchan <ttb@tentacle.dhs.org>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: john stultz <johnstul@us.ibm.com>
    Cc: Ram Pai <linuxram@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit db9c02fa8bd50eb104781a9f78cae923d8da1e74
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Tue May 8 00:30:17 2007 -0700

    pnpbios: convert to use the kthread API
    
    This patches modifies the pnpbios kernel thread to start with ktrhead_run
    not kernel_thread and deamonize.  Doing this makes the code a little
    simpler and easier to maintain.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1bd0cf1fc78e59e1d2b4e44348a85d39b983c80d
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Tue May 8 00:30:15 2007 -0700

    smbfs: remove unnecessary allow_signal
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f16825bbeb9e6e0970531aa2f21b18b2e8ae9e47
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:30:13 2007 -0700

    Taskstats: fix getdelays usage information
    
    Add usage to getdelays.c. This patch was originally posted by Randy Dunlap
    http://lkml.org/lkml/2007/3/19/168
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Balbir Singh <balbir@in.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9e860d000a90cfc9ca270ddb6e99b177e6aa91cd
Author: Jarek Poplawski <jarkao2@o2.pl>
Date:   Tue May 8 00:30:12 2007 -0700

    lockdep: lookup_chain_cache comment errata
    
    Signed-off-by: Jarek Poplawski <jarkao2@o2.pl>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 076fa0fa2d53046d32f5157022d683b8027f05ed
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:30:10 2007 -0700

    SPIN_LOCK_UNLOCKED cleanup in drivers/serial
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ccc942567e10d6a5d59c4d57f03d07b4110611ea
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:30:09 2007 -0700

    SPIN_LOCK_UNLOCKED cleanup in drivers/char/keyboard
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b32e41bb97971161ad34ea69364c4f9ec3909151
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:30:08 2007 -0700

    SPIN_LOCK_UNLOCKED cleanup in init_task.h
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6c080f1a93591500299a514ef63209079ff007ac
Author: Stephen M. Cameron <steve.cameron@hp.com>
Date:   Tue May 8 00:30:05 2007 -0700

    Documentation: cciss: detecting failed drives
    
    Document how to detect drive failures for cciss
    
    Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d3ed782458f315c30ea679b919a2cc59f2b82565
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Tue May 8 00:30:03 2007 -0700

    highres/dyntick: prevent xtime lock contention
    
    While the !highres/!dyntick code assigns the duty of the do_timer() call to
    one specific CPU, this was dropped in the highres/dyntick part during
    development.
    
    Steven Rostedt discovered the xtime lock contention on highres/dyntick due
    to several CPUs trying to update jiffies.
    
    Add the single CPU assignement back.  In the dyntick case this needs to be
    handled carefully, as the CPU which has the do_timer() duty must drop the
    assignement and let it be grabbed by another CPU, which is active.
    Otherwise the do_timer() calls would not happen during the long sleep.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: Steven Rostedt <rostedt@goodmis.org>
    Acked-by: Mark Lord <mlord@pobox.com>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d5d3b736e3264934ec832a657a9a434b65f3d51f
Author: Stephen Cameron <steve.cameron@hp.com>
Date:   Tue May 8 00:30:02 2007 -0700

    cciss: include scsi/scsi.h unconditionally
    
    Make cciss unconditionally include scsi/scsi.h, because of the use of
    SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER.
    
    Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c9919380187e8182ac449652094c345c82dce0c3
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Tue May 8 00:29:58 2007 -0700

    apm: fix incorrect comment
    
    HZ has not always been 100Hz for some time.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 873ec746158403af82c57ce26780166aafc159e1
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Tue May 8 00:29:57 2007 -0700

    EFI: warn only for pre-1.00 system tables
    
    We used to warn unless the EFI system table major revision was exactly 1.
    But EFI 2.00 firmware is starting to appear, and the 2.00 changes don't
    affect anything in Linux.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f038f9a361a764ed013447174b7170073f89cbe9
Author: Andi Kleen <ak@novell.com>
Date:   Tue May 8 00:29:55 2007 -0700

    Add keyboard blink driver
    
    Simple driver that blinks the keyboard LEDs when loaded.  Useful for
    checking that the kernel is still alive or for crashdumping
    
    Signed-off-by: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6b9686211374a9751ae70a95fd1fcfb8c2a80698
Author: Miguel Ojeda <maxextreme@gmail.com>
Date:   Tue May 8 00:29:54 2007 -0700

    Add webpages' URL and summarize 3 lines.
    
    CREDITS:
     - Summarize 3 lines into one.
     - Add webpage.
    
    MAINTAINERS:
     - Add auxdisplay drivers/tree webpages.
    
    Signed-off-by: Miguel Ojeda Sandonis <maxextreme@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3eb014a103701bedfaa11bc321f470e918c71ff7
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:29:51 2007 -0700

    kernel-doc: html mode struct highlights
    
    Johannes Berg reported that struct names are not highlighted
    (bold, italic, etc.) in html kernel-doc output.  (Also not in
    text-mode output, but I don't see that changing.)
    
    This patch adds the following:
    - highlight struct names in html output mode
    - highlight environment var. names in html output mode
    - indent struct fields in the original struct layout
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Cc: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3361c7bebbf207f57f3dd1282cd87e1e37c082ac
Author: Jeffrey Layton <jlayton@redhat.com>
Date:   Tue May 8 00:29:48 2007 -0700

    make iunique use a do/while loop rather than its obscure goto loop
    
    A while back, Christoph mentioned that he thought that iunique ought to be
    cleaned up to use a more conventional loop construct. This patch does that,
    turning the strange goto loop into a do/while.
    
    Signed-off-by: Jeff Layton <jlayton@redhat.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9d0633cfedde484d30eef869f749c04709ab3e42
Author: John Johansen <jjohansen@suse.de>
Date:   Tue May 8 00:29:44 2007 -0700

    Remove redundant check from proc_sys_setattr()
    
    notify_change() already calls security_inode_setattr() before
    calling iop->setattr.
    
    Alan sayeth
    
      This is a behaviour change on all of these and limits some behaviour of
      existing established security modules
    
      When inode_change_ok is called it has side effects.  This includes
      clearing the SGID bit on attribute changes caused by chmod.  If you make
      this change the results of some rulesets may be different before or after
      the change is made.
    
      I'm not saying the change is wrong but it does change behaviour so that
      needs looking at closely (ditto all other attribute twiddles)
    
    Signed-off-by: Steve Beattie <sbeattie@suse.de>
    Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
    Signed-off-by: John Johansen <jjohansen@suse.de>
    Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
    Cc: James Morris <jmorris@namei.org>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1e8123fdeda6b2b9e96f2ec56e7bed27a303d3eb
Author: John Johansen <jjohansen@suse.de>
Date:   Tue May 8 00:29:41 2007 -0700

    Remove redundant check from proc_setattr()
    
    notify_change() already calls security_inode_setattr() before
    calling iop->setattr.
    
    Signed-off-by: Tony Jones <tonyj@suse.de>
    Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
    Signed-off-by: John Johansen <jjohansen@suse.de>
    Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
    Cc: James Morris <jmorris@namei.org>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 49a4ec188f9a96c9a5567956718213d38a456a19
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:29:39 2007 -0700

    fix hotplug for legacy platform drivers
    
    We've had various reports of some legacy "probe the hardware" style
    platform drivers having nasty problems with hotplug support.
    
    The core issue is that those legacy drivers don't fully conform to the
    driver model.  They assume a role that should be the responsibility of
    infrastructure code: creating device nodes.
    
    The "modprobe" step in hotplugging relies on drivers to have split those
    roles into different modules.  The lack of this split causes the problems.
    When a driver creates nodes for devices that don't exist (sending a hotplug
    event), then exits (aborting one modprobe) before the "modprobe $MODALIAS"
    step completes (by failing, since it's in the middle of a modprobe), the
    result can be an endless loop of modprobe invocations ...  badness.
    
    This fix uses the newish per-device flag controlling issuance of "add"
    events.  (A previous version of this patch used a per-device "driver can
    hotplug" flag, which only scrubbed $MODALIAS from the environment rather
    than suppressing the entire hotplug event.) It also shrinks that flag to
    one bit, saving a word in "struct device".
    
    So the net of this patch is removing some nasty failures with legacy
    drivers, while retaining hotplug capability for the majority of platform
    drivers.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Greg KH <gregkh@suse.de>
    Cc: Andres Salomon <dilinger@debian.org>
    Cc: Dominik Brodowski <linux@dominikbrodowski.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit eb81d93046e7de51d47b8f1303d80e6f51ac9e33
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Tue May 8 00:29:36 2007 -0700

    kernel-doc: generate main index page when building 'htmldocs'
    
    A patch for kernel-doc that enables the generation of a global, TOC-like
    index.html page after building 'htmldocs'
    
    Signed-off-by: Borislav Petkov <bbpetkov@yahoo.de>
    Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 198b766013e680a9e367aeb0d62f402029868a09
Author: Mike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net>
Date:   Tue May 8 00:29:34 2007 -0700

    cciss: set rq->errors more correctly in driver
    
    Set rq->errors more correctly in cciss driver.  Previously we had set it
    synonymously with the meaning of the last parameter of end_that_last_request
    and complete_buffers (the "uptodate" parameter) and had gotten away with it
    for all this time because nobody ever looked at rq->errors.
    SCSI_IOCTL_SEND_COMMAND looks at rq->errors, so now it matters that it be
    right.
    
    Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
    Signed-off-by: Mike Miller <mike.miller@hp.com>
    Cc: James Bottomley <James.Bottomley@steeleye.com>
    Cc: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 03bbfee58d440f5dc2e880944ab75fc644534794
Author: Mike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net>
Date:   Tue May 8 00:29:32 2007 -0700

    cciss: add SG_IO ioctl to cciss
    
    For all of you that think cciss should be a scsi driver here is the patch that
    you have been waiting for all these years. This patch actually adds the SG_IO
    ioctl to cciss. The primary purpose is for clustering and high-availibilty.
    But now anyone can exploit this ioctl in any manner they wish.
    
    Note, SCSI_IOCTL_SEND_COMMAND doesn't work with this patch due to rq->errors
    being set incorrectly.  Subsequent patch fixes that.
    
    Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
    Signed-off-by: Mike Miller <mike.miller@hp.com>
    Cc: James Bottomley <James.Bottomley@steeleye.com>
    Cc: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d38ae168bfde9195466b9d45cb1126a657c10942
Author: Mike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net>
Date:   Tue May 8 00:29:29 2007 -0700

    cciss: reformat error handling
    
    Reformat some error handling code to reduce line lengths a bit.
    
    Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
    Signed-off-by: Mike Miller <mike.miller@hp.com>
    Cc: James Bottomley <James.Bottomley@steeleye.com>
    Cc: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 09f0892ec7f8068ba1d1fcef4d1fca23ec96e0dd
Author: Martin Peschke <mp3@de.ibm.com>
Date:   Tue May 8 00:29:26 2007 -0700

    proc: cleanup: use seq_release_private() where appropriate
    
    We can save some lines of code by using seq_release_private().
    
    Signed-off-by: Martin Peschke <mp3@de.ibm.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5a0c6a0d1ae97473291f479ef64573d6b2c0e2d5
Author: Martin Peschke <mp3@de.ibm.com>
Date:   Tue May 8 00:29:25 2007 -0700

    kallsyms: cleanup: use seq_release_private() where appropriate
    
    We can save some lines of code by using seq_release_private().
    
    Signed-off-by: Martin Peschke <mp3@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6272e2667965dfb5b59199f462cd0f001fb304a6
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:29:21 2007 -0700

    cleanup compat ioctl handling
    
    Merge all compat ioctl handling into compat_ioctl.c instead of splitting it
    over compat.c and compat_ioctl.c.  This also allows to get rid of ioctl32.h
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Looks-good-to: Andi Kleen <ak@suse.de>
    Acked-by: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 039b6b3ed84e45a6f8316358dd2bfdc83d59fc45
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:29:20 2007 -0700

    audit: add spaces on either side of case "..." operator.
    
    Following the programming advice laid down in the gcc manual, make
    sure the case "..." operator has spaces on either side.
    
    According to:
    
    http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Case-Ranges.html#Case-Ranges:
    
      "Be careful: Write spaces around the ..., for otherwise it may be
    parsed wrong when you use it with integer values."
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b2bbe383ef7e792e92a5f53be955e71bd253ab32
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Tue May 8 00:29:18 2007 -0700

    dtlk: fix error checks in module_init()
    
    This patch fixes two things in module_init.
    
    - fix register_chrdev() error check
    
      Currently dtlk doesn't check register_chrdev() failure correctly.
      register_chrdev() returns a errno on failure.
    
    - check probe failure
    
      dtlk ignores probe failure and allows the module loading without
      such device. I got "Trying to free nonexistent resource" message
      by release_region() when unloading module without device.
    
    [akpm@linux-foundation.org: fix error code return]
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Cc: Chris Pallotta <chris@allmedia.com>
    Cc: Jim Van Zandt <jrv@vanzandt.mv.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 19d0e8ce856a7628a630710aed82931ce1c7eb97
Author: Philippe De Muyter <phdm@macqel.be>
Date:   Tue May 8 00:29:15 2007 -0700

    partition: add support for sysv68 partitions
    
    Add support for the Motorola sysv68 disk partition (slices in motorola
    doc).
    
    Signed-off-by: Philippe De Muyter <phdm@macqel.be>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e729aa16b168fb202d1a20f936028cb7c2a0278d
Author: Ravikiran G Thirumalai <kiran@scalex86.org>
Date:   Tue May 8 00:29:13 2007 -0700

    Pad irq_desc to internode cacheline size
    
    We noticed a drop in n/w performance due to the irq_desc being cacheline
    aligned rather than internode aligned.  We see 50% of expected performance
    when two e1000 nics local to two different nodes have consecutive irq
    descriptors allocated, due to false sharing.
    
    Note that this patch does away with cacheline padding for the UP case, as
    it does not seem useful for UP configurations.
    
    Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org>
    Signed-off-by: Shai Fultheim <shai@scalex86.org>
    Cc: "Siddha, Suresh B" <suresh.b.siddha@intel.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 428e6ce023c5890cfecc8ad10335da3f28dbf893
Author: Pavel Emelianov <xemul@sw.ru>
Date:   Tue May 8 00:29:10 2007 -0700

    Lockdep treats down_write_trylock like regular down_write
    
    This causes constructions like
    
    down_write(&mm1->mmap_sem);
    if (down_write_trylock(&mm2->mmap_sem)) {
           ...
           up_write(&mm2->mmap_sem);
    }
    up_write(&mm1->mmap_sem);
    
    generate a lockdep warning about circular locking dependence.
    
    Call rwsem_acquire() with trylock set to 1.
    
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Arjan van de Ven <arjan@infradead.org>
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 644fd4f5de9ca147daeb6dc5f844b44ec3d58b47
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:29:07 2007 -0700

    merge compat_ioctl.h into compat_ioctl.c
    
    Now that there is no arch-specific compat ioctl handling left there is not
    point in having a separate copat_ioctl.h, so merge it into compat_ioctl.c
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Acked-by: Arnd Bergmann <arnd@arndb.de>
    Acked-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 884f2810b15b6bb489c9dca5013aafbea2f19fba
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Tue May 8 00:29:05 2007 -0700

    kernel-doc: handle arrays with arithmetic expressions as initializers
    
    In a different approach here's a patch that handles the special case of
    composite arithmetic expressions in array size initializers.  With it,
    prior to pushing the split strings on the @first_arg array, I split the
    keywords before the array name as before and then keep the array name along
    with the subscript expression as a single whole element which gets pushed
    last.  In this manner, kernel-doc produces correct output without removing
    whitespaces which makes the array subscripts unreadable in the docs.
    
    Signed-off-by: Borislav Petkov <bbpetkov@yahoo.de>
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1525dccbc248b87568f2477f1b2d417b69d418c3
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:29:03 2007 -0700

    ROUND_UP macro cleanup in fs/smbfs/request.c
    
    ROUND_UP macro cleanup use ALIGN
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 022a1692444cd683ef42f637cc717db4d8fd9378
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:29:02 2007 -0700

    ROUND_UP macro cleanup in fs/(select|compat|readdir).c
    
    ROUND_UP macro cleanup use,ALIGN or DIV_ROUND_UP where ever appropriate.
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 10f8a59813ee8bb41fb1d72ed2ec12a1c9f66da2
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:29:01 2007 -0700

    parport_serial: fix PCI must_checks
    
    drivers/parport/parport_serial.c:402: warning: ignoring return value of 'pci_enable_device', declared with attribute warn_unused_result
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7e80d0d0b64f5c00b0ac7e623d96189309c298ca
Author: Alexey Dobriyan <adobriyan@gmail.com>
Date:   Tue May 8 00:28:59 2007 -0700

    i386: sched.h inclusion from module.h is baack
    
      linux/module.h
      -> linux/elf.h
         -> asm-i386/elf.h
            -> linux/utsname.h
               -> linux/sched.h
    
    Noticeably cut the number of files which are rebuild upon touching sched.h
    and cut down pulled junk from every module.h inclusion.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b259d74b39595f6ac74c3627b9c3657ac90249a0
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 8 00:28:57 2007 -0700

    ROUND_UP macro cleanup in drivers/char/lp.c
    
    ROUND_UP macro cleanup use DIV_ROUND_UP
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0e8638e2ace18eb6b814a63fe087106be05ca267
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Tue May 8 00:28:56 2007 -0700

    Deprecate SA_xxx interrupt flags -V2
    
    The deprecation of the SA_xxx interrupt flags did not emit deprecated
    warnings. Andrew said about the removal of the deprecated flag defines:
    
    > This is going to break a lot of external stuff.  We should have found
    > a way to make usage of SA_* emit deprecated warnings (or _some_
    > warning) to warn people of impending doom.  But I can't immediately
    > find a way of doing that. if we _can_ find a way of doing this, I
    > suspect we'll need to do it, and give people another six months.  It's
    > going to get ugly out there.  We shall see...
    
    Define the deprecated flags as a call to a __deprecated inline function
    so a warning is emitted on compile time.
    
    Extend the reprieve of out of tree drivers to 9/2007.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2833bf68b9634a02895d9463349d8c21bd32ccf6
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Tue May 8 00:28:52 2007 -0700

    Replace deprecated SA_xxx interrupt flags
    
    Fix the last users of the deprecated SA_xxx interrupt flags.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9730b5b06fee7ffd1f0150855f03cf319c0e004f
Author: Bert Wesarg <wesarg@informatik.uni-halle.de>
Date:   Tue May 8 00:28:50 2007 -0700

    kernel/params.c: fix lying comment for param_array()
    
    This fixes the comment for the function param_array. Which lies that it
    only *temporarily* mangle the input string @val.
    
    Signed-off-by: Bert Wesarg <wesarg@informatik.uni-halle.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a5c43dae7ae38c2a6b3e9a819bcf45f010bf6a4a
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:28:47 2007 -0700

    Fix race between cat /proc/slab_allocators and rmmod
    
    Same story as with cat /proc/*/wchan race vs rmmod race, only
    /proc/slab_allocators want more info than just symbol name.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Acked-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9d65cb4a1718a072898c7a57a3bc61b2dc4bcd4d
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:28:43 2007 -0700

    Fix race between cat /proc/*/wchan and rmmod et al
    
    kallsyms_lookup() can go iterating over modules list unprotected which is OK
    for emergency situations (oops), but not OK for regular stuff like
    /proc/*/wchan.
    
    Introduce lookup_symbol_name()/lookup_module_symbol_name() which copy symbol
    name into caller-supplied buffer or return -ERANGE.  All copying is done with
    module_mutex held, so...
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ffb45122766db220d0bf3d01848d575fbbcb6430
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:28:41 2007 -0700

    Simplify kallsyms_lookup()
    
    Several kallsyms_lookup() pass dummy arguments but only need, say, module's
    name.  Make kallsyms_lookup() accept NULLs where possible.
    
    Also, makes picture clearer about what interfaces are needed for all symbol
    resolving business.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ea07890a680273b25127129fb555aac0d9324bea
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:28:39 2007 -0700

    Fix race between rmmod and cat /proc/kallsyms
    
    module_get_kallsym() leaks "struct module *" outside of module_mutex which is
    no-no, because module can dissapear right after mutex unlock.
    
    Copy all needed information from inside module_mutex into caller-supplied
    space.
    
    [bunk@stusta.de: is_exported() can now become static]
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ae84e324709d6320ed8c1fd7b1736fcbaf26df95
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:28:38 2007 -0700

    Simplify module_get_kallsym() by dropping length arg
    
    module_get_kallsym() could in theory truncate module symbol name to fit in
    buffer, but nobody does this.  Always use KSYM_NAME_LEN + 1 bytes for name.
    
    Suggested by lg^WRusty.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Acked-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 55955aad7c09e4d93029d0cf2d360b41891f2fe4
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:28:35 2007 -0700

    PNPACPI sets pnpdev->dev.archdata
    
    Teach PNPACPI how to hook up its devices to their ACPI nodes, so that
    pnpdev->dev.archdata points to the parallel acpi device node.  Previously
    this only worked for PCI, leaving a notable hole.
    
    Export "acpi_bus_type" so this can work.
    
    Remove some extraneous whitespace.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Adam Belay <ambx1@neo.rr.com>
    Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Cc: Len Brown <lenb@kernel.org>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 98701d1b0fe98b477b53df89114e6862547f8107
Author: kalash nainwal <kalash.nainwal@gmail.com>
Date:   Tue May 8 00:28:31 2007 -0700

    (re)register_binfmt returns with -EBUSY
    
    When a binary format is unregistered and re-registered, register_binfmt
    fails with -EBUSY.  The reason is that unregister_binfmt does not set
    fmt->next to NULL, and seeing (fmt->next != NULL), register_binfmt fails
    with -EBUSY.
    
    One can find his way around by explicitly setting fmt->next to NULL after
    unregistering, but that is kind of unclean (one should better be using only
    the interfaces, and not the interal members, isn't it?)
    
    Attached one-liner can fix it.
    
    Signed-off-by: Kalash Nainwal <kalash.nainwal@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0f95b7fc839bc3272b1bf2325d8748a649bd3534
Author: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Date:   Tue May 8 00:28:27 2007 -0700

    Kprobes: print details of kretprobe on assertion failure
    
    In certain cases like when the real return address can't be found or when
    the number of tracked calls to a kretprobed function is less than the
    number of returns, we may not be able to find the correct return address
    after processing a kretprobe.  Currently we just do a BUG_ON, but no
    information is provided about the actual failing kretprobe.
    
    Print out details of the kretprobe before calling BUG().
    
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Cc: Prasanna S Panchamukhi <prasanna@in.ibm.com>
    Cc: Jim Keniston <jkenisto@us.ibm.com>
    Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Cc: Maneesh Soni <maneesh@in.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8f0c45cdf87dc9141e87b0ad2fc6fff216a95f79
Author: Ingo Molnar <mingo@elte.hu>
Date:   Tue May 8 00:28:26 2007 -0700

    enhance initcall_debug, measure latency
    
    enhance the initcall_debug boot option:
    
     - measure the time the initcall took to execute and report
       it in units of milliseconds.
    
     - show the return code of initcalls (useful to see failures and
       to make sure that an initcall hung)
    
    [akpm@linux-foundation.org: fix printk warning]
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b73a7e76c1eeaa770a41554698917c3c45686a07
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Tue May 8 00:28:24 2007 -0700

    Fix kevent's childs priority greediness
    
    Fix kevent's childs priority greediness.  Such tasks were always scheduled
    at nice level -5 and, at that time, udev stole us the CPU time with -5.
    
    Already posted at http://lkml.org/lkml/2005/1/10/85
    
    [akpm@linux-foundation.org: add comment]
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6672f76a5a1878d42264c1deba8f1ab52b4618d9
Author: Simon Horman <horms@verge.net.au>
Date:   Tue May 8 00:28:22 2007 -0700

    kdump/kexec: calculate note size at compile time
    
    Currently the size of the per-cpu region reserved to save crash notes is
    set by the per-architecture value MAX_NOTE_BYTES.  Which in turn is
    currently set to 1024 on all supported architectures.
    
    While testing ia64 I recently discovered that this value is in fact too
    small.  The particular setup I was using actually needs 1172 bytes.  This
    lead to very tedious failure mode where the tail of one elf note would
    overwrite the head of another if they ended up being alocated sequentially
    by kmalloc, which was often the case.
    
    It seems to me that a far better approach is to caclculate the size that
    the area needs to be.  This patch does just that.
    
    If a simpler stop-gap patch for ia64 to be squeezed into 2.6.21(.X) is
    needed then this should be as easy as making MAX_NOTE_BYTES larger in
    arch/asm-ia64/kexec.h.  Perhaps 2048 would be a good choice.  However, I
    think that the approach in this patch is a much more robust idea.
    
    Acked-by:  Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Simon Horman <horms@verge.net.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 73285082745045bcd64333c1fbaa88f8490f2626
Author: Ken Chen <kenchen@google.com>
Date:   Tue May 8 00:28:20 2007 -0700

    remove artificial software max_loop limit
    
    Remove artificial maximum 256 loop device that can be created due to a
    legacy device number limit.  Searching through lkml archive, there are
    several instances where users complained about the artificial limit that
    the loop driver impose.  There is no reason to have such limit.
    
    This patch rid the limit entirely and make loop device and associated block
    queue instantiation on demand.  With on-demand instantiation, it also gives
    the benefit of not wasting memory if these devices are not in use (compare
    to current implementation that always create 8 loop devices), a net
    improvement in both areas.  This version is both tested with creation of
    large number of loop devices and is compatible with existing losetup/mount
    user land tools.
    
    There are a number of people who worked on this and provided valuable
    suggestions, in no particular order, by:
    
    Jens Axboe
    Jan Engelhardt
    Christoph Hellwig
    Thomas M
    
    Signed-off-by: Ken Chen <kenchen@google.com>
    Cc: Jan Engelhardt <jengelh@linux01.gwdg.de>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4f911d64e04a44c47985be30f978fb3c2efcee0c
Author: Russell King <rmk+lkml@arm.linux.org.uk>
Date:   Tue May 8 00:28:17 2007 -0700

    Make /dev/port conditional on config symbol
    
    Instead of having /dev/port support dependent in multiple places on a
    string of preprocessor symbols, define a new configuration directive for
    it.  This ensures that all four places remain consistent with each other.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 62456726d715042e1976b830c59fd73f41c4aaa6
Author: John Feeney <jfeeney@redhat.com>
Date:   Tue May 8 00:28:12 2007 -0700

    Fix 82875 PCI setup
    
    The 82875 EDAC driver enables an otherwise-hidden PCI device, but doesn't
    register it as a PCI device properly.  Therefore, the device list in
    /proc/bus/pci/devices is different than the tree in /sys/bus/pci.  This
    usually manifests as the X server failing to start, since it expects the
    two lists to be consistent.
    
    Signed-off-by: Adam Jackson <ajackson@redhat.com>
    Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Cc: Greg KH <greg@kroah.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Doug Thompson <norsk5@xmission.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e63340ae6b6205fef26b40a75673d1c9c0c8bb90
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:28:08 2007 -0700

    header cleaning: don't include smp_lock.h when not used
    
    Remove includes of <linux/smp_lock.h> where it is not used/needed.
    Suggested by Al Viro.
    
    Builds cleanly on x86_64, i386, alpha, ia64, powerpc, sparc,
    sparc64, and arm (all 59 defconfigs).
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 04c9167f91e309c9c4ea982992aa08e83b2eb42e
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Tue May 8 00:28:05 2007 -0700

    add touch_all_softlockup_watchdogs()
    
    Add touch_all_softlockup_watchdogs() to allow the softlockup watchdog
    timers on all cpus to be updated.  This is used to prevent sysrq-t from
    generating a spurious watchdog message when generating lots of output.
    
    Softlockup watchdogs use sched_clock() as its timebase, which is inherently
    per-cpu (at least, when it is measuring unstolen time).  Because of this,
    it isn't possible for one CPU to directly update the other CPU's timers,
    but it is possible to tell the other CPUs to do update themselves
    appropriately.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Acked-by: Chris Lalancette <clalance@redhat.com>
    Signed-off-by: Prarit Bhargava <prarit@redhat.com>
    Cc: Rick Lindsley <ricklind@us.ibm.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 966812dc98e6a7fcdf759cbfa0efab77500a8868
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Tue May 8 00:28:02 2007 -0700

    Ignore stolen time in the softlockup watchdog
    
    The softlockup watchdog is currently a nuisance in a virtual machine, since
    the whole system could have the CPU stolen from it for a long period of
    time.  While it would be unlikely for a guest domain to be denied timer
    interrupts for over 10s, it could happen and any softlockup message would
    be completely spurious.
    
    Earlier I proposed that sched_clock() return time in unstolen nanoseconds,
    which is how Xen and VMI currently implement it.  If the softlockup
    watchdog uses sched_clock() to measure time, it would automatically ignore
    stolen time, and therefore only report when the guest itself locked up.
    When running native, sched_clock() returns real-time nanoseconds, so the
    behaviour would be unchanged.
    
    Note that sched_clock() used this way is inherently per-cpu, so this patch
    makes sure that the per-processor watchdog thread initialized its own
    timestamp.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: john stultz <johnstul@us.ibm.com>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: James Morris <jmorris@namei.org>
    Cc: Dan Hecht <dhecht@vmware.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Cc: Prarit Bhargava <prarit@redhat.com>
    Cc: Chris Lalancette <clalance@redhat.com>
    Cc: Rick Lindsley <ricklind@us.ibm.com>
    Cc: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8524070b7982d76258942275908b7434cfcab4b4
Author: john stultz <johnstul@us.ibm.com>
Date:   Tue May 8 00:27:59 2007 -0700

    Move timekeeping code to timekeeping.c
    
    Move the timekeeping code out of kernel/timer.c and into
    kernel/time/timekeeping.c.  I made no cleanups or other changes in transit.
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: John Stultz <johnstul@us.ibm.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 329c8d84ca1946c037d9859dc251b56d8b1b4630
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue May 8 00:27:57 2007 -0700

    time: SMP friendly alignment of struct clocksource
    
    struct clocksource is a critical data structure.
    
    Most of its fields are read only, some of them are heavily modified at each
    timer interrupt.
    
    It makes sense to separate those fields and make sure they all share one
    cache line, or at least the minimum for machines with small cache lines.
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: John Stultz <johnstul@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f75d222b836f7febfab0954c7612b23059d748cb
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Tue May 8 00:27:55 2007 -0700

    IRQ: check for PERCPU flag only when adding first irqaction
    
    An irqaction structure won't be added to an IRQ descriptor irqaction list if
    it doesn't agree with other irqactions on the IRQF_PERCPU flag.  Don't check
    for this flag to change IRQ descriptor `status' for every irqaction added to
    the list, Doing the check only for the first irqaction added is enough.
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3367b994fe4f131ab1240600682a1981de7cad0c
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Tue May 8 00:27:52 2007 -0700

    <linux/sysdev.h> needs to include <linux/module.h>
    
    sysdev.h uses THIS_MODULE so should include <linux/module.h>.
    
    [akpm@linux-foundation.org: couple of fixes]
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 28287033e12463c8ff89f1ea8038783d0360391c
Author: Venki Pallipadi <venkatesh.pallipadi@intel.com>
Date:   Tue May 8 00:27:47 2007 -0700

    Add a new deferrable delayed work init
    
    Add a new deferrable delayed work init.  This can be used to schedule work
    that are 'unimportant' when CPU is idle and can be called later, when CPU
    eventually comes out of idle.
    
    Use this init in cpufreq ondemand governor.
    
    Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
    Cc: Dave Jones <davej@codemonkey.org.uk>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6e453a67510a17f01b63835f18569e8c3939a38c
Author: Venki Pallipadi <venkatesh.pallipadi@intel.com>
Date:   Tue May 8 00:27:44 2007 -0700

    Add support for deferrable timers
    
    Introduce a new flag for timers - deferrable: Timers that work normally
    when system is busy.  But, will not cause CPU to come out of idle (just to
    service this timer), when CPU is idle.  Instead, this timer will be
    serviced when CPU eventually wakes up with a subsequent non-deferrable
    timer.
    
    The main advantage of this is to avoid unnecessary timer interrupts when
    CPU is idle.  If the routine currently called by a timer can wait until
    next event without any issues, this new timer can be used to setup timer
    event for that routine.  This, with dynticks, allows CPUs to be lazy,
    allowing them to stay in idle for extended period of time by reducing
    unnecesary wakeup and thereby reducing the power consumption.
    
    This patch:
    
    Builds this new timer on top of existing timer infrastructure.  It uses
    last bit in 'base' pointer of timer_list structure to store this deferrable
    timer flag.  __next_timer_interrupt() function skips over these deferrable
    timers when CPU looks for next timer event for which it has to wake up.
    
    This is exported by a new interface init_timer_deferrable() that can be
    called in place of regular init_timer().
    
    [akpm@linux-foundation.org: Privatise a #define]
    Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Cc: Dave Jones <davej@codemonkey.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit da6752964290567a6b4ea180d1becda75e810e87
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:27:42 2007 -0700

    layered parport code uses parport->dev
    
    Update some of the layered parport_driver code to use parport->dev:
    
    	- i2c-parport (parent of i2c_adapter)
    	- spi_butterfly (parent of spi_master, allowing cruft removal)
    	- lp (creating class_device)
    	- ppdev (parent of parportN device)
    	- tipar (creating class_device)
    
    There are still drivers that should be updated, like some of the input
    drivers; but they won't be any worse off than they are today.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Greg KH <greg@kroah.com>
    Cc: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a7d801afc3d4d1c8aaa0449f17b9f9ce62e16236
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 00:27:40 2007 -0700

    legacy PC parports support parport->dev
    
    Give legacy parallel ports a platform device in the device tree.
    
    This is a quick and dirty implementation; it doesn't actually convert the
    legacy parport code to the device driver model (by splitting out probing from
    device creation).  But at least parallel port device drivers will finally have
    a device to work with.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c15a3837d2aa30e3ea41aed49d80abed355ab6bd
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:27:35 2007 -0700

    parport->dev driver model support
    
    Currently a parport_driver can't get a handle on the device node for the
    underlying parport (PNPACPI, PCI, etc).  That prevents correct placement of
    sysfs child nodes, which can affect things like power management.
    
    This patch adds a field to "struct parport" pointing to that device node, and
    updates non-legacy port drivers to initialize that device pointer.  That field
    replaces the analagous PCI-only support in parport_pc.
    
    [akpm@linux-foundation.org: fix powerpc build]
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d2d9433a4c84c9e7ed78d633fdbffb35d5afda17
Author: Dmitry Adamushko <dmitry.adamushko@gmail.com>
Date:   Tue May 8 00:27:31 2007 -0700

    kernel/irq/proc.c: unprotected iteration over the IRQ action list in name_unique()
    
    setup_irq() releases a desc->lock before calling register_handler_proc(), so
    the iteration over the IRQ action list is not protected.
    
    (akpm: the check itself is still racy, but at least it probably won't oops
    now).
    
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c467a388ae9f236c039d4d0f4c4be07c7deebe97
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:27:26 2007 -0700

    Delete unused header file linux/awe_voice.h
    
    Delete the unused header file include/linux/awe_voice.h, as well as
    its corresponding Kbuild entry.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dd9037a26a1e6ebec9121b4681c414dc77189a90
Author: Srivatsa Vaddagiri <vatsa@in.ibm.com>
Date:   Tue May 8 00:27:25 2007 -0700

    Fix race between attach_task and cpuset_exit
    
    Currently cpuset_exit() changes the exiting task's ->cpuset pointer w/o
    taking task_lock().  This can lead to ugly races between attach_task and
    cpuset_exit.  Details of the races are described at
    http://lkml.org/lkml/2007/3/24/132.
    
    Patch below closes those races.
    
    Signed-off-by: Srivatsa Vaddagiri <vatsa@in.ibm.com>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Balbir Singh <balbir@in.ibm.com>
    Cc: Paul Menage <menage@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e5f00f42f35e6f4699f105a3bd56874847cbf72f
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:27:22 2007 -0700

    make remove_inode_dquot_ref() static
    
    remove_inode_dquot_ref() can now become static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c6b40d16d1cfa1a01158049bb887a9bbe48ef7ba
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Tue May 8 00:27:20 2007 -0700

    fix sscanf %n match at end of input string
    
    I was playing with some code that sometimes got a string where a %n
    match should have been done where the input string ended, for example
    like this:
    
      sscanf("abc123", "abc%d%n", &a, &n);  /* doesn't work */
      sscanf("abc123a", "abc%d%n", &a, &n); /* works */
    
    However, the scanf function in the kernel doesn't convert the %n in that
    case because it has already matched the complete input after %d and just
    completely stops matching then. This patch fixes that.
    
    [akpm@linux-foundation.org: cleanups]
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 757dea93e136b219af09d3cd56a81063fdbdef1a
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:27:17 2007 -0700

    Delete unused header file math-emu/extended.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 274ee1cd91800a7aa1ed34b7ab2db7c53f09c93a
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:27:14 2007 -0700

    schedule obsolete OSS drivers for removal, 4th round
    
    Schedule obsolete OSS drivers for removal.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ca509f69dec7fa564005aa7e9fcf0cd46de3f7d6
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:27:12 2007 -0700

    Protect tty drivers list with tty_mutex
    
    Additions and removal from tty_drivers list were just done as well as
    iterating on it for /proc/tty/drivers generation.
    
    testing: modprobe/rmmod loop of simple module which does nothing but
    tty_register_driver() vs cat /proc/tty/drivers loop
    
    BUG: unable to handle kernel paging request at virtual address 6b6b6b6b
     printing eip:
    c01cefa7
    *pde = 00000000
    Oops: 0000 [#1]
    PREEMPT
    last sysfs file: devices/pci0000:00/0000:00:1d.7/usb5/5-0:1.0/bInterfaceProtocol
    Modules linked in: ohci_hcd af_packet e1000 ehci_hcd uhci_hcd usbcore xfs
    CPU:    0
    EIP:    0060:[<c01cefa7>]    Not tainted VLI
    EFLAGS: 00010297   (2.6.21-rc4-mm1 #4)
    EIP is at vsnprintf+0x3a4/0x5fc
    eax: 6b6b6b6b   ebx: f6cb50f2   ecx: 6b6b6b6b   edx: fffffffe
    esi: c0354700   edi: f6cb6000   ebp: 6b6b6b6b   esp: f31f5e68
    ds: 007b   es: 007b   fs: 00d8  gs: 0033  ss: 0068
    Process cat (pid: 31864, ti=f31f4000 task=c1998030 task.ti=f31f4000)
    Stack: 00000000 c0103f20 c013003a c0103f20 00000000 f6cb50da 0000000a 00000f0e
           f6cb50f2 00000010 00000014 ffffffff ffffffff 00000007 c0354753 f6cb50f2
           f73e39dc f73e39dc 00000001 c0175416 f31f5ed8 f31f5ed4 0ee00000 f32090bc
    Call Trace:
     [<c0103f20>] restore_nocheck+0x12/0x15
     [<c013003a>] mark_held_locks+0x6d/0x86
     [<c0103f20>] restore_nocheck+0x12/0x15
     [<c0175416>] seq_printf+0x2e/0x52
     [<c0192895>] show_tty_range+0x35/0x1f3
     [<c0175416>] seq_printf+0x2e/0x52
     [<c0192add>] show_tty_driver+0x8a/0x1d9
     [<c01758f6>] seq_read+0x70/0x2ba
     [<c0175886>] seq_read+0x0/0x2ba
     [<c018d8e6>] proc_reg_read+0x63/0x9f
     [<c015e764>] vfs_read+0x7d/0xb5
     [<c018d883>] proc_reg_read+0x0/0x9f
     [<c015eab1>] sys_read+0x41/0x6a
     [<c0103e4e>] sysenter_past_esp+0x5f/0x99
     =======================
    Code: 00 8b 4d 04 e9 44 ff ff ff 8d 4d 04 89 4c 24 50 8b 6d 00 81 fd ff 0f 00 00 b8 a4 c1 35 c0 0f 46 e8 8b 54 24 2c 89 e9 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 89 c6 8b 44 24 28 89
    EIP: [<c01cefa7>] vsnprintf+0x3a4/0x5fc SS:ESP 0068:f31f5e68
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ef51c97623b94f51e439ac91d2736aab3d1b6594
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Tue May 8 00:27:10 2007 -0700

    Remove do_sync_file_range()
    
    Remove do_sync_file_range() and convert callers to just use
    do_sync_mapping_range().
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 524e6752912a891a396a9cf74c5d7d60fff5510a
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:27:07 2007 -0700

    Char: cs5535_gpio, add MODULE_DEVICE_TABLE
    
    cs5535_gpio, add MODULE_DEVICE_TABLE
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Cc: Ben Gardner <bgardner@wabtec.com>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8d5916d3e0e1cff2e9ecf7fc2d191a2cf2146bd5
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Tue May 8 00:27:05 2007 -0700

    Char: rocket, add MODULE_DEVICE_TABLE
    
    rocket, add MODULE_DEVICE_TABLE
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1eeb66a1bb973534dc3d064920a5ca683823372e
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:27:03 2007 -0700

    move die notifier handling to common code
    
    This patch moves the die notifier handling to common code.  Previous
    various architectures had exactly the same code for it.  Note that the new
    code is compiled unconditionally, this should be understood as an appel to
    the other architecture maintainer to implement support for it aswell (aka
    sprinkling a notify_die or two in the proper place)
    
    arm had a notifiy_die that did something totally different, I renamed it to
    arm_notify_die as part of the patch and made it static to the file it's
    declared and used at.  avr32 used to pass slightly less information through
    this interface and I brought it into line with the other architectures.
    
    [akpm@linux-foundation.org: build fix]
    [akpm@linux-foundation.org: fix vmalloc_sync_all bustage]
    [bryan.wu@analog.com: fix vmalloc_sync_all in nommu]
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Cc: <linux-arch@vger.kernel.org>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e3869792990f708c97be5877499cada70d469bd3
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:27:01 2007 -0700

    kprobes: fix sparse NULL warning
    
    Fix sparse NULL warnings:
    kernel/kprobes.c:915:49: warning: Using plain integer as NULL pointer
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 880ebdc5166aa6a0aa2a3218357a3d6e0eebcec8
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:26:59 2007 -0700

    reiserfs: proc support requires PROC_FS
    
    REISER_FS /proc option needs to depend on PROC_FS.
    
    fs/reiserfs/procfs.c: In function 'show_super':
    fs/reiserfs/procfs.c:134: error: 'reiserfs_proc_info_data_t' has no member named 'max_hash_collisions'
    fs/reiserfs/procfs.c:134: error: 'reiserfs_proc_info_data_t' has no member named 'breads'
    fs/reiserfs/procfs.c:135: error: 'reiserfs_proc_info_data_t' has no member named 'bread_miss'
    fs/reiserfs/procfs.c:135: error: 'reiserfs_proc_info_data_t' has no member named 'search_by_key'
    fs/reiserfs/procfs.c:136: error: 'reiserfs_proc_info_data_t' has no member named 'search_by_key_fs_changed'
    fs/reiserfs/procfs.c:136: error: 'reiserfs_proc_info_data_t' has no member named 'search_by_key_restarted'
    fs/reiserfs/procfs.c:137: error: 'reiserfs_proc_info_data_t' has no member named 'insert_item_restarted'
    fs/reiserfs/procfs.c:137: error: 'reiserfs_proc_info_data_t' has no member named 'paste_into_item_restarted'
    fs/reiserfs/procfs.c:138: error: 'reiserfs_proc_info_data_t' has no member named 'cut_from_item_restarted'
    fs/reiserfs/procfs.c:139: error: 'reiserfs_proc_info_data_t' has no member named 'delete_solid_item_restarted'
    fs/reiserfs/procfs.c:139: error: 'reiserfs_proc_info_data_t' has no member named 'delete_item_restarted'
    fs/reiserfs/procfs.c:140: error: 'reiserfs_proc_info_data_t' has no member named 'leaked_oid'
    fs/reiserfs/procfs.c:140: error: 'reiserfs_proc_info_data_t' has no member named 'leaves_removable'
    fs/reiserfs/procfs.c: In function 'show_per_level':
    fs/reiserfs/procfs.c:184: error: 'reiserfs_proc_info_data_t' has no member named 'balance_at'
    fs/reiserfs/procfs.c:185: error: 'reiserfs_proc_info_data_t' has no member named 'sbk_read_at'
    fs/reiserfs/procfs.c:186: error: 'reiserfs_proc_info_data_t' has no member named 'sbk_fs_changed'
    fs/reiserfs/procfs.c:187: error: 'reiserfs_proc_info_data_t' has no member named 'sbk_restarted'
    fs/reiserfs/procfs.c:188: error: 'reiserfs_proc_info_data_t' has no member named 'free_at'
    fs/reiserfs/procfs.c:189: error: 'reiserfs_proc_info_data_t' has no member named 'items_at'
    fs/reiserfs/procfs.c:190: error: 'reiserfs_proc_info_data_t' has no member named 'can_node_be_removed'
    fs/reiserfs/procfs.c:191: error: 'reiserfs_proc_info_data_t' has no member named 'lnum'
    fs/reiserfs/procfs.c:192: error: 'reiserfs_proc_info_data_t' has no member named 'rnum'
    fs/reiserfs/procfs.c:193: error: 'reiserfs_proc_info_data_t' has no member named 'lbytes'
    fs/reiserfs/procfs.c:194: error: 'reiserfs_proc_info_data_t' has no member named 'rbytes'
    fs/reiserfs/procfs.c:195: error: 'reiserfs_proc_info_data_t' has no member named 'get_neighbors'
    fs/reiserfs/procfs.c:196: error: 'reiserfs_proc_info_data_t' has no member named 'get_neighbors_restart'
    fs/reiserfs/procfs.c:197: error: 'reiserfs_proc_info_data_t' has no member named 'need_l_neighbor'
    fs/reiserfs/procfs.c:197: error: 'reiserfs_proc_info_data_t' has no member named 'need_r_neighbor'
    fs/reiserfs/procfs.c: In function 'show_bitmap':
    fs/reiserfs/procfs.c:224: error: 'reiserfs_proc_info_data_t' has no member named 'free_block'
    fs/reiserfs/procfs.c:225: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:226: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:227: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:228: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:229: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:230: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c:230: error: 'reiserfs_proc_info_data_t' has no member named 'scan_bitmap'
    fs/reiserfs/procfs.c: In function 'show_journal':
    fs/reiserfs/procfs.c:384: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:385: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:386: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:387: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:388: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:389: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:390: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:391: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:392: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:393: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:394: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:395: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:395: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c:395: error: 'reiserfs_proc_info_data_t' has no member named 'journal'
    fs/reiserfs/procfs.c: In function 'reiserfs_proc_info_init':
    fs/reiserfs/procfs.c:504: warning: implicit declaration of function '__PINFO'
    fs/reiserfs/procfs.c:504: error: request for member 'lock' in something not a structure or union
    fs/reiserfs/procfs.c: In function 'reiserfs_proc_info_done':
    fs/reiserfs/procfs.c:544: error: request for member 'lock' in something not a structure or union
    fs/reiserfs/procfs.c:545: error: request for member 'exiting' in something not a structure or union
    fs/reiserfs/procfs.c:546: error: request for member 'lock' in something not a structure or union
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 98a27ba485c7508ef9d9527fe06e4686f3a163dc
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Tue May 8 00:26:56 2007 -0700

    tty: introduce no_tty and use it in selinux
    
    While researching the tty layer pid leaks I found a weird case in selinux when
    we drop a controlling tty because of inadequate permissions we don't do the
    normal hangup processing.  Which is a problem if it happens the session leader
    has exec'd something that can no longer access the tty.
    
    We already have code in the kernel to handle this case in the form of the
    TIOCNOTTY ioctl.  So this patch factors out a helper function that is the
    essence of that ioctl and calls it from the selinux code.
    
    This removes the inconsistency in handling dropping of a controlling tty and
    who knows it might even make some part of user space happy because it received
    a SIGHUP it was expecting.
    
    In addition since this removes the last user of proc_set_tty outside of
    tty_io.c proc_set_tty is made static and removed from tty.h
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: James Morris <jmorris@namei.org>
    Cc: Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2a65f1d9fe78475720bd8f0e0fbbf1973b1b5ac2
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Tue May 8 00:26:53 2007 -0700

    tty: simplify calling of put_pid.
    
    This patch should contain no functional changes.
    
    At some point I got confused and thought put_pid could not be called while a
    spin lock was held.  While it may be nice to avoid that to reduce lock hold
    times put_pid can be safely called while we hold a spin lock.
    
    This patch removes all of the complications from the code introduced by my
    misunderstanding, making the code a little more readable.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f67c3627b4abd8a3cf56bd20cafde702feffe236
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Tue May 8 00:26:51 2007 -0700

    tty: remove unnecessary export of proc_clear_tty
    
    All of the users of proc_clear_tty are compiled into the kernel so exporting
    this symbol appears gratuitous.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 69331af79cf29e26d1231152a172a1a10c2df511
Author: Gerd Hoffmann <kraxel@suse.de>
Date:   Tue May 8 00:26:49 2007 -0700

    Fixes and cleanups for earlyprintk aka boot console
    
    The console subsystem already has an idea of a boot console, using the
    CON_BOOT flag.  The implementation has some flaws though.  The major
    problem is that presence of a boot console makes register_console() ignore
    any other console devices (unless explicitly specified on the kernel
    command line).
    
    This patch fixes the console selection code to *not* consider a boot
    console a full-featured one, so the first non-boot console registering will
    become the default console instead.  This way the unregister call for the
    boot console in the register_console() function actually triggers and the
    handover from the boot console to the real console device works smoothly.
    Added a printk for the handover, so you know which console device the
    output goes to when the boot console stops printing messages.
    
    The disable_early_printk() call is obsolete with that patch, explicitly
    disabling the early console isn't needed any more as it works automagically
    with that patch.
    
    I've walked through the tree, dropped all disable_early_printk() instances
    found below arch/ and tagged the consoles with CON_BOOT if needed.  The
    code is tested on x86, sh (thanks to Paul) and mips (thanks to Ralf).
    
    Changes to last version: Rediffed against -rc3, adapted to mips cleanups by
    Ralf, fixed "udbg-immortal" cmd line arg on powerpc.
    
    Signed-off-by: Gerd Hoffmann <kraxel@exsuse.de>
    Acked-by: Paul Mundt <lethal@linux-sh.org>
    Acked-by: Ralf Baechle <ralf@linux-mips.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Jeremy Fitzhardinge <jeremy@goop.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6ae9200f2cab7b328e505fc9a7021db64e0590cf
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:26:47 2007 -0700

    enlarge console.name
    
    console.name[] is eight chars, but so is "earlyvga".  So when we try to print
    console->name when using earlyvga it runs off the end of the string.
    
    Make it bigger.
    
    Diagnosed-by: Gerd Hoffmann <kraxel@redhat.com>
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 19c5d45a09312ca20cd1f9df3fd1a87fe0cb8aac
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:26:46 2007 -0700

    /proc/*/oom_score oops re badness
    
    Eternal quest to make
    
    	while true; do cat /proc/fs/xfs/stat >/dev/null 2>/dev/null; done
    	while true; do find /proc -type f 2>/dev/null | xargs cat >/dev/null 2>/dev/null; done
    	while true; do modprobe xfs; rmmod xfs; done
    
    work reliably continues and now kernel oopses in the following way:
    
    BUG: unable to handle ... at virtual address 6b6b6b6b
    EIP is at badness
    process: cat
    	proc_oom_score
    	proc_info_read
    	sys_fstat64
    	vfs_read
    	proc_info_read
    	sys_read
    
    Failing code is prefetch hidden in list_for_each_entry() in badness().
    badness() is reachable from two points. One is proc_oom_score, another
    is out_of_memory() => select_bad_process() => badness().
    
    Second path grabs tasklist_lock, while first doesn't.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 72c1bbf308c75a136803d2d76d0e18258be14c7a
Author: Nick Piggin <npiggin@suse.de>
Date:   Tue May 8 00:26:43 2007 -0700

    futex: restartable futex_wait
    
    LTP test sigaction_16_24 fails, because it expects sem_wait to be restarted
    if SA_RESTART is set.  sem_wait is implemented with futex_wait, that
    currently doesn't support being restarted.  Ulrich confirms that the call
    should be restartable.
    
    Implement a restart_block method to handle the relative timeout, and allow
    restarts.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Ulrich Drepper <drepper@redhat.com>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Roland McGrath <roland@redhat.com>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9adef58b1d4fbb58d7daed931b6790c5a3b7543a
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Tue May 8 00:26:42 2007 -0700

    futex: get_futex_key, get_key_refs and drop_key_refs
    
    lguest uses the convenient futex infrastructure for inter-domain I/O, so
    expose get_futex_key, get_key_refs (renamed get_futex_key_refs) and
    drop_key_refs (renamed drop_futex_key_refs).  Also means we need to expose the
    union that these use.
    
    No code changes.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit aa5bd7e929325dbb48be43c3dccf7d1da433e38e
Author: Dale Farnsworth <dale@farnsworth.org>
Date:   Tue May 8 00:26:39 2007 -0700

    rtc: add RTC class driver for the Maxim MAX6900
    
    Signed-off-by: Dale Farnsworth.org <dale@farnsworth.org>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: David Brownell <david-b@pacbell.net>
    Cc: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e9f2bd8191a416fbd17e8bfc002dba5411937997
Author: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Date:   Tue May 8 00:26:37 2007 -0700

    RTC: add rtc-rs5c313 driver
    
    Add an RTC driver for Ricoh RS5C313 RTC chip.
    
    [akpm@linux-foundation.org: Zillions of coding-style fixes]
    [akpm@linux-foundation.org: build fixes]
    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c6a632a2b610c1bc123f1d258d688e8fe5cc70dd
Author: Nick Piggin <nickpiggin@yahoo.com.au>
Date:   Tue May 8 00:26:34 2007 -0700

    as: fix antic_expire check
    
    Fix units mismatch (jiffies vs msecs) in as-iosched.c, spotted by Xiaoning
    Ding <dingxn@cse.ohio-state.edu>.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e97cb3e28ce2fdd3b06a65f67d00462d86929008
Author: Len Sorensen <lsorense@csclub.uwaterloo.ca>
Date:   Tue May 8 00:26:33 2007 -0700

    Subject: jsm driver fix for linuxpps support
    
    The jsm driver doesn't currently use the uart_handle_*_change helper
    functions, which are the obvious place for things like linuxpps to tie
    into (which it now does of course), and as a result the jsm driver can
    not be used with linuxpps and anything else that ties into the
    serial_core helper functions.  This patch adds calls to these helper
    functions whenever the value they manage changes.  That actual storage
    of the state is not modified since the jsm driver caches the current
    settings (The 8250 driver reads them everytime a user asks for the
    state), and only updates them whenever they change.
    
    Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
    Cc: Scott H Kilau <Scott_Kilau@digi.com>
    Cc: Wendy Xiong <wendyx@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3c04c27251c4d064f16846c305cbc1ff2f5b5fbe
Author: Len Sorensen <lsorense@csclub.uwaterloo.ca>
Date:   Tue May 8 00:26:30 2007 -0700

    Small fixes for jsm driver
    
    The jsm driver fails when you try to use the TIOCSSERIAL ioctl.  The reason
    is that the driver never sets uart_port.uartclk, causing the data received
    using TIOCGSERIAL to not match the internal state of the driver.  This
    patch fixes this problem by settings the uartclk to the value used by the
    serial_core (16 times the baud base).
    
    Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
    Cc: Scott H Kilau <Scott_Kilau@digi.com>
    Cc: Wendy Xiong <wendyx@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1a86b5e34e4d09e3246a983c53929ce38af52275
Author: Klaus Kudielka <klaus.kudielka@gmx.net>
Date:   Tue May 8 00:26:26 2007 -0700

    cyclades: remove custom types
    
    Switch from private uclong, etc over to standard types.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7c4e95bf483231d55bc0d491bc585bb9b7e852b8
Author: Klaus Kudielka <klaus.kudielka@gmx.net>
Date:   Tue May 8 00:26:25 2007 -0700

    fix cyclades.h for x86_64 (and probably others)
    
    At least on x86_64 the present cyclades.h is broken due to the wrong size
    of uclong.  This affects, of course, both the kernel and the user-level
    utilities.  The symptom is that cyzload refuses to load the firmware.  I
    also managed to freeze the machine when unloading the module.
    
    The patch below fixes this in an architecture-independent way.  I have
    tested it with 2.6.19 and the driver works fine again with a Cyclades-Z on
    an Athlon 64 X2.
    
    [akpm@linux-foundation.org: fix warnings]
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9b3af29bf33bfe08c604769632799d27d56ae103
Author: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Date:   Tue May 8 00:26:23 2007 -0700

    Kprobes: Make kprobe.symbol_name const
    
    Kprobes doesn't scribble the kprobe.symbol_name field.  Its only set by the
    module when registering the probe.  Modules that exercise good hygiene
    using the "const" qualifier will see warnings...
    
    	warning: assignment discards qualifiers from pointer target type
    
    Make struct kprobe.symbol_name const char *
    
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6de02123bf3e8baeee97fff7efc50bc192332804
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Tue May 8 00:26:21 2007 -0700

    tty: i386/x86_64 arbitary speed support
    
    Adds the needed TCGETS2/TCSETS2 ioctl calls, structures, defines and the like.
    Tested against the test suite and passes.  Other platforms should need
    roughly the same change.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c23fbb6bcb3eb9cdf39a103edadf57bde8ce309c
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue May 8 00:26:18 2007 -0700

    VFS: delay the dentry name generation on sockets and pipes
    
    1) Introduces a new method in 'struct dentry_operations'.  This method
       called d_dname() might be called from d_path() to build a pathname for
       special filesystems.  It is called without locks.
    
       Future patches (if we succeed in having one common dentry for all
       pipes/sockets) may need to change prototype of this method, but we now
       use : char *d_dname(struct dentry *dentry, char *buffer, int buflen);
    
    2) Adds a dynamic_dname() helper function that eases d_dname() implementations
    
    3) Defines d_dname method for sockets : No more sprintf() at socket
       creation.  This is delayed up to the moment someone does an access to
       /proc/pid/fd/...
    
    4) Defines d_dname method for pipes : No more sprintf() at pipe
       creation.  This is delayed up to the moment someone does an access to
       /proc/pid/fd/...
    
    A benchmark consisting of 1.000.000 calls to pipe()/close()/close() gives a
    *nice* speedup on my Pentium(M) 1.6 Ghz :
    
    3.090 s instead of 3.450 s
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: Christoph Hellwig <hch@infradead.org>
    Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2793274298c4423d79701e9a8190f2940bf3c785
Author: Miklos Szeredi <mszeredi@suse.cz>
Date:   Tue May 8 00:26:17 2007 -0700

    add file position info to proc
    
    Add support for finding out the current file position, open flags and
    possibly other info in the future.
    
    These new entries are added:
    
      /proc/PID/fdinfo/FD
      /proc/PID/task/TID/fdinfo/FD
    
    For each fd the information is provided in the following format:
    
    pos:	1234
    flags:	0100002
    
    [bunk@stusta.de: make struct proc_fdinfo_file_operations static]
    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Cc: Alexey Dobriyan <adobriyan@sw.ru>
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c5141e6d64ab5c48a5e31413c7a6cdda84ac1d52
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue May 8 00:26:15 2007 -0700

    procfs: reorder struct pid_dentry to save space on 64bit archs, and constify them
    
    Change the order of fields of struct pid_entry (file fs/proc/base.c) in order
    to avoid a hole on 64bit archs.  (8 bytes saved per object)
    
    Also change all pid_entry arrays to be const qualified, to make clear they
    must not be modified.
    
    Before (on x86_64) :
    
    # size fs/proc/base.o
       text    data     bss     dec     hex filename
      15549    2192       0   17741    454d fs/proc/base.o
    
    After :
    
    # size fs/proc/base.o
       text    data     bss     dec     hex filename
      17229     176       0   17405    43fd fs/proc/base.o
    
    Thats 336 bytes saved on kernel size on x86_64
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d9a2f4a4945ebff54c9a011e4dc6e92d899ae26d
Author: Amit Choudhary <amit2030@gmail.com>
Date:   Tue May 8 00:26:13 2007 -0700

    drivers/char/synclink.c: check kmalloc() return value
    
    Signed-off-by: Amit Choudhary <amit2030@gmail.com>
    Cc: Paul Fulghum <paulkf@microgate.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fd463870dc89cac0f590ea007e3a5210103b1b04
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:26:10 2007 -0700

    remove unused header file: drivers/char/digi.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b656eeace5378321324a34b5aeb6062c54e2e4ed
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:26:06 2007 -0700

    remove unused header file: drivers/message/i2o/i2o_lan.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: Markus Lidel <Markus.Lidel@shadowconnect.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5096add84b9e96e2e0a9c72675c442fe5433388a
Author: Kees Cook <kees@outflux.net>
Date:   Tue May 8 00:26:04 2007 -0700

    proc: maps protection
    
    The /proc/pid/ "maps", "smaps", and "numa_maps" files contain sensitive
    information about the memory location and usage of processes.  Issues:
    
    - maps should not be world-readable, especially if programs expect any
      kind of ASLR protection from local attackers.
    - maps cannot just be 0400 because "-D_FORTIFY_SOURCE=2 -O2" makes glibc
      check the maps when %n is in a *printf call, and a setuid(getuid())
      process wouldn't be able to read its own maps file.  (For reference
      see http://lkml.org/lkml/2006/1/22/150)
    - a system-wide toggle is needed to allow prior behavior in the case of
      non-root applications that depend on access to the maps contents.
    
    This change implements a check using "ptrace_may_attach" before allowing
    access to read the maps contents.  To control this protection, the new knob
    /proc/sys/kernel/maps_protect has been added, with corresponding updates to
    the procfs documentation.
    
    [akpm@linux-foundation.org: build fixes]
    [akpm@linux-foundation.org: New sysctl numbers are old hat]
    Signed-off-by: Kees Cook <kees@outflux.net>
    Cc: Arjan van de Ven <arjan@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4a1ccb5b1eff949a90ab830869cb23d6609c3d5f
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:26:02 2007 -0700

    virtual_eisa_root_init() should be __init
    
    WARNING: vmlinux - Section mismatch: reference to
    .init.text:eisa_root_register from .text between 'virtual_eisa_root_init' (at
    offset 0xc026b80f) and 'cpufreq_debug_disable_ratelimit'
    
    Cc: Dave Jones <davej@codemonkey.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cd436afd6ef36d2c31d216e0e6e6c6c35fa13907
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:26:01 2007 -0700

    rocket: remove modversions include
    
    It misspelled "MODVERSIONS" preprocessor variable with "CONFIG_MODVERSIONS".
    Just kill it all.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4ea1b0f4c4f656e0838a937c47be9544ed1c5118
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Tue May 8 00:25:58 2007 -0700

    floppy: handle device_create_file() failure while init
    
    This patch kills the "ignoring return value of 'device_create_file'"
    warning message.
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6de2d20235a2b8c751d39ec4b68347d66b19d815
Author: Surya <surya.prabhakar@wipro.com>
Date:   Tue May 8 00:25:57 2007 -0700

    replace pci_find_device in drivers/telephony/ixj.c
    
    Cleaning up of pci_find_device in drivers/telephony/ixj.c.
    
    Signed-off-by: Surya Prabhakar <surya.prabhakar@wipro.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d954e8edee5de90f8625c041ce177e04ae2c88fe
Author: Alex Williamson <alex.williamson@hp.com>
Date:   Tue May 8 00:25:55 2007 -0700

    tpm_infineon: add support for devices in mmio space
    
    tAdd adds support for devices living in MMIO space to the Infineon TPM
    driver.  These can be found on some of the newer HP ia64 systems.
    
    Signed-off-by: Alex Williamson <alex.williamson@hp.com>
    Cc: Kylene Jo Hall <kjhall@us.ibm.com>
    Acked-by: Marcel Selhorst <tpm@selhorst.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5843205b55d0ec9564289d4b41bab093ae15f51a
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:25:54 2007 -0700

    namei.c: remove utterly outdated comment
    
    We don't have a routine called namei() anymore since at least 2.3.x, and
    the comment is just totally out of sync with the current lookup logic.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit acb0c854fa9483fa85e377b9f342352ea814a580
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:25:52 2007 -0700

    vfs: remove superflous sb == NULL checks
    
    inode->i_sb is always set, not need to check for it.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 578c8183c116e623d53b05d4c79762d053c7090f
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Tue May 8 00:25:49 2007 -0700

    proc: remove pathetic ->deleted WARN_ON
    
    WARN_ON(de && de->deleted); is sooo unreliable. Why?
    
    proc_lookup				remove_proc_entry
    ===========				=================
    lock_kernel();
    spin_lock(&proc_subdir_lock);
    [find proc entry]
    spin_unlock(&proc_subdir_lock);
    					spin_lock(&proc_subdir_lock);
    					[find proc entry]
    
    proc_get_inode
    ==============
    WARN_ON(de && de->deleted);			...
    
    					if (!atomic_read(&de->count))
    						free_proc_entry(de);
    					else
    						de->deleted = 1;
    
    So, if you have some strange oops [1], and doesn't see this WARN_ON it means
    nothing.
    
    [1] try_module_get() of module which doesn't exist, two lines below
        should suffice, or not?
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 59cd0cbc75367b82f704f63b104117462275060d
Author: Darrick J. Wong <djwong@us.ibm.com>
Date:   Tue May 8 00:25:47 2007 -0700

    Fix race between proc_readdir and remove_proc_entry
    
    Fix the following race:
    
    proc_readdir				remove_proc_entry
    ============				=================
    
    spin_lock(&proc_subdir_lock);
    [choose PDE to start filldir from]
    spin_unlock(&proc_subdir_lock);
    					spin_lock(&proc_subdir_lock);
    					[find PDE]
    					[free PDE, refcount is 0]
    					spin_unlock(&proc_subdir_lock);
    		    /* boom */
    if (filldir(dirent, de->name, ...
    
    [de_put on error path --adobriyan]
    Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7695650a924a6859910c8c19dfa43b4d08224d66
Author: Alexey Dobriyan <adobriyan@openvz.org>
Date:   Tue May 8 00:25:45 2007 -0700

    Fix race between proc_get_inode() and remove_proc_entry()
    
    proc_lookup				remove_proc_entry
    ===========				=================
    
    lock_kernel();
    spin_lock(&proc_subdir_lock);
    [find PDE with refcount 0]
    spin_unlock(&proc_subdir_lock);
    					spin_lock(&proc_subdir_lock);
    					[find PDE with refcount 0]
    					[check refcount and free PDE]
    					spin_unlock(&proc_subdir_lock);
    proc_get_inode:
    	de_get(de); /* boom */
    
    Signed-off-by: Alexey Dobriyan <adobriyan@openvz.org>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 79c0b2df79eb56fc71e54c75cd7fb3acf84370f9
Author: Miklos Szeredi <mszeredi@suse.cz>
Date:   Tue May 8 00:25:43 2007 -0700

    add filesystem subtype support
    
    There's a slight problem with filesystem type representation in fuse
    based filesystems.
    
    From the kernel's view, there are just two filesystem types: fuse and
    fuseblk.  From the user's view there are lots of different filesystem
    types.  The user is not even much concerned if the filesystem is fuse based
    or not.  So there's a conflict of interest in how this should be
    represented in fstab, mtab and /proc/mounts.
    
    The current scheme is to encode the real filesystem type in the mount
    source.  So an sshfs mount looks like this:
    
      sshfs#user@server:/   /mnt/server    fuse   rw,nosuid,nodev,...
    
    This url-ish syntax works OK for sshfs and similar filesystems.  However
    for block device based filesystems (ntfs-3g, zfs) it doesn't work, since
    the kernel expects the mount source to be a real device name.
    
    A possibly better scheme would be to encode the real type in the type
    field as "type.subtype".  So fuse mounts would look like this:
    
      /dev/hda1       /mnt/windows   fuseblk.ntfs-3g   rw,...
      user@server:/   /mnt/server    fuse.sshfs        rw,nosuid,nodev,...
    
    This patch adds the necessary code to the kernel so that this can be
    correctly displayed in /proc/mounts.
    
    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 880afc4d76af452267174b5989943f081c1db2c0
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 00:25:42 2007 -0700

    oss: strlcpy is smart enough
    
    strlcpy already accounts for the trailing zero in its length
    computation, so there is no need to substract one to the buffer size.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6192bd536f96c6a0d969081bc71ae24f9319bfdc
Author: Davide Libenzi <davidel@xmailserver.org>
Date:   Tue May 8 00:25:41 2007 -0700

    epoll: optimizations and cleanups
    
    Epoll is doing multiple passes over the ready set at the moment, because of
    the constraints over the f_op->poll() call.  Looking at the code again, I
    noticed that we already hold the epoll semaphore in read, and this
    (together with other locking conditions that hold while doing an
    epoll_wait()) can lead to a smarter way [1] to "ship" events to userspace
    (in a single pass).
    
    This is a stress application that can be used to test the new code.  It
    spwans multiple thread and call epoll_wait() and epoll_ctl() from many
    threads.  Stress tested on my dual Opteron 254 w/out any problems.
    
    http://www.xmailserver.org/totalmess.c
    
    This is not a benchmark, just something that tries to stress and exploit
    possible problems with the new code.
    Also, I made a stupid micro-benchmark:
    
    http://www.xmailserver.org/epwbench.c
    
    [1] Considering that epoll must be thread-safe, there are five ways we can
        be hit during an epoll_wait() transfer loop (ep_send_events()):
    
        1) The epoll fd going away and calling ep_free
           This just can't happen, since we did an fget() in sys_epoll_wait
    
        2) An epoll_ctl(EPOLL_CTL_DEL)
           This can't happen because epoll_ctl() gets ep->sem in write, and
           we're holding it in read during ep_send_events()
    
        3) An fd stored inside the epoll fd going away
           This can't happen because in eventpoll_release_file() we get
           ep->sem in write, and we're holding it in read during
           ep_send_events()
    
        4) Another epoll_wait() happening on another thread
           They both can be inside ep_send_events() at the same time, we get
           (splice) the ready-list under the spinlock, so each one will get
           its own ready list. Note that an fd cannot be at the same time
           inside more than one ready list, because ep_poll_callback() will
           not re-queue it if it sees it already linked:
    
           if (ep_is_linked(&epi->rdllink))
                    goto is_linked;
    
           Another case that can happen, is two concurrent epoll_wait(),
           coming in with a userspace event buffer of size, say, ten.
           Suppose there are 50 event ready in the list. The first
           epoll_wait() will "steal" the whole list, while the second, seeing
           no events, will go to sleep. But at the end of ep_send_events() in
           the first epoll_wait(), we will re-inject surplus ready fds, and we
           will trigger the proper wake_up to the second epoll_wait().
    
        5) ep_poll_callback() hitting us asyncronously
           This is the tricky part. As I said above, the ep_is_linked() test
           done inside ep_poll_callback(), will guarantee us that until the
           item will result linked to a list, ep_poll_callback() will not try
           to re-queue it again (read, write data on any of its members). When
           we do a list_del() in ep_send_events(), the item will still satisfy
           the ep_is_linked() test (whatever data is written in prev/next,
           it'll never be its own pointer), so ep_poll_callback() will still
           leave us alone. It's only after the eventual smp_mb()+INIT_LIST_HEAD(&epi->rdllink)
           that it'll become visible to ep_poll_callback(), but at the point
           we're already past it.
    
    [akpm@osdl.org: 80 cols]
    Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 44171df8e944f0bc8f7fa3f6d080f3e671431989
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:25:37 2007 -0700

    the scheduled removal of OBSOLETE_OSS options
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Paul Mackerras <paulus@samba.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fedee54d8f12cdfde299f181fec5c62b0c647ad6
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Tue May 8 00:25:34 2007 -0700

    ext3: dirindex error pointer issues
    
    - ext3_dx_find_entry() exit with out setting proper error pointer
    
    - do_split() exit with out setting proper error pointer
      it is realy painful because many callers contain folowing code:
    
              de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
              if (!(de))
                           return retval;
              <<< WOW retval wasn't changed by do_split(), so caller failed
              <<< but return SUCCESS :)
    
    - Rearrange do_split() error path. Current error path is realy ugly, all
      this up and down jump stuff doesn't make code easy to understand.
    
    [dmonakhov@sw.ru: fix annoying fake error messages]
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Cc: Andreas Dilger <adilger@clusterfs.com>
    Cc: Theodore Ts'o <tytso@mit.edu>
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 753e9c5cd9b123156152c66c816f751954b15e53
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue May 8 00:25:32 2007 -0700

    Optimize timespec_trunc()
    
    The first thing done by timespec_trunc() is :
    
      if (gran <= jiffies_to_usecs(1) * 1000)
    
    This should really be a test against a constant known at compile time.
    
    Alas, it isnt. jiffies_to_usec() was unilined so C compiler emits a function
    call and a multiply to compute : a CONSTANT.
    
    mov    $0x1,%edi
    mov    %rbx,0xffffffffffffffe8(%rbp)
    mov    %r12,0xfffffffffffffff0(%rbp)
    mov    %edx,%ebx
    mov    %rsi,0xffffffffffffffc8(%rbp)
    mov    %rsi,%r12
    callq  ffffffff80232010 <jiffies_to_usecs>
    imul   $0x3e8,%eax,%eax
    cmp    %ebx,%eax
    
    This patch reorders kernel/time.c a bit so that jiffies_to_usecs() is defined
    before timespec_trunc() so that compiler now generates :
    
    cmp    $0x3d0900,%edx  (HZ=250 on my machine)
    
    This gives a better code (timespec_trunc() becoming a leaf function), and
    shorter kernel size as well.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: john stultz <johnstul@us.ibm.com>
    Cc: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2e17c5508fa015f2c7690e29041f437e9308c64f
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 8 00:25:29 2007 -0700

    init dma masks in pnp_dev
    
    PNP now initializes device dma masks, which prevents oopses when generic
    dma calls are made using pnp device nodes.
    
    This assumes PNP only uses ISA DMA, with 24 bit addresses; and that it's
    safe to init those masks for all devices (rather than finding out which
    devices have been assigned DMA channels, and handling only those).
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Adam Belay <abelay@novell.com>
    Cc: Jaroslav Kysela <perex@suse.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6f8bc500a10ab9cb3861e5bb71155d7bd2bbd2d5
Author: Josh Triplett <josh@freedesktop.org>
Date:   Tue May 8 00:25:24 2007 -0700

    rcutorture: Mark rcu_torture_init as __init
    
    The corresponding rcu_torture_cleanup cannot get marked as __exit, because
    rcu_torture_init uses it to clean up if init fails.
    
    Signed-off-by: Josh Triplett <josh@freedesktop.org>
    Acked-by: "Paul E. McKenney" <paulmck@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e3222c4ecc649c4ae568e61dda9349482401b501
Author: Badari Pulavarty <pbadari@us.ibm.com>
Date:   Tue May 8 00:25:21 2007 -0700

    Merge sys_clone()/sys_unshare() nsproxy and namespace handling
    
    sys_clone() and sys_unshare() both makes copies of nsproxy and its associated
    namespaces.  But they have different code paths.
    
    This patch merges all the nsproxy and its associated namespace copy/clone
    handling (as much as possible).  Posted on container list earlier for
    feedback.
    
    - Create a new nsproxy and its associated namespaces and pass it back to
      caller to attach it to right process.
    
    - Changed all copy_*_ns() routines to return a new copy of namespace
      instead of attaching it to task->nsproxy.
    
    - Moved the CAP_SYS_ADMIN checks out of copy_*_ns() routines.
    
    - Removed unnessary !ns checks from copy_*_ns() and added BUG_ON()
      just incase.
    
    - Get rid of all individual unshare_*_ns() routines and make use of
      copy_*_ns() instead.
    
    [akpm@osdl.org: cleanups, warning fix]
    [clg@fr.ibm.com: remove dup_namespaces() declaration]
    [serue@us.ibm.com: fix CONFIG_IPC_NS=n, clone(CLONE_NEWIPC) retval]
    [akpm@linux-foundation.org: fix build with CONFIG_SYSVIPC=n]
    Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
    Signed-off-by: Serge Hallyn <serue@us.ibm.com>
    Cc: Cedric Le Goater <clg@fr.ibm.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: <containers@lists.osdl.org>
    Signed-off-by: Cedric Le Goater <clg@fr.ibm.com>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4fc75ff4816c3483b4b772b2f6cb3d8fd88ca547
Author: Nick Piggin <npiggin@suse.de>
Date:   Tue May 8 00:25:16 2007 -0700

    exec: fix remove_arg_zero
    
    Petr Tesarik discovered a problem in remove_arg_zero(). He writes:
    
     When a script is loaded, load_script() replaces argv[0] with the
     name of the interpreter and the filename passed to the exec syscall.
     However, there is no guarantee that the length of the interpreter
     name plus the length of the filename is greater than the length of
     the original argv[0]. If the difference happens to cross a page boundary,
     setup_arg_pages() will call put_dirty_page() [aka install_arg_page()]
     with an address outside the VMA.
    
     Therefore, remove_arg_zero() must free all pages which would be unused
     after the argument is removed.
    
    So, rewrite the remove_arg_zero function without gotos, with a few comments,
    and with the commonly used explicit index/offset. This fixes the problem
    and makes it easier to understand as well.
    
    [a.p.zijlstra@chello.nl: add comment]
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Petr Tesarik <ptesarik@suse.cz>
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit af7c693f146069a1f44739acef9abf1bc27f7247
Author: Guy Streeter <streeter@redhat.com>
Date:   Tue May 8 00:25:12 2007 -0700

    Cap shmmax at INT_MAX in compat shminfo
    
    The value of shmmax may be larger than will fit in the struct used by
    the 32bit compat version of sys_shmctl. This change mirrors what the
    normal sys_shmctl does when called with the old IPC_INFO command.
    
    Signed-off-by: Guy Streeter <streeter@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ee527cd3a20c2aeaac17d939e5d011f7a76d69f5
Author: Prarit Bhargava <prarit@redhat.com>
Date:   Tue May 8 00:25:08 2007 -0700

    Use stop_machine_run in the Intel RNG driver
    
    Replace call_smp_function with stop_machine_run in the Intel RNG driver.
    
    CPU A has done read_lock(&lock)
    CPU B has done write_lock_irq(&lock) and is waiting for A to release the lock.
    
    A third CPU calls call_smp_function and issues the IPI.  CPU A takes CPU
    C's IPI.  CPU B is waiting with interrupts disabled and does not see the
    IPI.  CPU C is stuck waiting for CPU B to respond to the IPI.
    
    Deadlock.
    
    The solution is to use stop_machine_run instead of call_smp_function
    (call_smp_function should not be called in situations where the CPUs may be
    suspended).
    
    [haruo.tomita@toshiba.co.jp: fix a typo in mod_init()]
    [haruo.tomita@toshiba.co.jp: fix memory leak]
    Signed-off-by: Prarit Bhargava <prarit@redhat.com>
    Cc: Jan Beulich <jbeulich@novell.com>
    Cc: "Tomita, Haruo" <haruo.tomita@toshiba.co.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 616883df78bd4b3fcdb6ddc39bd3d4cb902bfa32
Author: Monakhov Dmitriy <dmonakhov@openvz.org>
Date:   Tue May 8 00:25:07 2007 -0700

    IRQ: add __must_check to request_irq
    
    This could help to find buggy drivers where request_irq return value wasn't
    checked.  There's just no reason to ignore errors which can and do occur.
    Anyone who got warning during compilation have to realise what it is't
    realy safe code.
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c761c84154dcd952182e4867d841298c9eb0b14b
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:25:02 2007 -0700

    kconfig: centralize the selection of semaphore debugging in lib/Kconfig.debug
    
    Remove the Kconfig selection of semaphore debugging from the ALPHA and FRV
    Kconfig files, and centralize it in lib/Kconfig.debug.
    
    There doesn't seem to be much point in letting individual architectures
    independently define the same Kconfig option when it can just as easily be
    put in a single Kconfig file and made dependent on a subset of
    architectures.  that way, at least the option shows up in the same relative
    location in the menu each time.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f87367a6b1e3ec1fd440158e5eb357fbd5c2288e
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 8 00:25:01 2007 -0700

    reiserfs: correct misspelled "REISERFS_PROC_INFO" to "CONFIG_REISERFS_PROC_INFO"
    
    Correct the misspelling of the preprocessor check of a Kconfig option to refer
    to CONFIG_REISERFS_PROC_INFO and not just the incorrect REISERFS_PROC_INFO.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6d4f9c55002544bac1c99d0bab46c89319ab876e
Author: Pekka Enberg <penberg@cs.helsinki.fi>
Date:   Tue May 8 00:24:58 2007 -0700

    module: use krealloc
    
    This converts an open-coded krealloc() to use the shiny new API.
    
    Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Acked-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fe08a9d4982d9618ec25760ea715c46fe051e508
Author: Alexey Dobriyan <adobriyan@gmail.com>
Date:   Tue May 8 00:24:55 2007 -0700

    reiserfs: shrink superblock if no xattrs
    
    This makes in-core superblock fit into one cacheline here.
    
    Before:
        struct dentry *            xattr_root;           /*   124     4 */
        /* --- cacheline 1 boundary (128 bytes) --- */
        struct rw_semaphore        xattr_dir_sem;        /*   128    12 */
        int                        j_errno;              /*   140     4 */
        }; /* size: 144, cachelines: 2 */
           /* sum members: 142, holes: 1, sum holes: 2 */
           /* last cacheline: 16 bytes */
    
    After:
        int                        j_errno;              /*   124     4 */
        /* --- cacheline 1 boundary (128 bytes) --- */
        }; /* size: 128, cachelines: 1 */
           /* sum members: 126, holes: 1, sum holes: 2 */
    
    Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
    Cc: <reiserfs-dev@namesys.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6f2fad748ccced5b9313efce2a2c7ae4c04ef564
Author: Nicolas Boichat <nicolas@boichat.ch>
Date:   Tue May 8 00:24:52 2007 -0700

    Apple SMC driver (hardware monitoring and control)
    
    This driver provides support for the Apple System Management Controller, which
    provides an accelerometer (Apple Sudden Motion Sensor), light sensors,
    temperature sensors, keyboard backlight control and fan control. Only
    Intel-based Apple's computers are supported (MacBook Pro, MacBook, MacMini).
    
    [bunk@stusta.de: make drivers/hwmon/applesmc.c:backlight_work stati]
    [khali@linux-fr.org: fix temperature attribute file names]
    Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
    Cc: Jean Delvare <khali@linux-fr.org>
    Cc: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ee7b9e3706b9c5f90113eb16a1a84a1c01e09f95
Author: Michal Schmidt <xschmi00@stud.feec.vutbr.cz>
Date:   Tue May 8 00:24:49 2007 -0700

    Fix compilation of drivers with -O0
    
    It is sometimes useful to compile individual drivers with optimization
    disabled for easier debugging.  Currently drivers which use htonl() and
    similar functions don't compile with -O0.  This patch fixes it.  It also
    removes obsolete and misleading comments.  This header is not for
    userspace, so we don't have to care about strange programs these comments
    mention.
    
    (akpm: -O0 probably isn't a good idea, but this code looks pretty crufty and
    unuseful)
    
    Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 46595390e97b3ab2741a36f5ff69e8f6033fa9c0
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:24:47 2007 -0700

    init/do_mounts.c: proper prepare_namespace() prototype
    
    Add a proper protype for prepare_namespace() in include/linux/init.h.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b2ead6e012e2b2ab31851c288e0dd7872884a8a3
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Tue May 8 00:24:42 2007 -0700

    fix section mismatch warning in lib/swiotlb.c
    
    kbuild spits outs following warning on a
    defconfig x86_64 build:
    WARNING: swiotlb.o - Section mismatch: reference to .init.text:swiotlb_init from __ksymtab between '__ksymtab_swiotlb_init' (at offset 0xa0) and '__ksymtab_swiotlb_free_coherent'
    
    This warning happens because the function swiotlb_init is marked __init and
    EXPORT_SYMBOL().  A 'git grep swiotlb_init' showed no users in drivers/ so
    remove the EXPORT_SYMBOL.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3c308798a337d75d846773dd64155860852931fc
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue May 8 00:24:39 2007 -0700

    scripts: kernel-doc whitespace cleanup
    
    Whitespace cleanup only:  convert some series of spaces to tabs.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2d3466a348a61c4d7f958ce80020eba17c09d7f7
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Tue May 8 00:24:37 2007 -0700

    reiserfs: possible null pointer dereference during resize
    
    sb_read may return NULL, let's explicitly check it.  If so free new bitmap
    blocks array, after this we may safely exit as it done above during bitmap
    allocation.
    
    Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 82f703bb8cb2732b4437a9f555a1be564e9e71c2
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Tue May 8 00:24:34 2007 -0700

    freevxfs: possible null pointer dereference fix
    
    sb_read may return NULL, so let's explicitly check it.
    
    Signed-off-by: Dmitriy Monakhov <dmonakhov@openvz.org>
    Acked-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1368c4f2482c9e06bcb297217433818b171cc9e3
Author: Vignesh Babu BM <vignesh.babu@wipro.com>
Date:   Tue May 8 00:24:32 2007 -0700

    is_power_of_2 in fs/block_dev.c
    
    Replace (n & (n-1)) in the context of power of 2 checks with is_power_of_2
    
    Signed-off-by: vignesh babu <vignesh.babu@wipro.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e1b5c1d3da05c91129120d045dfcdfc7761f44f1
Author: Vignesh Babu BM <vignesh.babu@wipro.com>
Date:   Tue May 8 00:24:30 2007 -0700

    is_power_of_2 in fs/hfs
    
    Replace (n & (n-1)) in the context of power of 2 checks with is_power_of_2
    
    Signed-off-by: vignesh babu <vignesh.babu@wipro.com>
    Cc: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e7d709c096487078652a1384d7a2d0e4459e18b6
Author: Vignesh Babu BM <vignesh.babu@wipro.com>
Date:   Tue May 8 00:24:27 2007 -0700

    is_power_of_2 in fat
    
    Replacing (n & (n-1)) in the context of power of 2 checks with
    is_power_of_2
    
    Signed-off-by: vignesh babu <vignesh.babu@wipro.com>
    Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4fa156ea846daae44d60b05ea066d0e28fd3b6c4
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 8 00:24:24 2007 -0700

    drivers/char/hvc_console.c: cleanups
    
    - make needlessly global code static
    - remove the unused EXPORT_SYMBOL's
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6309ed7cb2b0671b0db9386abc6307ec3108bbaa
Author: Alan <alan@lxorguk.ukuu.org.uk>
Date:   Tue May 8 00:24:21 2007 -0700

    tty: Clarify documentation of ->write()
    
    The tty driver write method is different to the usual fops device write
    methods as the buffer is already in kernel space. Clarify the docs since
    someone writing a driver made that mistake.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3972b7f67bf1a352a4a4c350b2245d759a41ea06
Author: Florin Malita <fmalita@gmail.com>
Date:   Tue May 8 00:24:18 2007 -0700

    devpts: add fsnotify create event
    
    Currently, devpts doesn't generate an fsnotify event upon pts creation
    because the regular vfs paths aren't involved.  Deallocation, on the other
    hand, correctly generates a nameremove event thanks to the d_delete()
    invocation in devpts_pty_kill().
    
    This patch adds the missing fsnotify_create() trigger in devpts_pty_new().
    
    Signed-off-by: Florin Malita <fmalita@gmail.com>
    Acked-by: H. Peter Anvin <hpa@zytor.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1ae7075bcd805c3aa5e8f53effc63a4562d6110e
Author: Chris Snook <csnook@redhat.com>
Date:   Tue May 8 00:24:15 2007 -0700

    use use SEEK_MAX to validate user lseek arguments
    
    Add SEEK_MAX and use it to validate lseek arguments from userspace.
    
    Signed-off-by: Chris Snook <csnook@redhat.com>
    Acked-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7b8e89249ba54fb6e12358bbed7e3070fa1d1e6a
Author: Chris Snook <csnook@redhat.com>
Date:   Tue May 8 00:24:13 2007 -0700

    use symbolic constants in generic lseek code
    
    Convert magic numbers to SEEK_* values from fs.h
    
    Signed-off-by: Chris Snook <csnook@redhat.com>
    Acked-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5b7952021289b6d04d8c62c0f13acce570730dcd
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Tue May 8 00:24:07 2007 -0700

    Documentation: Ask driver writers to provide PM support
    
    Add a paragraph in Documentation/SubmittingDrivers requesting that the
    basic PM support be provided by new device drivers.
    
    Add two new documents in Documentation/power/ giving general instructions
    on debugging the suspend/resume functionality and testing the suspend and
    resume support in device drivers.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Cc: Pavel Machek <pavel@ucw.cz>
    Cc: David Brownell <david-b@pacbell.net>
    Cc: Nigel Cunningham <ncunningham@linuxmail.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8e2c20023f34b652605a5fb7c68bb843d2b100a8
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Tue May 8 00:24:05 2007 -0700

    Fix constant folding and poor optimization in byte swapping code
    
    Constant folding does not work for the swabXX() byte swapping functions,
    and the C versions optimize poorly.
    
    Attempting to initialize a global variable to swab16(0x1234) or put
    something like "case swab32(42):" in a switch statement will not compile.
    It can work, swab.h just isn't doing it correctly.  This patch fixes that.
    
    Contrary to the comment in asm-i386/byteorder.h, gcc does not recognize the
    "C" version of swab16 and turn it into efficient code.  gcc can do this,
    just not with the current code.  The simple function:
    
    u16 foo(u16 x) { return swab16(x); }
    
    Would compile to:
            movzwl  %ax, %eax
            movl    %eax, %edx
            shrl    $8, %eax
            sall    $8, %edx
            orl     %eax, %edx
    
    With this patch, it will compile to:
            rolw    $8, %ax
    
    I also attempted to document the maze different macros/inline functions
    that are used to create the final product.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Cc: Francois-Rene Rideau <fare@tunes.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 02fb6149f7a64c62934c035e7635321cb9a8cf2e
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date:   Tue May 8 00:24:03 2007 -0700

    softlockup: s/99/MAX_RT_PRIO/
    
    Don't use hardcoded 99 value, use MAX_RT_PRIO.
    
    Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1065d130dddc3241706c50a01ced7b03bcb657be
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date:   Tue May 8 00:24:01 2007 -0700

    freezer: task->exit_state should be treated as bolean
    
    Except for BUG_ON() checks, we should not use EXIT_XXXX defines outside of
    exit/wait paths.
    
    Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
    Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
    Cc: Pavel Machek <pavel@ucw.cz>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fca3b747795ae24f9667b6c9a69975f9eb98a2c0
Author: Corey Minyard <minyard@acm.org>
Date:   Tue May 8 00:23:59 2007 -0700

    ipmi: add pci remove handling
    
    Add pci_remove handling to the driver, so it will clean up if
    the device is hot-removed.
    
    Signed-off-by: Corey Minyard <minyard@acm.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f64da958dfc83335de1d2bef9d3868f30feb4e53
Author: Corey Minyard <minyard@acm.org>
Date:   Tue May 8 00:23:58 2007 -0700

    ipmi: add new IPMI nmi watchdog handling
    
    Convert over to the new NMI handling for getting IPMI watchdog timeouts via an
    NMI.  This add config options to know if there is the ability to receive NMIs
    and if it has an NMI post processing call.  Then it modifies the IPMI watchdog
    to take advantage of this so that it can know if an NMI comes in.
    
    It also adds testing that the IPMI NMI watchdog works.
    
    Signed-off-by: Corey Minyard <minyard@acm.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ee6cd5f8f573ad11f270a07fb201822c2862474d
Author: Corey Minyard <minyard@acm.org>
Date:   Tue May 8 00:23:54 2007 -0700

    ipmi: allow shared interrupts
    
    The IPMI driver used enable_irq and disable_irq when it got into situations
    where it couldn't allocate memory; it did this to avoid having the interrupt
    just lock the machine when it couldn't get memory to perform the transaction
    to disable the interrupt.
    
    This patch modifies the driver to not use disable_irq and enable_irq.  It
    instead sends the messages to the BMC to perform this operation.  It also
    makes sure interrupts are cleanly disabled when the interface is shut down and
    cleans up some shutdown things that are no longer necessary.
    
    Signed-off-by: Corey Minyard <cminyard@mvista.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dba9b4f6a096f39dd58d67fbc643a7c1bf2973eb
Author: Corey Minyard <minyard@acm.org>
Date:   Tue May 8 00:23:51 2007 -0700

    ipmi: add powerpc openfirmware sensing
    
    Add support for of_platform_driver to the ipmi_si module.  When loading the
    module, the driver will be registered to of_platform.  The driver will be
    probed for all devices with the type ipmi.  It's supporting devices with
    compatible settings ipmi-kcs, ipmi-smic and ipmi-bt.  Only ipmi-kcs could be
    tested.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Acked-by: Heiko J Schick <schihei@de.ibm.com>
    Signed-off-by: Corey Minyard <minyard@acm.org>
    Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 24c32d733dd44dbc5b9dcd0b8de58e16fdbeac76
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Tue May 8 00:23:49 2007 -0700

    mm: shrink parent dentries when shrinking slab
    
    Teach the dentry slab shrinker to aggressively shrink parent dentries when
    shrinking the dentry cache.
    
    This is done to attempt to improve the situation where the dentry slab cache
    gets a lot of internal fragmentation due to pages containing directory
    dentries.  It is expected that this change will cause some of those dentries
    to be reaped earlier, and with less scanning.
    
    Needs careful testing.
    
    Cc: Miklos Szeredi <mszeredi@suse.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d52b908646b88cb1952ab8c9b2d4423908a23f11
Author: Miklos Szeredi <mszeredi@suse.cz>
Date:   Tue May 8 00:23:46 2007 -0700

    fix quadratic behavior of shrink_dcache_parent()
    
    The time shrink_dcache_parent() takes, grows quadratically with the depth
    of the tree under 'parent'.  This starts to get noticable at about 10,000.
    
    These kinds of depths don't occur normally, and filesystems which invoke
    shrink_dcache_parent() via d_invalidate() seem to have other depth
    dependent timings, so it's not even easy to expose this problem.
    
    However with FUSE it's easy to create a deep tree and d_invalidate()
    will also get called.  This can make a syscall hang for a very long
    time.
    
    This is the original discovery of the problem by Russ Cox:
    
      http://article.gmane.org/gmane.comp.file-systems.fuse.devel/3826
    
    The following patch fixes the quadratic behavior, by optionally allowing
    prune_dcache() to prune ancestors of a dentry in one go, instead of doing
    it one at a time.
    
    Common code in dput() and prune_one_dentry() is extracted into a new helper
    function d_kill().
    
    shrink_dcache_parent() as well as shrink_dcache_sb() are converted to use
    the ancestry-pruner option.  Only for shrink_dcache_memory() is this
    behavior not desirable, so it keeps using the old algorithm.
    
    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Maneesh Soni <maneesh@in.ibm.com>
    Acked-by: "Paul E. McKenney" <paulmck@us.ibm.com>
    Cc: Dipankar Sarma <dipankar@in.ibm.com>
    Cc: Neil Brown <neilb@suse.de>
    Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 97dc32cdb1b53832801159d5f634b41aad9d0a23
Author: William Cohen <wcohen@redhat.com>
Date:   Tue May 8 00:23:41 2007 -0700

    reduce size of task_struct on 64-bit machines
    
    This past week I was playing around with that pahole tool
    (http://oops.ghostprotocols.net:81/acme/dwarves/) and looking at the size
    of various struct in the kernel.  I was surprised by the size of the
    task_struct on x86_64, approaching 4K.  I looked through the fields in
    task_struct and found that a number of them were declared as "unsigned
    long" rather than "unsigned int" despite them appearing okay as 32-bit
    sized fields.  On x86_64 "unsigned long" ends up being 8 bytes in size and
    forces 8 byte alignment.  Is there a reason there a reason they are
    "unsigned long"?
    
    The patch below drops the size of the struct from 3808 bytes (60 64-byte
    cachelines) to 3760 bytes (59 64-byte cachelines).  A couple other fields
    in the task struct take a signficant amount of space:
    
    struct thread_struct       thread;               688
    struct held_lock           held_locks[30];       1680
    
    CONFIG_LOCKDEP is turned on in the .config
    
    [akpm@linux-foundation.org: fix printk warnings]
    Cc: <linux-arch@vger.kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4d7bf11d649c72621ca31b8ea12b9c94af380e63
Author: Markus Rechberger <Markus.Rechberger@amd.com>
Date:   Tue May 8 00:23:39 2007 -0700

    ext2/3/4: fix file date underflow on ext2 3 filesystems on 64 bit systems
    
    Taken from http://bugzilla.kernel.org/show_bug.cgi?id=5079
    
    signed long ranges from -2.147.483.648 to 2.147.483.647 on x86 32bit
    
    10000011110110100100111110111101 .. -2,082,844,739
    10000011110110100100111110111101 ..  2,212,122,557 <- this currently gets
    stored on the disk but when converting it to a 64bit signed long value it loses
    its sign and becomes positive.
    
    Cc: Andreas Dilger <adilger@dilger.ca>
    Cc: <linux-ext4@vger.kernel.org>
    
    Andreas says:
    
    This patch is now treating timestamps with the high bit set as negative
    times (before Jan 1, 1970).  This means we lose 1/2 of the possible range
    of timestamps (lopping off 68 years before unix timestamp overflow -
    now only 30 years away :-) to handle the extremely rare case of setting
    timestamps into the distant past.
    
    If we are only interested in fixing the underflow case, we could just
    limit the values to 0 instead of storing negative values.  At worst this
    will skew the timestamp by a few hours for timezones in the far east
    (files would still show Jan 1, 1970 in "ls -l" output).
    
    That said, it seems 32-bit systems (mine at least) allow files to be set
    into the past (01/01/1907 works fine) so it seems this patch is bringing
    the x86_64 behaviour into sync with other kernels.
    
    On the plus side, we have a patch that is ready to add nanosecond timestamps
    to ext3 and as an added bonus adds 2 high bits to the on-disk timestamp so
    this extends the maximum date to 2242.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8948e11f450e6189a79e47d6051c3d5a0b98e3f3
Author: Alexey Dobriyan <adobriyan@openvz.org>
Date:   Tue May 8 00:23:35 2007 -0700

    Allow access to /proc/$PID/fd after setuid()
    
    /proc/$PID/fd has r-x------ permissions, so if process does setuid(), it
    will not be able to access /proc/*/fd/. This breaks fstatat() emulation
    in glibc.
    
    open("foo", O_RDONLY|O_DIRECTORY)       = 4
    setuid32(65534)                         = 0
    stat64("/proc/self/fd/4/bar", 0xbfafb298) = -1 EACCES (Permission denied)
    
    Signed-off-by: Alexey Dobriyan <adobriyan@openvz.org>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: James Morris <jmorris@namei.org>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: Ulrich Drepper <drepper@redhat.com>
    Cc: Oleg Nesterov <oleg@tv-sign.ru>
    Acked-By: Kirill Korotaev <dev@openvz.org>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ab1b6f03a10ba1f5638188ab06bf46e33ac3a160
Author: Christoph Hellwig <hch@lst.de>
Date:   Tue May 8 00:23:29 2007 -0700

    simplify the stacktrace code
    
    Simplify the stacktrace code:
    
     - remove the unused task argument to save_stack_trace, it's always
       current
     - remove the all_contexts flag, it's alwasy 0
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Akinobu Mita <akinobu.mita@gmail.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7e4c3690b07f04b1942c39db358a5c8a72831daa
Author: Andrew Morton <akpm@osdl.org>
Date:   Tue May 8 00:23:27 2007 -0700

    block_write_full_page(): report ENOSPC
    
    block_write_full_page() forgot to propagate ENPSOC into the address_space.
    
    Cc: Guillaume Chazarain <guichaz@yahoo.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3e9f45bd18191bbd05468b19b7064b8da8262aba
Author: Guillaume Chazarain <guichaz@yahoo.fr>
Date:   Tue May 8 00:23:25 2007 -0700

    Factor outstanding I/O error handling
    
    Cleanup: setting an outstanding error on a mapping was open coded too many
    times.  Factor it out in mapping_set_error().
    
    Signed-off-by: Guillaume Chazarain <guichaz@yahoo.fr>
    Cc: Steven Whitehouse <swhiteho@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c83e44842074a87614c78eca70fa6467b0bc3c4a
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:23:22 2007 -0700

    uml: an idle system should have zero load average
    
    The ever-vigilant users of linode.com noticed that an idle 2.6 UML has a
    persistent load average of ~.4.
    
    It turns out that because the UML timer handler processed softirqs before
    actually delivering the tick, the tick was counted in the context of the idle
    thread about half the time.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f1adc05e77383017bc63ea9c48ba217da76682b8
Author: Jeff Dike <jdike@addtoit.com>
Date:   Tue May 8 00:23:18 2007 -0700

    uml: hostfs style fixes
    
    hostfs needed some style goodness.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5822b7faca709c03a59c2929005bfe9caffe6592
Author: Alberto Bertogli <albertito@gmail.com>
Date:   Tue May 8 00:23:16 2007 -0700

    uml: make hostfs_setattr() support operations on unlinked open files
    
    This patch allows hostfs_setattr() to work on unlinked open files by calling
    set_attr() (the userspace part) with the inode's fd.
    
    Without this, applications that depend on doing attribute changes to unlinked
    open files will fail.
    
    It works by using the fd versions instead of the path ones (for example
    fchmod() instead of chmod(), fchown() instead of chown()) when an fd is
    available.
    
    Signed-off-by: Alberto Bertogli <albertito@gmail.com>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0e6b9c98be1b517bf99a21d8a7036a8a21e47dd1
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Tue May 8 00:23:13 2007 -0700

    use SLAB_PANIC flag cleanup
    
    Use SLAB_PANIC and delete duplicated panic().
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Cc: Ian Molton <spyro@f2s.com>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 72280ede316911fd5a82ef78d12a6705b1007d36
Author: Yasunori Goto <y-goto@jp.fujitsu.com>
Date:   Tue May 8 00:23:10 2007 -0700

    Add white list into modpost.c for memory hotplug code and ia64's machvec section
    
    This patch is add white list into modpost.c for some functions and
    ia64's section to fix section mismatchs.
    
      sparse_index_alloc() and zone_wait_table_init() calls bootmem allocator
      at boot time, and kmalloc/vmalloc at hotplug time. If config
      memory hotplug is on, there are references of bootmem allocater(init text)
      from them (normal text). This is cause of section mismatch.
    
      Bootmem is called by many functions and it must be
      used only at boot time. I think __init of them should keep for
      section mismatch check. So, I would like to register sparse_index_alloc()
      and zone_wait_table_init() into white list.
    
      In addition, ia64's .machvec section is function table of some platform
      dependent code. It is mixture of .init.text and normal text. These
      reference of __init functions are valid too.
    
    Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
    Cc: Sam Ravnborg <sam@ravnborg.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a3142c8e1dd57ff48040bdb3478cff9312543dc3
Author: Yasunori Goto <y-goto@jp.fujitsu.com>
Date:   Tue May 8 00:23:07 2007 -0700

    Fix section mismatch of memory hotplug related code.
    
    This is to fix many section mismatches of code related to memory hotplug.
    I checked compile with memory hotplug on/off on ia64 and x86-64 box.
    
    Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0ceb331433e8aad9c5f441a965d7c681f8b9046f
Author: Dmitriy Monakhov <dmonakhov@openvz.org>
Date:   Tue May 8 00:23:02 2007 -0700

    mm: move common segment checks to separate helper function
    
    [akpm@linux-foundation.org: cleanup]
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Cc: Christoph Hellwig <hch@lst.de>
    Acked-by: Anton Altaparmakov <aia21@cam.ac.uk>
    Acked-by: David Chinner <dgc@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b46b8f19c9cd435ecac4d9d12b39d78c137ecd66
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Tue May 8 00:22:59 2007 -0700

    Increase slab redzone to 64bits
    
    There are two problems with the existing redzone implementation.
    
    Firstly, it's causing misalignment of structures which contain a 64-bit
    integer, such as netfilter's 'struct ipt_entry' -- causing netfilter
    modules to fail to load because of the misalignment.  (In particular, the
    first check in
    net/ipv4/netfilter/ip_tables.c::check_entry_size_and_hooks())
    
    On ppc32 and sparc32, amongst others, __alignof__(uint64_t) == 8.
    
    With slab debugging, we use 32-bit redzones. And allocated slab objects
    aren't sufficiently aligned to hold a structure containing a uint64_t.
    
    By _just_ setting ARCH_KMALLOC_MINALIGN to __alignof__(u64) we'd disable
    redzone checks on those architectures.  By using 64-bit redzones we avoid that
    loss of debugging, and also fix the other problem while we're at it.
    
    When investigating this, I noticed that on 64-bit platforms we're using a
    32-bit value of RED_ACTIVE/RED_INACTIVE in the 64-bit memory location set
    aside for the redzone.  Which means that the four bytes immediately before
    or after the allocated object at 0x00,0x00,0x00,0x00 for LE and BE
    machines, respectively.  Which is probably not the most useful choice of
    poison value.
    
    One way to fix both of those at once is just to switch to 64-bit
    redzones in all cases.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>
    Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Acked-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 821de3a27bf33f11ec878562577c586cd5f83c64
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Tue May 8 19:12:23 2007 +0200

    [PATCH] ll_rw_blk: fix missing bounce in blk_rq_map_kern()
    
    I think we might just need the blk_map_kern users now. For the async
    execute I added the bounce code already and the block SG_IO has it
    atleady. I think the blk_map_kern bounce code got dropped because we
    thought the correct gfp_t would be passed in. But I think all we need is
    the patch below and all the paths are take care of. The patch is not
    tested. Patch was made against scsi-misc.
    
    The last place that is sending non sg commands may just be md/dm-emc.c
    but that is is just waiting on alasdair to take some patches that fix
    that and a bunch of junk in there including adding bounce support. If
    the patch below is ok though and dm-emc finally gets converted then it
    will have sg and bonce buffer support.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 1d72acf91abb327e25137ad2e371c1a788b34e45
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Tue May 8 17:22:04 2007 +0200

    Use menuconfig objects - hwmon
    
    Change Kconfig objects from "menu, config" into "menuconfig" so
    that the user can disable the whole feature without having to
    enter the menu first.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 3659a0178f76d13174e8924416e5d6805ea9bad1
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/smsc47b397: Use dynamic sysfs callbacks
    
    This lets us get rid of macro-generated functions and shrinks the
    driver size by a small amount.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 292fc1a5ff44d477ff335a343a48d2b67bbc70e3
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/smsc47b397: Convert to a platform driver
    
    Convert the smsc47b397 driver from the nonsensical i2c-isa hack to a
    regular platform driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit f5f8d38b18cb7731a8dbcd982f1b80370f0f19cd
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/w83781d: Deprecate W83627HF support
    
    The W83627HF is better supported by the w83627hf driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 348753379a7704087603dad403603e825422fd9a
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/w83781d: Use dynamic sysfs callbacks
    
    This lets us get rid of some of the macro-generated functions and
    shrinks the driver size significantly (about 9%).
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 31b8dc4d58b9905a77412c06fc0b22aa19c1cc1d
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/w83781d: Be less i2c_client-centric
    
    Use the driver data structure as the main device reference, instead of
    the i2c client. It makes the driver a bit smaller, and makes more sense
    as this is an hybrid driver, supporting both I2C and ISA devices.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 474d00a8912f56241cec6e1832ce390e87bfb243
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:03 2007 +0200

    hwmon/w83781d: Clean up conversion macros
    
    * Fix voltage rounding
    * Drop useless macros
    * Drop useless casts
    * Turn macros evaluating their parameters more than once into inline
      functions
    * Use signed variables for temperatures
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 7666c13c627fdc65e8057013893c183c3bafe59e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon/w83781d: No longer use i2c-isa
    
    Reimplement the ISA device support as a platform driver, so that we no
    longer rely on i2c-isa.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 47a5dba1dca723d890d0b9409c82e72311a1f641
Author: Olaf Hering <olaf@aepfle.de>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon/ams: Do not print error on systems without apple motion sensor
    
    It is not an error if a system has no ams hardware.  Do not clutter dmesg
    in this case.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Acked-by: Michael Hanselmann <linux-kernel@hansmi.ch>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 63232dcd555d60d70ce8e09b53c8ef8e4a49a3f9
Author: Stelian Pop <stelian@popies.net>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon/ams: Fix I2C read retry logic
    
    Fix sleep and retry logic in ams-i2c.
    
    Signed-off-by: Stelian Pop <stelian@popies.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 2d8dd65fc14287f2c004dd755e517ba0f45d446e
Author: Alessandro Zummo <azummo-lists@towertech.it>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon: New AD7416, AD7417 and AD7418 driver
    
    A driver for the Analog Devices AD7416, AD7417 and AD7418 chips.
    
    Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit d58ee056cc40117afe4d3bb03006ac537d779634
Author: Rudolf Marek <r.marek@assembler.cz>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon/coretemp: Add documentation
    
    Documentation for the coretemp driver.
    
    Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit bebe467823c0d8eeb7f49115c255d8a235a20ddb
Author: Rudolf Marek <r.marek@assembler.cz>
Date:   Tue May 8 17:22:02 2007 +0200

    hwmon: New coretemp driver
    
    Add the support for the digital temperature sensor found in recent
    Intel Core CPUs.
    
    Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 78a62d2c9817dc1adfc563f5a7654df2c89be416
Author: Nicolas Boichat <nicolas@boichat.ch>
Date:   Tue May 8 17:22:01 2007 +0200

    i386: Use functions from library in msr driver
    
    Use safe MSR functions provided by arch/*/lib/msr-on-cpu.c in
    arch/i386/kernel/msr.c.
    
    Signed-off-by: Nicolas Boichat <nicolas@boichat.ch>
    Cc: H. Peter Anvin <hpa@zytor.com>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 4e9baad8f5cb2040e802eff484fad7e721b21c0b
Author: Rudolf Marek <r.marek@assembler.cz>
Date:   Tue May 8 17:22:01 2007 +0200

    i386: Add safe variants of rdmsr_on_cpu and wrmsr_on_cpu
    
    Add safe (exception handled) variants of rdmsr_on_cpu and wrmsr_on_cpu.
    You should use these when the target MSR may not actually exist, as
    doing so could trigger an exception which the regular functions do not
    handle. The safe variants are slower, though.
    
    The upcoming coretemp hardware monitoring driver will need this.
    
    Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
    Cc: Alexey Dobriyan <adobriyan@openvz.org>
    Cc: Dave Jones <davej@redhat.com>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 9ca8e40c8414d25e880b587cbd4d130750c49588
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:01 2007 +0200

    hwmon/lm75: Use dynamic sysfs callbacks
    
    This lets us get rid of macro-generated functions and shrinks the
    driver size by about 8%.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 247dde4cdded4e4c332622b7c2860254e61cf5ce
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:01 2007 +0200

    hwmon/lm78: Use dynamic sysfs callbacks
    
    This lets us get rid of macro-generated functions and shrinks the
    driver size significantly (about 10%).
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit c59cc301ee4589b096d2364af7cf91a2e46b5b1d
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:01 2007 +0200

    hwmon/lm78: Be less i2c_client-centric
    
    Use the driver data structure as the main device reference, instead of
    the i2c client. It makes the driver a bit smaller, and makes more sense
    as this is an hybrid driver, supporting both I2C and ISA devices.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit c40769fee13c1ab43e1fb10320d6fbc29f582d8e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon/lm78: No longer use i2c-isa
    
    Reimplement the ISA device support as a platform driver, so that we no
    longer rely on i2c-isa.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit d20620de0c3de622a9d6a841725bafaed6d1aec2
Author: Hans-Juergen Koch <hjk@linutronix.de>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon: New max6650 driver
    
    This driver supports the Maxim MAX6650 and MAX6651 fan speed
    monitoring and control chips.
    
    Signed-off-by: Hans J. Koch <hjk@linutronix.de>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit e84cfbcbe830c20af030fd7ba37edf8ed88fda5f
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon/smsc47m1: Use dynamic sysfs callbacks
    
    This lets us get rid of macro-generated functions and shrinks the
    driver size by about 7%.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 620100cf97a5dd144035e51aeea330d691176489
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon/smsc47m1: Use DRVNAME consistently
    
    Also use pr_info instead of printk.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 51f2cca1f72db5e272ed79b678b62fb9472e916e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon/smsc47m1: Convert to a platform driver
    
    Convert the smsc47m1 driver from the nonsensical i2c-isa hack to a
    regular platform driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 2dbc514a2ed2b6f71eb6d18671d2c663160788c9
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon: Document the new fan1_target interface file
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 787c72b107888805981faf148c8fea96a752d22e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:22:00 2007 +0200

    hwmon/w83627hf: Convert to a platform driver
    
    Convert the w83627hf driver from the nonsensical i2c-isa hack to a
    regular platform driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit d27c37c0be3fd97a696dafb28507277d49875dcb
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon/w83627hf: Preliminary cleanups
    
    Some preliminary cleanups to the w83627hf hardware monitoring driver,
    to make its conversion to a platform driver easier:
    
    * Add missing include ioport.h
    * Drop unused enum value any_chip
    * Group module parameters
    * Define and use DRVNAME
    * Drop unused struct member lm75
    * Move the handling of force_addr and device activation to
      w83627hf_find
    * Consistently use local type in w83627hf_init_client
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit e46751bfd69839edd15ee54cabbeed8e801a4274
Author: Rudolf Marek <r.marek@assembler.cz>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon-vid: Add support for VIA Esther
    
    Update the VID type for certain VIA processors and remove
    the Itanium entries.
    
    Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 8a665a0552c414af88788cc0e2cf0e4626182c20
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon: Only call vid_which_vrm() when needed
    
    Some hardware monitoring drivers create the VID/VRM interface files
    conditionally depending on the chip model or configuration. We should
    only call vid_which_vrm() when we are actually going to create the
    files. Not only it is more logical and efficient that way, but it also
    prevents printing unnecessary warnings such as the one reported here:
    http://lists.lm-sensors.org/pipermail/lm-sensors/2007-February/018954.html
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 94e183fd0425a917d9c1453041ef88f3610c0f01
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon/smsc47m1: Get rid of a useless mutex
    
    The smsc47m1 driver uses a mutex to protect the accesses to the
    hardware registers. It really doesn't need any protection, as the
    register space is flat. Get rid of that mutex for a smaller and
    faster driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 8eccbb6fb97a5b54a9db166399f0d24f33114522
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon/smsc47m1: Add support for the LPC47M292
    
    The new SMSC LPC47M292 Super-I/O chip is a bit different from the
    previous ones, it supports a 3rd fan, but unfortunately the pin
    configuration registers are different.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit ce7ee4e80a72d3b1009ca232be8981de93c015f6
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon: Request the I/O regions in platform drivers
    
    My understanding of the resource management in the Linux 2.6 device
    driver model is that the devices should declare their resources, and
    then when a driver attaches to a device, it should request the
    resources it will be using, so as to mark them busy. This is how the
    PCI and PNP subsystems work, you can clearly see the two levels of
    resources (declaration and request) in /proc/ioports for these
    devices.
    
    So I believe that our platform hardware monitoring drivers should
    follow the same logic. At the moment, we only declare the resources
    but we do not request them. This patch adds the I/O region request
    and release calls.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Acked-by: Juerg Haefliger <juergh@gmail.com>

commit 00cb4739053fa0ce4594a7798a4095007a1c7c79
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 8 17:21:59 2007 +0200

    hwmon/smsc47m192: Document the LPC47M292 as supported
    
    The new SMSC LPC47M292 Super-I/O chip includes a hardware monitoring
    block which is compatible with those of the LPC47M192.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Hartmut Rick <linux@rick.claranet.de>

commit 86aa5ac53e478c94ee39a15b6eadde1ed1317be3
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Tue May 8 08:46:19 2007 +0200

    [PATCH] splice: always call into page_cache_readahead()
    
    Don't try to guess what the read-ahead logic will do, allow it
    to make its own decisions.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 9ae9d68cbf3fe0ec17c17c9ecaa2188ffb854a66
Author: Fengguang Wu <fengguang.wu@gmail.com>
Date:   Tue May 8 08:44:36 2007 +0200

    [PATCH] splice(): fix interaction with readahead
    
    Eric Dumazet, thank you for disclosing this bug.
    
    Readahead logic somehow fails to populate the page range with data.
    It can be because
    
    1) the readahead routine is not always called in the following lines of
    
    fs/splice.c:
            if (!loff || nr_pages > 1)
                    page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
    
    2) even called, page_cache_readahead() wont guarantee the pages are there.
    It wont submit readahead I/O for pages already in the radix tree, or when
    (ra_pages == 0), or after 256 cache hits.
    
    In your case, it should be because of the retried reads, which lead to
    excessive cache hits, and disables readahead at some time.
    
    And that _one_ failure of readahead blocks the whole read process.
    The application receives EAGAIN and retries the read, but
    __generic_file_splice_read() refuse to make progress:
    
    - in the previous invocation, it has allocated a blank page and inserted it
      into the radix tree, but never has the chance to start I/O for it: the test
      of SPLICE_F_NONBLOCK goes before that.
    
    - in the retried invocation, the readahead code will neither get out of the
      cache hit mode, nor will it submit I/O for an already existing page.
    
    Cc: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit e824f7836de25b1c2f659a2412d32227f1f68bcb
Author: Jeff Garzik <jeff@garzik.org>
Date:   Tue May 8 02:32:17 2007 -0400

    [netdrvr] atl1: fix build
    
    We need linux/pci.h.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ef68d295508d52e792abf70d4f84461104d33b9d
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Tue May 8 15:48:39 2007 +1000

    via: Make sure we flush write-combining using a follow-up read.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit a5fd22ebc71eecb7b61e542d34ac50a417b3031b
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:48:02 2007 -0500

    pasemi_mac: Use local-mac-address instead of mac-address if available
    
    Use local-mac-address in the device tree instead. Fall back to mac-address
    for older firmware.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit bb6e9590792834f905a92e439a083254649c985c
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:54 2007 -0500

    pasemi_mac: PHY support
    
    PHY support for pasemi_mac.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ceb51361370c003e13f782edb7171a8383e5c849
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:49 2007 -0500

    pasemi_mac: Add msglevel support and "debug" module param
    
    Add msglevel support for pasemi_mac. Move the MODULE_* defines to the
    top to go together with the variable (similar to tg3).
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit cd4ceb245be7926e94558e2b6cd279bfaa775908
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:45 2007 -0500

    pasemi_mac: Logic cleanup / rx performance improvements
    
    Logic cleanup and some performance enhancements to the RX path.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit cfa8007d5cee58d2c2121b7d00077c6f10969cb7
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:41 2007 -0500

    pasemi_mac: Minor cleanup / define fixes
    
    * Remove some unused defines
    * Fix a couple of wrong chip register defines, and add a few more fields
      that might be used in the near future.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9f05cfe250498791cd24707aea3b728b52d886d5
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:37 2007 -0500

    pasemi_mac: Add SKB reuse / copy-break
    
    Add a copy-break and recycle the SKB in the driver for small packets.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6dfa7522d8b08c887bf9f4cb2600b89232f132f5
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:32 2007 -0500

    pasemi_mac: Timer and interrupt fixes
    
    Timer and interrupt fixes:
    
    * Be pickier with what kind of interrupts are acked to avoid the device to
      get out of sync with the driver state
    * Set RX count threshhold to 1 (for NAPI interrupted mode), TX count
      threshold to 32.
    * Set timer thresholds to current max (~16ms).
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1b0335ea30bf85eecffd21be64b7653407d6259a
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:26 2007 -0500

    pasemi_mac: Abstract and fix up interrupt restart routines
    
    Abstract out (and fix up) the interrupt restart routines, making
    sure we start out in a consistent state.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 771f7404a9deca902594823d616cd7a84f827982
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 8 00:47:21 2007 -0500

    pasemi_mac: Move the IRQ mapping from the PCI layer to the driver
    
    Fixes for ethernet IRQ mapping, to be done in the driver instead of in
    the platform setup code.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a0a6dd0b221260be1e3da725e6b49797e5fa7429
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Tue May 8 15:47:41 2007 +1000

    via: Try to improve command-buffer chaining.
    
    Bump driver date and patchlevel.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 418aea75246d5f83caa3a003fd66fe3b1aa01738
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 8 00:46:04 2007 +0900

    tc35815: Remove unnecessary skb->dev assignment
    
    Apply changes in commit 4c13eb6657fe9ef7b4dc8f1a405c902e9e5234e0 to
    newly added piece of code.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6478fac6c31cbf45e8b818880728238e0c548d57
Author: Richard Knutsson <ricknu-0@student.ltu.se>
Date:   Tue May 1 18:43:27 2007 +0200

    drivers/net/dm9000: Convert to generic boolean
    
    Convert to generic boolean.
    
    Signed-off-by: Richard Knutsson <ricknu-0@student.ltu.se>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ba0acb5ee318901646f82c134cca2e4de0c43934
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Mon May 7 17:31:32 2007 -0400

    Input: move USB miscellaneous devices under drivers/input/misc
    
    This will allow concentrating all input devices in one place
    in {menu|x|q}config.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b5da20f8f7652e7a9648401a1942b7aac3b9ab9d
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Mon May 7 17:12:07 2007 -0400

    Input: move USB mice under drivers/input/mouse
    
    This will allow concentrating all input devices in one place
    in {menu|x|q}config.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1c362d46825259a48c1d543cab3805a6c770c0c8
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Mon May 7 16:48:50 2007 -0400

    Input: move USB gamepads under drivers/input/joystick
    
    This will allow concentrating all input devices in one place
    in {menu|x|q}config.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

commit d05e84e6cb21cca16987813fd3c271ebaed4233d
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Mon May 7 16:38:49 2007 -0400

    Input: move USB touchscreens under drivers/input/touchscreen
    
    This will allow concentrating all input devices in one place
    in {menu|x|q}config.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4104d13fe0194736393d97c88ee045fb689c783b
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Mon May 7 16:16:29 2007 -0400

    Input: move USB tablets under drivers/input/tablet
    
    This will allow concentrating all input devices in one place
    in {menu|x|q}config.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bc07dc7f07a2f2d4d0aa4ffb9597413ad9137d44
Author: Dave Airlie <airlied@linux.ie>
Date:   Tue May 8 15:32:35 2007 +1000

    drm: remove old taskqueue remnant
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit d2ada5597d33a9108acb2caf912f85cbc9caab1e
Author: Roland Scheidegger <sroland@tungstengraphics.com>
Date:   Tue May 8 01:31:40 2007 -0400

    Input: i8042 - fix AUX port detection with some chips
    
    The i8042 driver fails detection of the AUX port with some chips,
    because they apparently do not change the I8042_CTR_AUXDIS bit
    immediately. This is known to affect at least HP500/HP510 notebooks,
    consequently the built-in touchpad will not work. The patch will simply
    reread the value until it gets the expected value or a retry limit is
    hit, without touching other workaround code in the same area.
    
    Signed-off-by: Roland Scheidegger <sroland@tungstengraphics.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 8bc354730bc877ebdf35c692460b01e624934aea
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 12:11:38 2007 +0200

    AT91RM9200 Ethernet: Fix multicast addressing
    
    The order that the two 32-bit words written to the Hash Address (Low,
    High) Registers for matching of multicast addresses is incorrect.
    
    Signed-off-by: Lars Reemts <Lars.Reemts@entwicklung.eq-3.de>
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6b4aea7352bed6e2fdb59a3fe24ce2b42b31c35a
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Thu May 3 09:17:15 2007 +0200

    AT91RM9200 Ethernet: Support additional PHYs
    
    Add support for a number of new PHY's in the AT91RM9200 Ethernet driver.
    - Teridian 78Q21x3
    - SMSC LAN83C185
      (Patch from Luca Gamma)
    - National Semiconductor DP83848
      (Patches from Ivan Kuten & Thomas Foldesi)
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0b45d18643f0a3eab09616b8a1283b013a7417ea
Author: Komuro <komurojun-mbn@nifty.com>
Date:   Sun May 6 09:16:53 2007 +0900

    PCMCIA-NETDEV : xirc2ps_cs: bugfix of multicast code
    
    Dear Jeff
    
    Subject: [PATCH] xirc2ps_cs: bugfix of multicast code
    
    Signed-off-by: Komuro <komurojun-mbn@nifty.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0515b93c0ea89eb2120b0ec1d148359da01ad2e5
Author: Dave Airlie <airlied@linux.ie>
Date:   Tue May 8 15:28:15 2007 +1000

    drm: rename badly named define and cleanup ioctl code spacing
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 44a1d2e5c5c935fff3a093a1bcede32912c76421
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 30 14:23:49 2007 -0700

    sky2: re-enable 88E8056 for most motherboards
    
    This fixes the regression in 2.6.21 for users with 88e8056 on motherboard.
    Allow all but the Gigabyte motherboard has some unresolved bus problems.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 8cb5f30a413e9b883b5e47637d9aee5e812dce24
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 1 00:28:03 2007 +0900

    MIPS: Drop unnecessary CONFIG_ISA from RBTX49XX
    
    Those boards do not need CONFIG_ISA if the ne driver could be
    selectable without it.  Disable it and update a defconfig.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 57e386ce9d136261bc60a5223f39b179a3c11046
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 1 00:27:58 2007 +0900

    ne: MIPS: Use platform_driver for ne on RBTX49XX
    
    This patch lets RBTX49XX boards use generic platform_driver interface
    for the ne driver.
    
    * Use platform_device to pass ioaddr and irq to the ne driver.
    * Remove unnecessary ifdefs for RBTX49XX from the ne driver.
    * Make the ne driver selectable on these boards regardless of CONFIG_ISA
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1c08bf10658921dafae8d66be0effc915a209ab0
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 1 00:27:49 2007 +0900

    ne: Add NEEDS_PORTLIST to control ISA auto-probe
    
    Add NEEDS_PORTLIST cpp macro to control ISA auto-probe.
    (I'm not sure M32R needs auto-probe but it is current behavior)
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f0e93c10faf08e8840a0b7a44abccb520ead12df
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 1 00:27:39 2007 +0900

    ne: Misc fixes for platform driver.
    
    Miscellaneous fixes to make ne platform driver work properly.
    
    * Make ioaddr 'unsigned long'.
    * Move a printk down to show dev->name assigned in register_netdev.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a4d542b9fcae220a067156927e29a34cba605339
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Tue May 1 00:27:31 2007 +0900

    ne: Add platform_driver
    
    Add a platform_driver interface to ne driver.
    (Existing legacy ports did not covered by this ne_driver for now)
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 453ff94ca502d0a7441912823f20ed130f685429
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Tue May 8 15:21:14 2007 +1000

    radeon: Don't mess up page flipping when a file descriptor is closed.
    
    There can still be other contexts that may use page flipping later on, so do
    just unilaterally 'clean it up', which could lead to the wrong page being
    displayed, e.g. when running 3D apps with a GLX compositing manager such as
    compiz using page flipping.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 42b1c8cc25f6a5ecbd43f9d66e8b8b7ec25b7d9d
Author: John W. Linville <linville@tuxdriver.com>
Date:   Sat Apr 28 20:28:45 2007 -0400

    libertas: fix for wireless Kconfig changes
    
    Need to change the libertas Kconfig entry to match changes made for
    other wireless drivers.
    
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ab13a18a3c8cc5a386ae8c74d53ed5ca0b0ec7bb
Author: Jay Cliburn <jacliburn@bellsouth.net>
Date:   Sun Apr 29 21:42:11 2007 -0500

    atl1: fix whitespace damage
    
    Remove trailing whitespace and spaces preceding tabs.
    
    Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1e0063645ef1e89c63778fbb0417e79b7dc65b5f
Author: Jay Cliburn <jacliburn@bellsouth.net>
Date:   Sun Apr 29 21:42:10 2007 -0500

    atl1: use dev_printk macros
    
    Use dev_printk macros for PCI related errors, warnings, debug and info
    console messages.
    
    Signed-off-by: Jay Cliburn <jacliburn@bellsouth.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f2b04cd219e5c0f1214c0eeeec814ddd08a12c1b
Author: Dave Airlie <airlied@linux.ie>
Date:   Tue May 8 15:19:23 2007 +1000

    drm/radeon: upgrade to 1.27 - make PCI GART more flexible
    
    radeon: make PCI GART aperture size variable, but making table size variable
        This is precursor to getting a TTM backend for this stuff, and also
        allows the PCI table to be allocated at fb 0
    radeon: add support for reverse engineered xpress200m
    
        The IGPGART setup code was traced using mmio-trace on fglrx by myself
        and Phillip Ezolt <phillipezolt@gmail.com> on dri-devel.
    
        This code doesn't let the 3D driver work properly as the card has no
        vertex shader support.
    
        Thanks to Matthew Garrett + Ubuntu for providing me some hardware to do this
        work on.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 88ca2d070c3a169611ec38f00e945a036564ca26
Author: Thomas Klein <osstklei@de.ibm.com>
Date:   Wed May 2 16:07:05 2007 +0200

    ehea: Fix skb header access
    
    Adapt to new skb header access functions.
    
    Signed-off-by: Thomas Klein <tklein@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 7dd976fcfd89080915e217dd494be0c6c475835c
Author: Peter Tiedemann <ptiedem@de.ibm.com>
Date:   Wed May 2 15:19:35 2007 +0200

    s390: qeth driver hardware specs adaptions
    
    s390: qeth driver hardware specs adaptions
        - according to the latest OSA hardware specification
          incorporate actual IPA command and return codes into qeth.
        - whitespaces removed from qeth_mpc.h
    
    Signed-off-by: Peter Tiedemann <ptiedem@de.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0be4acec829ae37901aea7bd09aca1cea319833a
Author: Ursula Braun <braunu@de.ibm.com>
Date:   Wed May 2 15:18:44 2007 +0200

    s390: fix Oops when unloading module netiucv
    
    don't remove an entry from iucv_connection_list in netiucv_exit().
    netiucv_free_netdevice is called anyway, which takes care of entry
    removal.
    
    Signed-off-by: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1f8bdae9ef8e1ed2b208cdbaadb91061ede30212
Author: Ursula Braun <braunu@de.ibm.com>
Date:   Wed May 2 15:18:07 2007 +0200

    s390: free skbs in finite amount of time in qeth
    
    Free sent skbs in some finite amount of time. Affected are
    asynchronous queue of Hipersockets devices and the output
    queues of all eth-devices respectively.
    
    Signed-off-by: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a4c48a2691189cec0359ac13b41726d3005ef2f5
Author: Ursula Braun <braunu@de.ibm.com>
Date:   Wed May 2 15:17:11 2007 +0200

    s390: qeth driver connection hang
    
          Frank Pavlic <fpavlic@de.ibm.com>
    
    Connection hangs when using EDDP mode because sk_protocol is NULL
    when skb has been copied via skb_copy. This results in dropping
    packets.
    Also keep MAC address after recovery of Virtual NICs so that
    traffic can flow again and duplicate statements in
    qeth_dev_set_route_store removed.
    
    Signed-off-by: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1a14780960888c97371a9918f42c4dbe6957efb4
Author: Mark Brown <broonie@sirena.org.uk>
Date:   Thu May 3 10:36:56 2007 +0100

    Subject: natsemi: Allow users to disable workaround for DspCfg reset
    
    The natsemi driver contains a workaround for broken hardware which can
    partially reset the chip at unpredictable times, detected by checking for
    spontaneous changes in the DspCfg register.  The effects of the hardware
    bug appear to be variable and can range from minor problems like small
    numbers of corrupted packets to major ones such as the chip becoming
    non-functional.  In the case of minor problems the chip reconfiguration
    required to work around the hardware can cause more problems than the bug
    itself.
    
    Since we have no way of automatically determining how badly the problem
    manifests on any given system provide an option in sysfs allowing users to
    disable the workaround at runtime and provides a module option to set the
    default.
    
    Signed-Off-By: Mark Brown <broonie@sirena.org.uk>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d0ed48640e746a5537d0e7c49d5029949b15ee88
Author: Mark Brown <broonie@sirena.org.uk>
Date:   Thu May 3 10:36:50 2007 +0100

    natsemi: Improve diagnostics for DspCfg workaround
    
    The natsemi driver has a workaround for broken hardware which resets itself
    from time to time.  There is a diagnostic message for this workaround but
    it is not printed by default, making the driver behavior more obscure than
    it needs to be.  Make the message be displayed by default.
    
    Signed-Off-By: Mark Brown <broonie@sirena.org.uk>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5125ed914d238cf22783038393ea1e75bc470925
Author: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Date:   Thu May 3 18:56:56 2007 +0900

    smc91x SuperH support
    
    This patch supports SuperH of smc91x.
    smc91x installed on the board of SuperH comes to work by applying this patch.
    Please apply this patch .
    
    Signed-off-by:	Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9fd9f9b669ca71f7b3a7709d02d305c3d428d2fe
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Mon May 7 11:13:25 2007 +0000

    DM9000: fix use of kfree() on net device
    
    The DM9000 network driver is calling kfree() on an netdev
    causing the system to oops if the probe fails. The right
    thing to do is call free_netdev().
    
    Thanks to Russell King for spotting this.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d17ecb23b2e5ca174c0f5ce6be42cb3909a02ed0
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon May 7 11:01:55 2007 -0700

    skge: allow WOL except for known broken chips
    
    Wake On Lan works correctly on Yukon-FE and other variants.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>a
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5443e9ead4f53fd7a43e6846cf10fdc0c5366a93
Author: Brice Goglin <brice@myri.com>
Date:   Mon May 7 23:52:22 2007 +0200

    myri10ge: replace the chipset whitelist with firmware autodetection
    
    Remove the aligned-completion whitelist, and replace it by using the 1.4.16
    firmware's auto-detection features to choose which firmware to load.
    The driver now loads the aligned firmware, performs a MXGEFW_CMD_UNALIGNED_TEST,
    and falls back to using the unaligned firmware if:
    - The firmware is too old (ie, MXGEFW_CMD_UNALIGNED_TEST is an unknown command).
    - The MXGEFW_CMD_UNALIGNED_TEST returns MXGEFW_CMD_ERROR_UNALIGNED, meaning
      that it has seen an unaligned completion during the DMA test.
    
    Signed-off-by: Brice Goglin <brice@myri.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0d6ac257ab556838c3c5b1437a36251c2802285e
Author: Brice Goglin <brice@myri.com>
Date:   Mon May 7 23:51:45 2007 +0200

    myri10ge: move the DMA test code into its own function
    
    Move the DMA test code into its own function.
    
    Signed-off-by: Brice Goglin <brice@myri.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2f76216fe071a67fc110a85a10b1eca038379e11
Author: Brice Goglin <brice@myri.com>
Date:   Mon May 7 23:50:37 2007 +0200

    myri10ge: fix restoring of multicast list after reset
    
    Don't count on whatever implementation artifact preserves the
    multicast list across a reset cmd, and setup multicast filtering
    as part of our reset routine.
    
    The setting of allmulti when adopting firmware with the rx-filter
    broadcast bug is also moved into the multicast setup routine where
    it belongs.
    
    Signed-off-by: Brice Goglin <brice@myri.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 772a815804ae778aee7fcf937f3d29ab218ecdc7
Author: Brice Goglin <brice@myri.com>
Date:   Mon May 7 23:49:59 2007 +0200

    myri10ge: update firmware headers
    
    Update myri10ge firmware headers to those of 1.4.16.
    
    Signed-off-by: Brice Goglin <brice@myri.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit cee505db2459aa100a4c3619b8178ec323f1d11e
Author: Brice Goglin <brice@myri.com>
Date:   Mon May 7 23:49:25 2007 +0200

    myri10ge: support new firmware counters
    
    Add dropped_pause, dropped_bad_phy, dropped_bad_crc32,
    dropped_unicast_filtered to the set of ethtool counters.
    
    Signed-off-by: Brice Goglin <brice@myri.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 197686dfe0038fd190326d118b743ff65ad20c0e
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Fri May 4 16:38:03 2007 +1000

    [POWERPC] Abolish powerpc_flash_init()
    
    powerpc_flash_init() implements a broken way of probing for flash
    devices supported by the physmap_of driver.  It finds all nodes in the
    device tree with device_type=="rom" and instantiates of_platform
    devices for them.  This is fundamentally incompatible with the normal
    and correct way of probing for of_platform_bus_probe().  Platforms
    which relied on powerpc_flash_init()s behaviour (none are in-tree)
    will have to update their platform probing code to correctly probe
    busses containing flash devices.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0ce68c74162ce288cfd214dd126b8d03b8b7a8ed
Author: Olof Johansson <olof@lixom.net>
Date:   Sat Apr 28 15:36:40 2007 -0500

    pasemi_mac: A couple of minor bugfixes.
    
    Bugfixes:
    
    * Move the wake_queue logic from tx_intr to clean_tx
    * Always do wake_queue even if queue wasn't full before clean since
      it's safe to do
    * Fix polarity in checks in pasemi_mac_close
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d9b55a03611ff2e2e54fb4e1ad2648d5eb870fa3
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 12:59:31 2007 +1000

    [POWERPC] Early serial debug support for PPC44x
    
    This adds support for early serial debugging via the built in
    port on IBM/AMCC PowerPC 44x CPUs.  It uses a bolted TLB entry in
    address space 1 for the UART's mapping, allowing robust debugging both
    before and after the initialization of the MMU.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f6dfc80554b27da11dbb36ebae166b23ec3aa9ca
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 14:10:01 2007 +1000

    [POWERPC] Support for the Ebony 440GP reference board in arch/powerpc
    
    This adds platform support code for the Ebony (440GP) evaluation
    board.  This includes both code in arch/powerpc/platforms/44x for
    board initialization, and zImage wrapper code to correctly tweak the
    flattened device tree based on information from the firmware.  The
    zImage supports both IBM OpenBIOS (aka "treeboot") and old versions of
    uboot which don't support a flattened device tree.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ea20ff5d0338a0fbd78783df657f94ffa7967dd9
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 14:09:18 2007 +1000

    [POWERPC] Add device tree for Ebony
    
    Add a device tree for the Ebony evaluation board (440GP based).  This
    tree is not complete or finalized.  This tree needs a version of dtc
    recent enough to include reference-to-labels to process.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2cd976477035716af52a6eff6625f32e5813c02b
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 12:59:30 2007 +1000

    [POWERPC] Add powerpc/platforms/44x, disable platforms/4xx for now
    
    This prepares for Ebony/440 support by creating an
    arch/powerpc/platforms/44x directory.  It is populated with a single
    misc_44x.S file, into which is moved the 44x specific reset code from
    head_44x.S (on the grounds that we should really stop clogging up the
    head_* files with random asm helper routines).
    
    At the same time, we disable the (empty save Kconfig and Makefile)
    arch/powerpc/platforms/4xx directory from the arch/powerpc/platforms
    Makefile.  Contrary to the comment in
    arch/powerpc/platforms/4xx/Makefile, attempting to build such an empty
    Makefile will fail, thus breaking compile for the 44x platforms we're
    about to add.  It can go back in once we start porting some of the 40x
    platforms (and thus it becomes non-empty).
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f7c66ce3f70d8417de0cfb481ca4e5430382ec5d
Author: Lachlan McIlroy <lachlan@sgi.com>
Date:   Tue May 8 13:50:19 2007 +1000

    [XFS] Add lockdep support for XFS
    
    SGI-PV: 963965
    SGI-Modid: xfs-linux-melb:xfs-kern:28485a
    
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: David Chinner <dgc@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 71dfd5a396d11512aa6c8ed0d35b268bc084bb9b
Author: Lachlan McIlroy <lachlan@sgi.com>
Date:   Tue May 8 13:50:12 2007 +1000

    [XFS] Fix race in xfs_write() b/w dmapi callout and direct I/O checks.
    
    In xfs_write() the iolock is dropped and reacquired in XFS_SEND_DATA()
    which means that the file could change from not-cached to cached and we
    need to redo the direct I/O checks. We should also redo the direct I/O
    checks when the file size changes regardless if O_APPEND is set or not.
    
    SGI-PV: 963483
    SGI-Modid: xfs-linux-melb:xfs-kern:28440a
    
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: David Chinner <dgc@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 3a02ee1828915d6540b415a160344775e2a4f918
Author: Utako Kusaka <utako@tnes.nec.co.jp>
Date:   Tue May 8 13:50:06 2007 +1000

    [XFS] Get rid of redundant "required" in msg.
    
    SGI-PV: 963466
    SGI-Modid: xfs-linux-melb:xfs-kern:28416a
    
    Signed-off-by: Utako Kusaka <utako@tnes.nec.co.jp>
    Signed-off-by: Tim Shimmin <tes@sgi.com>
    Signed-off-by: Christoph Hellwig <hch@infradead.org>

commit e6a0e9cdff79e1406e5653f759aaf9f59b7ce4c8
Author: Tim Shimmin <tes@sgi.com>
Date:   Tue May 8 13:49:59 2007 +1000

    [XFS] Export via a function xfs_buftarg_list for use by kdb/xfsidbg.
    
    SGI-PV: 963465
    SGI-Modid: xfs-linux-melb:xfs-kern:28414a
    
    Signed-off-by: Tim Shimmin <tes@sgi.com>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>

commit f10bb2dad02a846966064a531ba6eec301bbb9e0
Author: Tim Shimmin <tes@sgi.com>
Date:   Tue May 8 13:49:53 2007 +1000

    [XFS] Remove unused ilen variable and references.
    
    SGI-PV: 907752
    SGI-Modid: xfs-linux-melb:xfs-kern:28344a
    
    Signed-off-by: Tim Shimmin <tes@sgi.com>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Eric Sandeen <sandeen@sandeen.net>

commit ba87ea699ebd9dd577bf055ebc4a98200e337542
Author: Lachlan McIlroy <lachlan@sgi.com>
Date:   Tue May 8 13:49:46 2007 +1000

    [XFS] Fix to prevent the notorious 'NULL files' problem after a crash.
    
    The problem that has been addressed is that of synchronising updates of
    the file size with writes that extend a file. Without the fix the update
    of a file's size, as a result of a write beyond eof, is independent of
    when the cached data is flushed to disk. Often the file size update would
    be written to the filesystem log before the data is flushed to disk. When
    a system crashes between these two events and the filesystem log is
    replayed on mount the file's size will be set but since the contents never
    made it to disk the file is full of holes. If some of the cached data was
    flushed to disk then it may just be a section of the file at the end that
    has holes.
    
    There are existing fixes to help alleviate this problem, particularly in
    the case where a file has been truncated, that force cached data to be
    flushed to disk when the file is closed. If the system crashes while the
    file(s) are still open then this flushing will never occur.
    
    The fix that we have implemented is to introduce a second file size,
    called the in-memory file size, that represents the current file size as
    viewed by the user. The existing file size, called the on-disk file size,
    is the one that get's written to the filesystem log and we only update it
    when it is safe to do so. When we write to a file beyond eof we only
    update the in- memory file size in the write operation. Later when the I/O
    operation, that flushes the cached data to disk completes, an I/O
    completion routine will update the on-disk file size. The on-disk file
    size will be updated to the maximum offset of the I/O or to the value of
    the in-memory file size if the I/O includes eof.
    
    SGI-PV: 958522
    SGI-Modid: xfs-linux-melb:xfs-kern:28322a
    
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: David Chinner <dgc@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 2a32963130aec5e157b58ff7dfa3dfa1afdf7ca1
Author: Lachlan McIlroy <lachlan@sgi.com>
Date:   Tue May 8 13:49:39 2007 +1000

    [XFS] Fix race condition in xfs_write().
    
    This change addresses a race in xfs_write() where, for direct I/O, the
    flags need_i_mutex and need_flush are setup before the iolock is acquired.
    The logic used to setup the flags may change between setting the flags and
    acquiring the iolock resulting in these flags having incorrect values. For
    example, if a file is not currently cached then need_i_mutex is set to
    zero and then if the file is cached before the iolock is acquired we will
    fail to do the flushinval before the direct write.
    
    The flush (and also the call to xfs_zero_eof()) need to be done with the
    iolock held exclusive so we need to acquire the iolock before checking for
    cached data (or if the write begins after eof) to prevent this state from
    changing. For direct I/O I've chosen to always acquire the iolock in
    shared mode initially and if there is a need to promote it then drop it
    and reacquire it.
    
    There's also some other tidy-ups including removing the O_APPEND offset
    adjustment since that work is done in generic_write_checks() (and we don't
    use offset as an input parameter anywhere).
    
    SGI-PV: 962170
    SGI-Modid: xfs-linux-melb:xfs-kern:28319a
    
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: David Chinner <dgc@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit e6d29426bc8a5d07d0eebd0842fe0cf6ecc862cd
Author: Kouta Ooizumi <k-ooizumi@tnes.nec.co.jp>
Date:   Tue May 8 13:49:33 2007 +1000

    [XFS] Fix uquota and oquota enforcement problems.
    
    When uquota and oquota (gquota/pquota) are enabled for accounting both are
    enforced if ether has enforcement active.
    
    Conditions:
    
    - Both XFS_UQUOTA_ACCT and XFS_GQUOTA_ACCT are enabled.
    
    - Either XFS_UQUOTA_ENFD or XFS_OQUOTA_ENFD is enabled.
    
    - The usage without enforce is reached at the soft limit.
    
    Problems:
    
    1. "repquota" shows all grace time even if no enforcement.
    
    2. we cannot make a file over a hard limits even if no enforcement.
    
    SGI-PV: 962291
    SGI-Modid: xfs-linux-melb:xfs-kern:28272a
    
    Signed-off-by: Kouta Ooizumi <k-ooizumi@tnes.nec.co.jp>
    Signed-off-by: Donald Douwsma <donaldd@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit d3cf209476b72c83907a412b6708c5e498410aa7
Author: Lachlan McIlroy <lachlan@sgi.com>
Date:   Tue May 8 13:49:27 2007 +1000

    [XFS] propogate return codes from flush routines
    
    This patch handles error return values in fs_flush_pages and
    fs_flushinval_pages. It changes the prototype of fs_flushinval_pages so we
    can propogate the errors and handle them at higher layers. I also modified
    xfs_itruncate_start so that it could propogate the error further.
    
    SGI-PV: 961990
    SGI-Modid: xfs-linux-melb:xfs-kern:28231a
    
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Stewart Smith <stewart@flamingspork.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 424ea91ba61c1cdc2dac68576c97030cbf47d84f
Author: Donald Douwsma <donaldd@sgi.com>
Date:   Tue May 8 13:49:15 2007 +1000

    [XFS] Fix quotaon syscall failures for group enforcement requests.
    
    xfs_qm_scall_quotaon was incorrectly failing requests to enable group
    quota enforcement. Fixes logic error in OQUOTA handling.
    
    SGI-PV: 961964
    SGI-Modid: xfs-linux-melb:xfs-kern:28227a
    
    Signed-off-by: Donald Douwsma <donaldd@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 646d5bdab38c88f4b9088d4e517986a3f3b0edb9
Author: Donald Douwsma <donaldd@sgi.com>
Date:   Tue May 8 13:49:09 2007 +1000

    [XFS] Invalidate quotacheck when mounting without a quota type.
    
    When quotas are mounted or remounted without a particular quota type the
    quota accounting for that type becomes invalid. Previously we were
    ignoring this leading to accounting errors.
    
    SGI-PV: 961964
    SGI-Modid: xfs-linux-melb:xfs-kern:28225a
    
    Signed-off-by: Donald Douwsma <donaldd@sgi.com>
    Signed-off-by: Utako Kusaka <utako@tnes.nec.co.jp>
    Signed-off-by: Vlad Apostolov <vapo@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit e7a23a9b37c395a153a541d4c50e166eef6abe49
Author: Joe Perches <joe@perches.com>
Date:   Tue May 8 13:49:03 2007 +1000

    [XFS] reducing the number of random number functions.
    
    Patch provided by Joe Perches
    
    SGI-PV: 961696
    SGI-Modid: xfs-linux-melb:xfs-kern:28209a
    
    Signed-off-by: Joe Perches <joe@perches.com>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit e9ed9d2240c71014a84043095af4465ffce61367
Author: Eric Sandeen <sandeen@sandeen.net>
Date:   Tue May 8 13:48:56 2007 +1000

    [XFS] remove more misc. unused args
    
    Patch provided by Eric Sandeen.
    
    SGI-PV: 961695
    SGI-Modid: xfs-linux-melb:xfs-kern:28205a
    
    Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit ef497f8a1eafe0447f0473940ff2e0f6c8519a14
Author: Eric Sandeen <sandeen@sandeen.net>
Date:   Tue May 8 13:48:49 2007 +1000

    [XFS] the "aendp" arg to xfs_dir2_data_freescan is always NULL, remove it.
    
    Patch provided by Eric Sandeen.
    
    SGI-PV: 961694
    SGI-Modid: xfs-linux-melb:xfs-kern:28204a
    
    Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 1c72bf90037f32fc2b10e0a05dff2640abce8ee2
Author: Eric Sandeen <sandeen@sandeen.net>
Date:   Tue May 8 13:48:42 2007 +1000

    [XFS] The last argument "lsn" of xfs_trans_commit() is always called with
    NULL.
    
    Patch provided by Eric Sandeen.
    
    SGI-PV: 961693
    SGI-Modid: xfs-linux-melb:xfs-kern:28199a
    
    Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
    Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
    Signed-off-by: Tim Shimmin <tes@sgi.com>

commit 05af7bd2d75e5098021864d83fbb831111755fa0
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:37 2007 +1000

    [POWERPC] MPIC U3/U4 MSI backend
    
    MPIC U3/U4 MSI backend. Based on code from Segher, heavily hacked by me.
    This only deals with MSI on U3/U4 MPICs, aka. CPC 9x5.
    
    If we find a U3/U4 then we enable this backend, ie. take over the ppc_md
    MSI hooks. We might need more elaborate logic in future to decide which
    backend is enabled.
    
    We need our own irq_chip so that we can do MSI masking/unmasking on
    the device itself. We also need to mask explicitly on shutdown to make
    sure we don't get bitten by lazy-disable semantics.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a7de7c74227edda719b257eb15aecd73790ff894
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:36 2007 +1000

    [POWERPC] MPIC MSI allocator
    
    To support MSI on MPIC we need a way to reserve and allocate hardware irq
    numbers, this patch implements an allocator for that purpose.
    
    New firmware platforms must define a "msi-available-ranges" property on their
    MPIC node for MSI to work. For U3/U4 we do a best-guess setup.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 812fd1fd63caf2d72906603ebb9c6049a19ef4d2
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:36 2007 +1000

    [POWERPC] Enable MSI mappings for MPIC
    
    On some Apple machines the HT MSI mappings are not enabled by firmware, so
    we need to do it by hand.
    
    We can't use the pci routines as this code runs too early.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 014dad902aad6f5efbd65d0524b2e99304d2b07e
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:35 2007 +1000

    [POWERPC] Tell Phyp we support MSI
    
    Tell Phyp we support MSI via the client architecture support mechanism.
    
    Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 85f2bf9f60f55b6727ed310ebbaa2df7142326e5
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:35 2007 +1000

    [POWERPC] RTAS MSI implementation
    
    Implement MSI support via RTAS (RTAS = run-time firmware on pSeries
    machines).  For now we assumes that if the required RTAS tokens for
    MSI are present, then we want to use the RTAS MSI routines.
    
    When RTAS is managing MSIs for us, it will/may enable MSI on devices that
    support it by default. This is contrary to the Linux model where a device
    is in LSI mode until the driver requests MSIs.
    
    To remedy this we add a pci_irq_fixup call, which disables MSI if they've
    been assigned by firmware and the device also supports LSI. Devices that
    don't support LSI at all will be left as is, drivers are still expected
    to call pci_enable_msi() before using the device.
    
    At the moment there is no pci_irq_fixup on pSeries, so we can just set it
    unconditionally. If other platforms use the RTAS MSI backend they'll need
    to check that still holds.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit df87ef5508b40fc655b6c4771be31741d8ec1596
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:34 2007 +1000

    [POWERPC] PowerPC MSI infrastructure
    
    This provides the architecture specific hooks to support MSI on
    powerpc.  We implement the newly added arch_setup_msi_irqs() and
    arch_teardown_msi_irqs(), and then delegate to ppc_md routines.
    
    Platforms that don't implement MSI will leave the ppc_md calls blank,
    arch_msi_check_device() will detect this and return ENOSYS. Drivers
    should detect this error and continue to use LSI.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f728b5c3a599d0410a079f447f921a10be7d59d6
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue May 8 12:58:33 2007 +1000

    [POWERPC] Rip out the existing powerpc msi stubs
    
    Rip out the existing powerpc msi stubs. These were the start of an
    implementation based on ppc_md calls, but were never used in mainline.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d1953c8888ef034b912ee33bc2ea2cce6a414402
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 8 12:46:49 2007 +1000

    [POWERPC] Remove use of 4level-fixup.h for ppc32
    
    For 32-bit systems, powerpc still relies on the 4level-fixup.h hack,
    to pretend that the generic pagetable handling stuff is 3-levels
    rather than 4.  This patch removes this, instead using the newer
    pgtable-nopmd.h to handle the elision of both the pud and pmd
    pagetable levels (ppc32 pagetables are actually 2 levels).
    
    This removes a little extraneous code, and makes it more easily
    compared to the 64-bit pagetable code.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 00c2ae35bd50664bcd841becc6efceef8aa5d074
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Tue May 8 08:04:05 2007 +1000

    [POWERPC] Add powerpc PCI-E reset API implementation
    
    Adds the pSeries platform implementation for a new PCI API
    which can be used to issue various types of PCI-E reset,
    including PCI-E warm reset and PCI-E hot reset. This is needed
    for an ipr PCI-E adapter which does not properly implement BIST.
    Running BIST on this adapter results in PCI-E errors. The only
    reliable reset mechanism that exists on this hardware is PCI
    Fundamental reset (warm reset).
    
    Acked-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7487a2245b8841c77ba9db406cf99a483b9334e9
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:32:10 2007 +1000

    [POWERPC] Holly bootwrapper
    
    Add Holly/Hickory bootwrapper
    
    Signed-off-by: Stephen Winiecki <stevewin@us.ibm.com>
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d4d19ec4931feb53f68fcc156563a21e34d50cb8
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:31:00 2007 +1000

    [POWERPC] Holly DTS
    
    Add Holly DTS file
    
    Signed-off-by: Stephen Winiecki <stevewin@us.ibm.com>
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 897fd81795de954cd3addb1e4d4d2cd5e9e14fdd
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:29:37 2007 +1000

    [POWERPC] Holly defconfig
    
    Holly/Hickory defconfig
    
    Signed-off-by: Stephen Winiecki <stevewin@us.ibm.com>
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cb9e4d10c448a388babd9dfbfa2b8bb1c5bbf84f
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:28:38 2007 +1000

    [POWERPC] Add support for 750CL Holly board
    
    Add PowerPC 750 Holly/Hickory platform support
    
    Signed-off-by: Stephen Winiecki <stevewin@us.ibm.com>
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 05ad6a9159401804c9bcec8922a9c4a1cb2bfb59
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:27:15 2007 +1000

    [POWERPC] Generalize tsi108 PCI setup
    
    Generalize tsi108_setup_pci to take the config space physical address and
    primary bus designator as a parameter.
    
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c1b78d05b3281d6f84284d421fc20eed8b8b78ce
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:26:22 2007 +1000

    [POWERPC] Generalize tsi108 PHY types
    
    Add a phy_type field to the tsi108 ethernet structures to indicate which PHY
    is used on a board.  This is derived from the "compatible" property in the
    ethernet-phy node of the device tree.  The default remains the MV88E PHY.
    
    Also, convert the setup code to use of_get_mac_address instead of hard coding
    a lookup for the "address" property in the ethernet node.
    
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 08390db07a012b972189629a30eb695cdcb0ec14
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 8 07:25:22 2007 +1000

    [POWERPC] Add tsi108_pci.h for common PCI functions
    
    Add a header file for the common PCI routines used for the TSI bridge
    
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit fb39a96e23d4d1115f8e7e0b9916d0e9c23d8f65
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Tue May 8 03:11:11 2007 +1000

    [POWERPC] Export pcibios_remove_pci_devices
    
    The pseries PCI hotplug code cannot build as a module, unless
    the pcibios_remove_pci_devices function is exported.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    ----
     arch/powerpc/platforms/pseries/pci_dlpar.c |    1 +
     1 file changed, 1 insertion(+)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f596575e81999c0faf01a2fd340bc96dda058f80
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Tue May 8 01:08:00 2007 +1000

    [POWERPC] via-pmu: remove LED sleep notifier
    
    The generic LED code now makes sure that suspended devices don't blink,
    so we no longer need to do it ourselves. For the suspend to disk case,
    however, we need to make sure that we don't blink if the PMU sysdev
    was suspended before the LED device.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0108d3fe3c44f01de224f39347b95f6a94181687
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Mon May 7 15:58:28 2007 +1000

    [POWERPC] Add __init annotations to reserve_mem() and stabs_alloc()
    
    reserve_mem() and stabs_alloc() are both called only from other __init
    routines, so can be marked __init.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 11fbb00c67e19737757e747ec7dd3ba8d584f5d1
Author: Paul Mackerras <paulus@samba.org>
Date:   Mon May 7 15:16:23 2007 +1000

    [POWERPC] Cope with PCI host bridge I/O window not starting at 0
    
    Currently our code to set up the data structures for a PCI host bridge
    and create the mapping for its I/O window assumes that the window
    starts at I/O port 0 on the PCI side.  If this is not true, we can end
    up with I/O port numbers in the resources for PCI devices which will
    cause an oops if a driver tries to access them via inb/outb etc.,
    because there is no mapping for the corresponding addresses.
    
    Normally the I/O window starts at 0, but there are some situations on
    partitioned machines with a hypervisor where the window may not start
    at 0.
    
    This fixes the problem by allocating space for the range from 0 to the
    end of the I/O window.  That is, hose->io_base_virt contains the
    virtual address for I/O port 0 on the PCI bus, and thus the assumption
    that hose->io_base_virt - pci_io_base is the offset between the
    "global" I/O port numbers (those in the PCI device resources) and the
    I/O port numbers on the PCI bus is maintained.
    
    For PCI host bridges that are present at boot, we only map the portion
    of that range that correspond to the bridge's I/O window.  For bridges
    added after boot we ioremap the range from 0 to the end of the I/O
    window, for now; in fact hot-added bridges should be using
    reserve_phb_iospace() and __ioremap_explicit (so they get sensible
    global port numbers), but we don't have the infrastructure yet to do
    that (basically a free_phb_iospace() routine plus appropriate
    locking).
    
    Interestingly, this makes the two arms of the if statement in
    get_bus_io_range do almost exactly the same thing; that function could
    now be simplified in a further patch.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d12db0b08f6c14dfd1438f6f6ad49dcd663c9ae5
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Mon May 7 17:32:08 2007 -0700

    Fix bluetooth HCI sysfs compile
    
    More fallout from the removal of "struct subsystem" from the core device
    model.
    
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d679f805e7d16291f7671710dd42522561a46611
Author: Martin Habets <errandir_news@mph.eclipse.co.uk>
Date:   Mon May 7 14:05:03 2007 -0700

    [SCSI] esp_scsi: Fix section mismatch warnings.
    
    Signed-off-by: Martin Habets <errandir_news@mph.eclipse.co.uk>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit de9f0cf93fcbccc2de4e6bcb5ef90f997616be3b
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 14:02:51 2007 -0700

    [VIDEO] sunxvr2500: Fix PCI device ID table.
    
    Noticed by Meelis Roos.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0f9008ef38d5a6305d94bbdd8f20d68fc75c63b6
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Mon May 7 12:31:58 2007 -0700

    Fix up SLUB compile
    
    The newly merged SLUB allocator patches had been generated before the
    removal of "struct subsystem", and ended up applying fine, but wouldn't
    build based on the current tree as a result.
    
    Fix up that merge error - not that SLUB is likely really ready for
    showtime yet, but at least I can fix the trivial stuff.
    
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 35c74823cb382c610be908f1b92f980b84e7c37c
Author: Arnaud Patard <arnaud.patard@rtp-net.org>
Date:   Sun May 6 14:52:00 2007 -0700

    spi_s3c24xx.c: Fix build
    
    Commit a836f5856ae46ccb2464ea76031ea05ae967b832 removes the shutdown
    member of the bitbang structure, breaking the build of spi_s3c24xx.c.
    
    Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 09762516761f9346ee521dcab45de0a543298410
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Sun May 6 14:51:58 2007 -0700

    rename TANBAC TB0219 config
    
    Rename config for TANBAC TB0219 GPIO support to something more appropriate.
    
    Fixes this:
    
    drivers/char/Kconfig:906:warning: type of 'TANBAC_TB0219' redefined from 'boolean' to 'tristate'
    drivers/char/Kconfig:907:warning: choice values currently only support a single
    prompt
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Acked-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2fda4c90f65fd96ef910ba285d66984caf600a08
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Sun May 6 14:51:57 2007 -0700

    ehci-ps3, ohci-ps3: fix compilation
    
    As seen on powerpc-cell et al:
    
      CC [M]  drivers/usb/host/ehci-hcd.o
    In file included from drivers/usb/host/ehci-hcd.c:941:
    drivers/usb/host/ehci-ps3.c:79: error: conflicting types for 'dev_dbg'
    include/linux/device.h:576: error: previous definition of 'dev_dbg' was here
    make[4]: *** [drivers/usb/host/ehci-hcd.o] Error 1
      CC [M]  drivers/usb/host/ohci-hcd.o
    In file included from drivers/usb/host/ohci-hcd.c:921:
    drivers/usb/host/ohci-ps3.c:83: error: conflicting types for 'dev_dbg'
    include/linux/device.h:576: error: previous definition of 'dev_dbg' was here
    
    dev_dbg() will check format string for you in dummy case also, so remove
    buggers.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
    Cc: Geert Uytterhoeven <geert@linux-m68k.org>
    Cc: Greg KH <greg@kroah.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f0ac675806441d17303707856f4d23bd27092014
Author: Richard Purdie <rpurdie@rpsys.net>
Date:   Sun May 6 14:51:56 2007 -0700

    Fix ppp_deflate issues with recent zlib_inflate changes
    
    The last zlib_inflate update broke certain corner cases for ppp_deflate
    decompression handling.  This patch fixes some logic to make things work
    properly again.  Users other than ppp_deflate (the only Z_PACKET_FLUSH
    user) should be unaffected.
    
    Fixes bug 8405 (confirmed by Stefan)
    
    Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
    Cc: Stefan Wenk <stefan.wenk@gmx.at>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c24228daa1e489721812815838220de607260df9
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sun May 6 14:51:55 2007 -0700

    cx88-video build fix
    
    alpha:
    
    drivers/media/video/cx88/cx88-video.c: In function 'cx8800_initdev':
    drivers/media/video/cx88/cx88-video.c:1782: error: 'DMA_32BIT_MASK' undeclared (first use in this function)
    drivers/media/video/cx88/cx88-video.c:1782: error: (Each undeclared identifier is reported only once
    drivers/media/video/cx88/cx88-video.c:1782: error: for each function it appears in.)
    
    Cc: Mauro Carvalho Chehab <mchehab@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0ddb16cfb05c04d644b4ba8e36e780b15f47a191
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sun May 6 14:51:54 2007 -0700

    xtensa: strlcpy is smart enough
    
    strlcpy already accounts for the trailing zero in its length
    computation, so there is no need to substract one to the buffer size.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Chris Zankel <chris@zankel.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ee17b36fd0dc2af37ea92548595e30964674ded8
Author: john stultz <johnstul@us.ibm.com>
Date:   Sun May 6 14:51:53 2007 -0700

    v850: generic timekeeping conversion
    
    Convert an arch that does not currently implement sub-jiffy timekeeping to
    use the generic timekeeping code.
    
    v850 looks like it has some intent to implement sub-jiffy timekeeping, so
    it may not yet be appropriate to try to convert, but I figured I'd get the
    maintainer's input and submit the patch for comment.
    
    Signed-off-by: John Stultz <johnstul@us.ibm.com>
    Cc: Miles Bader <uclinux-v850@lsi.nec.co.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c2f239d93e8af991392871c57465cb2ac556b482
Author: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Date:   Sun May 6 14:51:52 2007 -0700

    uml: fix prototypes
    
    Declare strlcpy and strlcat more correctly.
    
    Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Cc: Jeff Dike <jdike@addtoit.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b7ec15bd004f4524bf091f851348da2ccb519e4f
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:51 2007 -0700

    uml: virtualized time fix
    
    With the current timekeeping, !CONFIG_UML_REAL_TIME_CLOCK has
    inconsistent behavior.  Previously, gettimeofday could be (and was)
    isolated from the clock ticking.  Now, it's not, so when
    CONFIG_UML_REAL_TIME_CLOCK is disabled, gettimeofday must progress in
    lockstep with the clock, making it fully virtual.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 83ff7df5f1c1c44efd84d7341211aa0138fd9504
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:50 2007 -0700

    uml: out of tmpfs space error clarification
    
    It turns out that the message complaining about a lack of tmpfs space
    on the host can be misunderstood as referring to the UML.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1e7371c1a11f041d641cc0ff113bf1daa1bd98b9
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:49 2007 -0700

    uml: only flush areas covered by VMA
    
    When doing a full address space flush, only look at areas covered by a VMA.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 16dd07bc6404c8da0bdfeb7a5cde4e4a63991c00
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:48 2007 -0700

    uml: more page fault path trimming
    
    More trimming of the page fault path.
    
    Permissions are passed around in a single int rather than one bit per
    int.  The permission values are copied from libc so that they can be
    passed to mmap and mprotect without any further conversion.
    
    The register sets used by do_syscall_stub and copy_context_skas0 are
    initialized once, at boot time, rather than once per call.
    
    wait_stub_done checks whether it is getting the signals it expects by
    comparing the wait status to a mask containing bits for the signals of
    interest rather than comparing individually to the signal numbers.  It
    also has one check for a wait failure instead of two.  The caller is
    expected to do the initial continue of the stub.  This gets rid of an
    argument and some logic.  The fname argument is gone, as that can be
    had from a stack trace.
    
    user_signal() is collapsed into userspace() as it is basically one or
    two lines of code afterwards.
    
    The physical memory remapping stuff is gone, as it is unused.
    
    flush_tlb_page is inlined.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3ec704e6660aa58505110a50102e57cdb9daa044
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:47 2007 -0700

    uml: eliminate a piece of debugging code
    
    I missed removing another piece of debugging in an earlier patch.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 64f60841c096594b8073e408cd9b40d7d08dcfdd
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:45 2007 -0700

    uml: speed page fault path
    
    Give the page fault code a specialized path.  There is only one page to look
    at, so there's no point in going into the general page table walking code.
    There's only going to be one host operation, so there are no opportunities for
    merging.  So, we go straight to the pte we want, figure out what needs doing,
    and do it.
    
    While I was in here, I fixed the wart where the address passed to unmap was a
    void *, but an unsigned long to map and protect.
    
    This gives me just under 10% on a kernel build.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8603ec81487a5fefbc29611ff0d635b33b6da990
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:44 2007 -0700

    uml: aIO deadlock avoidance
    
    Allow deadlocks to be avoided in the AIO code by setting the pipe to the I/O
    thread non-blocking.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a6ea4cceed18edebe1eb6001cb9e0f88cd741a6c
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:43 2007 -0700

    uml: rename os_{read_write}_file_k back to os_{read_write}_file
    
    Rename os_{read_write}_file_k back to os_{read_write}_file, delete
    the originals and their bogus infrastructure, and fix all the callers.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a263672424e591067e42e1d8371e56927fe73af8
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:42 2007 -0700

    uml: remove debugging remnants
    
    I accidentally left the remnants of some debugging in an earlier patch.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit dc764e5087bceeb26714bb7975b711062b39d804
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:41 2007 -0700

    uml: formatting fixes around os_{read_write}_file callers
    
    Formatting fixes ahead of renaming os_{read_write}_file_k to
    os_{read_write}_file and fixing all the callers.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fda83a99b2b49016b9d7ed562745969db25c4ef9
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:41 2007 -0700

    uml: change remaining callers of os_{read_write}_file
    
    Convert all remaining os_{read_write}_file users to use the simple
    {read,write} wrappers, os_{read_write}_file_k.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 77f6af778dc23514d897f4fdc7935329285ecb1b
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:40 2007 -0700

    uml: don't try to handle signals on initial process stack
    
    Code running on the initial UML stack can't receive or process signals since
    current must be valid when IRQs are handled, and there is no current for this
    stack.
    
    So, instead of using UML_LONGJMP and UML_SETJMP, which are careful to save and
    restore signal state, and, as a side-effect, handle any deferred signals,
    start_idle_thread must use the bare equivalents, which don't do anything with
    signals.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 63843c265fd0e0c7894f713e0db5777560e756ae
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:39 2007 -0700

    uml: dump core on panic
    
    Dump core after a panic.  This will provide better debugging information than
    is currently available.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 990c55871b655156ffd7787af791be977d946ef6
Author: Peter Zijlstra <pzijlstr@redhat.com>
Date:   Sun May 6 14:51:38 2007 -0700

    uml: fixup allocation in the ubd driver
    
    Sanitise gfp flags; it actually is an atomic context, so drop the
    GFP_KERNEL part.
    
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Acked-by: Jeff Dike <jdike@addtoit.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2adcec2197897365e0a0f657f1098cbfdb44bc8b
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:37 2007 -0700

    uml: send pointers instead of structures to I/O thread
    
    Instead of writing entire structures between UML and the I/O thread, we send
    pointers.  This cuts down on the amount of data being copied and possibly
    allows more requests to be pending between the two.
    
    This requires that the requests be kmalloced and freed instead of living on
    the stack.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a0044bdf60c212366a314da09ca624cb315906e2
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:36 2007 -0700

    uml: batch I/O requests
    
    Send as many I/O requests to the I/O thread as possible, even though it will
    still only handle one at a time.  This provides an opportunity to reduce
    latency by starting one request before the previous one has been finished in
    the driver.
    
    Request handling is somewhat modernized by requesting sg pieces of a request
    and handling them separately, finishing off the entire request after all the
    pieces are done.
    
    When a request queue stalls, normally because its pipe to the I/O thread is
    full, it is put on the restart list.  This list is processed by starting up
    the queues on it whenever there is some indication that progress might be
    possible again.  Currently, this happens in the driver interrupt routine.
    Some requests have been finished, so there is likely to be room in the pipe
    again.
    
    This almost doubles throughput when copying data between devices, but made no
    noticable difference on anything else I tried.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Cc: Jens Axboe <jens.axboe@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a61f334fd2864b9b040f7e882726426ed7e8a317
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:35 2007 -0700

    uml: convert libc layer to call read and write
    
    This patch converts calls in the os layer to os_{read,write}_file to calls
    directly to libc read() and write() where it is clear that the I/O buffer is
    in the kernel.
    
    We can do that here instead of calling os_{read,write}_file_k since we are in
    libc code and can call libc directly.
    
    With the change in the calls, error handling needs to be changed to refer to
    errno directly rather than the return value of the call.
    
    CATCH_EINTR wrappers were also added where needed.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ef0470c053274c343b2be8737e0146d65e17f9be
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:33 2007 -0700

    uml: tidy libc code
    
    This patch lays some groundwork for the next one, which converts calls to
    os_{read,write}_file into {read,write}, by doing some tidying in the affected
    areas.
    
    do_not_aio gets restructured to make the final result a bit cleaner.
    
    There are also whitespace and other formatting fixes, fixes in error messages,
    and a typo fix.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3d564047a5f45cb628ec72514f68076e532988f3
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:32 2007 -0700

    uml: start fixing os_read_file and os_write_file
    
    This patch starts the removal of a very old, very broken piece of code.  This
    stems from the problem of passing a userspace buffer into read() or write() on
    the host.  If that buffer had not yet been faulted in, read and write will
    return -EFAULT.
    
    To avoid this problem, the solution was to fault the buffer in before the
    system call by touching the pages that hold the buffer by doing a copy-user of
    a byte to each page.  This is obviously bogus, but it does usually work, in tt
    mode, since the kernel and process are in the same address space and userspace
    addresses can be accessed directly in the kernel.
    
    In skas mode, where the kernel and process are in separate address spaces, it
    is completely bogus because the userspace address, which is invalid in the
    kernel, is passed into the system call instead of the corresponding physical
    address, which would be valid.  Here, it appears that this code, on every host
    read() or write(), tries to fault in a random process page.  This doesn't seem
    to cause any correctness problems, but there is a performance impact.  This
    patch, and the ones following, result in a 10-15% performance gain on a kernel
    build.
    
    This code can't be immediately tossed out because when it is, you can't log
    in.  Apparently, there is some code in the console driver which depends on
    this somehow.
    
    However, we can start removing it by switching the code which does I/O using
    kernel addresses to using plain read() and write().  This patch introduces
    os_read_file_k and os_write_file_k for use with kernel buffers and converts
    all call locations which use obvious kernel buffers to use them.  These
    include I/O using buffers which are local variables which are on the stack or
    kmalloc-ed.  Later patches will handle the less obvious cases, followed by a
    mass conversion back to the original interface.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f9d6e5f83b40d8ff73a74d4bba2c5f51d6048b12
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:31 2007 -0700

    uml: remove unused x86_64 code
    
    It turns out that essentially none of the x86_64 bugs.c is needed.  So, we can
    delete most of it.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7f0536f80cfbefd753eb123ed20940978f223900
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:30 2007 -0700

    uml: speed up page table walking
    
    The previous page table walking code was horribly inefficient.  This patch
    replaces it with code taken from elsewhere in the kernel.
    
    Forking from bash is now ~5% faster and page faults are handled ~10% faster.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f30c2c983e09470446ee00472f9d4a927fe2e9cb
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:29 2007 -0700

    uml: dump registers on ptrace or wait failure
    
    Provide a register dump if handle_trap fails.  Abstract out ptrace_dump_regs
    since it now has two callers.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2e3f5251ac716879df6b6271f243f657c6e02e9a
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:29 2007 -0700

    uml: drivers get release methods
    
    Define release methods for the ubd and net drivers.  They contain as much of
    the remove methods as make sense.  All error checking must have already been
    done as well as anything else that might be holding a reference on the device
    kobject.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d8839354a04181b4cc95cebf7f7622cf336bd58e
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:28 2007 -0700

    uml: delete HOST_FRAME_SIZE
    
    HOST_FRAME_SIZE isn't used any more.  It has been replaced with MAX_REG_NR.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d973a77bdb3ade9240173b6ed6e003a319499211
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:27 2007 -0700

    uml: irq locking commentary
    
    Locking commentary.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1d1497e1f9ffe2f7198c916abd112226a7a503f2
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:26 2007 -0700

    uml: comment early boot locking
    
    Commentary about missing locking.
    
    Also got rid of uml_start because it was pointless.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 377fad3acbb7e94ab9942a74e0d9ede8eeb2f039
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:25 2007 -0700

    uml: kernel segfaults should dump proper registers
    
    If there's a segfault inside the kernel, we want a dump of the registers at
    the point of the segfault, not the registers at the point of calling panic or
    the last userspace registers.
    
    sig_handler_common_skas now uses a static register set in the case of a
    SIGSEGV to avoid messing up the process registers if the segfault turns out to
    be non-fatal.
    
    The architecture sigcontext-to-pt_regs copying code was repurposed to copy
    data out of the SEGV stack frame.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5d86456d3852cb95a38d2b23fe01cede54984ba5
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:24 2007 -0700

    uml: tidy fault code
    
    Tidying in preparation for the segfault register dumping patch which follows.
    
    void * pointers are changed to union uml_pt_regs *.  This makes the types
    match reality, except in arch_fixup, which is changed to operate on a union
    uml_pt_regs.  This fixes a bug in the call from segv_handler, which passes a
    union uml_pt_regs, to segv, which expects to pass a struct sigcontext to
    arch_fixup.
    
    Whitespace and other style fixes.
    
    There's also a errno printk fix.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ccdddb57874522e6b267204f9c5e94ba7d9d66b0
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:23 2007 -0700

    uml: kernel_thread shouldn't panic
    
    kernel_thread() should just return an error value on do_fork failure, not
    panic.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1ffb9164f51094b7105ce9f81600b222ddf5b82c
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:22 2007 -0700

    uml: remove page_size()
    
    userspace code used to have to call the kernelspace function page_size() in
    order to determine the value of the kernel's PAGE_SIZE.  Since this is now
    available directly from kern_constants.h as UM_KERN_PAGE_SIZE, page_size() can
    be deleted and calls changed to use the constant.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6e21aec3fcf6c8862b755d45c0af45acdefff976
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:21 2007 -0700

    uml: tidy process.c
    
    Clean up arch/um/kernel/process.c:
    
    - lots of return(x); -> return x; conversions
    
    - a number of the small functions are either unused, in which case they are
      gone, along any declarations in a header, or could be made static.
    
    - current_pid is ifdefed on CONFIG_MODE_TT and its declaration is ifdefed on
      both CONFIG_MODE_TT and UML_CONFIG_MODE_TT because we don't know whether
      it's being used in a userspace or kernel file.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 65a58ab044308ae65ca06c50fb10be5e0e080989
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:20 2007 -0700

    uml: no locking needed in tls.c
    
    Comment the lack of locking on a couple of globals.
    
    Also fix the formatting of __setup_host_supports_tls.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a18ff1bde0c3da9ece3ba60e6eae2ef87f91a12e
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:19 2007 -0700

    uml: speed up exec
    
    flush_thread doesn't need to do a full page table walk in order to clear the
    address space.  It knows what the end result needs to be, so it can call unmap
    directly.
    
    This results in a 10-20% speedup in an exec from bash.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 57ac895a7f22d235f637317f58a2d9ba6ec91a27
Author: Davide Brini <davide.brini@unibo.it>
Date:   Sun May 6 14:51:16 2007 -0700

    uml: fix umid in xterm titles
    
    Calls lines_init() *after* xterm_title is modified to include umid.
    
    Signed-off-by: Davide Brini <davide.brini@unibo.it>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Acked-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c74c69b442364125fd13259ecaa4cd2ee43b9172
Author: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Date:   Sun May 6 14:51:15 2007 -0700

    uml: Replace one-element array with zero-element array
    
    To look at users I did:
    $ find arch/um/ include/asm-um -name '*.[ch]'|xargs grep -r 'net_kern\.h'
    +-l|xargs grep '\<user\>'
    
    Most users just cast user to the appropriate pointer, the remaining ones are
    fixed here.  In net_kern.c, I'm almost sure that save trick is not needed
    anymore, but I've not verified it.
    
    Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8c8408358f19a386298744829bf67b90c129ff18
Author: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Date:   Sun May 6 14:51:14 2007 -0700

    uml: Eliminate temporary buffer in eth_configure
    
    Avoid using the temporary buffer introduced by previous patch to hold the
    device name.
    
    Btw, avoid leaking device on an error path.  Other error paths may need
    cleanup.
    
    Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e024715f5f6250179a31716a898800a48cf23b39
Author: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Date:   Sun May 6 14:51:13 2007 -0700

    uml: improve checking and diagnostics of ethernet MACs
    
    Improve checking and diagnostics for broadcast and multicast Ethernet MAC
    addresses, and distinguish between those cases in output; also make sure the
    device is assigned a MAC address valid only locally to avoid collisions.
    
    Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 85ee2ce8ae7d6716beffc84451dd65cd217dbf7a
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun May 6 14:51:12 2007 -0700

    remove unused header file: arch/um/kernel/tt/include/mode_kern-tt.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Acked-by: Jeff Dike <jdike@addtoit.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 36e454630473caa178bcbc4982ed6a68cf002e95
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:11 2007 -0700

    uml: add missing __init declarations
    
    The build started finding calls from non-init to init functions.  These are
    just cases of init functions not being properly marked, so this patch fixes
    that.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9218b1714949095bff9d9739d80f431d58e561d6
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:10 2007 -0700

    uml: remove user_util.h
    
    user_util.h isn't needed any more, so delete it and remove all includes of it.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 24fa6c0832f4513ac897082d7d803970a40cc1b0
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:09 2007 -0700

    uml: move remaining useful contents of user_util.h
    
    Rescue the useful contents of the soon-to-be-gone user-util.h.
    
    pty.c now gets ptsname from stdlib.h like it should have always done.
    
    CATCH_EINTR is now in os.h, although perhaps all usage should be under
    os-Linux at some point.
    
    get_pty is also in os.h.
    
    This patch restores the old definition of ARRAY_SIZE in user.h.  This file is
    included only in userspace files, so there will be no conflict with the
    kernel's new ARRAY_SIZE.  The copy of the kernel's ARRAY_SIZE and associated
    infrastructure is now gone.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4ff83ce1114827f707b7f1f4f2e5f69de9df94ac
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:08 2007 -0700

    uml: create as-layout.h
    
    This patch moves all the the symbols defined in um_arch.c, which are mostly
    boundaries between different parts of the UML kernel address space, to a new
    header, as-layout.h.  There are also a few things here which aren't really
    related to address space layout, but which don't really have a better place to
    go.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit eb8307595baa729a12db0fec9a80910b13bd6fc8
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:07 2007 -0700

    uml: create arch.h
    
    This patch moves the declarations of the architecture hooks from user_util.h
    to a new header, arch.c, and adds the necessary includes to files which need
    those declarations.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c65badbdf5dc117e45873e760f807063ad59a854
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:06 2007 -0700

    uml: move SIGIO testing to sigio.c
    
    This patch narrows the sigio interface.  The boot-time SIGIO testing used to
    be in start_up.c, which meant that pty_output_sigio and pty_close_sigio needed
    to be global.  By moving that code here, those can become static and the
    declarations moved from user_util.h.
    
    os_check_bugs is also here because it only does the SIGIO checking.  If it
    does more, it'll probably move back to start_up.c.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c5e631cf65f4d6875efcd571275436f2964a8b48
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Sun May 6 14:51:05 2007 -0700

    ARRAY_SIZE: check for type
    
    We can use a gcc extension to ensure that ARRAY_SIZE() is handed an array,
    not a pointer.  This is especially important when code is changed from a
    fixed array to a pointer.  I assume the Intel compiler doesn't support
    __builtin_types_compatible_p.
    
    [jdike@addtoit.com: uml: update UML definition of ARRAY_SIZE]
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f34d9d2dcb7f17b64124841345b23adc0843e7a5
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:04 2007 -0700

    uml: network interface hotplug error handling
    
    This fixes a number of problems associated with network interface hotplug.
    
    The userspace initialization function can fail in some cases, but the
    failure was never passed back to eth_configure, which proceeded with the
    configuration.  This results in a zombie device that is present, but can't
    work.  This is fixed by allowing the initialization routines to return an
    error, which is checked, and the configuration aborted on failure.
    
    eth_configure failed to check for many failures.  Even when it did check,
    it didn't undo whatever initializations has already happened, so a present,
    but partially initialized and non-working device could result.  It now
    checks everything that can fail, and bails out, undoing whatever had been
    done.
    
    The return value of eth_configure was always ignored, so it is now just
    void.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b16895b63c504698b0c3ab26ca3c41a4fa162a42
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sun May 6 14:51:03 2007 -0700

    uml-driver-formatting-fixes-fix
    
    Cc: Jeff Dike <jdike@addtoit.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 56bd194bb200ef0c49517de67a7d7f4b043b11b1
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:02 2007 -0700

    uml: driver formatting fixes
    
    Fix a bunch of formatting violations in the drivers:
    	return(n) -> return n
    	whitespace fixes
    	emacs formatting comment removal
    	breaking if(foo) return(n) into two lines
    
    There are also a couple of errno use bugs:
    	using errno in a printk when the failure put errno into a local variable
    	saving errno after a printk, which can change it
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b47d2debf229469c78af4145ee7ad35a0f21b67f
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:01 2007 -0700

    uml: handle block device hotplug errors
    
    If a disk fails to open, i.e.  its host file doesn't exist, it won't be
    removable because the hot-unplug code checks the existence of its gendisk.
    This won't exist because it is only allocated for successfully opened disks.
    Thus, a typo on the command line can result in a unusable and unfixable disk.
    
    This is fixed by freeing the gendisk if it's there, but not letting that
    affect the removal.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1d94cda04eb82feb87c932ac3d4aef1e9dc78a43
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:00 2007 -0700

    uml: print coredump limits
    
    Print out core dump limits at boot time.  This is to allow core dumps
    to be collected if something goes very wrong and to tell if a core
    dump isn't going to happen because of a resource limit.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 48b201846901c1780fbc7ea779dcc8aa8ab8e16b
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:51:00 2007 -0700

    uml: mark tt-mode code for future removal
    
    Mark some tt-mode-only code as such.
    
    Also cleaned up some formatting.
    
    Signed-off-by: Jeff Dike <jdike@linux.intel.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b4ffb6ad8d8477b561377ca150bbbfc0db02da54
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:50:59 2007 -0700

    uml: host_info tidying
    
    Move the host_info string from util.c to um_arch.c, where it is
    actually initialized and used.  Also document its lack of locking.
    
    Signed-off-by: Jeff Dike <jdike@addtoit.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a5ed1ffa6c2480cdcf3f0aa945f0b8622fe4e90b
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:50:58 2007 -0700

    uml: formatting fixes
    
    Formatting fixes -
    	style violations
    	whitespace breakage
    	emacs formatting comment removal
    
    Signed-off-by: Jeff Dike <jdike@addtoit.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 11100b1dfb6e9444d54d38e822753f59ee42a7e6
Author: Jeff Dike <jdike@addtoit.com>
Date:   Sun May 6 14:50:57 2007 -0700

    uml: delete unused code
    
    Get rid of a bunch of unused stuff -
    	cpu_feature had no users
    	linux_prog is little-used, so its declaration is moved to the
    user for easy deletion when the whole file goes away
    	a long-unused debugging aid in helper.c is gone
    
    Signed-off-by: Jeff Dike <jdike@addtoit.com>
    Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7a3e965abfbdd5abacd29b9a67af91aa31b5f9d3
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun May 6 14:50:56 2007 -0700

    CRIS: remove code related to pre-2.2 kernel
    
    Remove conditionals and code related to checking for a pre-2.2 kernel.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 542401d97a3251ee20d7acb2f3736d0f34b49e64
Author: Cyrill Gorcunov <gorcunov@gmail.com>
Date:   Sun May 6 14:50:56 2007 -0700

    CRIS: check for memory allocation
    
    Add checking for allocated memory.  Indents and spaces are added to be
    familiar with the kernel coding style.
    
    Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
    Acked-by: Mikael Starvik <starvik@axis.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c65808ef769a486dc0c7c0e79069c06459054631
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun May 6 14:50:55 2007 -0700

    remove unused header file: drivers/serial/crisv10.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: Mikael Starvik <starvik@axis.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 241258d1cc4d3551608364cd678d5a85239ad481
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Sun May 6 14:50:54 2007 -0700

    SPIN_LOCK_UNLOCKED cleanup in arch/m68k
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: Geert Uytterhoeven <geert@linux-m68k.org>
    Cc: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit edfe7a569687c2cd85e82eaecae5b260577accbb
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun May 6 14:50:53 2007 -0700

    remove unused header file: arch/m68k/atari/atasound.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Cc: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 56f99bcb52d64d70078b41cc176dd8b6f5763108
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:52 2007 -0700

    swsusp: free more memory
    
    Move the definition of PAGES_FOR_IO to kernel/power/power.h and introduce
    SPARE_PAGES representing the number of pages that should be freed by the
    swsusp's memory shrinker in addition to PAGES_FOR_IO so that device drivers
    can allocate some memory (up to 1 MB total) in their .suspend() routines
    without causing the suspend to fail.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Cc: Nigel Cunningham <nigel@nigel.suspend2.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9b95e43763cfdfebc1318d27e55712e7b6bfe098
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:51 2007 -0700

    swsusp: fix snapshot_release
    
    Remove the leftover enable_nonboot_cpus() from snapshot_release().
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Cc: Nigel Cunningham <nigel@nigel.suspend2.net>
    Cc: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a7ee2e5f5b4c9c72f4390c60ba7ea30306f47188
Author: David Brownell <david-b@pacbell.net>
Date:   Sun May 6 14:50:50 2007 -0700

    kconfig: mention 'hibernation' not just swsusp
    
    Clarify that "software suspend" is what's called "hibernation" in most user
    interfaces, shrinking a terminology gap.  (Examples include Gnome and
    MS-Windows.)
    
    Also provide a more succinct description of what it does, so you won't have
    to read the whole novel in Kconfig; and highlights just why the lack of
    BIOS requirements for swsusp are a big deal.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Acked-by: "Rafael J. Wysocki" <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f0ced9b229cfbc76b5db9837b4b256b602d56610
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Sun May 6 14:50:50 2007 -0700

    power management: change /sys/power/disk display
    
    Change /sys/power/disk to display all valid modes as well as the currently
    selected one in a fashion known from the LED subsystem.
    
    This changes userspace API, but it is apparently not used much (we asked
    some userspace developers)
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: "Rafael J. Wysocki" <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ab3bfca7abf3fd0fe41d26d839610a787aa7e587
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Sun May 6 14:50:49 2007 -0700

    remove software_suspend()
    
    Remove software_suspend() and all its users since
    pm_suspend(PM_SUSPEND_DISK) should be equivalent and there's no point in
    having two interfaces for the same thing.
    
    The patch also changes the valid_state function to return 0 (false) for
    PM_SUSPEND_DISK when SOFTWARE_SUSPEND is not configured instead of
    accepting it and having the whole thing fail later.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: "Rafael J. Wysocki" <rjw@sisk.pl>
    Cc: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b1296cc48b39355241470ef934a5e2270e3f23bd
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:48 2007 -0700

    freezer: fix racy usage of try_to_freeze in kswapd
    
    Currently we can miss freeze_process()->signal_wake_up() in kswapd() if it
    happens between try_to_freeze() and prepare_to_wait().  To prevent this
    from happening we should check freezing(current) before calling schedule().
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Cc: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d1d241cc2c5feec057c370aa71637380b1b945d5
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:47 2007 -0700

    swsusp: use rbtree for tracking allocated swap
    
    Make swsusp use extents instead of a bitmap to trace swap pages allocated
    for saving the image (the tracking is only needed in case there's an error,
    so that the allocated swap pages can be released).
    
    This should allow us to reduce the memory usage, practically always, and
    improve performance.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Cc: Nigel Cunningham <nigel@nigel.suspend2.net>
    Cc: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 726162b5dad154a90dad51c0185b891312de5757
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:46 2007 -0700

    freezer: remove PF_NOFREEZE from handle_initrd
    
    Make handle_initrd() call try_to_freeze() in a suitable place instead of setting
    PF_NOFREEZE for the current task.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Nigel Cunningham <nigel@nigel.suspend2.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0709db6072c2e799eba1aa61bd19e0d7f38aa2cd
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:45 2007 -0700

    swsusp: use GFP_KERNEL for creating basic data structures
    
    Make swsusp call create_basic_memory_bitmaps() before processes are frozen, so
    that GFP_KERNEL allocations can be made in it.  Additionally, ensure that the
    swsusp's userland interface won't be used while either pm_suspend_disk() or
    software_resume() is being executed.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1525a2ad76f991eba9755f75c9b6d4d97abad25e
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:44 2007 -0700

    swsusp: fix error paths in snapshot_open
    
    We forget to increase device_available if there's an error in snapshot_open(),
    so the snapshot device cannot be open at all after snapshot_open() has
    returned an error.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 04293355ac9dbe81bd01b89ca2adb58be34c2c60
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:43 2007 -0700

    mm: remove unused page flags
    
    Remove the two page flags that were previously used by swsusp and are no
    longer needed.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 74dfd666de861c97d47bdbd892f6d21b801d0247
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:43 2007 -0700

    swsusp: do not use page flags
    
    Make swsusp use memory bitmaps instead of page flags for marking 'nosave' and
    free pages.  This allows us to 'recycle' two page flags that can be used for
    other purposes.  Also, the memory needed to store the bitmaps is allocated
    when necessary (ie.  before the suspend) and freed after the resume which is
    more reasonable.
    
    The patch is designed to minimize the amount of changes and there are some
    nice simplifications and optimizations possible on top of it.  I am going to
    implement them separately in the future.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7be9823491ecbaf9700d7d3502cb4b4dd0ed868a
Author: Rafael J. Wysocki <rjw@sisk.pl>
Date:   Sun May 6 14:50:42 2007 -0700

    swsusp: use inline functions for changing page flags
    
    Replace direct invocations of SetPageNosave(), SetPageNosaveFree() etc.  with
    calls to inline functions that can be changed in subsequent patches without
    modifying the code calling them.
    
    Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 433ecb4ab312f873870b67ee374502e84f6dcf92
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date:   Sun May 6 14:50:40 2007 -0700

    fix refrigerator() vs thaw_process() race
    
    refrigerator() can miss a wakeup, "wait event" loop needs a proper memory
    ordering.
    
    Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
    Acked-by: "Rafael J. Wysocki" <rjw@sisk.pl>
    Cc: Pavel Machek <pavel@ucw.cz>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e87be1143472d841c1907e6e7ae4862a30e3595c
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun May 6 14:50:39 2007 -0700

    ARM26: remove useless config option GENERIC_BUST_SPINLOCK.
    
    Remove the apparently useless config option GENERIC_BUST_SPINLOCK,
    since nothing in the source tree refers to it.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Acked-by: Ian Molton <spyro@f2s.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2af0bc94a665f22975de11bddcf6c57907ce8255
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sun May 6 14:50:39 2007 -0700

    srmcons: fix kmalloc(GFP_KERNEL) inside spinlock
    
    Fixes http://bugzilla.kernel.org/show_bug.cgi?id=8341
    
    Cc: <matthias.kaehlcke@gmail.com>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ed58a593dcf6bb9853f711e56f8618f84b7b8cb2
Author: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Date:   Sun May 6 14:50:38 2007 -0700

    ALPHA: "prctl" macros
    
    Files:
    
    include/asm-alpha/thread_info.h
    
    	Provide "prctl" macros for ALPHA.
    
    Signed-off-by: Jay Estabrook <jay.estabrook@hp.com>
    Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit eb2bce7f5e7ac1ca6da434461217fadf3c688d2c
Author: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Date:   Sun May 6 14:50:37 2007 -0700

    ALPHA: fix BOOTP image creation
    
    Files:
    
    arch/alpha/boot/bootpz.c
    
    	Create a dummy "__kmalloc()" to satisfy the loader; never called.
    
    arch/alpha/boot/tools/objstrip.c
    
    	Remove an include that is now (2.6.x) unnecessary.
    
    Signed-off-by: Jay Estabrook <jay.estabrook@hp.com>
    Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 180e53a71f78e72a244deb65140928d4f3d72385
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Sun May 6 14:50:36 2007 -0700

    ROUND_UP macro cleanup in arch/alpha/kernel/osf_sys.c
    
    ROUND_UP macro cleanup use ALIGN
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 97a572b3b877173e284c687be34d8ae81b826160
Author: Yoshinori Sato <ysato@users.sourceforge.jp>
Date:   Sun May 6 14:50:36 2007 -0700

    h8300: add zImage support
    
    h8300 zImage target support.
    
    Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c728d60455e8e8722ee08312a75f38dd7a866b5e
Author: Yoshinori Sato <ysato@users.sourceforge.jp>
Date:   Sun May 6 14:50:35 2007 -0700

    h8300 generic irq
    
    h8300 using generic irq handler patch.
    
    Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit aeecf3142d82414d511135cc85f86caddfb58338
Author: john stultz <johnstul@us.ibm.com>
Date:   Sun May 6 14:50:34 2007 -0700

    Convert h8/300 to generic timekeeping
    
    Currently h8/300 does not implement sub-jiffy timekeeping, so there is no
    benefit to having arch specific timekeeping code.
    
    This patch simply removes those functions and enables the generic
    timekeeping code.
    
    Signed-off-by: John Stultz <johnstul@us.ibm.com>
    Acked-by: Yoshinori Sato <ysato@users.sourceforge.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a5f6abd4f7558fea97bc4021fd0eb7dcc5d16a77
Author: Wu, Bryan <bryan.wu@analog.com>
Date:   Sun May 6 14:50:34 2007 -0700

    Blackfin: blackfin on-chip SPI controller driver
    
    This patch implements the driver necessary use the Analog Devices Blackfin
    processor's SPI Port.
    
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8cc75c9a1498913d668b6d3559940c6837cee8bf
Author: Wu, Bryan <bryan.wu@analog.com>
Date:   Sun May 6 14:50:32 2007 -0700

    Blackfin: on-chip RTC controller driver
    
    This patch implements the driver necessary use the Analog Devices Blackfin
    processor's on-chip RTC controller.
    
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Cc: Alessandro Zummo <a.zummo@towertech.it>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0851a2848cfd40012063ca9cf86fb67b7bebceff
Author: Wu, Bryan <bryan.wu@analog.com>
Date:   Sun May 6 14:50:32 2007 -0700

    Blackfin: add blackfin support in smc91x ethernet controller driver
    
    As SMC91X ethernet controller are used in blackfin STAMP 533 development
    board, this patch add blackfin support to the smc91x linux driver.
    
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Acked-by: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 194de5612777a9ff4f96dae1932f77a5a89e5f0a
Author: Bryan Wu <bryan.wu@analog.com>
Date:   Sun May 6 14:50:30 2007 -0700

    blackfin: serial driver
    
    This patch implements the driver necessary use the Analog Devices Blackfin
    processor's Serial Port.
    
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Russell King <rmk+lkml@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1394f03221790a988afc3e4b3cb79f2e477246a9
Author: Bryan Wu <bryan.wu@analog.com>
Date:   Sun May 6 14:50:22 2007 -0700

    blackfin architecture
    
    This adds support for the Analog Devices Blackfin processor architecture, and
    currently supports the BF533, BF532, BF531, BF537, BF536, BF534, and BF561
    (Dual Core) devices, with a variety of development platforms including those
    avaliable from Analog Devices (BF533-EZKit, BF533-STAMP, BF537-STAMP,
    BF561-EZKIT), and Bluetechnix!  Tinyboards.
    
    The Blackfin architecture was jointly developed by Intel and Analog Devices
    Inc.  (ADI) as the Micro Signal Architecture (MSA) core and introduced it in
    December of 2000.  Since then ADI has put this core into its Blackfin
    processor family of devices.  The Blackfin core has the advantages of a clean,
    orthogonal,RISC-like microprocessor instruction set.  It combines a dual-MAC
    (Multiply/Accumulate), state-of-the-art signal processing engine and
    single-instruction, multiple-data (SIMD) multimedia capabilities into a single
    instruction-set architecture.
    
    The Blackfin architecture, including the instruction set, is described by the
    ADSP-BF53x/BF56x Blackfin Processor Programming Reference
    http://blackfin.uclinux.org/gf/download/frsrelease/29/2549/Blackfin_PRM.pdf
    
    The Blackfin processor is already supported by major releases of gcc, and
    there are binary and source rpms/tarballs for many architectures at:
    http://blackfin.uclinux.org/gf/project/toolchain/frs There is complete
    documentation, including "getting started" guides available at:
    http://docs.blackfin.uclinux.org/ which provides links to the sources and
    patches you will need in order to set up a cross-compiling environment for
    bfin-linux-uclibc
    
    This patch, as well as the other patches (toolchain, distribution,
    uClibc) are actively supported by Analog Devices Inc, at:
    http://blackfin.uclinux.org/
    
    We have tested this on LTP, and our test plan (including pass/fails) can
    be found at:
    http://docs.blackfin.uclinux.org/doku.php?id=testing_the_linux_kernel
    
    [m.kozlowski@tuxland.pl: balance parenthesis in blackfin header files]
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
    Signed-off-by: Aubrey Li <aubrey.li@analog.com>
    Signed-off-by: Jie Zhang <jie.zhang@analog.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 73243284463a761e04d69d22c7516b2be7de096c
Author: Roland McGrath <roland@redhat.com>
Date:   Sun May 6 14:50:20 2007 -0700

    Return EPERM not ECHILD on security_task_wait failure
    
    wait* syscalls return -ECHILD even when an individual PID of a live child
    was requested explicitly, when security_task_wait denies the operation.
    This means that something like a broken SELinux policy can produce an
    unexpected failure that looks just like a bug with wait or ptrace or
    something.
    
    This patch makes do_wait return -EACCES (or other appropriate error returned
    from security_task_wait() instead of -ECHILD if some children were ruled out
    solely because security_task_wait failed.
    
    [jmorris@namei.org: switch error code to EACCES]
    Signed-off-by: Roland McGrath <roland@redhat.com>
    Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: James Morris <jmorris@namei.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 906e0be197232c219197d058ef5095baa7764cd4
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:50:20 2007 -0700

    page migration: Only migrate pages if allocation in the highest zone is possible
    
    Address spaces contain an allocation flag that specifies restriction on the
    zone for pages placed in the mapping.  I.e.  some device may require pages
    to be allocated from a DMA zone.  Block devices may not be able to use
    pages from HIGHMEM.
    
    Memory policies and the common use of page migration works only on the
    highest zone.  If the address space does not allow allocation from the
    highest zone then the pages in the address space are not migratable simply
    because we can only allocate memory for a specified node if we allow
    allocation for the highest zone on each node.
    
    Acked-by: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4ab688c51226188f2d4ad4f789032c107944ef89
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sun May 6 14:50:19 2007 -0700

    slob: fix page order calculation on not 4KB page
    
    SLOB doesn't calculate correct page order when page size is not 4KB.  This
    patch fixes it with using get_order() instead of find_order() which is SLOB
    version of get_order().
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Acked-by: Matt Mackall <mpm@selenic.com>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5bc98594d59672303c4c9c07262ecc373dc374da
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sun May 6 14:50:18 2007 -0700

    hugetlbfs: add NULL check in hugetlb_zero_setup()
    
    If hugetlbfs module_init() fails, hugetlbfs_vfsmount is not initialized and
    shmget() with SHM_HUGETLB flag will cause NULL pointer dereference.
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Acked-by: William Irwin <wli@holomorphy.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cfce66047f1893cb7d3abb0d53e65cbbd8d605f0
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:50:17 2007 -0700

    Slab allocators: remove useless __GFP_NO_GROW flag
    
    There is no user remaining and I have never seen any use of that flag.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4f104934591ed98534b3a4c3d17d972b790e9c42
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:50:17 2007 -0700

    slab allocators: Remove SLAB_CTOR_ATOMIC
    
    SLAB_CTOR atomic is never used which is no surprise since I cannot imagine
    that one would want to do something serious in a constructor or destructor.
     In particular given that the slab allocators run with interrupts disabled.
     Actions in constructors and destructors are by their nature very limited
    and usually do not go beyond initializing variables and list operations.
    
    (The i386 pgd ctor and dtors do take a spinlock in constructor and
    destructor.....  I think that is the furthest we go at this point.)
    
    There is no flag passed to the destructor so removing SLAB_CTOR_ATOMIC also
    establishes a certain symmetry.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 50953fe9e00ebbeffa032a565ab2f08312d51a87
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:50:16 2007 -0700

    slab allocators: Remove SLAB_DEBUG_INITIAL flag
    
    I have never seen a use of SLAB_DEBUG_INITIAL.  It is only supported by
    SLAB.
    
    I think its purpose was to have a callback after an object has been freed
    to verify that the state is the constructor state again?  The callback is
    performed before each freeing of an object.
    
    I would think that it is much easier to check the object state manually
    before the free.  That also places the check near the code object
    manipulation of the object.
    
    Also the SLAB_DEBUG_INITIAL callback is only performed if the kernel was
    compiled with SLAB debugging on.  If there would be code in a constructor
    handling SLAB_DEBUG_INITIAL then it would have to be conditional on
    SLAB_DEBUG otherwise it would just be dead code.  But there is no such code
    in the kernel.  I think SLUB_DEBUG_INITIAL is too problematic to make real
    use of, difficult to understand and there are easier ways to accomplish the
    same effect (i.e.  add debug code before kfree).
    
    There is a related flag SLAB_CTOR_VERIFY that is frequently checked to be
    clear in fs inode caches.  Remove the pointless checks (they would even be
    pointless without removeal of SLAB_DEBUG_INITIAL) from the fs constructors.
    
    This is the last slab flag that SLUB did not support.  Remove the check for
    unimplemented flags from SLUB.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4b1d89290b62bb2db476c94c82cf7442aab440c8
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:14 2007 -0700

    get_unmapped_area doesn't need hugetlbfs hacks anymore
    
    Remove the hugetlbfs specific hacks in toplevel get_unmapped_area() now that
    all archs and hugetlbfs itself do the right thing for both cases.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Russell King <rmk+kernel@arm.linux.org.uk>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Adam Litke <agl@us.ibm.com>
    Cc: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 06abdfb47ee745a4d79721de24260815ec6bca2b
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:13 2007 -0700

    get_unmapped_area handles MAP_FIXED in generic code
    
    generic arch_get_unmapped_area() now handles MAP_FIXED.  Now that all
    implementations have been fixed, change the toplevel get_unmapped_area() to
    call into arch or drivers for the MAP_FIXED case.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Russell King <rmk+kernel@arm.linux.org.uk>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: William Irwin <bill.irwin@oracle.com>
    Cc: Adam Litke <agl@us.ibm.com>
    Cc: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 036e08568cbee4b16e14551e9f004c3d490d6271
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:12 2007 -0700

    get_unmapped_area handles MAP_FIXED in hugetlbfs
    
    Generic hugetlb_get_unmapped_area() now handles MAP_FIXED by just calling
    prepare_hugepage_range()
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Russell King <rmk+kernel@arm.linux.org.uk>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Adam Litke <agl@us.ibm.com>
    Cc: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 11300a64d08ebce03e30cac8eb58e8ce008e4bb7
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:11 2007 -0700

    get_unmapped_area handles MAP_FIXED on x86_64
    
    Handle MAP_FIXED in x86_64 arch_get_unmapped_area(), simple case, just return
    the address as passed in
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ac35ee484df361e1aed89873a458900693effdbe
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:10 2007 -0700

    get_unmapped_area handles MAP_FIXED on sparc64
    
    Handle MAP_FIXED in hugetlb_get_unmapped_area on sparc64 by just using
    prepare_hugepage_range()
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: "David S. Miller" <davem@davemloft.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 869e5101728fe2f307f0a3c3cf599c184f81f0ee
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:09 2007 -0700

    get_unmapped_area handles MAP_FIXED on parisc
    
    Handle MAP_FIXED in parisc arch_get_unmapped_area(), just return the address.
    We might want to also check for possible cache aliasing issues now that we get
    called in that case (like ARM or MIPS), leave a comment for the maintainers to
    pick up.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Cc: Matthew Wilcox <willy@debian.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit afa37394d6bfc91907b0e08c902d36d848232b99
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:09 2007 -0700

    get_unmapped_area handles MAP_FIXED on ia64
    
    Handle MAP_FIXED in ia64 arch_get_unmapped_area and
    hugetlb_get_unmapped_area(), just call prepare_hugepage_range in the later and
    is_hugepage_only_range() in the former.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5a8130f2b186ac91190d1dcea875d66d08e6a1de
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:08 2007 -0700

    get_unmapped_area handles MAP_FIXED on i386
    
    Handle MAP_FIXED in i386 hugetlb_get_unmapped_area(), just call
    prepare_hugepage_range.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Adam Litke <agl@us.ibm.com>
    Cc: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2fd3bebaad9da3b3b99c46a3389099424bf7ee35
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:07 2007 -0700

    get_unmapped_area handles MAP_FIXED on frv
    
    Handle MAP_FIXED in arch_get_unmapped_area on frv.  Trivial case, just return
    the address.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: David Howells <dhowells@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit acec0ac0a87ca821f9d204780c2d1aa0509a6346
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:07 2007 -0700

    get_unmapped_area handles MAP_FIXED on arm
    
    ARM already had a case for MAP_FIXED in arch_get_unmapped_area() though it was
    not called before.  Fix the comment to reflect that it will now be called.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 4b87b3b2eb1fa2d6ac0a1400ad5fb8f4b7cbfc09
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:06 2007 -0700

    get_unmapped_area handles MAP_FIXED on alpha
    
    Handle MAP_FIXED in alpha's arch_get_unmapped_area(), simple case, just return
    the address as passed in
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d506a7725114aaddbf982fd18621b3e0e5c27f1b
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun May 6 14:50:02 2007 -0700

    get_unmapped_area handles MAP_FIXED on powerpc
    
    The current get_unmapped_area code calls the f_ops->get_unmapped_area or the
    arch one (via the mm) only when MAP_FIXED is not passed.  That makes it
    impossible for archs to impose proper constraints on regions of the virtual
    address space.  To work around that, get_unmapped_area() then calls some
    hugetlbfs specific hacks.
    
    This cause several problems, among others:
    
    - It makes it impossible for a driver or filesystem to do the same thing
      that hugetlbfs does (for example, to allow a driver to use larger page sizes
      to map external hardware) if that requires applying a constraint on the
      addresses (constraining that mapping in certain regions and other mappings
      out of those regions).
    
    - Some archs like arm, mips, sparc, sparc64, sh and sh64 already want
      MAP_FIXED to be passed down in order to deal with aliasing issues.  The code
      is there to handle it...  but is never called.
    
    This series of patches moves the logic to handle MAP_FIXED down to the various
    arch/driver get_unmapped_area() implementations, and then changes the generic
    code to always call them.  The hugetlbfs hacks then disappear from the generic
    code.
    
    Since I need to do some special 64K pages mappings for SPEs on cell, I need to
    work around the first problem at least.  I have further patches thus
    implementing a "slices" layer that handles multiple page sizes through slices
    of the address space for use by hugetlbfs, the SPE code, and possibly others,
    but it requires that serie of patches first/
    
    There is still a potential (but not practical) issue due to the fact that
    filesystems/drivers implemeting g_u_a will effectively bypass all arch checks.
     This is not an issue in practice as the only filesystems/drivers using that
    hook are doing so for arch specific purposes in the first place.
    
    There is also a problem with mremap that will completely bypass all arch
    checks.  I'll try to address that separately, I'm not 100% certain yet how,
    possibly by making it not work when the vma has a file whose f_ops has a
    get_unmapped_area callback, and by making it use is_hugepage_only_range()
    before expanding into a new area.
    
    Also, I want to turn is_hugepage_only_range() into a more generic
    is_normal_page_range() as that's really what it will end up meaning when used
    in stack grow, brk grow and mremap.
    
    None of the above "issues" however are introduced by this patch, they are
    already there, so I think the patch can go ini for 2.6.22.
    
    This patch:
    
    Handle MAP_FIXED in powerpc's arch_get_unmapped_area() in all 3
    implementations of it.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Russell King <rmk+kernel@arm.linux.org.uk>
    Cc: David Howells <dhowells@redhat.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Cc: Grant Grundler <grundler@parisc-linux.org>
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Adam Litke <agl@us.ibm.com>
    Cc: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2b45ab3398a0ba119b1f672c7c56fd5a431b7f0a
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:50:00 2007 -0700

    oom: fix constraint deadlock
    
    Fixes a deadlock in the OOM killer for allocations that are not
    __GFP_HARDWALL.
    
    Before the OOM killer checks for the allocation constraint, it takes
    callback_mutex.
    
    constrained_alloc() iterates through each zone in the allocation zonelist
    and calls cpuset_zone_allowed_softwall() to determine whether an allocation
    for gfp_mask is possible.  If a zone's node is not in the OOM-triggering
    task's mems_allowed, it is not exiting, and we did not fail on a
    __GFP_HARDWALL allocation, cpuset_zone_allowed_softwall() attempts to take
    callback_mutex to check the nearest exclusive ancestor of current's cpuset.
     This results in deadlock.
    
    We now take callback_mutex after iterating through the zonelist since we
    don't need it yet.
    
    Cc: Andi Kleen <ak@suse.de>
    Cc: Nick Piggin <npiggin@suse.de>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Cc: Martin J. Bligh <mbligh@mbligh.org>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2b744c01a54fe0c9974ff1b29522f25f07084053
Author: Yasunori Goto <y-goto@jp.fujitsu.com>
Date:   Sun May 6 14:49:59 2007 -0700

    mm: fix handling of panic_on_oom when cpusets are in use
    
    The current panic_on_oom may not work if there is a process using
    cpusets/mempolicy, because other nodes' memory may remain.  But some people
    want failover by panic ASAP even if they are used.  This patch makes new
    setting for its request.
    
    This is tested on my ia64 box which has 3 nodes.
    
    Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
    Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
    Cc: Christoph Lameter <clameter@sgi.com>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Ethan Solomita <solo@google.com>
    Cc: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 824ebef122153a03925ae0ed211b4e8568d1c8db
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sun May 6 14:49:58 2007 -0700

    fault injection: fix failslab with CONFIG_NUMA
    
    Currently failslab injects failures into ____cache_alloc().  But with enabling
    CONFIG_NUMA it's not enough to let actual slab allocator functions (kmalloc,
    kmem_cache_alloc, ...) return NULL.
    
    This patch moves fault injection hook inside of __cache_alloc() and
    __cache_alloc_node().  These are lower call path than ____cache_alloc() and
    enable to inject faulures to slab allocators with CONFIG_NUMA.
    
    Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Cc: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f0f3980b21508bd573eff1746d469436f50a903d
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:58 2007 -0700

    slab allocators: remove multiple alignment specifications
    
    It is not necessary to tell the slab allocators to align to a cacheline
    if an explicit alignment was already specified. It is rather confusing
    to specify multiple alignments.
    
    Make sure that the call sites only use one form of alignment.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0a31bd5f2bbb6473ef9d24f0063ca91cfa678b64
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:57 2007 -0700

    KMEM_CACHE(): simplify slab cache creation
    
    This patch provides a new macro
    
    KMEM_CACHE(<struct>, <flags>)
    
    to simplify slab creation. KMEM_CACHE creates a slab with the name of the
    struct, with the size of the struct and with the alignment of the struct.
    Additional slab flags may be specified if necessary.
    
    Example
    
    struct test_slab {
    	int a,b,c;
    	struct list_head;
    } __cacheline_aligned_in_smp;
    
    test_slab_cache = KMEM_CACHE(test_slab, SLAB_PANIC)
    
    will create a new slab named "test_slab" of the size sizeof(struct
    test_slab) and aligned to the alignment of test slab.  If it fails then we
    panic.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5af60839909b8e3b28ca7cd7912fa0b23475617f
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:56 2007 -0700

    slab allocators: Remove obsolete SLAB_MUST_HWCACHE_ALIGN
    
    This patch was recently posted to lkml and acked by Pekka.
    
    The flag SLAB_MUST_HWCACHE_ALIGN is
    
    1. Never checked by SLAB at all.
    
    2. A duplicate of SLAB_HWCACHE_ALIGN for SLUB
    
    3. Fulfills the role of SLAB_HWCACHE_ALIGN for SLOB.
    
    The only remaining use is in sparc64 and ppc64 and their use there
    reflects some earlier role that the slab flag once may have had. If
    its specified then SLAB_HWCACHE_ALIGN is also specified.
    
    The flag is confusing, inconsistent and has no purpose.
    
    Remove it.
    
    Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 96018fdacbfcaf6a0694d066b525f67c24025688
Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date:   Sun May 6 14:49:55 2007 -0700

    mm: optimize acorn partition truncate
    
    invalidate_bdev() is superfluous when truncate_inode_pages() is also
    called.  do call invalidate_bh_lrus() though, to avoid stale pointers.
    
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f9a14399aea13830d8af6798a53207bb0a900945
Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date:   Sun May 6 14:49:55 2007 -0700

    mm: optimize kill_bdev()
    
    Remove duplicate work in kill_bdev().
    
    It currently invalidates and then truncates the bdev's mapping.
    invalidate_mapping_pages() will opportunistically remove pages from the
    mapping.  And truncate_inode_pages() will forcefully remove all pages.
    
    The only thing truncate doesn't do is flush the bh lrus.  So do that
    explicitly.  This avoids (very unlikely) but possible invalid lookup
    results if the same bdev is quickly re-issued.
    
    It also will prevent extreme kernel latencies which are observed when
    blockdevs which have a large amount of pagecache are unmounted, by avoiding
    invalidate_mapping_pages() on that path.  invalidate_mapping_pages() has no
    cond_resched (it can be called under spinlock), whereas truncate_inode_pages()
    has one.
    
    [akpm@linux-foundation.org: restore nrpages==0 optimisation]
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f98393a64ca1392130724c3acb4e3f325801d2b6
Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
Date:   Sun May 6 14:49:54 2007 -0700

    mm: remove destroy_dirty_buffers from invalidate_bdev()
    
    Remove the destroy_dirty_buffers argument from invalidate_bdev(), it hasn't
    been used in 6 years (so akpm says).
    
    find * -name \*.[ch] | xargs grep -l invalidate_bdev |
    while read file; do
    	quilt add $file;
    	sed -ie 's/invalidate_bdev(\([^,]*\),[^)]*)/invalidate_bdev(\1)/g' $file;
    done
    
    Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0a27a14a62921b438bb6f33772690d345a089be6
Author: Nick Piggin <npiggin@suse.de>
Date:   Sun May 6 14:49:53 2007 -0700

    mm: madvise avoid exclusive mmap_sem
    
    Avoid down_write of the mmap_sem in madvise when we can help it.
    
    Acked-by: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Rik van Riel <riel@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b4169525bc2336ea6581c6ff2aa88b2671e3b9f9
Author: matze <matze@riseup.net>
Date:   Sun May 6 14:49:52 2007 -0700

    include KERN_* constant in printk() calls in mm/slab.c
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bc0055aee40ba40627361d8ffd8530d315920f18
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sun May 6 14:49:52 2007 -0700

    slob: handle SLAB_PANIC flag
    
    kmem_cache_create() for slob doesn't handle SLAB_PANIC.
    
    Signed-off-by: Matt Mackall <mpm@selenic.com>
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3a2cba993b0a04f258ab75e15cf3f08ada268dbd
Author: David Miller <davem@davemloft.net>
Date:   Sun May 6 14:49:51 2007 -0700

    Quicklist support for sparc64
    
    I ported this to sparc64 as per the patch below, tested on UP SunBlade1500 and
    24 cpu Niagara T1000.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: William Lee Irwin III <wli@holomorphy.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6225e93735acaa09865bce746958f1046c2e0bc3
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:50 2007 -0700

    Quicklists for page table pages
    
    On x86_64 this cuts allocation overhead for page table pages down to a
    fraction (kernel compile / editing load.  TSC based measurement of times spend
    in each function):
    
    no quicklist
    
    pte_alloc               1569048 4.3s(401ns/2.7us/179.7us)
    pmd_alloc                780988 2.1s(337ns/2.7us/86.1us)
    pud_alloc                780072 2.2s(424ns/2.8us/300.6us)
    pgd_alloc                260022 1s(920ns/4us/263.1us)
    
    quicklist:
    
    pte_alloc                452436 573.4ms(8ns/1.3us/121.1us)
    pmd_alloc                196204 174.5ms(7ns/889ns/46.1us)
    pud_alloc                195688 172.4ms(7ns/881ns/151.3us)
    pgd_alloc                 65228 9.8ms(8ns/150ns/6.1us)
    
    pgd allocations are the most complex and there we see the most dramatic
    improvement (may be we can cut down the amount of pgds cached somewhat?).  But
    even the pte allocations still see a doubling of performance.
    
    1. Proven code from the IA64 arch.
    
    	The method used here has been fine tuned for years and
    	is NUMA aware. It is based on the knowledge that accesses
    	to page table pages are sparse in nature. Taking a page
    	off the freelists instead of allocating a zeroed pages
    	allows a reduction of number of cachelines touched
    	in addition to getting rid of the slab overhead. So
    	performance improves. This is particularly useful if pgds
    	contain standard mappings. We can save on the teardown
    	and setup of such a page if we have some on the quicklists.
    	This includes avoiding lists operations that are otherwise
    	necessary on alloc and free to track pgds.
    
    2. Light weight alternative to use slab to manage page size pages
    
    	Slab overhead is significant and even page allocator use
    	is pretty heavy weight. The use of a per cpu quicklist
    	means that we touch only two cachelines for an allocation.
    	There is no need to access the page_struct (unless arch code
    	needs to fiddle around with it). So the fast past just
    	means bringing in one cacheline at the beginning of the
    	page. That same cacheline may then be used to store the
    	page table entry. Or a second cacheline may be used
    	if the page table entry is not in the first cacheline of
    	the page. The current code will zero the page which means
    	touching 32 cachelines (assuming 128 byte). We get down
    	from 32 to 2 cachelines in the fast path.
    
    3. x86_64 gets lightweight page table page management.
    
    	This will allow x86_64 arch code to faster repopulate pgds
    	and other page table entries. The list operations for pgds
    	are reduced in the same way as for i386 to the point where
    	a pgd is allocated from the page allocator and when it is
    	freed back to the page allocator. A pgd can pass through
    	the quicklists without having to be reinitialized.
    
    64 Consolidation of code from multiple arches
    
    	So far arches have their own implementation of quicklist
    	management. This patch moves that feature into the core allowing
    	an easier maintenance and consistent management of quicklists.
    
    Page table pages have the characteristics that they are typically zero or in a
    known state when they are freed.  This is usually the exactly same state as
    needed after allocation.  So it makes sense to build a list of freed page
    table pages and then consume the pages already in use first.  Those pages have
    already been initialized correctly (thus no need to zero them) and are likely
    already cached in such a way that the MMU can use them most effectively.  Page
    table pages are used in a sparse way so zeroing them on allocation is not too
    useful.
    
    Such an implementation already exits for ia64.  Howver, that implementation
    did not support constructors and destructors as needed by i386 / x86_64.  It
    also only supported a single quicklist.  The implementation here has
    constructor and destructor support as well as the ability for an arch to
    specify how many quicklists are needed.
    
    Quicklists are defined by an arch defining CONFIG_QUICKLIST.  If more than one
    quicklist is necessary then we can define NR_QUICK for additional lists.  F.e.
     i386 needs two and thus has
    
    config NR_QUICK
    	int
    	default 2
    
    If an arch has requested quicklist support then pages can be allocated
    from the quicklist (or from the page allocator if the quicklist is
    empty) via:
    
    quicklist_alloc(<quicklist-nr>, <gfpflags>, <constructor>)
    
    Page table pages can be freed using:
    
    quicklist_free(<quicklist-nr>, <destructor>, <page>)
    
    Pages must have a definite state after allocation and before
    they are freed. If no constructor is specified then pages
    will be zeroed on allocation and must be zeroed before they are
    freed.
    
    If a constructor is used then the constructor will establish
    a definite page state. F.e. the i386 and x86_64 pgd constructors
    establish certain mappings.
    
    Constructors and destructors can also be used to track the pages.
    i386 and x86_64 use a list of pgds in order to be able to dynamically
    update standard mappings.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Luck, Tony" <tony.luck@intel.com>
    Cc: William Lee Irwin III <wli@holomorphy.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c09d87517298fd01543739ba26987645deb4e6a9
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:48 2007 -0700

    slub: add slabinfo tool
    
    Add the tool which gets reports about slabs to the VM documentation directory.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 352434211dad370316155d90d7dab590519f465b
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:47 2007 -0700

    slub: user documentation
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 70d71228af9360cc4a0198ecd6351a1b34fa6d01
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:47 2007 -0700

    slub: remove object activities out of checking functions
    
    Make sure that the check function really only check things and do not perform
    activities.  Extract the tracing and object seeding out of the two check
    functions and place them into slab_alloc and slab_free
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2086d26a05a4b5bda4a2f677bc143933bbdfa9f8
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:46 2007 -0700

    SLUB: Free slabs and sort partial slab lists in kmem_cache_shrink
    
    At kmem_cache_shrink check if we have any empty slabs on the partial
    if so then remove them.
    
    Also--as an anti-fragmentation measure--sort the partial slabs so that
    the most fully allocated ones come first and the least allocated last.
    
    The next allocations may fill up the nearly full slabs. Having the
    least allocated slabs last gives them the maximum chance that their
    remaining objects may be freed. Thus we can hopefully minimize the
    partial slabs.
    
    I think this is the best one can do in terms antifragmentation
    measures. Real defragmentation (meaning moving objects out of slabs with
    the least free objects to those that are almost full) can be implemted
    by reverse scanning through the list produced here but that would mean
    that we need to provide a callback at slab cache creation that allows
    the deletion or moving of an object. This will involve slab API
    changes, so defer for now.
    
    Cc: Mel Gorman <mel@skynet.ie>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 88a420e4e21c1ff6592a668cf4e8af42eff30bad
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:45 2007 -0700

    slub: add ability to list alloc / free callers per slab
    
    This patch enables listing the callers who allocated or freed objects in a
    cache.
    
    For example to list the allocators for kmalloc-128 do
    
    cat /sys/slab/kmalloc-128/alloc_calls
          7 sn_io_slot_fixup+0x40/0x700
          7 sn_io_slot_fixup+0x80/0x700
          9 sn_bus_fixup+0xe0/0x380
          6 param_sysfs_setup+0xf0/0x280
        276 percpu_populate+0xf0/0x1a0
         19 __register_chrdev_region+0x30/0x360
          8 expand_files+0x2e0/0x6e0
          1 sys_epoll_create+0x60/0x200
          1 __mounts_open+0x140/0x2c0
         65 kmem_alloc+0x110/0x280
          3 alloc_disk_node+0xe0/0x200
         33 as_get_io_context+0x90/0x280
         74 kobject_kset_add_dir+0x40/0x140
         12 pci_create_bus+0x2a0/0x5c0
          1 acpi_ev_create_gpe_block+0x120/0x9e0
         41 con_insert_unipair+0x100/0x1c0
          1 uart_open+0x1c0/0xba0
          1 dma_pool_create+0xe0/0x340
          2 neigh_table_init_no_netlink+0x260/0x4c0
          6 neigh_parms_alloc+0x30/0x200
          1 netlink_kernel_create+0x130/0x320
          5 fz_hash_alloc+0x50/0xe0
          2 sn_common_hubdev_init+0xd0/0x6e0
         28 kernel_param_sysfs_setup+0x30/0x180
         72 process_zones+0x70/0x2e0
    
    cat /sys/slab/kmalloc-128/free_calls
        558 <not-available>
          3 sn_io_slot_fixup+0x600/0x700
         84 free_fdtable_rcu+0x120/0x260
          2 seq_release+0x40/0x60
          6 kmem_free+0x70/0xc0
         24 free_as_io_context+0x20/0x200
          1 acpi_get_object_info+0x3a0/0x3e0
          1 acpi_add_single_object+0xcf0/0x1e40
          2 con_release_unimap+0x80/0x140
          1 free+0x20/0x40
    
    SLAB_STORE_USER must be enabled for a slab cache by either booting with
    "slab_debug" or enabling user tracking specifically for the slab of interest.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e95eed571e85d7ad4cde73576296c615f305f59f
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:44 2007 -0700

    SLUB: Add MIN_PARTIAL
    
    We leave a mininum of partial slabs on nodes when we search for
    partial slabs on other node. Define a constant for that value.
    
    Then modify slub to keep MIN_PARTIAL slabs around.
    
    This avoids bad situations where a function frees the last object
    in a slab (which results in the page being returned to the page
    allocator) only to then allocate one again (which requires getting
    a page back from the page allocator if the partial list was empty).
    Keeping a couple of slabs on the partial list reduces overhead.
    
    Empty slabs are added to the end of the partial list to insure that
    partially allocated slabs are consumed first (defragmentation).
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 53e15af03be4fdaaf20802d78f141487d7272985
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:43 2007 -0700

    slub: validation of slabs (metadata and guard zones)
    
    This enables validation of slab.  Validation means that all objects are
    checked to see if there are redzone violations, if padding has been
    overwritten or any pointers have been corrupted.  Also checks the consistency
    of slab counters.
    
    Validation enables the detection of metadata corruption without the kernel
    having to execute code that actually uses (allocs/frees) and object.  It
    allows one to make sure that the slab metainformation and the guard values
    around an object have not been compromised.
    
    A single slabcache can be checked by writing a 1 to the "validate" file.
    
    i.e.
    
    echo 1 >/sys/slab/kmalloc-128/validate
    
    or use the slabinfo tool to check all slabs
    
    slabinfo -v
    
    Error messages will show up in the syslog.
    
    Note that validation can only reach slabs that are on a list.  This means that
    we are usually restricted to partial slabs and active slabs unless
    SLAB_STORE_USER is active which will build a full slab list and allows
    validation of slabs that are fully in use.  Booting with "slub_debug" set will
    enable SLAB_STORE_USER and then full diagnostic are available.
    
    Note that we attempt to push cpu slabs back to the lists when we start the
    check.  If the cpu slab is reactivated before we get to it (another processor
    grabs it before we get to it) then it cannot be checked.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 643b113849d8faa68c9f01c3c9d929bfbffd50bd
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:42 2007 -0700

    slub: enable tracking of full slabs
    
    If slab tracking is on then build a list of full slabs so that we can verify
    the integrity of all slabs and are also able to built list of alloc/free
    callers.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 77c5e2d01af871f4bfbe08feefa3d5118cb1001b
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:42 2007 -0700

    slub: fix object tracking
    
    Object tracking did not work the right way for several call chains. Fix this up
    by adding a new parameter to slub_alloc and slub_free that specifies the
    caller address explicitly.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b49af68ff9fc5d6e0d96704a1843968b91cc73c6
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:41 2007 -0700

    Add virt_to_head_page and consolidate code in slab and slub
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6d7779538f765963ced45a3fa4bed7ba8d2c277d
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:40 2007 -0700

    mm: optimize compound_head() by avoiding a shared page flag
    
    The patch adds PageTail(page) and PageHead(page) to check if a page is the
    head or the tail of a compound page.  This is done by masking the two bits
    describing the state of a compound page and then comparing them.  So one
    comparision and a branch instead of two bit checks and two branches.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d85f33855c303acfa87fa457157cef755b6087df
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:39 2007 -0700

    Make page->private usable in compound pages
    
    If we add a new flag so that we can distinguish between the first page and the
    tail pages then we can avoid to use page->private in the first page.
    page->private == page for the first page, so there is no real information in
    there.
    
    Freeing up page->private makes the use of compound pages more transparent.
    They become more usable like real pages.  Right now we have to be careful f.e.
     if we are going beyond PAGE_SIZE allocations in the slab on i386 because we
    can then no longer use the private field.  This is one of the issues that
    cause us not to support debugging for page size slabs in SLAB.
    
    Having page->private available for SLUB would allow more meta information in
    the page struct.  I can probably avoid the 16 bit ints that I have in there
    right now.
    
    Also if page->private is available then a compound page may be equipped with
    buffer heads.  This may free up the way for filesystems to support larger
    blocks than page size.
    
    We add PageTail as an alias of PageReclaim.  Compound pages cannot currently
    be reclaimed.  Because of the alias one needs to check PageCompound first.
    
    The RFC for the this approach was discussed at
    http://marc.info/?t=117574302800001&r=1&w=2
    
    [nacc@us.ibm.com: fix hugetlbfs]
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 30520864839dc796fd314812e7036e754880b47d
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:38 2007 -0700

    PowerPC: Disable SLUB for configurations in which slab page structs are modified
    
    PowerPC uses the slab allocator to manage the lowest level of the page
    table.  In high cpu configurations we also use the page struct to split the
    page table lock.  Disallow the selection of SLUB for that case.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Cc: Hugh Dickins <hugh@veritas.com>
    Cc: Paul Mackerras <paulus@samba.org>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 614410d5892af5f86d0ec14e28f9f6d5f4ac9e9b
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:38 2007 -0700

    SLUB: allocate smallest object size if the user asks for 0 bytes
    
    Makes SLUB behave like SLAB in this area to avoid issues....
    
    Throw a stack dump to alert people.
    
    At some point the behavior should be switched back.  NULL is no memory as
    far as I can tell and if the use asked for 0 bytes then he need to get no
    memory.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 47bfdc0d5a18a4b760ffb6a332932aaa5c0859e0
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:37 2007 -0700

    SLUB: change default alignments
    
    Structures may contain u64 items on 32 bit platforms that are only able to
    address 64 bit items on 64 bit boundaries.  Change the mininum alignment of
    slabs to conform to those expectations.
    
    ARCH_KMALLOC_MINALIGN must be changed for good since a variety of structure
    are mixed in the general slabs.
    
    ARCH_SLAB_MINALIGN is changed because currently there is no consistent
    specification of object alignment.  We may have that in the future when the
    KMEM_CACHE and related macros are used to generate slabs.  These pass the
    alignment of the structure generated by the compiler to the slab.
    
    With KMEM_CACHE etc we could align structures that do not contain 64
    bit values to 32 bit boundaries potentially saving some memory.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 81819f0fc8285a2a5a921c019e3e3d7b6169d225
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:36 2007 -0700

    SLUB core
    
    This is a new slab allocator which was motivated by the complexity of the
    existing code in mm/slab.c. It attempts to address a variety of concerns
    with the existing implementation.
    
    A. Management of object queues
    
       A particular concern was the complex management of the numerous object
       queues in SLAB. SLUB has no such queues. Instead we dedicate a slab for
       each allocating CPU and use objects from a slab directly instead of
       queueing them up.
    
    B. Storage overhead of object queues
    
       SLAB Object queues exist per node, per CPU. The alien cache queue even
       has a queue array that contain a queue for each processor on each
       node. For very large systems the number of queues and the number of
       objects that may be caught in those queues grows exponentially. On our
       systems with 1k nodes / processors we have several gigabytes just tied up
       for storing references to objects for those queues  This does not include
       the objects that could be on those queues. One fears that the whole
       memory of the machine could one day be consumed by those queues.
    
    C. SLAB meta data overhead
    
       SLAB has overhead at the beginning of each slab. This means that data
       cannot be naturally aligned at the beginning of a slab block. SLUB keeps
       all meta data in the corresponding page_struct. Objects can be naturally
       aligned in the slab. F.e. a 128 byte object will be aligned at 128 byte
       boundaries and can fit tightly into a 4k page with no bytes left over.
       SLAB cannot do this.
    
    D. SLAB has a complex cache reaper
    
       SLUB does not need a cache reaper for UP systems. On SMP systems
       the per CPU slab may be pushed back into partial list but that
       operation is simple and does not require an iteration over a list
       of objects. SLAB expires per CPU, shared and alien object queues
       during cache reaping which may cause strange hold offs.
    
    E. SLAB has complex NUMA policy layer support
    
       SLUB pushes NUMA policy handling into the page allocator. This means that
       allocation is coarser (SLUB does interleave on a page level) but that
       situation was also present before 2.6.13. SLABs application of
       policies to individual slab objects allocated in SLAB is
       certainly a performance concern due to the frequent references to
       memory policies which may lead a sequence of objects to come from
       one node after another. SLUB will get a slab full of objects
       from one node and then will switch to the next.
    
    F. Reduction of the size of partial slab lists
    
       SLAB has per node partial lists. This means that over time a large
       number of partial slabs may accumulate on those lists. These can
       only be reused if allocator occur on specific nodes. SLUB has a global
       pool of partial slabs and will consume slabs from that pool to
       decrease fragmentation.
    
    G. Tunables
    
       SLAB has sophisticated tuning abilities for each slab cache. One can
       manipulate the queue sizes in detail. However, filling the queues still
       requires the uses of the spin lock to check out slabs. SLUB has a global
       parameter (min_slab_order) for tuning. Increasing the minimum slab
       order can decrease the locking overhead. The bigger the slab order the
       less motions of pages between per CPU and partial lists occur and the
       better SLUB will be scaling.
    
    G. Slab merging
    
       We often have slab caches with similar parameters. SLUB detects those
       on boot up and merges them into the corresponding general caches. This
       leads to more effective memory use. About 50% of all caches can
       be eliminated through slab merging. This will also decrease
       slab fragmentation because partial allocated slabs can be filled
       up again. Slab merging can be switched off by specifying
       slub_nomerge on boot up.
    
       Note that merging can expose heretofore unknown bugs in the kernel
       because corrupted objects may now be placed differently and corrupt
       differing neighboring objects. Enable sanity checks to find those.
    
    H. Diagnostics
    
       The current slab diagnostics are difficult to use and require a
       recompilation of the kernel. SLUB contains debugging code that
       is always available (but is kept out of the hot code paths).
       SLUB diagnostics can be enabled via the "slab_debug" option.
       Parameters can be specified to select a single or a group of
       slab caches for diagnostics. This means that the system is running
       with the usual performance and it is much more likely that
       race conditions can be reproduced.
    
    I. Resiliency
    
       If basic sanity checks are on then SLUB is capable of detecting
       common error conditions and recover as best as possible to allow the
       system to continue.
    
    J. Tracing
    
       Tracing can be enabled via the slab_debug=T,<slabcache> option
       during boot. SLUB will then protocol all actions on that slabcache
       and dump the object contents on free.
    
    K. On demand DMA cache creation.
    
       Generally DMA caches are not needed. If a kmalloc is used with
       __GFP_DMA then just create this single slabcache that is needed.
       For systems that have no ZONE_DMA requirement the support is
       completely eliminated.
    
    L. Performance increase
    
       Some benchmarks have shown speed improvements on kernbench in the
       range of 5-10%. The locking overhead of slub is based on the
       underlying base allocation size. If we can reliably allocate
       larger order pages then it is possible to increase slub
       performance much further. The anti-fragmentation patches may
       enable further performance increases.
    
    Tested on:
    i386 UP + SMP, x86_64 UP + SMP + NUMA emulation, IA64 NUMA + Simulator
    
    SLUB Boot options
    
    slub_nomerge		Disable merging of slabs
    slub_min_order=x	Require a minimum order for slab caches. This
    			increases the managed chunk size and therefore
    			reduces meta data and locking overhead.
    slub_min_objects=x	Mininum objects per slab. Default is 8.
    slub_max_order=x	Avoid generating slabs larger than order specified.
    slub_debug		Enable all diagnostics for all caches
    slub_debug=<options>	Enable selective options for all caches
    slub_debug=<o>,<cache>	Enable selective options for a certain set of
    			caches
    
    Available Debug options
    F		Double Free checking, sanity and resiliency
    R		Red zoning
    P		Object / padding poisoning
    U		Track last free / alloc
    T		Trace all allocs / frees (only use for individual slabs).
    
    To use SLUB: Apply this patch and then select SLUB as the default slab
    allocator.
    
    [hugh@veritas.com: fix an oops-causing locking error]
    [akpm@linux-foundation.org: various stupid cleanups and small fixes]
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 543691a6cd70b606dd9bed5e77b120c5d9c5c506
Author: Andy Whitcroft <apw@shadowen.org>
Date:   Sun May 6 14:49:33 2007 -0700

    tty_register_driver: only allocate tty instances when defined
    
    If device->num is zero we attempt to kmalloc() zero bytes.  When SLUB is
    enabled this returns a null pointer and take that as an allocation failure
    and fail the device register.  Check for no devices and avoid the
    allocation.
    
    [akpm: opportunistic kzalloc() conversion]
    Signed-off-by: Andy Whitcroft <apw@shadowen.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b5637e65ee2cecd344b1f8ff750013f697d3ae16
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:49:33 2007 -0700

    i386: use page allocator to allocate thread_info structure
    
    i386 uses kmalloc to allocate the threadinfo structure assuming that the
    allocations result in a page sized aligned allocation.  That has worked so
    far because SLAB exempts page sized slabs from debugging and aligns them in
    special ways that goes beyond the restrictions imposed by
    KMALLOC_ARCH_MINALIGN valid for other slabs in the kmalloc array.
    
    SLUB also works fine without debugging since page sized allocations neatly
    align at page boundaries.  However, if debugging is switched on then SLUB
    will extend the slab with debug information.  The resulting slab is not
    longer of page size.  It will only be aligned following the requirements
    imposed by KMALLOC_ARCH_MINALIGN.  As a result the threadinfo structure may
    not be page aligned which makes i386 fail to boot with SLUB debug on.
    
    Replace the calls to kmalloc with calls into the page allocator.
    
    An alternate solution may be to create a custom slab cache where the
    alignment is set to PAGE_SIZE.  That would allow slub debugging to be
    applied to the threadinfo structure.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Cc: William Lee Irwin III <wli@holomorphy.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c596d9f320aaf30d28c1d793ff3a976dee1db8f5
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:49:32 2007 -0700

    cpusets: allow TIF_MEMDIE threads to allocate anywhere
    
    OOM killed tasks have access to memory reserves as specified by the
    TIF_MEMDIE flag in the hopes that it will quickly exit.  If such a task has
    memory allocations constrained by cpusets, we may encounter a deadlock if a
    blocking task cannot exit because it cannot allocate the necessary memory.
    
    We allow tasks that have the TIF_MEMDIE flag to allocate memory anywhere,
    including outside its cpuset restriction, so that it can quickly die
    regardless of whether it is __GFP_HARDWALL.
    
    Cc: Andi Kleen <ak@suse.de>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a3a02be79114b854acc555e8ed686eb84f44ae2e
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sun May 6 14:49:31 2007 -0700

    slab: mark set_up_list3s() __init
    
    It is only ever used prior to free_initmem().
    
    (It will cause a warning when we run the section checking, but that's a
    false-positive and it simply changes the source of an existing warning, which
    is also a false-positive)
    
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Cc: Pekka Enberg <penberg@cs.helsinki.fi>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3b1d92c56514987010bb0201b5c71aeb633fc4f8
Author: Mel Gorman <mel@csn.ul.ie>
Date:   Sun May 6 14:49:30 2007 -0700

    Do not disable interrupts when reading min_free_kbytes
    
    The sysctl handler for min_free_kbytes calls setup_per_zone_pages_min() on
    read or write.  This function iterates through every zone and calls
    spin_lock_irqsave() on the zone LRU lock.  When reading min_free_kbytes,
    this is a total waste of time that disables interrupts on the local
    processor.  It might even be noticable machines with large numbers of zones
    if a process started constantly reading min_free_kbytes.
    
    This patch only calls setup_per_zone_pages_min() only on write. Tested on
    an x86 laptop and it did the right thing.
    
    Signed-off-by: Mel Gorman <mel@csn.ul.ie>
    Acked-by: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8da3430d8a7f885c2bf65121181d76c9d290a86e
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun May 6 14:49:29 2007 -0700

    slab: NUMA kmem_cache diet
    
    Some NUMA machines have a big MAX_NUMNODES (possibly 1024), but fewer
    possible nodes.  This patch dynamically sizes the 'struct kmem_cache' to
    allocate only needed space.
    
    I moved nodelists[] field at the end of struct kmem_cache, and use the
    following computation in kmem_cache_init()
    
    cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
                                     nr_node_ids * sizeof(struct kmem_list3 *);
    
    On my two nodes x86_64 machine, kmem_cache.obj_size is now 192 instead of 704
    (This is because on x86_64, MAX_NUMNODES is 64)
    
    On bigger NUMA setups, this might reduce the gfporder of "cache_cache"
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Cc: Pekka Enberg <penberg@cs.helsinki.fi>
    Cc: Andy Whitcroft <apw@shadowen.org>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6310984694c8204ad16a2414cd58808fae68e02b
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun May 6 14:49:28 2007 -0700

    SLAB: don't allocate empty shared caches
    
    We can avoid allocating empty shared caches and avoid unecessary check of
    cache->limit.  We save some memory.  We avoid bringing into CPU cache
    unecessary cache lines.
    
    All accesses to l3->shared are already checking NULL pointers so this patch is
    safe.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 364fbb29a0105863d76a1f7bbc01783a4af30a75
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun May 6 14:49:27 2007 -0700

    SLAB: use num_possible_cpus() in enable_cpucache()
    
    The existing comment in mm/slab.c is *perfect*, so I reproduce it :
    
             /*
              * CPU bound tasks (e.g. network routing) can exhibit cpu bound
              * allocation behaviour: Most allocs on one cpu, most free operations
              * on another cpu. For these cases, an efficient object passing between
              * cpus is necessary. This is provided by a shared array. The array
              * replaces Bonwick's magazine layer.
              * On uniprocessor, it's functionally equivalent (but less efficient)
              * to a larger limit. Thus disabled by default.
              */
    
    As most shiped linux kernels are now compiled with CONFIG_SMP, there is no way
    a preprocessor #if can detect if the machine is UP or SMP. Better to use
    num_possible_cpus().
    
    This means on UP we allocate a 'size=0 shared array', to be more efficient.
    
    Another patch can later avoid the allocations of 'empty shared arrays', to
    save some memory.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Acked-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6ce745ed39d35f9d547d00d406db2be7c6c175b3
Author: Jan Kara <jack@suse.cz>
Date:   Sun May 6 14:49:26 2007 -0700

    readahead: code cleanup
    
    Rename file_ra_state.prev_page to prev_index and file_ra_state.offset to
    prev_offset.  Also update of prev_index in do_generic_mapping_read() is now
    moved close to the update of prev_offset.
    
    [wfg@mail.ustc.edu.cn: fix it]
    Signed-off-by: Jan Kara <jack@suse.cz>
    Cc: Nick Piggin <nickpiggin@yahoo.com.au>
    Cc: WU Fengguang <wfg@mail.ustc.edu.cn>
    Signed-off-by: Fengguang Wu <wfg@mail.ustc.edu.cn>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ec0f16372277052a29a6c17527c6cae5e898b3fd
Author: Jan Kara <jack@suse.cz>
Date:   Sun May 6 14:49:25 2007 -0700

    readahead: improve heuristic detecting sequential reads
    
    Introduce ra.offset and store in it an offset where the previous read
    ended.  This way we can detect whether reads are really sequential (and
    thus we should not mark the page as accessed repeatedly) or whether they
    are random and just happen to be in the same page (and the page should
    really be marked accessed again).
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Acked-by: Nick Piggin <nickpiggin@yahoo.com.au>
    Cc: WU Fengguang <wfg@mail.ustc.edu.cn>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b813e931b4c8235bb42e301096ea97dbdee3e8fe
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:49:24 2007 -0700

    smaps: add clear_refs file to clear reference
    
    Adds /proc/pid/clear_refs.  When any non-zero number is written to this file,
    pte_mkold() and ClearPageReferenced() is called for each pte and its
    corresponding page, respectively, in that task's VMAs.  This file is only
    writable by the user who owns the task.
    
    It is now possible to measure _approximately_ how much memory a task is using
    by clearing the reference bits with
    
    	echo 1 > /proc/pid/clear_refs
    
    and checking the reference count for each VMA from the /proc/pid/smaps output
    at a measured time interval.  For example, to observe the approximate change
    in memory footprint for a task, write a script that clears the references
    (echo 1 > /proc/pid/clear_refs), sleeps, and then greps for Pgs_Referenced and
    extracts the size in kB.  Add the sizes for each VMA together for the total
    referenced footprint.  Moments later, repeat the process and observe the
    difference.
    
    For example, using an efficient Mozilla:
    
    	accumulated time		referenced memory
    	----------------		-----------------
    		 0 s				 408 kB
    		 1 s				 408 kB
    		 2 s				 556 kB
    		 3 s				1028 kB
    		 4 s				 872 kB
    		 5 s				1956 kB
    		 6 s				 416 kB
    		 7 s				1560 kB
    		 8 s				2336 kB
    		 9 s				1044 kB
    		10 s				 416 kB
    
    This is a valuable tool to get an approximate measurement of the memory
    footprint for a task.
    
    Cc: Hugh Dickins <hugh@veritas.com>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    [akpm@linux-foundation.org: build fixes]
    [mpm@selenic.com: rename for_each_pmd]
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f79f177c25016647cc92ffac8afa7cb96ce47011
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:49:22 2007 -0700

    smaps: add pages referenced count to smaps
    
    Adds an additional unsigned long field to struct mem_size_stats called
    'referenced'.  For each pte walked in the smaps code, this field is
    incremented by PAGE_SIZE if it has pte-reference bits.
    
    An additional line was added to the /proc/pid/smaps output for each VMA to
    indicate how many pages within it are currently marked as referenced or
    accessed.
    
    Cc: Hugh Dickins <hugh@veritas.com>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 826fad1b93fdb4ffacfd9cd860f06140e852e377
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:49:21 2007 -0700

    smaps: extract pmd walker from smaps code
    
    Extracts the pmd walker from smaps-specific code in fs/proc/task_mmu.c.
    
    The new struct pmd_walker includes the struct vm_area_struct of the memory to
    walk over.  Iteration begins at the vma->vm_start and completes at
    vma->vm_end.  A pointer to another data structure may be stored in the private
    field such as struct mem_size_stats, which acts as the smaps accumulator.  For
    each pmd in the VMA, the action function is called with a pointer to its
    struct vm_area_struct, a pointer to the pmd_t, its start and end addresses,
    and the private field.
    
    The interface for walking pmd's in a VMA for fs/proc/task_mmu.c is now:
    
    	void for_each_pmd(struct vm_area_struct *vma,
    			  void (*action)(struct vm_area_struct *vma,
    					 pmd_t *pmd, unsigned long addr,
    					 unsigned long end,
    					 void *private),
    			  void *private);
    
    Since the pmd walker is now extracted from the smaps code, smaps_one_pmd() is
    invoked for each pmd in the VMA.  Its behavior and efficiency is identical to
    the existing implementation.
    
    Cc: Hugh Dickins <hugh@veritas.com>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0013572b2ae535bfd6314f22d9aef53725ea00d8
Author: Zachary Amsden <zach@vmware.com>
Date:   Sun May 6 14:49:20 2007 -0700

    i386: use pte_update_defer in ptep_test_and_clear_{dirty,young}
    
    If you actually clear the bit, you need to:
    
    +         pte_update_defer(vma->vm_mm, addr, ptep);
    
    The reason is, when updating PTEs, the hypervisor must be notified.  Using
    atomic operations to do this is fine for all hypervisors I am aware of.
    However, for hypervisors which shadow page tables, if these PTE
    modifications are not trapped, you need a post-modification call to fulfill
    the update of the shadow page table.
    
    Acked-by: Zachary Amsden <zach@vmware.com>
    Cc: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 10a8d6ae4b3182d6588a5809a8366343bc295c20
Author: David Rientjes <rientjes@google.com>
Date:   Sun May 6 14:49:19 2007 -0700

    i386: add ptep_test_and_clear_{dirty,young}
    
    Add ptep_test_and_clear_{dirty,young} to i386.  They advertise that they
    have it and there is at least one place where it needs to be called without
    the page table lock: to clear the accessed bit on write to
    /proc/pid/clear_refs.
    
    ptep_clear_flush_{dirty,young} are updated to use the new functions.  The
    overall net effect to current users of ptep_clear_flush_{dirty,young} is
    that we introduce an additional branch.
    
    Cc: Hugh Dickins <hugh@veritas.com>
    Cc: Ingo Molnar <mingo@redhat.com>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9490991482a2091a828d997adbc088e24c310a4d
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Sun May 6 14:49:17 2007 -0700

    Add unitialized_var() macro for suppressing gcc warnings
    
    Introduce a macro for suppressing gcc from generating a warning about a
    probable uninitialized state of a variable.
    
    Example:
    
    -	spinlock_t *ptl;
    +	spinlock_t *uninitialized_var(ptl);
    
    Not a happy solution, but those warnings are obnoxious.
    
    - Using the usual pointlessly-set-it-to-zero approach wastes several
      bytes of text.
    
    - Using a macro means we can (hopefully) do something else if gcc changes
      cause the `x = x' hack to stop working
    
    - Using a macro means that people who are worried about hiding true bugs
      can easily turn it off.
    
    Signed-off-by: Borislav Petkov <bbpetkov@yahoo.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a8127717cb24be7b8827a8d9e0ddbfde6b392146
Author: Nick Piggin <npiggin@suse.de>
Date:   Sun May 6 14:49:16 2007 -0700

    mm: simplify filemap_nopage
    
    Identical block is duplicated twice: contrary to the comment, we have been
    re-reading the page *twice* in filemap_nopage rather than once.
    
    If any retry logic or anything is needed, it belongs in lower levels anyway.
    Only retry once.  Linus agrees.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 14e072984179d3d421bf9ab75cc67e0961742841
Author: Andy Whitcroft <apw@shadowen.org>
Date:   Sun May 6 14:49:14 2007 -0700

    add pfn_valid_within helper for sub-MAX_ORDER hole detection
    
    Generally we work under the assumption that memory the mem_map array is
    contigious and valid out to MAX_ORDER_NR_PAGES block of pages, ie.  that if we
    have validated any page within this MAX_ORDER_NR_PAGES block we need not check
    any other.  This is not true when CONFIG_HOLES_IN_ZONE is set and we must
    check each and every reference we make from a pfn.
    
    Add a pfn_valid_within() helper which should be used when scanning pages
    within a MAX_ORDER_NR_PAGES block when we have already checked the validility
    of the block normally with pfn_valid().  This can then be optimised away when
    we do not have holes within a MAX_ORDER_NR_PAGES block of pages.
    
    Signed-off-by: Andy Whitcroft <apw@shadowen.org>
    Acked-by: Mel Gorman <mel@csn.ul.ie>
    Acked-by: Bob Picco <bob.picco@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ac267728f13c55017ed5ee243c9c3166e27ab929
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sun May 6 14:49:12 2007 -0700

    mm/slab.c: proper prototypes
    
    Add proper prototypes in include/linux/slab.h.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 411f0f3edc141a582190d3605cadd1d993abb6df
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Sun May 6 14:49:09 2007 -0700

    Introduce CONFIG_HAS_DMA
    
    Architectures that don't support DMA can say so by adding a config NO_DMA
    to their Kconfig file.  This will prevent compilation of some dma specific
    driver code.  Also dma-mapping-broken.h isn't needed anymore on at least
    s390.  This avoids compilation and linking of otherwise dead/broken code.
    
    Other architectures that include dma-mapping-broken.h are arm26, h8300,
    m68k, m68knommu and v850.  If these could be converted as well we could get
    rid of the header file.
    
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    "John W. Linville" <linville@tuxdriver.com>
    Cc: Kyle McMartin <kyle@parisc-linux.org>
    Cc: <James.Bottomley@SteelEye.com>
    Cc: Tejun Heo <htejun@gmail.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Cc: <geert@linux-m68k.org>
    Cc: <zippel@linux-m68k.org>
    Cc: <spyro@f2s.com>
    Cc: <uclinux-v850@lsi.nec.co.jp>
    Cc: <ysato@users.sourceforge.jp>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9a82782f8f58219d0c6dc5f0211ce301adf6c6f4
Author: Joshua N Pritikin <jpritikin@pobox.com>
Date:   Sun May 6 14:49:07 2007 -0700

    allow oom_adj of saintly processes
    
    If the badness of a process is zero then oom_adj>0 has no effect.  This
    patch makes sure that the oom_adj shift actually increases badness points
    appropriately.
    
    Signed-off-by: Joshua N. Pritikin <jpritikin@pobox.com>
    Cc: Andrea Arcangeli <andrea@novell.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3d67f2d7c0fb28b0eb6a6aa100b190526a971ad9
Author: Nick Piggin <npiggin@suse.de>
Date:   Sun May 6 14:49:05 2007 -0700

    fs: buffer don't PageUptodate without page locked
    
    __block_write_full_page is calling SetPageUptodate without the page locked.
    This is unusual, but not incorrect, as PG_writeback is still set.
    
    However the next patch will require that SetPageUptodate always be called with
    the page locked.  Simply don't bother setting the page uptodate in this case
    (it is unusual that the write path does such a thing anyway).  Instead just
    leave it to the read side to bring the page uptodate when it notices that all
    buffers are uptodate.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6fe6900e1e5b6fa9e5c59aa5061f244fe3f467e2
Author: Nick Piggin <npiggin@suse.de>
Date:   Sun May 6 14:49:04 2007 -0700

    mm: make read_cache_page synchronous
    
    Ensure pages are uptodate after returning from read_cache_page, which allows
    us to cut out most of the filesystem-internal PageUptodate calls.
    
    I didn't have a great look down the call chains, but this appears to fixes 7
    possible use-before uptodate in hfs, 2 in hfsplus, 1 in jfs, a few in
    ecryptfs, 1 in jffs2, and a possible cleared data overwritten with readpage in
    block2mtd.  All depending on whether the filler is async and/or can return
    with a !uptodate page.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Cc: Hugh Dickins <hugh@veritas.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 714b8171af9c930a59a0da8f6fe50518e70ab035
Author: Pekka Enberg <penberg@cs.helsinki.fi>
Date:   Sun May 6 14:49:03 2007 -0700

    slab: ensure cache_alloc_refill terminates
    
    If slab->inuse is corrupted, cache_alloc_refill can enter an infinite
    loop as detailed by Michael Richardson in the following post:
    <http://lkml.org/lkml/2007/2/16/292>. This adds a BUG_ON to catch
    those cases.
    
    Cc: Michael Richardson <mcr@sandelman.ca>
    Acked-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5f22df00a009e3f86301366c0ecddb63ebd22af9
Author: Nick Piggin <npiggin@suse.de>
Date:   Sun May 6 14:49:02 2007 -0700

    mm: remove gcc workaround
    
    Minimum gcc version is 3.2 now.  However, with likely profiling, even
    modern gcc versions cannot always eliminate the call.
    
    Replace the placeholder functions with the more conventional empty static
    inlines, which should be optimal for everyone.
    
    Signed-off-by: Nick Piggin <npiggin@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d2ba27e8007b35d24764c0877ab2428e00a5c5ab
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sun May 6 14:49:00 2007 -0700

    proper prototype for hugetlb_get_unmapped_area()
    
    Add a proper prototype for hugetlb_get_unmapped_area() in
    include/linux/hugetlb.h.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: William Irwin <wli@holomorphy.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1b4244647ceaad42ea6eb12899d58753d82b7727
Author: Christoph Lameter <clameter@sgi.com>
Date:   Sun May 6 14:48:59 2007 -0700

    Use ZVC counters to establish exact size of dirtyable pages
    
    We can use the global ZVC counters to establish the exact size of the LRU
    and the free pages.  This allows a more accurate determination of the dirty
    ratio.
    
    This patch will fix the broken ratio calculations if large amounts of
    memory are allocated to huge pags or other consumers that do not put the
    pages on to the LRU.
    
    Notes:
    - I did not add NR_SLAB_RECLAIMABLE to the calculation of the
      dirtyable pages. Those may be reclaimable but they are at this
      point not dirtyable. If NR_SLAB_RECLAIMABLE would be considered
      then a huge number of reclaimable pages would stop writeback
      from occurring.
    
    - This patch used to be in mm as the last one in a series of patches.
      It was removed when Linus updated the treatment of highmem because
      there was a conflict. I updated the patch to follow Linus' approach.
      This patch is neede to fulfill the claims made in the beginning of the
      patchset that is now in Linus' tree.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 476f35348eb8d2a827765992899fea78b7dcc46f
Author: Christoph Lameter <clameter@engr.sgi.com>
Date:   Sun May 6 14:48:58 2007 -0700

    Safer nr_node_ids and nr_node_ids determination and initial values
    
    The nr_cpu_ids value is currently only calculated in smp_init.  However, it
    may be needed before (SLUB needs it on kmem_cache_init!) and other kernel
    components may also want to allocate dynamically sized per cpu array before
    smp_init.  So move the determination of possible cpus into sched_init()
    where we already loop over all possible cpus early in boot.
    
    Also initialize both nr_node_ids and nr_cpu_ids with the highest value they
    could take.  If we have accidental users before these values are determined
    then the current valud of 0 may cause too small per cpu and per node arrays
    to be allocated.  If it is set to the maximum possible then we only waste
    some memory for early boot users.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit aee16b3cee2746880e40945a9b5bff4f309cfbc4
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Sun May 6 14:48:54 2007 -0700

    Add apply_to_page_range() which applies a function to a pte range
    
    Add a new mm function apply_to_page_range() which applies a given function to
    every pte in a given virtual address range in a given mm structure.  This is a
    generic alternative to cut-and-pasting the Linux idiomatic pagetable walking
    code in every place that a sequence of PTEs must be accessed.
    
    Although this interface is intended to be useful in a wide range of
    situations, it is currently used specifically by several Xen subsystems, for
    example: to ensure that pagetables have been allocated for a virtual address
    range, and to construct batched special pagetable update requests to map I/O
    memory (in ioremap()).
    
    [akpm@linux-foundation.org: fix warning, unpleasantly]
    Signed-off-by: Ian Pratt <ian.pratt@xensource.com>
    Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
    Signed-off-by: Chris Wright <chrisw@sous-sol.org>
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Cc: Christoph Lameter <clameter@sgi.com>
    Cc: Matt Mackall <mpm@waste.org>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit eb3a1e1145ca8f12372c7c96aa0702d86a9002a9
Author: Jiri Slaby <jirislaby@gmail.com>
Date:   Sun May 6 14:48:52 2007 -0700

    Serial: serial_core, use pr_debug
    
    serial_core, use pr_debug
    
    Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1733310bb762cb926669f2c10f6f8719bb20ed91
Author: Dave Jiang <djiang@mvista.com>
Date:   Sun May 6 14:48:50 2007 -0700

    MPSC serial driver tx locking
    
    The MPSC serial driver assumes that interrupt is always on to pick up the
    DMA transmit ops that aren't submitted while the DMA engine is active.
    However when irqs are off for a period of time such as operations under
    kernel crash dump console messages do not show up due to additional DMA ops
    are being dropped.  This makes console writes to process through all the tx
    DMAs queued up before submitting a new request.
    
    Also, the current locking mechanism does not protect the hardware registers
    and ring buffer when a printk is done during the serial write operations.
    The additional per port transmit lock provides a finer granular locking and
    protects registers being clobbered while printks are nested within UART
    writes.
    
    Signed-off-by: Dave Jiang <djiang@mvista.com>
    Signed-off-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit abb4a2390737867353ebafc012d45f2b03f3f944
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Sun May 6 14:48:49 2007 -0700

    serial: define FIXED_PORT flag for serial_core
    
    At present, the serial core always allows setserial in userspace to change the
    port address, irq and base clock of any serial port.  That makes sense for
    legacy ISA ports, but not for (say) embedded ns16550 compatible serial ports
    at peculiar addresses.  In these cases, the kernel code configuring the ports
    must know exactly where they are, and their clocking arrangements (which can
    be unusual on embedded boards).  It doesn't make sense for userspace to change
    these settings.
    
    Therefore, this patch defines a UPF_FIXED_PORT flag for the uart_port
    structure.  If this flag is set when the serial port is configured, any
    attempts to alter the port's type, io address, irq or base clock with
    setserial are ignored.
    
    In addition this patch uses the new flag for on-chip serial ports probed in
    arch/powerpc/kernel/legacy_serial.c, and for other hard-wired serial ports
    probed by drivers/serial/of_serial.c.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bd71c182d5a02337305fc381831c11029dd17d64
Author: Thomas Koeller <thomas.koeller@baslerweb.com>
Date:   Sun May 6 14:48:47 2007 -0700

    RM9000 serial driver
    
    Add support for the integrated serial ports of the MIPS RM9122 processor
    and its relatives.
    
    The patch also does some whitespace cleanup.
    
    [akpm@linux-foundation.org: cleanups]
    Signed-off-by: Thomas Koeller <thomas.koeller@baslerweb.com>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit beab697ab4b2962e3d741b476abe443baad0933d
Author: Marc St-Jean <stjeanma@pmc-sierra.com>
Date:   Sun May 6 14:48:45 2007 -0700

    serial driver PMC MSP71xx
    
    Serial driver patch for the PMC-Sierra MSP71xx devices.
    
    There are three different fixes:
    
    1 Fix for DesignWare APB THRE errata: In brief, this is a non-standard
      16550 in that the THRE interrupt will not re-assert itself simply by
      disabling and re-enabling the THRI bit in the IER, it is only re-enabled
      if a character is actually sent out.
    
      It appears that the "8250-uart-backup-timer.patch" in the "mm" tree
      also fixes it so we have dropped our initial workaround.  This patch now
      needs to be applied on top of that "mm" patch.
    
    2 Fix for Busy Detect on LCR write: The DesignWare APB UART has a feature
      which causes a new Busy Detect interrupt to be generated if it's busy
      when the LCR is written.  This fix saves the value of the LCR and
      rewrites it after clearing the interrupt.
    
    3 Workaround for interrupt/data concurrency issue: The SoC needs to
      ensure that writes that can cause interrupts to be cleared reach the UART
      before returning from the ISR.  This fix reads a non-destructive register
      on the UART so the read transaction completion ensures the previously
      queued write transaction has also completed.
    
    Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6179b5562d5d17c7c09b54cb11dd925ca308d7a9
Author: Bernhard Walle <bwalle@suse.de>
Date:   Sun May 6 14:48:44 2007 -0700

    add new_id to PCMCIA drivers
    
    PCI drivers have the new_id file in sysfs which allows new IDs to be added
    at runtime.  The advantage is to avoid re-compilation of a driver that
    works for a new device, but it's ID table doesn't contain the new device.
    This mechanism is only meant for testing, after the driver has been tested
    successfully, the ID should be added in source code so that new revisions
    of the kernel automatically detect the device.
    
    The implementation follows the PCI implementation. The interface is documented
    in Documentation/pcmcia/driver.txt. Computations should be done in userspace,
    so the sysfs string contains the raw structure members for matching.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Cc: Dominik Brodowski <linux@dominikbrodowski.net>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 02c83595b86480ee4d61665beb13f76685d40239
Author: David Brownell <david-b@pacbell.net>
Date:   Sun May 6 14:48:42 2007 -0700

    at91_cf, minor fix
    
    This is a minor correctness fix: since the at91_cf driver probe() routine
    is in the init section, it should use platform_driver_probe() instead of
    leaving that pointer around in the driver struct after init section
    removal.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Dominik Brodowski <linux@dominikbrodowski.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fd76bab2fa6d8f3ef6b326a4c6ae442fa21d30a4
Author: Pekka Enberg <penberg@cs.helsinki.fi>
Date:   Sun May 6 14:48:40 2007 -0700

    slab: introduce krealloc
    
    This introduce krealloc() that reallocates memory while keeping the contents
    unchanged.  The allocator avoids reallocation if the new size fits the
    currently used cache.  I also added a simple non-optimized version for
    mm/slob.c for compatibility.
    
    [akpm@linux-foundation.org: fix warnings]
    Acked-by: Josef Sipek <jsipek@fsl.cs.sunysb.edu>
    Acked-by: Matt Mackall <mpm@selenic.com>
    Acked-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e3ebadd95cb621e2c7436f3d3646447ac9d5c16d
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Mon May 7 08:44:24 2007 -0700

    Revert "[PATCH] x86: __pa and __pa_symbol address space separation"
    
    This was broken.  It adds complexity, for no good reason.  Rather than
    separate __pa() and __pa_symbol(), we should deprecate __pa_symbol(),
    and preferably __pa() too - and just use "virt_to_phys()" instead, which
    is more readable and has nicer semantics.
    
    However, right now, just undo the separation, and make __pa_symbol() be
    the exact same as __pa().  That fixes the bugs this patch introduced,
    and we can do the fairly obvious cleanups later.
    
    Do the new __phys_addr() function (which is now the actual workhorse for
    the unified __pa()/__pa_symbol()) as a real external function, that way
    all the potential issues with compile/link-time optimizations of
    constant symbol addresses go away, and we can also, if we choose to, add
    more sanity-checking of the argument.
    
    Cc: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Vivek Goyal <vgoyal@in.ibm.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0bd15c4b503b971024a3962b6a6b34c1af0628bf
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon May 7 12:13:36 2007 +1000

    [POWERPC] Fix build problem in ppc4xx_sgdma.c
    
    ppc4xx_sgdma.c is #including asm/dma-mapping.h directly, which should
    only ever be included via linux/dma-mapping.h.  asm/dma-mapping.h
    relies on an enum defined in linux/dma-mapping.h before its own
    include.  This fixes the problem.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2e1ee1f76684c5d4dd8e5a08cbf22d57f88769ed
Author: Domen Puncer <domen.puncer@telargo.com>
Date:   Mon May 7 01:38:52 2007 +1000

    [POWERPC] mpc52xx suspend to deep-sleep
    
    Implement deep-sleep on MPC52xx.
    SDRAM is put into self-refresh with help of SRAM code
    (alternatives would be code in FLASH, I-cache).
    Interrupt code must also not be in SDRAM, so put it
    in I-cache.
    MPC52xx core is static, so contents will remain intact even
    with clocks turned off.
    
    Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
    Acked-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a3481197783c187707090504062488862768260a
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Mon May 7 01:38:51 2007 +1000

    [POWERPC] Don't shutdown TX on mpc5200 serial port if it is a console
    
    If the serial port gets shut down, then console output stalls.  9 out
    of 10 kernel hackers agree, this is a bad thing.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3a5cc44268d9c3eee301f366801005e331b1e871
Author: Domen Puncer <domen.puncer@telargo.com>
Date:   Mon May 7 01:38:50 2007 +1000

    [POWERPC] Set efika's device_type to "soc"
    
    Device type should be "soc" (as in lite5200.dts), compatible is
    already set to "mpc5200".
    
    Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5cae84c9710cbb780bcbc96ac842a9e539f059ad
Author: Domen Puncer <domen.puncer@telargo.com>
Date:   Mon May 7 01:38:49 2007 +1000

    [POWERPC] lite5200(b) support for i2c
    
    Add fsl-i2c to mpc5200 i2c node in device tree, and enable FSL_SOC.
    
    Tested to work with built-in eeprom on lite5200b.
    
    Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0d0f4bc70e19f8782996793c3905bce14a7cabd7
Author: Domen Puncer <domen.puncer@telargo.com>
Date:   Mon May 7 01:38:48 2007 +1000

    [POWERPC] lite5200(b) DTS fixes
    
    Three trivial DTS fixes:
     -Mark Lite5200(b) boards as "mpc5200" compatible. On efika the
      firmware already does that.
     -Fix mscan interrupt.
     -Fix wakeup GPIO address.
    
    Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 29aa0289b895a0ad1641a90f94638c277f9cf8ec
Author: Sylvain Munaut <tnt@246tNt.com>
Date:   Mon May 7 01:38:47 2007 +1000

    [POWERPC] macintosh: Use common modalias generation for macio_sysfs
    
    There is now a common function to generate the modalias string,
    so use it. We just need to add the \n at the end.
    
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit de41189bf6838c1c885d360e5cdf7ec6b4d336d6
Author: Sylvain Munaut <tnt@246tNt.com>
Date:   Mon May 7 01:38:46 2007 +1000

    [POWERPC] Export of_device_get_modalias
    
    Apparently other parts of the kernel need to know the
    modalias internally (like the sysfs code in macintosh driver).
    
    To avoid consistency issues, we export this code and use it
    everywhere it's needed rather than repeat it ...
    
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d25a9d66e064e14aacc57c7fa95ca4b489df3df0
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Fri May 4 17:14:13 2007 +1000

    [POWERPC] Fix some missing build dependencies in arch/powerpc/boot
    
    This patch fixes a couple of missing dependencies in
    arch/powerpc/boot/Makefile.  First, it ensures that the zlib.h header
    is linked in before attempting to build gunzip_util.o, as it is,
    building gunzip_util.o usually works, but not always depending on make
    order.
    
    Second, it makes the final images which are built using a dts
    dependent on that dts, so the image will be correctly rebuilt if the
    dts changes.  This in turn requires fixing the definition of the dts
    variable.  CONFIG_DEVICE_TREE from Kconfig will have quotes around it,
    which don't matter when passing the variable to a shell, but which
    need to be removed when incorporating it into a filename for make's
    use.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0aeafb0cef401807fe7d2a50f298203659b668af
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Fri May 4 16:47:51 2007 +1000

    [POWERPC] Kill off the PTE_FMT macro
    
    32-bit powerpc uses a PTE_FMT macro to handle printk() formatting of
    PTE entries (which can vary in type and size).  Apparently there was a
    good reason for it once, but with current compilers it's simpler just
    to workaround the variation with a cast in the printk() itself
    (there's only one use).
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2abb7019e2877e7f9b1d2432f5a5c36caca5ed1c
Author: Olof Johansson <olof@lixom.net>
Date:   Fri May 4 14:39:21 2007 +1000

    [POWERPC] pasemi: Update ppc_proc_freq from cpufreq driver
    
    Update the global cpu speed variable according to current cpufreq speed,
    /proc/cpuinfo reports the actual speed.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 543b9fd3528f64c4b20439de0edb453764482de7
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu May 3 22:31:38 2007 +1000

    [POWERPC] powermac: Suspend to disk on G5
    
    Powermac G5 suspend to disk implementation.  The code is platform
    agnostic but only tested on powermac, no other 64-bit powerpc
    machines.
    
    Because nvidiafb still breaks suspend I have marked it EXPERIMENTAL on
    powermac and because I can't test it and some lowlevel code will need
    changes it is BROKEN on all other 64-bit platforms.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7e11580b362fc64693de7ad5c11fbf3d1d9d0e50
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu May 3 22:28:32 2007 +1000

    [POWERPC] DART iommu suspend
    
    This implements save and restore hooks for IOMMUs and implements
    it the DART iommu.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 55b61fec22caa3e7872caea6c4100fc75cb8f49b
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu May 3 17:26:52 2007 +1000

    [POWERPC] Rename device_is_compatible to of_device_is_compatible
    
    for consistency with other Open Firmware interfaces (and Sparc).
    
    This is just a straight replacement.
    
    This leaves the compatibility define in place.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d9333afd6a714760c13f76ba275a32ec7bd979c1
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu May 3 06:33:51 2007 +1000

    [POWERPC] powermac: Support G5 CPU hotplug
    
    This allows "hotplugging" of CPUs on G5 machines.  CPUs that are
    disabled are put into an idle loop with the decrementer frequency set
    to minimum.  To wake them up again we kick them just like when bringing
    them up.  To stop those CPUs from messing with any global state we stop
    them from entering the timer interrupt.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ac18c673e7fa71f62ce613edfe6634edb99f968b
Author: Scott Wood <scottwood@freescale.com>
Date:   Thu May 3 04:00:00 2007 +1000

    [POWERPC] bootwrapper: Only build cuImage if CONFIG_DEVICE_TREE is non-empty
    
    This allows the zImage target to once again be used to build
    all supported image types, rather than requiring an explicit
    "make uImage" to avoid failing to create an unneeded cuImage.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 44755d11a3c054adf7eb974a4720936563cf7dcf
Author: will schmidt <will_schmidt@vnet.ibm.com>
Date:   Thu May 3 03:12:34 2007 +1000

    [POWERPC] Add smp_call_function_map and smp_call_function_single
    
    Add a new function named smp_call_function_single().  This matches a generic
    prototype from include/linux/smp.h.
    
    Add a function smp_call_function_map().  This is, for the most part, a rename
    of smp_call_function, with some added cpumask support.  smp_call_function and
    smp_call_function_single call into smp_call_function_map.
    
    Lightly tested on 970mp (blade), power4 and power5.
    
    Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com>
    cc: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e9e77ce8718def7838626aa52bed02fe1b9837b9
Author: Kevin Corry <kevcorry@us.ibm.com>
Date:   Thu May 3 03:11:49 2007 +1000

    [POWERPC] Change topology_init() to a subsys_initcall
    
    Change the powerpc version of topology_init() from an __initcall to
    a subsys_initcall to match all other architectures.
    
    Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3669e930481d6dd510718279cd4bacb15ca3ae91
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Wed May 2 16:33:41 2007 +1000

    [POWERPC] MPIC sys_device & suspend/resume
    
    This adds mpic to the system devices and implements suspend
    and resume for them.  This is necessary to get interrupts for
    modules back to where they were before a suspend to disk.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 71bf08b6c083df4ee97874d895f911529f4150dd
Author: Luke Browning <lukebr@linux.vnet.ibm.com>
Date:   Thu May 3 00:19:11 2007 +1000

    [POWERPC] 64K page support for kexec
    
    This fixes a couple of kexec problems related to 64K page
    support in the kernel.  kexec issues a tlbie for each pte.  The
    parameters for the tlbie are the page size and the virtual address.
    Support was missing for the computation of these two parameters
    for 64K pages.  This adds that support.
    
    Signed-off-by: Luke Browning <lukebrowning@us.ibm.com>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Acked-by: Olof Johansson <olof@lixom.net>
    Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cf4328cd949c2086091c62c5685f1580fe9b55e4
Author: Ivo van Doorn <IvDoorn@gmail.com>
Date:   Mon May 7 00:34:20 2007 -0700

    [NET]: rfkill: add support for input key to control wireless radio
    
    The RF kill patch that provides infrastructure for implementing
    switches controlling radio states on various network and other cards.
    
    [dtor@insightbb.com: address review comments]
    [akpm@linux-foundation.org: cleanups, build fixes]
    
    Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2396a22e0989df6038996506bfbf7a57f116c299
Author: Josef 'Jeff' Sipek <jsipek@cs.sunysb.edu>
Date:   Mon May 7 00:33:18 2007 -0700

    [NET] net/core: Fix error handling
    
    Upon failure to register "ptype" procfs entry, "softnet_stat" was not
    removed, and an incorrect attempt was made to remove the "ptype" entry.
    
    Signed-off-by: Josef 'Jeff' Sipek <jsipek@cs.sunysb.edu>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 823036ed3291e30f32a905c94db821cd75524b59
Author: Michael Chan <mchan@broadcom.com>
Date:   Mon May 7 00:26:30 2007 -0700

    [TG3]: Update version and reldate.
    
    Update version to 3.76.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c04cb34725fdcf5fdb4135d8fdfaf6f318f10e99
Author: Michael Chan <mchan@broadcom.com>
Date:   Mon May 7 00:26:15 2007 -0700

    [TG3]: Eliminate spurious interrupts.
    
    Spurious interrupts are often encountered especially on systems
    using the 8259 PIC mode.  This is because the I/O write to deassert
    the interrupt is posted and won't get to the chip immediately.  As
    a result, the IRQ may remain asserted after the IRQ handler exits,
    causing spurious interrupts.
    
    Flush the interrupt mailbox in non-MSI handlers to de-assert the
    IRQ immediately.  This seems to be the most straight forward approach
    after discussion with Jeff Garzik and David Miller.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8ed5d97e5e0be0fb1aebad16f4c464613a0e472d
Author: Matt Carlson <mcarlson@broadcom.com>
Date:   Mon May 7 00:25:49 2007 -0700

    [TG3]: Add ASPM workaround.
    
    This patch adds workaround to fix performance problems caused by slow
    PCIE L1->L0 transitions on ICH8 platforms.
    
    Changed all magic numbers to constants as suggested by Jeff Garzik.
    
    Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 90a660a4546d6ba5ca5f3a23d5cc599db2b41e08
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 00:14:13 2007 -0700

    [SERIAL] sunsu: Fix section mismatch warnings.
    
    Mark sunsu_console_setup() as __init and rename 'sunsu_cons'
    to 'sunsu_console' so that it matches modpost.c's whitelist.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e7f11aeed02767541020984f72f823757c58e48e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 00:02:46 2007 -0700

    [SPARC64]: pgtable_cache_init() should be __init.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c35a376d6089ab0ece2913959c8363aad76eb820
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 00:02:24 2007 -0700

    [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/prom.c
    
    The IRQ translation init routines should all be __init.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a6009dda97776d50166e7f1e378cf553a1c20309
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 00:01:38 2007 -0700

    [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/pci.c
    
    apb_calc_first_last(), apb_fake_ranges(), pci_of_scan_bus(),
    of_scan_pci_bridge(), pci_of_scan_bus(), and pci_scan_one_pbm()
    should all be __devinit.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 23abc9ec6a4fbcb3da5475f9f4c25415c466de08
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon May 7 00:00:37 2007 -0700

    [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/console.c
    
    probe_other_fhcs() and central_probe() should be __init
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6a5b518f222449e707e553573f937faf6e57f03d
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun May 6 23:54:25 2007 -0700

    [MM]: sparse_init() should be __init.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7db00552d937e4c0825895734ba5fe257dfe8ced
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun May 6 22:47:14 2007 -0700

    [SPARC64]: Update defconfig.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 71227521459872c321e7a581e82723bbc1aa33e1
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun May 6 22:45:50 2007 -0700

    [VIDEO]: Add Sun XVR-2500 framebuffer driver.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 453e93b348ebabc517149b9d9a05042a3c1ccc82
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun May 6 22:45:08 2007 -0700

    [VIDEO]: Add Sun XVR-500 framebuffer driver.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 861fe90656b8e20d750d73c57088dc52d316ce7b
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed May 2 17:31:36 2007 -0700

    [SPARC64]: SUN4U PCI-E controller support.
    
    Some minor refactoring in the generic code was necessary for
    this:
    
    1) This controller requires 8-byte access to the interrupt map
       and clear register.  They are 64-bits on all the other
       SBUS and PCI controllers anyways, so this was easy to cure.
    
    2) The IMAP register has a different layout and some bits that we
       need to preserve, so use a read/modify/write when making
       changes to the IMAP register in generic code.
    
    3) Flushing the entire IOMMU TLB is best done with a single write
       to a register on this PCI controller, add a iommu->iommu_flushinv
       for this.
    
    Still lacks MSI support, that will come later.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4cad69174f385c183b2bcb369fb4304d8624ab96
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Apr 30 17:59:50 2007 -0700

    [SPARC]: Fix comment typo in smp4m_blackbox_current().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6025dfe5b2598056cd763a2b10ca7e7faffb2e16
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun Apr 29 16:12:29 2007 -0700

    [SCSI] SUNESP: sun_esp.c needs linux/delay.h
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8d1cc86a6278687efbab7b8c294ab01efe4d4231
Author: Roland Dreier <rolandd@cisco.com>
Date:   Sun May 6 21:05:32 2007 -0700

    IPoIB: Convert to NAPI
    
    Convert the IP-over-InfiniBand network device driver over to using
    NAPI to handle completions for the main CQ.  This covers all receives
    as well as datagram mode sends; send completions for connected mode
    connections are still handled from interrupt context.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit ed23a72778f3dbd465e55b06fe31629e7e1dd2f3
Author: Roland Dreier <rolandd@cisco.com>
Date:   Sun May 6 21:02:48 2007 -0700

    IB: Return "maybe missed event" hint from ib_req_notify_cq()
    
    The semantics defined by the InfiniBand specification say that
    completion events are only generated when a completions is added to a
    completion queue (CQ) after completion notification is requested.  In
    other words, this means that the following race is possible:
    
    	while (CQ is not empty)
    		ib_poll_cq(CQ);
    	// new completion is added after while loop is exited
    	ib_req_notify_cq(CQ);
    	// no event is generated for the existing completion
    
    To close this race, the IB spec recommends doing another poll of the
    CQ after requesting notification.
    
    However, it is not always possible to arrange code this way (for
    example, we have found that NAPI for IPoIB cannot poll after
    requesting notification).  Also, some hardware (eg Mellanox HCAs)
    actually will generate an event for completions added before the call
    to ib_req_notify_cq() -- which is allowed by the spec, since there's
    no way for any upper-layer consumer to know exactly when a completion
    was really added -- so the extra poll of the CQ is just a waste.
    
    Motivated by this, we add a new flag "IB_CQ_REPORT_MISSED_EVENTS" for
    ib_req_notify_cq() so that it can return a hint about whether the a
    completion may have been added before the request for notification.
    The return value of ib_req_notify_cq() is extended so:
    
    	 < 0	means an error occurred while requesting notification
    	== 0	means notification was requested successfully, and if
    		IB_CQ_REPORT_MISSED_EVENTS was passed in, then no
    		events were missed and it is safe to wait for another
    		event.
    	 > 0	is only returned if IB_CQ_REPORT_MISSED_EVENTS was
    		passed in.  It means that the consumer must poll the
    		CQ again to make sure it is empty to avoid the race
    		described above.
    
    We add a flag to enable this behavior rather than turning it on
    unconditionally, because checking for missed events may incur
    significant overhead for some low-level drivers, and consumers that
    don't care about the results of this test shouldn't be forced to pay
    for the test.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit f4fd0b224d60044d2da5ca02f8f2b5150c1d8731
Author: Michael S. Tsirkin <mst@dev.mellanox.co.il>
Date:   Thu May 3 13:48:47 2007 +0300

    IB: Add CQ comp_vector support
    
    Add a num_comp_vectors member to struct ib_device and extend
    ib_create_cq() to pass in a comp_vector parameter -- this parallels
    the userspace libibverbs API.  Update all hardware drivers to set
    num_comp_vectors to 1 and have all ULPs pass 0 for the comp_vector
    value.  Pass the value of num_comp_vectors to userspace rather than
    hard-coding a value of 1.
    
    We want multiple CQ event vector support (via MSI-X or similar for
    adapters that can generate multiple interrupts), but it's not clear
    how many vectors we want, or how we want to deal with policy issues
    such as how to decide which vector to use or how to set up interrupt
    affinity.  This patch is useful for experimenting, since no core
    changes will be necessary when updating a driver to support multiple
    vectors, and we know that we want to make at least these changes
    anyway.
    
    Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 154257f3626ea6dd96781fac0896c3f27fe2b0a1
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu May 3 12:43:03 2007 -0700

    IB/ipath: Fix a race condition when generating ACKs
    
    Fix a problem where simple ACKs can be sent ahead of RDMA read
    responses thus implicitly NAKing the RDMA read.
    
    Signed-off-by: Ralph Campbell <ralph.cambpell@qlogic.com>
    Signed-off-by: Robert Walsh <robert.walsh@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 6ed89b9574776d4178f1ad754d20e4f1e5a4b6c8
Author: Ralph Campbell <ralphc@pathscale.com>
Date:   Thu May 3 12:40:51 2007 -0700

    IB/ipath: Fix two more spin lock problems
    
    Fix a missing unlock in ipath_rc_rcv_resp() and remove an extra unlock
    from ipath_rc_rcv_error().
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 1a70a05d9d2b30db3e56f8cfbebb175663b41bad
Author: Roland Dreier <rolandd@cisco.com>
Date:   Sun May 6 21:18:11 2007 -0700

    IB/fmr_pool: Add prefix to all printks
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit b7f008fdc92e498af34671048556fd17ddfe9be9
Author: Roland Dreier <rolandd@cisco.com>
Date:   Sun May 6 21:18:11 2007 -0700

    IB/srp: Set proc_name
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 3633b3d096286cf21bc07b16fa6265fb006d0844
Author: Ishai Rabinovitz <ishai@mellanox.co.il>
Date:   Sun May 6 21:18:11 2007 -0700

    IB/srp: Add orig_dgid sysfs attribute to scsi_host
    
    Add an orig_dgid attribute in sysfs for SRP scsi_hosts, so that
    userspace can tell what the original dgid value written to the
    add_target file was, even if the connection is redirected to a
    different port while connecting.
    
    Signed-off-by: Ishai Rabinovitz <ishai@mellanox.co.il>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit d6ef7d68f6f51c5b9de01c542dab8b90067a9c27
Author: Michael S. Tsirkin <mst@dev.mellanox.co.il>
Date:   Wed May 2 15:31:12 2007 +0300

    IPoIB/cm: Don't crash if remote side uses one QP for both directions
    
    The IPoIB CM spec allows the use of a single connection in both
    active->passive and passive->active directions.  The current Linux
    code uses one connection for both directions, but if another node only
    uses one connection for both directions, we oops when we try to look
    up the passive connection.  Fix by checking that qp_context is
    non-NULL before dereferencing it.
    
    Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>

commit aff9e39d97585486764572ab2f3bf5dfce18c660
Author: Steve Wise <swise@opengridcomputing.com>
Date:   Thu Apr 26 15:21:20 2007 -0500

    RDMA/cxgb3: Support for new abort logic
    
    The HW now posts 2 ABORT_RPL and/or PEER_ABORT_REQ messages.  We need
    to handle them by silenty dropping the 1st but mark that we're ready
    for the final message.  This plugs some close races between the uP and
    HW.  Also update the minimum required firmware version.
    
    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 39374aadcd0159b4744ab456f4efa100bea84bd4
Author: Ryusuke Sakato <sakato.ryusuke@renesas.com>
Date:   Mon May 7 10:48:56 2007 +0900

    sh: R7785RP board updates.
    
    Some fixups for the R7785RP board. Gets iVDR working.
    
    Signed-off-by: Ryusuke Sakato <sakato.ryusuke@renesas.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 9c37dc633016e9ebdc39adba0737b390e0de1507
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Tue May 1 16:35:05 2007 +0900

    sh: Update r7780rp defconfig.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 3a2e117e220f000f95187ea1e1bbe83b0ed5fdfb
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Tue May 1 16:33:10 2007 +0900

    sh: Add die chain notifiers.
    
    Add the atomic die chains in, kprobes needs these.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 3dde7a3c74bcc25c6fc31b836fec8c91fb0b2b8f
Author: Kristoffer Ericson <kristoffer.ericson@gmail.com>
Date:   Tue May 1 12:21:26 2007 +0900

    sh: Fix APM emulation on hp6xx.
    
    With the shared APM emulation code being introduced, hp6xx was missed
    in the conversion. Get it building again.
    
    Signed-off-by: Kristoffer Ericson <kristoffer.ericson@gmail.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 70fe4d87bf72053f78cf3d2e6cefa5d51a2c30af
Author: Takashi YOSHII <takashi.yoshii.ze@hitachi.com>
Date:   Tue May 1 12:19:33 2007 +0900

    sh: Wire up more IRQs for SH7709.
    
    hp6xx requires some additional IRQs that aren't currently enabled in
    the SH7709 setup code. Wire them up.
    
    Signed-off-by: Takashi YOSHII <takashi.yoshii.ze@hitachi.com>
    Signed-off-by: Kristoffer Ericson <kristoffer.ericson@gmail.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 6865f0ea6ad91fec3ae7831c49d48b5a7db4b428
Author: Ryusuke Sakato <sakato.ryusuke@renesas.com>
Date:   Tue May 1 09:45:29 2007 +0900

    sh: Solution Engine 7722 board support.
    
    This adds more full-featured support for the SH7722 Solution Engine.
    Previously this was using the generic board, and lacked most of the
    peripheral support.
    
    Signed-off-by: Ryusuke Sakato <sakato.ryusuke@renesas.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 6b817c03489083a7457cda16b953a214dcef8d64
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Tue May 1 09:40:23 2007 +0900

    sh: Fix r7780rp build.
    
    With the addition of the R7780MP and R7785RP, the R7780RP build
    ended up breaking. Trivial compile fix.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 4d5ade5b29c618e97a8988efb6967cb4dd0e2183
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Fri Apr 27 11:25:57 2007 +0900

    sh: kdump support.
    
    This adds support for kexec based crash dumps.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit db62e5bd297d1f325811c5495ad23de36db0fdd4
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Apr 26 12:17:20 2007 +0900

    sh: Move clock reporting to its own proc entry.
    
    Previously this was done in cpuinfo, but with the number of clocks
    growing, it makes more sense to place this in a different proc entry.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 2a8ff4596cde3ec2a51980288ebb28a0d196d19a
Author: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
Date:   Thu Apr 26 11:51:00 2007 +0900

    sh: Solution Engine SH7705 board and CPU updates.
    
    This fixes up SH7705 CPU support and the SE7705 board
    for some of the recent changes.
    
    Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 005a336e71e9e3ea356f9afca5d66318d6901319
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Apr 26 11:45:32 2007 +0900

    serial: sh-sci: Fix module clock refcount for serial console.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 1534a3b3dc1cbab006f0add253be1b095d738b82
Author: dmitry pervushin <dimka@nomadgs.com>
Date:   Tue Apr 24 13:41:12 2007 +0900

    serial: sh-sci: Fix module clock refcounting.
    
    This adds the enable/disable hooks for the port clock to sh-sci.
    
    Signed-off-by: dmitry pervushin <dimka@nomadgs.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 1929cb340b74904c130fdf3de3fe5bbedb68a5aa
Author: dmitry pervushin <dimka@nomadgs.com>
Date:   Tue Apr 24 13:39:09 2007 +0900

    sh: SH7722 clock framework support.
    
    This adds support for the SH7722 (MobileR) to the clock framework.
    
    Signed-off-by: dmitry pervushin <dimka@nomadgs.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 34a780a0afeb8f99c9ca9934f4cc0822541769c6
Author: Kristoffer Ericson <Kristoffer_e1@hotmail.com>
Date:   Tue Apr 10 07:45:08 2007 +0900

    sh: hp6xx pata_platform support.
    
    Drop the hd64461 I/O ops and wire up pata_platform for MMIO.
    
    Signed-off-by: Kristoffer Ericson <Kristoffer_e1@hotmail.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit dd12666278daa0008ac439603c8d3037bc213556
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Tue Apr 10 07:38:10 2007 +0900

    sh: Obey CONFIG_HZ for HZ definition.
    
    This wasn't being set before, so now it's set for when it makes sense.
    The shwdt case still requires HZ to be fixed at 1000 for the WOVF period,
    so this is still preserved.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 760bcb1deec13c50e20399c84cb6a8ea41cc2820
Author: SUGIOKA Toshinobu <sugioka@itonet.co.jp>
Date:   Fri Mar 30 14:51:44 2007 +0900

    sh: Fix fstatat64() syscall.
    
    Signed-off-by: SUGIOKA Toshinobu <sugioka@itonet.co.jp>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit b7aee517c8302d651ff057fdcebee3c1f53c3b2e
Author: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
Date:   Fri Mar 30 14:49:21 2007 +0900

    sh: se7780 PCI support.
    
    Add support for the SH7780 PCIC on the Solution Engine 7780,
    missing from the previous board-support patch.
    
    Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit b75762302e144b73f12b72c59b99401d036680aa
Author: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
Date:   Thu Mar 29 00:07:35 2007 +0900

    sh: SH7780 Solution Engine board support.
    
    This adds support for the SH7780-based Solution Engine reference board.
    
    Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit cd6c7ea234dc8a8607283e056d8010b2bd3c6369
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Mar 29 00:04:39 2007 +0900

    sh: Add a dummy SH-4 PCIC fixup.
    
    By default we don't have anything to fix up for the SH-4 PCIC, boards can
    overload this as necessary.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 0264f1603904dbee3196abc748a53fb0b23b8046
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 28 23:36:03 2007 +0900

    sh: Tidy up L-BOX area5 addresses.
    
    L-BOX can use the normal PA_AREA5_IO, there's no reason for it to
    reproduce it.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 652b9672cfc4000382f0f3f41907d9d32e5bd327
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 28 17:20:47 2007 +0900

    sh: Add defconfig for se7722.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit cdf50b23bf83624708d0abbb381a1c1694e42e19
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 28 17:14:45 2007 +0900

    sh: Kill off udivdi3 div64_32 wrapping.
    
    Previously we've been handling udivdi3 references and wrapping
    them in to div64_32() automatically. This doesn't get a lot of
    use, however, and as akpm noted in the recent thread on l-k:
    
    	http://lkml.org/lkml/2007/2/27/241
    
    we're better off simply ripping it out and going the do_div()
    route if there happen to be any places that need it.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 01066625e9ae39742c92e21163f7f2a818e02762
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 28 16:38:13 2007 +0900

    sh: bootmem tidying for discontig/sparsemem preparation.
    
    This reworks some of the node 0 bootmem initialization in
    preparation for discontigmem and sparsemem support.
    
    ARCH_POPULATES_NODE_MAP is switched to as a result of this.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 759ab068c4d4216c4ad247bfa851601dfb6500dc
Author: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
Date:   Wed Mar 28 15:04:05 2007 +0900

    sh: Add defconfig for se7712.
    
    Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.zh@hitachi.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 9465a54fa4a9da628091c372baa84120f8304587
Author: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Date:   Tue Mar 27 18:13:51 2007 +0900

    sh: MS7712SE01 board support.
    
    Support the SH7712 (SH3-DSP) Solution Engine reference board.
    
    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit c86c5a910451dd5a30e62a9e36d8e9b3c7a0c1d1
Author: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Date:   Mon Mar 26 14:27:43 2007 +0900

    sh: L-BOX RE2 support.
    
    This adds support for the L-BOX RE2 router.
    
    	http://www.nttcom.co.jp/l-box/
    
    L-BOX RE2 is a SH7751R-based router. It has CF, Cardbus, serial,
    and LAN x2. This is one of the very few SH boards that a general
    person can obtain now.
    
    The L-BOX shipped with a 2.4.28 kernel, this is a rewritten patch
    adding it to current git.
    
    Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 00e8c494a1603eac0a2cae9836e624a752ad45b1
Author: kogiidena <kogiidena@eggplant.ddo.jp>
Date:   Mon Mar 19 16:24:12 2007 +0900

    sh: landisk updates.
    
    Updates for the landisk board:
    
    	- The push_switch framework was used.
    	- landisk_pwb.c was divided into psw.c and gio.c.
    	- pata_platform was supported in USL-5P.
    	- irq.c was rewritten.
    	- io.c was replaced with generic I/O routines.
    
    Signed-off-by: kogiidena <kogiidena@eggplant.ddo.jp>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 5753171b8234b98d35d559abc0d88b9e4b520b14
Author: Kristoffer Ericson <Kristoffer_e1@hotmail.com>
Date:   Mon Mar 19 16:12:13 2007 +0900

    sh: hp6xx driver compile fixes.
    
    Trivial compilation fixes for the hp6xx drivers.
    
    Signed-off-by: Kristoffer Ericson <Kristoffer_e1@hotmail.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit d29c91c70bc7790b112119135fae7690cbf17577
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 14 14:25:49 2007 +0900

    doc: Update sysrq doc for sh kgdb trigger.
    
    sh uses the same sysrq trigger as ppc, update the documentation to
    reflect that.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 8248daac6b9cde7748a659dcabea6584d62a9fd8
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Wed Mar 14 14:23:22 2007 +0900

    serial: sh-sci: Kill off breakpoint in break IRQ.
    
    With the GDB stub being entered via a special sysrq trigger,
    we don't want to hit it directly from sci_br_interrupt().
    Without this, there is access to the other sysrq triggers when
    kgdb is enabled.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit f6072896e3f4c577db7e3a06105ebdfd52d7e7c9
Author: Takashi YOSHII <takashi.yoshii.ze@hitachi.com>
Date:   Mon Mar 12 15:33:22 2007 +0900

    sh: heartbeat double 0 fix.
    
    This implements stricter and more compliant knightrider strobing in the
    heartbeat handler. While there still seems to be some debate as to
    whether the double 0 is "more" correct or not, this updated version
    appears to have general consensus. Fixes a long-term "bug".
    
    Signed-off-by: Takashi YOSHII <takashi.yoshii.ze@hitachi.com>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit f987fc880d191bf2ef66ac17e9d524aee6afa02e
Author: Nobuhiro Iwamatsu <hemamu@t-base.ne.jp>
Date:   Mon Mar 12 15:12:27 2007 +0900

    sh: pata_platform pcmcia support for SolutionEngine boards.
    
    This enables pata_platform support for the PCMCIA slot on the
    SolutionEngine.
    
    Signed-off-by: Nobuhiro Iwamatsu <hemamu@t-base.ne.jp>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 32351a28a7e1f2c68afbe559dd35e1ad0301be6d
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Mon Mar 12 14:38:59 2007 +0900

    sh: Add SH7785 Highlander board support (R7785RP).
    
    This adds preliminary support for the SH7785-based Highlander board.
    Some of the Highlander support code is reordered so that most of it
    can be reused directly.
    
    This also plugs in missing SH7785 checks in the places that need it,
    as this is the first board to support the CPU.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit be782df54c51b50dd4dbc363a5a5afa04565fc60
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Mon Mar 12 14:09:35 2007 +0900

    sh: NR_IRQS consolidation.
    
    Each board sets the total number of IRQs that it's interested in via
    the machvec. Previously we cared about the off vs on-chip IRQ range,
    but any code relying on that is long dead. Set NR_IRQS to something
    sensible given the vector range, and allow boards to cap it if they
    really care.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit fa69151173b1fc6fa3ced0edd5c2ea83b5d32bc1
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Mar 8 19:41:21 2007 +0900

    sh: generic BUG() support.
    
    Wire up GENERIC_BUG for SH. This moves off of the special bug
    frame and on to the generic struct bug_entry. Roughly the same
    semantics are retained, and we can kill off some of the verbose
    BUG() reporting code.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 45ed285b54930767937deb0eaf718b1d08c3c475
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Mar 8 18:12:17 2007 +0900

    sh: speculative execution support for SH7780.
    
    SH7780 has a speculative execution mode where it can speculatively
    perform an instruction fetch for subroutine returns, this allows it
    to be enabled. There are some various pitfalls associated with this
    mode, so it's left as depending on CONFIG_EXPERIMENTAL and not
    enabled by default.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit fc31b80957a14a60513d953cc67a55519a2b09c7
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Mar 8 17:33:24 2007 +0900

    sh: Rip out broken kgdb thread support.
    
    The kgdb thread support is woefully out of date (it predates
    the pidhash), and needs a complete rewrite before it's useful
    again. Just rip it out entirely.
    
    Updating the unified kgdb stub is a more worthwhile endeavour
    for anyone that happens to be interested in this, at present
    it's just limping along.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit fa5da2f7bdcf885efe65a37df13907c7d72296f6
Author: Paul Mundt <lethal@linux-sh.org>
Date:   Thu Mar 8 17:27:37 2007 +0900

    sh: Bring kgdb back from the dead.
    
    This code has suffered quite a bit of bitrot, do some basic
    tidying to get it to a reasonably functional state again.
    This gets the basic support and the console working again.
    
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>

commit 586759f03e2e9031ac5589912a51a909ed53c30a
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 14 16:37:25 2006 -0500

    gfs2: nfs lock support for gfs2
    
    Add NFS lock support to GFS2.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
    Acked-by: Steven Whitehouse <swhiteho@redhat.com>

commit 1a8322b2b02071b0c7ac37a28357b93e6362f13e
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:27:06 2006 -0500

    lockd: add code to handle deferred lock requests
    
    Rewrite nlmsvc_lock() to use the asynchronous interface.
    
    As with testlock, we answer nlm requests in nlmsvc_lock by first looking up
    the block and then using the results we find in the block if B_QUEUED is
    set, and calling vfs_lock_file() otherwise.
    
    If this a new lock request and we get -EINPROGRESS return on a non-blocking
    request then we defer the request.
    
    Also modify nlmsvc_unlock() to call the filesystem method if appropriate.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit f812048020282fdfa9b72a6cf539c33b6df1fd07
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Dec 5 23:48:10 2006 -0500

    lockd: always preallocate block in nlmsvc_lock()
    
    Normally we could skip ever having to allocate a block in the case where
    the client asks for a non-blocking lock, or asks for a blocking lock that
    succeeds immediately.
    
    However we're going to want to always look up a block first in order to
    check whether we're revisiting a deferred lock call, and to be prepared to
    handle the case where the filesystem returns -EINPROGRESS--in that case we
    want to make sure the lock we've given the filesystem is the one embedded
    in the block that we'll use to track the deferred request.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 5ea0d75037b93baa453b4d326c6319968fe91cea
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:27:06 2006 -0500

    lockd: handle test_lock deferrals
    
    Rewrite nlmsvc_testlock() to use the new asynchronous interface: instead of
    immediately doing a posix_test_lock(), we first look for a matching block.
    If the subsequent test_lock returns anything other than -EINPROGRESS, we
    then remove the block we've found and return the results.
    
    If it returns -EINPROGRESS, then we defer the lock request.
    
    In the case where the block we find in the first step has B_QUEUED set,
    we bypass the vfs_test_lock entirely, instead using the block to decide how
    to respond:
    	with nlm_lck_denied if B_TIMED_OUT is set.
    	with nlm_granted if B_GOT_CALLBACK is set.
    	by dropping if neither B_TIMED_OUT nor B_GOT_CALLBACK is set
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 85f3f1b3f7a6197b51a2ab98d927517df730214c
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:27:06 2006 -0500

    lockd: pass cookie in nlmsvc_testlock
    
    Change NLM internal interface to pass more information for test lock; we
    need this to make sure the cookie information is pushed down to the place
    where we do request deferral, which is handled for testlock by the
    following patch.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 0e4ac9d93515b27fd7635332d73eae3192ed5d4e
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:26:51 2006 -0500

    lockd: handle fl_grant callbacks
    
    Add code to handle file system callback when the lock is finally granted.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 2b36f412ab6f2e5b64af9832b20eb7ef67d025b4
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:26:47 2006 -0500

    lockd: save lock state on deferral
    
    We need to keep some state for a pending asynchronous lock request, so this
    patch adds that state to struct nlm_block.
    
    This also adds a function which defers the request, by calling
    rqstp->rq_chandle.defer and storing the resulting deferred request in a
    nlm_block structure which we insert into lockd's global block list.  That
    new function isn't called yet, so it's dead code until a later patch.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 2beb6614f5e36c6165b704c167d82ef3e4ceaa0c
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Dec 5 23:31:28 2006 -0500

    locks: add fl_grant callback for asynchronous lock return
    
    Acquiring a lock on a cluster filesystem may require communication with
    remote hosts, and to avoid blocking lockd or nfsd threads during such
    communication, we allow the results to be returned asynchronously.
    
    When a ->lock() call needs to block, the file system will return
    -EINPROGRESS, and then later return the results with a call to the
    routine in the fl_grant field of the lock_manager_operations struct.
    
    This differs from the case when ->lock returns -EAGAIN to a blocking
    lock request; in that case, the filesystem calls fl_notify when the lock
    is granted, and the caller retries the original lock.  So while
    fl_notify is merely a hint to the caller that it should retry, fl_grant
    actually communicates the final result of the lock operation (with the
    lock already acquired in the succesful case).
    
    Therefore fl_grant takes a lock, a status and, for the test lock case, a
    conflicting lock.  We also allow fl_grant to return an error to the
    filesystem, to handle the case where the fl_grant requests arrives after
    the lock manager has already given up waiting for it.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit fd85b8170dabbf021987875ef7f903791f4f181e
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Tue Nov 28 16:26:41 2006 -0500

    nfsd4: Convert NFSv4 to new lock interface
    
    Convert NFSv4 to the new lock interface.  We don't define any callback for now,
    so we're not taking advantage of the asynchronous feature--that's less critical
    for the multi-threaded nfsd then it is for the single-threaded lockd.  But this
    does allow a cluster filesystems to export cluster-coherent locking to NFS.
    
    Note that it's cluster filesystems that are the issue--of the filesystems that
    define lock methods (nfs, cifs, etc.), most are not exportable by nfsd.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

commit 9b9d2ab4154a42ea4a119f7d3e4e0288bfe0bb79
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Thu Jan 18 17:52:58 2007 -0500

    locks: add lock cancel command
    
    Lock managers need to be able to cancel pending lock requests.  In the case
    where the exported filesystem manages its own locks, it's not sufficient just
    to call posix_unblock_lock(); we need to let the filesystem know what's
    happening too.
    
    We do this by adding a new fcntl lock command: FL_CANCELLK.  Some day this
    might also be made available to userspace applications that could benefit from
    an asynchronous locking api.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 150b393456e5a23513cace286a019e87151e47f0
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Thu Jan 18 16:15:35 2007 -0500

    locks: allow {vfs,posix}_lock_file to return conflicting lock
    
    The nfsv4 protocol's lock operation, in the case of a conflict, returns
    information about the conflicting lock.
    
    It's unclear how clients can use this, so for now we're not going so far as to
    add a filesystem method that can return a conflicting lock, but we may as well
    return something in the local case when it's easy to.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 7723ec9777d9832849b76475b1a21a2872a40d20
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Thu Jan 18 15:08:55 2007 -0500

    locks: factor out generic/filesystem switch from setlock code
    
    Factor out the code that switches between generic and filesystem-specific lock
    methods; eventually we want to call this from lock managers (lockd and nfsd)
    too; currently they only call the generic methods.
    
    This patch does that for all the setlk code.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 3ee17abd14c728d4e0ca7a991c58f2250cb091af
Author: J. Bruce Fields <bfields@citi.umich.edu>
Date:   Wed Feb 21 00:58:50 2007 -0500

    locks: factor out generic/filesystem switch from test_lock
    
    Factor out the code that switches between generic and filesystem-specific lock
    methods; eventually we want to call this from lock managers (lockd and nfsd)
    too; currently they only call the generic methods.
    
    This patch does that for test_lock.
    
    Note that this hasn't been necessary until recently, because the few
    filesystems that define ->lock() (nfs, cifs...) aren't exportable via NFS.
    However GFS (and, in the future, other cluster filesystems) need to implement
    their own locking to get cluster-coherent locking, and also want to be able to
    export locking to NFS (lockd and NFSv4).
    
    So we accomplish this by factoring out code such as this and exporting it for
    the use of lockd and nfsd.
    
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 9d6a8c5c213e34c475e72b245a8eb709258e968c
Author: Marc Eshel <eshel@almaden.ibm.com>
Date:   Wed Feb 21 00:55:18 2007 -0500

    locks: give posix_test_lock same interface as ->lock
    
    posix_test_lock() and ->lock() do the same job but have gratuitously
    different interfaces.  Modify posix_test_lock() so the two agree,
    simplifying some code in the process.
    
    Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 70cc6487a4e08b8698c0e2ec935fb48d10490162
Author: J. Bruce Fields <bfields@citi.umich.edu>
Date:   Thu Feb 22 18:48:53 2007 -0500

    locks: make ->lock release private data before returning in GETLK case
    
    The file_lock argument to ->lock is used to return the conflicting lock
    when found.  There's no reason for the filesystem to return any private
    information with this conflicting lock, but nfsv4 is.
    
    Fix nfsv4 client, and modify locks.c to stop calling fl_release_private
    for it in this case.
    
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
    Cc: "Trond Myklebust" <Trond.Myklebust@netapp.com>"

commit 1b11652286a06988f721b506b094d026e8892e2c
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun May 6 14:49:56 2007 +0100

    [ARM] Add comments marking in-use ptrace numbers
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 5ba6d3febd4978f31b2c523d64d381603923a709
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun May 6 13:56:26 2007 +0100

    [ARM] Move syscall saving out of the way of utrace
    
    utrace removes the ptrace_message field in task_struct.  Move our use
    of this field into a new member in thread_info called "syscall"
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 11de39e2fbbc592018e0a231d0ee773653dcc8d6
Author: Marcin Garski <mgarski@post.pl>
Date:   Sat May 5 22:49:00 2007 +0200

    kconfig: fix mconf segmentation fault
    
    I have found small bug in mconf, when you run it without any argument it
    will sigsegv.
    
    Without patch:
    $ scripts/kconfig/mconf
    Segmentation fault
    
    With patch:
    $ scripts/kconfig/mconf
    can't find file (null)
    
    Signed-off-by: Marcin Garski <mgarski@post.pl>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 767e581d759fe6adfef5e676cd1cd8e11f603d1a
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun May 6 09:23:45 2007 +0200

    kbuild: enable use of code from a different dir
    
    To introduce support for source in one directory but output files
    in another directory during a non O= build prefix all paths
    with $(src) repsectively $(obj).
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 5447d34b080a1e3e312b05a91e87eff4710a1152
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun May 6 09:20:10 2007 +0200

    kconfig: error out if recursive dependencies are found
    
    Sample:
    config FOO
    	bool "This is foo"
    	depends on BAR
    
    config BAR
    	bool "This is bar"
    	depends on FOO
    
    This will result in following error message:
    error: found recursive dependency: FOO -> BAR -> FOO
    
    And will then exit with exit code equal 1 so make will stop.
    Inspired by patch from: Adrian Bunk <bunk@stusta.de>
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc: Adrian Bunk <bunk@stusta.de>
    Cc: Roman Zippel <zippel@linux-m68k.org>

commit 0ec54aa8af5e6faa346aa55a1ad15ee6c25bb42d
Author: Steve French <sfrench@us.ibm.com>
Date:   Sat May 5 22:08:06 2007 +0000

    [CIFS] Fix typo in cifs readme from previous commit
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 886a0768affe9a32f18c45f8e1393bca9ece5392
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Sat May 5 14:23:40 2007 -0700

    Fix compile of tmscsim SCSI driver
    
    It still used the long-deprecated "pci_module_init()" interface, rather
    than the proper "pci_register_driver()" one.
    
    [ I don't have the hardware, and I doubt many do, but the fix is
      trivial and obvious, and can't be worse than not compiling ]
    
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 989485c190cc6a64e5a21d98ef2d752df1db8c27
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Sat May 5 22:05:11 2007 +0100

    Fix nfsroot build
    
      CC      fs/nfs/nfsroot.o
    fs/nfs/nfsroot.c:131: error: tokens causes a section type conflict
    make[2]: *** [fs/nfs/nfsroot.o] Error 1
    
    This is due to mixing const and non-const content in the same section
    which halfway recent gccs absolutely hate.  Fixed by dropping the const.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d0fdb5a58e17cf788c76a52a53174dbc8fb58ee9
Author: Arnaud Patard <arnaud.patard@rtp-net.org>
Date:   Sat May 5 15:55:09 2007 +0100

    [ARM] 4360/1: S3C24XX: regs-udc.h remove unused macro
    
    The S3C2410_UDC_SETIX() macro is not used and won't be used by the udc
    driver, so delete it.
    
    Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit c4b5bd4b101a8da1fb24a072adde276547462b43
Author: Arnaud Patard <arnaud.patard@rtp-net.org>
Date:   Sat May 5 15:12:17 2007 +0100

    [ARM] 4358/1: S3C24XX: mach-qt2410.c: remove linux/mmc/protocol.h header
    
    linux/mmc/protocol.h header is gone, thus breaking the build of the
    mach-qt2410.c file. As this header is not used, I'm removing it. The
    right headers may still be added later if needed.
    
    Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7544b0972c1fc1a0e6c54baa1f44c81019743daa
Author: Michael Chan <mchan@broadcom.com>
Date:   Sat May 5 13:08:32 2007 -0700

    [TG3]: Add TG3_FLAG_SUPPORT_MSI flag.
    
    And fix up the code to always allow MSI on 5714 A2.
    
    Call tg3_find_peer() earlier because we need that information before
    we can determine whether we can set TG3_FLAG_SUPPORT_MSI or not.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aa12b2842aba8cc367a2e1ddb5c6ae4fd8ddb1da
Author: Fabrice Aeschbacher <Fabrice.Aeschbacher@siemens.com>
Date:   Sat May 5 22:03:51 2007 +0200

    ide-cs: recognize 2GB CompactFlash from Transcend
    
    Without the following patch, the kernel does not automatically detect
    2GB CompactFlash cards from Transcend.
    
    Signed-off-by: Fabrice Aeschbacher <fabrice.aeschbacher@siemens.com>
    Cc: Dominik Brodowski <linux@dominikbrodowski.net>
    Acked-by: Peter Stuge <peter@stuge.se>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit fdb0d72be4decaade6cedb5012ddd679a4817b5f
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:51 2007 +0200

    hpt366: don't check enablebits for HPT36x
    
    HPT36x chip don't seem to have the channel enable bits, so prevent the IDE core
    from checking them...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Cc: Michal Kepien <michal.kepien@poczta.onet.pl>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 55e4dee32916a569112f33a511adab4bd72cc4a2
Author: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date:   Sat May 5 22:03:51 2007 +0200

    ide-cris: fix ->speedproc and wrong ->swdma_mask
    
    * fix ->speedproc to set the drive speed
    
    * this driver doesn't support SWDMA so use the correct ->swdma_mask
    
    * BUG() if an unsupported mode is passed to ->speedproc
    
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 8e60d3762f32c9573a449950717a3de12dfebbe3
Author: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date:   Sat May 5 22:03:51 2007 +0200

    siimage: fix wrong ->swdma_mask
    
    This driver doesn't support SWDMA so use the correct ->swdma_mask.
    
    While at it:
    
    * no need to call config_chipset_for_pio() in config_chipset_for_dma(),
      if DMA is not available config_chipset_for_pio() will be called
      by siimage_config_drive_for_dma() and if DMA is available
      config_siimage_chipset_for_pio() will be called by siimage_tune_chipset()
    
    * remove needless config_chipset_for_pio() wrapper
    
    * bump driver version
    
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 0e9b4e535fec7e2a189952670937adfbe2826b63
Author: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date:   Sat May 5 22:03:50 2007 +0200

    it821x: PIO mode setup fixes
    
    * limit max PIO mode to PIO4, this driver doesn't support PIO5 and attempt
      to setup PIO5 by it821x_tuneproc() could result in incorrect PIO timings
      + incorrect base clock being set for controller in the passthrough mode
    
    * move code limiting max PIO according to the pair device capabilities from
      config_it821x_chipset_for_pio() to it821x_tuneproc() so the check is also
      applied for mode change requests coming through ->tuneproc and ->speedproc
      interfaces
    
    * set device speed in it821x_tuneproc()
    
    * in it821x_tune_chipset() call it821x_tuneproc() also if the controller is
      in the smart mode (so the check for pair device max PIO is done)
    
    * rename it821x_tuneproc() to it821x_tune_pio(), then add it821x_tuneproc()
      wrapper which does the max PIO mode check;  it worked by the pure luck
      previously, pio[4] and pio_want[4] arrays were used with index == 255
      so random PIO timings and base clock were set for the controller in the
      passthrough mode, thankfully PIO timings and base clock were corrected
      later by config_it821x_chipset_for_pio() call (but it was not called for
      PIO-only devices during resume and for user requested PIO autotuning)
    
    * remove config_it821x_chipset_for_pio() call from config_chipset_for_dma()
      as the driver sets ->autotune to 1 and ->tuneproc does the proper job now
    
    * convert the last user of config_it821x_chipset_for_pio() to use
      it821x_tuneproc(drive, 255) and remove no longer needed function
    
    While at it:
    
    * fix few comments
    
    * bump driver version
    
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 247b03f8dc4c01659030889f7fb4574013974ac6
Author: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date:   Sat May 5 22:03:50 2007 +0200

    pdc202xx_new: enable DMA for all ATAPI devices
    
    There is no reason to limit DMA to ide_cdrom type devices.
    
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 072cdcbb7af8a0e1894f9caa6d46d027bbe7f647
Author: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Date:   Sat May 5 22:03:50 2007 +0200

    alim15x3: PIO fallback fix
    
    If DMA tuning fails always set the best PIO mode.
    
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 826a1b6502d0d1d67fc41043fc831e90f2ef5835
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:50 2007 +0200

    aec62xx: fix PIO/DMA setup issues
    
    Teach the driver's tuneproc() method to do PIO auto-runing properly since it
    treated 5 instead of 255 as auto-tune request, and also passed the mode limit
    of PIO5 to ide_get_best_pio_mode() despite supporting up to PIO4 only.
    
    While at it, also:
    
    - remove the driver's wrong claim about supporting SWDMA modes;
    
    - stop hooking ide_dma_timeout() method as the handler clearly doesn't fit for
      the task...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 66602c83dcb6a5d82772d88ae7a32cd4a1213528
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:50 2007 +0200

    cmd64x: use interrupt status from MRDMODE register (take 2)
    
    Fold the parts of the ide_dma_end() methods identical to __ide_dma_end() into a
    mere call to it.
    Start using faster versions of the ide_dma_end() and ide_dma_test_irq() methods
    for the PCI0646U and newer chips that have the duplicate interrupt status bits
    in the I/O mapped MRDMODE register, determing what methods to use at the driver
    load time. Do some cleanup/renaming in the "old" ide_dma_test_irq() method too.
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 5826b318aa02e81575c352ca26f00773c999795b
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:50 2007 +0200

    cmd64x: procfs code fixes/cleanups (take 2)
    
    Fix several issues with the driver's procfs output:
    
    - when testing if channel is enabled, the code looks at the "simplex" bits, not
      at the real enable bits -- add #define for the primary channel enable bit;
    
    - UltraDMA modes 0, 1, 3 for slave drive reported incorrectly due to using the
      master drive's clock cycle resolution bit.
    
    While at it, also perform the following cleanups:
    
    - don't print extra newline before the first controller's dump;
    
    - correct the chipset names (from CMDxxx to PCI-xxx)
    
    - don't read from the registers which aren't used for dump;
    
    - better align the table column sizes;
    
    - rework UltraDMA mode dump code;
    
    - remove PIO mode dump code that has never been finished;
    
    - remove the duplicate interrupt status (the MRDMODE register bits mirror those
      those in the CFR and ARTTIM23 registers) and fold the dump into single line;
    
    - correct the style of the ?: operators...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 7accbffdb8163a59c7bdd3e4eb9a391198979522
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:49 2007 +0200

    cmd64x: add/fix enablebits (take 2)
    
    The IDE core looks at the wrong bit when checking if the secondary channel is
    enabled on PCI0646 -- CNTRL register bit 7 is read-ahead disable, bit 3 is the
    correct one.
    Starting with PCI0646U chip, the primary channel can also be enabled/disabled --
    so, add 'enablebits' initializers to each 'ide_pci_device_t' structure, handling
    the original PCI0646 via adding the init_setup() method and clearing the 'reg'
    field there if necessary...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit e51e2528d589c13f0e51dfa671c310021d003e21
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:49 2007 +0200

    cmd64x: interrupt status fixes (take 2)
    
    The driver's ide_dma_test_irq() method was reading the MRDMODE register even on
    PCI0643/6 where it was write-only -- fix this by always reading the "backward-
    compatible" interrupt bits, renaming dma_alt_stat to irq_stat as the interrupt
    status bits are not coupled to DMA.
    In addition, wrong interrupt bit was tested/cleared for the primary channel --
    it's bit 2 in all the chip specs and the driver used bit 1... :-/
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 60e7a82f1acb76af05d81e93ca0f65fdd52c23c2
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:49 2007 +0200

    cmd64x: fix multiword and remove single-word DMA support
    
    Fix the multiword DMA and drop the single-word DMA support (which nobody will
    miss, I think).  In order to do it, a number of changes was necessary:
    
    - rename program_drive_counts() to program_cycle_times(), pass to it cycle's
      total/active times instead of the clock counts, and convert them into the
      active/recovery clocks there instead of cmd64x_tune_pio() -- this causes
      quantize_timing() to also move;
    
    - contrarywise, move all the code handling the address setup timing into
      cmd64x_tune_pio(), so that setting MWDMA mode wouldn't change address setup;
    
    - remove from the speedproc() method the  bogus code pretending to set the DMA
      timings by twiddling bits in the BMIDE status register, handle setting MWDMA
      by just calling program_cycle_times(); while at it, improve the style of that
      whole switch statement;
    
    - stop fiddling with the DMA capable bits in the speedproc() method -- they do
      not enable DMA, and are properly dealt with by the dma_host_{on,off} methods;
    
    - don't set hwif->swdma_mask in the init_hwif() method anymore.
    
    In addition to those changes, do the following:
    
    - in cmd64x_tune_pio(), when writing to ARTTIM23 register preserve the interrupt
      status bit, eliminate local_irq_{save|restore}() around this code as there's
      *no* actual race with the interrupt handler, and move cmdprintk() to a more
      fitting place -- after ide_get_best_pio_mode() call;
    
    - make {arttim|drwtim}_regs arrays single-dimensional, indexed with drive->dn;
    
    - rename {setup|recovery}_counts[] into more fitting {setup|recovery}_values[];
    
    - in  the speedproc() method, get rid of the duplicate reads/writes from/to the
      UDIDETCRx registers and of the extra variable used to store the transfer mode
      value after filtering,  use another method of determining master/slave drive,
      and cleanup useless parens;
    
    - beautify cmdprintk() output here and there.
    
    While at it, remove meaningless comment about the driver being used only on
    UltraSPARC and long non-relevant RCS tag. :-)
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 688a87d145e04f6761c63e7f2e19fd9b3e4ca060
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:49 2007 +0200

    sl82c105: DMA support code cleanup (take 4)
    
    Fold the now equivalent code in the ide_dma_check() method into a mere call to
    ide_use_dma().  Make config_for_dma() return non-zero if DMA mode has been set
    and call it from the ide_dma_check() method instead of ide_dma_on().
    Defer writing the DMA timings to the chip registers until DMA is really turned
    on (and do not enable IORDY for DMA).
    Remove unneeded code from the init_hwif() method, improve its overall looks.
    Rename the dma_start(), ide_dma_check(), and ide_dma_lostirq() methods, and
    also use more proper hwif->dma_command, fix printk() and comment in the latter
    one as well.  While at it, cleanup style in several places.
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit e93df705af1992dbf5956a8c80fcb9987bc595c0
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat May 5 22:03:49 2007 +0200

    sl82c105: rework PIO support (take 2)
    
    Get rid of the 'pio_speed' member of 'ide_drive_t' that was only used by this
    driver by storing the PIO mode timings in the 'drive_data' instead -- this
    allows us to greatly  simplify the process of "reloading" of the chip's timing
    register and do it right in sl82c150_dma_off_quietly() and to get rid of two
    extra arguments to config_for_pio() -- which got renamed to sl82c105_tune_pio()
    and now returns a PIO mode selected, with ide_config_drive_speed() call moved
    into the tuneproc() method, now called sl82c105_tune_drive() with the code to
    set drive's 'io_32bit' and 'unmask' flags in its turn moved to its proper place
    in the init_hwif() method.
    Also, while at it, rename get_timing_sl82c105() into get_pio_timings() and get
    rid of the code in it clamping cycle counts to 32 which was both incorrect and
    never executed anyway...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

commit 3603ab2b62ad8372fc93816b080b370dd55d7cec
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat May 5 20:59:27 2007 +0100

    [ARM] mm 10: allow memory type to be specified with ioremap
    
    __ioremap() took a set of page table flags (specifically the cacheable
    and bufferable bits) to control the mapping type.  However, with
    the advent of ARMv6, this is far too limited.
    
    Replace the page table flags with a memory type index, so that the
    desired attributes can be selected from the mem_type table.
    
    Finally, to prevent silent miscompilation due to the differing
    arguments, rename the __ioremap() and __ioremap_pfn() functions.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 98efd8a6be79550767f5a9be6f3db8e7e9b747da
Author: Matt Carlson <mcarlson@broadcom.com>
Date:   Sat May 5 12:47:25 2007 -0700

    [TG3]: Eliminate the TG3_FLAG_5701_REG_WRITE_BUG flag.
    
    This patch removes the use of the TG3_FLAG_5701_REG_WRITE_BUG flag.
    It's logic is only used to set a function pointer and thus the
    logic can be collapsed and the flag removed.
    
    [ Comment tidy by Christoph Hellwig. -DaveM ]
    
    Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>

commit 0af92befeb4b330c46cce6b520b2cc775cd6931f
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat May 5 20:28:16 2007 +0100

    [ARM] mm 9: add additional device memory types
    
    Add cached device type for ioremap_cached().  Group all device memory
    types together, and ensure that they all have a "MT_DEVICE" prefix.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 05ec9e26be1f668ccba4ca54d9a4966c6208c611
Author: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Date:   Sat May 5 14:24:05 2007 -0500

    JFS: Fix race waking up jfsIO kernel thread
    
    It's possible for a journal I/O request to be added to the log_redrive
    queue and the jfsIO thread to be awakened after the thread releases
    log_redrive_lock but before it sets its state to TASK_INTERRUPTIBLE.
    
    The jfsIO thread should set the state before giving up the spinlock, so
    the waking thread will really wake it.
    
    Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>

commit 5cf64b8a7399999439f0d6748babb1ccb6bcad7c
Author: Michael Chan <mchan@broadcom.com>
Date:   Sat May 5 12:11:21 2007 -0700

    [TG3]: Eliminate the TG3_FLAG_GOT_SERDES_FLOWCTL flag.
    
    This flag does not do anything useful.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 986e0aeb9ae09127b401c3baa66f15b7a31f354c
Author: Michael Chan <mchan@broadcom.com>
Date:   Sat May 5 12:10:20 2007 -0700

    [TG3]: Remove reset during MAC address changes.
    
    The reset was added a while back so that ASF could re-init whatever
    MAC address it wanted to use after the MAC address was changed.
    Instead of resetting, we can just keep MAC address 1 unchanged during
    MAC address changes if MAC address 1 is different from MAC address 0.
    
    This fixes 2 problems:
    
    1. Bonding calls set_mac_address in contexts that cannot sleep.
    It no longer sleeps with the chip reset removed.
    
    2. When ASF shares the same MAC address as the NIC, it needs to
    always do that even when the MAC address is changed.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9ef7963503abd3287943125681c2dc17879e8d4e
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat May 5 20:03:35 2007 +0100

    [ARM] mm 8: define mem_types table L1 bit 4 to be for ARMv6
    
    Change the memory types table to define the L1 descriptor bit 4 to
    be in terms of the ARMv6 definition - execute never.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit a85feb8cfc53c08b6f0d770f930ca9cc6885f414
Author: Gary Zambrano <zambrano@broadcom.com>
Date:   Sat May 5 11:52:19 2007 -0700

    [TG3]: WoL fixes.
    
    Change TG3_FLAG_SERDES_WOL_CAP to TG3_FLAG_WOL_CAP to make it easier
    to manage WoL.  This flag is now used consistently during ethtool WoL
    setup and power setting changes.
    
    Signed-off-by: Gary Zambrano <zambrano@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aaf84465fc994e9a840a8c0c6fa842b54cdb3426
Author: Gary Zambrano <zambrano@broadcom.com>
Date:   Sat May 5 11:51:45 2007 -0700

    [TG3]: Clear GPIO mask before storing.
    
    The GPIO settings may change during reset and so the stored values in
    tp->grc_local_ctrl should be cleared first.
    
    Signed-off-by: Gary Zambrano <zambrano@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 989a9d239c5b9ae6053aed6e3819304930baf27d
Author: Matt Carlson <mcarlson@broadcom.com>
Date:   Sat May 5 11:51:05 2007 -0700

    [TG3]: Improve NVRAM sizing.
    
    This patch changes the NVRAM sizing procedure so that the driver can
    take advantage of devices with 1:1 NVRAM strapping configurations.  This
    is useful in cases where the traditional NVRAM sizing method fails.  In
    the event that the flash size cannot be determined, the largest known
    NVRAM size is used.  The patch also removes support for 5755 NVRAM
    devices that are not supported by Broadcom and adds explicit sizing for
    this device.
    
    Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c13e3713857d5ea572cd67f3d5749100b1963ad2
Author: Matt Carlson <mcarlson@broadcom.com>
Date:   Sat May 5 11:50:04 2007 -0700

    [TG3]: Fix TSO bugs.
    
    1. Remove the check for skb->len greater than MTU when doing TSO.
    When the destination has a smaller MSS than the source, a TSO packet
    may be smaller than the MTU and we still need to process it as a TSO
    packet.
    
    2. On 5705A3 devices with TSO enabled, the DMA engine can hang due to a
    hardware bug.  This patch avoids the hanging condition by reducing the
    DMA burst size.
    
    Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 64a327a7029d3860ddf6a024816afa9e6673eb57
Author: Jiri Benc <jbenc@suse.cz>
Date:   Sat May 5 11:47:08 2007 -0700

    [MAC80211]: Add maintainers entry for mac80211.
    
    Add MAINTAINERS entry for mac80211.
    
    Signed-off-by: Jiri Benc <jbenc@suse.cz>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e9f207f0ff90bf60b825800d7450e6f2ff2eab88
Author: Jiri Benc <jbenc@suse.cz>
Date:   Sat May 5 11:46:38 2007 -0700

    [MAC80211]: Add debugfs attributes.
    
    Export various mac80211 internal variables through debugfs.
    
    Signed-off-by: Jiri Benc <jbenc@suse.cz>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f0706e828e96d0fa4e80c0d25aa98523f6d589a0
Author: Jiri Benc <jbenc@suse.cz>
Date:   Sat May 5 11:45:53 2007 -0700

    [MAC80211]: Add mac80211 wireless stack.
    
    Add mac80211, the IEEE 802.11 software MAC layer.
    
    Signed-off-by: Jiri Benc <jbenc@suse.cz>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit a9de8ce0943e03b425be18561f51159fcceb873d
Author: Jiri Benc <jbenc@suse.cz>
Date:   Sat May 5 11:43:04 2007 -0700

    [MAC80211]: Add generic include/linux/ieee80211.h
    
    Add generic IEEE 802.11 definitions.
    
    Signed-off-by: Jiri Benc <jbenc@suse.cz>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cf130cb102487723bdfc53e4abde1227a7563797
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sat May 5 11:42:03 2007 -0700

    [NETLINK]: Remove references to process ID
    
    People treating the *_pid fields in netlink as a process ID has caused
    endless confusion over the years.  The fact that our own netlink.h
    does this only adds to the confusion.
    
    So here is a patch to change the comments to refer to it as the port
    ID which hopefully will make it clear what the purpose of the fields
    really is.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit af7cd373b01ccb8191dc16c77fff4cf2b11def50
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Sat May 5 11:41:18 2007 -0700

    [AF_IUCV]: Compile fix - adopt to skbuff changes.
    
    From: Heiko Carstens <heiko.carstens@de.ibm.com>
    
      CC [M]  net/iucv/af_iucv.o
    net/iucv/af_iucv.c: In function `iucv_fragment_skb':
    net/iucv/af_iucv.c:984: error: structure has no member named `h'
    net/iucv/af_iucv.c:985: error: structure has no member named `nh'
    net/iucv/af_iucv.c:988: error: incompatible type for argument 1 of
    			`skb_queue_tail'
    
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ad902cb9e29a4d6ff155f682ae79d8d8b2b73a9b
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat May 5 11:59:13 2007 +0100

    [ARM] iop: add missing parens in macro
    
    Fix:
    
     drivers/serial/8250.c:1837: warning: suggest parentheses around arithmetic in operand of |
    
    due to a macro argument being used without required parenthesis.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 0058ca32c3004547ede575668a2be31862b92000
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat May 5 11:57:39 2007 +0100

    [ARM] mm 7: remove duplicated __ioremap() prototypes
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit fcf126d847c41461d4f034b11541296f3e15d0b2
Author: David Brownell <david-b@pacbell.net>
Date:   Mon Apr 2 12:46:47 2007 -0700

    ARM: OMAP: fix OMAP1 mpuio suspend/resume oops
    
    Fix oops in omap16xx mpuio suspend/resume code; field wasn't initialized
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 11a78b7944963a8b052be46108d07a3ced9e2762
Author: David Brownell <dbrownell@users.sourceforge.net>
Date:   Wed Dec 6 17:14:11 2006 -0800

    ARM: OMAP: MPUIO wake updates
    
    GPIO and MPUIO wake updates:
    
     - Hook MPUIOs into the irq wakeup framework too.  This uses a platform
       device to update irq enables during system sleep states, instead of
       a sys_device, since the latter is no longer needed for such things.
    
     - Also forward enable/disable irq wake requests to the relevant GPIO
       controller, so the top level IRQ dispatcher can (eventually) handle
       these wakeup events automatically if more than one GPIO pin needs to
       be a wakeup event source.
    
     - Minor tweak to the 24xx non-wakeup gpio stuff: no need to check such
       read-only data under the spinlock.
    
    This assumes (maybe wrongly?) that only 16xx can do GPIO wakeup; without
    a 15xx I can't test such stuff.
    
    Also this expects the top level IRQ dispatcher to properly handle requests
    to enable/disable irq wake, which is currently known to be wrong:  omap1
    saves the flags but ignores them, omap2 doesn't even save it.  (Wakeup
    events are, wrongly, hardwired in the relevant mach-omapX/pm.c file ...)
    So MPUIO irqs won't yet trigger system wakeup.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 58781016c3637caf314ca7f579ce0acd1b0378dc
Author: David Brownell <dbrownell@users.sourceforge.net>
Date:   Wed Dec 6 17:14:10 2006 -0800

    ARM: OMAP: speed up gpio irq handling
    
    Speedup and shrink GPIO irq handling code, by using a pointer
    that's available in the irq_chip structure instead of calling
    the get_gpio_bank() function.  On OMAP1 this saves 44 words,
    most of which were in IRQ critical path methods.  Hey, every
    few instructions help.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 56a2564185db752d83bbc78be9b1e257bf103444
Author: Syed Mohammed Khasim <x0khasim@ti.com>
Date:   Wed Dec 6 17:14:08 2006 -0800

    ARM: OMAP: plat-omap changes for 2430 SDP
    
    This patch adds minimal OMAP2430 support to plat-omap files to
    get the kernel booting on 2430SDP.
    
    Signed-off-by: Syed Mohammed Khasim <x0khasim@ti.com>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit e5c56ed3c9caa6ba717af0a5c23e2c7bf5c97a1f
Author: David Brownell <dbrownell@users.sourceforge.net>
Date:   Wed Dec 6 17:13:59 2006 -0800

    ARM: OMAP: gpio object shrinkage, cleanup
    
    More GPIO/IRQ cleanup:
    
      - compile-time removal of much useless code
          * mpuio support on non-OMAP1.
          * 15xx/730/24xx gpio support on 1610
          * 15xx/730/16xx gpio support on 24xx
          * etc
    
      - remove all BUG() calls, which are always bad news ... replaced some
        with normal fault reports for that call, others with WARN_ON(1).
    
      - small mpuio bugfix:  add missing set_type() method
    
    Oh, and fix a minor merge issue: inode->u.generic_ip is now gone.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit b9772a220a0d1b1d83b770ed131fa8b090af3681
Author: David Brownell <dbrownell@users.sourceforge.net>
Date:   Wed Dec 6 17:13:53 2006 -0800

    ARM: OMAP: /sys/kernel/debug/omap_gpio
    
    Add some GPIO debug support:  /sys/kernel/debug/omap_gpio dumps the state
    of all GPIOs that have been claimed, including basic IRQ info if relevant.
    Tested on 24xx, 16xx.
    
    Includes minor bugfixes:  recording IRQ trigger mode (this should probably
    be a genirq patch), adding missing space to non-wakeup warning
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 3ac4fa99291a60329e9c9424ac3e67bb4f9564f5
Author: Juha Yrjola <juha.yrjola@solidboot.com>
Date:   Wed Dec 6 17:13:52 2006 -0800

    ARM: OMAP: Implement workaround for GPIO wakeup bug in OMAP2420 silicon
    
    Some GPIOs on OMAP2420 do not have wakeup capabilities. If these GPIOs
    are configured as IRQ sources, spurious interrupts will be generated
    each time the core domain enters retention.
    
    Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 14f1c3bf51b78d916a6aff9c9b5e6689e3e006e7
Author: Juha Yrjola <juha.yrjola@solidboot.com>
Date:   Wed Dec 6 17:13:48 2006 -0800

    ARM: OMAP: Enable 24xx GPIO autoidling
    
    Enable 24xx GPIO autoidling
    
    Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 28bd3a0dcce11bea6f99a351cc64053dff00196e
Author: Michael-Luke Jones <mlj28@cam.ac.uk>
Date:   Sat Apr 28 08:31:40 2007 +0100

    [ARM] 4318/2: DSM-G600 Board Support
    
    This patch adds support for the D-Link DSM-G600 Rev A.
    This is an ARM XScale IXP4xx system relatively similar to
    the NSLU2 and NAS-100D already supported by mainline. An
    important difference is Gigabit Ethernet support using
    the Via Velocity chipset.
    
    This patch is the combined work of Michael Westerhof and
    Alessandro Zummo, with contributions from Michael-Luke
    Jones. This version addresses review comments from rmk
    and Deepak Saxena.
    
    Signed-off-by: Michael-Luke Jones <mlj28@cam.ac.uk>
    Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
    Signed-off-by: Michael Westerhof <mwester@dls.net>
    Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 6cbf0c704d7c3bb215ae7e0381b1ff2ad5931f35
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Fri May 4 20:44:23 2007 -0700

    iomap: make the default iomap functions fail softer
    
    We used to BUG_ON() for a badly mapped IO port, which is certainly
    correct, but actually made it harder to debug the case where the ATA
    drivers had incorrectly mapped a nonconnected ATA port.
    
    So make badly mapped ports trigger a WARN_ON(), and throw the IO away
    instead (and return all ones for reads).  For things like broken driver
    initialization - which is the most likely cause anyway - that should
    mean that the machine comes up and is usable (at least that was the case
    for the ATA breakage that triggered this patch).
    
    It tends to be a whole lot easier to do a "dmesg" on a working machine
    than to try to capture logs off a dead one.
    
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8426c39c1289765a11fc9b9523212ed368ceebd8
Author: Jeff Layton <jlayton@redhat.com>
Date:   Sat May 5 03:27:49 2007 +0000

    [CIFS] Make sec=none force an anonymous mount
    
    We had a customer report that attempting to make CIFS mount with a null
    username (i.e. doing an anonymous mount) doesn't work. Looking through the
    code, it looks like CIFS expects a NULL username from userspace in order
    to trigger an anonymous mount. The mount.cifs code doesn't seem to ever
    pass a null username to the kernel, however.
    
    It looks also like the kernel can take a sec=none option, but it only seems
    to look at it if the username is already NULL. This seems redundant and
    effectively makes sec=none useless.
    
    The following patch makes sec=none force an anonymous mount.
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 253f04e78ded827c30f9582489773ebe2adc8924
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:38 2007 +0200

    ps3av: Use __func__ instead of __FUNCTION__
    
    ps3av: Replace GNU extension `__FUNCTION__' by C99 `__func__'
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d778c9a400e569029c8a48bc898c70780d6d2c1c
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:37 2007 +0200

    ps3fb: Use __func__ instead of __FUNCTION__
    
    ps3fb: Replace GNU extension `__FUNCTION__' by C99 `__func__'
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 640729014e073e6e2de1f513b2856b81aa7d84e9
Author: Masashi Kimoto <Masashi_Kimoto@hq.scei.sony.co.jp>
Date:   Wed May 2 14:48:36 2007 +0200

    ps3: Make `ps3videomode -v 0 (auto mode) work again
    
    ps3: Make `ps3videomode -v 0' (auto mode) work again
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fffe52e86b4ad5f8bdcb284c4ea6c87402967f3d
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:35 2007 +0200

    ps3av: misc updates
    
    ps3av:
      - Move the definition of struct ps3av to ps3av.c, as it's locally used only.
      - Kill ps3av.sem, use the existing ps3av.mutex instead.
      - Make the 512-byte buffer in ps3av_do_pkt() static to reduce stack usage.
        Its use is protected by a semaphore anyway.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bd685ac8e78b9bfd4a0145be22a7ff11ab11adef
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:34 2007 +0200

    ps3fb: kill superfluous zero initializations
    
    ps3fb: kill superfluous zero initializations
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 5caf5db887b2bc87d74a78674d8e3e4774fa2a14
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:33 2007 +0200

    ps3av: thread updates
    
    ps3av: Replace the kernel_thread and the ping pong semaphores by a singlethread
    workqueue and a completion.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit eca28743b74736456bd75e0dabeb7d2df09fc03e
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:32 2007 +0200

    ps3fb: atomic fixes
    
    ps3fb: Use atomic_dec_if_positive() instead of bogus atomic_read()/atomic_dec()
    combinations
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1c0c8461191d6d74926397abe2aa5f7cc9fd5a67
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Wed May 2 14:48:31 2007 +0200

    ps3fb: thread updates
    
    ps3fb: Replace the kernel_thread and the semaphore by a proper kthread, which
    is simply woken up when the screen must be updated
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 254f9c5cd2d3b41e64f59df816630f7ca5548a8a
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:33:07 2007 +0200

    Convert non-highmem kmap_atomic() to static inline function
    
    Convert kmap_atomic() in the non-highmem case from a macro to a static
    inline function, for better type-checking and the ability to pass void
    pointers instead of struct page pointers.
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f5456e040eaac7eb9545d49c38984af2047699be
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:33:06 2007 +0200

    m68k: export csum_partial_copy_from_user
    
    net/rxrpc/af-rxrpc.ko needs csum_partial_copy_from_user
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cfa08bb5ba6df4a76a67b7ddb9b2b549eda2458b
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:33:05 2007 +0200

    m68k: kill skb_copy_from_linear_data compiler warnings
    
    The recent conversion from `memcpy' to `skb_copy_from_linear_data' removed a
    few casts, which were needed to silence compiler warnings. Re-add them.
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 318175766e7688ba52cdf771d37e98a1e4759f98
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:33:04 2007 +0200

    Amiga Zorro bus: kill resource_size_t warnings
    
    Kill resource_size_t warnings by casting resource_size_t to unsigned long when
    formatting Zorro bus resources, as they are always 32-bit.
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f4d86754f956ab5ea73aa91759a0d89a2f0e3f2a
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Wed May 2 12:55:56 2007 +1000

    SONIC interrupt handling
    
    Install the built-in macsonic interrupt handler on both IRQs when using
    via_alt_mapping. Otherwise the rare interrupt that still comes from the
    nubus slot will wedge the nubus.
    
    $ cat /proc/interrupts
    auto       2:      89176 via2
    auto       3:     744367 sonic
    auto       4:          0 scc
    auto       6:     318363 via1
    auto       7:          0 NMI
    mac        9:     119413 framebuffer vbl
    mac       10:       1971 ADB
    mac       14:     198517 timer
    mac       17:      89104 nubus
    mac       19:         72 Mac ESP SCSI
    mac       56:        629 sonic
    mac       62:    1142593 ide0
    
    Version 1 of this patch had a bug where a nubus sonic card would register
    two interrupt handlers. Only a built-in sonic needs both.
    
    Versions 2 and 3 needed some cleanups, as Raylynn Knight and Christoph
    Hellwig pointed out (thanks).
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d74472f0b2553e59eafb7feee0ff9558136a17e0
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:33:02 2007 +0200

    SONIC: small fix and cleanup
    
    Fix a potential problem in the timeout handling: don't free the DMA buffers
    before resetting the chip.
    
    Also a trivial cleanup. Bring macsonic and jazzsonic into sync.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8b6aaab8c8bdbe011aac79af218dd1e657984bab
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:33:01 2007 +0200

    m68k: macmace fixes
    
    Fix a race condition in the transmit code, where the dma interrupt could update
    the free tx buffer count concurrently and wedge the tx queue.
    
    Fix the misuse of the rx frame status and rx frame length registers: no more
    "fifo overrun" errors caused by the OFLOW bit being tested in the frame length
    register (instead of the status register), and no more missed packets due to
    incorrect length taken from status register (instead of the frame length
    register).
    
    Fix a panic (skb_over_panic BUG) caused by allocating and then copying an
    incoming packet while the packet length register was changing.
    
    Cut-and-paste the reset code from the powermac mace driver (mace.c), so the NIC
    functions when MacOS does not initialise it (important for anyone wanting to
    use the Emile boot loader).
    
    Cut-and-paste the error counting and timeout recovery code from mace.c.
    
    Fix over allocation of rx buffer memory (it's page order, not page count).
    
    Converted to driver model.
    
    Converted to DMA API.
    
    Since I've run out of ways to make it fail, and since it performs well now,
    promote the driver from EXPERIMENTAL status. Tested on both quadra 840av and
    660av.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 0251c38ce503de01f5bc07917a824021b86b4ada
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:33:00 2007 +0200

    CUDA ADB fixes
    
    Fix the flakiness in the CUDA ADB driver on m68k macs (keypresses getting
    wedged down or ADB just going AWOL altogether).
    
    The only IRQ used by this driver is the VIA shift register IRQ. The PowerMac
    conditional code disables the other VIA IRQ sources, so don't mess with the
    other IRQ flags in the common code -- m68k macs need them.
    
    When polling, don't disable local interrupts when we only need to disable the
    CUDA interrupt.
    
    Unless polling, don't clear the shift register IRQ flag. On m68k macs this
    creates a race that often breaks CUDA ADB.
    
    Tested on Quadra 840av and LC630 (both m68k); also Beige G3 (powerpc).
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d95fd5fce88f05fd36004f2a0c317e665549e54c
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:59 2007 +0200

    m68k: Mac II ADB fixes
    
    Fix a crash caused by requests placed in the queue with the completed flag
    already set. This lead to some ADB_SYNC requests returning early and their
    request structs being popped off the stack while still queued. Stack corruption
    ensued or an invalid request callback pointer was invoked or both. Eliminate
    macii_retransmit() and its buggy implementation of macii_write(). Have
    macii_queue_poll() fully initialise the request queues.
    
    Fix a bug in macii_queue_poll() where the last_req pointer was not being set.
    This caused some requests to leave the queue before being completed (and would
    also corrupt the stack under certain conditions).
    
    Fix a race in macii_start that could set the state machine to "reading" while
    current_req was null.
    
    No longer send poll commands with the ADBREQ_REPLY flag -- doing that caused
    the replies to be stored in the request buffer where they were forgotten
    about.
    
    Don't autopoll by continuously sending new Talk commands. Get the controller to
    do that for us. This reduces the ADB interrupt rate on an idle bus to about 5
    per second. Only autopoll the devices that were probed.
    
    Explicitly clear the interrupt flag when polling.
    
    Use disable_irq rather than local_irq_save when polling.
    
    Remove excess local_irq_save/restore pairs.
    
    Improve bus timeout and service request detection.
    
    Remove unused code (last_reply, adb_dir etc) and unneeded code (prefix_len,
    first_byte etc).
    
    Change TIP and TACK to their correct names on this ADB controller (ST_EVEN and
    ST_ODD).
    
    Add some commentry.
    
    Add a generous quantity of sanity checks (BUG_ONs).
    
    Let m68k macs use the adb_sync boot param too.
    
    Tested on Mac II, Mac IIci, Quadra 650, Quadra 700 etc.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 217f6710c275118af1008bb1447d244be52d2dc3
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:58 2007 +0200

    m68k: Mac IRQ cleanup
    
    There are no slow IRQs on Macs since Roman Zippel's IRQ reorganisation that
    went into 2.6.16 and removed mac_irq_list[] and the do_mac_irq_list()
    dispatcher. (They were implemented in do_mac_irq_list() by lowering the IPL.)
    Hence there's no more use for mutual exclusion in the Mac interrupt
    dispatchers. Remove it.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit cd713ddc93bf2f612783aea8eff6d0df6107765e
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:57 2007 +0200

    m68k: Mac nubus IRQ fixes (plan E)
    
    Some Macs lack a slot interrupt enable register. So the existing code makes
    disabled and unregistered slot IRQ lines outputs set high. This seems to work
    on quadras, but does not work on genuine VIAs (perhaps the card still succeeds
    in pulling the line low, or perhaps because this increases the settle time on
    the port A input, meaning that the CA1 IRQ could fire before the slot line
    reads active).
    
    Because of this, the nubus_active flags were used to mask IRQs, which is
    actually worse than the problem it tries to solve. Any interrupt masked by
    nubus_active will remain asserted and prevent further transitions on CA1. And
    so the nubus gets wedged regardless of hardware (emulated VIA ASIC, real VIA
    chip or RBV).
    
    The best solution to this hardware limitation of genuine VIAs is to disable the
    umbrella SLOTS IRQ when disabling a slot on those machines. Unfortunately, this
    means all slot IRQs get disabled when any slot IRQ is disabled. But it is only
    a problem when there's more than 1 device using nubus interrupts.
    
    Another potential problem for genuine VIAs is an unregistered nubus IRQ.
    Eventually it will be possible to enable the CA1 interrupt by installing its
    handler only _after_ all nubus drivers have loaded but _before_ the kernel
    needs them, at which time this last problem can be fixed. For now it can be
    worked around:
    
      - disable MacOS extensions
      - don't boot MacOS (use the Emile bootloader instead)
      - get the bootloaders to disable ROM drivers (Penguin does this for video
        cards already, don't know about Emile)
      - physically remove unsupported cards
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 67dfb153a352e57e71404d550be7eb60d15d7f2d
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:56 2007 +0200

    m68k: Mac IRQ prep
    
    Make sure that there are no slot IRQs asserted before leaving the nubus
    handler. If there are and we don't then the nubus gets wedged because this
    prevents a CA1 transition, which means no more nubus IRQs.
    
    Make the interrupt dispatch loops terminate sooner.
    
    Explicitly initialise the VIA latches to make the code more easily understood.
    
    Also some cleanups.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 647b804c8237aa35e19caf8e11ea8d5565107b0e
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:55 2007 +0200

    m68k: reverse Mac IRQ damage
    
    Reverse the last of a monumental brown-paper-bag commit that went into the 2.3
    kernel.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 2964db0f590437b7efb7858bd2330134ac5292df
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:54 2007 +0200

    m68k: Mac DP8390 update
    
    Fix the support for C/NET nubus ethernet cards etc. Sync up the DP8390 driver
    with the latest code in the mac68k repo.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f877958879d413c37bfbeb7517614f3625cdea38
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:53 2007 +0200

    NuBus header update
    
    Sync the nubus defines with the latest code in the mac68k repo. Some of these
    are needed for DP8390 driver update in the next patch.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e10e5c4325b37e1a7dce9cd3d2cbcd8dd9536a7a
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:52 2007 +0200

    m68k: Mac interrupt priorities
    
    Add some more machines that support A/UX interrupt priorities. There are
    probably others as well, but I've only tested these ones so far.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit df7e7d6a8973dee3ea8bcc849ce5c8bb94210edc
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:51 2007 +0200

    m68k: remove unused adb.h
    
    The asm-m68k/adb.h header is unused. Some definitions are wrong and the rest
    are duplicated in linux/adb.h. Remove it.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3f5d987e62412ce6540b97b622b03ca9c1677eee
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:32:50 2007 +0200

    m68k: Amiga A2065 and Ariadne TX statistics
    
    Add missing code to the Amiga A2065 and Ariadne drivers to update
    net_device_stats.tx_bytes.
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit bff832cda7bd1a861fd43813c3037119e50e7d93
Author: Finn Thain <fthain@telegraphics.com.au>
Date:   Tue May 1 22:32:49 2007 +0200

    m68k: pmu_queue_request() declaration conflict
    
    Fixes a "static qualifier follows non-static qualifier" error from gcc 4.
    
    Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b312b38c7411d4a2fff3fcdff13556b090f80f25
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:32:48 2007 +0200

    m68k: Atari SCSI workqueue updates
    
    Workqueue updates for the Atari SCSI driver
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 35bdd52d7401b1208552523d6fa28d4a37dbc74d
Author: Sam Creasey <sammy@sammy.net>
Date:   Tue May 1 22:32:47 2007 +0200

    m68k: Correct number of interrupts for Sun3
    
    Only attempt to initialize the amount of interrupts a sun3 actually has...
    
    Signed-off-by: Sam Creasey <sammy@sammy.net>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit d6713b4091a99fa2af2fabdcd2f3fb97f32ecf2e
Author: Roman Zippel <zippel@linux-m68k.org>
Date:   Tue May 1 22:32:45 2007 +0200

    m68k: early parameter support
    
    Add early parameter support and convert current users to it.
    
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit f8744bc95dac461cef40df7143756d1bfa393991
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:32:44 2007 +0200

    hilkbd: Kill compiler warning and fix comment dyslexia
    
    hilkbd: Kill compiler warning and fix comment dyslexia
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 6ff5801acbb643e81d3420ac0f37c96089309063
Author: Roman Zippel <zippel@linux-m68k.org>
Date:   Tue May 1 22:32:43 2007 +0200

    m68k: reformat various m68k files
    
    Reformat various m68k files, so they actually look like Linux sources.
    
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit b3e2fd9cebcf4e82d0306fe7e796eeca5aac0614
Author: Roman Zippel <zippel@linux-m68k.org>
Date:   Tue May 1 22:32:42 2007 +0200

    lockdep: Add missing disable/enable irq variant
    
    Add missing disable/enable irq variant
    
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 39ad2cb352729a8b57803737905caae1e1d1942a
Author: Matthias Urlichs <smurf@smurf.noris.de>
Date:   Tue May 1 22:32:41 2007 +0200

    m68k: Mac89x0 Ethernet netif updates
    
    Macintosh CS89x0 Ethernet: Netif updates
    Addition of netif_stop_queue() before transmission by Michael Schmitz
    skb_copy_{from,to}_linear_data() conversion by Geert Uytterhoeven
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit ec0203e75360638237299b78a7b0d343301075b3
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Date:   Tue May 1 22:32:40 2007 +0200

    m68k: CROSS_COMPILE = m68k-linux-gnu-
    
    Recent cross-compilers are called m68k-linux-gnu-gcc instead of m68k-linux-gcc
    
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit a100501212f2e26bb6d70bfb5c55eefd90e22b65
Author: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
Date:   Tue May 1 22:32:39 2007 +0200

    m68k: Atari fb revival
    
    Update the atari fb to 2.6 by Michael Schmitz,
    Reformatting and rewrite of bit plane functions by Roman Zippel,
    A few more fixes by Geert Uytterhoeven.
    
    Signed-off-by: Michael Schmitz <schmitz@debian.org>
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c04cb856e20a8bf68762d60737b84328c1ab5900
Author: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
Date:   Tue May 1 22:32:38 2007 +0200

    m68k: Atari keyboard and mouse support.
    
    Atari keyboard and mouse support.
    (reformating and Kconfig fixes by Roman Zippel)
    
    Signed-off-by: Michael Schmitz <schmitz@debian.org>
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 3130d905ba86d5f2636b2f45d5beefe82cb03df6
Author: Roman Zippel <zippel@linux-m68k.org>
Date:   Tue May 1 22:32:37 2007 +0200

    m68k: Atari SCSI driver compile fixes
    
    Atari SCSI driver compile fixes
    
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit c28bda25175913c88396b643813321ef9cffe663
Author: Roman Zippel <zippel@linux-m68k.org>
Date:   Tue May 1 22:32:36 2007 +0200

    m68k: Reformat the Atari SCSI driver
    
    Reformat the Atari SCSI driver
    
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fb810d121bceb945c5e576356bccba11cbfad7e3
Author: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
Date:   Tue May 1 22:32:35 2007 +0200

    m68k: Atari SCSI revival
    
    SCSI should be working on a TT (but someone should really try!) but causes
    trouble on a Falcon (as in: it ate a filesystem of mine) at least when
    used concurrently with IDE. I have the notion it's because locking of the
    ST-DMA interrupt by IDE is broken in 2.6 (the IDE driver always complains
    about trying to release an already-released ST-DMA). Needs more work, but
    that's on the IDE or m68k interrupt side rather than SCSI.
    
    Signed-off-by: Michael Schmitz <schmitz@debian.org>
    Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
    Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 8bc8493063f938c932819958a7b5a0d56046bc96
Author: Stuart MacDonald <stuartm@connecttech.com>
Date:   Fri May 4 16:00:03 2007 -0400

    MAINTAINER change for Connect Tech Inc
    
    I am no longer with CTI. The Support Department will handle all
    inquiries regarding the WH.
    
    Signed-off-by: Stuart MacDonald <stuartm@connecttech.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 7bb078cba9ef55d810275b533747fa96a12e1823
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:22 2007 +0200

    [Bluetooth] Correct SCO buffer for another Broadcom based dongle
    
    The SCO buffer size values for Bluetooth chips from Broadcom are wrong
    and the USB Bluetooth driver has to set a quirk to correct these SCO
    buffer size values.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit c51bd3d3d883d900efbeab3697ae182d60bdd217
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:17 2007 +0200

    [Bluetooth] Add support for Targus ACB10US USB dongle
    
    This patch adds the vendor and product id of the Targus ACB10US
    dongle and sets a flag to send HCI_Reset as the first command.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org

commit 9cf5b0ea3a7f1432c61029f7aaf4b8b338628884
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:13 2007 +0200

    [Bluetooth] Disconnect L2CAP connection after last RFCOMM DLC
    
    The RFCOMM specification says that the device closing the last DLC on
    a particular session is responsible for closing the multiplexer by
    closing the corresponding L2CAP channel.
    
    Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit 77f2a45fa1ba33147fd6cc8ae546188504a822cd
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:10 2007 +0200

    [Bluetooth] Check that device is in rfcomm_dev_list before deleting
    
    If RFCOMM_RELEASE_ONHUP flag is on and rfcomm_release_dev is called
    before connection is closed, rfcomm_dev is deleted twice from the
    rfcomm_dev_list and refcount is messed up. This patch adds a check
    before deleting device that the device actually is listed.
    
    Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit 48db9ca4f2ac9f39eb90ccb12ad3ca7b645a552c
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:06 2007 +0200

    [Bluetooth] Use in-kernel sockets API
    
    The kernel provides a new convenient way to access the sockets API for
    in-kernel users. It is a good idea to actually use it.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit 53c1d4b0b22243c093ded25aaa01c8ff8ab6e6b3
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:36:03 2007 +0200

    [Bluetooth] Attach host adapters to the Bluetooth bus
    
    The Bluetooth host adapters are attached to the Bluetooth class and the
    low-level connections are children of these class devices. Having class
    devices as parent of bus devices breaks a lot of reasonable assumptions
    about sysfs. The host adapters should be attached to the Bluetooth bus
    to simplify the dependency resolving. For compatibility an additional
    symlink from the Bluetooth class will be used.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit 0878b6667f28772aa7d6b735abff53efc7bf6d91
Author: Marcel Holtmann <marcel@holtmann.org>
Date:   Sat May 5 00:35:59 2007 +0200

    [Bluetooth] Fix L2CAP and HCI setsockopt() information leaks
    
    The L2CAP and HCI setsockopt() implementations have a small information
    leak that makes it possible to leak kernel stack memory to userspace.
    
    If the optlen parameter is 0, no data will be copied by copy_from_user(),
    but the uninitialized stack buffer will be read and stored later. A call
    to getsockopt() can now retrieve the leaked information.
    
    To fix this problem the stack buffer given to copy_from_user() must be
    initialized with the current settings.
    
    Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

commit 07d939677166cc4f000c767196872a9becc2697b
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri May 4 13:55:27 2007 -0700

    [SCTP]: Set assoc_id correctly during INIT collision.
    
    During the INIT/COOKIE-ACK collision cases, it's possible to get
    into a situation where the association id is not yet set at the time
    of the user event generation.  As a result, user events have an
    association id set to 0 which will confuse applications.
    
    This happens if we hit case B of duplicate cookie processing.
    In the particular example found and provided by Oscar Isaula
    <Oscar.Isaula@motorola.com>, flow looks like this:
    A				B
    ---- INIT------->  (lost)
    	    <---------INIT------
    ---- INIT-ACK--->
    	    <------ Cookie ECHO
    
    When the Cookie Echo is received, we end up trying to update the
    association that was created on A as a result of the (lost) INIT,
    but that association doesn't have the ID set yet.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 827bf12236fbafc02bc899aec1b37c342c8cf4e5
Author: Sridhar Samudrala <sri@us.ibm.com>
Date:   Fri May 4 13:36:30 2007 -0700

    [SCTP]: Re-order SCTP initializations to avoid race with sctp_rcv()
    
    Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ce5325c1338acf965f4300f4976eac2129aeb439
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri May 4 13:34:49 2007 -0700

    [SCTP]: Fix the SO_REUSEADDR handling to be similar to TCP.
    
    Update the SO_REUSEADDR handling to also check for listen state.  This
    was muliple listening server sockets can't be created and they will
    not steal packets from each other.
    
    Reported by Paolo Galtieri <pgaltieri@mvista.com>
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 16d00fb7765a43a1b05989062e985d283b3a1f2d
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri May 4 13:34:09 2007 -0700

    [SCTP]: Verify all destination ports in sctp_connectx.
    
    We need to make sure that all destination ports are the same, since
    the association really must not connect to multiple different ports
    at once.  This was reported on the sctp-impl list.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5a6d34162f5c6f522f857df274f1c8240f161e11
Author: Jamal Hadi Salim <hadi@cyberus.ca>
Date:   Fri May 4 12:55:39 2007 -0700

    [XFRM] SPD info TLV aggregation
    
    Aggregate the SPD info TLVs.
    
    Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit af11e31609d93765c1b22611592543e028f7aa54
Author: Jamal Hadi Salim <hadi@cyberus.ca>
Date:   Fri May 4 12:55:13 2007 -0700

    [XFRM] SAD info TLV aggregationx
    
    Aggregate the SAD info TLVs.
    
    Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 224711df5c00f7540b89f32a8225866031977f17
Author: David Howells <dhowells@redhat.com>
Date:   Fri May 4 12:41:11 2007 -0700

    [AF_RXRPC]: Sort out MTU handling.
    
    Sort out the MTU determination and handling in AF_RXRPC:
    
     (1) If it's present, parse the additional information supplied by the peer at
         the end of the ACK packet (struct ackinfo) to determine the MTU sizes
         that peer is willing to support.
    
     (2) Initialise the MTU size to that peer from the kernel's routing records.
    
     (3) Send ACKs rather than ACKALLs as the former carry the additional info,
         and the latter do not.
    
     (4) Declare the interface MTU size in outgoing ACKs as a maximum amount of
         data that can be stuffed into an RxRPC packet without it having to be
         fragmented to come in this computer's NIC.
    
     (5) If sendmsg() is given MSG_MORE then it should allocate an skb of the
         maximum size rather than one just big enough for the data it's got left
         to process on the theory that there is more data to come that it can
         append to that packet.
    
         This means, for example, that if AFS does a large StoreData op, all the
         packets barring the last will be filled to the maximum unfragmented size.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit da99f0565477899f08b76ffcb32afbf6fa95d64a
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri May 4 12:23:27 2007 -0700

    [AF_IUCV/IUCV] : Add missing section annotations
    
    Add missing section annotations and found and fixed some
    Coding Style issues.
    
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>

commit 561e036006dc4078446815613781c6c33441dd3b
Author: Jennifer Hunt <jenhunt@us.ibm.com>
Date:   Fri May 4 12:22:07 2007 -0700

    [AF_IUCV]: Implementation of a skb backlog queue
    
    With the inital implementation we missed to implement a skb backlog
    queue . The result is that socket receive processing tossed packets.
    Since AF_IUCV connections are working synchronously it leads to
    connection hangs. Problems with read, close and select also occured.
    
    Using a skb backlog queue is fixing all of these problems .
    
    Signed-off-by: Jennifer Hunt <jenhunt@us.ibm.com>
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9e71efcd6d659afb9d390eea69b558a7432ba23e
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri May 4 12:15:11 2007 -0700

    [NETLINK]: Remove bogus BUG_ON
    
    Remove bogus BUG_ON(mutex_is_locked(nlk_sk(sk)->cb_mutex)), when the
    netlink_kernel_create caller specifies an external mutex it might
    validly be locked.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 84dde76c4a2d99ed2d7de6ec82c53b56620900a3
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Fri May 4 14:44:06 2007 -0400

    NFS: Fix a compile glitch on 64-bit systems
    
    fs/nfs/pagelist.c:226: error: conflicting types for 'nfs_pageio_init'
    include/linux/nfs_page.h:80: error: previous declaration of 'nfs_pageio_init' was here
    
    Thanks to Andrew for spotting this...
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit cf8ba7a95511b86608acb481ad96219fe2da4b3a
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri May 4 18:48:28 2007 +0200

    [S390] add hardware capability support (ELF_HWCAP).
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit e29630627702571eb2b2a0955605b7f8971c82c1
Author: Michael Holzheu <holzheu@de.ibm.com>
Date:   Fri May 4 18:47:53 2007 +0200

    [S390] tape: New read configuration data.
    
    Instead of the deprecated read_conf_data(), implement a new function
    tape_3590_read_dev_chars().
    
    Signed-off-by: Michael Holzheu <holzheu@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 6c82a8af923b25c2a9a41b7d4ba0bb2806ecc3dc
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri May 4 18:47:52 2007 +0200

    [S390] qeth: New read configuration data.
    
    Instead of the deprecated read_conf_data(), implement a new function
    qeth_read_conf_data().
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 17283b56eceb6b7d9cc48dc74759a2450699c22a
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri May 4 18:47:51 2007 +0200

    [S390] dasd: New read device characteristics and read configuration data.
    
    Instead of the deprecated read_dev_chars() and read_conf_data_lpm(),
    implement dasd_generic_read_dev_chars() and dasd_eckd_read_conf_lpm().
    These should even recover better from error than the original cio
    functions.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 52706ec903dcc7679acf5b93400d68fbc5384553
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri May 4 18:47:50 2007 +0200

    [S390] cio: Deprecate read_dev_chars() and read_conf_data{,_lpm}().
    
    These helper functions are a leftover from 2.4 sync I/O and are a
    notorious source for bugs. They lead to device driver specific code
    creeping into cio, and some issues can't really be fixed at all.
    
    Device drivers can easily implement those functions themselves in a
    more robust manner, so let's get rid of them.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 00c0c6466c66bdf05f2a3dcf59e6895179ea8b76
Author: Ursula Braun <braunu@de.ibm.com>
Date:   Fri May 4 18:47:49 2007 +0200

    [S390] qdio: make qdio statistics SMP-capable
    
    Use atomic_t/atomic64_t to make qdio performance statistics smp safe.
    Remove temporarily calculation of "total time of inbound actions".
    
    Signed-off-by: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit d4ee453bcfcc0ce76de8522e099868dc440cba23
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri May 4 18:47:48 2007 +0200

    [S390] Export uaccess as non-gpl symbol.
    
    Commit c1821c2e9711adc3cd298a16b7237c92a2cee78d introduced the
    uaccess structure that is used to select the correct set of user
    copy functions for the different execution modes (standard vs.
    noexec vs. z9 optimized user copy). The uaccess symbol is exported
    with EXPORT_SYMBOL_GPL. This breaks all non-gpl modules that use
    user copy. To make them work again change the export to
    EXPORT_SYMBOL.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit f67d1369665b2ce88227c40d9c9a6c8ba16bb866
Author: Jan Glauber <jan.glauber@de.ibm.com>
Date:   Fri May 4 18:47:47 2007 +0200

    [S390] aes-s390 key length.
    
    Register aes-s390 algorithms with the actual supported max keylen size
    
    Signed-off-by: Jan Glauber <jan.glauber@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 33464e3b57834e161add62b499492cf43e35e54c
Author: Christoph Hellwig <hch@lst.de>
Date:   Fri May 4 18:47:46 2007 +0200

    [S390] get rid of kprobes notifier call chain.
    
    And here's a port of the powerpc patch to get rid of the notifier
    chain completely to s390.  It's ontop of Martins patch as that one
    is in mainline already.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit db3459d1a71d885334831cdca6646a48f5ea0483
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Thu May 3 17:39:04 2007 -0700

    [IPV6]: Some cleanups in include/net/ipv6.h
    
    1) struct ip6_flowlabel : moves 'users' field to avoid two 32bits
       holes for 64bit arches. Shrinks by 8 bytes sizeof(struct
       ip6_flowlabel)
    
    2) ipv6_addr_cmp() and ipv6_addr_copy() dont need (void *) casts :
       Compiler might take into account natural alignement of in6_addr
       structs to emit better code for memcpy()/memcmp() Casts to (void *)
       force byte accesses.
    
    3) ipv6_addr_prefix() optimization :
    
    Better to clear whole struct, as compiler can emit better code for
    memset(addr, 0, 16) (2 stores on x86_64), and avoid some conditional
    branches.
    
    # size vmlinux.after vmlinux.before
       text    data     bss     dec     hex filename
    5262262  647612  557432 6467306  62aeea vmlinux.after
    5262550  647612  557432 6467594  62b00a vmlinux.before
    
    thats 288 bytes saved.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b40b4f79ce789e9e28d382c85006f62be2725282
Author: Srinivas Aji <Aji_Srinivas@emc.com>
Date:   Thu May 3 17:32:28 2007 -0700

    [TCP]: zero out rx_opt in tcp_disconnect()
    
    When the server drops its connection, NFS client reconnects using the
    same socket after disconnecting. If the new connection's SYN,ACK
    doesn't contain the TCP timestamp option and the old connection's did,
    tp->tcp_header_len is recomputed assuming no timestamp header but
    tp->rx_opt.tstamp_ok remains set. Then tcp_build_and_update_options()
    adds in a timestamp option past the end of the allocated TCP header,
    overwriting TCP data, or when the data is in skb_shinfo(skb)->frags[],
    overwriting skb_shinfo(skb) causing a crash soon after. (The issue was
    debugged from such a crash.)
    
    Similarly, wscale_ok and sack_ok also get set based on the SYN,ACK
    packet but not reset on disconnect, since they are zeroed out at
    initialization. The patch zeroes out the entire tp->rx_opt struct in
    tcp_disconnect() to avoid this sort of problem.
    
    Signed-off-by: Srinivas Aji <Aji_Srinivas@emc.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fde82055c1d0e64ff660d83c705db0e1abc9d12e
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 17:23:35 2007 -0700

    [BNX2]: Fix TSO problem with small MSS.
    
    Remove the check for skb->len greater than MTU when doing TSO.  When
    the destination has a smaller MSS than the source, a TSO packet may
    be smaller than the MTU at the source and we still need to process it
    as a TSO packet.
    
    Thanks to Brian Ristuccia <bristuccia@starentnetworks.com> for
    reporting the problem.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7562f876cd93800f2f8c89445f2a563590b24e09
Author: Pavel Emelianov <xemul@openvz.org>
Date:   Thu May 3 15:13:45 2007 -0700

    [NET]: Rework dev_base via list_head (v3)
    
    Cleanup of dev_base list use, with the aim to simplify making device
    list per-namespace. In almost every occasion, use of dev_base variable
    and dev->next pointer could be easily replaced by for_each_netdev
    loop. A few most complicated places were converted to using
    first_netdev()/next_netdev().
    
    Signed-off-by: Pavel Emelianov <xemul@openvz.org>
    Acked-by: Kirill Korotaev <dev@openvz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 03fba0479600114f32d29eee74ca3eaa364606bf
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Thu May 3 13:28:35 2007 -0700

    [TCP] Highspeed: Limited slow-start is nowadays in tcp_slow_start
    
    Reuse limited slow-start (RFC3742) included into tcp_cong instead
    of having another implementation in High Speed TCP.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 72fbaeb623971c321112de7fe3fa4e24e12ca59e
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:25:32 2007 -0700

    [BNX2]: Update version and reldate.
    
    Update version to 1.5.10.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 883e51511815930154c64a2645f4df112aa066fb
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:25:11 2007 -0700

    [BNX2]: Print bus information for PCIE devices.
    
    Fix the code to print PCI or PCIE bus information for all devices.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8e6a72c435bf8bdd738ad08a746d697abedacfc0
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:24:48 2007 -0700

    [BNX2]: Add 1-shot MSI handler for 5709.
    
    The 5709 supports the one-shot MSI handler similar to some of the tg3
    chips.  In this mode, the MSI disables itself automatically until it
    is re-enabled at the end of NAPI poll.
    
    Put the request_irq/free_irq logic in common procedures.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit da3e4fbed21a5d7edab10ffb77a8c04a725f9eff
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:24:23 2007 -0700

    [BNX2]: Restructure PHY event handling.
    
    Restructure by adding bnx2_phy_event_is_set() to make code cleaner
    and easier to understand.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1b8227c48e164655f02aa0eff55862af2d05da51
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:24:05 2007 -0700

    [BNX2]: Add indirect spinlock.
    
    The indirect register access method will be used by more than one
    caller in BH context (NAPI poll and timer), so a spinlock is required.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 27a005b883984ef3a3cf24e7ddd78eb78902f494
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:23:41 2007 -0700

    [BNX2]: Add support for 5709 Serdes.
    
    Add PCI ID and code to support the 5709 Serdes PHY.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 605a9e20aaea23f31a5403e969bd4ab4d0405dab
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:23:13 2007 -0700

    [BNX2]: Re-structure the 2.5G Serdes code.
    
    Add some common procedures to handle enabling and disabling 2.5G.
    Add some missing code to resolve flow control.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ca58c3af99b15f729e56dffe9b74b8b2ce157e8d
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:22:52 2007 -0700

    [BNX2]: Put MII register offsets in the bnx2 struct.
    
    The 5709 Serdes device uses non-standard MII register offsets.  This
    re-structuring will make it easier to support 5709 Serdes.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4666f87a82cf74b63737a7f55a8b3b057a7b83df
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:22:28 2007 -0700

    [BNX2]: Add ipv6 TSO and checksum for 5709.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 874bb672fdd939aec37ad3a06b50be4ff8b4feac
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:21:48 2007 -0700

    [BNX2]: Update 5709 firmware.
    
    Add ipv6 TSO support in firmware.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 41ccf61cf09c9a042415c04ccf0dc3c198623a9a
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:21:13 2007 -0700

    [BNX2]: Update 5708 firmware.
    
    This fixes the problem of not counting all dropped multicast packets.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 30c517b29130ddede977300235afcda1c256530b
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:20:40 2007 -0700

    [BNX2]: Save PCI state during suspend.
    
    This is needed to save the MSI state which will be lost during
    suspend.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1b2f922f6869eb13dadfe1ba3f8337bd42e50a2e
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:20:19 2007 -0700

    [BNX2]: Fix race conditions when calling register_netdev().
    
    Hot-plug scripts can call bnx2_open() as soon as register_netdev() is
    called in bnx2_init_one().  We need to call pci_set_drvdata() and
    setup everything before calling register_netdev(). netif_carrier_off()
    also needs to be moved to bnx2_open() to avoid race conditions with
    the irq.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 40453c839fdbf86738256cae1c9c1ebe55645d4a
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:19:18 2007 -0700

    [BNX2]: Add 40-bit DMA workaround for 5708.
    
    The internal PCIE-to-PCIX bridge of the 5708 has the same 40-bit DMA
    limitation as some of the tg3 chips.  Set dma_mask and persistent DMA
    mask to 40-bit to workaround.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5bae30c96a3bd09563e484b4ac7211b4b4664679
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:18:46 2007 -0700

    [BNX2]: Fix register and memory test on 5709.
    
    Tweak registers and memory test range for 5709.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit dad3e452dacd3c6c637e2f7c6469556cc8ffcd94
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:18:03 2007 -0700

    [BNX2]: Block MII access when ifdown.
    
    The device may be in D3hot state and should not allow MII register
    access.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 427c2196b92697a4a8ee87959ebc16bfac024f6b
Author: Michael Chan <mchan@broadcom.com>
Date:   Thu May 3 13:17:25 2007 -0700

    [ETHTOOL]: Add 2.5G bit definitions.
    
    Add 2.5G supported and advertising bit definitions.  2.5G is supported
    by the bnx2 driver.
    
    Signed-off-by: Michael Chan <mchan@broadcom.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 40435792525c49cf126ba92d223e877acb5ce021
Author: Nicolas Pitre <nico@cam.org>
Date:   Wed Feb 21 15:58:13 2007 +0100

    [ARM] 4227/1: minor head.S fixups
    
    Let's surround constructs like:
    
    	orr	r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
    
    between .if .endif since (KERNEL_RAM_PADDR & 0x00f00000) is 0 in 99% of
    all cases.
    
    Also let's mask PHYS_OFFSET with 0x00f00000 instead of 0x00e00000.
    Section mappings are really 1MB not 2MB and the 2MB groupping is
    a higher level issue already much better enforced with
    
    #if (PHYS_OFFSET & 0x001fffff)
    #error "PHYS_OFFSET must be at an even 2MiB boundary!"
    #endif
    
    at the top of the file.
    
    Signed-off-by: Nicolas Pitre <nico@cam.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit ff4bfb2163e8914332267be3758eb28239460316
Author: Sascha Hauer <sascha@saschahauer.de>
Date:   Thu Apr 26 08:26:13 2007 +0100

    [ARM] 4328/1: Move i.MX UART regs to driver
    
    This patch moves the i.MX UART register descriptions from
    include/asm-arm/arch-imx/imx-regs.h to the serial driver itself.
    This helps using the driver on other architectures like mx31
    
    Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit fe7fdb80e9e576e181b189d0fae62d35cb30fe4d
Author: Sascha Hauer <sascha@saschahauer.de>
Date:   Thu Apr 26 08:34:41 2007 +0100

    [ARM] 4329/1: fix position of NETX_SYSTEM_REG
    
    This patch fixes the position of the netx reset control register
    
    Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 93afa75230f5969d559386e52819f54bb1182327
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Thu May 3 14:39:41 2007 +0100

    [ARM] 4355/2: AT91: SAM9260-EK and SAM9263-EK board updates
    
    Various small changes for the Atmel AT91SAM9260-EK and AT91SAM9263-EK
    boards.
    
    SAM9260-EK:
      - Register I2C device.
    
    SAM9263-EK:
      - Add platform_data and register MACB device.
        (Patch by Nicolas Ferre)
      - Add platform_data and register AC97 device.
        (Patch by Nicolas Ferre)
      - Register I2C device.
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 5559bca8e66f968192a5416d953c88cc3389cb22
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Thu May 3 10:47:37 2007 +0100

    [ARM] ecard: Convert card type enum to a flag
    
    'type' in the struct expansion_card is only used to indicate
    whether this card is an EASI card or not.  Therefore, having
    it as an enum is wasteful (and introduces additional noise
    when we come to remove the enum.)  Convert it to a mere flag
    instead.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit c0b04d1b2c427629b2dbe066422a507ad855bf61
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Thu May 3 10:20:47 2007 +0100

    [ARM] ecard: Move private ecard junk out of asm/ecard.h
    
    Move ecard.c private junk from asm/ecard.h to a local header file.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit e6aeb47da6e02ec9807d30a368d4fc37972b022f
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Thu May 3 10:55:46 2007 +0100

    [ARM] ecard: silence new warning caused by previous commit
    
    PTR_ERR()'s type is unsigned long, so formats when printing
    must be %ld, not %d.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 134c99e907ef2572cdaa148c191984b95d671981
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Thu Apr 26 00:04:40 2007 -0700

    [ARM] ecard: convert to use the kthread API
    
    This patch modifies the startup of kecardd to use kthread_run not a
    kernel_thread combination of kernel_thread and daemonize.  Making the code
    slightly simpler and more maintainable.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 73b6a2be8b29b2067aa3c0f1d6433b6148d88705
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Thu May 3 09:55:52 2007 +0100

    [ARM] Add support for ICSIDE interface on RiscPC
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit a17dba8df9848c548912fbe9bf4b28c5a67c5413
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 15:55:06 2007 +0100

    [ARM] Add platform support for PATA on RiscPC
    
    Add pata_platform device for RiscPC, thereby converting the primary
    IDE channel on the machine to PATA.
    
    Acked-by: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 69f4f331a0f78470f0bc42ba8db8d6cdd9cae4a9
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Mon Apr 2 13:53:15 2007 +0100

    [ARM] Set coherent DMA mask for Acorn expansion cards
    
    Although expansion cards can't do bus-master DMA, subsystems
    want to be able to use coherent memory for DMA purposes to
    these cards.  Therefore, set the coherent DMA mask to allow
    such memory to be allocated.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 03abeac0a222060ae8f02e8359c285df0971437e
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Thu May 3 12:26:24 2007 +0100

    [ARM] 4357/1: AT91: Support slower serial baud-rates
    
    Allow slower serial baud-rates by switching the UART clock from MCK to
    MCK/8.
    
    Based on patches by Mike Wolfram and Russell King.
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7c73628f24ea73479232d1b608359aa7d8d2c95d
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 18:00:45 2007 +0100

    [ARM] 4354/1: AT91: Support ADS7846 touchsceen on SAM9263-EK board
    
    Add support for the ADS7846 Touchscreen found on the Atmel
    AT91SAM9263-EK board.
    
    Signed-off-by: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 235227285b3e4bae616be5720e6dedb49b914e9d
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 17:58:51 2007 +0100

    [ARM] 4353/1: AT91: Support ADS7846 touchsceen on SAM9261-EK board
    
    Add support for the ADS7846 Touchscreen found on the Atmel
    AT91SAM9261-EK board.
    
    Original patch by Morten Larsen.
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7776a94c311504f26e73060920dfb3ccf02786b7
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 17:46:49 2007 +0100

    [ARM] 4352/1: AT91: Platform data for LCD and AC97.
    
    Define resources, platform_device and device registration functions for
    the LCD and AC97 controllers on the AT91SAM9263.
    Also update the AT91SAM9261 to use the common atmel_lcdfb driver.
    
    Signed-off-by: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit e8788babe6ddb35ab041a146d6b3e18874513566
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 17:14:57 2007 +0100

    [ARM] 4351/1: AT91: Define rest of peripheral clocks
    
    Define and register the remaining peripheral clocks for the AT91
    processors.
    
    AT91SAM9261 clocks patch by Ivan Zhakov.
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit ce813b97e58cdfd780b8f8b4e15cd3ebfe940415
Author: Andrew Victor <andrew@sanpeople.com>
Date:   Wed May 2 17:08:13 2007 +0100

    [ARM] 4350/1: AT91: Hardware header for ADC peripheral
    
    Definitions for Analog-to-Digital Converter (ADC) found on the Atmel
    AT91SAM9260 processor.
    
    Signed-off-by: Andrew Victor <andrew@sanpeople.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 99cce8f7b10716f8fdbaca21a7f3ba000119ad3b
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Thu May 3 00:18:34 2007 +0100

    [ARM] 4356/1: arm: fix handling of svc mode undefined instructions
    
    Now that do_undefinstr handles kernel and user mode undefined
    instruction exceptions it must not assume that interrupts are enabled at
    entry.
    
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit d2dd8b1fed314d22c50965f78f6895117c4abfc8
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Wed May 2 17:47:47 2007 +0100

    [ARM] 4342/2:  iop13xx: add resource definitions for the tpmi units
    
    The tpmi units interface with the SAS controller on iop348.
    
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit e90ddd813df7897af34226ed1cd442f7a182816e
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Wed May 2 17:59:44 2007 +0100

    [ARM] 4348/4:  iop3xx: Give Linux control over PCI initialization
    
    Currently the iop3xx platform support code assumes that RedBoot is the
    bootloader and has already initialized the ATU.  Linux should handle this
    initialization for three reasons:
    
    1/ The memory map that RedBoot sets up is not optimal (page_to_dma and
    virt_to_phys return different addresses).  The effect of this is that using
    the dma mapping API for the internal bus dma units generates pci bus
    addresses that are incorrect for the internal bus.
    
    2/ Not all iop platforms use RedBoot
    
    3/ If the ATU is already initialized it indicates that the iop is an add-in
    card in another host, it does not own the PCI bus, and should not be
    re-initialized.
    
    Changelog:
    * rather than change nr_controllers to zero, simply do not call
      pci_common_init
    
    Cc: Lennert Buytenhek <kernel@wantstofly.org>
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit fc38582db98533066f4ba64f948720483fbfe7b2
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:36:16 2007 -0700

    [NETFILTER]: bridge netfilter: consolidate header pushing/pulling code
    
    Consolidate the common push/pull sequences into a few helper functions.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cfd6c38096d75c8b86782683c5f45c415a505b78
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Thu May 3 03:35:31 2007 -0700

    [NETFILTER]: sip: Fix RTP address NAT
    
    I needed to use this recently to talk to a Cisco server.  In my case
    I only did SNAT while the Cisco server used a different address for
    RTP traffic than the one for SIP.  I discovered that nf_nat_sip NATed
    the RTP address to the SIP one which was unnecessary but OK.  However,
    in doing so it did not DNAT the destination address on the RTP traffic
    to the Cisco back to the original RTP address.
    
    This patch corrects this by noting down the RTP address and using it
    when the expectation fires.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c2a1910b06fed96db77bb358c18c52a1fcf2b7fe
Author: Jorge Boncompte <jorge@dti2.net>
Date:   Thu May 3 03:34:42 2007 -0700

    [NETFILTER]: nf_nat_proto_gre: do not modify/corrupt GREv0 packets through NAT
    
    While porting some changes of the 2.6.21-rc7 pptp/proto_gre conntrack
    and nat modules to a 2.4.32 kernel I noticed that the gre_key function
    returns a wrong pointer to the GRE key of a version 0 packet thus
    corrupting the packet payload.
    
    The intended behaviour for GREv0 packets is to act like
    nf_conntrack_proto_generic/nf_nat_proto_unknown so I have ripped the
    offending functions (not used anymore) and modified the
    nf_nat_proto_gre modules to not touch version 0 (non PPTP) packets.
    
    Signed-off-by: Jorge Boncompte <jorge@dti2.net>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 327850070b019a96853c533c152688546201c286
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:34:03 2007 -0700

    [NETFILTER]: ipt_DNAT: accept port randomization option
    
    Also accept the --random option for DNAT to allow randomly selecting a
    destination port from the given range.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0ec96822d5c0df77107c03b8d9a81a436ab707fc
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Thu May 3 03:30:34 2007 -0700

    [TCP]: Use S+L catcher only with SACK for now
    
    TCP has a transitional state when SACK is not in use during
    which this invariant is temporarily broken. Without SACK,
    tcp_clean_rtx_queue does not decrement sacked_out. Therefore
    calls to tcp_sync_left_out before sacked_out is again
    corrected by tcp_fastretrans_alert can trigger this trap as
    sacked_out still has couple of segments that are already out
    of window.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ec9c948546a84d0dcee851be1009a8066958e69d
Author: David Howells <dhowells@redhat.com>
Date:   Thu May 3 03:29:41 2007 -0700

    [AFS]: Adjust the new netdevice scanning code
    
    Adjust the new netdevice scanning code provided by Patrick McHardy:
    
     (1) Restore the function banner comments that were dropped.
    
     (2) Rather than using an array size of 6 in some places and an array size of
         ETH_ALEN in others, pass a pointer instead and pass the array size
         through so that we can actually check it.
    
     (3) Do the buffer fill count check before checking the for_primary_ifa
         condition again.  This permits us to skip that check should maxbufs be
         reached before we run out of interfaces.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit dc1f6bff6a9d6733a07b9b97905bc824c055e8f4
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:28:49 2007 -0700

    [AFS]: Replace rtnetlink client by direct dev_base walking
    
    Replace the large and complicated rtnetlink client by two simple
    functions for getting the MAC address for the first ethernet device
    and building a list of IPv4 addresses.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4e9cac2ba437fcb093c7417b1cd91a77ebd1756a
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:28:13 2007 -0700

    [NET]: Add __dev_getfirstbyhwtype
    
    Add __dev_getfirstbyhwtype for callers that don't want a reference but
    some data from the device and thus need to take the rtnl anyway.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5b35fad9d4fc2fcaf5c23887c1de1bc3eb28ab8c
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:27:39 2007 -0700

    [AFS]: Fix memory leak in SRXAFSCB_GetCapabilities
    
    The interface array is not freed on exit.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 188ccb5583b8f501e1d0f5ba4f056afa141694e7
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu May 3 03:27:01 2007 -0700

    [NETLINK]: Fix use after free in netlink_recvmsg
    
    When the user passes in MSG_TRUNC the skb is used after getting freed.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3f660d66dfbc13ea4b61d3865851b348444c24b4
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Thu May 3 03:17:14 2007 -0700

    [NETLINK]: Kill CB only when socket is unused
    
    Since we can still receive packets until all references to the
    socket are gone, we don't need to kill the CB until that happens.
    This also aligns ourselves with the receive queue purging which
    happens at that point.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit be52178b9f73969b583c6a781ca613f4e601221a
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Thu May 3 03:16:20 2007 -0700

    [NET] skbuff: fix kernel-doc
    
    Fix skbuff.h kernel-doc:
    linux-2.6.21-git4//include/linux/skbuff.h:316): No description found for parameter 'transport_header'
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 825e7d45cfa41bc96dd8ac4978b4d458a9ad5770
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu May 3 03:13:35 2007 -0700

    [TCP]: Delete unused header file net/ipv4/tcp_yeah.h.
    
    Delete the apparently unused header file net/ipv4/tcp_yeah.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fbb3fcba72ff52ee3d9990c9dec0c95cd9d0ce17
Author: David Howells <dhowells@redhat.com>
Date:   Thu May 3 03:12:46 2007 -0700

    [AFS]: Fix use of __exit functions from __init path
    
    Fix use of __exit functions from __init path.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 80c72fe415698049a477314ac82790c1af0fa7e3
Author: David Howells <dhowells@redhat.com>
Date:   Thu May 3 03:11:29 2007 -0700

    [AFS/AF_RXRPC]: Miscellaneous fixes.
    
    Make miscellaneous fixes to AFS and AF_RXRPC:
    
     (*) Make AF_RXRPC select KEYS rather than RXKAD or AFS_FS in Kconfig.
    
     (*) Don't use FS_BINARY_MOUNTDATA.
    
     (*) Remove a done 'TODO' item in a comemnt on afs_get_sb().
    
     (*) Don't pass a void * as the page pointer argument of kmap_atomic() as this
         breaks on m68k.  Patch from Geert Uytterhoeven <geert@linux-m68k.org>.
    
     (*) Use match_*() functions rather than doing my own parsing.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ef4533f8af7a8798cb8f52b06f47acf0c0d2d767
Author: David Howells <dhowells@redhat.com>
Date:   Thu May 3 03:10:39 2007 -0700

    [AFS]: Make the match_*() functions take const options.
    
    Make the match_*() functions take a const pointer to the options table
    and make strings pointers in the options table const too.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 709525fad8a925de16938caf7fce3bf601ef869c
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Thu May 3 03:08:43 2007 -0700

    [IPV6]: Get rid of __HAVE_ARCH_ADDR_SET.
    
    __HAVE_ARCH_ADDR_SET seems unused these days, just get rid of it.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2ff81f70b56dc1cdd3bf2f08414608069db6ef1a
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Apr 29 16:25:49 2007 +0300

    KVM: Remove unused 'instruction_length'
    
    As we no longer emulate in userspace, this is meaningless.  We don't
    compute it on SVM anyway.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 02c83209726270ddf9597deabc45e08f6fc3942c
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Apr 29 15:02:17 2007 +0300

    KVM: Don't require explicit indication of completion of mmio or pio
    
    It is illegal not to return from a pio or mmio request without completing
    it, as mmio or pio is an atomic operation.  Therefore, we can simplify
    the userspace interface by avoiding the completion indication.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit e7df56e4a00358b6975fae3b70dc9df1282d427a
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 14 15:54:54 2007 +0200

    KVM: Remove extraneous guest entry on mmio read
    
    When emulating an mmio read, we actually emulate twice: once to determine
    the physical address of the mmio, and, after we've exited to userspace to
    get the mmio value, we emulate again to place the value in the result
    register and update any flags.
    
    But we don't really need to enter the guest again for that, only to take
    an immediate vmexit.  So, if we detect that we're doing an mmio read,
    emulate a single instruction before entering the guest again.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 94dfbdb3894eda2f673b70e20da2743c4a8d3968
Author: Anthony Liguori <aliguori@us.ibm.com>
Date:   Sun Apr 29 11:56:06 2007 +0300

    KVM: SVM: Only save/restore MSRs when needed
    
    We only have to save/restore MSR_GS_BASE on every VMEXIT.  The rest can be
    saved/restored when we leave the VCPU.  Since we don't emulate the DEBUGCTL
    MSRs and the guest cannot write to them, we don't have to worry about
    saving/restoring them at all.
    
    This shaves a whopping 40% off raw vmexit costs on AMD.
    
    Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 2807696c3791d6dd1dcf20f022eaa2dc7615bc5d
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sat Apr 28 21:20:48 2007 +0200

    KVM: fix an if() condition
    
    It might have worked in this case since PT_PRESENT_MASK is 1, but let's
    express this correctly.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 2ab455ccceb07945368709ba852e49f4c3119331
Author: Anthony Liguori <aliguori@us.ibm.com>
Date:   Fri Apr 27 09:29:49 2007 +0300

    KVM: VMX: Add lazy FPU support for VT
    
    Only save/restore the FPU host state when the guest is actually using the
    FPU.
    
    Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 25c4c2762e31a75403eca0dd59f2cab85e3a2532
Author: Anthony Liguori <aliguori@us.ibm.com>
Date:   Fri Apr 27 09:29:21 2007 +0300

    KVM: VMX: Properly shadow the CR0 register in the vcpu struct
    
    Set all of the host mask bits for CR0 so that we can maintain a proper
    shadow of CR0.  This exposes CR0.TS, paving the way for lazy fpu handling.
    
    Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit e0e5127d06957e76da3906b7a58d5d2665e81f59
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Apr 25 10:59:52 2007 +0300

    KVM: Don't complain about cpu erratum AA15
    
    It slows down Windows x64 horribly.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 7807fa6ca5af2e5660a0eb3cd90276ca0c5bdfc8
Author: Anthony Liguori <aliguori@us.ibm.com>
Date:   Mon Apr 23 09:17:21 2007 -0500

    KVM: Lazy FPU support for SVM
    
    Avoid saving and restoring the guest fpu state on every exit.  This
    shaves ~100 cycles off the guest/host switch.
    
    Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 4c690a1e8667a84b61a6114a4ad293681f32cb11
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Apr 22 15:28:19 2007 +0300

    KVM: Allow passing 64-bit values to the emulated read/write API
    
    This simplifies the API somewhat (by eliminating the special-case
    cmpxchg8b on i386).
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 1165f5fec18c077bdba88e7125fd41f8e3617cb4
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 19 17:27:43 2007 +0300

    KVM: Per-vcpu statistics
    
    Make the exit statistics per-vcpu instead of global.  This gives a 3.5%
    boost when running one virtual machine per core on my two socket dual core
    (4 cores total) machine.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 3fca03653010b8c5fa63b99fc94c78cbfb433d00
Author: Yaozu Dong <eddie.dong@intel.com>
Date:   Wed Apr 25 16:49:19 2007 +0300

    KVM: VMX: Avoid unnecessary vcpu_load()/vcpu_put() cycles
    
    By checking if a reschedule is needed, we avoid dropping the vcpu.
    
    [With changes by me, based on Anthony Liguori's observations]
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit d6c69ee9a24b307ce94e55ebfba6208a830c9ecb
Author: Yaozu Dong <eddie.dong@intel.com>
Date:   Wed Apr 25 14:17:25 2007 +0800

    KVM: MMU: Avoid heavy ASSERT at non debug mode.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 4d56c8a787aefb2e3fc4ac4be966db96c14d1ad8
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 19 14:28:44 2007 +0300

    KVM: VMX: Only save/restore MSR_K6_STAR if necessary
    
    Intel hosts only support syscall/sysret in long more (and only if efer.sce
    is enabled), so only reload the related MSR_K6_STAR if the guest will
    actually be able to use it.
    
    This reduces vmexit cost by about 500 cycles (6400 -> 5870) on my setup.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 35cc7f971188366f5a5c0d5da1456bb38cef5da9
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 19 13:26:39 2007 +0300

    KVM: Fold drivers/kvm/kvm_vmx.h into drivers/kvm/vmx.c
    
    No meat in that file.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit e38aea3e9330624d19a233c05f3e69c57519edd5
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 19 13:22:48 2007 +0300

    KVM: VMX: Don't switch 64-bit msrs for 32-bit guests
    
    Some msrs are only used by x86_64 instructions, and are therefore
    not needed when the guest is legacy mode.  By not bothering to switch
    them, we reduce vmexit latency by 2400 cycles (from about 8800) when
    running a 32-bt guest on a 64-bit host.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 2345df8c555ecb92c0c36172c07d5ac321a92dc7
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Apr 17 15:30:24 2007 +0300

    KVM: VMX: Reduce unnecessary saving of host msrs
    
    THe automatically switched msrs are never changed on the host (with
    the exception of MSR_KERNEL_GS_BASE) and thus there is no need to save
    them on every vm entry.
    
    This reduces vmexit latency by ~400 cycles on i386 and by ~900 cycles (10%)
    on x86_64.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit c9047f533373e934b96d19d6a3d313ca2132fbe5
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Apr 17 10:53:22 2007 +0300

    KVM: Handle guest page faults when emulating mmio
    
    Usually, guest page faults are detected by the kvm page fault handler,
    which detects if they are shadow faults, mmio faults, pagetable faults,
    or normal guest page faults.
    
    However, in ceratin circumstances, we can detect a page fault much later.
    One of these events is the following combination:
    
    - A two memory operand instruction (e.g. movsb) is executed.
    - The first operand is in mmio space (which is the fault reported to kvm)
    - The second operand is in an ummaped address (e.g. a guest page fault)
    
    The Windows 2000 installer does such an access, an promptly hangs.  Fix
    by adding the missing page fault injection on that path.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 364b625b561b1dd74e6fa696949ae3de28999a66
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Apr 16 14:28:40 2007 +0300

    KVM: SVM: Report hardware exit reason to userspace instead of dmesg
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 8c4385024d31cb909ad84a2cafa5c83a4c5fab61
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Apr 16 11:53:17 2007 +0300

    KVM: Retry sleeping allocation if atomic allocation fails
    
    This avoids -ENOMEM under memory pressure.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit b5a33a75720c03d58d8281a72b45ffd214f00ed7
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Apr 15 16:31:09 2007 +0300

    KVM: Use slab caches to allocate mmu data structures
    
    Better leak detection, statistics, memory use, speed -- goodness all
    around.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 417726a3fbecb2092f1054bbaee87bc442b05ef3
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 12 17:35:58 2007 +0300

    KVM: Handle partial pae pdptr
    
    Some guests (Solaris) do not set up all four pdptrs, but leave some invalid.
    kvm incorrectly treated these as valid page directories, pinning the
    wrong pages and causing general confusion.
    
    Fix by checking the valid bit of a pae pdpte.  This closes sourceforge bug
    1698922.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit d917a6b92d0d1e4e2b98e86c584bc9e643cd5117
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Apr 12 13:03:01 2007 +0300

    KVM: Initialize cr0 to indicate an fpu is present
    
    Solaris panics if it sees a cpu with no fpu, and it seems to rely on this
    bit.  Closes sourceforge bug 1698920.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 3964994bb5ba85a3d8b54ae618f7be1cecce916d
Author: Eric Sesterhenn / Snakebyte <snakebyte@gmx.de>
Date:   Mon Apr 9 16:15:05 2007 +0200

    KVM: Fix overflow bug in overflow detection code
    
    The expression
    
       sp - 6 < sp
    
    where sp is a u16 is undefined in C since 'sp - 6' is promoted to int,
    and signed overflow is undefined in C.  gcc 4.2 actually warns about it.
    Replace with a simpler test.
    
    Signed-off-by: Eric Sesterhenn <snakebyte@gmx.de>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 5008fdf5b6a31240da060c0867d8f16f08ce2384
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Apr 2 13:05:50 2007 +0300

    KVM: Use kernel-standard types
    
    Noted by Joerg Roedel.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 80b7706e4cbaa51d65bd6fea83bd0e59856f50e9
Author: Joerg Roedel <joerg.roedel@amd.com>
Date:   Fri Mar 30 17:02:14 2007 +0300

    KVM: SVM: enable LBRV virtualization if available
    
    This patch enables the virtualization of the last branch record MSRs on
    SVM if this feature is available in hardware. It also introduces a small
    and simple check feature for specific SVM extensions.
    
    Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit b8836737d92c139be770eae3d6574e33d1224caf
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Apr 1 16:34:31 2007 +0300

    KVM: Add fpu get/set operations
    
    These are really helpful when migrating an floating point app to another
    machine.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit e8207547d2f7b2f557bdb73015c1f74c32474438
Author: Avi Kivity <avi@qumranet.com>
Date:   Fri Mar 30 16:54:30 2007 +0300

    KVM: Add physical memory aliasing feature
    
    With this, we can specify that accesses to one physical memory range will
    be remapped to another.  This is useful for the vga window at 0xa0000 which
    is used as a movable window into the (much larger) framebuffer.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 954bbbc236afe23b368abdf4942f313a5f6e1d50
Author: Avi Kivity <avi@qumranet.com>
Date:   Fri Mar 30 14:02:32 2007 +0300

    KVM: Simply gfn_to_page()
    
    Mapping a guest page to a host page is a common operation.  Currently,
    one has first to find the memory slot where the page belongs (gfn_to_memslot),
    then locate the page itself (gfn_to_page()).
    
    This is clumsy, and also won't work well with memory aliases.  So simplify
    gfn_to_page() not to require memory slot translation first, and instead do it
    internally.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit e0fa826f969c262c23908953bf85add487cc2e6c
Author: Dor Laor <dor.laor@qumranet.com>
Date:   Fri Mar 30 13:06:33 2007 +0300

    KVM: Add mmu cache clear function
    
    Functions that play around with the physical memory map
    need a way to clear mappings to possibly nonexistent or
    invalid memory.  Both the mmu cache and the processor tlb
    are cleared.
    
    Signed-off-by: Dor Laor <dor.laor@qumranet.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit df513e2cdd099822ed32cbc20aaf4ff310372202
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 28 20:04:16 2007 +0200

    KVM: x86 emulator: fix bit string operations operand size
    
    On x86, bit operations operate on a string of bits that can reside in
    multiple words.  For example, 'btsl %eax, (blah)' will touch the word
    at blah+4 if %eax is between 32 and 63.
    
    The x86 emulator compensates for that by advancing the operand address
    by (bit offset / BITS_PER_LONG) and truncating the bit offset to the
    range (0..BITS_PER_LONG-1).  This has a side effect of forcing the operand
    size to 8 bytes on 64-bit hosts.
    
    Now, a 32-bit guest goes and fork()s a process.  It write protects a stack
    page at 0xbffff000 using the 'btr' instruction, at offset 0xffc in the page
    table, with bit offset 1 (for the write permission bit).
    
    The emulator now forces the operand size to 8 bytes as previously described,
    and an innocent page table update turns into a cross-page-boundary write,
    which is assumed by the mmu code not to be a page table, so it doesn't
    actually clear the corresponding shadow page table entry.  The guest and
    host permissions are out of sync and guest memory is corrupted soon
    afterwards, leading to guest failure.
    
    Fix by not using BITS_PER_LONG as the word size; instead use the actual
    operand size, so we get a 32-bit write in that case.
    
    Note we still have to teach the mmu to handle cross-page-boundary writes
    to guest page table; but for now this allows Damn Small Linux 0.4 (2.4.20)
    to boot.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit afeb1f14c5478560262b37431726eb0eb1a42e9e
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 27 17:50:20 2007 +0200

    KVM: Remove debug message
    
    No longer interesting.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 36868f7b0efd0b6a1d45fe3b40a6c4bc63222659
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Mar 26 19:31:52 2007 +0200

    KVM: Use list_move()
    
    Use list_move() where possible.  Noticed by Dor Laor.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 55bf4028342d96b21fe5dc0721b481b0bc1e81f6
Author: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
Date:   Sun Mar 25 17:59:32 2007 +0200

    KVM: Remove unused function
    
    Remove unused function
    
    CC      drivers/kvm/svm.o
    drivers/kvm/svm.c:207: warning: â€˜inject_dbâ€™ defined but not used
    
    Signed-off-by: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 0cc5064d335543a72c5ef904a3f528966fa3f2d2
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Mar 25 12:07:27 2007 +0200

    KVM: SVM: Ensure timestamp counter monotonicity
    
    When a vcpu is migrated from one cpu to another, its timestamp counter
    may lose its monotonic property if the host has unsynced timestamp counters.
    This can confuse the guest, sometimes to the point of refusing to boot.
    
    As the rdtsc instruction is rather fast on AMD processors (7-10 cycles),
    we can simply record the last host tsc when we drop the cpu, and adjust
    the vcpu tsc offset when we detect that we've migrated to a different cpu.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit d28c6cfbbc5e2d4fccfe6d733995ed5971ca87f6
Author: Avi Kivity <avi@qumranet.com>
Date:   Fri Mar 23 09:55:25 2007 +0200

    KVM: MMU: Fix hugepage pdes mapping same physical address with different access
    
    The kvm mmu keeps a shadow page for hugepage pdes; if several such pdes map
    the same physical address, they share the same shadow page.  This is a fairly
    common case (kernel mappings on i386 nonpae Linux, for example).
    
    However, if the two pdes map the same memory but with different permissions, kvm
    will happily use the cached shadow page.  If the access through the more
    permissive pde will occur after the access to the strict pde, an endless pagefault
    loop will be generated and the guest will make no progress.
    
    Fix by making the access permissions part of the cache lookup key.
    
    The fix allows Xen pae to boot on kvm and run guest domains.
    
    Thanks to Jeremy Fitzhardinge for reporting the bug and testing the fix.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 916ce2360fadc71d924e02403b31280112a31280
Author: Joerg Roedel <joerg.roedel@amd.com>
Date:   Wed Mar 21 19:47:00 2007 +0100

    KVM: SVM: forbid guest to execute monitor/mwait
    
    This patch forbids the guest to execute monitor/mwait instructions on
    SVM. This is necessary because the guest can execute these instructions
    if they are available even if the kvm cpuid doesn't report its
    existence.
    
    Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 0e5bf0d0e449f6597870570e8dd17e78ba4d75ff
Author: Sergey Kiselev <sergey.kiselev@intel.com>
Date:   Thu Mar 22 14:06:18 2007 +0200

    KVM: Handle writes to MCG_STATUS msr
    
    Some older (~2.6.7) kernels write MCG_STATUS register during kernel
    boot (mce_clear_all() function, called from mce_init()). It's not
    currently handled by kvm and will cause it to inject a GPF.
    Following patch adds a "nop" handler for this.
    
    Signed-off-by: Sergey Kiselev <sergey.kiselev@intel.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit fcd3410870049cb74bb1a3a2458cb3ec21185cd1
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 21 18:14:42 2007 +0200

    KVM: Remove unused and write-only variables
    
    Trivial cleanup.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 6da63cf95f6a19fe0a302232048452c96b178e45
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 21 18:11:36 2007 +0200

    KVM: Don't allow the guest to turn off the cpu cache
    
    The cpu cache is a host resource; the guest should not be able to turn
    it off (even for itself).
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 038881c8bec0e9a796d1782c56e29e7c2456626d
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 21 17:58:32 2007 +0200

    KVM: Hack real-mode segments on vmx from KVM_SET_SREGS
    
    As usual, we need to mangle segment registers when emulating real mode
    as vm86 has specific constraints.  We special case the reset segment base,
    and set the "access rights" (or descriptor flags) to vm86 comaptible values.
    
    This fixes reboot on vmx.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 024aa1c02f0a9f938af83f55c727bcb18187eba4
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 21 13:44:58 2007 +0200

    KVM: Modify guest segments after potentially switching modes
    
    The SET_SREGS ioctl modifies both cr0.pe (real mode/protected mode) and
    guest segment registers.  Since segment handling is modified by the mode on
    Intel procesors, update the segment registers after the mode switch has taken
    place.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit f6528b03f167785301908bf124db7be591e983ca
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 20 18:44:51 2007 +0200

    KVM: Remove set_cr0_no_modeswitch() arch op
    
    set_cr0_no_modeswitch() was a hack to avoid corrupting segment registers.
    As we now cache the protected mode values on entry to real mode, this
    isn't an issue anymore, and it interferes with reboot (which usually _is_
    a modeswitch).
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 8cb5b0333250beb382624f626851a31f601b4830
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 20 18:40:40 2007 +0200

    KVM: Workaround vmx inability to virtualize the reset state
    
    The reset state has cs.selector == 0xf000 and cs.base == 0xffff0000,
    which aren't compatible with vm86 mode, which is used for real mode
    virtualization.
    
    When we create a vcpu, we set cs.base to 0xf0000, but if we get there by
    way of a reset, the values are inconsistent and vmx refuses to enter
    guest mode.
    
    Workaround by detecting the state and munging it appropriately.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit aac012245a59d78372dc66d292ba567367d86b60
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 20 14:34:28 2007 +0200

    KVM: MMU: Remove global pte tracking
    
    The initial, noncaching, version of the kvm mmu flushed the all nonglobal
    shadow page table translations (much like a native tlb flush).  The new
    implementation flushes translations only when they change, rendering global
    pte tracking superfluous.
    
    This removes the unused tracking mechanism and storage space.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit ca5aac1f96c18b5e4dcfea253d7ab607b5dcd5c9
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 20 14:29:06 2007 +0200

    KVM: MMU: Remove unnecessary check for pdptr access
    
    We already special case the pdptr access, so no need to check it again.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 039576c03c35e2f990ad9bb9c39e1bad3cd60d34
Author: Avi Kivity <avi@qumranet.com>
Date:   Tue Mar 20 12:46:50 2007 +0200

    KVM: Avoid guest virtual addresses in string pio userspace interface
    
    The current string pio interface communicates using guest virtual addresses,
    relying on userspace to translate addresses and to check permissions.  This
    interface cannot fully support guest smp, as the check needs to take into
    account two pages at one in case an unaligned string transfer straddles a
    page boundary.
    
    Change the interface not to communicate guest addresses at all; instead use
    a buffer page (mmaped by userspace) and do transfers there.  The kernel
    manages the virtual to physical translation and can perform the checks
    atomically by taking the appropriate locks.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit f0fe510864a4520a85dfa35ae14f5f376c56efc7
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 7 13:11:17 2007 +0200

    KVM: Future-proof argument-less ioctls
    
    Some ioctls ignore their arguments.  By requiring them to be zero now,
    we allow a nonzero value to have some special meaning in the future.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 07c45a366d89f8eaec5d9890e810171b408f9a52
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 7 13:05:38 2007 +0200

    KVM: Allow kernel to select size of mmap() buffer
    
    This allows us to store offsets in the kernel/user kvm_run area, and be
    sure that userspace has them mapped.  As offsets can be outside the
    kvm_run struct, userspace has no way of knowing how much to mmap.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 1961d276c877b99f5f16aaf36377c75e0e191c3a
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Mar 5 19:46:05 2007 +0200

    KVM: Add guest mode signal mask
    
    Allow a special signal mask to be used while executing in guest mode.  This
    allows signals to be used to interrupt a vcpu without requiring signal
    delivery to a userspace handler, which is quite expensive.  Userspace still
    receives -EINTR and can get the signal via sigwait().
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 6722c51c51518af9581ab6cd9b6aec93774334a6
Author: Avi Kivity <avi@qumranet.com>
Date:   Mon Mar 5 17:45:40 2007 +0200

    KVM: Initialize the apic_base msr on svm too
    
    Older userspace didn't care, but newer userspace (with the cpuid changes)
    does.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 1b19f3e61d7e1edb395dd64bf7d63621a37af8ca
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Mar 4 14:24:03 2007 +0200

    KVM: Add a special exit reason when exiting due to an interrupt
    
    This is redundant, as we also return -EINTR from the ioctl, but it
    allows us to examine the exit_reason field on resume without seeing
    old data.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 8eb7d334bd8e693340ee198280f7d45035cdab8c
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Mar 4 14:17:08 2007 +0200

    KVM: Fold kvm_run::exit_type into kvm_run::exit_reason
    
    Currently, userspace is told about the nature of the last exit from the
    guest using two fields, exit_type and exit_reason, where exit_type has
    just two enumerations (and no need for more).  So fold exit_type into
    exit_reason, reducing the complexity of determining what really happened.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit b4e63f560beb187cffdaf706e534a1e2f9effb66
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Mar 4 13:59:30 2007 +0200

    KVM: Allow userspace to process hypercalls which have no kernel handler
    
    This is useful for paravirtualized graphics devices, for example.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 5d308f4550d9dc4c236e08b0377b610b9578577b
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Mar 1 17:56:20 2007 +0200

    KVM: Add method to check for backwards-compatible API extensions
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 739872c56f3322c38320c7a5a543ef6f56f174bc
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Mar 1 17:20:13 2007 +0200

    KVM: Renumber ioctls
    
    The recent changes have left the ioctl numbers in complete disarray.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 2a4dac3952468157297b81ae0a29815c02ead179
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Mar 1 16:47:06 2007 +0200

    KVM: Remove minor wart from KVM_CREATE_VCPU ioctl
    
    That ioctl does not transfer any data, so it should be an _IO rather than an
    _IOW.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 106b552b43beac2694df5fbafc8f125a72df5f65
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Mar 1 16:20:40 2007 +0200

    KVM: Remove the 'emulated' field from the userspace interface
    
    We no longer emulate single instructions in userspace.  Instead, we service
    mmio or pio requests.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 06465c5a3aa9948a7b00af49cd22ed8f235cdb0f
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Feb 28 20:46:53 2007 +0200

    KVM: Handle cpuid in the kernel instead of punting to userspace
    
    KVM used to handle cpuid by letting userspace decide what values to
    return to the guest.  We now handle cpuid completely in the kernel.  We
    still let userspace decide which values the guest will see by having
    userspace set up the value table beforehand (this is necessary to allow
    management software to set the cpu features to the least common denominator,
    so that live migration can work).
    
    The motivation for the change is that kvm kernel code can be impacted by
    cpuid features, for example the x86 emulator.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 46fc1477887c41c8e900f2c95485e222b9a54822
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Feb 22 19:39:30 2007 +0200

    KVM: Do not communicate to userspace through cpu registers during PIO
    
    Currently when passing the a PIO emulation request to userspace, we
    rely on userspace updating %rax (on 'in' instructions) and %rsi/%rdi/%rcx
    (on string instructions).  This (a) requires two extra ioctls for getting
    and setting the registers and (b) is unfriendly to non-x86 archs, when
    they get kvm ports.
    
    So fix by doing the register fixups in the kernel and passing to userspace
    only an abstract description of the PIO to be done.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 9a2bb7f486dc639a1cf2ad803bf2227f0dc0809d
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Feb 22 12:58:31 2007 +0200

    KVM: Use a shared page for kernel/user communication when runing a vcpu
    
    Instead of passing a 'struct kvm_run' back and forth between the kernel and
    userspace, allocate a page and allow the user to mmap() it.  This reduces
    needless copying and makes the interface expandable by providing lots of
    free space.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 1ea252afcd4b264b71d9c3f55358ff5ba4c04f1b
Author: Avi Kivity <avi@qumranet.com>
Date:   Thu Mar 8 11:48:09 2007 +0200

    KVM: Fix bogus sign extension in mmu mapping audit
    
    When auditing a 32-bit guest on a 64-bit host, sign extension of the page
    table directory pointer table index caused bogus addresses to be shown on
    audit errors.
    
    Fix by declaring the index unsigned.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit ff42697436ddf5bd026e2cb4f117656b967f0709
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed Mar 7 09:29:48 2007 +0200

    KVM: Export <linux/kvm.h>
    
    This allows users to actually build prgrams that use kvm without
    the entire source tree.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit bbe4432e669ab94fc8059e7ab878cafad7b8d123
Author: Avi Kivity <avi@qumranet.com>
Date:   Sun Mar 4 13:27:36 2007 +0200

    KVM: Use own minor number
    
    Use the minor number (232) allocated to kvm by lanana.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 510043da8582ad49d22a1e9a6b211e6ede10cd2e
Author: Dor Laor <dor.laor@qumranet.com>
Date:   Mon Feb 19 18:25:43 2007 +0200

    KVM: Use the generic skip_emulated_instruction() in hypercall code
    
    Instead of twiddling the rip registers directly, use the
    skip_emulated_instruction() function to do that for us.
    
    Signed-off-by: Dor Laor <dor.laor@qumranet.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 9b22bf578332d3e326c349bc8a8789af3d952435
Author: Dor Laor <dor.laor@qumranet.com>
Date:   Mon Feb 19 16:44:49 2007 +0200

    KVM: Fix guest register corruption on paravirt hypercall
    
    The hypercall code mixes up the ->cache_regs() and ->decache_regs()
    callbacks, resulting in guest register corruption.
    
    Signed-off-by: Dor Laor <dor.laor@qumranet.com>
    Signed-off-by: Avi Kivity <avi@qumranet.com>

commit 3f07d8796262f6aee135c8dd9a91210da9f888e4
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 01:02:07 2007 -0400

    Input: aaed2000_kbd - convert to use polldev library
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit e37a97d44038700ff8c2f1080f71fdfc3a4c0c1e
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:57:29 2007 -0400

    Input: drivers/usb/input - usb_buffer_free() cleanup
    
    usb_buffer_free() now handles NULLs so remove unneeded checks
    form callers.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 4bdd488f4bf7dc91b371fe160a4718b0a91bb2a4
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:56:18 2007 -0400

    Input: synaptics - don't complain about failed resets
    
    On many laptops (Compaq, HP) the touchpad is so slow responding
    to reset that keyboard controller times out. The device is reset
    nonetheless and works fine. Kill the "synaptics reset failed"
    error; if device is not working then other parts of
    synaptics_query_hardware() will fail anyway.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit a830df367cc8cd802b45baed2449bea267727721
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Thu May 3 00:55:34 2007 -0400

    Input: pull input.h into uinpit.h
    
    uinput.h relies on structures found in input.h, so pull in the header
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 4ee1fc8e554593061a71d6af7c94f31764b87606
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:54:54 2007 -0400

    Input: drivers/usb/input - fix sparse warnings (signedness)
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit ce305b6a0815cae4288e77723f80fbc97f651f9a
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:53:18 2007 -0400

    Input: evdev - fix some sparse warnings (signedness, shadowing)
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 78167236e23bb3c80d2b35b693e578a6e56b1171
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:52:51 2007 -0400

    Input: drivers/joystick - fix various sparse warnings
    
    Fix various issues pointed by sparse:
     - module_param_array_named() takes unsigned int as number
       of parameters argument
     - shadowing of global variables is not healthy. I think there was
       once a bug in db9 caused by it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit dec3eb01c2409ca8276c1152c167add66a37d1ba
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu May 3 00:51:10 2007 -0400

    Input: force feedback - make sure effect is present before playing
    
    Make sure that requested effect id is not out of range for the
    device and that effect is present before requesting device to
    play it.
    
    Reported-by: Jan Kratochvil <honza@jikos.cz>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 796e5661f6b6be1600b3ab47c61ce61cf3e7a353
Author: Roland Dreier <roland@digitalvampire.org>
Date:   Thu May 3 04:33:45 2007 +0000

    [CIFS] Change semaphore to mutex for cifs lock_sem
    
    Originally at http://lkml.org/lkml/2006/9/2/86
    
    The recent change to "allow Windows blocking locks to be cancelled via a
    CANCEL_LOCK call" introduced a new semaphore in struct cifsFileInfo,
    lock_sem.  However, semaphores used as mutexes are deprecated these days,
    and there's no reason to add a new one to the kernel.  Therefore, convert
    lock_sem to a struct mutex (and also fix one indentation glitch on one of
    the lines changed anyway).
    
    Signed-off-by: Roland Dreier <roland@digitalvampire.org>
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 0b2365f826f40d6e966365299d4e9dcc7ef4e93f
Author: Steve French <sfrench@us.ibm.com>
Date:   Thu May 3 04:30:13 2007 +0000

    [CIFS] Fix oops in reset_cifs_unix_caps on reconnect
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 9890b12a4a65a7b3181dd963421740edf0e14d69
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Wed Apr 18 13:34:12 2007 +1000

    PCI: Free resource files in error path of pci_create_sysfs_dev_files()
    
    pci_create_sysfs_dev_files() should call pci_remove_resource_files() in
    its error path, to match the call it makes to pci_create_resource_files().
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c0affe9db42bf85f4a606b3262c35ec59a5d3788
Author: Tejun Heo <htejun@gmail.com>
Date:   Mon Apr 16 13:59:18 2007 +0900

    pci-quirks: disable MSI on RS400-200 and RS480
    
    MSI doesn't work on RS400-200 and RS480 requiring pci=nomsi kernel
    boot parameter for ahci to work.  This patch disables MSI on those
    chips.
    
      http://thread.gmane.org/gmane.linux.ide/17820
      http://thread.gmane.org/gmane.linux.ide/17516
      https://bugzilla.novell.com/show_bug.cgi?id=263893
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit d4770143fe72979d463a911d7a1f75f27ce6437b
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Fri Apr 13 15:34:27 2007 -0700

    PCI hotplug: Use menuconfig objects
    
    Use menuconfigs instead of menus, so the whole menu can be disabled at
    once instead of going through all options.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Cc: Scott Murray <scottm@somanetworks.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 03555d591d2c8ee9291db171c0d21d3c9cab04d9
Author: Scott Murray <scottm@somanetworks.com>
Date:   Fri Apr 13 15:34:26 2007 -0700

    PCI: ZT5550 CPCI Hotplug driver fix
    
    cc: Philip Guo <pg@cs.stanford.edu>
    
    Here's a small patch against the current git tree for the ZT5550 CPCI
    hotplug driver to fix an issue with port freeing that Philip Guo found.
    
    Signed-off-by: Scott Murray <scottm@somanetworks.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ac1f0e9923356652f21756526e194a4a1a37dd38
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:25 2007 -0700

    PCI: rpaphp: Remove semaphores
    
    Remove the semaphores from the get routine. These do not
    appear to be protecting anything that I can make out,
    and they also do not seem to be required by the hotplug
    driver.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b5661479eeb863749ae28b9ee0dd288464311854
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:24 2007 -0700

    PCI: rpaphp: Ensure more pcibios_add/pcibios_remove symmetry
    
    Calls to pcibios_add should be symmetric with calls to pcibios_remove.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit e70ea2634afe7d04ffaf7417df7bfdbfdc460e10
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:23 2007 -0700

    PCI: rpaphp: Use pcibios_remove_pci_devices() symmetrically
    
    At first blush, the disable_slot() routine does not look
    at all like its symmetric with the enable_slot() routine;
    as it seems to call a very different set of routines.
    However, this is easily fixed: pcibios_remove_pci_devices()
    does the right thing.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit da65944be2441191539f50ce71cd1f8030699be1
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:22 2007 -0700

    PCI: rpaphp: Document is_php_dn()
    
    Fix up the documentation: the rpaphp_add_slot() does not actually
    handle embedded slots: in fact, it ignores them. Fix the flow of
    control in the routine that checks for embedded slots.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 8485d1a123e0d367bbcbfec36acf134e6895f39a
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:21 2007 -0700

    PCI: rpaphp: Document find_php_slot()
    
    Document some of the interaction between dlpar and hotplug.
    viz, the a dlpar remove of a htoplug slot uses hotplug to remove it.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fea54b8cc9c8290b4c99d481c3e600c46eb18fd5
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:20 2007 -0700

    PCI: rpaphp: Rename rpaphp_register_pci_slot() to rpaphp_enable_slot()
    
    Rename rpaphp_register_pci_slot() because its easy to confuse
    with  rpaphp_register_slot() even though it does something
    completely different. Rename it to rpaphp_enable_slot() because
    its almost identical to enbale_slot().
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 6f79eb749df7f1eea76c947f31603ade7d2b5f6d
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:19 2007 -0700

    PCI: rpaphp: refactor tail call to rpaphp_register_slot()
    
    Eliminate the tail call to rpaphp_register_slot()
    by placing it in the caller. This will help later
    dis-entanglement.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c02929c278f2bca68635e4c2daa00b7825d71061
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:18 2007 -0700

    PCI: rpaphp: remove rpaphp_set_attention_status()
    
    The rpaphp_set_attention_status() routine seems to be a wrapper
    around a single rtas call. Abolish it.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 307ff12e35526cfab9f09cafcb17239286e6eb85
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:17 2007 -0700

    PCI: rpaphp: remove print_slot_pci_funcs()
    
    The debug function print_slot_pci_funcs() is a large wrapper
    around two debug print statements.  Just invoke these directly.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 03a667559138d47cea487823332c4712fc6fbec7
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:16 2007 -0700

    PCI: rpaphp: Remove setup_pci_slot()
    
    The setup_pci_slot() routine appears to be nothing else than
    a big, complicated wrapper around pcibios_add_pci_devices().
    Remove the wrapping, and call pcibios_add_pci_devices() directly.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ebf42c0edd5ee325043d4ae8fbb8caebd707e791
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:15 2007 -0700

    PCI: rpaphp: remove a call that does nothing but a pointer lookup
    
    Delete another stovepipe: a call to a routine which does nothing.
    Remove un-needed semaphore as well.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bf0af511fcc856649a2a39c627828695b580d124
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:14 2007 -0700

    PCI: rpaphp: Remove another wrappered function
    
    Remove another stove-pipe; this funcion was called from
    two different places, with a compile-time const that is
    then run-time checked to perform two different things.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 427310ff02e80cc80826407c0121cec3694c9e7d
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:13 2007 -0700

    PCI: rpaphp: Remve another call that is a wrapper
    
    Remove another stovepipe: a call which wraps another call, and
    just adds printks.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 517d5a0417e19101eaa769039d1921d626ee546c
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:12 2007 -0700

    PCI: rpaphp: remove a function that does nothing but wrap debug printks
    
    Remove a stove-pipe-- a function that is called from only one place,
    does nothing but wraps another function with debug printk's.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 3499f0726ec179afd19669070681ac457d27033f
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:11 2007 -0700

    PCI: rpaphp: Remove un-needed goto
    
    Remove un-needed goto.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5fd39c35a016150e93b68c472a04b2d4b5574a2b
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:10 2007 -0700

    PCI: rpaphp: Fix a memleak; slot->location string was never freed
    
    Fix a memleak; the slot->location string was never freed.
    Fix some whitespace and overlong-line probelms while we're here.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 31be7586d1122538747519d786408f142f59dd46
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:09 2007 -0700

    PCI: rpaphp: match up alloc and free in same routine
    
    The routine that called an alloc should be the same routine that
    calles the mathcing free, if anything in the middle failed.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fa1891596ca252e48e8803738fd8ead5b3082217
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:08 2007 -0700

    PCI: rpaphp: Remove global num_slots variable
    
    Cleanup cruft: remove the global "num_slots" variable;
    although scattered across multiple files, it is used only
    once, in a debug statement.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bf8cbae47559170d2f2947dd547492714f195dd3
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Fri Apr 13 15:34:07 2007 -0700

    PCI: rpaphp: Cleanup flow of control for rpaphp_add_slot
    
    Cleanup the flow of control for rpaphp_add_slot(), so as to
    make it easier to read. The ext patch will fix a bug in this
    same code.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Cc: John Rose <johnrose@austin.ibm.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f14e3136509e3825a83f6689cb709f41dfacea47
Author: Chuck Ebbert <cebbert@redhat.com>
Date:   Tue Apr 10 10:25:44 2007 -0400

    PCI: add debug information to resource collision message
    
    Add more information to PCI resource collision message
    to help with debugging.
    
    Signed-off-by: Chuck Ebbert <cebbert@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ecf36501bc4ad399e6df2e0bdaa513a2d510b7ec
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 6 12:19:48 2007 +0200

    PCI: the overdue removal of pci_module_init()
    
    Unless we finally completely remove it, people will always add new users.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5adc55da4a7758021bcc374904b0f8b076508a11
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue Mar 27 03:02:51 2007 +0200

    PCI: remove the broken PCI_MULTITHREAD_PROBE option
    
    This patch removes the PCI_MULTITHREAD_PROBE option that had already
    been marked as broken.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 032de8e2fe3c0eec5fb0ffe4d38aa602dad397dc
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Wed Apr 18 19:39:22 2007 +1000

    MSI: Give archs the option to free all MSI/Xs at once.
    
    This patch introduces an optional function, arch_teardown_msi_irqs(),
    which gives an arch the opportunity to do per-device teardown for
    MSI/X. If that's not required, the default version simply calls
    arch_teardown_msi_irq() for each msi irq required.
    
    arch_teardown_msi_irqs() is simply passed a pdev, attached to the pdev
    is a list of msi_descs, it is up to the arch to free the irq associated
    with each of these as appropriate.
    
    For archs that _don't_ implement arch_teardown_msi_irqs(), all msi_descs
    with irq == 0 are considered unallocated, and the arch teardown routine
    is not called on them.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 9c8313343c83c0ca731ceb8d2a4ab1e022ed9c94
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Wed Apr 18 19:39:21 2007 +1000

    MSI: Give archs the option to allocate all MSI/Xs at once.
    
    This patch introduces an optional function, arch_setup_msi_irqs(),
    (note the plural) which gives an arch the opportunity to do per-device
    setup for MSI/X and then allocate all the requested MSI/Xs at once.
    
    If that's not required by the arch, the default version simply calls
    arch_setup_msi_irq() for each MSI irq required.
    
    arch_setup_msi_irqs() is passed a pdev, attached to the pdev is a list
    of msi_descs with irq == 0, it is up to the arch to connect these up to
    an irq (via set_irq_msi()) or return an error. For convenience the number
    of vectors and the type are passed also.
    
    All msi_descs with irq != 0 are considered allocated, and the arch
    teardown routine will be called on them when necessary.
    
    The existing semantics of pci_enable_msix() are that if the requested
    number of irqs can not be allocated, the maximum number that _could_ be
    allocated is returned. To support that, we define that in case of an
    error from arch_setup_msi_irqs(), the number of msi_descs with irq != 0
    are considered allocated, and are counted toward the "max that could be
    allocated".
    
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7fe3730de729b758e9f69b862b9255d998671b5f
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Wed Apr 18 19:39:21 2007 +1000

    MSI: arch must connect the irq and the msi_desc
    
    set_irq_msi() currently connects an irq_desc to an msi_desc. The archs call
    it at some point in their setup routine, and then the generic code sets up the
    reverse mapping from the msi_desc back to the irq.
    
    set_irq_msi() should do both connections, making it the one and only call
    required to connect an irq with it's MSI desc and vice versa.
    
    The arch code MUST call set_irq_msi(), and it must do so only once it's sure
    it's not going to fail the irq allocation.
    
    Given that there's no need for the arch to return the irq anymore, the return
    value from the arch setup routine just becomes 0 for success and anything else
    for failure.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f282b97021ddc95c6092b9016f667c0963858fb1
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Wed Apr 18 18:46:20 2007 +1000

    msi: introduce ARCH_SUPPORTS_MSI Kconfig option (rev2)
    
    Allows architectures to advertise that they support MSI rather than listing
    each architecture as a PCI_MSI dependency.
    
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 314e77b3eec57001eaff82b82920150175b74e09
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:12 2007 +1000

    MSI: Remove dev->first_msi_irq
    
    Now that we keep a list of msi descriptors, we don't need first_msi_irq
    in the pci dev.
    
    If we somehow have zero MSIs configured list_entry() will give us weird
    oopes or nice memory corruption bugs. So be paranoid. Add BUG_ONs and also
    a check in pci_msi_check_device() to make sure nvec > 0.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4aa9bc955d61fdf03b5f9cee67db188fe1ffa8b7
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:10 2007 +1000

    MSI: Use a list instead of the custom link structure
    
    The msi descriptors are linked together with what looks a lot like
    a linked list, but isn't a struct list_head list. Make it one.
    
    The only complication is that previously we walked a list of irqs, and
    got the descriptor for each with get_irq_msi(). Now we have a list of
    descriptors and need to get the irq out of it, so it needs to be in the
    actual struct msi_desc. We use 0 to indicate no irq is setup.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bab41e9be75121c473b00df2ffa33af3c44066a7
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:09 2007 +1000

    PCI: Convert to alloc_pci_dev()
    
    Convert code that allocs a struct pci_dev to use alloc_pci_dev().
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 65891215e6b822c368fb3f36abf129ed48af8be0
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:08 2007 +1000

    PCI: Create alloc_pci_dev(), the one true way to create a struct pci_dev
    
    There are currently several places in the kernel where we kmalloc()
    a struct pci_dev and start initialising it. It'd be preferable to
    have an allocator so we can ensure the pci_dev is correctly initialised
    in one place.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c9953a73e92df11edd812d863ff741877ea9e58c
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:08 2007 +1000

    MSI: Add an arch_msi_check_device()
    
    Add an arch_check_device(), which gives archs a chance to check the input
    to pci_enable_msi/x. The arch might be interested in the value of nvec so
    pass it in. Propagate the error value returned from the arch routine out
    to the caller.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 17bbc12acdb23ffb9613e12ca974fafd31bfcb56
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Apr 5 17:19:07 2007 +1000

    MSI: Rename pci_msi_supported() to pci_msi_check_device()
    
    As pointed out by Eric, the name pci_msi_supported() suggests it should
    return a boolean value, however it doesn't. So update the name to be
    a bit less confusing and update the doco too.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 128bc5fced238752d01b5169077f2ec624b3d59b
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:39 2007 +1100

    MSI: Consolidate precondition checks
    
    Consolidate precondition checks into a single if statement.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b1e2303dba021ee417c65a89e467a2b145ff9217
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:39 2007 +1100

    MSI: Expand pci_msi_supported()
    
    pci_enable_msi() and pci_enable_msix() both search for the MSI/MSI-X
    capability, we can fold this into pci_msi_supported() by passing the
    type in.
    
    Update the code to match the comment for pci_msi_supported(). That is
    it returns 0 on success, and anything else indicates an error.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 3e916c0503a34ba32202a69df1cfeb82f2c5749d
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:36 2007 +1100

    MSI: Remove msi_cache
    
    We don't need a special cache just for msi descriptors. They're not
    particularly large, under 100 bytes for sure, and don't seem to require any
    special alignment etc. On most systems there will be relatively few MSIs,
    and hence we waste most of a page on the cache. Better to just kzalloc the
    space for the few we do need.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4cc086fa5b648dc3dcd56c963e42a212f2d9df29
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:34 2007 +1100

    MSI: Move EXPORT_SYMBOL()s near their definition
    
    Move EXPORT_SYMBOL()s near their definition.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7ede9c1fa50e01a8222217d4606bcbc44cd68f1a
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:34 2007 +1100

    MSI: Consolidate BUG_ON()s.
    
    When freeing MSIs and MSI-Xs, we BUG_ON() if the irq has not been
    freed, ie. if it still has an action. We can consolidate all of these
    BUG_ON()s into msi_free_irqs() as all the code paths lead there almost
    immediately anyway.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fc4afc7b2bdd81e2dbded5a8222676d3161758d3
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:33 2007 +1100

    MSI: Consolidate MSI-X irq freeing code
    
    For the MSI-X case we do exactly the same logic in pci_disable_msix() and
    msi_remove_pci_irq_vectors(), so consolidate them.
    
    msi_remove_pci_irq_vectors() wasn't setting dev->first_msi_irq to 0, but
    I think it should have been, so the consolidated version does.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 00ba16ab2658afe11d4fdcaf16a331292c44bee6
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:31 2007 +1100

    MSI: Simplify BUG() handling in msi_remove_pci_irq_vectors() part 2
    
    Although it might be nice to do a printk before BUG'ing, it's really not
    necessary, and it complicates the code.
    
    The behaviour has changed slightly, in that before we set a flag if the irq
    had an action, and continued freeing the other irqs. But as I see it that's
    all irrelevant because we end up BUG'ing anyway.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c31af3987020eeb1facf64d702dcf39e6c7382e6
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:31 2007 +1100

    MSI: Simplify BUG() handling in msi_remove_pci_irq_vectors() part 1
    
    Although it might be nice to do a printk before BUG'ing, it's really not
    necessary, and it complicates the code.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 54bc6c0b0edd164fc2ea85b3964736c182f6bd5d
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:27 2007 +1100

    MSI: Simplify BUG() handling in pci_disable_msix()
    
    Although it might be nice to do a printk before BUG'ing, it's really not
    necessary, and it complicates the code.
    
    The behaviour has changed slightly, in that before we set a flag if the irq
    had an action, and continued freeing the other irqs. But as I see it that's
    all irrelevant because we end up BUG'ing anyway.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit e387b9eefe89a23245f2446f947529cce5d6db35
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Thu Mar 22 21:51:27 2007 +1100

    MSI: Simplify BUG() handling in pci_disable_msi()
    
    Although it might be nice to do a printk before BUG'ing, it's really not
    necessary, and it complicates the code.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 54eee4c5bf553ad54ba200d00487b61eb6b155f6
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed Apr 4 21:35:39 2007 -0700

    PCI Documentation: power/pci.txt fix copy/paste error
    
    Correct function name copy-paste error.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 0da0ead90122578ef6e4afba9ba4bcd3455fd8e8
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sun Apr 1 21:13:58 2007 +0400

    PCI: define pci_request/release_regions() for CONFIG_PCI=n
    
    Balance declarations of pci_request_regions() and pci_release_regions() with
    empty inline definitions for the CONFIG_PCI=n case -- otherwise my patch to
    drivers/net/3c59x.c in the -mm tree doesn't compile. :-)
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 96bde06a2df1b363206d3cdef53134b84ff37813
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Mon Mar 26 21:53:30 2007 -0800

    pci: do not mark exported functions as __devinit
    
    Functions marked __devinit will be removed after kernel init.  But being
    exported they are potentially called by a module much later.
    
    So the safer choice seems to be to keep the function even in the non
    CONFIG_HOTPLUG case.
    
    This silence the follwoing section mismatch warnings:
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_bus_add_device from __ksymtab_gpl between '__ksymtab_pci_bus_add_device' (at offset 0x20) and '__ksymtab_pci_walk_bus'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_create_bus from __ksymtab_gpl between '__ksymtab_pci_create_bus' (at offset 0x40) and '__ksymtab_pci_stop_bus_device'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_bus_max_busnr from __ksymtab_gpl between '__ksymtab_pci_bus_max_busnr' (at offset 0xc0) and '__ksymtab_pci_assign_resource_fixed'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_claim_resource from __ksymtab_gpl between '__ksymtab_pci_claim_resource' (at offset 0xe0) and '__ksymtab_pcie_port_bus_type'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_bus_add_devices from __ksymtab between '__ksymtab_pci_bus_add_devices' (at offset 0x70) and '__ksymtab_pci_bus_alloc_resource'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_scan_bus_parented from __ksymtab between '__ksymtab_pci_scan_bus_parented' (at offset 0x90) and '__ksymtab_pci_root_buses'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_bus_assign_resources from __ksymtab between '__ksymtab_pci_bus_assign_resources' (at offset 0x4d0) and '__ksymtab_pci_bus_size_bridges'
    WARNING: drivers/built-in.o - Section mismatch: reference to .init.text:pci_bus_size_bridges from __ksymtab between '__ksymtab_pci_bus_size_bridges' (at offset 0x4e0) and '__ksymtab_pci_setup_cardbus'
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 6ba186361ed2cda7e174856a3ab8a8e3237b3c3d
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sat Apr 7 17:21:28 2007 +0200

    PCI: Require vendor and device for new_id
    
    Currently, there is no minimum number of fields required when adding
    a new device ID to a PCI driver through the new_id sysfs file. It is
    possible to add a new ID with only the vendor ID set, causing the
    driver to attempt to attach to all PCI devices from that vendor. This
    has been reported to happen accidentally:
      http://lists.lm-sensors.org/pipermail/lm-sensors/2007-March/019366.html
    It is even possible to not even set the vendor ID field, causing the
    driver to attempt to attach to _all_ the PCI devices.
    
    This sounds dangerous and I fail to see any valid use of this
    "feature". Thus I suggest that we now require at least the first two
    fields (vendor ID and device ID) to be set. For what it's worth, this
    is what the USB subsystem does.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 40ee9e9f8d52d85f2446bbdda7823a3f1de62f3f
Author: Jesse Barnes <jbarnes@virtuousgeek.org>
Date:   Sat Mar 24 11:03:32 2007 -0700

    PCI: fix sysfs rom file creation for BIOS ROM shadows
    
    At one time, if a BIOS ROM shadow was detected for the boot video
    device (stored at offset 0xc0000), we'd set a special resource flag,
    IORESOURCE_ROM_SHADOW, so that the sysfs ROM file code could handle
    it properly.  That broke along the way somewhere though, so current
    kernels will be missing 'rom' files in sysfs if the video device
    doesn't have an explicit ROM BAR.
    
    This patch fixes the regression by moving the video fixup quirk to a
    little later in the boot cycle (to avoid having its work undone by
    PCI resource allocation) and checking in the PCI sysfs code whether
    a rom file should be created due to a shadow resource, which is also
    moved to a little later in the boot cycle so it will occur after the
    video fixup.  Tested and works on my i386 test box.
    
    Signed-off-by:  Jesse Barnes <jbarnes@virtuousgeek.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 8d7d86e9bd377e5779bf3c8da03b27d823c039b4
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Fri Mar 16 19:55:52 2007 -0700

    PCI: kernel-doc fix
    
    Warning(linux-2621-rc3g7/drivers/pci/pci.c:1283): No description found for parameter 'dev'
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 6473d160b4aba8023bcf38519a5989694dfd51a7
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue Mar 6 02:45:12 2007 -0800

    PCI: Cleanup the includes of <linux/pci.h>
    
    I noticed that many source files include <linux/pci.h> while they do
    not appear to need it. Here is an attempt to clean it all up.
    
    In order to find all possibly affected files, I searched for all
    files including <linux/pci.h> but without any other occurence of "pci"
    or "PCI". I removed the include statement from all of these, then I
    compiled an allmodconfig kernel on both i386 and x86_64 and fixed the
    false positives manually.
    
    My tests covered 66% of the affected files, so there could be false
    positives remaining. Untested files are:
    
    arch/alpha/kernel/err_common.c
    arch/alpha/kernel/err_ev6.c
    arch/alpha/kernel/err_ev7.c
    arch/ia64/sn/kernel/huberror.c
    arch/ia64/sn/kernel/xpnet.c
    arch/m68knommu/kernel/dma.c
    arch/mips/lib/iomap.c
    arch/powerpc/platforms/pseries/ras.c
    arch/ppc/8260_io/enet.c
    arch/ppc/8260_io/fcc_enet.c
    arch/ppc/8xx_io/enet.c
    arch/ppc/syslib/ppc4xx_sgdma.c
    arch/sh64/mach-cayman/iomap.c
    arch/xtensa/kernel/xtensa_ksyms.c
    arch/xtensa/platform-iss/setup.c
    drivers/i2c/busses/i2c-at91.c
    drivers/i2c/busses/i2c-mpc.c
    drivers/media/video/saa711x.c
    drivers/misc/hdpuftrs/hdpu_cpustate.c
    drivers/misc/hdpuftrs/hdpu_nexus.c
    drivers/net/au1000_eth.c
    drivers/net/fec_8xx/fec_main.c
    drivers/net/fec_8xx/fec_mii.c
    drivers/net/fs_enet/fs_enet-main.c
    drivers/net/fs_enet/mac-fcc.c
    drivers/net/fs_enet/mac-fec.c
    drivers/net/fs_enet/mac-scc.c
    drivers/net/fs_enet/mii-bitbang.c
    drivers/net/fs_enet/mii-fec.c
    drivers/net/ibm_emac/ibm_emac_core.c
    drivers/net/lasi_82596.c
    drivers/parisc/hppb.c
    drivers/sbus/sbus.c
    drivers/video/g364fb.c
    drivers/video/platinumfb.c
    drivers/video/stifb.c
    drivers/video/valkyriefb.c
    include/asm-arm/arch-ixp4xx/dma.h
    sound/oss/au1550_ac97.c
    
    I would welcome test reports for these files. I am fine with removing
    the untested files from the patch if the general opinion is that these
    changes aren't safe. The tested part would still be nice to have.
    
    Note that this patch depends on another header fixup patch I submitted
    to LKML yesterday:
      [PATCH] scatterlist.h needs types.h
      http://lkml.org/lkml/2007/3/01/141
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Badari Pulavarty <pbadari@us.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit a9dfd281a7e12f6d9b53b5a28649b3a3c76a70e6
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue Mar 6 02:45:12 2007 -0800

    PCI: scatterlist.h needs types.h
    
    Most architectures' scatterlist.h use the type dma_addr_t, but omit to
    include <asm/types.h> which defines it.  This could lead to build failures,
    so let's add the missing includes.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit e325e1f0783382298141c74737712637943c6063
Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Date:   Wed Mar 21 11:45:31 2007 -0700

    PCI: fix multiple definition of `queue_pushbutton_work'
    
    Fix duplicate names in shpchp and pciehp.
    
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 9233352628bc8e284f66fc90c4dc74473db1fbc1
Author: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Date:   Tue Mar 6 15:02:32 2007 -0800

    pciehp: Adapt to device driver model
    
    This patch adapts PCIEHP driver to PCI device driver model.
    
    Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5d386e1ac4025b4bcc6bad6811e771cb76064dfe
Author: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Date:   Tue Mar 6 15:02:26 2007 -0800

    pciehp: Event handling rework
    
    The event handler of PCIEHP driver is unnecessarily very complex. In
    addition, current event handler can only a fixed number of events at
    the same time, and some of events would be lost if several number of
    events happened at the same time.
    
    This patch simplify the event handler using 'work queue', and it also
    fix the above-mentioned issue.
    
    Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
    Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f7bdd12d234d9064bd0aa1b5610508959120a9b4
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Fri Apr 6 16:39:36 2007 -0500

    pci: New PCI-E reset API
    
    Adds a new API which can be used to issue various types
    of PCI-E reset, including PCI-E warm reset and PCI-E hot reset.
    This is needed for an ipr PCI-E adapter which does not properly
    implement BIST. Running BIST on this adapter results in PCI-E
    errors. The only reliable reset mechanism that exists on this
    hardware is PCI Fundamental reset (warm reset). Since driving
    this type of reset is architecture unique, this provides the
    necessary hooks for architectures to add this support.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Acked-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 988cbb15e00e6f924d052874b40c6a5447f9fdd7
Author: Mitch Williams <mitch.a.williams@intel.com>
Date:   Fri Mar 30 11:54:08 2007 -0700

    PCI: Flush MSI-X table writes
    
    This patch fixes a kernel bug which is triggered when using the
    irqbalance daemon with MSI-X hardware.
    
    Because both MSI-X interrupt messages and MSI-X table writes are posted,
    it's possible for them to cross while in-flight.  This results in
    interrupts being received long after the kernel thinks they're disabled,
    and in interrupts being sent to stale vectors after rebalancing.
    
    This patch performs a read flush after writes to the MSI-X table for
    mask and unmask operations.  Since the SMP affinity is set while
    the interrupt is masked, and since it's unmasked immediately after,
    no additional flushes are required in the various affinity setting
    routines.
    
    This patch has been validated with (unreleased) network hardware which
    uses MSI-X.
    
    Revised with input from Eric Biederman.
    
    Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
    Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 823bccfc4002296ba88c3ad0f049e1abd8108d30
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Fri Apr 13 13:15:19 2007 -0700

    remove "struct subsystem" as it is no longer needed
    
    We need to work on cleaning up the relationship between kobjects, ksets and
    ktypes.  The removal of 'struct subsystem' is the first step of this,
    especially as it is not really needed at all.
    
    Thanks to Kay for fixing the bugs in this patch.
    
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2609e7b9bebfd433254c02538ba803dc516ff674
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Mon Apr 30 17:55:03 2007 -0700

    sysfs: printk format warning
    
    Fix sysfs printk format warning:
    fs/sysfs/bin.c:62: warning: format '%d' expects type 'int', but argument 4 has type 'size_t'
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 3265b54556b2d8ed4e9612b08edb592b60205c40
Author: Rolf Eike Beer <eike-kernel@sf-tec.de>
Date:   Tue May 1 11:00:19 2007 +0200

    DOC: Fix wrong identifier name in Documentation/driver-model/devres.txt
    
    Above and below we talk about my_midlayer_create_something, I assume that is
    also meant here.
    
    Signed-off-by: Rolf Eike Beer <eike-kernel@sf-tec.de>
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit dc4c15d44b2b43279b2667baa7645c65c2ff960e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Wed May 2 20:55:54 2007 +0200

    platform: reorder platform_device_del
    
    In platform_device_del(), we currently delete the device resources
    first, then we delete the device itself. This causes a (minor) bug to
    occur when one unregisters a platform device before unregistering its
    platform driver, and the driver is requesting (in .probe()) and
    releasing (in .remove()) a resource of the device. The device
    resources are already gone by the time the driver gets the chance to
    release the resources it had been requesting, causing an error like:
    Trying to free nonexistent resource <0000000000000295-0000000000000296>
    
    If the platform driver is unregistered first, the problem doesn't
    occur, as the driver will have the opportunity to release the
    resources it had requested before the device resources themselves are
    released. It's a bit odd that unregistering the driver first or the
    device first doesn't lead to the same result.
    
    So I believe that we should delete the device first in
    platform_device_del(). I've searched the git history and found that it
    used to be the case before 2.6.8, but was changed here:
    
    http://www.kernel.org/git/?p=linux/kernel/git/torvalds/old-2.6-bkcvs.git;a=commitdiff;h=96ef7b3689936ee1e64b711511342026a8ce459c
    
    > 2004/07/14 16:09:44-07:00 dtor_core
    > [PATCH] Driver core: Fix OOPS in device_platform_unregister
    >
    > Driver core: platform_device_unregister should release resources first
    >              and only then call device_unregister, otherwise if there
    >              are no more references to the device it will be freed and
    >              the fucntion will try to access freed memory.
    
    However we now have an explicit call to put_device() at the end of
    platform_device_unregister() so I guess the original problem no longer
    exists and it is safe to revert that change.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c7308c81a8220ab68eebfadde37db881a2800064
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Wed May 2 14:14:11 2007 +0200

    Driver core: fix show_uevent from taking up way too much stack
    
    Declaring an array of PAGE_SIZE does bad things for people running with
    4k stacks...
    
    Thanks to Tilman Schmidt for tracking this down.
    
    Cc: Tilman Schmidt <tilman@imap.cc>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 9315f130e11249457f5c3a7f74ee82a7065bd854
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Tue May 1 17:44:20 2007 -0700

    ocfs2: Force use of GFP_NOFS in ocfs2_write()
    
    We can otherwise recurse into the file system.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 5fdf1e677127cb460c38733b9586b772d657be43
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Apr 27 16:50:03 2007 -0700

    ocfs2: fix sparse warnings in fs/ocfs2/cluster
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit a7d25539fdd43fe962a0654542ba96e889ac62b5
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Apr 27 16:49:20 2007 -0700

    ocfs2: fix sparse warnings in fs/ocfs2/dlm
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 1ca1a111b1e6be843c9ce5245dcd570312998d94
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Apr 27 16:01:25 2007 -0700

    ocfs2: fix sparse warnings in fs/ocfs2
    
    None of these are actually harmful, but the noise makes looking for real
    problems difficult.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 6e4b0d5692cd27d3c9be893a9f5939a9cafbb09f
Author: Jan Kara <jack@suse.cz>
Date:   Fri Apr 27 11:08:01 2007 -0700

    [PATCH] Copy i_flags to ocfs2 inode flags on write
    
    Propagate flags such as S_APPEND, S_IMMUTABLE, etc. from i_flags into
    ocfs2-specific ip_attr. Hence, when someone sets these flags via a different
    interface than ioctl, they are stored correctly.
    
    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 5c2c9d383ef7f7cfc02d6355798b95988de359b4
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 26 00:29:35 2007 -0700

    [PATCH] ocfs2: use __set_current_state()
    
    use __set_current_state(TASK_*) instead of current->state = TASK_*, in
    fs/ocfs2
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit ee19a77956cb65c5da54d85a5efefe50b39fa6e5
Author: Joel Becker <joel.becker@oracle.com>
Date:   Wed Mar 28 18:27:07 2007 -0700

    ocfs2: Wrap access of directory allocations with ip_alloc_sem.
    
    OCFS2_I(inode)->ip_alloc_sem is a read-write semaphore protecting
    local concurrent access of ocfs2 inodes.  However, ocfs2 directories were
    not taking the semaphore while they accessed or modified the allocation
    tree.
    
    ocfs2_extend_dir() needs to take the semaphore in a write mode when it
    adds to the allocation.  All other directory users get there via
    ocfs2_bread(), which takes the semaphore in read mode.
    
    Signed-off-by: Joel Becker <joel.becker@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 6cb129f5675c39944e5fe18fd2530a2eb771b754
Author: Adrian Bunk <bunk@stusta.de>
Date:   Thu Apr 26 00:29:35 2007 -0700

    [PATCH] fs/ocfs2/: make 3 functions static
    
    This patch makes the following needlessly global functions static:
    - aops.c: ocfs2_write_data_page()
    - dlmglue.c: ocfs2_dump_meta_lvb_info()
    - file.c: ocfs2_set_inode_size()
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 586d232b191b776a1c6d51c10c662b8b3e238fdf
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Mar 9 15:56:28 2007 -0800

    ocfs2: Implement compat_ioctl()
    
    We need this to support 32 bit system calls on 64 bit kernels.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 04c58f8196b386948abf68128605de3d2db3c6ba
Author: Andy Green <andy@warmcat.com>
Date:   Wed May 2 12:49:06 2007 +0100

    kbuild: scripts/basic/fixdep segfault on pathological string-o-death
    
    build scripts: fixdep blows segfault on string CONFIG_MODULE seen
    
    The string "CONFIG_MODULE" appearing anywhere in a source file causes
    fixdep to segfault.  This string appeared in the wild in the current
    mISDN sources (I think they meant CONFIG_MODULES).  But it shouldn't
    segfault (esp as CONFIG_MODULE appeared in a quoted string).
    
    Signed-off-by: Andy Green <andy@warmcat.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 1e093ecd4a850ad61b93d84c221e342a67ea9d56
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Apr 30 15:44:27 2007 -0400

    kconfig: correct minor typo in Kconfig warning message.
    
    Correct a minor spelling mistake in a Kconfig warning message.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 39f5fb30351efa9d6f6e22754c222354fa2b7e1e
Author: Alexander E. Patrakov <patrakov@ums.usu.ru>
Date:   Fri Mar 16 18:28:43 2007 +0500

    kconfig: fix path to modules.txt in Kconfig help
    
    Documentation/modules.txt doesn't exist, but
    Documentation/kbuild/modules.txt does.
    
    Signed-off-by: Alexander E. Patrakov
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 0979f378e4f8bd8896bd63179d9a9dce501616dc
Author: Alexander E. Patrakov <patrakov@ums.usu.ru>
Date:   Fri Mar 16 18:01:45 2007 +0500

    usr/Kconfig: fix typo
    
    Signed-off-by: Alexander E. Patrakov
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit f15a3ccdc800cef08b346fef5f96860a05e7a3fa
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed Apr 11 08:44:12 2007 -0700

    kernel-doc: alphabetically-sorted entries in index.html of 'htmldocs'
    
    Make docbook index.html contain sorted output.
    
    I prefer to let the computer do it.  This also avoids
    people not reading the comment(s).
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 7ac1c145250adaccf4dbde77a8f811e937aa43c8
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed Apr 4 21:58:41 2007 -0700

    kbuild: be more explicit on missing .config file
    
    Somewhat in reponse to kernel bugzilla #8197, be more explicit about
    why 'make all' fails when there is no .config file.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 6e5a5420b7cdac356efbdc7832e90a805670b889
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue May 1 23:08:11 2007 +0200

    kbuild: clarify the creation of the LOCALVERSION_AUTO string.
    
    Clarify the creation of the LOCALVERSION_AUTO string during kernel
    configuration, and fix a couple typoes while we're there.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit eda890af7959a79ab10a7a8ae979dadcdba41c58
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Mon Apr 30 15:34:15 2007 +1000

    kbuild: propagate errors from find in scripts/gen_initramfs_list.sh
    
    If the find(1) in scripts/gen_initramfs_list.sh generates any errors, it
    will cause gen_initramfs_list.sh to fail (because of "set -e"), however
    the errors from find are not printed to the user. This is rather confusing:
    
    ~/src/powerpc$ make O=~/build/powerpc-cell32/
    make[2]: *** [usr/initramfs_data.cpio.gz] Error 1
    make[1]: *** [usr] Error 2
    make[1]: *** Waiting for unfinished jobs....
    make[1]: *** wait: No child processes.  Stop.
    make: *** [_all] Error 2
    
    It is much easier to work out what the problem is if we let the errors
    from find hit the console, eg:
    
    ~/src/powerpc$ make O=~/build/powerpc-cell32/
    find: /home/michael/initramfs-source/home: Permission denied
    find: /home/michael/initramfs-source/lost+found: Permission denied
    find: /home/michael/initramfs-source/opt: Permission denied
    find: /home/michael/initramfs-source/root: Permission denied
    make[2]: *** [usr/initramfs_data.cpio.gz] Error 1
    make[1]: *** [usr] Error 2
    make[1]: *** Waiting for unfinished jobs....
    make[1]: *** wait: No child processes.  Stop.
    make: *** [_all] Error 2
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 9ae57004ca9c38ff8292c38a475c98b0ebbc0d74
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun Apr 29 21:01:52 2007 +0200

    kconfig: refer to qt3 if we cannot find qt libraries
    
    We do not support qt4 (yet) so the simple fix was to warn
    that qt3 are missing.
    The better fix would have been to implment qt4 support
    but that has failed so far.
    
    This solves http://bugzilla.kernel.org/show_bug.cgi?id=8277
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit c299ec2d8e8d2f1a99d5c993fca485257b950d40
Author: Alex Landau <landau.alex@gmail.com>
Date:   Thu Apr 26 00:17:29 2007 -0700

    kbuild: handle compressed cpio initramfs-es
    
    Make kbuild handle compressed cpio initramfs-es.  An already compressed
    cpio is copied directly to usr/, while a non-compressed cpio is filtered
    through gzip (no changes here) on its way to usr/.
    
    If the user has created a compressed cpio by other means, this saves him
    from uncompressing it, just to be compressed again by kbuild.
    
    Signed-off-by: Alex Landau <landau.alex@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit b4d5171ac7d9806b1ea61903ff954cd9620135bf
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun Apr 29 20:53:01 2007 +0200

    kbuild: ignore section mismatch warning for references from .paravirtprobe to .init.text
    
    Added on request from:  Rusty Russell <rusty@rustcorp.com.au>
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc:  Rusty Russell <rusty@rustcorp.com.au>

commit 66bd32e443203735b00f22bede637ec98f3070ca
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun Apr 29 20:40:53 2007 +0200

    kbuild: remove stale comment in modpost.c
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit f03e1666d6164da6f098dc1a2e539eced3e4461a
Author: Uwe kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
Date:   Wed Mar 28 16:55:55 2007 +0200

    kbuild/mkuboot.sh: allow spaces in CROSS_COMPILE
    
    I'm currently using CROSS_COMPILE="ccache arm-linux-".  With that the bash
    builtin command "type" searches for ccache and arm-linux-mkimage and so sets
    MKIMAGE="/path/to/ccache" as I don't have arm-linux-mkimage.  Then the script
    dies with an error, that ccache doesn't support the argument -A.
    
    This patch adds some quoting such that it works again for me.
    
    Please note that this patch doesn't help you if you use ${CROSSCOMPILE}-mkimage
    and ccache as mkuboot.sh now searches for the command
    "ccache arm-linux-mkimage".
    
    Signed-off-by: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit e711db3edfe7c0e32b6430e7d041905f856aa79a
Author: Sam Ravnborg <sam@neptun.ravnborg.org>
Date:   Fri Apr 13 23:07:00 2007 +0200

    kbuild: fix make mrproper for Documentation/DocBook/man
    
    "make mandocs" generate > 2000 files in Documentation/DocBook/man
    and this caused kbuild to barf out during make mrproper like this:
    
    make -f scripts/Makefile.clean obj=Documentation/DocBook
    make -f scripts/Makefile.clean obj=Documentation/DocBook/man/
    make[2]: execvp: /bin/sh: Argument list too long
    make[2]: *** [__clean] Error 127
    make[1]: *** [Documentation/DocBook/man/] Error 2
    make: *** [_mrproper_Documentation/DocBook] Error 2
    
    The man directory were solely used for output
    so the fix is to remove it entirely during the
    make mrproper process.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Acked-by: Randy Dunlap <randy.dunlap@oracle.com>

commit 145c90475f809060c8601828f14543191e06a0bb
Author: Sam Ravnborg <sam@neptun.ravnborg.org>
Date:   Sun Apr 1 23:14:11 2007 +0200

    kbuild: remove kconfig binaries during make mrproper
    
    Nigel Cunningham <nigel@nigel.suspend2.net> noticed
    that 'make mrproper' did not remove mconf.
    Fixed so we now remove all relevant binaries.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc:  Nigel Cunningham <nigel@nigel.suspend2.net>

commit d802b50f0d63d2d18d8dae15d7e3285e99e7e7b6
Author: Sam Ravnborg <sam@neptun.ravnborg.org>
Date:   Sun Apr 1 22:29:38 2007 +0200

    kconfig/menuconfig: do not hardcode '.config'
    
    Export and use the function conf_get_configname()
    to retreive the default configuration filename.
    
    Suggested by: Roman Zippel <zippel@linux-m68k.org>
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 87c94bfb8ad354fb43d2caf870d7ca0b3f98dab3
Author: Sam Ravnborg <sam@neptun.ravnborg.org>
Date:   Sun Apr 1 21:49:27 2007 +0200

    kbuild: override build timestamp & version
    
    Introduce KBUILD_BUILD_VERSION to make it
    possible to override kernel build version
    during build time.
    
    Introduce KBUILD_BUILD_TIMESTAMP to make it
    possible to override kernel build timestamp
    during build time.
    
    But variables are useful mainly by distros
    that want to pass info from an SCM when
    building the kernel. Timestamp could be last
    checkin date for a file etc.
    
    The idea came from Olaf Hering <olaf@aepfle.de>
    
    Cc: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit b72e53f8bbbec8421316220291d8a8002a5562ba
Author: Andreas Dilger <adilger@clusterfs.com>
Date:   Tue Mar 27 15:21:33 2007 -0600

    kconfig.debug: clarify CONFIG_DEBUG_INFO help text
    
    The following patch adds some extra clarification to the CONFIG_DEBUG_INFO
    Kconfig help text.  The current text is mostly a recursive definition and
    doesn't really say much of anything.  When I first read this I thought it
    was going to enable extra verbosity in debug messages or something, but it
    is only enabling the "gcc -g" compile option in the Makefile.
    
    Signed-off-by: Andreas Dilger <adilger@clusterfs.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit c53aeca059c4d2108335810fba6ba89ab6a944dd
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Tue Mar 27 22:50:29 2007 +0200

    kbuild: complain about missing system calls
    
    Most system calls seems to get added to i386 first. This patch
    automatically generates a warning for any new system call which is
    implemented on i386 but not the architecture currently being compiled.
    On PowerPC at the moment, for example, it results in these warnings:
    init/missing_syscalls.h:935:3: warning: #warning syscall sync_file_range not implemented
    init/missing_syscalls.h:947:3: warning: #warning syscall getcpu not implemented
    init/missing_syscalls.h:950:3: warning: #warning syscall epoll_pwait not implemented
    
    The file scripts/checksyscalls.sh list a number of legacy system calls
    that are ignored because they only makes sense on i386 systems.
    
    Other contributors to this patch are Russell King <rmk+lkml@arm.linux.org.uk>
    and StÃ©phane Jourdois <kwisatz@rubis.org>
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit ded2e1640ffaee26c054a42e5210c1086fb1d8eb
Author: Anton Blanchard <anton@samba.org>
Date:   Tue Mar 20 09:47:47 2007 -0500

    kbuild: small documentation fix in Documentation/kbuild/modules.txt
    
    The Makefile fragment in Documentation/kbuild/modules.txt looks to be
    missing some braces.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 4be40e22233cfe6254bbf039ec09a5d7bff2ad14
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Tue Mar 20 21:30:23 2007 +0100

    kbuild: do not emit src version warning for non-modules
    
    modpost is now called with .o files that are not modules.
    So do not warn if there is no corresponding .mod
    file listing .o files (in .tmp_versions/).
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 95e30f9593ebf39e26227a20ae8d9f160c50fb67
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sun Mar 18 10:48:46 2007 +0100

    menuconfig: remember alternate config filename
    
    When loading an alternate configuration use that file as
    current configuration filename.
    Make the filename visible in the dialog.
    Default continue to be .config.
    
    Inspired by patch from: Cyrill Gorcunov <gorcunov@gmail.com>
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc:  Cyrill Gorcunov <gorcunov@gmail.com>

commit dd7e54ade8f515ec38d5dc2129705352e2296f8e
Author: Don Mullis <dwm@meer.net>
Date:   Thu Jan 4 10:14:52 2007 -0800

    kbuild: move tags from ARCH and include/ ahead of drivers
    
    Move tags extracted from the ARCH and include/ sub-trees ahead of
    those from device drivers, so that the former will appear first
    during searches.
    
    Saves user time during interactive searches for certain patterns
    that happen to find unwanted matches in driver files.
    
    Example in emacs:
    	 "M-x find-tag PAGE_SIZE"
    	 "M-1 M-." (repeated until definition from asm-i386/page.h appears)
    
    Signed-off-by: Don Mullis <dwm@meer.net>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 2a11665945d510e1a4df8dc44dc3668b01945ade
Author: Matthew Wilcox <matthew@wil.cx>
Date:   Sat Oct 7 05:35:32 2006 -0600

    kbuild: distinguish between errors and warnings in modpost
    
    Some of modpost's warnings are fatal, and some are not.  Adopt the
    compiler distinction between errors and warnings by calling merror()
    for fatal diagnostics and warn() for non-fatal ones.
    merror() was used as replacemtn for error() to avoid clash with glibc
    
    Signed-off-by: Matthew Wilcox <matthew@wil.cx>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 63431e75691c410819023ab0e6cd047cbfcf64e2
Author: Marco Costalba <mcostalba@gmail.com>
Date:   Thu Oct 5 19:12:59 2006 +0200

    kconfig/xconfig: sync main view with search dialog current menu
    
    When changing current menu in search dialog update also main view
    
    Signed-off-by: Marco Costalba <mcostalba@gmail.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit f88d205501e35195444bdd41983e26546af3f56a
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Sat Mar 17 02:37:07 2007 -0400

    menuconfig: dont use obsolete index() function in lxdialog
    
    The index() function is obsolete, use strchr() instead.
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 2462566f21a5ecdb2a7e75e09db90ff175b1f748
Author: Uwe Zeisberger <zeisberg@informatik.uni-freiburg.de>
Date:   Thu Oct 5 16:24:45 2006 +0200

    kbuild: add a missing slash in the comments
    
    Signed-off-by: Uwe Zeisberger <zeisberg@informatik.uni-freiburg.de>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 6e019b001d27c4289f8e48ebc458e92410446259
Author: H. Peter Anvin <hpa@zytor.com>
Date:   Fri Mar 16 14:45:06 2007 -0700

    cleanpatch: a script to clean up stealth whitespace added by a patch
    
    This script is a companion to the "cleanfile" script.  This cleans
    up a patch in unified diff format *before* it is applied.  Note that
    the empty lines at the end of file detection *requires* that the diff was
    taken with at least one line of context around each hunk, or bad things
    will happen.
    
    This script cleans up various classes of stealth whitespace.  In
    particular, it cleans up:
    
    - Whitespace (spaces or tabs)before newline;
    - DOS line endings (CR before LF);
    - Space before tab (spaces are deleted or converted to tabs);
    - Empty lines at end of file.
    
    Signed-off-by: H. Peter Anvin <hpa@zytor.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 12b315603a1eb95b4e4ea3389ba44bd7ded0aa35
Author: H. Peter Anvin <hpa@zytor.com>
Date:   Mon Mar 12 12:16:30 2007 -0700

    cleanfile: a script to clean up stealth whitespace
    
    This script cleans up various classes of stealth whitespace.  In
    particular, it cleans up:
    
    - Whitespace (spaces or tabs)before newline;
    - DOS line endings (CR before LF);
    - Space before tab (spaces are deleted or converted to tabs);
    - Empty lines at end of file.
    
    Signed-off-by: H. Peter Anvin <hpa@zytor.com>
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit dc24f0e708c8a6a27b5b967a2599c04973054398
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Fri Mar 9 19:59:06 2007 +0100

    kbuild: remove dependency on input.h from file2alias
    
    Almost all definitions used by file2alias was already
    present in mod_devicetable.h.
    Added the last definition and killed the input.h usage.
    
    The errornous include was pointed out
    by: Jan Engelhardt <jengelh@linux01.gwdg.de>
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Cc: Jan Engelhardt <jengelh@linux01.gwdg.de>
    Cc: Deepak Saxena <dsaxena@plexity.net>

commit 5a4910fbbeef14cc91daa41086449a1a4acebc96
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Tue Feb 27 09:14:58 2007 +0100

    kbuild: whitelist logo references from .text to .init.data
    
    drivers/video/logo has references from .text to .init.data
    but function is only used during early init.
    So reference is OK and we do not want to warn about them =>
    whitelist the reference.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit a61b2dfd1823506dbf1f9b046e0b09237ec1b985
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Mon Feb 26 19:46:52 2007 +0100

    kbuild: fix segmentation fault in modpost
    
    If modpost was called manually with filenames without '/'
    then modpost would segfault.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 9bf8cb9b7908383752b1842eae78269f7e16d9fb
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Mon Feb 26 17:49:06 2007 +0100

    kbuild: fix warnings from .pci_fixup section
    
    Now where we do not pass vmlinux to modpost we started
    to see section mismatch warnings from .pci_fixup.
    Refactored code a little to include these in the
    whitelist again.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit aae5f662a32c35b1a962627535acb588d48ff5f9
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Mon Feb 26 16:45:41 2007 +0100

    kbuild: whitelist section mismatch in init/main.c
    
    In init/main.c we have a reference from rest_init() to .init.text
    which is intentional.
    Rename the function 'init' to 'kernel_init' to make it a
    kernel wide unique symbol and whitelist the reference.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 85bd2fddd68e757da8e1af98f857f61a3c9ce647
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Mon Feb 26 15:33:52 2007 +0100

    kbuild: fix section mismatch check for vmlinux
    
    vmlinux does not contain relocation entries which is
    used by the section mismatch checks.
    Reported by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    
    Use the individual objects as inputs to overcome
    this limitation.
    In modpost check the .o files and skip non-ELF files.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>

commit 35060b6a9a4e1c89bc6fbea61090e302dbc61847
Author: Thomas Renninger <trenn@suse.de>
Date:   Wed May 2 19:27:22 2007 +0200

    [PATCH] i386: Don't delete cpu_devs data to identify different x86 types in late_initcall
    
    In arch/i386/cpu/common.c there is:
    cpu_devs[X86_VENDOR_INTEL]
    cpu_devs[X86_VENDOR_CYRIX]
    cpu_devs[X86_VENDOR_AMD]
    ...
    They are all filled with data early.
    The data (struct) got set to NULL  for all, but Intel in different
    late_initcall (exit_cpu_vendor) calls.
    I don't see what sense this makes at all, maybe something that got
    forgotten with the HOTPLUG_CPU extenstions?
    
    Please check/review whether initdata, cpuinitdata is still ok and this
    still works with HOTPLUG_CPU and without, it should...
    
    Signed-off-by: Thomas Renninger <trenn@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: davej@redhat.com

commit a3193348d407baaa7aef79decfa0e9a7fef74a17
Author: David Rientjes <rientjes@google.com>
Date:   Wed May 2 19:27:22 2007 +0200

    [PATCH] i386: type may be unused
    
    In the case of !CONFIG_PCI_DIRECT && !CONFIG_PCI_MMCONFIG, type is
    unreferened.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b5229dbb857f61d77d8d4048d9033387a5411b8e
Author: Olivier Galibert <galibert@pobox.com>
Date:   Wed May 2 19:27:22 2007 +0200

    [PATCH] i386: Some additional chipset register values validation.
    
    On i945, a mmconfig range hitting the f0000000-ffffffff zone conflicts
    with the APIC registers and others.  Consider it invalid.
    
    On E7520, values 0000 and f000 for the window register are defined
    invalid in the documentation.
    
    I haven't seen a bios use these values, but who trusts biosen these
    days?
    
    Signed-off-by: Olivier Galibert <galibert@pobox.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    
     arch/i386/pci/mmconfig-shared.c |   25 +++++++++++++++++--------
     1 file changed, 17 insertions(+), 8 deletions(-)

commit 6c2af35820f100bde7b9de8a00a76faa7af6bede
Author: Bill Irwin <bill.irwin@oracle.com>
Date:   Wed May 2 19:27:22 2007 +0200

    [PATCH] i386: Add missing !X86_PAE dependincy to the 2G/2G split.
    
    Only 1GB-aligned kernel/user splits are now handled for PAE. The
    2GB/2GB split attempts to avoid aliasing vmallocspace with the 1:1
    mapping for physical memory by using an actual split of 1.875/2.125
    to accommodate 128MB of vmallocspace out of what would otherwise
    be a full 2GB for userspace. That attempt disturbs the alignment
    required by PAE for 2GB/2GB splits, and furthermore does not provide
    a 2GB/2GB split as advertised.
    
    This patch resolves the issues here in two manners. The first is
    by providing a true 2GB/2GB split in addition to the 1.875/2.125
    split. The second is by renaming the 1.875/2.125 split to
    CONFIG_VMSPLIT_2G_OPT analogously to CONFIG_VMSPLIT_3G_OPT, which
    performs a similar manuever to avoid aliasing vmallocspace with
    the 1:1 mapping for physical memory around the 3GB boundary. With
    the 1.875/2.125 split properly-named, its config option is then
    tagged as depending on !HIGHMEM to express the PAE implementation's
    current inability to deal with such unaligned splits.
    
    This patch is essentially a combination of two patches, one written
    by Eric Biederman and the other by Eric Dumazet. If they could add
    their Signed-off-by: to this, I'd be much obliged.
    
    Signed-off-by: William Irwin <wli@holomorphy.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Eric Dumazet <dada1@cosmosbay.com>
    Cc: Mark Lord <lkml@rtr.ca>
    Cc: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>

commit b466004a660c490f3bfb12be8b5ca18bfc393261
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Don't exclude asm-offsets.c in Documentation/dontdiff
    
    asm-offsets.c is valid source code and needs to be diffed.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c41bf8fa5e777b6a8a19cf2484937a7167eac77f
Author: Jan Kiszka <jan.kiszka@web.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] i386: avoid redundant preempt_disable in __unlazy_fpu
    
    There are two callers of __unlazy_fpu, unlazy_fpu and __switch_to, and
    none of them appear to require additional preempt_disable/enable here.
    Let's open-code save_init_fpu in __unlazy_fpu to save a few ops.
    
    Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 02b64dab5675bc08048c7f70cbb0d8a417d20dbe
Author: Jan Kiszka <jan.kiszka@web.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] i386: white space fixes in i387.h
    
    Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1306383282aaf58e85e5461404db367be0f88dca
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] i386: Drop noisy e820 debugging printks
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f19cccf366a07e05703c90038704a3a5ffcb0607
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Fix allnoconfig error in genapic_flat.c
    
    Fix:
    
    In file included from include2/asm/apic.h:5,
                     from include2/asm/smp.h:15,
                     from linux/arch/x86_64/kernel/genapic_flat.c:18:
    linux/include/linux/pm.h: In function â€˜call_platform_enable_wakeupâ€™:
    linux/include/linux/pm.h:331: error: â€˜EIOâ€™ undeclared (first use in this function)
    linux/include/linux/pm.h:331: error: (Each undeclared identifier is reported only once
    linux/include/linux/pm.h:331: error: for each function it appears in.)
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2724b6db663a4efb69462ff6eb8f88d7528cace3
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Shut up warnings for vfat compat ioctls on other file systems
    
    vfat implements compat handlers for these ioctls, but when they
    were executed on other file systems the kernel would still complain
    about an unknown compat ioctl.  Just declare them as compatible
    and let them be rejected when not needed by the normal path.
    
    This makes wine runs a lot quieter
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit fac15a8e4d4c36eb4676bfd2c30ea16ad05c401a
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Share identical video.S between i386 and x86-64
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2136220d00d84e5dd923f23552f75b1864a76f21
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Remove CONFIG_REORDER
    
    The option never worked well and functionlist wasn't well maintained.
    Also it made the build very slow on many binutils version.
    
    So just remove it.
    
    Cc: arjan@linux.intel.com
    Signed-off-by: Andi Kleen <ak@suse.de>

commit a106009bdfa12b6452b724cc0718ca8e1334745d
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Print type and size correctly for unknown compat ioctls
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c812d6c198c5f39a6ea22a9a12d518cd3714af16
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] i386: Remove copy_*_user BUG_ONs for (size < 0)
    
    access_ok checks this case anyways, no need to check twice.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ec1180db2ca2ec8692ce101560eff9eedf561781
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] i386: Little cleanups in smpboot.c
    
    - Remove #if that is always set
    - Fix warning
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3bea9c9793a17053e05d970e5d90d48fc9fce07d
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86-64: Don't enable NUMA for a single node in K8 NUMA scanning
    
    This was supposed to see the full memory on a ASUS A8SX motherboard
    with 4GB RAM where the northbridge reports less memory, but it didn't
    help there. But it's a reasonable change so let's include it anyways.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c5bcb5635a03da3158f121ae20ccbbf72b4fc62a
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:21 2007 +0200

    [PATCH] x86: Use RDTSCP for synchronous get_cycles if possible
    
    RDTSCP is already synchronous and doesn't need an explicit CPUID.
    This is a little faster and more importantly avoids VMEXITs on Hypervisors.
    
    Original patch from Joerg Roedel, but reworked by AK
    Also includes miscompilation fix by Eric Biederman
    
    Cc: "Joerg Roedel" <joerg.roedel@amd.com>
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9bccb23dc5fc2d268ab676e2d4212d29e230fd86
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Add X86_FEATURE_RDTSCP
    
    Following x86-64
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3aefbe0746580a710d4392a884ac1e4aac7c728f
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Implement X86_FEATURE_SYNC_RDTSC on i386
    
    Syncs up with x86-64.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit e859dc553c857f4672b3bbb73ee9170a901f8712
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Implement alternative_io for i386
    
    Ported from x86-64.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3671df8572a299acff9c9cac2bf7279ee614d154
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Evaluate constant cpu features at runtime
    
    Redefine cpu_has() to evaluate cpu features already checked in early
    boot at compile time.  This way the compiler might eliminate some dead code.
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c7f81c9453375d6416658995eafd3397cb9bba1d
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Verify important CPUID bits in real mode
    
    Check some CPUID bits that are needed for compiler generated early in boot.
    When the system is still in real mode before changing the VESA BIOS mode
    it is possible to still display an visible error message on the screen.
    
    Similar to x86-64.
    
    Includes cleanups from Eric Biederman
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 484ad393659f20d784a3a93613fb3fd3d9f171fa
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Drop -traditional in arch/i386/boot
    
    Needed for followon patch
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit fa0a00910925fdbd3a528404a47817b3a9fda5be
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Drop -traditional for arch/x86_64/boot
    
    Follows i386 and useful cleanup.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 72b1b1d0133d7eb4040697f1052bf92123fb051b
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Use symbolic CPU features in early CPUID check
    
    Dead to magic numbers!
    
    Generated code is the same.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 4637a74cf2ac3a3696d385c8624d84de789d1bbe
Author: David P. Reed <dpreed@reed.com>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Avoid overflows during apic timer calibration
    
    - Use 64bit TSC calculations to avoid handling overflow
    - Use 32bit unsigned arithmetic for the APIC timer. This
    way overflows are handled correctly.
    - Fix exit check of loop to account for apic timer counting down
    
    Signed-off-by: dpreed@reed.com
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9d016dd43b8df0228f1022f483f582eeb52d256e
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Shut up 32bit emulation for SIOCGIFCOUNT
    
    The kernel doesn't implement it, but some programs like java use it
    anyways. Shut the code up.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 421f028100cbef0ba15086d63cad87fb6e5c3da9
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Define IGNORE_IOCTL() macro for compat_ioctls
    
    Define a new IGNORE_IOCTL() to let a compat ioctl not be warned about even when
    it is not implemented.
    
    This is the same as COMPATIBLE_IOCTL internally, but better self documentng.
    
    Valid reasons to use this:
    - It is implemented with ->compat_ioctl on some device, but programs
      call it on others too.
    - The ioctl is not implemented in the native kernel, but programs
      call it commonly anyways.
    Most other reasons are not valid.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 05cb007dac9a50148daf87d0b9469e0cd05fd5e7
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: Use the 32bit wd_ops for 64bit too.
    
    This mainly removes a lot of code, replacing it with calls into the new 32bit
    perfctr-watchdog.c
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 09198e68501a7e34737cd9264d266f42429abcdc
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] i386: Clean up NMI watchdog code
    
    - Introduce a wd_ops structure
    - Convert the various nmi watchdogs over to it
    - This allows to split the perfctr reservation from the watchdog
    setup cleanly.
    - Do perfctr reservation globally as it should have always been
    - Remove dead code referenced only by unused EXPORT_SYMBOLs
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit e3f1caeef9a70b0699518092d653c15274b025ab
Author: Suresh Siddha <suresh.b.siddha@intel.com>
Date:   Wed May 2 19:27:20 2007 +0200

    [PATCH] x86-64: set node_possible_map at runtime - try 2
    
    Set the node_possible_map at runtime on x86_64.  On a non NUMA system,
    num_possible_nodes() will now say '1'.
    
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <andi@firstfloor.org>
    Cc: Eric Dumazet <dada1@cosmosbay.com>
    Cc: David Rientjes <rientjes@google.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>

commit 8a336b0a4b6dfacc8cc5fd617ba1e1904077de2d
Author: Tim Hockin <thockin@google.com>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] x86-64: Dynamically adjust machine check interval
    
    Background:
     We've found that MCEs (specifically DRAM SBEs) tend to come in bunches,
     especially when we are trying really hard to stress the system out.  The
     current MCE poller uses a static interval which does not care whether it
     has or has not found MCEs recently.
    
    Description:
     This patch makes the MCE poller adjust the polling interval dynamically.
     If we find an MCE, poll 2x faster (down to 10 ms).  When we stop finding
     MCEs, poll 2x slower (up to check_interval seconds).  The check_interval
     tunable becomes the max polling interval.  The "Machine check events
     logged" printk() is rate limited to the check_interval, which should be
     identical behavior to the old functionality.
    
    Result:
     If you start to take a lot of correctable errors (not exceptions), you
     log them faster and more accurately (less chance of overflowing the MCA
     registers).  If you don't take a lot of errors, you will see no change.
    
    Alternatives:
     I considered simply reducing the polling interval to 10 ms immediately
     and keeping it there as long as we continue to find errors.  This felt a
     bit heavy handed, but does perform significantly better for the default
     check_interval of 5 minutes (we're using a few seconds when testing for
     DRAM errors).  I could be convinced to go with this, if anyone felt it
     was not too aggressive.
    
    Testing:
     I used an error-injecting DIMM to create lots of correctable DRAM errors
     and verified that the polling interval accelerates.  The printk() only
     happens once per check_interval seconds.
    
    Patch:
     This patch is against 2.6.21-rc7.
    
    Signed-Off-By: Tim Hockin <thockin@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f82af20e1a028e16b9bb11da081fa1148d40fa6a
Author: Gerd Hoffmann <kraxel@suse.de>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] x86-64: ignore vgacon if hardware not present
    
    Avoid trying to set up vgacon if there's no vga hardware present.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Alan <alan@lxorguk.ukuu.org.uk>
    Acked-by: Ingo Molnar <mingo@elte.hu>

commit 889f21ce272e38db19c8114a7e0a5793d4590077
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] i386: fix wrong comment for syscall stack layout
    
    `ret_from_sys_call' label no longer exist and `syscall_exit' label was
    introduced instead.
    
    Signed-off-by: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 425001fea782dd072cfec5694b93778eb59a1fd3
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] x86-64: unexport cpu_llc_id
    
    WARNING: arch/x86_64/kernel/built-in.o - Section mismatch: reference to .init.data:cpu_llc_id from __ksymtab between '__ksymtab_cpu_llc_id' (at offset 0x4a0) and '__ksymtab_smp_num_siblings'
    
    It is strange to export a __cpuinitdata symbols to modules, and no module
    appears to use it anyway.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f26d6a2bbcf381230df771123578380584004631
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] i386: convert to the kthread API
    
    This patch just trivial converts from calling kernel_thread and daemonize
    to just calling kthread_run.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 9e5e3162b2d5e4466187ecd63c9eec2de33cb7bc
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] i386: pte simplify ops
    
    Add comment and condense code to make use of native_local_ptep_get_and_clear
    function.  Also, it turns out the 2-level and 3-level paging definitions were
    identical, so move the common definition into pgtable.h
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 142dd975911fdd82b1b6f6617cd20ac90a8ccf00
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] i386: pte xchg optimization
    
    In situations where page table updates need only be made locally, and there is
    no cross-processor A/D bit races involved, we need not use the heavyweight
    xchg instruction to atomically fetch and clear page table entries.  Instead,
    we can just read and clear them directly.
    
    This introduces a neat optimization for non-SMP kernels; drop the atomic xchg
    operations from page table updates.
    
    Thanks to Michel Lespinasse for noting this potential optimization.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c2c1accd4b2f9c82fb89d40611c7f581948db255
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:19 2007 +0200

    [PATCH] i386: pte clear optimization
    
    When exiting from an address space, no special hypervisor notification of page
    table updates needs to occur; direct page table hypervisors, such as Xen,
    switch to another address space first (init_mm) and unprotects the page tables
    to avoid the cost of trapping to the hypervisor for each pte_clear.  Shadow
    mode hypervisors, such as VMI and lhype don't need to do the extra work of
    calling through paravirt-ops, and can just directly clear the page table
    entries without notifiying the hypervisor, since all the page tables are about
    to be freed.
    
    So introduce native_pte_clear functions which bypass any paravirt-ops
    notification.  This results in a significant performance win for VMI and
    removes some indirect calls from zap_pte_range.
    
    Note the 3-level paging already had a native_pte_clear function, thus
    demanding argument conformance and extra args for the 2-level definition.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit df3624aa293dfa2d46089747d919711089a702eb
Author: Daniel Walker <dwalker@mvista.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: remove xtime_lock'ing around cpufreq notifier
    
    The locking of the xtime_lock around the cpu notifier is unessesary now.
    At one time the tsc was used after a frequency change for timekeeping, but
    the re-write of timekeeping no longer uses the TSC unless the frequency is
    constant.
    
    The variables that are changed in this section of code had also once been
    used for timekeeping, but not any longer ..
    
    Signed-off-by: Daniel Walker <dwalker@mvista.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: john stultz <johnstul@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 62918a036148230ba1ad175dc8a0952e3752ac57
Author: Siddha, Suresh B <suresh.b.siddha@intel.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] x86-64: skip cache_free_alien() on non NUMA
    
    Set use_alien_caches to 0 on non NUMA platforms.  And avoid calling the
    cache_free_alien() when use_alien_caches is not set.  This will avoid the
    cache miss that happens while dereferencing slabp to get nodeid.
    
    Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <andi@firstfloor.org>
    Cc: Eric Dumazet <dada1@cosmosbay.com>
    Cc: David Rientjes <rientjes@google.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 57a4f91ae5571edd7c0428285d8df16bb8bf5f40
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] x86-64: Auto compute __NR_syscall_max at compile time
    
    No need to maintain it anymore
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2f3c30e6a886ddaf65cb74df82c03245050ff0aa
Author: Joachim Deguara <joachim.deguara@amd.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: check capability
    
    Currently the i386 architecture checks the family for mce capability and this
    removes that and uses the CPUID information.  Tested on a K8 revE and a
    family10h processor.
    
    This eliminates checking of a set AMD procesor family if mce is
    allowed and relies on the information being in CPUID.
    
    Signed-off-by: Joachim Deguara <joachim.deguara@amd.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 1bdae4583e7abd2c1daedfc9f46ac6420a26c1b0
Author: Keshavamurthy, Anil S <anil.s.keshavamurthy@intel.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: clean up flush_tlb_others fn
    
    Cleanup flush_tlb_others(), no functional change.
    
    Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 62dbc210e2532dec061ca65eeb8bc31b6c898b01
Author: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: replace spin_lock_irqsave with spin_lock
    
    IRQ is already disabled through local_irq_disable().  So
    spin_lock_irqsave() can be replaced with spin_lock().
    
    Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit e8a72ffa3aa618fb25b5727c0e0ae939d30d66c0
Author: Keshavamurthy, Anil S <anil.s.keshavamurthy@intel.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: avoid checking for cpu gone when CONFIG_HOTPLUG_CPU not defined
    
    Avoid checking for cpu gone in mm hot path when CONFIG_HOTPLUG_CPU is not
    defined.
    
    Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Gautham R Shenoy <ego@in.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 141a892f57972b01891df7036f567a70459c19ac
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] x86-64: move __vgetcpu_mode & __jiffies to the vsyscall_2 zone
    
    We apparently hit the 1024 limit of vsyscall_0 zone when some debugging
    options are set, or if __vsyscall_gtod_data is 64 bytes larger.
    
    In order to save 128 bytes from the vsyscall_0 zone, we move __vgetcpu_mode
    & __jiffies to vsyscall_2 zone where they really belong, since they are
    used only from vgetcpu() (which is in this vsyscall_2 area).
    
    After patch is applied, new layout is :
    
    ffffffffff600000 T vgettimeofday
    ffffffffff60004e t vsysc2
    ffffffffff600140 t vread_hpet
    ffffffffff600150 t vread_tsc
    ffffffffff600180 D __vsyscall_gtod_data
    ffffffffff600400 T vtime
    ffffffffff600413 t vsysc1
    ffffffffff600800 T vgetcpu
    ffffffffff600870 D __vgetcpu_mode
    ffffffffff600880 D __jiffies
    ffffffffff600c00 T venosys_1
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 0260c196c97e48e4b821031ae55912c22113ed87
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: PARAVIRT: fix startup_ipi_hook config dependency
    
    startup_ipi_hook depends on CONFIG_X86_LOCAL_APIC, so move it to the
    right part of the paravirt_ops initialization.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 25c16b992c32db4bc7e085b763abd866a505ca72
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: fix mtrr sections
    
    Fix section mismatch warnings in mtrr code.
    Fix line length on one source line.
    
    WARNING: arch/x86_64/kernel/built-in.o - Section mismatch: reference to .init.data: from .text.get_mtrr_state after 'get_mtrr_state' (at offset 0x103)
    WARNING: arch/x86_64/kernel/built-in.o - Section mismatch: reference to .init.text: from .text.get_mtrr_state after 'get_mtrr_state' (at offset 0x180)
    WARNING: arch/x86_64/kernel/built-in.o - Section mismatch: reference to .init.text: from .text.get_mtrr_state after 'get_mtrr_state' (at offset 0x199)
    WARNING: arch/x86_64/kernel/built-in.o - Section mismatch: reference to .init.text: from .text.get_mtrr_state after 'get_mtrr_state' (at offset 0x1c1)
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 70ae77f497a57b3ef6b0987b6310327264517cb0
Author: Fernando Luis [** ISO-8859-1 charset **] VázquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] x86-64: Use safe_apic_wait_icr_idle in __send_IPI_dest_field - x86_64
    
    Use safe_apic_wait_icr_idle to check ICR idle bit if the vector is
    NMI_VECTOR to avoid potential hangups in the event of crash when kdump
    tries to stop the other CPUs.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f5efb41e793ce587836b89b7191083b9a6185ed5
Author: Fernando Luis [** ISO-8859-1 charset **] VázquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: Use safe_apic_wait_icr_idle in safe_apic_wait_icr_idle - i386
    
    Use safe_apic_wait_icr_idle to check ICR idle bit if the vector is
    NMI_VECTOR to avoid potential hangups in the event of crash when kdump
    tries to stop the other CPUs.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9062d888aa448318e38792b6879a795dd10adda4
Author: Fernando Luis [** ISO-8859-1 charset **] VázquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] x86-64: __send_IPI_dest_field - x86_64
    
    Implement __send_IPI_dest_field which can be used to send IPIs when the
    "destination shorthand" field of the ICR is set to 00 (destination
    field). Use it whenever possible.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 45ae5e968ea01d8326833ca2863cec5183ce1930
Author: Fernando Luis [** ISO-8859-1 charset **] VázquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:18 2007 +0200

    [PATCH] i386: __send_IPI_dest_field - i386
    
    Implement __send_IPI_dest_field which can be used to send IPIs when the
    "destination shorthand" field of the ICR is set to 00 (destination
    field). Use it whenever possible.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3144c332fa2ee4c4b9804aae5fe31098f04bffd9
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86-64: use safe_apic_wait_icr_idle in smpboot.c - x86_64
    
    inquire_remote_apic is used for APIC debugging, so use
    safe_apic_wait_icr_idle  instead of apic_wait_icr_idle to avoid possible
    lockups when APIC delivery fails.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 4312fa8157f5ebdaf36e615cf40f9d7a6137a22c
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: use safe_apic_wait_icr_idle in smpboot.c
    
    __inquire_remote_apic is used for APIC debugging, so use
    safe_apic_wait_icr_idle  instead of apic_wait_icr_idle to avoid possible
    lockups when APIC delivery fails.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ea8c733b98b73289421ed8f8fc15cfbce3adc3bc
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86-64: use safe_apic_wait_icr_idle in smpboot.c - x86_64
    
    The functionality provided by the new safe_apic_wait_icr_idle is being
    open-coded all over "kernel/smpboot.c". Use safe_apic_wait_icr_idle
    instead to consolidate code and ease maintenance.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ae08e43eecd250e50ffa40c4bd62a65e005b875b
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: use safe_apic_wait_icr_idle - i386
    
    The functionality provided by the new safe_apic_wait_icr_idle is being
    open-coded all over "kernel/smpboot.c". Use safe_apic_wait_icr_idle
    instead to consolidate code and ease maintenance.
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 8339e9fba33aa3205f541478c413982c0ac5a37f
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86-64: safe_apic_wait_icr_idle - x86_64
    
    apic_wait_icr_idle looks like this:
    
    static __inline__ void apic_wait_icr_idle(void)
    {
      while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
        cpu_relax();
    }
    
    The busy loop in this function would not be problematic if the
    corresponding status bit in the ICR were always updated, but that does
    not seem to be the case under certain crash scenarios. Kdump uses an IPI
    to stop the other CPUs in the event of a crash, but when any of the
    other CPUs are locked-up inside the NMI handler the CPU that sends the
    IPI will end up looping forever in the ICR check, effectively
    hard-locking the whole system.
    
    Quoting from Intel's "MultiProcessor Specification" (Version 1.4), B-3:
    
    "A local APIC unit indicates successful dispatch of an IPI by
    resetting the Delivery Status bit in the Interrupt Command
    Register (ICR). The operating system polls the delivery status
    bit after sending an INIT or STARTUP IPI until the command has
    been dispatched.
    
    A period of 20 microseconds should be sufficient for IPI dispatch
    to complete under normal operating conditions. If the IPI is not
    successfully dispatched, the operating system can abort the
    command. Alternatively, the operating system can retry the IPI by
    writing the lower 32-bit double word of the ICR. This â€œtime-outâ€
    mechanism can be implemented through an external interrupt, if
    interrupts are enabled on the processor, or through execution of
    an instruction or time-stamp counter spin loop."
    
    Intel's documentation suggests the implementation of a time-out
    mechanism, which, by the way, is already being open-coded in some parts
    of the kernel that tinker with ICR.
    
    Create a apic_wait_icr_idle replacement that implements the time-out
    mechanism and that can be used to solve the aforementioned problem.
    
    AK: moved both functions out of line
    AK: Added improved loop from Keith Owens
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f2b218dd6199983b120a96bc6531c1b81f4090d8
Author: Fernando Luis VazquezCao <fernando@oss.ntt.co.jp>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: safe_apic_wait_icr_idle - i386
    
    apic_wait_icr_idle looks like this:
    
    static __inline__ void apic_wait_icr_idle(void)
    {
      while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
        cpu_relax();
    }
    
    The busy loop in this function would not be problematic if the
    corresponding status bit in the ICR were always updated, but that does
    not seem to be the case under certain crash scenarios. Kdump uses an IPI
    to stop the other CPUs in the event of a crash, but when any of the
    other CPUs are locked-up inside the NMI handler the CPU that sends the
    IPI will end up looping forever in the ICR check, effectively
    hard-locking the whole system.
    
    Quoting from Intel's "MultiProcessor Specification" (Version 1.4), B-3:
    
    "A local APIC unit indicates successful dispatch of an IPI by
    resetting the Delivery Status bit in the Interrupt Command
    Register (ICR). The operating system polls the delivery status
    bit after sending an INIT or STARTUP IPI until the command has
    been dispatched.
    
    A period of 20 microseconds should be sufficient for IPI dispatch
    to complete under normal operating conditions. If the IPI is not
    successfully dispatched, the operating system can abort the
    command. Alternatively, the operating system can retry the IPI by
    writing the lower 32-bit double word of the ICR. This â€œtime-outâ€
    mechanism can be implemented through an external interrupt, if
    interrupts are enabled on the processor, or through execution of
    an instruction or time-stamp counter spin loop."
    
    Intel's documentation suggests the implementation of a time-out
    mechanism, which, by the way, is already being open-coded in some parts
    of the kernel that tinker with ICR.
    
    Create a apic_wait_icr_idle replacement that implements the time-out
    mechanism and that can be used to solve the aforementioned problem.
    
    AK: moved both functions out of line
    AK: added improved loop from Keith Owens
    
    Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit de938c51d5fec4ae03af64b06beb15d4423ec611
Author: Bernhard Kaindl <bk@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: Enable support for fixed-range IORRs to keep RdMem & WrMem in sync
    
    If our copy of the MTRRs of the BSP has RdMem or WrMem set, and
    we are running on an AMD64/K8 system, the boot CPU must have had
    MtrrFixDramEn and MtrrFixDramModEn set (otherwise our RDMSR would
    have copied these bits cleared), so we set them on this CPU as well.
    
    This allows us to keep the AMD64/K8 RdMem and WrMem bits in sync
    across the CPUs of SMP systems in order to fullfill the duty of
    system software to "initialize and maintain MTRR consistency
    across all processors." as written in the AMD and Intel manuals.
    
    If an WRMSR instruction fails because MtrrFixDramModEn is not
    set, I expect that also the Intel-style MTRR bits are not updated.
    
    AK: minor cleanup, moved MSR defines around
    
    Signed-off-by: Bernhard Kaindl <bk@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>

commit 3ebad5905609476a4ff1151a66b21d9794009961
Author: Bernhard Kaindl <bk@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86: Save and restore the fixed-range MTRRs of the BSP when suspending
    
    Note: This patch didn'nt need an update since it's initial post.
    
    Some BIOSes may modify fixed-range MTRRs in SMM, e.g. when they
    transition the system into ACPI mode, which is entered thru an SMI,
    triggered by Linux in acpi_enable().
    
    SMIs which cause that Linux is interrupted and BIOS code is
    executed (which may change e.g. fixed-range MTRRs) in SMM may
    be raised by an embedded system controller which is often found
    in notebooks also at other occasions.
    
    If we would not update our copy of the fixed-range MTRRs before
    suspending to RAM or to disk, restore_processor_state() would
    set the fixed-range MTRRs of the BSP using old backup values
    which may be outdated and this could cause the system to fail
    later during resume.
    
    This patch ensures that our copy of the fixed-range MTRRs
    is updated when saving the boot processor state on suspend
    to disk and suspend to RAM.
    
    In combination with other patches this allows to fix s2ram
    and s2disk on the Acer Ferrari 1000 notebook and at least
    s2disk on the Acer Ferrari 5000 notebook.
    
    Signed-off-by: Bernhard Kaindl <bk@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>

commit 2b1f6278d77c1f2f669346fc2bb48012b5e9495a
Author: Bernhard Kaindl <bk@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86: Save the MTRRs of the BSP before booting an AP
    
    Applied fix by Andew Morton:
    http://lkml.org/lkml/2007/4/8/88 - Fix `make headers_check'.
    
    AMD and Intel x86 CPU manuals state that it is the responsibility of
    system software to initialize and maintain MTRR consistency across
    all processors in Multi-Processing Environments.
    
    Quote from page 188 of the AMD64 System Programming manual (Volume 2):
    
    7.6.5 MTRRs in Multi-Processing Environments
    
    "In multi-processing environments, the MTRRs located in all processors must
    characterize memory in the same way. Generally, this means that identical
    values are written to the MTRRs used by the processors." (short omission here)
    "Failure to do so may result in coherency violations or loss of atomicity.
    Processor implementations do not check the MTRR settings in other processors
    to ensure consistency. It is the responsibility of system software to
    initialize and maintain MTRR consistency across all processors."
    
    Current Linux MTRR code already implements the above in the case that the
    BIOS does not properly initialize MTRRs on the secondary processors,
    but the case where the fixed-range MTRRs of the boot processor are changed
    after Linux started to boot, before the initialsation of a secondary
    processor, is not handled yet.
    
    In this case, secondary processors are currently initialized by Linux
    with MTRRs which the boot processor had very early, when mtrr_bp_init()
    did run, but not with the MTRRs which the boot processor uses at the
    time when that secondary processors is actually booted,
    causing differing MTRR contents on the secondary processors.
    
    Such situation happens on Acer Ferrari 1000 and 5000 notebooks where the
    BIOS enables and sets AMD-specific IORR bits in the fixed-range MTRRs
    of the boot processor when it transitions the system into ACPI mode.
    The SMI handler of the BIOS does this in SMM, entered while Linux ACPI
    code runs acpi_enable().
    
    Other occasions where the SMI handler of the BIOS may change bits in
    the MTRRs could occur as well. To initialize newly booted secodary
    processors with the fixed-range MTRRs which the boot processor uses
    at that time, this patch saves the fixed-range MTRRs of the boot
    processor before new secondary processors are started. When the
    secondary processors run their Linux initialisation code, their
    fixed-range MTRRs will be updated with the saved fixed-range MTRRs.
    
    If CONFIG_MTRR is not set, we define mtrr_save_state
    as an empty statement because there is nothing to do.
    
    Possible TODOs:
    
    *) CPU-hotplugging outside of SMP suspend/resume is not yet tested
       with this patch.
    
    *) If, even in this case, an AP never runs i386/do_boot_cpu or x86_64/cpu_up,
       then the calls to mtrr_save_state() could be replaced by calls to
       mtrr_save_fixed_ranges(NULL) and  mtrr_save_state() would not be
       needed.
    
       That would need either verification of the CPU-hotplug code or
       at least a test on a >2 CPU machine.
    
    *) The MTRRs of other running processors are not yet checked at this
       time but it might be interesting to syncronize the MTTRs of all
       processors before booting. That would be an incremental patch,
       but of rather low priority since there is no machine known so
       far which would require this.
    
    AK: moved prototypes on x86-64 around to fix warnings
    
    Signed-off-by: Bernhard Kaindl <bk@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>

commit 2b3b4835c94226681c496de9446d456dcf42ed08
Author: Bernhard Kaindl <bk@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86: Adds mtrr_save_fixed_ranges() for use in two later patches.
    
    In this current implementation which is used in other patches,
    mtrr_save_fixed_ranges() accepts a dummy void pointer because
    in the current implementation of one of these patches, this
    function may be called from smp_call_function_single() which
    requires that this function takes a void pointer argument.
    
    This function calls get_fixed_ranges(), passing mtrr_state.fixed_ranges
    which is the element of the static struct which stores our current
    backup of the fixed-range MTRR values which all CPUs shall be
    using.
    
    Because  mtrr_save_fixed_ranges calls get_fixed_ranges after
    kernel initialisation time, __init needs to be removed from
    the declaration of get_fixed_ranges().
    
    If CONFIG_MTRR is not set, we define mtrr_save_fixed_ranges
    as an empty statement because there is nothing to do.
    
    AK: Moved prototypes for x86-64 around to fix warnings
    
    Signed-off-by: Bernhard Kaindl <bk@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>

commit 856f44ff4af6e57fdc39a8b2bec498c88438bd27
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] x86-64: Move mtrr prototypes from proto.h to mtrr.h
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 03df4f6ee997589a84d5f9492c6419183724c710
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: Clean up ELF note generation
    
    Three cleanups:
    
    1: ELF notes are never mapped, so there's no need to have any access
    flags in their phdr.
    
    2: When generating them from asm, tell the assembler to use a SHT_NOTE
    section type.  There doesn't seem to be a way to do this from C.
    
    3: Use ANSI rather than traditional cpp behaviour to stringify the
    macro argument.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Eric W. Biederman <ebiederm@xmission.com>

commit 21564fd2a3deb48200b595332f9ed4c9f311f2a7
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:17 2007 +0200

    [PATCH] i386: PARAVIRT: Export paravirt_ops for non GPL modules too
    
    Otherwise non GPL modules cannot even do basic operations
    like disabling interrupts anymore, which would be excessive.
    
    Longer term should split the single structure up into
    internal and external symbols and not export the internal
    ones at all.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 441d40dca024deb305a5e3d5003e8cd9d364d10f
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] x86: PARAVIRT: Jeremy Fitzhardinge <jeremy@goop.org>
    
    The other symbols used to delineate the alt-instructions sections have the
    form __foo/__foo_end.  Rename parainstructions to match.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit e0bb8643974397a8d36670e06e6a54bb84f3289f
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Convert VMI timer to use clock events
    
    Convert VMI timer to use clock events, making it properly able to use the NO_HZ
    infrastructure.  On UP systems, with no local APIC, we just continue to route
    these events through the PIT.  On systems with a local APIC, or SMP, we provide
    a single source interrupt chip which creates the local timer IRQ.  It actually
    gets delivered by the APIC hardware, but we don't want to use the same local
    APIC clocksource processing, so we create our own handler here.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    CC: Dan Hecht <dhecht@vmware.com>
    CC: Ingo Molnar <mingo@elte.hu>
    CC: Thomas Gleixner <tglx@linutronix.de>

commit eeef9c68aae2f4f21ab810d0339e0f22d30b0cd8
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Implement vmi_kmap_atomic_pte
    
    Implement vmi_kmap_atomic_pte in terms of the backend set_linear_mapping
    operation.  The conversion is rather straighforward; call kmap_atomic
    and then inform the hypervisor of the page mapping.
    
    The _flush_tlb damage is due to macros being pulled in from highmem.h.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9f53a729dbf0ba8abdc464f6eb828f485d3417f7
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Now that the VDSO can be relocated, we can support it in VMI configurations.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 18420001d6ceafbe094a6f911126c6eee34d25c4
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Clean up arch/i386/kernel/cpu/mcheck/p4.c
    
    No, just no.  You do not use goto to skip a code block.  You do not
    return an obvious variable from a singly-inlined function and give
    the function a return value.  You don't put unexplained comments
    about kmalloc in code which doesn't do dynamic allocation.  And
    you don't leave stray warnings around for no good reason.
    
    Also, when possible, it is better to use block scoped variables
    because gcc can sometime generate better code.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 959b4fdfe7e27bcf101e2381e500e4076f2bb9ce
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: PARAVIRT: Allow boot-time disable of paravirt_ops patching
    
    Add "noreplace-paravirt" to disable paravirt_ops patching.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 752783c050f1729452a89b2baea45b0124ac91c7
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: In compat mode, the return value here was uninitialized.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 57decbda6a2a7c400b2a3b3b12e52ccbdc977118
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] x86: update for i386 and x86-64 check_bugs
    
    Remove spurious comments, headers and keywords from x86-64 bugs.[ch].
    
    Use identify_boot_cpu()
    
    AK: merged with other patch
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9ce8c2ed12550f90fd6e902990652b13df647793
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: map enough initial memory to create lowmem mappings
    
    head.S creates the very initial pagetable for the kernel.  This just
    maps enough space for the kernel itself, and an allocation bitmap.
    The amount of mapped memory is rounded up to 4Mbytes, and so this
    typically ends up mapping 8Mbytes of memory.
    
    When booting, pagetable_init() needs to create mappings for all
    lowmem, and the pagetables for these mappings are allocated from the
    free pages around the kernel in low memory.  If the number of
    pagetable pages + kernel size exceeds head.S's initial mapping, it
    will end up faulting on an unmapped page.  This will only happen with
    specific combinations of kernel size and memory size.
    
    This patch makes sure that head.S also maps enough space to fit the
    kernel pagetables as well as the kernel itself.  It ends up using an
    additional two pages of unreclaimable memory.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: "H. Peter Anvin" <hpa@zytor.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>,

commit c5413fbe894924ddb8aa474a4d4da52e7a6c7e0b
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Fix UP gdt bugs
    
    Fixes two problems with the GDT when compiling for uniprocessor:
     - There's no percpu segment, so trying to load its selector into %fs fails.
       Use a null selector instead.
     - The real gdt needs to be loaded at some point.  Do it in cpu_init().
    
    Signed-off-by: Chris Wright <chrisw@sous-sol.org>
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>

commit 1956c73bb5bf81ee577ed7d3c64e3cad876ad2a5
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Define per_cpu_offset
    
    Define per_cpu_offset in asm-i386/percpu.h when SMP defined, like
    asm-generic/percpu.h does for UP.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>

commit 978c038ec944e4f2c940b0975c6acb433203a9be
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: cleanups to help using per-cpu variables from asm
    
    This patch does a few small cleanups:
     - use PER_CPU_NAME to generate the names of per-cpu variables
     - use lea to add the per_cpu offset in PER_CPU(), because it doesn't
       affect condition flags
     - add PER_CPU_VAR which allows direct access to pre-cpu variables
       with the %fs: prefix on SMP.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>

commit 7c3576d261ce046789a7db14f43303f8120910c7
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:16 2007 +0200

    [PATCH] i386: Convert PDA into the percpu section
    
    Currently x86 (similar to x84-64) has a special per-cpu structure
    called "i386_pda" which can be easily and efficiently referenced via
    the %fs register.  An ELF section is more flexible than a structure,
    allowing any piece of code to use this area.  Indeed, such a section
    already exists: the per-cpu area.
    
    So this patch:
    (1) Removes the PDA and uses per-cpu variables for each current member.
    (2) Replaces the __KERNEL_PDA segment with __KERNEL_PERCPU.
    (3) Creates a per-cpu mirror of __per_cpu_offset called this_cpu_off, which
        can be used to calculate addresses for this CPU's variables.
    (4) Simplifies startup, because %fs doesn't need to be loaded with a
        special segment at early boot; it can be deferred until the first
        percpu area is allocated (or never for UP).
    
    The result is less code and one less x86-specific concept.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>

commit 7a61d35d4b4056e7711031202da7605e052f4137
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: Page-align the GDT
    
    Xen wants a dedicated page for the GDT.  I believe VMI likes it too.
    lguest, KVM and native don't care.
    
    Simple transformation to page-aligned "struct gdt_page".
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Jeremy Fitzhardinge <jeremy@xensource.com>

commit 39b7ee06859b07ca5fd4fabb44c4600316532574
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] x86-64: deflate inflate_dynamic too
    
    inflate_dynamic() has piggy stack usage too, so heap allocate it too.
    I'm not sure it actually gets used, but it shows up large in "make
    checkstack".
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 35c7422649ee7a3d0eb4ebd32c997eeb45f81046
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] x86: deflate stack usage in lib/inflate.c
    
    inflate_fixed and huft_build together use around 2.7k of stack.  When
    using 4k stacks, I saw stack overflows from interrupts arriving while
    unpacking the root initrd:
    
    do_IRQ: stack overflow: 384
     [<c0106b64>] show_trace_log_lvl+0x1a/0x30
     [<c01075e6>] show_trace+0x12/0x14
     [<c010763f>] dump_stack+0x16/0x18
     [<c0107ca4>] do_IRQ+0x6d/0xd9
     [<c010202b>] xen_evtchn_do_upcall+0x6e/0xa2
     [<c0106781>] xen_hypervisor_callback+0x25/0x2c
     [<c010116c>] xen_restore_fl+0x27/0x29
     [<c0330f63>] _spin_unlock_irqrestore+0x4a/0x50
     [<c0117aab>] change_page_attr+0x577/0x584
     [<c0117b45>] kernel_map_pages+0x8d/0xb4
     [<c016a314>] cache_alloc_refill+0x53f/0x632
     [<c016a6c2>] __kmalloc+0xc1/0x10d
     [<c0463d34>] malloc+0x10/0x12
     [<c04641c1>] huft_build+0x2a7/0x5fa
     [<c04645a5>] inflate_fixed+0x91/0x136
     [<c04657e2>] unpack_to_rootfs+0x5f2/0x8c1
     [<c0465acf>] populate_rootfs+0x1e/0xe4
    
    (This was under Xen, but there's no reason it couldn't happen on bare
      hardware.)
    
    This patch mallocs the local variables, thereby reducing the stack
    usage to sane levels.
    
    Also, up the heap size for the kernel decompressor to deal with the
    extra allocation.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Tim Yamin <plasmaroo@gentoo.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Matt Mackall <mpm@selenic.com>
    Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
    Cc: Richard Henderson <rth@twiddle.net>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Cc: Ian Molton <spyro@f2s.com>

commit 4cdd9c8931767e1c56a51a1078d33a8c340f4405
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: drop unused ptep_get_and_clear
    
    In shadow mode hypervisors, ptep_get_and_clear achieves the desired
    purpose of keeping the shadows in sync by issuing a native_get_and_clear,
    followed by a call to pte_update, which indicates the PTE has been
    modified.
    
    Direct mode hypervisors (Xen) have no need for this anyway, and will trap
    the update using writable pagetables.
    
    This means no hypervisor makes use of ptep_get_and_clear; there is no
    reason to have it in the paravirt-ops structure.  Change confusing
    terminology about raw vs. native functions into consistent use of
    native_pte_xxx for operations which do not invoke paravirt-ops.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1a45b7aaa5051489b46afbc48509bd91f8b4a1ba
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: Clean up paravirt patchable wrappers
    
    Replace all the open-coded macros for generating calls with a pair of
    more general macros (__PVOP_CALL/VCALL), and redefine all the
    PVOP_V?CALL[0-4] in terms of them.
    
    [ Andrew, Andi: this should slot in immediately after "Document asm-i386/paravirt.h"
      (paravirt_ops-document-asm-i386-paravirth.patch) ]
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>

commit 4e0fa85602a4fa219fc3a9c053d5140bf987d3e3
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: Use enums for paravirt lazy flush modi
    
    Remove #defines, add enum for PARAVIRT_LAZY_FLUSH.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 7b2f27f4e1818fad980da7bea688dca2b9e9c3f3
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: flush lazy mmu updates on kunmap_atomic
    
    kunmap_atomic should flush any pending lazy mmu updates, mainly to be
    consistent with kmap_atomic, and to preserve its normal behaviour.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ce6234b5298902aaec831a67d5f8d9bd2ef5a488
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: add kmap_atomic_pte for mapping highpte pages
    
    Xen and VMI both have special requirements when mapping a highmem pte
    page into the kernel address space.  These can be dealt with by adding
    a new kmap_atomic_pte() function for mapping highptes, and hooking it
    into the paravirt_ops infrastructure.
    
    Xen specifically wants to map the pte page RO, so this patch exposes a
    helper function, kmap_atomic_prot, which maps the page with the
    specified page protections.
    
    This also adds a kmap_flush_unused() function to clear out the cached
    kmap mappings.  Xen needs this to clear out any potential stray RW
    mappings of pages which will become part of a pagetable.
    
    [ Zach - vmi.c will need some attention after this patch.  It wasn't
      immediately obvious to me what needs to be done. ]
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>

commit a27fe809b82c5e18932fcceded28d0d1481ce7bb
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: revert map_pt_hook.
    
    Back out the map_pt_hook to clear the way for kmap_atomic_pte.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>

commit d4c104771a1c58e3de2a888b73b0ba1b54c0ae76
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:15 2007 +0200

    [PATCH] i386: PARAVIRT: add flush_tlb_others paravirt_op
    
    This patch adds a pv_op for flush_tlb_others.  Linux running on native
    hardware uses cross-CPU IPIs to flush the TLB on any CPU which may
    have a particular mm's pagetable entries cached in its TLB.  This is
    inefficient in a paravirtualized environment, since the hypervisor
    knows which real CPUs actually contain cached mappings, which may be a
    small subset of a guest's VCPUs.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 63f70270ccd981ce40a8ff58c03a8c2e97e368be
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: add common patching machinery
    
    Implement the actual patching machinery.  paravirt_patch_default()
    contains the logic to automatically patch a callsite based on a few
    simple rules:
    
     - if the paravirt_op function is paravirt_nop, then patch nops
     - if the paravirt_op function is a jmp target, then jmp to it
     - if the paravirt_op function is callable and doesn't clobber too much
        for the callsite, call it directly
    
    paravirt_patch_default is suitable as a default implementation of
    paravirt_ops.patch, will remove most of the expensive indirect calls
    in favour of either a direct call or a pile of nops.
    
    Backends may implement their own patcher, however.  There are several
    helper functions to help with this:
    
    paravirt_patch_nop	nop out a callsite
    paravirt_patch_ignore	leave the callsite as-is
    paravirt_patch_call	patch a call if the caller and callee
    			have compatible clobbers
    paravirt_patch_jmp	patch in a jmp
    paravirt_patch_insns	patch some literal instructions over
    			the callsite, if they fit
    
    This patch also implements more direct patches for the native case, so
    that when running on native hardware many common operations are
    implemented inline.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Anthony Liguori <anthony@codemonkey.ws>
    Acked-by: Ingo Molnar <mingo@elte.hu>

commit 294688c028e80fd467cdd22da79f62c5f311eaf5
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: Document asm-i386/paravirt.h
    
    Clean things up, and broadly document:
     - the paravirt_ops functions themselves
     - the patching mechanism
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>

commit f8822f42019eceed19cc6c0f985a489e17796ed8
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: Consistently wrap paravirt ops callsites to make them patchable
    
    Wrap a set of interesting paravirt_ops calls in a wrapper which makes
    the callsites available for patching.  Unfortunately this is pretty
    ugly because there's no way to get gcc to generate a function call,
    but also wrap just the callsite itself with the necessary labels.
    
    This patch supports functions with 0-4 arguments, and either void or
    returning a value.  64-bit arguments must be split into a pair of
    32-bit arguments (lower word first).  Small structures are returned in
    registers.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Anthony Liguori <anthony@codemonkey.ws>

commit 42c24fa22e86365055fc931d833f26165e687c19
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: Fix patch site clobbers to include return register
    
    Fix a few clobbers to include the return register.  The clobbers set
    is the set of all registers modified (or may be modified) by the code
    snippet, regardless of whether it was deliberate or accidental.
    
    Also, make sure that callsites which are used in contexts which don't
    allow clobbers actually save and restore all clobberable registers.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Zachary Amsden <zach@vmware.com>

commit d582203578a1f3d408e27bb9042e8635954cd320
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: Use patch site IDs computed from offset in paravirt_ops structure
    
    Use patch type identifiers derived from the offset of the operation in
    the paravirt_ops structure.  This avoids having to maintain a separate
    enum for patch site types.
    
    Also, since the identifier is derived from the offset into
    paravirt_ops, the offset can be derived from the identifier.  This is
    used to remove replicated information in the various callsite macros,
    which has been a source of bugs in the past.
    
    This patch also drops the fused save_fl+cli operation, which doesn't
    really add much and makes things more complex - specifically because
    it breaks the 1:1 relationship between identifiers and offsets.  If
    this operation turns out to be particularly beneficial, then the right
    answer is to define a new entrypoint for it.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Zachary Amsden <zach@vmware.com>

commit 98de032b681d8a7532d44dfc66aa5c0c1c755a9d
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] i386: PARAVIRT: rename struct paravirt_patch to paravirt_patch_site for clarity
    
    Rename struct paravirt_patch to paravirt_patch_site, so that it
    clearly refers to a callsite, and not the patch which may be applied
    to that callsite.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Zachary Amsden <zach@vmware.com>

commit d6dd61c831226f9cd7750885da04d360d6455101
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:14 2007 +0200

    [PATCH] x86: PARAVIRT: add hooks to intercept mm creation and destruction
    
    Add hooks to allow a paravirt implementation to track the lifetime of
    an mm.  Paravirtualization requires three hooks, but only two are
    needed in common code.  They are:
    
    arch_dup_mmap, which is called when a new mmap is created at fork
    
    arch_exit_mmap, which is called when the last process reference to an
      mm is dropped, which typically happens on exit and exec.
    
    The third hook is activate_mm, which is called from the arch-specific
    activate_mm() macro/function, and so doesn't need stub versions for
    other architectures.  It's called when an mm is first used.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: linux-arch@vger.kernel.org
    Cc: James Bottomley <James.Bottomley@SteelEye.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>

commit 5311ab62cdc7788784971ed816ce85e926f3e994
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: Allow paravirt backend to choose kernel PMD sharing
    
    Normally when running in PAE mode, the 4th PMD maps the kernel address space,
    which can be shared among all processes (since they all need the same kernel
    mappings).
    
    Xen, however, does not allow guests to have the kernel pmd shared between page
    tables, so parameterize pgtable.c to allow both modes of operation.
    
    There are several side-effects of this.  One is that vmalloc will update the
    kernel address space mappings, and those updates need to be propagated into
    all processes if the kernel mappings are not intrinsically shared.  In the
    non-PAE case, this is done by maintaining a pgd_list of all processes; this
    list is used when all process pagetables must be updated.  pgd_list is
    threaded via otherwise unused entries in the page structure for the pgd, which
    means that the pgd must be page-sized for this to work.
    
    Normally the PAE pgd is only 4x64 byte entries large, but Xen requires the PAE
    pgd to page aligned anyway, so this patch forces the pgd to be page
    aligned+sized when the kernel pmd is unshared, to accomodate both these
    requirements.
    
    Also, since there may be several distinct kernel pmds (if the user/kernel
    split is below 3G), there's no point in allocating them from a slab cache;
    they're just allocated with get_free_page and initialized appropriately.  (Of
    course the could be cached if there is just a single kernel pmd - which is the
    default with a 3G user/kernel split - but it doesn't seem worthwhile to add
    yet another case into this code).
    
    [ Many thanks to wli for review comments. ]
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: William Lee Irwin III <wli@holomorphy.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Christoph Lameter <clameter@sgi.com>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 90caccb9758e88db68a69553689baee38254287b
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: Allocate a fixmap slot
    
    Allocate a fixmap slot for use by a paravirt_ops implementation.  This
    is intended for early-boot bootstrap mappings.  Once the zones and
    allocator have been set up, it would be better to use get_vm_area() to
    allocate some virtual space.
    
    Xen uses this to map the hypervisor's shared info page, which doesn't
    have a pseudo-physical page number, and therefore can't be mapped
    ordinarily.  It is needed early because it contains the vcpu state,
    including the interrupt mask.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>

commit b239fb2501117bf3aeb4dd6926edd855be92333d
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: Hooks to set up initial pagetable
    
    This patch introduces paravirt_ops hooks to control how the kernel's
    initial pagetable is set up.
    
    In the case of a native boot, the very early bootstrap code creates a
    simple non-PAE pagetable to map the kernel and physical memory.  When
    the VM subsystem is initialized, it creates a proper pagetable which
    respects the PAE mode, large pages, etc.
    
    When booting under a hypervisor, there are many possibilities for what
    paging environment the hypervisor establishes for the guest kernel, so
    the constructon of the kernel's pagetable depends on the hypervisor.
    
    In the case of Xen, the hypervisor boots the kernel with a fully
    constructed pagetable, which is already using PAE if necessary.  Also,
    Xen requires particular care when constructing pagetables to make sure
    all pagetables are always mapped read-only.
    
    In order to make this easier, kernel's initial pagetable construction
    has been changed to only allocate and initialize a pagetable page if
    there's no page already present in the pagetable.  This allows the Xen
    paravirt backend to make a copy of the hypervisor-provided pagetable,
    allowing the kernel to establish any more mappings it needs while
    keeping the existing ones.
    
    A slightly subtle point which is worth highlighting here is that Xen
    requires all kernel mappings to share the same pte_t pages between all
    pagetables, so that updating a kernel page's mapping in one pagetable
    is reflected in all other pagetables.  This makes it possible to
    allocate a page and attach it to a pagetable without having to
    explicitly enumerate that page's mapping in all pagetables.
    
    And:
    
    +From: "Eric W. Biederman" <ebiederm@xmission.com>
    
    If we don't set the leaf page table entries it is quite possible that
    will inherit and incorrect page table entry from the initial boot
    page table setup in head.S.  So we need to redo the effort here,
    so we pick up PSE, PGE and the like.
    
    Hypervisors like Xen require that their page tables be read-only,
    which is slightly incompatible with our low identity mappings, however
    I discussed this with Jeremy he has modified the Xen early set_pte
    function to avoid problems in this area.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: William Irwin <bill.irwin@oracle.com>
    Cc: Ingo Molnar <mingo@elte.hu>

commit 3dc494e86d1c93afd4c66385f270899dbfae483d
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: Add pagetable accessors to pack and unpack pagetable entries
    
    Add a set of accessors to pack, unpack and modify page table entries
    (at all levels).  This allows a paravirt implementation to control the
    contents of pgd/pmd/pte entries.  For example, Xen uses this to
    convert the (pseudo-)physical address into a machine address when
    populating a pagetable entry, and converting back to pphys address
    when an entry is read.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>

commit 45876233605c268e929a7875081e129debe34bdc
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: use paravirt_nop to consistently mark no-op operations
    
    Add a _paravirt_nop function for use as a stub for no-op operations,
    and paravirt_nop #defined void * version to make using it easier
    (since all its uses are as a void *).
    
    This is useful to allow the patcher to automatically identify noop
    operations so it can simply nop out the callsite.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    [mingo] but only as a cleanup of the current open-coded (void *) casts.
    My problem with this is that it loses the types. Not that there is much
    to check for, but still, this adds some assumptions about how function
    calls look like

commit 7f63c41c6c57371a0931da3940c6620c2301442c
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: PARAVIRT: Remove CONFIG_DEBUG_PARAVIRT
    
    Remove CONFIG_DEBUG_PARAVIRT.  When inlining code, this option
    attempts to trash registers in the patch-site's "clobber" field, on
    the grounds that this should find bugs with incorrect clobbers.
    Unfortunately, the clobber field really means "registers modified by
    this patch site", which includes return values.
    
    Because of this, this option has outlived its usefulness, so remove
    it.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>

commit 4cdf6bc2476157f397f3b71a9bd4e23c7a7aaf80
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] x86-64: update MAINTAINERS
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Chris Wright <chrisw@sous-sol.org>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Rusty Russell <rusty@rustcorp.com.au>

commit a75c54f933bd8db9f4a609bd128663c179b3e6a1
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: i386 separate hardware-defined TSS from Linux additions
    
    On Thu, 2007-03-29 at 13:16 +0200, Andi Kleen wrote:
    > Please clean it up properly with two structs.
    
    Not sure about this, now I've done it.  Running it here.
    
    If you like it, I can do x86-64 as well.
    
    ==
    lguest defines its own TSS struct because the "struct tss_struct"
    contains linux-specific additions.  Andi asked me to split the struct
    in processor.h.
    
    Unfortunately it makes usage a little awkward.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 82d1bb725e128c97b362a4b33fcbfff08fdaaa5a
Author: James Puthukattukaran <James.Puthukattukaran@sun.com>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] x86-64: x86-64 system crashes when no memory populating Node 0
    
    I have a 4 socket AMD Operton system. The 2.6.18 kernel I have crashes
    when there is no memory in node0.
    
    AK: changed call to _nopanic
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1c3d99c11c47c8a1a9ed6a46555dbf6520683c52
Author: Glauber de Oliveira Costa <gcosta@redhat.com>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] x86-64: Fix x86_64 compilation with DEBUG_SIG on
    
    Setting the DEBUG_SIG flag breaks compilation due to a wrong
    struct access. Aditionally, it raises two warnings. This is one
    patch to fix them all.
    
    Signed-off-by: Glauber de Oliveira Costa <gcosta@redhat.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b7fb4af06c18496950a45b365f7a09c47ea64c17
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: Allow boot-time disable of SMP altinstructions
    
    Add "noreplace-smp" to disable SMP instruction replacement.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d0175ab64412aabc93da8682aaa99124d6815056
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:13 2007 +0200

    [PATCH] i386: Remove smp_alt_instructions
    
    The .smp_altinstructions section and its corresponding symbols are
    completely unused, so remove them.
    
    Also, remove stray #ifdef __KENREL__ in asm-i386/alternative.h
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>

commit 4bc5aa91fb1e544ad37805520030a0d9fc6e11d3
Author: H. Peter Anvin <hpa@zytor.com>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86: Clean up x86 control register and MSR macros (corrected)
    
    This patch is based on Rusty's recent cleanup of the EFLAGS-related
    macros; it extends the same kind of cleanup to control registers and
    MSRs.
    
    It also unifies these between i386 and x86-64; at least with regards
    to MSRs, the two had definitely gotten out of sync.
    
    Signed-off-by: H. Peter Anvin <hpa@zytor.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b6e3590f8145c77b8fcef3247e2412335221412f
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86: Allow percpu variables to be page-aligned
    
    Let's allow page-alignment in general for per-cpu data (wanted by Xen, and
    Ingo suggested KVM as well).
    
    Because larger alignments can use more room, we increase the max per-cpu
    memory to 64k rather than 32k: it's getting a little tight.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Ingo Molnar <mingo@elte.hu>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit de90c5ce832b1218042316260ff9268b00fdcba3
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Enable bank 0 on non K7 Athlon
    
    As a bug workaround bank 0 on K7s is normally disabled, but no need
    to do that on other AMD CPUs.
    
    Cc: davej@redhat.com
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d479d2cc0802d5c8546a6a7492646e08228effd5
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Update smp_call_function* comments
    
    Update documentation for i386 smp_call_function* functions.
    
    As reported by Randy Dunlap <rdunlap@xenotime.net>
    
    [ I've posted this before but it seems to have been lost along the way. ]
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Randy Dunlap <rdunlap@xenotime.net>

commit 7946331856f99bdb00b0a0a53e97d9b621546622
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Use menuconfig objects - APM
    
    (I hope Andi is the right one to Cc, otherwise please add, thanks!)
    
    Use menuconfigs instead of menus, so the whole menu can be disabled at
    once instead of going through all options.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f039b754714a422959027cb18bb33760eb8153f0
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86: Don't use MWAIT on AMD Family 10
    
    It doesn't put the CPU into deeper sleep states, so it's better to use the standard
    idle loop to save power. But allow to reenable it anyways for benchmarking.
    
    I also removed the obsolete idle=halt on i386
    
    Cc: andreas.herrmann@amd.com
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c169859d6dfc7471ef9f2dbd720936e17906a084
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86-64: Clean up asm-x86_64/bugs.h
    
    Most of asm-x86_64/bugs.h is code which should be in a C file, so put it there.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>

commit 1dbf527c51c6c20c19869c8125cb5b87c3d09506
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Make COMPAT_VDSO runtime selectable.
    
    Now that relocation of the VDSO for COMPAT_VDSO users is done at
    runtime rather than compile time, it is possible to enable/disable
    compat mode at runtime.
    
    This patch allows you to enable COMPAT_VDSO mode with "vdso=2" on the
    kernel command line, or via sysctl.  (Switching on a running system
    shouldn't be done lightly; any process which was relying on the compat
    VDSO will be upset if it goes away.)
    
    The COMPAT_VDSO config option still exists, but if enabled it just
    makes vdso_enabled default to VDSO_COMPAT.
    
    +From: Hugh Dickins <hugh@veritas.com>
    
    Fix oops from i386-make-compat_vdso-runtime-selectable.patch.
    
    Even mingetty at system startup finds it easy to trigger an oops
    while reading /proc/PID/maps: though it has a good hold on the mm
    itself, that cannot stop exit_mm() from resetting tsk->mm to NULL.
    
    (It is usually show_map()'s call to get_gate_vma() which oopses,
    and I expect we could change that to check priv->tail_vma instead;
    but no matter, even m_start()'s call just after get_task_mm() is racy.)
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: "Jan Beulich" <JBeulich@novell.com>
    Cc: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Roland McGrath <roland@redhat.com>

commit d4f7a2c18e59e0304a1c733589ce14fc02fec1bd
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Relocate VDSO ELF headers to match mapped location with COMPAT_VDSO
    
    Some versions of libc can't deal with a VDSO which doesn't have its
    ELF headers matching its mapped address.  COMPAT_VDSO maps the VDSO at
    a specific system-wide fixed address.  Previously this was all done at
    build time, on the grounds that the fixed VDSO address is always at
    the top of the address space.  However, a hypervisor may reserve some
    of that address space, pushing the fixmap address down.
    
    This patch does the adjustment dynamically at runtime, depending on
    the runtime location of the VDSO fixmap.
    
    [ Patch has been through several hands: Jan Beulich wrote the orignal
      version; Zach reworked it, and Jeremy converted it to relocate phdrs
      as well as sections. ]
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: "Jan Beulich" <JBeulich@novell.com>
    Cc: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Roland McGrath <roland@redhat.com>

commit a6c4e076ee4c1ea670e4faa55814e63dd08e3f29
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: clean up identify_cpu
    
    identify_cpu() is used to identify both the boot CPU and secondary
    CPUs, but it performs some actions which only apply to the boot CPU.
    Those functions are therefore really __init functions, but because
    they're called by identify_cpu(), they must be marked __cpuinit.
    
    This patch splits identify_cpu() into identify_boot_cpu() and
    identify_secondary_cpu(), and calls the appropriate init functions
    from each.  Also, identify_boot_cpu() and all the functions it
    dominates are marked __init.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1353ebb4b48151e3810d9a60449edd43a90ea3c3
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] i386: Clean up asm-i386/bugs.h
    
    Most of asm-i386/bugs.h is code which should be in a C file, so put it there.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>

commit 0d08e0d3a97cce22ebf80b54785e00d9b94e1add
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86-64: Fix vmalloc_32 to really allocate <4GB on 64bit platforms
    
    Ugly ifdef, but should handle all 64bit platforms that have suitable
    zones. On some like Altix it's probably impossible without IOMMU
    use to get memory <4GB this way,  but they have to live with that.
    Signed-off-by: Andi Kleen <ak@suse.de>

commit bbf30a1650be396b5467f769f4fbee715f16ec36
Author: Avi Kivity <avi@qumranet.com>
Date:   Wed May 2 19:27:12 2007 +0200

    [PATCH] x86-64: fix arithmetic in comment
    
    The xmm space on x86_64 is 256 bytes.
    
    Signed-off-by: Avi Kivity <avi@qumranet.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 5d02d7ae73ac9446f20bbf604b04a74637178b35
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: Use X86_EFLAGS_IF in x86-64/irqflags.h.
    
    As per i386 patch: move X86_EFLAGS_IF et al out to a new header:
    processor-flags.h, so we can include it from irqflags.h and use it in
    raw_irqs_disabled_flags().
    
    As a side-effect, we could now use these flags in .S files.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b92e9fac400d4ae5bc7a75c568e9844ec53ea329
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86: fix amd64-agp aperture validation
    
    Under CONFIG_DISCONTIGMEM, assuming that a !pfn_valid() implies all
    subsequent pfn-s are also invalid is wrong. Thus replace this by
    explicitly checking against the E820 map.
    
    AK: make e820 on x86-64 not initdata
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Mark Langsdorf <mark.langsdorf@amd.com>

commit b00742d399513a4100c24cc2accefdc1bb1e0b15
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: Account for module percpu space separately from kernel percpu
    
    Rather than using a single constant PERCPU_ENOUGH_ROOM, compute it as
    the sum of kernel_percpu + PERCPU_MODULE_RESERVE.  This is now common
    to all architectures; if an architecture wants to set
    PERCPU_ENOUGH_ROOM to something special, then it may do so (ia64 is
    the only one which does).
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>

commit bbba11c35baaad3f70f32e185a2c1d40d7901fe9
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] i386: Remove unneeded externs in nmi.c
    
    All were already in some header
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 43c3ab308d0e8e6ad9a5fb24020eb59cd423a3db
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: Change my email address
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 07f3331c6bfd27a06dfb0ca9fa4f06dec6606876
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] i386: Add machine_ops interface to abstract halting and rebooting
    
    machine_ops is an interface for the machine_* functions defined in
    <linux/reboot.h>.  This is intended to allow hypervisors to intercept
    the reboot process, but it could be used to implement other x86
    subarchtecture reboots.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 01a2f435564b4baab61328b4018d36464468f57b
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] i386: Add smp_ops interface
    
    Add a smp_ops interface.  This abstracts the API defined by
    <linux/smp.h> for use within arch/i386.  The primary intent is that it
    be used by a paravirtualizing hypervisor to implement SMP, but it
    could also be used by non-APIC-using sub-architectures.
    
    This is related to CONFIG_PARAVIRT, but is implemented unconditionally
    since it is simpler that way and not a highly performance-sensitive
    interface.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: James Bottomley <James.Bottomley@HansenPartnership.com>

commit 4fbb5968810b237e81977f131986b9efd5245368
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] i386: cleanup GDT Access
    
    Now we have an explicit per-cpu GDT variable, we don't need to keep the
    descriptors around to use them to find the GDT: expose cpu_gdt directly.
    
    We could go further and make load_gdt() pack the descriptor for us, or even
    assume it means "load the current cpu's GDT" which is what it always does.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 141f9cfe0a948c8fe26e5669364ee62c03ea42e8
Author: Bernhard Walle <bwalle@suse.de>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: Fix "Section mismatch" compile warning
    
    Fix "Section mismatch" warnings in arch/x86_64/kernel/time.c
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit dd4ecfc2b10d962d70ff59f8994a29aa048700ec
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: adjust EDID retrieval
    
    commit 5e518d7672dea4cd7c60871e40d0490c52f01d13 did the same change to
    i386's variant.
    
    With this change, i386's and x86-64's versions are identical, raising
    the question whether the x86-64 one should go (just like there's only
    one instance of edd.S).
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ae32b1297a77c23fd0badd642bb685062f7a37f8
Author: Konrad Rzeszutek <konrad@darnok.org>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: Inhibit machine from asserting an NMI when doing Alt-SysRq-M operation.
    
    This patch touches the NMI watchdog every MAX_ORDER_NR_PAGES
    to inhibit the machine from triggering an NMI while the CPUs
    are locked. This situation is happening on boxes with more
    than 64CPUs and 128GB of RAM when Alt-SysRq-m is performed.
    
    It has been succesfully tested for regression on uni, 2, 4, 8
    32, and 64 CPU boxes with various memory configuration.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c8118c6c07f2edfd697aaa0b93e08c3b65a5a675
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: vsyscall_gtod_data diet and vgettimeofday() fix
    
    Current vsyscall_gtod_data is large (3 or 4 cache lines dirtied at timer
    interrupt). We can shrink it to exactly 64 bytes (1 cache line on AMD64)
    
    Instead of copying a whole struct clocksource, we copy only needed fields.
    
    I deleted an unused field : offset_base
    
    This patch fixes one oddity in vgettimeofday(): It can returns a timeval with
    tv_usec = 1000000. Maybe not a bug, but why not doing the right thing ?
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 272a3713bb9e302e0455c894c41180a482d2c8a3
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86-64: fix vtime() vsyscall
    
    There is a tiny probability that the return value from vtime(time_t *t) is
    Signed-off-by: Andi Kleen <ak@suse.de>
    
    different than the value stored in *t
    
    Using a temporary variable solves the problem and gives a faster code.
    
       17:   48 85 ff                test   %rdi,%rdi
       1a:   48 8b 05 00 00 00 00    mov    0(%rip),%rax        #
    __vsyscall_gtod_data.wall_time_tv.tv_sec
       21:   74 03                   je     26
       23:   48 89 07                mov    %rax,(%rdi)
       26:   c9                      leaveq
       27:   c3                      retq
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>

commit bd8559c38ee5be40ce2c57a80fd3c3e978cca267
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:11 2007 +0200

    [PATCH] x86: remove UNEXPECTED_IO_APIC()
    
    Many years ago, UNEXPECTED_IO_APIC() contained printk()'s (but nothing more).
    
    Now that it's completely empty for years, we can as well remove it.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit ca906e42312781c38b7a9625109fc65b937ca56c
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86: sys_ioperm() prototype cleanup
    
    - there's no reason for duplicating the prototype from
      include/linux/syscalls.h in include/asm-x86_64/unistd.h
    - every file should #include the headers containing the prototypes for
      it's global functions
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2bff73830c3df5f575d3bc21bf19df1a10bf7091
Author: Christoph Lameter <clameter@sgi.com>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86-64: use lru instead of page->index and page->private for pgd lists management.
    
    x86_64 currently simulates a list using the index and private fields of the
    page struct.  Seems that the code was inherited from i386.  But x86_64 does
    not use the slab to allocate pgds and pmds etc.  So the lru field is not
    used by the slab and therefore available.
    
    This patch uses standard list operations on page->lru to realize pgd
    tracking.
    
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 05f36927eddd83e2840a981ef4d9af754dcb86e9
Author: Parag Warudkar <parag.warudkar@gmail.com>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: remove the APM_RTC_IS_GMT config option.
    
    Signed-off-by: Parag Warudkar <parag.warudkar@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b8716890f35dd567a3f8e4dd69c428a8b3f47814
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86-64: Remove unused stext symbol
    
    suggested by Jan Beulich
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b4531e863dbd06b5d336afefdb37483b690dea59
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: Use X86_EFLAGS_IF in irqflags.h.
    
    Move X86_EFLAGS_IF et al out to a new header: processor-flags.h, so we
    can include it from irqflags.h and use it in raw_irqs_disabled_flags().
    
    As a side-effect, we could now use these flags in .S files.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 78eea47ac3e256559d97f0c2434928be39cba524
Author: Parag Warudkar <parag.warudkar@gmail.com>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: get rid of unused variables
    
    Signed-off-by: Parag Warudkar <parag.warudkar@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 6fb14755a676282a4e6caa05a08c92db8e45cfff
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86: tighten kernel image page access rights
    
    On x86-64, kernel memory freed after init can be entirely unmapped instead
    of just getting 'poisoned' by overwriting with a debug pattern.
    
    On i386 and x86-64 (under CONFIG_DEBUG_RODATA), kernel text and bug table
    can also be write-protected.
    
    Compared to the first version, this one prevents re-creating deleted
    mappings in the kernel image range on x86-64, if those got removed
    previously. This, together with the original changes, prevents temporarily
    having inconsistent mappings when cacheability attributes are being
    changed on such pages (e.g. from AGP code). While on i386 such duplicate
    mappings don't exist, the same change is done there, too, both for
    consistency and because checking pte_present() before using various other
    pte_XXX functions is a requirement anyway. At once, i386 code gets
    adjusted to use pte_huge() instead of open coding this.
    
    AK: split out cpa() changes
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d01ad8dd56527be72947b4b9997bb2c05783c3ed
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86: Improve handling of kernel mappings in change_page_attr
    
    Fix various broken corner cases in i386 and x86-64 change_page_attr.
    
    AK: split off from tighten kernel image access rights
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 90a0a06aa81692028864c21f981905fda46b1208
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: rationalize paravirt wrappers
    
    paravirt.c used to implement native versions of all low-level
    functions.  Far cleaner is to have the native versions exposed in the
    headers and as inline native_XXX, and if !CONFIG_PARAVIRT, then simply
    #define XXX native_XXX.
    
    There are several nice side effects:
    
    1) write_dt_entry() now takes the correct "struct Xgt_desc_struct *"
       not "void *".
    
    2) load_TLS is reintroduced to the for loop, not manually unrolled
       with a #error in case the bounds ever change.
    
    3) Macros become inlines, with type checking.
    
    4) Access to the native versions is trivial for KVM, lguest, Xen and
       others who might want it.
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@muc.de>
    Cc: Avi Kivity <avi@qumranet.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 52de74dd3994e165ef1b35c33d54655a6400e30c
Author: Sebastien Dugue <sebastien.dugue@bull.net>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: Rename boot_gdt_table to boot_gdt
    
    Rename boot_gdt_table to boot_gdt to avoid the duplicate T(able).
    
    Signed-off-by: Sebastien Dugue <sebastien.dugue@bull.net>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit d2cbcc49e2bfd6eaa44d7e4e5e5f171aaa5ec80d
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: clean up cpu_init()
    
    We now have cpu_init() and secondary_cpu_init() doing nothing but calling
    _cpu_init() with the same arguments.  Rename _cpu_init() to cpu_init() and use
    it as a replcement for secondary_cpu_init().
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit bf50467204b435421d8de33ad080fa46c6f3d50b
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: Use per-cpu GDT immediately upon boot
    
    Now we are no longer dynamically allocating the GDT, we don't need the
    "cpu_gdt_table" at all: we can switch straight from "boot_gdt_table" to the
    per-cpu GDT.  This means initializing the cpu_gdt array in C.
    
    The boot CPU uses the per-cpu var directly, then in smp_prepare_cpus() it
    switches to the per-cpu copy just allocated.  For secondary CPUs, the
    early_gdt_descr is set to point directly to their per-cpu copy.
    
    For UP the code is very simple: it keeps using the "per-cpu" GDT as per SMP,
    but we never have to move.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit ae1ee11be77f51cedb6c569887dddc70c163ab6d
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] i386: Use per-cpu variables for GDT, PDA
    
    Allocating PDA and GDT at boot is a pain.  Using simple per-cpu variables adds
    happiness (although we need the GDT page-aligned for Xen, which we do in a
    followup patch).
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 8f9aeca7a081d81c4c9862be1e04f15b5ab5461f
Author: Bernhard Walle <bwalle@suse.de>
Date:   Wed May 2 19:27:10 2007 +0200

    [PATCH] x86: add command line length to boot protocol
    
    Because the command line is increased to 2048 characters after 2.6.21, it's
    not possible for boot loaders and userspace tools to determine the length
    of the command line the kernel can understand.  The benefit of knowing the
    length is that users can be warned if the command line size is too long
    which prevents surprise if things don't work after bootup.
    
    This patch updates the boot protocol to contain a field called
    "cmdline_size" that contain the length of the command line (excluding the
    terminating zero).
    
    The patch also adds missing fields (of protocol version 2.05) to the x86_64
    setup code.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Alon Bar-Lev <alon.barlev@gmail.com>
    Acked-by: H. Peter Anvin <hpa@zytor.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 79e030114a8d97a1dcd593ab84fb986f8c91c536
Author: Ian Campbell <ian.campbell@xensource.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] i386: Allow i386 crash kernels to handle x86_64 dumps
    
    The specific case I am encountering is kdump under Xen with a 64 bit
    hypervisor and 32 bit kernel/userspace.  The dump created is 64 bit due to
    the hypervisor but the dump kernel is 32 bit for maximum compatibility.
    
    It's possibly less likely to be useful in a purely native scenario but I
    see no reason to disallow it.
    
    [akpm@linux-foundation.org: build fix]
    Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Vivek Goyal <vgoyal@in.ibm.com>
    Cc: Horms <horms@verge.net.au>
    Cc: Magnus Damm <magnus.damm@gmail.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit eab0c72aecd7982b2c848f7d493ba379efcef15e
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: Introduce load_TLS to the "for" loop.
    
    GCC (4.1 at least) unrolls it anyway, but I can't believe this code
    was ever justifiable.  (I've also submitted a patch which cleans up
    i386, which is even uglier).
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 692174b97d5b871f4b0f648b1fb17aa37b955876
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] i386: Initialize esp0 properly all the time
    
    Whenever we schedule, __switch_to calls load_esp0 which does:
    
    	tss->esp0 = thread->esp0;
    
    This is never initialized for the initial thread (ie "swapper"), so when we're
    scheduling that, we end up setting esp0 to 0.  This is fine: the swapper never
    leaves ring 0, so this field is never used.
    
    lguest, however, gets upset that we're trying to used an unmapped page as our
    kernel stack.  Rather than work around it there, let's initialize it.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 1b523fb54977c9bb81b16c4badce581a2b455994
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] i386: VDSO_PRELINK warning fix
    
    The lguest patches somehow managed to trigger this:
    
    In file included from arch/i386/lguest/lguest.c:38:
    include/asm/asm-offsets.h:67:1: warning: "VDSO_PRELINK" redefined
    In file included from include/linux/elf.h:7,
                     from include/linux/module.h:15,
                     from include/linux/device.h:21,
                     from include/linux/interrupt.h:15,
                     from arch/i386/lguest/lguest.c:27:
    include/asm/elf.h:140:1: warning: this is the location of the previous definition
    
    I assume that using the same identifier twice was a bad idea..
    
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 20280195f2a3d80c42a190959ca22108c93cd7e0
Author: David Rientjes <rientjes@google.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: fake numa for cpusets document
    
    Create a document to explain how to use numa=fake in conjunction with cpusets
    for coarse memory resource management.
    
    An attempt to get more awareness and testing for this feature.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit d824395c5994adbf7efe377cc67f732133270554
Author: Joerg Roedel <joerg.roedel@amd.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86: remove constant_tsc reporting from /proc/cpuinfo' power flags
    
    remove the reporting of the constant_tsc flag from the "power management"
    field in /proc/cpuinfo.  The NULL value there was replaced by "" because
    the former would result in a printout of [8] if the flag is set.
    
    Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 382591d500bbcd20a44416c5e0e292708468587c
Author: David Rientjes <rientjes@google.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: fixed size remaining fake nodes
    
    Extends the numa=fake x86_64 command-line option to split the remaining system
    memory into nodes of fixed size.  Any leftover memory is allocated to a final
    node unless the command-line ends with a comma.
    
    For example:
      numa=fake=2*512,*128	gives two 512M nodes and the remaining system
    			memory is split into nodes of 128M each.
    
    This is beneficial for systems where the exact size of RAM is unknown or not
    necessarily relevant, but the size of the remaining nodes to be allocated is
    known based on their capacity for resource management.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 14694d736bb66d0ec250d05c81c6e98a19c229c6
Author: David Rientjes <rientjes@google.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: split remaining fake nodes equally
    
    Extends the numa=fake x86_64 command-line option to split the remaining
    system memory into equal-sized nodes.
    
    For example:
    numa=fake=2*512,4*	gives two 512M nodes and the remaining system
    			memory is split into four approximately equal
    			chunks.
    
    This is beneficial for systems where the exact size of RAM is unknown or not
    necessarily relevant, but the granularity with which nodes shall be allocated
    is known.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 8b8ca80e192b10eecc01fc44a2902510af86f73b
Author: David Rientjes <rientjes@google.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: configurable fake numa node sizes
    
    Extends the numa=fake x86_64 command-line option to allow for configurable
    node sizes.  These nodes can be used in conjunction with cpusets for coarse
    memory resource management.
    
    The old command-line option is still supported:
      numa=fake=32	gives 32 fake NUMA nodes, ignoring the NUMA setup of the
    		actual machine.
    
    But now you may configure your system for the node sizes of your choice:
      numa=fake=2*512,1024,2*256
    		gives two 512M nodes, one 1024M node, two 256M nodes, and
    		the rest of system memory to a sixth node.
    
    The existing hash function is maintained to support the various node sizes
    that are possible with this implementation.
    
    Each node of the same size receives roughly the same amount of available
    pages, regardless of any reserved memory with its address range.  The total
    available pages on the system is calculated and divided by the number of equal
    nodes to allocate.  These nodes are then dynamically allocated and their
    borders extended until such time as their number of available pages reaches
    the required size.
    
    Configurable node sizes are recommended when used in conjunction with cpusets
    for memory control because it eliminates the overhead associated with scanning
    the zonelists of many smaller full nodes on page_alloc().
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Paul Jackson <pj@sgi.com>
    Cc: Christoph Lameter <clameter@engr.sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 8280c0c58e9762a9fe29d550a9db81410de77691
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] i386: fix GDT's number of quadwords in comment
    
    Fix comments to represent the true number of quadwords in GDT.
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 8eb68faed9e077c45c2bab5fce7c4e371fe9c28f
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] i386: vmi_pmd_clear() static
    
    This patch makes the needlessly global vmi_pmd_clear() static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 786142fab86cfddd3e7797e9ccf8a8a3bcaf0456
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:09 2007 +0200

    [PATCH] x86-64: make simnow_init() static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f0e13ae76a607eab9c387544ebca550f2196a876
Author: Yinghai Lu <yinghai.lu@amd.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: remove extra smp_processor_id calling
    
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9f7290ed23b1cedf7198ef7b67f2ed256bc8553e
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: fix ia32_binfmt.c build error
    
    Reorder code to avoid multiple inclusion of elf.h.
    
    #undef several symbols to avoid build errors over redefinitions.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 5a90cf205c922707ffed2d8f87cefd942e96b0ba
Author: john stultz <johnstul@us.ibm.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86: Log reason why TSC was marked unstable
    
    Change mark_tsc_unstable() so it takes a string argument, which holds the
    reason the TSC was marked unstable.
    
    This is then displayed the first time mark_tsc_unstable is called.
    
    This should help us better debug why the TSC was marked unstable on certain
    systems and allow us to make sure we're not being overly paranoid when
    throwing out this troublesome clocksource.
    
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2714221985ce6388ec2fa78d7d52e2a5bef78eec
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] i386: workaround for a -Wmissing-prototypes warning
    
    Work around a warning with -Wmissing-prototypes in
    arch/i386/kernel/asm-offsets.c
    
    The warning isn't gcc's fault - asm-offsets.c is simply a special file.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@muc.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit e48b30c189559e20e1f616faccae487972486320
Author: Ken Chen <kenchen@google.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] i386: type cast clean up for find_next_zero_bit
    
    clean up unneeded type cast by properly declare data type.
    
    Signed-off-by: Ken Chen <kenchen@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 30a1528d3bf444eac7f2886ba284da22114b2f7c
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] i386: make struct vmi_ops static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 1833d6bc72893265f22addd79cf52e6987496e0f
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] i386: modpost apic related warning fixes
    
    o Modpost generates warnings for i386 if compiled with CONFIG_RELOCATABLE=y
    
    WARNING: vmlinux - Section mismatch: reference to .init.text:find_unisys_acpi_oem_table from .text between 'acpi_madt_oem_check' (at offset 0xc0101eda) and 'enable_apic_mode'
    WARNING: vmlinux - Section mismatch: reference to .init.text:acpi_get_table_header_early from .text between 'acpi_madt_oem_check' (at offset 0xc0101ef0) and 'enable_apic_mode'
    WARNING: vmlinux - Section mismatch: reference to .init.text:parse_unisys_oem from .text between 'acpi_madt_oem_check' (at offset 0xc0101f2e) and 'enable_apic_mode'
    WARNING: vmlinux - Section mismatch: reference to .init.text:setup_unisys from .text between 'acpi_madt_oem_check' (at offset 0xc0101f37) and 'enable_apic_mode'WARNING: vmlinux - Section mismatch: reference to .init.text:parse_unisys_oem from .text between 'mps_oem_check' (at offset 0xc0101ec7) and 'acpi_madt_oem_check'
    WARNING: vmlinux - Section mismatch: reference to .init.text:es7000_sw_apic from .text between 'enable_apic_mode' (at offset 0xc0101f48) and 'check_apicid_present'
    
    o Some functions which are inline (acpi_madt_oem_check) are not inlined by
      compiler as these functions are accessed using function pointer. These
      functions are put in .text section and they in-turn access __init type
      functions hence modpost generates warnings.
    
    o Do not iniline acpi_madt_oem_check, instead make it __init.
    
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Len Brown <lenb@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit e073ae1b34d5600ffc550407625dcb2d4cf46c6e
Author: Ravikiran G Thirumalai <kiran@scalex86.org>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Set HASHDIST_DEFAULT to 1 for x86_64 NUMA
    
    Enable system hashtable memory to be distributed among nodes on x86_64 NUMA
    
    Forcing the kernel to use node interleaved vmalloc instead of bootmem for
    the system hashtable memory (alloc_large_system_hash) reduces the memory
    imbalance on node 0 by around 40MB on a 8 node x86_64 NUMA box:
    
    Before the following patch, on bootup of a 8 node box:
    
    Node 0 MemTotal:      3407488 kB
    Node 0 MemFree:       3206296 kB
    Node 0 MemUsed:        201192 kB
    Node 0 Active:           7012 kB
    Node 0 Inactive:          512 kB
    Node 0 Dirty:               0 kB
    Node 0 Writeback:           0 kB
    Node 0 FilePages:        1912 kB
    Node 0 Mapped:            420 kB
    Node 0 AnonPages:        5612 kB
    Node 0 PageTables:        468 kB
    Node 0 NFS_Unstable:        0 kB
    Node 0 Bounce:              0 kB
    Node 0 Slab:             5408 kB
    Node 0 SReclaimable:      644 kB
    Node 0 SUnreclaim:       4764 kB
    
    After the patch (or using hashdist=1 on the kernel command line):
    
    Node 0 MemTotal:      3407488 kB
    Node 0 MemFree:       3247608 kB
    Node 0 MemUsed:        159880 kB
    Node 0 Active:           3012 kB
    Node 0 Inactive:          616 kB
    Node 0 Dirty:               0 kB
    Node 0 Writeback:           0 kB
    Node 0 FilePages:        2424 kB
    Node 0 Mapped:            380 kB
    Node 0 AnonPages:        1200 kB
    Node 0 PageTables:        396 kB
    Node 0 NFS_Unstable:        0 kB
    Node 0 Bounce:              0 kB
    Node 0 Slab:             6304 kB
    Node 0 SReclaimable:     1596 kB
    Node 0 SUnreclaim:       4708 kB
    
    I guess it is a good idea to keep HASHDIST_DEFAULT "on" for x86_64 NUMA
    since x86_64 has no dearth of vmalloc space?  Or maybe enable hash
    distribution for all 64bit NUMA arches?  The following patch does it only
    for x86_64.
    
    I ran a HPC MPI benchmark -- 'Ansys wingsolid', which takes up quite a bit of
    memory and uses up tlb entries.  This was on a 4 way, 2 socket
    Tyan AMD box (non vsmp), with 8G total memory (4G pernode).
    
    The results with and without hash distribution are:
    
    1. Vanilla - runtime of 1188.000s
    2. With hashdist=1 runtime of 1154.000s
    
    Oprofile output for the duration of run is:
    
    1. Vanilla:
    PU: AMD64 processors, speed 2411.16 MHz (estimated)
    Counted L1_AND_L2_DTLB_MISSES events (L1 and L2 DTLB misses) with a unit
    mask of 0x00 (No unit mask) count 500
    samples  %        app name                 symbol name
    163054    6.5513  libansys1.so             MultiFront::decompose(int, int,
    Elemset *, int *, int, int, int)
    162061    6.5114  libansys3.so             blockSaxpy6L_fd
    162042    6.5107  libansys3.so             blockInnerProduct6L_fd
    156286    6.2794  libansys3.so             maxb33_
    87879     3.5309  libansys1.so             elmatrixmultpcg_
    84857     3.4095  libansys4.so             saxpy_pcg
    58637     2.3560  libansys4.so             .st4560
    46612     1.8728  libansys4.so             .st4282
    43043     1.7294  vmlinux-t                copy_user_generic_string
    41326     1.6604  libansys3.so             blockSaxpyBackSolve6L_fd
    41288     1.6589  libansys3.so             blockInnerProductBackSolve6L_fd
    
    2. With hashdist=1
    CPU: AMD64 processors, speed 2411.13 MHz (estimated)
    Counted L1_AND_L2_DTLB_MISSES events (L1 and L2 DTLB misses) with a unit
    mask of 0x00 (No unit mask) count 500
    samples  %        app name                 symbol name
    162993    6.9814  libansys1.so             MultiFront::decompose(int, int,
    Elemset *, int *, int, int, int)
    160799    6.8874  libansys3.so             blockInnerProduct6L_fd
    160459    6.8729  libansys3.so             blockSaxpy6L_fd
    156018    6.6826  libansys3.so             maxb33_
    84700     3.6279  libansys4.so             saxpy_pcg
    83434     3.5737  libansys1.so             elmatrixmultpcg_
    58074     2.4875  libansys4.so             .st4560
    46000     1.9703  libansys4.so             .st4282
    41166     1.7632  libansys3.so             blockSaxpyBackSolve6L_fd
    41033     1.7575  libansys3.so             blockInnerProductBackSolve6L_fd
    35762     1.5318  libansys1.so             inner_product_sub
    35591     1.5245  libansys1.so             inner_product_sub2
    28259     1.2104  libansys4.so             addVectors
    
    Signed-off-by: Pravin B. Shelar <pravin.shelar@calsoftinc.com>
    Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org>
    Signed-off-by: Shai Fultheim <shai@scalex86.org>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Christoph Lameter <clameter@engr.sgi.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit d039c688c6b3e7217381d2804bc0ca3171913fec
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Minor white space cleanup in traps.c
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit fb60b8392ce8ab185a7a0b4f7cefbe18b2afdab5
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Allow sys_uselib unconditionally
    
    Previously it wasn't enabled in the binfmt_aout is a module case.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1652fcbf37abdbbebaf386b46b20e486769e7b45
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Don't disable basic block reordering
    
    When compiling with -Os (which is default) the compiler defaults to it
    anyways. And with -O2 it probably generates somewhat better (although
    also larger) code.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 184c44d2049c4db7ef6ec65794546954da2c6a0e
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: fix x86_64-mm-sched-clock-share
    
    Fix for the following patch. Provide dummy cpufreq functions when
    CPUFREQ is not compiled in.
    
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit a4831e08b7f3ed51623c9eb25e8c945b76b3eda3
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Move cpu verification code to common file
    
    o This patch moves the code to verify long mode and SSE to a common file.
      This code is now shared by trampoline.S, wakeup.S, boot/setup.S and
      boot/compressed/head.S
    
    o So far we used to do very limited check in trampoline.S, wakeup.S and
      in 32bit entry point. Now all the entry paths are forced to do the
      exhaustive check, including SSE because verify_cpu is shared.
    
    o I am keeping this patch as last in the x86 relocatable series because
      previous patches have got quite some amount of testing done and don't want
      to distrub that. So that if there is problem introduced by this patch, at
      least it can be easily isolated.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 8035d3ea78c2a61a9738c7857742370e0aa74d5c
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: Extend bzImage protocol for relocatable bzImage
    
    o Extend the bzImage protocol (same as i386) to allow bzImage loaders to
      load the protected mode kernel at non-1MB address. Now protected mode
      component is relocatable and can be loaded at non-1MB addresses.
    
    o As of today kdump uses it to run a second kernel from a reserved memory
      area.
    
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 6a50a664ca0cfd2a487525f10cec3ff4d570b5e8
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:08 2007 +0200

    [PATCH] x86-64: build-time checking
    
    o X86_64 kernel should run from 2MB aligned address for two reasons.
    	- Performance.
    	- For relocatable kernels, page tables are updated based on difference
    	  between compile time address and load time physical address.
    	  This difference should be multiple of 2MB as kernel text and data
    	  is mapped using 2MB pages and PMD should be pointing to a 2MB
    	  aligned address. Life is simpler if both compile time and load time
    	  kernel addresses are 2MB aligned.
    
    o Flag the error at compile time if one is trying to build a kernel which
      does not meet alignment restrictions.
    
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 1ab60e0f72f71ec54831e525a3e1154f1c092408
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: Relocatable Kernel Support
    
    This patch modifies the x86_64 kernel so that it can be loaded and run
    at any 2M aligned address, below 512G.  The technique used is to
    compile the decompressor with -fPIC and modify it so the decompressor
    is fully relocatable.  For the main kernel the page tables are
    modified so the kernel remains at the same virtual address.  In
    addition a variable phys_base is kept that holds the physical address
    the kernel is loaded at.  __pa_symbol is modified to add that when
    we take the address of a kernel symbol.
    
    When loaded with a normal bootloader the decompressor will decompress
    the kernel to 2M and it will run there.  This both ensures the
    relocation code is always working, and makes it easier to use 2M
    pages for the kernel and the cpu.
    
    AK: changed to not make RELOCATABLE default in Kconfig
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 0dbf7028c0c1f266c9631139450a1502d3cd457e
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86: __pa and __pa_symbol address space separation
    
    Currently __pa_symbol is for use with symbols in the kernel address
    map and __pa is for use with pointers into the physical memory map.
    But the code is implemented so you can usually interchange the two.
    
    __pa which is much more common can be implemented much more cheaply
    if it is it doesn't have to worry about any other kernel address
    spaces.  This is especially true with a relocatable kernel as
    __pa_symbol needs to peform an extra variable read to resolve
    the address.
    
    There is a third macro that is added for the vsyscall data
    __pa_vsymbol for finding the physical addesses of vsyscall pages.
    
    Most of this patch is simply sorting through the references to
    __pa or __pa_symbol and using the proper one.  A little of
    it is continuing to use a physical address when we have it
    instead of recalculating it several times.
    
    swapper_pgd is now NULL.  leave_mm now uses init_mm.pgd
    and init_mm.pgd is initialized at boot (instead of compile time)
    to the physmem virtual mapping of init_level4_pgd.  The
    physical address changed.
    
    Except for the for EMPTY_ZERO page all of the remaining references
    to __pa_symbol appear to be during kernel initialization.  So this
    should reduce the cost of __pa in the common case, even on a relocated
    kernel.
    
    As this is technically a semantic change we need to be on the lookout
    for anything I missed.  But it works for me (tm).
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 1b29c1643c0d82512477ccd97dc290198fe23e22
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: do not use virt_to_page on kernel data address
    
    o virt_to_page() call should be used on kernel linear addresses and not
      on kernel text and data addresses. Swsusp code uses it on kernel data
      (statically allocated swsusp_header).
    
    o Allocate swsusp_header dynamically so that virt_to_page() can be used
      safely.
    
    o I am changing this because in next few patches, __pa() on x86_64 will
      no longer support kernel text and data addresses and hibernation breaks.
    
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 49c3df6aaa6a51071fc135273d1a2515d019099f
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86: Move swsusp __pa() dependent code to arch portion
    
    o __pa() should be used only on kernel linearly mapped virtual addresses
      and not on kernel text and data addresses.
    
    o Hibernation code needs to determine the physical address associated
      with kernel symbol to mark a section boundary which contains pages which
      don't have to be saved and restored during hibernate/resume operation.
    
    o Move this piece of code in arch dependent section. So that architectures
      which don't have kernel text/data mapped into kernel linearly mapped
      region can come up with their own ways of determining physical addresses
      associated with a kernel text.
    
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit cfd243d4af7c7f8f52f5cb99d3932d9074b039ff
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: Remove the identity mapping as early as possible
    
    With the rewrite of the SMP trampoline and the early page
    allocator there is nothing that needs identity mapped pages,
    once we start executing C code.
    
    So add zap_identity_mappings into head64.c and remove
    zap_low_mappings() from much later in the code.  The functions
     are subtly different thus the name change.
    
    This also kills boot_level4_pgt which was from an earlier
    attempt to move the identity mappings as early as possible,
    and is now no longer needed.  Essentially I have replaced
    boot_level4_pgt with trampoline_level4_pgt in trampoline.S
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit bdb96a6614cfaba24e23dd9de4040c068c3af19b
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: Modify discover_ebda to use virtual addresses
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d8e1baf10d62c06fc52e89137357e54da3d92672
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: 64bit ACPI wakeup trampoline
    
    o Moved wakeup_level4_pgt into the wakeup routine so we can
      run the kernel above 4G.
    
    o Now we first go to 64bit mode and continue to run from trampoline and
      then then start accessing kernel symbols and restore processor context.
      This enables us to resume even in relocatable kernel context when
      kernel might not be loaded at physical addr it has been compiled for.
    
    o Removed the need for modifying any existing kernel page table.
    
    o Increased the size of the wakeup routine to 8K. This is required as
      wake page tables are on trampoline itself and they got to be at 4K
      boundary, hence one page is not sufficient.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 275f55170ec2b5d777b070cb8ab9e5d58e65a2a8
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: wakeup.S misc cleanups
    
    o Various cleanups. One of the main purpose of cleanups is that make
      wakeup.S as close as possible to trampoline.S.
    
    o Following are the changes
    	- Indentations for comments.
    	- Changed the gdt table to compact form and to resemble the
    	  one in trampoline.S
    	- Take the jump to 32bit from real mode using ljmpl. Makes code
    	  more readable.
    	- After enabling long mode, directly take a long jump for 64bit
    	  mode. No need to take an extra jump to "reach_comaptibility_mode"
    	- Stack is not used after real mode. So don't load stack in
     	  32 bit mode.
    	- No need to enable PGE here.
    	- No need to do extra EFER read, anyway we trash the read contents.
    	- No need to enable system call (EFER_SCE). Anyway it will be
    	  enabled when original EFER is restored.
    	- No need to set MP, ET, NE, WP, AM bits in cr0. Very soon we will
      	  reload the original cr0 while restroing the processor state.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 7db681d7e4038ad205b5face5cf7f7815633e1b5
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: wakeup.S rename registers to reflect right names
    
    o Use appropriate names for 64bit regsiters.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 7c17e70613d2c70f9d5d0b5d37126fd5e8e9b728
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: Get rid of dead code in suspend resume
    
    o Get rid of dead code in wakeup.S
    
    o We never restore from saved_gdt, saved_idt, saved_ltd, saved_tss, saved_cr3,
      saved_cr4, saved_cr0, real_save_gdt, saved_efer, saved_efer2. Get rid
      of of associated code.
    
    o Get rid of bogus_magic, bogus_31_magic and bogus_magic2. No longer being
      used.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 90b1c2085ea1955641e60a4f0acd63fdc271cd0b
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: 64bit PIC SMP trampoline
    
    This modifies the SMP trampoline and all of the associated code so
    it can jump to a 64bit kernel loaded at an arbitrary address.
    
    The dependencies on having an idenetity mapped page in the kernel
    page tables for SMP bootup have all been removed.
    
    In addition the trampoline has been modified to verify
    that long mode is supported.  Asking if long mode is implemented is
    down right silly but we have traditionally had some of these checks,
    and they can't hurt anything.  So when the totally ludicrous happens
    we just might handle it correctly.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3c321bceb4a626639ab43a5a24d884930e511826
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: Add EFER to the register set saved by save_processor_state
    
    EFER varies like %cr4 depending on the cpu capabilities, and which cpu
    capabilities we want to make use of.  So save/restore it make certain
    we have the same EFER value when we are done.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 30f472895401fbe8e64f861a2569bc9acb098741
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: cleanup segments
    
    Move __KERNEL32_CS up into the unused gdt entry.  __KERNEL32_CS is
    used when entering the kernel so putting it first is useful when
    trying to keep boot gdt sizes to a minimum.
    
    Set the accessed bit on all gdt entries.  We don't care
    so there is no need for the cpu to burn the extra cycles,
    and it potentially allows the pages to be immutable.  Plus
    it is confusing when debugging and your gdt entries mysteriously
    change.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 278c0eb7f96586c02b2bfaa8e250d951919a2e6a
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:07 2007 +0200

    [PATCH] x86-64: modify copy_bootdata to use virtual addresses
    
    Use virtual addresses instead of physical addresses
    in copy bootdata.  In addition fix the implementation
    of the old bootloader convention.  Everything is
    at real_mode_data always.  It is just that sometimes
    real_mode_data was relocated by setup.S to not sit at
    0x90000.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 93fd755e47d7b00fa5470199cfb14cbd9ded0284
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Fix early printk to use standard ISA mapping
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 67dcbb6bc6537aea92a2466bfc75f015b00e465e
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Clean up the early boot page table
    
    - Merge physmem_pgt and ident_pgt, removing physmem_pgt.  The merge
      is broken as soon as mm/init.c:init_memory_mapping is run.
    - As physmem_pgt is gone don't export it in pgtable.h.
    - Use defines from pgtable.h for page permissions.
    - Fix the physical memory identity mapping so it is at the correct
      address.
    - Remove the physical memory mapping from wakeup_level4_pgt it
      is at the wrong address so we can't possibly be usinging it.
    - Simply NEXT_PAGE the work to calculate the phys_ alias
      of the labels was very cool.  Unfortuantely it was a brittle
      special purpose hack that makes maitenance more difficult.
      Instead just use label - __START_KERNEL_map like we do
      everywhere else in assembly.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit dafe41ee3a9389c08c91cdfd8670295f20f89e04
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Kill temp boot pmds
    
    Early in the boot process we need the ability to set
    up temporary mappings, before our normal mechanisms are
    initialized.  Currently this is used to map pages that
    are part of the page tables we are building and pages
    during the dmi scan.
    
    The core problem is that we are using the user portion of
    the page tables to implement this.  Which means that while
    this mechanism is active we cannot catch NULL pointer dereferences
    and we deviate from the normal ways of handling things.
    
    In this patch I modify early_ioremap to map pages into
    the kernel portion of address space, roughly where
    we will later put modules, and I make the discovery of
    which addresses we can use dynamic which removes all
    kinds of static limits and remove the dependencies
    on implementation details between different parts of the code.
    
    Now alloc_low_page() and unmap_low_page() use
    early_iomap() and early_iounmap() to allocate/map and
    unmap a page.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9d291e787b2b71d1b57e5fbb24ba9c70e748ed84
Author: Vivek Goyal <vgoyal@in.ibm.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Assembly safe page.h and pgtable.h
    
    This patch makes pgtable.h and page.h safe to include
    in assembly files like head.S.  Allowing us to use
    symbolic constants instead of hard coded numbers when
    refering to the page tables.
    
    This patch copies asm-sparc64/const.h to asm-x86_64 to
    get a definition of _AC() a very convinient macro that
    allows us to force the type when we are compiling the
    code in C and to drop all of the type information when
    we are using the constant in assembly.  Previously this
    was done with multiple definition of the same constant.
    const.h was modified slightly so that it works when given
    CONFIG options as arguments.
    
    This patch adds #ifndef __ASSEMBLY__ ... #endif
    and _AC(1,UL) where appropriate so the assembler won't
    choke on the header files.  Otherwise nothing
    should have changed.
    
    AK: added const.h to exported headers to fix headers_check
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit e65845045588806fa5c8df8a4f4253516515a5e3
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: dma_ops as const
    
    The dma_ops structure can be const since it never changes
    after boot.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 19d1743315099665db4ce02c9942507a5ee1deea
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] i386: Simplify smp_call_function*() by using common implementation
    
    smp_call_function and smp_call_function_single are almost complete
    duplicates of the same logic.  This patch combines them by
    implementing them in terms of the more general
    smp_call_function_mask().
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Stephane Eranian <eranian@hpl.hp.com>
    Cc: Andrew Morton <akpm@osdl.org>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
    Cc: Ingo Molnar <mingo@elte.hu>

commit 6b37f5a20c0e5c334c010a587058354215433e92
Author: Joerg Roedel <joerg.roedel@amd.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: fix cpu MHz reporting on constant_tsc cpus
    
    This patch fixes the reporting of cpu_mhz in /proc/cpuinfo on CPUs with
    a constant TSC rate and a kernel with disabled cpufreq.
    
    Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com>
    Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    
     arch/x86_64/kernel/apic.c     |    2 -
     arch/x86_64/kernel/time.c     |   58 +++++++++++++++++++++++++++++++++++++++---
     arch/x86_64/kernel/tsc.c      |   12 +++++---
     arch/x86_64/kernel/tsc_sync.c |    2 -
     include/asm-x86_64/proto.h    |    1
     5 files changed, 65 insertions(+), 10 deletions(-)

commit fbc16f2c2a0e16dbd75ac85d3b6db97f92b642ba
Author: Glauber de Oliveira Costa <gcosta@redhat.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Remove duplicated code for reading control registers
    
    On Tue, Mar 13, 2007 at 05:33:09AM -0700, Randy.Dunlap wrote:
    > On Tue, 13 Mar 2007, Glauber de Oliveira Costa wrote:
    >
    > > Tiny cleanup:
    > >
    > > In x86_64, the same functions for reading cr3 and writing cr{3,4} are
    > > defined in tlbflush.h and system.h, whith just a name change.
    > > The only difference is the clobbering of memory, which seems a safe, and
    > > even needed change for the write_cr4. This patch removes the duplicate.
    > > write_cr3() is moved to system.h for consistency.
    >
    > missing patch.....
    >
    thanks. Attached now
    
    --
    Glauber de Oliveira Costa
    Red Hat Inc.
    "Free as in Freedom"
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit f9d09645d6157fefa18ff75930737060c8092ddb
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: Remove unused set_seg_base
    
    The set_seg_base function isn't used anywhere (2.6.21-rc3-git1)
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b0b1ff653a0ce88dc9d5cec4e67c9c2be0ba03ef
Author: Lasse Collin <lasse.collin@tukaani.org>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] i386: Fix usage of -mtune when X86_GENERIC=y or CONFIG_MCORE2=y
    
    Hi!
    
    I sent this simple patch to lkml about two weeks ago and also cc'ed
    to Linus, but seems that the patch got ignored. I decided to write to
    you, because you have modified the relevant file most recently.
    
    Below is a copy of the mail that is also available at
    <http://lkml.org/lkml/2007/2/28/230>.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 973efae21beb2feda138f152ed06d4204774d93c
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] i386: clean up mach_reboot_fixups
    
    The reboot_fixups stuff seems to be a bit of a mess, specifically the
    header is in linux/ when its a purely i386-specific piece of code.  I'm
    not sure why it has its config option; its only currently needed for
    "geode-gx1/cs5530a", so perhaps whatever config option controls that
    hardware should enable this?
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 6d1c426158131b11d05d66e7dd6bf91e5b1b4fc7
Author: Aneesh Kumar K.V <aneesh.kumar@gmail.com>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] i386: Update __copy_to_user_inatomic linuxdoc description
    
    Explicity specify that the caller should pin the user memory
    otherwise the function will sleep
    
    Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@gmail.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit c8fdd247255a3a027cd9f66dcf93e6847d1d2f85
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] x86: Drop cc-options call for all options supported in gcc 3.2+
    
    The kernel only supports gcc 3.2+ now so it doesn't make sense
    anymore to explicitely check for options this compiler version
    already has.
    
    This actually fixes a bug. The -mprefered-stack-boundary check
    never worked because gcc rightly complains
    
      CC      arch/i386/kernel/asm-offsets.s
    cc1: -mpreferred-stack-boundary=2 is not between 4 and 12
    
    We just never saw the error because of cc-options.
    I changed it to 4 to actually work.
    
    Tested by compiling i386 and x86-64 defconfig with gcc 3.2.
    
    Should speed up the build time a tiny bit and improve
    stack usage on i386 slightly.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2a12652c0335ec90747d3402a82b6699ae883b58
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:06 2007 +0200

    [PATCH] i386: Support Oprofile for AMD Family 10 CPUs
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d9c93813ac17b34ee6eb7a424578acae6f90d759
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86-64: Correct max number of CPUs in Kconfig
    
    Pointed out by Adrian Bunk
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 86c0baf123e474b6eb404798926ecf62b426bf3a
Author: Prarit Bhargava <prarit@redhat.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: Change sysenter_setup to __cpuinit & improve __INIT, __INITDATA
    
    Change sysenter_setup to __cpuinit.
    Change __INIT & __INITDATA to be cpu hotplug aware.
    
    Resolve MODPOST warnings similar to:
    
    WARNING: vmlinux - Section mismatch: reference to .init.text:sysenter_setup from
     .text between 'identify_cpu' (at offset 0xc040a380) and 'detect_ht'
    
    and
    
    WARNING: vmlinux - Section mismatch: reference to .init.data:vsyscall_int80_end
    from .text between 'sysenter_setup' (at offset 0xc041a269) and 'enable_sep_cpu'
    WARNING: vmlinux - Section mismatch: reference to
    .init.data:vsyscall_int80_start from .text between 'sysenter_setup' (at offset
    0xc041a26e) and 'enable_sep_cpu'
    WARNING: vmlinux - Section mismatch: reference to
    .init.data:vsyscall_sysenter_end from .text between 'sysenter_setup' (at offset
    0xc041a275) and 'enable_sep_cpu'
    WARNING: vmlinux - Section mismatch: reference to
    .init.data:vsyscall_sysenter_start from .text between 'sysenter_setup' (at
    offset 0xc041a27a) and 'enable_sep_cpu'
    
    Signed-off-by: Prarit Bhargava <prarit@redhat.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit e319af1d8722bc3fb61ed6968c88bb66fbb3f58e
Author: Prarit Bhargava <prarit@redhat.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: Add __init to probe_bigsmp
    
    Add __init to probe_bigsmp.  All callers are __init and data being examined
    is __initdata.
    
    Resolves MODPOST warning similar to:
    
    WARNING: vmlinux - Section mismatch: reference to .init.data: from .text between 'probe_bigsmp' (at offset 0xc0401e56) and 'init_apic_ldr'
    
    Signed-off-by: Prarit Bhargava <prarit@redhat.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 405e494d91bac85cc992f55ad434b0f325e399a5
Author: Stephane Eranian <eranian@hpl.hp.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86-64: x86_64 make NMI use PERFCTR1 for architectural perfmon (take 2)
    
    Hello,
    
    This patch against 2.6.20-git14 makes the NMI watchdog use PERFSEL1/PERFCTR1
    instead of PERFSEL0/PERFCTR0 on processors supporting Intel architectural
    perfmon, such as Intel Core 2. Although all PMU events can work on
    both counters, the Precise Event-Based Sampling (PEBS) requires that the
    event be in PERFCTR0 to work correctly (see section 18.14.4.1 in the
    IA32 SDM Vol 3b). This versions has 3 chunks compared to previous where
    we had missed on check.
    
    Changelog:
            - make the x86-64 NMI watchdog use PERFSEL1/PERFCTR1 instead of PERFSEL0/PERFCTR0
              on processors supporting the Intel architectural perfmon (e.g. Core 2 Duo).
              This allows PEBS to work when the NMI watchdog is active.
    
    signed-off-by: stephane eranian <eranian@hpl.hp.com>
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit bf8696ed6dfa561198b4736deaf11ab68dcc4845
Author: Stephane Eranian <eranian@hpl.hp.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: i386 make NMI use PERFCTR1 for architectural perfmon (take 2)
    
    Hello,
    
    This patch against 2.6.20-git14 makes the NMI watchdog use PERFSEL1/PERFCTR1
    instead of PERFSEL0/PERFCTR0 on processors supporting Intel architectural
    perfmon, such as Intel Core 2. Although all PMU events can work on
    both counters, the Precise Event-Based Sampling (PEBS) requires that the
    event be in PERFCTR0 to work correctly (see section 18.14.4.1 in the
    IA32 SDM Vol 3b).
    
    A similar patch for x86-64 is to follow.
    
    Changelog:
            - make the i386 NMI watchdog use PERFSEL1/PERFCTR1 instead of PERFSEL0/PERFCTR0
              on processors supporting the Intel architectural perfmon (e.g. Core 2 Duo).
              This allows PEBS to work when the NMI watchdog is active.
    
    signed-off-by: stephane eranian <eranian@hpl.hp.com>
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 803d80f65038f77c4681a0d7708e9d693e68aaa8
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86-64: Some cleanup in time.c
    
    Move prototypes into header files
    Remove unneeded includes.
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit d18951834216eae82e2f9112416111b4f55f1849
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86: Fix i386 and x86_64 fault information pollution
    
    a userspace fault or a kernelspace fault which will result in the
    immediate death of the process.  They should not be filled in as a
    result of a kernelspace fault which can be fixed up.
    
    Otherwise, if the process is handling SIGSEGV and examining the fault
    information, this can result in the kernel space fault trashing the
    previously stored fault information if it arrives between the
    userspace fault happening and the SIGSEGV being delivered to the process.
    
    Signed-off-by: Jeff Dike <jdike@addtoit.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Acked-by: Jan Beulich <jbeulich@novell.com>
    --
     arch/i386/kernel/traps.c   |   24 ++++++++++++++++++------
     arch/x86_64/kernel/traps.c |   30 +++++++++++++++++++++++-------
     2 files changed, 41 insertions(+), 13 deletions(-)

commit 00e065ea587363e538d9624eea8cacad12cb7397
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: Add dwarf2 annotations to *_user and checksum functions
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3755090722e5a9c44780e5461ed9e49ab542bc73
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86-64: a few missing entry.S annotations
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 0adad171c2334d43fc2fa208f6b45e88f0679427
Author: Rene Herman <rene.herman@gmail.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: probe_roms() cleanup
    
    Remove the assumption that if the first page of a legacy ROM is mapped,
    it'll all be mapped. This'll also stop people reading this code from
    wondering if they're looking at a bug...
    
    Signed-off-by: Rene Herman <rene.herman@gmail.com>
    Signed-off-by: Martin Murray <murrayma@citi.umich.edu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Zachary Amsden <zach@vmware.com>
    Cc: Jeremy Fitzhardinge <jeremy@goop.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 0949be35095b53dbaa72db700cb5074c5c249629
Author: Simon Arlott <simon@arlott.org>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: Add an option for the VIA C7 which sets appropriate L1 cache
    
    The VIA C7 is a 686 (with TSC) that supports MMX, SSE and SSE2, it also has
    a cache line length of 64 according to
    http://www.digit-life.com/articles2/cpu/rmma-via-c7.html.  This patch sets
    gcc to -march=686 and select s the correct cache shift.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Dave Jones <davej@codemonkey.org.uk>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit f5e8861583a591020176c90c10c6a130fed4f3ec
Author: takada <takada@mbf.nifty.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: pit_latch_buggy has no effect
    
    Eliminated the arch/i386/kernel/timers in 2.6.18, use clocksoures instead.
    pit_latch_buggy was referred in timers/timer_tsc.c, and currently removed.
    Therefore nobody refer it.
    
    Until 2.6.17, MediaGX's TSC works correctly.  after 2.6.18, warned "TSC
    appears to be running slowly.  Marking it as unstable".  So marked unstable
    TSC when CS55x0.
    
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9215da33209b861b01c51382254b178a3fe92a30
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: mtrr range check correction
    
    Whether a region is below 1Mb is determined by its start rather than
    its end.
    
    This hunk got erroneously dropped from a previous patch.
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit f76c392380a40008ee6ecaea4e5a51a3a10282c4
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] i386: No need to use -traditional for processing asm in i386/kernel/
    
    No need to use -traditional for processing asm in i386/kernel/
    
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 9964cf7d776600724ef5f1b33303ceadc588b8ba
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:05 2007 +0200

    [PATCH] x86: consolidate smp_send_stop()
    
    Synchronize i386's smp_send_stop() with x86-64's in only try-locking
    the call lock to prevent deadlocks when called from panic().
    In both version, disable interrupts before clearing the CPU off the
    online map to eliminate races with IRQ handlers inspecting this map.
    Also in both versions, save/restore interrupts rather than disabling/
    enabling them.
    On x86-64, eliminate one function used here by folding it into its
    single caller, convert to static, and rename for consistency with i386
    (lkcd may like this).
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit b0354795c9c8fef2fadf8f867586c78efd9a1dc9
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: adjust inclusion of asm/vsyscall32.h
    
    Avoid including asm/vsyscall32.h in virtually every source file.
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 00f1ea696702163b7411d2316264525996c66ed3
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86: adjust inclusion of asm/fixmap.h
    
    Move inclusion of asm/fixmap.h to where it is really used rather than
    where it may have been used long ago (requires a few other adjustments
    to includes due to previous implicit dependencies).
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 28609f6e4921ebb75ceaf5317454b8047b07cef4
Author: Jan Beulich <jbeulich@novell.com>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] i386: adjustments to page table dump during oops (v4)
    
    - make the page table contents printing PAE capable
    - make sure the address stored in current->thread.cr2 is unmodified
      from what was read from CR2
    - don't call oops_may_print() multiple times, when one time suffices
    - print pte even in highpte case, as long as the pte page isn't in
      actually in high memory (which is specifically the case for all page
      tables covering kernel space)
    
    (Changes to v3: Use sizeof()*2 rather than the suggested sizeof()*4 for
    printing width, use fixed 16-nibble width for PAE, and also apply the
    max_low_pfn range check to the middle level lookup on PAE.)
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3c43f03908de98fa8f7a9e8fc9411ebf4c2de298
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86: default to physical mode on hotplug CPU kernels
    
    Default to physical mode on hotplug CPU kernels.  Furher simplify and clean up
    the APIC initialization code.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>

commit 424df390101f9dfe015f0633aaec696c159b37a8
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: remove clustered APIC mode
    
    Remove now unused clustered APIC mode code.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>

commit 07c7c4744400f93a7c52b32159c31d823e1747a5
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: always use physical delivery mode on > 8 CPUs
    
    Remove clustered APIC mode.  There's little point in the use of clustered APIC
    mode, broadcasting is limited to within the cluster only, and chipsets have
    bugs in this area as well.  So default to physical APIC mode when the CPU
    count is large, and default to logical APIC mode when the CPU count is 8 or
    smaller.
    
    (this patch only removes the use of genapic_cluster and cleans up the
    resulting genapic.c file - removal of all remaining traces of clustered
    mode will be done by another patch.)
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>

commit f18d397e6aa5cde638d164b1d519c3ee903f4867
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: optimize & fix APIC mode setup
    
    Fix a couple of inconsistencies/problems I found while reviewing the x86_64
    genapic code (when I was chasing mysterious eth0 timeouts that would only
    trigger if CPU_HOTPLUG is enabled):
    
     - AMD systems defaulted to the slower flat-physical mode instead
       of the flat-logical mode. The only restriction on AMD systems
       is that they should not use clustered APIC mode.
    
     - removed the CPU hotplug hacks, switching the default for small
       systems back from phys-flat to logical-flat. The switching to logical
       flat mode on small systems fixed sporadic ethernet driver timeouts i
       was getting on a dual-core Athlon64 system:
    
        NETDEV WATCHDOG: eth0: transmit timed out
        eth0: Transmit timeout, status 0c 0005 c07f media 80.
        eth0: Tx queue start entry 32  dirty entry 28.
        eth0:  Tx descriptor 0 is 0008a04a. (queue head)
        eth0:  Tx descriptor 1 is 0008a04a.
        eth0:  Tx descriptor 2 is 0008a04a.
        eth0:  Tx descriptor 3 is 0008a04a.
        eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
    
     - The use of '<= 8' was a bug by itself (the valid APIC ids
       for logical flat mode go from 0 to 7, not 0 to 8). The new logic
       is to use logical flat mode on both AMD and Intel systems, and
       to only switch to physical mode when logical mode cannot be used.
       If CPU hotplug is racy wrt. APIC shutdown then CPU hotplug needs
       fixing, not the whole IRQ system be made inconsistent and slowed
       down.
    
     - minor cleanups: simplified some code constructs
    
    build & booted on a couple of AMD and Intel SMP systems.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>

commit a86f34b49f32b238d16b2e3bf6c9a5391a3f683f
Author: Andrew Morton <akpm@osdl.org>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86: revert x86_64-mm-fix-the-irqbalance-quirk-for-e7320-e7520-e7525
    
    Obsoleted by Ingo's genapic stuff.
    
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 3dc68d9b58ae644cee8e218e3dcde0dceb5c47a3
Author: Andrew Morton <akpm@osdl.org>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: revert x86_64-mm-add-genapic_force
    
    This is obsoleted by new Ingo genapic patches.
    
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: "Li, Shaohua" <shaohua.li@intel.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit fb27145d6ad2548d2d770f33ffa0a268c0afba85
Author: Andrew Morton <akpm@osdl.org>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] i386: revert i386-fix-the-verify_quirk_intel_irqbalance
    
    This is unneeded with Ingo's genapic rework.
    
    Cc: Suresh Siddha <suresh.b.siddha@intel.com>
    Cc: Andi Kleen <ak@suse.de>
    Cc: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Andi Kleen <ak@suse.de>

commit bdd0dc5210b5bb35dbddd5b0bc742e65a812a067
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] i386: Update defconfig
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit 2ca8c1a1269630473840835d1585adf2582b7c0b
Author: Andi Kleen <ak@suse.de>
Date:   Wed May 2 19:27:04 2007 +0200

    [PATCH] x86-64: Update defconfig
    
    Signed-off-by: Andi Kleen <ak@suse.de>

commit a19b89cad51b6f0da8f4bafdfdcfb10264cbcdea
Author: Jason Uhlenkott <juhlenko@akamai.com>
Date:   Thu Apr 26 17:25:51 2007 -0700

    NFS: Clean up nfs_create_request comments
    
    Remove some stale comments about hard limits which went away in 2.5.
    
    Signed-off-by: Jason Uhlenkott <juhlenko@akamai.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 61322b30139b79ec77170723a3a80043dcc94e87
Author: J. Bruce Fields - unquoted <bfields@snoopy.citi.umich.edu>
Date:   Sat Feb 10 01:33:27 2007 -0500

    spkm3: initialize hash
    
    There's an initialization step here I missed.
    
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit b80e183deff5f3d43565b552ed91e511128a6ea9
Author: J. Bruce Fields - unquoted <bfields@snoopy.citi.umich.edu>
Date:   Sat Feb 10 01:33:26 2007 -0500

    spkm3: remove bad kfree, unnecessary export
    
    We're kfree()'ing something that was allocated on the stack!
    
    Also remove an unnecessary symbol export while we're at it.
    
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit f32824d8ca9d3f84613ae2422070cc5469fe9e91
Author: J. Bruce Fields - unquoted <bfields@snoopy.citi.umich.edu>
Date:   Sat Feb 10 01:33:25 2007 -0500

    spkm3: fix spkm3's use of hmac
    
    I think I botched an attempt to keep an spkm3 patch up-to-date with a recent
    crypto api change.
    
    Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 08efa202eb398ce7939885a4a01df370fd392068
Author: J. Bruce Fields <bfields@citi.umich.edu>
Date:   Tue May 1 10:56:25 2007 -0400

    NFS4: invalidate cached acl on setacl
    
    The ACL that the server sets may not be exactly the one we set--for
    example, it may silently turn off bits that it does not support.  So we
    should remove any cached ACL so that any subsequent request for the ACL
    will go to the server.
    
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit f6259deacfd55607ae57cff422d3bc7694ea14e7
Author: Simon Arlott <simon@fire.lp0.eu>
Date:   Wed May 2 22:08:26 2007 +1000

    [CRYPTO] padlock: Remove pointless padlock module
    
    When this is compiled in it is run too early to do anything useful:
    [    6.052000] padlock: No VIA PadLock drivers have been loaded.
    [    6.052000] padlock: Using VIA PadLock ACE for AES algorithm.
    [    6.052000] padlock: Using VIA PadLock ACE for SHA1/SHA256 algorithms.
    
    When it's a module it isn't doing anything special, the same functionality
    can be provided in userspace by "probeall padlock padlock-aes padlock-sha"
    in modules.conf if it is required.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Cc: Michal Ludvig <michal@logix.cz>
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 9f90b997de4efd5404a8c52f89c400f0f4e2d216
Author: Christoph Hellwig <hch@infradead.org>
Date:   Mon Apr 30 11:56:46 2007 +0100

    [POWERPC] Minor fault path optimization
    
    Call the kprobes pagefault handler directly instead of going through
    the complex notifier chain.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit eb609e52d188775da738a1ffd1e982e6212c77d7
Author: Srinivasa Ds <srinivasa@in.ibm.com>
Date:   Mon Apr 23 11:28:49 2007 +0530

    [POWERPC] Transparently handle <.symbol> lookup for kprobes
    
    When data symbols are not present in kernel image, user needs to add
    dot(".") before function name explicitly, that he wants to probe in kprobe
    module on ppc64.
    
    for ex:-
    When data symbols are missing on ppc64,
    ====================
    [root@llm27lp1 ~]# cat /proc/kallsyms | grep do_fork
    c00000000006283c T .do_fork
    ==============================
    User needs add "." to "do_fork"
    
    kp.symbol_name = ".do_fork";
    ============================
    
    This makes kprobe modules unportable.  This fixes the problem.
    
    Signed-off-by: Srinivasa Ds <srinivasa@in.ibm.com>
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 14d1d2f25bca1c4ed45704c8019f6c971c40bba4
Author: Scott Wood <scottwood@freescale.com>
Date:   Wed May 2 02:05:38 2007 +1000

    [POWERPC] Remove duplicate export of __div64_32.
    
    Change 3927f2e8f9afa3424bb51ca81f7abac01ffd0005 moved lib/lib64.c from
    lib-y to obj-y, preventing the export in ppc_ksyms.c from overriding
    the one in lib, and thus causing a duplicate-export warning.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 90f7afefaeda946977824617c225b53f0813e357
Author: Olof Johansson <olof@lixom.net>
Date:   Tue May 1 14:43:39 2007 +1000

    [POWERPC] pasemi: Only call of_platform_bus_probe() on relevant platforms
    
    Only publish of_platform devices if running on a machine that has them.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 40cd3a4564ed6b7bc0279430120ca0e9b83cf486
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue May 1 13:54:02 2007 +1000

    [POWERPC] Rename get_property to of_get_property: drivers
    
    These are all the remaining instances of get_property.  Simple rename of
    get_property to of_get_property.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9f9a3b8a06b7965335bfe5162c1a50e4d9c3859b
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue May 1 13:51:32 2007 +1000

    [POWERPC] get_property returns const
    
    This is the last place that needs changing since get_property was changed
    to return "const void *".
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a6afacb6b8ba3d2eed6406a018e604d6f9c0f97d
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue May 1 10:20:20 2007 +1000

    [POWERPC] Small cleanups to the cuboot bootwrapper code
    
    This patch makes a few small cleanups to the cuboot code.
    	- It removes the double layered selection of images, via
    cuboot-plat-y, instead having the cuboot platforms directly select a
    suitable image-y (this changes the name of the final cuboot image from
    plain cuImage to cuImage.<platform>).
    	- Factors out some code in the wrapper that's potentially
    useful to platforms other than uboot.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Acked-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0cd74f398a1b86eab9d56224f3469235b2097e3c
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Tue May 1 07:01:11 2007 +1000

    [POWERPC] PS3: Defconfig updates
    
    Updates to ps3_defconfig for linux-2.6.21.
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0874dd40bf3c1f291da14b2c554c5640c0b6bf1b
Author: Takao Shinohara <shin@sm.sony.co.jp>
Date:   Tue May 1 07:01:07 2007 +1000

    [POWERPC] PS3: Fix system slowdown
    
    The PS3 HV will deliver soft-disabled interrupts at the next HV call or
    interrupt.  Add an HV call to local_irq_restore() to force the timely
    delivery of any pending interrupts.
    
    This fixes the system slowdown bug reported here
    http://bugzilla.kernel.org/show_bug.cgi?id=8260
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit dc4f60c25ae71e8278dcf909486e4aa34de7eecb
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Tue May 1 07:01:01 2007 +1000

    [POWERPC] PS3: Interrupt routine fixups.
    
    Fixups for the ps3 interrupt routines to support all HV device
    in a generic way.
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 12828856630e616742e092c8ccbda6ebc56a9375
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Tue May 1 07:00:56 2007 +1000

    [POWERPC] PS3: Remove duplicate variable assignement
    
    A minor change to remove a duplicate variable assignement in ps3_mm_shutdown();
    
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f0a1d024cc2699f4897d611da1d91777cccc530b
Author: Geoff Levand <geoffrey.levand@am.sony.com>
Date:   Tue May 1 07:00:50 2007 +1000

    [POWERPC] PS3: Add DABR support
    
    Add PS3 support for the PowerPC processor's Data Address Breakpoint Register
    (DABR).
    
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5cddd2e355d0df400782dae80722945c8197b1c5
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Tue May 1 06:38:11 2007 +1000

    [POWERPC] Fix spurious vectors on weird MPIC
    
    The weird TSI 10x MPIC needs an EOI after getting a spurious vector.  This
    patch uses the existing MPIC_SPV_EOI flag to fix this issue.
    
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0f21712df1cbf21d35da8287331d64ff75ca7b01
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Mon Apr 30 21:37:55 2007 +1000

    [POWERPC] Use menuconfig objects II - Macintosh
    
    Make a "menuconfig" out of the Kconfig objects "menu, ..., endmenu",
    so that the user can disable all the options in that menu at once
    instead of having to disable each option separately.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit be9c94dd7776467813419f49fabe8017bc2d4c81
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 30 21:37:15 2007 +1000

    [POWERPC] Fix suspend states again
    
    In commit 0fba3a1f39f8b0a50b56c8b068fa52131cbc84c2 (a very long time ago,
    May 2006), I fixed a bug that caused powermacs to crash when you tried
    entering standby/mem suspend states.
    
    As I'm now getting more familiar with the suspend code I notice a few
    more things:
     1. we previously misunderstood what pm_ops is for, it isn't supposed to be
        for doing platform dependent suspend/resume stuff that needs to be done
        for suspend to disk (as we currently try to use it!), it is instead for
        entering platform dependent suspend states ("standby", "mem").
     2. due to the first point, we never properly save FPU and altivec states
        when suspending to disk. It probably hasn't hurt yet because the process
        that writes the "disk" to /sys/power/state uses neither and its context
        is used.
    
    This patch addresses these points as follows:
     1. remove all pm_ops from powermac, powermac suspend to ram isn't currently
        usable via /sys/power/state but is done via the PMU instead.
     2. move the code responsible for storing FPU/altivec state into
        save_processor_state and the set_context() call to restore_processor_state.
     3. add a call to kernel_enable_spe()
    
    It may look like there is some code removal missing but that is
    actually because the new suspend.h file overrides the ppc/suspend.h
    one which was previously used.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f88df14b1f15cdeffa060580a40c1ce3e13bb79e
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Apr 30 16:30:56 2007 +1000

    [POWERPC] Remove arch/powerpc's dependence on asm-ppc/pg{alloc,table}.h
    
    Currently, all 32-bit powerpc platforms use asm-ppc/pgtable.h and
    asm-ppc/pgalloc.h, even when otherwise compiled with ARCH=powerpc.
    Those asm-ppc files are a fairly nasty tangle of #ifdefs including a
    bunch of things which shouldn't be necessary any more in arch/powerpc.
    
    Cleaning up that mess is going to take a while, but this patch is a
    first step.  It separates the asm-powerpc/pg{alloc,table}.h into 64
    bit and 32 bit versions in asm-powerpc, which the basic .h files in
    asm-powerpc select based on config.  We make a few tiny tweaks to the
    innards of the files along the way, making the outermost ifdefs
    (double-inclusion protection and __KERNEL__) a little cleaner, and
    #including asm-generic/pgtable.h from the top-level
    asm-powerpc/pgtable.h (since both the old 32-bit and 64-bit versions
    ended with such an #include).
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 69d48b409cac747cc0707b05b769e38488a6ad35
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Apr 30 15:37:06 2007 +1000

    [POWERPC] Fix STRICT_MM_TYPECHECKS
    
    Since we don't have it active by default, the STRICT_MM_TYPECHECKS
    option has bitrotted again.  This patch fixes a couple of simple build
    fixes if the option is selected.  First, pud_t mustn't be defined in
    page.h on 32-bit systems, because it conflicts with the version in the
    generic pud-folding code.  Second, pci_32.c is missing a __pgprot()
    wrapper call.  Third, a couple of PS3 files use constants of type
    pgprot_t when they need the raw values, we add pgprot_val() calls to
    fix this.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 57d7909e0d2dd54567ae775e22b14076b777042a
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Apr 30 14:06:25 2007 +1000

    [POWERPC] Revise PPC44x MMU code for arch/powerpc
    
    This patch takes the definitions for the PPC44x MMU (a software loaded
    TLB) from asm-ppc/mmu.h, cleans them up of things no longer necessary
    in arch/powerpc and puts them in a new asm-powerpc/mmu_44x.h file.  It
    also substantially simplifies arch/powerpc/mm/44x_mmu.c and makes a
    couple of small fixes necessary for the 44x MMU code to build and work
    properly in arch/powerpc.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c3e8011ad1bf4791a9c6d70ac1b377df93a9f5af
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Wed Apr 25 01:32:02 2007 +1000

    [POWERPC] Uninline of_iomap function
    
    There is no big reason to have that function inlined.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ed16669298b26266fc0c81bcd4ecc4b4126f77eb
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Wed Apr 18 11:50:09 2007 +1000

    [POWERPC] Initialise spinlock in the DEBUG_PAGEALLOC code
    
    Fixes:
    
    BUG: spinlock bad magic on CPU#0, swapper/0
     lock: c00000000064ec30, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0
    Call Trace:
    [c00000000062b980] [c00000000000f920] .show_stack+0x6c/0x1a0 (unreliable)
    [c00000000062ba20] [c0000000001c2b40] .spin_bug+0xb0/0xd4
    [c00000000062bab0] [c0000000001c2ed0] ._raw_spin_lock+0x44/0x184
    [c00000000062bb50] [c0000000003a42b4] ._spin_lock+0x10/0x24
    [c00000000062bbd0] [c00000000002b4dc] .kernel_map_pages+0x198/0x278
    [c00000000062bc90] [c000000000079720] .free_hot_cold_page+0x124/0x418
    [c00000000062bd70] [c000000000530278] .free_all_bootmem_core+0x14c/0x224
    [c00000000062be50] [c00000000052a178] .mem_init+0x68/0x170
    [c00000000062bee0] [c00000000051d874] .start_kernel+0x2a0/0x37c
    [c00000000062bf90] [c0000000000084c8] .start_here_common+0x54/0x8c
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 543e51c0e1fc9480ffb94b6b3536da0f1bfb21d4
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Wed Apr 11 07:56:53 2007 +1000

    [POWERPC] Turn on corresponding PHY drivers in QE UEC platforms defconfigs
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3baee955953957be5496cd28e9c544d9db214262
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Wed Apr 11 07:56:49 2007 +1000

    [POWERPC] Add 'mdio' to bus scan id list for platforms with QE UEC
    
    Add 'mdio' to bus scan id list for platforms with QE UEC
    as a consequence of converting UEC mdio driver to an
    of_platform driver in the ucc_geth phylib conversion patch.
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0fd8c47cccb101ce4bed049e4bb3b50e44b16500
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Tue Apr 24 07:26:14 2007 +1000

    [POWERPC] Replace undocumented interface properties in dts files
    
    phy-connection-type now supersedes the interface property.
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 60c1922c6909b2d1242d8476069d8459b859de59
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Tue Apr 24 07:26:10 2007 +1000

    [POWERPC] Document phy-connection-type property
    
    Since ucc_geth is being migrated to use the phylib, the existing
    (undocumented) 'interface' property is being deprecated in favour
    of 'phy-connection-type'.
    
    phy-connection-type is now maintained one-to-one with definitions
    in include/linux/phy.h, albeit in the form of a string.
    If not specified, "mii" is assumed.
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 650f7b3b2f0ead0673e90452cf3dedde97c537ba
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Wed Apr 11 06:11:23 2007 +1000

    [POWERPC] pseries: Handle null iommu dma-window property correctly
    
    Some versions of pSeries firmware fail to set up a
    dma-window property for PCI slots that are unoccupied.
    As a result, the loop searching for this propery, in
    pci_dma_dev_setup_pSeriesLP(), can run to the end, resulting
    in a NULL pointer dereference later in the routine. This
    patch prevents the crash, and prints a warning message.
    
    This is theoretically a rare error, as it occurs on what
    is hopefully just beta levels of firmware. But just in case
    this firmware escapes into the wild, this patch will avoid
    the crash.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>

commit 8fce6dd29fa9d1ac880bf0cb4528e9bd5878cf68
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Wed Mar 21 21:40:42 2007 +1100

    [POWERPC] powermac: Fix G5-cpufreq for cpu on/offline
    
    The original code here is wrong, it applies "previous" knowledge.
    The way the cpufreq core is designed is that the policy for the
    secondary CPU that comes online says that it must in fact not
    use this policy but use the same as the other CPUs that are
    listed, which in fact is CPU#0.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit b302887854d6f0c6f9fc3f1080535e7c1bd53134
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Tue Mar 20 05:18:02 2007 +1100

    [POWERPC] apm_emu: Use generic apm-emulation
    
    This patch removes a huge amount of code that is now in common code
    in drivers/char/apm-emulation.c
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6bfeccdc110a4f92e44d51d67b274977392cbf46
Author: Zang Roy-r61911 <tie-fei.zang@freescale.com>
Date:   Thu Mar 15 10:37:56 2007 +1100

    [POWERPC] kernel: Remove loops_per_jiffy code for 7448HPC2 platforms
    
    Remove loops_per_jiffy early initialization code for 7448HPC2 platforms.
    Since udelay no longer uses loops_per_jiffy it is not necessary to
    initialize it early.
    
    Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f3e5d2bf52514bb92b46bf866d20cc53bbbeb0fb
Author: Adrian Bunk <bunk@stusta.de>
Date:   Thu Mar 8 09:41:07 2007 +1100

    [POWERPC] drivers/macintosh/mac_hid.c: Make code static
    
    This patch makes some needlessly global code static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a3cf4bdef090530cf2e07dcd45265107db6e4752
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Fri Feb 9 00:27:44 2007 +1100

    [POWERPC] Remove unneeded page_is_ram export
    
    arch/powerpc/mm/mem.c exports page_is_ram, which is not used anywhere
    that could be modular.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c0b3ae14f14f53fb0d0453feeeb830a080726155
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue Feb 6 12:03:31 2007 +1100

    [POWERPC] Move of_irq_to_resource from prom.h to prom_parse.c
    
    In the powerpc architecture, of_irq_to_resource, currently sitting in
    prom.h, needs irq_of_parse_and_map and NO_IRQ from asm-powerpc/irq.h.
    The solution suggested by Benjamin Herrenschmidt is to move it to
    arch/powerpc/kernel/prom_parse.c.
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0eb2e6019ae8e76a537bdca07b31e1524a3bba48
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Wed Nov 1 15:53:00 2006 +1100

    [POWERPC] pmac_feature_call checks platform
    
    This patch makes sure that a caller of pmac_call_feature() won't try
    to call into ppc_md.feature_call of another platform, which might
    happen if some powermac drivers are loaded on non-powermac machines.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e196d6259141eda47aeafd88514aae652bfbfc7f
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sat Apr 14 16:09:14 2007 +1000

    [CRYPTO] api: Add ablkcipher_request_set_tfm
    
    This patch adds ablkcipher_request_set_tfm for those users that need
    to manage the memory for ablkcipher requests directly.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 124b53d020622ffa24e27406f2373d5a3debd0d3
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 16 20:49:20 2007 +1000

    [CRYPTO] cryptd: Add software async crypto daemon
    
    This patch adds the cryptd module which is a template that takes a
    synchronous software crypto algorithm and converts it to an asynchronous
    one by executing it in a kernel thread.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit a73e69965fa2647faa36caf40f4132b9c99d61fd
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sun Apr 8 21:31:36 2007 +1000

    [CRYPTO] api: Do not remove users unless new algorithm matches
    
    As it is whenever a new algorithm with the same name is registered
    users of the old algorithm will be removed so that they can take
    advantage of the new algorithm.  This presents a problem when the
    new algorithm is not equivalent to the old algorithm.  In particular,
    the new algorithm might only function on top of the existing one.
    
    Hence we should not remove users unless they can make use of the
    new algorithm.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit cf02f5da9437201d57d93f529839dd40aac8b5f9
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Thu Mar 29 17:32:59 2007 +1000

    [CRYPTO] cryptomgr: Fix parsing of nested templates
    
    This patch allows the use of nested templates by allowing the use of
    brackets inside a template parameter.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit b5b7f08869340aa8cfa23303f7d195f161479592
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 16 20:48:54 2007 +1000

    [CRYPTO] api: Add async blkcipher type
    
    This patch adds the mid-level interface for asynchronous block ciphers.
    It also includes a generic queueing mechanism that can be used by other
    asynchronous crypto operations in future.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit ebc610e5bc76df073221e64e86c3f7533a09ea40
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Jan 1 18:37:02 2007 +1100

    [CRYPTO] templates: Pass type/mask when creating instances
    
    This patch passes the type/mask along when constructing instances of
    templates.  This is in preparation for templates that may support
    multiple types of instances depending on what is requested.  For example,
    the planned software async crypto driver will use this construct.
    
    For the moment this allows us to check whether the instance constructed
    is of the correct type and avoid returning success if the type does not
    match.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 6158efc09016d3186263f6fd3a50667446ec4008
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Wed Apr 4 17:41:07 2007 +1000

    [CRYPTO] tcrypt: Use async blkcipher interface
    
    This patch converts the tcrypt module to use the asynchronous block cipher
    interface.  As all synchronous block ciphers can be used through the async
    interface, tcrypt is still able to test them.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 32e3983fe590ac4cd70c7728eb330d43cef031a7
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sat Mar 24 14:35:34 2007 +1100

    [CRYPTO] api: Add async block cipher interface
    
    This patch adds the frontend interface for asynchronous block ciphers.
    In addition to the usual block cipher parameters, there is a callback
    function pointer and a data pointer.  The callback will be invoked only
    if the encrypt/decrypt handlers return -EINPROGRESS.  In other words,
    if the return value of zero the completion handler (or the equivalent
    code) needs to be invoked by the caller.
    
    The request structure is allocated and freed by the caller.  Its size
    is determined by calling crypto_ablkcipher_reqsize().  The helpers
    ablkcipher_request_alloc/ablkcipher_request_free can be used to manage
    the memory for a request.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 03f5d8cedb31deb558cd97095730cbc8bc54b12a
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sun Dec 31 10:42:06 2006 +1100

    [CRYPTO] api: Proc functions should be marked as unused
    
    The proc functions were incorrectly marked as used rather than unused.
    They may be unused if proc is disabled.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

commit 5b68790cd5e2879067bcbc45b01eeb6081e7d731
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Tue May 1 23:26:35 2007 +0200

    i2c-s3c2410: Fix bug in releasing driver
    
    When compiled as a module, the i2c-s3c2410 driver does not
    free either the IRQ or the i2c adapter it attached to the system.
    
    As part of this fix, move to the usual kernel style
    of freeing items as part of the probe error path
    making the remove process easier.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit e00a8cdf325346c531c841ee85c803792db60157
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Tue May 1 23:26:35 2007 +0200

    i2c-s3c2410: Fix I2C SDA to SCL setup time
    
    Fix the setup time for SDA to SCL due to the way
    the S3C24XX I2C controller works.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit e8c76eed2ecdb8e9ca5339761d2c076d32b7cbca
Author: Till Harbaum <lists@harbaum.org>
Date:   Tue May 1 23:26:35 2007 +0200

    i2c: New i2c-tiny-usb bus driver
    
    Add a driver for the i2c-tiny-usb interface. This is a simple
    do-it-yourself USB to I2C interface targeted at experimental and
    home use. See the i2c-tiny-usb homepage for hardware details:
    http://www.harbaum.org/till/i2c_tiny_usb
    
    Signed-off-by: Till Harbaum <till@harbaum.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit eefcd75e72f382270f8f64e030550b10e3882b2b
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:35 2007 +0200

    i2c: Documentation update
    
    Make the documentation on how to write and port i2c drivers more in
    line with the current state of things:
    * i2c-isa is deprecated and soon gone, so stop advertising it.
    * Drop many sensors-specific references. Most of them were outdated
      anyway.
    * Update the example code to reflect the recent and not-so-recent
      API and coding style preference changes.
    * Simplify the example init and cleanup functions.
    
    This should make things less complex to understand for newcomers.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 35532d20035d04b0ec28508583a56c7a65c5fa47
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Tue May 1 23:26:34 2007 +0200

    i2c: SPIN_LOCK_UNLOCKED cleanup
    
    SPIN_LOCK_UNLOCKED cleanup, use __SPIN_LOCK_UNLOCKED instead.
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 11de70bd4d40a1a39c1133b260bfbd6306e981d3
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:34 2007 +0200

    i2c: Obsolete i2c-ixp2000, i2c-ixp4xx and scx200_i2c
    
    The new generic i2c-gpio driver should be used instead.
    The obsolete drivers will be removed in September 2007.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Deepak Saxena <dsaxena@plexity.net>
    Cc: Jordan Crouse <jordan.crouse@amd.com>

commit bcda9f1eb0de0e1108c8b2765e5b7afa0dfb6c9f
Author: Ben Dooks <ben@fluff.org>
Date:   Tue May 1 23:26:34 2007 +0200

    i2c: New Simtec I2C bus driver
    
    Platform driver for the Simtec CPLD based simple I2C logic.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 1c23af90dc44d05bbb6a3b5246ab664b1f943943
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Tue May 1 23:26:34 2007 +0200

    i2c: Bitbanging I2C bus driver using the GPIO API
    
    This is a very simple bitbanging I2C bus driver utilizing the new
    arch-neutral GPIO API. Useful for chips that don't have a built-in
    I2C controller, additional I2C busses, or testing purposes.
    
    To use, include something similar to the following in the
    board-specific setup code:
    
      #include <linux/i2c-gpio.h>
    
      static struct i2c_gpio_platform_data i2c_gpio_data = {
    	.sda_pin	= GPIO_PIN_FOO,
    	.scl_pin	= GPIO_PIN_BAR,
      };
      static struct platform_device i2c_gpio_device = {
    	.name		= "i2c-gpio",
    	.id		= 0,
    	.dev		= {
    		.platform_data	= &i2c_gpio_data,
    	},
      };
    
    Register this platform_device, set up the I2C pins as GPIO if
    required and you're ready to go. This will use default values for
    udelay and timeout, and will work with GPIO hardware that does not
    support open drain mode, but allows sensing of the SDA and SCL lines
    even when they are being driven.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 16538e6b32600f76ad212d42fc2b1f801e32ab4b
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Tue May 1 23:26:34 2007 +0200

    Use menuconfig objects - I2C
    
    Allow the whole I2C menu to be disabled at once without diving into
    the submenus for deselecting all options (should the user desire so).
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit b86a1bc8e39641d0c4676943b77a3486ee296db8
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:34 2007 +0200

    i2c: Restore i2c_smbus_read_block_data
    
    Add back the i2c_smbus_read_block_data helper function, it is needed
    by the upcoming lm93 hardware monitoring driver and possibly others.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 7d054817b780e664bed6701b2aa637718e1905b7
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:33 2007 +0200

    i2c-pxa: Clean transaction stop
    
    It was reported to me that the i2c-pxa driver was not able to process
    more that 50 transactions per second. Investigation revealed that the
    I2C unit was busy for 20 ms after every transaction. The reason seems
    to be that we forget to clear the STOP and ACKNACK bits at the end of
    the transaction. According to the PXA27x developer's manual, we shall
    do so.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Lennert Buytenhek <kernel@wantstofly.org>
    Cc: Nicolas Pitre <nico@cam.org>

commit 494dbb64dc5b369cc28542f4c4d634e57b0d7f18
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:33 2007 +0200

    i2c-algo-bit: Improve debugging
    
    Improve the debugging features of the i2c-algo-bit driver:
    * Make it possible to compile the driver without debugging support
      at all, making it much smaller.
    * Use dev_dbg() for debugging messages where possible, and dev_err()
      for error messages.
    * Remove redundant debugging messages.
    
    These changes allowed for minor code cleanups, which are included
    as well.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 424ed67c7dae37e8115e1bebc3261e86a624dff2
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:33 2007 +0200

    i2c-algo-bit: Implement a 50/50 SCL duty cycle
    
    The original i2c-algo-bit implementation uses a 33/66 SCL duty cycle
    when bits are being written on the bus. While the I2C specification
    doesn't forbid it, this prevents us from driving the I2C bus to its
    max speed, limiting us to 66 kbps max on standard I2C busses.
    
    Implementing a 50/50 duty cycle instead lets us max out the bandwidth
    up to the theoretical max of 100 kbps on standard I2C busses. This is
    particularly important when large amounts of data need to be transfered
    over the bus, as is the case with some TV adapters when the firmware is
    being uploaded.
    
    In fact this change even allows, at least in theory, fast-mode I2C
    support at 125, 166 and 250 kbps. There's no way to reach the
    theoretical max of 400 kbps with this implementation. But I don't
    think we want to put efforts in that direction anyway: software-driven
    I2C is very CPU-intensive and bad for latency.
    
    Other timing changes:
    * Don't set SDA high explicitly on error, we're going to issue a stop
      condition before we leave anyway.
    * If an error occurs when sending the slave address, yield the CPU
      before retrying, and remove the additional delay after the new start
      condition.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 7c175499822ba34ba60f32e4995fcc16c007d308
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c-omap: Switch to static adapter numbering
    
    Update the OMAP I2C driver to use i2c_add_numbered_adapter(), so that
    later patches can convert boards to using new-style drivers.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit d24ecfcc3953f9c3b833508cd839be614a3f3c64
Author: Bryan Wu <bryan.wu@analog.com>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c: Blackfin Two Wire Interface driver
    
    The i2c linux driver for blackfin architecture which supports blackfin
    on-chip TWI controller i2c operation.
    
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Reviewed-by: Alexey Dobriyan <adobriyan@gmail.com>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 6edac5803fb66f514d454d8e45595a170f04ea0e
Author: Ladislav Michl <ladis@linux-mips.org>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c-algo-sgi: Comment and whitespace cleanups
    
    Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit b3e820968ad47219f7d559117a30e85cf96b4e4e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c: Make i2c_del_driver a void function
    
    Make i2c_del_driver a void function, like all other driver removal
    functions. It always returned 0 even when errors occured, and nobody
    ever actually checked the return value anyway. And we cannot fail
    a module removal anyway.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit a97f1ed090fc01a5876a7caf2cbdf93470436201
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c: Move i2c-isa-only exported symbol declarations
    
    Move the declaration of i2c-isa-only exported symbols to i2c-isa
    itself, that's the best way to ensure nobody will attempt to use them.
    Hopefully we'll get rid of the exports themselves soon anyway.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit ce9e0794c23fb1d0222cb10009a198b427dcf6ad
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:32 2007 +0200

    i2c: Document i2c_new_device()
    
    Document the new i2c_new_device(), i2c_new_probed_device() and
    i2c_unregister_device() functions.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 12b5053ac58709c7d475888bc18d1f61958afc4e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c: Add i2c_new_probed_device()
    
    Add a new helper function to instantiate an i2c device. It is meant as a
    replacement for i2c_new_device() when you don't know for sure at which
    address your I2C/SMBus device lives. This happens frequently on TV
    adapters for example, you know there is a tuner chip on the bus, but
    depending on the exact board model and revision, it can live at different
    addresses. So, the new i2c_new_probed_device() function will probe the bus
    according to a list of addresses, and as soon as one of these addresses
    responds, it will call i2c_new_device() on that one address.
    
    This function will make it possible to port the old i2c drivers to the
    new model quickly.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 0f3b48385213355a2d4408bec1b481ffcf0e8638
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c-algo-bit: Add i2c_bit_add_numbered_bus
    
    Add i2c_bit_add_numbered_bus(), which is equivalent to i2c_bit_add_bus
    except that it calls i2c_add_numbered_adapter() at the end instead of
    i2c_add_adapter().
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit c05646069ccf8e94031ca9c8ab18fff35ba4405e
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c: i2c EXPORT_SYMBOL cleanup
    
    Make i2c-core.c obey Documentation/CodingStyle better by snugging
    the EXPORT_SYMBOL declarations next to the relevant definitions.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 6e13e641841833cc2aa5baefe89bb04bc388801b
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c: Add i2c_add_numbered_adapter()
    
    This adds a call, i2c_add_numbered_adapter(), registering an I2C adapter
    with a specific bus number and then creating I2C device nodes for any
    pre-declared devices on that bus.  It builds on previous patches adding
    I2C probe() and remove() support, and that pre-declaration of devices.
    
    This completes the core support for "new style" I2C device drivers.
    Those follow the standard driver model for binding devices to drivers
    (using probe and remove methods) rather than a legacy model (where the
    driver tries to autoconfigure each bus, and registers devices itself).
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 9c1600eda42e52796f49b36cf15b9debcfd09bea
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c: Add i2c_board_info and i2c_new_device()
    
    This provides partial support for new-style I2C driver binding.  It builds
    on "struct i2c_board_info" declarations that identify I2C devices on a given
    board.  This is needed on systems with I2C devices that can't be fully probed
    and/or autoconfigured, such as many embedded Linux configurations where the
    way a given I2C device is wired may affect how it must be used.
    
    There are two models for declaring such devices:
    
     * LATE -- using a public function i2c_new_device().  This lets modules
       declare I2C devices found *AFTER* a given I2C adapter becomes available.
    
       For example, a PCI card could create adapters giving access to utility
       chips on that card, and this would be used to associate those chips with
       those adapters.
    
     * EARLY -- from arch_initcall() level code, using a non-exported function
       i2c_register_board_info().  This copies the declarations *BEFORE* such
       an i2c_adapter becomes available, arranging that i2c_new_device() will
       be called later when i2c-core registers the relevant i2c_adapter.
    
       For example, arch/.../.../board-*.c files would declare the I2C devices
       along with their platform data, and I2C devices would behave much like
       PNPACPI devices.  (That is, both enumerate from board-specific tables.)
    
    To match the exported i2c_new_device(), the previously-private function
    i2c_unregister_device() is now exported.
    
    Pending later patches using these new APIs, this is effectively a NOP.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 4298cfc3eb6110df989f784be516c6340c597a66
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:31 2007 +0200

    i2c: i2c probe() and remove() documented
    
    Update Documentation/i2c to match previous patches updating probe()
    and remove() logic.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit a1d9e6e49f4b473a6945a6b553f5070e8c793e0a
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c: i2c stack can remove()
    
    More update for new style driver support:  add a remove() method, and
    use it in the relevant code paths.
    
    Again, nothing will use this yet since there's nothing to create devices
    feeding this infrastructure.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 7b4fbc50fabb810523be522fe7ec5cc40f85c7a1
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c: i2c stack can probe()
    
    One of a series of I2C infrastructure updates to support enumeration using
    the standard Linux driver model.
    
    This patch updates probe() and associated hotplug/coldplug support, but
    not remove().  Nothing yet _uses_ it to create I2C devices, so those
    hotplug/coldplug mechanisms will be the only externally visible change.
    This patch will be an overall NOP since the I2C stack doesn't yet create
    clients/devices except as part of binding them to legacy drivers.
    
    Some code is moved earlier in the source code, helping group more of the
    per-device infrastructure in one place and simplifying handling per-device
    attributes.
    
    Terminology being adopted:  "legacy drivers" create devices (i2c_client)
    themselves, while "new style" ones follow the driver model (the i2c_client
    is handed to the probe routine).  It's an either/or thing; the two models
    don't mix, and drivers that try mixing them won't even be registered.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 5cedb05db3c3084c9641403dd24c310a6b3ea19f
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c-pca-isa: Port to the new device driver model
    
    Port the i2c-pca-isa driver to the new device driver model. I'm
    using Rene Herman's new isa bus type, as it fits the needs nicely. One
    benefit is that we can now give a proper parent to our i2c adapter.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 4a5d30302ec82c53613915d5eb8381b8efe1dd0e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c-elektor: Port to the new device driver model
    
    Port the i2c-elektor driver to the new device driver model. I'm
    using Rene Herman's new isa bus type, as it fits the needs nicely. One
    benefit is that we can now give a proper parent to our i2c adapter.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit c6e8bb2ca5e50547557650c9251d24f55a8f4cfb
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c-parport-light: Port to the new device driver model
    
    Also fix a small race on driver unload: we need to unregister the
    i2c adapter before we power it off.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 3af07bd297b6ba3d77474fdb3b2656dd3f0404d5
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:30 2007 +0200

    i2c-parport: Fix a minor race on driver unload
    
    When unloading the driver, we really want to unregister the i2c adapter
    before we power it off, rather than the other way around.
    
    Also speed up the bus a bit when we can sense SCL. The slaves will
    stretch the line as needed.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 4b4686e7a6fe8347938beef518e9b309127945f1
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:30 2007 +0200

    scx200_acb: Fix PCI device reference count
    
    The scx200_acb driver supports two kind of devices, PCI ones and ISA
    ones. Even ISA ones are detected using the presence of a given PCI
    device, and we get a reference to it, but never put it back, so we
    have a leak. Fix it.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 7c59b6615fed9d3006b1e7b865fb07e483129611
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:29 2007 +0200

    i2c: Cleanup the includes of <linux/i2c.h>
    
    Clean up the includes of <linux/i2c.h>. Only include this header file
    when we actually need it.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit f75803de6ae9aaebaf096d4590b40503c896eca7
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:29 2007 +0200

    i2c-nforce2: Add support for the MCP61 and MCP65
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Hans-Frieder Vogt <hfvogt@gmx.net>

commit cacf2269b6cde2ff2c29a13dff5ce6886ff1dc73
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:29 2007 +0200

    i2c-parport: Optimize binary size
    
    Initialize the fields of the i2c_adapter structure individually,
    rather than copying a whole static template structure. This shaves
    off 474 bytes or 14% (on i386) from the binary size.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 3c4bb241d34ee3d9ab87aad265734885385f179b
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:29 2007 +0200

    i2c-algo-bit: Emulate SMBus block read
    
    Now that i2c-core lets the i2c bus drivers emulate the SMBus block read
    and SMBus block process call transaction types, let's implement that in
    the popular i2c bit-banging driver. This will also act as a reference
    implementation for other bus drivers which want to do the same.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 209d27c3b1676c0497108f0642c51a08b98a7856
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:29 2007 +0200

    i2c: Emulate SMBus block read over I2C
    
    Let the I2C bus drivers emulate the SMBus Block Read and Block Process
    Call transactions if they wish. This requires to define a new message
    flag, which i2c-core will use to let the underlying I2C bus driver
    know that the first received byte will specify the length of the read
    message.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 1ecac07abaca1a4084d0259d4a15b55188852a2e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c-algo-bit: Always send a stop condition before leaving
    
    The i2c-algo-bit driver doesn't behave well on read errors: it'll
    bail out without even sending a stop condition on the bus, so the bus
    will be stuck. So make sure that we always send a stop condition on
    the bus before we leave. The best way to make sure is to always send
    it at the end of function bit_xfer.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit ef2c8321f5a27ff9ecdae1ee587430cafa495586
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c: Rename dev_to_i2c_adapter()
    
    Rename dev_to_i2c_adapter() as to_i2c_adapter(), since the previous
    syntax was a surprising and needless difference from normal naming
    conventions in Linux.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 16ffadfc680bd0683dc88573c1d72cbf1e27030e
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c: Class attribute cleanup
    
    This patch is a minor cleanup/code shrink, using class infrastructure
    in i2c-core to manage the i2c_adapter attribute.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 2096b956d24c4b5950b808fc23b218425d79ebb1
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c: Shrink struct i2c_client
    
    This shrinks the size of "struct i2c_client" by 40 bytes:
    
     - Substantially shrinks the string used to identify the chip type
     - The "flags" don't need to be so big
     - Removes some internal padding
    
    It also adds kerneldoc for that struct, explaining how "name" is really a
    chip type identifier; it's otherwise potentially confusing.
    
    Because the I2C_NAME_SIZE symbol was abused for both i2c_client.name
    and for i2c_adapter.name, this needed to affect i2c_adapter too.  The
    adapters which used that symbol now use the more-obviously-correct
    idiom of taking the size of that field.
    
    JD: Shorten i2c_adapter.name from 50 to 48 bytes while we're here, to
    avoid wasting space in padding.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit 4ad4eac60667f7c321faae28a3437f7a8b3d17cb
Author: David Brownell <david-b@pacbell.net>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c: i2c_register_driver() cleanup
    
    Minor cleanup in i2c_register_driver():  use list_for_each_entry().
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit b31366f4394f7b1e8e1726ba049f294934db4495
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:28 2007 +0200

    i2c: i2c_adapter devices need no driver
    
    Kill i2c_adapter_driver as it doesn't make sense and it prevents
    further i2c-core cleanups. i2c_adapter devices are virtual devices
    (ex-class devices) and as such they don't need a driver.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit fccb56e4d82132ac15359efc9e419371e4533437
Author: Jean Delvare <khali@linux-fr.org>
Date:   Tue May 1 23:26:27 2007 +0200

    i2c: Kill i2c_adapter.class_dev
    
    Kill i2c_adapter.class_dev. Instead, set the class of i2c_adapter.dev
    to i2c_adapter_class, so that a symlink will be created for every
    i2c_adapter in /sys/class/i2c-adapter.
    
    The same change must be mirrored to i2c-isa as it duplicates some
    of the i2c-core functionalities.
    
    User-space tools and libraries might need some adjustments. In
    particular, libsensors from lm_sensors 2.10.3 or later is required for
    proper discovery of i2c adapter names after this change.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>

commit d6444514b89098284099c17b9f168ef6236d3e8f
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
Date:   Tue May 1 10:13:46 2007 -0500

    [VOYAGER] add smp alternatives
    
    It's about time voyager had them
    
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit 9d0e59a34116f5ee48efc9a397fb09aaedc3b2f0
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Mon Apr 30 09:57:40 2007 -0600

    [VOYAGER] Use modern techniques to setup and teardown low identiy mappings.
    
    This is a trivial and hopefully obviously correct patch to setup
    and teardown the identity mappings the way the rest of arch/i386
    does.
    
    My new page table setup code will break some assumptions below so
    this is my attempt to keep voyager working.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit f3402a4e52fc1bdfc386a7f512e6e384cd69ecad
Author: Christoph Hellwig <hch@infradead.org>
Date:   Sun Apr 22 20:30:43 2007 +0100

    [VOYAGER] Convert the monitor thread to use the kthread API
    
    full kthread conversion on the voyager power switch handling thread.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit 9f483519be82420e308b9a90a96a9c62f28032ae
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
Date:   Mon Apr 30 11:30:10 2007 -0500

    [VOYAGER] clockevents driver: bring voyager in to line
    
    The irq0 timer interrupt should be initiallised identically with
    mach-default.
    
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit 2feae2158a96aa5e02ca2e630896e6f553c36dc0
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
Date:   Mon Apr 30 11:27:25 2007 -0500

    [VOYAGER] clockevents: correct boot cpu is zero assumption
    
    This isn't true for voyager, so alter setup_pit_timer() to initialise
    the cpumask from the current processor id (which should be the boot
    processor) rather than defaulting to zero.
    
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit d3af5abe9a809becbe4b413144b607844560d445
Author: Tony Lindgren <tony@atomide.com>
Date:   Tue May 1 16:36:00 2007 +0200

    mmc-omap: Clean up omap set_ios and make MMC_POWER_ON work
    
    Move divisor calculation into a separate function and re-arrange the
    init order to make MMC_POWER_ON work.
    
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 46a6730e3ff9add5089ddd007f998b97fb4e8571
Author: Tony Lindgren <tony@atomide.com>
Date:   Tue May 1 16:34:16 2007 +0200

    mmc-omap: Fix omap to use MMC_POWER_ON
    
    As discussed earlier on LKML:
    
    http://lkml.org/lkml/2006/5/4/44
    
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 3647afcec11f2fcfc6269e513ff97fec1374d1b8
Author: Arnaud Patard <arnaud.patard@rtp-net.org>
Date:   Tue May 1 16:18:36 2007 +0200

    mmc-omap: add missing '\n'
    
    This patch add a missing '\n' at the end of the 'cover is open' string
    in mmc_omap_switch_handler().
    
    Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit d97956f86bec90ab131b9f1af60c0e686198d45e
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue May 1 16:14:29 2007 +0200

    mmc: make tifm_sd_set_dma_data() static
    
    This patch makes the needlessly global tifm_sd_set_dma_data() static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit bd766312618d2ecc85bce663f95faec601447ecb
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue May 1 16:11:57 2007 +0200

    mmc: remove old card states
    
    Remove card states that no longer make any sense.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 6abaa0c9fec563538f2a28a682af8c89bb9b125c
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue May 1 16:00:02 2007 +0200

    mmc: support unsafe resume of cards
    
    Since many have the system root on MMC/SD we must allow some foot
    shooting when it comes to resume.
    
    We cannot detect if a card is removed and reinserted during suspend,
    so the safe approach would be to assume it was, avoiding potential
    filesystem corruption. This will of course not work if you cannot
    release the card before suspend.
    
    This commit adds a compile time option that makes the MMC layer
    assume the card wasn't touched if it is redetected upon resume.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 89a73cf52ba2ae4402c53487b71ec4475544f139
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue May 1 15:08:30 2007 +0200

    mmc: separate out reading EXT_CSD
    
    Separate the reading and decoding of the EXT_CSD register with the
    actions taken on it.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 1addfcdbe4b23a20f28a097c2469d9f0c21bef23
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue May 1 14:46:08 2007 +0200

    mmc: break apart switch function
    
    Break apart the SD switch function into one that reads the capabilities
    and one that acts on them.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 55556da01284af8c2174b786b3eca8e11301b656
Author: Philip Langdale <philipl@overt.org>
Date:   Fri Mar 16 19:39:00 2007 -0700

    MMC: Fix handling of low-voltage cards
    
    Fix handling of low voltage MMC cards.
    
    The latest MMC and SD specs both agree that support for
    low-voltage operations is indicated by bit 7 in the OCR.
    The MMC spec states that the low voltage range is
    1.65-1.95V while the SD spec leaves the actual voltage
    range undefined - meaning that there is still no such
    thing as a low voltage SD card.
    
    However, an old Sandisk spec implied that bits 7.0
    represented voltages below 2.0V in 1V or 0.5V increments,
    and the code was accordingly written with that expectation.
    
    This confusion meant that host drivers attempting to support
    the typical low voltage (1.8V) would set the wrong bits in
    the host OCR mask (usually bits 5 and/or 6) resulting in the
    the low voltage mode never being used.
    
    This change corrects the low voltage range and adds sanity
    checks on the reserved bits (0-6) and for SD cards that
    claim to support low-voltage operations.
    
    Signed-off-by: Philip Langdale <philipl@overt.org>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 27c78b372d05e47bbd059c9bb003c6d716abff54
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 09:41:19 2007 -0500

    [libata reset-seq] build and merge fixes
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 31daabda16063b64a99a526242add727601e43c3
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Feb 2 16:50:52 2007 +0900

    libata: reimplement reset sequencing
    
    libata previously depended upon waits in prereset to get resets after
    hotplug right for both spin up and device ready wait.  This was
    necessary both for reliablity and speed as reset was likely to fail if
    initiated too early and each try usually took more than 30secs to
    fail.  Previous patches fixed the reliability part by fixing status
    and SCR handling in resets.  This patch remedies the speed part by
    improving reset sequencing.
    
    Prereset waiting timeout is adjusted to 10s because spinup wait is
    replaced by reset sequencing and !BSY wait is not as important as
    before.  During boot or module loading where the drive is already
    fully spun up, !BSY wait succeeds immediately, so 10s should be enough
    in most cases.  It matters after hotplugging or other error
    conditions, but in those cases, !BSY wait in prereset simply can't be
    relied upon due to the varied and weird behaviors ATA controllers and
    devices show.
    
    Reset is now driven by ata_eh_reset_timeouts[] table which contains
    timeouts for each reset try.  The first reset can be softreset but the
    following ones are always hardreset if available.  Each timeout
    defines deadline for the reset try.  If a reset try fails, reset is
    retried with the next timeout till the end of the timeout table is
    reached.  If a reset try fails before the timeout with error, libata
    waits till the deadline of the failed try before retrying.
    
    IOW, the timeout table defines timetable of reset tries such that the
    n'th try always begins at least after the sum of all previous timeouts
    has passed.  The current timetable defines 4 tries and takes around 1
    minute.
    
    @0	: First try.  This should succeed most of the time during boot.
    @10	: 10s is enough to spin up most consumer harddrives.  Give it
    	  another shot.
    @20	: 20s should spin up > 99% of working drives.  This has 30s
    	  timeout for retarded devices needing long idleness post reset.
    @55	: Final try with 5s timeout just in case.
    
    The above timetable is trade off between not annoying the device too
    much with frequent resets and taking reasonable amount of time in most
    cases.  Some controllers may do better with shorter timeouts while
    others may fare better with longer but we just can't rely upon LLD
    writers to test each controller with wide variety of devices using
    various scenarios.  We need default behavior which reasonably fits
    most cases.
    
    I've tested the above timetable on a dozen SATA controllers and a few
    PATA controllers with about a dozen different drives from all major
    vendors and 4 different ODDs from three different vendors for both
    boot and hotplug (if available) cases.
    
    Boot probing is not affected unless the device is broken in which
    cases new code gives up on the port after a minute rather than five or
    nine minutes.  When hotplugging, most devices get detected on the
    first or second try.  Multi-platter drives with long spin up time
    which sometimes took > 40 secs with the original code, now usually
    comes up during the second try and at least right after the third try
    @20.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit b8cffc6ad8c000410186815b7bcc6b76ef1bbb13
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Feb 2 16:50:52 2007 +0900

    libata: improve ata_std_prereset()
    
    This patch updates ata_std_prereset() as follows.
    
    * Don't fail on phy resume failure.  Just whine and continue.  Failure
      from prereset makes libata abort whole reset sequence and give up
      the port, so prereset() should be best effort.  This is more
      important with the coming EH updates as prereset() will be called
      with shorter timeout.
    
    * If ata_wait_ready() fails, whine and request hardreset instead.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9b89391cc861b8a1105551909eb66c024fe18ab2
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Feb 2 16:50:52 2007 +0900

    libata: improve 0xff status handling
    
    For PATA, 0xff status indicates empty port.  For SATA, it depends on
    how the controller emulates status register.  On some controllers,
    0xff is used to represent broken link or certain stage during reset.
    
    libata currently deals SATA the same.  This hasn't caused any problem
    because problematic situations usually only occur after hotplug or
    other link disruption events and libata blindly waited for the device
    to spin up and settle after hotplug giving the link and device
    whatever time to go through those stages.
    
    libata is going to replace unconditional spinup wait with generic
    timed sequence of resets, so not only getting 0xff handling right for
    SATA is, well, the right thing to do, it's much more important now.
    
    This patch makes the following changes.
    
    * Make ata_bus_softreset() return -ENODEV if any of its wait fails
      due to 0xff status.
    
    * Fail soft/hardreset if status wait returns -ENODEV indicating 0xff
      status while SStatus says the link is online.  e.g. Reset fails if
      status is 0xff after reset when SStatus reports the linke is online.
      If SCR registers are not available, everything is the same as
      before.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d4b2bab4f26345ea1803feb23ea92fbe3f6b77bc
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Feb 2 16:50:52 2007 +0900

    libata: add deadline support to prereset and reset methods
    
    Add @deadline to prereset and reset methods and make them honor it.
    ata_wait_ready() which directly takes @deadline is implemented to be
    used as the wait function.  This patch is in preparation for EH timing
    improvements.
    
    * ata_wait_ready() never does busy sleep.  It's only used from EH and
      no wait in EH is that urgent.  This function also prints 'be
      patient' message automatically after 5 secs of waiting if more than
      3 secs is remaining till deadline.
    
    * ata_bus_post_reset() now fails with error code if any of its wait
      fails.  This is important because earlier reset tries will have
      shorter timeout than the spec requires.  If a device fails to
      respond before the short timeout, reset should be retried with
      longer timeout rather than silently ignoring the device.
    
      There are three behavior differences.
    
      1. Timeout is applied to both devices at once, not separately.  This
         is more consistent with what the spec says.
    
      2. When a device passes devchk but fails to become ready before
         deadline.  Previouly, post_reset would just succeed and let
         device classification remove the device.  New code fails the
         reset thus causing reset retry.  After a few times, EH will give
         up disabling the port.
    
      3. When slave device passes devchk but fails to become accessible
         (TF-wise) after reset.  Original code disables dev1 after 30s
         timeout and continues as if the device doesn't exist, while the
         patched code fails reset.  When this happens, new code fails
         reset on whole port rather than proceeding with only the primary
         device.
    
      If the failing device is suffering transient problems, new code
      retries reset which is a better behavior.  If the failing device is
      actually broken, the net effect is identical to it, but not to the
      other device sharing the channel.  In the previous code, reset would
      have succeeded after 30s thus detecting the working one.  In the new
      code, reset fails and whole port gets disabled.  IMO, it's a
      pathological case anyway (broken device sharing bus with working
      one) and doesn't really matter.
    
    * ata_bus_softreset() is changed to return error code from
      ata_bus_post_reset().  It used to return 0 unconditionally.
    
    * Spin up waiting is to be removed and not converted to honor
      deadline.
    
    * To be on the safe side, deadline is set to 40s for the time being.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4be34c99a2f3aa90fa42e62c0918f07afb8a645b
Author: Philip Langdale <philipl@overt.org>
Date:   Sun Mar 11 17:15:15 2007 -0700

    MMC: Consolidate voltage definitions
    
    Consolidate the list of available voltages.
    
    Up until now, a separate set of defines has been
    used for host->vdd than that used for the OCR
    voltage mask values. Having two sets of defines
    allows them to get out of sync and the current
    sets are already inconsistent with one claiming
    to describe ranges and the other specific voltages.
    
    Only the SDHCI driver uses the host->vdd defines and
    it is easily fixed to use the OCR defines.
    
    Signed-off-by: Philip Langdale <philipl@overt.org>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 7ea239d9e6d6993469a6a8ca83ff23834dfc3fce
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sun Dec 31 00:11:32 2006 +0100

    mmc: add bus handler
    
    Delegate protocol handling to "bus handlers". This allows the core to
    just handle the task of arbitrating the bus. Initialisation and
    pampering of cards is now done by the different bus handlers.
    
    This design also allows MMC and SD (and later SDIO) to be more cleanly
    separated, allowing easier maintenance.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit b2670b1c6ddd54be4a0f72f853122510ea5ef285
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue May 1 13:35:19 2007 +0200

    wbsd: check for data opcode earlier
    
    Move the check for supported data opcodes to the beginning of the
    request function to avoid wedging the card.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit da7fbe58d2d347e95af699ddf04d885be6362bbe
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sun Dec 24 22:46:55 2006 +0100

    mmc: Separate out protocol ops
    
    Move protocol operations and definitions into their own files
    in an effort to separate protocol handling and bus
    arbitration more clearly.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit aaac1b470bd0dccb30912356617069dc6199cc80
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Wed Feb 28 15:33:10 2007 +0100

    mmc: Move core functions to subdir
    
    Create a "core" subdirectory to house the central bus handling
    functions.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit b855885e3b60cf6f9452848712a62517b94583eb
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Wed Jan 3 19:47:29 2007 +0100

    mmc: deprecate mmc bus topology
    
    The classic MMC bus was defined as multi card bus
    system, which is reflected in the design in the MMC
    layer.
    
    When SD showed up, the bus topology was abandoned
    and a star topology (one card per host) was mandated.
    MMC version 4 has followed this, officially deprecating
    the bus topology.
    
    As we do not have any known users of the bus
    topology we can remove support for it. This will
    simplify the code and rectify some incorrect
    assumptions in the newer additions.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit b5af25bee2de2f6cd1ac74ba737cbc4f3d303e5d
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Apr 28 17:30:50 2007 +0200

    mmc: remove card upon suspend
    
    Suspending MMC/SD cards (versus removing and readding them) is an
    inherently unsafe operation and has even been broken for some time.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit d2b46f66b4b342be07a4194bd5e82384d07e470d
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Apr 28 16:52:12 2007 +0200

    mmc: allow suspended block driver to be removed
    
    Make sure we don't deadlock when removing a suspended block
    queue, something that might happen if the card is removed during
    suspend.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 3b91e5507cddaca53bccf1524ff11a0ac5c85531
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sun Feb 11 20:43:19 2007 +0100

    mmc: Flush pending detects on host removal
    
    Make sure we kill of any pending detection runs when the host
    is removed instead of when it is freed. Also add some debugging
    to make sure the driver doesn't queue up more detection after it
    has removed the host.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 1c6a0718f0bfdab0d9b7da5f7b74f38a0058c03a
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sun Feb 11 19:57:36 2007 +0100

    mmc: Move host and card drivers to subdirs
    
    Clean up the drivers/mmc directory by moving card and host drivers
    into subdirectories.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 98ac2162699f7e9880683cb954891817f20b607c
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Dec 23 20:03:02 2006 +0100

    mmc: Move queue functions to mmc_block
    
    The mmc block queue functions are tailored for the mmc_block
    driver, so move those functions into that module.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 29041dbe199b0dff392bf1b9d634357da0b3208f
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Feb 10 15:52:23 2007 +0100

    mmc: Move "present" marking
    
    The "present" state indicates that the card is a registered device, so
    it is more clear to put it together with the actual registration.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit f74d132cec60b686bce1f284822c1a496700bd3c
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Fri Feb 9 22:49:31 2007 +0100

    mmc: Move OCR bit defines
    
    All host drivers were #include:ing mmc/protocol.h just to
    get access to the OCR bit defines. Move these to host.h instead.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 9c2c0af950345e63ef86f28eca44333a1e1e709b
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue Dec 26 15:25:58 2006 +0100

    mmc: add type field to cards
    
    Split out the type of card into its own field as it hardly
    qualifies as a state.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 85a18ad93ec66888d85758630019b10a84257f3c
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Feb 17 22:15:27 2007 +0100

    mmc: MMC sector based cards
    
    Support for MMC 4.2 sector based cards. This tweaks the init a
    bit and reads a new field out of the EXT_CSD.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit de85989511f3a0e15b04d18582b23d428d6ddbbd
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Sat Apr 28 14:59:35 2007 +0200

    mmc: use right timing mode constant
    
    Fix copy-n-paste error.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit c4030698029bb30d220fb0342a34280c629cee01
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sat Apr 28 14:21:10 2007 +0200

    tifm: add missing include for DMA_32BIT_MASK
    
    sparc64:
    
    drivers/misc/tifm_7xx1.c: In function `tifm_7xx1_probe':
    drivers/misc/tifm_7xx1.c:294: error: `DMA_32BIT_MASK' undeclared
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 91f8d0118a0e1f25f809f3fde5a7616a1eaabc2b
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 17:05:26 2007 +1000

    tifm: layout fixes, small changes to comments and printfs
    
    Cosmetic changes to the code.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 13cdf48ef15befbd36f8295091b9e0f9bd322963
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 17:05:25 2007 +1000

    tifm_sd: implement software scatter-gather
    
    It was found that delays associated with issue and completion of the commands
    severely limit performance of the new, fast SD cards. To alleviate this issue
    scatter-gather emulation in software is implemented for both dma and pio
    transfer modes. Non-block aligned and high memory sg entries are accounted
    for.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 5897d657b58efb244b1f82a912ee93e5141ed14c
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 17:05:24 2007 +1000

    tifm_sd: fix resume handler
    
    Resume should not explicitly check for media type. Instead, it may relay
    on success of socket initialization.
    Small changes are introduced to tifm_sd_initialize to make it more robust.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 72dc9d9619dd4682f4197e7a7f19af22fd6516a7
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 17:05:23 2007 +1000

    tifm_sd: replace command completion state machine with full checking
    
    State machine used to to track mmc command state was found to be fragile
    and unreliable, making many cards unusable. The safer solution is to perform
    all needed checks at every card event.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit dfef26d9aad4f983da232b259ee7f7faec479b2d
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:24 2007 +1000

    tifm_sd: merge dma and pio request processing paths
    
    To allow for switching of trasfer mode (dma/pio) on a per-request basis,
    pio and dma request issue and completion function are now merged.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 0007d4837ac94d672f313cfc462f879b5d06f221
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:23 2007 +1000

    tifm_sd: separate command flags, socket flags and register bit masks
    
    host->flags variable was hosting a collection of bits with different
    semantics. For clarity, hardware bit masks are now defined as macros,
    socket flags represented as bit fields and flags (now cmd_flags) only
    hosts command processing modifiers.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 592d372ae89dd5b43117cf5113a910f67f6e6a7e
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:22 2007 +1000

    tifm_sd: remove wait for power off on remove
    
    This wait was needed because of the mmc layer failure to wait for completion
    of all outstanding commands before host removal. It should be fixed now in
    the mmc layer.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit b039d4a187a4064c926159db063004377281b041
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:21 2007 +1000

    tifm_sd: remove tifm_sd_terminate function
    
    tifm_sd_terminate can only lawfully be called on device removal so it can be
    merged with tifm_sd_remove.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 4e64f223857b138e3474bedc967d51db25c414b3
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:20 2007 +1000

    tifm: add sysfs attribute for tifm devices
    
    A sysfs attribute reflecting current media type is added.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 88de1b2fed2bbe9eb1b7310195be84cf143efb4f
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:19 2007 +1000

    tifm_7xx1: fix adapter resume function
    
    Fixes to the adapter resume function to correctly handle all possible cases:
    1. Card is removed during suspend
    2. Card is inserted during suspend into previously empty socket
    3. Card is replaced during suspend by same or different media type card.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 2428a8fe2261e901e058d9ea8b6ed7e1b4268b79
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:18 2007 +1000

    tifm: move common device management tasks from tifm_7xx1 to tifm_core
    
    Some details of the device management (create, add, remove) are really
    belong to the tifm_core, as they are not hardware specific.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 6113ed73e61a13db9da48831e1b35788b7f837cc
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:17 2007 +1000

    tifm: move common adapter management tasks from tifm_7xx1 to tifm_core
    
    Some details of the adapter management (create, add, remove) are really
    belong to the tifm_core, as they are not hardware specific.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 342c0ec4859446140c0dc5d7d903bb3b3f0577cd
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:16 2007 +1000

    tifm_7xx1: improve card detection routine
    
    Remove unneeded conditions and change a sleeping regime a little in the
    card type detection routine.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 3540af8ffddcdbc7573451ac0b5cd57a2eaf8af5
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:15 2007 +1000

    tifm: replace per-adapter kthread with freezeable workqueue
    
    Freezeable workqueue makes sure that adapter work items (device insertions
    and removals) would be handled after the system is fully resumed. Previously
    this was achieved by explicit freezing of the kthread.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit e23f2b8a1a52c00f0150659eb0bfde3a73976ffe
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:14 2007 +1000

    tifm: simplify bus match and uevent handlers
    
    Remove code duplicating the kernel functionality and clean up data
    structures involved in driver matching.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 8dc4a61eca31dd45a9d45f9bc9c67d959f0f6cbd
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:13 2007 +1000

    tifm: use bus methods to handle probe/remove instead of driver ones.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 4552f0cbd45225f2c1cbadc224505f14f8749569
Author: Alex Dubov <oakad@yahoo.com>
Date:   Thu Apr 12 16:59:12 2007 +1000

    tifm: hide details of interrupt processing from socket drivers
    
    Instead of passing transformed value of adapter interrupt status to
    socket drivers, implement two separate callbacks - one for card events
    and another for dma events.
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 5721dbf217b073b40e31936781379ab2d17ea2ae
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Fri Apr 13 23:25:59 2007 +0200

    wbsd: remove block crc test
    
    Block completion interrupts occur faster than we can process
    them, so just ignore them competely.
    
    Commit also fixes up some incorrect register defines.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 976d9276c826d6b35e4a2478fd4978dbd63bdd6f
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Fri Apr 13 22:47:01 2007 +0200

    mmc: enforce correct sg list
    
    Now that we've fixed our only offender when it comes to strange sg
    list, add a check so that future users keep the sg list proper with
    regard to transfer size.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 14d836e7499c53a1f6a65086c3d11600e871a971
Author: Alex Dubov <oakad@yahoo.com>
Date:   Fri Apr 13 19:04:38 2007 +0200

    mmc: cull sg list to match mmc request size
    
    mmc layer may introduce additional (compared to block layer) limits on
    request size. Culling of the sg list to match adjusted request size
    simplifies the handling of such cases in the low level driver, allowing
    it to skip block count checks while processing sg entries.
    
    (fixes for wbsd and sdhci by Pierre Ossman)
    
    Signed-off-by: Alex Dubov <oakad@yahoo.com>
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

commit 37fde8ca6c60ea61f5e9d7cb877c25ac60e74167
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Tue May 1 09:51:39 2007 +0100

    [GFS2] Uncomment sprintf_symbol calling code
    
    Now that the patch from -mm has gone upstream, we can uncomment the code
    in GFS2 which uses sprintf_symbol.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
    Cc: Robert Peterson <rpeterso@redhat.com>

commit 617e82e10ccf96a13eb2efd5eac4abef44a87d02
Author: David Teigland <teigland@redhat.com>
Date:   Thu Apr 26 13:46:49 2007 -0500

    [DLM] lowcomms style
    
    Replace some printk with log_print, and fix some simple cases of lines
    over 80.  Also, return -ENOTCONN if lowcomms_start fails due to no local
    IP address being available.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit f391a4ead61e4510ff385815ddaf3c0777fbad1b
Author: akpm@linux-foundation.org <akpm@linux-foundation.org>
Date:   Wed Apr 25 21:08:02 2007 -0700

    [GFS2] printk warning fixes
    
    alpha:
    
    fs/gfs2/dir.c: In function 'gfs2_dir_read_leaf':
    fs/gfs2/dir.c:1322: warning: format '%llu' expects type 'long long unsigned int', but argument 3 has type 'sector_t'
    fs/gfs2/dir.c: In function 'gfs2_dir_read':
    fs/gfs2/dir.c:1455: warning: format '%llu' expects type 'long long unsigned int', but argument 3 has type '__u64'
    
    Cc: Steven Whitehouse <swhiteho@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit bf126aee6d54fe1e509846abf3b27aba84c6d7ce
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Fri Apr 20 09:18:30 2007 +0100

    [GFS2] Patch to fix mmap of stuffed files
    
    If a stuffed file is mmaped and a page fault is generated at some offset
    above the initial page, we need to create a zero page to hang the buffer
    heads off before we can unstuff the file. This is a fix for bz #236087
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 476c006be009d4121e401a9e9f49a3362a7a272f
Author: Josef Bacik <jwhiter@redhat.com>
Date:   Mon Apr 23 11:55:39 2007 -0400

    [GFS2] use lib/parser for parsing mount options
    
    This patch converts the mount option parsing to use the kernels lib/parser stuff
    like all of the other filesystems.  I tested this and it works well.  Thank you,
    
    Signed-off-by: Josef Bacik <jwhiter@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 30d3a2373f171e62e4032819f55fed2ec887d0b8
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Mon Apr 23 16:26:21 2007 +0100

    [DLM] Lowcomms nodeid range & initialisation fixes
    
    Fix a few range & initialization bugs in lowcomms.
    - max_nodeid is really the highest nodeid encountered, so all loops must include
    it in their iterations.
    - clean dlm_local_count & connection_idr so we can do a clean restart.
    - Remove a spurious BUG_ON
    
    Signed-Off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 2439fe50724e8693e8b933b3f8125d870bfbdb25
Author: Josef Bacik <jwhiter@redhat.com>
Date:   Thu Apr 19 17:59:05 2007 -0400

    [DLM] Fix dlm_lowcoms_stop hang
    
    When you attempt to release a lockspace in DLM, it will hang trying to down a
    semaphore that has already been downed.  The attached patch fixes the problem.
    
    Signed-off-by: Josef Bacik <jwhiter@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
    Cc: Patrick Caulfield <pcaulfie@redhat.com>

commit 7d3c1feb80913ba4253c3517d48b9b3741c44fc9
Author: David Teigland <teigland@redhat.com>
Date:   Thu Apr 19 10:30:41 2007 -0500

    [DLM] fix mode munging
    
    There are flags to enable two specialized features in the dlm:
    1. CONVDEADLK causes the dlm to resolve conversion deadlocks internally by
       changing the granted mode of locks to NL.
    2. ALTPR/ALTCW cause the dlm to change the requested mode of locks to PR
       or CW to grant them if the normal requested mode can't be granted.
    
    GFS direct i/o exercises both of these features, especially when mixed
    with buffered i/o.  The dlm has problems with them.
    
    The first problem is on the master node. If it demotes a lock as a part of
    converting it, the actual step of converting the lock isn't being done
    after the demotion, the lock is just left sitting on the granted queue
    with a granted mode of NL.  I think the mistaken assumption was that the
    call to grant_pending_locks() would grant it, but that function naturally
    doesn't look at locks on the granted queue.
    
    The second problem is on the process node.  If the master either demotes
    or gives an altmode, the munging of the gr/rq modes is never done in the
    process copy of the lock, leaving the master/process copies out of sync.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 5f8820960cf4fb621483d4a37c24939ad831bfe7
Author: Robert Peterson <rpeterso@redhat.com>
Date:   Wed Apr 18 11:41:11 2007 -0500

    [GFS2] lockdump improvements
    
    The patch below consists of the following changes (in code order):
    
    1. I fixed a minor compiler warning regarding the printing of
       a kernel symbol address.
    2. I implemented a suggestion from Dave Teigland that moves
       the debugfs information for gfs2 into a subdirectory so
       we can easily expand our use of debugfs in the future.
       The current code keeps the glock information in:
       /debug/gfs2/<fs>
       With the patch, the new code keeps the glock information in:
       /debug/gfs2/<fs>/glock
       That will allow us to create more debugfs files in the future.
    3. This fixes a bug whereby a failed mount attempt causes the
       debugfs file to not be deleted.  Failed mount attempts should
       always clean up after themselves, including deleting the
       debugfs file and/or directory.
    
    Signed-off-by: Bob Peterson <rpeterso@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit bdd19a22f85a7039e01accd8717eaec4addd9dfd
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Wed Apr 18 09:38:42 2007 +0100

    [GFS2] Patch to detect corrupt number of dir entries in leaf and/or inode blocks
    
    This patch detects when the number of entries in a leaf block or inode
    block (in the case of stuffed directories) is corrupt and informs the
    user. It prevents us from running off the end of the array thats been
    allocated for the sorting in this case,
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 7a0079d9e3fe8826475a08785f3d348c4b509774
Author: Robert Peterson <rpeterso@redhat.com>
Date:   Tue Apr 17 11:37:11 2007 -0500

    [GFS2] bz 236008: Kernel gpf doing cat /debugfs/gfs2/xxx (lock dump)
    
    This is for Bugzilla Bug 236008: Kernel gpf doing cat /debugfs/gfs2/xxx
    (lock dump) seen at the "gfs2 summit".  This also fixes the bug that caused
    garbage to be printed by the "initialized at" field.  I apologize for the
    kludge, but that code will all be ripped out anyway when the official
    sprint_symbol function becomes available in the Linux kernel.  I also
    changed some formatting so that spaces are replaced by proper tabs.
    
    Signed-off-by: Robert Peterson <rpeterso@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 8fa1de386f4d72f0710b389ccf96308fef87df78
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed Apr 4 17:25:29 2007 +0200

    [DLM] fs/dlm/ast.c should #include "ast.h"
    
    Every file should include the headers containing the prototypes for
    it's global functions.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 6ed7257b46709e87d79ac2b6b819b7e0c9184998
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Tue Apr 17 15:39:57 2007 +0100

    [DLM] Consolidate transport protocols
    
    This patch consolidates the TCP & SCTP protocols for the DLM into a single file
    and makes it switchable at run-time (well, at least before the DLM actually
    starts up!)
    
    For RHEL5 this patch requires Neil Horman's patch that expands the in-kernel
    socket API but that has already been twice ACKed so it should be OK.
    
    The patch adds a new lowcomms.c file that replaces the existing lowcomms-sctp.c
    & lowcomms-tcp.c files.
    
    Signed-off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit fc7c44f03d95f20b5446d06f5bb9605cddd53203
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Tue Apr 10 09:40:19 2007 +0100

    [DLM] Remove redundant assignment
    
    This patch removes a redundant (and incorrect) assignment from compat_output
    
    Signed-Off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit a43a49066d36612f3bb46653cdb265a89c235eff
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Mon Apr 2 10:48:17 2007 +0100

    [GFS2] Fix bz 234168 (ignoring rgrp flags)
    
    Ths following patch makes GFS2 use the rgrp flags properly. Although
    there are also separate flags for both data and metadata as well, I've
    not implemented these as there seems little use for them. On the
    otherhand, the "noalloc" flag is generally useful for future changes we
    might which to make, so this ensures that we interpret it correctly.
    
    In addition I fixed the comment above the function which was incorrect.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit ce03f12b37c0bd81ad707d3642241cc55c944711
Author: David Teigland <teigland@redhat.com>
Date:   Mon Apr 2 12:12:55 2007 -0500

    [DLM] change lkid format
    
    A lock id is a uint32 and is used as an opaque reference to the lock.  For
    userland apps, the lkid is passed up, through libdlm, as the return value
    from a write() on the dlm device.  This created a problem when the high
    bit was 1, making the lkid look like an error.  This is fixed by changing
    how the lkid is composed.  The low 16 bits identified the hash bucket for
    the lock and the high 16 bits were a per-bucket counter (which eventually
    hit 0x8000 causing the problem).  These are simply swapped around; the
    number of hash table buckets is far below 0x8000, making all lkid's
    positive when viewed as signed.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 72c2be776bd6eec5186e316e6d9dd4aab78d314d
Author: David Teigland <teigland@redhat.com>
Date:   Fri Mar 30 15:06:16 2007 -0500

    [DLM] interface for purge (2/2)
    
    Add code to accept purge commands from userland.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 8499137d4ef1829281e04838113b6b09a0bf1269
Author: David Teigland <teigland@redhat.com>
Date:   Fri Mar 30 15:02:40 2007 -0500

    [DLM] add orphan purging code (1/2)
    
    Add code for purging orphan locks.  A process can also purge all of its
    own non-orphan locks by passing a pid of zero.  Code already exists for
    processes to create persistent locks that become orphans when the process
    exits, but the complimentary capability for another process to then purge
    these orphans has been missing.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 7e4dac33594468153c38b5c94d8ebcafb0e0a68d
Author: David Teigland <teigland@redhat.com>
Date:   Mon Apr 2 09:06:41 2007 -0500

    [DLM] split create_message function
    
    This splits the current create_message() function into two parts so that
    later patches can call the new lower-level _create_message() function when
    they don't have an rsb struct.  No functional change in this patch.
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit f01963f2648cfd708ee8d521b3737cfa55ea8795
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Mon Apr 2 10:03:24 2007 +0100

    [GFS2] Set drop_count to 0 (off) by default
    
    This sets the drop_count to 0 by default which is a better default
    for most people.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit b9af8a788ade3435b53667873774b5366cf73f58
Author: David Teigland <teigland@redhat.com>
Date:   Wed Mar 28 11:08:04 2007 -0500

    [GFS2] use log_error before LM_OUT_ERROR
    
    We always want to see the details of the error returned to gfs, but
    log_debug is often turned off, so use log_error (printk).
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit ef0c2bb05f40f9a0cd2deae63e199bfa62faa7fa
Author: David Teigland <teigland@redhat.com>
Date:   Wed Mar 28 09:56:46 2007 -0500

    [DLM] overlapping cancel and unlock
    
    Full cancel and force-unlock support.  In the past, cancel and force-unlock
    wouldn't work if there was another operation in progress on the lock.  Now,
    both cancel and unlock-force can overlap an operation on a lock, meaning there
    may be 2 or 3 operations in progress on a lock in parallel.  This support is
    important not only because cancel and force-unlock are explicit operations
    that an app can use, but both are used implicitly when a process exits while
    holding locks.
    
    Summary of changes:
    
    - add-to and remove-from waiters functions were rewritten to handle situations
      with more than one remote operation outstanding on a lock
    
    - validate_unlock_args detects when an overlapping cancel/unlock-force
      can be sent and when it needs to be delayed until a request/lookup
      reply is received
    
    - processing request/lookup replies detects when cancel/unlock-force
      occured during the op, and carries out the delayed cancel/unlock-force
    
    - manipulation of the "waiters" (remote operation) state of a lock moved under
      the standard rsb mutex that protects all the other lock state
    
    - the two recovery routines related to locks on the waiters list changed
      according to the way lkb's are now locked before accessing waiters state
    
    - waiters recovery detects when lkb's being recovered have overlapping
      cancel/unlock-force, and may not recover such locks
    
    - revert_lock (cancel) returns a value to distinguish cases where it did
      nothing vs cases where it actually did a cancel; the cancel completion ast
      should only be done when cancel did something
    
    - orphaned locks put on new list so they can be found later for purging
    
    - cancel must be called on a lock when making it an orphan
    
    - flag user locks (ENDOFLIFE) at the end of their useful life (to the
      application) so we can return an error for any further cancel/unlock-force
    
    - we weren't setting COMP/BAST ast flags if one was already set, so we'd lose
      either a completion or blocking ast
    
    - clear an unread bast on a lock that's become unlocked
    
    Signed-off-by: David Teigland <teigland@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 032067270295cfca11975c0f7b467244aa170c14
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Mon Mar 26 09:56:00 2007 +0100

    [DLM] fix coverity-spotted stupidity
    
    Replacement patch to remove redundant code rather than moving it around.
    
    Signed-Off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 04b933f27bc8e7f3f6423020cec58a4eab3bb7a7
Author: Robert Peterson <rpeterso@redhat.com>
Date:   Fri Mar 23 17:05:15 2007 -0500

    [GFS2] Red Hat bz 228540: owner references
    
    In Testing the previously posted and accepted patch for
    https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=228540
    I uncovered some gfs2 badness.  It turns out that the current
    gfs2 code saves off a process pointer when glocks is taken
    in both the glock and glock holder structures.  Those
    structures will persist in memory long after the process has
    ended; pointers to poisoned memory.
    
    This problem isn't caused by the 228540 fix; the new capability
    introduced by the fix just uncovered the problem.
    
    I wrote this patch that avoids saving process pointers
    and instead saves off the process pid.  Rather than
    referencing the bad pointers, it now does process lookups.
    There is special code that makes the output nicer for
    printing holder information for processes that have ended.
    
    This patch also adds a stub for the new "sprint_symbol"
    function that exists in Andrew Morton's -mm patch set, but
    won't go into the base kernel until 2.6.22, since it adds
    functionality but doesn't fix a bug.
    
    Signed-off-by: Bob Peterson <rpeterso@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 172e045a7fcc3ee647fa70dbd585a3c247b49cb2
Author: Benjamin Marzinski <bmarzins@redhat.com>
Date:   Fri Mar 23 14:51:56 2007 -0600

    [GFS2] flush the log if a transaction can't allocate space
    
    This is a fix for bz #208514. When GFS2 frees up space, the freed blocks
    aren't available for reuse until the resource group is successfully written
    to the ondisk journal. So in rare cases, GFS2 operations will fail, saying
    that the filesystem is out of space, when in reality, you are just waiting for
    a log flush. For instance, on a 1Gig filesystem, if I continually write 10 Mb
    to a file, and then truncate it, after a hundred interations, the write will
    fail with -ENOSPC, even though the filesystem is just 1% full.
    
    The attached patch calls a log flush in these cases.  I tested this patch
    fairly heavily to check if there were any locking issues that I missed, and
    it seems to work just fine. Also, this patch only does the log flush if
    get_local_rgrp makes a complete loop of resource groups without skipping
    any do to locking issues. The code would be slightly simpler if it just always
    did the log flush after the first failed pass, and you could only ever have
    to go through the loop twice, instead of up to three times. However, I guessed
    that failing to find a rg simply do to locking issues would be common enough
    to skip the log flush in that case, but I'm not certain that this is the right
    way to go. Either way, I don't suppose this code will be hit all that often.
    
    Signed-off-by: Benjamin E. Marzinski <bmarzins@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 6883562588bc6c70776ecc396ee7eda36c2c8da9
Author: Benjamin Marzinski <bmarzins@redhat.com>
Date:   Fri Mar 23 09:05:12 2007 +0000

    [GFS2] Fix log entry list corruption
    
    When glock_lo_add and rg_lo_add attempt to add an element to the log, they
    check to see if has already been added before locking the log. If another
    process adds that element to the log in this window between the check and
    locking the log, the element will be added to the list twice. This causes
    the log element list to become corrupted in such a way that the log element
    can never be successfully removed from the list. This patch pulls the
    list_empty() check inside the log lock, to remove this window.
    
    Signed-off-by: Benjamin E. Marzinski <bmarzins@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit f35ac346bc48b2086aa94f031baf1f6237a89de6
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Sun Mar 18 17:04:15 2007 +0000

    [GFS2] Speed up lock_dlm's locking (move sprintf)
    
    The following patch speeds up lock_dlm's locking by moving the sprintf
    out from the lock acquisition path and into the lock creation path. This
    reduces the amount of CPU time used in acquiring locks by a fair amount.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
    Acked-by: David Teigland <teigland@redhat.com>

commit 254da030dfb1b13d42d07e4292a4790d88c6874f
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Wed Mar 21 09:23:53 2007 +0000

    [DLM] Don't delete misc device if lockspace removal fails
    
    Currently if the lockspace removal fails the misc device associated with a
    lockspace is left deleted. After that there is no way to access the orphaned
    lockspace from userland.
    
    This patch recreates the misc device if th dlm_release_lockspace fails. I
    believe this is better than attempting to remove the lockspace first because
    that leaves an unattached device lying around. The potential gap in which there
    is no access to the lockspace between removing the misc device and recreating it
    is acceptable ... after all the application is trying to remove it, and only new
    users of the lockspace will be affected.
    
    Signed-Off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 420d2a1028b906f24e836e37089a6ad55ab1848f
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Sun Mar 18 16:05:27 2007 +0000

    [GFS2] Fix a bug on i386 due to evaluation order
    
    Since gcc didn't evaluate the last two terms of the expression in
    glock.c:1881 as a constant expression, it resulted in an error on
    i386 due to the lack of a 64bit divide instruction. This adds some
    brackets to fix the problem.
    
    This was reported by Andrew Morton.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
    Cc: Andrew Morton <akpm@linux-foundation.org>

commit 3b8249f6178cb2b68b9d683587797270125cc06a
Author: Steven Whitehouse <swhiteho@redhat.com>
Date:   Fri Mar 16 09:40:31 2007 +0000

    [GFS2] Fix bz 224480 and cleanup glock demotion code
    
    This patch prevents the printing of a warning message in cases where
    the fs is functioning normally by handing off responsibility for
    unlinked, but still open inodes, to another node for eventual deallocation.
    Also, there is now an improved system for ensuring that such requests
    to other nodes do not get lost. The callback on the iopen lock is
    only ever called when i_nlink == 0 and when a node is unable to deallocate
    it due to it still being in use on another node. When a node receives
    the callback therefore, it knows that i_nlink must be zero, so we mark
    it as such (in gfs2_drop_inode) in order that it will then attempt
    deallocation of the inode itself.
    
    As an additional benefit, queuing a demote request no longer requires
    a memory allocation. This simplifies the code for dealing with gfs2_holders
    as it removes one special case.
    
    There are two new fields in struct gfs2_glock. gl_demote_state is the
    state which the remote node has requested and gl_demote_time is the
    time when the request came in. Both fields are only valid when the
    GLF_DEMOTE flag is set in gl_flags.
    
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 1de913909263ba7f7054debeda1b79771a7233db
Author: Josef Whiter <jwhiter@redhat.com>
Date:   Mon Mar 12 16:55:07 2007 -0500

    [GFS2] Fix bz 231380, unlock page before dequeing glocks in gfs2_commit_write
    
    If we are writing a file, and in the middle of writing the file
    another node attempts to get a shared lock on that file (by doing a du for
    example) the process doing the writing will hang waiting on lock_page.  The
    reason for this is because when we have waiters on a exclusive glock, we will go
    through and flush out all dirty pages associated with that inode and release the
    lock.  The problem is that when we flush the dirty pages, we could hit a page
    that we have locked durring the generic_file_buffered_write part of this
    operation.  This patch unlocks the page before we go to dequeue the lock and
    locks it immediatly afterwards, since generic_file_buffered_write needs the page
    locked when the commit_write is completed.  This patch resolves the problem,
    however if somebody sees a better way to do this please don't hesistate to yell.
    
    Signed-off-by: Josef Whiter <jwhiter@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 89adc934f3f96600e7f31447426c7e99d62c5460
Author: Patrick Caulfield <pcaulfie@redhat.com>
Date:   Tue Mar 13 17:08:45 2007 +0000

    [DLM] Fix uninitialised variable in receiving
    
    The length of the second element of the kvec array was not initialised before
    being added to the first one. This could cause invalid lengths to be passed to
    kernel_recvmsg
    
    Signed-Off-By: Patrick Caulfield <pcaulfie@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 5c7342d894973636f03270673e1fb7b908a421a8
Author: Josef Whiter <jwhiter@redhat.com>
Date:   Wed Mar 7 17:09:10 2007 -0500

    [GFS2] fix bz 231369, gfs2 will oops if you specify an invalid mount option
    
    If you specify an invalid mount option when trying to mount a gfs2 filesystem,
    gfs2 will oops.  The attached patch resolves this problem.
    
    Signed-off-by: Josef Whiter <jwhiter@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 7c52b166c588c98cf3d2b2e7e6a0468a98e84d0d
Author: Robert Peterson <rpeterso@redhat.com>
Date:   Fri Mar 16 10:26:37 2007 +0000

    [GFS2] Add gfs2_tool lockdump support to gfs2 (bz 228540)
    
    The attached patch resolves bz 228540.  This adds the capability
    for gfs2 to dump gfs2 locks through the debugfs file system.
    This used to exist in gfs1 as "gfs_tool lockdump" but it's missing from
    gfs2 because all the ioctls were stripped out.  Please see the bugzilla
    for more history about the fix.  This patch is also attached to the bugzilla
    record.
    
    The patch is against Steve Whitehouse's latest nmw git tree kernel
    (2.6.21-rc1) and has been tested on system trin-10.
    
    Signed-off-by: Robert Peterson <rpeterso@redhat.com>
    Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

commit 83672d392f7bcf556f7920d6715e4174d9373ee0
Author: Neil Brown <neilb@suse.de>
Date:   Mon Feb 26 12:48:25 2007 +1100

    NFS: Fix directory caching problem - with test case and patch.
    
    Try running this script in an NFS mounted directory (Client relatively
    recent - 2.6.18 has the problem as does 2.6.20).
    
    ------------------------------------------------------
    #!/bin/bash
    #
    # This script will produce the following errormessage from tar:
    #
    #   tar: newdir/innerdir/innerfile: file changed as we read it
    
    # create dirs
    rm -rf nfstest
    mkdir -p nfstest/dir/innerdir
    
    # create files (should not be empty)
    echo "Hello World!" >nfstest/dir/file
    echo "Hello World!" >nfstest/dir/innerdir/innerfile
    
    # problem only happens if we sleep before chmod
    sleep 1
    
    # change file modes
    chmod -R a+r nfstest
    
    # rename dir
    mv nfstest/dir nfstest/newdir
    
    # tar it
    tar -cf nfstest/nfstest.tar -C nfstest newdir
    
    # restore old dir name
    mv nfstest/newdir nfstest/dir
    --------------------------------------------------------
    
    What happens:
    
    The 'chmod -R' does a readdir_plus in each directory and the results
    get cached in the page cache.  It then updates the ctime on each file
    by one second.  When this happens, the post-op attributes are used to
    update the ctime stored on the client to match the value in the kernel.
    
    The 'mv' calls shrink_dcache_parent on the directory tree which
    flushes all the dentries (so a new lookup will be required) but
    doesn't flush the inodes or pagecache.
    
    The 'tar' does a readdir on each directory, but (in the case of
    'innerdir' at least) satisfies it from the pagecache and uses the
    READDIRPLUS data to update all the inodes.  In the case of
    'innerdir/innerfile', the ctime is out of date.
    
    'tar' then calls 'lstat' on innerdir/innerfile getting an old ctime.
    It then opens the file (triggering a GETATTR), reads the content, and
    then calls fstat to see if anything has changed.  It finds that ctime
    has changed and so complains.
    
    The problem seems to be that the cache readdirplus info is kept around
    for too long.
    
    My patch below discards pagecache data for directories when
    dentry_iput is called on them.  This effectively removes the symptom
    which convinces me that I correctly understand the problem.  However
    I'm not convinced that is a proper solution, as there could easily be
    other races that trigger the same problem without being affected by
    this 'fix'.
    
    One possibility would be to require that readdirplus pagecache data be
    only used *once* to instantiate an inode.  Somehow it should then be
    invalidated so that if the dentry subsequently disappears, it will
    cause a new request to the server to fill in the stat data.
    
    Another possibility is to compare the cache_change_attribute on the
    inode with something similar for the readdirplus info and reject the
    info from readdirplus if it is too old.
    
    I haven't tried to implement these and would value other opinions
    before I do.
    
    Thanks,
    NeilBrown
    
    
    Signed-off-by: Neil Brown <neilb@suse.de>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 1f4eab7e7c1d90dcd8ca4d7c064ee78dfbb345eb
Author: Neil Brown <neilb@suse.de>
Date:   Mon Apr 16 09:35:27 2007 +1000

    NFS: Set meaningful value for fattr->time_start in readdirplus results.
    
    Don't use uninitialsed value for fattr->time_start in readdirplus results.
    
    The 'fattr' structure filled in by nfs3_decode_direct does not get a
    value for ->time_start set.
    Thus if an entry is for an inode that we already have in cache,
    when nfs_readdir_lookup calls nfs_fhget, it will call nfs_refresh_inode
    and may update the inode with out-of-date information.
    
    Directories are read a page at a time, so each page could have a
    different timestamp that "should" be used to set the time_start for
    the fattr for info in that page.  However storing the timestamp per
    page is awkward.  (We could stick in the first 4 bytes and only read 4092
    bytes, but that is a bigger code change than I am interested it).
    
    This patch ignores the readdir_plus attributes if a readdir finds the
    information already in cache, and otherwise sets ->time_start to the time
    the readdir request was sent to the server.
    
    It might be nice to store - in the directory inode - the time stamp for
    the earliest readdir request that is still in the page cache, so that we
    don't ignore attribute data that we don't have to.  This patch doesn't do
    that.
    
    Signed-off-by: Neil Brown <neilb@suse.de>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 74dd34e6e8bb127ff4c182423154b294729b663b
Author: Steve Dickson <steved@redhat.com>
Date:   Sat Apr 14 17:01:15 2007 -0400

    NFS: Added support to turn off the NFSv3 READDIRPLUS RPC.
    
    READDIRPLUS can be a performance hindrance when the client is working with
    large directories. In addition, some servers still have bugs in their
    implementations (e.g. Tru64 returns wrong values for the fsid).
    
    Add a mount flag to enable users to turn it off at mount time following the
    implementation in Apple's NFS client.
    
    Signed-off-by: Steve Dickson <steved@redhat.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 00a6e7bbf990e3a5e59a9a1e6a68e99c94fe001c
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:33 2007 -0400

    SUNRPC: RPC client should retry with different versions of rpcbind
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 4c2eaf073f0cc2b5bf593b8133c078b9d9406e95
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:27 2007 -0400

    SUNRPC: remove old portmapper
    
    net/sunrpc/pmap_clnt.c has been replaced by net/sunrpc/rpcb_clnt.c.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit df8b172a8880521396d2048ecef7e75df43b5bc4
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:22 2007 -0400

    NFS: switch NFSROOT to use new rpcbind client
    
    It is arguable whether NFSROOT will support IPv6, and thus whether
    rpcb_getport_external needs to support rpcbind versions greater than 2.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 260800142071a3a33e4523c7578358c6e29c0f53
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:16 2007 -0400

    SUNRPC: switch the RPC server to use the new rpcbind registration API
    
    Eventually this interface will support versions 3 and 4 of the rpcbind
    protocol, which will allow the Linux RPC server to register services on
    IPv6 addresses.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit e9b1c9c98c051f49a76dcd76f914c02653aecccb
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:10 2007 -0400

    SUNRPC: switch socket-based RPC transports to use rpcbind
    
    Now that we have a version of the portmapper that supports versions 3 and 4
    of the rpcbind protocol, use it for new RPC client connections over
    sockets.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit a509050bd3b8e0aa269c2241aa10d74ca7701e2f
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:48:04 2007 -0400

    SUNRPC: introduce rpcbind: replacement for in-kernel portmapper
    
    Introduce a replacement for the in-kernel portmapper client that supports
    all 3 versions of the rpcbind protocol.  This code is not used yet.
    
    Original code by Groupe Bull updated for the latest kernel, with multiple
    bug fixes.
    
    Note that rpcb_clnt.c does not yet support registering via versions 3 and
    4 of the rpcbind protocol.  That is planned for a later patch.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit c5a4dd8b7c15927a8fbff83171b57cad675a79b9
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:47:58 2007 -0400

    SUNRPC: Eliminate side effects from rpc_malloc
    
    Currently rpc_malloc sets req->rq_buffer internally.  Make this a more
    generic interface:  return a pointer to the new buffer (or NULL) and
    make the caller set req->rq_buffer and req->rq_bufsize.  This looks much
    more like kmalloc and eliminates the side effects.
    
    To fix a potential deadlock, this patch also replaces GFP_NOFS with
    GFP_NOWAIT in rpc_malloc.  This prevents async RPCs from sleeping outside
    the RPC's task scheduler while allocating their buffer.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 2bea90d43a050bbc4021d44e59beb34f384438db
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:47:53 2007 -0400

    SUNRPC: RPC buffer size estimates are too large
    
    The RPC buffer size estimation logic in net/sunrpc/clnt.c always
    significantly overestimates the requirements for the buffer size.
    A little instrumentation demonstrated that in fact rpc_malloc was never
    allocating the buffer from the mempool, but almost always called kmalloc.
    
    To compute the size of the RPC buffer more precisely, split p_bufsiz into
    two fields; one for the argument size, and one for the result size.
    
    Then, compute the sum of the exact call and reply header sizes, and split
    the RPC buffer precisely between the two.  That should keep almost all RPC
    buffers within the 2KiB buffer mempool limit.
    
    And, we can finally be rid of RPC_SLACK_SPACE!
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 511d2e8855a065c8251d0c140ebc353854f1929e
Author: Chuck Lever <chuck.lever@oracle.com>
Date:   Thu Mar 29 16:47:47 2007 -0400

    NLM: Shrink the maximum request size of NLM4 requests
    
    NLM version 4 requests estimate the call and reply header sizes rather
    conservatively, using the very maximum size allowed in the protocol even
    though Linux always uses only a small fraction of the allowable space.
    
    Reduce the size of caller and lock arguments to conserve RPC buffer space
    while XDR encoding NLM4 arguments.  Add compile-time checks to ensure the
    hostname string won't overflow NLM protocol maximums.
    
    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit ca52fec152282ef73e5e882b847b36b1febbb1c6
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Tue Apr 17 17:22:13 2007 -0400

    NFS: Use pgoff_t in structures and functions that pass page cache offsets
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 724c439c204b12a3537b71289fb4c0a42c3aa566
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Tue Apr 17 17:22:13 2007 -0400

    NFS: Clean up nfs_sync_mapping_wait()
    
    It has no business touching wbc->pages_skipped.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 8d5658c949e6d89edc579a1f112aeee3bc232a8e
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Tue Apr 10 09:26:35 2007 -0400

    NFS: Fix a buffer overflow in the allocation of struct nfs_read/writedata
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit c63c7b051395368573779c8309aa5c990dcf2f96
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Mon Apr 2 19:29:52 2007 -0400

    NFS: Fix a race when doing NFS write coalescing
    
    Currently we do write coalescing in a very inefficient manner: one pass in
    generic_writepages() in order to lock the pages for writing, then one pass
    in nfs_flush_mapping() and/or nfs_sync_mapping_wait() in order to gather
    the locked pages for coalescing into RPC requests of size "wsize".
    
    In fact, it turns out there is actually a deadlock possible here since we
    only start I/O on the second pass. If the user signals the process while
    we're in nfs_sync_mapping_wait(), for instance, then we may exit before
    starting I/O on all the requests that have been queued up.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 8b09bee3083897e375bd0bf9d60f48daedfab3e0
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Mon Apr 2 18:48:28 2007 -0400

    NFS: Cleanup for nfs_readpages()
    
    Do the coalescing of read requests into block sized requests at start of
    I/O as we scan through the pages instead of going through a second pass.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit bcb71bba7e64f0442d0ca339d7d3117a7060589f
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Mon Apr 2 18:48:28 2007 -0400

    NFS: Another cleanup of the read/write request coalescing code
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit d8a5ad75cc4d577987964e37a4c43b1c648c201e
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Mon Apr 2 18:48:28 2007 -0400

    NFS: Cleanup the coalescing code
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 91e59c368c6ba5eed0369a085c42c9f270b97aa8
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Fri Apr 6 13:12:46 2007 -0400

    NFS: Don't wait for congestion in nfs_update_request()
    
    It is redundant, and will interfere with the call to
    balance_dirty_pages_ratelimited_nr in generic_file_write().
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 1a0ba9ae485c5fd17d0bff2f14d9dd75b8985593
Author: Amnon Aaronsohn <amnonaar@gmail.com>
Date:   Mon Apr 9 22:05:26 2007 -0700

    NFS: statfs error-handling fix
    
    The nfs statfs function returns a success code on error, and fills the
    output buffer with invalid values.  The attached patch makes it return a
    correct error code instead.
    
    Signed-off-by: Amnon Aaronsohn <amnonaar@gmail.com>
    Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
     (Modified patch to reinstate the dprintk())

commit d585158b608248a6ba8ae75e234672e048d3fde9
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:   Mon Apr 30 22:17:02 2007 -0700

    NFS: Fix nfs_set_page_dirty()
    
    Be more careful about testing page->mapping.
    
    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

commit 84767d00a8fd54dd97866561f6e2ee246c8e1cdc
Author: Roman Moravcik <roman.moravcik@gmail.com>
Date:   Tue May 1 00:39:13 2007 -0400

    Input: gpio_keys - add support for switches (EV_SW)
    
    Signed-off-by: Roman Moravcik <roman.moravcik@gmail.com>
    Signed-off-by: Paul Sokolovsky <pmiscml@gmail.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit dc87c3985e9b442c60994308a96f887579addc39
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Mon Apr 30 17:43:48 2007 -0700

    libata: honour host controllers that want just one host
    
    The Marvell IDE interface on my machine would hit a BUG_ON() in
    lib/iomem.c because it was calling ata_pci_init_one() specifying just a
    single port on the host, but that would actually end up trying to
    initialize two ports, the second one with bogus information.
    
    This fixes "ata_pci_init_one()" so that it actually passes down the
    n_ports variable that it got from the low-level driver to the host
    allocation routine ("ata_host_alloc_pinfo()"), which results in the ATA
    layer actually having the correct port number information.
    
    And in order to make it all work, I also needed to fix a few places that
    had incorrectly hard-coded the fact that a host always had exactly two
    ports (both ata_pci_init_bmdma() and ata_request_legacy_irqs() would
    just always iterate over both ports).
    
    Acked-by: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 60be4b5966e22040f97db9dada72841bf90479d1
Author: Steve Wise <swise@opengridcomputing.com>
Date:   Thu Apr 26 15:21:15 2007 -0500

    RDMA/cxgb3: Initialize cpu_idx field in cpl_close_listserv_req message
    
    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 1860cdf802310e4a988e0b8fca41cc97da36f779
Author: Steve Wise <swise@opengridcomputing.com>
Date:   Thu Apr 26 15:21:09 2007 -0500

    RDMA/cxgb3: Fail qp creation if the requested max_inline is too large
    
    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 4a97d47ef7946cf31b76945c3199b0b5cad6a8ed
Author: Steve Wise <swise@opengridcomputing.com>
Date:   Thu Apr 26 15:21:02 2007 -0500

    RDMA/cxgb3: Fix TERM codes
    
    Fix TERMINATE layer, type, and ecode values based on
    conformance testing.
    
    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 347fcfbed261fdd11f46fa03d524e1bddddab3a6
Author: Michael S. Tsirkin <mst@dev.mellanox.co.il>
Date:   Mon Apr 30 17:30:28 2007 -0700

    IPoIB/cm: Fix error handling in ipoib_cm_dev_open()
    
    If skb allocation fails when we start the device, we call
    ipoib_cm_dev_stop() even though ipoib_cm_dev_open() did not run to
    completion, so we pass an invalid pointer to ib_destroy_cm_id and get
    an oops.
    
    Fix by clearing cm.id on error, and testing it in cm_dev_stop().
    This fixes <https://bugs.openfabrics.org/show_bug.cgi?id=561>
    
    Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 6b66b2da1e821181a001c00b04a807724ad803cd
Author: Robert Walsh <rjwalsh@pathscale.com>
Date:   Fri Apr 27 21:07:23 2007 -0700

    IB/ipath: Don't corrupt pending mmap list when unmapped objects are freed
    
    Fix the pending mmap code so it doesn't corrupt the list of pending
    mmaps and crash the machine when pending mmaps are destroyed without
    first being mapped.  Also, remove an unused variable, and use standard
    kernel lists instead of our own homebrewed linked list implementation
    to keep the pending mmap list.
    
    Signed-off-by: Robert Walsh <robert.walsh@qlogic.com>
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 9ba6d5529dd919b442eedf5bef1dd28aca2ee9fe
Author: Michael S. Tsirkin <mst@mellanox.co.il>
Date:   Thu Apr 12 18:10:25 2007 +0300

    IB/mthca: Work around kernel QP starvation
    
    With mthca, RC QPs can starve each other and even UD QPs on the same
    hardware schedule queue.  As a result, userspace MPI can starve
    e.g. IPoIB traffic, with netdev watchdog warnings getting printed out,
    and TCP connections getting stuck or failing.
    
    Reduce the chance of this happening by using three separate hardware
    schedule queues: one for userspace RC QPs, one for kernel RC QPs, and
    one for all other QPs.
    
    Signed-off-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit c3af664adbe06803931dbc7a3c8588982d72fac1
Author: Ralph Campbell <ralphc@pathscale.com>
Date:   Fri Apr 27 11:08:40 2007 -0700

    IB/ipath: Don't put QP in timeout queue if waiting to send
    
    This fixes a problem which causes too many RC timeouts and
    retransmits.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 35ff032e65ab5cc03bbba46cefece7376c7c562f
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Fri Apr 27 11:11:11 2007 -0700

    IB/ipath: Don't call spin_lock_irq() from interrupt context
    
    This patch fixes the problem reported by Bernd Schubert <bs@q-leap.de>
    with kernel debug options enabled:
    
        BUG: at kernel/lockdep.c:1860 trace_hardirqs_on()
    
    This was caused by using spin_lock_irq()/spin_unlock_irq() from
    interrupt context.  Fix all the places that might be called from
    interrupts to use spin_lock_irqsave()/spin_unlock_irqrestore().
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 14e38ac823b7b25e3f4e563c182f93fde78167d6
Author: David Rientjes <rientjes@google.com>
Date:   Mon Apr 30 15:09:56 2007 -0700

    pm: include EIO from errno-base.h
    
    For backwards compatibility, call_platform_enable_wakeup() can return 0
    instead of -EIO since we aren't guaranteed to have errno defined.
    
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: David Rientjes <rientjes@google.com>
    Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 11443ec7d9286dd25663516436a14edfb5f43857
Author: Jeremy Fitzhardinge <jeremy@goop.org>
Date:   Mon Apr 30 15:09:56 2007 -0700

    Add kvasprintf()
    
    Add a kvasprintf() function to complement kasprintf().
    
    No in-tree users yet, but I have some coming up.
    
    [akpm@linux-foundation.org: EXPORT it]
    Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Cc: Keir Fraser <keir@xensource.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 9684e51cd157607f0727c1550e7df6e31de40808
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 30 15:09:55 2007 -0700

    power management: force pm_ops.valid callback to be assigned
    
    This patch changes the docs and behaviour from "all states valid" to "no
    states valid" if no .valid callback is assigned.  Users of pm_ops that only
    need mem sleep can assign pm_valid_only_mem without any overhead, others
    will require more elaborate callbacks.
    
    Now that all users of pm_ops have a .valid callback this is a safe thing to
    do and prevents things from getting messy again as they were before.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Looks-okay-to: Rafael J. Wysocki <rjw@sisk.pl>
    Cc: <linux-pm@lists.linux-foundation.org>
    Cc: Greg KH <greg@kroah.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit e8c9c502690efd24b7055bf608e7a3c34216848b
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 30 15:09:54 2007 -0700

    power management: implement pm_ops.valid for everybody
    
    Almost all users of pm_ops only support mem sleep, don't check in .valid and
    don't reject any others in .prepare so users can be confused if they check
    /sys/power/state, especially when new states are added (these would then
    result in s-t-r although they're supposed to be something different).
    
    This patch implements a generic pm_valid_only_mem function that is then
    exported for users and puts it to use in almost all existing pm_ops.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Cc: David Brownell <david-b@pacbell.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Cc: linux-pm@lists.linux-foundation.org
    Cc: Len Brown <lenb@kernel.org>
    Acked-by: Russell King <rmk@arm.linux.org.uk>
    Cc: Greg KH <greg@kroah.com>
    Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 11d77d0c01b80e44c7aceb21928508dafce774f9
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 30 15:09:53 2007 -0700

    power management: remove firmware disk mode
    
    This patch removes the firmware disk suspend mode which is the wrong approach,
    it is supposed to be used for implementing firmware-based disk suspend but
    cannot actually be used for that.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Cc: <linux-pm@lists.linux-foundation.org>
    Cc: David Brownell <david-b@pacbell.net>
    Cc: Len Brown <lenb@kernel.org>
    Acked-by: Russell King <rmk@arm.linux.org.uk>
    Cc: Greg KH <greg@kroah.com>
    Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit fe0c935a6cbf25d72a27c7a345df8a2151de0b74
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 30 15:09:51 2007 -0700

    rework pm_ops pm_disk_mode, kill misuse
    
    This patch series cleans up some misconceptions about pm_ops.  Some users of
    the pm_ops structure attempt to use it to stop the user from entering suspend
    to disk, this, however, is not possible since the user can always use
    "shutdown" in /sys/power/disk and then the pm_ops are never invoked.  Also,
    platforms that don't support suspend to disk simply should not allow
    configuring SOFTWARE_SUSPEND (read the help text on it, it only selects
    suspend to disk and nothing else, all the other stuff depends on PM).
    
    The pm_ops structure is actually intended to provide a way to enter
    platform-defined sleep states (currently supported states are "standby" and
    "mem" (suspend to ram)) and additionally (if SOFTWARE_SUSPEND is configured)
    allows a platform to support a platform specific way to enter low-power mode
    once everything has been saved to disk.  This is currently only used by ACPI
    (S4).
    
    This patch:
    
    The pm_ops.pm_disk_mode is used in totally bogus ways since nobody really
    seems to understand what it actually does.
    
    This patch clarifies the pm_disk_mode description.
    
    It also removes all the arm and sh users that think they can veto suspend to
    disk via pm_ops; not so since the user can always do echo shutdown >
    /sys/power/disk, they need to find a better way involving Kconfig or such.
    
    ACPI is the only user left with a non-zero pm_disk_mode.
    
    The patch also sets the default mode to shutdown again, but when a new pm_ops
    is registered its pm_disk_mode is selected as default, that way the default
    stays for ACPI where it is apparently required.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Cc: David Brownell <david-b@pacbell.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Cc: <linux-pm@lists.linux-foundation.org>
    Cc: Len Brown <lenb@kernel.org>
    Acked-by: Russell King <rmk@arm.linux.org.uk>
    Cc: Greg KH <greg@kroah.com>
    Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
    Acked-by: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 1173a729fc3ce2fa0d698bd39be8ff7bf6c70bf1
Author: Jeff Mahoney <jeffm@suse.de>
Date:   Mon Apr 30 15:09:50 2007 -0700

    reiserfs: suppress lockdep warning
    
    We're getting lockdep warnings due to a post-2.6.21-rc7 bugfix.
    
    The xattr_sem can never be taken in the manner described. Internal inodes
    are protected by I_PRIVATE.  Add the appropriate annotation.
    
    Cc: <stable@kernel.org>
    Cc: "Antonino A. Daplas" <adaplas@pol.net>
    Cc: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 42e380832a6911c8a3173ee0172fbc0e4864d80b
Author: Robert Peterson <rpeterso@redhat.com>
Date:   Mon Apr 30 15:09:48 2007 -0700

    Extend print_symbol capability
    
    Today's print_symbol function dumps a kernel symbol with printk.  This
    patch extends the functionality of kallsyms.c so that the symbol lookup
    function may be used without the printk.  This is useful for modules that
    want to dump symbols elsewhere, for example, to debugfs.  I intend to use
    the new function call in the GFS2 file system (which will be a separate
    patch).
    
    [akpm@linux-foundation.org: build fix]
    [clameter@sgi.com: sprint_symbol should return length of string like sprintf]
    Signed-off-by: Robert Peterson <rpeterso@redhat.com>
    Cc: Rusty Russell <rusty@rustcorp.com.au>
    Cc: Roman Zippel <zippel@linux-m68k.org>
    Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
    Cc: Sam Ravnborg <sam@ravnborg.org>
    Acked-by: Paulo Marques <pmarques@grupopie.com>
    Signed-off-by: Christoph Lameter <clameter@sgi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit de34ed91c4ffa4727964a832c46e624dd1495cf5
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Apr 30 14:51:58 2007 -0700

    [UDP]: Do not allow specific bind when wildcard bind exists.
    
    When allocating local ports, do not allow a bind to a port
    with a specific local address when a bind to that port with
    a wildcard local address already exists.
    
    Noticed by Linus.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b7b5f487ab39bc10ed0694af35651a03d9cb97ff
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Apr 30 13:35:29 2007 -0700

    [IPV4] UDP: Fix endianness bugs in hashing changes.
    
    I accidently applied an earlier version of Eric Dumazet's patch, from
    March 21st.  His version from March 30th didn't have these bugs, so
    this just interdiffs to the correct patch.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4523cc3044d1bc7fcf3d7fee75d62bc76b8e1abb
Author: Steve French <sfrench@us.ibm.com>
Date:   Mon Apr 30 20:13:06 2007 +0000

    [CIFS] UID/GID override on CIFS mounts to Samba
    
    When CIFS Unix Extensions are negotiated we get the Unix uid and gid
    owners of the file from the server (on the Unix Query Path Info
    levels), but if the server's uids don't match the client uid's users
    were having to disable the Unix Extensions (which turned off features
    they still wanted).   The changeset patch allows users to override uid
    and/or gid for file/directory owner with a default uid and/or gid
    specified at mount (as is often done when mounting from Linux cifs
    client to Windows server).  This changeset also displays the uid
    and gid used by default in /proc/mounts (if applicable).
    
    Also cleans up code by adding some of the missing spaces after
    "if" keywords per-kernel style guidelines (as suggested by Randy Dunlap
    when he reviewed the patch).
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 2e4976206396274cf66590328c6913811c271495
Author: Mark Langsdorf <mark.langsdorf@amd.com>
Date:   Mon Apr 30 14:15:05 2007 -0500

    [CPUFREQ] Report the number of processors in PowerNow-k8 correctly
    
    The PowerNow! driver for Opteron reports the number of cores
    in the system, but claims to report the number of processors.
    Fix this minor cosmetic bug.
    
    Signed-off-by: Bhavana Nagendra <bhavana.nagendra@amd.com>
    Acked-by: Mark Langsdorf <mark.langsdorf@amd.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit b96e80e3237777e5d7994a720ab722eb8f7edc60
Author: David Rientjes <rientjes@google.com>
Date:   Mon Apr 30 07:34:37 2007 -0700

    [CPUFREQ] do not declare undefined functions
    
    fill_powernow_table_pstate() and fill_powernow_table_fidvid() are only
    defined and used for X86_POWERNOW_K8_ACPI.
    
    Signed-off-by: David Rientjes <rientjes@google.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 0293ca814b74e20e77cf719074ee15372204fc55
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
Date:   Mon Apr 30 11:24:05 2007 -0500

    [VOYAGER] add smp_call_function_single
    
    This apparently has msr users now, so add it to the voyager HAL
    
    Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

commit 7297824581755593535fc97d2c8b6c47e2dc2db6
Author: Eric Moore <eric.moore@lsi.com>
Date:   Wed Feb 7 16:51:40 2007 -0700

    [SCSI] fusion: fix domain validation loops
    
    After host reset, the device are programmed to default asyn narrow nego.
    We need to reprogram the parameter back to previous values.  If the host
    reset is called as a result of spi_dv_device() commands timing out, its
    possible to get into an infinite loop of dv to host reset.  This will
    prevent that case, as we merely program old values.  If host reset is
    called outside context of domain validation, then we can  call
    spi_dv_device.
    
    Signed-off-by: Eric Moore <Eric.Moore@lsi.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 4e08df3f91837656c36712f559d5ce8d80852760
Author: David Miller <davem@davemloft.net>
Date:   Mon Apr 16 12:37:43 2007 -0700

    [SCSI] qla2xxx: fix regression on sparc64
    
    Some sparc64 boxes don't have a valid NVRAM (from which the driver
    takes its WWPN) try to extract this from open firmware instead and if
    that fails, fall back to a default, which would be invalid if more
    than one machine on the same SAN does this, since two machines with
    the same WWPN would be illegal, so warn when taking this potentially
    invalid default.
    
    Tested on SunBlade-1000:
    
    Acked-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit fa543f005de175080640266ca536d45b4b0b1a61
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Sun Apr 29 09:33:22 2007 +0100

    [ARM] 4344/1: iop13xx: do not claim both uarts by default on iop342
    
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 84c981ffb371828ad6d1d220f076453b54734302
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Sun Apr 29 09:32:51 2007 +0100

    [ARM] 4343/1: iop13xx: automatically detect the internal bus frequency
    
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7dcad376e85b6eff56f29ee21e10e1fe855f1ed7
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Sun Apr 29 09:31:51 2007 +0100

    [ARM] 4341/1: iop13xx: fix i/o address translation
    
    PCI devices were being programmed with an incorrect base address value.
    This patch moves I/O space into a 16-bit addressable region and corrects
    the i/o offset.
    
    Much thanks to Martin Michlmayr for tracking this issue and testing
    debug patches.
    
    Cc: Martin Michlmayr <tbm@cyrius.com>
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 8903fcce9b91bab6bb98adbb57a4edfc372c8bff
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Sun Apr 29 09:31:21 2007 +0100

    [ARM] 4340/1: iop: fix iop_getttimeoffset
    
    Fix a typo which causes a necessary cpwait to be missed on iop3xx, Michael
    Brunner <mibru@gmx.de>
    
    Save a register in the assembly routine, rmk
    
    Cc: Lennert Buytenhek <kernel@wantstofly.org>
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 80787ebc2bbd8e675d8b9ff8cfa40f15134feebe
Author: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date:   Mon Apr 30 00:48:20 2007 -0700

    [IPV4] SNMP: Support OutMcastPkts and OutBcastPkts
    
    A transmitted IP multicast datagram should be counted as OutMcastPkts.
    By the same token, a transmitted IP broadcast datagram should be
    counted as OutBcastPkts.
    
    Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5506b54b36f067b9776935085c9f8e607b026b23
Author: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date:   Mon Apr 30 00:48:10 2007 -0700

    [IPV4] SNMP: Support InMcastPkts and InBcastPkts
    
    A received IP multicast datagram should be counted as InMcastPkts.
    By the same token, a received IP broadcast datagram should be
    counted as InBcastPkts.
    
    Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 704aed53b4e43bebfbd425cf95b66794a9cfa2c2
Author: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date:   Mon Apr 30 00:46:30 2007 -0700

    [IPV4] SNMP: Support InTruncatedPkts
    
    An IP datagram which is being discarded because the datagram frame
    didn't carry enough data should be counted as InTruncatedPkts.
    
    Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e91a47ebb130b90790c7a8c625ade4dcea246842
Author: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date:   Mon Apr 30 00:45:49 2007 -0700

    [IPV4] SNMP: Support InNoRoutes
    
    An IP datagram which is being discarded because of no routes in the
    forwarding path should be counted as InNoRoutes.
    
    Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 71ff6c0a857d11e70aec0c8f1e0d4ae9a45dd468
Author: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date:   Mon Apr 30 00:45:02 2007 -0700

    [SNMP]: Add definitions for {In,Out}BcastPkts
    
    The updated IP-MIB RFC (RFC4293) specifys new objects, InBcastPkts
    and OutBcastPkts. This adds definitions for them.
    
    Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d551e4541dd60ae53459f77a971f2d6043431f5f
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Mon Apr 30 00:42:20 2007 -0700

    [TCP] FRTO: RFC4138 allows Nagle override when new data must be sent
    
    This is a corner case where less than MSS sized new data thingie
    is awaiting in the send queue. For F-RTO to work correctly, a
    new data segment must be sent at certain point or F-RTO cannot
    be used at all. RFC4138 allows overriding of Nagle at that
    point.
    
    Implementation uses frto_counter states 2 and 3 to distinguish
    when Nagle override is needed.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 575ee7140dabe9b9c4f66f4f867039b97e548867
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Mon Apr 30 00:39:55 2007 -0700

    [TCP] FRTO: Delay skb available check until it's mandatory
    
    No new data is needed until the first ACK comes, so no need to check
    for application limitedness until then.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 157bfc25020f7eb731f94140e099307ade47299e
Author: Masahide NAKAMURA <nakam@linux-ipv6.org>
Date:   Mon Apr 30 00:33:35 2007 -0700

    [XFRM]: Restrict upper layer information by bundle.
    
    On MIPv6 usage, XFRM sub policy is enabled.
    When main (IPsec) and sub (MIPv6) policy selectors have the same
    address set but different upper layer information (i.e. protocol
    number and its ports or type/code), multiple bundle should be created.
    However, currently we have issue to use the same bundle created for
    the first time with all flows covered by the case.
    
    It is useful for the bundle to have the upper layer information
    to be restructured correctly if it does not match with the flow.
    
    1. Bundle was created by two policies
    Selector from another policy is added to xfrm_dst.
    If the flow does not match the selector, it goes to slow path to
    restructure new bundle by single policy.
    
    2. Bundle was created by one policy
    Flow cache is added to xfrm_dst as originated one. If the flow does
    not match the cache, it goes to slow path to try searching another
    policy.
    
    Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 34588b4c046c34773e5a1a962da7b78b05c4d1bd
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Mon Apr 30 00:57:33 2007 -0700

    [TCP]: Catch skb with S+L bugs earlier
    
    SACKED_ACKED and LOST are mutually exclusive with SACK, thus
    having their sum larger than packets_out is bug with SACK.
    Eventually these bugs trigger traps in the tcp_clean_rtx_queue
    with SACK but it's much more informative to do this here.
    
    Non-SACK TCP, however, could get more than packets_out duplicate
    ACKs which each increment sacked_out, so it makes sense to do
    this kind of limitting for non-SACK TCP but not for SACK enabled
    one. Perhaps the author had the opposite in mind but did the
    logic accidently wrong way around? Anyway, the sacked_out
    incrementer code for non-SACK already deals this issue before
    calling sync_left_out so this trapping can be done
    unconditionally.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6aaf47fa48d3c44280810b1b470261d340e4ed87
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Mon Apr 30 00:26:00 2007 -0700

    [PATCH] INET : IPV4 UDP lookups converted to a 2 pass algo
    
    Some people want to have many UDP sockets, binded to a single port but
    many different addresses. We currently hash all those sockets into a
    single chain.  Processing of incoming packets is very expensive,
    because the whole chain must be examined to find the best match.
    
    I chose in this patch to hash UDP sockets with a hash function that
    take into account both their port number and address : This has a
    drawback because we need two lookups : one with a given address, one
    with a wildcard (null) address.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 65def812ab25d7565756e5748d91e22e302197ee
Author: James Chapman <jchapman@katalix.com>
Date:   Mon Apr 30 00:21:02 2007 -0700

    [L2TP]: Add the ability to autoload a pppox protocol module.
    
    This patch allows a name "pppox-proto-nnn" to be used in modprobe.conf
    to autoload a PPPoX protocol nnn.
    
    Signed-off-by: James Chapman <jchapman@katalix.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2a12dcd71a5e0667b33f7b47bcac95c71d551840
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Thu Apr 26 14:41:53 2007 +0200

    [PATCH] elevator: elv_list_lock does not need irq disabling
    
    It's never grabbed from irq context, so just make it plain spin_lock().
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 5972511b77809cb7c9ccdb79b825c54921c5c546
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Mon Apr 2 10:06:42 2007 +0200

    [BLOCK] Don't pin lots of memory in mempools
    
    Currently we scale the mempool sizes depending on memory installed
    in the machine, except for the bio pool itself which sits at a fixed
    256 entry pre-allocation.
    
    There's really no point in "optimizing" this OOM path, we just need
    enough preallocated to make progress. A single unit is enough, lets
    scale it down to 2 just to be on the safe side.
    
    This patch saves ~150kb of pinned kernel memory on a 32-bit box.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 46f8914e53c28d0716c586e08a7c819d8ebb9d54
Author: James Chapman <jchapman@katalix.com>
Date:   Mon Apr 30 00:07:31 2007 -0700

    [SKB]: Introduce skb_queue_walk_safe()
    
    This patch provides a method for walking skb lists while inserting or
    removing skbs from the list.
    
    Signed-off-by: James Chapman <jchapman@katalix.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 597bc485d6906359ad667fc8ead5e5f0ede03a0a
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Tue Apr 24 21:23:53 2007 +0200

    cfq-iosched: speedup cic rb lookup
    
    We often lookup the same queue many times in succession, so cache
    the last looked up queue to avoid browsing the rbtree.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 4e521c27eee33cebd618c26649e2c93803004647
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Tue Apr 24 21:17:33 2007 +0200

    ll_rw_blk: add io_context private pointer
    
    To be used by as/cfq as they see fit.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 91fac317a34859986a2359a5a5c0e37dc17a9c3d
Author: Vasily Tarasov <vtaras@openvz.org>
Date:   Wed Apr 25 12:29:51 2007 +0200

    cfq-iosched: get rid of cfqq hash
    
    cfq hash is no more necessary.  We always can get cfqq from io context.
    cfq_get_io_context_noalloc() function is introduced, because we don't
    want to allocate cic on merging and checking may_queue.  In order to
    identify sync queue we've used hash key = CFQ_KEY_ASYNC. Since hash is
    eliminated we need to use other criterion: sync flag for queue is added.
    In all places where we dig in rb_tree we're in current context, so no
    additional locking is required.
    
    Advantages of this patch: no additional memory for hash, no seeking in
    hash, code is cleaner. But it is necessary now to seek cic in per-ioc
    rbtree, but it is faster:
    - most processes work only with few devices
    - most systems have only few block devices
    - it is a rb-tree
    
    Signed-off-by: Vasily Tarasov <vtaras@openvz.org>
    
    Changes by me:
    
    - Merge into CFQ devel branch
    - Get rid of cfq_get_io_context_noalloc()
    - Fix various bugs with dereferencing cic->cfqq[] with offset other
      than 0 or 1.
    - Fix bug in cfqq setup, is_sync condition was reversed.
    - Fix bug where only bio_sync() is used, we need to check for a READ too
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit cc19747977824ece6aa1c56a29e974fef5ec2b32
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Fri Apr 20 20:45:39 2007 +0200

    cfq-iosched: tighten queue request overlap condition
    
    For tagged devices, allow overlap of requests if the idle window
    isn't enabled on the current active queue.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 3ed9a2965c47636bc0ebafab31a39f1c105492ca
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Mon Apr 23 08:33:33 2007 +0200

    cfq-iosched: improve sync vs async workloads
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 1be92f2fc7b563db3a8909d2d1c6a6520aeca323
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Thu Apr 19 14:32:26 2007 +0200

    cfq-iosched: never allow an async queue idling
    
    We don't enable it by default, don't let it get enabled during
    runtime.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 20e493a8d03b3b2f51b619a453f7bbbebedd6bda
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Mon Apr 23 08:26:36 2007 +0200

    cfq-iosched: get rid of ->dispatch_slice
    
    We can track it fairly accurately locally, let the slice handling
    take care of the rest.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 6084cdda0ea4561feb68e00a8c50068bba98006d
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Mon Apr 23 08:25:00 2007 +0200

    cfq-iosched: don't pass unused preemption variable around
    
    We don't use it anymore in the slice expiry handling.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit edd75ffd92a5b7f6244431e8ff6c32b846f9ba86
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Thu Apr 19 12:03:34 2007 +0200

    cfq-iosched: get rid of ->cur_rr and ->cfq_list
    
    It's only used for preemption now that the IDLE and RT queues also
    use the rbtree. If we pass an 'add_front' variable to
    cfq_service_tree_add(), we can set ->rb_key to 0 to force insertion
    at the front of the tree.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 67e6b49e39e9b9bf5ce1351ef21dad391856183f
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Fri Apr 20 14:18:00 2007 +0200

    cfq-iosched: slice offset should take ioprio into account
    
    Use the max_slice-cur_slice as the multipler for the insertion offset.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 498d3aa2b4f791059acd8c942ee8fa15c2ce36c2
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Thu Apr 26 12:54:48 2007 +0200

    [PATCH] cfq-iosched: style cleanups and comments
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 67060e37994444ee9c0bd2413c8baa6cc58e7adb
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Wed Apr 18 20:13:32 2007 +0200

    cfq-iosched: sort IDLE queues into the rbtree
    
    Same treatment as the RT conversion, just put the sorted idle
    branch at the end of the tree.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 0c534e0a463e2eeafc97ba25ab23c14f3cdf2bdb
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Wed Apr 18 20:01:57 2007 +0200

    cfq-iosched: sort RT queues into the rbtree
    
    Currently CFQ does a linked insert into the current list for RT
    queues. We can just factor the class into the rb insertion,
    and then we don't have to treat RT queues in a special way. It's
    faster, too.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit cc09e2990fdd96d25fdbb9db6bc9b4c82d9e4a3c
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Thu Apr 26 12:53:50 2007 +0200

    [PATCH] cfq-iosched: speed up rbtree handling
    
    For cases where the rbtree is mainly used for sorting and min retrieval,
    a nice speedup of the rbtree code is to maintain a cache of the leftmost
    node in the tree.
    
    Also spotted in the CFS CPU scheduler code.
    
    Improved by Alan D. Brunelle <Alan.Brunelle@hp.com> by updating the
    leftmost hint in cfq_rb_first() if it isn't set, instead of only
    updating it on insert.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit d9e7620e60bc6648c3dcabbc8d1a320b69c846f9
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Fri Apr 20 14:27:50 2007 +0200

    cfq-iosched: rework the whole round-robin list concept
    
    Drawing on some inspiration from the CFS CPU scheduler design, overhaul
    the pending cfq_queue concept list management. Currently CFQ uses a
    doubly linked list per priority level for sorting and service uses.
    Kill those lists and maintain an rbtree of cfq_queue's, sorted by when
    to service them.
    
    This unfortunately means that the ionice levels aren't as strong
    anymore, will work on improving those later. We only scale the slice
    time now, not the number of times we service. This means that latency
    is better (for all priority levels), but that the distinction between
    the highest and lower levels aren't as big.
    
    The diffstat speaks for itself.
    
     cfq-iosched.c |  363 +++++++++++++++++---------------------------------
     1 file changed, 125 insertions(+), 238 deletions(-)
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 1afba0451c83cbff622a08f2d86fbb2e680dfd5f
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Tue Apr 17 12:47:55 2007 +0200

    cfq-iosched: minor updates
    
    - Move the queue_new flag clear to when the queue is selected
    - Only select the non-first queue in cfq_get_best_queue(), if there's
      a substantial difference between the best and first.
    - Get rid of ->busy_rr
    - Only select a close cooperator, if the current queue is known to take
      a while to "think".
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 6d048f5310aa2dda2b5acd947eab3598c25e269f
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Wed Apr 25 12:44:27 2007 +0200

    cfq-iosched: development update
    
    - Implement logic for detecting cooperating processes, so we
      choose the best available queue whenever possible.
    
    - Improve residual slice time accounting.
    
    - Remove dead code: we no longer see async requests coming in on
      sync queues. That part was removed a long time ago. That means
      that we can also remove the difference between cfq_cfqq_sync()
      and cfq_cfqq_class_sync(), they are now indentical. And we can
      kill the on_dispatch array, just make it a counter.
    
    - Allow a process to go into the current list, if it hasn't been
      serviced in this scheduler tick yet.
    
    Possible future improvements including caching the cfqq lookup
    in cfq_close_cooperator(), so we don't have to look it up twice.
    cfq_get_best_queue() should just use that last decision instead
    of doing it again.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 1e3335de05da3dfbe48b8caa03db1834a2133256
Author: Jens Axboe <jens.axboe@oracle.com>
Date:   Wed Feb 14 19:59:49 2007 +0100

    cfq-iosched: improve preemption for cooperating tasks
    
    When testing the syslet async io approach, I discovered that CFQ
    sometimes didn't perform as well as expected. cfq_should_preempt()
    needs to better check for cooperating tasks, so fix that by allowing
    preemption of an equal priority queue if the recently queued request
    is as good a candidate for IO as the one we are currently waiting for.
    
    Signed-off-by: Jens Axboe <jens.axboe@oracle.com>

commit 3d29cdff999c37b3876082278a8134a0642a02cd
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Sun Apr 29 23:43:06 2007 -0400

    Input: cobalt_btns - convert to use polldev library
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

commit 0dcd8073673115eeb67343787f244905f62532f2
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Sun Apr 29 23:42:45 2007 -0400

    Input: add skeleton for simple polled devices
    
    input-polldev provides a skeleton for supporting simple input
    devices that need to be periodically scanned or polled to
    detect changes in their state.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 85796e7d939a39787f10a643477298678fed85db
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Sun Apr 29 23:42:08 2007 -0400

    Input: update some documentation
    
    Input-programming.txt got out of sync with the latest changes in input
    core; let's refresh it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit fd013ce8d42a6667bea2a3c6dca37da8842ab2bf
Author: Eric Piel <eric.piel@tremplin-utc.net>
Date:   Sun Apr 29 23:41:53 2007 -0400

    Input: wistron - fix typo in keymap for Acer TM610
    
    This patch fixes typo that prevented PROG2 key from working
    on Acer Travelmate 610.
    
    Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit f900e9777fc9b65140cb9570438597bc8fae56ab
Author: Paul Mackerras <paulus@samba.org>
Date:   Mon Apr 30 13:03:39 2007 +1000

    [POWERPC] Remove dev_dbg redefinition in drivers/ps3/vuart.c
    
    Commit 404d5b185b4eb56d6fa2f7bd27833f8df1c38ce4 changed the definition
    of dev_dbg in the !DEBUG case from being a #define to being a static
    inline.  There was code in drivers/ps3/vuart.c to do exactly that,
    which fails to compile now.  This fixes it by removing the redefinition,
    as the redefinition is now superfluous.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 34f6d749c0a328817d5e36274e53121c1db734dc
Author: Dave Jiang <djiang@mvista.com>
Date:   Sat Apr 14 08:25:24 2007 +1000

    [POWERPC] remove kernel module option for booke wdt
    
    Remove option of making booke_wdt into a kernel module. This watchdog
    cannot be disabled. No point being a kernel module.
    
    Signed-off-by: Dave Jiang <djiang@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6ec367091a418dd6119e381758940a38b180089c
Author: John Rigby <jcrigby@gmail.com>
Date:   Sat Apr 7 08:57:37 2007 +1000

    [POWERPC] Avoid putting cpu node twice
    
    Call of_find_node_by_type with NULL instead of np
    so the cpu node does not get put twice.
    This was causing kref_put warnings.
    
    Signed-off-by: John Rigby <jrigby@freescale.com>
    Acked-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 057b184a007376562e905aa39f1ba352fb8d78b1
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Sun Apr 29 16:10:39 2007 +0000

    [POWERPC] Spinlock initializer cleanup
    
    Use DEFINE_SPINLOCK instead of initializing spinlocks to
    SPIN_LOCK_UNLOCKED, since DEFINE_SPINLOCK is better for lockdep.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f139efedb8d34904cf8ea30b174c3ee57204d114
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:07:05 2007 -0700

    [POWERPC] ppc4xx_sgdma needs dma-mapping.h
    
    For dma_alloc_*()
    
    Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 738925b6855f989d3f90a3330eeff34010309be3
Author: Srinivasa Ds <srinivasa@in.ibm.com>
Date:   Thu Apr 26 00:07:04 2007 -0700

    [POWERPC] arch/powerpc/sysdev/timer.c build fix
    
    arch/powerpc/sysdev/timer.c:51: error: variable `timer_sysclass' has
    initializer but incomplete type
    arch/powerpc/sysdev/timer.c:52: error: unknown field `resume' specified in initializer
    <etc>
    
    Signed-off-by: Srinivasa Ds <srinivasa@in.ibm.com>
    Acked-by: Johannes Berg <johannes@sipsolutions.net>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 12d371a69e6df96cd949af6bcb569e978e8f9d41
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Apr 29 16:29:08 2007 +1000

    [POWERPC] get_property cleanups
    
    Just another pass through arch/powerpc for old usages.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8d1cea6e1439a113b1f17eab9b4e2f0cfc24bbb0
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sun Apr 29 05:19:56 2007 +1000

    [POWERPC] Remove the unused HTDMSOUND driver
    
    Recently, someone fixed a syntax error in the HTDMSOUND driver
    introduced 4 years ago.
    
    Unfortunately not by trying to compile this driver for his hardware but
    by code inspection - which seems to be a strong indication that there
    are no users left for this OSS sound driver.
    
    This patch therefore removes it.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Dan Malek <dan@embeddedalley.com>
    Acked-by: Marcelo Tosatti <marcelo@kvack.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 4bd4aa1967628fa85a40936410acab6b8bbae6f5
Author: Olof Johansson <olof@lixom.net>
Date:   Sat Apr 28 12:49:03 2007 +1000

    [POWERPC] cell: cbe_cpufreq cleanup and crash fix
    
    cbe_cpufreq cleanups:
    
    * comment format
    * whitespace
    * don't init on non-cell platforms
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Acked-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d169d140944a67edd6f88f78b65b3117059f4380
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Sat Apr 28 08:00:03 2007 +1000

    [POWERPC] Declare enable_kernel_spe in a header
    
    This patch puts enable_kernel_spe into <asm-powerpc/system.h> along with
    enable_kernel_altivec etc.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8895ea483e144f8acca16adfff7c60a993e77b7d
Author: Mark A. Greer <mgreer@mvista.com>
Date:   Sat Apr 28 06:48:24 2007 +1000

    [POWERPC] Add dt_xlate_addr() to bootwrapper
    
    dt_xlate_reg() looks up the 'reg' property in the specified node
    to get the address and size to translate.  Add dt_xlate_addr()
    which is passed in the address and size to translate.
    
    Signed-off-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d818d7ec8bb06c1bc10270962e28fb0cbd93b64a
Author: Scott Wood <scottwood@freescale.com>
Date:   Sat Apr 28 06:32:15 2007 +1000

    [POWERPC] bootwrapper: CONFIG_ -> CONFIG_DEVICE_TREE
    
    A usage of CONFIG_DEVICE_TREE got accidentally truncated; this
    fix allows out-of-tree dts files to work.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9be4dcb606e647854760fafd0bb1cb3e1a804d16
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:05 2007 +1000

    [POWERPC] Don't define a custom bd_t for Xilixn Virtex based boards.
    
    Why create a platform specific board_info structure that is hacked
    together, ugly, and dangerous, when we've got a perfectly fine common
    board_info structure that is hacked-together, ugly and dangerous.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 30fea61fd01955cc35c6a63260b374d7a6d12c8b
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:04 2007 +1000

    [POWERPC] Add sane defaults for Xilinx EDK generated xparameters files
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8b01653ab01eebc781c5a375ff336d0837f30c4e
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:03 2007 +1000

    [POWERPC] Add uartlite boot console driver for the zImage wrapper
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8c38fc2b7429b26105fe244890c8d5ab3043f099
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:02 2007 +1000

    [POWERPC] Stop using ppc_sys for Xilinx Virtex boards
    
    The arch/ppc/syslib/ppc_sys.c infrastructure does not work well for the
    virtex ports.  Move the ml300 and ml403 board ports over to use the new
    virtex_devices infrastructure.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d26cd57071b4358bcf3a9140a90b38514c7f345e
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:01 2007 +1000

    [POWERPC] New registration for common Xilinx Virtex ppc405 platform devices
    
    Currently virtex support in mainline make use of the infrastructure in
    arch/ppc/syslib/ppc_sys.c for registering common devices on virtex ppc405
    platforms.  The ppc_sys.c code is not well suited to the dynamic nature of
    FPGA designs and makes adding new board ports more complex.  This patch
    adds a new listing of common devices which does not depend on the ppc_sys.c
    infrastructure.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5ff084f21da25ffcc5e0cb0293a0ea588cb46272
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:50:00 2007 +1000

    [POWERPC] Merge common virtex header files
    
    The header files for the ml403 and ml300 are virtually identical, merge
    them into a single file.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2b10caf380b0dbe3923b0ceefed17e3eaa7f2d4b
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sat Apr 28 05:49:59 2007 +1000

    [POWERPC] Rework Kconfig dependancies for Xilinx Virtex ppc405 platform
    
    Reverse dependency order for Xilinx Virtex parts.  For these parts, It
    makes more sense for boards/chips to specify which features they
    provide instead of the features listing the parts they are implemented
    in.  I think it also makes adding new board ports simpler.
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c146c958dc953da172231577d7ee81cf06d7eeb4
Author: Olof Johansson <olof@lixom.net>
Date:   Fri Apr 27 15:52:43 2007 +1000

    [POWERPC] Clean up cpufreq Kconfig dependencies
    
    Shuffle Kconfig order, making the platform drivers menu depend on the global
    option instead of each driver being dependent on it.
    
    Also fix dependency of PPC_PMAC on the G5 one.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e089ad46dbede9eed650f12d039d1addc05adf43
Author: Paul Mackerras <paulus@samba.org>
Date:   Mon Apr 30 10:24:24 2007 +1000

    Revert "[POWERPC] Autodetect serial console on efika"
    
    This reverts commit 9414715a7bbb45450015e9bc2676d85d919d08d4,
    at Olaf Hering's request:
    
    > Paul, please discard this patch. The optional graphics card may have
    > also device_type 'serial' if it is in VGA mode.
    > I will send an updated patch later.

commit bcfd09ee48f77a4fe903dbc3757e7af931998ce1
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sat Apr 21 21:02:52 2007 +0200

    ieee1394: remove garbage from Kconfig
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 3f94aa4d69bb9837857bac2755090a3cd28bfdc1
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sat Apr 21 20:54:37 2007 +0200

    ieee1394: more help in Kconfig
    
      - s/Device Drivers/Controllers/
      - clarify who needs pcilynx
      - don't recommend Y for raw1394; M is typically used
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 749cf76620a8f0d1ab4ff83c8e8f18028045a094
Author: Simon Arlott <simon@fire.lp0.eu>
Date:   Tue Apr 24 23:44:57 2007 +0100

    ieee1394: ohci1394: Fix mistake in printk message.
    
    Fix the "attempting to setting" message in ohci1394.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 2ab77524693ab855fc756faff0d1d26cb11a89e8
Author: Bernhard Kauer <kauer@os.inf.tu-dresden.de>
Date:   Fri Apr 20 13:59:54 2007 +0200

    ieee1394: ohci1394: remove unnecessary rcvPhyPkt bit flipping in LinkControl register
    
    Remove the unneeded code that clears, sets and again clears the
    rcvPhyPkt bit in the ohci1394 LinkControl register in ohci_initialize().
    
    Signed-off-by: Bernhard Kauer <kauer@os.inf.tu-dresden.de>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit c13596b0e5db1135ca22d068eca16ffe1e0ea912
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Thu Apr 12 22:21:55 2007 +0200

    ieee1394: ohci1394: fix cosmetic problem in error logging
    
    If posted write failed, an "Unhandled interrupt(s) 0x00000100" message
    was logged by mistake.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 21b2c5647b057624628888857f0e2246538a80b1
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 23 21:28:47 2007 +0200

    ieee1394: eth1394: send async streams at S100 on 1394b buses
    
    eth1394 did not work on buses consisting of S100B...S400B hardware
    because it attempted to send GASP packets at S800.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 809e905ce73eaa13972c2617959f8ec16e7d0d6f
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sat Apr 21 18:36:26 2007 +0900

    ieee1394: eth1394: fix error path in module_init
    
    This patch fixes some error handlings in eth1394:
    
    - check return value of kmem_cache_create()
    - cleanup resources if hpsb_register_protocol() fails
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (whitespace)

commit fdc0092bfd68cedfb9929256957f64c2c2760b5c
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:24:27 2007 +0200

    ieee1394: eth1394: correct return codes in hard_start_xmit
    
    This patch actually doesn't change anything because there was always 0
    == NETDEV_TX_OK returned before.
    
    TODO: Return NETDEV_TX_BUSY in error case and test in different error
    conditions.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 53f374e76c2b37835966382b27efb6bb3715f9d8
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:23:19 2007 +0200

    ieee1394: eth1394: hard_start_xmit is called in atomic context
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 099398719bb53119734354bc079840bebf1c7386
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:22:21 2007 +0200

    ieee1394: eth1394: some conditions are unlikely
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 2e2173df68f419aa41558e1fa90d7263b2d0211f
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:21:46 2007 +0200

    ieee1394: eth1394: clean up fragment_overlap
    
    offset > fi->offset + fi->len - 1  ==  !(offset < fi->offset + fi->len)
    offset + len - 1 < fi->offset      ==  !(offset + len > fi->offset)
    !(A || B)  ==  (!A && !B)
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 01590d20b42400be46cf4e565b39764e38ca87fe
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:20:37 2007 +0200

    ieee1394: eth1394: don't use alloc_etherdev
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 8a62bf7978eaa428e400677d5e5f5441262f79b1
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:19:48 2007 +0200

    ieee1394: eth1394: omit useless set_mac_address callback
    
    We can't reconfigure the MAC address, hence we don't need the callback.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 599bba9647f7813c09bf921c72351609430c8a33
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:19:02 2007 +0200

    ieee1394: eth1394: CONFIG_INET is always defined
    
    because CONFIG_IEEE1394_ETH1394 depends on it.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 17bab407d54ba1320d71a45641ecffc33bd331c1
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Tue Apr 3 23:55:40 2007 +0200

    ieee1394: eth1394: allow MTU bigger than 1500
    
    RFC 2734 says: "IP-capable nodes may operate with an MTU size larger
    than the default [1500 octets], but the means by which a larger MTU is
    configured are beyond the scope of this document."
    
    Allow users to set an MTU bigger than 1500.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit f982e5ffcfa9d0a2480d0b8261bd11521f3a1994
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 27 01:47:32 2007 +0200

    ieee1394: unexport highlevel_host_reset
    
    highlevel_host_reset no longer has any modular users.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 246a5fdade88cbeba09d07c69f67444a24a57d79
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:16:40 2007 +0200

    ieee1394: eth1394: contain host reset
    
    Call only eth1394's own host reset handler from .tx_timeout, not the
    reset hooks of all other IEEE 1394 drivers.
    
    A minor drawback of this patch is that ether1394_host_reset by timeout
    is not serialized against ether1394_host_reset by bus reset.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 5009d269610b4c89761dcae296d9717f2f48234b
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:15:53 2007 +0200

    ieee1394: eth1394: shorter error messages
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 027611b84260cf3adf14e30d2480007795829e6e
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:15:21 2007 +0200

    ieee1394: eth1394: correct a memset argument
    
    The old argument calculated the correct value in a wrong way.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit d06c1ddad9055eef55456abbae795279d6b1bbcf
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:14:45 2007 +0200

    ieee1394: eth1394: refactor .probe and .update
    
    Move common code into an extra function.  This implicitly adds a missing
    node_info->fifo = CSR1212_INVALID_ADDR_SPACE; to .update.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 5e7abccd38f7f2ce838eb49a657eea70b22f0803
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:13:51 2007 +0200

    ieee1394: eth1394: .probe and .update may sleep
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit efbeccf174bac803421a5f35076a17af47c9ce00
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 2 02:12:32 2007 +0200

    ieee1394: eth1394: coding style
    
    Adjust white space and line wraps.  Remove unnecessary parentheses and
    braces, unused macros, and some of the more redundant comments.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 09d7a96f5ad1019386594e2795c1f0229dd43305
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sun Apr 1 10:06:33 2007 +0200

    ieee1394: eth1394: Move common recv_init code to helper function
    
    There is some common code between ether1394_open and ether1394_add_host
    which can be moved to a separate helper function for a slightly smaller
    eth1394 driver (-160 bytes on i386.)
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 70093cfde8af52b0b9030d90f9004cbde38f2ff8
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Tue Mar 27 01:36:50 2007 +0200

    ieee1394: eth1394: don't autoload by hotplug when ohci1394 starts
    
    Until now, ieee1394 put an IP-over-1394 capability entry into each new
    host's config ROM.  As soon as the controller was initialized --- i.e.
    right after modprobe ohci1394 --- this entry triggered a hotplug event
    which typically caused auto-loading of eth1394.
    
    This irritated or annoyed many users and distributors.  Of course they
    could blacklist eth1394, but then ieee1394 wrongly advertized IP-over-
    1394 capability to the FireWire bus.
    
    Therefore
      - remove the offending kernel config option
        IEEE1394_CONFIG_ROM_IP1394,
      - let eth1394 add the ROM entry by itself, i.e. only after eth1394 was
        loaded.
    
    This fixes http://bugzilla.kernel.org/show_bug.cgi?id=7793 .
    
    To emulate the behaviour of older kernels, simply add the following to
    to /etc/modprobe.conf:
    
    install ohci1394 /sbin/modprobe eth1394; \
                     /sbin/modprobe --ignore-install ohci1394
    
    Note, autoloading of eth1394 when an _external_ IP-over-1394 capable
    device is discovered is _not_ affected by this patch.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit e00f04a70fa387b3accc81b5c346200f836e2a52
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 18 12:23:11 2007 +0100

    ieee1394: eth1394: reduce excessive function inlining
    
    Shrinks eth1394.ko by about 5%.
    
    Many of these functions have only one caller and are therefore auto-
    inlined anyway.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 2cd556ae61c862f4d00bb63863c6e5c67fd55bd4
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sat Feb 10 23:57:57 2007 +0100

    ieee1394: eth1394: clean up host removal
    
    ether1394_add_host() guarantees that hi->dev != NULL if hi != NULL.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 157188cb54b22e5c0c6439ef0500ba97b068097a
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sat Feb 10 23:56:38 2007 +0100

    ieee1394: eth1394: unregister address space in failure case
    
    Warn if hpsb_allocate_and_register_addrspace() failed.
    Unregister the address space if something else failed.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit ea9057ad622db41745be416e29c5760d141a6514
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Apr 23 21:27:13 2007 +0200

    ieee1394: send async streams at S100
    
    The comment says it all.  This affects only asynchronous streams sent
    via raw1394; the eth1394 driver has own code and needs an own fix.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit df18ce85de3deeaf311f96eb3d47e45fc7050f87
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Wed Apr 11 23:24:34 2007 +0530

    ieee1394: SPIN_LOCK_UNLOCKED cleanup
    
    SPIN_LOCK_UNLOCKED cleanup,use DEFINE_SPINLOCK instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 9be51c5d789a4864a820662460b8896b12a34c9d
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Fri Mar 30 19:21:05 2007 +0200

    ieee1394: nodemgr: unify some error messages
    
    Shrinks object file size a little bit.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 9324547235f63b7ebc905feb606291fce5d85ef5
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Fri Mar 30 19:19:55 2007 +0200

    ieee1394: nodemgr: less noise in dmesg
    
    Everytime when eth1394 or a libraw1394 client updates the configuration
    ROM, a certain sysfs attribute cannot be added since it already exists.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit d4c60085a97549ad3bb648e0652b9b48b7e42fa8
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 18 00:55:15 2007 +0100

    ieee1394: unroll a weird macro
    
    This is a coding style touch-up for ieee1394's handle_incoming_packet().
    
    A preprocessor macro contained hardwired variable names and, even worse,
    the 'break' keyword.  This macro is now unrolled and removed.
    
    Also, all 'break's which had the effect of a return are replaced by
    return.  And a FIXME comment is brought up to date.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit b9e5eb067b6882f564e1daa26e37ad6145f01da4
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:16:04 2007 -0700

    ieee1394: iso.c needs sched.h
    
    alpha:
    
    drivers/ieee1394/iso.c: In function 'hpsb_iso_xmit_sync':
    drivers/ieee1394/iso.c:440: error: invalid use of undefined type 'struct task_struct'
    drivers/ieee1394/iso.c:440: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function)
    drivers/ieee1394/iso.c:440: error: (Each undeclared identifier is reported only once
    drivers/ieee1394/iso.c:440: error: for each function it appears in.)
    drivers/ieee1394/iso.c:440: warning: implicit declaration of function 'signal_pending'
    drivers/ieee1394/iso.c:440: error: invalid use of undefined type 'struct task_struct'
    drivers/ieee1394/iso.c:440: warning: implicit declaration of function 'schedule'
    drivers/ieee1394/iso.c: In function 'hpsb_iso_wake':
    drivers/ieee1394/iso.c:562: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function)
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (brought into alphabetic order)

commit 9543a931dcd82bfc5143807440ff63c7721a2e2a
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Tue Apr 10 02:39:07 2007 +0200

    ieee1394: some more includes
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 3a23a81e83fddb40ec0242c74acb4b1829676bfc
Author: Torsten Kaiser <just.for.lkml@googlemail.com>
Date:   Mon Apr 9 21:03:15 2007 +0200

    ieee1394: ieee1394_transactions needs sched.h
    
    drivers/ieee1394/ieee1394_transactions.c fails for me if CONFIG_SMP=n
    
    gcc complains:
      CC      drivers/ieee1394/ieee1394_transactions.o
    drivers/ieee1394/ieee1394_transactions.c: In function 'hpsb_get_tlabel':
    drivers/ieee1394/ieee1394_transactions.c:183: error:
    'TASK_INTERRUPTIBLE' undeclared (first use in this function)
    drivers/ieee1394/ieee1394_transactions.c:183: error: (Each undeclared
    identifier is reported only once
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (added comment)

commit 504945c9c6954b83758272d04797f31437dfce9e
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue Apr 3 13:00:47 2007 -0700

    ieee1394: ieee1394_core printk format
    
    Fix printk format string:
    drivers/ieee1394/ieee1394_core.c:702: warning: format '%d' expects type 'int', but argument 2 has type 'size_t'
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 7542e0e696d1b6e71e6eb3183cbf2c63ec6b5acb
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 25 22:22:40 2007 +0200

    ieee1394: remove usage of skb_queue as packet queue
    
    This considerably reduces the memory requirements for a packet and
    eliminates ieee1394's dependency on CONFIG_NET.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit d265250341f83fa904d4fecdfadb46d7ab50765f
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:29:20 2007 +0100

    ieee1394: csr1212: log if devices have CRC errors in their ROM
    
    This will point out firmware bugs.
    
    I tested with 11 SBP-2 devices and one OS X PC and got these errors from
    two old CD-RWs only.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 511f7b3227eef52b56cf336a5313d8ff766c3050
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:28:36 2007 +0100

    ieee1394: csr1212: more sensible names for jump targets
    
    Code beneath two labels called "fail" is actually also reached in case
    of success.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit c94ccf9e3389ff55078a049bfe59b82f854436e8
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:27:46 2007 +0100

    ieee1394: csr1212: warn on unreachable code
    
    We want bugs to show themselves.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit a1c6250cb60a52a7f799610f9a4b1f4e8671175f
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:27:18 2007 +0100

    ieee1394: shrink csr1212_new_string_descriptor_leaf
    
    Make unnecessarily generic code specific and thus simpler.
    Shrink a lookup table from 128 to 16 bytes.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit c868ae2a1d1ad3a474d2a17295ac1ab190b30061
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:26:38 2007 +0100

    ieee1394: csr1212: coding style
    
    Whitespace, line breaks, braces...
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit fd2f3bddaeb20564f32e59f64e5063fbe0c8f4cc
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 11 22:51:24 2007 +0100

    ieee1394: replace vmalloc by kmalloc in csr1212
    
    The biggest chunk ever allocated by CSR1212_MALLOC is 1024 Bytes +
    sizeof(struct csr1212_csr_rom_cache) big.  Most of the time much
    smaller data structures are allocated.  Therefore vmalloc is a waste.
    
    The one exception is csr1212_append_new_cache() which is called to
    append a chunk of CSR1212_EXTENDED_ROM_SIZE + sizeof(struct
    csr1212_csr_rom_cache) if the currently allocated ROM cache is too
    small.  CSR1212_EXTENDED_ROM_SIZE is generously defined as 256 kBytes.
    In SVN commit 1220, Steve Kinneberg lowered this to 2 kBytes in the
    config_rom_2.4 branch.  This same commit also switched CSR1212_MALLOC
    from kmalloc to vmalloc in the SVN trunk branch:
    
    > r1220 | kberg | 2004-05-31 01:51:44 +0200 (Mon, 31 May 2004) | 13 lines
    >
    > CSR1212 Extended ROM bug fixes:
    > trunk line changes:
    >   - Use vmalloc instead of kmalloc
    >   - Change delayed_reset_bus() to operate in a work_queue instead of a
    >     timer interrupt.
    >   - Fix hpsb_allocate_and_register_addrspace() to not allocate space
    >     on top of already allocated space.
    >   - Fix problems in csr1212.c filling ConfigROM images when extend
    >     ROMs are present.
    > config-rom-2.4 changes:
    >   - Changed extended rom allocation from 256K to 8K.
    (It was actually 2 kB, not 8 kB.)
    >   - Fix hpsb_allocate_and_register_addrspace() to not allocate space
    >     on top of already allocated space.
    >   - Fix problems in csr1212.c filling ConfigROM images when extend
    >     ROMs are present.
    
    I am now setting CSR1212_EXTENDED_ROM_SIZE to 2 kB minus the overhead of
    struct csr1212_csr_rom_cache.  Note, this code path is not used by the
    in-kernel drivers though.  raw1394 could trigger it, but the respective
    libraw1394 functions don't exist yet.
    
    Furthermore, userspace programs can replace the entire local ROM via
    raw1394.  If kmalloc does not fulfill their needs --- well, tough luck.
    I decree that nobody needs such huge extended ROMs.  (Extended ROMs are
    defined by IEEE 1212 clause 7.7.18.  The spec does not impose
    practically relevant restrictions on the size of extended ROM chunks.)
    
    Another potentially demanding use of CSR1212_MALLOC is if external
    FireWire devices come with Extended ROM entries.  If they are too big
    for kmalloc (or have been too big for vmalloc) we just fail to read
    their ROM.  This is quite unlikely though, to my knowledge.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit c1a37f2c6572031203243dd083585aa4a1c138d5
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Wed Mar 14 00:20:53 2007 +0100

    ieee1394: de-inline some functions
    
    This small reorganization of public csr1212 functions saves one
    exported symbol and a few bytes in the driver modules.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 64ff712321875c2457d3a77d3fc4ab4989f7a8c0
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 11 22:50:13 2007 +0100

    ieee1394: stricter error checks in csr1212
    
    return -EINVAL becomes BUG_ON in checks of function call parameters.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 982610bd0d8e64baff36099f6dc456ea52d22257
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 11 22:49:34 2007 +0100

    ieee1394: csr1212: rename some types
    
    Use u8, u32 etc. instead of u_int8_t, csr1212_quad_t etc.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 7fb9addba8ebd67306099e7fa629ff76c1be2105
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 11 22:49:05 2007 +0100

    ieee1394: drop csr1212's support for external compilation
    
    csr1212 was written to be compiled either as part of the ieee1394 kernel
    driver or of an anticipated IEEE 1212 userspace library.  We now drop
    support for the latter.  The costs in terms of code footprint and depth
    of abstraction are not countered by any actual benefit.
    
    Also remove some obsolete #includes.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 6c88e475660edcd5571a5aab39ce8062183af951
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Mar 11 22:47:34 2007 +0100

    ieee1394: remove unused csr1212 code
    
    Delete unused code.
    Make some extern functions static.
    Remove superfluous inline keywords.
    Move private definitions from csr1212.h to csr1212.c.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit e167c88ebb2fcc2d98bd9a9970ae29e4fda4bdf9
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Mar 5 03:07:38 2007 +0100

    ieee1394: small header cleanup
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit afd6546d8d2d8ba1dbe1d2508baf81eebdca3d79
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Mar 5 03:06:23 2007 +0100

    ieee1394: move some comments from declaration to definition
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit ef8153348f82688af87e19d594162ca81741fe6a
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Mon Mar 5 03:05:32 2007 +0100

    ieee1394: remove declarations of nonexisting functions
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit f84c922ba16fdadb9e4ebf9dc177e3dbd3282f7c
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Mon Apr 23 11:50:56 2007 -0700

    ieee1394: sbp2: include fixes
    
    drivers/ieee1394/sbp2.c: In function 'sbp2util_access_timeout':
    drivers/ieee1394/sbp2.c:399: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function)
    drivers/ieee1394/sbp2.c:399: error: (Each undeclared identifier is reported only once
    drivers/ieee1394/sbp2.c:399: error: for each function it appears in.)
    drivers/ieee1394/sbp2.c:399: warning: implicit declaration of function 'signal_pending'
    drivers/ieee1394/sbp2.c:399: warning: implicit declaration of function 'schedule_timeout'
    drivers/ieee1394/sbp2.c: In function 'sbp2_prep_command_orb_sg':
    drivers/ieee1394/sbp2.c:1438: warning: implicit declaration of function 'page_address'
    drivers/ieee1394/sbp2.c:1438: warning: passing argument 2 of 'dma_map_single' makes pointer from integer without a cast
    drivers/ieee1394/sbp2.c: In function 'sbp2_handle_status_write':
    drivers/ieee1394/sbp2.c:1842: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function)
    
    Possibly due to changes in -mm, but this file should explicitly include the
    headers for the stuff it uses.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (brought into alphabetic order)

commit 3d269cb50c81d3bb01d5856d5157d4db346bab4b
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Feb 4 20:57:38 2007 +0100

    ieee1394: sbp2: move some memory allocations into non-atomic context
    
    When the command ORB pool is created, the ORB list won't be accessed
    concurrently.  Therefore we don't have to take the spinlock there.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 2446a79f4f0a5e88e5d8316dac407d66ac10f70d
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Feb 4 20:54:57 2007 +0100

    ieee1394: sbp2: optimize DMA direction of s/g tables
    
    Unlike the name suggests, "cmd->scatter_gather_element" holds only the
    s/g table, not the actual s/g elements.  Since the table is only read
    but never written by the device, DMA_BIDIRECTIONAL can be replaced by
    DMA_TO_DEVICE which may be cheaper on some architectures.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit 0555659d63c285ceb7ead3115532e1b71b0f27a7
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Feb 4 20:25:43 2007 +0100

    ieee1394: sbp2: enforce 32bit DMA mapping
    
    In order to use OHCI-1394 physical DMA, all s/g elements, s/g tables,
    ORBs, and response buffers have to reside within the first 4 GB of the
    FireWire controller's physical address space.  Set the correct mask for
    DMA mappings.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit f412bf440be2dfc0f0ded917410c599c002549e0
Author: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date:   Sun Feb 4 13:04:32 2007 +0100

    ieee1394: sbp2: remove unnecessary alignments of struct members
    
    The members "dma_addr_t command_orb_dma" and "dma_addr_t sge_dma" of
    sbp2.h::sbp2_command_info do not have to be aligned themselves --- only
    the memory which they point to has to be.
    
    The member "struct sbp2_command_orb command_orb" has to be aligned on
    4 bytes boundary which is guaranteed because it contains u32 members.
    
    The member "struct sbp2_unrestricted_page_table scatter_gather_element",
    i.e. the SBP-2 s/g table, has to be aligned on 8 bytes boundary
    according to the SBP-2 spec.  This is not a requirement for FireWire
    controllers but could be expected by SBP-2 targets.
    
    I see no need to align the members command_orb and
    scatter_gather_element on CPU cacheline boundaries.  It could have
    performance benefits, but on the other hand sbp2 has a somewhat wasteful
    allocation scheme which should be optimized first before further tweaks
    like cacheline alignments.  (E.g. don't always allocate SG_ALL s/g table
    elements.)
    
    Note, before as well as after the patch, the code relies on the
    assumption that memory alignment in the virtual address space is
    preserved in the physical address space after DMA mapping.
    
    Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

commit f61c9127b9840661244b1b6571e4304a7f0b5c73
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Sun Apr 29 13:14:56 2007 +0200

    USB HID: don't warn on idVendor == 0
    
    It turns out that there are broken devices out there that incorrectly
    report VID/PID as 0x000, see http://lkml.org/lkml/2007/4/27/496
    
    Therefore we should not confuse users by dumping warnings and stacktraces
    in such situation. It is not possible to add quirks for such horribly
    broken devices, but currently that's not needed.
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 04b090d50c88ac8e5ec9c2e985bb65bd153893aa
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Sat Apr 28 23:03:59 2007 -0700

    [AF_IUCV/IUCV]: smp_call_function deadlock
    
    Calling smp_call_function can lead to a deadlock if it is called
    from tasklet context.
    Fixing this deadlock requires to move the smp_call_function from the
    tasklet context to a work queue. To do that queue the path pending
    interrupts to a separate list and move the path cleanup out of
    iucv_path_sever to iucv_path_connect and iucv_path_pending.
    This creates a new requirement for iucv_path_connect: it may not be
    called from tasklet context anymore.
    Also fixed compile problem for CONFIG_HOTPLUG_CPU=n and
    another one when walking the cpu_online mask. When doing this,
    we must disable cpu hotplug.
    
    Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d0772b70faaf8e9f2013b6c4273d94d5eac8047a
Author: Eric Sesterhenn <snakebyte@gmx.de>
Date:   Sat Apr 28 21:26:23 2007 -0700

    [IPV6]: Fix slab corruption running ip6sic
    
    From: Eric Sesterhenn <snakebyte@gmx.de>
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 65bb723c9502b7ba0a3aad13bdac8832e213ba74
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Sat Apr 28 21:21:46 2007 -0700

    [TCP]: Update references in two old comments
    
    This updates references to drafts in comments which must be about 10
    years old.  Internet draft draft-ietf-tcpimpl-prob-03.txt expired in 1998
    and was replaced by RFC 2525 in March 1999.
    
    Section 3.10 of the draft maps almost identically into section 2.17 of RFC
    2525: both are entitled "Failure to RST on close with data pending", the
    differences in text body amount to a typo and minor sentence change.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ecfd6b183780c6d9e85873693b3ce6c5f4d08b58
Author: Jamal Hadi Salim <hadi@cyberus.ca>
Date:   Sat Apr 28 21:20:32 2007 -0700

    [XFRM]: Export SPD info
    
    With this patch you can use iproute2 in user space to efficiently see
    how many policies exist in different directions.
    
    Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5632c5152aa621885d87ea0b8fdd5a6bb9f69c6f
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sat Apr 28 21:16:39 2007 -0700

    [IPV6]: Track device renames in snmp6.
    
    When network device's are renamed, the IPV6 snmp6 code
    gets confused. It doesn't track name changes so it will OOPS
    when network device's are removed.
    
    The fix is trivial, just unregister/re-register in notify handler.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aad97f38b71dd2ecd730b3a3dce8264d13fbcd56
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Sat Apr 28 21:09:04 2007 -0700

    [SCTP]: Fix sctp_getsockopt_local_addrs_old() to use local storage.
    
    sctp_getsockopt_local_addrs_old() in net/sctp/socket.c calls
    copy_to_user() while the spinlock addr_lock is held. this should not
    be done as copy_to_user() might sleep. the call to
    sctp_copy_laddrs_to_user() while holding the lock is also problematic
    as it calls copy_to_user()
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5a1b5898ee9e0bf68a86609ecb9775457b1857a5
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Sat Apr 28 21:04:03 2007 -0700

    [NET]: Remove NETIF_F_INTERNAL_STATS, default to internal stats.
    
    Herbert Xu conviced me that a new flag was overkill; every driver
    currently overrides get_stats, so we might as well make the internal
    one the default.  If someone did fail to set get_stats, they would now
    get all 0 stats instead of "No statistics available".
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d16bfd0c77b35a0a0f0e159b94b9921510bf7934
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat Apr 28 20:58:22 2007 -0700

    [NETPOLL]: Remove CONFIG_NETPOLL_RX
    
    Get rid of the CONFIG_NETPOLL_RX option completely since all the
    dependencies have been removed long ago...
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Acked-by: Jeff Garzik <jgarzik@pobox.com>
    Acked-by: Matt Mackall <mpm@selenic.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5f286e113fa377e50bd18fc45e5a0d4d83f6950c
Author: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Date:   Sat Apr 28 20:57:37 2007 -0700

    [NETPOLL]: Fix TX queue overflow in trapped mode.
    
    CONFIG_NETPOLL_TRAP causes the TX queue controls to be completely bypassed in
    the netpoll's "trapped" mode which easily causes overflows in the drivers with
    short TX queues (most notably, in 8139too with its 4-deep queue).  So, make
    this option more sensible by making it only bypass the TX softirq wakeup.
    
    Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
    Acked-by: Jeff Garzik <jgarzik@pobox.com>
    Acked-by: Tom Rini <trini@kernel.crashing.org>
    Acked-by: Matt Mackall <mpm@selenic.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c6c60106b9584f17c55e4c5e0ce9b905a1a6cdb6
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue Apr 24 22:02:35 2007 +0200

    sonypi: use mutex instead of semaphore
    
    the Sony Programmable I/O Control driver uses a semaphore as
    mutex. use the mutex API instead of the (binary) semaphore
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Acked-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1b20d34406775369d50fc2ffe27a64a0d6fd313e
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:36:40 2007 +0900

    sony-laptop: remove user visible camera controls as platform attributes
    
    Avoid giving the user the possibility to shoot his own foot and let
    the meye driver enable/disable the camera wisely (PCI_ID based).
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit cbefb762b67fa6d3eb2a48ae3380358a940e8c9d
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:36:26 2007 +0900

    meye: make meye use sony-laptop instead of sonypi
    
    Change sonypi_camera_command() calls to sony_pic_camera_command() and use
    the renamed macros.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1ce82c14d06ff68380d7c647f768858e077930c5
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:34:36 2007 +0900

    sony-laptop: add a meye-usable include file for camera ops
    
    Copy and rename (for easier co-existence) the MEYE-wise exported interface.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit e364632e740fe9fcb401e5ece3be69e4d81c5a80
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:34:22 2007 +0900

    sony-laptop: complete the motion eye camera support in sony-laptop
    
    Add the exported sony_pic_camera_command() function to make the MEYE
    driver happy.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1a3e323907dc5991cba2d715d5db3ae2eac78280
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:34:10 2007 +0900

    sonypi: try to detect if sony-laptop has already taken one of the known ioports
    
    Get the IO resources list in sony-laptop in the same order as listed
    in sonypi and make sonypi check if one of those is already busy.
    The sonypi check can be disabled by a module parameter in case the user
    thinks we are plainly wrong (check_ioport=0).
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 74a882e4857414a98ca5904b3be90fb6aba2f25e
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:22:11 2007 +0900

    sonypi: suggest sonypi users to try sony-laptop instead
    
    Try to migrate sonypi users to sony-laptop gracefully.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 9476cdfae61a3c3fa61d06c18dd002b03671ca9f
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:21:42 2007 +0900

    sony-laptop: add edge modem support (also called WWAN)
    
    Some SZ Vaios have a gsm built-in modem. Allow powering on/off this device.
    Thanks to Joshua Wise for the base code.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 9f9f0761712928768198278c6cbc5cafe5502d38
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:19:36 2007 +0900

    sony-laptop: add locking on accesses to the ioport and global vars
    
    Better avoid having ioport commands mixing and global variables reading/writing.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 5f3d2898d79520bc8d8706ed3859060f9cbb969e
Author: malattia@linux.it <malattia@linux.it>
Date:   Sat Apr 28 23:18:45 2007 +0900

    sony-laptop: add camera enable/disable parameter, better handle possible infinite loop
    
    Use a parameter to enable/disable motion eye camera (for C1VE/C1VN models)
    controls and avoid entering an infinite loop if the camera is not present
    and the HW doesn't answer as we expect on io commands.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 836a53f42f3b5d5cb3a0751587ea33801e4b120d
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sat Apr 28 21:19:38 2007 +0200

    thinkpad-acpi: make drivers/misc/thinkpad_acpi:fan_mutex static
    
    This patch makes the needlessly global fan_mutex static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d3a6ade4f84416d774c3e5db5faae1840d55bd97
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:17 2007 -0300

    ACPI: thinkpad-acpi: add sysfs support to wan and bluetooth subdrivers
    
    Add support to sysfs to the wan and bluetooth subdrivers.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit a0416420e2c6244792d6f308183ad57c40532078
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:16 2007 -0300

    ACPI: thinkpad-acpi: add sysfs support to hotkey subdriver
    
    Add the hotkey sysfs support.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d94a7f16cad7700f8d2b142cc13cfba5387af3db
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:15 2007 -0300

    ACPI: thinkpad-acpi: improve dock subdriver initialization
    
    The dock sub-driver has split-personality (two subdrivers), and it was
    doing some unoptimal things on init because of that.  Fix it so that the
    second half of it will only init when necessary, and only if the first half
    initialized sucessfully in the first place.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 5ae930e685018e2dc6d4139362213e4b283e5700
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:14 2007 -0300

    ACPI: thinkpad-acpi: improve debugging for acpi helpers
    
    Some issues with the dock subdriver proved that a slightly improved
    debugging setup for ACPI notifiers and handler helpers would be useful.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b39fe582eb9252dca9a62f7135bcad2e486083e5
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:13 2007 -0300

    ACPI: thinkpad-acpi: improve fan control documentation
    
    Improve fan control documentation and fix one mistake.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit c573ddb998456a89a5ccb83a922d2c8ba18484a6
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:12 2007 -0300

    ACPI: thinkpad-acpi: map ENXIO to EINVAL for fan sysfs
    
    Currently, all fan control operations return ENXIO if unsupported
    operations are requested, but return EINVAL if invalid fan modes are
    requested on a given ThinkPad.
    
    This is not strictly correct for sysfs, so map ENXIO to EINVAL in the sysfs
    attribute store handlers, as we do benefit from the ENXIO in other parts of
    the driver code.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit ca4ac2f48a4502bbbfcb47b86312273c28194f53
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:11 2007 -0300

    ACPI: thinkpad-acpi: fix a fan watchdog invocation
    
    The fan control watchdog was being called in one place even when the fan
    control operation had failed.  Fix it.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 4985cd0a63b0713b6469ef01aae6a0e63ea72f83
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:10 2007 -0300

    ACPI: thinkpad-acpi: do not arm fan watchdog if it would not work
    
    Do not enable/rearm the fan control safety watchdog if we would not be able
    to do anything to the fan anyway.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit ecf2a80a97b3d38ae008fa8a3cb98cd540ac1eae
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Apr 27 22:00:09 2007 -0300

    ACPI: thinkpad-acpi: add a fan-control feature master toggle
    
    Len Brown considers that an active by default fan control interface in
    laptops may be too close to giving users enough rope.  There is a good
    chance he is quite correct on this, especially if someone decides to use
    that interface in applets and users are not aware of its risks.
    
    This patch adds a master switch to thinkpad-acpi that enables or disables
    the entire fan-control feature as a module parameter: "fan_control".  It
    defaults to disabled.  Set it to non-zero to enable fan control.
    
    Also, the patch removes the expermiental status from fan control, since it
    is stable enough to not be called experimental, and the master switch makes
    it safe enough to do so.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 79fff270026dc46634563a29b99e4034028ee919
Author: Bob Moore <robert.moore@intel.com>
Date:   Sat Apr 28 20:53:50 2007 -0400

    ACPICA: clear fields reserved before FADT r3
    
    Linux-2.6.21 stopped booting on a P4/HT because Linux
    wrote the FADT.CST_CNT value to the SMI_CMD.
    Apparently this stumbled over some SMM instability,
    such as confusing SMM when invoking it from cpu1.
    
    Linux did this because even though the r2 FADT reserves
    the CST_CNT field, this BIOS set that field and Linux
    used it.
    
    Turns out that up through 2.6.20 we explicitly cleared
    cst_control for r2 FADTs.  So here we go back to doing that,
    plus also clear some additional fields that are reserved
    until FADT r3.
    
    http://bugzilla.kernel.org/show_bug.cgi?id=8346
    
    Signed-off-by: Bob Moore <robert.moore@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 225036314e768bbfe8331ea9b0e91ca101afe427
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 26 00:19:27 2007 -0700

    SPIN_LOCK_UNLOCKED cleanup in drivers/ata/pata_winbond.c
    
    remove SPIN_LOCK_UNLOCKED, use DEFINE_SPINLOCK instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Acked-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4b22afd743a3882123a16135fa863558c0ac2d94
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:19:26 2007 -0700

    drivers/ata/pata_cmd640.c: fix build with CONFIG_PM=n
    
    This is grubby, but all the ata drivers do it this way.
    
    Would it not be better to do
    
    #define ata_scsi_device_resume NULL
    
    in libata.h, remove all those ifdefs?
    
    (updated version, ug, ug)
    
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Cc: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a473446856374668c4296db5256ca708ce8f7095
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Apr 26 00:19:25 2007 -0700

    pata_hpt37x: Further small fixes
    
    Further HPT37x changes
    
    - No 66MHz 370/370A
    - Remove dead special case check now we use the DPLL (as per the IDE driver)
    
    Pointed out by Sergei
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 28e21c8c0d44cd63bad4c62f94ef0c5a1cb8402c
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Apr 26 00:19:25 2007 -0700

    pata_hpt3x2n: Add HPT371N support and other bits
    
    Yes its no longer 3x2n but 3xxn, I can rename it if you want Jeff
    
    - Don't reset both ports each time (Sergei)
    - If we can't get a DPLL then abort entirely
    - Use ioport access for clock (from drivers/ide)
    - Add HPT371N support (from drivers/ide)
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit bd1d5ec64fff579e624b7c50c8a737da112efe5f
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:19:21 2007 -0700

    ata: printk warning fixes
    
    drivers/ata/libata-core.c: In function 'ata_hpa_resize':
    drivers/ata/libata-core.c:986: warning: format '%lld' expects type 'long long int', but argument 5 has type 'u64'
    drivers/ata/libata-core.c:986: warning: format '%lld' expects type 'long long int', but argument 6 has type 'u64'
    drivers/ata/libata-core.c:990: warning: format '%lld' expects type 'long long int', but argument 4 has type 'u64'
    drivers/ata/libata-core.c:990: warning: format '%lld' expects type 'long long int', but argument 5 has type 'u64'
    drivers/ata/libata-core.c:1003: warning: format '%lld' expects type 'long long int', but argument 4 has type 'u64'
    
    Also fix various 80-col bustage.
    
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0d64a233fe6a8fd45a062fe125159854ffed60c7
Author: Tejun Heo <htejun@gmail.com>
Date:   Mon Apr 23 02:41:05 2007 +0900

    libata: separate ATA_EHI_DID_RESET into DID_SOFTRESET and DID_HARDRESET
    
    Separate ATA_EHI_DID_RESET into ATA_EHI_DID_SOFTRESET and
    ATA_EHI_DID_HARDRESET.  ATA_EHI_DID_RESET is redefined as OR of the
    two flags.  This patch doesn't introduce any behavior change.  This
    will be used later to determine whether _SDD is necessary or not.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1188c0d83ca010c3799711e85e63dbde122e6a90
Author: Tejun Heo <htejun@gmail.com>
Date:   Mon Apr 23 02:41:05 2007 +0900

    ahci: consolidate common port flags
    
    Consolidate common port flags into AHCI_FLAG_COMMON.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4f701d1e9a796a3d6657e1129bee0566d7cda916
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 11:55:36 2007 +0100

    ata_timing: ensure t->cycle is always correct
    
    Russell King hit a case where quantisation errors accumulated such that
    the cycle time was shorter than rather than equal to the active/recovery
    time. The code already knows how to stretch times to fit the cycle time
    but does not know about the reverse.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c1c4e8d55757f8aec5f95eb80860e340d717c217
Author: Tejun Heo <htejun@gmail.com>
Date:   Mon Apr 23 02:05:53 2007 +0900

    libata: add missing call to ->cable_detect() in new EH path
    
    ->cable_detect() used to be called on by the old ata_bus_probe() path.
    Add invocation to ata_eh_revalidate_and_attach() right after IDENTIFYs
    are done.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit abcfa88bd47d433c796cf724a8a8b321a7190bdd
Author: Tejun Heo <htejun@gmail.com>
Date:   Mon Apr 23 02:04:38 2007 +0900

    pata_amd: remove contamination added during cable_detect conversion
    
    This is added by added by cff63dfceb52c564fe1ba5394d50ab7d599a11b9
     - pata: cable methods.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 169439c2e35f01e7832a9b4fc8a7446980c3d593
Author: Mark Lord <liml@rtr.ca>
Date:   Tue Apr 17 18:26:07 2007 -0400

    libata: Handle drives that require a spin-up command before first access
    
    (S)ATA drives can be configured for "power-up in standby",
    a mode whereby a specific "spin up now!" command is required
    before the first media access.
    
    Currently, a drive with this feature enabled can not be used at all
    with libata, and once in this mode, the drive becomes a doorstop.
    
    The older drivers/ide subsystem at least enumerates the drive,
    so that it can be woken up after the fact from a userspace HDIO_*
    command, but not libata.
    
    This patch adds support to libata for the "power-up in standby"
    mode where a "spin up now!" command (SET_FEATURES) is needed.
    With this, libata will recognize such drives, spin them up,
    and then re-IDENTIFY them if necessary to get a full/complete
    set of drive features data.
    
    Drives in this state are determined by looking for
    special values in id[2], as documented in the current ATA specs.
    
    Signed-off-by: Mark Lord <mlord@pobox.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1e999736cafdffc374f22eed37b291129ef82e4e
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Apr 11 00:23:13 2007 +0100

    libata: HPA support
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    
    Add support for ignoring the BIOS HPA result (off by default) and setting
    the disk to the full available size unless already frozen.
    
    Tested with various platforms/disks and confirmed to work with the
    Macintosh (which broke earlier) and ata_piix (breakage due to the LBA48
    readback that Tejun fixed).
    
    For normal users this brings us, I believe, to feature parity with old IDE
    (and of course more featured in some areas too).
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6bfff31e77cfa1b13490337e5a4dbaa3407e83ac
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:08 2007 +0900

    libata: kill probe_ent and related helpers
    
    All drivers are converted to new init model.  Kill probe_ent,
    ata_device_add() and ata_pci_init_native_mode().
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5d728824efeda61d304153bfcf1378a3c18b7d70
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:08 2007 +0900

    libata: convert the remaining PATA drivers to new init model
    
    Convert pdc_adma, pata_cs5520, pata_isapnp, pata_ixp4xx_cf,
    pata_legacy, pata_mpc52xx, pata_mpiix, pata_pcmcia, pata_pdc2027x,
    pata_platform, pata_qdi, pata_scc and pata_winbond to new init model.
    
    * init_one()'s now follow more consistent init order
    
    * cs5520 now registers one host with two ports, not two hosts.  If any
      of the two ports are disabled, it's made dummy as other drivers do.
    
    Tested pdc_adma and pata_legacy.  Both are as broken as before.  The
    rest are compile tested only.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4447d35156169cf136e829eb6b5cac2d6370f2d9
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:08 2007 +0900

    libata: convert the remaining SATA drivers to new init model
    
    Convert ahci, sata_sil, sata_sil24, sata_svw, sata_qstor, sata_mv,
    sata_sx4, sata_vsc and sata_inic162x to new init model.
    
    Now that host and ap are available during intialization, functions are
    converted to take either host or ap instead of low level parameters
    which were inevitable for functions shared between init and other
    paths.  This simplifies code quite a bit.
    
    * init_one()'s now follow more consistent init order
    
    * ahci_setup_port() and ahci_host_init() collapsed into
      ahci_init_one() for init order consistency
    
    * sata_vsc uses port_info instead of setting fields manually
    
    * in sata_svw, k2_board_info converted to port_info (info is now in
      port flags).  port number is honored now.
    
    Tested on ICH7/8 AHCI, jmb360, sil3112, 3114, 3124 and 3132.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9a829ccfc833269bdb85751f5048288ab93678ac
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:08 2007 +0900

    libata: convert ata_pci_init_native_mode() users to new init model
    
    Convert drivers which use ata_pci_init_native_mode() to new init
    model.  ata_pci_init_native_host() is used instead.  sata_nv, sata_uli
    and sata_sis are in this category.
    
    Tested on nVidia Corporation CK804 Serial ATA Controller [10de:0054]
    in both BMDMA and ADMA mode.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit eca25dca17630ae354f4b1df559ed90578b794fe
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: convert drivers with combined SATA/PATA ports to new init model
    
    Convert sata_via and sata_promise to new init model.  Both controllers
    can have combined configuration (SATA + PATA) and used twisted
    initialization method (modifying port in ->port_start) to overcome
    probe_ent limitations.
    
    This patch converts both drivers to new init model in which such
    configuration is natively supported.
    
    * promise: Combined pata port now uses separate port_info entry right
      after the sata counterpart entry.
    
    * promise: Controller configuration is discerned using ap->flags.
      This simplifies init path and makes it look more like other LLDs.
    
    * via: Both SATA and PATA ports in vt6421 are represented in their
      own port_info structure.
    
    Tested on PDC20375 (SATA150 TX2plus) [105a:3375] and PDC40775 (SATA
    300 TX2plus) [105a:3d73].  Couldn't test via cuz my c3 won't boot the
    current kernel.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 21b0ad4fb8306ac2bf5a249ffc978b1b8924c7d0
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: add init helpers including ata_pci_prepare_native_host()
    
    These will be used to convert LLDs to new init model.
    
    * Add irq_handler field to port_info.  In new init model, requesting
      IRQ is LLD's responsibility and libata doesn't need to know about
      irq_handler.  Most LLDs can simply register their irq_handler but
      some need different irq_handler depending on specific chip.  The
      added port_info->irq_handler field can be used by LLDs to select
      the matching IRQ handler in such cases.
    
    * Add ata_dummy_port_info.
    
    * Implement ata_pci_prepare_native_host(), a helper to alloc ATA host,
      acquire all resources and init the host in one go.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d491b27b1959565671e2c05dff09b5f535a854ce
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: convert native PCI host handling to new init model
    
    Convert native PCI host handling to alloc-init-register model.  New
    function ata_pci_init_native_host() follows the new init model and
    replaces ata_pci_init_native_mode().  As there are remaining LLD
    users, the old function isn't removed yet.
    
    ata_pci_init_one() is reimplemented using the new function and now
    fully converted to new init model.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0f834de3ea61aacacf1fac59ba9e82680f83c846
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: convert legacy PCI host handling to new init model
    
    Convert legacy PCI host handling to alloc-init-register model.
    ata_init_legacy_host(), ata_request_legacy_irqs() and
    ata_pci_init_bmdma() are separated out and follow the new init model.
    
    The two legacy handling functions use separate ata_legacy_devres
    instead of generic devm_* resources.  This reduces devres overhead for
    legacy hosts which was a bit high because it didn't use PCI/iomap
    merged resoruces.
    
    ata_pci_init_one() is rewritten in terms of the aboved functions but
    native mode handling is still using the old method.  Conversion will
    be completed when native mode handling is updated.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f5cda257296fbd3683b1f568f2d94d3caaacf74d
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: implement ata_host_alloc_pinfo() and ata_host_register()
    
    Implement ata_host_alloc_pinfo() and ata_host_register().  These helpers
    will be used in the following patches to adopt new init model.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f31871951b38daf2d7ca17daad59fdb735062da3
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:07 2007 +0900

    libata: separate out ata_host_alloc() and ata_host_register()
    
    Reorganize ata_host_alloc() and its subroutines into the following
    three functions.
    
    * ata_host_alloc() : allocates host and its ports.  shost is not
      registered automatically.
    
    * ata_scsi_add_hosts() : allocates and adds shosts associated with an
      ATA host.  Used by ata_host_register().
    
    * ata_host_register() : takes a fully initialized ata_host structure
      and registers it to libata layer and probes it.
    
    Only ata_host_alloc() and ata_host_register() are exported.
    ata_device_add() is rewritten using the above functions.  This patch
    does not introduce any observable behavior change.  Things worth
    mentioning.
    
    * print_id is assigned at registration time and LLDs are allowed to
      overallocate ports and reduce host->n_ports during initialization.
      ata_host_register() will throw away unused ports automatically.
    
    * All SCSI host initialization stuff now resides in
      ata_scsi_add_hosts() in libata-scsi.c, where it should be.
    
    * ipr is now the only user of ata_host_init().  Either kill it by
      converting ipr to use ata_host_alloc() and friends or rename and
      move it to libata-scsi.c
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ecef7253235e7a9365afe08a508e11bed91c1c11
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:06 2007 +0900

    libata: separate out ata_host_start()
    
    Separate out ata_host_start() from ata_device_add().  ata_host_start()
    calls ->port_start on each port if available and freezes the port.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4911487a34baa89ec5b5f09a661761b73091fbec
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Apr 17 23:44:06 2007 +0900

    libata: allocate ap separately from shost
    
    Don't embed ap inside shost.  Allocate it separately and point it back
    from shosts's hostdata.  This makes port allocation more flexible and
    allows regular ATA and SAS share host alloc/init paths.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit bf33554290bb6a6b2bd8827076f89fb17fb19e3d
Author: Tejun Heo <htejun@gmail.com>
Date:   Wed Apr 11 17:27:14 2007 +0900

    ahci: add PCI ID for new VIA chip
    
    Add PCI ID for new VIA chip.  Original patch is from Maarten Vanraes.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Cc: Maarten Vanraes <maarten.vanraes@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 03ec52dea0f3c615b1b502672c189f296842f7dd
Author: Tejun Heo <htejun@gmail.com>
Date:   Thu Apr 12 13:38:11 2007 +0900

    libata: kill type mismatch compile warning
    
    kill the following compile warning.
    
    drivers/ata/libata-core.c:1786: warning: comparison of distinct pointer types lacks a cast
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c65ec1c25dc23123040efdc4ada46071431723e3
Author: Conke Hu <conke.hu@gmail.com>
Date:   Wed Apr 11 18:23:14 2007 +0800

    ahci.c: remove non-existing SB600 raid id (re-send)
    
        SB600 RAID and SB600 SATA is the same controller and share the
    same PCI ID 0x4380. There is no such PCI ID 0x4381.
    
        Signed-off-by: Conke Hu <conke.hu@gmail.com>
     ---------
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a51d644af6eb0a93bc383e5f005faa445c87f335
Author: Tejun Heo <htejun@gmail.com>
Date:   Tue Mar 20 15:24:11 2007 +0900

    libata: improve AC_ERR_DEV handling for ->post_internal_cmd
    
    ->post_internal_cmd is simplified EH for internal commands.  Its
    primary mission is to stop the controller such that no rogue memory
    access or other activities occur after the internal command is
    released.  It may provide error diagnostics by setting qc->err_mask
    but this hasn't been a requirement.
    
    To ignore SETXFER failure for CFA devices, libata needs to know
    whether a command was failed by the device or for any other reason.
    ie. internal command needs to get AC_ERR_DEV right.
    
    This patch makes the following changes to AC_ERR_DEV handling and
    ->post_internal_cmd semantics to accomodate this need and simplify
    callback implementation.
    
    1. As long as the correct bits in the result TF registers are set,
       there is no need to set AC_ERR_DEV explicitly.  libata EH core
       takes care of that for both normal and internal commands.
    
    2. The only requirement for ->post_internal_cmd() is to put the
       controller into quiescent state.  It needs not to set any err_mask.
    
    3. ata_exec_internal_sg() performs minimal error analysis such that
       AC_ERR_DEV is automatically set as long as result_tf is filled
       correctly.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 55a6adeea4077521b4bba1dfe674f5835157a00b
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Mar 9 19:43:35 2007 +0900

    libata: fix native mode disabled port handling
    
    Disabled port handling in ata_pci_init_native_mode() is slightly
    broken in that it may end up using the wrong port_info.  This patch
    updates it such that disables ports are made dummy as done in the
    legacy and other cases.
    
    While at it, fix indentation in ata_resources_present().
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 17199b187b5d9a22f2ec835c9fdb38302501b918
Author: Tejun Heo <htejun@gmail.com>
Date:   Sun Mar 18 22:26:53 2007 +0900

    ahci: move port_map handling to ahci_save_initial_config()
    
    Move cross checking between port_map and cap.n_ports into
    ahci_save_initial_config().  After save_initial_config is done,
    hpriv->port_map is always setup properly.
    
    Tested on JMB363, ICH7 and ICH8 (with dummy ports).
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d447df140d0f07a02bd221cb42eb0b61bce16042
Author: Tejun Heo <htejun@gmail.com>
Date:   Sun Mar 18 22:15:33 2007 +0900

    ahci: implement ata_save/restore_initial_config()
    
    There are several registers which describe how the controller is
    configured.  These registers are sometimes implemented as r/w
    registers which are configured by firmware and get cleared on
    controller reset or after suspend/resume cycle.  ahci saved and
    restored those values inside ahci_reset_controller() which is a bit
    messy and doesn't work over suspend/resume cycle.
    
    This patch implements ahci_save/restore_initial_config().  The save
    function is called during driver initialization and saves cap and
    port_map to hpriv.  The restore function is called after the
    controller is reset to restore the initial values.
    
    Sometimes the initial firmware values are inconsistent and need to be
    fixed up.  This is handled by ahci_save_initial_config().  For this,
    there are two versions of saved registers.  One to write back to the
    hardware register, the other to use during driver operation.  This is
    necessary to keep ahci's behavior unchanged (write back fixed up
    port_map while keeping cap as-is).
    
    This patch makes ahci save the register values once before the first
    controller reset, not after it's been reset.  Also, the same stored
    values are used written back after each reset, so the register values
    are properly recovered after suspend/resume cycle.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ce2d3abc292c1eecd9ddc6f03391a0a46c6561dc
Author: Mikael Pettersson <mikpe@it.uu.se>
Date:   Sat Apr 7 14:29:51 2007 +0200

    sata_promise: fix error decode regression
    
    Promise ATA ports should always be reset by pdc_reset_port()
    when errors are detected, but the recent error reason decoding
    update to sata_promise replaced that reset with a freeze.
    
    This patch changes the error detection to do a reset again.
    This makes the error decoding update safer, as it now only
    adds error decoding without changing any other behaviour.
    
    Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9bedb799f2d270dc6434473fcab745adc930a85b
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Apr 11 00:19:00 2007 +0100

    pata_pdc2027x: Updates
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    
    Correct missing modefilter (crash if BAR4 unassigned)
    Use Cable Detect method
    Wrap ->set_mode instead ready for ->post_set_mode removal
    Maxtor errata as per Jeff Garzik report
    Remove duplicated private udma_mask hacking
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ad648c08835851b1b447b08144013e86aceafe5f
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Apr 11 00:14:09 2007 +0100

    pata_winbond
    
    Not a PCI device so doesn't need PCI includes
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit eb4a2c7f03db06dda0370591c958fa5a62ff2ec3
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Apr 11 00:04:20 2007 +0100

    pata: cable methods
    
    Versus upstream as requested
    
    Last of the trivial switches to cable_detect methods.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5a5dbd18a7496ed403f6f54bb20c955c65482fa5
Author: Mark Lord <liml@rtr.ca>
Date:   Fri Mar 16 10:22:26 2007 -0400

    libata: add support for READ/WRITE LONG
    
    The READ/WRITE LONG commands are theoretically obsolete,
    but the majority of drives in existance still implement them.
    
    The WRITE_LONG and WRITE_LONG_ONCE commands are of particular
    interest for fault injection testing -- eg. creating "media errors"
    at specific locations on a disk.
    
    The fussy bit is that these commands require a non-standard
    sector size, usually 520 bytes instead of 512.
    
    This patch adds support to libata for READ/WRITE LONG commands
    issued via SG_IO/ATA_16.
    
    Signed-off-by:  Mark Lord <mlord@pobox.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1234010684bb9cde51125ec3d1c71054a9f24f47
Author: Robin H\. Johnson <robbat2@gentoo.org>
Date:   Wed Mar 28 18:02:07 2007 -0700

    Add notation that the Asus W5F laptop has a short cable instead of 80-wire.
    
    The Asus W5F laptop uses a short cable instead of the 80-wire style, and thus
    needs to be in the ich_laptop special cases for correct detection and support
    of UDMA/100 for the hard drive. I noticed this because I have the W5F laptop,
    and was tracing apparent slowness.
    
    Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5c25bf0d2893ae03287693b958e9ef12e4893e04
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:43 2007 -0800

    pata_optidma: rework for cable detect and to remove post_set_mode()
    
    A lot of noise because I had to rename the optidma_set_mode() method to
    avoid confusion with the new ->set_mode() method that was added. Cable
    detect side is pretty trivial.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2f5344b1be57e63b6a3bfa19e69c5cd84f031edb
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:42 2007 -0800

    pata_winbond: restore cable method
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c45a6328742be39eee351a4ac7a5e60f7d048846
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:41 2007 -0800

    pata_sl82c105: restore cable detect method
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3b4ba5910b150c5db019642899d7b6ba9bec27b4
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:40 2007 -0800

    pata_netcell: re-remove all the crud
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3be40d7665e733c2b53bac38fcb148433718f555
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:40 2007 -0800

    pata_qdI: restore cable detect
    
    Signed-off-by: Alan Cox <number6@the-village.bc.nu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit b723d1448cbefc9fd591798d229d1dafb358bc66
Author: Alan Cox <alan@redhat.com>
Date:   Mon Mar 26 21:43:37 2007 -0800

    pata_ali: remove all the crap again and switch to cable_detect method
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f2fb344beadf79f9d265c3fc60e8399bbf917a4d
Author: Robert Hancock <hancockr@shaw.ca>
Date:   Mon Mar 26 21:43:36 2007 -0800

    sata_nv: don't read shadow registers when in ADMA mode
    
    Reading from the ATA shadow registers while we are in ADMA mode may cause
    undefined behavior.  Don't read the ATA status register when completing
    commands for this reason, it shouldn't be needed as the controller will
    notify us if the command failed.  Also, don't allow commands with result
    taskfile requested to execute in ADMA mode, since that requires accessing
    the shadow registers.  We also still need to override tf_read since libata
    will read the result taskfile on a command failure, and we need to go into
    port register mode before allowing this.
    
    Signed-off-by: Robert Hancock <hancockr@shaw.ca>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4dc5200d70a3e81510956c35fbb9fa3c15b440a5
Author: Alan <alan@lxorguk.ukuu.org.uk>
Date:   Mon Mar 26 21:43:34 2007 -0800

    pcmcia - spot slave decode flaws (for testing)
    
    It tries to spot when the slave is a mirror of the master and to fix up
    problems that causes.
    
    I've got two confirmations so far that this plus the "can fail set_xfer" patch
    work for folks who had problems before.  Also if you are unfortunate enough to
    be running something like HAL then it'll automount the same disk twice for you
    and corrupt it without the fix (aint that nice...)
    
    Tested (successfully) by Komuro <komurojun-mbn@nifty.com>.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 120bda35ff8514c937dac6d4e5c7dc6c01c699ac
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Mon Mar 26 02:17:43 2007 -0700

    git-libata-all-ipr-fix
    
    drivers/scsi/ipr.c: In function '__ipr_eh_dev_reset':
    drivers/scsi/ipr.c:3865: warning: passing argument 4 of 'ata_do_eh' from incompatible pointer type
    
    Cc: Tejun Heo <htejun@gmail.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 771b8dad9653d2659e0ffcc237184cb16c317788
Author: Tejun Heo <htejun@gmail.com>
Date:   Wed Mar 14 01:20:51 2007 +0900

    libata: hardreset on SERR_INTERNAL
    
    There was a rare report where SB600 reported SERR_INTERNAL and SRST
    couldn't get it out of the failure mode.  Hardreset on SERR_INTERNAL.
    As the problem is intermittent, whether this fixes the problem or not
    hasn't been verified yet, but hardresetting the channel on internal
    error is a good idea anyway.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 176efb054422bffe6b5a34194ffad134366c7f7e
Author: Mikael Pettersson <mikpe@it.uu.se>
Date:   Wed Mar 14 09:51:35 2007 +0100

    sata_promise: decode and report error reasons
    
    This patch adds much needed error reason decoding and
    reporting to sata_promise. It's simplistic but should
    log all relevant error info the controller provides.
    
    Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 724114a5738131997af9272f3c716dbe457c1690
Author: Mikael Pettersson <mikpe@it.uu.se>
Date:   Sun Mar 11 21:20:43 2007 +0100

    sata_promise: separate SATA and PATA ops
    
    This patch changes sata_promise so that the PATA ports
    on TX2plus chips are bound to the pdc_pata_ops structure.
    This means that operations called from the SATA ops
    structures don't need any SATA-vs-PATA tests any more.
    Instead, operations that depend on a port being SATA or
    PATA are separated into different procedures.
    
    * pdc_cable_type() is split into a PATA version and a
      SATA version
    * pdc_error_handler() is split into a PATA version and a
      SATA version, that both call a common version after
      setting up the `hardreset' function pointer
    * pdc_old_check_atapi_dma() is now only used for SATAI
      ports, so is renamed to pdc_old_sata_check_atapi_dma()
      and simplified
    * pdc_sata_scr_{read,write}() are now only used for SATA
      ports, so their is-not-SATA tests are removed
    * pdc_port_start() is split into three procedures: a wrapper
      which performs the ->ops adjustment on TX2plus PATA ports,
      a procedure with the common code, and a procedure with
      the SATA-specific code (this bit might be cleaned up by
      Tejun's new init model)
    
    Tested on 20619, 20575, and 20775 chips.
    
    Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 799331fda03f969b781553b786f38b83ec3bb608
Author: Mikael Pettersson <mikpe@it.uu.se>
Date:   Sun Mar 11 21:19:27 2007 +0100

    sata_promise: add missing cable_detect hooks
    
    The recent change which moved cable detection from
    pdc_pre_reset() to the new ->cable_detect hook only
    added the hook for SATAII chips, leaving SATAI chips
    and the 20619 without the hook. Fixed by this patch.
    
    Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 8cdfb29c0cd8018f92214c11c631d8926f4cb032
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 10:54:42 2007 -0500

    libata/IDE: remove combined mode quirk
    
    Both old-IDE and libata should be able handle all controllers and
    devices found using normal resource reservation methods.
    
    This eliminates the awful, low-performing split-driver configuration
    where old-IDE drove the PATA portion of a PCI device, in PIO-only mode,
    and libata drove the SATA portion of the /same/ PCI device, in DMA mode.
    Typically vendors would ship SATA hard drive / PATA optical
    configuration, which would lend itself to slow (PIO-only) CD-ROM
    performance.
    
    For Intel users running in combined mode, it is now wholly dependent on
    your driver choice (potentially link order, if you compile both drivers
    in) whether old-IDE or libata will drive your hardware.
    
    In either case, you will get full performance from both SATA and PATA
    ports now, without having to pass a kernel command line parameter.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit e424675f152572d8d2365e351b90bfd81686a150
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 09:56:46 2007 -0500

    [libata] turn on !IORDY filter
    
    The previous commit erroneously noted that the !IORDY filter was turned
    on.  No true, that change was split out into this commit.
    
    Originally authored and signed-off-by Alan Cox.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit cffacd85bcf6fc652292001873119333555fe260
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 09:46:47 2007 -0500

    [libata] sata_mv: support ->cable_detect
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a76b62ca70662cd0ca98edf366c6637009a95f7d
Author: Alan Cox <alan@redhat.com>
Date:   Fri Mar 9 09:34:07 2007 -0500

    libata: Change prototype of mode_filter to remove ata_port*
    
    With Tejun having added adev->ap some time ago we can get rid of the
    almost unused port being passed to mode filters. And while we are
    doing filters, lets turn on the !IORDY filter as well.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    
    With some hand massaging from
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9d2c7c75f889a3eefad016c71f651b0796e0a6e9
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:09:12 2007 +0000

    sata_sil: First step to removing ->post_set_mode
    
    Now that we have ata_do_set_mode() available for drivers to use we don't
    actually need ->post_set_mode() as the driver can wrap set_mode nicely
    and do stuff before or after (eg PCMCIA needs before), so we can kill off
    a method in all the structs
    
    While I was at it I added kernel-doc to the function involved.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 432729f0b0c299ae9731aaa31beaa0dd3a9751eb
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:22:59 2007 +0000

    libata-core: Fix the iordy methods
    
    This alone isn't sufficient to save the universe from prehistoric disks
    and controllers but it is a first important step. Split off a separate
    function to provide a mode filter when controller iordy is not available.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 04351821b43e6c0c91ad50d7e4be54a935f749e1
Author: Alan <alan@lxorguk.ukuu.org.uk>
Date:   Tue Mar 6 02:37:52 2007 -0800

    pata: expose set_mode method so it can be wrapped
    
    This splits set_mode into do_set_mode and the wrapper so that a driver can
    call the standard method inside its own.  This in theory also obsoletes
    ->post_set_mode().
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Tejun Heo <htejun@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit fcc2f69a6fad1543b466db9c35aa5a2f364eb3d4
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:28:52 2007 +0000

    pata_hpt37x: Updates from drivers/ide work
    
    Drag pata_hpt37x kicking and screaming in the direction of
    drivers/ide/pci/hpt366.c and all the work that Sergei has been doing
    there. Plenty left to be done but this is a good snapshot for folks to
    work on and to review
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ec04b075843d12b5115267415d0426b48e672136
Author: Tejun Heo <htejun@gmail.com>
Date:   Fri Mar 9 19:45:58 2007 +0900

    iomap: implement pcim_iounmap_regions()
    
    Implement pcim_iounmap_regions() - the opposite of
    pcim_iomap_regions().
    
    Signed-off-by: Tejun heo <htejun@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a73984a0d5664fa1bfdd9f0a475b8d74af7f44a6
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 08:37:46 2007 -0500

    [libata] More PATA driver ->cable_detect support
    
    Roll-up of ->cable_detect feature addition patches, authored and
    signed-off-by Alan Cox.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit fecfda5d88dcc3775f72d6f3a55d11b77c67f878
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 19:34:28 2007 +0000

    pata_hpt366: support ->cable_detect
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6bfed3fb035b4eff59160c2da5e3fbb69d6b0531
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 19:33:29 2007 +0000

    pata_efar: support ->cable_detect
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 847086069cdb5eac14f70cd0aea8545d499c80b4
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 19:27:31 2007 +0000

    pata_atiixp: support ->cable_detect
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d36a76482c19c186aa638446def39ec643993955
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 22:56:07 2007 +0000

    pata_radisys: support cable_detect
    
    Signed-off-by: Alan Cox <number6@the-village.bc.nu>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 745975c052cc8e808860c8634a2efdcc2da6dd01
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 22:58:03 2007 +0000

    pata_sc1200: restore cable type
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2a25dfe4f43b2199376424dce67ed11e3e276467
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 22:57:03 2007 +0000

    pata_rz1000: support cable_detect
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 570cb62deef574db10bcf1b4e9a8a0cbf7b101ee
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 22:54:04 2007 +0000

    pata_platform: Add cable_detect method
    
    Signed-off-by: Alan Cox <number6@the-village.bc.nu>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit e2a9752a21df4407a2094fb3345878d18a6c6d68
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:06:47 2007 +0000

    sata_promise: Switch to cable method, clean up some bits as a result
    
    Signed-off-by: Alan Cox <number6@the-village.bc.nu>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2e41e8e67af4cb0917793922fc8f55d3eeb6fa43
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:19:19 2007 +0000

    libata-core: fix comments on cable type
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 942d09470c3fb3254905c75f0cc9cd2d0dff24dd
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Thu Mar 8 23:24:49 2007 +0000

    libata: Restore Kconfig updated experimental levels and correct
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 7938a72db4d82f3caf3ae22aafa1ea18793a3149
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Mar 7 16:43:29 2007 +0000

    pata_cmd640: Multiple updates
    
    Fix suspend/resume support
    Write 0x5B to 0 not 0x5C
    
    The former is important as we must kill the FIFO on a resume
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 97cb81c335565f3ce27cd26d71480dff0211797a
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Mar 7 16:56:54 2007 +0000

    pata_via: Use cable_detect method
    
    We end up shifting a few bits of logic around in this driver but the
    basic change is the same.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2e413f510f1b77846e0e7728b991849e697d7f8b
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Mar 7 16:54:24 2007 +0000

    pata_sis: Clean up using cable_detect methods
    
    This changeset revolves around the fact that all the SiS controllers have
    the same enable bits, but differing cable detection methods. Previously
    that meant each type had its own error_handler methods. Instead we can
    now implement different ->cable_detect methods and share a single
    error_handler which does the filtering by enable bits.
    
    In addition we had some auto const arrays that should be static const. I'm
    not sure if gcc already treats them intelligently but adding the static
    will make sure.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 307c6054ad67428ad4e2bd4e5faae54fc4f8bcd2
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Mar 7 16:48:09 2007 +0000

    pata_marvell: Cable and reset fixes
    
    There are two changes here. Firstly we switch to a cable detect method,
    secondly the old code forgot to call ata_std_prereset() but somehow
    managed to work anyway. Fix the missing call.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5816fbbf22470b687964462e6c1f18165b291f22
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Wed Mar 7 16:46:20 2007 +0000

    pata_it8213: Cable detect
    
    Another not-quite PIIX, another cable type conversion
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a0fcdc0259e98d1c16d96baea9ba8a8603e41791
Author: Jeff Garzik <jeff@garzik.org>
Date:   Fri Mar 9 07:24:15 2007 -0500

    [libata] Update several PATA drivers for new ->cable_detect hook
    
    All patches authored and signed-off-by Alan Cox, sent on Mar 7, 2007.
    I merely combined them all into a single patch.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6a3d586d8e8a50e4cfd7f8c36d82a53c5614e05b
Author: Morrison, Tom <tmorrison@empirix.com>
Date:   Tue Mar 6 02:38:10 2007 -0800

    Support for Marvell 7042 Chip
    
    Added Support for Marvell 7042 Chip - 7042 has same capabilities & behavior
    as 6042.
    
    Signed-off-by: Thomas A. Morrison <tmorrison@empirix.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit b2248dac07cf057e4af3ec970e7d36a09f44fac8
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Tue Mar 6 02:38:11 2007 -0800

    pata_cmd640: CMD640 PCI support
    
    Support for the PCI CMD640 (not VLB)
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit be0d18dff5fae83845801929f297977c10ab99ad
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Tue Mar 6 02:37:56 2007 -0800

    libata: cable detection fixes
    
    2.6.21-rc has horrible problems with libata and PATA cable types (and
    thus speeds). This occurs because Tejun fixed a pile of other bugs and
    we now do cable detect enforcement for drive side detection properly.
    
    Unfortunately we don't do the process around cable detection right. Tejun
    identified the problem and pointed to the right Annex in the spec, this patch
    implements the rest of the needed changes.
    
    We add a ->cable_detect() method called after the identify
    sequence which allows a host to do host side detection at this point
    should it wish, or to modify the results of the drive side identify.
    
    This separate ->cable_detect method also cleans up a lot of code because
    many drivers have their own error_handler methods which really just set
    the cable type.
    
    If there is no ->cable_detect method the cable type is left alone so a
    driver setting it earlier (eg because it has the SATA flags set or
    because it uses the old error_handler approach) will still do the right
    thing (or at least the same thing) as before.
    
    This patch simply adds the cable_detect method and helpers it doesn't use
    them but other follow up patches will (ie Adrian please don't submit
    patches to unexport them ;))
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5aea408df5ae459cb29b91d45fa0f8bc1bee924e
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Tue Mar 6 02:37:54 2007 -0800

    libata: handle ata_pci_device_do_resume() failure while resuming
    
    Since commit:553c4aa630af7bc885e056d0436e4eb7f238579b
    ata_pci_device_do_resume() can return error code, all callers was updated
    except this one.
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 8343f88999bfcf4c4169e964c8a5c040f40c5a77
Author: Robert Hancock <hancockr@shaw.ca>
Date:   Tue Mar 6 02:37:51 2007 -0800

    libata: warn if speed limited due to 40-wire cable
    
    Warn the user if a drive's transfer rate is limited because of a 40-wire
    cable detection.
    
    Signed-off-by: Robert Hancock <hancockr@shaw.ca>
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f0ef88ed413232daebfe675c7b1bbf100d604d4b
Author: Mark Lord <liml@rtr.ca>
Date:   Fri Feb 2 12:36:25 2007 -0500

    RESEND: libata: check cdb len per dev instead of per host
    
    Resending, with s/printk/DPRINTK/ as pointed out by Alan.
    
    Fix libata to perform CDB len validation per device
    rather than per host.  This way, validation still works
    when we have a mix of 12-byte and 16-byte devices on
    a common host interface.
    
    Signed-off-by: Mark Lord <mlord@pobox.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit cd0d3bbcdd650651b7ccfaf55d107e3fc237d95a
Author: Alan <alan@lxorguk.ukuu.org.uk>
Date:   Fri Mar 2 00:56:15 2007 +0000

    libata: dev_config does not need ap and adev passing
    
    It used to be impossible to get from ata_device to ata_port but that is
    no longer true. Various methods have been cleaned up over time but
    dev_config still takes both and most users don't need both anyway. Tidy
    this one up
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d88184fb2348a50f7c34f5d49a901c875b2e0114
Author: Jeff Garzik <jeff@garzik.org>
Date:   Mon Feb 26 01:26:06 2007 -0500

    [libata] sata_mv: clean up DMA boundary issues, turn on 64-bit DMA
    
    The chips covered by sata_mv have a 32-bit DMA boundary they must not
    cross, not a 64K boundary.  We are merely limited to a 64K maximum
    segment size.  Therefore, the DMA scatter/gather table fill code can be
    greatly simplified, and we need not cut in half the S/G table size as
    reported to the SCSI layer.
    
    Also, the driver forget to turn on 64-bit DMA at the PCI layer.  All
    other data structures (both hardware and software) have been prepped for
    64-bit PCI DMA.  It was simply never turned on.  <fingers crossed> let's
    see if it still works...
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 43727fbc753c63f9d2764c56467303698cc52c14
Author: Jeff Garzik <jeff@garzik.org>
Date:   Sun Feb 25 16:50:52 2007 -0500

    [libata] export sata_print_link_status()
    
    To be used in sata_mv's exception handling code, and overall is a
    generally useful function.
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 351772658a4d1acc0221a6e30676bb0594e74812
Author: Jeff Garzik <jeff@garzik.org>
Date:   Sat Feb 24 21:26:42 2007 -0500

    [libata] sata_mv: remove extra braces
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 56fca7cc337752e3d31e107db050f7fff2402e7d
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Thu Apr 26 12:11:24 2007 +0100

    [ARM] 4330/1: S3C24XX: add S3C2410_UDC_FUNCADDR_UPDATE
    
    Add definition for S3C2410_UDC_FUNCADDR_UDPATE
    register definition for UDC driver.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit b4cf205846463a0a23a917bb18ad833bc9a8c0bb
Author: Vitaly Wool <vwool@ru.mvista.com>
Date:   Fri Apr 27 14:42:09 2007 +0400

    smc911x: fix compilation breakage wjen debug is on
    
    the patch below fixes compilation breakage of smc911x driver when
    ENABLE_SMC_DEBUG_PKTS equals to 1.
    
    Signed-off-by: Vitaly Wool <vitalywool@gmail.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1c0d6dcf885badc72f72bfba9bc5b4f1469b8501
Author: Shani Moideen <shani.moideen@wipro.com>
Date:   Sat Apr 28 11:05:43 2007 -0400

    [netdrvr] eexpress: minor corrections
    
    A few corrections related to time_after and time_before in
    drivers/net/eexpress.c as suggested by Marcin slusarz.
    
    Signed-off-by: Shani Moideen <shani.moideen@wipro.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 693aa9470d8273a0ded8b211a8f5f7c0835adf30
Author: Mark Mason <mmason@upwardaccess.com>
Date:   Thu Apr 26 00:23:22 2007 -0700

    add NAPI support to sb1250-mac.c
    
    Patch to add NAPI support to sb1250-mac.c (rev 2).  This patch differs from
    the last in that the NAPI support isn't marked as experimental, nor is it
    configurable (ie.  once applied - NAPI is enabled all the time).  This was
    based on feedback from Ralf and others.
    
    Signed-off-by: Mark Mason <mason@broadcom.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 55e924cf5772cbcf00549e448be35b392ff3084c
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Fri Apr 27 13:55:31 2007 -0700

    ixgb: ROUND_UP macro cleanup in drivers/net/ixgb
    
    IXGB_ROUNDUP macro cleanup ,use ALIGN
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 9099cfb9170f352f08207dfa099717a904cff71f
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Fri Apr 27 13:55:29 2007 -0700

    e1000: ROUND_UP macro cleanup in drivers/net/e1000
    
    E1000_ROUNDUP macro cleanup, use ALIGN
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit abf17ffda7b7b6c83a29d7ccea91d46065c6ca3e
Author: Krzysztof Halasa <khc@pm.waw.pl>
Date:   Fri Apr 27 13:13:33 2007 +0200

    Generic HDLC sparse annotations
    
    Sparse annotations, including two minor bugfixes.
    
    Signed-off-by: Krzysztof Halasa <khc@pm.waw.pl>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 27345bb684140f5f306963e0d6e25a60c7857dfe
Author: Jesse Brandeburg <jesse.brandeburg@intel.com>
Date:   Thu Apr 26 09:43:20 2007 -0700

    e100: Optionally use I/O mode only to access register space
    
    It appears that some systems still like e100 better if it uses
    I/O access mode.  Setting the new parameter use_io=1 will cause
    all driver instances to use io mapping to access the register
    space on the e100 device.
    
    Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 948cd43fed7c7d919fa30e0609b2b5852c4503ef
Author: Jesse Brandeburg <jesse.brandeburg@intel.com>
Date:   Thu Apr 26 09:43:11 2007 -0700

    e100: allow bad MAC address when running with invalid eeprom csum
    
    Seved Torstendahl <seved.torstendahl@netinsight.net> suggested to
    let the module parameter for invalid eeprom checksum control the valid
    mac address test.
    
    If this bypass happens we should print a different message,
    or at least one that is correct, maybe something like below
    
    Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1211bb6dcd935c48e864d4eecbf8a684e982419a
Author: Thomas Klein <osstklei@de.ibm.com>
Date:   Thu Apr 26 11:56:43 2007 +0200

    ehea: fix for dlpar support
    
    Certain resources may only be allocated when first logical port is available,
    and must be removed when last logical port has been removed.
    
    Signed-off-by: Thomas Klein <tklein@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d1dea38d54311f6b3dd37ce485e794bd133e3593
Author: Thomas Klein <osstklei@de.ibm.com>
Date:   Thu Apr 26 11:56:13 2007 +0200

    ehea: fix for sysfs entries
    
    Create symbolic link from each logical port to ehea driver
    
    Signed-off-by: Thomas Klein <tklein@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3b0dc5c1cfcdff806fe860a28d62fbf70af112e9
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Apr 26 00:23:25 2007 -0700

    3C509: Remove unnecessary include of <linux/pm_legacy.h>
    
    Remove the apparently redundant include of <linux/pm_legacy.h>.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 78403a929a176813d7911bebccad303a1fdfe281
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:57:26 2007 -0700

    NetXen: Fix for vmalloc issues
    
    NetXen: Fix vmalloc errors on seen on some X86 high end machines.
    
    Signed-off by: Milan Bag <mbag@netxen.com>
    Acked-by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6d1495f29a59aad464024693a413a945e274c1ed
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:56:42 2007 -0700

    NetXen: Fixes for Power PC architecture
    
    NetXen: Fix PPC architecture specific bugs
    Fixes some issues seen on Big endian machines.
    
    Signed-off by: Milan Bag <mbag@netxen.com>
    Signed-off by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6c80b18df3537d1221ab34555c150bccbfd90260
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:55:26 2007 -0700

    NetXen: Port swap feature for multi port cards
    
    NetXen: Port Swap feature
    This patch will allow a port numbers on the card to be swapped in
    host driver. This feature is applicable to cards having more than
    1 port.
    
    Signed-off by: Milan Bag <mbag@netxen.com>
    Signed-off by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 5d512f5594f9f4829b099c87f7bc6f683ef146ca
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:54:28 2007 -0700

    NetXen: Removal of redundant macros
    
    NetXen: Remove 2 redundant macro definitions from header file.
    
    Signed-off by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 595e3fb8cf0c3c1c6d63dc3d7fd166e50bf150ff
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:53:52 2007 -0700

    NetXen: Multi PCI support for Quad cards
    
    NetXen: Fix the multi PCI function for cards with more than 2 ports.
    This patch fixes the working of multi PCI capable driver on cards with
    more than 2 ports by adding the addresses for their rings and sizes.
    
    Signed-off by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 13ba9c7714cfa40821d29090442de14d01d6eb33
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:53:05 2007 -0700

    NetXen: Removal of redundant argument passing
    
    NetXen: Removal of redundant function call parameters and bug fixes.
    This patch will remove the redundant paramters which were being passed to
    many functions since now adapter->portnum can be used.
    
    Signed-off-by: Mithlesh Thukral <mithlesh@netxen.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3176ff3ee71bddbd1d68e6a9e28dbcf0a2960c95
Author: Mithlesh Thukral <mithlesh@netxen.com>
Date:   Fri Apr 20 07:52:37 2007 -0700

    NetXen: Use multiple PCI functions
    
    NetXen: Make driver use multiple PCI functions.
    This patch will make NetXen driver work with multiple PCI functions. This will
    make the usage of memory resources as well as interrupts more independent
    among different functions which results in better throughput. This change has
    been done after the multiport support is added in firmware.
    
    Signed-off by: Mithlesh Thukral <mithlesh@netxen.com>
    
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d52df4a35af569071fda3f4eb08e47cc7023f094
Author: Scott Feldman <sfeldma@pobox.com>
Date:   Wed Nov 9 02:18:52 2005 -0500

    [netdrvr e100] experiment with doing RX in a similar manner to eepro100
    
    I was going to say that eepro100's speedo_rx_link() does the same DMA
    abuse as e100, but then I noticed one little detail: eepro100 sets  both
    EL (end of list) and S (suspend) bits in the RFD as it chains it  to the
    RFD list.  e100 was only setting the EL bit.  Hmmm, that's  interesting.
    That means that if HW reads a RFD with the S-bit set,  it'll process
    that RFD and then suspend the receive unit.  The  receive unit will
    resume when SW clears the S-bit.  There is no need  for SW to restart
    the receive unit.  Which means a lot of the receive  unit state tracking
    code in the driver goes away.
    
    So here's a patch against 2.6.14.  (Sorry for inlining it; the mailer
    I'm using now will mess with the word wrap).  I can't test this on
    XScale (unless someone has an e100 module for Gumstix :) .  It should
    be doing exactly what eepro100 does with RFDs.  I don't believe this
    change will introduce a performance hit because the S-bit and EL-bit  go
    hand-in-hand meaning if we're going to suspend because of the S- bit,
    we're on the last resource anyway, so we'll have to wait for SW  to
    replenish.
    (cherry picked from 29e79da9495261119e3b2e4e7c72507348e75976 commit)

commit 2933d42cb7b0f14e0f83f6f231c966e97c79cdc9
Author: Larry Finger <Larry.Finger@lwfinger.net>
Date:   Tue Apr 17 10:28:47 2007 -0500

    [PATCH] ieee80211: add missing global needed by IEEE80211_DEBUG_XXXX
    
    Using any of the IEEE80211_DEBUG_XXXX macros in any ieee80211_crypt
    routine built as a module results in a missing global for
    'ieee80211_debug_level'.  The fix is to export the symbol in ieee80211.
    
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 32684ec61678c61c6ceebfb29901b7723410ed83
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Fri Apr 6 11:08:24 2007 -0700

    mii: add kernel-doc notation
    
    Add kernel-doc notation to drivers/net/mii.c functions.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 493a684ab8af36173e54ee9a102ed1768991f78a
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue Apr 17 13:12:55 2007 +1000

    Fix sparse errors in drivers/net/ibmveth.c
    
    drivers/net/ibmveth.c:96:46: error: marked inline, but without a definition
    drivers/net/ibmveth.c:96: warning: 'ibmveth_rxq_harvest_buffer' declared inline after being called
    drivers/net/ibmveth.c:96: warning: previous declaration of 'ibmveth_rxq_harvest_buffer' was here
    
    Just let the compiler decide, as it happens gcc 4.~ inlines it anyway.
    
    drivers/net/ibmveth.c:957:71: warning: Using plain integer as NULL pointer
    drivers/net/ibmveth.c:964:85: warning: Using plain integer as NULL pointer
    
    Split the long lines as well, ugly, but < 80 columns.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c2bcf00b437805b3c13374a4c4c8b6af646bdc2f
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Fri Apr 13 01:26:36 2007 -0500

    ucc_geth: version 1.1
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3a8205ead4dc4b05fbc164eeb852b8f8921d11d3
Author: Nicu Ioan Petru <ionut.nicu@freescale.com>
Date:   Fri Apr 13 01:26:29 2007 -0500

    ucc_geth: fixes for ucc_geth_memclean
    
    The ucc_geth_memclean function can be called before the Tx BD rings, Rx
    BD rings and associated socket buffers are allocated (for example if
    ucc_fast_init fails). The current code doesn't check if p_tx_bd_ring[i]
    is null, generating a kernel panic when trying to free the associated
    socket buffers.
    
    The function can also fail when accessing the uninitialized list_head
    structures ugeth->group_hash_q and ugeth->ind_hash_q. In the current
    implementation the list heads are initialized only when
    maxGroupAddrInHash and maxIndAddrInHash are positive values, although I
    think it's better to always initialize them.
    
    Signed-off-by: Ionut Nicu <ionut.nicu@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d5b9049df25f38b3eaf3af48d494b0747aae4349
Author: Michael Reiss <michael.f.reiss@freescale.com>
Date:   Fri Apr 13 01:26:19 2007 -0500

    ucc_geth: Implement Transmit on Demand support
    
    Transmit on Demand: Fix spelling in config option, and make it actually enable TOD.
    
    Signed-off-by: Michael Reiss <michael.f.reiss@freescale.com>
    Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 7563907eb8aad8f15b6a39fa6d863c091d83ef48
Author: Michael Barkowski <michael.barkowski@freescale.com>
Date:   Fri Apr 13 01:26:15 2007 -0500

    ucc_geth: Fix interrupt coalescing size and alignment
    
    The rx interrupt coalescing table alignment was "guessed" to be 4,
    but should be 64. The size should be 8 * number of queues + 4.
    Verified in the MPC8323E manual.
    
    Signed-off-by: Michael Barkowski <Michael.Barkowski@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 702ff12ce7e9643084232a8d50b0b1eec26026ae
Author: Michael Reiss <michael.f.reiss@freescale.com>
Date:   Fri Apr 13 01:26:11 2007 -0500

    ucc_geth: NAPI-related bug fixes
    
    Based partly on the gianfar driver, this patch fixes several
    bugs which were causing NAPI to be completely unusable.
    * An IRQ is still needed in NAPI, to kick off NAPI task,
      and for Tx processing.  Request the IRQ.
    * If rx_work_limit = 0 we are not complete.
    * While running Rx NAPI processing we must mask Rx events,
      including Rx busy.
    * ucc_geth_rx function does not need a lock.
      Could lead to deadlock in NAPI case.
    * There's no need to loop reading ucce multiple times in the ISR,
      so while adding the call to schedule NAPI which was not there,
      simplify the event processing into if-else format.
    * Rx Busy now kicks off NAPI processing, while still
      being counted as an error.
    
    Signed-off-by: Michael Reiss <michael.f.reiss@freescale.com>
    Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 728de4c927a3544b6d3da331b634035d4c75ca17
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Fri Apr 13 01:26:03 2007 -0500

    ucc_geth: migrate ucc_geth to phylib
    
    migrate ucc_geth to use the common phylib code.
    
    There are several side effects from doing this:
    
    o deprecate 'interface' property specification present
      in some old device tree source files in
      favour of a split 'max-speed' and 'interface-type'
      description to appropriately match definitions
      in include/linux/phy.h.  Note that 'interface' property
      is still honoured if max-speed or interface-type
      are not present (backward compatible).
    o compile-time CONFIG_UGETH_HAS_GIGA is eliminated
      in favour of probe time speed derivation logic.
    o adjust_link streamlined to only operate on maccfg2
      and upsmr.r10m, instead of reapplying static initial
      values related to the interface-type.
    o Addition of UEC MDIO of_platform driver requires
      platform code add 'mdio' type to id list
      prior to calling of_platform_bus_probe (separate patch).
    o ucc_struct_init introduced to reduce ucc_geth_startup
      complexity.
    
    Signed-off-by: Li Yang <leoli@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a999589ccaae16472531e0616f23826ad097aa40
Author: Kim Phillips <kim.phillips@freescale.com>
Date:   Fri Apr 13 01:25:57 2007 -0500

    phylib: add RGMII-ID interface mode definition
    
    The RGMII spec allows compliance for devices that implement an internal
    delay on TXC or RXC inside the transmitter.  This patch adds an RGMII_ID
    definition to support RGMII-ID devices in the phylib.
    
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit aeb998c124786e8c7fbd6eab347230469e911872
Author: Larry Finger <Larry.Finger@lwfinger.net>
Date:   Mon Apr 9 11:24:41 2007 -0500

    [PATCH] ieee80211-crypt: Make some TKIP and CCMP error logging conditional
    
    There are messages arising from ieee80211_crypt that spam the logs
    of casual users. These are changed to be logged only if the user
    specifically requests the IEEE80211_DEBUG_DROP messages. In either
    case, the error/drop count is incremented.
    
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 5d082fe85bf77f11aebb98d3bd29d66284d46851
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sat Apr 7 16:00:43 2007 +0100

    [PATCH] zd1211rw: Add ID for ZyXEL AG-220
    
    Tested by Christoph Sager and Tomas Klas
    
    zd1211b chip 0586:3412 v4810 high 00-13-49 AL7230B_RF pa0 g----
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit ba528c4587005a004d136ed2e69705401ee4b878
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sat Apr 7 16:00:30 2007 +0100

    [PATCH] zd1211rw: Add AL7230B RF support for ZD1211B
    
    This patch adds support for some new ZD1211B devices which ship with
    the AL7230B RF.
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 72018b223dcacb631f140d4c8fada3790bd1b03c
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sat Apr 7 16:00:15 2007 +0100

    [PATCH] zd1211rw: rework band edge patching
    
    This change allows RF drivers to provide their own 6M band edge patching
    implementation, while providing a generic implementation shared by most
    currently supported RF's.
    
    The upcoming ZD1211B/AL7230B code will use this to define its own
    patching function, which is different from the other RF configurations.
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit dc536a706951e23d3c81d0aa81414dc9f2c34ce5
Author: Daniel Drake <dsd@gentoo.org>
Date:   Tue Apr 3 23:17:10 2007 +0100

    [PATCH] zd1211rw: Remove invalid CR write during ZD1211 phy reset
    
    The vendor driver only does the CR123 write for non-USB devices (which
    don't exist on the consumer market)
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 25ac6c2627acd68bd50307e61a3b581b2f82552e
Author: Marcin Juszkiewicz <openembedded@hrw.one.pl>
Date:   Fri Mar 30 15:34:14 2007 +0200

    [PATCH] hostap_cs: support ADLINK 345 CF
    
    Add ADLINK 345 CF card into hostap_cs
    
    product info: "ADLINK 345 CF"
     manfid 0xd601, 0x0005
    
    Signed-off-by: Marcin Juszkiewicz <openembedded@hrw.one.pl>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 6693228da9cc8cd6a8ede97989cf2e46b99d6934
Author: Pavel Roskin <proski@gnu.org>
Date:   Wed Mar 28 17:08:51 2007 -0400

    [PATCH] Remove comment about IEEE80211_RADIOTAP_FCS
    
    IEEE80211_RADIOTAP_FCS is obsolete and should not be used.  It's no
    longer defined.  Remove it from the comment too.
    
    Signed-off-by: Pavel Roskin <proski@gnu.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 3a5c393e6f3e9f537e790016f3214447f2b50e51
Author: Larry Finger <Larry.Finger@lwfinger.net>
Date:   Wed Mar 28 11:07:49 2007 -0500

    [PATCH] bcm43xx: Change initialization for 2050 radios
    
    This patch implements the changes in the specifications for
    2050radio_init that were recently posted.
    
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit b1fc1fa9b36512e928df95aead1a85381380ad1f
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sat Mar 31 22:55:40 2007 +0200

    make drivers/net/qla3xxx.c:PHY_DEVICES[] static
    
    On Fri, Mar 30, 2007 at 01:05:59AM -0700, Andrew Morton wrote:
    >...
    > Changes since 2.6.21-rc5-mm2:
    >...
    >  git-netdev-all.patch
    >...
    >  git trees
    >...
    
    This patch makes the needlessly global PHY_DEVICES[] static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3ef34b807d35f81ee686e90e28084ee572a66e01
Author: Ramkrishna Vepa <ramkrishna.vepa@neterion.com>
Date:   Fri Mar 30 18:42:27 2007 -0700

    S2io: Change of driver maintainers
    
    - Changed the maintainers for the S2io driver.
    
    Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d7ef45b04905468b08e36b43dbce5b1de496e682
Author: Shani <shani.moideen@wipro.com>
Date:   Wed Mar 28 10:44:31 2007 +0530

    Patch:replace with time_after in drivers/net/eexpress.c
    
    Replacing with time_after in drivers/net/eexpress.c
    Applies and compiles clean on latest tree.Not tested.
    
    Signed-off-by: Shani Moideen <shani.moideen@wipro.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit acbddb591ba76bb20204fd6a407cb87d3f5f751e
Author: Jan-Bernd Themann <ossthema@de.ibm.com>
Date:   Fri Mar 23 17:18:53 2007 +0100

    ehea: removing unused functionality
    
    This patch includes:
    - removal of unused fields in structs
    - ethtool statistics cleanup
    - removes unsed functionality from send path
    
    Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 144213d71ce8b2a1e0740dd25808143e9ace655a
Author: Gabriel Paubert <paubert@iram.es>
Date:   Fri Mar 23 12:07:26 2007 -0700

    mv643xx_eth: make eth_port_uc_addr_{get,set}() calls symmetric
    
    There is no good reason for the asymmetry in the parameters of
    eth_port_uc_addr_get() and eth_port_uc_addr_set().  Make them
    symmetric.  Remove some gratuitous block comments while we're here.
    
    Signed-off-by: Gabriel Paubert <paubert@iram.es>
    Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 201f27e625cb2fe150e92d81d9725fe28c279792
Author: Ron Mercer <ron.mercer@qlogic.com>
Date:   Mon Mar 26 13:43:03 2007 -0700

    qla3xxx: Bumping driver version number to v2.03.00-k4
    
    Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3efedf2e5b814f3edd99e4f4ca47a604871ebe0e
Author: Ron Mercer <ron.mercer@qlogic.com>
Date:   Mon Mar 26 12:43:52 2007 -0700

    qla3xxx: Adding support for the Agere PHY (ET1011C)
    
    This PHY support patch was written by Benjamin Li.
    Signed-off-by: Benjamin Li <benjamin.li@qlogic.com>
    Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit ec8263839aa8bc6eeee608a045e8f51738d7e436
Author: Ron Mercer <ron.mercer@qlogic.com>
Date:   Mon Mar 26 13:43:01 2007 -0700

    qla3xxx: Add ethtool get_pauseparam for improved bonding support.
    
    Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f930e46a85a61895ef5c7c56c66c28272bec1ae1
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Mar 26 21:47:24 2007 -0800

    remove unused header file: drivers/net/skfp/h/lnkstat.h
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 939456ac51dd0b6b2b5653823b5655a790e72769
Author: Folkert van Heusden <folkert@vanheusden.com>
Date:   Mon Mar 26 21:47:23 2007 -0800

    baycom_ser_fdx: also allow i/o ports >= 0x1000 and enhanced failure logging
    
    The baycom_ser_fdx driver did not allow i/o ports >= 0x1000.  Now that
    there are pci cards (with rs232 ports) which use for example 0xb800 this
    limit should not exists.
    
    Also, for non kernel coders find the cause of problems was challenging so I
    added extra logging.
    
    Signed-off-by: Folkert van Heusden <folkert@vanheusden.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4eccccb36223be5271b550a9ba4722a1e72c9312
Author: Jean Delvare <khali@linux-fr.org>
Date:   Mon Mar 26 21:47:22 2007 -0800

    strlcpy is smart enough
    
    strlcpy already accounts for the trailing zero in its length
    computation, so there is no need to substract one to the buffer size.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Cc: Jan-Bernd Themann <themann@de.ibm.com>
    Cc: Thomas Klein <osstklei@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a3fa3aba7a0e00aa1cbb13c9e9bed162fa057973
Author: Daniel Drake <dsd@gentoo.org>
Date:   Mon Mar 26 01:00:12 2007 +0100

    [PATCH] zd1211rw: Add another ID for Linksys WUSBF54G
    
    Tested by TiCPU on irc
    
    zd1211 chip 13b1:001e v4802 high 00-14-bf AL2230_RF pa0 g---
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 44713b1da5a78d722dc0c03a87dc9ddf46668f80
Author: Daniel Drake <dsd@gentoo.org>
Date:   Mon Mar 26 00:59:47 2007 +0100

    [PATCH] zd1211rw: Don't handle broken frames in monitor mode
    
    Using monitor mode, Johannes Berg observed out that lots of corrupted
    and otherwise invalid frames were being passed to the host.
    
    When in monitor mode we were disabling the hardware filtering here, but
    this is not how monitor mode should work.
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit d2d7c052106ebee75952da4dd547f40a1673d9e0
Author: Daniel Drake <dsd@gentoo.org>
Date:   Mon Mar 26 00:59:18 2007 +0100

    [PATCH] zd1211rw: Mark some data const
    
    This is a backport of Helge Deller's recent patch for wireless-dev.git
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 85d32e7b0ea53a11d2a4018d8ad2605052778df7
Author: Jouni Malinen <j@w1.fi>
Date:   Sat Mar 24 17:15:30 2007 -0700

    [PATCH] Update my email address from jkmaline@cc.hut.fi to j@w1.fi
    
    After 13 years of use, it looks like my email address is finally going
    to disappear. While this is likely to drop the amount of incoming spam
    greatly ;-), it may also affect more appropriate messages, so let's
    update my email address in various places. In addition, Host AP mailing
    list is subscribers-only and linux-wireless can also be used for
    discussing issues related to this driver which is now shown in
    MAINTAINERS.
    
    Signed-off-by: Jouni Malinen <j@w1.fi>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit e542aa6bd50ba163253e60ba8e7e51c0d56162a7
Author: Jan-Bernd Themann <ossthema@de.ibm.com>
Date:   Thu Mar 22 17:50:24 2007 +0100

    ehea: code cleanup
    
    This patch includes:
    
    - code cleanup related to resource management
    - extended error data gathering for resource management
    - removing trailing whitespaces
    
    Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1eef4e04c95fb52a1a3885c8f53a822206fc9aa5
Author: Jan-Bernd Themann <ossthema@de.ibm.com>
Date:   Thu Mar 22 17:49:42 2007 +0100

    ehea: fix for dynamic lpar support
    
    The patch fixes bugs related to the probe / remove adapter
    functionality (handling of OFDT nodes)
    
    Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit d68300182828596016d7a6c0f23a912f07d9d0df
Author: Deepak Saxena <dsaxena@plexity.net>
Date:   Mon Mar 19 15:43:11 2007 -0700

    Netpoll support for Sibyte MAC
    
    NETPOLL support for Sibyte MAC
    
    Signed-off-by: Manish Lachwani <mlachwani@mvista.com>
    Signed-off-by: Deepak Saxena <dsaxena@mvista.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0c61ed5fe2c36b502a716a2ea3dd24e846029287
Author: Ramkrishna Vepa <ram.vepa@neterion.com>
Date:   Fri Mar 9 18:28:32 2007 -0800

    S2io: Remove unused variables
    
    - Remove unused variables from s2io_nic structure
    
    - Changed the memory failure printk messages to print only in debug mode
    
    - Updated the copyright messages
    
    (Resending; due to patch being corrupted)
    
    Signed-off-by: Santosh Rastapur <santosh.rastapur@neterion.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1e2b980fdfb6189baa779ba7de93f7dba70aa3fd
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Sun Mar 18 23:21:22 2007 +0000

    MIPSnet: Modernize use platform_device API.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a5f8f3b6c91b07ee9aa2445a92a1d6c00a71a3cd
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Mar 16 14:01:32 2007 -0700

    skge: version 1.11
    
    New version to track changes.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3f0dec7f6069c308ee7110e29e2b2d63bc5baeea
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Mar 16 14:01:31 2007 -0700

    skge: rearrange fields
    
    Do some minor rearrangement of data structures to try and optimize
    cache usage.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 992c9623b148ba939e9cdba0d668eedd3af1a5d2
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Mar 16 14:01:30 2007 -0700

    skge: transmit locking improvements
    
    Don't need to lock when processing transmit complete unless queue fills.
    Modeled after tg3.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 7e0038a414c38085dfbf352f21006bcca4cd308b
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Mar 16 14:01:29 2007 -0700

    skge: ignore unused error interrupts
    
    The following hardware error bits only show up on Genesis chipset
    and are handled elsewhere, so they can be masked off.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit a0d69f229fedea3f2b510ee8ece985c974860d41
Author: Pavel Roskin <proski@gnu.org>
Date:   Sat Mar 10 22:54:22 2007 -0500

    [PATCH] sparse-annotate radiotap header
    
    Document that all fields must be little endian.  Use annotated types
    even in the comments.  Consistently use shorter type names (u8, s8).
    Realign the comments.
    
    Signed-off-by: Pavel Roskin <proski@gnu.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit d2f11e0991e3794f11d851b7ee0d98e064b10333
Author: Tony Breeds <tony@bakeyournoodle.com>
Date:   Fri Mar 9 13:11:46 2007 +1100

    [PATCH] libertas: use standard kernel macros
    
    Cleanup drivers/net/wireless/libertas/debugfs.c to use standard kernel
    macros and functions.
    
    Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit af5b5c9aa92ced95fca509e775aec90933f8959d
Author: Michal Schmidt <mschmidt@redhat.com>
Date:   Fri Mar 16 12:44:40 2007 +0100

    [PATCH] airo: Make /sys/bus/pci/drivers/airo/{,un}bind work
    
    The way airo.c keeps track of all its devices is complicated and buggy
    as well (del_airo_dev forgets to free the memory add_airo_dev allocates).
    It's cleaner to use the standard list primitives.
    While we're at it, it's not necessary to put PCI cards in the list, because
    the kernel already keeps track of them. We can take advantage of it and
    use the .remove callback as it was meant to be.
    This makes /sys/bus/pci/drivers/airo/{,un}bind work.
    
    Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit fd48f8d3a3e147e666d838194d5f9de64403ecb1
Author: Michal Schmidt <mschmidt@redhat.com>
Date:   Fri Mar 16 12:40:00 2007 +0100

    [PATCH] airo: Don't check for NULL before kfree()
    
    It's unnecessary to check for NULL before calling kfree().
    
    Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit aa93c85d09295dcb269fc1a0690d9ddfb58f46cc
Author: Larry Finger <Larry.Finger@lwfinger.net>
Date:   Wed Mar 14 15:06:22 2007 -0500

    [PATCH] bcm43xx:Eliminate some 'G Mode Enable' magic numbers
    
    In code manipulating the TM State Low register of 802.11 cores, two
    different magic numbers are used to reference the 'G Mode Enable' bit.
    One of these, 0x20000000, is clear, but the other, (0x800 << 18), is not.
    This patch replaces both types with a defined constant. In addition, two
    bits in the TM State High registers are given definitions to help in
    following the code.
    
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit aec91028db71cae7efa1101cf2e38c407096f023
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sun Mar 11 19:54:39 2007 +0000

    [PATCH] zd1211rw: More device IDs
    
    ASUS A9Rp
    Tested by Serge
    zd1211b chip 0b05:171b v4802 high 00-17-31 AL2230_RF pa0 g--
    
    ZyXEL G-202
    Tested by Marcus D. Hanwell
    zd1211b chip 0586:3410 v4810 high 00-13-49 AL2230_RF pa0 g---
    
    US Robotics USR805423
    Tested by Pascal S. de Kloe
    FCC ID: RAXWN4501H
    zd1211b chip 0baf:0121 v4810 high 00-14-c1 AL2230_RF pa0 g--N
    Julien Pinon reports this also comes in AL2230S form
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit f2a81a161d5089fe838ec6c4c7b6357f25aeacbe
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sun Mar 11 19:54:28 2007 +0000

    [PATCH] zd1211rw: Add AL2230S RF support
    
    ZD1211 appears to be back in production: a number of new devices have
    been appearing! Some of them are using new radios.
    
    This patch adds support for the next generation AL2230 RF chip which has
    been spotted in a few new devices.
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 832855dc5a9beb78644d6163f94eccf2094bf30d
Author: Daniel Drake <dsd@gentoo.org>
Date:   Sun Mar 11 19:53:40 2007 +0000

    [PATCH] zd1211rw: Use compare_ether_addr()
    
    Suggested by Maxime Austruy, based on mac80211 changes from Stephen
    Hemminger
    
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 6bab99be917054736097b758489a9ea27fd44245
Author: Valerie Henson <val_henson@linux.intel.com>
Date:   Mon Mar 12 02:31:34 2007 -0700

    Rev tulip version
    
    Rev tulip version... things have changed since 2002!
    
    Signed-off-by: Valerie Henson <val_henson@linux.intel.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1ddb98618d5b797cb5300f093c1df1f38f79d9ba
Author: Valerie Henson <val_henson@linux.intel.com>
Date:   Mon Mar 12 02:31:33 2007 -0700

    Fix tulip SytemError typo
    
    Fix an annoying typo - SytemError -> SystemError
    
    Signed-off-by: Valerie Henson <val_henson@linux.intel.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit eb117b1786804f2e128b871879ffe8f6a2701378
Author: Thibaut VARENE <T-Bone@parisc-linux.org>
Date:   Mon Mar 12 02:31:30 2007 -0700

    TULIP: Natsemi dp83840a PHY fix
    
    Fix a problem with Tulip 21142 HP branded PCI cards (PN#: B5509-66001),
    which feature a NatSemi DP83840A PHY.
    
    Without that patch, it is impossible to properly initialize the card's PHY,
    and it's thus impossible to monitor/configure it.
    
    [VAL: I'm happy with the 1.5 ms max delay; it doesn't seem excessive.]
    
    Signed-off-by: Thibaut VARENE <varenet@parisc-linux.org>
    Cc: Jeff Garzik <jgarzik@pobox.com>
    Acked-by: Grant Grundler <grundler@parisc-linux.org>
    Signed-off-by: Valerie Henson <val_henson@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit b3bff39a2b3574542f5007e19038393dfdd64c85
Author: Valerie Henson <val_henson@linux.intel.com>
Date:   Mon Mar 12 02:31:29 2007 -0700

    TULIP: Fix for 64-bit MIPS
    
    From: Jim Gifford <maillist@jg555.com>, Grant Grundler <grundler@parisc-linux.org>, Peter Horton <pdh@colonel-panic.org>
    
    With Grant's help I was able to get the tulip driver to work with 64 bit
    MIPS.
    
    [VAL: I'm happy with the 1.5 ms max delay; it doesn't seem excessive.]
    
    Signed-off-by: Valerie Henson <val_henson@linux.intel.com>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Cc: Jeff Garzik <jgarzik@pobox.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c28896a4244e2fbe28c94e3a6048625f5c15cab4
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Thu Mar 15 00:10:37 2007 +0900

    tc35815: Zap changelog from source code
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 793bc0afbdccd97e66b2bdf43c2ce5653140ee5e
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Wed Mar 14 01:02:20 2007 +0900

    tc35815: Fix an usage of streaming DMA API.
    
    The tc35815 driver lacks a call to pci_dma_sync_single_for_device() on
    receiving.  Recent fix of MIPS dma_sync_single_for_cpu() reveal this
    bug.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1e56a4b4029dd1cabf73f28970b5c11bcbae6bb7
Author: Don Fry <pcnet32@verizon.net>
Date:   Tue Mar 6 10:55:00 2007 -0800

    pcnet32: change to use netdev_priv
    
    use netdev_priv() instead of dev->priv
    
    Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
    Signed-off-by: Don Fry <pcnet32@verizon.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 6ecb766710e5128e3b8f3c775f907dcb8fead8d1
Author: Don Fry <pcnet32@verizon.net>
Date:   Tue Mar 6 10:45:23 2007 -0800

    pcnet32: only allocate init_block dma consistent
    
    The patch below moves the init_block out of the private struct and
    only allocates init block with pci_alloc_consistent.
    
    This has two effects:
    
    1. Performance increase for non cache coherent machines, because the
       CPU only data in the private struct are now cached
    
    2. locks are working now for platforms, which need to have locks
       in cached memory
    
    Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
    Acked-by: Don Fry <pcnet32@verizon.net>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1c8816c6fe375ed3a1e342fcf7f403cd4f0d5041
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Tue Mar 6 11:08:28 2007 -0800

    ixgb: Use ARRAY_SIZE macro when appropriate.
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 363dc36733b06a94d3dce7c43b56c888f6d185de
Author: Ramkrishna Vepa <ram.vepa@neterion.com>
Date:   Tue Mar 6 17:01:00 2007 -0800

    S2IO: Save/Restore unused buffer mappings in 2/3 buffer mode
    
    - Save/Restore unused buffer mappings in 2/3 buffer mode to avoid
    frequent mapping
    
    - Save/Restore adapter reset count during adapter reset
    
      (Resending; forgot to cc netdev)
    
    Signed-off-by: Santosh Rastapur <santosh.rastapur@neterion.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit dcd01faf66372f1806451422ad67b06adcc68f82
Author: Auke Kok <auke-jan.h.kok@intel.com>
Date:   Tue Mar 6 08:58:06 2007 -0800

    e1000: list e1000-devel mailing list in MAINTAINERS
    
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1c7e5b125a0d31efd994326ed4c6d60c5760c43b
Author: Yan Burman <burman.yan@gmail.com>
Date:   Tue Mar 6 08:58:04 2007 -0800

    e1000: Use kcalloc()
    
    Replace kmalloc+memsetout the driver. Slightly modified by Auke Kok.
    
    Signed-off-by: Yan Burman <burman.yan@gmail.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit c38db30b22913394f4634dc09f32d7838eb52ca1
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Tue Mar 6 08:58:02 2007 -0800

    e1000: Use ARRAY_SIZE macro when appropriate
    
    A patch to use ARRAY_SIZE macro already defined in kernel.h.
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 024a0a3cfb4c98cb3c6c81ec70672c6a925cf164
Author: Shan Lu <shanlu@cs.uiuc.edu>
Date:   Tue Mar 6 02:42:03 2007 -0800

    network: add the missing phy_device speed information to phy_mii_ioctl
    
    Function `phy_mii_ioctl' returns physical device's information based on
    user requests.  When requested to return the basic mode control register
    information (BMCR), the original implementation only returns the physical
    device's duplex information and forgets to return speed information, which
    should not be because BMCR register is used to hold both duplex and speed
    information.
    
    The patch checks the BMCR value against speed-related flags and fills the
    return structure's speed field accordingly.
    
    Signed-off-by: Shan <shanlu@cs.uiuc.edu>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 2b272221ad3d5c686f1d5ffb3b3c8a45120ad765
Author: Dmitriy Monakhov <dmonakhov@openvz.org>
Date:   Tue Mar 6 02:42:01 2007 -0800

    sk98lin: handle pci_enable_device() return value in skge_resume()
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit f1069046b4c7a5750611305433646c1bff3686fd
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Tue Mar 6 02:41:54 2007 -0800

    dmfe: add support for Wake on lan
    
    Add support for WOL on Magic Packet and on link change
    
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Cc: Valerie Henson <val_henson@linux.intel.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit bc8a8387ba57db2275e717c19838a8d5a404c270
Author: Maxim Levitsky <maximlevitsky@gmail.com>
Date:   Tue Mar 6 02:41:53 2007 -0800

    dmfe: add support for suspend/resume
    
    This adds support for suspend resume
    
    [akpm@linux-foundation.org: fix CONFIG_PM=n, coding style]
    Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
    Cc: Valerie Henson <val_henson@linux.intel.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit b3df0da886ffdb3e70c3197f589e959e5f8c9c04
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue Mar 6 02:41:48 2007 -0800

    phy layer: add kernel-doc + DocBook
    
    Convert function documentation in drivers/net/phy/ to kernel-doc
    and add it to DocBook.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 56e1393f82349d8206fe7feb94db96b065c55e51
Author: Arjan van de Ven <arjan@linux.intel.com>
Date:   Tue Mar 6 02:41:48 2007 -0800

    user of the jiffies rounding code: e1000
    
    Use the round_jiffies() function in e1000.
    
    These timers all were of the "about once a second" or "about once every X
    seconds" variety and several showed up in the "what wakes the cpu up" profiles
    that the tickless patches provide.  Some timers are highly dynamic based on
    network load; but even on low activity systems they still show up so the
    rounding is done only in cases of low activity, allowing higher frequency
    timers in the high activity case.
    
    The various hardware watchdogs are an obvious case; they run every 2 seconds
    but aren't otherwise specific of exactly when they need to run.
    
    Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
    Acked-by: Auke Kok <auke-jan.h.kok@intel.com>
    Cc: Jeff Garzik <jeff@garzik.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit eea221ce48803a92e2319270b2b7b8e21cd470ca
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Sat Mar 3 23:54:59 2007 +0900

    tc35815 driver update (take 2)
    
    Current tc35815 driver is very obsolete and less maintained for a long
    time.  Replace it with a new driver based on one from CELF patch
    archive.
    
    Major advantages of CELF version (version 1.23, for kernel 2.6.10) are:
    
    * Independent of JMR3927.
      (Actually independent of MIPS, but AFAIK the chip is used only on
       MIPS platforms)
    * TX4938 support.
    * 64-bit proof.
    * Asynchronous and on-demand auto negotiation.
    * High performance on non-coherent architecture.
    * ethtool support.
    * Many bugfixes and cleanups.
    
    And improvoments since version 1.23 are:
    
    * TX4939 support.
    * NETPOLL support.
    * NAPI support. (disabled by default)
    * Reduce memcpy on receiving.
    * PM support.
    * Many cleanups and bugfixes.
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 3664006ab9d90caca5c195e11a2b2e400d454265
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 5 02:49:27 2007 +0100

    drivers/net/qla3xxx.c: make 2 functions static
    
    This patch makes two needlessly global functions static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 7b49034399bfbf4eaaa3e0447d325e8f3a132209
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 5 02:49:25 2007 +0100

    make drivers/net/s2io.c:vlan_strip_flag static
    
    This patch makes the needlessly global vlan_strip_flag static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 78ee5b3cc88297bb98843c24b231e99f3f2886a0
Author: Ladislav Michl <ladis@linux-mips.org>
Date:   Wed Feb 28 01:18:35 2007 +0000

    Add support for Seeq 8003 on Challenge S Mezz board.
    
    Thanks to JÃ¶ Fahlke for donating hardware.
    
    Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
    
    Forward porting of Ladis' 2.4 patch.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 18604c54854549ee0ad65e27ca9cb91c96af784c
Author: Jan-Bernd Themann <ossthema@de.ibm.com>
Date:   Wed Feb 28 18:34:10 2007 +0100

    ehea: NAPI multi queue TX/RX path for SMP
    
    This patch provides a functionality that allows parallel
    RX processing on multiple RX queues by using dummy netdevices.
    
    Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1acf2318dd136edfbfa30f1f33b43f69f2e2ec6c
Author: Jan-Bernd Themann <ossthema@de.ibm.com>
Date:   Wed Feb 28 18:34:02 2007 +0100

    ehea: dynamic add / remove port
    
    This patch introduces functionality to dynamically add / remove
    ehea ports via an userspace DLPAR tool. It creates a subnode for
    each logical port in the sysfs.
    
    Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 459e536b1ddfd217ec8a3437a3214968a98223c7
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Tue Feb 20 15:58:02 2007 -0800

    chelsio: use const for virtual functions
    
    There are several uses of _ops structure in this driver that
    can be converted to const.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4c247db114d95fb42528afe4c16db522dd050d7b
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Tue Feb 20 15:58:01 2007 -0800

    chelsio: use C99 style initialization
    
    Convert some initialized structures to C99 style.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 4d2b8f66b89dd74d76d2b40cb45dffaa5567bb8f
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Tue Feb 20 15:58:00 2007 -0800

    chelsio: remove unused code for 1G boards
    
    Some code for Chelsio 1G boards was put in the driver
    based on the vendor version (minus TOE). Well some of those board
    versions are only supported with TOE on the vendor driver, so additional
    dead code was added.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 0ae08183d89fa48c0e4be019f45b93ad638c3890
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Sat Mar 3 23:55:08 2007 -0600

    [PATCH] bcm43xx: do not rebuild when kernel version changes
    
    In bcm43xx_ethtool, UTS_RELEASE is used. Replacing this with utsname()->release
    avoids rebuilding this module each time the kernel version changes.
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 99d3184ac7b4e91c88073f474ebe758540b3ad82
Author: Jouni Malinen <jkmaline@cc.hut.fi>
Date:   Tue Feb 27 19:46:46 2007 -0800

    [PATCH] hostap: Add D-Link DWL-650 Rev. P1 product id
    
    It looks like some of the PC Card manfid/product strings were lost
    when Host AP driver was converted to use PCMCIA_DEVICE_* helpers. This
    patch adds back D-Link DWL-650 Rev. P1 using the same product ID
    string match as the pcmcia-cs/cardmgr configuration used before.
    
    Signed-off-by: Jouni Malinen <jkmaline@cc.hut.fi>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 742e9910d68a338189de8b5be77ae1d141f3851f
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Mar 1 08:19:29 2007 -0500

    [PATCH] ipw2200: fix ieee80211_get_geo typo
    
    testing much?
    
    Cc: Zhu Yi <yi.zhu@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit b3f1b8cf11e412367a35045a60abbbd2ada5f75d
Author: John W. Linville <linville@tuxdriver.com>
Date:   Tue Feb 27 14:39:04 2007 -0500

    [PATCH] libertas: fix build breakage from netdev class_device -> device
    
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit ebb4e07e351e456216681f9bcf6bc4a5f0f7f55b
Author: John W. Linville <linville@tuxdriver.com>
Date:   Tue Feb 27 13:41:26 2007 -0500

    [PATCH] wireless: remove obsolete text files
    
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 70a734391a7e12ae177f703b8caf37c7f2014682
Author: Larry Finger <Larry.Finger@lwfinger.net>
Date:   Tue Feb 20 10:33:13 2007 -0600

    [PATCH] bcm43xx: Update Documentation/bcm43xx.txt
    
    The in-kernel documentation of the bcm43xx driver is out of date.
    
    Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit c6710e50f6b976dead878e143c568d4f8b068c7c
Author: Pavel Roskin <proski@gnu.org>
Date:   Sun Feb 18 20:44:06 2007 -0500

    [PATCH] hostap: use offsetof() instead of own equivalent
    
    The original macros result in gcc 4.2 warning about "cast from pointer
    to integer of different size" on 64-bit systems.
    
    Use of offsetof() on fields in substructures is widespread throughout
    the kernel code and should work whether offsetof() is defined using
    __compiler_offsetof() or a cast.
    
    Signed-off-by: Pavel Roskin <proski@gnu.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 876c9d3aeb989cf1961f2c228d309ba5dcfb1172
Author: Marcelo Tosatti <marcelo@kvack.org>
Date:   Sat Feb 10 12:25:27 2007 -0200

    [PATCH] Marvell Libertas 8388 802.11b/g USB driver
    
    Add the Marvell Libertas 8388 802.11 USB driver.
    
    Signed-off-by: Marcelo Tosatti <marcelo@kvack.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 35c3404efa7407811b706453f83d39b2539dcbd0
Author: Ulrich Kunitz <kune@deine-taler.de>
Date:   Sun Feb 18 20:28:23 2007 +0000

    [PATCH] zd1211rw: changed GFP_NOFS to GFP_KERNEL
    
    Michael Buesch commented that GFP_NOFS should not be used in a
    network driver.
    
    Signed-off-by: Ulrich Kunitz <kune@deine-taler.de>
    Signed-off-by: Daniel Drake <dsd@gentoo.org>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 375dd24428cfe900f4ed95d301fe604f8e0d459b
Author: Zhu Yi <yi.zhu@intel.com>
Date:   Wed Feb 14 16:04:24 2007 +0800

    [PATCH] ipw2200: add channels sysfs entry
    
    Add 'channels' sysfs entry for ipw2200. The entry exports channels
    information for the user space.
    
    Signed-off-by: Zhu Yi <yi.zhu@intel.com>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>

commit 3e18c8dd0d3456f96e13bc2e72197bfae11d8501
Author: Sam Ravnborg <sam@ravnborg.org>
Date:   Thu Apr 26 00:04:39 2007 -0700

    [ARM] fix section mismatch warning in board-sam9260
    
    Andrew Morton found a section mismatch warning in x86_64 triggered by a
    wrongly placed __initdata marker.
    
    git grep "struct __initdata" revealed that board-sam9260.c had the same
    problem.
    
    This patch fixes this by placing the __initdata marker correct.  It was
    checked with objdump that the variable was moved to .init.data by this
    change.
    
    Fixed an unrelated section mismatch warning while touching the file.
    
    Both changes are only compile tested but obvious correct.
    [Used at91sam9260ek_defconfig to get compile coverage]
    
    Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit f16fb1ecc5a1cb2f7cc595179d1fe55e711e599f
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 28 09:59:37 2007 +0100

    [ARM] Add stacktrace support and make oprofile use it
    
    Add support for stacktrace.  Use the new stacktrace code with
    oprofile instead of it's version; there's no point having
    multiple versions of stacktracing in the kernel.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit dc5a144991ba803bc8afded105c9db1dea0e57ab
Author: Neil Horman <nhorman@tuxdriver.com>
Date:   Thu Apr 26 13:47:36 2007 -0400

    sis900: Allocate rx replacement buffer before rx operation
    
    Just found a hole in my last patch.  It was reported to me that shortly after we
    integrated this patch.  The report was of an oops that took place inside of
    netif_rx when using the sis900 driver.  Looking at my origional patch I noted
    that there was a spot between the new skb_alloc and the refill_rx_ring label
    where skb got reassigned to the pointer currently held in the rx_ring for the
    purposes of receiveing the frame.  The result of this is however that the buffer
    that gets passed to netif_rx (if it is called), then gets placed right back into
    the rx_ring.  So if you receive frames fast enough the skb being processed by
    the network stack can get corrupted.  The reporter is testing out the fix I've
    written for this below (I'm not near my hardware at the moment to test myself),
    but I wanted to post it for review ASAP.  I'll post test results when I hear
    them, but I think this is a pretty straightforward fix.  It just uses a separate
    pointer to do the rx operation, so that we don't improperly reassign the pointer
    that we use to refill the rx ring.
    
    Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 1764f15016fea54db723a96234a82646dac9a036
Author: Dan Williams <dcbw@redhat.com>
Date:   Wed Apr 25 21:30:29 2007 -0400

    usb-net/pegasus: simplify carrier detection
    
    Simplify pegasus carrier detection; rely only on the periodic MII
    polling.  Reverts pieces of c43c49bd61fdb9bb085ddafcaadb17d06f95ec43.
    
    Signed-off-by: Dan Williams <dcbw@redhat.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 28b57cddb3ed4f7999e4b76ef36ebaaf6e2e0c37
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 27 01:48:01 2007 +0200

    [MTD] [MAPS] drivers/mtd/maps/ck804xrom.c: convert pci_module_init()
    
    This patch converts the pci_module_init() usage to pci_register_driver().
    
    It's currently #if 0'ed, but still not a bad idea to change it.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit b8b8fd2dc23725fba77f66b3fef11b11f983fc08
Author: David Howells <dhowells@redhat.com>
Date:   Fri Apr 27 15:31:24 2007 -0700

    [NET]: Fix networking compilation errors
    
    Fix miscellaneous networking compilation errors.
    
     (*) Export ktime_add_ns() for modules.
    
     (*) wext_proc_init() should have an ANSI declaration.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b1bdb691c3c38b4fbaf99fa8474f5cfa99b2d774
Author: David Howells <dhowells@redhat.com>
Date:   Fri Apr 27 15:28:45 2007 -0700

    [AF_RXRPC/AFS]: Arch-specific fixes.
    
    Fixes for various arch compilation problems:
    
     (*) Missing module exports.
    
     (*) Variable name collision when rxkad and af_rxrpc both built in
         (rxrpc_debug).
    
     (*) Large constant representation problem (AFS_UUID_TO_UNIX_TIME).
    
     (*) Configuration dependencies.
    
     (*) printk() format warnings.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 47051a2152f8b2355ee70249a0faaf7b682e8ce5
Author: David Howells <dhowells@redhat.com>
Date:   Fri Apr 27 15:26:30 2007 -0700

    [AFS]: Fix VLocation record update wakeup
    
    Fix the wakeup transitions after a VLocation record update completes
    one way or another.  This builds on Dave Miller's partial fix.
    
    Also move wakeups outside the spinlocked sections.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1a028e50729b85d0a038fad13daf0ee201a37454
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Fri Apr 27 15:21:23 2007 -0700

    [NET]: Revert sk_buff walker cleanups.
    
    This reverts eefa3906283a2b60a6d02a2cda593a7d7d7946c5
    
    The simplification made in that change works with the assumption that
    the 'offset' parameter to these functions is always positive or zero,
    which is not true.  It can be and often is negative in order to access
    SKB header values in front of skb->data.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e1f2a094bdfa8e7ecc31f048e6c6dbea2b4f5f74
Author: Alexey Dobriyan <adobriyan@gmail.com>
Date:   Fri Apr 27 15:19:27 2007 -0700

    [SCSI] esp_scsi.c: Fix compilation.
    
    irqreturn.h for irqreturn_t and dma_addr_t being u128 warnings ;-)
    
    Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 54d33c4c715b80cc022b8e4974a4de693c96fc99
Author: Mike Rapoport <mike@compulab.co.il>
Date:   Sun Apr 22 08:53:21 2007 +0300

    [MTD] [NAND] CM-x270 MTD driver
    
    This patch provides MTD support for NAND flash devices on CM-x270 modules.
    
    Signed-off-by: Mike Rapoport <mike@compulab.co.il>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit a7205b30106a2d4ee268132644cdb292da2d9b41
Author: Li Yang <leoli@freescale.com>
Date:   Mon Apr 23 10:38:18 2007 -0700

    USB: update MAINAINERS and CREDITS for Freescale USB driver
    
    Add MAINAINERS and CREDITS entry for Freescale Highspeed USB device
    driver.
    
    Signed-off-by: Li Yang <leoli@freescale.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit d2eef1fc99640f7de302dcdbcfbdfcec2eef13f6
Author: Li Yang <leoli@freescale.com>
Date:   Mon Apr 23 10:37:36 2007 -0700

    USB: update gadget files for fsl_usb2_udc driver
    
    Update gadget_chip.c, ether.c for newly added Freescale Highspeed USB
    device driver.
    
    Signed-off-by: Li Yang <leoli@freescale.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b504882da539c17ce6fee9da2a97f2fafabd495d
Author: Li Yang <leoli@freescale.com>
Date:   Mon Apr 23 10:54:25 2007 -0700

    USB: add Freescale high-speed USB SOC device controller driver
    
    Freescale high-speed USB SOC can be found on some Freescale processors
    among different architectures.  It supports both host and device functions.
    This driver adds its device support for Linux USB Gadget layer.
    It is tested on MPC8349 and MPC8313, but should work on other platforms
    with minor tweaks.  The driver passed USBCV 1.3 compliance tests.  Note
    that this driver doesn't yet include OTG support.
    
    Signed-off-by: Li Yang <leoli@freescale.com>
    Signed-off-by: Jiang Bo <tanya.jiang@freescale.com>
    Signed-off-by: Bruce Schmid <duck@freescale.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 33f73e56198457c38789e08c47d2af47174c1d8f
Author: Raphael Assenat <raph@8d.com>
Date:   Tue Apr 17 13:09:18 2007 -0700

    USB: quirk for broken suspend of IT8152F/G
    
    Here's a patch which adds my device to the list.
    
    This patch enables the broken suspend quirk for the PCI OHCI controller
    present in the IT8152F/G RISC-to-PCI Companion Chip.
    
    Signed-off-by: Raphael Assenat <raph@8d.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 147c5a17338fc72a89452f0a6c14ae6fcf853919
Author: Eberhard Fahle <e.fahle@wayoda.org>
Date:   Thu Apr 5 11:13:21 2007 +0200

    USB: iowarrior.c: timeouts too small in usb_control_msg calls
    
    The driver uses usb_control_msg() for exchanging data with the device.
    When the driver lived freeley _outside_ the kernel tree (pre 2.6.21) the
    timeouts for these calls where set to 5*HZ for reading, 1HZ for writing.
    (These timeouts seemed to work fine for all users of the driver, at
    least nobody complained in the last 2 years.
    
    The current code (2.6.21-rc5) removed the 'HZ' from the timeouts and
    left the driver with 5 jiffies for reading and 1 jiffy for writing. My
    new machine is fast, but not that fast.
    
    The patch also removes a useless debug statement, which was left over
    from testing a broken firmware version
    
    From: Eberhard Fahle <e.fahle@wayoda.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit a03c6facf84a51a04958d75ceef443108c44872d
Author: Hans Engelen <engelenh@gmail.com>
Date:   Thu Apr 12 14:40:26 2007 +0200

    USB: dell device id for option.c
    
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 862e9043776578d575494db79d9189795350ed67
Author: Phil Dibowitz <phil@ipom.com>
Date:   Sun Apr 15 23:42:40 2007 -0700

    USB: Remove Huawei unusual_devs entry
    
    Per the Rui Santos and the hardware manufacturers, this actually inhibits
    useful parts of the hardware. The correct way to use this hardware is with the
    software at http://www.kanoistika.sk/bobovsky/archiv/umts/ and the manufacturers
    are also planning on including Linux drivers/material in future revisions.
    
    CC: Rui Santos <rsantos@grupopie.com>
    CC: <johann.wilhelm@student.tugraz.at>
    CC: <zihan@huawei.com>
    CC: <wanganyu1983@huawei.com>
    CC: <dingjianjian@huawei.com>
    Signed-off-by: Phil Dibowitz <phil@ipom.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 92f5cae2e8914d2d762728dd7629e5121ba070f3
Author: Craig Shelley <craig@microtron.org.uk>
Date:   Fri Apr 20 14:37:17 2007 +0100

    USB: CP2101 New Device IDs
    
    Two new device IDs for CP2101 driver.
    
    Signed-off-by: Craig Shelley <craig@microtron.org.uk>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 79dcdbf67d8885375711c4f2261168fa87389a31
Author: Joey Goncalves <jgoncalves@peragrin.com>
Date:   Fri Apr 20 11:05:54 2007 -0700

    USB: add picdem device to ldusb
    
    Hi Greg:
    
    I have found that  /drivers/usb/misc/ldusb.c  works with the "PICDEM Full
    Speed USB"
    http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en021940
    
    
    Signed-off-by: Joey S Goncalves <jgoncalves@peragrin.com>
    Cc: Michael Hund <MHund@LD-Didactic.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 527660a819f513edc52fea6bcb4068ce1d4d966b
Author: Oliver Neukum <oliver@neukum.org>
Date:   Fri Apr 20 20:50:48 2007 +0200

    usbfs micro optimitation
    
    the memory barrier is needed only with smp.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1b101ceb9162086035ce0c9cbe83ca7b4845179a
Author: David Brownell <david-b@pacbell.net>
Date:   Sun Apr 22 11:05:52 2007 -0700

    USB: remove ancient/broken CRIS hcd
    
    Remove the old crisv10 HCD ... it can't have built for some time,
    doesn't even have a Kconfig entry, was the last driver not to have
    been converted to the "hcd" framework, and considering the usbcore
    changes since its last patch was merged, has just got to buggy as
    all get-out.
    
    I'm told Axis has a new driver, and will be submitting it soon.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: Mikael Starvik <mikael.starvik@axis.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b8d297c93a888fcd4d74ba0bbeeabe9b84caf514
Author: Erik Hovland <erik@hovland.org>
Date:   Mon Apr 23 10:50:15 2007 -0700

    usb ethernet gadget, workaround network stack API glitch
    
    Another workaround for the glitch in the network layer, whereby one call
    ignores the (otherwise kernel-wide) convention that free() calls should
    not oops when passed nulls.  This code already handles that API glitch in
    most other paths.
    
    From: Erik Hovland <erik@hovland.org>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 83f7d958eab2fbc6b159ee92bf1493924e1d0f72
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Wed Apr 25 15:15:43 2007 -0400

    USB: add "busnum" attribute for USB devices
    
    This patch (as903) adds a "busnum" sysfs attribute for USB devices.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 6a02c996bce297a782432e29c69268356e97fadd
Author: Simon Arlott <simon@fire.lp0.eu>
Date:   Thu Apr 26 00:38:05 2007 -0700

    USB: cxacru: ADSL state management
    
    The device has commands to start/stop the ADSL function, so this adds a
    sysfs attribute to allow it to be started/stopped/restarted.  It also stops
    polling the device for status when the ADSL function is disabled.
    
    There are no problems with sending multiple start or stop commands, even
    with a fast loop of them the device still works.  There is no need to
    protect the restart process from further user actions while it's waiting
    for 1.5s.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Cc: Duncan Sands <duncan.sands@math.u-psud.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7d5e1dd40bd5ced457be178e4f0b1267a3df2142
Author: Simon Arlott <simon@fire.lp0.eu>
Date:   Thu Apr 26 00:38:04 2007 -0700

    usbatm: Detect usb device shutdown and ignore failed urbs
    
    Detect usb device shutdown and ignore failed urbs.  This happens when the
    driver is unloaded or the device is unplugged.
    
    I'm not sure what other urb statuses should be ignored, and the warning
    message doesn't need to be shown when the module is unloaded or the device
    is removed.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Cc: Duncan Sands <duncan.sands@math.u-psud.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5c975acb99168827a8ce5453be0e44ad2e4b70b2
Author: S.Caglar Onur <caglar@pardus.org.tr>
Date:   Thu Apr 26 00:38:03 2007 -0700

    USB: Remove duplicate define of OHCI_QUIRK_ZFMICRO
    
    Remove duplicate define of OHCI_QUIRK_ZFMICRO from ftdi-elan.c, its already
    defined in drivers/ush/host/ohci.c
    
    Signed-off-by: "S.Caglar Onur" <caglar@pardus.org.tr>
    Cc: <tony.olech@elandigitalsystems.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 3f6e58467c635ebbb4a139cbe5e0c1f46792e18c
Author: Leon Leong <upleong@bandrich.com>
Date:   Thu Apr 26 00:38:02 2007 -0700

    USB: BandRich BandLuxe HSDPA Data Card Driver
    
    Add the detection for the BandRich BandLuxe C100/C100S/C120 HSDPA Data
    Card.  With the vendor and product IDs are set properly, the data card can
    be detected and works fine.
    
    Signed-off-by: Leon Leong <upleong@bandrich.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 178398dca00b276aaa1aded7cded89921f710365
Author: Wu, Bryan <bryan.wu@analog.com>
Date:   Thu Apr 26 00:38:01 2007 -0700

    USB gadget rndis: fix struct rndis_packet_msg_type unaligned bug
    
    skb_push function may return a pointer which is not aligned as required
    by struct rndis_packet_msg_type. Using attribute trick to fix this bug.
    
    Signed-off-by: Roy Huang <roy.huang@analog.com>
    Signed-off-by: Jie Zhang <jie.zhang@analog.com>
    Signed-off-by: Bryan Wu <bryan.wu@analog.com>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 893a342a686e6ce36ef24d322f3f52420a041313
Author: Cyrill Gorcunov <gorcunov@gmail.com>
Date:   Thu Apr 26 00:38:00 2007 -0700

    USB Elan FTDI: check for driver registration status
    
    Add checking of driver registration status and release allocated resources
    if it failed.
    
    Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
    Cc: Pete Zaitcev <zaitcev@redhat.com>
    Cc: "Luiz Fernando N. Capitulino" <lcapitulino@mandriva.com.br>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f094e4f358c2f9f0a46dc777f64ed7794f73d283
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Thu Apr 26 00:12:01 2007 -0700

    USB: sierra: add more checks on shutdown
    
    This should help with any potential NULL pointer usages as reported by a
    few users.
    
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 931384fb0ec99a7459b3052f5d4db15bcb5037ea
Author: David Brownell <david-b@pacbell.net>
Date:   Tue Apr 17 13:06:29 2007 -0700

    USB: add an ohci board-specific quirk
    
    Use the new ohci-pci quirk infrastructure to address the problem it was
    created to address: a quirk specific to the Portege 4000, in buzilla as
    
    	http://bugzilla.kernel.org/show_bug.cgi?id=6723
    
    Also fix a misuse of "__devinit" for the quirk functions.  It must not
    be used without first ensuring that the references from the quirk tables
    are gone, and that the function using those quirk tables is also gone.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 296c02429271e1b9525b52fed76daa3b1cafefc4
Author: David Brownell <david-b@pacbell.net>
Date:   Tue Apr 17 16:10:10 2007 -0700

    USB: usbnet reports minidriver name through ethtool
    
    Update "usbnet" so that ethtool reports the name of the minidriver in use
    (e.g. asix, cdc_ether, dm9601, rndis_host) instead of "usbnet".  This is a
    better match to how other network drivers work, resolving a minor open issue.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ddda08624013e8435e9f7cfc34a35bd7b3520b6d
Author: David Brownell <david-b@pacbell.net>
Date:   Tue Apr 17 17:53:20 2007 -0700

    USB: rndis_host, various cleanups
    
    Cleanups to the rndis_host code, and a tweak that helps talking to
    PXA hardware.  Mostly from Ole AndrÃ© Vadla RavnÃ¥s <oleavr@gmail.com>
    
      - Prevent SET_INTERFACE requests, they give PXA hardware bad indigestion
      - For paranoia, null a pointer after freeing its data
      - Wrap up ActiveSync oddities for RNDIS_QUERY in one routine
      - Use that wrapper when getting the Ethernet address
      - Whitespace fixes
    
    Plus add a comment noting the open issues about some RNDIS clients still
    needing TBD kinds of browbeating to accept non-jumbogram packets.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit aa2ce5ca6be480cb139e21258671c2c27826f8ff
Author: David Brownell <david-b@pacbell.net>
Date:   Tue Apr 17 17:51:38 2007 -0700

    USB: <linux/usb/ch9.h> minor doc update
    
    Minor doc update to <linux/usb/ch9.h> ... say where USB_DT_CS_* came
    from and update the definitions to match how they're derived there.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 8c9862e512f59ae3f41f83c109be12f93e37bb2d
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Wed Apr 11 12:06:16 2007 -0400

    USB: fix signed jiffies issue in autosuspend logic
    
    This patch (as897) changes the autosuspend timer code to use the
    standard types and macros in dealing with jiffies values.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ecb658d387dc09f344b3d755e8674076072032c7
Author: Pete Zaitcev <zaitcev@redhat.com>
Date:   Wed Apr 11 13:47:26 2007 -0700

    usbmon: bus zero
    
    Add the "bus zero" feature to the usbmon. If a user process specifies bus
    with number zero, it receives events from all buses. This is useful when
    we wish to see initial enumeration when a bus is created, typically after
    a modprobe. Until now, an application had to loop until a new bus could
    be open, then start capturing on it. This procedure was cumbersome and
    could lose initial events. Also, often it's too bothersome to find exactly
    to which bus a specific device is attached.
    
    Paolo Albeni provided the original concept implementation. I added the
    handling of "bus->monitored" flag and generally fixed it up.
    
    Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 35d07fd58f47284adecf219d3b73e4ea197cf29f
Author: Tony Lindgren <tony@atomide.com>
Date:   Sat Mar 31 18:15:43 2007 -0700

    USB: Allow transfer_buffer with transfer_dma
    
    Some host controller drivers may need a PIO fallback when a DMA channel
    is temporarily unavailable.  This patch provides an address that such
    drivers can use for PIO in those cases, and nulls that field out when
    no such address is available (highmem) which should help usbmon.
    
    Signed-off-by: Tony Lindgren <tony@atomide.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ebc3ac149bf3a20c235625f1c07e0f997b3e08ba
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Apr 2 15:16:36 2007 +0200

    USB: cleanup ofd adutux
    
    this driver does
    - ignore errors during open
    - submit a running urb
    - use down_interruptible not handling signals
    - GFP_KERNEL with a spinlock held
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1941044aa9632aa8debbb94a3c8a5ed0ebddade8
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 27 13:33:59 2007 -0400

    USB: add "last_busy" field for use in autosuspend
    
    This patch (as877) adds a "last_busy" field to struct usb_device, for
    use by the autosuspend framework.  Now if an autosuspend call comes at
    a time when the device isn't busy but hasn't yet been idle for long
    enough, the timer can be set to exactly the desired value.  And we
    will be ready to handle things like HID drivers, which can't maintain
    a useful usage count and must rely on the time-of-last-use to decide
    when to autosuspend.
    
    The patch also makes some related minor improvements:
    
    	Move the calls to the autosuspend condition-checking routine
    	into usb_suspend_both(), which is the only place where it
    	really matters.
    
    	If the autosuspend timer is already running, don't stop
    	and restart it.
    
    	Replace immediate returns with gotos so that the optional
    	debugging ouput won't be bypassed.
    
    	If autoresume is disabled but the device is already awake,
    	don't return an error for an autoresume call.
    
    	Don't try to autoresume a device if it isn't suspended.
    	(Yes, this undercuts the previous change -- so sue me.)
    
    	Don't duplicate existing code in the autosuspend work routine.
    
    	Fix the kerneldoc in usb_autopm_put_interface(): If an
    	autoresume call fails, the usage counter is left unchanged.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 38c3cb5b677cf551cd93a494dc5c551271d90ac1
Author: Richard Knutsson <ricknu-0@student.ltu.se>
Date:   Mon Mar 26 22:00:28 2007 -0800

    USB: whiteheat: Convert to generic boolean
    
    Signed-off-by: Richard Knutsson <ricknu-0@student.ltu.se>
    Acked-by: Stuart MacDonald <stuartm@connecttech.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5ec1862e7b612d804ca10a0475dccf98c857efec
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Mar 27 16:02:34 2007 +0200

    USB: fix omninet write vs. close race
    
    omninet kills all URBs in close. However write() returns as soon as
    the URB has been submitted. Killing the last URB means a race that
    can lose that date written in the last call to write().
    As a fix this is moved to shutdown().
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2f007de2f4296e4dafae6ab0b3cc1bc49443137a
Author: Oliver Neukum <oneukum@suse.de>
Date:   Thu Mar 29 10:45:17 2007 +0200

    USB: fix error handling for mct_u232
    
    we report errors to the caller. THis patch adds error handling to the driver.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 9306fff17d3852e088dfc512e6f6673f3d80e71e
Author: Oliver Neukum <oneukum@suse.de>
Date:   Thu Mar 29 11:23:54 2007 +0200

    USB: fix error handling in kl5kusb
    
    - report errors
    - cleanup in error case
    - use of endianness macros
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5a9f4e338179e75e7e9b56293acb17023e342d81
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 30 13:11:00 2007 +0200

    USB: fix catc error handling
    
    this driver ignores errors while starting the transmit queue. It will
    never be reported stopped as the completion handler won't run
    and it will never be started again as it will be considered started.
    This patch adds error handling.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 949ce47168a34618c3e24cb7dd4ab52233a4653c
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 30 10:52:16 2007 +0200

    USB: cypress_cy7c63: race disconnect/sysfs read-write leading to following NULL pointer
    
    this driver sets intfdata to NULL while it still can be read and happily followed.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4edf2c83637b9e9db771cc5629de036fe4488564
Author: Oliver Neukum <oliver@neukum.org>
Date:   Mon Mar 26 18:12:44 2007 +0200

    USB: fix ark3116 memory leak
    
    this driver has a memory leak in an error case.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 868e440d2f2b55f790d106100a46034b6aa12577
Author: Jelle Foks <jelle@foks.8m.com>
Date:   Sun Mar 25 21:08:35 2007 -0400

    USB: ftdi_sio: Add USB ID of ADSTech USBX-707
    
    This patch adds the USB ID of the ADS Tech USBX-707 USB IR blaster (that
    comes with the ADS Tech PTV-305 grabber card), which has a ftdi232bm
    inside hooked up to a pic.
    
    With this it should be fairly straightforward to make at least lirc
    receiving work with this device. I will submit a patch to lirc for that
    as soon as I have one ready, I'm getting data with minicom with this
    patch, but need to figure out some more details such as best/correct
    baudrate.
    
    Signed-off-by: Jelle Foks <jelle@foks.8m.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 62127a585cc72509a0bfae502cc16f9935a4cda6
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 23 14:30:16 2007 +0100

    USB: fix race in ftdio_write
    
    this has the same race as the visor driver. The counter must be incremented
    under the lock it is checked under.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b80349b17c6e1236a24616f71e59ed31279de25a
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 23 11:58:03 2007 +0100

    USB: fix race in visor_write
    
    this fixes a small race in visor_write.
    
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b19d402a3450bb2597d0c1b54f6139462a5f35ae
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Mar 26 16:55:16 2007 +0200

    USB: aircable cleanup
    
    - proper endianness macros
    - scheduling in interrupt in error case
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Naranjo Manuel Francisco <naranjo.manuel@gmail.com>

commit 9f8b17e643fe6aa505629658445849397bda4e4f
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Tue Mar 13 15:59:31 2007 +0100

    USB: make usbdevices export their device nodes instead of using a separate class
    
    o The "real" usb-devices export now a device node which can
      populate /dev/bus/usb.
    
    o The usb_device class is optional now and can be disabled in the
      kernel config. Major/minor of the "real" devices and class devices
      are the same.
    
    o The environment of the usb-device event contains DEVNUM and BUSNUM to
      help udev and get rid of the ugly udev rule we need for the class
      devices.
    
    o The usb-devices and usb-interfaces share the same bus, so I used
      the new "struct device_type" to let these devices identify
      themselves. This also removes the current logic of using a magic
      platform-pointer.
      The name of the device_type is also added to the environment
      which makes it easier to distinguish the different kinds of devices
      on the same subsystem.
    
      It looks like this:
        add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1
        ACTION=add
        DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1
        SUBSYSTEM=usb
        SEQNUM=1533
        MAJOR=189
        MINOR=131
        DEVTYPE=usb_device
        PRODUCT=46d/c03e/2000
        TYPE=0/0/0
        BUSNUM=002
        DEVNUM=004
    
    This udev rule works as a replacement for usb_device class devices:
      SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
        NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
    
    Updated patch, which needs the device_type patches in Greg's tree.
    
    I also got a bugzilla assigned for this. :)
      https://bugzilla.novell.com/show_bug.cgi?id=250659
    
    
    Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 87840289637e9ea95118ebd76e2e335fdcddd725
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed Mar 21 13:57:51 2007 -0700

    USB: gadget-storage needs BLOCK
    
    With CONFIG_BLOCK=n, this build error happens:
    WARNING: "bdev_read_only" [drivers/usb/gadget/g_file_storage.ko] undefined!
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Acked-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2add5229d77a3de08015feef437653e02372162f
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 20 14:59:39 2007 -0400

    USB: add power/level sysfs attribute
    
    This patch (as874) adds another piece to the user-visible part of the
    USB autosuspend interface.  The new power/level sysfs attribute allows
    users to force the device on (with autosuspend off), force the device
    to sleep (with autoresume off), or return to normal automatic operation.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 13f6be01db9ada144f28241f939f4f3f8ec8e40b
Author: Peter Stokes <linux@dadeos.freeserve.co.uk>
Date:   Sat Mar 17 16:14:12 2007 +0200

    USB: ati_remote2: Add channel support
    
    Add logical channel support for ATI Remote Wonder II
    
    The ATI Remote Wonder II can be configured with one of 16 unique logical
    channels. Allowing up to 16 remotes to be used independently within
    range of each other. This change adds functionality to configure the
    receiver and filter the input data to respond or exclude remotes
    configured with different logical channels.
    
    Signed-off-by: Peter Stokes <linux@dadeos.freeserve.co.uk>
    Acked-by: Ville Syrjala <syrjala@sci.fi>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ebcf3ede6d84bf8aeff4378035d3fb312ede8dc9
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Mar 20 13:54:05 2007 +0100

    USB: sierra close race
    
    the sierra driver does not directly use usb_kill_urb(). It uses a wrapper.
    This wrapper means that callbacks which are running are not killed during
    close, resubmitting and illicitly pushing data into the tty layer.
    The whole purpose of usb_kill_urb() is subverted. The wrapper must be removed.
    The same problem as the option driver.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7d28e74b97c8eb859fd9f5eb018bb1c75627bd55
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Mar 20 13:41:21 2007 +0100

    USB: option close race
    
    the option driver does not directly use usb_kill_urb(). It uses a wrapper.
    This wrapper means that callbacks which are running are not killed during
    close, resubmitting and illicitly pushing data into the tty layer.
    The whole purpose of usb_kill_urb() is subverted. The wrapper must be removed.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Matthias Urlichs <smurf@smurf.noris.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4f93b3e8212df43ff380e118aebb68f6d1e5b060
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Mar 20 13:15:05 2007 +0100

    USB: omninet memory leak in error case
    
    memory allocated must be freed in the error case.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 0cef7727c953056bb3ef9852a79d9658a1d8df4e
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Mon Mar 19 15:33:11 2007 -0400

    UHCI: Add some WARN_ON()s
    
    This patch (as872) adds some WARN_ON()s to various error checks which
    are never supposed to fail.  Unsettlingly, one of them has shown up in
    a user's log!  Maybe making the warning more visible and having the
    call-stack information available will help pinpoint the source of the
    problem.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 325b70c233396f0cfe15012682a5080bf8040901
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Mar 19 13:58:29 2007 +0100

    USB: fix endianness in mos7720
    
    there's code unclean w.r.t. endianness in the mos7720 driver.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1b55fa2d430d6c708d3e5efbc6134be4a0c32b15
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 19 10:26:32 2007 +0100

    USB: gtco.c: fix a use-before-check
    
    NULL checks should be before the first dereference.
    
    Spotted by the Coverity checker.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f81ee4d52880b08c213982df5041217212689960
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Mar 19 11:39:13 2007 +0100

    USB: iowarrior.c: fix NULL dereference
    
    Am Montag, 19. 2007 10:25 schrieb Adrian Bunk:
    > The Coverity checker spotted the following NULL dereference:
    
    And this fixes an oops upon allocation failures.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 686149f488e1912f29bcfc593fad4c18f0f75397
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Fri Mar 16 18:33:13 2007 -0700

    USB: dm9601: fix sparse NULL warnings
    
    Fix sparse NULL warnings:
    
    drivers/usb/net/dm9601.c:88:23: warning: Using plain integer as NULL pointer
    drivers/usb/net/dm9601.c:174:22: warning: Using plain integer as NULL pointer
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit cb8eaa8b2b913387a9a1d3d8fe48edfc1595ba3e
Author: Richard Knutsson <ricknu-0@student.ltu.se>
Date:   Sat Mar 17 01:35:53 2007 +0100

    USB: io_edgeport: Convert to generic boolean
    
    Signed-off-by: Richard Knutsson <ricknu-0@student.ltu.se>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 0de9a7024e7ae62512d080c7e2beb59d82958cd5
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 16 20:28:28 2007 +0100

    USB: overhaul of mos7840 driver
    
    This fixes:
    
    - breaking DMA rules about buffers
    - usage of _global_ variables to save a single device's attributes
    - racy access to urb->status
    - smp monotonity issue with statistics
    - use of one buffer for many simultaneous URBs
    - error handling introduced
    - several instances of following NULL pointers
    - use after free
    - unnecessary GFP_ATOMIC
    - GFP_KERNEL in interrupt
    - various cleanups
    - write room granularity issue that bit cdc-acm
    - race in shutdown
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 96c706ed1c46470598d785124b2a7fb233b27dab
Author: Oliver Neukum <oneukum@suse.de>
Date:   Thu Mar 15 15:27:17 2007 +0100

    USB: io_edgeport race condition in counters
    
    io_edgeport is using a global variable without locking.
    This is _the_ classical race condition. This patch switches to atomic_t.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit e198a31489146bb723fef179e5d1d18c8225f246
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Thu Mar 15 15:54:30 2007 -0400

    EHCI: add delay to bus_resume before accessing ports
    
    This patch (as870) adds a delay to ehci-hcd's bus_resume routine.
    Apparently there are controllers and/or BIOSes out there which need
    such a delay to get the ports back into their correct state.  This
    fixes Bugzilla #8190.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Cc: David Brownell <david-b@pacbell.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit eaafbc3a8adab16babe2c20e54ad3ba40d1fbbc9
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 13 16:39:15 2007 -0400

    USB: Allow autosuspend delay to equal 0
    
    This patch (as867) adds an entry for the new power/autosuspend
    attribute in Documentation/ABI/testing, and it changes the behavior of
    the delay value.  Now a delay of 0 means to autosuspend as soon as
    possible, and negative values will prevent autosuspend.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 6b157c9bf3bace6eeb4a973da63923ef24995cce
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 13 16:37:30 2007 -0400

    USB: separate autosuspend from external suspend
    
    This patch (as866) adds new entry points for external USB device
    suspend and resume requests, as opposed to internally-generated
    autosuspend or autoresume.  It also changes the existing
    remote-wakeup code paths to use the new routines, since remote wakeup
    is not the same as autoresume.
    
    As part of the change, it turns out to be necessary to do remote
    wakeup of root hubs from a workqueue.  We had been using khubd, but it
    does autoresume rather than an external resume.  Using the
    ksuspend_usb_wq workqueue for this purpose seemed a logical choice.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 378465396e74aa6ef36271cecaea49eb742025a8
Author: Oliver Neukum <oneukum@suse.de>
Date:   Wed Mar 14 15:23:56 2007 +0100

    USB: help text for mos 7720 driver
    
    this driver's help text incorrectly claims to support only single port
    devices.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fe4b65ec9127a336eeaa503f878062d9e6f44591
Author: Oliver Neukum <oneukum@suse.de>
Date:   Wed Mar 14 15:22:25 2007 +0100

    mos7720 update
    
    this driver has an interesting way of handling ENOMEM: complain and ignore.
    If you decide to live with allocation failures, you must
    
    1. guard against URBs without corresponding buffers
    2. complete allocation failures
    3. always test entries for NULL before you follow the pointers
    
    This patch does so.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7378c57a8d4cf36e2f2b389d96d0d85043bd1c17
Author: Christian Engelmayer <Christian.Engelmayer@frequentis.com>
Date:   Mon Mar 12 09:08:36 2007 +0100

    ehci-fsl: change SI_CTRL, PRI_CTRL register offsets according to errata
    
    Correct the offsets of the SI_CTRL, PRI_CTRL registers according to
    the Reference Manual errata sheet in order to prevent unwanted
    settings regarding burst transactions and priority states.
    
    Signed-off-by: Christian Engelmayer <Christian.Engelmayer@frequentis.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1b42ae6d4355328dc4406b6f0188adcf8c566435
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 13 11:10:52 2007 -0400

    USB: fix race in HCD removal
    
    This patch (as865) fixes a race in the HCD removal code discovered by
    Milan Plzik.  Arrival of an interrupt after the root hub was
    unregistered could cause the root-hub status timer to start up, even
    after it was supposed to have been shut down.  The problem is fixed by
    moving the del_timer_sync() call to after the HCD's stop() method, at
    which time IRQ generation should be disabled.
    
    Cc: Milan Plzik <milan.plzik@gmail.com>
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 949be0f7be8de0c5a6a46626bd983f7a03a4b26e
Author: Simon Arlott <simon@arlott.org>
Date:   Tue Mar 6 02:47:46 2007 -0800

    USB: MAINTAINERS: cxacru
    
    I've acquired a second device for testing and plan to make some changes in
    the near future to export all the device stats to sysfs (based on my
    proposed patch to add them to the proc file ~2007-01-30).
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Acked-by: Duncan Sands <baldrick@free.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fa70fe44aba95ce373d7bcd27df4a594b53dcbdc
Author: Simon Arlott <simon@arlott.org>
Date:   Tue Mar 6 02:47:45 2007 -0800

    USB: cxacru: export detailed device info through sysfs
    
    When the device is polled for status there is a lot of useful status
    information available that is ignored.  This patch stores the device info
    array when the status is polled and adds sysfs files to the usb device to
    allow userspace to query it.  Since the device updates its status
    internally once a second the poll time is changed to this, and
    round_jiffies_relative is used to avoid waking the cpu unnecessarily.
    
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Cc: Duncan Sands <duncan.sands@free.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit e9b8daf31b459acb440647a651b1bda3b30e6188
Author: Simon Arlott <simon@arlott.org>
Date:   Tue Mar 6 02:47:43 2007 -0800

    usbatm: create sysfs link "device" from atm class device to usb interface
    
    There is currently no path from the ATM device in /sys to the USB device's
    interface that the driver is using; this patch creates a "device" symlink.  It
    is then possible to get to the cxacru ADSL statistics
    (http://lkml.org/lkml/2007/2/23/328):
    
    /sys/class/atm/cxacru0/device $ ls *_rate *_margin *_attenuation
    downstream_attenuation  downstream_snr_margin  upstream_rate
    downstream_rate         upstream_attenuation   upstream_snr_margin
    
    If this link is not appropriate I'd have to create device files in
    /sys/class/atm/cxacru0 instead - which seems less appropriate since the ADSL
    statistics are for the USB device not ATM (which is running over the ADSL).
    
    [akpm@linux-foundation.org: cleanups]
    Signed-off-by: Simon Arlott <simon@fire.lp0.eu>
    Cc: Duncan Sands <duncan.sands@math.u-psud.fr>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c2cf3f6ec58cf1d9e2a92cd74506dcf2265b31a1
Author: Oliver Neukum <oliver@neukum.org>
Date:   Tue Mar 6 16:21:22 2007 +0100

    USB: unnecessary GFP_ATOMIC in mos7720 driver
    
    GFP_KERNEL will do.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 718efa64e30a5e9db0351d70c5a91969306a12d1
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Fri Mar 9 15:41:13 2007 -0500

    usbcore: move usb_autosuspend_work
    
    This patch (as864) moves the work routine for USB autosuspend from one
    source file to another.  This permits the removal of one whole global
    symbol (!) and should smooth the way for more changes in the future.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 64e35d92367d8cd376946eb924838de1dd3287c7
Author: Pete Zaitcev <zaitcev@redhat.com>
Date:   Thu Mar 8 20:02:26 2007 -0800

    libusual: change block scope variable to function scope
    
    Someone changed the code to kthread and used his style instead of mine.
    
    The problem with the block variables is that they provoke shadowing,
    which is actually exactly what has happened in my other tree which
    has the class patch.
    
    Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 643616e6780b26dd8c9cea0b9344bb5d7aeae29d
Author: Pete Zaitcev <zaitcev@redhat.com>
Date:   Thu Mar 8 19:56:23 2007 -0800

    ub: Bind to first endpoint, not to last
    
    The usb-storage switched to binding to first endpoint recently. Apparently,
    there are devices out there with extra endpoints. It is perfectly legal.
    
    Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c4cabd28c73116716dcfd0d5f91414b48c0cf5ce
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Feb 27 15:28:55 2007 +0100

    USB: cdc-acm: export parsed capabilities through sysfs
    
    this patch exports the attributes cdc-acm knows about a device through sysfs.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bb74782e621e988555354abba03812982236a3af
Author: Oliver Neukum <oneukum@suse.de>
Date:   Tue Feb 27 11:30:24 2007 +0100

    USB: additional structure from cdc spec
    
    this adds another structure for CDC devices to cdc.h.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f1c9e30b5e4cdd8aae5f0ea87004b1b61ec41881
Author: Pete Zaitcev <zaitcev@redhat.com>
Date:   Sat Feb 24 19:27:33 2007 -0800

    usbmon: Extended text API
    
    This patch adds a new text API, codenamed '1u', which captures more URB
    fields than old '1t' interface did. Also the '1u' text API is compatible
    with the future "bus zero" extension.
    
    Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
    Acked-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2e85c91e2e0f4e58fb54354bb7f6cc7dd3466dd9
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Mar 5 15:11:14 2007 +0100

    USB: kill BKL in usblcd
    
    this patch removes usage of BKL from usblcd, which got it from the old
    skeleton driver.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 5d9b89b33f3ed19479dc5240986b0fedda08b82c
Author: Oliver Neukum <oneukum@suse.de>
Date:   Thu Mar 1 23:07:32 2007 +0100

    USB: kill BKL in skeleton driver
    
    Iet's kill BKL where we can. This is relative to the last patch to the
    skeleton driver.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ba35e02bdcbd3a25238421a7e20efdb69436d3cf
Author: Oliver Neukum <oneukum@suse.de>
Date:   Thu Mar 1 14:31:02 2007 +0100

    USB: fix skeleton driver
    
    compilation of the skeleton driver is currently broken. It doesn't compile.
    So while I am it:
    
    - fix typo
    - add comments to answer common questions
    - actually allow autosuspend in the driver struct
    - increase paralellism by restricting code under locks
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 08a78cbb410032a025e0323bcfb12b348fc7a389
Author: Milan Svoboda <msvoboda@ra.rockwell.com>
Date:   Tue Feb 27 09:20:09 2007 +0000

    USB: pxa2xx_udc: fix hardcoded irq number
    
    This patch changes last use of hardcoded number of irq to
    use platfrom_get_irq.
    
    Signed-off-by: Milan Svoboda <msvoboda@ra.rockwell.com>
    Acked-by: David Brownell <david-b@pacbell.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 34ebcd28235dc58633eeb8f7ca603838af23df0d
Author: David Brownell <david-b@pacbell.net>
Date:   Sat Feb 24 12:23:52 2007 -0800

    pxa2xx_udc: cleanups, use platform_get_irq
    
    Make the pxa2xx_udc driver fetch its IRQ from platform resources
    rather than using compile-time constants, so that it works properly
    on IXP4xx systems not just PXA21x/25x/26x.
    
    
    Other updates:
     - Do that using platform_get_irq()
     - Switch to platform_driver_probe()
     - Handle device_add() errors
     - Remove "function" sysfs attribute and its potential errors
     - Whitespace cleanups
    
    Signed-off-by: Milan Svoboda <msvoboda@ra.rockwell.com>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c51e9749ab49c5fa6c9cc1cb96bb5f36a571f553
Author: Norihiko Tomiyama <norihiko.tomiyama@ctc-g.co.jp>
Date:   Thu Apr 5 10:05:40 2007 +0900

    Adding PID of SHARP S01SH for ipaq.c
    
    I write a patch adding support "SHARP EMONE(S01SH)" device for ipaq.c.
    EMONE is a PDA with built-in HSDPA function.
    
    
    
    From: Norihiko Tomiyama <norihiko.tomiyama@ctc-g.co.jp>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit d455cf5d0db9e3eb1b204cd4a61d8c5ccfe4305f
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Thu Apr 26 16:44:55 2007 -0300

    V4L/DVB (5563): Radio-maestro.c Replace radio_ioctl to use video_ioctl2
    
    Convert radio-maestro to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6f66446c5465c0d29f8805ef47810f4a72842e5c
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Thu Apr 26 10:42:12 2007 -0300

    V4L/DVB (5562): Radio-gemtek-pci.c Replace gemtek_pci_ioctl to use video_ioctl2
    
    Convert radio-gemtek-pci to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 018ba85bf6d77eefc67796d707c81e8531b74d2f
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Tue Apr 10 18:59:09 2007 -0300

    V4L/DVB (5560): Ivtv: fix incorrect bitwise-and for command flags.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 86534e5e8eaeab2f5d2e92cff5e16980750095c6
Author: Marco Gittler <g.marco@freenet.de>
Date:   Mon Apr 23 17:52:58 2007 -0300

    V4L/DVB (5558): Opera: use 7-bit i2c addresses
    
    - the tuner i2c addr now without define (as wanted).
    - now 7 bit addr are used (the power_ctrl fkt ist ok so,
      because this is a raw write)
    - the addr >> 1 , addr << 1 is ok so, i think beause the
      read write is now taken from the last bit.
    - now i have no datasheet for the device, all taken from usb-logs
    
    Signed-off-by: Marco Gittler <g.marco@freenet.de>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 12df2f54e5522d89b3de6df62a800a0edeb10dcc
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Apr 25 00:20:13 2007 -0300

    V4L/DVB (5557): Cafe_ccic: check return value of pci_enable_device
    
    Remove warnings
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e9bb9c643924aee08f2a6b353174361ab567e436
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Wed Apr 25 00:15:46 2007 -0300

    V4L/DVB (5556): Radio-gemtek.c Replace gemtek_ioctl to use video_ioctl2
    
    Convert radio-gemtek to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 385e8d8fc6a3b5d0a656d69fc11cc6e26d9512cf
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Wed Apr 25 00:14:36 2007 -0300

    V4L/DVB (5555): Radio-aimslab.c Replace rt_ioctl to use video_ioctl2
    
    Convert radio-aimslab to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 2aa2342f2ba7caac0c5ed08331e883b7a72da2dd
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Tue Apr 24 13:40:07 2007 -0300

    V4L/DVB (5554): Fix: vidioc_g_parm were not zeroing the memory
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3f6892aca5d23730a747ce88eb0b6848e7a52a2f
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Tue Apr 24 08:40:06 2007 -0300

    V4L/DVB (5553): Replace typhoon_do_ioctl to use video_ioctl2
    
    Convert radio-typhoon to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 74ea1c7a7e7b5dfe961f3ed08365f9deb899b163
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 17:57:28 2007 -0300

    V4L/DVB (5552): Plan-b: Switch to refcounting PCI API
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 8ca966d7fdfa44f5ffbc2aac6b65e5aa5482123b
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 17:57:22 2007 -0300

    V4L/DVB (5551): Plan-b: header change
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c123b867713425f8db060b5e29201a1056c45d90
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Mon Apr 23 17:52:12 2007 -0300

    V4L/DVB (5550): Radio-sf16fmi.c Replace fmi_do_ioctl to use video_ioctl2
    
    Convert radio-sf16fmi to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 34ab962db8765a494072908e2dd5bf1478ac070d
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Mon Apr 23 17:51:37 2007 -0300

    V4L/DVB (5549): Radio-sf16fmr2.c Replace fmr2_do_ioctl to use video_ioctl2
    
    Convert radio-sf16fmr2 to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 288bb0e79015d4121d4ccf77a4db2bde27a49492
Author: Luc Saillard <luc@saillard.org>
Date:   Sun Apr 22 23:55:10 2007 -0300

    V4L/DVB (5548): Fix v4l2 buffer to the length
    
    Set the length of the v4l2 buffer to the length of the mapped memory.
    
    This should fix the problem with amsn.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9ee6d78cd4112c0f5a257a01383c64dadbf66da9
Author: Luc Saillard <luc@saillard.org>
Date:   Sun Apr 22 23:54:36 2007 -0300

    V4L/DVB (5547): Add ENUM_FRAMESIZES and ENUM_FRAMEINTERVALS ioctls
    
    This patch add support for the VIDIOC_ENUM_FRAMESIZES and
    VIDIOC_ENUM_FRAMEINTERVALS ioctl.
    * check if the maximum native framesize for raw mode is correct
    * raw mode framerates for all three chipset types
    
    Signed-off-by: Gregor Jasny <gjasny@web.de>
    Signed-off-by: Luc Saillard <luc@saillard.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1de69238111a65283a4548d8fd4727397873a02f
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Sun Apr 22 23:15:47 2007 -0300

    V4L/DVB (5546): Radio-terratec.c Replace tt_do_ioctl to use video_ioctl2
    
    Convert radio-terratec to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 2970c49270be2a62b1115f73bbfc0b8d3b3f48ba
Author: Hartmut Birr <e9hack@gmail.com>
Date:   Sun Apr 22 06:57:26 2007 -0300

    V4L/DVB (5545): Saa7146: Release capture buffers on device close
    
    If the video device (saa7146 on a FF card) was open for capturing,
    the close call didn't release the capture buffers.
    
    Signed-off-by: Hartmut Birr <e9hack@gmail.com>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit dc120b0734fcc6a4c42c73790a02f2fa74a7a326
Author: Hartmut Birr <e9hack@googlemail.com>
Date:   Sat Apr 21 19:44:10 2007 -0300

    V4L/DVB (5544): Budget-av: Make inversion setting configurable, add KNC ONE V1.0 card
    
    Make the inversion setting configurable. The KNC ONE V1.0 uses
    non inverted setting for the inversion and add the KNC ONE V1.0 card.
    
    Signed-off-by: Hartmut Birr <e9hack@googlemail.com>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit aa323ac89c5724de89656fcf31590d19e74594ec
Author: Hartmut Birr <e9hack@googlemail.com>
Date:   Sat Apr 21 19:37:17 2007 -0300

    V4L/DVB (5543): Tda10023: Add support for frontend TDA10023
    
    Add support for the frontend TDA10023 and add cards that need the
    tda10023.
    
    Signed-off-by: Hartmut Birr <e9hack@googlemail.com>
    Signed-off-by: Georg Acher <acher@in.tum.de>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit fd9c66e269a44bd3c6c615957c79b21f3dde69af
Author: Hartmut Birr <e9hack@googlemail.com>
Date:   Sat Apr 21 19:17:49 2007 -0300

    V4L/DVB (5542): Budget-av: Remove polarity switching of the clock for DVB-C
    
    Remove the polarity switching of the clock for the DVB-C cards in
    budget-av.c. This hack is no longer necessary because the saa7146 can
    do the job to remove the additional FEC bytes from the TS.
    
    Signed-off-by: Hartmut Birr <e9hack@googlemail.com>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a1314b1ab61027ac803b0899ead1ce1229d46a37
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Fri Apr 20 18:23:38 2007 -0300

    V4L/DVB (5541): Radio-zoltrix.c Replace zol_do_ioctl to use video_ioctl2
    
    Convert radio-zoltrix to use video_ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c5f822bf60b174c52d6d491d631d205384a2d1ca
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Fri Apr 20 18:22:19 2007 -0300

    V4L/DVB (5540): Radio-trust.c Replace tr_do_ioctl to use video_ioctl2
    
    Convert radio-trust to use video ioctl2
    
    Signed-off-by:  Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 8b811cf0c618915b286b5f829a77349a200b814c
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Fri Apr 20 06:37:36 2007 -0300

    V4L/DVB (5539): Radio-rtrack2.c Added VIDIOC_[GS]_AUDIO and VIDIOC_[S|G]_INPUT
    
    Implements VIDIOC_[GS]_AUDIO and VIDIOC_[S|G]_INPUT on radio-rtrack2
    
    Signed-off-by: Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ec709bb801a98dcac0a95c060c431eda73e31587
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Tue Apr 17 02:28:32 2007 -0300

    V4L/DVB (5530): Usbvision: remove CustomDevice facility
    
    usbvision has a module parameter that ables the user to add a new USB
    entry at driver load. This functionality is useless by experience
    (adding statically the entry is easy).
    
    Furthermore, the USB_DEVICE(0xfff0, 0xfff0) USB entry caused
    usbvision_probe to be called for all unclaimed devices.
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Acked-by: Dwaine Garden <DwaineGarden@rogers.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 25f30389dd84dcaf54d7d76fdd84e85bec206db6
Author: Douglas Landgraf <dougsland@gmail.com>
Date:   Thu Apr 19 16:42:25 2007 -0300

    V4L/DVB (5534): Radio-rtrack2.c Replace rt_ioctl to use video_ioctl2
    
    Convert radio-rtrack2 to use video_ioctl2
    
    Signed-off-by: Douglas Schilling Landgraf <dougsland@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 941491f3a52c34506137060716ce73e642ee326e
Author: Marco Gittler <g.marco@freenet.de>
Date:   Thu Apr 19 11:26:47 2007 -0300

    V4L/DVB (5532): Add support for Opera S1- DVB-USB
    
    This patch adds support for DVB-Opera S1 USB 2.0 BOX.
    
    Signed-off-by: Marco Gittler <g.marco@freenet.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6284feafcf589103f4a85d98d305e7a9d98970d3
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Mon Apr 16 17:47:08 2007 -0300

    V4L/DVB (5529): Usbvision: remove not needed TUNER_SET_TYPE_ADDR call
    
    usbvision_i2c: remove TUNER_SET_TYPE_ADDR call in attach_inform
    since it is done by tuner_core.
    Acked-by: Dwaine Garden <DwaineGarden@rogers.com>
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit bf8b20e190f9878978117e39e9a4e493a2e9d6bd
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Mon Apr 16 18:00:49 2007 -0300

    V4L/DVB (5528): Usbvision: reverting some i2c cleanups
    
    usbvision-i2c.c: reverting some i2c cleanups in order to recover a safe state.
    Acked-by: Dwaine Garden <DwaineGarden@rogers.com>
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c42cabefce5a333d8158434f902117d8c8dfd3b0
Author: vignesh.babu@wipro.com <vignesh.babu@wipro.com>
Date:   Mon Apr 16 10:34:33 2007 -0300

    V4L/DVB (5526): Cx88-alsa.c: Use kzalloc
    
    Replacing kmalloc/memset combination with kzalloc.
    
    Signed-off-by: vignesh babu <vignesh.babu@wipro.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3153bd91bfe14b6b93aef5b6b7c9fc279eec60d9
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Sun Apr 15 10:09:56 2007 -0300

    V4L/DVB (5525): Usbvision: fix confusion over 7-bit vs 8-bit TDDA9887 addresses
    
    The code was testing an 8-bit address against a 7-bit address.  Will the
    confusion of the two never cease?
    Biggest flaw of the I2C protocol:  the R/W bit is the LSB instead of the
    MSB.  No one can ever agree if addresses are 7-bits and the R/W bit
    follows them, or if they are 8-bit and the R/W bit is OR-ed into the
    address byte.  If the R/W bit was first, it wouldn't make any difference!
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 66ab6e023ebbb362b7cf42c8f56cc54a85fb7bb0
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sat Apr 14 10:24:15 2007 -0300

    V4L/DVB (5513): Bt878: prevent probing wrong card entry
    
    I got strange message when I did modprobe bt878:
    bt878_probe: card id=[0x0],[ <NULL> ] has DVB functions.
    The card_list array is terminated by sentinel entry.
    But this list is traversed by:
    for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list);
         i++, dvb_cards++) {
    ...
    }
    in bt878_probe().
    So this loop checks dummy sentinel entry, too.
    This patch removes unnecessary sentinel entry.
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f2c340583c27f2f93ed1c720ae863ea601e1d74a
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Sun Apr 15 04:29:13 2007 -0300

    V4L/DVB (5524): Usbvision: fix TDA9887 detection
    
    - Adding 0x86 as possible I2C addresses for TDA9887 to call TUNER_SET_TYPE_ADDR.
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 672d013bed5e144ac641db343251e35d3212c9ad
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Sat Apr 14 17:53:55 2007 -0300

    V4L/DVB (5523): Usbvision: fix a debug message in usb probe function
    
    - change a printk to PDEBUG when USB probe detects an unknown device.
    This will avoid a message log from usbvision when an unclaimed device is inserted.
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1ff16c2091a557f8080eb62c087465a87e4330e9
Author: Thierry MERLE <thierry.merle@free.fr>
Date:   Sat Apr 14 16:23:49 2007 -0300

    V4L/DVB (5522): Usbvision: i2c function cleanups
    
    usbvision-i2c function renamings, code cleanup
    
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d3df9c4fa13db14cb9f6cd4cf31bd2a61c0e9911
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Sat Apr 14 16:19:13 2007 -0300

    V4L/DVB (5521): Usb_get_dev were called twice. Removing the extra call.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 28aedb8fd95b9a11cb9dc75d3be1f30227cb4385
Author: Ville-Pekka Vainio <vpivaini@cs.helsinki.fi>
Date:   Sat Apr 14 15:38:23 2007 -0300

    V4L/DVB (5520): Add support for the extra keys in the black Technotrend 1500 IR
    
    It has come to my knowledge that the Technotrend 1500 DVB cards have
    been sold bundled with at least two different kinds of remotes, a grey
    one and a black one.
    This patch adds support for the extra keys in the black remote to
    ir-keymaps.c.
    
    Signed-off-by: Ville-Pekka Vainio <vpivaini@cs.helsinki.fi>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f8a389db502f7b287903b209f925df5570ff5478
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Sat Apr 14 15:17:35 2007 -0300

    V4L/DVB (5518): Fix a bug on device detection
    
    Thanks to: Thierry MERLE <thierry.merle@free.fr> for pointing this
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c682b3a7fb8ec69ac73511bbb6a378e40aa35f35
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Sat Apr 14 15:16:26 2007 -0300

    V4L/DVB (5517): Usbvision: store the device database more efficiently
    
    One bit wide bitfields need to declared unsigned to have the range 0 to
    1, or they have the range -1 to 0.
    
    A few techniques to reduce the driver's size by about 1700 bytes on ia32,
    probably more on x86-64.
    
    Put the biggest fields first, less padding is necessary that way.
    
    Put fields with a limited range into a smaller type.  For example
    VideoChannels will fit in 3 bits, and TunerType can use 8 bits.
    
    Vin_Reg1, Vin_Reg2, and Dvi_yuv define values for 8-bit registers, but
    they can't just go into an 8-bit field with no changes, since -1 was used
    as a flag to indicate a value was not present.  So what we do is create a
    one-bit flag for each one to indicate if a value is or is not present.
    
    This only takes 9 bits and has the added advantage that when the register
    isn't overridden (Vin_Reg[12] never are) it doesn't need to appear in the
    structure definition since the default value for the flag will be zero.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f7ca6256bc1db4fb44adda99e082f8c80ada8957
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Sat Apr 14 15:15:43 2007 -0300

    V4L/DVB (5516): Reduce usbvision data size
    
    This patch reduces usbvision driver on about 1Kb on i386 over the
    original version with the old struct:
       text    data     bss     dec     hex filename
      52312   11848      60   64220    fadc old/usbvision.ko
      52474   10708      60   63242    f70a new/usbvision.ko
    
    Acked-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 659ae56dcd5a50e4560cb526a0e0dc881418dad4
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Sat Apr 14 15:09:59 2007 -0300

    V4L/DVB (5515): Use a better format to represent usbvision supported boards
    
    Changed usbvision cards table to allow:
    	1) Not repeat USB ID on two structs;
    	2) Not need to specify both usb and card description tables at
    	   the same order, removing some magic;
    Some cards had duplicated names. Fixed.
    A test for an specific board were doing by using a string comparation.
    The comparation were wrong. Also, it is not a good practice to recognize
    a board based on his string name.
    Acked-by: Thierry MERLE <thierry.merle@free.fr>
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 2c4d336468b400f9a47d6c1785d230548b89ca24
Author: Markus Rechberger <markus.rechberger@amd.com>
Date:   Sat Apr 14 10:19:36 2007 -0300

    V4L/DVB (5512): Fix 3/3 for bug 7819: fixed hotplugging for dvbnet
    
    fixed hotplugging for dvbnet
    
    Signed-off-by: Michal CIJOML Semler <cijoml@volny.cz>
    Signed-off-by: Markus Rechberger <markus.rechberger@amd.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 57861b432bda77f8bfafda2fb6f5a922d5f3aef1
Author: Markus Rechberger <markus.rechberger@amd.com>
Date:   Sat Apr 14 10:19:18 2007 -0300

    V4L/DVB (5511): Fix 2/3 for bug 7819: demux and dvr
    
    fixing hotplug issue for demux[n] and dvr[n]
    
    Signed-off-by: Michal CIJOML Semler <cijoml@volny.cz>
    Signed-off-by: Markus Rechberger <markus.rechberger@amd.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ca5be9cd0516629cb8ee335b7dad076e66d72a22
Author: Markus Rechberger <markus.rechberger@amd.com>
Date:   Sat Apr 14 10:18:58 2007 -0300

    V4L/DVB (5510): Fix 1/3 for bug 7819: fixed frontend hotplug issue
    
    fixed frontend hotplug issue
    
    Signed-off-by: Michal CIJOML Semler <cijoml@volny.cz>
    Signed-off-by: Markus Rechberger <markus.rechberger@amd.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 31a1854706707dc3b67eb0d3bf0f51c67d91c82e
Author: Mike Isely <isely@pobox.com>
Date:   Sun Apr 8 01:11:47 2007 -0300

    V4L/DVB (5507): Pvrusb2: Gather USB bus address info and report it
    
    The V4L2 API requires a unique bus_info string returned as part of the
    v4l2_capability structure.  These changes gather up the USB address
    information, from the underlying device, into a string and report that
    out through v4l2 and via sysfs (for completeness).
    
    Signed-off-by: Mike Isely <isely@pobox.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 4f210e072235c3c123b068d348a1a02e624ff5be
Author: Hendrik Borghorst <hendrik@borghorst.org>
Date:   Thu Apr 5 14:28:11 2007 -0300

    V4L/DVB (5505): Fix Kernel Bugzilla #8301: spinlock fix for flexcop-pci
    
    If you modprobe the b2c2-flexcop-pci module you got a hardlock of your system.
    This is due the usage of spin_lock before spin_lock_init is called.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 990e3743b505a0bb08c04a381d5477e19d31ef5e
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Apr 4 17:11:06 2007 -0300

    V4L/DVB (5504): Sn9c102: Make driver V4L2 not V4L1
    
    sn9c102 is a v4l2 driver, except it used a couple v4l1 helper functions.
    Stop using those functions and depend on V4L2 in Kconfig.
    Acked-by: Luca Risolia <luca.risolia@studio.unibo.it>
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 7e81d8254d4f00817b98588fce1afb448ccc14a9
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Apr 4 17:11:05 2007 -0300

    V4L/DVB (5503): Sn9c102: declare constant byte sequences as static const
    
    Makes sure they don't get copied onto the stack.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Luca Risolia <luca.risolia@studio.unibo.it>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c680dd603857d7218b84751e9f6f0654bbfbefa2
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Apr 4 17:11:04 2007 -0300

    V4L/DVB (5502): Sn9c102: more efficient register writing code
    
    There were many places in the driver which had long sequences of constant
    register initializations.  These were done with one function call per
    register.  The register address and value were immediate values in the
    function calls.
    This is very inefficient, as each register and value take twice the space
    when they are code, as each includes a push instruction to put it on
    the stack.  There there is the overhead, both size and time, for a
    function call for each register.  It's also quite a few lines of C code
    to do this.
    The patch creates a function that writes multiple registers from a list,
    and a macro that makes it easy to construct a such a list as a const
    static local to send to the function.
    This gets rid of quite a bit of C code, and shrinks the driver by around
    8k, while at the same time being more efficient.
    Acked-by: Luca Risolia <luca.risolia@studio.unibo.it>
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 0ee32871c18a3662d8958a8e9998eb4d2ae94159
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Tue Apr 3 18:08:19 2007 -0300

    V4L/DVB (5500): Add a CARDLIST for the supported devices by usbvision driver
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1ebba670edac28d4ea37579453417ced71fd9128
Author: Scott Alfter <salfter@ssai.us>
Date:   Mon Apr 2 14:22:39 2007 -0300

    V4L/DVB (5497): Additional card support for bttv driver
    
    SSAI (www.ssai.us) makes several Bt878-based capture cards that get used in our
    surveillance, conferencing, and medical imaging systems.  The attached
    relatively small patch adds support for these cards, which fall into two broad
    * boards with one or more Bt878s, one or more composite inputs, and no S-video
      or tuner inputs
    * boards with one Bt878, one composite input, one S-video input, and no tuner
      input
    
    Signed-off-by: Scott Alfter <salfter@ssai.us>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 4b9d4e7dba102c8ab5ef651e538e9d0c79c80cab
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Sun Apr 1 18:29:04 2007 -0300

    V4L/DVB (5494): Lgdt330x: Fix some warnings
    
    It's KERN_WARNING "lgdt....", not "KERN_WARNING lgdt...."
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 82c2e4617c28f1e64ecbbeb7a2325f79c80a5aa9
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sat Mar 31 10:35:24 2007 -0300

    V4L/DVB (5492): Remove useless includes of i2c-algo-bit.h
    
    The tda7432, tda9875 and tvaudio media drivers don't need to include
    the linux/i2c-algo-bit.h header file.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e8f4e7525c6ba52d97bb057420163b4c704c6d10
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sat Mar 31 10:34:59 2007 -0300

    V4L/DVB (5491): Cx88: Support the DTV1000 T analog inputs
    
    Add support for the S-Video and CVBS (composite) analog video inputs
    of the Leadtek WinFast DTV1000 T adapter.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Acked-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit fd51c697dd6111ee4260d8c752ba4d09dc614c3f
Author: Amit Choudhary <amit2030@gmail.com>
Date:   Fri Mar 30 17:48:59 2007 -0300

    V4L/DVB (5490): Drivers/media/video/se401.c: check kmalloc() return value.
    
    Check the return value of kmalloc() in function se401_start_stream(), in
    file drivers/media/video/se401.c.
    
    Signed-off-by: Amit Choudhary <amit2030@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 20ec811eddb362f821c6fd57e5449f3ddb80b466
Author: Amit Choudhary <amit2030@gmail.com>
Date:   Fri Mar 30 17:34:14 2007 -0300

    V4L/DVB (5489): Codec.c: check kmalloc() return value.
    
    Signed-off-by: Amit Choudhary <amit2030@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit aaa40cb8b7056b597fa77c9f61a1b271c0e341cf
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Fri Mar 30 10:58:01 2007 -0300

    V4L/DVB (5488): Replace DMA magic mask for its aliases
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 904ab884a25fbaebe5d76d633d1c30c9f2a7c0aa
Author: Ed Vipas <epvipas@gmail.com>
Date:   Thu Mar 29 18:32:49 2007 -0300

    V4L/DVB (5486): Add support for remote of Asustech P7131 Hybrid	LNA
    
    This patch just defines the remote control type.
    
    Signed-off-by: Ed Vipas <epvipas@gmail.com>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9971f4f1d3d71a5b6654ba226976ba82d2e047a4
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Mar 23 21:00:07 2007 -0300

    V4L/DVB (5485): Tda827x: delayed probing of tuner version
    
    When the tuner is attached, the tda10046 is not initilized yet, so it
    is searching for its firmware. If the tuner is attached to the tda10046
    silent i2c port, a bus collision can occur. Now the version is probed
    during the first init or sleep call.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e65ec752ced103eb86e5f9c1f747f06d3e266780
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Thu Mar 22 20:58:43 2007 -0300

    V4L/DVB (5484): Set tda8290 to analog mode after init
    
    Set tda8290 to analog mode after init, otherwise the tuner driver will
    not accept i.e. the standby command.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f992a497c71981e215b1415759fc13593ed2919f
Author: Jarod Wilson <jwilson@redhat.com>
Date:   Sat Mar 24 15:23:50 2007 -0300

    V4L/DVB (5482): Bttv: automatically load dvb-bt8xx for bttv cards with dvb
    
    This patch causes the bttv driver to automatically load the dvb-bt8xx module
    for bttv/dvb hybrid cards. Successfully tested with a pcHDTV HD-2000 card.
    This patch is based on the recent patches to enable autoloading of cx88-dvb,
    cx88-blackbird and saa7134-dvb.
    
    Signed-off-by: Jarod Wilson <jwilson@redhat.com>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit fbc8408a0d9deeba8926e041db0bb1ef7f1b2cd6
Author: Damian Minkov <damencho@damencho.com>
Date:   Thu Mar 29 08:47:39 2007 -0300

    V4L/DVB (5481): Fix audio input for AverTv Go 007
    
    Fix audio input source for capturing(playing) audio on AverTv Go 007 cards.
    
    Signed-off-by: Damian Minkov <damencho@damencho.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 66623a0419da2bae2efab40a46018faacce2e3aa
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Thu Mar 29 08:47:04 2007 -0300

    V4L/DVB (5480): Fix cx88_print_irqbits calls to use ARRAY_SIZE
    
    cx88_print_irqbits were expecting a string pointer with 32 bytes. Better
    to pass the string size and use ARRAY_SIZE on its calls.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 53c4e9551c2930767fcdaa54323616c32ed6e9c6
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Thu Mar 29 08:42:30 2007 -0300

    V4L/DVB (5479): Use ARRAY_SIZE instead of a magic number
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5b9c4e6dbb3204568d4c058af6e34772393ada19
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Wed Mar 28 22:37:26 2007 -0300

    V4L/DVB (5478): Use ARRAY_SIZE and a cleaner logic for initializing tuner
    
    ATI HDTV Wonder needs to initialize some registers before allowing the
    tuner to start working.
    The current logic have lots of magic. This patch makes the code cleaner,
    using ARRAY_SIZE() for the initialization array and using a
    bidimensional array, instead of doing some stuff like:
    	&buffer[i+2]
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit c1d570385bd6dd5fe4c0cab09b1c390331111b35
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Wed Mar 28 22:37:23 2007 -0300

    V4L/DVB (5477): CodingStyle cleanups on for loops at bttv-cards.c
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 57747b7f2517524aed5f0c5b744badf9da94a91b
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Wed Mar 28 22:37:20 2007 -0300

    V4L/DVB (5476): Fix gpiomux array size
    
    there were several "magic" for loops, addressing gpiomux array size (4).
    Adrian Bunk showed that one of the loops were wrong, going from 0 to 4.
    
    This patch provides the right fix for this trouble, by using ARRAY_SIZE
    on all places where we have a for loop using gpiomux.
    
    Thanks to: Adrian Bunk <bunk@stusta.de> for pointing me about this trouble.
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f423b9a86a6dd3d2bc08d78f4d21525a14c40a6b
Author: Luca Risolia <luca.risolia@studio.unibo.it>
Date:   Mon Mar 26 16:12:04 2007 -0300

    V4L/DVB (5474): SN9C1xx driver updates
    
    @ Don't assume that SOF headers can't cross packets boundaries
    @ Fix compression quality selection
    + Add support for MI-0360 image sensor
    * Documentation updates
    @ Fix sysfs
    @ MI0343 rewritten
    * HV7131R color fixes and add new ABLC control
    * Rename the archive from "sn9c102" to "sn9c1xx"
    * fix typos
    * better support for TAS5110D
    @ fix OV7630 wrong colors
    @ Don't return an error if no input buffers are enqueued yet on VIDIOC_STREAMON
    * Add informations about colorspaces
    * More appropriate error codes in case of failure of some system calls
    * More precise hardware detection
    * Add more informations about supported hardware in the documentation
    + More supported devices
    + Add support for HV7131R image sensor
    
    Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9ab7e323af9f9efad3e20a14faa4d947adfac381
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sun Mar 25 12:14:38 2007 -0300

    V4L/DVB (5471): Cpia_pp.c: convert to module_{init,exit}
    
    After looking at a section bug (in the non-modular case, clearly
    non-init code referenced the __initdata parport_nr[]), I thought it was
    time to convert this driver to module_{init,exit}.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 585553ecedabf434e5cdc59d05bf64596ceab7bc
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Sun Mar 25 11:38:21 2007 -0300

    V4L/DVB (5469): Add raw bayer support to the ov7670 driver
    
    Add raw bayer support to the ov7670 driver
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 77d5140fe78ca628bfc9d2567c35457481f9c63d
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Thu Mar 22 19:44:17 2007 -0300

    V4L/DVB (5469a): Copyright and maintainer tweaks
    
    Fix up Cafe/ov7670 copyrights and maintainer entries
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 7f7b12f09be8e396d159800baeaf922df46e25cf
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Sun Mar 25 11:36:42 2007 -0300

    V4L/DVB (5468): Don't mirror ov7670 images by default
    
    Don't mirror ov7670 images by default.
    
    The ov7670 sensor driver sets the mirror bit by default, which is not
    the desired mode.  OLPC has been running with this patch for a while.
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ff68defa08376b6c0482b249b7dfd35241861bce
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Sun Mar 25 11:36:28 2007 -0300

    V4L/DVB (5467): Add suspend/resume support to the Cafe CCIC
    
    Add suspend/resume support to the Cafe CCIC driver.
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5b50ed7ca2432e7ea3caf8cc2ef5ac805c082519
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Fri Apr 27 12:32:28 2007 -0300

    V4L/DVB (5466): Fix up some Cafe CCIC delay issues
    
    Fix up unsociable Cafe CCIC delays.
    
    The Cafe CCIC driver contains some lengthy delays, some of which are
    unnecessary and some of which are done under lock.  Some were marked
    with comments, but the comments somehow failed to make the issue go
    away.  So fix it for real.
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 76f4a12000254d460e947d2a95ab422ee6e598bf
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Sun Mar 25 11:36:02 2007 -0300

    V4L/DVB (5465): Remove an obsolete PCI ID
    
    Remove an obsolete PCI ID.
    
    The CAFE driver includes three PCI IDs, one of which corresponds to
    a development board which is no longer in use.
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 018cfd51f682876fec682a33819964c1d6ed6794
Author: Jonathan Corbet <corbet@lwn.net>
Date:   Sun Mar 25 11:35:56 2007 -0300

    V4L/DVB (5464): Set the PCI device in the V4L2 device
    
    Set the PCI dev in the V4L2 dev so that the proper sysfs link gets made
    
    Signed-off-by: Jonathan Corbet <corbet@lwn.net>
    Signed-off-by: Dan Williams <dcbw@redhat.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6b1ce3c1017adce52675ec72825f0b052a6af5d4
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Wed Mar 21 16:35:28 2007 -0300

    V4L/DVB (5462): Add Logitech ViewPort AV 100
    
    Logitech ViewPort AV 100 has the same internals as Cisco VT Camera.
    Fixing Pwc driver to handle it properly.
    Also, fixed the comments for both cameras.
    Thanks to Martin Rubli for pointing me this.
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a63e157fc6147ae9792325cb55fa0c6d1d0f9905
Author: Jean Tourrilhes <jt@hpl.hp.com>
Date:   Wed Mar 21 16:29:16 2007 -0300

    V4L/DVB (5461): Pwc: cisco VT Camera support
    
    I have a Cisco VT Camera, and it was just collecting dust.  I decided to
    try connecting it to my Linux box at home.
    
    Just a disgression about the product.  The Cisco VT Camera is a webcam
    Cisco sold to work with their IP phone hardware and software.  It's mostly
    useless on Windows, as it interfaces only to Cisco software.  You can find
    some for cheap on eBay...
    
    Physically, it's just a Logitech Pro 4000.  The only difference with the
    Pro 4000 is the Cisco logo and that it's grey like the Pro 3000.  I believe
    Cisco is now selling the Cisco VT Camera II, which look to be something
    else...
    
    So, assuming that it was a Pro 4000 inside, I created the little patch
    attached.
    
    I'm new to webcam under Linux, but I managed to get an image from it using
    xawtv, and the image looked all right, so I consider that a success.  The
    imaged seemed a bit small and I could not get the microphone driver loaded,
    but I assume it's my lack of experience.  Note that I did not try any other
    type_id, but this one works great.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d4ca23b188d458ef508649a0c6866937b48d4bf8
Author: Pierre Willenbrock <pierre@pirsoft.de>
Date:   Sun Mar 18 19:54:07 2007 -0300

    V4L/DVB (5459): M920x: add support for Anubis Electronics / MSI Digi Vox Mini II
    
    Add support for Anubis Electronics "Lifeview" (USB-ID: 0x10fd:0x1513)
    
    Signed-off-by: Pierre Willenbrock <pierre@pirsoft.de>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 08cdf94c076121cd0214ef9ea18ae3fbb9ace684
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Sun Mar 18 19:23:20 2007 -0300

    V4L/DVB (5458): Tda1004x: add ts_mode option to config struct
    
    The struct tda1004x_config has a new entry: .ts_mode
    Possible values are TDA10046_TS_PARALLEL or TDA10046_TS_SERIAL
    There always is only one interface active, default is parallel.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d519dcf61ed55bcfb947a31122cea068a73ad974
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Mon Mar 19 02:24:09 2007 -0300

    V4L/DVB (5457): Dvb-pll: Replace sleep function with a more capable one
    
    The dvb-pll sleep function could only send a 2-byte sequence to the PLL.
    This isn't enough in some cases, for example fmd1216me will need to send
    a 4-byte command to set both BB and AB to the correct values.
    
    Instead of using a fake band with a frequency of 0 to store the sleep
    data (which has room for only two bytes), the new sleep function works
    like the init function.  A new pointer is added to the pll description,
    and when non-NULL points to a buffer with the length and data to send.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit df78cb0a1870703b7622fe8c63e5bcb6563197fd
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Mon Mar 19 02:24:04 2007 -0300

    V4L/DVB (5456): Dvb-pll: Move IF frequency from per-band data to per-tuner data
    
    The IF frequency was specified for each band, but it's not something that
    changes from band to band.  None of the tuner definitions had a different
    IF frequency (called offset) from one band to another.
    Acked-by: Michael Krufky <mkrufky@linuxtv.org>
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 0fd17d6da8154e1a6391440a268b0620ab339122
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Mon Mar 19 02:23:59 2007 -0300

    V4L/DVB (5455): Dvb-pll: Adjust rounding to be consistent
    
    Some PLLs had one half the step size added to the offset, so that the
    divisor would be rounded to the nearest integer.  Some didn't and so
    would always be rounded down.
    
    This makes dvb-pll round to the nearest when calculating the divisor,
    without the offset needing to be fudged.  PLLs that had a fudged offset
    have the offset changed to be just the IF frequency.
    The satellite PLL dvb_pll_philips_sd1878_tda8261 was rounding up for some
    reason, and I've kept it that way.
    
    In addition, frequencies that were rounded to the nearest kHz are
    extended to full Hz resolution.  One sixth MHz step sizes that were
    listed as 166,666 Hz are changed to 166,667 Hz, which is slightly closer.
    
    PLLs that were already rounding:
    dvb_pll_tda665x, offset was 36 1/6 (to nearest kHz) + step/2
    dvb_pll_fmd1216me, offset was 36 1/8 (to two digits) + step/2
    dvb_pll_thomson_fe6600, offset was 36 1/8 (to two digits) + step/2
    dvb_pll_env57h1xd5, offset was 36 1/8 + step
    
    Note that the last PLL, dvb_pll_env57h1xd5, appears to have had a bug in
    the offset.  Rather than adding stepsize/2, it was adding a full
    stepsize.  The PLL definition originally came from the dibusb driver,
    which used 36 1/8 + step/2.  The change to 36 1/8 + step was probably a
    mistake added when the tuner was converted to dvb-pll.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a5a2ecfc3b9b1f97a7f141bd95ea75097ad49b7c
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Mar 9 15:07:07 2007 -0300

    V4L/DVB (5452): Cx88: merge identical boards
    
    The attach code for HAUPPAUGE_HVR3000 and HAUPPAUGE_HVR1300 is exactly
    the same as the code used by HAUPPAUGE_HVR1100, HAUPPAUGE_HVR1100LP, and
    WINFAST_DTV2000H.  So, those first two cards are added to the case block
    used by the last three.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 59069e53a27605d14a1a693683a45de837ee7521
Author: Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
Date:   Thu Mar 15 13:24:29 2007 -0300

    V4L/DVB (5449): M920x: add error messages for debugging purposes
    
    Signed-off-by: Pierre Willenbrock <pierre@pirsoft.dnsalias.org>
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 7d1d4e6c58243614c38ad516a5acfd1af096ba9b
Author: Aapo Tahkola <aet@rasterburn.org>
Date:   Thu Mar 15 13:01:46 2007 -0300

    V4L/DVB (5448): M920x: rename megasky_identify_state to m920x_identify_state
    
    This function should work for all m920x-based devices.
    
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f3eec0c001a6781224d39912d41b58eaf2126586
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Wed Mar 14 20:33:55 2007 -0300

    V4L/DVB (5446): Renamed ASUStek P7131 card [1043:4876]
    
    The new name fits to what it is and what is on the box.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e06cea4cb4a16076dfca4863b12e1c4aeb781c8d
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Tue Mar 13 20:58:29 2007 -0300

    V4L/DVB (5445): Added / corrected support for some ASUS hybrid boards
    
    There are 2 new entries for p7131 boards and one correction for a board
    with LNA.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit cf83ac433c275b8a652492cabdb39b88a7f8d45c
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Tue Mar 13 20:52:35 2007 -0300

    V4L/DVB (5444): Saa7134-dvb fix sleep function of the fmd1216 tuner.
    
    Static locals should not be changed - the original contents gets lost.
    Thanks to Trent Piepho for pointing me to this.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 80d352374be7ac88a23fb427d146ac9a71beff90
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Tue Mar 13 20:44:22 2007 -0300

    V4L/DVB (5443): Saa7134: put tuner to sleep mode after board initialization
    
    Besides power saving, this puts the AGC output of the tda8290
    to tristate. This is necessary for some hybrid boards which
    don't use a multiplexer for the AGC
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1b2457680f237f858d5f6bcf933cd173a7b27a81
Author: Oliver Endriss <o.endriss@gmx.de>
Date:   Mon Mar 12 21:45:46 2007 -0300

    V4L/DVB (5440): Dvb-ttpci: Infrared remote initialization fix
    
    Fix bug introduced during infrared refactoring.
    Thanks to Johann Friedrichs for spotting this.
    
    Thanks-to: Johann Friedrichs <johann.friedrichs@web.de>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9e0df402e695e638dfee94a6e05fca48b15404e6
Author: Ian Armstrong <ian@iarmst.demon.co.uk>
Date:   Fri Mar 16 07:44:42 2007 -0300

    V4L/DVB (5438): Fix ivtv yuv threshold handling
    
    Modifies automatic mode selection for yuv playback. Behaviour is now that
    source video with a vertical resolution below that of the currently set
    broadcast mode will be treated as progressive. Video with a vertical
    resolution greater or equal to the current broadcast mode (up to 576 lines)
    will be treated as interlaced.
    
    Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 59fc7f52898fb35eb053bc7b54430d81629b5966
Author: Ian Armstrong <ian@iarmst.demon.co.uk>
Date:   Fri Mar 16 07:40:48 2007 -0300

    V4L/DVB (5437): Update cx23415 documentation
    
    Adds more osd mode switching information.
    Corrects some information regarding mode selection & local alpha operation for
    16 bit modes.
    
    Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 31a7c549eda6bf0a38d8fc12c903a8535a9f27ca
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Tue Mar 13 19:22:40 2007 -0300

    V4L/DVB (5436): Fix TV output initialization
    
    The TV standard should be set AFTER the TV output is fully initialized.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ddc285c7632b64fb1ac3ec8f25bcc8abd4a1f727
Author: Steven Toth <stoth@hauppauge.com>
Date:   Mon Mar 12 22:26:40 2007 -0300

    V4L/DVB (5434): Updates to the tveeprom tuner, video decoder and audio chip
    
    Some of the new tuner entries may need to be mapped to compatible
    tuners already defined. I don't know for certain which tuners
    are compatible between manufacturers.
    
    Signed-off-by: Steven Toth <stoth@hauppauge.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 923da8a750fe008da308d0698f66052dfccb037d
Author: Michael Krufky <mkrufky@linuxtv.org>
Date:   Sun Mar 11 12:52:48 2007 -0300

    V4L/DVB (5432): Cx88: whitespace cleanup
    
    replace leading spaces with tabs
    
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 733aeaf4c006353b1ed8c54b707c03a6385c30ed
Author: Michael Krufky <mkrufky@linuxtv.org>
Date:   Sun Mar 11 12:48:04 2007 -0300

    V4L/DVB (5431): Cx88: autodetect ADS Tech InstantTV DVB-S
    
    The ADS Tech InstantTV DVB-S is a clone of the KWorld DVB-S 100.
    This patch adds autodetection support for this card based on
    pci subsystem id.
    
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 57f8dcf90bdf4c6b23ea2af3d307d1d137b696b9
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Mon Mar 12 12:13:12 2007 -0300

    V4L/DVB (5428): M920x: Detect zero-length I2C messages and fix a typo
    
    Change a 00 to just 0
    Detect zero-length I2C messages and return not supported.  I think I know
    how to send one, but the problem is getting the slave's ack.  The only
    point of a zero-length message is for probing; too see if the slave will
    ack its address.  Since we don't know how to get the ack, we can't
    support zero-length messages in a useful way, so it's probably best to
    just return not supported for them.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d40860f8e2edb31196f4233d3691704d313dbdd6
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Mon Mar 5 23:55:00 2007 -0300

    V4L/DVB (5427): M920x: Improve I2C operations
    
    Write some better documentation about what might be known about how the
    m920x I2C works, since a datasheet is lacking.
    The I2C xfer function should now handle more types of I2C transactions
    than it could before.  Those it can't, will return error codes instead of
    being executed incorrectly.  Multi-byte reads were not being done
    correctly, which should be fixed.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 634bc48da766a9817e55e7dbd9909a6b26567e92
Author: Aapo Tahkola <aet@rasterburn.org>
Date:   Mon Mar 5 18:57:27 2007 -0300

    V4L/DVB (5426): M920x: remove unneeded code
    
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 480ac761729349f9005d2c6dce6076f7e33de3bc
Author: Aapo Tahkola <aet@rasterburn.org>
Date:   Mon Mar 5 18:54:27 2007 -0300

    V4L/DVB (5425): M920x: rework driver code to allow for different devices
    
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 26a154c355cceba66ff13b383aa2019c28dbc685
Author: Aapo Tahkola <aet@rasterburn.org>
Date:   Mon Mar 5 18:25:36 2007 -0300

    V4L/DVB (5424): Fix i2c implementation for gl861 and au6610
    
    - r/w bit is not part of the i2c address
    
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 26247018be1ca7ca464f5f32e8ca7c897ded5393
Author: Aapo Tahkola <aet@rasterburn.org>
Date:   Mon Mar 5 18:23:19 2007 -0300

    V4L/DVB (5423): M920x: i2c cleanups
    
    - Implement m920x i2c as suggested by Pierre Willenbrock
    - remove "magic" hack
    - r/w bit is not part of the i2c address
    - move hardware remarks to header file
    
    Signed-off-by: Aapo Tahkola <aet@rasterburn.org>
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit fee73165ee0ff7cfbffad4233a70f56b821f434e
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sun Mar 11 14:16:42 2007 -0300

    V4L/DVB (5420): Initialize the inputs before registering the devices.
    
    Once the devices have been registered anyone can start changing the inputs or
    TV standard before they have been initialized by the driver. This leads to
    cases were the input is changed in an udev rule, but after that rule is
    triggered the tail-end of the ivtv driver initialization can override
    that by selecting the tuner input.
    The correct sequence is to first setup the input, initial frequency and TV
    standard before finally registering the video devices. This prevents any
    udev rules from being triggered prematurely.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6816b1991fd4bcb457c9534e8136476e45bfee0a
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sun Mar 11 10:54:11 2007 -0300

    V4L/DVB (5419): Add comment how the speed field is interpreted.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3700a90f05f316948328e8d0e6a9955338a96565
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sun Mar 11 10:50:03 2007 -0300

    V4L/DVB (5418): Speed is a signed 32-bit integer, not unsigned.
    
    Negative speed values have to be allowed for reverse playback.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f40a29168475d64d854ef16a9263b24b0b2a9c6e
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 20:50:51 2007 -0300

    V4L/DVB (5417): First unregister the driver, and then free the memory.
    
    ivtv_remove which is called by pci_unregister_driver was still using
    memory that was already freed. Ouch.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6773c1c24d48f0aa667ba2aff573904a77050f09
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 20:34:54 2007 -0300

    V4L/DVB (5416): Use pci_register_driver instead of pci_module_init in ivtv.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1e5e9aab31d3f73977d2b14189a0bb08b582cbb9
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 20:11:23 2007 -0300

    V4L/DVB (5414): Add missing kfree in early exit of saa7115.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d6102900e7e06e1c0c93889d38848a5b2d44e41d
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 20:09:07 2007 -0300

    V4L/DVB (5413): Use spin_lock_init to fix lockdep warnings.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 25415cf3b8b3982b065e2227f079ea9cf7a97ef7
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 18:29:48 2007 -0300

    V4L/DVB (5412): Fix VIDIOC_TRY_ENCODER_CMD and VIDEO_TRY_COMMAND
    
    VIDIOC_TRY_ENCODER_CMD did the same as VIDIOC_ENCODER_CMD, now it no longer
    touches the encoder.
    Both the encoder and decoder commands did not clear the flags field of unknown
    flags.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d4e7ee36f988d2757c218d61c2f334df0a1acd45
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 18:19:12 2007 -0300

    V4L/DVB (5411): Use v4l_printk_ioctl for debug
    
    Using v4l_printk_ioctl saves a lot of code duplication. Also moved a few
    ioctl cases to another function, improving the ioctl grouping.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d46c17d7aa12e30b612acae35535fcd64f2db3d6
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 17:59:15 2007 -0300

    V4L/DVB (5410): Add VIDIOC_G/S_PRIORITY support to ivtv.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a542fe47fe3f758e47d71640e7ca328c032a13e1
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 13:56:56 2007 -0300

    V4L/DVB (5409): Add CARDLIST.ivtv and README.ivtv
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3f3f6a5958ffc651227df671704467654b71c09d
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 08:10:11 2007 -0300

    V4L/DVB (5407a): Update feature-removal-schedule.txt: remove VIDIOC_S/G_MPEGCOMP
    
    Those two experimental APIs never worked fine nor, afaik, were
    implemented at the apps. Their functionalities were implemented by other
    means.
    So, let's remove those obsolete stuff.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit b6735ac24ef735532d8f6d71eb30bca365d9307a
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 06:59:44 2007 -0300

    V4L/DVB (5406): Add comment why the symbols are exported.
    
    It is not immediately obvious why the ivtv symbols are exported
    in ivtv-driver.c since both ivtv-fb and the IR-blaster module
    are still out-of-tree, currently being ported to be in kernel.
    
    Added a comment so people are aware of these issues.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 83df8e7b0d7b319f9ce9773eaf4b1da324ae17d7
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 06:54:58 2007 -0300

    V4L/DVB (5405): Add missing includes.
    
    Every file should include the headers containing the prototypes
    for its global functions.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1e13f9e3f1501cc167e40a2adf07e6e4705cb331
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 06:52:02 2007 -0300

    V4L/DVB (5404): Merges VBI & YUV handling into a single work queue.
    
    Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 037c86c53362b0b3dda6201c9f62f64c9d17abb6
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 06:30:19 2007 -0300

    V4L/DVB (5403): Set vsync_field correctly in ivtv.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 43d0dfcfc654fa18b6dd91b9483273b44112997f
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 10 06:24:30 2007 -0300

    V4L/DVB (5402): Add vsync_field to the union in video_event for VIDEO_EVENT_VSYNC
    
    VIDEO_EVENT_VSYNC needs to tell the application which field it was that
    received a VSYNC (odd/even/progressive). The vsync_field was added to the
    union in video_event for this purpose.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5332bdbe9aae9e1a8fc5daaca6c75f05bc37d310
Author: Oliver Neukum <oneukum@suse.de>
Date:   Fri Mar 9 18:05:43 2007 -0300

    V4L/DVB (5399): Usbvideo module handling
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5cdc178d1c7e677f0344b7b933d71c900ae73c85
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date:   Fri Mar 9 17:43:39 2007 -0300

    V4L/DVB (5398): Cpia_pp.c: don't use _WORK_NAR
    
    pp_cam_entry->cb_task need not to be _NOAUTOREL ... because in fact it is
    never used ???
    
    Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 15f189e9780d2859ee2bd5ee6b7180a010a9ebf5
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Mar 9 17:39:52 2007 -0300

    V4L/DVB (5397): Saa7134: fix MODULES=n compilation
    
    This patch fixes the following compile error with CONFIG_MODULES=n:
      CC      drivers/media/video/saa7134/saa7134-core.o
    /home/bunk/linux/kernel-2.6/linux-2.6.21-rc2-mm1/drivers/media/video/saa7134/saa7134-core.c:979:24: error: macro "request_submodules" passed 1 arguments, but takes just 0
    /home/bunk/linux/kernel-2.6/linux-2.6.21-rc2-mm1/drivers/media/video/saa7134/saa7134-core.c: In function 'saa7134_initdev':
    /home/bunk/linux/kernel-2.6/linux-2.6.21-rc2-mm1/drivers/media/video/saa7134/saa7134-core.c:979: error: 'request_submodules' undeclared (first use in this function)
    /home/bunk/linux/kernel-2.6/linux-2.6.21-rc2-mm1/drivers/media/video/saa7134/saa7134-core.c:979: error: (Each undeclared identifier is reported only once
    /home/bunk/linux/kernel-2.6/linux-2.6.21-rc2-mm1/drivers/media/video/saa7134/saa7134-core.c:979: error: for each function it appears in.)
    make[5]: *** [drivers/media/video/saa7134/saa7134-core.o] Error 1
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 93566ad8068a968c3e72951b4539eb9da661446d
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Mar 7 18:19:49 2007 -0300

    V4L/DVB (5392): Zr364xx: Use kernel's byte-swapping function
    
    Some code to swap bytes wasn't using the swab16() function that the
    kernel provides for this.  Make use of it, which results in more
    efficient code.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Antoine Jacquet <royale@zerezo.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit cf3c34c87f921c5c63d47285c9860345cdaf5170
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Wed Mar 7 18:19:48 2007 -0300

    V4L/DVB (5391): Saa7134: Clean up printk()s
    
    Change some debug messages from printk() to dprintk().
    
    Add KERN_WARNING and KERN_ERR level indicators to other printk()s that
    lacked them.
    
    Format printk lines with consistent ("%s/dvb: ", dev->name) prefix.
    
    Fixed dprintk macro, which had an if with no else that wasn't protected
    with a do {} while(0) block.  That leads to "if(...) dprintk(); else" not
    doing what one would expect.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3b35b4b38049356b1e0b8e64ee27d1aca606b766
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Wed Mar 7 17:10:07 2007 -0300

    V4L/DVB (5389): Add tveeprom entry for tuner LG S701D MK3
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a415783bbb9fba7be2eeaeb5e3e08262bd3d64a1
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Wed Mar 7 11:28:33 2007 -0300

    V4L/DVB (5388): Ivtv warning fix
    
    drivers/media/video/ivtv/ivtv-i2c.c:547: warning: initializer-string for array of chars is too long
    drivers/media/video/ivtv/ivtv-i2c.c:547: warning: (near initialization for 'ivtv_i2c_client_template.name')
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e6c1df5581320720b8212a543e055e19d46f32bb
Author: Dwaine P. Garden <DwaineGarden@rogers.com>
Date:   Tue Mar 6 15:15:19 2007 -0300

    V4L/DVB (5386): Add some missing Hauppauge and Belkin devices to the driver
    
    -Add some missing Hauppauge and Belkin devices to the driver.
    -Fixed up some device descriptions.
    
    Signed-off-by: Dwaine P. Garden <DwaineGarden@rogers.com>
    Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 2575f84a50f71b867d8d2ff2994eefc92d60ac79
Author: Antoine Jacquet <royale@zerezo.com>
Date:   Mon Mar 5 06:32:29 2007 -0300

    V4L/DVB (5385): Fix compilation issue with zr364xx when V4L1 is disabled
    
    Add a missing header to fix compilation issue in the zr364xx driver when
    CONFIG_VIDEO_V4L1 and CONFIG_VIDEO_V4L1_COMPAT are not set.
    
    Signed-off-by: Antoine Jacquet <royale@zerezo.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a6210b7bea86305871bdca32f38b115b3ea67edf
Author: Emil Georgiev <emilonlinester@gmail.com>
Date:   Sun Mar 4 07:03:17 2007 -0300

    V4L/DVB (5383): Fix duplicated codes in Pinnacle Grey remote
    
    The keymap for this remote had duplicated labels for different keys,
    which resulted in those key pairs being unable to function as different
    inputs.
    
    Signed-off-by: Emil Georgiev <emilonlinester@gmail.com>
    Signed-off-by: Ricardo Cerqueira <v4l@cerqueira.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 14500d4a5140252f2524d8d89a22166ef2313614
Author: Oliver Endriss <o.endriss@gmx.de>
Date:   Sat Mar 3 14:45:48 2007 -0300

    V4L/DVB (5381): Dvb-ttpci: Update frontend lock status in transfer mode (bugfix)
    
    In transfer/replay mode the frontend lock status was never updated.
    This caused a 'black screen' if VDR switched from transfer mode to
    live mode on the same transponder.
    Thanks to Marco Schluessler for spotting the problem.
    
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit bfce1747e8c5a7b4b0d1331328a08f26fa5b2f2e
Author: Jean Delvare <khali@linux-fr.org>
Date:   Sat Mar 3 13:34:34 2007 -0300

    V4L/DVB (5380): Cx25840-firmware include cleanup
    
    There is no reason why cx25840-firmware.c would need to include
    <linux/i2c-algo-bit.h>.
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 31ec13561060b748221f4e0404bcc5bf8078ccd0
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 3 08:50:42 2007 -0300

    V4L/DVB (5379): If possible make vars/functions static.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 43053c07fa2935038bfc0e5dbaf417d1d66cd95d
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 3 08:40:36 2007 -0300

    V4L/DVB (5378): Add missing IVTV_FB_WARN #define
    
    This is needed for ivtv-fb.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit a51a50bd01e9f45245edd67dad7cef3ddb8452c5
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 3 08:28:54 2007 -0300

    V4L/DVB (5377): Replace SA_* with IRQF_*
    
    SA_* interrupt flags are being phased out, update to newer flags.
    Thanks to Maarten Maathuis for pointing this out to me.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 4b0e51dd6d7998a7acaca880392979a4a7072d21
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 3 08:15:36 2007 -0300

    V4L/DVB (5376): Add dependency on VIDEO_V4L1
    
    VIDEO_V4L1 is needed to get tvaudio to be built. Stupid really as ivtv is only
    using the v4l2 API to communicate with tvaudio.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 82dcab2d628ec680d701f6de66441ddc2c367227
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Sat Mar 3 08:01:54 2007 -0300

    V4L/DVB (5375): Add missing VIDEO_CX25840 dep, remove unused VIDEO_TLV320AIC23B dep
    
    VIDEO_CX25840 was missing in the ivtv dependencies. VIDEO_TLV320AIC23B
    was removed since it isn't used by ivtv.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit d9e54324d03add27990ac27fcb34a1ae7a0f97ef
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Mar 2 19:42:21 2007 -0300

    V4L/DVB (5374): Or51132: refactor i2c code, improve error resilience
    
    The code the i2c transactions was leftover from the old V4L-based ATSC
    driver.  It did too little with too much code.  It is re-written to
    remove unnecessary parameters and be more efficient.  A demod register
    can now be read with one function call, instead of repeating a dozen line
    block of code each time.
    
    There were msleep()'s, which appear to be unnecessary, spread around all
    the I2C transactions.  These have been removed.  Reading SNR used to take
    about 130 ms, now it's down to 1.8 ms.
    
    Reads from the demodulator's registers do not return correct results
    sometimes.  Adding or removing the delays in the I2C transactions did not
    appear to effect the probability of failure.  If anything, the
    transactions without delays were less likely to fail, but since far more
    transactions could be made per second the number of failures per hour was
    greater.
    
    To increase reliability, the SNR and get_params functions will now retry
    once if they get bad data back.  This appears to have reduced the
    probability of failure to effectively zero.
    Some error messages are cleaned up or given KERN_* levels when they were
    missing.
    
    or51132_setmode() wasn't returning correct error codes, which is fixed as
    well.
    
    CC: Rusty Scott <rustys@ieee.org>
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 387e69adff3d441616b45002ff85c5b36001be9e
Author: Dennis Ranke <mail@exoticorn.de>
Date:   Fri Mar 2 06:27:28 2007 -0300

    V4L/DVB (5373): [PATCH] Hauppauge Nova-T endianess problem on powerpc
    
    When trying to use a Hauppauge Nova-T Stick on a big-endian architecture
    (such as powerpc) no frontend can be attached.
    The attached patch fixes this problem by removing two lines in
    dib0700_ctrl_rd() that try to correct the endianess on two values that
    already are correct:
    -       /* think about swapping here */
    -       value = le16_to_cpu(value);
    -       index = le16_to_cpu(index);
    With this simple patch this dvb hardware works great, thanks to anyone
    involved for the good work. :)
    
    Signed-off-by: Dennis Ranke <mail@exoticorn.de>
    Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ddc9ece89dbeb374e34772232f5e26f64ce63390
Author: Christophe Cattelain <xof@skynet.be>
Date:   Fri Apr 27 12:31:32 2007 -0300

    V4L/DVB (5371): [PATCH] Pinnacle PCTV Sat Pro USB (450e) support by ttusb2.c (400e driver)
    
    Added USB_PID_PCTV_450E to the 'usb_device_id ttusb2_table' and an entry in the
    .devices table.  The 400e driver now supports the 'Pinnacle PCTV Sat Pro USB
    (450e)' with USB_ID 2304:0222.
    
    Signed-off-by: Christophe Cattelain <xof@skynet.be>
    Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ede2200d79777d461cf2f0fd19cf7a17f633d3a4
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:32 2007 -0300

    V4L/DVB (5369): Fixed 1 byte too short buffer in tda827x.c
    
    - The i2c data buffer in tda827xa_set_params was 1 byte too short
    - saa7134-dvb now gives an error mesage if tda827x could not be attached
    - coding style fix in tda1004x.c
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 8481a7506bc71622bb5bbd89bc89b2f38bff5ead
Author: Mike Isely <isely@pobox.com>
Date:   Fri Apr 27 12:31:31 2007 -0300

    V4L/DVB (5367): Pvrusb2: (trivial) Fix too-wide source line
    
    Signed-off-by: Mike Isely <isely@pobox.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 6bdcc6e6dbab8daffd05e5026486f34ba41a6c72
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Apr 27 12:31:30 2007 -0300

    V4L/DVB (5363): Dvb: Remove lgh06xf driver
    
    The code of the dvb-pll driver and the lgh06xf driver is nearly
    identical.  The main difference is that the lgh06xf driver would set the
    AGC TOP value on every tune call.  The dvb-pll driver now has the ability
    to set the AGC TOP when the front-end device is opened, which is a better
    way to go about it.  By using this ability of dvb-pll, the lgh06xf driver
    is made unnecessary.
    
    There is one other difference.  dvb-pll will probe for the presence of an
    I2C pll chip by doing a one byte read, the lgh06xf driver did not do
    this.  In some devices the PLL is not reachable over I2C at the timer the
    tuner is attached.  Some more initialization, such as firmware loading,
    must take place first.  None of the devices using a LG-H06xF should have
    this problem.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Acked-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 26aed92289ae8caffeedebb3f841a9e0371119a9
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Apr 27 12:31:29 2007 -0300

    V4L/DVB (5362): Dvb-pll: add code for doing tuner initialization
    
    Some tuners need or benefit from initialization, to change certain
    settings from their power on default values.
    
    Typically, tuners with TUA603x PLLs can benefit from setting the AGC TOP
    value to something else.  This patch includes code to set the AGC TOP to
    103 dBuV for the Thomson DTT-761x tuners, which I have experimentally
    verified gives the best SNR readings, increasing SNR by about 0.19 dB
    over the default value.
    
    Other tuners can make use of this as well.  For example, the separate LG
    TDVS-H06xF driver's only difference from dvb-pll is this same setting of
    AGC TOP value.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9ab1ba38e6a25a480234f196aa26239e28ac2407
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Apr 27 12:31:28 2007 -0300

    V4L/DVB (5361): Dvb-pll: Fix Kconfig files and allow dvb-pll to be optional
    
    A number of drivers selected DVB_PLL when they did not need it, and some
    that did need it did not select it.
    
    The DVB_PLL option is given a name and help text, so that it will show up
    in the config menu.  DVB_PLL support can be turned on if an out-of-tree
    driver needs it.
    
    The standard dvb fe customization support is added to dvb-pll.h.  Since
    all modules which select DVB_PLL do so unconditionally, it is not
    possible to turn dvb-pll off when an enabled module selects it, unlike
    most of the other frontend/tuner drivers.  This is because the users of
    dvb-pll have static references to dvb-pll symbols other than the attach
    function.  If these references are removed, then dvb-pll will be
    disablable as the other frontend/tuner drivers are.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 982dd1bdaab39185ccd55cafd3c099b7fee5f2dd
Author: Trent Piepho <xyzzy@speakeasy.org>
Date:   Fri Apr 27 12:31:27 2007 -0300

    V4L/DVB (5360): Dvb-pll: Use sizeof() to get name length
    
    Better to use sizeof() to get the size of the output buffer for the tuner
    name, instead of just hard coding 128.
    
    Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 51dec1f1abef9771d9085c2336234b28b3e78821
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:27 2007 -0300

    V4L/DVB (5356): Fix bogus error messages in ivtv for VIDIOC_G_CHIP_IDENT
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 74cab31c413c8615efe818d44ff4ac83e2a138be
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:26 2007 -0300

    V4L/DVB (5355): Add VIDIOC_G_CHIP_IDENT to various i2c modules
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1a0adaf37c30e89e44d1470ef604a930999a5826
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:25 2007 -0300

    V4L/DVB (5345): ivtv driver for Conexant cx23416/cx23415 MPEG encoder/decoder
    
    It took three core maintainers, over four years of work, eight new i2c
    modules, eleven new V4L2 ioctls, three new DVB video ioctls, a Sliced
    VBI API, a new MPEG encoder API, an enhanced DVB video MPEG decoding
    API, major YUV/OSD contributions from Ian and John, web/wiki/svn/trac
    support from Axel Thimm, (hardware) support from Hauppauge, support and
    assistance from the v4l-dvb people and the many, many users of ivtv to
    finally make it possible to merge this driver into the kernel.
    Thank you all!
    
    Signed-off-by: Kevin Thayer <nufan_wfk@yahoo.com>
    Signed-off-by: Chris Kennedy <c@groovy.org>
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: John P Harvey <john.p.harvey@btinternet.com>
    Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ac52ea3c3c04403d10acf0253180ec6f51977142
Author: Oliver Endriss <o.endriss@gmx.de>
Date:   Fri Apr 27 12:31:24 2007 -0300

    V4L/DVB (5344): Dvb-ttpci: Support for MSC_RAW and MSC_SCAN RC events
    
    Support for MSC_RAW and MSC_SCAN remote control events.
    
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1b5888cea1d371239a130150222e63d476298d89
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:23 2007 -0300

    V4L/DVB (5341): Add cx23415/6 chip idents.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 0b20060f6c2cc69c5394cf9782513e7b526e87b9
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:22 2007 -0300

    V4L/DVB (5336): Cx23416 doc updates + rename CX2341X_ENC_UNKNOWN
    
    The documentation of Several miscellaneous commands was updated.
    As a result of which the CX2341X_ENC_UNKNOWN command was renamed to
    CX2341X_ENC_SET_VERT_CROP_LINE.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 145859cb8fafc1d75e780ea182413b13f5913a7f
Author: David Härdeman <david@hardeman.nu>
Date:   Fri Apr 27 12:31:22 2007 -0300

    V4L/DVB (5335): Budget-ci: Use the repeat handling of the input subsystem
    
    The attached patch contains the last set of changes to the budget-ci IR
    handling which makes it use the repeat handling of the input subsystem.
    This allows some code simplification, makes sure that repeat key presses
    are reported as such and also allows the "debounce" hack to be removed
    altogether.
    In addition a couple of static variables were removed which would have
    confused the IR code if more than one card is used.
    
    Signed-off-by: David Hardeman <david@hardeman.nu>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ee820a648fb333034aa455e8e1479b89798a1281
Author: Oliver Endriss <o.endriss@gmx.de>
Date:   Fri Apr 27 12:31:21 2007 -0300

    V4L/DVB (5334): Dvb-ttpci: Infrared remote control refactoring
    
    Infrared remote control support rewritten.
    Now each device provides its own event device, keymap, protocol,
    inversion and address setting.
    EVIOCGKEYCODE and EVIOCSKEYCODE ioctls are supported to read/modify
    a keymap. Keymaps may be loaded using
    - input tools (keyb etc.)
    - av7110_loadkeys (obsolete, for backward compatibility)
    New command line parameters:
    - ir_protocol:    select infrared protocol: 0 RC5, 1 RCMM (default)
    - ir_inversion:   signal inversion: 0 not inverted (default), 1 inverted
    - ir_device_mask: bitmask of infrared devices (default: accept all)
    Those parameters may be set anytime.
    
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit db4836791dc578f0f6e9573468cffeee00fa7ebc
Author: Peter Missel <peter.missel@onlinehome.de>
Date:   Fri Apr 27 12:31:20 2007 -0300

    V4L/DVB (5331): Identify MSI TV@nywhere Duo
    
    It is a Lifeview Duo with a different ID
    
    Signed-off-by: Peter Missel <peter.missel@onlinehome.de>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit e95d317da2de7116ef66fa16bd9664cd39f1c11c
Author: Markus Rechberger <mrechberger@gmail.com>
Date:   Fri Apr 27 12:31:19 2007 -0300

    V4L/DVB (5330): Added card definition for AverMedia M102 miniPCI
    
    Signed-off-by: Markus Rechberger <mrechberger@gmail.com>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 9040b32ea34eff58c59b46abf440c0dd1614c8a2
Author: Heikki Orsila <shdl@zakalwe.fi>
Date:   Fri Apr 27 12:31:18 2007 -0300

    V4L/DVB (5329): Some saa7134 cleanups
    
    - use generic sort instead of bubblesort
     - removed useless saa7134_video_fini function
     - small coding style changes
    
    Signed-off-by: Heikki Orsila <heikki.orsila@iki.fi>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 80f90fba3ed8c8826d968125004e4462d2de172e
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:18 2007 -0300

    V4L/DVB (5326): Allow to set tuner_config in attach inform
    
    This patch move the assignment of the tuner config and the callback
    before the check whether it is called in the attach inform.
    This solves a module load order issue
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 4217e25275eeb1973ca5bed65645f70b8f6c199d
Author: Markus Rechberger <markus.rechberger@amd.com>
Date:   Fri Apr 27 12:31:17 2007 -0300

    V4L/DVB (5324): This patch fixes request_module_depend()
    
    this patch fixes request_module_depend()
    
    Signed-off-by: Markus Rechberger <markus.rechberger@amd.com>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit cfeb88398f004a0e85ee011fd89a01f5d3bf3c81
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:17 2007 -0300

    V4L/DVB (5323): Updated support for tuner callbacks
    
    This change supplies a more generic version of the tuner callback.
    The tuner struct now has a function pointer
      int (*tuner_callback) (void *dev, int command, int arg)
    additionally to a int config parameter.
    both can be set through the TUNER_SET_TYPE_ADDR client call.
    Note that the meaning of the parameters depend on the tuner type.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit b8bc76d88fa7a1e4cd679fac3adfc5afeb2b3427
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:16 2007 -0300

    V4L/DVB (5322): Removed board naming code in saa7134-dvb
    
    This is for better consistency with other drivers
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1c4f76abb85918646eed5dee0b26744cc49fd1da
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:16 2007 -0300

    V4L/DVB (5321): Saa7134-dvb: initialize the dvb frontend in dvb_init
    
    The hardware is completely initialized afterwards, especially the
    tda10046 has its firmware - which is also necessary in analog mode
    of some hybrid boards.
    Calling the sleep function afterwards saves power and definitely puts
    hybrid boards into analog mode without additional code elsewere.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 11f65106adb25a9ef5b6d8911267b2365c97a759
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:15 2007 -0300

    V4L/DVB (5320): Filled in limiting values in tda827x.c
    
    The parameters for minimum and maximum frequency were missing.
    Also added mail addresses of the module authors.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 68717583557341874b2eea4dea36635256e932b6
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:15 2007 -0300

    V4L/DVB (5319): Set tda827x to sleep mode after attach
    
    This change sets the tda827x to sleep mode right after attach in dvb
    mode. It is just to save power. For the same reason, the ADC of the
    tda10046 gets turned off in sleep mode.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 06be3035f96d73cf64dc20a8ee37c902d7a2ff2d
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:15 2007 -0300

    V4L/DVB (5318): Fix tda8290 code for tda827x module
    
    During tuner attach, the pointers to host dev structure
    are not set yet, so the I2c adapter needs to be accessed differently.
    This patch also does some minor cleanup in the saa7134-dvb module.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 8ce47dad8e2b9fcb899a67e6537337fa9c18c1f5
Author: Michael Krufky <mkrufky@linuxtv.org>
Date:   Fri Apr 27 12:31:14 2007 -0300

    V4L/DVB (5317): Create tda827x dvb tuner module
    
    The patch moves the tda827x dvb tuning code to a separate module
    
    Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 7c7fea669d77048b3013567dfb4c9171d536da05
Author: Peter Missel <peter.missel@onlinehome.de>
Date:   Fri Apr 27 12:31:14 2007 -0300

    V4L/DVB (5316): Add radio support for the Lifeview FlyDVB-T Duo
    
    There are card variants supporting FM radio through tda8275.
    
    Signed-off-by: Peter Missel <peter.missel@onlinehome.de>
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit f4546e702a89d2e483570f0f16c5155bb781cc38
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:13 2007 -0300

    V4L/DVB (5315): Tda1004x: check request firmware for NULL ponter again
    
    In older versions, this was used to decide whether to boot from
    eeprom or file. This is no longer necessary but the check helps to avoid
    an oops with misconfigured cards.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 58ef4f924cf2824ae198b1fec3eea1e4059a021c
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:12 2007 -0300

    V4L/DVB (5314): Added support for tda827x tuners with preamlifiers
    
    This patch contains
    - new tuning code for the tda827xa silicon tuner.
    - controls the preamplifier of some boards with this tuner.
    - support for the Philips Tiger S hybrid DVB-T reference design.
    - reworked the saa7134-dvb modulue to get rid of most of the
      small board specific functions.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit de956c1e0f89413a3837b642d592e2dff3e3eb78
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:12 2007 -0300

    V4L/DVB (5313): Added a config entry and a gpio function pointer to tuner struct
    
    These entries mainly are to support configurations of the tda827x
    silicon tuner with a preamplifier.
    The values can be set throgh the attach inform or through
    the extended TUNER_SET_TYPE_ADDR client call. The function pointer
    will only be updated if the parameter is not NULL.
    Since a typecast is necessary to set the pointer, i added a typedef for
    this pointer (tuner_gpio_func_t) in tuner.h
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit b8195946228c749702dfe5995b98516ea4b04cdc
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:11 2007 -0300

    V4L/DVB (5312): Saa713x: added a GPIO handler function
    
    This function allows to set, clear and tristate the GPIO ports.
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 1bb0e8667fab773d6c5a3d7caf506001deaeb7f5
Author: Hartmut Hackmann <hartmut.hackmann@t-online.de>
Date:   Fri Apr 27 12:31:10 2007 -0300

    V4L/DVB (5311): Tda1004x driver updates
    
    There are the following changes:
    - separate configuration of IF and GPIOs.
    - set GPIOs before firmware load. This helps to avoid I2C address
      collisions.
    - if desired invert GPIOs at sleep (automatic return to analog mode of card).
    - added 3 tuner configuration bytes to config stuct.
    - added i2c gate address to config struct.
    - moved _state struct declaration to header file to make it accessible
      on board layer.
    - added "conf_probed" to the state struct to allow i.e. probing for correct
      tuner version.
    - changed firmware load mechanism to always:
      + check if already loaded
      + try to boot from eeprom
      + try downlad from host
    - corrected name of tda10046 firmware image (backward compatible).
    
    Signed-off-by: Hartmut Hackmann <hartmut.hackmann@t-online.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 2435be11ae1afb64ac7dfb25e10b6e3037ab0522
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:09 2007 -0300

    V4L/DVB (5307): Add support for the cx23415 MPEG decoding features.
    
    The cx23415 adds some extra features that this DVB decoding API did
    not support. This API has been expanded to support the required
    features. Both source and binary backwards compatibility is kept
    intact by these changes. So existing applications are not affected.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
    Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3434eb7e14d9587ee56f3462bcfa5726b62dadb9
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:08 2007 -0300

    V4L/DVB (5306): Add support for VIDIOC_G_CHIP_IDENT
    
    VIDIOC_G_CHIP_IDENT improves debugging of card problems: it can be
    used to detect which chips are on the board and based on that information
    selected register dumps can be made, making it easy to debug complicated
    media chips containing tens or hundreds of registers.
    This ioctl replaces the internal VIDIOC_INT_G_CHIP_IDENT ioctl.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit ced80c67cd1ed503c6fb72f02ac7342ab4ebf67a
Author: Markus Rechberger <mrechberger@gmail.com>
Date:   Fri Apr 27 12:31:07 2007 -0300

    V4L/DVB (5299): Added support for loading cx88-dvb and cx88-blackbird
    
    Added support for loading cx88-dvb and cx88-blackbird
    
    Signed-off-by: Markus Rechberger <mrechberger@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 77b7477467824098741351b6253a4ad292e28df9
Author: Markus Rechberger <mrechberger@gmail.com>
Date:   Fri Apr 27 12:31:06 2007 -0300

    V4L/DVB (5298): Added support for deferred module requesting to cx88
    
    added support for deferred module requesting to cx88
    
    Signed-off-by: Markus Rechberger <mrechberger@gmail.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit acf2821282bdd912f9ca46780879a21679429f85
Author: Mauro Carvalho Chehab <mchehab@infradead.org>
Date:   Fri Apr 27 12:31:06 2007 -0300

    V4L/DVB (5297): Fix identation on tda10021.c
    
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5948e52cee0f2e72f8aaf0a78fec257f217efd88
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 27 12:31:05 2007 -0300

    V4L/DVB (5294): Make pvr2_encoder_prep_config() static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3721929ed327ac2a6a879ad0b7dcbfc8ba2ae93f
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 27 12:31:05 2007 -0300

    V4L/DVB (5293): Make dvb_usb_gl861_debug static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 045290b2a90ff1be60196a061aadecf70eb6bcc3
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:04 2007 -0300

    V4L/DVB (5290): Add support for VIDIOC_INT_G/S_STD_OUTPUT
    
    Added VIDIOC_INT_G_STD_OUTPUT and VIDIOC_INT_S_STD_OUTPUT to allow drivers
    to set the TV standard for video output separately from the video capture.
    This is needed for cx23415 support where the decoder is separate from the
    encoder and can have a different TV standard.
    Modified the saa7127 module to listen to VIDIOC_INT_G/S_STD_OUTPUT instead
    of VIDIOC_G/S_STD.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit b2787845fb91da18ebb079dc9297f92d990e9fe1
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:02 2007 -0300

    V4L/DVB (5289): Add support for video output overlays.
    
    Add V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY support.
    Also add support for local and global alpha overlays.
    Add new field enums V4L2_FIELD_INTERLACED_TB and V4L2_FIELD_INTERLACED_BT.
    These changes are needed to support the ivtv On Screen Display features.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 3bfb7398e2554fb54acb2900b81de144eb41c3ac
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 27 12:31:01 2007 -0300

    V4L/DVB (5278): Bt8xx/: possible cleanups
    
    This patch contains the following possible cleanups:
    - remove the following unused global functions:
      - bttv-if.c: bttv_get_cardinfo()
      - bttv-if.c: bttv_get_id()
      - bttv-if.c: bttv_get_gpio_queue()
      - bttv-if.c: bttv_i2c_call()
    - remove the following unused EXPORT_SYMBOL's:
      - bttv-gpio.c: bttv_sub_bus_type
      - bttv-gpio.c: bttv_gpio_inout
      - bttv-gpio.c: bttv_gpio_read
      - bttv-gpio.c: bttv_gpio_write
      - bttv-gpio.c: bttv_gpio_bits
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 206ebaf32795cf1582b1e2ff2ec6a560c9e986b8
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:01 2007 -0300

    V4L/DVB (5272): Add V4L2_CAP_VIDEO_OUTPUT_POS capability
    
    Add V4L2_CAP_VIDEO_OUTPUT_POS capability and x, y position coordinates
    to struct v4l2_pix_format.
    This is needed to support positioning the MPEG/YUV output of the cx23415.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 5eee72e88416ef11f55791626440ac3c9018c4c0
Author: Hans Verkuil <hverkuil@xs4all.nl>
Date:   Fri Apr 27 12:31:00 2007 -0300

    V4L/DVB (5268): Add support for three new MPEG controls.
    
    Added V4L2_CID_MPEG_AUDIO_MUTE, V4L2_CID_MPEG_VIDEO_MUTE and
    V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS controls together with
    their implementation in the cx2341x module.
    
    Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit b7eee616ad8db5db5441a7d82083003df3ab6d3b
Author: Antoine Jacquet <royale@zerezo.com>
Date:   Fri Apr 27 12:30:59 2007 -0300

    V4L/DVB (5257): USB: add zr364xx V4L2 driver
    
    This patch adds a V4L2 driver giving support for USB webcams based on the
    zr364xx chipsets.
    
    Signed-off-by: Antoine Jacquet <royale@zerezo.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

commit 404d5b185b4eb56d6fa2f7bd27833f8df1c38ce4
Author: Dan Williams <dan.j.williams@intel.com>
Date:   Thu Apr 26 00:12:10 2007 -0700

    dev_dbg: check dev_dbg() arguments
    
    Duplicate what Zach Brown did for pr_debug in commit
    8b2a1fd1b394c60eaa2587716102dd5e9b4e5990
    
    [akpm@linux-foundation.org: fix a couple of things which broke]
    Signed-off-by: Dan Williams <dan.j.williams@intel.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 61a2f59af6c8ffd9d6dd53f0da32563d4434e790
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Thu Apr 26 00:12:09 2007 -0700

    drivers/base/attribute_container.c: use mutex instead of binary semaphore
    
    use mutex instead of binary semaphore in
    drivers/base/attribute_container.c
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 240936e18b75937e7866934df723c2db0011d24f
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Thu Apr 26 00:12:09 2007 -0700

    mod_sysfs_setup() doesn't return errno when kobject_add_dir() failure occurs
    
    mod_sysfs_setup() doesn't return an errno when kobject_add_dir() for module
    "holders" directory fails.  So caller of mod_sysfs_setup() will keep going
    and get oops.
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit a53c46dc8253cc613ad66a2ca7aad6de8b7e61b9
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 11:43:58 2007 +0200

    s2ram: add arch irq disable/enable hooks
    
    After some more discussion this patch replaces it:
    
    From: Johannes Berg <johannes@sipsolutions.net>
    Subject: suspend: add arch irq disable/enable hooks
    
    For powermac, we need to do some things between suspending devices and
    device_power_off, for example setting the decrementer. This patch
    allows architectures to define arch_s2ram_{en,dis}able_irqs in their
    asm/suspend.h to have control over this step.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Pavel Machek <pavel@ucw.cz>
    Cc: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 075c1771526c85849ed22298d048bc07e400aee5
Author: David Brownell <david-b@pacbell.net>
Date:   Thu Apr 26 00:12:06 2007 -0700

    define platform wakeup hook, use in pci_enable_wake()
    
    This defines a platform hook to enable/disable a device as a wakeup event
    source.  It's initially for use with ACPI, but more generally it could be used
    whenever enable_irq_wake()/disable_irq_wake() don't suffice.
    
    The hook is called -- if available -- inside pci_enable_wake(); and the
    semantics of that call are enhanced so that support for PCI PME# is no longer
    needed.  It can now work for devices with "legacy PCI PM", when platform
    support allows it.  (That support would use some board-specific signal for for
    the same purpose as PME#.)
    
    [akpm@linux-foundation.org: Make it compile with CONFIG_PM=n]
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Zhang Rui <rui.zhang@intel.com>
    Cc: Len Brown <lenb@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 057f6c019fff9ee290641d50647359bb8898918e
Author: James Morris <jmorris@namei.org>
Date:   Thu Apr 26 00:12:05 2007 -0700

    security: prevent permission checking of file removal via sysfs_remove_group()
    
    Prevent permission checking from being performed when the kernel wants to
    unconditionally remove a sysfs group, by introducing an kernel-only variant
    of lookup_one_len(), lookup_one_len_kern().
    
    Additionally, as sysfs_remove_group() does not check the return value of
    the lookup before using it, a BUG_ON has been added to pinpoint the cause
    of any problems potentially caused by this (and as a form of annotation).
    
    Signed-off-by: James Morris <jmorris@namei.org>
    Cc: Nagendra Singh Tomar <nagendra_tomar@adaptec.com>
    Cc: Tejun Heo <htejun@gmail.com>
    Cc: Stephen Smalley <sds@tycho.nsa.gov>
    Cc: Eric Paris <eparis@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 523ded71de0c5e66973335bf99a80edfda9f401b
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Thu Apr 26 00:12:04 2007 -0700

    device_schedule_callback() needs a module reference
    
    This patch (as896b) fixes an oversight in the design of
    device_schedule_callback().  It is necessary to acquire a reference to the
    module owning the callback routine, to prevent the module from being
    unloaded before the callback can run.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Cc: Satyam Sharma <satyam.sharma@gmail.com>
    Cc: Neil Brown <neilb@suse.de>
    Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit fa1a8c23eb7d3ded8a3c6d0e653339a2bc7fca9e
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Thu Apr 26 00:12:03 2007 -0700

    s390: cio: Delay uevents for subchannels
    
    We often have the situation that we register a subchannel and start device
    recognition, only to find out that the device is not usable after all, which
    triggers an unregister of the subchannel.  This often happens on hundreds of
    subchannels on a LPAR, leading to a storm of events which aren't of any use.
    Therefore, use uevent_suppress to delay the KOBJ_ADD uevent for a subchannel
    until we know that its ccw_device is to be registered.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Cc: Eric Rannaud <eric.rannaud@gmail.com>
    Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 45cd8d8e1e56fba41b1e4fae988f40fe938045c2
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:12:10 2007 -0700

    sysfs: bin.c printk fix
    
    fs/sysfs/bin.c: In function 'read':
    fs/sysfs/bin.c:77: warning: format '%zd' expects type 'signed size_t', but argument 4 has type 'int'
    
    
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b2366d68d9ec3498b342507facf526c1f66ffa41
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Tue Apr 24 22:45:25 2007 +0200

    Driver core: use mutex instead of semaphore in DMA pool handler
    
    the DMA pool handler uses a semaphore as mutex. use the mutex API
    instead of the (binary) semaphore
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4f6e1945fecad6ac8134e9fa68b7708e55690e9e
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Fri Apr 20 11:29:52 2007 -0700

    driver core: bus_add_driver should return an error if no bus
    
    As pointed out by Dave Jones.
    
    Cc: Dave Jones <davej@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 8447891fe845851738439788c74b3c811578e3f9
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Tue Apr 17 15:59:36 2007 +1000

    debugfs: Add debugfs_create_u64()
    
    I went to use this the other day, only to find it didn't exist.
    
    It's a straight copy of the debugfs u32 code, then s/u32/u64/. A quick
    test shows it seems to be working.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 3106d46f51a1a72fdbf071ebc0800a9bcfcbc544
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Apr 6 12:21:45 2007 +0200

    the overdue removal of the mount/umount uevents
    
    This patch contains the overdue removal of the mount/umount uevents.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2753133eb3321feb81dcb9c88141dd2aa5973ee1
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Fri Apr 6 10:47:11 2007 -0600

    kobject: Comment and warning fixes to kobject.c
    
    This dots some i's and crosses some t's after left over from when
    kobject_kset_add_dir was built from kobject_add_dir.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 22af74f3b221f1436a37554501431e51c06ee77e
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Fri Apr 6 01:40:38 2007 +0200

    Driver core: warn when userspace writes to the uevent file in a non-supported way
    
    In the future we will allow the uevent type to be written to the uevent
    file to trigger the different types of uevents.  But for now, as we only
    support the ADD event, warn if userspace tries to write anything else to
    this file.
    
    Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 16574dccd8f62dc1b585325f8a6a0aab10047ed8
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Fri Apr 6 01:40:38 2007 +0200

    Driver core: make uevent-environment available in uevent-file
    
    This allows sysfs to show the environment variables that are available
    if the uevent happens.  This lets userspace not have to cache all of
    this information as the kernel already knows it.
    
    Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 4628803062d93dadc6ba8e801fd075526904a38c
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    kobject core: remove rwsem from struct subsystem
    
    It isn't used at all by the driver core anymore, and the few usages of
    it within the kernel have now all been fixed as most of them were using
    it incorrectly.  So remove it.
    
    Now the whole struct subsys can be removed from the system, but that's
    for a later patch...
    
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 2f66858a0ae48faf4c8dc19042f3aff52208dc57
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Tue Apr 17 13:01:38 2007 +0200

    qeth: Remove usage of subsys.rwsem
    
    the current driver tree contains the removal of subsys.rwsem.
    Unfortunately, this breaks qeth. However, it should be no problem to
    fix the walking of the devices for /proc/qeth:
    
    No need to take subsys.rwsem during walking the devices,
    driver_find_devices() should already suffice.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 87aebe078e450795d336d20304d01095251ff9fa
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    PHY: remove rwsem use from phy core
    
    The subsystem rwsem is not used by the driver core at all, so the use of
    it in the phy code doesn't make any sense.  They might possibly
    want to use a local lock, but I am unsure about that.
    
    Cc: netdev <netdev@vger.kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit a2a0f74dc1e7d588b0ba6a1d177f42bef18117d0
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    IEEE1394: remove rwsem use from ieee1394 core
    
    The subsystem rwsem is not used by the driver core at all, so the use of
    it in the ieee1394 code doesn't make any sense.  They might possibly
    want to use a local lock, but as most of these operations are already
    protected by a local lock, it really doesn't look like it would be
    needed.
    
    Cc: Ben Collins <bcollins@debian.org>
    Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
    Cc: linux1394-devel <linux1394-devel@lists.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c401110186cc0ce2f0e4a03695af115e6c177d95
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    IDE: remove rwsem use from ide-proc core
    
    The subsystem rwsem is not used by the driver core at all, so the use of
    it in the ide-proc code of it doesn't make any sense.  Perhaps a local
    lock might be needed, but I do not really think so.
    
    Cc: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
    Cc: linux ide <linux-ide@vger.kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 79580057de60867f535b7e7ec17c85709853d6bf
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Tue Apr 10 00:40:48 2007 -0400

    Input: gameport - do not touch bus's rwsem
    
    The subsystem rwsem is not used by the driver core at all, so there is
    no point in trying to access it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 70f256fda1649fbb3deea37e86342f6139a0a82c
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Tue Apr 10 00:40:27 2007 -0400

    Input: serio - do not touch bus's rwsem
    
    The subsystem rwsem is not used by the driver core at all, so there is
    no point in trying to access it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 75f1115c9b1a0c24d9025865285870122ec6f811
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    PNP: stop using the subsystem rwsem
    
    The rwsem is not used to protect anything, so the use of it by the PNP
    subsystem isn't really useful, and it's doubtful if it really did anything or
    not.  So I've removed it.
    
    Cc: Adam Belay <ambx1@neo.rr.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 341487a837c02cbd674d4751061e7d098b0b8e98
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    USB: remove use of the bus rwsem, as it doesn't really protect anything.
    
    The driver core stopped using the rwsem a long time ago, yet the USB
    core still grabbed the lock, thinking it protected something.  This
    patch removes that useless use.
    
    Cc: Alan Stern <stern@rowland.harvard.edu>
    Cc: Oliver Neukum <oneukum@suse.de>
    Cc: David Brownell <david-b@pacbell.net>
    Cc: linux-usb-devel <linux-usb-devel@lists.sourceforge.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b7bb125dc3d0ca3f72c9116525ce0f018a9844e1
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    SCSI: use the proper semaphore to protect the class lists
    
    SCSI was using the incorrect lock to protect walking the list of all
    devices in the class.  This patch fixes this.
    
    Cc: James Bottomley <James.Bottomley@SteelEye.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 49f019d66d056ebb261d261d7c89cb698f5eec18
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Mon Apr 9 11:52:31 2007 -0400

    Driver core: remove use of rwsem
    
    This lock is never used by the rest of the driver core, so the fact that
    we are grabbing it here means it isn't correct...
    
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 88db4721d47bc59b92d46de04e21c7975ea983f2
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Tue Apr 10 14:35:27 2007 +0200

    kobject: kobject_add() reference leak
    
    We leak a reference if we attempt to add a kobject with no name.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 14193fb91a7d88d3fe55d3160892edeb2b02e0c2
Author: John Anthony Kazos Jr <jakj@j-a-k-j.com>
Date:   Wed Apr 4 07:39:17 2007 -0400

    Kobject: kobject_uevent.c: Collapse unnecessary loop nesting (top_kobj)
    
    Collapses a do..while() loop within an if() to a simple while() loop for
    simplicity and readability.
    
    Signed-off-by: John Anthony Kazos Jr. <jakj@j-a-k-j.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit f89cbc399ecd924c4bd879344e662aace2274b4f
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Tue Apr 3 01:08:40 2007 -0400

    Driver core: add suspend() and resume() to struct device_type
    
    Driver core: add suspend() and resume() to struct device_type
    
    In cases when there are devices of different types in the same class
    we can't use class's implementation of suspend and resume methods and
    we need to add them to struct device_type instead.
    
    Also fix error handling in resume code (we should not try to call
    class's resume method iof bus's resume method for the device failed.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bf62456eb91f3d2ef0736081583d09b0b3c8b7ea
Author: Eric Rannaud <eric.rannaud@gmail.com>
Date:   Fri Mar 30 22:23:12 2007 -0700

    uevent: use add_uevent_var() instead of open coding it
    
    Make use of add_uevent_var() instead of (often incorrectly) open coding it.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Eric Rannaud <eric.rannaud@gmail.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Cc: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit bdc4960a0b4831a24276b65f1f7afdfc57f2f5cf
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Thu Mar 29 11:12:14 2007 +0200

    Driver core: switch firmware_class to uevent_suppress.
    
    Use uevent_suppress instead of returning an error code in
    firmware_uevent(). Get rid of the now unneeded FW_STATUS_READY
    and FW_STATUS_READY_NOHOTPLUG.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 83b5fb4cce13b9f7b218ed88ee05387c3f3bdda3
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Thu Mar 29 11:12:11 2007 +0200

    Driver core: suppress uevents via filter
    
    Suppress uevents for devices if uevent_suppress is set via
    dev_uevent_filter(). This makes the driver core suppress all device
    uevents, not just the add event in device_add().
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit ca2f37dbc5324c7278577731033a358f1f86050a
Author: Jean Tourrilhes <jt@hpl.hp.com>
Date:   Wed Mar 7 10:49:30 2007 -0800

    Driver core: notify userspace of network device renames
    
    Provide rename event for when we rename network devices.
    
    Signed-off-by: Jean Tourrilhes <jt@hpl.hp.com>
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 1b0b3b9980e482ab7c603430462538334f69f14a
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Apr 2 14:47:59 2007 +0200

    kref: fix CPU ordering with respect to krefs
    
    some atomic operations are only atomic, not ordered. Thus a CPU is allowed
    to reorder memory references to an object to before the reference is
    obtained. This fixes it.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 74e9f5fa1570f956c96dd5d3f1053daedbbf01a0
Author: Greg Kroah-Hartman <gregkh@suse.de>
Date:   Tue Apr 9 12:14:34 2002 -0700

    Driver core: remove unneeded completion from driver release path
    
    The completion in the driver release path is due to ancient history in
    the _very_ early 2.5 days when we were not tracking the module reference
    count of attributes.  It is not needed at all and can be removed.
    
    Note, we now have an empty release function for the driver structure.
    This is due to the fact that drivers are statically allocated in the
    system at this point in time, something which I want to change in the
    future.  But remember, drivers are really code, which is reference
    counted by the module, unlike devices, which are data and _must_ be
    reference counted properly in order to work correctly.
    
    
    Cc: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit c6a46696f97ff260a4ecce5e287f8de4b9d7fe14
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Mon Feb 5 16:15:26 2007 -0800

    driver core: don't fail attaching the device if it cannot be bound
    
    Don't fail bus_attach_device() if the device cannot be bound.
    
    If dev->driver has been specified, reset it to NULL if device_bind_driver()
    failed and add the device as an unbound device.  As a result,
    bus_attach_device() now cannot fail, and we can remove some checking from
    device_add().
    
    Also remove an unneeded check in bus_rescan_devices_helper().
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit eed40d3ad2ba652c08422d62a5ff6f62ac0be16d
Author: Andrew Morton <akpm@osdl.org>
Date:   Mon Feb 5 16:15:25 2007 -0800

    powerpc: make it compile for multithread change
    
    arch/powerpc/kernel/of_platform.c:479: error: unknown field `multithread_probe' specified in initializer
    
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 21c7f30b1d3f8a3de3128478daca3ce203fc8733
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Mon Feb 5 16:15:25 2007 -0800

    driver core: per-subsystem multithreaded probing
    
    Make multithreaded probing work per subsystem instead of per driver.
    
    It doesn't make much sense to probe the same device for multiple drivers in
    parallel (after all, only one driver can bind to the device).  Instead, create
    a probing thread for each device that probes the drivers one after another.
    Also make the decision to use multi-threaded probe per bus instead of per
    device and adapt the pci code.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 460f7e9a1bde2c74f060f7ce0a308dab4be6a56b
Author: Dmitriy Monakhov <dmonakhov@openvz.org>
Date:   Sat Mar 10 14:00:10 2007 +0300

    kobject: kobject_shadow_add cleanup
    
     - correct function name in comments
     - parrent assignment does metter only inside "if" block,
       so move it inside this block.
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 414264f959cf46f49f974b3510400e12ac3624a6
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Mon Mar 12 21:08:57 2007 +0100

    Driver core: add name to device_type
    
    If "name" of a device_type is specified, the uevent will
    contain the device_type name in the DEVTYPE variable.
    This helps userspace to distingiush between different types
    of devices, belonging to the same subsystem.
    
    Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 621a1672f7377e08a942f205d6742d8af1292aab
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Sat Mar 10 01:37:34 2007 -0500

    driver core: Use attribute groups in struct device_type
    
    Driver core: use attribute groups in struct device_type
    
    Attribute groups are more flexible than attribute lists
    (an attribute list can be represented by anonymous group)
    so switch struct device_type to use them.
    
    Also rework attribute creation for devices so that they all
    cleaned up properly in case of errors.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Cc: Kay Sievers <kay.sievers@novell.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit b8c5cec23d5c33b767a1cddebd4f8813a9563e3c
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Fri Feb 16 17:33:36 2007 +0100

    Driver core: udev triggered device-<>driver binding
    
    We get two per-bus sysfs files:
      ls-l /sys/subsystem/usb
      drwxr-xr-x 2 root root    0 2007-02-16 16:42 devices
      drwxr-xr-x 7 root root    0 2007-02-16 14:55 drivers
      -rw-r--r-- 1 root root 4096 2007-02-16 16:42 drivers_autoprobe
      --w------- 1 root root 4096 2007-02-16 16:42 drivers_probe
    
    The flag "drivers_autoprobe" controls the behavior of the bus to bind
    devices by default, or just initialize the device and leave it alone.
    
    The command "drivers_probe" accepts a bus_id and the bus tries to bind a
    driver to this device.
    
    Systems who want to control the driver binding with udev, switch off the
    bus initiated probing:
      echo 0 > /sys/subsystem/usb/drivers_autoprobe
      echo 0 > /sys/subsystem/pcmcia/drivers_autoprobe
      ...
    
    and initiate the probing with udev rules like:
      ACTION=="add", SUBSYSTEM=="usb", ATTR{subsystem/drivers_probe}="$kernel"
      ACTION=="add", SUBSYSTEM=="pcmcia", ATTR{subsystem/drivers_probe}="$kernel"
      ...
    
    Custom driver binding can happen in earlier rules by something like:
      ACTION=="add", SUBSYSTEM=="usb", \
      ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678" \
      ATTR{subsystem/drivers/<custom-driver>/bind}="$kernel"
    
    This is intended to solve the modprobe.conf mess with "install-rules", custom
    bind/unbind-scripts and all the weird things people invented over the years.
    It should also provide the functionality "libusual" was supposed to do.
    
    With udev, one can just write a udev rule to drive all USB-disks at the
    third port of USB-hub by the "ub" driver, and everything else by
    usb-storage. One can also instruct udev to bind different wireless
    drivers to identical cards - just selected by the pcmcia slot-number, and
    whatever ...
    
    To use the mentioned rules, it needs udev version 106, to be able to
    write ATTR{}="$kernel" to sysfs files.
    
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit a456b7023e0abf80bb03b0bdf5471b48878e5c49
Author: Jean Delvare <khali@linux-fr.org>
Date:   Fri Mar 9 16:33:10 2007 +0100

    dev_printk and new-style class devices
    
    As the new-style class devices (as opposed to old-style struct
    class_device) are becoming more widely used, I noticed that the
    dev_printk-based functions are not working properly with these.
    New-style class devices have no driver nor bus, almost by definition,
    and as a result dev_driver_string(), which is used as the first
    parameter of dev_printk, resolves to an empty string. This causes
    entries like the following to show in my logs:
    
     i2c-2: adapter [SMBus stub driver] registered
    
    Notice the unaesthetical leading whitespace. In order to fix this
    problem, I suggest that we extend dev_driver_string to deal with
    new-style class devices:
    
    Signed-off-by: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 864062457a2e444227bd368ca5f2a2b740de604f
Author: Kay Sievers <kay.sievers@vrfy.org>
Date:   Wed Mar 14 03:25:56 2007 +0100

    driver core: fix namespace issue with devices assigned to classes
    
      - uses a kset in "struct class" to keep track of all directories
        belonging to this class
      - merges with the /sys/devices/virtual logic.
      - removes the namespace-dir if the last member of that class
        leaves the directory.
    
    There may be locking or refcounting fixes left, I stopped when it seemed
    to work with network and sound modules. :)
    
    From: Kay Sievers <kay.sievers@vrfy.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 00ed8e3dda47f8421b11da17e353d7db8c878121
Author: Dmitriy Monakhov <dmonakhov@sw.ru>
Date:   Sun Mar 11 15:36:19 2007 +0300

    driver core: fix device_add error path
    
     - At the moment we jump here device was't added to
       dev->class->devices list yet.
    
    Signed-off-by: Monakhov Dmitriy <dmonakhov@openvz.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 39bc89fd4019b164002adaacef92c4140e37955a
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed Apr 25 20:50:03 2007 -0700

    make SysRq-T show all tasks again
    
    show_state() (SysRq-T) developed the buggy habbit of not showing
    TASK_RUNNING tasks.  This was due to the mistaken belief that state_filter
    == -1 would be a pass-through filter - while in reality it did not let
    TASK_RUNNING == 0 p->state values through.
    
    Fix this by restoring the original '!state_filter means all tasks'
    special-case i had in the original version.  Test-built and test-booted on
    i686, SysRq-T now works as intended.
    
    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 20f09390b2da2432309afe8aaa0bd64ec64c4584
Author: Daniel Walker <dwalker@mvista.com>
Date:   Thu Apr 26 09:46:05 2007 -0700

    seqlocks: trivial remove weird whitespace
    
    Signed-off-by: Daniel Walker <dwalker@mvista.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 07db59bd6b0f279c31044cba6787344f63be87ea
Author: Linus Torvalds <torvalds@woody.linux-foundation.org>
Date:   Fri Apr 27 09:10:47 2007 -0700

    Change default dirty-writeback limits
    
    Do this really early in the 2.6.22-rc series, so that we'll get
    feedback.  And don't change by half measures.  Just cut the default
    dirty limit to a quarter of what it was, and see if anybody even
    notices.
    
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

commit 14cf232ab161ce87ca538af3daad5f717c20d487
Author: Franck Bui-Huu <fbuihuu@gmail.com>
Date:   Thu Apr 26 00:20:15 2007 -0700

    [MIPS] Don't force frame pointers for lockdep on MIPS
    
    Stacktrace support on MIPS doesn't use frame pointers.  Since this option
    considerably increases the size of the kernel code, force lockdep to not
    use it.
    
    Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit c4be17370b76bc6c23a239ca512fe360785d2369
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Thu Apr 26 19:53:59 2007 +0900

    [MIPS] update vr41xx Kconfig
    
    This patch has updated vr41xx/Kconfig.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 678f4e34a66eb364f4f8e7dc82746c3df14dc1e8
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Thu Apr 26 19:51:31 2007 +0900

    [MIPS] remove 2 select entries for VR41xx
    
    This patch has removed 2 select entries for VR41xx.
    These entries are selected in arch/mips/vr41xx/Kconfig.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 74142d65b23b46587ea329202e957c901d9a57a1
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Thu Apr 26 19:45:09 2007 +0900

    [MIPS] rename VR41XX to VR4100 series
    
    This patch has renamed VR41XX to VR4100 series.
    That's better.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 820c229f6c82bb91c0dbfbce90f7e6eb9639c7ab
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 19 15:05:16 2007 +0530

    [MIPS] Use DEFINE_SPINLOCK instead of SPIN_LOCK_UNLOCKED.
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit a4c9bb7d22aa61ec585984f46df185669e557e3d
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Tue Apr 10 06:23:27 2007 -0400

    [MIPS] Replace old fashioned "__typeof" with "__typeof__".
    
    [Robert's original log message said this was a bug but it isn't, it's
    just very old fashioned syntax that is not (no longer?) documented in the
    gcc documentation.  So for the sake of uniformity I'm applying his
    patch but with a modified log message. -- Ralf]
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 05bc284a719b778243f51e23c88fe6cefe6b219b
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Thu Apr 26 15:46:28 2007 +0100

    [MIPS] Remove unused _THREAD_SIZE_ORDER from asm-offset.c.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit bea771751c116a690054581902b4144fe5a4520e
Author: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Date:   Sun Apr 8 13:34:57 2007 +0200

    [MIPS] Change PCI host bridge setup/resources
    
    PCI host bridge setup for SNI RM machines with PCI is quite broken, now
    that Linux does it's resource setup own its own. It will use IO addresses,
    which are needed by the EISA config detection and assigns PCI memory
    addresses, which overlap with ISA legacy addresses (video ram). Below
    is a patch, which changes the way how the PCI memory addresses are
    used and sets the minimum IO address to give enough IO space for
    8 EISA slots). This patch needs the other PCI resource change, I've
    posted.
    
    Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 639702bd725b3cc1a9bd442a7822c83849d66e91
Author: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Date:   Sun Apr 8 13:28:44 2007 +0200

    [MIPS] Register PCI host bridge resource earlier
    
    PCI based SNI RM machines have their EISA bus behind an Intel PCI/EISA
    bridge. So the PCI IO range must start at 0x0000. Changing that will
    break the PCI bus, because i8259.c already has registered it's IO
    addresses before the PCI bus gets initialized. Below is a patch,
    which will register the PCI host bridge resources inside
    register_pci_controller(). It also changes i8259.c to use insert_region(),
    because request_resource() will fail, if the IO space of the PIT hanging
    of the PCI host bridge (maybe passing the resource parent to
    init_i8259_irqs() is a cleaner fix for that).
    
    Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 3c5e370600c2dda8a4f59f841f323df04e6ce7b2
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Wed Apr 4 16:40:52 2007 +0900

    [MIPS] Remove pnx8550-v2pci_defconfig
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit d619f38fdacb5cec0c841798bbadeaf903868852
Author: Mark Mason <mmason@upwardaccess.com>
Date:   Thu Mar 29 11:39:56 2007 -0700

    [MIPS] Add bcm1480 ZBus trace support, fix wait related bugs
    
    Make ZBus tracing generic - moving it to a common direcotry under
    arch/mips/sibyte, add bcm1480 support and fix some wait related
    bugs (thanks to Ralf for assistance on that).
    
    Signed-off-by: Mark Mason <mason@broadcom.com>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 8deab1144b553548fb2f1b51affdd36dcd652aaa
Author: Mark Mason <mmason@upwardaccess.com>
Date:   Wed Mar 28 14:40:25 2007 -0700

    [MIPS] Updated Sibyte headers
    
    This is an update to the earlier patch for the sibyte headers, and superceeds
    the previous patch.  Changes were necessary to get the tbprof driver working
    on the bcm1480.
    
    Patch to update Sibyte header files to match master versions maintained
    at Broadcom.  This patch also corrects some whitespace problems, and
    (hopefully) shouldn't introduce any new ones.
    
    Signed-off-by: Mark Mason <mason@broadcom.com>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit eacb9d61919db56482dcea7ec943c9508175dc16
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Thu Apr 26 15:46:25 2007 +0100

    [MIPS] Remove unused argument from kunmap_coherent().
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit e3cf10e93f42171224e88b06c226d450f3b3a55f
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Thu Apr 26 15:46:25 2007 +0100

    [MIPS] Malta: Delete unused prototype of mips_timer_interrupt.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 05502339332564ffd545be9ca37b208296a2eaad
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Wed Mar 21 00:36:02 2007 +0900

    [MIPS] Select ZONE_DMA only if GENERIC_ISA_DMA selected
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit f197465384bf7ef1af184c2ed1a4e268911a91e3
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Thu Apr 26 15:46:24 2007 +0100

    [MIPS] MIPS Tech: Get rid of volatile in core code.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 78709b9df35346965b214e0e548412748d147776
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Thu Apr 26 15:46:24 2007 +0100

    [MIPS] IP22: Get rid of volatile in IP22 core code.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 2127435e57a15f1fea8d6969e264eeb05b28ba4b
Author: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date:   Thu Mar 15 00:58:28 2007 +0900

    [MIPS] JMR3927 cleanup
    
    * Kill dead codes
    * Rearrange irq chip handlers
    * Minimize defconfig
    
    Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 252161eccd1a44f32a506d0fedb424d4ff84e4dc
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Wed Mar 14 21:51:26 2007 +0900

    [MIPS] merge GT64111 PCI routines and GT64120 PCI_0 routines
    
    This patch has merged GT64111 PCI routines and GT64120 PCI_0 routines.
    GT64111 PCI is almost the same as GT64120's PCI_0.
    This patch don't change GT64120 PCI routines.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 2a9effc67804102d6d5182eb0116520588ae2256
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Mon Mar 5 19:10:03 2007 +0900

    [MIPS] Cobalt: Split PCI codes from setup.c
    
    It's removed #ifdef CONFIG_PCI/#endif from cobalt setup.c .
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit cc50b67dcd84c6215232c0e1c95e24786e555782
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Tue Mar 6 21:34:44 2007 +0900

    [MIPS] Cobalt: clean up include files
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

commit 7f5a7716dc0b380fd3c85ca5a5841969555feaa7
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Wed Apr 25 15:08:57 2007 +0100

    [MIPS] Fix AP/SP to work in the reality of modern kernels.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

commit 78ab67da1002d954ea4c3e2b441e2483c41f94e8
Author: Knobloch, Thomas <knobloch@siemens.com>
Date:   Fri Apr 27 13:19:36 2007 +0200

    [MTD] [NAND] Wrong calculation of page number in nand_block_bad()
    
    In case that there is no memory based bad block table available the
    function nand_block_checkbad() in drivers/mtd/nand/nand_base.c will call
    nand_block_bad() directly. When parameter 'getchip' is set to zero,
    nand_block_bad() will not right shift the offset to calculate the
    correct page number.
    
    Signed-off-by: Thomas Knobloch <knobloch@siemens.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit cb629a01bb5bca951287e761c590a5686c6ca416
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Fri Apr 27 16:02:01 2007 +0200

    [S390] SPIN_LOCK_UNLOCKED cleanup in drivers/s390
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead.
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 39ce010d38bf6703b49f59eb73bef030b1d659f2
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:02:00 2007 +0200

    [S390] Clean up smp code in preparation for some larger changes.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 9ff6f4577e69801a43c0d58606a80040aecbc4bc
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:59 2007 +0200

    [S390] Remove debugging junk.
    
    arch/s390/appldata/appldata_base.c has some confusing debugging code left
    over to allow compiling it as a module. In practice, it cannot be configured
    as module and there is no need to keep that code.
    
    Signed-off-by: Gerald Schaefer <geraldsc@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit ecdcc0234b27472b561378ac59e2beeea06ec6ff
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:58 2007 +0200

    [S390] Switch etr from tasklet to workqueue.
    
    The clock synchronization of the ETR code requires an smp_call_function
    to synchronize all cpus. Calling smp_call_function from a tasklet is
    illegal. Replace the tasklet with a job on the global workqueue.
    ETR work is rare and can be postponed to a be done by a kernel thread.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 6c210482ae4a9a5bb9377ad250feaacec3faa3cd
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:57 2007 +0200

    [S390] split page_test_and_clear_dirty.
    
    The page_test_and_clear_dirty primitive really consists of two
    operations, page_test_dirty and the page_clear_dirty. The combination
    of the two is not an atomic operation, so it makes more sense to have
    two separate operations instead of one.
    In addition to the improved readability of the s390 version of
    SetPageUptodate, it now avoids the page_test_dirty operation which is
    an insert-storage-key-extended (iske) instruction which is an expensive
    operation.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 2fc2d1e9ffcde78af7ab63ed640d9a4901797de2
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:01:56 2007 +0200

    [S390] Processor degradation notification.
    
    Generate uevents for all cpus if cpu capability changes. This can
    happen e.g. because the cpus are overheating. The cpu capability can
    be read via /sys/devices/system/cpu/cpuN/capability.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit db77aa5f3d01fe6a6cc629dbd37936b1fdd129ba
Author: Jan Glauber <jan.glauber@de.ibm.com>
Date:   Fri Apr 27 16:01:55 2007 +0200

    [S390] vtime: cleanup per_cpu usage.
    
    Replace per_cpu(... , smp_processor_id()) with __get_cpu_var()
    
    Signed-off-by: Jan Glauber <jan.glauber@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 131a395c18af43d824841642038e5cc0d48f0bd2
Author: Jan Glauber <jan.glauber@de.ibm.com>
Date:   Fri Apr 27 16:01:54 2007 +0200

    [S390] crypto: cleanup.
    
    Cleanup code and remove obsolete documentation.
    
    Signed-off-by: Jan Glauber <jan.glauber@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 6d4740c89c187ee8f5ac7355c4eeffda26493d1f
Author: Stefan Haberland <stefan.haberland@de.ibm.com>
Date:   Fri Apr 27 16:01:53 2007 +0200

    [S390] sclp: fix coding style.
    
    Use only capital letters for defines.
    
    Cc: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 66b494a7178cbd84d8fc0e5f1e92d81fb6ec9f6e
Author: Ursula Braun <braunu@de.ibm.com>
Date:   Fri Apr 27 16:01:52 2007 +0200

    [S390] vmlogrdr: stop IUCV connection in vmlogrdr_release.
    
    Reopen of /dev/account failed. The IUCV path has to be terminated
    in vmlogrdr_release.
    
    Signed-off-by: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit b3d00c3b9278876b84a808bc513048b145fdef90
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:51 2007 +0200

    [S390] sclp: initialize early.
    
    Add explicit sclp initialization for those sclp users that do not
    register with the interface.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit b7127dfeed3252a76aa31f016aac5fba53d99711
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Fri Apr 27 16:01:50 2007 +0200

    [S390] ctc: kmalloc->kzalloc/casting cleanups.
    
    A patch for the CTC / ESCON network driver.  Switch from kmalloc to kzalloc
    when appropriate, remove some unnecessary kmalloc casts too.  Since I have no
    s390 machine, I didn't compile it but I examined it carefully.
    
    Signed-off-by: "Ahmed S. Darwish" <darwish.07@gmail.com>
    Cc: Frank Pavlic <fpavlic@de.ibm.com>
    Cc: Ursula Braun <braunu@de.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 411ed3225733dbd83b4cbaaa992ef80d6ec1534e
Author: Michael Holzheu <holzheu@de.ibm.com>
Date:   Fri Apr 27 16:01:49 2007 +0200

    [S390] zfcpdump support.
    
    s390 machines provide hardware support for creating Linux dumps on SCSI
    disks. For creating a dump a special purpose dump Linux is used. The first
    32 MB of memory are saved by the hardware before the dump Linux is
    booted. Via an SCLP interface, the saved memory can be accessed from
    Linux. This patch exports memory and registers of the crashed Linux to
    userspace via a debugfs file. For more information refer to
    Documentation/s390/zfcpdump.txt, which is included in this patch.
    
    Signed-off-by: Michael Holzheu <holzheu@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 7039d3a11c4b4b59f9ef933b4b0a28304bdd07d1
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:48 2007 +0200

    [S390] dasd: Add ipldev parameter.
    
    Specifying 'ipldev' in the dasd= kernel parameter will automatically
    activate the boot device for use by the dasd driver.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 4dfd5c4593e69e9d399dd9e01d184dc534408f7e
Author: Horst Hummel <horst.hummel@de.ibm.com>
Date:   Fri Apr 27 16:01:47 2007 +0200

    [S390] dasd: Add sysfs attribute status and generate uevents.
    
    This patch adds a sysfs-attribute 'status' to make the DASD device-status
    accessible from user-space. In addition, the DASD driver generates an
    uevent(CHANGE) for the ccw-device on each device-status change.
    This enables user-space applications (e.g. udev) to do related processing.
    
    Signed-off-by: Horst Hummel <horst.hummel@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit be7962856d299a0f231ac36f89f4a89cbecfe0ff
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:46 2007 +0200

    [S390] Improved kernel stack overflow checking.
    
    Recent cvs versions of gcc have support for an improved stack overflow
    checking that calculates the size of the guard size for each function.
    If the compiler accepts -mstack-size without -mstack-guard then the
    new stack check is available. We always want to use the new stack
    checker.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 60691d3c2c0fe9ecc264741ff41f283fef579b8a
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:01:45 2007 +0200

    [S390] Get rid of console setup functions.
    
    We get this:
    
    Section mismatch: reference to .init.text:con3270_consetup from .data
    		  between 'con3270' (at offset 0x45c8) and 'con3270_fn'
    Section mismatch: reference to .init.text:con3215_consetup from .data
    		  between 'con3215' (at offset 0x4678) and
    		  'raw3215_ccw_driver'
    
    Since there is no difference between a non present console setup
    function and one that returns only 0 remove them.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit be5ec363e958982454ac9b3138b0e78c032e758d
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:44 2007 +0200

    [S390] No execute support cleanup.
    
    Simplify the signal_return function that checks for the two special
    system calls sigreturn and rt_sigreturn. No need to do a page table
    walk, a call to copy_from_user while disabled page faults will work
    as well.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 10c1031f706bbe0690d84cdbccad15b11c6dc661
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:43 2007 +0200

    [S390] Minor fault path optimization.
    
    The minor fault path has grown a lot in terms of cycles. In particular
    the kprobes hook is very costly. Optimize the path to save a couple of
    cycles. If kprobes is enabled more than 300 cycles can be avoided if
    kprobes_running() is false.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit c0007f1a65762eaf55633d403b380130ec60adad
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:01:42 2007 +0200

    [S390] Use generic bug.
    
    Generic bug implementation for s390. Will increase the value of the
    console output on BUG() statements since registers r0-r5,r14 will
    not be clobbered by a printk() call that was previously done before
    the illegal instruction of BUG() was hit.
    Also implements an architecture specific WARN_ON(). Output of that
    could be increased but requires common code change.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit bb11e3bdbac08f773a89f3ca287024a956ee8a12
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:41 2007 +0200

    [S390] Improved oops output.
    
    This patch adds two improvements to the oops output. First it adds an
    additional line after the PSW which decodes the different fields of it.
    Second a disassembler is added that decodes the instructions surrounding
    the faulting PSW. The output of a test oops now looks like this:
    
    kernel BUG at init/main.c:419
    illegal operation: 0001 [#1]
    CPU:    0    Not tainted
    Process swapper (pid: 0, task: 0000000000464968, ksp: 00000000004be000)
    Krnl PSW : 0700000180000000 00000000000120b6 (rest_init+0x36/0x38)
               R:0 T:1 IO:1 EX:1 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 EA:3
    Krnl GPRS: 0000000000000003 00000000004ba017 0000000000000022 0000000000000001
               000000000003a5f6 0000000000000000 00000000004be6a8 0000000000000000
               0000000000000000 00000000004b8200 0000000000003a50 0000000000008000
               0000000000516368 000000000033d008 00000000000120b2 00000000004bdee0
    Krnl Code: 00000000000120a6: e3e0f0980024       stg     %r14,152(%r15)
               00000000000120ac: c0e500014296       brasl   %r14,3a5d8
               00000000000120b2: a7f40001           brc     15,120b4
              >00000000000120b6: 0707               bcr     0,%r7
               00000000000120b8: eb7ff0500024       stmg    %r7,%r15,80(%r15)
               00000000000120be: c0d000195825       larl    %r13,33d108
               00000000000120c4: a7f13f00           tmll    %r15,16128
               00000000000120c8: a7840001           brc     8,120ca
    Call Trace:
    ([<00000000000120b2>] rest_init+0x32/0x38)
     [<00000000004be614>] start_kernel+0x37c/0x410
     [<0000000000012020>] _ehead+0x20/0x80
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 03ff9a235a0602724fc54916469b6e0939c62c9b
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date:   Fri Apr 27 16:01:40 2007 +0200

    [S390] System call cleanup.
    
    Remove system call glue for sys_clone, sys_fork, sys_vfork, sys_execve,
    sys_sigreturn, sys_rt_sigreturn and sys_sigaltstack. Call do_execve from
    kernel_execve directly, move pt_regs to the right place and branch to
    sysc_return to start the user space program. This removes the last
    in-kernel system call.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit ef99516c9646802c3d38c3eb83de302e05b3c1b5
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:39 2007 +0200

    [S390] cio: Unregister ccw devices directly.
    
    We used to unregister ccw devices not directly from the I/O
    subchannel remove function in order to avoid lifelocks on the
    css bus semaphore. This semaphore is gone, and there is no reason
    to not unregister the ccw device directly (it is even better since
    it is more in keeping with the goal of immediate disconnect).
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 8c4941c53b14e5a08ed2f270e9f087b410a9abcc
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:38 2007 +0200

    [S390] cio: cm_enable memory leak.
    
    We allocage two pages when channel path measurements are enabled
    via cm_enable. We must not forget to free them again when
    channel path measurements are disabled again.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit d76123eb357a4baa653714183df286c1bb99f707
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:37 2007 +0200

    [S390] cio: ccwgroup register vs. unregister.
    
    Introduce a mutex for struct ccwgroup to prevent simuntaneous
    register/unregister on the same ccwgroup device.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 82b7ac058f60e0c92f9237fbaf440671f437ecdf
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:36 2007 +0200

    [S390] cio: Dont call css_update_ssd_info from interrupt context.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 7ad6a24970325294a22a08446d473384c15b928e
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:35 2007 +0200

    [S390] cio: fix subchannel channel-path data usage
    
    Ensure that channel-path related subchannel data is only retrieved and
    used when it is valid and that it is updated when it may have changed.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 83b3370c79b91b9be3f6540c3c914e689134b45f
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:34 2007 +0200

    [S390] cio: replace subchannel evaluation queue with bitmap
    
    Use a bitmap for indicating which subchannels require evaluation
    instead of allocating memory for each evaluation request. This
    approach reduces memory consumption during recovery in case of
    massive evaluation request occurrence and removes the need for
    memory allocation failure handling.
    
    Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit 387b734fc2b55f776b192c7afdfd892ba42347d4
Author: Stefan Bader <shbader@de.ibm.com>
Date:   Fri Apr 27 16:01:33 2007 +0200

    [S390] cio: Re-start path verification after aborting internal I/O.
    
    Path verification triggered by changes to the available CHPIDs will be
    interrupted by another change but not re-started. This results in an
    invalid path mask.
    To solve this make sure to completely re-start path verification when
    changing the available paths.
    
    Signed-off-by: Stefan Bader <shbader@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit cfbe9bb2fb5de1da58d351432a9465c22d6d3ee5
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:32 2007 +0200

    [S390] cio: Use add_uevent_var.
    
    Convert ccw_uevent to use add_uevent_var and adapt snprint_alias.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit e5854a5839fa426a7873f038080f63587de5f1f1
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:31 2007 +0200

    [S390] cio: Channel-path configure function.
    
    Add a new attribute to the channel-path sysfs directory through which
    channel-path configure operations can be triggered. Also listen for
    hardware events requesting channel-path configure operations and
    process them accordingly.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit f5ba6c863617c15d22cce5f8666ff4c832773025
Author: Cornelia Huck <cornelia.huck@de.ibm.com>
Date:   Fri Apr 27 16:01:30 2007 +0200

    [S390] cio: Clean up online_store.
    
    Detangle the online_store code and make it more readable.
    
    Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit c9182e0f42c5646e670c2166b6d6638052d574af
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:29 2007 +0200

    [S390] cio: observe chpid valid flag
    
    Check validity flag of CHPID description data before continuing with
    channel-path initialization.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

commit e6b6e10ac1de116fc6d2288f185393014851cccf
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:28 2007 +0200

    [S390] cio: Introduce separate files for channel-path related code.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit d120b2a4e60cc9e62e7cc5dcf049100af3745cc4
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:27 2007 +0200

    [S390] cio: Allow 0 and 1 as input for channel path status attribute.
    
    Channel path status can now be modified by writing '0' and '1'
    to the sysfs status attribute in addition to 'offline' and
    'online' respectively.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit f86635fad14c4a6810cf0e08488fc9129a3b3b32
Author: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Date:   Fri Apr 27 16:01:26 2007 +0200

    [S390] cio: Introduce struct chp_id.
    
    Introduce data type for channel-path IDs.
    
    Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 6fc321fd7dd91f0592f37503219196835314fbb7
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:01:25 2007 +0200

    [S390] cio/ipl: Clean interface between cio and ipl code.
    
    Clean interface between cio and ipl code, so Peter stops complaining.
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 29c380f5f06d0c5a320b9bb6f8987065e7b81c91
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Fri Apr 27 16:01:04 2007 +0200

    [S390] memory detection: stop at first memory hole.
    
    If both sclp and diag memory detection don't work stop at the first
    memory hole. Otherwise the code might loop forever...
    
    Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>

commit 8224ca195874525533665bbcd23b6da1e575aa4d
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Fri Apr 27 14:21:47 2007 +0200

    [AVR32] Fix compile error with gcc 4.1
    
    gcc 4.1 doesn't seem to like const variables as inline assembly
    outputs. Drop support for reading 64-bit values using get_user() so
    that we can use an unsigned long to hold the result regardless of the
    actual size. This should be safe since many architectures, including
    i386, doesn't support reading 64-bit values with get_user().
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit d468a030026017008286919aa6127b1190efb2c2
Author: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date:   Fri Apr 27 15:11:44 2007 +0300

    UBI: remove unused variable
    
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

commit a4022b0d6005b117a985cec64559e048981a4244
Author: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Date:   Tue Apr 10 18:23:09 2007 -0400

    avr32: remove unneeded cast in atomic.h
    
    This int cast is superfluous since system.h cmpxchg already casts it in
    (typeof(*(ptr))).
    
    Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 0277b378c3779e3c8a413afb7d4ee00fa24a5a26
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Apr 26 08:53:38 2007 -0400

    AVR32: Remove useless config option "GENERIC_BUST_SPINLOCK".
    
    Remove the clearly useless config option GENERIC_BUST_SPINLOCK, which
    is not used anywhere in the tree.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit c0c3e81608fc300027f2131e351e67ab118cf24c
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 14 13:59:13 2007 +0100

    [AVR32] Optimize the TLB miss handler
    
    Reorder some instructions and change the register usage to reduce
    the number of pipeline stalls. Also use the bfextu and bfins
    instructions for bitfield manipulations instead of shifting and
    masking.
    
    This makes gzipping a 80MB file approximately 2% faster.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 9ca20a8366462c553c27216161c735937f9de108
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Thu Apr 12 17:26:57 2007 +0200

    [AVR32] Board code for ATNGW100
    
    Add board code and defconfig for the ATNGW100 Network Gateway kit.
    For more information about this board, see
    
    http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4102
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 2c1a2a3441a754a9b5a8e7184071154f8a9bd61b
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 7 10:40:44 2007 +0100

    [AVR32] Use memcpy/memset in memcpy_{from,to}_io and memset_io
    
    Using readb/writeb to implement these breaks NOR flash support. I
    can't see any reason why regular memcpy and memset shouldn't work.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit d80e2bb12606906fd0b5b5592f519852de8b0113
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 21 16:23:41 2007 +0100

    [AVR32] Get rid of board_setup_fbmem()
    
    Since the core setup code takes care of both allocation and
    reservation of framebuffer memory, there's no need for this board-
    specific hook anymore. Replace it with two global variables,
    fbmem_start and fbmem_size, which can be used directly.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit f9692b9501c339ec90647d8cd6ee5c106f072f9f
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 21 16:16:50 2007 +0100

    [AVR32] Reserve framebuffer memory in early_parse_fbmem()
    
    With the current strategy of using the bootmem allocator to allocate
    or reserve framebuffer memory, there's a slight chance that the
    requested area has been taken by the boot allocator bitmap before we
    get around to reserving it.
    
    By inserting the framebuffer region as a reserved region as early as
    possible, we improve our chances for success and we make the region
    visible as a reserved region in dmesg and /proc/iomem without any
    extra work.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit d8011768e6bdd0d9de5cc7bdbd3077b4b4fab8c7
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 21 16:02:57 2007 +0100

    [AVR32] Simplify early handling of memory regions
    
    Use struct resource to specify both physical memory regions and
    reserved regions and push everything into the same framework,
    including kernel code/data and initrd memory. This allows us to get
    rid of many special cases in the bootmem initialization and will also
    make it easier to implement more robust handling of framebuffer
    memory later.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 5539f59ac40473730806580f212c4eac6e769f01
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 21 15:39:18 2007 +0100

    [AVR32] Move setup_bootmem() from mm/init.c to kernel/setup.c
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit e3e7d8d4ea37b8372ee417452d03171c5dc55125
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Mon Feb 12 16:28:56 2007 +0100

    [AVR32] Make I/O access macros work with external devices
    
    Fix the I/O access macros so that they work with externally connected
    devices accessed in little-endian mode over any bus width:
    
    * Use a set of macros to define I/O port- and memory operations
      borrowed from MIPS.
    * Allow subarchitecture to specify address- and data-mangling
    * Implement at32ap-specific port mangling (with build-time
      configurable bus width. Only one bus width at a time supported
      for now.)
    * Rewrite iowriteN and friends to use write[bwl] and friends
      (not the __raw counterparts.)
    
    This has been tested using pata_pcmcia to access a CompactFlash card
    connected to the EBI (16-bit bus width.)
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 92b728c147adb8c690b520304f4c9ee3eee43c21
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Tue Mar 13 10:06:37 2007 +0100

    [AVR32] Fix NMI handler
    
    Fix a problem with the NMI handler entry code related to the NMI handler
    sharing some code with the exception handlers. This is not a good idea
    because the RSR and RAR registers are not the same, and the NMI handler
    runs with interrupts masked the whole time so there's no need to check
    for pending work.
    
    Open-code the low-level NMI handling logic instead so that the pt_regs
    layout is actually correct when the higher-level handler is called.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 623b0355d5b1f9c6d05005b649a2f3a7b9fd7816
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Tue Mar 13 17:59:11 2007 +0100

    [AVR32] Clean up exception handling code
    
      * Use generic BUG() handling
      * Remove some useless debug statements
      * Use a common function _exception() to send signals or oops when
        an exception can't be handled. This makes sure init doesn't
        enter an infinite exception loop as well. Borrowed from powerpc.
      * Add some basic exception tracing support to the page fault code.
      * Rework dump_stack(), show_regs() and friends and move everything
        into process.c
      * Print information about configuration options and chip type when
        oopsing
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 3b328c98093702c584692bffabd440800b383d73
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Tue Mar 13 15:30:38 2007 +0100

    [AVR32] Clean up cpu identification and add features bitmap
    
    Clean up the cpu identification code, using definitions from
    <asm/sysreg.h> instead of hardcoded constants. Also, add a features
    bitmap to struct avr32_cpuinfo to allow other code to make decisions
    based upon what the running cpu is actually capable of.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 535c806c26ef602d578792083df52b31803b961e
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Tue Mar 13 14:17:14 2007 +0100

    [AVR32] Clean up asm/sysreg.h
    
    Fix indentation and remove spurious comments in asm-avr32/sysreg.h
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 188ff65d49dadf7b0e9b6718abc3fe98a5098711
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 14 13:23:44 2007 +0100

    [AVR32] Don't enable clocks with no users
    
    Bring the code that sets the initial PM clock masks in line with the
    comment preceding it by only enabling clocks that have users != 0.
    Fix SM clock definition and avr32_hpt_init() so that the SM and TC0
    clocks keep ticking.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 19b7ce8bad718a2850ea19aeb7383f1728596c24
Author: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Date:   Mon Feb 26 13:50:43 2007 +0100

    [AVR32] Put cpu in sleep 0 when idle.
    
    This patch puts the CPU in sleep 0 when doing nothing, idle. This will
    turn of the CPU clock and thus save power. The CPU is waken again when
    an interrupt occurs.
    
    Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 7760989e5e2900e484e9115e6e690c6ce0b0221c
Author: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Date:   Mon Mar 12 18:15:16 2007 +0100

    [AVR32] Change system timer from count-compare to Timer/Counter 0
    
    Due to limitation of the count-compare system timer (not able to
    count when CPU is in sleep), the system timer had to be changed to
    use a peripheral timer/counter.
    
    The old COUNT-COMPARE code is still present in time.c as weak
    functions. The new timer is added to the architecture directory.
    
    This patch sets up TC0 as system timer The new timer has been tested
    on AT32AP7000/ATSTK1000 at 100 Hz, 250 Hz, 300 Hz and 1000 Hz.
    
    For more details about the timer/counter see the datasheet for
    AT32AP700x available at
    
    http://www.atmel.com/dyn/products/product_card.asp?part_id=3903
    
    Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 228e845fd243bf42033998afab792357444e9e4a
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Wed Mar 7 15:24:34 2007 +0100

    [AVR32] Add mach-specific Kconfig
    
    Include at32ap-specific Kconfig file from top-level Kconfig file. The
    at32ap Kconfig is currently empty, but it will grow some machine-
    specific options soon.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 068d9f6eb9369a00eb45be91c07653cfef65f4a0
Author: Hans-Christian Egtvedt <hcegtvedt@atmel.com>
Date:   Wed Jan 31 18:01:45 2007 +0100

    [AVR32] Add nwait and tdf parameters to SMC configuration
    
    Complete the SMC configuration code by adding nwait and tdf
    parameter. After this change, we support the same parameters as the
    hardware.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 485764016d5accb813e8bdd076802a7e3318bb64
Author: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date:   Tue Feb 13 17:11:10 2007 +0200

    UBI: add me to MAINTAINERS
    
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

commit 0029da3bf430eea498eee8cef5933f9214534b8a
Author: Artem Bityutskiy <dedekind@infradead.org>
Date:   Wed Oct 4 19:15:21 2006 +0300

    JFFS2: add UBI support
    
    This patch make JFFS2 able to work with UBI volumes via the emulated MTD
    devices which are directly mapped to these volumes.
    
    Signed-off-by: Artem Bityutskiy <dedekind@infradead.org>

commit 801c135ce73d5df1caf3eca35b66a10824ae0707
Author: Artem B. Bityutskiy <dedekind@linutronix.de>
Date:   Tue Jun 27 12:22:22 2006 +0400

    UBI: Unsorted Block Images
    
    UBI (Latin: "where?") manages multiple logical volumes on a single
    flash device, specifically supporting NAND flash devices. UBI provides
    a flexible partitioning concept which still allows for wear-levelling
    across the whole flash device.
    
    In a sense, UBI may be compared to the Logical Volume Manager
    (LVM). Whereas LVM maps logical sector numbers to physical HDD sector
    numbers, UBI maps logical eraseblocks to physical eraseblocks.
    
    More information may be found at
    http://www.linux-mtd.infradead.org/doc/ubi.html
    
    Partitioning/Re-partitioning
    
      An UBI volume occupies a certain number of erase blocks. This is
      limited by a configured maximum volume size, which could also be
      viewed as the partition size. Each individual UBI volume's size can
      be changed independently of the other UBI volumes, provided that the
      sum of all volume sizes doesn't exceed a certain limit.
    
      UBI supports dynamic volumes and static volumes. Static volumes are
      read-only and their contents are protected by CRC check sums.
    
    Bad eraseblocks handling
    
      UBI transparently handles bad eraseblocks. When a physical
      eraseblock becomes bad, it is substituted by a good physical
      eraseblock, and the user does not even notice this.
    
    Scrubbing
    
      On a NAND flash bit flips can occur on any write operation,
      sometimes also on read. If bit flips persist on the device, at first
      they can still be corrected by ECC, but once they accumulate,
      correction will become impossible. Thus it is best to actively scrub
      the affected eraseblock, by first copying it to a free eraseblock
      and then erasing the original. The UBI layer performs this type of
      scrubbing under the covers, transparently to the UBI volume users.
    
    Erase Counts
    
      UBI maintains an erase count header per eraseblock. This frees
      higher-level layers (like file systems) from doing this and allows
      for centralized erase count management instead. The erase counts are
      used by the wear-levelling algorithm in the UBI layer. The algorithm
      itself is exchangeable.
    
    Booting from NAND
    
      For booting directly from NAND flash the hardware must at least be
      capable of fetching and executing a small portion of the NAND
      flash. Some NAND flash controllers have this kind of support. They
      usually limit the window to a few kilobytes in erase block 0. This
      "initial program loader" (IPL) must then contain sufficient logic to
      load and execute the next boot phase.
    
      Due to bad eraseblocks, which may be randomly scattered over the
      flash device, it is problematic to store the "secondary program
      loader" (SPL) statically. Also, due to bit-flips it may become
      corrupted over time. UBI allows to solve this problem gracefully by
      storing the SPL in a small static UBI volume.
    
    UBI volumes vs. static partitions
    
      UBI volumes are still very similar to static MTD partitions:
    
        * both consist of eraseblocks (logical eraseblocks in case of UBI
          volumes, and physical eraseblocks in case of static partitions;
        * both support three basic operations - read, write, erase.
    
      But UBI volumes have the following advantages over traditional
      static MTD partitions:
    
        * there are no eraseblock wear-leveling constraints in case of UBI
          volumes, so the user should not care about this;
        * there are no bit-flips and bad eraseblocks in case of UBI volumes.
    
      So, UBI volumes may be considered as flash devices with relaxed
      restrictions.
    
    Where can it be found?
    
      Documentation, kernel code and applications can be found in the MTD
      gits.
    
    What are the applications for?
    
      The applications help to create binary flash images for two purposes: pfi
      files (partial flash images) for in-system update of UBI volumes, and plain
      binary images, with or without OOB data in case of NAND, for a manufacturing
      step. Furthermore some tools are/and will be created that allow flash content
      analysis after a system has crashed..
    
    Who did UBI?
    
      The original ideas, where UBI is based on, were developed by Andreas
      Arnez, Frank Haverkamp and Thomas Gleixner. Josh W. Boyer and some others
      were involved too. The implementation of the kernel layer was done by Artem
      B. Bityutskiy. The user-space applications and tools were written by Oliver
      Lohmann with contributions from Frank Haverkamp, Andreas Arnez, and Artem.
      Joern Engel contributed a patch which modifies JFFS2 so that it can be run on
      a UBI volume. Thomas Gleixner did modifications to the NAND layer. Alexander
      Schmidt made some testing work as well as core functionality improvements.
    
    Signed-off-by: Artem B. Bityutskiy <dedekind@linutronix.de>
    Signed-off-by: Frank Haverkamp <haver@vnet.ibm.com>

commit 8d8a0241eb019ce9648a77b55f9f76a834207cbb
Author: Olaf Hering <olaf@aepfle.de>
Date:   Thu Apr 26 06:36:56 2007 +1000

    [POWERPC] Generic check_legacy_ioport
    
    check_legacy_ioport makes only sense on PREP, CHRP and pSeries.
    They may have an isa node with PS/2, parport, floppy and serial ports.
    
    Remove the check_legacy_ioport call from ppc_md, it's not needed
    anymore.  Hardware capabilities come from the device-tree.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8d2169e8d6b8a91413df33bc402e0f602ceaabcc
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Fri Apr 27 11:53:52 2007 +1000

    [POWERPC] Prepare for splitting up mmu.h by MMU type
    
    Currently asm-powerpc/mmu.h has definitions for the 64-bit hash based
    MMU.  If CONFIG_PPC64 is not set, it instead includes asm-ppc/mmu.h
    which contains a particularly horrible mess of #ifdefs giving the
    definitions for all the various 32-bit MMUs.
    
    It would be nice to have the low level definitions for each MMU type
    neatly in their own separate files.  It would also be good to wean
    arch/powerpc off dependence on the old asm-ppc/mmu.h.
    
    This patch makes a start on such a cleanup by moving the definitions
    for the 64-bit hash MMU to their own file, asm-powerpc/mmu_hash64.h.
    Definitions for the other MMUs still all come from asm-ppc/mmu.h,
    however each MMU type can now be one-by-one moved over to their own
    file, in the process cleaning them up stripping them of cruft no
    longer necessary in arch/powerpc.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 173ba87b9584e4cba41ce9a06916eba80baa1bf4
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Apr 27 03:19:31 2007 +1000

    [POWERPC] bootwrapper: cuboot-83xx: Exclude upper 1MB from heap.
    
    The uppermost part of memory is where u-boot puts the stack, so don't
    include that in the heap.  It's not currently causing problems, as the
    current code allocates from the bottom of the heap, but this will keep
    things from potentially breaking if a future implementation were to
    allocate from the top.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 4536b937466ff6784d2a9a4bebde924a0d6e01cb
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Apr 27 03:09:01 2007 +1000

    [POWERPC] bootwrapper: cuImage for 85xx
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e4bb688d9f11d7fee927312cc97d443472c7c212
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Apr 27 03:08:13 2007 +1000

    [POWERPC] bootwrapper: Fix array handling in dt_xlate_reg().
    
    This fixes a few bugs in how dt_xlate_reg() handles address arrays:
    
    1. copy_val() was copying into the wrong end of the array, resulting
    in random stack garbage at the other end.
    2. dt_xlate_reg() was getting the result from the wrong end of the array.
    3. add_reg() and sub_reg() were treating the arrays as
    little-endian rather than big-endian.
    4. add_reg() only returned an error on a carry out of the entire
    array, rather than out of the naddr portion.
    5. The requested reg resource was checked to see if it exceeded
    the size of the reg property, but not to see if it exceeded the
    size of the buffer.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3c5f6162549b9045a2925dff64c140c7f49ea344
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Apr 11 18:32:36 2007 +1000

    [POWERPC] boot: More verbose gunzip error message
    
    Change the error message in gunzip_exactly to be more verbose.
    
    Besides the identifier being unrelated to the current function name,
    the user had no indication if the corruption was near the beginning
    or the end.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 928370c676729df118f15939ef69b540a7b946b1
Author: Akinobu Mita <mita@fixstars.com>
Date:   Tue Apr 10 21:05:31 2007 +1000

    [POWERPC] Enable make install
    
    make help on powerpc says make install is available.
    But it failed due to no rule to make install.
    
    This patch enables make install to work.
    
    Signed-off-by: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 57647a4dada06bb4d4056e57b4dcb79c4c8bb191
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Thu Mar 22 17:23:44 2007 +1100

    [POWERPC] Always use -mno-string
    
    The string load/store instructions are unimplemented on some processors
    and slow (microcoded) on some others.  It's simplest to just not use
    them at all.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f13659e0b3907548402ce1f47bf866544b804260
Author: Anton Blanchard <anton@samba.org>
Date:   Wed Mar 21 01:48:34 2007 +1100

    [POWERPC] Fix WARN_ON when entering xmon
    
    Whenever we enter xmon we get a WARN_ON out of the rtas code since it
    thinks interrupts are still on:
    
    Unable to handle kernel paging request for data at address 0x00000000
    Faulting instruction address: 0xd000000000080008
    cpu 0x3: Vector: 300 (Data Access) at [c0000000075dba00]
        pc: d000000000080008: .doit+0x8/0x40 [oopser]
        lr: c000000000077704: .sys_init_module+0x1664/0x1824
        sp: c0000000075dbc80
       msr: 9000000000009032
       dar: 0
     dsisr: 42000000
      current = 0xc000000003fa64b0
      paca    = 0xc000000000694280
        pid   = 2260, comm = insmod
    
    ------------[ cut here ]------------
    Badness at arch/powerpc/kernel/entry_64.S:651
    Call Trace:
    [C0000000075DAE70] [C00000000000EB64] .show_stack+0x68/0x1b0 (unreliable)
    [C0000000075DAF10] [C000000000216254] .report_bug+0x94/0xe8
    [C0000000075DAFA0] [C00000000047B140] __kprobes_text_start+0x178/0x584
    [C0000000075DB040] [C0000000000044F4] program_check_common+0xf4/0x100
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e7273d2a0841612794dff43328d461beee95c986
Author: Will Schmidt <will_schmidt@vnet.ibm.com>
Date:   Tue Mar 13 06:21:16 2007 +1100

    [POWERPC] Replace if-then-else with a switch statement
    
    Convert a compound if-else blob to a switch statement.
    This better fits the kernel coding style.
    
    Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5dd60166c22dbbb7a8684c119d28cb88b6087784
Author: Domen Puncer <domen.puncer@telargo.com>
Date:   Fri Mar 2 21:44:45 2007 +1100

    [POWERPC] Fix typos in booting-without-of.txt
    
    Fix typos + some cosmetic changes.
    
    Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9c8f8e752431f3f7ed6ea6ea6e491ce12057f572
Author: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date:   Thu Feb 1 16:34:10 2007 +0100

    [AVR32] Add basic HMATRIX support
    
    This adds register and clock definitions for the High-speed bus Matrix
    (HMATRIX) as well as a function that can be used to configure special
    EBI functionality like CompactFlash and NAND flash support.
    
    Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>

commit 912a41a4ab935ce8c4308428ec13fc7f8b1f18f4
Author: Sergey Vlasov <vsu@altlinux.ru>
Date:   Fri Apr 27 02:17:19 2007 -0700

    [IPV4] nl_fib_lookup: Initialise res.r before fib_res_put(&res)
    
    When CONFIG_IP_MULTIPLE_TABLES is enabled, the code in nl_fib_lookup()
    needs to initialize the res.r field before fib_res_put(&res) - unlike
    fib_lookup(), a direct call to ->tb_lookup does not set this field.
    
    Signed-off-by: Sergey Vlasov <vsu@altlinux.ru>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ebbd90a730711280142017e482f27ec3fbb4f227
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 27 02:13:39 2007 -0700

    [IPV6]: Fix thinko in ipv6_rthdr_rcv() changes.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 49e9f70f8e7a4df00a5185e7f5c91e3c583847db
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Fri Apr 27 01:04:23 2007 -0700

    [IPV4]: Add multipath cached to feature-removal-schedule.txt
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cd9ad58d4061494e7fdd70ded7bcf2418daf356a
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 21:19:23 2007 -0700

    [SCSI] SUNESP: Complete driver rewrite to version 2.0
    
    Major features:
    
    1) Tagged queuing support.
    2) Will properly negotiate for synchronous transfers even on
       devices that reject the wide negotiation message, such as
       CDROMs
    3) Significantly lower kernel stack usage in interrupt
       handler path by elimination of function vector arrays,
       replaced by a top-level switch statement state machine.
    4) Uses generic scsi infrastructure as much as possible to
       avoid code duplication.
    5) Automatic request of sense data in response to CHECK_CONDITION
    6) Portable to other platforms using ESP such as DEC and Sun3
       systems.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2e0c3370b3ecf831ef209f1094df36a808865845
Author: Olof Johansson <olof@lixom.net>
Date:   Fri Apr 27 15:46:01 2007 +1000

    [POWERPC] pasemi: Cpufreq driver
    
    Cpufreq driver for PA Semi PWRficient processors.
    
    Signed-off-by: Egor Martovetsky <egor@pasemi.com>
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 116ab40df8decf8c519368e31825e9584c86adf2
Author: Olof Johansson <olof@lixom.net>
Date:   Wed Apr 25 09:17:33 2007 +1000

    [POWERPC] pasemi: Kconfig for gpio_mdio
    
    arch/powerpc/platforms/pasemi/gpio_mdio.c really depends on CONFIG_PHYLIB.
    Add a config option for it, allow for it to be disabled if needed and fix
    the dependency.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 952418cd3894cf370cf2c9acdfd498c84c3b7cf9
Author: Olof Johansson <olof@lixom.net>
Date:   Wed Apr 25 04:01:34 2007 +1000

    [POWERPC] pasemi: Remove build warning
    
    arch/powerpc/platforms/pasemi/setup.c: In function 'pasemi_publish_devices':
    arch/powerpc/platforms/pasemi/setup.c:220: warning: implicit declaration of function 'of_platform_bus_probe'
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5bcec54f026b13617ec8aa8fa229970f9acf8dd5
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Fri Apr 27 14:32:37 2007 +1000

    [POWERPC] Partially revert a7edd0e676d51145ae634a2acf7a447e319200fa
    
    Due to conflicts with the network drivers tree.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 01b2726dd11ef198ac6cf8f88974b4427d40ffdb
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Fri Apr 27 13:41:15 2007 +1000

    [POWERPC] Rename get_property to of_get_property: partial drivers
    
    This does drivers/machintosh and the hvc code.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 16ce82d846f2e6b652a064f91c5019cfe8682be4
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 21:08:21 2007 -0700

    [SPARC64]: Convert PCI over to generic struct iommu/strbuf.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f16bfc1c0958ff340a02779ab139b03fb5ba6e82
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:51:12 2007 -0700

    [WIRELESS] cfg80211: Clarify locking comment.
    
    This patch clarifies the comment about locking in wiphy_unregister.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a4d73ee168eeaed3baea86542ad42e1fd7e192d3
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:50:35 2007 -0700

    [WIRELESS] cfg80211: Fix locking in wiphy_new.
    
    This patch fixes the locking in wiphy new. Ingo Oeser
    <netdev@axxeo.de> noticed that locking in the error case was wrong and
    also suggested this fix.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b86e0280bb5585a610783ff5392d9d439dee7ddd
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:48:23 2007 -0700

    [WEXT] net_device: Don't include wext bits if not required.
    
    This patch makes the wext bits in struct net_device depend on
    CONFIG_WIRELESS_EXT.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4d44e0dfe961e02489d40d32334454ebe0e784e8
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:47:25 2007 -0700

    [WEXT]: Misc code cleanups.
    
    Just a few things that didn't fit in with the other patches.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bdf51894c1d7ce3fba8c8fdf485e85173ac60c6c
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:46:55 2007 -0700

    [WEXT]: Reduce inline abuse.
    
    This patch removes a bunch of inline abuse from wext. Most functions
    that were marked inline are only used once so the compiler will inline
    them anyway, others are used multiple times but there's no requirement
    for them to be inline since they aren't in any fast paths.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7a9df167db0f200d5f8e393376dba8ceeae0fd53
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:46:23 2007 -0700

    [WEXT]: Move EXPORT_SYMBOL statements where they belong.
    
    EXPORT_SYMBOL statements are supposed to go together with the symbol
    they're exporting. This patch moves them accordingly.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit dd8ceabcd10d47f6f28ecfaf2eac7beffca11b3c
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:45:47 2007 -0700

    [WEXT]: Cleanup early ioctl call path.
    
    This patch makes the code in wireless_process_ioctl somewhat more
    readable.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4b1e255384570138c2a823904796d46f628e8350
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:45:14 2007 -0700

    [WEXT]: Remove options.
    
    This patch kills the two options in wext that are required to be
    enabled anyway because they influence the userspace API.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 235c107ba08becb3ae6c3d3449c8b1053a5a9d75
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:44:35 2007 -0700

    [WEXT]: Remove dead debug code.
    
    This patch kills a whole bunch of code that can only ever be used by
    defining some things in wext.c. Also, the things that are printed are
    mostly useless since the API is fairly well-tested.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 295f4a1fa3ecdf816b18393ef7bcd37c032df2fa
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:43:56 2007 -0700

    [WEXT]: Clean up how wext is called.
    
    This patch cleans up the call paths from the core code into wext.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 11433ee450eb4a320f46ce5ed51410b52803ffcc
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Thu Apr 26 20:42:51 2007 -0700

    [WEXT]: Move to net/wireless
    
    This patch moves dev/core/wireless.c to net/wireless/wext.c.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 39bf09493042200b967cdf2ee6e3f670b7963903
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 20:39:14 2007 -0700

    [AFS]: Eliminate cmpxchg() usage in vlocation code.
    
    cmpxchg() is not available on every processor so can't
    be used in generic code.
    
    Replace with spinlock protection on the ->state changes,
    wakeups, and wait loops.
    
    Add what appears to be a missing wakeup on transition
    to AFS_VL_VALID state in afs_vlocation_updater().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 68c708fd5e90f6d178c84bb7e641589eb2842319
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 20:20:21 2007 -0700

    [RXRPC]: Fix pointers passed to bitops.
    
      CC [M]  net/rxrpc/ar-input.o
    net/rxrpc/ar-input.c: In function â€˜rxrpc_fast_process_dataâ€™:
    net/rxrpc/ar-input.c:171: warning: passing argument 2 of â€˜__test_and_set_bitâ€™ from incompatible pointer type
    net/rxrpc/ar-input.c:180: warning: passing argument 2 of â€˜__clear_bitâ€™ from incompatible pointer type
    net/rxrpc/ar-input.c:218: warning: passing argument 2 of â€˜__clear_bitâ€™ from incompatible pointer type
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 411faf5810cdd0e4f5071a3805d8adb49d120a07
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 20:18:17 2007 -0700

    [RXRPC]: Remove bogus atomic_* overrides.
    
    These are done with CPP defines which several platforms
    use for their atomic.h implementation, which floods the
    build with warnings and breaks the build.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ba3e0e1accd8d5bb12eaeb0977429d8dc04f6d1e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 26 16:06:22 2007 -0700

    [AFS]: Fix u64 printing in debug logging.
    
    Need 'unsigned long long' casts to quiet warnings on
    64-bit platforms when using %ll on a u64.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 260a980317dac80182dd76140cf67c6e81d6d3dd
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:59:35 2007 -0700

    [AFS]: Add "directory write" support.
    
    Add support for the create, link, symlink, unlink, mkdir, rmdir and
    rename VFS operations to the in-kernel AFS filesystem.
    
    Also:
    
     (1) Fix dentry and inode revalidation.  d_revalidate should only look at
         state of the dentry.  Revalidation of the contents of an inode pointed to
         by a dentry is now separate.
    
     (2) Fix afs_lookup() to hash negative dentries as well as positive ones.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c35eccb1f614954b10cba3f74b7c301993b2f42e
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:58:49 2007 -0700

    [AFS]: Implement the CB.InitCallBackState3 operation.
    
    Implement the CB.InitCallBackState3 operation for the fileserver to
    call.  This reduces the amount of network traffic because if this op
    is aborted, the fileserver will then attempt an CB.InitCallBackState
    operation.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b908fe6b2d1294d93b0d0badf6bf4f9a2cd7d729
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:58:17 2007 -0700

    [AFS]: Add support for the CB.GetCapabilities operation.
    
    Add support for the CB.GetCapabilities operation with which the fileserver can
    ask the client for the following information:
    
     (1) The list of network interfaces it has available as IPv4 address + netmask
         plus the MTUs.
    
     (2) The client's UUID.
    
     (3) The extended capabilities of the client, for which the only current one
         is unified error mapping (abort code interpretation).
    
    To support this, the patch adds the following routines to AFS:
    
     (1) A function to iterate through all the network interfaces using RTNETLINK
         to extract IPv4 addresses and MTUs.
    
     (2) A function to iterate through all the network interfaces using RTNETLINK
         to pull out the MAC address of the lowest index interface to use in UUID
         construction.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0795e7c031c4bda46fbdde678adf29de19bef7f4
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:57:43 2007 -0700

    [AFS]: Update the AFS fs documentation.
    
    Update the AFS fs documentation.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 00d3b7a4533e367b0dc2812a706db8f9f071c27f
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:57:07 2007 -0700

    [AFS]: Add security support.
    
    Add security support to the AFS filesystem.  Kerberos IV tickets are added as
    RxRPC keys are added to the session keyring with the klog program.  open() and
    other VFS operations then find this ticket with request_key() and either use
    it immediately (eg: mkdir, unlink) or attach it to a file descriptor (open).
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 436058a49e0fb91c74454dbee9cfee6fb53b4336
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:56:24 2007 -0700

    [AFS]: Handle multiple mounts of an AFS superblock correctly.
    
    Handle multiple mounts of an AFS superblock correctly, checking to see
    whether the superblock is already initialised after calling sget()
    rather than just unconditionally stamping all over it.
    
    Also delete the "silent" parameter to afs_fill_super() as it's not
    used and can, in any case, be obtained from sb->s_flags.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 63b6be55e8b51cb718468794d343058e96c7462c
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:55:48 2007 -0700

    [AF_RXRPC]: Delete the old RxRPC code.
    
    Delete the old RxRPC code as it's now no longer used.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 08e0e7c82eeadec6f4871a386b86bf0f0fbcb4eb
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:55:03 2007 -0700

    [AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC.
    
    Make the in-kernel AFS filesystem use AF_RXRPC instead of the old RxRPC code.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 651350d10f93bed7003c9a66e24cf25e0f8eed3d
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:50:17 2007 -0700

    [AF_RXRPC]: Add an interface to the AF_RXRPC module for the AFS filesystem to use
    
    Add an interface to the AF_RXRPC module so that the AFS filesystem module can
    more easily make use of the services available.  AFS still opens a socket but
    then uses the action functions in lieu of sendmsg() and registers an intercept
    functions to grab messages before they're queued on the socket Rx queue.
    
    This permits AFS (or whatever) to:
    
     (1) Avoid the overhead of using the recvmsg() call.
    
     (2) Use different keys directly on individual client calls on one socket
         rather than having to open a whole slew of sockets, one for each key it
         might want to use.
    
     (3) Avoid calling request_key() at the point of issue of a call or opening of
         a socket.  This is done instead by AFS at the point of open(), unlink() or
         other VFS operation and the key handed through.
    
     (4) Request the use of something other than GFP_KERNEL to allocate memory.
    
    Furthermore:
    
     (*) The socket buffer markings used by RxRPC are made available for AFS so
         that it can interpret the cooked RxRPC messages itself.
    
     (*) rxgen (un)marshalling abort codes are made available.
    
    
    The following documentation for the kernel interface is added to
    Documentation/networking/rxrpc.txt:
    
    =========================
    AF_RXRPC KERNEL INTERFACE
    =========================
    
    The AF_RXRPC module also provides an interface for use by in-kernel utilities
    such as the AFS filesystem.  This permits such a utility to:
    
     (1) Use different keys directly on individual client calls on one socket
         rather than having to open a whole slew of sockets, one for each key it
         might want to use.
    
     (2) Avoid having RxRPC call request_key() at the point of issue of a call or
         opening of a socket.  Instead the utility is responsible for requesting a
         key at the appropriate point.  AFS, for instance, would do this during VFS
         operations such as open() or unlink().  The key is then handed through
         when the call is initiated.
    
     (3) Request the use of something other than GFP_KERNEL to allocate memory.
    
     (4) Avoid the overhead of using the recvmsg() call.  RxRPC messages can be
         intercepted before they get put into the socket Rx queue and the socket
         buffers manipulated directly.
    
    To use the RxRPC facility, a kernel utility must still open an AF_RXRPC socket,
    bind an addess as appropriate and listen if it's to be a server socket, but
    then it passes this to the kernel interface functions.
    
    The kernel interface functions are as follows:
    
     (*) Begin a new client call.
    
    	struct rxrpc_call *
    	rxrpc_kernel_begin_call(struct socket *sock,
    				struct sockaddr_rxrpc *srx,
    				struct key *key,
    				unsigned long user_call_ID,
    				gfp_t gfp);
    
         This allocates the infrastructure to make a new RxRPC call and assigns
         call and connection numbers.  The call will be made on the UDP port that
         the socket is bound to.  The call will go to the destination address of a
         connected client socket unless an alternative is supplied (srx is
         non-NULL).
    
         If a key is supplied then this will be used to secure the call instead of
         the key bound to the socket with the RXRPC_SECURITY_KEY sockopt.  Calls
         secured in this way will still share connections if at all possible.
    
         The user_call_ID is equivalent to that supplied to sendmsg() in the
         control data buffer.  It is entirely feasible to use this to point to a
         kernel data structure.
    
         If this function is successful, an opaque reference to the RxRPC call is
         returned.  The caller now holds a reference on this and it must be
         properly ended.
    
     (*) End a client call.
    
    	void rxrpc_kernel_end_call(struct rxrpc_call *call);
    
         This is used to end a previously begun call.  The user_call_ID is expunged
         from AF_RXRPC's knowledge and will not be seen again in association with
         the specified call.
    
     (*) Send data through a call.
    
    	int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,
    				   size_t len);
    
         This is used to supply either the request part of a client call or the
         reply part of a server call.  msg.msg_iovlen and msg.msg_iov specify the
         data buffers to be used.  msg_iov may not be NULL and must point
         exclusively to in-kernel virtual addresses.  msg.msg_flags may be given
         MSG_MORE if there will be subsequent data sends for this call.
    
         The msg must not specify a destination address, control data or any flags
         other than MSG_MORE.  len is the total amount of data to transmit.
    
     (*) Abort a call.
    
    	void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code);
    
         This is used to abort a call if it's still in an abortable state.  The
         abort code specified will be placed in the ABORT message sent.
    
     (*) Intercept received RxRPC messages.
    
    	typedef void (*rxrpc_interceptor_t)(struct sock *sk,
    					    unsigned long user_call_ID,
    					    struct sk_buff *skb);
    
    	void
    	rxrpc_kernel_intercept_rx_messages(struct socket *sock,
    					   rxrpc_interceptor_t interceptor);
    
         This installs an interceptor function on the specified AF_RXRPC socket.
         All messages that would otherwise wind up in the socket's Rx queue are
         then diverted to this function.  Note that care must be taken to process
         the messages in the right order to maintain DATA message sequentiality.
    
         The interceptor function itself is provided with the address of the socket
         and handling the incoming message, the ID assigned by the kernel utility
         to the call and the socket buffer containing the message.
    
         The skb->mark field indicates the type of message:
    
    	MARK				MEANING
    	===============================	=======================================
    	RXRPC_SKB_MARK_DATA		Data message
    	RXRPC_SKB_MARK_FINAL_ACK	Final ACK received for an incoming call
    	RXRPC_SKB_MARK_BUSY		Client call rejected as server busy
    	RXRPC_SKB_MARK_REMOTE_ABORT	Call aborted by peer
    	RXRPC_SKB_MARK_NET_ERROR	Network error detected
    	RXRPC_SKB_MARK_LOCAL_ERROR	Local error encountered
    	RXRPC_SKB_MARK_NEW_CALL		New incoming call awaiting acceptance
    
         The remote abort message can be probed with rxrpc_kernel_get_abort_code().
         The two error messages can be probed with rxrpc_kernel_get_error_number().
         A new call can be accepted with rxrpc_kernel_accept_call().
    
         Data messages can have their contents extracted with the usual bunch of
         socket buffer manipulation functions.  A data message can be determined to
         be the last one in a sequence with rxrpc_kernel_is_data_last().  When a
         data message has been used up, rxrpc_kernel_data_delivered() should be
         called on it..
    
         Non-data messages should be handled to rxrpc_kernel_free_skb() to dispose
         of.  It is possible to get extra refs on all types of message for later
         freeing, but this may pin the state of a call until the message is finally
         freed.
    
     (*) Accept an incoming call.
    
    	struct rxrpc_call *
    	rxrpc_kernel_accept_call(struct socket *sock,
    				 unsigned long user_call_ID);
    
         This is used to accept an incoming call and to assign it a call ID.  This
         function is similar to rxrpc_kernel_begin_call() and calls accepted must
         be ended in the same way.
    
         If this function is successful, an opaque reference to the RxRPC call is
         returned.  The caller now holds a reference on this and it must be
         properly ended.
    
     (*) Reject an incoming call.
    
    	int rxrpc_kernel_reject_call(struct socket *sock);
    
         This is used to reject the first incoming call on the socket's queue with
         a BUSY message.  -ENODATA is returned if there were no incoming calls.
         Other errors may be returned if the call had been aborted (-ECONNABORTED)
         or had timed out (-ETIME).
    
     (*) Record the delivery of a data message and free it.
    
    	void rxrpc_kernel_data_delivered(struct sk_buff *skb);
    
         This is used to record a data message as having been delivered and to
         update the ACK state for the call.  The socket buffer will be freed.
    
     (*) Free a message.
    
    	void rxrpc_kernel_free_skb(struct sk_buff *skb);
    
         This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC
         socket.
    
     (*) Determine if a data message is the last one on a call.
    
    	bool rxrpc_kernel_is_data_last(struct sk_buff *skb);
    
         This is used to determine if a socket buffer holds the last data message
         to be received for a call (true will be returned if it does, false
         if not).
    
         The data message will be part of the reply on a client call and the
         request on an incoming call.  In the latter case there will be more
         messages, but in the former case there will not.
    
     (*) Get the abort code from an abort message.
    
    	u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb);
    
         This is used to extract the abort code from a remote abort message.
    
     (*) Get the error number from a local or network error message.
    
    	int rxrpc_kernel_get_error_number(struct sk_buff *skb);
    
         This is used to extract the error number from a message indicating either
         a local error occurred or a network error occurred.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ec26815ad847dbf74a1e27aa5515fb7d5dc6ee6f
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:49:28 2007 -0700

    [AFS]: Clean up the AFS sources
    
    Clean up the AFS sources.
    
    Also remove references to AFS keys.  RxRPC keys are used instead.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 17926a79320afa9b95df6b977b40cca6d8713cea
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:48:28 2007 -0700

    [AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both
    
    Provide AF_RXRPC sockets that can be used to talk to AFS servers, or serve
    answers to AFS clients.  KerberosIV security is fully supported.  The patches
    and some example test programs can be found in:
    
    	http://people.redhat.com/~dhowells/rxrpc/
    
    This will eventually replace the old implementation of kernel-only RxRPC
    currently resident in net/rxrpc/.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e19dff1fdd99a25819af74cf0710e147fff4fd3a
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:46:56 2007 -0700

    [AF_RXRPC]: Make it possible to merely try to cancel timers from a module
    
    Export try_to_del_timer_sync() for use by the AF_RXRPC module.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7318226ea2931a627f3572e5f4804c91ca19ecbc
Author: David Howells <dhowells@redhat.com>
Date:   Thu Apr 26 15:46:23 2007 -0700

    [AF_RXRPC]: Key facility changes for AF_RXRPC
    
    Export the keyring key type definition and document its availability.
    
    Add alternative types into the key's type_data union to make it more useful.
    Not all users necessarily want to use it as a list_head (AF_RXRPC doesn't, for
    example), so make it clear that it can be used in other ways.
    
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 071b638689464c6b39407025eedd810d5b5e6f5d
Author: Oleg Nesterov <oleg@tv-sign.ru>
Date:   Thu Apr 26 15:45:32 2007 -0700

    [WORKQUEUE]: cancel_delayed_work: use del_timer() instead of del_timer_sync()
    
    del_timer_sync() buys nothing for cancel_delayed_work(), but it is less
    efficient since it locks the timer unconditionally, and may wait for the
    completion of the delayed_work_timer_fn().
    
    cancel_delayed_work() == 0 means:
    
    	before this patch:
    		work->func may still be running or queued
    
    	after this patch:
    		work->func may still be running or queued, or
    		delayed_work_timer_fn->__queue_work() in progress.
    
    		The latter doesn't differ from the caller's POV,
    		delayed_work_timer_fn() is called with _PENDING
    		bit set.
    
    cancel_delayed_work() == 1 with this patch adds a new possibility:
    
    	delayed_work->work was cancelled, but delayed_work_timer_fn
    	is still running (this is only possible for the re-arming
    	works on single-threaded workqueue).
    
    	In this case the timer was re-started by work->func(), nobody
    	else can do this. This in turn means that delayed_work_timer_fn
    	has already passed __queue_work() (and wont't touch delayed_work)
    	because nobody else can queue delayed_work->work.
    
    Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
    Signed-Off-By: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 83418978827324918a8cd25ce5227312de1d4468
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Mon Apr 23 18:53:12 2007 -0700

    ocfs2: Cache extent records
    
    The extent map code was ripped out earlier because of an inability to deal
    with holes. This patch adds back a simpler caching scheme requiring far less
    code.
    
    Our old extent map caching was designed back when meta data block caching in
    Ocfs2 didn't work very well, resulting in many disk reads. These days our
    metadata caching is much better, resulting in no un-necessary disk reads. As
    a result, extent caching doesn't have to be as fancy, nor does it have to
    cache as many extents. Keeping the last 3 extents seen should be sufficient
    to give us a small performance boost on some streaming workloads.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 7cdfc3a1c3971c9125c317cb8c2525745851798e
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Mon Apr 16 17:28:51 2007 -0700

    ocfs2: Remember rw lock level during direct io
    
    Cluster locking might have been redone because a direct write won't
    complete, so this needs to be reflected in the iocb.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 8110b073a9135acf0a71bccfc20c0d1023f179c6
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Thu Mar 22 16:53:23 2007 -0700

    ocfs2: Fix up i_blocks calculation to know about holes
    
    Older file systems which didn't support holes did a dumb calculation of
    i_blocks based on i_size. This is no longer accurate, so fix things up to
    take actual allocation into account.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 4f902c37727bbedbc0508a1477874c58ddcc9af8
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Mar 9 16:26:50 2007 -0800

    ocfs2: Fix extent lookup to return true size of holes
    
    Initially, we had wired things to return a size '1' of holes. Cook up a
    small amount of code to find the next extent and calculate the number of
    clusters between the virtual offset and the next allocated extent.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 49cb8d2d496ce06869ccca2ab368ed6b0b5b979d
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Mar 9 16:21:46 2007 -0800

    ocfs2: Read from an unwritten extent returns zeros
    
    Return an optional extent flags field from our lookup functions and wire up
    callers to treat unwritten regions as holes for the purpose of returning
    zeros to the user.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit e48edee2d8eab812f31f0ff62c6ba635ca2e1e21
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Mar 7 16:46:57 2007 -0800

    ocfs2: make room for unwritten extents flag
    
    Due to the size of our group bitmaps, we'll never have a leaf node extent
    record with more than 16 bits worth of clusters. Split e_clusters up so that
    leaf nodes can get a flags field where we can mark unwritten extents.
    Interior nodes whose length references all the child nodes beneath it can't
    split their e_clusters field, so we use a union to preserve sizing there.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 6af67d8205cf65fbaaa743edc7ebb46e486e34ff
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Tue Mar 6 17:24:46 2007 -0800

    ocfs2: Use own splice write actor
    
    We need to fill holes during a splice write. Provide our own splice write
    actor which can call ocfs2_file_buffered_write() with a splice-specific
    callback.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit fa41045fcbf78269991d5aebb1820fc51534f05d
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Thu Mar 1 11:22:19 2007 -0800

    ocfs2: Use do_sync_mapping_range() in ocfs2_zero_tail_for_truncate()
    
    Do this instead of filemap_fdatawrite() - this way we sync only the
    range between i_size and the cluster boundary.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 5b04aa3a64f854244bc40a6f528176ed50b5c4f6
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Thu Mar 1 11:01:55 2007 -0800

    [PATCH] Turn do_sync_file_range() into do_sync_mapping_range()
    
    do_sync_file_range() accepts a file * from which it takes an address_space to
    sync.  Abstract out the bulk of the function into do_sync_mapping_range()
    which takes the address_space directly.  This way callers who want to sync an
    address_space directly can take advantage of the functionality provided.
    
    do_sync_file_range() is preserved as a small wrapper around
    do_sync_mapping_range().
    
    Ocfs2 in particular would like to use this to initiate a sync of a specific
    inode range during truncate, where a file * may not be available.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
    Cc: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 60b11392f1a09433740bda3048202213daa27736
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Feb 16 11:46:50 2007 -0800

    ocfs2: zero tail of sparse files on truncate
    
    Since we don't zero on extend anymore, truncate needs to be fixed up to zero
    the part of a file between i_size and and end of it's cluster. Otherwise a
    subsequent extend could expose bad data.
    
    This introduced a new helper, which can be used in ocfs2_write().
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 25baf2da1473d9dcde1a4c7b0ab26e7d67d9bf62
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Feb 14 15:30:30 2007 -0800

    ocfs2: Teach ocfs2_get_block() about holes
    
    ocfs2_get_block() didn't understand sparse files, fix that. Also remove some
    code that isn't really useful anymore. We can fix up
    ocfs2_direct_IO_get_blocks() at the same time.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 5069120b7227fd323152a3755a0aa6bdeb361310
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Feb 9 20:52:53 2007 -0800

    ocfs2: remove ocfs2_prepare_write() and ocfs2_commit_write()
    
    These are no longer used, and can't handle file systems with sparse file
    allocation.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 9517bac6cc7a7aa4fee63cb38a32cb6014e264c7
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Fri Feb 9 20:24:12 2007 -0800

    ocfs2: teach ocfs2_file_aio_write() about sparse files
    
    Unfortunately, ocfs2 can no longer make use of generic_file_aio_write_nlock()
    because allocating writes will require zeroing of pages adjacent to the I/O
    for cluster sizes greater than page size.
    
    Implement a custom file write here, which can order page locks for zeroing.
    This also has the advantage that cluster locks can easily be ordered outside
    of the page locks.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 89488984ac23b0580f959b9ee549f2fcb1c2f194
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Jan 17 13:10:55 2007 -0800

    ocfs2: Turn off shared writeable mmap for local files systems with holes.
    
    This will be turned back on once we can do allocation in ->page_mkwrite().
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit abf8b1569415bb4a8915a4884943ecd39c510957
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Jan 17 13:07:24 2007 -0800

    ocfs2: abstract out allocation locking
    
    Right now, file allocation for ocfs2 is done within ocfs2_extend_file(),
    which is either called from ->setattr() (for an i_size change), or at the
    top of ocfs2_file_aio_write().
    
    Inodes on file systems with sparse file support will want to do their
    allocation during the actual write call.
    
    In either case the cluster locking decisions are the same. We abstract out
    that code into a new function, ocfs2_lock_allocators() which will be used by
    a later patch to enable writing to sparse files.
    
    This also provides a nice cleanup of ocfs2_extend_allocation().
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 3a0782d09c07aa3ec767ba6089cd15cfbfbfc508
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Jan 17 12:53:31 2007 -0800

    ocfs2: teach extend/truncate about sparse files
    
    For ocfs2_truncate_file(), we eliminate the "simple" truncate case which no
    longer exists since i_size is not tied to i_clusters. In
    ocfs2_extend_file(), we skip the allocation / page zeroing code for file
    systems which understand sparse files.
    
    The core truncate code is changed to do a bottom up tree traversal. This
    gets abstracted out into it's own function. To make things more readable,
    most of the special case handling for in-inode extents from
    ocfs2_do_truncate() is also removed.
    
    Though write support for sparse files comes in a later patch, we at least
    update ocfs2_prepare_inode_for_write() to skip allocation for sparse files.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 363041a5f74b953ab6b705ac9c88e5eda218a24b
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Jan 17 12:31:35 2007 -0800

    ocfs2: temporarily remove extent map caching
    
    The code in extent_map.c is not prepared to deal with a subtree being
    rotated between lookups. This can happen when filling holes in sparse files.
    Instead of a lengthy patch to update the code (which would likely lose the
    benefit of caching subtree roots), we remove most of the algorithms and
    implement a simple path based lookup. A less ambitious extent caching scheme
    will be added in a later patch.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit dcd0538ff4e854fa9d7f4630b359ca8fdb5cb5a8
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Tue Jan 16 11:32:23 2007 -0800

    ocfs2: sparse b-tree support
    
    Introduce tree rotations into the b-tree code. This will allow ocfs2 to
    support sparse files. Much of the added code is designed to be generic (in
    the ocfs2 sense) so that it can later be re-used to implement large
    extended attributes.
    
    This patch only adds the rotation code and does minimal updates to callers
    of the extent api.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 6f16bf655c5795586dd2ac96a7c70e0b9a378746
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Tue Mar 20 17:17:54 2007 -0700

    ocfs2: small cleanup of ocfs2_request_delete()
    
    There are two checks in there (one for inode newness, one for other mounted
    nodes) which are unnecessary, so remove them. The DLM will allow the trylock
    in either case without any messaging overhead.
    
    Removing these makes ocfs2_request_delete() a one liner function, so just
    move the trylock out one level into ocfs2_query_inode_wipe().
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 68e2b740c4b5394680cfefccddbdb486c5866a4c
Author: Tiger Yang <tiger.yang@oracle.com>
Date:   Tue Mar 20 16:42:10 2007 -0700

    ocfs2: remove unused code
    
    Remove node messaging code that becomes unused with the delete inode vote
    removal.
    
    [Removed even more cruft which I spotted during review --Mark]
    
    Signed-off-by: Tiger Yang <tiger.yang@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 500086300e6dc5308a7328990bd50d17e075162b
Author: Tiger Yang <tiger.yang@oracle.com>
Date:   Tue Mar 20 16:01:38 2007 -0700

    ocfs2: Remove delete inode vote
    
    Ocfs2 currently does cluster-wide node messaging to check the open state of
    an inode during delete. This patch removes that mechanism in favor of an
    inode cluster lock which is taken at shared read when an inode is first read
    and dropped in clear_inode(). This allows a deleting node to test the
    liveness of an inode by attempting to take an exclusive lock.
    
    Signed-off-by: Tiger Yang <tiger.yang@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 566ec03448052c096dc3982fbe573522dc0ba479
Author: Jamal Hadi Salim <hadi@cyberus.ca>
Date:   Thu Apr 26 14:12:15 2007 -0700

    [XFRM]: Missing bits to SAD info.
    
    This brings the SAD info in sync with net-2.6.22/net-2.6
    
    Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a9f5f70739363ccca2e771c274c4f015c5fb7a88
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Thu Apr 26 11:43:43 2007 -0700

    ocfs2: filter more error prints
    
    We don't want to print anything at all in ocfs2_lookup() when getting an
    error from ocfs2_iget() - it could be something as innocuous as a signal
    being detected in the dlm.
    
    ocfs2_permission() should filter on -ENOENT which ocfs2_meta_lock() can
    return if the inode was deleted on another node.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit bebe6f120b036349f7212205eeaf8248d4820c4b
Author: Sunil Mushran <sunil.mushran@oracle.com>
Date:   Tue Apr 17 13:53:38 2007 -0700

    ocfs2: Replace panic() with emergency_restart() when fencing
    
    We have noticed panic() hanging leading us to a situation in which
    the node, while otherwise dead, is still disk heartbeating. This
    leads to a hung cluster as the other nodes are waiting for this
    node to stop disk heartbeating. This situation is only resolved
    by power resetting the box.
    
    Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 5d262cc7dd3d47784f8233ad4ec2cc5a08059b71
Author: Sunil Mushran <sunil.mushran@oracle.com>
Date:   Tue Apr 17 13:49:19 2007 -0700

    ocfs2: Silence compiler warnings
    
    Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit be9e986b824b41c9d5cc5eca34ee3424c35fd162
Author: Mark Fasheh <mark.fasheh@oracle.com>
Date:   Wed Apr 18 15:22:08 2007 -0700

    ocfs2: Local mounts should skip inode updates
    
    We don't want the extent map and uptodate cache destruction in
    ocfs2_meta_lock_update() on a local mount, so skip that.
    
    This fixes several bugs with uptodate being cleared on buffers and extent
    maps being corrupted.
    
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 0d01af6e5dd6bc7abbcb6331021f8fee18005540
Author: Sunil Mushran <sunil.mushran@oracle.com>
Date:   Tue Apr 17 13:32:20 2007 -0700

    ocfs2_dlm: Call cond_resched_lock() once per hash bucket scan
    
    In dlm_migrate_all_locks(), we currently call cond_resched_lock() after
    processing each lockres in a hash bucket. Move it outside the loop so as to
    call it only after the entire hash bucket has been processed.
    
    Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 756a1501ddbbe73098aa031939460930f6edc9cd
Author: Srinivas Eeda <srinivas.eeda@oracle.com>
Date:   Tue Apr 17 13:26:33 2007 -0700

    ocfs2_dlm: fix race in dlm_remaster_locks
    
    There is a possibility that dlm_remaster_locks could overwride node->state
    with DLM_RECO_NODE_DATA_REQUESTED after dlm_reco_data_done_handler sets the
    node->state to DLM_RECO_NODE_DATA_DONE. This could lead to recovery getting
    stuck and requires a cluster reboot. Synchronize with dlm_reco_state_lock
    spinlock.
    
    Signed-off-by: Srinivas Eeda <srinivas.eeda@oracle.com>
    Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>

commit 9101be532a3c60c7e8773868395e3b75259d84c3
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Wed Apr 18 16:18:13 2007 -0400

    [CPUFREQ] cleanup kconfig options
    
    Adds proper lines to help output of kconfig so people can find the module names.
    Also fixed some broken leading spaces versus tabs.
    
    Signed-off-by: Mike Frysinger <vapier@gentoo.org>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 07844252ffd81ec192a62014bada1016c9703765
Author: Rafal Bilski <rafalbilski@interia.pl>
Date:   Sun Apr 22 12:26:04 2007 +0200

    [CPUFREQ] Longhaul - Revert Longhaul ver. 2
    
    There is something wrong with this code. It needs more
    testing. It is better to disable it for now because support
    for some machines will be broken.
    
    Signed-off-by: Rafal Bilski <rafalbilski@interia.pl>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 632786ce9ff6206951ee4c84fe5c0d5c1d12f4cc
Author: Thomas Renninger <trenn@suse.de>
Date:   Thu Apr 19 15:49:09 2007 +0200

    [CPUFREQ] Remove deprecated /proc/acpi/processor/performance write support
    
    Remove deprecated /proc/acpi/processor/performance write support
    
    Writing to /proc/acpi/processor/xy/performance interferes with sysfs
    cpufreq interface. Also removes buggy cpufreq_set_policy exported symbol.
    
    Signed-off-by: Thomas Renninger <trenn@suse.de>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 22c970f3468a6766b362d57fa32ebb92cb8cd6db
Author: Thomas Renninger <trenn@suse.de>
Date:   Thu Apr 19 15:48:34 2007 +0200

    [CPUFREQ] Fix limited cpufreq when booted on battery
    
    References:
    https://bugzilla.novell.com/show_bug.cgi?id=231107
    https://bugzilla.novell.com/show_bug.cgi?id=264077
    
    Fix limited cpufreq when booted on battery
    
    If booted on battery:
    cpufreq_set_policy (evil) is invoked which calls verify_within_limits.
    max_freq gets lowered and therefore users_policy.max, which
    is used to restore higher freqs via update_policy later is set to the
    already limited frequency -> you can never go up again, even BIOS
    allows higher freqs later.
    
    Signed-off-by: Thomas Renninger <trenn@suse.de>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit e8e49190f64896afe79f7136a67c2bdefbd3e322
Author: Dave Jones <davej@redhat.com>
Date:   Wed Apr 11 18:22:34 2007 -0400

    Fix preemption warnings in speedstep-centrino.c
    
    BUG: using smp_processor_id() in preemptible [00000001] code:
    kondemand/0/2473
    caller is centrino_target+0xfb/0x600
    [<401e3646>] debug_smp_processor_id+0x9e/0xb0
    [<40112afb>] centrino_target+0xfb/0x600
    [<40112a00>] centrino_target+0x0/0x600
    [<40305bd9>] __cpufreq_driver_target+0x5c/0x6b
    [<f897a537>] do_dbs_timer+0x1bc/0x208 [cpufreq_ondemand]
    [<40134a46>] run_workqueue+0x85/0x125
    [<40374f7f>] _spin_lock_irqsave+0x18/0x66
    [<f897a37b>] do_dbs_timer+0x0/0x208 [cpufreq_ondemand]
    [<401353fb>] worker_thread+0xf9/0x124
    [<401213b9>] default_wake_function+0x0/0xc
    [<40135302>] worker_thread+0x0/0x124
    [<40137b37>] kthread+0xb0/0xd9
    [<40137a87>] kthread+0x0/0xd9
    [<40104b2f>] kernel_thread_helper+0x7/0x10
    
    Signed-off-by: Dave Jones <davej@redhat.com>

commit fb48e15645fb702cb2ec02c84f82ece2fbc1574d
Author: RafaÅ‚ Bilski <rafalbilski@interia.pl>
Date:   Fri Mar 2 20:12:27 2007 +0100

    [CPUFREQ] Longhaul - Correct PCI code
    
    Replace obsolete pci_find_device with pci_get_device.
    
    Signed-off-by: Rafal Bilski <rafalbilski@interia.pl>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 551948bc44260a5ab3ad63546506b2062f77eaa0
Author: Alexey Dobriyan <adobriyan@sw.ru>
Date:   Mon Mar 19 19:17:00 2007 +0300

    [CPUFREQ] p4-clockmod: switch to rdmsr_on_cpu/wrmsr_on_cpu
    
    Dances with cpumasks go away.
    
    Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 881ba59d4685b28433bf313b6db51672a02696a3
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 14:51:29 2007 +0100

    [AGPGART] sworks-agp: Switch to PCI ref counting APIs
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 1e415732834991c8335da39832ee7a91f2a65602
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 14:50:27 2007 +0100

    [AGPGART] Nvidia AGP: Use refcount aware PCI interfaces
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit b826b4d6e497f862239c16b25fe864026858aad5
Author: Dave Jones <davej@redhat.com>
Date:   Mon Apr 9 02:20:34 2007 -0400

    [AGPGART] Fix sparse warning in sgi-agp.c
    
    drivers/char/agp/sgi-agp.c:51:10: warning: Using plain integer as NULL pointer
    
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 89cf7ccc936db979e5e9d9ce49437ef859cdd889
Author: Jan Beulich <jbeulich@novell.com>
Date:   Mon Apr 2 14:50:14 2007 +0100

    [AGPGART] Intel-agp adjustments
    
    Fix a call to __free_page where __free_pages(, 2) was meant, and do proper
    error path handling. Also remove a redundant conditional.
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 9eeee244142562cba4f9fbc93962acf6a61847b5
Author: Jan Beulich <jbeulich@novell.com>
Date:   Mon Apr 2 14:50:14 2007 +0100

    [AGPGART] Move [un]map_page_into_agp into asm/agp.h
    
    Remove an arch-dependent hunk in favor of #define-ing the respective bits in
    asm-<arch>/agp.h (allowing easier overriding in para-virtualized environments).
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 77ec430ec3b5c6b9bd6dcb0ff9764d9c95bbd227
Author: Jan Beulich <jbeulich@novell.com>
Date:   Mon Apr 2 14:50:14 2007 +0100

    [AGPGART] Add missing calls to global_flush_tlb() to ali-agp
    
    add missing calls to global_flush_tlb().
    
    Signed-off-by: Jan Beulich <jbeulich@novell.com>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 82eab1306c20f67f718cb5439f7efd62f4e86fc8
Author: Oliver Neukum <oneukum@suse.de>
Date:   Mon Mar 26 21:39:20 2007 -0800

    [AGPGART] prevent probe collision of sis-agp and amd64_agp
    
    For some vendor/id pairs the kernel will autoload both the sis-agp and the
    amd64_agp modules as the sis-agp module will load for all sis devices.
    This collision causes the bug reported in:
    http://bugzilla.novell.com/show_bug.cgi?id=248665
    
    As currently sis_probe does its own matching, requesting the whole range
    gains nothing.  The clean fix seems to me to leave the matching to the core
    and advertise only the devices actually supported.  This patch does so.
    
    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Jones <davej@redhat.com>

commit 984acfe1cfb613257a15f30b3cf60ae7e4ed8f06
Author: Steve French <sfrench@us.ibm.com>
Date:   Thu Apr 26 16:42:50 2007 +0000

    [CIFS] prefixpath mounts to servers supporting posix paths used wrong slash
    
    Acked-by: Alexander Bokovoy <abokovoy@ru.ibm.com>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit deb0420c6ffdee5608856ec3e8e65fcbea67d5d4
Author: Steve French <sfrench@us.ibm.com>
Date:   Thu Apr 26 14:35:54 2007 +0000

    [CIFS] Update cifs version to 1.49
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 3cbb1c8e1a4787d3dc2951b7615d7bb3788c49a0
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 26 07:30:29 2007 -0500

    JFS: use __set_current_state()
    
    use __set_current_state(TASK_*) instead of current->state = TASK_*
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>

commit a48141db68e4b9143759435badcc1a49d9022db4
Author: Paul Mackerras <paulus@samba.org>
Date:   Thu Apr 26 22:24:31 2007 +1000

    Revert "[POWERPC] Rename get_property to of_get_property: drivers"
    
    This reverts commit d05c7a80cf39ae7d0f8d0c3e47c93d51fcd393d3,
    which included changes which should go via other subsystem
    maintainers.

commit 0999ed7f57728c1919b131207e47d9b311cfbd74
Author: Paul Mackerras <paulus@samba.org>
Date:   Thu Apr 26 17:01:04 2007 +1000

    Revert "[POWERPC] DMA 4GB boundary protection"
    
    This reverts commit 618d3adc351a24c4c48437c767befb88ca2d199d, because
    it is superseded by 569975591c5530fdc9c7a3c45122e5e46f075a74.

commit ee5ac9ddf2ea13be2418ac7d0ce5a930e78af013
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Apr 26 00:03:53 2007 -0700

    [SPARC]: device_node name constification fallout
    
    A couple of routines need their arguments to be const.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3e4d26508af6d03034a97583c895f33bef671d06
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Apr 25 15:58:22 2007 -0700

    [SPARC64]: Convert SBUS over to generic iommu/strbuf structs.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 66875088098f314af1a4d9e0cc47e617d643bffd
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Apr 25 00:12:09 2007 -0700

    [SPARC64]: Add generic iommu and strbuf structs to iommu.h
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9b3627f389c07c5be9c86ac4d472a0d4fd47feac
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Tue Apr 24 23:51:18 2007 -0700

    [SPARC64]: Consolidate {sbus,pci}_iommu_arena.
    
    Move to asm-sparc64/iommu.h and rename to plain "iommu_arena".
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 711b360d64418e88ed45f812e0ebd202073d888d
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Apr 12 14:38:34 2007 -0700

    [SPARC]: Make device_node name and type const
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3dfe10ee7caae9802d84a06fe7724274dea24020
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 11:22:57 2007 -0700

    [SPARC64]: constify some paramaters of OF routines
    
    This starts bringing the PowerPC and Sparc64 implemetations back closer
    together.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 374d4cac6283469f101282ca83ee008368bd8350
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:57:57 2007 -0700

    [TIGON3]: of_get_property() returns const.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a165b4205e0097c7544ec3c59522a3b20ec14eb1
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:50:16 2007 -0700

    [SPARC64]: Fix PCI rework to adhere to of_get_property() const return.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f1cfdb55f16596752e8a61a8570a90ee26af183a
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 22:52:18 2007 -0700

    [SPARC64]: Document and fix calculation of pages_avail.
    
    It should be set to the total number of pages that the
    system will really have available after things like
    initmem, the bootmem map, and initrd are freed up.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0f3e25049e0a54916d0991c1eaa5f8df926c7f92
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 21:44:03 2007 -0700

    [SPARC64]: Make sure pbm->prom_node is setup easly enough in psycho.c
    
    It needs to be ready before we invoke pci_determine_mem_io_space().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3996465392fd1632b671707d16bbc96a9481cfe2
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 19:36:53 2007 -0700

    [SPARC64]: Use bootmem_bootmap_pages() in choose_bootmap_pfn().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b93f2620231d4641bdbaaa952d3e8890687124bb
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 18:29:13 2007 -0700

    [SPARC64]: Add proper header file extern for cmdline_memory_size.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9753f0d6502acd65761ff15244d26d0e88f0820a
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 18:26:00 2007 -0700

    [SPARC64]: Kill sparc_ultra_dump_{i,d}tlb()
    
    While useful in odd circumstances to debug something, they are
    normally totally unused and anyone can fetch this code out of the
    history if they really need it.
    
    And in any event, the person who needs this kind of code is usually me
    :-)
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 85f1e1f66011e67e68065f2db4cde499decb9c84
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 17:51:26 2007 -0700

    [SPARC64]: Use DECLARE_BITMAP and BITS_TO_LONGS in mm/init.c
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5be4a963675d3270fab7f55e8c4a2e56afd408f6
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 16:00:29 2007 -0700

    [SPARC64]: Give move verbose show_mem() output just like i386.
    
    We now report everything i386 does except for highmem which
    doesn't apply.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 28256ca2e04c72eee1e83524d7f78ce5646030e2
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 15:56:07 2007 -0700

    [SPARC64]: Mark show_mem() printk's with KERN_INFO.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a94aa2530643f02a4b243f81b5f6354b9b958d7e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 15:50:11 2007 -0700

    [SPARC64]: Kill kvaddr_to_phys() and friends.
    
    Just inline it into flush_icache_range() which is the only
    user.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4be5c34dc47b5a9e6f91c8f5937a93c464870b8e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 15:44:05 2007 -0700

    [SPARC64]: Privatize sun4u_get_pte() and fix name.
    
    __get_phys is only called from init.c as is prom_virt_to_phys(),
    __get_iospace() is not called at all, and sun4u_get_pte() is largely
    misnamed.
    
    Privatize the implementation and helper functions of
    sun4u_get_phys() to mm/init.c, and rename to
    kvaddr_to_paddr().
    
    The only used of this thing is flush_icache_range(), and thus
    things can be considerably further simplified.  For example,
    we should only see module or PAGE_OFFSET kernel addresses here,
    so we don't need the OBP firmware range handling at all.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a0963bdfb91ca97c2b0b6d4ca81ff557fac66901
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 15:09:06 2007 -0700

    [SPARC64]: Kill _start[]/_end[] declarations in mm/init.c
    
    We already get those from asm/sections.h
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4e286d5be63c93b17f8a82d6f3618faa9c1b025c
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 00:21:45 2007 -0700

    [SPARC64]: MAX_PHYSADDR_BITS et al. really need to be 42 bits not 41.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0015d3d68c84eb33e6b380802ad61b23f7eb6523
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 15 00:06:34 2007 -0700

    [SPARC64]: Simplify read_obp_memory().
    
    Kick out empty entries as soon as we spot them, and use memmove()
    instead of a silly loop to make the operation more clear.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d78d0891d3dd976a2fb707c6c691d9cd5ed60727
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Mar 14 22:47:01 2007 -0700

    [SPARC64]: Use SPARSEMEM_STATIC
    
    Decrease the SECTION_SIZE_BITS --> MAX_PHYSADDR_BITS
    range a little bit.
    
    The cost of going to SPARSEMEM_STATIC becomes 8K of BSS space, and in
    return we save a pointer dereferences on every page struct lookup.
    Even better we hit the main kernel image for the base address which is
    in a hugepage locked TLB entry.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 43bed127376ff2ef9c268cf6688a43d0fbed2ff4
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Mar 14 18:33:49 2007 -0700

    [SPARC64]: Use DECLARE_BITMAP in struct pci_iommu.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 28f57e774d91ce01e03ff65caa2313bc8786b66f
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Mar 12 19:40:26 2007 -0700

    [SPARC64]: Force dummy host controller onto bus zero.
    
    This helps deal with the invisible bridge that sits between
    the host controller and the top-most visisble PCI devices
    on hypervisor systems.
    
    For example, on T1000 the bus-range property says 2 --> 4
    and so there is a PCI express bridge at bus 2, devfn 0, etc.
    
    So if we don't force the dummy host controller to bus zero,
    we'll try to create two devices with the same domain/bus/devfn
    triplet.
    
    Also, add some more log diagnostics to make debugging stuff like this
    easyer.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 97b3cf050b467dda571943ceadff5452bed04549
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Sun Mar 11 16:42:53 2007 -0700

    [SPARC64]: Add dummy host controller to root of all PCI domains.
    
    We fake up a dummy one in all cases because that is the simplest
    thing to do and it happens to be necessary for hypervisor systems.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c6e87566ea080bbbe926c0e429fed48e6f680d93
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Fri Mar 9 16:58:43 2007 -0800

    [SPARC64]: Const'ify pci_iommu_ops.
    
    Based upon a similar patch for x86_64 written by
    Stephen Hemminger.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0bba2dd823fd995ed805ae5cbd5a1c1381257a12
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 23:06:39 2007 -0800

    [SPARC64]: Kill pbm->pci_first_slot.
    
    Set but never used.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3875c5c02d7112aa85f815d65d8add2e39ae9e34
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 22:52:11 2007 -0800

    [SPARC64]: Kill pci_controller->pbms_same_domain
    
    We don't do the "Simba APB is a PBM" bogosity for Sabre
    controllers any longer, so this pbms_same_domain thing
    is no longer necessary.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8d3aee937596d2ca6676c2c27789751445bf0bc9
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 22:46:02 2007 -0800

    [SPARC64]: Kill pci_controller->base_address_update().
    
    Implemented but never actually used.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0bae5f81b6f8130f5197e59b0e2ad6820c766b2b
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 22:42:19 2007 -0800

    [SPARC64]: Kill pci_controller->resource_adjust()
    
    All the implementations can be identical and generic, so
    no need for controller specific methods.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3487a1f9e719d36c9b2d4d492994b2dd815a58b7
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 22:28:17 2007 -0800

    [SPARC64]: Kill PBM ranges software state.
    
    It is only used in one spot and we can just fetch the
    OF property right there.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 229177c7f38d6a2b1285b42da4b19d76346b4bac
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 22:11:00 2007 -0800

    [SPARC64]: Kill PBM intmap software state.
    
    Set but never used.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9fd8b64761d3fe7e4ef567161be57e4234af5c1c
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 8 21:55:49 2007 -0800

    [SPARC64]: Consolidate PCI mem/io resource determination.
    
    It can be done for every PCI configuration using OF properties.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 01f94c4a6ced476ce69b895426fc29bfc48c69bd
Author: David S. Miller <davem@ultra5.davemloft.net>
Date:   Sun Mar 4 12:53:19 2007 -0800

    [SPARC64]: Fix sabre pci controllers with new probing scheme.
    
    The SIMBA APB bridge is strange, it is a PCI bridge but it lacks
    some standard OF properties, in particular it lacks a 'ranges'
    property.
    
    What you have to do is read the IO and MEM range registers in
    the APB bridge to determine the ranges handled by each bridge.
    So fill in the bus resources by doing that.
    
    Since we now handle this quirk in the generic PCI and OF device
    probing layers, we can flat out eliminate all of that code from
    the sabre pci controller driver.
    
    In fact we can thus eliminate completely another quirk of the sabre
    driver.  It tried to make the two APB bridges look like PBMs but that
    makes zero sense now (and it's questionable whether it ever made sense).
    So now just use pbm_A and probe the whole PCI hierarchy using that as
    the root.
    
    This simplification allows many future cleanups to occur.
    
    Also, I've found yet another quirk that needs to be worked around
    while testing this.  You can't use the 'class-code' OF firmware
    property, especially for IDE controllers.  We have to read the value
    out of PCI config space or else we'll see the value the device was
    showing before it was programmed into native mode.
    
    I'm starting to think it might be wise to just read all of the values
    out of PCI config space instead of using the OF properties. :-/
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a378fd0ee8ea6af5dafd0ab3d634f22b926b5ac4
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 1 11:46:13 2007 -0800

    [SPARC64]: Fix obppath pci device sysfs creation.
    
    Need to traverse recursively down child busses else we only
    get the file created under devices at the top-level.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bc606f3c917aa453fca62b76c8e9998b4171f4fa
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 1 11:20:37 2007 -0800

    [SPARC64]: Minor cleanups to schizo pci controller driver.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1e8a8cc52daa95e702303ca3ce67955a4c051d7d
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 23:38:38 2007 -0800

    [SPARC64]: Internalize pci_memspace_mask.
    
    The only user was bus_dvma_to_mem() which is no longer used
    by any driver, so kill that, and the export of pci_memspace_mask.
    
    The only user now is the PCI mmap support code.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a2fb23af1c31ad6e0c281e56d385f803229d57fa
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 23:35:04 2007 -0800

    [SPARC64]: Probe PCI bus using OF device tree.
    
    Almost entirely taken from the 64-bit PowerPC PCI code.
    
    This allowed to eliminate a ton of cruft from the sparc64
    PCI layer.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit deb66c4521e119442aa266553e8cbfc86eb71232
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 18:01:38 2007 -0800

    [SPARC64] isa: Convert to use pci_device_to_OF_node().
    
    Also, do not try to compute resources by hand, instead use
    the pre-computed ones in the of_device.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1327e9b62fc88e64ffbbd42d61fccd34e521bb86
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 17:55:46 2007 -0800

    [SPARC64] ebus: Convert to use pci_device_to_OF_node().
    
    Also, we don't need to store or use the PBM so kill that
    from the linux_ebus.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9b1caafe09ccec8e0103e9375b711e3a0c838260
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 17:05:06 2007 -0800

    [IGAFB]: Use pci_device_to_OF_node() on sparc.
    
    Also __sparc__ --> CONFIG_SPARC
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a02079cdb74dde27391d019abca4a37988504b4e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 17:02:45 2007 -0800

    [ATYFB]: Use pci_device_to_OF_node() in sparc.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fa449bd602c8871da48e6dbadfa0faaf4d33d32e
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Apr 25 16:01:51 2007 -0700

    [OPENPROM]: Use pci_device_to_OF_node().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d297c31fd101473983c17734a7e8a3752da1880f
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:41:28 2007 -0700

    [TULIP]: Use pci_device_to_OF_node() on sparc.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 49345103fef36617abc9a649dfc34f7e921c6878
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:39:44 2007 -0700

    [TULIP]: Use CONFIG_SPARC consistently in ifdef tests.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 49b6e95ff6d05722bcf7a52b00454566ce0c44eb
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:38:42 2007 -0700

    [TG3]: Use pci_device_to_OF_node() on sparc.
    
    And use CONFIG_SPARC instead of CONFIG_SPARC64 as the
    test.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6f85a8597d1d0d8ceeec5a82881c6ddf5cfb45e5
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 16:40:57 2007 -0800

    [SUNHME]: Use pci_device_to_OF_node().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 457e1a8afbcf5deffa501f2e9829526c18ed55b5
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:36:44 2007 -0700

    [SUNGEM]: Consolidate powerpc and sparc MAC probing code.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit dadb830dac401c4b1420ee2fd6c7559871b43319
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Feb 28 15:42:50 2007 -0800

    [SUNGEM]: __sparc__ --> CONFIG_SPARC
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9f47df264fa53e562cafa0de4a405d0846a81fbd
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:33:46 2007 -0700

    [RADEON]: Probe clocks and monitor using OF properties on sparc.
    
    Just like powerpc does.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a8b8814bdfe3bb2bdfa23722de947bad8283037c
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:28:51 2007 -0700

    [SPARC]: Use strcasecmp for OFW property name comparisons.
    
    This allows us to simplify sharing code with powerpc which
    has properties that have various forms of capitalization
    when on the sparc64 side the property is all lower-case.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ded220bd8f0823771fc0a9bdf7f5bcbe543197b6
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 01:18:42 2007 -0700

    [STRING]: Move strcasecmp/strncasecmp to lib/string.c
    
    We have several platforms using local copies of identical
    code.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 357418e7cac16fed4ca558c6037d189d2109c9c2
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:54:04 2007 -0700

    [SPARC]: constify some paramaters of OF routines
    
    This starts bringing the PowerPC and Sparc implemetations back closer
    together.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 64b94701c0714f814e640ff351d5f784fdc0381e
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:53:28 2007 -0700

    [SPARC/64]: constify of_get_property return
    
    Finally, we actually change the functions themselves.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3198514d2d10fb3ce5e49ba0c611764ad8a214d0
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:50:57 2007 -0700

    [SPARC/64] constify of_get_property return: sound
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 66f3cb7ccfe6d735bd1fa435aebc9b985ac74e07
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:50:29 2007 -0700

    [SPARC64] constify of_get_property return: include
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:49:54 2007 -0700

    [SPARC/64] constify of_get_property return: drivers
    
    The only unfortunate bit here is that the name field of struct map_info
    is not const, so for now we put a cast on the assignment of it.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6a23acf3905287eb952a6f1dbbc8fb3e4eeae2f6
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Mon Apr 23 15:53:27 2007 -0700

    [SPARC64]: constify of_get_property return: arch/sparc64
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8271f04242af8ddf8390f289cd6ef78fb3e3c6d9
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Thu Mar 29 00:47:23 2007 -0700

    [SPARC]: constify of_get_property return: arch/sparc
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 644923d4a5f117d437aefd47688d1141cc8361ed
Author: Tony Breeds <tony@bakeyournoodle.com>
Date:   Wed Mar 28 19:10:12 2007 -0700

    [SPARC64]: Small cleanups time.c
    
    - Removes days_in_mo[], as it's almost identical to month_days[]
    - Use the leapyear() macro
    - Line length wrapping.
    
    Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d62c6f093a1ef8fa5f8951e8da93c8ddd3ce193a
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Tue Mar 27 01:20:14 2007 -0700

    [SPARC64]: Fix sparc64_next_event() error return.
    
    It should return an error code not a boolean.
    
    Based upon an hpet timer fix by Thomas Gleixner.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 112f48716d9f292c92a033cff9e3ce7405ed4280
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Mar 5 15:28:37 2007 -0800

    [SPARC64]: Add clocksource/clockevents support.
    
    I'd like to thank John Stul and others for helping
    me along the way.
    
    A lot of cleanups fell out of this.  For example, the get_compare()
    tick_op was totally unused, so was deleted.  And the most often used
    tick_op members were grouped together for cache-friendlyness.
    
    The sparc64 TSC is given to the kernel as a one-shot timer.
    
    tick_ops->init_timer() simply turns off the privileged bit in
    the tick register (when possible), and disables the interrupt
    by setting bit 63 in the compare register.  The ->disable_irq()
    op also sets this bit.
    
    tick_ops->add_compare() is changed to:
    
    1) Add the given delta to "tick" not to "compare"
    2) Return a boolean which, if true, means that the tick
       value read after writing the compare value was found
       to have incremented past the initial tick value.  This
       mirrors logic used in the HPET driver's ->next_event()
       method.
    
    Each tick_ops implementation also now provides a name string.
    And we feed this into the clocksource and clockevents layers.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 038cb01ea69cb24ecf30e3ec882e429c84badbeb
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Feb 22 06:24:45 2007 -0800

    [SPARC64]: Add tick_nohz_{stop,restart}_sched_tick() calls to cpu_idle().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 777a447529ad138f5fceb9c9ad28bab19848f277
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Feb 22 06:24:10 2007 -0800

    [SPARC64]: Unify timer interrupt handler.
    
    Things were scattered all over the place, split between
    SMP and non-SMP.
    
    Unify it all so that dyntick support is easier to add.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a58c9f3c1e929c3c323c26dbdafef46373a719d4
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Feb 22 04:16:21 2007 -0800

    [SPARC64]: Synchronize RTC clock via timer just like x86.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bfbf3c0968498f5232c02965cf41695edae1bc4d
Author: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
Date:   Thu Apr 26 01:41:49 2007 -0700

    [ATM]: Use mutex instead of binary semaphore in FORE Systems 200E-series driver
    
    (akpm: remove CVS control string too)
    
    Signed-off-by: Matthias Kaehlcke <matthias.kaehlcke@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 74da9d88bf5ffd31aed61a0b19519684ad744ded
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 01:41:01 2007 -0700

    [BLUETOOTH] rfcomm_worker(): fix wakeup race
    
    Set TASK_INTERRUPTIBLE prior to testing the flag to avoid missed wakeups.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Acked-by: Marcel Holtmann <marcel@holtmann.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9198d2220d29b87ac3a05a3b791c50bb8a014d63
Author: Alexandra N. Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
Date:   Thu Apr 26 01:40:13 2007 -0700

    [NET]: bonding documentation fix for multiple bonding interfaces
    
    Fix bonding driver documentation for the case of multiple bonding interfaces.
    
    Signed-off-by: "Alexandra N. Kossovsky" <Alexandra.Kossovsky@oktetlabs.ru>
    Acked-by: Jay Vosburgh <fubar@us.ibm.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4ef8d0aeafda8388dd51f2671b7059192b1e5a5f
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 26 01:37:44 2007 -0700

    [NET]: SPIN_LOCK_UNLOCKED cleanup in drivers/atm, net
    
    SPIN_LOCK_UNLOCKED cleanup,use __SPIN_LOCK_UNLOCKED instead
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1c8ea5aee0b16409295d96a5e8984bd902f06a77
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 01:36:49 2007 -0700

    [IRDA] irda_device_dongle_init: fix kzalloc(GFP_KERNEL) in spinlock
    
    Fix http://bugzilla.kernel.org/show_bug.cgi?id=8343
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 14690fc649f4c59712f497135f7323eb8ceceaaf
Author: Martin Peschke <mp3@de.ibm.com>
Date:   Thu Apr 26 01:03:43 2007 -0700

    [SUNRPC]: cleanup: use seq_release_private() where appropriate
    
    We can save some lines of code by using seq_release_private().
    
    Signed-off-by: Martin Peschke <mp3@de.ibm.com>
    Acked-by: Neil Brown <neilb@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f8a6d97043f9adc25889876b681998b77f543bfa
Author: Alexey Dobriyan <adobriyan@gmail.com>
Date:   Thu Apr 26 01:02:51 2007 -0700

    [AF_IUCV]: Fix compilation on s390-up
    
      CC [M]  net/iucv/iucv.o
    net/iucv/iucv.c: In function 'iucv_init':
    net/iucv/iucv.c:1556: error: 'iucv_cpu_notifier' undeclared (first use in this function)
    
    Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 57cd5f754e04240ee587c51b7be8d3b7793542ae
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Thu Apr 26 01:01:53 2007 -0700

    [NET]: ROUND_UP macro cleanup in drivers/net/ppp_generic.c
    
    ROUND_UP macro cleanup use DIV_ROUND_UP
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Acked-by: Paul Mackerras <paulus@samba.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 36226a8ded46b89a94f9de5976f554bb5e02d84c
Author: Brian Braunstein <linuxkernel@bristyle.com>
Date:   Thu Apr 26 01:00:55 2007 -0700

    [NET] tun/tap: fixed hw address handling
    
    Fixed tun/tap driver's handling of hw addresses.  The hw address is stored
    in both the net_device.dev_addr and tun.dev_addr fields.  These fields were
    not kept synchronized, and in fact weren't even initialized to the same
    value.  Now during both init and when performing SIOCSIFHWADDR on the tun
    device these values are both updated.  However, if SIOCSIFHWADDR is
    performed on the net device directly (for instance, setting the hw address
    using ifconfig), the tun device does not get updated.  Perhaps the
    tun.dev_addr field should be removed completely at some point, as it is
    redundant and net_device.dev_addr can be used anywhere it is used.
    
    Signed-off-by: Brian Braunstein <linuxkernel@bristyle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 48491e6bdb8fa73751cc95f740175ec799db5d55
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Apr 26 00:59:27 2007 -0700

    [NET]: Delete unused header file linux/if_wanpipe_common.h
    
    Delete the unreferenced header file include/linux/if_wanpipe_common.h,
    as well as the reference to it in the Doc file.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c1a068f6b0c38665c079e8d4ca241e24020eff36
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Apr 26 00:58:39 2007 -0700

    [NET]: Delete unused header file linux/sdla_fr.h.
    
    Delete the unreferenced header file include/linux/sdla_fr.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

commit 42bad1da506cafa7041a02ab84033a724afe88ac
Author: Adrian Bunk <bunk@stusta.de>
Date:   Thu Apr 26 00:57:41 2007 -0700

    [NETLINK]: Possible cleanups.
    
    - make the following needlessly global variables static:
      - core/rtnetlink.c: struct rtnl_msg_handlers[]
      - netfilter/nf_conntrack_proto.c: struct nf_ct_protos[]
    - make the following needlessly global functions static:
      - core/rtnetlink.c: rtnl_dump_all()
      - netlink/af_netlink.c: netlink_queue_skip()
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 55404bca6c45595fee1a546f1a0cc616aeef0b00
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 00:55:53 2007 -0700

    [NET]: Fix yam.c
    
    drivers/net/hamradio/yam.c: In function `yam_tx_byte':
    drivers/net/hamradio/yam.c:643: warning: passing arg 1 of `skb_copy_from_linear_data_offset' from incompatible pointer type
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit eefa3906283a2b60a6d02a2cda593a7d7d7946c5
Author: Jean Delvare <jdelvare@suse.de>
Date:   Thu Apr 26 00:44:22 2007 -0700

    [NET]: Clean up sk_buff walkers.
    
    I noticed recently that, in skb_checksum(), "offset" and "start" are
    essentially the same thing and have the same value throughout the
    function, despite being computed differently. Using a single variable
    allows some cleanups and makes the skb_checksum() function smaller,
    more readable, and presumably marginally faster.
    
    We appear to have many other "sk_buff walker" functions built on the
    exact same model, so the cleanup applies to them, too. Here is a list
    of the functions I found to be affected:
    
    net/appletalk/ddp.c:atalk_sum_skb()
    net/core/datagram.c:skb_copy_datagram_iovec()
    net/core/datagram.c:skb_copy_and_csum_datagram()
    net/core/skbuff.c:skb_copy_bits()
    net/core/skbuff.c:skb_store_bits()
    net/core/skbuff.c:skb_checksum()
    net/core/skbuff.c:skb_copy_and_csum_bit()
    net/core/user_dma.c:dma_skb_copy_datagram_iovec()
    net/xfrm/xfrm_algo.c:skb_icv_walk()
    net/xfrm/xfrm_algo.c:skb_to_sgvec()
    
    OTOH, I admit I'm a bit surprised, the cleanup is rather obvious so I'm
    really wondering if I am missing something. Can anyone please comment
    on this?
    
    Signed-off-by: Jean Delvare <jdelvare@suse.de>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 28d8909bc790d936ce33f4402adf7577533bbd4b
Author: Jamal Hadi Salim <hadi@cyberus.ca>
Date:   Thu Apr 26 00:10:29 2007 -0700

    [XFRM]: Export SAD info.
    
    On a system with a lot of SAs, counting SAD entries chews useful
    CPU time since you need to dump the whole SAD to user space;
    i.e something like ip xfrm state ls | grep -i src | wc -l
    I have seen taking literally minutes on a 40K SAs when the system
    is swapping.
    With this patch, some of the SAD info (that was already being tracked)
    is exposed to user space. i.e you do:
    ip xfrm state count
    And you get the count; you can also pass -s to the command line and
    get the hash info.
    
    Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 06d63cc51d47f572009138a7f3ac34d95773405d
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Wed Apr 25 22:41:34 2007 -0700

    [MTD] [MAPS] fix plat-ram printk format
    
    drivers/mtd/maps/plat-ram.c:172: warning: format '%lx' expects type 'long unsigned int', but argument 4 has type 'resource_size_t'
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit f6449f4ece2bf283500bda73edcbea82f2cb3a1b
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Thu Apr 26 07:27:04 2007 +0100

    [JFFS2] Fix compr_rubin.c build after include file elimination.
    
    It seems to be silly season lately.
    
    (Oops, test builds are more useful if the file in question is actually
    configured on. dwmw2).
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit f50393fe869ba457cd75569c74c0f9bd2e7f7a0f
Author: Mark Huth <mhuth@mvista.com>
Date:   Tue Mar 6 08:57:26 2007 -0800

    e1000: FIX: Stop raw interrupts disabled nag from RT
    
    Current e1000_xmit_frame spews raw interrupt disabled nag messages when
    used with RT kernel patches.  This patch uses spin_trylock_irqsave,
    which allows RT patches to properly manage the irq semantics.
    
    Signed-off-by: Mark Huth <mhuth@mvista.com>
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit 31d76442f719af834718cbf5bf866370acc36093
Author: Bruce Allan <bruce.w.allan@intel.com>
Date:   Tue Mar 6 08:57:24 2007 -0800

    e1000: FIX: firmware handover bits
    
    Upon code inspection it was spotted that the firmware handover bit get/set
    mismatched, which may have resulted in management issues on PCI-E
    adapters. Setting them correctly may fix some management issues such
    as arp routing etc.
    
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit e0aac5a289b1dacbc94bd9ae8c449bcdf9ab508c
Author: Auke Kok <auke-jan.h.kok@intel.com>
Date:   Tue Mar 6 08:57:21 2007 -0800

    e1000: FIX: be ready for incoming irq at pci_request_irq
    
    DEBUG_SHIRQ code exposed that e1000 was not ready for incoming interrupts
    after having called pci_request_irq. This obviously requires us to finish
    our software setup which assigns the irq handler before we request the
    irq.
    
    Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
    Signed-off-by: Jeff Garzik <jeff@garzik.org>

commit e900a7d90ae1486ac95c10e0b7337fc2c2eda529
Author: Stephen Smalley <sds@tycho.nsa.gov>
Date:   Thu Apr 19 14:16:19 2007 -0400

    selinux: preserve boolean values across policy reloads
    
    At present, the userland policy loading code has to go through contortions to preserve
    boolean values across policy reloads, and cannot do so atomically.
    As this is what we always want to do for reloads, let the kernel preserve them instead.
    
    Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
    Acked-by: Karl MacMillan <kmacmillan@mentalrootkit.com>
    Signed-off-by: James Morris <jmorris@namei.org>

commit bce34bc0eef03c68b5c49a3cc5bc77c84760cfe2
Author: James Carter <jwcart2@tycho.nsa.gov>
Date:   Wed Apr 4 16:18:50 2007 -0400

    selinux: change numbering of boolean directory inodes in selinuxfs
    
    Change the numbering of the booleans directory inodes in selinuxfs to
    provide more room for new inodes without a conflict in inode numbers and
    to be consistent with how inode numbering is done in the
    initial_contexts directory.
    
    Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
    Acked-by: Eric Paris <eparis@parisplace.org>
    Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 68b00df9bb5f38e87c102b3179a18eba9c9937a8
Author: James Carter <jwcart2@tycho.nsa.gov>
Date:   Wed Apr 4 16:18:43 2007 -0400

    selinux: remove unused enumeration constant from selinuxfs
    
    Remove the unused enumeration constant, SEL_AVC, from the sel_inos
    enumeration in selinuxfs.
    
    Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
    Acked-by: Eric Paris <eparis@parisplace.org>
    Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 6174eafce3a38114adc6058e2872434c53feae87
Author: James Carter <jwcart2@tycho.nsa.gov>
Date:   Wed Apr 4 16:18:39 2007 -0400

    selinux: explicitly number all selinuxfs inodes
    
    Explicitly number all selinuxfs inodes to prevent a conflict between
    inodes numbered using last_ino when created with new_inode() and those
    labeled explicitly.
    
    Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
    Acked-by: Eric Paris <eparis@parisplace.org>
    Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit f0ee2e467ffa68c3122128b704c1540ee294b748
Author: James Carter <jwcart2@tycho.nsa.gov>
Date:   Wed Apr 4 10:11:29 2007 -0400

    selinux: export initial SID contexts via selinuxfs
    
    Make the initial SID contexts accessible to userspace via selinuxfs.
    An initial use of this support will be to make the unlabeled context
    available to libselinux for use for invalidated userspace SIDs.
    
    Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
    Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit a764ae4b0781fac75f9657bc737c37ae59888389
Author: Stephen Smalley <sds@tycho.nsa.gov>
Date:   Mon Mar 26 13:36:26 2007 -0400

    selinux: remove userland security class and permission definitions
    
    Remove userland security class and permission definitions from the kernel
    as the kernel only needs to use and validate its own class and permission
    definitions and userland definitions may change.
    
    Signed-off-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 4f6a993f96a256e83b9be7612f958c7bc4ca9f00
Author: Paul Moore <paul.moore@hp.com>
Date:   Thu Mar 1 14:35:22 2007 -0500

    SELinux: move security_skb_extlbl_sid() out of the security server
    
    As suggested, move the security_skb_extlbl_sid() function out of the security
    server and into the SELinux hooks file.
    
    Signed-off-by: Paul Moore <paul.moore@hp.com>
    Acked-by:  Stephen Smalley <sds@tycho.nsa.gov>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 588a31577f86a5cd8b0bcde6026e4e6dcac8c383
Author: Stephen Smalley <sds@tycho.nsa.gov>
Date:   Fri Feb 23 09:20:09 2007 -0500

    MAINTAINERS: update selinux entry
    
    Add Eric Paris as an SELinux maintainer.
    
    Signed-off-by: James Morris <jmorris@namei.org>

commit c60475bf35fc5fa10198df89187ab148527e72f7
Author: Paul Moore <paul.moore@hp.com>
Date:   Wed Feb 28 15:14:23 2007 -0500

    SELinux: rename selinux_netlabel.h to netlabel.h
    
    In the beginning I named the file selinux_netlabel.h to avoid potential
    namespace colisions.  However, over time I have realized that there are several
    other similar cases of multiple header files with the same name so I'm changing
    the name to something which better fits with existing naming conventions.
    
    Signed-off-by: Paul Moore <paul.moore@hp.com>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 5778eabd9cdbf16ea3e40248c452b4fd25554d11
Author: Paul Moore <paul.moore@hp.com>
Date:   Wed Feb 28 15:14:22 2007 -0500

    SELinux: extract the NetLabel SELinux support from the security server
    
    Up until this patch the functions which have provided NetLabel support to
    SELinux have been integrated into the SELinux security server, which for
    various reasons is not really ideal.  This patch makes an effort to extract as
    much of the NetLabel support from the security server as possibile and move it
    into it's own file within the SELinux directory structure.
    
    Signed-off-by: Paul Moore <paul.moore@hp.com>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 128c6b6cbffc8203e13ea5712a8aa65d2ed82e4e
Author: Paul Moore <paul.moore@hp.com>
Date:   Wed Feb 28 15:14:21 2007 -0500

    NetLabel: convert a BUG_ON in the CIPSO code to a runtime check
    
    This patch changes a BUG_ON in the CIPSO code to a runtime check.  It should
    also increase the readability of the code as it replaces an unexplained
    constant with a well defined macro.
    
    Signed-off-by: Paul Moore <paul.moore@hp.com>
    Signed-off-by: James Morris <jmorris@namei.org>

commit f998e8cb52396c6a197d14f6afb07144324aea6d
Author: Paul Moore <paul.moore@hp.com>
Date:   Wed Feb 28 15:14:20 2007 -0500

    NetLabel: cleanup and document CIPSO constants
    
    This patch collects all of the CIPSO constants and puts them in one place; it
    also documents each value explaining how the value is derived.
    
    Signed-off-by: Paul Moore <paul.moore@hp.com>
    Signed-off-by: James Morris <jmorris@namei.org>

commit 98486fa2f4894e2b01e325c659635596bdec1614
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Apr 25 22:08:46 2007 -0700

    [BRIDGE]: Missing rtnl.
    
    Writing to /sys/class/net/brX/bridge/stp_state causes a warning because
    RTNL is not held when call br_stp_if.c
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c2886d6259b8faac4c05ffd9c3c401ac84478de0
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Apr 25 22:07:58 2007 -0700

    [BRIDGE]: if no STP then forward all BPDUs
    
    If a bridge is not running STP, then it has no way to detect a cycle
    in the network. But if it is not running STP and some other machine
    or device is running STP, then if STP BPDU's get forwarded to it can
    detect the cycle.
    
    This is how the old 2.4 and early 2.6 code worked.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2111f8b9e58fd04b87b8b07d66485f255a57b0bb
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Apr 25 22:05:55 2007 -0700

    [BRIDGE]: drop PAUSE frames
    
    Pause frames should never make it out of the network device into
    the stack. But if a device was misconfigured, it might happen.
    So drop pause frames in bridge.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 83aa0938ff59e8ef6d0b99260063ebe84fc84a16
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Apr 25 22:03:10 2007 -0700

    [BRIDGE]: don't change packet type
    
    The change to forward STP bpdu's (for usermode STP) through normal path,
    changed the packet type in the process. Since link local stuff is multicast, it
    should stay pkt_type = PACKET_MULTICAST.  The code was probably copy/pasted
    incorrectly from the bridge pseudo-device receive path.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e1ec7842df5db897516d73c76bd2a568b4abc33b
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:52 2007 +0900

    [IPV6] NDISC: Unify main process of sending ND messages.
    
    Because ndisc_send_na(), ndisc_send_ns() and ndisc_send_rs()
    are almost identical, so let's unify their common part.
    
    With gcc (GCC) 3.3.5 (Debian 1:3.3.5-13) on i386,
    	Before:
    	   text	   data	    bss	    dec	    hex	filename
    	  14689	    364	     24	  15077	   3ae5	net/ipv6/ndisc.o
    	After:
    	   text	   data	    bss	    dec	    hex	filename
    	  12317	    364	     24	  12705	   31a1	net/ipv6/ndisc.o
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit c53b3590bb294a42121b640e8309379752482b38
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:50 2007 +0900

    [IPV6] XFRM: Use ip6addr_any where applicable.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit df8981dc1928f3a231d91f27c2b3dc373fb4d410
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:49 2007 +0900

    [IPV6]: Export in6addr_any for future use.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 5056a1ef9e2597cff7b15904fbc74193f316fc40
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:48 2007 +0900

    [IPV4] IP_GRE: Unify code path to get hash array index.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 87d1a164df0b5e297cda698724ea7984d8392b06
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:47 2007 +0900

    [IPV4] IPIP: Unify code path to get hash array index.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 420fe234ad7adaa5a5445e5fab83b1485ed9e0f3
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 20:44:47 2007 +0900

    [IPV6] SIT: Unify code path to get hash array index.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 30041e4af426bc9ab7a73440ce4a7c78881b6001
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Tue Apr 24 22:15:40 2007 -0700

    [IPV6]: Fix Makefile thinko.
    
    obj-$(CONFIG_PROC_FS) --> ipv6-$(CONFIG_PROC_FS)
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7f7d9a6b96c5708c5184cbed61bbc15b163a0f08
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Tue Apr 24 21:54:09 2007 -0700

    [IPV6]: Consolidate common SNMP code
    
    This patch moves the non-proc SNMP code into addrconf.c and reuses
    IPv4 SNMP code where applicable.
    
    As a result we can skip proc.o if /proc is disabled.
    
    Note that I've made a number of functions static since they're only
    used by addrconf.c for now.  If they ever get used elsewhere we can
    always remove the static.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5e0f04351d11e07a23b5ab4914282cbb78027e50
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Tue Apr 24 21:53:35 2007 -0700

    [IPV4]: Consolidate common SNMP code
    
    This patch moves the SNMP code shared between IPv4/IPv6 from proc.c
    into net/ipv4/af_inet.c.  This makes sense because these functions
    aren't specific to /proc.
    
    As a result we can again skip proc.o if /proc is disabled.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bb7ec6dfb5aa32b5b4d7d6388b4098b33cd01e8c
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 16:22:42 2007 -0700

    [IPV4]: Fix build without procfs.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 84299b3bc4eaedc0734fcc9052b01291e44445fc
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Apr 24 16:21:38 2007 -0700

    [TCP]: Fix linkage errors on i386.
    
    To avoid raw division, use ktime_to_timeval() to get usec.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1f9eda7e2b67898fb8e79b3aa3880211b51235e6
Author: Allan Stephens <allan.stephens@windriver.com>
Date:   Tue Apr 24 14:51:55 2007 -0700

    [TIPC]: Enhancements to msg_set_bits() routine
    
    This patch makes two enhancements to msg_set_bits():
    
    1) It now ignores any bits of the new field value that are not
       covered by the mask being used.  (Previously, if the new value
       exceeded the size of the mask the extra bits could corrupt
       other fields in the message header word being updated.)
    
    2) The code has been optimized to minimize the number of run-time
       endianness conversion operations by leveraging the fact that the
       mask (and, in some cases, the value as well) is constant and the
       necessary conversion can be performed by the compiler.
    
    Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
    Signed-off-by: Jon Paul Maloy <jon.maloy@ericsson.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 43fb45cb79e9441a79ece206cf741774500dd627
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Tue Apr 24 14:07:27 2007 -0700

    [WIRELESS] cfg80211: Update comment for locking.
    
    This patch adds a comment that was part of my rtnl locking patch for
    cfg80211 but which I forgot for the merge.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f9d106a6d53b57b78eae5544f9582c643343a764
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 23 22:36:13 2007 -0700

    [NET]: Warn about GSO/checksum abuse
    
    Now that Patrick has added the code to deal with GSO in netfilter,
    we no longer need the crutch that computes partial checksums just
    before transmission.
    
    This patch turns this into a warning again.  If this goes OK, we
    can then turn it into a BUG_ON and remove the gso_send_check cruft.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7752237e9f07b316f81aebdc43f0d7c9a4ba0acf
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 23 22:28:23 2007 -0700

    [TCP] TCP YEAH: Use vegas dont copy it.
    
    Rather than using a copy of vegas code, the YEAH code should just have
    it exported so there is common code.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 164891aadf1721fca4dce473bb0e0998181537c6
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 23 22:26:16 2007 -0700

    [TCP]: Congestion control API update.
    
    Do some simple changes to make congestion control API faster/cleaner.
    * use ktime_t rather than timeval
    * merge rtt sampling into existing ack callback
      this means one indirect call versus two per ack.
    * use flags bits to store options/settings
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 65d1b4a7e73fe0e1f5275ad7d2d3547981480886
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 23 22:24:32 2007 -0700

    [TCP]: TCP Illinois update.
    
    This version more closely matches the paper, and fixes several
    math errors. The biggest difference is that it updates alpha/beta
    once per RTT
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 42431592e74a968d919a46baf0515a2ee6978dac
Author: John W. Linville <linville@tuxdriver.com>
Date:   Mon Apr 23 13:28:49 2007 -0700

    [WIRELESS] drivers/net/wireless/Kconfig: correct minor typo
    
    Correct minor typo in drivers/net/wireless/Kconfig identified by
    Stefano Brivio <stefano.brivio@polimi.it>.
    
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9e101eab153073d8a1fc7ea22b20af65de8ab44b
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 23 12:20:55 2007 -0700

    [WIRELESS]: Remove wext over netlink.
    
    As scheduled, this patch removes the pointless wext over netlink code.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 704232c2718c9d4b3375ec15a14fc0397970c449
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 23 12:20:05 2007 -0700

    [WIRELESS] cfg80211: New wireless config infrastructure.
    
    This patch creates the core cfg80211 code along with some sysfs bits.
    This is a stripped down version to allow mac80211 to function, but
    doesn't include any configuration yet except for creating and removing
    virtual interfaces.
    
    This patch includes the nl80211 header file but it only contains the
    interface types which the cfg80211 interface for creating virtual
    interfaces relies on.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2a5e1c0eb9efe26eed1dd072fe08de5797a7efd5
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 23 12:19:12 2007 -0700

    [WIRELESS]: Refactor wireless Kconfig.
    
    This patch refactors the wireless Kconfig all over and already
    introduces net/wireless/Kconfig with just the WEXT bit for now,
    the cfg80211 patch will add to that as well.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 724c6b35ecff0fb68bbb315a34b2f9cb694865d3
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Apr 23 12:18:20 2007 -0700

    [WIRELESS]: Update MAINTAINERS for wireless mailing list.
    
    This patch adds the linux-wireless mailing list to all appropriate
    entries in the MAINTAINERS file.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 372cc74c8b41d808af0a3fa8b11795cba79e7299
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Sun Apr 22 23:22:24 2007 -0700

    [NET]: Prevent much sadness in qdisc_lock_tree().
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 97fc8d0bc58cd09e62dc06ea5a64b58841738934
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sat Apr 21 19:52:04 2007 -0700

    [IPV6] SNMP: Use put_unaligned() instead of memcpy().
    
    Hint from David Miller <davem@davemloft.net>.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 952a10be3272c4b5b7839b09cb0483dc72137101
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sat Apr 21 20:13:44 2007 +0900

    [IPV6] SNMP: Fix several warnings without procfs.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 2334e973559e119fa4161047035f03ad97a8676a
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sat Apr 21 20:12:43 2007 +0900

    [IPV6] SNMP: Avoid unaligned accesses.
    
    Because stats pointer may not be aligned for u64, use memcpy
    to fill u64 values.
    Issue reported by David Miller <davem@davemloft.net>.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit 9e412ba7632f71259a53085665d4983b78257b7c
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Fri Apr 20 22:18:02 2007 -0700

    [TCP]: Sed magic converts func(sk, tp, ...) -> func(sk, ...)
    
    This is (mostly) automated change using magic:
    
    sed -e '/struct sock \*sk/ N' -e '/struct sock \*sk/ N'
        -e '/struct sock \*sk/ N' -e '/struct sock \*sk/ N'
        -e 's|struct sock \*sk,[\n\t ]*struct tcp_sock \*tp\([^{]*\n{\n\)|
    	  struct sock \*sk\1\tstruct tcp_sock *tp = tcp_sk(sk);\n|g'
        -e 's|struct sock \*sk, struct tcp_sock \*tp|
    	  struct sock \*sk|g' -e 's|sk, tp\([^-]\)|sk\1|g'
    
    Fixed four unused variable (tp) warnings that were introduced.
    
    In addition, manually added newlines after local variables and
    tweaked function arguments positioning.
    
    $ gcc --version
    gcc (GCC) 4.1.1 20060525 (Red Hat 4.1.1-1)
    ...
    $ codiff -fV built-in.o.old built-in.o.new
    net/ipv4/route.c:
      rt_cache_flush |  +14
     1 function changed, 14 bytes added
    
    net/ipv4/tcp.c:
      tcp_setsockopt |   -5
      tcp_sendpage   |  -25
      tcp_sendmsg    |  -16
     3 functions changed, 46 bytes removed
    
    net/ipv4/tcp_input.c:
      tcp_try_undo_recovery |   +3
      tcp_try_undo_dsack    |   +2
      tcp_mark_head_lost    |  -12
      tcp_ack               |  -15
      tcp_event_data_recv   |  -32
      tcp_rcv_state_process |  -10
      tcp_rcv_established   |   +1
     7 functions changed, 6 bytes added, 69 bytes removed, diff: -63
    
    net/ipv4/tcp_output.c:
      update_send_head          |   -9
      tcp_transmit_skb          |  +19
      tcp_cwnd_validate         |   +1
      tcp_write_wakeup          |  -17
      __tcp_push_pending_frames |  -25
      tcp_push_one              |   -8
      tcp_send_fin              |   -4
     7 functions changed, 20 bytes added, 63 bytes removed, diff: -43
    
    built-in.o.new:
     18 functions changed, 40 bytes added, 178 bytes removed, diff: -138
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 38b4da383705394788aa09208917ba200792de4b
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Fri Apr 20 22:14:10 2007 -0700

    [NET]: Fix comments for register_netdev().
    
    Correct the function name in the comments supplied with
    register_netdev()
    
    Signed-off-by: Borislav Petkov <bbpetkov@yahoo.de>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b450777a572d68975c8748b0d48d517dd3468ea6
Author: G. Liakhovetski <gl@dsa-ac.de>
Date:   Fri Apr 20 22:12:48 2007 -0700

    [IrDA]: Misc spelling corrections.
    
    Spelling corrections, from "to" to "too".
    
    Signed-off-by: G. Liakhovetski <gl@dsa-ac.de>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 599b1fa91439cff8605a71f1a2b5bb42c177b667
Author: Samuel Ortiz <samuel@ortiz.org>
Date:   Fri Apr 20 22:12:07 2007 -0700

    [IrDA]: Adding carriage returns to mcs7780 debug statements
    
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c3ea9fa2741320f9cade15efe10559b549af4ebf
Author: Samuel Ortiz <samuel@ortiz.org>
Date:   Fri Apr 20 22:10:13 2007 -0700

    [IrDA] af_irda: IRDA_ASSERT cleanups
    
    In af_irda.c, the multiple IRDA_ASSERT() are either hiding bugs, useless, or
    returning the wrong value.
    Let's clean that up.
    
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d7f48d1a9398a3bd7bb6f4774640b24a0294cda3
Author: Samuel Ortiz <samuel@ortiz.org>
Date:   Fri Apr 20 22:09:33 2007 -0700

    [IrDA] af_irda: irda_accept cleanup
    
    This patch removes a cut'n'paste copy of wait_event_interruptible
    from irda_accept.
    
    Signed-off-by: Samuel Ortiz <samuel@ortiz.org>
    Acked-by: Olaf Kirch <olaf.kirch@oracle.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6e66aa15d8873ae7418d5afc6476daec466ff93b
Author: Olaf Kirch <olaf.kirch@oracle.com>
Date:   Fri Apr 20 22:08:15 2007 -0700

    [IrDA] af_irda: Silence kernel message in irda_recvmsg_stream
    
    This patch silences an IRDA_ASSERT in irda_recvmsg_stream, as described in
    http://bugzilla.kernel.org/show_bug.cgi?id=7512 irda_disconnect_indication
    would set sk->sk_err to ECONNRESET, and a subsequent call to recvmsg
    would print an irritating kernel message and return -1.
    
    When a connected socket is closed by the peer, recvmsg should return 0
    rather than an error. This patch fixes this.
    
    Signed-off-by: Olaf Kirch <olaf.kirch@oracle.com>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 305f2aa18214555e611ad05e586dd385e64ab665
Author: Olaf Kirch <olaf.kirch@oracle.com>
Date:   Fri Apr 20 22:05:27 2007 -0700

    [IrDA] af_irda: irda_recvmsg_stream cleanup
    
    This patch cleans up some code in irda_recvmsg_stream, replacing some
    homebrew code with prepare_to_wait/finish_wait, and by making the
    code honor sock_rcvtimeo.
    
    Signed-off-by: Olaf Kirch <olaf.kirch@oracle.com>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9958089a43ae8a9af07402461c0b2b7548c7341e
Author: Andi Kleen <ak@suse.de>
Date:   Fri Apr 20 17:12:43 2007 -0700

    [NET]: Move sk_setup_caps() out of line.
    
    It is far too large to be an inline and not in any hot paths.
    
    Signed-off-by: Andi Kleen <ak@suse.de>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4ac02bab77438b484a5cf855a002fb6a1d592894
Author: Andi Kleen <ak@suse.de>
Date:   Fri Apr 20 17:11:46 2007 -0700

    [TCP]: Uninline tcp_done().
    
    The function is quite big and has several call sites and nothing
    to collapse by compiler optimization on inlining.
    
    Besides it's nicer to read in a in .c file.
    
    Signed-off-by: Andi Kleen <ak@suse.de>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3ff50b7997fe06cd5d276b229967bb52d6b3b6c1
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Apr 20 17:09:22 2007 -0700

    [NET]: cleanup extra semicolons
    
    Spring cleaning time...
    
    There seems to be a lot of places in the network code that have
    extra bogus semicolons after conditionals.  Most commonly is a
    bogus semicolon after: switch() { }
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c462238d6a6d8ee855bda10f9fff442971540ed2
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Apr 20 17:07:51 2007 -0700

    [TCP]: TCP Illinois congestion control (rev3)
    
    This is an implementation of TCP Illinois invented by Shao Liu
    at University of Illinois. It is a another variant of Reno which adapts
    the alpha and beta parameters based on RTT. The basic idea is to increase
    window less rapidly as delay approaches the maximum. See the papers
    and talks to get a more complete description.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9be9a6b983314dd57e2c5ba548dee8b53d338ac3
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Apr 20 17:02:45 2007 -0700

    [NET]: Get rid of netdev_nit
    
    It isn't any faster to test a boolean global variable than do a simple
    check for empty list.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 42dc9cd54b7290f862874a2544e50395e5719985
Author: Michal Ostrowski <mostrows@earthlink.net>
Date:   Fri Apr 20 16:59:24 2007 -0700

    [PPPOE]: Fix device tear-down notification.
    
    pppoe_flush_dev() kicks all sockets bound to a device that is going down.
    In doing so, locks must be taken in the right order consistently (sock lock,
    followed by the pppoe_hash_lock).  However, the scan process is based on
    us holding the sock lock.  So, when something is found in the scan we must
    release the lock we're holding and grab the sock lock.
    
    This patch fixes race conditions between this code and pppoe_release(),
    both of which perform similar functions but would naturally prefer to grab
    locks in opposing orders.  Both code paths are now going after these locks
    in a consistent manner.
    
    pppoe_hash_lock protects the contents of the "pppox_sock" objects that reside
    inside the hash.  Thus, NULL'ing out the pppoe_dev field should be done
    under the protection of this lock.
    
    Signed-off-by: Michal Ostrowski <mostrows@earthlink.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 202a03acf9994076055df40ae093a5c5474ad0bd
Author: Florian Zumbiehl <florz@florz.de>
Date:   Fri Apr 20 16:58:14 2007 -0700

    [PPPOE]: memory leak when socket is release()d before PPPIOCGCHAN has been called on it
    
    below you find a patch that fixes a memory leak when a PPPoE socket is
    release()d after it has been connect()ed, but before the PPPIOCGCHAN ioctl
    ever has been called on it.
    
    This is somewhat of a security problem, too, since PPPoE sockets can be
    created by any user, so any user can easily allocate all the machine's
    RAM to non-swappable address space and thus DoS the system.
    
    Is there any specific reason for PPPoE sockets being available to any
    unprivileged process, BTW? After all, you need a packet socket for the
    discovery stage anyway, so it's unlikely that any unprivileged process
    will ever need to create a PPPoE socket, no? Allocating all session IDs
    for a known AC is a kind of DoS, too, after all - with Juniper ERXes,
    this is really easy, actually, since they don't ever assign session ids
    above 8000 ...
    
    Signed-off-by: Florian Zumbiehl <florz@florz.de>
    Acked-by: Michal Ostrowski <mostrows@earthlink.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 74b885cf86def9bc836772e3c1788c00b72a35c9
Author: Florian Zumbiehl <florz@florz.de>
Date:   Fri Apr 20 16:57:27 2007 -0700

    [PPPOE]: race between interface going down and connect()
    
    below you find a patch that (hopefully) fixes a race between an interface
    going down and a connect() to a peer on that interface. Before,
    connect() would determine that an interface is up, then the interface
    could go down and all entries referring to that interface in the
    item_hash_table would be marked as ZOMBIEs and their references to
    the device would be freed, and after that, connect() would put a new
    entry into the hash table referring to the device that meanwhile is
    down already - which also would cause unregister_netdevice() to wait
    until the socket has been release()d.
    
    This patch does not suffice if we are not allowed to accept connect()s
    referring to a device that we already acked a NETDEV_GOING_DOWN for
    (that is: all references are only guaranteed to be freed after
    NETDEV_DOWN has been acknowledged, not necessarily after the
    NETDEV_GOING_DOWN already). And if we are allowed to, we could avoid
    looking through the hash table upon NETDEV_GOING_DOWN completely and
    only do that once we get the NETDEV_DOWN ...
    
    mostrows:
    pppoe_flush_dev is called on NETDEV_GOING_DOWN and NETDEV_DOWN to deal with
    this "late connect" issue.  Ideally one would hope to notify users at the
    "NETDEV_GOING_DOWN" phase (just to pretend to be nice).  However, it is the
    NETDEV_DOWN scan that takes all the responsibility for ensuring nobody is
    hanging around at that time.
    
    Signed-off-by: Florian Zumbiehl <florz@florz.de>
    Acked-by: Michal Ostrowski <mostrows@earthlink.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bfafb26e11849fe99e03cc1902a91f7f65354e47
Author: Florian Zumbiehl <florz@florz.de>
Date:   Fri Apr 20 16:56:31 2007 -0700

    [PPPoE]: miscellaneous smaller cleanups
    
    below is a patch that just removes dead code/initializers without any
    effect (first access is an assignment) that I stumbled accross while
    reading the source.
    
    Signed-off-by: Florian Zumbiehl <florz@florz.de>
    Acked-by: Michal Ostrowski <mostrows@earthlink.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0c6fcc8a8cfcc737d05b6be8b2c3e931ef99cfc2
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Apr 20 16:40:01 2007 -0700

    [NET] skbuff: skb_store_bits const is backwards
    
    Getting warnings becuase skb_store_bits has skb as constant,
    but the function overwrites it. Looks like const was on the
    wrong side.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3e6cf558b0098a15d8c360c4eaad3e4d719a555a
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Apr 20 16:39:17 2007 -0700

    [BRIDGE]: Fix warning in net-2.6.22
    
    The following is leftover from earlier change in net-2.6.22.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 75606dc69adcfff433bca0ff747538d8495da0ab
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Fri Apr 20 16:06:45 2007 -0700

    [AX25/NETROM/ROSE]: Convert to use modern wait queue API
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 80feaacb8a6400a9540a961b6743c69a5896b937
Author: Peter P. Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Date:   Fri Apr 20 16:05:39 2007 -0700

    [AF_PACKET]: Add option to return orig_dev to userspace.
    
    Add a packet socket option to allow the orig_dev index to be returned
    to userspace when passing traffic through a decapsulated device, such
    as the bonding driver.
    
    This is very useful for layer 2 traffic being able to report which
    physical device actually received the traffic, instead of having the
    encapsulating device hide that information.
    
    The new option is called PACKET_ORIGDEV.
    
    Signed-off-by: Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1370b5a59b941ac3873b5e8614d496e9f481d670
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 20 15:57:45 2007 -0700

    [IPV6] SNMP: Export statistics via netlink without CONFIG_PROC_FS.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 334901700f9f58993ebd7f6136d3f9062460d34d
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 20 15:57:15 2007 -0700

    [IPV4] SNMP: Move some statistic bits to net/ipv4/proc.c.
    
    This also fixes memory leak in error path.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 49ed67a9eee3c756263feed4474e4fcf5c8eaed2
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 20 15:56:48 2007 -0700

    [IPV6] SNMP: Move some statistic bits to net/ipv6/proc.c.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bf99f1bde3b3009af74874f3465f6861431fbb66
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 20 15:56:20 2007 -0700

    [IPV6] SNMP: Netlink interface.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 628a5c561890a9a9a74dea017873530584aab06e
Author: John Heffner <jheffner@psc.edu>
Date:   Fri Apr 20 15:53:27 2007 -0700

    [INET]: Add IP(V6)_PMTUDISC_RPOBE
    
    Add IP(V6)_PMTUDISC_PROBE value for IP(V6)_MTU_DISCOVER.  This option forces
    us not to fragment, but does not make use of the kernel path MTU discovery.
    That is, it allows for user-mode MTU probing (or, packetization-layer path
    MTU discovery).  This is particularly useful for diagnostic utilities, like
    traceroute/tracepath.
    
    Signed-off-by: John Heffner <jheffner@psc.edu>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b881ef7603230550aa0150b22af94089f07ab00d
Author: John Heffner <jheffner@psc.edu>
Date:   Fri Apr 20 15:52:39 2007 -0700

    [IPV6]: MTU discovery check in ip6_fragment()
    
    Adds a check in ip6_fragment() mirroring ip_fragment() for packets
    that we can't fragment, and sends an ICMP Packet Too Big message
    in response.
    
    Signed-off-by: John Heffner <jheffner@psc.edu>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fd44de7cc1d430caef91ad9aecec9ff000fe86f8
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 16 17:07:08 2007 -0700

    [NET_SCHED]: ingress: switch back to using ingress_lock
    
    Switch ingress queueing back to use ingress_lock. qdisc_lock_tree now locks
    both the ingress and egress qdiscs on the device. All changes to data that
    might be used on both ingress and egress needs to be protected by using
    qdisc_lock_tree instead of manually taking dev->queue_lock. Additionally
    the qdisc stats_lock needs to be initialized to ingress_lock for ingress
    qdiscs.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0463d4ae25771aaf3379bb6b2392f6edf23c2828
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 16 17:02:10 2007 -0700

    [NET_SCHED]: Eliminate qdisc_tree_lock
    
    Since we're now holding the rtnl during the entire dump operation, we
    can remove qdisc_tree_lock, whose only purpose is to protect dump
    callbacks from concurrent changes to the qdisc tree.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ffa4d7216e848fbfdcb8e6f0bb66abeaa1888964
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Apr 25 14:01:17 2007 -0700

    [NETLINK]: don't reinitialize callback mutex
    
    Don't reinitialize the callback mutex the netlink_kernel_create caller
    handed in, it is supposed to already be initialized and could already
    be held by someone.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6313c1e0992feaee56bc09b85042b3186041fa3c
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 16 17:00:53 2007 -0700

    [RTNETLINK]: Remove unnecessary locking in dump callbacks
    
    Since we're now holding the rtnl during the entire dump operation, we can
    remove additional locking for rtnl protected data. This patch does that
    for all simple cases (dev_base_lock for dev_base walking, RCU protection
    for FIB rule dumping).
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1c2d670f3660e9103fdcdca702f6dbf8ea7d6afb
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 16 16:59:10 2007 -0700

    [RTNETLINK]: Hold rtnl_mutex during netlink dump callbacks
    
    Hold rtnl_mutex during the entire netlink dump operation. This allows
    to simplify locking in the dump callbacks, since they can now rely on
    that no concurrent changes happen.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit af65bdfce98d7965fbe93a48b8128444a2eea024
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Apr 20 14:14:21 2007 -0700

    [NETLINK]: Switch cb_lock spinlock to mutex and allow to override it
    
    Switch cb_lock to mutex and allow netlink kernel users to override it
    with a subsystem specific mutex for consistent locking in dump callbacks.
    All netlink_dump_start users have been audited not to rely on any
    side-effects of the previously used spinlock.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b076deb8498e26c9aa2f44046fe5e9936ae2fb5a
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Apr 12 22:17:05 2007 -0700

    [NETFILTER]: ipt_ULOG: add compat conversion functions
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d3a2c3ca8e7d908824701db978b936d115aea506
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Apr 12 22:16:38 2007 -0700

    [NETFILTER]: nfnetlink_log: remove fallback to group 0
    
    Don't fallback to group 0 if no instance can be found for the given group.
    This potentially confuses the listener and is not what the user configured.
    Also remove the ring buffer spamming that happens when rules are set up
    before the logging daemon is started.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3b5018d6766186474366f26cc87fba81407b9089
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Apr 12 22:16:18 2007 -0700

    [NETFILTER]: {eb,ip6,ip}t_LOG: remove remains of LOG target overloading
    
    All LOG targets always use their internal logging function nowadays, so
    remove the incorrect error message and handle real errors (!= -EEXIST)
    by failing to load.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fe6092ea0019cbba5263a915c9ce9f2bf383209e
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Apr 12 22:15:50 2007 -0700

    [NETFILTER]: nf_nat: use HW checksumming when possible
    
    When mangling packets forwarded to a HW checksumming capable device,
    offload recalculation of the checksum instead of doing it in software.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c15bf6e699f4c366f2d1e19ac5d7add21c6b5a19
Author: Bart De Schuymer <bdschuym@pandora.be>
Date:   Thu Apr 12 22:15:06 2007 -0700

    [NETFILTER]: ebt_arp: add gratuitous arp filtering
    
    The attached patch adds gratuitous arp filtering, more precisely: it
    allows checking that the IPv4 source address matches the IPv4
    destination address inside the ARP header. It also adds a check for the
    hardware address type when matching MAC addresses (nothing critical,
    just for better consistency).
    
    Signed-off-by: Bart De Schuymer <bdschuym@pandora.be>
    Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 516299d2f5b6f9703b9b388faf91898dc636a678
Author: Michael Milner <milner@blissisland.ca>
Date:   Thu Apr 12 22:14:23 2007 -0700

    [NETFILTER]: bridge-nf: filter bridged IPv4/IPv6 encapsulated in pppoe traffic
    
    The attached patch by Michael Milner adds support for using iptables and
    ip6tables on bridged traffic encapsulated in ppoe frames, similar to
    what's already supported for vlan.
    
    Signed-off-by: Michael Milner <milner@blissisland.ca>
    Signed-off-by: Bart De Schuymer <bdschuym@pandora.be>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 91d73c15cb165195bc8c3d6a35e30df454b1485b
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Fri Apr 20 13:57:21 2007 -0700

    [DCCP]: Complete documentation of dccp_sock
    
    This fills in missing documentation for dccp_sock fields.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f73f7097c986aab159491dcded7fc918e76e9ec3
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Fri Apr 20 13:56:47 2007 -0700

    [DCCP]: Debug statements for Elapsed Time option
    
    This prints the value of the parsed Elapsed Time when received via a
    Timestamp Echo option [RFC 4342, 13.3].
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b2449fdc30ccac550344df5e60d38bb8427b109c
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Fri Apr 20 13:02:55 2007 -0700

    [DCCP]: Fix bug in the calculation of very low sending rates
    
    This fixes an error in the calculation of t_ipi when X converges towards
    very low sending rates (between 1 and 64 bytes per second).
    
    Although this case may not sound likely, it can be reproduced by connecting,
    hitting enter (1 byte sent) and waiting for some time, during which the
    nofeedback timer halves the sending rate until finally it reaches the region
    1..64 bytes/sec. Computing X is handled correctly (tested separately); but by
    dividing X _before_ entering the calculation of t_ipi, X becomes zero as
    a result.  This in turn triggers a BUG condition caught in scaled_div().
    
    Fixed by replacing with equivalent statement and explicit typecast for good
    measure.
    
    Calculation verified and effect of patch tested - reduced never below 1 byte
    per 64 seconds afterwards, i.e. not allowing divide-by-zero.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cb8c181f288a1157bc717cc7a02412d4d1dc19bc
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Tue Apr 10 22:10:39 2007 -0700

    [S390]: Fix build on 31-bit.
    
    Allow s390 to properly override the generic
    __div64_32() implementation by:
    
    1) Using obj-y for div64.o in s390's makefile instead
       of lib-y
    
    2) Adding the weak attribute to the generic implementation.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit efd1e8d569b3d35a3a636683c2a9ebffec9c1fcf
Author: Patrick McHardy <kaber@trash.net>
Date:   Tue Apr 10 18:30:09 2007 -0700

    [SK_BUFF]: Fix missing offset adjustment in skb_copy_expand
    
    skb_copy_expand changes the headroom, so it needs to adjust the header
    offsets by the difference between the old and the new value.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 33036807b32d5ed1f4fdfe2d5e6bab2bb260b9f7
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue Apr 10 13:25:40 2007 -0700

    [NET]: loopback driver can use loopback_dev integrated net_device_stats
    
    Rusty added a new 'stats' field to struct net_device.
    
    loopback driver can use it instead of declaring another struct
    net_device_stats This saves some memory.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 87a596e0b8bc344bd6bfebe83b56d11fb79ee23a
Author: Akinobu Mita <akinobu.mita@gmail.com>
Date:   Sat Apr 7 18:57:07 2007 +0900

    bridge: check kmem_cache_create() error
    
    This patch checks kmem_cache_create() error and aborts loading module
    on failure.
    
    Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit ffe1d49cc300f3dff990093aa952a2fbb371c1b6
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 9 11:49:58 2007 -0700

    bridge: allow changing hardware address to any valid address
    
    For case of bridging pseudo devices, the get created/destroyed (Xen)
    need to allow setting address to any valid value.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit b86c45035c439cfa6ef5b2e4bf080b24bd8765f1
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 14:08:46 2007 -0700

    bridge: change when netlink events go to STP
    
    Need to tell STP daemon about more events, like any time a
    device is added even when it is down.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 9cde070874b822d4677f4f01fe146991785813b1
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Mar 21 14:22:44 2007 -0700

    bridge: add support for user mode STP
    
    This patchset based on work by Aji_Srinivas@emc.com provides allows
    spanning tree to be controled from userspace.  Like hotplug, it
    uses call_usermodehelper when spanning tree is enabled so there
    is no visible API change. If call to start usermode STP fails
    it falls back to existing kernel STP.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 9cf637473c8535b5abe27fee79254c2d552e042a
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Apr 9 12:57:54 2007 -0700

    bridge: add sysfs hook to flush forwarding table
    
    The RSTP daemon needs to be able to flush all dynamic forwarding
    entries in the case of topology change.
    
    This is a temporary interface. It will change to a netlink interface
    before RSTP daemon is officially released.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 3f890923182aeebc572f3818dd51c9014827e0ec
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Mar 21 13:42:33 2007 -0700

    bridge: simpler hash with salt
    
    Instead of hashing the whole Ethernet address, it should be faster
    to just use the last 4 bytes. Add a random salt value to the hash
    to make it more difficult to construct worst case DoS hash chains.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 467aea0ddfd1f0f1158c57cbef0e8941dd63374c
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Wed Mar 21 13:42:06 2007 -0700

    bridge: don't route packets while learning
    
    While in the STP learning state, don't route packets; wait until
    forwarding delay has expired. The purpose of the forwarding delay
    is to detect loops in the network, and if a brouter started up
    and started forwarding, it could cause a flood.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 6229e362dd49b9e8387126bd4483ab0574d23e9c
Author: Stephen Hemminger <shemminger@osdl.org>
Date:   Wed Mar 21 13:38:47 2007 -0700

    bridge: eliminate call by reference
    
    Change the bridging hook to be simple function with return value
    rather than modifying the skb argument. This could generate better
    code and is cleaner.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

commit 604763722c655c7e3f31ecf6f7b4dafcd26a7a15
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 9 11:59:39 2007 -0700

    [NET]: Treat CHECKSUM_PARTIAL as CHECKSUM_UNNECESSARY
    
    When a transmitted packet is looped back directly, CHECKSUM_PARTIAL
    maps to the semantics of CHECKSUM_UNNECESSARY.  Therefore we should
    treat it as such in the stack.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 628592ccdbbb5bb751217cf02e2e7abb500d7ffe
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 23 17:06:40 2007 -0700

    [NETDRV]: Perform missing csum_offset conversions
    
    When csum_offset was introduced we did a conversion from csum to
    csum_offset where applicable.  A couple of drivers were missed in
    this process.
    
    It was harmless to begin with since the two fields coincided.  Now
    that we've made them different with the addition of csum_start, the
    missed drivers must be converted or they can't send packets out at
    all that require checksum offload.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 663ead3bb8d5b561e70fc3bb3861c9220b5a77eb
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Apr 9 11:59:07 2007 -0700

    [NET]: Use csum_start offset instead of skb_transport_header
    
    The skb transport pointer is currently used to specify the start
    of the checksum region for transmit checksum offload.  Unfortunately,
    the same pointer is also used during receive side processing.
    
    This creates a problem when we want to retransmit a received
    packet with partial checksums since the skb transport pointer
    would be overwritten.
    
    This patch solves this problem by creating a new 16-bit csum_start
    offset value to replace the skb transport header for the purpose
    of checksums.  This offset is calculated from skb->head so that
    it does not have to change when skb->data changes.
    
    No extra space is required since csum_offset itself fits within
    a 16-bit word so we can use the other 16 bits for csum_start.
    
    For backwards compatibility, just before we push a packet with
    partial checksums off into the device driver, we set the skb
    transport header to what it would have been under the old scheme.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ac758e3c55c529714354fc268892ca4d23ca1e99
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 9 11:47:58 2007 -0700

    [XFRM]: beet: fix worst case header_len calculation
    
    esp_init_state doesn't account for the beet pseudo header in the header_len
    calculation, which may result in undersized skbs hitting xfrm4_beet_output,
    causing unnecessary reallocations in ip_finish_output2.
    
    The skbs should still always have enough room to avoid causing
    skb_under_panic in skb_push since we have at least 16 bytes available
    from LL_RESERVED_SPACE in xfrm_state_check_space.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c5c2523893747f88a83376abad310c8ad13f7197
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 9 11:47:18 2007 -0700

    [XFRM]: Optimize MTU calculation
    
    Replace the probing based MTU estimation, which usually takes 2-3 iterations
    to find a fitting value and may underestimate the MTU, by an exact calculation.
    
    Also fix underestimation of the XFRM trailer_len, which causes unnecessary
    reallocations.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 557922584d9c5b6b990bcfb2fec3134f0e73a05d
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 9 11:46:17 2007 -0700

    [XFRM]: esp: fix skb_tail_pointer conversion bug
    
    Fix incorrect switch of "trailer" skb by "skb" during skb_tail_pointer
    conversion:
    
    -       *(u8*)(trailer->tail - 1) = top_iph->protocol;
    +       *(skb_tail_pointer(skb) - 1) = top_iph->protocol;
    
    -       *(u8 *)(trailer->tail - 1) = *skb_network_header(skb);
    +       *(skb_tail_pointer(skb) - 1) = *skb_network_header(skb);
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 56eb88828b78f6f3b11a2996350092a40745301f
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Apr 9 11:45:04 2007 -0700

    [SK_BUFF]: Fix missing offset adjustment in pskb_expand_head
    
    Since we're increasing the headroom, the header offsets need to be
    increased by the same amount as well.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 29f6af7712c40045e7886d0fa356d97a6f9aba49
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Apr 6 11:45:39 2007 -0700

    [IPV6] FIB6RULE: Find source address during looking up route.
    
    When looking up route for destination with rules with
    source address restrictions, we may need to find a source
    address for the traffic if not given.
    
    Based on patch from Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ea2f10a3c81724701fe6a754789eafd50b33909f
Author: Patrick McHardy <kaber@trash.net>
Date:   Thu Apr 5 16:04:04 2007 -0700

    [XFRM]: beet: minor cleanups
    
    Remove unnecessary initialization/variable.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 038890fed8d1fa95bbbdeb517f5710eb75fa9e2e
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Apr 5 14:35:52 2007 -0700

    [RTNL]: Improve error codes for unsupported operations
    
    The most common trigger of these errors is that the
    config option hasn't been enable wich would make the
    functionality available. Therefore returning EOPNOTSUPP
    gives a better idea on what is going wrong.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 716ea3a7aae3a2bfc44cb97b5419c1c9868c7bc9
Author: David Howells <dhowells@redhat.com>
Date:   Mon Apr 2 20:19:53 2007 -0700

    [NET]: Move generic skbuff stuff from XFRM code to generic code
    
    Move generic skbuff stuff from XFRM code to generic code so that
    AF_RXRPC can use it too.
    
    The kdoc comments I've attached to the functions needs to be checked
    by whoever wrote them as I had to make some guesses about the workings
    of these functions.
    
    Signed-off-By: David Howells <dhowells@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 926554c4b74e53d5da4cefdc3bbd7e92427fb1a9
Author: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Date:   Sat Mar 31 12:05:49 2007 -0300

    [CREDITS]: Update Arnaldo entry
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>

commit 1a4e2d093fd5f3eaf8cffc04a1b803f8b0ddef6d
Author: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Date:   Sat Mar 31 11:55:45 2007 -0300

    [SK_BUFF]: Some more conversions to skb_copy_from_linear_data
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>

commit 27d7ff46a3498d3debc6ba68fb8014c702b81170
Author: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Date:   Sat Mar 31 11:55:19 2007 -0300

    [SK_BUFF]: Introduce skb_copy_to_linear_data{_offset}
    
    To clearly state the intent of copying to linear sk_buffs, _offset being a
    overly long variant but interesting for the sake of saving some bytes.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>

commit 3dbad80ac7632f243b824d469301abb97ec634a1
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Mar 29 19:16:03 2007 -0700

    [NET]: Fix warnings in 3c523.c and ni52.c
    
    We have to put back the cast to "char *" because these
    pointers are volatile.
    
    Reported by Andrew Morton.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c45d286e72dd72c0229dc9e2849743ba427fee84
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Wed Mar 28 14:29:08 2007 -0700

    [NET]: Inline net_device_stats
    
    Network drivers which keep stats allocate their own stats structure
    then write a get_stats() function to return them.  It would be nice if
    this were done by default.
    
    1) Add a new "stats" field to "struct net_device".
    2) Add a new feature field to say "this driver uses the internal one"
    3) Have a default "get_stats" which returns NULL if that feature not set.
    4) Change callers to check result of get_stats call for NULL, not if
       ->get_stats is set.
    
    This should not break backwards compatibility with older drivers, yet
    allow modern drivers to shed some boilerplate code.
    
    Lightly tested: works for a modified lguest network driver.
    
    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f85958151900f9d30fa5ff941b0ce71eaa45a7de
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Wed Mar 28 14:22:33 2007 -0700

    [NET]: random functions can use nsec resolution instead of usec
    
    In order to get more randomness for secure_tcpv6_sequence_number(),
    secure_tcp_sequence_number(), secure_dccp_sequence_number() functions,
    we can use the high resolution time services, providing nanosec
    resolution.
    
    I've also done two kmalloc()/kzalloc() conversions.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Acked-by: James Morris <jmorris@namei.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4b19ca44cbafabfe0b7b98e2e24b21a96198f509
Author: Thomas Graf <tgraf@suug.ch>
Date:   Wed Mar 28 14:18:52 2007 -0700

    [NET] fib_rules: delay route cache flush by ip_rt_min_delay
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d626f62b11e00c16e81e4308ab93d3f13551812a
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 27 18:55:52 2007 -0300

    [SK_BUFF]: Introduce skb_copy_from_linear_data{_offset}
    
    To clearly state the intent of copying from linear sk_buffs, _offset being a
    overly long variant but interesting for the sake of saving some bytes.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit 2a123b86e2b242a4a6db990d2851d45e192f88e5
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 27 18:38:07 2007 -0300

    [BLUETOOTH]: Introduce skb->data accessor methods for hci_{acl,event,sco}_hdr
    
    For consistency with other skb data accessors, reducing the number of direct
    accesses to skb->data.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit 03d4f879b9ddf7d5c1f788792247e62450342eed
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue Mar 27 14:18:34 2007 -0700

    [IPV4]: align inet_protos[] on SMP
    
    As IPPROTO_TCP is 6, it makes sense to make sure inet_protos[] array
    is properly cache line aligned to avoid false sharing on SMP.
    
    c0680540 b peer_total
    c0680544 b inet_peer_unused_head
    c0680560 B inet_protos
    
    On i386 this example, we can see that inet_protos[IPPROTO_TCP] shares
    a potentially hot (and modified) cache line.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4103f8cd5c1f260d674a7b426ed221812de54d47
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue Mar 27 13:58:31 2007 -0700

    [TCP]: tcp_memory_pressure and tcp_socket are__read_mostly candidates
    
    tcp_memory_pressure and tcp_socket currently share a cache line with tcp_memory_allocated, tcp_sockets_allocated.
    (Very hot cache line)
    It makes sense to declare these variables as __read_mostly, to avoid false sharing on SMP.
    
    ffffffff8081d9c0 B tcp_orphan_count
    ffffffff8081d9c4 B tcp_memory_allocated
    ffffffff8081d9c8 B tcp_sockets_allocated
    ffffffff8081d9cc B tcp_memory_pressure
    ffffffff8081d9d0 b tcp_md5sig_users
    ffffffff8081d9d8 b tcp_md5sig_pool
    ffffffff8081d9e0 b warntime.31570
    ffffffff8081d9e8 b tcp_socket
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 73417f617a93cf30342c3ea41abc38927bd467aa
Author: Thomas Graf <tgraf@suug.ch>
Date:   Tue Mar 27 13:56:52 2007 -0700

    [NET] fib_rules: Flush route cache after rule modifications
    
    The results of FIB rules lookups are cached in the routing cache
    except for IPv6 as no such cache exists. So far, it was the
    responsibility of the user to flush the cache after modifying any
    rules. This lead to many false bug reports due to misunderstanding
    of this concept.
    
    This patch automatically flushes the route cache after inserting
    or deleting a rule.
    
    Thanks to Muli Ben-Yehuda <muli@il.ibm.com> for catching a bug
    in the previous patch.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit be776281aee54626a474ba06f91926b98bdd180d
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue Mar 27 13:53:04 2007 -0700

    [NET]: inet_ehash_secret should be __read_mostly and set only once
    
    There is a very tiny probability that build_ehash_secret() is called
    at the same time by different CPUS.
    
    Also, using __read_mostly is a must for inet_ehash_secret
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 35fc92a9deee0da6e35fdc3150bb134e58f2fd63
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Mon Mar 26 23:22:20 2007 -0700

    [NET]: Allow forwarding of ip_summed except CHECKSUM_COMPLETE
    
    Right now Xen has a horrible hack that lets it forward packets with
    partial checksums.  One of the reasons that CHECKSUM_PARTIAL and
    CHECKSUM_COMPLETE were added is so that we can get rid of this hack
    (where it creates two extra bits in the skbuff to essentially mirror
    ip_summed without being destroyed by the forwarding code).
    
    I had forgotten that I've already gone through all the deivce drivers
    last time around to make sure that they're looking at ip_summed ==
    CHECKSUM_PARTIAL rather than ip_summed != 0 on transmit.  In any case,
    I've now done that again so it should definitely be safe.
    
    Unfortunately nobody has yet added any code to update CHECKSUM_COMPLETE
    values on forward so we I'm setting that to CHECKSUM_NONE.  This should
    be safe to remove for bridging but I'd like to check that code path
    first.
    
    So here is the patch that lets us get rid of the hack by preserving
    ip_summed (mostly) on forwarded packets.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2d771cd86d4c3af26f34a7bcdc1b87696824cad9
Author: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Date:   Mon Mar 26 18:03:44 2007 -0700

    [IPV4] LVS: Allow to send ICMP unreachable responses when real-servers are removed
    
    this is a small patch by Janusz Krzysztofik to ip_route_output_slow()
    that allows VIP-less LVS linux director to generate packets
    originating >From VIP if sysctl_ip_nonlocal_bind is set.
    
    In a nutshell, the intention is for an LVS linux director to be able
    to send ICMP unreachable responses to end-users when real-servers are
    removed.
    
    http://archive.linuxvirtualserver.org/html/lvs-users/2007-01/msg00106.html
    
    Signed-off-by: Simon Horman <horms@verge.net.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fa0b2d1d2196dd46527a8d028797e2bca5930a92
Author: Thomas Graf <tgraf@suug.ch>
Date:   Mon Mar 26 17:38:53 2007 -0700

    [NET] fib_rules: Add no-operation action
    
    The use of nop rules simplifies the usage of goto rules
    and adds more flexibility as they allow targets to remain
    while the actual content of the branches can change easly.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2b44368307cd06c5614d7b53801f516c0654020b
Author: Thomas Graf <tgraf@suug.ch>
Date:   Mon Mar 26 17:37:59 2007 -0700

    [NET] fib_rules: Mark rules detached from the device
    
    Rules which match against device names in their selector can
    remain while the device itself disappears, in fact the device
    doesn't have to present when the rule is added in the first
    place. The device name is resolved by trying when the rule is
    added and later by listening to NETDEV_REGISTER/UNREGISTER
    notifications.
    
    This patch adds the flag FIB_RULE_DEV_DETACHED which is set
    towards userspace when a rule contains a device match which
    is unresolved at the moment. This eases spotting the reason
    why certain rules seem not to function properly.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0947c9fe56d9cf7ad0bc3a03ccd30446cde698e4
Author: Thomas Graf <tgraf@suug.ch>
Date:   Mon Mar 26 17:14:15 2007 -0700

    [NET] fib_rules: goto rule action
    
    This patch adds a new rule action FR_ACT_GOTO which allows
    to skip a set of rules by jumping to another rule. The rule
    to jump to is specified via the FRA_GOTO attribute which
    carries a rule preference.
    
    Referring to a rule which doesn't exists is explicitely allowed.
    Such goto rules are marked with the flag FIB_RULE_UNRESOLVED
    and will act like a rule with a non-matching selector. The rule
    will become functional as soon as its target is present.
    
    The goto action enables performance optimizations by reducing
    the average number of rules that have to be passed per lookup.
    
    Example:
    0:      from all lookup local
    40:     not from all to 192.168.23.128 goto 32766
    41:     from all fwmark 0xa blackhole
    42:     from all fwmark 0xff blackhole
    32766:  from all lookup main
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2f7826c02447480c7c1b5500b34fc783f1ed8145
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Mon Mar 26 02:00:58 2007 -0700

    [WAN] cosa.c: Build fix.
    
    Caused by skb_reset_mac_header() changes, missing semicolon.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 85795d64eddd4546375f5ee37bedd88cb5bc4ece
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sat Mar 24 21:35:33 2007 -0700

    [TCP] tcp_probe: improvements for net-2.6.22
    
    Change tcp_probe to use ktime (needed to add one export).
    Add option to only get events when cwnd changes - from Doug Leith
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e1c3e7ab6de9711d2e0e9daf369c6638582eb7e7
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sat Mar 24 21:34:38 2007 -0700

    [TCP]: cubic update for net-2.6.22
    
    The following update received from Injong updates TCP cubic to the latest
    version. I am running more complete tests and will have results after 4/1.
    
    According to Injong: the new version improves on its scalability,
    fairness and stability.  So in all properties, we confirmed it shows better
    performance.
    
    NCSU results (for 2.6.18 and 2.6.20) available:
    	http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_Testing
    
    This version is described in a new Internet draft for CUBIC.
    	http://www.ietf.org/internet-drafts/draft-rhee-tcp-cubic-00.txt
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9af3912ec9e30509b76cb376abb65a4d8af27df3
Author: John Heffner <jheffner@psc.edu>
Date:   Sun Mar 25 23:32:29 2007 -0700

    [NET] Move DF check to ip_forward
    
    Do fragmentation check in ip_forward, similar to ipv6 forwarding.
    
    Signed-off-by: John Heffner <jheffner@psc.edu>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b3da2cf37c5c6e47698957a25ab43a7223dbb90f
Author: David S. Miller <davem@davemloft.net>
Date:   Fri Mar 23 11:40:27 2007 -0700

    [INET]: Use jhash + random secret for ehash.
    
    The days are gone when this was not an issue, there are folks out
    there with huge bot networks that can be used to attack the
    established hash tables on remote systems.
    
    So just like the routing cache and connection tracking
    hash, use Jenkins hash with random secret input.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d30045a0bcf144753869175dd9d840f7ceaf4aba
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Fri Mar 23 11:37:48 2007 -0700

    [NETLINK]: introduce NLA_BINARY type
    
    This patch introduces a new NLA_BINARY attribute policy type with the
    verification of simply checking the maximum length of the payload.
    
    It also fixes a small typo in the example.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 703315712cfccfe0b45ef4aa6994527d8ee95e33
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Mar 23 11:34:36 2007 -0700

    [SCTP]: Implement SCTP_MAX_BURST socket option.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a5a35e76753d27e782028843a5186f176b50dd16
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Mar 23 11:34:08 2007 -0700

    [SCTP]: Implement sac_info field in SCTP_ASSOC_CHANGE notification.
    
    As stated in the sctp socket api draft:
    
       sac_info: variable
    
       If the sac_state is SCTP_COMM_LOST and an ABORT chunk was received
       for this association, sac_info[] contains the complete ABORT chunk as
       defined in the SCTP specification RFC2960 [RFC2960] section 3.3.7.
    
    We now save received ABORT chunks into the sac_info field and pass that
    to the user.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bdf3092af601ccad765974652ab103162fbe14f4
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Mar 23 11:33:12 2007 -0700

    [SCTP]: Honor flags when setting peer address parameters
    
    Parameters only take effect when a corresponding flag bit is set
    and a value is specified. This means we need to check the flags
    in addition to checking for non-zero value.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1ae4114dce35dd1d32ed847f60b599dbbdfd5829
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Mar 23 11:32:26 2007 -0700

    [SCTP]: Implement SCTP_ADDR_CONFIRMED state for ADDR_CHNAGE event
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d49d91d79a8dc5e85108a5ae1c8eef23dec135c1
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Mar 23 11:32:00 2007 -0700

    [SCTP]: Implement SCTP_PARTIAL_DELIVERY_POINT option.
    
    This option induces partial delivery to run as soon
    as the specified amount of data has been accumulated on
    the association.  However, we give preference to fully
    reassembled messages over PD messages.  In any case,
    window and buffer is freed up.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@.hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b6e1331f3ce25a56edb956054eaf8011654686cb
Author: Vlad Yasevich <vladislav.yasevich@hp.com>
Date:   Fri Apr 20 12:23:15 2007 -0700

    [SCTP]: Implement SCTP_FRAGMENT_INTERLEAVE socket option
    
    This option was introduced in draft-ietf-tsvwg-sctpsocket-13.  It
    prevents head-of-line blocking in the case of one-to-many endpoint.
    Applications enabling this option really must enable SCTP_SNDRCV event
    so that they would know where the data belongs.  Based on an
    earlier patch by Ivan Skytte JÃ¸rgensen.
    
    Additionally, this functionality now permits multiple associations
    on the same endpoint to enter Partial Delivery.  Applications should
    be extra careful, when using this functionality, to track EOR indicators.
    
    Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c95e939508e64863a1c5c73a9e1a908784e06820
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:30:04 2007 -0700

    [NET_SCHED]: qdisc: remove unnecessary memory barriers
    
    We're holding dev->queue_lock in qdisc_watchdog_schedule and
    qdisc_watchdog_cancel, no need for the barriers.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a48b5a61448899040dfbd2e0cd55b06a2bd2466c
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:29:43 2007 -0700

    [NET_SCHED]: Unline tcf_destroy
    
    Uninline tcf_destroy and add a helper function to destroy an entire filter
    chain.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3bebcda28077375470dd60545b71bba2f83335fd
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:29:25 2007 -0700

    [NET_SCHED]: turn PSCHED_GET_TIME into inline function
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 03cc45c0a5b9b7f74768feb43b9a2525d203bbdb
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:29:11 2007 -0700

    [NET_SCHED]: turn PSCHED_TDIFF_SAFE into inline function
    
    Also rename to psched_tdiff_bounded.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8edc0c31d6b7849b0fb50db86824830769241939
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:28:55 2007 -0700

    [NET_SCHED]: kill PSCHED_TDIFF
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a084980dcbf56c896e4b6c19aff2b082d5db7006
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:28:30 2007 -0700

    [NET_SCHED]: kill PSCHED_SET_PASTPERFECT/PSCHED_IS_PASTPERFECT
    
    Use direct assignment and comparison instead.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 104e0878984bb467e3f54d61105d8903babb4ec1
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:28:07 2007 -0700

    [NET_SCHED]: kill PSCHED_TLESS
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7c59e25f3186f26e85b13a318dbc4482d1d363e9
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:27:45 2007 -0700

    [NET_SCHED]: kill PSCHED_TADD/PSCHED_TADD2
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 26e252df1e6e5b68eb790e4a4baf745aa3870038
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:27:29 2007 -0700

    [NET_SCHED]: kill PSCHED_AUDIT_TDIFF
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 76d643cd3bd2b4a1e27e3eafee8e37be9c681792
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:27:04 2007 -0700

    [NET_SCHED]: sch_netem: fix off-by-one in send time comparison
    
    netem checks PSCHED_TLESS(cb->time_to_send, now) to find out whether it is
    allowed to send a packet, which is equivalent to cb->time_to_send < now.
    Use !PSCHED_TLESS(now, cb->time_to_send) instead to properly handle
    cb->time_to_send == now.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c7bf5f9dc2f78ae8ebbfffc5f17becd0d9e6ba9e
Author: Thomas Graf <tgraf@suug.ch>
Date:   Fri Mar 23 11:17:57 2007 -0700

    [NETFILTER] nfnetlink: netlink_run_queue() already checks for NLM_F_REQUEST
    
    Patrick has made use of netlink_run_queue() in nfnetlink while my patches
    have been waiting for net-2.6.22 to open. So this check for NLM_F_REQUEST
    can go as well.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit de6e05c49f8b4ed63224c5d38891f531ecc4eabb
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Fri Mar 23 11:17:27 2007 -0700

    [NETFILTER]: nf_conntrack: kill destroy() in struct nf_conntrack for diet
    
    The destructor per conntrack is unnecessary, then this replaces it with
    system wide destructor.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5f79e0f916a3bdeccc910fdf466bca582a9b2cca
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Fri Mar 23 11:17:07 2007 -0700

    [NETFILTER]: nf_conntrack: don't use nfct in skb if conntrack is disabled
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e6f689db51a789807edede411b32eb7c9e457948
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:16:30 2007 -0700

    [NETFILTER]: Use setup_timer
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9afdb00c80b0b9c20435ce690b5287fa2434ef44
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:12:50 2007 -0700

    [NETFILTER]: nfnetlink_log: remove conditional locking
    
    This is gross, have the wrapper function take the lock.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 370e6a878962cad614eb8c7c5a22240e5cd316bb
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:12:21 2007 -0700

    [NETFILTER]: nfnetlink_log: micro-optimization: inst->skb != NULL in __nfulnl_send()
    
    No other function calls __nfulnl_send() with inst->skb == NULL than
    nfulnl_timer().
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f76cdcee5ba4a3fb41de93d5f1c17fb6ab4d0820
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:12:03 2007 -0700

    [NETFILTER]: nfnetlink_log: iterator functions need iter_state * only
    
    get_*() don't need access to seq_file - iter_state is enough for them.
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9a36e8c2b337c424ed77f5dea0a67dc8039d351b
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:11:48 2007 -0700

    [NETFILTER]: nfnetlink_log: micro-optimization: don't modify destroyed instance
    
    Simple micro-optimization: Don't change any options if the instance is
    being destroyed.
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f414c16c04b1c998e90370791f9a728e292146ea
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:11:31 2007 -0700

    [NETFILTER]: nfnetlink_log: micro-optimization for inst==NULL in nfulnl_recv_config()
    
    Simple micro-optimization: don't call instance_put() on known NULL pointers.
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 55b5a91e1723280570957990a0c5ab8c3ec4090a
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:11:05 2007 -0700

    [NETFILTER]: nfnetlink_log: kill duplicate code
    
    Kill some duplicate code in nfulnl_log_packet().
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 09972d6f968d67dd82cbd403d5aa42c241a8d0cb
Author: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
Date:   Fri Mar 23 11:10:47 2007 -0700

    [NETFILTER]: nfnetlink_log: don't count max(a,b) twice
    
    We don't need local nlbufsiz (skb size) as nfulnl_alloc_skb() takes
    the maximum anyway.
    
    Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1b53d9042c04b8eb875d02e65792e9884efc3784
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 23 11:10:13 2007 -0700

    [NETFILTER]: Remove changelogs and CVS IDs
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bb2f8cc0ecf025d6d3947e0389434650023f432e
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Fri Mar 23 00:12:09 2007 -0700

    [NETEM]: spelling errors
    
    Get rid of some of my creative spelling.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c702e8047fe74648f7852a9c1de781b0d5a98402
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:30:55 2007 -0700

    [NETLINK]: Directly return -EINTR from netlink_dump_start()
    
    Now that all users of netlink_dump_start() use netlink_run_queue()
    to process the receive queue, it is possible to return -EINTR from
    netlink_dump_start() directly, therefore simplying the callers.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ead592ba246dfcc643b3f0f0c8c03f7bc898a59f
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:30:35 2007 -0700

    [IPv4] diag: Use netlink_run_queue() to process the receive queue
    
    Makes use of netlink_run_queue() to process the receive queue and
    converts inet_diag_rcv_msg() to use the type safe netlink interface.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1d00a4eb42bdade33a6ec0961cada93577a66ae6
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:30:12 2007 -0700

    [NETLINK]: Remove error pointer from netlink message handler
    
    The error pointer argument in netlink message handlers is used
    to signal the special case where processing has to be interrupted
    because a dump was started but no error happened. Instead it is
    simpler and more clear to return -EINTR and have netlink_run_queue()
    deal with getting the queue right.
    
    nfnetlink passed on this error pointer to its subsystem handlers
    but only uses it to signal the start of a netlink dump. Therefore
    it can be removed there as well.
    
    This patch also cleans up the error handling in the affected
    message handlers to be consistent since it had to be touched anyway.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 45e7ae7f716086994e4e747226881f901c67b031
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:29:10 2007 -0700

    [NETLINK]: Ignore control messages directly in netlink_run_queue()
    
    Changes netlink_rcv_skb() to skip netlink controll messages and don't
    pass them on to the message handler.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d35b685640aeb39eb4f5e98c75e8e001e406f9a3
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:28:46 2007 -0700

    [NETLINK]: Ignore !NLM_F_REQUEST messages directly in netlink_run_queue()
    
    netlink_rcv_skb() is changed to skip messages which don't have the
    NLM_F_REQUEST bit to avoid every netlink family having to perform this
    check on their own.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 33a0543cd9e090d2c6759e0ed85c3049c6efcc06
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:27:39 2007 -0700

    [NETLINK]: Remove unused groups variable
    
    Leftover from dynamic multicast groups allocation work.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 267281058c4cfd6a9a173aa957bffa58239f9656
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:27:19 2007 -0700

    [TCP] westwood: Use type safe netlink interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e9195d677d6f06730edd5c2a3fe3283564e39c51
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 23:27:01 2007 -0700

    [TCP] vegas: Use type safe netlink interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 51057f2fecff1c520b083c5ac9229e7aebce9e01
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 21:41:06 2007 -0700

    [RTNL]: Properly return rntl message handler
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1936502d00ae6c2aa3931c42f6cf54afaba094f2
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:18:35 2007 -0700

    [NET_SCHED] qdisc: avoid transmit softirq on watchdog wakeup
    
    If possible, avoid having to do a transmit softirq when a qdisc
    watchdog decides to re-enable.  The watchdog routine runs off
    a timer, so it is already in the same effective context as
    the softirq.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 11274e5a43266d531140530adebead6903380caf
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:17:42 2007 -0700

    [NETEM]: avoid excessive requeues
    
    The netem code would call getnstimeofday() and dequeue/requeue after
    every packet, even if it was waiting. Avoid this overhead by using
    the throttled flag.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 075aa573b74a732aeff487ab77d3fbd627c10856
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:17:05 2007 -0700

    [NETEM]: Optimize tfifo
    
    In most cases, the next packet will be sent after the
    last one. So optimize that case.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b407621c35ed5f9a0734e57472e9539117963768
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:16:21 2007 -0700

    [NETEM]: use better types for time values
    
    The random number generator always generates 32 bit values.
    The time values are limited by psched_tdiff_t
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:15:45 2007 -0700

    [NETEM]: report reorder percent correctly.
    
    If you setup netem to just delay packets; "tc qdisc ls" will report
    the reordering as 100%. Well it's a lie, reorder isn't used unless
    gap is set, so just set value to 0 so the output of utility
    is correct.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7e58886b45bc4a309aeaa8178ef89ff767daaf7f
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:10:58 2007 -0700

    [TCP]: cubic optimization
    
    Use willy's work in optimizing cube root by having table for small values.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 22b9a0a3a49ab1a856e0853b3f3dd2abd156bd7c
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 22 12:10:18 2007 -0700

    [LIB]: div64_64 optimization
    
    Minor optimization of div64_64.  do_div() already does optimization
    for the case of 32 by 32 divide, so no need to do it here.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c454673da7c1d6533f40ec2f788023df9af56ebf
Author: Thomas Graf <tgraf@suug.ch>
Date:   Sun Mar 25 23:24:24 2007 -0700

    [NET] rules: Unified rules dumping
    
    Implements a unified, protocol independant rules dumping function
    which is capable of both, dumping a specific protocol family or
    all of them. This speeds up dumping as less lookups are required.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 687ad8cc640fd1f1619cc44a9ab274dabd48c758
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:59:42 2007 -0700

    [RTNL]: Use rtnl registration interface for dump-all aliases
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 32fe21c0c0a3091552fea8f2f7e4905f547a3433
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:59:03 2007 -0700

    [BRIDGE]: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c127ea2c45d1b13a672fde254679721bb282e90a
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:58:32 2007 -0700

    [IPv6]: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fa34ddd739cecf3999ec0b7562618e8321829d41
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:57:46 2007 -0700

    [DECNet]: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Acked-by: Steven Whitehouse <swhiteho@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 708914cc5e1657eb1a1f9eefc6333dfd2df8c73a
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:56:59 2007 -0700

    [PKT_SCHED] act: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 82623c0d73bd111cad26e501e509966b2455b0e0
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:56:22 2007 -0700

    [PKT_SCHED] cls: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit be577ddc2b4aca0849f701222f5bc13cf1b79c9a
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:55:50 2007 -0700

    [PKT_SCHED] qdisc: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 63f3444fb9a54c024d55f1205f8b94e7d2786595
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:55:17 2007 -0700

    [IPv4]: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9d9e6a5819230b5a5cc036f213135cb123ab1e50
Author: Thomas Graf <tgraf@suug.ch>
Date:   Sun Mar 25 23:20:05 2007 -0700

    [NET] rules: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c8822a4e00442e65d42d50db8e529d75c2025630
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:50:06 2007 -0700

    [NEIGH]: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 340d17fc9d577c93678850e46963e9b19b92db7e
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:49:22 2007 -0700

    [NET] link: Use rtnl registration interface
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e284986385b6420a5f30f2dcd743512bbe1a3202
Author: Thomas Graf <tgraf@suug.ch>
Date:   Thu Mar 22 11:48:11 2007 -0700

    [RTNL]: Message handler registration interface
    
    This patch adds a new interface to register rtnetlink message
    handlers replacing the exported rtnl_links[] array which
    required many message handlers to be exported unnecessarly.
    
    Signed-off-by: Thomas Graf <tgraf@suug.ch>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 30833ffead66e1f0052150a51db0b45151189ac1
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:31:56 2007 -0300

    [CCID3]: Use initial RTT sample from SYN exchange
    
    The patch follows the following recommendation made in an erratum to RFC 4342:
    
      "Senders MAY additionally make use of other available RTT measurements,
       including those from the initial Request-Response packet exchange."
    
    It implements larger initial windows with regard to this inital RTT measurement,
    using the mechanism suggested in draft-ietf-dccp-rfc3448bis, section 4.2.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 89560b53b92a07c529e13a462aa7fd87a844f1f5
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:27:17 2007 -0300

    [DCCP]: Sample RTT from SYN exchange
    
    Function:

commit 7dfee1a9c07f80a82aa5fbad340146f2b5c794b4
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:24:37 2007 -0300

    [CCID3]: Use function for RTT sampling
    
    This replaces the existing occurrences of RTT sampling with
    the use of the new function dccp_sample_rtt.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4712a792ee661921374c163eb6a4d06e33fd305f
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:23:18 2007 -0300

    [DCCP]: Provide function for RTT sampling
    
    A recurring problem, in particular in the CCID code, is that RTT samples
    from packets with timestamp echo and elapsed time options need to be taken.
    
    This service is provided via a new function dccp_sample_rtt in this patch.
    Furthermore, to protect against `insane' RTT samples, the sampled value
    is bounded between 100 microseconds and 4 seconds - for which u32 is sufficient.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0c150efb280986db7958cf2a559b91d826241e59
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:19:07 2007 -0300

    [CCID3]: Handle Idle and Application-Limited periods
    
    This updates the code with regard to handling idle and application-limited
    periods as specified in [RFC 4342, 5.1].
    
    Background:

commit a21f9f96cd035b0d9aec32d80ea0152672fbed42
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:12:10 2007 -0300

    [CCID3]: Wrap computation of RFC3390-initial rate into separate function
    
    The CCID 3 and TFRC specs (RFC 4342, RFC 3448, draft-3448bis) make frequent
    reference to the computation of the RFC-3390 initial sending rate:
    
      1. Initial sending rate when RTT is known (RFC 4342, p. 6)
      2. Response to Idle/Application-Limited periods (RFC 4342, 5.1)
    
    This warrants putting the code into its own function, for later code reuse.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1761f7d7fea32c2290710f5c0afa0c3d93220593
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:04:30 2007 -0300

    [CCID3]: Remove build warnings for 64bit
    
    This clears the following sparc64 build warnings:
     1) warning: format "%ld" expects type "long int", but argument 3 has type "suseconds_t"
     2) warning: format "%llu" expects type "long long unsigned int", but argument 3 has type "__u64"
    Fixed by using typecast to unsigned. This is argued to be safe, since the quantities, after
    de-scaling (factor 2^6) fit all in u32.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fddc2feb94c1f734dc27d44d166e97ab2e005ec1
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:02:10 2007 -0300

    [CCID3]: More to see in dccp_probe
    
    This adds a few more fields of interest to /proc/net/dccpprobe, the following output ensues:
    
    1           2          3           4     5  6     7   8        9        10   11
    sec.usec   src:sport   dst:dport   size  s  rtt   p   X_calc   X_recv   X    t_ipi
    
    Also made the formatting consistent.
    
    Scripts that go with this can be downloaded from http://139.133.210.30/users/gerrit/dccp/dccp_probe/
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f2645101350c6db66f0a1e72648909cc411f2b38
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:01:14 2007 -0300

    [CCID3]: Add documentation for socket options
    
    This updates the documentation on CCID3-specific options.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6626e3628fe42837f733d103e194c6b4473d8669
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 15:00:28 2007 -0300

    [DCCP]: More debug information for dccp_wait_for_ccid
    
    This adds more detail in the wait_for_ccid packet scheduling loop.
    In particular, it informs about (i) when delay is used and (ii) why
    a packet is discarded.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ac12b0c49571fe4c3a2f4957ed494da316d558be
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 14:59:23 2007 -0300

    [DCCP]: Always use debug-toggle parameters
    
    Currently debugging output (when configured) is automatically enabled when
    DCCP modules are compiled into the kernel rather than built as loadable modules.
    This is not necessary, since the module parameters in this case become kernel
    commandline parameters, e.g. DCCP or CCID3 debug output can be enabled for a
    static build by appending the following at the boot prompt:
    
    	dccp.dccp_debug=1 	dccp_ccid3.ccid3_debug=1
    
    This patch therefore does away with the more complicated way of always enabling
    debug output for static builds
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1266adee12d25385a25e1c57b1e3ff05a90bb4d7
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 14:56:11 2007 -0300

    [CCID3]: Remove race condition and update t_ipi when `s' changes
    
    This:
    
     1. removes a race condition in the access to the scheduled send time t_nom which
        results from allowing asynchronous r/w access to t_nom without locks;
    
     2. updates the inter-packet interval t_ipi = s/X when `s' changes, following a
        suggestion by Ian McDonald.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8699be7d240e37c91a84bdf32e79941d72bc7bd5
Author: Ian McDonald <ian.mcdonald@jandi.co.nz>
Date:   Tue Mar 20 14:49:20 2007 -0300

    [CCID3]: More verbose debugging
    
    This adds a few debugging statements to ccid3.c
    
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 551dc5f7a11cfb66685bfd36cbbdb209c5a11d14
Author: Ian McDonald <ian.mcdonald@jandi.co.nz>
Date:   Tue Mar 20 14:46:52 2007 -0300

    [CCID3]: Fix use of invalid loss intervals
    
    This fixes a bug which uses an invalid comparison.
    The bug resulted in the use of invalid loss intervals.
    
    Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Acked-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 371fe7779cad6557a58df9a1b5543652e067400f
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 14:28:44 2007 -0300

    [CCID3]: Use MSS for larger initial windows
    
    This improves the slow-start phase by using the MSS
    (as suggested in RFC 4342, sec. 5) instead of the packet size s.
    Also figured out that __u32 is ample resource enough.
    
    After applying, I got the following in the logs:
    
      ccid3_hc_tx_packet_recv: client(f7421700), s=6, MSS=1424, w_init=4380, R_sample=176us, X=24886363
    
    Had the previous variant been used, w_init would have been as low as 24.
    
    Committer note: removed unneeded cast to unsigned long long that was
                    causing a compiler warning on 64bit architectures.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9bf17475eb658a920125bd8f05edf9c57c2dd950
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 13:11:24 2007 -0300

    [CCID3]: Re-order CCID 3 source file
    
    No code change at all.
    This splits ccid3.c into a RX and a TX section, so that the file has an
    organisation similar to the other ones (e.g. packet_history.{h,c}).
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 353b13e10a3f1a18c6b33858fb3337bcd2692eb5
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 13:10:15 2007 -0300

    [CCID3]: Remove redundant `len' test
    
    Since CCID3 avoids  sending 0-byte data packets (cf. ccid3_hc_tx_send_packet),
    testing for zero-payload length, as performed by ccid3_hc_tx_update_s, is
    redundant - hence removed by this patch.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8d13bf9a0bd4984756e234ce54299b92acefab99
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 13:08:19 2007 -0300

    [DCCP]: Remove ambiguity in the way before48 is used
    
    This removes two ambiguities in employing the new definition of before48,
    following the analysis on http://www.mail-archive.com/dccp@vger.kernel.org/msg01295.html
    
     (1) Updating GSR when P.seqno >= S.SWL
         With the old definition we did not update when P.seqno and S.SWL are 2^47 apart. To
         ensure the same behaviour as with the old definition, this is replaced with the
         equivalent condition dccp_delta_seqno(S.SWL, P.seqno) >= 0
    
     (2) Sending SYNC when P.seqno >= S.OSR
         Here it is debatable whether the new definition causes an ambiguity: the case is
         similar to (1); and to have consistency with the case (1), we use the equivalent
         condition dccp_delta_seqno(S.OSR, P.seqno) >= 0
    
    Detailed Justification

commit b16be51b5e5d75cec71b18ebc75f15a4734c62ad
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 13:03:47 2007 -0300

    [DCCP]: Fix for follows48
    
    The follows48 relation identifies whether 48-bit sequence number
    x is the direct successor of y. Currently, it does not handle cases
    of the following type correctly:
    
    	follows48(0x(prefix)10000LL, 0x(prefix)0FFFFLL)
    
    where prefix is an arbitrary hex sequence of up to 7 digits.
    
    This is fixed by reusing the new dccp_delta_seqno function.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d52de17b8cf36d43a9d6977e7861a9f415541c6b
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 13:00:26 2007 -0300

    [DCCP]: Make `before' relation unambiguous
    
    Problem:

commit 0aec51c86986f61de26dd04913667af544a8b8eb
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 12:45:59 2007 -0300

    [DCCP]: Make dccp_delta_seqno return signed numbers
    
    Problem:

commit 6b811d43f6cc9eccdfc011a99f8571df2abc46d1
Author: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date:   Tue Mar 20 12:26:51 2007 -0300

    [DCCP]: 48-bit sequence number arithmetic
    
    This patch
     * organizes the sequence arithmetic functions into one corner of dccp.h
     * performs a small modification of dccp_set_seqno to make it more widely reusable
       (now it is safe to use any number, since it performs modulo-2^48 assignment)
     * adds functions and generic macros for 48-bit sequence arithmetic:
     	--48 bit complement
     	--modulo-48 addition and modulo-48 subtraction
    	--dccp_inc_seqno now a special case of add48
    Constants renamed following a suggestion by Arnaldo.
    
    Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
    Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8b5be26831b973d8013e8b4c9860d9694310cdc6
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 20 12:08:20 2007 -0300

    [FORCEDETH]: Use skb_tailroom where appropriate
    
    Reducing the number of skb->data direct accesses.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d004b8d4903180c111e114726982c194adf2a04f
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 20 12:00:44 2007 -0300

    [LMC]: lmc_main wants to use skb_tailroom
    
    At that point it is equivalent to what was being used, skb->end - skb->data,
    and the need is clearly the one skb_tailroom satisfies.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f2adc9866742e7904f0268824edc53c948741415
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 20 11:52:34 2007 -0300

    [ATM] idt77252: Fix double kfree_skb on failure in push_rx_skb
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit 6b88dd966b42e374dc783c397efc15f5c1458265
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 22:29:03 2007 -0300

    [SK_BUFF] ipv6: Use skb_network_offset in some more places
    
    So that we reduce the number of direct accesses to skb->data.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sun Mar 25 23:06:12 2007 -0700

    [NETLINK]: Use nlmsg_trim() where appropriate
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a36ca733375860b389c15ffdf6a5f92df64a33b6
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 22:28:08 2007 -0300

    [NETLINK]: Remove NLMSG_{NEW_ANSWER,CANCEL,END}
    
    Not used anywhere and defined inside __KERNEL__, Thomas acked this on irc.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit 897933bcdf31c372e029dd4e2ecd573ebe6cfd9c
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 22:27:36 2007 -0300

    [SK_BUFF]: Remove skb_add_mtu() leftovers
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

commit b529ccf2799c14346d1518e9bdf1f88f03643e99
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 19:08:35 2007 -0700

    [NETLINK]: Introduce nlmsg_hdr() helper
    
    For the common "(struct nlmsghdr *)skb->data" sequence, so that we reduce the
    number of direct accesses to skb->data and for consistency with all the other
    cast skb member helpers.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 965ffea43d4ebe8cd7b9fee78d651268dd7d23c5
Author: Robert Olsson <robert.olsson@its.uu.se>
Date:   Mon Mar 19 16:29:58 2007 -0700

    [IPV4]: fib_trie root node settings
    
    The threshold for root node can be more aggressive set to get
    better tree compression. The new setting mekes the root grow
    from 16 to 19 bits and substansial improvemnt in Aver depth
    this with the current table of 214393 prefixes
    
    But really the dynamic resize should need more investigation
    both in terms convergence and performance and maybe it should
    be possible to change...
    
    Maybe just for the brave to start with or we may have to back
    this out.

commit 05eee48c5af8213a71bd908ce17f577b2b776f79
Author: Robert Olsson <robert.olsson@its.uu.se>
Date:   Mon Mar 19 16:27:37 2007 -0700

    [IPV4]: fib_trie resize break
    
    The patch below adds break condition for the resize operations. If
    we don't achieve the desired fill factor a warning is printed. Trie
    should still be operational but new thresholds should be considered.
    
    Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ca0605a7c8a42379c695308944b3ae82a85479f1
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 10:48:59 2007 -0300

    [SK_BUFF]: Adjust the zeroing up to tail in __alloc_skb too
    
    I did it just in alloc_skb_from_cache, forgot __alloc_skb, fixed now.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4305b541357ddbd205aa145dc378926b7cb12283
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Thu Apr 19 20:43:29 2007 -0700

    [SK_BUFF]: Convert skb->end to sk_buff_data_t
    
    Now to convert the last one, skb->data, that will allow many simplifications
    and removal of some of the offset helpers.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 27a884dc3cb63b93c2b3b643f5b31eed5f8a4d26
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Thu Apr 19 20:29:13 2007 -0700

    [SK_BUFF]: Convert skb->tail to sk_buff_data_t
    
    So that it is also an offset from skb->head, reduces its size from 8 to 4 bytes
    on 64bit architectures, allowing us to combine the 4 bytes hole left by the
    layer headers conversion, reducing struct sk_buff size to 256 bytes, i.e. 4
    64byte cachelines, and since the sk_buff slab cache is SLAB_HWCACHE_ALIGN...
    :-)
    
    Many calculations that previously required that skb->{transport,network,
    mac}_header be first converted to a pointer now can be done directly, being
    meaningful as offsets or pointers.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit be8bd86321fa7f06359d866ef61fb4d2f3e9dce9
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 19 20:34:51 2007 -0700

    [VLAN] vlan_dev: Use skb_reset_network_header().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit afdf27c95629634ea40703197b6788e454d31609
Author: Peter Kovar <peter.kovar@gmail.com>
Date:   Fri Mar 16 20:39:25 2007 -0700

    [IrDA]: SMC SuperIO Chip LPC47N227 not identified properly
    
    SMC SuperIO Chip LPC47N227 used for IrDA is not detected because its device
    identification byte can be 0x7A instead of 0x5A.
    
    Patch from Peter Kovar <peter.kovar@gmail.com>
    Cc: Jean Delvare <khali@linux-fr.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c7630a4b932af254d61947a3a7e3831de92c7fb5
Author: Samuel Ortiz <samuel@sortiz.org>
Date:   Fri Mar 16 20:38:23 2007 -0700

    [IrDA]: irda lockdep annotation
    
    Rmmoding irda triggers a lockdep false positive.
    
    Reported-by: Dave Jones <davej@redhat.com>
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5c81cd75fa63eaf2df0b8904508e53e953f316cf
Author: Samuel Ortiz <samuel@sortiz.org>
Date:   Fri Mar 16 20:35:25 2007 -0700

    [IrDA]: removing stir4200 useless include
    
    stir4200 doesn't need to include irlap.h
    
    Signed-off-by: Samuel Ortiz <samuel@sortiz.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2e07fa9cd3bac1e28cfe3131ed86b053afb02fc9
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 21:22:35 2007 -0700

    [SK_BUFF]: Use offsets for skb->{mac,network,transport}_header on 64bit architectures
    
    With this we save 8 bytes per network packet, leaving a 4 bytes hole to be used
    in further shrinking work, likely with the offsetization of other pointers,
    such as ->{data,tail,end}, at the cost of adds, that were minimized by the
    usual practice of setting skb->{mac,nh,n}.raw to a local variable that is then
    accessed multiple times in each function, it also is not more expensive than
    before with regards to most of the handling of such headers, like setting one
    of these headers to another (transport to network, etc), or subtracting, adding
    to/from it, comparing them, etc.
    
    Now we have this layout for sk_buff on a x86_64 machine:
    
    [acme@mica net-2.6.22]$ pahole vmlinux sk_buff
    struct sk_buff {
    	struct sk_buff *       next;             /*   0   8 */
    	struct sk_buff *       prev;             /*   8   8 */
    	struct rb_node         rb;               /*  16  24 */
    	struct sock *          sk;               /*  40   8 */
    	ktime_t                tstamp;           /*  48   8 */
    	struct net_device *    dev;              /*  56   8 */
    	/* --- cacheline 1 boundary (64 bytes) --- */
    	struct net_device *    input_dev;        /*  64   8 */
    	sk_buff_data_t         transport_header; /*  72   4 */
    	sk_buff_data_t         network_header;   /*  76   4 */
    	sk_buff_data_t         mac_header;       /*  80   4 */
    
    	/* XXX 4 bytes hole, try to pack */
    
    	struct dst_entry *     dst;              /*  88   8 */
    	struct sec_path *      sp;               /*  96   8 */
    	char                   cb[48];           /* 104  48 */
    	/* cacheline 2 boundary (128 bytes) was 24 bytes ago*/
    	unsigned int           len;              /* 152   4 */
    	unsigned int           data_len;         /* 156   4 */
    	unsigned int           mac_len;          /* 160   4 */
    	union {
    		__wsum         csum;             /*       4 */
    		__u32          csum_offset;      /*       4 */
    	};                                       /* 164   4 */
    	__u32                  priority;         /* 168   4 */
    	__u8                   local_df:1;       /* 172   1 */
    	__u8                   cloned:1;         /* 172   1 */
    	__u8                   ip_summed:2;      /* 172   1 */
    	__u8                   nohdr:1;          /* 172   1 */
    	__u8                   nfctinfo:3;       /* 172   1 */
    	__u8                   pkt_type:3;       /* 173   1 */
    	__u8                   fclone:2;         /* 173   1 */
    	__u8                   ipvs_property:1;  /* 173   1 */
    
    	/* XXX 2 bits hole, try to pack */
    
    	__be16                 protocol;         /* 174   2 */
    	void    (*destructor)(struct sk_buff *); /* 176   8 */
    	struct nf_conntrack *  nfct;             /* 184   8 */
    	/* --- cacheline 3 boundary (192 bytes) --- */
    	struct sk_buff *       nfct_reasm;       /* 192   8 */
    	struct nf_bridge_info *nf_bridge;        /* 200   8 */
    	__u16                  tc_index;         /* 208   2 */
    	__u16                  tc_verd;          /* 210   2 */
    	dma_cookie_t           dma_cookie;       /* 212   4 */
    	__u32                  secmark;          /* 216   4 */
    	__u32                  mark;             /* 220   4 */
    	unsigned int           truesize;         /* 224   4 */
    	atomic_t               users;            /* 228   4 */
    	unsigned char *        head;             /* 232   8 */
    	unsigned char *        data;             /* 240   8 */
    	unsigned char *        tail;             /* 248   8 */
    	/* --- cacheline 4 boundary (256 bytes) --- */
    	unsigned char *        end;              /* 256   8 */
    }; /* size: 264, cachelines: 5 */
       /* sum members: 260, holes: 1, sum holes: 4 */
       /* bit holes: 1, sum bit holes: 2 bits */
       /* last cacheline: 8 bytes */
    
    On 32 bits nothing changes, and pointers continue to be used with the compiler
    turning all this abstraction layer into dust. But there are some sk_buff
    validation tricks that are now possible, humm... :-)
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b0e380b1d8a8e0aca215df97702f99815f05c094
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 21:21:55 2007 -0700

    [SK_BUFF]: unions of just one member don't get anything done, kill them
    
    Renaming skb->h to skb->transport_header, skb->nh to skb->network_header and
    skb->mac to skb->mac_header, to match the names of the associated helpers
    (skb[_[re]set]_{transport,network,mac}_header).
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cfe1fc7759fdacb0c650b575daed1692bf3eaece
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Fri Mar 16 17:26:39 2007 -0300

    [SK_BUFF]: Introduce skb_network_header_len
    
    For the common sequence "skb->h.raw - skb->nh.raw", similar to skb->mac_len,
    that is precalculated tho, don't think we need to bloat skb with one more
    member, so just use this new helper, reducing the number of non-skbuff.h
    references to the layer headers even more.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bff9b61ce330df04c6830d823c30c04203543f01
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Fri Mar 16 17:19:57 2007 -0300

    [SK_BUFF]: Use the helpers to get the layer header pointer
    
    Some more cases...
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 514bca322cb9220308d22691ac1e74038bfabac3
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 12:34:52 2007 -0700

    [NET_SCHED]: Fix warning
    
    net/sched/sch_api.c: In function 'psched_show':
    net/sched/sch_api.c:1219: warning: format '%08x' expects type 'unsigned int', but argument 6 has type 's64'
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bb239acf5679ee1936f6b1b034ad260c4fec89c8
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 12:31:28 2007 -0700

    [NET_SCHED]: sch_cbq: fix watchdog scheduled too late
    
    q->now is increased during dequeue and doesn't contain the current time
    afterwards, resulting in a too large timeout value for the qdisc watchdog.
    Use "now" instead, which still contains the current time.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4361cb17f0df5491fe6e2c3ae1defc98e9a64a79
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:23:28 2007 -0700

    [NET_SCHED]: Export real timer resolution in /proc/net/psched
    
    The timer resolution exported in /proc/net/psched is used by userspace to
    calculate HTB's burst values. Currently it is set to HZ, since we're now
    using hrtimers, use KTIME_MONOTONIC_RES, which makes HTB use smaller burst
    values.
    
    This patch also affects libnl, which incorrectly uses this value for
    the SFQ perturbation parameter, which is always in seconds, and some
    routing cache values, which are in USER_HZ, so both cases are broken
    anyway.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 00c04af9df3d26e5a8093da850e982a7b6aeada7
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:23:02 2007 -0700

    [NET_SCHED]: kill jiffie conversion macros
    
    Now that all packet schedulers have been converted to hrtimers most users
    of PSCHED_JIFFIE2US and PSCHED_US2JIFFIE are gone. The remaining users use
    it to convert external time units to packet scheduler clock ticks, so use
    PSCHED_TICKS_PER_SEC instead.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fb983d4578e238b7f483b4f8f39f3a0f35d34d16
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:22:39 2007 -0700

    [NET_SCHED]: sch_htb: use hrtimer based watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1a13cb63d679da328cfa339c89b8b2d0eba3b81e
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:22:20 2007 -0700

    [NET_SCHED]: sch_cbq: use hrtimer for delay_timer
    
    Switch delay_timer to hrtimer.
    
    The class penalty parameter is changed to use psched ticks as units.
    Since iproute never supported using this and the only existing user
    (libnl) incorrectly assumes psched ticks as units anyway, this
    shouldn't break anything.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e9054a339eb275c756efeeaee42af484ac72a3f4
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:21:40 2007 -0700

    [NET_SCHED]: sch_cbq: fix cbq_undelay_prio for non-active priorites
    
    cbq_undelay_prio is supposed to return a time delta, but returns the
    current time for non-active priorities, causing cbq_undelay to mark
    the priority as active and schedule a timer for twice the current
    time.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 88a993540a65c38865f83961520494b4ad5d0363
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:21:11 2007 -0700

    [NET_SCHED]: sch_cbq: use hrtimer based watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 59cb5c6734021acc68590c7c2e0e92ad9a4952c6
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:20:31 2007 -0700

    [NET_SCHED]: sch_netem: use hrtimer based watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f7f593e383145931cb2a65df62c31ce1bcc0cffc
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:20:07 2007 -0700

    [NET_SCHED]: sch_tbf: use hrtimer based watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ed2b229a97fd537857ad8441ab8b5996b15eadfd
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:19:33 2007 -0700

    [NET_SCHED]: sch_hfsc: use hrtimer based watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4179477f637caa730626bd597fdf28c5bad73565
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:19:15 2007 -0700

    [NET_SCHED]: Add hrtimer based qdisc watchdog
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 641b9e0e8b7f96425da6ce98f3361e3af0baee29
Author: Patrick McHardy <kaber@trash.net>
Date:   Fri Mar 16 01:18:42 2007 -0700

    [NET_SCHED]: Use ktime as clocksource
    
    Get rid of the manual clock source selection mess and use ktime. Also
    use a scalar representation, which allows to clean up pkt_sched.h a bit
    more and results in less ktime_to_ns() calls in most cases.
    
    The PSCHED_US2JIFFIE/PSCHED_JIFFIE2US macros are implemented quite
    inefficient by this patch, following patches will convert all qdiscs
    to hrtimers and get rid of them entirely.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ddc7b8e32b22fe8b45d306b7d99472d4b560add6
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Thu Mar 15 21:42:27 2007 -0300

    [SK_BUFF]: Some more layer header conversions
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0a6114d94b6d6f82e81cb8e0d8b0d4cf50739fec
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Thu Mar 15 21:08:55 2007 -0300

    [KBUILD]: Unifdef headers changed by the skb layer header refactorings
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d10ba34b001944a8d1c8adb5646140ef089c432b
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Mar 14 21:05:37 2007 -0300

    [SK_BUFF]: More skb_put related skb_reset_transport_header
    
    This time we have to set it to skb->tail that is not anymore equal to
    skb->data, so we either add a new helper or just add the skb->tail - skb->data
    offset, for now do the later.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 55f79cc0c02f9ce8f85e965e9679796f62b790f5
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Mar 14 21:05:03 2007 -0300

    [IPV6]: Reset the network header in ip6_nd_hdr
    
    ip6_nd_hdr is always called immediately after a alloc_skb + skb_reserve
    sequence, i.e. when skb->tail is equal to skb->data, making it correct to use
    skb_reset_network_header().
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit eeeb03745bf9ea352df2373b9cb5fa14e60a2de0
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Mar 14 21:04:34 2007 -0300

    [SK_BUFF]: More skb_put related conversions to skb_reset_transport_header
    
    This is similar to the skb_reset_network_header(), i.e. at the point we reset
    the transport header pointer/offset skb->tail is equal to skb->data.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ac6d141dc7d1d0eeec850d1b451dca83ce649684
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:45:39 2007 -0700

    [NETFILTER]: nfnetlink: parse attributes with nfattr_parse in nfnetlink_check_attribute
    
    Use nfattr_parse to parse attributes, this patch also modifies the default
    behaviour since unknown attributes will be ignored instead of returning
    EINVAL. This ensure backward compatibility: new libraries with new
    attributes and old kernels can work.
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c8e2078cfe414a99cf6f2f2f1d78c7e75392e9d4
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:45:19 2007 -0700

    [NETFILTER]: ctnetlink: add support for internal tcp connection tracking flags handling
    
    This patch let userspace programs set the IP_CT_TCP_BE_LIBERAL flag to
    force the pickup of established connections.
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5c8ce7c92106434d2bdc9d5dfa5f62bf4546b296
Author: Willy Tarreau <w@1wt.eu>
Date:   Wed Mar 14 16:44:53 2007 -0700

    [NETFILTER]: TCP conntrack: factorize out the PUSH flag
    
    The PUSH flag is accepted with every other valid combination.
    Let's get it out of the tcp_valid_flags table and reduce the
    number of combinations we have to handle. This does not
    significantly reduce the table size however (8 bytes).
    
    Signed-off-by: Willy Tarreau <w@1wt.eu>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8f5bd99071212cd16b3449d16639971a44540d51
Author: Willy Tarreau <w@1wt.eu>
Date:   Wed Mar 14 16:44:31 2007 -0700

    [NETFILTER]: TCP conntrack: accept RST|PSH as valid
    
    This combination has been encountered on an IBM AS/400 in response
    to packets sent to a closed session. There is no particular reason
    to mark it invalid.
    
    Signed-off-by: Willy Tarreau <w@1wt.eu>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e7ac05f3407a3fb5a1b2ff5d5554899eaa0a10a3
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Wed Mar 14 16:44:01 2007 -0700

    [NETFILTER]: nf_conntrack: add nf_copy() to safely copy members in skb
    
    This unifies the codes to copy netfilter related datas. Before copying,
    nf_copy() puts original members in destination skb.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit edda553c324bdc5bb5c2d553b524cab37058a855
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Wed Mar 14 16:43:37 2007 -0700

    [NETFILTER]: nf_conntrack: add __nf_copy() to copy members in skb
    
    This unifies the codes to copy netfilter related datas. Note that
    __nf_copy() assumes destination skb doesn't have any netfilter
    related members.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9b88790972498d235a2a4d2b66640c3c5b70bb7c
Author: Sami Farin <safari-netfilter@safari.iki.fi>
Date:   Wed Mar 14 16:43:00 2007 -0700

    [NETFILTER]: nf_conntrack: use jhash2 in __hash_conntrack
    
    Now it uses jhash, but using jhash2 would be around 3-4 times faster
    (on P4).
    
    Signed-off-by: Sami Farin <safari-netfilter@safari.iki.fi>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8e87e014ec881ce353e1f43340157f519b5d9f30
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:42:29 2007 -0700

    [JHASH]: Use const in jhash2
    
    Use const to avoid forcing users to cast const data.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f4bc177f0ff0bf41b178452877762a9f0184d1a1
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:42:11 2007 -0700

    [NETFILTER]: nfnetlink: move EXPORT_SYMBOL declarations next to the exported symbol
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8a2e89533a9b06bc960445dd6034eeab76117424
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:41:47 2007 -0700

    [NETFILTER]: nfnetlink: remove unused includes in nfnetlink.c
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ac0f1d9894650d900af99bdaed83e110d9dce025
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:41:28 2007 -0700

    [NETFILTER]: nfnetlink: remove unrequired check in nfnetlink_get_subsys
    
    subsys_table is initialized to NULL, therefore just returns NULL in case
    that it is not set.
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d9e6d029498ab9e943c70f24c027aeda5602196d
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:41:03 2007 -0700

    [NETFILTER]: nfnetlink: remove duplicate checks in nfnetlink_check_attributes
    
    Remove nfnetlink_check_attributes duplicates message size and callback
    id checks. nfnetlink_find_client and nfnetlink_rcv_msg already do
    such checks.
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 67ca396606432aae3b747d5e6bb61d0c297eb782
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date:   Wed Mar 14 16:40:38 2007 -0700

    [NETFILTER]: nfnetlink: remove early debugging messages from nfnetlink
    
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 010c7d6f867e98c86723f420d485583464fbab45
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:40:10 2007 -0700

    [NETFILTER]: nf_conntrack: uninline notifier registration functions
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 73c361862c2be2e4ed6019da283fe1b422107f16
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:39:45 2007 -0700

    [NETFILTER]: nfnetlink: use netlink_run_queue()
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a3c5029cf7a96da3acdf6884a21581b5bef310c3
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:39:25 2007 -0700

    [NETFILTER]: nfnetlink: use mutex instead of semaphore
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c6a1e615d1ba942b9e783079d53f741e4a8e1c89
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:39:07 2007 -0700

    [NETFILTER]: nf_conntrack: simplify l4 protocol array allocation
    
    The retrying after an allocation failure is not necessary anymore
    since we're holding the mutex the entire time, for the same
    reason the double allocation race can't happen anymore.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0661cca9c216322e77dca7f47df107c02ce4e70c
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:38:48 2007 -0700

    [NETFILTER]: nf_conntrack: simplify protocol locking
    
    Now that we don't use nf_conntrack_lock anymore but a single mutex for
    all protocol handling, no need to release and grab it again for sysctl
    registration.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ac5357ebac43e191003c2cd0722377dccfa01a84
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:38:25 2007 -0700

    [NETFILTER]: nf_conntrack: remove ugly hack in l4proto registration
    
    Remove ugly special-casing of nf_conntrack_l4proto_generic, all it
    wants is its sysctl tables registered, so do that explicitly in an
    init function and move the remaining protocol initialization and
    cleanup code to nf_conntrack_proto.c as well.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b19caa0ca071dce76b0e81e957e7eb7c03d72cf5
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:37:52 2007 -0700

    [NETFILTER]: nf_conntrack: switch protocol registration/unregistration to mutex
    
    The protocol lookups done by nf_conntrack are already protected by RCU,
    there is no need to keep taking nf_conntrack_lock for registration
    and unregistration. Switch to a mutex.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 587aa64163bb14f70098f450abab9410787fce9d
Author: Patrick McHardy <kaber@trash.net>
Date:   Wed Mar 14 16:37:25 2007 -0700

    [NETFILTER]: Remove IPv4 only connection tracking/NAT
    
    Remove the obsolete IPv4 only connection tracking/NAT as scheduled in
    feature-removal-schedule.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ce18afe57bf53477f133208856dd2b7e6b5db5e3
Author: Tobias Klauser <tklauser@distanz.ch>
Date:   Wed Mar 14 16:36:16 2007 -0700

    [NETFILTER]: x_tables: remove duplicate of xt_prefix
    
    Remove xt_proto_prefix array which duplicates xt_prefix and change all
    users of xt_proto_prefix to xt_prefix.
    
    Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
    Signed-off-by: Patrick McHardy <kaber@trash.net>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 239254fedcbc6ff79bcf5696fe94723f7a5d0782
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Apr 19 19:55:44 2007 -0700

    [IPV4] xfrm4_mode_beet: Use skb_transport_header().
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9c70220b73908f64792422a2c39c593c4792f2c5
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 18:04:18 2007 -0700

    [SK_BUFF]: Introduce skb_transport_header(skb)
    
    For the places where we need a pointer to the transport header, it is
    still legal to touch skb->h.raw directly if just adding to,
    subtracting from or setting it to another layer header.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a27ef749e7be3b06fb58df53d94eb97a21f18707
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 17:17:10 2007 -0300

    [SCTP]: Eliminate some pointer attributions to the skb layer headers
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bd82393ca23324d103b21aae43160728da6e6c9c
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 17:10:43 2007 -0300

    [SK_BUFF]: More skb_reset_transport_header conversions
    
    These are a bit more subtle, they are of this type:
    
    -       skb->h.raw = payload;
            __skb_pull(skb, payload - skb->data);
    +       skb_reset_transport_header(skb);
    
    __skb_pull results in:
    
    skb->data = skb->data + payload - skb->data;
    skb->data = payload;
    
    So after __skb_pull we have skb->data pointing to payload and we can
    just call skb_reset_transport_header(skb), that will do:
    
    skb->h.raw = payload;
    
    The others are similar, allowing us to get rid of some more cases where a
    pointer was being attributed to the layer headers.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 39b89160df691045d1449cbaef43c02084c7543a
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 21:06:25 2007 -0700

    [SK_BUFF]: Introduce ipipv6_hdr(), remove skb->h.ipv6h
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b0061ce49c83657563b64ffcf1ec137110230d93
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 18:02:22 2007 -0700

    [SK_BUFF]: Introduce ipip_hdr(), remove skb->h.ipiph
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aa8223c7bb0b05183e1737881ed21827aa5b9e73
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 21:04:22 2007 -0700

    [SK_BUFF]: Introduce tcp_hdr(), remove skb->h.th
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ab6a5bb6b28a970104a34f0f6959b73cf61bdc72
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sun Mar 18 17:43:48 2007 -0700

    [TCP]: Introduce tcp_hdrlen() and tcp_optlen()
    
    The ip_hdrlen() buddy, created to reduce the number of skb->h.th-> uses and to
    avoid the longer, open coded equivalent.
    
    Ditched a no-op in bnx2 in the process.
    
    I wonder if we should have a BUG_ON(skb->h.th->doff < 5) in tcp_optlen()...
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 88c7664f13bd1a36acb8566b93892a4c58759ac6
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 14:43:18 2007 -0300

    [SK_BUFF]: Introduce icmp_hdr(), remove skb->h.icmph
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4bedb45203eab92a87b4c863fe2d0cded633427f
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 14:28:48 2007 -0300

    [SK_BUFF]: Introduce udp_hdr(), remove skb->h.uh
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d9edf9e2be0f7661558984c32bd53867a7037fd3
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 14:19:23 2007 -0300

    [SK_BUFF]: Introduce igmp_hdr() & friends, remove skb->h.igmph
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cc70ab261c9f997589546100ddec5da6bfd89c4e
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 14:03:22 2007 -0300

    [ICMP6]: Introduce icmp6_hdr()
    
    For consistency with all the other skb->h.raw accessors.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2c0fd387b00a6758550b5ca1aae4408374483fe7
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 13:59:32 2007 -0300

    [SCTP]: Introduce sctp_hdr()
    
    For consistency with all the other skb->h.raw accessors.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 967b05f64e27d04a4c8879addd0e1c52137e2c9e
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 13:51:52 2007 -0300

    [SK_BUFF]: Introduce skb_set_transport_header
    
    For the cases where the transport header is being set to a offset from
    skb->data.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ea2ae17d6443abddc79480dc9f7af8feacabddc4
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 17:55:53 2007 -0700

    [SK_BUFF]: Introduce skb_transport_offset()
    
    For the quite common 'skb->h.raw - skb->data' sequence.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit badff6d01a8589a1c828b0bf118903ca38627f4e
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Mar 13 13:06:52 2007 -0300

    [SK_BUFF]: Introduce skb_reset_transport_header(skb)
    
    For the common, open coded 'skb->h.raw = skb->data' operation, so that we can
    later turn skb->h.raw into a offset, reducing the size of struct sk_buff in
    64bit land while possibly keeping it as a pointer on 32bit.
    
    This one touches just the most simple cases:
    
    skb->h.raw = skb->data;
    skb->h.raw = {skb_push|[__]skb_pull}()
    
    The next ones will handle the slightly more "complex" cases.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0660e03f6b18f19b6bbafe7583265a51b90daf36
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 17:54:47 2007 -0700

    [SK_BUFF]: Introduce ipv6_hdr(), remove skb->nh.ipv6h
    
    Now the skb->nh union has just one member, .raw, i.e. it is just like the
    skb->mac union, strange, no? I'm just leaving it like that till the transport
    layer is done with, when we'll rename skb->mac.raw to skb->mac_header (or
    ->mac_header_offset?), ditto for ->{h,nh}.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d0a92be05ed4aea7d35c2b257e3f9173565fe4eb
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 12 20:56:31 2007 -0300

    [SK_BUFF]: Introduce arp_hdr(), remove skb->nh.arph
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fd74e6ccd522e2f26163eb5ac1abebcab2bd017c
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Mar 12 16:25:32 2007 -0700

    [BRIDGE]: faster compare for link local addresses
    
    Use logic operations rather than memcmp() to compare destination
    address with link local multicast addresses.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit eddc9ec53be2ecdbf4efe0efd4a83052594f0ac0
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Fri Apr 20 22:47:35 2007 -0700

    [SK_BUFF]: Introduce ip_hdr(), remove skb->nh.iph
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e023dd643798c4f06c16466af90b4d250e4b8bd7
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 12 20:09:36 2007 -0300

    [IPMR]: Fix bug introduced when converting to skb_network_reset_header
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c9bdd4b5257406b0608385d19c40b5511decf4f6
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 12 20:09:15 2007 -0300

    [IP]: Introduce ip_hdrlen()
    
    For the common sequence "skb->nh.iph->ihl * 4", removing a good number of open
    coded skb->nh.iph uses, now to go after the rest...
    
    Just out of curiosity, here are the idioms found to get the same result:
    
    skb->nh.iph->ihl << 2
    skb->nh.iph->ihl<<2
    skb->nh.iph->ihl * 4
    skb->nh.iph->ihl*4
    (skb->nh.iph)->ihl * sizeof(u32)
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0272ffc46f81a4bbbf302ba093c737e969c5bb55
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 12 20:05:39 2007 -0300

    [SK_BUFF] ipmr: Missed one conversion to skb_network_header()
    
    We can't access skb->nh.raw directly anymore, it will become an offset.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0e1256ffd1ec654b35e023c66f6b262d4cba91e9
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Mar 12 14:35:37 2007 -0700

    [NET]: show bound packet types
    
    Show what protocols are bound to what packet types in /proc/net/ptype
    Uses kallsyms to decode function pointers if possible.
    Example:
    	Type Device      Function
    	ALL  eth1     packet_rcv_spkt+0x0
    	0800          ip_rcv+0x0
    	0806          arp_rcv+0x0
    	86dd          :ipv6:ipv6_rcv+0x0
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f690808e17925fc45217eb22e8670902ecee5c1b
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Mar 12 14:34:29 2007 -0700

    [NET]: make seq_operations const
    
    The seq_file operations stuff can be marked constant to
    get it out of dirty cache.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6b2bedc3a659ba228a93afc8e3f008e152abf18a
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Mon Mar 12 14:33:50 2007 -0700

    [NET]: network dev read_mostly
    
    For Eric, mark packet type and network device watermarks
    as read mostly.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c14d2450cb7fe1786e2ec325172baf66922bf597
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sun Mar 11 22:39:41 2007 -0300

    [SK_BUFF]: Introduce skb_set_network_header
    
    For the cases where the network header is being set to a offset from skb->data.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 878c814500b123dd61a5e211879a32e5fd932713
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sun Mar 11 22:38:29 2007 -0300

    [SK_BUFF] ipmr: Another skb_push related conversion to skb_reset_network_header
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d56f90a7c96da5187f0cdf07ee7434fe6aa78bbc
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 20:50:43 2007 -0700

    [SK_BUFF]: Introduce skb_network_header()
    
    For the places where we need a pointer to the network header, it is still legal
    to touch skb->nh.raw directly if just adding to, subtracting from or setting it
    to another layer header.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bbe735e4247dba32568a305553b010081c8dea99
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 22:16:10 2007 -0300

    [SK_BUFF]: Introduce skb_network_offset()
    
    For the quite common 'skb->nh.raw - skb->data' sequence.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e7dd65dafda5737a983c04d652a69ab8da78ee3f
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 20:09:45 2007 -0300

    [SK_BUFF] bonding: Set skb->nh.raw relative to skb->mac.raw
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7f5c0cb05f158ee91414e1f99d3fe18349a80371
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:59:16 2007 -0300

    [SK_BUFF] xfrm4: use skb_reset_network_header
    
    Setting it to skb->h.raw, which is valid, in the (to become) old pointer based
    world order and in the new world of offset based layer headers.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1ced98e81d1c2f1ce965ecf8d0032e02ffa07bf0
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:57:15 2007 -0300

    [SK_BUFF] ipv6: More skb_reset_network_header conversions related to skb_pull
    
    Now related to this form:
    
    skb->nh.ipv6h = (struct ipv6hdr *)skb_put(skb, length);
    
    That, as the others, is done when skb->tail is still equal to skb->data, making
    the conversion to skb_reset_network_header possible.
    
    Also one more case equivalent to skb->nh.raw = skb->data, of this form:
    
    iph = (struct ipv6hdr *)skb->data;
    <SNIP>
    skb->nh.ipv6h = iph;
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8856dfa3e9b71ac2177016f66ace3a8978afecc1
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:40:39 2007 -0300

    [SK_BUFF]: Use skb_reset_network_header after skb_push
    
    Some more cases where skb->nh.iph was being set that were converted
    to using skb_reset_network_header.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 04b964dbad25cbd6edd8ecbeca2efb40c9860865
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:27:27 2007 -0300

    [SK_BUFF] ipconfig: Another conversion to skb_reset_network_header related to skb_put
    
    boot_pkt->iph is the first member, that is at skb->data, so just use
    skb_reset_network_header().
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2ca9e6f2c2a4117d21947e911ae1f5e5306b0df0
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:15:25 2007 -0300

    [SK_BUFF]: Some more skb_put cases converted to skb_reset_network_header
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 31c7711b509d470ab1e175e7bb98ea66a82aa916
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 19:04:55 2007 -0300

    [SK_BUFF]: Some more simple skb_reset_network_header conversions
    
    This time of the type:
    
     skb->nh.iph = (struct iphdr *)skb->data;
    
    That is completely equivalent to:
    
     skb->nh.raw = skb->data;
    
    Wonder why people love casts... :-)
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4209fb601c0a0e0a9d90c0008f350dd345c8b7de
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 18:42:03 2007 -0300

    [SK_BUFF]: Use skb_reset_network_header where the return of __pskb_pull was being used
    
    It returns skb->data, so we can just use skb_reset_network_header after it.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7e28ecc282574a7d72ace365fc9bc86e27ba880f
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 18:40:59 2007 -0300

    [SK_BUFF]: Use skb_reset_network_header where the skb_pull return was being used
    
    But only in the cases where its a newly allocated skb, i.e. one where skb->tail
    is equal to skb->data, or just after skb_reserve, where this requirement is
    maintained.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e2d1bca7e6134671bcb19810d004a252aa6a644d
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 20:46:21 2007 -0700

    [SK_BUFF]: Use skb_reset_network_header in skb_push cases
    
    skb_push updates and returns skb->data, so we can just call
    skb_reset_network_header after the call to skb_push.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ce
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Tue Apr 10 20:45:18 2007 -0700

    [SK_BUFF]: Introduce skb_reset_network_header(skb)
    
    For the common, open coded 'skb->nh.raw = skb->data' operation, so that we can
    later turn skb->nh.raw into a offset, reducing the size of struct sk_buff in
    64bit land while possibly keeping it as a pointer on 32bit.
    
    This one touches just the most simple case, next will handle the slightly more
    "complex" cases.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 57effc70a5be9f7804e9a99964eb7265367effca
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 16:21:45 2007 -0300

    [IPV6]: Use skb->nh.ipv6h instead of casting skb->nh.raw
    
    nh.ipv6h is there exactly for this reason! Use it while it exists ;-)
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a16aeb36239ce612699ed64a75a03c88cbc657e8
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 16:07:19 2007 -0300

    [BONDING]: Introduce arp_pkt()
    
    For consistency with all the other skb->nh.raw accessors.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 797659fb4a4a511649cd71028141c32ad1698a12
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 15:56:08 2007 -0300

    [PPPOE]: Introduce pppoe_hdr()
    
    For consistency with all the other skb->nh.raw accessors.
    
    Also do some really obvious simplifications in pppoe_recvmsg, well the
    kfree_skb one is not so obvious, but free() and kfree() have the same behaviour
    (hint :-) ).
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 37e6636669b0b996681586facee8034f7f674f6a
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 15:34:36 2007 -0300

    [LLC]: Kill llc_set_pdu_hdr
    
    We'll have skb_reset_network_header soon.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 98e399f82ab3a6d863d1d4a7ea48925cc91c830e
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 15:33:04 2007 -0700

    [SK_BUFF]: Introduce skb_mac_header()
    
    For the places where we need a pointer to the mac header, it is still legal to
    touch skb->mac.raw directly if just adding to, subtracting from or setting it
    to another layer header.
    
    This one also converts some more cases to skb_reset_mac_header() that my
    regex missed as it had no spaces before nor after '=', ugh.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 31713c333ddbb66d694829082620b69b71c4b09a
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:48:37 2007 -0300

    [TCP]: Use skb_set_mac_header in tcp_collapse
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c51957dafa6f960c5c6372aa3da6c8fa71c13730
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:47:22 2007 -0300

    [TCP]: Do the layer header setting in tcp_collapse relative to skb->data
    
    That is equal to skb->head before skb_reserve, to help in the layer header
    changes.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 39f69c6f922fbfb51e1ff24c9e196584a79f1484
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:40:27 2007 -0300

    [SK_BUFF] xfrm: Use skb_set_mac_header in the memmove cases
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 48d49d0ccdaa9caff4636ef9c3410973d28131b5
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:30:58 2007 -0300

    [SK_BUFF]: Introduce skb_set_mac_header()
    
    For the cases where we want to set skb->mac.raw to an offset from skb->data.
    
    Simple cases first, the memmove ones and specially pktgen will be left for later.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f64955eb117ad62480b858fd69a11e6f9e74f60b
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:17:29 2007 -0300

    [LLC]: Use skb_reset_mac_header in llc_mac_hdr_init
    
    skb_push updates and returns skb->data, so we can just call
    skb_reset_mac_header after the call to skb_push.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0a1b0ad9ae27f918fd935c6da101083e11446f09
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 12:14:56 2007 -0300

    [LLC]: Use skb_reset_mac_header in llc_alloc_frame
    
    skb->head is equal to skb->data after alloc_skb, so reset the mac header while
    this is true, i.e. before skb_reserve.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 459a98ed881802dee55897441bc7f77af614368e
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 15:30:44 2007 -0700

    [SK_BUFF]: Introduce skb_reset_mac_header(skb)
    
    For the common, open coded 'skb->mac.raw = skb->data' operation, so that we can
    later turn skb->mac.raw into a offset, reducing the size of struct sk_buff in
    64bit land while possibly keeping it as a pointer on 32bit.
    
    This one touches just the most simple case, next will handle the slightly more
    "complex" cases.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4c13eb6657fe9ef7b4dc8f1a405c902e9e5234e0
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Wed Apr 25 17:40:23 2007 -0700

    [ETH]: Make eth_type_trans set skb->dev like the other *_type_trans
    
    One less thing for drivers writers to worry about.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 029720f15dcd3c6c16824177cfc486083b229411
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 11:20:07 2007 -0300

    [AOE]: Introduce aoe_hdr()
    
    For consistency with other skb->mac.raw users.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4839fccea04b5f4d2b3ce01585d6bdbcbc24002c
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 11:13:59 2007 -0300

    [QETH]: Use eth_hdr()
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 0a4f23fbbff70c268b0f2f5e0b87301c132fb305
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 10:57:13 2007 -0300

    [HIPPI/FDDI]: Make {hippi,fddi}_type_trans set skb->dev
    
    Now all the _type_trans routines are consistent in this regard.
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c8fb7948dc1aeff0515b2912b564d4236f6c0ebd
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 15:29:16 2007 -0700

    [TR]: Make tr_type_trans set skb->dev
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c1a4b86e396b6870b420d23e4d49c7b685aef0a4
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Mon Mar 19 15:27:07 2007 -0700

    [TR]: Use tr_hdr() were appropriate
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7c81fd8bfbaa9732eca142350de5154da6919411
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Sat Mar 10 00:39:35 2007 -0300

    [SOCKET]: Export __sock_recv_timestamp
    
    Kernel: arch/x86_64/boot/bzImage is ready  (#2)
      MODPOST 1816 modules
    WARNING: "__sock_recv_timestamp" [net/sctp/sctp.ko] undefined!
    WARNING: "__sock_recv_timestamp" [net/packet/af_packet.ko] undefined!
    WARNING: "__sock_recv_timestamp" [net/key/af_key.ko] undefined!
    WARNING: "__sock_recv_timestamp" [net/ipv6/ipv6.ko] undefined!
    WARNING: "__sock_recv_timestamp" [net/atm/atm.ko] undefined!
    make[2]: *** [__modpost] Error 1
    make[1]: *** [modules] Error 2
    make: *** [_all] Error 2
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 92f37fd2ee805aa77925c1e64fd56088b46094fc
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun Mar 25 22:14:49 2007 -0700

    [NET]: Adding SO_TIMESTAMPNS / SCM_TIMESTAMPNS support
    
    Now that network timestamps use ktime_t infrastructure, we can add a new
    SOL_SOCKET sockopt  SO_TIMESTAMPNS.
    
    This command is similar to SO_TIMESTAMP, but permits transmission of
    a 'timespec struct' instead of a 'timeval struct' control message.
    (nanosecond resolution instead of microsecond)
    
    Control message is labelled SCM_TIMESTAMPNS instead of SCM_TIMESTAMP
    
    A socket cannot mix SO_TIMESTAMP and SO_TIMESTAMPNS : the two modes are
    mutually exclusive.
    
    sock_recv_timestamp() became too big to be fully inlined so I added a
    __sock_recv_timestamp() helper function.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    CC: linux-arch@vger.kernel.org
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c7a3c5da35055e2fa97ed4f0da3eec4bd0ef4c38
Author: Arnaldo Carvalho de Melo <acme@redhat.com>
Date:   Fri Mar 9 13:51:54 2007 -0800

    [UDP]: Use __skb_pull since we have checked it won't fail with pskb_may_pull
    
    Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6dea649a8a4c4b086227018c919298f988c34b30
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Thu Mar 8 22:36:37 2007 -0800

    [NET]: New sysctls should use __read_mostly tags
    
    net_msg_warn should be placed in the read_mostly section, to avoid
    performance problems on SMP
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e5268f12f26f1f51590cd1ed26547e21c46b08f2
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Thu Mar 8 20:48:23 2007 -0800

    [IPV6]: Ensure to truncate result and return full length for sticky options.
    
    Bug noticed by Chris Wright <chrisw@sous-sol.org>.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4c6510a738c71ca6b4b7b624a7d0a00acebfd7fb
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 18 17:35:57 2007 -0700

    [IPV6]: Return correct result for sticky options.
    
    We returned incorrect result with IPV6_RTHDRDSTOPTS, IPV6_RTHDR and
    IPV6_DSTOPTS.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3fbe070a4293e8ab2d2edb1bc23f1e5220ce61af
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:46:41 2007 -0800

    [UDP]: deinline
    
    A couple of functions are exported or used indirectly
    so it is pointless to mark them as inline.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6f05f629716a71d4c9c82813f45d3e9a6e90d146
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:46:03 2007 -0800

    [NET]: deinline some functions
    
    Several functions are marked inline or forced inline, but it
    would be better to let the compiler decide.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2de979bd7da9c8b39cc0aabb0ab5aa1516d929eb
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:45:19 2007 -0800

    [TCP]: whitespace cleanup
    
    Add whitespace around keywords.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 132adf54639cf7dd9315e8df89c2faa59f6e46d9
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:44:43 2007 -0800

    [IPV4]: cleanup
    
    Add whitespace around keywords.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1ac58ee37f439044eb09381f33c97ce0e7f2643b
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:43:49 2007 -0800

    [WIRELESS]: use ARRAY_SIZE()
    
    Use ARRAY_SIZE() macro now.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e71a4783aae059931f63b2d4e7013e36529badef
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Tue Apr 10 20:10:33 2007 -0700

    [NET] core: whitespace cleanup
    
    Fix whitespace around keywords. Fix indentation especially of switch
    statements.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit add459aa1afe05472abc96f6a29aefd0c84e73d6
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:42:35 2007 -0800

    [UDP]: ipv6 style cleanup
    
    Fix whitespace around keywords. Eliminate unnecessary ()'s on return
    statements.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6516c65573fde5e421c6c92c4b180bbe2245b23b
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:41:55 2007 -0800

    [UDP]: ipv4 whitespace cleanup
    
    Fix whitespace around keywords.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit a2a316fd068c455c609ecc155dcfaa7e208d29fe
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Thu Mar 8 20:41:08 2007 -0800

    [NET]: Replace CONFIG_NET_DEBUG with sysctl.
    
    Covert network warning messages from a compile time to runtime choice.
    Removes kernel config option and replaces it with new /proc/sys/net/core/warnings.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ae40eb1ef30ab4120bd3c8b7e3da99ee53d27a23
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun Mar 18 17:33:16 2007 -0700

    [NET]: Introduce SIOCGSTAMPNS ioctl to get timestamps with nanosec resolution
    
    Now network timestamps use ktime_t infrastructure, we can add a new
    ioctl() SIOCGSTAMPNS command to get timestamps in 'struct timespec'.
    User programs can thus access to nanosecond resolution.
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    CC: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cb69cc52364690d7789940c480b3a9490784b680
Author: Adrian Bunk <bunk@stusta.de>
Date:   Wed Mar 7 19:33:52 2007 -0800

    [TCP/DCCP/RANDOM]: Remove unused exports.
    
    This patch removes the following not or no longer used exports:
    - drivers/char/random.c: secure_tcp_sequence_number
    - net/dccp/options.c: sysctl_dccp_feat_sequence_window
    - net/netlink/af_netlink.c: netlink_set_err
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fe067e8ab5e0dc5ca3c54634924c628da92090b4
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Wed Mar 7 12:12:44 2007 -0800

    [TCP]: Abstract out all write queue operations.
    
    This allows the write queue implementation to be changed,
    for example, to one which allows fast interval searching.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 02ea4923b4997d7e1310c027081f46d584b9d714
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:21:31 2007 +0900

    [NET] TIPC: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b6d9bcb0697e60d5424e2f395fe950f0e22f4418
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:21:20 2007 +0900

    [NET] SCHED: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8f05ce91c8b801af106611ad83b1d8d7429b9b46
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:21:00 2007 +0900

    [NET] NETFILTER: Use htonl() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4412ec494868160d57da6e436a92b0696f40b19d
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:19:10 2007 +0900

    [NET] IPV4: Use hton{s,l}() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1c9e8ef7f731c2548414644e5bf540c38c85aff0
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:19:05 2007 +0900

    [NET] IEEE80211: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit f576e24ffaf2c6b01af389e3bad3342681a8b84f
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Mar 7 14:19:03 2007 +0900

    [NET] ETHERNET: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 724800d61b8bc574a364707b6a6c6a6252e8cdb4
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 25 20:13:04 2007 -0700

    [NET] CORE: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aca3192cc60d2bf193c2252e45563c32e3117289
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 25 20:12:50 2007 -0700

    [NET] BLUETOOTH: Use cpu_to_le{16,32}() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit acde4855bb8f5fba8bb065d35ff6ac8a94b3dfa8
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 25 20:12:32 2007 -0700

    [NET] ATM: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b93b7eebd328d5c1d171896fb823267539d4a0f6
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 25 20:12:18 2007 -0700

    [NET] 8021Q: Use htons() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 2953fd246845f4d00af3717163f37b2ff4c5ce29
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Sun Mar 25 20:11:55 2007 -0700

    [NET] 802: Use hton{s,l}() where appropriate.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 759e5d006462d53fb708daa8284b4ad909415da1
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Sun Mar 25 20:10:56 2007 -0700

    [UDP]: Clean up UDP-Lite receive checksum
    
    This patch eliminates some duplicate code for the verification of
    receive checksums between UDP-Lite and UDP.  It does this by
    introducing __skb_checksum_complete_head which is identical to
    __skb_checksum_complete_head apart from the fact that it takes
    a length parameter rather than computing the first skb->len bytes.
    
    As a result UDP-Lite will be able to use hardware checksum offload
    for packets which do not use partial coverage checksums.  It also
    means that UDP-Lite loopback no longer does unnecessary checksum
    verification.
    
    If any NICs start support UDP-Lite this would also start working
    automatically.
    
    This patch removes the assumption that msg_flags has MSG_TRUNC clear
    upon entry in recvmsg.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 1ab6eb62b02e0949a392fb19bf31ba59ae1022b1
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Tue Mar 6 20:29:58 2007 -0800

    [UDP6]: Restore sk_filter optimisation
    
    This reverts the changeset
    
        [IPV6]: UDPv6 checksum.
    
        We always need to check UDPv6 checksum because it is mandatory.
    
    The sk_filter optimisation has nothing to do whether we verify the
    checksum.  It simply postpones it to the point when the user calls
    recv or poll.
    
    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 243bbcaa09e8482aa28065cbc2eb99f0ca2fc8d6
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Tue Mar 6 20:23:10 2007 -0800

    [IPV4]: Optimize inet_getpeer()
    
    1) Some sysctl vars are declared __read_mostly
    
    2) We can avoid updating stack[] when doing an AVL lookup only.
    
        lookup() macro is extended to receive a second parameter, that may be NULL
    in case of a pure lookup (no need to save the AVL path). This removes
    unnecessary instructions, because compiler knows if this _stack parameter is
    NULL or not.
    
        text size of net/ipv4/inetpeer.o is 2063 bytes instead of 2107 on x86_64
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 43e683926f808cec9802466c27cee7499eda3d11
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Tue Mar 6 20:21:20 2007 -0800

    [TCP] TCP Yeah: cleanup
    
    Eliminate need for full 6/4/64 divide to compute queue.
    Variable maxqueue was really a constant.
    Fix indentation.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c5f5877c043ca471c3a607fa2c864848b19bc49a
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 25 20:21:15 2007 -0700

    [TCP] tcp_cubic: faster cube root
    
    The Newton-Raphson method is quadratically convergent so
    only a small fixed number of steps are necessary.
    Therefore it is faster to unroll the loop. Since div64_64 is no longer
    inline it won't cause code explosion.
    
    Also fixes a bug that can occur if x^2 was bigger than 32 bits.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8570419fb7be0af84085ac8f13307392a748482c
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Mar 6 20:19:26 2007 -0800

    [ATM] ENI: Convert to struct timeval to ktime_t.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fc910a27839584209726537698b596576940add4
Author: David S. Miller <davem@davemloft.net>
Date:   Sun Mar 25 20:27:59 2007 -0700

    [NETLINK]: Limit NLMSG_GOODSIZE to 8K.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ca043569390c528de4cd5ec9e07502f2bf4ecd1f
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Wed Feb 28 23:13:20 2007 +0900

    [IPV6] ADDRCONF: Fix possible inet6_ifaddr leakage with CONFIG_OPTIMISTIC_DAD.
    
    The inet6_ifaddr for source address of RS is leaked if the address
    is not an optimistic address.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 95c385b4d5a71b8ad552aecaa968ea46d7da2f6a
Author: Neil Horman <nhorman@tuxdriver.com>
Date:   Wed Apr 25 17:08:10 2007 -0700

    [IPV6] ADDRCONF: Optimistic Duplicate Address Detection (RFC 4429) Support.
    
    Nominally an autoconfigured IPv6 address is added to an interface in the
    Tentative state (as per RFC 2462).  Addresses in this state remain in this
    state while the Duplicate Address Detection process operates on them to
    determine their uniqueness on the network.  During this period, these
    tentative addresses may not be used for communication, increasing the time
    before a node may be able to communicate on a network.  Using Optimistic
    Duplicate Address Detection, autoconfigured addresses may be used
    immediately for communication on the network, as long as certain rules are
    followed to avoid conflicts with other nodes during the Duplicate Address
    Detection process.
    
    Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 502b093569e48db264831be7966e1c447de2f52f
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Thu Nov 30 14:43:28 2006 +0900

    [IPV6] IP6TUNNEL: Enable to control the handled inner protocol.
    
    ip6_tunnel before supporting IPv4/IPv6 tunnel allows only IPPROTO_IPV6
    in configurations from userland. This allows userland to set IPPROTO_IPIP
    and 0(wildcard). ip6_tunnel only handles allowed inner protocols.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3144581cb0b4b1ef897470195128cc1c8dc037b6
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Sat Feb 10 00:30:33 2007 +0900

    [IPV6] IP6TUNNEL: Rename functions ip6ip6_* to ip6_tnl_*.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c4d3efafcc933fd2ffd169d7dc4f980393a13796
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Thu Feb 15 00:43:16 2007 +0900

    [IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.
    
    Some notes
    - Protocol number IPPROTO_IPIP is used for IPv4 over IPv6 packets.
    - If IP6_TNL_F_USE_ORIG_TCLASS is set, TOS in IPv4 header is copied to
      Traffic Class in outer IPv6 header on xmit.
    - IP6_TNL_F_USE_ORIG_FLOWLABEL is ignored on xmit of IPv4 packets, because
      IPv4 header does not have flow label.
    - Kernel sends ICMP error if IPv4 packet is too big on xmit, even if
      DF flag is not set.
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 61ec2aec28ba8de09f76a558a5d6d3893b1d2e47
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Sun Nov 5 22:56:45 2006 +0900

    [IPV6] IP6TUNNEL: Split out generic routine in ip6ip6_xmit().
    
    This enables to add IPv4/IPv6 specific handling later,
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 8359925be8bb5960f614e3f25454f3ef7cc9df65
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Fri Nov 3 09:39:14 2006 +0900

    [IPV6] IP6TUNNEL: Split out generic routine in ip6ip6_rcv().
    
    This enables to add IPv4/IPv6 specific handling later,
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e490d1d85cf5e191791979e5f260d32eb4f703a8
Author: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Date:   Tue Oct 31 23:11:25 2006 +0900

    [IPV6] IP6TUNNEL: Split out generic routine in ip6ip6_err().
    
    This enables to add IPv4/IPv6 specific error handling later,
    
    Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7159039a128fa0a73ca7b532f6e1d30d9885277f
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Thu Feb 22 22:05:40 2007 +0900

    [IPV6]: Decentralize EXPORT_SYMBOLs.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

commit b558ff799977a4eda8b3823d1cf6c1c33becb671
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Tue Mar 6 17:02:35 2007 -0800

    [NETLINK]: Mirror UDP MSG_TRUNC semantics.
    
    If the user passes MSG_TRUNC in via msg_flags, return
    the full packet size not the truncated size.
    
    Idea from Herbert Xu and Thomas Graf.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit b7aa0bf70c4afb9e38be25f5c0922498d0f8684c
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Thu Apr 19 16:16:32 2007 -0700

    [NET]: convert network timestamps to ktime_t
    
    We currently use a special structure (struct skb_timeval) and plain
    'struct timeval' to store packet timestamps in sk_buffs and struct
    sock.
    
    This has some drawbacks :
    - Fixed resolution of micro second.
    - Waste of space on 64bit platforms where sizeof(struct timeval)=16
    
    I suggest using ktime_t that is a nice abstraction of high resolution
    time services, currently capable of nanosecond resolution.
    
    As sizeof(ktime_t) is 8 bytes, using ktime_t in 'struct sock' permits
    a 8 byte shrink of this structure on 64bit architectures. Some other
    structures also benefit from this size reduction (struct ipq in
    ipv4/ip_fragment.c, struct frag_queue in ipv6/reassembly.c, ...)
    
    Once this ktime infrastructure adopted, we can more easily provide
    nanosecond resolution on top of it. (ioctl SIOCGSTAMPNS and/or
    SO_TIMESTAMPNS/SCM_TIMESTAMPNS)
    
    Note : this patch includes a bug correction in
    compat_sock_get_timestamp() where a "err = 0;" was missing (so this
    syscall returned -ENOENT instead of 0)
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    CC: Stephen Hemminger <shemminger@linux-foundation.org>
    CC: John find <linux.kernel@free.fr>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3927f2e8f9afa3424bb51ca81f7abac01ffd0005
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 25 19:54:23 2007 -0700

    [NET]: div64_64 consolidate (rev3)
    
    Here is the current version of the 64 bit divide common code.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9d729f72dca9406025bcfa9c1f660d71d9ef0ff5
Author: James Morris <jmorris@namei.org>
Date:   Sun Mar 4 16:12:44 2007 -0800

    [NET]: Convert xtime.tv_sec to get_seconds()
    
    Where appropriate, convert references to xtime.tv_sec to the
    get_seconds() helper function.
    
    Signed-off-by: James Morris <jmorris@namei.org>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 39df232f1a9ba48d41c68ee7d4046756e709cf91
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 4 16:11:51 2007 -0800

    [PKTGEN]: fix device name handling
    
    Since devices can change name and other wierdness, don't hold onto
    a copy of device name, instead use pointer to output device.
    
    Fix a couple of leaks in error handling path as well.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d5f1ce9a5e80fb315c86b036a89b1237fdf11938
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 4 16:08:08 2007 -0800

    [PKTGEN]: don't use __constant_htonl()
    
    The existing htonl() macro is smart enough to do the same code as
    using __constant_htonl() and it looks cleaner.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5fa6fc76f55c5c42fff52ae1d57a685b9373fcdc
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 4 16:07:28 2007 -0800

    [PKTGEN]: use random32
    
    Can use random32() now.
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 25c4e53a4c9bfe45be52821f54ec5ce957519db2
Author: Stephen Hemminger <shemminger@linux-foundation.org>
Date:   Sun Mar 4 16:06:47 2007 -0800

    [PKTGEN]: use pr_debug
    
    Remove private debug macro and replace with standard version
    
    Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
    Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit fa438ccfdfd3f6db02c13b61b21454eb81cd6a13
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Sun Mar 4 16:05:44 2007 -0800

    [NET]: Keep sk_backlog near sk_lock
    
    sk_backlog is a critical field of struct sock. (known famous words)
    
    It is (ab)used in hot paths, in particular in release_sock(), tcp_recvmsg(),
    tcp_v4_rcv(), sk_receive_skb().
    
    It really makes sense to place it next to sk_lock, because sk_backlog is only
    used after sk_lock locked (and thus memory cache line in L1 cache). This
    should reduce cache misses and sk_lock acquisition time.
    
    (In theory, we could only move the head pointer near sk_lock, and leaving tail
    far away, because 'tail' is normally not so hot, but keep it simple :) )
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e317f6f69cb95527799d308a9421b7dc1252989a
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Fri Mar 2 13:34:19 2007 -0800

    [TCP]: FRTO undo response falls back to ratehalving one if ECEd
    
    Undoing ssthresh is disabled in fastretrans_alert whenever
    FLAG_ECE is set by clearing prior_ssthresh. The clearing does
    not protect FRTO because FRTO operates before fastretrans_alert.
    Moving the clearing of prior_ssthresh earlier seems to be a
    suboptimal solution to the FRTO case because then FLAG_ECE will
    cause a second ssthresh reduction in try_to_open (the first
    occurred when FRTO was entered). So instead, FRTO falls back
    immediately to the rate halving response, which switches TCP to
    CA_CWR state preventing the latter reduction of ssthresh.
    
    If the first ECE arrived before the ACK after which FRTO is able
    to decide RTO as spurious, prior_ssthresh is already cleared.
    Thus no undoing for ssthresh occurs. Besides, FLAG_ECE should be
    set also in the following ACKs resulting in rate halving response
    that sees TCP is already in CA_CWR, which again prevents an extra
    ssthresh reduction on that round-trip.
    
    If the first ECE arrived before RTO, ssthresh has already been
    adapted and prior_ssthresh remains cleared on entry because TCP
    is in CA_CWR (the same applies also to a case where FRTO is
    entered more than once and ECE comes in the middle).
    
    High_seq must not be touched after tcp_enter_cwr because CWR
    round-trip calculation depends on it.
    
    I believe that after this patch, FRTO should be ECN-safe and
    even able to take advantage of synergy benefits.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e01f9d7793be82e6c252efbd52c399d3eb65abe4
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Fri Mar 2 13:27:25 2007 -0800

    [TCP]: Complete icsk-to-local-variable change (in tcp_enter_cwr)
    
    A local variable for icsk was created but this change was
    missing. Spotted by Jarek Poplawski.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 89808060b7a71376cc2ba8092d43b2010da465b6
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Tue Feb 27 10:10:55 2007 -0800

    [TCP] Sysctl documentation: tcp_frto_response
    
    In addition, fixed minor things in tcp_frto sysctl.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 3cfe3baaf07c9e40a75f9a70662de56df1c246a8
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Tue Feb 27 10:09:49 2007 -0800

    [TCP]: Add two new spurious RTO responses to FRTO
    
    New sysctl tcp_frto_response is added to select amongst these
    responses:
    	- Rate halving based; reuses CA_CWR state (default)
    	- Very conservative; used to be the only one available (=1)
    	- Undo cwr; undoes ssthresh and cwnd reductions (=2)
    
    The response with rate halving requires a new parameter to
    tcp_enter_cwr because FRTO has already reduced ssthresh and
    doing a second reduction there has to be prevented. In addition,
    to keep things nice on 80 cols screen, a local variable was
    added.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit c5e7af0df5d7234afd8596560d9f570cfc6c18bf
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Fri Feb 23 16:22:06 2007 -0800

    [TCP]: Correct reordering detection change (no FRTO case)
    
    The reordering detection must work also when FRTO has not been
    used at all which was the original intention of mine, just the
    expression of the idea was flawed.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit e0ef57cc56c3c96493f9b0d6c77bb9608eeaa173
Author: David S. Miller <davem@sunset.davemloft.net>
Date:   Thu Feb 22 22:52:59 2007 -0800

    [TCP]: Make snd_cwnd_clamp a u32.
    
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 54287cc178cf85dbae0decec8b4dc190bff757ad
Author: Eric Dumazet <dada1@cosmosbay.com>
Date:   Thu Feb 22 03:20:44 2007 -0800

    [TCP]: Keep copied_seq, rcv_wup and rcv_next together.
    
    I noticed in oprofile study a cache miss in tcp_rcv_established() to read
    copied_seq.
    
    ffffffff80400a80 <tcp_rcv_established>: /* tcp_rcv_established total: 4034293 Â 
    2.0400 */
    
    Â 55493 Â 0.0281 :ffffffff80400bc9: Â  mov Â  Â 0x4c8(%r12),%eax copied_seq
    543103 Â 0.2746 :ffffffff80400bd1: Â  cmp Â  Â 0x3e0(%r12),%eax Â  rcv_nxt Â  Â 
    
    if (tp->copied_seq == tp->rcv_nxt &&
    Â Â Â Â Â Â Â Â len - tcp_header_len <= tp->ucopy.len) {
    
    In this function, the cache line 0x4c0 -> 0x500 is used only for this
    reading 'copied_seq' field.
    
    rcv_wup and copied_seq should be next to rcv_nxt field, to lower number of
    active cache lines in hot paths. (tcp_rcv_established(), tcp_poll(), ...)
    
    As you suggested, I changed tcp_create_openreq_child() so that these fields
    are changed together, to avoid adding a new store buffer stall.
    
    Patch is 64bit friendly (no new hole because of alignment constraints)
    
    Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit cf4c6bf83d0fa070f60b1ba8124dfe0e65fbfbcc
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Thu Feb 22 01:13:58 2007 -0800

    [TCP]: struct *sock argument renamed: sp -> sk
    
    In general, TCP code uses "sk" for struct sock pointer.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 886236c1247ab5e2ad9c73f6e9a652e3ae3c8b07
Author: John Heffner <jheffner@psc.edu>
Date:   Sun Mar 25 19:21:45 2007 -0700

    [TCP]: Add RFC3742 Limited Slow-Start, controlled by variable sysctl_tcp_max_ssthresh.
    
    Signed-off-by: John Heffner <jheffner@psc.edu>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 5ef814753eb810d900fbd77af7c87f6d04f0e551
Author: Angelo P. Castellani <angelo.castellani@gmail.con>
Date:   Thu Feb 22 00:23:05 2007 -0800

    [TCP] YeAH-TCP: algorithm implementation
    
    YeAH-TCP is a sender-side high-speed enabled TCP congestion control
    algorithm, which uses a mixed loss/delay approach to compute the
    congestion window. It's design goals target high efficiency, internal,
    RTT and Reno fairness, resilience to link loss while keeping network
    elements load as low as possible.
    
    For further details look here:
        http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf
    
    Signed-off-by: Angelo P. Castellani <angelo.castellani@gmail.con>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 127af0c44fc916908abd145914d65b9fe598bcd7
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:16:38 2007 -0800

    [TCP] FRTO: Sysctl documentation for SACK enhanced version
    
    The description is overly verbose to avoid ambiguity between
    "SACK enabled" and "SACK enhanced FRTO"
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 4dc2665e3634d720a62bd27128fc8781fcdad2dc
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:16:11 2007 -0800

    [TCP]: SACK enhanced FRTO
    
    Implements the SACK-enhanced FRTO given in RFC4138 using the
    variant given in Appendix B.
    
    RFC4138, Appendix B:
      "This means that in order to declare timeout spurious, the TCP
       sender must receive an acknowledgment for non-retransmitted
       segment between SND.UNA and RecoveryPoint in algorithm step 3.
       RecoveryPoint is defined in conservative SACK-recovery
       algorithm [RFC3517]"
    
    The basic version of the FRTO algorithm can still be used also
    when SACK is enabled. To enabled SACK-enhanced version, tcp_frto
    sysctl is set to 2.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 288035f915686a9a9e85e0358c5392bb5d7ae58d
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:14:42 2007 -0800

    [TCP]: Prevent reordering adjustments during FRTO
    
    To be honest, I'm not too sure how the reord stuff works in the
    first place but this seems necessary.
    
    When FRTO has been active, the one and only retransmission could
    be unnecessary but the state and sending order might not be what
    the sacktag code expects it to be (to work correctly).
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 66e93e45c09affa407750cc06398492e8b897848
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:13:47 2007 -0800

    [TCP] FRTO: Fake cwnd for ssthresh callback
    
    TCP without FRTO would be in Loss state with small cwnd. FRTO,
    however, leaves cwnd (typically) to a larger value which causes
    ssthresh to become too large in case RTO is triggered again
    compared to what conventional recovery would do. Because
    consecutive RTOs result in only a single ssthresh reduction,
    RTO+cumulative ACK+RTO pattern is required to trigger this
    event.
    
    A large comment is included for congestion control module writers
    trying to figure out what CA_EVENT_FRTO handler should do because
    there exists a remote possibility of incompatibility between
    FRTO and module defined ssthresh functions.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit d1a54c6a0a3f9c2c4ef71982d89b8571bd9eaa51
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:11:57 2007 -0800

    [TCP] FRTO: Reverse RETRANS bit clearing logic
    
    Previously RETRANS bits were cleared on the entry to FRTO. We
    postpone that into tcp_enter_frto_loss, which is really the
    place were the clearing should be done anyway. This allows
    simplification of the logic from a clearing loop to the head skb
    clearing only.
    
    Besides, the other changes made in the previous patches to
    tcp_use_frto made it impossible for the non-SACKed FRTO to be
    entered if other than the head has been rexmitted.
    
    With SACK-enhanced FRTO (and Appendix B), however, there can be
    a number retransmissions in flight when RTO expires (same thing
    could happen before this patchset also with non-SACK FRTO). To
    not introduce any jumpiness into the packet counting during FRTO,
    instead of clearing RETRANS bits from skbs during entry, do it
    later on.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 46d0de4ed92650b95f27acae09914996bbe624e7
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:10:39 2007 -0800

    [TCP] FRTO: Entry is allowed only during (New)Reno like recovery
    
    This interpretation comes from RFC4138:
        "If the sender implements some loss recovery algorithm other
         than Reno or NewReno [FHG04], the F-RTO algorithm SHOULD
         NOT be entered when earlier fast recovery is underway."
    
    I think the RFC means to say (especially in the light of
    Appendix B) that ...recovery is underway (not just fast recovery)
    or was underway when it was interrupted by an earlier (F-)RTO
    that hasn't yet been resolved (snd_una has not advanced enough).
    Thus, my interpretation is that whenever TCP has ever
    retransmitted other than head, basic version cannot be used
    because then the order assumptions which are used as FRTO basis
    do not hold.
    
    NewReno has only the head segment retransmitted at a time.
    Therefore, walk up to the segment that has not been SACKed, if
    that segment is not retransmitted nor anything before it, we know
    for sure, that nothing after the non-SACKed segment should be
    either. This assumption is valid because TCPCB_EVER_RETRANS does
    not leave holes but each non-SACKed segment is rexmitted
    in-order.
    
    Check for retrans_out > 1 avoids more expensive walk through the
    skb list, as we can know the result beforehand: F-RTO will not be
    allowed.
    
    SACKed skb can turn into non-SACked only in the extremely rare
    case of SACK reneging, in this case we might fail to detect
    retransmissions if there were them for any other than head. To
    get rid of that feature, whole rexmit queue would have to be
    walked (always) or FRTO should be prevented when SACK reneging
    happens. Of course RTO should still trigger after reneging which
    makes this issue even less likely to show up. And as long as the
    response is as conservative as it's now, nothing bad happens even
    then.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7c9a4a5b67926dd186d427bc5b9fce6ccbde154c
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:08:34 2007 -0800

    [TCP]: Prevent unrelated cwnd adjustment while using FRTO
    
    FRTO controls cwnd when it still processes the ACK input or it
    has just reverted back to conventional RTO recovery; the normal
    rules apply when FRTO has reverted to standard congestion
    control.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 94d0ea7786714d78d7cb73144bb850254dd0bb78
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:07:27 2007 -0800

    [TCP] FRTO: frto_counter modulo-op converted to two assignments
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 52c63f1e86ebb18ef4b710b5b647e552a041e5ca
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:06:52 2007 -0800

    [TCP]: Don't enter to fast recovery while using FRTO
    
    Because TCP is not in Loss state during FRTO recovery, fast
    recovery could be triggered by accident. Non-SACK FRTO is more
    robust than not yet included SACK-enhanced version (that can
    receiver high number of duplicate ACKs with SACK blocks during
    FRTO), at least with unidirectional transfers, but under
    extraordinary patterns fast recovery can be incorrectly
    triggered, e.g., Data loss+ACK losses => cumulative ACK with
    enough SACK blocks to meet sacked_out >= dupthresh condition).
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit aa8b6a7ad147dfbaaf10368ff15df9418b670d8b
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:06:03 2007 -0800

    [TCP] FRTO: Response should reset also snd_cwnd_cnt
    
    Since purpose is to reduce CWND, we prevent immediate growth. This
    is not a major issue nor is "the correct way" specified anywhere.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 95c4922bf9330eb2c71b752359dd89c4e166f3c5
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:05:18 2007 -0800

    [TCP] FRTO: fixes fallback to conventional recovery
    
    The FRTO detection did not care how ACK pattern affects to cwnd
    calculation of the conventional recovery. This caused incorrect
    setting of cwnd when the fallback becames necessary. The
    knowledge tcp_process_frto() has about the incoming ACK is now
    passed on to tcp_enter_frto_loss() in allowed_segments parameter
    that gives the number of segments that must be added to
    packets-in-flight while calculating the new cwnd.
    
    Instead of snd_una we use FLAG_DATA_ACKED in duplicate ACK
    detection because RFC4138 states (in Section 2.2):
      If the first acknowledgment after the RTO retransmission
      does not acknowledge all of the data that was retransmitted
      in step 1, the TCP sender reverts to the conventional RTO
      recovery.  Otherwise, a malicious receiver acknowledging
      partial segments could cause the sender to declare the
      timeout spurious in a case where data was lost.
    
    If the next ACK after RTO is duplicate, we do not retransmit
    anything, which is equal to what conservative conventional
    recovery does in such case.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 6408d206c7484615ecae54bf6474a02c94e9e862
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:04:11 2007 -0800

    [TCP] FRTO: Ignore some uninteresting ACKs
    
    Handles RFC4138 shortcoming (in step 2); it should also have case
    c) which ignores ACKs that are not duplicates nor advance window
    (opposite dir data, winupdate).
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7b0eb22b1d3b049306813a4aaa52966650f7491c
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:03:35 2007 -0800

    [TCP] FRTO: Use Disorder state during operation instead of Open
    
    Retransmission counter assumptions are to be changed. Forcing
    reason to do this exist: Using sysctl in check would be racy
    as soon as FRTO starts to ignore some ACKs (doing that in the
    following patches). Userspace may disable it at any moment
    giving nice oops if timing is right. frto_counter would be
    inaccessible from userspace, but with SACK enhanced FRTO
    retrans_out can include other than head, and possibly leaving
    it non-zero after spurious RTO, boom again.
    
    Luckily, solution seems rather simple: never go directly to Open
    state but use Disorder instead. This does not really change much,
    since TCP could anyway change its state to Disorder during FRTO
    using path tcp_fastretrans_alert -> tcp_try_to_open (e.g., when
    a SACK block makes ACK dubious). Besides, Disorder seems to be
    the state where TCP should be if not recovering (in Recovery or
    Loss state) while having some retransmissions in-flight (see
    tcp_try_to_open), which is exactly what happens with FRTO.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 7487c48c4fd15d1e2542be1183b783562cfe10bc
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:02:30 2007 -0800

    [TCP] FRTO: Consecutive RTOs keep prior_ssthresh and ssthresh
    
    In case a latency spike causes more than one RTO, the later should not
    cause the already reduced ssthresh to propagate into the prior_ssthresh
    since FRTO declares all such RTOs spurious at once or none of them. In
    treating of ssthresh, we mimic what tcp_enter_loss() does.
    
    The previous state (in frto_counter) must be available until we have
    checked it in tcp_enter_frto(), and also ACK information flag in
    process_frto().
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 30935cf4f915c3178ce63331d6ff4c82163e26af
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 23:01:36 2007 -0800

    [TCP] FRTO: Comment cleanup & improvement
    
    Moved comments out from the body of process_frto() to the head
    (preferred way; see Documentation/CodingStyle). Bonus: it's much
    easier to read in this compacted form.
    
    FRTO algorithm and implementation is described in greater detail.
    For interested reader, more information is available in RFC4138.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit bdaae17da81db79b9aa4dfbf43305cfeef64f6a8
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 22:59:58 2007 -0800

    [TCP] FRTO: Moved tcp_use_frto from tcp.h to tcp_input.c
    
    In addition, removed inline.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 9ead9a1d385ae2c52a6dcf2828d84ce66be04fc2
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 22:56:19 2007 -0800

    [TCP] FRTO: Separated response from FRTO detection algorithm
    
    FRTO spurious RTO detection algorithm (RFC4138) does not include response
    to a detected spurious RTO but can use different response algorithms.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit 522e7548a9bd40305df41c0beae69448b7620d6b
Author: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
Date:   Wed Feb 21 22:54:52 2007 -0800

    [TCP] FRTO: Incorrectly clears TCPCB_EVER_RETRANS bit
    
    FRTO was slightly too brave... Should only clear
    TCPCB_SACKED_RETRANS bit.
    
    Signed-off-by: Ilpo JÃ¤rvinen <ilpo.jarvinen@helsinki.fi>
    Signed-off-by: David S. Miller <davem@davemloft.net>

commit ce7dd06372058f9e3e57ee4c0aeba694a43a80ad
Author: Wang Zhenyu <zhenyu.z.wang@intel.com>
Date:   Thu Apr 26 07:42:56 2007 +1000

    drm/i915: Add 965GM pci id update
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit afd3810d9b6b0d446a34e1d4e94f0cc020b00a14
Author: Zachary Amsden <zach@vmware.com>
Date:   Wed Apr 25 15:32:23 2007 -0400

    ACPI: Remove a warning about unused variable in !CONFIG_ACPI compilation.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Cc: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b2983f10f87423fab92326bbe1e92e2256573d4f
Author: Thierry Vignaud <tvignaud@mandriva.com>
Date:   Wed Apr 25 15:31:30 2007 -0400

    ACPI: prevent ACPI quirk warning mass spamming in logs
    
    The following patch prevent this warning to be displayed again & again (eg:
    nine times on my NForce2 motherboard) and thus improve signal to noise
    ratio in logs.
    
    The ATI quirk below probably needs a similar "fix" but I don't have
    the hardware to test.
    
    Btw arch/x86_64/kernel/early-quirks.c::nvidia_bugs() would probably need to
    be synced (but I don't have an x86_64 NVidia motherboard to boot test it).
    Still it shows the usefullity of the recent x86 merge thread.
    
    [akpm@linux-foundation.org: cleanup]
    Signed-off-by: Thierry Vignaud <tvignaud@mandriva.com>
    Signed-off-by: Andi Kleen <ak@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 8aa55591bfea25c441117e82711cbfd7c274250a
Author: David Brownell <david-b@pacbell.net>
Date:   Wed Apr 25 15:20:10 2007 -0400

    ACPI: make /proc/acpi/wakeup more useful
    
    This updates /proc/acpi/wakeup to be more informative, primarily by showing
    the sysfs node associated with each wakeup-enabled device.  Example:
    
    	Device	S-state	  Status   Sysfs node
    	PCI0	  S4	 disabled  no-bus:pci0000:00
    	PS2M	  S4	 disabled  pnp:00:05
    	PS2K	  S4	 disabled  pnp:00:06
    	UAR1	  S4	 disabled  pnp:00:08
    	USB1	  S3	 disabled  pci:0000:00:03.0
    	USB2	  S3	 disabled  pci:0000:00:03.1
    	USB3	  S3	 disabled
    	USB4	  S3	 disabled  pci:0000:00:03.3
    	S139	  S4	 disabled
    	LAN	  S4	 disabled  pci:0000:00:04.0
    	MDM	  S4	 disabled
    	AUD	  S4	 disabled  pci:0000:00:02.7
    	SLPB	  S4	*enabled
    
    Eventually this file should be removed, but until then it's almost the only
    way we have to tell how the relevant ACPI tables are broken (and cope).  In
    that example, two devices don't actually exist (USB3, S139), one can't issue
    wakeup events (PCI0), and two seem harmlessly (?) confused (MDM and AUD are
    the same PCI device, but it's the _modem_ that does wake-on-ring).
    
    In particular, we need to be sure driver model nodes are properly hooked
    up before we can get rid of this ACPI-only interface for wakeup events.
    
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit cf6c6045a06aed2ccd8ebd0a3128ce0f2f8a11aa
Author: Borislav Petkov <bbpetkov@yahoo.de>
Date:   Wed Apr 25 14:29:50 2007 -0400

    ACPI: word-smith kconfig help
    
    Signed-off-by: <bbpetkov@yahoo.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 8ce8e2f99a973c39c4aeddbe0966038196a8e71a
Author: Daniel Walker <dwalker@mvista.com>
Date:   Wed Apr 25 14:27:06 2007 -0400

    ACPI: correct pathname in comment
    
    Signed-off-by: Daniel Walker <dwalker@mvista.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 0c0e8921018dbb4fe189a1034f80ac32553bc7bc
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Wed Apr 25 14:20:58 2007 -0400

    ACPI: use _STA bit names rather than 0x0F
    
    Be explicit about what "device->status = 0x0F" really means.
    
    syntax only.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit a0bd4ac498acfe60f7533d15ba60d5efdd4e9ca5
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Wed Apr 25 14:17:39 2007 -0400

    ACPI: Remove duplicate definitions for _STA bits
    
    No need to duplicate the existing definitions in include/acpi/actypes.h.
    
    syntax only -- no functional change.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d8938801d10945ac2fbe0f41ded43f6276660a17
Author: Ray Lee <ray-lk@madrabbit.org>
Date:   Wed Apr 25 14:12:00 2007 -0400

    ACPI: remove duplicate include
    
    Thomas's patch for including <asm/apic.h> for x86 UP builds came into
    Linus's tree from two different directions, both of which were merged.
    This reverts the latter, yanking out the duplicate #include and comment.
    
    Signed-off-by: Ray Lee <ray-lk@madrabbit.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 61c4b23770d1b0cef7c06a23378ab544eb0c64b4
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Wed Apr 25 17:04:23 2007 +0100

    [JFFS2] Handle inodes with only a single metadata node with non-zero isize
    
    This should never happen unless there's corruption on the medium and the
    actual data nodes go missing. But the failure mode (an oops when we assume
    the fragtree isn't empty and go looking for its last node) isn't useful.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 3e2221c73cba7d33fd5706f9bc4906ffaf421478
Author: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Date:   Wed Apr 25 09:36:20 2007 -0500

    Copy i_flags to jfs inode flags on write
    
    This mirrors Jan Kara's patches for ext3.  This patch makes sure that
    changes made to inode->i_flags are reflected on disk for jfs.  It also
    moves a call of jfs_set_inode_flags() to be more consistent with where
    jfs_get_inode_flags() is called.
    
    Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>

commit c00c310eac04a28d2143368ae988716792ed53ce
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Wed Apr 25 14:16:47 2007 +0100

    [JFFS2] Tidy up licensing/copyright boilerplate.
    
    In particular, remove the bit in the LICENCE file about contacting
    Red Hat for alternative arrangements. Their errant IS department broke
    that arrangement a long time ago -- the policy of collecting copyright
    assignments from contributors came to an end when the plug was pulled on
    the servers hosting the project, without notice or reason.
    
    We do still dual-license it for use with eCos, with the GPL+exception
    licence approved by the FSF as being GPL-compatible. It's just that nobody
    has the right to license it differently.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit eaa33a9ac04cf5760cf4e661241db19f4151cf06
Author: vignesh <vignesh.babu@wipro.com>
Date:   Wed Apr 25 12:13:48 2007 +0000

    [CIFS] Replace kmalloc/memset combination with kzalloc
    
    Signed-off-by: Vignesh Babu <vignesh.babu@wipro.com>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 5858ae44e289ac6c809af3fe81b9a6ed41914d41
Author: Steve French <sfrench@us.ibm.com>
Date:   Wed Apr 25 11:59:10 2007 +0000

    [CIFS]  Add IPv6 support
    
    IPv6 support was started a few years ago in the cifs client, but lacked a
    kernel helper function for parsing the ascii form of the ipv6 address. Now
    that that is added (and now IPv6 is the default that some OS use now) it
    was fairly easy to finish  the cifs ipv6 support.  This  requires that
    CIFS_EXPERIMENTAL be enabled and (at least until the mount.cifs module is
    modified to use a new ipv6 friendly call instead of gethostbyname) and the
    ipv6 address be passed on the mount as "ip=" mount option.
    
    Thanks
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit cbac3cba66ab51492da53e7bf4f38da872408065
Author: Steve French <sfrench@us.ibm.com>
Date:   Wed Apr 25 11:46:06 2007 +0000

    [CIFS] New CIFS POSIX mkdir performance improvement (part 2)
    
    Fix incorrect parsing of return data
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit c36c46d53b2f95bfcbe992cfb541a78ab92310a4
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Fri Mar 23 17:16:22 2007 +0900

    [MTD] [OneNAND] Exit loop only when column start with 0
    
    The JFFS2 requests OOB function from column 0.
    But the oobtest in nand-tests doesn't.
    So we only exit loop only when column start with 0.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit ad286343665cad2135792bcf53117d8344f64b03
Author: Kyungmin Park <kyungmin.park@samsung.com>
Date:   Fri Mar 23 10:19:52 2007 +0900

    [MTD] [OneNAND] Fix access the past of the real oobfree array
    
    Here it's not the case: all the entries are occupied by
    OOB chunks. Therefore, once we get into a loop like
    
            for (free = this->ecclayout->oobfree; free->length; ++free) {
    	}
    
    we might end up scanning past the real oobfree array.
    
    Probably the best way out, as the same thing might happen for common NAND
    as well, is to check index against MTD_MAX_OOBFREE_ENTRIES.
    
    Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit c19df27ec7f8b184db867c4490d87f997fdc6e4e
Author: Kyungmin Park <kyungmin.park@samsung.com>
Date:   Wed Apr 25 11:05:48 2007 +0100

    [MTD] [OneNAND] Update Samsung OneNAND official URL
    
    Update Samsung OneNAND official URL.
    
    Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 7d5a015eece8be9186d3613d595643a520555e33
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:20 2007 -0300

    ACPI: thinkpad-acpi: update brightness sysfs interface support
    
    Update the brightness sysfs interface (done through the backlight class) to
    be in line with the rest of the thinkpad-acpi driver.
    
    This renames the incorrect, un-obvious, and clash-prone name of "ibm" for
    the backlight device to a much more fitting and descriptive
    "thinkpad_screen".  This is something I wanted to do for quite a while...
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b616004c70dd7f60a1477c3e9d6fddd00ee1fa37
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:19 2007 -0300

    ACPI: thinkpad-acpi: add sysfs support to the cmos command subdriver
    
    Add sysfs attributes to send ThinkPad CMOS commands.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit eaa7571b2d1a08873e4bdd8e6db3431df61cd9ad
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:18 2007 -0300

    ACPI: thinkpad-acpi: add a safety net for TPEC fan control mode
    
    The Linux ThinkPad community is not positive that all ThinkPads that do
    HFSP EC fan control do implement full-speed and auto modes, some of the
    earlier ones supporting HFSP might not.
    
    If the EC ignores the AUTO or FULL-SPEED bits, it will pay attention to the
    lower three bits that set the fan level.  And as thinkpad-acpi was leaving
    these set to zero, it would stop(!) the fan, which is Not A Good Thing.
    
    So, as a safety net, we now make sure to also set the fan level part of the
    HFSP register to speed 7 for full-speed, and a minimum of speed 4 for auto
    mode.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit fe98a52ce7540fb3a19d57488a08864110cf4d5c
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:17 2007 -0300

    ACPI: thinkpad-acpi: add sysfs support to fan subdriver
    
    Export sysfs attributes to monitor and control the internal thinkpad fan
    (some thinkpads have more than one fan, but thinkpad-acpi doesn't support
    the second fan yet).  The sysfs interface follows the hwmon design guide
    for fan devices.
    
    Also, fix some stray "thermal" files in the fan procfs description that
    have been there forever, and officially support "full-speed" as the name
    for the PWM-disabled state of the fan controller to keep it in line with
    the hwmon interface.  It is much better a name for that mode than the
    unobvious "disengaged" anyway.  Change the procfs interface to also accept
    full-speed as a fan level, but still report it as disengaged for backwards
    compatibility.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 2c37aa4e22dd55070c608290c5031f2ee93e69ce
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:16 2007 -0300

    ACPI: thinkpad-acpi: add sysfs support to the thermal subdriver
    
    Export thinkpad thermal sensors to sysfs, following the hwmon
    specification for thermal monitoring sensors.
    
    ThinkPad thermal monitoring is done by the EC.  Sensors can show up or
    disappear at runtime when they are inside hotswappable hardware, such as
    batteries.  Sensors that are not available return -ENXIO when accessed.
    
    Up to 16 thermal sensors are supported on new firmware (but nobody has
    reported a ThinkPad with more than 12 sensors so far), and 8 sensors are
    supported on older firmware.  Thermal sensor mapping is model-specific.
    Precision varies, it is 1 degree Celcius on new ThinkPads, but higher on
    some older models.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 40ca9fdf8aa7d929e2b8939be1e6380d107381e1
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:15 2007 -0300

    ACPI: thinkpad-acpi: protect fan and hotkey data structures
    
    Add proper mutex locking to some data structures access subject to races
    due to concurrent access of driver functions on the hotkey and fan
    subdrivers.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 7252374a39d794879f5e47bcfa0a16e7599b27b5
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:14 2007 -0300

    ACPI: thinkpad-acpi: add infrastructure for the sysfs device attributes
    
    Add infrastructure to deal with sysfs attributes and grouping, and helpers
    for common sysfs parsing.  Switch driver attributes to use them.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 176750d68801bfa4a88d1cf54174aa0347d7e5d8
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:13 2007 -0300

    ACPI: thinkpad-acpi: driver sysfs conversion
    
    Add the sysfs attributes for the platform driver.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 54ae15014c306b3d7ad32c996fea9a5ac8560b60
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Tue Apr 24 11:48:12 2007 -0300

    ACPI: thinkpad-acpi: register with the device model
    
    Register thinkpad-acpi platform driver and platform device for the device
    model.  Also register the platform device with the hwmon class.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit f989106cac719f8fe91da7734e73b3ca09146ecc
Author: Zhang Rui <rui.zhang@intel.com>
Date:   Tue Apr 24 13:53:22 2007 +0800

    ACPI: Improve acpi debug documentation
    
    Now we use acpi.debug_level and acpi.debug_layer as kernel boot
    parameters instead of acpi_dbg_level and acpi_dbg_layer.
    Thanks to Andi Kleen for pointing it out.
    
    Signed-off-by: Zhang Rui <rui.zhang@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit f8993aff8b4de0317c6e081802ca5c86c449fef2
Author: Shaohua Li <shaohua.li@intel.com>
Date:   Wed Apr 25 11:05:12 2007 +0800

    ACPI: Disable MSI on request of FADT
    
    The ACPI spec defines the bit and Microsoft uses it,
    so Linux must use it too.
    
    Signed-off-by: Shaohua Li <shaohua.li@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 534565f254490227e3bec20d50f387800960acd9
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Apr 25 00:53:18 2007 -0400

    Input: add input_set_capability() helper
    
    Add input_set_capability() helper used to indicate that an input
    device supports a certain event without need to manipulate bitmaps
    directly.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit b9973954c5f3264a2afa6ec357adb542f4b76e06
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Apr 25 00:40:53 2007 -0400

    Input: i8042 - add Fujitsu touchscreen/touchpad PNP IDs
    
    Add PNP IDs for Fujitsu touchscreen/touchpad for AUX port
    detection to latch onto.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit cc8310e33b0439b43cdb19de55b2507cb27bd229
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Apr 25 00:40:32 2007 -0400

    Input: i8042 - add Panasonic CF-29 to nomux list
    
    There is no data coming from touchscreen on Panasonic CF-29
    notebook unless keyboard controller is in legacy mode.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 2ebdcc615bde8317058d76ce1f24a67f59185884
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Apr 25 00:39:53 2007 -0400

    Input: lifebook - split into 2 devices
    
    Have lifebook protocol register 2 separate input devices -
    one for the touchscreen reporting absolute coordinates and
    touches and another one for touchpad reporting relative
    coordinates and left and right button presses.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 43887ba15a0c1e293be63793541fe444778c0474
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Apr 25 00:39:31 2007 -0400

    Input: lifebook - add signature of Panasonic CF-29
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 1912ffbb88efe872eb8fa8113dfb3cb0b7238764
Author: Joachim Fenkes <fenkes@de.ibm.com>
Date:   Mon Apr 23 18:20:27 2007 +0200

    IB: Set class_dev->dev in core for nice device symlink
    
    All RDMA drivers except ehca set class_dev->dev to their dma_device
    value (ehca leaves this unset).  dma_device is the only value that
    makes any sense, so move this assignment to core/sysfs.c.  This reduce
    the duplicated code in the rest of the drivers and gives ehca a nice
    /sys/class/infiniband/ehcaX/device symlink.
    
    Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit c4ed790dfd4b2182c76e0fcd79d4aa85ab02eccf
Author: Joachim Fenkes <fenkes@de.ibm.com>
Date:   Tue Apr 24 17:44:31 2007 +0200

    IB/ehca: Implement modify_port
    
    Add "Modify Port" verb support to eHCA driver.  The IB communication
    manager needs this to set the IsCM port capability bit when
    initializing.
    
    Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit bd8031b49a9b05933fb1ec1c36620ed4e1e67793
Author: Hal Rosenstock <halr@voltaire.com>
Date:   Tue Apr 24 21:30:38 2007 -0700

    IB/umad: Clarify documentation of transaction ID
    
    Signed-off-by: Hal Rosenstock <halr@voltaire.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 37aebbde7023d75bf09fbadb6796276d0a65a068
Author: Roland Dreier <rolandd@cisco.com>
Date:   Tue Apr 24 21:30:37 2007 -0700

    IPoIB/cm: spin_lock_irqsave() -> spin_lock_irq() replacements
    
    There are quite a few places in ipoib_cm.c where we know IRQs are
    enabled because we do something that sleeps in the same function, so
    we can convert several occurrences of spin_lock_irqsave() to a plain
    spin_lock_irq().  This cleans up the source a little and makes the
    code smaller too:
    
    add/remove: 0/0 grow/shrink: 1/5 up/down: 3/-51 (-48)
    function                                     old     new   delta
    ipoib_cm_tx_reap                             403     406      +3
    ipoib_cm_stale_task                          146     145      -1
    ipoib_cm_dev_stop                            173     172      -1
    ipoib_cm_tx_handler                          964     956      -8
    ipoib_cm_rx_handler                          956     937     -19
    ipoib_cm_skb_reap                            212     190     -22
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 0dec4c8bc6ed62a65b61594aa754e21270423796
Author: Joakim Tjernlund <joakim.tjernlund@transmode.se>
Date:   Sat Mar 10 17:08:44 2007 +0100

    [JFFS2] Better fix for all-zero node headers
    
    No need to check for all-zero header since the header cannot
    be zero due to other checks.
    
    Replace the all-zero header check in readinode.c with a
    check for the magic word.
    
    Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit df8e96f39103adf5a13332d784040a2c62667243
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Wed Apr 25 03:23:42 2007 +0100

    [JFFS2] Improve read_inode memory usage, v2.
    
    We originally used to read every node and allocate a jffs2_tmp_dnode_info
    structure for each, before processing them in (reverse) version order
    and discarding the ones which are obsoleted by later nodes.
    
    With huge logfiles, this behaviour caused memory problems. For example, a
    file involved in OLPC trac #1292 has 1822391 nodes, and would cause the XO
    machine to run out of memory during the first stage of read_inode().
    
    Instead of just inserting nodes into a tree in version order as we find
    them, we now put them into a tree in order of their offset within the
    file, which allows us to immediately discard nodes which are completely
    obsoleted.
    
    We don't use a full tree with 'fragments' pointing to the real data
    structure, as we do in the normal fragtree. We sort only on the start
    address, and add an 'overlapped' flag to the tmp_dnode_info to indicate
    that the node in question is (partially) overlapped by another.
    
    When the scan is complete, we start at the end of the file, adding each
    node to a real fragtree as before. Where the node is non-overlapped, we
    just add it (it doesn't matter that it's not the latest version; there is
    no overlap). When the node at the end of the tree _is_ overlapped, we sort
    it and all its overlapping nodes into version order and then add them to
    the fragtree in that order.
    
    This 'early discard' reduces the peak allocation of tmp_dnode_info
    structures from 1.8M to a mere 62872 (3.5%) in the degenerate case
    referenced above.
    
    This version of the patch also correctly rememembers the highest node
    version# seen for an inode when it's scanned.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit de493d47d8b4738827d8914a4dc94058c58f4249
Author: Hal Rosenstock <halr@voltaire.com>
Date:   Mon Apr 2 11:24:07 2007 -0400

    IB/mad: Change SMI to use enums rather than magic return codes
    
    Clarify code by changing return values from SMI functions to named
    enum values instead of magic 0/1 values.
    
    Signed-off-by: Hal Rosenstock <halr@voltaire.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit aeba84a9251968a51fc6faae846518aac4e77565
Author: Sean Hefty <sean.hefty@intel.com>
Date:   Thu Apr 5 11:49:21 2007 -0700

    IB/umad: Implement GRH handling for sent/received MADs
    
    We need to set the SGID index for routed MADs and pass received
    GRH information to userspace when a MAD is received.
    
    Signed-off-by: Sean Hefty <sean.hefty@intel.com>

commit 46f1b3d7aff99ef4c1e729e023b9c8ee51de5973
Author: Sean Hefty <sean.hefty@intel.com>
Date:   Thu Apr 5 11:50:11 2007 -0700

    IB/ipoib: Use ib_init_ah_from_path to initialize ah_attr
    
    To support destinations that are not on the local IB subnet, IPoIB
    should include the GRH information when constructing an address
    handle.  Using the existing ib_init_ah_from_path() call will do this
    for us.
    
    Signed-off-by: Sean Hefty <sean.hefty@intel.com>

commit d0e7bb141837db620f24406ca8b4667424138d42
Author: Sean Hefty <sean.hefty@intel.com>
Date:   Thu Apr 5 10:51:10 2007 -0700

    IB/sa: Set src_path_bits correctly in ib_init_ah_from_path()
    
    src_path_bits needs to mask off the base LID value.
    
    Signed-off-by: Sean Hefty <sean.hefty@intel.com>

commit 9d41b7fdeadb76bd4d06c16803daffd9fcf8dc7f
Author: Sean Hefty <sean.hefty@intel.com>
Date:   Thu Apr 5 10:51:05 2007 -0700

    IB/ucm: Simplify ib_ucm_event()
    
    Use wait_event_interruptible() instead of a more complicated
    open-coded equivalent.
    
    Signed-off-by: Sean Hefty <sean.hefty@intel.com>

commit d92f76448c1a3e40ff3df96a653ecd83aeac6ee7
Author: Sean Hefty <sean.hefty@intel.com>
Date:   Thu Apr 5 10:49:51 2007 -0700

    RDMA/ucma: Simplify ucma_get_event()
    
    Use wait_event_interruptible() instead of a more complicated
    open-coded equivalent.
    
    Signed-off-by: Sean Hefty <sean.hefty@intel.com>

commit 30c00986f3a610cdcee2602b8254c3ffa6cddc04
Author: Roland Dreier <rolandd@cisco.com>
Date:   Tue Apr 24 16:31:11 2007 -0700

    IB/mthca: Simplify CQ cleaning in mthca_free_qp()
    
    mthca_free_qp() already has local variables to hold the QP's send_cq
    and recv_cq, so we can slightly clean up the calls to mthca_cq_clean()
    by using those local variables instead of expressions like
    to_mcq(qp->ibqp.send_cq).
    
    Also, by cleaning the recv_cq first, we can avoid worrying about
    whether the QP is attached to an SRQ for the second call, because we
    would only clean send_cq if send_cq is not equal to recv_cq, and that
    means send_cq cannot have any receive completions from the QP being
    destroyed.
    
    All this work even improves the generated code a bit:
    
    add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-5 (-5)
    function                                     old     new   delta
    mthca_free_qp                                510     505      -5
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 532c3b581725e2c6480a20c845fff920690286f1
Author: Roland Dreier <rolandd@cisco.com>
Date:   Tue Apr 24 16:31:04 2007 -0700

    IB/mthca: Fix mthca_write_mtt() on HCAs with hidden memory
    
    Commit b2875d4c ("IB/mthca: Always fill MTTs from CPU") causes a crash
    in mthca_write_mtt() with non-memfree HCAs that have their memory
    hidden (that is, have only two PCI BARs instead of having a third BAR
    that allows access to the RAM attached to the HCA) on 64-bit
    architectures.  This is because the commit just before, c20e20ab
    ("IB/mthca: Merge MR and FMR space on 64-bit systems") makes
    dev->mr_table.fmr_mtt_buddy equal to &dev->mr_table.mtt_buddy and
    hence mthca_write_mtt() tries to write directly into the HCA's MTT
    table.  However, since that table is in the HCA's memory, this is
    impossible without the PCI BAR that gives access to that memory.
    
    This causes a crash because mthca_tavor_write_mtt_seg() basically
    tries to dereference some offset of a NULL pointer.  Fix this by
    adding a test of MTHCA_FLAG_FMR in mthca_write_mtt() so that we always
    use the WRITE_MTT firmware command rather than writing directly if
    FMRs are not enabled.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit c78f830547087aa4143affd3404a854995603544
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 14:56:01 2007 +0100

    [POWERPC] via-pmu: Switch to ref counting PCI API
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ab4627683a0e4430cb5acb1cd896f08ec5dad90c
Author: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date:   Mon Apr 23 14:47:59 2007 +0100

    [POWERPC] pci_32.c: Switch to ref counting PCI API
    
    pci_find_slot isn't hot-plug safe.  Move this code to the pci hotplug
    safe equivalent and hold a refcount properly while doing
    make_one_node_map.
    
    Signed-off-by: Alan Cox <alan@redhat.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 37f01d64d83705f82bb06eac8134acc8ef665565
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue Apr 24 15:05:18 2007 +1000

    [POWERPC] Abolish PHYS_FMT macro from arch/powerpc
    
    32-bit powerpc systems define a macro, PHYS_FMT, giving a printf
    format string fragment for displaying physical addresses, since most
    32-bit powerpc platforms use 32-bit physical addresses but a few use
    64-bit physical addresses.
    
    This macro is used in exactly one place, a rare error message, where
    we can solve the problem more simply by just unconditionally casting
    the address up to 64-bit quantity before formatting it.
    
    This patch does so, meaning that as we bring MMU definitions from
    asm-ppc over to asm-powerpc, cleaning them up in the process, we don't
    need to implement this ugly macro (which additionally has a very bad
    name for something global).
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 30686ba6d56858657829d3eb524ed73e5dc98d2b
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 24 13:53:04 2007 +1000

    [POWERPC] Remove old interface find_devices
    
    Replace uses with of_find_node_by_name and for_each_node_by_name.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1658ab66781d918f604c6069c5cf9a94b6f52f84
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 24 13:51:59 2007 +1000

    [POWERPC] Remove old interface find_type_devices
    
    Replaced by of_find_node_by_type.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8c8dc322486d5394dc981bef9276dd0ce6c8d1ce
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 24 13:50:55 2007 +1000

    [POWERPC] Remove old interface find_path_device
    
    Replaced by of_find_node_by_path.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 112466b4d0036b3244509d01dbbf3c8caec52a23
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 24 13:49:47 2007 +1000

    [POWERPC] Remove find_all_nodes
    
    This old interface has no more users.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 4bf56e1725a298fb430977cf143ad3a36c91b46a
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 24 13:48:41 2007 +1000

    [POWERPC] Remove find_compatible_devices
    
    This is an old interface and is replaced by of_find_compatible_node.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 621023072524fc0155ed16490255e1ea3aa11585
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Tue Apr 24 13:09:12 2007 +1000

    [POWERPC] Cleanup and fix breakage in tlbflush.h
    
    BenH's commit a741e67969577163a4cfc78d7fd2753219087ef1 in powerpc.git,
    although (AFAICT) only intended to affect ppc64, also has side-effects
    which break 44x.  I think 40x, 8xx and Freescale Book E are also
    affected, though I haven't tested them.
    
    The problem lies in unconditionally removing flush_tlb_pending() from
    the versions of flush_tlb_mm(), flush_tlb_range() and
    flush_tlb_kernel_range() used on ppc64 - which are also used the
    embedded platforms mentioned above.
    
    The patch below cleans up the convoluted #ifdef logic in tlbflush.h,
    in the process restoring the necessary flushes for the software TLB
    platforms.  There are three sets of definitions for the flushing
    hooks: the software TLB versions (revised to avoid using names which
    appear to related to TLB batching), the 32-bit hash based versions
    (external functions) amd the 64-bit hash based versions (which
    implement batching).
    
    It also moves the declaration of update_mmu_cache() to always be in
    tlbflush.h (previously it was in tlbflush.h except for PPC64, where it
    was in pgtable.h).
    
    Booted on Ebony (440GP) and compiled for 64-bit and 32-bit
    multiplatform.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 687304014f7ca8e2fbb3feaefef356b4a0da65ad
Author: Olof Johansson <olof@lixom.net>
Date:   Tue Apr 24 01:11:55 2007 +1000

    [POWERPC] Save trap number in bad_stack
    
    Save the trap number in the case of getting a bad stack in an exception
    handler. It is sometimes useful to know what exception it was that caused
    this to happen. Without this, no trap number is reported.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6cfef5b27e49e826125f12637ee0d7210a896044
Author: Michael Ellerman <michael@ellerman.id.au>
Date:   Mon Apr 23 18:47:08 2007 +1000

    [POWERPC] Rename MPIC_BROKEN_U3 to MPIC_U3_HT_IRQS
    
    Rename MPIC_BROKEN_U3 to something a little more descriptive. Its
    effect is to enable support for HT irqs behind the PCI-X/HT bridge on
    U3/U4 (aka. CPC9x5) parts.
    
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e3f64788d32f97b31709a45911dabaa37f933359
Author: Grant Likely <grant.likely@secretlab.ca>
Date:   Sun Apr 22 07:24:04 2007 +1000

    [POWERPC] Fix comment typo in Kurobox device tree
    
    Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 4ca478e6066ce57f7cc856af36aaf1a2d64417cb
Author: Geert Uytterhoeven <Geert.Uytterhoeven@eu.sony.com>
Date:   Wed Apr 18 19:24:12 2007 +1000

    [POWERPC] bootwrapper: Use `unsigned long' for malloc sizes
    
    Use `unsigned long' for malloc sizes, to match common practice and types used
    by most callers and callees.
    Also use `unsigned long' for integers representing pointers in simple_alloc.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@eu.sony.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e58923ed14370e0facc5eb2c3923216adc3bf260
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Apr 18 16:36:26 2007 +1000

    [POWERPC] Add arch/powerpc driver for UIC, PPC4xx interrupt controller
    
    This patch adds a driver to arch/powerpc/sysdev for the UIC, the
    on-chip interrupt controller from IBM/AMCC 4xx chips.  It uses the new
    irq host mapping infrastructure.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f65573314e4e2d7deacd7ed101c004148e156296
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Apr 18 16:36:26 2007 +1000

    [POWERPC] Re-organize Kconfig code for 4xx in arch/powerpc
    
    Now that we always take a device tree in arch/powerpc, there's no good
    reason not to allow a single kernel to support multiple embedded 4xx
    boards - the correct platform code can be selected based on the device
    tree information.
    
    Therefore, this patch re-arranges the 4xx Kconfig code to allow this.
    In addition we:
    	- use "select" instead of depends to configure the correct
    	  config options for specific 4xx CPUs and workarounds, which
    	  makes the information about specific boards and CPUs less
    	  scattered.
    	- Some old, unused (in arch/powerpc) config options are
    	  removed: WANT_EARLY_SERIAL, IBM_OCP, etc.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e6349a958b3577da6e5c5eacda85c07f9a364cb5
Author: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Date:   Wed Apr 18 15:57:51 2007 +1000

    [POWERPC] kprobes: Eliminate sstep exception if instruction can be emulated
    
    For cases when probes are placed on instructions that can be emulated,
    don't take the single-step exception.
    
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6888199f7fe5ea496f48bb6de67b9b7f05b8071b
Author: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Date:   Wed Apr 18 15:56:38 2007 +1000

    [POWERPC] Emulate more instructions in software
    
    Emulate a few more instructions in software - especially useful during
    singlestepping (xmon/kprobes).
    
    Instructions emulated with this patch are mfcr/mtcr rX, mfxer/mtxer rX,
    mflr/mtlr rX, mfctr/mtctr rX and mr rA,rB.
    
    Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5cc5133a29fab993f0b40c03e975bc5458ece507
Author: Scott Wood <scottwood@freescale.com>
Date:   Tue Apr 17 09:25:55 2007 +1000

    [POWERPC] bootwrapper: cuboot for 83xx
    
    This adds cuboot support for MPC83xx platforms.
    
    A device tree used with this must have linux,stdout-path in /chosen and
    linux,network-index in any network device nodes that need mac addresses
    assigned.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9b1c59e256e91aaf2a6543b32afc3658d8f96d4b
Author: Scott Wood <scottwood@freescale.com>
Date:   Tue Apr 17 09:25:53 2007 +1000

    [POWERPC] bootwrapper: Add ppcboot.h
    
    This file describes the bd_t struct, which is used by old versions of
    U-boot to pass information to the kernel.  Platform code that needs to
    interoperate with such firmware can use this; it should not be used for
    anything new.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0fdd717ed4d9c82f3f766007b3f5da656649f3aa
Author: Scott Wood <scottwood@freescale.com>
Date:   Tue Apr 17 09:25:50 2007 +1000

    [POWERPC] bootwrapper: Add a cuboot platform and a cuImage target
    
    The cuImage target will build a uImage with bootwrapper code and a device
    tree.  The default device tree and platform file are determined by the
    kernel configuration.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 270429baa928fa6beff4042a7701944e23396417
Author: Scott Wood <scottwood@freescale.com>
Date:   Tue Apr 17 09:24:51 2007 +1000

    [POWERPC] bootwrapper: Add CONFIG_DEVICE_TREE
    
    This provides a way to tell the bootwrapper makefile which device tree to
    include by default.  The wrapper can still be invoked standalone to wrap
    with a different device tree without reconfiguring the kernel, if that is
    desired.
    
    The user will only be asked to provide a device tree if the platform
    selects CONFIG_WANT_DEVICE_TREE.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit b97d27914354619ec6883ffe08dbd9c8e4b826b7
Author: Olof Johansson <olof@lixom.net>
Date:   Wed Apr 18 16:39:54 2007 +1000

    [POWERPC] pasemi: GPIO MDIO of_platform driver
    
    MDIO driver for PHY's connected via GPIO as on the PA Semi Electra
    eval board.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 25fc530eed1ca9ccde2a1e96d0b2060867f76bb2
Author: Olof Johansson <olof@lixom.net>
Date:   Wed Apr 18 16:38:21 2007 +1000

    [POWERPC] pasemi: PA6T oprofile support
    
    Oprofile support for PA6T, kernel side.
    
    Also rename the PA6T_SPRN.* defines to SPRN_PA6T.*.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7e8bddf56661a16b7d5945390a37cd2e9c5e45fe
Author: Olof Johansson <olof@lixom.net>
Date:   Mon Apr 16 16:28:38 2007 +1000

    [POWERPC] pasemi: Reset mpic on boot
    
    Reset MPIC on boot to clear some timer state that firmware might
    leave configured.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 62357d821550e253b53a6106e3e5dc946647fec4
Author: Olof Johansson <olof@lixom.net>
Date:   Mon Apr 16 16:27:45 2007 +1000

    [POWERPC] pasemi: Enable one more hid bit
    
    Minor HID change. Firmware can't know that we want this set so we have
    to set it in the kernel.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit df7e70a2b0899845bb9a53548beeed05b9947705
Author: Olof Johansson <olof@lixom.net>
Date:   Mon Apr 16 16:26:34 2007 +1000

    [POWERPC] pasemi: Allow 8KB config space for I/O bridge
    
    Device 0 function 0 on the root bus is really a two-function bus agent,
    but only the first function is visible. Because of this, we need to
    allow config accesses into the second range. Modify the check for valid
    offsets accordingly.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a14c4508f4bb1bb7772b1976a82646be8d8b515a
Author: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Date:   Fri Apr 13 04:33:25 2007 +1000

    [POWERPC] Fix PowerPC 750CL and 750GX CPU features
    
    PowerPC 750CL has high BATs.  The patch below adds a CPU_FTRS_750CL that
    includes that.  Without it, the original firmware mappings in the high BATs
    aren't cleared which continue to override the linux translations.
    
    It also adds CPU_FTR_COMMON to CPU_FTRS_750GX for completeness.
    
    Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c3ea6921a68ed4bdcfc782676c52707cbe347952
Author: will schmidt <will_schmidt@vnet.ibm.com>
Date:   Wed Apr 18 00:54:51 2007 +1000

    [POWERPC] hvc_console: Typo fixes
    
    Fix a handful of comment typos for hvc_console.
    
    Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit b791072ba3c3b29bab1890963bde52eb944a8451
Author: Will Schmidt <will_schmidt@vnet.ibm.com>
Date:   Wed Apr 18 00:44:46 2007 +1000

    [POWERPC] hvc_console: Polling mode timer backoff
    
    Add a back-off mechanism to hvc_console's polling logic.   This change
    drops the timers/second ratio from ~90 to ~1/2 while the console is
    idle.
    This change is most noticeable when watching /proc/timer_stats output.
    
    This only affects when the hvc_console is running in poll mode, i.e.
    power4 and cell systems.
    
    I've tested on Power4, Michael Ellerman has both contributed to the
    patch and tested on cell.
    
    Signed-off-by: Will Schmidt <will_schmidt@vnet.ibm.com>
    Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
    Acked-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit b3a6d2a54b8be331b36d849577a716867895ca75
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Fri Apr 13 17:14:22 2007 +1000

    [POWERPC] Rename last get_property calls
    
    These got added recently.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit edfedbf0cd0a57b16b638275e8fe8c369580b726
Author: Paul Mackerras <paulus@samba.org>
Date:   Tue Apr 24 13:57:12 2007 +1000

    [POWERPC] Partially revert "Add correct interrupt property for pegasos ide"
    
    It turns out that commit e48059225c2edc6f1e5a2008261f1efdf606f247
    breaks some existing systems that use the via82cxxx driver.  This
    reverts the change to via82cxxx.c.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2dd29d3133ad4c7926ea03b8431e604373c4ad65
Author: Steve French <sfrench@us.ibm.com>
Date:   Mon Apr 23 22:07:35 2007 +0000

    [CIFS] New CIFS POSIX mkdir performance improvement
    
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit c6d344819ea26c4df1cf2572232706667e1d99ea
Author: Arnd Bergmann <arnd@arndb.de>
Date:   Mon Apr 23 21:35:48 2007 +0200

    [POWERPC] update cell_defconfig
    
    Sync with the Kconfig changes, and enable some options for celleb
    
    Cc: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
    Signed-off-by: Jens Osterkamp <jens@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 150f7e3cfec42a7d96ffda6f83881a7cee101c87
Author: Jeremy Kerr <jk@ozlabs.org>
Date:   Mon Apr 23 21:35:47 2007 +0200

    [POWERPC] cell: enable RTAS-based PTCAL for Cell XDR memory
    
    Enable Periodic Recalibration (PTCAL) support for Cell XDR memory,
    using the new ibm,cbe-start-ptcal and ibm,cbe-stop-ptcal RTAS calls.
    
    Tested on QS20 and QS21 (by Thomas Huth). It seems that SLOF has
    problems disabling, at least on QS20; this patch should only be
    used once these problems have been addressed.
    
    Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 9dd855a729abb4670522d5eae6854db48d624498
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:46 2007 +0200

    [POWERPC] cell: add support for proper device-tree
    
    This patch adds support for a proper device-tree.
    A porper device-tree on cell contains be nodes
    for each CBE containg nodes for SPEs and all the
    other special devices on it.
    Ofcourse oldschool devicetree is still supported.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 6bf05fd776e38a0a9c17e17c2345b59b1b9aa2cb
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:45 2007 +0200

    [POWERPC] add of_iomap function
    
    The of_iomap function maps memory for a given
    device_node and returns a pointer to that memory.
    This is used at some places, so it makes sense to
    a seperate function.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 4a065f9418274f2d73066f1638b3612341e4f030
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:44 2007 +0200

    [POWERPC] pmi probe device by device-type
    
    At the moment the pmi device driver is probing for devices with
    a given type and a given name. As there may be devices of
    the same type but with a different name, probing should be
    done also for device type only.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 79baf4a60e8aceb2b8a5bed8575885499cb21ce4
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:43 2007 +0200

    [POWERPC] add check for initialized driver data to pmi driver
    
    This patch adds a check for the private driver data to be initialized.
    The bug showed up, as the caller found a pmi device by it's type.
    Whereas the pmi driver probes for the type and the name.
    Since the name was not as the driver expected, it did not initialize.
    A more relaxed probing will be supplied with an extra patch, too.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 5050063c0464663a0b0c3dc9fc5bc822aa74a1dd
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:42 2007 +0200

    [POWERPC] cell: use pmi in cpufreq driver
    
    The new PMI driver was added in order to support
    cpufreq on blades that require the frequency to
    be controlled by the service processor, so use it
    on those.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 5f7bdaee2aaf7dfdf18c735dee62401fd26c8d72
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:41 2007 +0200

    [POWERPC] cbe_thermal: add throttling attributes to cpu and spu nodes
    
    This patch adds some attributes the cpu and spu nodes:
    /sys/devices/system/[c|s]pu/[c|s]pu*/thermal/throttle_begin
    /sys/devices/system/[c|s]pu/[c|s]pu*/thermal/throttle_end
    /sys/devices/system/[c|s]pu/[c|s]pu*/thermal/throttle_full_stop
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 24d560d7b9cf90451c6ef6248c09fb4cee1c76e6
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:40 2007 +0200

    [POWERPC] cbe_thermal: clean up computation of temperature
    
    This patch introduces a little function for transforming
    register values into temperature.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 91a69c9646a5b709381d99a171890e77377b1b9c
Author: Christian Krafft <krafft@de.ibm.com>
Date:   Mon Apr 23 21:35:39 2007 +0200

    [POWERPC] cell: add cbe_node_to_cpu function
    
    This patch adds code to deal with conversion of
    logical cpu to cbe nodes. It removes code that
    assummed there were two logical CPUs per CBE.
    
    Signed-off-by: Christian Krafft <krafft@de.ibm.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit ccf17e9d008dfebbf90dfa4ee1a56e81c784c73e
Author: Jeremy Kerr <jk@ozlabs.org>
Date:   Mon Apr 23 21:08:29 2007 +0200

    [POWERPC] spu_base: fix initialisation on systems with no SPEs
    
    This change fixes the case where spu_base and spufs are initialised on a
    system with no SPEs - unconditionally create the spu_lists so spu_alloc
    doesn't explode, and check for spu_management ops before starting spufs.
    
    Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    
     arch/powerpc/platforms/cell/spu_base.c    |    7 ++++---
     arch/powerpc/platforms/cell/spufs/inode.c |    5 +++++
     2 files changed, 9 insertions(+), 3 deletions(-)

commit befdc746ee027d686a06be29cb1391f9d2c45cf6
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:28 2007 +0200

    [POWERPC] spu_base: remove cleanup_spu_base
    
    spu_base.c is always built into the kernel image, so there is no need
    for a cleanup function.  And some of the things it does are in the
    way for my following patches, so I'd rather get rid of it ASAP.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit aa45e2569ffe963dfbbbfddfdccd12afe69b2d65
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:27 2007 +0200

    [POWERPC] spufs: various run.c cleanups
    
     - remove the spu_acquire_runnable from spu_run_init.  I need to
       opencode it in spufs_run_spu in the next patch
     - remove various inline attributes, we don't really want to inline
       long functions with multiple callsites
     - cleanup return values and runcntl_write calls in spu_run_init
     - use normal kernel codingstyle in spu_reacquire_runnable
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit fe8a29db5bce1b5bd1ceb85fd153fac52cdab7b2
Author: Akinobu Mita <mita@fixstars.com>
Date:   Mon Apr 23 21:08:26 2007 +0200

    [POWERPC] spufs: enable SPU coredump for kernel-builtin spufs
    
    spu_coredump_calls.owner is NULL in case of a builtin spufs,
    so the checks in here break.
    Check for the availability of the spu_coredump_calls variable
    instead.
    
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 6cf2179202cf706471777ad6ee5d0377d5990ab7
Author: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Date:   Mon Apr 23 21:08:25 2007 +0200

    [POWERPC] spufs: fix memory leak on coredump
    
    Dynamically allocated read/write buffer in spufs_arch_write_note() will
    not be freed. Convert it to get_free_page at the same time.
    
    Cc: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit d3764397d07b1e03943edfdcc3fb77af7bdac02b
Author: Jeremy Kerr <jk@ozlabs.org>
Date:   Mon Apr 23 21:08:24 2007 +0200

    [POWERPC] spufs: Minor cleanup of spu_wait
    
    Change the loop in spu_wait to be a little more straightforward.
    
    Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit f11f5ee70f48899506514e5e0d10ee2c8ddd359a
Author: Jeremy Kerr <jk@ozlabs.org>
Date:   Mon Apr 23 21:08:23 2007 +0200

    [POWERPC] spufs: add mode= mount option
    
    Add a 'mode=' option to spufs mount arguments. This allows more
    control over access to the top-level spufs directory.
    
    Tested on Cell.
    
    Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 9e2fe2ce4e957a79d3dc5d813e0cfb10d79b79b3
Author: Akinobu Mita <mita@fixstars.com>
Date:   Mon Apr 23 21:08:22 2007 +0200

    [POWERPC] spufs: use memcpy_fromio() to copy from local store
    
    GCC may generates inline copy loop to handle memcpy() function
    instead of kernel defined memcpy(). But this inlined version of memcpy()
    causes an alignment interrupt when copying from local store.
    
    This patch uses memcpy_fromio() and memcpy_toio to copy local store
    to prevent memcpy() being inlined.
    
    Signed-off-by: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 8a7d86bdb22678b17928eef0c8fa356d8b21cc76
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:21 2007 +0200

    [POWERPC] spufs: avoid spurious memory barriers
    
    We now have proper locking around assignets of the mapping pointers,
    and the spin_unlock implies enough of a barrier to get rid of the
    explicit one.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit db1384b40d12eda6910513ff429ad90453ca49e1
Author: Akinobu Mita <mita@fixstars.com>
Date:   Mon Apr 23 21:08:20 2007 +0200

    [POWERPC] spufs: fix memory leak on spufs reloading
    
    When SPU isolation mode enabled, isolated_loader would be
    allocated by spufs_init_isolated_loader() on module_init().
    But anyone do not free it.
    
    This patch introduces spufs_exit_isolated_loader() which is
    the opposite of spufs_init_isolated_loader() and called on
    module_exit().
    
    Cc: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit c99c1994a2bb9493b4ac372b2b6ee2606d291171
Author: Akinobu Mita <mita@fixstars.com>
Date:   Mon Apr 23 21:08:19 2007 +0200

    [POWERPC] spufs: fix missing error handling in module_init()
    
    spufs module_init forgot to call a few cleanup functions
    on error path. This patch also includes cosmetic changes in
    spu_sched_init() (identation fix and return error code).
    
    [modified by hch to apply ontop of the latest schedule changes]
    
    Cc: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 577f8f1021f9ee6ef2a98a142652759ec122d27f
Author: Akinobu Mita <mita@fixstars.com>
Date:   Mon Apr 23 21:08:18 2007 +0200

    [POWERPC] spufs: check spu_acquire_runnable() return value
    
    This patch checks return value of spu_acquire_runnable() in
    spufs_mfc_write().
    
    Signed-off-by: Akinobu Mita <mita@fixstars.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit e45d48a34d4d1862d28d22c2533b8c6bb83b8c1f
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:17 2007 +0200

    [POWERPC] spufs: turn run_sema into run_mutex
    
    There is no reason for run_sema to be a struct semaphore.  Changing
    it to a mutex and rename it accordingly.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit c8a1e9393a86f862ab9c8bc0db9b8a1822226f84
Author: Jeremy Kerr <jk@ozlabs.org>
Date:   Mon Apr 23 21:08:16 2007 +0200

    [POWERPC] spufs: provide siginfo for SPE faults
    
    This change populates a siginfo struct for SPE application exceptions
    (ie, invalid DMAs and illegal instructions).
    
    Tested on an IBM Cell Blade.
    
    Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 57dace2391ba10135e38457904121e7ef34d0c83
Author: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Date:   Mon Apr 23 21:08:15 2007 +0200

    [POWERPC] spufs: make spu page faults not block scheduling
    
    Until now, we have always entered the spu page fault handler
    with a mutex for the spu context held. This has multiple
    bad side-effects:
    - it becomes impossible to suspend the context during
      page faults
    - if an spu program attempts to access its own mmio
      areas through DMA, we get an immediate livelock when
      the nopage function tries to acquire the same mutex
    
    This patch makes the page fault logic operate on a
    struct spu_context instead of a struct spu, and moves it
    from spu_base.c to a new file fault.c inside of spufs.
    
    We now also need to copy the dar and dsisr contents
    of the last fault into the saved context to have it
    accessible in case we schedule out the context before
    activating the page fault handler.
    
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 62c05d583ec016c40011462d5f03b072bfbd3dc7
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:14 2007 +0200

    [POWERPC] spu_base: move spu_init_channels out of spu_mutex
    
    There is no reason to execute spu_init_channels under spu_mutex
    after the spu has been taken off the freelist it's ours.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 4e0f4ed0df71013290cd2a01f7b84264f7b99678
Author: Luke Browning <lukebrowning@us.ibm.com>
Date:   Mon Apr 23 21:08:13 2007 +0200

    [POWERPC] spu sched: make addition to stop_wq and runque atomic vs wakeup
    
    Addition to stop_wq needs to happen before adding to the runqeueue and
    under the same lock so that we don't have a race window for a lost
    wake up in the spu scheduler.
    
    Signed-off-by: Luke Browning <lukebrowning@us.ibm.com>
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 7ec18ab923a2e377ecb05c74a2d38f457f79950f
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:12 2007 +0200

    [POWERPC] spufs: streamline locking for isolated spu setup
    
    For quite a while now spu state is protected by a simple mutex instead
    of the old rw_semaphore, and this means we can simplify the locking
    around spu_setup_isolated a lot.
    
    Instead of doing an spu_release before entering spu_setup_isolated and
    then calling the complicated spu_acquire_exclusive we can now simply
    enter the function locked an in guaranteed runnable state, so that the
    only bit of spu_acquire_exclusive that's left is the call to
    spu_unmap_mappings.
    
    Similarly there's no more need to unlock and reacquire the state_mutex
    when spu_setup_isolated is done, but we can always return with the
    lock held and only drop it in spu_run_init in the failure case.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit a475c2f43520cb095452201da57395000cfeb94c
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:11 2007 +0200

    [POWERPC] spufs: remove woken threads from the runqueue early
    
    A single context should only be woken once, and we should not have
    more wakeups for a given priority than the number of contexts on
    that runqueue position.
    
    Also add some asserts to trap future problems in this area more
    easily.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 390c53430498c9973e015432806edd53b2efe6c6
Author: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Date:   Mon Apr 23 21:08:10 2007 +0200

    [POWERPC] spufs: add memory barriers after set_bit
    
    set_bit does not guarantee ordering on powerpc, so using it
    for communication between threads requires explicit
    mb() calls.
    
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit e097b513285e616215b23af234d127298bb8d89a
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:09 2007 +0200

    [POWERPC] spu sched: ensure preempted threads are put back on the runqueue, part2
    
    To not lose a spu thread we need to make sure it always gets put back
    on the runqueue.  In find_victim aswell as in the scheduler tick as done
    in the previous patch.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit b3e76cc3244ac139fc75750c5af9edbb9f191a10
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:08 2007 +0200

    [POWERPC] spu sched: ensure preempted threads are put back on the runqueue
    
    To not lose a spu thread we need to make sure it always gets put back
    on the runqueue.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Acked-by: Jeremy Kerr <jk@ozlabs.org>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 43c2bbd932b66403688f3d812065d82f8fb8f4b3
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:07 2007 +0200

    [POWERPC] spufs: clear mapping pointers after last close
    
    Make sure the pointers to various mappings are cleared once the last
    user stopped using them.  This avoids accessing freed memory when
    tearing down the gang directory aswell as optimizing away
    pte invalidations if no one uses these.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 0887309589824fb1c3744c69a330c99c369124a0
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 23 21:08:06 2007 +0200

    [POWERPC] spufs: use cancel_rearming_delayed_workqueue when stopping spu contexts
    
    The scheduler workqueue may rearm itself and deadlock when we try to stop
    it.  Put a flag in place to avoid skip the work if we're tearing down
    the context.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

commit 44b998e1eb254edc87177819ee693690fac68b7f
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Mon Apr 23 12:11:46 2007 +0100

    [JFFS2] Improve failure mode if inode checking leaves unchecked space.
    
    We should never find the unchecked size is non-zero after we've finished
    checking all inodes. If it happens, used to BUG(), leaving the alloc_sem
    held and deadlocking. Instead, just return -ENOSPC after complaining. The
    GC thread will die, but read-only operation should be able to continue and
    the file system should be unmountable.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 566865a2a4791c9290155f651ee0c2c606db0b1d
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Mon Apr 23 12:07:17 2007 +0100

    [JFFS2] Fix cross-endian build.
    
    When compiling a LE-capable JFFS2 on PowerPC, wbuf.c fails to compile:
    
    fs/jffs2/wbuf.c:973: error: braced-group within expression allowed only inside a function
    fs/jffs2/wbuf.c:973: error: initializer element is not constant
    fs/jffs2/wbuf.c:973: error: (near initialization for â€˜oob_cleanmarker.magicâ€™)
    fs/jffs2/wbuf.c:974: error: braced-group within expression allowed only inside a function
    fs/jffs2/wbuf.c:974: error: initializer element is not constant
    fs/jffs2/wbuf.c:974: error: (near initialization for â€˜oob_cleanmarker.nodetypeâ€™)
    fs/jffs2/wbuf.c:975: error: braced-group within expression allowed only inside a function
    fs/jffs2/wbuf.c:976: error: initializer element is not constant
    fs/jffs2/wbuf.c:976: error: (near initialization for â€˜oob_cleanmarker.totlenâ€™)
    
    Provide constant_cpu_to_je{16,32} functions, and use them for initialising the
    offending structure.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 3e67fe4543333048e486d7f360a0e2ae5d76c053
Author: Christoph Hellwig <hch@infradead.org>
Date:   Sun Apr 22 20:40:57 2007 +0100

    [MTD] Finish conversion mtd_blkdevs to use the kthread API
    
    Remove waitqueue, 'exiting' flag and completion; use kthread APIs instead.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit ed519dede3d705e1c0012acd5b8de4074aa30fa4
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Apr 22 12:30:41 2007 +0100

    [ARM] Convert AMBA PL010 driver to use the clk infrastructure
    
    Convert the AMBA PL010 serial driver to use the clock infrastructure
    to allow EP93xx platforms to properly gate the clock to the UARTs.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 1b0646a033c370d6c7f5390f2cb452cc1884bb5b
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Apr 22 11:55:59 2007 +0100

    [ARM] Convert AMBA PL010 driver to use 'uart_amba_port'
    
    Use a pointer to struct uart_amba_port throughout the driver
    rather than a mixture of that and struct uart_port.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7531a1c2c4477f63688871c1648d828f55313d42
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Apr 22 10:56:40 2007 +0100

    [ARM] Remove unnecessary asm/ptrace.h from VFP support code
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit d0a9d75b9cd9cc8097c746611cc57cc8438b94be
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Apr 22 10:08:58 2007 +0100

    [ARM] sa1100: use mutexes rather than semaphores
    
    Use a mutex in the sa1100 clock support rather than a semaphore.
    Remove the unused "module" field.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 99fba3f8177956170f3d86f83c2cf2f70747105f
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:44 2007 -0300

    ACPI: thinkpad-acpi: improve fan watchdog messages
    
    Improve some of the fan watchdog error messages to be a little more
    helpful.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 04cc862c1893a055ab1117fa6f3aa0886c0ba032
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:43 2007 -0300

    ACPI: thinkpad-acpi: cleanup thermal subdriver for sysfs conversion
    
    Clean-up the thermal subdriver for sysfs conversion.  Make thermal_get_*
    reentrancy-safe while at it, and add the missing thermal_read_mode variable
    to the header file.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit c9bea99c1a712548db3437cbca52b0da8f30069c
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:42 2007 -0300

    ACPI: thinkpad-acpi: clean up CMOS commands subdriver
    
    Some ThinkPad CMOS commands subdriver cleanups, and also rename/promote
    cmos_eval to a ACPI helper function, as it is used by many other
    subdrivers.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 83f34724643a3b0ec9322490b9ad9f1b60170a6c
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:41 2007 -0300

    ACPI: thinkpad-acpi: cleanup video subdriver
    
    Cleanup video subdriver for sysfs conversion, and properly check
    result status of acpi_evalf.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d6fdd1e91a8a4cd852dc1d945165e3a69ac9e257
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:40 2007 -0300

    ACPI: thinkpad-acpi: cleanup bluetooth and wan for sysfs conversion
    
    Prepare bluetooth and wan driver code to be more easily hooked into sysfs
    helpers, by separating the procfs logic from the device attribute handling.
    
    These changes also remove the entries from procfs on notebooks without the
    bluetooth/wan hardware installed.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b86c4722de62f336b82dff3c47ef59ba2a587ec1
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:39 2007 -0300

    ACPI: thinkpad-acpi: clean up hotkey subdriver
    
    Cleanup hotkey subdriver code.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d01320e606d334a0cd35d781a58f9f3c254829ab
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:38 2007 -0300

    ACPI: thinkpad-acpi: mark acpi helper functions __must_check
    
    Mark acpi_evalf and friends __must_check.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 8d376cd6543d57ef10799be02ba5f19aa6678032
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:37 2007 -0300

    ACPI: thinkpad-acpi: prepare for device model conversion
    
    Prepare the thinkpad-acpi driver for the conversion to the device
    model, by renaming variables and doing other glue work that shall
    make the later patches much cleaner.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d8fd94d9f08237ffda7e44e6825b057bf20a90e3
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:36 2007 -0300

    ACPI: thinkpad-acpi: use bitfields for module flags
    
    Use a bitfield to hold boolean module-wide flags, to conserve some memory.
    It is easy and it is clean, so we do it just for the heck of it even if it
    saves very little space.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 926411779287ad4f7013c9d80aa44fd131b70cd9
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:35 2007 -0300

    ACPI: thinkpad-acpi: use bitfields to hold subdriver flags
    
    Save some memory by using bitfields to hold boolean flags for the
    subdrivers.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 0dcef77c5b889338811d35e786b42046259fe433
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:34 2007 -0300

    ACPI: thinkpad-acpi: improve thinkpad detection
    
    Improve the detection of ThinkPads, so as to reduce the chances of false
    positives.
    
    Since this could potentially add false negatives on the very old models,
    add a module parameter to force the detection of a thinkpad.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit a5763f2223ce3fdbc75923f8c948fc7b59ed2f96
Author: Henrique de Moraes Holschuh <hmh@debian.org>
Date:   Sat Apr 21 11:08:33 2007 -0300

    ACPI: thinkpad-acpi: uncouple subdriver init from ibms struct
    
    Move the .init method from ibms struct to another struct, and use a list
    head to control which subdrivers have been activated.
    
    This allows us to have the subdriver init methods marked __init, saving
    quite a lot of .text size, and even a bit of .data size as some data can
    now be made __initdata.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit fe08bc4b4fd1371fad111675a564e4d2ebbf39ea
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:32 2007 -0300

    ACPI: thinkpad-acpi: add subdriver debug statements
    
    Add debug messages to the subdriver initialization and exit code.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 5fba344cfdbaa79e6320da26c3db34dfb219a845
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:31 2007 -0300

    ACPI: thinkpad-acpi: clean up probing and move init to subdrivers
    
    Move most of the probing code to its own function, and most of the
    subdriver-specific init code into subdriver init functions.
    
    This allows us to not define pci_handle unless the dock subdriver is
    enabled, as well.
    
    This patch causes a minor userland interface change: if a subdriver doesn't
    detect a capability, /proc entries for it are not created anymore (as
    opposed to a /proc entry that just returned "unsupported").
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 132ce09123755ec5e3d3a8ae22f4f753c3baac97
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:30 2007 -0300

    ACPI: thinkpad-acpi: add debug mode
    
    Add a debug mode parameter and verbose debug mode Kconfig option.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit f51d1a39840ae5e8678d702ab57377c611fc3826
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:29 2007 -0300

    ACPI: thinkpad-acpi: update fan firmware documentation
    
    Update some stuff in the in-code text describing the ThinkPad fan
    firmware.  This patch has no code changes.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit efa27145df34eacf2569bd45f68dbe00003d3616
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:28 2007 -0300

    ACPI: thinkpad-acpi: rename thinkpad constants
    
    Rename all IBMACPI_ constants, now that we are not called ibm-acpi anymore.
    Driver-specific constants are now prefixed TPACPI_, ThinkPad firmware
    specific ones are now prefixed TP_CMOS_, TP_ACPI_, or TP_EC_.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1def7115f0277ce9d2a54efd0ae187aa88d5c7fa
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:27 2007 -0300

    ACPI: thinkpad-acpi: rename module glue
    
    Rename module init and exit functions, now that we are not called ibm-acpi
    anymore.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 142cfc90f026b0b8fd1a14ba11ae29eb7b1b6ca1
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:26 2007 -0300

    ACPI: thinkpad-acpi: rename one stray use of ibm-acpi in a comment
    
    Rename a stray use of ibm-acpi on a comment, no functional changes.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 6700121b535fa16fe1c8aaac03559b2f12909726
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Sat Apr 21 11:08:25 2007 -0300

    ACPI: thinkpad-acpi: rename register_ibmacpi_subdriver
    
    Rename register_ibmacpi_subdriver to register_tpacpi_subdriver, as
    we are not called ibmacpi anymore.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 7053acbd78336abf5d4bc3d8a875a03624cfb83f
Author: Eric Miao <eric.y.miao@gmail.com>
Date:   Thu Apr 5 04:07:20 2007 +0100

    [ARM] 4304/1: removes the unnecessary bit number from CKENnn_XXXX
    
    This patch removes the unnecessary bit number from CKENnn_XXXX
    definitions for PXA, so that
    
    	CKEN0_PWM0 --> CKEN_PWM0
    	CKEN1_PWM1 --> CKEN_PWM1
    	...
    	CKEN24_CAMERA --> CKEN_CAMERA
    
    The reasons for the change of these defitions are:
    
    1. they do not scale - they are currently valid for pxa2xx, but
    definitely not valid for pxa3xx, e.g., pxa3xx has bit 3 for camera
    instead of bit 24
    
    2. they are unnecessary - the peripheral name within the definition
    has already announced its usage, we don't need those bit numbers
    to know which peripheral we are going to enable/disable clock for
    
    3. they are inconvenient - think about this: a driver programmer
    for pxa has to remember which bit in the CKEN register to turn
    on/off
    
    Another change in the patch is to make the definitions equal to its
    clock bit index, so that
    
       #define CKEN_CAMERA  (24)
    
    instead of
    
       #define CKEN_CAMERA  (1 << 24)
    
    this change, however, will add a run-time bit shift operation in
    pxa_set_cken(), but the benefit of this change is that it scales
    when bit index exceeds 32, e.g., pxa3xx has two registers CKENA
    and CKENB, totally 64 bit for this, suppose CAMERA clock enabling
    bit is CKENB:10, one can simply define CKEN_CAMERA to be (32 + 10)
    and so that pxa_set_cken() need minimum change to adapt to that.
    
    Signed-off-by: eric miao <eric.y.miao@gmail.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 075192ae807579448afcc0833bd349ccce057825
Author: Kevin Hilman <khilman@mvista.com>
Date:   Thu Mar 8 20:32:19 2007 +0100

    [ARM] 4262/1: OMAP: clocksource and clockevent support
    
    Update OMAP1 to enable support for hrtimers and dynticks by using new clocksource and clockevent infrastructure.
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 89df127246f23add865f4a8f719c990e41151843
Author: Kevin Hilman <khilman@mvista.com>
Date:   Thu Mar 8 20:30:38 2007 +0100

    [ARM] 4261/1: clockevent support for Versatile platform
    
    Update Versatile platform to use new clockevent infrastructure.
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit b49c87c2a5059af14b68ee5f596ac0e9c93678bb
Author: Kevin Hilman <khilman@mvista.com>
Date:   Thu Mar 8 20:25:13 2007 +0100

    [ARM] 4260/1: clocksource support for Versatile platform
    
    Update Versatile to use new clocksource infrastructure for basic timekeeping.
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit e32f1502be3fa459723b1e4105e014f0828f7513
Author: Kevin Hilman <khilman@mvista.com>
Date:   Thu Mar 8 20:23:59 2007 +0100

    [ARM] 4259/1: clockevent support for ixp4xx platform
    
    Update ixp4xx timer support to use new clockevent infrastructure.
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 9e4559ddffc012a73ea0b54ed3b6a219c1483ae9
Author: Kevin Hilman <khilman@mvista.com>
Date:   Wed Mar 14 17:33:24 2007 +0100

    [ARM] 4258/2: Support for dynticks in idle loop
    
    And, wrap timer_tick() and sysdev suspend/resume in
    !GENERIC_CLOCKEVENTS since clockevent layer takes care
    of these.
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 0567a0c022d5b343370a343121f38fd89925de55
Author: Kevin Hilman <khilman@mvista.com>
Date:   Tue Mar 13 20:29:24 2007 +0100

    [ARM] 4257/2: Kconfig support for GENERIC_CLOCKEVENTS
    
    This time with LEDS_TIMER set with !GENERIC_CLOCKEVENTS
    
    Signed-off-by: Kevin Hilman <khilman@mvista.com>
    Acked-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 5d01f133412b0e27b340ab1bbb2cf0017329ae61
Author: Simon Richter <Simon.Richter@kleinhenz.com>
Date:   Mon Apr 2 14:06:29 2007 +0100

    [ARM] 4300/1: Add picotux 200 ARM board
    
    Add the picotux 200 ARM board:
     - Enable its machine type in the filter in head.S
     - Add configuration option
     - Add board initialisation
     - Add default configuration
    
    Signed-off-by: Simon Richter <Simon.Richter@kleinhenz.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 6f621885feba507d40dd1bba253378ae04f9fe8e
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Wed Apr 11 12:42:09 2007 +0100

    [ARM] 4319/1: S3C2412: Add kconfig for MACH_SMDK2412
    
    Add Kconfig entry for SMDK2412 to go with the SMDK2413
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit a7717435656c874843b1742383cc37540f5ff91e
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Fri Apr 20 11:39:46 2007 +0100

    [ARM] 4326/1: S3C24XX: fix sparse errors in DMA code
    
    Fix the following sparse errors in arch/arm/plat-s3c24xx/dma.c:
    
    dma.c:47:30: warning: symbol 'dma_sel' was not declared. Should it be static?
    dma.c:883:6: warning: symbol 's3c2410_dma_waitforstop' was not declared. Should it be static?
    dma.c:961:1: warning: symbol 's3c2410_dma_started' was not declared. Should it be static?
    dma.c:1283:12: warning: symbol 's3c24xx_dma_sysclass_init' was not declared. Should it be static?
    dma.c:1295:12: warning: symbol 's3c24xx_dma_sysdev_register' was not declared. Should it be static?
    dma.c:1399:25: warning: symbol 's3c2410_dma_map_channel' was not declared. Should it be static?
    
    The patch makes all the relevant functions static.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 57e5171c9ff817d56344d8473e484d6870ae2bf3
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Fri Apr 20 11:19:16 2007 +0100

    [ARM] 4325/1: S3C24XX: remove s3c24xx_board
    
    Remove the use of struct s3c24xx_board as
    this is just as easily done by using the
    platform device registration functions to
    make the initialisation sequence easier.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit ce89c206ac03dfec700cfa538dcbcc347c0683ce
Author: Ben Dooks <ben-linux@fluff.org>
Date:   Fri Apr 20 11:15:27 2007 +0100

    [ARM] 4324/1: S3C24XX: remove clocks from s3c24xx_board
    
    Remove the clocks from the s3c24xx_board as part
    of the process of simplifying the initialisation
    sequence by removing struct s3c24xx_board.
    
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit ef08574729bcf65bbd1f0c9ad9b9baa9bbd7a830
Author: Graeme Gregory <gg@opensource.wolfsonmicro.com>
Date:   Mon Apr 2 12:00:33 2007 +0100

    [ARM] 4299/1: S3C AC97 fill in register bit defines
    
    Create defines in the same styles as other s3c include files
    giving names to bits in registers within the AC97 IO unit.
    
    Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
    Signed-off-by: Ben Dooks <ben-linux@fluff.org>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 13ea55b04eaafb60cd7df759c8d92566d1f19351
Author: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
Date:   Mon Apr 2 21:09:31 2007 +0100

    [ARM] 4301/1: add mach type cc9p9360js
    
    The support for that machine is not yet complete, but it's enough to
    be useful as a test platform for the serial and ethernet driver.
    
    Moreover a typo in the product name is fixed that I missed in the
    last patch.
    
    Signed-off-by: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 53b2e01be55f3c140e2704cf8d5f99ddba0ff823
Author: Vladimir Barinov <vbarinov@ru.mvista.com>
Date:   Wed Apr 11 16:32:46 2007 +0100

    [ARM] 4320/1: ixp4xx: cpu type detection stuff cleanup
    
    Move IXP4XX cpu detection stuff in a separate include file and remove unused definition.
    
    Signed-off-by: Vladimir Barinov <vbarinov@ru.mvista.com>
    Signed-off-by: Ruslan Sushko <rsushko@ru.mvista.com>
    Signed-off-by: Deepak Saxena <dsaxena@mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 45fba0846f5a5a48ed3c394aa4f8ca93699e7655
Author: Ruslan V. Sushko <rsushko@ru.mvista.com>
Date:   Fri Apr 6 15:00:31 2007 +0100

    [ARM] 4311/1: ixp4xx: add KIXRP435 platform
    
    Add Intel KIXRP435 Reference Platform based on IXP43x processor.
    Fixed after review : access to cp15 removed in identification functions,
    used access to global processor_id instead
    
    Signed-off-by: Vladimir Barinov <vbarinov@ru.mvista.com>
    Signed-off-by: Ruslan  Sushko <rsushko@ru.mvista.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 25735d10ba477d5128b1e5ccef42062bea429075
Author: Milan Svoboda <msvoboda@ra.rockwell.com>
Date:   Wed Mar 21 14:04:08 2007 +0100

    [ARM] 4275/1: generic gpio layer for ixp4xx
    
    This patch brings generic gpio layer support to ixp4xx. It creates
    functions needed for gpio->irq and irq->gpio translation.
    
    It expects and initial value to be passed to
    gpio_direction_output() which has been introduced by
    commit 28735a7253a6c24364765e80a5428b4a151fccc2 in Linus git tree.
    
    Generic gpio layer is going to be used by pxa2xx_udc driver.
    
    Signed-off-by: Milan Svoboda <msvoboda@ra.rockwell.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit f86bd61fd70af02e666a893aaf22653181423e99
Author: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
Date:   Wed Mar 28 18:06:41 2007 +0100

    [ARM] 4294/1: ns9xxx: Determine system clock from PLL register settings
    
    The function attribute const is abused here as the PLL register is read.  But I
    think this is all right because the PLL register cannot change without a reset.
    
    Note: This patch depends on 4293/1
    
    Signed-off-by: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 940089e007e8ed33295ef408b39a53e5ad518ebd
Author: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
Date:   Wed Mar 28 17:54:22 2007 +0100

    [ARM] 4293/1: ns9xxx: Add bit fields FS and ND to the definition of
    	SYS_PLL register
    
    Signed-off-by: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit fee64d1b55af57d7dba41f554769db83d7a32fde
Author: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
Date:   Wed Mar 28 17:18:30 2007 +0100

    [ARM] 4292/1: ns9xxx: Make REGGET consistant with REGSET
    
    This implies that REGGET gets a new parameter "var" to allow to hold the actual
    register value in a variable.
    
    Moreover REGGET was broken because it used "field" instead of
    "reg ## _ ## field" which proves that there are no callers to fix :-)
    
    Signed-off-by: Uwe Kleine-KÃ¶nig <ukleinek@informatik.uni-freiburg.de>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit a79220b7633b3926a9bd3527bdac3f04dbe6845c
Author: Matej Kenda <matej.kenda@hermes-softlab.com>
Date:   Mon Mar 5 13:06:40 2007 +0100

    [ARM] 4246/1: i2c-pxa: add adapter class to platform specific data
    
    Reposted patch for kernel 2.6.21-rc2.
    
    The driver i2c-pxa doesn't set the class member in i2c_adapter, which
    is used to register the I2C adapter. The hwmon (sensors) drivers (e.g.
    adm1021) that are connected to a i2c-pxa adapter don't attach because
    they expect that the adapter supports class I2C_CLASS_HWMON.
    
    This patch adds functionality to allow platforms to set the class and
    pass it as platform_data to the i2c-pxa driver. Sample usage in
    platform code:
    
    static struct i2c_pxa_platform_data my_i2c_platform_data = {
    	.class = I2C_CLASS_HWMON
    };
    
    static void __init my_platform_init(void)
    {
    	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
    
    	pxa_set_i2c_info(&my_i2c_platform_data);
    }
    
    Signed-off-by: Matej Kenda <matej.kenda@hermes-softlab.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 4fe4a2bf9a687fc87ea796c234da8c59df763aab
Author: Philipp Zabel <philipp.zabel@gmail.com>
Date:   Mon Feb 26 01:44:57 2007 +0100

    [ARM] 4236/2: basic {enable,disable}_irq_wake() support for PXA
    
    pxa_set_gpio_wake handles GPIOs > 1, so IRQ_TO_GPIO has to be used
    instead of just substracting IRQ_GPIO0 from the irq number.

commit c172cc92c87103c98b5cd359205b684bf99b5067
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 10:52:32 2007 +0100

    [ARM] mm 6: allow mem_types table to specify extended pte attributes
    
    Add prot_pte_ext to the mem_types table to allow the extended pte
    attributes to be passed to set_pte_ext(), thereby permitting us to
    specify memory type information for the hardware PTE entries.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit b29e9f5e64fb90d2e4be1c7ef8c925b56669c74a
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 10:47:29 2007 +0100

    [ARM] mm 5: Use mem_types table in ioremap
    
    We really want to be using the memory type table in ioremap, so we
    only have to do the CPU type fixups in one place.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 24e6c6996fb6e0e716c1dda1def1bb023a0fe43b
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 10:21:28 2007 +0100

    [ARM] mm 4: make create_mapping() more conventional
    
    Rather than our three separate loops to setup mappings (by page
    mappings up to a section boundary, then section mappings, and the
    remainder by page mappings) convert this to a more conventional
    Linux style of a loop over each page table level.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 4a56c1e41f19393577bdd5c774c289c199b7269d
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 10:16:48 2007 +0100

    [ARM] mm 3: separate out supersection mappings, avoid for <4GB
    
    Catalin Marinas at ARM Ltd says:
    > The CPU architects in ARM intended supersections only as a way to map
    > addresses >= 4GB. Supersections are not mandated by the architecture
    > and there is no easy way to detect their hardware support at run-time
    > (other than checking for a specific core). From the analysis done in
    > ARM, there wasn't a clear performance gain by using supersections
    > rather than sections (no significant improvement in the TLB misses).
    
    Therefore, we should avoid using supersections unless there's a real
    need (iow, we're mapping addresses >= 4GB).
    
    This means that we can simplify create_mapping() a bit since we will
    only use supersection mappings for addresses >= 4GB, which means that
    the physical, virtual and length must be multiples of the supersection
    mapping size.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit d5c98176ef34b8b78645646593c17e10f62f53ff
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 10:05:32 2007 +0100

    [ARM] mm 2: clean up create_mapping()
    
    There's now no need to carry around each protection separately.
    Instead, pass around the pointer to the entry in the mem_types
    array which we're interested in.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 2497f0a8125e307cf1fd4222bab53f66305eba27
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Apr 21 09:59:44 2007 +0100

    [ARM] mm 1: Combine mem_type domain into prot_* at init time
    
    Rather than combining the domain for a particular memory type with
    the protection information each time we want to use it, do so when
    we fix up the mem_type array at initialisation time.
    
    Rename struct mem_types to be mem_type - each structure is one
    memory type description, not several.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 235b185ce47ce64793362bd3ae4bcd8afc6b57b8
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Mar 4 20:44:59 2007 +0000

    [ARM] getuser.S and putuser.S don't need thread_info.h nor asm-offsets.h
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit b2a0d36fde90fa9dd20b7dde21dbcff09b130b38
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sun Mar 4 09:50:28 2007 +0000

    [ARM] ptrace: clean up single stepping support
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 0f0a00beb80624a446ba7c0152cd171008eeab2e
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Mar 3 19:45:25 2007 +0000

    [ARM] Remove needless linux/ptrace.h includes
    
    Lots of places in arch/arm were needlessly including linux/ptrace.h,
    resumably because we used to pass a struct pt_regs to interrupt
    handlers.  Now that we don't, all these ptrace.h includes are
    redundant.
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 27350afdfc94a78adbdee20bb00f6058a0ef1eab
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Sat Mar 3 11:51:31 2007 +0000

    [ARM] EBSA110: Add readsw/readsl/writesw/writesl
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit 7ab3f8d595a1b1e5cf8d726b72fd476fe0d0226c
Author: Russell King <rmk@dyn-67.arm.linux.org.uk>
Date:   Fri Mar 2 15:01:36 2007 +0000

    [ARM] Add ability to dump exception stacks to kernel backtraces
    
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

commit a491486a2087ac3dfc00efb4f838c8d684afaf54
Author: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Date:   Fri Mar 16 16:15:45 2007 +0100

    [JFFS2] Obsolete dirent nodes immediately on unlink, where possible.
    
    Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit ec98c681a5355469eee70227b7e0a88f0d688483
Author: Jan Engelhardt <jengelh@linux01.gwdg.de>
Date:   Thu Apr 19 16:21:41 2007 -0500

    Use menuconfig objects: MTD
    
    Use menuconfigs instead of menus, so the whole menu can be disabled at once
    instead of going through all options.
    
    Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 99f9b2431ed3da4a66cf1cfe74132a53a9569bba
Author: Eric W. Biederman <ebiederm@xmission.com>
Date:   Thu Apr 19 01:58:33 2007 -0600

    [MTD] mtd_blkdevs: Convert to use the kthread API
    
    thread_run is used intead of kernel_thread, daemonize, and mucking
    around blocking signals directly.
    
    Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 876b9276b993723f7a74d55b3b49b9186f05d09d
Author: Paul Walmsley <paul@booyaka.com>
Date:   Thu Apr 19 14:56:12 2007 +0200

    USB HID: add 'quirks' module parameter
    
    Add a 'quirks' module parameter for the usbhid module, so users can
    add or modify quirks at module load time.
    
    Signed-off-by: Paul Walmsley <paul@booyaka.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 8cef908235bcac898a4f4ccc50c781e08022a579
Author: Paul Walmsley <paul@booyaka.com>
Date:   Thu Apr 19 14:37:44 2007 +0200

    USB HID: add support for dynamically-created quirks
    
    Add internal support for dynamically-allocated HID quirks, "dquirks"
    (for "dynamic quirks").  Includes several functions to add/modify quirks
    from the list.  This code is used by the next patch to implement quirk
    modification upon module load.
    
    Signed-off-by: Paul Walmsley <paul@booyaka.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 8222fbe67cc6c83bb6d8d9d913aee17957fc0654
Author: Paul Walmsley <paul@booyaka.com>
Date:   Thu Apr 19 13:45:57 2007 +0200

    USB HID: clarify static quirk handling as squirks
    
    Rename existing quirks handling code that operates over a static array
    to "squirks" (short for static quirks) to differentiate it from the
    dynamically-allocated quirks that will be introduced in the
    next patch.  Add an accessor function specifically for static quirks,
    usbhid_exists_squirk().
    
    Signed-off-by: Paul Walmsley <paul@booyaka.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 2eb5dc30eb87aa30f67e3dff39d5c9f3fb643260
Author: Paul Walmsley <paul@booyaka.com>
Date:   Thu Apr 19 13:27:04 2007 +0200

    USB HID: encapsulate quirk handling into hid-quirks.c
    
    Move the USB_VENDOR* and USB_DEVICE* defines and the hid_blacklist[]
    array there from hid-core.c.  Add
    hid-quirks.c:usbhid_lookup_any_quirks() to return quirk information to
    hid-core.c.  Convert __u32, __u16 types to u32, u16.
    
    Signed-off-by: Paul Walmsley <paul@booyaka.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 3f114853d4f7c1746389f26e1d500887294da8fd
Author: Roland Dreier <rolandd@cisco.com>
Date:   Wed Apr 18 20:21:02 2007 -0700

    IB/mthca: Update HCA firmware revisions
    
    Update the driver's list of current firmware versions with Mellanox's
    latest releases.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 40b90430ecac40cc9adb26b808cc12a3d569da5d
Author: Robert Walsh <robert.walsh@qlogic.com>
Date:   Thu Mar 15 14:45:17 2007 -0700

    IB/ipath: Fix WC format drift between user and kernel space
    
    The kernel ib_wc structure now uses a QP pointer, but the user space
    equivalent uses a QP number instead.  This means we can no longer use
    a simple structure copy to copy stuff into user space.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 6ce73b07db7aa05d4a30716d6a99c832b6d9db4a
Author: Robert Walsh <robert.walsh@qlogic.com>
Date:   Thu Mar 15 14:45:16 2007 -0700

    IB/ipath: Check that a UD work request's address handle is valid
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 0d6172a4284b21e4762e8638a4d693ef52f63bfe
Author: Robert Walsh <robert.walsh@qlogic.com>
Date:   Thu Mar 15 14:45:15 2007 -0700

    IB/ipath: Remove duplicate stuff from ipath_verbs.h
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 253fb3902008353831525ab711909abdd5ee191f
Author: Robert Walsh <robert.walsh@qlogic.com>
Date:   Thu Mar 15 14:45:14 2007 -0700

    IB/ipath: Check reserved memory keys
    
    Don't let userspace use the direct-physical-map L_key or R_key.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit f0810daf74c564a3615eba5002cc11c21a0949ba
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:13 2007 -0700

    IB/ipath: Fix unit selection when all CPU affinity bits set
    
    At some point things changed so that all the affinity bits can be set,
    but cpus_full() macro is not true.  This caused problems with the unit
    selection logic on multi-unit (board) configurations.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 662af5813be9aadf95ca310b7b6d1d37070c9922
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:12 2007 -0700

    IB/ipath: Don't allow QPs 0 and 1 to be opened multiple times
    
    Signed-off-by: Robert Walsh <robert.walsh@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 53c1d2c943a67fb129ed2797182305a4633531fb
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:11 2007 -0700

    IB/ipath: Disable IB link earlier in shutdown sequence
    
    Move the code that shuts down the IB link earlier in the unload
    process, to be sure no new packets can arrive while we are unloading.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 490462c2686df6e35c21d1efe935e0b4a3bddb39
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:10 2007 -0700

    IB/ipath: Prevent random program use of diags interface
    
    To prevent random utility reads and writes of the diag interface to the
    chip, we first require a handshake of reading from offset 0 and writing
    to offset 0 before any other reads or writes can be done through the
    diags device.   Otherwise chip errors can be triggered.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit f5408ac7ccec0a7edd2b6add0da82735375a37a0
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:09 2007 -0700

    IB/ipath: On unrecoverable errors, force link down, LEDs off
    
    If the chip is no longer usable, LEDs should be turned off so system
    can be found easily in the cluster.
    
    Also some minor reorganizing so both chips print hardware error
    message at same point and only if there were unrecovered errors
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 27b044a815df7d4530bc68560796680ed588070c
Author: Michael Albaugh <Michael.Albaugh@QLogic.com>
Date:   Thu Mar 15 14:45:08 2007 -0700

    IB/ipath: Fix driver crash (in interrupt or during unload) after chip reset
    
    Re-init of the kernel structures after a chip reset was leaving the
    portdata structure for port zero in an inconsistent state, and a
    pointer to it either stale (in re-init code) or NULL (in devdata)
    Fixing the order of operations on this struct, and the condition for
    interrupt access, prevents the crashes.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 9783ab405844202b452ac673677e6c8f8c9a6a99
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:07 2007 -0700

    IB/ipath: Improve handling and reporting of parity errors
    
    Mostly cleanup.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 820054b7ca7a54ba94d89db4b3c53a24d2d66633
Author: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Date:   Thu Mar 15 14:45:06 2007 -0700

    IB/ipath: Print better error messages if kernel is misconfigured
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 569b87b47f906d65ee35d6ecc4767f20a6390b9b
Author: Arthur Jones <arthur.jones@qlogic.com>
Date:   Thu Mar 15 14:45:05 2007 -0700

    IB/ipath: Force PIOAvail update entry point
    
    Due to a chip bug, the PIOAvail register is not always updated to
    memory.  This patch allows userspace to force an update.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 7b196e2ff3953063b656212ff517f6115a1477b2
Author: Arthur Jones <arthur.jones@qlogic.com>
Date:   Thu Mar 15 14:45:04 2007 -0700

    IB/ipath: Call free_irq() on chip specific initialization failure
    
    In initialization, if we bailed at chip specific initialization, we
    forgot to clean up the irq we had requested.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 5a7d4eea9185c20275307fcd1077d6f9dfdab48a
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:03 2007 -0700

    IB/ipath: Discard multicast packets without a GRH
    
    This patch fixes a bug where multicast packets without a GRH were not
    being dropped as per the IB spec.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 0ed3c594e3878274787810422760dc7c51e0ee72
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:02 2007 -0700

    IB/ipath: Fix calculation for number of kernel PIO buffers
    
    If the module parameter "kpiobufs" is set too high, the calculation to
    reset it to a sane value was incorrect.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit c8c6f5d496fe794cbb52fe5a08c2bd839eecaa07
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:45:01 2007 -0700

    IB/ipath: Remove unused ipath_read_kreg64_port()
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit dd5190b6be0f3e27b6a4933a6a6d2d59957fc748
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:45:00 2007 -0700

    IB/ipath: Fix RDMA reads of length zero and error handling
    
    Fix RDMA read response length checking for RDMA_READ_RESPONSE_ONLY to
    allow a zero length response.  RDMA read responses which don't match
    the expected length or occur in response to some other operation
    should generate a completion queue error (see table 56, ch. 9.9.2.3 in
    the IB spec).
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit c7e29ff11f23ec78b3caf691789c2b791bb596bf
Author: Mark Debbage <mark.debbage@qlogic.com>
Date:   Thu Mar 15 14:44:59 2007 -0700

    IB/ipath: Allow receive ports mapped into userspace to be shared
    
    Improve port-sharing performance by allowing any process to receive
    packets from the shared hardware port under a spin lock for mutual
    exclusion. Previously, one process was nominated as the master and
    that process was responsible for receiving all packets from the shared
    hardware port and either consuming them or forwarding them to their
    destination. This led to starvation problems for other processes when
    the master process was busy in computation phases.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 0a5a83cffc03592c2102ad07b7532b596a16f8cd
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:58 2007 -0700

    IB/ipath: Fix port sharing on powerpc
    
    The port sharing feature mixed kernel virtual addresses as well as
    physical addresses for the offset used to describe the mmap address to
    map the InfiniPath hardware into user space.  This had a conflict on
    powerpc.  The new scheme converts it to a physical address so it
    doesn't conflict with chip addresses and yet still fits in 40/44 bits
    so it isn't truncated by 32-bit applications calling mmap64().
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 041eab9136d8325c332429df71d05ba3e0ea8ebc
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:57 2007 -0700

    IB/ipath: Fix CQ flushing when QP is modified to error state
    
    If a receive work request has been removed from the queue but has not
    had a CQ entry generated for it and the QP is modified to the error
    state, the completion entry generated is incorrect.  This patch fixes
    the problem.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 614d49a21e96737f84b13f644ac813f8eb6d297a
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:56 2007 -0700

    IB/ipath: Fix bad argument to clear_bit()
    
    Code was converted from a &= ~mask to clear_bit, but the bit was left
    shifted instead of being used directly, so we were either trashing
    memory several pages away, or sometimes taking a kernel page fault on
    an invalid page.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 8ec1077b35359c973f4b1de7c516be570a6df495
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:55 2007 -0700

    IB/ipath: Change packet problems vs chip errors handling and reporting
    
    Some types of packet errors are moderately common with longer IB
    cables and large clusters, and are not reported with prints by other
    IB HCA drivers.  This suppresses those messages unless the new
    __IPATH_ERRPKTDBG bit is set in ipath_debug.  Reporting of temporarily
    disabled frequent error interrupts was also made clearer
    
    We also distinguish between chip errors, and bad packets sent or
    received in the wording of the messages.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 6f5c407460bba332d6bee52e19f2305539395511
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:54 2007 -0700

    IB/ipath: Fix PSN update for RC retries
    
    This patch fixes a number of bugs with updating the PSN for retries of
    RC requests.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 0434d271fddaabd65aaa4dbd0145112d6e8aa388
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:53 2007 -0700

    IB/ipath: Fix QP error completion queue entries
    
    When switching to the QP error state, the completion queue entries
    (error or flush) were not being generated correctly.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 39c0d0b919ae5080163bd2d41c0271cda250d382
Author: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Date:   Thu Mar 15 14:44:52 2007 -0700

    IB/ipath: Fix up some debug messages
    
    ipath_dbg doesn't need the same prefixes that printk does.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 3859e39d75b72f35f7d38c618fbbacb39a440c22
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:51 2007 -0700

    IB/ipath: Support larger IB_QP_MAX_DEST_RD_ATOMIC and IB_QP_MAX_QP_RD_ATOMIC
    
    This patch adds support for multiple RDMA reads and atomics to be sent
    before an ACK is required to be seen by the requester.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 7b21d26ddad6912bf345e8e88a51a5ce98a036ad
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:50 2007 -0700

    IB/ipath: NMI cpu lockup if local loopback used
    
    If a post send is done in loopback and there is no receive queue
    entry, the sending QP is put on a timeout list for a while so the
    receiver has a chance to post a receive buffer. If the another post
    send is done, the code incorrectly tried to put the QP on the timeout
    list again an corrupted the timeout list. This eventually leads to a
    spin lock deadlock NMI due to the timer function looping forever with
    the lock held.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 9f9630d5e12a51f38513de0d64320a55ab6f02d5
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:49 2007 -0700

    IB/ipath: Fix SRQ limit event causing dropped CQ entry
    
    A silly programming error causes a CQ entry to not be generated if a
    SRQ limit event is generated.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 947d7617a1d876c2c93f73017a734e070c64d43b
Author: Ralph Campbell <ralph.campbell@qlogic.com>
Date:   Thu Mar 15 14:44:48 2007 -0700

    IB/ipath: Don't initialize port memory for subports
    
    A recent change was made to allocate memory for a port after CPU
    affinity is set. That change didn't account for subports and was
    trying to allocate memory for the port twice.
    
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 19085745598ec254fd814411b675b52380c3bac0
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:47 2007 -0700

    IB/ipath: Definitions of two RXE parity err bits were reversed
    
    The chip documentation on the expected TID vs eager TID parity error
    bits was reversed from what was implemented in the RTL, for both
    chips.  This corrects the definitions.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 165c552c35052284e8ec4f7e9c027dfd33490e2c
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:46 2007 -0700

    IB/ipath: Fix user memory region creation when IOMMU present
    
    The loop which initializes the user memory region from an array of
    pages was using the wrong limit for the array.  This worked OK when
    dma_map_sg() returned the same number as the number of pages.  This
    patch fixes the problem.
    
    Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 946db67fbf836af30835d610b914cdde0cf467f8
Author: Bryan O'Sullivan <bos@pathscale.com>
Date:   Thu Mar 15 14:44:45 2007 -0700

    IB/ipath: Add ability to set and clear IB local loopback
    
    This is a sticky state.  It is useful for diagnosing problems with
    boards versus cable/switch problems.
    
    Signed-off-by: Dave Olson <dave.olson@qlogic.com>
    Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit a89875fc7e23ec91561bc3742df3bd5d12b376b4
Author: Roland Dreier <rolandd@cisco.com>
Date:   Wed Apr 18 20:20:53 2007 -0700

    IPoIB: Remove pointless opcode field from debugging output
    
    There's no point in printing the opcode field in the completion
    handling debugging output, since the type of completion is already
    printed at the beginning of the line.  In fact the opcode field is not
    even defined for completions with a status other than success.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 9a4b65e35714516980c863bfb7edc5f232b8b458
Author: Hal Rosenstock <halr@voltaire.com>
Date:   Mon Apr 2 12:45:16 2007 -0400

    IB/umad: Fix declaration of dev_map[]
    
    The current ib_umad code never accesses bits past IB_UMAD_MAX_PORTS in
    dev_map[].  We shouldn't declare it to be twice as big.
    
    Pointed-out-by: Roland Dreier <rolandd@cisco.com>
    
    Signed-off-by: Hal Rosenstock <halr@voltaire.com>

commit 9b620d2a16814e5f2a063359c953c41f804e091a
Author: Roland Dreier <rolandd@cisco.com>
Date:   Wed Apr 18 20:20:53 2007 -0700

    IB: Remove reference to obsolete CONFIG_IPATH_CORE
    
    Since commit b1c1b6a3 ("IB/ipath: merge ipath_core and ib_ipath
    drivers"), CONFIG_IPATH_CORE no longer exists, so there's no reason to
    have a line for it in drivers/Makefile.
    
    Pointed out by Robert P. J. Day <rpjday@mindspring.com>.
    
    Signed-off-by: Roland Dreier <rolandd@cisco.com>

commit 4d5a1be98d8d40a7c558005d423b3daed8ba1ddb
Author: Paul Zaremba <pez-gpg@treeofice.net>
Date:   Wed Apr 18 15:29:47 2007 +0200

    USB HID: EMS USBII device needs HID_QUIRK_MULTI_INPUT
    
    Add HID_QUIRK_MULTI_INPUT to the EMS USBII (0x0b43/0003) so the kernel detects both joystick
    ports properly. Without it you end up with a single joystick node (js0) that combines the
    two physical port signals.
    
    Signed-off-by: Paul Zaremba <pez-gpg@treeofice.net>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit d7b8bcb0a0819315a51cae620ff7ae0c1704c069
Author: Michael Tokarev <mjt@tls.msk.ru>
Date:   Fri Oct 27 16:02:37 2006 +0400

    [SCSI] modalias for scsi devices
    
    The following patch adds support for sysfs/uevent modalias
    attribute for scsi devices (like disks, tapes, cdroms etc),
    based on whatever current sd.c, sr.c, st.c and osst.c drivers
    supports.
    
    The modalias format is like this:
    
     scsi:type-0x04
    
    (for TYPE_WORM, handled by sr.c now).
    
    Several comments.
    
    o This hexadecimal type value is because all TYPE_XXX constants
      in include/scsi/scsi.h are given in hex, but __stringify() will
      not convert them to decimal (so it will NOT be scsi:type-4).
      Since it does not really matter in which format it is, while
      both modalias in module and modalias attribute match each other,
      I descided to go for that 0x%02x format (and added a comment in
      include/scsi/scsi.h to keep them that way), instead of changing
      them all to decimal.
    
    o There was no .uevent routine for SCSI bus.  It might be a good
      idea to add some more ueven environment variables in there.
    
    o osst.c driver handles tapes too, like st.c, but only SOME tapes.
      With this setup, hotplug scripts (or whatever is used by the
      user) will try to load both st and osst modules for all SCSI
      tapes found, because both modules have scsi:type-0x01 alias).
      It is not harmful, but one extra module is no good either.
      It is possible to solve this, by exporting more info in
      modalias attribute, including vendor and device identification
      strings, so that modalias becomes something like
        scsi:type-0x12:vendor-Adaptec LTD:device-OnStream Tape Drive
      and having that, match for all 3 attributes, not only device
      type.  But oh well, vendor and device strings may be large,
      and they do contain spaces and whatnot.
      So I left them for now, awaiting for comments first.
    
    Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 44ec95425c1d9dce6e4638c29e4362cfb44814e7
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Feb 20 11:01:57 2007 -0500

    [SCSI] sg: cap reserved_size values at max_sectors
    
    This patch (as857) modifies the SG_GET_RESERVED_SIZE and
    SG_SET_RESERVED_SIZE ioctls in the sg driver, capping the values at
    the device's request_queue's max_sectors value.  This will permit
    cdrecord to obtain a legal value for the maximum transfer length,
    fixing Bugzilla #7026.
    
    The patch also caps the initial reserved_size value.  There's no
    reason to have a reserved buffer larger than max_sectors, since it
    would be impossible to use the extra space.
    
    The corresponding ioctls in the block layer are modified similarly,
    and the initial value for the reserved_size is set as large as
    possible.  This will effectively make it default to max_sectors.
    Note that the actual value is meaningless anyway, since block devices
    don't have a reserved buffer.
    
    Finally, the BLKSECTGET ioctl is added to sg, so that there will be a
    uniform way for users to determine the actual max_sectors value for
    any raw SCSI transport.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Acked-by: Jens Axboe <jens.axboe@oracle.com>
    Acked-by: Douglas Gilbert <dougg@torque.net>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 1079a2d251f24a7d9e7576217f5f738bc4218337
Author: Zachary Amsden <zach@vmware.com>
Date:   Tue Apr 10 08:53:08 2007 -0500

    [SCSI] BusLogic: stop using check_region
    
    I got so sick of seing the check_region warnings from BusLogic.c I actually
    fixed it properly.  Never use check region, reserve it before the probe
    with request region instead and check the error result; free region if
    setup fails.  Should be functionally identical to the original except for
    fixing the potential race.
    
    Signed-off-by: Zachary Amsden <zach@vmware.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit ad1331a792f9f253bef362de9b6872c6b8f88c0c
Author: Bastian Blank <bastian@waldi.eu.org>
Date:   Sat Apr 7 18:10:00 2007 +0900

    [SCSI] tgt: fix rdma transfer bugs
    
    - ibmstgt hits the max rdma transfer size (128k).
    - libsrp returns a rdma transfer error properly.
    
    Signed-off-by: Bastian Blank <bastian@waldi.eu.org>
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 4def7fa11208f779f22e6ba7344370b0220d3350
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Fri Apr 13 08:35:25 2007 -0400

    [SCSI] aacraid: fix aacraid not finding device
    
    Thanks for the help from Steve Fox and Duane Cox investigating this
    issue, I'd like to report that we found the problem. The issue is with
    the patch Steve Fox isolated below, by not accommodating older adapters
    properly and issuing a command they do not support when retrieving
    storage parameters about the arrays. This simple patch resolves the
    problem (and more accurately mimics the logic of the original code
    before the patch).
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 144ff8bf0d84a81806bfb5979b0a6b176b1fcace
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Wed Apr 4 15:49:54 2007 -0400

    [SCSI] aacraid: Correct SMC products in aacraid.txt
    
    Correct a spelling mistake for the SMC product names (replace 'B' with
    'R') in the Documentation/scsi/aacraid.txt file. This is a follow-up to
    a documentation patch '[PATCH] aacraid: Add SMC and SUN products to
    README' submitted and accepted to scsi-misc-2.6 on March 27 2007.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit ed773e66480fdcd06732eb2aa39362599dcd67fa
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 15:25:52 2007 -0500

    [SCSI] scsi_error.c: Add EH Start Unit retry
    
    Currently, the scsi error handler will issue a START_UNIT
    command if the drive indicates it needs its motor started
    and the allow_restart flag is set in the scsi_device. If,
    after the scsi error handler invokes a host adapter reset
    due to error recovery, a device is in a unit attention
    state AND also needs a START_UNIT, that device will be placed
    offline. The disk array devices on an ipr RAID adapter
    will do exactly this when in a dual initiator configuration.
    This patch adds a single retry to the EH initiated
    START_UNIT.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    
    Patch modified and
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e6be133b68ae2c8f89d46da25ed7b31b84793e7e
Author: Shashi Rao <shashi@sun.com>
Date:   Wed Mar 28 15:56:28 2007 -0700

    [MTD] Fix fwh_lock locking
    
    This is on a custom board with a mapping driver access to an ST
    M50LPW080 chip. This chip is probed successfully with
    do_map_probe("jedec_probe",...). If I use the mtdchar interface to
    perform unlock->erase->program->lock on any of the 16 eraseblocks in the
    chip, the chip is left in FL_STATUS mode while the data structures
    believe that the chip is in FL_READY mode. Hence, any subsequent reads
    to any flash byte results in 0x80 being read.
    
    Signed-off-by: Shashi Rao <shashi@sun.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit c2aecda79cd872679b9b11f9e59d797fb4c7d677
Author: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
Date:   Tue Mar 27 13:32:09 2007 +0200

    [JFFS2] Speed up mount for directly-mapped NOR flash
    
    Remove excessive scanning of empty flash after a clean
    marker for users of the point/unpoint method. cfi_cmdset_0001
    uses point/unpoint by default iff flash mapping is linear.
    The speedup is several orders of magnitude if FS is less than
    half full.
    
    Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 10731f83009e2556f98ffa5c7c2cbffe66dacfb3
Author: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date:   Wed Apr 4 13:59:11 2007 +0300

    [JFFS2] fix buffer sise calculations in jffs2_get_inode_nodes()
    
    In read inode we have an optimization which prevents one
    min. I/O unit (e.g. NAND page) to be read more then once.
    
    Namely, at the beginning we do not know which node type we read,
    so we read so we assume we read the directory entry, because it
    has the smallest node header. When we read it, we read up to the
    next min. I/O unit, just because if later we'll need to read more,
    we already have this data.
    
    If it turns out to be that the node is not directory entry, and
    we need more data, and we did not read it because it sits in the
    next min. I/O unit, we read the whole next (or several next)
    min. I/O unit(s). And if it happens to be that we read a data node,
    and we've read part of its data, we calculate partial CRC.
    So if later we need to check data CRC, we'll only read the rest
    of the data from further min. I/O units and continue CRC checking.
    
    This code was a bit messy and buggy. The bug was that it assumed
    relatively large min. I/O unit, so that the largest node header
    could overlap only one min. I/O unit boundary.
    
    This parch clean-ups the code a bit and fixes this bug.
    The patch was not tested on flash with small min. I/O unit, like
    NOR-ECC, nut it was tested on NAND with 512 bytes NAND page, so
    it at least does not break NAND. It was also tested with mtdram
    so it should not break NOR.
    
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 7f762ab24ca2215b69a1395b5b58877f8282a089
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Wed Apr 4 13:47:53 2007 +0300

    [JFFS2] Disable summary after wbuf recovery
    
    After a write error, any data in the write buffer must
    be relocated.  This is handled by the jffs2_wbuf_recover
    function.  This function does not fix up the erase block
    summary information that is collected for writing at the
    end of the block, which results in an incorrect summary
    (or BUG if the summary was found to be empty).
    
    As the summary is not essential (it is an optimisation),
    it may be disabled for the current erase block when this
    situation arises.  This patch does that.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 99c2594f0e13de1ca84f97efc3f9e7bc49f91e11
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Thu Mar 29 11:00:47 2007 +0300

    [JFFS2] Prevent list corruption when handling write errors
    
    If a write error occurs, the affected block is placed on the
    bad_used_list.  In the case that the write error occured
    when writing summary data the block was also being placed on
    the dirty_list, which caused list corruption and ultimately
    a soft lockup in jffs2_mark_node_obsolete. This fixes that.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit a5ac8aeb29000fcab8d91848273a6616fcd039ee
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Mon Mar 19 12:49:11 2007 +0200

    [MTD] nandsim: enhance nandsim to allow arbitrary NAND size
    
    A new module parameter has been added called 'overridesize',
    which overrides the size that would be determined by the
    ID bytes. 'overridesize' is specified in erase blocks and
    as the exponent of a power of two e.g. 5 means a size of
    32 erase blocks.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 57aa6b545f6f772dd317ccd29bdada999b16a13d
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Mon Mar 19 12:40:41 2007 +0200

    [MTD] nandsim: Enhance nandsim optionally to report wear information
    
    A new module parameter 'rptwear' specifies how many erases between
    reporting wear information.  Zero means never.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 514087e74fb401a6621e8c836f4eaab87c269f24
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Mon Mar 19 12:47:45 2007 +0200

    [MTD] nandsim: enhance nandsim to simulate flash errors
    
    New module parameters have been added to nandsim to
    simulate:
    
            bitflips        random bit flips
            badblocks       blocks that are initially marked bad
            weakblocks      blocks that fail to erase after a
                            small number of erase cycles
            weakpages       pages that fail to write after a
                            small number of successful writes
            gravepages      pages that fail to read after a
                            small number of successful reads
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 2b77a0ed54eeea61937e7f71b0487b815edfbcdf
Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
Date:   Mon Mar 19 12:46:43 2007 +0200

    [MTD] nandsim: add partition capability to nandsim
    
    Enhance nandsim to be able to create more than 1 partition.
    A new module parameter 'parts' may be used to specify partition
    sizes.
    
    Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit b0afbbec4981417f79e05865a36e57abfc289002
Author: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Date:   Wed Mar 21 11:07:05 2007 +0200

    [JFFS2] fix deadlock on error path
    
    When the MTD driver returns write failure, the following deadlock
    occurs:
    
    We are in __jffs2_flush_wbuf(), we hold &c->wbuf_sem. Write failure.
    jffs2_wbuf_recover()->jffs2_reserve_space_gc()->jffs2_do_reserve_space()
    ->jffs2_erase_pending_blocks()->jffs2_flash_read()
    
    and it tries to lock &c->wbuf_sem again. Deadlock.
    
    Reported-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
    Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 4226b510371efd9cdc628663527d36aee36054a9
Author: Andre Renaud <andre@bluewatersys.com>
Date:   Tue Apr 17 13:50:59 2007 -0400

    [MTD] [NAND] Casting bug in nand_default_block_markbad
    
    There is a slight bug in nand_default_block_markbad, where the offset is
    cast to an integer, prior to being shifted. This means that on large
    offsets, it is incorrectly doing a signed shift & losing bits. Fixed
    this by doing the cast after the shift (as is done elsewhere in the code).
    
    Signed-off-by: Andre Renaud <andre@bluewatersys.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 340ea370c2ce89d1c15fbf785460f2f74314ce58
Author: Hans-JÃ¼rgen Koch <hjk@linutronix.de>
Date:   Tue Apr 17 13:42:56 2007 -0400

    [MTD] Driver for AT26Fxxx dataflash devices
    
    Add support for AT26Fxxx dataflash devices. These devices have a quite different
    commandset than the AT45xxx chips, which are handled by at91_dataflash.c, so a
    combined driver turned out to be more ugly than useful.
    
    Tested only on AT26F004.
    
    Signed-off-by: Hans-JÃ¼rgen Koch <hjk@linutronix.de>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 408b483d9cc2d839ecbc9134958c42814865081c
Author: Thomas Gleixner <tglx@inhell4.(none)>
Date:   Fri Apr 13 19:50:48 2007 +0200

    [MTD] Fix length comparison in MEMREADOOB
    
    The ops.len member is not initialized, because it is unused for this
    operation. The length check needs to use ops.ooblen instead
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 1cf9827b6852d5d81130efbf2e777e50b7126d23
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Tue Apr 17 18:30:57 2007 +0100

    [MTD] [NAND] Move ancient NAND chip support into a config option
    
    The support for obsolete ancient NAND chips adds .data size and one
    of the old ids conflicts with a modern one. Make the support for
    such chips depending on a config option.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 90424de8d0646eaf7cddbdb111edaf429dea6042
Author: Thomas Gleixner <tglx@inhell4.tec.linutronix.de>
Date:   Thu Apr 5 11:44:05 2007 +0200

    [MTD] [NAND] Use ecc.read/write_page_raw consequently
    
    Use the functions in the ecc structure instead of the default ones,
    so the override by the board driver is effective also for software ecc
    code paths.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 8c60e5475d8ca614d712cd3e2fe7330480709e02
Author: sshahrom@micron.com <sshahrom@micron.com>
Date:   Wed Mar 21 18:48:02 2007 -0700

    [MTD][NAND] Add Micron Manufacturer ID
    
    Add Micron Manufacturer ID.
    
    Signed-off-by: Shahrom Sharif <sshahrom@micron.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 53043002ef6cc0369fd5c5fa0a257f290ba6a3a6
Author: Thomas Gleixner <tglx@inhell4.tec.linutronix.de>
Date:   Thu Apr 5 11:09:01 2007 +0200

    [JFFS2] check node crc before doing anything else
    
    Check the node CRC on scan before doing anything else with the node.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 873b6a230652803d1de480f5d3b802e4ffd0bcad
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Sat Mar 10 23:10:50 2007 +0000

    [MTD] Fix dependencies for MIPS MTD drivers
    
     o A dependency on the processor architecture does not make sense;
       delete it.
     o The Alchemy and MTX drivers requires MTD_PARTITIONS and MTD_CFI to work,
       make those dependencies.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 19da63d1d2df393f8bf891d02e9960430f9178f8
Author: Ralf Baechle <ralf@linux-mips.org>
Date:   Sat Mar 10 23:14:12 2007 +0000

    [MTD] Alchemy cleanups
    
    Delete RCS $Id string and unused debug code.
    
    Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit c2fa1b8a6c059dd08a802545fed3badc8df2adc1
Author: J. Bruce Fields <bfields@citi.umich.edu>
Date:   Tue Feb 20 16:10:11 2007 -0500

    locks: create posix-to-flock helper functions
    
    Factor out a bit of messy code by creating posix-to-flock counterparts
    to the existing flock-to-posix helper functions.
    
    Cc: Christoph Hellwig <hch@infradead.org>
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit 226a998dbf3c6f9b85f67d08a52c5a2143ed9d88
Author: J. Bruce Fields <bfields@citi.umich.edu>
Date:   Wed Feb 14 14:25:00 2007 -0500

    locks: trivial removal of unnecessary parentheses
    
    Remove some unnecessary parentheses.
    
    Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>

commit f142b3a4f64eca235f5890d9cecb68482f62ed26
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Mon Apr 16 11:29:28 2007 +0200

    HID: update copyright and authorship macro
    
    Updates Copyright and DRIVER_AUTHOR in HID and USB HID sources.
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 390cbb56a731546edc0f35fbc4c5045676467581
Author: Paul Mackerras <paulus@samba.org>
Date:   Fri Apr 13 10:46:21 2007 +1000

    [POWERPC] Fix detection of loader-supplied initrd on OF platforms
    
    Commit 79c8541924a220964f9f2cbed31eaa9fdb042eab introduced code to move
    the initrd if it was in a place where it would get overwritten by the
    kernel image.  Unfortunately this exposed the fact that the code that
    checks whether the values passed in r3 and r4 are intended to indicate
    the start address and size of an initrd image was not as thorough as the
    kernel's checks.  The symptom is that on OF-based platforms, the
    bootwrapper can cause an exception which causes the system to drop back
    into OF.
    
    Previously it didn't matter so much if the code incorrectly thought that
    there was an initrd, since the values for start and size were just passed
    through to the kernel.  Now the bootwrapper needs to apply the same checks
    as the kernel since it is now using the initrd data itself (in the process
    of copying it if necessary).  This adds the code to do that.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 98750261fbf6348517ef517f617014de8238475f
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 18:01:34 2007 -0500

    [POWERPC] Miscellaneous arch/powerpc Kconfig and platform/Kconfig cleanup
    
    * Cleaned up some whitespace in arch/powerpc/Kconfig
    * Moved sourcing of platforms/embedded6xx/Kconfig into platform/Kconfig
    * Moved sourcing of platforms/4xx/Kconfig into platform/Kconfig and disabled it
    * Removed EMBEDDEDBOOT since its not supported in arch/powerpc
    * Removed PC_KEYBOARD since its not used anywhere
    * Moved a few CONFIG options around in platform/Kconfig
    * Moved interrupt controllers into platform/Kconfig out of bus section
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit db9478086dc9c8b46b19f5308c49caff773110ff
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 17:44:07 2007 -0500

    [POWERPC] Convert 85xx platform to unified platform Kconfig
    
    Moved 85xx platform Kconfig over to being sourced by the unified
    arch/powerpc/platforms/Kconfig.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit c8a55f3ddaa725a171385d9ffb416b183243856e
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 17:35:54 2007 -0500

    [POWERPC] Convert 8xx platform to unified platform Kconfig
    
    Moved 8xx platform Kconfig over to being sourced by the unified
    arch/powerpc/platforms/Kconfig.  Also, cleaned up whitespace issues in 8xx
    Kconfig.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit d6071f881fcd3c45c00ea1c2d13a5b01bbb6c412
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 16:53:32 2007 -0500

    [POWERPC] Convert 82xx platform to unified platform Kconfig
    
    Moved 82xx platform Kconfig over to being sourced by the unified
    arch/powerpc/platforms/Kconfig.  Also, cleaned up whitespace issues in 82xx
    Kconfig.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit b5a4834692ab799a7a6b75a7f1e20e9f41a3126e
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 15:46:21 2007 -0500

    [POWERPC] Convert 83xx platform to unified platform Kconfig
    
    Moved 83xx platform Kconfig over to being sourced by the unified
    arch/powerpc/platforms/Kconfig.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 4a89f7fa7a32e35d3b5d956846cd2ae274db5ed2
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 15:41:26 2007 -0500

    [POWERPC] Convert 86xx platform to unified platform Kconfig
    
    Moved 86xx platform Kconfig over to being sourced by the unified
    arch/powerpc/platforms/Kconfig.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 164a460d467a43e9f403cd4b76cec626dff99779
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Apr 12 15:35:50 2007 -0500

    [POWERPC] Ensure platform CONFIG options have correct dependencies
    
    We currently support TAU and CPU frequency scaling only on discrete
    (non-SOC) processors.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 0727702a3a6a9e33db4a4f9a038327d014753b6e
Author: Joachim Fenkes <fenkes@de.ibm.com>
Date:   Thu Mar 22 17:00:46 2007 +0100

    [POWERPC] ibmebus: change probe/remove interface from using loc-code to DT path
    
    In some cases, multiple OFDT nodes might share the same location code, so
    the location code is not a unique identifier for an OFDT node. Changed the
    ibmebus probe/remove interface to use the DT path of the device node instead
    of the location code.
    
    The DT path must be written into probe/remove right as it would appear in
    the "devspec" attribute of the ebus device: relative to the DT root, with a
    leading slash and without a trailing slash. One trailing newline will not
    hurt; multiple newlines will (like perl's chomp()).
    
    Example:
    
     Add a device "/proc/device-tree/foo@12345678" to ibmebus like this:
        echo /foo@12345678 > /sys/bus/ibmebus/probe
    
     Remove the device like this:
        echo /foo@12345678 > /sys/bus/ibmebus/remove
    
    Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 370a908db154f51008cea41e67e7409efa251c7b
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Thu Apr 12 15:30:23 2007 +1000

    [POWERPC] DEBUG_PAGEALLOC for 64-bit
    
    Here's an implementation of DEBUG_PAGEALLOC for 64 bits powerpc.
    It applies on top of the 32 bits patch.
    
    Unlike Anton's previous attempt, I'm not using updatepp. I'm removing
    the hash entries from the bolted mapping (using a map in RAM of all the
    slots). Expensive but it doesn't really matter, does it ? :-)
    
    Memory hot-added doesn't benefit from this unless it's added at an
    address that is below end_of_DRAM() as calculated at boot time.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    
     arch/powerpc/Kconfig.debug      |    2
     arch/powerpc/mm/hash_utils_64.c |   84 ++++++++++++++++++++++++++++++++++++++--
     2 files changed, 82 insertions(+), 4 deletions(-)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 88df6e90fa9782dbf44d936e44649afe271e4790
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Thu Apr 12 15:30:22 2007 +1000

    [POWERPC] DEBUG_PAGEALLOC for 32-bit
    
    Here's an implementation of DEBUG_PAGEALLOC for ppc32. It disables BAT
    mapping and is only tested with Hash table based processor though it
    shouldn't be too hard to adapt it to others.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    
     arch/powerpc/Kconfig.debug       |    9 ++++++
     arch/powerpc/mm/init_32.c        |    4 +++
     arch/powerpc/mm/pgtable_32.c     |   52 +++++++++++++++++++++++++++++++++++++++
     arch/powerpc/mm/ppc_mmu_32.c     |    4 ++-
     include/asm-powerpc/cacheflush.h |    6 ++++
     5 files changed, 74 insertions(+), 1 deletion(-)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ee4f2ea48674b6c9d91bc854edc51a3e6a7168c4
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Thu Apr 12 15:30:22 2007 +1000

    [POWERPC] Fix 32-bit mm operations when not using BATs
    
    On hash table based 32 bits powerpc's, the hash management code runs with
    a big spinlock. It's thus important that it never causes itself a hash
    fault. That code is generally safe (it does memory accesses in real mode
    among other things) with the exception of the actual access to the code
    itself. That is, the kernel text needs to be accessible without taking
    a hash miss exceptions.
    
    This is currently guaranteed by having a BAT register mapping part of the
    linear mapping permanently, which includes the kernel text. But this is
    not true if using the "nobats" kernel command line option (which can be
    useful for debugging) and will not be true when using DEBUG_PAGEALLOC
    implemented in a subsequent patch.
    
    This patch fixes this by pre-faulting in the hash table pages that hit
    the kernel text, and making sure we never evict such a page under hash
    pressure.
    
    Signed-off-by: Benjamin Herrenchmidt <benh@kernel.crashing.org>
    
     arch/powerpc/mm/hash_low_32.S |   22 ++++++++++++++++++++--
     arch/powerpc/mm/mem.c         |    3 ---
     arch/powerpc/mm/mmu_decl.h    |    4 ++++
     arch/powerpc/mm/pgtable_32.c  |   11 +++++++----
     4 files changed, 31 insertions(+), 9 deletions(-)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3be4e6990edf65624cfcbf8f7e33810626b2eefa
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Thu Apr 12 15:30:21 2007 +1000

    [POWERPC] Cleanup 32-bit map_page
    
    The 32 bits map_page() function is used internally by the mm code
    for early mmu mappings and for ioremap. It should never be called
    for an address that already has a valid PTE or hash entry, so we
    add a BUG_ON for that and remove the useless flush_HPTE call.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    
     arch/powerpc/mm/pgtable_32.c |    9 ++++++---
     1 file changed, 6 insertions(+), 3 deletions(-)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a741e67969577163a4cfc78d7fd2753219087ef1
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Tue Apr 10 17:09:37 2007 +1000

    [POWERPC] Make tlb flush batch use lazy MMU mode
    
    The current tlb flush code on powerpc 64 bits has a subtle race since we
    lost the page table lock due to the possible faulting in of new PTEs
    after a previous one has been removed but before the corresponding hash
    entry has been evicted, which can leads to all sort of fatal problems.
    
    This patch reworks the batch code completely. It doesn't use the mmu_gather
    stuff anymore. Instead, we use the lazy mmu hooks that were added by the
    paravirt code. They have the nice property that the enter/leave lazy mmu
    mode pair is always fully contained by the PTE lock for a given range
    of PTEs. Thus we can guarantee that all batches are flushed on a given
    CPU before it drops that lock.
    
    We also generalize batching for any PTE update that require a flush.
    
    Batching is now enabled on a CPU by arch_enter_lazy_mmu_mode() and
    disabled by arch_leave_lazy_mmu_mode(). The code epects that this is
    always contained within a PTE lock section so no preemption can happen
    and no PTE insertion in that range from another CPU. When batching
    is enabled on a CPU, every PTE updates that need a hash flush will
    use the batch for that flush.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e4ee3891db35aa9a069bb403c2a66a8fbfa274d6
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Wed Apr 11 16:13:19 2007 +1000

    [POWERPC] Alignment exception uses __get/put_user_inatomic
    
    Make the alignment exception handler use the new _inatomic variants
    of __get/put_user. This fixes erroneous warnings in the very rare
    cases where we manage to have copy_tofrom_user_inatomic() trigger
    an alignment exception.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    
     arch/powerpc/kernel/align.c |   56 ++++++++++++++++++++++++--------------------
     1 file changed, 31 insertions(+), 25 deletions(-)
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e68c825bb016703eda94aac99be96de73b482d61
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Wed Apr 11 16:13:19 2007 +1000

    [POWERPC] Add inatomic versions of __get_user and __put_user
    
    Those are needed by things like alignment exception fixup handlers
    since those can now be triggered by copy_tofrom_user_inatomic.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 06533e28c9e8b252fbfb6858647afe48b5147e16
Author: Milind Arun Choudhary <milindchoudhary@gmail.com>
Date:   Wed Apr 4 22:07:40 2007 +0530

    [POWERPC] Clean up unused ROUND_UP, NAME_OFFSET macros in arch/powerpc
    
    Unused ROUND_UP, NAME_OFFSET macro cleanup
    
    Signed-off-by: Milind Arun Choudhary <milindchoudhary@gmail.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e48059225c2edc6f1e5a2008261f1efdf606f247
Author: Olaf Hering <olaf@aepfle.de>
Date:   Wed Apr 4 18:20:04 2007 +0200

    [POWERPC] Add correct interrupt property for pegasos ide
    
    The firmware assigns irq 20/21 to the VIA IDE device on Pegasos.
    But the required interrupt is 14/15.
    Maybe someone confused decimal vs. hexadecimal values.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9c1a2bae0cc52b21121ea2380a2db0294ad0d8e7
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 22:50:59 2007 +1000

    [POWERPC] Rename get_property to of_get_property: the last one
    
    This also fixes a bug where a property value was being modified
    in place.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d05c7a80cf39ae7d0f8d0c3e47c93d51fcd393d3
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 22:40:39 2007 +1000

    [POWERPC] Rename get_property to of_get_property: drivers
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c4f55b394505fff6ad831d17e36e02dde1c3a8d7
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 22:39:14 2007 +1000

    [POWERPC] Rename get_property to of_get_property: sound
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e2eb63927bfcb54232163bfec32440246fd44457
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 22:26:41 2007 +1000

    [POWERPC] Rename get_property to of_get_property: arch/powerpc
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ceef87782a9452eeeca774e65d7f4e06455780a3
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 22:24:06 2007 +1000

    [POWERPC] Rename get_property to of_get_property: include
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 721151d004dcf01a71b12bb6b893f9160284cf6e
Author: Paul Mackerras <paulus@samba.org>
Date:   Tue Apr 3 21:24:02 2007 +1000

    [POWERPC] Allow drivers to map individual 4k pages to userspace
    
    Some drivers have resources that they want to be able to map into
    userspace that are 4k in size.  On a kernel configured with 64k pages
    we currently end up mapping the 4k we want plus another 60k of
    physical address space, which could contain anything.  This can
    introduce security problems, for example in the case of an infiniband
    adaptor where the other 60k could contain registers that some other
    program is using for its communications.
    
    This patch adds a new function, remap_4k_pfn, which drivers can use to
    map a single 4k page to userspace regardless of whether the kernel is
    using a 4k or a 64k page size.  Like remap_pfn_range, it would
    typically be called in a driver's mmap function.  It only maps a
    single 4k page, which on a 64k page kernel appears replicated 16 times
    throughout a 64k page.  On a 4k page kernel it reduces to a call to
    remap_pfn_range.
    
    The way this works on a 64k kernel is that a new bit, _PAGE_4K_PFN,
    gets set on the linux PTE.  This alters the way that __hash_page_4K
    computes the real address to put in the HPTE.  The RPN field of the
    linux PTE becomes the 4k RPN directly rather than being interpreted as
    a 64k RPN.  Since the RPN field is 32 bits, this means that physical
    addresses being mapped with remap_4k_pfn have to be below 2^44,
    i.e. 0x100000000000.
    
    The patch also factors out the code in arch/powerpc/mm/hash_utils_64.c
    that deals with demoting a process to use 4k pages into one function
    that gets called in the various different places where we need to do
    that.  There were some discrepancies between exactly what was done in
    the various places, such as a call to spu_flush_all_slbs in one case
    but not in others.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1a38147ed0737a9c01dbf5f2ca47fd2a0aa5cb55
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:58:52 2007 +1000

    [POWERPC] Make struct property's value a void *
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9213feea6e197f8507ec855337798cc3388f5570
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:57:48 2007 +1000

    [POWERPC] Rename prom_n_size_cells to of_n_size_cells
    
    This is more consistent and gets us closer to the Sparc code.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a8bda5dd4f99d6469f3c0dc362db3cce8a4d6416
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:56:50 2007 +1000

    [POWERPC] Rename prom_n_addr_cells to of_n_addr_cells
    
    This is more consistent and gets us closer to the Sparc code.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7a92f74f98bde8498c98aad6cac5da5a87dd0bf4
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:55:39 2007 +1000

    [POWERPC] Rename device_is_compatible to of_device_is_compatible
    
    This is more consistent and gets us closer to the Sparc code.
    
    We add a device_is_compatible define for compatibility during the
    change over.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0e56efc7dcd1eb5004363e52bdbe801783245638
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:54:01 2007 +1000

    [POWERPC] Rename get_property to of_get_property
    
    This is more consistent and gets us closer to the Sparc code.
    
    We add a get_property define for compatibility during the change over.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a7edd0e676d51145ae634a2acf7a447e319200fa
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Tue Apr 3 10:52:17 2007 +1000

    [POWERPC] get_property returns const
    
    This just tidies up some of the remains.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6c2d046980299d52d78b2738ad7f11fc593dea75
Author: Olaf Hering <olaf@aepfle.de>
Date:   Mon Apr 2 14:33:27 2007 +0200

    [POWERPC] Fix modalias content in sysfs for macio devices
    
    Currently the buf pointer is advanced too far during each iteration.
    Also terminate the string with a newline.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9414715a7bbb45450015e9bc2676d85d919d08d4
Author: Olaf Hering <olaf@aepfle.de>
Date:   Sat Mar 31 17:08:23 2007 +0200

    [POWERPC] Autodetect serial console on efika
    
    Efika boards have to be booted with console=ttyPSC0 unless there is a
    graphics card plugged in. Detect if the firmware stdout is the serial
    connector.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Acked-by: Grant Likely <grant.likely@secretlab.ca>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 02cc51149f99e3c6c106e1e16dcc2e016b1bc3b5
Author: Milton Miller <miltonm@bga.com>
Date:   Thu Mar 29 07:31:41 2007 -0600

    [POWERPC] bootwrapper: Decompress less, check more
    
    Our kernels put everything in the first load segment, and we read that.
    Instead of decompressing to the end of the gzip stream or supplied image
    and hoping we get it all, decompress the expected size and complain if
    it is not available.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1383a34fafeb9f49975fc33783960729fbd2cddf
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 28 02:21:04 2007 -0600

    [POWERPC] bootwrapper: no-gzip fixes
    
    Commit a9903811bf8d130a26004f9cb27b66513a267908 missed two uses of the
    the .gz suffix in the wrapper script and didn't clean the additonal
    possibly cached files.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Acked-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f4bdbfc41b3cad813745f64fb849c298770da517
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 28 02:21:02 2007 -0600

    [POWERPC] bootwrapper: missing relocation in crt0.S
    
    crt0.S had provisions to provide run address relocaton to got2 and
    cache flush, but not on the bss clear or stack pointer load.  Apply
    the same fixup for them.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d6f1d2a9a83f447af6c210c8268ce117772da77f
Author: Mark A. Greer <mgreer@mvista.com>
Date:   Tue Mar 27 15:31:41 2007 -0700

    [POWERPC] Routine to find the devtree node of a linux,phandle
    
    Signed-off-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 88e687313e683ee006152d611b95f40900e3bce0
Author: Mark A. Greer <mgreer@mvista.com>
Date:   Tue Mar 27 15:29:50 2007 -0700

    [POWERPC] Move bootwrapper ELF parsing routines to a file
    
    The ELF parsing routines local to arch/powerpc/boot/main.c are useful
    to other callers therefore move them to their own file.
    
    Signed-off-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5e41763ae9b4b6335fab88da85600f16d7a5a7b5
Author: Giuliano Pochini <pochini@shiny.it>
Date:   Mon Mar 26 21:40:28 2007 -0800

    [POWERPC] Fix breakage caused by 72486f1f8f0a2bc828b9d30cf4690cf2dd6807fc
    
    72486f1f8f0a2bc828b9d30cf4690cf2dd6807fc inverted the sense for enabling
    hotplug CPU controls without reference to any other architecture other than
    i386, ia64 and PowerPC.  This left everyone else without hotplug CPU control.
    
    Fix powerpc for this brain damage.
    
    (akpm: patch adapted from rmk's ARM fix.  Changelog stolen from rmk)
    
    Signed-off-by: Giuliano Pochini <pochini@shiny.it>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Cc: Russell King <rmk@arm.linux.org.uk>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6590a0197cc89e663d884503073dbe235b3bd860
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Mar 26 21:40:27 2007 -0800

    [POWERPC] Remove unused header file: arch/ppc/syslib/cpc710.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0fbbeba2427a842a1a4ac9f379ca2ca37ea907eb
Author: Bart Van Assche <bart.vanassche@gmail.com>
Date:   Mon Mar 26 21:40:29 2007 -0800

    [POWERPC] Ocotea board: ntpd complains that the frequency error exceeds the tolerance
    
    Lifted from http://bugzilla.kernel.org/show_bug.cgi?id=8182
    
    Steps to reproduce:
    - Boot an Ocotea board with the mainline 2.6.20.1 kernel.
    - Create an /etc/ntp.conf file with at least one NTP server and iburst mode set.
    - Issue the command "ntpd -g".
    - Wait about two minutes.
    - Verify ntpd's status via "ntpq -pn" and by looking in /var/log/ntp.
    
    This fixes this problem by adjusting the expected clock frequency.
    
    Cc: Kumar Gala <galak@gate.crashing.org>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6e1af384f1c1742ae6d86bbf779d4fa020c509bc
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 26 15:52:24 2007 -0500

    [POWERPC] bootwrapper: Add dt_xlate_reg(), and use it to find serial registers.
    
    dt_xlate_reg() uses the ranges properties of a node's parentage to find
    the absolute physical address of the node's registers.
    
    The ns16550 driver uses this when no virtual-reg property is found.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit dbf8eefa2b814d6922492120bfa46d4bc42ceb20
Author: Christoph Hellwig <hch@lst.de>
Date:   Fri Mar 23 15:12:26 2007 +0100

    [POWERPC] spufs: don't yield CPU in spu_yield
    
    There is no reason to yield the CPU in spu_yield - if the backing
    thread reenters spu_run it gets added to the end of the runqueue for
    it's priority.  So the yield is just a slowdown for the case where
    we have higher priority contexts waiting.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Acked-by: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 28066ae91b2050d79531a6f2d5e35dd8f666bafd
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Fri Mar 23 14:06:43 2007 +0100

    [POWERPC] CBE thermal support on PS3
    
    I wanted to enable CBE_THERM on PS3.  So I had to enable CBE_RAS first.
    
    But the resulting kernel doesn't link, as cbe_regs.c isn't compiled for
    non-PPC_CELL_NATIVE.
    
    CBE_RAS should depend on PPC_CELL_NATIVE; this makes it so.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Acked-by: Arnd Bergmann <arnd@arndb.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a5bcbcaff24185695b296d4aa2278c5f890a7987
Author: Sonny Rao <sonny@burdell.org>
Date:   Thu Mar 22 22:44:31 2007 -0400

    [POWERPC] Remove stale comment from head_64.S
    
    This is now inaccurate because we may not have entered prom_init() and
    r3 is overwritten immediately anyway.
    
    Signed-off-by: Sonny Rao <sonny@burdell.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8545cd201134860b1eb72578419f5cbd4c0789c0
Author: Olaf Hering <olaf@aepfle.de>
Date:   Fri Mar 23 01:11:59 2007 +0100

    [POWERPC] Remove unused inclusion of linux/ide.h
    
    Remove unneeded inclusion of linux/ide.h
    It does not compile with CONFIG_BLOCK=n.
    
    Remove asm/ide.h from ksyms file, it gets included earlier via
    linux/ide.h.
    
    Compile tested with all defconfig files.
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e51b85dcf56c87772b47a0781e6cfa88848b50b8
Author: Tony Vroon <chainsaw@gentoo.org>
Date:   Thu Mar 22 23:31:08 2007 +0000

    [POWERPC] PMU LED whitelisting of PowerMac 7,2 and 7,3
    
    This allows the PMU LED on both a PowerMac 7,2 (Dual G5 2.0GHz, June 2003)
    and a PowerMac 7,3 (Dual G5 2.0GHz, June 2004) to be controlled.
    The physical LED is never off, unlike an iBook/PowerBook LED.
    It is rather dim ("off") or very bright ("on").
    
    Signed-off-by: Tony Vroon <chainsaw@gentoo.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c3b9d9ab96becbd901bd31db0ea8174fcc02e83f
Author: Olaf Hering <olaf@aepfle.de>
Date:   Thu Mar 22 23:14:07 2007 +0100

    [POWERPC] Fix link errors when EEH is disabled
    
    Fix link errors with CONFIG_EEH=n:
    
    arch/powerpc/platforms/built-in.o: In function `.pcibios_fixup_new_pci_devices':
    (.text+0x41c8): undefined reference to `.eeh_add_device_tree_late'
    arch/powerpc/platforms/built-in.o: In function `.init_phb_dynamic':
    (.text+0x4280): undefined reference to `.eeh_add_device_tree_early'
    arch/powerpc/platforms/built-in.o: In function `.pcibios_remove_pci_devices':
    (.text+0x42fc): undefined reference to `.eeh_remove_bus_device'
    arch/powerpc/platforms/built-in.o: In function `.pcibios_add_pci_devices':
    (.text+0x43c0): undefined reference to `.eeh_add_device_tree_early'
    arch/powerpc/platforms/built-in.o: In function `.pSeries_final_fixup':
    (.init.text+0xb4): undefined reference to `.pci_addr_cache_build'
    make[1]: *** [.tmp_vmlinux1] Error 1
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3af82a8b00f98ca54e4c860eeb2b9ede6d8cadf4
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Thu Mar 22 17:02:21 2007 +1100

    [POWERPC] Clean up zImage handling of the command line
    
    This cleans up how the zImage code manipulates the kernel
    command line.  Notable improvements from the old handling:
    	- Command line manipulation is consolidated into a new
    prep_cmdline() function, rather than being scattered across start()
    and some helper functions
    	- Less stack space use: we use just a single global command
    line buffer, which can be initialized by an external tool as before,
    we no longer need another command line sized buffer on the stack.
    	- Easier to support platforms whose firmware passes a
    commandline, but not a device tree.  Platform code can now point new
    loader_info fields to the firmware's command line, rather than having
    to do early manipulation of the /chosen bootargs property which may
    then be rewritten again by the core.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 27fbaa9702e548e74dffd21855769f6cedad42bd
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Thu Mar 22 17:02:21 2007 +1100

    [POWERPC] Add device tree utility functions to zImage
    
    This patch adds a library of useful device tree manipulation functions
    to the zImage library, for use by platform code.  These functions are
    based on the hooks already in dt_ops, so they're not dependent on a
    particular device tree implementation.  This patch also slightly
    streamlines the code in main.c using these new functions.
    
    This is a consolidation of my work in this area with Scott Wood's
    patches to a very similar end.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3467bfd340f9ad48f3732415533a2e9c18240b62
Author: Olof Johansson <olof@lixom.net>
Date:   Thu Mar 22 09:34:13 2007 -0500

    [POWERPC] Use mtocrf instruction in asm when CONFIG_POWER4_ONLY=y
    
    mtocrf is a faster single-field mtcrf (move to condition register
    fields) instruction available in POWER4 and later processors.  It can
    make quite a difference in performance on some implementations, so use
    it for CONFIG_POWER4_ONLY builds.
    
    Signed-off-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 569975591c5530fdc9c7a3c45122e5e46f075a74
Author: Jake Moilanen <moilanen@austin.ibm.com>
Date:   Thu Mar 29 08:44:02 2007 -0500

    [POWERPC] DMA 4GB boundary protection
    
    There are many adapters which cannot handle DMAing across any 4 GB
    boundary.  For instance, the latest Emulex adapters.
    
    This normally is not an issue as firmware gives dma-windows under
    4gigs.  However, some of the new System-P boxes have dma-windows above
    4gigs, and this present a problem.
    
    During initialization of the IOMMU tables, the last entry at each 4GB
    boundary is marked as used.  Thus no mappings can cross the boundary.
    If a table ends at a 4GB boundary, the entry is not marked as used.
    
    A boot option to remove this 4GB protection is given w/ protect4gb=off.
    This exposes the potential issue for driver and hardware development
    purposes.
    
    Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1f9209cfe06be715b82075e79c9aab3c5b714010
Author: Sylvain Munaut <tnt@246tNt.com>
Date:   Mon Feb 12 23:13:27 2007 +0100

    [POWERPC] Add uevent handler for of_platform_bus
    
    Adding this handler allow userspace to properly handle the module
    autoloading. The generation of the uevent itself is now common to
    all bus using of_device, so not much code here.
    
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cc11645b9d04c3df5180620bded522e14e619604
Author: Sylvain Munaut <tnt@246tNt.com>
Date:   Mon Feb 12 23:13:26 2007 +0100

    [POWERPC] powermac: Use the new of_device common uevent handler
    
    The generation of the uevent is now common to all bus using
    of_device.
    
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit eb0cb8a07e320ed3237789cc4f29858338d14d8e
Author: Sylvain Munaut <tnt@246tNt.com>
Date:   Mon Feb 12 23:13:25 2007 +0100

    [POWERPC] Add a unified uevent handler for bus based on of_device
    
    This common uevent handler allow the several bus types based on
    of_device to generate the uevent properly and avoiding
    code duplication.
    
    This handlers take a struct device as argument and can therefore
    be used as the uevent call directly if no special treatment is
    needed for the bus.
    
    Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1b118799cceab69d80c162bc661c77fdc33dd756
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:36:34 2007 -0400

    Input: lifebook - activate 6-byte protocol on select models
    
    It appears that if we turn on 6-byte Lifebook protocol on
    Panasonic CF-28 its touchpad is left alone and generates
    standard 3-byte PS/2 data stream with relative packets
    instead of being converted in 3-byte Lifebook protocol with
    absolute coordinates - in other words what get what we need
    to distinguish between touchscreen and touchpad.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit e7afcd1bf784dde4cd6c6efbf9a4709626cc8e08
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:36:25 2007 -0400

    Input: lifebook - work properly on Panasonic CF-18
    
    Panasonic CF18 has an active multiplexing controller with
    touchscreen connected to one port and a touchpad to another.
    Use "phys" from serio port to activate lifebook protoocol
    only on the port that has touchscreen connected to it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit d0a0515fc30b55d4b09395d44762c5f41d6d02d5
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:36:12 2007 -0400

    Input: cobalt buttons - separate device and driver registration
    
    Create platform device for cobalt buttons as part of arch setup.
    This makes the driver follow current driver model more closely.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Acked-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>

commit 0de9550971a0ee614ea4f06655e8a49aa3a942a8
Author: Karl Pickett <karl.pickett@gmail.com>
Date:   Thu Apr 12 01:35:59 2007 -0400

    Input: ati_remote - make button repeat sensitivity configurable
    
    ati_remote causes repeats after only .23 seconds with my remote and
    makes it hard to use comfortably. Make a precise way of setting the
    repeat delay time in milliseconds and default it to 500ms.  The old
    behavior can be had by setting repeat_delay = 0.
    
    Signed-off-by: Karl Pickett <karl.pickett@gmail.com>
    Signed-off-by: Vincent Vanackere <vincent.vanackere@gmail.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit b7fd4a0aa52c95309219240bf9c5fd210a6e7061
Author: Thomas Gleixner <tglx@linutronix.de>
Date:   Thu Apr 12 01:35:51 2007 -0400

    Input: pxa27x - do not use deprecated SA_INTERRUPT flag
    
    IRQF_DISABLED is the proper name.
    
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit b5b16c5296c3276bb409a948173d557241b74379
Author: Cliff Brake <cbrake@bec-systems.com>
Date:   Thu Apr 12 01:35:43 2007 -0400

    Input: ucb1400 - make delays configurable
    
    This patch adds module parameters for several timing values used
    in the driver. These values can vary based on the hardware design
    and how much capacitive filtering there is on the touch panel inputs,
    and the resistance of the panel.
    
    Signed-off-by: Cliff Brake <cbrake@bec-systems.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 293e6392d72dfaef1f6aef605769869512bec45d
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:35:32 2007 -0400

    Input: misc devices - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 935e658e89678a7e3427b90cd7a1c86025d95bfe
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:35:26 2007 -0400

    Input: joysticks - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit a5394fb075a80212765ee3cd4a7842bdccf5fc0a
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:35:14 2007 -0400

    Input: touchscreens - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 28aa7f1c8178db8b277a6e11325ef09adea8ac46
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:35:09 2007 -0400

    Input: mice - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit c0f82d570c84f2592367e350a92ebd71e72ba68a
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:35:03 2007 -0400

    Input: USB devices - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 469ba4dff954389f58cebb3df645e24433dcd565
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:58 2007 -0400

    Input: keyboards - switch to using input_dev->dev.parent
    
    In preparation for struct class_device -> struct device input
    core conversion, switch to using input_dev->dev.parent when
    specifying device position in sysfs tree.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 88a447a030bfec9f1e8666daf27d9d73c8c92448
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:47 2007 -0400

    Input: prepare to switching to struct device
    
    In preparation to switching to struct device and class device
    going away provide an alias to allow drivers that create devices
    to use either input_dev->cdev.dev or input_dev->dev.parent to
    put them into sysfs tree. The former will go away once conversion
    to struct device is complete.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 7791bdae71243050132ede7ea1558c828b69458f
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:39 2007 -0400

    Input: drivers/usb/input - don't access dev->private directly
    
    Use input_get_drvdata() and input_set_drvdata() instead.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 373f9713dccc8fc8e076157001a60133455c0550
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:33 2007 -0400

    Input: drivers/input/misc - don't access dev->private directly
    
    Use input_get_drvdata() and input_set_drvdata() instead.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit b356872fa48a3f6b6f187444b0ea55e6e21c3575
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:20 2007 -0400

    Input: drivers/input/keyboard - don't access dev->private directly
    
    Use input_get_drvdata() and input_set_drvdata() instead.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 8715c1cfadf8cce24e79d254f95bd4a84c7741f0
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:14 2007 -0400

    Input: drivers/input/joystick - don't access dev->private directly
    
    Use input_get_drvdata() and input_set_drvdata() instead.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 40b9b0b82e664bfdf26fd33014d52e23ff80b9f4
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:08 2007 -0400

    Input: drivers/input/touchscreen - don't access dev->private directly
    
    Use input_get_drvdata() and input_set_drvdata() instead.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 0ca1804f2e4d78e6a037da23f96aa56f762e78fb
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:34:02 2007 -0400

    Input: drivers/input/mice - don't access dev->private directly
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 3abccf36081ac827cf5d14db6837117f088937eb
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:33:51 2007 -0400

    Input: add input_{get|set}_drvdata() helpers
    
    Add helpers to set up and access driver-specific data in input
    device structure. Once conversion to struct driver is complete
    we will drop input_dev->private and will use dev_get_drvdata()
    and dev_set_drvdata().
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 5014186de89708d0e9eed60526b698d5b786b707
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:33:39 2007 -0400

    Input: USB devices - handle errors when registering input devices
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit db61a9124880a1d79b7b320d4b6bef717f23e485
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:33:28 2007 -0400

    Input: remove old USB touchscreen drivers
    
    itmtoch, mtouchusb and touchkitusb have been replaced with
    composite usbtouchscreen driver and can be removed now.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 21298f7153f71c7fa70247518851f7aac41c4781
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:33:19 2007 -0400

    Input: logips2pp - add model 1 information
    
    It turns out I had an old 2-button Logitech mouse that responds
    to Logitech's queries with model of 1.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit a1421d3c780c373d5f74a0ab99b0652041d61876
Author: Peter Stokes <linux@dadeos.freeserve.co.uk>
Date:   Thu Apr 12 01:33:10 2007 -0400

    Input: add logical channel support for ATI Remote Wonder II
    
    The ATI Remote Wonder II can be configured with one of 16 unique logical
    channels. Allowing up to 16 remotes to be used independently within
    range of each other. This change adds functionality to configure the
    receiver and filter the input data to respond or exclude remotes
    configured with different logical channels.
    
    Signed-off-by: Peter Stokes <linux@dadeos.freeserve.co.uk>
    Acked-by: Ville Syrjala <syrjala@sci.fi>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 1b726a02d97cef2471521ae6947416f7374c6590
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:33:00 2007 -0400

    Input: gtco - handle errors from input_register_device()
    
    Also fix URB leak in gtco_probe error path, formatting fixes.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 55d29c98418df737e87dbdfc36c78d3ed99a6698
Author: Eric Piel <eric.piel@tremplin-utc.net>
Date:   Thu Apr 12 01:32:49 2007 -0400

    Input: wistron - declare keymaps as initdata
    
    As the number of keymaps increases and is very unlikely to
    reduce, this patch helps to reduce memory consumption by
    declaring all keymaps as __initdata and copying right keymap
    during DMI detection. On x86 this make the module size at
    runtime going from 10616 to 9428: a bit more than 1kb saved.
    
    Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 7b0a4cd7601774d1312f477a879f86b0968880fd
Author: Eric Piel <eric.piel@tremplin-utc.net>
Date:   Thu Apr 12 01:32:41 2007 -0400

    Input: wistron - introduce generic keymap
    
    It turns out that the keymaps in the wistron driver are almost the
    same, the main difference being some keys which may not exist and
    leds which might not be present. Therefore it's possible to write
    a generic keymap which would allow the use of an unknown keyboard
    with little drawbacks. The user can select it specifying the parameter
    "keymap=generic".
    
    Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 6480e2a275ff8ff48ae23a011616fcf819ed7a4e
Author: Eric Piel <eric.piel@tremplin-utc.net>
Date:   Thu Apr 12 01:32:34 2007 -0400

    Input: wistron - add acerhk laptop database
    
    Acerhk supports already a lot of laptops. Lets import its database so
    that everyone can benefit of the work of Olaf Tauber. Only the "tm_new"
    laptops were imported. "tm_old" laptops could be possible but requires
    more testing and probably only few laptops are still alive. "dritek"
    laptops should probably be imported into a different driver. Also compress
    the keymaps by fitting each entry on an int. Most of the dmi matching was
    written based on google searches, so it's rather prone to errors. That's
    why I'm asking people to confirm it works.
    
    Support to generate switch input events was added as some laptops indicate
    lid open/close through this interface.
    
    This adds the following hardware:
    Acer TravelMate 370
    Acer TravelMate 380
    Acer TravelMate C300
    Acer TravelMate C100
    Acer TravelMate C110
    Acer TravelMate 250
    Acer TravelMate 350
    Acer TravelMate 620
    Acer TravelMate 630
    Acer TravelMate 220
    Acer TravelMate 230
    Acer TravelMate 260
    Acer TravelMate 280
    Acer TravelMate 360
    Acer TravelMate 2100
    Acer TravelMate 2410
    Acer Aspire 1500
    Acer Aspire 1600
    Acer Aspire 3020
    Acer Aspire 5020
    Medion MD 2900
    Medion MD 40100
    Medion MD 95400
    Medion MD 96500
    Fujitsu Siemens Amilo 7820
    
    Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 688897b0d4910e097f34c0e263d649cf2036eb45
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:32:22 2007 -0400

    Input: logips2pp - ignore mice reporting model as 0
    
    There are mice reporting to logitech's queries with model
    of 0. Do not claim that these are Logitech mice.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 8d04ddb64c7bf62aec1102fddc5336a68bcaebe9
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:32:09 2007 -0400

    Input: i8042 - disable interfaces when switching to legacy mode
    
    Disable both keyboard and auxiliary interfaces before switching
    to legacy mode to prevent atkbd from getting "empty" interrupts.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 0d9d93c411c9351ba186f5ec910b10da7c1d9d14
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:31:55 2007 -0400

    Input: mousedev - fix sudden warps with touchpads
    
    Pete Zaitcev reports that with his touchpad, if he lifts the finger
    and places it elsewhere, the pointer sometimes warps dramatically.
    This happens because we don't store coordinates unless we detect a
    touch so sometimes we have stale coordinates in queue (from where
    the finger left the pad) and averaging makes cursor to jump across
    the screen. The solution is to always store the latest coordinates.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit f42649e84831efc69d5f621f1c36a39b4e384a99
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:31:13 2007 -0400

    Input: ALPS - handle errors from input_register_device()
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit f3901d9e3bf2b57604358eea62f3414000772e2a
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Apr 12 01:31:05 2007 -0400

    Input: remove no longer used power.c handler
    
    Delete the never-compiled source file drivers/input/power.c, and
    remove its entry from the corresponding Makefile, as there is no
    Kconfig file that refers to the config option INPUT_POWER
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 9e35d20663344b38339ffb6127ba08285f3397a9
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:30:52 2007 -0400

    Input: keyboard handler - use printk_ratelimit()
    
    Use printk_ratelimit() to protect ourselves from buggy drivers or
    devices endlessly generating invalid events.
    
    Suggested by Andrew Morton.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 887cc127233f34e833d074380f433a04de207563
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:30:41 2007 -0400

    Input: synaptics - export model bits
    
    Encode synaptics model in psmouse->model so it will be
    exported via sysfs as input_dev->id.version and become
    visible for applications.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 598972d4fb39c8a0826b396e45dc2a8c1dbe4f11
Author: Johann Deneux <johann.deneux@gmail.com>
Date:   Thu Apr 12 01:30:24 2007 -0400

    Input: iforce - use usb_kill_urb instead of usb_unlink_urb
    
    Using usb_unlink_urb can cause iforce_open to fail when called
    soon after iforce_release. Also updated my email address and
    replaced calls to printk() by dbg(), warn(), info(), err()...
    
    Signed-off-by: Johann Deneux <johann.deneux@gmail.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit d542ed82fdc72cf63549deec19e86ee4addf2499
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:30:15 2007 -0400

    Input: handlers - handle errors from input_open_device()
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit d0ffb9be866519775da19c0a6790f5431c1a8dc6
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:30:00 2007 -0400

    Input: handlers - rename 'list' to 'client'
    
    The naming convention in input handlers was very confusing -
    client stuctures were called lists, regular lists were also
    called lists making anyone looking at the code go mad.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 5b2a08262a8c952fef008154933953f083ca5766
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Thu Apr 12 01:29:46 2007 -0400

    Input: rework handle creation code
    
     - consolidate code for binding handlers to a device
     - return error codes from handlers connect() methods back to input
       core and log failures
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 46386b587086c8d2698222a031bf749688464032
Author: Simon Budig <simon@budig.de>
Date:   Mon Mar 12 13:52:04 2007 +0100

    HID: introduce proper zeroing of unused bits in output reports
    
    Some HID devices are looking on the unused bits in the HID reports they
    receive. This is violating the specification, but we want to make those
    devices work. Well-behaving devices are unaffected, as they don't care
    about the unused bits.
    
    If bitsused % 8 is 0 all bits in data[] get used and we don't need to
    clear anything. Otherwise (bitsused % 8) bits of the last byte get used.
    By shifting 1 for (bitsused % 8) bits and subtracting 1 we create a mask
    consisting of (bitsused % 8) ones and remaining zeroes. By ANDing we
    clear the upper unused bits.
    
    Signed-off-by: Simon Budig <simon@budig.de>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 42cfb632f0210caa7d979666058075b06fc4680c
Author: Sam Liddicott <sam@liddicott.com>
Date:   Tue Apr 10 15:50:45 2007 +0200

    USB HID: add support for WiseGroup MP-8800 Quad Joypad
    
    This adds support for WiseGroup Quad Joypad (0x0925/0x8800). The
    same quirks as for Dual Joypad (0x0925/0x8866) are needed.
    
    Signed-off-by: Sam Liddicott <sam@liddicott.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 320c01500c6ecb189c577b921a2357c7a56aaebc
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Tue Apr 10 16:08:34 2007 +0200

    USB HID: add FF support for Logitech Force 3D Pro Joystick
    
    This patch adds support for Logitech Force 3D Pro Joystick (0x046d/0xc286)
    to hid-lgff driver.
    
    Device ID reported by Richard Bolkey <rbolkey@cs.utexas.edu>
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 713c8aad6b7202671ce1ac6109f6b48d8223e938
Author: Pete Zaitcev <zaitcev@redhat.com>
Date:   Fri Apr 6 14:33:18 2007 +0200

    USB HID: numlock quirk for dell W7658 keyboard
    
    On Dell W7658 keyboard, when BIOS sets NumLock LED on, it survives the
    takeover by kernel and thus confuses users.
    
    Eating of an increasibly scarce quirk bit is unfortunate. We do it for safety,
    given the history of nervous input devices which crash if anything unusual
    happens.
    
    Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 85cbea3952135ecad4b47cb6cc57e25279129e2d
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Thu Apr 5 12:23:09 2007 +0200

    USB HID: Logitech MX3000 keyboard needs report descriptor quirk
    
    Logitech MX3000 contains report descriptor which doesn't cover usages
    above 0x28c, but emits such usages. Report descriptor needs fixing
    in the very same way as with receivers shipped with S510 keyboards.
    
    This patch also adds a few mappings for multimedia keys that S510 didn't
    emit.
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit bf892e60d0b32989bc55ef64cd6557a49806f0cf
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Wed Apr 4 10:56:12 2007 +0200

    USB HID: extend quirk for Logitech S510 keyboard
    
    Logitech S510 keyboard is shipped with USB receivers with various product
    ids, all need their report descriptor to be fixed. This adds PID 0xc50c.
    
    Reported by Christophe Colombier in kernel.org bugzilla #7352
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 5d6341c606b9eb62fbaa7b2a0da82ac851bf0fc4
Author: Dmitry Torokhov <dtor@mail.ru>
Date:   Wed Apr 4 10:40:57 2007 +0200

    USB HID: usbkbd/usbmouse - handle errors when registering devices
    
    Handle errors when registering input devices in usbkbd/usbmouse.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 66df514b1dbf51a0a02a8abe1219e46e49710aea
Author: Daniel P. Engel <dengel@sourceharvest.com>
Date:   Tue Apr 3 23:43:46 2007 +0200

    USB HID: add QUIRK_HIDDEV for Belkin Flip KVM
    
    Add HID_QUIRK_HIDDEV for the Belkin Flip USB KVM, which provides for software
    control of switching via a HID class interface. It overloads three HID LED
    usages, two of which aren't mapped in the ev_dev input subsection, and which it
    doesn't make sense to map. In order to force the creation of a hiddev device
    for controlling the Flip, this quirk flag is needed.
    
    Signed-off-by: Daniel P. Engel <dengel@sourceharvest.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit daa0bc902c8e9476673b47d3b59c9bb922843563
Author: Chris Clayton <chris2553@googlemail.com>
Date:   Sun Apr 1 23:07:55 2007 +0200

    HID: enable dead keys on a belkin wireless keyboard
    
    Belkin Wireless keyboard, model number F8E849KYBD, USB ID 1020:0006,
    FCCID: K7SF8E849KYBD emits usages 0x03a-0x03c from Consumer usage page.
    As of HUT v1.12, these are marked as reserved. If any conflict arises
    later, the mapping could be made conditional on VID/PID.
    
    Signed-off-by: Chris Clayton <chris2553@gmail.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 38d4b89e274c7eed99fcf6c3f8686f70edd6ab7c
Author: Ronny Peine <RonnyPeine@gmx.de>
Date:   Tue Mar 27 14:37:44 2007 +0200

    USB HID: Thustmaster firestorm dual power v1 support
    
    This patch adds support for version 1 of Thustmaster firestorm dual power
    (0x44f/0xb300).
    
    Signed-off-by: Ronny Peine <RonnyPeine@gmx.de>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 4cbe7d28f2c63e801d651b3b56f953a5ff5ae70f
Author: Paul Walmsley <paul@booyaka.com>
Date:   Tue Mar 20 19:23:16 2007 +0100

    USB HID: specify explicit size for hid_blacklist.quirks
    
    Explicitly specify the size of the hid_blacklist quirks member, to guard
    against surprises on architectures where unsigned ints aren't 32 bits long.
    
    Signed-off-by: Paul Walmsley <paul@booyaka.com>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 5e2a55f25d255a356bdaf2cb04c71b8d76c307a8
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Tue Mar 20 19:03:31 2007 +0100

    USB HID: fix retry & reset logic
    
    The USB HID driver fails to reset its error-retry timeout when there
    has been a long time interval between I/O errors with no successful URB
    completions in the meantime.  As a result, the very next error would
    trigger an immediate reset, even if it was a chance event occurring
    long after the previous error.
    
    More USB keyboards and mice than one might expect end up getting I/O
    errors. Almost always this results from hardware problems of one sort of
    another. For example, people attach the device to a USB extension cable,
    which degrades the signal.  Or they simply have poor quality cables to
    begin with. Or they use a KVM switch which doesn't handle USB messages
    correctly. Etc...
    
    There have been reports from several users in which these I/O
    errors would occur more or less randomly, at intervals ranging from
    seconds to minutes.  The error-handling code in hid-core.c was originally
    meant for situations where a single outage would persist for a few hundred
    ms (electromagnetic interference, for example).  It didn't work right when
    these more sporadic errors occurred, because of a flaw in the logic
    which this patch fixes.
    
    This patch (as873) fixes that oversight.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 48b4554aca28f721d3dfbab077c05032b3d1cd31
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Tue Apr 3 23:39:37 2007 +0200

    USB HID: consolidate vendor/product ids
    
    The vendor/product IDs for the purposes of hid_blacklist got
    scathered around the hid-core.c in a rather random way over the
    time.
    
    Move all the related definitions at the beginning of the file,
    and make them sorted again. Sort also hid_blacklist properly.
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>

commit 6db3dfefa28739e7c9c60809c3a5aef7cc088b97
Author: Jiri Kosina <jkosina@suse.cz>
Date:   Thu Mar 8 16:47:49 2007 +0100

    USB HID: move usbhid code from drivers/usb/input to drivers/hid/usbhid
    
    Separate usbhid code into dedicated drivers/hid/usbhid directory as
    discussed previously with Greg, so that it eases maintaineance process.
    
    Signed-off-by: Jiri Kosina <jkosina@suse.cz>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

commit 7b153f366867a3b70daeaf3c6074e4a0594057a7
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 19:31:25 2007 +0200

    sony-laptop: sonypi backward compatibility code
    
    Compatibility code to allow old sonypi bound userspace apps to still work.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 3d2b8a9f2c26bc0fe03b3545d07245798b1b81b9
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 19:31:16 2007 +0200

    sony-laptop: update documentation and Kconfig help
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit f6119b027578c21b544a98fd67e5f0b7e4fbea7d
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 19:31:06 2007 +0200

    sony-laptop: sanitize printks
    
    Unify printks to resemble a unique driver.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 49a11deade3c1d9e2d7c88d25899b3a9174d048e
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 19:28:56 2007 +0200

    sony-laptop: additional platform attributes coming from SNY6001
    
    Register additional platform attributes coming from the SPIC (sonypi) driver.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1549ee6fb122400c0767b5f3da2c42abbc4f750a
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 10:19:08 2007 +0200

    sony-laptop: Unify the input subsystem event forwarding
    
    SNC and SPIC events are forwarded to the same input devices
    and are thus handled together.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 33a04454527edd33d4a6332a2944d2b4f46fbb18
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 19:26:03 2007 +0200

    sony-laptop: Add SNY6001 device handling (sonypi reimplementation)
    
    Reimplement sonypi using ACPI only functions.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b9a218b738c5c2387f666731b81a4376021d681e
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 10:19:06 2007 +0200

    sony-laptop: Add debug macros also used by the sonypi reimplementation
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 56b8756b3bc8812837a21f3e066dba1b489e071e
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 10:19:05 2007 +0200

    sony-laptop: Prepare the platform driver for multiple users.
    
    Both the SNC and SPIC device drivers will create attributes and thus
    there's the need to have an internal usage count to avoid
    re-registering or de-registering at the wrong time.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 59b19106f3f20487093ea06c8220426147cf7835
Author: malattia@linux.it <malattia@linux.it>
Date:   Mon Apr 9 10:19:04 2007 +0200

    sony-laptop: Remove ACPI references from variable and function names.
    
    Signed-off-by: Mattia Dongili <malattia@linux.it>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 5268df2ead6def933ace27ab4d46f67d2989b905
Author: Steve French <sfrench@us.ibm.com>
Date:   Fri Apr 6 19:28:16 2007 +0000

    [CIFS] Add write perm for usr to file on windows should remove r/o dos attr
    
    Remove read only dos attribute on chmod when adding any write permission (ie on any of
    user/group/other (not all of user/group/other ie  0222) when
    mounted to windows.
    
    Suggested by: Urs Fleisch
    
    Signed-off-by: Urs Fleisch <urs.fleisch@gmail.com>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 3a9f462f6d07ab6f26a347120e173e945139befd
Author: Steve French <sfrench@us.ibm.com>
Date:   Wed Apr 4 17:10:24 2007 +0000

    [CIFS] Remove unnecessary parm to cifs_reopen_file
    
    Also expand debug entry to show which character on a failed Unicode
    mapping.
    
    Acked-by: Shaggy <shaggy@us.ibm.com>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit aaf737adb6937339494d5a7111f0433cd9676db8
Author: Igor Mammedov <qwerty0987654321@mail.ru>
Date:   Tue Apr 3 19:16:43 2007 +0000

    [CIFS] Switch cifsd to kthread_run from kernel_thread
    
    cifsd was the only cifs thread that had not been switched to the newer
    kthread interface
    
    Signed-off-by: Igor Mammedov <niallain at gmail.com>
    Signed-off-by: Wilhelm Meier <wilhelm.meier@fh-kl.de>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit c33f8d32746db12ba353b0a05b25f7893a0ac344
Author: Christoph Hellwig <hch@lst.de>
Date:   Mon Apr 2 18:47:20 2007 +0000

    [CIFS] Remove unnecessary checks
    
    file->f_path.dentry or file->f_path.dentry.d_inode can't be NULL since at
    least ten years, similar for all but very few arguments passed in from the
    VFS.
    
    Signed-off-by: Christoph Hellwig <hch@lst.de>
    Signed-off-by: Steve French <sfrench@us.ibm.com>

commit 0ecbc81adfcb9f15f86b05ff576b342ce81bbef8
Author: Rodolfo Giometti <giometti@enneenne.com>
Date:   Mon Mar 26 21:45:43 2007 -0800

    [MTD] [NOR] Support for auto locking flash on power up
    
    Auto unlock sectors on resume for auto locking flash on power up.
    
    Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 8dc64fca75b631142f282047d7f6ae9e8af82543
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Mar 26 21:45:41 2007 -0800

    [JFFS2] Delete everything related to obsolete JFFS2_PROC option
    
    Delete everything related to the apparently non-existent kernel config
    option JFFS2_PROC.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 68aa0fa87f6d4b2f5e8ad39ecaec8bba9137bb3d
Author: Marc St-Jean <stjeanma@pmc-sierra.com>
Date:   Mon Mar 26 21:45:41 2007 -0800

    [MTD] PMC MSP71xx flash/rootfs mappings
    
    Add flash and rootfs mappings for the PMC-Sierra MSP71xx devices.
    
    This patch references some platform support files previously submitted to
    the linux-mips@linux-mips.org list.
    
    Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 18a6598f2d3bb7275dadba77df5f06bc996a77d4
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Fri Mar 30 10:30:48 2007 -0400

    [SCSI] aacraid: [Fastboot] Panics for AACRAID driver during 'insmod' for kexec test.
    
    Attached is the patch I feel will address this issue. As an added
    'perk' I have also added the code to detect if the controller was
    previously initialized for interrupted operations by ANY operating
    system should the reset_devices kernel parameter not be set and we are
    dealing with a naÃ¯ve kexec without the addition of this kernel
    parameter. The reset handler is also improved. Related to reset
    operations, but not pertinent specifically to this issue, I have also
    altered the handling somewhat so that we reset the adapter if we feel
    it is taking too long (three minutes) to start up.
    
    We have not unit tested the reset_devices flag propagation to this
    driver code, nor have we unit tested the check for the interrupted
    operations under the conditions of a naively issued kexec. We are
    submitting this modified driver to our Q/A department for integration
    testing in our current programs. I would appreciate an ACK to this
    patch should it resolve the issue described in this thread...
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit aa2e07b4c2addaa4ad4bd7a6ee205565e83c2a14
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:57 2007 -0500

    [SCSI] ipr: Driver version to 2.3.2
    
    Bump driver version.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 51b1c7e19e18e84a44277951dd5c4c4617330baa
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:50 2007 -0500

    [SCSI] ipr: Faster sg list fetch
    
    Improve overall command performance by embedding the scatterlist
    in the command block used by the adapter. This decreases
    the overall number of DMAs required for a single command.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 0feeed823af05ca556087a89fdcf644f156f73b8
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:43 2007 -0500

    [SCSI] ipr: Return better qc_issue errors
    
    If qc_issue fails for some reason, return a better error
    to libata.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e435340c4b583b4472dad1178029b8e3e7dafd0b
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:37 2007 -0500

    [SCSI] ipr: Disrupt device error
    
    Add entry in ipr error translation table for an error
    received when a device is forced into the failed state
    by the user.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 933916f365f9ef1268c058bfaba2d4dcf26e4fd0
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:30 2007 -0500

    [SCSI] ipr: Improve async error logging level control
    
    Add the ability to control how much error data gets logged
    on a per error basis.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a9aedb098437655b7b78d66e0e28405830cbdbef
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:23 2007 -0500

    [SCSI] ipr: PCI unblock config access fix
    
    Fix to make sure user config accesses get re-enabled if the
    PCI config write to start BIST fails.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 24d6f2b50bd34d0da540a9e6f71c4b6ab25f4b93
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:17 2007 -0500

    [SCSI] ipr: Fix for oops following SATA request sense
    
    This patch fixes a problem discovered on a system with some
    bad SATA devices attached. If a command to a SATAPI device
    times out and the device gets reset as part of error recovery,
    its possible that ipr will set err_mask to indicate a device
    error has occurred. If this happens, a request sense will get
    issued by libata. Since scsi core thinks this scsi command is
    now completed, because the device reset handler completed successfully,
    scsi core will free the associated scsi command, which may
    cause an oops when that request sense is completed later
    by ipr. This patch ensures that any commands that get aborted
    as a result of a device reset set err_mask appropriately so
    that the request sense does not get sent.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit b0692dd4d7e90ce5cf1241731c6e80118402e3b4
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:09 2007 -0500

    [SCSI] ipr: Log error for SAS dual path switch
    
    For ipr SAS adapters that support dual pathing, this
    patch modifies ipr to log an error when a path fails.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit cc9bd5d4256ecc1b6e0448febb4be29db1a91256
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:43:01 2007 -0500

    [SCSI] ipr: Enable logging of debug error data for all devices
    
    The ipr driver has a sysfs attribute which can be used to
    adjust the logging level of the driver for error events.
    The error response data for commands can be dumped by
    increasing the logging level of the ipr driver. This
    currently only works for JBOD passthrough devices.
    This patch enables this function for all devices, including
    RAID devices, to aid in debugging problems.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 185eb31cc242f415800a1a06dca522d27c269279
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:42:53 2007 -0500

    [SCSI] ipr: Add new PCI-E IDs to device table
    
    Adds support for some new PCI-E ipr adapters.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 7d2267bb9d94aabfa316a13d04b0bce2fb51ff83
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:42:47 2007 -0500

    [SCSI] ipr: Remove auto RAID create module parameter
    
    Remove the auto RAID 0 array creation module parameter, since
    support for this function has been removed from the firmware.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 5469cb5bdef76dbe18865fff30975f0694fff2c2
Author: Brian King <brking@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:42:40 2007 -0500

    [SCSI] ipr: Make adapter operational timeout be per adapter type
    
    Some ipr adapters may take longer than others to come operational.
    This patch makes this timeout different for different adapters,
    while still preserving the module parameter which can be used
    to globally override the default.
    
    Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 0979c84b4affaf924a894380dd0069638b64de03
Author: Robert Jennings <rcj@linux.vnet.ibm.com>
Date:   Thu Mar 29 12:30:40 2007 -0500

    [SCSI] ibmvscsi: add slave_configure to allow device restart
    
    Fixed the kernel-doc comment for ibmvscsi_slave_configure.  Thanks to
    Randy Dunlap for pointing this out.
    
    Adding a slave_configure function for the driver. Now the disks can be
    restarted by the scsi mid-layer when the are disconnected and reconnected.
    
    Signed-off-by: "Robert Jennings" <rcj@linux.vnet.ibm.com>
    Signed-off-by: "Santiago Leon" <santil@us.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a897ff2a6386ac4368ba41db18b626afd903f9d8
Author: Robert Jennings <rcjenn@us.ibm.com>
Date:   Wed Mar 28 12:45:46 2007 -0500

    [SCSI] ibmvscsi: allow for dynamic adjustment of server request_limit
    
    The request limit calculations used previously on the client failed to
    mirror the state of the server.  Additionally, when a value < 3 was provided
    there could be problems setting can_queue and handling abort and reset
    commands.
    
    Signed-off-by: "Robert Jennings" <rcj@linux.vnet.ibm.com>
    Signed-off-by: Santiago Leon <santil@us.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a45c863f02c808107172b4b2975e1130c7da66d6
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Wed Mar 28 13:44:54 2007 -0400

    [SCSI] aacraid: fix print of Firmware Build Date and add TSID
    
    The Adapter build date that is to be printed on instantiation was not
    displayed as a result of the supplemental adapter information structure
    not being in sync with the Firmware; the driver took an early test cycle
    version that had a miss-sized padded region at the head and the
    structure was not re-checked at the end of qualification. The Build Date
    was not a priority and is merely a cosmetic enhancement, and the wrong
    location for the start of the structure member would not induce any
    side-effect problems. We updated the structure to match the actual
    format, and added the TSID (Tech Support Identification) value print,
    should it be present, to the adapter instantiation announcements during
    driver load.
    
    This later enhancement should improve the relationship between Service
    folk & Tech Support if the printed value of the TSID found it's way into
    the circular file labeled G...
    
    Neither of these values show in sysfs (yet).
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 74ee9d52cf8b524edf8ae6222c8bfcc6df6f5954
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Wed Mar 28 09:22:39 2007 -0400

    [SCSI] aacraid: remove unused or deprecated firmware constants
    
    Just sweeping the floor clean in one spot. Some of these constants have
    never been used in the driver or in the firmware (and thus are
    meaningless). Triggered this patch because I discovered one of the
    unused constants was actually incorrect and figured it was better to
    clean them out than correct and update. There are no side effects at all
    regarding this patch, it is purely cosmetic.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 9e3738f3c83f534d82f1d7d5191dcecb2425f7f9
Author: Christof Schmitt <christof.schmitt@de.ibm.com>
Date:   Wed Mar 28 14:20:40 2007 +0200

    [SCSI] zfcp: fix initialization of FSF timer
    
    Correctly initialize the timer for FSF requests with jiffies + timeout.
    
    Cc: Swen Schillig <swen@vnet.ibm.com>
    Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 665db93b8a5fc6a11e2ace6b20569420a353d037
Author: Bernhard Walle <bwalle@suse.de>
Date:   Wed Mar 28 00:49:49 2007 +0200

    [SCSI] qla2xxx: Remove duplicate pci_disable_device() call
    
    On the path qla2x00_probe_one() -> probe_failed -> qla2x00_free_device(),
    pci_disable_device() is executed twice, once in qla2x00_free_device()
    and once in qla2x00_probe_one().
    
    This patch removes the unnecessary call.
    
    Signed-off-by: Bernhard Walle <bwalle@suse.de>
    Acked-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 4dfb7cbef856689caebd0f498dbd140d1b79954f
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Tue Mar 27 15:07:28 2007 -0400

    [SCSI] aacraid: resolve compiler warnings using ptrdiff_t
    
    Unsigned long is not always the same size as a pointer, namely on 32 bit
    systems with 64 bit address space. Ptrdiff_t is the same size as a
    pointer in all configurations. By using ptrdiff_t we can mitigate the
    warning messages on these configurations. There should be no side
    effects of this patch.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 10c9a017f1bd84a7aedaea7029cd5224863197db
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Tue Mar 27 11:51:34 2007 -0400

    [SCSI] aacraid: Add SMC and SUN products to README
    
    Add SMC and SUN products to aacraid documentation
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e3e0ca5143d7a78522df30b75bd1acfcf80c2a38
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 26 21:59:29 2007 -0800

    [SCSI] aic7xxx: make functions static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Hannes Reinecke <hare@suse.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 9695a25dbff788f26225966c43425e8bae7f06e8
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 26 21:59:35 2007 -0800

    [SCSI] aacraid: cleanups
    
    - proper prototypes for global code in aacraid.h
    - aac_rx_start_adapter() can now become static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Acked-by: "Salyzyn, Mark" <mark_salyzyn@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 3cfff0fc74bf5ac8213b5a2be583bf675ccd9511
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 26 21:59:25 2007 -0800

    [SCSI] dpt_i2o: remove dead code
    
    The Coverity checker spotted this dead code introduced by
    commit a07f353701acae77e023f6270e8af353b37af7c4.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Acked-by: "Salyzyn, Mark" <mark_salyzyn@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 301b01aa621305e8d59a2eb948b4ad7bf26be86e
Author: Adrian Bunk <bunk@stusta.de>
Date:   Mon Mar 26 21:59:46 2007 -0800

    [SCSI] fusion: make mptspi_target_destroy() static
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Acked-by: Eric Moore <Eric.Moore@lsi.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit b73c3d778647bffff6dbcbe41e8fc01215a22194
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Mar 26 21:59:33 2007 -0800

    [SCSI] Remove some unused SCSI-related kernel config variables.
    
    Remove the unused SCSI-related kernel config variables
    
    	SCSI_NCR53C8XX_PROFILE_SUPPORT
    	SCSI_NCR53C8XX_PROFILE
    	53C700_IO_MAPPED
    	AIC79XX_ENABLE_RD_STRM
    	AIC7XXX_PROBE_EISA_VL
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 0d06b281a1001ed40cace820d99eeb7d4453adb7
Author: Henne <henne@nachtwindheim.de>
Date:   Mon Mar 26 21:59:28 2007 -0800

    [SCSI] dpt: whitespace cleanup
    
    Remove some trailing whitespaces and some replace whitespaces with tabs.
    
    Signed-off-by: Henrik Kretzschmar <henne@nachtwindheim.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Acked-by: "Salyzyn, Mark" <mark_salyzyn@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 023ae6199938fc79a51d2616903b44b07fe338b6
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Mon Mar 26 16:06:45 2007 -0400

    [SCSI] pcmcia: allow drivers to be built non-modular
    
    Remove the Kconfig requirement that the PCMCIA SCSI drivers be built
    only as modules, and allow them to be built into the kernel.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Acked-by: Dominik Brodowski <linux@dominikbrodowski.net>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 912d4e8851389eee5c289ce0a7953e9067198232
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Mon Mar 26 09:21:14 2007 -0400

    [SCSI] aacraid: Add likely() and unlikely()
    
    Add some likely() and unlikely() compiler hints in some of the aacraid
    hardware interface layers. There should be no operational side effects
    resulting from this patch and the changes should be mostly benign on x86
    platforms.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 1196ae025ba4a36eb9e6baab57ba903d36139ff2
Author: Richard Lary <rlary@us.ibm.com>
Date:   Thu Mar 22 10:53:19 2007 -0500

    [SCSI] qla2xxx: fix for byteswap in fc_host fabric_name
    
    This patch fixes byte swap issue in qla2xxx driver
    to fix corrupted fabric_name passed to
    /sys/class/fc_host/host*/fabric_name.
    
    Signed-off-by: Richard Lary <rlary@us.ibm.com>
    Acked-by: Seokmann Ju <seokmann.ju@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 07da60c1f45a6a5f563429e88e8c94c82f9132eb
Author: Anton Blanchard <anton@samba.org>
Date:   Wed Mar 21 08:41:47 2007 -0500

    [SCSI] lpfc: fix oops when parsing dodgy VPD
    
    We have seen two cases where VPD on an emulex card has been incorrect
    and we end up walking off the end of memory. It looks like someone made
    an update (increased the length of a string) without increasing the
    Length field. Then we do:
    
    	Length -= (3+i);
    
    And since Length is unsigned it becomes very large and we loop forever
    in the encapsulating:
    
    	while (Length > 0) {
    
    If we make Length signed then we fall out of the loop and proceed on.
    
    Its important to note we have only seen this in the lab and it may be
    the only two cases of this in existence, but since the rest of the code
    has been written to be resilient against bad VPD we may as well fix this
    too.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Acked-by: James Smart <James.Smart@Emulex.Com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 756970ad4bb93027a60da2de9b43d094b7f387a2
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Thu Mar 29 01:58:44 2007 -0300

    ACPI: thinkpad-acpi: update MAINTAINERS
    
    Update MAINTAINERS file for the ibm-acpi -> thinkpad-acpi renaming.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 643f12dbb660e139fbaea268f3e3ce4d7d594b8f
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Thu Mar 29 01:58:43 2007 -0300

    ACPI: thinkpad-acpi: cleanup after rename
    
    Cleanup documentation, driver strings and other misc stuff, now that the
    driver is named "thinkpad-acpi".
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d903ac5455102b13d0e28d6a39f640175fb4cd4d
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Thu Mar 29 01:58:42 2007 -0300

    ACPI: thinkpad-acpi: add compatibility MODULE_ALIAS entry
    
    Add a ibm_acpi module alias for userpace, so that modprobe ibm_acpi will
    still load the correct driver.  This alias can be removed in the future,
    probably two years from now if nothing warrants removing it sooner.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 85998248b2e8c6ae7d3ad1fa7b059aed22205ec4
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Thu Mar 29 01:58:41 2007 -0300

    ACPI: thinkpad-acpi: cleanup Kconfig for thinkpad-acpi
    
    Since ibm-acpi was renamed to thinkpad-acpi, rename and update its Kconfig
    entries and Kconfig-related symbols accordingly.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit f21f85de4b3b9ad4a671fb19a889c16db2ea38b2
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Thu Mar 29 01:58:40 2007 -0300

    ACPI: ibm-acpi: rename driver to thinkpad-acpi
    
    Rename the ibm-acpi driver to thinkpad-acpi.  ThinkPads are not even made
    by IBM anymore, so it is high time to rename the driver...
    
    The name thinkpad-acpi was used sometime ago by a thinkpad-specific hotkey
    driver by Erik Rigtorp, around the 2.6.8-2.6.10 time frame.  The driver
    apparently never got merged into mainline (it did make some trips through
    -mm).  ibm-acpi was merged soon after, making its debut in 2.6.10.
    
    The reuse of the thinkpad-acpi name shouldn't be a problem as far as user
    confusion goes, as Erik's thinkpad-acpi apparently didn't get widespread
    use in the Linux ThinkPad community and most hits for thinkpad-acpi in
    google point to ibm-acpi anyway.
    
    Erik, if you read this, please consider the reuse of the thinkpad-acpi name
    as a compliment to your effort to make ThinkPads more useful to all of us.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit ddd83eff58888928115b3e225a46d3c686e64594
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Fri Mar 30 10:39:42 2007 -0600

    [IA64] update memory attribute aliasing documentation & test cases
    
    Updates documentation and adds some test cases.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 6d40fc514c9ea886dc18ddd20043a411816b63d1
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Fri Mar 30 10:35:43 2007 -0600

    [IA64] fail mmaps that span areas with incompatible attributes
    
    Example memory map (from HP sx1000 with VGA enabled):
        0x00000 - 0x9FFFF supports only WB (cacheable) access
        0xA0000 - 0xBFFFF supports only UC (uncacheable) access
        0xC0000 - 0xFFFFF supports only WB (cacheable) access
    
    Some versions of X map the entire 0x00000-0xFFFFF area at once.  With the
    example above, this mmap must fail because there's no memory attribute that's
    safe for the entire area.
    
    Prior to this patch, we performed the mmap with a UC mapping.  When X
    accessed the WB memory at 0xC0000, it caused an MCA.  The crash can happen
    when mapping 0xC0000 from either /dev/mem or a /sys/.../legacy_mem file.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 2cb22e23a5fcbcac2de49493aa57c7694028a06a
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Fri Mar 30 10:34:44 2007 -0600

    [IA64] allow WB /sys/.../legacy_mem mmaps
    
    Allow cacheable mmaps of legacy_mem if WB access is supported for the region.
    The "legacy_mem" file often contains a shadow option ROM, and some versions of
    X depend on this.
    
    Tim Yamin <plasm@roo.me.uk> reported that this change fixes X on a Dell
    PowerEdge 3250.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 9b50ffb0c0281bc5a08ccd56ae9bb84296c28f38
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Fri Mar 30 10:34:05 2007 -0600

    [IA64] make ioremap avoid unsupported attributes
    
    Example memory map (from HP sx1000 with VGA enabled):
        0x00000 - 0x9FFFF supports only WB (cacheable) access
        0xA0000 - 0xBFFFF supports only UC (uncacheable) access
        0xC0000 - 0xFFFFF supports only WB (cacheable) access
    
    pci_read_rom() indirectly uses ioremap(0xC0000) to read the shadow VGA option
    ROM.  ioremap() used to default to a 16MB or 64MB UC kernel identity mapping,
    which would cause an MCA when reading 0xC0000 since only WB is supported there.
    
    X uses reads the option ROM to initialize devices.  A smaller test case is:
      # echo 1 > /sys/bus/pci/devices/0000:aa:03.0/rom
      # cp /sys/bus/pci/devices/0000:aa:03.0/rom x
    
    To avoid this, we can use the same ioremap_page_range() strategy that most
    architectures use for all ioremaps.  These page table mappings come out of the
    vmalloc area.  On ia64, these are in region 5 (0xA... addresses) and typically
    use 16KB or 64KB mappings instead of 16MB or 64MB mappings.  The smaller
    mappings give more flexibility to use the correct attributes.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit c4add2e537e6f60048dce8dc518254e7e605301d
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date:   Fri Mar 30 10:33:11 2007 -0600

    [IA64] rename ioremap variables to match i386
    
    No functional change, just use the same names as i386.
    
    Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit edfac96a92b88d3b0b53e3f8231b74beee9ecd1d
Author: Jon Loeliger <jdl@freescale.com>
Date:   Tue Mar 20 11:18:46 2007 -0500

    [POWERPC] 85xx: Add initial MPC8544DS basic port defconfig.
    
    Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
    Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
    Signed-off-by: York Sun <yorksun@freescale.com>
    Signed-off-by: Andy Fleming <afleming@freescale.com>
    Signed-off-by: Jon Loeliger <jdl@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit d93daf848161043c06b665bbbd4bc22ef0247065
Author: Jon Loeliger <jdl@freescale.com>
Date:   Tue Mar 20 11:19:10 2007 -0500

    [POWERPC] 85xx: Add initial MPC8544 DS platform files.
    
    This patch provides the basic MPC8544 DS platform code and config.
    Follow-up patches will add peripherals such as PCI and SATA.
    
    Signed-off-by: Xianghua Xiao <x.xiao@freescale.com>
    Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
    Signed-off-by: York Sun <yorksun@freescale.com>
    Signed-off-by: Andy Fleming <afleming@freescale.com>
    Signed-off-by: Jon Loeliger <jdl@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 23308c54d559a210019a576c5741cfb762af69d6
Author: Michael Barkowski <michael.barkowski@freescale.com>
Date:   Mon Mar 19 09:15:28 2007 -0500

    [POWERPC] 83xx: Add MPC832x RDB board support.
    
    Add support for the MPC8323E Reference Development Board (RDB).  The board
    is a mini-ITX reference board with 64M DDR2, 16M flash, USB, PCI,
    10/100 ethernet, serial, and phone ports.
    
    Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com>
    Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 62a6d7fd9bc1d85f9aae734c46234e88fa839db0
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Mon Mar 26 21:38:49 2007 -0800

    ACPI: dock: use NULL for pointer
    
    Use NULL instead of 0 for pointers:
    drivers/acpi/dock.c:677:75: warning: Using plain integer as NULL pointer
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1a4d9399a921c287eb175d29f288d1d92d02b302
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Mar 15 10:01:14 2007 -0500

    [POWERPC] 83xx: Removed dead header
    
    mpc832x_mds.h was exporting a function that didn't exist anymore.  Once removed
    the header had no purpose.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit de74f70360353929009f8611f3bb8fbb4f030527
Author: Timur Tabi <timur@freescale.com>
Date:   Thu Mar 15 09:48:53 2007 -0500

    [POWERPC] QE: fix invalid pointer usage in ucc_slow_init()
    
    In two places, ucc_slow_init() passes a physical address instead of the
    virtual address to functions that were expecting the latter, causing a kernel
    panic.  us_info->regs contains the physical address of the UCC register set.
    The registers are ioremap'd to kernel space, and the virtual pointers are
    stored in us_regs.  The code was using us_info->regs when it should have been
    using us_regs.
    
    Signed-off-by: Timur Tabi <timur@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 8b03336752e664880182a8f50e1807edc7fe93d4
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sat Mar 10 16:17:28 2007 -0500

    [POWERPC] 83xx: Delete unused header file.
    
      Delete apparently unused header file
    arch/powerpc/platforms/83xx/mpc834x_itx.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 7d776cb596994219584257eb5956b87628e5deaf
Author: Timur Tabi <timur@freescale.com>
Date:   Mon Mar 12 15:40:27 2007 -0500

    [POWERPC] QE: automatically select QE options
    
    Change the Kconfig files so that the Freescale QE options are automatically
    selected if a QE device is selected.  Previously, you'd need to manually
    select UCC_FAST if you want any "fast" UCC devices, such as Gigabit Ethernet.
    Now, the QE Gigabit Ethernet option is always available if the device has a
    QE, and UCC_FAST is automatically enabled.  A side-effect is that the
    "QE Options" menu no longer exists.
    
    Signed-off-by: Timur Tabi <timur@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 9eb90a0c3b333e27db74412833a36da3f27da6a3
Author: Zang Roy-r61911 <tie-fei.zang@freescale.com>
Date:   Fri Mar 9 13:27:28 2007 +0800

    [POWERPC] 86xx/85xx: Unify Freescale PCI Express memory map registers structure
    
    Unify PCI Express memory map registers structure define
    to arch/pwoerpc/sysdev/fsl_pcie.h for Freescale 85xx/86xx
    processor family.
    
    Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 3e4e97f42e134e1fe46bdf36bd5d874f5b4f8755
Author: Jon Loeliger <jdl@freescale.com>
Date:   Wed Mar 7 14:48:45 2007 -0600

    [POWERPC] 86xx/85xx: Move 8641 PCI-Express to arch/powerpc/sysdev/fsl_pcie.c.
    
    This move sets the stage for the use of generic PCI Express
    code in 85xx and 86xx parts from FSL.  Subsequent patches
    for 8548 and 8544 will be able to use this shared code.
    
    Signed-off-by: Jon Loeliger <jdl@freescale.com>
    Acked-by: Andy Fleming <afleming@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit e0e3c8d432ab9503b167e53d60b145f0e26bb1e2
Author: Zhang Wei <wei.zhang@freescale.com>
Date:   Wed Mar 7 11:47:41 2007 -0600

    [POWERPC] 86xx: Added 2nd PCI-Ex controller support for MPC8641 HPCN to DTS.
    
    Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
    Signed-off-by: Jon Loeliger <jdl@freescale.com>
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit e5a2072bd48eb4a35c57a8ec45897ac2db3a3f82
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Thu Mar 22 17:02:21 2007 +1100

    [POWERPC] New reg.h for the zImage
    
    This patch adds a reg.h to the zImage code, with common definitions
    for accessing system registers.  For now, this includes functions for
    retrieving the PVR and the stack pointer.  This patch then uses the
    new reg.h to let start() display the running stack address without
    having to explicitly pass the stack as a parameter from the asm code.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit fae59c39e885148acf42320fe0d4ebf4cb3e9231
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Thu Mar 22 16:59:13 2007 +1100

    [POWERPC] Add gcc format warnings to zImage printf()
    
    This patch adds the correct attributes to the zImage's versions of
    printf to make gcc generate format string mismatch warnings.  It also
    corrects several minor problems with format strings in the zImage thus
    discovered.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9da82a6dee9db4cd5ae7a74ab4f51afb52b6efb9
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 21 09:03:23 2007 -0600

    [POWERPC] boot: Use a common zImage rule
    
    Before the plethora of platforms gets any worse, establish a common
    rule to invoke the wrapper for any platform.  Add arguments to
    the rule for initrd, dts, dtb, etc.   Show example usage with initrd.
    
    Create default rules for zImage, and zImage.initrd.  initrd targets
    depend on the ramdisk file.
    
    Don't consider targets for zImage.initrd that are targets for zImage.
    This means uImage is no longer considered a target for zImage.initrd.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5d7960ffb8157acdf92223e32d34da504578aca0
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 21 09:03:10 2007 -0600

    [POWERPC] boot: clean rule fixes
    
    Now that obj-boot is in targets, we can remove (twice) it from clean-files.
    zImage.initrd was missing, move zImage nearer where its used, and place
    zImage.initrd next to it.  Remove non-ported zImage.sandpoint, and add
    auto-generation of unconfigured zImage.initrd* like image-.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    --
    Testing: did a few builds and cleans
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 235fd8354528a7dabb3b6050ca4d201549a6f858
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 21 09:02:37 2007 -0600

    [POWERPC] boot: Use FORCE
    
    Kbuild if_changed and if_changed_dep require the use of the dummy
    FORCE to get the dependencies right.   Also add to targets to get
    correct behavior.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 160cc3ece727c5158facec9937c2a5b10013bae1
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 21 09:02:53 2007 -0600

    [POWERPC] bootwrapper: Allow platforms to call library zImage_start
    
    Some platforms might need to run some code before the zImage start, but
    could otherwise use the bss clear and relocation code.   Export the
    start address strongly as zImage_start_lib.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6a923216aac01d0f3eeea606377b81541f1a2773
Author: Milton Miller <miltonm@bga.com>
Date:   Wed Mar 21 09:02:44 2007 -0600

    [POWERPC] bootwrapper: Add a fatal error helper
    
    Add a macro fatal that calls printf then exit.  User must include stdio.h.
    
    Typically replaces 3 lines with 1, although I added back some whitespace.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 3ede41c718c7845905231019e42d05a3ed329515
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:34:00 2007 -0300

    ACPI: ibm-acpi: move driver to drivers/misc hierarchy
    
    ibm-acpi is not an ACPICA driver, so move it to drivers/misc as per Len
    Brown's request.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 38f996ed21089fa4ae40526a5f428e3c792ea561
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:59 2007 -0300

    ACPI: ibm-acpi: update documentation
    
    Update documentation header, and relocate a hunk of text that was missplaced.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit a62bc916cf48caaf9efa2fed20440fd617647c6c
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:58 2007 -0300

    ACPI: ibm-acpi: update copyright notice
    
    Update copyright and license info on the source code comments.  No
    functional changes.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 56b6aeb05890f219895197f5166637b3d7a6f679
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:57 2007 -0300

    ACPI: ibm-acpi: organize code
    
    Shuffle code around to better organize the driver code inside the
    ibm-acpi.c file.
    
    This patch adds no functional changes.  It is pure fluff that will make me
    a bit more productive.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 1406cdd1760743106278c1f02a0f445159c8f400
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:56 2007 -0300

    ACPI: ibm-acpi: add header file
    
    Add a (private) header file for ibm-acpi, and move type definitions and
    ThinkPad driver constants to the new header file.
    
    This patch has no functional changes.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit e062e0343871a41e8ec408f1c1e8ac3b0310da9d
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:55 2007 -0300

    ACPI: ibm-acpi: rename some identifiers
    
    Rename some identifiers so that they are more in tune with the rest of the
    driver code, or less generic.
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 837ca6ddb440c186eaa8e01b69486581d3457f2c
Author: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Date:   Fri Mar 23 17:33:54 2007 -0300

    ACPI: ibm-acpi: kill trailing whitespace
    
    I shall protect the ibm-acpi city against the invasion of the barbarian
    blanks!  To the unforgiving jaws of sed s/[[:blank:]]\+$// they go!
    
    Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 70b52b3869a31aab85241a1f998f9943a3905637
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Mar 19 11:53:55 2007 +0100

    [POWERPC] powermac: disallow pmu sleep notifiers from aborting sleep
    
    Tracing through the code, no current PMU sleep notifier can abort sleep.
    Since no new PMU sleep notifiers should be added, this patch simplifies the
    code and removes the ability to abort sleep.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 17e638bc28f2fdc9c0d3eebfb80fce43827b8d12
Author: Johannes Berg <johannes@sipsolutions.net>
Date:   Mon Mar 19 11:53:53 2007 +0100

    [POWERPC] Generic time suspend/resume code
    
    This removes the time suspend/restore code that was done through
    a PMU notifier in arch/platforms/powermac/time.c.
    
    Instead, introduce arch/powerpc/sysdev/timer.c which creates a sys
    device and handles time of day suspend/resume through that.
    
    This should probably be replaced by using the generic RTC framework
    but for now it gets rid of the arcane powermac specific hack.
    
    Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ec5f77e789a02adf7c45f03a76455b4e71ae1c5b
Author: Stefan Roese <sr@denx.de>
Date:   Fri Mar 16 21:06:00 2007 +0100

    [POWERPC] ppc: Fix PCIX configuration of Ocotea & Taishan for > 512MB DDR
    
    Change the configuration of the PCIX PCI->PLB inbound memory window
    to be 2GB instead of 512kB. The comment already mentioned 2GB, but the
    code unfortunately didn't reflect this.
    
    Signed-off-by: Stefan Roese <sr@denx.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f6f7dde3f778b318aca71220834482d4ea2d7738
Author: anton@samba.org <anton@samba.org>
Date:   Tue Mar 20 20:38:19 2007 -0500

    [POWERPC] Use lowercase for hex printouts in oops messages.
    
    Use lowercase for hex printouts in oops messages. The number of times I have
    tried to copy and paste from an oops into an objdump search...
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Acked-by: Olof Johansson <olof@lixom.net>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ae7f4463773dafac52d70c9803f283afe27ab1e3
Author: anton@samba.org <anton@samba.org>
Date:   Tue Mar 20 20:38:14 2007 -0500

    [POWERPC] Fix backwards ? : when printing machine type
    
    Looks like someone got this backwards, highlighting the perils of the
    ? : !!! :)
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 34c2a14fc20e4ab878fbf87e5f7fe1cff6afb3d4
Author: anton@samba.org <anton@samba.org>
Date:   Tue Mar 20 20:38:13 2007 -0500

    [POWERPC] Handle recursive oopses
    
    Handle recursive oopses, like on x86. We had a few cases recently where
    we locked up in oops printing and didnt make it into crashdump.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6031d9d9ad905b514bf45572bd1877fe6b5145ab
Author: anton@samba.org <anton@samba.org>
Date:   Tue Mar 20 20:38:12 2007 -0500

    [POWERPC] Clean up pmac_backlight_unblank in oops path
    
    Move pmac_backlight_unblank into its own function and only take the
    pmac_backlight_mutex when we are on a pmac for that added bit of
    paranoia.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 293e4688fe2fec87fccf84a3b1100b27191424e9
Author: anton@samba.org <anton@samba.org>
Date:   Tue Mar 20 20:38:11 2007 -0500

    [POWERPC] Add missing oops_enter/oops_exit
    
    Add missing oops_enter/oops_exit, makes pause_on_oops boot parameter work.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9e9c1326a592c677c94d730fcf4446d0e275aef4
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Mar 24 17:57:54 2007 +1100

    drm: just use io_remap_pfn_range on all archs..
    
    Move the sparc64 ifdef around to clean this up.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 38315878a560eede1a2db52e511ad3a2cfbb4206
Author: Hugh Dickins <hugh@veritas.com>
Date:   Sat Mar 24 17:55:16 2007 +1100

    drm: fix DRM_CONSISTENT mapping
    
    This patch got lost in the DRM git tree for ages, bring it back to life.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit d7d8aac79dc38cbdef83b774e49bafdae9918137
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Sat Mar 24 17:52:49 2007 +1100

    drm: fix up mmap locking in preparation for ttm changes
    
    This change is needed to protect againt disappearing maps which aren't common.
    The map lists are protected using sturct_mutex but drm_mmap never locked it.
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 118af321b24529d546cad1c4b6fccf02cd838384
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Fri Mar 23 11:27:01 2007 -0400

    [MTD] Delete unused header file linux/mtd/iflash.h.
    
    Delete the unreferenced header file include/linux/mtd/iflash.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 8e5368a1e230a87220ef0d238584002e4a429ce3
Author: David Woodhouse <dwmw2@infradead.org>
Date:   Fri Mar 23 10:40:04 2007 +0000

    [MTD] [NAND] Remember timing settings for CAFÃ‰ NAND controller.
    
    We'll need them for suspend/resume.
    
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 040ac32048d5efabd557c1e0a6ab8aec2c710c56
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Fri Mar 23 13:28:33 2007 +1100

    drm: fix driver deadlock with AIGLX and reclaim_buffers_locked
    
    Bugzilla Bug #9457
    
    Add refcounting of user waiters to the DRM hardware lock, so that we can use
    DRM_LOCK_CONT flag more conservatively.
    
    Also add a kernel waiter refcount that if nonzero transfers the lock for the
    kernel context when it is released. This is useful when waiting for idle and can be used for very simple fence object driver implementations for the new memory manager
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 4330f5da98eb91392c7a7b00c22a24c57079c0fc
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Fri Mar 16 09:32:17 2007 -0500

    [POWERPC] Created arch/powerpc/platforms/Kconfig for "Platform support"
    
    Split "Platform support" menu out from arch/powerpc/Kconfig into
    arch/powerpc/platforms/Kconfig in prep for allowing other sub-arches to
    be configured via a single "Platform support" menu.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 35a1245ad09412ffba2f17631a9fb3cae3d5a5ac
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Fri Mar 16 09:14:08 2007 -0500

    [POWERPC] Split several platforms into their respective Kconfig file
    
    Moved pseries, iseries, chrp, prep, maple and pasemi into their respective
    arch/powerpc/platform/*/Kconfig files out of arch/powerpc/Kconfig
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit fd42c717510cd65529ccb46ccfa71fe4dde9fbd9
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Fri Mar 16 08:46:55 2007 -0500

    [POWERPC] Removed config options that we don't support in embedded6xx
    
    When we started arch/powerpc we duplicated a number of config options from
    arch/ppc for various platforms that are supported.  Now that we actually
    support a few platforms, remove all the ones that haven't been moved over.
    Additionally, this cleanup moved the 82xx/PQ2 options over into
    arch/powerpc/platforms/82xx/Kconfig where they belong.  It also killed
    GEN550 which doesn't exist in arch/powerpc.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 72e77a1b941e24e67f396246310438afbad9e6b3
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Fri Mar 16 08:13:18 2007 -0500

    [POWERPC] Split cell platforms into their respective Kconfig file
    
    Cleaning up arch/powerpc/Kconfig platform support.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 9b8babf4a9cc0ba3a8f00b84419ab44bb4d22e05
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Mar 15 18:15:07 2007 -0500

    [POWERPC] Split powermac platforms into their own Kconfig file
    
    Cleaning up arch/powerpc/Kconfig platform support.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 5396132cf90423d988bde340987ba21a27b787d7
Author: Kumar Gala <galak@kernel.crashing.org>
Date:   Thu Mar 15 18:13:20 2007 -0500

    [POWERPC] Split 52xx platforms into their own Kconfig file
    
    Cleaning up arch/powerpc/Kconfig platform support.
    
    Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

commit 4002aca771a2aa2848e94a98cf51a2cae4e77ae0
Author: Anton Blanchard <anton@samba.org>
Date:   Tue Mar 20 10:08:33 2007 -0500

    [POWERPC] Remove last_syscall
    
    Remove last_syscall from 32bit powerpc, its been gone in 64bit for years.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f4db196717c615db68100dee2de8f47d2dc19372
Author: Anton Blanchard <anton@samba.org>
Date:   Tue Mar 20 10:07:12 2007 -0500

    [POWERPC] Remove _get_SP
    
    We already have an inline __get_SP, no need for yet another one.
    
    Signed-off-by: Anton Blanchard <anton@samba.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 4980d5eb750288ffc0bb9daff3feb947e1bac61e
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 15:01:31 2007 -0500

    [POWERPC] EEH: restructure multi-function support
    
    Rework how multi-function PCI devices are identified and traversed.
    This fixes a bug with multi-function recovery on Power4 that was
    introduced by a recent Power4 EEH patch.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit fa1be476a2baa0961f63161caee6733cdc353adb
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:59:59 2007 -0500

    [POWERPC] EEH: verify state change
    
    After requesting a state change, verify that the state change
    actually ocurred, and the system ends up in the expected state.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d0ab95ca9854174029cef2f08acf1859441cb547
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:59:10 2007 -0500

    [POWERPC] EEH: rm un-needed data
    
    The EEH event notification system passes around data that is
    not needed or at least, not used properly. Stop passing this
    data; get it in a more reliable fashion.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9c547768e7d9f456f1b145102e75f79e30f7b709
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:58:07 2007 -0500

    [POWERPC] EEH: wait for slot status
    
    Modify routine that returns PCI slot status to wait for slot status
    to become available. This is needed, as slots that are in some remote
    card cage may go offline for extended periods of time. New users for
    this routine in following patches.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 90375f53960f2b1e8d2a6af3324d440e3a977bf3
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:56:43 2007 -0500

    [POWERPC] EEH: handle reset state high
    
    Some firmware versions will return a slot reset state of "1"
    when a slot is EEH frozen. Recognize this as a state that can be
    handled.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 5794dbcbab862e416c4ea4f10fda5e67f5565fd7
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:55:51 2007 -0500

    [POWERPC] EEH: multifunction recovery bugfix
    
    If the second or higher function of a multi-function device fails
    to recover, this failure is not reported upwards. Fix this.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 90fdd6130f5c0053c48e8c8e247091739b6e4092
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:55:10 2007 -0500

    [POWERPC] EEH: hotplug recovery bugfix
    
    If a device driver does not have native PCI error recovery,
    a hotplug error recovery will be attemped. In this case,
    the device driver will not report back whether its healthy
    or not; simply assume that it is.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 147d6a37500348b6bda5738453d84c46678209cf
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:54:21 2007 -0500

    [POWERPC] EEH: support ibm,get-config-addr-info2 RTAS call
    
    Provide support for the new ibm,get-config-addr-info2 RTAS token,
    whenever it is actually available.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 2fd30be8dae25386fc5167c34c6d73201334a8d4
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:53:22 2007 -0500

    [POWERPC] EEH: Tolerate high mmio
    
    Some drivers will attempt to perform a lot of mmio even after
    an EEH event was detected. This is especially the case for fast cpu's
    and PCI-E slots. Be a bit more lenient in allowing this.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e0f90b64181d668ce5995a40f312ed21085bfa98
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:52:04 2007 -0500

    [POWERPC] EEH: Add clarifying messages.
    
    There are multiple code patchs tht resuls in a "permanent
    failure"; when examining rare events, it can be hard to see
    which was taken. This patch adds printk's to assist.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 39d16e295966a1f0025a65eaab4cb59fe5ba8c17
Author: Linas Vepstas <linas@austin.ibm.com>
Date:   Mon Mar 19 14:51:00 2007 -0500

    [POWERPC] EEH: modify order of EEH state checking
    
    Change the order in which pci error state is examined;
    the "capabilites" is not valid if "reset state" is 5.
    
    Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 439a888885c584f7ac8536a43be80475f9eaed71
Author: Len Brown <len.brown@intel.com>
Date:   Thu Mar 22 01:21:05 2007 -0400

    ACPI: sbs: remove i2c_ec.[ch]
    
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 722062334b972c31a3b83dbf7e9b5a58bb2707dd
Author: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Date:   Mon Mar 19 17:45:50 2007 +0300

    ACPI: sbs: Common interface with CM battery
    
    The SBS driver has tne features as CM battery:
    SBS update_time variable has tne same definition as CM battery 'update_time' variable.
    
    Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 6845118b3b7a9cc2ba14dc665370217bc3ba8057
Author: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Date:   Mon Mar 19 17:45:50 2007 +0300

    ACPI: sbs: Debug messages correction/improvement
    
    Debug messages correction/improvement:
    Use ACPI_EXCEPTION instead of ACPI_DEBUG_PRINT.
    
    Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 84cb55987236ffea062a35fbe1441768b6bb2722
Author: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Date:   Mon Mar 19 17:45:50 2007 +0300

    ACPI: sbs: remove I2C Makefile hooks
    
    SBS does not depend on I2C.
    i2c_ec.h and i2c_ec.c are not needed
    
    Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit b4150fc4ae20621edf2f8e1ea5ce13eb2c803e7a
Author: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Date:   Mon Mar 19 17:45:50 2007 +0300

    ACPI: sbs: remove I2C Kconfig dependency
    
    SBS does not depend on I2C.
    
    Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 6d15702cc07503b74494dc4f1ddb15f354987b14
Author: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
Date:   Mon Mar 19 17:45:50 2007 +0300

    ACPI: sbs: use EC rather than I2C
    
    SBS is based on EC function(ec_read/ec_write).
    Not needed using of I2C structures/functions ... is removed.
    SBS does not depend on I2C now.
    
    Signed-off-by: Vladimir Lebedev <vladimir.p.lebedev@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 802ae2f05b646c1e5f9e33cfe4c80cfa1452a0e3
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Wed Mar 21 13:49:47 2007 -0400

    [SCSI] aacraid: cleanup and version stamp driver
    
    There is some residual cleanup of the last series of patches and the
    need to bump the revision number to draw the line in the sand.
    
    The cmd->SCp.phase is set in the aac_valid_context routine, then set
    again to the same value following it's return. The cmd->scsi_done is set
    twice in the aac_queuecommand routine. Free up the scsidev FILO in
    aac_probe_container as it is not needed further down the function in any
    case. Improve the efficiency of the abort handler kernel print
    parameters. Bump revision number of driver to approximate the equivalent
    in the Adaptec supplied version.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 20235f35221472f1a127a5d5414f11091eb0a845
Author: Salyzyn, Mark <mark_salyzyn@adaptec.com>
Date:   Wed Mar 21 13:22:56 2007 -0400

    [SCSI] aacraid: check buffer address in aac_internal_transfer
    
    Captured a panic on an older kernel where an application issuing
    commands via sg was sending requests that lacked a request_buffer, thus
    the buffer pointer used in aac_internal_transer was NULL. The
    application was fixed closing the issue, but felt it was advised to
    immunize the driver against the eventuality.
    
    Signed-off-by: Mark Salyzyn <aacraid@adaptec.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 0272bf7271eb6895b081c3df34c3ebe50cb769b7
Author: James Bottomley <James.Bottomley@steeleye.com>
Date:   Tue Mar 20 14:44:04 2007 -0500

    [SCSI] fix scsi_wait_scan build problem
    
    The #ifdef MODULE around the export of scsi_complete_async_scans()
    which is the API the scsi_wait_scan module uses is incorrect and
    causes the symbol to be undefined in certain circumstances leading to
    a build failure.  Remove the defines.
    
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e91948fd84086020072e022d5463036033d449c1
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Fri Mar 16 17:47:07 2007 +1100

    [POWERPC] Minor paca optimisation
    
    Move the slb_shadow_ptr field into the first cache line since it is
    (like everything there) read-only after boot.  It is in fact statically
    initialised and thereafter only read.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Acked-by: Michael Neuling <mikey@neuling.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0e6806734fd861c360ecbb4262d3d5678cea7faf
Author: Milton Miller <miltonm@bga.com>
Date:   Mon Mar 19 14:58:06 2007 -0600

    [POWERPC] boot: export flush_cache
    
    Move the declaration of flush_cache to ops.h for use by platform code.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 65b580395d234350b53a03285b98c9a271eb5eb7
Author: Milton Miller <miltonm@bga.com>
Date:   Mon Mar 19 14:58:04 2007 -0600

    [POWERPC] boot: rebuild when wrapper changes
    
    Since there is magic defined per platform in the wrapper script, the
    zImage targets should depend on it.
    
    Signed-off-by: Milton Miller <miltonm@bga.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit f61e7cd21b47b07002aa39d2f8f0db14b4a51719
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Mar 16 12:28:49 2007 -0500

    [POWERPC] bootwrapper: Make setprop accept a const buffer.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit e0a2f28b4dee2a1e4c62dc8389f25defb284e387
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Mar 16 12:28:46 2007 -0500

    [POWERPC] Document the linux,network-index property.
    
    To allow more robust association of each network device node with an
    index (such as is used by the firmware or an EEPROM to indicate MAC
    addresses), a network device's node may specify the index explicitly.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a9903811bf8d130a26004f9cb27b66513a267908
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Mar 16 12:27:59 2007 -0500

    [POWERPC] bootwrapper: Make compression of the kernel image optional.
    
    The --no-gzip option can be passed to the wrapper so that the kernel
    image is included uncompressed into the zImage.  This is intended for
    bootloaders where the zImage itself can be compressed, or where boot time
    is considered more important than kernel image size.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a07940ba00218267493798e89e3f4a86fea53125
Author: Scott Wood <scottwood@freescale.com>
Date:   Fri Mar 16 12:27:54 2007 -0500

    [POWERPC] bootwrapper: Add dt_ops methods.
    
    Add get_parent, create_node, and find_node_by_prop_value to dt_ops.
    Currently only implemented by flatdevtree_misc.
    
    Also, add a _str convenience wrapper for setprop.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cc5d2c8c64804564617a7be71c73a075a426d1c6
Author: James Bottomley <James.Bottomley@steeleye.com>
Date:   Tue Mar 20 12:26:03 2007 -0500

    [SCSI] sd: fix up start/stop messages for new sd_printk() API
    
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit c3c94c5a2fb43a654e777f509d5032b0db8ed09f
Author: Tejun Heo <htejun@gmail.com>
Date:   Wed Mar 21 00:13:59 2007 +0900

    [SCSI] sd: implement START/STOP management
    
    Implement SBC START/STOP management.  sdev->mange_start_stop is added.
    When it's set to one, sd STOPs the device on suspend and shutdown and
    STARTs it on resume.  sdev->manage_start_stop defaults is in sdev
    instead of scsi_disk cdev to allow ->slave_config() override the
    default configuration but is exported under scsi_disk sysfs node as
    sdev->allow_restart is.
    
    When manage_start_stop is zero (the default value), this patch doesn't
    introduce any behavior change.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    
    Rejections fixed and
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 3721050afc6cb6ddf6de0f782e2054ebcc225e9b
Author: Tejun Heo <htejun@gmail.com>
Date:   Wed Mar 21 00:07:18 2007 +0900

    [SCSI] sd: fix return value of sd_sync_cache()
    
    sd_sync_cache() should return -errno on error, fix it.
    
    Signed-off-by: Tejun Heo <htejun@gmail.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit ad8c31bb69d60c0c6bc6431bccdf67e5a96c0d31
Author: Eric Moore <eric.moore@lsi.com>
Date:   Mon Mar 19 10:31:51 2007 -0600

    [SCSI] fusion: remove VMWare guest OS remounted as read only work around
    
    This address the issue of VMWare guest OS being remounted as read-only
    becuase the underlying device was held busy too long and at the
    same time address Engenio MPP driver concerns over infinite retries.
    This patch removes the code that snoops the SAM STATUS on busy, which
    would be returning DID_BUS_BUSY, instead we return the status as is.
    Retry hanlding seems to be properly handled in scsi_softirq_done,
    where a busy sam status would only occurr for the time specified by
    (cmd->allowed +1) * cmd->timeout_per_command.
    
    Signed-off-by: Eric Moore <Eric.Moore@lsi.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit b364fd5081b02fa8a966a29eea2da628913fd4b8
Author: Horms <horms@verge.net.au>
Date:   Mon Mar 19 15:06:44 2007 +0900

    [SCSI] fusion: honour return value of pci_enable_device() in mpt_resume()
    
    Honour the return value of pci_enable_device(), which
    seems to be a desirable thing to do:
    
      2.6.20-rc4
      gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
    
        CC [M]  drivers/message/fusion/mptbase.o
        drivers/message/fusion/mptbase.c: In function `mpt_resume':
        drivers/message/fusion/mptbase.c:1541: warning: ignoring return value
        of `pci_enable_device', declared with attribute warn_unused_result
    
    It also in turn has mptscsih_resume() honour the return value of
    mpt_resume()
    
    I'm not sure about the handling of the other potential error cases
    in mpt_resume(), of which there appear to be many. But this does
    seem to be a good start.
    
    Signed-off-by: Simon Horman <horms@verge.net.au>
    Acked-by: "Moore, Eric" <Eric.Moore@lsi.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a1f9ce056a1875b6c8633f370df4fb169b925b16
Author: Horms <horms@verge.net.au>
Date:   Fri Mar 16 16:05:22 2007 +0900

    [SCSI] fusion: remove unnecessary code in mptscsih_resume()
    
    It seems that most of the code in mptscsih_resume() doesn't
    do anything. This patch removes that code.
    
    Signed-off-by: Simon Horman <horms@verge.net.au>
    Acked-by: "Moore, Eric" <Eric.Moore@lsi.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 5f9279f23913045c810eeb4ab03c694c46231f75
Author: Richard Knutsson <ricknu-0@student.ltu.se>
Date:   Sun Mar 18 00:58:23 2007 +0100

    [SCSI] eata_pio: Remove FALSE/TRUE defines
    
    eata_generic.h is only included by eata_pio.c and it only uses
    FALSE/TRUE in comments.
    
    Signed-off-by: Richard Knutsson <ricknu-0@student.ltu.se>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 6c5f8ce1fb7e8925d957f754a9513911399791b9
Author: James Bottomley <James.Bottomley@steeleye.com>
Date:   Fri Mar 16 17:44:41 2007 -0500

    [SCSI] expose eh_timed_out to the host template
    
    It looks like megaraid_sas at least needs this to throttle its commands
    as they begin to time out.  The code keeps the existing transport
    template use of eh_timed_out (and allows the transport to override the
    host if they both have this callback).
    
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 03d4433721880bf1972c924b168e4e1dd3c59d53
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:27:45 2007 -0700

    [SCSI] aacraid: Improved error handling
    
    Received from Mark Salyzyn,
    
    This set of fixes improve error handling stability of the driver. A popular
    manifestation of the problems is an NULL pointer reference in the interrupt
    handler when referencing portions of the scsi command context, or in the
    scsi_done handling when an offlined device is referenced.
    
    The aacraid driver currently does not get notification of orphaned command
    completions due to devices going offline. The driver also fails to handle the
    commands that are finished by the error handler, and thus can complete again
    later at the hands of the adapter causing situations of completion of an
    invalid scsi command context. Test Unit Ready calls abort assuming that the
    abort was successful, but are not, and thus when the interrupt from the adapter
    occurs, they reference invalid command contexts. We add in a TIMED_OUT flag to
    inform the aacraid FIB context that the interrupt service should merely release
    the driver resources and not complete the command up. We take advantage of this
    with the abort handler as well for select abortable commands. And we detect and
    react if a command that can not be aborted is currently still outstanding to
    the controller when reissued by the retry mechanism.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit f2b1a06ad46209c6e631e3099138d1fa3f14d3a8
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:27:32 2007 -0700

    [SCSI] aacraid: fix srb ioctl for 64 bits
    
    Received from Mark Salyzyn,
    
    The raw srb ioctl is supposed to be able to take packets with 32 and 64 bit
    virtual address SG elements, it did not handle the frames with 64 bit SG
    elements well when communicating with 64 bit DMA capable adapters, and it did
    not handle the 32 bit limited DMA adapters at all.  The enclosed patch now
    handles all four quadrants (32 bit / 64 bit SG elements in SRB requests + 32
    bit or 64 bit DMA capable adapters)
    
    This fix is required before Java based management applications in a 64 bit user
    space can submit raw srb requests to the array physical components via the
    ioctl mechanism, the allocated user memory pool on 64 bit machines under this
    environment forced the management software's hands to submit 64 bit user space
    virtual address SG elements in via the ioctl.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 9e7c349c91db3a9f9ac6cd74a693c4093c7d4571
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:26:55 2007 -0700

    [SCSI] aacraid: remove un-needed references to container id (cid)
    
    Received from Mark Salyzyn,
    
    This little patch removes the ',cid)' container identification argument
    from some of the functions. The argument is used in some cases as merely
    a debug helper and thus not used, and in others, the value can be
    quickly acquired from the scsi command in their single solitary use in
    the procedure rather than wasting resources on passing the argument in
    from above.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 33bb3b296207ff4f9e3b8dddb623e645ee1b8809
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:27:21 2007 -0700

    [SCSI] aacraid: Fix ioctl handling when adapter resets
    
    Received from Mark Salyzyn,
    
    Outstanding ioctl calls still have some problems with aborting cleanly
    in the face of a reset iop recovery action should the adapter ever enter
    into a Firmware Assert (BlinkLED) condition. The enclosed patch resolves
    some uncovered flawed handling.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit fe76df4235986cfacc2d3b71cef7c42bc1a6dd6c
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 12:55:07 2007 -0700

    [SCSI] aacraid: Fix blocking issue with container probing function (cast update)
    
    Received from Mark Salyzyn,
    
    The aac_probe_container call blocks. This is an issue because it is called on
    occasion in the context of the queuecommand handler. Once in a blue moon this
    has resulted in a kernel panic sleeping during interrupt; or problems with some
    embedded system versions of the kernel that depend on queuecommand to not
    block. This ugly patch rewrites the aac_probe_container call into a new routine
    _aac_probe_container that is an asynchronous state machine to complete the
    series of operations. The legacy blocking aac_probe_container call used in
    other areas of the driver (during initialization scanning for all targets and
    in the separate hot-add/remove [aacraid] thread) merely issues
    _aac_probe_container and then simple spins calling schedule() waiting for
    completion.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a8166a52968216ae079a5530ac3269147de2ef31
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:26:22 2007 -0700

    [SCSI] aacraid: Fix struct element name issue
    
    Received from Mark Salyzyn,
    
    This patch is to resolve a namespace issue that will result from a patch
    expected in the future that adds a new interface; rationalized as
    correcting a long term issue where hw_fib, instead of hw_fib_va, refers
    to the virtual address space and hw_fib_pa refers to the physical
    address space. A small fragment of this patch also cleans up an unused
    variable that was close to the patch fragments.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 8418852d11f0bbaeebeedd4243560d8fdc85410d
Author: Mark Haverkamp <markh@linux-foundation.org>
Date:   Thu Mar 15 10:26:05 2007 -0700

    [SCSI] aacraid: add restart adapter platform function
    
    Received from Mark Salyzyn,
    
    This patch updates the adapter restart function to deal with some
    adapters that have specific IOP reset needs. Since the code for
    restarting the adapter was in two places, changed over to utilizing a
    platform function in one place.
    
    Signed-off-by: Mark Haverkamp <markh@linux-foundation.org>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit b22f687dd28a7a8886b918294b4d558ef175c07d
Author: Pete Wyckoff <pw@osc.edu>
Date:   Tue Mar 13 16:53:28 2007 -0400

    [SCSI] set resid in scsi_io_completion() even for check condition
    
    Some targets can return both valid data and sense information.
    Always update the request data_len from the SCSI command residual.
    Callers should interpret sense data to determine what parts of the
    data are valid in case of a CHECK CONDITION status.
    
    Signed-off-by: Pete Wyckoff <pw@osc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a52decafbe3fdca5e8430d4f58ffcec1f4a6302c
Author: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Date:   Tue Mar 13 10:07:15 2007 +0900

    [SCSI] tgt: remove the code to build sense
    
    tgt notifies a LLD of the failure with sense when it hits the
    user-space daemon bugs. However, tgt doesn't know anything about SCSI
    devices that initiators talks to. So it's impossible to send proper
    sense buffer (format and contents).
    
    This patch changes tgt not to notify a LLD of the failure with bogus
    sense. Instead, tgt just re-queues the failure command to the internal
    list so that it will be freed cleanly later on when the scsi_host is
    removed.
    
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit c3d2350a8420dbf9d48f5f8a0fb72117bfcbc1b0
Author: James Smart <James.Smart@Emulex.Com>
Date:   Mon Mar 12 14:16:35 2007 -0500

    [SCSI] fc_transport: update potential link speeds
    
    This patch updates the FC transport for all speeds identified in
    SM-HBA.  Note: it does not sync the "bit" definitions, as that is
    actually insulated from user-space via the sysfs text string. (I could
    do it, but it does introduce a potential binary-incompatibility).
    
    Signed-off-by: James Smart <James.Smart@emulex.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 457620b47a5398e779584fc3c470683fbb3d1c8d
Author: Andrew Vasquez <andrew.vasquez@qlogic.com>
Date:   Mon Mar 12 10:41:31 2007 -0700

    [SCSI] qla2xxx: Update version number to 8.01.07-k6.
    
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 27d940352840bb7a55c351b5b5d6e042fcaf8d47
Author: Andrew Vasquez <andrew.vasquez@qlogic.com>
Date:   Mon Mar 12 10:41:30 2007 -0700

    [SCSI] qla2xxx: Allow the extended-error-logging flag to be dynamic.
    
    The module parameter, ql2xextended_error_logging, can now be
    set dynamically by writing to the following sysfs entry:
    
    	/sys/module/qla2xxx/parameters/ql2xextended_error_logging
    
    This alleviates the need for the driver to be unloaded and
    reloaded in order to enable logging.
    
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit fecf97882a8f1e9b52627c30322232c18060aa2c
Author: Andrew Vasquez <andrew.vasquez@qlogic.com>
Date:   Mon Mar 12 10:41:29 2007 -0700

    [SCSI] qla2xxx: Drop acquisition of hardware_lock during flash manipulations.
    
    There's no need given, I/O has been quiesced, RISC
    interrupts have been disabled, and finally the RISC has been
    paused.  Flash manipulation on ISP21xx, ISP22xx, and ISP23xx
    parts requires the RISC to go through a full reset to
    recover.
    
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 40a2e34a94c336b716f631b2952d233e1ba76e3c
Author: Andrew Vasquez <andrew.vasquez@qlogic.com>
Date:   Mon Mar 12 10:41:28 2007 -0700

    [SCSI] qla2xxx: Add cond_resched() calls during HBA flash manipulation.
    
    We're observing soft lockups during HBA FLASH retrieval and
    update.  Add cond_resched() each time around the tight-loops
    during flash read()s/write()s.
    
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit ed6770863945e6695f403c7b951395dab298c392
Author: Andrew Vasquez <andrew.vasquez@qlogic.com>
Date:   Mon Mar 12 10:41:27 2007 -0700

    [SCSI] qla2xxx: Add scan_[start|finish]() callbacks for ISP24xx HBAs.
    
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit b889d531b635da66ce2704a47febfed68173d9db
Author: Malahal Naineni <malahal@us.ibm.com>
Date:   Mon Mar 12 10:41:26 2007 -0700

    [SCSI] qla2xxx: fix RSCN handling on big-endian systems
    
    qla2xxx driver fails to handle RSCN events affecting area or domain due
    to an endian issue on big endian systems.  This fixes the port_id_t
    structure on big endian systems.
    
    Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
    Acked-by: Seokmann Ju <seokmann.ju@qlogic.com>
    Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 840c2835a1c867281d27158378a9d34f593a7664
Author: James Bottomley <James.Bottomley@steeleye.com>
Date:   Sun Mar 11 14:16:43 2007 -0500

    [SCSI] make scsi_wait_scan always modular
    
    Currently scsi_wait_scan is only built modular if SCSI is modular.
    However, it's perfectly possible for a built in SCSI still to have
    modular drivers and thus need scsi_wait_scan as a module.  Therefore,
    scsi_wait_scan should always be built as a module (unless the kernel
    doesn't support modules).
    
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 1544d67738c864245b8a061fb72093daeea8d4f1
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Tue Feb 20 11:17:03 2007 -0800

    [SCSI] fusion: kernel-doc warning fixes
    
    Fix kernel-doc warnings in fusion driver code.
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Acked-by: "Moore, Eric" <Eric.Moore@lsi.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 4b560fde06aeb342f3ff0bce924627ab722d251a
Author: Andrew Morton <akpm@linux-foundation.org>
Date:   Mon Mar 19 09:08:21 2007 +1100

    drm: fix warning in drm_fops.c
    
    drivers/char/drm/drm_fops.c: In function 'drm_setup':
    drivers/char/drm/drm_fops.c:60: warning: comparison of distinct pointer types lacks a cast
    
    Unfortunately PAGE_SIZE has different types on different architectures.
    
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 99da6d861c659bb1a961b70f50fad268b9ed5a5f
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Mon Mar 19 08:52:17 2007 +1100

    drm: allow for more generic drm ioctls
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit e85f008d016d2de59ee5b01dba18ea3dea41545b
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Thu Mar 8 11:19:39 2007 -0500

    [POWERPC] Correct apparently misspelled "XMON" preprocessor symbol.
    
    Correct the apparent misspelling of "XMON" to "CONFIG_XMON".
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7850ad5c39a40ae14ab37e030357e2ae8252af2b
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Mar 14 16:32:17 2007 +1100

    [POWERPC] Add documentation for the zImage's gunzip convenience functions
    
    This patch adds documenting comments to the gunzip convenience
    functions added in commit ad9d2716cfc1cda5a7e0d7bc0db45e3af8a4adbb.
    It also removes a stray newline, and an unused global variable.
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0e0293c898c424c52e5d4e7f6923a203d06b9c4b
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Mar 14 11:50:40 2007 +1100

    [POWERPC] Update documentation for flat device tree format v17
    
    This patch updates booting-without-of.txt to describe version 17 of
    the flattened device tree format.  Version 17 is a small, backwards
    compatible change from version 16, adding an extra field giving the
    size of the device tree's structure block.  At this time, the kernel
    has no use for the extra information, however its presence can make
    life easier for bootloaders or other software manipulating the tree.
    
    In addition this patch adds information on the size_dt_strings field
    of the device tree header, present since version 3 of the flattened
    tree format, but omitted from the documentation.  It also makes
    changes to consistently refer to versions 16 and 17 as versions 16 and
    17 in decimal, rather than version 0x10 which was occasionally used
    for version 16 previously.
    
    Finally, we also add the new field to the definition of the device
    tree header structure in prom.h
    
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
    Acked-by: Jon Loeliger <jdl@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a782a9e3a12bcea4916117b0832016c24fffeb85
Author: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
Date:   Thu Mar 15 23:20:44 2007 +0100

    [POWERPC] 8xx parenthesis balance
    
    This balances parenthesis in powerpc 8xx header files.
    
    Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6bccf755ff53241d46c01c229b3c2452b9029ec4
Author: Joachim Fenkes <fenkes@de.ibm.com>
Date:   Fri Mar 9 19:00:32 2007 +0100

    [POWERPC] ibmebus: dynamic addition/removal of adapters, some code cleanup
    
    This adds two sysfs attributes to /sys/bus/ibmebus which can be used to
    notify the ebus driver of added / removed ebus devices in the OF device
    tree.
    
    Echoing the device's location code (as found in the OFDT "ibm,loc-code"
    property) into the "probe" attribute will notify ebus of addition of the
    device and cause the appropriate device driver's probe function to be called
    on the device.
    
    Likewise, echoing the location code into the "remove" attribute will cause
    the device to be removed from the system.
    
    The writes will block until the respective operation has finished and return
    an error code if the operation failed.
    
    In addition, two minor tidbits are fixed:
    
    - The fake root device used to provide a common parent for all ebus devices
      is now based on device instead of of_device - it had no associated devtree
      node. This saves several checks throughout the ebus driver.
    
    - The sysfs attributes are now generated automagically by device_register()
      instead of by the ibmebus code, which saves a few compiler warnings about
      unused return codes.
    
    Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a83088003cd53f3cd8d550ab5d7778866568d204
Author: Joachim Fenkes <fenkes@de.ibm.com>
Date:   Fri Mar 9 18:56:46 2007 +0100

    [POWERPC] ibmebus: whitespace fixes
    
    This fixes a lot of whitespace in ibmebus.[ch]
    
    Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 556b09c8189b9b3f5626ca73196009e397503f85
Author: Mark A. Greer <mgreer@mvista.com>
Date:   Wed Oct 25 16:36:49 2006 -0700

    [POWERPC] 32-bit early_init() should zero from __bss_start to __bss_stop only
    
    Currently, early_init() in setup_32.c zeroes from '_bss_start' to '_end'.
    It should only zero from '__bss_start' to '__bss_stop'.  This patch does that.
    
    Signed-off-by: Mark A. Greer <mgreer@mvista.com>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6e782584e0713ea89da151333e7fe754c8f40324
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Fri Mar 16 00:59:42 2007 -0400

    Input: i8042 - add HP Pavilion DV4017EA to the MUX blacklist
    
    This should get rid of "atkbd.c: Suprious NAK on isa0060/serio0"
    messages caused by broken MUX implementation. The box does not
    have external PS/2 ports so disabling MUX mode is safe.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 9575499dfebc0f0fbbf122223f02e9e92630661d
Author: Helge Deller <deller@gmx.de>
Date:   Fri Mar 16 00:59:29 2007 -0400

    Input: HIL - fix rwlock recursion bug
    
    The following bug happens when insmoding hp_sdc_mlc.ko:
    
        HP SDC MLC: Registering the System Domain Controller's HIL MLC.
        BUG: rwlock recursion on CPU#0, hotplug/1814, 00854734
        Backtrace:
         [<10267560>] _raw_write_lock+0x50/0x88
         [<10104008>] _write_lock_irqsave+0x14/0x24
         [<008537d4>] hp_sdc_mlc_out+0x38/0x25c [hp_sdc_mlc]
         [<0084ebd8>] hilse_donode+0x308/0x470 [hil_mlc]
         [<0084ed80>] hil_mlcs_process+0x40/0x6c [hil_mlc]
         [<10130f80>] tasklet_action+0x78/0xb8
         [<10130cec>] __do_softirq+0x60/0xcc
         [<1010428c>] __lock_text_end+0x38/0x48
         [<10108348>] do_cpu_irq_mask+0xf0/0x11c
         [<1010b068>] intr_return+0x0/0xc
    
    Signed-off-by: Helge Deller <deller@gmx.de>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 5a90e5bca96696f1daa0bb0a9db299eb40241ada
Author: Rodolfo Giometti <giometti@enneenne.com>
Date:   Fri Mar 16 00:58:52 2007 -0400

    Input: add support for PXA27x keyboard controller
    
    Signed-off-by: Rodolfo Giometti <giometti@enneenne.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 867d2682e92a3999e3862f1679cfcb549142d776
Author: Peter Osterlund <petero2@telia.com>
Date:   Fri Mar 16 00:58:37 2007 -0400

    Input: sermouse - improve protocol error recovery
    
    When using MS protocol the driver should wait for a byte with
    bit 6 set before assuming that it sees beginning of a data packet.
    This should allow driver better cope with lost bytes and prevent
    spurious left/right button events when serial communication is
    disturbed by a CPU-hungry real-time process.
    
    Also fix some formatting.
    
    Signed-off-by: Peter Osterlund <petero2@telia.com>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 54f9e36cb83e7da17dc0596d365fe019a25c226f
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Fri Mar 16 00:57:25 2007 -0400

    Input: simplify input_free_device()
    
    Now that sysfs attributes that were marked for deletion can't access
    their devices we do not need to set name, phys and uniq to NULL.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 86a1b63349bb2cbed6c2cbf8f9e9de9259a404df
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:59 2007 -0600

    [POWERPC] bootwrapper: Make ft_create_node() pay attention to the parent parameter.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8941c0c495e8765206ec1017b1e069ce41bf6e8f
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:58 2007 -0600

    [POWERPC] bootwrapper: Add ft_find_node_by_prop_value().
    
    ft_find_node_by_prop_value() finds nodes with the specified
    property/value pair.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit a9ec7669fc07f80f6e39807f1ac319764a304319
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:56 2007 -0600

    [POWERPC] bootwrapper: Make ft_get_parent() return a phandle, and NULL if already top-level.
    
    Most of ft_get_parent() is factored out into __ft_get_parent(), which
    deals only in internal node pointers.  The ft_get_parent() wrapper
    handles phandle conversion in both directions (previously,
    ft_get_parent() did not convert its return value).
    
    It also now returns NULL as the parent of the toplevel node, rather than
    just returning the toplevel node again (which made it rather useless in
    loops).
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c350038b2bdabb07611dcc8116b55f917ada09fa
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:54 2007 -0600

    [POWERPC] bootwrapper: Refactor ft_get_prop() into internal and external functions.
    
    The property searching part of ft_get_prop is factored out into an
    internal __ft_get_prop() which does not deal with phandles and does not
    copy the property data.  ft_get_prop() is then a wrapper that does the
    phandle translation and copying.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit fc583411617bf8a466c68350697a806704e88fc3
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:53 2007 -0600

    [POWERPC] bootwrapper: Add ft_find_device_rel().
    
    Add a function to look up a relative, rather than absolute, path name.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c8e4c77277ca5db0c4ddbfb4bc628b8abad585b0
Author: Marvin Raaijmakers <marvin_raaijmakers@linux-box.nl>
Date:   Wed Mar 14 22:50:42 2007 -0400

    Input: add getkeycode and setkeycode methods
    
    Allow drivers to implement their own get and set keycode methods. This
    will allow drivers to change their keymaps without allocating huge
    tables covering entire range of possible scancodes.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 5adeef52ccc0229e06a6e0b2fefe442d8779f025
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:51 2007 -0600

    [POWERPC] bootwrapper: Use map_string() instead of lookup_string() in ft_prop().
    
    When adding a property, the property name should be added to the string
    table if it doesn't already exist.  map_string() does that;
    lookup_string() will fail instead.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9dd2c31ab89a12571db89648bcc9992cf71b63d8
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:48 2007 -0600

    [POWERPC] bootwrapper: Modify *pp, not *p, in ft_shuffle().
    
    Move the caller's pointer back to match the change in the region's start,
    rather than alter a byte of the device tree's content.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 78438b36011d8ef7d28ef63a30b11801be1eea71
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:47 2007 -0600

    [POWERPC] bootwrapper: Preserve the pp pointer in ft_make_space() when calling ft_reorder().
    
    The ft_reorder() function may change the start of the region of interest,
    so the pointer provided by the caller into that region must be fixed up
    to still point to the same datum.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit c8aa72633e65c5c215b0cdd9970642e2a4f9a9a3
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:45 2007 -0600

    [POWERPC] bootwrapper: Make ft_get_phandle() accept and return NULL.
    
    Currently, if ft_get_phandle() is passed NULL it will allocate an entry
    for it and return a non-NULL phandle.  This patch makes it simply pass
    the NULL through.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1c53a496ba6132a37f052aa907e23445b3fe928c
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:44 2007 -0600

    [POWERPC] bootwrapper: Rename ft_node_add() to ft_get_phandle().
    
    This name better reflects what the function does, which is to
    look up the phandle for an internal node pointer, and add it to the
    internal pointer to phandle table if not found.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 7c71c04625483c1da91846fd6746057d24ad6be8
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:42 2007 -0600

    [POWERPC] bootwrapper: Add ft_root_node().
    
    Clean up some of the open-coded data structure references by providing a
    function to return a pointer to the tree's root node.  This is only used
    in high-level functions trying to access the root of the tree, not in
    low-level code that is actually manipulating the data structure.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ce3edb30ec2b6350c4258e3d52e73b410e2ea12d
Author: Scott Wood <scottwood@freescale.com>
Date:   Mon Mar 12 14:41:38 2007 -0600

    [POWERPC] bootwrapper: Add stddef.h to ops.h
    
    ops.h references NULL, so include stddef.h, so files including ops.h
    don't have to.
    
    Signed-off-by: Scott Wood <scottwood@freescale.com>
    Acked-by: Mark A. Greer <mgreer@mvista.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cd197ffcf10bcc1a260efe5c09a3188fd9228c83
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Mar 5 14:24:52 2007 +1100

    [POWERPC] zImage: Cleanup and improve zImage entry point
    
    This patch re-organises the way the zImage wrapper code is entered, to
    allow more flexibility on platforms with unusual entry conditions.
    After this patch, a platform .o file has two options:
    
    1) It can define a _zimage_start, in which case the platform code gets
       control from the very beginning of execution.  In this case the
       platform code is responsible for relocating the zImage if necessary,
       clearing the BSS, performing any platform specific initialization, and
       finally calling start() to load and enter the kernel.
    
    2) It can define platform_init().  In this case the generic crt0.S
       handles initial entry, and calls platform_init() before calling
       start().  The signature of platform_init() is changed, however, to
       take up to 5 parameters (in r3..r7) as they come from the platform's
       initial loader, instead of a fixed set of parameters based on OF's
       usage.
    
       When using the generic crt0.S, the platform .o can optionally
       supply a custom stack to use, using the BSS_STACK() macro.  If this
       is not supplied, the crt0.S will assume that the loader has
       supplied a usable stack.
    
    In either case, the platform code communicates information to the
    generic code (specifically, a PROM pointer for OF systems, and/or an
    initrd image address supplied by the bootloader) via a global
    structure "loader_info".
    
    In addition the wrapper script is rearranged to ensure that the
    platform .o is always linked first.  This means that platforms where
    the zImage entry point is at a fixed address or offset, rather than
    being encoded in the binary header can be supported using option (1).
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 79c8541924a220964f9f2cbed31eaa9fdb042eab
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Mar 5 14:24:52 2007 +1100

    [POWERPC] zImage: Cleanup and improve prep_kernel()
    
    This patch rewrites prep_kernel() in the zImage wrapper code to be
    clearer and more flexible.  Notable changes:
    
    	- Handling of the initrd image from prep_kernel() has moved
    into a new prep_initrd() function.
    	- The address of the initrd image is now added as device tree
    properties, as the kernel expects.
    	- We only copy a packaged initrd image to a new location if it
    is in danger of being clobbered when the kernel moves to its final
    location, instead of always.
    	- By default we decompress the kernel directly to address 0,
    instead of requiring it to relocate itself.  Platforms (such as OF)
    where doing this could clobber still-live firmware data structures can
    override the vmlinux_alloc hook to provide an alternate place to
    decompress the kernel.
    	- We no longer pass lots of information between functions in
    global variables.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit ad9d2716cfc1cda5a7e0d7bc0db45e3af8a4adbb
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Mon Mar 5 14:24:52 2007 +1100

    [POWERPC] zImage: Add more flexible gunzip convenience functions
    
    At present, arch/powerpc/boot/main.c includes a gunzip() function
    which is a convenient wrapper around zlib.  However, it doesn't
    conveniently allow decompressing part of an image to one location,
    then the remainder to a different address.
    
    This patch adds a new set of more flexible convenience wrappers around
    zlib, moving them to their own file, gunzip_util.c, in the process.
    These wrappers allow decompressing sections of the compressed image to
    different locations.  In addition, they transparently handle
    uncompressed data, avoiding special case code to handle uncompressed
    vmlinux images.
    
    The patch also converts main.c to use the new wrappers, using the new
    flexibility to avoid decompressing the vmlinux's ELF header twice as
    we did previously.  That in turn means we avoid extending our
    allocations for the vmlinux to allow space for the extra copy of the
    ELF header.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8ec555c2c4c6c33759a1dbb13fa8f3b14fc77e10
Author: Corentin Chary <corentincj@iksaif.net>
Date:   Sun Mar 11 10:28:03 2007 +0100

    asus-laptop: version bump
    
    Version and copyright bump.
    
    Signed-off-by: Corentin Chary <corentincj@iksaif.net>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 185e5af98b1e09b1e0f859332243223776b2ad57
Author: Corentin Chary <corentincj@iksaif.net>
Date:   Sun Mar 11 10:27:33 2007 +0100

    asus-laptop: add wapf param
    
    Add the "wapf" param. This param allows to define the behavior
    of  the Fn F2 key (wlan switch).
    
    Signed-off-by: Corentin Chary <corentincj@iksaif.net>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit fdd8d08084663242b42e27f7d71739f3f9009286
Author: Corentin Chary <corentincj@iksaif.net>
Date:   Sun Mar 11 10:26:48 2007 +0100

    asus-laptop: add GLED
    
    Add support for "gaming" led.
    
    Signed-off-by: Corentin Chary <corentincj@iksaif.net>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 935ffeeca84fe5d48d0cc9f35c58db42b384229f
Author: Corentin Chary <corentincj@iksaif.net>
Date:   Sun Mar 11 10:26:12 2007 +0100

    asus-laptop: clean write_status
    
    Clean the write_status function, and implement special case with
    a switch inside write_status. It also make sure bt and wl status
    are right when booting with the hardware switch off.
    
    Signed-off-by: Corentin Chary <corentincj@iksaif.net>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 9a8168500674b1062afe438d34d0c8216d38dc31
Author: Corentin Chary <corentincj@iksaif.net>
Date:   Sun Mar 11 10:25:38 2007 +0100

    asus-laptop: use acpi_evaluate_integer instead of read_acpi_int
    
    Use acpi_evaluate_integer() instead of read_acpi_int()
    
    Signed-off-by: Corentin Chary <corentincj@iksaif.net>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 56937f7b78d3e495a9f557775f3c3ea1d50ca7b3
Author: James Bottomley <jejb@mulgrave.il.steeleye.com>
Date:   Sun Mar 11 12:25:33 2007 -0500

    [SCSI] sd: typo fix: sdkp_printk should be sd_printk
    
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 38891cb6b0de3f5986e6a7688c5ae17c18b000a9
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sat Mar 10 17:16:26 2007 -0500

    [SCSI] pci2000: Delete unused header file.
    
    This driver was removed a while ago by commit
    
    099175c94a221fa2723b7273883c98cd32efe900
    
    However, it seems that pci2000.h wasn't properly eliminated, so remove
    it now.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e8f8248cbadcd8cb1b737fc57a01bccca4fb7aec
Author: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Date:   Sat Mar 3 09:55:55 2007 +0900

    [SCSI] tgt: fix scsi command leak
    
    The failure to map user-space pages leads to scsi command leak. It can
    happens mostly because of user-space daemon bugs (or OOM). This patch
    makes tgt just notify a LLD of the failure with sense when
    blk_rq_map_user() fails.
    
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit bc7e380a6a4c94f79a49c36bdb28062a750b3c2b
Author: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Date:   Sat Mar 3 09:55:54 2007 +0900

    [SCSI] tgt: fix sesnse buffer problems
    
    This patch simplify the way to notify LLDs of the command completion
    and addresses the following sense buffer problems:
    
    - can't handle both data and sense.
    - forces user-space to use aligned sense buffer
    
    tgt copies sense_data from userspace to cmnd->sense_buffer (if
    necessary), maps user-space pages (if necessary) and then calls
    host->transfer_response (host->transfer_data is removed).
    
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 181011e04a2a32f8d5df212254239ac9a3c8ab5e
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Sat Mar 3 09:55:54 2007 +0900

    [SCSI] tgt: rm bio hacks in scsi tgt
    
    scsi tgt breaks up a command into multple scatterlists
    if we cannot fit all the data in one. This was because
    the block rq helpers did not support large requests and
    because we can get a command of any old size so it is
    hard to preallocate pages for scatterlist large enough
    (we cannot really preallocate pages with the bio map
    user path). In 2.6.20, we added large request support to
    the block layer helper, blk_rq_map_user. And at LSF,
    we talked about increasing SCSI_MAX_PHYS_SEGMENTS for
    scsi tgt if we want to support really really :) large
    (greater than 256 * PAGE_SIZE in the worst mapping case)
    requests.
    
    The only target currently implemented does not even support
    the multiple scatterlists stuff and only supports smaller
    requests, so this patch just coverts scsi tgt to use
    blk_rq_map_user.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 0f238418b6d41cdfc85f2f399848429ff6fbfbd0
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:21 2007 -0600

    [SCSI] iscsi_tcp: print useful error message when iscsi crc23c allocation fails
    
    People do not read the README and seem to like to
    unselect the crc32c module even though iscsi_tcp selects
    it for them. This patch spits a error that tells the user
    that they really do need the module. Hopefully, we will
    get fewer people asking about this now.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 8231f0eddbe425cc3b54f2d723bb03531925272e
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:20 2007 -0600

    [SCSI] iscsi_tcp: increase max_sectors
    
    For a while now, the block layer has seperated max sectors
    and max hw sectors. Software iscsi has no limit so this patch
    increases max hw sectors, so we can support large pass through
    commands.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 8eb00539d92187ade7e4cc24a1a36ab248ee8639
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:19 2007 -0600

    [SCSI] libiscsi: use get_unaligned
    
    Dave Miller meantioned that the data buffer in a past
    sense fixup patch was not gauranteed to be aligned
    properly for ia64. This patch has libiscsi use get_unalinged
    to make sure. There are a couple more places in the
    digest handling we may need to do this, but we are in the middle
    of fixing that code for big endien systems so just the sense
    access is fixed here.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 41be14442213b6dbeea3cba2ed18a2923666278c
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:18 2007 -0600

    [SCSI] iscsi transport: use atomic for session_nr allocations
    
    qla4xxx and iscsi_tcp or iser could be creating
    sessions at the same time, so make session_nr id
    allocation atomic.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit bf32ed33e97ac7905fa5a2bf49a634c2eaf62457
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:17 2007 -0600

    [SCSI] iscsi: rename DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH
    
    This patch renames DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH to avoid
    confusion with the drivers default values (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH
    is the iscsi RFC specific default).
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 05db888a46866fd4eae643792c162e1a5c1a8612
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:16 2007 -0600

    [SCSI] libiscsi: clear mtask
    
    Consolidate the mtask clearing code.
    
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 779ea1207b6a43943faa44f41be7311263315604
Author: Mike Christie <michaelc@cs.wisc.edu>
Date:   Wed Feb 28 17:32:15 2007 -0600

    [SCSI] libiscsi: flush work before freeing connection
    
    It's possible that we call iscsi_xmitworker after iscsi_conn_release
    which causes a oops. This patch flushes the workqueue.
    
    Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
    Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 62d42a62770dd66da2d3df693e70f4e5fae1716a
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Wed Feb 28 12:37:06 2007 -0500

    [SCSI] constants.c: Update ASC list and make it const
    
    Add missing additional sense code and provide pointer to upstream
    reference (from Doug Gilbert).
    
    Add missing const (from Michael Tokarev).
    
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit fa0d34be06213e02a4df29a9d34ca915728a8434
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Tue Feb 27 22:41:19 2007 -0500

    [SCSI] sd: convert logging to new printk helpers
    
    Convert the sd.c SCSI logging calls to scmd_printk()/sd_printk()
    instead of plain printk().
    
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit e73aec8247032ee730b5f38edf48922c4f72522e
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Tue Feb 27 22:40:55 2007 -0500

    [SCSI] sd: make printing use a common prefix
    
    Make SCSI disk printing more consistent:
    
     - Define sd_printk(), sd_print_sense_hdr() and sd_print_result()
    
     - Move relevant header bits into sd.h
    
     - Remove all the legacy disk_name passing and use scsi_disk pointers
       where possible
    
     - Switch printk() lines to the new sd_ functions so that output is
       consistent
    
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit a4d04a4cd9881e89fdc62107b6b57053438f2b30
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Tue Feb 27 22:40:27 2007 -0500

    [SCSI] Make error printing more verbose
    
    This patch enhances SCSI error printing by:
    
     - Making use of scsi_print_result() in the completion functions.
    
     - Having scmd_printk() output the disk name (when applicable).
    
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 684b7fe976554d12e6266d7280c87a0f3feff02e
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Tue Feb 27 22:39:44 2007 -0500

    [SCSI] constants.c: cleanup, verbose result printing
    
    Clean up constants.c and make result printing more user friendly:
    
     - Refactor the command and sense functions so that the actual
       formatting can be called from the various helper functions with the
       correct prefix.
    
     - Replace scsi_print_hostbyte() and scsi_print_driverbyte() with
       scsi_print_result() which is verbose when CONFIG_SCSI_CONSTANTS is
       on.
    
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 862794fa3fd4c8a44ee22582418736c93e0d3c3a
Author: Heiko Carstens <heiko.carstens@de.ibm.com>
Date:   Wed Feb 21 09:28:00 2007 +0100

    [SCSI] zfcp: fix likely/unlikely usage
    
    zfcp_fsf_protstatus_eval() takes always the 'wrong' branch.
    
    Likely Profiling Results
     ---------------------------------------------------------
    [+- ] Type | # True | # False | Function:Filename@Line
    +unlikely  |   11042|        0  zfcp_fsf_protstatus_eval()
    
    Acked-by: Swen Schillig <swen@vnet.ibm.com>
    Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
    Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

commit 6244270ef62203e057191bf85489e2ff91cc0e60
Author: Jay Estabrook <Jay.Estabrook@hp.com>
Date:   Sun Mar 11 11:46:27 2007 +1100

    drm: fix alpha domain handling
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 74be8e3b3707956f8f232313de9fad896d5489ac
Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Date:   Sun Mar 11 11:45:24 2007 +1100

    via: fix CX700 pci id
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 0bead7cdc94b4897f3d92db6170737a2da527134
Author: Adrian Bunk <bunk@stusta.de>
Date:   Sun Mar 11 11:41:16 2007 +1100

    drm: make drm_io_prot static.
    
    This patch makes the needlessly global drm_io_prot() static.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 5379397182a7b5fa1c68ceaefe311ce4c1d04b2a
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sun Mar 11 11:39:31 2007 +1100

    drm: remove via_mm.h
    
    Delete apparently unused header file drivers/char/drm/via_mm.h.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit c1185ccdfb797df82fa84b581eea128041bd63b0
Author: Dave Airlie <airlied@linux.ie>
Date:   Sun Feb 18 18:23:11 2007 +1100

    drm: add missing NULL assignment
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 80b2c386f3d8c3367533a8600b599f8686c9d386
Author: Michel DÃ¤nzer <michel@tungstengraphics.com>
Date:   Sun Feb 18 18:03:21 2007 +1100

    drm/radeon: Fix u32 overflows when determining AGP base address in card space.
    
    The overflows could lead to the AGP aperture overlapping the framebuffer are    in the card's address space when the latter is located at the very end of th    32 bit address space, which would result in a freeze on X server startup,
    probably because the card read commands from the framebuffer instead of from    AGP.
    
    See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=392915 .
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit cd839d0048c3cb332cb0cd7d3de3431f8e1d3c7a
Author: Dave Airlie <airlied@linux.ie>
Date:   Sun Feb 18 17:14:09 2007 +1100

    drm: port over use_vmalloc code from git hashtab
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 11d9c2fd0ae74647ea2b52f9bdfa7a920b48d1f1
Author: Dave Airlie <airlied@linux.ie>
Date:   Sun Feb 18 17:13:39 2007 +1100

    drm: fix crash with fops lock and fixup sarea/page size locking
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 54ba2f76e281286cf4b2860ed8354602eab4c1ef
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Feb 10 12:07:47 2007 +1100

    drm: bring bufs code from git tree.
    
    This checks the AGP mappings are in a valid place and also fixes the size
    check in the vm..
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 5cc7f9abec8391e43b0a052c8880509668e24b35
Author: Dave Airlie <airlied@linux.ie>
Date:   Sat Feb 10 11:53:13 2007 +1100

    drm: move protection stuff into separate function
    
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 8311d570bcb3faea68941ebd5e240eb2e96d65a0
Author: Ahmed S. Darwish <darwish.07@gmail.com>
Date:   Fri Feb 9 10:30:10 2007 +1100

    drm: Use ARRAY_SIZE macro when appropriate
    
    Use ARRAY_SIZE macro already defined in kernel.h
    
    Signed-off-by: Ahmed S. Darwish <darwish.07@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit f54d1e40b2732cd882646de3c860d24a6920cbc2
Author: Randy Dunlap <randy.dunlap@oracle.com>
Date:   Fri Feb 9 10:28:21 2007 +1100

    drm: update README.drm (bugzilla #7933)
    
    Update URLs in drivers/char/drm/README.drm, to take care of kernel bugzilla
    
    Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 41ed5de9714f3690642d50c44973308476a7d334
Author: Adrian Bunk <bunk@stusta.de>
Date:   Fri Feb 9 10:25:22 2007 +1100

    drm: remove unused exports
    
    This patch removes two unused exports.
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dave Airlie <airlied@linux.ie>

commit 3a6effe81fa0bd2fb9c6c5ecde665492536733e3
Author: Robert P. J. Day <rpjday@mindspring.com>
Date:   Sat Mar 10 03:57:25 2007 -0500

    [JFFS2] Remove superfluous source file fs/jffs2/comprtest.c
    
      Delete the obsolete source file fs/jffs2/comprtest.c.
    
    Signed-off-by: Robert P. J. Day <rpjday@mindspring.com>
    Signed-off-by: David Woodhouse <dwmw2@infradead.org>

commit 55e3d9224b60df0fd2dc36bff9b538ce40fd9586
Author: Andres Salomon <dilinger@debian.org>
Date:   Sat Mar 10 01:39:54 2007 -0500

    Input: psmouse - allow disabing certain protocol extensions
    
    Allow ALPS, LOGIPS2PP, LIFEBOOK, TRACKPOINT and TOUCHKIT protocol
    extensions of psmouse to be disabled during compilation. This will
    allow users save some memory when they are sure that they will only
    use a certain type of mice.
    
    Signed-off-by: Andres Salomon <dilinger@debian.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 9fd9f8e8bdcfc9aa309dae5bccc55d02804337d0
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Block queries until EC is fully initialized
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 01f2246269639f6aa93086719a8dbec26cb68e98
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Cleanup of EC initialization
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d033879c9838b960014e861d0eb3bdf11d3b9d9d
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: first_ec is better to be acpi_ec than acpi_device.
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit d66d969df88c742494736ed06eeaf3229d3a7259
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Rename ec_ecdt to more informative boot_ec
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit c0900c3512dc8fd0b37f8fbcebc7853ed9efff10
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Clean ECDT and namespace parsing.
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit e8284321048aac7be307b3ec5e0631f5c514935a
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Put install handlers into separate function.
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 3d02b90be2c7bc7ffbc5e502a135c13838d23ef4
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Remove casts to/from void* from ec.c
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit c45aac43fec2d6ca8d0be8408f94e8176c8110ef
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: enable burst functionality in EC.
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 33c7a0738c5f753a7d94fd3b2ec7d84e79a141a8
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: "Fake ECDT" workaround is not needed any longer.
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit 33d20b6100d05a0b14883e7dc8ab41e4531fcf59
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:28:00 2007 +0300

    ACPI: EC: Make EC to initialize first in ACPI
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit a5f8dee2d367e69fd57f5ea107072bb72eb15327
Author: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Date:   Wed Mar 7 22:27:59 2007 +0300

    ACPI: EC: Don't use Global Lock if not asked to do so
    
    Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
    Signed-off-by: Len Brown <len.brown@intel.com>

commit ac122bb64b0d51f0512185d3522a75f3f3a80bc9
Author: Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
Date:   Mon Feb 19 15:19:31 2007 -0800

    ACPI: dock: add access to ACPI docking station UID
    
    It is useful to know whether your laptop is docked or not,
    but it is even more useful to know which docking station it's
    docked to. Attached patch adds "uid" file to sysfs.
    Tested on Dell Latitude D600 with D/Dock.
    Patch is against official 2.6.20 release.
    
    Signed-off-by: Len Brown <len.brown@intel.com>

commit ba863a0016a33637acc7888698a5d75096fcec05
Author: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Date:   Fri Mar 9 10:27:31 2007 -0600

    JFS: document uid, gid, and umask mount options in jfs.txt
    
    Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>

commit cfbff8a3802542c4d8b2290c49b1a59128c4a380
Author: Jake Moilanen <moilanen@austin.ibm.com>
Date:   Tue Oct 3 14:29:34 2006 -0500

    [POWERPC] 750CL cputable entry
    
    750CL cputable entry from Steve Winiecki.
    
    Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 6406063899cc6f558df1e751d46de2e3c45c2189
Author: Zang Roy-r61911 <tie-fei.zang@freescale.com>
Date:   Tue Mar 6 14:10:36 2007 +0800

    [POWERPC] Remove fixed setting of ROOT_DEV for 7448HPC2 platforms
    
    Remove fixed setting of ROOT_DEV for 7448HPC2 platforms.
    Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 36241ce695f16193d0f76ea010f212119da37071
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 17:07:38 2007 +1100

    [POWERPC] Make find_and_init_pbs() a void function
    
    It always returned 0 and noone checked.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 0a7c7efccc08f00ae6fc8e1f2de0ee61f07357fd
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 17:05:34 2007 +1100

    [POWERPC] Allow xmon to build without CONFIG_DEBUG_BUGVERBOSE
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit bed59275810a55500e885cbdc5c2a0507f13c00e
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 17:04:44 2007 +1100

    [POWERPC] Allow pSeries to build without CONFIG_PCI
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit be9e95b17e150c7b6933cb2f1e1c46a501976080
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 17:03:48 2007 +1100

    [POWERPC] Make iSeries build without CONFIG_PCI
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 57190708f1f52d732d94fa21a8e576302d384d33
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 17:02:41 2007 +1100

    [POWERPC] Create and use get_pci_dma_ops()
    
    This allows us to hide pci_dma_ops.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 9874777016e06ad2df420237963e81389776cb6d
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Sun Mar 4 16:58:39 2007 +1100

    [POWERPC] Create and use set_pci_dma_ops
    
    This will allow us to build without PCI easier.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 618d3adc351a24c4c48437c767befb88ca2d199d
Author: Jake Moilanen <moilanen@austin.ibm.com>
Date:   Fri Mar 2 15:49:43 2007 -0600

    [POWERPC] DMA 4GB boundary protection
    
    There are many adapters which can not handle DMAing acrosss any 4 GB
    boundary.  For instance the latest Emulex adapters.
    
    This normally is not an issue as firmware gives us dma-windows under
    4gigs.  However, some of the new System-P boxes have dma-windows above
    4gigs, and this present a problem.
    
    I propose fixing it in the IOMMU allocation instead of making each
    driver protect against it as it is more efficient, and won't require
    changing every driver which has not considered this issue.
    
    This patch checks to see if the mapping spans a 4 gig boundary, and if
    it does, retries the allocation.  It tries the next allocation at the
    start of the crossed 4 gig boundary.
    
    Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 723ec731de880a76a004a304b62bf8d0f96435d8
Author: Dave Jiang <djiang@mvista.com>
Date:   Fri Mar 2 13:36:21 2007 -0700

    [POWERPC] EDAC ECC software scrubber
    
    Implements the per arch atomic_scrub() that EDAC uses for software
    ECC scrubbing.  It reads memory and then writes back the original
    value, allowing the hardware to detect and correct memory errors.
    
    Signed-off-by: Dave Jiang <djiang@mvista.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 27565903e94d548256bf5923653ab2a9668c9b9f
Author: Stuart Yoder <b08248@freescale.com>
Date:   Fri Mar 2 13:42:33 2007 -0600

    [POWERPC] Update interrupt info in booting-without-of.txt
    
    Create a new section descrbing how interrupts are represented
    in the device tree.  Added more detail.  Clarified some things.
    
    Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 500798d48fdcffbbc7f619bd3e6b5b5cea6869d1
Author: Stuart Yoder <b08248@freescale.com>
Date:   Tue Feb 27 10:14:14 2007 -0600

    [POWERPC] Remove unused, undocumented #cpus property from cpus node
    
    The #cpus property is unused and undocumented and is therefore
    being removed.
    
    Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
    Acked-by: David Gibson <david@gibson.dropbear.id.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit fdc0a9be3a63a71c12de86cc97d4cd8cf46239c0
Author: MOKUNO Masakazu <mokuno@sm.sony.co.jp>
Date:   Mon Feb 26 17:21:05 2007 +0900

    [POWERPC] Remove some redundant isync instructions
    
    Remove some redundant isync instructions.
    
    enable_64b_mode() already does an isync, so there is no need to do it again.
    
    Signed-off-by: MOKUNO, Masakazu <mokuno@sm.sony.co.jp>
    Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit dbc11f539df7c9a32424b78afb0314c68d5e7d0b
Author: Olaf Hering <olaf@aepfle.de>
Date:   Sun Feb 25 20:04:18 2007 +0100

    [POWERPC] Include stddef.h in asm-powerpc/current.h to get offsetof
    
    On Tue, Oct 31, Hugh Dickins wrote:
    
    > +++ linux/include/asm-powerpc/current.h	2006-10-30 19:27:05.000000000 +0000
    
    > +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)));
    
    This breaks compile of 2.6.18.8:
    
      CC [M]  drivers/media/video/pwc/pwc-uncompress.o
    In file included from /home/olaf/kernel/linux-2.6.18.8/drivers/media/video/pwc/pwc-uncompress.c:29:
    include2/asm/current.h: In function 'get_current':
    include2/asm/current.h:23: warning: implicit declaration of function 'offsetof'
    include2/asm/current.h:23: error: expected expression before 'struct'
    make[5]: *** [drivers/media/video/pwc/pwc-uncompress.o] Error 1
    
    Signed-off-by: Olaf Hering <olaf@aepfle.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 1c56f838a9d0b25d68363bca133722c5330707b3
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Fri Feb 23 14:41:41 2007 +1100

    [POWERPC] Make ppc64_defconfig without CONFIG_PPC_PSERIES build
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 44d7631bdb16211a492921dbc0d14fce66c20501
Author: Segher Boessenkool <segher@kernel.crashing.org>
Date:   Thu Feb 22 23:52:02 2007 +0100

    [POWERPC] PowerPC: select default image for Linkstation
    
    Signed-off-by: Segher Boessenkool <segher@kernel.crashing.org>
    Acked-by: G. Liakhovetski <g.liakhovetski@gmx.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 8170f524894b17a3f36351fe0e1a3fb6aca733ee
Author: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Date:   Thu Feb 22 16:43:12 2007 +0100

    [POWERPC] ps3: always make sure we're running on a PS3
    
    Add missing checks to PS3 specific drivers ps3av and sys-manager to verify that
    we are actually running on a PS3 (pointed out by Arnd).
    
    Correct existing checks in other subsystems/drivers to return -ENODEV instead
    of zero.
    
    Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
    Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 02567c6cdad4d6254052f25f3b93aa2771f48d25
Author: Stephen Rothwell <sfr@canb.auug.org.au>
Date:   Wed Feb 21 14:53:50 2007 +1100

    [POWERPC] Allocate syscall number for sys_getcpu
    
    I forgot to do this when wiring up the syscall.
    
    Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 30437b3e743f33e9b68f813ca24e547aa9fcf7d7
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Feb 28 14:12:29 2007 +1100

    [POWERPC] Automatically lmb_reserve() initrd
    
    At present, when an initrd is passed to the kernel used flat device
    tree properties, the memory the initrd occupies must also be reserved
    in the flat tree's reserve map, or the kernel may overwrite it.  That
    makes life more complicated than it could be for the bootwrapper.
    
    This patch makes the kernel automatically reserve the initrd's space.
    That in turn requires parsing the initrd parameters earlier than they
    are currently, in early_init_dt_scan_chosen() instead of
    check_for_initrd().
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit eb6de2863750e696201780283e4c9ada19b4728e
Author: David Gibson <david@gibson.dropbear.id.au>
Date:   Wed Feb 28 14:12:29 2007 +1100

    [POWERPC] Allow duplicate lmb_reserve() calls
    
    At present calling lmb_reserve() (and hence lmb_add_region()) twice
    for exactly the same memory region will cause strange behaviour.
    
    This makes life difficult when booting from a flat device tree with
    memory reserve map.  Which regions are automatically reserved by the
    kernel has changed over time, so it's quite possible a newer kernel
    could attempt to auto-reserve a region which is also explicitly listed
    in the device tree's reserve map, leading to trouble.
    
    This patch avoids the problem by making lmb_reserve() ignore a call to
    reserve a previously reserved region.  It also removes a now redundant
    test designed to avoid one specific case of the problem noted above.
    
    At present, this patch deals only with duplicate reservations of an
    identical region.  Attempting to reserve two different, but
    overlapping regions will still cause problems.  I might post another
    patch later dealing with this case, but I'm avoiding it now since it
    is substantially more complicated to deal with, less likely to occur
    and more likely to indicate a genuine bug elsewhere if it does occur.
    
    Signed-off-by: David Gibson <dwg@au1.ibm.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 83ddcf5d364be7b1d8c214d2dd97753e1df589cd
Author: Adrian Bunk <bunk@stusta.de>
Date:   Tue Feb 20 01:08:12 2007 +0100

    [POWERPC] Unexport mac_hid_mouse_emulate_buttons
    
    This patch removes the unused
    EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons).
    
    Signed-off-by: Adrian Bunk <bunk@stusta.de>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit d1bff9ed3c05859fe4a8d00e51f331f5d45350ed
Author: Stuart Yoder <b08248@freescale.com>
Date:   Mon Feb 19 11:25:05 2007 -0600

    [POWERPC] Remove interrupt-controller as a property under /chosen
    
     Remove interrupt-controller as a valid property under /chosen in
     the documentation.  There is a consensus that an
     interrupt-controller property does not belong under /chosen.
     /chosen is specifically for dynamic properties set at runtime.
    
    Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit bb72c481e970dc1b4034ddccbe8302ff39e0d948
Author: Paul Mackerras <paulus@samba.org>
Date:   Mon Feb 19 11:42:42 2007 +1100

    [POWERPC] Harden validate_sp against stack corruption
    
    If something has overflowed or corrupted the stack and causes an oops,
    and we try to print a stack trace, that will call validate_sp, which
    can itself cause an oops if the cpu field of the thread_info struct at
    the bottom of the stack has been corrupted (if CONFIG_IRQSTACKS is
    set).  This makes debugging harder.
    
    To avoid the second oops, this adds a check to make sure that the cpu
    number is reasonable before using it to check whether the stack is on
    the softirq or hardirq stack.
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit 99ddef9bfe714c3273e3fce4c6b6a2a99e7d0bf8
Author: Andrew Morton <akpm@osdl.org>
Date:   Sat Feb 17 18:17:16 2007 -0700

    [POWERPC] Fix compile error in prom.h
    
    In file included from include/asm/pci.h:20,
                     from include/linux/pci.h:751,
                     from arch/powerpc/sysdev/dart_iommu.c:36:
    include/asm/prom.h: In function `of_irq_to_resource':
    include/asm/prom.h:341: warning: implicit declaration of function `irq_of_parse_and_map'
    include/asm/prom.h:345: error: `NO_IRQ' undeclared (first use in this function)
    include/asm/prom.h:345: error: (Each undeclared identifier is reported only once
    include/asm/prom.h:345: error: for each function it appears in.)
    
    Seems that prom.h has always wanted irq.h.
    
    Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
    Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
    Signed-off-by: Andrew Morton <akpm@osdl.org>
    Signed-off-by: Paul Mackerras <paulus@samba.org>

commit cb9def4dff9fe7e3d3114eba4e2d89f52265e22c
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Mar 7 23:20:26 2007 -0500

    Input: let driver core create class device attribute groups
    
    Rely on device core to create attribute groups for input devices
    instead of open-coding it.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 15e03ae811475c2beebfde18717935ee9ce64617
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Mar 7 23:20:17 2007 -0500

    Input: export 'uniq' in /proc/bus/input/devices
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit bc413c9563db6d596e841b2756ed3fccc48de5c0
Author: Eric Piel <eric.piel@tremplin-utc.net>
Date:   Wed Mar 7 01:45:16 2007 -0500

    Input: wistron - add support for TravelMate 610
    
    Add support for Acer TravelMate 610 to wistron_btns. All special keys
    are detected, but the 2 leds are not handled (yet).
    
    Signed-off-by: Eric Piel <eric.piel@tremplin-utc.net>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 243db53bbd8503065b21fd6e8265387048eb569b
Author: Dmitry Torokhov <dtor@insightbb.com>
Date:   Wed Mar 7 01:44:59 2007 -0500

    Input: psmouse - do not force stream mode
    
    Forcing stream mode after reset confuses some devices (reported
    by Andrea Arcangeli) so let's take it out - spec says that after
    reset mouse should already be in stream mode.
    
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit ffd51f46cdf856c0b453d2828a74d552cc15f881
Author: Helge Deller <deller@gmx.de>
Date:   Wed Feb 28 23:51:29 2007 -0500

    Input: HIL - cleanup coding style
    
    Signed-off-by: Helge Deller <deller@gmx.de>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 3acaf540a33199141695f2e2fcfa8829053159bf
Author: Helge Deller <deller@gmx.de>
Date:   Wed Feb 28 23:51:19 2007 -0500

    Input: HIL - various fixes for HIL drivers
    
     - mark some structures const or __read_mostly
     - hilkbd.c: fix uninitialized spinlock in HIL keyboard driver
     - hil_mlc.c: use USEC_PER_SEC instead of 1000000
     - hp_sdc: bugfix for request_irq()/free_irq() parameters, this prevented
               multiple load/unload cycles as module
    
    Signed-off-by: Helge Deller <deller@gmx.de>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 969111e900226a8dbd1f596f34c09eecd20afc7d
Author: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
Date:   Wed Feb 28 23:51:03 2007 -0500

    Input: ads7846 - add support for the ads7843 touchscreen
    
    The ads7843 support has now become almost trivial since the last
    rework.
    
    Signed-off-by: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
    Acked-by: David Brownell <dbrownell@users.sourceforge.net>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 21d31f1f7c8f832324fb55eb4b1397b16258904e
Author: Joern Engel <joern@wh.fh-wedel.de>
Date:   Tue Feb 20 20:22:22 2007 +0100

    [PATCH] [MTD] block2mtd: remove readahead code
    
    Over the years there was a slow trickle of complaints against the readahead
    code.  Most of them concerned performance, Peter Zijlstra stumbled over it
    when working unrelated changes and I believe there was an actual bug report.
    Oh, Andrew Morton also complained about duplicating code from mm/readahead.c.
    
    It is just not worth it.  On flash media like usb sticks, readahead will
    make things go slow - very slow.  On spinning disks, readahead may be a
    win, but this is definitely not the place to add it.
    
    Signed-off-by: JÃ¶rn Engel <joern@lazybastard.org>

commit 8870530a4053add56a2c0eb90a3669facb9f7117
Author: Joern Engel <joern@wh.fh-wedel.de>
Date:   Tue Feb 20 20:21:41 2007 +0100

    [PATCH] [MTD] block2mtd: remove warning
    
    drivers/mtd/devices/block2mtd.c:311:9: warning: symbol 'dev' shadows an earlier one
    drivers/mtd/devices/block2mtd.c:294:23: originally declared here
    
    Signed-off-by: JÃ¶rn Engel <joern@lazybastard.org>

commit 0ffb74ccc06a112042adfaf8229684b78202bcae
Author: Joern Engel <joern@wh.fh-wedel.de>
Date:   Tue Feb 20 20:20:58 2007 +0100

    [PATCH] [MTD] block2mtd: remove casts
    
    Remove two casts - they were not only pointless, but outright harmful.
    
    Spotted by Felix Fietkau <nbd@openwrt.org>
    
    Signed-off-by: JÃ¶rn Engel <joern@lazybastard.org>

commit bebb8a2bc180a4c920c57e89b2d713a34c1d096c
Author: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Date:   Sun Feb 18 01:50:18 2007 -0500

    Input: add driver for MIPS Cobalt back panel buttons
    
    Tested on Cobalt Qube2.
    
    Signed-off-by: Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 24bf10ab2d72863a14187905fd992ca8119c809e
Author: Stefan Lucke <stefan@lucke.in-berlin.de>
Date:   Sun Feb 18 01:49:10 2007 -0500

    Input: psmouse - add support for eGalax PS/2 touchscreen controller
    
    Based on the touchkit USB and lifebook PS/2 touchscreen driver.
    
    The egalax touchsreen controller (PS/2 or USB version) is used in this 7"
    device: http://www.cartft.com/catalog/il/449
    
    Signed-off-by: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

commit 00b65985fb2fc542b855b03fcda0d0f2bab4f442
Author: Chen, Kenneth W <kenneth.w.chen@intel.com>
Date:   Fri Oct 13 10:08:13 2006 -0700

    [IA64] relax per-cpu TLB requirement to DTC
    
    Instead of pinning per-cpu TLB into a DTR, use DTC.  This will free up
    one TLB entry for application, or even kernel if access pattern to
    per-cpu data area has high temporal locality.
    
    Since per-cpu is mapped at the top of region 7 address, we just need to
    add special case in alt_dtlb_miss.  The physical address of per-cpu data
    is already conveniently stored in IA64_KR(PER_CPU_DATA).  Latency for
    alt_dtlb_miss is not affected as we can hide all the latency.  It was
    measured that alt_dtlb_miss handler has 23 cycles latency before and
    after the patch.
    
    The performance effect is massive for applications that put lots of tlb
    pressure on CPU.  Workload environment like database online transaction
    processing or application uses tera-byte of memory would benefit the most.
    Measurement with industry standard database benchmark shown an upward
    of 1.6% gain.  While smaller workloads like cpu, java also showing small
    improvement.
    
    Signed-off-by: Ken Chen <kenneth.w.chen@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit a0776ec8e97bf109e7d973d09fc3e1814eb32bfb
Author: Chen, Kenneth W <kenneth.w.chen@intel.com>
Date:   Fri Oct 13 10:05:45 2006 -0700

    [IA64] remove per-cpu ia64_phys_stacked_size_p8
    
    It's not efficient to use a per-cpu variable just to store
    how many physical stack register a cpu has.  Ever since the
    incarnation of ia64 up till upcoming Montecito processor, that
    variable has "glued" to 96. Having a variable in memory means
    that the kernel is burning an extra cacheline access on every
    syscall and kernel exit path.  Such "static" value is better
    served with the instruction patching utility exists today.
    Convert ia64_phys_stacked_size_p8 into dynamic insn patching.
    
    This also has a pleasant side effect of eliminating access to
    per-cpu area while psr.ic=0 in the kernel exit path. (fixable
    for per-cpu DTC work, but why bother?)
    
    There are some concerns with the default value that the instruc-
    tion encoded in the kernel image.  It shouldn't be concerned.
    The reasons are:
    
    (1) cpu_init() is called at CPU initialization.  In there, we
        find out physical stack register size from PAL and patch
        two instructions in kernel exit code.  The code in question
        can not be executed before the patching is done.
    
    (2) current implementation stores zero in ia64_phys_stacked_size_p8,
        and that's what the current kernel exit path loads the value with.
        With the new code, it is equivalent that we store reg size 96
        in ia64_phys_stacked_size_p8, thus creating a better safety net.
        Given (1) above can never fail, having (2) is just a bonus.
    
    All in all, this patch allow one less memory reference in the kernel
    exit path, thus reducing syscall and interrupt return latency; and
    avoid polluting potential useful data in the CPU cache.
    
    Signed-off-by: Ken Chen <kenneth.w.chen@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit e1b43bd556a611584a65f529e5077c1b54ace4f7
Author: Tony Luck <tony.luck@intel.com>
Date:   Mon Feb 5 15:47:43 2007 -0800

    [IA64] Fix example error injection program
    
    Progam accessed using /sys/devices/system/node/node0/cpu%d/err_inject/
    This path only exists for CONFIG_NUMA=y systems.  Better to use
    /sys/devices/system/cpu/cpu%d/err_inject/ which is available on all
    systems.
    
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 1138b7e2d40711b024768034beb64885994271e4
Author: Fenghua Yu <fenghua.yu@intel.com>
Date:   Fri Dec 8 16:17:31 2006 -0800

    [IA64] Itanium MC Error Injection Tool: pal_mc_error_inject() interface
    
    This patch implements pal_mc_error_inject() interface in kernel. Both physical
    mode and virtual mode are supported.
    
    Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 539d517ad10bbaac2c04e0ee22916a360c5bcc0d
Author: Fenghua Yu <fenghua.yu@intel.com>
Date:   Fri Dec 8 16:16:24 2006 -0800

    [IA64] Itanium MC Error Injection Tool: Makefile changes
    
    This patch has Makefile changes.
    
    Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit 62fa562af36d32431ac8d7432b2c3ffbb7cf82df
Author: Fenghua Yu <fenghua.yu@intel.com>
Date:   Fri Dec 8 16:15:16 2006 -0800

    [IA64] Itanium MC Error Injection Tool: Driver sysfs interface
    
    This kernel driver patch provides sysfs interface for user application to
    call pal_mc_error_inject() procedure.
    
    Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit bf6285278418f1dc6f07296bbb286da0bfe26d5d
Author: Fenghua Yu <fenghua.yu@intel.com>
Date:   Fri Dec 8 16:14:22 2006 -0800

    [IA64] Itanium MC Error Injection Tool: Doc and sample application
    
    This patch contains a documention and sample application. Since the sample
    application has ~1000 lines of code, it might not be suitable in a kernel
    documention in kenrel tree. If you think this is not good place to hold
    the sample application, please let me know and I'm open to other choices
    e.g. sourceforge etc.
    
    Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>

commit e9ef08bdc189e98610bc4b9a6e6f19bc3793b2c8
Author: Fenghua Yu <fenghua.yu@intel.com>
Date:   Fri Dec 8 16:06:01 2006 -0800

    [IA64] Itanium MC Error Injection Tool: Kernel configuration
    
    This patch has kenrel configuration changes for the MC Error Injection
    Tool.
    
    Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
    Signed-off-by: Tony Luck <tony.luck@intel.com>
 CREDITS                                            |   36 
 Documentation/ABI/testing/sysfs-bus-usb            |   41 
 Documentation/CodingStyle                          |   17 
 Documentation/DocBook/Makefile                     |   19 
 Documentation/DocBook/kernel-api.tmpl              |   69 
 Documentation/DocBook/librs.tmpl                   |   16 
 Documentation/DocBook/man/Makefile                 |    3 
 Documentation/SubmittingDrivers                    |   15 
 Documentation/accounting/getdelays.c               |   20 
 Documentation/blackfin/00-INDEX                    |   11 
 Documentation/blackfin/Filesystems                 |  169 
 Documentation/blackfin/cache-lock.txt              |   48 
 Documentation/blackfin/cachefeatures.txt           |   65 
 Documentation/cciss.txt                            |   13 
 Documentation/dontdiff                             |    4 
 Documentation/driver-model/devres.txt              |    2 
 Documentation/fb/deferred_io.txt                   |   75 
 Documentation/fb/s3fb.txt                          |   12 
 Documentation/feature-removal-schedule.txt         |  136 
 Documentation/filesystems/Locking                  |    2 
 Documentation/filesystems/afs.txt                  |  214 -
 Documentation/filesystems/jfs.txt                  |    8 
 Documentation/filesystems/proc.txt                 |   47 
 Documentation/filesystems/vfat.txt                 |    7 
 Documentation/filesystems/vfs.txt                  |   23 
 Documentation/hwmon/coretemp                       |   36 
 Documentation/hwmon/max6650                        |   53 
 Documentation/hwmon/smsc47m1                       |   11 
 Documentation/hwmon/smsc47m192                     |    7 
 Documentation/hwmon/sysfs-interface                |    7 
 Documentation/i2c/busses/i2c-nforce2               |    2 
 Documentation/i2c/porting-clients                  |   18 
 Documentation/i2c/summary                          |   29 
 Documentation/i2c/writing-clients                  |  415 -
 Documentation/i386/boot.txt                        |   23 
 Documentation/ia64/aliasing-test.c                 |  247 +
 Documentation/ia64/aliasing.txt                    |   71 
 Documentation/ia64/err_inject.txt                  | 1068 +++
 Documentation/ibm-acpi.txt                         |  728 --
 Documentation/infiniband/user_mad.txt              |    8 
 Documentation/input/input-programming.txt          |  125 
 Documentation/ioctl-number.txt                     |    3 
 Documentation/kbuild/modules.txt                   |    2 
 Documentation/kernel-parameters.txt                |   95 
 Documentation/keys.txt                             |   12 
 Documentation/kprobes.txt                          |   34 
 Documentation/laptop-mode.txt                      |    2 
 Documentation/networking/bcm43xx.txt               |   97 
 Documentation/networking/bonding.txt               |   35 
 Documentation/networking/dccp.txt                  |   10 
 Documentation/networking/ip-sysctl.txt             |   31 
 Documentation/networking/rxrpc.txt                 |  859 ++
 Documentation/networking/wan-router.txt            |    1 
 Documentation/oops-tracing.txt                     |    3 
 Documentation/pci.txt                              |   12 
 Documentation/pcmcia/driver.txt                    |   30 
 Documentation/power/basic-pm-debugging.txt         |  106 
 Documentation/power/drivers-testing.txt            |   42 
 Documentation/power/interface.txt                  |   29 
 Documentation/power/pci.txt                        |    2 
 Documentation/power/states.txt                     |   13 
 Documentation/power/swsusp.txt                     |   14 
 Documentation/powerpc/booting-without-of.txt       |  260 -
 Documentation/rtc.txt                              |    7 
 Documentation/s390/crypto/crypto-API.txt           |   83 
 Documentation/s390/zfcpdump.txt                    |   87 
 Documentation/scsi/aacraid.txt                     |    7 
 Documentation/scsi/ncr53c8xx.txt                   |    5 
 Documentation/sh/clk.txt                           |   32 
 Documentation/sony-laptop.txt                      |   25 
 Documentation/spi/pxa2xx                           |    2 
 Documentation/spi/spi-summary                      |   43 
 Documentation/spi/spidev                           |  307 +
 Documentation/sysctl/vm.txt                        |   23 
 Documentation/sysrq.txt                            |    4 
 Documentation/thinkpad-acpi.txt                    |  981 ++
 Documentation/tty.txt                              |    4 
 Documentation/usb/usb-serial.txt                   |    2 
 Documentation/usb/usbmon.txt                       |   80 
 Documentation/video4linux/CARDLIST.bttv            |    2 
 Documentation/video4linux/CARDLIST.cx88            |    2 
 Documentation/video4linux/CARDLIST.ivtv            |   18 
 Documentation/video4linux/CARDLIST.saa7134         |    8 
 Documentation/video4linux/CARDLIST.usbvision       |   64 
 Documentation/video4linux/README.ivtv              |  187 
 .../video4linux/cx2341x/fw-decoder-regs.txt        |   12 
 .../video4linux/cx2341x/fw-encoder-api.txt         |   19 
 Documentation/video4linux/cx2341x/fw-osd-api.txt   |   12 
 Documentation/video4linux/meye.txt                 |    7 
 Documentation/video4linux/sn9c102.txt              |   64 
 Documentation/video4linux/zr364xx.txt              |   65 
 Documentation/vm/slabinfo.c                        |  943 ++
 Documentation/vm/slub.txt                          |  113 
 Documentation/x86_64/boot-options.txt              |   14 
 Documentation/x86_64/fake-numa-for-cpusets         |   66 
 Documentation/x86_64/machinecheck                  |    7 
 Kbuild                                             |   11 
 MAINTAINERS                                        |  272 +
 Makefile                                           |   17 
 arch/alpha/Kconfig.debug                           |    8 
 arch/alpha/boot/bootpz.c                           |    6 
 arch/alpha/boot/misc.c                             |    2 
 arch/alpha/boot/tools/objstrip.c                   |    1 
 arch/alpha/kernel/err_common.c                     |    1 
 arch/alpha/kernel/err_ev6.c                        |    1 
 arch/alpha/kernel/err_ev7.c                        |    1 
 arch/alpha/kernel/osf_sys.c                        |   21 
 arch/alpha/kernel/process.c                        |    1 
 arch/alpha/kernel/setup.c                          |    9 
 arch/alpha/kernel/signal.c                         |    1 
 arch/alpha/kernel/smp.c                            |    1 
 arch/alpha/kernel/srmcons.c                        |    4 
 arch/alpha/kernel/vmlinux.lds.S                    |    2 
 arch/alpha/lib/Makefile                            |    1 
 arch/alpha/lib/strcasecmp.c                        |   26 
 arch/alpha/mm/fault.c                              |    1 
 arch/arm/Kconfig                                   |   21 
 arch/arm/boot/compressed/head-at91rm9200.S         |    6 
 arch/arm/boot/compressed/misc.c                    |    2 
 arch/arm/common/sa1111.c                           |    1 
 arch/arm/common/sharpsl_pm.c                       |    2 
 arch/arm/common/via82c505.c                        |    1 
 arch/arm/configs/ixp4xx_defconfig                  |    2 
 arch/arm/configs/picotux200_defconfig              | 1386 ++++
 arch/arm/kernel/Makefile                           |    4 
 arch/arm/kernel/ecard.c                            |   31 
 arch/arm/kernel/ecard.h                            |   56 
 arch/arm/kernel/head.S                             |    6 
 arch/arm/kernel/irq.c                              |    3 
 arch/arm/kernel/process.c                          |    4 
 arch/arm/kernel/ptrace.c                           |   22 
 arch/arm/kernel/ptrace.h                           |   39 
 arch/arm/kernel/signal.c                           |   22 
 arch/arm/kernel/stacktrace.c                       |   73 
 arch/arm/kernel/stacktrace.h                       |    9 
 arch/arm/kernel/time.c                             |    4 
 arch/arm/kernel/traps.c                            |   38 
 arch/arm/kernel/vmlinux.lds.S                      |    5 
 arch/arm/lib/backtrace.S                           |  165 
 arch/arm/lib/getuser.S                             |    2 
 arch/arm/lib/putuser.S                             |    2 
 arch/arm/mach-aaec2000/core.c                      |    2 
 arch/arm/mach-at91/Kconfig                         |    7 
 arch/arm/mach-at91/Makefile                        |    1 
 arch/arm/mach-at91/at91rm9200.c                    |   19 
 arch/arm/mach-at91/at91rm9200_time.c               |    2 
 arch/arm/mach-at91/at91sam9260.c                   |    7 
 arch/arm/mach-at91/at91sam9261.c                   |   19 
 arch/arm/mach-at91/at91sam9261_devices.c           |   10 
 arch/arm/mach-at91/at91sam9263.c                   |   48 
 arch/arm/mach-at91/at91sam9263_devices.c           |  124 
 arch/arm/mach-at91/at91sam926x_time.c              |    2 
 arch/arm/mach-at91/board-picotux200.c              |  166 
 arch/arm/mach-at91/board-sam9260ek.c               |   10 
 arch/arm/mach-at91/board-sam9261ek.c               |   52 
 arch/arm/mach-at91/board-sam9263ek.c               |   70 
 arch/arm/mach-at91/pm.c                            |    1 
 arch/arm/mach-clps711x/time.c                      |    2 
 arch/arm/mach-clps7500/core.c                      |    2 
 arch/arm/mach-ebsa110/core.c                       |    2 
 arch/arm/mach-ebsa110/io.c                         |   40 
 arch/arm/mach-ep93xx/clock.c                       |    5 
 arch/arm/mach-ep93xx/core.c                        |    2 
 arch/arm/mach-footbridge/dc21285-timer.c           |    2 
 arch/arm/mach-footbridge/dc21285.c                 |    1 
 arch/arm/mach-footbridge/isa-timer.c               |    2 
 arch/arm/mach-h720x/cpu-h7201.c                    |    2 
 arch/arm/mach-h720x/cpu-h7202.c                    |    2 
 arch/arm/mach-imx/time.c                           |    2 
 arch/arm/mach-integrator/core.c                    |    2 
 arch/arm/mach-integrator/pci.c                     |    1 
 arch/arm/mach-integrator/pci_v3.c                  |    1 
 arch/arm/mach-iop13xx/Makefile                     |    1 
 arch/arm/mach-iop13xx/io.c                         |   10 
 arch/arm/mach-iop13xx/iq81340mc.c                  |    5 
 arch/arm/mach-iop13xx/iq81340sc.c                  |    5 
 arch/arm/mach-iop13xx/pci.c                        |   16 
 arch/arm/mach-iop13xx/setup.c                      |    6 
 arch/arm/mach-iop13xx/tpmi.c                       |  234 +
 arch/arm/mach-iop32x/Kconfig                       |    8 
 arch/arm/mach-iop32x/iq31244.c                     |   11 
 arch/arm/mach-iop32x/iq80321.c                     |    3 
 arch/arm/mach-iop33x/Kconfig                       |    8 
 arch/arm/mach-iop33x/iq80331.c                     |    3 
 arch/arm/mach-iop33x/iq80332.c                     |    3 
 arch/arm/mach-ixp2000/core.c                       |   24 
 arch/arm/mach-ixp2000/enp2611.c                    |    6 
 arch/arm/mach-ixp23xx/core.c                       |    2 
 arch/arm/mach-ixp4xx/Kconfig                       |   22 
 arch/arm/mach-ixp4xx/Makefile                      |    2 
 arch/arm/mach-ixp4xx/common-pci.c                  |    4 
 arch/arm/mach-ixp4xx/common.c                      |  124 
 arch/arm/mach-ixp4xx/dsmg600-pci.c                 |   74 
 arch/arm/mach-ixp4xx/dsmg600-power.c               |  125 
 arch/arm/mach-ixp4xx/dsmg600-setup.c               |  175 
 arch/arm/mach-ixp4xx/ixdp425-pci.c                 |    2 
 arch/arm/mach-ixp4xx/ixdp425-setup.c               |   18 
 arch/arm/mach-lh7a40x/irq-lh7a400.c                |    1 
 arch/arm/mach-lh7a40x/irq-lh7a404.c                |    1 
 arch/arm/mach-lh7a40x/irq-lpd7a40x.c               |    1 
 arch/arm/mach-lh7a40x/time.c                       |    2 
 arch/arm/mach-netx/time.c                          |    2 
 arch/arm/mach-ns9xxx/Kconfig                       |   15 
 arch/arm/mach-ns9xxx/Makefile                      |    1 
 arch/arm/mach-ns9xxx/board-jscc9p9360.c            |   17 
 arch/arm/mach-ns9xxx/board-jscc9p9360.h            |   13 
 arch/arm/mach-ns9xxx/mach-cc9p9360js.c             |   29 
 arch/arm/mach-ns9xxx/time.c                        |    2 
 arch/arm/mach-omap1/irq.c                          |    1 
 arch/arm/mach-omap1/pm.c                           |    8 
 arch/arm/mach-omap1/time.c                         |  206 -
 arch/arm/mach-omap2/pm.c                           |    2 
 arch/arm/mach-omap2/timer-gp.c                     |    2 
 arch/arm/mach-pnx4008/pm.c                         |   39 
 arch/arm/mach-pnx4008/time.c                       |    2 
 arch/arm/mach-pxa/generic.c                        |    4 
 arch/arm/mach-pxa/irq.c                            |   73 
 arch/arm/mach-pxa/lpd270.c                         |    4 
 arch/arm/mach-pxa/lubbock.c                        |    2 
 arch/arm/mach-pxa/mainstone.c                      |    4 
 arch/arm/mach-pxa/pm.c                             |    5 
 arch/arm/mach-pxa/pxa27x.c                         |    4 
 arch/arm/mach-pxa/ssp.c                            |   12 
 arch/arm/mach-pxa/time.c                           |    2 
 arch/arm/mach-realview/core.c                      |    2 
 arch/arm/mach-rpc/riscpc.c                         |   35 
 arch/arm/mach-s3c2410/bast-irq.c                   |    1 
 arch/arm/mach-s3c2410/irq.c                        |    1 
 arch/arm/mach-s3c2410/mach-amlm5900.c              |    7 
 arch/arm/mach-s3c2410/mach-bast.c                  |   12 
 arch/arm/mach-s3c2410/mach-h1940.c                 |    9 
 arch/arm/mach-s3c2410/mach-n30.c                   |    8 
 arch/arm/mach-s3c2410/mach-otom.c                  |   12 
 arch/arm/mach-s3c2410/mach-qt2410.c                |    8 
 arch/arm/mach-s3c2410/mach-smdk2410.c              |   14 
 arch/arm/mach-s3c2410/mach-vr1000.c                |   16 
 arch/arm/mach-s3c2412/Kconfig                      |    9 
 arch/arm/mach-s3c2412/irq.c                        |    1 
 arch/arm/mach-s3c2412/mach-smdk2413.c              |    7 
 arch/arm/mach-s3c2412/mach-vstms.c                 |   12 
 arch/arm/mach-s3c2440/irq.c                        |    1 
 arch/arm/mach-s3c2440/mach-anubis.c                |   17 
 arch/arm/mach-s3c2440/mach-nexcoder.c              |   13 
 arch/arm/mach-s3c2440/mach-osiris.c                |   16 
 arch/arm/mach-s3c2440/mach-rx3715.c                |    8 
 arch/arm/mach-s3c2440/mach-smdk2440.c              |    7 
 arch/arm/mach-s3c2443/irq.c                        |    1 
 arch/arm/mach-s3c2443/mach-smdk2443.c              |    7 
 arch/arm/mach-sa1100/clock.c                       |   24 
 arch/arm/mach-sa1100/h3600.c                       |    2 
 arch/arm/mach-sa1100/irq.c                         |    1 
 arch/arm/mach-sa1100/neponset.c                    |    1 
 arch/arm/mach-sa1100/pm.c                          |    8 
 arch/arm/mach-sa1100/time.c                        |    2 
 arch/arm/mach-shark/core.c                         |    2 
 arch/arm/mach-shark/irq.c                          |    1 
 arch/arm/mach-versatile/core.c                     |  131 
 arch/arm/mach-versatile/pci.c                      |    1 
 arch/arm/mm/alignment.c                            |    1 
 arch/arm/mm/fault.c                                |    7 
 arch/arm/mm/init.c                                 |    1 
 arch/arm/mm/ioremap.c                              |   80 
 arch/arm/mm/mm.h                                   |   10 
 arch/arm/mm/mmap.c                                 |    3 
 arch/arm/mm/mmu.c                                  |  349 -
 arch/arm/mm/nommu.c                                |   12 
 arch/arm/mm/proc-xscale.S                          |   28 
 arch/arm/oprofile/backtrace.c                      |   69 
 arch/arm/plat-iop/io.c                             |    4 
 arch/arm/plat-iop/pci.c                            |  140 
 arch/arm/plat-iop/time.c                           |   10 
 arch/arm/plat-omap/Kconfig                         |    1 
 arch/arm/plat-omap/common.c                        |   50 
 arch/arm/plat-omap/devices.c                       |    6 
 arch/arm/plat-omap/dmtimer.c                       |    2 
 arch/arm/plat-omap/gpio.c                          |  613 +-
 arch/arm/plat-omap/mcbsp.c                         |   15 
 arch/arm/plat-omap/timer32k.c                      |  141 
 arch/arm/plat-s3c24xx/clock.c                      |   12 
 arch/arm/plat-s3c24xx/cpu.c                        |   38 
 arch/arm/plat-s3c24xx/dma.c                        |   13 
 arch/arm/plat-s3c24xx/irq.c                        |    1 
 arch/arm/plat-s3c24xx/pm.c                         |   28 
 arch/arm/plat-s3c24xx/s3c244x-irq.c                |    1 
 arch/arm/plat-s3c24xx/time.c                       |    2 
 arch/arm/vfp/vfpdouble.c                           |    1 
 arch/arm/vfp/vfpsingle.c                           |    1 
 arch/arm26/Kconfig                                 |    3 
 arch/arm26/boot/compressed/misc.c                  |    2 
 arch/arm26/kernel/armksyms.c                       |    1 
 arch/arm26/kernel/ptrace.c                         |    1 
 arch/arm26/kernel/signal.c                         |    1 
 arch/arm26/mm/memc.c                               |    8 
 arch/avr32/Kconfig                                 |   13 
 arch/avr32/Makefile                                |    1 
 arch/avr32/boards/atngw100/Makefile                |    1 
 arch/avr32/boards/atngw100/flash.c                 |   95 
 arch/avr32/boards/atngw100/setup.c                 |  124 
 arch/avr32/boards/atstk1000/atstk1002.c            |    4 
 arch/avr32/boards/atstk1000/setup.c                |   30 
 arch/avr32/configs/atngw100_defconfig              | 1085 +++
 arch/avr32/kernel/cpu.c                            |   64 
 arch/avr32/kernel/entry-avr32b.S                   |  124 
 arch/avr32/kernel/kprobes.c                        |    2 
 arch/avr32/kernel/module.c                         |   11 
 arch/avr32/kernel/process.c                        |  193 
 arch/avr32/kernel/ptrace.c                         |    5 
 arch/avr32/kernel/setup.c                          |  484 +
 arch/avr32/kernel/time.c                           |  150 
 arch/avr32/kernel/traps.c                          |  433 -
 arch/avr32/kernel/vmlinux.lds.c                    |    9 
 arch/avr32/mach-at32ap/Kconfig                     |   31 
 arch/avr32/mach-at32ap/Makefile                    |    1 
 arch/avr32/mach-at32ap/at32ap7000.c                |   70 
 arch/avr32/mach-at32ap/hmatrix.h                   |  182 
 arch/avr32/mach-at32ap/hsmc.c                      |   23 
 arch/avr32/mach-at32ap/time-tc.c                   |  218 +
 arch/avr32/mm/fault.c                              |  118 
 arch/avr32/mm/init.c                               |  238 -
 arch/blackfin/Kconfig                              |  989 +++
 arch/blackfin/Makefile                             |   80 
 arch/blackfin/boot/Makefile                        |   27 
 arch/blackfin/defconfig                            | 1314 +++
 arch/blackfin/kernel/Makefile                      |   14 
 arch/blackfin/kernel/asm-offsets.c                 |  136 
 arch/blackfin/kernel/bfin_dma_5xx.c                |  742 ++
 arch/blackfin/kernel/bfin_gpio.c                   |  637 ++
 arch/blackfin/kernel/bfin_ksyms.c                  |  119 
 arch/blackfin/kernel/dma-mapping.c                 |  183 
 arch/blackfin/kernel/dualcore_test.c               |   49 
 arch/blackfin/kernel/entry.S                       |   94 
 arch/blackfin/kernel/flat.c                        |  101 
 arch/blackfin/kernel/init_task.c                   |   60 
 arch/blackfin/kernel/irqchip.c                     |  147 
 arch/blackfin/kernel/module.c                      |  429 +
 arch/blackfin/kernel/process.c                     |  394 +
 arch/blackfin/kernel/ptrace.c                      |  430 +
 arch/blackfin/kernel/setup.c                       |  902 ++
 arch/blackfin/kernel/signal.c                      |  356 +
 arch/blackfin/kernel/sys_bfin.c                    |  115 
 arch/blackfin/kernel/time.c                        |  326 +
 arch/blackfin/kernel/traps.c                       |  649 ++
 arch/blackfin/kernel/vmlinux.lds.S                 |  228 +
 arch/blackfin/lib/Makefile                         |   11 
 arch/blackfin/lib/ashldi3.c                        |   58 
 arch/blackfin/lib/ashrdi3.c                        |   59 
 arch/blackfin/lib/checksum.c                       |  140 
 arch/blackfin/lib/divsi3.S                         |  216 +
 arch/blackfin/lib/gcclib.h                         |   47 
 arch/blackfin/lib/ins.S                            |   69 
 arch/blackfin/lib/lshrdi3.c                        |   72 
 arch/blackfin/lib/memchr.S                         |   70 
 arch/blackfin/lib/memcmp.S                         |  110 
 arch/blackfin/lib/memcpy.S                         |  142 
 arch/blackfin/lib/memmove.S                        |  103 
 arch/blackfin/lib/memset.S                         |  109 
 arch/blackfin/lib/modsi3.S                         |   79 
 arch/blackfin/lib/muldi3.c                         |   99 
 arch/blackfin/lib/outs.S                           |   62 
 arch/blackfin/lib/smulsi3_highpart.S               |   30 
 arch/blackfin/lib/strcmp.c                         |   11 
 arch/blackfin/lib/strcpy.c                         |   11 
 arch/blackfin/lib/strncmp.c                        |   11 
 arch/blackfin/lib/strncpy.c                        |   11 
 arch/blackfin/lib/udivsi3.S                        |  298 +
 arch/blackfin/lib/umodsi3.S                        |   66 
 arch/blackfin/lib/umulsi3_highpart.S               |   23 
 arch/blackfin/mach-bf533/Kconfig                   |   92 
 arch/blackfin/mach-bf533/Makefile                  |    9 
 arch/blackfin/mach-bf533/boards/Makefile           |    8 
 arch/blackfin/mach-bf533/boards/cm_bf533.c         |  267 +
 arch/blackfin/mach-bf533/boards/ezkit.c            |  224 +
 arch/blackfin/mach-bf533/boards/generic_board.c    |   95 
 arch/blackfin/mach-bf533/boards/stamp.c            |  321 +
 arch/blackfin/mach-bf533/cpu.c                     |  161 
 arch/blackfin/mach-bf533/head.S                    |  774 ++
 arch/blackfin/mach-bf533/ints-priority.c           |   65 
 arch/blackfin/mach-bf537/Kconfig                   |  141 
 arch/blackfin/mach-bf537/Makefile                  |    9 
 arch/blackfin/mach-bf537/boards/Makefile           |    9 
 arch/blackfin/mach-bf537/boards/cm_bf537.c         |  364 +
 arch/blackfin/mach-bf537/boards/eth_mac.c          |   51 
 arch/blackfin/mach-bf537/boards/generic_board.c    |  445 +
 arch/blackfin/mach-bf537/boards/led.S              |  183 
 arch/blackfin/mach-bf537/boards/pnav10.c           |  523 +
 arch/blackfin/mach-bf537/boards/stamp.c            |  615 ++
 arch/blackfin/mach-bf537/cpu.c                     |  161 
 arch/blackfin/mach-bf537/head.S                    |  602 ++
 arch/blackfin/mach-bf537/ints-priority.c           |   74 
 arch/blackfin/mach-bf561/Kconfig                   |  222 +
 arch/blackfin/mach-bf561/Makefile                  |    9 
 arch/blackfin/mach-bf561/boards/Makefile           |    7 
 arch/blackfin/mach-bf561/boards/cm_bf561.c         |  289 +
 arch/blackfin/mach-bf561/boards/ezkit.c            |  147 
 arch/blackfin/mach-bf561/boards/generic_board.c    |   82 
 arch/blackfin/mach-bf561/coreb.c                   |  402 +
 arch/blackfin/mach-bf561/head.S                    |  512 +
 arch/blackfin/mach-bf561/ints-priority.c           |  108 
 arch/blackfin/mach-common/Makefile                 |   12 
 arch/blackfin/mach-common/cache.S                  |  253 +
 arch/blackfin/mach-common/cacheinit.S              |  137 
 arch/blackfin/mach-common/cplbhdlr.S               |  130 
 arch/blackfin/mach-common/cplbinfo.c               |  211 +
 arch/blackfin/mach-common/cplbmgr.S                |  607 ++
 arch/blackfin/mach-common/dpmc.S                   |  418 +
 arch/blackfin/mach-common/entry.S                  | 1207 +++
 arch/blackfin/mach-common/interrupt.S              |  253 +
 arch/blackfin/mach-common/ints-priority-dc.c       |  476 +
 arch/blackfin/mach-common/ints-priority-sc.c       |  577 +
 arch/blackfin/mach-common/irqpanic.c               |  194 
 arch/blackfin/mach-common/lock.S                   |  204 +
 arch/blackfin/mach-common/pm.c                     |  181 
 arch/blackfin/mm/Makefile                          |    5 
 arch/blackfin/mm/blackfin_sram.c                   |  540 +
 arch/blackfin/mm/blackfin_sram.h                   |   38 
 arch/blackfin/mm/init.c                            |  208 +
 arch/blackfin/oprofile/Kconfig                     |   29 
 arch/blackfin/oprofile/Makefile                    |   14 
 arch/blackfin/oprofile/common.c                    |  168 
 arch/blackfin/oprofile/op_blackfin.h               |   98 
 arch/blackfin/oprofile/op_model_bf533.c            |  161 
 arch/blackfin/oprofile/timer_int.c                 |   74 
 arch/cris/arch-v10/kernel/ptrace.c                 |    1 
 arch/cris/arch-v10/kernel/signal.c                 |    1 
 arch/cris/arch-v32/drivers/pci/dma.c               |    2 
 arch/cris/arch-v32/kernel/fasttimer.c              |   30 
 arch/cris/arch-v32/kernel/ptrace.c                 |    1 
 arch/cris/arch-v32/vmlinux.lds.S                   |    1 
 arch/cris/kernel/crisksyms.c                       |    1 
 arch/cris/kernel/profile.c                         |   81 
 arch/cris/kernel/ptrace.c                          |    1 
 arch/frv/Kconfig                                   |    4 
 arch/frv/kernel/irq.c                              |    1 
 arch/frv/kernel/ptrace.c                           |    1 
 arch/frv/kernel/semaphore.c                        |    2 
 arch/frv/kernel/signal.c                           |    1 
 arch/frv/kernel/sys_frv.c                          |    1 
 arch/frv/kernel/vmlinux.lds.S                      |    1 
 arch/frv/mm/elf-fdpic.c                            |    4 
 arch/frv/mm/pgalloc.c                              |    4 
 arch/h8300/Kconfig                                 |    8 
 arch/h8300/Makefile                                |    2 
 arch/h8300/boot/Makefile                           |   12 
 arch/h8300/boot/compressed/Makefile                |   37 
 arch/h8300/boot/compressed/head.S                  |   47 
 arch/h8300/boot/compressed/misc.c                  |  219 +
 arch/h8300/kernel/Makefile                         |    6 
 arch/h8300/kernel/irq.c                            |  211 +
 arch/h8300/kernel/ptrace.c                         |    1 
 arch/h8300/kernel/setup.c                          |    3 
 arch/h8300/kernel/sys_h8300.c                      |    1 
 arch/h8300/kernel/time.c                           |   54 
 arch/h8300/mm/kmap.c                               |    4 
 arch/h8300/platform/h8300h/Makefile                |    2 
 arch/h8300/platform/h8300h/entry.S                 |    4 
 arch/h8300/platform/h8300h/generic/Makefile        |    2 
 arch/h8300/platform/h8300h/ints_h8300h.c           |   85 
 arch/h8300/platform/h8s/entry.S                    |   17 
 arch/i386/Kconfig                                  |   43 
 arch/i386/Kconfig.cpu                              |   35 
 arch/i386/Kconfig.debug                            |   10 
 arch/i386/Makefile                                 |    2 
 arch/i386/Makefile.cpu                             |    9 
 arch/i386/boot/Makefile                            |    4 
 arch/i386/boot/compressed/misc.c                   |    2 
 arch/i386/boot/setup.S                             |   24 
 arch/i386/boot/video.S                             |    4 
 arch/i386/defconfig                                |   74 
 arch/i386/kernel/Makefile                          |    5 
 arch/i386/kernel/acpi/boot.c                       |    2 
 arch/i386/kernel/acpi/earlyquirk.c                 |   26 
 arch/i386/kernel/alternative.c                     |  102 
 arch/i386/kernel/apic.c                            |   23 
 arch/i386/kernel/apm.c                             |   13 
 arch/i386/kernel/asm-offsets.c                     |   18 
 arch/i386/kernel/cpu/Makefile                      |    4 
 arch/i386/kernel/cpu/amd.c                         |   15 
 arch/i386/kernel/cpu/bugs.c                        |  191 
 arch/i386/kernel/cpu/centaur.c                     |   10 
 arch/i386/kernel/cpu/common.c                      |  217 -
 arch/i386/kernel/cpu/cpufreq/longhaul.c            |   21 
 arch/i386/kernel/cpu/cpufreq/p4-clockmod.c         |   31 
 arch/i386/kernel/cpu/cpufreq/powernow-k8.c         |    6 
 arch/i386/kernel/cpu/cpufreq/powernow-k8.h         |    2 
 arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c  |   10 
 arch/i386/kernel/cpu/cpufreq/speedstep-lib.c       |    1 
 arch/i386/kernel/cpu/cpufreq/speedstep-smi.c       |    2 
 arch/i386/kernel/cpu/cyrix.c                       |   21 
 arch/i386/kernel/cpu/intel.c                       |    4 
 arch/i386/kernel/cpu/mcheck/k7.c                   |   13 
 arch/i386/kernel/cpu/mcheck/mce.c                  |    3 
 arch/i386/kernel/cpu/mcheck/p4.c                   |   16 
 arch/i386/kernel/cpu/mtrr/generic.c                |  101 
 arch/i386/kernel/cpu/mtrr/main.c                   |   11 
 arch/i386/kernel/cpu/nexgen.c                      |   10 
 arch/i386/kernel/cpu/perfctr-watchdog.c            |  658 ++
 arch/i386/kernel/cpu/proc.c                        |    3 
 arch/i386/kernel/cpu/rise.c                        |    9 
 arch/i386/kernel/cpu/transmeta.c                   |   10 
 arch/i386/kernel/cpu/umc.c                         |   10 
 arch/i386/kernel/crash.c                           |    2 
 arch/i386/kernel/doublefault.c                     |   29 
 arch/i386/kernel/e820.c                            |   64 
 arch/i386/kernel/efi.c                             |   28 
 arch/i386/kernel/entry.S                           |   23 
 arch/i386/kernel/head.S                            |  118 
 arch/i386/kernel/i386_ksyms.c                      |    2 
 arch/i386/kernel/i8253.c                           |    2 
 arch/i386/kernel/i8259.c                           |    1 
 arch/i386/kernel/io_apic.c                         |   43 
 arch/i386/kernel/ioport.c                          |    4 
 arch/i386/kernel/irq.c                             |    3 
 arch/i386/kernel/kprobes.c                         |   27 
 arch/i386/kernel/ldt.c                             |    1 
 arch/i386/kernel/legacy_serial.c                   |   67 
 arch/i386/kernel/mpparse.c                         |    3 
 arch/i386/kernel/msr.c                             |  106 
 arch/i386/kernel/nmi.c                             |  834 --
 arch/i386/kernel/paravirt.c                        |  522 -
 arch/i386/kernel/pci-dma.c                         |    2 
 arch/i386/kernel/process.c                         |   38 
 arch/i386/kernel/ptrace.c                          |    1 
 arch/i386/kernel/quirks.c                          |   69 
 arch/i386/kernel/reboot.c                          |   55 
 arch/i386/kernel/reboot_fixups.c                   |    2 
 arch/i386/kernel/signal.c                          |    1 
 arch/i386/kernel/smp.c                             |  305 -
 arch/i386/kernel/smpboot.c                         |  147 
 arch/i386/kernel/sys_i386.c                        |    1 
 arch/i386/kernel/syscall_table.S                   |    1 
 arch/i386/kernel/sysenter.c                        |  269 +
 arch/i386/kernel/time.c                            |    2 
 arch/i386/kernel/trampoline.S                      |   12 
 arch/i386/kernel/traps.c                           |   53 
 arch/i386/kernel/tsc.c                             |   13 
 arch/i386/kernel/verify_cpu.S                      |   65 
 arch/i386/kernel/vm86.c                            |    1 
 arch/i386/kernel/vmi.c                             |  131 
 arch/i386/kernel/vmiclock.c                        |  318 +
 arch/i386/kernel/vmitime.c                         |  482 -
 arch/i386/kernel/vmlinux.lds.S                     |   24 
 arch/i386/kernel/vsyscall.lds.S                    |    4 
 arch/i386/lib/bitops.c                             |    4 
 arch/i386/lib/checksum.S                           |   69 
 arch/i386/lib/getuser.S                            |   26 
 arch/i386/lib/msr-on-cpu.c                         |   73 
 arch/i386/lib/putuser.S                            |   39 
 arch/i386/lib/usercopy.c                           |    7 
 arch/i386/mach-default/setup.c                     |    2 
 arch/i386/mach-generic/bigsmp.c                    |    2 
 arch/i386/mach-generic/es7000.c                    |   41 
 arch/i386/mach-visws/setup.c                       |    2 
 arch/i386/mach-visws/visws_apic.c                  |    1 
 arch/i386/mach-voyager/setup.c                     |    8 
 arch/i386/mach-voyager/voyager_cat.c               |    4 
 arch/i386/mach-voyager/voyager_smp.c               |  114 
 arch/i386/mach-voyager/voyager_thread.c            |   70 
 arch/i386/mm/fault.c                               |   64 
 arch/i386/mm/highmem.c                             |   10 
 arch/i386/mm/hugetlbpage.c                         |    7 
 arch/i386/mm/init.c                                |  188 
 arch/i386/mm/pageattr.c                            |    6 
 arch/i386/mm/pgtable.c                             |   94 
 arch/i386/oprofile/nmi_int.c                       |    6 
 arch/i386/oprofile/nmi_timer_int.c                 |    3 
 arch/i386/pci/fixup.c                              |    2 
 arch/i386/pci/i386.c                               |    4 
 arch/i386/pci/init.c                               |    2 
 arch/i386/pci/mmconfig-shared.c                    |   25 
 arch/i386/power/cpu.c                              |    1 
 arch/i386/power/suspend.c                          |   14 
 arch/ia64/Kconfig                                  |   11 
 arch/ia64/defconfig                                |    1 
 arch/ia64/hp/sim/boot/fw-emu.c                     |    2 
 arch/ia64/hp/sim/simeth.c                          |    3 
 arch/ia64/ia32/ia32_ldt.c                          |    1 
 arch/ia64/ia32/ia32_signal.c                       |    1 
 arch/ia64/ia32/ia32_support.c                      |    6 
 arch/ia64/kernel/Makefile                          |    1 
 arch/ia64/kernel/crash.c                           |    4 
 arch/ia64/kernel/efi.c                             |   56 
 arch/ia64/kernel/entry.S                           |    7 
 arch/ia64/kernel/err_inject.c                      |  293 +
 arch/ia64/kernel/iosapic.c                         |    1 
 arch/ia64/kernel/irq_ia64.c                        |    1 
 arch/ia64/kernel/ivt.S                             |   19 
 arch/ia64/kernel/kprobes.c                         |   32 
 arch/ia64/kernel/mca.c                             |    3 
 arch/ia64/kernel/mca_asm.S                         |   24 
 arch/ia64/kernel/mca_drv.c                         |    1 
 arch/ia64/kernel/patch.c                           |   20 
 arch/ia64/kernel/perfmon.c                         |    1 
 arch/ia64/kernel/process.c                         |    3 
 arch/ia64/kernel/salinfo.c                         |    1 
 arch/ia64/kernel/setup.c                           |    7 
 arch/ia64/kernel/signal.c                          |    1 
 arch/ia64/kernel/smpboot.c                         |    1 
 arch/ia64/kernel/sys_ia64.c                        |    8 
 arch/ia64/kernel/time.c                            |    2 
 arch/ia64/kernel/traps.c                           |   18 
 arch/ia64/kernel/unaligned.c                       |    1 
 arch/ia64/kernel/vmlinux.lds.S                     |    7 
 arch/ia64/lib/csum_partial_copy.c                  |    2 
 arch/ia64/mm/discontig.c                           |    2 
 arch/ia64/mm/fault.c                               |    3 
 arch/ia64/mm/hugetlbpage.c                         |    9 
 arch/ia64/mm/init.c                                |   13 
 arch/ia64/mm/ioremap.c                             |   78 
 arch/ia64/pci/pci.c                                |    3 
 arch/ia64/sn/kernel/huberror.c                     |    1 
 arch/ia64/sn/kernel/msi_sn.c                       |    4 
 arch/ia64/sn/kernel/xpc_main.c                     |    4 
 arch/ia64/sn/kernel/xpnet.c                        |   19 
 arch/m32r/kernel/m32r_ksyms.c                      |    1 
 arch/m32r/kernel/signal.c                          |    1 
 arch/m32r/kernel/smpboot.c                         |    1 
 arch/m32r/kernel/sys_m32r.c                        |    1 
 arch/m32r/kernel/vmlinux.lds.S                     |    2 
 arch/m32r/mm/fault-nommu.c                         |    1 
 arch/m32r/mm/fault.c                               |    1 
 arch/m68k/Kconfig                                  |    3 
 arch/m68k/Makefile                                 |    2 
 arch/m68k/amiga/amiints.c                          |    2 
 arch/m68k/amiga/cia.c                              |    4 
 arch/m68k/amiga/config.c                           | 1091 +--
 arch/m68k/apollo/dn_ints.c                         |    2 
 arch/m68k/atari/Makefile                           |    1 
 arch/m68k/atari/ataints.c                          |    2 
 arch/m68k/atari/atakeyb.c                          |  730 ++
 arch/m68k/atari/atasound.h                         |   33 
 arch/m68k/atari/config.c                           |  998 +--
 arch/m68k/atari/debug.c                            |  482 +
 arch/m68k/kernel/entry.S                           |    2 
 arch/m68k/kernel/head.S                            |    2 
 arch/m68k/kernel/ints.c                            |    4 
 arch/m68k/kernel/ptrace.c                          |    1 
 arch/m68k/kernel/setup.c                           |  368 -
 arch/m68k/lib/checksum.c                           |    3 
 arch/m68k/mac/baboon.c                             |   32 
 arch/m68k/mac/config.c                             |  167 
 arch/m68k/mac/debug.c                              |  331 -
 arch/m68k/mac/macints.c                            |    2 
 arch/m68k/mac/oss.c                                |   18 
 arch/m68k/mac/psc.c                                |   21 
 arch/m68k/mac/via.c                                |  284 -
 arch/m68k/mvme16x/rtc.c                            |    1 
 arch/m68k/q40/config.c                             |  272 -
 arch/m68k/q40/q40ints.c                            |    2 
 arch/m68k/sun3/sun3ints.c                          |    4 
 arch/m68k/sun3x/prom.c                             |  132 
 arch/m68knommu/kernel/dma.c                        |    1 
 arch/m68knommu/kernel/ptrace.c                     |    1 
 arch/m68knommu/kernel/sys_m68k.c                   |    1 
 arch/mips/Kconfig                                  |   32 
 arch/mips/Makefile                                 |    6 
 arch/mips/basler/excite/excite_setup.c             |    2 
 arch/mips/cobalt/Makefile                          |    3 
 arch/mips/cobalt/buttons.c                         |   54 
 arch/mips/cobalt/console.c                         |    8 
 arch/mips/cobalt/irq.c                             |    2 
 arch/mips/cobalt/pci.c                             |   47 
 arch/mips/cobalt/reset.c                           |   11 
 arch/mips/cobalt/setup.c                           |   32 
 arch/mips/configs/jmr3927_defconfig                |  254 -
 arch/mips/configs/pnx8550-v2pci_defconfig          | 1540 ----
 arch/mips/configs/rbhma4500_defconfig              |   31 
 arch/mips/gt64120/wrppmc/pci.c                     |    4 
 arch/mips/jmr3927/common/prom.c                    |   12 
 arch/mips/jmr3927/common/puts.c                    |  122 
 arch/mips/jmr3927/rbhma3100/Makefile               |    1 
 arch/mips/jmr3927/rbhma3100/init.c                 |   16 
 arch/mips/jmr3927/rbhma3100/irq.c                  |  312 -
 arch/mips/jmr3927/rbhma3100/kgdb_io.c              |   54 
 arch/mips/jmr3927/rbhma3100/setup.c                |  157 
 arch/mips/kernel/asm-offsets.c                     |    1 
 arch/mips/kernel/early_printk.c                    |    5 
 arch/mips/kernel/i8259.c                           |    4 
 arch/mips/kernel/irixelf.c                         |    1 
 arch/mips/kernel/irixioctl.c                       |    1 
 arch/mips/kernel/irixsig.c                         |    1 
 arch/mips/kernel/kspd.c                            |    5 
 arch/mips/kernel/ptrace.c                          |    1 
 arch/mips/kernel/rtlx.c                            |    7 
 arch/mips/kernel/signal.c                          |    1 
 arch/mips/kernel/signal32.c                        |    1 
 arch/mips/kernel/signal_n32.c                      |    1 
 arch/mips/kernel/stacktrace.c                      |   22 
 arch/mips/kernel/syscall.c                         |    1 
 arch/mips/kernel/traps.c                           |    1 
 arch/mips/kernel/unaligned.c                       |    1 
 arch/mips/kernel/vmlinux.lds.S                     |    2 
 arch/mips/lib/iomap.c                              |    1 
 arch/mips/math-emu/dsemul.c                        |    1 
 arch/mips/mips-boards/generic/display.c            |    8 
 arch/mips/mips-boards/generic/pci.c                |    4 
 arch/mips/mips-boards/generic/reset.c              |   12 
 arch/mips/mips-boards/malta/malta_int.c            |    4 
 arch/mips/mips-boards/malta/malta_setup.c          |    4 
 arch/mips/mips-boards/sim/Makefile                 |    3 
 arch/mips/mips-boards/sim/sim_platform.c           |   35 
 arch/mips/mm/cache.c                               |    2 
 arch/mips/mm/fault.c                               |    1 
 arch/mips/mm/init.c                                |   25 
 arch/mips/pci/Makefile                             |    3 
 arch/mips/pci/fixup-jmr3927.c                      |   11 
 arch/mips/pci/ops-gt64111.c                        |  100 
 arch/mips/pci/ops-gt64120.c                        |  152 
 arch/mips/pci/ops-gt64xxx_pci0.c                   |  152 
 arch/mips/pci/ops-tx3927.c                         |  232 -
 arch/mips/pci/pci-lasat.c                          |    4 
 arch/mips/pci/pci-ocelot.c                         |    2 
 arch/mips/pci/pci.c                                |   25 
 arch/mips/pmc-sierra/msp71xx/msp_serial.c          |  165 
 arch/mips/sgi-ip22/ip22-nvram.c                    |   24 
 arch/mips/sgi-ip22/ip22-time.c                     |   14 
 arch/mips/sgi-ip27/ip27-irq.c                      |    1 
 arch/mips/sibyte/Kconfig                           |    2 
 arch/mips/sibyte/common/Makefile                   |    5 
 arch/mips/sibyte/common/sb_tbprof.c                |  601 ++
 arch/mips/sibyte/sb1250/Makefile                   |    1 
 arch/mips/sibyte/sb1250/bcm1250_tbprof.c           |  571 -
 arch/mips/sni/irq.c                                |    2 
 arch/mips/sni/pcimt.c                              |  105 
 arch/mips/sni/pcit.c                               |  122 
 .../toshiba_rbtx4927/toshiba_rbtx4927_setup.c      |   19 
 arch/mips/tx4938/toshiba_rbtx4938/setup.c          |   20 
 arch/mips/vr41xx/Kconfig                           |   92 
 arch/parisc/configs/c3000_defconfig                |    1 
 arch/parisc/hpux/fs.c                              |    1 
 arch/parisc/hpux/ioctl.c                           |    1 
 arch/parisc/kernel/irq.c                           |    2 
 arch/parisc/kernel/ptrace.c                        |    1 
 arch/parisc/kernel/signal.c                        |    1 
 arch/parisc/kernel/signal32.c                      |    1 
 arch/parisc/kernel/sys_parisc.c                    |    6 
 arch/parisc/kernel/traps.c                         |    1 
 arch/parisc/kernel/unwind.c                        |    5 
 arch/parisc/kernel/vmlinux.lds.S                   |    2 
 arch/powerpc/Kconfig                               |  502 -
 arch/powerpc/Kconfig.debug                         |   32 
 arch/powerpc/Makefile                              |    9 
 arch/powerpc/boot/.gitignore                       |    3 
 arch/powerpc/boot/44x.c                            |   40 
 arch/powerpc/boot/44x.h                            |   16 
 arch/powerpc/boot/Makefile                         |  143 
 arch/powerpc/boot/crt0.S                           |   37 
 arch/powerpc/boot/cuboot-83xx.c                    |   68 
 arch/powerpc/boot/cuboot-85xx.c                    |   69 
 arch/powerpc/boot/cuboot-ebony.c                   |   42 
 arch/powerpc/boot/dcr.h                            |   87 
 arch/powerpc/boot/devtree.c                        |  307 +
 arch/powerpc/boot/dts/ebony.dts                    |  307 +
 arch/powerpc/boot/dts/holly.dts                    |  198 +
 arch/powerpc/boot/dts/kuroboxHD.dts                |    7 
 arch/powerpc/boot/dts/kuroboxHG.dts                |    7 
 arch/powerpc/boot/dts/lite5200.dts                 |   12 
 arch/powerpc/boot/dts/lite5200b.dts                |   12 
 arch/powerpc/boot/dts/mpc7448hpc2.dts              |    1 
 arch/powerpc/boot/dts/mpc8272ads.dts               |    1 
 arch/powerpc/boot/dts/mpc8313erdb.dts              |    1 
 arch/powerpc/boot/dts/mpc832x_mds.dts              |    3 
 arch/powerpc/boot/dts/mpc832x_rdb.dts              |  289 +
 arch/powerpc/boot/dts/mpc8349emitx.dts             |    1 
 arch/powerpc/boot/dts/mpc8349emitxgp.dts           |    1 
 arch/powerpc/boot/dts/mpc834x_mds.dts              |    1 
 arch/powerpc/boot/dts/mpc836x_mds.dts              |    5 
 arch/powerpc/boot/dts/mpc8540ads.dts               |    1 
 arch/powerpc/boot/dts/mpc8541cds.dts               |    1 
 arch/powerpc/boot/dts/mpc8544ds.dts                |  136 
 arch/powerpc/boot/dts/mpc8548cds.dts               |    1 
 arch/powerpc/boot/dts/mpc8555cds.dts               |    1 
 arch/powerpc/boot/dts/mpc8560ads.dts               |    1 
 arch/powerpc/boot/dts/mpc8568mds.dts               |    7 
 arch/powerpc/boot/dts/mpc8641_hpcn.dts             |   25 
 arch/powerpc/boot/dts/mpc866ads.dts                |    1 
 arch/powerpc/boot/dts/mpc885ads.dts                |    1 
 arch/powerpc/boot/ebony.c                          |  129 
 arch/powerpc/boot/elf.h                            |    8 
 arch/powerpc/boot/elf_util.c                       |   76 
 arch/powerpc/boot/flatdevtree.c                    |  199 -
 arch/powerpc/boot/flatdevtree.h                    |    7 
 arch/powerpc/boot/flatdevtree_misc.c               |   42 
 arch/powerpc/boot/gunzip_util.c                    |  206 +
 arch/powerpc/boot/gunzip_util.h                    |   45 
 arch/powerpc/boot/holly.c                          |   38 
 arch/powerpc/boot/main.c                           |  369 -
 arch/powerpc/boot/mktree.c                         |   10 
 arch/powerpc/boot/ns16550.c                        |    9 
 arch/powerpc/boot/of.c                             |   21 
 arch/powerpc/boot/ops.h                            |  103 
 arch/powerpc/boot/ppcboot.h                        |  108 
 arch/powerpc/boot/reg.h                            |   22 
 arch/powerpc/boot/simple_alloc.c                   |   31 
 arch/powerpc/boot/stdio.h                          |    5 
 arch/powerpc/boot/treeboot-ebony.c                 |   34 
 arch/powerpc/boot/wrapper                          |   65 
 arch/powerpc/boot/zImage.coff.lds.S                |    3 
 arch/powerpc/boot/zImage.lds.S                     |    1 
 arch/powerpc/configs/cell_defconfig                |   57 
 arch/powerpc/configs/ebony_defconfig               |  905 ++
 arch/powerpc/configs/g5_defconfig                  |    2 
 arch/powerpc/configs/holly_defconfig               | 1070 +++
 arch/powerpc/configs/maple_defconfig               |    2 
 arch/powerpc/configs/mpc832x_mds_defconfig         |   67 
 arch/powerpc/configs/mpc832x_rdb_defconfig         | 1300 +++
 arch/powerpc/configs/mpc836x_mds_defconfig         |   42 
 arch/powerpc/configs/mpc8544_ds_defconfig          | 1077 +++
 arch/powerpc/configs/ppc64_defconfig               |    2 
 arch/powerpc/configs/ps3_defconfig                 |  329 +
 arch/powerpc/kernel/Makefile                       |    7 
 arch/powerpc/kernel/align.c                        |   56 
 arch/powerpc/kernel/asm-offsets.c                  |    6 
 arch/powerpc/kernel/btext.c                        |   22 
 arch/powerpc/kernel/cpu_setup_pa6t.S               |    2 
 arch/powerpc/kernel/cputable.c                     |   14 
 arch/powerpc/kernel/entry_32.S                     |    1 
 arch/powerpc/kernel/head_44x.S                     |   48 
 arch/powerpc/kernel/head_64.S                      |   16 
 arch/powerpc/kernel/ibmebus.c                      |  288 -
 arch/powerpc/kernel/idle.c                         |    5 
 arch/powerpc/kernel/idle_power4.S                  |   21 
 arch/powerpc/kernel/iommu.c                        |   35 
 arch/powerpc/kernel/irq.c                          |   40 
 arch/powerpc/kernel/kprobes.c                      |   77 
 arch/powerpc/kernel/legacy_serial.c                |   41 
 arch/powerpc/kernel/lparcfg.c                      |   58 
 arch/powerpc/kernel/machine_kexec_64.c             |   14 
 arch/powerpc/kernel/misc_32.S                      |    4 
 arch/powerpc/kernel/msi.c                          |   38 
 arch/powerpc/kernel/of_device.c                    |  115 
 arch/powerpc/kernel/of_platform.c                  |    9 
 arch/powerpc/kernel/pci_32.c                       |   44 
 arch/powerpc/kernel/pci_64.c                       |   43 
 arch/powerpc/kernel/pci_dn.c                       |    9 
 arch/powerpc/kernel/ppc_ksyms.c                    |    4 
 arch/powerpc/kernel/process.c                      |   55 
 arch/powerpc/kernel/prom.c                         |  167 
 arch/powerpc/kernel/prom_init.c                    |   67 
 arch/powerpc/kernel/prom_parse.c                   |   76 
 arch/powerpc/kernel/ptrace.c                       |    1 
 arch/powerpc/kernel/rtas-proc.c                    |    4 
 arch/powerpc/kernel/rtas.c                         |   19 
 arch/powerpc/kernel/rtas_pci.c                     |   14 
 arch/powerpc/kernel/setup-common.c                 |   68 
 arch/powerpc/kernel/setup_32.c                     |   17 
 arch/powerpc/kernel/setup_64.c                     |   15 
 arch/powerpc/kernel/signal_32.c                    |    1 
 arch/powerpc/kernel/signal_64.c                    |    1 
 arch/powerpc/kernel/smp.c                          |   77 
 arch/powerpc/kernel/suspend.c                      |   24 
 arch/powerpc/kernel/swsusp.c                       |   43 
 arch/powerpc/kernel/swsusp_64.c                    |   24 
 arch/powerpc/kernel/swsusp_asm64.S                 |  228 +
 arch/powerpc/kernel/sys_ppc32.c                    |    4 
 arch/powerpc/kernel/syscalls.c                     |    1 
 arch/powerpc/kernel/sysfs.c                        |   19 
 arch/powerpc/kernel/time.c                         |    2 
 arch/powerpc/kernel/traps.c                        |   92 
 arch/powerpc/kernel/udbg.c                         |   22 
 arch/powerpc/kernel/udbg_16550.c                   |   23 
 arch/powerpc/kernel/vdso.c                         |    1 
 arch/powerpc/kernel/vio.c                          |   23 
 arch/powerpc/kernel/vmlinux.lds.S                  |    6 
 arch/powerpc/lib/Makefile                          |    5 
 arch/powerpc/lib/copyuser_64.S                     |    6 
 arch/powerpc/lib/dma-noncoherent.c                 |    4 
 arch/powerpc/lib/locks.c                           |    4 
 arch/powerpc/lib/mem_64.S                          |    6 
 arch/powerpc/lib/memcpy_64.S                       |    6 
 arch/powerpc/lib/sstep.c                           |   45 
 arch/powerpc/lib/strcase.c                         |   25 
 arch/powerpc/mm/44x_mmu.c                          |   82 
 arch/powerpc/mm/fault.c                            |   44 
 arch/powerpc/mm/hash_low_32.S                      |   22 
 arch/powerpc/mm/hash_low_64.S                      |    5 
 arch/powerpc/mm/hash_native_64.c                   |   86 
 arch/powerpc/mm/hash_utils_64.c                    |  127 
 arch/powerpc/mm/hugetlbpage.c                      |   41 
 arch/powerpc/mm/init_32.c                          |    4 
 arch/powerpc/mm/init_64.c                          |    6 
 arch/powerpc/mm/lmb.c                              |    4 
 arch/powerpc/mm/mem.c                              |    4 
 arch/powerpc/mm/mmu_decl.h                         |    8 
 arch/powerpc/mm/numa.c                             |   24 
 arch/powerpc/mm/pgtable_32.c                       |  104 
 arch/powerpc/mm/ppc_mmu_32.c                       |    4 
 arch/powerpc/mm/stab.c                             |    2 
 arch/powerpc/mm/tlb_64.c                           |   68 
 arch/powerpc/oprofile/Makefile                     |    2 
 arch/powerpc/oprofile/common.c                     |    3 
 arch/powerpc/oprofile/op_model_cell.c              |    3 
 arch/powerpc/oprofile/op_model_pa6t.c              |  234 +
 arch/powerpc/platforms/44x/44x.h                   |    8 
 arch/powerpc/platforms/44x/Kconfig                 |   56 
 arch/powerpc/platforms/44x/Makefile                |    2 
 arch/powerpc/platforms/44x/ebony.c                 |   73 
 arch/powerpc/platforms/44x/misc_44x.S              |   57 
 arch/powerpc/platforms/4xx/Kconfig                 |  372 -
 arch/powerpc/platforms/52xx/Kconfig                |   36 
 arch/powerpc/platforms/52xx/Makefile               |    2 
 arch/powerpc/platforms/52xx/efika.c                |   30 
 arch/powerpc/platforms/52xx/lite5200.c             |   40 
 arch/powerpc/platforms/52xx/mpc52xx_common.c       |    2 
 arch/powerpc/platforms/52xx/mpc52xx_pci.c          |    2 
 arch/powerpc/platforms/52xx/mpc52xx_pm.c           |  191 
 arch/powerpc/platforms/52xx/mpc52xx_sleep.S        |  154 
 arch/powerpc/platforms/82xx/Kconfig                |   45 
 arch/powerpc/platforms/82xx/mpc82xx.c              |    6 
 arch/powerpc/platforms/82xx/mpc82xx_ads.c          |   12 
 arch/powerpc/platforms/83xx/Kconfig                |   15 
 arch/powerpc/platforms/83xx/Makefile               |    1 
 arch/powerpc/platforms/83xx/mpc832x_mds.c          |    2 
 arch/powerpc/platforms/83xx/mpc832x_mds.h          |   19 
 arch/powerpc/platforms/83xx/mpc832x_rdb.c          |  139 
 arch/powerpc/platforms/83xx/mpc834x_itx.h          |   23 
 arch/powerpc/platforms/83xx/mpc836x_mds.c          |    1 
 arch/powerpc/platforms/83xx/pci.c                  |    2 
 arch/powerpc/platforms/85xx/Kconfig                |   38 
 arch/powerpc/platforms/85xx/Makefile               |    1 
 arch/powerpc/platforms/85xx/mpc8544_ds.c           |  144 
 arch/powerpc/platforms/85xx/mpc85xx_ads.c          |    2 
 arch/powerpc/platforms/85xx/mpc85xx_cds.c          |    4 
 arch/powerpc/platforms/85xx/mpc85xx_mds.c          |    3 
 arch/powerpc/platforms/85xx/pci.c                  |    2 
 arch/powerpc/platforms/86xx/Kconfig                |   18 
 arch/powerpc/platforms/86xx/Makefile               |    2 
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c         |    6 
 arch/powerpc/platforms/86xx/mpc86xx_pcie.c         |  173 
 arch/powerpc/platforms/86xx/pci.c                  |    4 
 arch/powerpc/platforms/8xx/Kconfig                 |   67 
 arch/powerpc/platforms/8xx/m8xx_setup.c            |    8 
 arch/powerpc/platforms/8xx/mpc86xads.h             |    2 
 arch/powerpc/platforms/8xx/mpc86xads_setup.c       |    4 
 arch/powerpc/platforms/8xx/mpc885ads.h             |    2 
 arch/powerpc/platforms/8xx/mpc885ads_setup.c       |    4 
 arch/powerpc/platforms/Kconfig                     |  260 +
 arch/powerpc/platforms/Makefile                    |    3 
 arch/powerpc/platforms/cell/Kconfig                |   24 
 arch/powerpc/platforms/cell/cbe_cpufreq.c          |  112 
 arch/powerpc/platforms/cell/cbe_regs.c             |  168 
 arch/powerpc/platforms/cell/cbe_regs.h             |    5 
 arch/powerpc/platforms/cell/cbe_thermal.c          |  181 
 arch/powerpc/platforms/cell/interrupt.c            |   10 
 arch/powerpc/platforms/cell/io-workarounds.c       |    2 
 arch/powerpc/platforms/cell/iommu.c                |   16 
 arch/powerpc/platforms/cell/ras.c                  |  160 
 arch/powerpc/platforms/cell/setup.c                |   14 
 arch/powerpc/platforms/cell/spider-pic.c           |   12 
 arch/powerpc/platforms/cell/spu_base.c             |  163 
 arch/powerpc/platforms/cell/spu_coredump.c         |   34 
 arch/powerpc/platforms/cell/spu_manage.c           |   18 
 arch/powerpc/platforms/cell/spufs/Makefile         |    2 
 arch/powerpc/platforms/cell/spufs/backing_ops.c    |    7 
 arch/powerpc/platforms/cell/spufs/context.c        |   45 
 arch/powerpc/platforms/cell/spufs/coredump.c       |   19 
 arch/powerpc/platforms/cell/spufs/fault.c          |  211 +
 arch/powerpc/platforms/cell/spufs/file.c           |  152 
 arch/powerpc/platforms/cell/spufs/hw_ops.c         |   10 
 arch/powerpc/platforms/cell/spufs/inode.c          |   47 
 arch/powerpc/platforms/cell/spufs/run.c            |  123 
 arch/powerpc/platforms/cell/spufs/sched.c          |  114 
 arch/powerpc/platforms/cell/spufs/spufs.h          |   34 
 arch/powerpc/platforms/cell/spufs/switch.c         |    9 
 arch/powerpc/platforms/celleb/Kconfig              |    9 
 arch/powerpc/platforms/celleb/iommu.c              |    6 
 arch/powerpc/platforms/celleb/pci.c                |   18 
 arch/powerpc/platforms/celleb/setup.c              |   12 
 arch/powerpc/platforms/chrp/Kconfig                |   11 
 arch/powerpc/platforms/chrp/nvram.c                |    2 
 arch/powerpc/platforms/chrp/pci.c                  |   27 
 arch/powerpc/platforms/chrp/setup.c                |   54 
 arch/powerpc/platforms/chrp/smp.c                  |    1 
 arch/powerpc/platforms/chrp/time.c                 |   13 
 arch/powerpc/platforms/embedded6xx/Kconfig         |  274 -
 arch/powerpc/platforms/embedded6xx/Makefile        |    1 
 arch/powerpc/platforms/embedded6xx/holly.c         |  317 +
 arch/powerpc/platforms/embedded6xx/linkstation.c   |    8 
 arch/powerpc/platforms/embedded6xx/ls_uart.c       |    4 
 arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c  |   34 
 arch/powerpc/platforms/iseries/Kconfig             |    4 
 arch/powerpc/platforms/iseries/iommu.c             |    4 
 arch/powerpc/platforms/iseries/irq.c               |    4 
 arch/powerpc/platforms/iseries/pci.c               |    5 
 arch/powerpc/platforms/iseries/setup.c             |   10 
 arch/powerpc/platforms/iseries/smp.c               |    1 
 arch/powerpc/platforms/iseries/viopath.c           |    3 
 arch/powerpc/platforms/maple/Kconfig               |   17 
 arch/powerpc/platforms/maple/pci.c                 |   20 
 arch/powerpc/platforms/maple/setup.c               |   19 
 arch/powerpc/platforms/pasemi/Kconfig              |   19 
 arch/powerpc/platforms/pasemi/Makefile             |    3 
 arch/powerpc/platforms/pasemi/cpufreq.c            |  312 +
 arch/powerpc/platforms/pasemi/gpio_mdio.c          |  339 +
 arch/powerpc/platforms/pasemi/idle.c               |    9 
 arch/powerpc/platforms/pasemi/iommu.c              |    6 
 arch/powerpc/platforms/pasemi/pasemi.h             |    8 
 arch/powerpc/platforms/pasemi/pci.c                |   29 
 arch/powerpc/platforms/pasemi/setup.c              |   34 
 arch/powerpc/platforms/powermac/Kconfig            |   20 
 arch/powerpc/platforms/powermac/backlight.c        |    9 
 arch/powerpc/platforms/powermac/cpufreq_32.c       |   25 
 arch/powerpc/platforms/powermac/cpufreq_64.c       |   24 
 arch/powerpc/platforms/powermac/feature.c          |  127 
 arch/powerpc/platforms/powermac/low_i2c.c          |   17 
 arch/powerpc/platforms/powermac/nvram.c            |    4 
 arch/powerpc/platforms/powermac/pci.c              |   71 
 arch/powerpc/platforms/powermac/pfunc_base.c       |    2 
 arch/powerpc/platforms/powermac/pfunc_core.c       |    5 
 arch/powerpc/platforms/powermac/pic.c              |   10 
 arch/powerpc/platforms/powermac/setup.c            |  182 
 arch/powerpc/platforms/powermac/smp.c              |   30 
 arch/powerpc/platforms/powermac/time.c             |   38 
 arch/powerpc/platforms/powermac/udbg_scc.c         |    6 
 arch/powerpc/platforms/prep/Kconfig                |    9 
 arch/powerpc/platforms/ps3/Kconfig                 |   16 
 arch/powerpc/platforms/ps3/htab.c                  |    5 
 arch/powerpc/platforms/ps3/interrupt.c             |  234 -
 arch/powerpc/platforms/ps3/mm.c                    |    1 
 arch/powerpc/platforms/ps3/setup.c                 |    7 
 arch/powerpc/platforms/ps3/smp.c                   |    6 
 arch/powerpc/platforms/ps3/spu.c                   |   18 
 arch/powerpc/platforms/pseries/Kconfig             |   10 
 arch/powerpc/platforms/pseries/Makefile            |    6 
 arch/powerpc/platforms/pseries/eeh.c               |  234 -
 arch/powerpc/platforms/pseries/eeh_driver.c        |   78 
 arch/powerpc/platforms/pseries/eeh_event.c         |    8 
 arch/powerpc/platforms/pseries/firmware.c          |    2 
 arch/powerpc/platforms/pseries/hotplug-cpu.c       |    4 
 arch/powerpc/platforms/pseries/iommu.c             |   73 
 arch/powerpc/platforms/pseries/lpar.c              |   10 
 arch/powerpc/platforms/pseries/msi.c               |  270 +
 arch/powerpc/platforms/pseries/nvram.c             |    2 
 arch/powerpc/platforms/pseries/pci.c               |    3 
 arch/powerpc/platforms/pseries/pci_dlpar.c         |    2 
 arch/powerpc/platforms/pseries/power.c             |    8 
 arch/powerpc/platforms/pseries/ras.c               |    3 
 arch/powerpc/platforms/pseries/rtasd.c             |    2 
 arch/powerpc/platforms/pseries/setup.c             |   46 
 arch/powerpc/platforms/pseries/xics.c              |   21 
 arch/powerpc/sysdev/Makefile                       |   10 
 arch/powerpc/sysdev/dart_iommu.c                   |   50 
 arch/powerpc/sysdev/dcr.c                          |   14 
 arch/powerpc/sysdev/fsl_pcie.c                     |  171 
 arch/powerpc/sysdev/fsl_pcie.h                     |   94 
 arch/powerpc/sysdev/fsl_soc.c                      |   90 
 arch/powerpc/sysdev/mpic.c                         |  192 
 arch/powerpc/sysdev/mpic.h                         |   38 
 arch/powerpc/sysdev/mpic_msi.c                     |  183 
 arch/powerpc/sysdev/mpic_u3msi.c                   |  186 
 arch/powerpc/sysdev/pmi.c                          |   29 
 arch/powerpc/sysdev/qe_lib/Kconfig                 |   10 
 arch/powerpc/sysdev/qe_lib/qe.c                    |    4 
 arch/powerpc/sysdev/qe_lib/qe_io.c                 |    6 
 arch/powerpc/sysdev/qe_lib/ucc_fast.c              |    3 
 arch/powerpc/sysdev/qe_lib/ucc_slow.c              |    4 
 arch/powerpc/sysdev/rom.c                          |   32 
 arch/powerpc/sysdev/timer.c                        |   71 
 arch/powerpc/sysdev/tsi108_dev.c                   |   21 
 arch/powerpc/sysdev/tsi108_pci.c                   |   14 
 arch/powerpc/sysdev/uic.c                          |  342 +
 arch/powerpc/xmon/xmon.c                           |   14 
 arch/ppc/8260_io/enet.c                            |    2 
 arch/ppc/8260_io/fcc_enet.c                        |    2 
 arch/ppc/8xx_io/Kconfig                            |    4 
 arch/ppc/8xx_io/Makefile                           |    1 
 arch/ppc/8xx_io/cs4218.h                           |  166 
 arch/ppc/8xx_io/cs4218_tdm.c                       | 2833 -------
 arch/ppc/8xx_io/enet.c                             |    2 
 arch/ppc/8xx_io/fec.c                              |    1 
 arch/ppc/boot/common/misc-common.c                 |   15 
 arch/ppc/boot/simple/Makefile                      |    1 
 arch/ppc/boot/simple/uartlite_tty.c                |   37 
 arch/ppc/kernel/asm-offsets.c                      |    1 
 arch/ppc/kernel/entry.S                            |    1 
 arch/ppc/kernel/ppc_htab.c                         |    1 
 arch/ppc/kernel/ppc_ksyms.c                        |    2 
 arch/ppc/kernel/smp.c                              |    1 
 arch/ppc/kernel/vmlinux.lds.S                      |    2 
 arch/ppc/lib/Makefile                              |    2 
 arch/ppc/lib/strcase.c                             |   24 
 arch/ppc/platforms/4xx/Kconfig                     |   15 
 arch/ppc/platforms/4xx/Makefile                    |    1 
 arch/ppc/platforms/4xx/ocotea.c                    |    4 
 arch/ppc/platforms/4xx/taishan.c                   |    2 
 arch/ppc/platforms/4xx/virtex.c                    |   56 
 arch/ppc/platforms/4xx/virtex.h                    |   34 
 arch/ppc/platforms/4xx/xilinx_ml300.c              |   65 
 arch/ppc/platforms/4xx/xilinx_ml300.h              |   45 
 arch/ppc/platforms/4xx/xilinx_ml403.c              |   66 
 arch/ppc/platforms/4xx/xilinx_ml403.h              |   49 
 arch/ppc/platforms/4xx/xparameters/xparameters.h   |   60 
 arch/ppc/platforms/rpxclassic.h                    |    4 
 arch/ppc/platforms/rpxhiox.h                       |   41 
 arch/ppc/platforms/rpxlite.h                       |    4 
 arch/ppc/syslib/Makefile                           |    3 
 arch/ppc/syslib/cpc710.h                           |   81 
 arch/ppc/syslib/m8xx_setup.c                       |    2 
 arch/ppc/syslib/ppc4xx_sgdma.c                     |    2 
 arch/ppc/syslib/virtex_devices.c                   |  233 +
 arch/ppc/syslib/virtex_devices.h                   |   34 
 arch/s390/Kconfig                                  |   16 
 arch/s390/Makefile                                 |    5 
 arch/s390/appldata/appldata_base.c                 |   38 
 arch/s390/appldata/appldata_net_sum.c              |    5 
 arch/s390/crypto/aes_s390.c                        |   15 
 arch/s390/crypto/sha1_s390.c                       |  129 
 arch/s390/crypto/sha256_s390.c                     |   38 
 arch/s390/defconfig                                |    3 
 arch/s390/kernel/Makefile                          |    2 
 arch/s390/kernel/compat_linux.c                    |   60 
 arch/s390/kernel/compat_signal.c                   |   15 
 arch/s390/kernel/dis.c                             | 1278 +++
 arch/s390/kernel/early.c                           |    7 
 arch/s390/kernel/entry.S                           |   87 
 arch/s390/kernel/entry64.S                         |  100 
 arch/s390/kernel/head64.S                          |   72 
 arch/s390/kernel/ipl.c                             |  285 -
 arch/s390/kernel/kprobes.c                         |   30 
 arch/s390/kernel/module.c                          |    4 
 arch/s390/kernel/process.c                         |   83 
 arch/s390/kernel/setup.c                           |  149 
 arch/s390/kernel/signal.c                          |   11 
 arch/s390/kernel/smp.c                             |  370 +
 arch/s390/kernel/stacktrace.c                      |   18 
 arch/s390/kernel/sys_s390.c                        |   21 
 arch/s390/kernel/syscalls.S                        |   14 
 arch/s390/kernel/time.c                            |   35 
 arch/s390/kernel/traps.c                           |   89 
 arch/s390/kernel/vmlinux.lds.S                     |   12 
 arch/s390/kernel/vtime.c                           |   16 
 arch/s390/lib/Makefile                             |    2 
 arch/s390/lib/div64.c                              |    2 
 arch/s390/mm/fault.c                               |  341 -
 arch/sh/Kconfig                                    |   97 
 arch/sh/Kconfig.debug                              |   20 
 arch/sh/Makefile                                   |    6 
 arch/sh/boards/hp6xx/Makefile                      |    4 
 arch/sh/boards/hp6xx/pm.c                          |    8 
 arch/sh/boards/hp6xx/setup.c                       |   67 
 arch/sh/boards/landisk/Makefile                    |    2 
 arch/sh/boards/landisk/gio.c                       |  167 
 arch/sh/boards/landisk/io.c                        |  250 -
 arch/sh/boards/landisk/irq.c                       |   83 
 arch/sh/boards/landisk/landisk_pwb.c               |  346 -
 arch/sh/boards/landisk/psw.c                       |  143 
 arch/sh/boards/landisk/rtc.c                       |   91 
 arch/sh/boards/landisk/setup.c                     |  163 
 arch/sh/boards/lboxre2/Makefile                    |    5 
 arch/sh/boards/lboxre2/irq.c                       |   31 
 arch/sh/boards/lboxre2/setup.c                     |   85 
 arch/sh/boards/renesas/r7780rp/Kconfig             |   18 
 arch/sh/boards/renesas/r7780rp/Makefile            |    6 
 arch/sh/boards/renesas/r7780rp/irq-r7780rp.c       |   21 
 arch/sh/boards/renesas/r7780rp/irq-r7785rp.c       |   29 
 arch/sh/boards/renesas/r7780rp/irq.c               |   25 
 arch/sh/boards/renesas/r7780rp/setup.c             |   78 
 arch/sh/boards/se/770x/io.c                        |    2 
 arch/sh/boards/se/770x/irq.c                       |   57 
 arch/sh/boards/se/770x/setup.c                     |   30 
 arch/sh/boards/se/7722/Makefile                    |   10 
 arch/sh/boards/se/7722/irq.c                       |  101 
 arch/sh/boards/se/7722/setup.c                     |  148 
 arch/sh/boards/se/7751/setup.c                     |  148 
 arch/sh/boards/se/7780/Makefile                    |   10 
 arch/sh/boards/se/7780/irq.c                       |   89 
 arch/sh/boards/se/7780/setup.c                     |  122 
 arch/sh/configs/lboxre2_defconfig                  | 1271 +++
 arch/sh/configs/r7780rp_defconfig                  |  108 
 arch/sh/configs/r7785rp_defconfig                  | 1334 +++
 arch/sh/configs/se7705_defconfig                   |  106 
 arch/sh/configs/se7712_defconfig                   | 1088 +++
 arch/sh/configs/se7722_defconfig                   |  980 ++
 arch/sh/configs/se7780_defconfig                   | 1309 +++
 arch/sh/drivers/Kconfig                            |   10 
 arch/sh/drivers/heartbeat.c                        |   13 
 arch/sh/drivers/pci/Makefile                       |    5 
 arch/sh/drivers/pci/fixups-lboxre2.c               |   41 
 arch/sh/drivers/pci/fixups-se7780.c                |   60 
 arch/sh/drivers/pci/ops-landisk.c                  |    4 
 arch/sh/drivers/pci/ops-lboxre2.c                  |   63 
 arch/sh/drivers/pci/ops-r7780rp.c                  |   27 
 arch/sh/drivers/pci/ops-se7780.c                   |   96 
 arch/sh/drivers/pci/ops-sh4.c                      |    6 
 arch/sh/drivers/pci/pci-sh4.h                      |    2 
 arch/sh/drivers/pci/pci-sh7751.c                   |   15 
 arch/sh/drivers/pci/pci-sh7780.c                   |   45 
 arch/sh/drivers/pci/pci-sh7780.h                   |   19 
 arch/sh/drivers/pci/pci-st40.c                     |    1 
 arch/sh/kernel/Makefile                            |    1 
 arch/sh/kernel/cf-enabler.c                        |   28 
 arch/sh/kernel/cpu/clock.c                         |  102 
 arch/sh/kernel/cpu/init.c                          |   19 
 arch/sh/kernel/cpu/irq/Makefile                    |    2 
 arch/sh/kernel/cpu/irq/intc2.c                     |    3 
 arch/sh/kernel/cpu/irq/pint.c                      |   56 
 arch/sh/kernel/cpu/sh3/Makefile                    |    1 
 arch/sh/kernel/cpu/sh3/probe.c                     |    3 
 arch/sh/kernel/cpu/sh3/setup-sh7705.c              |   54 
 arch/sh/kernel/cpu/sh3/setup-sh7709.c              |   29 
 arch/sh/kernel/cpu/sh3/setup-sh7710.c              |   60 
 arch/sh/kernel/cpu/sh4/clock-sh4-202.c             |    3 
 arch/sh/kernel/cpu/sh4/probe.c                     |    8 
 arch/sh/kernel/cpu/sh4a/Makefile                   |    4 
 arch/sh/kernel/cpu/sh4a/clock-sh7722.c             |  600 ++
 arch/sh/kernel/cpu/sh4a/clock-sh7785.c             |  162 
 arch/sh/kernel/cpu/sh4a/setup-sh7785.c             |  103 
 arch/sh/kernel/crash_dump.c                        |   46 
 arch/sh/kernel/early_printk.c                      |   18 
 arch/sh/kernel/irq.c                               |    5 
 arch/sh/kernel/kgdb_stub.c                         |  490 -
 arch/sh/kernel/machine_kexec.c                     |   29 
 arch/sh/kernel/process.c                           |   14 
 arch/sh/kernel/ptrace.c                            |    1 
 arch/sh/kernel/setup.c                             |  267 -
 arch/sh/kernel/sh_ksyms.c                          |    2 
 arch/sh/kernel/signal.c                            |    1 
 arch/sh/kernel/stacktrace.c                        |    9 
 arch/sh/kernel/sys_sh.c                            |    1 
 arch/sh/kernel/timers/timer-cmt.c                  |    2 
 arch/sh/kernel/timers/timer-mtu2.c                 |    2 
 arch/sh/kernel/timers/timer-tmu.c                  |    6 
 arch/sh/kernel/traps.c                             |   73 
 arch/sh/kernel/vmlinux.lds.S                       |   49 
 arch/sh/lib/Makefile                               |    4 
 arch/sh/lib/strcasecmp.c                           |   26 
 arch/sh/lib/udivdi3.c                              |   16 
 arch/sh/mm/Kconfig                                 |   20 
 arch/sh/mm/fault-nommu.c                           |    1 
 arch/sh/mm/fault.c                                 |   39 
 arch/sh/mm/hugetlbpage.c                           |    1 
 arch/sh/mm/init.c                                  |  197 -
 arch/sh/mm/pmb.c                                   |    6 
 arch/sh/tools/mach-types                           |    2 
 arch/sh64/kernel/early_printk.c                    |    8 
 arch/sh64/kernel/irq.c                             |    1 
 arch/sh64/kernel/pci_sh5.c                         |    1 
 arch/sh64/kernel/sh_ksyms.c                        |    1 
 arch/sh64/kernel/signal.c                          |    1 
 arch/sh64/kernel/sys_sh64.c                        |    1 
 arch/sh64/kernel/traps.c                           |    1 
 arch/sh64/kernel/unwind.c                          |    6 
 arch/sh64/kernel/vmlinux.lds.S                     |    2 
 arch/sh64/mach-cayman/iomap.c                      |    1 
 arch/sh64/mm/fault.c                               |    1 
 arch/sh64/mm/hugetlbpage.c                         |    1 
 arch/sh64/mm/tlbmiss.c                             |    1 
 arch/sparc/kernel/ebus.c                           |   14 
 arch/sparc/kernel/head.S                           |    2 
 arch/sparc/kernel/irq.c                            |    1 
 arch/sparc/kernel/of_device.c                      |   21 
 arch/sparc/kernel/pcic.c                           |    4 
 arch/sparc/kernel/process.c                        |    1 
 arch/sparc/kernel/prom.c                           |   19 
 arch/sparc/kernel/setup.c                          |    2 
 arch/sparc/kernel/signal.c                         |    1 
 arch/sparc/kernel/smp.c                            |    1 
 arch/sparc/kernel/sun4d_irq.c                      |    1 
 arch/sparc/kernel/sun4d_smp.c                      |    1 
 arch/sparc/kernel/sun4m_smp.c                      |    3 
 arch/sparc/kernel/sunos_ioctl.c                    |    1 
 arch/sparc/kernel/sys_solaris.c                    |    1 
 arch/sparc/kernel/time.c                           |    2 
 arch/sparc/kernel/traps.c                          |    2 
 arch/sparc/kernel/vmlinux.lds.S                    |    2 
 arch/sparc/lib/bitext.c                            |    1 
 arch/sparc/mm/fault.c                              |    3 
 arch/sparc/mm/srmmu.c                              |    2 
 arch/sparc64/Kconfig                               |   18 
 arch/sparc64/defconfig                             |   71 
 arch/sparc64/kernel/Makefile                       |    2 
 arch/sparc64/kernel/central.c                      |   18 
 arch/sparc64/kernel/chmc.c                         |    4 
 arch/sparc64/kernel/ebus.c                         |   14 
 arch/sparc64/kernel/irq.c                          |   44 
 arch/sparc64/kernel/isa.c                          |   36 
 arch/sparc64/kernel/kprobes.c                      |    2 
 arch/sparc64/kernel/of_device.c                    |   59 
 arch/sparc64/kernel/pci.c                          |  613 +-
 arch/sparc64/kernel/pci_common.c                   |  806 --
 arch/sparc64/kernel/pci_fire.c                     |  418 +
 arch/sparc64/kernel/pci_impl.h                     |   33 
 arch/sparc64/kernel/pci_iommu.c                    |  126 
 arch/sparc64/kernel/pci_psycho.c                   |  154 
 arch/sparc64/kernel/pci_sabre.c                    |  465 -
 arch/sparc64/kernel/pci_schizo.c                   |  295 -
 arch/sparc64/kernel/pci_sun4v.c                    |  406 -
 arch/sparc64/kernel/process.c                      |   16 
 arch/sparc64/kernel/prom.c                         |  151 
 arch/sparc64/kernel/sbus.c                         |  243 -
 arch/sparc64/kernel/signal.c                       |    1 
 arch/sparc64/kernel/signal32.c                     |    1 
 arch/sparc64/kernel/smp.c                          |  123 
 arch/sparc64/kernel/sparc64_ksyms.c                |    1 
 arch/sparc64/kernel/stacktrace.c                   |   20 
 arch/sparc64/kernel/sunos_ioctl32.c                |    1 
 arch/sparc64/kernel/sys_sparc.c                    |    1 
 arch/sparc64/kernel/sys_sparc32.c                  |   14 
 arch/sparc64/kernel/time.c                         |  484 +
 arch/sparc64/kernel/traps.c                        |   16 
 arch/sparc64/kernel/ttable.S                       |    6 
 arch/sparc64/kernel/unaligned.c                    |    1 
 arch/sparc64/mm/fault.c                            |    3 
 arch/sparc64/mm/hugetlbpage.c                      |    7 
 arch/sparc64/mm/init.c                             |  304 -
 arch/sparc64/mm/tsb.c                              |    5 
 arch/sparc64/solaris/ioctl.c                       |    3 
 arch/sparc64/solaris/ipc.c                         |    1 
 arch/sparc64/solaris/misc.c                        |    4 
 arch/sparc64/solaris/signal.c                      |    1 
 arch/sparc64/solaris/socket.c                      |    1 
 arch/sparc64/solaris/socksys.c                     |    1 
 arch/um/defconfig                                  |    1 
 arch/um/drivers/chan_kern.c                        |    1 
 arch/um/drivers/chan_user.c                        |   14 
 arch/um/drivers/cow_sys.h                          |   18 
 arch/um/drivers/daemon_kern.c                      |    2 
 arch/um/drivers/daemon_user.c                      |   31 
 arch/um/drivers/fd.c                               |    1 
 arch/um/drivers/harddog_user.c                     |    1 
 arch/um/drivers/line.c                             |    1 
 arch/um/drivers/mcast_kern.c                       |    2 
 arch/um/drivers/mcast_user.c                       |   16 
 arch/um/drivers/mconsole_kern.c                    |    1 
 arch/um/drivers/mconsole_user.c                    |    1 
 arch/um/drivers/mmapper_kern.c                     |    1 
 arch/um/drivers/net_kern.c                         |  167 
 arch/um/drivers/net_user.c                         |    4 
 arch/um/drivers/pcap_kern.c                        |   27 
 arch/um/drivers/pcap_user.c                        |   61 
 arch/um/drivers/port_user.c                        |    1 
 arch/um/drivers/pty.c                              |    2 
 arch/um/drivers/slip_kern.c                        |    2 
 arch/um/drivers/slip_user.c                        |    7 
 arch/um/drivers/slirp_kern.c                       |    2 
 arch/um/drivers/slirp_user.c                       |    4 
 arch/um/drivers/ssl.c                              |    5 
 arch/um/drivers/stdio_console.c                    |    5 
 arch/um/drivers/tty.c                              |    1 
 arch/um/drivers/ubd_kern.c                         |  351 -
 arch/um/drivers/ubd_user.c                         |   16 
 arch/um/drivers/xterm.c                            |    1 
 arch/um/include/arch.h                             |   15 
 arch/um/include/as-layout.h                        |   35 
 arch/um/include/common-offsets.h                   |    2 
 arch/um/include/kern_util.h                        |   13 
 arch/um/include/net_kern.h                         |    2 
 arch/um/include/net_user.h                         |    2 
 arch/um/include/os.h                               |   17 
 arch/um/include/skas/mode_kern_skas.h              |    2 
 arch/um/include/tlb.h                              |    8 
 arch/um/include/tt/uaccess-tt.h                    |    2 
 arch/um/include/um_malloc.h                        |    1 
 arch/um/include/user.h                             |   29 
 arch/um/include/user_util.h                        |   69 
 arch/um/kernel/exec.c                              |    2 
 arch/um/kernel/init_task.c                         |    1 
 arch/um/kernel/initrd.c                            |   33 
 arch/um/kernel/irq.c                               |   16 
 arch/um/kernel/ksyms.c                             |    2 
 arch/um/kernel/mem.c                               |    4 
 arch/um/kernel/physmem.c                           |  230 -
 arch/um/kernel/process.c                           |  125 
 arch/um/kernel/reboot.c                            |    1 
 arch/um/kernel/signal.c                            |    1 
 arch/um/kernel/skas/exec.c                         |   12 
 arch/um/kernel/skas/process.c                      |    2 
 arch/um/kernel/skas/tlb.c                          |   87 
 arch/um/kernel/smp.c                               |   28 
 arch/um/kernel/syscall.c                           |    1 
 arch/um/kernel/sysrq.c                             |    1 
 arch/um/kernel/time.c                              |   19 
 arch/um/kernel/tlb.c                               |  226 -
 arch/um/kernel/trap.c                              |   50 
 arch/um/kernel/tt/exec_kern.c                      |    1 
 arch/um/kernel/tt/exec_user.c                      |    1 
 arch/um/kernel/tt/gdb.c                            |    3 
 arch/um/kernel/tt/include/mode_kern-tt.h           |   52 
 arch/um/kernel/tt/mem.c                            |    1 
 arch/um/kernel/tt/mem_user.c                       |    1 
 arch/um/kernel/tt/process_kern.c                   |    4 
 arch/um/kernel/tt/ptproxy/proxy.c                  |    6 
 arch/um/kernel/tt/ptproxy/ptrace.c                 |    1 
 arch/um/kernel/tt/ptproxy/sysdep.c                 |    1 
 arch/um/kernel/tt/ptproxy/wait.c                   |    1 
 arch/um/kernel/tt/syscall_user.c                   |    1 
 arch/um/kernel/tt/tlb.c                            |    1 
 arch/um/kernel/tt/tracer.c                         |    1 
 arch/um/kernel/tt/trap_user.c                      |    1 
 arch/um/kernel/tt/uaccess_user.c                   |    1 
 arch/um/kernel/um_arch.c                           |   84 
 arch/um/os-Linux/aio.c                             |   61 
 arch/um/os-Linux/drivers/ethertap_kern.c           |    2 
 arch/um/os-Linux/drivers/ethertap_user.c           |   66 
 arch/um/os-Linux/drivers/tuntap_kern.c             |    2 
 arch/um/os-Linux/drivers/tuntap_user.c             |   44 
 arch/um/os-Linux/file.c                            |   47 
 arch/um/os-Linux/helper.c                          |   31 
 arch/um/os-Linux/irq.c                             |    1 
 arch/um/os-Linux/main.c                            |   23 
 arch/um/os-Linux/mem.c                             |   15 
 arch/um/os-Linux/process.c                         |   45 
 arch/um/os-Linux/sigio.c                           |  164 
 arch/um/os-Linux/signal.c                          |    1 
 arch/um/os-Linux/skas/mem.c                        |   75 
 arch/um/os-Linux/skas/process.c                    |  190 
 arch/um/os-Linux/skas/trap.c                       |   49 
 arch/um/os-Linux/start_up.c                        |  173 
 arch/um/os-Linux/sys-i386/tls.c                    |    2 
 arch/um/os-Linux/time.c                            |    1 
 arch/um/os-Linux/trap.c                            |    1 
 arch/um/os-Linux/tt.c                              |    4 
 arch/um/os-Linux/tty_log.c                         |   28 
 arch/um/os-Linux/util.c                            |   26 
 arch/um/sys-i386/bugs.c                            |   78 
 arch/um/sys-i386/fault.c                           |   18 
 arch/um/sys-i386/ptrace_user.c                     |   17 
 arch/um/sys-i386/signal.c                          |   84 
 arch/um/sys-i386/tls.c                             |   11 
 arch/um/sys-i386/user-offsets.c                    |   10 
 arch/um/sys-ppc/sigcontext.c                       |    1 
 arch/um/sys-x86_64/bugs.c                          |  104 
 arch/um/sys-x86_64/fault.c                         |   30 
 arch/um/sys-x86_64/signal.c                        |   32 
 arch/um/sys-x86_64/user-offsets.c                  |    6 
 arch/v850/Kconfig                                  |    4 
 arch/v850/kernel/process.c                         |    1 
 arch/v850/kernel/ptrace.c                          |    1 
 arch/v850/kernel/signal.c                          |    1 
 arch/v850/kernel/syscalls.c                        |    1 
 arch/v850/kernel/time.c                            |   75 
 arch/x86_64/Kconfig                                |   62 
 arch/x86_64/Makefile                               |    4 
 arch/x86_64/boot/Makefile                          |    2 
 arch/x86_64/boot/compressed/Makefile               |   12 
 arch/x86_64/boot/compressed/head.S                 |  339 +
 arch/x86_64/boot/compressed/misc.c                 |  247 -
 arch/x86_64/boot/compressed/vmlinux.lds            |   44 
 arch/x86_64/boot/compressed/vmlinux.scr            |    9 
 arch/x86_64/boot/setup.S                           |   85 
 arch/x86_64/boot/video.S                           | 2043 -----
 arch/x86_64/defconfig                              |  184 
 arch/x86_64/ia32/ia32_binfmt.c                     |   10 
 arch/x86_64/ia32/ia32_signal.c                     |    1 
 arch/x86_64/ia32/ia32entry.S                       |    7 
 arch/x86_64/ia32/syscall32.c                       |    1 
 arch/x86_64/kernel/Makefile                        |    9 
 arch/x86_64/kernel/acpi/sleep.c                    |   24 
 arch/x86_64/kernel/acpi/wakeup.S                   |  286 -
 arch/x86_64/kernel/aperture.c                      |    5 
 arch/x86_64/kernel/apic.c                          |   36 
 arch/x86_64/kernel/asm-offsets.c                   |   10 
 arch/x86_64/kernel/bugs.c                          |   21 
 arch/x86_64/kernel/cpufreq/Kconfig                 |   19 
 arch/x86_64/kernel/crash.c                         |    2 
 arch/x86_64/kernel/e820.c                          |   31 
 arch/x86_64/kernel/early-quirks.c                  |   13 
 arch/x86_64/kernel/early_printk.c                  |   25 
 arch/x86_64/kernel/entry.S                         |    5 
 arch/x86_64/kernel/functionlist                    | 1284 ---
 arch/x86_64/kernel/genapic.c                       |  104 
 arch/x86_64/kernel/genapic_cluster.c               |  137 
 arch/x86_64/kernel/genapic_flat.c                  |   25 
 arch/x86_64/kernel/head.S                          |  340 -
 arch/x86_64/kernel/head64.c                        |   41 
 arch/x86_64/kernel/i8259.c                         |    1 
 arch/x86_64/kernel/io_apic.c                       |   36 
 arch/x86_64/kernel/ioport.c                        |    2 
 arch/x86_64/kernel/kprobes.c                       |   29 
 arch/x86_64/kernel/ldt.c                           |    1 
 arch/x86_64/kernel/machine_kexec.c                 |   16 
 arch/x86_64/kernel/mce.c                           |   34 
 arch/x86_64/kernel/mpparse.c                       |    3 
 arch/x86_64/kernel/nmi.c                           |  680 --
 arch/x86_64/kernel/pci-calgary.c                   |    2 
 arch/x86_64/kernel/pci-gart.c                      |    4 
 arch/x86_64/kernel/pci-nommu.c                     |    2 
 arch/x86_64/kernel/pci-swiotlb.c                   |    2 
 arch/x86_64/kernel/process.c                       |   14 
 arch/x86_64/kernel/ptrace.c                        |    1 
 arch/x86_64/kernel/reboot.c                        |    2 
 arch/x86_64/kernel/setup.c                         |   26 
 arch/x86_64/kernel/setup64.c                       |    5 
 arch/x86_64/kernel/signal.c                        |    7 
 arch/x86_64/kernel/smp.c                           |   29 
 arch/x86_64/kernel/smpboot.c                       |   50 
 arch/x86_64/kernel/stacktrace.c                    |    8 
 arch/x86_64/kernel/suspend.c                       |   19 
 arch/x86_64/kernel/suspend_asm.S                   |    7 
 arch/x86_64/kernel/sys_x86_64.c                    |    4 
 arch/x86_64/kernel/syscall.c                       |    1 
 arch/x86_64/kernel/time.c                          |   76 
 arch/x86_64/kernel/trampoline.S                    |  123 
 arch/x86_64/kernel/traps.c                         |   54 
 arch/x86_64/kernel/tsc.c                           |   17 
 arch/x86_64/kernel/tsc_sync.c                      |    4 
 arch/x86_64/kernel/verify_cpu.S                    |  119 
 arch/x86_64/kernel/vmlinux.lds.S                   |   20 
 arch/x86_64/kernel/vsyscall.c                      |   68 
 arch/x86_64/mm/fault.c                             |    9 
 arch/x86_64/mm/init.c                              |  167 
 arch/x86_64/mm/ioremap.c                           |    9 
 arch/x86_64/mm/k8topology.c                        |    9 
 arch/x86_64/mm/numa.c                              |  306 +
 arch/x86_64/mm/pageattr.c                          |   16 
 arch/x86_64/mm/srat.c                              |    8 
 arch/xtensa/kernel/process.c                       |    1 
 arch/xtensa/kernel/ptrace.c                        |    1 
 arch/xtensa/kernel/signal.c                        |    1 
 arch/xtensa/kernel/vmlinux.lds.S                   |    2 
 arch/xtensa/kernel/xtensa_ksyms.c                  |    1 
 arch/xtensa/lib/Makefile                           |    2 
 arch/xtensa/lib/strcasecmp.c                       |   32 
 arch/xtensa/platform-iss/network.c                 |    4 
 arch/xtensa/platform-iss/setup.c                   |    1 
 block/as-iosched.c                                 |    6 
 block/cfq-iosched.c                                |  859 +-
 block/elevator.c                                   |   17 
 block/genhd.c                                      |   12 
 block/ioctl.c                                      |    4 
 block/ll_rw_blk.c                                  |    4 
 block/scsi_ioctl.c                                 |    4 
 crypto/Kconfig                                     |   13 
 crypto/Makefile                                    |    2 
 crypto/ablkcipher.c                                |   83 
 crypto/algapi.c                                    |  169 
 crypto/blkcipher.c                                 |   72 
 crypto/cbc.c                                       |   11 
 crypto/cryptd.c                                    |  375 +
 crypto/cryptomgr.c                                 |   66 
 crypto/ecb.c                                       |   11 
 crypto/hash.c                                      |    2 
 crypto/hmac.c                                      |   11 
 crypto/lrw.c                                       |   11 
 crypto/michael_mic.c                               |    4 
 crypto/pcbc.c                                      |   11 
 crypto/tcrypt.c                                    |  121 
 crypto/xcbc.c                                      |   12 
 drivers/Makefile                                   |    3 
 drivers/acpi/Kconfig                               |   44 
 drivers/acpi/Makefile                              |   10 
 drivers/acpi/acpi_memhotplug.c                     |   13 
 drivers/acpi/bus.c                                 |    4 
 drivers/acpi/container.c                           |    6 
 drivers/acpi/dock.c                                |   25 
 drivers/acpi/ec.c                                  |  495 -
 drivers/acpi/glue.c                                |   46 
 drivers/acpi/i2c_ec.c                              |  403 -
 drivers/acpi/i2c_ec.h                              |   23 
 drivers/acpi/ibm_acpi.c                            | 2798 -------
 drivers/acpi/numa.c                                |    4 
 drivers/acpi/osl.c                                 |    1 
 drivers/acpi/processor_core.c                      |    4 
 drivers/acpi/processor_idle.c                      |   12 
 drivers/acpi/processor_perflib.c                   |   46 
 drivers/acpi/sbs.c                                 | 1291 ++-
 drivers/acpi/scan.c                                |    6 
 drivers/acpi/sleep/main.c                          |   13 
 drivers/acpi/sleep/proc.c                          |   37 
 drivers/acpi/tables/tbfadt.c                       |   12 
 drivers/amba/bus.c                                 |   13 
 drivers/ata/Kconfig                                |   53 
 drivers/ata/Makefile                               |    2 
 drivers/ata/ahci.c                                 |  501 +
 drivers/ata/ata_generic.c                          |   32 
 drivers/ata/ata_piix.c                             |   62 
 drivers/ata/libata-core.c                          | 1240 ++-
 drivers/ata/libata-eh.c                            |   77 
 drivers/ata/libata-scsi.c                          |   85 
 drivers/ata/libata-sff.c                           |  636 +-
 drivers/ata/libata.h                               |   10 
 drivers/ata/pata_ali.c                             |   74 
 drivers/ata/pata_amd.c                             |  100 
 drivers/ata/pata_artop.c                           |   33 
 drivers/ata/pata_atiixp.c                          |   30 
 drivers/ata/pata_cmd640.c                          |  312 +
 drivers/ata/pata_cmd64x.c                          |   34 
 drivers/ata/pata_cs5520.c                          |  145 
 drivers/ata/pata_cs5530.c                          |   15 
 drivers/ata/pata_cs5535.c                          |   25 
 drivers/ata/pata_cypress.c                         |   14 
 drivers/ata/pata_efar.c                            |   36 
 drivers/ata/pata_hpt366.c                          |   30 
 drivers/ata/pata_hpt37x.c                          |  390 -
 drivers/ata/pata_hpt3x2n.c                         |   75 
 drivers/ata/pata_hpt3x3.c                          |   22 
 drivers/ata/pata_icside.c                          |  686 ++
 drivers/ata/pata_isapnp.c                          |   44 
 drivers/ata/pata_it8213.c                          |   40 
 drivers/ata/pata_it821x.c                          |   36 
 drivers/ata/pata_ixp4xx_cf.c                       |   40 
 drivers/ata/pata_jmicron.c                         |    7 
 drivers/ata/pata_legacy.c                          |   45 
 drivers/ata/pata_marvell.c                         |   25 
 drivers/ata/pata_mpc52xx.c                         |   49 
 drivers/ata/pata_mpiix.c                           |   45 
 drivers/ata/pata_netcell.c                         |   31 
 drivers/ata/pata_ns87410.c                         |   12 
 drivers/ata/pata_oldpiix.c                         |   12 
 drivers/ata/pata_opti.c                            |    9 
 drivers/ata/pata_optidma.c                         |   59 
 drivers/ata/pata_pcmcia.c                          |   77 
 drivers/ata/pata_pdc2027x.c                        |  163 
 drivers/ata/pata_pdc202xx_old.c                    |   45 
 drivers/ata/pata_platform.c                        |   44 
 drivers/ata/pata_qdi.c                             |   47 
 drivers/ata/pata_radisys.c                         |   37 
 drivers/ata/pata_rz1000.c                          |   28 
 drivers/ata/pata_sc1200.c                          |    1 
 drivers/ata/pata_scc.c                             |   51 
 drivers/ata/pata_serverworks.c                     |   36 
 drivers/ata/pata_sil680.c                          |   17 
 drivers/ata/pata_sis.c                             |  115 
 drivers/ata/pata_sl82c105.c                        |    7 
 drivers/ata/pata_triflex.c                         |   10 
 drivers/ata/pata_via.c                             |   30 
 drivers/ata/pata_winbond.c                         |  101 
 drivers/ata/pdc_adma.c                             |   85 
 drivers/ata/sata_inic162x.c                        |  101 
 drivers/ata/sata_mv.c                              |  213 -
 drivers/ata/sata_nv.c                              |  135 
 drivers/ata/sata_promise.c                         |  398 +
 drivers/ata/sata_qstor.c                           |   62 
 drivers/ata/sata_sil.c                             |  118 
 drivers/ata/sata_sil24.c                           |  132 
 drivers/ata/sata_sis.c                             |   50 
 drivers/ata/sata_svw.c                             |  109 
 drivers/ata/sata_sx4.c                             |  150 
 drivers/ata/sata_uli.c                             |   65 
 drivers/ata/sata_via.c                             |  222 -
 drivers/ata/sata_vsc.c                             |   72 
 drivers/atm/adummy.c                               |    1 
 drivers/atm/ambassador.c                           |    2 
 drivers/atm/atmtcp.c                               |    6 
 drivers/atm/eni.c                                  |    4 
 drivers/atm/eni.h                                  |    2 
 drivers/atm/fore200e.c                             |   20 
 drivers/atm/fore200e.h                             |    2 
 drivers/atm/he.c                                   |    4 
 drivers/atm/idt77252.c                             |   28 
 drivers/atm/nicstar.c                              |   14 
 drivers/base/Makefile                              |    4 
 drivers/base/attribute_container.c                 |   26 
 drivers/base/base.h                                |    4 
 drivers/base/bus.c                                 |  128 
 drivers/base/class.c                               |   20 
 drivers/base/core.c                                |  318 +
 drivers/base/dd.c                                  |   81 
 drivers/base/dmapool.c                             |   14 
 drivers/base/driver.c                              |   20 
 drivers/base/firmware.c                            |    6 
 drivers/base/firmware_class.c                      |   10 
 drivers/base/platform.c                            |   26 
 drivers/base/power/main.c                          |    3 
 drivers/base/power/resume.c                        |   13 
 drivers/base/power/shutdown.c                      |    6 
 drivers/base/power/suspend.c                       |   12 
 drivers/base/sys.c                                 |   14 
 drivers/block/acsi_slm.c                           |    1 
 drivers/block/amiflop.c                            |    2 
 drivers/block/aoe/aoe.h                            |    9 
 drivers/block/aoe/aoecmd.c                         |   25 
 drivers/block/aoe/aoenet.c                         |    2 
 drivers/block/cciss.c                              |  288 -
 drivers/block/cciss_scsi.c                         |    1 
 drivers/block/floppy.c                             |    7 
 drivers/block/loop.c                               |  188 
 drivers/block/rd.c                                 |    2 
 drivers/block/ub.c                                 |   11 
 drivers/block/umem.c                               |    1 
 drivers/bluetooth/bfusb.c                          |    2 
 drivers/bluetooth/bluecard_cs.c                    |    6 
 drivers/bluetooth/bpa10x.c                         |    4 
 drivers/bluetooth/bt3c_cs.c                        |    6 
 drivers/bluetooth/btuart_cs.c                      |    6 
 drivers/bluetooth/dtl1_cs.c                        |    2 
 drivers/bluetooth/hci_h4.c                         |    6 
 drivers/bluetooth/hci_usb.c                        |    6 
 drivers/cdrom/cdrom.c                              |    2 
 drivers/char/Kconfig                               |   12 
 drivers/char/Makefile                              |    2 
 drivers/char/agp/ali-agp.c                         |    2 
 drivers/char/agp/alpha-agp.c                       |    2 
 drivers/char/agp/amd64-agp.c                       |   13 
 drivers/char/agp/generic.c                         |   22 
 drivers/char/agp/intel-agp.c                       |    8 
 drivers/char/agp/nvidia-agp.c                      |    9 
 drivers/char/agp/parisc-agp.c                      |    2 
 drivers/char/agp/sgi-agp.c                         |    5 
 drivers/char/agp/sis-agp.c                         |  278 -
 drivers/char/agp/sworks-agp.c                      |   23 
 drivers/char/agp/uninorth-agp.c                    |    2 
 drivers/char/amiserial.c                           |    4 
 drivers/char/briq_panel.c                          |    9 
 drivers/char/consolemap.c                          |    6 
 drivers/char/cs5535_gpio.c                         |    1 
 drivers/char/cyclades.c                            | 2581 +++----
 drivers/char/digi.h                                |   71 
 drivers/char/drm/README.drm                        |   16 
 drivers/char/drm/ati_pcigart.c                     |   84 
 drivers/char/drm/drm.h                             |    4 
 drivers/char/drm/drmP.h                            |   30 
 drivers/char/drm/drm_bufs.c                        |   75 
 drivers/char/drm/drm_drv.c                         |   15 
 drivers/char/drm/drm_fops.c                        |   96 
 drivers/char/drm/drm_hashtab.c                     |   17 
 drivers/char/drm/drm_hashtab.h                     |    1 
 drivers/char/drm/drm_irq.c                         |    4 
 drivers/char/drm/drm_lock.c                        |  134 
 drivers/char/drm/drm_mm.c                          |    2 
 drivers/char/drm/drm_os_linux.h                    |    3 
 drivers/char/drm/drm_pciids.h                      |    4 
 drivers/char/drm/drm_proc.c                        |    2 
 drivers/char/drm/drm_stub.c                        |    1 
 drivers/char/drm/drm_vm.c                          |  102 
 drivers/char/drm/i915_dma.c                        |    3 
 drivers/char/drm/r128_cce.c                        |    3 
 drivers/char/drm/r128_drv.h                        |    2 
 drivers/char/drm/radeon_cp.c                       |   79 
 drivers/char/drm/radeon_drm.h                      |    1 
 drivers/char/drm/radeon_drv.h                      |   24 
 drivers/char/drm/radeon_state.c                    |   52 
 drivers/char/drm/sis_drv.c                         |    2 
 drivers/char/drm/via_dma.c                         |  111 
 drivers/char/drm/via_drv.c                         |    3 
 drivers/char/drm/via_drv.h                         |    5 
 drivers/char/drm/via_mm.h                          |   40 
 drivers/char/ds1620.c                              |    1 
 drivers/char/dsp56k.c                              |    1 
 drivers/char/dtlk.c                                |   15 
 drivers/char/ec3104_keyb.c                         |    1 
 drivers/char/epca.c                                |    2 
 drivers/char/genrtc.c                              |    2 
 drivers/char/hangcheck-timer.c                     |    1 
 drivers/char/hvc_console.c                         |   61 
 drivers/char/hvc_iseries.c                         |    4 
 drivers/char/hvc_vio.c                             |    4 
 drivers/char/hvsi.c                                |    4 
 drivers/char/hw_random/intel-rng.c                 |  219 -
 drivers/char/hw_random/via-rng.c                   |    1 
 drivers/char/i8k.c                                 |    1 
 drivers/char/ip27-rtc.c                            |    1 
 drivers/char/ipmi/ipmi_si_intf.c                   |  235 +
 drivers/char/ipmi/ipmi_watchdog.c                  |  136 
 drivers/char/isicom.c                              |    3 
 drivers/char/keyboard.c                            |  103 
 drivers/char/lp.c                                  |    8 
 drivers/char/mem.c                                 |    9 
 drivers/char/misc.c                                |   27 
 drivers/char/moxa.c                                |    8 
 drivers/char/mxser.c                               |    1 
 drivers/char/mxser_new.c                           |    1 
 drivers/char/n_r3964.c                             |    4 
 drivers/char/pcmcia/synclink_cs.c                  |    3 
 drivers/char/ppdev.c                               |    3 
 drivers/char/random.c                              |   38 
 drivers/char/riscom8.c                             |    2 
 drivers/char/rocket.c                              |   33 
 drivers/char/rocket_int.h                          |    4 
 drivers/char/rtc.c                                 |    2 
 drivers/char/selection.c                           |    2 
 drivers/char/serial167.c                           |    2 
 drivers/char/sonypi.c                              |   53 
 drivers/char/synclink.c                            |    7 
 drivers/char/synclink_gt.c                         |   34 
 drivers/char/sysrq.c                               |    1 
 drivers/char/tipar.c                               |    2 
 drivers/char/tpm/tpm.c                             |   36 
 drivers/char/tpm/tpm.h                             |    6 
 drivers/char/tpm/tpm_atmel.h                       |    8 
 drivers/char/tpm/tpm_infineon.c                    |  231 -
 drivers/char/tty_io.c                              |   58 
 drivers/char/vc_screen.c                           |   19 
 drivers/char/vt.c                                  |  304 +
 drivers/char/vt_ioctl.c                            |    2 
 drivers/char/watchdog/Kconfig                      |    2 
 drivers/char/watchdog/omap_wdt.c                   |    1 
 drivers/char/watchdog/sc1200wdt.c                  |    1 
 drivers/char/watchdog/scx200_wdt.c                 |    2 
 drivers/clocksource/acpi_pm.c                      |    2 
 drivers/connector/connector.c                      |    4 
 drivers/cpufreq/Kconfig                            |   61 
 drivers/cpufreq/cpufreq.c                          |   47 
 drivers/cpufreq/cpufreq_ondemand.c                 |    2 
 drivers/crypto/Kconfig                             |   16 
 drivers/crypto/Makefile                            |    1 
 drivers/crypto/padlock.c                           |   58 
 drivers/edac/i82875p_edac.c                        |   13 
 drivers/eisa/virtual_root.c                        |    2 
 drivers/firmware/efivars.c                         |   12 
 drivers/hid/Kconfig                                |    2 
 drivers/hid/Makefile                               |    4 
 drivers/hid/hid-core.c                             |   10 
 drivers/hid/hid-input.c                            |   27 
 drivers/hid/usbhid/Kconfig                         |  149 
 drivers/hid/usbhid/Makefile                        |   35 
 drivers/hid/usbhid/hid-core.c                      | 1114 +++
 drivers/hid/usbhid/hid-ff.c                        |   91 
 drivers/hid/usbhid/hid-lgff.c                      |  151 
 drivers/hid/usbhid/hid-pidff.c                     | 1331 +++
 drivers/hid/usbhid/hid-plff.c                      |  129 
 drivers/hid/usbhid/hid-quirks.c                    |  681 ++
 drivers/hid/usbhid/hid-tmff.c                      |  147 
 drivers/hid/usbhid/hid-zpff.c                      |  111 
 drivers/hid/usbhid/hiddev.c                        |  847 ++
 drivers/hid/usbhid/usbhid.h                        |   87 
 drivers/hid/usbhid/usbkbd.c                        |  367 +
 drivers/hid/usbhid/usbmouse.c                      |  252 +
 drivers/hwmon/Kconfig                              |  170 
 drivers/hwmon/Makefile                             |    4 
 drivers/hwmon/ad7418.c                             |  373 +
 drivers/hwmon/ams/ams-core.c                       |   11 
 drivers/hwmon/ams/ams-i2c.c                        |   12 
 drivers/hwmon/ams/ams-pmu.c                        |    4 
 drivers/hwmon/applesmc.c                           | 1339 +++
 drivers/hwmon/coretemp.c                           |  406 +
 drivers/hwmon/f71805f.c                            |   16 
 drivers/hwmon/hdaps.c                              |   38 
 drivers/hwmon/hwmon-vid.c                          |    6 
 drivers/hwmon/lm75.c                               |   82 
 drivers/hwmon/lm78.c                               |  662 +-
 drivers/hwmon/lm87.c                               |    2 
 drivers/hwmon/max6650.c                            |  693 ++
 drivers/hwmon/pc87427.c                            |   15 
 drivers/hwmon/smsc47b397.c                         |  228 -
 drivers/hwmon/smsc47m1.c                           |  606 +-
 drivers/hwmon/smsc47m192.c                         |    4 
 drivers/hwmon/vt1211.c                             |   13 
 drivers/hwmon/w83627hf.c                           |  670 +-
 drivers/hwmon/w83781d.c                            | 1205 ++-
 drivers/i2c/Kconfig                                |   18 
 drivers/i2c/Makefile                               |    1 
 drivers/i2c/algos/Kconfig                          |    8 
 drivers/i2c/algos/i2c-algo-bit.c                   |  286 -
 drivers/i2c/algos/i2c-algo-sgi.c                   |    9 
 drivers/i2c/busses/Kconfig                         |  151 
 drivers/i2c/busses/Makefile                        |    4 
 drivers/i2c/busses/i2c-ali1535.c                   |    2 
 drivers/i2c/busses/i2c-ali15x3.c                   |    2 
 drivers/i2c/busses/i2c-amd8111.c                   |    2 
 drivers/i2c/busses/i2c-at91.c                      |    1 
 drivers/i2c/busses/i2c-bfin-twi.c                  |  644 ++
 drivers/i2c/busses/i2c-elektor.c                   |   51 
 drivers/i2c/busses/i2c-gpio.c                      |  215 +
 drivers/i2c/busses/i2c-i801.c                      |    2 
 drivers/i2c/busses/i2c-isa.c                       |   43 
 drivers/i2c/busses/i2c-ixp2000.c                   |    2 
 drivers/i2c/busses/i2c-ixp4xx.c                    |    2 
 drivers/i2c/busses/i2c-mpc.c                       |    1 
 drivers/i2c/busses/i2c-mv64xxx.c                   |    2 
 drivers/i2c/busses/i2c-nforce2.c                   |    6 
 drivers/i2c/busses/i2c-omap.c                      |    3 
 drivers/i2c/busses/i2c-parport-light.c             |  144 
 drivers/i2c/busses/i2c-parport.c                   |   26 
 drivers/i2c/busses/i2c-pasemi.c                    |    2 
 drivers/i2c/busses/i2c-pca-isa.c                   |   36 
 drivers/i2c/busses/i2c-piix4.c                     |    2 
 drivers/i2c/busses/i2c-pxa.c                       |   33 
 drivers/i2c/busses/i2c-s3c2410.c                   |   96 
 drivers/i2c/busses/i2c-simtec.c                    |  186 
 drivers/i2c/busses/i2c-sis96x.c                    |    2 
 drivers/i2c/busses/i2c-tiny-usb.c                  |  277 +
 drivers/i2c/busses/i2c-viapro.c                    |    2 
 drivers/i2c/busses/scx200_acb.c                    |    4 
 drivers/i2c/chips/Kconfig                          |   21 
 drivers/i2c/chips/tps65010.c                       |    4 
 drivers/i2c/i2c-boardinfo.c                        |   90 
 drivers/i2c/i2c-core.c                             |  662 +-
 drivers/i2c/i2c-core.h                             |   31 
 drivers/i2c/i2c-dev.c                              |    1 
 drivers/ide/cris/ide-cris.c                        |    9 
 drivers/ide/ide-proc.c                             |    4 
 drivers/ide/legacy/ide-cs.c                        |    1 
 drivers/ide/pci/aec62xx.c                          |   22 
 drivers/ide/pci/alim15x3.c                         |    7 
 drivers/ide/pci/cmd64x.c                           |  537 +
 drivers/ide/pci/hpt366.c                           |    7 
 drivers/ide/pci/it821x.c                           |  126 
 drivers/ide/pci/pdc202xx_new.c                     |    5 
 drivers/ide/pci/siimage.c                          |   12 
 drivers/ide/pci/sl82c105.c                         |  247 -
 drivers/ide/ppc/pmac.c                             |   18 
 drivers/ieee1394/Kconfig                           |   52 
 drivers/ieee1394/config_roms.c                     |   93 
 drivers/ieee1394/config_roms.h                     |   20 
 drivers/ieee1394/csr1212.c                         |  870 +-
 drivers/ieee1394/csr1212.h                         |  483 -
 drivers/ieee1394/dma.c                             |   24 
 drivers/ieee1394/dma.h                             |   22 
 drivers/ieee1394/dv1394.c                          |    1 
 drivers/ieee1394/eth1394.c                         |  802 +-
 drivers/ieee1394/eth1394.h                         |   27 
 drivers/ieee1394/highlevel.c                       |   89 
 drivers/ieee1394/highlevel.h                       |   55 
 drivers/ieee1394/hosts.c                           |   24 
 drivers/ieee1394/hosts.h                           |   10 
 drivers/ieee1394/ieee1394_core.c                   |  461 +
 drivers/ieee1394/ieee1394_core.h                   |  100 
 drivers/ieee1394/ieee1394_transactions.c           |   43 
 drivers/ieee1394/ieee1394_transactions.h           |   20 
 drivers/ieee1394/iso.c                             |   85 
 drivers/ieee1394/iso.h                             |   35 
 drivers/ieee1394/nodemgr.c                         |   83 
 drivers/ieee1394/nodemgr.h                         |   24 
 drivers/ieee1394/ohci1394.c                        |   12 
 drivers/ieee1394/ohci1394.h                        |    4 
 drivers/ieee1394/raw1394.c                         |    4 
 drivers/ieee1394/sbp2.c                            |   39 
 drivers/ieee1394/sbp2.h                            |    8 
 drivers/ieee1394/video1394.c                       |    1 
 drivers/infiniband/core/cm.c                       |    1 
 drivers/infiniband/core/fmr_pool.c                 |   32 
 drivers/infiniband/core/iwcm.c                     |    1 
 drivers/infiniband/core/mad.c                      |   36 
 drivers/infiniband/core/mad_priv.h                 |    1 
 drivers/infiniband/core/multicast.c                |    1 
 drivers/infiniband/core/sa_query.c                 |   25 
 drivers/infiniband/core/smi.c                      |   86 
 drivers/infiniband/core/smi.h                      |   34 
 drivers/infiniband/core/sysfs.c                    |    1 
 drivers/infiniband/core/ucm.c                      |   23 
 drivers/infiniband/core/ucma.c                     |   22 
 drivers/infiniband/core/user_mad.c                 |   21 
 drivers/infiniband/core/uverbs_cmd.c               |    1 
 drivers/infiniband/core/uverbs_main.c              |    2 
 drivers/infiniband/core/verbs.c                    |    4 
 drivers/infiniband/hw/amso1100/c2.c                |    6 
 drivers/infiniband/hw/amso1100/c2.h                |    2 
 drivers/infiniband/hw/amso1100/c2_cq.c             |   16 
 drivers/infiniband/hw/amso1100/c2_provider.c       |    4 
 drivers/infiniband/hw/cxgb3/cxio_hal.c             |    3 
 drivers/infiniband/hw/cxgb3/cxio_wr.h              |    1 
 drivers/infiniband/hw/cxgb3/iwch_cm.c              |   36 
 drivers/infiniband/hw/cxgb3/iwch_cm.h              |    6 
 drivers/infiniband/hw/cxgb3/iwch_provider.c        |   15 
 drivers/infiniband/hw/cxgb3/iwch_qp.c              |   69 
 drivers/infiniband/hw/ehca/ehca_classes.h          |    1 
 drivers/infiniband/hw/ehca/ehca_cq.c               |    2 
 drivers/infiniband/hw/ehca/ehca_hca.c              |   55 
 drivers/infiniband/hw/ehca/ehca_iverbs.h           |    4 
 drivers/infiniband/hw/ehca/ehca_main.c             |    8 
 drivers/infiniband/hw/ehca/ehca_reqs.c             |   14 
 drivers/infiniband/hw/ehca/hcp_if.c                |   24 
 drivers/infiniband/hw/ehca/hcp_if.h                |    4 
 drivers/infiniband/hw/ehca/ipz_pt_fn.h             |    8 
 drivers/infiniband/hw/ipath/ipath_common.h         |   23 
 drivers/infiniband/hw/ipath/ipath_cq.c             |  106 
 drivers/infiniband/hw/ipath/ipath_debug.h          |    1 
 drivers/infiniband/hw/ipath/ipath_diag.c           |   11 
 drivers/infiniband/hw/ipath/ipath_driver.c         |  123 
 drivers/infiniband/hw/ipath/ipath_eeprom.c         |    4 
 drivers/infiniband/hw/ipath/ipath_file_ops.c       |  287 -
 drivers/infiniband/hw/ipath/ipath_fs.c             |    3 
 drivers/infiniband/hw/ipath/ipath_iba6110.c        |  152 
 drivers/infiniband/hw/ipath/ipath_iba6120.c        |   73 
 drivers/infiniband/hw/ipath/ipath_init_chip.c      |   86 
 drivers/infiniband/hw/ipath/ipath_intr.c           |  100 
 drivers/infiniband/hw/ipath/ipath_kernel.h         |   10 
 drivers/infiniband/hw/ipath/ipath_keys.c           |   14 
 drivers/infiniband/hw/ipath/ipath_layer.c          |    1 
 drivers/infiniband/hw/ipath/ipath_mmap.c           |   64 
 drivers/infiniband/hw/ipath/ipath_mr.c             |   12 
 drivers/infiniband/hw/ipath/ipath_qp.c             |  185 
 drivers/infiniband/hw/ipath/ipath_rc.c             |  937 +-
 drivers/infiniband/hw/ipath/ipath_registers.h      |   22 
 drivers/infiniband/hw/ipath/ipath_ruc.c            |   63 
 drivers/infiniband/hw/ipath/ipath_srq.c            |   55 
 drivers/infiniband/hw/ipath/ipath_stats.c          |   18 
 drivers/infiniband/hw/ipath/ipath_sysfs.c          |    1 
 drivers/infiniband/hw/ipath/ipath_uc.c             |    6 
 drivers/infiniband/hw/ipath/ipath_ud.c             |    8 
 drivers/infiniband/hw/ipath/ipath_verbs.c          |   19 
 drivers/infiniband/hw/ipath/ipath_verbs.h          |   81 
 drivers/infiniband/hw/mthca/mthca_cq.c             |   12 
 drivers/infiniband/hw/mthca/mthca_dev.h            |    4 
 drivers/infiniband/hw/mthca/mthca_main.c           |   10 
 drivers/infiniband/hw/mthca/mthca_memfree.h        |    1 
 drivers/infiniband/hw/mthca/mthca_mr.c             |    6 
 drivers/infiniband/hw/mthca/mthca_provider.c       |    3 
 drivers/infiniband/hw/mthca/mthca_qp.c             |   20 
 drivers/infiniband/ulp/ipoib/ipoib.h               |    2 
 drivers/infiniband/ulp/ipoib/ipoib_cm.c            |   80 
 drivers/infiniband/ulp/ipoib/ipoib_ib.c            |   99 
 drivers/infiniband/ulp/ipoib/ipoib_main.c          |   14 
 drivers/infiniband/ulp/ipoib/ipoib_verbs.c         |    2 
 drivers/infiniband/ulp/iser/iser_initiator.c       |    2 
 drivers/infiniband/ulp/iser/iser_verbs.c           |    3 
 drivers/infiniband/ulp/srp/ib_srp.c                |   27 
 drivers/infiniband/ulp/srp/ib_srp.h                |    1 
 drivers/input/Kconfig                              |    2 
 drivers/input/Makefile                             |    2 
 drivers/input/evbug.c                              |   32 
 drivers/input/evdev.c                              |  242 -
 drivers/input/ff-core.c                            |    3 
 drivers/input/gameport/gameport.c                  |   39 
 drivers/input/input.c                              |  267 +
 drivers/input/joydev.c                             |  188 
 drivers/input/joystick/Kconfig                     |   18 
 drivers/input/joystick/Makefile                    |    1 
 drivers/input/joystick/a3d.c                       |    9 
 drivers/input/joystick/adi.c                       |    9 
 drivers/input/joystick/analog.c                    |   11 
 drivers/input/joystick/cobra.c                     |    9 
 drivers/input/joystick/db9.c                       |   25 
 drivers/input/joystick/gamecon.c                   |   24 
 drivers/input/joystick/gf2k.c                      |   10 
 drivers/input/joystick/grip.c                      |    9 
 drivers/input/joystick/grip_mp.c                   |   11 
 drivers/input/joystick/guillemot.c                 |    9 
 drivers/input/joystick/iforce/iforce-ff.c          |   10 
 drivers/input/joystick/iforce/iforce-main.c        |   26 
 drivers/input/joystick/iforce/iforce-packets.c     |   22 
 drivers/input/joystick/iforce/iforce-serio.c       |    2 
 drivers/input/joystick/iforce/iforce-usb.c         |   13 
 drivers/input/joystick/iforce/iforce.h             |    4 
 drivers/input/joystick/interact.c                  |    8 
 drivers/input/joystick/magellan.c                  |    3 
 drivers/input/joystick/sidewinder.c                |    9 
 drivers/input/joystick/spaceball.c                 |    3 
 drivers/input/joystick/spaceorb.c                  |    3 
 drivers/input/joystick/stinger.c                   |    3 
 drivers/input/joystick/tmdc.c                      |    9 
 drivers/input/joystick/turbografx.c                |   25 
 drivers/input/joystick/twidjoy.c                   |    4 
 drivers/input/joystick/warrior.c                   |    3 
 drivers/input/joystick/xpad.c                      |  433 +
 drivers/input/keyboard/Kconfig                     |   21 
 drivers/input/keyboard/Makefile                    |    2 
 drivers/input/keyboard/aaed2000_kbd.c              |   63 
 drivers/input/keyboard/atakbd.c                    |  134 
 drivers/input/keyboard/atkbd.c                     |    7 
 drivers/input/keyboard/corgikbd.c                  |    3 
 drivers/input/keyboard/gpio_keys.c                 |   22 
 drivers/input/keyboard/hil_kbd.c                   |   89 
 drivers/input/keyboard/hilkbd.c                    |    8 
 drivers/input/keyboard/lkkbd.c                     |    7 
 drivers/input/keyboard/locomokbd.c                 |    2 
 drivers/input/keyboard/newtonkbd.c                 |    3 
 drivers/input/keyboard/omap-keypad.c               |    3 
 drivers/input/keyboard/pxa27x_keyboard.c           |  258 +
 drivers/input/keyboard/spitzkbd.c                  |    3 
 drivers/input/keyboard/stowaway.c                  |    3 
 drivers/input/keyboard/sunkbd.c                    |    8 
 drivers/input/keyboard/xtkbd.c                     |    3 
 drivers/input/misc/Kconfig                         |  111 
 drivers/input/misc/Makefile                        |   11 
 drivers/input/misc/ati_remote.c                    |  862 ++
 drivers/input/misc/ati_remote2.c                   |  543 +
 drivers/input/misc/cobalt_btns.c                   |  172 
 drivers/input/misc/input-polldev.c                 |  171 
 drivers/input/misc/ixp4xx-beeper.c                 |   11 
 drivers/input/misc/keyspan_remote.c                |  592 ++
 drivers/input/misc/m68kspkr.c                      |    2 
 drivers/input/misc/map_to_7segment.h               |  189 
 drivers/input/misc/pcspkr.c                        |    2 
 drivers/input/misc/powermate.c                     |  463 +
 drivers/input/misc/sparcspkr.c                     |    6 
 drivers/input/misc/uinput.c                        |   11 
 drivers/input/misc/wistron_btns.c                  |  685 ++
 drivers/input/misc/yealink.c                       | 1004 +++
 drivers/input/misc/yealink.h                       |  220 +
 drivers/input/mouse/Kconfig                        |   98 
 drivers/input/mouse/Makefile                       |   10 
 drivers/input/mouse/alps.c                         |   13 
 drivers/input/mouse/alps.h                         |   18 
 drivers/input/mouse/appletouch.c                   |  706 ++
 drivers/input/mouse/atarimouse.c                   |  160 
 drivers/input/mouse/hil_ptr.c                      |   97 
 drivers/input/mouse/lifebook.c                     |  195 
 drivers/input/mouse/lifebook.h                     |   11 
 drivers/input/mouse/logips2pp.c                    |    7 
 drivers/input/mouse/logips2pp.h                    |    7 
 drivers/input/mouse/psmouse-base.c                 |   50 
 drivers/input/mouse/psmouse.h                      |    1 
 drivers/input/mouse/sermouse.c                     |   19 
 drivers/input/mouse/synaptics.c                    |  111 
 drivers/input/mouse/synaptics.h                    |   18 
 drivers/input/mouse/touchkit_ps2.c                 |  100 
 drivers/input/mouse/touchkit_ps2.h                 |   24 
 drivers/input/mouse/trackpoint.h                   |    9 
 drivers/input/mouse/vsxxxaa.c                      |    3 
 drivers/input/mousedev.c                           |  442 +
 drivers/input/power.c                              |  166 
 drivers/input/serio/hil_mlc.c                      |  505 +
 drivers/input/serio/hp_sdc.c                       |  427 +
 drivers/input/serio/hp_sdc_mlc.c                   |  227 -
 drivers/input/serio/i8042-x86ia64io.h              |   24 
 drivers/input/serio/i8042.c                        |   42 
 drivers/input/serio/serio.c                        |   41 
 drivers/input/tablet/Kconfig                       |   74 
 drivers/input/tablet/Makefile                      |   12 
 drivers/input/tablet/acecad.c                      |  289 +
 drivers/input/tablet/aiptek.c                      | 2236 ++++++
 drivers/input/tablet/gtco.c                        | 1055 +++
 drivers/input/tablet/kbtab.c                       |  226 +
 drivers/input/tablet/wacom.h                       |  131 
 drivers/input/tablet/wacom_sys.c                   |  318 +
 drivers/input/tablet/wacom_wac.c                   |  675 ++
 drivers/input/tablet/wacom_wac.h                   |   49 
 drivers/input/touchscreen/Kconfig                  |   60 
 drivers/input/touchscreen/Makefile                 |   17 
 drivers/input/touchscreen/ads7846.c                |   30 
 drivers/input/touchscreen/corgi_ts.c               |    3 
 drivers/input/touchscreen/elo.c                    |    3 
 drivers/input/touchscreen/gunze.c                  |    2 
 drivers/input/touchscreen/h3600_ts_input.c         |    9 
 drivers/input/touchscreen/hp680_ts_input.c         |    2 
 drivers/input/touchscreen/mtouch.c                 |    2 
 drivers/input/touchscreen/penmount.c               |    3 
 drivers/input/touchscreen/touchright.c             |    2 
 drivers/input/touchscreen/touchwin.c               |    2 
 drivers/input/touchscreen/ucb1400_ts.c             |   26 
 drivers/input/touchscreen/usbtouchscreen.c         |  839 ++
 drivers/input/tsdev.c                              |  178 
 drivers/isdn/act2000/module.c                      |    2 
 drivers/isdn/capi/capi.c                           |   34 
 drivers/isdn/capi/capiutil.c                       |    8 
 drivers/isdn/divert/divert_procfs.c                |    1 
 drivers/isdn/gigaset/usb-gigaset.c                 |    2 
 drivers/isdn/hardware/avm/b1dma.c                  |    3 
 drivers/isdn/hardware/avm/c4.c                     |    3 
 drivers/isdn/hardware/eicon/capimain.c             |    1 
 drivers/isdn/hardware/eicon/dbgioctl.h             |  198 -
 drivers/isdn/hardware/eicon/divamnt.c              |    1 
 drivers/isdn/hardware/eicon/divasi.c               |    1 
 drivers/isdn/hardware/eicon/divasmain.c            |    1 
 drivers/isdn/hardware/eicon/main_if.h              |   50 
 drivers/isdn/hardware/eicon/platform.h             |    1 
 drivers/isdn/hisax/elsa_ser.c                      |    6 
 drivers/isdn/hisax/hfc_usb.c                       |    1 
 drivers/isdn/hisax/isdnl2.c                        |    3 
 drivers/isdn/hisax/netjet.c                        |    1 
 drivers/isdn/hysdn/boardergo.c                     |    2 
 drivers/isdn/hysdn/hycapi.c                        |    5 
 drivers/isdn/hysdn/hysdn_net.c                     |    2 
 drivers/isdn/hysdn/hysdn_proclog.c                 |    5 
 drivers/isdn/hysdn/hysdn_sched.c                   |    5 
 drivers/isdn/i4l/isdn_common.c                     |    2 
 drivers/isdn/i4l/isdn_net.c                        |   11 
 drivers/isdn/i4l/isdn_ppp.c                        |    9 
 drivers/isdn/isdnloop/isdnloop.c                   |    5 
 drivers/isdn/pcbit/capi.c                          |   12 
 drivers/kvm/kvm.h                                  |  100 
 drivers/kvm/kvm_main.c                             |  792 ++
 drivers/kvm/kvm_svm.h                              |   13 
 drivers/kvm/kvm_vmx.h                              |   14 
 drivers/kvm/mmu.c                                  |  154 
 drivers/kvm/paging_tmpl.h                          |   12 
 drivers/kvm/svm.c                                  |  197 -
 drivers/kvm/svm.h                                  |    6 
 drivers/kvm/vmx.c                                  |  273 -
 drivers/kvm/x86_emulate.c                          |   51 
 drivers/kvm/x86_emulate.h                          |   32 
 drivers/macintosh/Kconfig                          |   12 
 drivers/macintosh/adb.c                            |   42 
 drivers/macintosh/ans-lcd.c                        |    9 
 drivers/macintosh/apm_emu.c                        |  526 -
 drivers/macintosh/mac_hid.c                        |   10 
 drivers/macintosh/macio-adb.c                      |   16 
 drivers/macintosh/macio_asic.c                     |  100 
 drivers/macintosh/macio_sysfs.c                    |   27 
 drivers/macintosh/rack-meter.c                     |    2 
 drivers/macintosh/smu.c                            |   10 
 drivers/macintosh/therm_adt746x.c                  |   13 
 drivers/macintosh/therm_pm72.c                     |    9 
 drivers/macintosh/therm_windtunnel.c               |    5 
 drivers/macintosh/via-cuda.c                       |   60 
 drivers/macintosh/via-macii.c                      |  582 +
 drivers/macintosh/via-pmu-led.c                    |   43 
 drivers/macintosh/via-pmu.c                        |   67 
 drivers/macintosh/via-pmu68k.c                     |    3 
 drivers/macintosh/windfarm_core.c                  |    1 
 drivers/macintosh/windfarm_lm75_sensor.c           |    6 
 drivers/macintosh/windfarm_max6690_sensor.c        |    4 
 drivers/macintosh/windfarm_smu_controls.c          |   10 
 drivers/macintosh/windfarm_smu_sat.c               |   10 
 drivers/macintosh/windfarm_smu_sensors.c           |    6 
 drivers/md/bitmap.c                                |    8 
 drivers/md/dm-crypt.c                              |    2 
 drivers/md/dm-io.c                                 |    2 
 drivers/md/dm.c                                    |    2 
 drivers/md/md.c                                    |    2 
 drivers/media/common/ir-keymaps.c                  |   18 
 drivers/media/common/saa7146_video.c               |    6 
 drivers/media/dvb/b2c2/Kconfig                     |    1 
 drivers/media/dvb/b2c2/flexcop-fe-tuner.c          |    3 
 drivers/media/dvb/b2c2/flexcop-i2c.c               |    3 
 drivers/media/dvb/b2c2/flexcop-pci.c               |    9 
 drivers/media/dvb/bt8xx/Kconfig                    |    2 
 drivers/media/dvb/bt8xx/bt878.c                    |    4 
 drivers/media/dvb/bt8xx/dst_common.h               |    1 
 drivers/media/dvb/bt8xx/dvb-bt8xx.c                |    3 
 drivers/media/dvb/bt8xx/dvb-bt8xx.h                |    2 
 drivers/media/dvb/cinergyT2/cinergyT2.c            |    2 
 drivers/media/dvb/dvb-core/dmxdev.c                |   56 
 drivers/media/dvb/dvb-core/dmxdev.h                |    2 
 drivers/media/dvb/dvb-core/dvb_frontend.c          |   20 
 drivers/media/dvb/dvb-core/dvb_net.c               |   48 
 drivers/media/dvb/dvb-core/dvb_net.h               |    1 
 drivers/media/dvb/dvb-core/dvbdev.c                |    1 
 drivers/media/dvb/dvb-core/dvbdev.h                |    1 
 drivers/media/dvb/dvb-usb/Kconfig                  |   12 
 drivers/media/dvb/dvb-usb/Makefile                 |    4 
 drivers/media/dvb/dvb-usb/au6610.c                 |    6 
 drivers/media/dvb/dvb-usb/cxusb.c                  |    4 
 drivers/media/dvb/dvb-usb/dib0700_core.c           |    4 
 drivers/media/dvb/dvb-usb/dvb-usb-i2c.c            |    2 
 drivers/media/dvb/dvb-usb/dvb-usb-ids.h            |    6 
 drivers/media/dvb/dvb-usb/gl861.c                  |    8 
 drivers/media/dvb/dvb-usb/m920x.c                  |  235 -
 drivers/media/dvb/dvb-usb/m920x.h                  |   46 
 drivers/media/dvb/dvb-usb/opera1.c                 |  581 +
 drivers/media/dvb/dvb-usb/opera1.h                 |    9 
 drivers/media/dvb/dvb-usb/ttusb2.c                 |    7 
 drivers/media/dvb/frontends/Kconfig                |   28 
 drivers/media/dvb/frontends/Makefile               |    3 
 drivers/media/dvb/frontends/dibx000_common.c       |    4 
 drivers/media/dvb/frontends/dvb-pll.c              |  340 +
 drivers/media/dvb/frontends/dvb-pll.h              |   16 
 drivers/media/dvb/frontends/lgdt330x.c             |    4 
 drivers/media/dvb/frontends/lgh06xf.c              |  134 
 drivers/media/dvb/frontends/lgh06xf.h              |   35 
 drivers/media/dvb/frontends/or51132.c              |  305 -
 drivers/media/dvb/frontends/tda10021.c             |   47 
 drivers/media/dvb/frontends/tda10021.h             |   55 
 drivers/media/dvb/frontends/tda10023.c             |  540 +
 drivers/media/dvb/frontends/tda1002x.h             |   60 
 drivers/media/dvb/frontends/tda1004x.c             |   98 
 drivers/media/dvb/frontends/tda1004x.h             |   54 
 drivers/media/dvb/frontends/tda827x.c              |  512 +
 drivers/media/dvb/frontends/tda827x.h              |   62 
 drivers/media/dvb/pluto2/Kconfig                   |    1 
 drivers/media/dvb/ttpci/Kconfig                    |    6 
 drivers/media/dvb/ttpci/av7110.c                   |   17 
 drivers/media/dvb/ttpci/av7110.h                   |   28 
 drivers/media/dvb/ttpci/av7110_av.c                |   25 
 drivers/media/dvb/ttpci/av7110_ca.c                |    1 
 drivers/media/dvb/ttpci/av7110_hw.c                |    1 
 drivers/media/dvb/ttpci/av7110_hw.h                |   10 
 drivers/media/dvb/ttpci/av7110_ir.c                |  365 +
 drivers/media/dvb/ttpci/av7110_v4l.c               |    1 
 drivers/media/dvb/ttpci/budget-av.c                |  147 
 drivers/media/dvb/ttpci/budget-ci.c                |   96 
 drivers/media/dvb/ttpci/budget-core.c              |   58 
 drivers/media/dvb/ttpci/budget.h                   |    3 
 drivers/media/dvb/ttusb-budget/Kconfig             |    1 
 drivers/media/radio/dsbr100.c                      |    1 
 drivers/media/radio/radio-aimslab.c                |  240 -
 drivers/media/radio/radio-gemtek-pci.c             |  253 -
 drivers/media/radio/radio-gemtek.c                 |  260 -
 drivers/media/radio/radio-maestro.c                |  266 -
 drivers/media/radio/radio-rtrack2.c                |  255 -
 drivers/media/radio/radio-sf16fmi.c                |  262 -
 drivers/media/radio/radio-sf16fmr2.c               |  350 -
 drivers/media/radio/radio-terratec.c               |  247 -
 drivers/media/radio/radio-trust.c                  |  256 -
 drivers/media/radio/radio-typhoon.c                |  239 -
 drivers/media/radio/radio-zoltrix.c                |  256 -
 drivers/media/video/Kconfig                        |   20 
 drivers/media/video/Makefile                       |    2 
 drivers/media/video/adv7170.c                      |    1 
 drivers/media/video/adv7175.c                      |    1 
 drivers/media/video/bt819.c                        |    1 
 drivers/media/video/bt856.c                        |    1 
 drivers/media/video/bt866.c                        |    1 
 drivers/media/video/bt8xx/bttv-cards.c             |   53 
 drivers/media/video/bt8xx/bttv-driver.c            |   24 
 drivers/media/video/bt8xx/bttv-gpio.c              |    5 
 drivers/media/video/bt8xx/bttv-i2c.c               |    2 
 drivers/media/video/bt8xx/bttv-if.c                |   48 
 drivers/media/video/bt8xx/bttv.h                   |   25 
 drivers/media/video/bt8xx/bttvp.h                  |    3 
 drivers/media/video/cafe_ccic.c                    |   79 
 drivers/media/video/cpia.h                         |    1 
 drivers/media/video/cpia_pp.c                      |   50 
 drivers/media/video/cs53l32a.c                     |    4 
 drivers/media/video/cx2341x.c                      |   73 
 drivers/media/video/cx25840/cx25840-core.c         |    9 
 drivers/media/video/cx25840/cx25840-core.h         |    3 
 drivers/media/video/cx25840/cx25840-firmware.c     |    1 
 drivers/media/video/cx88/Kconfig                   |    1 
 drivers/media/video/cx88/cx88-alsa.c               |   11 
 drivers/media/video/cx88/cx88-cards.c              |   37 
 drivers/media/video/cx88/cx88-core.c               |    8 
 drivers/media/video/cx88/cx88-dvb.c                |   31 
 drivers/media/video/cx88/cx88-i2c.c                |    3 
 drivers/media/video/cx88/cx88-mpeg.c               |   30 
 drivers/media/video/cx88/cx88-tvaudio.c            |    2 
 drivers/media/video/cx88/cx88-video.c              |    7 
 drivers/media/video/cx88/cx88.h                    |    4 
 drivers/media/video/dabusb.c                       |    1 
 drivers/media/video/em28xx/em28xx-cards.c          |    1 
 drivers/media/video/em28xx/em28xx-i2c.c            |    2 
 drivers/media/video/ir-kbd-i2c.c                   |    2 
 drivers/media/video/ivtv/Kconfig                   |   26 
 drivers/media/video/ivtv/Makefile                  |    7 
 drivers/media/video/ivtv/ivtv-audio.c              |   74 
 drivers/media/video/ivtv/ivtv-audio.h              |   23 
 drivers/media/video/ivtv/ivtv-cards.c              |  964 ++
 drivers/media/video/ivtv/ivtv-cards.h              |  207 +
 drivers/media/video/ivtv/ivtv-controls.c           |  303 +
 drivers/media/video/ivtv/ivtv-controls.h           |   21 
 drivers/media/video/ivtv/ivtv-driver.c             | 1374 +++
 drivers/media/video/ivtv/ivtv-driver.h             |  868 ++
 drivers/media/video/ivtv/ivtv-fileops.c            |  921 ++
 drivers/media/video/ivtv/ivtv-fileops.h            |   44 
 drivers/media/video/ivtv/ivtv-firmware.c           |  272 +
 drivers/media/video/ivtv/ivtv-firmware.h           |   25 
 drivers/media/video/ivtv/ivtv-gpio.c               |  307 +
 drivers/media/video/ivtv/ivtv-gpio.h               |   25 
 drivers/media/video/ivtv/ivtv-i2c.c                |  748 ++
 drivers/media/video/ivtv/ivtv-i2c.h                |   36 
 drivers/media/video/ivtv/ivtv-ioctl.c              | 1567 ++++
 drivers/media/video/ivtv/ivtv-ioctl.h              |   28 
 drivers/media/video/ivtv/ivtv-irq.c                |  838 ++
 drivers/media/video/ivtv/ivtv-irq.h                |   26 
 drivers/media/video/ivtv/ivtv-mailbox.c            |  360 +
 drivers/media/video/ivtv/ivtv-mailbox.h            |   25 
 drivers/media/video/ivtv/ivtv-queue.c              |  262 +
 drivers/media/video/ivtv/ivtv-queue.h              |   64 
 drivers/media/video/ivtv/ivtv-streams.c            |  977 ++
 drivers/media/video/ivtv/ivtv-streams.h            |   31 
 drivers/media/video/ivtv/ivtv-udma.c               |  200 +
 drivers/media/video/ivtv/ivtv-udma.h               |   43 
 drivers/media/video/ivtv/ivtv-vbi.c                |  538 +
 drivers/media/video/ivtv/ivtv-vbi.h                |   26 
 drivers/media/video/ivtv/ivtv-version.h            |   26 
 drivers/media/video/ivtv/ivtv-video.c              |  142 
 drivers/media/video/ivtv/ivtv-video.h              |   24 
 drivers/media/video/ivtv/ivtv-yuv.c                | 1129 +++
 drivers/media/video/ivtv/ivtv-yuv.h                |   24 
 drivers/media/video/meye.c                         |   62 
 drivers/media/video/meye.h                         |    2 
 drivers/media/video/msp3400-driver.c               |    5 
 drivers/media/video/msp3400-driver.h               |    1 
 drivers/media/video/ov511.h                        |    1 
 drivers/media/video/ov7670.c                       |   40 
 drivers/media/video/ovcamchip/ovcamchip_priv.h     |    1 
 drivers/media/video/planb.c                        |   11 
 drivers/media/video/planb.h                        |    1 
 drivers/media/video/pvrusb2/pvrusb2-encoder.c      |    2 
 drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h |    2 
 drivers/media/video/pvrusb2/pvrusb2-hdw.c          |   16 
 drivers/media/video/pvrusb2/pvrusb2-hdw.h          |    3 
 drivers/media/video/pvrusb2/pvrusb2-main.c         |    1 
 drivers/media/video/pvrusb2/pvrusb2-sysfs.c        |   30 
 drivers/media/video/pvrusb2/pvrusb2-v4l2.c         |    2 
 drivers/media/video/pwc/pwc-ctrl.c                 |   61 
 drivers/media/video/pwc/pwc-if.c                   |   16 
 drivers/media/video/pwc/pwc-ioctl.h                |   36 
 drivers/media/video/pwc/pwc-kiara.c                |    2 
 drivers/media/video/pwc/pwc-kiara.h                |    5 
 drivers/media/video/pwc/pwc-timon.c                |    4 
 drivers/media/video/pwc/pwc-timon.h                |    6 
 drivers/media/video/pwc/pwc-v4l.c                  |   60 
 drivers/media/video/pwc/pwc.h                      |    5 
 drivers/media/video/saa7111.c                      |    1 
 drivers/media/video/saa7114.c                      |    1 
 drivers/media/video/saa7115.c                      |   10 
 drivers/media/video/saa711x.c                      |    1 
 drivers/media/video/saa7127.c                      |   12 
 drivers/media/video/saa7134/Kconfig                |    1 
 drivers/media/video/saa7134/saa7134-cards.c        |  204 -
 drivers/media/video/saa7134/saa7134-core.c         |  125 
 drivers/media/video/saa7134/saa7134-dvb.c          | 1027 +--
 drivers/media/video/saa7134/saa7134-i2c.c          |    4 
 drivers/media/video/saa7134/saa7134-input.c        |    1 
 drivers/media/video/saa7134/saa7134-tvaudio.c      |    1 
 drivers/media/video/saa7134/saa7134-video.c        |   85 
 drivers/media/video/saa7134/saa7134.h              |   10 
 drivers/media/video/saa7185.c                      |    1 
 drivers/media/video/se401.c                        |   36 
 drivers/media/video/se401.h                        |    1 
 drivers/media/video/sn9c102/Kconfig                |    2 
 drivers/media/video/sn9c102/Makefile               |   17 
 drivers/media/video/sn9c102/sn9c102.h              |   17 
 drivers/media/video/sn9c102/sn9c102_core.c         |  274 -
 drivers/media/video/sn9c102/sn9c102_devtable.h     |   14 
 drivers/media/video/sn9c102/sn9c102_hv7131d.c      |   25 
 drivers/media/video/sn9c102/sn9c102_hv7131r.c      |  366 +
 drivers/media/video/sn9c102/sn9c102_mi0343.c       |  130 
 drivers/media/video/sn9c102/sn9c102_mi0360.c       |  338 +
 drivers/media/video/sn9c102/sn9c102_ov7630.c       |  121 
 drivers/media/video/sn9c102/sn9c102_ov7660.c       |  234 -
 drivers/media/video/sn9c102/sn9c102_pas106b.c      |   23 
 drivers/media/video/sn9c102/sn9c102_pas202bcb.c    |   77 
 drivers/media/video/sn9c102/sn9c102_sensor.h       |   12 
 drivers/media/video/sn9c102/sn9c102_tas5110c1b.c   |   18 
 drivers/media/video/sn9c102/sn9c102_tas5110d.c     |  118 
 drivers/media/video/sn9c102/sn9c102_tas5130d1b.c   |   19 
 drivers/media/video/tda7432.c                      |    1 
 drivers/media/video/tda8290.c                      |  144 
 drivers/media/video/tda9875.c                      |    1 
 drivers/media/video/tuner-core.c                   |   28 
 drivers/media/video/tvaudio.c                      |    6 
 drivers/media/video/tveeprom.c                     |   45 
 drivers/media/video/upd64031a.c                    |    4 
 drivers/media/video/upd64083.c                     |    5 
 drivers/media/video/usbvideo/usbvideo.c            |   19 
 drivers/media/video/usbvision/usbvision-cards.c    | 1166 +++
 drivers/media/video/usbvision/usbvision-cards.h    |   66 
 drivers/media/video/usbvision/usbvision-core.c     |   11 
 drivers/media/video/usbvision/usbvision-i2c.c      |  104 
 drivers/media/video/usbvision/usbvision-video.c    |  174 
 drivers/media/video/usbvision/usbvision.h          |   39 
 drivers/media/video/v4l1-compat.c                  |    1 
 drivers/media/video/v4l2-common.c                  |   42 
 drivers/media/video/videocodec.c                   |    3 
 drivers/media/video/videodev.c                     |   41 
 drivers/media/video/wm8739.c                       |    4 
 drivers/media/video/wm8775.c                       |    4 
 drivers/media/video/zoran_driver.c                 |    2 
 drivers/media/video/zr364xx.c                      |  929 ++
 drivers/message/fusion/mptbase.c                   |   27 
 drivers/message/fusion/mptbase.h                   |    1 
 drivers/message/fusion/mptlan.c                    |   36 
 drivers/message/fusion/mptscsih.c                  |   35 
 drivers/message/fusion/mptspi.c                    |   36 
 drivers/message/i2o/i2o_lan.h                      |  159 
 drivers/mfd/ucb1x00-ts.c                           |    1 
 drivers/misc/Kconfig                               |   84 
 drivers/misc/Makefile                              |    3 
 drivers/misc/asus-laptop.c                         |  151 
 drivers/misc/blink.c                               |   27 
 drivers/misc/hdpuftrs/hdpu_cpustate.c              |    1 
 drivers/misc/hdpuftrs/hdpu_nexus.c                 |    1 
 drivers/misc/phantom.c                             |  463 +
 drivers/misc/sony-laptop.c                         | 2131 +++++
 drivers/misc/thinkpad_acpi.c                       | 4312 +++++++++++
 drivers/misc/thinkpad_acpi.h                       |  572 +
 drivers/misc/tifm_7xx1.c                           |  332 -
 drivers/misc/tifm_core.c                           |  305 -
 drivers/mmc/Kconfig                                |  106 
 drivers/mmc/Makefile                               |   33 
 drivers/mmc/at91_mci.c                             | 1002 ---
 drivers/mmc/au1xmmc.c                              | 1032 ---
 drivers/mmc/au1xmmc.h                              |   96 
 drivers/mmc/card/Kconfig                           |   17 
 drivers/mmc/card/Makefile                          |   11 
 drivers/mmc/card/block.c                           |  665 ++
 drivers/mmc/card/queue.c                           |  252 +
 drivers/mmc/card/queue.h                           |   32 
 drivers/mmc/core/Kconfig                           |   17 
 drivers/mmc/core/Makefile                          |   11 
 drivers/mmc/core/core.c                            |  727 ++
 drivers/mmc/core/core.h                            |   70 
 drivers/mmc/core/mmc.c                             |  537 +
 drivers/mmc/core/mmc_ops.c                         |  276 +
 drivers/mmc/core/mmc_ops.h                         |   27 
 drivers/mmc/core/sd.c                              |  587 +
 drivers/mmc/core/sd_ops.c                          |  316 +
 drivers/mmc/core/sd_ops.h                          |   25 
 drivers/mmc/core/sysfs.c                           |  360 +
 drivers/mmc/core/sysfs.h                           |   27 
 drivers/mmc/host/Kconfig                           |  103 
 drivers/mmc/host/Makefile                          |   18 
 drivers/mmc/host/at91_mci.c                        | 1001 +++
 drivers/mmc/host/au1xmmc.c                         | 1031 +++
 drivers/mmc/host/au1xmmc.h                         |   96 
 drivers/mmc/host/imxmmc.c                          | 1137 +++
 drivers/mmc/host/imxmmc.h                          |   67 
 drivers/mmc/host/mmci.c                            |  702 ++
 drivers/mmc/host/mmci.h                            |  179 
 drivers/mmc/host/omap.c                            | 1295 +++
 drivers/mmc/host/pxamci.c                          |  616 ++
 drivers/mmc/host/pxamci.h                          |  124 
 drivers/mmc/host/sdhci.c                           | 1535 ++++
 drivers/mmc/host/sdhci.h                           |  210 +
 drivers/mmc/host/tifm_sd.c                         | 1102 +++
 drivers/mmc/host/wbsd.c                            | 2061 +++++
 drivers/mmc/host/wbsd.h                            |  185 
 drivers/mmc/imxmmc.c                               | 1138 ---
 drivers/mmc/imxmmc.h                               |   67 
 drivers/mmc/mmc.c                                  | 1724 ----
 drivers/mmc/mmc.h                                  |   25 
 drivers/mmc/mmc_block.c                            |  644 --
 drivers/mmc/mmc_queue.c                            |  250 -
 drivers/mmc/mmc_queue.h                            |   32 
 drivers/mmc/mmc_sysfs.c                            |  364 -
 drivers/mmc/mmci.c                                 |  703 --
 drivers/mmc/mmci.h                                 |  179 
 drivers/mmc/omap.c                                 | 1289 ---
 drivers/mmc/pxamci.c                               |  617 --
 drivers/mmc/pxamci.h                               |  124 
 drivers/mmc/sdhci.c                                | 1550 ----
 drivers/mmc/sdhci.h                                |  212 -
 drivers/mmc/tifm_sd.c                              |  987 ---
 drivers/mmc/wbsd.c                                 | 2172 ------
 drivers/mmc/wbsd.h                                 |  188 
 drivers/mtd/Kconfig                                |   30 
 drivers/mtd/Makefile                               |    2 
 drivers/mtd/chips/Kconfig                          |   12 
 drivers/mtd/chips/cfi_cmdset_0001.c                |   93 
 drivers/mtd/chips/fwh_lock.h                       |    3 
 drivers/mtd/devices/Kconfig                        |   30 
 drivers/mtd/devices/Makefile                       |    1 
 drivers/mtd/devices/at91_dataflash26.c             |  485 +
 drivers/mtd/devices/block2mtd.c                    |   71 
 drivers/mtd/devices/doc2000.c                      |    1 
 drivers/mtd/devices/doc2001.c                      |    1 
 drivers/mtd/devices/doc2001plus.c                  |    1 
 drivers/mtd/devices/docecc.c                       |    1 
 drivers/mtd/inftlmount.c                           |    1 
 drivers/mtd/maps/Kconfig                           |   47 
 drivers/mtd/maps/Makefile                          |    2 
 drivers/mtd/maps/alchemy-flash.c                   |    9 
 drivers/mtd/maps/ck804xrom.c                       |    2 
 drivers/mtd/maps/physmap_of.c                      |    8 
 drivers/mtd/maps/plat-ram.c                        |    3 
 drivers/mtd/maps/pmcmsp-flash.c                    |  184 
 drivers/mtd/maps/pmcmsp-ramroot.c                  |  105 
 drivers/mtd/maps/sun_uflash.c                      |    4 
 drivers/mtd/mtd_blkdevs.c                          |   47 
 drivers/mtd/mtdchar.c                              |    2 
 drivers/mtd/nand/Kconfig                           |   63 
 drivers/mtd/nand/Makefile                          |    1 
 drivers/mtd/nand/cafe.c                            |   25 
 drivers/mtd/nand/cmx270_nand.c                     |  267 +
 drivers/mtd/nand/cs553x_nand.c                     |    1 
 drivers/mtd/nand/nand_base.c                       |    8 
 drivers/mtd/nand/nand_ids.c                        |    4 
 drivers/mtd/nand/nandsim.c                         |  518 +
 drivers/mtd/nftlcore.c                             |    1 
 drivers/mtd/onenand/Kconfig                        |   15 
 drivers/mtd/onenand/onenand_base.c                 |   21 
 drivers/mtd/ubi/Kconfig                            |   58 
 drivers/mtd/ubi/Kconfig.debug                      |  104 
 drivers/mtd/ubi/Makefile                           |    7 
 drivers/mtd/ubi/build.c                            |  848 ++
 drivers/mtd/ubi/cdev.c                             |  722 ++
 drivers/mtd/ubi/debug.c                            |  224 +
 drivers/mtd/ubi/debug.h                            |  161 
 drivers/mtd/ubi/eba.c                              | 1240 +++
 drivers/mtd/ubi/gluebi.c                           |  323 +
 drivers/mtd/ubi/io.c                               | 1259 +++
 drivers/mtd/ubi/kapi.c                             |  575 +
 drivers/mtd/ubi/misc.c                             |  105 
 drivers/mtd/ubi/scan.c                             | 1368 +++
 drivers/mtd/ubi/scan.h                             |  167 
 drivers/mtd/ubi/ubi.h                              |  535 +
 drivers/mtd/ubi/upd.c                              |  348 +
 drivers/mtd/ubi/vmt.c                              |  809 ++
 drivers/mtd/ubi/vtbl.c                             |  809 ++
 drivers/mtd/ubi/wl.c                               | 1671 ++++
 drivers/net/3c501.c                                |    1 
 drivers/net/3c505.c                                |    3 
 drivers/net/3c507.c                                |    1 
 drivers/net/3c509.c                                |    2 
 drivers/net/3c515.c                                |    2 
 drivers/net/3c523.c                                |    3 
 drivers/net/3c527.c                                |    1 
 drivers/net/3c59x.c                                |    2 
 drivers/net/7990.c                                 |    7 
 drivers/net/8139cp.c                               |    6 
 drivers/net/8139too.c                              |    7 
 drivers/net/82596.c                                |    1 
 drivers/net/Kconfig                                |   46 
 drivers/net/Makefile                               |    4 
 drivers/net/Space.c                                |    4 
 drivers/net/a2065.c                                |    9 
 drivers/net/acenic.c                               |    1 
 drivers/net/amd8111e.c                             |    4 
 drivers/net/appletalk/cops.c                       |    4 
 drivers/net/appletalk/ltpc.c                       |   15 
 drivers/net/arcnet/arc-rawmode.c                   |    2 
 drivers/net/arcnet/arcnet.c                        |   17 
 drivers/net/arcnet/capmode.c                       |   14 
 drivers/net/arcnet/rfc1051.c                       |    2 
 drivers/net/arcnet/rfc1201.c                       |    2 
 drivers/net/ariadne.c                              |    2 
 drivers/net/arm/am79c961a.c                        |    1 
 drivers/net/arm/at91_ether.c                       |   50 
 drivers/net/arm/at91_ether.h                       |   49 
 drivers/net/arm/ep93xx_eth.c                       |    1 
 drivers/net/arm/ether1.c                           |    1 
 drivers/net/arm/ether3.c                           |    1 
 drivers/net/at1700.c                               |    1 
 drivers/net/atari_bionet.c                         |    7 
 drivers/net/atari_pamsnet.c                        |    6 
 drivers/net/atarilance.c                           |    1 
 drivers/net/atl1/atl1_ethtool.c                    |   19 
 drivers/net/atl1/atl1_hw.c                         |   44 
 drivers/net/atl1/atl1_main.c                       |  116 
 drivers/net/atl1/atl1_param.c                      |   33 
 drivers/net/atp.c                                  |    1 
 drivers/net/au1000_eth.c                           |    4 
 drivers/net/b44.c                                  |    8 
 drivers/net/bmac.c                                 |    6 
 drivers/net/bnx2.c                                 |  983 ++
 drivers/net/bnx2.h                                 |   65 
 drivers/net/bnx2_fw.h                              | 1697 +++-
 drivers/net/bnx2_fw2.h                             | 7868 ++++++++++----------
 drivers/net/bonding/bond_3ad.c                     |    8 
 drivers/net/bonding/bond_alb.c                     |   36 
 drivers/net/bonding/bond_main.c                    |   66 
 drivers/net/cassini.c                              |   11 
 drivers/net/chelsio/Makefile                       |    4 
 drivers/net/chelsio/common.h                       |    6 
 drivers/net/chelsio/cphy.h                         |   16 
 drivers/net/chelsio/gmac.h                         |   10 
 drivers/net/chelsio/ixf1010.c                      |  505 -
 drivers/net/chelsio/mac.c                          |    2 
 drivers/net/chelsio/mv88e1xxx.c                    |    8 
 drivers/net/chelsio/mv88x201x.c                    |    8 
 drivers/net/chelsio/my3126.c                       |    8 
 drivers/net/chelsio/pm3393.c                       |    8 
 drivers/net/chelsio/sge.c                          |   39 
 drivers/net/chelsio/subr.c                         |  199 -
 drivers/net/chelsio/vsc7326.c                      |    2 
 drivers/net/chelsio/vsc8244.c                      |  367 -
 drivers/net/chelsio/vsc8244_reg.h                  |  172 
 drivers/net/cris/eth_v10.c                         |    4 
 drivers/net/cs89x0.c                               |    2 
 drivers/net/cxgb3/cxgb3_offload.c                  |    2 
 drivers/net/cxgb3/sge.c                            |   39 
 drivers/net/cxgb3/version.h                        |    4 
 drivers/net/de600.c                                |    1 
 drivers/net/de620.c                                |    1 
 drivers/net/declance.c                             |    1 
 drivers/net/defxx.c                                |    6 
 drivers/net/depca.c                                |    1 
 drivers/net/dgrs.c                                 |    3 
 drivers/net/dl2k.c                                 |    4 
 drivers/net/dm9000.c                               |   16 
 drivers/net/e100.c                                 |  161 
 drivers/net/e1000/e1000.h                          |    3 
 drivers/net/e1000/e1000_ethtool.c                  |   34 
 drivers/net/e1000/e1000_main.c                     |  208 -
 drivers/net/e1000/e1000_param.c                    |    4 
 drivers/net/eepro.c                                |    1 
 drivers/net/eepro100.c                             |    6 
 drivers/net/eexpress.c                             |   10 
 drivers/net/ehea/ehea.h                            |   42 
 drivers/net/ehea/ehea_ethtool.c                    |  115 
 drivers/net/ehea/ehea_main.c                       |  982 ++
 drivers/net/ehea/ehea_phyp.c                       |    6 
 drivers/net/ehea/ehea_phyp.h                       |    6 
 drivers/net/ehea/ehea_qmr.c                        |  184 
 drivers/net/ehea/ehea_qmr.h                        |   16 
 drivers/net/epic100.c                              |    3 
 drivers/net/eth16i.c                               |    1 
 drivers/net/ewrk3.c                                |    1 
 drivers/net/fealnx.c                               |    1 
 drivers/net/fec.c                                  |    1 
 drivers/net/fec_8xx/fec_main.c                     |    6 
 drivers/net/fec_8xx/fec_mii.c                      |    1 
 drivers/net/forcedeth.c                            |   30 
 drivers/net/fs_enet/fs_enet-main.c                 |   10 
 drivers/net/fs_enet/mac-fcc.c                      |    1 
 drivers/net/fs_enet/mac-fec.c                      |    1 
 drivers/net/fs_enet/mac-scc.c                      |    1 
 drivers/net/fs_enet/mii-bitbang.c                  |    1 
 drivers/net/fs_enet/mii-fec.c                      |    1 
 drivers/net/gianfar.c                              |   12 
 drivers/net/hamachi.c                              |    1 
 drivers/net/hamradio/baycom_ser_fdx.c              |   13 
 drivers/net/hamradio/bpqether.c                    |    2 
 drivers/net/hamradio/dmascc.c                      |    2 
 drivers/net/hamradio/hdlcdrv.c                     |    4 
 drivers/net/hamradio/yam.c                         |    4 
 drivers/net/hp100.c                                |    1 
 drivers/net/ibm_emac/ibm_emac_core.c               |    4 
 drivers/net/ibmlana.c                              |    1 
 drivers/net/ibmveth.c                              |   11 
 drivers/net/ioc3-eth.c                             |   13 
 drivers/net/irda/ali-ircc.c                        |    9 
 drivers/net/irda/au1k_ir.c                         |    6 
 drivers/net/irda/donauboe.c                        |    8 
 drivers/net/irda/irda-usb.c                        |    6 
 drivers/net/irda/mcs7780.c                         |   38 
 drivers/net/irda/nsc-ircc.c                        |   15 
 drivers/net/irda/pxaficp_ir.c                      |   18 
 drivers/net/irda/sa1100_ir.c                       |    2 
 drivers/net/irda/sir_dev.c                         |    1 
 drivers/net/irda/sir_dongle.c                      |    1 
 drivers/net/irda/smsc-ircc2.c                      |  117 
 drivers/net/irda/stir4200.c                        |    5 
 drivers/net/irda/via-ircc.c                        |   18 
 drivers/net/irda/vlsi_ir.c                         |    5 
 drivers/net/irda/w83977af_ir.c                     |   12 
 drivers/net/iseries_veth.c                         |    1 
 drivers/net/ixgb/ixgb.h                            |    3 
 drivers/net/ixgb/ixgb_ethtool.c                    |    4 
 drivers/net/ixgb/ixgb_main.c                       |   40 
 drivers/net/ixgb/ixgb_osdep.h                      |    1 
 drivers/net/ixgb/ixgb_param.c                      |    8 
 drivers/net/ixp2000/ixpdev.c                       |    3 
 drivers/net/jazzsonic.c                            |   27 
 drivers/net/lance.c                                |    3 
 drivers/net/lasi_82596.c                           |    2 
 drivers/net/lib8390.c                              |    1 
 drivers/net/loopback.c                             |   24 
 drivers/net/lp486e.c                               |    1 
 drivers/net/mac8390.c                              |  245 -
 drivers/net/mac89x0.c                              |   89 
 drivers/net/macb.c                                 |   11 
 drivers/net/mace.c                                 |    5 
 drivers/net/macmace.c                              |  595 +-
 drivers/net/macsonic.c                             |   65 
 drivers/net/meth.c                                 |   11 
 drivers/net/mii.c                                  |   57 
 drivers/net/mipsnet.c                              |   54 
 drivers/net/mv643xx_eth.c                          |   68 
 drivers/net/mv643xx_eth.h                          |    4 
 drivers/net/myri10ge/myri10ge.c                    |  268 -
 drivers/net/myri10ge/myri10ge_mcp.h                |   20 
 drivers/net/myri_sbus.c                            |    4 
 drivers/net/natsemi.c                              |   71 
 drivers/net/ne.c                                   |  123 
 drivers/net/netx-eth.c                             |    1 
 drivers/net/netxen/netxen_nic.h                    |  189 
 drivers/net/netxen/netxen_nic_ethtool.c            |  212 -
 drivers/net/netxen/netxen_nic_hdr.h                |   12 
 drivers/net/netxen/netxen_nic_hw.c                 |  416 +
 drivers/net/netxen/netxen_nic_hw.h                 |   85 
 drivers/net/netxen/netxen_nic_init.c               |  131 
 drivers/net/netxen/netxen_nic_isr.c                |  101 
 drivers/net/netxen/netxen_nic_main.c               |  781 +-
 drivers/net/netxen/netxen_nic_niu.c                |  168 
 drivers/net/netxen/netxen_nic_phan_reg.h           |  134 
 drivers/net/ni5010.c                               |    1 
 drivers/net/ni52.c                                 |    3 
 drivers/net/ni65.c                                 |    7 
 drivers/net/ns83820.c                              |    6 
 drivers/net/pasemi_mac.c                           |  418 +
 drivers/net/pasemi_mac.h                           |   23 
 drivers/net/pci-skeleton.c                         |    3 
 drivers/net/pcmcia/3c574_cs.c                      |    1 
 drivers/net/pcmcia/3c589_cs.c                      |    1 
 drivers/net/pcmcia/axnet_cs.c                      |    3 
 drivers/net/pcmcia/fmvj18x_cs.c                    |    1 
 drivers/net/pcmcia/nmclan_cs.c                     |    4 
 drivers/net/pcmcia/smc91c92_cs.c                   |    1 
 drivers/net/pcmcia/xirc2ps_cs.c                    |   15 
 drivers/net/pcnet32.c                              |  160 
 drivers/net/phy/fixed.c                            |    6 
 drivers/net/phy/mdio_bus.c                         |   19 
 drivers/net/phy/phy.c                              |  194 
 drivers/net/phy/phy_device.c                       |  123 
 drivers/net/plip.c                                 |    2 
 drivers/net/ppp_generic.c                          |    7 
 drivers/net/ppp_synctty.c                          |    3 
 drivers/net/pppoe.c                                |  156 
 drivers/net/pppox.c                                |   10 
 drivers/net/qla3xxx.c                              |  376 +
 drivers/net/qla3xxx.h                              |   33 
 drivers/net/r8169.c                                |    3 
 drivers/net/rionet.c                               |    1 
 drivers/net/rrunner.c                              |    3 
 drivers/net/s2io-regs.h                            |    2 
 drivers/net/s2io.c                                 |   82 
 drivers/net/s2io.h                                 |    8 
 drivers/net/saa9730.c                              |    1 
 drivers/net/sb1000.c                               |    2 
 drivers/net/sb1250-mac.c                           |  297 +
 drivers/net/sc92031.c                              |    1 
 drivers/net/seeq8005.c                             |    1 
 drivers/net/sgiseeq.c                              |   31 
 drivers/net/sis190.c                               |    1 
 drivers/net/sis900.c                               |   12 
 drivers/net/sk98lin/skge.c                         |   32 
 drivers/net/skfp/h/lnkstat.h                       |   84 
 drivers/net/skfp/skfddi.c                          |    3 
 drivers/net/skge.c                                 |   45 
 drivers/net/skge.h                                 |   10 
 drivers/net/sky2.c                                 |   28 
 drivers/net/slip.c                                 |    2 
 drivers/net/smc911x.c                              |    4 
 drivers/net/smc9194.c                              |    1 
 drivers/net/smc91x.c                               |    1 
 drivers/net/smc91x.h                               |   81 
 drivers/net/sonic.c                                |   34 
 drivers/net/spider_net.c                           |    7 
 drivers/net/starfire.c                             |    1 
 drivers/net/sun3_82586.c                           |    6 
 drivers/net/sun3lance.c                            |    5 
 drivers/net/sunbmac.c                              |    1 
 drivers/net/sundance.c                             |    1 
 drivers/net/sungem.c                               |   48 
 drivers/net/sungem.h                               |    2 
 drivers/net/sungem_phy.c                           |    2 
 drivers/net/sunhme.c                               |   33 
 drivers/net/sunlance.c                             |    4 
 drivers/net/sunqe.c                                |    3 
 drivers/net/tc35815.c                              | 2554 +++++-
 drivers/net/tg3.c                                  |  289 -
 drivers/net/tg3.h                                  |   16 
 drivers/net/tlan.c                                 |    4 
 drivers/net/tokenring/3c359.c                      |   11 
 drivers/net/tokenring/ibmtr.c                      |    1 
 drivers/net/tokenring/lanstreamer.c                |    7 
 drivers/net/tokenring/madgemc.c                    |    1 
 drivers/net/tokenring/olympic.c                    |   18 
 drivers/net/tokenring/smctr.c                      |    7 
 drivers/net/tokenring/tms380tr.c                   |    6 
 drivers/net/tsi108_eth.c                           |   13 
 drivers/net/tsi108_eth.h                           |    9 
 drivers/net/tulip/21142.c                          |    1 
 drivers/net/tulip/de2104x.c                        |    7 
 drivers/net/tulip/de4x5.c                          |   12 
 drivers/net/tulip/dmfe.c                           |  130 
 drivers/net/tulip/interrupt.c                      |    6 
 drivers/net/tulip/media.c                          |   40 
 drivers/net/tulip/pnic.c                           |    1 
 drivers/net/tulip/pnic2.c                          |    1 
 drivers/net/tulip/timer.c                          |    1 
 drivers/net/tulip/tulip.h                          |   10 
 drivers/net/tulip/tulip_core.c                     |   36 
 drivers/net/tulip/uli526x.c                        |   22 
 drivers/net/tulip/winbond-840.c                    |    7 
 drivers/net/tulip/xircom_cb.c                      |    7 
 drivers/net/tulip/xircom_tulip_cb.c                |    7 
 drivers/net/tun.c                                  |   46 
 drivers/net/typhoon.c                              |    1 
 drivers/net/ucc_geth.c                             |  956 +-
 drivers/net/ucc_geth.h                             |  114 
 drivers/net/ucc_geth_mii.c                         |  279 +
 drivers/net/ucc_geth_mii.h                         |  100 
 drivers/net/ucc_geth_phy.c                         |  785 --
 drivers/net/ucc_geth_phy.h                         |  217 -
 drivers/net/via-rhine.c                            |    1 
 drivers/net/via-velocity.c                         |   12 
 drivers/net/wan/cosa.c                             |    3 
 drivers/net/wan/cycx_x25.c                         |    2 
 drivers/net/wan/dlci.c                             |    2 
 drivers/net/wan/dscc4.c                            |    3 
 drivers/net/wan/farsync.c                          |    2 
 drivers/net/wan/hdlc_cisco.c                       |   31 
 drivers/net/wan/hdlc_fr.c                          |   23 
 drivers/net/wan/hostess_sv11.c                     |    2 
 drivers/net/wan/lmc/lmc_main.c                     |   16 
 drivers/net/wan/lmc/lmc_media.c                    |    1 
 drivers/net/wan/lmc/lmc_proto.c                    |    1 
 drivers/net/wan/pc300_drv.c                        |    6 
 drivers/net/wan/pc300_tty.c                        |    7 
 drivers/net/wan/sbni.c                             |    5 
 drivers/net/wan/sealevel.c                         |    2 
 drivers/net/wan/syncppp.c                          |    2 
 drivers/net/wan/z85230.c                           |    4 
 drivers/net/wireless/Kconfig                       |  145 
 drivers/net/wireless/Makefile                      |    1 
 drivers/net/wireless/README                        |   25 
 drivers/net/wireless/airo.c                        |   82 
 drivers/net/wireless/arlan-main.c                  |    1 
 drivers/net/wireless/atmel.c                       |    6 
 drivers/net/wireless/bcm43xx/Kconfig               |    3 
 drivers/net/wireless/bcm43xx/bcm43xx.h             |    3 
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c         |    3 
 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c     |    4 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c        |    4 
 drivers/net/wireless/bcm43xx/bcm43xx_phy.c         |   23 
 drivers/net/wireless/bcm43xx/bcm43xx_phy.h         |    4 
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c       |  196 
 drivers/net/wireless/hostap/Kconfig                |    3 
 drivers/net/wireless/hostap/hostap_80211_rx.c      |   23 
 drivers/net/wireless/hostap/hostap_80211_tx.c      |   25 
 drivers/net/wireless/hostap/hostap_ap.c            |   11 
 drivers/net/wireless/hostap/hostap_common.h        |    4 
 drivers/net/wireless/hostap/hostap_cs.c            |    9 
 drivers/net/wireless/hostap/hostap_hw.c            |   11 
 drivers/net/wireless/hostap/hostap_ioctl.c         |    1 
 drivers/net/wireless/hostap/hostap_main.c          |   21 
 drivers/net/wireless/hostap/hostap_pci.c           |    2 
 drivers/net/wireless/hostap/hostap_plx.c           |    2 
 drivers/net/wireless/ipw2100.c                     |    9 
 drivers/net/wireless/ipw2200.c                     |   51 
 drivers/net/wireless/libertas/11d.c                |  754 ++
 drivers/net/wireless/libertas/11d.h                |  105 
 drivers/net/wireless/libertas/LICENSE              |   16 
 drivers/net/wireless/libertas/Makefile             |   21 
 drivers/net/wireless/libertas/README               | 1044 +++
 drivers/net/wireless/libertas/assoc.c              |  588 +
 drivers/net/wireless/libertas/assoc.h              |   30 
 drivers/net/wireless/libertas/cmd.c                | 1958 +++++
 drivers/net/wireless/libertas/cmdresp.c            | 1031 +++
 drivers/net/wireless/libertas/debugfs.c            | 1935 +++++
 drivers/net/wireless/libertas/debugfs.h            |    6 
 drivers/net/wireless/libertas/decl.h               |   83 
 drivers/net/wireless/libertas/defs.h               |  369 +
 drivers/net/wireless/libertas/dev.h                |  403 +
 drivers/net/wireless/libertas/ethtool.c            |  184 
 drivers/net/wireless/libertas/fw.c                 |  361 +
 drivers/net/wireless/libertas/fw.h                 |   13 
 drivers/net/wireless/libertas/host.h               |  338 +
 drivers/net/wireless/libertas/hostcmd.h            |  693 ++
 drivers/net/wireless/libertas/if_bootcmd.c         |   38 
 drivers/net/wireless/libertas/if_usb.c             |  952 ++
 drivers/net/wireless/libertas/if_usb.h             |  109 
 drivers/net/wireless/libertas/ioctl.c              | 2500 ++++++
 drivers/net/wireless/libertas/join.c               | 1055 +++
 drivers/net/wireless/libertas/join.h               |   64 
 drivers/net/wireless/libertas/main.c               | 1258 +++
 drivers/net/wireless/libertas/radiotap.h           |   57 
 drivers/net/wireless/libertas/rx.c                 |  459 +
 drivers/net/wireless/libertas/sbi.h                |   40 
 drivers/net/wireless/libertas/scan.c               | 2044 +++++
 drivers/net/wireless/libertas/scan.h               |  216 +
 drivers/net/wireless/libertas/thread.h             |   52 
 drivers/net/wireless/libertas/tx.c                 |  285 +
 drivers/net/wireless/libertas/types.h              |  289 +
 drivers/net/wireless/libertas/version.h            |    8 
 drivers/net/wireless/libertas/wext.c               | 2769 +++++++
 drivers/net/wireless/libertas/wext.h               |  147 
 drivers/net/wireless/netwave_cs.c                  |    1 
 drivers/net/wireless/orinoco.c                     |    5 
 drivers/net/wireless/prism54/islpci_eth.c          |   23 
 drivers/net/wireless/ray_cs.c                      |    4 
 drivers/net/wireless/strip.c                       |    6 
 drivers/net/wireless/todo.txt                      |   15 
 drivers/net/wireless/wavelan.c                     |    9 
 drivers/net/wireless/wavelan_cs.c                  |    6 
 drivers/net/wireless/zd1201.c                      |    6 
 drivers/net/wireless/zd1211rw/Kconfig              |    3 
 drivers/net/wireless/zd1211rw/zd_chip.c            |   47 
 drivers/net/wireless/zd1211rw/zd_chip.h            |    1 
 drivers/net/wireless/zd1211rw/zd_mac.c             |   23 
 drivers/net/wireless/zd1211rw/zd_rf.c              |   18 
 drivers/net/wireless/zd1211rw/zd_rf.h              |   11 
 drivers/net/wireless/zd1211rw/zd_rf_al2230.c       |   91 
 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c      |  317 +
 drivers/net/wireless/zd1211rw/zd_rf_rf2959.c       |    4 
 drivers/net/wireless/zd1211rw/zd_usb.c             |   24 
 drivers/net/yellowfin.c                            |    1 
 drivers/net/znet.c                                 |    1 
 drivers/parisc/hppb.c                              |    2 
 drivers/parisc/lba_pci.c                           |    1 
 drivers/parisc/led.c                               |    4 
 drivers/parisc/pdc_stable.c                        |   94 
 drivers/parport/parport_cs.c                       |    2 
 drivers/parport/parport_mfc3.c                     |    1 
 drivers/parport/parport_pc.c                       |   70 
 drivers/parport/parport_serial.c                   |   10 
 drivers/parport/parport_sunbpp.c                   |    1 
 drivers/parport/share.c                            |    5 
 drivers/pci/Kconfig                                |   31 
 drivers/pci/bus.c                                  |    4 
 drivers/pci/hotplug/Kconfig                        |   25 
 drivers/pci/hotplug/acpiphp_core.c                 |    1 
 drivers/pci/hotplug/acpiphp_glue.c                 |    1 
 drivers/pci/hotplug/acpiphp_ibm.c                  |    4 
 drivers/pci/hotplug/cpcihp_zt5550.c                |    6 
 drivers/pci/hotplug/fakephp.c                      |    2 
 drivers/pci/hotplug/ibmphp_core.c                  |    1 
 drivers/pci/hotplug/ibmphp_hpc.c                   |    1 
 drivers/pci/hotplug/pci_hotplug_core.c             |    5 
 drivers/pci/hotplug/pciehp.h                       |   19 
 drivers/pci/hotplug/pciehp_core.c                  |   82 
 drivers/pci/hotplug/pciehp_ctrl.c                  |  616 +-
 drivers/pci/hotplug/pciehp_hpc.c                   |   34 
 drivers/pci/hotplug/rpadlpar_core.c                |   27 
 drivers/pci/hotplug/rpaphp.h                       |    8 
 drivers/pci/hotplug/rpaphp_core.c                  |  211 -
 drivers/pci/hotplug/rpaphp_pci.c                   |  167 
 drivers/pci/hotplug/rpaphp_slot.c                  |   49 
 drivers/pci/hotplug/shpchp.h                       |    2 
 drivers/pci/hotplug/shpchp_core.c                  |    2 
 drivers/pci/hotplug/shpchp_ctrl.c                  |    3 
 drivers/pci/msi.c                                  |  399 -
 drivers/pci/pci-acpi.c                             |    4 
 drivers/pci/pci-driver.c                           |   23 
 drivers/pci/pci-sysfs.c                            |    9 
 drivers/pci/pci.c                                  |   92 
 drivers/pci/pci.h                                  |    2 
 drivers/pci/probe.c                                |   42 
 drivers/pci/proc.c                                 |    1 
 drivers/pci/quirks.c                               |  115 
 drivers/pci/search.c                               |    3 
 drivers/pci/setup-bus.c                            |   21 
 drivers/pci/setup-res.c                            |    6 
 drivers/pcmcia/at91_cf.c                           |    3 
 drivers/pcmcia/cs.c                                |    1 
 drivers/pcmcia/ds.c                                |  113 
 drivers/pcmcia/pxa2xx_mainstone.c                  |    1 
 drivers/pcmcia/pxa2xx_sharpsl.c                    |    1 
 drivers/pcmcia/socket_sysfs.c                      |    1 
 drivers/pnp/card.c                                 |    6 
 drivers/pnp/core.c                                 |   11 
 drivers/pnp/pnpacpi/core.c                         |   55 
 drivers/pnp/pnpbios/core.c                         |   17 
 drivers/pnp/quirks.c                               |   30 
 drivers/ps3/ps3av.c                                |  108 
 drivers/ps3/ps3av_cmd.c                            |   20 
 drivers/ps3/vuart.c                                |   16 
 drivers/rtc/Kconfig                                |  272 -
 drivers/rtc/Makefile                               |    9 
 drivers/rtc/class.c                                |  118 
 drivers/rtc/hctosys.c                              |   14 
 drivers/rtc/interface.c                            |   86 
 drivers/rtc/rtc-at91rm9200.c                       |   32 
 drivers/rtc/rtc-bfin.c                             |  445 +
 drivers/rtc/rtc-cmos.c                             |   79 
 drivers/rtc/rtc-core.h                             |   70 
 drivers/rtc/rtc-dev.c                              |  184 
 drivers/rtc/rtc-ds1553.c                           |    2 
 drivers/rtc/rtc-lib.c                              |   81 
 drivers/rtc/rtc-max6900.c                          |  311 +
 drivers/rtc/rtc-omap.c                             |   57 
 drivers/rtc/rtc-pl031.c                            |    2 
 drivers/rtc/rtc-proc.c                             |   68 
 drivers/rtc/rtc-rs5c313.c                          |  405 +
 drivers/rtc/rtc-s3c.c                              |   26 
 drivers/rtc/rtc-sa1100.c                           |    4 
 drivers/rtc/rtc-sh.c                               |    6 
 drivers/rtc/rtc-sysfs.c                            |  129 
 drivers/rtc/rtc-test.c                             |    6 
 drivers/rtc/rtc-vr41xx.c                           |   32 
 drivers/s390/block/dasd.c                          |   48 
 drivers/s390/block/dasd_devmap.c                   |   58 
 drivers/s390/block/dasd_eckd.c                     |   81 
 drivers/s390/block/dasd_fba.c                      |    2 
 drivers/s390/block/dasd_int.h                      |    2 
 drivers/s390/char/Makefile                         |    5 
 drivers/s390/char/con3215.c                        |    7 
 drivers/s390/char/con3270.c                        |    7 
 drivers/s390/char/sclp.c                           |   10 
 drivers/s390/char/sclp.h                           |   72 
 drivers/s390/char/sclp_chp.c                       |  196 
 drivers/s390/char/sclp_config.c                    |   75 
 drivers/s390/char/sclp_cpi.c                       |    4 
 drivers/s390/char/sclp_quiesce.c                   |    2 
 drivers/s390/char/sclp_rw.c                        |   16 
 drivers/s390/char/sclp_sdias.c                     |  255 +
 drivers/s390/char/sclp_tty.c                       |    6 
 drivers/s390/char/sclp_vt220.c                     |    8 
 drivers/s390/char/tape.h                           |    1 
 drivers/s390/char/tape_3590.c                      |   29 
 drivers/s390/char/tape_3590.h                      |    4 
 drivers/s390/char/tape_core.c                      |    3 
 drivers/s390/char/vmlogrdr.c                       |    9 
 drivers/s390/char/zcore.c                          |  651 ++
 drivers/s390/cio/Makefile                          |    2 
 drivers/s390/cio/ccwgroup.c                        |   33 
 drivers/s390/cio/chp.c                             |  683 ++
 drivers/s390/cio/chp.h                             |   53 
 drivers/s390/cio/chsc.c                            | 1024 +--
 drivers/s390/cio/chsc.h                            |   42 
 drivers/s390/cio/cio.c                             |   52 
 drivers/s390/cio/cio.h                             |   17 
 drivers/s390/cio/cmf.c                             |    2 
 drivers/s390/cio/css.c                             |  201 -
 drivers/s390/cio/css.h                             |   16 
 drivers/s390/cio/device.c                          |  252 -
 drivers/s390/cio/device_fsm.c                      |    8 
 drivers/s390/cio/device_ops.c                      |    7 
 drivers/s390/cio/idset.c                           |  112 
 drivers/s390/cio/idset.h                           |   25 
 drivers/s390/cio/ioasm.h                           |    5 
 drivers/s390/cio/qdio.c                            |  277 -
 drivers/s390/cio/qdio.h                            |   56 
 drivers/s390/crypto/ap_bus.c                       |   28 
 drivers/s390/net/claw.c                            |    2 
 drivers/s390/net/ctcmain.c                         |   51 
 drivers/s390/net/lcs.c                             |    3 
 drivers/s390/net/netiucv.c                         |   26 
 drivers/s390/net/qeth.h                            |    3 
 drivers/s390/net/qeth_eddp.c                       |   34 
 drivers/s390/net/qeth_eddp.h                       |    3 
 drivers/s390/net/qeth_main.c                       |  167 
 drivers/s390/net/qeth_mpc.c                        |  101 
 drivers/s390/net/qeth_mpc.h                        |  220 -
 drivers/s390/net/qeth_proc.c                       |    2 
 drivers/s390/net/qeth_sys.c                        |    2 
 drivers/s390/net/qeth_tso.h                        |   14 
 drivers/s390/s390mach.c                            |   25 
 drivers/s390/scsi/zfcp_erp.c                       |    2 
 drivers/s390/scsi/zfcp_fsf.c                       |   10 
 drivers/s390/sysinfo.c                             |   18 
 drivers/sbus/char/bpp.c                            |    1 
 drivers/sbus/char/envctrl.c                        |    8 
 drivers/sbus/char/flash.c                          |    2 
 drivers/sbus/char/openprom.c                       |   22 
 drivers/sbus/char/rtc.c                            |    1 
 drivers/sbus/char/vfc_dev.c                        |    1 
 drivers/sbus/sbus.c                                |    5 
 drivers/scsi/BusLogic.c                            |   73 
 drivers/scsi/Kconfig                               |   34 
 drivers/scsi/Makefile                              |    5 
 drivers/scsi/aacraid/aachba.c                      |  402 +
 drivers/scsi/aacraid/aacraid.h                     |   76 
 drivers/scsi/aacraid/commctrl.c                    |  286 -
 drivers/scsi/aacraid/comminit.c                    |    4 
 drivers/scsi/aacraid/commsup.c                     |  112 
 drivers/scsi/aacraid/dpcsup.c                      |   36 
 drivers/scsi/aacraid/linit.c                       |   65 
 drivers/scsi/aacraid/nark.c                        |    3 
 drivers/scsi/aacraid/rkt.c                         |    3 
 drivers/scsi/aacraid/rx.c                          |  115 
 drivers/scsi/aacraid/sa.c                          |    1 
 drivers/scsi/aha1542.c                             |    1 
 drivers/scsi/aic7xxx/Kconfig.aic79xx               |   12 
 drivers/scsi/aic7xxx/Kconfig.aic7xxx               |   10 
 drivers/scsi/aic7xxx/aic79xx_osm.c                 |    6 
 drivers/scsi/aic7xxx/aic79xx_osm.h                 |    3 
 drivers/scsi/aic7xxx/aic7xxx.h                     |    5 
 drivers/scsi/aic7xxx/aic7xxx_core.c                |    2 
 drivers/scsi/aic7xxx/aic7xxx_osm.h                 |    1 
 drivers/scsi/aic94xx/aic94xx_scb.c                 |    1 
 drivers/scsi/arcmsr/arcmsr_attr.c                  |    1 
 drivers/scsi/atari_NCR5380.c                       | 4398 ++++++-----
 drivers/scsi/atari_scsi.c                          |  377 -
 drivers/scsi/atari_scsi.h                          |  174 
 drivers/scsi/constants.c                           |  274 -
 drivers/scsi/dpt/dpti_i2o.h                        |   48 
 drivers/scsi/dpt/dpti_ioctl.h                      |    2 
 drivers/scsi/dpt/dptsig.h                          |    4 
 drivers/scsi/dpt_i2o.c                             |    3 
 drivers/scsi/eata_generic.h                        |    7 
 drivers/scsi/esp.c                                 | 4394 -----------
 drivers/scsi/esp.h                                 |  406 -
 drivers/scsi/esp_scsi.c                            | 2711 +++++++
 drivers/scsi/esp_scsi.h                            |  560 +
 drivers/scsi/hosts.c                               |    4 
 drivers/scsi/ibmvscsi/ibmvscsi.c                   |   80 
 drivers/scsi/ibmvscsi/ibmvscsi.h                   |    2 
 drivers/scsi/ibmvscsi/ibmvstgt.c                   |   50 
 drivers/scsi/ibmvscsi/rpa_vscsi.c                  |    7 
 drivers/scsi/ipr.c                                 |  293 -
 drivers/scsi/ipr.h                                 |   45 
 drivers/scsi/iscsi_tcp.c                           |   21 
 drivers/scsi/libiscsi.c                            |   29 
 drivers/scsi/libsas/sas_expander.c                 |    1 
 drivers/scsi/libsrp.c                              |   13 
 drivers/scsi/lpfc/lpfc_init.c                      |    2 
 drivers/scsi/mac53c94.c                            |    2 
 drivers/scsi/megaraid.c                            |    2 
 drivers/scsi/mesh.c                                |    2 
 drivers/scsi/osst.c                                |    1 
 drivers/scsi/pci2000.h                             |  197 -
 drivers/scsi/pcmcia/Kconfig                        |    9 
 drivers/scsi/qla2xxx/qla_def.h                     |   13 
 drivers/scsi/qla2xxx/qla_init.c                    |  177 
 drivers/scsi/qla2xxx/qla_mbx.c                     |   16 
 drivers/scsi/qla2xxx/qla_os.c                      |    7 
 drivers/scsi/qla2xxx/qla_sup.c                     |   11 
 drivers/scsi/qla2xxx/qla_version.h                 |    2 
 drivers/scsi/qlogicpti.c                           |    2 
 drivers/scsi/scsi.c                                |   47 
 drivers/scsi/scsi_debug.c                          |    1 
 drivers/scsi/scsi_error.c                          |   19 
 drivers/scsi/scsi_lib.c                            |   10 
 drivers/scsi/scsi_netlink.c                        |    5 
 drivers/scsi/scsi_scan.c                           |    2 
 drivers/scsi/scsi_sysfs.c                          |   54 
 drivers/scsi/scsi_tgt_if.c                         |    6 
 drivers/scsi/scsi_tgt_lib.c                        |  261 -
 drivers/scsi/scsi_tgt_priv.h                       |    5 
 drivers/scsi/scsi_transport_fc.c                   |    2 
 drivers/scsi/scsi_transport_iscsi.c                |   10 
 drivers/scsi/sd.c                                  |  405 +
 drivers/scsi/sg.c                                  |   14 
 drivers/scsi/sni_53c710.c                          |    2 
 drivers/scsi/sr.c                                  |    2 
 drivers/scsi/st.c                                  |    1 
 drivers/scsi/sun_esp.c                             |  635 ++
 drivers/scsi/tmscsim.c                             |    2 
 drivers/serial/8250.c                              |  125 
 drivers/serial/Kconfig                             |  117 
 drivers/serial/Makefile                            |    1 
 drivers/serial/amba-pl010.c                        |  295 -
 drivers/serial/atmel_serial.c                      |    9 
 drivers/serial/atmel_serial.h                      |    3 
 drivers/serial/bfin_5xx.c                          | 1012 +++
 drivers/serial/cpm_uart/cpm_uart_core.c            |   12 
 drivers/serial/crisv10.h                           |  136 
 drivers/serial/icom.c                              |    1 
 drivers/serial/imx.c                               |  268 +
 drivers/serial/jsm/jsm_neo.c                       |    7 
 drivers/serial/jsm/jsm_tty.c                       |    1 
 drivers/serial/mpc52xx_uart.c                      |    7 
 drivers/serial/mpsc.c                              |   25 
 drivers/serial/of_serial.c                         |    7 
 drivers/serial/pmac_zilog.c                        |   12 
 drivers/serial/pxa.c                               |    8 
 drivers/serial/s3c2410.c                           |    6 
 drivers/serial/serial_core.c                       |   41 
 drivers/serial/serial_txx9.c                       |   32 
 drivers/serial/sh-sci.c                            |  113 
 drivers/serial/sh-sci.h                            |   83 
 drivers/serial/sunsu.c                             |   12 
 drivers/spi/Kconfig                                |   27 
 drivers/spi/Makefile                               |    5 
 drivers/spi/au1550_spi.c                           |  974 ++
 drivers/spi/spi.c                                  |   33 
 drivers/spi/spi_bfin5xx.c                          | 1313 +++
 drivers/spi/spi_butterfly.c                        |   83 
 drivers/spi/spi_s3c24xx.c                          |    2 
 drivers/spi/spidev.c                               |  584 +
 drivers/telephony/ixj.c                            |    3 
 drivers/usb/Kconfig                                |    2 
 drivers/usb/Makefile                               |   13 
 drivers/usb/atm/cxacru.c                           |  411 +
 drivers/usb/atm/usbatm.c                           |   28 
 drivers/usb/class/cdc-acm.c                        |   82 
 drivers/usb/class/cdc-acm.h                        |    3 
 drivers/usb/class/usblp.c                          |    1 
 drivers/usb/core/Kconfig                           |   25 
 drivers/usb/core/devices.c                         |    2 
 drivers/usb/core/devio.c                           |  109 
 drivers/usb/core/driver.c                          |  267 -
 drivers/usb/core/hcd.c                             |   34 
 drivers/usb/core/hcd.h                             |    3 
 drivers/usb/core/hub.c                             |   30 
 drivers/usb/core/inode.c                           |    3 
 drivers/usb/core/message.c                         |   83 
 drivers/usb/core/quirks.c                          |    2 
 drivers/usb/core/sysfs.c                           |  102 
 drivers/usb/core/usb.c                             |   47 
 drivers/usb/core/usb.h                             |   26 
 drivers/usb/gadget/Kconfig                         |   22 
 drivers/usb/gadget/Makefile                        |    1 
 drivers/usb/gadget/at91_udc.c                      |    1 
 drivers/usb/gadget/dummy_hcd.c                     |    1 
 drivers/usb/gadget/ether.c                         |    8 
 drivers/usb/gadget/fsl_usb2_udc.c                  | 2500 ++++++
 drivers/usb/gadget/fsl_usb2_udc.h                  |  579 +
 drivers/usb/gadget/gadget_chips.h                  |    8 
 drivers/usb/gadget/goku_udc.c                      |    1 
 drivers/usb/gadget/net2280.c                       |    1 
 drivers/usb/gadget/pxa2xx_udc.c                    |  102 
 drivers/usb/gadget/rndis.h                         |    2 
 drivers/usb/gadget/serial.c                        |    1 
 drivers/usb/gadget/zero.c                          |    1 
 drivers/usb/host/Makefile                          |    1 
 drivers/usb/host/ehci-fsl.h                        |    4 
 drivers/usb/host/ehci-hcd.c                        |    1 
 drivers/usb/host/ehci-hub.c                        |    4 
 drivers/usb/host/ehci-ps3.c                        |   11 
 drivers/usb/host/hc_crisv10.c                      | 4550 ------------
 drivers/usb/host/hc_crisv10.h                      |  289 -
 drivers/usb/host/ohci-hcd.c                        |    7 
 drivers/usb/host/ohci-pci.c                        |   32 
 drivers/usb/host/ohci-ppc-of.c                     |    4 
 drivers/usb/host/ohci-ps3.c                        |   12 
 drivers/usb/host/ohci-pxa27x.c                     |    4 
 drivers/usb/host/sl811-hcd.c                       |    1 
 drivers/usb/host/u132-hcd.c                        |    1 
 drivers/usb/host/uhci-q.c                          |   16 
 drivers/usb/image/mdc800.c                         |    1 
 drivers/usb/image/microtek.c                       |    1 
 drivers/usb/input/Kconfig                          |  370 -
 drivers/usb/input/Makefile                         |   55 
 drivers/usb/input/acecad.c                         |  279 -
 drivers/usb/input/aiptek.c                         | 2234 ------
 drivers/usb/input/appletouch.c                     |  705 --
 drivers/usb/input/ati_remote.c                     |  842 --
 drivers/usb/input/ati_remote2.c                    |  474 -
 drivers/usb/input/gtco.c                           | 1104 ---
 drivers/usb/input/hid-core.c                       | 1477 ----
 drivers/usb/input/hid-ff.c                         |   89 
 drivers/usb/input/hid-lgff.c                       |  150 
 drivers/usb/input/hid-pidff.c                      | 1331 ---
 drivers/usb/input/hid-plff.c                       |  129 
 drivers/usb/input/hid-tmff.c                       |  147 
 drivers/usb/input/hid-zpff.c                       |  111 
 drivers/usb/input/hiddev.c                         |  847 --
 drivers/usb/input/itmtouch.c                       |  271 -
 drivers/usb/input/kbtab.c                          |  220 -
 drivers/usb/input/keyspan_remote.c                 |  589 -
 drivers/usb/input/map_to_7segment.h                |  189 
 drivers/usb/input/mtouchusb.c                      |  332 -
 drivers/usb/input/powermate.c                      |  460 -
 drivers/usb/input/touchkitusb.c                    |  392 -
 drivers/usb/input/usbhid.h                         |   87 
 drivers/usb/input/usbkbd.c                         |  362 -
 drivers/usb/input/usbmouse.c                       |  245 -
 drivers/usb/input/usbtouchscreen.c                 |  838 --
 drivers/usb/input/wacom.h                          |  131 
 drivers/usb/input/wacom_sys.c                      |  312 -
 drivers/usb/input/wacom_wac.c                      |  675 --
 drivers/usb/input/wacom_wac.h                      |   49 
 drivers/usb/input/xpad.c                           |  428 -
 drivers/usb/input/yealink.c                        | 1002 ---
 drivers/usb/input/yealink.h                        |  220 -
 drivers/usb/misc/adutux.c                          |   48 
 drivers/usb/misc/cypress_cy7c63.c                  |    4 
 drivers/usb/misc/ftdi-elan.c                       |   19 
 drivers/usb/misc/idmouse.c                         |    1 
 drivers/usb/misc/iowarrior.c                       |   20 
 drivers/usb/misc/ldusb.c                           |    3 
 drivers/usb/misc/legousbtower.c                    |    1 
 drivers/usb/misc/rio500.c                          |    1 
 drivers/usb/misc/sisusbvga/sisusb_con.c            |    3 
 drivers/usb/misc/usblcd.c                          |    7 
 drivers/usb/mon/mon_bin.c                          |   14 
 drivers/usb/mon/mon_main.c                         |  159 
 drivers/usb/mon/mon_text.c                         |  315 +
 drivers/usb/mon/usb_mon.h                          |    6 
 drivers/usb/net/asix.c                             |    8 
 drivers/usb/net/catc.c                             |   30 
 drivers/usb/net/dm9601.c                           |    5 
 drivers/usb/net/gl620a.c                           |    2 
 drivers/usb/net/kaweth.c                           |    3 
 drivers/usb/net/net1080.c                          |    2 
 drivers/usb/net/pegasus.c                          |   17 
 drivers/usb/net/pegasus.h                          |    3 
 drivers/usb/net/rndis_host.c                       |  114 
 drivers/usb/net/rtl8150.c                          |    1 
 drivers/usb/net/usbnet.c                           |    9 
 drivers/usb/net/usbnet.h                           |    1 
 drivers/usb/serial/Kconfig                         |    6 
 drivers/usb/serial/aircable.c                      |    7 
 drivers/usb/serial/ark3116.c                       |    3 
 drivers/usb/serial/cp2101.c                        |    2 
 drivers/usb/serial/ftdi_sio.c                      |   23 
 drivers/usb/serial/ftdi_sio.h                      |    1 
 drivers/usb/serial/io_edgeport.c                   |  139 
 drivers/usb/serial/io_edgeport.h                   |    6 
 drivers/usb/serial/ipaq.c                          |    1 
 drivers/usb/serial/kl5kusb105.c                    |   28 
 drivers/usb/serial/mct_u232.c                      |   12 
 drivers/usb/serial/mos7720.c                       |   34 
 drivers/usb/serial/mos7840.c                       |  233 -
 drivers/usb/serial/omninet.c                       |   40 
 drivers/usb/serial/option.c                        |   23 
 drivers/usb/serial/sierra.c                        |   25 
 drivers/usb/serial/usb-serial.c                    |    1 
 drivers/usb/serial/visor.c                         |   22 
 drivers/usb/serial/whiteheat.c                     |    8 
 drivers/usb/serial/whiteheat.h                     |    4 
 drivers/usb/storage/libusual.c                     |    3 
 drivers/usb/storage/unusual_devs.h                 |    9 
 drivers/usb/storage/usb.h                          |    1 
 drivers/usb/usb-skeleton.c                         |   41 
 drivers/video/Kconfig                              |  168 
 drivers/video/Makefile                             |   25 
 drivers/video/arcfb.c                              |   28 
 drivers/video/atafb.c                              | 2801 ++++---
 drivers/video/atafb.h                              |   36 
 drivers/video/atafb_iplan2p2.c                     |  293 +
 drivers/video/atafb_iplan2p4.c                     |  308 +
 drivers/video/atafb_iplan2p8.c                     |  345 +
 drivers/video/atafb_mfb.c                          |  112 
 drivers/video/atafb_utils.h                        |  400 +
 drivers/video/aty/ati_ids.h                        |    2 
 drivers/video/aty/aty128fb.c                       |   29 
 drivers/video/aty/atyfb_base.c                     |   43 
 drivers/video/aty/mach64_ct.c                      |    8 
 drivers/video/aty/radeon_base.c                    |   23 
 drivers/video/aty/radeon_i2c.c                     |    1 
 drivers/video/aty/radeon_monitor.c                 |   27 
 drivers/video/aty/radeon_pm.c                      |   14 
 drivers/video/aty/radeonfb.h                       |    8 
 drivers/video/backlight/Kconfig                    |    8 
 drivers/video/backlight/Makefile                   |    1 
 drivers/video/backlight/cr_bllcd.c                 |  287 +
 drivers/video/cfbcopyarea.c                        |   14 
 drivers/video/cfbfillrect.c                        |   68 
 drivers/video/cg3.c                                |    2 
 drivers/video/cirrusfb.c                           |   69 
 drivers/video/console/fbcon.c                      |  136 
 drivers/video/console/fonts.c                      |   10 
 drivers/video/console/mdacon.c                     |    3 
 drivers/video/console/promcon.c                    |    3 
 drivers/video/console/sticon.c                     |    2 
 drivers/video/console/sticore.c                    |    2 
 drivers/video/console/vgacon.c                     |   20 
 drivers/video/controlfb.c                          |   16 
 drivers/video/display/Kconfig                      |   24 
 drivers/video/display/Makefile                     |    6 
 drivers/video/display/display-sysfs.c              |  217 +
 drivers/video/epson1355fb.c                        |   21 
 drivers/video/fb_defio.c                           |  151 
 drivers/video/fb_draw.h                            |   72 
 drivers/video/fb_sys_fops.c                        |  104 
 drivers/video/fbmem.c                              |  127 
 drivers/video/fbmon.c                              |  169 
 drivers/video/fbsysfs.c                            |    2 
 drivers/video/g364fb.c                             |    1 
 drivers/video/hecubafb.c                           |  471 +
 drivers/video/i810/i810.h                          |    2 
 drivers/video/igafb.c                              |   24 
 drivers/video/intelfb/intelfb_i2c.c                |    3 
 drivers/video/intelfb/intelfbhw.c                  |   34 
 drivers/video/logo/Kconfig                         |   30 
 drivers/video/matrox/i2c-matroxfb.c                |    2 
 drivers/video/modedb.c                             |    4 
 drivers/video/neofb.c                              |    1 
 drivers/video/nvidia/nv_accel.c                    |   76 
 drivers/video/nvidia/nv_hw.c                       |   15 
 drivers/video/nvidia/nv_i2c.c                      |   94 
 drivers/video/nvidia/nv_local.h                    |    4 
 drivers/video/nvidia/nv_of.c                       |    8 
 drivers/video/nvidia/nv_setup.c                    |    5 
 drivers/video/nvidia/nv_type.h                     |    8 
 drivers/video/nvidia/nvidia.c                      |   81 
 drivers/video/offb.c                               |   32 
 drivers/video/platinumfb.c                         |    1 
 drivers/video/pm2fb.c                              |  246 +
 drivers/video/ps3fb.c                              |  128 
 drivers/video/pvr2fb.c                             |    4 
 drivers/video/pxafb.c                              |    6 
 drivers/video/riva/fbdev.c                         |   22 
 drivers/video/riva/nv4ref.h                        | 2445 ------
 drivers/video/riva/nv_driver.c                     |    6 
 drivers/video/riva/riva_hw.c                       |   12 
 drivers/video/riva/rivafb-i2c.c                    |   41 
 drivers/video/riva/rivafb.h                        |    2 
 drivers/video/s3fb.c                               |   66 
 drivers/video/savage/savagefb-i2c.c                |   22 
 drivers/video/savage/savagefb.h                    |   10 
 drivers/video/savage/savagefb_driver.c             |   39 
 drivers/video/sis/osdef.h                          |    5 
 drivers/video/sis/sis.h                            |   51 
 drivers/video/sis/sis_main.c                       |  106 
 drivers/video/skeletonfb.c                         |  217 -
 drivers/video/sm501fb.c                            |    2 
 drivers/video/stifb.c                              |    1 
 drivers/video/sunxvr2500.c                         |  277 +
 drivers/video/sunxvr500.c                          |  443 +
 drivers/video/svgalib.c                            |   38 
 drivers/video/syscopyarea.c                        |  378 +
 drivers/video/sysfillrect.c                        |  334 +
 drivers/video/sysimgblt.c                          |  291 +
 drivers/video/tgafb.c                              |  425 +
 drivers/video/valkyriefb.c                         |    1 
 drivers/video/vermilion/Makefile                   |    5 
 drivers/video/vermilion/cr_pll.c                   |  208 +
 drivers/video/vermilion/vermilion.c                | 1195 +++
 drivers/video/vermilion/vermilion.h                |  260 +
 drivers/video/vfb.c                                |    8 
 drivers/video/vga16fb.c                            |    2 
 drivers/video/vgastate.c                           |   26 
 drivers/video/xilinxfb.c                           |  381 +
 drivers/w1/masters/Kconfig                         |    8 
 drivers/w1/masters/Makefile                        |    2 
 drivers/w1/masters/ds1wm.c                         |  468 +
 drivers/w1/w1.c                                    |    2 
 drivers/w1/w1_int.c                                |    3 
 drivers/zorro/proc.c                               |    5 
 drivers/zorro/zorro-sysfs.c                        |    3 
 drivers/zorro/zorro.c                              |    3 
 fs/9p/vfs_addr.c                                   |    1 
 fs/9p/vfs_dentry.c                                 |    1 
 fs/9p/vfs_dir.c                                    |    1 
 fs/9p/vfs_file.c                                   |    1 
 fs/9p/vfs_inode.c                                  |    1 
 fs/9p/vfs_super.c                                  |    1 
 fs/Kconfig                                         |   27 
 fs/Kconfig.binfmt                                  |    2 
 fs/adfs/super.c                                    |    3 
 fs/affs/super.c                                    |    3 
 fs/afs/Makefile                                    |    7 
 fs/afs/afs.h                                       |  146 
 fs/afs/afs_cm.h                                    |   32 
 fs/afs/afs_fs.h                                    |   48 
 fs/afs/afs_vl.h                                    |   84 
 fs/afs/cache.c                                     |  256 +
 fs/afs/cache.h                                     |   12 
 fs/afs/callback.c                                  |  509 +
 fs/afs/cell.c                                      |  471 -
 fs/afs/cell.h                                      |   78 
 fs/afs/cmservice.c                                 |  927 +-
 fs/afs/cmservice.h                                 |   29 
 fs/afs/dir.c                                       |  855 ++
 fs/afs/errors.h                                    |   34 
 fs/afs/file.c                                      |  124 
 fs/afs/fsclient.c                                  | 1529 ++--
 fs/afs/fsclient.h                                  |   54 
 fs/afs/inode.c                                     |  248 -
 fs/afs/internal.h                                  |  754 ++
 fs/afs/kafsasyncd.c                                |  255 -
 fs/afs/kafsasyncd.h                                |   52 
 fs/afs/kafstimod.c                                 |  205 -
 fs/afs/kafstimod.h                                 |   49 
 fs/afs/main.c                                      |  262 -
 fs/afs/misc.c                                      |   38 
 fs/afs/mntpt.c                                     |  150 
 fs/afs/mount.h                                     |   23 
 fs/afs/netdevices.c                                |   68 
 fs/afs/proc.c                                      |  230 -
 fs/afs/rxrpc.c                                     |  782 ++
 fs/afs/security.c                                  |  356 +
 fs/afs/server.c                                    |  647 +-
 fs/afs/server.h                                    |  102 
 fs/afs/super.c                                     |  395 +
 fs/afs/super.h                                     |   45 
 fs/afs/transport.h                                 |   21 
 fs/afs/types.h                                     |  125 
 fs/afs/vlclient.c                                  |  737 --
 fs/afs/vlclient.h                                  |   93 
 fs/afs/vlocation.c                                 | 1224 +--
 fs/afs/vnode.c                                     |  731 +-
 fs/afs/vnode.h                                     |   94 
 fs/afs/volume.c                                    |  290 -
 fs/afs/volume.h                                    |  140 
 fs/aio.c                                           |    6 
 fs/attr.c                                          |    1 
 fs/autofs4/inode.c                                 |    1 
 fs/autofs4/root.c                                  |    1 
 fs/bad_inode.c                                     |    1 
 fs/befs/linuxvfs.c                                 |    3 
 fs/bfs/inode.c                                     |    3 
 fs/binfmt_elf.c                                    |    5 
 fs/binfmt_elf_fdpic.c                              |    1 
 fs/binfmt_em86.c                                   |    1 
 fs/binfmt_misc.c                                   |    4 
 fs/binfmt_script.c                                 |    1 
 fs/bio.c                                           |   44 
 fs/block_dev.c                                     |   15 
 fs/buffer.c                                        |   26 
 fs/cifs/CHANGES                                    |   22 
 fs/cifs/README                                     |   43 
 fs/cifs/TODO                                       |   69 
 fs/cifs/cifs_fs_sb.h                               |   14 
 fs/cifs/cifs_unicode.c                             |    4 
 fs/cifs/cifsfs.c                                   |   82 
 fs/cifs/cifsfs.h                                   |    2 
 fs/cifs/cifsglob.h                                 |    2 
 fs/cifs/cifspdu.h                                  |   32 
 fs/cifs/cifsproto.h                                |    7 
 fs/cifs/cifssmb.c                                  |  130 
 fs/cifs/connect.c                                  |  140 
 fs/cifs/dir.c                                      |    2 
 fs/cifs/file.c                                     |  130 
 fs/cifs/inode.c                                    |  282 +
 fs/cifs/netmisc.c                                  |   24 
 fs/cifs/readdir.c                                  |  162 
 fs/coda/inode.c                                    |    3 
 fs/compat.c                                        |  224 -
 fs/compat_ioctl.c                                  | 1043 +++
 fs/configfs/mount.c                                |    2 
 fs/cramfs/inode.c                                  |    3 
 fs/dcache.c                                        |  144 
 fs/debugfs/file.c                                  |   42 
 fs/debugfs/inode.c                                 |    2 
 fs/devpts/inode.c                                  |    5 
 fs/dlm/Kconfig                                     |   31 
 fs/dlm/Makefile                                    |    6 
 fs/dlm/ast.c                                       |    1 
 fs/dlm/config.c                                    |   10 
 fs/dlm/config.h                                    |    3 
 fs/dlm/dlm_internal.h                              |   11 
 fs/dlm/lock.c                                      |  955 ++
 fs/dlm/lock.h                                      |    2 
 fs/dlm/lockspace.c                                 |    6 
 fs/dlm/lowcomms-sctp.c                             | 1210 ---
 fs/dlm/lowcomms-tcp.c                              | 1007 ---
 fs/dlm/lowcomms.c                                  | 1475 ++++
 fs/dlm/user.c                                      |  163 
 fs/dquot.c                                         |   10 
 fs/ecryptfs/file.c                                 |    1 
 fs/ecryptfs/main.c                                 |   15 
 fs/ecryptfs/mmap.c                                 |   11 
 fs/ecryptfs/netlink.c                              |    6 
 fs/efs/super.c                                     |    3 
 fs/eventpoll.c                                     |  238 -
 fs/exec.c                                          |   51 
 fs/exportfs/expfs.c                                |    1 
 fs/ext2/dir.c                                      |    4 
 fs/ext2/ext2.h                                     |    1 
 fs/ext2/fsync.c                                    |    1 
 fs/ext2/inode.c                                    |   26 
 fs/ext2/ioctl.c                                    |    1 
 fs/ext2/super.c                                    |    3 
 fs/ext2/xattr_security.c                           |    1 
 fs/ext2/xattr_trusted.c                            |    1 
 fs/ext3/dir.c                                      |    1 
 fs/ext3/inode.c                                    |   27 
 fs/ext3/ioctl.c                                    |    1 
 fs/ext3/namei.c                                    |   27 
 fs/ext3/resize.c                                   |    1 
 fs/ext3/super.c                                    |    7 
 fs/ext3/xattr_security.c                           |    1 
 fs/ext3/xattr_trusted.c                            |    1 
 fs/ext3/xattr_user.c                               |    1 
 fs/ext4/dir.c                                      |    1 
 fs/ext4/extents.c                                  |    1 
 fs/ext4/inode.c                                    |    7 
 fs/ext4/namei.c                                    |   27 
 fs/ext4/resize.c                                   |    1 
 fs/ext4/super.c                                    |    7 
 fs/ext4/xattr_security.c                           |    1 
 fs/ext4/xattr_trusted.c                            |    1 
 fs/ext4/xattr_user.c                               |    1 
 fs/fat/cache.c                                     |    3 
 fs/fat/dir.c                                       |  199 -
 fs/fat/inode.c                                     |   24 
 fs/fifo.c                                          |    1 
 fs/file_table.c                                    |    1 
 fs/filesystems.c                                   |   21 
 fs/freevxfs/vxfs_bmap.c                            |    2 
 fs/freevxfs/vxfs_inode.c                           |    2 
 fs/freevxfs/vxfs_subr.c                            |    3 
 fs/fuse/file.c                                     |    3 
 fs/fuse/inode.c                                    |    9 
 fs/gfs2/dir.c                                      |   38 
 fs/gfs2/glock.c                                    |  619 +-
 fs/gfs2/glock.h                                    |    8 
 fs/gfs2/glops.c                                    |    5 
 fs/gfs2/incore.h                                   |   14 
 fs/gfs2/locking/dlm/lock.c                         |   14 
 fs/gfs2/locking/dlm/lock_dlm.h                     |    3 
 fs/gfs2/locking/dlm/plock.c                        |  109 
 fs/gfs2/locking/dlm/sysfs.c                        |    2 
 fs/gfs2/locking/nolock/main.c                      |    9 
 fs/gfs2/lops.c                                     |   20 
 fs/gfs2/main.c                                     |   10 
 fs/gfs2/mount.c                                    |  239 -
 fs/gfs2/ops_address.c                              |   21 
 fs/gfs2/ops_dentry.c                               |    1 
 fs/gfs2/ops_file.c                                 |   13 
 fs/gfs2/ops_fstype.c                               |    4 
 fs/gfs2/ops_super.c                                |   28 
 fs/gfs2/rgrp.c                                     |   12 
 fs/gfs2/sys.c                                      |    2 
 fs/hfs/btree.c                                     |    3 
 fs/hfs/super.c                                     |    2 
 fs/hfsplus/btree.c                                 |    3 
 fs/hfsplus/super.c                                 |    2 
 fs/hostfs/hostfs.h                                 |   15 
 fs/hostfs/hostfs_kern.c                            |  192 
 fs/hostfs/hostfs_user.c                            |  229 -
 fs/hpfs/super.c                                    |    3 
 fs/hugetlbfs/inode.c                               |   20 
 fs/inode.c                                         |   47 
 fs/inotify.c                                       |    2 
 fs/internal.h                                      |   10 
 fs/ioctl.c                                         |    2 
 fs/isofs/inode.c                                   |    3 
 fs/jbd/commit.c                                    |    1 
 fs/jbd/journal.c                                   |   14 
 fs/jbd/revoke.c                                    |    1 
 fs/jbd/transaction.c                               |    1 
 fs/jbd2/commit.c                                   |    1 
 fs/jbd2/journal.c                                  |   14 
 fs/jbd2/revoke.c                                   |    1 
 fs/jbd2/transaction.c                              |    1 
 fs/jffs2/LICENCE                                   |    7 
 fs/jffs2/Makefile                                  |    1 
 fs/jffs2/README.Locking                            |    1 
 fs/jffs2/TODO                                      |    3 
 fs/jffs2/acl.c                                     |    3 
 fs/jffs2/acl.h                                     |    3 
 fs/jffs2/background.c                              |    4 
 fs/jffs2/build.c                                   |    4 
 fs/jffs2/compr.c                                   |  144 
 fs/jffs2/compr.h                                   |   17 
 fs/jffs2/compr_rtime.c                             |    3 
 fs/jffs2/compr_rubin.c                             |   81 
 fs/jffs2/compr_rubin.h                             |   21 
 fs/jffs2/compr_zlib.c                              |    4 
 fs/jffs2/comprtest.c                               |  307 -
 fs/jffs2/debug.c                                   |    5 
 fs/jffs2/debug.h                                   |    5 
 fs/jffs2/dir.c                                     |    4 
 fs/jffs2/erase.c                                   |    6 
 fs/jffs2/file.c                                    |    4 
 fs/jffs2/fs.c                                      |   16 
 fs/jffs2/gc.c                                      |    7 
 fs/jffs2/ioctl.c                                   |    4 
 fs/jffs2/jffs2_fs_i.h                              |   11 
 fs/jffs2/jffs2_fs_sb.h                             |   11 
 fs/jffs2/malloc.c                                  |    4 
 fs/jffs2/nodelist.c                                |  482 -
 fs/jffs2/nodelist.h                                |   40 
 fs/jffs2/nodemgmt.c                                |    9 
 fs/jffs2/os-linux.h                                |   10 
 fs/jffs2/pushpull.h                                |   72 
 fs/jffs2/read.c                                    |    4 
 fs/jffs2/readinode.c                               |  851 ++
 fs/jffs2/scan.c                                    |   62 
 fs/jffs2/security.c                                |    3 
 fs/jffs2/summary.c                                 |   12 
 fs/jffs2/summary.h                                 |   10 
 fs/jffs2/super.c                                   |    9 
 fs/jffs2/symlink.c                                 |    5 
 fs/jffs2/wbuf.c                                    |   39 
 fs/jffs2/write.c                                   |    7 
 fs/jffs2/writev.c                                  |    4 
 fs/jffs2/xattr.c                                   |    3 
 fs/jffs2/xattr.h                                   |    3 
 fs/jffs2/xattr_trusted.c                           |    3 
 fs/jffs2/xattr_user.c                              |    3 
 fs/jfs/inode.c                                     |    1 
 fs/jfs/ioctl.c                                     |    2 
 fs/jfs/jfs_imap.c                                  |    2 
 fs/jfs/jfs_inode.c                                 |   18 
 fs/jfs/jfs_inode.h                                 |    1 
 fs/jfs/jfs_lock.h                                  |    2 
 fs/jfs/jfs_logmgr.c                                |    8 
 fs/jfs/jfs_metapage.c                              |    3 
 fs/jfs/jfs_txnmgr.c                                |    7 
 fs/jfs/super.c                                     |    3 
 fs/libfs.c                                         |   23 
 fs/lockd/clntproc.c                                |    1 
 fs/lockd/mon.c                                     |   10 
 fs/lockd/svc4proc.c                                |    6 
 fs/lockd/svclock.c                                 |  275 +
 fs/lockd/svcproc.c                                 |    7 
 fs/lockd/svcsubs.c                                 |    2 
 fs/lockd/xdr.c                                     |   20 
 fs/lockd/xdr4.c                                    |   24 
 fs/locks.c                                         |  267 -
 fs/minix/dir.c                                     |    1 
 fs/minix/inode.c                                   |    3 
 fs/mpage.c                                         |   16 
 fs/namei.c                                         |   96 
 fs/namespace.c                                     |   41 
 fs/ncpfs/file.c                                    |    1 
 fs/ncpfs/inode.c                                   |    3 
 fs/nfs/client.c                                    |    4 
 fs/nfs/dir.c                                       |   25 
 fs/nfs/direct.c                                    |    6 
 fs/nfs/file.c                                      |    7 
 fs/nfs/getroot.c                                   |    1 
 fs/nfs/inode.c                                     |    3 
 fs/nfs/internal.h                                  |   12 
 fs/nfs/mount_clnt.c                                |    7 
 fs/nfs/nfs2xdr.c                                   |    7 
 fs/nfs/nfs3proc.c                                  |    1 
 fs/nfs/nfs3xdr.c                                   |   13 
 fs/nfs/nfs4proc.c                                  |    4 
 fs/nfs/nfs4renewd.c                                |    1 
 fs/nfs/nfs4xdr.c                                   |    7 
 fs/nfs/nfsroot.c                                   |    2 
 fs/nfs/pagelist.c                                  |  242 -
 fs/nfs/proc.c                                      |    1 
 fs/nfs/read.c                                      |   92 
 fs/nfs/super.c                                     |   10 
 fs/nfs/symlink.c                                   |    7 
 fs/nfs/write.c                                     |  263 -
 fs/nfsd/nfs4callback.c                             |    7 
 fs/nfsd/nfs4idmap.c                                |    1 
 fs/nfsd/nfs4state.c                                |   30 
 fs/nfsd/nfs4xdr.c                                  |    1 
 fs/nfsd/nfsfh.c                                    |    1 
 fs/ntfs/aops.h                                     |    3 
 fs/ntfs/attrib.c                                   |   18 
 fs/ntfs/dir.c                                      |    1 
 fs/ntfs/file.c                                     |   24 
 fs/ntfs/inode.c                                    |    1 
 fs/ntfs/super.c                                    |   33 
 fs/ocfs2/alloc.c                                   | 3043 ++++++--
 fs/ocfs2/alloc.h                                   |   27 
 fs/ocfs2/aops.c                                    | 1014 ++-
 fs/ocfs2/aops.h                                    |   77 
 fs/ocfs2/cluster/heartbeat.c                       |    2 
 fs/ocfs2/cluster/masklog.c                         |    4 
 fs/ocfs2/cluster/masklog.h                         |    2 
 fs/ocfs2/cluster/quorum.c                          |    5 
 fs/ocfs2/cluster/sys.c                             |    7 
 fs/ocfs2/cluster/tcp.c                             |   10 
 fs/ocfs2/cluster/tcp_internal.h                    |    5 
 fs/ocfs2/dir.c                                     |   22 
 fs/ocfs2/dlm/dlmast.c                              |   12 
 fs/ocfs2/dlm/dlmdomain.c                           |    5 
 fs/ocfs2/dlm/dlmfs.c                               |    4 
 fs/ocfs2/dlm/dlmrecovery.c                         |    6 
 fs/ocfs2/dlm/dlmthread.c                           |    2 
 fs/ocfs2/dlmglue.c                                 |  198 -
 fs/ocfs2/dlmglue.h                                 |   10 
 fs/ocfs2/export.c                                  |    6 
 fs/ocfs2/extent_map.c                              | 1233 +--
 fs/ocfs2/extent_map.h                              |   39 
 fs/ocfs2/file.c                                    |  654 +-
 fs/ocfs2/file.h                                    |   10 
 fs/ocfs2/inode.c                                   |  229 -
 fs/ocfs2/inode.h                                   |   24 
 fs/ocfs2/ioctl.c                                   |   24 
 fs/ocfs2/ioctl.h                                   |    1 
 fs/ocfs2/journal.c                                 |   31 
 fs/ocfs2/journal.h                                 |    2 
 fs/ocfs2/mmap.c                                    |    7 
 fs/ocfs2/namei.c                                   |   28 
 fs/ocfs2/ocfs2.h                                   |   67 
 fs/ocfs2/ocfs2_fs.h                                |   33 
 fs/ocfs2/ocfs2_lockid.h                            |    5 
 fs/ocfs2/slot_map.c                                |    3 
 fs/ocfs2/suballoc.c                                |   13 
 fs/ocfs2/super.c                                   |   12 
 fs/ocfs2/symlink.c                                 |    7 
 fs/ocfs2/vote.c                                    |  290 -
 fs/ocfs2/vote.h                                    |    3 
 fs/open.c                                          |    1 
 fs/openpromfs/inode.c                              |    3 
 fs/partitions/Kconfig                              |    9 
 fs/partitions/Makefile                             |    1 
 fs/partitions/acorn.c                              |    2 
 fs/partitions/check.c                              |   13 
 fs/partitions/sysv68.c                             |   92 
 fs/partitions/sysv68.h                             |    1 
 fs/pipe.c                                          |   18 
 fs/pnode.c                                         |    2 
 fs/proc/array.c                                    |    4 
 fs/proc/base.c                                     |  302 +
 fs/proc/generic.c                                  |   13 
 fs/proc/inode.c                                    |   17 
 fs/proc/internal.h                                 |    2 
 fs/proc/proc_devtree.c                             |    2 
 fs/proc/proc_misc.c                                |   12 
 fs/proc/proc_sysctl.c                              |    7 
 fs/proc/proc_tty.c                                 |    3 
 fs/proc/task_mmu.c                                 |  151 
 fs/proc/task_nommu.c                               |    7 
 fs/proc/vmcore.c                                   |    2 
 fs/qnx4/inode.c                                    |    3 
 fs/quota.c                                         |    1 
 fs/ramfs/file-nommu.c                              |    1 
 fs/ramfs/inode.c                                   |    1 
 fs/read_write.c                                    |   16 
 fs/readdir.c                                       |    9 
 fs/reiserfs/dir.c                                  |    1 
 fs/reiserfs/file.c                                 |    1 
 fs/reiserfs/journal.c                              |    2 
 fs/reiserfs/namei.c                                |    1 
 fs/reiserfs/procfs.c                               |    3 
 fs/reiserfs/resize.c                               |    4 
 fs/reiserfs/stree.c                                |    1 
 fs/reiserfs/super.c                                |   10 
 fs/reiserfs/xattr.c                                |    6 
 fs/romfs/inode.c                                   |    3 
 fs/select.c                                        |    9 
 fs/smbfs/inode.c                                   |    3 
 fs/smbfs/request.c                                 |    7 
 fs/smbfs/smbiod.c                                  |    3 
 fs/smbfs/sock.c                                    |    1 
 fs/smbfs/symlink.c                                 |    1 
 fs/splice.c                                        |   17 
 fs/stat.c                                          |    1 
 fs/super.c                                         |   39 
 fs/sync.c                                          |   10 
 fs/sysfs/file.c                                    |   25 
 fs/sysfs/group.c                                   |    6 
 fs/sysv/dir.c                                      |   10 
 fs/sysv/inode.c                                    |    3 
 fs/sysv/namei.c                                    |    1 
 fs/udf/balloc.c                                    |  177 
 fs/udf/dir.c                                       |   39 
 fs/udf/directory.c                                 |   30 
 fs/udf/fsync.c                                     |    1 
 fs/udf/inode.c                                     |  581 +
 fs/udf/misc.c                                      |    6 
 fs/udf/namei.c                                     |  226 -
 fs/udf/partition.c                                 |    2 
 fs/udf/super.c                                     |   79 
 fs/udf/symlink.c                                   |    2 
 fs/udf/truncate.c                                  |  206 -
 fs/udf/udf_sb.h                                    |    2 
 fs/udf/udfdecl.h                                   |   25 
 fs/ufs/dir.c                                       |    7 
 fs/ufs/super.c                                     |    3 
 fs/ufs/util.c                                      |    6 
 fs/utimes.c                                        |  162 
 fs/xattr.c                                         |    1 
 fs/xfs/linux-2.6/mrlock.h                          |   12 
 fs/xfs/linux-2.6/xfs_aops.c                        |   89 
 fs/xfs/linux-2.6/xfs_buf.c                         |   10 
 fs/xfs/linux-2.6/xfs_buf.h                         |    3 
 fs/xfs/linux-2.6/xfs_fs_subr.c                     |   21 
 fs/xfs/linux-2.6/xfs_fs_subr.h                     |    2 
 fs/xfs/linux-2.6/xfs_lrw.c                         |  185 
 fs/xfs/linux-2.6/xfs_super.c                       |    3 
 fs/xfs/linux-2.6/xfs_vnode.h                       |    2 
 fs/xfs/quota/xfs_dquot.c                           |    3 
 fs/xfs/quota/xfs_qm.c                              |   16 
 fs/xfs/quota/xfs_qm_syscalls.c                     |   19 
 fs/xfs/quota/xfs_trans_dquot.c                     |    4 
 fs/xfs/support/debug.c                             |   17 
 fs/xfs/support/debug.h                             |    2 
 fs/xfs/xfs_alloc.c                                 |    2 
 fs/xfs/xfs_attr.c                                  |   12 
 fs/xfs/xfs_attr_leaf.c                             |    2 
 fs/xfs/xfs_bmap.c                                  |   28 
 fs/xfs/xfs_dfrag.c                                 |    6 
 fs/xfs/xfs_dir2_block.c                            |   14 
 fs/xfs/xfs_dir2_data.c                             |    7 
 fs/xfs/xfs_dir2_data.h                             |    2 
 fs/xfs/xfs_dir2_leaf.c                             |    7 
 fs/xfs/xfs_dir2_node.c                             |    4 
 fs/xfs/xfs_error.c                                 |    2 
 fs/xfs/xfs_fsops.c                                 |    4 
 fs/xfs/xfs_iget.c                                  |   15 
 fs/xfs/xfs_inode.c                                 |   58 
 fs/xfs/xfs_inode.h                                 |   65 
 fs/xfs/xfs_iocore.c                                |    2 
 fs/xfs/xfs_iomap.c                                 |   15 
 fs/xfs/xfs_iomap.h                                 |    1 
 fs/xfs/xfs_log_recover.c                           |   15 
 fs/xfs/xfs_mount.c                                 |    2 
 fs/xfs/xfs_qmops.c                                 |    2 
 fs/xfs/xfs_quota.h                                 |    3 
 fs/xfs/xfs_rename.c                                |    2 
 fs/xfs/xfs_rtalloc.c                               |    6 
 fs/xfs/xfs_rw.c                                    |    4 
 fs/xfs/xfs_trans.c                                 |    6 
 fs/xfs/xfs_trans.h                                 |    4 
 fs/xfs/xfs_utils.c                                 |   11 
 fs/xfs/xfs_vfsops.c                                |    6 
 fs/xfs/xfs_vnodeops.c                              |  125 
 include/acpi/acpi_bus.h                            |    5 
 include/acpi/actbl.h                               |    1 
 include/asm-alpha/atomic.h                         |   64 
 include/asm-alpha/kdebug.h                         |    1 
 include/asm-alpha/local.h                          |  126 
 include/asm-alpha/mmu_context.h                    |    1 
 include/asm-alpha/percpu.h                         |   14 
 include/asm-alpha/pgtable.h                        |    4 
 include/asm-alpha/scatterlist.h                    |    1 
 include/asm-alpha/socket.h                         |    2 
 include/asm-alpha/sockios.h                        |    3 
 include/asm-alpha/string.h                         |    2 
 include/asm-alpha/system.h                         |  226 +
 include/asm-alpha/thread_info.h                    |   22 
 include/asm-arm/arch-at91/at91_adc.h               |   61 
 include/asm-arm/arch-at91/board.h                  |   12 
 include/asm-arm/arch-ebsa110/io.h                  |    8 
 include/asm-arm/arch-imx/imx-regs.h                |  118 
 include/asm-arm/arch-imx/mmc.h                     |    2 
 include/asm-arm/arch-iop13xx/io.h                  |    1 
 include/asm-arm/arch-iop13xx/iop13xx.h             |   24 
 include/asm-arm/arch-iop13xx/time.h                |   56 
 include/asm-arm/arch-iop32x/io.h                   |    1 
 include/asm-arm/arch-iop32x/iop32x.h               |    9 
 include/asm-arm/arch-iop32x/memory.h               |    4 
 include/asm-arm/arch-iop33x/io.h                   |    1 
 include/asm-arm/arch-iop33x/iop33x.h               |   10 
 include/asm-arm/arch-iop33x/memory.h               |    4 
 include/asm-arm/arch-ixp23xx/io.h                  |    4 
 include/asm-arm/arch-ixp4xx/cpu.h                  |   31 
 include/asm-arm/arch-ixp4xx/dma.h                  |    1 
 include/asm-arm/arch-ixp4xx/dsmg600.h              |   57 
 include/asm-arm/arch-ixp4xx/entry-macro.S          |    4 
 include/asm-arm/arch-ixp4xx/gpio.h                 |   73 
 include/asm-arm/arch-ixp4xx/hardware.h             |   12 
 include/asm-arm/arch-ixp4xx/io.h                   |    6 
 include/asm-arm/arch-ixp4xx/irqs.h                 |   16 
 include/asm-arm/arch-ixp4xx/ixp4xx-regs.h          |   15 
 include/asm-arm/arch-netx/netx-regs.h              |    4 
 include/asm-arm/arch-ns9xxx/board.h                |    2 
 include/asm-arm/arch-ns9xxx/clock.h                |   34 
 include/asm-arm/arch-ns9xxx/hardware.h             |    5 
 include/asm-arm/arch-ns9xxx/processor.h            |    3 
 include/asm-arm/arch-ns9xxx/regs-sys.h             |    6 
 include/asm-arm/arch-pxa/i2c.h                     |    1 
 include/asm-arm/arch-pxa/mmc.h                     |    2 
 include/asm-arm/arch-pxa/pxa-regs.h                |   58 
 include/asm-arm/arch-pxa/pxa27x_keyboard.h         |   13 
 include/asm-arm/arch-s3c2410/regs-ac97.h           |   56 
 include/asm-arm/arch-s3c2410/regs-udc.h            |    6 
 include/asm-arm/atomic.h                           |    1 
 include/asm-arm/div64.h                            |    3 
 include/asm-arm/ecard.h                            |   52 
 include/asm-arm/hardware/iop3xx.h                  |   24 
 include/asm-arm/io.h                               |   33 
 include/asm-arm/kdebug.h                           |    1 
 include/asm-arm/kexec.h                            |    2 
 include/asm-arm/mach/map.h                         |   21 
 include/asm-arm/mach/mmc.h                         |    2 
 include/asm-arm/mmu_context.h                      |    1 
 include/asm-arm/pgtable-nommu.h                    |    4 
 include/asm-arm/pgtable.h                          |    4 
 include/asm-arm/plat-s3c24xx/clock.h               |    1 
 include/asm-arm/plat-s3c24xx/cpu.h                 |   16 
 include/asm-arm/ptrace.h                           |   10 
 include/asm-arm/socket.h                           |    2 
 include/asm-arm/sockios.h                          |    3 
 include/asm-arm/system.h                           |    6 
 include/asm-arm/thread_info.h                      |    1 
 include/asm-arm26/atomic.h                         |    1 
 include/asm-arm26/kdebug.h                         |    1 
 include/asm-arm26/mmu_context.h                    |    2 
 include/asm-arm26/pgtable.h                        |    4 
 include/asm-arm26/socket.h                         |    2 
 include/asm-arm26/sockios.h                        |    3 
 include/asm-arm26/system.h                         |    2 
 include/asm-avr32/arch-at32ap/io.h                 |   39 
 include/asm-avr32/arch-at32ap/smc.h                |   22 
 include/asm-avr32/arch-at32ap/time.h               |  112 
 include/asm-avr32/atomic.h                         |    2 
 include/asm-avr32/bug.h                            |   50 
 include/asm-avr32/io.h                             |  326 -
 include/asm-avr32/kdebug.h                         |   25 
 include/asm-avr32/mmu_context.h                    |    1 
 include/asm-avr32/pgtable.h                        |    4 
 include/asm-avr32/processor.h                      |   15 
 include/asm-avr32/scatterlist.h                    |    2 
 include/asm-avr32/setup.h                          |   13 
 include/asm-avr32/socket.h                         |    2 
 include/asm-avr32/sockios.h                        |    3 
 include/asm-avr32/sysreg.h                         |  543 +
 include/asm-avr32/system.h                         |   13 
 include/asm-avr32/thread_info.h                    |    2 
 include/asm-avr32/uaccess.h                        |   13 
 include/asm-blackfin/Kbuild                        |    1 
 include/asm-blackfin/a.out.h                       |   25 
 include/asm-blackfin/atomic.h                      |  144 
 include/asm-blackfin/auxvec.h                      |    4 
 include/asm-blackfin/bf5xx_timers.h                |  209 +
 include/asm-blackfin/bfin-global.h                 |  120 
 include/asm-blackfin/bfin5xx_spi.h                 |  170 
 include/asm-blackfin/bfin_simple_timer.h           |   13 
 include/asm-blackfin/bfin_sport.h                  |  175 
 include/asm-blackfin/bitops.h                      |  213 +
 include/asm-blackfin/blackfin.h                    |   81 
 include/asm-blackfin/bug.h                         |    4 
 include/asm-blackfin/bugs.h                        |   16 
 include/asm-blackfin/byteorder.h                   |   48 
 include/asm-blackfin/cache.h                       |   29 
 include/asm-blackfin/cacheflush.h                  |   90 
 include/asm-blackfin/checksum.h                    |  101 
 include/asm-blackfin/cplb.h                        |   51 
 include/asm-blackfin/cplbinit.h                    |  203 +
 include/asm-blackfin/cpumask.h                     |    6 
 include/asm-blackfin/cputime.h                     |    6 
 include/asm-blackfin/current.h                     |   23 
 include/asm-blackfin/delay.h                       |   44 
 include/asm-blackfin/device.h                      |    7 
 include/asm-blackfin/div64.h                       |    1 
 include/asm-blackfin/dma-mapping.h                 |   66 
 include/asm-blackfin/dma.h                         |  188 
 include/asm-blackfin/dpmc.h                        |   70 
 include/asm-blackfin/elf.h                         |  127 
 include/asm-blackfin/emergency-restart.h           |    6 
 include/asm-blackfin/entry.h                       |   56 
 include/asm-blackfin/errno.h                       |    6 
 include/asm-blackfin/fcntl.h                       |   13 
 include/asm-blackfin/flat.h                        |   58 
 include/asm-blackfin/futex.h                       |    6 
 include/asm-blackfin/gpio.h                        |  367 +
 include/asm-blackfin/hardirq.h                     |   41 
 include/asm-blackfin/hw_irq.h                      |    6 
 include/asm-blackfin/ide.h                         |   32 
 include/asm-blackfin/io.h                          |  207 +
 include/asm-blackfin/ioctl.h                       |    1 
 include/asm-blackfin/ioctls.h                      |   82 
 include/asm-blackfin/ipc.h                         |    1 
 include/asm-blackfin/ipcbuf.h                      |   30 
 include/asm-blackfin/irq.h                         |   70 
 include/asm-blackfin/irq_handler.h                 |   22 
 include/asm-blackfin/irq_regs.h                    |    1 
 include/asm-blackfin/kdebug.h                      |    1 
 include/asm-blackfin/kmap_types.h                  |   21 
 include/asm-blackfin/l1layout.h                    |   31 
 include/asm-blackfin/linkage.h                     |    7 
 include/asm-blackfin/local.h                       |    6 
 include/asm-blackfin/mach-bf533/anomaly.h          |  175 
 include/asm-blackfin/mach-bf533/bf533.h            |  306 +
 include/asm-blackfin/mach-bf533/bfin_serial_5xx.h  |  108 
 include/asm-blackfin/mach-bf533/blackfin.h         |   45 
 include/asm-blackfin/mach-bf533/cdefBF532.h        |  706 ++
 include/asm-blackfin/mach-bf533/defBF532.h         | 1175 +++
 include/asm-blackfin/mach-bf533/dma.h              |   54 
 include/asm-blackfin/mach-bf533/irq.h              |  177 
 include/asm-blackfin/mach-bf533/mem_init.h         |  316 +
 include/asm-blackfin/mach-bf533/mem_map.h          |  168 
 include/asm-blackfin/mach-bf537/anomaly.h          |  120 
 include/asm-blackfin/mach-bf537/bf537.h            |  287 +
 include/asm-blackfin/mach-bf537/bfin_serial_5xx.h  |  147 
 include/asm-blackfin/mach-bf537/blackfin.h         |  430 +
 include/asm-blackfin/mach-bf537/cdefBF534.h        | 1823 +++++
 include/asm-blackfin/mach-bf537/cdefBF537.h        |  209 +
 include/asm-blackfin/mach-bf537/defBF534.h         | 2501 ++++++
 include/asm-blackfin/mach-bf537/defBF537.h         |  404 +
 include/asm-blackfin/mach-bf537/dma.h              |   55 
 include/asm-blackfin/mach-bf537/irq.h              |  219 +
 include/asm-blackfin/mach-bf537/mem_init.h         |  330 +
 include/asm-blackfin/mach-bf537/mem_map.h          |  175 
 include/asm-blackfin/mach-bf561/anomaly.h          |  184 
 include/asm-blackfin/mach-bf561/bf561.h            |  408 +
 include/asm-blackfin/mach-bf561/bfin_serial_5xx.h  |  108 
 include/asm-blackfin/mach-bf561/blackfin.h         |   52 
 include/asm-blackfin/mach-bf561/cdefBF561.h        | 1543 ++++
 include/asm-blackfin/mach-bf561/defBF561.h         | 1717 ++++
 include/asm-blackfin/mach-bf561/dma.h              |   35 
 include/asm-blackfin/mach-bf561/irq.h              |  450 +
 include/asm-blackfin/mach-bf561/mem_init.h         |  322 +
 include/asm-blackfin/mach-bf561/mem_map.h          |   75 
 include/asm-blackfin/mach-common/cdef_LPBlackfin.h |  471 +
 include/asm-blackfin/mach-common/context.S         |  350 +
 include/asm-blackfin/mach-common/def_LPBlackfin.h  |  691 ++
 include/asm-blackfin/macros.h                      |   95 
 include/asm-blackfin/mem_map.h                     |   12 
 include/asm-blackfin/mman.h                        |   45 
 include/asm-blackfin/mmu.h                         |   30 
 include/asm-blackfin/mmu_context.h                 |  129 
 include/asm-blackfin/module.h                      |   19 
 include/asm-blackfin/msgbuf.h                      |   31 
 include/asm-blackfin/mutex.h                       |    9 
 include/asm-blackfin/namei.h                       |   19 
 include/asm-blackfin/page.h                        |   89 
 include/asm-blackfin/page_offset.h                 |    6 
 include/asm-blackfin/param.h                       |   22 
 include/asm-blackfin/pci.h                         |  148 
 include/asm-blackfin/percpu.h                      |    6 
 include/asm-blackfin/pgalloc.h                     |    8 
 include/asm-blackfin/pgtable.h                     |   96 
 include/asm-blackfin/poll.h                        |   24 
 include/asm-blackfin/posix_types.h                 |   65 
 include/asm-blackfin/processor.h                   |  130 
 include/asm-blackfin/ptrace.h                      |  166 
 include/asm-blackfin/resource.h                    |    6 
 include/asm-blackfin/scatterlist.h                 |   26 
 include/asm-blackfin/sections.h                    |    7 
 include/asm-blackfin/segment.h                     |    7 
 include/asm-blackfin/semaphore-helper.h            |   82 
 include/asm-blackfin/semaphore.h                   |  106 
 include/asm-blackfin/sembuf.h                      |   25 
 include/asm-blackfin/setup.h                       |   17 
 include/asm-blackfin/shmbuf.h                      |   42 
 include/asm-blackfin/shmparam.h                    |    6 
 include/asm-blackfin/sigcontext.h                  |   55 
 include/asm-blackfin/siginfo.h                     |   35 
 include/asm-blackfin/signal.h                      |  160 
 include/asm-blackfin/socket.h                      |   53 
 include/asm-blackfin/sockios.h                     |   13 
 include/asm-blackfin/spinlock.h                    |    6 
 include/asm-blackfin/stat.h                        |   63 
 include/asm-blackfin/statfs.h                      |    6 
 include/asm-blackfin/string.h                      |  104 
 include/asm-blackfin/system.h                      |  249 +
 include/asm-blackfin/termbits.h                    |  184 
 include/asm-blackfin/termios.h                     |  106 
 include/asm-blackfin/thread_info.h                 |  143 
 include/asm-blackfin/timex.h                       |   18 
 include/asm-blackfin/tlb.h                         |   16 
 include/asm-blackfin/tlbflush.h                    |   62 
 include/asm-blackfin/topology.h                    |    6 
 include/asm-blackfin/traps.h                       |   75 
 include/asm-blackfin/types.h                       |   66 
 include/asm-blackfin/uaccess.h                     |  271 +
 include/asm-blackfin/ucontext.h                    |   17 
 include/asm-blackfin/unaligned.h                   |    6 
 include/asm-blackfin/unistd.h                      |  382 +
 include/asm-blackfin/user.h                        |   89 
 include/asm-cris/kdebug.h                          |    1 
 include/asm-cris/mmu_context.h                     |    2 
 include/asm-cris/socket.h                          |    2 
 include/asm-cris/sockios.h                         |    3 
 include/asm-frv/atomic.h                           |   91 
 include/asm-frv/kdebug.h                           |    1 
 include/asm-frv/mmu_context.h                      |    1 
 include/asm-frv/pgtable.h                          |    4 
 include/asm-frv/scatterlist.h                      |    2 
 include/asm-frv/semaphore.h                        |   14 
 include/asm-frv/socket.h                           |    2 
 include/asm-frv/sockios.h                          |    3 
 include/asm-frv/system.h                           |   70 
 include/asm-generic/atomic.h                       |  140 
 include/asm-generic/div64.h                        |    7 
 include/asm-generic/kdebug.h                       |    8 
 include/asm-generic/local.h                        |   33 
 include/asm-generic/mm_hooks.h                     |   18 
 include/asm-generic/percpu.h                       |    1 
 include/asm-generic/pgtable.h                      |   11 
 include/asm-generic/vmlinux.lds.h                  |    2 
 include/asm-h8300/irq.h                            |    1 
 include/asm-h8300/irq_regs.h                       |    1 
 include/asm-h8300/kdebug.h                         |    1 
 include/asm-h8300/mmu_context.h                    |    1 
 include/asm-h8300/pgtable.h                        |    5 
 include/asm-h8300/scatterlist.h                    |    2 
 include/asm-h8300/socket.h                         |    2 
 include/asm-h8300/sockios.h                        |    3 
 include/asm-h8300/system.h                         |    1 
 include/asm-i386/Kbuild                            |    2 
 include/asm-i386/agp.h                             |    6 
 include/asm-i386/alternative.h                     |   34 
 include/asm-i386/apic.h                            |    9 
 include/asm-i386/atomic.h                          |   45 
 include/asm-i386/bugs.h                            |  194 
 include/asm-i386/cmpxchg.h                         |  293 +
 include/asm-i386/cpufeature.h                      |   13 
 include/asm-i386/current.h                         |    5 
 include/asm-i386/desc.h                            |   95 
 include/asm-i386/div64.h                           |    4 
 include/asm-i386/e820.h                            |    1 
 include/asm-i386/elf.h                             |   30 
 include/asm-i386/fixmap.h                          |   11 
 include/asm-i386/genapic.h                         |    6 
 include/asm-i386/highmem.h                         |    6 
 include/asm-i386/hpet.h                            |    2 
 include/asm-i386/i387.h                            |   17 
 include/asm-i386/io.h                              |   15 
 include/asm-i386/ioctls.h                          |    4 
 include/asm-i386/irq.h                             |    2 
 include/asm-i386/irq_regs.h                        |   12 
 include/asm-i386/irqflags.h                        |   64 
 include/asm-i386/kdebug.h                          |   25 
 include/asm-i386/kexec.h                           |    8 
 include/asm-i386/local.h                           |  205 -
 include/asm-i386/mach-bigsmp/mach_apic.h           |    2 
 include/asm-i386/mach-default/mach_apic.h          |    2 
 include/asm-i386/mach-es7000/mach_apic.h           |    9 
 include/asm-i386/mach-es7000/mach_mpparse.h        |   32 
 include/asm-i386/mach-generic/mach_apic.h          |    2 
 include/asm-i386/mach-numaq/mach_apic.h            |    2 
 include/asm-i386/mach-summit/mach_apic.h           |    2 
 include/asm-i386/mach-summit/mach_mpparse.h        |    4 
 include/asm-i386/mach-visws/mach_apic.h            |    2 
 include/asm-i386/mmu_context.h                     |   17 
 include/asm-i386/module.h                          |    2 
 include/asm-i386/msr-index.h                       |  278 +
 include/asm-i386/msr.h                             |  412 -
 include/asm-i386/mtrr.h                            |    4 
 include/asm-i386/nmi.h                             |    8 
 include/asm-i386/page.h                            |   81 
 include/asm-i386/paravirt.h                        |  957 ++
 include/asm-i386/pda.h                             |  100 
 include/asm-i386/percpu.h                          |  136 
 include/asm-i386/pgalloc.h                         |    1 
 include/asm-i386/pgtable-2level-defs.h             |    2 
 include/asm-i386/pgtable-2level.h                  |   37 
 include/asm-i386/pgtable-3level-defs.h             |    6 
 include/asm-i386/pgtable-3level.h                  |   69 
 include/asm-i386/pgtable.h                         |   99 
 include/asm-i386/processor-flags.h                 |   91 
 include/asm-i386/processor.h                       |  187 
 include/asm-i386/reboot.h                          |   20 
 include/asm-i386/reboot_fixups.h                   |    6 
 include/asm-i386/required-features.h               |   34 
 include/asm-i386/scatterlist.h                     |    2 
 include/asm-i386/segment.h                         |   10 
 include/asm-i386/serial.h                          |   16 
 include/asm-i386/smp.h                             |   64 
 include/asm-i386/socket.h                          |    2 
 include/asm-i386/sockios.h                         |    3 
 include/asm-i386/system.h                          |  347 -
 include/asm-i386/termbits.h                        |   14 
 include/asm-i386/termios.h                         |    6 
 include/asm-i386/thread_info.h                     |    8 
 include/asm-i386/timer.h                           |    2 
 include/asm-i386/tlbflush.h                        |   19 
 include/asm-i386/tsc.h                             |   15 
 include/asm-i386/uaccess.h                         |   14 
 include/asm-i386/unistd.h                          |    3 
 include/asm-i386/vmi_time.h                        |   18 
 include/asm-i386/voyager.h                         |    6 
 include/asm-ia64/asmmacro.h                        |   10 
 include/asm-ia64/atomic.h                          |   53 
 include/asm-ia64/io.h                              |    6 
 include/asm-ia64/kdebug.h                          |   27 
 include/asm-ia64/kexec.h                           |    2 
 include/asm-ia64/kregs.h                           |    3 
 include/asm-ia64/local.h                           |   51 
 include/asm-ia64/mmu_context.h                     |    1 
 include/asm-ia64/pal.h                             |   33 
 include/asm-ia64/patch.h                           |    1 
 include/asm-ia64/pgtable.h                         |    4 
 include/asm-ia64/processor.h                       |    1 
 include/asm-ia64/scatterlist.h                     |    2 
 include/asm-ia64/sections.h                        |    1 
 include/asm-ia64/socket.h                          |    2 
 include/asm-ia64/sockios.h                         |    3 
 include/asm-m32r/atomic.h                          |   23 
 include/asm-m32r/kdebug.h                          |    1 
 include/asm-m32r/mmu_context.h                     |    1 
 include/asm-m32r/pgtable.h                         |    4 
 include/asm-m32r/scatterlist.h                     |    2 
 include/asm-m32r/socket.h                          |    2 
 include/asm-m32r/sockios.h                         |    3 
 include/asm-m32r/system.h                          |    2 
 include/asm-m68k/adb.h                             |   75 
 include/asm-m68k/atarikb.h                         |    6 
 include/asm-m68k/atomic.h                          |   31 
 include/asm-m68k/div64.h                           |    3 
 include/asm-m68k/kdebug.h                          |    1 
 include/asm-m68k/mmu_context.h                     |    1 
 include/asm-m68k/pgtable.h                         |    4 
 include/asm-m68k/socket.h                          |    2 
 include/asm-m68k/sockios.h                         |    3 
 include/asm-m68k/system.h                          |    1 
 include/asm-m68knommu/atomic.h                     |   25 
 include/asm-m68knommu/kdebug.h                     |    1 
 include/asm-m68knommu/mmu_context.h                |    1 
 include/asm-m68knommu/pgtable.h                    |    4 
 include/asm-m68knommu/scatterlist.h                |    1 
 include/asm-m68knommu/system.h                     |    1 
 include/asm-mips/atomic.h                          |   57 
 include/asm-mips/cacheflush.h                      |    2 
 include/asm-mips/div64.h                           |   11 
 include/asm-mips/jmr3927/irq.h                     |   57 
 include/asm-mips/jmr3927/jmr3927.h                 |  130 
 include/asm-mips/jmr3927/tx3927.h                  |    8 
 include/asm-mips/jmr3927/txx927.h                  |    5 
 include/asm-mips/kdebug.h                          |    1 
 include/asm-mips/kexec.h                           |    2 
 include/asm-mips/local.h                           |  304 +
 include/asm-mips/mach-au1x00/au1550_spi.h          |   16 
 include/asm-mips/mmu_context.h                     |    1 
 include/asm-mips/paccess.h                         |    2 
 include/asm-mips/pgtable.h                         |    4 
 include/asm-mips/scatterlist.h                     |    2 
 include/asm-mips/sgi/hpc3.h                        |    2 
 include/asm-mips/sgi/ip22.h                        |    2 
 include/asm-mips/sgi/mc.h                          |    2 
 include/asm-mips/sibyte/bcm1480_int.h              |    2 
 include/asm-mips/sibyte/bcm1480_mc.h               |   32 
 include/asm-mips/sibyte/bcm1480_regs.h             |   20 
 include/asm-mips/sibyte/bcm1480_scd.h              |   94 
 include/asm-mips/sibyte/board.h                    |   14 
 include/asm-mips/sibyte/carmel.h                   |    1 
 include/asm-mips/sibyte/sb1250_int.h               |    5 
 include/asm-mips/sibyte/sb1250_mac.h               |   24 
 include/asm-mips/sibyte/sb1250_mc.h                |    2 
 include/asm-mips/sibyte/sb1250_regs.h              |   46 
 include/asm-mips/sibyte/sb1250_scd.h               |   30 
 include/asm-mips/sibyte/swarm.h                    |   12 
 include/asm-mips/socket.h                          |    2 
 include/asm-mips/sockios.h                         |    3 
 include/asm-mips/system.h                          |  126 
 include/asm-parisc/atomic.h                        |   56 
 include/asm-parisc/kdebug.h                        |    1 
 include/asm-parisc/local.h                         |   41 
 include/asm-parisc/mmu_context.h                   |    1 
 include/asm-parisc/pgtable.h                       |    4 
 include/asm-parisc/scatterlist.h                   |    1 
 include/asm-parisc/socket.h                        |    2 
 include/asm-parisc/sockios.h                       |    3 
 include/asm-powerpc/asm-compat.h                   |   10 
 include/asm-powerpc/atomic.h                       |    7 
 include/asm-powerpc/bitops.h                       |    1 
 include/asm-powerpc/cacheflush.h                   |    6 
 include/asm-powerpc/cell-pmu.h                     |    5 
 include/asm-powerpc/cputable.h                     |   11 
 include/asm-powerpc/current.h                      |    1 
 include/asm-powerpc/edac.h                         |   40 
 include/asm-powerpc/eeh_event.h                    |    6 
 include/asm-powerpc/ibmebus.h                      |   44 
 include/asm-powerpc/immap_86xx.h                   |   75 
 include/asm-powerpc/io.h                           |    7 
 include/asm-powerpc/iommu.h                        |   14 
 include/asm-powerpc/kdebug.h                       |   34 
 include/asm-powerpc/kexec.h                        |    2 
 include/asm-powerpc/kprobes.h                      |   12 
 include/asm-powerpc/local.h                        |  201 +
 include/asm-powerpc/machdep.h                      |   22 
 include/asm-powerpc/mmu-44x.h                      |   78 
 include/asm-powerpc/mmu-hash64.h                   |  400 +
 include/asm-powerpc/mmu.h                          |  408 -
 include/asm-powerpc/mmu_context.h                  |    1 
 include/asm-powerpc/mpc52xx.h                      |   11 
 include/asm-powerpc/mpic.h                         |   32 
 include/asm-powerpc/of_device.h                    |    5 
 include/asm-powerpc/oprofile_impl.h                |    2 
 include/asm-powerpc/paca.h                         |    4 
 include/asm-powerpc/page.h                         |   10 
 include/asm-powerpc/page_32.h                      |    2 
 include/asm-powerpc/parport.h                      |   11 
 include/asm-powerpc/pci.h                          |   14 
 include/asm-powerpc/pgalloc-32.h                   |   41 
 include/asm-powerpc/pgalloc-64.h                   |  152 
 include/asm-powerpc/pgalloc.h                      |  154 
 include/asm-powerpc/pgtable-4k.h                   |    6 
 include/asm-powerpc/pgtable-64k.h                  |   10 
 include/asm-powerpc/pgtable-ppc32.h                |  813 ++
 include/asm-powerpc/pgtable-ppc64.h                |  492 +
 include/asm-powerpc/pgtable.h                      |  521 -
 include/asm-powerpc/pmac_feature.h                 |    2 
 include/asm-powerpc/pmc.h                          |    1 
 include/asm-powerpc/ppc-pci.h                      |   12 
 include/asm-powerpc/processor.h                    |    1 
 include/asm-powerpc/prom.h                         |   46 
 include/asm-powerpc/ps3.h                          |   33 
 include/asm-powerpc/ps3av.h                        |   22 
 include/asm-powerpc/reg.h                          |   68 
 include/asm-powerpc/socket.h                       |    2 
 include/asm-powerpc/sockios.h                      |    3 
 include/asm-powerpc/spu_csa.h                      |    1 
 include/asm-powerpc/string.h                       |    2 
 include/asm-powerpc/suspend.h                      |    9 
 include/asm-powerpc/system.h                       |  131 
 include/asm-powerpc/tlb.h                          |    1 
 include/asm-powerpc/tlbflush.h                     |  172 
 include/asm-powerpc/tsi108.h                       |   12 
 include/asm-powerpc/tsi108_pci.h                   |   45 
 include/asm-powerpc/uaccess.h                      |   28 
 include/asm-powerpc/ucc_fast.h                     |    3 
 include/asm-powerpc/udbg.h                         |    1 
 include/asm-powerpc/uic.h                          |   23 
 include/asm-ppc/ibm4xx.h                           |    8 
 include/asm-ppc/kdebug.h                           |    1 
 include/asm-ppc/mmu_context.h                      |    1 
 include/asm-ppc/pgtable.h                          |    4 
 include/asm-ppc/ppc_sys.h                          |    2 
 include/asm-ppc/prom.h                             |    3 
 include/asm-ppc/system.h                           |    2 
 include/asm-s390/bug.h                             |   69 
 include/asm-s390/ccwdev.h                          |    6 
 include/asm-s390/ccwgroup.h                        |    1 
 include/asm-s390/chpid.h                           |   53 
 include/asm-s390/cio.h                             |    8 
 include/asm-s390/dma-mapping.h                     |    2 
 include/asm-s390/elf.h                             |    7 
 include/asm-s390/ipl.h                             |   35 
 include/asm-s390/kdebug.h                          |   42 
 include/asm-s390/kexec.h                           |    2 
 include/asm-s390/kprobes.h                         |   16 
 include/asm-s390/lowcore.h                         |   56 
 include/asm-s390/mmu_context.h                     |    2 
 include/asm-s390/pgtable.h                         |   15 
 include/asm-s390/processor.h                       |    2 
 include/asm-s390/qdio.h                            |    1 
 include/asm-s390/sclp.h                            |   14 
 include/asm-s390/setup.h                           |    2 
 include/asm-s390/smp.h                             |    6 
 include/asm-s390/socket.h                          |    2 
 include/asm-s390/sockios.h                         |    3 
 include/asm-sh/bug.h                               |   92 
 include/asm-sh/clock.h                             |   32 
 include/asm-sh/cpu-sh3/mmu_context.h               |    1 
 include/asm-sh/cpu-sh4/freq.h                      |    8 
 include/asm-sh/irq.h                               |   91 
 include/asm-sh/kdebug.h                            |   36 
 include/asm-sh/kexec.h                             |   44 
 include/asm-sh/kgdb.h                              |   51 
 include/asm-sh/lboxre2.h                           |   27 
 include/asm-sh/mmu_context.h                       |    7 
 include/asm-sh/page.h                              |   10 
 include/asm-sh/param.h                             |    2 
 include/asm-sh/pci.h                               |    2 
 include/asm-sh/pgtable.h                           |    4 
 include/asm-sh/processor.h                         |    2 
 include/asm-sh/r7780rp.h                           |   76 
 include/asm-sh/scatterlist.h                       |    2 
 include/asm-sh/se.h                                |    4 
 include/asm-sh/se7722.h                            |  118 
 include/asm-sh/se7751.h                            |    2 
 include/asm-sh/se7780.h                            |  108 
 include/asm-sh/socket.h                            |    2 
 include/asm-sh/sockios.h                           |    3 
 include/asm-sh/stat.h                              |   19 
 include/asm-sh/string.h                            |    3 
 include/asm-sh/system.h                            |   13 
 include/asm-sh64/kdebug.h                          |    1 
 include/asm-sh64/mmu_context.h                     |    2 
 include/asm-sh64/pgtable.h                         |    4 
 include/asm-sh64/scatterlist.h                     |    2 
 include/asm-sh64/sockios.h                         |    3 
 include/asm-sh64/system.h                          |    2 
 include/asm-sparc/kdebug.h                         |    4 
 include/asm-sparc/mmu_context.h                    |    2 
 include/asm-sparc/prom.h                           |   14 
 include/asm-sparc/socket.h                         |    2 
 include/asm-sparc/sockios.h                        |    3 
 include/asm-sparc/system.h                         |    1 
 include/asm-sparc64/Kbuild                         |    1 
 include/asm-sparc64/atomic.h                       |   53 
 include/asm-sparc64/const.h                        |   19 
 include/asm-sparc64/cpudata.h                      |    4 
 include/asm-sparc64/device.h                       |   18 
 include/asm-sparc64/ebus.h                         |    2 
 include/asm-sparc64/floppy.h                       |    4 
 include/asm-sparc64/io.h                           |    8 
 include/asm-sparc64/iommu.h                        |   52 
 include/asm-sparc64/isa.h                          |    2 
 include/asm-sparc64/kdebug.h                       |   23 
 include/asm-sparc64/local.h                        |   41 
 include/asm-sparc64/lsu.h                          |    2 
 include/asm-sparc64/mmu.h                          |    2 
 include/asm-sparc64/mmu_context.h                  |    1 
 include/asm-sparc64/page.h                         |    2 
 include/asm-sparc64/parport.h                      |    2 
 include/asm-sparc64/pbm.h                          |  132 
 include/asm-sparc64/pci.h                          |    2 
 include/asm-sparc64/percpu.h                       |   10 
 include/asm-sparc64/pgalloc.h                      |   26 
 include/asm-sparc64/pgtable.h                      |   18 
 include/asm-sparc64/prom.h                         |   12 
 include/asm-sparc64/pstate.h                       |    2 
 include/asm-sparc64/scatterlist.h                  |    1 
 include/asm-sparc64/sfafsr.h                       |    2 
 include/asm-sparc64/smp.h                          |    4 
 include/asm-sparc64/socket.h                       |    2 
 include/asm-sparc64/sockios.h                      |    3 
 include/asm-sparc64/sparsemem.h                    |    2 
 include/asm-sparc64/system.h                       |    1 
 include/asm-sparc64/timer.h                        |   17 
 include/asm-sparc64/ttable.h                       |   27 
 include/asm-um/cmpxchg.h                           |    6 
 include/asm-um/div64.h                             |    1 
 include/asm-um/kdebug.h                            |    1 
 include/asm-um/mmu_context.h                       |    2 
 include/asm-um/page.h                              |    3 
 include/asm-um/tlbflush.h                          |   24 
 include/asm-v850/kdebug.h                          |    1 
 include/asm-v850/mmu_context.h                     |    2 
 include/asm-v850/scatterlist.h                     |    2 
 include/asm-v850/socket.h                          |    2 
 include/asm-v850/sockios.h                         |    3 
 include/asm-v850/system.h                          |    1 
 include/asm-x86_64/Kbuild                          |    3 
 include/asm-x86_64/agp.h                           |    6 
 include/asm-x86_64/alternative.h                   |    5 
 include/asm-x86_64/apic.h                          |   10 
 include/asm-x86_64/atomic.h                        |   65 
 include/asm-x86_64/bugs.h                          |   30 
 include/asm-x86_64/cmpxchg.h                       |  134 
 include/asm-x86_64/desc.h                          |   21 
 include/asm-x86_64/dma-mapping.h                   |    2 
 include/asm-x86_64/fixmap.h                        |    1 
 include/asm-x86_64/genapic.h                       |    4 
 include/asm-x86_64/ipi.h                           |   61 
 include/asm-x86_64/irqflags.h                      |    9 
 include/asm-x86_64/kdebug.h                        |   25 
 include/asm-x86_64/kexec.h                         |    2 
 include/asm-x86_64/local.h                         |  196 
 include/asm-x86_64/mmu_context.h                   |    1 
 include/asm-x86_64/mmzone.h                        |    2 
 include/asm-x86_64/msr-index.h                     |    1 
 include/asm-x86_64/msr.h                           |  285 -
 include/asm-x86_64/mtrr.h                          |   12 
 include/asm-x86_64/nmi.h                           |    9 
 include/asm-x86_64/page.h                          |   50 
 include/asm-x86_64/percpu.h                        |   10 
 include/asm-x86_64/pgalloc.h                       |   15 
 include/asm-x86_64/pgtable.h                       |   43 
 include/asm-x86_64/processor-flags.h               |    1 
 include/asm-x86_64/processor.h                     |   55 
 include/asm-x86_64/proto.h                         |   15 
 include/asm-x86_64/scatterlist.h                   |    2 
 include/asm-x86_64/segment.h                       |    2 
 include/asm-x86_64/serial.h                        |   16 
 include/asm-x86_64/smp.h                           |    4 
 include/asm-x86_64/socket.h                        |    2 
 include/asm-x86_64/sockios.h                       |    3 
 include/asm-x86_64/suspend.h                       |   13 
 include/asm-x86_64/system.h                        |  103 
 include/asm-x86_64/termbits.h                      |    2 
 include/asm-x86_64/timex.h                         |    2 
 include/asm-x86_64/tlbflush.h                      |   33 
 include/asm-x86_64/unistd.h                        |    5 
 include/asm-xtensa/atomic.h                        |   23 
 include/asm-xtensa/div64.h                         |    6 
 include/asm-xtensa/kdebug.h                        |    1 
 include/asm-xtensa/mmu_context.h                   |    1 
 include/asm-xtensa/scatterlist.h                   |    2 
 include/asm-xtensa/socket.h                        |    2 
 include/asm-xtensa/sockios.h                       |    3 
 include/asm-xtensa/system.h                        |    2 
 include/crypto/algapi.h                            |   84 
 include/keys/rxrpc-type.h                          |   22 
 include/linux/Kbuild                               |   15 
 include/linux/ata.h                                |   10 
 include/linux/atalk.h                              |    4 
 include/linux/awe_voice.h                          |  525 -
 include/linux/bio.h                                |    2 
 include/linux/blkdev.h                             |    1 
 include/linux/bootmem.h                            |    4 
 include/linux/buffer_head.h                        |    5 
 include/linux/byteorder/generic.h                  |   25 
 include/linux/byteorder/swab.h                     |  108 
 include/linux/clockchips.h                         |   10 
 include/linux/clocksource.h                        |   15 
 include/linux/compat_ioctl.h                       |  830 --
 include/linux/compiler-gcc.h                       |    3 
 include/linux/compiler-gcc3.h                      |    6 
 include/linux/compiler-gcc4.h                      |    6 
 include/linux/compiler-intel.h                     |    5 
 include/linux/console.h                            |    7 
 include/linux/console_struct.h                     |    3 
 include/linux/const.h                              |   19 
 include/linux/cpu.h                                |    3 
 include/linux/cpufreq.h                            |   20 
 include/linux/crash_dump.h                         |    8 
 include/linux/crypto.h                             |  236 +
 include/linux/cyclades.h                           |  229 -
 include/linux/dcache.h                             |    6 
 include/linux/dccp.h                               |   46 
 include/linux/debugfs.h                            |    9 
 include/linux/device.h                             |   80 
 include/linux/display.h                            |   61 
 include/linux/dlm_device.h                         |    9 
 include/linux/ds1wm.h                              |   11 
 include/linux/dvb/audio.h                          |    5 
 include/linux/dvb/version.h                        |    2 
 include/linux/dvb/video.h                          |   62 
 include/linux/efi.h                                |    1 
 include/linux/elf-em.h                             |    1 
 include/linux/elf.h                                |   17 
 include/linux/elfnote.h                            |    4 
 include/linux/etherdevice.h                        |   12 
 include/linux/ethtool.h                            |    2 
 include/linux/ext3_fs.h                            |    1 
 include/linux/fb.h                                 |   57 
 include/linux/fcntl.h                              |    4 
 include/linux/fib_rules.h                          |   15 
 include/linux/font.h                               |    3 
 include/linux/fs.h                                 |   28 
 include/linux/fsl_devices.h                        |   39 
 include/linux/futex.h                              |   29 
 include/linux/gfp.h                                |    3 
 include/linux/gpio_keys.h                          |    3 
 include/linux/hdlc.h                               |    7 
 include/linux/hid.h                                |   14 
 include/linux/highmem.h                            |   15 
 include/linux/hp_sdc.h                             |    1 
 include/linux/hugetlb.h                            |    6 
 include/linux/i2c-algo-bit.h                       |    7 
 include/linux/i2c-gpio.h                           |   38 
 include/linux/i2c-id.h                             |    3 
 include/linux/i2c.h                                |  123 
 include/linux/icmp.h                               |    9 
 include/linux/icmpv6.h                             |    9 
 include/linux/ide.h                                |    1 
 include/linux/ieee80211.h                          |  342 +
 include/linux/if_addr.h                            |    1 
 include/linux/if_arp.h                             |    9 
 include/linux/if_bridge.h                          |    3 
 include/linux/if_ether.h                           |    3 
 include/linux/if_link.h                            |    1 
 include/linux/if_packet.h                          |    1 
 include/linux/if_pppox.h                           |   10 
 include/linux/if_tr.h                              |    2 
 include/linux/if_vlan.h                            |    6 
 include/linux/if_wanpipe_common.h                  |   58 
 include/linux/igmp.h                               |   21 
 include/linux/in.h                                 |    1 
 include/linux/in6.h                                |    3 
 include/linux/init.h                               |   12 
 include/linux/init_task.h                          |    2 
 include/linux/input-polldev.h                      |   46 
 include/linux/input.h                              |   57 
 include/linux/interrupt.h                          |   44 
 include/linux/ioctl32.h                            |   17 
 include/linux/ioport.h                             |    1 
 include/linux/ip.h                                 |   14 
 include/linux/ipc.h                                |   11 
 include/linux/ipv6.h                               |   14 
 include/linux/irq.h                                |    4 
 include/linux/isdn/capiutil.h                      |    1 
 include/linux/isdn_divertif.h                      |    5 
 include/linux/jhash.h                              |    2 
 include/linux/kallsyms.h                           |   26 
 include/linux/kdebug.h                             |   20 
 include/linux/kernel.h                             |    4 
 include/linux/kexec.h                              |   17 
 include/linux/key.h                                |    2 
 include/linux/kobject.h                            |   70 
 include/linux/kprobes.h                            |   22 
 include/linux/ktime.h                              |    6 
 include/linux/kvm.h                                |  133 
 include/linux/libata.h                             |  118 
 include/linux/list.h                               |   11 
 include/linux/lockd/lockd.h                        |   16 
 include/linux/loop.h                               |    2 
 include/linux/mc146818rtc.h                        |    7 
 include/linux/migrate.h                            |   15 
 include/linux/miscdevice.h                         |    1 
 include/linux/mm.h                                 |   55 
 include/linux/mm_types.h                           |   17 
 include/linux/mmc/card.h                           |   32 
 include/linux/mmc/core.h                           |  112 
 include/linux/mmc/host.h                           |   59 
 include/linux/mmc/mmc.h                            |  322 +
 include/linux/mmc/protocol.h                       |  327 -
 include/linux/mmc/sd.h                             |   83 
 include/linux/mmzone.h                             |   12 
 include/linux/mnt_namespace.h                      |    5 
 include/linux/mod_devicetable.h                    |    1 
 include/linux/module.h                             |   32 
 include/linux/msdos_fs.h                           |    3 
 include/linux/msi.h                                |   11 
 include/linux/mtd/iflash.h                         |   98 
 include/linux/mtd/mtd.h                            |    1 
 include/linux/mtd/nand.h                           |    1 
 include/linux/mtd/ubi.h                            |  202 +
 include/linux/namei.h                              |    1 
 include/linux/net.h                                |    2 
 include/linux/netdevice.h                          |   43 
 include/linux/netfilter.h                          |   12 
 include/linux/netfilter/nf_conntrack_proto_gre.h   |   18 
 include/linux/netfilter/nf_conntrack_tcp.h         |    5 
 include/linux/netfilter/nfnetlink.h                |   19 
 include/linux/netfilter/nfnetlink_conntrack.h      |    4 
 include/linux/netfilter_bridge.h                   |   20 
 include/linux/netfilter_bridge/ebt_802_3.h         |    2 
 include/linux/netfilter_bridge/ebt_arp.h           |    4 
 include/linux/netfilter_ipv4/Kbuild                |   14 
 include/linux/netfilter_ipv4/ip_conntrack.h        |  402 -
 include/linux/netfilter_ipv4/ip_conntrack_amanda.h |   11 
 include/linux/netfilter_ipv4/ip_conntrack_core.h   |   61 
 include/linux/netfilter_ipv4/ip_conntrack_ftp.h    |   44 
 include/linux/netfilter_ipv4/ip_conntrack_h323.h   |   89 
 include/linux/netfilter_ipv4/ip_conntrack_helper.h |   46 
 include/linux/netfilter_ipv4/ip_conntrack_icmp.h   |    6 
 include/linux/netfilter_ipv4/ip_conntrack_irc.h    |   32 
 include/linux/netfilter_ipv4/ip_conntrack_pptp.h   |  326 -
 .../linux/netfilter_ipv4/ip_conntrack_proto_gre.h  |  114 
 .../linux/netfilter_ipv4/ip_conntrack_protocol.h   |   98 
 include/linux/netfilter_ipv4/ip_conntrack_sctp.h   |    6 
 include/linux/netfilter_ipv4/ip_conntrack_sip.h    |   40 
 include/linux/netfilter_ipv4/ip_conntrack_tcp.h    |    6 
 include/linux/netfilter_ipv4/ip_conntrack_tftp.h   |   20 
 include/linux/netfilter_ipv4/ip_conntrack_tuple.h  |  146 
 include/linux/netfilter_ipv4/ip_nat.h              |   79 
 include/linux/netfilter_ipv4/ip_nat_core.h         |   18 
 include/linux/netfilter_ipv4/ip_nat_helper.h       |   33 
 include/linux/netfilter_ipv4/ip_nat_pptp.h         |   11 
 include/linux/netfilter_ipv4/ip_nat_protocol.h     |   74 
 include/linux/netfilter_ipv4/ip_nat_rule.h         |   28 
 include/linux/netfilter_ipv4/ipt_SAME.h            |    2 
 include/linux/netlink.h                            |   37 
 include/linux/nfs_fs.h                             |    4 
 include/linux/nfs_fs_sb.h                          |    2 
 include/linux/nfs_mount.h                          |    1 
 include/linux/nfs_page.h                           |   33 
 include/linux/nl80211.h                            |   38 
 include/linux/nsproxy.h                            |    3 
 include/linux/nubus.h                              |  126 
 include/linux/page-flags.h                         |   43 
 include/linux/pagemap.h                            |   22 
 include/linux/parport.h                            |    8 
 include/linux/parport_pc.h                         |    3 
 include/linux/parser.h                             |    6 
 include/linux/pci.h                                |   30 
 include/linux/pci_hotplug.h                        |    2 
 include/linux/pci_ids.h                            |    6 
 include/linux/percpu.h                             |    9 
 include/linux/phantom.h                            |   42 
 include/linux/phy.h                                |    1 
 include/linux/pid_namespace.h                      |    2 
 include/linux/pm.h                                 |   83 
 include/linux/pmu.h                                |   20 
 include/linux/pnp.h                                |    3 
 include/linux/poison.h                             |   10 
 include/linux/proc_fs.h                            |    4 
 include/linux/quicklist.h                          |   94 
 include/linux/quota.h                              |    4 
 include/linux/quotaops.h                           |    3 
 include/linux/reboot_fixups.h                      |   10 
 include/linux/reiserfs_fs_sb.h                     |    3 
 include/linux/rfkill.h                             |   89 
 include/linux/rtc.h                                |   39 
 include/linux/rtnetlink.h                          |   13 
 include/linux/rxrpc.h                              |   62 
 include/linux/sched.h                              |   39 
 include/linux/sctp.h                               |    9 
 include/linux/sdla_fr.h                            |  638 --
 include/linux/seqlock.h                            |    8 
 include/linux/serial_core.h                        |   10 
 include/linux/serial_reg.h                         |    2 
 include/linux/skbuff.h                             |  399 +
 include/linux/slab.h                               |   36 
 include/linux/slub_def.h                           |  206 +
 include/linux/snmp.h                               |    2 
 include/linux/socket.h                             |    5 
 include/linux/sony-laptop.h                        |   34 
 include/linux/spi/Kbuild                           |    1 
 include/linux/spi/ad7877.h                         |   24 
 include/linux/spi/spi.h                            |   82 
 include/linux/spi/spidev.h                         |  124 
 include/linux/spinlock_types.h                     |    6 
 include/linux/stacktrace.h                         |    6 
 include/linux/stat.h                               |    3 
 include/linux/string.h                             |    6 
 include/linux/sunrpc/clnt.h                        |    9 
 include/linux/sunrpc/debug.h                       |    2 
 include/linux/sunrpc/msg_prot.h                    |    4 
 include/linux/sunrpc/sched.h                       |    2 
 include/linux/sunrpc/xprt.h                        |    7 
 include/linux/suspend.h                            |   37 
 include/linux/svga.h                               |    1 
 include/linux/sysctl.h                             |    4 
 include/linux/sysdev.h                             |    1 
 include/linux/sysfs.h                              |    4 
 include/linux/tcp.h                                |   21 
 include/linux/tifm.h                               |  117 
 include/linux/time.h                               |    3 
 include/linux/timer.h                              |    1 
 include/linux/tty.h                                |    2 
 include/linux/udp.h                                |    9 
 include/linux/uinput.h                             |    2 
 include/linux/usb.h                                |   22 
 include/linux/usb/cdc.h                            |   11 
 include/linux/usb/ch9.h                            |   15 
 include/linux/usb_sl811.h                          |   26 
 include/linux/utsname.h                            |   19 
 include/linux/videodev2.h                          |   83 
 include/linux/vmalloc.h                            |    1 
 include/linux/vt_kern.h                            |    3 
 include/linux/wireless.h                           |    2 
 include/linux/workqueue.h                          |   13 
 include/linux/writeback.h                          |    2 
 include/linux/xfrm.h                               |   46 
 include/math-emu/extended.h                        |  396 -
 include/media/cx2341x.h                            |    6 
 include/media/ivtv.h                               |   65 
 include/media/ovcamchip.h                          |    1 
 include/media/tuner.h                              |    6 
 include/media/v4l2-chip-ident.h                    |  149 
 include/media/v4l2-common.h                        |   47 
 include/media/v4l2-dev.h                           |   10 
 include/mtd/Kbuild                                 |    2 
 include/mtd/mtd-abi.h                              |    1 
 include/mtd/ubi-header.h                           |  360 +
 include/mtd/ubi-user.h                             |  161 
 include/net/addrconf.h                             |    4 
 include/net/af_rxrpc.h                             |   57 
 include/net/ax25.h                                 |    2 
 include/net/bluetooth/hci.h                        |   18 
 include/net/cfg80211.h                             |   40 
 include/net/cipso_ipv4.h                           |    2 
 include/net/compat.h                               |    1 
 include/net/dn_fib.h                               |    9 
 include/net/dn_route.h                             |    1 
 include/net/esp.h                                  |    2 
 include/net/fib_rules.h                            |   20 
 include/net/flow.h                                 |    6 
 include/net/ieee80211.h                            |    4 
 include/net/ieee80211_crypt.h                      |    4 
 include/net/ieee80211_radiotap.h                   |   77 
 include/net/inet6_hashtables.h                     |   12 
 include/net/inet_ecn.h                             |    8 
 include/net/inet_sock.h                            |   11 
 include/net/ip.h                                   |   11 
 include/net/ip6_fib.h                              |    2 
 include/net/ip6_route.h                            |    5 
 include/net/ip_fib.h                               |    6 
 include/net/ipv6.h                                 |   34 
 include/net/ipx.h                                  |    2 
 include/net/iucv/af_iucv.h                         |    2 
 include/net/iucv/iucv.h                            |    2 
 include/net/iw_handler.h                           |   21 
 include/net/llc_pdu.h                              |   15 
 include/net/mac80211.h                             | 1045 +++
 include/net/neighbour.h                            |   10 
 include/net/netfilter/nf_conntrack.h               |    5 
 include/net/netfilter/nf_conntrack_compat.h        |  145 
 include/net/netfilter/nf_conntrack_core.h          |    3 
 include/net/netfilter/nf_conntrack_ecache.h        |   30 
 include/net/netfilter/nf_conntrack_l3proto.h       |    5 
 include/net/netfilter/nf_conntrack_l4proto.h       |    1 
 include/net/netfilter/nf_nat_rule.h                |   10 
 include/net/netlink.h                              |   18 
 include/net/pkt_cls.h                              |   10 
 include/net/pkt_sched.h                            |  182 
 include/net/red.h                                  |   10 
 include/net/rtnetlink.h                            |   25 
 include/net/sch_generic.h                          |   12 
 include/net/sctp/command.h                         |    2 
 include/net/sctp/constants.h                       |    2 
 include/net/sctp/sctp.h                            |    4 
 include/net/sctp/structs.h                         |    6 
 include/net/sctp/ulpevent.h                        |    1 
 include/net/sctp/ulpqueue.h                        |    2 
 include/net/sctp/user.h                            |   25 
 include/net/sock.h                                 |   98 
 include/net/tcp.h                                  |  200 -
 include/net/tcp_ecn.h                              |   17 
 include/net/udp.h                                  |   11 
 include/net/udplite.h                              |   45 
 include/net/wext.h                                 |   24 
 include/net/wireless.h                             |  139 
 include/net/x25device.h                            |    2 
 include/net/xfrm.h                                 |   32 
 include/pcmcia/ds.h                                |    6 
 include/rdma/ib_mad.h                              |    2 
 include/rdma/ib_verbs.h                            |   47 
 include/rxrpc/call.h                               |  212 -
 include/rxrpc/connection.h                         |   83 
 include/rxrpc/krxiod.h                             |   27 
 include/rxrpc/krxsecd.h                            |   22 
 include/rxrpc/krxtimod.h                           |   45 
 include/rxrpc/message.h                            |   71 
 include/rxrpc/packet.h                             |  119 
 include/rxrpc/peer.h                               |   82 
 include/rxrpc/rxrpc.h                              |   36 
 include/rxrpc/transport.h                          |  106 
 include/scsi/iscsi_proto.h                         |   12 
 include/scsi/scsi.h                                |    1 
 include/scsi/scsi_cmnd.h                           |    3 
 include/scsi/scsi_dbg.h                            |   10 
 include/scsi/scsi_device.h                         |   14 
 include/scsi/scsi_host.h                           |   32 
 include/scsi/scsi_tgt_if.h                         |    6 
 include/scsi/scsi_transport_fc.h                   |    2 
 include/scsi/sd.h                                  |   72 
 include/video/mach64.h                             |    1 
 include/video/permedia2.h                          |    4 
 include/video/tgafb.h                              |   47 
 init/Kconfig                                       |   88 
 init/do_mounts.c                                   |    1 
 init/do_mounts_initrd.c                            |    5 
 init/main.c                                        |   37 
 ipc/compat.c                                       |    4 
 ipc/mqueue.c                                       |    3 
 ipc/sem.c                                          |    1 
 ipc/util.c                                         |   54 
 kernel/Makefile                                    |    2 
 kernel/audit.c                                     |   24 
 kernel/cpuset.c                                    |   67 
 kernel/delayacct.c                                 |    6 
 kernel/die_notifier.c                              |   38 
 kernel/exit.c                                      |   18 
 kernel/fork.c                                      |   91 
 kernel/futex.c                                     |  106 
 kernel/hrtimer.c                                   |    4 
 kernel/irq/chip.c                                  |    3 
 kernel/irq/handle.c                                |    4 
 kernel/irq/manage.c                                |   10 
 kernel/irq/proc.c                                  |   15 
 kernel/irq/spurious.c                              |    4 
 kernel/itimer.c                                    |   60 
 kernel/kallsyms.c                                  |  104 
 kernel/kexec.c                                     |    4 
 kernel/kmod.c                                      |    7 
 kernel/kprobes.c                                   |  293 +
 kernel/ksysfs.c                                    |   12 
 kernel/lockdep.c                                   |   51 
 kernel/module.c                                    |  101 
 kernel/nsproxy.c                                   |  139 
 kernel/params.c                                    |    4 
 kernel/pid.c                                       |   15 
 kernel/posix-cpu-timers.c                          |   14 
 kernel/posix-timers.c                              |    1 
 kernel/power/Kconfig                               |   15 
 kernel/power/disk.c                                |  164 
 kernel/power/main.c                                |   70 
 kernel/power/power.h                               |   49 
 kernel/power/process.c                             |   12 
 kernel/power/snapshot.c                            |  310 +
 kernel/power/swap.c                                |   61 
 kernel/power/swsusp.c                              |  139 
 kernel/power/user.c                                |   39 
 kernel/printk.c                                    |   27 
 kernel/rcutorture.c                                |   45 
 kernel/resource.c                                  |   21 
 kernel/rwsem.c                                     |    2 
 kernel/sched.c                                     |  375 +
 kernel/signal.c                                    |    7 
 kernel/softlockup.c                                |   48 
 kernel/stop_machine.c                              |    8 
 kernel/sys.c                                       |   21 
 kernel/sysctl.c                                    |   11 
 kernel/taskstats.c                                 |    8 
 kernel/time.c                                      |   63 
 kernel/time/Makefile                               |    2 
 kernel/time/tick-common.c                          |    8 
 kernel/time/tick-internal.h                        |    1 
 kernel/time/tick-sched.c                           |   51 
 kernel/time/timekeeping.c                          |  476 +
 kernel/time/timer_list.c                           |   15 
 kernel/time/timer_stats.c                          |   14 
 kernel/timer.c                                     |  530 -
 kernel/uid16.c                                     |    1 
 kernel/utsname.c                                   |   41 
 lib/Kconfig                                        |    5 
 lib/Kconfig.debug                                  |   36 
 lib/Makefile                                       |    5 
 lib/cpumask.c                                      |    3 
 lib/devres.c                                       |   26 
 lib/div64.c                                        |   22 
 lib/fault-inject.c                                 |    3 
 lib/inflate.c                                      |  129 
 lib/iomap.c                                        |   27 
 lib/kobject.c                                      |  129 
 lib/kobject_uevent.c                               |   28 
 lib/kref.c                                         |    2 
 lib/parser.c                                       |   10 
 lib/string.c                                       |   28 
 lib/swiotlb.c                                      |    1 
 lib/vsprintf.c                                     |   37 
 lib/zlib_inflate/inflate.c                         |    8 
 mm/Kconfig                                         |    5 
 mm/Makefile                                        |    3 
 mm/filemap.c                                       |  175 
 mm/highmem.c                                       |    9 
 mm/internal.h                                      |    2 
 mm/madvise.c                                       |   33 
 mm/memory.c                                        |  106 
 mm/mmap.c                                          |   48 
 mm/nommu.c                                         |    8 
 mm/oom_kill.c                                      |   17 
 mm/page-writeback.c                                |   61 
 mm/page_alloc.c                                    |   78 
 mm/quicklist.c                                     |   88 
 mm/readahead.c                                     |   29 
 mm/rmap.c                                          |   12 
 mm/shmem.c                                         |    3 
 mm/slab.c                                          |  252 -
 mm/slob.c                                          |   57 
 mm/slub.c                                          | 3520 +++++++++
 mm/sparse.c                                        |   14 
 mm/swap.c                                          |    2 
 mm/swapfile.c                                      |    3 
 mm/vmalloc.c                                       |   21 
 mm/vmscan.c                                        |   21 
 net/802/fddi.c                                     |    7 
 net/802/hippi.c                                    |   12 
 net/802/psnap.c                                    |    4 
 net/802/tr.c                                       |    9 
 net/8021q/vlan.c                                   |    9 
 net/8021q/vlan_dev.c                               |   14 
 net/8021q/vlanproc.c                               |   36 
 net/Kconfig                                        |   22 
 net/Makefile                                       |    4 
 net/appletalk/aarp.c                               |   14 
 net/appletalk/ddp.c                                |   22 
 net/atm/br2684.c                                   |    8 
 net/atm/clip.c                                     |    4 
 net/atm/ioctl.c                                    |    3 
 net/atm/lec.c                                      |   15 
 net/atm/mpc.c                                      |   17 
 net/atm/signaling.c                                |    2 
 net/ax25/af_ax25.c                                 |  114 
 net/ax25/ax25_ds_subr.c                            |    2 
 net/ax25/ax25_in.c                                 |   24 
 net/ax25/ax25_ip.c                                 |    4 
 net/ax25/ax25_out.c                                |   12 
 net/ax25/ax25_subr.c                               |    4 
 net/bluetooth/af_bluetooth.c                       |    2 
 net/bluetooth/bnep/core.c                          |   17 
 net/bluetooth/cmtp/core.c                          |    4 
 net/bluetooth/hci_conn.c                           |   36 
 net/bluetooth/hci_core.c                           |   35 
 net/bluetooth/hci_event.c                          |    8 
 net/bluetooth/hci_sock.c                           |   11 
 net/bluetooth/hci_sysfs.c                          |    9 
 net/bluetooth/l2cap.c                              |   82 
 net/bluetooth/rfcomm/core.c                        |   35 
 net/bluetooth/rfcomm/tty.c                         |   11 
 net/bluetooth/sco.c                                |    2 
 net/bridge/br.c                                    |   12 
 net/bridge/br_device.c                             |   22 
 net/bridge/br_fdb.c                                |   42 
 net/bridge/br_forward.c                            |    2 
 net/bridge/br_if.c                                 |   10 
 net/bridge/br_input.c                              |   51 
 net/bridge/br_ioctl.c                              |    9 
 net/bridge/br_netfilter.c                          |  182 
 net/bridge/br_netlink.c                            |   27 
 net/bridge/br_notify.c                             |   13 
 net/bridge/br_private.h                            |   23 
 net/bridge/br_stp.c                                |   11 
 net/bridge/br_stp_bpdu.c                           |   19 
 net/bridge/br_stp_if.c                             |   60 
 net/bridge/br_stp_timer.c                          |    1 
 net/bridge/br_sysfs_br.c                           |   20 
 net/bridge/br_sysfs_if.c                           |    8 
 net/bridge/netfilter/ebt_arp.c                     |   48 
 net/bridge/netfilter/ebt_log.c                     |   12 
 net/bridge/netfilter/ebt_ulog.c                    |   12 
 net/compat.c                                       |   79 
 net/core/Makefile                                  |    1 
 net/core/datagram.c                                |   10 
 net/core/dev.c                                     |  460 +
 net/core/dev_mcast.c                               |    7 
 net/core/ethtool.c                                 |    4 
 net/core/fib_rules.c                               |  161 
 net/core/filter.c                                  |    6 
 net/core/gen_stats.c                               |    4 
 net/core/link_watch.c                              |    2 
 net/core/neighbour.c                               |   34 
 net/core/net-sysfs.c                               |   31 
 net/core/netpoll.c                                 |   24 
 net/core/pktgen.c                                  |  300 -
 net/core/rtnetlink.c                               |  305 -
 net/core/skbuff.c                                  |  373 +
 net/core/sock.c                                    |  775 +-
 net/core/sysctl_net_core.c                         |    8 
 net/core/utils.c                                   |    6 
 net/core/wireless.c                                | 2371 ------
 net/dccp/ackvec.c                                  |    2 
 net/dccp/ccids/ccid3.c                             |  322 -
 net/dccp/ccids/ccid3.h                             |   10 
 net/dccp/ccids/lib/loss_interval.c                 |    2 
 net/dccp/dccp.h                                    |   75 
 net/dccp/input.c                                   |   54 
 net/dccp/ipv4.c                                    |   43 
 net/dccp/ipv6.c                                    |   40 
 net/dccp/minisocks.c                               |    2 
 net/dccp/options.c                                 |   18 
 net/dccp/output.c                                  |    3 
 net/dccp/probe.c                                   |   17 
 net/decnet/af_decnet.c                             |   12 
 net/decnet/dn_dev.c                                |  116 
 net/decnet/dn_fib.c                                |   10 
 net/decnet/dn_neigh.c                              |    6 
 net/decnet/dn_nsp_in.c                             |    7 
 net/decnet/dn_nsp_out.c                            |    8 
 net/decnet/dn_route.c                              |   42 
 net/decnet/dn_rules.c                              |    6 
 net/decnet/dn_table.c                              |   11 
 net/decnet/netfilter/dn_rtmsg.c                    |    8 
 net/econet/af_econet.c                             |   15 
 net/ethernet/eth.c                                 |    5 
 net/ieee80211/Kconfig                              |    3 
 net/ieee80211/ieee80211_crypt.c                    |    2 
 net/ieee80211/ieee80211_crypt_ccmp.c               |    4 
 net/ieee80211/ieee80211_crypt_tkip.c               |    6 
 net/ieee80211/ieee80211_crypt_wep.c                |    4 
 net/ieee80211/ieee80211_module.c                   |    5 
 net/ieee80211/ieee80211_rx.c                       |   25 
 net/ieee80211/ieee80211_tx.c                       |   12 
 net/ieee80211/ieee80211_wx.c                       |    4 
 net/ipv4/Kconfig                                   |   27 
 net/ipv4/Makefile                                  |    2 
 net/ipv4/af_inet.c                                 |  149 
 net/ipv4/ah4.c                                     |   14 
 net/ipv4/arp.c                                     |   16 
 net/ipv4/cipso_ipv4.c                              |   45 
 net/ipv4/devinet.c                                 |   54 
 net/ipv4/esp4.c                                    |   59 
 net/ipv4/fib_frontend.c                            |   21 
 net/ipv4/fib_hash.c                                |    2 
 net/ipv4/fib_rules.c                               |   11 
 net/ipv4/fib_semantics.c                           |    2 
 net/ipv4/fib_trie.c                                |   51 
 net/ipv4/icmp.c                                    |   31 
 net/ipv4/igmp.c                                    |   58 
 net/ipv4/inet_diag.c                               |   90 
 net/ipv4/inetpeer.c                                |   38 
 net/ipv4/ip_forward.c                              |   14 
 net/ipv4/ip_fragment.c                             |   47 
 net/ipv4/ip_gre.c                                  |   63 
 net/ipv4/ip_input.c                                |   38 
 net/ipv4/ip_options.c                              |   26 
 net/ipv4/ip_output.c                               |  129 
 net/ipv4/ip_sockglue.c                             | 1169 +--
 net/ipv4/ipcomp.c                                  |   58 
 net/ipv4/ipconfig.c                                |   21 
 net/ipv4/ipip.c                                    |   60 
 net/ipv4/ipmr.c                                    |  418 +
 net/ipv4/ipvs/ip_vs_app.c                          |   14 
 net/ipv4/ipvs/ip_vs_core.c                         |   56 
 net/ipv4/ipvs/ip_vs_dh.c                           |    2 
 net/ipv4/ipvs/ip_vs_ftp.c                          |    8 
 net/ipv4/ipvs/ip_vs_lblc.c                         |    2 
 net/ipv4/ipvs/ip_vs_lblcr.c                        |    2 
 net/ipv4/ipvs/ip_vs_proto_ah.c                     |   16 
 net/ipv4/ipvs/ip_vs_proto_tcp.c                    |   24 
 net/ipv4/ipvs/ip_vs_proto_udp.c                    |   26 
 net/ipv4/ipvs/ip_vs_sh.c                           |    2 
 net/ipv4/ipvs/ip_vs_xmit.c                         |   44 
 net/ipv4/multipath_drr.c                           |    2 
 net/ipv4/netfilter.c                               |    8 
 net/ipv4/netfilter/Kconfig                         |  267 -
 net/ipv4/netfilter/Makefile                        |   45 
 net/ipv4/netfilter/arp_tables.c                    |    4 
 net/ipv4/netfilter/arpt_mangle.c                   |   12 
 net/ipv4/netfilter/ip_conntrack_amanda.c           |  229 -
 net/ipv4/netfilter/ip_conntrack_core.c             | 1550 ----
 net/ipv4/netfilter/ip_conntrack_ftp.c              |  520 -
 net/ipv4/netfilter/ip_conntrack_helper_h323.c      | 1841 -----
 net/ipv4/netfilter/ip_conntrack_helper_pptp.c      |  684 --
 net/ipv4/netfilter/ip_conntrack_irc.c              |  314 -
 net/ipv4/netfilter/ip_conntrack_netbios_ns.c       |  143 
 net/ipv4/netfilter/ip_conntrack_netlink.c          | 1577 ----
 net/ipv4/netfilter/ip_conntrack_proto_generic.c    |   74 
 net/ipv4/netfilter/ip_conntrack_proto_gre.c        |  328 -
 net/ipv4/netfilter/ip_conntrack_proto_icmp.c       |  315 -
 net/ipv4/netfilter/ip_conntrack_proto_sctp.c       |  659 --
 net/ipv4/netfilter/ip_conntrack_proto_tcp.c        | 1164 ---
 net/ipv4/netfilter/ip_conntrack_proto_udp.c        |  148 
 net/ipv4/netfilter/ip_conntrack_sip.c              |  520 -
 net/ipv4/netfilter/ip_conntrack_standalone.c       |  962 --
 net/ipv4/netfilter/ip_conntrack_tftp.c             |  161 
 net/ipv4/netfilter/ip_nat_amanda.c                 |   85 
 net/ipv4/netfilter/ip_nat_core.c                   |  634 --
 net/ipv4/netfilter/ip_nat_ftp.c                    |  180 
 net/ipv4/netfilter/ip_nat_helper.c                 |  436 -
 net/ipv4/netfilter/ip_nat_helper_h323.c            |  611 --
 net/ipv4/netfilter/ip_nat_helper_pptp.c            |  350 -
 net/ipv4/netfilter/ip_nat_irc.c                    |  122 
 net/ipv4/netfilter/ip_nat_proto_gre.c              |  174 
 net/ipv4/netfilter/ip_nat_proto_icmp.c             |   87 
 net/ipv4/netfilter/ip_nat_proto_tcp.c              |  154 
 net/ipv4/netfilter/ip_nat_proto_udp.c              |  144 
 net/ipv4/netfilter/ip_nat_proto_unknown.c          |   55 
 net/ipv4/netfilter/ip_nat_rule.c                   |  314 -
 net/ipv4/netfilter/ip_nat_sip.c                    |  282 -
 net/ipv4/netfilter/ip_nat_snmp_basic.c             | 1333 ---
 net/ipv4/netfilter/ip_nat_standalone.c             |  388 -
 net/ipv4/netfilter/ip_nat_tftp.c                   |   70 
 net/ipv4/netfilter/ip_queue.c                      |   28 
 net/ipv4/netfilter/ip_tables.c                     |   12 
 net/ipv4/netfilter/ipt_CLUSTERIP.c                 |   24 
 net/ipv4/netfilter/ipt_ECN.c                       |   15 
 net/ipv4/netfilter/ipt_LOG.c                       |   16 
 net/ipv4/netfilter/ipt_MASQUERADE.c                |   57 
 net/ipv4/netfilter/ipt_NETMAP.c                    |   26 
 net/ipv4/netfilter/ipt_REDIRECT.c                  |   24 
 net/ipv4/netfilter/ipt_REJECT.c                    |   45 
 net/ipv4/netfilter/ipt_SAME.c                      |   40 
 net/ipv4/netfilter/ipt_TOS.c                       |    4 
 net/ipv4/netfilter/ipt_TTL.c                       |    2 
 net/ipv4/netfilter/ipt_ULOG.c                      |   77 
 net/ipv4/netfilter/ipt_addrtype.c                  |    2 
 net/ipv4/netfilter/ipt_ecn.c                       |   10 
 net/ipv4/netfilter/ipt_iprange.c                   |    2 
 net/ipv4/netfilter/ipt_recent.c                    |    6 
 net/ipv4/netfilter/ipt_tos.c                       |    2 
 net/ipv4/netfilter/ipt_ttl.c                       |   11 
 net/ipv4/netfilter/iptable_filter.c                |    3 
 net/ipv4/netfilter/iptable_mangle.c                |   30 
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c     |   27 
 net/ipv4/netfilter/nf_conntrack_proto_icmp.c       |   11 
 net/ipv4/netfilter/nf_nat_core.c                   |   14 
 net/ipv4/netfilter/nf_nat_h323.c                   |   14 
 net/ipv4/netfilter/nf_nat_helper.c                 |   76 
 net/ipv4/netfilter/nf_nat_pptp.c                   |    2 
 net/ipv4/netfilter/nf_nat_proto_gre.c              |   20 
 net/ipv4/netfilter/nf_nat_rule.c                   |    6 
 net/ipv4/netfilter/nf_nat_sip.c                    |   37 
 net/ipv4/netfilter/nf_nat_snmp_basic.c             |    8 
 net/ipv4/netfilter/nf_nat_standalone.c             |   18 
 net/ipv4/proc.c                                    |   41 
 net/ipv4/protocol.c                                |    2 
 net/ipv4/raw.c                                     |   18 
 net/ipv4/route.c                                   |   29 
 net/ipv4/syncookies.c                              |   40 
 net/ipv4/sysctl_net_ipv4.c                         |   16 
 net/ipv4/tcp.c                                     |  149 
 net/ipv4/tcp_bic.c                                 |    2 
 net/ipv4/tcp_cong.c                                |   45 
 net/ipv4/tcp_cubic.c                               |   81 
 net/ipv4/tcp_highspeed.c                           |   24 
 net/ipv4/tcp_htcp.c                                |    2 
 net/ipv4/tcp_hybla.c                               |    2 
 net/ipv4/tcp_illinois.c                            |  356 +
 net/ipv4/tcp_input.c                               |  646 +-
 net/ipv4/tcp_ipv4.c                                |  143 
 net/ipv4/tcp_lp.c                                  |    8 
 net/ipv4/tcp_minisocks.c                           |   29 
 net/ipv4/tcp_output.c                              |  207 -
 net/ipv4/tcp_probe.c                               |   68 
 net/ipv4/tcp_timer.c                               |   10 
 net/ipv4/tcp_vegas.c                               |   57 
 net/ipv4/tcp_vegas.h                               |   24 
 net/ipv4/tcp_veno.c                                |   10 
 net/ipv4/tcp_westwood.c                            |   21 
 net/ipv4/tcp_yeah.c                                |  268 +
 net/ipv4/udp.c                                     |  438 +
 net/ipv4/udplite.c                                 |    2 
 net/ipv4/xfrm4_input.c                             |   23 
 net/ipv4/xfrm4_mode_beet.c                         |   37 
 net/ipv4/xfrm4_mode_transport.c                    |   28 
 net/ipv4/xfrm4_mode_tunnel.c                       |   31 
 net/ipv4/xfrm4_output.c                            |    3 
 net/ipv4/xfrm4_policy.c                            |    8 
 net/ipv4/xfrm4_tunnel.c                            |    3 
 net/ipv6/Kconfig                                   |   10 
 net/ipv6/Makefile                                  |    5 
 net/ipv6/addrconf.c                                |  274 +
 net/ipv6/af_inet6.c                                |   89 
 net/ipv6/ah6.c                                     |   34 
 net/ipv6/anycast.c                                 |   17 
 net/ipv6/datagram.c                                |   63 
 net/ipv6/esp6.c                                    |   52 
 net/ipv6/exthdrs.c                                 |  118 
 net/ipv6/fib6_rules.c                              |   39 
 net/ipv6/icmp.c                                    |   48 
 net/ipv6/ip6_fib.c                                 |    4 
 net/ipv6/ip6_input.c                               |   18 
 net/ipv6/ip6_output.c                              |  187 
 net/ipv6/ip6_tunnel.c                              |  643 +-
 net/ipv6/ipcomp6.c                                 |   16 
 net/ipv6/ipv6_sockglue.c                           |   46 
 net/ipv6/ipv6_syms.c                               |   36 
 net/ipv6/mcast.c                                   |   61 
 net/ipv6/mip6.c                                    |   62 
 net/ipv6/ndisc.c                                   |  435 -
 net/ipv6/netfilter.c                               |    8 
 net/ipv6/netfilter/Kconfig                         |    2 
 net/ipv6/netfilter/ip6_queue.c                     |   28 
 net/ipv6/netfilter/ip6_tables.c                    |   17 
 net/ipv6/netfilter/ip6t_HL.c                       |    2 
 net/ipv6/netfilter/ip6t_LOG.c                      |   21 
 net/ipv6/netfilter/ip6t_REJECT.c                   |   11 
 net/ipv6/netfilter/ip6t_eui64.c                    |    8 
 net/ipv6/netfilter/ip6t_hl.c                       |    2 
 net/ipv6/netfilter/ip6t_ipv6header.c               |    2 
 net/ipv6/netfilter/ip6table_filter.c               |    2 
 net/ipv6/netfilter/ip6table_mangle.c               |   18 
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c     |   30 
 net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c     |    7 
 net/ipv6/netfilter/nf_conntrack_reasm.c            |   59 
 net/ipv6/proc.c                                    |   62 
 net/ipv6/protocol.c                                |    4 
 net/ipv6/raw.c                                     |   52 
 net/ipv6/reassembly.c                              |   62 
 net/ipv6/route.c                                   |   24 
 net/ipv6/sit.c                                     |   58 
 net/ipv6/tcp_ipv6.c                                |  120 
 net/ipv6/udp.c                                     |  123 
 net/ipv6/udplite.c                                 |    2 
 net/ipv6/xfrm6_input.c                             |   18 
 net/ipv6/xfrm6_mode_beet.c                         |   27 
 net/ipv6/xfrm6_mode_ro.c                           |    7 
 net/ipv6/xfrm6_mode_transport.c                    |   20 
 net/ipv6/xfrm6_mode_tunnel.c                       |   36 
 net/ipv6/xfrm6_output.c                            |    6 
 net/ipv6/xfrm6_policy.c                            |   25 
 net/ipv6/xfrm6_tunnel.c                            |    4 
 net/ipx/af_ipx.c                                   |    9 
 net/ipx/ipx_route.c                                |    4 
 net/irda/af_irda.c                                 |  137 
 net/irda/ircomm/ircomm_param.c                     |    4 
 net/irda/irda_device.c                             |   21 
 net/irda/irlan/irlan_common.c                      |    2 
 net/irda/irlan/irlan_eth.c                         |    3 
 net/irda/irlap_event.c                             |    2 
 net/irda/irlap_frame.c                             |   18 
 net/irda/irqueue.c                                 |    9 
 net/irda/irttp.c                                   |   10 
 net/irda/parameters.c                              |    8 
 net/irda/qos.c                                     |   14 
 net/irda/wrapper.c                                 |    5 
 net/iucv/af_iucv.c                                 |  195 
 net/iucv/iucv.c                                    |  256 -
 net/key/af_key.c                                   |    4 
 net/llc/llc_core.c                                 |   10 
 net/llc/llc_input.c                                |    2 
 net/llc/llc_output.c                               |    8 
 net/llc/llc_sap.c                                  |    5 
 net/mac80211/Kconfig                               |   78 
 net/mac80211/Makefile                              |   20 
 net/mac80211/aes_ccm.c                             |  155 
 net/mac80211/aes_ccm.h                             |   26 
 net/mac80211/debugfs.c                             |  433 +
 net/mac80211/debugfs.h                             |   16 
 net/mac80211/debugfs_key.c                         |  252 +
 net/mac80211/debugfs_key.h                         |   34 
 net/mac80211/debugfs_netdev.c                      |  440 +
 net/mac80211/debugfs_netdev.h                      |   30 
 net/mac80211/debugfs_sta.c                         |  246 +
 net/mac80211/debugfs_sta.h                         |   12 
 net/mac80211/hostapd_ioctl.h                       |  108 
 net/mac80211/ieee80211.c                           | 4984 +++++++++++++
 net/mac80211/ieee80211_cfg.c                       |   66 
 net/mac80211/ieee80211_cfg.h                       |    9 
 net/mac80211/ieee80211_common.h                    |   98 
 net/mac80211/ieee80211_i.h                         |  798 ++
 net/mac80211/ieee80211_iface.c                     |  352 +
 net/mac80211/ieee80211_ioctl.c                     | 1822 +++++
 net/mac80211/ieee80211_key.h                       |  106 
 net/mac80211/ieee80211_led.c                       |   91 
 net/mac80211/ieee80211_led.h                       |   32 
 net/mac80211/ieee80211_rate.c                      |  140 
 net/mac80211/ieee80211_rate.h                      |  144 
 net/mac80211/ieee80211_sta.c                       | 3060 ++++++++
 net/mac80211/michael.c                             |  104 
 net/mac80211/michael.h                             |   20 
 net/mac80211/rc80211_simple.c                      |  432 +
 net/mac80211/sta_info.c                            |  470 +
 net/mac80211/sta_info.h                            |  164 
 net/mac80211/tkip.c                                |  341 +
 net/mac80211/tkip.h                                |   36 
 net/mac80211/wep.c                                 |  328 +
 net/mac80211/wep.h                                 |   40 
 net/mac80211/wme.c                                 |  678 ++
 net/mac80211/wme.h                                 |   57 
 net/mac80211/wpa.c                                 |  660 ++
 net/mac80211/wpa.h                                 |   31 
 net/netfilter/Kconfig                              |   87 
 net/netfilter/core.c                               |   21 
 net/netfilter/nf_conntrack_core.c                  |   58 
 net/netfilter/nf_conntrack_ecache.c                |   23 
 net/netfilter/nf_conntrack_expect.c                |    4 
 net/netfilter/nf_conntrack_ftp.c                   |    6 
 net/netfilter/nf_conntrack_netbios_ns.c            |    2 
 net/netfilter/nf_conntrack_netlink.c               |   66 
 net/netfilter/nf_conntrack_proto.c                 |  144 
 net/netfilter/nf_conntrack_proto_generic.c         |    5 
 net/netfilter/nf_conntrack_proto_sctp.c            |    9 
 net/netfilter/nf_conntrack_proto_tcp.c             |   88 
 net/netfilter/nf_conntrack_proto_udp.c             |    5 
 net/netfilter/nf_conntrack_standalone.c            |   11 
 net/netfilter/nfnetlink.c                          |  197 -
 net/netfilter/nfnetlink_log.c                      |  108 
 net/netfilter/nfnetlink_queue.c                    |   20 
 net/netfilter/x_tables.c                           |   26 
 net/netfilter/xt_CONNMARK.c                        |   32 
 net/netfilter/xt_CONNSECMARK.c                     |   18 
 net/netfilter/xt_DSCP.c                            |   10 
 net/netfilter/xt_NOTRACK.c                         |    4 
 net/netfilter/xt_TCPMSS.c                          |   12 
 net/netfilter/xt_connbytes.c                       |   35 
 net/netfilter/xt_connmark.c                        |   17 
 net/netfilter/xt_conntrack.c                       |  110 
 net/netfilter/xt_dscp.c                            |    6 
 net/netfilter/xt_hashlimit.c                       |   14 
 net/netfilter/xt_helper.c                          |   60 
 net/netfilter/xt_length.c                          |    5 
 net/netfilter/xt_limit.c                           |    7 
 net/netfilter/xt_mac.c                             |    4 
 net/netfilter/xt_pkttype.c                         |    2 
 net/netfilter/xt_realm.c                           |    2 
 net/netfilter/xt_state.c                           |    4 
 net/netlabel/netlabel_kapi.c                       |    3 
 net/netlink/af_netlink.c                           |  123 
 net/netlink/attr.c                                 |    5 
 net/netlink/genetlink.c                            |   66 
 net/netrom/af_netrom.c                             |  115 
 net/netrom/nr_dev.c                                |    4 
 net/netrom/nr_in.c                                 |    6 
 net/netrom/nr_loopback.c                           |    4 
 net/netrom/nr_out.c                                |    8 
 net/netrom/nr_route.c                              |    5 
 net/netrom/nr_subr.c                               |    4 
 net/packet/af_packet.c                             |   94 
 net/rfkill/Kconfig                                 |   24 
 net/rfkill/Makefile                                |    6 
 net/rfkill/rfkill-input.c                          |  174 
 net/rfkill/rfkill.c                                |  407 +
 net/rose/af_rose.c                                 |   70 
 net/rose/rose_loopback.c                           |    2 
 net/rose/rose_route.c                              |   10 
 net/rxrpc/Kconfig                                  |   43 
 net/rxrpc/Makefile                                 |   40 
 net/rxrpc/af_rxrpc.c                               |  879 ++
 net/rxrpc/ar-accept.c                              |  504 +
 net/rxrpc/ar-ack.c                                 | 1306 +++
 net/rxrpc/ar-call.c                                |  804 ++
 net/rxrpc/ar-connection.c                          |  911 ++
 net/rxrpc/ar-connevent.c                           |  403 +
 net/rxrpc/ar-error.c                               |  255 +
 net/rxrpc/ar-input.c                               |  797 ++
 net/rxrpc/ar-internal.h                            |  808 ++
 net/rxrpc/ar-key.c                                 |  334 +
 net/rxrpc/ar-local.c                               |  309 +
 net/rxrpc/ar-output.c                              |  734 ++
 net/rxrpc/ar-peer.c                                |  316 +
 net/rxrpc/ar-proc.c                                |  247 +
 net/rxrpc/ar-recvmsg.c                             |  437 +
 net/rxrpc/ar-security.c                            |  258 +
 net/rxrpc/ar-skbuff.c                              |  132 
 net/rxrpc/ar-transport.c                           |  276 +
 net/rxrpc/call.c                                   | 2277 ------
 net/rxrpc/connection.c                             |  777 --
 net/rxrpc/internal.h                               |  106 
 net/rxrpc/krxiod.c                                 |  262 -
 net/rxrpc/krxsecd.c                                |  270 -
 net/rxrpc/krxtimod.c                               |  204 -
 net/rxrpc/main.c                                   |  180 
 net/rxrpc/peer.c                                   |  398 -
 net/rxrpc/proc.c                                   |  617 --
 net/rxrpc/rxkad.c                                  | 1154 +++
 net/rxrpc/rxrpc_syms.c                             |   34 
 net/rxrpc/sysctl.c                                 |  121 
 net/rxrpc/transport.c                              |  846 --
 net/sched/Kconfig                                  |   56 
 net/sched/act_api.c                                |   81 
 net/sched/act_gact.c                               |    5 
 net/sched/act_ipt.c                                |    5 
 net/sched/act_mirred.c                             |    5 
 net/sched/act_pedit.c                              |    7 
 net/sched/act_police.c                             |   34 
 net/sched/act_simple.c                             |    5 
 net/sched/cls_api.c                                |   36 
 net/sched/cls_basic.c                              |    7 
 net/sched/cls_fw.c                                 |    7 
 net/sched/cls_route.c                              |   11 
 net/sched/cls_rsvp.c                               |    1 
 net/sched/cls_rsvp.h                               |   12 
 net/sched/cls_rsvp6.c                              |    1 
 net/sched/cls_tcindex.c                            |    9 
 net/sched/cls_u32.c                                |   13 
 net/sched/em_u32.c                                 |    2 
 net/sched/ematch.c                                 |   17 
 net/sched/sch_api.c                                |  234 -
 net/sched/sch_atm.c                                |   28 
 net/sched/sch_cbq.c                                |  207 -
 net/sched/sch_dsmark.c                             |   22 
 net/sched/sch_generic.c                            |   35 
 net/sched/sch_hfsc.c                               |  109 
 net/sched/sch_htb.c                                |  130 
 net/sched/sch_ingress.c                            |   27 
 net/sched/sch_netem.c                              |  108 
 net/sched/sch_prio.c                               |   14 
 net/sched/sch_sfq.c                                |    9 
 net/sched/sch_tbf.c                                |   47 
 net/sched/sch_teql.c                               |    2 
 net/sctp/associola.c                               |   43 
 net/sctp/debug.c                                   |    5 
 net/sctp/input.c                                   |   51 
 net/sctp/inqueue.c                                 |    8 
 net/sctp/ipv6.c                                    |   85 
 net/sctp/output.c                                  |    2 
 net/sctp/outqueue.c                                |   12 
 net/sctp/protocol.c                                |  101 
 net/sctp/sm_make_chunk.c                           |   27 
 net/sctp/sm_sideeffect.c                           |   51 
 net/sctp/sm_statefuns.c                            |   57 
 net/sctp/sm_statetable.c                           |    2 
 net/sctp/socket.c                                  |  403 +
 net/sctp/transport.c                               |    2 
 net/sctp/ulpevent.c                                |   49 
 net/sctp/ulpqueue.c                                |  173 
 net/socket.c                                       |   56 
 net/sunrpc/Makefile                                |    2 
 net/sunrpc/auth_gss/gss_spkm3_seal.c               |   13 
 net/sunrpc/cache.c                                 |   10 
 net/sunrpc/clnt.c                                  |   69 
 net/sunrpc/pmap_clnt.c                             |  383 -
 net/sunrpc/rpc_pipe.c                              |    3 
 net/sunrpc/rpcb_clnt.c                             |  625 ++
 net/sunrpc/sched.c                                 |   65 
 net/sunrpc/socklib.c                               |    2 
 net/sunrpc/svc.c                                   |    2 
 net/sunrpc/svcsock.c                               |   10 
 net/sunrpc/xprt.c                                  |    4 
 net/sunrpc/xprtsock.c                              |    4 
 net/tipc/Kconfig                                   |    2 
 net/tipc/config.c                                  |    2 
 net/tipc/eth_media.c                               |   20 
 net/tipc/link.c                                    |   48 
 net/tipc/msg.h                                     |   18 
 net/tipc/netlink.c                                 |    2 
 net/tipc/port.c                                    |    8 
 net/tipc/socket.c                                  |    2 
 net/unix/af_unix.c                                 |    3 
 net/wanrouter/wanmain.c                            |    6 
 net/wireless/Kconfig                               |   16 
 net/wireless/Makefile                              |    4 
 net/wireless/core.c                                |  224 +
 net/wireless/core.h                                |   49 
 net/wireless/sysfs.c                               |   80 
 net/wireless/sysfs.h                               |    9 
 net/wireless/wext.c                                | 1509 ++++
 net/x25/af_x25.c                                   |   23 
 net/x25/x25_dev.c                                  |    4 
 net/x25/x25_in.c                                   |   14 
 net/x25/x25_out.c                                  |    6 
 net/xfrm/xfrm_algo.c                               |  169 
 net/xfrm/xfrm_input.c                              |    6 
 net/xfrm/xfrm_policy.c                             |   85 
 net/xfrm/xfrm_state.c                              |   60 
 net/xfrm/xfrm_user.c                               |  233 -
 scripts/Makefile.build                             |   19 
 scripts/Makefile.host                              |   14 
 scripts/Makefile.modpost                           |    8 
 scripts/basic/fixdep.c                             |    2 
 scripts/checksyscalls.sh                           |  118 
 scripts/cleanfile                                  |  126 
 scripts/cleanpatch                                 |  206 +
 scripts/gen_initramfs_list.sh                      |   12 
 scripts/genksyms/genksyms.c                        |    3 
 scripts/kconfig/Makefile                           |    5 
 scripts/kconfig/conf.c                             |    1 
 scripts/kconfig/lex.zconf.c_shipped                |    2 
 scripts/kconfig/lkc.h                              |    1 
 scripts/kconfig/lxdialog/dialog.h                  |    1 
 scripts/kconfig/lxdialog/util.c                    |    9 
 scripts/kconfig/mconf.c                            |   43 
 scripts/kconfig/menu.c                             |    2 
 scripts/kconfig/qconf.cc                           |    5 
 scripts/kconfig/qconf.h                            |    2 
 scripts/kconfig/symbol.c                           |   13 
 scripts/kconfig/zconf.l                            |    2 
 scripts/kconfig/zconf.tab.c_shipped                |    6 
 scripts/kconfig/zconf.y                            |    6 
 scripts/kernel-doc                                 |  140 
 scripts/mkcompile_h                                |   27 
 scripts/mkuboot.sh                                 |    2 
 scripts/mod/file2alias.c                           |   21 
 scripts/mod/mk_elfconfig.c                         |    3 
 scripts/mod/modpost.c                              |  167 
 scripts/mod/modpost.h                              |    1 
 scripts/mod/sumversion.c                           |    5 
 security/capability.c                              |    1 
 security/commoncap.c                               |    1 
 security/inode.c                                   |    2 
 security/keys/keyring.c                            |    2 
 security/selinux/Makefile                          |    2 
 security/selinux/avc.c                             |    2 
 security/selinux/hooks.c                           |   52 
 security/selinux/include/av_perm_to_string.h       |  102 
 security/selinux/include/av_permissions.h          |  179 
 security/selinux/include/class_to_string.h         |   34 
 security/selinux/include/flask.h                   |   16 
 security/selinux/include/netlabel.h                |  121 
 security/selinux/include/security.h                |   29 
 security/selinux/include/selinux_netlabel.h        |  124 
 security/selinux/netlabel.c                        |  363 +
 security/selinux/netlink.c                         |    4 
 security/selinux/selinuxfs.c                       |   85 
 security/selinux/ss/services.c                     |  499 -
 sound/aoa/codecs/snd-aoa-codec-onyx.c              |    8 
 sound/aoa/codecs/snd-aoa-codec-tas.c               |   11 
 sound/aoa/core/snd-aoa-gpio-feature.c              |    8 
 sound/aoa/fabrics/snd-aoa-fabric-layout.c          |    8 
 sound/aoa/soundbus/core.c                          |   82 
 sound/aoa/soundbus/i2sbus/i2sbus-core.c            |   12 
 sound/arm/pxa2xx-ac97.c                            |   12 
 sound/core/control.c                               |    1 
 sound/core/hwdep.c                                 |    1 
 sound/core/init.c                                  |    1 
 sound/core/oss/mixer_oss.c                         |    1 
 sound/core/oss/pcm_oss.c                           |    1 
 sound/core/pcm_native.c                            |    1 
 sound/core/rawmidi.c                               |    1 
 sound/core/seq/oss/seq_oss.c                       |    1 
 sound/core/seq/seq_clientmgr.c                     |    1 
 sound/core/timer.c                                 |    1 
 sound/oss/Kconfig                                  |   30 
 sound/oss/au1550_ac97.c                            |    1 
 sound/oss/btaudio.c                                |    2 
 sound/oss/dmasound/Kconfig                         |   14 
 sound/oss/dmasound/dmasound_awacs.c                |  137 
 sound/oss/dmasound/tas_common.c                    |    9 
 sound/oss/dmasound/tas_ioctl.h                     |    1 
 sound/oss/sh_dac_audio.c                           |    2 
 sound/oss/soundcard.c                              |    1 
 sound/oss/swarm_cs4297a.c                          |    1 
 sound/oss/trident.c                                |    1 
 sound/oss/via82cxxx_audio.c                        |    1 
 sound/pci/ca0106/ca0106_mixer.c                    |    2 
 sound/pci/ca0106/ca0106_proc.c                     |    2 
 sound/pci/cs46xx/dsp_spos.c                        |    1 
 sound/pci/cs46xx/dsp_spos_scb_lib.c                |    1 
 sound/pci/hda/hda_generic.c                        |    1 
 sound/pci/hda/hda_proc.c                           |    1 
 sound/pci/hda/patch_atihdmi.c                      |    1 
 sound/pci/hda/patch_si3054.c                       |    1 
 sound/pci/hda/patch_via.c                          |    1 
 sound/ppc/pmac.c                                   |   55 
 sound/ppc/tumbler.c                                |   57 
 sound/soc/pxa/pxa2xx-ac97.c                        |   12 
 sound/soc/pxa/pxa2xx-i2s.c                         |    4 
 sound/sparc/amd7930.c                              |    4 
 sound/sparc/cs4231.c                               |    2 
 usr/Kconfig                                        |    2 
 5612 files changed, 371328 insertions(+), 197629 deletions(-)

diff --git a/CREDITS b/CREDITS
index 6bd8ab8..80e2413 100644
--- a/CREDITS
+++ b/CREDITS
@@ -317,6 +317,12 @@ S: 2322 37th Ave SW
 S: Seattle, Washington 98126-2010
 S: USA
 
+N: Johannes Berg
+E: johannes@sipsolutions.net
+W: http://johannes.sipsolutions.net/
+P: 1024D/9AB78CA5 AD02 0176 4E29 C137 1DF6 08D2 FC44 CF86 9AB7 8CA5
+D: powerpc & 802.11 hacker
+
 N: Stephen R. van den Berg (AKA BuGless)
 E: berg@pool.informatik.rwth-aachen.de
 D: General kernel, gcc, and libc hacker
@@ -655,7 +661,7 @@ N: Kees Cook
 E: kees@outflux.net
 W: http://outflux.net/
 P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30  1975 1FFF 4BA9 1706 3E6D
-D: Minor updates to SCSI code for the Communications type
+D: Minor updates to SCSI types, added /proc/pid/maps protection
 S: (ask for current address)
 S: USA
 
@@ -1739,8 +1745,9 @@ S: D-64295
 S: Germany
 
 N: Andi Kleen
-E: ak@muc.de
-D: network hacker, syncookies
+E: andi@firstfloor.org
+U: http://www.halobates.de
+D: network, x86, NUMA, various hacks
 S: Schwalbenstr. 96
 S: 85551 Ottobrunn
 S: Germany
@@ -2286,14 +2293,14 @@ S: D-90453 Nuernberg
 S: Germany
 
 N: Arnaldo Carvalho de Melo
-E: acme@mandriva.com
 E: acme@ghostprotocols.net
+E: arnaldo.melo@gmail.com
+E: acme@redhat.com
 W: http://oops.ghostprotocols.net:81/blog/
 P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD  841A B6AB 4681 9224 DF01
 D: IPX, LLC, DCCP, cyc2x, wl3501_cs, net/ hacks
-S: Mandriva
-S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+S: R. Brasílio Itiberê, 4270/1010 - Água Verde
+S: 80240-060 - Curitiba - Paraná
 S: Brazil
 
 N: Karsten Merker
@@ -2573,10 +2580,9 @@ S: Australia
 
 N: Miguel Ojeda Sandonis
 E: maxextreme@gmail.com
-D: Author: Auxiliary LCD Controller driver (ks0108)
-D: Author: Auxiliary LCD driver (cfag12864b)
-D: Author: Auxiliary LCD framebuffer driver (cfag12864bfb)
-D: Maintainer: Auxiliary display drivers tree (drivers/auxdisplay/*)
+W: http://maxextreme.googlepages.com/
+D: Author of the ks0108, cfag12864b and cfag12864bfb auxiliary display drivers.
+D: Maintainer of the auxiliary display drivers tree (drivers/auxdisplay/*)
 S: C/ Mieses 20, 9-B
 S: Valladolid 47009
 S: Spain
@@ -3295,6 +3301,14 @@ S: 12725 SW Millikan Way, Suite 400
 S: Beaverton, Oregon 97005
 S: USA
 
+N: Li Yang
+E: leoli@freescale.com
+D: Freescale Highspeed USB device driver
+D: Freescale QE SoC support and Ethernet driver
+S: B-1206 Jingmao Guojigongyu
+S: 16 Baliqiao Nanjie, Beijing 101100
+S: People's Repulic of China
+
 N: Marcelo Tosatti
 E: marcelo@kvack.org
 D: v2.4 kernel maintainer
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
new file mode 100644
index 0000000..f9937ad
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -0,0 +1,41 @@
+What:		/sys/bus/usb/devices/.../power/autosuspend
+Date:		March 2007
+KernelVersion:	2.6.21
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		Each USB device directory will contain a file named
+		power/autosuspend.  This file holds the time (in seconds)
+		the device must be idle before it will be autosuspended.
+		0 means the device will be autosuspended as soon as
+		possible.  Negative values will prevent the device from
+		being autosuspended at all, and writing a negative value
+		will resume the device if it is already suspended.
+
+		The autosuspend delay for newly-created devices is set to
+		the value of the usbcore.autosuspend module parameter.
+
+What:		/sys/bus/usb/devices/.../power/level
+Date:		March 2007
+KernelVersion:	2.6.21
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		Each USB device directory will contain a file named
+		power/level.  This file holds a power-level setting for
+		the device, one of "on", "auto", or "suspend".
+
+		"on" means that the device is not allowed to autosuspend,
+		although normal suspends for system sleep will still
+		be honored.  "auto" means the device will autosuspend
+		and autoresume in the usual manner, according to the
+		capabilities of its driver.  "suspend" means the device
+		is forced into a suspended state and it will not autoresume
+		in response to I/O requests.  However remote-wakeup requests
+		from the device may still be enabled (the remote-wakeup
+		setting is controlled separately by the power/wakeup
+		attribute).
+
+		During normal use, devices should be left in the "auto"
+		level.  The other levels are meant for administrative uses.
+		If you want to suspend a device immediately but leave it
+		free to wake up in response to I/O requests, you should
+		write "0" to power/autosuspend.
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 9069189..afc2867 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -160,6 +160,21 @@ supply of new-lines on your screen is no
 25-line terminal screens here), you have more empty lines to put
 comments on.
 
+Do not unnecessarily use braces where a single statement will do.
+
+if (condition)
+	action();
+
+This does not apply if one branch of a conditional statement is a single
+statement. Use braces in both branches.
+
+if (condition) {
+	do_this();
+	do_that();
+} else {
+	otherwise();
+}
+
 		3.1:  Spaces
 
 Linux kernel style for use of spaces depends (mostly) on
@@ -625,7 +640,7 @@ language.
 
 There appears to be a common misperception that gcc has a magic "make me
 faster" speedup option called "inline". While the use of inlines can be
-appropriate (for example as a means of replacing macros, see Chapter 11), it
+appropriate (for example as a means of replacing macros, see Chapter 12), it
 very often is not. Abundant use of the inline keyword leads to a much bigger
 kernel, which in turn slows the system as a whole down, due to a bigger
 icache footprint for the CPU and simply because there is less memory
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 867608a..6fd1646 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -41,8 +41,9 @@ psdocs: $(PS)
 PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
 pdfdocs: $(PDF)
 
-HTML := $(patsubst %.xml, %.html, $(BOOKS))
+HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
 htmldocs: $(HTML)
+	$(call build_main_index)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
@@ -132,10 +133,17 @@ quiet_cmd_db2pdf = PDF      $@
 %.pdf : %.xml
 	$(call cmd,db2pdf)
 
+
+main_idx = Documentation/DocBook/index.html
+build_main_index = rm -rf $(main_idx) && \
+		   echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
+		   echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
+		   cat $(HTML) >> $(main_idx)
+
 quiet_cmd_db2html = HTML   $@
       cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
 		echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
-         Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
+        $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
 
 %.html:	%.xml
 	@(which xmlto > /dev/null 2>&1) || \
@@ -152,6 +160,7 @@ quiet_cmd_db2man = MAN     $@
 	@(which xmlto > /dev/null 2>&1) || \
 	 (echo "*** You need to install xmlto ***"; \
 	  exit 1)
+	$(Q)mkdir -p $(obj)/man
 	$(call cmd,db2man)
 	@touch $@
 
@@ -212,11 +221,7 @@ clean-files := $(DOCBOOKS) \
 	$(patsubst %.xml, %.9,    $(DOCBOOKS)) \
 	$(C-procfs-example)
 
-clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS))
-
-#man put files in man subdir - traverse down
-subdir- := man/
-
+clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
 
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable se we can use it in if_changed and friends.
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 0bb9023..a2b2b4d 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -236,6 +236,12 @@ X!Ilib/string.c
 !Enet/core/dev.c
 !Enet/ethernet/eth.c
 !Iinclude/linux/etherdevice.h
+!Edrivers/net/phy/phy.c
+!Idrivers/net/phy/phy.c
+!Edrivers/net/phy/phy_device.c
+!Idrivers/net/phy/phy_device.c
+!Edrivers/net/phy/mdio_bus.c
+!Idrivers/net/phy/mdio_bus.c
 <!-- FIXME: Removed for now since no structured comments in source
 X!Enet/core/wireless.c
 -->
@@ -570,4 +576,67 @@ X!Idrivers/video/console/fonts.c
 !Edrivers/input/ff-core.c
 !Edrivers/input/ff-memless.c
   </chapter>
+
+  <chapter id="spi">
+      <title>Serial Peripheral Interface (SPI)</title>
+  <para>
+	SPI is the "Serial Peripheral Interface", widely used with
+	embedded systems because it is a simple and efficient
+	interface:  basically a multiplexed shift register.
+	Its three signal wires hold a clock (SCK, often in the range
+	of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
+	a "Master In, Slave Out" (MISO) data line.
+	SPI is a full duplex protocol; for each bit shifted out the
+	MOSI line (one per clock) another is shifted in on the MISO line.
+	Those bits are assembled into words of various sizes on the
+	way to and from system memory.
+	An additional chipselect line is usually active-low (nCS);
+	four signals are normally used for each peripheral, plus
+	sometimes an interrupt.
+  </para>
+  <para>
+	The SPI bus facilities listed here provide a generalized
+	interface to declare SPI busses and devices, manage them
+	according to the standard Linux driver model, and perform
+	input/output operations.
+	At this time, only "master" side interfaces are supported,
+	where Linux talks to SPI peripherals and does not implement
+	such a peripheral itself.
+	(Interfaces to support implementing SPI slaves would
+	necessarily look different.)
+  </para>
+  <para>
+	The programming interface is structured around two kinds of driver,
+	and two kinds of device.
+	A "Controller Driver" abstracts the controller hardware, which may
+	be as simple as a set of GPIO pins or as complex as a pair of FIFOs
+	connected to dual DMA engines on the other side of the SPI shift
+	register (maximizing throughput).  Such drivers bridge between
+	whatever bus they sit on (often the platform bus) and SPI, and
+	expose the SPI side of their device as a
+	<structname>struct spi_master</structname>.
+	SPI devices are children of that master, represented as a
+	<structname>struct spi_device</structname> and manufactured from
+	<structname>struct spi_board_info</structname> descriptors which
+	are usually provided by board-specific initialization code.
+	A <structname>struct spi_driver</structname> is called a
+	"Protocol Driver", and is bound to a spi_device using normal
+	driver model calls.
+  </para>
+  <para>
+	The I/O model is a set of queued messages.  Protocol drivers
+	submit one or more <structname>struct spi_message</structname>
+	objects, which are processed and completed asynchronously.
+	(There are synchronous wrappers, however.)  Messages are
+	built from one or more <structname>struct spi_transfer</structname>
+	objects, each of which wraps a full duplex SPI transfer.
+	A variety of protocol tweaking options are needed, because
+	different chips adopt very different policies for how they
+	use the bits transferred with SPI.
+  </para>
+!Iinclude/linux/spi/spi.h
+!Fdrivers/spi/spi.c spi_register_board_info
+!Edrivers/spi/spi.c
+  </chapter>
+
 </book>
diff --git a/Documentation/DocBook/librs.tmpl b/Documentation/DocBook/librs.tmpl
index 3ff39ba..94f2136 100644
--- a/Documentation/DocBook/librs.tmpl
+++ b/Documentation/DocBook/librs.tmpl
@@ -79,12 +79,12 @@
   <chapter id="usage">
      	<title>Usage</title>
 	<para>
-		This chapter provides examples how to use the library.
+		This chapter provides examples of how to use the library.
 	</para>
 	<sect1>
 		<title>Initializing</title>
 		<para>
-			The init function init_rs returns a pointer to a
+			The init function init_rs returns a pointer to an
 			rs decoder structure, which holds the necessary
 			information for encoding, decoding and error correction
 			with the given polynomial. It either uses an existing
@@ -98,10 +98,10 @@
 static struct rs_control *rs_decoder;
 
 /* Symbolsize is 10 (bits)
- * Primitve polynomial is x^10+x^3+1
+ * Primitive polynomial is x^10+x^3+1
  * first consecutive root is 0
- * primitve element to generate roots = 1
- * generator polinomial degree (number of roots) = 6
+ * primitive element to generate roots = 1
+ * generator polynomial degree (number of roots) = 6
  */
 rs_decoder = init_rs (10, 0x409, 0, 1, 6);
 		</programlisting>
@@ -116,12 +116,12 @@ rs_decoder = init_rs (10, 0x409, 0, 1, 6
 		</para>
 		<para>
 			The expanded data can be inverted on the fly by
-			providing a non zero inversion mask. The expanded data is
+			providing a non-zero inversion mask. The expanded data is
 			XOR'ed with the mask. This is used e.g. for FLASH
 			ECC, where the all 0xFF is inverted to an all 0x00.
 			The Reed-Solomon code for all 0x00 is all 0x00. The
 			code is inverted before storing to FLASH so it is 0xFF
-			too. This prevent's that reading from an erased FLASH
+			too. This prevents that reading from an erased FLASH
 			results in ECC errors.
 		</para>
 		<para>
@@ -273,7 +273,7 @@ free_rs(rs_decoder);
  		May be used under the terms of the GNU General Public License (GPL)
 	</programlisting>
 	<para>
-		The wrapper functions and interfaces are written by Thomas Gleixner
+		The wrapper functions and interfaces are written by Thomas Gleixner.
 	</para>
 	<para>
 		Many users have provided bugfixes, improvements and helping hands for testing.
diff --git a/Documentation/DocBook/man/Makefile b/Documentation/DocBook/man/Makefile
deleted file mode 100644
index 4fb7ea0..0000000
--- a/Documentation/DocBook/man/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# Rules are put in Documentation/DocBook
-
-clean-files := *.9.gz *.sgml manpage.links manpage.refs
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 58bead0..d7e2642 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -87,6 +87,21 @@ Clarity:	It helps if anyone can see how 
 		driver that intentionally obfuscates how the hardware works
 		it will go in the bitbucket.
 
+PM support:	Since Linux is used on many portable and desktop systems, your
+		driver is likely to be used on such a system and therefore it
+		should support basic power management by implementing, if
+		necessary, the .suspend and .resume methods used during the
+		system-wide suspend and resume transitions.  You should verify
+		that your driver correctly handles the suspend and resume, but
+		if you are unable to ensure that, please at least define the
+		.suspend method returning the -ENOSYS ("Function not
+		implemented") error.  You should also try to make sure that your
+		driver uses as little power as possible when it's not doing
+		anything.  For the driver testing instructions see
+		Documentation/power/drivers-testing.txt and for a relatively
+		complete overview of the power management issues related to
+		drivers see Documentation/power/devices.txt .
+
 Control:	In general if there is active maintainance of a driver by
 		the author then patches will be redirected to them unless
 		they are totally obvious and without need of checking.
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index e9126e7..71acc28 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -61,8 +61,6 @@ #define PRINTF(fmt, arg...) {			\
 #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 */
-#define MAX_FILENAME	256
 
 struct msgtemplate {
 	struct nlmsghdr n;
@@ -72,6 +70,16 @@ struct msgtemplate {
 
 char cpumask[100+6*MAX_CPUS];
 
+static void usage(void)
+{
+	fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
+			"[-m cpumask] [-t tgid] [-p pid]\n");
+	fprintf(stderr, "  -d: print delayacct stats\n");
+	fprintf(stderr, "  -i: print IO accounting (works only with -p)\n");
+	fprintf(stderr, "  -l: listen forever\n");
+	fprintf(stderr, "  -v: debug on\n");
+}
+
 /*
  * Create a raw netlink socket and bind
  */
@@ -221,13 +229,13 @@ int main(int argc, char *argv[])
 	int count = 0;
 	int write_file = 0;
 	int maskset = 0;
-	char logfile[128];
+	char *logfile = NULL;
 	int loop = 0;
 
 	struct msgtemplate msg;
 
 	while (1) {
-		c = getopt(argc, argv, "diw:r:m:t:p:v:l");
+		c = getopt(argc, argv, "diw:r:m:t:p:vl");
 		if (c < 0)
 			break;
 
@@ -241,7 +249,7 @@ int main(int argc, char *argv[])
 			print_io_accounting = 1;
 			break;
 		case 'w':
-			strncpy(logfile, optarg, MAX_FILENAME);
+			logfile = strdup(optarg);
 			printf("write to file %s\n", logfile);
 			write_file = 1;
 			break;
@@ -277,7 +285,7 @@ int main(int argc, char *argv[])
 			loop = 1;
 			break;
 		default:
-			printf("Unknown option %d\n", c);
+			usage();
 			exit(-1);
 		}
 	}
diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX
new file mode 100644
index 0000000..7cb3b35
--- /dev/null
+++ b/Documentation/blackfin/00-INDEX
@@ -0,0 +1,11 @@
+00-INDEX
+	- This file
+
+cache-lock.txt
+	- HOWTO for blackfin cache locking.
+
+cachefeatures.txt
+	- Supported cache features.
+
+Filesystems
+	- Requirements for mounting the root file system.
diff --git a/Documentation/blackfin/Filesystems b/Documentation/blackfin/Filesystems
new file mode 100644
index 0000000..51260a1
--- /dev/null
+++ b/Documentation/blackfin/Filesystems
@@ -0,0 +1,169 @@
+/*
+ * File:         Documentation/blackfin/Filesystems
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev:          $Id: Filesystems 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+		How to mount the root file system in uClinux/Blackfin
+		-----------------------------------------------------
+
+1	Mounting EXT3 File system.
+	------------------------
+
+	Creating an EXT3 File system for uClinux/Blackfin:
+
+
+Please follow the steps to form the EXT3 File system and mount the same as root
+file system.
+
+a	Make an ext3 file system as large as you want the final root file
+	system.
+
+		mkfs.ext3  /dev/ram0 <your-rootfs-size-in-1k-blocks>
+
+b	Mount this Empty file system on a free directory as:
+
+		mount -t ext3 /dev/ram0  ./test
+			where ./test is the empty directory.
+
+c	Copy your root fs directory that you have so carefully made over.
+
+		cp -af  /tmp/my_final_rootfs_files/* ./test
+
+		(For ex: cp -af uClinux-dist/romfs/* ./test)
+
+d	If you have done everything right till now you should be able to see
+	the required "root" dir's (that's etc, root, bin, lib, sbin...)
+
+e	Now unmount the file system
+
+		umount  ./test
+
+f	Create the root file system image.
+
+		dd if=/dev/ram0 bs=1k count=<your-rootfs-size-in-1k-blocks> \
+		> ext3fs.img
+
+
+Now you have to tell the kernel that will be mounting this file system as
+rootfs.
+So do a make menuconfig under kernel and select the Ext3 journaling file system
+support under File system --> submenu.
+
+
+2.	Mounting EXT2 File system.
+	-------------------------
+
+By default the ext2 file system image will be created if you invoke make from
+the top uClinux-dist directory.
+
+
+3.	Mounting CRAMFS File System
+	----------------------------
+
+To create a CRAMFS file system image execute the command
+
+	mkfs.cramfs ./test cramfs.img
+
+	where ./test is the target directory.
+
+
+4.	Mounting ROMFS File System
+	--------------------------
+
+To create a ROMFS file system image execute the command
+
+	genromfs -v -V "ROMdisk" -f romfs.img -d ./test
+
+	where ./test is the target directory
+
+
+5.	Mounting the JFFS2 Filesystem
+	-----------------------------
+
+To create a compressed JFFS filesystem (JFFS2), please execute the command
+
+	mkfs.jffs2 -d ./test -o jffs2.img
+
+	where ./test is the target directory.
+
+However, please make sure the following is in your kernel config.
+
+/*
+ * RAM/ROM/Flash chip drivers
+ */
+#define CONFIG_MTD_CFI 1
+#define CONFIG_MTD_ROM 1
+/*
+ * Mapping drivers for chip access
+ */
+#define CONFIG_MTD_COMPLEX_MAPPINGS 1
+#define CONFIG_MTD_BF533 1
+#undef CONFIG_MTD_UCLINUX
+
+Through the u-boot boot loader, use the jffs2.img in the corresponding
+partition made in linux-2.6.x/drivers/mtd/maps/bf533_flash.c.
+
+NOTE - 	Currently the Flash driver is available only for EZKIT. Watch out for a
+	STAMP driver soon.
+
+
+6. 	Mounting the NFS File system
+	-----------------------------
+
+	For mounting the NFS please do the following in the kernel config.
+
+	In Networking Support --> Networking options --> TCP/IP networking -->
+		IP: kernel level autoconfiguration
+
+	Enable BOOTP Support.
+
+	In Kernel hacking --> Compiled-in kernel boot parameter add the following
+
+		root=/dev/nfs rw ip=bootp
+
+	In File system --> Network File system, Enable
+
+		NFS file system support --> NFSv3 client support
+		Root File system on NFS
+
+	in uClibc menuconfig, do the following
+	In Networking Support
+		enable Remote Procedure Call (RPC) support
+			Full RPC Support
+
+	On the Host side, ensure that /etc/dhcpd.conf looks something like this
+
+		ddns-update-style ad-hoc;
+		allow bootp;
+		subnet 10.100.4.0 netmask 255.255.255.0 {
+		default-lease-time 122209600;
+		max-lease-time 31557600;
+		group {
+			host bf533 {
+				hardware ethernet 00:CF:52:49:C3:01;
+				fixed-address 10.100.4.50;
+				option root-path "/home/nfsmount";
+			}
+		}
+
+	ensure that /etc/exports looks something like this
+		/home/nfsmount *(rw,no_root_squash,no_all_squash)
+
+	 run the following commands as root (may differ depending on your
+	 distribution) :
+		-  service nfs start
+		-  service portmap start
+		-  service dhcpd start
+		-  /usr/sbin/exportfs
diff --git a/Documentation/blackfin/cache-lock.txt b/Documentation/blackfin/cache-lock.txt
new file mode 100644
index 0000000..88ba1e6
--- /dev/null
+++ b/Documentation/blackfin/cache-lock.txt
@@ -0,0 +1,48 @@
+/*
+ * File:         Documentation/blackfin/cache-lock.txt
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev:          $Id: cache-lock.txt 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+How to lock your code in cache in uClinux/blackfin
+--------------------------------------------------
+
+There are only a few steps required to lock your code into the cache.
+Currently you can lock the code by Way.
+
+Below are the interface provided for locking the cache.
+
+
+1. cache_grab_lock(int Ways);
+
+This function grab the lock for locking your code into the cache specified
+by Ways.
+
+
+2. cache_lock(int Ways);
+
+This function should be called after your critical code has been executed.
+Once the critical code exits, the code is now loaded into the cache. This
+function locks the code into the cache.
+
+
+So, the example sequence will be:
+
+	cache_grab_lock(WAY0_L);	/* Grab the lock */
+
+	critical_code();		/* Execute the code of interest */
+
+	cache_lock(WAY0_L);		/* Lock the cache */
+
+Where WAY0_L signifies WAY0 locking.
diff --git a/Documentation/blackfin/cachefeatures.txt b/Documentation/blackfin/cachefeatures.txt
new file mode 100644
index 0000000..0fbec23
--- /dev/null
+++ b/Documentation/blackfin/cachefeatures.txt
@@ -0,0 +1,65 @@
+/*
+ * File:         Documentation/blackfin/cachefeatures.txt
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev:          $Id: cachefeatures.txt 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+	- Instruction and Data cache initialization.
+		icache_init();
+		dcache_init();
+
+	-  Instruction and Data cache Invalidation Routines, when flushing the
+	   same is not required.
+		_icache_invalidate();
+		_dcache_invalidate();
+
+	Also, for invalidating the entire instruction and data cache, the below
+	routines are provided (another method for invalidation, refer page no 267 and 287 of
+	ADSP-BF533 Hardware Reference manual)
+
+		invalidate_entire_dcache();
+		invalidate_entire_icache();
+
+	-External Flushing of Instruction and data cache routines.
+
+		flush_instruction_cache();
+		flush_data_cache();
+
+	- Internal Flushing of Instruction and Data Cache.
+
+		icplb_flush();
+		dcplb_flush();
+
+	- Locking the cache.
+
+		cache_grab_lock();
+		cache_lock();
+
+	Please refer linux-2.6.x/Documentation/blackfin/cache-lock.txt for how to
+	lock the cache.
+
+	Locking the cache is optional feature.
+
+	- Miscellaneous cache functions.
+
+		flush_cache_all();
+		flush_cache_mm();
+		invalidate_dcache_range();
+		flush_dcache_range();
+		flush_dcache_page();
+		flush_cache_range();
+		flush_cache_page();
+		invalidate_dcache_range();
+		flush_page_to_ram();
+
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index f74affe..e65736c 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -22,14 +22,21 @@ This driver is known to work with the fo
 	* SA E200i
 	* SA E500
 
-If nodes are not already created in the /dev/cciss directory, run as root:
+Detecting drive failures:
+-------------------------
 
-# cd /dev
-# ./MAKEDEV cciss
+To get the status of logical volumes and to detect physical drive
+failures, you can use the cciss_vol_status program found here:
+http://cciss.sourceforge.net/#cciss_utils
 
 Device Naming:
 --------------
 
+If nodes are not already created in the /dev/cciss directory, run as root:
+
+# cd /dev
+# ./MAKEDEV cciss
+
 You need some entries in /dev for the cciss device.  The MAKEDEV script
 can make device nodes for you automatically.  Currently the device setup
 is as follows:
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 63c2d0c..64e9f6c 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -55,8 +55,8 @@ aic7*seq.h*
 aicasm
 aicdb.h*
 asm
-asm-offsets.*
-asm_offsets.*
+asm-offsets.h
+asm_offsets.h
 autoconf.h*
 bbootsect
 bin2c
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 5163b85..6c8d8f2 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -182,7 +182,7 @@ For example, you can do something like t
 
 	...
 
-	devres_close_group(dev, my_midlayer_something);
+	devres_close_group(dev, my_midlayer_create_something);
 	return 0;
   }
 
diff --git a/Documentation/fb/deferred_io.txt b/Documentation/fb/deferred_io.txt
new file mode 100644
index 0000000..73cf9fb
--- /dev/null
+++ b/Documentation/fb/deferred_io.txt
@@ -0,0 +1,75 @@
+Deferred IO
+-----------
+
+Deferred IO is a way to delay and repurpose IO. It uses host memory as a
+buffer and the MMU pagefault as a pretrigger for when to perform the device
+IO. The following example may be a useful explaination of how one such setup
+works:
+
+- userspace app like Xfbdev mmaps framebuffer
+- deferred IO and driver sets up nopage and page_mkwrite handlers
+- userspace app tries to write to mmaped vaddress
+- we get pagefault and reach nopage handler
+- nopage handler finds and returns physical page
+- we get page_mkwrite where we add this page to a list
+- schedule a workqueue task to be run after a delay
+- app continues writing to that page with no additional cost. this is
+  the key benefit.
+- the workqueue task comes in and mkcleans the pages on the list, then
+ completes the work associated with updating the framebuffer. this is
+  the real work talking to the device.
+- app tries to write to the address (that has now been mkcleaned)
+- get pagefault and the above sequence occurs again
+
+As can be seen from above, one benefit is roughly to allow bursty framebuffer
+writes to occur at minimum cost. Then after some time when hopefully things
+have gone quiet, we go and really update the framebuffer which would be
+a relatively more expensive operation.
+
+For some types of nonvolatile high latency displays, the desired image is
+the final image rather than the intermediate stages which is why it's okay
+to not update for each write that is occuring.
+
+It may be the case that this is useful in other scenarios as well. Paul Mundt
+has mentioned a case where it is beneficial to use the page count to decide
+whether to coalesce and issue SG DMA or to do memory bursts.
+
+Another one may be if one has a device framebuffer that is in an usual format,
+say diagonally shifting RGB, this may then be a mechanism for you to allow
+apps to pretend to have a normal framebuffer but reswizzle for the device
+framebuffer at vsync time based on the touched pagelist.
+
+How to use it: (for applications)
+---------------------------------
+No changes needed. mmap the framebuffer like normal and just use it.
+
+How to use it: (for fbdev drivers)
+----------------------------------
+The following example may be helpful.
+
+1. Setup your structure. Eg:
+
+static struct fb_deferred_io hecubafb_defio = {
+	.delay		= HZ,
+	.deferred_io	= hecubafb_dpy_deferred_io,
+};
+
+The delay is the minimum delay between when the page_mkwrite trigger occurs
+and when the deferred_io callback is called. The deferred_io callback is
+explained below.
+
+2. Setup your deferred IO callback. Eg:
+static void hecubafb_dpy_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+
+The deferred_io callback is where you would perform all your IO to the display
+device. You receive the pagelist which is the list of pages that were written
+to during the delay. You must not modify this list. This callback is called
+from a workqueue.
+
+3. Call init
+	info->fbdefio = &hecubafb_defio;
+	fb_deferred_io_init(info);
+
+4. Call cleanup
+	fb_deferred_io_cleanup(info);
diff --git a/Documentation/fb/s3fb.txt b/Documentation/fb/s3fb.txt
index 8a04c0d..2c97770 100644
--- a/Documentation/fb/s3fb.txt
+++ b/Documentation/fb/s3fb.txt
@@ -35,10 +35,12 @@ Supported Features
 	* suspend/resume support
 	* DPMS support
 
-Text mode is supported even in higher resolutions, but there is limitation
-to lower pixclocks (maximum between 50-60 MHz, depending on specific hardware).
-This limitation is not enforced by driver. Text mode supports 8bit wide fonts
-only (hardware limitation) and 16bit tall fonts (driver limitation).
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (maximum usually between 50-60 MHz, depending on specific
+hardware, i get best results from plain S3 Trio32 card - about 75 MHz). This
+limitation is not enforced by driver. Text mode supports 8bit wide fonts only
+(hardware limitation) and 16bit tall fonts (driver limitation). Text mode
+support is broken on S3 Trio64 V2/DX.
 
 There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
 packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
@@ -73,6 +75,8 @@ Known bugs
 ==========
 
 	* cursor disable in text mode doesn't work
+	* text mode broken on S3 Trio64 V2/DX
+
 
 --
 Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 19b4c96..2291ff6 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,26 @@ be removed from this file.
 
 ---------------------------
 
+What:	MXSER
+When:	December 2007
+Why:	Old mxser driver is obsoleted by the mxser_new. Give it some time yet
+	and remove it.
+Who:	Jiri Slaby <jirislaby@gmail.com>
+
+---------------------------
+
+What:	V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP
+When:	October 2007
+Why:	Broken attempt to set MPEG compression parameters. These ioctls are
+	not able to implement the wide variety of parameters that can be set
+	by hardware MPEG encoders. A new MPEG control mechanism was created
+	in kernel 2.6.18 that replaces these ioctls. See the V4L2 specification
+	(section 1.9: Extended controls) for more information on this topic.
+Who:	Hans Verkuil <hverkuil@xs4all.nl> and
+	Mauro Carvalho Chehab <mchehab@infradead.org>
+
+---------------------------
+
 What:	/sys/devices/.../power/state
 	dev->power.power_state
 	dpm_runtime_{suspend,resume)()
@@ -105,25 +125,6 @@ Who:   Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
-What:	pci_module_init(driver)
-When:	January 2007
-Why:	Is replaced by pci_register_driver(pci_driver).
-Who:	Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de>
-
----------------------------
-
-What:	Usage of invalid timevals in setitimer
-When:	March 2007
-Why:	POSIX requires to validate timevals in the setitimer call. This
-	was never done by Linux. The invalid (e.g. negative timevals) were
-	silently converted to more or less random timeouts and intervals.
-	Until the removal a per boot limited number of warnings is printed
-	and the timevals are sanitized.
-
-Who:	Thomas Gleixner <tglx@linutronix.de>
-
----------------------------
-
 What:	Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
 	(temporary transition config option provided until then)
 	The transition config option will also be removed at the same time.
@@ -134,15 +135,6 @@ Who:	Arjan van de Ven <arjan@linux.intel
 
 ---------------------------
 
-What:	mount/umount uevents
-When:	February 2007
-Why:	These events are not correct, and do not properly let userspace know
-	when a file system has been mounted or unmounted.  Userspace should
-	poll the /proc/mounts file instead to detect this properly.
-Who:	Greg Kroah-Hartman <gregkh@suse.de>
-
----------------------------
-
 What:	USB driver API moves to EXPORT_SYMBOL_GPL
 When:	February 2008
 Files:	include/linux/usb.h, drivers/usb/core/driver.c
@@ -160,7 +152,7 @@ Who:	Greg Kroah-Hartman <gregkh@suse.de>
 ---------------------------
 
 What:	Interrupt only SA_* flags
-When:	Januar 2007
+When:	September 2007
 Why:	The interrupt related SA_* flags are replaced by IRQF_* to move them
 	out of the signal namespace.
 
@@ -187,18 +179,10 @@ Who:	Jean Delvare <khali@linux-fr.org>
 
 ---------------------------
 
-What:	i2c_adapter.dev
-	i2c_adapter.list
+What:	i2c_adapter.list
 When:	July 2007
-Why:	Superfluous, given i2c_adapter.class_dev:
-	  * The "dev" was a stand-in for the physical device node that legacy
-	    drivers would not have; but now it's almost always present.  Any
-	    remaining legacy drivers must upgrade (they now trigger warnings).
-	  * The "list" duplicates class device children.
-	The delay in removing this is so upgraded lm_sensors and libsensors
-	can get deployed.  (Removal causes minor changes in the sysfs layout,
-	notably the location of the adapter type name and parenting the i2c
-	client hardware directly from their controller.)
+Why:	Superfluous, this list duplicates the one maintained by the driver
+	core.
 Who:	Jean Delvare <khali@linux-fr.org>,
 	David Brownell <dbrownell@users.sourceforge.net>
 
@@ -211,15 +195,6 @@ Who:   Adrian Bunk <bunk@stusta.de>
 
 ---------------------------
 
-What:	IPv4 only connection tracking/NAT/helpers
-When:	2.6.22
-Why:	The new layer 3 independant connection tracking replaces the old
-	IPv4 only version. After some stabilization of the new code the
-	old one will be removed.
-Who:	Patrick McHardy <kaber@trash.net>
-
----------------------------
-
 What:	ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver
 When:	December 2006
 Why:	Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are
@@ -294,18 +269,6 @@ Who:	Richard Purdie <rpurdie@rpsys.net>
 
 ---------------------------
 
-What:	Wireless extensions over netlink (CONFIG_NET_WIRELESS_RTNETLINK)
-When:	with the merge of wireless-dev, 2.6.22 or later
-Why:	The option/code is
-	 * not enabled on most kernels
-	 * not required by any userspace tools (except an experimental one,
-	   and even there only for some parts, others use ioctl)
-	 * pointless since wext is no longer evolving and the ioctl
-	   interface needs to be kept
-Who:	Johannes Berg <johannes@sipsolutions.net>
-
----------------------------
-
 What:	i8xx_tco watchdog driver
 When:	in 2.6.22
 Why:	the i8xx_tco watchdog driver has been replaced by the iTCO_wdt
@@ -313,3 +276,54 @@ Why:	the i8xx_tco watchdog driver has be
 Who:	Wim Van Sebroeck <wim@iguana.be>
 
 ---------------------------
+
+What:	Multipath cached routing support in ipv4
+When:	in 2.6.23
+Why:	Code was merged, then submitter immediately disappeared leaving
+	us with no maintainer and lots of bugs.  The code should not have
+	been merged in the first place, and many aspects of it's
+	implementation are blocking more critical core networking
+	development.  It's marked EXPERIMENTAL and no distribution
+	enables it because it cause obscure crashes due to unfixable bugs
+	(interfaces don't return errors so memory allocation can't be
+	handled, calling contexts of these interfaces make handling
+	errors impossible too because they get called after we've
+	totally commited to creating a route object, for example).
+	This problem has existed for years and no forward progress
+	has ever been made, and nobody steps up to try and salvage
+	this code, so we're going to finally just get rid of it.
+Who:	David S. Miller <davem@davemloft.net>
+
+---------------------------
+
+What:	read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer)
+When:	December 2007
+Why:	These functions are a leftover from 2.4 times. They have several
+	problems:
+	- Duplication of checks that are done in the device driver's
+	  interrupt handler
+	- common I/O layer can't do device specific error recovery
+	- device driver can't be notified for conditions happening during
+	  execution of the function
+	Device drivers should issue the read device characteristics and read
+	configuration data ccws and do the appropriate error handling
+	themselves.
+Who:	Cornelia Huck <cornelia.huck@de.ibm.com>
+
+---------------------------
+
+What:	i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
+When:	September 2007
+Why:	Obsolete. The new i2c-gpio driver replaces all hardware-specific
+	I2C-over-GPIO drivers.
+Who:	Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What:  drivers depending on OSS_OBSOLETE
+When:  options in 2.6.23, code in 2.6.25
+Why:   obsolete OSS drivers
+Who:   Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 28bfea7..59c1415 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -15,6 +15,7 @@ prototypes:
 	int (*d_delete)(struct dentry *);
 	void (*d_release)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
+	char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
 
 locking rules:
 	none have BKL
@@ -25,6 +26,7 @@ d_compare:	no		yes		no		no 
 d_delete:	yes		no		yes		no
 d_release:	no		no		no		yes
 d_iput:		no		no		no		yes
+d_dname:	no		no		no		no
 
 --------------------------- inode_operations --------------------------- 
 prototypes:
diff --git a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt
index 2f4237d..12ad6c7 100644
--- a/Documentation/filesystems/afs.txt
+++ b/Documentation/filesystems/afs.txt
@@ -1,31 +1,82 @@
+			     ====================
 			     kAFS: AFS FILESYSTEM
 			     ====================
 
-ABOUT
-=====
+Contents:
+
+ - Overview.
+ - Usage.
+ - Mountpoints.
+ - Proc filesystem.
+ - The cell database.
+ - Security.
+ - Examples.
+
+
+========
+OVERVIEW
+========
 
-This filesystem provides a fairly simple AFS filesystem driver. It is under
-development and only provides very basic facilities. It does not yet support
-the following AFS features:
+This filesystem provides a fairly simple secure AFS filesystem driver. It is
+under development and does not yet provide the full feature set.  The features
+it does support include:
 
-	(*) Write support.
-	(*) Communications security.
-	(*) Local caching.
-	(*) pioctl() system call.
-	(*) Automatic mounting of embedded mountpoints.
+ (*) Security (currently only AFS kaserver and KerberosIV tickets).
 
+ (*) File reading.
 
+ (*) Automounting.
+
+It does not yet support the following AFS features:
+
+ (*) Write support.
+
+ (*) Local caching.
+
+ (*) pioctl() system call.
+
+
+===========
+COMPILATION
+===========
+
+The filesystem should be enabled by turning on the kernel configuration
+options:
+
+	CONFIG_AF_RXRPC		- The RxRPC protocol transport
+	CONFIG_RXKAD		- The RxRPC Kerberos security handler
+	CONFIG_AFS		- The AFS filesystem
+
+Additionally, the following can be turned on to aid debugging:
+
+	CONFIG_AF_RXRPC_DEBUG	- Permit AF_RXRPC debugging to be enabled
+	CONFIG_AFS_DEBUG	- Permit AFS debugging to be enabled
+
+They permit the debugging messages to be turned on dynamically by manipulating
+the masks in the following files:
+
+	/sys/module/af_rxrpc/parameters/debug
+	/sys/module/afs/parameters/debug
+
+
+=====
 USAGE
 =====
 
 When inserting the driver modules the root cell must be specified along with a
 list of volume location server IP addresses:
 
-	insmod rxrpc.o
+	insmod af_rxrpc.o
+	insmod rxkad.o
 	insmod kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91
 
-The first module is a driver for the RxRPC remote operation protocol, and the
-second is the actual filesystem driver for the AFS filesystem.
+The first module is the AF_RXRPC network protocol driver.  This provides the
+RxRPC remote operation protocol and may also be accessed from userspace.  See:
+
+	Documentation/networking/rxrpc.txt
+
+The second module is the kerberos RxRPC security driver, and the third module
+is the actual filesystem driver for the AFS filesystem.
 
 Once the module has been loaded, more modules can be added by the following
 procedure:
@@ -33,7 +84,7 @@ procedure:
 	echo add grand.central.org 18.7.14.88:128.2.191.224 >/proc/fs/afs/cells
 
 Where the parameters to the "add" command are the name of a cell and a list of
-volume location servers within that cell.
+volume location servers within that cell, with the latter separated by colons.
 
 Filesystems can be mounted anywhere by commands similar to the following:
 
@@ -42,11 +93,6 @@ Filesystems can be mounted anywhere by c
 	mount -t afs "#root.afs." /afs
 	mount -t afs "#root.cell." /afs/cambridge
 
-  NB: When using this on Linux 2.4, the mount command has to be different,
-      since the filesystem doesn't have access to the device name argument:
-
-	mount -t afs none /afs -ovol="#root.afs."
-
 Where the initial character is either a hash or a percent symbol depending on
 whether you definitely want a R/W volume (hash) or whether you'd prefer a R/O
 volume, but are willing to use a R/W volume instead (percent).
@@ -60,55 +106,66 @@ named volume will be looked up in the ce
 Additional cells can be added through /proc (see later section).
 
 
+===========
 MOUNTPOINTS
 ===========
 
-AFS has a concept of mountpoints. These are specially formatted symbolic links
-(of the same form as the "device name" passed to mount). kAFS presents these
-to the user as directories that have special properties:
+AFS has a concept of mountpoints. In AFS terms, these are specially formatted
+symbolic links (of the same form as the "device name" passed to mount).  kAFS
+presents these to the user as directories that have a follow-link capability
+(ie: symbolic link semantics).  If anyone attempts to access them, they will
+automatically cause the target volume to be mounted (if possible) on that site.
 
-  (*) They cannot be listed. Running a program like "ls" on them will incur an
-      EREMOTE error (Object is remote).
+Automatically mounted filesystems will be automatically unmounted approximately
+twenty minutes after they were last used.  Alternatively they can be unmounted
+directly with the umount() system call.
 
-  (*) Other objects can't be looked up inside of them. This also incurs an
-      EREMOTE error.
+Manually unmounting an AFS volume will cause any idle submounts upon it to be
+culled first.  If all are culled, then the requested volume will also be
+unmounted, otherwise error EBUSY will be returned.
 
-  (*) They can be queried with the readlink() system call, which will return
-      the name of the mountpoint to which they point. The "readlink" program
-      will also work.
+This can be used by the administrator to attempt to unmount the whole AFS tree
+mounted on /afs in one go by doing:
 
-  (*) They can be mounted on (which symbolic links can't).
+	umount /afs
 
 
+===============
 PROC FILESYSTEM
 ===============
 
-The rxrpc module creates a number of files in various places in the /proc
-filesystem:
-
-  (*) Firstly, some information files are made available in a directory called
-      "/proc/net/rxrpc/". These list the extant transport endpoint, peer,
-      connection and call records.
-
-  (*) Secondly, some control files are made available in a directory called
-      "/proc/sys/rxrpc/". Currently, all these files can be used for is to
-      turn on various levels of tracing.
-
 The AFS modules creates a "/proc/fs/afs/" directory and populates it:
 
-  (*) A "cells" file that lists cells currently known to the afs module.
+  (*) A "cells" file that lists cells currently known to the afs module and
+      their usage counts:
+
+	[root@andromeda ~]# cat /proc/fs/afs/cells
+	USE NAME
+	  3 cambridge.redhat.com
 
   (*) A directory per cell that contains files that list volume location
       servers, volumes, and active servers known within that cell.
 
+	[root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/servers
+	USE ADDR            STATE
+	  4 172.16.18.91        0
+	[root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/vlservers
+	ADDRESS
+	172.16.18.91
+	[root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/volumes
+	USE STT VLID[0]  VLID[1]  VLID[2]  NAME
+	  1 Val 20000000 20000001 20000002 root.afs
 
+
+=================
 THE CELL DATABASE
 =================
 
-The filesystem maintains an internal database of all the cells it knows and
-the IP addresses of the volume location servers for those cells. The cell to
-which the computer belongs is added to the database when insmod is performed
-by the "rootcell=" argument.
+The filesystem maintains an internal database of all the cells it knows and the
+IP addresses of the volume location servers for those cells.  The cell to which
+the system belongs is added to the database when insmod is performed by the
+"rootcell=" argument or, if compiled in, using a "kafs.rootcell=" argument on
+the kernel command line.
 
 Further cells can be added by commands similar to the following:
 
@@ -118,20 +175,65 @@ Further cells can be added by commands s
 No other cell database operations are available at this time.
 
 
+========
+SECURITY
+========
+
+Secure operations are initiated by acquiring a key using the klog program.  A
+very primitive klog program is available at:
+
+	http://people.redhat.com/~dhowells/rxrpc/klog.c
+
+This should be compiled by:
+
+	make klog LDLIBS="-lcrypto -lcrypt -lkrb4 -lkeyutils"
+
+And then run as:
+
+	./klog
+
+Assuming it's successful, this adds a key of type RxRPC, named for the service
+and cell, eg: "afs@<cellname>".  This can be viewed with the keyctl program or
+by cat'ing /proc/keys:
+
+	[root@andromeda ~]# keyctl show
+	Session Keyring
+	       -3 --alswrv      0     0  keyring: _ses.3268
+		2 --alswrv      0     0   \_ keyring: _uid.0
+	111416553 --als--v      0     0   \_ rxrpc: afs@CAMBRIDGE.REDHAT.COM
+
+Currently the username, realm, password and proposed ticket lifetime are
+compiled in to the program.
+
+It is not required to acquire a key before using AFS facilities, but if one is
+not acquired then all operations will be governed by the anonymous user parts
+of the ACLs.
+
+If a key is acquired, then all AFS operations, including mounts and automounts,
+made by a possessor of that key will be secured with that key.
+
+If a file is opened with a particular key and then the file descriptor is
+passed to a process that doesn't have that key (perhaps over an AF_UNIX
+socket), then the operations on the file will be made with key that was used to
+open the file.
+
+
+========
 EXAMPLES
 ========
 
-Here's what I use to test this. Some of the names and IP addresses are local
-to my internal DNS. My "root.afs" partition has a mount point within it for
+Here's what I use to test this.  Some of the names and IP addresses are local
+to my internal DNS.  My "root.afs" partition has a mount point within it for
 some public volumes volumes.
 
-insmod -S /tmp/rxrpc.o 
-insmod -S /tmp/kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91
+insmod /tmp/rxrpc.o
+insmod /tmp/rxkad.o
+insmod /tmp/kafs.o rootcell=cambridge.redhat.com:172.16.18.91
 
 mount -t afs \%root.afs. /afs
 mount -t afs \%cambridge.redhat.com:root.cell. /afs/cambridge.redhat.com/
 
-echo add grand.central.org 18.7.14.88:128.2.191.224 > /proc/fs/afs/cells 
+echo add grand.central.org 18.7.14.88:128.2.191.224 > /proc/fs/afs/cells
 mount -t afs "#grand.central.org:root.cell." /afs/grand.central.org/
 mount -t afs "#grand.central.org:root.archive." /afs/grand.central.org/archive
 mount -t afs "#grand.central.org:root.contrib." /afs/grand.central.org/contrib
@@ -141,15 +243,7 @@ mount -t afs "#grand.central.org:root.se
 mount -t afs "#grand.central.org:root.software." /afs/grand.central.org/software
 mount -t afs "#grand.central.org:root.user." /afs/grand.central.org/user
 
-umount /afs/grand.central.org/user
-umount /afs/grand.central.org/software
-umount /afs/grand.central.org/service
-umount /afs/grand.central.org/project
-umount /afs/grand.central.org/doc
-umount /afs/grand.central.org/contrib
-umount /afs/grand.central.org/archive
-umount /afs/grand.central.org
-umount /afs/cambridge.redhat.com
 umount /afs
 rmmod kafs
+rmmod rxkad
 rmmod rxrpc
diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
index bae1286..26ebde7 100644
--- a/Documentation/filesystems/jfs.txt
+++ b/Documentation/filesystems/jfs.txt
@@ -29,7 +29,13 @@ errors=continue		Keep going on a filesys
 errors=remount-ro	Default. Remount the filesystem read-only on an error.
 errors=panic		Panic and halt the machine if an error occurs.
 
-Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
+uid=value	Override on-disk uid with specified value
+gid=value	Override on-disk gid with specified value
+umask=value	Override on-disk umask with specified octal value.  For
+		directories, the execute bit will be set if the corresponding
+		read bit is set.
+
+Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com.
 
 The JFS mailing list can be subscribed to by using the link labeled
 "Mail list Subscribe" at our web page http://jfs.sourceforge.net/
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 5484ab5..4f3e84c 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -122,21 +122,22 @@ subdirectory has the entries listed in T
 
 Table 1-1: Process specific entries in /proc 
 ..............................................................................
- File    Content                                        
- cmdline Command line arguments                         
- cpu	 Current and last cpu in which it was executed		(2.4)(smp)
- cwd	 Link to the current working directory
- environ Values of environment variables      
- exe	 Link to the executable of this process
- fd      Directory, which contains all file descriptors 
- maps	 Memory maps to executables and library files		(2.4)
- mem     Memory held by this process                    
- root	 Link to the root directory of this process
- stat    Process status                                 
- statm   Process memory status information              
- status  Process status in human readable form          
- wchan   If CONFIG_KALLSYMS is set, a pre-decoded wchan
- smaps	 Extension based on maps, presenting the rss size for each mapped file
+ File		Content
+ clear_refs	Clears page referenced bits shown in smaps output
+ cmdline	Command line arguments
+ cpu		Current and last cpu in which it was executed	(2.4)(smp)
+ cwd		Link to the current working directory
+ environ	Values of environment variables
+ exe		Link to the executable of this process
+ fd		Directory, which contains all file descriptors
+ maps		Memory maps to executables and library files	(2.4)
+ mem		Memory held by this process
+ root		Link to the root directory of this process
+ stat		Process status
+ statm		Process memory status information
+ status		Process status in human readable form
+ wchan		If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ smaps		Extension based on maps, the rss size for each mapped file
 ..............................................................................
 
 For example, to get the status information of a process, all you have to do is
@@ -1137,6 +1138,13 @@ determine whether or not they are still 
 Because the NMI watchdog shares registers with oprofile, by disabling the NMI
 watchdog, oprofile may have more registers to utilize.
 
+maps_protect
+------------
+
+Enables/Disables the protection of the per-process proc entries "maps" and
+"smaps".  When enabled, the contents of these files are visible only to
+readers that are allowed to ptrace() the given process.
+
 
 2.4 /proc/sys/vm - The virtual memory subsystem
 -----------------------------------------------
@@ -1421,6 +1429,15 @@ fewer messages that will be written. Mes
 be dropped.  The  default  settings  limit  warning messages to one every five
 seconds.
 
+warnings
+--------
+
+This controls console messages from the networking stack that can occur because
+of problems on the network like duplicate address or bad checksums. Normally,
+this should be enabled, but if the problem persists the messages can be
+disabled.
+
+
 netdev_max_backlog
 ------------------
 
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index 069cb10..fcc123f 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -57,6 +57,13 @@ nonumtail=<bool> -- When creating 8.3 al
                  currently exist in the directory, 'longfile.txt' will
                  be the short alias instead of 'longfi~1.txt'. 
                   
+usefree       -- Use the "free clusters" value stored on FSINFO. It'll
+                 be used to determine number of free clusters without
+                 scanning disk. But it's not used by default, because
+                 recent Windows don't update it correctly in some
+                 case. If you are sure the "free clusters" on FSINFO is
+                 correct, by this option you can avoid scanning disk.
+
 quiet         -- Stops printing certain warning messages.
 
 check=s|r|n   -- Case sensitivity checking setting.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index ea271f2..a47cc81 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -827,7 +827,7 @@ This describes how a filesystem can over
 operations. Dentries and the dcache are the domain of the VFS and the
 individual filesystem implementations. Device drivers have no business
 here. These methods may be set to NULL, as they are either optional or
-the VFS uses a default. As of kernel 2.6.13, the following members are
+the VFS uses a default. As of kernel 2.6.22, the following members are
 defined:
 
 struct dentry_operations {
@@ -837,6 +837,7 @@ struct dentry_operations {
 	int (*d_delete)(struct dentry *);
 	void (*d_release)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
+	char *(*d_dname)(struct dentry *, char *, int);
 };
 
   d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -859,6 +860,26 @@ struct dentry_operations {
 	VFS calls iput(). If you define this method, you must call
 	iput() yourself
 
+  d_dname: called when the pathname of a dentry should be generated.
+	Usefull for some pseudo filesystems (sockfs, pipefs, ...) to delay
+	pathname generation. (Instead of doing it when dentry is created,
+	its done only when the path is needed.). Real filesystems probably
+	dont want to use it, because their dentries are present in global
+	dcache hash, so their hash should be an invariant. As no lock is
+	held, d_dname() should not try to modify the dentry itself, unless
+	appropriate SMP safety is used. CAUTION : d_path() logic is quite
+	tricky. The correct way to return for example "Hello" is to put it
+	at the end of the buffer, and returns a pointer to the first char.
+	dynamic_dname() helper function is provided to take care of this.
+
+Example :
+
+static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
+{
+	return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+				dentry->d_inode->i_ino);
+}
+
 Each dentry has a pointer to its parent dentry, as well as a hash list
 of child dentries. Child dentries are basically like files in a
 directory.
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
new file mode 100644
index 0000000..870cda9
--- /dev/null
+++ b/Documentation/hwmon/coretemp
@@ -0,0 +1,36 @@
+Kernel driver coretemp
+======================
+
+Supported chips:
+  * All Intel Core family
+    Prefix: 'coretemp'
+    CPUID: family 0x6, models 0xe, 0xf
+    Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
+               Volume 3A: System Programming Guide
+
+Author: Rudolf Marek
+
+Description
+-----------
+
+This driver permits reading temperature sensor embedded inside Intel Core CPU.
+Temperature is measured in degrees Celsius and measurement resolution is
+1 degree C. Valid temperatures are from 0 to TjMax degrees C, because
+the actual value of temperature register is in fact a delta from TjMax.
+
+Temperature known as TjMax is the maximum junction temperature of processor.
+Intel defines this temperature as 85C or 100C. At this temperature, protection
+mechanism will perform actions to forcibly cool down the processor. Alarm
+may be raised, if the temperature grows enough (more than TjMax) to trigger
+the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
+
+temp1_input	 - Core temperature (in millidegrees Celsius).
+temp1_crit	 - Maximum junction temperature  (in millidegrees Celsius).
+temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
+		   Correct CPU operation is no longer guaranteed.
+temp1_label	 - Contains string "Core X", where X is processor
+		   number.
+
+The TjMax temperature is set to 85 degrees C if undocumented model specific
+register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
+(sometimes) documented in processor datasheet.
diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650
new file mode 100644
index 0000000..8be7beb
--- /dev/null
+++ b/Documentation/hwmon/max6650
@@ -0,0 +1,53 @@
+Kernel driver max6650
+=====================
+
+Supported chips:
+  * Maxim 6650 / 6651
+    Prefix: 'max6650'
+    Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b
+    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+
+Authors:
+    Hans J. Koch <hjk@linutronix.de>
+    John Morris <john.morris@spirentcom.com>
+    Claus Gindhart <claus.gindhart@kontron.com>
+
+Description
+-----------
+
+This driver implements support for the Maxim 6650/6651
+
+The 2 devices are very similar, but the Maxim 6550 has a reduced feature
+set, e.g. only one fan-input, instead of 4 for the 6651.
+
+The driver is not able to distinguish between the 2 devices.
+
+The driver provides the following sensor accesses in sysfs:
+
+fan1_input	ro	fan tachometer speed in RPM
+fan2_input	ro	"
+fan3_input	ro	"
+fan4_input	ro	"
+fan1_target	rw	desired fan speed in RPM (closed loop mode only)
+pwm1_enable	rw	regulator mode, 0=full on, 1=open loop, 2=closed loop
+pwm1		rw	relative speed (0-255), 255=max. speed.
+			Used in open loop mode only.
+fan1_div	rw	sets the speed range the inputs can handle. Legal
+			values are 1, 2, 4, and 8. Use lower values for
+			faster fans.
+
+Module parameters
+-----------------
+
+If your board has a BIOS that initializes the MAX6650/6651 correctly, you can
+simply load your module without parameters. It won't touch the configuration
+registers then. If your board BIOS doesn't initialize the chip, or you want
+different settings, you can set the following parameters:
+
+voltage_12V: 5=5V fan, 12=12V fan, 0=don't change
+prescaler: Possible values are 1,2,4,8,16, or 0 for don't change
+clock: The clock frequency in Hz of the chip the driver should assume [254000]
+
+Please have a look at the MAX6650/6651 data sheet and make sure that you fully
+understand the meaning of these parameters before you attempt to change them.
+
diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1
index 04a1112..42c8431 100644
--- a/Documentation/hwmon/smsc47m1
+++ b/Documentation/hwmon/smsc47m1
@@ -14,6 +14,10 @@ Supported chips:
         http://www.smsc.com/main/datasheets/47m14x.pdf
         http://www.smsc.com/main/tools/discontinued/47m15x.pdf
         http://www.smsc.com/main/datasheets/47m192.pdf
+  * SMSC LPC47M292
+    Addresses scanned: none, address read from Super I/O config space
+    Prefix: 'smsc47m2'
+    Datasheet: Not public
   * SMSC LPC47M997
     Addresses scanned: none, address read from Super I/O config space
     Prefix: 'smsc47m1'
@@ -32,9 +36,10 @@ Description
 The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips
 contain monitoring and PWM control circuitry for two fans.
 
-The 47M15x and 47M192 chips contain a full 'hardware monitoring block'
-in addition to the fan monitoring and control. The hardware monitoring
-block is not supported by the driver.
+The LPC47M15x, LPC47M192 and LPC47M292 chips contain a full 'hardware
+monitoring block' in addition to the fan monitoring and control. The
+hardware monitoring block is not supported by this driver, use the
+smsc47m192 driver for that.
 
 No documentation is available for the 47M997, but it has the same device
 ID as the 47M15x and 47M192 chips and seems to be compatible.
diff --git a/Documentation/hwmon/smsc47m192 b/Documentation/hwmon/smsc47m192
index 45d6453..6d54ecb 100644
--- a/Documentation/hwmon/smsc47m192
+++ b/Documentation/hwmon/smsc47m192
@@ -2,12 +2,13 @@ Kernel driver smsc47m192
 ========================
 
 Supported chips:
-  * SMSC LPC47M192 and LPC47M997
+  * SMSC LPC47M192, LPC47M15x, LPC47M292 and LPC47M997
     Prefix: 'smsc47m192'
     Addresses scanned: I2C 0x2c - 0x2d
     Datasheet: The datasheet for LPC47M192 is publicly available from
                http://www.smsc.com/
-               The LPC47M997 is compatible for hardware monitoring.
+               The LPC47M15x, LPC47M292 and LPC47M997 are compatible for
+               hardware monitoring.
 
 Author: Hartmut Rick <linux@rick.claranet.de>
         Special thanks to Jean Delvare for careful checking
@@ -18,7 +19,7 @@ Description
 -----------
 
 This driver implements support for the hardware sensor capabilities
-of the SMSC LPC47M192 and LPC47M997 Super-I/O chips.
+of the SMSC LPC47M192 and compatible Super-I/O chips.
 
 These chips support 3 temperature channels and 8 voltage inputs
 as well as CPU voltage VID input.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index d73d2e8..a9a18ad 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -152,6 +152,13 @@ fan[1-*]_div	Fan divisor.
 		Note that this is actually an internal clock divisor, which
 		affects the measurable speed range, not the read value.
 
+fan[1-*]_target
+		Desired fan speed
+		Unit: revolution/min (RPM)
+		RW
+		Only makes sense if the chip supports closed-loop fan speed
+		control based on the measured fan speed.
+
 Also see the Alarms section for status flags associated with fans.
 
 
diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
index 7f61fbc..fae3495 100644
--- a/Documentation/i2c/busses/i2c-nforce2
+++ b/Documentation/i2c/busses/i2c-nforce2
@@ -9,6 +9,8 @@ Supported adapters:
   * nForce4 MCP-04             10de:0034
   * nForce4 MCP51              10de:0264
   * nForce4 MCP55              10de:0368
+  * nForce4 MCP61              10de:03EB
+  * nForce4 MCP65              10de:0446
 
 Datasheet: not publicly available, but seems to be similar to the
            AMD-8111 SMBus 2.0 adapter.
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients
index ca272b2..7bf82c0 100644
--- a/Documentation/i2c/porting-clients
+++ b/Documentation/i2c/porting-clients
@@ -1,4 +1,4 @@
-Revision 6, 2005-11-20
+Revision 7, 2007-04-19
 Jean Delvare <khali@linux-fr.org>
 Greg KH <greg@kroah.com>
 
@@ -20,6 +20,10 @@ yours for best results.
 
 Technical changes:
 
+* [Driver type] Any driver that was relying on i2c-isa has to be
+  converted to a proper isa, platform or pci driver. This is not
+  covered by this guide.
+
 * [Includes] Get rid of "version.h" and <linux/i2c-proc.h>.
   Includes typically look like that:
   #include <linux/module.h>
@@ -27,12 +31,10 @@ Technical changes:
   #include <linux/slab.h>
   #include <linux/jiffies.h>
   #include <linux/i2c.h>
-  #include <linux/i2c-isa.h>	/* for ISA drivers */
   #include <linux/hwmon.h>	/* for hardware monitoring drivers */
   #include <linux/hwmon-sysfs.h>
   #include <linux/hwmon-vid.h>	/* if you need VRM support */
   #include <linux/err.h>	/* for class registration */
-  #include <asm/io.h>		/* if you have I/O operations */
   Please respect this inclusion order. Some extra headers may be
   required for a given driver (e.g. "lm75.h").
 
@@ -69,20 +71,16 @@ Technical changes:
   sensors mailing list <lm-sensors@lm-sensors.org> by providing a
   patch to the Documentation/hwmon/sysfs-interface file.
 
-* [Attach] For I2C drivers, the attach function should make sure
-  that the adapter's class has I2C_CLASS_HWMON (or whatever class is
-  suitable for your driver), using the following construct:
+* [Attach] The attach function should make sure that the adapter's
+  class has I2C_CLASS_HWMON (or whatever class is suitable for your
+  driver), using the following construct:
   if (!(adapter->class & I2C_CLASS_HWMON))
           return 0;
-  ISA-only drivers of course don't need this.
   Call i2c_probe() instead of i2c_detect().
 
 * [Detect] As mentioned earlier, the flags parameter is gone.
   The type_name and client_name strings are replaced by a single
   name string, which will be filled with a lowercase, short string.
-  In i2c-only drivers, drop the i2c_is_isa_adapter check, it's
-  useless. Same for isa-only drivers, as the test would always be
-  true. Only hybrid drivers (which are quite rare) still need it.
   The labels used for error paths are reduced to the number needed.
   It is advised that the labels are given descriptive names such as
   exit and exit_free. Don't forget to properly set err before
diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary
index 41dde87..aea60bf 100644
--- a/Documentation/i2c/summary
+++ b/Documentation/i2c/summary
@@ -4,17 +4,23 @@ I2C and SMBus
 =============
 
 I2C (pronounce: I squared C) is a protocol developed by Philips. It is a 
-slow two-wire protocol (10-400 kHz), but it suffices for many types of 
-devices.
+slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
+extension (3.4 MHz).  It provides an inexpensive bus for connecting many
+types of devices with infrequent or low bandwidth communications needs.
+I2C is widely used with embedded systems.  Some systems use variants that
+don't meet branding requirements, and so are not advertised as being I2C.
 
-SMBus (System Management Bus) is a subset of the I2C protocol. Many
-modern mainboards have a System Management Bus. There are a lot of 
-devices which can be connected to a SMBus; the most notable are modern 
-memory chips with EEPROM memories and chips for hardware monitoring.
+SMBus (System Management Bus) is based on the I2C protocol, and is mostly
+a subset of I2C protocols and signaling.  Many I2C devices will work on an
+SMBus, but some SMBus protocols add semantics beyond what is required to
+achieve I2C branding.  Modern PC mainboards rely on SMBus.  The most common
+devices connected through SMBus are RAM modules configured using I2C EEPROMs,
+and hardware monitoring chips.
 
-Because the SMBus is just a special case of the generalized I2C bus, we
-can simulate the SMBus protocol on plain I2C busses. The reverse is
-regretfully impossible.
+Because the SMBus is mostly a subset of the generalized I2C bus, we can
+use its protocols on many I2C systems.  However, there are systems that don't
+meet both SMBus and I2C electrical constraints; and others which can't
+implement all the common SMBus protocol semantics or messages.
 
 
 Terminology
@@ -29,6 +35,7 @@ When we talk about I2C, we use the follo
 An Algorithm driver contains general code that can be used for a whole class
 of I2C adapters. Each specific adapter driver depends on one algorithm
 driver.
+
 A Driver driver (yes, this sounds ridiculous, sorry) contains the general
 code to access some type of device. Each detected device gets its own
 data in the Client structure. Usually, Driver and Client are more closely
@@ -40,6 +47,10 @@ (usually one driver for each device). Th
 in this package. See the lm_sensors project http://www.lm-sensors.nu
 for device drivers.
 
+At this time, Linux only operates I2C (or SMBus) in master mode; you can't
+use these APIs to make a Linux system behave as a slave/device, either to
+speak a custom protocol or to emulate some other device.
+
 
 Included Bus Drivers
 ====================
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index fbcff96..3d8d36b 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -1,5 +1,5 @@
 This is a small guide for those who want to write kernel drivers for I2C
-or SMBus devices.
+or SMBus devices, using Linux as the protocol host/master (not slave).
 
 To set up a driver, you need to do several things. Some are optional, and
 some things can be done slightly or completely different. Use this as a
@@ -29,8 +29,16 @@ static struct i2c_driver foo_driver = {
 	.driver = {
 		.name	= "foo",
 	},
+
+	/* iff driver uses driver model ("new style") binding model: */
+	.probe		= foo_probe,
+	.remove		= foo_remove,
+
+	/* else, driver uses "legacy" binding model: */
 	.attach_adapter	= foo_attach_adapter,
 	.detach_client	= foo_detach_client,
+
+	/* these may be used regardless of the driver binding model */
 	.shutdown	= foo_shutdown,	/* optional */
 	.suspend	= foo_suspend,	/* optional */
 	.resume		= foo_resume,	/* optional */
@@ -40,7 +48,8 @@ static struct i2c_driver foo_driver = {
 The name field is the driver name, and must not contain spaces.  It
 should match the module name (if the driver can be compiled as a module),
 although you can use MODULE_ALIAS (passing "foo" in this example) to add
-another name for the module.
+another name for the module.  If the driver name doesn't match the module
+name, the module won't be automatically loaded (hotplug/coldplug).
 
 All other fields are for call-back functions which will be explained 
 below.
@@ -65,16 +74,13 @@ An example structure is below.
 
   struct foo_data {
     struct i2c_client client;
-    struct semaphore lock; /* For ISA access in `sensors' drivers. */
-    int sysctl_id;         /* To keep the /proc directory entry for 
-                              `sensors' drivers. */
     enum chips type;       /* To keep the chips type for `sensors' drivers. */
    
     /* Because the i2c bus is slow, it is often useful to cache the read
        information of a chip for some time (for example, 1 or 2 seconds).
        It depends of course on the device whether this is really worthwhile
        or even sensible. */
-    struct semaphore update_lock; /* When we are reading lots of information,
+    struct mutex update_lock;     /* When we are reading lots of information,
                                      another process should not update the
                                      below information */
     char valid;                   /* != 0 if the following fields are valid. */
@@ -95,8 +101,7 @@ some obscure clients). But we need gener
 I have found it useful to define foo_read and foo_write function for this.
 For some cases, it will be easier to call the i2c functions directly,
 but many chips have some kind of register-value idea that can easily
-be encapsulated. Also, some chips have both ISA and I2C interfaces, and
-it useful to abstract from this (only for `sensors' drivers).
+be encapsulated.
 
 The below functions are simple examples, and should not be copied
 literally.
@@ -119,28 +124,101 @@ literally.
       return i2c_smbus_write_word_data(client,reg,value);
   }
 
-For sensors code, you may have to cope with ISA registers too. Something
-like the below often works. Note the locking! 
-
-  int foo_read_value(struct i2c_client *client, u8 reg)
-  {
-    int res;
-    if (i2c_is_isa_client(client)) {
-      down(&(((struct foo_data *) (client->data)) -> lock));
-      outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET);
-      res = inb_p(client->addr + FOO_DATA_REG_OFFSET);
-      up(&(((struct foo_data *) (client->data)) -> lock));
-      return res;
-    } else
-      return i2c_smbus_read_byte_data(client,reg);
-  }
-
-Writing is done the same way.
-
 
 Probing and attaching
 =====================
 
+The Linux I2C stack was originally written to support access to hardware
+monitoring chips on PC motherboards, and thus it embeds some assumptions
+that are more appropriate to SMBus (and PCs) than to I2C.  One of these
+assumptions is that most adapters and devices drivers support the SMBUS_QUICK
+protocol to probe device presence.  Another is that devices and their drivers
+can be sufficiently configured using only such probe primitives.
+
+As Linux and its I2C stack became more widely used in embedded systems
+and complex components such as DVB adapters, those assumptions became more
+problematic.  Drivers for I2C devices that issue interrupts need more (and
+different) configuration information, as do drivers handling chip variants
+that can't be distinguished by protocol probing, or which need some board
+specific information to operate correctly.
+
+Accordingly, the I2C stack now has two models for associating I2C devices
+with their drivers:  the original "legacy" model, and a newer one that's
+fully compatible with the Linux 2.6 driver model.  These models do not mix,
+since the "legacy" model requires drivers to create "i2c_client" device
+objects after SMBus style probing, while the Linux driver model expects
+drivers to be given such device objects in their probe() routines.
+
+
+Standard Driver Model Binding ("New Style")
+-------------------------------------------
+
+System infrastructure, typically board-specific initialization code or
+boot firmware, reports what I2C devices exist.  For example, there may be
+a table, in the kernel or from the boot loader, identifying I2C devices
+and linking them to board-specific configuration information about IRQs
+and other wiring artifacts, chip type, and so on.  That could be used to
+create i2c_client objects for each I2C device.
+
+I2C device drivers using this binding model work just like any other
+kind of driver in Linux:  they provide a probe() method to bind to
+those devices, and a remove() method to unbind.
+
+	static int foo_probe(struct i2c_client *client);
+	static int foo_remove(struct i2c_client *client);
+
+Remember that the i2c_driver does not create those client handles.  The
+handle may be used during foo_probe().  If foo_probe() reports success
+(zero not a negative status code) it may save the handle and use it until
+foo_remove() returns.  That binding model is used by most Linux drivers.
+
+Drivers match devices when i2c_client.driver_name and the driver name are
+the same; this approach is used in several other busses that don't have
+device typing support in the hardware.  The driver and module name should
+match, so hotplug/coldplug mechanisms will modprobe the driver.
+
+
+Device Creation (Standard driver model)
+---------------------------------------
+
+If you know for a fact that an I2C device is connected to a given I2C bus,
+you can instantiate that device by simply filling an i2c_board_info
+structure with the device address and driver name, and calling
+i2c_new_device().  This will create the device, then the driver core will
+take care of finding the right driver and will call its probe() method.
+If a driver supports different device types, you can specify the type you
+want using the type field.  You can also specify an IRQ and platform data
+if needed.
+
+Sometimes you know that a device is connected to a given I2C bus, but you
+don't know the exact address it uses.  This happens on TV adapters for
+example, where the same driver supports dozens of slightly different
+models, and I2C device addresses change from one model to the next.  In
+that case, you can use the i2c_new_probed_device() variant, which is
+similar to i2c_new_device(), except that it takes an additional list of
+possible I2C addresses to probe.  A device is created for the first
+responsive address in the list.  If you expect more than one device to be
+present in the address range, simply call i2c_new_probed_device() that
+many times.
+
+The call to i2c_new_device() or i2c_new_probed_device() typically happens
+in the I2C bus driver. You may want to save the returned i2c_client
+reference for later use.
+
+
+Device Deletion (Standard driver model)
+---------------------------------------
+
+Each I2C device which has been created using i2c_new_device() or
+i2c_new_probed_device() can be unregistered by calling
+i2c_unregister_device().  If you don't call it explicitly, it will be
+called automatically before the underlying I2C bus itself is removed, as a
+device can't survive its parent in the device driver model.
+
+
+Legacy Driver Binding Model
+---------------------------
+
 Most i2c devices can be present on several i2c addresses; for some this
 is determined in hardware (by soldering some chip pins to Vcc or Ground),
 for others this can be changed in software (by writing to specific client
@@ -157,13 +235,9 @@ detection algorithm.
 You do not have to use this parameter interface; but don't try to use
 function i2c_probe() if you don't.
 
-NOTE: If you want to write a `sensors' driver, the interface is slightly
-      different! See below.
-
 
-
-Probing classes
----------------
+Probing classes (Legacy model)
+------------------------------
 
 All parameters are given as lists of unsigned 16-bit integers. Lists are
 terminated by I2C_CLIENT_END.
@@ -210,8 +284,8 @@ Note that you *have* to call the defined
 without any prefix!
 
 
-Attaching to an adapter
------------------------
+Attaching to an adapter (Legacy model)
+--------------------------------------
 
 Whenever a new adapter is inserted, or for all adapters if the driver is
 being registered, the callback attach_adapter() is called. Now is the
@@ -237,17 +311,13 @@ them (unless a `force' parameter was use
 are already in use (by some other registered client) are skipped.
 
 
-The detect client function
---------------------------
+The detect client function (Legacy model)
+-----------------------------------------
 
 The detect client function is called by i2c_probe. The `kind' parameter
 contains -1 for a probed detection, 0 for a forced detection, or a positive
 number for a forced detection with a chip type forced.
 
-Below, some things are only needed if this is a `sensors' driver. Those
-parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
-markers. 
-
 Returning an error different from -ENODEV in a detect function will cause
 the detection to stop: other addresses and adapters won't be scanned.
 This should only be done on fatal or internal errors, such as a memory
@@ -256,64 +326,20 @@ shortage or i2c_attach_client failing.
 For now, you can ignore the `flags' parameter. It is there for future use.
 
   int foo_detect_client(struct i2c_adapter *adapter, int address, 
-                        unsigned short flags, int kind)
+                        int kind)
   {
     int err = 0;
     int i;
-    struct i2c_client *new_client;
+    struct i2c_client *client;
     struct foo_data *data;
-    const char *client_name = ""; /* For non-`sensors' drivers, put the real
-                                     name here! */
+    const char *name = "";
    
     /* Let's see whether this adapter can support what we need.
-       Please substitute the things you need here! 
-       For `sensors' drivers, add `! is_isa &&' to the if statement */
+       Please substitute the things you need here! */
     if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
                                         I2C_FUNC_SMBUS_WRITE_BYTE))
        goto ERROR0;
 
-    /* SENSORS ONLY START */
-    const char *type_name = "";
-    int is_isa = i2c_is_isa_adapter(adapter);
-
-    /* Do this only if the chip can additionally be found on the ISA bus
-       (hybrid chip). */
-
-    if (is_isa) {
-
-      /* Discard immediately if this ISA range is already used */
-      /* FIXME: never use check_region(), only request_region() */
-      if (check_region(address,FOO_EXTENT))
-        goto ERROR0;
-
-      /* Probe whether there is anything on this address.
-         Some example code is below, but you will have to adapt this
-         for your own driver */
-
-      if (kind < 0) /* Only if no force parameter was used */ {
-        /* We may need long timeouts at least for some chips. */
-        #define REALLY_SLOW_IO
-        i = inb_p(address + 1);
-        if (inb_p(address + 2) != i)
-          goto ERROR0;
-        if (inb_p(address + 3) != i)
-          goto ERROR0;
-        if (inb_p(address + 7) != i)
-          goto ERROR0;
-        #undef REALLY_SLOW_IO
-
-        /* Let's just hope nothing breaks here */
-        i = inb_p(address + 5) & 0x7f;
-        outb_p(~i & 0x7f,address+5);
-        if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
-          outb_p(i,address+5);
-          return 0;
-        }
-      }
-    }
-
-    /* SENSORS ONLY END */
-
     /* OK. For now, we presume we have a valid client. We now create the
        client structure, even though we cannot fill it completely yet.
        But it allows us to access several i2c functions safely */
@@ -323,13 +349,12 @@ For now, you can ignore the `flags' para
       goto ERROR0;
     }
 
-    new_client = &data->client;
-    i2c_set_clientdata(new_client, data);
+    client = &data->client;
+    i2c_set_clientdata(client, data);
 
-    new_client->addr = address;
-    new_client->adapter = adapter;
-    new_client->driver = &foo_driver;
-    new_client->flags = 0;
+    client->addr = address;
+    client->adapter = adapter;
+    client->driver = &foo_driver;
 
     /* Now, we do the remaining detection. If no `force' parameter is used. */
 
@@ -337,19 +362,17 @@ For now, you can ignore the `flags' para
        parameter was used. */
     if (kind < 0) {
       /* The below is of course bogus */
-      if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
+      if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
          goto ERROR1;
     }
 
-    /* SENSORS ONLY START */
-
     /* Next, specific detection. This is especially important for `sensors'
        devices. */
 
     /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter
        was used. */
     if (kind <= 0) {
-      i = foo_read(new_client,FOO_REG_CHIPTYPE);
+      i = foo_read(client, FOO_REG_CHIPTYPE);
       if (i == FOO_TYPE_1) 
         kind = chip1; /* As defined in the enum */
       else if (i == FOO_TYPE_2)
@@ -363,63 +386,31 @@ For now, you can ignore the `flags' para
 
     /* Now set the type and chip names */
     if (kind == chip1) {
-      type_name = "chip1"; /* For /proc entry */
-      client_name = "CHIP 1";
+      name = "chip1";
     } else if (kind == chip2) {
-      type_name = "chip2"; /* For /proc entry */
-      client_name = "CHIP 2";
+      name = "chip2";
     }
    
-    /* Reserve the ISA region */
-    if (is_isa)
-      request_region(address,FOO_EXTENT,type_name);
-
-    /* SENSORS ONLY END */
-
     /* Fill in the remaining client fields. */
-    strcpy(new_client->name,client_name);
-
-    /* SENSORS ONLY BEGIN */
+    strlcpy(client->name, name, I2C_NAME_SIZE);
     data->type = kind;
-    /* SENSORS ONLY END */
-
-    data->valid = 0; /* Only if you use this field */
-    init_MUTEX(&data->update_lock); /* Only if you use this field */
+    mutex_init(&data->update_lock); /* Only if you use this field */
 
     /* Any other initializations in data must be done here too. */
 
-    /* Tell the i2c layer a new client has arrived */
-    if ((err = i2c_attach_client(new_client)))
-      goto ERROR3;
-
-    /* SENSORS ONLY BEGIN */
-    /* Register a new directory entry with module sensors. See below for
-       the `template' structure. */
-    if ((i = i2c_register_entry(new_client, type_name,
-                                    foo_dir_table_template,THIS_MODULE)) < 0) {
-      err = i;
-      goto ERROR4;
-    }
-    data->sysctl_id = i;
-
-    /* SENSORS ONLY END */
-
     /* This function can write default values to the client registers, if
        needed. */
-    foo_init_client(new_client);
+    foo_init_client(client);
+
+    /* Tell the i2c layer a new client has arrived */
+    if ((err = i2c_attach_client(client)))
+      goto ERROR1;
+
     return 0;
 
     /* OK, this is not exactly good programming practice, usually. But it is
        very code-efficient in this case. */
 
-    ERROR4:
-      i2c_detach_client(new_client);
-    ERROR3:
-    ERROR2:
-    /* SENSORS ONLY START */
-      if (is_isa)
-        release_region(address,FOO_EXTENT);
-    /* SENSORS ONLY END */
     ERROR1:
       kfree(data);
     ERROR0:
@@ -427,8 +418,8 @@ For now, you can ignore the `flags' para
   }
 
 
-Removing the client
-===================
+Removing the client (Legacy model)
+==================================
 
 The detach_client call back function is called when a client should be
 removed. It may actually fail, but only when panicking. This code is
@@ -436,22 +427,12 @@ much simpler than the attachment code, f
 
   int foo_detach_client(struct i2c_client *client)
   {
-    int err,i;
-
-    /* SENSORS ONLY START */
-    /* Deregister with the `i2c-proc' module. */
-    i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
-    /* SENSORS ONLY END */
+    int err;
 
     /* Try to detach the client from i2c space */
     if ((err = i2c_detach_client(client)))
       return err;
 
-    /* HYBRID SENSORS CHIP ONLY START */
-    if i2c_is_isa_client(client)
-      release_region(client->addr,LM78_EXTENT);
-    /* HYBRID SENSORS CHIP ONLY END */
-
     kfree(i2c_get_clientdata(client));
     return 0;
   }
@@ -464,45 +445,34 @@ When the kernel is booted, or when your 
 you have to do some initializing. Fortunately, just attaching (registering)
 the driver module is usually enough.
 
-  /* Keep track of how far we got in the initialization process. If several
-     things have to initialized, and we fail halfway, only those things
-     have to be cleaned up! */
-  static int __initdata foo_initialized = 0;
-
   static int __init foo_init(void)
   {
     int res;
-    printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE);
     
     if ((res = i2c_add_driver(&foo_driver))) {
       printk("foo: Driver registration failed, module not inserted.\n");
-      foo_cleanup();
       return res;
     }
-    foo_initialized ++;
     return 0;
   }
 
-  void foo_cleanup(void)
+  static void __exit foo_cleanup(void)
   {
-    if (foo_initialized == 1) {
-      if ((res = i2c_del_driver(&foo_driver))) {
-        printk("foo: Driver registration failed, module not removed.\n");
-        return;
-      }
-      foo_initialized --;
-    }
+    i2c_del_driver(&foo_driver);
   }
 
   /* Substitute your own name and email address */
   MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
   MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
 
+  /* a few non-GPL license types are also allowed */
+  MODULE_LICENSE("GPL");
+
   module_init(foo_init);
   module_exit(foo_cleanup);
 
 Note that some functions are marked by `__init', and some data structures
-by `__init_data'.  Hose functions and structures can be removed after
+by `__initdata'.  These functions and structures can be removed after
 kernel booting (or module loading) is completed.
 
 
@@ -632,110 +602,7 @@ General purpose routines
 Below all general purpose routines are listed, that were not mentioned
 before.
 
-  /* This call returns a unique low identifier for each registered adapter,
-   * or -1 if the adapter was not registered.
+  /* This call returns a unique low identifier for each registered adapter.
    */
   extern int i2c_adapter_id(struct i2c_adapter *adap);
 
-
-The sensors sysctl/proc interface
-=================================
-
-This section only applies if you write `sensors' drivers.
-
-Each sensors driver creates a directory in /proc/sys/dev/sensors for each
-registered client. The directory is called something like foo-i2c-4-65.
-The sensors module helps you to do this as easily as possible.
-
-The template
-------------
-
-You will need to define a ctl_table template. This template will automatically
-be copied to a newly allocated structure and filled in where necessary when
-you call sensors_register_entry.
-
-First, I will give an example definition.
-  static ctl_table foo_dir_table_template[] = {
-    { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real,
-      &i2c_sysctl_real,NULL,&foo_func },
-    { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real,
-      &i2c_sysctl_real,NULL,&foo_func },
-    { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real,
-      &i2c_sysctl_real,NULL,&foo_data },
-    { 0 }
-  };
-
-In the above example, three entries are defined. They can either be
-accessed through the /proc interface, in the /proc/sys/dev/sensors/*
-directories, as files named func1, func2 and data, or alternatively 
-through the sysctl interface, in the appropriate table, with identifiers
-FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA.
-
-The third, sixth and ninth parameters should always be NULL, and the
-fourth should always be 0. The fifth is the mode of the /proc file;
-0644 is safe, as the file will be owned by root:root. 
-
-The seventh and eighth parameters should be &i2c_proc_real and
-&i2c_sysctl_real if you want to export lists of reals (scaled
-integers). You can also use your own function for them, as usual.
-Finally, the last parameter is the call-back to gather the data
-(see below) if you use the *_proc_real functions. 
-
-
-Gathering the data
-------------------
-
-The call back functions (foo_func and foo_data in the above example)
-can be called in several ways; the operation parameter determines
-what should be done:
-
-  * If operation == SENSORS_PROC_REAL_INFO, you must return the
-    magnitude (scaling) in nrels_mag;
-  * If operation == SENSORS_PROC_REAL_READ, you must read information
-    from the chip and return it in results. The number of integers
-    to display should be put in nrels_mag;
-  * If operation == SENSORS_PROC_REAL_WRITE, you must write the
-    supplied information to the chip. nrels_mag will contain the number
-    of integers, results the integers themselves.
-
-The *_proc_real functions will display the elements as reals for the
-/proc interface. If you set the magnitude to 2, and supply 345 for
-SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would
-write 45.6 to the /proc file, it would be returned as 4560 for
-SENSORS_PROC_REAL_WRITE. A magnitude may even be negative!
-
-An example function:
-
-  /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and
-     register values. Note the use of the read cache. */
-  void foo_in(struct i2c_client *client, int operation, int ctl_name, 
-              int *nrels_mag, long *results)
-  {
-    struct foo_data *data = client->data;
-    int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */
-    
-    if (operation == SENSORS_PROC_REAL_INFO)
-      *nrels_mag = 2;
-    else if (operation == SENSORS_PROC_REAL_READ) {
-      /* Update the readings cache (if necessary) */
-      foo_update_client(client);
-      /* Get the readings from the cache */
-      results[0] = FOO_FROM_REG(data->foo_func_base[nr]);
-      results[1] = FOO_FROM_REG(data->foo_func_more[nr]);
-      results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]);
-      *nrels_mag = 2;
-    } else if (operation == SENSORS_PROC_REAL_WRITE) {
-      if (*nrels_mag >= 1) {
-        /* Update the cache */
-        data->foo_base[nr] = FOO_TO_REG(results[0]);
-        /* Update the chip */
-        foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]);
-      }
-      if (*nrels_mag >= 2) {
-        /* Update the cache */
-        data->foo_more[nr] = FOO_TO_REG(results[1]);
-        /* Update the chip */
-        foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]);
-      }
-    }
-  }
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 38fe1f0..6498666 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -2,7 +2,7 @@
 		     ----------------------------
 
 		    H. Peter Anvin <hpa@zytor.com>
-			Last update 2007-01-26
+			Last update 2007-03-06
 
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
@@ -35,9 +35,13 @@ Protocol 2.03:	(Kernel 2.4.18-pre1) Expl
 		initrd address available to the bootloader.
 
 Protocol 2.04:	(Kernel 2.6.14) Extend the syssize field to four bytes.
+
 Protocol 2.05:	(Kernel 2.6.20) Make protected mode kernel relocatable.
 		Introduce relocatable_kernel and kernel_alignment fields.
 
+Protocol 2.06:	(Kernel 2.6.22) Added a field that contains the size of
+		the boot command line
+
 
 **** MEMORY LAYOUT
 
@@ -133,6 +137,8 @@ Offset	Proto	Name		Meaning
 022C/4	2.03+	initrd_addr_max	Highest legal initrd address
 0230/4	2.05+	kernel_alignment Physical addr alignment required for kernel
 0234/1	2.05+	relocatable_kernel Whether kernel is relocatable or not
+0235/3	N/A	pad2		Unused
+0238/4	2.06+	cmdline_size	Maximum size of the kernel command line
 
 (1) For backwards compatibility, if the setup_sects field contains 0, the
     real value is 4.
@@ -233,6 +239,12 @@ filled out, however:
 	if your ramdisk is exactly 131072 bytes long and this field is
 	0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
 
+  cmdline_size:
+	The maximum size of the command line without the terminating
+	zero. This means that the command line can contain at most
+	cmdline_size characters. With protocol version 2.05 and
+	earlier, the maximum size was 255.
+
 
 **** THE KERNEL COMMAND LINE
 
@@ -241,11 +253,10 @@ loader to communicate with the kernel.  
 relevant to the boot loader itself, see "special command line options"
 below.
 
-The kernel command line is a null-terminated string currently up to
-255 characters long, plus the final null.  A string that is too long
-will be automatically truncated by the kernel, a boot loader may allow
-a longer command line to be passed to permit future kernels to extend
-this limit.
+The kernel command line is a null-terminated string. The maximum
+length can be retrieved from the field cmdline_size.  Before protocol
+version 2.06, the maximum was 255 characters.  A string that is too
+long will be automatically truncated by the kernel.
 
 If the boot protocol version is 2.02 or later, the address of the
 kernel command line is given by the header field cmd_line_ptr (see
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
new file mode 100644
index 0000000..3153167
--- /dev/null
+++ b/Documentation/ia64/aliasing-test.c
@@ -0,0 +1,247 @@
+/*
+ * Exercise /dev/mem mmap cases that have been troublesome in the past
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <bjorn.helgaas@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 <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int sum;
+
+int map_mem(char *path, off_t offset, size_t length, int touch)
+{
+	int fd, rc;
+	void *addr;
+	int *c;
+
+	fd = open(path, O_RDWR);
+	if (fd == -1) {
+		perror(path);
+		return -1;
+	}
+
+	addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+	if (addr == MAP_FAILED)
+		return 1;
+
+	if (touch) {
+		c = (int *) addr;
+		while (c < (int *) (offset + length))
+			sum += *c++;
+	}
+
+	rc = munmap(addr, length);
+	if (rc == -1) {
+		perror("munmap");
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
+{
+	struct dirent **namelist;
+	char *name, *path2;
+	int i, n, r, rc, result = 0;
+	struct stat buf;
+
+	n = scandir(path, &namelist, 0, alphasort);
+	if (n < 0) {
+		perror("scandir");
+		return -1;
+	}
+
+	for (i = 0; i < n; i++) {
+		name = namelist[i]->d_name;
+
+		if (fnmatch(".", name, 0) == 0)
+			goto skip;
+		if (fnmatch("..", name, 0) == 0)
+			goto skip;
+
+		path2 = malloc(strlen(path) + strlen(name) + 3);
+		strcpy(path2, path);
+		strcat(path2, "/");
+		strcat(path2, name);
+
+		if (fnmatch(file, name, 0) == 0) {
+			rc = map_mem(path2, offset, length, touch);
+			if (rc == 0)
+				fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
+			else if (rc > 0)
+				fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
+			else {
+				fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
+				return rc;
+			}
+		} else {
+			r = lstat(path2, &buf);
+			if (r == 0 && S_ISDIR(buf.st_mode)) {
+				rc = scan_sysfs(path2, file, offset, length, touch);
+				if (rc < 0)
+					return rc;
+			}
+		}
+
+		result |= rc;
+		free(path2);
+
+skip:
+		free(namelist[i]);
+	}
+	free(namelist);
+	return rc;
+}
+
+char buf[1024];
+
+int read_rom(char *path)
+{
+	int fd, rc;
+	size_t size = 0;
+
+	fd = open(path, O_RDWR);
+	if (fd == -1) {
+		perror(path);
+		return -1;
+	}
+
+	rc = write(fd, "1", 2);
+	if (rc <= 0) {
+		perror("write");
+		return -1;
+	}
+
+	do {
+		rc = read(fd, buf, sizeof(buf));
+		if (rc > 0)
+			size += rc;
+	} while (rc > 0);
+
+	close(fd);
+	return size;
+}
+
+int scan_rom(char *path, char *file)
+{
+	struct dirent **namelist;
+	char *name, *path2;
+	int i, n, r, rc, result = 0;
+	struct stat buf;
+
+	n = scandir(path, &namelist, 0, alphasort);
+	if (n < 0) {
+		perror("scandir");
+		return -1;
+	}
+
+	for (i = 0; i < n; i++) {
+		name = namelist[i]->d_name;
+
+		if (fnmatch(".", name, 0) == 0)
+			goto skip;
+		if (fnmatch("..", name, 0) == 0)
+			goto skip;
+
+		path2 = malloc(strlen(path) + strlen(name) + 3);
+		strcpy(path2, path);
+		strcat(path2, "/");
+		strcat(path2, name);
+
+		if (fnmatch(file, name, 0) == 0) {
+			rc = read_rom(path2);
+
+			/*
+			 * It's OK if the ROM is unreadable.  Maybe there
+			 * is no ROM, or some other error ocurred.  The
+			 * important thing is that no MCA happened.
+			 */
+			if (rc > 0)
+				fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
+			else {
+				fprintf(stderr, "PASS: %s not readable\n", path2);
+				return rc;
+			}
+		} else {
+			r = lstat(path2, &buf);
+			if (r == 0 && S_ISDIR(buf.st_mode)) {
+				rc = scan_rom(path2, file);
+				if (rc < 0)
+					return rc;
+			}
+		}
+
+		result |= rc;
+		free(path2);
+
+skip:
+		free(namelist[i]);
+	}
+	free(namelist);
+	return rc;
+}
+
+main()
+{
+	int rc;
+
+	if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
+		fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
+	else
+		fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
+
+	/*
+	 * It's not safe to blindly read the VGA frame buffer.  If you know
+	 * how to poke the card the right way, it should respond, but it's
+	 * not safe in general.  Many machines, e.g., Intel chipsets, cover
+	 * up a non-responding card by just returning -1, but others will
+	 * report the failure as a machine check.
+	 */
+	if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
+		fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
+	else
+		fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
+
+	if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
+		fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
+	else
+		fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
+
+	/*
+	 * Often you can map all the individual pieces above (0-0xA0000,
+	 * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
+	 * thing at once.  This is because the individual pieces use different
+	 * attributes, and there's no single attribute supported over the
+	 * whole region.
+	 */
+	rc = map_mem("/dev/mem", 0, 1024*1024, 0);
+	if (rc == 0)
+		fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
+	else if (rc > 0)
+		fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
+	else
+		fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
+
+	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
+	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
+	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
+	scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
+
+	scan_rom("/sys/devices", "rom");
+}
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
index 38f9a52..9a431a7 100644
--- a/Documentation/ia64/aliasing.txt
+++ b/Documentation/ia64/aliasing.txt
@@ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES
 
 	The /dev/mem mmap constraints apply.
 
-	However, since this is for mapping legacy MMIO space, WB access
-	does not make sense.  This matters on machines without legacy
-	VGA support: these machines may have WB memory for the entire
-	first megabyte (or even the entire first granule).
-
-	On these machines, we could mmap legacy_mem as WB, which would
-	be safe in terms of attribute aliasing, but X has no way of
-	knowing that it is accessing regular memory, not a frame buffer,
-	so the kernel should fail the mmap rather than doing it with WB.
-
     read/write of /dev/mem
 
 	This uses copy_from_user(), which implicitly uses a kernel
@@ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES
 
     ioremap()
 
-	This returns a kernel identity mapping for use inside the
-	kernel.
+	This returns a mapping for use inside the kernel.
 
 	If the region is in kern_memmap, we should use the attribute
-	specified there.  Otherwise, if the EFI memory map reports that
-	the entire granule supports WB, we should use that (granules
-	that are partially reserved or occupied by firmware do not appear
-	in kern_memmap).  Otherwise, we should use a UC mapping.
+	specified there.
+
+	If the EFI memory map reports that the entire granule supports
+	WB, we should use that (granules that are partially reserved
+	or occupied by firmware do not appear in kern_memmap).
+
+	If the granule contains non-WB memory, but we can cover the
+	region safely with kernel page table mappings, we can use
+	ioremap_page_range() as most other architectures do.
+
+	Failing all of the above, we have to fall back to a UC mapping.
 
 PAST PROBLEM CASES
 
@@ -158,7 +154,7 @@ PAST PROBLEM CASES
       succeed.  It may create either WB or UC user mappings, depending
       on whether the region is in kern_memmap or the EFI memory map.
 
-    mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
+    mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
 
       See https://bugzilla.novell.com/show_bug.cgi?id=140858.
 
@@ -171,28 +167,25 @@ PAST PROBLEM CASES
       so it is safe to use WB mappings.
 
       The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
-      which will use a granule-sized UC mapping covering 0-0xFFFFF.  This
-      granule covers some WB-only memory, but since UC is non-speculative,
-      the processor will never generate an uncacheable reference to the
-      WB-only areas unless the driver explicitly touches them.
+      which uses a granule-sized UC mapping.  This granule will cover some
+      WB-only memory, but since UC is non-speculative, the processor will
+      never generate an uncacheable reference to the WB-only areas unless
+      the driver explicitly touches them.
 
     mmap of 0x0-0xFFFFF legacy_mem by "X"
 
-      If the EFI memory map reports this entire range as WB, there
-      is no VGA MMIO hole, and the mmap should fail or be done with
-      a WB mapping.
+      If the EFI memory map reports that the entire range supports the
+      same attributes, we can allow the mmap (and we will prefer WB if
+      supported, as is the case with HP sx[12]000 machines with VGA
+      disabled).
 
-      There's no easy way for X to determine whether the 0xA0000-0xBFFFF
-      region is a frame buffer or just memory, so I think it's best to
-      just fail this mmap request rather than using a WB mapping.  As
-      far as I know, there's no need to map legacy_mem with WB
-      mappings.
+      If EFI reports the range as partly WB and partly UC (as on sx[12]000
+      machines with VGA enabled), we must fail the mmap because there's no
+      safe attribute to use.
 
-      Otherwise, a UC mapping of the entire region is probably safe.
-      The VGA hole means the region will not be in kern_memmap.  The
-      HP sx1000 chipset doesn't support UC access to the memory surrounding
-      the VGA hole, but X doesn't need that area anyway and should not
-      reference it.
+      If EFI reports some of the range but not all (as on Intel firmware
+      that doesn't report the VGA frame buffer at all), we should fail the
+      mmap and force the user to map just the specific region of interest.
 
     mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
 
@@ -202,6 +195,16 @@ PAST PROBLEM CASES
       This is a special case of the previous case, and the mmap should
       fail for the same reason as above.
 
+    read of /sys/devices/.../rom
+
+      For VGA devices, this may cause an ioremap() of 0xC0000.  This
+      used to be done with a UC mapping, because the VGA frame buffer
+      at 0xA0000 prevents use of a WB granule.  The UC mapping causes
+      an MCA on HP sx[12]000 chipsets.
+
+      We should use WB page table mappings to avoid covering the VGA
+      frame buffer.
+
 NOTES
 
     [1] SDM rev 2.2, vol 2, sec 4.4.1.
diff --git a/Documentation/ia64/err_inject.txt b/Documentation/ia64/err_inject.txt
new file mode 100644
index 0000000..6449a70
--- /dev/null
+++ b/Documentation/ia64/err_inject.txt
@@ -0,0 +1,1068 @@
+
+IPF Machine Check (MC) error inject tool
+========================================
+
+IPF Machine Check (MC) error inject tool is used to inject MC
+errors from Linux. The tool is a test bed for IPF MC work flow including
+hardware correctable error handling, OS recoverable error handling, MC
+event logging, etc.
+
+The tool includes two parts: a kernel driver and a user application
+sample. The driver provides interface to PAL to inject error
+and query error injection capabilities. The driver code is in
+arch/ia64/kernel/err_inject.c. The application sample (shown below)
+provides a combination of various errors and calls the driver's interface
+(sysfs interface) to inject errors or query error injection capabilities.
+
+The tool can be used to test Intel IPF machine MC handling capabilities.
+It's especially useful for people who can not access hardware MC injection
+tool to inject error. It's also very useful to integrate with other
+software test suits to do stressful testing on IPF.
+
+Below is a sample application as part of the whole tool. The sample
+can be used as a working test tool. Or it can be expanded to include
+more features. It also can be a integrated into a libary or other user
+application to have more thorough test.
+
+The sample application takes err.conf as error configuation input. Gcc
+compiles the code. After you install err_inject driver, you can run
+this sample application to inject errors.
+
+Errata: Itanium 2 Processors Specification Update lists some errata against
+the pal_mc_error_inject PAL procedure. The following err.conf has been tested
+on latest Montecito PAL.
+
+err.conf:
+
+#This is configuration file for err_inject_tool.
+#The format of the each line is:
+#cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer
+#where
+#	cpu: logical cpu number the error will be inject in.
+#	loop: times the error will be injected.
+#	interval: In second. every so often one error is injected.
+#	err_type_info, err_struct_info: PAL parameters.
+#
+#Note: All values are hex w/o or w/ 0x prefix.
+
+
+#On cpu2, inject only total 0x10 errors, interval 5 seconds
+#corrected, data cache, hier-2, physical addr(assigned by tool code).
+#working on Montecito latest PAL.
+2, 10, 5, 4101, 95
+
+#On cpu4, inject and consume total 0x10 errors, interval 5 seconds
+#corrected, data cache, hier-2, physical addr(assigned by tool code).
+#working on Montecito latest PAL.
+4, 10, 5, 4109, 95
+
+#On cpu15, inject and consume total 0x10 errors, interval 5 seconds
+#recoverable, DTR0, hier-2.
+#working on Montecito latest PAL.
+0xf, 0x10, 5, 4249, 15
+
+The sample application source code:
+
+err_injection_tool.c:
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, 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.
+ *
+ * Copyright (C) 2006 Intel Co
+ *	Fenghua Yu <fenghua.yu@intel.com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sched.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+
+#define MAX_FN_SIZE 		256
+#define MAX_BUF_SIZE 		256
+#define DATA_BUF_SIZE 		256
+#define NR_CPUS 		512
+#define MAX_TASK_NUM		2048
+#define MIN_INTERVAL		5	// seconds
+#define	ERR_DATA_BUFFER_SIZE 	3	// Three 8-byte.
+#define PARA_FIELD_NUM		5
+#define MASK_SIZE		(NR_CPUS/64)
+#define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/"
+
+int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask);
+
+int verbose;
+#define vbprintf if (verbose) printf
+
+int log_info(int cpu, const char *fmt, ...)
+{
+	FILE *log;
+	char fn[MAX_FN_SIZE];
+	char buf[MAX_BUF_SIZE];
+	va_list args;
+
+	sprintf(fn, "%d.log", cpu);
+	log=fopen(fn, "a+");
+	if (log==NULL) {
+		perror("Error open:");
+		return -1;
+	}
+
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	memset(buf, 0, MAX_BUF_SIZE);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	fwrite(buf, sizeof(buf), 1, log);
+	fclose(log);
+
+	return 0;
+}
+
+typedef unsigned long u64;
+typedef unsigned int  u32;
+
+typedef union err_type_info_u {
+	struct {
+		u64	mode		: 3,	/* 0-2 */
+			err_inj		: 3,	/* 3-5 */
+			err_sev		: 2,	/* 6-7 */
+			err_struct	: 5,	/* 8-12 */
+			struct_hier	: 3,	/* 13-15 */
+			reserved	: 48;	/* 16-63 */
+	} err_type_info_u;
+	u64	err_type_info;
+} err_type_info_t;
+
+typedef union err_struct_info_u {
+	struct {
+		u64	siv		: 1,	/* 0	 */
+			c_t		: 2,	/* 1-2	 */
+			cl_p		: 3,	/* 3-5	 */
+			cl_id		: 3,	/* 6-8	 */
+			cl_dp		: 1,	/* 9	 */
+			reserved1	: 22,	/* 10-31 */
+			tiv		: 1,	/* 32	 */
+			trigger		: 4,	/* 33-36 */
+			trigger_pl 	: 3,	/* 37-39 */
+			reserved2 	: 24;	/* 40-63 */
+	} err_struct_info_cache;
+	struct {
+		u64	siv		: 1,	/* 0	 */
+			tt		: 2,	/* 1-2	 */
+			tc_tr		: 2,	/* 3-4	 */
+			tr_slot		: 8,	/* 5-12	 */
+			reserved1	: 19,	/* 13-31 */
+			tiv		: 1,	/* 32	 */
+			trigger		: 4,	/* 33-36 */
+			trigger_pl 	: 3,	/* 37-39 */
+			reserved2 	: 24;	/* 40-63 */
+	} err_struct_info_tlb;
+	struct {
+		u64	siv		: 1,	/* 0	 */
+			regfile_id	: 4,	/* 1-4	 */
+			reg_num		: 7,	/* 5-11	 */
+			reserved1	: 20,	/* 12-31 */
+			tiv		: 1,	/* 32	 */
+			trigger		: 4,	/* 33-36 */
+			trigger_pl 	: 3,	/* 37-39 */
+			reserved2 	: 24;	/* 40-63 */
+	} err_struct_info_register;
+	struct {
+		u64	reserved;
+	} err_struct_info_bus_processor_interconnect;
+	u64	err_struct_info;
+} err_struct_info_t;
+
+typedef union err_data_buffer_u {
+	struct {
+		u64	trigger_addr;		/* 0-63		*/
+		u64	inj_addr;		/* 64-127 	*/
+		u64	way		: 5,	/* 128-132	*/
+			index		: 20,	/* 133-152	*/
+					: 39;	/* 153-191	*/
+	} err_data_buffer_cache;
+	struct {
+		u64	trigger_addr;		/* 0-63		*/
+		u64	inj_addr;		/* 64-127 	*/
+		u64	way		: 5,	/* 128-132	*/
+			index		: 20,	/* 133-152	*/
+			reserved	: 39;	/* 153-191	*/
+	} err_data_buffer_tlb;
+	struct {
+		u64	trigger_addr;		/* 0-63		*/
+	} err_data_buffer_register;
+	struct {
+		u64	reserved;		/* 0-63		*/
+	} err_data_buffer_bus_processor_interconnect;
+	u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+} err_data_buffer_t;
+
+typedef union capabilities_u {
+	struct {
+		u64	i		: 1,
+			d		: 1,
+			rv		: 1,
+			tag		: 1,
+			data		: 1,
+			mesi		: 1,
+			dp		: 1,
+			reserved1	: 3,
+			pa		: 1,
+			va		: 1,
+			wi		: 1,
+			reserved2	: 20,
+			trigger		: 1,
+			trigger_pl	: 1,
+			reserved3	: 30;
+	} capabilities_cache;
+	struct {
+		u64	d		: 1,
+			i		: 1,
+			rv		: 1,
+			tc		: 1,
+			tr		: 1,
+			reserved1	: 27,
+			trigger		: 1,
+			trigger_pl	: 1,
+			reserved2	: 30;
+	} capabilities_tlb;
+	struct {
+		u64	gr_b0		: 1,
+			gr_b1		: 1,
+			fr		: 1,
+			br		: 1,
+			pr		: 1,
+			ar		: 1,
+			cr		: 1,
+			rr		: 1,
+			pkr		: 1,
+			dbr		: 1,
+			ibr		: 1,
+			pmc		: 1,
+			pmd		: 1,
+			reserved1	: 3,
+			regnum		: 1,
+			reserved2	: 15,
+			trigger		: 1,
+			trigger_pl	: 1,
+			reserved3	: 30;
+	} capabilities_register;
+	struct {
+		u64	reserved;
+	} capabilities_bus_processor_interconnect;
+} capabilities_t;
+
+typedef struct resources_s {
+	u64	ibr0		: 1,
+		ibr2		: 1,
+		ibr4		: 1,
+		ibr6		: 1,
+		dbr0		: 1,
+		dbr2		: 1,
+		dbr4		: 1,
+		dbr6		: 1,
+		reserved	: 48;
+} resources_t;
+
+
+long get_page_size(void)
+{
+	long page_size=sysconf(_SC_PAGESIZE);
+	return page_size;
+}
+
+#define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size())
+#define SHM_SIZE (2*PAGE_SIZE*NR_CPUS)
+#define SHM_VA 0x2000000100000000
+
+int shmid;
+void *shmaddr;
+
+int create_shm(void)
+{
+	key_t key;
+	char fn[MAX_FN_SIZE];
+
+	/* cpu0 is always existing */
+	sprintf(fn, PATH_FORMAT, 0);
+	if ((key = ftok(fn, 's')) == -1) {
+		perror("ftok");
+		return -1;
+	}
+
+	shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);
+	if (shmid == -1) {
+		if (errno==EEXIST) {
+			shmid = shmget(key, SHM_SIZE, 0);
+			if (shmid == -1) {
+				perror("shmget");
+				return -1;
+			}
+		}
+		else {
+			perror("shmget");
+			return -1;
+		}
+	}
+	vbprintf("shmid=%d", shmid);
+
+	/* connect to the segment: */
+	shmaddr = shmat(shmid, (void *)SHM_VA, 0);
+	if (shmaddr == (void*)-1) {
+		perror("shmat");
+		return -1;
+	}
+
+	memset(shmaddr, 0, SHM_SIZE);
+	mlock(shmaddr, SHM_SIZE);
+
+	return 0;
+}
+
+int free_shm()
+{
+	munlock(shmaddr, SHM_SIZE);
+        shmdt(shmaddr);
+	semctl(shmid, 0, IPC_RMID);
+
+	return 0;
+}
+
+#ifdef _SEM_SEMUN_UNDEFINED
+union semun
+{
+	int val;
+	struct semid_ds *buf;
+	unsigned short int *array;
+	struct seminfo *__buf;
+};
+#endif
+
+u32 mode=1; /* 1: physical mode; 2: virtual mode. */
+int one_lock=1;
+key_t key[NR_CPUS];
+int semid[NR_CPUS];
+
+int create_sem(int cpu)
+{
+	union semun arg;
+	char fn[MAX_FN_SIZE];
+	int sid;
+
+	sprintf(fn, PATH_FORMAT, cpu);
+	sprintf(fn, "%s/%s", fn, "err_type_info");
+	if ((key[cpu] = ftok(fn, 'e')) == -1) {
+		perror("ftok");
+		return -1;
+	}
+
+	if (semid[cpu]!=0)
+		return 0;
+
+	/* clear old semaphore */
+	if ((sid = semget(key[cpu], 1, 0)) != -1)
+		semctl(sid, 0, IPC_RMID);
+
+	/* get one semaphore */
+	if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) {
+		perror("semget");
+		printf("Please remove semaphore with key=0x%lx, then run the tool.\n",
+			(u64)key[cpu]);
+		return -1;
+	}
+
+	vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu,
+		(u64)key[cpu]);
+	/* initialize the semaphore to 1: */
+	arg.val = 1;
+	if (semctl(semid[cpu], 0, SETVAL, arg) == -1) {
+		perror("semctl");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int lock(int cpu)
+{
+	struct sembuf lock;
+
+	lock.sem_num = cpu;
+	lock.sem_op = 1;
+	semop(semid[cpu], &lock, 1);
+
+        return 0;
+}
+
+static int unlock(int cpu)
+{
+	struct sembuf unlock;
+
+	unlock.sem_num = cpu;
+	unlock.sem_op = -1;
+	semop(semid[cpu], &unlock, 1);
+
+        return 0;
+}
+
+void free_sem(int cpu)
+{
+	semctl(semid[cpu], 0, IPC_RMID);
+}
+
+int wr_multi(char *fn, unsigned long *data, int size)
+{
+	int fd;
+	char buf[MAX_BUF_SIZE];
+	int ret;
+
+	if (size==1)
+		sprintf(buf, "%lx", *data);
+	else if (size==3)
+		sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]);
+	else {
+		fprintf(stderr,"write to file with wrong size!\n");
+		return -1;
+	}
+
+	fd=open(fn, O_RDWR);
+	if (!fd) {
+		perror("Error:");
+		return -1;
+	}
+	ret=write(fd, buf, sizeof(buf));
+	close(fd);
+	return ret;
+}
+
+int wr(char *fn, unsigned long data)
+{
+	return wr_multi(fn, &data, 1);
+}
+
+int rd(char *fn, unsigned long *data)
+{
+	int fd;
+	char buf[MAX_BUF_SIZE];
+
+	fd=open(fn, O_RDONLY);
+	if (fd<0) {
+		perror("Error:");
+		return -1;
+	}
+	read(fd, buf, MAX_BUF_SIZE);
+	*data=strtoul(buf, NULL, 16);
+	close(fd);
+	return 0;
+}
+
+int rd_status(char *path, int *status)
+{
+	char fn[MAX_FN_SIZE];
+	sprintf(fn, "%s/status", path);
+	if (rd(fn, (u64*)status)<0) {
+		perror("status reading error.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rd_capabilities(char *path, u64 *capabilities)
+{
+	char fn[MAX_FN_SIZE];
+	sprintf(fn, "%s/capabilities", path);
+	if (rd(fn, capabilities)<0) {
+		perror("capabilities reading error.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rd_all(char *path)
+{
+	unsigned long err_type_info, err_struct_info, err_data_buffer;
+	int status;
+	unsigned long capabilities, resources;
+	char fn[MAX_FN_SIZE];
+
+	sprintf(fn, "%s/err_type_info", path);
+	if (rd(fn, &err_type_info)<0) {
+		perror("err_type_info reading error.\n");
+		return -1;
+	}
+	printf("err_type_info=%lx\n", err_type_info);
+
+	sprintf(fn, "%s/err_struct_info", path);
+	if (rd(fn, &err_struct_info)<0) {
+		perror("err_struct_info reading error.\n");
+		return -1;
+	}
+	printf("err_struct_info=%lx\n", err_struct_info);
+
+	sprintf(fn, "%s/err_data_buffer", path);
+	if (rd(fn, &err_data_buffer)<0) {
+		perror("err_data_buffer reading error.\n");
+		return -1;
+	}
+	printf("err_data_buffer=%lx\n", err_data_buffer);
+
+	sprintf(fn, "%s/status", path);
+	if (rd("status", (u64*)&status)<0) {
+		perror("status reading error.\n");
+		return -1;
+	}
+	printf("status=%d\n", status);
+
+	sprintf(fn, "%s/capabilities", path);
+	if (rd(fn,&capabilities)<0) {
+		perror("capabilities reading error.\n");
+		return -1;
+	}
+	printf("capabilities=%lx\n", capabilities);
+
+	sprintf(fn, "%s/resources", path);
+	if (rd(fn, &resources)<0) {
+		perror("resources reading error.\n");
+		return -1;
+	}
+	printf("resources=%lx\n", resources);
+
+	return 0;
+}
+
+int query_capabilities(char *path, err_type_info_t err_type_info,
+			u64 *capabilities)
+{
+	char fn[MAX_FN_SIZE];
+	err_struct_info_t err_struct_info;
+	err_data_buffer_t err_data_buffer;
+
+	err_struct_info.err_struct_info=0;
+	memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8);
+
+	sprintf(fn, "%s/err_type_info", path);
+	wr(fn, err_type_info.err_type_info);
+	sprintf(fn, "%s/err_struct_info", path);
+	wr(fn, 0x0);
+	sprintf(fn, "%s/err_data_buffer", path);
+	wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+	// Fire pal_mc_error_inject procedure.
+	sprintf(fn, "%s/call_start", path);
+	wr(fn, mode);
+
+	if (rd_capabilities(path, capabilities)<0)
+		return -1;
+
+	return 0;
+}
+
+int query_all_capabilities()
+{
+	int status;
+	err_type_info_t err_type_info;
+	int err_sev, err_struct, struct_hier;
+	int cap=0;
+	u64 capabilities;
+	char path[MAX_FN_SIZE];
+
+	err_type_info.err_type_info=0;			// Initial
+	err_type_info.err_type_info_u.mode=0;		// Query mode;
+	err_type_info.err_type_info_u.err_inj=0;
+
+	printf("All capabilities implemented in pal_mc_error_inject:\n");
+	sprintf(path, PATH_FORMAT ,0);
+	for (err_sev=0;err_sev<3;err_sev++)
+		for (err_struct=0;err_struct<5;err_struct++)
+			for (struct_hier=0;struct_hier<5;struct_hier++)
+	{
+		status=-1;
+		capabilities=0;
+		err_type_info.err_type_info_u.err_sev=err_sev;
+		err_type_info.err_type_info_u.err_struct=err_struct;
+		err_type_info.err_type_info_u.struct_hier=struct_hier;
+
+		if (query_capabilities(path, err_type_info, &capabilities)<0)
+			continue;
+
+		if (rd_status(path, &status)<0)
+			continue;
+
+		if (status==0) {
+			cap=1;
+			printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ",
+				err_sev, err_struct, struct_hier);
+			printf("capabilities 0x%lx\n", capabilities);
+		}
+	}
+	if (!cap) {
+		printf("No capabilities supported.\n");
+		return 0;
+	}
+
+	return 0;
+}
+
+int err_inject(int cpu, char *path, err_type_info_t err_type_info,
+		err_struct_info_t err_struct_info,
+		err_data_buffer_t err_data_buffer)
+{
+	int status;
+	char fn[MAX_FN_SIZE];
+
+	log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ",
+		err_type_info.err_type_info,
+		err_struct_info.err_struct_info);
+	log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n",
+		err_data_buffer.err_data_buffer[0],
+		err_data_buffer.err_data_buffer[1],
+		err_data_buffer.err_data_buffer[2]);
+	sprintf(fn, "%s/err_type_info", path);
+	wr(fn, err_type_info.err_type_info);
+	sprintf(fn, "%s/err_struct_info", path);
+	wr(fn, err_struct_info.err_struct_info);
+	sprintf(fn, "%s/err_data_buffer", path);
+	wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+	// Fire pal_mc_error_inject procedure.
+	sprintf(fn, "%s/call_start", path);
+	wr(fn,mode);
+
+	if (rd_status(path, &status)<0) {
+		vbprintf("fail: read status\n");
+		return -100;
+	}
+
+	if (status!=0) {
+		log_info(cpu, "fail: status=%d\n", status);
+		return status;
+	}
+
+	return status;
+}
+
+static int construct_data_buf(char *path, err_type_info_t err_type_info,
+		err_struct_info_t err_struct_info,
+		err_data_buffer_t *err_data_buffer,
+		void *va1)
+{
+	char fn[MAX_FN_SIZE];
+	u64 virt_addr=0, phys_addr=0;
+
+	vbprintf("va1=%lx\n", (u64)va1);
+	memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8);
+
+	switch (err_type_info.err_type_info_u.err_struct) {
+		case 1: // Cache
+			switch (err_struct_info.err_struct_info_cache.cl_id) {
+				case 1: //Virtual addr
+					err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1;
+					break;
+				case 2: //Phys addr
+					sprintf(fn, "%s/virtual_to_phys", path);
+					virt_addr=(u64)va1;
+					if (wr(fn,virt_addr)<0)
+						return -1;
+					rd(fn, &phys_addr);
+					err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr;
+					break;
+				default:
+					printf("Not supported cl_id\n");
+					break;
+			}
+			break;
+		case 2: //  TLB
+			break;
+		case 3: //  Register file
+			break;
+		case 4: //  Bus/system interconnect
+		default:
+			printf("Not supported err_struct\n");
+			break;
+	}
+
+	return 0;
+}
+
+typedef struct {
+	u64 cpu;
+	u64 loop;
+	u64 interval;
+	u64 err_type_info;
+	u64 err_struct_info;
+	u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+} parameters_t;
+
+parameters_t line_para;
+int para;
+
+static int empty_data_buffer(u64 *err_data_buffer)
+{
+	int empty=1;
+	int i;
+
+	for (i=0;i<ERR_DATA_BUFFER_SIZE; i++)
+	   if (err_data_buffer[i]!=-1)
+		empty=0;
+
+	return empty;
+}
+
+int err_inj()
+{
+	err_type_info_t err_type_info;
+	err_struct_info_t err_struct_info;
+	err_data_buffer_t err_data_buffer;
+	int count;
+	FILE *fp;
+	unsigned long cpu, loop, interval, err_type_info_conf, err_struct_info_conf;
+	u64 err_data_buffer_conf[ERR_DATA_BUFFER_SIZE];
+	int num;
+	int i;
+	char path[MAX_FN_SIZE];
+	parameters_t parameters[MAX_TASK_NUM]={};
+	pid_t child_pid[MAX_TASK_NUM];
+	time_t current_time;
+	int status;
+
+	if (!para) {
+	    fp=fopen("err.conf", "r");
+	    if (fp==NULL) {
+		perror("Error open err.conf");
+		return -1;
+	    }
+
+	    num=0;
+	    while (!feof(fp)) {
+		char buf[256];
+		memset(buf,0,256);
+		fgets(buf, 256, fp);
+		count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+				&cpu, &loop, &interval,&err_type_info_conf,
+				&err_struct_info_conf,
+				&err_data_buffer_conf[0],
+				&err_data_buffer_conf[1],
+				&err_data_buffer_conf[2]);
+		if (count!=PARA_FIELD_NUM+3) {
+			err_data_buffer_conf[0]=-1;
+			err_data_buffer_conf[1]=-1;
+			err_data_buffer_conf[2]=-1;
+			count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx\n",
+				&cpu, &loop, &interval,&err_type_info_conf,
+				&err_struct_info_conf);
+			if (count!=PARA_FIELD_NUM)
+				continue;
+		}
+
+		parameters[num].cpu=cpu;
+		parameters[num].loop=loop;
+		parameters[num].interval= interval>MIN_INTERVAL
+					  ?interval:MIN_INTERVAL;
+		parameters[num].err_type_info=err_type_info_conf;
+		parameters[num].err_struct_info=err_struct_info_conf;
+		memcpy(parameters[num++].err_data_buffer,
+			err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ;
+
+		if (num>=MAX_TASK_NUM)
+			break;
+	    }
+	}
+	else {
+		parameters[0].cpu=line_para.cpu;
+		parameters[0].loop=line_para.loop;
+		parameters[0].interval= line_para.interval>MIN_INTERVAL
+					  ?line_para.interval:MIN_INTERVAL;
+		parameters[0].err_type_info=line_para.err_type_info;
+		parameters[0].err_struct_info=line_para.err_struct_info;
+		memcpy(parameters[0].err_data_buffer,
+			line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ;
+
+		num=1;
+	}
+
+	/* Create semaphore: If one_lock, one semaphore for all processors.
+	   Otherwise, one sempaphore for each processor. */
+	if (one_lock) {
+		if (create_sem(0)) {
+			printf("Can not create semaphore...exit\n");
+			free_sem(0);
+			return -1;
+		}
+	}
+	else {
+		for (i=0;i<num;i++) {
+		   if (create_sem(parameters[i].cpu)) {
+			printf("Can not create semaphore for cpu%d...exit\n",i);
+			free_sem(parameters[num].cpu);
+			return -1;
+		   }
+		}
+	}
+
+	/* Create a shm segment which will be used to inject/consume errors on.*/
+	if (create_shm()==-1) {
+		printf("Error to create shm...exit\n");
+		return -1;
+	}
+
+	for (i=0;i<num;i++) {
+		pid_t pid;
+
+		current_time=time(NULL);
+		log_info(parameters[i].cpu, "\nBegine at %s", ctime(&current_time));
+		log_info(parameters[i].cpu, "Configurations:\n");
+		log_info(parameters[i].cpu,"On cpu%ld: loop=%lx, interval=%lx(s)",
+			parameters[i].cpu,
+			parameters[i].loop,
+			parameters[i].interval);
+		log_info(parameters[i].cpu," err_type_info=%lx,err_struct_info=%lx\n",
+			parameters[i].err_type_info,
+			parameters[i].err_struct_info);
+
+		sprintf(path, PATH_FORMAT, (int)parameters[i].cpu);
+		err_type_info.err_type_info=parameters[i].err_type_info;
+		err_struct_info.err_struct_info=parameters[i].err_struct_info;
+		memcpy(err_data_buffer.err_data_buffer,
+			parameters[i].err_data_buffer,
+			ERR_DATA_BUFFER_SIZE*8);
+
+		pid=fork();
+		if (pid==0) {
+			unsigned long mask[MASK_SIZE];
+			int j, k;
+
+			void *va1, *va2;
+
+			/* Allocate two memory areas va1 and va2 in shm */
+			va1=shmaddr+parameters[i].cpu*PAGE_SIZE;
+			va2=shmaddr+parameters[i].cpu*PAGE_SIZE+PAGE_SIZE;
+
+			vbprintf("va1=%lx, va2=%lx\n", (u64)va1, (u64)va2);
+			memset(va1, 0x1, PAGE_SIZE);
+			memset(va2, 0x2, PAGE_SIZE);
+
+			if (empty_data_buffer(err_data_buffer.err_data_buffer))
+				/* If not specified yet, construct data buffer
+				 * with va1
+				 */
+				construct_data_buf(path, err_type_info,
+					err_struct_info, &err_data_buffer,va1);
+
+			for (j=0;j<MASK_SIZE;j++)
+				mask[j]=0;
+
+			cpu=parameters[i].cpu;
+			k = cpu%64;
+			j = cpu/64;
+			mask[j]=1<<k;
+
+			if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
+				perror("Error sched_setaffinity:");
+				return -1;
+			}
+
+			for (j=0; j<parameters[i].loop; j++) {
+				log_info(parameters[i].cpu,"Injection ");
+				log_info(parameters[i].cpu,"on cpu%ld: #%d/%ld ",
+
+					parameters[i].cpu,j+1, parameters[i].loop);
+
+				/* Hold the lock */
+				if (one_lock)
+					lock(0);
+				else
+				/* Hold lock on this cpu */
+					lock(parameters[i].cpu);
+
+				if ((status=err_inject(parameters[i].cpu,
+					   path, err_type_info,
+					   err_struct_info, err_data_buffer))
+					   ==0) {
+					/* consume the error for "inject only"*/
+					memcpy(va2, va1, PAGE_SIZE);
+					memcpy(va1, va2, PAGE_SIZE);
+					log_info(parameters[i].cpu,
+						"successful\n");
+				}
+				else {
+					log_info(parameters[i].cpu,"fail:");
+					log_info(parameters[i].cpu,
+						"status=%d\n", status);
+					unlock(parameters[i].cpu);
+					break;
+				}
+				if (one_lock)
+				/* Release the lock */
+					unlock(0);
+				/* Release lock on this cpu */
+				else
+					unlock(parameters[i].cpu);
+
+				if (j < parameters[i].loop-1)
+					sleep(parameters[i].interval);
+			}
+			current_time=time(NULL);
+			log_info(parameters[i].cpu, "Done at %s", ctime(&current_time));
+			return 0;
+		}
+		else if (pid<0) {
+			perror("Error fork:");
+			continue;
+		}
+		child_pid[i]=pid;
+	}
+	for (i=0;i<num;i++)
+		waitpid(child_pid[i], NULL, 0);
+
+	if (one_lock)
+		free_sem(0);
+	else
+		for (i=0;i<num;i++)
+			free_sem(parameters[i].cpu);
+
+	printf("All done.\n");
+
+	return 0;
+}
+
+void help()
+{
+	printf("err_inject_tool:\n");
+	printf("\t-q: query all capabilities. default: off\n");
+	printf("\t-m: procedure mode. 1: physical 2: virtual. default: 1\n");
+	printf("\t-i: inject errors. default: off\n");
+	printf("\t-l: one lock per cpu. default: one lock for all\n");
+	printf("\t-e: error parameters:\n");
+	printf("\t\tcpu,loop,interval,err_type_info,err_struct_info[,err_data_buffer[0],err_data_buffer[1],err_data_buffer[2]]\n");
+	printf("\t\t   cpu: logical cpu number the error will be inject in.\n");
+	printf("\t\t   loop: times the error will be injected.\n");
+	printf("\t\t   interval: In second. every so often one error is injected.\n");
+	printf("\t\t   err_type_info, err_struct_info: PAL parameters.\n");
+	printf("\t\t   err_data_buffer: PAL parameter. Optional. If not present,\n");
+	printf("\t\t                    it's constructed by tool automatically. Be\n");
+	printf("\t\t                    careful to provide err_data_buffer and make\n");
+	printf("\t\t                    sure it's working with the environment.\n");
+	printf("\t    Note:no space between error parameters.\n");
+	printf("\t    default: Take error parameters from err.conf instead of command line.\n");
+	printf("\t-v: verbose. default: off\n");
+	printf("\t-h: help\n\n");
+	printf("The tool will take err.conf file as ");
+	printf("input to inject single or multiple errors ");
+	printf("on one or multiple cpus in parallel.\n");
+}
+
+int main(int argc, char **argv)
+{
+	char c;
+	int do_err_inj=0;
+	int do_query_all=0;
+	int count;
+	u32 m;
+
+	/* Default one lock for all cpu's */
+	one_lock=1;
+	while ((c = getopt(argc, argv, "m:iqvhle:")) != EOF)
+		switch (c) {
+			case 'm':	/* Procedure mode. 1: phys 2: virt */
+				count=sscanf(optarg, "%x", &m);
+				if (count!=1 || (m!=1 && m!=2)) {
+					printf("Wrong mode number.\n");
+					help();
+					return -1;
+				}
+				mode=m;
+				break;
+			case 'i':	/* Inject errors */
+				do_err_inj=1;
+				break;
+			case 'q':	/* Query */
+				do_query_all=1;
+				break;
+			case 'v':	/* Verbose */
+				verbose=1;
+				break;
+			case 'l':	/* One lock per cpu */
+				one_lock=0;
+				break;
+			case 'e':	/* error arguments */
+				/* Take parameters:
+				 * #cpu, loop, interval, err_type_info, err_struct_info[, err_data_buffer]
+				 * err_data_buffer is optional. Recommend not to specify
+				 * err_data_buffer. Better to use tool to generate it.
+				 */
+				count=sscanf(optarg,
+					"%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+					&line_para.cpu,
+					&line_para.loop,
+					&line_para.interval,
+					&line_para.err_type_info,
+					&line_para.err_struct_info,
+					&line_para.err_data_buffer[0],
+					&line_para.err_data_buffer[1],
+					&line_para.err_data_buffer[2]);
+				if (count!=PARA_FIELD_NUM+3) {
+				    line_para.err_data_buffer[0]=-1,
+				    line_para.err_data_buffer[1]=-1,
+			 	    line_para.err_data_buffer[2]=-1;
+				    count=sscanf(optarg, "%lx, %lx, %lx, %lx, %lx\n",
+						&line_para.cpu,
+						&line_para.loop,
+						&line_para.interval,
+						&line_para.err_type_info,
+						&line_para.err_struct_info);
+				    if (count!=PARA_FIELD_NUM) {
+					printf("Wrong error arguments.\n");
+					help();
+					return -1;
+				    }
+				}
+				para=1;
+				break;
+			continue;
+				break;
+			case 'h':
+				help();
+				return 0;
+			default:
+				break;
+		}
+
+	if (do_query_all)
+		query_all_capabilities();
+	if (do_err_inj)
+		err_inj();
+
+	if (!do_query_all &&  !do_err_inj)
+		help();
+
+	return 0;
+}
+
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
deleted file mode 100644
index 0132d36..0000000
--- a/Documentation/ibm-acpi.txt
+++ /dev/null
@@ -1,728 +0,0 @@
-		    IBM ThinkPad ACPI Extras Driver
-
-                            Version 0.12
-                           17 August 2005
-
-               Borislav Deianov <borislav@users.sf.net>
-		      http://ibm-acpi.sf.net/
-
-
-This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports
-various features of these laptops which are accessible through the
-ACPI framework but not otherwise supported by the generic Linux ACPI
-drivers.
-
-
-Status
-------
-
-The features currently supported are the following (see below for
-detailed description):
-
-	- Fn key combinations
-	- Bluetooth enable and disable
-	- video output switching, expansion control	
-	- ThinkLight on and off
-	- limited docking and undocking
-	- UltraBay eject
-	- CMOS control
-	- LED control
-	- ACPI sounds
-	- temperature sensors
-	- Experimental: embedded controller register dump
-	- 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
-reports, especially if they add to or correct the compatibility table.
-Please include the following information in your report:
-
-	- ThinkPad model name
-	- a copy of your DSDT, from /proc/acpi/dsdt
-	- which driver features work and which don't
-	- the observed behavior of non-working features
-
-Any other comments or patches are also more than welcome.
-
-
-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).
-
-Features
---------
-
-The driver creates the /proc/acpi/ibm directory. There is a file under
-that directory for each feature described below. Note that while the
-driver is still in the alpha stage, the exact proc file format and
-commands supported by the various features is guaranteed to change
-frequently.
-
-Driver version -- /proc/acpi/ibm/driver
----------------------------------------
-
-The driver name and version. No commands can be written to this file.
-
-Hot keys -- /proc/acpi/ibm/hotkey
----------------------------------
-
-Without this driver, only the Fn-F4 key (sleep button) generates an
-ACPI event. With the driver loaded, the hotkey feature enabled and the
-mask set (see below), the various hot keys generate ACPI events in the
-following format:
-
-	ibm/hotkey HKEY 00000080 0000xxxx
-
-The last four digits vary depending on the key combination pressed.
-All labeled Fn-Fx key combinations generate distinct events. In
-addition, the lid microswitch and some docking station buttons may
-also generate such events.
-
-The following commands can be written to this file:
-
-	echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
-	echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
-	echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
-	echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
-	... any other 4-hex-digit mask ...
-	echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
-
-The bit mask allows some control over which hot keys generate ACPI
-events. Not all bits in the mask can be modified. Not all bits that
-can be modified do anything. Not all hot keys can be individually
-controlled by the mask. Most recent ThinkPad models honor the
-following bits (assuming the hot keys feature has been enabled):
-
-	key	bit	behavior when set	behavior when unset
-
-	Fn-F3			always generates ACPI event
-	Fn-F4			always generates ACPI event
-	Fn-F5	0010	generate ACPI event	enable/disable Bluetooth
-	Fn-F7	0040	generate ACPI event	switch LCD and external display
-	Fn-F8	0080	generate ACPI event	expand screen or none
-	Fn-F9	0100	generate ACPI event	none
-	Fn-F12			always generates ACPI event
-
-Some models do not support all of the above. For example, the T30 does
-not support Fn-F5 and Fn-F9. Other models do not support the mask at
-all. On those models, hot keys cannot be controlled individually.
-
-Note that enabling ACPI events for some keys prevents their default
-behavior. For example, if events for Fn-F5 are enabled, that key will
-no longer enable/disable Bluetooth by itself. This can still be done
-from an acpid handler for the ibm/hotkey event.
-
-Note also that not all Fn key combinations are supported through
-ACPI. For example, on the X40, the brightness, volume and "Access IBM"
-buttons do not generate ACPI events even with this driver. They *can*
-be used through the "ThinkPad Buttons" utility, see
-http://www.nongnu.org/tpb/
-
-Bluetooth -- /proc/acpi/ibm/bluetooth
--------------------------------------
-
-This feature shows the presence and current state of a Bluetooth
-device. If Bluetooth is installed, the following commands can be used:
-
-	echo enable > /proc/acpi/ibm/bluetooth
-	echo disable > /proc/acpi/ibm/bluetooth
-
-Video output control -- /proc/acpi/ibm/video
---------------------------------------------
-
-This feature allows control over the devices used for video output -
-LCD, CRT or DVI (if available). The following commands are available:
-
-	echo lcd_enable > /proc/acpi/ibm/video
-	echo lcd_disable > /proc/acpi/ibm/video
-	echo crt_enable > /proc/acpi/ibm/video
-	echo crt_disable > /proc/acpi/ibm/video
-	echo dvi_enable > /proc/acpi/ibm/video
-	echo dvi_disable > /proc/acpi/ibm/video
-	echo auto_enable > /proc/acpi/ibm/video
-	echo auto_disable > /proc/acpi/ibm/video
-	echo expand_toggle > /proc/acpi/ibm/video
-	echo video_switch > /proc/acpi/ibm/video
-
-Each video output device can be enabled or disabled individually.
-Reading /proc/acpi/ibm/video shows the status of each device.
-
-Automatic video switching can be enabled or disabled.  When automatic
-video switching is enabled, certain events (e.g. opening the lid,
-docking or undocking) cause the video output device to change
-automatically. While this can be useful, it also causes flickering
-and, on the X40, video corruption. By disabling automatic switching,
-the flickering or video corruption can be avoided.
-
-The video_switch command cycles through the available video outputs
-(it simulates the behavior of Fn-F7).
-
-Video expansion can be toggled through this feature. This controls
-whether the display is expanded to fill the entire LCD screen when a
-mode with less than full resolution is used. Note that the current
-video expansion status cannot be determined through this feature.
-
-Note that on many models (particularly those using Radeon graphics
-chips) the X driver configures the video card in a way which prevents
-Fn-F7 from working. This also disables the video output switching
-features of this driver, as it uses the same ACPI methods as
-Fn-F7. Video switching on the console should still work.
-
-UPDATE: There's now a patch for the X.org Radeon driver which
-addresses this issue. Some people are reporting success with the patch
-while others are still having problems. For more information:
-
-https://bugs.freedesktop.org/show_bug.cgi?id=2000
-
-ThinkLight control -- /proc/acpi/ibm/light
-------------------------------------------
-
-The current status of the ThinkLight can be found in this file. A few
-models which do not make the status available will show it as
-"unknown". The available commands are:
-
-	echo on  > /proc/acpi/ibm/light
-	echo off > /proc/acpi/ibm/light
-
-Docking / undocking -- /proc/acpi/ibm/dock
-------------------------------------------
-
-Docking and undocking (e.g. with the X4 UltraBase) requires some
-actions to be taken by the operating system to safely make or break
-the electrical connections with the dock.
-
-The docking feature of this driver generates the following ACPI events:
-
-	ibm/dock GDCK 00000003 00000001 -- eject request
-	ibm/dock GDCK 00000003 00000002 -- undocked
-	ibm/dock GDCK 00000000 00000003 -- docked
-
-NOTE: These events will only be generated if the laptop was docked
-when originally booted. This is due to the current lack of support for
-hot plugging of devices in the Linux ACPI framework. If the laptop was
-booted while not in the dock, the following message is shown in the
-logs:
-
-	Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present
-
-In this case, no dock-related events are generated but the dock and
-undock commands described below still work. They can be executed
-manually or triggered by Fn key combinations (see the example acpid
-configuration files included in the driver tarball package available
-on the web site).
-
-When the eject request button on the dock is pressed, the first event
-above is generated. The handler for this event should issue the
-following command:
-
-	echo undock > /proc/acpi/ibm/dock
-
-After the LED on the dock goes off, it is safe to eject the laptop.
-Note: if you pressed this key by mistake, go ahead and eject the
-laptop, then dock it back in. Otherwise, the dock may not function as
-expected.
-
-When the laptop is docked, the third event above is generated. The
-handler for this event should issue the following command to fully
-enable the dock:
-
-	echo dock > /proc/acpi/ibm/dock
-
-The contents of the /proc/acpi/ibm/dock file shows the current status
-of the dock, as provided by the ACPI framework.
-
-The docking support in this driver does not take care of enabling or
-disabling any other devices you may have attached to the dock. For
-example, a CD drive plugged into the UltraBase needs to be disabled or
-enabled separately. See the provided example acpid configuration files
-for how this can be accomplished.
-
-There is no support yet for PCI devices that may be attached to a
-docking station, e.g. in the ThinkPad Dock II. The driver currently
-does not recognize, enable or disable such devices. This means that
-the only docking stations currently supported are the X-series
-UltraBase docks and "dumb" port replicators like the Mini Dock (the
-latter don't need any ACPI support, actually).
-
-UltraBay eject -- /proc/acpi/ibm/bay
-------------------------------------
-
-Inserting or ejecting an UltraBay device requires some actions to be
-taken by the operating system to safely make or break the electrical
-connections with the device.
-
-This feature generates the following ACPI events:
-
-	ibm/bay MSTR 00000003 00000000 -- eject request
-	ibm/bay MSTR 00000001 00000000 -- eject lever inserted
-
-NOTE: These events will only be generated if the UltraBay was present
-when the laptop was originally booted (on the X series, the UltraBay
-is in the dock, so it may not be present if the laptop was undocked).
-This is due to the current lack of support for hot plugging of devices
-in the Linux ACPI framework. If the laptop was booted without the
-UltraBay, the following message is shown in the logs:
-
-	Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present
-
-In this case, no bay-related events are generated but the eject
-command described below still works. It can be executed manually or
-triggered by a hot key combination.
-
-Sliding the eject lever generates the first event shown above. The
-handler for this event should take whatever actions are necessary to
-shut down the device in the UltraBay (e.g. call idectl), then issue
-the following command:
-
-	echo eject > /proc/acpi/ibm/bay
-
-After the LED on the UltraBay goes off, it is safe to pull out the
-device.
-
-When the eject lever is inserted, the second event above is
-generated. The handler for this event should take whatever actions are
-necessary to enable the UltraBay device (e.g. call idectl).
-
-The contents of the /proc/acpi/ibm/bay file shows the current status
-of the UltraBay, as provided by the ACPI framework.
-
-EXPERIMENTAL warm eject support on the 600e/x, A22p and A3x (To use
-this feature, you need to supply the experimental=1 parameter when
-loading the module):
-
-These models do not have a button near the UltraBay device to request
-a hot eject but rather require the laptop to be put to sleep
-(suspend-to-ram) before the bay device is ejected or inserted).
-The sequence of steps to eject the device is as follows:
-
-	echo eject > /proc/acpi/ibm/bay
-	put the ThinkPad to sleep
-	remove the drive
-	resume from sleep
-	cat /proc/acpi/ibm/bay should show that the drive was removed
-
-On the A3x, both the UltraBay 2000 and UltraBay Plus devices are
-supported. Use "eject2" instead of "eject" for the second bay.
-
-Note: the UltraBay eject support on the 600e/x, A22p and A3x is
-EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
-
-CMOS control -- /proc/acpi/ibm/cmos
------------------------------------
-
-This feature is used internally by the ACPI firmware to control the
-ThinkLight on most newer ThinkPad models. It may also control LCD
-brightness, sounds volume and more, but only on some models.
-
-The commands are non-negative integer numbers:
-
-	echo 0 >/proc/acpi/ibm/cmos
-	echo 1 >/proc/acpi/ibm/cmos
-	echo 2 >/proc/acpi/ibm/cmos
-	...
-
-The range of valid numbers is 0 to 21, but not all have an effect and
-the behavior varies from model to model. Here is the behavior on the
-X40 (tpb is the ThinkPad Buttons utility):
-
-	0 - no effect but tpb reports "Volume down"
-	1 - no effect but tpb reports "Volume up"
-	2 - no effect but tpb reports "Mute on"
-	3 - simulate pressing the "Access IBM" button
-	4 - LCD brightness up
-	5 - LCD brightness down
-	11 - toggle screen expansion
-	12 - ThinkLight on
-	13 - ThinkLight off
-	14 - no effect but tpb reports ThinkLight status change
-
-LED control -- /proc/acpi/ibm/led
----------------------------------
-
-Some of the LED indicators can be controlled through this feature. The
-available commands are:
-
-	echo '<led number> on' >/proc/acpi/ibm/led
-	echo '<led number> off' >/proc/acpi/ibm/led
-	echo '<led number> blink' >/proc/acpi/ibm/led
-
-The <led number> range is 0 to 7. The set of LEDs that can be
-controlled varies from model to model. Here is the mapping on the X40:
-
-	0 - power
-	1 - battery (orange)
-	2 - battery (green)
-	3 - UltraBase
-	4 - UltraBay
-	7 - standby
-
-All of the above can be turned on and off and can be made to blink.
-
-ACPI sounds -- /proc/acpi/ibm/beep
-----------------------------------
-
-The BEEP method is used internally by the ACPI firmware to provide
-audible alerts in various situations. This feature allows the same
-sounds to be triggered manually.
-
-The commands are non-negative integer numbers:
-
-	echo <number> >/proc/acpi/ibm/beep
-
-The valid <number> range is 0 to 17. Not all numbers trigger sounds
-and the sounds vary from model to model. Here is the behavior on the
-X40:
-
-	0 - stop a sound in progress (but use 17 to stop 16)
-	2 - two beeps, pause, third beep ("low battery")
-	3 - single beep
-	4 - high, followed by low-pitched beep ("unable")
-	5 - single beep
-	6 - very high, followed by high-pitched beep ("AC/DC")
-	7 - high-pitched beep
-	9 - three short beeps
-	10 - very long beep
-	12 - low-pitched beep
-	15 - three high-pitched beeps repeating constantly, stop with 0
-	16 - one medium-pitched beep repeating constantly, stop with 17
-	17 - stop 16
-
-Temperature sensors -- /proc/acpi/ibm/thermal
----------------------------------------------
-
-Most ThinkPads include six or more separate temperature sensors but
-only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors on older
-ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads.  Readings from sensors that are not available
-return -128.
-
-No commands can be written to this file.
-
-EXPERIMENTAL: The 16-sensors 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.  When EXPERIMENTAL
-mode is enabled, reading the first 8 sensors on newer ThinkPads will
-also use an new experimental thermal sensor access mode.
-
-For example, on the X40, a typical output may be:
-temperatures:   42 42 45 41 36 -128 33 -128
-
-EXPERIMENTAL: On the T43/p, a typical output may be:
-temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
-
-The mapping of thermal sensors to physical locations varies depending on
-system-board model (and thus, on ThinkPad model).
-
-http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
-tries to track down these locations for various models.
-
-Most (newer?) models seem to follow this pattern:
-
-1:  CPU
-2:  (depends on model)
-3:  (depends on model)
-4:  GPU
-5:  Main battery: main sensor
-6:  Bay battery: main sensor
-7:  Main battery: secondary sensor
-8:  Bay battery: secondary sensor
-9-15: (depends on model)
-
-For the R51 (source: Thomas Gruber):
-2:  Mini-PCI
-3:  Internal HDD
-
-For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
-http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
-2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
-3:  PCMCIA slot
-9:  MCH (northbridge) to DRAM Bus
-10: ICH (southbridge), under Mini-PCI card, under touchpad
-11: Power regulator, underside of system board, below F2 key
-
-The A31 has a very atypical layout for the thermal sensors
-(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
-1:  CPU
-2:  Main Battery: main sensor
-3:  Power Converter
-4:  Bay Battery: main sensor
-5:  MCH (northbridge)
-6:  PCMCIA/ambient
-7:  Main Battery: secondary sensor
-8:  Bay Battery: secondary sensor
-
-
-EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
-------------------------------------------------------------------------
-
-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 dumps the values of 256 embedded controller
-registers. Values which have changed since the last time the registers
-were dumped are marked with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 
-EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
-EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
-EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
-EC 0x30:  01  07  1a  00  30  04  00  00 *85  00  00  10  00  50  00  00
-EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
-EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03 *bc *02 *bc
-EC 0x60: *02 *bc *02  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0x70:  00  00  00  00  00  12  30  40 *24 *26 *2c *27 *20  80 *1f  80
-EC 0x80:  00  00  00  06 *37 *0e  03  00  00  00  0e  07  00  00  00  00
-EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xa0: *ff  09  ff  09  ff  ff *64  00 *00 *00 *a2  41 *ff *ff *e0  00
-EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
-EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
-
-This feature can be used to determine the register holding the fan
-speed on some models. To do that, do the following:
-
-	- make sure the battery is fully charged
-	- make sure the fan is running
-	- run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so
-
-The first step makes sure various charging-related values don't
-vary. The second ensures that the fan-related values do vary, since
-the fan speed fluctuates a bit. The third will (hopefully) mark the
-fan register with a star:
-
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 
-EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
-EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
-EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
-EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
-EC 0x30:  01  07  1a  00  30  04  00  00  85  00  00  10  00  50  00  00
-EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
-EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03  bc  02  bc
-EC 0x60:  02  bc  02  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0x70:  00  00  00  00  00  12  30  40  24  27  2c  27  21  80  1f  80
-EC 0x80:  00  00  00  06 *be  0d  03  00  00  00  0e  07  00  00  00  00
-EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xa0:  ff  09  ff  09  ff  ff  64  00  00  00  a2  41  ff  ff  e0  00
-EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
-EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
-EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
-
-Another set of values that varies often is the temperature
-readings. Since temperatures don't change vary fast, you can take
-several quick dumps to eliminate them.
-
-You can use a similar method to figure out the meaning of other
-embedded controller registers - e.g. make sure nothing else changes
-except the charging or discharging battery to determine which
-registers contain the current battery capacity, etc. If you experiment
-with this, do send me your results (including some complete dumps with
-a description of the conditions when they were taken.)
-
-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
-commands are:
-
-	echo up   >/proc/acpi/ibm/brightness
-	echo down >/proc/acpi/ibm/brightness
-	echo 'level <level>' >/proc/acpi/ibm/brightness
-
-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.
-
-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:
-
-	echo up   >/proc/acpi/ibm/volume
-	echo down >/proc/acpi/ibm/volume
-	echo mute >/proc/acpi/ibm/volume
-	echo 'level <level>' >/proc/acpi/ibm/volume
-
-The <level> number range is 0 to 15 although not all of them may be
-distinct. The unmute the volume after the mute command, use either the
-up or down command (the level command will not unmute the volume).
-The current volume level and mute state is shown in the file.
-
-EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan
------------------------------------------------------------------
-
-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 attempts to show the current fan speed, control mode and
-other fan data that might be available.  The speed is read directly
-from the hardware registers of the embedded controller.  This is known
-to work on later R, T and X series ThinkPads but may show a bogus
-value on other models.
-
-Most ThinkPad fans work in "levels".  Level 0 stops the fan.  The higher
-the level, the higher the fan speed, although adjacent levels often map
-to the same fan speed.  7 is the highest level, where the fan reaches
-the maximum recommended speed.  Level "auto" means the EC changes the
-fan level according to some internal algorithm, usually based on
-readings from the thermal sensors.  Level "disengaged" means the EC
-disables the speed-locked closed-loop fan control, and drives the fan as
-fast as it can go, which might exceed hardware limits, so use this level
-with caution.
-
-The fan usually ramps up or down slowly from one speed to another,
-and it is normal for the EC to take several seconds to react to fan
-commands.
-
-The fan may be enabled or disabled with the following commands:
-
-	echo enable  >/proc/acpi/ibm/fan
-	echo disable >/proc/acpi/ibm/fan
-
-Placing a fan on level 0 is the same as disabling it.  Enabling a fan
-will try to place it in a safe level if it is too slow or disabled.
-
-WARNING WARNING WARNING: do not leave the fan disabled unless you are
-monitoring all of the temperature sensor readings and you are ready to
-enable it if necessary to avoid overheating.
-
-An enabled fan in level "auto" may stop spinning if the EC decides the
-ThinkPad is cool enough and doesn't need the extra airflow.  This is
-normal, and the EC will spin the fan up if the varios thermal readings
-rise too much.
-
-On the X40, this seems to depend on the CPU and HDD temperatures.
-Specifically, the fan is turned on when either the CPU temperature
-climbs to 56 degrees or the HDD temperature climbs to 46 degrees.  The
-fan is turned off when the CPU temperature drops to 49 degrees and the
-HDD temperature drops to 41 degrees.  These thresholds cannot
-currently be controlled.
-
-The fan level can be controlled with the command:
-
-	echo 'level <level>' > /proc/acpi/ibm/thermal
-
-Where <level> is an integer from 0 to 7, or one of the words "auto"
-or "disengaged" (without the quotes).  Not all ThinkPads support the
-"auto" and "disengaged" levels.
-
-On the X31 and X40 (and ONLY on those models), the fan speed can be
-controlled to a certain degree. Once the fan is running, it can be
-forced to run faster or slower with the following command:
-
-	echo 'speed <speed>' > /proc/acpi/ibm/thermal
-
-The sustainable range of fan speeds on the X40 appears to be from
-about 3700 to about 7350. Values outside this range either do not have
-any effect or the fan speed eventually settles somewhere in that
-range. The fan cannot be stopped or started with this command.
-
-The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
-certain conditions are met.  It will override any fan programming done
-through ibm-acpi.
-
-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
-------------------------------------
-
-Multiple commands can be written to the proc files in one shot by
-separating them with commas, for example:
-
-	echo enable,0xffff > /proc/acpi/ibm/hotkey
-	echo lcd_disable,crt_enable > /proc/acpi/ibm/video
-
-Commands can also be specified when loading the ibm_acpi module, for
-example:
-
-	modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
-
-The ibm-acpi kernel driver can be programmed to revert the fan level
-to a safe setting if userspace does not issue one of the fan commands:
-"enable", "disable", "level" or "watchdog" within a configurable
-ammount of time.  To do this, use the "watchdog" command.
-
-	echo 'watchdog <interval>' > /proc/acpi/ibm/fan
-
-Interval is the ammount of time in seconds to wait for one of the
-above mentioned fan commands before reseting the fan level to a safe
-one.  If set to zero, the watchdog is disabled (default).  When the
-watchdog timer runs out, it does the exact equivalent of the "enable"
-fan command.
-
-Note that the watchdog timer stops after it enables the fan.  It will
-be rearmed again automatically (using the same interval) when one of
-the above mentioned fan commands is received.  The fan watchdog is,
-therefore, not suitable to protect against fan mode changes made
-through means other than the "enable", "disable", and "level" fan
-commands.
-
-
-Example Configuration
----------------------
-
-The ACPI support in the kernel is intended to be used in conjunction
-with a user-space daemon, acpid. The configuration files for this
-daemon control what actions are taken in response to various ACPI
-events. An example set of configuration files are included in the
-config/ directory of the tarball package available on the web
-site. Note that these are provided for illustration purposes only and
-may need to be adapted to your particular setup.
-
-The following utility scripts are used by the example action
-scripts (included with ibm-acpi for completeness):
-
-	/usr/local/sbin/idectl -- from the hdparm source distribution,
-		see http://www.ibiblio.org/pub/Linux/system/hardware
-	/usr/local/sbin/laptop_mode -- from the Linux kernel source
-		distribution, see Documentation/laptop-mode.txt
-	/sbin/service -- comes with Redhat/Fedora distributions
-	/usr/sbin/hibernate -- from the Software Suspend 2 distribution,
-		see http://softwaresuspend.berlios.de/
-
-Toan T Nguyen <ntt@physics.ucla.edu> notes that Suse uses the
-powersave program to suspend ('powersave --suspend-to-ram') or
-hibernate ('powersave --suspend-to-disk'). This means that the
-hibernate script is not needed on that distribution.
-
-Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
-handler script for the X31. You can get the latest version from
-http://dev.gentoo.org/~brix/files/x31.sh
-
-David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
-script which works on Debian systems. This scripts has now been
-extended to also work on Fedora systems and included as the default
-blank.sh in the distribution.
diff --git a/Documentation/infiniband/user_mad.txt b/Documentation/infiniband/user_mad.txt
index 750fe5e..8ec54b9 100644
--- a/Documentation/infiniband/user_mad.txt
+++ b/Documentation/infiniband/user_mad.txt
@@ -91,6 +91,14 @@ Sending MADs
 	if (ret != sizeof *mad + mad_length)
 		perror("write");
 
+Transaction IDs
+
+  Users of the umad devices can use the lower 32 bits of the
+  transaction ID field (that is, the least significant half of the
+  field in network byte order) in MADs being sent to match
+  request/response pairs.  The upper 32 bits are reserved for use by
+  the kernel and will be overwritten before a MAD is sent.
+
 Setting IsSM Capability Bit
 
   To set the IsSM capability bit for a port, simply open the
diff --git a/Documentation/input/input-programming.txt b/Documentation/input/input-programming.txt
index 180e068..d9d5230 100644
--- a/Documentation/input/input-programming.txt
+++ b/Documentation/input/input-programming.txt
@@ -1,5 +1,3 @@
-$Id: input-programming.txt,v 1.4 2001/05/04 09:47:14 vojtech Exp $
-
 Programming input drivers
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -20,28 +18,51 @@ #include <linux/init.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
+static struct input_dev *button_dev;
+
 static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
 {
-	input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
-	input_sync(&button_dev);
+	input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
+	input_sync(button_dev);
 }
 
 static int __init button_init(void)
 {
+	int error;
+
 	if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
                 printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
                 return -EBUSY;
         }
-	
-	button_dev.evbit[0] = BIT(EV_KEY);
-	button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
-	
-	input_register_device(&button_dev);
+
+	button_dev = input_allocate_device();
+	if (!button_dev) {
+		printk(KERN_ERR "button.c: Not enough memory\n");
+		error = -ENOMEM;
+		goto err_free_irq;
+	}
+
+	button_dev->evbit[0] = BIT(EV_KEY);
+	button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+	error = input_register_device(button_dev);
+	if (error) {
+		printk(KERN_ERR "button.c: Failed to register device\n");
+		goto err_free_dev;
+	}
+
+	return 0;
+
+ err_free_dev:
+	input_free_device(button_dev);
+ err_free_irq:
+	free_irq(BUTTON_IRQ, button_interrupt);
+	return error;
 }
 
 static void __exit button_exit(void)
 {
-        input_unregister_device(&button_dev);
+        input_unregister_device(button_dev);
 	free_irq(BUTTON_IRQ, button_interrupt);
 }
 
@@ -58,17 +79,18 @@ In the _init function, which is called e
 booting the kernel, it grabs the required resources (it should also check
 for the presence of the device).
 
-Then it sets the input bitfields. This way the device driver tells the other
+Then it allocates a new input device structure with input_aloocate_device()
+and sets up input bitfields. This way the device driver tells the other
 parts of the input systems what it is - what events can be generated or
-accepted by this input device. Our example device can only generate EV_KEY type
-events, and from those only BTN_0 event code. Thus we only set these two
-bits. We could have used
+accepted by this input device. Our example device can only generate EV_KEY
+type events, and from those only BTN_0 event code. Thus we only set these
+two bits. We could have used
 
 	set_bit(EV_KEY, button_dev.evbit);
 	set_bit(BTN_0, button_dev.keybit);
 
 as well, but with more than single bits the first approach tends to be
-shorter. 
+shorter.
 
 Then the example driver registers the input device structure by calling
 
@@ -76,16 +98,15 @@ Then the example driver registers the in
 
 This adds the button_dev structure to linked lists of the input driver and
 calls device handler modules _connect functions to tell them a new input
-device has appeared. Because the _connect functions may call kmalloc(,
-GFP_KERNEL), which can sleep, input_register_device() must not be called
-from an interrupt or with a spinlock held.
+device has appeared. input_register_device() may sleep and therefore must
+not be called from an interrupt or with a spinlock held.
 
 While in use, the only used function of the driver is
 
 	button_interrupt()
 
 which upon every interrupt from the button checks its state and reports it
-via the 
+via the
 
 	input_report_key()
 
@@ -113,16 +134,10 @@ can use the open and close callback to k
 release the interrupt and when it must resume polling or grab the interrupt
 again. To do that, we would add this to our example driver:
 
-int button_used = 0;
-
 static int button_open(struct input_dev *dev)
 {
-        if (button_used++)
-                return 0;
-
 	if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
                 printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
-                button_used--;
                 return -EBUSY;
         }
 
@@ -131,20 +146,21 @@ static int button_open(struct input_dev 
 
 static void button_close(struct input_dev *dev)
 {
-        if (!--button_used)
-                free_irq(IRQ_AMIGA_VERTB, button_interrupt);
+        free_irq(IRQ_AMIGA_VERTB, button_interrupt);
 }
 
 static int __init button_init(void)
 {
 	...
-	button_dev.open = button_open;
-	button_dev.close = button_close;
+	button_dev->open = button_open;
+	button_dev->close = button_close;
 	...
 }
 
-Note the button_used variable - we have to track how many times the open
-function was called to know when exactly our device stops being used.
+Note that input core keeps track of number of users for the device and
+makes sure that dev->open() is called only when the first user connects
+to the device and that dev->close() is called when the very last user
+disconnects. Calls to both callbacks are serialized.
 
 The open() callback should return a 0 in case of success or any nonzero value
 in case of failure. The close() callback (which is void) must always succeed.
@@ -175,7 +191,7 @@ set the corresponding bits and call the
 
 	input_report_rel(struct input_dev *dev, int code, int value)
 
-function. Events are generated only for nonzero value. 
+function. Events are generated only for nonzero value.
 
 However EV_ABS requires a little special care. Before calling
 input_register_device, you have to fill additional fields in the input_dev
@@ -187,6 +203,10 @@ the ABS_X axis:
 	button_dev.absfuzz[ABS_X] = 4;
 	button_dev.absflat[ABS_X] = 8;
 
+Or, you can just say:
+
+	input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);
+
 This setting would be appropriate for a joystick X axis, with the minimum of
 0, maximum of 255 (which the joystick *must* be able to reach, no problem if
 it sometimes reports more, but it must be able to always reach the min and
@@ -197,14 +217,7 @@ If you don't need absfuzz and absflat, y
 that the thing is precise and always returns to exactly the center position
 (if it has any).
 
-1.4 The void *private field
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This field in the input structure can be used to point to any private data
-structures in the input device driver, in case the driver handles more than
-one device. You'll need it in the open and close callbacks.
-
-1.5 NBITS(), LONG(), BIT()
+1.4 NBITS(), LONG(), BIT()
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 These three macros from input.h help some bitfield computations:
@@ -213,13 +226,9 @@ These three macros from input.h help som
 	LONG(x)  - returns the index in the array in longs for bit x
 	BIT(x)   - returns the index in a long for bit x
 
-1.6 The number, id* and name fields
+1.5 The id* and name fields
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The dev->number is assigned by the input system to the input device when it
-is registered. It has no use except for identifying the device to the user
-in system messages.
-
 The dev->name should be set before registering the input device by the input
 device driver. It's a string like 'Generic button device' containing a
 user friendly name of the device.
@@ -234,15 +243,25 @@ driver.
 
 The id and name fields can be passed to userland via the evdev interface.
 
-1.7 The keycode, keycodemax, keycodesize fields
+1.6 The keycode, keycodemax, keycodesize fields
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-These two fields will be used for any input devices that report their data
-as scancodes. If not all scancodes can be known by autodetection, they may
-need to be set by userland utilities. The keycode array then is an array
-used to map from scancodes to input system keycodes. The keycode max will
-contain the size of the array and keycodesize the size of each entry in it
-(in bytes).
+These three fields should be used by input devices that have dense keymaps.
+The keycode is an array used to map from scancodes to input system keycodes.
+The keycode max should contain the size of the array and keycodesize the
+size of each entry in it (in bytes).
+
+Userspace can query and alter current scancode to keycode mappings using
+EVIOCGKEYCODE and EVIOCSKEYCODE ioctls on corresponding evdev interface.
+When a device has all 3 aforementioned fields filled in, the driver may
+rely on kernel's default implementation of setting and querying keycode
+mappings.
+
+1.7 dev->getkeycode() and dev->setkeycode()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+getkeycode() and setkeycode() callbacks allow drivers to override default
+keycode/keycodesize/keycodemax mapping mechanism provided by input core
+and implement sparse keycode maps.
 
 1.8 Key autorepeat
 ~~~~~~~~~~~~~~~~~~
@@ -266,7 +285,7 @@ direction - from the system to the input
 driver can handle these events, it has to set the respective bits in evbit,
 *and* also the callback routine:
 
-	button_dev.event = button_event;
+	button_dev->event = button_event;
 
 int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 {
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 8f750c0..3de7d37 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -138,7 +138,8 @@ Code	Seq#	Include File		Comments
 'm'	00-1F	net/irda/irmod.h	conflict!
 'n'	00-7F	linux/ncp_fs.h
 'n'	E0-FF	video/matrox.h          matroxfb
-'p'	00-3F	linux/mc146818rtc.h
+'p'	00-0F	linux/phantom.h		conflict! (OpenHaptics needs this)
+'p'	00-3F	linux/mc146818rtc.h	conflict!
 'p'	40-7F	linux/nvram.h
 'p'	80-9F				user-space parport
 					<mailto:tim@cyberelk.net>
diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
index 769ee05..1d247d5 100644
--- a/Documentation/kbuild/modules.txt
+++ b/Documentation/kbuild/modules.txt
@@ -249,7 +249,7 @@ following files:
 		--> filename: Makefile
 		KERNELDIR := /lib/modules/`uname -r`/build
 		all::
-			$(MAKE) -C $KERNELDIR M=`pwd` $@
+			$(MAKE) -C $(KERNELDIR) M=`pwd` $@
 
 		# Module specific targets
 		genbin:
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 12533a9..6b8ad06 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -64,6 +64,7 @@ parameter is applicable:
 	GENERIC_TIME The generic timeofday code is enabled.
 	NFS	Appropriate NFS support is enabled.
 	OSS	OSS sound support is enabled.
+	PV_OPS	A paravirtualized kernel
 	PARIDE	The ParIDE subsystem is enabled.
 	PARISC	The PA-RISC architecture is enabled.
 	PCI	PCI bus support is enabled.
@@ -181,19 +182,41 @@ and is between 256 and 4096 characters. 
 			that require a timer override, but don't have
 			HPET
 
-	acpi_dbg_layer=	[HW,ACPI]
+	acpi.debug_layer=	[HW,ACPI]
 			Format: <int>
 			Each bit of the <int> indicates an ACPI debug layer,
 			1: enable, 0: disable. It is useful for boot time
 			debugging. After system has booted up, it can be set
-			via /proc/acpi/debug_layer.
-
-	acpi_dbg_level=	[HW,ACPI]
+			via /sys/module/acpi/parameters/debug_layer.
+			CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+			Available bits (add the numbers together) to enable debug output
+			for specific parts of the ACPI subsystem:
+			0x01 utilities 0x02 hardware 0x04 events 0x08 tables
+			0x10 namespace 0x20 parser 0x40 dispatcher
+			0x80 executer 0x100 resources 0x200 acpica debugger
+			0x400 os services 0x800 acpica disassembler.
+			The number can be in decimal or prefixed with 0x in hex.
+			Warning: Many of these options can produce a lot of
+			output and make your system unusable. Be very careful.
+
+	acpi.debug_level=	[HW,ACPI]
 			Format: <int>
 			Each bit of the <int> indicates an ACPI debug level,
 			1: enable, 0: disable. It is useful for boot time
 			debugging. After system has booted up, it can be set
-			via /proc/acpi/debug_level.
+			via /sys/module/acpi/parameters/debug_level.
+			CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+			Available bits (add the numbers together) to enable different
+			debug output levels of the ACPI subsystem:
+			0x01 error 0x02 warn 0x04 init 0x08 debug object
+			0x10 info 0x20 init names 0x40 parse 0x80 load
+			0x100 dispatch 0x200 execute 0x400 names 0x800 operation region
+			0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects
+			0x10000 resources 0x20000 user requests 0x40000 package.
+			The number can be in decimal or prefixed with 0x in hex.
+			Warning: Many of these options can produce a lot of
+			output and make your system unusable. Be very careful.
+
 
 	acpi_fake_ecdt	[HW,ACPI] Workaround failure due to BIOS lacking ECDT
 
@@ -473,6 +496,30 @@ and is between 256 and 4096 characters. 
 			Format: <area>[,<node>]
 			See also Documentation/networking/decnet.txt.
 
+	default_blu=	[VT]
+			Format: <blue0>,<blue1>,<blue2>,...,<blue15>
+			Change the default blue palette of the console.
+			This is a 16-member array composed of values
+			ranging from 0-255.
+
+	default_grn=	[VT]
+			Format: <green0>,<green1>,<green2>,...,<green15>
+			Change the default green palette of the console.
+			This is a 16-member array composed of values
+			ranging from 0-255.
+
+	default_red=	[VT]
+			Format: <red0>,<red1>,<red2>,...,<red15>
+			Change the default red palette of the console.
+			This is a 16-member array composed of values
+			ranging from 0-255.
+
+	default_utf8=   [VT]
+			Format=<0|1>
+			Set system-wide default UTF-8 mode for all tty's.
+			Default is 0 and by setting to 1, it enables UTF-8
+			mode for all newly opened or allocated terminals.
+
 	dhash_entries=	[KNL]
 			Set number of hash buckets for dentry cache.
 
@@ -673,8 +720,15 @@ and is between 256 and 4096 characters. 
 	idebus=		[HW] (E)IDE subsystem - VLB/PCI bus speed
 			See Documentation/ide.txt.
 
-	idle=		[HW]
-			Format: idle=poll or idle=halt
+	idle=		[X86]
+			Format: idle=poll or idle=mwait
+			Poll forces a polling idle loop that can slightly improves the performance
+			of waking up a idle CPU, but will use a lot of power and make the system
+			run hot. Not recommended.
+			idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose
+			to not use it because it doesn't save as much power as a normal idle
+			loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
+			as idle=poll.
 
 	ignore_loglevel	[KNL]
 			Ignore loglevel setting - this will print /all/
@@ -786,6 +840,11 @@ and is between 256 and 4096 characters. 
 	lasi=		[HW,SCSI] PARISC LASI driver for the 53c700 chip
 			Format: addr:<io>,irq:<irq>
 
+	legacy_serial.force [HW,IA-32,X86-64]
+			Probe for COM ports at legacy addresses even
+			if PNPBIOS or ACPI should describe them.  This
+			is for working around firmware defects.
+
 	llsc*=		[IA64] See function print_params() in
 			arch/ia64/sn/kernel/llsc4.c.
 
@@ -1135,6 +1194,11 @@ and is between 256 and 4096 characters. 
 
 	nomce		[IA-32] Machine Check Exception
 
+	noreplace-paravirt	[IA-32,PV_OPS] Don't patch paravirt_ops
+
+	noreplace-smp	[IA-32,SMP] Don't replace SMP instructions
+			with UP alternatives
+
 	noresidual	[PPC] Don't use residual data on PReP machines.
 
 	noresume	[SWSUSP] Disables resume and restores original swap
@@ -1540,6 +1604,20 @@ and is between 256 and 4096 characters. 
 	smart2=		[HW]
 			Format: <io1>[,<io2>[,...,<io8>]]
 
+	smp-alt-once	[IA-32,SMP] On a hotplug CPU system, only
+			attempt to substitute SMP alternatives once at boot.
+
+	smsc-ircc2.nopnp	[HW] Don't use PNP to discover SMC devices
+	smsc-ircc2.ircc_cfg=	[HW] Device configuration I/O port
+	smsc-ircc2.ircc_sir=	[HW] SIR base I/O port
+	smsc-ircc2.ircc_fir=	[HW] FIR base I/O port
+	smsc-ircc2.ircc_irq=	[HW] IRQ line
+	smsc-ircc2.ircc_dma=	[HW] DMA channel
+	smsc-ircc2.ircc_transceiver= [HW] Transceiver type:
+				0: Toshiba Satellite 1800 (GP data pin select)
+				1: Fast pin select (default)
+				2: ATC IRMode
+
 	snd-ad1816a=	[HW,ALSA]
 
 	snd-ad1848=	[HW,ALSA]
@@ -1792,12 +1870,13 @@ and is between 256 and 4096 characters. 
 			for newly-detected USB devices (default 2).  This
 			is the time required before an idle device will be
 			autosuspended.  Devices for which the delay is set
-			to 0 won't be autosuspended at all.
+			to a negative value won't be autosuspended at all.
 
 	usbhid.mousepoll=
 			[USBHID] The interval which mice are to be polled at.
 
 	vdso=		[IA-32,SH]
+			vdso=2: enable compat VDSO (default with COMPAT_VDSO)
 			vdso=1: enable VDSO (default)
 			vdso=0: disable VDSO mapping
 
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index 60c665d..81d9aa0 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -859,6 +859,18 @@ (*) To unregister a key type, call:
 	void unregister_key_type(struct key_type *type);
 
 
+Under some circumstances, it may be desirable to desirable to deal with a
+bundle of keys.  The facility provides access to the keyring type for managing
+such a bundle:
+
+	struct key_type key_type_keyring;
+
+This can be used with a function such as request_key() to find a specific
+keyring in a process's keyrings.  A keyring thus found can then be searched
+with keyring_search().  Note that it is not possible to use request_key() to
+search a specific keyring, so using keyrings in this way is of limited utility.
+
+
 ===================================
 NOTES ON ACCESSING PAYLOAD CONTENTS
 ===================================
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index d71faff..da5404a 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -14,6 +14,7 @@ CONTENTS
 8. Kprobes Example
 9. Jprobes Example
 10. Kretprobes Example
+Appendix A: The kprobes debugfs interface
 
 1. Concepts: Kprobes, Jprobes, Return Probes
 
@@ -349,9 +350,12 @@ for instrumentation and error reporting.
 
 If the number of times a function is called does not match the number
 of times it returns, registering a return probe on that function may
-produce undesirable results.  We have the do_exit() case covered.
-do_execve() and do_fork() are not an issue.  We're unaware of other
-specific cases where this could be a problem.
+produce undesirable results. In such a case, a line:
+kretprobe BUG!: Processing kretprobe d000000000041aa8 @ c00000000004f48c
+gets printed. With this information, one will be able to correlate the
+exact instance of the kretprobe that caused the problem. We have the
+do_exit() case covered. do_execve() and do_fork() are not an issue.
+We're unaware of other specific cases where this could be a problem.
 
 If, upon entry to or exit from a function, the CPU is running on
 a stack other than that of the current task, registering a return
@@ -614,3 +618,27 @@ http://www-106.ibm.com/developerworks/li
 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)
+
+
+Appendix A: The kprobes debugfs interface
+
+With recent kernels (> 2.6.20) the list of registered kprobes is visible
+under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
+
+/debug/kprobes/list: Lists all registered probes on the system
+
+c015d71a  k  vfs_read+0x0
+c011a316  j  do_fork+0x0
+c03dedc5  r  tcp_v4_rcv+0x0
+
+The first column provides the kernel address where the probe is inserted.
+The second column identifies the type of probe (k - kprobe, r - kretprobe
+and j - jprobe), while the third column specifies the symbol+offset of
+the probe. If the probed function belongs to a module, the module name
+is also specified.
+
+/debug/kprobes/enabled: Turn kprobes ON/OFF
+
+Provides a knob to globally turn registered kprobes ON or OFF. By default,
+all kprobes are enabled. By echoing "0" to this file, all registered probes
+will be disarmed, till such time a "1" is echoed to this file.
diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt
index 6f639e3..eeedee1 100644
--- a/Documentation/laptop-mode.txt
+++ b/Documentation/laptop-mode.txt
@@ -33,7 +33,7 @@ or anything. Simply install all the file
 laptop mode will automatically be started when you're on battery. For
 your convenience, a tarball containing an installer can be downloaded at:
 
-http://www.xs4all.nl/~bsamwel/laptop_mode/tools/
+http://www.samwel.tk/laptop_mode/laptop_mode/
 
 To configure laptop mode, you need to edit the configuration file, which is
 located in /etc/default/laptop-mode on Debian-based systems, or in
diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt
index 28541d2..a136721 100644
--- a/Documentation/networking/bcm43xx.txt
+++ b/Documentation/networking/bcm43xx.txt
@@ -2,35 +2,88 @@
 			BCM43xx Linux Driver Project
 			============================
 
-About this software
--------------------
+Introduction
+------------
 
-The goal of this project is to develop a linux driver for Broadcom
-BCM43xx chips, based on the specification at 
-http://bcm-specs.sipsolutions.net/
+Many of the wireless devices found in modern notebook computers are
+based on the wireless chips produced by Broadcom. These devices have
+been a problem for Linux users as there is no open-source driver
+available. In addition, Broadcom has not released specifications
+for the device, and driver availability has been limited to the
+binary-only form used in the GPL versions of AP hardware such as the
+Linksys WRT54G, and the Windows and OS X drivers.  Before this project
+began, the only way to use these devices were to use the Windows or
+OS X drivers with either the Linuxant or ndiswrapper modules. There
+is a strong penalty if this method is used as loading the binary-only
+module "taints" the kernel, and no kernel developer will help diagnose
+any kernel problems.
 
-The project page is http://bcm43xx.berlios.de/
+Development
+-----------
 
+This driver has been developed using
+a clean-room technique that is described at
+http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+reasons, none of the clean-room crew works on the on the Linux driver,
+and none of the Linux developers sees anything but the specifications,
+which are the ultimate product of the reverse-engineering group.
 
-Requirements
-------------
+Software
+--------
+
+Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+distributed with the kernel source, and is prebuilt in most, if not
+all, distributions.  There is, however, additional software that is
+required. The firmware used by the chip is the intellectual property
+of Broadcom and they have not given the bcm43xx team redistribution
+rights to this firmware.  Since we cannot legally redistribute
+the firwmare we cannot include it with the driver. Furthermore, it
+cannot be placed in the downloadable archives of any distributing
+organization; therefore, the user is responsible for obtaining the
+firmware and placing it in the appropriate location so that the driver
+can find it when initializing.
+
+To help with this process, the bcm43xx developers provide a separate
+program named bcm43xx-fwcutter to "cut" the firmware out of a
+Windows or OS X driver and write the extracted files to the proper
+location. This program is usually provided with the distribution;
+however, it may be downloaded from
+
+http://developer.berlios.de/project/showfiles.php?group_id=4547
 
-1)	Linux Kernel 2.6.16 or later
-	http://www.kernel.org/
+The firmware is available in two versions. V3 firmware is used with
+the in-kernel bcm43xx driver that uses a software MAC layer called
+SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+V4 firmware is used by an out-of-kernel driver employing a variation of
+the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+a satisfactory level of development, it will replace bcm43xx-softmac
+in the kernel as it is much more flexible and powerful.
 
-	You may want to configure your kernel with:
+A source for the latest V3 firmware is
 
-	CONFIG_DEBUG_FS (optional):
-		-> Kernel hacking
-		  -> Debug Filesystem
+http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
 
-2)	SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
-	modules:
-	http://softmac.sipsolutions.net/
+Once this file is downloaded, the command
+'bcm43xx-fwcutter -w <dir> <filename>'
+will extract the microcode and write it to directory
+<dir>. The correct directory will depend on your distribution;
+however, most use '/lib/firmware'. Once this step is completed,
+the bcm3xx driver should load when the system is booted. To see
+any messages relating to the driver, issue the command 'dmesg |
+grep bcm43xx' from a terminal window. If there are any problems,
+please send that output to Bcm43xx-dev@lists.berlios.de.
 
-3)	Firmware Files
+Although the driver has been in-kernel since 2.6.17, the earliest
+version is quite limited in its capability. Patches that include
+all features of later versions are available for the stable kernel
+versions from 2.6.18. These will be needed if you use a BCM4318,
+or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+have an early BCM4306 and more than 1 GB RAM, your kernel will need
+to be patched.	These patches, which are being updated regularly,
+are available at ftp://lwfinger.dynalias.org/patches. Look for
+combined_2.6.YY.patch. Of course you will need kernel source downloaded
+from kernel.org, or the source from your distribution.
 
-	Please try fwcutter. Fwcutter can extract the firmware from various 
-	binary driver files. It supports driver files from Windows, MacOS and 
-	Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
-	Also, fwcutter comes with a README file for further instructions.
+If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+essential for solving any problems.
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index de809e5..1da5666 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -920,40 +920,9 @@ options, you may wish to use the "max_bo
 documented above.
 
 	To create multiple bonding devices with differing options, it
-is necessary to load the bonding driver multiple times.  Note that
-current versions of the sysconfig network initialization scripts
-handle this automatically; if your distro uses these scripts, no
-special action is needed.  See the section Configuring Bonding
-Devices, above, if you're not sure about your network initialization
-scripts.
-
-	To load multiple instances of the module, it is necessary to
-specify a different name for each instance (the module loading system
-requires that every loaded module, even multiple instances of the same
-module, have a unique name).  This is accomplished by supplying
-multiple sets of bonding options in /etc/modprobe.conf, for example:
-	
-alias bond0 bonding
-options bond0 -o bond0 mode=balance-rr miimon=100
-
-alias bond1 bonding
-options bond1 -o bond1 mode=balance-alb miimon=50
-
-	will load the bonding module two times.  The first instance is
-named "bond0" and creates the bond0 device in balance-rr mode with an
-miimon of 100.  The second instance is named "bond1" and creates the
-bond1 device in balance-alb mode with an miimon of 50.
-
-	In some circumstances (typically with older distributions),
-the above does not work, and the second bonding instance never sees
-its options.  In that case, the second options line can be substituted
-as follows:
-
-install bond1 /sbin/modprobe --ignore-install bonding -o bond1 \
-	mode=balance-alb miimon=50
+is necessary to use bonding parameters exported by sysfs, documented
+in the section below.
 
-	This may be repeated any number of times, specifying a new and
-unique name in place of bond1 for each subsequent instance.
 
 3.4 Configuring Bonding Manually via Sysfs
 ------------------------------------------
diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt
index 387482e..4504cc5 100644
--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,16 @@ DCCP_SOCKOPT_SEND_CSCOV is for the recei
 	coverage value are also acceptable. The higher the number, the more
 	restrictive this setting (see [RFC 4340, sec. 9.2.1]).
 
+The following two options apply to CCID 3 exclusively and are getsockopt()-only.
+In either case, a TFRC info struct (defined in <linux/tfrc.h>) is returned.
+DCCP_SOCKOPT_CCID_RX_INFO
+	Returns a `struct tfrc_rx_info' in optval; the buffer for optval and
+	optlen must be set to at least sizeof(struct tfrc_rx_info).
+DCCP_SOCKOPT_CCID_TX_INFO
+	Returns a `struct tfrc_tx_info' in optval; the buffer for optval and
+	optlen must be set to at least sizeof(struct tfrc_tx_info).
+
+
 Sysctl variables
 ================
 Several DCCP default parameters can be managed by the following sysctls
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 702d1d8..af6a63a 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -179,11 +179,31 @@ tcp_fin_timeout - INTEGER
 	because they eat maximum 1.5K of memory, but they tend
 	to live longer.	Cf. tcp_max_orphans.
 
-tcp_frto - BOOLEAN
+tcp_frto - INTEGER
 	Enables F-RTO, an enhanced recovery algorithm for TCP retransmission
 	timeouts.  It is particularly beneficial in wireless environments
 	where packet loss is typically due to random radio interference
-	rather than intermediate router congestion.
+	rather than intermediate router congestion. If set to 1, basic
+	version is enabled. 2 enables SACK enhanced F-RTO, which is
+	EXPERIMENTAL. The basic version can be used also when SACK is
+	enabled for a flow through tcp_sack sysctl.
+
+tcp_frto_response - INTEGER
+	When F-RTO has detected that a TCP retransmission timeout was
+	spurious (i.e, the timeout would have been avoided had TCP set a
+	longer retransmission timeout), TCP has several options what to do
+	next. Possible values are:
+		0 Rate halving based; a smooth and conservative response,
+		  results in halved cwnd and ssthresh after one RTT
+		1 Very conservative response; not recommended because even
+		  though being valid, it interacts poorly with the rest of
+		  Linux TCP, halves cwnd and ssthresh immediately
+		2 Aggressive response; undoes congestion control measures
+		  that are now known to be unnecessary (ignoring the
+		  possibility of a lost retransmission that would require
+		  TCP to be more cautious), cwnd and ssthresh are restored
+		  to the values prior timeout
+	Default: 0 (rate halving based)
 
 tcp_keepalive_time - INTEGER
 	How often TCP sends out keepalive messages when keepalive is enabled.
@@ -995,7 +1015,12 @@ bridge-nf-call-ip6tables - BOOLEAN
 	Default: 1
 
 bridge-nf-filter-vlan-tagged - BOOLEAN
-	1 : pass bridged vlan-tagged ARP/IP traffic to arptables/iptables.
+	1 : pass bridged vlan-tagged ARP/IP/IPv6 traffic to {arp,ip,ip6}tables.
+	0 : disable this.
+	Default: 1
+
+bridge-nf-filter-pppoe-tagged - BOOLEAN
+	1 : pass bridged pppoe-tagged IP/IPv6 traffic to {ip,ip6}tables.
 	0 : disable this.
 	Default: 1
 
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt
new file mode 100644
index 0000000..cae231b
--- /dev/null
+++ b/Documentation/networking/rxrpc.txt
@@ -0,0 +1,859 @@
+			    ======================
+			    RxRPC NETWORK PROTOCOL
+			    ======================
+
+The RxRPC protocol driver provides a reliable two-phase transport on top of UDP
+that can be used to perform RxRPC remote operations.  This is done over sockets
+of AF_RXRPC family, using sendmsg() and recvmsg() with control data to send and
+receive data, aborts and errors.
+
+Contents of this document:
+
+ (*) Overview.
+
+ (*) RxRPC protocol summary.
+
+ (*) AF_RXRPC driver model.
+
+ (*) Control messages.
+
+ (*) Socket options.
+
+ (*) Security.
+
+ (*) Example client usage.
+
+ (*) Example server usage.
+
+ (*) AF_RXRPC kernel interface.
+
+
+========
+OVERVIEW
+========
+
+RxRPC is a two-layer protocol.  There is a session layer which provides
+reliable virtual connections using UDP over IPv4 (or IPv6) as the transport
+layer, but implements a real network protocol; and there's the presentation
+layer which renders structured data to binary blobs and back again using XDR
+(as does SunRPC):
+
+		+-------------+
+		| Application |
+		+-------------+
+		|     XDR     |		Presentation
+		+-------------+
+		|    RxRPC    |		Session
+		+-------------+
+		|     UDP     |		Transport
+		+-------------+
+
+
+AF_RXRPC provides:
+
+ (1) Part of an RxRPC facility for both kernel and userspace applications by
+     making the session part of it a Linux network protocol (AF_RXRPC).
+
+ (2) A two-phase protocol.  The client transmits a blob (the request) and then
+     receives a blob (the reply), and the server receives the request and then
+     transmits the reply.
+
+ (3) Retention of the reusable bits of the transport system set up for one call
+     to speed up subsequent calls.
+
+ (4) A secure protocol, using the Linux kernel's key retention facility to
+     manage security on the client end.  The server end must of necessity be
+     more active in security negotiations.
+
+AF_RXRPC does not provide XDR marshalling/presentation facilities.  That is
+left to the application.  AF_RXRPC only deals in blobs.  Even the operation ID
+is just the first four bytes of the request blob, and as such is beyond the
+kernel's interest.
+
+
+Sockets of AF_RXRPC family are:
+
+ (1) created as type SOCK_DGRAM;
+
+ (2) provided with a protocol of the type of underlying transport they're going
+     to use - currently only PF_INET is supported.
+
+
+The Andrew File System (AFS) is an example of an application that uses this and
+that has both kernel (filesystem) and userspace (utility) components.
+
+
+======================
+RXRPC PROTOCOL SUMMARY
+======================
+
+An overview of the RxRPC protocol:
+
+ (*) RxRPC sits on top of another networking protocol (UDP is the only option
+     currently), and uses this to provide network transport.  UDP ports, for
+     example, provide transport endpoints.
+
+ (*) RxRPC supports multiple virtual "connections" from any given transport
+     endpoint, thus allowing the endpoints to be shared, even to the same
+     remote endpoint.
+
+ (*) Each connection goes to a particular "service".  A connection may not go
+     to multiple services.  A service may be considered the RxRPC equivalent of
+     a port number.  AF_RXRPC permits multiple services to share an endpoint.
+
+ (*) Client-originating packets are marked, thus a transport endpoint can be
+     shared between client and server connections (connections have a
+     direction).
+
+ (*) Up to a billion connections may be supported concurrently between one
+     local transport endpoint and one service on one remote endpoint.  An RxRPC
+     connection is described by seven numbers:
+
+	Local address	}
+	Local port	} Transport (UDP) address
+	Remote address	}
+	Remote port	}
+	Direction
+	Connection ID
+	Service ID
+
+ (*) Each RxRPC operation is a "call".  A connection may make up to four
+     billion calls, but only up to four calls may be in progress on a
+     connection at any one time.
+
+ (*) Calls are two-phase and asymmetric: the client sends its request data,
+     which the service receives; then the service transmits the reply data
+     which the client receives.
+
+ (*) The data blobs are of indefinite size, the end of a phase is marked with a
+     flag in the packet.  The number of packets of data making up one blob may
+     not exceed 4 billion, however, as this would cause the sequence number to
+     wrap.
+
+ (*) The first four bytes of the request data are the service operation ID.
+
+ (*) Security is negotiated on a per-connection basis.  The connection is
+     initiated by the first data packet on it arriving.  If security is
+     requested, the server then issues a "challenge" and then the client
+     replies with a "response".  If the response is successful, the security is
+     set for the lifetime of that connection, and all subsequent calls made
+     upon it use that same security.  In the event that the server lets a
+     connection lapse before the client, the security will be renegotiated if
+     the client uses the connection again.
+
+ (*) Calls use ACK packets to handle reliability.  Data packets are also
+     explicitly sequenced per call.
+
+ (*) There are two types of positive acknowledgement: hard-ACKs and soft-ACKs.
+     A hard-ACK indicates to the far side that all the data received to a point
+     has been received and processed; a soft-ACK indicates that the data has
+     been received but may yet be discarded and re-requested.  The sender may
+     not discard any transmittable packets until they've been hard-ACK'd.
+
+ (*) Reception of a reply data packet implicitly hard-ACK's all the data
+     packets that make up the request.
+
+ (*) An call is complete when the request has been sent, the reply has been
+     received and the final hard-ACK on the last packet of the reply has
+     reached the server.
+
+ (*) An call may be aborted by either end at any time up to its completion.
+
+
+=====================
+AF_RXRPC DRIVER MODEL
+=====================
+
+About the AF_RXRPC driver:
+
+ (*) The AF_RXRPC protocol transparently uses internal sockets of the transport
+     protocol to represent transport endpoints.
+
+ (*) AF_RXRPC sockets map onto RxRPC connection bundles.  Actual RxRPC
+     connections are handled transparently.  One client socket may be used to
+     make multiple simultaneous calls to the same service.  One server socket
+     may handle calls from many clients.
+
+ (*) Additional parallel client connections will be initiated to support extra
+     concurrent calls, up to a tunable limit.
+
+ (*) Each connection is retained for a certain amount of time [tunable] after
+     the last call currently using it has completed in case a new call is made
+     that could reuse it.
+
+ (*) Each internal UDP socket is retained [tunable] for a certain amount of
+     time [tunable] after the last connection using it discarded, in case a new
+     connection is made that could use it.
+
+ (*) A client-side connection is only shared between calls if they have have
+     the same key struct describing their security (and assuming the calls
+     would otherwise share the connection).  Non-secured calls would also be
+     able to share connections with each other.
+
+ (*) A server-side connection is shared if the client says it is.
+
+ (*) ACK'ing is handled by the protocol driver automatically, including ping
+     replying.
+
+ (*) SO_KEEPALIVE automatically pings the other side to keep the connection
+     alive [TODO].
+
+ (*) If an ICMP error is received, all calls affected by that error will be
+     aborted with an appropriate network error passed through recvmsg().
+
+
+Interaction with the user of the RxRPC socket:
+
+ (*) A socket is made into a server socket by binding an address with a
+     non-zero service ID.
+
+ (*) In the client, sending a request is achieved with one or more sendmsgs,
+     followed by the reply being received with one or more recvmsgs.
+
+ (*) The first sendmsg for a request to be sent from a client contains a tag to
+     be used in all other sendmsgs or recvmsgs associated with that call.  The
+     tag is carried in the control data.
+
+ (*) connect() is used to supply a default destination address for a client
+     socket.  This may be overridden by supplying an alternate address to the
+     first sendmsg() of a call (struct msghdr::msg_name).
+
+ (*) If connect() is called on an unbound client, a random local port will
+     bound before the operation takes place.
+
+ (*) A server socket may also be used to make client calls.  To do this, the
+     first sendmsg() of the call must specify the target address.  The server's
+     transport endpoint is used to send the packets.
+
+ (*) Once the application has received the last message associated with a call,
+     the tag is guaranteed not to be seen again, and so it can be used to pin
+     client resources.  A new call can then be initiated with the same tag
+     without fear of interference.
+
+ (*) In the server, a request is received with one or more recvmsgs, then the
+     the reply is transmitted with one or more sendmsgs, and then the final ACK
+     is received with a last recvmsg.
+
+ (*) When sending data for a call, sendmsg is given MSG_MORE if there's more
+     data to come on that call.
+
+ (*) When receiving data for a call, recvmsg flags MSG_MORE if there's more
+     data to come for that call.
+
+ (*) When receiving data or messages for a call, MSG_EOR is flagged by recvmsg
+     to indicate the terminal message for that call.
+
+ (*) A call may be aborted by adding an abort control message to the control
+     data.  Issuing an abort terminates the kernel's use of that call's tag.
+     Any messages waiting in the receive queue for that call will be discarded.
+
+ (*) Aborts, busy notifications and challenge packets are delivered by recvmsg,
+     and control data messages will be set to indicate the context.  Receiving
+     an abort or a busy message terminates the kernel's use of that call's tag.
+
+ (*) The control data part of the msghdr struct is used for a number of things:
+
+     (*) The tag of the intended or affected call.
+
+     (*) Sending or receiving errors, aborts and busy notifications.
+
+     (*) Notifications of incoming calls.
+
+     (*) Sending debug requests and receiving debug replies [TODO].
+
+ (*) When the kernel has received and set up an incoming call, it sends a
+     message to server application to let it know there's a new call awaiting
+     its acceptance [recvmsg reports a special control message].  The server
+     application then uses sendmsg to assign a tag to the new call.  Once that
+     is done, the first part of the request data will be delivered by recvmsg.
+
+ (*) The server application has to provide the server socket with a keyring of
+     secret keys corresponding to the security types it permits.  When a secure
+     connection is being set up, the kernel looks up the appropriate secret key
+     in the keyring and then sends a challenge packet to the client and
+     receives a response packet.  The kernel then checks the authorisation of
+     the packet and either aborts the connection or sets up the security.
+
+ (*) The name of the key a client will use to secure its communications is
+     nominated by a socket option.
+
+
+Notes on recvmsg:
+
+ (*) If there's a sequence of data messages belonging to a particular call on
+     the receive queue, then recvmsg will keep working through them until:
+
+     (a) it meets the end of that call's received data,
+
+     (b) it meets a non-data message,
+
+     (c) it meets a message belonging to a different call, or
+
+     (d) it fills the user buffer.
+
+     If recvmsg is called in blocking mode, it will keep sleeping, awaiting the
+     reception of further data, until one of the above four conditions is met.
+
+ (2) MSG_PEEK operates similarly, but will return immediately if it has put any
+     data in the buffer rather than sleeping until it can fill the buffer.
+
+ (3) If a data message is only partially consumed in filling a user buffer,
+     then the remainder of that message will be left on the front of the queue
+     for the next taker.  MSG_TRUNC will never be flagged.
+
+ (4) If there is more data to be had on a call (it hasn't copied the last byte
+     of the last data message in that phase yet), then MSG_MORE will be
+     flagged.
+
+
+================
+CONTROL MESSAGES
+================
+
+AF_RXRPC makes use of control messages in sendmsg() and recvmsg() to multiplex
+calls, to invoke certain actions and to report certain conditions.  These are:
+
+	MESSAGE ID		SRT DATA	MEANING
+	=======================	=== ===========	===============================
+	RXRPC_USER_CALL_ID	sr- User ID	App's call specifier
+	RXRPC_ABORT		srt Abort code	Abort code to issue/received
+	RXRPC_ACK		-rt n/a		Final ACK received
+	RXRPC_NET_ERROR		-rt error num	Network error on call
+	RXRPC_BUSY		-rt n/a		Call rejected (server busy)
+	RXRPC_LOCAL_ERROR	-rt error num	Local error encountered
+	RXRPC_NEW_CALL		-r- n/a		New call received
+	RXRPC_ACCEPT		s-- n/a		Accept new call
+
+	(SRT = usable in Sendmsg / delivered by Recvmsg / Terminal message)
+
+ (*) RXRPC_USER_CALL_ID
+
+     This is used to indicate the application's call ID.  It's an unsigned long
+     that the app specifies in the client by attaching it to the first data
+     message or in the server by passing it in association with an RXRPC_ACCEPT
+     message.  recvmsg() passes it in conjunction with all messages except
+     those of the RXRPC_NEW_CALL message.
+
+ (*) RXRPC_ABORT
+
+     This is can be used by an application to abort a call by passing it to
+     sendmsg, or it can be delivered by recvmsg to indicate a remote abort was
+     received.  Either way, it must be associated with an RXRPC_USER_CALL_ID to
+     specify the call affected.  If an abort is being sent, then error EBADSLT
+     will be returned if there is no call with that user ID.
+
+ (*) RXRPC_ACK
+
+     This is delivered to a server application to indicate that the final ACK
+     of a call was received from the client.  It will be associated with an
+     RXRPC_USER_CALL_ID to indicate the call that's now complete.
+
+ (*) RXRPC_NET_ERROR
+
+     This is delivered to an application to indicate that an ICMP error message
+     was encountered in the process of trying to talk to the peer.  An
+     errno-class integer value will be included in the control message data
+     indicating the problem, and an RXRPC_USER_CALL_ID will indicate the call
+     affected.
+
+ (*) RXRPC_BUSY
+
+     This is delivered to a client application to indicate that a call was
+     rejected by the server due to the server being busy.  It will be
+     associated with an RXRPC_USER_CALL_ID to indicate the rejected call.
+
+ (*) RXRPC_LOCAL_ERROR
+
+     This is delivered to an application to indicate that a local error was
+     encountered and that a call has been aborted because of it.  An
+     errno-class integer value will be included in the control message data
+     indicating the problem, and an RXRPC_USER_CALL_ID will indicate the call
+     affected.
+
+ (*) RXRPC_NEW_CALL
+
+     This is delivered to indicate to a server application that a new call has
+     arrived and is awaiting acceptance.  No user ID is associated with this,
+     as a user ID must subsequently be assigned by doing an RXRPC_ACCEPT.
+
+ (*) RXRPC_ACCEPT
+
+     This is used by a server application to attempt to accept a call and
+     assign it a user ID.  It should be associated with an RXRPC_USER_CALL_ID
+     to indicate the user ID to be assigned.  If there is no call to be
+     accepted (it may have timed out, been aborted, etc.), then sendmsg will
+     return error ENODATA.  If the user ID is already in use by another call,
+     then error EBADSLT will be returned.
+
+
+==============
+SOCKET OPTIONS
+==============
+
+AF_RXRPC sockets support a few socket options at the SOL_RXRPC level:
+
+ (*) RXRPC_SECURITY_KEY
+
+     This is used to specify the description of the key to be used.  The key is
+     extracted from the calling process's keyrings with request_key() and
+     should be of "rxrpc" type.
+
+     The optval pointer points to the description string, and optlen indicates
+     how long the string is, without the NUL terminator.
+
+ (*) RXRPC_SECURITY_KEYRING
+
+     Similar to above but specifies a keyring of server secret keys to use (key
+     type "keyring").  See the "Security" section.
+
+ (*) RXRPC_EXCLUSIVE_CONNECTION
+
+     This is used to request that new connections should be used for each call
+     made subsequently on this socket.  optval should be NULL and optlen 0.
+
+ (*) RXRPC_MIN_SECURITY_LEVEL
+
+     This is used to specify the minimum security level required for calls on
+     this socket.  optval must point to an int containing one of the following
+     values:
+
+     (a) RXRPC_SECURITY_PLAIN
+
+	 Encrypted checksum only.
+
+     (b) RXRPC_SECURITY_AUTH
+
+	 Encrypted checksum plus packet padded and first eight bytes of packet
+	 encrypted - which includes the actual packet length.
+
+     (c) RXRPC_SECURITY_ENCRYPTED
+
+	 Encrypted checksum plus entire packet padded and encrypted, including
+	 actual packet length.
+
+
+========
+SECURITY
+========
+
+Currently, only the kerberos 4 equivalent protocol has been implemented
+(security index 2 - rxkad).  This requires the rxkad module to be loaded and,
+on the client, tickets of the appropriate type to be obtained from the AFS
+kaserver or the kerberos server and installed as "rxrpc" type keys.  This is
+normally done using the klog program.  An example simple klog program can be
+found at:
+
+	http://people.redhat.com/~dhowells/rxrpc/klog.c
+
+The payload provided to add_key() on the client should be of the following
+form:
+
+	struct rxrpc_key_sec2_v1 {
+		uint16_t	security_index;	/* 2 */
+		uint16_t	ticket_length;	/* length of ticket[] */
+		uint32_t	expiry;		/* time at which expires */
+		uint8_t		kvno;		/* key version number */
+		uint8_t		__pad[3];
+		uint8_t		session_key[8];	/* DES session key */
+		uint8_t		ticket[0];	/* the encrypted ticket */
+	};
+
+Where the ticket blob is just appended to the above structure.
+
+
+For the server, keys of type "rxrpc_s" must be made available to the server.
+They have a description of "<serviceID>:<securityIndex>" (eg: "52:2" for an
+rxkad key for the AFS VL service).  When such a key is created, it should be
+given the server's secret key as the instantiation data (see the example
+below).
+
+	add_key("rxrpc_s", "52:2", secret_key, 8, keyring);
+
+A keyring is passed to the server socket by naming it in a sockopt.  The server
+socket then looks the server secret keys up in this keyring when secure
+incoming connections are made.  This can be seen in an example program that can
+be found at:
+
+	http://people.redhat.com/~dhowells/rxrpc/listen.c
+
+
+====================
+EXAMPLE CLIENT USAGE
+====================
+
+A client would issue an operation by:
+
+ (1) An RxRPC socket is set up by:
+
+	client = socket(AF_RXRPC, SOCK_DGRAM, PF_INET);
+
+     Where the third parameter indicates the protocol family of the transport
+     socket used - usually IPv4 but it can also be IPv6 [TODO].
+
+ (2) A local address can optionally be bound:
+
+	struct sockaddr_rxrpc srx = {
+		.srx_family	= AF_RXRPC,
+		.srx_service	= 0,  /* we're a client */
+		.transport_type	= SOCK_DGRAM,	/* type of transport socket */
+		.transport.sin_family	= AF_INET,
+		.transport.sin_port	= htons(7000), /* AFS callback */
+		.transport.sin_address	= 0,  /* all local interfaces */
+	};
+	bind(client, &srx, sizeof(srx));
+
+     This specifies the local UDP port to be used.  If not given, a random
+     non-privileged port will be used.  A UDP port may be shared between
+     several unrelated RxRPC sockets.  Security is handled on a basis of
+     per-RxRPC virtual connection.
+
+ (3) The security is set:
+
+	const char *key = "AFS:cambridge.redhat.com";
+	setsockopt(client, SOL_RXRPC, RXRPC_SECURITY_KEY, key, strlen(key));
+
+     This issues a request_key() to get the key representing the security
+     context.  The minimum security level can be set:
+
+	unsigned int sec = RXRPC_SECURITY_ENCRYPTED;
+	setsockopt(client, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL,
+		   &sec, sizeof(sec));
+
+ (4) The server to be contacted can then be specified (alternatively this can
+     be done through sendmsg):
+
+	struct sockaddr_rxrpc srx = {
+		.srx_family	= AF_RXRPC,
+		.srx_service	= VL_SERVICE_ID,
+		.transport_type	= SOCK_DGRAM,	/* type of transport socket */
+		.transport.sin_family	= AF_INET,
+		.transport.sin_port	= htons(7005), /* AFS volume manager */
+		.transport.sin_address	= ...,
+	};
+	connect(client, &srx, sizeof(srx));
+
+ (5) The request data should then be posted to the server socket using a series
+     of sendmsg() calls, each with the following control message attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+
+     MSG_MORE should be set in msghdr::msg_flags on all but the last part of
+     the request.  Multiple requests may be made simultaneously.
+
+     If a call is intended to go to a destination other then the default
+     specified through connect(), then msghdr::msg_name should be set on the
+     first request message of that call.
+
+ (6) The reply data will then be posted to the server socket for recvmsg() to
+     pick up.  MSG_MORE will be flagged by recvmsg() if there's more reply data
+     for a particular call to be read.  MSG_EOR will be set on the terminal
+     read for a call.
+
+     All data will be delivered with the following control message attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+
+     If an abort or error occurred, this will be returned in the control data
+     buffer instead, and MSG_EOR will be flagged to indicate the end of that
+     call.
+
+
+====================
+EXAMPLE SERVER USAGE
+====================
+
+A server would be set up to accept operations in the following manner:
+
+ (1) An RxRPC socket is created by:
+
+	server = socket(AF_RXRPC, SOCK_DGRAM, PF_INET);
+
+     Where the third parameter indicates the address type of the transport
+     socket used - usually IPv4.
+
+ (2) Security is set up if desired by giving the socket a keyring with server
+     secret keys in it:
+
+	keyring = add_key("keyring", "AFSkeys", NULL, 0,
+			  KEY_SPEC_PROCESS_KEYRING);
+
+	const char secret_key[8] = {
+		0xa7, 0x83, 0x8a, 0xcb, 0xc7, 0x83, 0xec, 0x94 };
+	add_key("rxrpc_s", "52:2", secret_key, 8, keyring);
+
+	setsockopt(server, SOL_RXRPC, RXRPC_SECURITY_KEYRING, "AFSkeys", 7);
+
+     The keyring can be manipulated after it has been given to the socket. This
+     permits the server to add more keys, replace keys, etc. whilst it is live.
+
+ (2) A local address must then be bound:
+
+	struct sockaddr_rxrpc srx = {
+		.srx_family	= AF_RXRPC,
+		.srx_service	= VL_SERVICE_ID, /* RxRPC service ID */
+		.transport_type	= SOCK_DGRAM,	/* type of transport socket */
+		.transport.sin_family	= AF_INET,
+		.transport.sin_port	= htons(7000), /* AFS callback */
+		.transport.sin_address	= 0,  /* all local interfaces */
+	};
+	bind(server, &srx, sizeof(srx));
+
+ (3) The server is then set to listen out for incoming calls:
+
+	listen(server, 100);
+
+ (4) The kernel notifies the server of pending incoming connections by sending
+     it a message for each.  This is received with recvmsg() on the server
+     socket.  It has no data, and has a single dataless control message
+     attached:
+
+	RXRPC_NEW_CALL
+
+     The address that can be passed back by recvmsg() at this point should be
+     ignored since the call for which the message was posted may have gone by
+     the time it is accepted - in which case the first call still on the queue
+     will be accepted.
+
+ (5) The server then accepts the new call by issuing a sendmsg() with two
+     pieces of control data and no actual data:
+
+	RXRPC_ACCEPT		- indicate connection acceptance
+	RXRPC_USER_CALL_ID	- specify user ID for this call
+
+ (6) The first request data packet will then be posted to the server socket for
+     recvmsg() to pick up.  At that point, the RxRPC address for the call can
+     be read from the address fields in the msghdr struct.
+
+     Subsequent request data will be posted to the server socket for recvmsg()
+     to collect as it arrives.  All but the last piece of the request data will
+     be delivered with MSG_MORE flagged.
+
+     All data will be delivered with the following control message attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+
+ (8) The reply data should then be posted to the server socket using a series
+     of sendmsg() calls, each with the following control messages attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+
+     MSG_MORE should be set in msghdr::msg_flags on all but the last message
+     for a particular call.
+
+ (9) The final ACK from the client will be posted for retrieval by recvmsg()
+     when it is received.  It will take the form of a dataless message with two
+     control messages attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+	RXRPC_ACK		- indicates final ACK (no data)
+
+     MSG_EOR will be flagged to indicate that this is the final message for
+     this call.
+
+(10) Up to the point the final packet of reply data is sent, the call can be
+     aborted by calling sendmsg() with a dataless message with the following
+     control messages attached:
+
+	RXRPC_USER_CALL_ID	- specifies the user ID for this call
+	RXRPC_ABORT		- indicates abort code (4 byte data)
+
+     Any packets waiting in the socket's receive queue will be discarded if
+     this is issued.
+
+Note that all the communications for a particular service take place through
+the one server socket, using control messages on sendmsg() and recvmsg() to
+determine the call affected.
+
+
+=========================
+AF_RXRPC KERNEL INTERFACE
+=========================
+
+The AF_RXRPC module also provides an interface for use by in-kernel utilities
+such as the AFS filesystem.  This permits such a utility to:
+
+ (1) Use different keys directly on individual client calls on one socket
+     rather than having to open a whole slew of sockets, one for each key it
+     might want to use.
+
+ (2) Avoid having RxRPC call request_key() at the point of issue of a call or
+     opening of a socket.  Instead the utility is responsible for requesting a
+     key at the appropriate point.  AFS, for instance, would do this during VFS
+     operations such as open() or unlink().  The key is then handed through
+     when the call is initiated.
+
+ (3) Request the use of something other than GFP_KERNEL to allocate memory.
+
+ (4) Avoid the overhead of using the recvmsg() call.  RxRPC messages can be
+     intercepted before they get put into the socket Rx queue and the socket
+     buffers manipulated directly.
+
+To use the RxRPC facility, a kernel utility must still open an AF_RXRPC socket,
+bind an addess as appropriate and listen if it's to be a server socket, but
+then it passes this to the kernel interface functions.
+
+The kernel interface functions are as follows:
+
+ (*) Begin a new client call.
+
+	struct rxrpc_call *
+	rxrpc_kernel_begin_call(struct socket *sock,
+				struct sockaddr_rxrpc *srx,
+				struct key *key,
+				unsigned long user_call_ID,
+				gfp_t gfp);
+
+     This allocates the infrastructure to make a new RxRPC call and assigns
+     call and connection numbers.  The call will be made on the UDP port that
+     the socket is bound to.  The call will go to the destination address of a
+     connected client socket unless an alternative is supplied (srx is
+     non-NULL).
+
+     If a key is supplied then this will be used to secure the call instead of
+     the key bound to the socket with the RXRPC_SECURITY_KEY sockopt.  Calls
+     secured in this way will still share connections if at all possible.
+
+     The user_call_ID is equivalent to that supplied to sendmsg() in the
+     control data buffer.  It is entirely feasible to use this to point to a
+     kernel data structure.
+
+     If this function is successful, an opaque reference to the RxRPC call is
+     returned.  The caller now holds a reference on this and it must be
+     properly ended.
+
+ (*) End a client call.
+
+	void rxrpc_kernel_end_call(struct rxrpc_call *call);
+
+     This is used to end a previously begun call.  The user_call_ID is expunged
+     from AF_RXRPC's knowledge and will not be seen again in association with
+     the specified call.
+
+ (*) Send data through a call.
+
+	int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,
+				   size_t len);
+
+     This is used to supply either the request part of a client call or the
+     reply part of a server call.  msg.msg_iovlen and msg.msg_iov specify the
+     data buffers to be used.  msg_iov may not be NULL and must point
+     exclusively to in-kernel virtual addresses.  msg.msg_flags may be given
+     MSG_MORE if there will be subsequent data sends for this call.
+
+     The msg must not specify a destination address, control data or any flags
+     other than MSG_MORE.  len is the total amount of data to transmit.
+
+ (*) Abort a call.
+
+	void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code);
+
+     This is used to abort a call if it's still in an abortable state.  The
+     abort code specified will be placed in the ABORT message sent.
+
+ (*) Intercept received RxRPC messages.
+
+	typedef void (*rxrpc_interceptor_t)(struct sock *sk,
+					    unsigned long user_call_ID,
+					    struct sk_buff *skb);
+
+	void
+	rxrpc_kernel_intercept_rx_messages(struct socket *sock,
+					   rxrpc_interceptor_t interceptor);
+
+     This installs an interceptor function on the specified AF_RXRPC socket.
+     All messages that would otherwise wind up in the socket's Rx queue are
+     then diverted to this function.  Note that care must be taken to process
+     the messages in the right order to maintain DATA message sequentiality.
+
+     The interceptor function itself is provided with the address of the socket
+     and handling the incoming message, the ID assigned by the kernel utility
+     to the call and the socket buffer containing the message.
+
+     The skb->mark field indicates the type of message:
+
+	MARK				MEANING
+	===============================	=======================================
+	RXRPC_SKB_MARK_DATA		Data message
+	RXRPC_SKB_MARK_FINAL_ACK	Final ACK received for an incoming call
+	RXRPC_SKB_MARK_BUSY		Client call rejected as server busy
+	RXRPC_SKB_MARK_REMOTE_ABORT	Call aborted by peer
+	RXRPC_SKB_MARK_NET_ERROR	Network error detected
+	RXRPC_SKB_MARK_LOCAL_ERROR	Local error encountered
+	RXRPC_SKB_MARK_NEW_CALL		New incoming call awaiting acceptance
+
+     The remote abort message can be probed with rxrpc_kernel_get_abort_code().
+     The two error messages can be probed with rxrpc_kernel_get_error_number().
+     A new call can be accepted with rxrpc_kernel_accept_call().
+
+     Data messages can have their contents extracted with the usual bunch of
+     socket buffer manipulation functions.  A data message can be determined to
+     be the last one in a sequence with rxrpc_kernel_is_data_last().  When a
+     data message has been used up, rxrpc_kernel_data_delivered() should be
+     called on it..
+
+     Non-data messages should be handled to rxrpc_kernel_free_skb() to dispose
+     of.  It is possible to get extra refs on all types of message for later
+     freeing, but this may pin the state of a call until the message is finally
+     freed.
+
+ (*) Accept an incoming call.
+
+	struct rxrpc_call *
+	rxrpc_kernel_accept_call(struct socket *sock,
+				 unsigned long user_call_ID);
+
+     This is used to accept an incoming call and to assign it a call ID.  This
+     function is similar to rxrpc_kernel_begin_call() and calls accepted must
+     be ended in the same way.
+
+     If this function is successful, an opaque reference to the RxRPC call is
+     returned.  The caller now holds a reference on this and it must be
+     properly ended.
+
+ (*) Reject an incoming call.
+
+	int rxrpc_kernel_reject_call(struct socket *sock);
+
+     This is used to reject the first incoming call on the socket's queue with
+     a BUSY message.  -ENODATA is returned if there were no incoming calls.
+     Other errors may be returned if the call had been aborted (-ECONNABORTED)
+     or had timed out (-ETIME).
+
+ (*) Record the delivery of a data message and free it.
+
+	void rxrpc_kernel_data_delivered(struct sk_buff *skb);
+
+     This is used to record a data message as having been delivered and to
+     update the ACK state for the call.  The socket buffer will be freed.
+
+ (*) Free a message.
+
+	void rxrpc_kernel_free_skb(struct sk_buff *skb);
+
+     This is used to free a non-DATA socket buffer intercepted from an AF_RXRPC
+     socket.
+
+ (*) Determine if a data message is the last one on a call.
+
+	bool rxrpc_kernel_is_data_last(struct sk_buff *skb);
+
+     This is used to determine if a socket buffer holds the last data message
+     to be received for a call (true will be returned if it does, false
+     if not).
+
+     The data message will be part of the reply on a client call and the
+     request on an incoming call.  In the latter case there will be more
+     messages, but in the former case there will not.
+
+ (*) Get the abort code from an abort message.
+
+	u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb);
+
+     This is used to extract the abort code from a remote abort message.
+
+ (*) Get the error number from a local or network error message.
+
+	int rxrpc_kernel_get_error_number(struct sk_buff *skb);
+
+     This is used to extract the error number from a message indicating either
+     a local error occurred or a network error occurred.
diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
index 653978d..07dd6d9 100644
--- a/Documentation/networking/wan-router.txt
+++ b/Documentation/networking/wan-router.txt
@@ -250,7 +250,6 @@ PRODUCT COMPONENTS AND RELATED FILES
 	sdladrv.h	SDLA support module API definitions
 	sdlasfm.h	SDLA firmware module definitions
 	if_wanpipe.h	WANPIPE Socket definitions
-	if_wanpipe_common.h	WANPIPE Socket/Driver common definitions.
 	sdlapci.h	WANPIPE PCI definitions
 	
 
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index ea55ea8..7d5b60d 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -234,9 +234,6 @@ characters, each representing a particul
   6: 'B' if a page-release function has found a bad page reference or
      some unexpected page flags.
 
-  7: 'U' if a user specifically requested that the Tainted flag be set,
-     ' ' otherwise.
-
   7: 'U' if a user or user application specifically requested that the
      Tainted flag be set, ' ' otherwise.
 
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index cdf2f3c..e2c9d0a 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -124,10 +124,6 @@ (struct pci_driver):
 
 	err_handler	See Documentation/pci-error-recovery.txt
 
-	multithread_probe	Enable multi-threaded probe/scan. Driver must
-			provide its own locking/syncronization for init
-			operations if this is enabled.
-
 
 The ID table is an array of struct pci_device_id entries ending with an
 all-zero entry.  Each entry consists of:
@@ -163,9 +159,9 @@ echo "vendor device subvendor subdevice 
 /sys/bus/pci/drivers/{driver}/new_id
 
 All fields are passed in as hexadecimal values (no leading 0x).
-Users need pass only as many fields as necessary:
-	o vendor, device, subvendor, and subdevice fields default
-	  to PCI_ANY_ID (FFFFFFFF),
+The vendor and device fields are mandatory, the others are optional. Users
+need pass only as many optional fields as necessary:
+	o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF)
 	o class and classmask fields default to 0
 	o driver_data defaults to 0UL.
 
@@ -549,8 +545,6 @@ pci_find_slot()			Find pci_dev correspon
 pci_set_power_state()		Set PCI Power Management state (0=D0 ... 3=D3)
 pci_find_capability()		Find specified capability in device's capability
 				list.
-pci_module_init()		Inline helper function for ensuring correct
-				pci_driver initialization and error handling.
 pci_resource_start()		Returns bus start address for a given PCI region
 pci_resource_end()		Returns bus end address for a given PCI region
 pci_resource_len()		Returns the byte length of a PCI region
diff --git a/Documentation/pcmcia/driver.txt b/Documentation/pcmcia/driver.txt
new file mode 100644
index 0000000..0ac1679
--- /dev/null
+++ b/Documentation/pcmcia/driver.txt
@@ -0,0 +1,30 @@
+PCMCIA Driver
+-------------
+
+
+sysfs
+-----
+
+New PCMCIA IDs may be added to a device driver pcmcia_device_id table at
+runtime as shown below:
+
+echo "match_flags manf_id card_id func_id function device_no \
+prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \
+/sys/bus/pcmcia/drivers/{driver}/new_id
+
+All fields are passed in as hexadecimal values (no leading 0x).
+The meaning is described in the PCMCIA specification, the match_flags is
+a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants
+defined in include/linux/mod_devicetable.h.
+
+Once added, the driver probe routine will be invoked for any unclaimed
+PCMCIA device listed in its (newly updated) pcmcia_device_id list.
+
+A common use-case is to add a new device according to the manufacturer ID
+and the card ID (form the manf_id and card_id file in the device tree).
+For this, just use:
+
+echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \
+        /sys/bus/pcmcia/drivers/{driver}/new_id
+
+after loading the driver.
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
new file mode 100644
index 0000000..1a85e2b
--- /dev/null
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -0,0 +1,106 @@
+Debugging suspend and resume
+	(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+1. Testing suspend to disk (STD)
+
+To verify that the STD works, you can try to suspend in the "reboot" mode:
+
+# echo reboot > /sys/power/disk
+# echo disk > /sys/power/state
+
+and the system should suspend, reboot, resume and get back to the command prompt
+where you have started the transition.  If that happens, the STD is most likely
+to work correctly, but you need to repeat the test at least a couple of times in
+a row for confidence.  This is necessary, because some problems only show up on
+a second attempt at suspending and resuming the system.  You should also test
+the "platform" and "shutdown" modes of suspend:
+
+# echo platform > /sys/power/disk
+# echo disk > /sys/power/state
+
+or
+
+# echo shutdown > /sys/power/disk
+# echo disk > /sys/power/state
+
+in which cases you will have to press the power button to make the system
+resume.  If that does not work, you will need to identify what goes wrong.
+
+a) Test mode of STD
+
+To verify if there are any drivers that cause problems you can run the STD
+in the test mode:
+
+# echo test > /sys/power/disk
+# echo disk > /sys/power/state
+
+in which case the system should freeze tasks, suspend devices, disable nonboot
+CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
+tasks and return to your command prompt.  If that fails, most likely there is
+a driver that fails to either suspend or resume (in the latter case the system
+may hang or be unstable after the test, so please take that into consideration).
+To find this driver, you can carry out a binary search according to the rules:
+- if the test fails, unload a half of the drivers currently loaded and repeat
+(that would probably involve rebooting the system, so always note what drivers
+have been loaded before the test),
+- if the test succeeds, load a half of the drivers you have unloaded most
+recently and repeat.
+
+Once you have found the failing driver (there can be more than just one of
+them), you have to unload it every time before the STD transition.  In that case
+please make sure to report the problem with the driver.
+
+It is also possible that a cycle can still fail after you have unloaded
+all modules. In that case, you would want to look in your kernel configuration
+for the drivers that can be compiled as modules (testing again with them as
+modules), and possibly also try boot time options such as "noapic" or "noacpi".
+
+b) Testing minimal configuration
+
+If the test mode of STD works, you can boot the system with "init=/bin/bash"
+and attempt to suspend in the "reboot", "shutdown" and "platform" modes.  If
+that does not work, there probably is a problem with a driver statically
+compiled into the kernel and you can try to compile more drivers as modules,
+so that they can be tested individually.  Otherwise, there is a problem with a
+modular driver and you can find it by loading a half of the modules you normally
+use and binary searching in accordance with the algorithm:
+- if there are n modules loaded and the attempt to suspend and resume fails,
+unload n/2 of the modules and try again (that would probably involve rebooting
+the system),
+- if there are n modules loaded and the attempt to suspend and resume succeeds,
+load n/2 modules more and try again.
+
+Again, if you find the offending module(s), it(they) must be unloaded every time
+before the STD transition, and please report the problem with it(them).
+
+c) Advanced debugging
+
+In case the STD does not work on your system even in the minimal configuration
+and compiling more drivers as modules is not practical or some modules cannot
+be unloaded, you can use one of the more advanced debugging techniques to find
+the problem.  First, if there is a serial port in your box, you can set the
+CONFIG_DISABLE_CONSOLE_SUSPEND kernel configuration option and try to log kernel
+messages using the serial console.  This may provide you with some information
+about the reasons of the suspend (resume) failure.  Alternatively, it may be
+possible to use a FireWire port for debugging with firescope
+(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On i386 it is also possible to
+use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
+
+2. Testing suspend to RAM (STR)
+
+To verify that the STR works, it is generally more convenient to use the s2ram
+tool available from http://suspend.sf.net and documented at
+http://en.opensuse.org/s2ram .  However, before doing that it is recommended to
+carry out the procedure described in section 1.
+
+Assume you have resolved the problems with the STD and you have found some
+failing drivers.  These drivers are also likely to fail during the STR or
+during the resume, so it is better to unload them every time before the STR
+transition.  Now, you can follow the instructions at
+http://en.opensuse.org/s2ram to test the system, but if it does not work
+"out of the box", you may need to boot it with "init=/bin/bash" and test
+s2ram in the minimal configuration.  In that case, you may be able to search
+for failing drivers by following the procedure analogous to the one described in
+1b).  If you find some failing drivers, you will have to unload them every time
+before the STR transition (ie. before you run s2ram), and please report the
+problems with them.
diff --git a/Documentation/power/drivers-testing.txt b/Documentation/power/drivers-testing.txt
new file mode 100644
index 0000000..33016c2
--- /dev/null
+++ b/Documentation/power/drivers-testing.txt
@@ -0,0 +1,42 @@
+Testing suspend and resume support in device drivers
+	(C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+1. Preparing the test system
+
+Unfortunately, to effectively test the support for the system-wide suspend and
+resume transitions in a driver, it is necessary to suspend and resume a fully
+functional system with this driver loaded.  Moreover, that should be done
+several times, preferably several times in a row, and separately for the suspend
+to disk (STD) and the suspend to RAM (STR) transitions, because each of these
+cases involves different ordering of operations and different interactions with
+the machine's BIOS.
+
+Of course, for this purpose the test system has to be known to suspend and
+resume without the driver being tested.  Thus, if possible, you should first
+resolve all suspend/resume-related problems in the test system before you start
+testing the new driver.  Please see Documents/power/basic-pm-debugging.txt for
+more information about the debugging of suspend/resume functionality.
+
+2. Testing the driver
+
+Once you have resolved the suspend/resume-related problems with your test system
+without the new driver, you are ready to test it:
+
+a) Build the driver as a module, load it and try the STD in the test mode (see:
+Documents/power/basic-pm-debugging.txt, 1a)).
+
+b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
+and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+
+c) Compile the driver directly into the kernel and try the STD in the test mode.
+
+d) Attempt to suspend to disk with the driver compiled directly into the kernel
+in the "reboot", "shutdown" and "platform" modes.
+
+e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
+Documents/power/basic-pm-debugging.txt, 2).  As far as the STR tests are
+concerned, it should not matter whether or not the driver is built as a module.
+
+Each of the above tests should be repeated several times and the STD tests
+should be mixed with the STR tests.  If any of them fails, the driver cannot be
+regarded as suspend/resume-safe.
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
index 74311d7..fd5192a 100644
--- a/Documentation/power/interface.txt
+++ b/Documentation/power/interface.txt
@@ -18,17 +18,10 @@ states.
 
 
 /sys/power/disk controls the operating mode of the suspend-to-disk
-mechanism. Suspend-to-disk can be handled in several ways. The
-greatest distinction is who writes memory to disk - the firmware or
-the kernel. If the firmware does it, we assume that it also handles
-suspending the system. 
-
-If the kernel does it, then we have three options for putting the system
-to sleep - using the platform driver (e.g. ACPI or other PM
-registers), powering off the system or rebooting the system (for
-testing). The system will support either 'firmware' or 'platform', and
-that is known a priori. But, the user may choose 'shutdown' or
-'reboot' as alternatives. 
+mechanism. Suspend-to-disk can be handled in several ways. We have a
+few options for putting the system to sleep - using the platform driver
+(e.g. ACPI or other pm_ops), powering off the system or rebooting the
+system (for testing).
 
 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
@@ -41,19 +34,19 @@ for 5 seconds, resume devices, unfreeze 
 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
+Reading from this file will display all supported modes and the currently
+selected one in brackets, for example
 
-       'firmware'
-       'platform'
+	[shutdown] reboot test testproc
+
+Writing to this file will accept one of
+
+       'platform' (only if the platform supports it)
        'shutdown'
        'reboot'
        'testproc'
        'test'
 
-It will only change to 'firmware' or 'platform' if the system supports
-it. 
-
 /sys/power/image_size 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
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
index b6a3cbf..e00b099 100644
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -203,7 +203,7 @@ resume
 
 Usage:
 
-if (dev->driver && dev->driver->suspend)
+if (dev->driver && dev->driver->resume)
 	dev->driver->resume(dev)
 
 The resume callback may be called from any power state, and is always meant to
diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt
index 0931a33..34800cc 100644
--- a/Documentation/power/states.txt
+++ b/Documentation/power/states.txt
@@ -62,17 +62,18 @@ setup via another operating system for i
 inconvenience, this method requires minimal work by the kernel, since
 the firmware will also handle restoring memory contents on resume. 
 
-If the kernel is responsible for persistently saving state, a mechanism
-called 'swsusp' (Swap Suspend) is used to write memory contents to
-free swap space. swsusp has some restrictive requirements, but should
-work in most cases. Some, albeit outdated, documentation can be found
-in Documentation/power/swsusp.txt. 
+For suspend-to-disk, a mechanism called swsusp called 'swsusp' (Swap
+Suspend) is used to write memory contents to free swap space.
+swsusp has some restrictive requirements, but should work in most
+cases. Some, albeit outdated, documentation can be found in
+Documentation/power/swsusp.txt. Alternatively, userspace can do most
+of the actual suspend to disk work, see userland-swsusp.txt.
 
 Once memory state is written to disk, the system may either enter a
 low-power state (like ACPI S4), or it may simply power down. Powering
 down offers greater savings, and allows this mechanism to work on any
 system. However, entering a real low-power state allows the user to
-trigger wake up events (e.g. pressing a key or opening a laptop lid). 
+trigger wake up events (e.g. pressing a key or opening a laptop lid).
 
 A transition from Suspend-to-Disk to the On state should take about 30
 seconds, though it's typically a bit more with the current
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 0761ff6..c55bd50 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -156,8 +156,7 @@ instead set the PF_NOFREEZE process flag
 be very careful).
 
 
-Q: What is the difference between "platform", "shutdown" and
-"firmware" in /sys/power/disk?
+Q: What is the difference between "platform" and "shutdown"?
 
 A:
 
@@ -166,11 +165,8 @@ shutdown: save state in linux, then tell
 platform: save state in linux, then tell bios to powerdown and blink
           "suspended led"
 
-firmware: tell bios to save state itself [needs BIOS-specific suspend
-	  partition, and has very little to do with swsusp]
-
-"platform" is actually right thing to do, but "shutdown" is most
-reliable.
+"platform" is actually right thing to do where supported, but
+"shutdown" is most reliable (except on ACPI systems).
 
 Q: I do not understand why you have such strong objections to idea of
 selective suspend.
@@ -388,8 +384,8 @@ while the system is asleep, maintaining 
 modes like "suspend-to-RAM" or "standby".  (Don't write "disk" to the
 /sys/power/state file; write "standby" or "mem".)  We've not seen any
 hardware that can use these modes through software suspend, although in
-theory some systems might support "platform" or "firmware" modes that
-won't break the USB connections.
+theory some systems might support "platform" modes that won't break the
+USB connections.
 
 Remember that it's always a bad idea to unplug a disk drive containing a
 mounted filesystem.  That's true even when your system is asleep!  The
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b41397d..d4bfae7 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -39,7 +39,7 @@ (c) 2006 MontaVista Software, Inc.
                            and property data. The old style variable
                            alignment would make it impossible to do
                            "simple" insertion of properties using
-                           memove (thanks Milton for
+                           memmove (thanks Milton for
                            noticing). Updated kernel patch as well
 			 - Correct a few more alignment constraints
 			 - Add a chapter about the device-tree
@@ -55,7 +55,7 @@ (c) 2006 MontaVista Software, Inc.
 
  ToDo:
 	- Add some definitions of interrupt tree (simple/complex)
-	- Add some definitions for pci host bridges
+	- Add some definitions for PCI host bridges
 	- Add some common address format examples
 	- Add definitions for standard properties and "compatible"
 	  names for cells that are not already defined by the existing
@@ -114,7 +114,7 @@ it with special cases.
         forth words isn't required), you can enter the kernel with:
 
               r5 : OF callback pointer as defined by IEEE 1275
-              bindings to powerpc. Only the 32 bit client interface
+              bindings to powerpc. Only the 32-bit client interface
               is currently supported
 
               r3, r4 : address & length of an initrd if any or 0
@@ -194,7 +194,7 @@ it with special cases.
   for this is to keep kernels on embedded systems small and efficient;
   part of this is due to the fact the code is already that way. In the
   future, a kernel may support multiple platforms, but only if the
-  platforms feature the same core architectire.  A single kernel build
+  platforms feature the same core architecture.  A single kernel build
   cannot support both configurations with Book E and configurations
   with classic Powerpc architectures.
 
@@ -215,7 +215,7 @@ of the boot sequences.... someone speak 
   enable another config option to select the specific board
   supported.
 
-NOTE: If ben doesn't merge the setup files, may need to change this to
+NOTE: If Ben doesn't merge the setup files, may need to change this to
 point to setup_32.c
 
 
@@ -256,7 +256,7 @@ struct boot_param_header {
         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 */
 
@@ -265,6 +265,9 @@ struct boot_param_header {
                                            booting on */
         /* version 3 fields below */
         u32     size_dt_strings;        /* size of the strings block */
+
+        /* version 17 fields below */
+        u32	size_dt_struct;		/* size of the DT structure block */
 };
 
    Along with the constants:
@@ -273,7 +276,7 @@ struct boot_param_header {
 #define OF_DT_HEADER            0xd00dfeed      /* 4: version,
 						   4: total size */
 #define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
-*/
+						   */
 #define OF_DT_END_NODE          0x2             /* End node */
 #define OF_DT_PROP              0x3             /* Property: name off,
                                                    size, content */
@@ -310,9 +313,8 @@ #define OF_DT_END               0x9
    - off_mem_rsvmap
 
      This is an offset from the beginning of the header to the start
-     of the reserved memory map. This map is a list of pairs of 64
+     of the reserved memory map. This map is a list of pairs of 64-
      bit integers. Each pair is a physical address and a size. The
-
      list is terminated by an entry of size 0. This map provides the
      kernel with a list of physical memory areas that are "reserved"
      and thus not to be used for memory allocations, especially during
@@ -325,7 +327,7 @@ #define OF_DT_END               0x9
      contain _at least_ this DT block itself (header,total_size). If
      you are passing an initrd to the kernel, you should reserve it as
      well. You do not need to reserve the kernel image itself. The map
-     should be 64 bit aligned.
+     should be 64-bit aligned.
 
    - version
 
@@ -335,10 +337,13 @@ #define OF_DT_END               0x9
      to reallocate it easily at boot and free up the unused flattened
      structure after expansion. Version 16 introduces a new more
      "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 explicitly aim at being backward
-     compatible.
+     compatible. Version 17 adds an additional field, size_dt_struct,
+     allowing it to be reallocated or moved more easily (this is
+     particularly useful for bootloaders which need to make
+     adjustments to a device tree based on probed information). You
+     should always generate a structure of the highest version defined
+     at the time of your implementation. Currently that is version 17,
+     unless you explicitly aim at being backward compatible.
 
    - last_comp_version
 
@@ -347,7 +352,7 @@ #define OF_DT_END               0x9
      is backward compatible with version 1 (that is, a kernel build
      for version 1 will be able to boot with a version 2 format). You
      should put a 1 in this field if you generate a device tree of
-     version 1 to 3, or 0x10 if you generate a tree of version 0x10
+     version 1 to 3, or 16 if you generate a tree of version 16 or 17
      using the new unit name format.
 
    - boot_cpuid_phys
@@ -360,6 +365,17 @@ #define OF_DT_END               0x9
      point (see further chapters for more informations on the required
      device-tree contents)
 
+   - size_dt_strings
+
+     This field only exists on version 3 and later headers.  It
+     gives the size of the "strings" section of the device tree (which
+     starts at the offset given by off_dt_strings).
+
+   - size_dt_struct
+
+     This field only exists on version 17 and later headers.  It gives
+     the size of the "structure" section of the device tree (which
+     starts at the offset given by off_dt_struct).
 
    So the typical layout of a DT block (though the various parts don't
    need to be in that order) looks like this (addresses go from top to
@@ -417,7 +433,7 @@ root node who has no parent.
 A node has 2 names. The actual node name is generally contained in a
 property of type "name" in the node property list whose value is a
 zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 0x10 makes it
+format definition (as it is in Open Firmware). Version 16 makes it
 optional as it can generate it from the unit name defined below.
 
 There is also a "unit name" that is used to differentiate nodes with
@@ -461,7 +477,7 @@ referencing another node via "phandle" i
 interrupt tree which will be described in a further version of this
 document.
 
-This "linux, phandle" property is a 32 bit value that uniquely
+This "linux, phandle" property is a 32-bit value that uniquely
 identifies a node. You are free to use whatever values or system of
 values, internal pointers, or whatever to generate these, the only
 requirement is that every node for which you provide that property has
@@ -471,7 +487,7 @@ Here is an example of a simple device-tr
 designates a node followed by the node unit name. Properties are
 presented with their name followed by their content. "content"
 represents an ASCII string (zero terminated) value, while <content>
-represents a 32 bit hexadecimal value. The various nodes in this
+represents a 32-bit hexadecimal value. The various nodes in this
 example will be discussed in a later chapter. At this point, it is
 only meant to give you a idea of what a device-tree looks like. I have
 purposefully kept the "name" and "linux,phandle" properties which
@@ -543,15 +559,15 @@ Here's the basic structure of a single n
      * [align gap to next 4 bytes boundary]
      * for each property:
         * token OF_DT_PROP (that is 0x00000003)
-        * 32 bit value of property value size in bytes (or 0 of no
-     * value)
-        * 32 bit value of offset in string block of property name
+        * 32-bit value of property value size in bytes (or 0 if no
+          value)
+        * 32-bit value of offset in string block of property name
         * property value data if any
         * [align gap to next 4 bytes boundary]
      * [child nodes if any]
      * token OF_DT_END_NODE (that is 0x00000002)
 
-So the node content can be summarised as a start token, a full path,
+So the node content can be summarized 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.
 
@@ -583,7 +599,7 @@ provide those properties yourself.
 ----------------------------------------------
 
 The general rule is documented in the various Open Firmware
-documentations. If you chose to describe a bus with the device-tree
+documentations. If you choose to describe a bus with the device-tree
 and there exist an OF bus binding, then you should follow the
 specification. However, the kernel does not require every single
 device or bus to be described by the device tree.
@@ -596,9 +612,9 @@ those properties defining addresses form
 on the processor bus.
 
 Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32 bit number. For example, if both contain 2
+size. A "cell" is a 32-bit number. For example, if both contain 2
 like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64 bit number (cells are
+composed of 2 cells, and each is a 64-bit number (cells are
 concatenated and expected to be in big endian format). Another example
 is the way Apple firmware defines them, with 2 cells for an address
 and one cell for a size.  Most 32-bit implementations should define
@@ -632,7 +648,7 @@ prom_parse.c file of the recent kernels 
 
 The "reg" property only defines addresses and sizes (if #size-cells
 is non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into cpu physical
+(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" property for a
@@ -648,9 +664,9 @@ example, for a PCI host controller, that
 PCI<->ISA bridge, that would be a PCI address. It defines the base
 address in the parent bus where the beginning of that range is mapped.
 
-For a new 64 bit powerpc board, I recommend either the 2/2 format or
+For a new 64-bit powerpc board, I recommend either the 2/2 format or
 Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32 bit word.   New 32 bit powerpc boards should use a
+fit in a single 32-bit word.   New 32-bit powerpc boards should use a
 1/1 format, unless the processor supports physical addresses greater
 than 32-bits, in which case a 2/1 format is recommended.
 
@@ -764,7 +780,7 @@ address which can extend beyond that lim
   Required properties:
 
     - device_type : has to be "cpu"
-    - reg : This is the physical cpu number, it's a single 32 bit cell
+    - reg : This is the physical CPU number, it's a single 32-bit cell
       and is also used as-is as the unit number for constructing the
       unit name in the full path. For example, with 2 CPUs, you would
       have the full path:
@@ -785,7 +801,7 @@ address which can extend beyond that lim
       the kernel timebase/decrementer calibration based on this
       value.
     - clock-frequency : a cell indicating the CPU core clock frequency
-      in Hz. A new property will be defined for 64 bit values, but if
+      in Hz. A new property will be defined for 64-bit values, but if
       your frequency is < 4Ghz, one cell is enough. Here as well as
       for the above, the common code doesn't use that property, but
       you are welcome to re-use the pSeries or Maple one. A future
@@ -832,8 +848,7 @@ address which can extend beyond that lim
 
   This node is a bit "special". Normally, that's where open firmware
   puts some variable environment information, like the arguments, or
-  phandle pointers to nodes like the main interrupt controller, or the
-  default input/output devices.
+  the default input/output devices.
 
   This specification makes a few of these mandatory, but also defines
   some linux-specific properties that would be normally constructed by
@@ -853,14 +868,14 @@ address which can extend beyond that lim
       that the kernel tries to find out the default console and has
       knowledge of various types like 8250 serial ports. You may want
       to extend this function to add your own.
-    - interrupt-controller : This is one cell containing a phandle
-      value that matches the "linux,phandle" property of your main
-      interrupt controller node. May be used for interrupt routing.
-
 
   Note that u-boot creates and fills in the chosen node for platforms
   that use it.
 
+  (Note: a practice that is now obsolete was to include a property
+  under /chosen called interrupt-controller which had a phandle value
+  that pointed to the main interrupt controller)
+
   f) the /soc<SOCname> node
 
   This node is used to represent a system-on-a-chip (SOC) and must be
@@ -908,8 +923,7 @@ address which can extend beyond that lim
   The SOC node may contain child nodes for each SOC device that the
   platform uses.  Nodes should not be created for devices which exist
   on the SOC but are not used by a particular platform. See chapter VI
-  for more information on how to specify devices that are part of an
-SOC.
+  for more information on how to specify devices that are part of a SOC.
 
   Example SOC node for the MPC8540:
 
@@ -972,7 +986,7 @@ The syntax of the dtc tool is
         [-o output-filename] [-V output_version] input_filename
 
 
-The "output_version" defines what versio of the "blob" format will be
+The "output_version" defines what version of the "blob" format will be
 generated. Supported versions are 1,2,3 and 16. The default is
 currently version 3 but that may change in the future to version 16.
 
@@ -994,12 +1008,12 @@ supported currently at the toplevel.
 				 */
 
   property2 = <1234abcd>;	/* define a property containing a
-                                 * numerical 32 bits value (hexadecimal)
+                                 * numerical 32-bit value (hexadecimal)
 				 */
 
   property3 = <12345678 12345678 deadbeef>;
                                 /* define a property containing 3
-                                 * numerical 32 bits values (cells) in
+                                 * numerical 32-bit values (cells) in
                                  * hexadecimal
 				 */
   property4 = [0a 0b 0c 0d de ea ad be ef];
@@ -1068,7 +1082,7 @@ while all this has been defined and impl
     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
-    to discuss possible free licencing to any vendor who wishes to
+    to discuss possible free licensing to any vendor who wishes to
     integrate all or part of this code into a non-GPL bootloader.
 
 
@@ -1077,7 +1091,7 @@ VI - System-on-a-chip devices and nodes
 =======================================
 
 Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (cpu) and many peripheral devices
+processors, where the processor core (CPU) and many peripheral devices
 exist on a single piece of silicon.  For these SOCs, an SOC node
 should be used that defines child nodes for the devices that make
 up the SOC. While platforms are not required to use this model in
@@ -1109,42 +1123,7 @@ See appendix A for an example partial SO
 MPC8540.
 
 
-2) Specifying interrupt information for SOC devices
----------------------------------------------------
-
-Each device that is part of an SOC and which generates interrupts
-should have the following properties:
-
-	- interrupt-parent : contains the phandle of the interrupt
-          controller which handles interrupts for this device
-	- interrupts : a list of tuples representing the interrupt
-          number and the interrupt sense and level for each interrupt
-          for this device.
-
-This information is used by the kernel to build the interrupt table
-for the interrupt controllers in the system.
-
-Sense and level information should be encoded as follows:
-
-   Devices connected to openPIC-compatible controllers should encode
-   sense and polarity as follows:
-
-	0 = low to high edge sensitive type enabled
-	1 = active low level sensitive type enabled
-	2 = active high level sensitive type enabled
-	3 = high to low edge sensitive type enabled
-
-   ISA PIC interrupt controllers should adhere to the ISA PIC
-   encodings listed below:
-
-	0 =  active low level sensitive type enabled
-	1 =  active high level sensitive type enabled
-	2 =  high to low edge sensitive type enabled
-	3 =  low to high edge sensitive type enabled
-
-
-
-3) Representing devices without a current OF specification
+2) Representing devices without a current OF specification
 ----------------------------------------------------------
 
 Currently, there are many devices on SOCs that do not have a standard
@@ -1201,6 +1180,13 @@ platforms are moved over to use the flat
     - phy-handle : The phandle for the PHY connected to this ethernet
       controller.
 
+  Recommended properties:
+
+    - linux,network-index : This is the intended "index" of this
+      network device.  This is used by the bootwrapper to interpret
+      MAC addresses passed by the firmware when no information other
+      than indices is available to associate an address with a device.
+
   Example:
 
 	ethernet@24000 {
@@ -1312,10 +1298,10 @@ platforms are moved over to use the flat
    and additions :  
 
    Required properties :
-    - compatible : Should be "fsl-usb2-mph" for multi port host usb
-      controllers, or "fsl-usb2-dr" for dual role usb controllers
-    - phy_type : For multi port host usb controllers, should be one of
-      "ulpi", or "serial". For dual role usb controllers, should be
+    - compatible : Should be "fsl-usb2-mph" for multi port host USB
+      controllers, or "fsl-usb2-dr" for dual role USB controllers
+    - phy_type : For multi port host USB controllers, should be one of
+      "ulpi", or "serial". For dual role USB controllers, should be
       one of "ulpi", "utmi", "utmi_wide", or "serial".
     - reg : Offset and length of the register set for the device
     - port0 : boolean; if defined, indicates port0 is connected for
@@ -1339,7 +1325,7 @@ platforms are moved over to use the flat
     - interrupt-parent : the phandle for the interrupt controller that
       services interrupts for this device.
 
-   Example multi port host usb controller device node : 
+   Example multi port host USB controller device node :
 	usb@22000 {
 	        device_type = "usb";
 		compatible = "fsl-usb2-mph";
@@ -1353,7 +1339,7 @@ platforms are moved over to use the flat
 		port1;
 	};
 
-   Example dual role usb controller device node : 
+   Example dual role USB controller device node :
 	usb@23000 {
 		device_type = "usb";
 		compatible = "fsl-usb2-dr";
@@ -1387,7 +1373,7 @@ platforms are moved over to use the flat
     - channel-fifo-len : An integer representing the number of
       descriptor pointers each channel fetch fifo can hold.
     - exec-units-mask : The bitmask representing what execution units
-      (EUs) are available. It's a single 32 bit cell. EU information
+      (EUs) are available. It's a single 32-bit cell. EU information
       should be encoded following the SEC's Descriptor Header Dword
       EU_SEL0 field documentation, i.e. as follows:
 
@@ -1403,7 +1389,7 @@ platforms are moved over to use the flat
       bits 8 through 31 are reserved for future SEC EUs.
 
     - descriptor-types-mask : The bitmask representing what descriptors
-      are available. It's a single 32 bit cell. Descriptor type
+      are available. It's a single 32-bit cell. Descriptor type
       information should be encoded following the SEC's Descriptor
       Header Dword DESC_TYPE field documentation, i.e. as follows:
 
@@ -1492,7 +1478,7 @@ platforms are moved over to use the flat
    Required properties:
    - device_type : should be "spi".
    - compatible : should be "fsl_spi".
-   - mode : the spi operation mode, it can be "cpu" or "qe".
+   - 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
@@ -1569,6 +1555,15 @@ platforms are moved over to use the flat
    - mac-address : list of bytes representing the ethernet address.
    - phy-handle : The phandle for the PHY connected to this controller.
 
+   Recommended properties:
+   - linux,network-index : This is the intended "index" of this
+     network device.  This is used by the bootwrapper to interpret
+     MAC addresses passed by the firmware when no information other
+     than indices is available to associate an address with a device.
+   - phy-connection-type : a string naming the controller/PHY interface type,
+     i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "tbi",
+     or "rtbi".
+
    Example:
 	ucc@2000 {
 		device_type = "network";
@@ -1582,6 +1577,7 @@ platforms are moved over to use the flat
 		rx-clock = "none";
 		tx-clock = "clk9";
 		phy-handle = <212000>;
+		phy-connection-type = "gmii";
 		pio-handle = <140001>;
 	};
 
@@ -1712,7 +1708,7 @@ platforms are moved over to use the flat
      - partitions : Several pairs of 32-bit values where the first value is
        partition's offset from the start of the device and the second one is
        partition size in bytes with LSB used to signify a read only
-       partition (so, the parition size should always be an even number).
+       partition (so, the partition size should always be an even number).
      - partition-names : The list of concatenated zero terminated strings
        representing the partition names.
      - probe-type : The type of probe which should be done for the chip
@@ -1733,6 +1729,92 @@ platforms are moved over to use the flat
 
    More devices will be defined as this spec matures.
 
+VII - Specifying interrupt information for devices
+===================================================
+
+The device tree represents the busses and devices of a hardware
+system in a form similar to the physical bus topology of the
+hardware.
+
+In addition, a logical 'interrupt tree' exists which represents the
+hierarchy and routing of interrupts in the hardware.
+
+The interrupt tree model is fully described in the
+document "Open Firmware Recommended Practice: Interrupt
+Mapping Version 0.9".  The document is available at:
+<http://playground.sun.com/1275/practice>.
+
+1) interrupts property
+----------------------
+
+Devices that generate interrupts to a single interrupt controller
+should use the conventional OF representation described in the
+OF interrupt mapping documentation.
+
+Each device which generates interrupts must have an 'interrupt'
+property.  The interrupt property value is an arbitrary number of
+of 'interrupt specifier' values which describe the interrupt or
+interrupts for the device.
+
+The encoding of an interrupt specifier is determined by the
+interrupt domain in which the device is located in the
+interrupt tree.  The root of an interrupt domain specifies in
+its #interrupt-cells property the number of 32-bit cells
+required to encode an interrupt specifier.  See the OF interrupt
+mapping documentation for a detailed description of domains.
+
+For example, the binding for the OpenPIC interrupt controller
+specifies  an #interrupt-cells value of 2 to encode the interrupt
+number and level/sense information. All interrupt children in an
+OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
+property.
+
+The PCI bus binding specifies a #interrupt-cell value of 1 to encode
+which interrupt pin (INTA,INTB,INTC,INTD) is used.
+
+2) interrupt-parent property
+----------------------------
+
+The interrupt-parent property is specified to define an explicit
+link between a device node and its interrupt parent in
+the interrupt tree.  The value of interrupt-parent is the
+phandle of the parent node.
+
+If the interrupt-parent property is not defined for a node, it's
+interrupt parent is assumed to be an ancestor in the node's
+_device tree_ hierarchy.
+
+3) OpenPIC Interrupt Controllers
+--------------------------------
+
+OpenPIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+Sense and level information should be encoded as follows:
+
+	0 = low to high edge sensitive type enabled
+	1 = active low level sensitive type enabled
+	2 = active high level sensitive type enabled
+	3 = high to low edge sensitive type enabled
+
+4) ISA Interrupt Controllers
+----------------------------
+
+ISA PIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+ISA PIC interrupt controllers should adhere to the ISA PIC
+encodings listed below:
+
+	0 =  active low level sensitive type enabled
+	1 =  active high level sensitive type enabled
+	2 =  high to low edge sensitive type enabled
+	3 =  low to high edge sensitive type enabled
+
 
 Appendix A - Sample SOC node for MPC8540
 ========================================
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 1ef6bb8..7c701b8 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -147,7 +147,7 @@ RTC class framework, but can't be suppor
 
     *	RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC
 	is connected to an IRQ line, it can often issue an alarm IRQ up to
-	24 hours in the future.
+	24 hours in the future.  (Use RTC_WKALM_* by preference.)
 
     *	RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond
 	the next 24 hours use a slightly more powerful API, which supports
@@ -175,10 +175,7 @@ driver returns ENOIOCTLCMD.  Some common
 	called with appropriate values.
 
     *	RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the
-	set_alarm/read_alarm functions will be called.  To differentiate
-	between the ALM and WKALM, check the larger fields of the rtc_wkalrm
-	struct (like tm_year).  These will be set to -1 when using ALM and
-	will be set to proper values when using WKALM.
+	set_alarm/read_alarm functions will be called.
 
     *	RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called
 	to set the frequency while the framework will handle the read for you
diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt
deleted file mode 100644
index 71ae6ca..0000000
--- a/Documentation/s390/crypto/crypto-API.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-crypto-API support for z990 Message Security Assist (MSA) instructions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-AUTHOR:	Thomas Spatzier (tspat@de.ibm.com)
-
-
-1. Introduction crypto-API
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-See Documentation/crypto/api-intro.txt for an introduction/description of the
-kernel crypto API.
-According to api-intro.txt support for z990 crypto instructions has been added
-in the algorithm api layer of the crypto API. Several files containing z990
-optimized implementations of crypto algorithms are placed in the
-arch/s390/crypto directory.
-
-
-2. Probing for availability of MSA
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It should be possible to use Kernels with the z990 crypto implementations both
-on machines with MSA available and on those without MSA (pre z990 or z990
-without MSA). Therefore a simple probing mechanism has been implemented:
-In the init function of each crypto module the availability of MSA and of the
-respective crypto algorithm in particular will be tested. If the algorithm is
-available the module will load and register its algorithm with the crypto API.
-
-If the respective crypto algorithm is not available, the init function will
-return -ENOSYS. In that case a fallback to the standard software implementation
-of the crypto algorithm must be taken ( -> the standard crypto modules are
-also built when compiling the kernel).
-
-
-3. Ensuring z990 crypto module preference
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If z990 crypto instructions are available the optimized modules should be
-preferred instead of standard modules.
-
-3.1. compiled-in modules
-~~~~~~~~~~~~~~~~~~~~~~~~
-For compiled-in modules it has to be ensured that the z990 modules are linked
-before the standard crypto modules. Then, on system startup the init functions
-of z990 crypto modules will be called first and query for availability of z990
-crypto instructions. If instruction is available, the z990 module will register
-its crypto algorithm implementation -> the load of the standard module will fail
-since the algorithm is already registered.
-If z990 crypto instruction is not available the load of the z990 module will
-fail -> the standard module will load and register its algorithm.
-
-3.2. dynamic modules
-~~~~~~~~~~~~~~~~~~~~
-A system administrator has to take care of giving preference to z990 crypto
-modules. If MSA is available appropriate lines have to be added to
-/etc/modprobe.conf.
-
-Example:	z990 crypto instruction for SHA1 algorithm is available
-
-		add the following line to /etc/modprobe.conf (assuming the
-		z990 crypto modules for SHA1 is called sha1_z990):
-
-		alias sha1 sha1_z990
-
-		-> 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 probing mechanism
-	something like 'probe sha1 sha1_z990 sha1' in modprobe.conf
-	-> try module sha1_z990, if it fails to load standard module sha1
-	the 'probe' statement is currently not supported in modprobe.conf
-
-
-4. Currently implemented z990 crypto algorithms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The following crypto algorithms with z990 MSA support are currently implemented.
-The name of each algorithm under which it is registered in crypto API and the
-name of the respective module is given in square brackets.
-
-- SHA1 Digest Algorithm [sha1 -> sha1_z990]
-- DES Encrypt/Decrypt Algorithm (64bit key) [des -> des_z990]
-- Triple DES Encrypt/Decrypt Algorithm (128bit key) [des3_ede128 -> des_z990]
-- Triple DES Encrypt/Decrypt Algorithm (192bit key) [des3_ede -> des_z990]
-
-In order to load, for example, the sha1_z990 module when the sha1 algorithm is
-requested (see 3.2.) add 'alias sha1 sha1_z990' to /etc/modprobe.conf.
-
diff --git a/Documentation/s390/zfcpdump.txt b/Documentation/s390/zfcpdump.txt
new file mode 100644
index 0000000..cf45d27
--- /dev/null
+++ b/Documentation/s390/zfcpdump.txt
@@ -0,0 +1,87 @@
+s390 SCSI dump tool (zfcpdump)
+
+System z machines (z900 or higher) provide hardware support for creating system
+dumps on SCSI disks. The dump process is initiated by booting a dump tool, which
+has to create a dump of the current (probably crashed) Linux image. In order to
+not overwrite memory of the crashed Linux with data of the dump tool, the
+hardware saves some memory plus the register sets of the boot cpu before the
+dump tool is loaded. There exists an SCLP hardware interface to obtain the saved
+memory afterwards. Currently 32 MB are saved.
+
+This zfcpdump implementation consists of a Linux dump kernel together with
+a userspace dump tool, which are loaded together into the saved memory region
+below 32 MB. zfcpdump is installed on a SCSI disk using zipl (as contained in
+the s390-tools package) to make the device bootable. The operator of a Linux
+system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump
+resides on.
+
+The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem",
+which exports memory and registers of the crashed Linux in an s390
+standalone dump format. It can be used in the same way as e.g. /dev/mem. The
+dump format defines a 4K header followed by plain uncompressed memory. The
+register sets are stored in the prefix pages of the respective cpus. To build a
+dump enabled kernel with the zcore driver, the kernel config option
+CONFIG_ZFCPDUMP has to be set. When reading from "zcore/mem", the part of
+memory, which has been saved by hardware is read by the driver via the SCLP
+hardware interface. The second part is just copied from the non overwritten real
+memory.
+
+The userspace application of zfcpdump can reside e.g. in an intitramfs or an
+initrd. It reads from zcore/mem and writes the system dump to a file on a
+SCSI disk.
+
+To build a zfcpdump kernel use the following settings in your kernel
+configuration:
+ * CONFIG_ZFCPDUMP=y
+ * Enable ZFCP driver
+ * Enable SCSI driver
+ * Enable ext2 and ext3 filesystems
+ * Disable as many features as possible to keep the kernel small.
+   E.g. network support is not needed at all.
+
+To use the zfcpdump userspace application in an initramfs you have to do the
+following:
+
+ * Copy the zfcpdump executable somewhere into your Linux tree.
+   E.g. to "arch/s390/boot/zfcpdump. If you do not want to include
+   shared libraries, compile the tool with the "-static" gcc option.
+ * If you want to include e2fsck, add it to your source tree, too. The zfcpdump
+   application attempts to start /sbin/e2fsck from the ramdisk.
+ * Use an initramfs config file like the following:
+
+   dir /dev 755 0 0
+   nod /dev/console 644 0 0 c 5 1
+   nod /dev/null 644 0 0 c 1 3
+   nod /dev/sda1 644 0 0 b 8 1
+   nod /dev/sda2 644 0 0 b 8 2
+   nod /dev/sda3 644 0 0 b 8 3
+   nod /dev/sda4 644 0 0 b 8 4
+   nod /dev/sda5 644 0 0 b 8 5
+   nod /dev/sda6 644 0 0 b 8 6
+   nod /dev/sda7 644 0 0 b 8 7
+   nod /dev/sda8 644 0 0 b 8 8
+   nod /dev/sda9 644 0 0 b 8 9
+   nod /dev/sda10 644 0 0 b 8 10
+   nod /dev/sda11 644 0 0 b 8 11
+   nod /dev/sda12 644 0 0 b 8 12
+   nod /dev/sda13 644 0 0 b 8 13
+   nod /dev/sda14 644 0 0 b 8 14
+   nod /dev/sda15 644 0 0 b 8 15
+   file /init arch/s390/boot/zfcpdump 755 0 0
+   file /sbin/e2fsck arch/s390/boot/e2fsck 755 0 0
+   dir /proc 755 0 0
+   dir /sys 755 0 0
+   dir /mnt 755 0 0
+   dir /sbin 755 0 0
+
+ * Issue "make image" to build the zfcpdump image with initramfs.
+
+In a Linux distribution the zfcpdump enabled kernel image must be copied to
+/usr/share/zfcpdump/zfcpdump.image, where the s390 zipl tool is looking for the
+dump kernel when preparing a SCSI dump disk.
+
+If you use a ramdisk copy it to "/usr/share/zfcpdump/zfcpdump.rd".
+
+For more information on how to use zfcpdump refer to the s390 'Using the Dump
+Tools book', which is available from
+http://www.ibm.com/developerworks/linux/linux390.
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index dc8e44f..2368e7e 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -37,7 +37,11 @@ Supported Cards/Chipsets
 	9005:0286:9005:029d	Adaptec	2420SA (Intruder HP release)
 	9005:0286:9005:02ac	Adaptec	1800 (Typhoon44)
 	9005:0285:9005:02b5	Adaptec	5445 (Voodoo44)
+	9005:0285:15d9:02b5	SMC	AOC-USAS-S4i
+	9005:0285:15d9:02c9	SMC	AOC-USAS-S4iR
 	9005:0285:9005:02b6	Adaptec	5805 (Voodoo80)
+	9005:0285:15d9:02b6	SMC	AOC-USAS-S8i
+	9005:0285:15d9:02ca	SMC	AOC-USAS-S8iR
 	9005:0285:9005:02b7	Adaptec	5085 (Voodoo08)
 	9005:0285:9005:02bb	Adaptec	3405 (Marauder40LP)
 	9005:0285:9005:02bc	Adaptec	3805 (Marauder80LP)
@@ -93,6 +97,9 @@ Supported Cards/Chipsets
 	9005:0286:9005:02ae		(Aurora Lite ARK)
 	9005:0285:9005:02b0		(Sunrise Lake ARK)
 	9005:0285:9005:02b1	Adaptec	(Voodoo 8 internal 8 external)
+	9005:0285:108e:7aac	SUN	STK RAID REM (Voodoo44 Coyote)
+	9005:0285:108e:0286	SUN	SG-XPCIESAS-R-IN (Cougar)
+	9005:0285:108e:0287	SUN	SG-XPCIESAS-R-EX (Prometheus)
 
 People
 -------------------------
diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
index caf10b1..88ef88b 100644
--- a/Documentation/scsi/ncr53c8xx.txt
+++ b/Documentation/scsi/ncr53c8xx.txt
@@ -562,11 +562,6 @@ if only one has a flaw for some SCSI fea
 support by the driver of this feature at linux start-up and enable
 this feature after boot-up only for devices that support it safely.
 
-CONFIG_SCSI_NCR53C8XX_PROFILE_SUPPORT  (default answer: n)
-    This option must be set for profiling information to be gathered 
-    and printed out through the proc file system. This features may 
-    impact performances.
-
 CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
     Answer "y" if you suspect your mother board to not allow memory mapped I/O.
     May slow down performance a little.  This option is required by
diff --git a/Documentation/sh/clk.txt b/Documentation/sh/clk.txt
new file mode 100644
index 0000000..9aef710
--- /dev/null
+++ b/Documentation/sh/clk.txt
@@ -0,0 +1,32 @@
+Clock framework on SuperH architecture
+
+The framework on SH extends existing API by the function clk_set_rate_ex,
+which prototype is as follows:
+
+    clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
+
+The algo_id parameter is used to specify algorithm used to recalculate clocks,
+adjanced to clock, specified as first argument. It is assumed that algo_id==0
+means no changes to adjanced clock
+
+Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
+if it is present in ops structure. The method should set the clock rate and adjust
+all needed clocks according to the passed algo_id.
+Exact values for algo_id are machine-dependend. For the sh7722, the following
+values are defined:
+
+	NO_CHANGE	= 0,
+	IUS_N1_N1,	/* I:U = N:1, U:Sh = N:1 */
+	IUS_322,	/* I:U:Sh = 3:2:2	 */
+	IUS_522,	/* I:U:Sh = 5:2:2 	 */
+	IUS_N11,	/* I:U:Sh = N:1:1	 */
+	SB_N1,		/* Sh:B = N:1		 */
+	SB3_N1,		/* Sh:B3 = N:1		 */
+	SB3_32,		/* Sh:B3 = 3:2		 */
+	SB3_43,		/* Sh:B3 = 4:3		 */
+	SB3_54,		/* Sh:B3 = 5:4		 */
+	BP_N1,		/* B:P	 = N:1		 */
+	IP_N1		/* I:P	 = N:1		 */
+
+Each of these constants means relation between clocks that can be set via the FRQCR
+register
diff --git a/Documentation/sony-laptop.txt b/Documentation/sony-laptop.txt
index dfd26df..7a5c1a8 100644
--- a/Documentation/sony-laptop.txt
+++ b/Documentation/sony-laptop.txt
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readm
 	Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
 	Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
 
-This mini-driver drives the SNC device present in the ACPI BIOS of
-the Sony Vaio laptops.
+This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
+Sony Vaio laptops. This driver mixes both devices functions under the same
+(hopefully consistent) interface. This also means that the sonypi driver is
+obsoleted by sony-laptop now.
 
-It gives access to some extra laptop functionalities. In its current
-form, this driver let the user set or query the screen brightness
-through the backlight subsystem and remove/apply power to some devices.
+Fn keys (hotkeys):
+------------------
+Some models report hotkeys through the SNC or SPIC devices, such events are
+reported both through the ACPI subsystem as acpi events and through the INPUT
+subsystem. See the logs of acpid or /proc/acpi/event and
+/proc/bus/input/devices to find out what those events are and which input
+devices are created by the driver.
 
 Backlight control:
 ------------------
@@ -39,6 +45,8 @@ The files are:
 	audiopower		power on/off the internal sound card
 	lanpower		power on/off the internal ethernet card
 				(only in debug mode)
+	bluetoothpower		power on/off the internal bluetooth device
+	fanspeed		get/set the fan speed
 
 Note that some files may be missing if they are not supported
 by your particular laptop model.
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some
 current ones found on several Vaio models), an entry under
 /sys/devices/platform/sony-laptop, just like the 'cdpower' one.
 You can create other entries corresponding to your own laptop methods by
-further editing the source (see the 'sony_acpi_values' table, and add a new
+further editing the source (see the 'sony_nc_values' table, and add a new
 entry to this table with your get/set method names using the
-HANDLE_NAMES macro).
+SNC_HANDLE_NAMES macro).
 
 Your mission, should you accept it, is to try finding out what
 those entries are for, by reading/writing random values from/to those
@@ -87,6 +95,9 @@ files and find out what is the impact on
 Should you find anything interesting, please report it back to me,
 I will not disavow all knowledge of your actions :)
 
+See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
+useful info.
+
 Bugs/Limitations:
 -----------------
 
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index f9717fe..215e3b8 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -62,7 +62,7 @@ static struct resource pxa_spi_nssp_reso
 
 static struct pxa2xx_spi_master pxa_nssp_master_info = {
 	.ssp_type = PXA25x_NSSP, /* Type of SSP */
-	.clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */
+	.clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
 	.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
 	.enable_dma = 1, /* Enables NSSP DMA */
 };
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index ecc7c9e..795fbb4 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -8,7 +8,7 @@ What is SPI?
 The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial
 link used to connect microcontrollers to sensors, memory, and peripherals.
 
-The three signal wires hold a clock (SCLK, often on the order of 10 MHz),
+The three signal wires hold a clock (SCK, often on the order of 10 MHz),
 and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In,
 Slave Out" (MISO) signals.  (Other names are also used.)  There are four
 clocking modes through which data is exchanged; mode-0 and mode-3 are most
@@ -22,7 +22,7 @@ other signals, often including an interr
 
 Unlike serial busses like USB or SMBUS, even low level protocols for
 SPI slave functions are usually not interoperable between vendors
-(except for cases like SPI memory chips).
+(except for commodities like SPI memory chips).
 
   - SPI may be used for request/response style device protocols, as with
     touchscreen sensors and memory chips.
@@ -77,8 +77,9 @@ cards without needing a special purpose 
 How do these driver programming interfaces work?
 ------------------------------------------------
 The <linux/spi/spi.h> header file includes kerneldoc, as does the
-main source code, and you should certainly read that.  This is just
-an overview, so you get the big picture before the details.
+main source code, and you should certainly read that chapter of the
+kernel API document.  This is just an overview, so you get the big
+picture before those details.
 
 SPI requests always go into I/O queues.  Requests for a given SPI device
 are always executed in FIFO order, and complete asynchronously through
@@ -88,7 +89,7 @@ a command and then reading its response.
 
 There are two types of SPI driver, here called:
 
-  Controller drivers ... these are often built in to System-On-Chip
+  Controller drivers ... controllers may be built in to System-On-Chip
 	processors, and often support both Master and Slave roles.
 	These drivers touch hardware registers and may use DMA.
 	Or they can be PIO bitbangers, needing just GPIO pins.
@@ -108,18 +109,18 @@ those two types of driver.  At this writ
 programming interface.
 
 There is a minimal core of SPI programming interfaces, focussing on
-using driver model to connect controller and protocol drivers using
+using the driver model to connect controller and protocol drivers using
 device tables provided by board specific initialization code.  SPI
 shows up in sysfs in several locations:
 
-   /sys/devices/.../CTLR/spiB.C ... spi_device for on bus "B",
+   /sys/devices/.../CTLR/spiB.C ... spi_device on bus "B",
 	chipselect C, accessed through CTLR.
 
    /sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver
 	that should be used with this device (for hotplug/coldplug)
 
    /sys/bus/spi/devices/spiB.C ... symlink to the physical
-   	spiB-C device
+   	spiB.C device
 
    /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
 
@@ -240,7 +241,7 @@ The board_info should provide enough inf
 without the chip's driver being loaded.  The most troublesome aspect of
 that is likely the SPI_CS_HIGH bit in the spi_device.mode field, since
 sharing a bus with a device that interprets chipselect "backwards" is
-not possible.
+not possible until the infrastructure knows how to deselect it.
 
 Then your board initialization code would register that table with the SPI
 infrastructure, so that it's available later when the SPI master controller
@@ -268,16 +269,14 @@ board info based on the board that was h
 call at least spi_unregister_device() when that board is removed.
 
 When Linux includes support for MMC/SD/SDIO/DataFlash cards through SPI, those
-configurations will also be dynamic.  Fortunately, those devices all support
-basic device identification probes, so that support should hotplug normally.
+configurations will also be dynamic.  Fortunately, such devices all support
+basic device identification probes, so they should hotplug normally.
 
 
 How do I write an "SPI Protocol Driver"?
 ----------------------------------------
-All SPI drivers are currently kernel drivers.  A userspace driver API
-would just be another kernel driver, probably offering some lowlevel
-access through aio_read(), aio_write(), and ioctl() calls and using the
-standard userspace sysfs mechanisms to bind to a given SPI device.
+Most SPI drivers are currently kernel drivers, but there's also support
+for userspace drivers.  Here we talk only about kernel drivers.
 
 SPI protocol drivers somewhat resemble platform device drivers:
 
@@ -319,7 +318,8 @@ might look like this unless you're creat
 
 As soon as it enters probe(), the driver may issue I/O requests to
 the SPI device using "struct spi_message".  When remove() returns,
-the driver guarantees that it won't submit any more such messages.
+or after probe() fails, the driver guarantees that it won't submit
+any more such messages.
 
   - An spi_message is a sequence of protocol operations, executed
     as one atomic sequence.  SPI driver controls include:
@@ -368,7 +368,8 @@ the driver guarantees that it won't subm
 Some drivers may need to modify spi_device characteristics like the
 transfer mode, wordsize, or clock rate.  This is done with spi_setup(),
 which would normally be called from probe() before the first I/O is
-done to the device.
+done to the device.  However, that can also be called at any time
+that no message is pending for that device.
 
 While "spi_device" would be the bottom boundary of the driver, the
 upper boundaries might include sysfs (especially for sensor readings),
@@ -445,11 +446,15 @@ SPI MASTER METHODS
 	This sets up the device clock rate, SPI mode, and word sizes.
 	Drivers may change the defaults provided by board_info, and then
 	call spi_setup(spi) to invoke this routine.  It may sleep.
+	Unless each SPI slave has its own configuration registers, don't
+	change them right away ... otherwise drivers could corrupt I/O
+	that's in progress for other SPI devices.
 
     master->transfer(struct spi_device *spi, struct spi_message *message)
     	This must not sleep.  Its responsibility is arrange that the
-	transfer happens and its complete() callback is issued; the two
-	will normally happen later, after other transfers complete.
+	transfer happens and its complete() callback is issued.  The two
+	will normally happen later, after other transfers complete, and
+	if the controller is idle it will need to be kickstarted.
 
     master->cleanup(struct spi_device *spi)
 	Your controller driver may use spi_device.controller_state to hold
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
new file mode 100644
index 0000000..5c8e1b9
--- /dev/null
+++ b/Documentation/spi/spidev
@@ -0,0 +1,307 @@
+SPI devices have a limited userspace API, supporting basic half-duplex
+read() and write() access to SPI slave devices.  Using ioctl() requests,
+full duplex transfers and device I/O configuration are also available.
+
+	#include <fcntl.h>
+	#include <unistd.h>
+	#include <sys/ioctl.h>
+	#include <linux/types.h>
+	#include <linux/spi/spidev.h>
+
+Some reasons you might want to use this programming interface include:
+
+ * Prototyping in an environment that's not crash-prone; stray pointers
+   in userspace won't normally bring down any Linux system.
+
+ * Developing simple protocols used to talk to microcontrollers acting
+   as SPI slaves, which you may need to change quite often.
+
+Of course there are drivers that can never be written in userspace, because
+they need to access kernel interfaces (such as IRQ handlers or other layers
+of the driver stack) that are not accessible to userspace.
+
+
+DEVICE CREATION, DRIVER BINDING
+===============================
+The simplest way to arrange to use this driver is to just list it in the
+spi_board_info for a device as the driver it should use:  the "modalias"
+entry is "spidev", matching the name of the driver exposing this API.
+Set up the other device characteristics (bits per word, SPI clocking,
+chipselect polarity, etc) as usual, so you won't always need to override
+them later.
+
+(Sysfs also supports userspace driven binding/unbinding of drivers to
+devices.  That mechanism might be supported here in the future.)
+
+When you do that, the sysfs node for the SPI device will include a child
+device node with a "dev" attribute that will be understood by udev or mdev.
+(Larger systems will have "udev".  Smaller ones may configure "mdev" into
+busybox; it's less featureful, but often enough.)  For a SPI device with
+chipselect C on bus B, you should see:
+
+    /dev/spidevB.C ... character special device, major number 153 with
+	a dynamically chosen minor device number.  This is the node
+	that userspace programs will open, created by "udev" or "mdev".
+
+    /sys/devices/.../spiB.C ... as usual, the SPI device node will
+	be a child of its SPI master controller.
+
+    /sys/class/spidev/spidevB.C ... created when the "spidev" driver
+	binds to that device.  (Directory or symlink, based on whether
+	or not you enabled the "deprecated sysfs files" Kconfig option.)
+
+Do not try to manage the /dev character device special file nodes by hand.
+That's error prone, and you'd need to pay careful attention to system
+security issues; udev/mdev should already be configured securely.
+
+If you unbind the "spidev" driver from that device, those two "spidev" nodes
+(in sysfs and in /dev) should automatically be removed (respectively by the
+kernel and by udev/mdev).  You can unbind by removing the "spidev" driver
+module, which will affect all devices using this driver.  You can also unbind
+by having kernel code remove the SPI device, probably by removing the driver
+for its SPI controller (so its spi_master vanishes).
+
+Since this is a standard Linux device driver -- even though it just happens
+to expose a low level API to userspace -- it can be associated with any number
+of devices at a time.  Just provide one spi_board_info record for each such
+SPI device, and you'll get a /dev device node for each device.
+
+
+BASIC CHARACTER DEVICE API
+==========================
+Normal open() and close() operations on /dev/spidevB.D files work as you
+would expect.
+
+Standard read() and write() operations are obviously only half-duplex, and
+the chipselect is deactivated between those operations.  Full-duplex access,
+and composite operation without chipselect de-activation, is available using
+the SPI_IOC_MESSAGE(N) request.
+
+Several ioctl() requests let your driver read or override the device's current
+settings for data transfer parameters:
+
+    SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will
+	return (RD) or assign (WR) the SPI transfer mode.  Use the constants
+	SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
+	(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
+	sample on trailing edge iff this is set) flags.
+
+    SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
+	which will return (RD) or assign (WR) the bit justification used to
+	transfer SPI words.  Zero indicates MSB-first; other values indicate
+	the less common LSB-first encoding.  In both cases the specified value
+	is right-justified in each word, so that unused (TX) or undefined (RX)
+	bits are in the MSBs.
+
+    SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to
+	a byte which will return (RD) or assign (WR) the number of bits in
+	each SPI transfer word.  The value zero signifies eight bits.
+
+    SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a
+	u32 which will return (RD) or assign (WR) the maximum SPI transfer
+	speed, in Hz.  The controller can't necessarily assign that specific
+	clock speed.
+
+NOTES:
+
+    - At this time there is no async I/O support; everything is purely
+      synchronous.
+
+    - There's currently no way to report the actual bit rate used to
+      shift data to/from a given device.
+
+    - From userspace, you can't currently change the chip select polarity;
+      that could corrupt transfers to other devices sharing the SPI bus.
+      Each SPI device is deselected when it's not in active use, allowing
+      other drivers to talk to other devices.
+
+    - There's a limit on the number of bytes each I/O request can transfer
+      to the SPI device.  It defaults to one page, but that can be changed
+      using a module parameter.
+
+    - Because SPI has no low-level transfer acknowledgement, you usually
+      won't see any I/O errors when talking to a non-existent device.
+
+
+FULL DUPLEX CHARACTER DEVICE API
+================================
+
+See the sample program below for one example showing the use of the full
+duplex programming interface.  (Although it doesn't perform a full duplex
+transfer.)  The model is the same as that used in the kernel spi_sync()
+request; the individual transfers offer the same capabilities as are
+available to kernel drivers (except that it's not asynchronous).
+
+The example shows one half-duplex RPC-style request and response message.
+These requests commonly require that the chip not be deselected between
+the request and response.  Several such requests could be chained into
+a single kernel request, even allowing the chip to be deselected after
+each response.  (Other protocol options include changing the word size
+and bitrate for each transfer segment.)
+
+To make a full duplex request, provide both rx_buf and tx_buf for the
+same transfer.  It's even OK if those are the same buffer.
+
+
+SAMPLE PROGRAM
+==============
+
+--------------------------------	CUT HERE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+
+static int verbose;
+
+static void do_read(int fd, int len)
+{
+	unsigned char	buf[32], *bp;
+	int		status;
+
+	/* read at least 2 bytes, no more than 32 */
+	if (len < 2)
+		len = 2;
+	else if (len > sizeof(buf))
+		len = sizeof(buf);
+	memset(buf, 0, sizeof buf);
+
+	status = read(fd, buf, len);
+	if (status < 0) {
+		perror("read");
+		return;
+	}
+	if (status != len) {
+		fprintf(stderr, "short read\n");
+		return;
+	}
+
+	printf("read(%2d, %2d): %02x %02x,", len, status,
+		buf[0], buf[1]);
+	status -= 2;
+	bp = buf + 2;
+	while (status-- > 0)
+		printf(" %02x", *bp++);
+	printf("\n");
+}
+
+static void do_msg(int fd, int len)
+{
+	struct spi_ioc_transfer	xfer[2];
+	unsigned char		buf[32], *bp;
+	int			status;
+
+	memset(xfer, 0, sizeof xfer);
+	memset(buf, 0, sizeof buf);
+
+	if (len > sizeof buf)
+		len = sizeof buf;
+
+	buf[0] = 0xaa;
+	xfer[0].tx_buf = (__u64) buf;
+	xfer[0].len = 1;
+
+	xfer[1].rx_buf = (__u64) buf;
+	xfer[1].len = len;
+
+	status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
+	if (status < 0) {
+		perror("SPI_IOC_MESSAGE");
+		return;
+	}
+
+	printf("response(%2d, %2d): ", len, status);
+	for (bp = buf; len; len--)
+		printf(" %02x", *bp++);
+	printf("\n");
+}
+
+static void dumpstat(const char *name, int fd)
+{
+	__u8	mode, lsb, bits;
+	__u32	speed;
+
+	if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+		perror("SPI rd_mode");
+		return;
+	}
+	if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
+		perror("SPI rd_lsb_fist");
+		return;
+	}
+	if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
+		perror("SPI bits_per_word");
+		return;
+	}
+	if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
+		perror("SPI max_speed_hz");
+		return;
+	}
+
+	printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+		name, mode, bits, lsb ? "(lsb first) " : "", speed);
+}
+
+int main(int argc, char **argv)
+{
+	int		c;
+	int		readcount = 0;
+	int		msglen = 0;
+	int		fd;
+	const char	*name;
+
+	while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
+		switch (c) {
+		case 'm':
+			msglen = atoi(optarg);
+			if (msglen < 0)
+				goto usage;
+			continue;
+		case 'r':
+			readcount = atoi(optarg);
+			if (readcount < 0)
+				goto usage;
+			continue;
+		case 'v':
+			verbose++;
+			continue;
+		case 'h':
+		case '?':
+usage:
+			fprintf(stderr,
+				"usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
+				argv[0]);
+			return 1;
+		}
+	}
+
+	if ((optind + 1) != argc)
+		goto usage;
+	name = argv[optind];
+
+	fd = open(name, O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		return 1;
+	}
+
+	dumpstat(name, fd);
+
+	if (msglen)
+		do_msg(fd, msglen);
+
+	if (readcount)
+		do_read(fd, readcount);
+
+	close(fd);
+	return 0;
+}
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index e96a341..1d19256 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -197,11 +197,22 @@ and may not be fast.
 
 panic_on_oom
 
-This enables or disables panic on out-of-memory feature.  If this is set to 1,
-the kernel panics when out-of-memory happens.  If this is set to 0, the kernel
-will kill some rogue process, called oom_killer.  Usually, oom_killer can kill
-rogue processes and system will survive.  If you want to panic the system
-rather than killing rogue processes, set this to 1.
+This enables or disables panic on out-of-memory feature.
 
-The default value is 0.
+If this is set to 0, the kernel will kill some rogue process,
+called oom_killer.  Usually, oom_killer can kill rogue processes and
+system will survive.
+
+If this is set to 1, the kernel panics when out-of-memory happens.
+However, if a process limits using nodes by mempolicy/cpusets,
+and those nodes become memory exhaustion status, one process
+may be killed by oom-killer. No panic occurs in this case.
+Because other nodes' memory may be free. This means system total status
+may be not fatal yet.
 
+If this is set to 2, the kernel panics compulsorily even on the
+above-mentioned.
+
+The default value is 0.
+1 and 2 are for failover of clustering. Please select either
+according to your policy of failover.
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index d43aa9d..ba328f2 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -1,6 +1,6 @@
 Linux Magic System Request Key Hacks
 Documentation for sysrq.c
-Last update: 2007-JAN-06
+Last update: 2007-MAR-14
 
 *  What is the magic SysRq key?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -75,7 +75,7 @@ On all -  write a character to /proc/sys
 
 'f'	- Will call oom_kill to kill a memory hog process.
 
-'g'	- Used by kgdb on ppc platforms.
+'g'	- Used by kgdb on ppc and sh platforms.
 
 'h'     - Will display help (actually any other key than those listed
           above will display help. but 'h' is easy to remember :-)
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
new file mode 100644
index 0000000..2d48033
--- /dev/null
+++ b/Documentation/thinkpad-acpi.txt
@@ -0,0 +1,981 @@
+		     ThinkPad ACPI Extras Driver
+
+                            Version 0.14
+                          April 21st, 2007
+
+               Borislav Deianov <borislav@users.sf.net>
+	     Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+		      http://ibm-acpi.sf.net/
+
+
+This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
+supports various features of these laptops which are accessible
+through the ACPI and ACPI EC framework, but not otherwise fully
+supported by the generic Linux ACPI drivers.
+
+This driver used to be named ibm-acpi until kernel 2.6.21 and release
+0.13-20070314.  It used to be in the drivers/acpi tree, but it was
+moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
+2.6.22, and release 0.14.
+
+
+Status
+------
+
+The features currently supported are the following (see below for
+detailed description):
+
+	- Fn key combinations
+	- Bluetooth enable and disable
+	- video output switching, expansion control
+	- ThinkLight on and off
+	- limited docking and undocking
+	- UltraBay eject
+	- CMOS control
+	- LED control
+	- ACPI sounds
+	- temperature sensors
+	- Experimental: embedded controller register dump
+	- LCD brightness control
+	- Volume control
+	- Fan control and monitoring: 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
+reports, especially if they add to or correct the compatibility table.
+Please include the following information in your report:
+
+	- ThinkPad model name
+	- a copy of your DSDT, from /proc/acpi/dsdt
+	- a copy of the output of dmidecode, with serial numbers
+	  and UUIDs masked off
+	- which driver features work and which don't
+	- the observed behavior of non-working features
+
+Any other comments or patches are also more than welcome.
+
+
+Installation
+------------
+
+If you are compiling this driver as included in the Linux kernel
+sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally
+enable the CONFIG_THINKPAD_ACPI_BAY option if you want the
+thinkpad-specific bay functionality.
+
+Features
+--------
+
+The driver exports two different interfaces to userspace, which can be
+used to access the features it provides.  One is a legacy procfs-based
+interface, which will be removed at some time in the distant future.
+The other is a new sysfs-based interface which is not complete yet.
+
+The procfs interface creates the /proc/acpi/ibm directory.  There is a
+file under that directory for each feature it supports.  The procfs
+interface is mostly frozen, and will change very little if at all: it
+will not be extended to add any new functionality in the driver, instead
+all new functionality will be implemented on the sysfs interface.
+
+The sysfs interface tries to blend in the generic Linux sysfs subsystems
+and classes as much as possible.  Since some of these subsystems are not
+yet ready or stabilized, it is expected that this interface will change,
+and any and all userspace programs must deal with it.
+
+
+Notes about the sysfs interface:
+
+Unlike what was done with the procfs interface, correctness when talking
+to the sysfs interfaces will be enforced, as will correctness in the
+thinkpad-acpi's implementation of sysfs interfaces.
+
+Also, any bugs in the thinkpad-acpi sysfs driver code or in the
+thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
+maximum correctness, even if that means changing an interface in
+non-compatible ways.  As these interfaces mature both in the kernel and
+in thinkpad-acpi, such changes should become quite rare.
+
+Applications interfacing to the thinkpad-acpi sysfs interfaces must
+follow all sysfs guidelines and correctly process all errors (the sysfs
+interface makes extensive use of errors).  File descriptors and open /
+close operations to the sysfs inodes must also be properly implemented.
+
+The version of thinkpad-acpi's sysfs interface is exported by the driver
+as a driver attribute (see below).
+
+Sysfs driver attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/bus/platform/drivers/thinkpad-acpi/.
+
+Sysfs device attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/.
+
+Driver version
+--------------
+
+procfs: /proc/acpi/ibm/driver
+sysfs driver attribute: version
+
+The driver name and version. No commands can be written to this file.
+
+Sysfs interface version
+-----------------------
+
+sysfs driver attribute: interface_version
+
+Version of the thinkpad-acpi sysfs interface, as an unsigned long
+(output in hex format: 0xAAAABBCC), where:
+	AAAA - major revision
+	BB - minor revision
+	CC - bugfix revision
+
+The sysfs interface version changelog for the driver can be found at the
+end of this document.  Changes to the sysfs interface done by the kernel
+subsystems are not documented here, nor are they tracked by this
+attribute.
+
+Hot keys
+--------
+
+procfs: /proc/acpi/ibm/hotkey
+sysfs device attribute: hotkey/*
+
+Without this driver, only the Fn-F4 key (sleep button) generates an
+ACPI event. With the driver loaded, the hotkey feature enabled and the
+mask set (see below), the various hot keys generate ACPI events in the
+following format:
+
+	ibm/hotkey HKEY 00000080 0000xxxx
+
+The last four digits vary depending on the key combination pressed.
+All labeled Fn-Fx key combinations generate distinct events. In
+addition, the lid microswitch and some docking station buttons may
+also generate such events.
+
+The bit mask allows some control over which hot keys generate ACPI
+events. Not all bits in the mask can be modified. Not all bits that
+can be modified do anything. Not all hot keys can be individually
+controlled by the mask. Most recent ThinkPad models honor the
+following bits (assuming the hot keys feature has been enabled):
+
+	key	bit	behavior when set	behavior when unset
+
+	Fn-F3			always generates ACPI event
+	Fn-F4			always generates ACPI event
+	Fn-F5	0010	generate ACPI event	enable/disable Bluetooth
+	Fn-F7	0040	generate ACPI event	switch LCD and external display
+	Fn-F8	0080	generate ACPI event	expand screen or none
+	Fn-F9	0100	generate ACPI event	none
+	Fn-F12			always generates ACPI event
+
+Some models do not support all of the above. For example, the T30 does
+not support Fn-F5 and Fn-F9. Other models do not support the mask at
+all. On those models, hot keys cannot be controlled individually.
+
+Note that enabling ACPI events for some keys prevents their default
+behavior. For example, if events for Fn-F5 are enabled, that key will
+no longer enable/disable Bluetooth by itself. This can still be done
+from an acpid handler for the ibm/hotkey event.
+
+Note also that not all Fn key combinations are supported through
+ACPI. For example, on the X40, the brightness, volume and "Access IBM"
+buttons do not generate ACPI events even with this driver. They *can*
+be used through the "ThinkPad Buttons" utility, see
+http://www.nongnu.org/tpb/
+
+procfs notes:
+
+The following commands can be written to the /proc/acpi/ibm/hotkey file:
+
+	echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
+	echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
+	echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
+	echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+	... any other 4-hex-digit mask ...
+	echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+
+sysfs notes:
+
+	The hot keys attributes are in a hotkey/ subdirectory off the
+	thinkpad device.
+
+	bios_enabled:
+		Returns the status of the hot keys feature when
+		thinkpad-acpi was loaded.  Upon module unload, the hot
+		key feature status will be restored to this value.
+
+		0: hot keys were disabled
+		1: hot keys were enabled
+
+	bios_mask:
+		Returns the hot keys mask when thinkpad-acpi was loaded.
+		Upon module unload, the hot keys mask will be restored
+		to this value.
+
+	enable:
+		Enables/disables the hot keys feature, and reports
+		current status of the hot keys feature.
+
+		0: disables the hot keys feature / feature disabled
+		1: enables the hot keys feature / feature enabled
+
+	mask:
+		bit mask to enable ACPI event generation for each hot
+		key (see above).  Returns the current status of the hot
+		keys mask, and allows one to modify it.
+
+
+Bluetooth
+---------
+
+procfs: /proc/acpi/ibm/bluetooth
+sysfs device attribute: bluetooth/enable
+
+This feature shows the presence and current state of a ThinkPad
+Bluetooth device in the internal ThinkPad CDC slot.
+
+Procfs notes:
+
+If Bluetooth is installed, the following commands can be used:
+
+	echo enable > /proc/acpi/ibm/bluetooth
+	echo disable > /proc/acpi/ibm/bluetooth
+
+Sysfs notes:
+
+	If the Bluetooth CDC card is installed, it can be enabled /
+	disabled through the "bluetooth/enable" thinkpad-acpi device
+	attribute, and its current status can also be queried.
+
+	enable:
+		0: disables Bluetooth / Bluetooth is disabled
+		1: enables Bluetooth / Bluetooth is enabled.
+
+	Note: this interface will be probably be superseeded by the
+	generic rfkill class.
+
+Video output control -- /proc/acpi/ibm/video
+--------------------------------------------
+
+This feature allows control over the devices used for video output -
+LCD, CRT or DVI (if available). The following commands are available:
+
+	echo lcd_enable > /proc/acpi/ibm/video
+	echo lcd_disable > /proc/acpi/ibm/video
+	echo crt_enable > /proc/acpi/ibm/video
+	echo crt_disable > /proc/acpi/ibm/video
+	echo dvi_enable > /proc/acpi/ibm/video
+	echo dvi_disable > /proc/acpi/ibm/video
+	echo auto_enable > /proc/acpi/ibm/video
+	echo auto_disable > /proc/acpi/ibm/video
+	echo expand_toggle > /proc/acpi/ibm/video
+	echo video_switch > /proc/acpi/ibm/video
+
+Each video output device can be enabled or disabled individually.
+Reading /proc/acpi/ibm/video shows the status of each device.
+
+Automatic video switching can be enabled or disabled.  When automatic
+video switching is enabled, certain events (e.g. opening the lid,
+docking or undocking) cause the video output device to change
+automatically. While this can be useful, it also causes flickering
+and, on the X40, video corruption. By disabling automatic switching,
+the flickering or video corruption can be avoided.
+
+The video_switch command cycles through the available video outputs
+(it simulates the behavior of Fn-F7).
+
+Video expansion can be toggled through this feature. This controls
+whether the display is expanded to fill the entire LCD screen when a
+mode with less than full resolution is used. Note that the current
+video expansion status cannot be determined through this feature.
+
+Note that on many models (particularly those using Radeon graphics
+chips) the X driver configures the video card in a way which prevents
+Fn-F7 from working. This also disables the video output switching
+features of this driver, as it uses the same ACPI methods as
+Fn-F7. Video switching on the console should still work.
+
+UPDATE: There's now a patch for the X.org Radeon driver which
+addresses this issue. Some people are reporting success with the patch
+while others are still having problems. For more information:
+
+https://bugs.freedesktop.org/show_bug.cgi?id=2000
+
+ThinkLight control -- /proc/acpi/ibm/light
+------------------------------------------
+
+The current status of the ThinkLight can be found in this file. A few
+models which do not make the status available will show it as
+"unknown". The available commands are:
+
+	echo on  > /proc/acpi/ibm/light
+	echo off > /proc/acpi/ibm/light
+
+Docking / undocking -- /proc/acpi/ibm/dock
+------------------------------------------
+
+Docking and undocking (e.g. with the X4 UltraBase) requires some
+actions to be taken by the operating system to safely make or break
+the electrical connections with the dock.
+
+The docking feature of this driver generates the following ACPI events:
+
+	ibm/dock GDCK 00000003 00000001 -- eject request
+	ibm/dock GDCK 00000003 00000002 -- undocked
+	ibm/dock GDCK 00000000 00000003 -- docked
+
+NOTE: These events will only be generated if the laptop was docked
+when originally booted. This is due to the current lack of support for
+hot plugging of devices in the Linux ACPI framework. If the laptop was
+booted while not in the dock, the following message is shown in the
+logs:
+
+	Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present
+
+In this case, no dock-related events are generated but the dock and
+undock commands described below still work. They can be executed
+manually or triggered by Fn key combinations (see the example acpid
+configuration files included in the driver tarball package available
+on the web site).
+
+When the eject request button on the dock is pressed, the first event
+above is generated. The handler for this event should issue the
+following command:
+
+	echo undock > /proc/acpi/ibm/dock
+
+After the LED on the dock goes off, it is safe to eject the laptop.
+Note: if you pressed this key by mistake, go ahead and eject the
+laptop, then dock it back in. Otherwise, the dock may not function as
+expected.
+
+When the laptop is docked, the third event above is generated. The
+handler for this event should issue the following command to fully
+enable the dock:
+
+	echo dock > /proc/acpi/ibm/dock
+
+The contents of the /proc/acpi/ibm/dock file shows the current status
+of the dock, as provided by the ACPI framework.
+
+The docking support in this driver does not take care of enabling or
+disabling any other devices you may have attached to the dock. For
+example, a CD drive plugged into the UltraBase needs to be disabled or
+enabled separately. See the provided example acpid configuration files
+for how this can be accomplished.
+
+There is no support yet for PCI devices that may be attached to a
+docking station, e.g. in the ThinkPad Dock II. The driver currently
+does not recognize, enable or disable such devices. This means that
+the only docking stations currently supported are the X-series
+UltraBase docks and "dumb" port replicators like the Mini Dock (the
+latter don't need any ACPI support, actually).
+
+UltraBay eject -- /proc/acpi/ibm/bay
+------------------------------------
+
+Inserting or ejecting an UltraBay device requires some actions to be
+taken by the operating system to safely make or break the electrical
+connections with the device.
+
+This feature generates the following ACPI events:
+
+	ibm/bay MSTR 00000003 00000000 -- eject request
+	ibm/bay MSTR 00000001 00000000 -- eject lever inserted
+
+NOTE: These events will only be generated if the UltraBay was present
+when the laptop was originally booted (on the X series, the UltraBay
+is in the dock, so it may not be present if the laptop was undocked).
+This is due to the current lack of support for hot plugging of devices
+in the Linux ACPI framework. If the laptop was booted without the
+UltraBay, the following message is shown in the logs:
+
+	Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present
+
+In this case, no bay-related events are generated but the eject
+command described below still works. It can be executed manually or
+triggered by a hot key combination.
+
+Sliding the eject lever generates the first event shown above. The
+handler for this event should take whatever actions are necessary to
+shut down the device in the UltraBay (e.g. call idectl), then issue
+the following command:
+
+	echo eject > /proc/acpi/ibm/bay
+
+After the LED on the UltraBay goes off, it is safe to pull out the
+device.
+
+When the eject lever is inserted, the second event above is
+generated. The handler for this event should take whatever actions are
+necessary to enable the UltraBay device (e.g. call idectl).
+
+The contents of the /proc/acpi/ibm/bay file shows the current status
+of the UltraBay, as provided by the ACPI framework.
+
+EXPERIMENTAL warm eject support on the 600e/x, A22p and A3x (To use
+this feature, you need to supply the experimental=1 parameter when
+loading the module):
+
+These models do not have a button near the UltraBay device to request
+a hot eject but rather require the laptop to be put to sleep
+(suspend-to-ram) before the bay device is ejected or inserted).
+The sequence of steps to eject the device is as follows:
+
+	echo eject > /proc/acpi/ibm/bay
+	put the ThinkPad to sleep
+	remove the drive
+	resume from sleep
+	cat /proc/acpi/ibm/bay should show that the drive was removed
+
+On the A3x, both the UltraBay 2000 and UltraBay Plus devices are
+supported. Use "eject2" instead of "eject" for the second bay.
+
+Note: the UltraBay eject support on the 600e/x, A22p and A3x is
+EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
+
+CMOS control
+------------
+
+procfs: /proc/acpi/ibm/cmos
+sysfs device attribute: cmos_command
+
+This feature is used internally by the ACPI firmware to control the
+ThinkLight on most newer ThinkPad models. It may also control LCD
+brightness, sounds volume and more, but only on some models.
+
+The range of valid cmos command numbers is 0 to 21, but not all have an
+effect and the behavior varies from model to model.  Here is the behavior
+on the X40 (tpb is the ThinkPad Buttons utility):
+
+	0 - no effect but tpb reports "Volume down"
+	1 - no effect but tpb reports "Volume up"
+	2 - no effect but tpb reports "Mute on"
+	3 - simulate pressing the "Access IBM" button
+	4 - LCD brightness up
+	5 - LCD brightness down
+	11 - toggle screen expansion
+	12 - ThinkLight on
+	13 - ThinkLight off
+	14 - no effect but tpb reports ThinkLight status change
+
+The cmos command interface is prone to firmware split-brain problems, as
+in newer ThinkPads it is just a compatibility layer.
+
+LED control -- /proc/acpi/ibm/led
+---------------------------------
+
+Some of the LED indicators can be controlled through this feature. The
+available commands are:
+
+	echo '<led number> on' >/proc/acpi/ibm/led
+	echo '<led number> off' >/proc/acpi/ibm/led
+	echo '<led number> blink' >/proc/acpi/ibm/led
+
+The <led number> range is 0 to 7. The set of LEDs that can be
+controlled varies from model to model. Here is the mapping on the X40:
+
+	0 - power
+	1 - battery (orange)
+	2 - battery (green)
+	3 - UltraBase
+	4 - UltraBay
+	7 - standby
+
+All of the above can be turned on and off and can be made to blink.
+
+ACPI sounds -- /proc/acpi/ibm/beep
+----------------------------------
+
+The BEEP method is used internally by the ACPI firmware to provide
+audible alerts in various situations. This feature allows the same
+sounds to be triggered manually.
+
+The commands are non-negative integer numbers:
+
+	echo <number> >/proc/acpi/ibm/beep
+
+The valid <number> range is 0 to 17. Not all numbers trigger sounds
+and the sounds vary from model to model. Here is the behavior on the
+X40:
+
+	0 - stop a sound in progress (but use 17 to stop 16)
+	2 - two beeps, pause, third beep ("low battery")
+	3 - single beep
+	4 - high, followed by low-pitched beep ("unable")
+	5 - single beep
+	6 - very high, followed by high-pitched beep ("AC/DC")
+	7 - high-pitched beep
+	9 - three short beeps
+	10 - very long beep
+	12 - low-pitched beep
+	15 - three high-pitched beeps repeating constantly, stop with 0
+	16 - one medium-pitched beep repeating constantly, stop with 17
+	17 - stop 16
+
+Temperature sensors
+-------------------
+
+procfs: /proc/acpi/ibm/thermal
+sysfs device attributes: (hwmon) temp*_input
+
+Most ThinkPads include six or more separate temperature sensors but
+only expose the CPU temperature through the standard ACPI methods.
+This feature shows readings from up to eight different sensors on older
+ThinkPads, and it has experimental support for up to sixteen different
+sensors on newer ThinkPads.
+
+EXPERIMENTAL: The 16-sensors 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.  When EXPERIMENTAL
+mode is enabled, reading the first 8 sensors on newer ThinkPads will
+also use an new experimental thermal sensor access mode.
+
+For example, on the X40, a typical output may be:
+temperatures:   42 42 45 41 36 -128 33 -128
+
+EXPERIMENTAL: On the T43/p, a typical output may be:
+temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
+
+The mapping of thermal sensors to physical locations varies depending on
+system-board model (and thus, on ThinkPad model).
+
+http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
+tries to track down these locations for various models.
+
+Most (newer?) models seem to follow this pattern:
+
+1:  CPU
+2:  (depends on model)
+3:  (depends on model)
+4:  GPU
+5:  Main battery: main sensor
+6:  Bay battery: main sensor
+7:  Main battery: secondary sensor
+8:  Bay battery: secondary sensor
+9-15: (depends on model)
+
+For the R51 (source: Thomas Gruber):
+2:  Mini-PCI
+3:  Internal HDD
+
+For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
+http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
+2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
+3:  PCMCIA slot
+9:  MCH (northbridge) to DRAM Bus
+10: ICH (southbridge), under Mini-PCI card, under touchpad
+11: Power regulator, underside of system board, below F2 key
+
+The A31 has a very atypical layout for the thermal sensors
+(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
+1:  CPU
+2:  Main Battery: main sensor
+3:  Power Converter
+4:  Bay Battery: main sensor
+5:  MCH (northbridge)
+6:  PCMCIA/ambient
+7:  Main Battery: secondary sensor
+8:  Bay Battery: secondary sensor
+
+
+Procfs notes:
+	Readings from sensors that are not available return -128.
+	No commands can be written to this file.
+
+Sysfs notes:
+	Sensors that are not available return the ENXIO error.  This
+	status may change at runtime, as there are hotplug thermal
+	sensors, like those inside the batteries and docks.
+
+	thinkpad-acpi thermal sensors are reported through the hwmon
+	subsystem, and follow all of the hwmon guidelines at
+	Documentation/hwmon.
+
+
+EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
+------------------------------------------------------------------------
+
+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 dumps the values of 256 embedded controller
+registers. Values which have changed since the last time the registers
+were dumped are marked with a star:
+
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
+EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
+EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
+EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
+EC 0x30:  01  07  1a  00  30  04  00  00 *85  00  00  10  00  50  00  00
+EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
+EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03 *bc *02 *bc
+EC 0x60: *02 *bc *02  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0x70:  00  00  00  00  00  12  30  40 *24 *26 *2c *27 *20  80 *1f  80
+EC 0x80:  00  00  00  06 *37 *0e  03  00  00  00  0e  07  00  00  00  00
+EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xa0: *ff  09  ff  09  ff  ff *64  00 *00 *00 *a2  41 *ff *ff *e0  00
+EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
+EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
+
+This feature can be used to determine the register holding the fan
+speed on some models. To do that, do the following:
+
+	- make sure the battery is fully charged
+	- make sure the fan is running
+	- run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so
+
+The first step makes sure various charging-related values don't
+vary. The second ensures that the fan-related values do vary, since
+the fan speed fluctuates a bit. The third will (hopefully) mark the
+fan register with a star:
+
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+EC       +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
+EC 0x00:  a7  47  87  01  fe  96  00  08  01  00  cb  00  00  00  40  00
+EC 0x10:  00  00  ff  ff  f4  3c  87  09  01  ff  42  01  ff  ff  0d  00
+EC 0x20:  00  00  00  00  00  00  00  00  00  00  00  03  43  00  00  80
+EC 0x30:  01  07  1a  00  30  04  00  00  85  00  00  10  00  50  00  00
+EC 0x40:  00  00  00  00  00  00  14  01  00  04  00  00  00  00  00  00
+EC 0x50:  00  c0  02  0d  00  01  01  02  02  03  03  03  03  bc  02  bc
+EC 0x60:  02  bc  02  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0x70:  00  00  00  00  00  12  30  40  24  27  2c  27  21  80  1f  80
+EC 0x80:  00  00  00  06 *be  0d  03  00  00  00  0e  07  00  00  00  00
+EC 0x90:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xa0:  ff  09  ff  09  ff  ff  64  00  00  00  a2  41  ff  ff  e0  00
+EC 0xb0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xc0:  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xd0:  03  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
+EC 0xe0:  00  00  00  00  00  00  00  00  11  20  49  04  24  06  55  03
+EC 0xf0:  31  55  48  54  35  38  57  57  08  2f  45  73  07  65  6c  1a
+
+Another set of values that varies often is the temperature
+readings. Since temperatures don't change vary fast, you can take
+several quick dumps to eliminate them.
+
+You can use a similar method to figure out the meaning of other
+embedded controller registers - e.g. make sure nothing else changes
+except the charging or discharging battery to determine which
+registers contain the current battery capacity, etc. If you experiment
+with this, do send me your results (including some complete dumps with
+a description of the conditions when they were taken.)
+
+LCD brightness control
+----------------------
+
+procfs: /proc/acpi/ibm/brightness
+sysfs backlight device "thinkpad_screen"
+
+This feature allows software control of the LCD brightness on ThinkPad
+models which don't have a hardware brightness slider.
+
+It has some limitations: the LCD backlight cannot be actually turned on or off
+by this interface, and in many ThinkPad models, the "dim while on battery"
+functionality will be enabled by the BIOS when this interface is used, and
+cannot be controlled.
+
+The backlight control has eight levels, ranging from 0 to 7.  Some of the
+levels may not be distinct.
+
+Procfs notes:
+
+	The available commands are:
+
+	echo up   >/proc/acpi/ibm/brightness
+	echo down >/proc/acpi/ibm/brightness
+	echo 'level <level>' >/proc/acpi/ibm/brightness
+
+Sysfs notes:
+
+The interface is implemented through the backlight sysfs class, which is poorly
+documented at this time.
+
+Locate the thinkpad_screen device under /sys/class/backlight, and inside it
+there will be the following attributes:
+
+	max_brightness:
+		Reads the maximum brightness the hardware can be set to.
+		The minimum is always zero.
+
+	actual_brightness:
+		Reads what brightness the screen is set to at this instant.
+
+	brightness:
+		Writes request the driver to change brightness to the given
+		value.  Reads will tell you what brightness the driver is trying
+		to set the display to when "power" is set to zero and the display
+		has not been dimmed by a kernel power management event.
+
+	power:
+		power management mode, where 0 is "display on", and 1 to 3 will
+		dim the display backlight to brightness level 0 because
+		thinkpad-acpi cannot really turn the backlight off.  Kernel
+		power management events can temporarily increase the current
+		power management level, i.e. they can dim the display.
+
+
+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:
+
+	echo up   >/proc/acpi/ibm/volume
+	echo down >/proc/acpi/ibm/volume
+	echo mute >/proc/acpi/ibm/volume
+	echo 'level <level>' >/proc/acpi/ibm/volume
+
+The <level> number range is 0 to 15 although not all of them may be
+distinct. The unmute the volume after the mute command, use either the
+up or down command (the level command will not unmute the volume).
+The current volume level and mute state is shown in the file.
+
+Fan control and monitoring: fan speed, fan enable/disable
+---------------------------------------------------------
+
+procfs: /proc/acpi/ibm/fan
+sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable
+
+NOTE NOTE NOTE: fan control operations are disabled by default for
+safety reasons.  To enable them, the module parameter "fan_control=1"
+must be given to thinkpad-acpi.
+
+This feature attempts to show the current fan speed, control mode and
+other fan data that might be available.  The speed is read directly
+from the hardware registers of the embedded controller.  This is known
+to work on later R, T, X and Z series ThinkPads but may show a bogus
+value on other models.
+
+Fan levels:
+
+Most ThinkPad fans work in "levels" at the firmware interface.  Level 0
+stops the fan.  The higher the level, the higher the fan speed, although
+adjacent levels often map to the same fan speed.  7 is the highest
+level, where the fan reaches the maximum recommended speed.
+
+Level "auto" means the EC changes the fan level according to some
+internal algorithm, usually based on readings from the thermal sensors.
+
+There is also a "full-speed" level, also known as "disengaged" level.
+In this level, the EC disables the speed-locked closed-loop fan control,
+and drives the fan as fast as it can go, which might exceed hardware
+limits, so use this level with caution.
+
+The fan usually ramps up or down slowly from one speed to another, and
+it is normal for the EC to take several seconds to react to fan
+commands.  The full-speed level may take up to two minutes to ramp up to
+maximum speed, and in some ThinkPads, the tachometer readings go stale
+while the EC is transitioning to the full-speed level.
+
+WARNING WARNING WARNING: do not leave the fan disabled unless you are
+monitoring all of the temperature sensor readings and you are ready to
+enable it if necessary to avoid overheating.
+
+An enabled fan in level "auto" may stop spinning if the EC decides the
+ThinkPad is cool enough and doesn't need the extra airflow.  This is
+normal, and the EC will spin the fan up if the varios thermal readings
+rise too much.
+
+On the X40, this seems to depend on the CPU and HDD temperatures.
+Specifically, the fan is turned on when either the CPU temperature
+climbs to 56 degrees or the HDD temperature climbs to 46 degrees.  The
+fan is turned off when the CPU temperature drops to 49 degrees and the
+HDD temperature drops to 41 degrees.  These thresholds cannot
+currently be controlled.
+
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met.  It will override any fan programming done
+through thinkpad-acpi.
+
+The thinkpad-acpi kernel driver can be programmed to revert the fan
+level to a safe setting if userspace does not issue one of the procfs
+fan commands: "enable", "disable", "level" or "watchdog", or if there
+are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
+set to 1, manual mode) within a configurable amount of time of up to
+120 seconds.  This functionality is called fan safety watchdog.
+
+Note that the watchdog timer stops after it enables the fan.  It will be
+rearmed again automatically (using the same interval) when one of the
+above mentioned fan commands is received.  The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made through
+means other than the "enable", "disable", and "level" procfs fan
+commands, or the hwmon fan control sysfs interface.
+
+Procfs notes:
+
+The fan may be enabled or disabled with the following commands:
+
+	echo enable  >/proc/acpi/ibm/fan
+	echo disable >/proc/acpi/ibm/fan
+
+Placing a fan on level 0 is the same as disabling it.  Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
+The fan level can be controlled with the command:
+
+	echo 'level <level>' > /proc/acpi/ibm/fan
+
+Where <level> is an integer from 0 to 7, or one of the words "auto" or
+"full-speed" (without the quotes).  Not all ThinkPads support the "auto"
+and "full-speed" levels.  The driver accepts "disengaged" as an alias for
+"full-speed", and reports it as "disengaged" for backwards
+compatibility.
+
+On the X31 and X40 (and ONLY on those models), the fan speed can be
+controlled to a certain degree.  Once the fan is running, it can be
+forced to run faster or slower with the following command:
+
+	echo 'speed <speed>' > /proc/acpi/ibm/fan
+
+The sustainable range of fan speeds on the X40 appears to be from about
+3700 to about 7350. Values outside this range either do not have any
+effect or the fan speed eventually settles somewhere in that range.  The
+fan cannot be stopped or started with this command.  This functionality
+is incomplete, and not available through the sysfs interface.
+
+To program the safety watchdog, use the "watchdog" command.
+
+	echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
+
+If you want to disable the watchdog, use 0 as the interval.
+
+Sysfs notes:
+
+The sysfs interface follows the hwmon subsystem guidelines for the most
+part, and the exception is the fan safety watchdog.
+
+Writes to any of the sysfs attributes may return the EINVAL error if
+that operation is not supported in a given ThinkPad or if the parameter
+is out-of-bounds, and EPERM if it is forbidden.  They may also return
+EINTR (interrupted system call), and EIO (I/O error while trying to talk
+to the firmware).
+
+Features not yet implemented by the driver return ENOSYS.
+
+hwmon device attribute pwm1_enable:
+	0: PWM offline (fan is set to full-speed mode)
+	1: Manual PWM control (use pwm1 to set fan level)
+	2: Hardware PWM control (EC "auto" mode)
+	3: reserved (Software PWM control, not implemented yet)
+
+	Modes 0 and 2 are not supported by all ThinkPads, and the
+	driver is not always able to detect this.  If it does know a
+	mode is unsupported, it will return -EINVAL.
+
+hwmon device attribute pwm1:
+	Fan level, scaled from the firmware values of 0-7 to the hwmon
+	scale of 0-255.  0 means fan stopped, 255 means highest normal
+	speed (level 7).
+
+	This attribute only commands the fan if pmw1_enable is set to 1
+	(manual PWM control).
+
+hwmon device attribute fan1_input:
+	Fan tachometer reading, in RPM.  May go stale on certain
+	ThinkPads while the EC transitions the PWM to offline mode,
+	which can take up to two minutes.  May return rubbish on older
+	ThinkPads.
+
+driver attribute fan_watchdog:
+	Fan safety watchdog timer interval, in seconds.  Minimum is
+	1 second, maximum is 120 seconds.  0 disables the watchdog.
+
+To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
+
+To start the fan in a safe mode: set pwm1_enable to 2.  If that fails
+with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
+would be the safest choice, though).
+
+
+EXPERIMENTAL: WAN
+-----------------
+
+procfs: /proc/acpi/ibm/wan
+sysfs device attribute: wwan/enable
+
+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 W-WAN (Sierra
+Wireless EV-DO) device.
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
+
+Procfs notes:
+
+If the W-WAN card is installed, the following commands can be used:
+
+	echo enable > /proc/acpi/ibm/wan
+	echo disable > /proc/acpi/ibm/wan
+
+Sysfs notes:
+
+	If the W-WAN card is installed, it can be enabled /
+	disabled through the "wwan/enable" thinkpad-acpi device
+	attribute, and its current status can also be queried.
+
+	enable:
+		0: disables WWAN card / WWAN card is disabled
+		1: enables WWAN card / WWAN card is enabled.
+
+	Note: this interface will be probably be superseeded by the
+	generic rfkill class.
+
+Multiple Commands, Module Parameters
+------------------------------------
+
+Multiple commands can be written to the proc files in one shot by
+separating them with commas, for example:
+
+	echo enable,0xffff > /proc/acpi/ibm/hotkey
+	echo lcd_disable,crt_enable > /proc/acpi/ibm/video
+
+Commands can also be specified when loading the thinkpad-acpi module,
+for example:
+
+	modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
+
+Enabling debugging output
+-------------------------
+
+The module takes a debug paramater which can be used to selectively
+enable various classes of debugging output, for example:
+
+	 modprobe ibm_acpi debug=0xffff
+
+will enable all debugging output classes.  It takes a bitmask, so
+to enable more than one output class, just add their values.
+
+	Debug bitmask		Description
+	0x0001			Initialization and probing
+	0x0002			Removal
+
+There is also a kernel build option to enable more debugging
+information, which may be necessary to debug driver problems.
+
+The level of debugging information output by the driver can be changed
+at runtime through sysfs, using the driver attribute debug_level.  The
+attribute takes the same bitmask as the debug module parameter above.
+
+Force loading of module
+-----------------------
+
+If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
+the module parameter force_load=1.  Regardless of whether this works or
+not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
+
+
+Sysfs interface changelog:
+
+0x000100:	Initial sysfs support, as a single platform driver and
+		device.
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
index 5f799e6..048a876 100644
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -108,7 +108,9 @@ hardware driver through the function poi
 structure:
 
 write()			Write a block of characters to the tty device.
-			Returns the number of characters accepted.
+			Returns the number of characters accepted. The
+			character buffer passed to this method is already
+			in kernel space.
 
 put_char()		Queues a character for writing to the tty device.
 			If there is no room in the queue, the character is
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index d61f6e7..b18e86a 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -42,7 +42,7 @@ ConnectTech WhiteHEAT 4 port converter
   http://www.connecttech.com
 
   For any questions or problems with this driver, please contact
-  Stuart MacDonald at stuartm@connecttech.com
+  Connect Tech's Support Department at support@connecttech.com
 
 
 HandSpring Visor, Palm USB, and Clié USB driver
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index 0f6808a..53ae866 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -16,7 +16,7 @@ situation as with tcpdump.
 
 Unlike the packet socket, usbmon has an interface which provides traces
 in a text format. This is used for two purposes. First, it serves as a
-common trace exchange format for tools while most sophisticated formats
+common trace exchange format for tools while more sophisticated formats
 are finalized. Second, humans can read it in case tools are not available.
 
 To collect a raw text trace, execute following steps.
@@ -34,7 +34,7 @@ #
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  2s  2t  3s  3t  4s  4t
+1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
 2. Find which bus connects to the desired device
@@ -54,7 +54,7 @@ Bus=03 means it's bus 3.
 
 3. Start 'cat'
 
-# cat /sys/kernel/debug/usbmon/3t > /tmp/1.mon.out
+# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
@@ -75,46 +75,80 @@ that the file size is not excessive for 
 
 * Raw text data format
 
-The '1t' type data consists of a stream of events, such as URB submission,
+Two formats are supported currently: the original, or '1t' format, and
+the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u'
+format adds a few fields, such as ISO frame descriptors, interval, etc.
+It produces slightly longer lines, but otherwise is a perfect superset
+of '1t' format.
+
+If it is desired to recognize one from the other in a program, look at the
+"address" word (see below), where '1u' format adds a bus number. If 2 colons
+are present, it's the '1t' format, otherwise '1u'.
+
+Any text format data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
 of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 
 Here is the list of words, from left to right:
+
 - URB Tag. This is used to identify URBs is normally a kernel mode address
  of the URB structure in hexadecimal.
+
 - Timestamp in microseconds, a decimal number. The timestamp's resolution
   depends on available clock, and so it can be much worse than a microsecond
   (if the implementation uses jiffies, for example).
+
 - Event Type. This type refers to the format of the event, not URB type.
   Available types are: S - submission, C - callback, E - submission error.
-- "Pipe". The pipe concept is deprecated. This is a composite word, used to
-  be derived from information in pipes. It consists of three fields, separated
-  by colons: URB type and direction, Device address, Endpoint number.
+
+- "Address" word (formerly a "pipe"). It consists of four fields, separated by
+  colons: URB type and direction, Bus number, Device address, Endpoint number.
   Type and direction are encoded with two bytes in the following manner:
     Ci Co   Control input and output
     Zi Zo   Isochronous input and output
     Ii Io   Interrupt input and output
     Bi Bo   Bulk input and output
-  Device address and Endpoint number are 3-digit and 2-digit (respectively)
-  decimal numbers, with leading zeroes.
-- URB Status. In most cases, this field contains a number, sometimes negative,
-  which represents a "status" field of the URB. This field makes no sense for
-  submissions, but is present anyway to help scripts with parsing. When an
-  error occurs, the field contains the error code. In case of a submission of
-  a Control packet, this field contains a Setup Tag instead of an error code.
-  It is easy to tell whether the Setup Tag is present because it is never a
-  number. Thus if scripts find a number in this field, they proceed to read
-  Data Length. If they find something else, like a letter, they read the setup
-  packet before reading the Data Length.
+  Bus number, Device address, and Endpoint are decimal numbers, but they may
+  have leading zeros, for the sake of human readers.
+
+- URB Status word. This is either a letter, or several numbers separated
+  by colons: URB status, interval, start frame, and error count. Unlike the
+  "address" word, all fields save the status are optional. Interval is printed
+  only for interrupt and isochronous URBs. Start frame is printed only for
+  isochronous URBs. Error count is printed only for isochronous callback
+  events.
+
+  The status field is a decimal number, sometimes negative, which represents
+  a "status" field of the URB. This field makes no sense for submissions, but
+  is present anyway to help scripts with parsing. When an error occurs, the
+  field contains the error code.
+
+  In case of a submission of a Control packet, this field contains a Setup Tag
+  instead of an group of numbers. It is easy to tell whether the Setup Tag is
+  present because it is never a number. Thus if scripts find a set of numbers
+  in this word, they proceed to read Data Length (except for isochronous URBs).
+  If they find something else, like a letter, they read the setup packet before
+  reading the Data Length or isochronous descriptors.
+
 - Setup packet, if present, consists of 5 words: one of each for bmRequestType,
   bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
   These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
   packet was present, but not captured, and the fields contain filler.
+
+- Number of isochronous frame descriptors and descriptors themselves.
+  If an Isochronous transfer event has a set of descriptors, a total number
+  of them in an URB is printed first, then a word per descriptor, up to a
+  total of 5. The word consists of 3 colon-separated decimal numbers for
+  status, offset, and length respectively. For submissions, initial length
+  is reported. For callbacks, actual length is reported.
+
 - Data Length. For submissions, this is the requested length. For callbacks,
   this is the actual length.
+
 - Data tag. The usbmon may not always capture data, even if length is nonzero.
   The data words are present only if this tag is '='.
+
 - Data words follow, in big endian hexadecimal format. Notice that they are
   not machine words, but really just a byte stream split into words to make
   it easier to read. Thus, the last word may contain from one to four bytes.
@@ -153,20 +187,18 @@ class ParsedLine {
 	}
 }
 
-This format may be changed in the future.
-
 Examples:
 
 An input control transfer to get a port status.
 
-d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 <
-d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000
+d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
+d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000
 
 An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
 to a storage device at address 5:
 
-dd65f0e8 4128379752 S Bo:005:02 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
-dd65f0e8 4128379808 C Bo:005:02 0 31 >
+dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
+dd65f0e8 4128379808 C Bo:1:005:2 0 31 >
 
 * Raw binary format and API
 
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index fc2fe9b..b606391 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -143,3 +143,5 @@
 142 -> Sabrent TV-FM (bttv version)
 143 -> Hauppauge ImpactVCB (bt878)                         [0070:13eb]
 144 -> MagicTV
+145 -> SSAI Security Video Interface                       [4149:5353]
+146 -> SSAI Ultrasound Video Interface                     [414a:5353]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 62e32b4..60f838b 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -37,7 +37,7 @@
  36 -> AVerTV 303 (M126)                                   [1461:000a]
  37 -> Hauppauge Nova-S-Plus DVB-S                         [0070:9201,0070:9202]
  38 -> Hauppauge Nova-SE2 DVB-S                            [0070:9200]
- 39 -> KWorld DVB-S 100                                    [17de:08b2]
+ 39 -> KWorld DVB-S 100                                    [17de:08b2,1421:0341]
  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]
diff --git a/Documentation/video4linux/CARDLIST.ivtv b/Documentation/video4linux/CARDLIST.ivtv
new file mode 100644
index 0000000..ddd76a0
--- /dev/null
+++ b/Documentation/video4linux/CARDLIST.ivtv
@@ -0,0 +1,18 @@
+ 1 -> Hauppauge WinTV PVR-250
+ 2 -> Hauppauge WinTV PVR-350
+ 3 -> Hauppauge WinTV PVR-150 or PVR-500
+ 4 -> AVerMedia M179 				[1461:a3ce,1461:a3cf]
+ 5 -> Yuan MPG600/Kuroutoshikou iTVC16-STVLP 	[12ab:fff3,12ab:ffff]
+ 6 -> Yuan MPG160/Kuroutoshikou iTVC15-STVLP 	[12ab:0000,10fc:40a0]
+ 7 -> Yuan PG600/DiamondMM PVR-550 		[ff92:0070,ffab:0600]
+ 8 -> Adaptec AVC-2410 				[9005:0093]
+ 9 -> Adaptec AVC-2010 				[9005:0092]
+10 -> NAGASE TRANSGEAR 5000TV 			[1461:bfff]
+11 -> AOpen VA2000MAX-STN6 			[0000:ff5f]
+12 -> YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP [12ab:0600,fbab:0600,1154:0523]
+13 -> I/O Data GV-MVP/RX 			[10fc:d01e,10fc:d038,10fc:d039]
+14 -> I/O Data GV-MVP/RX2E 			[10fc:d025]
+15 -> GOTVIEW PCI DVD (partial support only) 	[12ab:0600]
+16 -> GOTVIEW PCI DVD2 Deluxe 			[ffac:0600]
+17 -> Yuan MPC622 				[ff01:d998]
+18 -> Digital Cowboy DCT-MTVP1 			[1461:bfff]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index a12246a..d7bb2e2 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -53,7 +53,7 @@
  52 -> AverMedia AverTV/305                     [1461:2108]
  53 -> ASUS TV-FM 7135                          [1043:4845]
  54 -> LifeView FlyTV Platinum FM / Gold        [5168:0214,1489:0214,5168:0304]
- 55 -> LifeView FlyDVB-T DUO                    [5168:0306]
+ 55 -> LifeView FlyDVB-T DUO / MSI TV@nywhere Duo [5168:0306,4E42:0306]
  56 -> Avermedia AVerTV 307                     [1461:a70a]
  57 -> Avermedia AVerTV GO 007 FM               [1461:f31f]
  58 -> ADS Tech Instant TV (saa7135)            [1421:0350,1421:0351,1421:0370,1421:1370]
@@ -76,7 +76,7 @@
  75 -> AVerMedia AVerTVHD MCE A180              [1461:1044]
  76 -> SKNet MonsterTV Mobile                   [1131:4ee9]
  77 -> Pinnacle PCTV 40i/50i/110i (saa7133)     [11bd:002e]
- 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4876]
+ 78 -> ASUSTeK P7131 Dual                       [1043:4862,1043:4857]
  79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
  80 -> ASUS Digimatrix TV                       [1043:0210]
  81 -> Philips Tiger reference design           [1131:2018]
@@ -107,3 +107,7 @@
 106 -> Encore ENLTV                             [1131:2342,1131:2341,3016:2344]
 107 -> Encore ENLTV-FM                          [1131:230f]
 108 -> Terratec Cinergy HT PCI                  [153b:1175]
+109 -> Philips Tiger - S Reference design
+110 -> Avermedia M102                           [1461:f31e]
+111 -> ASUS P7131 4871                          [1043:4871]
+112 -> ASUSTeK P7131 Hybrid                     [1043:4876]
diff --git a/Documentation/video4linux/CARDLIST.usbvision b/Documentation/video4linux/CARDLIST.usbvision
new file mode 100644
index 0000000..3d6850e
--- /dev/null
+++ b/Documentation/video4linux/CARDLIST.usbvision
@@ -0,0 +1,64 @@
+  0 -> Xanboo                                                   [0a6f:0400]
+  1 -> Belkin USB VideoBus II Adapter                           [050d:0106]
+  2 -> Belkin Components USB VideoBus                           [050d:0207]
+  3 -> Belkin USB VideoBus II                                   [050d:0208]
+  4 -> echoFX InterView Lite                                    [0571:0002]
+  5 -> USBGear USBG-V1 resp. HAMA USB                           [0573:0003]
+  6 -> D-Link V100                                              [0573:0400]
+  7 -> X10 USB Camera                                           [0573:2000]
+  8 -> Hauppauge WinTV USB Live (PAL B/G)                       [0573:2d00]
+  9 -> Hauppauge WinTV USB Live Pro (NTSC M/N)                  [0573:2d01]
+ 10 -> Zoran Co. PMD (Nogatech) AV-grabber Manhattan            [0573:2101]
+ 11 -> Nogatech USB-TV (NTSC) FM                                [0573:4100]
+ 12 -> PNY USB-TV (NTSC) FM                                     [0573:4110]
+ 13 -> PixelView PlayTv-USB PRO (PAL) FM                        [0573:4450]
+ 14 -> ZTV ZT-721 2.4GHz USB A/V Receiver                       [0573:4550]
+ 15 -> Hauppauge WinTV USB (NTSC M/N)                           [0573:4d00]
+ 16 -> Hauppauge WinTV USB (PAL B/G)                            [0573:4d01]
+ 17 -> Hauppauge WinTV USB (PAL I)                              [0573:4d02]
+ 18 -> Hauppauge WinTV USB (PAL/SECAM L)                        [0573:4d03]
+ 19 -> Hauppauge WinTV USB (PAL D/K)                            [0573:4d04]
+ 20 -> Hauppauge WinTV USB (NTSC FM)                            [0573:4d10]
+ 21 -> Hauppauge WinTV USB (PAL B/G FM)                         [0573:4d11]
+ 22 -> Hauppauge WinTV USB (PAL I FM)                           [0573:4d12]
+ 23 -> Hauppauge WinTV USB (PAL D/K FM)                         [0573:4d14]
+ 24 -> Hauppauge WinTV USB Pro (NTSC M/N)                       [0573:4d2a]
+ 25 -> Hauppauge WinTV USB Pro (NTSC M/N) V2                    [0573:4d2b]
+ 26 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)          [0573:4d2c]
+ 27 -> Hauppauge WinTV USB Pro (NTSC M/N) V3                    [0573:4d20]
+ 28 -> Hauppauge WinTV USB Pro (PAL B/G)                        [0573:4d21]
+ 29 -> Hauppauge WinTV USB Pro (PAL I)                          [0573:4d22]
+ 30 -> Hauppauge WinTV USB Pro (PAL/SECAM L)                    [0573:4d23]
+ 31 -> Hauppauge WinTV USB Pro (PAL D/K)                        [0573:4d24]
+ 32 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)             [0573:4d25]
+ 33 -> Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2          [0573:4d26]
+ 34 -> Hauppauge WinTV USB Pro (PAL B/G) V2                     [0573:4d27]
+ 35 -> Hauppauge WinTV USB Pro (PAL B/G,D/K)                    [0573:4d28]
+ 36 -> Hauppauge WinTV USB Pro (PAL I,D/K)                      [0573:4d29]
+ 37 -> Hauppauge WinTV USB Pro (NTSC M/N FM)                    [0573:4d30]
+ 38 -> Hauppauge WinTV USB Pro (PAL B/G FM)                     [0573:4d31]
+ 39 -> Hauppauge WinTV USB Pro (PAL I FM)                       [0573:4d32]
+ 40 -> Hauppauge WinTV USB Pro (PAL D/K FM)                     [0573:4d34]
+ 41 -> Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM) [0573:4d35]
+ 42 -> Hauppauge WinTV USB Pro (Temic PAL B/G FM)               [0573:4d36]
+ 43 -> Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)       [0573:4d37]
+ 44 -> Hauppauge WinTV USB Pro (NTSC M/N FM) V2                 [0573:4d38]
+ 45 -> Camtel Technology USB TV Genie Pro FM Model TVB330       [0768:0006]
+ 46 -> Digital Video Creator I                                  [07d0:0001]
+ 47 -> Global Village GV-007 (NTSC)                             [07d0:0002]
+ 48 -> Dazzle Fusion Model DVC-50 Rev 1 (NTSC)                  [07d0:0003]
+ 49 -> Dazzle Fusion Model DVC-80 Rev 1 (PAL)                   [07d0:0004]
+ 50 -> Dazzle Fusion Model DVC-90 Rev 1 (SECAM)                 [07d0:0005]
+ 51 -> Eskape Labs MyTV2Go                                      [07f8:9104]
+ 52 -> Pinnacle Studio PCTV USB (PAL)                           [2304:010d]
+ 53 -> Pinnacle Studio PCTV USB (SECAM)                         [2304:0109]
+ 54 -> Pinnacle Studio PCTV USB (PAL) FM                        [2304:0110]
+ 55 -> Miro PCTV USB                                            [2304:0111]
+ 56 -> Pinnacle Studio PCTV USB (NTSC) FM                       [2304:0112]
+ 57 -> Pinnacle Studio PCTV USB (PAL) FM V2                     [2304:0210]
+ 58 -> Pinnacle Studio PCTV USB (NTSC) FM V2                    [2304:0212]
+ 59 -> Pinnacle Studio PCTV USB (PAL) FM V3                     [2304:0214]
+ 60 -> Pinnacle Studio Linx Video input cable (NTSC)            [2304:0300]
+ 61 -> Pinnacle Studio Linx Video input cable (PAL)             [2304:0301]
+ 62 -> Pinnacle PCTV Bungee USB (PAL) FM                        [2304:0419]
+ 63 -> Hauppauge WinTv-USB                                      [2400:4200]
diff --git a/Documentation/video4linux/README.ivtv b/Documentation/video4linux/README.ivtv
new file mode 100644
index 0000000..73df22c
--- /dev/null
+++ b/Documentation/video4linux/README.ivtv
@@ -0,0 +1,187 @@
+
+ivtv release notes
+==================
+
+This is a v4l2 device driver for the Conexant cx23415/6 MPEG encoder/decoder.
+The cx23415 can do both encoding and decoding, the cx23416 can only do MPEG
+encoding. Currently the only card featuring full decoding support is the
+Hauppauge PVR-350.
+
+NOTE: this driver requires the latest encoder firmware (version 2.06.039, size
+376836 bytes). Get the firmware from here:
+
+http://dl.ivtvdriver.org/ivtv/firmware/firmware.tar.gz
+
+NOTE: 'normal' TV applications do not work with this driver, you need
+an application that can handle MPEG input such as mplayer, xine, MythTV,
+etc.
+
+The primary goal of the IVTV project is to provide a "clean room" Linux
+Open Source driver implementation for video capture cards based on the
+iCompression iTVC15 or Conexant CX23415/CX23416 MPEG Codec.
+
+Features:
+ * Hardware mpeg2 capture of broadcast video (and sound) via the tuner or
+   S-Video/Composite and audio line-in.
+ * Hardware mpeg2 capture of FM radio where hardware support exists
+ * Supports NTSC, PAL, SECAM with stereo sound
+ * Supports SAP and bilingual transmissions.
+ * Supports raw VBI (closed captions and teletext).
+ * Supports sliced VBI (closed captions and teletext) and is able to insert
+   this into the captured MPEG stream.
+ * Supports raw YUV and PCM input.
+
+Additional features for the PVR-350 (CX23415 based):
+ * Provides hardware mpeg2 playback
+ * Provides comprehensive OSD (On Screen Display: ie. graphics overlaying the
+   video signal)
+ * Provides a framebuffer (allowing X applications to appear on the video
+   device) (this framebuffer is not yet part of the kernel. In the meantime it
+   is available from www.ivtvdriver.org).
+ * Supports raw YUV output.
+
+IMPORTANT: In case of problems first read this page:
+	   http://www.ivtvdriver.org/index.php/Troubleshooting
+
+See also:
+
+Homepage + Wiki
+http://www.ivtvdriver.org
+
+IRC
+irc://irc.freenode.net/ivtv-dev
+
+----------------------------------------------------------
+
+Devices
+=======
+
+A maximum of 12 ivtv boards are allowed at the moment.
+
+Cards that don't have a video output capability (i.e. non PVR350 cards)
+lack the vbi8, vbi16, video16 and video48 devices. They also do not
+support the framebuffer device /dev/fbx for OSD.
+
+The radio0 device may or may not be present, depending on whether the
+card has a radio tuner or not.
+
+Here is a list of the base v4l devices:
+crw-rw----    1 root     video     81,   0 Jun 19 22:22 /dev/video0
+crw-rw----    1 root     video     81,  16 Jun 19 22:22 /dev/video16
+crw-rw----    1 root     video     81,  24 Jun 19 22:22 /dev/video24
+crw-rw----    1 root     video     81,  32 Jun 19 22:22 /dev/video32
+crw-rw----    1 root     video     81,  48 Jun 19 22:22 /dev/video48
+crw-rw----    1 root     video     81,  64 Jun 19 22:22 /dev/radio0
+crw-rw----    1 root     video     81, 224 Jun 19 22:22 /dev/vbi0
+crw-rw----    1 root     video     81, 228 Jun 19 22:22 /dev/vbi8
+crw-rw----    1 root     video     81, 232 Jun 19 22:22 /dev/vbi16
+
+Base devices
+============
+
+For every extra card you have the numbers increased by one. For example,
+/dev/video0 is listed as the 'base' encoding capture device so we have:
+
+ /dev/video0  is the encoding capture device for the first card (card 0)
+ /dev/video1  is the encoding capture device for the second card (card 1)
+ /dev/video2  is the encoding capture device for the third card (card 2)
+
+Note that if the first card doesn't have a feature (eg no decoder, so no
+video16, the second card will still use video17. The simple rule is 'add
+the card number to the base device number'. If you have other capture
+cards (e.g. WinTV PCI) that are detected first, then you have to tell
+the ivtv module about it so that it will start counting at 1 (or 2, or
+whatever). Otherwise the device numbers can get confusing. The ivtv
+'ivtv_first_minor' module option can be used for that.
+
+
+/dev/video0
+The encoding capture device(s).
+Read-only.
+
+Reading from this device gets you the MPEG1/2 program stream.
+Example:
+
+cat /dev/video0 > my.mpg (you need to hit ctrl-c to exit)
+
+
+/dev/video16
+The decoder output device(s)
+Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
+
+An mpeg2 stream sent to this device will appear on the selected video
+display, audio will appear on the line-out/audio out.  It is only
+available for cards that support video out. Example:
+
+cat my.mpg >/dev/video16
+
+
+/dev/video24
+The raw audio capture device(s).
+Read-only
+
+The raw audio PCM stereo stream from the currently selected
+tuner or audio line-in.  Reading from this device results in a raw
+(signed 16 bit Little Endian, 48000 Hz, stereo pcm) capture.
+This device only captures audio. This should be replaced by an ALSA
+device in the future.
+Note that there is no corresponding raw audio output device, this is
+not supported in the decoder firmware.
+
+
+/dev/video32
+The raw video capture device(s)
+Read-only
+
+The raw YUV video output from the current video input. The YUV format
+is non-standard (V4L2_PIX_FMT_HM12).
+
+Note that the YUV and PCM streams are not synchronized, so they are of
+limited use.
+
+
+/dev/video48
+The raw video display device(s)
+Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
+
+Writes a YUV stream to the decoder of the card.
+
+
+/dev/radio0
+The radio tuner device(s)
+Cannot be read or written.
+
+Used to enable the radio tuner and tune to a frequency. You cannot
+read or write audio streams with this device.  Once you use this
+device to tune the radio, use /dev/video24 to read the raw pcm stream
+or /dev/video0 to get an mpeg2 stream with black video.
+
+
+/dev/vbi0
+The 'vertical blank interval' (Teletext, CC, WSS etc) capture device(s)
+Read-only
+
+Captures the raw (or sliced) video data sent during the Vertical Blank
+Interval. This data is used to encode teletext, closed captions, VPS,
+widescreen signalling, electronic program guide information, and other
+services.
+
+
+/dev/vbi8
+Processed vbi feedback device(s)
+Read-only. Only present if the MPEG decoder (i.e. CX23415) exists.
+
+The sliced VBI data embedded in an MPEG stream is reproduced on this
+device. So while playing back a recording on /dev/video16, you can
+read the embedded VBI data from /dev/vbi8.
+
+
+/dev/vbi16
+The vbi 'display' device(s)
+Write-only. Only present if the MPEG decoder (i.e. CX23415) exists.
+
+Can be used to send sliced VBI data to the video-out connector.
+
+---------------------------------
+
+Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-regs.txt b/Documentation/video4linux/cx2341x/fw-decoder-regs.txt
index db2366c..cf52c8f 100644
--- a/Documentation/video4linux/cx2341x/fw-decoder-regs.txt
+++ b/Documentation/video4linux/cx2341x/fw-decoder-regs.txt
@@ -624,11 +624,11 @@ out what values are bad when it hangs.
 2A00
       bits 0:2
 	osd colour mode
+	  000 = 8 bit indexed
 	  001 = 16 bit (565)
 	  010 = 15 bit (555)
 	  011 = 12 bit (444)
 	  100 = 32 bit (8888)
-	  101 = 8 bit indexed
 
       bits 4:5
 	osd display bpp
@@ -676,9 +676,11 @@ out what values are bad when it hangs.
      completely transparent. When using 565, 555 or 444 colour modes, the
      colour key is always 16 bits wide. The colour to key on is set in Reg 2A18.
 
-     Local alpha is a per-pixel 256 step transparency, with 0 being transparent
-     and 255 being solid. This is only available in 32 bit & 8 bit indexed
-     colour modes.
+     Local alpha works differently depending on the colour mode. For 32bpp & 8
+     bit indexed, local alpha is a per-pixel 256 step transparency, with 0 being
+     transparent and 255 being solid. For the 16bpp modes 555 & 444, the unused
+     bit(s) act as a simple transparency switch, with 0 being solid & 1 being
+     fully transparent. There is no local alpha support for 16bit 565.
 
      Global alpha is a 256 step transparency that applies to the entire osd,
      with 0 being transparent & 255 being solid.
@@ -811,5 +813,5 @@ out what values are bad when it hangs.
 
 --------------------------------------------------------------------------------
 
-v0.3 - 2 February 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
+v0.4 - 12 March 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
 
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
index 242104c..5dd3109 100644
--- a/Documentation/video4linux/cx2341x/fw-encoder-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
@@ -663,12 +663,13 @@ Param[0]
 
 -------------------------------------------------------------------------------
 
-Name 	CX2341X_ENC_UNKNOWN
+Name 	CX2341X_ENC_SET_VERT_CROP_LINE
 Enum 	219/0xDB
 Description
-	Unknown API, it's used by Hauppauge though.
+	Something to do with 'Vertical Crop Line'
 Param[0]
-	0 This is the value Hauppauge uses, Unknown what it means.
+	If saa7114 and raw VBI capture and 60 Hz, then set to 10001.
+	Else 0.
 
 -------------------------------------------------------------------------------
 
@@ -682,11 +683,9 @@ Param[0]
 	Command number:
 	 1=set initial SCR value when starting encoding (works).
 	 2=set quality mode (apparently some test setting).
-	 3=setup advanced VIM protection handling (supposedly only for the cx23416
-	   for raw YUV).
-	   Actually it looks like this should be 0 for saa7114/5 based card and 1
-	   for cx25840 based cards.
-	 4=generate artificial PTS timestamps
+	 3=setup advanced VIM protection handling.
+	   Always 1 for the cx23416 and 0 for cx23415.
+	 4=generate DVD compatible PTS timestamps
 	 5=USB flush mode
 	 6=something to do with the quantization matrix
 	 7=set navigation pack insertion for DVD: adds 0xbf (private stream 2)
@@ -698,7 +697,9 @@ Param[0]
 	 9=set history parameters of the video input module
 	10=set input field order of VIM
 	11=set quantization matrix
-	12=reset audio interface
+	12=reset audio interface after channel change or input switch (has no argument).
+	   Needed for the cx2584x, not needed for the mspx4xx, but it doesn't seem to
+	   do any harm calling it regardless.
 	13=set audio volume delay
 	14=set audio delay
 
diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
index 0a602f3..89c4601 100644
--- a/Documentation/video4linux/cx2341x/fw-osd-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-osd-api.txt
@@ -21,7 +21,11 @@ Enum 	66/0x42
 Description
 	Query OSD format
 Result[0]
-	0=8bit index, 4=AlphaRGB 8:8:8:8
+	0=8bit index
+	1=16bit RGB 5:6:5
+	2=16bit ARGB 1:5:5:5
+	3=16bit ARGB 1:4:4:4
+	4=32bit ARGB 8:8:8:8
 
 -------------------------------------------------------------------------------
 
@@ -30,7 +34,11 @@ Enum 	67/0x43
 Description
 	Assign pixel format
 Param[0]
-	0=8bit index, 4=AlphaRGB 8:8:8:8
+	0=8bit index
+	1=16bit RGB 5:6:5
+	2=16bit ARGB 1:5:5:5
+	3=16bit ARGB 1:4:4:4
+	4=32bit ARGB 8:8:8:8
 
 -------------------------------------------------------------------------------
 
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index ecb3416..5e51c59 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -5,10 +5,9 @@ Vaio Picturebook Motion Eye Camera Drive
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
-Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
-Control Device" driver (which can be found in the "Character drivers"
-section of the kernel configuration utility) to be compiled and installed
-(using its "camera=1" parameter).
+Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which
+can be found in the "Misc devices" section of the kernel configuration utility)
+to be compiled and installed (using its "camera=1" parameter).
 
 It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
 
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 2913da3..5fe0ad7 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -25,7 +25,7 @@ Index
 
 1. Copyright
 ============
-Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
 
 
 2. Disclaimer
@@ -216,10 +216,10 @@ Description:    Debugging information le
 		1 = critical errors
 		2 = significant informations
 		3 = more verbose messages
-		Level 3 is useful for testing only, when only one device
-		is used. It also shows some more informations about the
-		hardware being detected. This parameter can be changed at
-		runtime thanks to the /sys filesystem interface.
+		Level 3 is useful for testing only. It also shows some more
+		informations about the hardware being detected.
+		This parameter can be changed at runtime thanks to the /sys
+		filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
@@ -235,7 +235,7 @@ created in the /sys/class/video4linux/vi
 channel's gain by writing the desired value to it. The value may range from 0
 to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
 SN9C105 and SN9C120 bridges.
-Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
+Similarly, only for the SN9C103, SN9C105 and SN9C120 controllers, blue and red
 gain control files are available in the same directory, for which accepted
 values may range from 0 to 127.
 
@@ -402,38 +402,49 @@ Vendor ID  Product ID
 0x0c45     0x60bc
 0x0c45     0x60be
 0x0c45     0x60c0
+0x0c45     0x60c2
 0x0c45     0x60c8
 0x0c45     0x60cc
 0x0c45     0x60ea
 0x0c45     0x60ec
+0x0c45     0x60ef
 0x0c45     0x60fa
 0x0c45     0x60fb
 0x0c45     0x60fc
 0x0c45     0x60fe
+0x0c45     0x6102
+0x0c45     0x6108
+0x0c45     0x610f
 0x0c45     0x6130
+0x0c45     0x6138
 0x0c45     0x613a
 0x0c45     0x613b
 0x0c45     0x613c
 0x0c45     0x613e
 
 The list above does not imply that all those devices work with this driver: up
-until now only the ones that assemble the following image sensors are
-supported; kernel messages will always tell you whether this is the case (see
-"Module loading" paragraph):
-
-Model       Manufacturer
------       ------------
-HV7131D     Hynix Semiconductor, Inc.
-MI-0343     Micron Technology, Inc.
-OV7630      OmniVision Technologies, Inc.
-OV7660      OmniVision Technologies, Inc.
-PAS106B     PixArt Imaging, Inc.
-PAS202BCA   PixArt Imaging, Inc.
-PAS202BCB   PixArt Imaging, Inc.
-TAS5110C1B  Taiwan Advanced Sensor Corporation
-TAS5130D1B  Taiwan Advanced Sensor Corporation
-
-Some of the available control settings of each image sensor are supported
+until now only the ones that assemble the following pairs of SN9C1xx bridges
+and image sensors are supported; kernel messages will always tell you whether
+this is the case (see "Module loading" paragraph):
+
+Image sensor / SN9C1xx bridge      | SN9C10[12]  SN9C103  SN9C105  SN9C120
+-------------------------------------------------------------------------------
+HV7131D    Hynix Semiconductor     | Yes         No       No       No
+HV7131R    Hynix Semiconductor     | No          Yes      Yes      Yes
+MI-0343    Micron Technology       | Yes         No       No       No
+MI-0360    Micron Technology       | No          Yes      No       No
+OV7630     OmniVision Technologies | Yes         Yes      No       No
+OV7660     OmniVision Technologies | No          No       Yes      Yes
+PAS106B    PixArt Imaging          | Yes         No       No       No
+PAS202B    PixArt Imaging          | Yes         Yes      No       No
+TAS5110C1B Taiwan Advanced Sensor  | Yes         No       No       No
+TAS5110D   Taiwan Advanced Sensor  | Yes         No       No       No
+TAS5130D1B Taiwan Advanced Sensor  | Yes         No       No       No
+
+"Yes" means that the pair is supported by the driver, while "No" means that the
+pair does not exist or is not supported by the driver.
+
+Only some of the available control settings of each image sensor are supported
 through the V4L2 interface.
 
 Donations of new models for further testing and support would be much
@@ -482,8 +493,8 @@ The SN9C1xx PC Camera Controllers can se
 formats over the USB: either native "Sequential RGB Bayer" or compressed.
 The compression is used to achieve high frame rates. With regard to the
 SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
-algorithm described below, while the SN9C105 and SN9C120 the compression is
-based on the JPEG standard.
+algorithm described below, while with regard to the SN9C105 and SN9C120 the
+compression is based on the JPEG standard.
 The current video format may be selected or queried from the user application
 by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
 API specifications.
@@ -573,4 +584,5 @@ order):
 - Mizuno Takafumi for the donation of a webcam;
 - an "anonymous" donator (who didn't want his name to be revealed) for the
   donation of a webcam.
-- an anonymous donator for the donation of four webcams.
+- an anonymous donator for the donation of four webcams and two boards with ten
+  image sensors.
diff --git a/Documentation/video4linux/zr364xx.txt b/Documentation/video4linux/zr364xx.txt
new file mode 100644
index 0000000..c76992d
--- /dev/null
+++ b/Documentation/video4linux/zr364xx.txt
@@ -0,0 +1,65 @@
+Zoran 364xx based USB webcam module version 0.72
+site: http://royale.zerezo.com/zr364xx/
+mail: royale@zerezo.com
+
+introduction:
+This brings support under Linux for the Aiptek PocketDV 3300 in webcam mode.
+If you just want to get on your PC the pictures and movies on the camera, you should use the usb-storage module instead.
+The driver works with several other cameras in webcam mode (see the list below).
+Maybe this code can work for other JPEG/USB cams based on the Coach chips from Zoran?
+Possible chipsets are : ZR36430 (ZR36430BGC) and maybe ZR36431, ZR36440, ZR36442...
+You can try the experience changing the vendor/product ID values (look at the source code).
+You can get these values by looking at /var/log/messages when you plug your camera, or by typing : cat /proc/bus/usb/devices.
+If you manage to use your cam with this code, you can send me a mail (royale@zerezo.com) with the name of your cam and a patch if needed.
+This is a beta release of the driver.
+Since version 0.70, this driver is only compatible with V4L2 API and 2.6.x kernels.
+If you need V4L1 or 2.4x kernels support, please use an older version, but the code is not maintained anymore.
+Good luck!
+
+install:
+In order to use this driver, you must compile it with your kernel.
+Location: Device Drivers -> Multimedia devices -> Video For Linux -> Video Capture Adapters -> V4L USB devices
+
+usage:
+modprobe zr364xx debug=X mode=Y
+ - debug      : set to 1 to enable verbose debug messages
+ - mode       : 0 = 320x240, 1 = 160x120, 2 = 640x480
+You can then use the camera with V4L2 compatible applications, for example Ekiga.
+To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1 count=1
+
+links :
+http://mxhaard.free.fr/ (support for many others cams including some Aiptek PocketDV)
+http://www.harmwal.nl/pccam880/ (this project also supports cameras based on this chipset)
+
+supported devices:
+------  -------  -----------     -----
+Vendor  Product  Distributor     Model
+------  -------  -----------     -----
+0x08ca  0x0109   Aiptek          PocketDV 3300
+0x08ca  0x0109   Maxell          Maxcam PRO DV3
+0x041e  0x4024   Creative        PC-CAM 880
+0x0d64  0x0108   Aiptek          Fidelity 3200
+0x0d64  0x0108   Praktica        DCZ 1.3 S
+0x0d64  0x0108   Genius          Digital Camera (?)
+0x0d64  0x0108   DXG Technology  Fashion Cam
+0x0546  0x3187   Polaroid        iON 230
+0x0d64  0x3108   Praktica        Exakta DC 2200
+0x0d64  0x3108   Genius          G-Shot D211
+0x0595  0x4343   Concord         Eye-Q Duo 1300
+0x0595  0x4343   Concord         Eye-Q Duo 2000
+0x0595  0x4343   Fujifilm        EX-10
+0x0595  0x4343   Ricoh           RDC-6000
+0x0595  0x4343   Digitrex        DSC 1300
+0x0595  0x4343   Firstline       FDC 2000
+0x0bb0  0x500d   Concord         EyeQ Go Wireless
+0x0feb  0x2004   CRS Electronic  3.3 Digital Camera
+0x0feb  0x2004   Packard Bell    DSC-300
+0x055f  0xb500   Mustek          MDC 3000
+0x08ca  0x2062   Aiptek          PocketDV 5700
+0x052b  0x1a18   Chiphead        Megapix V12
+0x04c8  0x0729   Konica          Revio 2
+0x04f2  0xa208   Creative        PC-CAM 850
+0x0784  0x0040   Traveler        Slimline X5
+0x06d6  0x0034   Trust           Powerc@m 750
+0x0a17  0x0062   Pentax          Optio 50L
+
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
new file mode 100644
index 0000000..41710cc
--- /dev/null
+++ b/Documentation/vm/slabinfo.c
@@ -0,0 +1,943 @@
+/*
+ * Slabinfo: Tool to get reports about slabs
+ *
+ * (C) 2007 sgi, Christoph Lameter <clameter@sgi.com>
+ *
+ * Compile by:
+ *
+ * gcc -o slabinfo slabinfo.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <regex.h>
+
+#define MAX_SLABS 500
+#define MAX_ALIASES 500
+#define MAX_NODES 1024
+
+struct slabinfo {
+	char *name;
+	int alias;
+	int refs;
+	int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
+	int hwcache_align, object_size, objs_per_slab;
+	int sanity_checks, slab_size, store_user, trace;
+	int order, poison, reclaim_account, red_zone;
+	unsigned long partial, objects, slabs;
+	int numa[MAX_NODES];
+	int numa_partial[MAX_NODES];
+} slabinfo[MAX_SLABS];
+
+struct aliasinfo {
+	char *name;
+	char *ref;
+	struct slabinfo *slab;
+} aliasinfo[MAX_ALIASES];
+
+int slabs = 0;
+int aliases = 0;
+int alias_targets = 0;
+int highest_node = 0;
+
+char buffer[4096];
+
+int show_alias = 0;
+int show_slab = 0;
+int skip_zero = 1;
+int show_numa = 0;
+int show_track = 0;
+int show_first_alias = 0;
+int validate = 0;
+int shrink = 0;
+int show_inverted = 0;
+int show_single_ref = 0;
+int show_totals = 0;
+int sort_size = 0;
+
+int page_size;
+
+regex_t pattern;
+
+void fatal(const char *x, ...)
+{
+	va_list ap;
+
+	va_start(ap, x);
+	vfprintf(stderr, x, ap);
+	va_end(ap);
+	exit(1);
+}
+
+void usage(void)
+{
+	printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
+		"-a|--aliases           Show aliases\n"
+		"-h|--help              Show usage information\n"
+		"-n|--numa              Show NUMA information\n"
+		"-s|--shrink            Shrink slabs\n"
+		"-v|--validate          Validate slabs\n"
+		"-t|--tracking          Show alloc/free information\n"
+		"-T|--Totals            Show summary information\n"
+		"-l|--slabs             Show slabs\n"
+		"-S|--Size              Sort by size\n"
+		"-z|--zero              Include empty slabs\n"
+		"-f|--first-alias       Show first alias\n"
+		"-i|--inverted          Inverted list\n"
+		"-1|--1ref              Single reference\n"
+	);
+}
+
+unsigned long read_obj(char *name)
+{
+	FILE *f = fopen(name, "r");
+
+	if (!f)
+		buffer[0] = 0;
+	else {
+		if (!fgets(buffer,sizeof(buffer), f))
+			buffer[0] = 0;
+		fclose(f);
+		if (buffer[strlen(buffer)] == '\n')
+			buffer[strlen(buffer)] = 0;
+	}
+	return strlen(buffer);
+}
+
+
+/*
+ * Get the contents of an attribute
+ */
+unsigned long get_obj(char *name)
+{
+	if (!read_obj(name))
+		return 0;
+
+	return atol(buffer);
+}
+
+unsigned long get_obj_and_str(char *name, char **x)
+{
+	unsigned long result = 0;
+	char *p;
+
+	*x = NULL;
+
+	if (!read_obj(name)) {
+		x = NULL;
+		return 0;
+	}
+	result = strtoul(buffer, &p, 10);
+	while (*p == ' ')
+		p++;
+	if (*p)
+		*x = strdup(p);
+	return result;
+}
+
+void set_obj(struct slabinfo *s, char *name, int n)
+{
+	char x[100];
+
+	sprintf(x, "%s/%s", s->name, name);
+
+	FILE *f = fopen(x, "w");
+
+	if (!f)
+		fatal("Cannot write to %s\n", x);
+
+	fprintf(f, "%d\n", n);
+	fclose(f);
+}
+
+/*
+ * Put a size string together
+ */
+int store_size(char *buffer, unsigned long value)
+{
+	unsigned long divisor = 1;
+	char trailer = 0;
+	int n;
+
+	if (value > 1000000000UL) {
+		divisor = 100000000UL;
+		trailer = 'G';
+	} else if (value > 1000000UL) {
+		divisor = 100000UL;
+		trailer = 'M';
+	} else if (value > 1000UL) {
+		divisor = 100;
+		trailer = 'K';
+	}
+
+	value /= divisor;
+	n = sprintf(buffer, "%ld",value);
+	if (trailer) {
+		buffer[n] = trailer;
+		n++;
+		buffer[n] = 0;
+	}
+	if (divisor != 1) {
+		memmove(buffer + n - 2, buffer + n - 3, 4);
+		buffer[n-2] = '.';
+		n++;
+	}
+	return n;
+}
+
+void decode_numa_list(int *numa, char *t)
+{
+	int node;
+	int nr;
+
+	memset(numa, 0, MAX_NODES * sizeof(int));
+
+	while (*t == 'N') {
+		t++;
+		node = strtoul(t, &t, 10);
+		if (*t == '=') {
+			t++;
+			nr = strtoul(t, &t, 10);
+			numa[node] = nr;
+			if (node > highest_node)
+				highest_node = node;
+		}
+		while (*t == ' ')
+			t++;
+	}
+}
+
+void slab_validate(struct slabinfo *s)
+{
+	set_obj(s, "validate", 1);
+}
+
+void slab_shrink(struct slabinfo *s)
+{
+	set_obj(s, "shrink", 1);
+}
+
+int line = 0;
+
+void first_line(void)
+{
+	printf("Name                 Objects   Objsize    Space "
+		"Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
+}
+
+/*
+ * Find the shortest alias of a slab
+ */
+struct aliasinfo *find_one_alias(struct slabinfo *find)
+{
+	struct aliasinfo *a;
+	struct aliasinfo *best = NULL;
+
+	for(a = aliasinfo;a < aliasinfo + aliases; a++) {
+		if (a->slab == find &&
+			(!best || strlen(best->name) < strlen(a->name))) {
+				best = a;
+				if (strncmp(a->name,"kmall", 5) == 0)
+					return best;
+			}
+	}
+	if (best)
+		return best;
+	fatal("Cannot find alias for %s\n", find->name);
+	return NULL;
+}
+
+unsigned long slab_size(struct slabinfo *s)
+{
+	return 	s->slabs * (page_size << s->order);
+}
+
+
+void slabcache(struct slabinfo *s)
+{
+	char size_str[20];
+	char dist_str[40];
+	char flags[20];
+	char *p = flags;
+
+	if (skip_zero && !s->slabs)
+		return;
+
+	store_size(size_str, slab_size(s));
+	sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);
+
+	if (!line++)
+		first_line();
+
+	if (s->aliases)
+		*p++ = '*';
+	if (s->cache_dma)
+		*p++ = 'd';
+	if (s->hwcache_align)
+		*p++ = 'A';
+	if (s->poison)
+		*p++ = 'P';
+	if (s->reclaim_account)
+		*p++ = 'a';
+	if (s->red_zone)
+		*p++ = 'Z';
+	if (s->sanity_checks)
+		*p++ = 'F';
+	if (s->store_user)
+		*p++ = 'U';
+	if (s->trace)
+		*p++ = 'T';
+
+	*p = 0;
+	printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
+		s->name, s->objects, s->object_size, size_str, dist_str,
+		s->objs_per_slab, s->order,
+		s->slabs ? (s->partial * 100) / s->slabs : 100,
+		s->slabs ? (s->objects * s->object_size * 100) /
+			(s->slabs * (page_size << s->order)) : 100,
+		flags);
+}
+
+void slab_numa(struct slabinfo *s)
+{
+	int node;
+
+	if (!highest_node)
+		fatal("No NUMA information available.\n");
+
+	if (skip_zero && !s->slabs)
+		return;
+
+	if (!line) {
+		printf("\nSlab             Node ");
+		for(node = 0; node <= highest_node; node++)
+			printf(" %4d", node);
+		printf("\n----------------------");
+		for(node = 0; node <= highest_node; node++)
+			printf("-----");
+		printf("\n");
+	}
+	printf("%-21s ", s->name);
+	for(node = 0; node <= highest_node; node++) {
+		char b[20];
+
+		store_size(b, s->numa[node]);
+		printf(" %4s", b);
+	}
+	printf("\n");
+	line++;
+}
+
+void show_tracking(struct slabinfo *s)
+{
+	printf("\n%s: Calls to allocate a slab object\n", s->name);
+	printf("---------------------------------------------------\n");
+	if (read_obj("alloc_calls"))
+		printf(buffer);
+
+	printf("%s: Calls to free a slab object\n", s->name);
+	printf("-----------------------------------------------\n");
+	if (read_obj("free_calls"))
+		printf(buffer);
+
+}
+
+void totals(void)
+{
+	struct slabinfo *s;
+
+	int used_slabs = 0;
+	char b1[20], b2[20], b3[20], b4[20];
+	unsigned long long max = 1ULL << 63;
+
+	/* Object size */
+	unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
+
+	/* Number of partial slabs in a slabcache */
+	unsigned long long min_partial = max, max_partial = 0,
+				avg_partial, total_partial = 0;
+
+	/* Number of slabs in a slab cache */
+	unsigned long long min_slabs = max, max_slabs = 0,
+				avg_slabs, total_slabs = 0;
+
+	/* Size of the whole slab */
+	unsigned long long min_size = max, max_size = 0,
+				avg_size, total_size = 0;
+
+	/* Bytes used for object storage in a slab */
+	unsigned long long min_used = max, max_used = 0,
+				avg_used, total_used = 0;
+
+	/* Waste: Bytes used for alignment and padding */
+	unsigned long long min_waste = max, max_waste = 0,
+				avg_waste, total_waste = 0;
+	/* Number of objects in a slab */
+	unsigned long long min_objects = max, max_objects = 0,
+				avg_objects, total_objects = 0;
+	/* Waste per object */
+	unsigned long long min_objwaste = max,
+				max_objwaste = 0, avg_objwaste,
+				total_objwaste = 0;
+
+	/* Memory per object */
+	unsigned long long min_memobj = max,
+				max_memobj = 0, avg_memobj,
+				total_objsize = 0;
+
+	/* Percentage of partial slabs per slab */
+	unsigned long min_ppart = 100, max_ppart = 0,
+				avg_ppart, total_ppart = 0;
+
+	/* Number of objects in partial slabs */
+	unsigned long min_partobj = max, max_partobj = 0,
+				avg_partobj, total_partobj = 0;
+
+	/* Percentage of partial objects of all objects in a slab */
+	unsigned long min_ppartobj = 100, max_ppartobj = 0,
+				avg_ppartobj, total_ppartobj = 0;
+
+
+	for (s = slabinfo; s < slabinfo + slabs; s++) {
+		unsigned long long size;
+		unsigned long used;
+		unsigned long long wasted;
+		unsigned long long objwaste;
+		long long objects_in_partial_slabs;
+		unsigned long percentage_partial_slabs;
+		unsigned long percentage_partial_objs;
+
+		if (!s->slabs || !s->objects)
+			continue;
+
+		used_slabs++;
+
+		size = slab_size(s);
+		used = s->objects * s->object_size;
+		wasted = size - used;
+		objwaste = s->slab_size - s->object_size;
+
+		objects_in_partial_slabs = s->objects -
+			(s->slabs - s->partial - s ->cpu_slabs) *
+			s->objs_per_slab;
+
+		if (objects_in_partial_slabs < 0)
+			objects_in_partial_slabs = 0;
+
+		percentage_partial_slabs = s->partial * 100 / s->slabs;
+		if (percentage_partial_slabs > 100)
+			percentage_partial_slabs = 100;
+
+		percentage_partial_objs = objects_in_partial_slabs * 100
+							/ s->objects;
+
+		if (percentage_partial_objs > 100)
+			percentage_partial_objs = 100;
+
+		if (s->object_size < min_objsize)
+			min_objsize = s->object_size;
+		if (s->partial < min_partial)
+			min_partial = s->partial;
+		if (s->slabs < min_slabs)
+			min_slabs = s->slabs;
+		if (size < min_size)
+			min_size = size;
+		if (wasted < min_waste)
+			min_waste = wasted;
+		if (objwaste < min_objwaste)
+			min_objwaste = objwaste;
+		if (s->objects < min_objects)
+			min_objects = s->objects;
+		if (used < min_used)
+			min_used = used;
+		if (objects_in_partial_slabs < min_partobj)
+			min_partobj = objects_in_partial_slabs;
+		if (percentage_partial_slabs < min_ppart)
+			min_ppart = percentage_partial_slabs;
+		if (percentage_partial_objs < min_ppartobj)
+			min_ppartobj = percentage_partial_objs;
+		if (s->slab_size < min_memobj)
+			min_memobj = s->slab_size;
+
+		if (s->object_size > max_objsize)
+			max_objsize = s->object_size;
+		if (s->partial > max_partial)
+			max_partial = s->partial;
+		if (s->slabs > max_slabs)
+			max_slabs = s->slabs;
+		if (size > max_size)
+			max_size = size;
+		if (wasted > max_waste)
+			max_waste = wasted;
+		if (objwaste > max_objwaste)
+			max_objwaste = objwaste;
+		if (s->objects > max_objects)
+			max_objects = s->objects;
+		if (used > max_used)
+			max_used = used;
+		if (objects_in_partial_slabs > max_partobj)
+			max_partobj = objects_in_partial_slabs;
+		if (percentage_partial_slabs > max_ppart)
+			max_ppart = percentage_partial_slabs;
+		if (percentage_partial_objs > max_ppartobj)
+			max_ppartobj = percentage_partial_objs;
+		if (s->slab_size > max_memobj)
+			max_memobj = s->slab_size;
+
+		total_partial += s->partial;
+		total_slabs += s->slabs;
+		total_size += size;
+		total_waste += wasted;
+
+		total_objects += s->objects;
+		total_used += used;
+		total_partobj += objects_in_partial_slabs;
+		total_ppart += percentage_partial_slabs;
+		total_ppartobj += percentage_partial_objs;
+
+		total_objwaste += s->objects * objwaste;
+		total_objsize += s->objects * s->slab_size;
+	}
+
+	if (!total_objects) {
+		printf("No objects\n");
+		return;
+	}
+	if (!used_slabs) {
+		printf("No slabs\n");
+		return;
+	}
+
+	/* Per slab averages */
+	avg_partial = total_partial / used_slabs;
+	avg_slabs = total_slabs / used_slabs;
+	avg_size = total_size / used_slabs;
+	avg_waste = total_waste / used_slabs;
+
+	avg_objects = total_objects / used_slabs;
+	avg_used = total_used / used_slabs;
+	avg_partobj = total_partobj / used_slabs;
+	avg_ppart = total_ppart / used_slabs;
+	avg_ppartobj = total_ppartobj / used_slabs;
+
+	/* Per object object sizes */
+	avg_objsize = total_used / total_objects;
+	avg_objwaste = total_objwaste / total_objects;
+	avg_partobj = total_partobj * 100 / total_objects;
+	avg_memobj = total_objsize / total_objects;
+
+	printf("Slabcache Totals\n");
+	printf("----------------\n");
+	printf("Slabcaches : %3d      Aliases  : %3d->%-3d Active: %3d\n",
+			slabs, aliases, alias_targets, used_slabs);
+
+	store_size(b1, total_size);store_size(b2, total_waste);
+	store_size(b3, total_waste * 100 / total_used);
+	printf("Memory used: %6s   # Loss   : %6s   MRatio: %6s%%\n", b1, b2, b3);
+
+	store_size(b1, total_objects);store_size(b2, total_partobj);
+	store_size(b3, total_partobj * 100 / total_objects);
+	printf("# Objects  : %6s   # PartObj: %6s   ORatio: %6s%%\n", b1, b2, b3);
+
+	printf("\n");
+	printf("Per Cache    Average         Min         Max       Total\n");
+	printf("---------------------------------------------------------\n");
+
+	store_size(b1, avg_objects);store_size(b2, min_objects);
+	store_size(b3, max_objects);store_size(b4, total_objects);
+	printf("#Objects  %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_slabs);store_size(b2, min_slabs);
+	store_size(b3, max_slabs);store_size(b4, total_slabs);
+	printf("#Slabs    %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_partial);store_size(b2, min_partial);
+	store_size(b3, max_partial);store_size(b4, total_partial);
+	printf("#PartSlab %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+	store_size(b1, avg_ppart);store_size(b2, min_ppart);
+	store_size(b3, max_ppart);
+	store_size(b4, total_partial * 100  / total_slabs);
+	printf("%%PartSlab %10s%% %10s%% %10s%% %10s%%\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_partobj);store_size(b2, min_partobj);
+	store_size(b3, max_partobj);
+	store_size(b4, total_partobj);
+	printf("PartObjs  %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
+	store_size(b3, max_ppartobj);
+	store_size(b4, total_partobj * 100 / total_objects);
+	printf("%% PartObj %10s%% %10s%% %10s%% %10s%%\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_size);store_size(b2, min_size);
+	store_size(b3, max_size);store_size(b4, total_size);
+	printf("Memory    %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_used);store_size(b2, min_used);
+	store_size(b3, max_used);store_size(b4, total_used);
+	printf("Used      %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	store_size(b1, avg_waste);store_size(b2, min_waste);
+	store_size(b3, max_waste);store_size(b4, total_waste);
+	printf("Loss      %10s  %10s  %10s  %10s\n",
+			b1,	b2,	b3,	b4);
+
+	printf("\n");
+	printf("Per Object   Average         Min         Max\n");
+	printf("---------------------------------------------\n");
+
+	store_size(b1, avg_memobj);store_size(b2, min_memobj);
+	store_size(b3, max_memobj);
+	printf("Memory    %10s  %10s  %10s\n",
+			b1,	b2,	b3);
+	store_size(b1, avg_objsize);store_size(b2, min_objsize);
+	store_size(b3, max_objsize);
+	printf("User      %10s  %10s  %10s\n",
+			b1,	b2,	b3);
+
+	store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
+	store_size(b3, max_objwaste);
+	printf("Loss      %10s  %10s  %10s\n",
+			b1,	b2,	b3);
+}
+
+void sort_slabs(void)
+{
+	struct slabinfo *s1,*s2;
+
+	for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
+		for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
+			int result;
+
+			if (sort_size)
+				result = slab_size(s1) < slab_size(s2);
+			else
+				result = strcasecmp(s1->name, s2->name);
+
+			if (show_inverted)
+				result = -result;
+
+			if (result > 0) {
+				struct slabinfo t;
+
+				memcpy(&t, s1, sizeof(struct slabinfo));
+				memcpy(s1, s2, sizeof(struct slabinfo));
+				memcpy(s2, &t, sizeof(struct slabinfo));
+			}
+		}
+	}
+}
+
+void sort_aliases(void)
+{
+	struct aliasinfo *a1,*a2;
+
+	for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
+		for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
+			char *n1, *n2;
+
+			n1 = a1->name;
+			n2 = a2->name;
+			if (show_alias && !show_inverted) {
+				n1 = a1->ref;
+				n2 = a2->ref;
+			}
+			if (strcasecmp(n1, n2) > 0) {
+				struct aliasinfo t;
+
+				memcpy(&t, a1, sizeof(struct aliasinfo));
+				memcpy(a1, a2, sizeof(struct aliasinfo));
+				memcpy(a2, &t, sizeof(struct aliasinfo));
+			}
+		}
+	}
+}
+
+void link_slabs(void)
+{
+	struct aliasinfo *a;
+	struct slabinfo *s;
+
+	for (a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+		for(s = slabinfo; s < slabinfo + slabs; s++)
+			if (strcmp(a->ref, s->name) == 0) {
+				a->slab = s;
+				s->refs++;
+				break;
+			}
+		if (s == slabinfo + slabs)
+			fatal("Unresolved alias %s\n", a->ref);
+	}
+}
+
+void alias(void)
+{
+	struct aliasinfo *a;
+	char *active = NULL;
+
+	sort_aliases();
+	link_slabs();
+
+	for(a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+		if (!show_single_ref && a->slab->refs == 1)
+			continue;
+
+		if (!show_inverted) {
+			if (active) {
+				if (strcmp(a->slab->name, active) == 0) {
+					printf(" %s", a->name);
+					continue;
+				}
+			}
+			printf("\n%-20s <- %s", a->slab->name, a->name);
+			active = a->slab->name;
+		}
+		else
+			printf("%-20s -> %s\n", a->name, a->slab->name);
+	}
+	if (active)
+		printf("\n");
+}
+
+
+void rename_slabs(void)
+{
+	struct slabinfo *s;
+	struct aliasinfo *a;
+
+	for (s = slabinfo; s < slabinfo + slabs; s++) {
+		if (*s->name != ':')
+			continue;
+
+		if (s->refs > 1 && !show_first_alias)
+			continue;
+
+		a = find_one_alias(s);
+
+		s->name = a->name;
+	}
+}
+
+int slab_mismatch(char *slab)
+{
+	return regexec(&pattern, slab, 0, NULL, 0);
+}
+
+void read_slab_dir(void)
+{
+	DIR *dir;
+	struct dirent *de;
+	struct slabinfo *slab = slabinfo;
+	struct aliasinfo *alias = aliasinfo;
+	char *p;
+	char *t;
+	int count;
+
+	dir = opendir(".");
+	while ((de = readdir(dir))) {
+		if (de->d_name[0] == '.' ||
+				slab_mismatch(de->d_name))
+			continue;
+		switch (de->d_type) {
+		   case DT_LNK:
+		   	alias->name = strdup(de->d_name);
+			count = readlink(de->d_name, buffer, sizeof(buffer));
+
+			if (count < 0)
+				fatal("Cannot read symlink %s\n", de->d_name);
+
+			buffer[count] = 0;
+			p = buffer + count;
+			while (p > buffer && p[-1] != '/')
+				p--;
+			alias->ref = strdup(p);
+			alias++;
+			break;
+		   case DT_DIR:
+			if (chdir(de->d_name))
+				fatal("Unable to access slab %s\n", slab->name);
+		   	slab->name = strdup(de->d_name);
+			slab->alias = 0;
+			slab->refs = 0;
+			slab->aliases = get_obj("aliases");
+			slab->align = get_obj("align");
+			slab->cache_dma = get_obj("cache_dma");
+			slab->cpu_slabs = get_obj("cpu_slabs");
+			slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+			slab->hwcache_align = get_obj("hwcache_align");
+			slab->object_size = get_obj("object_size");
+			slab->objects = get_obj("objects");
+			slab->objs_per_slab = get_obj("objs_per_slab");
+			slab->order = get_obj("order");
+			slab->partial = get_obj("partial");
+			slab->partial = get_obj_and_str("partial", &t);
+			decode_numa_list(slab->numa_partial, t);
+			slab->poison = get_obj("poison");
+			slab->reclaim_account = get_obj("reclaim_account");
+			slab->red_zone = get_obj("red_zone");
+			slab->sanity_checks = get_obj("sanity_checks");
+			slab->slab_size = get_obj("slab_size");
+			slab->slabs = get_obj_and_str("slabs", &t);
+			decode_numa_list(slab->numa, t);
+			slab->store_user = get_obj("store_user");
+			slab->trace = get_obj("trace");
+			chdir("..");
+			if (slab->name[0] == ':')
+				alias_targets++;
+			slab++;
+			break;
+		   default :
+			fatal("Unknown file type %lx\n", de->d_type);
+		}
+	}
+	closedir(dir);
+	slabs = slab - slabinfo;
+	aliases = alias - aliasinfo;
+	if (slabs > MAX_SLABS)
+		fatal("Too many slabs\n");
+	if (aliases > MAX_ALIASES)
+		fatal("Too many aliases\n");
+}
+
+void output_slabs(void)
+{
+	struct slabinfo *slab;
+
+	for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
+
+		if (slab->alias)
+			continue;
+
+
+		if (show_numa)
+			slab_numa(slab);
+		else
+		if (show_track)
+			show_tracking(slab);
+		else
+		if (validate)
+			slab_validate(slab);
+		else
+		if (shrink)
+			slab_shrink(slab);
+		else {
+			if (show_slab)
+				slabcache(slab);
+		}
+	}
+}
+
+struct option opts[] = {
+	{ "aliases", 0, NULL, 'a' },
+	{ "slabs", 0, NULL, 'l' },
+	{ "numa", 0, NULL, 'n' },
+	{ "zero", 0, NULL, 'z' },
+	{ "help", 0, NULL, 'h' },
+	{ "validate", 0, NULL, 'v' },
+	{ "first-alias", 0, NULL, 'f' },
+	{ "shrink", 0, NULL, 's' },
+	{ "track", 0, NULL, 't'},
+	{ "inverted", 0, NULL, 'i'},
+	{ "1ref", 0, NULL, '1'},
+	{ NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+	int c;
+	int err;
+	char *pattern_source;
+
+	page_size = getpagesize();
+	if (chdir("/sys/slab"))
+		fatal("This kernel does not have SLUB support.\n");
+
+	while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1)
+	switch(c) {
+		case '1':
+			show_single_ref = 1;
+			break;
+		case 'a':
+			show_alias = 1;
+			break;
+		case 'f':
+			show_first_alias = 1;
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'i':
+			show_inverted = 1;
+			break;
+		case 'n':
+			show_numa = 1;
+			break;
+		case 's':
+			shrink = 1;
+			break;
+		case 'l':
+			show_slab = 1;
+			break;
+		case 't':
+			show_track = 1;
+			break;
+		case 'v':
+			validate = 1;
+			break;
+		case 'z':
+			skip_zero = 0;
+			break;
+		case 'T':
+			show_totals = 1;
+			break;
+		case 'S':
+			sort_size = 1;
+			break;
+
+		default:
+			fatal("%s: Invalid option '%c'\n", argv[0], optopt);
+
+	}
+
+	if (!show_slab && !show_alias && !show_track
+		&& !validate && !shrink)
+			show_slab = 1;
+
+	if (argc > optind)
+		pattern_source = argv[optind];
+	else
+		pattern_source = ".*";
+
+	err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
+	if (err)
+		fatal("%s: Invalid pattern '%s' code %d\n",
+			argv[0], pattern_source, err);
+	read_slab_dir();
+	if (show_alias)
+		alias();
+	else
+	if (show_totals)
+		totals();
+	else {
+		link_slabs();
+		rename_slabs();
+		sort_slabs();
+		output_slabs();
+	}
+	return 0;
+}
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
new file mode 100644
index 0000000..727c8d8
--- /dev/null
+++ b/Documentation/vm/slub.txt
@@ -0,0 +1,113 @@
+Short users guide for SLUB
+--------------------------
+
+First of all slub should transparently replace SLAB. If you enable
+SLUB then everything should work the same (Note the word "should".
+There is likely not much value in that word at this point).
+
+The basic philosophy of SLUB is very different from SLAB. SLAB
+requires rebuilding the kernel to activate debug options for all
+SLABS. SLUB always includes full debugging but its off by default.
+SLUB can enable debugging only for selected slabs in order to avoid
+an impact on overall system performance which may make a bug more
+difficult to find.
+
+In order to switch debugging on one can add a option "slub_debug"
+to the kernel command line. That will enable full debugging for
+all slabs.
+
+Typically one would then use the "slabinfo" command to get statistical
+data and perform operation on the slabs. By default slabinfo only lists
+slabs that have data in them. See "slabinfo -h" for more options when
+running the command. slabinfo can be compiled with
+
+gcc -o slabinfo Documentation/vm/slabinfo.c
+
+Some of the modes of operation of slabinfo require that slub debugging
+be enabled on the command line. F.e. no tracking information will be
+available without debugging on and validation can only partially
+be performed if debugging was not switched on.
+
+Some more sophisticated uses of slub_debug:
+-------------------------------------------
+
+Parameters may be given to slub_debug. If none is specified then full
+debugging is enabled. Format:
+
+slub_debug=<Debug-Options>       Enable options for all slabs
+slub_debug=<Debug-Options>,<slab name>
+				Enable options only for select slabs
+
+Possible debug options are
+	F		Sanity checks on (enables SLAB_DEBUG_FREE. Sorry
+			SLAB legacy issues)
+	Z		Red zoning
+	P		Poisoning (object and padding)
+	U		User tracking (free and alloc)
+	T		Trace (please only use on single slabs)
+
+F.e. in order to boot just with sanity checks and red zoning one would specify:
+
+	slub_debug=FZ
+
+Trying to find an issue in the dentry cache? Try
+
+	slub_debug=,dentry_cache
+
+to only enable debugging on the dentry cache.
+
+Red zoning and tracking may realign the slab.  We can just apply sanity checks
+to the dentry cache with
+
+	slub_debug=F,dentry_cache
+
+In case you forgot to enable debugging on the kernel command line: It is
+possible to enable debugging manually when the kernel is up. Look at the
+contents of:
+
+/sys/slab/<slab name>/
+
+Look at the writable files. Writing 1 to them will enable the
+corresponding debug option. All options can be set on a slab that does
+not contain objects. If the slab already contains objects then sanity checks
+and tracing may only be enabled. The other options may cause the realignment
+of objects.
+
+Careful with tracing: It may spew out lots of information and never stop if
+used on the wrong slab.
+
+SLAB Merging
+------------
+
+If no debugging is specified then SLUB may merge similar slabs together
+in order to reduce overhead and increase cache hotness of objects.
+slabinfo -a displays which slabs were merged together.
+
+Getting more performance
+------------------------
+
+To some degree SLUB's performance is limited by the need to take the
+list_lock once in a while to deal with partial slabs. That overhead is
+governed by the order of the allocation for each slab. The allocations
+can be influenced by kernel parameters:
+
+slub_min_objects=x		(default 8)
+slub_min_order=x		(default 0)
+slub_max_order=x		(default 4)
+
+slub_min_objects allows to specify how many objects must at least fit
+into one slab in order for the allocation order to be acceptable.
+In general slub will be able to perform this number of allocations
+on a slab without consulting centralized resources (list_lock) where
+contention may occur.
+
+slub_min_order specifies a minim order of slabs. A similar effect like
+slub_min_objects.
+
+slub_max_order specified the order at which slub_min_objects should no
+longer be checked. This is useful to avoid SLUB trying to generate
+super large order pages to fit slub_min_objects of a slab cache with
+large object sizes into one high order page.
+
+
+Christoph Lameter, <clameter@sgi.com>, April 10, 2007
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 85f51e5..6177d88 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -149,7 +149,19 @@ NUMA
 
   numa=noacpi   Don't parse the SRAT table for NUMA setup
 
-  numa=fake=X   Fake X nodes and ignore NUMA setup of the actual machine.
+  numa=fake=CMDLINE
+		If a number, fakes CMDLINE nodes and ignores NUMA setup of the
+		actual machine.  Otherwise, system memory is configured
+		depending on the sizes and coefficients listed.  For example:
+			numa=fake=2*512,1024,4*256,*128
+		gives two 512M nodes, a 1024M node, four 256M nodes, and the
+		rest split into 128M chunks.  If the last character of CMDLINE
+		is a *, the remaining memory is divided up equally among its
+		coefficient:
+			numa=fake=2*512,2*
+		gives two 512M nodes and the rest split into two nodes.
+		Otherwise, the remaining system RAM is allocated to an
+		additional node.
 
   numa=hotadd=percent
 		Only allow hotadd memory to preallocate page structures upto
diff --git a/Documentation/x86_64/fake-numa-for-cpusets b/Documentation/x86_64/fake-numa-for-cpusets
new file mode 100644
index 0000000..d1a985c
--- /dev/null
+++ b/Documentation/x86_64/fake-numa-for-cpusets
@@ -0,0 +1,66 @@
+Using numa=fake and CPUSets for Resource Management
+Written by David Rientjes <rientjes@cs.washington.edu>
+
+This document describes how the numa=fake x86_64 command-line option can be used
+in conjunction with cpusets for coarse memory management.  Using this feature,
+you can create fake NUMA nodes that represent contiguous chunks of memory and
+assign them to cpusets and their attached tasks.  This is a way of limiting the
+amount of system memory that are available to a certain class of tasks.
+
+For more information on the features of cpusets, see Documentation/cpusets.txt.
+There are a number of different configurations you can use for your needs.  For
+more information on the numa=fake command line option and its various ways of
+configuring fake nodes, see Documentation/x86_64/boot-options.txt.
+
+For the purposes of this introduction, we'll assume a very primitive NUMA
+emulation setup of "numa=fake=4*512,".  This will split our system memory into
+four equal chunks of 512M each that we can now use to assign to cpusets.  As
+you become more familiar with using this combination for resource control,
+you'll determine a better setup to minimize the number of nodes you have to deal
+with.
+
+A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
+
+	Faking node 0 at 0000000000000000-0000000020000000 (512MB)
+	Faking node 1 at 0000000020000000-0000000040000000 (512MB)
+	Faking node 2 at 0000000040000000-0000000060000000 (512MB)
+	Faking node 3 at 0000000060000000-0000000080000000 (512MB)
+	...
+	On node 0 totalpages: 130975
+	On node 1 totalpages: 131072
+	On node 2 totalpages: 131072
+	On node 3 totalpages: 131072
+
+Now following the instructions for mounting the cpusets filesystem from
+Documentation/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
+address spaces) to individual cpusets:
+
+	[root@xroads /]# mkdir exampleset
+	[root@xroads /]# mount -t cpuset none exampleset
+	[root@xroads /]# mkdir exampleset/ddset
+	[root@xroads /]# cd exampleset/ddset
+	[root@xroads /exampleset/ddset]# echo 0-1 > cpus
+	[root@xroads /exampleset/ddset]# echo 0-1 > mems
+
+Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for
+memory allocations (1G).
+
+You can now assign tasks to these cpusets to limit the memory resources
+available to them according to the fake nodes assigned as mems:
+
+	[root@xroads /exampleset/ddset]# echo $$ > tasks
+	[root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G
+	[1] 13425
+
+Notice the difference between the system memory usage as reported by
+/proc/meminfo between the restricted cpuset case above and the unrestricted
+case (i.e. running the same 'dd' command without assigning it to a fake NUMA
+cpuset):
+				Unrestricted	Restricted
+	MemTotal:		3091900 kB	3091900 kB
+	MemFree:		  42113 kB	1513236 kB
+
+This allows for coarse memory management for the tasks you assign to particular
+cpusets.  Since cpusets can form a hierarchy, you can create some pretty
+interesting combinations of use-cases for various classes of tasks for your
+memory management needs.
diff --git a/Documentation/x86_64/machinecheck b/Documentation/x86_64/machinecheck
index 068a6d9..feaeaf6 100644
--- a/Documentation/x86_64/machinecheck
+++ b/Documentation/x86_64/machinecheck
@@ -36,7 +36,12 @@ between all CPUs.
 
 check_interval
 	How often to poll for corrected machine check errors, in seconds
-	(Note output is hexademical). Default 5 minutes.
+	(Note output is hexademical). Default 5 minutes.  When the poller
+	finds MCEs it triggers an exponential speedup (poll more often) on
+	the polling interval.  When the poller stops finding MCEs, it
+	triggers an exponential backoff (poll less often) on the polling
+	interval. The check_interval variable is both the initial and
+	maximum polling interval.
 
 tolerant
 	Tolerance level. When a machine check exception occurs for a non
diff --git a/Kbuild b/Kbuild
index 0451f69..163f8cb 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2,6 +2,7 @@ #
 # Kbuild for top-level directory of the kernel
 # This file takes care of the following:
 # 1) Generate asm-offsets.h
+# 2) Check for missing system calls
 
 #####
 # 1) Generate asm-offsets.h
@@ -46,3 +47,13 @@ arch/$(ARCH)/kernel/asm-offsets.s: arch/
 	$(Q)mkdir -p $(dir $@)
 	$(call cmd,offsets)
 
+#####
+# 2) Check for missing system calls
+#
+
+quiet_cmd_syscalls = CALL    $<
+      cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags)
+
+PHONY += missing-syscalls
+missing-syscalls: scripts/checksyscalls.sh FORCE
+	$(call cmd,syscalls)
diff --git a/MAINTAINERS b/MAINTAINERS
index 277877a..41a4b47 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -55,7 +55,7 @@ trivial patch so apply some common sense
 
 8.	Happy hacking.
 
- 		-----------------------------------
+		-----------------------------------
 
 Maintainers List (try to look for most precise areas first)
 
@@ -382,9 +382,15 @@ L:	linux-laptop@vger.kernel.org
 W:	http://www.canb.auug.org.au/~sfr/
 S:	Supported
 
+APPLE SMC DRIVER
+P:	Nicolas Boichat
+M:	nicolas@boichat.ch
+L:	mactel-linux-devel@lists.sourceforge.net
+S:	Maintained
+
 APPLETALK NETWORK LAYER
 P:	Arnaldo Carvalho de Melo
-M:	acme@conectiva.com.br
+M:	acme@ghostprotocols.net
 S:	Maintained
 
 ARC FRAMEBUFFER DRIVER
@@ -656,6 +662,7 @@ S:	Supported
 ATMEL WIRELESS DRIVER
 P:	Simon Kelley
 M:	simon@thekelleys.org.uk
+L:	linux-wireless@vger.kernel.org
 W:	http://www.thekelleys.org.uk/atmel
 W:	http://atmelwlandriver.sourceforge.net/
 S:	Maintained
@@ -672,6 +679,7 @@ AUXILIARY DISPLAY DRIVERS
 P:	Miguel Ojeda Sandonis
 M:	maxextreme@gmail.com
 L:	linux-kernel@vger.kernel.org
+W:	http://auxdisplay.googlepages.com/
 S:	Maintained
 
 AVR32 ARCHITECTURE
@@ -699,6 +707,44 @@ P:	Richard Purdie
 M:	rpurdie@rpsys.net
 S:	Maintained
 
+BLACKFIN ARCHITECTURE
+P:     Aubrey Li
+M:     aubrey.li@analog.com
+P:     Bernd Schmidt
+M:     bernd.schmidt@analog.com
+P:     Bryan Wu
+M:     bryan.wu@analog.com
+P:     Grace Pan
+M:     grace.pan@analog.com
+P:     Michael Hennerich
+M:     michael.hennerich@analog.com
+P:     Mike Frysinger
+M:     michael.frysinger@analog.com
+P:     Jane Lv
+M:     jane.lv@analog.com
+P:     Jerry Zeng
+M:     jerry.zeng@analog.com
+P:     Jie Zhang
+M:     jie.zhang@analog.com
+P:     Robin Getz
+M:     robin.getz@analog.com
+P:     Roy Huang
+M:     roy.huang@analog.com
+P:     Sonic Zhang
+M:     sonic.zhang@analog.com
+P:     Yi Li
+M:     yi.li@analog.com
+L:     uclinux-dist-devel@blackfin.uclinux.org
+W:     http://blackfin.uclinux.org
+S:     Supported
+
+BLACKFIN SERIAL DRIVER
+P:     Aubrey Li
+M:     aubrey.li@analog.com
+L:     uclinux-dist-devel@blackfin.uclinux.org
+W:     http://blackfin.uclinux.org
+S:     Supported
+
 BAYCOM/HDLCDRV DRIVERS FOR AX.25
 P:	Thomas Sailer
 M:	t.sailer@alumni.ethz.ch
@@ -711,6 +757,7 @@ P:	Larry Finger
 M:	Larry.Finger@lwfinger.net
 P:	Stefano Brivio
 M:	st3@riseup.net
+L:	linux-wireless@vger.kernel.org
 W:	http://bcm43xx.berlios.de/
 S:	Maintained
 
@@ -731,6 +778,13 @@ M:	tigran@aivazian.fsnet.co.uk
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+BLACKFIN I2C TWI DRIVER
+P:	Sonic Zhang
+M:	sonic.zhang@analog.com
+L:	uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
+W:	http://blackfin.uclinux.org/
+S:	Supported
+
 BLOCK LAYER
 P:	Jens Axboe
 M:	axboe@kernel.dk
@@ -871,6 +925,12 @@ W:	http://linuxtv.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
 S:	Maintained
 
+CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
+P:   	Jonathan Corbet
+M:	corbet@lwn.net
+L:	video4linux-list@redhat.com
+S:	Maintained
+
 CALGARY x86-64 IOMMU
 P:	Muli Ben-Yehuda
 M:	muli@il.ibm.com
@@ -884,12 +944,20 @@ CFAG12864B LCD DRIVER
 P:	Miguel Ojeda Sandonis
 M:	maxextreme@gmail.com
 L:	linux-kernel@vger.kernel.org
+W:	http://auxdisplay.googlepages.com/
 S:	Maintained
 
 CFAG12864BFB LCD FRAMEBUFFER DRIVER
 P:	Miguel Ojeda Sandonis
 M:	maxextreme@gmail.com
 L:	linux-kernel@vger.kernel.org
+W:	http://auxdisplay.googlepages.com/
+S:	Maintained
+
+CFG80211 and NL80211
+P:	Johannes Berg
+M:	johannes@sipsolutions.net
+L:	linux-wireless@vger.kernel.org
 S:	Maintained
 
 COMMON INTERNET FILE SYSTEM (CIFS)
@@ -899,7 +967,7 @@ L:	linux-cifs-client@lists.samba.org
 L:	samba-technical@lists.samba.org
 W:	http://us1.samba.org/samba/Linux_CIFS_client.html
 T:	git kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
-S:	Supported	
+S:	Supported
 
 CONFIGFS
 P:	Joel Becker
@@ -967,6 +1035,17 @@ M:	mhw@wittsend.com
 W:	http://www.wittsend.com/computone.html
 S:	Maintained
 
+CONEXANT ACCESSRUNNER USB DRIVER
+P:	Simon Arlott
+M:	cxacru@fire.lp0.eu
+S:	Maintained
+
+CORETEMP HARDWARE MONITORING DRIVER
+P:	Rudolf Marek
+M:	r.marek@assembler.cz
+L:	lm-sensors@lm-sensors.org
+S:	Maintained
+
 COSA/SRP SYNC SERIAL DRIVER
 P:	Jan "Yenya" Kasprzak
 M:	kas@fi.muni.cz
@@ -1034,9 +1113,8 @@ S:	Maintained
 
 CYCLADES 2X SYNC CARD DRIVER
 P:	Arnaldo Carvalho de Melo
-M:	acme@conectiva.com.br
-W:	http://advogato.org/person/acme
-L:	cycsyn-devel@bazar.conectiva.com.br
+M:	acme@ghostprotocols.net
+W:	http://oops.ghostprotocols.net:81/blog
 S:	Maintained
 
 CYCLADES ASYNC MUX DRIVER
@@ -1077,7 +1155,7 @@ S:	Maintained
 
 DCCP PROTOCOL
 P:	Arnaldo Carvalho de Melo
-M:	acme@mandriva.com
+M:	acme@ghostprotocols.net
 L:	dccp@vger.kernel.org
 W:	http://linux-net.osdl.org/index.php/DCCP
 S:	Maintained
@@ -1376,6 +1454,13 @@ L:	linuxppc-embedded@ozlabs.org
 L:	netdev@vger.kernel.org
 S:	Maintained
 
+FREESCALE HIGHSPEED USB DEVICE DRIVER
+P:	Li Yang
+M:	leoli@freescale.com
+L:	linux-usb-devel@lists.sourceforge.net
+L:	linuxppc-embedded@ozlabs.org
+S:	Maintained
+
 FILE LOCKING (flock() and fcntl()/lockf())
 P:	Matthew Wilcox
 M:	matthew@wil.cx
@@ -1434,6 +1519,11 @@ L:	linux-scsi@vger.kernel.org
 W:	http://www.icp-vortex.com/
 S:	Supported
 
+GENERIC GPIO I2C DRIVER
+P:	Haavard Skinnemoen
+M:	hskinnemoen@atmel.com
+S:	Supported
+
 GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
 P:	Krzysztof Halasa
 M:	khc@pm.waw.pl
@@ -1542,23 +1632,24 @@ P:	Chirag Kantharia
 M:	chirag.kantharia@hp.com
 L:	iss_storagedev@hp.com
 S:	Maintained
- 
+
 HEWLETT-PACKARD SMART2 RAID DRIVER
 P:	Chirag Kantharia
 M:	chirag.kantharia@hp.com
 L:	iss_storagedev@hp.com
 S:	Maintained
- 
+
 HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
 P:	Mike Miller
 M:	mike.miller@hp.com
 L:	iss_storagedev@hp.com
 S:	Supported
- 
+
 HOST AP DRIVER
 P:	Jouni Malinen
-M:	jkmaline@cc.hut.fi
-L:	hostap@shmoo.com
+M:	j@w1.fi
+L:	hostap@shmoo.com (subscribers-only)
+L:	linux-wireless@vger.kernel.org
 W:	http://hostap.epitest.fi/
 S:	Maintained
 
@@ -1579,7 +1670,7 @@ S:	Maintained
 
 HPET:	x86_64
 P:	Andi Kleen and Vojtech Pavlik
-M:	ak@muc.de and vojtech@suse.cz
+M:	andi@firstfloor.org and vojtech@suse.cz
 S:	Maintained
 
 HPET:	ACPI hpet.c
@@ -1605,6 +1696,13 @@ L:	i2c@lm-sensors.org
 T:	quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/
 S:	Maintained
 
+I2C-TINY-USB DRIVER
+P:	Till Harbaum
+M:	till@harbaum.org
+L:	i2c@lm-sensors.org
+T:	http://www.harbaum.org/till/i2c_tiny_usb
+S:	Maintained
+
 i386 BOOT CODE
 P:	Riley H. Williams
 M:	Riley@Williams.Name
@@ -1632,15 +1730,6 @@ W:	http://www.ia64-linux.org/
 T:	git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:	Maintained
 
-IBM ACPI EXTRAS DRIVER
-P:	Henrique de Moraes Holschuh
-M:	ibm-acpi@hmh.eng.br
-L:	ibm-acpi-devel@lists.sourceforge.net
-W:	http://ibm-acpi.sourceforge.net
-W:	http://thinkwiki.org/wiki/Ibm-acpi
-T:	git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
-S:	Maintained
-
 SN-IA64 (Itanium) SUB-PLATFORM
 P:	Jes Sorensen
 M:	jes@sgi.com
@@ -1665,7 +1754,7 @@ P:	Jack Hammer
 P:	Dave Jeffery
 M:	ipslinux@adaptec.com
 W:	http://www.developer.ibm.com/welcome/netfinity/serveraid.html
-S:	Supported 
+S:	Supported
 
 IDE SUBSYSTEM
 P:	Bartlomiej Zolnierkiewicz
@@ -1794,6 +1883,7 @@ P:	Jeff Kirsher
 M:	jeffrey.t.kirsher@intel.com
 P:	Auke Kok
 M:	auke-jan.h.kok@intel.com
+L:	e1000-devel@lists.sourceforge.net
 W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
@@ -1808,6 +1898,7 @@ P:	Jeff Kirsher
 M:	jeffrey.t.kirsher@intel.com
 P:	Auke Kok
 M:	auke-jan.h.kok@intel.com
+L:	e1000-devel@lists.sourceforge.net
 W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
@@ -1822,6 +1913,7 @@ P:	Jesse Brandeburg
 M:	jesse.brandeburg@intel.com
 P:	Auke Kok
 M:	auke-jan.h.kok@intel.com
+L:	e1000-devel@lists.sourceforge.net
 W:	http://sourceforge.net/projects/e1000/
 S:	Supported
 
@@ -1830,6 +1922,7 @@ P:	Yi Zhu
 M:	yi.zhu@intel.com
 P:	James Ketrenos
 M:	jketreno@linux.intel.com
+L:	linux-wireless@vger.kernel.org
 L:	ipw2100-devel@lists.sourceforge.net
 L:	http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
 W:	http://ipw2100.sourceforge.net
@@ -1840,6 +1933,7 @@ P:	Yi Zhu
 M:	yi.zhu@intel.com
 P:	James Ketrenos
 M:	jketreno@linux.intel.com
+L:	linux-wireless@vger.kernel.org
 L:	ipw2100-devel@lists.sourceforge.net
 L:	http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel
 W:	http://ipw2200.sourceforge.net
@@ -1871,7 +1965,7 @@ S:	Supported
 
 IPX NETWORK LAYER
 P:	Arnaldo Carvalho de Melo
-M:	acme@conectiva.com.br
+M:	acme@ghostprotocols.net
 L:	netdev@vger.kernel.org
 S:	Maintained
 
@@ -1942,7 +2036,7 @@ P:	Vivek Goyal
 M:	vgoyal@in.ibm.com
 P:	Haren Myneni
 M:	hbabu@us.ibm.com
-L:	fastboot@lists.linux-foundation.org
+L:	kexec@lists.infradead.org
 L:	linux-kernel@vger.kernel.org
 W:	http://lse.sourceforge.net/kdump/
 S:	Maintained
@@ -1965,7 +2059,7 @@ M:	kai@germaschewski.name
 P:	Sam Ravnborg
 M:	sam@ravnborg.org
 T:	git kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
-S:	Maintained 
+S:	Maintained
 
 KERNEL JANITORS
 P:	Several
@@ -1992,7 +2086,7 @@ P:	Eric Biederman
 M:	ebiederm@xmission.com
 W:	http://www.xmission.com/~ebiederm/files/kexec/
 L:	linux-kernel@vger.kernel.org
-L:	fastboot@lists.linux-foundation.org
+L:	kexec@lists.infradead.org
 S:	Maintained
 
 KPROBES
@@ -2011,6 +2105,7 @@ KS0108 LCD CONTROLLER DRIVER
 P:	Miguel Ojeda Sandonis
 M:	maxextreme@gmail.com
 L:	linux-kernel@vger.kernel.org
+W:	http://auxdisplay.googlepages.com/
 S:	Maintained
 
 LAPB module
@@ -2108,7 +2203,7 @@ S:	Supported
 
 LLC (802.2)
 P:	Arnaldo Carvalho de Melo
-M:	acme@conectiva.com.br
+M:	acme@ghostprotocols.net
 S:	Maintained
 
 LINUX FOR 64BIT POWERPC
@@ -2145,7 +2240,7 @@ S:	Maintained
 LOGICAL DISK MANAGER SUPPORT (LDM, Windows 2000/XP Dynamic Disks)
 P:	Richard Russon (FlatCap)
 M:	ldm@flatcap.org
-L:	ldm-devel@lists.sourceforge.net	
+L:	ldm-devel@lists.sourceforge.net
 W:	http://ldm.sourceforge.net
 S:	Maintained
 
@@ -2187,6 +2282,16 @@ M:	philb@gnu.org
 W:	http://www.tazenda.demon.co.uk/phil/linux-hp
 S:	Maintained
 
+MAC80211
+P:	Jiri Benc
+M:	jbenc@suse.cz
+P:	Michael Wu
+M:	flamingice@sourmilk.net
+L:	linux-wireless@vger.kernel.org
+W:	http://linuxwireless.org/
+T:	git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
+S:	Maintained
+
 MARVELL YUKON / SYSKONNECT DRIVER
 P:	Mirko Lindner
 M: 	mlindner@syskonnect.de
@@ -2215,6 +2320,12 @@ M:	vandrove@vc.cvut.cz
 L:	linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
 S:	Maintained
 
+MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
+P:	Hans J. Koch
+M:	hjk@linutronix.de
+L:	lm-sensors@lm-sensors.org
+S:	Maintained
+
 MEGARAID SCSI DRIVERS
 P:	Neela Syam Kolli
 M:	Neela.Kolli@engenio.com
@@ -2236,6 +2347,14 @@ L:	linux-mtd@lists.infradead.org
 T:	git git://git.infradead.org/mtd-2.6.git
 S:	Maintained
 
+UNSORTED BLOCK IMAGES (UBI)
+P:	Artem Bityutskiy
+M:	dedekind@infradead.org
+W:	http://www.linux-mtd.infradead.org/
+L:	linux-mtd@lists.infradead.org
+T:	git git://git.infradead.org/ubi-2.6.git
+S:	Maintained
+
 MICROTEK X6 SCANNER
 P:	Oliver Neukum
 M:	oliver@neukum.name
@@ -2473,6 +2592,19 @@ M:	adaplas@gmail.com
 L:	linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
 S:	Maintained
 
+NETERION (S2IO) Xframe 10GbE DRIVER
+P:	Ramkrishna Vepa
+M:	ram.vepa@neterion.com
+P:	Rastapur Santosh
+M:	santosh.rastapur@neterion.com
+P:	Sivakumar Subramani
+M:	sivakumar.subramani@neterion.com
+P:	Sreenivasa Honnur
+M:	sreenivasa.honnur@neterion.com
+L:	netdev@vger.kernel.org
+W:	http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous
+S:	Supported
+
 OPENCORES I2C BUS DRIVER
 P:	Peter Korsgaard
 M:	jacmet@sunsite.dk
@@ -2486,13 +2618,13 @@ P:	Kurt Hackel
 M:	kurt.hackel@oracle.com
 L:	ocfs2-devel@oss.oracle.com
 W:	http://oss.oracle.com/projects/ocfs2/
-S:	Supported	
+S:	Supported
 
 OLYMPIC NETWORK DRIVER
 P:	Peter De Shrijver
 M:	p2@ace.ulyssis.student.kuleuven.ac.be
 P:	Mike Phillips
-M:	mikep@linuxtr.net 
+M:	mikep@linuxtr.net
 L:	netdev@vger.kernel.org
 L:	linux-tr@linuxtr.net
 W:	http://www.linuxtr.net
@@ -2508,6 +2640,12 @@ P:	Harald Welte
 M:	laforge@gnumonks.org
 S:	Maintained
 
+OMNIVISION OV7670 SENSOR DRIVER
+P:   	Jonathan Corbet
+M:	corbet@lwn.net
+L:	video4linux-list@redhat.com
+S:	Maintained
+
 ONSTREAM SCSI TAPE DRIVER
 P:	Willem Riede
 M:	osst@riede.org
@@ -2532,6 +2670,7 @@ P:	Pavel Roskin
 M:	proski@gnu.org
 P:	David Gibson
 M:	hermes@gibson.dropbear.id.au
+L:	linux-wireless@vger.kernel.org
 L:	orinoco-users@lists.sourceforge.net
 L:	orinoco-devel@lists.sourceforge.net
 W:	http://www.nongnu.org/orinoco/
@@ -2573,6 +2712,19 @@ T:	git kernel.org:/pub/scm/linux/kernel/
 T:	cvs cvs.parisc-linux.org:/var/cvs/linux-2.6
 S:	Maintained
 
+PARAVIRT_OPS INTERFACE
+P:	Jeremy Fitzhardinge
+M:	jeremy@xensource.com
+P:	Chris Wright
+M:	chrisw@sous-sol.org
+P:	Zachary Amsden
+M:	zach@vmware.com
+P:	Rusty Russell
+M:	rusty@rustcorp.com.au
+L:	virtualization@lists.osdl.org
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
 PC87360 HARDWARE MONITORING DRIVER
 P:	Jim Cromie
 M:	jim.cromie@gmail.com
@@ -2711,7 +2863,7 @@ S:	Supported
 PRISM54 WIRELESS DRIVER
 P:	Prism54 Development Team
 M:	developers@islsm.org
-L:	netdev@vger.kernel.org
+L:	linux-wireless@vger.kernel.org
 W:	http://prism54.org
 S:	Maintained
 
@@ -2782,7 +2934,7 @@ S:	Maintained
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
 P:	Corey Thomas
 M:	corey@world.std.com
-L:	linux-kernel@vger.kernel.org
+L:	linux-wireless@vger.kernel.org
 S:	Maintained
 
 RANDOM NUMBER DRIVER
@@ -2961,11 +3113,18 @@ P:	Stephen Smalley
 M:	sds@tycho.nsa.gov
 P:	James Morris
 M:	jmorris@namei.org
+P:	Eric Paris
+M:	eparis@parisplace.org
 L:	linux-kernel@vger.kernel.org (kernel issues)
-L: 	selinux@tycho.nsa.gov (general discussion)
+L: 	selinux@tycho.nsa.gov (subscribers-only, general discussion)
 W:	http://www.nsa.gov/selinux
 S:	Supported
 
+SENSABLE PHANTOM
+P:	Jiri Slaby
+M:	jirislaby@gmail.com
+S:	Maintained
+
 SERIAL ATA (SATA) SUBSYSTEM:
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
@@ -3024,7 +3183,7 @@ SIS FRAMEBUFFER DRIVER
 P:	Thomas Winischhofer
 M:	thomas@winischhofer.net
 W:	http://www.winischhofer.net/linuxsisvga.shtml
-S:	Maintained	
+S:	Maintained
 
 SIS USB2VGA DRIVER
 P:	Thomas Winischhofer
@@ -3045,7 +3204,7 @@ M:	josejx@gentoo.org
 P:	Daniel Drake
 M:	dsd@gentoo.org
 W:	http://softmac.sipsolutions.net/
-L:	netdev@vger.kernel.org
+L:	linux-wireless@vger.kernel.org
 S:	Maintained
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
@@ -3121,6 +3280,15 @@ P:	Chris Zankel
 M:	chris@zankel.net
 S:	Maintained
 
+THINKPAD ACPI EXTRAS DRIVER
+P:	Henrique de Moraes Holschuh
+M:	ibm-acpi@hmh.eng.br
+L:	ibm-acpi-devel@lists.sourceforge.net
+W:	http://ibm-acpi.sourceforge.net
+W:	http://thinkwiki.org/wiki/Ibm-acpi
+T:	git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S:	Maintained
+
 UltraSPARC (sparc64):
 P:	David S. Miller
 M:	davem@davemloft.net
@@ -3566,14 +3734,14 @@ W:	http://www.kroah.com/linux/
 S:	Maintained
 
 USB SERIAL WHITEHEAT DRIVER
-P:	Stuart MacDonald
-M:	stuartm@connecttech.com
+P:	Support Department
+M:	support@connecttech.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 W:	http://www.connecttech.com
 S:	Supported
 
-USB SN9C10x DRIVER
+USB SN9C1xx DRIVER
 P:	Luca Risolia
 M:	luca.risolia@studio.unibo.it
 L:	linux-usb-devel@lists.sourceforge.net
@@ -3628,6 +3796,14 @@ L:	linux-usb-devel@lists.sourceforge.net
 W:	http://linux-lc100020.sourceforge.net
 S:	Maintained
 
+USB ZR364XX DRIVER
+P:	Antoine Jacquet
+M:	royale@zerezo.com
+L:	linux-usb-devel@lists.sourceforge.net
+L:	video4linux-list@redhat.com
+W:	http://royale.zerezo.com/zr364xx/
+S:	Maintained
+
 USER-MODE LINUX
 P:	Jeff Dike
 M:	jdike@karaya.com
@@ -3635,7 +3811,7 @@ L:	user-mode-linux-devel@lists.sourcefor
 L:	user-mode-linux-user@lists.sourceforge.net
 W:	http://user-mode-linux.sourceforge.net
 S:	Maintained
-	
+
 FAT/VFAT/MSDOS FILESYSTEM:
 P:	OGAWA Hirofumi
 M:	hirofumi@mail.parknet.co.jp
@@ -3750,6 +3926,7 @@ S:	Maintained
 WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS
 P:	Jean Tourrilhes
 M:	jt@hpl.hp.com
+L:	linux-wireless@vger.kernel.org
 W:	http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
 S:	Maintained
 
@@ -3766,8 +3943,9 @@ S:	Maintained
 
 WL3501 WIRELESS PCMCIA CARD DRIVER
 P:	Arnaldo Carvalho de Melo
-M:	acme@conectiva.com.br
-W:	http://advogato.org/person/acme
+M:	acme@ghostprotocols.net
+L:	linux-wireless@vger.kernel.org
+W:	http://oops.ghostprotocols.net:81/blog
 S:	Maintained
 
 X.25 NETWORK LAYER
@@ -3776,6 +3954,15 @@ M:	eis@baty.hanse.de
 L:	linux-x25@vger.kernel.org
 S:	Maintained
 
+XEN HYPERVISOR INTERFACE
+P:	Jeremy Fitzhardinge
+M:	jeremy@xensource.com
+P:	Chris Wright
+M:	chrisw@sous-sol.org
+L:	virtualization@lists.osdl.org
+L:	xen-devel@lists.xensource.com
+S:	Supported
+
 XFS FILESYSTEM
 P:	Silicon Graphics Inc
 P:	Tim Shimmin, David Chatterton
@@ -3830,6 +4017,7 @@ M:	dsd@gentoo.org
 P:	Ulrich Kunitz
 M:	kune@deine-taler.de
 W:	http://zd1211.ath.cx/wiki/DriverRewrite
+L:	linux-wireless@vger.kernel.org
 L:	zd1211-devs@lists.sourceforge.net (subscribers-only)
 S:	Maintained
 
diff --git a/Makefile b/Makefile
index d970cb1..dfe559c 100644
--- a/Makefile
+++ b/Makefile
@@ -491,7 +491,7 @@ endif
 include $(srctree)/arch/$(ARCH)/Makefile
 
 ifdef CONFIG_FRAME_POINTER
-CFLAGS		+= -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+CFLAGS		+= -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
 CFLAGS		+= -fomit-frame-pointer
 endif
@@ -576,7 +576,7 @@ # Build vmlinux
 # ---------------------------------------------------------------------------
 # vmlinux is built from the objects selected by $(vmlinux-init) and
 # $(vmlinux-main). Most are built-in.o files from top-level directories
-# in the kernel tree, others are specified in arch/$(ARCH)Makefile.
+# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
 # Ordering when linking is important, and $(vmlinux-init) must be first.
 #
 # vmlinux
@@ -603,6 +603,7 @@ vmlinux-init := $(head-y) $(init-y)
 vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
 vmlinux-all  := $(vmlinux-init) $(vmlinux-main)
 vmlinux-lds  := arch/$(ARCH)/kernel/vmlinux.lds
+export KBUILD_VMLINUX_OBJS := $(vmlinux-all)
 
 # Rule to link vmlinux - also used during CONFIG_KALLSYMS
 # May be overridden by arch/$(ARCH)/Makefile
@@ -855,6 +856,7 @@ archprepare: prepare1 scripts_basic
 
 prepare0: archprepare FORCE
 	$(Q)$(MAKE) $(build)=.
+	$(Q)$(MAKE) $(build)=. missing-syscalls
 
 # All the preparing..
 prepare: prepare0
@@ -1277,10 +1279,7 @@ endif
 ALLSOURCE_ARCHS := $(ARCH)
 
 define find-sources
-        ( find $(__srctree) $(RCS_FIND_IGNORE) \
-	       \( -name include -o -name arch \) -prune -o \
-	       -name $1 -print; \
-	  for ARCH in $(ALLSOURCE_ARCHS) ; do \
+        ( for ARCH in $(ALLSOURCE_ARCHS) ; do \
 	       find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
 	            -name $1 -print; \
 	  done ; \
@@ -1294,7 +1293,11 @@ define find-sources
 	            -name $1 -print; \
 	  done ; \
 	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
-	       -name $1 -print )
+	       -name $1 -print; \
+	  find $(__srctree) $(RCS_FIND_IGNORE) \
+	       \( -name include -o -name arch \) -prune -o \
+	       -name $1 -print; \
+	  )
 endef
 
 define all-sources
diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug
index 36d0106..f45f28c 100644
--- a/arch/alpha/Kconfig.debug
+++ b/arch/alpha/Kconfig.debug
@@ -16,14 +16,6 @@ config DEBUG_RWLOCK
 	  too many attempts.  If you suspect a rwlock problem or a kernel
 	  hacker asks for this option then say Y.  Otherwise say N.
 
-config DEBUG_SEMAPHORE
-	bool "Semaphore debugging"
-	depends on DEBUG_KERNEL
-	help
-	  If you say Y here then semaphore processing will issue lots of
-	  verbose debugging messages.  If you suspect a semaphore problem or a
-	  kernel hacker asks for this option then say Y.  Otherwise say N.
-
 config ALPHA_LEGACY_START_ADDRESS
 	bool "Legacy kernel start address"
 	depends on ALPHA_GENERIC
diff --git a/arch/alpha/boot/bootpz.c b/arch/alpha/boot/bootpz.c
index 4307bde..1036b51 100644
--- a/arch/alpha/boot/bootpz.c
+++ b/arch/alpha/boot/bootpz.c
@@ -467,3 +467,9 @@ #ifdef DEBUG_LAST_STEPS
 #endif
 	runkernel();
 }
+
+ /* dummy function, should never be called. */
+void *__kmalloc(size_t size, gfp_t flags)
+{
+	return (void *)NULL;
+}
diff --git a/arch/alpha/boot/misc.c b/arch/alpha/boot/misc.c
index 1d65adf..c00646b 100644
--- a/arch/alpha/boot/misc.c
+++ b/arch/alpha/boot/misc.c
@@ -98,7 +98,7 @@ extern int end;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../lib/inflate.c"
 
diff --git a/arch/alpha/boot/tools/objstrip.c b/arch/alpha/boot/tools/objstrip.c
index 67beb1b..96154e7 100644
--- a/arch/alpha/boot/tools/objstrip.c
+++ b/arch/alpha/boot/tools/objstrip.c
@@ -25,7 +25,6 @@ #include <sys/types.h>
 #include <linux/a.out.h>
 #include <linux/coff.h>
 #include <linux/param.h>
-#include <linux/string.h>
 #ifdef __ELF__
 # include <linux/elf.h>
 #endif
diff --git a/arch/alpha/kernel/err_common.c b/arch/alpha/kernel/err_common.c
index 687580b..13d53b1 100644
--- a/arch/alpha/kernel/err_common.c
+++ b/arch/alpha/kernel/err_common.c
@@ -7,7 +7,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 69b5f4e..11aee01 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -7,7 +7,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c
index 95463ab..bc799f7 100644
--- a/arch/alpha/kernel/err_ev7.c
+++ b/arch/alpha/kernel/err_ev7.c
@@ -7,7 +7,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index be133f1..ce85715 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -93,7 +93,6 @@ #endif
  * offset differences aren't the same as "d_reclen").
  */
 #define NAME_OFFSET	offsetof (struct osf_dirent, d_name)
-#define ROUND_UP(x)	(((x)+3) & ~3)
 
 struct osf_dirent {
 	unsigned int d_ino;
@@ -115,7 +114,7 @@ osf_filldir(void *__buf, const char *nam
 {
 	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 reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
 	unsigned int d_ino;
 
 	buf->error = -EINVAL;	/* only used if we fail */
@@ -174,7 +173,6 @@ osf_getdirentries(unsigned int fd, struc
 	return error;
 }
 
-#undef ROUND_UP
 #undef NAME_OFFSET
 
 asmlinkage unsigned long
@@ -955,15 +953,25 @@ osf_setitimer(int which, struct itimerva
 asmlinkage int
 osf_utimes(char __user *filename, struct timeval32 __user *tvs)
 {
-	struct timeval ktvs[2];
+	struct timespec tv[2];
 
 	if (tvs) {
+		struct timeval ktvs[2];
 		if (get_tv32(&ktvs[0], &tvs[0]) ||
 		    get_tv32(&ktvs[1], &tvs[1]))
 			return -EFAULT;
+
+		if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
+		    ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
+			return -EINVAL;
+
+		tv[0].tv_sec = ktvs[0].tv_sec;
+		tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
+		tv[1].tv_sec = ktvs[1].tv_sec;
+		tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
 	}
 
-	return do_utimes(AT_FDCWD, filename, tvs ? ktvs : NULL);
+	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
 }
 
 #define MAX_SELECT_SECONDS \
@@ -1267,6 +1275,9 @@ arch_get_unmapped_area(struct file *filp
 	if (len > limit)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED)
+		return addr;
+
 	/* First, see if the given suggestion fits.
 
 	   The OSF/1 loader (/sbin/loader) relies on us returning an
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index c151863..92b6162 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -14,7 +14,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index d352c2b..915f263 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -744,15 +744,6 @@ #endif
 	paging_init();
 }
 
-void __init
-disable_early_printk(void)
-{
-	if (alpha_using_srm && srmcons_output) {
-		unregister_srm_console();
-		srmcons_output = 0;
-	}
-}
-
 static char sys_unknown[] = "Unknown";
 static char systype_names[][16] = {
 	"0",
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 741da09..7f64aa7 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -15,7 +15,6 @@ #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index d1ec4f5..80cfb75 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -18,7 +18,6 @@ #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 7569232..930cedc 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -164,9 +164,9 @@ srmcons_get_private_struct(struct srmcon
 	int retval = 0;
 
 	if (srmconsp == NULL) {
+		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
 		spin_lock_irqsave(&srmconsp_lock, flags);
 
-		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
 		if (srmconsp == NULL)
 			retval = -ENOMEM;
 		else {
@@ -300,7 +300,7 @@ static struct console srmcons = {
 	.write		= srm_console_write,
 	.device		= srm_console_device,
 	.setup		= srm_console_setup,
-	.flags		= CON_PRINTBUFFER,
+	.flags		= CON_PRINTBUFFER | CON_BOOT,
 	.index		= -1,
 };
 
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 4cc44bd..cf1e6fc 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -69,7 +69,7 @@ #endif
   . = ALIGN(8);
   SECURITY_INIT
 
-  . = ALIGN(64);
+  . = ALIGN(8192);
   __per_cpu_start = .;
   .data.percpu : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index 21cf624..ea098f3 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -36,7 +36,6 @@ lib-y =	__divqu.o __remqu.o __divlu.o __
 	$(ev6-y)csum_ipv6_magic.o \
 	$(ev6-y)clear_page.o \
 	$(ev6-y)copy_page.o \
-	strcasecmp.o \
 	fpreg.o \
 	callback_srm.o srm_puts.o srm_printk.o
 
diff --git a/arch/alpha/lib/strcasecmp.c b/arch/alpha/lib/strcasecmp.c
deleted file mode 100644
index 4e57a21..0000000
--- a/arch/alpha/lib/strcasecmp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/arch/alpha/lib/strcasecmp.c
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale.  Since this is used in
-   only one place, on strings known to contain only 7 bit ASCII, this
-   is ok.  */
-
-int strcasecmp(const char *a, const char *b)
-{
-	int ca, cb;
-
-	do {
-		ca = *a++ & 0xff;
-		cb = *b++ & 0xff;
-		if (ca >= 'A' && ca <= 'Z')
-			ca += 'a' - 'A';
-		if (cb >= 'A' && cb <= 'Z')
-			cb += 'a' - 'A';
-	} while (ca == cb && ca != '\0');
-
-	return ca - cb;
-}
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 8aa9db8..f586279 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -21,7 +21,6 @@ #include <linux/types.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e7baca2..0d8fac3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,6 +29,10 @@ config GENERIC_TIME
 	bool
 	default n
 
+config GENERIC_CLOCKEVENTS
+	bool
+	default n
+
 config MMU
 	bool
 	default y
@@ -67,6 +71,14 @@ config GENERIC_HARDIRQS
 	bool
 	default y
 
+config STACKTRACE_SUPPORT
+	bool
+	default y
+
+config LOCKDEP_SUPPORT
+	bool
+	default y
+
 config TRACE_IRQFLAGS_SUPPORT
 	bool
 	default y
@@ -162,6 +174,8 @@ config ARCH_VERSATILE
 	select ARM_AMBA
 	select ARM_VIC
 	select ICST307
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
 	help
 	  This enables support for ARM Ltd Versatile board.
 
@@ -255,6 +269,7 @@ config ARCH_IOP13XX
 	depends on MMU
 	select PLAT_IOP
 	select PCI
+	select ARCH_SUPPORTS_MSI
 	help
 	  Support for Intel's IOP13XX (XScale) family of processors.
 
@@ -262,6 +277,7 @@ config ARCH_IXP4XX
 	bool "IXP4xx-based"
 	depends on MMU
 	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
 	help
 	  Support for Intel's IXP4XX (XScale) family of processors.
 
@@ -363,6 +379,7 @@ config ARCH_LH7A40X
 config ARCH_OMAP
 	bool "TI OMAP"
 	select GENERIC_GPIO
+	select GENERIC_TIME
 	help
 	  Support for TI's OMAP platform (OMAP1 and OMAP2).
 
@@ -513,6 +530,8 @@ endmenu
 
 menu "Kernel Features"
 
+source "kernel/time/Kconfig"
+
 config SMP
 	bool "Symmetric Multi-Processing (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && REALVIEW_MPCORE
@@ -572,6 +591,7 @@ config PREEMPT
 
 config NO_IDLE_HZ
 	bool "Dynamic tick timer"
+	depends on !GENERIC_CLOCKEVENTS
 	help
 	  Select this option if you want to disable continuous timer ticks
 	  and have them programmed to occur as required. This option saves
@@ -669,6 +689,7 @@ config LEDS_TIMER
 	bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
 			    MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
 	depends on LEDS
+	depends on !GENERIC_CLOCKEVENTS
 	default y if ARCH_EBSA110
 	help
 	  If you say Y here, one of the system LEDs (the green one on the
diff --git a/arch/arm/boot/compressed/head-at91rm9200.S b/arch/arm/boot/compressed/head-at91rm9200.S
index d68b9ac..11782cc 100644
--- a/arch/arm/boot/compressed/head-at91rm9200.S
+++ b/arch/arm/boot/compressed/head-at91rm9200.S
@@ -61,6 +61,12 @@ #include <asm/mach-types.h>
 		cmp	r7, r3
 		beq	99f
 
+		@ picotux 200 : 963
+		mov	r3,	#(MACH_TYPE_PICOTUX2XX & 0xff)
+		orr	r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00)
+		cmp	r7, r3
+		beq	99f
+
 		@ Ajeco 1ARM : 1075
 		mov	r3,	#(MACH_TYPE_ONEARM & 0xff)
 		orr	r3, r3, #(MACH_TYPE_ONEARM & 0xff00)
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 283891c..9b44402 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -239,7 +239,7 @@ extern int end;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../../lib/inflate.c"
 
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index fe3f059..798bbfc 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -18,7 +18,6 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index a9bc5b5..5972df2 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -766,10 +766,10 @@ static void sharpsl_apm_get_power_status
 }
 
 static struct pm_ops sharpsl_pm_ops = {
-	.pm_disk_mode	= PM_DISK_FIRMWARE,
 	.prepare	= pxa_pm_prepare,
 	.enter		= corgi_pxa_pm_enter,
 	.finish		= pxa_pm_finish,
+	.valid		= pm_valid_only_mem,
 };
 
 static int __init sharpsl_pm_probe(struct platform_device *pdev)
diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c
index ba2e629..79a8206 100644
--- a/arch/arm/common/via82c505.c
+++ b/arch/arm/common/via82c505.c
@@ -1,6 +1,5 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/init.h>
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index fabf74c..db850a5 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -117,11 +117,13 @@ CONFIG_ARCH_ADI_COYOTE=y
 CONFIG_ARCH_IXDP425=y
 CONFIG_MACH_IXDPG425=y
 CONFIG_MACH_IXDP465=y
+CONFIG_MACH_KIXRP435=y
 CONFIG_ARCH_IXCDP1100=y
 CONFIG_ARCH_PRPMC1100=y
 CONFIG_MACH_NAS100D=y
 CONFIG_ARCH_IXDP4XX=y
 CONFIG_CPU_IXP46X=y
+CONFIG_CPU_IXP43X=y
 # CONFIG_MACH_GTWX5715 is not set
 
 #
diff --git a/arch/arm/configs/picotux200_defconfig b/arch/arm/configs/picotux200_defconfig
new file mode 100644
index 0000000..339c489
--- /dev/null
+++ b/arch/arm/configs/picotux200_defconfig
@@ -0,0 +1,1386 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Wed Mar 28 16:19:50 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=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_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# 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=m
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=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=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 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_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=y
+# 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_IOP13XX 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_NS9XXX 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
+
+#
+# Atmel AT91 System-on-Chip
+#
+CONFIG_ARCH_AT91RM9200=y
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+
+#
+# AT91RM9200 Board Type
+#
+# CONFIG_MACH_ONEARM is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MACH_AT91RM9200EK is not set
+# CONFIG_MACH_CSB337 is not set
+# CONFIG_MACH_CSB637 is not set
+# CONFIG_MACH_CARMEVA is not set
+# CONFIG_MACH_ATEB9200 is not set
+# CONFIG_MACH_KB9200 is not set
+CONFIG_MACH_PICOTUX2XX=y
+# CONFIG_MACH_KAFA is not set
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4T=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
+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_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# 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
+CONFIG_KEXEC=y
+
+#
+# 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 is not set
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# 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=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE 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=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# 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_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+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"
+# CONFIG_TCP_MD5SIG 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=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_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES 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=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 is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# 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 is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI 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_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES 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_BLKDEVS=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_ARM_INTEGRATOR 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT is not set
+# 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=y
+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
+# CONFIG_SCSI_SCAN_ASYNC 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_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
+
+#
+# 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_ARM_AT91_ETHER=y
+# CONFIG_SMC91X 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=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+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=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
+
+#
+# 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_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=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91RM9200_WATCHDOG=m
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 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=m
+
+#
+# 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_AT91=m
+CONFIG_I2C_ISA=m
+# 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=m
+CONFIG_SENSORS_DS1374=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCA9539=m
+CONFIG_SENSORS_PCF8591=m
+# 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
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=m
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ABITUGURU is not set
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DS1621=m
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+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 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+CONFIG_SENSORS_SMSC47B397=m
+# CONFIG_SENSORS_VT1211 is not set
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83L785TS=m
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 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
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=m
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# 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=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_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=m
+# 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_GTCO 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_MII=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=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_KC2190=y
+CONFIG_USB_NET_ZAURUS=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_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 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
+# CONFIG_USB_SERIAL_DEBUG 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_BERRY_CHARGE 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_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR 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=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_AT91=m
+
+#
+# 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_CMOS is not set
+# 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_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_AT91RM9200=m
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG 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=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=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=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=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
+# 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=y
+# 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="utf-8"
+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
+#
+# CONFIG_DLM 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER 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=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+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_GF128MUL=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=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_CAMELLIA=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index bb28087..593b565 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OF
 # Object file lists.
 
 obj-y		:= compat.o entry-armv.o entry-common.o irq.o \
-		   process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \
-		   time.o traps.o
+		   process.o ptrace.o semaphore.o setup.o signal.o \
+		   sys_arm.o stacktrace.o time.o traps.o
 
 obj-$(CONFIG_ISA_DMA_API)	+= dma.o
 obj-$(CONFIG_ARCH_ACORN)	+= ecard.o 
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index f1c0fb9..bdbd7da 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -40,6 +40,7 @@ #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 
 #include <asm/dma.h>
 #include <asm/ecard.h>
@@ -50,6 +51,8 @@ #include <asm/mmu_context.h>
 #include <asm/mach/irq.h>
 #include <asm/tlbflush.h>
 
+#include "ecard.h"
+
 #ifndef CONFIG_ARCH_RPC
 #define HAVE_EXPMASK
 #endif
@@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecar
 
 	res = ec->slot_no == 8
 		? &ec->resource[ECARD_RES_MEMC]
-		: ec->type == ECARD_EASI
+		: ec->easi
 		  ? &ec->resource[ECARD_RES_EASI]
 		  : &ec->resource[ECARD_RES_IOCSYNC];
 
@@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct 
 			index += 1;
 		}
 	} else {
-		unsigned long base = (ec->type == ECARD_EASI
+		unsigned long base = (ec->easi
 			 ? &ec->resource[ECARD_RES_EASI]
 			 : &ec->resource[ECARD_RES_IOCSYNC])->start;
 		void __iomem *pbase = (void __iomem *)base;
@@ -263,8 +266,6 @@ static int ecard_init_mm(void)
 static int
 ecard_task(void * unused)
 {
-	daemonize("kecardd");
-
 	/*
 	 * Allocate a mm.  We're not a lazy-TLB kernel task since we need
 	 * to set page table entries where the user space would be.  Note
@@ -727,7 +728,7 @@ static int ecard_prints(char *buffer, ec
 	char *start = buffer;
 
 	buffer += sprintf(buffer, "  %d: %s ", ec->slot_no,
-			  ec->type == ECARD_EASI ? "EASI" : "    ");
+			  ec->easi ? "EASI" : "    ");
 
 	if (ec->cid.id == 0) {
 		struct in_chunk_dir incd;
@@ -814,7 +815,7 @@ static struct expansion_card *__init eca
 	}
 
 	ec->slot_no = slot;
-	ec->type = type;
+	ec->easi = type == ECARD_EASI;
 	ec->irq = NO_IRQ;
 	ec->fiq = NO_IRQ;
 	ec->dma = NO_DMA;
@@ -825,6 +826,7 @@ static struct expansion_card *__init eca
 	ec->dev.bus = &ecard_bus_type;
 	ec->dev.dma_mask = &ec->dma_mask;
 	ec->dma_mask = (u64)0xffffffff;
+	ec->dev.coherent_dma_mask = ec->dma_mask;
 
 	if (slot < 4) {
 		ec_set_resource(ec, ECARD_RES_MEMC,
@@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct 
 static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct expansion_card *ec = ECARD_DEV(dev);
-	return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC");
+	return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
 }
 
 static struct device_attribute ecard_dev_attrs[] = {
@@ -1058,13 +1060,14 @@ #endif
  */
 static int __init ecard_init(void)
 {
-	int slot, irqhw, ret;
-
-	ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
-	if (ret < 0) {
-		printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n",
-		       ret);
-		return ret;
+	struct task_struct *task;
+	int slot, irqhw;
+
+	task = kthread_run(ecard_task, NULL, "kecardd");
+	if (IS_ERR(task)) {
+		printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
+		       PTR_ERR(task));
+		return PTR_ERR(task);
 	}
 
 	printk("Probing expansion cards\n");
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h
new file mode 100644
index 0000000..d7c2dac
--- /dev/null
+++ b/arch/arm/kernel/ecard.h
@@ -0,0 +1,56 @@
+/*
+ *  ecard.h
+ *
+ *  Copyright 2007 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.
+ */
+
+/* Definitions internal to ecard.c - for it's use only!!
+ *
+ * External expansion card header as read from the card
+ */
+struct ex_ecid {
+	unsigned char	r_irq:1;
+	unsigned char	r_zero:1;
+	unsigned char	r_fiq:1;
+	unsigned char	r_id:4;
+	unsigned char	r_a:1;
+
+	unsigned char	r_cd:1;
+	unsigned char	r_is:1;
+	unsigned char	r_w:2;
+	unsigned char	r_r1:4;
+
+	unsigned char	r_r2:8;
+
+	unsigned char	r_prod[2];
+
+	unsigned char	r_manu[2];
+
+	unsigned char	r_country;
+
+	unsigned char	r_fiqmask;
+	unsigned char	r_fiqoff[3];
+
+	unsigned char	r_irqmask;
+	unsigned char	r_irqoff[3];
+};
+
+/*
+ * Chunk directory entry as read from the card
+ */
+struct ex_chunk_dir {
+	unsigned char r_id;
+	unsigned char r_len[3];
+	unsigned long r_start;
+	union {
+		char string[256];
+		char data[1];
+	} d;
+#define c_id(x)		((x)->r_id)
+#define c_len(x)	((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
+#define c_start(x)	((x)->r_start)
+};
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 66db0a9..1d35eda 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -257,7 +257,9 @@ #ifdef CONFIG_XIP_KERNEL
 	 * Map some ram to cover our .data and .bss areas.
 	 */
 	orr	r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
+	.if	(KERNEL_RAM_PADDR & 0x00f00000)
 	orr	r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
+	.endif
 	add	r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> 18
 	str	r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
 	ldr	r6, =(_end - 1)
@@ -274,7 +276,9 @@ #endif
 	 */
 	add	r0, r4, #PAGE_OFFSET >> 18
 	orr	r6, r7, #(PHYS_OFFSET & 0xff000000)
-	orr	r6, r6, #(PHYS_OFFSET & 0x00e00000)
+	.if	(PHYS_OFFSET & 0x00f00000)
+	orr	r6, r6, #(PHYS_OFFSET & 0x00f00000)
+	.endif
 	str	r6, [r0]
 
 #ifdef CONFIG_DEBUG_LL
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index e101846..11dcd52 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -27,7 +27,6 @@ #include <linux/signal.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = {
  * come via this function.  Instead, they should provide their
  * own 'handler'
  */
-asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	struct irq_desc *desc = irq_desc + irq;
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 782af3c..5d6e652 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -16,7 +16,6 @@ #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>
@@ -28,6 +27,7 @@ #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/elfcore.h>
 #include <linux/pm.h>
+#include <linux/tick.h>
 
 #include <asm/leds.h>
 #include <asm/processor.h>
@@ -160,9 +160,11 @@ #endif
 		if (!idle)
 			idle = default_idle;
 		leds_event(led_idle_start);
+		tick_nohz_stop_sched_tick();
 		while (!need_resched())
 			idle();
 		leds_event(led_idle_end);
+		tick_nohz_restart_sched_tick();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9254ba2..6f2f46c 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -13,7 +13,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
@@ -457,13 +456,10 @@ void ptrace_cancel_bpt(struct task_struc
 
 /*
  * Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
  */
 void ptrace_disable(struct task_struct *child)
 {
-	child->ptrace &= ~PT_SINGLESTEP;
-	ptrace_cancel_bpt(child);
+	single_step_disable(child);
 }
 
 /*
@@ -712,9 +708,7 @@ long arch_ptrace(struct task_struct *chi
 			else
 				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 			child->exit_code = data;
-			/* make sure single-step breakpoint is gone. */
-			child->ptrace &= ~PT_SINGLESTEP;
-			ptrace_cancel_bpt(child);
+			single_step_disable(child);
 			wake_up_process(child);
 			ret = 0;
 			break;
@@ -725,9 +719,7 @@ long arch_ptrace(struct task_struct *chi
 		 * exit.
 		 */
 		case PTRACE_KILL:
-			/* make sure single-step breakpoint is gone. */
-			child->ptrace &= ~PT_SINGLESTEP;
-			ptrace_cancel_bpt(child);
+			single_step_disable(child);
 			if (child->exit_state != EXIT_ZOMBIE) {
 				child->exit_code = SIGKILL;
 				wake_up_process(child);
@@ -742,7 +734,7 @@ long arch_ptrace(struct task_struct *chi
 			ret = -EIO;
 			if (!valid_signal(data))
 				break;
-			child->ptrace |= PT_SINGLESTEP;
+			single_step_enable(child);
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 			child->exit_code = data;
 			/* give it a chance to run. */
@@ -786,8 +778,8 @@ #endif
 			break;
 
 		case PTRACE_SET_SYSCALL:
+			task_thread_info(child)->syscall = data;
 			ret = 0;
-			child->ptrace_message = data;
 			break;
 
 #ifdef CONFIG_CRUNCH
@@ -824,7 +816,7 @@ asmlinkage int syscall_trace(int why, st
 	ip = regs->ARM_ip;
 	regs->ARM_ip = why;
 
-	current->ptrace_message = scno;
+	current_thread_info()->syscall = scno;
 
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
@@ -841,5 +833,5 @@ asmlinkage int syscall_trace(int why, st
 	}
 	regs->ARM_ip = ip;
 
-	return current->ptrace_message;
+	return current_thread_info()->syscall;
 }
diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h
index f7cad13..def3b61 100644
--- a/arch/arm/kernel/ptrace.h
+++ b/arch/arm/kernel/ptrace.h
@@ -7,6 +7,45 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/ptrace.h>
+
 extern void ptrace_cancel_bpt(struct task_struct *);
 extern void ptrace_set_bpt(struct task_struct *);
 extern void ptrace_break(struct task_struct *, struct pt_regs *);
+
+/*
+ * make sure single-step breakpoint is gone.
+ */
+static inline void single_step_disable(struct task_struct *task)
+{
+	task->ptrace &= ~PT_SINGLESTEP;
+	ptrace_cancel_bpt(task);
+}
+
+static inline void single_step_enable(struct task_struct *task)
+{
+	task->ptrace |= PT_SINGLESTEP;
+}
+
+/*
+ * Send SIGTRAP if we're single-stepping
+ */
+static inline void single_step_trap(struct task_struct *task)
+{
+	if (task->ptrace & PT_SINGLESTEP) {
+		ptrace_cancel_bpt(task);
+		send_sig(SIGTRAP, task, 1);
+	}
+}
+
+static inline void single_step_clear(struct task_struct *task)
+{
+	if (task->ptrace & PT_SINGLESTEP)
+		ptrace_cancel_bpt(task);
+}
+
+static inline void single_step_set(struct task_struct *task)
+{
+	if (task->ptrace & PT_SINGLESTEP)
+		ptrace_set_bpt(task);
+}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 3843d3b..54cdf1a 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -9,7 +9,6 @@
  */
 #include <linux/errno.h>
 #include <linux/signal.h>
-#include <linux/ptrace.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
 
@@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_r
 	if (restore_sigframe(regs, frame))
 		goto badframe;
 
-	/* Send SIGTRAP if we're single-stepping */
-	if (current->ptrace & PT_SINGLESTEP) {
-		ptrace_cancel_bpt(current);
-		send_sig(SIGTRAP, current, 1);
-	}
+	single_step_trap(current);
 
 	return regs->ARM_r0;
 
@@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct p
 	if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
 		goto badframe;
 
-	/* Send SIGTRAP if we're single-stepping */
-	if (current->ptrace & PT_SINGLESTEP) {
-		ptrace_cancel_bpt(current);
-		send_sig(SIGTRAP, current, 1);
-	}
+	single_step_trap(current);
 
 	return regs->ARM_r0;
 
@@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, s
 	if (try_to_freeze())
 		goto no_signal;
 
-	if (current->ptrace & PT_SINGLESTEP)
-		ptrace_cancel_bpt(current);
+	single_step_clear(current);
 
 	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
 	if (signr > 0) {
 		handle_signal(signr, &ka, &info, oldset, regs, syscall);
-		if (current->ptrace & PT_SINGLESTEP)
-			ptrace_set_bpt(current);
+		single_step_set(current);
 		return 1;
 	}
 
@@ -705,8 +694,7 @@ #endif
 			restart_syscall(regs);
 		}
 	}
-	if (current->ptrace & PT_SINGLESTEP)
-		ptrace_set_bpt(current);
+	single_step_set(current);
 	return 0;
 }
 
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
new file mode 100644
index 0000000..77ef35e
--- /dev/null
+++ b/arch/arm/kernel/stacktrace.c
@@ -0,0 +1,73 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+
+#include "stacktrace.h"
+
+int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
+		    int (*fn)(struct stackframe *, void *), void *data)
+{
+	struct stackframe *frame;
+
+	do {
+		/*
+		 * Check current frame pointer is within bounds
+		 */
+		if ((fp - 12) < low || fp + 4 >= high)
+			break;
+
+		frame = (struct stackframe *)(fp - 12);
+
+		if (fn(frame, data))
+			break;
+
+		/*
+		 * Update the low bound - the next frame must always
+		 * be at a higher address than the current frame.
+		 */
+		low = fp + 4;
+		fp = frame->fp;
+	} while (fp);
+
+	return 0;
+}
+
+#ifdef CONFIG_STACKTRACE
+struct stack_trace_data {
+	struct stack_trace *trace;
+	unsigned int skip;
+};
+
+static int save_trace(struct stackframe *frame, void *d)
+{
+	struct stack_trace_data *data = d;
+	struct stack_trace *trace = data->trace;
+
+	if (data->skip) {
+		data->skip--;
+		return 0;
+	}
+
+	trace->entries[trace->nr_entries++] = frame->lr;
+
+	return trace->nr_entries >= trace->max_entries;
+}
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+	struct stack_trace_data data;
+	unsigned long fp, base;
+
+	data.trace = trace;
+	data.skip = trace->skip;
+
+	if (task) {
+		base = (unsigned long)task_stack_page(task);
+		fp = 0; /* FIXME */
+	} else {
+		base = (unsigned long)task_stack_page(current);
+		asm("mov %0, fp" : "=r" (fp));
+	}
+
+	walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
+}
+#endif
diff --git a/arch/arm/kernel/stacktrace.h b/arch/arm/kernel/stacktrace.h
new file mode 100644
index 0000000..e9fd20c
--- /dev/null
+++ b/arch/arm/kernel/stacktrace.h
@@ -0,0 +1,9 @@
+struct stackframe {
+	unsigned long fp;
+	unsigned long sp;
+	unsigned long lr;
+	unsigned long pc;
+};
+
+int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
+		    int (*fn)(struct stackframe *, void *), void *data);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index f61decb..d0540e4 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -327,6 +327,7 @@ void restore_time_delta(struct timespec 
 }
 EXPORT_SYMBOL(restore_time_delta);
 
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * Kernel system timer support.
  */
@@ -340,8 +341,9 @@ #ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
 #endif
 }
+#endif
 
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
 static int timer_suspend(struct sys_device *dev, pm_message_t state)
 {
 	struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2409560..10ff36e 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -16,7 +16,6 @@ #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/spinlock.h>
 #include <linux/personality.h>
-#include <linux/ptrace.h>
 #include <linux/kallsyms.h>
 #include <linux/delay.h>
 #include <linux/init.h>
@@ -45,7 +44,18 @@ static int __init user_debug_setup(char 
 __setup("user_debug=", user_debug_setup);
 #endif
 
-void dump_backtrace_entry(unsigned long where, unsigned long from)
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
+
+static inline int in_exception_text(unsigned long ptr)
+{
+	extern char __exception_text_start[];
+	extern char __exception_text_end[];
+
+	return ptr >= (unsigned long)&__exception_text_start &&
+	       ptr < (unsigned long)&__exception_text_end;
+}
+
+void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
 {
 #ifdef CONFIG_KALLSYMS
 	printk("[<%08lx>] ", where);
@@ -55,6 +65,9 @@ #ifdef CONFIG_KALLSYMS
 #else
 	printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
 #endif
+
+	if (in_exception_text(where))
+		dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
 }
 
 /*
@@ -232,8 +245,8 @@ NORET_TYPE void die(const char *str, str
 	do_exit(SIGSEGV);
 }
 
-void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
-		unsigned long err, unsigned long trap)
+void arm_notify_die(const char *str, struct pt_regs *regs,
+		struct siginfo *info, unsigned long err, unsigned long trap)
 {
 	if (user_mode(regs)) {
 		current->thread.error_code = err;
@@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_
 	spin_unlock_irqrestore(&undef_lock, flags);
 }
 
-asmlinkage void do_undefinstr(struct pt_regs *regs)
+asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
 	unsigned int correction = thumb_mode(regs) ? 2 : 4;
 	unsigned int instr;
 	struct undef_hook *hook;
 	siginfo_t info;
 	void __user *pc;
+	unsigned long flags;
 
 	/*
 	 * According to the ARM ARM, PC is 2 or 4 bytes ahead,
@@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_
 		get_user(instr, (u32 __user *)pc);
 	}
 
-	spin_lock_irq(&undef_lock);
+	spin_lock_irqsave(&undef_lock, flags);
 	list_for_each_entry(hook, &undef_hook, node) {
 		if ((instr & hook->instr_mask) == hook->instr_val &&
 		    (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
@@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_
 			}
 		}
 	}
-	spin_unlock_irq(&undef_lock);
+	spin_unlock_irqrestore(&undef_lock, flags);
 
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_UNDEFINED) {
@@ -316,7 +330,7 @@ #endif
 	info.si_code  = ILL_ILLOPC;
 	info.si_addr  = pc;
 
-	notify_die("Oops - undefined instruction", regs, &info, 0, 6);
+	arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
 }
 
 asmlinkage void do_unexp_fiq (struct pt_regs *regs)
@@ -370,7 +384,7 @@ #endif
 	info.si_addr  = (void __user *)instruction_pointer(regs) -
 			 (thumb_mode(regs) ? 2 : 4);
 
-	notify_die("Oops - bad syscall", regs, &info, n, 0);
+	arm_notify_die("Oops - bad syscall", regs, &info, n, 0);
 
 	return regs->ARM_r0;
 }
@@ -414,7 +428,7 @@ asmlinkage int arm_syscall(int no, struc
 		info.si_code  = SEGV_MAPERR;
 		info.si_addr  = NULL;
 
-		notify_die("branch through zero", regs, &info, 0, 0);
+		arm_notify_die("branch through zero", regs, &info, 0, 0);
 		return 0;
 
 	case NR(breakpoint): /* SWI BREAK_POINT */
@@ -550,7 +564,7 @@ #endif
 	info.si_addr  = (void __user *)instruction_pointer(regs) -
 			 (thumb_mode(regs) ? 2 : 4);
 
-	notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
+	arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
 	return 0;
 }
 
@@ -624,7 +638,7 @@ #endif
 	info.si_code  = ILL_ILLOPC;
 	info.si_addr  = (void __user *)addr;
 
-	notify_die("unknown data abort code", regs, &info, instr, 0);
+	arm_notify_die("unknown data abort code", regs, &info, instr, 0);
 }
 
 void __attribute__((noreturn)) __bug(const char *file, int line)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ddbdad4..6be6729 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -59,7 +59,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
 			usr/built-in.o(.init.ramfs)
 		__initramfs_end = .;
 #endif
-		. = ALIGN(64);
+		. = ALIGN(4096);
 		__per_cpu_start = .;
 			*(.data.percpu)
 		__per_cpu_end = .;
@@ -83,6 +83,9 @@ #endif
 
 	.text : {			/* Real text segment		*/
 		_text = .;		/* Text and read-only data	*/
+			__exception_text_start = .;
+			*(.exception.text)
+			__exception_text_end = .;
 			*(.text)
 			SCHED_TEXT
 			LOCK_TEXT
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index 7423008..84dc890 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -17,8 +17,8 @@ #include <asm/assembler.h>
 @ fp is 0 or stack frame
 
 #define frame	r4
-#define next	r5
-#define save	r6
+#define sv_fp	r5
+#define sv_pc	r6
 #define mask	r7
 #define offset	r8
 
@@ -31,108 +31,106 @@ ENTRY(c_backtrace)
 #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
 		mov	pc, lr
 #else
-
 		stmfd	sp!, {r4 - r8, lr}	@ Save an extra register so we have a location...
-		tst	r1, #0x10		@ 26 or 32-bit?
-		moveq	mask, #0xfc000003
-		movne	mask, #0
-		tst	mask, r0
-		movne	r0, #0
-		movs	frame, r0
-1:		moveq	r0, #-2
-		ldmeqfd	sp!, {r4 - r8, pc}
-
-2:		stmfd	sp!, {pc}		@ calculate offset of PC in STMIA instruction
-		ldr	r0, [sp], #4
-		adr	r1, 2b - 4
+		movs	frame, r0		@ if frame pointer is zero
+		beq	no_frame		@ we have no stack frames
+
+		tst	r1, #0x10		@ 26 or 32-bit mode?
+		moveq	mask, #0xfc000003	@ mask for 26-bit
+		movne	mask, #0		@ mask for 32-bit
+
+1:		stmfd	sp!, {pc}		@ calculate offset of PC stored
+		ldr	r0, [sp], #4		@ by stmfd for this CPU
+		adr	r1, 1b
 		sub	offset, r0, r1
 
-3:		tst	frame, mask		@ Check for address exceptions...
-		bne	1b
+/*
+ * Stack frame layout:
+ *             optionally saved caller registers (r4 - r10)
+ *             saved fp
+ *             saved sp
+ *             saved lr
+ *    frame => saved pc
+ *             optionally saved arguments (r0 - r3)
+ * saved sp => <next word>
+ *
+ * Functions start with the following code sequence:
+ *                  mov   ip, sp
+ *                  stmfd sp!, {r0 - r3} (optional)
+ * corrected pc =>  stmfd sp!, {..., fp, ip, lr, pc}
+ */
+for_each_frame:	tst	frame, mask		@ Check for address exceptions
+		bne	no_frame
+
+1001:		ldr	sv_pc, [frame, #0]	@ get saved pc
+1002:		ldr	sv_fp, [frame, #-12]	@ get saved fp
 
-1001:		ldr	next, [frame, #-12]	@ get fp
-1002:		ldr	r2, [frame, #-4]	@ get lr
-1003:		ldr	r3, [frame, #0]		@ get pc
-		sub	save, r3, offset	@ Correct PC for prefetching
-		bic	save, save, mask
-1004:		ldr	r1, [save, #0]		@ get instruction at function
-		mov	r1, r1, lsr #10
-		ldr	r3, .Ldsi+4
-		teq	r1, r3
-		subeq	save, save, #4
-		mov	r0, save
-		bic	r1, r2, mask
+		sub	sv_pc, sv_pc, offset	@ Correct PC for prefetching
+		bic	sv_pc, sv_pc, mask	@ mask PC/LR for the mode
+
+1003:		ldr	r2, [sv_pc, #-4]	@ if stmfd sp!, {args} exists,
+		ldr	r3, .Ldsi+4		@ adjust saved 'pc' back one
+		teq	r3, r2, lsr #10		@ instruction
+		subne	r0, sv_pc, #4		@ allow for mov
+		subeq	r0, sv_pc, #8		@ allow for mov + stmia
+
+		ldr	r1, [frame, #-4]	@ get saved lr
+		mov	r2, frame
+		bic	r1, r1, mask		@ mask PC/LR for the mode
 		bl	dump_backtrace_entry
 
-		ldr	r0, [frame, #-8]	@ get sp
-		sub	r0, r0, #4
-1005:		ldr	r1, [save, #4]		@ get instruction at function+4
-		mov	r3, r1, lsr #10
-		ldr	r2, .Ldsi+4
-		teq	r3, r2			@ Check for stmia sp!, {args}
-		addeq	save, save, #4		@ next instruction
-		bleq	.Ldumpstm
-
-		sub	r0, frame, #16
-1006:		ldr	r1, [save, #4]		@ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
-		mov	r3, r1, lsr #10
-		ldr	r2, .Ldsi
-		teq	r3, r2
-		bleq	.Ldumpstm
-
-		/*
-		 * A zero next framepointer means we're done.
-		 */
-		teq	next, #0
-		ldmeqfd	sp!, {r4 - r8, pc}
-
-		/*
-		 * The next framepointer must be above the
-		 * current framepointer.
-		 */
-		cmp	next, frame
-		mov	frame, next
-		bhi	3b
-		b	1007f
+		ldr	r1, [sv_pc, #-4]	@ if stmfd sp!, {args} exists,
+		ldr	r3, .Ldsi+4
+		teq	r3, r1, lsr #10
+		ldreq	r0, [frame, #-8]	@ get sp
+		subeq	r0, r0, #4		@ point at the last arg
+		bleq	.Ldumpstm		@ dump saved registers
 
-/*
- * Fixup for LDMDB.  Note that this must not be in the fixup section.
- */
-1007:		ldr	r0, =.Lbad
+1004:		ldr	r1, [sv_pc, #0]		@ if stmfd sp!, {..., fp, ip, lr, pc}
+		ldr	r3, .Ldsi		@ instruction exists,
+		teq	r3, r1, lsr #10
+		subeq	r0, frame, #16
+		bleq	.Ldumpstm		@ dump saved registers
+
+		teq	sv_fp, #0		@ zero saved fp means
+		beq	no_frame		@ no further frames
+
+		cmp	sv_fp, frame		@ next frame must be
+		mov	frame, sv_fp		@ above the current frame
+		bhi	for_each_frame
+
+1006:		adr	r0, .Lbad
 		mov	r1, frame
 		bl	printk
-		ldmfd	sp!, {r4 - r8, pc}
-		.ltorg
+no_frame:	ldmfd	sp!, {r4 - r8, pc}
 		
 		.section __ex_table,"a"
 		.align	3
-		.long	1001b, 1007b
-		.long	1002b, 1007b
-		.long	1003b, 1007b
-		.long	1004b, 1007b
-		.long	1005b, 1007b
-		.long	1006b, 1007b
+		.long	1001b, 1006b
+		.long	1002b, 1006b
+		.long	1003b, 1006b
+		.long	1004b, 1006b
 		.previous
 
 #define instr r4
 #define reg   r5
 #define stack r6
 
-.Ldumpstm:	stmfd	sp!, {instr, reg, stack, r7, r8, lr}
+.Ldumpstm:	stmfd	sp!, {instr, reg, stack, r7, lr}
 		mov	stack, r0
 		mov	instr, r1
-		mov	reg, #9
+		mov	reg, #10
 		mov	r7, #0
 1:		mov	r3, #1
 		tst	instr, r3, lsl reg
 		beq	2f
 		add	r7, r7, #1
-		teq	r7, #4
-		moveq	r7, #0
-		moveq	r3, #'\n'
-		movne	r3, #' '
-		ldr	r2, [stack], #-4
-		mov	r1, reg
+		teq	r7, #6
+		moveq	r7, #1
+		moveq	r1, #'\n'
+		movne	r1, #' '
+		ldr	r3, [stack], #-4
+		mov	r2, reg
 		adr	r0, .Lfp
 		bl	printk
 2:		subs	reg, reg, #1
@@ -140,14 +138,13 @@ #define stack r6
 		teq	r7, #0
 		adrne	r0, .Lcr
 		blne	printk
-		mov	r0, stack
-		ldmfd	sp!, {instr, reg, stack, r7, r8, pc}
+		ldmfd	sp!, {instr, reg, stack, r7, pc}
 
-.Lfp:		.asciz	" r%d = %08X%c"
+.Lfp:		.asciz	"%cr%d:%08x"
 .Lcr:		.asciz	"\n"
 .Lbad:		.asciz	"Backtrace aborted due to bad frame pointer <%p>\n"
 		.align
-.Ldsi:		.word	0x00e92dd8 >> 2
-		.word	0x00e92d00 >> 2
+.Ldsi:		.word	0xe92dd800 >> 10	@ stmfd sp!, {... fp, ip, lr, pc}
+		.word	0xe92d0000 >> 10	@ stmfd sp!, {}
 
 #endif
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index c03ea8e..1dd8ea4 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -26,8 +26,6 @@
  * Note that ADDR_LIMIT is either 0 or 0xc0000000.
  * Note also that it is intended that __get_user_bad is not global.
  */
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
 #include <asm/errno.h>
 
 	.global	__get_user_1
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 4593e9c..8620afe 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -26,8 +26,6 @@
  * Note that ADDR_LIMIT is either 0 or 0xc0000000
  * Note also that it is intended that __put_user_bad is not global.
  */
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
 #include <asm/errno.h>
 
 	.global	__put_user_1
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index a950160..0446ef2 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -142,7 +142,7 @@ aaec2000_timer_interrupt(int irq, void *
 
 static struct irqaction aaec2000_timer_irq = {
 	.name		= "AAEC-2000 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= aaec2000_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index bf0d962..e238ad8 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -81,6 +81,13 @@ config MACH_KB9200
 	  Select this if you are using KwikByte's KB920x board.
 	  <http://kwikbyte.com/KB9202_description_new.htm>
 
+config MACH_PICOTUX2XX
+	bool "picotux 200"
+	depends on ARCH_AT91RM9200
+	help
+	  Select this if you are using a picotux 200.
+	  <http://www.picotux.com/>
+
 config MACH_KAFA
 	bool "Sperry-Sun KAFA board"
 	depends on ARCH_AT91RM9200
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 05de6cd..a412ae1 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_MACH_CARMEVA)	+= board-carm
 obj-$(CONFIG_MACH_KB9200)	+= board-kb9202.o
 obj-$(CONFIG_MACH_ATEB9200)	+= board-eb9200.o
 obj-$(CONFIG_MACH_KAFA)		+= board-kafa.o
+obj-$(CONFIG_MACH_PICOTUX2XX)	+= board-picotux200.o
 
 # AT91SAM9260 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 2ddcdd6..2cad2bf 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -117,6 +117,21 @@ static struct clk pioD_clk = {
 	.pmc_mask	= 1 << AT91RM9200_ID_PIOD,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc0_clk = {
+	.name		= "ssc0_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_SSC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc2_clk = {
+	.name		= "ssc2_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_SSC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk tc0_clk = {
 	.name		= "tc0_clk",
 	.pmc_mask	= 1 << AT91RM9200_ID_TC0,
@@ -161,7 +176,9 @@ static struct clk *periph_clocks[] __ini
 	&udc_clk,
 	&twi_clk,
 	&spi_clk,
-	// ssc 0 .. ssc2
+	&ssc0_clk,
+	&ssc1_clk,
+	&ssc2_clk,
 	&tc0_clk,
 	&tc1_clk,
 	&tc2_clk,
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index 949199a..a634035 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -87,7 +87,7 @@ static irqreturn_t at91rm9200_timer_inte
 
 static struct irqaction at91rm9200_timer_irq = {
 	.name		= "at91_tick",
-	.flags		= IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= at91rm9200_timer_interrupt
 };
 
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 6ea41d8..e47381e 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -119,6 +119,11 @@ static struct clk spi1_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_SPI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc_clk = {
+	.name		= "ssc_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_SSC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk tc0_clk = {
 	.name		= "tc0_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_TC0,
@@ -193,7 +198,7 @@ static struct clk *periph_clocks[] __ini
 	&twi_clk,
 	&spi0_clk,
 	&spi1_clk,
-	// ssc
+	&ssc_clk,
 	&tc0_clk,
 	&tc1_clk,
 	&tc2_clk,
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 784d1e6..dfe8c39 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -97,6 +97,21 @@ static struct clk spi1_clk = {
 	.pmc_mask	= 1 << AT91SAM9261_ID_SPI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc0_clk = {
+	.name		= "ssc0_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_SSC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc2_clk = {
+	.name		= "ssc2_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_SSC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk tc0_clk = {
 	.name		= "tc0_clk",
 	.pmc_mask	= 1 << AT91SAM9261_ID_TC0,
@@ -135,7 +150,9 @@ static struct clk *periph_clocks[] __ini
 	&twi_clk,
 	&spi0_clk,
 	&spi1_clk,
-	// ssc 0 .. ssc2
+	&ssc0_clk,
+	&ssc1_clk,
+	&ssc2_clk,
 	&tc0_clk,
 	&tc1_clk,
 	&tc2_clk,
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index e150476..8e78199 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -430,9 +430,9 @@ #endif
  *  LCD Controller
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_FB_AT91) || defined(CONFIG_FB_AT91_MODULE)
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = 0xffffffffUL;
-static struct at91fb_info lcdc_data;
+static struct atmel_lcdfb_info lcdc_data;
 
 static struct resource lcdc_resources[] = {
 	[0] = {
@@ -455,7 +455,7 @@ #endif
 };
 
 static struct platform_device at91_lcdc_device = {
-	.name		= "at91-fb",
+	.name		= "atmel_lcdfb",
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &lcdc_dmamask,
@@ -466,7 +466,7 @@ static struct platform_device at91_lcdc_
 	.num_resources	= ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct at91fb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
 {
 	if (!data) {
 		return;
@@ -499,7 +499,7 @@ void __init at91_add_device_lcdc(struct 
 	platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct at91fb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
 #endif
 
 
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 0e89a7f..00e27b1 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -87,6 +87,11 @@ static struct clk mmc1_clk = {
 	.pmc_mask	= 1 << AT91SAM9263_ID_MCI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk can_clk = {
+	.name		= "can_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_CAN,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk twi_clk = {
 	.name		= "twi_clk",
 	.pmc_mask	= 1 << AT91SAM9263_ID_TWI,
@@ -102,16 +107,46 @@ static struct clk spi1_clk = {
 	.pmc_mask	= 1 << AT91SAM9263_ID_SPI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc0_clk = {
+	.name		= "ssc0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SSC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+	.name		= "ac97_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_AC97C,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk tcb_clk = {
 	.name		= "tcb_clk",
 	.pmc_mask	= 1 << AT91SAM9263_ID_TCB,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk pwmc_clk = {
+	.name		= "pwmc_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PWMC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk macb_clk = {
 	.name		= "macb_clk",
 	.pmc_mask	= 1 << AT91SAM9263_ID_EMAC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk dma_clk = {
+	.name		= "dma_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_DMA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twodge_clk = {
+	.name		= "2dge_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_2DGE,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk udc_clk = {
 	.name		= "udc_clk",
 	.pmc_mask	= 1 << AT91SAM9263_ID_UDP,
@@ -142,20 +177,21 @@ static struct clk *periph_clocks[] __ini
 	&usart2_clk,
 	&mmc0_clk,
 	&mmc1_clk,
-	// can
+	&can_clk,
 	&twi_clk,
 	&spi0_clk,
 	&spi1_clk,
-	// ssc0 .. ssc1
-	// ac97
+	&ssc0_clk,
+	&ssc1_clk,
+	&ac97_clk,
 	&tcb_clk,
-	// pwmc
+	&pwmc_clk,
 	&macb_clk,
-	// 2dge
+	&twodge_clk,
 	&udc_clk,
 	&isi_clk,
 	&lcdc_clk,
-	// dma
+	&dma_clk,
 	&ohci_clk,
 	// irq0 .. irq1
 };
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index b77121f..2b2e18a 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -573,6 +573,130 @@ #endif
 
 
 /* --------------------------------------------------------------------
+ *  AC97
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
+static u64 ac97_dmamask = 0xffffffffUL;
+static struct atmel_ac97_data ac97_data;
+
+static struct resource ac97_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_AC97C,
+		.end	= AT91SAM9263_BASE_AC97C + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_AC97C,
+		.end	= AT91SAM9263_ID_AC97C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_ac97_device = {
+	.name		= "ac97c",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &ac97_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &ac97_data,
+	},
+	.resource	= ac97_resources,
+	.num_resources	= ARRAY_SIZE(ac97_resources),
+};
+
+void __init at91_add_device_ac97(struct atmel_ac97_data *data)
+{
+	if (!data)
+		return;
+
+	at91_set_A_periph(AT91_PIN_PB0, 0);	/* AC97FS */
+	at91_set_A_periph(AT91_PIN_PB1, 0);	/* AC97CK */
+	at91_set_A_periph(AT91_PIN_PB2, 0);	/* AC97TX */
+	at91_set_A_periph(AT91_PIN_PB3, 0);	/* AC97RX */
+
+	/* reset */
+	if (data->reset_pin)
+		at91_set_gpio_output(data->reset_pin, 0);
+
+	ac97_data = *ek_data;
+	platform_device_register(&at91sam9263_ac97_device);
+}
+#else
+void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = 0xffffffffUL;
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_LCDC_BASE,
+		.end	= AT91SAM9263_LCDC_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_LCDC,
+		.end	= AT91SAM9263_ID_LCDC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_lcdc_device = {
+	.name		= "atmel_lcdfb",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &lcdc_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &lcdc_data,
+	},
+	.resource	= lcdc_resources,
+	.num_resources	= ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	if (!data)
+		return;
+
+	at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
+	at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
+	at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
+	at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
+	at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
+	at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
+	at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
+	at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
+	at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
+	at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
+	at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
+	at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
+	at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
+	at91_set_B_periph(AT91_PIN_PC12, 0);	/* LCDD13 */
+	at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
+	at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
+	at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
+	at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
+	at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
+	at91_set_B_periph(AT91_PIN_PC17, 0);	/* LCDD21 */
+	at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
+	at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
+
+	lcdc_data = *data;
+	platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
  *  LEDs
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index a4dded2..5c090c9 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -66,7 +66,7 @@ static irqreturn_t at91sam926x_timer_int
 
 static struct irqaction at91sam926x_timer_irq = {
 	.name		= "at91_tick",
-	.flags		= IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= at91sam926x_timer_interrupt
 };
 
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
new file mode 100644
index 0000000..49cfe7a
--- /dev/null
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -0,0 +1,166 @@
+/*
+ * linux/arch/arm/mach-at91/board-picotux200.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2007 Kleinhenz Elektronik 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91rm9200_mc.h>
+
+#include "generic.h"
+
+
+/*
+ * Serial port configuration.
+ *    0 .. 3 = USART0 .. USART3
+ *    4      = DBGU
+ */
+static struct at91_uart_config __initdata picotux200_uart_config = {
+	.console_tty	= 0,				/* ttyS0 */
+	.nr_tty		= 2,
+	.tty_map	= { 4, 1, -1, -1, -1 }		/* ttyS0, ..., ttyS4 */
+};
+
+static void __init picotux200_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+	/* Setup the serial ports and console */
+	at91_init_serial(&picotux200_uart_config);
+}
+
+static void __init picotux200_init_irq(void)
+{
+	at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata picotux200_eth_data = {
+	.phy_irq_pin	= AT91_PIN_PC4,
+	.is_rmii	= 1,
+};
+
+static struct at91_usbh_data __initdata picotux200_usbh_data = {
+	.ports		= 1,
+};
+
+// static struct at91_udc_data __initdata picotux200_udc_data = {
+// 	.vbus_pin	= AT91_PIN_PD4,
+// 	.pullup_pin	= AT91_PIN_PD5,
+// };
+
+static struct at91_mmc_data __initdata picotux200_mmc_data = {
+	.det_pin	= AT91_PIN_PB27,
+	.slot_b		= 0,
+	.wire4		= 1,
+	.wp_pin		= AT91_PIN_PA17,
+};
+
+// static struct spi_board_info picotux200_spi_devices[] = {
+// 	{	/* DataFlash chip */
+// 		.modalias	= "mtd_dataflash",
+// 		.chip_select	= 0,
+// 		.max_speed_hz	= 15 * 1000 * 1000,
+// 	},
+// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+// 	{	/* DataFlash card */
+// 		.modalias	= "mtd_dataflash",
+// 		.chip_select	= 3,
+// 		.max_speed_hz	= 15 * 1000 * 1000,
+// 	},
+// #endif
+// };
+
+#define PICOTUX200_FLASH_BASE	AT91_CHIPSELECT_0
+#define PICOTUX200_FLASH_SIZE	0x400000
+
+static struct physmap_flash_data picotux200_flash_data = {
+	.width	= 2,
+};
+
+static struct resource picotux200_flash_resource = {
+	.start		= PICOTUX200_FLASH_BASE,
+	.end		= PICOTUX200_FLASH_BASE + PICOTUX200_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device picotux200_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data	= &picotux200_flash_data,
+			},
+	.resource	= &picotux200_flash_resource,
+	.num_resources	= 1,
+};
+
+static void __init picotux200_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* Ethernet */
+	at91_add_device_eth(&picotux200_eth_data);
+	/* USB Host */
+	at91_add_device_usbh(&picotux200_usbh_data);
+	/* USB Device */
+	// at91_add_device_udc(&picotux200_udc_data);
+	// at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
+	/* I2C */
+	at91_add_device_i2c();
+	/* SPI */
+	// at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	/* DataFlash card */
+	at91_set_gpio_output(AT91_PIN_PB22, 0);
+#else
+	/* MMC */
+	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
+	at91_add_device_mmc(0, &picotux200_mmc_data);
+#endif
+	/* NOR Flash */
+	platform_device_register(&picotux200_flash);
+}
+
+MACHINE_START(PICOTUX2XX, "picotux 200")
+	/* Maintainer: Kleinhenz Elektronik GmbH */
+	.phys_io	= AT91_BASE_SYS,
+	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91rm9200_timer,
+	.map_io		= picotux200_map_io,
+	.init_irq	= picotux200_init_irq,
+	.init_machine	= picotux200_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index 57fb449..65fa532 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -104,9 +104,9 @@ #if defined(CONFIG_MTD_AT91_DATAFLASH_CA
 	},
 #endif
 #endif
-#if defined(CONFIG_SND_AT73C213)
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
 	{	/* AT73C213 DAC */
-		.modalias	= "snd_at73c213",
+		.modalias	= "at73c213",
 		.chip_select	= 0,
 		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 1,
@@ -118,7 +118,7 @@ #endif
 /*
  * MACB Ethernet device
  */
-static struct __initdata at91_eth_data ek_macb_data = {
+static struct at91_eth_data __initdata ek_macb_data = {
 	.phy_irq_pin	= AT91_PIN_PA7,
 	.is_rmii	= 1,
 };
@@ -140,7 +140,7 @@ static struct mtd_partition __initdata e
 	},
 };
 
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
 {
 	*num_partitions = ARRAY_SIZE(ek_nand_partition);
 	return ek_nand_partition;
@@ -188,6 +188,8 @@ static void __init ek_board_init(void)
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
+	/* I2C */
+	at91_add_device_i2c();
 }
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index b7e7724..bcf7153 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -25,6 +25,7 @@ #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 #include <linux/dm9000.h>
 
 #include <asm/hardware.h>
@@ -195,6 +196,41 @@ #endif
 };
 
 /*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+static int ads7843_pendown_state(void)
+{
+	return !at91_get_gpio_value(AT91_PIN_PC2);	/* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model			= 7843,
+	.x_min			= 150,
+	.x_max			= 3830,
+	.y_min			= 190,
+	.y_max			= 3830,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 450,
+	.y_plate_ohms		= 250,
+	.pressure_max		= 15000,
+	.debounce_max		= 1,
+	.debounce_rep		= 0,
+	.debounce_tol		= (~0),
+	.get_pendown_state	= ads7843_pendown_state,
+};
+
+static void __init ek_add_device_ts(void)
+{
+	at91_set_B_periph(AT91_PIN_PC2, 1);	/* External IRQ0, with pullup */
+	at91_set_gpio_input(AT91_PIN_PA11, 1);	/* Touchscreen BUSY signal */
+}
+#else
+static void __init ek_add_device_ts(void) {}
+#endif
+
+/*
  * SPI devices
  */
 static struct spi_board_info ek_spi_devices[] = {
@@ -204,6 +240,16 @@ static struct spi_board_info ek_spi_devi
 		.max_speed_hz	= 15 * 1000 * 1000,
 		.bus_num	= 0,
 	},
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias	= "ads7846",
+		.chip_select	= 2,
+		.max_speed_hz	= 125000 * 26,	/* (max sample rate @ 3V) * (cmd + data + overhead) */
+		.bus_num	= 0,
+		.platform_data	= &ads_info,
+		.irq		= AT91SAM9261_ID_IRQ0,
+	},
+#endif
 #if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
 	{	/* DataFlash card - jumper (J12) configurable to CS3 or CS0 */
 		.modalias	= "mtd_dataflash",
@@ -211,9 +257,9 @@ #if defined(CONFIG_MTD_AT91_DATAFLASH_CA
 		.max_speed_hz	= 15 * 1000 * 1000,
 		.bus_num	= 0,
 	},
-#elif defined(CONFIG_SND_AT73C213)
+#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
 	{	/* AT73C213 DAC */
-		.modalias	= "snd_at73c213",
+		.modalias	= "at73c213",
 		.chip_select	= 3,
 		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 0,
@@ -241,6 +287,8 @@ static void __init ek_board_init(void)
 #if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
 	/* SPI */
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+	/* Touchscreen */
+	ek_add_device_ts();
 #else
 	/* MMC */
 	at91_add_device_mmc(0, &ek_mmc_data);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 8fdce11..f574585 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -25,6 +25,7 @@ #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -86,6 +87,40 @@ static struct at91_udc_data __initdata e
 
 
 /*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static int ads7843_pendown_state(void)
+{
+	return !at91_get_gpio_value(AT91_PIN_PA15);	/* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model			= 7843,
+	.x_min			= 150,
+	.x_max			= 3830,
+	.y_min			= 190,
+	.y_max			= 3830,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 450,
+	.y_plate_ohms		= 250,
+	.pressure_max		= 15000,
+	.debounce_max		= 1,
+	.debounce_rep		= 0,
+	.debounce_tol		= (~0),
+	.get_pendown_state	= ads7843_pendown_state,
+};
+
+static void __init ek_add_device_ts(void)
+{
+	at91_set_B_periph(AT91_PIN_PA15, 1);	/* External IRQ1, with pullup */
+	at91_set_gpio_input(AT91_PIN_PA31, 1);	/* Touchscreen BUSY signal */
+}
+#else
+static void __init ek_add_device_ts(void) {}
+#endif
+
+/*
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
@@ -97,6 +132,16 @@ #if defined(CONFIG_MTD_AT91_DATAFLASH_CA
 		.bus_num	= 0,
 	},
 #endif
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias	= "ads7846",
+		.chip_select	= 3,
+		.max_speed_hz	= 125000 * 26,	/* (max sample rate @ 3V) * (cmd + data + overhead) */
+		.bus_num	= 0,
+		.platform_data	= &ads_info,
+		.irq		= AT91SAM9263_ID_IRQ1,
+	},
+#endif
 };
 
 
@@ -112,6 +157,14 @@ static struct at91_mmc_data __initdata e
 
 
 /*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata ek_macb_data = {
+	.is_rmii	= 1,
+};
+
+
+/*
  * NAND flash
  */
 static struct mtd_partition __initdata ek_nand_partition[] = {
@@ -148,6 +201,14 @@ #endif
 };
 
 
+/*
+ * AC97
+ */
+static struct atmel_ac97_data ek_ac97_data = {
+	.reset_pin	= AT91_PIN_PA13,
+};
+
+
 static void __init ek_board_init(void)
 {
 	/* Serial */
@@ -157,11 +218,20 @@ static void __init ek_board_init(void)
 	/* USB Device */
 	at91_add_device_udc(&ek_udc_data);
 	/* SPI */
+	at91_set_gpio_output(AT91_PIN_PE20, 1);		/* select spi0 clock */
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+	/* Touchscreen */
+	ek_add_device_ts();
 	/* MMC */
 	at91_add_device_mmc(1, &ek_mmc_data);
+	/* Ethernet */
+	at91_add_device_eth(&ek_macb_data);
 	/* NAND */
 	at91_add_device_nand(&ek_nand_data);
+	/* I2C */
+	at91_add_device_i2c();
+	/* AC97 */
+	at91_add_device_ac97(&ek_ac97_data);
 }
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index b49bfda..ff8db29 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -201,7 +201,6 @@ error:
 
 
 static struct pm_ops at91_pm_ops ={
-	.pm_disk_mode	= 0,
 	.valid		= at91_pm_valid_state,
 	.prepare	= at91_pm_prepare,
 	.enter		= at91_pm_enter,
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index 428493d..f428af7 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -58,7 +58,7 @@ p720t_timer_interrupt(int irq, void *dev
 
 static struct irqaction clps711x_timer_irq = {
 	.name		= "CLPS711x Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= p720t_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 231b900..4dde34f 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -316,7 +316,7 @@ clps7500_timer_interrupt(int irq, void *
 
 static struct irqaction clps7500_timer_irq = {
 	.name		= "CLPS7500 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= clps7500_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 8459431..8c1b569 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -199,7 +199,7 @@ ebsa110_timer_interrupt(int irq, void *d
 
 static struct irqaction ebsa110_timer_irq = {
 	.name		= "EBSA110 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= ebsa110_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index db38afb..bbf0d33 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -102,6 +102,26 @@ EXPORT_SYMBOL(__readb);
 EXPORT_SYMBOL(__readw);
 EXPORT_SYMBOL(__readl);
 
+void readsw(void __iomem *addr, void *data, int len)
+{
+	void __iomem *a = __isamem_convert_addr(addr);
+
+	BUG_ON((unsigned long)addr & 1);
+
+	__raw_readsw(a, data, len);
+}
+EXPORT_SYMBOL(readsw);
+
+void readsl(void __iomem *addr, void *data, int len)
+{
+	void __iomem *a = __isamem_convert_addr(addr);
+
+	BUG_ON((unsigned long)addr & 3);
+
+	__raw_readsl(a, data, len);
+}
+EXPORT_SYMBOL(readsl);
+
 void __writeb(u8 val, void __iomem *addr)
 {
 	void __iomem *a = __isamem_convert_addr(addr);
@@ -137,6 +157,26 @@ EXPORT_SYMBOL(__writeb);
 EXPORT_SYMBOL(__writew);
 EXPORT_SYMBOL(__writel);
 
+void writesw(void __iomem *addr, void *data, int len)
+{
+	void __iomem *a = __isamem_convert_addr(addr);
+
+	BUG_ON((unsigned long)addr & 1);
+
+	__raw_writesw(a, data, len);
+}
+EXPORT_SYMBOL(writesw);
+
+void writesl(void __iomem *addr, void *data, int len)
+{
+	void __iomem *a = __isamem_convert_addr(addr);
+
+	BUG_ON((unsigned long)addr & 3);
+
+	__raw_writesl(a, data, len);
+}
+EXPORT_SYMBOL(writesl);
+
 #define SUPERIO_PORT(p) \
 	(((p) >> 3) == (0x3f8 >> 3) || \
 	 ((p) >> 3) == (0x2f8 >> 3) || \
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index f174d1a..9d7515c 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -27,6 +27,10 @@ struct clk {
 	u32		enable_mask;
 };
 
+static struct clk clk_uart = {
+	.name		= "UARTCLK",
+	.rate		= 14745600,
+};
 static struct clk clk_pll1 = {
 	.name		= "pll1",
 };
@@ -50,6 +54,7 @@ static struct clk clk_usb_host = {
 
 
 static struct clk *clocks[] = {
+	&clk_uart,
 	&clk_pll1,
 	&clk_f,
 	&clk_h,
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 829aed6..851cc71 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -116,7 +116,7 @@ static int ep93xx_timer_interrupt(int ir
 
 static struct irqaction ep93xx_timer_irq = {
 	.name		= "ep93xx timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= ep93xx_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index fa6be87..3a63941 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -44,7 +44,7 @@ timer1_interrupt(int irq, void *dev_id)
 static struct irqaction footbridge_timer_irq = {
 	.name		= "Timer1 timer tick",
 	.handler	= timer1_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
 /*
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 1463330..d0dc51e 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -10,7 +10,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index d884a39..d08d641 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -73,7 +73,7 @@ isa_timer_interrupt(int irq, void *dev_i
 static struct irqaction isa_timer_irq = {
 	.name		= "ISA timer tick",
 	.handler	= isa_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
 static void __init isa_timer_init(void)
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index 13f76bd..9107b8e 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -41,7 +41,7 @@ h7201_timer_interrupt(int irq, void *dev
 
 static struct irqaction h7201_timer_irq = {
 	.name		= "h7201 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= h7201_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 703870f..82e420d 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -170,7 +170,7 @@ static struct irq_chip h7202_timerx_chip
 
 static struct irqaction h7202_timer_irq = {
 	.name		= "h7202 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= h7202_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 2703a73..6960a9d 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -56,7 +56,7 @@ imx_timer_interrupt(int irq, void *dev_i
 
 static struct irqaction imx_timer_irq = {
 	.name		= "i.MX Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= imx_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 8d880cb..897c21c 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -282,7 +282,7 @@ #endif /* CONFIG_SMP */
 
 static struct irqaction integrator_timer_irq = {
 	.name		= "Integrator Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= integrator_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c
index 394ec92..af7d3ff 100644
--- a/arch/arm/mach-integrator/pci.c
+++ b/arch/arm/mach-integrator/pci.c
@@ -23,7 +23,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index fb8c6d9..af9ebcc 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -22,7 +22,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
diff --git a/arch/arm/mach-iop13xx/Makefile b/arch/arm/mach-iop13xx/Makefile
index 4185e05..da1609d 100644
--- a/arch/arm/mach-iop13xx/Makefile
+++ b/arch/arm/mach-iop13xx/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ARCH_IOP13XX) += setup.o
 obj-$(CONFIG_ARCH_IOP13XX) += irq.o
 obj-$(CONFIG_ARCH_IOP13XX) += pci.o
 obj-$(CONFIG_ARCH_IOP13XX) += io.o
+obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o
 obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o
 obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index e79a1b6..5b22fde 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -41,7 +41,7 @@ void * __iomem __iop13xx_io(unsigned lon
 EXPORT_SYMBOL(__iop13xx_io);
 
 void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
-	unsigned long flags)
+	unsigned int mtype)
 {
 	void __iomem * retval;
 
@@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigne
 			         (cookie - IOP13XX_PCIE_LOWER_MEM_RA));
 		break;
 	case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
-		retval = __ioremap(IOP13XX_PBI_LOWER_MEM_PA +
-				  (cookie - IOP13XX_PBI_LOWER_MEM_RA),
-				  size, flags);
+		retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA +
+				       (cookie - IOP13XX_PBI_LOWER_MEM_RA),
+				       size, mtype);
 		break;
 	case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
 		retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
@@ -75,7 +75,7 @@ void * __iomem __iop13xx_ioremap(unsigne
 		retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
 		break;
 	default:
-		retval = __ioremap(cookie, size, flags);
+		retval = __arm_ioremap(cookie, size, mtype);
 	}
 
 	return retval;
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index a519d70..268a8d8 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -75,11 +75,14 @@ static void __init iq81340mc_init(void)
 {
 	iop13xx_platform_init();
 	iq81340mc_pci_init();
+	iop13xx_add_tpmi_devices();
 }
 
 static void __init iq81340mc_timer_init(void)
 {
-	iop_init_time(400000000);
+	unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
+	printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
+	iop_init_time(bus_freq);
 }
 
 static struct sys_timer iq81340mc_timer = {
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index 0e71fbc..a51ffd2 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -77,11 +77,14 @@ static void __init iq81340sc_init(void)
 {
 	iop13xx_platform_init();
 	iq81340sc_pci_init();
+	iop13xx_add_tpmi_devices();
 }
 
 static void __init iq81340sc_timer_init(void)
 {
-	iop_init_time(400000000);
+	unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
+	printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
+	iop_init_time(bus_freq);
 }
 
 static struct sys_timer iq81340sc_timer = {
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 89ec70e..d1d0d32 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -88,9 +88,9 @@ void iop13xx_map_pci_memory(void)
 
 				if (end) {
 					iop13xx_atux_mem_base =
-					(u32) __ioremap_pfn(
+					(u32) __arm_ioremap_pfn(
 					__phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA)
-					, 0, iop13xx_atux_mem_size, 0);
+					, 0, iop13xx_atux_mem_size, MT_DEVICE);
 					if (!iop13xx_atux_mem_base) {
 						printk("%s: atux allocation "
 						       "failed\n", __FUNCTION__);
@@ -114,9 +114,9 @@ void iop13xx_map_pci_memory(void)
 
 				if (end) {
 					iop13xx_atue_mem_base =
-					(u32) __ioremap_pfn(
+					(u32) __arm_ioremap_pfn(
 					__phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA)
-					, 0, iop13xx_atue_mem_size, 0);
+					, 0, iop13xx_atue_mem_size, MT_DEVICE);
 					if (!iop13xx_atue_mem_base) {
 						printk("%s: atue allocation "
 						       "failed\n", __FUNCTION__);
@@ -1023,7 +1023,7 @@ int iop13xx_pci_setup(int nr, struct pci
 				  << IOP13XX_ATUX_PCIXSR_FUNC_NUM;
 		__raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
 
-		res[0].start = IOP13XX_PCIX_LOWER_IO_PA;
+		res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
 		res[0].end   = IOP13XX_PCIX_UPPER_IO_PA;
 		res[0].name  = "IQ81340 ATUX PCI I/O Space";
 		res[0].flags = IORESOURCE_IO;
@@ -1033,7 +1033,7 @@ int iop13xx_pci_setup(int nr, struct pci
 		res[1].name  = "IQ81340 ATUX PCI Memory Space";
 		res[1].flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIX_IO_OFFSET;
+		sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
 		break;
 	case IOP13XX_INIT_ATU_ATUE:
 		/* Note: the function number field in the PCSR is ro */
@@ -1044,7 +1044,7 @@ int iop13xx_pci_setup(int nr, struct pci
 
 		__raw_writel(pcsr, IOP13XX_ATUE_PCSR);
 
-		res[0].start = IOP13XX_PCIE_LOWER_IO_PA;
+		res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
 		res[0].end   = IOP13XX_PCIE_UPPER_IO_PA;
 		res[0].name  = "IQ81340 ATUE PCI I/O Space";
 		res[0].flags = IORESOURCE_IO;
@@ -1054,7 +1054,7 @@ int iop13xx_pci_setup(int nr, struct pci
 		res[1].name  = "IQ81340 ATUE PCI Memory Space";
 		res[1].flags = IORESOURCE_MEM;
 		sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
-		sys->io_offset = IOP13XX_PCIE_IO_OFFSET;
+		sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
 		sys->map_irq = iop13xx_pcie_map_irq;
 		break;
 	default:
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index 9a46bcd..bc48715 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -258,15 +258,11 @@ void __init iop13xx_platform_init(void)
 
 	if (init_uart == IOP13XX_INIT_UART_DEFAULT) {
 		switch (iop13xx_dev_id()) {
-		/* enable both uarts on iop341 and iop342 */
+		/* enable both uarts on iop341 */
 		case 0x3380:
 		case 0x3384:
 		case 0x3388:
 		case 0x338c:
-		case 0x3382:
-		case 0x3386:
-		case 0x338a:
-		case 0x338e:
 			init_uart |= IOP13XX_INIT_UART_0;
 			init_uart |= IOP13XX_INIT_UART_1;
 			break;
diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c
new file mode 100644
index 0000000..d3dc278
--- /dev/null
+++ b/arch/arm/mach-iop13xx/tpmi.c
@@ -0,0 +1,234 @@
+/*
+ * iop13xx tpmi device resources
+ * Copyright (c) 2005-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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+/* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */
+#define IOP13XX_TPMI_MMR(dev) 	IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12))
+#define IOP13XX_TPMI_MEM(dev) 	IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13))
+#define IOP13XX_TPMI_CTRL(dev)	IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10))
+#define IOP13XX_TPMI_MMR_SIZE	    (SZ_4K - 1)
+#define IOP13XX_TPMI_MEM_SIZE	    (255)
+#define IOP13XX_TPMI_MEM_CTRL	    (SZ_1K - 1)
+#define IOP13XX_TPMI_RESOURCE_MMR  0
+#define IOP13XX_TPMI_RESOURCE_MEM  1
+#define IOP13XX_TPMI_RESOURCE_CTRL 2
+#define IOP13XX_TPMI_RESOURCE_IRQ  3
+
+static struct resource iop13xx_tpmi_0_resources[] = {
+	[IOP13XX_TPMI_RESOURCE_MMR] = {
+		.start = IOP13XX_TPMI_MMR(4), /* tpmi0 starts at dev == 4 */
+		.end = IOP13XX_TPMI_MMR(4) + IOP13XX_TPMI_MMR_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_MEM] = {
+		.start = IOP13XX_TPMI_MEM(0),
+		.end = IOP13XX_TPMI_MEM(0) + IOP13XX_TPMI_MEM_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_CTRL] = {
+		.start = IOP13XX_TPMI_CTRL(0),
+		.end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_IRQ] = {
+		.start = IRQ_IOP13XX_TPMI0_OUT,
+		.end = IRQ_IOP13XX_TPMI0_OUT,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct resource iop13xx_tpmi_1_resources[] = {
+	[IOP13XX_TPMI_RESOURCE_MMR] = {
+		.start = IOP13XX_TPMI_MMR(1),
+		.end = IOP13XX_TPMI_MMR(1) + IOP13XX_TPMI_MMR_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_MEM] = {
+		.start = IOP13XX_TPMI_MEM(1),
+		.end = IOP13XX_TPMI_MEM(1) + IOP13XX_TPMI_MEM_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_CTRL] = {
+		.start = IOP13XX_TPMI_CTRL(1),
+		.end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_IRQ] = {
+		.start = IRQ_IOP13XX_TPMI1_OUT,
+		.end = IRQ_IOP13XX_TPMI1_OUT,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct resource iop13xx_tpmi_2_resources[] = {
+	[IOP13XX_TPMI_RESOURCE_MMR] = {
+		.start = IOP13XX_TPMI_MMR(2),
+		.end = IOP13XX_TPMI_MMR(2) + IOP13XX_TPMI_MMR_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_MEM] = {
+		.start = IOP13XX_TPMI_MEM(2),
+		.end = IOP13XX_TPMI_MEM(2) + IOP13XX_TPMI_MEM_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_CTRL] = {
+		.start = IOP13XX_TPMI_CTRL(2),
+		.end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_IRQ] = {
+		.start = IRQ_IOP13XX_TPMI2_OUT,
+		.end = IRQ_IOP13XX_TPMI2_OUT,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+static struct resource iop13xx_tpmi_3_resources[] = {
+	[IOP13XX_TPMI_RESOURCE_MMR] = {
+		.start = IOP13XX_TPMI_MMR(3),
+		.end = IOP13XX_TPMI_MMR(3) + IOP13XX_TPMI_MMR_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_MEM] = {
+		.start = IOP13XX_TPMI_MEM(3),
+		.end = IOP13XX_TPMI_MEM(3) + IOP13XX_TPMI_MEM_SIZE,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_CTRL] = {
+		.start = IOP13XX_TPMI_CTRL(3),
+		.end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL,
+		.flags = IORESOURCE_MEM,
+	},
+	[IOP13XX_TPMI_RESOURCE_IRQ] = {
+		.start = IRQ_IOP13XX_TPMI3_OUT,
+		.end = IRQ_IOP13XX_TPMI3_OUT,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+u64 iop13xx_tpmi_mask = DMA_64BIT_MASK;
+static struct platform_device iop13xx_tpmi_0_device = {
+	.name = "iop-tpmi",
+	.id = 0,
+	.num_resources = 4,
+	.resource = iop13xx_tpmi_0_resources,
+	.dev = {
+		.dma_mask          = &iop13xx_tpmi_mask,
+		.coherent_dma_mask = DMA_64BIT_MASK,
+	},
+};
+
+static struct platform_device iop13xx_tpmi_1_device = {
+	.name = "iop-tpmi",
+	.id = 1,
+	.num_resources = 4,
+	.resource = iop13xx_tpmi_1_resources,
+	.dev = {
+		.dma_mask          = &iop13xx_tpmi_mask,
+		.coherent_dma_mask = DMA_64BIT_MASK,
+	},
+};
+
+static struct platform_device iop13xx_tpmi_2_device = {
+	.name = "iop-tpmi",
+	.id = 2,
+	.num_resources = 4,
+	.resource = iop13xx_tpmi_2_resources,
+	.dev = {
+		.dma_mask          = &iop13xx_tpmi_mask,
+		.coherent_dma_mask = DMA_64BIT_MASK,
+	},
+};
+
+static struct platform_device iop13xx_tpmi_3_device = {
+	.name = "iop-tpmi",
+	.id = 3,
+	.num_resources = 4,
+	.resource = iop13xx_tpmi_3_resources,
+	.dev = {
+		.dma_mask          = &iop13xx_tpmi_mask,
+		.coherent_dma_mask = DMA_64BIT_MASK,
+	},
+};
+
+__init void iop13xx_add_tpmi_devices(void)
+{
+	unsigned short device_id;
+
+	/* tpmi's not present on iop341 or iop342 */
+	if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX)
+		/* ATUE must be present */
+		device_id = __raw_readw(IOP13XX_ATUE_DID);
+	else
+		/* ATUX must be present */
+		device_id = __raw_readw(IOP13XX_ATUX_DID);
+
+	switch (device_id) {
+	/* iop34[1|2] 0-tpmi */
+	case 0x3380:
+	case 0x3384:
+	case 0x3388:
+	case 0x338c:
+	case 0x3382:
+	case 0x3386:
+	case 0x338a:
+	case 0x338e:
+		return;
+	/* iop348 1-tpmi */
+	case 0x3310:
+	case 0x3312:
+	case 0x3314:
+	case 0x3318:
+	case 0x331a:
+	case 0x331c:
+	case 0x33c0:
+	case 0x33c2:
+	case 0x33c4:
+	case 0x33c8:
+	case 0x33ca:
+	case 0x33cc:
+	case 0x33b0:
+	case 0x33b2:
+	case 0x33b4:
+	case 0x33b8:
+	case 0x33ba:
+	case 0x33bc:
+	case 0x3320:
+	case 0x3322:
+	case 0x3324:
+	case 0x3328:
+	case 0x332a:
+	case 0x332c:
+		platform_device_register(&iop13xx_tpmi_0_device);
+		return;
+	default:
+		platform_device_register(&iop13xx_tpmi_0_device);
+		platform_device_register(&iop13xx_tpmi_1_device);
+		platform_device_register(&iop13xx_tpmi_2_device);
+		platform_device_register(&iop13xx_tpmi_3_device);
+		return;
+	}
+}
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig
index 9dd49cf..9bb02b6 100644
--- a/arch/arm/mach-iop32x/Kconfig
+++ b/arch/arm/mach-iop32x/Kconfig
@@ -34,6 +34,14 @@ config MACH_N2100
 	  Say Y here if you want to run your kernel on the Thecus n2100
 	  NAS appliance.
 
+config IOP3XX_ATU
+        bool "Enable the PCI Controller"
+        default y
+        help
+          Say Y here if you want the IOP to initialize its PCI Controller.
+          Say N if the IOP is an add in card, the host system owns the PCI
+          bus in this case.
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index 60e7430..7b21c6e 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -178,9 +178,10 @@ static struct hw_pci iq31244_pci __initd
 
 static int __init iq31244_pci_init(void)
 {
-	if (is_ep80219())
-		pci_common_init(&ep80219_pci);
-	else if (machine_is_iq31244()) {
+	if (is_ep80219()) {
+		if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
+			pci_common_init(&ep80219_pci);
+	} else if (machine_is_iq31244()) {
 		if (is_80219()) {
 			printk("note: iq31244 board type has been selected\n");
 			printk("note: to select ep80219 operation:\n");
@@ -189,7 +190,9 @@ static int __init iq31244_pci_init(void)
 			printk("\t2/ update boot loader to pass"
 				" the ep80219 id: %d\n", MACH_TYPE_EP80219);
 		}
-		pci_common_init(&iq31244_pci);
+
+		if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
+			pci_common_init(&iq31244_pci);
 	}
 
 	return 0;
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index 361c70c..bc25fb9 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -113,7 +113,8 @@ static struct hw_pci iq80321_pci __initd
 
 static int __init iq80321_pci_init(void)
 {
-	if (machine_is_iq80321())
+	if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+		machine_is_iq80321())
 		pci_common_init(&iq80321_pci);
 
 	return 0;
diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig
index 9aa016b..45598e0 100644
--- a/arch/arm/mach-iop33x/Kconfig
+++ b/arch/arm/mach-iop33x/Kconfig
@@ -16,6 +16,14 @@ config MACH_IQ80332
 	  Say Y here if you want to run your kernel on the Intel IQ80332
 	  evaluation kit for the IOP332 chipset.
 
+config IOP3XX_ATU
+	bool "Enable the PCI Controller"
+	default y
+	help
+	  Say Y here if you want the IOP to initialize its PCI Controller.
+	  Say N if the IOP is an add in card, the host system owns the PCI
+	  bus in this case.
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
index 1a9e361..376c932 100644
--- a/arch/arm/mach-iop33x/iq80331.c
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -96,7 +96,8 @@ static struct hw_pci iq80331_pci __initd
 
 static int __init iq80331_pci_init(void)
 {
-	if (machine_is_iq80331())
+	if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+		machine_is_iq80331())
 		pci_common_init(&iq80331_pci);
 
 	return 0;
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
index 96d6f0f..58c8149 100644
--- a/arch/arm/mach-iop33x/iq80332.c
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -96,7 +96,8 @@ static struct hw_pci iq80332_pci __initd
 
 static int __init iq80332_pci_init(void)
 {
-	if (machine_is_iq80332())
+	if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+		machine_is_iq80332())
 		pci_common_init(&iq80332_pci);
 
 	return 0;
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 27b7480..cb6ad21 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -84,59 +84,59 @@ static struct map_desc ixp2000_io_desc[]
 		.virtual	= IXP2000_CAP_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
 		.length		= IXP2000_CAP_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_INTCTL_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
 		.length		= IXP2000_INTCTL_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_PCI_CREG_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
 		.length		= IXP2000_PCI_CREG_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_PCI_CSR_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
 		.length		= IXP2000_PCI_CSR_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_MSF_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
 		.length		= IXP2000_MSF_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_SCRATCH_RING_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
 		.length		= IXP2000_SCRATCH_RING_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_SRAM0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
 		.length		= IXP2000_SRAM0_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_PCI_IO_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
 		.length		= IXP2000_PCI_IO_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_PCI_CFG0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
 		.length		= IXP2000_PCI_CFG0_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= IXP2000_PCI_CFG1_VIRT_BASE,
 		.pfn		= __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
 		.length		= IXP2000_PCI_CFG1_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}
 };
 
 void __init ixp2000_map_io(void)
 {
 	/*
-	 * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE so that
+	 * On IXP2400 CPUs we need to use MT_DEVICE_IXP2000 so that
 	 * XCB=101 (to avoid triggering erratum #66), and given that
 	 * this mode speeds up I/O accesses and we have write buffer
 	 * flushes in the right places anyway, it doesn't hurt to use
@@ -224,7 +224,7 @@ static int ixp2000_timer_interrupt(int i
 
 static struct irqaction ixp2000_timer_irq = {
 	.name		= "IXP2000 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= ixp2000_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index ac29298..500e997 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -70,17 +70,17 @@ static struct map_desc enp2611_io_desc[]
 		.virtual	= ENP2611_CALEB_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_CALEB_PHYS_BASE),
 		.length		= ENP2611_CALEB_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= ENP2611_PM3386_0_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE),
 		.length		= ENP2611_PM3386_0_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}, {
 		.virtual	= ENP2611_PM3386_1_VIRT_BASE,
 		.pfn		= __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE),
 		.length		= ENP2611_PM3386_1_SIZE,
-		.type		= MT_IXP2000_DEVICE,
+		.type		= MT_DEVICE_IXP2000,
 	}
 };
 
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index ce6ad63..b644bba 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -363,7 +363,7 @@ ixp23xx_timer_interrupt(int irq, void *d
 static struct irqaction ixp23xx_timer_irq = {
 	.name		= "IXP23xx Timer Tick",
 	.handler	= ixp23xx_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
 void __init ixp23xx_init_timer(void)
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 8a339cd..9715ef5 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -62,6 +62,12 @@ config MACH_IXDP465
 	  IXDP465 Development Platform (Also known as BMP).
 	  For more information on this platform, see <file:Documentation/arm/IXP4xx>.
 
+config MACH_KIXRP435
+	bool "KIXRP435"
+	help
+	  Say 'Y' here if you want your kernel to support Intel's
+	  KIXRP435 Reference Platform.
+	  For more information on this platform, see <file:Documentation/arm/IXP4xx>.
 
 #
 # IXCDP1100 is the exact same HW as IXDP425, but with a different machine 
@@ -89,12 +95,21 @@ config MACH_NAS100D
 	  NAS 100d device. For more information on this platform,
 	  see http://www.nslu2-linux.org/wiki/NAS100d/HomePage
 
+config MACH_DSMG600
+	bool
+	prompt "D-Link DSM-G600 RevA"
+	select PCI
+	help
+	  Say 'Y' here if you want your kernel to support D-Link's
+	  DSM-G600 RevA device. For more information on this platform,
+	  see http://www.nslu2-linux.org/wiki/DSMG600/HomePage
+
 #
 # Avila and IXDP share the same source for now. Will change in future
 #
 config	ARCH_IXDP4XX
 	bool
-	depends on ARCH_IXDP425 || MACH_IXDP465
+	depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435
 	default y
 
 #
@@ -105,6 +120,11 @@ config CPU_IXP46X
 	depends on MACH_IXDP465
 	default y
 
+config CPU_IXP43X
+	bool
+	depends on MACH_KIXRP435
+	default y
+
 config MACH_GTWX5715
 	bool "Gemtek WX5715 (Linksys WRV54G)"
 	depends on ARCH_IXP4XX
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 746e297..3b87c47 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -12,6 +12,7 @@ obj-pci-$(CONFIG_ARCH_ADI_COYOTE)	+= coy
 obj-pci-$(CONFIG_MACH_GTWX5715)		+= gtwx5715-pci.o
 obj-pci-$(CONFIG_MACH_NSLU2)		+= nslu2-pci.o
 obj-pci-$(CONFIG_MACH_NAS100D)		+= nas100d-pci.o
+obj-pci-$(CONFIG_MACH_DSMG600)		+= dsmg600-pci.o
 
 obj-y	+= common.o
 
@@ -22,5 +23,6 @@ obj-$(CONFIG_ARCH_ADI_COYOTE)	+= coyote-
 obj-$(CONFIG_MACH_GTWX5715)	+= gtwx5715-setup.o
 obj-$(CONFIG_MACH_NSLU2)	+= nslu2-setup.o nslu2-power.o
 obj-$(CONFIG_MACH_NAS100D)	+= nas100d-setup.o nas100d-power.o
+obj-$(CONFIG_MACH_DSMG600)      += dsmg600-setup.o dsmg600-power.o
 
 obj-$(CONFIG_PCI)		+= $(obj-pci-$(CONFIG_PCI)) common-pci.o
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 9562177..bf04121 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -374,7 +374,7 @@ void __init ixp4xx_pci_preinit(void)
 	 * Determine which PCI read method to use.
 	 * Rev 0 IXP425 requires workaround.
 	 */
-	if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
+	if (!(processor_id & 0xf) && cpu_is_ixp42x()) {
 		printk("PCI: IXP42x A0 silicon detected - "
 			"PCI Non-Prefetch Workaround Enabled\n");
 		ixp4xx_pci_read = ixp4xx_pci_read_errata;
@@ -480,7 +480,7 @@ int ixp4xx_setup(int nr, struct pci_sys_
 	res[0].flags = IORESOURCE_IO;
 
 	res[1].name = "PCI Memory Space";
-	res[1].start = 0x48000000;
+	res[1].start = PCIBIOS_MIN_MEM;
 #ifndef CONFIG_IXP4XX_INDIRECT_PCI
 	res[1].end = 0x4bffffff;
 #else
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 45068c3..64685da 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -27,6 +27,7 @@ #include <linux/bitops.h>
 #include <linux/time.h>
 #include <linux/timex.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/arch/udc.h>
 #include <asm/hardware.h>
@@ -41,6 +42,8 @@ #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
 static int __init ixp4xx_clocksource_init(void);
+static int __init ixp4xx_clockevent_init(void);
+static struct clock_event_device clockevent_ixp4xx;
 
 /*************************************************************************
  * IXP4xx chipset I/O mapping
@@ -102,6 +105,29 @@ static signed char irq2gpio[32] = {
 	 7,  8,  9, 10, 11, 12, -1, -1,
 };
 
+int gpio_to_irq(int gpio)
+{
+	int irq;
+
+	for (irq = 0; irq < 32; irq++) {
+		if (irq2gpio[irq] == gpio)
+			return irq;
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(int irq)
+{
+	int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL;
+
+	if (gpio == -1)
+		return -EINVAL;
+
+	return gpio;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+
 static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
 {
 	int line = irq2gpio[irq];
@@ -169,7 +195,7 @@ static int ixp4xx_set_irq_type(unsigned 
 
 static void ixp4xx_irq_mask(unsigned int irq)
 {
-	if (cpu_is_ixp46x() && irq >= 32)
+	if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
 		*IXP4XX_ICMR2 &= ~(1 << (irq - 32));
 	else
 		*IXP4XX_ICMR &= ~(1 << irq);
@@ -192,7 +218,7 @@ static void ixp4xx_irq_unmask(unsigned i
 	if (!(ixp4xx_irq_edge & (1 << irq)))
 		ixp4xx_irq_ack(irq);
 
-	if (cpu_is_ixp46x() && irq >= 32)
+	if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
 		*IXP4XX_ICMR2 |= (1 << (irq - 32));
 	else
 		*IXP4XX_ICMR |= (1 << irq);
@@ -216,7 +242,7 @@ void __init ixp4xx_init_irq(void)
 	/* Disable all interrupt */
 	*IXP4XX_ICMR = 0x0; 
 
-	if (cpu_is_ixp46x()) {
+	if (cpu_is_ixp46x() || cpu_is_ixp43x()) {
 		/* Route upper 32 sources to IRQ instead of FIQ */
 		*IXP4XX_ICLR2 = 0x00;
 
@@ -239,52 +265,40 @@ void __init ixp4xx_init_irq(void)
  * counter as a source of real clock ticks to account for missed jiffies.
  *************************************************************************/
 
-static unsigned volatile last_jiffy_time;
-
-#define CLOCK_TICKS_PER_USEC	((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
-
 static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
+	struct clock_event_device *evt = &clockevent_ixp4xx;
 
 	/* Clear Pending Interrupt by writing '1' to it */
 	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
 
-	/*
-	 * Catch up with the real idea of time
-	 */
-	while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
-		timer_tick();
-		last_jiffy_time += LATCH;
-	}
-
-	write_sequnlock(&xtime_lock);
+	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
 }
 
 static struct irqaction ixp4xx_timer_irq = {
-	.name		= "IXP4xx Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.name		= "timer1",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= ixp4xx_timer_interrupt,
 };
 
 static void __init ixp4xx_timer_init(void)
 {
+	/* Reset/disable counter */
+	*IXP4XX_OSRT1 = 0;
+
 	/* Clear Pending Interrupt by writing '1' to it */
 	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
 
-	/* Setup the Timer counter value */
-	*IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
-
 	/* Reset time-stamp counter */
 	*IXP4XX_OSTS = 0;
-	last_jiffy_time = 0;
 
 	/* Connect the interrupt handler and enable the interrupt */
 	setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
 
 	ixp4xx_clocksource_init();
+	ixp4xx_clockevent_init();
 }
 
 struct sys_timer ixp4xx_timer = {
@@ -384,6 +398,9 @@ void __init ixp4xx_sys_init(void)
 			ixp4xx_exp_bus_size >> 20);
 }
 
+/*
+ * clocksource
+ */
 cycle_t ixp4xx_get_cycles(void)
 {
 	return *IXP4XX_OSTS;
@@ -408,3 +425,64 @@ static int __init ixp4xx_clocksource_ini
 
 	return 0;
 }
+
+/*
+ * clockevents
+ */
+static int ixp4xx_set_next_event(unsigned long evt,
+				 struct clock_event_device *unused)
+{
+	unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
+
+	*IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts;
+
+	return 0;
+}
+
+static void ixp4xx_set_mode(enum clock_event_mode mode,
+			    struct clock_event_device *evt)
+{
+	unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK;
+ 		opts = IXP4XX_OST_ENABLE;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* period set by 'set next_event' */
+		osrt = 0;
+		opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT;
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+	default:
+		osrt = opts = 0;
+		break;
+	}
+
+	*IXP4XX_OSRT1 = osrt | opts;
+}
+
+static struct clock_event_device clockevent_ixp4xx = {
+	.name		= "ixp4xx timer1",
+	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.rating         = 200,
+	.shift		= 24,
+	.set_mode	= ixp4xx_set_mode,
+	.set_next_event	= ixp4xx_set_next_event,
+};
+
+static int __init ixp4xx_clockevent_init(void)
+{
+	clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
+					clockevent_ixp4xx.shift);
+	clockevent_ixp4xx.max_delta_ns =
+		clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
+	clockevent_ixp4xx.min_delta_ns =
+		clockevent_delta2ns(0xf, &clockevent_ixp4xx);
+	clockevent_ixp4xx.cpumask = cpumask_of_cpu(0);
+
+	clockevents_register_device(&clockevent_ixp4xx);
+	return 0;
+}
diff --git a/arch/arm/mach-ixp4xx/dsmg600-pci.c b/arch/arm/mach-ixp4xx/dsmg600-pci.c
new file mode 100644
index 0000000..9db7e1f
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-pci.c
@@ -0,0 +1,74 @@
+/*
+ * DSM-G600 board-level PCI initialization
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on ixdp425-pci.c:
+ *	Copyright (C) 2002 Intel Corporation.
+ *	Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Maintainer: http://www.nslu2-linux.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/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+void __init dsmg600_pci_preinit(void)
+{
+	set_irq_type(IRQ_DSMG600_PCI_INTA, IRQT_LOW);
+	set_irq_type(IRQ_DSMG600_PCI_INTB, IRQT_LOW);
+	set_irq_type(IRQ_DSMG600_PCI_INTC, IRQT_LOW);
+	set_irq_type(IRQ_DSMG600_PCI_INTD, IRQT_LOW);
+	set_irq_type(IRQ_DSMG600_PCI_INTE, IRQT_LOW);
+	set_irq_type(IRQ_DSMG600_PCI_INTF, IRQT_LOW);
+
+	ixp4xx_pci_preinit();
+}
+
+static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	static int pci_irq_table[DSMG600_PCI_MAX_DEV][DSMG600_PCI_IRQ_LINES] =
+	{
+		{ IRQ_DSMG600_PCI_INTE, -1, -1 },
+		{ IRQ_DSMG600_PCI_INTA, -1, -1 },
+		{ IRQ_DSMG600_PCI_INTB, IRQ_DSMG600_PCI_INTC, IRQ_DSMG600_PCI_INTD },
+		{ IRQ_DSMG600_PCI_INTF, -1, -1 },
+	};
+
+	int irq = -1;
+
+	if (slot >= 1 && slot <= DSMG600_PCI_MAX_DEV &&
+		pin >= 1 && pin <= DSMG600_PCI_IRQ_LINES)
+		irq = pci_irq_table[slot-1][pin-1];
+
+	return irq;
+}
+
+struct hw_pci __initdata dsmg600_pci = {
+	.nr_controllers = 1,
+	.preinit	= dsmg600_pci_preinit,
+	.swizzle	= pci_std_swizzle,
+	.setup		= ixp4xx_setup,
+	.scan		= ixp4xx_scan_bus,
+	.map_irq	= dsmg600_map_irq,
+};
+
+int __init dsmg600_pci_init(void)
+{
+	if (machine_is_dsmg600())
+		pci_common_init(&dsmg600_pci);
+
+	return 0;
+}
+
+subsys_initcall(dsmg600_pci_init);
diff --git a/arch/arm/mach-ixp4xx/dsmg600-power.c b/arch/arm/mach-ixp4xx/dsmg600-power.c
new file mode 100644
index 0000000..3471787
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-power.c
@@ -0,0 +1,125 @@
+/*
+ * arch/arm/mach-ixp4xx/dsmg600-power.c
+ *
+ * DSM-G600 Power/Reset driver
+ * Author: Michael Westerhof <mwester@dls.net>
+ *
+ * Based on nslu2-power.c
+ *  Copyright (C) 2005 Tower Technologies
+ *  Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * which was based on nslu2-io.c
+ *  Copyright (C) 2004 Karen Spearel
+ *
+ * Maintainers: http://www.nslu2-linux.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/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+
+#include <asm/mach-types.h>
+
+extern void ctrl_alt_del(void);
+
+/* This is used to make sure the power-button pusher is serious.  The button
+ * must be held until the value of this counter reaches zero.
+ */
+static volatile int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void dsmg600_power_handler(unsigned long data);
+static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
+
+static void dsmg600_power_handler(unsigned long data)
+{
+	/* This routine is called twice per second to check the
+	 * state of the power button.
+	 */
+
+	if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) {
+
+		/* IO Pin is 1 (button pushed) */
+		if (power_button_countdown == 0) {
+			/* Signal init to do the ctrlaltdel action, this will bypass
+			 * init if it hasn't started and do a kernel_restart.
+			 */
+			ctrl_alt_del();
+
+			/* Change the state of the power LED to "blink" */
+			gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+		}
+		power_button_countdown--;
+
+	} else {
+		power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+	}
+
+	mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
+{
+	/* This is the paper-clip reset, it shuts the machine down directly. */
+	machine_power_off();
+
+	return IRQ_HANDLED;
+}
+
+static int __init dsmg600_power_init(void)
+{
+	if (!(machine_is_dsmg600()))
+		return 0;
+
+	if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler,
+		IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button",
+		NULL) < 0) {
+
+		printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+			DSMG600_RB_IRQ);
+
+		return -EIO;
+	}
+
+	/* The power button on the D-Link DSM-G600 is on GPIO 15, but
+	 * it cannot handle interrupts on that GPIO line.  So we'll
+	 * have to poll it with a kernel timer.
+	 */
+
+	/* Make sure that the power button GPIO is set up as an input */
+	gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
+
+	/* Set the initial value for the power button IRQ handler */
+	power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+	mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+
+	return 0;
+}
+
+static void __exit dsmg600_power_exit(void)
+{
+	if (!(machine_is_dsmg600()))
+		return;
+
+	del_timer_sync(&dsmg600_power_timer);
+
+	free_irq(DSMG600_RB_IRQ, NULL);
+}
+
+module_init(dsmg600_power_init);
+module_exit(dsmg600_power_exit);
+
+MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>");
+MODULE_DESCRIPTION("DSM-G600 Power/Reset driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
new file mode 100644
index 0000000..1caff65
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -0,0 +1,175 @@
+/*
+ * DSM-G600 board-setup
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based ixdp425-setup.c:
+ *      Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+static struct flash_platform_data dsmg600_flash_data = {
+	.map_name		= "cfi_probe",
+	.width			= 2,
+};
+
+static struct resource dsmg600_flash_resource = {
+	.flags			= IORESOURCE_MEM,
+};
+
+static struct platform_device dsmg600_flash = {
+	.name			= "IXP4XX-Flash",
+	.id			= 0,
+	.dev.platform_data	= &dsmg600_flash_data,
+	.num_resources		= 1,
+	.resource		= &dsmg600_flash_resource,
+};
+
+static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = {
+	.sda_pin		= DSMG600_SDA_PIN,
+	.scl_pin		= DSMG600_SCL_PIN,
+};
+
+static struct platform_device dsmg600_i2c_controller = {
+	.name			= "IXP4XX-I2C",
+	.id			= 0,
+	.dev.platform_data	= &dsmg600_i2c_gpio_pins,
+};
+
+#ifdef CONFIG_LEDS_CLASS
+static struct resource dsmg600_led_resources[] = {
+	{
+		.name           = "power",
+		.start          = DSMG600_LED_PWR_GPIO,
+		.end            = DSMG600_LED_PWR_GPIO,
+		.flags          = IXP4XX_GPIO_HIGH,
+	},
+	{
+		.name           = "wlan",
+		.start		= DSMG600_LED_WLAN_GPIO,
+		.end            = DSMG600_LED_WLAN_GPIO,
+		.flags          = IXP4XX_GPIO_LOW,
+	},
+};
+
+static struct platform_device dsmg600_leds = {
+        .name                   = "IXP4XX-GPIO-LED",
+        .id                     = -1,
+        .num_resources          = ARRAY_SIZE(dsmg600_led_resources),
+        .resource               = dsmg600_led_resources,
+};
+#endif
+
+static struct resource dsmg600_uart_resources[] = {
+	{
+		.start		= IXP4XX_UART1_BASE_PHYS,
+		.end		= IXP4XX_UART1_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= IXP4XX_UART2_BASE_PHYS,
+		.end		= IXP4XX_UART2_BASE_PHYS + 0x0fff,
+		.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct plat_serial8250_port dsmg600_uart_data[] = {
+	{
+		.mapbase	= IXP4XX_UART1_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{
+		.mapbase	= IXP4XX_UART2_BASE_PHYS,
+		.membase	= (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+		.irq		= IRQ_IXP4XX_UART2,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= IXP4XX_UART_XTAL,
+	},
+	{ }
+};
+
+static struct platform_device dsmg600_uart = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev.platform_data	= dsmg600_uart_data,
+	.num_resources		= ARRAY_SIZE(dsmg600_uart_resources),
+	.resource		= dsmg600_uart_resources,
+};
+
+static struct platform_device *dsmg600_devices[] __initdata = {
+	&dsmg600_i2c_controller,
+	&dsmg600_flash,
+};
+
+static void dsmg600_power_off(void)
+{
+	/* enable the pwr cntl gpio */
+	gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT);
+
+	/* poweroff */
+	gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
+}
+
+static void __init dsmg600_init(void)
+{
+	ixp4xx_sys_init();
+
+	/* Make sure that GPIO14 and GPIO15 are not used as clocks */
+	*IXP4XX_GPIO_GPCLKR = 0;
+
+	dsmg600_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+	dsmg600_flash_resource.end =
+		IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+
+	pm_power_off = dsmg600_power_off;
+
+	/* The UART is required on the DSM-G600 (Redboot cannot use the
+	 * NIC) -- do it here so that it does *not* get removed if
+	 * platform_add_devices fails!
+         */
+        (void)platform_device_register(&dsmg600_uart);
+
+	platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
+
+#ifdef CONFIG_LEDS_CLASS
+        /* We don't care whether or not this works. */
+        (void)platform_device_register(&dsmg600_leds);
+#endif
+}
+
+static void __init dsmg600_fixup(struct machine_desc *desc,
+                struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+       /* The xtal on this machine is non-standard. */
+        ixp4xx_timer_freq = DSMG600_FREQ;
+}
+
+MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
+	/* Maintainer: www.nslu2-linux.org */
+	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
+	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
+	.boot_params	= 0x00000100,
+	.fixup          = dsmg600_fixup,
+	.map_io		= ixp4xx_map_io,
+	.init_irq	= ixp4xx_init_irq,
+	.timer          = &ixp4xx_timer,
+	.init_machine	= dsmg600_init,
+MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c
index 99c1dc8..4087960 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
@@ -66,7 +66,7 @@ struct hw_pci ixdp425_pci __initdata = {
 int __init ixdp425_pci_init(void)
 {
 	if (machine_is_ixdp425() || machine_is_ixcdp1100() ||
-			machine_is_ixdp465())
+			machine_is_ixdp465() || machine_is_kixrp435())
 		pci_common_init(&ixdp425_pci);
 	return 0;
 }
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 04b1d56..ec4f079 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -115,6 +115,11 @@ static void __init ixdp425_init(void)
 	ixdp425_flash_resource.end =
 		IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
 
+	if (cpu_is_ixp43x()) {
+		ixdp425_uart.num_resources = 1;
+		ixdp425_uart_data[1].flags = 0;
+	}
+
 	platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices));
 }
 
@@ -156,3 +161,16 @@ MACHINE_START(IXCDP1100, "Intel IXCDP110
 	.init_machine	= ixdp425_init,
 MACHINE_END
 #endif
+
+#ifdef CONFIG_MACH_KIXRP435
+MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
+	/* Maintainer: MontaVista Software, Inc. */
+	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
+	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+	.map_io		= ixp4xx_map_io,
+	.init_irq	= ixp4xx_init_irq,
+	.timer		= &ixp4xx_timer,
+	.boot_params	= 0x0100,
+	.init_machine	= ixdp425_init,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a400.c b/arch/arm/mach-lh7a40x/irq-lh7a400.c
index 0b938e8..9472bbe 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a400.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a400.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a404.c b/arch/arm/mach-lh7a40x/irq-lh7a404.c
index 5760f8c..9b28389 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a404.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a404.c
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
index 15b9577..66e1ed3 100644
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index bef3c4b..c25316d 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -53,7 +53,7 @@ lh7a40x_timer_interrupt(int irq, void *d
 
 static struct irqaction lh7a40x_timer_irq = {
 	.name		= "LHA740x Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= lh7a40x_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index 7e132fc..4762e20 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -47,7 +47,7 @@ netx_timer_interrupt(int irq, void *dev_
 
 static struct irqaction netx_timer_irq = {
 	.name           = "NetX Timer Tick",
-	.flags          = IRQF_DISABLED | IRQF_TIMER,
+	.flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler        = netx_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig
index 8175ba9..8584ed1 100644
--- a/arch/arm/mach-ns9xxx/Kconfig
+++ b/arch/arm/mach-ns9xxx/Kconfig
@@ -3,19 +3,30 @@ if ARCH_NS9XXX
 menu "NS9xxx Implementations"
 
 config MACH_CC9P9360DEV
-	bool "Connect Core 9P 9360 on an A9M9750 Devboard"
+	bool "ConnectCore 9P 9360 on an A9M9750 Devboard"
 	select PROCESSOR_NS9360
 	select BOARD_A9M9750DEV
 	help
-	  Say Y here if you are using the Digi Connect Core 9P 9360
+	  Say Y here if you are using the Digi ConnectCore 9P 9360
 	  on an A9M9750 Development Board.
 
+config MACH_CC9P9360JS
+	bool "ConnectCore 9P 9360 on a JSCC9P9360 Devboard"
+	select PROCESSOR_NS9360
+	select BOARD_JSCC9P9360
+	help
+	  Say Y here if you are using the Digi ConnectCore 9P 9360
+	  on an JSCC9P9360 Development Board.
+
 config PROCESSOR_NS9360
 	bool
 
 config BOARD_A9M9750DEV
 	bool
 
+config BOARD_JSCC9P9360
+	bool
+
 endmenu
 
 endif
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
index 91e945f..53213a6 100644
--- a/arch/arm/mach-ns9xxx/Makefile
+++ b/arch/arm/mach-ns9xxx/Makefile
@@ -3,3 +3,4 @@ obj-y := irq.o time.o generic.o
 obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
 
 obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
+obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.c b/arch/arm/mach-ns9xxx/board-jscc9p9360.c
new file mode 100644
index 0000000..4bd3eec
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-jscc9p9360.c
@@ -0,0 +1,17 @@
+/*
+ * arch/arm/mach-ns9xxx/board-jscc9p9360.c
+ *
+ * Copyright (C) 2006,2007 by Digi International 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+#include "board-jscc9p9360.h"
+
+void __init board_jscc9p9360_init_machine(void)
+{
+	/* TODO: reserve GPIOs for push buttons, etc pp */
+}
+
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.h b/arch/arm/mach-ns9xxx/board-jscc9p9360.h
new file mode 100644
index 0000000..1a81a07
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-jscc9p9360.h
@@ -0,0 +1,13 @@
+/*
+ * arch/arm/mach-ns9xxx/board-jscc9p9360.h
+ *
+ * Copyright (C) 2006 by Digi International 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/init.h>
+
+void __init board_jscc9p9360_init_machine(void);
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
new file mode 100644
index 0000000..d09d5fa
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-ns9xxx/mach-cc9p9360js.c
+ *
+ * Copyright (C) 2006 by Digi International 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 version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include "board-jscc9p9360.h"
+#include "generic.h"
+
+static void __init mach_cc9p9360js_init_machine(void)
+{
+	ns9xxx_init_machine();
+	board_jscc9p9360_init_machine();
+}
+
+MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
+	.map_io = ns9xxx_map_io,
+	.init_irq = ns9xxx_init_irq,
+	.init_machine = mach_cc9p9360js_init_machine,
+	.timer = &ns9xxx_timer,
+	.boot_params = 0x100,
+MACHINE_END
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
index eec05f1..dd25708 100644
--- a/arch/arm/mach-ns9xxx/time.c
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -53,7 +53,7 @@ static unsigned long ns9xxx_timer_gettim
 
 static struct irqaction ns9xxx_timer_irq = {
 	.name = "NS9xxx Timer Tick",
-	.flags = IRQF_DISABLED | IRQF_TIMER,
+	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler = ns9xxx_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 410d3e7..0733078 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -40,7 +40,6 @@ #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 49efe90..6f4ea4b 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -72,12 +72,12 @@ static unsigned int mpui1610_sleep_save[
 
 static unsigned short enable_dyn_sleep = 1;
 
-static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf)
 {
 	return sprintf(buf, "%hu\n", enable_dyn_sleep);
 }
 
-static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
 					      const char * buf,
 					      size_t n)
 {
@@ -100,7 +100,7 @@ static struct subsys_attribute sleep_whi
 	.store  = omap_pm_sleep_while_idle_store,
 };
 
-extern struct subsystem power_subsys;
+extern struct kset power_subsys;
 static void (*omap_sram_idle)(void) = NULL;
 static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
 
@@ -698,10 +698,10 @@ static struct irqaction omap_wakeup_irq 
 
 
 static struct pm_ops omap_pm_ops ={
-	.pm_disk_mode	= 0,
 	.prepare	= omap_pm_prepare,
 	.enter		= omap_pm_enter,
 	.finish		= omap_pm_finish,
+	.valid		= pm_valid_only_mem,
 };
 
 static int __init omap_pm_init(void)
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 1b7e4a5..3705d20 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -39,6 +39,10 @@ #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -48,13 +52,7 @@ #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-struct sys_timer omap_timer;
 
-/*
- * ---------------------------------------------------------------------------
- * MPU timer
- * ---------------------------------------------------------------------------
- */
 #define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
 #define OMAP_MPU_TIMER_OFFSET		0x100
 
@@ -88,21 +86,6 @@ static inline unsigned long long cycles_
 	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
 }
 
-/*
- * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
- * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
- * with 0. This divides the 13MHz input by 2, and is undocumented.
- */
-#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
-/* REVISIT: This ifdef construct should be replaced by a query to clock
- * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
- */
-#define MPU_TICKS_PER_SEC		(13000000 / 2)
-#else
-#define MPU_TICKS_PER_SEC		(12000000 / 2)
-#endif
-
-#define MPU_TIMER_TICK_PERIOD		((MPU_TICKS_PER_SEC / HZ) - 1)
 
 typedef struct {
 	u32 cntl;			/* CNTL_TIMER, R/W */
@@ -120,98 +103,164 @@ static inline unsigned long omap_mpu_tim
 	return timer->read_tim;
 }
 
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
+{
+	volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+	timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+	volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+	timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+					int autoreset)
 {
 	volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+	unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+	if (autoreset) timerflags |= MPU_TIMER_AR;
 
 	timer->cntl = MPU_TIMER_CLOCK_ENABLE;
 	udelay(1);
 	timer->load_tim = load_val;
         udelay(1);
-	timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+	timer->cntl = timerflags;
 }
 
-unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 1 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int omap_mpu_set_next_event(unsigned long cycles,
+				    struct clock_event_device *evt)
 {
-	unsigned long long nsec;
+	omap_mpu_timer_start(0, cycles, 0);
+	return 0;
+}
 
-	nsec = cycles_2_ns((unsigned long long)nr_ticks);
-	return (unsigned long)nsec / 1000;
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		omap_mpu_set_autoreset(0);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		omap_mpu_remove_autoreset(0);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		break;
+	}
 }
 
-/*
- * Last processed system timer interrupt
- */
-static unsigned long omap_mpu_timer_last = 0;
+static struct clock_event_device clockevent_mpu_timer1 = {
+	.name		= "mpu_timer1",
+	.features       = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= omap_mpu_set_next_event,
+	.set_mode	= omap_mpu_set_mode,
+};
 
-/*
- * Returns elapsed usecs since last system timer interrupt
- */
-static unsigned long omap_mpu_timer_gettimeoffset(void)
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer1_irq = {
+	.name		= "mpu_timer1",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= omap_mpu_timer1_interrupt,
+};
+
+static __init void omap_init_mpu_timer(unsigned long rate)
 {
-	unsigned long now = 0 - omap_mpu_timer_read(0);
-	unsigned long elapsed = now - omap_mpu_timer_last;
+	set_cyc2ns_scale(rate / 1000);
+
+	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+	omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+	clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+					    clockevent_mpu_timer1.shift);
+	clockevent_mpu_timer1.max_delta_ns =
+		clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+	clockevent_mpu_timer1.min_delta_ns =
+		clockevent_delta2ns(1, &clockevent_mpu_timer1);
 
-	return omap_mpu_timer_ticks_to_usecs(elapsed);
+	clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+	clockevents_register_device(&clockevent_mpu_timer1);
 }
 
+
 /*
- * Elapsed time between interrupts is calculated using timer0.
- * Latency during the interrupt is calculated using timer1.
- * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ * ---------------------------------------------------------------------------
+ * MPU timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
  */
-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
-{
-	unsigned long now, latency;
 
-	write_seqlock(&xtime_lock);
-	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();
-	write_sequnlock(&xtime_lock);
+static unsigned long omap_mpu_timer2_overflows;
 
+static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+	omap_mpu_timer2_overflows++;
 	return IRQ_HANDLED;
 }
 
-static struct irqaction omap_mpu_timer_irq = {
-	.name		= "mpu timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
-	.handler	= omap_mpu_timer_interrupt,
+static struct irqaction omap_mpu_timer2_irq = {
+	.name		= "mpu_timer2",
+	.flags		= IRQF_DISABLED,
+	.handler	= omap_mpu_timer2_interrupt,
 };
 
-static unsigned long omap_mpu_timer1_overflows;
-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+static cycle_t mpu_read(void)
 {
-	omap_mpu_timer1_overflows++;
-	return IRQ_HANDLED;
+	return ~omap_mpu_timer_read(1);
 }
 
-static struct irqaction omap_mpu_timer1_irq = {
-	.name		= "mpu timer1 overflow",
-	.flags		= IRQF_DISABLED,
-	.handler	= omap_mpu_timer1_interrupt,
+static struct clocksource clocksource_mpu = {
+	.name		= "mpu_timer2",
+	.rating		= 300,
+	.read		= mpu_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 24,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static __init void omap_init_mpu_timer(void)
+static void __init omap_init_clocksource(unsigned long rate)
 {
-	set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
-	omap_timer.offset = omap_mpu_timer_gettimeoffset;
-	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
-	setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
-	omap_mpu_timer_start(0, 0xffffffff);
-	omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+
+	clocksource_mpu.mult
+		= clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
+
+	setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
+	omap_mpu_timer_start(1, ~0, 1);
+
+	if (clocksource_register(&clocksource_mpu))
+		printk(err, clocksource_mpu.name);
 }
 
+
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
 unsigned long long sched_clock(void)
 {
-	unsigned long ticks = 0 - omap_mpu_timer_read(0);
+	unsigned long ticks = 0 - omap_mpu_timer_read(1);
 	unsigned long long ticks64;
 
-	ticks64 = omap_mpu_timer1_overflows;
+	ticks64 = omap_mpu_timer2_overflows;
 	ticks64 <<= 32;
 	ticks64 |= ticks;
 
@@ -225,10 +274,21 @@ unsigned long long sched_clock(void)
  */
 static void __init omap_timer_init(void)
 {
-	omap_init_mpu_timer();
+	struct clk	*ck_ref = clk_get(NULL, "ck_ref");
+	unsigned long	rate;
+
+	BUG_ON(IS_ERR(ck_ref));
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+
+	/* PTV = 0 */
+	rate /= 2;
+
+	omap_init_mpu_timer(rate);
+	omap_init_clocksource(rate);
 }
 
 struct sys_timer omap_timer = {
 	.init		= omap_timer_init,
-	.offset		= NULL,		/* Initialized later */
 };
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d7eee99..6f4a543 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -370,10 +370,10 @@ static int omap2_pm_finish(suspend_state
 }
 
 static struct pm_ops omap_pm_ops = {
-	.pm_disk_mode	= 0,
 	.prepare	= omap2_pm_prepare,
 	.enter		= omap2_pm_enter,
 	.finish		= omap2_pm_finish,
+	.valid		= pm_valid_only_mem,
 };
 
 int __init omap2_pm_init(void)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 45d1aaa..62e801e 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -52,7 +52,7 @@ static irqreturn_t omap2_gp_timer_interr
 
 static struct irqaction omap2_gp_timer_irq = {
 	.name		= "gp timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= omap2_gp_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
index 3649cd3..2a137f3 100644
--- a/arch/arm/mach-pnx4008/pm.c
+++ b/arch/arm/mach-pnx4008/pm.c
@@ -107,50 +107,19 @@ static int pnx4008_pm_enter(suspend_stat
 	case PM_SUSPEND_MEM:
 		pnx4008_suspend();
 		break;
-	case PM_SUSPEND_DISK:
-		return -ENOTSUPP;
-	default:
-		return -EINVAL;
 	}
 	return 0;
 }
 
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-static int pnx4008_pm_prepare(suspend_state_t state)
-{
-	switch (state) {
-	case PM_SUSPEND_STANDBY:
-	case PM_SUSPEND_MEM:
-		break;
-
-	case PM_SUSPEND_DISK:
-		return -ENOTSUPP;
-		break;
-
-	default:
-		return -EINVAL;
-		break;
-	}
-	return 0;
-}
-
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-static int pnx4008_pm_finish(suspend_state_t state)
+static int pnx4008_pm_valid(suspend_state_t state)
 {
-	return 0;
+	return (state == PM_SUSPEND_STANDBY) ||
+	       (state == PM_SUSPEND_MEM);
 }
 
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
 static struct pm_ops pnx4008_pm_ops = {
-	.prepare = pnx4008_pm_prepare,
 	.enter = pnx4008_pm_enter,
-	.finish = pnx4008_pm_finish,
+	.valid = pnx4008_pm_valid,
 };
 
 static int __init pnx4008_pm_init(void)
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 8621c20..67e05f0 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -82,7 +82,7 @@ static irqreturn_t pnx4008_timer_interru
 
 static struct irqaction pnx4008_timer_irq = {
 	.name = "PNX4008 Tick Timer",
-	.flags = IRQF_DISABLED | IRQF_TIMER,
+	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler = pnx4008_timer_interrupt
 };
 
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index b8cb79f..64b08b7 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -164,9 +164,9 @@ void pxa_set_cken(int clock, int enable)
 	local_irq_save(flags);
 
 	if (enable)
-		CKEN |= clock;
+		CKEN |= (1 << clock);
 	else
-		CKEN &= ~clock;
+		CKEN &= ~(1 << clock);
 
 	local_irq_restore(flags);
 }
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index f815678..4619d5f 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -15,7 +15,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -39,11 +38,33 @@ static void pxa_unmask_low_irq(unsigned 
 	ICMR |= (1 << (irq + PXA_IRQ_SKIP));
 }
 
+static int pxa_set_wake(unsigned int irq, unsigned int on)
+{
+	u32	mask;
+
+	switch (irq) {
+	case IRQ_RTCAlrm:
+		mask = PWER_RTC;
+		break;
+#ifdef CONFIG_PXA27x
+	/* REVISIT can handle USBH1, USBH2, USB, MSL, USIM, ... */
+#endif
+	default:
+		return -EINVAL;
+	}
+	if (on)
+		PWER |= mask;
+	else
+		PWER &= ~mask;
+	return 0;
+}
+
 static struct irq_chip pxa_internal_chip_low = {
 	.name		= "SC",
 	.ack		= pxa_mask_low_irq,
 	.mask		= pxa_mask_low_irq,
 	.unmask		= pxa_unmask_low_irq,
+	.set_wake	= pxa_set_wake,
 };
 
 #if PXA_INTERNAL_IRQS > 32
@@ -71,6 +92,26 @@ static struct irq_chip pxa_internal_chip
 
 #endif
 
+/* Note that if an input/irq line ever gets changed to an output during
+ * suspend, the relevant PWER, PRER, and PFER bits should be cleared.
+ */
+#ifdef CONFIG_PXA27x
+
+/* PXA27x:  Various gpios can issue wakeup events.  This logic only
+ * handles the simple cases, not the WEMUX2 and WEMUX3 options
+ */
+#define PXA27x_GPIO_NOWAKE_MASK \
+	((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2))
+#define	WAKEMASK(gpio) \
+	(((gpio) <= 15) \
+		? ((1 << (gpio)) & ~PXA27x_GPIO_NOWAKE_MASK) \
+		: ((gpio == 35) ? (1 << 24) : 0))
+#else
+
+/* pxa 210, 250, 255, 26x:  gpios 0..15 can issue wakeups */
+#define	WAKEMASK(gpio) (((gpio) <= 15) ? (1 << (gpio)) : 0)
+#endif
+
 /*
  * PXA GPIO edge detection for IRQs:
  * IRQs are generated on Falling-Edge, Rising-Edge, or both.
@@ -84,9 +125,11 @@ static long GPIO_IRQ_mask[4];
 static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
 {
 	int gpio, idx;
+	u32 mask;
 
 	gpio = IRQ_TO_GPIO(irq);
 	idx = gpio >> 5;
+	mask = WAKEMASK(gpio);
 
 	if (type == IRQT_PROBE) {
 	    /* Don't mess with enabled GPIOs using preconfigured edges or
@@ -106,14 +149,20 @@ static int pxa_gpio_irq_type(unsigned in
 	if (type & __IRQT_RISEDGE) {
 		/* printk("rising "); */
 		__set_bit (gpio, GPIO_IRQ_rising_edge);
-	} else
+		PRER |= mask;
+	} else {
 		__clear_bit (gpio, GPIO_IRQ_rising_edge);
+		PRER &= ~mask;
+	}
 
 	if (type & __IRQT_FALEDGE) {
 		/* printk("falling "); */
 		__set_bit (gpio, GPIO_IRQ_falling_edge);
-	} else
+		PFER |= mask;
+	} else {
 		__clear_bit (gpio, GPIO_IRQ_falling_edge);
+		PFER &= ~mask;
+	}
 
 	/* printk("edges\n"); */
 
@@ -131,12 +180,29 @@ static void pxa_ack_low_gpio(unsigned in
 	GEDR0 = (1 << (irq - IRQ_GPIO0));
 }
 
+static int pxa_set_gpio_wake(unsigned int irq, unsigned int on)
+{
+	int	gpio = IRQ_TO_GPIO(irq);
+	u32	mask = WAKEMASK(gpio);
+
+	if (!mask)
+		return -EINVAL;
+
+	if (on)
+		PWER |= mask;
+	else
+		PWER &= ~mask;
+	return 0;
+}
+
+
 static struct irq_chip pxa_low_gpio_chip = {
 	.name		= "GPIO-l",
 	.ack		= pxa_ack_low_gpio,
 	.mask		= pxa_mask_low_irq,
 	.unmask		= pxa_unmask_low_irq,
 	.set_type	= pxa_gpio_irq_type,
+	.set_wake	= pxa_set_gpio_wake,
 };
 
 /*
@@ -245,6 +311,7 @@ static struct irq_chip pxa_muxed_gpio_ch
 	.mask		= pxa_mask_muxed_gpio,
 	.unmask		= pxa_unmask_muxed_gpio,
 	.set_type	= pxa_gpio_irq_type,
+	.set_wake	= pxa_set_gpio_wake,
 };
 
 
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 8e27a64..e309766 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -234,7 +234,7 @@ static void lpd270_backlight_power(int o
 {
 	if (on) {
 		pxa_gpio_mode(GPIO16_PWM0_MD);
-		pxa_set_cken(CKEN0_PWM0, 1);
+		pxa_set_cken(CKEN_PWM0, 1);
 		PWM_CTRL0 = 0;
 		PWM_PWDUTY0 = 0x3ff;
 		PWM_PERVAL0 = 0x3ff;
@@ -242,7 +242,7 @@ static void lpd270_backlight_power(int o
 		PWM_CTRL0 = 0;
 		PWM_PWDUTY0 = 0x0;
 		PWM_PERVAL0 = 0x3FF;
-		pxa_set_cken(CKEN0_PWM0, 0);
+		pxa_set_cken(CKEN_PWM0, 0);
 	}
 }
 
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 055de7f..6377b2e 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -220,7 +220,7 @@ static struct resource pxa_ssp_resources
 
 static struct pxa2xx_spi_master pxa_ssp_master_info = {
 	.ssp_type	= PXA25x_SSP,
-	.clock_enable	= CKEN3_SSP,
+	.clock_enable	= CKEN_SSP,
 	.num_chipselect	= 0,
 };
 
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 56d94d8..ed99a81 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -266,7 +266,7 @@ static void mainstone_backlight_power(in
 {
 	if (on) {
 		pxa_gpio_mode(GPIO16_PWM0_MD);
-		pxa_set_cken(CKEN0_PWM0, 1);
+		pxa_set_cken(CKEN_PWM0, 1);
 		PWM_CTRL0 = 0;
 		PWM_PWDUTY0 = 0x3ff;
 		PWM_PERVAL0 = 0x3ff;
@@ -274,7 +274,7 @@ static void mainstone_backlight_power(in
 		PWM_CTRL0 = 0;
 		PWM_PWDUTY0 = 0x0;
 		PWM_PERVAL0 = 0x3FF;
-		pxa_set_cken(CKEN0_PWM0, 0);
+		pxa_set_cken(CKEN_PWM0, 0);
 	}
 }
 
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index b4d8276..6bf15ae 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -223,14 +223,11 @@ int pxa_pm_finish(suspend_state_t state)
 
 EXPORT_SYMBOL_GPL(pxa_pm_finish);
 
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
 static struct pm_ops pxa_pm_ops = {
-	.pm_disk_mode	= PM_DISK_FIRMWARE,
 	.prepare	= pxa_pm_prepare,
 	.enter		= pxa_pm_enter,
 	.finish		= pxa_pm_finish,
+	.valid		= pm_valid_only_mem,
 };
 
 static int __init pxa_pm_init(void)
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 74eeada..c64bab4 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -140,9 +140,9 @@ void pxa_cpu_pm_enter(suspend_state_t st
 	extern void pxa_cpu_resume(void);
 
 	if (state == PM_SUSPEND_STANDBY)
-		CKEN = CKEN22_MEMC | CKEN9_OSTIMER | CKEN16_LCD |CKEN0_PWM0;
+		CKEN = CKEN_MEMC | CKEN_OSTIMER | CKEN_LCD | CKEN_PWM0;
 	else
-		CKEN = CKEN22_MEMC | CKEN9_OSTIMER;
+		CKEN = CKEN_MEMC | CKEN_OSTIMER;
 
 	/* ensure voltage-change sequencer not initiated, which hangs */
 	PCFR &= ~PCFR_FVC;
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 6cc2027..71766ac 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -52,13 +52,13 @@ struct ssp_info_ {
  */
 static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
 #if defined (CONFIG_PXA27x)
-	{IRQ_SSP,	CKEN23_SSP1},
-	{IRQ_SSP2,	CKEN3_SSP2},
-	{IRQ_SSP3,	CKEN4_SSP3},
+	{IRQ_SSP,	CKEN_SSP1},
+	{IRQ_SSP2,	CKEN_SSP2},
+	{IRQ_SSP3,	CKEN_SSP3},
 #else
-	{IRQ_SSP,	CKEN3_SSP},
-	{IRQ_NSSP,	CKEN9_NSSP},
-	{IRQ_ASSP,	CKEN10_ASSP},
+	{IRQ_SSP,	CKEN_SSP},
+	{IRQ_NSSP,	CKEN_NSSP},
+	{IRQ_ASSP,	CKEN_ASSP},
 #endif
 };
 
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index fc3b82a..5248abe 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -97,7 +97,7 @@ #endif
 
 static struct irqaction pxa_timer_irq = {
 	.name		= "PXA Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= pxa_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 84d3fe7..c7f1b44 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -549,7 +549,7 @@ #endif
 
 static struct irqaction realview_timer_irq = {
 	.name		= "RealView Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= realview_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 208a2b5..570cf93 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -17,6 +17,7 @@ #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/serial_8250.h>
+#include <linux/pata_platform.h>
 
 #include <asm/elf.h>
 #include <asm/io.h>
@@ -159,11 +160,45 @@ static struct platform_device serial_dev
 	},
 };
 
+static struct pata_platform_info pata_platform_data = {
+	.ioport_shift		= 2,
+};
+
+static struct resource pata_resources[] = {
+	[0] = {
+		.start		= 0x030107c0,
+		.end		= 0x030107df,
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start		= 0x03010fd8,
+		.end		= 0x03010fdb,
+		.flags		= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start		= IRQ_HARDDISK,
+		.end		= IRQ_HARDDISK,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device pata_device = {
+	.name			= "pata_platform",
+	.id			= -1,
+	.num_resources		= ARRAY_SIZE(pata_resources),
+	.resource		= pata_resources,
+	.dev			= {
+		.platform_data	= &pata_platform_data,
+		.coherent_dma_mask = ~0,	/* grumble */
+	},
+};
+
 static struct platform_device *devs[] __initdata = {
 	&iomd_device,
 	&kbd_device,
 	&serial_device,
 	&acornfb_device,
+	&pata_device,
 };
 
 static int __init rpc_init(void)
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index daeba42..76a7cb1 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
-#include <linux/ptrace.h>
 #include <linux/sysdev.h>
 
 #include <asm/mach-types.h>
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 53cbdaa..f5c5c53 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -23,7 +23,6 @@ #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 <asm/plat-s3c24xx/cpu.h>
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 72f2cc4..bc308ce 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -160,17 +160,11 @@ #ifdef CONFIG_MTD_PARTITIONS
 #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
@@ -247,6 +241,7 @@ static void __init amlm5900_init(void)
 #ifdef CONFIG_FB_S3C2410
 	s3c24xx_fb_set_platdata(&amlm5900_lcd_info);
 #endif
+	platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices));
 }
 
 MACHINE_START(AML_M5900, "AML_M5900")
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 7b81296..f01de80 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -464,13 +464,6 @@ static struct clk *bast_clocks[] = {
 	&s3c24xx_uclk,
 };
 
-static struct s3c24xx_board bast_board __initdata = {
-	.devices       = bast_devices,
-	.devices_count = ARRAY_SIZE(bast_devices),
-	.clocks	       = bast_clocks,
-	.clocks_count  = ARRAY_SIZE(bast_clocks),
-};
-
 static void __init bast_map_io(void)
 {
 	/* initialise the clocks */
@@ -486,19 +479,22 @@ static void __init bast_map_io(void)
 
 	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
 
+	s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
+
 	s3c_device_nand.dev.platform_data = &bast_nand_info;
 	s3c_device_i2c.dev.platform_data = &bast_i2c_info;
 
 	s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
-	s3c24xx_set_board(&bast_board);
+
 	usb_simtec_init();
 }
 
 static void __init bast_init(void)
 {
 	s3c24xx_fb_set_platdata(&bast_lcd_info);
+	platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
 }
 
 MACHINE_START(BAST, "Simtec-BAST")
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index d052ab2..5d5f00e 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -129,7 +129,6 @@ static struct s3c2410_udc_mach_info h194
 };
 
 
-
 /**
  * Set lcd on or off
  **/
@@ -188,17 +187,11 @@ static struct platform_device *h1940_dev
 	&s3c_device_leds,
 };
 
-static struct s3c24xx_board h1940_board __initdata = {
-	.devices       = h1940_devices,
-	.devices_count = ARRAY_SIZE(h1940_devices)
-};
-
 static void __init h1940_map_io(void)
 {
 	s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
-	s3c24xx_set_board(&h1940_board);
 
 	/* setup PM */
 
@@ -232,6 +225,8 @@ static void __init h1940_init(void)
 	      | (0x02 << S3C2410_PLLCON_PDIVSHIFT)
 	      | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
 	writel(tmp, S3C2410_UPLLCON);
+
+	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
 }
 
 MACHINE_START(H1940, "IPAQ-H1940")
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 261aa4c..412e50c 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -90,17 +90,11 @@ static struct s3c2410_platform_i2c n30_i
 	.max_freq	= 10*1000,
 };
 
-static struct s3c24xx_board n30_board __initdata = {
-	.devices       = n30_devices,
-	.devices_count = ARRAY_SIZE(n30_devices)
-};
-
 static void __init n30_map_io(void)
 {
 	s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
-	s3c24xx_set_board(&n30_board);
 }
 
 static void __init n30_init_irq(void)
@@ -120,6 +114,8 @@ static void __init n30_init(void)
 	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
 			      S3C2410_MISCCR_USBSUSPND0 |
 			      S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+	platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
 }
 
 MACHINE_START(N30, "Acer-N30")
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index c78ab75..1f899fa 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -100,20 +100,17 @@ static struct platform_device *otom11_de
 	&otom_device_nor,
 };
 
-static struct s3c24xx_board otom11_board __initdata = {
-	.devices       = otom11_devices,
-	.devices_count = ARRAY_SIZE(otom11_devices)
-};
-
-
 static void __init otom11_map_io(void)
 {
 	s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
-	s3c24xx_set_board(&otom11_board);
 }
 
+static void __init otom11_init(void)
+{
+	platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices));
+}
 
 MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
@@ -121,6 +118,7 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= otom11_map_io,
+	.init_machine	= otom11_init,
 	.init_irq	= s3c24xx_init_irq,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index c6a4159..9cc4253 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -29,7 +29,6 @@ #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
-#include <linux/mmc/protocol.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 
@@ -331,11 +330,6 @@ static struct platform_device *qt2410_de
 	&qt2410_led,
 };
 
-static struct s3c24xx_board qt2410_board __initdata = {
-	.devices       = qt2410_devices,
-	.devices_count = ARRAY_SIZE(qt2410_devices)
-};
-
 static struct mtd_partition qt2410_nand_part[] = {
 	[0] = {
 		.name	= "U-Boot",
@@ -405,7 +399,6 @@ static void __init qt2410_map_io(void)
 	s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc));
 	s3c24xx_init_clocks(12*1000*1000);
 	s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
-	s3c24xx_set_board(&qt2410_board);
 }
 
 static void __init qt2410_machine_init(void)
@@ -432,6 +425,7 @@ static void __init qt2410_machine_init(v
 
 	s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
 
+	platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
 	s3c2410_pm_init();
 }
 
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 57b8a80..5852d30 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -94,17 +94,17 @@ static struct platform_device *smdk2410_
 	&s3c_device_iis,
 };
 
-static struct s3c24xx_board smdk2410_board __initdata = {
-	.devices       = smdk2410_devices,
-	.devices_count = ARRAY_SIZE(smdk2410_devices)
-};
-
 static void __init smdk2410_map_io(void)
 {
 	s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
-	s3c24xx_set_board(&smdk2410_board);
+}
+
+static void __init smdk2410_init(void)
+{
+	platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
+	smdk_machine_init();
 }
 
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
@@ -115,7 +115,7 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= smdk2410_map_io,
 	.init_irq	= s3c24xx_init_irq,
-	.init_machine	= smdk_machine_init,
+	.init_machine	= smdk2410_init,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
 
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index c947c75..7b624bb 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -384,13 +384,6 @@ static struct clk *vr1000_clocks[] = {
 	&s3c24xx_uclk,
 };
 
-static struct s3c24xx_board vr1000_board __initdata = {
-	.devices       = vr1000_devices,
-	.devices_count = ARRAY_SIZE(vr1000_devices),
-	.clocks	       = vr1000_clocks,
-	.clocks_count  = ARRAY_SIZE(vr1000_clocks),
-};
-
 static void vr1000_power_off(void)
 {
 	s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
@@ -412,15 +405,19 @@ static void __init vr1000_map_io(void)
 
 	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
 
+	s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
+
 	pm_power_off = vr1000_power_off;
 
 	s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
-	s3c24xx_set_board(&vr1000_board);
-	usb_simtec_init();
 }
 
+static void __init vr1000_init(void)
+{
+	platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
+}
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
@@ -428,6 +425,7 @@ MACHINE_START(VR1000, "Thorcom-VR1000")
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= vr1000_map_io,
+	.init_machine	= vr1000_init,
 	.init_irq	= s3c24xx_init_irq,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index befc5fd..d5be5d0 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -47,6 +47,15 @@ config MACH_S3C2413
 	  machine_is_s3c2413() will work when MACH_SMDK2413 is
 	  selected
 
+config MACH_SMDK2412
+	bool "SMDK2412"
+	select MACH_SMDK2413
+	help
+	  Say Y here if you are using an SMDK2412
+
+	  Note, this shares support with SMDK2413, so will automatically
+	  select MACH_SMDK2413.
+
 config MACH_VSTMS
 	bool "VMSTMS"
 	select CPU_S3C2412
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index e89dbdc..f0d6682 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -23,7 +23,6 @@ #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 <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index b5befce..063af09 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -110,11 +110,6 @@ static struct platform_device *smdk2413_
 	&s3c_device_usbgadget,
 };
 
-static struct s3c24xx_board smdk2413_board __initdata = {
-	.devices       = smdk2413_devices,
-	.devices_count = ARRAY_SIZE(smdk2413_devices)
-};
-
 static void __init smdk2413_fixup(struct machine_desc *desc,
 				  struct tag *tags, char **cmdline,
 				  struct meminfo *mi)
@@ -132,7 +127,6 @@ static void __init smdk2413_map_io(void)
 	s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
 	s3c24xx_init_clocks(12000000);
 	s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
-	s3c24xx_set_board(&smdk2413_board);
 }
 
 static void __init smdk2413_machine_init(void)
@@ -149,6 +143,7 @@ static void __init smdk2413_machine_init
 
  	s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
 
+	platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices));
 	smdk_machine_init();
 }
 
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 4231b54..f2fbd65 100644
--- a/arch/arm/mach-s3c2412/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -129,11 +129,6 @@ static struct platform_device *vstms_dev
 	&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)
@@ -153,7 +148,11 @@ static void __init vstms_map_io(void)
 	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);
+}
+
+static void __init vstms_init(void)
+{
+	platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
 }
 
 MACHINE_START(VSTMS, "VSTMS")
@@ -163,6 +162,7 @@ MACHINE_START(VSTMS, "VSTMS")
 
 	.fixup		= vstms_fixup,
 	.init_irq	= s3c24xx_init_irq,
+	.init_machine	= vstms_init,
 	.map_io		= vstms_map_io,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
index 1069d13..a87608b 100644
--- a/arch/arm/mach-s3c2440/irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -23,7 +23,6 @@ #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 <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 3f0288e..b5d387e 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -281,13 +281,6 @@ static struct clk *anubis_clocks[] = {
 	&s3c24xx_uclk,
 };
 
-static struct s3c24xx_board anubis_board __initdata = {
-	.devices       = anubis_devices,
-	.devices_count = ARRAY_SIZE(anubis_devices),
-	.clocks	       = anubis_clocks,
-	.clocks_count  = ARRAY_SIZE(anubis_clocks),
-};
-
 static void __init anubis_map_io(void)
 {
 	/* initialise the clocks */
@@ -303,23 +296,31 @@ static void __init anubis_map_io(void)
 
 	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
 
+	s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
+
 	s3c_device_nand.dev.platform_data = &anubis_nand_info;
 
 	s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
-	s3c24xx_set_board(&anubis_board);
 
 	/* ensure that the GPIO is setup */
 	s3c2410_gpio_setpin(S3C2410_GPA0, 1);
 }
 
+static void __init anubis_init(void)
+{
+	platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
+}
+
+
 MACHINE_START(ANUBIS, "Simtec-Anubis")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= anubis_map_io,
+	.init_machine	= anubis_init,
 	.init_irq	= s3c24xx_init_irq,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 6d551d8..5e61f21 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -116,12 +116,6 @@ static struct platform_device *nexcoder_
 	&nexcoder_device_nor,
 };
 
-static struct s3c24xx_board nexcoder_board __initdata = {
-	.devices       = nexcoder_devices,
-	.devices_count = ARRAY_SIZE(nexcoder_devices),
-};
-
-
 static void __init nexcoder_sensorboard_init(void)
 {
 	// Initialize SCCB bus
@@ -142,10 +136,14 @@ static void __init nexcoder_map_io(void)
 	s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
-	s3c24xx_set_board(&nexcoder_board);
+
 	nexcoder_sensorboard_init();
 }
 
+static void __init nexcoder_init(void)
+{
+	platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices));
+};
 
 MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
@@ -153,6 +151,7 @@ MACHINE_START(NEXCODER_2440, "NexVision 
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= nexcoder_map_io,
+	.init_machine	= nexcoder_init,
 	.init_irq	= s3c24xx_init_irq,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 2ed8e51..324f5a2 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -251,13 +251,6 @@ static struct clk *osiris_clocks[] = {
 	&s3c24xx_uclk,
 };
 
-static struct s3c24xx_board osiris_board __initdata = {
-	.devices       = osiris_devices,
-	.devices_count = ARRAY_SIZE(osiris_devices),
-	.clocks	       = osiris_clocks,
-	.clocks_count  = ARRAY_SIZE(osiris_clocks),
-};
-
 static void __init osiris_map_io(void)
 {
 	unsigned long flags;
@@ -275,12 +268,13 @@ static void __init osiris_map_io(void)
 
 	s3c24xx_uclk.parent  = &s3c24xx_clkout1;
 
+	s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
+
 	s3c_device_nand.dev.platform_data = &osiris_nand_info;
 
 	s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
 	s3c24xx_init_clocks(0);
 	s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
-	s3c24xx_set_board(&osiris_board);
 
 	/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
 
@@ -292,12 +286,18 @@ static void __init osiris_map_io(void)
 	s3c2410_gpio_setpin(S3C2410_GPA0, 1);
 }
 
+static void __init osiris_init(void)
+{
+	platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
+};
+
 MACHINE_START(OSIRIS, "Simtec-OSIRIS")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
 	.phys_io	= S3C2410_PA_UART,
 	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= osiris_map_io,
+	.init_machine	= osiris_init,
 	.init_irq	= s3c24xx_init_irq,
 	.timer		= &s3c24xx_timer,
 MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index ae1d0a8..c3cc4bf 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -202,11 +202,6 @@ static struct platform_device *rx3715_de
 	&s3c_device_nand,
 };
 
-static struct s3c24xx_board rx3715_board __initdata = {
-	.devices       = rx3715_devices,
-	.devices_count = ARRAY_SIZE(rx3715_devices)
-};
-
 static void __init rx3715_map_io(void)
 {
 	s3c_device_nand.dev.platform_data = &rx3715_nand_info;
@@ -214,7 +209,6 @@ static void __init rx3715_map_io(void)
 	s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
 	s3c24xx_init_clocks(16934000);
 	s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
-	s3c24xx_set_board(&rx3715_board);
 }
 
 static void __init rx3715_init_irq(void)
@@ -230,9 +224,9 @@ #endif
 	s3c2410_pm_init();
 
 	s3c24xx_fb_set_platdata(&rx3715_lcdcfg);
+	platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
 }
 
-
 MACHINE_START(RX3715, "IPAQ-RX3715")
 	/* Maintainer: Ben Dooks <ben@fluff.org> */
 	.phys_io	= S3C2410_PA_UART,
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index c17eb5b..e167254 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -174,23 +174,18 @@ static struct platform_device *smdk2440_
 	&s3c_device_iis,
 };
 
-static struct s3c24xx_board smdk2440_board __initdata = {
-	.devices       = smdk2440_devices,
-	.devices_count = ARRAY_SIZE(smdk2440_devices)
-};
-
 static void __init smdk2440_map_io(void)
 {
 	s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
 	s3c24xx_init_clocks(16934400);
 	s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
-	s3c24xx_set_board(&smdk2440_board);
 }
 
 static void __init smdk2440_machine_init(void)
 {
 	s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
 
+	platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
 	smdk_machine_init();
 }
 
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
index 7565735..6cd4818 100644
--- a/arch/arm/mach-s3c2443/irq.c
+++ b/arch/arm/mach-s3c2443/irq.c
@@ -23,7 +23,6 @@ #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 <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
index e82aaff..b71ee53 100644
--- a/arch/arm/mach-s3c2443/mach-smdk2443.c
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -106,21 +106,16 @@ static struct platform_device *smdk2443_
 	&s3c_device_i2c,
 };
 
-static struct s3c24xx_board smdk2443_board __initdata = {
-	.devices       = smdk2443_devices,
-	.devices_count = ARRAY_SIZE(smdk2443_devices)
-};
-
 static void __init smdk2443_map_io(void)
 {
 	s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
 	s3c24xx_init_clocks(12000000);
 	s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
-	s3c24xx_set_board(&smdk2443_board);
 }
 
 static void __init smdk2443_machine_init(void)
 {
+	platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices));
 	smdk_machine_init();
 }
 
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index b1e8fd7..fc97fe5 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -9,14 +9,17 @@ #include <linux/err.h>
 #include <linux/string.h>
 #include <linux/clk.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 
 #include <asm/hardware.h>
-#include <asm/semaphore.h>
 
+/*
+ * Very simple clock implementation - we only have one clock to
+ * deal with at the moment, so we only match using the "name".
+ */
 struct clk {
 	struct list_head	node;
 	unsigned long		rate;
-	struct module		*owner;
 	const char		*name;
 	unsigned int		enabled;
 	void			(*enable)(void);
@@ -24,21 +27,21 @@ struct clk {
 };
 
 static LIST_HEAD(clocks);
-static DECLARE_MUTEX(clocks_sem);
+static DEFINE_MUTEX(clocks_mutex);
 static DEFINE_SPINLOCK(clocks_lock);
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
 	struct clk *p, *clk = ERR_PTR(-ENOENT);
 
-	down(&clocks_sem);
+	mutex_lock(&clocks_mutex);
 	list_for_each_entry(p, &clocks, node) {
-		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+		if (strcmp(id, p->name) == 0) {
 			clk = p;
 			break;
 		}
 	}
-	up(&clocks_sem);
+	mutex_unlock(&clocks_mutex);
 
 	return clk;
 }
@@ -46,7 +49,6 @@ EXPORT_SYMBOL(clk_get);
 
 void clk_put(struct clk *clk)
 {
-	module_put(clk->owner);
 }
 EXPORT_SYMBOL(clk_put);
 
@@ -109,18 +111,18 @@ static struct clk clk_gpio27 = {
 
 int clk_register(struct clk *clk)
 {
-	down(&clocks_sem);
+	mutex_lock(&clocks_mutex);
 	list_add(&clk->node, &clocks);
-	up(&clocks_sem);
+	mutex_unlock(&clocks_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(clk_register);
 
 void clk_unregister(struct clk *clk)
 {
-	down(&clocks_sem);
+	mutex_lock(&clocks_mutex);
 	list_del(&clk->node);
-	up(&clocks_sem);
+	mutex_unlock(&clocks_mutex);
 }
 EXPORT_SYMBOL(clk_unregister);
 
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index b034ad6..b72fee0 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -740,7 +740,7 @@ static void h3800_IRQ_demux(unsigned int
 static struct irqaction h3800_irq = {
 	.name		= "h3800_asic",
 	.handler	= h3800_IRQ_demux,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
 u32 kpio_int_shadow = 0;
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 5642aec..edf3347 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -14,7 +14,6 @@ #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/ioport.h>
-#include <linux/ptrace.h>
 #include <linux/sysdev.h>
 
 #include <asm/hardware.h>
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 075d4d1..d7c038a 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -4,7 +4,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/ptrace.h>
 #include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/serial_core.h>
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index 786c853..d674cf3 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -59,9 +59,6 @@ static int sa11x0_pm_enter(suspend_state
 	unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
 	struct timespec delta, rtc;
 
-	if (state != PM_SUSPEND_MEM)
-		return -EINVAL;
-
 	/* preserve current time */
 	rtc.tv_sec = RCNR;
 	rtc.tv_nsec = 0;
@@ -134,12 +131,9 @@ unsigned long sleep_phys_sp(void *sp)
 	return virt_to_phys(sp);
 }
 
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
 static struct pm_ops sa11x0_pm_ops = {
-	.pm_disk_mode	= PM_DISK_FIRMWARE,
 	.enter		= sa11x0_pm_enter,
+	.valid		= pm_valid_only_mem,
 };
 
 static int __init sa11x0_pm_init(void)
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 29c89f9..416e277 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -111,7 +111,7 @@ #endif
 
 static struct irqaction sa1100_timer_irq = {
 	.name		= "SA11xx Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= sa1100_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 0e480fa..a0545db 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -90,7 +90,7 @@ shark_timer_interrupt(int irq, void *dev
 
 static struct irqaction shark_timer_irq = {
 	.name		= "Shark Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= shark_timer_interrupt,
 };
 
diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
index 00a6c14..5b0c6af 100644
--- a/arch/arm/mach-shark/irq.c
+++ b/arch/arm/mach-shark/irq.c
@@ -10,7 +10,6 @@
 
 #include <linux/init.h>
 #include <linux/fs.h>
-#include <linux/ptrace.h>
 #include <linux/interrupt.h>
 
 #include <asm/irq.h>
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index bf71507..a7dd094 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -26,6 +26,8 @@ #include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/cnt32_to_63.h>
 #include <asm/system.h>
@@ -828,69 +830,101 @@ #define TIMER_DIVISOR	(TIMER_CTRL_DIV1)
 #define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
 #endif
 
-/*
- * Returns number of ms since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long versatile_gettimeoffset(void)
+static void timer_set_mode(enum clock_event_mode mode,
+			   struct clock_event_device *clk)
 {
-	unsigned long ticks1, ticks2, status;
+	unsigned long ctrl;
 
-	/*
-	 * Get the current number of ticks.  Note that there is a race
-	 * condition between us reading the timer and checking for
-	 * an interrupt.  We get around this by ensuring that the
-	 * counter has not reloaded between our two reads.
-	 */
-	ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
-	do {
-		ticks1 = ticks2;
-		status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS);
-		ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
-	} while (ticks2 > ticks1);
+	switch(mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
 
-	/*
-	 * Number of ticks since last interrupt.
-	 */
-	ticks1 = TIMER_RELOAD - ticks2;
+		ctrl = TIMER_CTRL_PERIODIC;
+		ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* period set, and timer enabled in 'next_event' hook */
+		ctrl = TIMER_CTRL_ONESHOT;
+		ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		ctrl = 0;
+	}
 
-	/*
-	 * Interrupt pending?  If so, we've reloaded once already.
-	 *
-	 * FIXME: Need to check this is effectively timer 0 that expires
-	 */
-	if (status & IRQMASK_TIMERINT0_1)
-		ticks1 += TIMER_RELOAD;
+	writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
+}
 
-	/*
-	 * Convert the ticks to usecs
-	 */
-	return TICKS2USECS(ticks1);
+static int timer_set_next_event(unsigned long evt,
+				struct clock_event_device *unused)
+{
+	unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
+
+	writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
+	writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
+
+	return 0;
 }
 
+static struct clock_event_device timer0_clockevent =	 {
+	.name		= "timer0",
+	.shift		= 32,
+	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= timer_set_mode,
+	.set_next_event	= timer_set_next_event,
+};
+
 /*
  * IRQ handler for the timer
  */
 static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
 {
-	write_seqlock(&xtime_lock);
+	struct clock_event_device *evt = &timer0_clockevent;
 
-	// ...clear the interrupt
 	writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
 
-	timer_tick();
-
-	write_sequnlock(&xtime_lock);
+	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
 }
 
 static struct irqaction versatile_timer_irq = {
 	.name		= "Versatile Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= versatile_timer_interrupt,
 };
 
+static cycle_t versatile_get_cycles(void)
+{
+	return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_versatile = {
+	.name 		= "timer3",
+ 	.rating		= 200,
+ 	.read		= versatile_get_cycles,
+	.mask		= CLOCKSOURCE_MASK(32),
+ 	.shift 		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init versatile_clocksource_init(void)
+{
+	/* setup timer3 as free-running clocksource */
+	writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+	writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
+	writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
+	writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+	       TIMER3_VA_BASE + TIMER_CTRL);
+
+ 	clocksource_versatile.mult =
+ 		clocksource_khz2mult(1000, clocksource_versatile.shift);
+ 	clocksource_register(&clocksource_versatile);
+
+ 	return 0;
+}
+
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
@@ -918,18 +952,25 @@ static void __init versatile_timer_init(
 	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
 	writel(0, TIMER3_VA_BASE + TIMER_CTRL);
 
-	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
-	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
-	writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
-	       TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
-
 	/* 
 	 * Make irqs happen for the system timer
 	 */
 	setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq);
+
+	versatile_clocksource_init();
+
+	timer0_clockevent.mult =
+		div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+	timer0_clockevent.max_delta_ns =
+		clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+	timer0_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xf, &timer0_clockevent);
+
+	timer0_clockevent.cpumask = cpumask_of_cpu(0);
+	clockevents_register_device(&timer0_clockevent);
 }
 
 struct sys_timer versatile_timer = {
 	.init		= versatile_timer_init,
-	.offset		= versatile_gettimeoffset,
 };
+
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 5cd0b5d..ba58223 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -16,7 +16,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index aa109f0..19ca333 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -15,7 +15,6 @@ #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#include <linux/ptrace.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 9fd6d2e..75d4914 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -10,7 +10,6 @@
  */
 #include <linux/module.h>
 #include <linux/signal.h>
-#include <linux/ptrace.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 
@@ -438,7 +437,7 @@ hook_fault_code(int nr, int (*fn)(unsign
 /*
  * Dispatch a data abort to the relevant handler.
  */
-asmlinkage void
+asmlinkage void __exception
 do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
 	const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
@@ -454,10 +453,10 @@ do_DataAbort(unsigned long addr, unsigne
 	info.si_errno = 0;
 	info.si_code  = inf->code;
 	info.si_addr  = (void __user *)addr;
-	notify_die("", regs, &info, fsr, 0);
+	arm_notify_die("", regs, &info, fsr, 0);
 }
 
-asmlinkage void
+asmlinkage void __exception
 do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
 	do_translation_fault(addr, 0, regs);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 7760193..c0ad7c0 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -9,7 +9,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/ptrace.h>
 #include <linux/swap.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 0ac615c..d6167ad 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -32,6 +32,9 @@ #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/sizes.h>
 
+#include <asm/mach/map.h>
+#include "mm.h"
+
 /*
  * Used by ioremap() and iounmap() code to mark (super)section-mapped
  * I/O regions in vm_struct->flags field.
@@ -39,8 +42,9 @@ #include <asm/sizes.h>
 #define VM_ARM_SECTION_MAPPING	0x80000000
 
 static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
-			  unsigned long phys_addr, pgprot_t prot)
+			  unsigned long phys_addr, const struct mem_type *type)
 {
+	pgprot_t prot = __pgprot(type->prot_pte);
 	pte_t *pte;
 
 	pte = pte_alloc_kernel(pmd, addr);
@@ -51,7 +55,8 @@ static int remap_area_pte(pmd_t *pmd, un
 		if (!pte_none(*pte))
 			goto bad;
 
-		set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0);
+		set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot),
+			    type->prot_pte_ext);
 		phys_addr += PAGE_SIZE;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 	return 0;
@@ -63,7 +68,7 @@ static int remap_area_pte(pmd_t *pmd, un
 
 static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
 				 unsigned long end, unsigned long phys_addr,
-				 pgprot_t prot)
+				 const struct mem_type *type)
 {
 	unsigned long next;
 	pmd_t *pmd;
@@ -75,7 +80,7 @@ static inline int remap_area_pmd(pgd_t *
 
 	do {
 		next = pmd_addr_end(addr, end);
-		ret = remap_area_pte(pmd, addr, next, phys_addr, prot);
+		ret = remap_area_pte(pmd, addr, next, phys_addr, type);
 		if (ret)
 			return ret;
 		phys_addr += next - addr;
@@ -84,13 +89,11 @@ static inline int remap_area_pmd(pgd_t *
 }
 
 static int remap_area_pages(unsigned long start, unsigned long pfn,
-			    unsigned long size, unsigned long flags)
+			    size_t size, const struct mem_type *type)
 {
 	unsigned long addr = start;
 	unsigned long next, end = start + size;
 	unsigned long phys_addr = __pfn_to_phys(pfn);
-	pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
-				 L_PTE_DIRTY | L_PTE_WRITE | flags);
 	pgd_t *pgd;
 	int err = 0;
 
@@ -98,7 +101,7 @@ static int remap_area_pages(unsigned lon
 	pgd = pgd_offset_k(addr);
 	do {
 		next = pgd_addr_end(addr, end);
-		err = remap_area_pmd(pgd, addr, next, phys_addr, prot);
+		err = remap_area_pmd(pgd, addr, next, phys_addr, type);
 		if (err)
 			break;
 		phys_addr += next - addr;
@@ -178,9 +181,9 @@ static void unmap_area_sections(unsigned
 
 static int
 remap_area_sections(unsigned long virt, unsigned long pfn,
-		    unsigned long size, unsigned long flags)
+		    size_t size, const struct mem_type *type)
 {
-	unsigned long prot, addr = virt, end = virt + size;
+	unsigned long addr = virt, end = virt + size;
 	pgd_t *pgd;
 
 	/*
@@ -189,23 +192,13 @@ remap_area_sections(unsigned long virt, 
 	 */
 	unmap_area_sections(virt, size);
 
-	prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO) |
-	       (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE));
-
-	/*
-	 * ARMv6 and above need XN set to prevent speculative prefetches
-	 * hitting IO.
-	 */
-	if (cpu_architecture() >= CPU_ARCH_ARMv6)
-		prot |= PMD_SECT_XN;
-
 	pgd = pgd_offset_k(addr);
 	do {
 		pmd_t *pmd = pmd_offset(pgd, addr);
 
-		pmd[0] = __pmd(__pfn_to_phys(pfn) | prot);
+		pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
 		pfn += SZ_1M >> PAGE_SHIFT;
-		pmd[1] = __pmd(__pfn_to_phys(pfn) | prot);
+		pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
 		pfn += SZ_1M >> PAGE_SHIFT;
 		flush_pmd_entry(pmd);
 
@@ -218,9 +211,9 @@ remap_area_sections(unsigned long virt, 
 
 static int
 remap_area_supersections(unsigned long virt, unsigned long pfn,
-			 unsigned long size, unsigned long flags)
+			 size_t size, const struct mem_type *type)
 {
-	unsigned long prot, addr = virt, end = virt + size;
+	unsigned long addr = virt, end = virt + size;
 	pgd_t *pgd;
 
 	/*
@@ -229,22 +222,12 @@ remap_area_supersections(unsigned long v
 	 */
 	unmap_area_sections(virt, size);
 
-	prot = PMD_TYPE_SECT | PMD_SECT_SUPER | PMD_SECT_AP_WRITE |
-			PMD_DOMAIN(DOMAIN_IO) |
-			(flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE));
-
-	/*
-	 * ARMv6 and above need XN set to prevent speculative prefetches
-	 * hitting IO.
-	 */
-	if (cpu_architecture() >= CPU_ARCH_ARMv6)
-		prot |= PMD_SECT_XN;
-
 	pgd = pgd_offset_k(virt);
 	do {
 		unsigned long super_pmd_val, i;
 
-		super_pmd_val = __pfn_to_phys(pfn) | prot;
+		super_pmd_val = __pfn_to_phys(pfn) | type->prot_sect |
+				PMD_SECT_SUPER;
 		super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20;
 
 		for (i = 0; i < 8; i++) {
@@ -279,9 +262,10 @@ #endif
  * mapping.  See include/asm-arm/proc-armv/pgtable.h for more information.
  */
 void __iomem *
-__ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
-	      unsigned long flags)
+__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
+		  unsigned int mtype)
 {
+	const struct mem_type *type;
 	int err;
 	unsigned long addr;
  	struct vm_struct * area;
@@ -292,6 +276,10 @@ __ioremap_pfn(unsigned long pfn, unsigne
 	if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
 		return NULL;
 
+	type = get_mem_type(mtype);
+	if (!type)
+		return NULL;
+
 	size = PAGE_ALIGN(size);
 
  	area = get_vm_area(size, VM_IOREMAP);
@@ -302,16 +290,16 @@ __ioremap_pfn(unsigned long pfn, unsigne
 #ifndef CONFIG_SMP
 	if (DOMAIN_IO == 0 &&
 	    (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
-	       cpu_is_xsc3()) &&
+	       cpu_is_xsc3()) && pfn >= 0x100000 &&
 	       !((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
 		area->flags |= VM_ARM_SECTION_MAPPING;
-		err = remap_area_supersections(addr, pfn, size, flags);
+		err = remap_area_supersections(addr, pfn, size, type);
 	} else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
 		area->flags |= VM_ARM_SECTION_MAPPING;
-		err = remap_area_sections(addr, pfn, size, flags);
+		err = remap_area_sections(addr, pfn, size, type);
 	} else
 #endif
-		err = remap_area_pages(addr, pfn, size, flags);
+		err = remap_area_pages(addr, pfn, size, type);
 
 	if (err) {
  		vunmap((void *)addr);
@@ -321,10 +309,10 @@ #endif
 	flush_cache_vmap(addr, addr + size);
 	return (void __iomem *) (offset + addr);
 }
-EXPORT_SYMBOL(__ioremap_pfn);
+EXPORT_SYMBOL(__arm_ioremap_pfn);
 
 void __iomem *
-__ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
+__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
 {
 	unsigned long last_addr;
  	unsigned long offset = phys_addr & ~PAGE_MASK;
@@ -342,9 +330,9 @@ __ioremap(unsigned long phys_addr, size_
 	 */
 	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
- 	return __ioremap_pfn(pfn, offset, size, flags);
+ 	return __arm_ioremap_pfn(pfn, offset, size, mtype);
 }
-EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(__arm_ioremap);
 
 void __iounmap(volatile void __iomem *addr)
 {
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a44e309..7647c59 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -16,6 +16,16 @@ static inline pmd_t *pmd_off_k(unsigned 
 	return pmd_off(pgd_offset_k(virt), virt);
 }
 
+struct mem_type {
+	unsigned int prot_pte;
+	unsigned int prot_pte_ext;
+	unsigned int prot_l1;
+	unsigned int prot_sect;
+	unsigned int domain;
+};
+
+const struct mem_type *get_mem_type(unsigned int type);
+
 #endif
 
 struct map_desc;
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index b0b5f46..2c4c242 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -49,8 +49,7 @@ #define aliasing 0
 #endif
 
 	/*
-	 * We should enforce the MAP_FIXED case.  However, currently
-	 * the generic kernel code doesn't allow us to handle this.
+	 * We enforce the MAP_FIXED case.
 	 */
 	if (flags & MAP_FIXED) {
 		if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1))
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 94fd4bf..2ba1530 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -176,28 +176,42 @@ void adjust_cr(unsigned long mask, unsig
 }
 #endif
 
-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,
+#define PROT_PTE_DEVICE		L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_WRITE
+#define PROT_SECT_DEVICE	PMD_TYPE_SECT|PMD_SECT_XN|PMD_SECT_AP_WRITE
+
+static struct mem_type mem_types[] = {
+	[MT_DEVICE] = {		  /* Strongly ordered / ARMv6 shared device */
+		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_l1	= PMD_TYPE_TABLE,
+		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_UNCACHED,
+		.domain		= DOMAIN_IO,
+	},
+	[MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */
+		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_pte_ext	= PTE_EXT_TEX(2),
+		.prot_l1	= PMD_TYPE_TABLE,
+		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_TEX(2),
+		.domain		= DOMAIN_IO,
+	},
+	[MT_DEVICE_CACHED] = {	  /* ioremap_cached */
+		.prot_pte	= PROT_PTE_DEVICE | L_PTE_CACHEABLE | L_PTE_BUFFERABLE,
+		.prot_l1	= PMD_TYPE_TABLE,
+		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_WB,
+		.domain		= DOMAIN_IO,
+	},	
+	[MT_DEVICE_IXP2000] = {	  /* IXP2400 requires XCB=101 for on-chip I/O */
+		.prot_pte	= PROT_PTE_DEVICE,
+		.prot_l1	= PMD_TYPE_TABLE,
+		.prot_sect	= PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE |
+				  PMD_SECT_TEX(1),
+		.domain		= DOMAIN_IO,
 	},
 	[MT_CACHECLEAN] = {
-		.prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MINICLEAN] = {
-		.prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_LOW_VECTORS] = {
@@ -213,30 +227,20 @@ static struct mem_types mem_types[] __in
 		.domain    = DOMAIN_USER,
 	},
 	[MT_MEMORY] = {
-		.prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_ROM] = {
-		.prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+		.prot_sect = PMD_TYPE_SECT,
 		.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,
-	}
 };
 
+const struct mem_type *get_mem_type(unsigned int type)
+{
+	return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
+}
+
 /*
  * Adjust the PMD section entries according to the CPU in use.
  */
@@ -262,20 +266,23 @@ #endif
 	}
 
 	/*
-	 * Xscale must not have PMD bit 4 set for section mappings.
+	 * ARMv5 and lower, bit 4 must be set for page tables.
+	 * (was: cache "update-able on write" bit on ARM610)
+	 * However, Xscale cores require this bit to be cleared.
 	 */
-	if (cpu_is_xscale())
-		for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+	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++)
+			mem_types[i].prot_l1 &= ~PMD_BIT4;
+		}
+	} else if (cpu_arch < CPU_ARCH_ARMv6) {
+		for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
 			if (mem_types[i].prot_l1)
 				mem_types[i].prot_l1 |= PMD_BIT4;
+			if (mem_types[i].prot_sect)
+				mem_types[i].prot_sect |= PMD_BIT4;
+		}
+	}
 
 	cp = &cache_policies[cachepolicy];
 	kern_pgprot = user_pgprot = cp->pte;
@@ -296,13 +303,6 @@ #endif
 	 */
 	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.
 		 */
@@ -368,64 +368,126 @@ #endif
 	}
 	printk("Memory policy: ECC %sabled, Data cache %s\n",
 		ecc_mask ? "en" : "dis", cp->policy);
+
+	for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
+		struct mem_type *t = &mem_types[i];
+		if (t->prot_l1)
+			t->prot_l1 |= PMD_DOMAIN(t->domain);
+		if (t->prot_sect)
+			t->prot_sect |= PMD_DOMAIN(t->domain);
+	}
 }
 
 #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)
+static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
+				  unsigned long end, unsigned long pfn,
+				  const struct mem_type *type)
 {
-	pmd_t *pmdp = pmd_off_k(virt);
+	pte_t *pte;
 
-	if (virt & (1 << 20))
-		pmdp++;
+	if (pmd_none(*pmd)) {
+		pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
+		__pmd_populate(pmd, __pa(pte) | type->prot_l1);
+	}
 
-	*pmdp = __pmd(phys | prot);
-	flush_pmd_entry(pmdp);
+	pte = pte_offset_kernel(pmd, addr);
+	do {
+		set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)),
+			    type->prot_pte_ext);
+		pfn++;
+	} while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
-/*
- * 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)
+static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
+				      unsigned long end, unsigned long phys,
+				      const struct mem_type *type)
 {
-	int i;
+	pmd_t *pmd = pmd_offset(pgd, addr);
+
+	/*
+	 * Try a section mapping - end, addr and phys must all be aligned
+	 * to a section boundary.  Note that PMDs refer to the individual
+	 * L1 entries, whereas PGDs refer to a group of L1 entries making
+	 * up one logical pointer to an L2 table.
+	 */
+	if (((addr | end | phys) & ~SECTION_MASK) == 0) {
+		pmd_t *p = pmd;
+
+		if (addr & SECTION_SIZE)
+			pmd++;
 
-	for (i = 0; i < 16; i += 1) {
-		alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
+		do {
+			*pmd = __pmd(phys | type->prot_sect);
+			phys += SECTION_SIZE;
+		} while (pmd++, addr += SECTION_SIZE, addr != end);
 
-		virt += (PGDIR_SIZE / 2);
+		flush_pmd_entry(p);
+	} else {
+		/*
+		 * No need to loop; pte's aren't interested in the
+		 * individual L1 entries.
+		 */
+		alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
 	}
 }
 
-/*
- * 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)
+static void __init create_36bit_mapping(struct map_desc *md,
+					const struct mem_type *type)
 {
-	pmd_t *pmdp = pmd_off_k(virt);
-	pte_t *ptep;
+	unsigned long phys, addr, length, end;
+	pgd_t *pgd;
+
+	addr = md->virtual;
+	phys = (unsigned long)__pfn_to_phys(md->pfn);
+	length = PAGE_ALIGN(md->length);
+
+	if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
+		printk(KERN_ERR "MM: CPU does not support supersection "
+		       "mapping for 0x%08llx at 0x%08lx\n",
+		       __pfn_to_phys((u64)md->pfn), addr);
+		return;
+	}
 
-	if (pmd_none(*pmdp)) {
-		ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
-					       sizeof(pte_t));
+	/* 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 (type->domain) {
+		printk(KERN_ERR "MM: invalid domain in supersection "
+		       "mapping for 0x%08llx at 0x%08lx\n",
+		       __pfn_to_phys((u64)md->pfn), addr);
+		return;
+	}
 
-		__pmd_populate(pmdp, __pa(ptep) | prot_l1);
+	if ((addr | 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), addr);
+		return;
 	}
-	ptep = pte_offset_kernel(pmdp, virt);
 
-	set_pte_ext(ptep, pfn_pte(phys >> PAGE_SHIFT, prot), 0);
+	/*
+	 * Shift bits [35:32] of address into bits [23:20] of PMD
+	 * (See ARMv6 spec).
+	 */
+	phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+
+	pgd = pgd_offset_k(addr);
+	end = addr + length;
+	do {
+		pmd_t *pmd = pmd_offset(pgd, addr);
+		int i;
+
+		for (i = 0; i < 16; i++)
+			*pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER);
+
+		addr += SUPERSECTION_SIZE;
+		phys += SUPERSECTION_SIZE;
+		pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT;
+	} while (addr != end);
 }
 
 /*
@@ -437,10 +499,9 @@ alloc_init_page(unsigned long virt, unsi
  */
 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);
+	unsigned long phys, addr, length, end;
+	const struct mem_type *type;
+	pgd_t *pgd;
 
 	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
 		printk(KERN_WARNING "BUG: not creating mapping for "
@@ -456,105 +517,37 @@ void __init create_mapping(struct map_de
 		       __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);
+	type = &mem_types[md->type];
 
 	/*
 	 * 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);
+	if (md->pfn >= 0x100000) {
+		create_36bit_mapping(md, type);
+		return;
 	}
 
-	virt   = md->virtual;
-	off   -= virt;
-	length = md->length;
+	addr = md->virtual;
+	phys = (unsigned long)__pfn_to_phys(md->pfn);
+	length = PAGE_ALIGN(md->length);
 
-	if (mem_types[md->type].prot_l1 == 0 &&
-	    (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
+	if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
 		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);
+		       __pfn_to_phys(md->pfn), addr);
 		return;
 	}
 
-	while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
-		alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+	pgd = pgd_offset_k(addr);
+	end = addr + length;
+	do {
+		unsigned long next = pgd_addr_end(addr, end);
 
-		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);
-			}
-		}
+		alloc_init_section(pgd, addr, next, phys, type);
 
-		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;
-	}
+		phys += next - addr;
+		addr = next;
+	} while (pgd++, addr != end);
 }
 
 /*
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 05818fc..8cd3a60 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -62,21 +62,21 @@ void flush_dcache_page(struct page *page
 }
 EXPORT_SYMBOL(flush_dcache_page);
 
-void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset,
-			    size_t size, unsigned long flags)
+void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
+				size_t size, unsigned int mtype)
 {
 	if (pfn >= (0x100000000ULL >> PAGE_SHIFT))
 		return NULL;
 	return (void __iomem *) (offset + (pfn << PAGE_SHIFT));
 }
-EXPORT_SYMBOL(__ioremap_pfn);
+EXPORT_SYMBOL(__arm_ioremap_pfn);
 
-void __iomem *__ioremap(unsigned long phys_addr, size_t size,
-			unsigned long flags)
+void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+			    unsigned int mtype)
 {
 	return (void __iomem *)phys_addr;
 }
-EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(__arm_ioremap);
 
 void __iounmap(volatile void __iomem *addr)
 {
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index d29fe92..c156dda 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -584,6 +584,11 @@ cpu_ixp42x_name:
 	.asciz	"XScale-IXP42x Family"
 	.size	cpu_ixp42x_name, . - cpu_ixp42x_name
 
+	.type	cpu_ixp43x_name, #object
+cpu_ixp43x_name:
+	.asciz	"XScale-IXP43x Family"
+	.size	cpu_ixp43x_name, . - cpu_ixp43x_name
+
 	.type	cpu_ixp46x_name, #object
 cpu_ixp46x_name:
 	.asciz	"XScale-IXP46x Family"
@@ -843,6 +848,29 @@ __ixp42x_proc_info:
 	.long	xscale_cache_fns
 	.size   __ixp42x_proc_info, . - __ixp42x_proc_info                
 
+	.type   __ixp43x_proc_info, #object
+__ixp43x_proc_info:
+	.long   0x69054040
+	.long   0xfffffff0
+	.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_ixp43x_name
+	.long   xscale_processor_functions
+	.long   v4wbi_tlb_fns
+	.long   xscale_mc_user_fns
+	.long   xscale_cache_fns
+	.size   __ixp43x_proc_info, . - __ixp43x_proc_info
+
 	.type	__ixp46x_proc_info, #object
 __ixp46x_proc_info:
 	.long   0x69054200
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
index 7c22c12..f5ebf30 100644
--- a/arch/arm/oprofile/backtrace.c
+++ b/arch/arm/oprofile/backtrace.c
@@ -19,6 +19,19 @@ #include <linux/mm.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
+#include "../kernel/stacktrace.h"
+
+static int report_trace(struct stackframe *frame, void *d)
+{
+	unsigned int *depth = d;
+
+	if (*depth) {
+		oprofile_add_trace(frame->lr);
+		(*depth)--;
+	}
+
+	return *depth == 0;
+}
 
 /*
  * The registers we're interested in are at the end of the variable
@@ -32,21 +45,6 @@ struct frame_tail {
 	unsigned long lr;
 } __attribute__((packed));
 
-
-#ifdef CONFIG_FRAME_POINTER
-static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
-{
-	oprofile_add_trace(tail->lr);
-
-	/* frame pointers should strictly progress back up the stack
-	 * (towards higher addresses) */
-	if (tail >= tail->fp)
-		return NULL;
-
-	return tail->fp-1;
-}
-#endif
-
 static struct frame_tail* user_backtrace(struct frame_tail *tail)
 {
 	struct frame_tail buftail[2];
@@ -67,47 +65,14 @@ static struct frame_tail* user_backtrace
 	return buftail[0].fp-1;
 }
 
-/*
- * |             | /\ Higher addresses
- * |             |
- * --------------- stack base (address of current_thread_info)
- * | thread info |
- * .             .
- * |    stack    |
- * --------------- saved regs->ARM_fp value if valid (frame_tail address)
- * .             .
- * --------------- struct pt_regs stored on stack (struct pt_regs *)
- * |             |
- * .             .
- * |             |
- * --------------- %esp
- * |             |
- * |             | \/ Lower addresses
- *
- * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
- */
-static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
-{
-	unsigned long tailaddr = (unsigned long)tail;
-	unsigned long stack = (unsigned long)regs;
-	unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
-
-	return (tailaddr > stack) && (tailaddr < stack_base);
-}
-
 void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
 {
-	struct frame_tail *tail;
-
-	tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+	struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
 
 	if (!user_mode(regs)) {
-
-#ifdef CONFIG_FRAME_POINTER
-		while (depth-- && tail && valid_kernel_stack(tail, regs)) {
-			tail = kernel_backtrace(tail);
-		}
-#endif
+		unsigned long base = ((unsigned long)regs) & ~(THREAD_SIZE - 1);
+		walk_stackframe(regs->ARM_fp, base, base + THREAD_SIZE,
+				report_trace, &depth);
 		return;
 	}
 
diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c
index f7eccec..498675d 100644
--- a/arch/arm/plat-iop/io.c
+++ b/arch/arm/plat-iop/io.c
@@ -22,7 +22,7 @@ #include <asm/hardware.h>
 #include <asm/io.h>
 
 void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
-	unsigned long flags)
+	unsigned int mtype)
 {
 	void __iomem * retval;
 
@@ -34,7 +34,7 @@ void * __iomem __iop3xx_ioremap(unsigned
 		retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie);
 		break;
 	default:
-		retval = __ioremap(cookie, size, flags);
+		retval = __arm_ioremap(cookie, size, mtype);
 	}
 
 	return retval;
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index b5f6ec3..e2744b7 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -55,7 +55,7 @@ static u32 iop3xx_cfg_address(struct pci
  * 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
+ * errors occur during a config cycle where there is no device, like during
  * the discovery stage.
  */
 static int iop3xx_pci_status(void)
@@ -223,8 +223,111 @@ struct pci_bus *iop3xx_pci_scan_bus(int 
 	return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
 }
 
+void __init iop3xx_atu_setup(void)
+{
+	/* BAR 0 ( Disabled ) */
+	*IOP3XX_IAUBAR0 = 0x0;
+	*IOP3XX_IABAR0  = 0x0;
+	*IOP3XX_IATVR0  = 0x0;
+	*IOP3XX_IALR0   = 0x0;
+
+	/* BAR 1 ( Disabled ) */
+	*IOP3XX_IAUBAR1 = 0x0;
+	*IOP3XX_IABAR1  = 0x0;
+	*IOP3XX_IALR1   = 0x0;
+
+	/* BAR 2 (1:1 mapping with Physical RAM) */
+	/* Set limit and enable */
+	*IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1;
+	*IOP3XX_IAUBAR2 = 0x0;
+
+	/* Align the inbound bar with the base of memory */
+	*IOP3XX_IABAR2 = PHYS_OFFSET |
+			       PCI_BASE_ADDRESS_MEM_TYPE_64 |
+			       PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+	*IOP3XX_IATVR2 = PHYS_OFFSET;
+
+	/* Outbound window 0 */
+	*IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA;
+	*IOP3XX_OUMWTVR0 = 0;
+
+	/* Outbound window 1 */
+	*IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE;
+	*IOP3XX_OUMWTVR1 = 0;
+
+	/* BAR 3 ( Disabled ) */
+	*IOP3XX_IAUBAR3 = 0x0;
+	*IOP3XX_IABAR3  = 0x0;
+	*IOP3XX_IATVR3  = 0x0;
+	*IOP3XX_IALR3   = 0x0;
+
+	/* Setup the I/O Bar
+	 */
+	*IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA;;
+
+	/* Enable inbound and outbound cycles
+	 */
+	*IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+			       PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+	*IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN;
+}
+
+void __init iop3xx_atu_disable(void)
+{
+	*IOP3XX_ATUCMD = 0;
+	*IOP3XX_ATUCR = 0;
+
+	/* wait for cycles to quiesce */
+	while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY |
+				     IOP3XX_PCSR_IN_Q_BUSY))
+		cpu_relax();
+
+	/* BAR 0 ( Disabled ) */
+	*IOP3XX_IAUBAR0 = 0x0;
+	*IOP3XX_IABAR0  = 0x0;
+	*IOP3XX_IATVR0  = 0x0;
+	*IOP3XX_IALR0   = 0x0;
+
+	/* BAR 1 ( Disabled ) */
+	*IOP3XX_IAUBAR1 = 0x0;
+	*IOP3XX_IABAR1  = 0x0;
+	*IOP3XX_IALR1   = 0x0;
+
+	/* BAR 2 ( Disabled ) */
+	*IOP3XX_IAUBAR2 = 0x0;
+	*IOP3XX_IABAR2  = 0x0;
+	*IOP3XX_IATVR2  = 0x0;
+	*IOP3XX_IALR2   = 0x0;
+
+	/* BAR 3 ( Disabled ) */
+	*IOP3XX_IAUBAR3 = 0x0;
+	*IOP3XX_IABAR3  = 0x0;
+	*IOP3XX_IATVR3  = 0x0;
+	*IOP3XX_IALR3   = 0x0;
+
+	/* Clear the outbound windows */
+	*IOP3XX_OIOWTVR  = 0;
+
+	/* Outbound window 0 */
+	*IOP3XX_OMWTVR0 = 0;
+	*IOP3XX_OUMWTVR0 = 0;
+
+	/* Outbound window 1 */
+	*IOP3XX_OMWTVR1 = 0;
+	*IOP3XX_OUMWTVR1 = 0;
+}
+
+/* Flag to determine whether the ATU is initialized and the PCI bus scanned */
+int init_atu;
+
 void iop3xx_pci_preinit(void)
 {
+	if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) {
+		iop3xx_atu_disable();
+		iop3xx_atu_setup();
+	}
+
 	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",
@@ -245,3 +348,38 @@ void iop3xx_pci_preinit(void)
 
 	hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort");
 }
+
+/* allow init_atu to be user overridden */
+static int __init iop3xx_init_atu_setup(char *str)
+{
+	init_atu = IOP3XX_INIT_ATU_DEFAULT;
+	if (str) {
+		while (*str != '\0') {
+			switch (*str) {
+			case 'y':
+			case 'Y':
+				init_atu = IOP3XX_INIT_ATU_ENABLE;
+				break;
+			case 'n':
+			case 'N':
+				init_atu = IOP3XX_INIT_ATU_DISABLE;
+				break;
+			case ',':
+			case '=':
+				break;
+			default:
+				printk(KERN_DEBUG "\"%s\" malformed at "
+					    "character: \'%c\'",
+					    __FUNCTION__,
+					    *str);
+				*(str + 1) = '\0';
+			}
+			str++;
+		}
+	}
+
+	return 1;
+}
+
+__setup("iop3xx_init_atu", iop3xx_init_atu_setup);
+
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 16300ad..100d57a 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -32,22 +32,22 @@ static unsigned long next_jiffy_time;
 
 unsigned long iop_gettimeoffset(void)
 {
-	unsigned long offset, temp1, temp2;
+	unsigned long offset, temp;
 
 	/* enable cp6, if necessary, to avoid taking the overhead of an
 	 * undefined instruction trap
 	 */
 	asm volatile (
 	"mrc	p15, 0, %0, c15, c1, 0\n\t"
-	"ands	%1, %0, #(1 << 6)\n\t"
+	"tst	%0, #(1 << 6)\n\t"
 	"orreq	%0, %0, #(1 << 6)\n\t"
 	"mcreq	p15, 0, %0, c15, c1, 0\n\t"
-#ifdef CONFIG_XSCALE
+#ifdef CONFIG_CPU_XSCALE
 	"mrceq	p15, 0, %0, c15, c1, 0\n\t"
 	"moveq	%0, %0\n\t"
 	"subeq	pc, pc, #4\n\t"
 #endif
-	: "=r"(temp1), "=r"(temp2) : : "cc");
+	: "=r"(temp) : : "cc");
 
 	offset = next_jiffy_time - read_tcr1();
 
@@ -75,7 +75,7 @@ iop_timer_interrupt(int irq, void *dev_i
 static struct irqaction iop_timer_irq = {
 	.name		= "IOP Timer Tick",
 	.handler	= iop_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 };
 
 void __init iop_init_time(unsigned long tick_rate)
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index f2dc363..9e8d21e 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -11,6 +11,7 @@ choice
 
 config ARCH_OMAP1
 	bool "TI OMAP1"
+	select GENERIC_CLOCKEVENTS
 
 config ARCH_OMAP2
 	bool "TI OMAP2"
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 57b7b93..fecd3d6 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -156,3 +156,53 @@ static int __init omap_add_serial_consol
 	return add_preferred_console("ttyS", line, opt);
 }
 console_initcall(omap_add_serial_console);
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510.  Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED		0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define TIMER_32K_SYNCHRONIZED		0x48004010
+#endif
+
+#ifdef	TIMER_32K_SYNCHRONIZED
+
+#include <linux/clocksource.h>
+
+static cycle_t omap_32k_read(void)
+{
+	return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static struct clocksource clocksource_32k = {
+	.name		= "32k_counter",
+	.rating		= 250,
+	.read		= omap_32k_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 10,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init omap_init_clocksource_32k(void)
+{
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+
+	if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+		clocksource_32k.mult = clocksource_hz2mult(32768,
+					    clocksource_32k.shift);
+
+		if (clocksource_register(&clocksource_32k))
+			printk(err, clocksource_32k.name);
+	}
+	return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif	/* TIMER_32K_SYNCHRONIZED */
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index dbc3f44..eeb33fe 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -429,6 +429,10 @@ #endif
  */
 static int __init omap_init_devices(void)
 {
+/*
+ * Need to enable relevant once for 2430 SDP
+ */
+#ifndef CONFIG_MACH_OMAP_2430SDP
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
@@ -438,7 +442,7 @@ static int __init omap_init_devices(void
 	omap_init_uwire();
 	omap_init_wdt();
 	omap_init_rng();
-
+#endif
 	return 0;
 }
 arch_initcall(omap_init_devices);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 45f0439..659619f 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -506,6 +506,8 @@ #ifdef CONFIG_ARCH_OMAP2
 		BUG_ON(dm_source_clocks[i] == NULL);
 	}
 #endif
+	if (cpu_is_omap243x())
+		dm_timers[0].phys_base = 0x49018000;
 
 	for (i = 0; i < dm_timer_count; i++) {
 #ifdef CONFIG_ARCH_OMAP2
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index b8c01de..9dc6d36 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -15,7 +15,6 @@ #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -86,10 +85,17 @@ #define OMAP730_GPIO_INT_STATUS		0x14
 /*
  * omap24xx specific GPIO registers
  */
-#define OMAP24XX_GPIO1_BASE		(void __iomem *)0x48018000
-#define OMAP24XX_GPIO2_BASE		(void __iomem *)0x4801a000
-#define OMAP24XX_GPIO3_BASE		(void __iomem *)0x4801c000
-#define OMAP24XX_GPIO4_BASE		(void __iomem *)0x4801e000
+#define OMAP242X_GPIO1_BASE		(void __iomem *)0x48018000
+#define OMAP242X_GPIO2_BASE		(void __iomem *)0x4801a000
+#define OMAP242X_GPIO3_BASE		(void __iomem *)0x4801c000
+#define OMAP242X_GPIO4_BASE		(void __iomem *)0x4801e000
+
+#define OMAP243X_GPIO1_BASE		(void __iomem *)0x4900C000
+#define OMAP243X_GPIO2_BASE		(void __iomem *)0x4900E000
+#define OMAP243X_GPIO3_BASE		(void __iomem *)0x49010000
+#define OMAP243X_GPIO4_BASE		(void __iomem *)0x49012000
+#define OMAP243X_GPIO5_BASE		(void __iomem *)0x480B6000
+
 #define OMAP24XX_GPIO_REVISION		0x0000
 #define OMAP24XX_GPIO_SYSCONFIG		0x0010
 #define OMAP24XX_GPIO_SYSSTATUS		0x0014
@@ -118,8 +124,18 @@ struct gpio_bank {
 	u16 virtual_irq_start;
 	int method;
 	u32 reserved_map;
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
 	u32 suspend_wakeup;
 	u32 saved_wakeup;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+	u32 non_wakeup_gpios;
+	u32 enabled_non_wakeup_gpios;
+
+	u32 saved_datain;
+	u32 saved_fallingdetect;
+	u32 saved_risingdetect;
+#endif
 	spinlock_t lock;
 };
 
@@ -159,12 +175,22 @@ static struct gpio_bank gpio_bank_730[7]
 #endif
 
 #ifdef CONFIG_ARCH_OMAP24XX
-static struct gpio_bank gpio_bank_24xx[4] = {
-	{ OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,	METHOD_GPIO_24XX },
-	{ OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,	METHOD_GPIO_24XX },
-	{ OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,	METHOD_GPIO_24XX },
-	{ OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,	METHOD_GPIO_24XX },
+
+static struct gpio_bank gpio_bank_242x[4] = {
+	{ OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,	METHOD_GPIO_24XX },
+	{ OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,	METHOD_GPIO_24XX },
+	{ OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,	METHOD_GPIO_24XX },
+	{ OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,	METHOD_GPIO_24XX },
+};
+
+static struct gpio_bank gpio_bank_243x[5] = {
+	{ OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE,	METHOD_GPIO_24XX },
+	{ OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32,	METHOD_GPIO_24XX },
+	{ OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64,	METHOD_GPIO_24XX },
+	{ OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96,	METHOD_GPIO_24XX },
+	{ OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
 };
+
 #endif
 
 static struct gpio_bank *gpio_bank;
@@ -258,21 +284,34 @@ static void _set_gpio_direction(struct g
 	u32 l;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_IO_CNTL;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_DIR_CONTROL;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		reg += OMAP1610_GPIO_DIRECTION;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_DIR_CONTROL;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_OE;
 		break;
+#endif
+	default:
+		WARN_ON(1);
+		return;
 	}
 	l = __raw_readl(reg);
 	if (is_input)
@@ -300,6 +339,7 @@ static void _set_gpio_dataout(struct gpi
 	u32 l = 0;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_OUTPUT;
 		l = __raw_readl(reg);
@@ -308,6 +348,8 @@ static void _set_gpio_dataout(struct gpi
 		else
 			l &= ~(1 << gpio);
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_DATA_OUTPUT;
 		l = __raw_readl(reg);
@@ -316,6 +358,8 @@ static void _set_gpio_dataout(struct gpi
 		else
 			l &= ~(1 << gpio);
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		if (enable)
 			reg += OMAP1610_GPIO_SET_DATAOUT;
@@ -323,6 +367,8 @@ static void _set_gpio_dataout(struct gpi
 			reg += OMAP1610_GPIO_CLEAR_DATAOUT;
 		l = 1 << gpio;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_DATA_OUTPUT;
 		l = __raw_readl(reg);
@@ -331,6 +377,8 @@ static void _set_gpio_dataout(struct gpi
 		else
 			l &= ~(1 << gpio);
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		if (enable)
 			reg += OMAP24XX_GPIO_SETDATAOUT;
@@ -338,8 +386,9 @@ static void _set_gpio_dataout(struct gpi
 			reg += OMAP24XX_GPIO_CLEARDATAOUT;
 		l = 1 << gpio;
 		break;
+#endif
 	default:
-		BUG();
+		WARN_ON(1);
 		return;
 	}
 	__raw_writel(l, reg);
@@ -363,28 +412,37 @@ int omap_get_gpio_datain(int gpio)
 	void __iomem *reg;
 
 	if (check_gpio(gpio) < 0)
-		return -1;
+		return -EINVAL;
 	bank = get_gpio_bank(gpio);
 	reg = bank->base;
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_INPUT_LATCH;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_DATA_INPUT;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		reg += OMAP1610_GPIO_DATAIN;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_DATA_INPUT;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_DATAIN;
 		break;
+#endif
 	default:
-		BUG();
-		return -1;
+		return -EINVAL;
 	}
 	return (__raw_readl(reg)
 			& (1 << get_gpio_index(gpio))) != 0;
@@ -398,8 +456,10 @@ do {	\
 	__raw_writel(l, base + reg); \
 } while(0)
 
-static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
+#ifdef CONFIG_ARCH_OMAP24XX
+static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 {
+	void __iomem *base = bank->base;
 	u32 gpio_bit = 1 << gpio;
 
 	MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
@@ -410,9 +470,21 @@ static inline void set_24xx_gpio_trigger
 		trigger & __IRQT_RISEDGE);
 	MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
 		trigger & __IRQT_FALEDGE);
+	if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
+		if (trigger != 0)
+			__raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA);
+		else
+			__raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA);
+	} else {
+		if (trigger != 0)
+			bank->enabled_non_wakeup_gpios |= gpio_bit;
+		else
+			bank->enabled_non_wakeup_gpios &= ~gpio_bit;
+	}
 	/* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level
 	 * triggering requested. */
 }
+#endif
 
 static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 {
@@ -420,6 +492,7 @@ static int _set_gpio_triggering(struct g
 	u32 l = 0;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_GPIO_INT_EDGE;
 		l = __raw_readl(reg);
@@ -430,6 +503,8 @@ static int _set_gpio_triggering(struct g
 		else
 			goto bad;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_INT_CONTROL;
 		l = __raw_readl(reg);
@@ -440,22 +515,28 @@ static int _set_gpio_triggering(struct g
 		else
 			goto bad;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		if (gpio & 0x08)
 			reg += OMAP1610_GPIO_EDGE_CTRL2;
 		else
 			reg += OMAP1610_GPIO_EDGE_CTRL1;
 		gpio &= 0x07;
-		/* We allow only edge triggering, i.e. two lowest bits */
-		if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL))
-			BUG();
 		l = __raw_readl(reg);
 		l &= ~(3 << (gpio << 1));
 		if (trigger & __IRQT_RISEDGE)
 			l |= 2 << (gpio << 1);
 		if (trigger & __IRQT_FALEDGE)
 			l |= 1 << (gpio << 1);
+		if (trigger)
+			/* Enable wake-up during idle for dynamic tick */
+			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
+		else
+			__raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_INT_CONTROL;
 		l = __raw_readl(reg);
@@ -466,11 +547,13 @@ static int _set_gpio_triggering(struct g
 		else
 			goto bad;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
-		set_24xx_gpio_triggering(reg, gpio, trigger);
+		set_24xx_gpio_triggering(bank, gpio, trigger);
 		break;
+#endif
 	default:
-		BUG();
 		goto bad;
 	}
 	__raw_writel(l, reg);
@@ -485,7 +568,7 @@ static int gpio_irq_type(unsigned irq, u
 	unsigned gpio;
 	int retval;
 
-	if (irq > IH_MPUIO_BASE)
+	if (!cpu_is_omap24xx() && irq > IH_MPUIO_BASE)
 		gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
 	else
 		gpio = irq - IH_GPIO_BASE;
@@ -493,14 +576,21 @@ static int gpio_irq_type(unsigned irq, u
 	if (check_gpio(gpio) < 0)
 		return -EINVAL;
 
-	if (type & IRQT_PROBE)
+	if (type & ~IRQ_TYPE_SENSE_MASK)
 		return -EINVAL;
-	if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL)))
+
+	/* OMAP1 allows only only edge triggering */
+	if (!cpu_is_omap24xx()
+			&& (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
 		return -EINVAL;
 
-	bank = get_gpio_bank(gpio);
+	bank = get_irq_chip_data(irq);
 	spin_lock(&bank->lock);
 	retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
+	if (retval == 0) {
+		irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
+		irq_desc[irq].status |= type;
+	}
 	spin_unlock(&bank->lock);
 	return retval;
 }
@@ -510,24 +600,34 @@ static void _clear_gpio_irqbank(struct g
 	void __iomem *reg = bank->base;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		/* MPUIO irqstatus is reset by reading the status register,
 		 * so do nothing here */
 		return;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_INT_STATUS;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		reg += OMAP1610_GPIO_IRQSTATUS1;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_INT_STATUS;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_IRQSTATUS1;
 		break;
+#endif
 	default:
-		BUG();
+		WARN_ON(1);
 		return;
 	}
 	__raw_writel(gpio_mask, reg);
@@ -550,31 +650,41 @@ static u32 _get_gpio_irqbank_mask(struct
 	u32 mask;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_GPIO_MASKIT;
 		mask = 0xffff;
 		inv = 1;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_INT_MASK;
 		mask = 0xffff;
 		inv = 1;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		reg += OMAP1610_GPIO_IRQENABLE1;
 		mask = 0xffff;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_INT_MASK;
 		mask = 0xffffffff;
 		inv = 1;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		reg += OMAP24XX_GPIO_IRQENABLE1;
 		mask = 0xffffffff;
 		break;
+#endif
 	default:
-		BUG();
+		WARN_ON(1);
 		return 0;
 	}
 
@@ -591,6 +701,7 @@ static void _enable_gpio_irqbank(struct 
 	u32 l;
 
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
 	case METHOD_MPUIO:
 		reg += OMAP_MPUIO_GPIO_MASKIT;
 		l = __raw_readl(reg);
@@ -599,6 +710,8 @@ static void _enable_gpio_irqbank(struct 
 		else
 			l |= gpio_mask;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
 	case METHOD_GPIO_1510:
 		reg += OMAP1510_GPIO_INT_MASK;
 		l = __raw_readl(reg);
@@ -607,6 +720,8 @@ static void _enable_gpio_irqbank(struct 
 		else
 			l |= gpio_mask;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
 	case METHOD_GPIO_1610:
 		if (enable)
 			reg += OMAP1610_GPIO_SET_IRQENABLE1;
@@ -614,6 +729,8 @@ static void _enable_gpio_irqbank(struct 
 			reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
 		l = gpio_mask;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
 	case METHOD_GPIO_730:
 		reg += OMAP730_GPIO_INT_MASK;
 		l = __raw_readl(reg);
@@ -622,6 +739,8 @@ static void _enable_gpio_irqbank(struct 
 		else
 			l |= gpio_mask;
 		break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
 		if (enable)
 			reg += OMAP24XX_GPIO_SETIRQENABLE1;
@@ -629,8 +748,9 @@ static void _enable_gpio_irqbank(struct 
 			reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
 		l = gpio_mask;
 		break;
+#endif
 	default:
-		BUG();
+		WARN_ON(1);
 		return;
 	}
 	__raw_writel(l, reg);
@@ -652,15 +772,39 @@ static inline void _set_gpio_irqenable(s
 static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
 {
 	switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
+	case METHOD_MPUIO:
 	case METHOD_GPIO_1610:
+		spin_lock(&bank->lock);
+		if (enable) {
+			bank->suspend_wakeup |= (1 << gpio);
+			enable_irq_wake(bank->irq);
+		} else {
+			disable_irq_wake(bank->irq);
+			bank->suspend_wakeup &= ~(1 << gpio);
+		}
+		spin_unlock(&bank->lock);
+		return 0;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 	case METHOD_GPIO_24XX:
+		if (bank->non_wakeup_gpios & (1 << gpio)) {
+			printk(KERN_ERR "Unable to modify wakeup on "
+					"non-wakeup GPIO%d\n",
+					(bank - gpio_bank) * 32 + gpio);
+			return -EINVAL;
+		}
 		spin_lock(&bank->lock);
-		if (enable)
+		if (enable) {
 			bank->suspend_wakeup |= (1 << gpio);
-		else
+			enable_irq_wake(bank->irq);
+		} else {
+			disable_irq_wake(bank->irq);
 			bank->suspend_wakeup &= ~(1 << gpio);
+		}
 		spin_unlock(&bank->lock);
 		return 0;
+#endif
 	default:
 		printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
 		       bank->method);
@@ -685,7 +829,7 @@ static int gpio_wake_enable(unsigned int
 
 	if (check_gpio(gpio) < 0)
 		return -ENODEV;
-	bank = get_gpio_bank(gpio);
+	bank = get_irq_chip_data(irq);
 	retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
 
 	return retval;
@@ -722,20 +866,6 @@ #ifdef CONFIG_ARCH_OMAP15XX
 		__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
 	}
 #endif
-#ifdef CONFIG_ARCH_OMAP16XX
-	if (bank->method == METHOD_GPIO_1610) {
-		/* Enable wake-up during idle for dynamic tick */
-		void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
-		__raw_writel(1 << get_gpio_index(gpio), reg);
-	}
-#endif
-#ifdef CONFIG_ARCH_OMAP24XX
-	if (bank->method == METHOD_GPIO_24XX) {
-		/* Enable wake-up during idle for dynamic tick */
-		void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
-		__raw_writel(1 << get_gpio_index(gpio), reg);
-	}
-#endif
 	spin_unlock(&bank->lock);
 
 	return 0;
@@ -795,8 +925,10 @@ static void gpio_irq_handler(unsigned in
 	desc->chip->ack(irq);
 
 	bank = get_irq_data(irq);
+#ifdef CONFIG_ARCH_OMAP1
 	if (bank->method == METHOD_MPUIO)
 		isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
+#endif
 #ifdef CONFIG_ARCH_OMAP15XX
 	if (bank->method == METHOD_GPIO_1510)
 		isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
@@ -912,7 +1044,7 @@ #endif
 static void gpio_irq_shutdown(unsigned int irq)
 {
 	unsigned int gpio = irq - IH_GPIO_BASE;
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_reset_gpio(bank, gpio);
 }
@@ -920,7 +1052,7 @@ static void gpio_irq_shutdown(unsigned i
 static void gpio_ack_irq(unsigned int irq)
 {
 	unsigned int gpio = irq - IH_GPIO_BASE;
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_clear_gpio_irqstatus(bank, gpio);
 }
@@ -928,7 +1060,7 @@ static void gpio_ack_irq(unsigned int ir
 static void gpio_mask_irq(unsigned int irq)
 {
 	unsigned int gpio = irq - IH_GPIO_BASE;
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_set_gpio_irqenable(bank, gpio, 0);
 }
@@ -937,11 +1069,27 @@ static void gpio_unmask_irq(unsigned int
 {
 	unsigned int gpio = irq - IH_GPIO_BASE;
 	unsigned int gpio_idx = get_gpio_index(gpio);
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_set_gpio_irqenable(bank, gpio_idx, 1);
 }
 
+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,
+	.set_type	= gpio_irq_type,
+	.set_wake	= gpio_wake_enable,
+};
+
+/*---------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1
+
+/* MPUIO uses the always-on 32k clock */
+
 static void mpuio_ack_irq(unsigned int irq)
 {
 	/* The ISR is reset automatically, so do nothing here. */
@@ -950,7 +1098,7 @@ static void mpuio_ack_irq(unsigned int i
 static void mpuio_mask_irq(unsigned int irq)
 {
 	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_set_gpio_irqenable(bank, gpio, 0);
 }
@@ -958,33 +1106,108 @@ static void mpuio_mask_irq(unsigned int 
 static void mpuio_unmask_irq(unsigned int irq)
 {
 	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
-	struct gpio_bank *bank = get_gpio_bank(gpio);
+	struct gpio_bank *bank = get_irq_chip_data(irq);
 
 	_set_gpio_irqenable(bank, gpio, 1);
 }
 
-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,
+static struct irq_chip mpuio_irq_chip = {
+	.name		= "MPUIO",
+	.ack		= mpuio_ack_irq,
+	.mask		= mpuio_mask_irq,
+	.unmask		= mpuio_unmask_irq,
 	.set_type	= gpio_irq_type,
+#ifdef CONFIG_ARCH_OMAP16XX
+	/* REVISIT: assuming only 16xx supports MPUIO wake events */
 	.set_wake	= gpio_wake_enable,
+#endif
 };
 
-static struct irq_chip mpuio_irq_chip = {
-	.name	  = "MPUIO",
-	.ack	  = mpuio_ack_irq,
-	.mask	  = mpuio_mask_irq,
-	.unmask	  = mpuio_unmask_irq,
-	.set_type = gpio_irq_type,
+
+#define bank_is_mpuio(bank)	((bank)->method == METHOD_MPUIO)
+
+
+#ifdef CONFIG_ARCH_OMAP16XX
+
+#include <linux/platform_device.h>
+
+static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+	struct gpio_bank	*bank = platform_get_drvdata(pdev);
+	void __iomem		*mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+	spin_lock(&bank->lock);
+	bank->saved_wakeup = __raw_readl(mask_reg);
+	__raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
+	spin_unlock(&bank->lock);
+
+	return 0;
+}
+
+static int omap_mpuio_resume_early(struct platform_device *pdev)
+{
+	struct gpio_bank	*bank = platform_get_drvdata(pdev);
+	void __iomem		*mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+	spin_lock(&bank->lock);
+	__raw_writel(bank->saved_wakeup, mask_reg);
+	spin_unlock(&bank->lock);
+
+	return 0;
+}
+
+/* use platform_driver for this, now that there's no longer any
+ * point to sys_device (other than not disturbing old code).
+ */
+static struct platform_driver omap_mpuio_driver = {
+	.suspend_late	= omap_mpuio_suspend_late,
+	.resume_early	= omap_mpuio_resume_early,
+	.driver		= {
+		.name	= "mpuio",
+	},
+};
+
+static struct platform_device omap_mpuio_device = {
+	.name		= "mpuio",
+	.id		= -1,
+	.dev = {
+		.driver = &omap_mpuio_driver.driver,
+	}
+	/* could list the /proc/iomem resources */
 };
 
+static inline void mpuio_init(void)
+{
+	platform_set_drvdata(&omap_mpuio_device, &gpio_bank_1610[0]);
+
+	if (platform_driver_register(&omap_mpuio_driver) == 0)
+		(void) platform_device_register(&omap_mpuio_device);
+}
+
+#else
+static inline void mpuio_init(void) {}
+#endif	/* 16xx */
+
+#else
+
+extern struct irq_chip mpuio_irq_chip;
+
+#define bank_is_mpuio(bank)	0
+static inline void mpuio_init(void) {}
+
+#endif
+
+/*---------------------------------------------------------------------*/
+
 static int initialized;
 static struct clk * gpio_ick;
 static struct clk * gpio_fck;
 
+#ifdef CONFIG_ARCH_OMAP2430
+static struct clk * gpio5_ick;
+static struct clk * gpio5_fck;
+#endif
+
 static int __init _omap_gpio_init(void)
 {
 	int i;
@@ -1010,7 +1233,25 @@ static int __init _omap_gpio_init(void)
 			printk("Could not get gpios_fck\n");
 		else
 			clk_enable(gpio_fck);
-	}
+
+		/*
+		 * On 2430 GPIO 5 uses CORE L4 ICLK
+		 */
+#ifdef CONFIG_ARCH_OMAP2430
+		if (cpu_is_omap2430()) {
+			gpio5_ick = clk_get(NULL, "gpio5_ick");
+			if (IS_ERR(gpio5_ick))
+				printk("Could not get gpio5_ick\n");
+			else
+				clk_enable(gpio5_ick);
+			gpio5_fck = clk_get(NULL, "gpio5_fck");
+			if (IS_ERR(gpio5_fck))
+				printk("Could not get gpio5_fck\n");
+			else
+				clk_enable(gpio5_fck);
+		}
+#endif
+}
 
 #ifdef CONFIG_ARCH_OMAP15XX
 	if (cpu_is_omap15xx()) {
@@ -1037,14 +1278,24 @@ #ifdef CONFIG_ARCH_OMAP730
 		gpio_bank = gpio_bank_730;
 	}
 #endif
+
 #ifdef CONFIG_ARCH_OMAP24XX
-	if (cpu_is_omap24xx()) {
+	if (cpu_is_omap242x()) {
 		int rev;
 
 		gpio_bank_count = 4;
-		gpio_bank = gpio_bank_24xx;
+		gpio_bank = gpio_bank_242x;
+		rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+		printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
+			(rev >> 4) & 0x0f, rev & 0x0f);
+	}
+	if (cpu_is_omap243x()) {
+		int rev;
+
+		gpio_bank_count = 5;
+		gpio_bank = gpio_bank_243x;
 		rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
-		printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
+		printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
 			(rev >> 4) & 0x0f, rev & 0x0f);
 	}
 #endif
@@ -1055,9 +1306,8 @@ #endif
 		bank->reserved_map = 0;
 		bank->base = IO_ADDRESS(bank->base);
 		spin_lock_init(&bank->lock);
-		if (bank->method == METHOD_MPUIO) {
+		if (bank_is_mpuio(bank))
 			omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
-		}
 #ifdef CONFIG_ARCH_OMAP15XX
 		if (bank->method == METHOD_GPIO_1510) {
 			__raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
@@ -1081,15 +1331,25 @@ #ifdef CONFIG_ARCH_OMAP730
 #endif
 #ifdef CONFIG_ARCH_OMAP24XX
 		if (bank->method == METHOD_GPIO_24XX) {
+			static const u32 non_wakeup_gpios[] = {
+				0xe203ffc0, 0x08700040
+			};
+
 			__raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
 			__raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
+			__raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
 
+			/* Initialize interface clock ungated, module enabled */
+			__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
+			if (i < ARRAY_SIZE(non_wakeup_gpios))
+				bank->non_wakeup_gpios = non_wakeup_gpios[i];
 			gpio_count = 32;
 		}
 #endif
 		for (j = bank->virtual_irq_start;
 		     j < bank->virtual_irq_start + gpio_count; j++) {
-			if (bank->method == METHOD_MPUIO)
+			set_irq_chip_data(j, bank);
+			if (bank_is_mpuio(bank))
 				set_irq_chip(j, &mpuio_irq_chip);
 			else
 				set_irq_chip(j, &gpio_irq_chip);
@@ -1105,6 +1365,12 @@ #endif
 	if (cpu_is_omap16xx())
 		omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
 
+#ifdef CONFIG_ARCH_OMAP24XX
+	/* Enable autoidle for the OCP interface */
+	if (cpu_is_omap24xx())
+		omap_writel(1 << 0, 0x48019010);
+#endif
+
 	return 0;
 }
 
@@ -1123,16 +1389,20 @@ static int omap_gpio_suspend(struct sys_
 		void __iomem *wake_set;
 
 		switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
 		case METHOD_GPIO_1610:
 			wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
 			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
 			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
 			break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 		case METHOD_GPIO_24XX:
 			wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
 			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
 			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
 			break;
+#endif
 		default:
 			continue;
 		}
@@ -1160,14 +1430,18 @@ static int omap_gpio_resume(struct sys_d
 		void __iomem *wake_set;
 
 		switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
 		case METHOD_GPIO_1610:
 			wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
 			wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
 			break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
 		case METHOD_GPIO_24XX:
 			wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
 			wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
 			break;
+#endif
 		default:
 			continue;
 		}
@@ -1191,6 +1465,80 @@ static struct sys_device omap_gpio_devic
 	.id		= 0,
 	.cls		= &omap_gpio_sysclass,
 };
+
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+static int workaround_enabled;
+
+void omap2_gpio_prepare_for_retention(void)
+{
+	int i, c = 0;
+
+	/* Remove triggering for all non-wakeup GPIOs.  Otherwise spurious
+	 * IRQs will be generated.  See OMAP2420 Errata item 1.101. */
+	for (i = 0; i < gpio_bank_count; i++) {
+		struct gpio_bank *bank = &gpio_bank[i];
+		u32 l1, l2;
+
+		if (!(bank->enabled_non_wakeup_gpios))
+			continue;
+		bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+		l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+		l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+		bank->saved_fallingdetect = l1;
+		bank->saved_risingdetect = l2;
+		l1 &= ~bank->enabled_non_wakeup_gpios;
+		l2 &= ~bank->enabled_non_wakeup_gpios;
+		__raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+		__raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
+		c++;
+	}
+	if (!c) {
+		workaround_enabled = 0;
+		return;
+	}
+	workaround_enabled = 1;
+}
+
+void omap2_gpio_resume_after_retention(void)
+{
+	int i;
+
+	if (!workaround_enabled)
+		return;
+	for (i = 0; i < gpio_bank_count; i++) {
+		struct gpio_bank *bank = &gpio_bank[i];
+		u32 l;
+
+		if (!(bank->enabled_non_wakeup_gpios))
+			continue;
+		__raw_writel(bank->saved_fallingdetect,
+				 bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+		__raw_writel(bank->saved_risingdetect,
+				 bank->base + OMAP24XX_GPIO_RISINGDETECT);
+		/* Check if any of the non-wakeup interrupt GPIOs have changed
+		 * state.  If so, generate an IRQ by software.  This is
+		 * horribly racy, but it's the best we can do to work around
+		 * this silicon bug. */
+		l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+		l ^= bank->saved_datain;
+		l &= bank->non_wakeup_gpios;
+		if (l) {
+			u32 old0, old1;
+
+			old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+			old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+			__raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+			__raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+			__raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+			__raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+		}
+	}
+
+}
+
 #endif
 
 /*
@@ -1212,6 +1560,8 @@ static int __init omap_gpio_sysinit(void
 	if (!initialized)
 		ret = _omap_gpio_init();
 
+	mpuio_init();
+
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
 	if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
 		if (ret == 0) {
@@ -1232,3 +1582,128 @@ EXPORT_SYMBOL(omap_set_gpio_dataout);
 EXPORT_SYMBOL(omap_get_gpio_datain);
 
 arch_initcall(omap_gpio_sysinit);
+
+
+#ifdef	CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+	void __iomem *reg = bank->base;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_IO_CNTL;
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_DIR_CONTROL;
+		break;
+	case METHOD_GPIO_1610:
+		reg += OMAP1610_GPIO_DIRECTION;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_DIR_CONTROL;
+		break;
+	case METHOD_GPIO_24XX:
+		reg += OMAP24XX_GPIO_OE;
+		break;
+	}
+	return __raw_readl(reg) & mask;
+}
+
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+	unsigned	i, j, gpio;
+
+	for (i = 0, gpio = 0; i < gpio_bank_count; i++) {
+		struct gpio_bank	*bank = gpio_bank + i;
+		unsigned		bankwidth = 16;
+		u32			mask = 1;
+
+		if (bank_is_mpuio(bank))
+			gpio = OMAP_MPUIO(0);
+		else if (cpu_is_omap24xx() || cpu_is_omap730())
+			bankwidth = 32;
+
+		for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
+			unsigned	irq, value, is_in, irqstat;
+
+			if (!(bank->reserved_map & mask))
+				continue;
+
+			irq = bank->virtual_irq_start + j;
+			value = omap_get_gpio_datain(gpio);
+			is_in = gpio_is_input(bank, mask);
+
+			if (bank_is_mpuio(bank))
+				seq_printf(s, "MPUIO %2d: ", j);
+			else
+				seq_printf(s, "GPIO %3d: ", gpio);
+			seq_printf(s, "%s %s",
+					is_in ? "in " : "out",
+					value ? "hi"  : "lo");
+
+			irqstat = irq_desc[irq].status;
+			if (is_in && ((bank->suspend_wakeup & mask)
+					|| irqstat & IRQ_TYPE_SENSE_MASK)) {
+				char	*trigger = NULL;
+
+				switch (irqstat & IRQ_TYPE_SENSE_MASK) {
+				case IRQ_TYPE_EDGE_FALLING:
+					trigger = "falling";
+					break;
+				case IRQ_TYPE_EDGE_RISING:
+					trigger = "rising";
+					break;
+				case IRQ_TYPE_EDGE_BOTH:
+					trigger = "bothedge";
+					break;
+				case IRQ_TYPE_LEVEL_LOW:
+					trigger = "low";
+					break;
+				case IRQ_TYPE_LEVEL_HIGH:
+					trigger = "high";
+					break;
+				case IRQ_TYPE_NONE:
+					trigger = "(unspecified)";
+					break;
+				}
+				seq_printf(s, ", irq-%d %s%s",
+						irq, trigger,
+						(bank->suspend_wakeup & mask)
+							? " wakeup" : "");
+			}
+			seq_printf(s, "\n");
+		}
+
+		if (bank_is_mpuio(bank)) {
+			seq_printf(s, "\n");
+			gpio = 0;
+		}
+	}
+	return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+	.open		= dbg_gpio_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init omap_gpio_debuginit(void)
+{
+	(void) debugfs_create_file("omap_gpio", S_IRUGO,
+					NULL, NULL, &debug_fops);
+	return 0;
+}
+late_initcall(omap_gpio_debuginit);
+#endif
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index b8d6f17..f7b9ccd 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -225,11 +225,16 @@ #endif
 #ifdef CONFIG_ARCH_OMAP2
 static void omap2_mcbsp2_mux_setup(void)
 {
-	omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
-	omap_cfg_reg(R14_24XX_MCBSP2_FSX);
-	omap_cfg_reg(W15_24XX_MCBSP2_DR);
-	omap_cfg_reg(V15_24XX_MCBSP2_DX);
-	omap_cfg_reg(V14_24XX_GPIO117);
+	if (cpu_is_omap2420()) {
+		omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
+		omap_cfg_reg(R14_24XX_MCBSP2_FSX);
+		omap_cfg_reg(W15_24XX_MCBSP2_DR);
+		omap_cfg_reg(V15_24XX_MCBSP2_DX);
+		omap_cfg_reg(V14_24XX_GPIO117);
+	}
+	/*
+	 * Need to add MUX settings for OMAP 2430 SDP
+	 */
 }
 #endif
 
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 2653106..2feceec 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -42,6 +42,8 @@ #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
@@ -80,13 +82,13 @@ #define OMAP1_32K_TIMER_CR		0x08
 #define OMAP1_32K_TIMER_TVR		0x00
 #define OMAP1_32K_TIMER_TCR		0x04
 
-#define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
+#define OMAP_32K_TICKS_PER_SEC		(32768)
 
 /*
  * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
  * so with HZ = 128, TVR = 255.
  */
-#define OMAP_32K_TIMER_TICK_PERIOD	((32768 / HZ) - 1)
+#define OMAP_32K_TIMER_TICK_PERIOD	((OMAP_32K_TICKS_PER_SEC / HZ) - 1)
 
 #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate)			\
 				(((nr_jiffies) * (clock_rate)) / HZ)
@@ -142,6 +144,28 @@ static inline void omap_32k_timer_ack_ir
 
 #endif
 
+static void omap_32k_timer_set_mode(enum clock_event_mode mode,
+				    struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_PERIODIC:
+		omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		omap_32k_timer_stop();
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_32k_timer = {
+	.name		= "32k-timer",
+	.features       = CLOCK_EVT_FEAT_PERIODIC,
+	.shift		= 32,
+	.set_mode	= omap_32k_timer_set_mode,
+};
+
 /*
  * The 32KHz synchronized timer is an additional timer on 16xx.
  * It is always running.
@@ -171,15 +195,6 @@ omap_32k_ticks_to_nsecs(unsigned long ti
 static unsigned long omap_32k_last_tick = 0;
 
 /*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
-	unsigned long now = omap_32k_sync_timer_read();
-	return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
-/*
  * Returns current time from boot in nsecs. It's OK for this to wrap
  * around for now, as it's just a relative time stamp.
  */
@@ -188,110 +203,26 @@ unsigned long long sched_clock(void)
 	return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
 }
 
-/*
- * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
- * function is also called from other interrupts to remove latency
- * issues with dynamic tick. In the dynamic tick case, we need to lock
- * with irqsave.
- */
-static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
-{
-	unsigned long now;
-
-	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();
-	}
-
-	/* Restart timer so we don't drift off due to modulo or dynamic tick.
-	 * By default we program the next timer to be continuous to avoid
-	 * latencies during high system load. During dynamic tick operation the
-	 * 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;
+	struct clock_event_device *evt = &clockevent_32k_timer;
+	omap_32k_timer_ack_irq();
 
-	write_seqlock_irqsave(&xtime_lock, flags);
-	_omap_32k_timer_interrupt(irq, dev_id);
-	write_sequnlock_irqrestore(&xtime_lock, flags);
+	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_NO_IDLE_HZ
-/*
- * Programs the next timer interrupt needed. Called when dynamic tick is
- * enabled, and to reprogram the ticks to skip from pm_idle. Note that
- * we can keep the timer continuous, and don't need to set it to run in
- * one-shot mode. This is because the timer will get reprogrammed again
- * after next interrupt.
- */
-void omap_32k_timer_reprogram(unsigned long next_tick)
-{
-	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;
-extern struct timer_update_handler timer_update;
-
-static int omap_32k_timer_enable_dyn_tick(void)
-{
-	/* No need to reprogram timer, just use the next interrupt */
-	return 0;
-}
-
-static int omap_32k_timer_disable_dyn_tick(void)
-{
-	omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
-	return 0;
-}
-
-static struct dyn_tick_timer omap_dyn_tick_timer = {
-	.enable		= omap_32k_timer_enable_dyn_tick,
-	.disable	= omap_32k_timer_disable_dyn_tick,
-	.reprogram	= omap_32k_timer_reprogram,
-	.handler	= omap_32k_timer_handler,
-};
-#endif	/* CONFIG_NO_IDLE_HZ */
-
 static struct irqaction omap_32k_timer_irq = {
 	.name		= "32KHz timer",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= omap_32k_timer_interrupt,
 };
 
 static __init void omap_init_32k_timer(void)
 {
-#ifdef CONFIG_NO_IDLE_HZ
-	omap_timer.dyn_tick = &omap_dyn_tick_timer;
-#endif
-
 	if (cpu_class_is_omap1())
 		setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
-	omap_timer.offset  = omap_32k_timer_gettimeoffset;
 	omap_32k_last_tick = omap_32k_sync_timer_read();
 
 #ifdef CONFIG_ARCH_OMAP2
@@ -308,7 +239,16 @@ #ifdef CONFIG_ARCH_OMAP2
 	}
 #endif
 
-	omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+	clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC,
+					   NSEC_PER_SEC,
+					   clockevent_32k_timer.shift);
+	clockevent_32k_timer.max_delta_ns =
+		clockevent_delta2ns(0xfffffffe, &clockevent_32k_timer);
+	clockevent_32k_timer.min_delta_ns =
+		clockevent_delta2ns(1, &clockevent_32k_timer);
+
+	clockevent_32k_timer.cpumask = cpumask_of_cpu(0);
+	clockevents_register_device(&clockevent_32k_timer);
 }
 
 /*
@@ -326,5 +266,4 @@ #endif
 
 struct sys_timer omap_timer = {
 	.init		= omap_timer_init,
-	.offset		= NULL,		/* Initialized later */
 };
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index d3dc03a..79cda0f 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -404,6 +404,18 @@ int s3c24xx_register_clock(struct clk *c
 	return 0;
 }
 
+int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
+{
+	int fails = 0;
+
+	for (; nr_clks > 0; nr_clks--, clks++) {
+		if (s3c24xx_register_clock(*clks) < 0)
+			fails++;
+	}
+
+	return fails;
+}
+
 /* initalise all the clocks */
 
 int __init s3c24xx_setup_clocks(unsigned long xtal,
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 6a2d107..8ce4904 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -181,24 +181,6 @@ s3c_lookup_cpu(unsigned long idcode)
 	return NULL;
 }
 
-/* board information */
-
-static struct s3c24xx_board *board;
-
-void s3c24xx_set_board(struct s3c24xx_board *b)
-{
-	int i;
-
-	board = b;
-
-	if (b->clocks_count != 0) {
-		struct clk **ptr = b->clocks;
-
-		for (i = b->clocks_count; i > 0; i--, ptr++)
-			s3c24xx_register_clock(*ptr);
-	}
-}
-
 /* cpu information */
 
 static struct cpu_table *cpu;
@@ -342,26 +324,6 @@ static int __init s3c_arch_init(void)
 		return ret;
 
 	ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
-	if (ret != 0)
-		return ret;
-
-	if (board != NULL) {
-		struct platform_device **ptr = board->devices;
-		int i;
-
-		for (i = 0; i < board->devices_count; i++, ptr++) {
-			ret = platform_device_register(*ptr);
-
-			if (ret) {
-				printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr);
-			}
-		}
-
-		/* mask any error, we may not need all these board
-		 * devices */
-		ret = 0;
-	}
-
 	return ret;
 }
 
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 4540a80..6f03c93 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -44,7 +44,7 @@ static struct kmem_cache *dma_kmem;
 
 static int dma_channels;
 
-struct s3c24xx_dma_selection dma_sel;
+static struct s3c24xx_dma_selection dma_sel;
 
 /* dma channel state information */
 struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
@@ -880,7 +880,7 @@ #endif
 	return 0;
 }
 
-void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
+static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
 {
 	unsigned long tmp;
 	unsigned int timeout = 0x10000;
@@ -957,8 +957,7 @@ #endif
 	return 0;
 }
 
-int
-s3c2410_dma_started(struct s3c2410_dma_chan *chan)
+static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 {
 	unsigned long flags;
 
@@ -1280,7 +1279,7 @@ static void s3c2410_dma_cache_ctor(void 
 
 /* initialisation code */
 
-int __init s3c24xx_dma_sysclass_init(void)
+static int __init s3c24xx_dma_sysclass_init(void)
 {
 	int ret = sysdev_class_register(&dma_sysclass);
 
@@ -1292,7 +1291,7 @@ int __init s3c24xx_dma_sysclass_init(voi
 
 core_initcall(s3c24xx_dma_sysclass_init);
 
-int __init s3c24xx_dma_sysdev_register(void)
+static int __init s3c24xx_dma_sysdev_register(void)
 {
 	struct s3c2410_dma_chan *cp = s3c2410_chans;
 	int channel, ret;
@@ -1396,7 +1395,7 @@ static struct s3c24xx_dma_order *dma_ord
  * channel
 */
 
-struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
 {
 	struct s3c24xx_dma_order_ch *ord = NULL;
 	struct s3c24xx_dma_map *ch_map;
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index ce18639..8fbc884 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -54,7 +54,6 @@ #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 <asm/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index ecf68d6..c6b03f8 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -511,11 +511,6 @@ static int s3c2410_pm_enter(suspend_stat
 		return -EINVAL;
 	}
 
-	if (state != PM_SUSPEND_MEM) {
-		printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
-		return -EINVAL;
-	}
-
 	/* check if we have anything to wake-up with... bad things seem
 	 * to happen if you suspend with no wakeup (system will often
 	 * require a full power-cycle)
@@ -617,30 +612,9 @@ static int s3c2410_pm_enter(suspend_stat
 	return 0;
 }
 
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-static int s3c2410_pm_prepare(suspend_state_t state)
-{
-	return 0;
-}
-
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-static int s3c2410_pm_finish(suspend_state_t state)
-{
-	return 0;
-}
-
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
 static struct pm_ops s3c2410_pm_ops = {
-	.pm_disk_mode	= PM_DISK_FIRMWARE,
-	.prepare	= s3c2410_pm_prepare,
 	.enter		= s3c2410_pm_enter,
-	.finish		= s3c2410_pm_finish,
+	.valid		= pm_valid_only_mem,
 };
 
 /* s3c2410_pm_init
diff --git a/arch/arm/plat-s3c24xx/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c
index a0e39d8..2dbb260 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-irq.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c
@@ -23,7 +23,6 @@ #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 <asm/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index c523d1c..b766737 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -138,7 +138,7 @@ s3c2410_timer_interrupt(int irq, void *d
 
 static struct irqaction s3c2410_timer_irq = {
 	.name		= "S3C2410 Timer Tick",
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.handler	= s3c2410_timer_interrupt,
 };
 
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index e44b9ed..74e89f8 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -34,7 +34,6 @@ #include <linux/kernel.h>
 #include <linux/bitops.h>
 
 #include <asm/div64.h>
-#include <asm/ptrace.h>
 #include <asm/vfp.h>
 
 #include "vfpinstr.h"
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index 0221ba3..b252631 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -34,7 +34,6 @@ #include <linux/kernel.h>
 #include <linux/bitops.h>
 
 #include <asm/div64.h>
-#include <asm/ptrace.h>
 #include <asm/vfp.h>
 
 #include "vfpinstr.h"
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index 989113d..20688bc 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -57,9 +57,6 @@ config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
 
-config GENERIC_BUST_SPINLOCK
-	bool
-
 config ZONE_DMA
 	bool
 	default y
diff --git a/arch/arm26/boot/compressed/misc.c b/arch/arm26/boot/compressed/misc.c
index f17f50e..0714d19 100644
--- a/arch/arm26/boot/compressed/misc.c
+++ b/arch/arm26/boot/compressed/misc.c
@@ -182,7 +182,7 @@ extern int end;
 static ulg free_mem_ptr;
 static ulg free_mem_ptr_end;
 
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
 
 #include "../../../../lib/inflate.c"
 
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
index 93293d0..f735d7e 100644
--- a/arch/arm26/kernel/armksyms.c
+++ b/arch/arm26/kernel/armksyms.c
@@ -20,7 +20,6 @@ #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 
 #include <asm/byteorder.h>
diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c
index 9343889..4169279 100644
--- a/arch/arm26/kernel/ptrace.c
+++ b/arch/arm26/kernel/ptrace.c
@@ -13,7 +13,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c
index 6a8ef8d..379b82d 100644
--- a/arch/arm26/kernel/signal.c
+++ b/arch/arm26/kernel/signal.c
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c
index f290158..4250554 100644
--- a/arch/arm26/mm/memc.c
+++ b/arch/arm26/mm/memc.c
@@ -176,13 +176,9 @@ void __init pgtable_cache_init(void)
 {
 	pte_cache = kmem_cache_create("pte-cache",
 				sizeof(pte_t) * PTRS_PER_PTE,
-				0, 0, pte_cache_ctor, NULL);
-	if (!pte_cache)
-		BUG();
+				0, SLAB_PANIC, pte_cache_ctor, NULL);
 
 	pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE +
 				sizeof(pgd_t) * PTRS_PER_PGD,
-				0, 0, pgd_cache_ctor, NULL);
-	if (!pgd_cache)
-		BUG();
+				0, SLAB_PANIC, pgd_cache_ctor, NULL);
 }
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index ce4013a..3ec7658 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -57,9 +57,6 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default n
 
-config GENERIC_BUST_SPINLOCK
-	bool
-
 config GENERIC_HWEIGHT
 	bool
 	default y
@@ -68,6 +65,11 @@ config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
 
+config GENERIC_BUG
+	bool
+	default y
+	depends on BUG
+
 source "init/Kconfig"
 
 menu "System Type and features"
@@ -106,6 +108,9 @@ choice
 config BOARD_ATSTK1000
 	bool "ATSTK1000 evaluation board"
 	select BOARD_ATSTK1002 if CPU_AT32AP7000
+
+config BOARD_ATNGW100
+	bool "ATNGW100 Network Gateway"
 endchoice
 
 choice
@@ -116,6 +121,8 @@ config	LOADER_U_BOOT
 	bool "U-Boot (or similar) bootloader"
 endchoice
 
+source "arch/avr32/mach-at32ap/Kconfig"
+
 config LOAD_ADDRESS
 	hex
 	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 7b842e9..6115fc1 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -27,6 +27,7 @@ head-$(CONFIG_LOADER_U_BOOT)		+= arch/av
 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_BOARD_ATNGW100)		+= arch/avr32/boards/atngw100/
 core-$(CONFIG_LOADER_U_BOOT)		+= arch/avr32/boot/u-boot/
 core-y					+= arch/avr32/kernel/
 core-y					+= arch/avr32/mm/
diff --git a/arch/avr32/boards/atngw100/Makefile b/arch/avr32/boards/atngw100/Makefile
new file mode 100644
index 0000000..c740aa1
--- /dev/null
+++ b/arch/avr32/boards/atngw100/Makefile
@@ -0,0 +1 @@
+obj-y				+= setup.o flash.o
diff --git a/arch/avr32/boards/atngw100/flash.c b/arch/avr32/boards/atngw100/flash.c
new file mode 100644
index 0000000..f9b32a8
--- /dev/null
+++ b/arch/avr32/boards/atngw100/flash.c
@@ -0,0 +1,95 @@
+/*
+ * ATNGW100 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 atngw100_flash_init(void)
+{
+	int ret;
+
+	ret = smc_set_configuration(0, &flash_config);
+	if (ret < 0) {
+		printk(KERN_ERR "atngw100: failed to set NOR flash timing\n");
+		return ret;
+	}
+
+	platform_device_register(&flash_device);
+
+	return 0;
+}
+device_initcall(atngw100_flash_init);
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
new file mode 100644
index 0000000..9bc37d4
--- /dev/null
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -0,0 +1,124 @@
+/*
+ * Board-specific setup code for the ATNGW100 Network Gateway
+ *
+ * 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/etherdevice.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap7000.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+
+/* Initialized by bootloader-specific startup code. */
+struct tag *bootloader_tags __initdata;
+
+struct eth_addr {
+	u8 addr[6];
+};
+static struct eth_addr __initdata hw_addr[2];
+static struct eth_platform_data __initdata eth_data[2];
+
+static struct spi_board_info spi0_board_info[] __initdata = {
+	{
+		.modalias	= "mtd_dataflash",
+		.max_speed_hz	= 10000000,
+		.chip_select	= 0,
+	},
+};
+
+/*
+ * The next two functions should go away as the boot loader is
+ * supposed to initialize the macb address registers with a valid
+ * ethernet address. But we need to keep it around for a while until
+ * we can be reasonably sure the boot loader does this.
+ *
+ * The phy_id is ignored as the driver will probe for it.
+ */
+static int __init parse_tag_ethernet(struct tag *tag)
+{
+	int i;
+
+	i = tag->u.ethernet.mac_index;
+	if (i < ARRAY_SIZE(hw_addr))
+		memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address,
+		       sizeof(hw_addr[i].addr));
+
+	return 0;
+}
+__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
+
+static void __init set_hw_addr(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	const u8 *addr;
+	void __iomem *regs;
+	struct clk *pclk;
+
+	if (!res)
+		return;
+	if (pdev->id >= ARRAY_SIZE(hw_addr))
+		return;
+
+	addr = hw_addr[pdev->id].addr;
+	if (!is_valid_ether_addr(addr))
+		return;
+
+	/*
+	 * Since this is board-specific code, we'll cheat and use the
+	 * physical address directly as we happen to know that it's
+	 * the same as the virtual address.
+	 */
+	regs = (void __iomem __force *)res->start;
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (!pclk)
+		return;
+
+	clk_enable(pclk);
+	__raw_writel((addr[3] << 24) | (addr[2] << 16)
+		     | (addr[1] << 8) | addr[0], regs + 0x98);
+	__raw_writel((addr[5] << 8) | addr[4], regs + 0x9c);
+	clk_disable(pclk);
+	clk_put(pclk);
+}
+
+struct platform_device *at32_usart_map[1];
+unsigned int at32_nr_usarts = 1;
+
+void __init setup_board(void)
+{
+	at32_map_usart(1, 0);	/* USART 1: /dev/ttyS0, DB9 */
+	at32_setup_serial_console(0);
+}
+
+static int __init atngw100_init(void)
+{
+	/*
+	 * ATNGW100 uses 16-bit SDRAM interface, so we don't need to
+	 * reserve any pins for it.
+	 */
+
+	at32_add_system_devices();
+
+	at32_add_device_usart(0);
+
+	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
+	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
+
+	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+
+	return 0;
+}
+postcore_initcall(atngw100_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 5974768..abe6ca2 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -33,7 +33,7 @@ struct eth_addr {
 static struct eth_addr __initdata hw_addr[2];
 
 static struct eth_platform_data __initdata eth_data[2];
-extern struct lcdc_platform_data atstk1000_fb0_data;
+static struct lcdc_platform_data atstk1000_fb0_data;
 
 static struct spi_board_info spi0_board_info[] __initdata = {
 	{
@@ -148,6 +148,8 @@ #endif
 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
 
 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+	atstk1000_fb0_data.fbmem_start = fbmem_start;
+	atstk1000_fb0_data.fbmem_size = fbmem_size;
 	at32_add_device_lcdc(0, &atstk1000_fb0_data);
 
 	return 0;
diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
index 272c011..2bc4b88 100644
--- a/arch/avr32/boards/atstk1000/setup.c
+++ b/arch/avr32/boards/atstk1000/setup.c
@@ -18,33 +18,3 @@ #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/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
new file mode 100644
index 0000000..c254ffc
--- /dev/null
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -0,0 +1,1085 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc6
+# Thu Apr 12 16:35:07 2007
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=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_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=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_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+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=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 is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+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 and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP7000=y
+# CONFIG_BOARD_ATSTK1000 is not set
+CONFIG_BOARD_ATNGW100=y
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP7000_32_BIT_SMC is not set
+CONFIG_AP7000_16_BIT_SMC=y
+# CONFIG_AP7000_8_BIT_SMC is not set
+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_ZONE_DMA_FLAG=0
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE 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=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=y
+CONFIG_IP_PIMSM_V1=y
+# CONFIG_IP_PIMSM_V2 is not set
+# 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=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+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_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=y
+# CONFIG_IPV6_TUNNEL 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
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+CONFIG_NF_CT_PROTO_GRE=m
+# CONFIG_NF_CT_PROTO_SCTP is not set
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=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 is not set
+# 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_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+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_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_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_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_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_NF_CONNTRACK_IPV6=m
+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_MH=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
+
+#
+# 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=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_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=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 is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES 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_BLKDEVS=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=0x80000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# 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 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# 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=m
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=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=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# 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
+# 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=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 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
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG 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 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=m
+
+#
+# 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=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# 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_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=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_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 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=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
+# 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 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# 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=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_KPROBES 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_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+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
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2e72fd2..2714cf6 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -209,16 +209,17 @@ static const char *mmu_types[] = {
 void __init setup_processor(void)
 {
 	unsigned long config0, config1;
+	unsigned long features;
 	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;
+	config0 = sysreg_read(CONFIG0);
+	config1 = sysreg_read(CONFIG1);
+	cpu_id = SYSREG_BFEXT(PROCESSORID, config0);
+	cpu_rev = SYSREG_BFEXT(PROCESSORREVISION, config0);
+	arch_id = SYSREG_BFEXT(AT, config0);
+	arch_rev = SYSREG_BFEXT(AR, config0);
+	mmu_type = SYSREG_BFEXT(MMUT, config0);
 
 	boot_cpu_data.arch_type = arch_id;
 	boot_cpu_data.cpu_type = cpu_id;
@@ -226,16 +227,16 @@ void __init setup_processor(void)
 	boot_cpu_data.cpu_revision = cpu_rev;
 	boot_cpu_data.tlb_config = mmu_type;
 
-	tmp = (config1 >> 13) & 0x07;
+	tmp = SYSREG_BFEXT(ILSZ, config1);
 	if (tmp) {
-		boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07);
-		boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f);
+		boot_cpu_data.icache.ways = 1 << SYSREG_BFEXT(IASS, config1);
+		boot_cpu_data.icache.sets = 1 << SYSREG_BFEXT(ISET, config1);
 		boot_cpu_data.icache.linesz = 1 << (tmp + 1);
 	}
-	tmp = (config1 >> 3) & 0x07;
+	tmp = SYSREG_BFEXT(DLSZ, config1);
 	if (tmp) {
-		boot_cpu_data.dcache.ways = 1 << (config1 & 0x07);
-		boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f);
+		boot_cpu_data.dcache.ways = 1 << SYSREG_BFEXT(DASS, config1);
+		boot_cpu_data.dcache.sets = 1 << SYSREG_BFEXT(DSET, config1);
 		boot_cpu_data.dcache.linesz = 1 << (tmp + 1);
 	}
 
@@ -250,16 +251,39 @@ void __init setup_processor(void)
 		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))
+	features = 0;
+	if (config0 & SYSREG_BIT(CONFIG0_R)) {
+		features |= AVR32_FEATURE_RMW;
+		printk(" rmw");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_D)) {
+		features |= AVR32_FEATURE_DSP;
+		printk(" dsp");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_S)) {
+		features |= AVR32_FEATURE_SIMD;
+		printk(" simd");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_O)) {
+		features |= AVR32_FEATURE_OCD;
 		printk(" ocd");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_P)) {
+		features |= AVR32_FEATURE_PCTR;
+		printk(" perfctr");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_J)) {
+		features |= AVR32_FEATURE_JAVA;
+		printk(" java");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_F)) {
+		features |= AVR32_FEATURE_FPU;
+		printk(" fpu");
+	}
 	printk("\n");
+	boot_cpu_data.features = features;
 }
 
 #ifdef CONFIG_PROC_FS
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index eeb6679..42657f1 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -100,55 +100,49 @@ dtlb_miss_write:
 
 	.global	tlb_miss_common
 tlb_miss_common:
-	mfsr	r0, SYSREG_PTBR
-	mfsr	r1, SYSREG_TLBEAR
+	mfsr	r0, SYSREG_TLBEAR
+	mfsr	r1, SYSREG_PTBR
 
 	/* Is it the vmalloc space? */
-	bld	r1, 31
+	bld	r0, 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
+	lsr	r2, r0, PGDIR_SHIFT
+	ld.w	r3, r1[r2 << 2]
+	bfextu	r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
+	bld	r3, _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
+	andl	r3, 0xf000
+	sbr	r3, 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
+	ld.w	r2, r3[r1 << 2]
+	mfsr	r0, SYSREG_TLBARLO
+	bld	r2, _PAGE_BIT_PRESENT
 	brcc	page_not_present
 
 	/* Mark the page as accessed */
-	sbr	r1, _PAGE_BIT_ACCESSED
-	st.w	r2[0], r1
+	sbr	r2, _PAGE_BIT_ACCESSED
+	st.w	r3[r1 << 2], r2
 
 	/* Drop software flags */
-	andl	r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
-	mtsr	SYSREG_TLBELO, r1
+	andl	r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
+	mtsr	SYSREG_TLBELO, r2
 
 	/* Figure out which entry we want to replace */
-	mfsr	r0, SYSREG_TLBARLO
+	mfsr	r1, SYSREG_MMUCR
 	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
+	mov	r3, -1			/* All entries have been accessed, */
+	mov	r2, 0			/* so start at 0 */
+	mtsr	SYSREG_TLBARLO, r3	/* and reset TLBAR */
 
+1:	bfins	r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE
+	mtsr	SYSREG_MMUCR, r1
 	tlbw
 
 	tlbmiss_restore
@@ -156,8 +150,8 @@ pgtbl_lookup:
 
 handle_vmalloc_miss:
 	/* Simply do the lookup in init's page table */
-	mov	r0, lo(swapper_pg_dir)
-	orh	r0, hi(swapper_pg_dir)
+	mov	r1, lo(swapper_pg_dir)
+	orh	r1, hi(swapper_pg_dir)
 	rjmp	pgtbl_lookup
 
 
@@ -340,12 +334,34 @@ do_bus_error_read:
 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	r9, SYSREG_RSR_NMI
+	mfsr	r8, SYSREG_RAR_NMI
+	bfextu	r0, r9, MODE_SHIFT, 3
+	brne	2f
+
+1:	pushm	r8, r9	/* PC and SR */
 	mfsr	r12, SYSREG_ECR
 	mov	r11, sp
 	rcall	do_nmi
-	rjmp	bad_return
+	popm	r8-r9
+	mtsr	SYSREG_RAR_NMI, r8
+	tst	r0, r0
+	mtsr	SYSREG_RSR_NMI, r9
+	brne	3f
+
+	ldmts	sp++, r0-lr
+	sub	sp, -4		/* skip r12_orig */
+	rete
+
+2:	sub	r10, sp, -(FRAME_SIZE_FULL - REG_LR)
+	stdsp	sp[4], r10	/* replace saved SP */
+	rjmp	1b
+
+3:	popm	lr
+	sub	sp, -4		/* skip sp */
+	popm	r0-r12
+	sub	sp, -4		/* skip r12_orig */
+	rete
 
 handle_address_fault:
 	sub	sp, 4
@@ -630,9 +646,12 @@ irq_level\level:
 	rcall	do_IRQ
 
 	lddsp	r4, sp[REG_SR]
-	andh	r4, (MODE_MASK >> 16), COH
+	bfextu	r4, r4, SYSREG_M0_OFFSET, 3
+	cp.w	r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET
+	breq	2f
+	cp.w	r4, MODE_USER >> SYSREG_M0_OFFSET
 #ifdef CONFIG_PREEMPT
-	brne	2f
+	brne	3f
 #else
 	brne	1f
 #endif
@@ -649,9 +668,18 @@ #endif
 	sub	sp, -4		/* ignore r12_orig */
 	rete
 
+2:	get_thread_info	r0
+	ld.w	r1, r0[TI_flags]
+	bld	r1, TIF_CPU_GOING_TO_SLEEP
 #ifdef CONFIG_PREEMPT
-2:
-	get_thread_info	r0
+	brcc	3f
+#else
+	brcc	1b
+#endif
+	sub	r1, pc, . - cpu_idle_skip_sleep
+	stdsp	sp[REG_PC], r1
+#ifdef CONFIG_PREEMPT
+3:	get_thread_info r0
 	ld.w	r2, r0[TI_preempt_count]
 	cp.w	r2, 0
 	brne	1b
@@ -662,12 +690,32 @@ #ifdef CONFIG_PREEMPT
 	bld	r4, SYSREG_GM_OFFSET
 	brcs	1b
 	rcall	preempt_schedule_irq
-	rjmp	1b
 #endif
+	rjmp	1b
 	.endm
 
 	.section .irq.text,"ax",@progbits
 
+.global cpu_idle_sleep
+cpu_idle_sleep:
+	mask_interrupts
+	get_thread_info r8
+	ld.w	r9, r8[TI_flags]
+	bld	r9, TIF_NEED_RESCHED
+	brcs	cpu_idle_enable_int_and_exit
+	sbr	r9, TIF_CPU_GOING_TO_SLEEP
+	st.w	r8[TI_flags], r9
+	unmask_interrupts
+	sleep 0
+cpu_idle_skip_sleep:
+	mask_interrupts
+	ld.w	r9, r8[TI_flags]
+	cbr	r9, TIF_CPU_GOING_TO_SLEEP
+	st.w	r8[TI_flags], r9
+cpu_idle_enable_int_and_exit:
+	unmask_interrupts
+	retal	r12
+
 	.global	irq_level0
 	.global	irq_level1
 	.global	irq_level2
diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
index d0abbca..004c94b 100644
--- a/arch/avr32/kernel/kprobes.c
+++ b/arch/avr32/kernel/kprobes.c
@@ -15,7 +15,7 @@ #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/ocd.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe);
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index b599eae..1167fe9 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -12,10 +12,11 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/moduleloader.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleloader.h>
 #include <linux/vmalloc.h>
 
 void *module_alloc(unsigned long size)
@@ -315,10 +316,10 @@ int module_finalize(const Elf_Ehdr *hdr,
 	vfree(module->arch.syminfo);
 	module->arch.syminfo = NULL;
 
-	return 0;
+	return module_bug_finalize(hdr, sechdrs, module);
 }
 
 void module_arch_cleanup(struct module *module)
 {
-
+	module_bug_cleanup(module);
 }
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 0b43259..4e4181e 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -11,6 +11,7 @@ #include <linux/kallsyms.h>
 #include <linux/fs.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
+#include <linux/uaccess.h>
 #include <linux/unistd.h>
 
 #include <asm/sysreg.h>
@@ -19,6 +20,8 @@ #include <asm/ocd.h>
 void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
+extern void cpu_idle_sleep(void);
+
 /*
  * This file handles the architecture-dependent parts of process handling..
  */
@@ -27,9 +30,8 @@ void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
-		/* TODO: Enter sleep mode */
 		while (!need_resched())
-			cpu_relax();
+			cpu_idle_sleep();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
@@ -114,39 +116,178 @@ void release_thread(struct task_struct *
 	/* do nothing */
 }
 
+static void dump_mem(const char *str, const char *log_lvl,
+		     unsigned long bottom, unsigned long top)
+{
+	unsigned long p;
+	int i;
+
+	printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top);
+
+	for (p = bottom & ~31; p < top; ) {
+		printk("%s%04lx: ", log_lvl, 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;
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+	return (p > (unsigned long)tinfo)
+		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+#ifdef CONFIG_FRAME_POINTER
+static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
+			       struct pt_regs *regs, const char *log_lvl)
+{
+	unsigned long lr, fp;
+	struct thread_info *tinfo;
+
+	if (regs)
+		fp = regs->r7;
+	else if (tsk == current)
+		asm("mov %0, r7" : "=r"(fp));
+	else
+		fp = tsk->thread.cpu_context.r7;
+
+	/*
+	 * Walk the stack as long as the frame pointer (a) is within
+	 * the kernel stack of the task, and (b) it doesn't move
+	 * downwards.
+	 */
+	tinfo = task_thread_info(tsk);
+	printk("%sCall trace:\n", log_lvl);
+	while (valid_stack_ptr(tinfo, fp)) {
+		unsigned long new_fp;
+
+		lr = *(unsigned long *)fp;
+#ifdef CONFIG_KALLSYMS
+		printk("%s [<%08lx>] ", log_lvl, lr);
+#else
+		printk(" [<%08lx>] ", lr);
+#endif
+		print_symbol("%s\n", lr);
+
+		new_fp = *(unsigned long *)(fp + 4);
+		if (new_fp <= fp)
+			break;
+		fp = new_fp;
+	}
+	printk("\n");
+}
+#else
+static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
+			       struct pt_regs *regs, const char *log_lvl)
+{
+	unsigned long addr;
+
+	printk("%sCall trace:\n", log_lvl);
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		if (kernel_text_address(addr)) {
+#ifdef CONFIG_KALLSYMS
+			printk("%s [<%08lx>] ", log_lvl, addr);
+#else
+			printk(" [<%08lx>] ", addr);
+#endif
+			print_symbol("%s\n", addr);
+		}
+	}
+	printk("\n");
+}
+#endif
+
+void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
+			struct pt_regs *regs, const char *log_lvl)
+{
+	struct thread_info *tinfo;
+
+	if (sp == 0) {
+		if (tsk)
+			sp = tsk->thread.cpu_context.ksp;
+		else
+			sp = (unsigned long)&tinfo;
+	}
+	if (!tsk)
+		tsk = current;
+
+	tinfo = task_thread_info(tsk);
+
+	if (valid_stack_ptr(tinfo, sp)) {
+		dump_mem("Stack: ", log_lvl, sp,
+			 THREAD_SIZE + (unsigned long)tinfo);
+		show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl);
+	}
+}
+
+void show_stack(struct task_struct *tsk, unsigned long *stack)
+{
+	show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
+}
+
+void dump_stack(void)
+{
+	unsigned long stack;
+
+	show_trace_log_lvl(current, &stack, NULL, "");
+}
+EXPORT_SYMBOL(dump_stack);
+
 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)
+void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
 {
 	unsigned long sp = regs->sp;
 	unsigned long lr = regs->lr;
 	unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
 
-	if (!user_mode(regs))
+	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",
+		printk("%s", log_lvl);
+		print_symbol("PC is at %s\n", instruction_pointer(regs));
+		printk("%s", log_lvl);
+		print_symbol("LR is at %s\n", lr);
+	}
+
+	printk("%spc : [<%08lx>]    lr : [<%08lx>]    %s\n"
+	       "%ssp : %08lx  r12: %08lx  r11: %08lx\n",
+	       log_lvl, instruction_pointer(regs), lr, print_tainted(),
+	       log_lvl, sp, regs->r12, regs->r11);
+	printk("%sr10: %08lx  r9 : %08lx  r8 : %08lx\n",
+	       log_lvl, regs->r10, regs->r9, regs->r8);
+	printk("%sr7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+	       log_lvl, regs->r7, regs->r6, regs->r5, regs->r4);
+	printk("%sr3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+	       log_lvl, regs->r3, regs->r2, regs->r1, regs->r0);
+	printk("%sFlags: %c%c%c%c%c\n", log_lvl,
 	       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",
+	printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl,
 	       regs->sr & SR_H ? 'H' : 'h',
 	       regs->sr & SR_R ? 'R' : 'r',
 	       regs->sr & SR_J ? 'J' : 'j',
@@ -156,9 +297,21 @@ void show_regs(struct pt_regs *regs)
 	       regs->sr & SR_I1M ? '1' : '.',
 	       regs->sr & SR_I0M ? '0' : '.',
 	       regs->sr & SR_GM ? 'G' : 'g');
-	printk("CPU Mode: %s\n", cpu_modes[mode]);
+	printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
+	printk("%sProcess: %s [%d] (task: %p thread: %p)\n",
+	       log_lvl, current->comm, current->pid, current,
+	       task_thread_info(current));
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	unsigned long sp = regs->sp;
+
+	if (!user_mode(regs))
+		sp = (unsigned long)regs + FRAME_SIZE_FULL;
 
-	show_trace(NULL, (unsigned long *)sp, regs);
+	show_regs_log_lvl(regs, "");
+	show_trace_log_lvl(current, (unsigned long *)sp, regs, "");
 }
 EXPORT_SYMBOL(show_regs);
 
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 6f4388f..8ac74dd 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -9,7 +9,6 @@ #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>
@@ -21,7 +20,7 @@ #include <asm/traps.h>
 #include <asm/uaccess.h>
 #include <asm/ocd.h>
 #include <asm/mmu_context.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 
 static struct pt_regs *get_user_regs(struct task_struct *tsk)
 {
@@ -300,7 +299,7 @@ asmlinkage void do_debug_priv(struct pt_
 	else
 		die_val = DIE_BREAKPOINT;
 
-	if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP)
+	if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
 		return;
 
 	if (likely(ds & DS_SSS)) {
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index a1a7c3c..b279d66 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -8,12 +8,14 @@
 
 #include <linux/clk.h>
 #include <linux/init.h>
+#include <linux/initrd.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/pfn.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/kernel.h>
@@ -30,13 +32,6 @@ #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...
  */
@@ -48,48 +43,193 @@ EXPORT_SYMBOL(boot_cpu_data);
 static char __initdata 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...
+ * Standard memory resources
  */
-static struct tag_mem_range __initdata mem_range_cache[32];
-static unsigned mem_range_next_free;
+static struct resource __initdata kernel_data = {
+	.name	= "Kernel data",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_MEM,
+};
+static struct resource __initdata kernel_code = {
+	.name	= "Kernel code",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_MEM,
+	.sibling = &kernel_data,
+};
 
 /*
- * Standard memory resources
+ * Available system RAM and reserved regions as singly linked
+ * lists. These lists are traversed using the sibling pointer in
+ * struct resource and are kept sorted at all times.
  */
-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,
-	},
-};
+static struct resource *__initdata system_ram;
+static struct resource *__initdata reserved = &kernel_code;
+
+/*
+ * We need to allocate these before the bootmem allocator is up and
+ * running, so we need this "cache". 32 entries are probably enough
+ * for all but the most insanely complex systems.
+ */
+static struct resource __initdata res_cache[32];
+static unsigned int __initdata res_cache_next_free;
+
+static void __init resource_init(void)
+{
+	struct resource *mem, *res;
+	struct resource *new;
+
+	kernel_code.start = __pa(init_mm.start_code);
+
+	for (mem = system_ram; mem; mem = mem->sibling) {
+		new = alloc_bootmem_low(sizeof(struct resource));
+		memcpy(new, mem, sizeof(struct resource));
+
+		new->sibling = NULL;
+		if (request_resource(&iomem_resource, new))
+			printk(KERN_WARNING "Bad RAM resource %08x-%08x\n",
+			       mem->start, mem->end);
+	}
+
+	for (res = reserved; res; res = res->sibling) {
+		new = alloc_bootmem_low(sizeof(struct resource));
+		memcpy(new, res, sizeof(struct resource));
+
+		new->sibling = NULL;
+		if (insert_resource(&iomem_resource, new))
+			printk(KERN_WARNING
+			       "Bad reserved resource %s (%08x-%08x)\n",
+			       res->name, res->start, res->end);
+	}
+}
+
+static void __init
+add_physical_memory(resource_size_t start, resource_size_t end)
+{
+	struct resource *new, *next, **pprev;
+
+	for (pprev = &system_ram, next = system_ram; next;
+	     pprev = &next->sibling, next = next->sibling) {
+		if (end < next->start)
+			break;
+		if (start <= next->end) {
+			printk(KERN_WARNING
+			       "Warning: Physical memory map is broken\n");
+			printk(KERN_WARNING
+			       "Warning: %08x-%08x overlaps %08x-%08x\n",
+			       start, end, next->start, next->end);
+			return;
+		}
+	}
+
+	if (res_cache_next_free >= ARRAY_SIZE(res_cache)) {
+		printk(KERN_WARNING
+		       "Warning: Failed to add physical memory %08x-%08x\n",
+		       start, end);
+		return;
+	}
+
+	new = &res_cache[res_cache_next_free++];
+	new->start = start;
+	new->end = end;
+	new->name = "System RAM";
+	new->flags = IORESOURCE_MEM;
+
+	*pprev = new;
+}
+
+static int __init
+add_reserved_region(resource_size_t start, resource_size_t end,
+		    const char *name)
+{
+	struct resource *new, *next, **pprev;
+
+	if (end < start)
+		return -EINVAL;
+
+	if (res_cache_next_free >= ARRAY_SIZE(res_cache))
+		return -ENOMEM;
+
+	for (pprev = &reserved, next = reserved; next;
+	     pprev = &next->sibling, next = next->sibling) {
+		if (end < next->start)
+			break;
+		if (start <= next->end)
+			return -EBUSY;
+	}
+
+	new = &res_cache[res_cache_next_free++];
+	new->start = start;
+	new->end = end;
+	new->name = name;
+	new->flags = IORESOURCE_MEM;
+
+	*pprev = new;
+
+	return 0;
+}
+
+static unsigned long __init
+find_free_region(const struct resource *mem, resource_size_t size,
+		 resource_size_t align)
+{
+	struct resource *res;
+	unsigned long target;
+
+	target = ALIGN(mem->start, align);
+	for (res = reserved; res; res = res->sibling) {
+		if ((target + size) <= res->start)
+			break;
+		if (target <= res->end)
+			target = ALIGN(res->end + 1, align);
+	}
+
+	if ((target + size) > (mem->end + 1))
+		return mem->end + 1;
+
+	return target;
+}
+
+static int __init
+alloc_reserved_region(resource_size_t *start, resource_size_t size,
+		      resource_size_t align, const char *name)
+{
+	struct resource *mem;
+	resource_size_t target;
+	int ret;
+
+	for (mem = system_ram; mem; mem = mem->sibling) {
+		target = find_free_region(mem, size, align);
+		if (target <= mem->end) {
+			ret = add_reserved_region(target, target + size - 1,
+						  name);
+			if (!ret)
+				*start = target;
+			return ret;
+		}
+	}
 
-#define kernel_code	mem_res[0]
-#define kernel_data	mem_res[1]
+	return -ENOMEM;
+}
 
 /*
  * 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.
+ *     a block of fbmem_size bytes will be reserved before bootmem
+ *     initialization. It will be aligned to the largest page size
+ *     that fbmem_size is a multiple of.
  *   - 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.
+ *     reserved at the physical address fbmem_start if possible. If
+ *     it collides with other reserved memory, a different block of
+ *     same size will be allocated, just as if fbmem_start was zero.
  *
  * 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;
+resource_size_t __initdata fbmem_start;
+resource_size_t __initdata fbmem_size;
 
 /*
  * "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for
@@ -103,48 +243,42 @@ static unsigned long __initdata fbmem_si
  */
 static int __init early_parse_fbmem(char *p)
 {
+	int ret;
+	unsigned long align;
+
 	fbmem_size = memparse(p, &p);
-	if (*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);
+		ret = add_reserved_region(fbmem_start,
+					  fbmem_start + fbmem_size - 1,
+					  "Framebuffer");
+		if (ret) {
+			printk(KERN_WARNING
+			       "Failed to reserve framebuffer memory\n");
+			fbmem_start = 0;
+		}
+	}
 
-		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);
+	if (!fbmem_start) {
+		if ((fbmem_size & 0x000fffffUL) == 0)
+			align = 0x100000;	/* 1 MiB */
+		else if ((fbmem_size & 0x0000ffffUL) == 0)
+			align = 0x10000;	/* 64 KiB */
+		else
+			align = 0x1000;		/* 4 KiB */
+
+		ret = alloc_reserved_region(&fbmem_start, fbmem_size,
+					    align, "Framebuffer");
+		if (ret) {
+			printk(KERN_WARNING
+			       "Failed to allocate framebuffer memory\n");
+			fbmem_size = 0;
+		}
 	}
+
+	return 0;
 }
+early_param("fbmem", early_parse_fbmem);
 
 static int __init parse_tag_core(struct tag *tag)
 {
@@ -157,11 +291,9 @@ static int __init parse_tag_core(struct 
 }
 __tagtable(ATAG_CORE, parse_tag_core);
 
-static int __init parse_tag_mem_range(struct tag *tag,
-				      struct tag_mem_range **root)
+static int __init parse_tag_mem(struct tag *tag)
 {
-	struct tag_mem_range *cur, **pprev;
-	struct tag_mem_range *new;
+	unsigned long start, end;
 
 	/*
 	 * Ignore zero-sized entries. If we're running standalone, the
@@ -171,34 +303,53 @@ static int __init parse_tag_mem_range(st
 	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 >= ARRAY_SIZE(mem_range_cache))
-		panic("Physical memory map too complex!\n");
+	start = tag->u.mem_range.addr;
+	end = tag->u.mem_range.addr + tag->u.mem_range.size - 1;
+
+	add_physical_memory(start, end);
+	return 0;
+}
+__tagtable(ATAG_MEM, parse_tag_mem);
+
+static int __init parse_tag_rdimg(struct tag *tag)
+{
+#ifdef CONFIG_INITRD
+	struct tag_mem_range *mem = &tag->u.mem_range;
+	int ret;
 
-	new = &mem_range_cache[mem_range_next_free++];
-	*new = tag->u.mem_range;
+	if (initrd_start) {
+		printk(KERN_WARNING
+		       "Warning: Only the first initrd image will be used\n");
+		return 0;
+	}
 
-	pprev = root;
-	cur = *root;
-	while (cur) {
-		pprev = &cur->next;
-		cur = cur->next;
+	ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+				  "initrd");
+	if (ret) {
+		printk(KERN_WARNING
+		       "Warning: Failed to reserve initrd memory\n");
+		return ret;
 	}
 
-	*pprev = new;
-	new->next = NULL;
+	initrd_start = (unsigned long)__va(mem->addr);
+	initrd_end = initrd_start + mem->size;
+#else
+	printk(KERN_WARNING "RAM disk image present, but "
+	       "no initrd support in kernel, ignoring\n");
+#endif
 
 	return 0;
 }
+__tagtable(ATAG_RDIMG, parse_tag_rdimg);
 
-static int __init parse_tag_mem(struct tag *tag)
+static int __init parse_tag_rsvd_mem(struct tag *tag)
 {
-	return parse_tag_mem_range(tag, &mem_phys);
+	struct tag_mem_range *mem = &tag->u.mem_range;
+
+	return add_reserved_region(mem->addr, mem->addr + mem->size - 1,
+				   "Reserved");
 }
-__tagtable(ATAG_MEM, parse_tag_mem);
+__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
 
 static int __init parse_tag_cmdline(struct tag *tag)
 {
@@ -207,12 +358,6 @@ static int __init parse_tag_cmdline(stru
 }
 __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)
 {
 	/*
@@ -223,12 +368,6 @@ static int __init parse_tag_clock(struct
 }
 __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);
-
 /*
  * Scan the tag table for this tag, and call its parse function. The
  * tag table is built by the linker from all the __tagtable
@@ -260,10 +399,137 @@ static void __init parse_tags(struct tag
 			       t->hdr.tag);
 }
 
+/*
+ * Find a free memory region large enough for storing the
+ * bootmem bitmap.
+ */
+static unsigned long __init
+find_bootmap_pfn(const struct resource *mem)
+{
+	unsigned long bootmap_pages, bootmap_len;
+	unsigned long node_pages = PFN_UP(mem->end - mem->start + 1);
+	unsigned long bootmap_start;
+
+	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 that we don't collide with any reserved
+	 * regions, which includes the kernel image and any RAMDISK
+	 * images.
+	 */
+	bootmap_start = find_free_region(mem, bootmap_len, PAGE_SIZE);
+
+	return bootmap_start >> PAGE_SHIFT;
+}
+
+#define MAX_LOWMEM	HIGHMEM_START
+#define MAX_LOWMEM_PFN	PFN_DOWN(MAX_LOWMEM)
+
+static void __init setup_bootmem(void)
+{
+	unsigned bootmap_size;
+	unsigned long first_pfn, bootmap_pfn, pages;
+	unsigned long max_pfn, max_low_pfn;
+	unsigned node = 0;
+	struct resource *res;
+
+	printk(KERN_INFO "Physical memory:\n");
+	for (res = system_ram; res; res = res->sibling)
+		printk("  %08x-%08x\n", res->start, res->end);
+	printk(KERN_INFO "Reserved memory:\n");
+	for (res = reserved; res; res = res->sibling)
+		printk("  %08x-%08x: %s\n",
+		       res->start, res->end, res->name);
+
+	nodes_clear(node_online_map);
+
+	if (system_ram->sibling)
+		printk(KERN_WARNING "Only using first memory bank\n");
+
+	for (res = system_ram; res; res = NULL) {
+		first_pfn = PFN_UP(res->start);
+		max_low_pfn = max_pfn = PFN_DOWN(res->end + 1);
+		bootmap_pfn = find_bootmap_pfn(res);
+		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);
+
+		/*
+		 * 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 bootmem bitmap... */
+		reserve_bootmem_node(NODE_DATA(node),
+				     PFN_PHYS(bootmap_pfn),
+				     bootmap_size);
+
+		/* ...and any other reserved regions. */
+		for (res = reserved; res; res = res->sibling) {
+			if (res->start > PFN_PHYS(max_pfn))
+				break;
+
+			/*
+			 * resource_init will complain about partial
+			 * overlaps, so we'll just ignore such
+			 * resources for now.
+			 */
+			if (res->start >= PFN_PHYS(first_pfn)
+			    && res->end < PFN_PHYS(max_pfn))
+				reserve_bootmem_node(
+					NODE_DATA(node), res->start,
+					res->end - res->start + 1);
+		}
+
+		node_set_online(node);
+	}
+}
+
 void __init setup_arch (char **cmdline_p)
 {
 	struct clk *cpu_clk;
 
+	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;
+
+	/*
+	 * Include .init section to make allocations easier. It will
+	 * be removed before the resource is actually requested.
+	 */
+	kernel_code.start = __pa(__init_begin);
+	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);
+
 	parse_tags(bootloader_tags);
 
 	setup_processor();
@@ -289,24 +555,16 @@ void __init setup_arch (char **cmdline_p
 		       ((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, boot_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/time.c b/arch/avr32/kernel/time.c
index c10833f..7014a35 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2006 Atmel Corporation
+ * Copyright (C) 2004-2007 Atmel Corporation
  *
  * Based on MIPS implementation arch/mips/kernel/time.c
  *   Copyright 2001 MontaVista Software Inc.
@@ -20,18 +20,25 @@ #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/profile.h>
 #include <linux/sysdev.h>
+#include <linux/err.h>
 
 #include <asm/div64.h>
 #include <asm/sysreg.h>
 #include <asm/io.h>
 #include <asm/sections.h>
 
-static cycle_t read_cycle_count(void)
+/* how many counter cycles in a jiffy? */
+static u32 cycles_per_jiffy;
+
+/* the count value for the next timer interrupt */
+static u32 expirelo;
+
+cycle_t __weak read_cycle_count(void)
 {
 	return (cycle_t)sysreg_read(COUNT);
 }
 
-static struct clocksource clocksource_avr32 = {
+struct clocksource __weak clocksource_avr32 = {
 	.name		= "avr32",
 	.rating		= 350,
 	.read		= read_cycle_count,
@@ -40,12 +47,20 @@ static struct clocksource clocksource_av
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+irqreturn_t __weak timer_interrupt(int irq, void *dev_id);
+
+struct irqaction timer_irqaction = {
+	.handler	= timer_interrupt,
+	.flags		= IRQF_DISABLED,
+	.name		= "timer",
+};
+
 /*
  * By default we provide the null RTC ops
  */
 static unsigned long null_rtc_get_time(void)
 {
-	return mktime(2004, 1, 1, 0, 0, 0);
+	return mktime(2007, 1, 1, 0, 0, 0);
 }
 
 static int null_rtc_set_time(unsigned long sec)
@@ -56,23 +71,14 @@ static int null_rtc_set_time(unsigned lo
 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;
+	u32 count;
 
 	/* Ack this timer interrupt and set the next one */
 	expirelo += cycles_per_jiffy;
+	/* setting COMPARE to 0 stops the COUNT-COMPARE */
 	if (expirelo == 0) {
-		printk(KERN_DEBUG "expirelo == 0\n");
 		sysreg_write(COMPARE, expirelo + 1);
 	} else {
 		sysreg_write(COMPARE, expirelo);
@@ -86,27 +92,56 @@ static void avr32_timer_ack(void)
 	}
 }
 
-static unsigned int avr32_hpt_read(void)
+int __weak avr32_hpt_init(void)
 {
-	return sysreg_read(COUNT);
+	int ret;
+	unsigned long mult, shift, count_hz;
+
+	count_hz = clk_get_rate(boot_cpu_data.clk);
+	shift = clocksource_avr32.shift;
+	mult = clocksource_hz2mult(count_hz, shift);
+	clocksource_avr32.mult = mult;
+
+	{
+		u64 tmp;
+
+		tmp = TICK_NSEC;
+		tmp <<= shift;
+		tmp += mult / 2;
+		do_div(tmp, mult);
+
+		cycles_per_jiffy = tmp;
+	}
+
+	ret = setup_irq(0, &timer_irqaction);
+	if (ret) {
+		pr_debug("timer: could not request IRQ 0: %d\n", ret);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "timer: AT32AP COUNT-COMPARE at irq 0, "
+			"%lu.%03lu MHz\n",
+			((count_hz + 500) / 1000) / 1000,
+			((count_hz + 500) / 1000) % 1000);
+
+	return 0;
 }
 
 /*
  * 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.
+ * 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)
+int __weak avr32_hpt_start(void)
 {
-	count = sysreg_read(COUNT) - count;
+	u32 count = sysreg_read(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);
+
+	return 0;
 }
 
 /*
@@ -115,26 +150,18 @@ static void avr32_hpt_init(unsigned int 
  *
  * In UP mode, it is invoked from the (global) timer_interrupt.
  */
-static void local_timer_interrupt(int irq, void *dev_id)
+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)
+irqreturn_t __weak 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
 	 */
@@ -153,60 +180,37 @@ timer_interrupt(int irq, void *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;
 
+	/*
+	 * Make sure we don't get any COMPARE interrupts before we can
+	 * handle them.
+	 */
+	sysreg_write(COMPARE, 0);
+
 	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;
+	ret = avr32_hpt_init();
+	if (ret) {
+		pr_debug("timer: failed setup: %d\n", ret);
+		return;
 	}
 
-	/* 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);
+		pr_debug("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);
+	ret = avr32_hpt_start();
+	if (ret) {
+		pr_debug("timer: failed starting: %d\n", ret);
+		return;
+	}
 }
 
 static struct sysdev_class timer_class = {
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index adc01a1..4de9edf 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -5,257 +5,120 @@
  * 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/bug.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/module.h>
 #include <linux/notifier.h>
+#include <linux/sched.h>
+#include <linux/uaccess.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;
-}
+#include <asm/ocd.h>
+#include <asm/sysreg.h>
+#include <asm/traps.h>
 
-static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
-{
-	return (p > (unsigned long)tinfo)
-		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
-}
+static DEFINE_SPINLOCK(die_lock);
 
-#ifdef CONFIG_FRAME_POINTER
-static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
-				struct pt_regs *regs)
+void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
 {
-	unsigned long lr, fp;
-	struct thread_info *tinfo;
-
-	tinfo = (struct thread_info *)
-		((unsigned long)sp & ~(THREAD_SIZE - 1));
-
-	if (regs)
-		fp = regs->r7;
-	else if (tsk == current)
-		asm("mov %0, r7" : "=r"(fp));
-	else
-		fp = tsk->thread.cpu_context.r7;
-
-	/*
-	 * Walk the stack as long as the frame pointer (a) is within
-	 * the kernel stack of the task, and (b) it doesn't move
-	 * downwards.
-	 */
-	while (valid_stack_ptr(tinfo, fp)) {
-		unsigned long new_fp;
-
-		lr = *(unsigned long *)fp;
-		printk(" [<%08lx>] ", lr);
-		print_symbol("%s\n", lr);
+	static int die_counter;
 
-		new_fp = *(unsigned long *)(fp + 4);
-		if (new_fp <= fp)
-			break;
-		fp = new_fp;
-	}
-	printk("\n");
-}
-#else
-static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
-				struct pt_regs *regs)
-{
-	unsigned long addr;
+	console_verbose();
+	spin_lock_irq(&die_lock);
+	bust_spinlocks(1);
 
-	while (!kstack_end(sp)) {
-		addr = *sp++;
-		if (kernel_text_address(addr)) {
-			printk(" [<%08lx>] ", addr);
-			print_symbol("%s\n", addr);
-		}
-	}
-}
+	printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG,
+	       str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
 #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");
+#ifdef CONFIG_FRAME_POINTER
+	printk("FRAME_POINTER ");
 #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;
-		}
+	if (current_cpu_data.features & AVR32_FEATURE_OCD) {
+		unsigned long did = __mfdr(DBGREG_DID);
+		printk("chip: 0x%03lx:0x%04lx rev %lu\n",
+		       (did >> 1) & 0x7ff,
+		       (did >> 12) & 0x7fff,
+		       (did >> 28) & 0xf);
+	} else {
+		printk("cpu: arch %u r%u / core %u r%u\n",
+		       current_cpu_data.arch_type,
+		       current_cpu_data.arch_revision,
+		       current_cpu_data.cpu_type,
+		       current_cpu_data.cpu_revision);
 	}
 
-	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);
+	print_modules();
+	show_regs_log_lvl(regs, KERN_EMERG);
+	show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
+	bust_spinlocks(0);
+	spin_unlock_irq(&die_lock);
 
-ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
 
-int register_die_notifier(struct notifier_block *nb)
-{
-	pr_debug("register_die_notifier: %p\n", nb);
+	if (panic_on_oops)
+		panic("Fatal exception");
 
-	return atomic_notifier_chain_register(&avr32_die_chain, nb);
+	do_exit(err);
 }
-EXPORT_SYMBOL(register_die_notifier);
 
-int unregister_die_notifier(struct notifier_block *nb)
+void _exception(long signr, struct pt_regs *regs, int code,
+		unsigned long addr)
 {
-	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;
+	siginfo_t info;
 
-	console_verbose();
-	spin_lock_irq(&die_lock);
-	bust_spinlocks(1);
+	if (!user_mode(regs))
+		die("Unhandled exception in kernel mode", regs, signr);
 
-	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);
+	memset(&info, 0, sizeof(info));
+	info.si_signo = signr;
+	info.si_code = code;
+	info.si_addr = (void __user *)addr;
+	force_sig_info(signr, &info, current);
 
-	if (!user_mode(regs) || in_interrupt()) {
-		dump_mem("Stack: ", regs->sp,
-			 THREAD_SIZE + (unsigned long)tsk->thread_info);
+	/*
+	 * Init gets no signals that it doesn't have a handler for.
+	 * That's all very well, but if it has caused a synchronous
+	 * exception and we ignore the resulting signal, it will just
+	 * generate the same exception over and over again and we get
+	 * nowhere.  Better to kill it and let the kernel panic.
+	 */
+	if (is_init(current)) {
+		__sighandler_t handler;
+
+		spin_lock_irq(&current->sighand->siglock);
+		handler = current->sighand->action[signr-1].sa.sa_handler;
+		spin_unlock_irq(&current->sighand->siglock);
+		if (handler == SIG_DFL) {
+			/* init has generated a synchronous exception
+			   and it doesn't have a handler for the signal */
+			printk(KERN_CRIT "init has generated signal %ld "
+			       "but has no handler for it\n", signr);
+			do_exit(signr);
+		}
 	}
-
-	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();
+	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
+	show_regs_log_lvl(regs, KERN_ALERT);
+	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
 }
 
 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();
+	die("Critical exception", regs, SIGKILL);
 }
 
 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);
+	_exception(SIGBUS, regs, BUS_ADRALN, regs->pc);
 }
 
 /* This way of handling undefined instructions is stolen from ARM */
@@ -280,7 +143,8 @@ static int do_cop_absent(u32 insn)
 {
 	int cop_nr;
 	u32 cpucr;
-	if ( (insn & 0xfdf00000) == 0xf1900000 )
+
+	if ((insn & 0xfdf00000) == 0xf1900000)
 		/* LDC0 */
 		cop_nr = 0;
 	else
@@ -292,136 +156,91 @@ static int do_cop_absent(u32 insn)
 	sysreg_write(CPUCR, cpucr);
 
 	cpucr = sysreg_read(CPUCR);
-	if ( !(cpucr & (1 << (24 + cop_nr))) ){
-		printk("Coprocessor #%i not found!\n", cop_nr);
-		return -1;
-	}
+	if (!(cpucr & (1 << (24 + cop_nr))))
+		return -ENODEV;
 
 	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)
+int is_valid_bugaddr(unsigned long pc)
 {
+	unsigned short opcode;
 
+	if (pc < PAGE_OFFSET)
+		return 0;
+	if (probe_kernel_address((u16 *)pc, opcode))
+		return 0;
+
+	return opcode == AVR32_BUG_OPCODE;
 }
-#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;
+	long code;
 
-	if (!user_mode(regs))
-		goto kernel_trap;
+	if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) {
+		enum bug_trap_type type;
+
+		type = report_bug(regs->pc);
+		switch (type) {
+		case BUG_TRAP_TYPE_NONE:
+			break;
+		case BUG_TRAP_TYPE_WARN:
+			regs->pc += 2;
+			return;
+		case BUG_TRAP_TYPE_BUG:
+			die("Kernel BUG", regs, SIGKILL);
+		}
+	}
 
 	local_irq_enable();
 
-	pc = (void __user *)instruction_pointer(regs);
-	if (__get_user(insn, (u32 __user *)pc))
-		goto invalid_area;
+	if (user_mode(regs)) {
+		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)
+		if (ecr == ECR_COPROC_ABSENT && !do_cop_absent(insn))
 			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_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);
 	}
-	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;
+		code = ILL_PRVOPC;
 		break;
 	case ECR_COPROC_ABSENT:
-		info.si_code = ILL_COPROC;
+		code = ILL_COPROC;
 		break;
 	default:
-		BUG();
+		code = ILL_ILLOPC;
+		break;
 	}
 
-	force_sig_info(SIGILL, &info, current);
+	_exception(SIGILL, regs, code, regs->pc);
 	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);
+invalid_area:
+	_exception(SIGSEGV, regs, SEGV_MAPERR, regs->pc);
 }
 
 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);
+	/* We have no FPU yet */
+	_exception(SIGILL, regs, ILL_COPROC, regs->pc);
 }
 
 
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index ef13b7c..7ad20cf 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -26,6 +26,12 @@ SECTIONS
 			_sinittext = .;
 			*(.text.reset)
 			*(.init.text)
+			/*
+			 * .exit.text is discarded at runtime, not
+			 * link time, to deal with references from
+			 * __bug_table
+			 */
+			*(.exit.text)
 			_einittext = .;
 		. = ALIGN(4);
 		__tagtable_begin = .;
@@ -86,6 +92,8 @@ #endif
 		__stop___ex_table = .;
 	}
 
+	BUG_TABLE
+
 	RODATA
 
 	. = ALIGN(8192);
@@ -126,7 +134,6 @@ #endif
 	 * thrown away, as cleanup code is never called unless it's a module.
 	 */
 	/DISCARD/       	: {
-		*(.exit.text)
 		*(.exit.data)
 		*(.exitcall.exit)
 	}
diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
new file mode 100644
index 0000000..eb30783
--- /dev/null
+++ b/arch/avr32/mach-at32ap/Kconfig
@@ -0,0 +1,31 @@
+if PLATFORM_AT32AP
+
+menu "Atmel AVR32 AP options"
+
+choice
+	prompt "AT32AP7000 static memory bus width"
+	depends on CPU_AT32AP7000
+	default AP7000_16_BIT_SMC
+	help
+	  Define the width of the AP7000 external static memory interface.
+	  This is used to determine how to mangle the address and/or data
+	  when doing little-endian port access.
+
+	  The current code can only support a single external memory bus
+	  width for all chip selects, excluding the flash (which is using
+	  raw access and is thus not affected by any of this.)
+
+config AP7000_32_BIT_SMC
+	bool "32 bit"
+
+config AP7000_16_BIT_SMC
+	bool "16 bit"
+
+config AP7000_8_BIT_SMC
+	bool "8 bit"
+
+endchoice
+
+endmenu
+
+endif # PLATFORM_AT32AP
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index b21bea9..f1d3957 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,2 +1,3 @@
 obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP7000)	+= at32ap7000.o
+obj-$(CONFIG_CPU_AT32AP7000)	+= time-tc.o
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 472703f..56db45b 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -18,6 +18,7 @@ #include <asm/arch/portmux.h>
 #include <asm/arch/sm.h>
 
 #include "clock.h"
+#include "hmatrix.h"
 #include "pio.h"
 #include "sm.h"
 
@@ -416,7 +417,15 @@ struct platform_device at32_sm_device = 
 	.resource	= sm_resource,
 	.num_resources	= ARRAY_SIZE(sm_resource),
 };
-DEV_CLK(pclk, at32_sm, pbb, 0);
+static struct clk at32_sm_pclk = {
+	.name		= "pclk",
+	.dev		= &at32_sm_device.dev,
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.users		= 1,
+	.index		= 0,
+};
 
 static struct resource intc0_resource[] = {
 	PBMEM(0xfff00400),
@@ -442,6 +451,7 @@ static struct clk hramc_clk = {
 	.mode		= hsb_clk_mode,
 	.get_rate	= hsb_clk_get_rate,
 	.users		= 1,
+	.index		= 3,
 };
 
 static struct resource smc0_resource[] = {
@@ -467,6 +477,57 @@ static struct clk pico_clk = {
 };
 
 /* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+	.name		= "hmatrix_clk",
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.index		= 2,
+	.users		= 1,
+};
+#define HMATRIX_BASE	((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg)					\
+	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value)				\
+	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+	u32 sfr;
+
+	clk_enable(&hmatrix_clk);
+	sfr = hmatrix_readl(SFR4);
+	sfr |= mask;
+	hmatrix_writel(SFR4, sfr);
+	clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ *  System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+	PBMEM(0xfff00c00),
+	IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+	.name		= "systc",
+	.id		= 0,
+	.resource	= at32_systc0_resource,
+	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
+/* --------------------------------------------------------------------
  *  PIO
  * -------------------------------------------------------------------- */
 
@@ -514,6 +575,8 @@ void __init at32_add_system_devices(void
 	platform_device_register(&smc0_device);
 	platform_device_register(&pdc_device);
 
+	platform_device_register(&at32_systc0_device);
+
 	platform_device_register(&pio0_device);
 	platform_device_register(&pio1_device);
 	platform_device_register(&pio2_device);
@@ -950,6 +1013,7 @@ struct clk *at32_clock_list[] = {
 	&pbb_clk,
 	&at32_sm_pclk,
 	&at32_intc0_pclk,
+	&hmatrix_clk,
 	&ebi_clk,
 	&hramc_clk,
 	&smc0_pclk,
@@ -962,6 +1026,7 @@ struct clk *at32_clock_list[] = {
 	&pio2_mck,
 	&pio3_mck,
 	&pio4_mck,
+	&at32_systc0_pclk,
 	&atmel_usart0_usart,
 	&atmel_usart1_usart,
 	&atmel_usart2_usart,
@@ -1024,6 +1089,9 @@ void __init at32_clock_init(void)
 	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
 		struct clk *clk = at32_clock_list[i];
 
+		if (clk->users == 0)
+			continue;
+
 		if (clk->mode == &cpu_clk_mode)
 			cpu_mask |= 1 << clk->index;
 		else if (clk->mode == &hsb_clk_mode)
diff --git a/arch/avr32/mach-at32ap/hmatrix.h b/arch/avr32/mach-at32ap/hmatrix.h
new file mode 100644
index 0000000..d10bfb6
--- /dev/null
+++ b/arch/avr32/mach-at32ap/hmatrix.h
@@ -0,0 +1,182 @@
+/*
+ * Register definitions for High-Speed Bus Matrix
+ */
+#ifndef __HMATRIX_H
+#define __HMATRIX_H
+
+/* HMATRIX register offsets */
+#define HMATRIX_MCFG0				0x0000
+#define HMATRIX_MCFG1				0x0004
+#define HMATRIX_MCFG2				0x0008
+#define HMATRIX_MCFG3				0x000c
+#define HMATRIX_MCFG4				0x0010
+#define HMATRIX_MCFG5				0x0014
+#define HMATRIX_MCFG6				0x0018
+#define HMATRIX_MCFG7				0x001c
+#define HMATRIX_MCFG8				0x0020
+#define HMATRIX_MCFG9				0x0024
+#define HMATRIX_MCFG10				0x0028
+#define HMATRIX_MCFG11				0x002c
+#define HMATRIX_MCFG12				0x0030
+#define HMATRIX_MCFG13				0x0034
+#define HMATRIX_MCFG14				0x0038
+#define HMATRIX_MCFG15				0x003c
+#define HMATRIX_SCFG0				0x0040
+#define HMATRIX_SCFG1				0x0044
+#define HMATRIX_SCFG2				0x0048
+#define HMATRIX_SCFG3				0x004c
+#define HMATRIX_SCFG4				0x0050
+#define HMATRIX_SCFG5				0x0054
+#define HMATRIX_SCFG6				0x0058
+#define HMATRIX_SCFG7				0x005c
+#define HMATRIX_SCFG8				0x0060
+#define HMATRIX_SCFG9				0x0064
+#define HMATRIX_SCFG10				0x0068
+#define HMATRIX_SCFG11				0x006c
+#define HMATRIX_SCFG12				0x0070
+#define HMATRIX_SCFG13				0x0074
+#define HMATRIX_SCFG14				0x0078
+#define HMATRIX_SCFG15				0x007c
+#define HMATRIX_PRAS0				0x0080
+#define HMATRIX_PRBS0				0x0084
+#define HMATRIX_PRAS1				0x0088
+#define HMATRIX_PRBS1				0x008c
+#define HMATRIX_PRAS2				0x0090
+#define HMATRIX_PRBS2				0x0094
+#define HMATRIX_PRAS3				0x0098
+#define HMATRIX_PRBS3				0x009c
+#define HMATRIX_PRAS4				0x00a0
+#define HMATRIX_PRBS4				0x00a4
+#define HMATRIX_PRAS5				0x00a8
+#define HMATRIX_PRBS5				0x00ac
+#define HMATRIX_PRAS6				0x00b0
+#define HMATRIX_PRBS6				0x00b4
+#define HMATRIX_PRAS7				0x00b8
+#define HMATRIX_PRBS7				0x00bc
+#define HMATRIX_PRAS8				0x00c0
+#define HMATRIX_PRBS8				0x00c4
+#define HMATRIX_PRAS9				0x00c8
+#define HMATRIX_PRBS9				0x00cc
+#define HMATRIX_PRAS10				0x00d0
+#define HMATRIX_PRBS10				0x00d4
+#define HMATRIX_PRAS11				0x00d8
+#define HMATRIX_PRBS11				0x00dc
+#define HMATRIX_PRAS12				0x00e0
+#define HMATRIX_PRBS12				0x00e4
+#define HMATRIX_PRAS13				0x00e8
+#define HMATRIX_PRBS13				0x00ec
+#define HMATRIX_PRAS14				0x00f0
+#define HMATRIX_PRBS14				0x00f4
+#define HMATRIX_PRAS15				0x00f8
+#define HMATRIX_PRBS15				0x00fc
+#define HMATRIX_MRCR				0x0100
+#define HMATRIX_SFR0				0x0110
+#define HMATRIX_SFR1				0x0114
+#define HMATRIX_SFR2				0x0118
+#define HMATRIX_SFR3				0x011c
+#define HMATRIX_SFR4				0x0120
+#define HMATRIX_SFR5				0x0124
+#define HMATRIX_SFR6				0x0128
+#define HMATRIX_SFR7				0x012c
+#define HMATRIX_SFR8				0x0130
+#define HMATRIX_SFR9				0x0134
+#define HMATRIX_SFR10				0x0138
+#define HMATRIX_SFR11				0x013c
+#define HMATRIX_SFR12				0x0140
+#define HMATRIX_SFR13				0x0144
+#define HMATRIX_SFR14				0x0148
+#define HMATRIX_SFR15				0x014c
+
+/* Bitfields in MCFGx */
+#define HMATRIX_ULBT_OFFSET			0
+#define HMATRIX_ULBT_SIZE			3
+
+/* Bitfields in SCFGx */
+#define HMATRIX_SLOT_CYCLE_OFFSET		0
+#define HMATRIX_SLOT_CYCLE_SIZE			8
+#define HMATRIX_DEFMSTR_TYPE_OFFSET		16
+#define HMATRIX_DEFMSTR_TYPE_SIZE		2
+#define HMATRIX_FIXED_DEFMSTR_OFFSET		18
+#define HMATRIX_FIXED_DEFMSTR_SIZE		4
+#define HMATRIX_ARBT_OFFSET			24
+#define HMATRIX_ARBT_SIZE			2
+
+/* Bitfields in PRASx */
+#define HMATRIX_M0PR_OFFSET			0
+#define HMATRIX_M0PR_SIZE			4
+#define HMATRIX_M1PR_OFFSET			4
+#define HMATRIX_M1PR_SIZE			4
+#define HMATRIX_M2PR_OFFSET			8
+#define HMATRIX_M2PR_SIZE			4
+#define HMATRIX_M3PR_OFFSET			12
+#define HMATRIX_M3PR_SIZE			4
+#define HMATRIX_M4PR_OFFSET			16
+#define HMATRIX_M4PR_SIZE			4
+#define HMATRIX_M5PR_OFFSET			20
+#define HMATRIX_M5PR_SIZE			4
+#define HMATRIX_M6PR_OFFSET			24
+#define HMATRIX_M6PR_SIZE			4
+#define HMATRIX_M7PR_OFFSET			28
+#define HMATRIX_M7PR_SIZE			4
+
+/* Bitfields in PRBSx */
+#define HMATRIX_M8PR_OFFSET			0
+#define HMATRIX_M8PR_SIZE			4
+#define HMATRIX_M9PR_OFFSET			4
+#define HMATRIX_M9PR_SIZE			4
+#define HMATRIX_M10PR_OFFSET			8
+#define HMATRIX_M10PR_SIZE			4
+#define HMATRIX_M11PR_OFFSET			12
+#define HMATRIX_M11PR_SIZE			4
+#define HMATRIX_M12PR_OFFSET			16
+#define HMATRIX_M12PR_SIZE			4
+#define HMATRIX_M13PR_OFFSET			20
+#define HMATRIX_M13PR_SIZE			4
+#define HMATRIX_M14PR_OFFSET			24
+#define HMATRIX_M14PR_SIZE			4
+#define HMATRIX_M15PR_OFFSET			28
+#define HMATRIX_M15PR_SIZE			4
+
+/* Bitfields in SFR4 */
+#define HMATRIX_CS1A_OFFSET			1
+#define HMATRIX_CS1A_SIZE			1
+#define HMATRIX_CS3A_OFFSET			3
+#define HMATRIX_CS3A_SIZE			1
+#define HMATRIX_CS4A_OFFSET			4
+#define HMATRIX_CS4A_SIZE			1
+#define HMATRIX_CS5A_OFFSET			5
+#define HMATRIX_CS5A_SIZE			1
+#define HMATRIX_DBPUC_OFFSET			8
+#define HMATRIX_DBPUC_SIZE			1
+
+/* Constants for ULBT */
+#define HMATRIX_ULBT_INFINITE			0
+#define HMATRIX_ULBT_SINGLE			1
+#define HMATRIX_ULBT_FOUR_BEAT			2
+#define HMATRIX_ULBT_EIGHT_BEAT			3
+#define HMATRIX_ULBT_SIXTEEN_BEAT		4
+
+/* Constants for DEFMSTR_TYPE */
+#define HMATRIX_DEFMSTR_TYPE_NO_DEFAULT		0
+#define HMATRIX_DEFMSTR_TYPE_LAST_DEFAULT	1
+#define HMATRIX_DEFMSTR_TYPE_FIXED_DEFAULT	2
+
+/* Constants for ARBT */
+#define HMATRIX_ARBT_ROUND_ROBIN		0
+#define HMATRIX_ARBT_FIXED_PRIORITY		1
+
+/* Bit manipulation macros */
+#define HMATRIX_BIT(name)					\
+	(1 << HMATRIX_##name##_OFFSET)
+#define HMATRIX_BF(name,value)					\
+	(((value) & ((1 << HMATRIX_##name##_SIZE) - 1))		\
+	 << HMATRIX_##name##_OFFSET)
+#define HMATRIX_BFEXT(name,value)				\
+	(((value) >> HMATRIX_##name##_OFFSET)			\
+	 & ((1 << HMATRIX_##name##_SIZE) - 1))
+#define HMATRIX_BFINS(name,value,old)				\
+	(((old) & ~(((1 << HMATRIX_##name##_SIZE) - 1)		\
+		    << HMATRIX_##name##_OFFSET))		\
+	 | HMATRIX_BF(name,value))
+
+#endif /* __HMATRIX_H */
diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c
index 7691721..5e22a75 100644
--- a/arch/avr32/mach-at32ap/hsmc.c
+++ b/arch/avr32/mach-at32ap/hsmc.c
@@ -75,12 +75,35 @@ #define ns2cyc(x) ((((x) * mul) + 65535)
 		return -EINVAL;
 	}
 
+	switch (config->nwait_mode) {
+	case 0:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED);
+		break;
+	case 1:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED);
+		break;
+	case 2:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN);
+		break;
+	case 3:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (config->tdf_cycles) {
+		mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles);
+	}
+
 	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);
+	if (config->tdf_mode)
+		mode |= HSMC_BIT(TDF_MODE);
 
 	pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
 		 cs, setup, pulse, cycle, mode);
diff --git a/arch/avr32/mach-at32ap/time-tc.c b/arch/avr32/mach-at32ap/time-tc.c
new file mode 100644
index 0000000..e3070bd
--- /dev/null
+++ b/arch/avr32/mach-at32ap/time-tc.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2004-2007 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 <linux/err.h>
+
+#include <asm/div64.h>
+#include <asm/sysreg.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include <asm/arch/time.h>
+
+/* how many counter cycles in a jiffy? */
+static u32 cycles_per_jiffy;
+
+/* the count value for the next timer interrupt */
+static u32 expirelo;
+
+/* the I/O registers of the TC module */
+static void __iomem *ioregs;
+
+cycle_t read_cycle_count(void)
+{
+	return (cycle_t)timer_read(ioregs, 0, CV);
+}
+
+struct clocksource clocksource_avr32 = {
+	.name		= "avr32",
+	.rating		= 342,
+	.read		= read_cycle_count,
+	.mask		= CLOCKSOURCE_MASK(16),
+	.shift		= 16,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void avr32_timer_ack(void)
+{
+	u16 count = expirelo;
+
+	/* Ack this timer interrupt and set the next one, use a u16
+	 * variable so it will wrap around correctly */
+	count += cycles_per_jiffy;
+	expirelo = count;
+	timer_write(ioregs, 0, RC, expirelo);
+
+	/* Check to see if we have missed any timer interrupts */
+	count = timer_read(ioregs, 0, CV);
+	if ((count - expirelo) < 0x7fff) {
+		expirelo = count + cycles_per_jiffy;
+		timer_write(ioregs, 0, RC, expirelo);
+	}
+}
+
+u32 avr32_hpt_read(void)
+{
+	return timer_read(ioregs, 0, CV);
+}
+
+static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
+{
+	unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
+	unsigned int divs[] = { 4, 8, 16, 32 };
+	int divs_size = sizeof(divs) / sizeof(*divs);
+	int i = 0;
+	unsigned long count_hz;
+	unsigned long shift;
+	unsigned long mult;
+	int clock_div = -1;
+	u64 tmp;
+
+	shift = clocksource_avr32.shift;
+
+	do {
+		count_hz = clk_get_rate(pclk) / divs[i];
+		mult = clocksource_hz2mult(count_hz, shift);
+		clocksource_avr32.mult = mult;
+
+		tmp = TICK_NSEC;
+		tmp <<= shift;
+		tmp += mult / 2;
+		do_div(tmp, mult);
+
+		cycles_per_jiffy = tmp;
+	} while (cycles_per_jiffy > cycles_max && ++i < divs_size);
+
+	clock_div = i + 1;
+
+	if (clock_div > divs_size) {
+		pr_debug("timer: could not calculate clock divider\n");
+		return -EFAULT;
+	}
+
+	/* Set the clock divider */
+	timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
+
+	return 0;
+}
+
+int avr32_hpt_init(unsigned int count)
+{
+	struct resource *regs;
+	struct clk *pclk;
+	int irq = -1;
+	int ret = 0;
+
+	ret = -ENXIO;
+
+	irq = platform_get_irq(&at32_systc0_device, 0);
+	if (irq < 0) {
+		pr_debug("timer: could not get irq\n");
+		goto out_error;
+	}
+
+	pclk = clk_get(&at32_systc0_device.dev, "pclk");
+	if (IS_ERR(pclk)) {
+		pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
+		goto out_error;
+	}
+	clk_enable(pclk);
+
+	regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
+	if (!regs) {
+		pr_debug("timer: could not get resource\n");
+		goto out_error_clk;
+	}
+
+	ioregs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!ioregs) {
+		pr_debug("timer: could not get ioregs\n");
+		goto out_error_clk;
+	}
+
+	ret = avr32_timer_calc_div_and_set_jiffies(pclk);
+	if (ret)
+		goto out_error_io;
+
+	ret = setup_irq(irq, &timer_irqaction);
+	if (ret) {
+		pr_debug("timer: could not request irq %d: %d\n",
+				irq, ret);
+		goto out_error_io;
+	}
+
+	expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
+		* cycles_per_jiffy;
+
+	/* Enable clock and interrupts on RC compare */
+	timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
+	timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
+	/* Set cycles to first interrupt */
+	timer_write(ioregs, 0,  RC, expirelo);
+
+	printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
+			ioregs, irq);
+
+	return 0;
+
+out_error_io:
+	iounmap(ioregs);
+out_error_clk:
+	clk_put(pclk);
+out_error:
+	return ret;
+}
+
+int avr32_hpt_start(void)
+{
+	timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
+	return 0;
+}
+
+irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	unsigned int sr = timer_read(ioregs, 0, SR);
+
+	if (sr & TIMER_BIT(SR_CPCS)) {
+		/* ack timer interrupt and try to set next interrupt */
+		avr32_timer_ack();
+
+		/*
+		 * 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;
+	}
+
+	return IRQ_NONE;
+}
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index 6785572..88b00b1 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -13,29 +13,11 @@ #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
 
-#include <asm/kdebug.h>
+#include <linux/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
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_KPROBES
 ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
@@ -68,17 +50,19 @@ static inline int notify_page_fault(enum
 }
 #endif
 
+int exception_trace = 1;
+
 /*
  * 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)
+ *   15: Protection fault (read access)
+ *   16: Protection fault (write access)
+ *   20: Page not found (instruction access)
+ *   24: Page not found (read access)
+ *   28: Page not found (write access)
  */
 asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 {
@@ -88,7 +72,9 @@ asmlinkage void do_page_fault(unsigned l
 	const struct exception_table_entry *fixup;
 	unsigned long address;
 	unsigned long page;
-	int writeaccess = 0;
+	int writeaccess;
+	long signr;
+	int code;
 
 	if (notify_page_fault(DIE_PAGE_FAULT, regs,
 			      ecr, SIGSEGV) == NOTIFY_STOP)
@@ -99,6 +85,9 @@ asmlinkage void do_page_fault(unsigned l
 	tsk = current;
 	mm = tsk->mm;
 
+	signr = SIGSEGV;
+	code = SEGV_MAPERR;
+
 	/*
 	 * If we're in an interrupt or have no user context, we must
 	 * not take the fault...
@@ -125,7 +114,9 @@ asmlinkage void do_page_fault(unsigned l
 	 * can handle it...
 	 */
 good_area:
-	//pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags);
+	code = SEGV_ACCERR;
+	writeaccess = 0;
+
 	switch (ecr) {
 	case ECR_PROTECTION_X:
 	case ECR_TLB_MISS_X:
@@ -176,46 +167,24 @@ survive:
 	 * 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);
+		if (exception_trace)
+			printk("%s%s[%d]: segfault at %08lx pc %08lx "
+			       "sp %08lx ecr %lu\n",
+			       is_init(tsk) ? KERN_EMERG : KERN_INFO,
+			       tsk->comm, tsk->pid, address, regs->pc,
+			       regs->sp, ecr);
+		_exception(SIGSEGV, regs, code, address);
 		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;
 	}
 
@@ -230,7 +199,6 @@ no_context:
 		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);
@@ -241,20 +209,20 @@ no_context:
 			page &= PAGE_MASK;
 			address &= 0x003ff000;
 			page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
-			printk(" pte = %08lx\n", page);
+			printk(" pte = %08lx", page);
 		}
 	}
-	die("\nOops", regs, ecr);
-	do_exit(SIGKILL);
+	printk("\n");
+	die("Kernel access of bad area", regs, signr);
+	return;
 
 	/*
 	 * We ran out of memory, or some other thing happened to us
 	 * that made us unable to handle the page fault gracefully.
 	 */
 out_of_memory:
-	printk("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;
@@ -267,21 +235,20 @@ out_of_memory:
 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 */
+	signr = SIGBUS;
+	code = BUS_ADRERR;
 	if (!user_mode(regs))
 		goto no_context;
+
+	if (exception_trace)
+		printk("%s%s[%d]: bus error at %08lx pc %08lx "
+		       "sp %08lx ecr %lu\n",
+		       is_init(tsk) ? KERN_EMERG : KERN_INFO,
+		       tsk->comm, tsk->pid, address, regs->pc,
+		       regs->sp, ecr);
+
+	_exception(SIGBUS, regs, BUS_ADRERR, address);
 }
 
 asmlinkage void do_bus_error(unsigned long addr, int write_access,
@@ -292,8 +259,7 @@ asmlinkage void do_bus_error(unsigned lo
 	       addr, write_access ? "write" : "read");
 	printk(KERN_INFO "DTLB dump:\n");
 	dump_dtlb();
-	die("Bus Error", regs, write_access);
-	do_exit(SIGKILL);
+	die("Bus Error", regs, SIGKILL);
 }
 
 /*
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 70da689..82cf708 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -10,11 +10,9 @@ #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>
@@ -78,242 +76,6 @@ void show_mem(void)
 	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
  *
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
new file mode 100644
index 0000000..1a49305
--- /dev/null
+++ b/arch/blackfin/Kconfig
@@ -0,0 +1,989 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "uClinux/Blackfin (w/o MMU) Kernel Configuration"
+
+config MMU
+	bool
+	default n
+
+config FPU
+	bool
+	default n
+
+config RWSEM_GENERIC_SPINLOCK
+	bool
+	default y
+
+config RWSEM_XCHGADD_ALGORITHM
+	bool
+	default n
+
+config BLACKFIN
+	bool
+	default y
+
+config BFIN
+	bool
+	default y
+
+config SEMAPHORE_SLEEPERS
+	bool
+	default y
+
+config GENERIC_FIND_NEXT_BIT
+	bool
+	default y
+
+config GENERIC_HWEIGHT
+	bool
+	default y
+
+config GENERIC_HARDIRQS
+	bool
+	default y
+
+config GENERIC_IRQ_PROBE
+        bool
+	default y
+
+config GENERIC_TIME
+	bool
+	default n
+
+config GENERIC_CALIBRATE_DELAY
+	bool
+	default y
+
+config FORCE_MAX_ZONEORDER
+	int
+	default "14"
+
+config GENERIC_CALIBRATE_DELAY
+	bool
+	default y
+
+config IRQCHIP_DEMUX_GPIO
+	bool
+	default y
+
+source "init/Kconfig"
+source "kernel/Kconfig.preempt"
+
+menu "Blackfin Processor Options"
+
+comment "Processor and Board Settings"
+
+choice
+	prompt "CPU"
+	default BF533
+
+config BF531
+	bool "BF531"
+	help
+	  BF531 Processor Support.
+
+config BF532
+	bool "BF532"
+	help
+	  BF532 Processor Support.
+
+config BF533
+	bool "BF533"
+	help
+	  BF533 Processor Support.
+
+config BF534
+	bool "BF534"
+	help
+	  BF534 Processor Support.
+
+config BF536
+	bool "BF536"
+	help
+	  BF536 Processor Support.
+
+config BF537
+	bool "BF537"
+	help
+	  BF537 Processor Support.
+
+config BF561
+	bool "BF561"
+	help
+	  Not Supported Yet - Work in progress - BF561 Processor Support.
+
+endchoice
+
+choice
+	prompt "Silicon Rev"
+	default BF_REV_0_2 if BF537
+	default BF_REV_0_3 if BF533
+
+config BF_REV_0_2
+	bool "0.2"
+	depends on (BF537 || BF536 || BF534)
+
+config BF_REV_0_3
+	bool "0.3"
+	depends on (BF561 || BF537 || BF536 || BF534 || BF533 || BF532 || BF531)
+
+config BF_REV_0_4
+	bool "0.4"
+	depends on (BF561 || BF533 || BF532 || BF531)
+
+config BF_REV_0_5
+	bool "0.5"
+	depends on (BF561 || BF533 || BF532 || BF531)
+
+endchoice
+
+config BFIN_DUAL_CORE
+	bool
+	depends on (BF561)
+	default y
+
+config BFIN_SINGLE_CORE
+	bool
+	depends on !BFIN_DUAL_CORE
+	default y
+
+choice
+	prompt "System type"
+	default BFIN533_STAMP
+	help
+	  Do NOT change the board here.  Please use the top level
+	  configuration to ensure that all the other settings are
+	  correct.
+
+config BFIN533_EZKIT
+	bool "BF533-EZKIT"
+	depends on (BF533 || BF532 || BF531)
+	help
+	  BF533-EZKIT-LITE board Support.
+
+config  BFIN533_STAMP
+	bool "BF533-STAMP"
+	depends on (BF533 || BF532 || BF531)
+	help
+	  BF533-STAMP board Support.
+
+config BFIN537_STAMP
+	bool "BF537-STAMP"
+	depends on (BF537 || BF536 || BF534)
+	help
+	  BF537-STAMP board Support.
+
+config BFIN533_BLUETECHNIX_CM
+	bool "Bluetechnix CM-BF533"
+	depends on (BF533)
+	help
+	  CM-BF533 support for EVAL- and DEV-Board.
+
+config BFIN537_BLUETECHNIX_CM
+	bool "Bluetechnix CM-BF537"
+	depends on (BF537)
+	help
+	  CM-BF537 support for EVAL- and DEV-Board.
+
+config BFIN561_BLUETECHNIX_CM
+	bool "BF561-CM"
+	depends on (BF561)
+	help
+	  CM-BF561 support for EVAL- and DEV-Board.
+
+config BFIN561_EZKIT
+	bool "BF561-EZKIT"
+	depends on (BF561)
+	help
+	  BF561-EZKIT-LITE board Support.
+
+config PNAV10
+	bool "PNAV 1.0 board"
+	depends on (BF537)
+	help
+	  PNAV 1.0 board Support.
+
+config GENERIC_BOARD
+	bool "Custom"
+	depends on (BF537 || BF536 \
+		|| BF534 || BF561 || BF535 || BF533 || BF532 || BF531)
+	help
+	  GENERIC or Custom board Support.
+
+endchoice
+
+config MEM_GENERIC_BOARD
+	bool
+	depends on GENERIC_BOARD
+	default y
+
+config MEM_MT48LC64M4A2FB_7E
+	bool
+	depends on (BFIN533_STAMP)
+	default y
+
+config MEM_MT48LC16M16A2TG_75
+	bool
+	depends on (BFIN533_EZKIT || BFIN561_EZKIT \
+		|| BFIN533_BLUETECHNIX_CM || BFIN537_BLUETECHNIX_CM)
+	default y
+
+config MEM_MT48LC32M8A2_75
+	bool
+	depends on (BFIN537_STAMP || PNAV10)
+	default y
+
+config MEM_MT48LC8M32B2B5_7
+	bool
+	depends on (BFIN561_BLUETECHNIX_CM)
+	default y
+
+config BFIN_SHARED_FLASH_ENET
+	bool
+	depends on (BFIN533_STAMP)
+	default y
+
+source "arch/blackfin/mach-bf533/Kconfig"
+source "arch/blackfin/mach-bf561/Kconfig"
+source "arch/blackfin/mach-bf537/Kconfig"
+
+menu "Board customizations"
+
+config CMDLINE_BOOL
+	bool "Default bootloader kernel arguments"
+
+config CMDLINE
+	string "Initial kernel command string"
+	depends on CMDLINE_BOOL
+	default "console=ttyBF0,57600"
+	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).
+
+comment "Board Setup"
+
+config CLKIN_HZ
+	int "Crystal Frequency in Hz"
+	default "11059200" if BFIN533_STAMP
+	default "27000000" if BFIN533_EZKIT
+	default "25000000" if BFIN537_STAMP
+	default "30000000" if BFIN561_EZKIT
+	default "24576000" if PNAV10
+	help
+	  The frequency of CLKIN crystal oscillator on the board in Hz.
+
+config MEM_SIZE
+	int "SDRAM Memory Size in MBytes"
+	default  32 if BFIN533_EZKIT
+	default  64 if BFIN537_STAMP
+	default  64 if BFIN561_EZKIT
+	default 128 if BFIN533_STAMP
+	default  64 if PNAV10
+
+config MEM_ADD_WIDTH
+	int "SDRAM Memory Address Width"
+	default  9 if BFIN533_EZKIT
+	default  9 if BFIN561_EZKIT
+	default 10 if BFIN537_STAMP
+	default 11 if BFIN533_STAMP
+	default 10 if PNAV10
+
+config ENET_FLASH_PIN
+	int "PF port/pin used for flash and ethernet sharing"
+	depends on (BFIN533_STAMP)
+	default  0
+	help
+	  PF port/pin used for flash and ethernet sharing to allow other PF
+	  pins to be used on other platforms without having to touch common
+	  code.
+	  For example: PF0 --> 0,PF1 --> 1,PF2 --> 2, etc.
+
+config BOOT_LOAD
+	hex "Kernel load address for booting"
+	default "0x1000"
+	help
+	  This option allows you to set the load address of the kernel.
+	  This can be useful if you are on a board which has a small amount
+	  of memory or you wish to reserve some memory at the beginning of
+	  the address space.
+
+	  Note that you generally want to keep this value at or above 4k
+	  (0x1000) as this will allow the kernel to capture NULL pointer
+	  references.
+
+comment "LED Status Indicators"
+	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+
+config BFIN_ALIVE_LED
+	bool "Enable Board Alive"
+	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+	default n
+	help
+	  Blink the LEDs you select when the kernel is running.  Helps detect
+	  a hung kernel.
+
+config BFIN_ALIVE_LED_NUM
+	int "LED"
+	depends on BFIN_ALIVE_LED
+	range 1 3 if BFIN533_STAMP
+	default "3" if BFIN533_STAMP
+	help
+	  Select the LED (marked on the board) for you to blink.
+
+config BFIN_IDLE_LED
+	bool "Enable System Load/Idle LED"
+	depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+	default n
+	help
+	  Blinks the LED you select when to determine kernel load.
+
+config BFIN_IDLE_LED_NUM
+	int "LED"
+	depends on BFIN_IDLE_LED
+	range 1 3 if BFIN533_STAMP
+	default "2" if BFIN533_STAMP
+	help
+	  Select the LED (marked on the board) for you to blink.
+
+#
+# Sorry - but you need to put the hex address here -
+#
+
+# Flag Data register
+config BFIN_ALIVE_LED_PORT
+	hex
+	default 0xFFC00700 if (BFIN533_STAMP)
+
+# Peripheral Flag Direction Register
+config BFIN_ALIVE_LED_DPORT
+	hex
+	default 0xFFC00730 if (BFIN533_STAMP)
+
+config BFIN_ALIVE_LED_PIN
+	hex
+	default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
+	default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
+	default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
+
+config BFIN_IDLE_LED_PORT
+	hex
+	default 0xFFC00700 if (BFIN533_STAMP)
+
+# Peripheral Flag Direction Register
+config BFIN_IDLE_LED_DPORT
+	hex
+	default 0xFFC00730 if (BFIN533_STAMP)
+
+config BFIN_IDLE_LED_PIN
+	hex
+	default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
+	default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
+	default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
+
+comment "Console UART Setup"
+
+choice
+	prompt "Baud Rate"
+	default BAUD_57600
+config BAUD_9600
+	bool "9600"
+config BAUD_19200
+	bool "19200"
+config BAUD_38400
+	bool "38400"
+config BAUD_57600
+	bool "57600"
+config BAUD_115200
+	bool "115200"
+endchoice
+
+choice
+	prompt "Parity"
+	default BAUD_NO_PARITY
+config  BAUD_NO_PARITY
+	bool "No Parity"
+config  BAUD_PARITY
+	bool "Parity"
+endchoice
+
+choice
+	prompt "Stop Bits"
+	default BAUD_1_STOPBIT
+config  BAUD_1_STOPBIT
+	bool "1"
+config  BAUD_2_STOPBIT
+	bool "2"
+endchoice
+
+endmenu
+
+
+menu "Blackfin Kernel Optimizations"
+
+comment "Timer Tick"
+
+source kernel/Kconfig.hz
+
+comment "Memory Optimizations"
+
+config I_ENTRY_L1
+	bool "Locate interrupt entry code in L1 Memory"
+	default y
+	help
+	  If enabled interrupt entry code (STORE/RESTORE CONTEXT) is linked
+	  into L1 instruction memory.(less latency)
+
+config EXCPT_IRQ_SYSC_L1
+	bool "Locate entire ASM lowlevel excepetion / interrupt - Syscall and CPLB handler code in L1 Memory"
+	default y
+	help
+	  If enabled entire ASM lowlevel exception and interrupt entry code (STORE/RESTORE CONTEXT) is linked
+	  into L1 instruction memory.(less latency)
+
+config DO_IRQ_L1
+	bool "Locate frequently called do_irq dispatcher function in L1 Memory"
+	default y
+	help
+	  If enabled frequently called do_irq dispatcher function is linked
+	  into L1 instruction memory.(less latency)
+
+config CORE_TIMER_IRQ_L1
+	bool "Locate frequently called timer_interrupt() function in L1 Memory"
+	default y
+	help
+	  If enabled frequently called timer_interrupt() function is linked
+	  into L1 instruction memory.(less latency)
+
+config IDLE_L1
+	bool "Locate frequently idle function in L1 Memory"
+	default y
+	help
+	  If enabled frequently called idle function is linked
+	  into L1 instruction memory.(less latency)
+
+config SCHEDULE_L1
+	bool "Locate kernel schedule function in L1 Memory"
+	default y
+	help
+	  If enabled frequently called kernel schedule is linked
+	  into L1 instruction memory.(less latency)
+
+config ARITHMETIC_OPS_L1
+	bool "Locate kernel owned arithmetic functions in L1 Memory"
+	default y
+	help
+	  If enabled arithmetic functions are linked
+	  into L1 instruction memory.(less latency)
+
+config ACCESS_OK_L1
+	bool "Locate access_ok function in L1 Memory"
+	default y
+	help
+	  If enabled access_ok function is linked
+	  into L1 instruction memory.(less latency)
+
+config MEMSET_L1
+	bool "Locate memset function in L1 Memory"
+	default y
+	help
+	  If enabled memset function is linked
+	  into L1 instruction memory.(less latency)
+
+config MEMCPY_L1
+	bool "Locate memcpy function in L1 Memory"
+	default y
+	help
+	  If enabled memcpy function is linked
+	  into L1 instruction memory.(less latency)
+
+config SYS_BFIN_SPINLOCK_L1
+	bool "Locate sys_bfin_spinlock function in L1 Memory"
+	default y
+	help
+	  If enabled sys_bfin_spinlock function is linked
+	  into L1 instruction memory.(less latency)
+
+config IP_CHECKSUM_L1
+	bool "Locate IP Checksum function in L1 Memory"
+	default n
+	help
+	  If enabled IP Checksum function is linked
+	  into L1 instruction memory.(less latency)
+
+config CACHELINE_ALIGNED_L1
+	bool "Locate cacheline_aligned data to L1 Data Memory"
+	default y
+	depends on !BF531
+	help
+	  If enabled cacheline_anligned data is linked
+	  into L1 data memory.(less latency)
+
+config SYSCALL_TAB_L1
+	bool "Locate Syscall Table L1 Data Memory"
+	default n
+	depends on !BF531
+	help
+	  If enabled the Syscall LUT is linked
+	  into L1 data memory.(less latency)
+
+config CPLB_SWITCH_TAB_L1
+	bool "Locate CPLB Switch Tables L1 Data Memory"
+	default n
+	depends on !BF531
+	help
+	  If enabled the CPLB Switch Tables are linked
+	  into L1 data memory.(less latency)
+
+endmenu
+
+
+choice
+	prompt "Kernel executes from"
+	help
+	  Choose the memory type that the kernel will be running in.
+
+config RAMKERNEL
+	bool "RAM"
+	help
+	  The kernel will be resident in RAM when running.
+
+config ROMKERNEL
+	bool "ROM"
+	help
+	  The kernel will be resident in FLASH/ROM when running.
+
+endchoice
+
+source "mm/Kconfig"
+
+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 - upto 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.
+
+config BFIN_DMA_5XX
+	bool "Enable DMA Support"
+	depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561)
+	default y
+	help
+	  DMA driver for BF5xx.
+
+choice
+	prompt "Uncached SDRAM region"
+	default DMA_UNCACHED_1M
+	depends BFIN_DMA_5XX
+config DMA_UNCACHED_2M
+	bool "Enable 2M DMA region"
+config DMA_UNCACHED_1M
+	bool "Enable 1M DMA region"
+config DMA_UNCACHED_NONE
+	bool "Disable DMA region"
+endchoice
+
+
+comment "Cache Support"
+config BLKFIN_CACHE
+	bool "Enable ICACHE"
+config BLKFIN_DCACHE
+	bool "Enable DCACHE"
+config BLKFIN_DCACHE_BANKA
+	bool "Enable only 16k BankA DCACHE - BankB is SRAM"
+	depends on BLKFIN_DCACHE && !BF531
+	default n
+config BLKFIN_CACHE_LOCK
+	bool "Enable Cache Locking"
+
+choice
+	prompt "Policy"
+	depends on BLKFIN_DCACHE
+	default BLKFIN_WB
+config BLKFIN_WB
+	bool "Write back"
+	help
+	  Write Back Policy:
+	    Cached data will be written back to SDRAM only when needed.
+	    This can give a nice increase in performance, but beware of
+	    broken drivers that do not properly invalidate/flush their
+	    cache.
+
+	  Write Through Policy:
+	    Cached data will always be written back to SDRAM when the
+	    cache is updated.  This is a completely safe setting, but
+	    performance is worse than Write Back.
+
+	  If you are unsure of the options and you want to be safe,
+	  then go with Write Through.
+
+config BLKFIN_WT
+	bool "Write through"
+	help
+	  Write Back Policy:
+	    Cached data will be written back to SDRAM only when needed.
+	    This can give a nice increase in performance, but beware of
+	    broken drivers that do not properly invalidate/flush their
+	    cache.
+
+	  Write Through Policy:
+	    Cached data will always be written back to SDRAM when the
+	    cache is updated.  This is a completely safe setting, but
+	    performance is worse than Write Back.
+
+	  If you are unsure of the options and you want to be safe,
+	  then go with Write Through.
+
+endchoice
+
+config L1_MAX_PIECE
+	int "Set the max L1 SRAM pieces"
+	default 16
+	help
+	  Set the max memory pieces for the L1 SRAM allocation algorithm.
+	  Min value is 16. Max value is 1024.
+
+menu "Clock Settings"
+
+
+config BFIN_KERNEL_CLOCK
+	bool "Re-program Clocks while Kernel boots?"
+	default n
+	help
+	  This option decides if kernel clocks are re-programed from the
+	  bootloader settings. If the clocks are not set, the SDRAM settings
+	  are also not changed, and the Bootloader does 100% of the hardware
+	  configuration.
+
+config VCO_MULT
+	int "VCO Multiplier"
+	depends on BFIN_KERNEL_CLOCK
+	default "22" if BFIN533_EZKIT
+	default "45" if BFIN533_STAMP
+	default "20" if BFIN537_STAMP
+	default "22" if BFIN533_BLUETECHNIX_CM
+	default "20" if BFIN537_BLUETECHNIX_CM
+	default "20" if BFIN561_BLUETECHNIX_CM
+	default "20" if BFIN561_EZKIT
+
+config CCLK_DIV
+	int "Core Clock Divider"
+	depends on BFIN_KERNEL_CLOCK
+	default 1 if BFIN533_EZKIT
+	default 1 if BFIN533_STAMP
+	default 1 if BFIN537_STAMP
+	default 1 if BFIN533_BLUETECHNIX_CM
+	default 1 if BFIN537_BLUETECHNIX_CM
+	default 1 if BFIN561_BLUETECHNIX_CM
+	default 1 if BFIN561_EZKIT
+
+config SCLK_DIV
+	int "System Clock Divider"
+	depends on BFIN_KERNEL_CLOCK
+	default 5 if BFIN533_EZKIT
+	default 5 if BFIN533_STAMP
+	default 4 if BFIN537_STAMP
+	default 5 if BFIN533_BLUETECHNIX_CM
+	default 4 if BFIN537_BLUETECHNIX_CM
+	default 4 if BFIN561_BLUETECHNIX_CM
+	default 5 if BFIN561_EZKIT
+
+config CLKIN_HALF
+	bool "Half ClockIn"
+	depends on BFIN_KERNEL_CLOCK
+	default n
+
+config PLL_BYPASS
+	bool "Bypass PLL"
+	depends on BFIN_KERNEL_CLOCK
+	default n
+
+endmenu
+
+comment "Asynchonous Memory Configuration"
+
+menu "EBIU_AMBCTL Global Control"
+config C_AMCKEN
+	bool "Enable CLKOUT"
+	default y
+
+config C_CDPRIO
+	bool "DMA has priority over core for ext. accesses"
+	default n
+
+config C_B0PEN
+	depends on BF561
+	bool "Bank 0 16 bit packing enable"
+	default y
+
+config C_B1PEN
+	depends on BF561
+	bool "Bank 1 16 bit packing enable"
+	default y
+
+config C_B2PEN
+	depends on BF561
+	bool "Bank 2 16 bit packing enable"
+	default y
+
+config C_B3PEN
+	depends on BF561
+	bool "Bank 3 16 bit packing enable"
+	default n
+
+choice
+	prompt"Enable Asynchonous Memory Banks"
+	default C_AMBEN_ALL
+
+config C_AMBEN
+	bool "Disable All Banks"
+
+config C_AMBEN_B0
+	bool "Enable Bank 0"
+
+config C_AMBEN_B0_B1
+	bool "Enable Bank 0 & 1"
+
+config C_AMBEN_B0_B1_B2
+	bool "Enable Bank 0 & 1 & 2"
+
+config C_AMBEN_ALL
+	bool "Enable All Banks"
+endchoice
+endmenu
+
+menu "EBIU_AMBCTL Control"
+config BANK_0
+	hex "Bank 0"
+	default 0x7BB0
+
+config BANK_1
+	hex "Bank 1"
+	default 0x7BB0
+
+config BANK_2
+	hex "Bank 2"
+	default 0x7BB0
+
+config BANK_3
+	hex "Bank 3"
+	default 0x99B3
+endmenu
+
+endmenu
+
+#############################################################################
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+
+config PCI
+	bool "PCI support"
+	help
+	  Support for PCI bus.
+
+source "drivers/pci/Kconfig"
+
+config HOTPLUG
+	bool "Support for hot-pluggable device"
+	  help
+	  Say Y here if you want to plug devices into your computer while
+	  the system is running, and be able to use them quickly.  In many
+	  cases, the devices can likewise be unplugged at any time too.
+
+	  One well known example of this is PCMCIA- or PC-cards, credit-card
+	  size devices such as network cards, modems or hard drives which are
+	  plugged into slots found on all modern laptop computers.  Another
+	  example, used on modern desktops as well as laptops, is USB.
+
+	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
+	  software (at <http://linux-hotplug.sourceforge.net/>) and install it.
+	  Then your kernel will automatically call out to a user mode "policy
+	  agent" (/sbin/hotplug) to load modules and set up software needed
+	  to use devices as you hotplug them.
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+menu "Power management options"
+source "kernel/power/Kconfig"
+
+choice
+	prompt "Select PM Wakeup Event Source"
+	default PM_WAKEUP_GPIO_BY_SIC_IWR
+	depends on PM
+	help
+	  If you have a GPIO already configured as input with the corresponding PORTx_MASK
+	  bit set - "Specify Wakeup Event by SIC_IWR value"
+
+config PM_WAKEUP_GPIO_BY_SIC_IWR
+	bool "Specify Wakeup Event by SIC_IWR value"
+config PM_WAKEUP_BY_GPIO
+	bool "Cause Wakeup Event by GPIO"
+config PM_WAKEUP_GPIO_API
+	bool "Configure Wakeup Event by PM GPIO API"
+
+endchoice
+
+config PM_WAKEUP_SIC_IWR
+	hex "Wakeup Events (SIC_IWR)"
+	depends on PM_WAKEUP_GPIO_BY_SIC_IWR
+	default 0x80000000 if (BF537 || BF536 || BF534)
+	default 0x100000 if (BF533 || BF532 || BF531)
+
+config PM_WAKEUP_GPIO_NUMBER
+	int "Wakeup GPIO number"
+	range 0 47
+	depends on PM_WAKEUP_BY_GPIO
+	default 2 if BFIN537_STAMP
+
+choice
+	prompt "GPIO Polarity"
+	depends on PM_WAKEUP_BY_GPIO
+	default PM_WAKEUP_GPIO_POLAR_H
+config  PM_WAKEUP_GPIO_POLAR_H
+	bool "Active High"
+config  PM_WAKEUP_GPIO_POLAR_L
+	bool "Active Low"
+config  PM_WAKEUP_GPIO_POLAR_EDGE_F
+	bool "Falling EDGE"
+config  PM_WAKEUP_GPIO_POLAR_EDGE_R
+	bool "Rising EDGE"
+config  PM_WAKEUP_GPIO_POLAR_EDGE_B
+	bool "Both EDGE"
+endchoice
+
+endmenu
+
+if (BF537 || BF533)
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ
+	bool
+	default n
+	help
+	  If you want to enable this option, you should select the
+	  DPMC driver from Character Devices.
+endmenu
+
+endif
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/blackfin/oprofile/Kconfig"
+
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_HWERR
+	bool "Hardware error interrupt debugging"
+	depends on DEBUG_KERNEL
+	help
+	  When enabled, the hardware error interrupt is never disabled, and
+	  will happen immediately when an error condition occurs.  This comes
+	  at a slight cost in code size, but is necessary if you are getting
+	  hardware error interrupts and need to know where they are coming
+	  from.
+
+config DEBUG_ICACHE_CHECK
+	bool "Check Instruction cache coherancy"
+	depends on DEBUG_KERNEL
+	depends on DEBUG_HWERR
+	help
+	  Say Y here if you are getting wierd unexplained errors. This will
+	  ensure that icache is what SDRAM says it should be, by doing a
+	  byte wise comparision between SDRAM and instruction cache. This
+	  also relocates the irq_panic() function to L1 memory, (which is
+	  un-cached).
+
+config DEBUG_KERNEL_START
+	bool "Debug Kernel Startup"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here to put in an mini-execption handler before the kernel
+	  replaces the bootloader exception handler. This will stop kernels
+	  from dieing at startup with no visible error messages.
+
+config DEBUG_SERIAL_EARLY_INIT
+	bool "Initialize serial driver early"
+	default n
+	depends on SERIAL_BFIN
+	help
+	  Say Y here if you want to get kernel output early when kernel
+	  crashes before the normal console initialization. If this option
+	  is enable, console output will always go to the ttyBF0, no matter
+	  what kernel boot paramters you set.
+
+config DEBUG_HUNT_FOR_ZERO
+	bool "Catch NULL pointer reads/writes"
+	default y
+	help
+	  Say Y here to catch reads/writes to anywhere in the memory range
+	  from 0x0000 - 0x0FFF (the first 4k) of memory.  This is useful in
+	  catching common programming errors such as NULL pointer dereferences.
+
+	  Misbehaving applications will be killed (generate a SEGV) while the
+	  kernel will trigger a panic.
+
+	  Enabling this option will take up an extra entry in CPLB table.
+	  Otherwise, there is no extra overhead.
+
+config DEBUG_BFIN_NO_KERN_HWTRACE
+	bool "Trace user apps (turn off hwtrace in kernel)"
+	default n
+	help
+	  Some pieces of the kernel contain a lot of flow changes which can
+	  quickly fill up the hardware trace buffer.  When debugging crashes,
+	  the hardware trace may indicate that the problem lies in kernel
+	  space when in reality an application is buggy.
+
+	  Say Y here to disable hardware tracing in some known "jumpy" pieces
+	  of code so that the trace buffer will extend further back.
+
+config DUAL_CORE_TEST_MODULE
+	tristate "Dual Core Test Module"
+	depends on (BF561)
+	default n
+	help
+	  Say Y here to build-in dual core test module for dual core test.
+
+config CPLB_INFO
+	bool "Display the CPLB information"
+	help
+	  Display the CPLB information.
+
+config ACCESS_CHECK
+	bool "Check the user pointer address"
+	default y
+	help
+	  Usually the pointer transfer from user space is checked to see if its
+	  address is in the kernel space.
+
+	  Say N here to disable that check to improve the performance.
+
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
new file mode 100644
index 0000000..52d4dbd
--- /dev/null
+++ b/arch/blackfin/Makefile
@@ -0,0 +1,80 @@
+#
+# arch/blackfin/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+
+CROSS_COMPILE    ?= bfin-uclinux-
+LDFLAGS_vmlinux  := -X
+OBJCOPYFLAGS     := -O binary -R .note -R .comment -S
+GZFLAGS          := -9
+
+CFLAGS_MODULE    += -mlong-calls
+KALLSYMS         += --symbol-prefix=_
+
+
+# setup the machine name and the machine dependent settings
+machine-$(CONFIG_BF531) := bf533
+machine-$(CONFIG_BF532) := bf533
+machine-$(CONFIG_BF533) := bf533
+machine-$(CONFIG_BF534) := bf537
+machine-$(CONFIG_BF536) := bf537
+machine-$(CONFIG_BF537) := bf537
+machine-$(CONFIG_BF561) := bf561
+MACHINE := $(machine-y)
+export MACHINE
+
+
+head-y   := arch/$(ARCH)/mach-$(MACHINE)/head.o arch/$(ARCH)/kernel/init_task.o
+
+core-y   += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ arch/$(ARCH)/mach-common/
+
+# If we have a machine-specific directory, then include it in the build.
+ifneq ($(machine-y),)
+core-y   += arch/$(ARCH)/mach-$(MACHINE)/
+core-y   += arch/$(ARCH)/mach-$(MACHINE)/boards/
+endif
+
+libs-y   += arch/$(ARCH)/lib/
+
+drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
+
+
+
+#	Update machine arch symlinks if something which affects
+#	them changed.  We use .mach to indicate when they were updated
+#	last, otherwise make uses the target directory mtime.
+
+include/asm-blackfin/.mach: $(wildcard include/config/arch/*.h) include/config/auto.conf
+	@echo '  SYMLINK include/asm-$(ARCH)/mach-$(MACHINE) -> include/asm-$(ARCH)/mach'
+ifneq ($(KBUILD_SRC),)
+	$(Q)mkdir -p include/asm-$(ARCH)
+	$(Q)ln -fsn $(srctree)/include/asm-$(ARCH)/mach-$(MACHINE) include/asm-$(ARCH)/mach
+else
+	$(Q)ln -fsn mach-$(MACHINE) include/asm-$(ARCH)/mach
+endif
+	@touch $@
+
+CLEAN_FILES += \
+	include/asm-$(ARCH)/asm-offsets.h \
+	arch/$(ARCH)/kernel/asm-offsets.s \
+	include/asm-$(ARCH)/mach \
+	include/asm-$(ARCH)/.mach
+
+archprepare: include/asm-blackfin/.mach
+archclean:
+	$(Q)$(MAKE) $(clean)=$(boot)
+
+
+all: vmImage
+boot := arch/$(ARCH)/boot
+BOOT_TARGETS = vmImage
+.PHONY: $(BOOT_TARGETS)
+$(BOOT_TARGETS): vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+define archhelp
+  echo  '* vmImage         - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
+endef
diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile
new file mode 100644
index 0000000..49e8098
--- /dev/null
+++ b/arch/blackfin/boot/Makefile
@@ -0,0 +1,27 @@
+#
+# arch/blackfin/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
+targets := vmImage
+extra-y += vmlinux.bin vmlinux.gz
+
+quiet_cmd_uimage = UIMAGE  $@
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
+                   -C gzip -a $(CONFIG_BOOT_LOAD) -e $(CONFIG_BOOT_LOAD) -n 'Linux-$(KERNELRELEASE)' \
+                   -d $< $@
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+	$(call if_changed,objcopy)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,gzip)
+
+$(obj)/vmImage: $(obj)/vmlinux.gz
+	$(call if_changed,uimage)
+	@echo 'Kernel: $@ is ready'
diff --git a/arch/blackfin/defconfig b/arch/blackfin/defconfig
new file mode 100644
index 0000000..d5904ca
--- /dev/null
+++ b/arch/blackfin/defconfig
@@ -0,0 +1,1314 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BFIN=y
+CONFIG_SEMAPHORE_SLEEPERS=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_UCLINUX=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_IRQCHIP_DEMUX_GPIO=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_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_SYSFS_DEPRECATED=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=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_LIMIT_PAGECACHE is not set
+CONFIG_BUDDY=y
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=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 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 is not set
+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"
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF535 is not set
+# CONFIG_BF536 is not set
+CONFIG_BF537=y
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+CONFIG_BLACKFIN=y
+CONFIG_BFIN_SINGLE_CORE=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+CONFIG_BFIN537_STAMP=y
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_PNAV10 is not set
+# CONFIG_GENERIC_BOARD is not set
+CONFIG_MEM_MT48LC32M8A2_75=y
+CONFIG_IRQ_PLL_WAKEUP=7
+
+#
+# BF537 Specific Configuration
+#
+
+#
+# PORT F/G Selection
+#
+CONFIG_BF537_PORT_F=y
+# CONFIG_BF537_PORT_G is not set
+# CONFIG_BF537_PORT_H is not set
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA_ERROR=7
+CONFIG_IRQ_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_CAN_RX=11
+CONFIG_IRQ_CAN_TX=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PROG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+
+#
+# Board customizations
+#
+
+#
+# Board Setup
+#
+CONFIG_CLKIN_HZ=25000000
+CONFIG_MEM_SIZE=64
+CONFIG_MEM_ADD_WIDTH=10
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Console UART Setup
+#
+# CONFIG_BAUD_9600 is not set
+# CONFIG_BAUD_19200 is not set
+# CONFIG_BAUD_38400 is not set
+CONFIG_BAUD_57600=y
+# CONFIG_BAUD_115200 is not set
+CONFIG_BAUD_NO_PARITY=y
+# CONFIG_BAUD_PARITY is not set
+CONFIG_BAUD_1_STOPBIT=y
+# CONFIG_BAUD_2_STOPBIT is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Timer Tick
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL 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_LARGE_ALLOCS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BLKFIN_CACHE=y
+CONFIG_BLKFIN_DCACHE=y
+# CONFIG_BLKFIN_CACHE_LOCK is not set
+# CONFIG_BLKFIN_WB is not set
+CONFIG_BLKFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+
+#
+# Clock Settings
+#
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMBCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+# CONFIG_PM_WAKEUP_GPIO_API is not set
+CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ 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=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_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_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL 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=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# 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=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=m
+CONFIG_MTD_BLKDEVS=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 is not set
+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_MW320D=m
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# 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_BF5xx=m
+CONFIG_BFIN_FLASH_SIZE=0x400000
+CONFIG_EBIU_FLASH_BASE=0x20000000
+
+#
+# FLASH_EBIU_AMBCTL Control
+#
+CONFIG_BFIN_FLASH_BANK_0=0x7BB0
+CONFIG_BFIN_FLASH_BANK_1=0x7BB0
+CONFIG_BFIN_FLASH_BANK_2=0x7BB0
+CONFIG_BFIN_FLASH_BANK_3=0x7BB0
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# 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
+# 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_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+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
+#
+# 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=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_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 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 is not set
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_MAC_USE_L1=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+# CONFIG_BFIN_MAC_RMII 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=m
+# 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=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_BF53X_PFBUTTONS is not set
+CONFIG_TWI_KEYPAD=m
+CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF533_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BF5xx_TIMERS is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+CONFIG_TWI_LCD=m
+CONFIG_TWI_LCD_SLAVE_ADDR=34
+# CONFIG_AD5304 is not set
+# 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_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART1 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+CONFIG_CAN4LINUX=y
+
+#
+# linux embedded drivers
+#
+# CONFIG_CAN_MCF5282 is not set
+# CONFIG_CAN_UNCTWINCAN is not set
+CONFIG_CAN_BLACKFIN=m
+
+#
+# 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_BLACKFIN_DPMC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 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=m
+
+#
+# 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_BFIN_GPIO is not set
+CONFIG_I2C_BFIN_TWI=m
+CONFIG_TWICLK_KHZ=50
+# 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_AD5252=m
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8575 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
+CONFIG_SPI_BFIN=y
+
+#
+# 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_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_LM70 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_PC87427 is not set
+# 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
+# CONFIG_SENSORS_W83793 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
+
+#
+# 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=m
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# 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_BFIN_7171=m
+CONFIG_FB_BFIN_7393=m
+CONFIG_NTSC=y
+# CONFIG_PAL is not set
+# CONFIG_NTSC_640x480 is not set
+# CONFIG_PAL_640x480 is not set
+# CONFIG_NTSC_YCBCR is not set
+# CONFIG_PAL_YCBCR is not set
+CONFIG_ADV7393_1XMEM=y
+# CONFIG_ADV7393_2XMEM is not set
+CONFIG_FB_BF537_LQ035=m
+CONFIG_LQ035_SLAVE_ADDR=0x58
+# CONFIG_FB_BFIN_LANDSCAPE is not set
+# CONFIG_FB_BFIN_BGR is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=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_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_DUMMY 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
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# 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_SPI_MMC is not set
+# 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=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_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_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
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS 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_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 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_SYSCTL=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_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+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=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 is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+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=m
+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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_BOOTPARAM is not set
+# CONFIG_NO_KERNEL_MSG is not set
+CONFIG_CPLB_INFO=y
+# CONFIG_NO_ACCESS_CHECK is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
new file mode 100644
index 0000000..f3b7d2f
--- /dev/null
+++ b/arch/blackfin/kernel/Makefile
@@ -0,0 +1,14 @@
+#
+# arch/blackfin/kernel/Makefile
+#
+
+extra-y := init_task.o vmlinux.lds
+
+obj-y := \
+	entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
+	sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
+	flat.o
+
+obj-$(CONFIG_MODULES)                += module.o
+obj-$(CONFIG_BFIN_DMA_5XX)           += bfin_dma_5xx.o
+obj-$(CONFIG_DUAL_CORE_TEST_MODULE)  += dualcore_test.o
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
new file mode 100644
index 0000000..41d9a9f
--- /dev/null
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -0,0 +1,136 @@
+/*
+ * File:         arch/blackfin/kernel/asm-offsets.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  generate definitions needed by assembly language modules.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <asm/irq.h>
+#include <asm/thread_info.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+int main(void)
+{
+	/* offsets into the task struct */
+	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
+	DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
+
+	/* offsets into the irq_cpustat_t struct */
+	DEFINE(CPUSTAT_SOFTIRQ_PENDING,
+	       offsetof(irq_cpustat_t, __softirq_pending));
+
+	/* offsets into the thread struct */
+	DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+	DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+	DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
+	DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
+	DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+	DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
+	DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
+
+	/* offsets into the pt_regs */
+	DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
+	DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
+	DEFINE(PT_R0, offsetof(struct pt_regs, r0));
+	DEFINE(PT_R1, offsetof(struct pt_regs, r1));
+	DEFINE(PT_R2, offsetof(struct pt_regs, r2));
+	DEFINE(PT_R3, offsetof(struct pt_regs, r3));
+	DEFINE(PT_R4, offsetof(struct pt_regs, r4));
+	DEFINE(PT_R5, offsetof(struct pt_regs, r5));
+	DEFINE(PT_R6, offsetof(struct pt_regs, r6));
+	DEFINE(PT_R7, offsetof(struct pt_regs, r7));
+
+	DEFINE(PT_P0, offsetof(struct pt_regs, p0));
+	DEFINE(PT_P1, offsetof(struct pt_regs, p1));
+	DEFINE(PT_P2, offsetof(struct pt_regs, p2));
+	DEFINE(PT_P3, offsetof(struct pt_regs, p3));
+	DEFINE(PT_P4, offsetof(struct pt_regs, p4));
+	DEFINE(PT_P5, offsetof(struct pt_regs, p5));
+
+	DEFINE(PT_FP, offsetof(struct pt_regs, fp));
+	DEFINE(PT_USP, offsetof(struct pt_regs, usp));
+	DEFINE(PT_I0, offsetof(struct pt_regs, i0));
+	DEFINE(PT_I1, offsetof(struct pt_regs, i1));
+	DEFINE(PT_I2, offsetof(struct pt_regs, i2));
+	DEFINE(PT_I3, offsetof(struct pt_regs, i3));
+	DEFINE(PT_M0, offsetof(struct pt_regs, m0));
+	DEFINE(PT_M1, offsetof(struct pt_regs, m1));
+	DEFINE(PT_M2, offsetof(struct pt_regs, m2));
+	DEFINE(PT_M3, offsetof(struct pt_regs, m3));
+	DEFINE(PT_L0, offsetof(struct pt_regs, l0));
+	DEFINE(PT_L1, offsetof(struct pt_regs, l1));
+	DEFINE(PT_L2, offsetof(struct pt_regs, l2));
+	DEFINE(PT_L3, offsetof(struct pt_regs, l3));
+	DEFINE(PT_B0, offsetof(struct pt_regs, b0));
+	DEFINE(PT_B1, offsetof(struct pt_regs, b1));
+	DEFINE(PT_B2, offsetof(struct pt_regs, b2));
+	DEFINE(PT_B3, offsetof(struct pt_regs, b3));
+	DEFINE(PT_A0X, offsetof(struct pt_regs, a0x));
+	DEFINE(PT_A0W, offsetof(struct pt_regs, a0w));
+	DEFINE(PT_A1X, offsetof(struct pt_regs, a1x));
+	DEFINE(PT_A1W, offsetof(struct pt_regs, a1w));
+	DEFINE(PT_LC0, offsetof(struct pt_regs, lc0));
+	DEFINE(PT_LC1, offsetof(struct pt_regs, lc1));
+	DEFINE(PT_LT0, offsetof(struct pt_regs, lt0));
+	DEFINE(PT_LT1, offsetof(struct pt_regs, lt1));
+	DEFINE(PT_LB0, offsetof(struct pt_regs, lb0));
+	DEFINE(PT_LB1, offsetof(struct pt_regs, lb1));
+	DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat));
+	DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved));
+	DEFINE(PT_RETS, offsetof(struct pt_regs, rets));
+	DEFINE(PT_PC, offsetof(struct pt_regs, pc));
+	DEFINE(PT_RETX, offsetof(struct pt_regs, retx));
+	DEFINE(PT_RETN, offsetof(struct pt_regs, retn));
+	DEFINE(PT_RETE, offsetof(struct pt_regs, rete));
+	DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat));
+	DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg));
+	DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend));
+	DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs));
+	DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs));        /* Needed by gdb */
+	DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */
+	DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs));    /* Needed by gdb */
+	DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs));  /* Needed by gdb */
+	DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */
+
+	/* signal defines */
+	DEFINE(SIGSEGV, SIGSEGV);
+	DEFINE(SIGTRAP, SIGTRAP);
+
+	return 0;
+}
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
new file mode 100644
index 0000000..8ea079e
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -0,0 +1,742 @@
+/*
+ * File:         arch/blackfin/kernel/bfin_dma_5xx.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+/* Remove unused code not exported by symbol or internally called */
+#define REMOVE_DEAD_CODE
+
+/**************************************************************************
+ * Global Variables
+***************************************************************************/
+
+static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
+#if defined (CONFIG_BF561)
+static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+	(struct dma_register *) DMA1_0_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_1_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_2_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_3_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_4_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_5_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_6_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_7_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_8_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_9_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_10_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_11_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_0_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_1_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_2_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_3_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_4_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_5_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_6_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_7_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_8_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_9_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_10_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_11_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
+	(struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
+	(struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
+	(struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
+	(struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
+};
+#else
+static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+	(struct dma_register *) DMA0_NEXT_DESC_PTR,
+	(struct dma_register *) DMA1_NEXT_DESC_PTR,
+	(struct dma_register *) DMA2_NEXT_DESC_PTR,
+	(struct dma_register *) DMA3_NEXT_DESC_PTR,
+	(struct dma_register *) DMA4_NEXT_DESC_PTR,
+	(struct dma_register *) DMA5_NEXT_DESC_PTR,
+	(struct dma_register *) DMA6_NEXT_DESC_PTR,
+	(struct dma_register *) DMA7_NEXT_DESC_PTR,
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
+	(struct dma_register *) DMA8_NEXT_DESC_PTR,
+	(struct dma_register *) DMA9_NEXT_DESC_PTR,
+	(struct dma_register *) DMA10_NEXT_DESC_PTR,
+	(struct dma_register *) DMA11_NEXT_DESC_PTR,
+#endif
+	(struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+	(struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+};
+#endif
+
+/*------------------------------------------------------------------------------
+ *       Set the Buffer Clear bit in the Configuration register of specific DMA
+ *       channel. This will stop the descriptor based DMA operation.
+ *-----------------------------------------------------------------------------*/
+static void clear_dma_buffer(unsigned int channel)
+{
+	dma_ch[channel].regs->cfg |= RESTART;
+	SSYNC();
+	dma_ch[channel].regs->cfg &= ~RESTART;
+	SSYNC();
+}
+
+int __init blackfin_dma_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "Blackfin DMA Controller\n");
+
+	for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
+		dma_ch[i].chan_status = DMA_CHANNEL_FREE;
+		dma_ch[i].regs = base_addr[i];
+		mutex_init(&(dma_ch[i].dmalock));
+	}
+
+	return 0;
+}
+
+arch_initcall(blackfin_dma_init);
+
+/*
+ *	Form the channel find the irq number for that channel.
+ */
+#if !defined(CONFIG_BF561)
+
+static int bf533_channel2irq(unsigned int channel)
+{
+	int ret_irq = -1;
+
+	switch (channel) {
+	case CH_PPI:
+		ret_irq = IRQ_PPI;
+		break;
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
+	case CH_EMAC_RX:
+		ret_irq = IRQ_MAC_RX;
+		break;
+
+	case CH_EMAC_TX:
+		ret_irq = IRQ_MAC_TX;
+		break;
+
+	case CH_UART1_RX:
+		ret_irq = IRQ_UART1_RX;
+		break;
+
+	case CH_UART1_TX:
+		ret_irq = IRQ_UART1_TX;
+		break;
+#endif
+
+	case CH_SPORT0_RX:
+		ret_irq = IRQ_SPORT0_RX;
+		break;
+
+	case CH_SPORT0_TX:
+		ret_irq = IRQ_SPORT0_TX;
+		break;
+
+	case CH_SPORT1_RX:
+		ret_irq = IRQ_SPORT1_RX;
+		break;
+
+	case CH_SPORT1_TX:
+		ret_irq = IRQ_SPORT1_TX;
+		break;
+
+	case CH_SPI:
+		ret_irq = IRQ_SPI;
+		break;
+
+	case CH_UART_RX:
+		ret_irq = IRQ_UART_RX;
+		break;
+
+	case CH_UART_TX:
+		ret_irq = IRQ_UART_TX;
+		break;
+
+	case CH_MEM_STREAM0_SRC:
+	case CH_MEM_STREAM0_DEST:
+		ret_irq = IRQ_MEM_DMA0;
+		break;
+
+	case CH_MEM_STREAM1_SRC:
+	case CH_MEM_STREAM1_DEST:
+		ret_irq = IRQ_MEM_DMA1;
+		break;
+	}
+	return ret_irq;
+}
+
+# define channel2irq(channel) bf533_channel2irq(channel)
+
+#else
+
+static int bf561_channel2irq(unsigned int channel)
+{
+	int ret_irq = -1;
+
+	switch (channel) {
+	case CH_PPI0:
+		ret_irq = IRQ_PPI0;
+		break;
+	case CH_PPI1:
+		ret_irq = IRQ_PPI1;
+		break;
+	case CH_SPORT0_RX:
+		ret_irq = IRQ_SPORT0_RX;
+		break;
+	case CH_SPORT0_TX:
+		ret_irq = IRQ_SPORT0_TX;
+		break;
+	case CH_SPORT1_RX:
+		ret_irq = IRQ_SPORT1_RX;
+		break;
+	case CH_SPORT1_TX:
+		ret_irq = IRQ_SPORT1_TX;
+		break;
+	case CH_SPI:
+		ret_irq = IRQ_SPI;
+		break;
+	case CH_UART_RX:
+		ret_irq = IRQ_UART_RX;
+		break;
+	case CH_UART_TX:
+		ret_irq = IRQ_UART_TX;
+		break;
+
+	case CH_MEM_STREAM0_SRC:
+	case CH_MEM_STREAM0_DEST:
+		ret_irq = IRQ_MEM_DMA0;
+		break;
+	case CH_MEM_STREAM1_SRC:
+	case CH_MEM_STREAM1_DEST:
+		ret_irq = IRQ_MEM_DMA1;
+		break;
+	case CH_MEM_STREAM2_SRC:
+	case CH_MEM_STREAM2_DEST:
+		ret_irq = IRQ_MEM_DMA2;
+		break;
+	case CH_MEM_STREAM3_SRC:
+	case CH_MEM_STREAM3_DEST:
+		ret_irq = IRQ_MEM_DMA3;
+		break;
+
+	case CH_IMEM_STREAM0_SRC:
+	case CH_IMEM_STREAM0_DEST:
+		ret_irq = IRQ_IMEM_DMA0;
+		break;
+	case CH_IMEM_STREAM1_SRC:
+	case CH_IMEM_STREAM1_DEST:
+		ret_irq = IRQ_IMEM_DMA1;
+		break;
+	}
+	return ret_irq;
+}
+
+# define channel2irq(channel) bf561_channel2irq(channel)
+
+#endif
+
+/*------------------------------------------------------------------------------
+ *	Request the specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+int request_dma(unsigned int channel, char *device_id)
+{
+
+	pr_debug("request_dma() : BEGIN \n");
+	mutex_lock(&(dma_ch[channel].dmalock));
+
+	if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
+	    || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
+		mutex_unlock(&(dma_ch[channel].dmalock));
+		pr_debug("DMA CHANNEL IN USE  \n");
+		return -EBUSY;
+	} else {
+		dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
+		pr_debug("DMA CHANNEL IS ALLOCATED  \n");
+	}
+
+	mutex_unlock(&(dma_ch[channel].dmalock));
+
+	dma_ch[channel].device_id = device_id;
+	dma_ch[channel].irq_callback = NULL;
+
+	/* This is to be enabled by putting a restriction -
+	 * you have to request DMA, before doing any operations on
+	 * descriptor/channel
+	 */
+	pr_debug("request_dma() : END  \n");
+	return channel;
+}
+EXPORT_SYMBOL(request_dma);
+
+int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data)
+{
+	int ret_irq = 0;
+
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	if (callback != NULL) {
+		int ret_val;
+		ret_irq = channel2irq(channel);
+
+		dma_ch[channel].data = data;
+
+		ret_val =
+		    request_irq(ret_irq, (void *)callback, IRQF_DISABLED,
+				dma_ch[channel].device_id, data);
+		if (ret_val) {
+			printk(KERN_NOTICE
+			       "Request irq in DMA engine failed.\n");
+			return -EPERM;
+		}
+		dma_ch[channel].irq_callback = callback;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(set_dma_callback);
+
+void free_dma(unsigned int channel)
+{
+	int ret_irq;
+
+	pr_debug("freedma() : BEGIN \n");
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	/* Halt the DMA */
+	disable_dma(channel);
+	clear_dma_buffer(channel);
+
+	if (dma_ch[channel].irq_callback != NULL) {
+		ret_irq = channel2irq(channel);
+		free_irq(ret_irq, dma_ch[channel].data);
+	}
+
+	/* Clear the DMA Variable in the Channel */
+	mutex_lock(&(dma_ch[channel].dmalock));
+	dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
+	mutex_unlock(&(dma_ch[channel].dmalock));
+
+	pr_debug("freedma() : END \n");
+}
+EXPORT_SYMBOL(free_dma);
+
+void dma_enable_irq(unsigned int channel)
+{
+	int ret_irq;
+
+	pr_debug("dma_enable_irq() : BEGIN \n");
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	ret_irq = channel2irq(channel);
+	enable_irq(ret_irq);
+}
+EXPORT_SYMBOL(dma_enable_irq);
+
+void dma_disable_irq(unsigned int channel)
+{
+	int ret_irq;
+
+	pr_debug("dma_disable_irq() : BEGIN \n");
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	ret_irq = channel2irq(channel);
+	disable_irq(ret_irq);
+}
+EXPORT_SYMBOL(dma_disable_irq);
+
+int dma_channel_active(unsigned int channel)
+{
+	if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) {
+		return 0;
+	} else {
+		return 1;
+	}
+}
+EXPORT_SYMBOL(dma_channel_active);
+
+/*------------------------------------------------------------------------------
+*	stop the specific DMA channel.
+*-----------------------------------------------------------------------------*/
+void disable_dma(unsigned int channel)
+{
+	pr_debug("stop_dma() : BEGIN \n");
+
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->cfg &= ~DMAEN;	/* Clean the enable bit */
+	SSYNC();
+	dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
+	/* Needs to be enabled Later */
+	pr_debug("stop_dma() : END \n");
+	return;
+}
+EXPORT_SYMBOL(disable_dma);
+
+void enable_dma(unsigned int channel)
+{
+	pr_debug("enable_dma() : BEGIN \n");
+
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
+	dma_ch[channel].regs->curr_x_count = 0;
+	dma_ch[channel].regs->curr_y_count = 0;
+
+	dma_ch[channel].regs->cfg |= DMAEN;	/* Set the enable bit */
+	SSYNC();
+	pr_debug("enable_dma() : END \n");
+	return;
+}
+EXPORT_SYMBOL(enable_dma);
+
+/*------------------------------------------------------------------------------
+*		Set the Start Address register for the specific DMA channel
+* 		This function can be used for register based DMA,
+*		to setup the start address
+*		addr:		Starting address of the DMA Data to be transferred.
+*-----------------------------------------------------------------------------*/
+void set_dma_start_addr(unsigned int channel, unsigned long addr)
+{
+	pr_debug("set_dma_start_addr() : BEGIN \n");
+
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->start_addr = addr;
+	SSYNC();
+	pr_debug("set_dma_start_addr() : END\n");
+}
+EXPORT_SYMBOL(set_dma_start_addr);
+
+void set_dma_next_desc_addr(unsigned int channel, unsigned long addr)
+{
+	pr_debug("set_dma_next_desc_addr() : BEGIN \n");
+
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->next_desc_ptr = addr;
+	SSYNC();
+	pr_debug("set_dma_start_addr() : END\n");
+}
+EXPORT_SYMBOL(set_dma_next_desc_addr);
+
+void set_dma_x_count(unsigned int channel, unsigned short x_count)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->x_count = x_count;
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_x_count);
+
+void set_dma_y_count(unsigned int channel, unsigned short y_count)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->y_count = y_count;
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_y_count);
+
+void set_dma_x_modify(unsigned int channel, short x_modify)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->x_modify = x_modify;
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_x_modify);
+
+void set_dma_y_modify(unsigned int channel, short y_modify)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->y_modify = y_modify;
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_y_modify);
+
+void set_dma_config(unsigned int channel, unsigned short config)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->cfg = config;
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_config);
+
+unsigned short
+set_bfin_dma_config(char direction, char flow_mode,
+		    char intr_mode, char dma_mode, char width)
+{
+	unsigned short config;
+
+	config =
+	    ((direction << 1) | (width << 2) | (dma_mode << 4) |
+	     (intr_mode << 6) | (flow_mode << 12) | RESTART);
+	return config;
+}
+EXPORT_SYMBOL(set_bfin_dma_config);
+
+void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8);
+
+	dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg;
+
+	SSYNC();
+}
+EXPORT_SYMBOL(set_dma_sg);
+
+/*------------------------------------------------------------------------------
+ *	Get the DMA status of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_irqstat(unsigned int channel)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	return dma_ch[channel].regs->irq_status;
+}
+EXPORT_SYMBOL(get_dma_curr_irqstat);
+
+/*------------------------------------------------------------------------------
+ *	Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt.
+ *-----------------------------------------------------------------------------*/
+void clear_dma_irqstat(unsigned int channel)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+	dma_ch[channel].regs->irq_status |= 3;
+}
+EXPORT_SYMBOL(clear_dma_irqstat);
+
+/*------------------------------------------------------------------------------
+ *	Get current DMA xcount of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_xcount(unsigned int channel)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	return dma_ch[channel].regs->curr_x_count;
+}
+EXPORT_SYMBOL(get_dma_curr_xcount);
+
+/*------------------------------------------------------------------------------
+ *	Get current DMA ycount of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_ycount(unsigned int channel)
+{
+	BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+	       && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+	return dma_ch[channel].regs->curr_y_count;
+}
+EXPORT_SYMBOL(get_dma_curr_ycount);
+
+void *dma_memcpy(void *dest, const void *src, size_t size)
+{
+	int direction;	/* 1 - address decrease, 0 - address increase */
+	int flag_align;	/* 1 - address aligned,  0 - address unaligned */
+	int flag_2D;	/* 1 - 2D DMA needed,	 0 - 1D DMA needed */
+
+	if (size <= 0)
+		return NULL;
+
+	if ((unsigned long)src < memory_end)
+		blackfin_dcache_flush_range((unsigned int)src,
+					    (unsigned int)(src + size));
+
+	bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+	if ((unsigned long)src < (unsigned long)dest)
+		direction = 1;
+	else
+		direction = 0;
+
+	if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0)
+	    && ((size % 2) == 0))
+		flag_align = 1;
+	else
+		flag_align = 0;
+
+	if (size > 0x10000)	/* size > 64K */
+		flag_2D = 1;
+	else
+		flag_2D = 0;
+
+	/* Setup destination and source start address */
+	if (direction) {
+		if (flag_align) {
+			bfin_write_MDMA_D0_START_ADDR(dest + size - 2);
+			bfin_write_MDMA_S0_START_ADDR(src + size - 2);
+		} else {
+			bfin_write_MDMA_D0_START_ADDR(dest + size - 1);
+			bfin_write_MDMA_S0_START_ADDR(src + size - 1);
+		}
+	} else {
+		bfin_write_MDMA_D0_START_ADDR(dest);
+		bfin_write_MDMA_S0_START_ADDR(src);
+	}
+
+	/* Setup destination and source xcount */
+	if (flag_2D) {
+		if (flag_align) {
+			bfin_write_MDMA_D0_X_COUNT(1024 / 2);
+			bfin_write_MDMA_S0_X_COUNT(1024 / 2);
+		} else {
+			bfin_write_MDMA_D0_X_COUNT(1024);
+			bfin_write_MDMA_S0_X_COUNT(1024);
+		}
+		bfin_write_MDMA_D0_Y_COUNT(size >> 10);
+		bfin_write_MDMA_S0_Y_COUNT(size >> 10);
+	} else {
+		if (flag_align) {
+			bfin_write_MDMA_D0_X_COUNT(size / 2);
+			bfin_write_MDMA_S0_X_COUNT(size / 2);
+		} else {
+			bfin_write_MDMA_D0_X_COUNT(size);
+			bfin_write_MDMA_S0_X_COUNT(size);
+		}
+	}
+
+	/* Setup destination and source xmodify and ymodify */
+	if (direction) {
+		if (flag_align) {
+			bfin_write_MDMA_D0_X_MODIFY(-2);
+			bfin_write_MDMA_S0_X_MODIFY(-2);
+			if (flag_2D) {
+				bfin_write_MDMA_D0_Y_MODIFY(-2);
+				bfin_write_MDMA_S0_Y_MODIFY(-2);
+			}
+		} else {
+			bfin_write_MDMA_D0_X_MODIFY(-1);
+			bfin_write_MDMA_S0_X_MODIFY(-1);
+			if (flag_2D) {
+				bfin_write_MDMA_D0_Y_MODIFY(-1);
+				bfin_write_MDMA_S0_Y_MODIFY(-1);
+			}
+		}
+	} else {
+		if (flag_align) {
+			bfin_write_MDMA_D0_X_MODIFY(2);
+			bfin_write_MDMA_S0_X_MODIFY(2);
+			if (flag_2D) {
+				bfin_write_MDMA_D0_Y_MODIFY(2);
+				bfin_write_MDMA_S0_Y_MODIFY(2);
+			}
+		} else {
+			bfin_write_MDMA_D0_X_MODIFY(1);
+			bfin_write_MDMA_S0_X_MODIFY(1);
+			if (flag_2D) {
+				bfin_write_MDMA_D0_Y_MODIFY(1);
+				bfin_write_MDMA_S0_Y_MODIFY(1);
+			}
+		}
+	}
+
+	/* Enable source DMA */
+	if (flag_2D) {
+		if (flag_align) {
+			bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16);
+			bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16);
+		} else {
+			bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D);
+			bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D);
+		}
+	} else {
+		if (flag_align) {
+			bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
+			bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
+		} else {
+			bfin_write_MDMA_S0_CONFIG(DMAEN);
+			bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN);
+		}
+	}
+
+	while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
+		;
+
+	bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() |
+				      (DMA_DONE | DMA_ERR));
+
+	bfin_write_MDMA_S0_CONFIG(0);
+	bfin_write_MDMA_D0_CONFIG(0);
+
+	if ((unsigned long)dest < memory_end)
+		blackfin_dcache_invalidate_range((unsigned int)dest,
+						 (unsigned int)(dest + size));
+
+	return dest;
+}
+EXPORT_SYMBOL(dma_memcpy);
+
+void *safe_dma_memcpy(void *dest, const void *src, size_t size)
+{
+	int flags = 0;
+	void *addr;
+	local_irq_save(flags);
+	addr = dma_memcpy(dest, src, size);
+	local_irq_restore(flags);
+	return addr;
+}
+EXPORT_SYMBOL(safe_dma_memcpy);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
new file mode 100644
index 0000000..e9f24a9
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -0,0 +1,637 @@
+/*
+ * File:         arch/blackfin/kernel/bfin_gpio.c
+ * Based on:
+ * Author:       Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description:  GPIO Abstraction Layer
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+*  Number     BF537/6/4    BF561    BF533/2/1
+*
+*  GPIO_0       PF0         PF0        PF0
+*  GPIO_1       PF1         PF1        PF1
+*  GPIO_2       PF2         PF2        PF2
+*  GPIO_3       PF3         PF3        PF3
+*  GPIO_4       PF4         PF4        PF4
+*  GPIO_5       PF5         PF5        PF5
+*  GPIO_6       PF6         PF6        PF6
+*  GPIO_7       PF7         PF7        PF7
+*  GPIO_8       PF8         PF8        PF8
+*  GPIO_9       PF9         PF9        PF9
+*  GPIO_10      PF10        PF10       PF10
+*  GPIO_11      PF11        PF11       PF11
+*  GPIO_12      PF12        PF12       PF12
+*  GPIO_13      PF13        PF13       PF13
+*  GPIO_14      PF14        PF14       PF14
+*  GPIO_15      PF15        PF15       PF15
+*  GPIO_16      PG0         PF16
+*  GPIO_17      PG1         PF17
+*  GPIO_18      PG2         PF18
+*  GPIO_19      PG3         PF19
+*  GPIO_20      PG4         PF20
+*  GPIO_21      PG5         PF21
+*  GPIO_22      PG6         PF22
+*  GPIO_23      PG7         PF23
+*  GPIO_24      PG8         PF24
+*  GPIO_25      PG9         PF25
+*  GPIO_26      PG10        PF26
+*  GPIO_27      PG11        PF27
+*  GPIO_28      PG12        PF28
+*  GPIO_29      PG13        PF29
+*  GPIO_30      PG14        PF30
+*  GPIO_31      PG15        PF31
+*  GPIO_32      PH0         PF32
+*  GPIO_33      PH1         PF33
+*  GPIO_34      PH2         PF34
+*  GPIO_35      PH3         PF35
+*  GPIO_36      PH4         PF36
+*  GPIO_37      PH5         PF37
+*  GPIO_38      PH6         PF38
+*  GPIO_39      PH7         PF39
+*  GPIO_40      PH8         PF40
+*  GPIO_41      PH9         PF41
+*  GPIO_42      PH10        PF42
+*  GPIO_43      PH11        PF43
+*  GPIO_44      PH12        PF44
+*  GPIO_45      PH13        PF45
+*  GPIO_46      PH14        PF46
+*  GPIO_47      PH15        PF47
+*/
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <linux/irq.h>
+
+#ifdef BF533_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+	(struct gpio_port_t *) FIO_FLAG_D,
+};
+#endif
+
+#ifdef BF537_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+	(struct gpio_port_t *) PORTFIO,
+	(struct gpio_port_t *) PORTGIO,
+	(struct gpio_port_t *) PORTHIO,
+};
+
+static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+	(unsigned short *) PORTF_FER,
+	(unsigned short *) PORTG_FER,
+	(unsigned short *) PORTH_FER,
+};
+
+#endif
+
+#ifdef BF561_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+	(struct gpio_port_t *) FIO0_FLAG_D,
+	(struct gpio_port_t *) FIO1_FLAG_D,
+	(struct gpio_port_t *) FIO2_FLAG_D,
+};
+#endif
+
+static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+#ifdef CONFIG_PM
+static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
+static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+#ifdef BF533_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};
+#endif
+
+#ifdef BF537_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
+#endif
+
+#ifdef BF561_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
+#endif
+
+#endif /* CONFIG_PM */
+
+inline int check_gpio(unsigned short gpio)
+{
+	if (gpio > MAX_BLACKFIN_GPIOS)
+		return -EINVAL;
+	return 0;
+}
+
+#ifdef BF537_FAMILY
+void port_setup(unsigned short gpio, unsigned short usage)
+{
+	if (usage == GPIO_USAGE) {
+		if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
+			printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
+			       "usage and GPIO %d detected!\n", gpio);
+		*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+	} else
+		*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
+	SSYNC();
+}
+#else
+# define port_setup(...)  do { } while (0)
+#endif
+
+
+void default_gpio(unsigned short gpio)
+{
+	unsigned short bank,bitmask;
+
+	bank = gpio_bank(gpio);
+	bitmask = gpio_bit(gpio);
+
+	gpio_bankb[bank]->maska_clear = bitmask;
+	gpio_bankb[bank]->maskb_clear = bitmask;
+	SSYNC();
+	gpio_bankb[bank]->inen &= ~bitmask;
+	gpio_bankb[bank]->dir &= ~bitmask;
+	gpio_bankb[bank]->polar &= ~bitmask;
+	gpio_bankb[bank]->both &= ~bitmask;
+	gpio_bankb[bank]->edge &= ~bitmask;
+}
+
+
+int __init bfin_gpio_init(void)
+{
+	int i;
+
+	printk(KERN_INFO "Blackfin GPIO Controller\n");
+
+	for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
+		reserved_map[gpio_bank(i)] = 0;
+
+#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+# if defined(CONFIG_BFIN_MAC_RMII)
+	reserved_map[PORT_H] = 0xC373;
+# else
+	reserved_map[PORT_H] = 0xFFFF;
+# endif
+#endif
+
+	return 0;
+}
+
+arch_initcall(bfin_gpio_init);
+
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin General Purpose Ports Access Functions
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: These functions abstract direct register access
+*              to Blackfin processor General Purpose
+*              Ports Regsiters
+*
+* CAUTION: These functions do not belong to the GPIO Driver API
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+/* Set a specific bit */
+
+#define SET_GPIO(name) \
+void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+	unsigned long flags; \
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+	local_irq_save(flags); \
+	if (arg) \
+		gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
+	else \
+		gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
+	local_irq_restore(flags); \
+} \
+EXPORT_SYMBOL(set_gpio_ ## name);
+
+SET_GPIO(dir)
+SET_GPIO(inen)
+SET_GPIO(polar)
+SET_GPIO(edge)
+SET_GPIO(both)
+
+
+#define SET_GPIO_SC(name) \
+void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+	if (arg) \
+		gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
+	else \
+		gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
+} \
+EXPORT_SYMBOL(set_gpio_ ## name);
+
+SET_GPIO_SC(maska)
+SET_GPIO_SC(maskb)
+
+#if defined(ANOMALY_05000311)
+void set_gpio_data(unsigned short gpio, unsigned short arg)
+{
+	unsigned long flags;
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	local_irq_save(flags);
+	if (arg)
+		gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+	else
+		gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
+	bfin_read_CHIPID();
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(set_gpio_data);
+#else
+SET_GPIO_SC(data)
+#endif
+
+
+#if defined(ANOMALY_05000311)
+void set_gpio_toggle(unsigned short gpio)
+{
+	unsigned long flags;
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	local_irq_save(flags);
+	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+	bfin_read_CHIPID();
+	local_irq_restore(flags);
+}
+#else
+void set_gpio_toggle(unsigned short gpio)
+{
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+}
+#endif
+EXPORT_SYMBOL(set_gpio_toggle);
+
+
+/*Set current PORT date (16-bit word)*/
+
+#define SET_GPIO_P(name) \
+void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+	gpio_bankb[gpio_bank(gpio)]->name = arg; \
+} \
+EXPORT_SYMBOL(set_gpiop_ ## name);
+
+SET_GPIO_P(dir)
+SET_GPIO_P(inen)
+SET_GPIO_P(polar)
+SET_GPIO_P(edge)
+SET_GPIO_P(both)
+SET_GPIO_P(maska)
+SET_GPIO_P(maskb)
+
+
+#if defined(ANOMALY_05000311)
+void set_gpiop_data(unsigned short gpio, unsigned short arg)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+	gpio_bankb[gpio_bank(gpio)]->data = arg;
+	bfin_read_CHIPID();
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(set_gpiop_data);
+#else
+SET_GPIO_P(data)
+#endif
+
+
+
+/* Get a specific bit */
+
+#define GET_GPIO(name) \
+unsigned short get_gpio_ ## name(unsigned short gpio) \
+{ \
+	return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
+} \
+EXPORT_SYMBOL(get_gpio_ ## name);
+
+GET_GPIO(dir)
+GET_GPIO(inen)
+GET_GPIO(polar)
+GET_GPIO(edge)
+GET_GPIO(both)
+GET_GPIO(maska)
+GET_GPIO(maskb)
+
+
+#if defined(ANOMALY_05000311)
+unsigned short get_gpio_data(unsigned short gpio)
+{
+	unsigned long flags;
+	unsigned short ret;
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+	local_irq_save(flags);
+	ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
+	bfin_read_CHIPID();
+	local_irq_restore(flags);
+	return ret;
+}
+EXPORT_SYMBOL(get_gpio_data);
+#else
+GET_GPIO(data)
+#endif
+
+/*Get current PORT date (16-bit word)*/
+
+#define GET_GPIO_P(name) \
+unsigned short get_gpiop_ ## name(unsigned short gpio) \
+{ \
+	return (gpio_bankb[gpio_bank(gpio)]->name);\
+} \
+EXPORT_SYMBOL(get_gpiop_ ## name);
+
+GET_GPIO_P(dir)
+GET_GPIO_P(inen)
+GET_GPIO_P(polar)
+GET_GPIO_P(edge)
+GET_GPIO_P(both)
+GET_GPIO_P(maska)
+GET_GPIO_P(maskb)
+
+#if defined(ANOMALY_05000311)
+unsigned short get_gpiop_data(unsigned short gpio)
+{
+	unsigned long flags;
+	unsigned short ret;
+	local_irq_save(flags);
+	ret = gpio_bankb[gpio_bank(gpio)]->data;
+	bfin_read_CHIPID();
+	local_irq_restore(flags);
+	return ret;
+}
+EXPORT_SYMBOL(get_gpiop_data);
+#else
+GET_GPIO_P(data)
+#endif
+
+#ifdef CONFIG_PM
+/***********************************************************
+*
+* FUNCTIONS: Blackfin PM Setup API
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+* type -
+*	PM_WAKE_RISING
+*	PM_WAKE_FALLING
+*	PM_WAKE_HIGH
+*	PM_WAKE_LOW
+*	PM_WAKE_BOTH_EDGES
+*
+* DESCRIPTION: Blackfin PM Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
+{
+	unsigned long flags;
+
+	if ((check_gpio(gpio) < 0) || !type)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+	wakeup_flags_map[gpio] = type;
+	local_irq_restore(flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_pm_wakeup_request);
+
+void gpio_pm_wakeup_free(unsigned short gpio)
+{
+	unsigned long flags;
+
+	if (check_gpio(gpio) < 0)
+		return;
+
+	local_irq_save(flags);
+
+	wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_pm_wakeup_free);
+
+static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
+{
+	port_setup(gpio, GPIO_USAGE);
+	set_gpio_dir(gpio, 0);
+	set_gpio_inen(gpio, 1);
+
+	if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
+		set_gpio_edge(gpio, 1);
+	 else
+		set_gpio_edge(gpio, 0);
+
+	if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
+		set_gpio_both(gpio, 1);
+	else
+		set_gpio_both(gpio, 0);
+
+	if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
+		set_gpio_polar(gpio, 1);
+	else
+		set_gpio_polar(gpio, 0);
+
+	SSYNC();
+
+	return 0;
+}
+
+u32 gpio_pm_setup(void)
+{
+	u32 sic_iwr = 0;
+	u16 bank, mask, i, gpio;
+
+	for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+		mask = wakeup_map[gpio_bank(i)];
+		bank = gpio_bank(i);
+
+		gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb;
+		gpio_bankb[bank]->maskb = 0;
+
+		if (mask) {
+#ifdef BF537_FAMILY
+			gpio_bank_saved[bank].fer   = *port_fer[bank];
+#endif
+			gpio_bank_saved[bank].inen  = gpio_bankb[bank]->inen;
+			gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
+			gpio_bank_saved[bank].dir   = gpio_bankb[bank]->dir;
+			gpio_bank_saved[bank].edge  = gpio_bankb[bank]->edge;
+			gpio_bank_saved[bank].both  = gpio_bankb[bank]->both;
+
+			gpio = i;
+
+			while (mask) {
+				if (mask & 1) {
+					bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]);
+					set_gpio_data(gpio, 0); /*Clear*/
+				}
+				gpio++;
+				mask >>= 1;
+			}
+
+			sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
+			gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
+		}
+	}
+
+	if (sic_iwr)
+		return sic_iwr;
+	else
+		return IWR_ENABLE_ALL;
+}
+
+
+void gpio_pm_restore(void)
+{
+	u16 bank, mask, i;
+
+	for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+		mask = wakeup_map[gpio_bank(i)];
+		bank = gpio_bank(i);
+
+		if (mask) {
+#ifdef BF537_FAMILY
+			*port_fer[bank]   	= gpio_bank_saved[bank].fer;
+#endif
+			gpio_bankb[bank]->inen  = gpio_bank_saved[bank].inen;
+			gpio_bankb[bank]->dir   = gpio_bank_saved[bank].dir;
+			gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
+			gpio_bankb[bank]->edge  = gpio_bank_saved[bank].edge;
+			gpio_bankb[bank]->both  = gpio_bank_saved[bank].both;
+		}
+
+		gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
+	}
+}
+
+#endif
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: Blackfin GPIO Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+int gpio_request(unsigned short gpio, const char *label)
+{
+	unsigned long flags;
+
+	if (check_gpio(gpio) < 0)
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
+		dump_stack();
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+	reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+	local_irq_restore(flags);
+
+	port_setup(gpio, GPIO_USAGE);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+
+void gpio_free(unsigned short gpio)
+{
+	unsigned long flags;
+
+	if (check_gpio(gpio) < 0)
+		return;
+
+	local_irq_save(flags);
+
+	if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+		printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
+		dump_stack();
+		local_irq_restore(flags);
+		return;
+	}
+
+	default_gpio(gpio);
+
+	reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_free);
+
+
+void gpio_direction_input(unsigned short gpio)
+{
+	unsigned long flags;
+
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+	local_irq_save(flags);
+	gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
+	gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+void gpio_direction_output(unsigned short gpio)
+{
+	unsigned long flags;
+
+	BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+	local_irq_save(flags);
+	gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
+	gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_output);
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
new file mode 100644
index 0000000..f64ecb6
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -0,0 +1,119 @@
+/*
+ * File:         arch/blackfin/kernel/bfin_ksyms.c
+ * Based on:     none - original work
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <asm/irq.h>
+#include <asm/checksum.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+
+/* platform dependent support */
+
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(dump_thread);
+
+EXPORT_SYMBOL(ip_fast_csum);
+
+EXPORT_SYMBOL(kernel_thread);
+
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(is_in_rom);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy);
+
+/* The following are special because they're not called
+ * explicitly (the C compiler generates them).  Fortunately,
+ * their interface isn't gonna change any time soon now, so
+ * it's OK to leave it out of version control.
+ */
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(get_wchan);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __smulsi3_highpart(void);
+extern void __umulsi3_highpart(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+
+/* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__umulsi3_highpart);
+EXPORT_SYMBOL(__smulsi3_highpart);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(irq_flags);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
+EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
+EXPORT_SYMBOL(blackfin_icache_flush_range);
+EXPORT_SYMBOL(blackfin_dcache_flush_range);
+EXPORT_SYMBOL(blackfin_dflush_page);
+
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(__init_begin);
+EXPORT_SYMBOL(__init_end);
+EXPORT_SYMBOL(_ebss_l1);
+EXPORT_SYMBOL(_stext_l1);
+EXPORT_SYMBOL(_etext_l1);
+EXPORT_SYMBOL(_sdata_l1);
+EXPORT_SYMBOL(_ebss_b_l1);
+EXPORT_SYMBOL(_sdata_b_l1);
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
new file mode 100644
index 0000000..539eb24
--- /dev/null
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -0,0 +1,183 @@
+/*
+ * File:         arch/blackfin/kernel/dma-mapping.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  Dynamic DMA mapping support.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/bfin-global.h>
+
+static spinlock_t dma_page_lock;
+static unsigned int *dma_page;
+static unsigned int dma_pages;
+static unsigned long dma_base;
+static unsigned long dma_size;
+static unsigned int dma_initialized;
+
+void dma_alloc_init(unsigned long start, unsigned long end)
+{
+	spin_lock_init(&dma_page_lock);
+	dma_initialized = 0;
+
+	dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
+	memset(dma_page, 0, PAGE_SIZE);
+	dma_base = PAGE_ALIGN(start);
+	dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
+	dma_pages = dma_size >> PAGE_SHIFT;
+	memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
+	dma_initialized = 1;
+
+	printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
+	       dma_page, dma_pages, dma_base);
+}
+
+static inline unsigned int get_pages(size_t size)
+{
+	return ((size - 1) >> PAGE_SHIFT) + 1;
+}
+
+static unsigned long __alloc_dma_pages(unsigned int pages)
+{
+	unsigned long ret = 0, flags;
+	int i, count = 0;
+
+	if (dma_initialized == 0)
+		dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
+
+	spin_lock_irqsave(&dma_page_lock, flags);
+
+	for (i = 0; i < dma_pages;) {
+		if (dma_page[i++] == 0) {
+			if (++count == pages) {
+				while (count--)
+					dma_page[--i] = 1;
+				ret = dma_base + (i << PAGE_SHIFT);
+				break;
+			}
+		} else
+			count = 0;
+	}
+	spin_unlock_irqrestore(&dma_page_lock, flags);
+	return ret;
+}
+
+static void __free_dma_pages(unsigned long addr, unsigned int pages)
+{
+	unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
+	unsigned long flags;
+	int i;
+
+	if ((page + pages) > dma_pages) {
+		printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
+		BUG();
+	}
+
+	spin_lock_irqsave(&dma_page_lock, flags);
+	for (i = page; i < page + pages; i++) {
+		dma_page[i] = 0;
+	}
+	spin_unlock_irqrestore(&dma_page_lock, flags);
+}
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+			 dma_addr_t * dma_handle, gfp_t gfp)
+{
+	void *ret;
+
+	ret = (void *)__alloc_dma_pages(get_pages(size));
+
+	if (ret) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_phys(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)
+{
+	__free_dma_pages((unsigned long)vaddr, get_pages(size));
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+/*
+ * Dummy functions defined for some existing drivers
+ */
+
+dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+	       enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+
+	invalidate_dcache_range((unsigned long)ptr,
+			(unsigned long)ptr + size);
+
+	return (dma_addr_t) ptr;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+	   enum dma_data_direction direction)
+{
+	int i;
+
+	BUG_ON(direction == DMA_NONE);
+
+	for (i = 0; i < nents; i++)
+		invalidate_dcache_range(sg_dma_address(&sg[i]),
+					sg_dma_address(&sg[i]) +
+					sg_dma_len(&sg[i]));
+
+	return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+		enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+		int nhwentries, enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/blackfin/kernel/dualcore_test.c b/arch/blackfin/kernel/dualcore_test.c
new file mode 100644
index 0000000..8b89c99
--- /dev/null
+++ b/arch/blackfin/kernel/dualcore_test.c
@@ -0,0 +1,49 @@
+/*
+ * File:         arch/blackfin/kernel/dualcore_test.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  Small test code for CoreB on a BF561
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+static int *testarg = (int*)0xfeb00000;
+
+static int test_init(void)
+{
+	*testarg = 1;
+	printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
+	       *testarg, testarg);
+	return 0;
+}
+
+static void test_exit(void)
+{
+	printk("Dual core test module removed: testarg = [%d]\n", *testarg);
+}
+
+module_init(test_init);
+module_exit(test_exit);
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
new file mode 100644
index 0000000..5880b27
--- /dev/null
+++ b/arch/blackfin/kernel/entry.S
@@ -0,0 +1,94 @@
+/*
+ * File:         arch/blackfin/kernel/entry.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+ENTRY(_ret_from_fork)
+	SP += -12;
+	call _schedule_tail;
+	SP += 12;
+	r0 = [sp + PT_IPEND];
+	cc = bittst(r0,1);
+	if cc jump .Lin_kernel;
+	RESTORE_CONTEXT
+	rti;
+.Lin_kernel:
+	bitclr(r0,1);
+	[sp + PT_IPEND] = r0;
+	/* do a 'fake' RTI by jumping to [RETI]
+	 * to avoid clearing supervisor mode in child
+	*/
+	RESTORE_ALL_SYS
+	p0 = reti;
+	jump (p0);
+
+ENTRY(_sys_fork)
+	r0 = -EINVAL;
+	rts;
+
+ENTRY(_sys_vfork)
+	r0 = sp;
+	r0 += 24;
+	[--sp] = rets;
+	SP += -12;
+	call _bfin_vfork;
+	SP += 12;
+	rets = [sp++];
+	rts;
+
+ENTRY(_sys_clone)
+	r0 = sp;
+	r0 += 24;
+	[--sp] = rets;
+	SP += -12;
+	call _bfin_clone;
+	SP += 12;
+	rets = [sp++];
+	rts;
+
+ENTRY(_sys_rt_sigreturn)
+	r0 = sp;
+	r0 += 24;
+	[--sp] = rets;
+	SP += -12;
+	call _do_rt_sigreturn;
+	SP += 12;
+	rets = [sp++];
+	rts;
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
new file mode 100644
index 0000000..a92587b
--- /dev/null
+++ b/arch/blackfin/kernel/flat.c
@@ -0,0 +1,101 @@
+/*
+ *  arch/blackfin/kernel/flat.c
+ *
+ *  Copyright (C) 2007 Analog Devices, 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/module.h>
+#include <linux/sched.h>
+#include <linux/flat.h>
+
+#define FLAT_BFIN_RELOC_TYPE_16_BIT 0
+#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
+#define FLAT_BFIN_RELOC_TYPE_32_BIT 2
+
+unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
+		unsigned long relval,
+		unsigned long flags,
+		unsigned long *persistent)
+{
+	unsigned short *usptr = (unsigned short *)ptr;
+	int type = (relval >> 26) & 7;
+	unsigned long val;
+
+	switch (type) {
+		case FLAT_BFIN_RELOC_TYPE_16_BIT:
+		case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+			usptr = (unsigned short *)ptr;
+			pr_debug("*usptr = %x", get_unaligned(usptr));
+			val = get_unaligned(usptr);
+			val += *persistent;
+			break;
+
+		case FLAT_BFIN_RELOC_TYPE_32_BIT:
+			pr_debug("*ptr = %lx", get_unaligned(ptr));
+			val = get_unaligned(ptr);
+			break;
+
+		default:
+			pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
+				type);
+
+			return 0;
+	}
+
+	/*
+	 * Stack-relative relocs contain the offset into the stack, we
+	 * have to add the stack's start address here and return 1 from
+	 * flat_addr_absolute to prevent the normal address calculations
+	 */
+	if (relval & (1 << 29))
+		return val + current->mm->context.end_brk;
+
+	if ((flags & FLAT_FLAG_GOTPIC) == 0)
+		val = htonl(val);
+	return val;
+}
+EXPORT_SYMBOL(bfin_get_addr_from_rp);
+
+/*
+ * Insert the address ADDR into the symbol reference at RP;
+ * RELVAL is the raw relocation-table entry from which RP is derived
+ */
+void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
+		unsigned long relval)
+{
+	unsigned short *usptr = (unsigned short *)ptr;
+	int type = (relval >> 26) & 7;
+
+	switch (type) {
+		case FLAT_BFIN_RELOC_TYPE_16_BIT:
+			put_unaligned(addr, usptr);
+			pr_debug("new value %x at %p", get_unaligned(usptr),
+				usptr);
+			break;
+
+		case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+			put_unaligned(addr >> 16, usptr);
+			pr_debug("new value %x", get_unaligned(usptr));
+			break;
+
+		case FLAT_BFIN_RELOC_TYPE_32_BIT:
+			put_unaligned(addr, ptr);
+			pr_debug("new ptr =%lx", get_unaligned(ptr));
+			break;
+	}
+}
+EXPORT_SYMBOL(bfin_put_addr_at_rp);
diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c
new file mode 100644
index 0000000..b45188f
--- /dev/null
+++ b/arch/blackfin/kernel/init_task.c
@@ -0,0 +1,60 @@
+/*
+ * File:         arch/blackfin/kernel/init_task.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.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 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);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry.
+ */
+union thread_union init_thread_union
+    __attribute__ ((__section__(".data.init_task"))) = {
+INIT_THREAD_INFO(init_task)};
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
new file mode 100644
index 0000000..df5bf02
--- /dev/null
+++ b/arch/blackfin/kernel/irqchip.c
@@ -0,0 +1,147 @@
+/*
+ * File:         arch/blackfin/kernel/irqchip.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+static unsigned long irq_err_count;
+static spinlock_t irq_controller_lock;
+
+/*
+ * Dummy mask/unmask handler
+ */
+void dummy_mask_unmask_irq(unsigned int irq)
+{
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+	irq_err_count += 1;
+	printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
+}
+EXPORT_SYMBOL(ack_bad_irq);
+
+static struct irq_chip bad_chip = {
+	.ack = dummy_mask_unmask_irq,
+	.mask = dummy_mask_unmask_irq,
+	.unmask = dummy_mask_unmask_irq,
+};
+
+static struct irq_desc bad_irq_desc = {
+	.chip = &bad_chip,
+	.handle_irq = handle_bad_irq,
+	.depth = 1,
+};
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v;
+	struct irqaction *action;
+	unsigned long flags;
+
+	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: %10u ", i, kstat_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);
+	} else if (i == NR_IRQS) {
+		seq_printf(p, "Err: %10lu\n", irq_err_count);
+	}
+	return 0;
+}
+
+/*
+ * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
+ * come via this function.  Instead, they should provide their
+ * own 'handler'
+ */
+
+#ifdef CONFIG_DO_IRQ_L1
+asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text));
+#endif
+
+asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+{
+	struct pt_regs *old_regs;
+	struct irq_desc *desc = irq_desc + irq;
+	unsigned short pending, other_ints;
+
+	old_regs = set_irq_regs(regs);
+
+	/*
+	 * Some hardware gives randomly wrong interrupts.  Rather
+	 * than crashing, do something sensible.
+	 */
+	if (irq >= NR_IRQS)
+		desc = &bad_irq_desc;
+
+	irq_enter();
+
+	generic_handle_irq(irq);
+
+	/* If we're the only interrupt running (ignoring IRQ15 which is for
+	   syscalls), lower our priority to IRQ14 so that softirqs run at
+	   that level.  If there's another, lower-level interrupt, irq_exit
+	   will defer softirqs to that.  */
+	CSYNC();
+	pending = bfin_read_IPEND() & ~0x8000;
+	other_ints = pending & (pending - 1);
+	if (other_ints == 0)
+		lower_to_irq14();
+	irq_exit();
+
+	set_irq_regs(old_regs);
+}
+
+void __init init_IRQ(void)
+{
+	struct irq_desc *desc;
+	int irq;
+
+	spin_lock_init(&irq_controller_lock);
+	for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
+		*desc = bad_irq_desc;
+	}
+
+	init_arch_irq();
+}
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
new file mode 100644
index 0000000..372f756
--- /dev/null
+++ b/arch/blackfin/kernel/module.c
@@ -0,0 +1,429 @@
+/*
+ * File:         arch/blackfin/kernel/module.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+/*
+ * handle arithmetic relocations.
+ * See binutils/bfd/elf32-bfin.c for more details
+ */
+#define RELOC_STACK_SIZE 100
+static uint32_t reloc_stack[RELOC_STACK_SIZE];
+static unsigned int reloc_stack_tos;
+
+#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
+
+static void reloc_stack_push(uint32_t value)
+{
+	reloc_stack[reloc_stack_tos++] = value;
+}
+
+static uint32_t reloc_stack_pop(void)
+{
+	return reloc_stack[--reloc_stack_tos];
+}
+
+static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
+{
+	uint32_t value;
+
+	switch (oper) {
+	case R_add:
+		value = reloc_stack[reloc_stack_tos - 2] +
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_sub:
+		value = reloc_stack[reloc_stack_tos - 2] -
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_mult:
+		value = reloc_stack[reloc_stack_tos - 2] *
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_div:
+		value = reloc_stack[reloc_stack_tos - 2] /
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_mod:
+		value = reloc_stack[reloc_stack_tos - 2] %
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_lshift:
+		value = reloc_stack[reloc_stack_tos - 2] <<
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_rshift:
+		value = reloc_stack[reloc_stack_tos - 2] >>
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_and:
+		value = reloc_stack[reloc_stack_tos - 2] &
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_or:
+		value = reloc_stack[reloc_stack_tos - 2] |
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_xor:
+		value = reloc_stack[reloc_stack_tos - 2] ^
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_land:
+		value = reloc_stack[reloc_stack_tos - 2] &&
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_lor:
+		value = reloc_stack[reloc_stack_tos - 2] ||
+			reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 2;
+		break;
+	case R_neg:
+		value = -reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos--;
+		break;
+	case R_comp:
+		value = ~reloc_stack[reloc_stack_tos - 1];
+		reloc_stack_tos -= 1;
+		break;
+	default:
+		printk(KERN_WARNING "module %s: unhandled reloction\n",
+				mod->name);
+		return 0;
+	}
+
+	/* now push the new value back on stack */
+	reloc_stack_push(value);
+
+	return value;
+}
+
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc(size);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+}
+
+/* Transfer the section to the L1 memory */
+int
+module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
+			  char *secstrings, struct module *mod)
+{
+	Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+	void *dest = NULL;
+
+	for (s = sechdrs; s < sechdrs_end; ++s) {
+		if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
+			((strcmp(".text", secstrings + s->sh_name)==0) &&
+			 (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
+			mod->arch.text_l1 = s;
+			dest = l1_inst_sram_alloc(s->sh_size);
+			if (dest == NULL) {
+				printk(KERN_ERR
+				       "module %s: L1 instruction memory allocation failed\n",
+				       mod->name);
+				return -1;
+			}
+			dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
+			s->sh_flags &= ~SHF_ALLOC;
+			s->sh_addr = (unsigned long)dest;
+		}
+		if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
+			((strcmp(".data", secstrings + s->sh_name)==0) &&
+			 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+			mod->arch.data_a_l1 = s;
+			dest = l1_data_sram_alloc(s->sh_size);
+			if (dest == NULL) {
+				printk(KERN_ERR
+					"module %s: L1 data memory allocation failed\n",
+					mod->name);
+				return -1;
+			}
+			memcpy(dest, (void *)s->sh_addr, s->sh_size);
+			s->sh_flags &= ~SHF_ALLOC;
+			s->sh_addr = (unsigned long)dest;
+		}
+		if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
+			((strcmp(".bss", secstrings + s->sh_name)==0) &&
+			 (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+			mod->arch.bss_a_l1 = s;
+			dest = l1_data_sram_alloc(s->sh_size);
+			if (dest == NULL) {
+				printk(KERN_ERR
+					"module %s: L1 data memory allocation failed\n",
+					mod->name);
+				return -1;
+			}
+			memset(dest, 0, s->sh_size);
+			s->sh_flags &= ~SHF_ALLOC;
+			s->sh_addr = (unsigned long)dest;
+		}
+		if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
+			mod->arch.data_b_l1 = s;
+			dest = l1_data_B_sram_alloc(s->sh_size);
+			if (dest == NULL) {
+				printk(KERN_ERR
+					"module %s: L1 data memory allocation failed\n",
+					mod->name);
+				return -1;
+			}
+			memcpy(dest, (void *)s->sh_addr, s->sh_size);
+			s->sh_flags &= ~SHF_ALLOC;
+			s->sh_addr = (unsigned long)dest;
+		}
+		if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
+			mod->arch.bss_b_l1 = s;
+			dest = l1_data_B_sram_alloc(s->sh_size);
+			if (dest == NULL) {
+				printk(KERN_ERR
+					"module %s: L1 data memory allocation failed\n",
+					mod->name);
+				return -1;
+			}
+			memset(dest, 0, s->sh_size);
+			s->sh_flags &= ~SHF_ALLOC;
+			s->sh_addr = (unsigned long)dest;
+		}
+	}
+	return 0;
+}
+
+int
+apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
+	       unsigned int symindex, unsigned int relsec, struct module *me)
+{
+	printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
+	return -ENOEXEC;
+}
+
+/*************************************************************************/
+/* FUNCTION : apply_relocate_add                                         */
+/* ABSTRACT : Blackfin specific relocation handling for the loadable     */
+/*            modules. Modules are expected to be .o files.              */
+/*            Arithmetic relocations are handled.                        */
+/*            We do not expect LSETUP to be split and hence is not       */
+/*            handled.                                                   */
+/*            R_byte and R_byte2 are also not handled as the gas         */
+/*            does not generate it.                                      */
+/*************************************************************************/
+int
+apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
+		   unsigned int symindex, unsigned int relsec,
+		   struct module *mod)
+{
+	unsigned int i;
+	unsigned short tmp;
+	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	uint32_t *location32;
+	uint16_t *location16;
+	uint32_t value;
+
+	pr_debug("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location16 =
+		    (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
+				  rel[i].r_offset);
+		location32 = (uint32_t *) location16;
+		/* This is the symbol it is referring to. Note that all
+		   undefined symbols have been resolved. */
+		sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
+		    + ELF32_R_SYM(rel[i].r_info);
+		if (is_reloc_stack_empty()) {
+			value = sym->st_value;
+		} else {
+			value = reloc_stack_pop();
+		}
+		value += rel[i].r_addend;
+		pr_debug("location is %x, value is %x type is %d \n",
+			 (unsigned int) location32, value,
+			 ELF32_R_TYPE(rel[i].r_info));
+
+		switch (ELF32_R_TYPE(rel[i].r_info)) {
+
+		case R_pcrel24:
+		case R_pcrel24_jump_l:
+			/* Add the value, subtract its postition */
+			location16 =
+			    (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
+					  sh_addr + rel[i].r_offset - 2);
+			location32 = (uint32_t *) location16;
+			value -= (uint32_t) location32;
+			value >>= 1;
+			pr_debug("value is %x, before %x-%x after %x-%x\n", value,
+			       *location16, *(location16 + 1),
+			       (*location16 & 0xff00) | (value >> 16 & 0x00ff),
+			       value & 0xffff);
+			*location16 =
+			    (*location16 & 0xff00) | (value >> 16 & 0x00ff);
+			*(location16 + 1) = value & 0xffff;
+			break;
+		case R_pcrel12_jump:
+		case R_pcrel12_jump_s:
+			value -= (uint32_t) location32;
+			value >>= 1;
+			*location16 = (value & 0xfff);
+			break;
+		case R_pcrel10:
+			value -= (uint32_t) location32;
+			value >>= 1;
+			*location16 = (value & 0x3ff);
+			break;
+		case R_luimm16:
+			pr_debug("before %x after %x\n", *location16,
+				       (value & 0xffff));
+			tmp = (value & 0xffff);
+			if((unsigned long)location16 >= L1_CODE_START) {
+				dma_memcpy(location16, &tmp, 2);
+			} else
+				*location16 = tmp;
+			break;
+		case R_huimm16:
+			pr_debug("before %x after %x\n", *location16,
+				       ((value >> 16) & 0xffff));
+			tmp = ((value >> 16) & 0xffff);
+			if((unsigned long)location16 >= L1_CODE_START) {
+				dma_memcpy(location16, &tmp, 2);
+			} else
+				*location16 = tmp;
+			break;
+		case R_rimm16:
+			*location16 = (value & 0xffff);
+			break;
+		case R_byte4_data:
+			pr_debug("before %x after %x\n", *location32, value);
+			*location32 = value;
+			break;
+		case R_push:
+			reloc_stack_push(value);
+			break;
+		case R_const:
+			reloc_stack_push(rel[i].r_addend);
+			break;
+		case R_add:
+		case R_sub:
+		case R_mult:
+		case R_div:
+		case R_mod:
+		case R_lshift:
+		case R_rshift:
+		case R_and:
+		case R_or:
+		case R_xor:
+		case R_land:
+		case R_lor:
+		case R_neg:
+		case R_comp:
+			reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
+			break;
+		default:
+			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+			       mod->name, ELF32_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+	return 0;
+}
+
+int
+module_finalize(const Elf_Ehdr * hdr,
+		const Elf_Shdr * sechdrs, struct module *mod)
+{
+	unsigned int i, strindex = 0, symindex = 0;
+	char *secstrings;
+
+	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+	for (i = 1; i < hdr->e_shnum; i++) {
+		/* Internal symbols and strings. */
+		if (sechdrs[i].sh_type == SHT_SYMTAB) {
+			symindex = i;
+			strindex = sechdrs[i].sh_link;
+		}
+	}
+
+	for (i = 1; i < hdr->e_shnum; i++) {
+		const char *strtab = (char *)sechdrs[strindex].sh_addr;
+		unsigned int info = sechdrs[i].sh_info;
+
+		/* Not a valid relocation section? */
+		if (info >= hdr->e_shnum)
+			continue;
+
+		if ((sechdrs[i].sh_type == SHT_RELA) &&
+		    ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
+			((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
+			 (hdr->e_flags & FLG_CODE_IN_L1)))) {
+			apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
+					   symindex, i, mod);
+		}
+	}
+	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+	if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
+		l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
+	if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
+		l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
+	if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
+		l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
+	if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
+		l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
+	if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
+		l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
+}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
new file mode 100644
index 0000000..3eff743
--- /dev/null
+++ b/arch/blackfin/kernel/process.c
@@ -0,0 +1,394 @@
+/*
+ * File:         arch/blackfin/kernel/process.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  Blackfin architecture-dependent process handling.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/unistd.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define	LED_ON	0
+#define	LED_OFF	1
+
+asmlinkage void ret_from_fork(void);
+
+/* Points to the SDRAM backup memory for the stack that is currently in
+ * L1 scratchpad memory.
+ */
+void *current_l1_stack_save;
+
+/* The number of tasks currently using a L1 stack area.  The SRAM is
+ * allocated/deallocated whenever this changes from/to zero.
+ */
+int nr_l1stack_tasks;
+
+/* Start and length of the area in L1 scratchpad memory which we've allocated
+ * for process stacks.
+ */
+void *l1_stack_base;
+unsigned long l1_stack_len;
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void) = NULL;
+EXPORT_SYMBOL(pm_idle);
+
+void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
+
+/*
+ * We are using a different LED from the one used to indicate timer interrupt.
+ */
+#if defined(CONFIG_BFIN_IDLE_LED)
+static inline void leds_switch(int flag)
+{
+	unsigned short tmp = 0;
+
+	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+	SSYNC();
+
+	if (flag == LED_ON)
+		tmp &= ~CONFIG_BFIN_IDLE_LED_PIN;	/* light on */
+	else
+		tmp |= CONFIG_BFIN_IDLE_LED_PIN;	/* light off */
+
+	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
+	SSYNC();
+
+}
+#else
+static inline void leds_switch(int flag)
+{
+}
+#endif
+
+/*
+ * The idle loop on BFIN
+ */
+#ifdef CONFIG_IDLE_L1
+void default_idle(void)__attribute__((l1_text));
+void cpu_idle(void)__attribute__((l1_text));
+#endif
+
+void default_idle(void)
+{
+	while (!need_resched()) {
+		leds_switch(LED_OFF);
+		local_irq_disable();
+		if (likely(!need_resched()))
+			idle_with_irq_disabled();
+		local_irq_enable();
+		leds_switch(LED_ON);
+	}
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	while (1) {
+		idle();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
+}
+
+void machine_restart(char *__unused)
+{
+#if defined(CONFIG_BLKFIN_CACHE)
+	bfin_write_IMEM_CONTROL(0x01);
+	SSYNC();
+#endif
+	bfin_reset();
+	/* Dont do anything till the reset occurs */
+	while (1) {
+		SSYNC();
+	}
+}
+
+void machine_halt(void)
+{
+	for (;;)
+		asm volatile ("idle");
+}
+
+void machine_power_off(void)
+{
+	for (;;)
+		asm volatile ("idle");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	printk(KERN_NOTICE "\n");
+	printk(KERN_NOTICE
+	       "PC: %08lu  Status: %04lu  SysStatus: %04lu  RETS: %08lu\n",
+	       regs->pc, regs->astat, regs->seqstat, regs->rets);
+	printk(KERN_NOTICE
+	       "A0.x: %08lx  A0.w: %08lx  A1.x: %08lx  A1.w: %08lx\n",
+	       regs->a0x, regs->a0w, regs->a1x, regs->a1w);
+	printk(KERN_NOTICE "P0: %08lx  P1: %08lx  P2: %08lx  P3: %08lx\n",
+	       regs->p0, regs->p1, regs->p2, regs->p3);
+	printk(KERN_NOTICE "P4: %08lx  P5: %08lx\n", regs->p4, regs->p5);
+	printk(KERN_NOTICE "R0: %08lx  R1: %08lx  R2: %08lx  R3: %08lx\n",
+	       regs->r0, regs->r1, regs->r2, regs->r3);
+	printk(KERN_NOTICE "R4: %08lx  R5: %08lx  R6: %08lx  R7: %08lx\n",
+	       regs->r4, regs->r5, regs->r6, regs->r7);
+
+	if (!(regs->ipend))
+		printk("USP: %08lx\n", rdusp());
+}
+
+/* Fill in the fpu structure for a core dump.  */
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
+{
+	return 1;
+}
+
+/*
+ * This gets run with P1 containing the
+ * function to call, and R1 containing
+ * the "args".  Note P0 is clobbered on the way here.
+ */
+void kernel_thread_helper(void);
+__asm__(".section .text\n"
+	".align 4\n"
+	"_kernel_thread_helper:\n\t"
+	"\tsp += -12;\n\t"
+	"\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
+
+/*
+ * Create a kernel thread.
+ */
+pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+	regs.r1 = (unsigned long)arg;
+	regs.p1 = (unsigned long)fn;
+	regs.pc = (unsigned long)kernel_thread_helper;
+	regs.orig_p0 = -1;
+	/* Set bit 2 to tell ret_from_fork we should be returning to kernel
+	   mode.  */
+	regs.ipend = 0x8002;
+	__asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
+	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
+		       NULL);
+}
+
+void flush_thread(void)
+{
+}
+
+asmlinkage int bfin_vfork(struct pt_regs *regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
+		       NULL);
+}
+
+asmlinkage int bfin_clone(struct pt_regs *regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+
+	/* syscall2 puts clone_flags in r0 and usp in r1 */
+	clone_flags = regs->r0;
+	newsp = regs->r1;
+	if (!newsp)
+		newsp = rdusp();
+	else
+		newsp -= 12;
+	return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
+}
+
+int
+copy_thread(int nr, unsigned long clone_flags,
+	    unsigned long usp, unsigned long topstk,
+	    struct task_struct *p, struct pt_regs *regs)
+{
+	struct pt_regs *childregs;
+
+	childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+	*childregs = *regs;
+	childregs->r0 = 0;
+
+	p->thread.usp = usp;
+	p->thread.ksp = (unsigned long)childregs;
+	p->thread.pc = (unsigned long)ret_from_fork;
+
+	return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs *regs, struct user *dump)
+{
+	dump->magic = CMAGIC;
+	dump->start_code = 0;
+	dump->start_stack = rdusp() & ~(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;
+
+	if (dump->start_stack < TASK_SIZE)
+		dump->u_ssize =
+		    ((unsigned long)(TASK_SIZE -
+				     dump->start_stack)) >> PAGE_SHIFT;
+
+	dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
+
+	dump->regs.r0 = regs->r0;
+	dump->regs.r1 = regs->r1;
+	dump->regs.r2 = regs->r2;
+	dump->regs.r3 = regs->r3;
+	dump->regs.r4 = regs->r4;
+	dump->regs.r5 = regs->r5;
+	dump->regs.r6 = regs->r6;
+	dump->regs.r7 = regs->r7;
+	dump->regs.p0 = regs->p0;
+	dump->regs.p1 = regs->p1;
+	dump->regs.p2 = regs->p2;
+	dump->regs.p3 = regs->p3;
+	dump->regs.p4 = regs->p4;
+	dump->regs.p5 = regs->p5;
+	dump->regs.orig_p0 = regs->orig_p0;
+	dump->regs.a0w = regs->a0w;
+	dump->regs.a1w = regs->a1w;
+	dump->regs.a0x = regs->a0x;
+	dump->regs.a1x = regs->a1x;
+	dump->regs.rets = regs->rets;
+	dump->regs.astat = regs->astat;
+	dump->regs.pc = regs->pc;
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+asmlinkage int sys_execve(char *name, char **argv, char **envp)
+{
+	int error;
+	char *filename;
+	struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
+
+	lock_kernel();
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+      out:
+	unlock_kernel();
+	return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long fp, pc;
+	unsigned long stack_page;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	stack_page = (unsigned long)p;
+	fp = p->thread.usp;
+	do {
+		if (fp < stack_page + sizeof(struct thread_info) ||
+		    fp >= 8184 + stack_page)
+			return 0;
+		pc = ((unsigned long *)fp)[1];
+		if (!in_sched_functions(pc))
+			return pc;
+		fp = *(unsigned long *)fp;
+	}
+	while (count++ < 16);
+	return 0;
+}
+
+#if defined(CONFIG_ACCESS_CHECK)
+int _access_ok(unsigned long addr, unsigned long size)
+{
+
+	if (addr > (addr + size))
+		return 0;
+	if (segment_eq(get_fs(),KERNEL_DS))
+		return 1;
+#ifdef CONFIG_MTD_UCLINUX
+	if (addr >= memory_start && (addr + size) <= memory_end)
+		return 1;
+	if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
+		return 1;
+#else
+	if (addr >= memory_start && (addr + size) <= physical_mem_end)
+		return 1;
+#endif
+	if (addr >= (unsigned long)__init_begin &&
+	    addr + size <= (unsigned long)__init_end)
+		return 1;
+	if (addr >= L1_SCRATCH_START
+	    && addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)
+		return 1;
+#if L1_CODE_LENGTH != 0
+	if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1)
+	    && addr + size <= L1_CODE_START + L1_CODE_LENGTH)
+		return 1;
+#endif
+#if L1_DATA_A_LENGTH != 0
+	if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1)
+	    && addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)
+		return 1;
+#endif
+#if L1_DATA_B_LENGTH != 0
+	if (addr >= L1_DATA_B_START
+	    && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
+		return 1;
+#endif
+	return 0;
+}
+EXPORT_SYMBOL(_access_ok);
+#endif /* CONFIG_ACCESS_CHECK */
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
new file mode 100644
index 0000000..d7c8e51
--- /dev/null
+++ b/arch/blackfin/kernel/ptrace.c
@@ -0,0 +1,430 @@
+/*
+ * File:         arch/blackfin/kernel/ptrace.c
+ * Based on:     Taken from linux/kernel/ptrace.c
+ * Author:       linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Created:      1/23/92
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <asm/dma.h>
+
+#define MAX_SHARED_LIBS 3
+#define TEXT_OFFSET 0
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SYSCFG reg the user has access to. */
+/* 1 = access 0 = no access */
+#define SYSCFG_MASK 0x0007	/* SYSCFG reg */
+/* sets the trace bits. */
+#define TRACE_BITS 0x0001
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+static inline struct pt_regs *get_user_regs(struct task_struct *task)
+{
+	return (struct pt_regs *)
+	    ((unsigned long)task->thread_info +
+	     (THREAD_SIZE - sizeof(struct pt_regs)));
+}
+
+/*
+ * Get all user integer registers.
+ */
+static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
+{
+	struct pt_regs *regs = get_user_regs(tsk);
+	return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ * saved.  Notice that usp has no stack-slot and needs to be treated
+ * specially (see get_reg/put_reg below).
+ */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+	unsigned char *reg_ptr;
+
+	struct pt_regs *regs =
+	    (struct pt_regs *)((unsigned long)task->thread_info +
+			       (THREAD_SIZE - sizeof(struct pt_regs)));
+	reg_ptr = (char *)regs;
+
+	switch (regno) {
+	case PT_USP:
+		return task->thread.usp;
+	default:
+		if (regno <= 216)
+			return *(long *)(reg_ptr + regno);
+	}
+	/* slight mystery ... never seems to come here but kernel misbehaves without this code! */
+
+	printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
+	return 0;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int
+put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+	char * reg_ptr;
+
+	struct pt_regs *regs =
+	    (struct pt_regs *)((unsigned long)task->thread_info +
+			       (THREAD_SIZE - sizeof(struct pt_regs)));
+	reg_ptr = (char *)regs;
+
+	switch (regno) {
+	case PT_PC:
+		/*********************************************************************/
+		/* At this point the kernel is most likely in exception.             */
+		/* The RETX register will be used to populate the pc of the process. */
+		/*********************************************************************/
+		regs->retx = data;
+		regs->pc = data;
+		break;
+	case PT_RETX:
+		break;		/* regs->retx = data; break; */
+	case PT_USP:
+		regs->usp = data;
+		task->thread.usp = data;
+		break;
+	default:
+		if (regno <= 216)
+		        *(long *)(reg_ptr + regno) = data;
+	}
+	return 0;
+}
+
+/*
+ * check that an address falls within the bounds of the target process's memory mappings
+ */
+static inline int is_user_addr_valid(struct task_struct *child,
+				     unsigned long start, unsigned long len)
+{
+	struct vm_list_struct *vml;
+	struct sram_list_struct *sraml;
+
+	for (vml = child->mm->context.vmlist; vml; vml = vml->next)
+		if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
+			return 0;
+
+	for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
+		if (start >= (unsigned long)sraml->addr
+		    && start + len <= (unsigned long)sraml->addr + sraml->length)
+			return 0;
+
+	return -EIO;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	unsigned long tmp;
+	/* make sure the single step bit is not set. */
+	tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+	put_reg(child, PT_SR, tmp);
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+	int ret;
+	int add = 0;
+
+	switch (request) {
+		/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKDATA:
+		pr_debug("ptrace: PEEKDATA\n");
+		add = MAX_SHARED_LIBS * 4;	/* space between text and data */
+		/* fall through */
+	case PTRACE_PEEKTEXT:	/* read word at location addr. */
+		{
+			unsigned long tmp = 0;
+			int copied;
+
+			ret = -EIO;
+			pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
+			         sizeof(data));
+			if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
+				break;
+			pr_debug("ptrace: user address is valid\n");
+
+#if L1_CODE_LENGTH != 0
+			if (addr + add >= L1_CODE_START
+			    && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
+				safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
+				copied = sizeof(tmp);
+			} else
+#endif
+			copied =
+			    access_process_vm(child, addr + add, &tmp,
+					      sizeof(tmp), 0);
+			pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
+			if (copied != sizeof(tmp))
+				break;
+			ret = put_user(tmp, (unsigned long *)data);
+			break;
+		}
+
+		/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR:
+		{
+			unsigned long tmp;
+			ret = -EIO;
+			tmp = 0;
+			if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
+				printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
+				                    "0 - %x sizeof(pt_regs) is %lx\n",
+				     (int)addr, sizeof(struct pt_regs));
+				break;
+			}
+			if (addr == sizeof(struct pt_regs)) {
+				/* PT_TEXT_ADDR */
+				tmp = child->mm->start_code + TEXT_OFFSET;
+			} else if (addr == (sizeof(struct pt_regs) + 4)) {
+				/* PT_TEXT_END_ADDR */
+				tmp = child->mm->end_code;
+			} else if (addr == (sizeof(struct pt_regs) + 8)) {
+				/* PT_DATA_ADDR */
+				tmp = child->mm->start_data;
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+			} else if (addr == (sizeof(struct pt_regs) + 12)) {
+				tmp = child->mm->context.exec_fdpic_loadmap;
+			} else if (addr == (sizeof(struct pt_regs) + 16)) {
+				tmp = child->mm->context.interp_fdpic_loadmap;
+#endif
+			} else {
+				tmp = get_reg(child, addr);
+			}
+			ret = put_user(tmp, (unsigned long *)data);
+			break;
+		}
+
+		/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKEDATA:
+		printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
+		/* fall through */
+	case PTRACE_POKETEXT:	/* write the word at location addr. */
+		{
+			int copied;
+
+			ret = -EIO;
+			pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
+			         addr, add, sizeof(data), data);
+			if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
+				break;
+			pr_debug("ptrace: user address is valid\n");
+
+#if L1_CODE_LENGTH != 0
+			if (addr + add >= L1_CODE_START
+			    && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
+				safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
+				copied = sizeof(data);
+			} else
+#endif
+			copied =
+			    access_process_vm(child, addr + add, &data,
+					      sizeof(data), 1);
+			pr_debug("ptrace: copied size %d\n", copied);
+			if (copied != sizeof(data))
+				break;
+			ret = 0;
+			break;
+		}
+
+	case PTRACE_POKEUSR:	/* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
+			printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
+			break;
+		}
+
+		if (addr >= (sizeof(struct pt_regs))) {
+			ret = 0;
+			break;
+		}
+		if (addr == PT_SYSCFG) {
+			data &= SYSCFG_MASK;
+			data |= get_reg(child, PT_SYSCFG);
+		}
+		ret = put_reg(child, addr, data);
+		break;
+
+	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
+	case PTRACE_CONT:
+		{		/* restart after signal. */
+			long tmp;
+
+			pr_debug("ptrace_cont\n");
+
+			ret = -EIO;
+			if (!valid_signal(data))
+				break;
+			if (request == PTRACE_SYSCALL)
+				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			else
+				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+			child->exit_code = data;
+			/* make sure the single step bit is not set. */
+			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
+			put_reg(child, PT_SYSCFG, tmp);
+			pr_debug("before wake_up_process\n");
+			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:
+		{
+			long tmp;
+			ret = 0;
+			if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+				break;
+			child->exit_code = SIGKILL;
+			/* make sure the single step bit is not set. */
+			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
+			put_reg(child, PT_SYSCFG, tmp);
+			wake_up_process(child);
+			break;
+		}
+
+	case PTRACE_SINGLESTEP:
+		{		/* set the trap flag. */
+			long tmp;
+
+			pr_debug("single step\n");
+			ret = -EIO;
+			if (!valid_signal(data))
+				break;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+			tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
+			put_reg(child, PT_SYSCFG, tmp);
+
+			child->exit_code = data;
+			/* give it a chance to run. */
+			wake_up_process(child);
+			ret = 0;
+			break;
+		}
+
+	case PTRACE_DETACH:
+		{		/* detach a process that was attached. */
+			ret = ptrace_detach(child, data);
+			break;
+		}
+
+	case PTRACE_GETREGS:
+		{
+
+			/* Get all gp regs from the child. */
+			ret = ptrace_getregs(child, (void __user *)data);
+			break;
+		}
+
+	case PTRACE_SETREGS:
+		{
+			printk(KERN_NOTICE
+			       "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
+			/* Set all gp regs in the child. */
+			ret = 0;
+			break;
+		}
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+	return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	 * between a syscall stop and SIGTRAP delivery
+	 */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
new file mode 100644
index 0000000..342bb8d
--- /dev/null
+++ b/arch/blackfin/kernel/setup.c
@@ -0,0 +1,902 @@
+/*
+ * File:         arch/blackfin/kernel/setup.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+
+#include <linux/ext2_fs.h>
+#include <linux/cramfs_fs.h>
+#include <linux/romfs_fs.h>
+
+#include <asm/cacheflush.h>
+#include <asm/blackfin.h>
+#include <asm/cplbinit.h>
+
+unsigned long memory_start, memory_end, physical_mem_end;
+unsigned long reserved_mem_dcache_on;
+unsigned long reserved_mem_icache_on;
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+EXPORT_SYMBOL(physical_mem_end);
+EXPORT_SYMBOL(_ramend);
+
+#ifdef CONFIG_MTD_UCLINUX
+unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
+unsigned long _ebss;
+EXPORT_SYMBOL(memory_mtd_end);
+EXPORT_SYMBOL(memory_mtd_start);
+EXPORT_SYMBOL(mtd_size);
+#endif
+
+char command_line[COMMAND_LINE_SIZE];
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+static void generate_cpl_tables(void);
+#endif
+
+void __init bf53x_cache_init(void)
+{
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+	generate_cpl_tables();
+#endif
+
+#ifdef CONFIG_BLKFIN_CACHE
+	bfin_icache_init();
+	printk(KERN_INFO "Instruction Cache Enabled\n");
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+	bfin_dcache_init();
+	printk(KERN_INFO "Data Cache Enabled"
+# if defined CONFIG_BLKFIN_WB
+		" (write-back)"
+# elif defined CONFIG_BLKFIN_WT
+		" (write-through)"
+# endif
+		"\n");
+#endif
+}
+
+void bf53x_relocate_l1_mem(void)
+{
+	unsigned long l1_code_length;
+	unsigned long l1_data_a_length;
+	unsigned long l1_data_b_length;
+
+	l1_code_length = _etext_l1 - _stext_l1;
+	if (l1_code_length > L1_CODE_LENGTH)
+		l1_code_length = L1_CODE_LENGTH;
+	/* cannot complain as printk is not available as yet.
+	 * But we can continue booting and complain later!
+	 */
+
+	/* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
+	dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+
+	l1_data_a_length = _ebss_l1 - _sdata_l1;
+	if (l1_data_a_length > L1_DATA_A_LENGTH)
+		l1_data_a_length = L1_DATA_A_LENGTH;
+
+	/* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
+	dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
+
+	l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
+	if (l1_data_b_length > L1_DATA_B_LENGTH)
+		l1_data_b_length = L1_DATA_B_LENGTH;
+
+	/* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
+	dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
+			l1_data_a_length, l1_data_b_length);
+
+}
+
+/*
+ * Initial parsing of the command line.  Currently, we support:
+ *  - Controlling the linux memory size: mem=xxx[KMG]
+ *  - Controlling the physical memory size: max_mem=xxx[KMG][$][#]
+ *       $ -> reserved memory is dcacheable
+ *       # -> reserved memory is icacheable
+ */
+static __init void parse_cmdline_early(char *cmdline_p)
+{
+	char c = ' ', *to = cmdline_p;
+	unsigned int memsize;
+	for (;;) {
+		if (c == ' ') {
+
+			if (!memcmp(to, "mem=", 4)) {
+				to += 4;
+				memsize = memparse(to, &to);
+				if (memsize)
+					_ramend = memsize;
+
+			} else if (!memcmp(to, "max_mem=", 8)) {
+				to += 8;
+				memsize = memparse(to, &to);
+				if (memsize) {
+					physical_mem_end = memsize;
+					if (*to != ' ') {
+						if (*to == '$'
+						    || *(to + 1) == '$')
+							reserved_mem_dcache_on =
+							    1;
+						if (*to == '#'
+						    || *(to + 1) == '#')
+							reserved_mem_icache_on =
+							    1;
+					}
+				}
+			}
+
+		}
+		c = *(to++);
+		if (!c)
+			break;
+	}
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	int bootmap_size;
+	unsigned long l1_length, sclk, cclk;
+#ifdef CONFIG_MTD_UCLINUX
+	unsigned long mtd_phys = 0;
+#endif
+
+	cclk = get_cclk();
+	sclk = get_sclk();
+
+#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273)
+	if (cclk == sclk)
+		panic("ANOMALY 05000273, SCLK can not be same as CCLK");
+#endif
+
+#if defined(ANOMALY_05000266)
+	bfin_read_IMDMA_D0_IRQ_STATUS();
+	bfin_read_IMDMA_D1_IRQ_STATUS();
+#endif
+
+#ifdef DEBUG_SERIAL_EARLY_INIT
+	bfin_console_init();	/* early console registration */
+	/* this give a chance to get printk() working before crash. */
+#endif
+
+#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
+	/* we need to initialize the Flashrom device here since we might
+	 * do things with flash early on in the boot
+	 */
+	flash_probe();
+#endif
+
+#if defined(CONFIG_CMDLINE_BOOL)
+	memset(command_line, 0, sizeof(command_line));
+	strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
+	command_line[sizeof(command_line) - 1] = 0;
+#endif
+
+	/* Keep a copy of command line */
+	*cmdline_p = &command_line[0];
+	memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+	boot_command_line[COMMAND_LINE_SIZE - 1] = 0;
+
+	/* setup memory defaults from the user config */
+	physical_mem_end = 0;
+	_ramend = CONFIG_MEM_SIZE * 1024 * 1024;
+
+	parse_cmdline_early(&command_line[0]);
+
+	if (physical_mem_end == 0)
+		physical_mem_end = _ramend;
+
+	/* by now the stack is part of the init task */
+	memory_end = _ramend - DMA_UNCACHED_REGION;
+
+	_ramstart = (unsigned long)__bss_stop;
+	memory_start = PAGE_ALIGN(_ramstart);
+
+#if defined(CONFIG_MTD_UCLINUX)
+	/* generic memory mapped MTD driver */
+	memory_mtd_end = memory_end;
+
+	mtd_phys = _ramstart;
+	mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
+
+# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
+	if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
+		mtd_size =
+		    PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
+# endif
+
+# if defined(CONFIG_CRAMFS)
+	if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC)
+		mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4)));
+# endif
+
+# if defined(CONFIG_ROMFS_FS)
+	if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
+	    && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
+		mtd_size =
+		    PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
+#  if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+	/* Due to a Hardware Anomaly we need to limit the size of usable
+	 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
+	 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+	 */
+#   if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
+	if (memory_end >= 56 * 1024 * 1024)
+		memory_end = 56 * 1024 * 1024;
+#   else
+	if (memory_end >= 60 * 1024 * 1024)
+		memory_end = 60 * 1024 * 1024;
+#   endif				/* CONFIG_DEBUG_HUNT_FOR_ZERO */
+#  endif				/* ANOMALY_05000263 */
+# endif				/* CONFIG_ROMFS_FS */
+
+	memory_end -= mtd_size;
+
+	if (mtd_size == 0) {
+		console_init();
+		panic("Don't boot kernel without rootfs attached.\n");
+	}
+
+	/* Relocate MTD image to the top of memory after the uncached memory area */
+	dma_memcpy((char *)memory_end, __bss_stop, mtd_size);
+
+	memory_mtd_start = memory_end;
+	_ebss = memory_mtd_start;	/* define _ebss for compatible */
+#endif				/* CONFIG_MTD_UCLINUX */
+
+#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+	/* Due to a Hardware Anomaly we need to limit the size of usable
+	 * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
+	 * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+	 */
+#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
+	if (memory_end >= 56 * 1024 * 1024)
+		memory_end = 56 * 1024 * 1024;
+#else
+	if (memory_end >= 60 * 1024 * 1024)
+		memory_end = 60 * 1024 * 1024;
+#endif				/* CONFIG_DEBUG_HUNT_FOR_ZERO */
+	printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
+#endif				/* ANOMALY_05000263 */
+
+#if !defined(CONFIG_MTD_UCLINUX)
+	memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
+#endif
+	init_mm.start_code = (unsigned long)_stext;
+	init_mm.end_code = (unsigned long)_etext;
+	init_mm.end_data = (unsigned long)_edata;
+	init_mm.brk = (unsigned long)0;
+
+	init_leds();
+
+	printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n");
+	printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
+	if (bfin_revid() != bfin_compiled_revid())
+		printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+		       bfin_compiled_revid(), bfin_revid());
+	if (bfin_revid() < SUPPORTED_REVID)
+		printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+		       CPU, bfin_revid());
+	printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
+
+	printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
+	       cclk / 1000000,  sclk / 1000000);
+
+#if defined(ANOMALY_05000273)
+	if ((cclk >> 1) <= sclk)
+		printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
+#endif
+
+	printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
+	printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
+
+	printk(KERN_INFO "Memory map:\n"
+	       KERN_INFO "  text      = 0x%p-0x%p\n"
+	       KERN_INFO "  init      = 0x%p-0x%p\n"
+	       KERN_INFO "  data      = 0x%p-0x%p\n"
+	       KERN_INFO "  stack     = 0x%p-0x%p\n"
+	       KERN_INFO "  bss       = 0x%p-0x%p\n"
+	       KERN_INFO "  available = 0x%p-0x%p\n"
+#ifdef CONFIG_MTD_UCLINUX
+	       KERN_INFO "  rootfs    = 0x%p-0x%p\n"
+#endif
+#if DMA_UNCACHED_REGION > 0
+	       KERN_INFO "  DMA Zone  = 0x%p-0x%p\n"
+#endif
+	       , _stext, _etext,
+	       __init_begin, __init_end,
+	       _sdata, _edata,
+	       (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
+	       __bss_start, __bss_stop,
+	       (void*)_ramstart, (void*)memory_end
+#ifdef CONFIG_MTD_UCLINUX
+	       , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
+#endif
+#if DMA_UNCACHED_REGION > 0
+	       , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
+#endif
+	       );
+
+	/*
+	 * give all the memory to the bootmap allocator,  tell it to put the
+	 * boot mem_map at the start of memory
+	 */
+	bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT,	/* map goes here */
+					 PAGE_OFFSET >> PAGE_SHIFT,
+					 memory_end >> PAGE_SHIFT);
+	/*
+	 * free the usable memory,  we have to make sure we do not free
+	 * the bootmem bitmap so we then reserve it after freeing it :-)
+	 */
+	free_bootmem(memory_start, memory_end - memory_start);
+
+	reserve_bootmem(memory_start, bootmap_size);
+	/*
+	 * get kmalloc into gear
+	 */
+	paging_init();
+
+	/* check the size of the l1 area */
+	l1_length = _etext_l1 - _stext_l1;
+	if (l1_length > L1_CODE_LENGTH)
+		panic("L1 memory overflow\n");
+
+	l1_length = _ebss_l1 - _sdata_l1;
+	if (l1_length > L1_DATA_A_LENGTH)
+		panic("L1 memory overflow\n");
+
+	bf53x_cache_init();
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP)
+	/* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
+	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
+	bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
+	SSYNC();
+# endif
+# if defined (CONFIG_BFIN561_EZKIT)
+	bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12));
+	SSYNC();
+# endif /* defined (CONFIG_BFIN561_EZKIT) */
+#endif
+
+	printk(KERN_INFO "Hardware Trace Enabled\n");
+	bfin_write_TBUFCTL(0x03);
+}
+
+#if defined(CONFIG_BF561)
+static struct cpu cpu[2];
+#else
+static struct cpu cpu[1];
+#endif
+static int __init topology_init(void)
+{
+#if defined (CONFIG_BF561)
+	register_cpu(&cpu[0], 0);
+	register_cpu(&cpu[1], 1);
+	return 0;
+#else
+	return register_cpu(cpu, 0);
+#endif
+}
+
+subsys_initcall(topology_init);
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+u16 lock_kernel_check(u32 start, u32 end)
+{
+	if ((start <= (u32) _stext && end >= (u32) _end)
+	    || (start >= (u32) _stext && end <= (u32) _end))
+		return IN_KERNEL;
+	return 0;
+}
+
+static unsigned short __init
+fill_cplbtab(struct cplb_tab *table,
+	     unsigned long start, unsigned long end,
+	     unsigned long block_size, unsigned long cplb_data)
+{
+	int i;
+
+	switch (block_size) {
+	case SIZE_4M:
+		i = 3;
+		break;
+	case SIZE_1M:
+		i = 2;
+		break;
+	case SIZE_4K:
+		i = 1;
+		break;
+	case SIZE_1K:
+	default:
+		i = 0;
+		break;
+	}
+
+	cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
+
+	while ((start < end) && (table->pos < table->size)) {
+
+		table->tab[table->pos++] = start;
+
+		if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
+			table->tab[table->pos++] =
+			    cplb_data | CPLB_LOCK | CPLB_DIRTY;
+		else
+			table->tab[table->pos++] = cplb_data;
+
+		start += block_size;
+	}
+	return 0;
+}
+
+static unsigned short __init
+close_cplbtab(struct cplb_tab *table)
+{
+
+	while (table->pos < table->size) {
+
+		table->tab[table->pos++] = 0;
+		table->tab[table->pos++] = 0; /* !CPLB_VALID */
+	}
+	return 0;
+}
+
+static void __init generate_cpl_tables(void)
+{
+
+	u16 i, j, process;
+	u32 a_start, a_end, as, ae, as_1m;
+
+	struct cplb_tab *t_i = NULL;
+	struct cplb_tab *t_d = NULL;
+	struct s_cplb cplb;
+
+	cplb.init_i.size = MAX_CPLBS;
+	cplb.init_d.size = MAX_CPLBS;
+	cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
+	cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
+
+	cplb.init_i.pos = 0;
+	cplb.init_d.pos = 0;
+	cplb.switch_i.pos = 0;
+	cplb.switch_d.pos = 0;
+
+	cplb.init_i.tab = icplb_table;
+	cplb.init_d.tab = dcplb_table;
+	cplb.switch_i.tab = ipdt_table;
+	cplb.switch_d.tab = dpdt_table;
+
+	cplb_data[SDRAM_KERN].end = memory_end;
+
+#ifdef CONFIG_MTD_UCLINUX
+	cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
+	cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
+	cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
+# if defined(CONFIG_ROMFS_FS)
+	cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
+
+	/*
+	 * The ROMFS_FS size is often not multiple of 1MB.
+	 * This can cause multiple CPLB sets covering the same memory area.
+	 * This will then cause multiple CPLB hit exceptions.
+	 * Workaround: We ensure a contiguous memory area by extending the kernel
+	 * memory section over the mtd section.
+	 * For ROMFS_FS memory must be covered with ICPLBs anyways.
+	 * So there is no difference between kernel and mtd memory setup.
+	 */
+
+	cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
+	cplb_data[SDRAM_RAM_MTD].valid = 0;
+
+# endif
+#else
+	cplb_data[SDRAM_RAM_MTD].valid = 0;
+#endif
+
+	cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
+	cplb_data[SDRAM_DMAZ].end = _ramend;
+
+	cplb_data[RES_MEM].start = _ramend;
+	cplb_data[RES_MEM].end = physical_mem_end;
+
+	if (reserved_mem_dcache_on)
+		cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
+	else
+		cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
+
+	if (reserved_mem_icache_on)
+		cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
+	else
+		cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
+
+	for (i = ZERO_P; i <= L2_MEM; i++) {
+
+		if (cplb_data[i].valid) {
+
+			as_1m = cplb_data[i].start % SIZE_1M;
+
+			/* We need to make sure all sections are properly 1M aligned
+			 * However between Kernel Memory and the Kernel mtd section, depending on the
+			 * rootfs size, there can be overlapping memory areas.
+			 */
+
+			if (as_1m &&  i!=L1I_MEM && i!=L1D_MEM) {
+#ifdef CONFIG_MTD_UCLINUX
+				if (i == SDRAM_RAM_MTD) {
+					if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
+						cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
+					else
+						cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
+				} else
+#endif
+					printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
+					       cplb_data[i].name, cplb_data[i].start);
+			}
+
+			as = cplb_data[i].start % SIZE_4M;
+			ae = cplb_data[i].end % SIZE_4M;
+
+			if (as)
+				a_start = cplb_data[i].start + (SIZE_4M - (as));
+			else
+				a_start = cplb_data[i].start;
+
+			a_end = cplb_data[i].end - ae;
+
+			for (j = INITIAL_T; j <= SWITCH_T; j++) {
+
+				switch (j) {
+				case INITIAL_T:
+					if (cplb_data[i].attr & INITIAL_T) {
+						t_i = &cplb.init_i;
+						t_d = &cplb.init_d;
+						process = 1;
+					} else
+						process = 0;
+					break;
+				case SWITCH_T:
+					if (cplb_data[i].attr & SWITCH_T) {
+						t_i = &cplb.switch_i;
+						t_d = &cplb.switch_d;
+						process = 1;
+					} else
+						process = 0;
+					break;
+				default:
+						process = 0;
+					break;
+				}
+
+	if (process) {
+				if (cplb_data[i].attr & I_CPLB) {
+
+					if (cplb_data[i].psize) {
+						fill_cplbtab(t_i,
+							     cplb_data[i].start,
+							     cplb_data[i].end,
+							     cplb_data[i].psize,
+							     cplb_data[i].i_conf);
+					} else {
+						/*icplb_table */
+#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+						if (i == SDRAM_KERN) {
+							fill_cplbtab(t_i,
+								     cplb_data[i].start,
+								     cplb_data[i].end,
+								     SIZE_4M,
+								     cplb_data[i].i_conf);
+						} else
+#endif
+						{
+							fill_cplbtab(t_i,
+								     cplb_data[i].start,
+								     a_start,
+								     SIZE_1M,
+								     cplb_data[i].i_conf);
+							fill_cplbtab(t_i,
+								     a_start,
+								     a_end,
+								     SIZE_4M,
+								     cplb_data[i].i_conf);
+							fill_cplbtab(t_i, a_end,
+								     cplb_data[i].end,
+								     SIZE_1M,
+								     cplb_data[i].i_conf);
+						}
+					}
+
+				}
+				if (cplb_data[i].attr & D_CPLB) {
+
+					if (cplb_data[i].psize) {
+						fill_cplbtab(t_d,
+							     cplb_data[i].start,
+							     cplb_data[i].end,
+							     cplb_data[i].psize,
+							     cplb_data[i].d_conf);
+					} else {
+/*dcplb_table*/
+						fill_cplbtab(t_d,
+							     cplb_data[i].start,
+							     a_start, SIZE_1M,
+							     cplb_data[i].d_conf);
+						fill_cplbtab(t_d, a_start,
+							     a_end, SIZE_4M,
+							     cplb_data[i].d_conf);
+						fill_cplbtab(t_d, a_end,
+							     cplb_data[i].end,
+							     SIZE_1M,
+							     cplb_data[i].d_conf);
+
+					}
+
+				}
+			}
+			}
+
+		}
+	}
+
+/* close tables */
+
+	close_cplbtab(&cplb.init_i);
+	close_cplbtab(&cplb.init_d);
+
+	cplb.init_i.tab[cplb.init_i.pos] = -1;
+	cplb.init_d.tab[cplb.init_d.pos] = -1;
+	cplb.switch_i.tab[cplb.switch_i.pos] = -1;
+	cplb.switch_d.tab[cplb.switch_d.pos] = -1;
+
+}
+
+#endif
+
+static inline u_long get_vco(void)
+{
+	u_long msel;
+	u_long vco;
+
+	msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
+	if (0 == msel)
+		msel = 64;
+
+	vco = CONFIG_CLKIN_HZ;
+	vco >>= (1 & bfin_read_PLL_CTL());	/* DF bit */
+	vco = msel * vco;
+	return vco;
+}
+
+/*Get the Core clock*/
+u_long get_cclk(void)
+{
+	u_long csel, ssel;
+	if (bfin_read_PLL_STAT() & 0x1)
+		return CONFIG_CLKIN_HZ;
+
+	ssel = bfin_read_PLL_DIV();
+	csel = ((ssel >> 4) & 0x03);
+	ssel &= 0xf;
+	if (ssel && ssel < (1 << csel))	/* SCLK > CCLK */
+		return get_vco() / ssel;
+	return get_vco() >> csel;
+}
+
+EXPORT_SYMBOL(get_cclk);
+
+/* Get the System clock */
+u_long get_sclk(void)
+{
+	u_long ssel;
+
+	if (bfin_read_PLL_STAT() & 0x1)
+		return CONFIG_CLKIN_HZ;
+
+	ssel = (bfin_read_PLL_DIV() & 0xf);
+	if (0 == ssel) {
+		printk(KERN_WARNING "Invalid System Clock\n");
+		ssel = 1;
+	}
+
+	return get_vco() / ssel;
+}
+
+EXPORT_SYMBOL(get_sclk);
+
+/*
+ *	Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	char *cpu, *mmu, *fpu, *name;
+	uint32_t revid;
+
+	u_long cclk = 0, sclk = 0;
+	u_int dcache_size = 0, dsup_banks = 0;
+
+	cpu = CPU;
+	mmu = "none";
+	fpu = "none";
+	revid = bfin_revid();
+	name = bfin_board_name;
+
+	cclk = get_cclk();
+	sclk = get_sclk();
+
+	seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
+		   "MMU:\t\t%s\n"
+		   "FPU:\t\t%s\n"
+		   "Core Clock:\t%9lu Hz\n"
+		   "System Clock:\t%9lu Hz\n"
+		   "BogoMips:\t%lu.%02lu\n"
+		   "Calibration:\t%lu loops\n",
+		   cpu, revid, mmu, fpu,
+		   cclk,
+		   sclk,
+		   (loops_per_jiffy * HZ) / 500000,
+		   ((loops_per_jiffy * HZ) / 5000) % 100,
+		   (loops_per_jiffy * HZ));
+	seq_printf(m, "Board Name:\t%s\n", name);
+	seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
+	seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
+	if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
+		seq_printf(m, "I-CACHE:\tON\n");
+	else
+		seq_printf(m, "I-CACHE:\tOFF\n");
+	if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
+		seq_printf(m, "D-CACHE:\tON"
+#if defined CONFIG_BLKFIN_WB
+			   " (write-back)"
+#elif defined CONFIG_BLKFIN_WT
+			   " (write-through)"
+#endif
+			   "\n");
+	else
+		seq_printf(m, "D-CACHE:\tOFF\n");
+
+
+	switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
+		case ACACHE_BSRAM:
+			seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
+			dcache_size = 16;
+			dsup_banks = 1;
+			break;
+		case ACACHE_BCACHE:
+			seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
+			dcache_size = 32;
+			dsup_banks = 2;
+			break;
+		case ASRAM_BSRAM:
+			seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
+			dcache_size = 0;
+			dsup_banks = 0;
+			break;
+		default:
+		break;
+	}
+
+
+	seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024);
+	seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
+	seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
+		   BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES);
+	seq_printf(m,
+		   "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
+		   dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS,
+		   BLKFIN_DLINES);
+#ifdef CONFIG_BLKFIN_CACHE_LOCK
+	switch (read_iloc()) {
+	case WAY0_L:
+		seq_printf(m, "Way0 Locked-Down\n");
+		break;
+	case WAY1_L:
+		seq_printf(m, "Way1 Locked-Down\n");
+		break;
+	case WAY01_L:
+		seq_printf(m, "Way0,Way1 Locked-Down\n");
+		break;
+	case WAY2_L:
+		seq_printf(m, "Way2 Locked-Down\n");
+		break;
+	case WAY02_L:
+		seq_printf(m, "Way0,Way2 Locked-Down\n");
+		break;
+	case WAY12_L:
+		seq_printf(m, "Way1,Way2 Locked-Down\n");
+		break;
+	case WAY012_L:
+		seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
+		break;
+	case WAY3_L:
+		seq_printf(m, "Way3 Locked-Down\n");
+		break;
+	case WAY03_L:
+		seq_printf(m, "Way0,Way3 Locked-Down\n");
+		break;
+	case WAY13_L:
+		seq_printf(m, "Way1,Way3 Locked-Down\n");
+		break;
+	case WAY013_L:
+		seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
+		break;
+	case WAY32_L:
+		seq_printf(m, "Way3,Way2 Locked-Down\n");
+		break;
+	case WAY320_L:
+		seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
+		break;
+	case WAY321_L:
+		seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
+		break;
+	case WAYALL_L:
+		seq_printf(m, "All Ways are locked\n");
+		break;
+	default:
+		seq_printf(m, "No Ways are locked\n");
+	}
+#endif
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? ((void *)0x12345678) : 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,
+};
+
+void cmdline_init(unsigned long r0)
+{
+	if (r0)
+		strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE);
+}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
new file mode 100644
index 0000000..316e65c
--- /dev/null
+++ b/arch/blackfin/kernel/signal.c
@@ -0,0 +1,356 @@
+/*
+ * File:         arch/blackfin/kernel/signal.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/ptrace.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+#include <linux/freezer.h>
+
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+struct fdpic_func_descriptor {
+	unsigned long	text;
+	unsigned long	GOT;
+};
+
+struct rt_sigframe {
+	int sig;
+	struct siginfo *pinfo;
+	void *puc;
+	char retcode[8];
+	struct siginfo info;
+	struct ucontext uc;
+};
+
+asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
+{
+	return do_sigaltstack(uss, uoss, rdusp());
+}
+
+static inline int
+rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
+{
+	unsigned long usp = 0;
+	int err = 0;
+
+#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
+
+	/* restore passed registers */
+	RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3);
+	RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7);
+	RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3);
+	RESTORE(p4); RESTORE(p5);
+	err |= __get_user(usp, &sc->sc_usp);
+	wrusp(usp);
+	RESTORE(a0w); RESTORE(a1w);
+	RESTORE(a0x); RESTORE(a1x);
+	RESTORE(astat);
+	RESTORE(rets);
+	RESTORE(pc);
+	RESTORE(retx);
+	RESTORE(fp);
+	RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3);
+	RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3);
+	RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3);
+	RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3);
+	RESTORE(lc0); RESTORE(lc1);
+	RESTORE(lt0); RESTORE(lt1);
+	RESTORE(lb0); RESTORE(lb1);
+	RESTORE(seqstat);
+
+	regs->orig_p0 = -1;	/* disable syscall checks */
+
+	*pr0 = regs->r0;
+	return err;
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+	struct pt_regs *regs = (struct pt_regs *)__unused;
+	unsigned long usp = rdusp();
+	struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
+	sigset_t set;
+	int r0;
+
+	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(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+		goto badframe;
+
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
+		goto badframe;
+
+	return r0;
+
+      badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
+{
+	int err = 0;
+
+#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x)
+
+	SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3);
+	SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7);
+	SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3);
+	SETUP(p4); SETUP(p5);
+	err |= __put_user(rdusp(), &sc->sc_usp);
+	SETUP(a0w); SETUP(a1w);
+	SETUP(a0x); SETUP(a1x);
+	SETUP(astat);
+	SETUP(rets);
+	SETUP(pc);
+	SETUP(retx);
+	SETUP(fp);
+	SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3);
+	SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3);
+	SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3);
+	SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3);
+	SETUP(lc0); SETUP(lc1);
+	SETUP(lt0); SETUP(lt1);
+	SETUP(lb0); SETUP(lb1);
+	SETUP(seqstat);
+
+	return err;
+}
+
+static inline void push_cache(unsigned long vaddr, unsigned int len)
+{
+	flush_icache_range(vaddr, vaddr + len);
+}
+
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+				 size_t frame_size)
+{
+	unsigned long usp;
+
+	/* Default to using normal stack.  */
+	usp = rdusp();
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (!on_sig_stack(usp))
+			usp = current->sas_ss_sp + current->sas_ss_size;
+	}
+	return (void *)((usp - frame_size) & -8UL);
+}
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
+	       sigset_t * set, struct pt_regs *regs)
+{
+	struct rt_sigframe *frame;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
+
+	err |= __put_user((current_thread_info()->exec_domain
+			   && current_thread_info()->exec_domain->signal_invmap
+			   && sig < 32
+			   ? current_thread_info()->exec_domain->
+			   signal_invmap[sig] : sig), &frame->sig);
+
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |=
+	    __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
+	err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	/* Set up to return from userspace.  */
+	err |= __put_user(0x28, &(frame->retcode[0]));
+	err |= __put_user(0xe1, &(frame->retcode[1]));
+	err |= __put_user(0xad, &(frame->retcode[2]));
+	err |= __put_user(0x00, &(frame->retcode[3]));
+	err |= __put_user(0xa0, &(frame->retcode[4]));
+	err |= __put_user(0x00, &(frame->retcode[5]));
+
+	if (err)
+		goto give_sigsegv;
+
+	push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
+
+	/* Set up registers for signal handler */
+	wrusp((unsigned long)frame);
+	if (get_personality & FDPIC_FUNCPTRS) {
+		struct fdpic_func_descriptor __user *funcptr =
+			(struct fdpic_func_descriptor *) ka->sa.sa_handler;
+		__get_user(regs->pc, &funcptr->text);
+		__get_user(regs->p3, &funcptr->GOT);
+	} else
+		regs->pc = (unsigned long)ka->sa.sa_handler;
+	regs->rets = (unsigned long)(frame->retcode);
+
+	regs->r0 = frame->sig;
+	regs->r1 = (unsigned long)(&frame->info);
+	regs->r2 = (unsigned long)(&frame->uc);
+
+	return 0;
+
+      give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+	return -EFAULT;
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+	switch (regs->r0) {
+	case -ERESTARTNOHAND:
+		if (!has_handler)
+			goto do_restart;
+		regs->r0 = -EINTR;
+		break;
+
+	case -ERESTARTSYS:
+		if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+			regs->r0 = -EINTR;
+			break;
+		}
+		/* fallthrough */
+	case -ERESTARTNOINTR:
+	      do_restart:
+		regs->p0 = regs->orig_p0;
+		regs->r0 = regs->orig_r0;
+		regs->pc -= 2;
+		break;
+	}
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static int
+handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
+	      sigset_t *oldset, struct pt_regs *regs)
+{
+	int ret;
+
+	/* are we from a system call? to see pt_regs->orig_p0 */
+	if (regs->orig_p0 >= 0)
+		/* If so, check system call restarting.. */
+		handle_restart(regs, ka, 1);
+
+	/* set up the stack frame */
+	ret = setup_rt_frame(sig, ka, info, oldset, regs);
+
+	if (ret == 0) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked, &current->blocked,
+			  &ka->sa.sa_mask);
+		if (!(ka->sa.sa_flags & SA_NODEFER))
+			sigaddset(&current->blocked, sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+	return ret;
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals
+ * that the kernel can handle, and then we build all the user-level signal
+ * handling stack-frames in one go after that.
+ */
+asmlinkage void do_signal(struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+	struct k_sigaction ka;
+	sigset_t *oldset;
+
+	current->thread.esp0 = (unsigned long)regs;
+
+	if (try_to_freeze())
+		goto no_signal;
+
+	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+		oldset = &current->saved_sigmask;
+	else
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	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:
+	/* Did we come from a system call? */
+	if (regs->orig_p0 >= 0)
+		/* Restart the system call - no handlers present */
+		handle_restart(regs, NULL, 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, &current->saved_sigmask, NULL);
+	}
+}
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
new file mode 100644
index 0000000..f436e67
--- /dev/null
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -0,0 +1,115 @@
+/*
+ * File:         arch/blackfin/kernel/sys_bfin.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains various random system calls that
+ *               have a non-standard calling sequence on the Linux/bfin
+ *               platform.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+#include <asm/dma.h>
+#include <asm/unistd.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long *fildes)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe(fd);
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2 * sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+/* common code for old and new mmaps */
+static inline long
+do_mmap2(unsigned long addr, unsigned long len,
+	 unsigned long prot, unsigned long flags,
+	 unsigned long fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file *file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+      out:
+	return error;
+}
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+			  unsigned long prot, unsigned long flags,
+			  unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+	return PAGE_SIZE;
+}
+
+asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
+{
+	return sram_alloc_with_lsl(size, flags);
+}
+
+asmlinkage int sys_sram_free(const void *addr)
+{
+	return sram_free_with_lsl(addr);
+}
+
+asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
+{
+	return safe_dma_memcpy(dest, src, len);
+}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
new file mode 100644
index 0000000..f578176
--- /dev/null
+++ b/arch/blackfin/kernel/time.c
@@ -0,0 +1,326 @@
+/*
+ * File:         arch/blackfin/kernel/time.c
+ * Based on:     none - original work
+ * Author:
+ *
+ * Created:
+ * Description:  This file contains the bfin-specific time handling details.
+ *               Most of the stuff is located in the machine specific files.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/profile.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+
+#include <asm/blackfin.h>
+
+/* This is an NTP setting */
+#define	TICK_SIZE (tick_nsec / 1000)
+
+static void time_sched_init(irqreturn_t(*timer_routine)
+			(int, void *));
+static unsigned long gettimeoffset(void);
+static inline void do_leds(void);
+
+#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
+void __init init_leds(void)
+{
+	unsigned int tmp = 0;
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+	/* config pins as output. */
+	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
+	SSYNC();
+	bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
+	SSYNC();
+
+	/*      First set led be off */
+	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+	SSYNC();
+	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);	/* light off */
+	SSYNC();
+#endif
+
+#if defined(CONFIG_BFIN_IDLE_LED)
+	/* config pins as output. */
+	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
+	SSYNC();
+	bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
+	SSYNC();
+
+	/*      First set led be off */
+	tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+	SSYNC();
+	bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);	/* light off */
+	SSYNC();
+#endif
+}
+#else
+void __init init_leds(void)
+{
+}
+#endif
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+static inline void do_leds(void)
+{
+	static unsigned int count = 50;
+	static int flag = 0;
+	unsigned short tmp = 0;
+
+	if (--count == 0) {
+		count = 50;
+		flag = ~flag;
+	}
+	tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+	SSYNC();
+
+	if (flag)
+		tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN;	/* light on */
+	else
+		tmp |= CONFIG_BFIN_ALIVE_LED_PIN;	/* light off */
+
+	bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
+	SSYNC();
+
+}
+#else
+static inline void do_leds(void)
+{
+}
+#endif
+
+static struct irqaction bfin_timer_irq = {
+	.name = "BFIN Timer Tick",
+	.flags = IRQF_DISABLED
+};
+
+/*
+ * The way that the Blackfin core timer works is:
+ *  - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
+ *  - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
+ *
+ * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
+ *    10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
+ *    (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
+ *    to use TSCALE, and program it to zero (which is pass CCLK through).
+ *    If you feel like using it, try to keep HZ * TIMESCALE to some
+ *    value that divides easy (like power of 2).
+ */
+
+#define TIME_SCALE 1
+
+static void
+time_sched_init(irqreturn_t(*timer_routine) (int, void *))
+{
+	u32 tcount;
+
+	/* power up the timer, but don't enable it just yet */
+	bfin_write_TCNTL(1);
+	CSYNC();
+
+	/*
+	 * the TSCALE prescaler counter.
+	 */
+	bfin_write_TSCALE((TIME_SCALE - 1));
+
+	tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
+	bfin_write_TPERIOD(tcount);
+	bfin_write_TCOUNT(tcount);
+
+	/* now enable the timer */
+	CSYNC();
+
+	bfin_write_TCNTL(7);
+
+	bfin_timer_irq.handler = (irq_handler_t)timer_routine;
+	/* call setup_irq instead of request_irq because request_irq calls
+	 * kmalloc which has not been initialized yet
+	 */
+	setup_irq(IRQ_CORETMR, &bfin_timer_irq);
+}
+
+/*
+ * Should return useconds since last timer tick
+ */
+static unsigned long gettimeoffset(void)
+{
+	unsigned long offset;
+	unsigned long clocks_per_jiffy;
+
+	clocks_per_jiffy = bfin_read_TPERIOD();
+	offset =
+	    (clocks_per_jiffy -
+	     bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
+				    USEC_PER_SEC);
+
+	/* Check if we just wrapped the counters and maybe missed a tick */
+	if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
+	    && (offset < (100000 / HZ / 2)))
+		offset += (USEC_PER_SEC / HZ);
+
+	return offset;
+}
+
+static inline int set_rtc_mmss(unsigned long nowtime)
+{
+	return 0;
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
+#endif
+
+irqreturn_t timer_interrupt(int irq, void *dummy)
+{
+	/* last time the cmos clock got updated */
+	static long last_rtc_update = 0;
+
+	write_seqlock(&xtime_lock);
+
+	do_timer(1);
+	do_leds();
+
+#ifndef CONFIG_SMP
+	update_process_times(user_mode(get_irq_regs()));
+#endif
+	profile_tick(CPU_PROFILING);
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+
+	if (ntp_synced() &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / NSEC_PER_USEC) >=
+	    500000 - ((unsigned)TICK_SIZE) / 2
+	    && (xtime.tv_nsec / NSEC_PER_USEC) <=
+	    500000 + ((unsigned)TICK_SIZE) / 2) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			/* Do it again in 60s. */
+			last_rtc_update = xtime.tv_sec - 600;
+	}
+	write_sequnlock(&xtime_lock);
+	return IRQ_HANDLED;
+}
+
+void __init time_init(void)
+{
+	time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60;	/* 1 Jan 2007 */
+
+#ifdef CONFIG_RTC_DRV_BFIN
+	/* [#2663] hack to filter junk RTC values that would cause
+	 * userspace to have to deal with time values greater than
+	 * 2^31 seconds (which uClibc cannot cope with yet)
+	 */
+	if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
+		printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
+		bfin_write_RTC_STAT(0);
+	}
+#endif
+
+	/* Initialize xtime. From now on, xtime is updated with timer interrupts */
+	xtime.tv_sec = secs_since_1970;
+	xtime.tv_nsec = 0;
+
+	wall_to_monotonic.tv_sec = -xtime.tv_sec;
+
+	time_sched_init(timer_interrupt);
+}
+
+#ifndef CONFIG_GENERIC_TIME
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long seq;
+	unsigned long usec, sec;
+
+	do {
+		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+		usec = gettimeoffset();
+		sec = xtime.tv_sec;
+		usec += (xtime.tv_nsec / NSEC_PER_USEC);
+	}
+	while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+	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 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_usec
+	 * 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 -= (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);
+
+	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);
+#endif /* !CONFIG_GENERIC_TIME */
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
+}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
new file mode 100644
index 0000000..9556b73
--- /dev/null
+++ b/arch/blackfin/kernel/traps.c
@@ -0,0 +1,649 @@
+/*
+ * File:         arch/blackfin/kernel/traps.c
+ * Based on:
+ * Author:       Hamish Macdonald
+ *
+ * Created:
+ * Description:  uses S/W interrupt 15 for the system calls
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+#include <asm/irq_handler.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+#ifdef CONFIG_KGDB
+# include <linux/debugger.h>
+# include <linux/kgdb.h>
+#endif
+
+/* Initiate the event table handler */
+void __init trap_init(void)
+{
+	CSYNC();
+	bfin_write_EVT3(trap);
+	CSYNC();
+}
+
+asmlinkage void trap_c(struct pt_regs *fp);
+
+int kstack_depth_to_print = 48;
+
+static int printk_address(unsigned long address)
+{
+	struct vm_list_struct *vml;
+	struct task_struct *p;
+	struct mm_struct *mm;
+
+#ifdef CONFIG_KALLSYMS
+	unsigned long offset = 0, symsize;
+	const char *symname;
+	char *modname;
+	char *delim = ":";
+	char namebuf[128];
+
+	/* look up the address and see if we are in kernel space */
+	symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
+
+	if (symname) {
+		/* yeah! kernel space! */
+		if (!modname)
+			modname = delim = "";
+		return printk("<0x%p> { %s%s%s%s + 0x%lx }",
+		              (void*)address, delim, modname, delim, symname,
+		              (unsigned long)offset);
+
+	}
+#endif
+
+	/* looks like we're off in user-land, so let's walk all the
+	 * mappings of all our processes and see if we can't be a whee
+	 * bit more specific
+	 */
+	write_lock_irq(&tasklist_lock);
+	for_each_process(p) {
+		mm = get_task_mm(p);
+		if (!mm)
+			continue;
+
+		vml = mm->context.vmlist;
+		while (vml) {
+			struct vm_area_struct *vma = vml->vma;
+
+			if (address >= vma->vm_start && address < vma->vm_end) {
+				char *name = p->comm;
+				struct file *file = vma->vm_file;
+				if (file) {
+					char _tmpbuf[256];
+					name = d_path(file->f_dentry,
+					              file->f_vfsmnt,
+					              _tmpbuf,
+					              sizeof(_tmpbuf));
+				}
+
+				write_unlock_irq(&tasklist_lock);
+				return printk("<0x%p> [ %s + 0x%lx ]",
+				              (void*)address, name,
+				              (unsigned long)
+				                ((address - vma->vm_start) +
+				                 (vma->vm_pgoff << PAGE_SHIFT)));
+			}
+
+			vml = vml->next;
+		}
+	}
+	write_unlock_irq(&tasklist_lock);
+
+	/* we were unable to find this address anywhere */
+	return printk("[<0x%p>]", (void*)address);
+}
+
+#define trace_buffer_save(x) \
+	do { \
+		(x) = bfin_read_TBUFCTL(); \
+		bfin_write_TBUFCTL((x) & ~TBUFEN); \
+	} while (0)
+#define trace_buffer_restore(x) \
+	do { \
+		bfin_write_TBUFCTL((x));	\
+	} while (0)
+
+asmlinkage void trap_c(struct pt_regs *fp)
+{
+	int j, sig = 0;
+	siginfo_t info;
+	unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
+
+#ifdef CONFIG_KGDB
+# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0)
+# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0)
+#else
+# define CHK_DEBUGGER_TRAP() do { } while (0)
+# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
+#endif
+
+	trace_buffer_save(j);
+
+	/* trap_c() will be called for exceptions. During exceptions
+	 * processing, the pc value should be set with retx value.
+	 * With this change we can cleanup some code in signal.c- TODO
+	 */
+	fp->orig_pc = fp->retx;
+	/* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
+		trapnr, fp->ipend, fp->pc, fp->retx); */
+
+	/* send the appropriate signal to the user program */
+	switch (trapnr) {
+
+	/* This table works in conjuction with the one in ./mach-common/entry.S
+	 * Some exceptions are handled there (in assembly, in exception space)
+	 * Some are handled here, (in C, in interrupt space)
+	 * Some, like CPLB, are handled in both, where the normal path is
+	 * handled in assembly/exception space, and the error path is handled
+	 * here
+	 */
+
+	/* 0x00 - Linux Syscall, getting here is an error */
+	/* 0x01 - userspace gdb breakpoint, handled here */
+	case VEC_EXCPT01:
+		info.si_code = TRAP_ILLTRAP;
+		sig = SIGTRAP;
+		CHK_DEBUGGER_TRAP_MAYBE();
+		/* Check if this is a breakpoint in kernel space */
+		if (fp->ipend & 0xffc0)
+			return;
+		else
+			break;
+#ifdef CONFIG_KGDB
+	case VEC_EXCPT02 :		 /* gdb connection */
+		info.si_code = TRAP_ILLTRAP;
+		sig = SIGTRAP;
+		CHK_DEBUGGER_TRAP();
+		return;
+#else
+	/* 0x02 - User Defined, Caught by default */
+#endif
+	/* 0x03  - Atomic test and set */
+	case VEC_EXCPT03:
+		info.si_code = SEGV_STACKFLOW;
+		sig = SIGSEGV;
+		printk(KERN_EMERG EXC_0x03);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x04 - spinlock - handled by _ex_spinlock,
+		getting here is an error */
+	/* 0x05 - User Defined, Caught by default */
+	/* 0x06 - User Defined, Caught by default */
+	/* 0x07 - User Defined, Caught by default */
+	/* 0x08 - User Defined, Caught by default */
+	/* 0x09 - User Defined, Caught by default */
+	/* 0x0A - User Defined, Caught by default */
+	/* 0x0B - User Defined, Caught by default */
+	/* 0x0C - User Defined, Caught by default */
+	/* 0x0D - User Defined, Caught by default */
+	/* 0x0E - User Defined, Caught by default */
+	/* 0x0F - User Defined, Caught by default */
+	/* 0x10 HW Single step, handled here */
+	case VEC_STEP:
+		info.si_code = TRAP_STEP;
+		sig = SIGTRAP;
+		CHK_DEBUGGER_TRAP_MAYBE();
+		/* Check if this is a single step in kernel space */
+		if (fp->ipend & 0xffc0)
+			return;
+		else
+			break;
+	/* 0x11 - Trace Buffer Full, handled here */
+	case VEC_OVFLOW:
+		info.si_code = TRAP_TRACEFLOW;
+		sig = SIGTRAP;
+		printk(KERN_EMERG EXC_0x11);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x12 - Reserved, Caught by default */
+	/* 0x13 - Reserved, Caught by default */
+	/* 0x14 - Reserved, Caught by default */
+	/* 0x15 - Reserved, Caught by default */
+	/* 0x16 - Reserved, Caught by default */
+	/* 0x17 - Reserved, Caught by default */
+	/* 0x18 - Reserved, Caught by default */
+	/* 0x19 - Reserved, Caught by default */
+	/* 0x1A - Reserved, Caught by default */
+	/* 0x1B - Reserved, Caught by default */
+	/* 0x1C - Reserved, Caught by default */
+	/* 0x1D - Reserved, Caught by default */
+	/* 0x1E - Reserved, Caught by default */
+	/* 0x1F - Reserved, Caught by default */
+	/* 0x20 - Reserved, Caught by default */
+	/* 0x21 - Undefined Instruction, handled here */
+	case VEC_UNDEF_I:
+		info.si_code = ILL_ILLOPC;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x21);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x22 - Illegal Instruction Combination, handled here */
+	case VEC_ILGAL_I:
+		info.si_code = ILL_ILLPARAOP;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x22);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x23 - Data CPLB Protection Violation,
+		 normal case is handled in _cplb_hdr */
+	case VEC_CPLB_VL:
+		info.si_code = ILL_CPLB_VI;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x23);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x24 - Data access misaligned, handled here */
+	case VEC_MISALI_D:
+		info.si_code = BUS_ADRALN;
+		sig = SIGBUS;
+		printk(KERN_EMERG EXC_0x24);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x25 - Unrecoverable Event, handled here */
+	case VEC_UNCOV:
+		info.si_code = ILL_ILLEXCPT;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x25);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
+		error case is handled here */
+	case VEC_CPLB_M:
+		info.si_code = BUS_ADRALN;
+		sig = SIGBUS;
+		printk(KERN_EMERG EXC_0x26);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
+	case VEC_CPLB_MHIT:
+		info.si_code = ILL_CPLB_MULHIT;
+#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
+		sig = SIGSEGV;
+		printk(KERN_EMERG "\n\nNULL pointer access (probably)\n");
+#else
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x27);
+#endif
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x28 - Emulation Watchpoint, handled here */
+	case VEC_WATCH:
+		info.si_code = TRAP_WATCHPT;
+		sig = SIGTRAP;
+		pr_debug(EXC_0x28);
+		CHK_DEBUGGER_TRAP_MAYBE();
+		/* Check if this is a watchpoint in kernel space */
+		if (fp->ipend & 0xffc0)
+			return;
+		else
+			break;
+#ifdef CONFIG_BF535
+	/* 0x29 - Instruction fetch access error (535 only) */
+	case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
+		info.si_code = BUS_OPFETCH;
+		sig = SIGBUS;
+		printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n");
+		CHK_DEBUGGER_TRAP();
+		break;
+#else
+	/* 0x29 - Reserved, Caught by default */
+#endif
+	/* 0x2A - Instruction fetch misaligned, handled here */
+	case VEC_MISALI_I:
+		info.si_code = BUS_ADRALN;
+		sig = SIGBUS;
+		printk(KERN_EMERG EXC_0x2A);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x2B - Instruction CPLB protection Violation,
+		handled in _cplb_hdr */
+	case VEC_CPLB_I_VL:
+		info.si_code = ILL_CPLB_VI;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x2B);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
+	case VEC_CPLB_I_M:
+		info.si_code = ILL_CPLB_MISS;
+		sig = SIGBUS;
+		printk(KERN_EMERG EXC_0x2C);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x2D - Instruction CPLB Multiple Hits, handled here */
+	case VEC_CPLB_I_MHIT:
+		info.si_code = ILL_CPLB_MULHIT;
+#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
+		sig = SIGSEGV;
+		printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n");
+#else
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x2D);
+#endif
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x2E - Illegal use of Supervisor Resource, handled here */
+	case VEC_ILL_RES:
+		info.si_code = ILL_PRVOPC;
+		sig = SIGILL;
+		printk(KERN_EMERG EXC_0x2E);
+		CHK_DEBUGGER_TRAP();
+		break;
+	/* 0x2F - Reserved, Caught by default */
+	/* 0x30 - Reserved, Caught by default */
+	/* 0x31 - Reserved, Caught by default */
+	/* 0x32 - Reserved, Caught by default */
+	/* 0x33 - Reserved, Caught by default */
+	/* 0x34 - Reserved, Caught by default */
+	/* 0x35 - Reserved, Caught by default */
+	/* 0x36 - Reserved, Caught by default */
+	/* 0x37 - Reserved, Caught by default */
+	/* 0x38 - Reserved, Caught by default */
+	/* 0x39 - Reserved, Caught by default */
+	/* 0x3A - Reserved, Caught by default */
+	/* 0x3B - Reserved, Caught by default */
+	/* 0x3C - Reserved, Caught by default */
+	/* 0x3D - Reserved, Caught by default */
+	/* 0x3E - Reserved, Caught by default */
+	/* 0x3F - Reserved, Caught by default */
+	default:
+		info.si_code = TRAP_ILLTRAP;
+		sig = SIGTRAP;
+		printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
+			(fp->seqstat & SEQSTAT_EXCAUSE));
+		CHK_DEBUGGER_TRAP();
+		break;
+	}
+
+	info.si_signo = sig;
+	info.si_errno = 0;
+	info.si_addr = (void *)fp->pc;
+	force_sig_info(sig, &info, current);
+	if (sig != 0 && sig != SIGTRAP) {
+		unsigned long stack;
+		dump_bfin_regs(fp, (void *)fp->retx);
+		dump_bfin_trace_buffer();
+		show_stack(current, &stack);
+		if (current->mm == NULL)
+			panic("Kernel exception");
+	}
+
+	/* if the address that we are about to return to is not valid, set it
+	 * to a valid address, if we have a current application or panic
+	 */
+	if (!(fp->pc <= physical_mem_end
+#if L1_CODE_LENGTH != 0
+	    || (fp->pc >= L1_CODE_START &&
+	        fp->pc <= (L1_CODE_START + L1_CODE_LENGTH))
+#endif
+	)) {
+		if (current->mm) {
+			fp->pc = current->mm->start_code;
+		} else {
+			printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n");
+			panic("Help - I've fallen and can't get up\n");
+		}
+	}
+
+	trace_buffer_restore(j);
+	return;
+}
+
+/* Typical exception handling routines	*/
+
+void dump_bfin_trace_buffer(void)
+{
+	int tflags;
+	trace_buffer_save(tflags);
+
+	if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
+		int i;
+		printk(KERN_EMERG "Hardware Trace:\n");
+		for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
+			printk(KERN_EMERG "%2i Target : ", i);
+			printk_address((unsigned long)bfin_read_TBUF());
+			printk("\n" KERN_EMERG "   Source : ");
+			printk_address((unsigned long)bfin_read_TBUF());
+			printk("\n");
+		}
+	}
+
+	trace_buffer_restore(tflags);
+}
+EXPORT_SYMBOL(dump_bfin_trace_buffer);
+
+static void show_trace(struct task_struct *tsk, unsigned long *sp)
+{
+	unsigned long addr;
+
+	printk("\nCall Trace:");
+#ifdef CONFIG_KALLSYMS
+	printk("\n");
+#endif
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		/*
+		 * 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.
+		 */
+		if (kernel_text_address(addr))
+			print_ip_sym(addr);
+	}
+
+	printk("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+	unsigned long *endstack, addr;
+	int i;
+
+	/* Cannot call dump_bfin_trace_buffer() here as show_stack() is
+	 * called externally in some places in the kernel.
+	 */
+
+	if (!stack) {
+		if (task)
+			stack = (unsigned long *)task->thread.ksp;
+		else
+			stack = (unsigned long *)&stack;
+	}
+
+	addr = (unsigned long)stack;
+	endstack = (unsigned long *)PAGE_ALIGN(addr);
+
+	printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (stack + 1 > endstack)
+			break;
+		if (i % 8 == 0)
+			printk("\n" KERN_EMERG "       ");
+		printk(" %08lx", *stack++);
+	}
+
+	show_trace(task, stack);
+}
+
+void dump_stack(void)
+{
+	unsigned long stack;
+	int tflags;
+	trace_buffer_save(tflags);
+	dump_bfin_trace_buffer();
+	show_stack(current, &stack);
+	trace_buffer_restore(tflags);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
+{
+	if (current->pid) {
+		printk("\nCURRENT PROCESS:\n\n");
+		printk("COMM=%s PID=%d\n", current->comm, current->pid);
+	} else {
+		printk
+		    ("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n");
+	}
+
+	if (current->mm) {
+		printk("TEXT = 0x%p-0x%p  DATA = 0x%p-0x%p\n"
+		       "BSS = 0x%p-0x%p   USER-STACK = 0x%p\n\n",
+		       (void*)current->mm->start_code,
+		       (void*)current->mm->end_code,
+		       (void*)current->mm->start_data,
+		       (void*)current->mm->end_data,
+		       (void*)current->mm->end_data,
+		       (void*)current->mm->brk,
+		       (void*)current->mm->start_stack);
+	}
+
+	printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr);
+	if (retaddr != 0 && retaddr <= (void*)physical_mem_end
+#if L1_CODE_LENGTH != 0
+	    /* FIXME: Copy the code out of L1 Instruction SRAM through dma
+	       memcpy.  */
+	    && !(retaddr >= (void*)L1_CODE_START
+	         && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
+#endif
+	) {
+		int i = 0;
+		unsigned short x = 0;
+		for (i = -16; i < 8; i++) {
+			if (get_user(x, (unsigned short *)retaddr + i))
+				break;
+#ifndef CONFIG_DEBUG_HWERR
+			/* If one of the last few instructions was a STI
+			 * it is likily that the error occured awhile ago
+			 * and we just noticed
+			 */
+			if (x >= 0x0040 && x <= 0x0047 && i <= 0)
+				panic("\n\nWARNING : You should reconfigure the kernel to turn on\n"
+					" 'Hardware error interrupt debugging'\n"
+					" The rest of this error is meanless\n");
+#endif
+
+			if (i == -8)
+				printk("\n");
+			if (i == 0)
+				printk("X\n");
+			printk("%04x ", x);
+		}
+	} else
+		printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n");
+
+	printk("\n\n");
+
+	printk("RETE:  %08lx  RETN: %08lx  RETX: %08lx  RETS: %08lx\n",
+	       fp->rete, fp->retn, fp->retx, fp->rets);
+	printk("IPEND: %04lx  SYSCFG: %04lx\n", fp->ipend, fp->syscfg);
+	printk("SEQSTAT: %08lx    SP: %08lx\n", (long)fp->seqstat, (long)fp);
+	printk("R0: %08lx    R1: %08lx    R2: %08lx    R3: %08lx\n",
+	       fp->r0, fp->r1, fp->r2, fp->r3);
+	printk("R4: %08lx    R5: %08lx    R6: %08lx    R7: %08lx\n",
+	       fp->r4, fp->r5, fp->r6, fp->r7);
+	printk("P0: %08lx    P1: %08lx    P2: %08lx    P3: %08lx\n",
+	       fp->p0, fp->p1, fp->p2, fp->p3);
+	printk("P4: %08lx    P5: %08lx    FP: %08lx\n", fp->p4, fp->p5, fp->fp);
+	printk("A0.w: %08lx    A0.x: %08lx    A1.w: %08lx    A1.x: %08lx\n",
+	       fp->a0w, fp->a0x, fp->a1w, fp->a1x);
+
+	printk("LB0: %08lx  LT0: %08lx  LC0: %08lx\n", fp->lb0, fp->lt0,
+	       fp->lc0);
+	printk("LB1: %08lx  LT1: %08lx  LC1: %08lx\n", fp->lb1, fp->lt1,
+	       fp->lc1);
+	printk("B0: %08lx  L0: %08lx  M0: %08lx  I0: %08lx\n", fp->b0, fp->l0,
+	       fp->m0, fp->i0);
+	printk("B1: %08lx  L1: %08lx  M1: %08lx  I1: %08lx\n", fp->b1, fp->l1,
+	       fp->m1, fp->i1);
+	printk("B2: %08lx  L2: %08lx  M2: %08lx  I2: %08lx\n", fp->b2, fp->l2,
+	       fp->m2, fp->i2);
+	printk("B3: %08lx  L3: %08lx  M3: %08lx  I3: %08lx\n", fp->b3, fp->l3,
+	       fp->m3, fp->i3);
+
+	printk("\nUSP: %08lx   ASTAT: %08lx\n", rdusp(), fp->astat);
+	if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
+		printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
+		printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
+	}
+
+	printk("\n\n");
+}
+
+#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
+asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
+#endif
+
+asmlinkage int sys_bfin_spinlock(int *spinlock)
+{
+	int ret = 0;
+	int tmp = 0;
+
+	local_irq_disable();
+	ret = get_user(tmp, spinlock);
+	if (ret == 0) {
+		if (tmp)
+			ret = 1;
+		tmp = 1;
+		put_user(tmp, spinlock);
+	}
+	local_irq_enable();
+	return ret;
+}
+
+void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
+{
+	switch (cplb_panic) {
+	case CPLB_NO_UNLOCKED:
+		printk(KERN_EMERG "All CPLBs are locked\n");
+		break;
+	case CPLB_PROT_VIOL:
+		return;
+	case CPLB_NO_ADDR_MATCH:
+		return;
+	case CPLB_UNKNOWN_ERR:
+		printk(KERN_EMERG "Unknown CPLB Exception\n");
+		break;
+	}
+
+	printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
+	printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
+	dump_bfin_regs(fp, (void *)fp->retx);
+	dump_stack();
+	panic("Unrecoverable event\n");
+}
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..6ae9ebb
--- /dev/null
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -0,0 +1,228 @@
+/*
+ * File:         arch/blackfin/kernel/vmlinux.lds.S
+ * Based on:     none - original work
+ * Author:
+ *
+ * Created:      Tue Sep 21 2004
+ * Description:  Master linker script for blackfin architecture
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define VMLINUX_SYMBOL(_sym_) _##_sym_
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/mem_map.h>
+
+
+OUTPUT_FORMAT("elf32-bfin")
+ENTRY(__start)
+_jiffies = _jiffies_64;
+
+MEMORY
+{
+	ram         : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD)
+	l1_data_a   : ORIGIN = L1_DATA_A_START,  LENGTH = L1_DATA_A_LENGTH
+	l1_data_b   : ORIGIN = L1_DATA_B_START,  LENGTH = L1_DATA_B_LENGTH
+	l1_code     : ORIGIN = L1_CODE_START,    LENGTH = L1_CODE_LENGTH
+	l1_scratch  : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH
+}
+
+SECTIONS
+{
+	. = CONFIG_BOOT_LOAD;
+
+	.text :
+	{
+		 _text = .;
+		 __stext = .;
+		*(.text)
+		SCHED_TEXT
+		*(.text.lock)
+		. = ALIGN(16);
+		  ___start___ex_table = .;
+		*(__ex_table)
+		 ___stop___ex_table = .;
+
+		*($code)
+		*(.rodata)
+		*(.rodata.*)
+		*(__vermagic)		/* Kernel version magic */
+		*(.rodata1)
+		*(.fixup)
+		*(.spinlock.text)
+
+		/* Kernel symbol table: Normal symbols */
+		. = ALIGN(4);
+		___start___ksymtab = .;
+		*(__ksymtab)
+		___stop___ksymtab = .;
+
+		/* Kernel symbol table: GPL-only symbols */
+		___start___ksymtab_gpl = .;
+		*(__ksymtab_gpl)
+		___stop___ksymtab_gpl = .;
+
+		/* Kernel symbol table: Normal unused symbols */		\
+		___start___ksymtab_unused = .;
+		*(__ksymtab_unused)
+		___stop___ksymtab_unused = .;
+
+		/* Kernel symbol table: GPL-only unused symbols */
+		___start___ksymtab_unused_gpl = .;
+		*(__ksymtab_unused_gpl)
+		___stop___ksymtab_unused_gpl = .;
+
+
+		/* Kernel symbol table: GPL-future symbols */
+		___start___ksymtab_gpl_future = .;
+		*(__ksymtab_gpl_future)
+		___stop___ksymtab_gpl_future = .;
+
+		/* Kernel symbol table: Normal symbols */
+		___start___kcrctab = .;
+		*(__kcrctab)
+		___stop___kcrctab = .;
+
+		/* Kernel symbol table: GPL-only symbols */
+		___start___kcrctab_gpl = .;
+		*(__kcrctab_gpl)
+		___stop___kcrctab_gpl = .;
+
+		/* Kernel symbol table: GPL-future symbols */
+		___start___kcrctab_gpl_future = .;
+		*(__kcrctab_gpl_future)
+		___stop___kcrctab_gpl_future = .;
+
+		/* Kernel symbol table: strings */
+		*(__ksymtab_strings)
+
+		 . = ALIGN(4);
+		__etext = .;
+	} > ram
+
+	.init :
+	{
+		. = ALIGN(4096);
+		___init_begin = .;
+		__sinittext = .;
+		*(.init.text)
+		__einittext = .;
+		*(.init.data)
+		. = ALIGN(16);
+		___setup_start = .;
+		*(.init.setup)
+		___setup_end = .;
+		___start___param = .;
+		*(__param)
+		___stop___param = .;
+		___initcall_start = .;
+		INITCALLS
+		___initcall_end = .;
+		___con_initcall_start = .;
+		*(.con_initcall.init)
+		___con_initcall_end = .;
+		___security_initcall_start = .;
+		*(.security_initcall.init)
+		___security_initcall_end = .;
+		. = ALIGN(4);
+		___initramfs_start = .;
+		*(.init.ramfs)
+		___initramfs_end = .;
+		. = ALIGN(4);
+		___init_end = .;
+	} > ram
+
+	 __l1_lma_start = .;
+
+	.text_l1 :
+	{
+		. = ALIGN(4);
+		 __stext_l1 = .;
+		*(.l1.text)
+
+		. = ALIGN(4);
+		 __etext_l1 = .;
+	} > l1_code AT > ram
+
+	.data_l1 :
+	{
+		. = ALIGN(4);
+		 __sdata_l1 = .;
+		*(.l1.data)
+		 __edata_l1 = .;
+
+		. = ALIGN(4);
+		 __sbss_l1 = .;
+		*(.l1.bss)
+
+		. = ALIGN(32);
+		*(.data_l1.cacheline_aligned)
+
+		. = ALIGN(4);
+		 __ebss_l1 = .;
+	} > l1_data_a AT > ram
+	.data_b_l1 :
+	{
+		. = ALIGN(4);
+		__sdata_b_l1 = .;
+		*(.l1.data.B)
+		__edata_b_l1 = .;
+
+		. = ALIGN(4);
+		__sbss_b_l1 = .;
+		*(.l1.bss.B)
+
+		. = ALIGN(4);
+		__ebss_b_l1 = .;
+	} > l1_data_b AT > ram
+
+	.data :
+	{
+		 __sdata = .;
+		. = ALIGN(0x2000);
+		*(.data.init_task)
+		*(.data)
+
+		. = ALIGN(32);
+		*(.data.cacheline_aligned)
+
+		. = ALIGN(0x2000);
+		__edata = .;
+	} > ram
+
+	/DISCARD/ : {			/* Exit code and data*/
+		*(.exit.text)
+		*(.exit.data)
+		*(.exitcall.exit)
+	} > ram
+
+	.bss :
+	{
+		. = ALIGN(4);
+		 ___bss_start = .;
+		*(.bss)
+		*(COMMON)
+		. = ALIGN(4);
+		 ___bss_stop = .;
+		 __end = .	;
+	} > ram
+}
diff --git a/arch/blackfin/lib/Makefile b/arch/blackfin/lib/Makefile
new file mode 100644
index 0000000..635288f
--- /dev/null
+++ b/arch/blackfin/lib/Makefile
@@ -0,0 +1,11 @@
+#
+# arch/blackfin/lib/Makefile
+#
+
+lib-y := \
+	ashldi3.o ashrdi3.o lshrdi3.o \
+	muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
+	checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
+	strcmp.o strcpy.o strncmp.o strncpy.o \
+	umulsi3_highpart.o smulsi3_highpart.o \
+	ins.o outs.o
diff --git a/arch/blackfin/lib/ashldi3.c b/arch/blackfin/lib/ashldi3.c
new file mode 100644
index 0000000..a8c279e
--- /dev/null
+++ b/arch/blackfin/lib/ashldi3.c
@@ -0,0 +1,58 @@
+/*
+ * File:         arch/blackfin/lib/ashldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashldi3(DItype u, word_type b)
+{
+	DIunion w;
+	word_type bm;
+	DIunion uu;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+
+	bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+	if (bm <= 0) {
+		w.s.low = 0;
+		w.s.high = (USItype) uu.s.low << -bm;
+	} else {
+		USItype carries = (USItype) uu.s.low >> bm;
+		w.s.low = (USItype) uu.s.low << b;
+		w.s.high = ((USItype) uu.s.high << b) | carries;
+	}
+
+	return w.ll;
+}
diff --git a/arch/blackfin/lib/ashrdi3.c b/arch/blackfin/lib/ashrdi3.c
new file mode 100644
index 0000000..a0d3419
--- /dev/null
+++ b/arch/blackfin/lib/ashrdi3.c
@@ -0,0 +1,59 @@
+/*
+ * File:         arch/blackfin/lib/ashrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashrdi3(DItype u, word_type b)
+{
+	DIunion w;
+	word_type bm;
+	DIunion uu;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+
+	bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+	if (bm <= 0) {
+		/* w.s.high = 1..1 or 0..0 */
+		w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
+		w.s.low = uu.s.high >> -bm;
+	} else {
+		USItype carries = (USItype) uu.s.high << bm;
+		w.s.high = uu.s.high >> b;
+		w.s.low = ((USItype) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c
new file mode 100644
index 0000000..42768e0
--- /dev/null
+++ b/arch/blackfin/lib/checksum.c
@@ -0,0 +1,140 @@
+/*
+ * File:         arch/blackfin/lib/checksum.c
+ * Based on:     none - original work
+ * Author:
+ *
+ * Created:
+ * Description:  An implementation of the TCP/IP protocol suite for the LINUX
+ *               operating system.  INET is implemented using the  BSD Socket
+ *               interface as the means of communication with the user level.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <net/checksum.h>
+#include <asm/checksum.h>
+
+#ifdef CONFIG_IP_CHECKSUM_L1
+static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
+#endif
+
+static unsigned short do_csum(const unsigned char *buff, int len)
+{
+	register unsigned long sum = 0;
+	int swappem = 0;
+
+	if (1 & (unsigned long)buff) {
+		sum = *buff << 8;
+		buff++;
+		len--;
+		++swappem;
+	}
+
+	while (len > 1) {
+		sum += *(unsigned short *)buff;
+		buff += 2;
+		len -= 2;
+	}
+
+	if (len > 0)
+		sum += *buff;
+
+	/*  Fold 32-bit sum to 16 bits */
+	while (sum >> 16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	if (swappem)
+		sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
+
+	return sum;
+
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ */
+unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+	return ~do_csum(iph, ihl * 4);
+}
+
+/*
+ * 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)
+{
+	/*
+	 * Just in case we get nasty checksum data...
+	 * Like 0xffff6ec3 in the case of our IPv6 multicast header.
+	 * We fold to begin with, as well as at the end.
+	 */
+	sum = (sum & 0xffff) + (sum >> 16);
+
+	sum += do_csum(buff, len);
+
+	sum = (sum & 0xffff) + (sum >> 16);
+
+	return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(const unsigned char *buff, int len)
+{
+	return ~do_csum(buff, len);
+}
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
+			    int len, int sum, int *csum_err)
+{
+	if (csum_err)
+		*csum_err = 0;
+	memcpy(dst, src, len);
+	return csum_partial(dst, len, sum);
+}
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+			       int len, int sum)
+{
+	memcpy(dst, src, len);
+	return csum_partial(dst, len, sum);
+}
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
new file mode 100644
index 0000000..3e29861
--- /dev/null
+++ b/arch/blackfin/lib/divsi3.S
@@ -0,0 +1,216 @@
+/*
+ * File:         arch/blackfin/lib/divsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  16 / 32 bit signed division.
+ *                 Special cases :
+ *                      1)  If(numerator == 0)
+ *                             return 0
+ *                      2)  If(denominator ==0)
+ *                             return positive max = 0x7fffffff
+ *                      3)  If(numerator == denominator)
+ *                             return 1
+ *                      4)  If(denominator ==1)
+ *                             return numerator
+ *                      5)  If(denominator == -1)
+ *                             return -numerator
+ *
+ *                 Operand         : R0 - Numerator   (i)
+ *                                   R1 - Denominator (i)
+ *                                   R0 - Quotient    (o)
+ *                 Registers Used : R2-R7,P0-P2
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+.global   ___divsi3;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2;
+___divsi3 :
+
+
+  R3 = R0 ^ R1;
+  R0 = ABS R0;
+
+  CC = V;
+
+  r3 = rot r3 by -1;
+  r1 = abs r1;      /* now both positive, r3.30 means "negate result",
+                    ** r3.31 means overflow, add one to result
+                    */
+  cc = r0 < r1;
+  if cc jump .Lret_zero;
+  r2 = r1 >> 15;
+  cc = r2;
+  if cc jump .Lidents;
+  r2 = r1 << 16;
+  cc = r2 <= r0;
+  if cc jump .Lidents;
+
+  DIVS(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+  DIVQ(R0, R1);
+
+  R0 = R0.L (Z);
+  r1 = r3 >> 31;    /* add overflow issue back in */
+  r0 = r0 + r1;
+  r1 = -r0;
+  cc = bittst(r3, 30);
+  if cc r0 = r1;
+  RTS;
+
+/* Can't use the primitives. Test common identities.
+** If the identity is true, return the value in R2.
+*/
+
+.Lidents:
+  CC = R1 == 0;                   /* check for divide by zero */
+  IF CC JUMP .Lident_return;
+
+  CC = R0 == 0;                   /* check for division of zero */
+  IF CC JUMP .Lzero_return;
+
+  CC = R0 == R1;                  /* check for identical operands */
+  IF CC JUMP .Lident_return;
+
+  CC = R1 == 1;                   /* check for divide by 1 */
+  IF CC JUMP .Lident_return;
+
+  R2.L = ONES R1;
+  R2 = R2.L (Z);
+  CC = R2 == 1;
+  IF CC JUMP .Lpower_of_two;
+
+  /* Identities haven't helped either.
+  ** Perform the full division process.
+  */
+
+  P1 = 31;                        /* Set loop counter   */
+
+  [--SP] = (R7:5);                /* Push registers R5-R7 */
+  R2 = -R1;
+  [--SP] = R2;
+  R2 = R0 << 1;                   /* R2 lsw of dividend  */
+  R6 = R0 ^ R1;                   /* Get sign */
+  R5 = R6 >> 31;                  /* Shift sign to LSB */
+
+  R0 = 0 ;                        /* Clear msw partial remainder */
+  R2 = R2 | R5;                   /* Shift quotient bit */
+  R6 = R0 ^ R1;                   /* Get new quotient bit */
+
+  LSETUP(.Llst,.Llend)  LC0 = P1;   /* Setup loop */
+.Llst:   R7 = R2 >> 31;            /* record copy of carry from R2 */
+        R2 = R2 << 1;             /* Shift 64 bit dividend up by 1 bit */
+        R0 = R0 << 1 || R5 = [SP];
+        R0 = R0 | R7;             /* and add carry */
+        CC = R6 < 0;              /* Check quotient(AQ) */
+                                  /* we might be subtracting divisor (AQ==0) */
+        IF CC R5 = R1;            /* or we might be adding divisor  (AQ==1)*/
+        R0 = R0 + R5;             /* do add or subtract, as indicated by AQ */
+        R6 = R0 ^ R1;             /* Generate next quotient bit */
+        R5 = R6 >> 31;
+                                  /* Assume AQ==1, shift in zero */
+        BITTGL(R5,0);             /* tweak AQ to be what we want to shift in */
+.Llend:  R2 = R2 + R5;             /* and then set shifted-in value to
+                                  ** tweaked AQ.
+                                  */
+  r1 = r3 >> 31;
+  r2 = r2 + r1;
+  cc = bittst(r3,30);
+  r0 = -r2;
+  if !cc r0 = r2;
+  SP += 4;
+  (R7:5)= [SP++];                 /* Pop registers R6-R7 */
+  RTS;
+
+.Lident_return:
+  CC = R1 == 0;                   /* check for divide by zero  => 0x7fffffff */
+  R2 = -1 (X);
+  R2 >>= 1;
+  IF CC JUMP .Ltrue_ident_return;
+
+  CC = R0 == R1;                  /* check for identical operands => 1 */
+  R2 = 1 (Z);
+  IF CC JUMP .Ltrue_ident_return;
+
+  R2 = R0;                        /* assume divide by 1 => numerator */
+  /*FALLTHRU*/
+
+.Ltrue_ident_return:
+  R0 = R2;                        /* Return an identity value */
+  R2 = -R2;
+  CC = bittst(R3,30);
+  IF CC R0 = R2;
+.Lzero_return:
+  RTS;                            /* ...including zero */
+
+.Lpower_of_two:
+  /* Y has a single bit set, which means it's a power of two.
+  ** That means we can perform the division just by shifting
+  ** X to the right the appropriate number of bits
+  */
+
+  /* signbits returns the number of sign bits, minus one.
+  ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+  ** to shift right n-signbits spaces. It also means 0x80000000
+  ** is a special case, because that *also* gives a signbits of 0
+  */
+
+  R2 = R0 >> 31;
+  CC = R1 < 0;
+  IF CC JUMP .Ltrue_ident_return;
+
+  R1.l = SIGNBITS R1;
+  R1 = R1.L (Z);
+  R1 += -30;
+  R0 = LSHIFT R0 by R1.L;
+  r1 = r3 >> 31;
+  r0 = r0 + r1;
+  R2 = -R0;                       // negate result if necessary
+  CC = bittst(R3,30);
+  IF CC R0 = R2;
+  RTS;
+
+.Lret_zero:
+  R0 = 0;
+  RTS;
diff --git a/arch/blackfin/lib/gcclib.h b/arch/blackfin/lib/gcclib.h
new file mode 100644
index 0000000..9ccd39a
--- /dev/null
+++ b/arch/blackfin/lib/gcclib.h
@@ -0,0 +1,47 @@
+/*
+ * File:         arch/blackfin/lib/gcclib.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define BITS_PER_UNIT  8
+#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+
+typedef unsigned int UQItype __attribute__ ((mode(QI)));
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+typedef unsigned int UDItype __attribute__ ((mode(DI)));
+
+struct DIstruct {
+	SItype low, high;
+};
+
+typedef union {
+	struct DIstruct s;
+	DItype ll;
+} DIunion;
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
new file mode 100644
index 0000000..730d2b4
--- /dev/null
+++ b/arch/blackfin/lib/ins.S
@@ -0,0 +1,69 @@
+/*
+ * File:         arch/blackfin/lib/ins.S
+ * Based on:
+ * Author:       Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created:      Tue Mar 22 15:27:24 CEST 2005
+ * Description:  Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *               Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_insl)
+	P0 = R0;	/* P0 = port */
+	cli R3;
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+	SSYNC;
+	LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P0];
+.Llong_loop_e: [P1++] = R0;
+	sti R3;
+	RTS;
+
+ENTRY(_insw)
+	P0 = R0;	/* P0 = port */
+	cli R3;
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+	SSYNC;
+	LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P0];
+.Lword_loop_e: W[P1++] = R0;
+	sti R3;
+	RTS;
+
+ENTRY(_insb)
+	P0 = R0;	/* P0 = port */
+	cli R3;
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+	SSYNC;
+	LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P0];
+.Lbyte_loop_e: B[P1++] = R0;
+	sti R3;
+	RTS;
diff --git a/arch/blackfin/lib/lshrdi3.c b/arch/blackfin/lib/lshrdi3.c
new file mode 100644
index 0000000..84b9c55
--- /dev/null
+++ b/arch/blackfin/lib/lshrdi3.c
@@ -0,0 +1,72 @@
+/*
+ * File:         arch/blackfin/lib/lshrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#define BITS_PER_UNIT 8
+
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct DIstruct {
+	SItype high, low;
+};
+
+typedef union {
+	struct DIstruct s;
+	DItype ll;
+} DIunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __lshrdi3(DItype u, word_type b)
+{
+	DIunion w;
+	word_type bm;
+	DIunion uu;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+
+	bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+	if (bm <= 0) {
+		w.s.high = 0;
+		w.s.low = (USItype) uu.s.high >> -bm;
+	} else {
+		USItype carries = (USItype) uu.s.high << bm;
+		w.s.high = (USItype) uu.s.high >> b;
+		w.s.low = ((USItype) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
diff --git a/arch/blackfin/lib/memchr.S b/arch/blackfin/lib/memchr.S
new file mode 100644
index 0000000..4981222
--- /dev/null
+++ b/arch/blackfin/lib/memchr.S
@@ -0,0 +1,70 @@
+/*
+ * File:         arch/blackfin/lib/memchr.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memchr(const void *s, int c, size_t n);
+ * R0 = address (s)
+ * R1 = sought byte (c)
+ * R2 = count (n)
+ *
+ * Returns pointer to located character.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memchr)
+	P0 = R0;		/* P0 = address */
+	P2 = R2;		/* P2 = count */
+	R1 = R1.B(Z);
+	CC = R2 == 0;
+	IF CC JUMP .Lfailed;
+
+.Lbytes:
+	LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+
+.Lbyte_loop_s:
+	R3 = B[P0++](Z);
+	CC = R3 == R1;
+	IF CC JUMP .Lfound;
+.Lbyte_loop_e:
+	NOP;
+
+.Lfailed:
+	R0=0;
+	RTS;
+
+.Lfound:
+	R0 = P0;
+	R0 += -1;
+	RTS;
+
+.size _memchr,.-_memchr
diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S
new file mode 100644
index 0000000..5b95023
--- /dev/null
+++ b/arch/blackfin/lib/memcmp.S
@@ -0,0 +1,110 @@
+/*
+ * File:         arch/blackfin/lib/memcmp.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+/* int memcmp(const void *s1, const void *s2, size_t n);
+ * R0 = First Address (s1)
+ * R1 = Second Address (s2)
+ * R2 = count (n)
+ *
+ * Favours word aligned data.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memcmp)
+	I1 = P3;
+	P0 = R0;			/* P0 = s1 address */
+	P3 = R1;			/* P3 = s2 Address  */
+	P2 = R2 ;			/* P2 = count */
+	CC = R2 <= 7(IU);
+	IF CC JUMP .Ltoo_small;
+	I0 = R1;			/* s2 */
+	R1 = R1 | R0;		/* OR addresses together */
+	R1 <<= 30;		/* check bottom two bits */
+	CC =  AZ;			/* AZ set if zero. */
+	IF !CC JUMP .Lbytes ;	/* Jump if addrs not aligned. */
+
+	P1 = P2 >> 2;		/* count = n/4 */
+	R3 =  3;
+	R2 = R2 & R3;		/* remainder */
+	P2 = R2;			/* set remainder */
+
+	LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1;
+.Lquad_loop_s:
+	MNOP || R0 = [P0++] || R1 = [I0++];
+	CC = R0 == R1;
+	IF !CC JUMP .Lquad_different;
+.Lquad_loop_e:
+	NOP;
+
+	P3 = I0;			/* s2 */
+.Ltoo_small:
+	CC = P2 == 0;		/* Check zero count*/
+	IF CC JUMP .Lfinished;	/* very unlikely*/
+
+.Lbytes:
+	LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+.Lbyte_loop_s:
+	R1 = B[P3++](Z);	/* *s2 */
+	R0 = B[P0++](Z);	/* *s1 */
+	CC = R0 == R1;
+	IF !CC JUMP .Ldifferent;
+.Lbyte_loop_e:
+	NOP;
+
+.Ldifferent:
+	R0 = R0 - R1;
+	P3 = I1;
+	RTS;
+
+.Lquad_different:
+	/* We've read two quads which don't match.
+	 * Can't just compare them, because we're
+	 * a little-endian machine, so the MSBs of
+	 * the regs occur at later addresses in the
+	 * string.
+	 * Arrange to re-read those two quads again,
+	 * byte-by-byte.
+	 */
+	P0 += -4;		/* back up to the start of the */
+	P3 = I0;		/* quads, and increase the*/
+	P2 += 4;		/* remainder count*/
+	P3 += -4;
+	JUMP .Lbytes;
+
+.Lfinished:
+	R0 = 0;
+	P3 = I1;
+	RTS;
+
+.size _memcmp,.-_memcmp
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
new file mode 100644
index 0000000..c1e00ef
--- /dev/null
+++ b/arch/blackfin/lib/memcpy.S
@@ -0,0 +1,142 @@
+/*
+ * File:         arch/blackfin/lib/memcpy.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  internal version of memcpy(), issued by the compiler
+ *               to copy blocks of data around.
+ *               This is really memmove() - it has to be able to deal with
+ *               possible overlaps, because that ambiguity is when the compiler
+ *               gives up and calls a function. We have our own, internal version
+ *               so that we get something we trust, even if the user has redefined
+ *               the normal symbol.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memcpy(void *dest, const void *src, size_t n);
+ * R0 = To Address (dest) (leave unchanged to form result)
+ * R1 = From Address (src)
+ * R2 = count
+ *
+ * Note: Favours word alignment
+ */
+
+#ifdef CONFIG_MEMCPY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_memcpy)
+	CC = R2 <=  0;	/* length not positive? */
+	IF CC JUMP .L_P1L2147483647;	/* Nothing to do */
+
+	P0 = R0 ;	/* dst*/
+	P1 = R1 ;	/* src*/
+	P2 = R2 ;	/* length */
+
+	/* check for overlapping data */
+	CC = R1 < R0;	/* src < dst */
+	IF !CC JUMP .Lno_overlap;
+	R3 = R1 + R2;
+	CC = R0 < R3;	/* and dst < src+len */
+	IF CC JUMP .Lhas_overlap;
+
+.Lno_overlap:
+	/* Check for aligned data.*/
+
+	R3 = R1 | R0;
+	R0 = 0x3;
+	R3 = R3 & R0;
+	CC = R3;	/* low bits set on either address? */
+	IF CC JUMP .Lnot_aligned;
+
+	/* Both addresses are word-aligned, so we can copy
+	at least part of the data using word copies.*/
+	P2 = P2 >> 2;
+	CC = P2 <= 2;
+	IF !CC JUMP .Lmore_than_seven;
+	/* less than eight bytes... */
+	P2 = R2;
+	LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
+	R0 = R1;	/* setup src address for return */
+.Lthree_start:
+	R3 = B[P1++] (X);
+.Lthree_end:
+	B[P0++] = R3;
+
+	RTS;
+
+.Lmore_than_seven:
+	/* There's at least eight bytes to copy. */
+	P2 += -1;	/* because we unroll one iteration */
+	LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
+	R0 = R1;
+	I1 = P1;
+	R3 = [I1++];
+.Lword_loop:
+	MNOP || [P0++] = R3 || R3 = [I1++];
+
+	[P0++] = R3;
+	/* Any remaining bytes to copy? */
+	R3 = 0x3;
+	R3 = R2 & R3;
+	CC = R3 == 0;
+	P1 = I1;	/* in case there's something left, */
+	IF !CC JUMP .Lbytes_left;
+	RTS;
+.Lbytes_left:	P2 = R3;
+.Lnot_aligned:
+	/* From here, we're copying byte-by-byte. */
+	LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
+	R0 = R1;	/* Save src address for return */
+.Lbyte_start:
+	R1 = B[P1++] (X);
+.Lbyte_end:
+	B[P0++] = R1;
+
+.L_P1L2147483647:
+	RTS;
+
+.Lhas_overlap:
+	/* Need to reverse the copying, because the
+	 * dst would clobber the src.
+	 * Don't bother to work out alignment for
+	 * the reverse case.
+	 */
+	R0 = R1;	/* save src for later. */
+	P0 = P0 + P2;
+	P0 += -1;
+	P1 = P1 + P2;
+	P1 += -1;
+	LSETUP(.Lover_start, .Lover_end) LC0=P2;
+.Lover_start:
+	R1 = B[P1--] (X);
+.Lover_end:
+	B[P0--] = R1;
+
+	RTS;
diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S
new file mode 100644
index 0000000..2e5fb7f
--- /dev/null
+++ b/arch/blackfin/lib/memmove.S
@@ -0,0 +1,103 @@
+/*
+ * File:         arch/blackfin/lib/memmove.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+/*
+ * C Library function MEMMOVE
+ * R0 = To Address (leave unchanged to form result)
+ * R1 = From Address
+ * R2 = count
+ * Data may overlap
+ */
+
+ENTRY(_memmove)
+	I1 = P3;
+	P0 = R0;                  /* P0 = To address */
+	P3 = R1;                  /* P3 = From Address */
+	P2 = R2;                  /* P2 = count */
+	CC = P2 == 0;             /* Check zero count*/
+	IF CC JUMP .Lfinished;    /* very unlikely */
+
+	CC = R1 < R0 (IU);        /* From < To */
+	IF !CC JUMP .Lno_overlap;
+	R3 = R1 + R2;
+	CC = R0 <= R3 (IU);       /* (From+len) >= To */
+	IF CC JUMP .Loverlap;
+.Lno_overlap:
+	R3 = 11;
+	CC = R2 <= R3;
+	IF CC JUMP .Lbytes;
+	R3 = R1 | R0;             /* OR addresses together */
+	R3 <<= 30;                /* check bottom two bits */
+	CC =  AZ;                 /* AZ set if zero.*/
+	IF !CC JUMP .Lbytes;      /* Jump if addrs not aligned.*/
+
+	I0 = P3;
+	P1 = P2 >> 2;             /* count = n/4 */
+	P1 += -1;
+	R3 =  3;
+	R2 = R2 & R3;             /* remainder */
+	P2 = R2;                  /* set remainder */
+	R1 = [I0++];
+
+	LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1;
+.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
+	[P0++] = R1;
+
+	CC = P2 == 0;             /* any remaining bytes? */
+	P3 = I0;                  /* Ammend P3 to updated ptr. */
+	IF !CC JUMP .Lbytes;
+	P3 = I1;
+	RTS;
+
+.Lbytes:     LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2;
+.Lbyte2_s:   R1 = B[P3++](Z);
+.Lbyte2_e:   B[P0++] = R1;
+
+.Lfinished:  P3 = I1;
+	RTS;
+
+.Loverlap:
+	P2 += -1;
+	P0 = P0 + P2;
+	P3 = P3 + P2;
+	R1 = B[P3--] (Z);
+	CC = P2 == 0;
+	IF CC JUMP .Lno_loop;
+	LSETUP (.Lol_s, .Lol_e) LC0 = P2;
+.Lol_s:    B[P0--] = R1;
+.Lol_e:    R1 = B[P3--] (Z);
+.Lno_loop: B[P0] = R1;
+	P3 = I1;
+	RTS;
+
+.size _memmove,.-_memmove
diff --git a/arch/blackfin/lib/memset.S b/arch/blackfin/lib/memset.S
new file mode 100644
index 0000000..ba6d047
--- /dev/null
+++ b/arch/blackfin/lib/memset.S
@@ -0,0 +1,109 @@
+/*
+ * File:         arch/blackfin/lib/memset.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+#ifdef CONFIG_MEMSET_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/*
+ * C Library function MEMSET
+ * R0 = address (leave unchanged to form result)
+ * R1 = filler byte
+ * R2 = count
+ * Favours word aligned data.
+ */
+
+ENTRY(_memset)
+	P0 = R0 ;              /* P0 = address */
+	P2 = R2 ;              /* P2 = count   */
+	R3 = R0 + R2;          /* end          */
+	CC = R2 <= 7(IU);
+	IF CC JUMP  .Ltoo_small;
+	R1 = R1.B (Z);         /* R1 = fill char */
+	R2 =  3;
+	R2 = R0 & R2;          /* addr bottom two bits */
+	CC =  R2 == 0;             /* AZ set if zero.	*/
+	IF !CC JUMP  .Lforce_align ;  /* Jump if addr not aligned. */
+
+.Laligned:
+	P1 = P2 >> 2;          /* count = n/4        */
+	R2 = R1 <<  8;         /* create quad filler */
+	R2.L = R2.L + R1.L(NS);
+	R2.H = R2.L + R1.H(NS);
+	P2 = R3;
+
+	LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
+.Lquad_loop:
+	[P0++] = R2;
+
+	CC = P0 == P2;
+	IF !CC JUMP .Lbytes_left;
+	RTS;
+
+.Lbytes_left:
+	R2 = R3;                /* end point */
+	R3 = P0;                /* current position */
+	R2 = R2 - R3;           /* bytes left */
+	P2 = R2;
+
+.Ltoo_small:
+	CC = P2 == 0;           /* Check zero count */
+	IF CC JUMP .Lfinished;    /* Unusual */
+
+.Lbytes:
+	LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
+.Lbyte_loop:
+	B[P0++] = R1;
+
+.Lfinished:
+	RTS;
+
+.Lforce_align:
+	CC = BITTST (R0, 0);  /* odd byte */
+	R0 = 4;
+	R0 = R0 - R2;
+	P1 = R0;
+	R0 = P0;		    /* Recover return address */
+	IF !CC JUMP .Lskip1;
+	B[P0++] = R1;
+.Lskip1:
+	CC = R2 <= 2;          /* 2 bytes */
+	P2 -= P1;              /* reduce count */
+	IF !CC JUMP .Laligned;
+	B[P0++] = R1;
+	B[P0++] = R1;
+	JUMP .Laligned;
+
+.size _memset,.-_memset
diff --git a/arch/blackfin/lib/modsi3.S b/arch/blackfin/lib/modsi3.S
new file mode 100644
index 0000000..528b8b1
--- /dev/null
+++ b/arch/blackfin/lib/modsi3.S
@@ -0,0 +1,79 @@
+/*
+ * File:         arch/blackfin/lib/modsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  This program computes 32 bit signed remainder. It calls div32 function
+ *               for quotient estimation.
+ *
+ *               Registers used :
+ *               Numerator/ Denominator in  R0, R1
+ *                 R0  -  returns remainder.
+ *                 R2-R7
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+.global ___modsi3;
+.type ___modsi3, STT_FUNC;
+.extern ___divsi3;
+.type ___divsi3, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___modsi3:
+
+	CC=R0==0;
+	IF CC JUMP .LRETURN_R0;		/* Return 0, if numerator  == 0 */
+	CC=R1==0;
+	IF CC JUMP .LRETURN_ZERO;		/* Return 0, if denominator == 0 */
+	CC=R0==R1;
+	IF CC JUMP .LRETURN_ZERO;		/* Return 0, if numerator == denominator */
+	CC = R1 == 1;
+	IF CC JUMP .LRETURN_ZERO;		/* Return 0, if denominator ==  1 */
+	CC = R1 == -1;
+	IF CC JUMP .LRETURN_ZERO;		/* Return 0, if denominator == -1 */
+
+	/* Valid input. Use __divsi3() to compute the quotient, and then
+	 * derive the remainder from that. */
+
+	[--SP] = (R7:6);		/* Push  R7 and R6 */
+	[--SP] = RETS;			/* and return address */
+	R7 = R0;			/* Copy of R0 */
+	R6 = R1;			/* Save for later */
+	SP += -12;			/* Should always provide this space */
+	CALL ___divsi3;			/* Compute signed quotient using ___divsi3()*/
+	SP += 12;
+	R0 *= R6;			/* Quotient * divisor */
+	R0 = R7 - R0;			/* Dividend - (quotient * divisor) */
+	RETS = [SP++];			/* Get back return address */
+	(R7:6) = [SP++];		/* Pop registers R7 and R4 */
+	RTS;				/* Store remainder    */
+
+.LRETURN_ZERO:
+	R0 = 0;
+.LRETURN_R0:
+	RTS;
diff --git a/arch/blackfin/lib/muldi3.c b/arch/blackfin/lib/muldi3.c
new file mode 100644
index 0000000..303d0c6
--- /dev/null
+++ b/arch/blackfin/lib/muldi3.c
@@ -0,0 +1,99 @@
+/*
+ * File:         arch/blackfin/lib/muldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef SI_TYPE_SIZE
+#define SI_TYPE_SIZE 32
+#endif
+#define __ll_b (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
+#define __ll_highpart(t) ((usitype) (t) / __ll_b)
+#define BITS_PER_UNIT 8
+
+#if !defined(umul_ppmm)
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    usitype __x0, __x1, __x2, __x3;					\
+    usitype __ul, __vl, __uh, __vh;					\
+									\
+    __ul = __ll_lowpart (u);						\
+    __uh = __ll_highpart (u);						\
+    __vl = __ll_lowpart (v);						\
+    __vh = __ll_highpart (v);						\
+									\
+    __x0 = (usitype) __ul * __vl;					\
+    __x1 = (usitype) __ul * __vh;					\
+    __x2 = (usitype) __uh * __vl;					\
+    __x3 = (usitype) __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)
+#endif
+
+#if !defined(__umulsidi3)
+#define __umulsidi3(u, v) 						\
+  ({diunion __w;                                                        \
+       umul_ppmm (__w.s.high, __w.s.low, u, v);                         \
+           __w.ll; })
+#endif
+
+typedef unsigned int usitype __attribute__ ((mode(SI)));
+typedef int sitype __attribute__ ((mode(SI)));
+typedef int ditype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct distruct {
+	sitype low, high;
+};
+typedef union {
+	struct distruct s;
+	ditype ll;
+} diunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
+#endif
+
+ditype __muldi3(ditype u, ditype v)
+{
+	diunion w;
+	diunion uu, vv;
+
+	uu.ll = u, vv.ll = v;
+	w.ll = __umulsidi3(uu.s.low, vv.s.low);
+	w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
+		     + (usitype) uu.s.high * (usitype) vv.s.low);
+
+	return w.ll;
+}
diff --git a/arch/blackfin/lib/outs.S b/arch/blackfin/lib/outs.S
new file mode 100644
index 0000000..f8c876f
--- /dev/null
+++ b/arch/blackfin/lib/outs.S
@@ -0,0 +1,62 @@
+/*
+ * File:         arch/blackfin/lib/outs.S
+ * Based on:
+ * Author:       Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created:      Tue Mar 22 15:27:24 CEST 2005
+ * Description:  Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified:     Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_outsl)
+	P0 = R0;	/* P0 = port */
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+
+	LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P1++];
+.Llong_loop_e: [P0] = R0;
+	RTS;
+
+ENTRY(_outsw)
+	P0 = R0;	/* P0 = port */
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+
+	LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P1++];
+.Lword_loop_e: W[P0] = R0;
+	RTS;
+
+ENTRY(_outsb)
+	P0 = R0;	/* P0 = port */
+	P1 = R1;	/* P1 = address */
+	P2 = R2;	/* P2 = count */
+
+	LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P1++];
+.Lbyte_loop_e: B[P0] = R0;
+	RTS;
diff --git a/arch/blackfin/lib/smulsi3_highpart.S b/arch/blackfin/lib/smulsi3_highpart.S
new file mode 100644
index 0000000..10b8f8d
--- /dev/null
+++ b/arch/blackfin/lib/smulsi3_highpart.S
@@ -0,0 +1,30 @@
+.align 2
+.global ___smulsi3_highpart;
+.type ___smulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___smulsi3_highpart:
+	R2 = R1.L * R0.L (FU);
+	R3 = R1.H * R0.L (IS,M);
+	R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M);
+
+	R1.L = R2.H + R1.L;
+	cc = ac0;
+	R2 = cc;
+
+	R1.L = R1.L + R3.L;
+	cc = ac0;
+	R1 >>>= 16;
+	R3 >>>= 16;
+	R1 = R1 + R3;
+	R1 = R1 + R2;
+	R2 = cc;
+	R1 = R1 + R2;
+
+	R0 = R0 + R1;
+	RTS;
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
new file mode 100644
index 0000000..2ad47c4
--- /dev/null
+++ b/arch/blackfin/lib/strcmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcmp __inline_strcmp
+#include <asm/string.h>
+#undef strcmp
+
+int strcmp(const char *dest, const char *src)
+{
+	        return __inline_strcmp(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
new file mode 100644
index 0000000..4dc835a
--- /dev/null
+++ b/arch/blackfin/lib/strcpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcpy __inline_strcpy
+#include <asm/string.h>
+#undef strcpy
+
+char *strcpy(char *dest, const char *src)
+{
+	        return __inline_strcpy(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
new file mode 100644
index 0000000..947bcfe
--- /dev/null
+++ b/arch/blackfin/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncmp __inline_strncmp
+#include <asm/string.h>
+#undef strncmp
+
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+	        return __inline_strncmp(cs, ct, count);
+}
+
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
new file mode 100644
index 0000000..77a9b2e
--- /dev/null
+++ b/arch/blackfin/lib/strncpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncpy __inline_strncpy
+#include <asm/string.h>
+#undef strncpy
+
+char *strncpy(char *dest, const char *src, size_t n)
+{
+	        return __inline_strncpy(dest, src, n);
+}
+
diff --git a/arch/blackfin/lib/udivsi3.S b/arch/blackfin/lib/udivsi3.S
new file mode 100644
index 0000000..d39a129
--- /dev/null
+++ b/arch/blackfin/lib/udivsi3.S
@@ -0,0 +1,298 @@
+/*
+ * File:         arch/blackfin/lib/udivsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+
+#define CARRY AC0
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+
+ENTRY(___udivsi3)
+
+  CC = R0 < R1 (IU);    /* If X < Y, always return 0 */
+  IF CC JUMP .Lreturn_ident;
+
+  R2 = R1 << 16;
+  CC = R2 <= R0 (IU);
+  IF CC JUMP .Lidents;
+
+  R2 = R0 >> 31;       /* if X is a 31-bit number */
+  R3 = R1 >> 15;       /* and Y is a 15-bit number */
+  R2 = R2 | R3;        /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
+  CC = R2;
+  IF CC JUMP .Ly_16bit;
+
+/* METHOD 1: FAST DIVQ
+   We know we have a 31-bit dividend, and 15-bit divisor so we can use the
+   simple divq approach (first setting AQ to 0 - implying unsigned division,
+   then 16 DIVQ's).
+*/
+
+  AQ = CC;             /* Clear AQ (CC==0) */
+
+/* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
+   we need to shift the dividend one bit to the left.
+   We have already checked that we have a 31-bit number so we are safe to do
+   that.
+*/
+  R0 <<= 1;
+  DIVQ(R0, R1); // 1
+  DIVQ(R0, R1); // 2
+  DIVQ(R0, R1); // 3
+  DIVQ(R0, R1); // 4
+  DIVQ(R0, R1); // 5
+  DIVQ(R0, R1); // 6
+  DIVQ(R0, R1); // 7
+  DIVQ(R0, R1); // 8
+  DIVQ(R0, R1); // 9
+  DIVQ(R0, R1); // 10
+  DIVQ(R0, R1); // 11
+  DIVQ(R0, R1); // 12
+  DIVQ(R0, R1); // 13
+  DIVQ(R0, R1); // 14
+  DIVQ(R0, R1); // 15
+  DIVQ(R0, R1); // 16
+  R0 = R0.L (Z);
+  RTS;
+
+.Ly_16bit:
+  /* We know that the upper 17 bits of Y might have bits set,
+  ** or that the sign bit of X might have a bit. If Y is a
+  ** 16-bit number, but not bigger, then we can use the builtins
+  ** with a post-divide correction.
+  ** R3 currently holds Y>>15, which means R3's LSB is the
+  ** bit we're interested in.
+  */
+
+  /* According to the ISR, to use the Divide primitives for
+  ** unsigned integer divide, the useable range is 31 bits
+  */
+  CC = ! BITTST(R0, 31);
+
+  /* IF condition is true we can scale our inputs and use the divide primitives,
+  ** with some post-adjustment
+  */
+  R3 += -1;		/* if so, Y is 0x00008nnn */
+  CC &= AZ;
+
+  /* If condition is true we can scale our inputs and use the divide primitives,
+  ** with some post-adjustment
+  */
+  R3 = R1 >> 1;		/* Pre-scaled divisor for primitive case */
+  R2 = R0 >> 16;
+
+  R2 = R3 - R2;		/* shifted divisor < upper 16 bits of dividend */
+  CC &= CARRY;
+  IF CC JUMP .Lshift_and_correct;
+
+  /* Fall through to the identities */
+
+/* METHOD 2: identities and manual calculation
+   We are not able to use the divide primites, but may still catch some special
+   cases.
+*/
+.Lidents:
+  /* Test for common identities. Value to be returned is placed in R2. */
+  CC = R0 == 0;        /* 0/Y => 0 */
+  IF CC JUMP .Lreturn_r0;
+  CC = R0 == R1;       /* X==Y => 1 */
+  IF CC JUMP .Lreturn_ident;
+  CC = R1 == 1;        /* X/1 => X */
+  IF CC JUMP .Lreturn_ident;
+
+  R2.L = ONES R1;
+  R2 = R2.L (Z);
+  CC = R2 == 1;
+  IF CC JUMP .Lpower_of_two;
+
+  [--SP] = (R7:5);                /* Push registers R5-R7 */
+
+  /* Idents don't match. Go for the full operation. */
+
+
+  R6 = 2;                         /* assume we'll shift two */
+  R3 = 1;
+
+  P2 = R1;
+                                  /* If either R0 or R1 have sign set, */
+                                  /* divide them by two, and note it's */
+                                  /* been done. */
+  CC = R1 < 0;
+  R2 = R1 >> 1;
+  IF CC R1 = R2;                  /* Possibly-shifted R1 */
+  IF !CC R6 = R3;                 /* R1 doesn't, so at most 1 shifted */
+
+  P0 = 0;
+  R3 = -R1;
+  [--SP] = R3;
+  R2 = R0 >> 1;
+  R2 = R0 >> 1;
+  CC = R0 < 0;
+  IF CC P0 = R6;                  /* Number of values divided */
+  IF !CC R2 = R0;                 /* Shifted R0 */
+
+                                  /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
+
+                                  /* r2 holds Copy dividend  */
+  R3 = 0;                         /* Clear partial remainder */
+  R7 = 0;                         /* Initialise quotient bit */
+
+  P1 = 32;                        /* Set loop counter */
+  LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
+.Lulst:  R6 = R2 >> 31;             /* R6 = sign bit of R2, for carry */
+       R2 = R2 << 1;              /* Shift 64 bit dividend up by 1 bit */
+       R3 = R3 << 1 || R5 = [SP];
+       R3 = R3 | R6;              /* Include any carry */
+       CC = R7 < 0;               /* Check quotient(AQ) */
+                                  /* If AQ==0, we'll sub divisor */
+       IF CC R5 = R1;             /* and if AQ==1, we'll add it. */
+       R3 = R3 + R5;              /* Add/sub divsor to partial remainder */
+       R7 = R3 ^ R1;              /* Generate next quotient bit */
+
+       R5 = R7 >> 31;             /* Get AQ */
+       BITTGL(R5, 0);             /* Invert it, to get what we'll shift */
+.Lulend: R2 = R2 + R5;              /* and "shift" it in. */
+
+  CC = P0 == 0;                   /* Check how many inputs we shifted */
+  IF CC JUMP .Lno_mult;            /* if none... */
+  R6 = R2 << 1;
+  CC = P0 == 1;
+  IF CC R2 = R6;                  /* if 1, Q = Q*2 */
+  IF !CC R1 = P2;                 /* if 2, restore stored divisor */
+
+  R3 = R2;                        /* Copy of R2 */
+  R3 *= R1;                       /* Q * divisor */
+  R5 = R0 - R3;                   /* Z = (dividend - Q * divisor) */
+  CC = R1 <= R5 (IU);             /* Check if divisor <= Z? */
+  R6 = CC;                        /* if yes, R6 = 1 */
+  R2 = R2 + R6;                   /* if yes, add one to quotient(Q) */
+.Lno_mult:
+  SP += 4;
+  (R7:5) = [SP++];                /* Pop registers R5-R7 */
+  R0 = R2;                        /* Store quotient */
+  RTS;
+
+.Lreturn_ident:
+  CC = R0 < R1 (IU);    /* If X < Y, always return 0 */
+  R2 = 0;
+  IF CC JUMP .Ltrue_return_ident;
+  R2 = -1 (X);         /* X/0 => 0xFFFFFFFF */
+  CC = R1 == 0;
+  IF CC JUMP .Ltrue_return_ident;
+  R2 = -R2;            /* R2 now 1 */
+  CC = R0 == R1;       /* X==Y => 1 */
+  IF CC JUMP .Ltrue_return_ident;
+  R2 = R0;             /* X/1 => X */
+  /*FALLTHRU*/
+
+.Ltrue_return_ident:
+  R0 = R2;
+.Lreturn_r0:
+  RTS;
+
+.Lpower_of_two:
+  /* Y has a single bit set, which means it's a power of two.
+  ** That means we can perform the division just by shifting
+  ** X to the right the appropriate number of bits
+  */
+
+  /* signbits returns the number of sign bits, minus one.
+  ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+  ** to shift right n-signbits spaces. It also means 0x80000000
+  ** is a special case, because that *also* gives a signbits of 0
+  */
+
+  R2 = R0 >> 31;
+  CC = R1 < 0;
+  IF CC JUMP .Ltrue_return_ident;
+
+  R1.l = SIGNBITS R1;
+  R1 = R1.L (Z);
+  R1 += -30;
+  R0 = LSHIFT R0 by R1.L;
+  RTS;
+
+/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
+  Two scaling operations are required to use the divide primitives with a
+  divisor > 0x7FFFF.
+  Firstly (as in method 1) we need to shift the dividend 1 to the left for
+  integer division.
+  Secondly we need to shift both the divisor and dividend 1 to the right so
+  both are in range for the primitives.
+  The left/right shift of the dividend does nothing so we can skip it.
+*/
+.Lshift_and_correct:
+  R2 = R0;
+  // R3 is already R1 >> 1
+  CC=!CC;
+  AQ = CC;                        /* Clear AQ, got here with CC = 0 */
+  DIVQ(R2, R3); // 1
+  DIVQ(R2, R3); // 2
+  DIVQ(R2, R3); // 3
+  DIVQ(R2, R3); // 4
+  DIVQ(R2, R3); // 5
+  DIVQ(R2, R3); // 6
+  DIVQ(R2, R3); // 7
+  DIVQ(R2, R3); // 8
+  DIVQ(R2, R3); // 9
+  DIVQ(R2, R3); // 10
+  DIVQ(R2, R3); // 11
+  DIVQ(R2, R3); // 12
+  DIVQ(R2, R3); // 13
+  DIVQ(R2, R3); // 14
+  DIVQ(R2, R3); // 15
+  DIVQ(R2, R3); // 16
+
+  /* According to the Instruction Set Reference:
+     To divide by a divisor > 0x7FFF,
+     1. prescale and perform divide to obtain quotient (Q) (done above),
+     2. multiply quotient by unscaled divisor (result M)
+     3. subtract the product from the divident to get an error (E = X - M)
+     4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
+   */
+  R3 = R2.L (Z);		/* Q = X' / Y' */
+  R2 = R3;		/* Preserve Q */
+  R2 *= R1;		/* M = Q * Y */
+  R2 = R0 - R2;		/* E = X - M */
+  R0 = R3;		/* Copy Q into result reg */
+
+/* Correction: If result of the multiply is negative, we overflowed
+   and need to correct the result by subtracting 1 from the result.*/
+  R3 = 0xFFFF (Z);
+  R2 = R2 >> 16;		/* E >> 16 */
+  CC = R2 == R3;
+  R3 = 1 ;
+  R1 = R0 - R3;
+  IF CC R0 = R1;
+  RTS;
diff --git a/arch/blackfin/lib/umodsi3.S b/arch/blackfin/lib/umodsi3.S
new file mode 100644
index 0000000..b55ce96
--- /dev/null
+++ b/arch/blackfin/lib/umodsi3.S
@@ -0,0 +1,66 @@
+/*
+ * File:         arch/blackfin/lib/umodsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  libgcc1 routines for Blackfin 5xx
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.extern ___udivsi3;
+.globl	___umodsi3
+___umodsi3:
+
+	CC=R0==0;
+	IF CC JUMP .LRETURN_R0;		/* Return 0, if NR == 0 */
+	CC= R1==0;
+	IF CC JUMP .LRETURN_ZERO_VAL;	/* Return 0, if DR == 0 */
+	CC=R0==R1;
+	IF CC JUMP .LRETURN_ZERO_VAL;	/* Return 0, if NR == DR */
+	CC = R1 == 1;
+	IF CC JUMP .LRETURN_ZERO_VAL;	/* Return 0, if  DR == 1 */
+	CC = R0<R1 (IU);
+	IF CC JUMP .LRETURN_R0;		/* Return dividend (R0),IF NR<DR */
+
+	[--SP] = (R7:6);		/* Push registers and */
+	[--SP] = RETS;			/* Return address */
+	R7 = R0;			/* Copy of R0 */
+	R6 = R1;
+	SP += -12;			/* Should always provide this space */
+	CALL ___udivsi3;		/* Compute unsigned quotient using ___udiv32()*/
+	SP += 12;
+	R0 *= R6;			/* Quotient * divisor */
+	R0 = R7 - R0;			/* Dividend - (quotient * divisor) */
+	RETS = [SP++];			/* Pop return address */
+	( R7:6) = [SP++];		/* And registers */
+	RTS;				/* Return remainder */
+.LRETURN_ZERO_VAL:
+	R0 = 0;
+.LRETURN_R0:
+	RTS;
diff --git a/arch/blackfin/lib/umulsi3_highpart.S b/arch/blackfin/lib/umulsi3_highpart.S
new file mode 100644
index 0000000..aac8218
--- /dev/null
+++ b/arch/blackfin/lib/umulsi3_highpart.S
@@ -0,0 +1,23 @@
+.align 2
+.global ___umulsi3_highpart;
+.type ___umulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___umulsi3_highpart:
+	R2 = R1.H * R0.H, R3 = R1.L * R0.H (FU);
+	R0 = R1.L * R0.L, R1 = R1.H * R0.L (FU);
+	R0 >>= 16;
+	/* Unsigned multiplication has the nice property that we can
+	   ignore carry on this first addition.  */
+	R0 = R0 + R3;
+	R0 = R0 + R1;
+	cc = ac0;
+	R1 = cc;
+	R1 = PACK(R1.l,R0.h);
+	R0 = R1 + R2;
+	RTS;
diff --git a/arch/blackfin/mach-bf533/Kconfig b/arch/blackfin/mach-bf533/Kconfig
new file mode 100644
index 0000000..14297b3
--- /dev/null
+++ b/arch/blackfin/mach-bf533/Kconfig
@@ -0,0 +1,92 @@
+if (BF533 || BF532 || BF531)
+
+menu "BF533/2/1 Specific Configuration"
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config UART_ERROR
+	int "UART ERROR"
+	default 7
+config SPORT0_ERROR
+	int "SPORT0 ERROR"
+	default 7
+config SPI_ERROR
+	int "SPI ERROR"
+	default 7
+config SPORT1_ERROR
+	int "SPORT1 ERROR"
+	default 7
+config PPI_ERROR
+	int "PPI ERROR"
+	default 7
+config DMA_ERROR
+	int "DMA ERROR"
+	default 7
+config PLLWAKE_ERROR
+	int "PLL WAKEUP ERROR"
+	default 7
+
+config RTC_ERROR
+	int "RTC ERROR"
+	default 8
+config DMA0_PPI
+	int "DMA0 PPI"
+	default 8
+
+config DMA1_SPORT0RX
+	int "DMA1 (SPORT0 RX)"
+	default 9
+config DMA2_SPORT0TX
+	int "DMA2 (SPORT0 TX)"
+	default 9
+config DMA3_SPORT1RX
+	int "DMA3 (SPORT1 RX)"
+	default 9
+config DMA4_SPORT1TX
+	int "DMA4 (SPORT1 TX)"
+	default 9
+config DMA5_SPI
+	int "DMA5 (SPI)"
+	default 10
+config DMA6_UARTRX
+	int "DMA6 (UART0 RX)"
+	default 10
+config DMA7_UARTTX
+	int "DMA7 (UART0 TX)"
+	default 10
+config TIMER0
+	int "TIMER0"
+	default 11
+config TIMER1
+	int "TIMER1"
+	default 11
+config TIMER2
+	int "TIMER2"
+	default 11
+config PFA
+	int "PF Interrupt A"
+	default 12
+config PFB
+	int "PF Interrupt B"
+	default 12
+config MEMDMA0
+	int "MEMORY DMA0"
+	default 13
+config MEMDMA1
+	int "MEMORY DMA1"
+	default 13
+config WDTIMER
+	int "WATCH DOG TIMER"
+	default 13
+
+	help
+	  Enter the priority numbers between 7-13 ONLY.  Others are Reserved.
+	  This applies to all the above.  It is not recommended to assign the
+	  highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf533/Makefile b/arch/blackfin/mach-bf533/Makefile
new file mode 100644
index 0000000..76d2c2b
--- /dev/null
+++ b/arch/blackfin/mach-bf533/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf533/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_CPU_FREQ_BF533) += cpu.o
diff --git a/arch/blackfin/mach-bf533/boards/Makefile b/arch/blackfin/mach-bf533/boards/Makefile
new file mode 100644
index 0000000..12a631a
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/Makefile
@@ -0,0 +1,8 @@
+#
+# arch/blackfin/mach-bf533/boards/Makefile
+#
+
+obj-$(CONFIG_GENERIC_BOARD)            += generic_board.o
+obj-$(CONFIG_BFIN533_STAMP)            += stamp.o
+obj-$(CONFIG_BFIN533_EZKIT)            += ezkit.o
+obj-$(CONFIG_BFIN533_BLUETECHNIX_CM)   += cm_bf533.o
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
new file mode 100644
index 0000000..23a7f60
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -0,0 +1,267 @@
+/*
+ * File:         arch/blackfin/mach-bf533/boards/cm_bf533.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au> Copright 2005
+ *
+ * Created:      2005
+ * Description:  Board description file
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF533";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80",       /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,               /* Framework bus number */
+		.chip_select = 1,           /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,               /* Framework bus number */
+		.chip_select = 2,           /* Framework chip select. */
+		.platform_data = NULL,      /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.start = 0x20200300,
+		.end = 0x20200300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF0,
+		.end = IRQ_PF0,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20308000,
+		.end = 0x20308000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20308004,
+		.end = 0x20308004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF4,
+		.end = IRQ_PF4,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+static struct platform_device *cm_bf533_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+};
+
+static int __init cm_bf533_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(cm_bf533_init);
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
new file mode 100644
index 0000000..747298e
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -0,0 +1,224 @@
+/*
+ * File:         arch/blackfin/mach-bf533/ezkit.c
+ * Based on:     Orginal Work
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:      2005
+ * Description:
+ *
+ * Modified:     Robin Getz <rgetz@blackfin.uclinux.org> - Named the boards
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF533-EZKIT";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+/*
+ *  USB-LAN EzExtender board
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x20310300,
+		.end = 0x20310300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF9,
+		.end = IRQ_PF9,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *ezkit_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+};
+
+static int __init ezkit_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(ezkit_init);
diff --git a/arch/blackfin/mach-bf533/boards/generic_board.c b/arch/blackfin/mach-bf533/boards/generic_board.c
new file mode 100644
index 0000000..c0f43cc
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/generic_board.c
@@ -0,0 +1,95 @@
+/*
+ * File:         arch/blackfin/mach-bf533/generic_board.c
+ * Based on:     arch/blackfin/mach-bf533/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:      2005
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "UNKNOWN BOARD";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.start = 0x20300300,
+		.end = 0x20300300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTB,
+		.end = IRQ_PROG_INTB,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},{
+		/*
+		 *  denotes the flag pin and is used directly if
+		 *  CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+		 */
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+static struct platform_device *generic_board_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+};
+
+static int __init generic_board_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	return platform_add_devices(generic_board_devices, ARRAY_SIZE(generic_board_devices));
+}
+
+arch_initcall(generic_board_init);
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
new file mode 100644
index 0000000..d7b3a5d
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -0,0 +1,321 @@
+/*
+ * File:         arch/blackfin/mach-bf533/stamp.c
+ * Based on:     arch/blackfin/mach-bf533/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:      2005
+ * Description:  Board Info File for the BF533-STAMP
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF533-STAMP";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x20300300,
+		.end = 0x20300300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20300000,
+		.end = 0x20300000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF10,
+		.end = IRQ_PF10,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+	.ctl_reg	= 0x4, /* send zero */
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+	.cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+static struct bfin5xx_spi_chip ad5304_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 31250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_PBX)
+	{
+		.modalias	= "fxs-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 3,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias	= "fxo-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 2,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+	{
+		.modalias = "ad5304_spi",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 2,
+		.platform_data = NULL,
+		.controller_data = &ad5304_chip_info,
+		.mode = SPI_MODE_2,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+	.name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
new file mode 100644
index 0000000..99547c4
--- /dev/null
+++ b/arch/blackfin/mach-bf533/cpu.c
@@ -0,0 +1,161 @@
+/*
+ * File:         arch/blackfin/mach-bf533/cpu.c
+ * Based on:
+ * Author:       michael.kang@analog.com
+ *
+ * Created:
+ * Description:  clock scaling for the bf533
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=11059200 */
+#define VCO5 (CONFIG_CLKIN_HZ*45)	/*497664000 */
+#define VCO4 (CONFIG_CLKIN_HZ*36)	/*398131200 */
+#define VCO3 (CONFIG_CLKIN_HZ*27)	/*298598400 */
+#define VCO2 (CONFIG_CLKIN_HZ*18)	/*199065600 */
+#define VCO1 (CONFIG_CLKIN_HZ*9)	/*99532800 */
+#define VCO(x) VCO##x
+
+#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf533_freq_table[] = {
+	FREQ(1),
+	FREQ(3),
+	{VCO4, VCO4 / 2}, {VCO4, VCO4},
+	FREQ(5),
+	{0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf533_getfreq(unsigned int cpu)
+{
+	unsigned long cclk_mhz, vco_mhz;
+
+	/* The driver only support single cpu */
+	if (cpu == 0)
+		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+	else
+		cclk_mhz = -1;
+	return cclk_mhz;
+}
+
+static int bf533_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq, unsigned int relation)
+{
+	unsigned long cclk_mhz;
+	unsigned long vco_mhz;
+	unsigned long flags;
+	unsigned int index, vco_index;
+	int i;
+
+	struct cpufreq_freqs freqs;
+	if (cpufreq_frequency_table_target
+	    (policy, bf533_freq_table, target_freq, relation, &index))
+		return -EINVAL;
+	cclk_mhz = bf533_freq_table[index].frequency;
+	vco_mhz = bf533_freq_table[index].index;
+
+	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+	freqs.old = bf533_getfreq(0);
+	freqs.new = cclk_mhz;
+	freqs.cpu = 0;
+
+	pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+	         cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	local_irq_save(flags);
+	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+	local_irq_restore(flags);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	vco_mhz = get_vco();
+	cclk_mhz = get_cclk();
+	return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf533_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &bf533_freq_table);
+}
+
+static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
+{
+	int result;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	/*Now ,only support one cpu */
+	policy->cur = bf533_getfreq(0);
+	cpufreq_frequency_table_get_attr(bf533_freq_table, policy->cpu);
+	return cpufreq_frequency_table_cpuinfo(policy, bf533_freq_table);
+}
+
+static struct freq_attr *bf533_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bf533_driver = {
+	.verify = bf533_verify_speed,
+	.target = bf533_target,
+	.get = bf533_getfreq,
+	.init = __bf533_cpu_init,
+	.name = "bf533",
+	.owner = THIS_MODULE,
+	.attr = bf533_freq_attr,
+};
+
+static int __init bf533_cpu_init(void)
+{
+	return cpufreq_register_driver(&bf533_driver);
+}
+
+static void __exit bf533_cpu_exit(void)
+{
+	cpufreq_unregister_driver(&bf533_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for BF533 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf533_cpu_init);
+module_exit(bf533_cpu_exit);
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
new file mode 100644
index 0000000..4808edb
--- /dev/null
+++ b/arch/blackfin/mach-bf533/head.S
@@ -0,0 +1,774 @@
+/*
+ * File:         arch/blackfin/mach-bf533/head.S
+ * Based on:
+ * Author:       Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created:      1998
+ * Description:  bf533 startup file
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+#if CONFIG_DEBUG_KERNEL_START
+#include <asm/mach-common/def_LPBlackfin.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK	0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+	/* R0: argument of command line string, passed from uboot, save it */
+	R7 = R0;
+	/* Set the SYSCFG register */
+	R0 = 0x36;
+	/*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+	SYSCFG = R0;
+	R0 = 0;
+
+	/*Clear Out All the data and pointer  Registers*/
+	R1 = R0;
+	R2 = R0;
+	R3 = R0;
+	R4 = R0;
+	R5 = R0;
+	R6 = R0;
+
+	P0 = R0;
+	P1 = R0;
+	P2 = R0;
+	P3 = R0;
+	P4 = R0;
+	P5 = R0;
+
+	LC0 = r0;
+	LC1 = r0;
+	L0 = r0;
+	L1 = r0;
+	L2 = r0;
+	L3 = r0;
+
+	/* Clear Out All the DAG Registers*/
+	B0 = r0;
+	B1 = r0;
+	B2 = r0;
+	B3 = r0;
+
+	I0 = r0;
+	I1 = r0;
+	I2 = r0;
+	I3 = r0;
+
+	M0 = r0;
+	M1 = r0;
+	M2 = r0;
+	M3 = r0;
+
+#if CONFIG_DEBUG_KERNEL_START
+
+/*
+ * Set up a temporary Event Vector Table, so if something bad happens before
+ * the kernel is fully started, it doesn't vector off into the bootloaders
+ * table
+ */
+	P0.l = lo(EVT2);
+	P0.h = hi(EVT2);
+	P1.l = lo(EVT15);
+	P1.h = hi(EVT15);
+	P2.l = debug_kernel_start_trap;
+	P2.h = debug_kernel_start_trap;
+
+	RTS = P2;
+	RTI = P2;
+	RTX = P2;
+	RTN = P2;
+	RTE = P2;
+
+.Lfill_temp_vector_table:
+	[P0++] = P2;	/* Core Event Vector Table */
+	CC = P0 == P1;
+	if !CC JUMP .Lfill_temp_vector_table
+	P0 = r0;
+	P1 = r0;
+	P2 = r0;
+
+#endif
+
+	p0.h = hi(FIO_MASKA_C);
+	p0.l = lo(FIO_MASKA_C);
+	r0 = 0xFFFF(Z);
+	w[p0] = r0.L;	/* Disable all interrupts */
+	ssync;
+
+	p0.h = hi(FIO_MASKB_C);
+	p0.l = lo(FIO_MASKB_C);
+	r0 = 0xFFFF(Z);
+	w[p0] = r0.L;	/* Disable all interrupts */
+	ssync;
+
+	/* Turn off the icache */
+	p0.l = (IMEM_CONTROL & 0xFFFF);
+	p0.h = (IMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENICPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Turn off the dcache */
+	p0.l = (DMEM_CONTROL & 0xFFFF);
+	p0.h = (DMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENDCPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Initialise UART */
+	p0.h = hi(UART_LCR);
+	p0.l = lo(UART_LCR);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable DLL writes */
+	ssync;
+
+	p0.h = hi(UART_DLL);
+	p0.l = lo(UART_DLL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_DLH);
+	p0.l = lo(UART_DLH);
+	r0 = 0x00(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable UART clock */
+	ssync;
+
+	/* Initialize stack pointer */
+	sp.l = lo(INITIAL_STACK);
+	sp.h = hi(INITIAL_STACK);
+	fp = sp;
+	usp = sp;
+
+	/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+	call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+	call _start_dma_code;
+#endif
+
+	/* Code for initializing Async memory banks */
+
+	p2.h = hi(EBIU_AMBCTL1);
+	p2.l = lo(EBIU_AMBCTL1);
+	r0.h = hi(AMBCTL1VAL);
+	r0.l = lo(AMBCTL1VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMBCTL0);
+	p2.l = lo(EBIU_AMBCTL0);
+	r0.h = hi(AMBCTL0VAL);
+	r0.l = lo(AMBCTL0VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMGCTL);
+	p2.l = lo(EBIU_AMGCTL);
+	r0 = AMGCTLVAL;
+	w[p2] = r0;
+	ssync;
+
+	/* This section keeps the processor in supervisor mode
+	 * during kernel boot.  Switches to user mode at end of boot.
+	 * See page 3-9 of Hardware Reference manual for documentation.
+	 */
+
+	/* EVT15 = _real_start */
+
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _real_start;
+	p1.h = _real_start;
+	[p0] = p1;
+	csync;
+
+	p0.l = lo(IMASK);
+	p0.h = hi(IMASK);
+	p1.l = IMASK_IVG15;
+	p1.h = 0x0;
+	[p0] = p1;
+	csync;
+
+	raise 15;
+	p0.l = .LWAIT_HERE;
+	p0.h = .LWAIT_HERE;
+	reti = p0;
+#if defined(ANOMALY_05000281)
+	nop; nop; nop;
+#endif
+	rti;
+
+.LWAIT_HERE:
+	jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+	[ -- sp ] = reti;
+	p0.l = lo(WDOG_CTL);
+	p0.h = hi(WDOG_CTL);
+	r0 = 0xAD6(z);
+	w[p0] = r0;	/* watchdog off for now */
+	ssync;
+
+	/* Code update for BSS size == 0
+	 * Zero out the bss region.
+	 */
+
+	p1.l = ___bss_start;
+	p1.h = ___bss_start;
+	p2.l = ___bss_stop;
+	p2.h = ___bss_stop;
+	r0 = 0;
+	p2 -= p1;
+	lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
+.L_clear_bss:
+	B[p1++] = r0;
+
+	/* In case there is a NULL pointer reference
+	 * Zero out region before stext
+	 */
+
+	p1.l = 0x0;
+	p1.h = 0x0;
+	r0.l = __stext;
+	r0.h = __stext;
+	r0 = r0 >> 1;
+	p2 = r0;
+	r0 = 0;
+	lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
+.L_clear_zero:
+	W[p1++] = r0;
+
+/* pass the uboot arguments to the global value command line */
+	R0 = R7;
+	call _cmdline_init;
+
+	p1.l = __rambase;
+	p1.h = __rambase;
+	r0.l = __sdata;
+	r0.h = __sdata;
+	[p1] = r0;
+
+	p1.l = __ramstart;
+	p1.h = __ramstart;
+	p3.l = ___bss_stop;
+	p3.h = ___bss_stop;
+
+	r1 = p3;
+	[p1] = r1;
+
+	/*
+	 *  load the current thread pointer and stack
+	 */
+	r1.l = _init_thread_union;
+	r1.h = _init_thread_union;
+
+	r2.l = 0x2000;
+	r2.h = 0x0000;
+	r1 = r1 + r2;
+	sp = r1;
+	usp = sp;
+	fp = sp;
+	call _start_kernel;
+.L_exit:
+	jump.s	.L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+	p0.h = hi(SIC_IWR);
+	p0.l = lo(SIC_IWR);
+	r0.l = 0x1;
+	r0.h = 0x0;
+	[p0] = r0;
+	SSYNC;
+
+	/*
+	 *  Set PLL_CTL
+	 *   - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+	 *   - [8]     = BYPASS    : BYPASS the PLL, run CLKIN into CCLK/SCLK
+	 *   - [7]     = output delay (add 200ps of delay to mem signals)
+	 *   - [6]     = input delay (add 200ps of input delay to mem signals)
+	 *   - [5]     = PDWN      : 1=All Clocks off
+	 *   - [3]     = STOPCK    : 1=Core Clock off
+	 *   - [1]     = PLL_OFF   : 1=Disable Power to PLL
+	 *   - [0]     = DF        : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+	 *   all other bits set to zero
+	 */
+
+	p0.h = hi(PLL_LOCKCNT);
+	p0.l = lo(PLL_LOCKCNT);
+	r0 = 0x300(Z);
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITSET (R0, 24);
+	[P2] = R0;
+	SSYNC;
+
+	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
+	r0 = r0 << 9;                    /* Shift it over,                  */
+	r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
+	r0 = r1 | r0;
+	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
+	r1 = r1 << 8;                    /* Shift it over                   */
+	r0 = r1 | r0;                    /* add them all together           */
+
+	p0.h = hi(PLL_CTL);
+	p0.l = lo(PLL_CTL);              /* Load the address                */
+	cli r2;                          /* Disable interrupts              */
+	ssync;
+	w[p0] = r0.l;                    /* Set the value                   */
+	idle;                            /* Wait for the PLL to stablize    */
+	sti r2;                          /* Enable interrupts               */
+
+.Lcheck_again:
+	p0.h = hi(PLL_STAT);
+	p0.l = lo(PLL_STAT);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,5);
+	if ! CC jump .Lcheck_again;
+
+	/* Configure SCLK & CCLK Dividers */
+	r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+	p0.h = hi(PLL_DIV);
+	p0.l = lo(PLL_DIV);
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = lo(EBIU_SDRRC);
+	p0.h = hi(EBIU_SDRRC);
+	r0 = mem_SDRRC;
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = (EBIU_SDBCTL & 0xFFFF);
+	p0.h = (EBIU_SDBCTL >> 16);     /* SDRAM Memory Bank Control Register */
+	r0 = mem_SDBCTL;
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITCLR (R0, 24);
+	p0.h = hi(EBIU_SDSTAT);
+	p0.l = lo(EBIU_SDSTAT);
+	r2.l = w[p0];
+	cc = bittst(r2,3);
+	if !cc jump .Lskip;
+	NOP;
+	BITSET (R0, 23);
+.Lskip:
+	[P2] = R0;
+	SSYNC;
+
+	R0.L = lo(mem_SDGCTL);
+	R0.H = hi(mem_SDGCTL);
+	R1 = [p2];
+	R1 = R1 | R0;
+	[P2] = R1;
+	SSYNC;
+
+	p0.h = hi(SIC_IWR);
+	p0.l = lo(SIC_IWR);
+	r0.l = lo(IWR_ENABLE_ALL)
+	r0.h = hi(IWR_ENABLE_ALL)
+	[p0] = r0;
+	SSYNC;
+
+	RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+	/* No more interrupts to be handled*/
+	CLI R6;
+	SSYNC;
+
+#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+	p0.h = hi(FIO_INEN);
+	p0.l = lo(FIO_INEN);
+	r0.l = ~(1 << CONFIG_ENET_FLASH_PIN);
+	w[p0] = r0.l;
+
+	p0.h = hi(FIO_DIR);
+	p0.l = lo(FIO_DIR);
+	r0.l = (1 << CONFIG_ENET_FLASH_PIN);
+	w[p0] = r0.l;
+
+	p0.h = hi(FIO_FLAG_C);
+	p0.l = lo(FIO_FLAG_C);
+	r0.l = (1 << CONFIG_ENET_FLASH_PIN);
+	w[p0] = r0.l;
+#endif
+
+	/* Clear the bits 13-15 in SWRST if they werent cleared */
+	p0.h = hi(SWRST);
+	p0.l = lo(SWRST);
+	csync;
+	r0.l = w[p0];
+
+	/* Clear the IMASK register */
+	p0.h = hi(IMASK);
+	p0.l = lo(IMASK);
+	r0 = 0x0;
+	[p0] = r0;
+
+	/* Clear the ILAT register */
+	p0.h = hi(ILAT);
+	p0.l = lo(ILAT);
+	r0 = [p0];
+	[p0] = r0;
+	SSYNC;
+
+	/* Disable the WDOG TIMER */
+	p0.h = hi(WDOG_CTL);
+	p0.l = lo(WDOG_CTL);
+	r0.l = 0xAD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Clear the sticky bit incase it is already set */
+	p0.h = hi(WDOG_CTL);
+	p0.l = lo(WDOG_CTL);
+	r0.l = 0x8AD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Program the count value */
+	R0.l = 0x100;
+	R0.h = 0x0;
+	P0.h = hi(WDOG_CNT);
+	P0.l = lo(WDOG_CNT);
+	[P0] = R0;
+	SSYNC;
+
+	/* Program WDOG_STAT if necessary */
+	P0.h = hi(WDOG_CTL);
+	P0.l = lo(WDOG_CTL);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,1);
+	if !CC JUMP .LWRITESTAT;
+	CC = BITTST(R0,2);
+	if !CC JUMP .LWRITESTAT;
+	JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+	/* When watch dog timer is enabled, a write to STAT will load the contents of CNT to STAT */
+	R0 = 0x0000(z);
+	P0.h = hi(WDOG_STAT);
+	P0.l = lo(WDOG_STAT)
+	[P0] = R0;
+	SSYNC;
+
+.LSKIP_WRITE:
+	/* Enable the reset event */
+	P0.h = hi(WDOG_CTL);
+	P0.l = lo(WDOG_CTL);
+	R0 = W[P0](Z);
+	BITCLR(R0,1);
+	BITCLR(R0,2);
+	W[P0] = R0.L;
+	SSYNC;
+	NOP;
+
+	/* Enable the wdog counter */
+	R0 = W[P0](Z);
+	BITCLR(R0,4);
+	W[P0] = R0.L;
+	SSYNC;
+
+	IDLE;
+
+	RTS;
+
+#if CONFIG_DEBUG_KERNEL_START
+debug_kernel_start_trap:
+	/* Set up a temp stack in L1 - SDRAM might not be working  */
+	P0.L = lo(L1_DATA_A_START + 0x100);
+	P0.H = hi(L1_DATA_A_START + 0x100);
+	SP = P0;
+
+	/* Make sure the Clocks are the way I think they should be */
+	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
+	r0 = r0 << 9;                    /* Shift it over,                  */
+	r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
+	r0 = r1 | r0;
+	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
+	r1 = r1 << 8;                    /* Shift it over                   */
+	r0 = r1 | r0;                    /* add them all together           */
+
+	p0.h = hi(PLL_CTL);
+	p0.l = lo(PLL_CTL);              /* Load the address                */
+	cli r2;                          /* Disable interrupts              */
+	ssync;
+	w[p0] = r0.l;                    /* Set the value                   */
+	idle;                            /* Wait for the PLL to stablize    */
+	sti r2;                          /* Enable interrupts               */
+
+.Lcheck_again1:
+	p0.h = hi(PLL_STAT);
+	p0.l = lo(PLL_STAT);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,5);
+	if ! CC jump .Lcheck_again1;
+
+	/* Configure SCLK & CCLK Dividers */
+	r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+	p0.h = hi(PLL_DIV);
+	p0.l = lo(PLL_DIV);
+	w[p0] = r0.l;
+	ssync;
+
+	/* Make sure UART is enabled - you can never be sure */
+
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+
+#ifdef CONFIG_BAUD_9600
+#define CONSOLE_BAUD_RATE       9600
+#elif CONFIG_BAUD_19200
+#define CONSOLE_BAUD_RATE       19200
+#elif CONFIG_BAUD_38400
+#define CONSOLE_BAUD_RATE       38400
+#elif CONFIG_BAUD_57600
+#define CONSOLE_BAUD_RATE       57600
+#elif CONFIG_BAUD_115200
+#define CONSOLE_BAUD_RATE       115200
+#endif
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x00(Z);
+	w[p0] = r0.L;   /* To Turn off UART clocks */
+	ssync;
+
+	p0.h = hi(UART_LCR);
+	p0.l = lo(UART_LCR);
+	r0 = 0x83(Z);
+	w[p0] = r0.L;   /* To enable DLL writes */
+	ssync;
+
+	R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16));
+
+	p0.h = hi(UART_DLL);
+	p0.l = lo(UART_DLL);
+	r0 = 0xFF(Z);
+	r0 = R1 & R0;
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_DLH);
+	p0.l = lo(UART_DLH);
+	r1 >>= 8 ;
+	w[p0] = r1.L;
+	ssync;
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;   /* To enable UART clock */
+	ssync;
+
+	p0.h = hi(UART_LCR);
+	p0.l = lo(UART_LCR);
+	r0 = 0x03(Z);
+	w[p0] = r0.L;   /* To Turn on UART */
+	ssync;
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x01(Z);
+	w[p0] = r0.L;   /* To Turn on UART Clocks */
+	ssync;
+
+	P0.h = hi(UART_THR);
+	P0.l = lo(UART_THR);
+	P1.h = hi(UART_LSR);
+	P1.l = lo(UART_LSR);
+
+	R0.L = 'K';
+	call .Lwait_char;
+	R0.L='e';
+	call .Lwait_char;
+	R0.L='r';
+	call .Lwait_char;
+	R0.L='n'
+	call .Lwait_char;
+	R0.L='e'
+	call .Lwait_char;
+	R0.L='l';
+	call .Lwait_char;
+	R0.L=' ';
+	call .Lwait_char;
+	R0.L='c';
+	call .Lwait_char;
+	R0.L='r';
+	call .Lwait_char;
+	R0.L='a';
+	call .Lwait_char;
+	R0.L='s';
+	call .Lwait_char;
+	R0.L='h';
+	call .Lwait_char;
+	R0.L='\r';
+	call .Lwait_char;
+	R0.L='\n';
+	call .Lwait_char;
+
+	R0.L='S';
+	call .Lwait_char;
+	R0.L='E';
+	call .Lwait_char;
+	R0.L='Q'
+	call .Lwait_char;
+	R0.L='S'
+	call .Lwait_char;
+	R0.L='T';
+	call .Lwait_char;
+	R0.L='A';
+	call .Lwait_char;
+	R0.L='T';
+	call .Lwait_char;
+	R0.L='=';
+	call .Lwait_char;
+	R2 = SEQSTAT;
+	call .Ldump_reg;
+
+	R0.L=' ';
+	call .Lwait_char;
+	R0.L='R';
+	call .Lwait_char;
+	R0.L='E'
+	call .Lwait_char;
+	R0.L='T'
+	call .Lwait_char;
+	R0.L='X';
+	call .Lwait_char;
+	R0.L='=';
+	call .Lwait_char;
+	R2 = RETX;
+	call .Ldump_reg;
+
+	R0.L='\r';
+	call .Lwait_char;
+	R0.L='\n';
+	call .Lwait_char;
+
+.Ldebug_kernel_start_trap_done:
+	JUMP    .Ldebug_kernel_start_trap_done;
+.Ldump_reg:
+	R3 = 32;
+	R4 = 0x0F;
+	R5 = ':';  /* one past 9 */
+
+.Ldump_reg2:
+	R0 = R2;
+	R3 += -4;
+	R0 >>>= R3;
+	R0 = R0 & R4;
+	R0 += 0x30;
+	CC = R0 <= R5;
+	if CC JUMP .Ldump_reg1;
+	R0 += 7;
+
+.Ldump_reg1:
+	R1.l = W[P1];
+	CC = BITTST(R1, 5);
+	if !CC JUMP .Ldump_reg1;
+	W[P0] = r0;
+
+	CC = R3 == 0;
+	if !CC JUMP .Ldump_reg2
+	RTS;
+
+.Lwait_char:
+	R1.l = W[P1];
+	CC = BITTST(R1, 5);
+	if !CC JUMP .Lwait_char;
+	W[P0] = r0;
+	RTS;
+
+#endif  /* CONFIG_DEBUG_KERNEL_START  */
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long   0
+__ramstart:
+.long   0
+__ramend:
+.long   0
diff --git a/arch/blackfin/mach-bf533/ints-priority.c b/arch/blackfin/mach-bf533/ints-priority.c
new file mode 100644
index 0000000..36a6933
--- /dev/null
+++ b/arch/blackfin/mach-bf533/ints-priority.c
@@ -0,0 +1,65 @@
+/*
+ * File:         arch/blackfin/mach-bf533/ints-priority.c
+ * Based on:
+ * Author:       Michael Hennerich
+ *
+ * Created:      ?
+ * Description:  Set up the interupt priorities
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+	/* Program the IAR0 Register with the configured priority */
+	bfin_write_SIC_IAR0(((CONFIG_PLLWAKE_ERROR - 7) << PLLWAKE_ERROR_POS) |
+			    ((CONFIG_DMA_ERROR - 7) << DMA_ERROR_POS) |
+			    ((CONFIG_PPI_ERROR - 7) << PPI_ERROR_POS) |
+			    ((CONFIG_SPORT0_ERROR - 7) << SPORT0_ERROR_POS) |
+			    ((CONFIG_SPI_ERROR - 7) << SPI_ERROR_POS) |
+			    ((CONFIG_SPORT1_ERROR - 7) << SPORT1_ERROR_POS) |
+			    ((CONFIG_UART_ERROR - 7) << UART_ERROR_POS) |
+			    ((CONFIG_RTC_ERROR - 7) << RTC_ERROR_POS));
+
+	bfin_write_SIC_IAR1(((CONFIG_DMA0_PPI - 7) << DMA0_PPI_POS) |
+			    ((CONFIG_DMA1_SPORT0RX - 7) << DMA1_SPORT0RX_POS) |
+			    ((CONFIG_DMA2_SPORT0TX - 7) << DMA2_SPORT0TX_POS) |
+			    ((CONFIG_DMA3_SPORT1RX - 7) << DMA3_SPORT1RX_POS) |
+			    ((CONFIG_DMA4_SPORT1TX - 7) << DMA4_SPORT1TX_POS) |
+			    ((CONFIG_DMA5_SPI - 7) << DMA5_SPI_POS) |
+			    ((CONFIG_DMA6_UARTRX - 7) << DMA6_UARTRX_POS) |
+			    ((CONFIG_DMA7_UARTTX - 7) << DMA7_UARTTX_POS));
+
+	bfin_write_SIC_IAR2(((CONFIG_TIMER0 - 7) << TIMER0_POS) |
+			    ((CONFIG_TIMER1 - 7) << TIMER1_POS) |
+			    ((CONFIG_TIMER2 - 7) << TIMER2_POS) |
+			    ((CONFIG_PFA - 7) << PFA_POS) |
+			    ((CONFIG_PFB - 7) << PFB_POS) |
+			    ((CONFIG_MEMDMA0 - 7) << MEMDMA0_POS) |
+			    ((CONFIG_MEMDMA1 - 7) << MEMDMA1_POS) |
+			    ((CONFIG_WDTIMER - 7) << WDTIMER_POS));
+
+	SSYNC();
+}
diff --git a/arch/blackfin/mach-bf537/Kconfig b/arch/blackfin/mach-bf537/Kconfig
new file mode 100644
index 0000000..cc9ae38
--- /dev/null
+++ b/arch/blackfin/mach-bf537/Kconfig
@@ -0,0 +1,141 @@
+if (BF537 || BF534 || BF536)
+
+menu "BF537 Specific Configuration"
+
+comment "PORT F/G Selection"
+choice
+	prompt "Select BF537/6/4 default GPIO PFx PORTx"
+	help
+	  Quick Hack for BF537/6/4 default GPIO PFx PORTF.
+
+config BF537_PORT_F
+	bool "Select BF537/6/4 default GPIO PFx PORTF"
+	depends on (BF537 || BF536 || BF534)
+	help
+	  Quick Hack for BF537/6/4 default GPIO PFx PORTF.
+
+config BF537_PORT_G
+	bool "Select BF537/6/4 default GPIO PFx PORTG"
+	depends on (BF537 || BF536 || BF534)
+	help
+	  Quick Hack for BF537/6/4 default GPIO PFx PORTG.
+
+config BF537_PORT_H
+	bool "Select BF537/6/4 default GPIO PFx PORTH"
+	depends on (BF537 || BF536 || BF534)
+	help
+	  Quick Hack for BF537/6/4 default GPIO PFx PORTH
+	  Use only when Blackfin EMAC support is not required.
+
+endchoice
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+	int "IRQ_PLL_WAKEUP"
+	default 7
+config IRQ_DMA_ERROR
+	int "IRQ_DMA_ERROR Generic"
+	default 7
+config IRQ_ERROR
+	int "IRQ_ERROR: CAN MAC SPORT0 SPORT1 SPI UART0 UART1"
+	default 7
+config IRQ_RTC
+	int "IRQ_RTC"
+	default 8
+config IRQ_PPI
+	int "IRQ_PPI"
+	default 8
+config IRQ_SPORT0_RX
+	int "IRQ_SPORT0_RX"
+	default 9
+config IRQ_SPORT0_TX
+	int "IRQ_SPORT0_TX"
+	default 9
+config IRQ_SPORT1_RX
+	int "IRQ_SPORT1_RX"
+	default 9
+config IRQ_SPORT1_TX
+	int "IRQ_SPORT1_TX"
+	default 9
+config IRQ_TWI
+	int "IRQ_TWI"
+	default 10
+config IRQ_SPI
+	int "IRQ_SPI"
+	default 10
+config IRQ_UART0_RX
+	int "IRQ_UART0_RX"
+	default 10
+config IRQ_UART0_TX
+	int "IRQ_UART0_TX"
+	default 10
+config IRQ_UART1_RX
+	int "IRQ_UART1_RX"
+	default 10
+config IRQ_UART1_TX
+	int "IRQ_UART1_TX"
+	default 10
+config IRQ_CAN_RX
+	int "IRQ_CAN_RX"
+	default 11
+config IRQ_CAN_TX
+	int "IRQ_CAN_TX"
+	default 11
+config IRQ_MAC_RX
+	int "IRQ_MAC_RX"
+	default 11
+config IRQ_MAC_TX
+	int "IRQ_MAC_TX"
+	default 11
+config IRQ_TMR0
+	int "IRQ_TMR0"
+	default 12
+config IRQ_TMR1
+	int "IRQ_TMR1"
+	default 12
+config IRQ_TMR2
+	int "IRQ_TMR2"
+	default 12
+config IRQ_TMR3
+	int "IRQ_TMR3"
+	default 12
+config IRQ_TMR4
+	int "IRQ_TMR4"
+	default 12
+config IRQ_TMR5
+	int "IRQ_TMR5"
+	default 12
+config IRQ_TMR6
+	int "IRQ_TMR6"
+	default 12
+config IRQ_TMR7
+	int "IRQ_TMR7"
+	default 12
+config IRQ_PROG_INTA
+	int "IRQ_PROG_INTA"
+	default 12
+config IRQ_PORTG_INTB
+	int "IRQ_PORTG_INTB"
+	default 12
+config IRQ_MEM_DMA0
+	int "IRQ_MEM_DMA0"
+	default 13
+config IRQ_MEM_DMA1
+	int "IRQ_MEM_DMA1"
+	default 13
+config IRQ_WATCH
+	int "IRQ_WATCH"
+	default 13
+
+	help
+	  Enter the priority numbers between 7-13 ONLY.  Others are Reserved.
+	  This applies to all the above.  It is not recommended to assign the
+	  highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf537/Makefile b/arch/blackfin/mach-bf537/Makefile
new file mode 100644
index 0000000..f32d442
--- /dev/null
+++ b/arch/blackfin/mach-bf537/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf537/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_CPU_FREQ)   += cpu.o
diff --git a/arch/blackfin/mach-bf537/boards/Makefile b/arch/blackfin/mach-bf537/boards/Makefile
new file mode 100644
index 0000000..23323ca
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf537/boards/Makefile
+#
+
+obj-y					+= eth_mac.o
+obj-$(CONFIG_GENERIC_BOARD)		+= generic_board.o
+obj-$(CONFIG_BFIN537_STAMP)		+= stamp.o led.o
+obj-$(CONFIG_BFIN537_BLUETECHNIX_CM)	+= cm_bf537.o
+obj-$(CONFIG_PNAV10)			+= pnav10.o
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
new file mode 100644
index 0000000..6a60618
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -0,0 +1,364 @@
+/*
+ * File:         arch/blackfin/mach-bf537/boards/cm_bf537.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:      2005
+ * Description:  Board description file
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF537";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+	{
+		.modalias = "ad9960-spi",
+		.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 1,
+		.controller_data = &ad9960_spi_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc_dummy",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 7,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.start = 0x20200300,
+		.end = 0x20200300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF14,
+		.end = IRQ_PF14,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		},
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20308000,
+		.end = 0x20308000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20308004,
+		.end = 0x20308004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PG15,
+		.end = IRQ_PG15,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20200000,
+		.end = 0x20200000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+static struct platform_device *cm_bf537_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+};
+
+static int __init cm_bf537_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(cm_bf537_init);
diff --git a/arch/blackfin/mach-bf537/boards/eth_mac.c b/arch/blackfin/mach-bf537/boards/eth_mac.c
new file mode 100644
index 0000000..e129a08
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/eth_mac.c
@@ -0,0 +1,51 @@
+/*
+ *  arch/blackfin/mach-bf537/board/eth_mac.c
+ *
+ *  Copyright (C) 2007 Analog Devices, 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/module.h>
+#include <asm/blackfin.h>
+
+#if	defined(CONFIG_GENERIC_BOARD) \
+	|| defined(CONFIG_BFIN537_STAMP)
+
+/*
+ * Currently the MAC address is saved in Flash by U-Boot
+ */
+#define FLASH_MAC	0x203f0000
+
+void get_bf537_ether_addr(char *addr)
+{
+	unsigned int flash_mac = (unsigned int) FLASH_MAC;
+	*(u32 *)(&(addr[0])) = bfin_read32(flash_mac);
+	flash_mac += 4;
+	*(u16 *)(&(addr[4])) = bfin_read16(flash_mac);
+}
+
+#else
+
+/*
+ * Provide MAC address function for other specific board setting
+ */
+void get_bf537_ether_addr(char *addr)
+{
+	printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n",__FILE__);
+}
+
+#endif
+
+EXPORT_SYMBOL(get_bf537_ether_addr);
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
new file mode 100644
index 0000000..9019c0e
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -0,0 +1,445 @@
+/*
+ * File:         arch/blackfin/mach-bf537/boards/generic_board.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "UNKNOWN BOARD";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+	{
+		.start = 0x20310000, /* IO PORT */
+		.end = 0x20312000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20311000, /* Attribute Memeory */
+		.end = 0x20311FFF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTA,
+		.end = IRQ_PROG_INTA,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},{
+		.start = IRQ_PF4,
+		.end = IRQ_PF4,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},{
+		.start = 6, /* Card Detect PF6 */
+		.end = 6,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+	.name = "bfin_cf_pcmcia",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+	.resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x20300300,
+		.end = 0x20300300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTB,
+		.end = IRQ_PROG_INTB,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},{
+		/*
+		 *  denotes the flag pin and is used directly if
+		 *  CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+		 */
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+	{
+		.start = 0x20340000,
+		.end = 0x20340000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20340004,
+		.end = 0x20340004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTA,
+		.end = IRQ_PROG_INTA,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},{
+		.start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
+		.end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+	unsigned short mask = (1<<CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+	bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+	if (is_on)
+		bfin_write_FIO_FLAG_S(mask);
+	else
+		bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+	.potpg = 10,
+	.power = 250,		/* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+	.port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+	.name = "sl811-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &sl811_priv,
+	},
+	.num_resources = ARRAY_SIZE(sl811_hcd_resources),
+	.resource = sl811_hcd_resources,
+};
+
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20360000,
+		.end = 0x20360000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20360004,
+		.end = 0x20360004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTA,
+		.end = IRQ_PROG_INTA,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},{
+		.start = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
+		.end = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20300000,
+		.end = 0x20300000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+	{
+		.modalias = "ad9960-spi",
+		.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 1,
+		.controller_data = &ad9960_spi_chip_info,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+	.name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+	&bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+	&sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+	&bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/boards/led.S b/arch/blackfin/mach-bf537/boards/led.S
new file mode 100644
index 0000000..4e9ea42
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/led.S
@@ -0,0 +1,183 @@
+/****************************************************
+ * LED1 ---- PF6        LED2 ---- PF7               *
+ * LED3 ---- PF8        LED4 ---- PF9               *
+ * LED5 ---- PF10       LED6 ---- PF11              *
+ ****************************************************/
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+/* All functions in this file save the registers they uses.
+   So there is no need to save any registers before calling them.  */
+
+	.text;
+
+/* Initialize LEDs.  */
+
+ENTRY(_led_init)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R0;
+	[--SP] = R1;
+	[--SP] = R2;
+	R1 = PF6|PF7|PF8|PF9|PF10|PF11 (Z);
+	R2 = ~R1;
+
+	P0.H = hi(PORTF_FER);
+	P0.L = lo(PORTF_FER);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 & R2;
+	W[P0] = R0.L;
+	SSYNC;
+
+	P0.H = hi(PORTFIO_DIR);
+	P0.L = lo(PORTFIO_DIR);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 | R1;
+	W[P0] = R0.L;
+	SSYNC;
+
+	P0.H = hi(PORTFIO_INEN);
+	P0.L = lo(PORTFIO_INEN);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 & R2;
+	W[P0] = R0.L;
+	SSYNC;
+
+	R2 = [SP++];
+	R1 = [SP++];
+	R0 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_init, .-_led_init
+
+/* Set one LED on. Leave other LEDs unchanged.
+   It expects the LED number passed through R0.  */
+
+ENTRY(_led_on)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R1;
+	CALL _led_init;
+	R1 = 1;
+	R0 += 5;
+	R1 <<= R0;
+	P0.H = hi(PORTFIO);
+	P0.L = lo(PORTFIO);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 | R1;
+	W[P0] = R0.L;
+	SSYNC;
+	R1 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_on, .-_led_on
+
+/* Set one LED off. Leave other LEDs unchanged.  */
+
+ENTRY(_led_off)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R1;
+	CALL _led_init;
+	R1 = 1;
+	R0 += 5;
+	R1 <<= R0;
+	R1 = ~R1;
+	P0.H = hi(PORTFIO);
+	P0.L = lo(PORTFIO);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 & R1;
+	W[P0] = R0.L;
+	SSYNC;
+	R1 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_off, .-_led_off
+
+/* Toggle one LED. Leave other LEDs unchanged.  */
+
+ENTRY(_led_toggle)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R1;
+	CALL _led_init;
+	R1 = 1;
+	R0 += 5;
+	R1 <<= R0;
+	P0.H = hi(PORTFIO);
+	P0.L = lo(PORTFIO);
+	R0 = W[P0](Z);
+	SSYNC;
+	R0 = R0 ^ R1;
+	W[P0] = R0.L;
+	SSYNC;
+	R1 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_toggle, .-_led_toggle
+
+/* Display the number using LEDs in binary format.  */
+
+ENTRY(_led_disp_num)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R1;
+	[--SP] = R2;
+	CALL _led_init;
+	R1 = 0x3f(X);
+	R0 = R0 & R1;
+	R2 = 6(X);
+	R0 <<= R2;
+	R1 <<= R2;
+	P0.H = hi(PORTFIO);
+	P0.L = lo(PORTFIO);
+	R2 = W[P0](Z);
+	SSYNC;
+	R1 = ~R1;
+	R2 = R2 & R1;
+	R2 = R2 | R0;
+	W[P0] = R2.L;
+	SSYNC;
+	R2 = [SP++];
+	R1 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_disp_num, .-_led_disp_num
+
+/* Toggle the number using LEDs in binary format.  */
+
+ENTRY(_led_toggle_num)
+	LINK 12;
+	[--SP] = P0;
+	[--SP] = R1;
+	[--SP] = R2;
+	CALL _led_init;
+	R1 = 0x3f(X);
+	R0 = R0 & R1;
+	R1 = 6(X);
+	R0 <<= R1;
+	P0.H = hi(PORTFIO);
+	P0.L = lo(PORTFIO);
+	R1 = W[P0](Z);
+	SSYNC;
+	R1 = R1 ^ R0;
+	W[P0] = R1.L;
+	SSYNC;
+	R2 = [SP++];
+	R1 = [SP++];
+	P0 = [SP++];
+	UNLINK;
+	RTS;
+	.size	_led_toggle_num, .-_led_toggle_num
+
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
new file mode 100644
index 0000000..40d3a1b
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -0,0 +1,523 @@
+/*
+ * File:         arch/blackfin/mach-bf537/boards/stamp.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "PNAV-1.0";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+	{
+		.start = 0x20310000, /* IO PORT */
+		.end = 0x20312000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20311000, /* Attribute Memeory */
+		.end = 0x20311FFF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF4,
+		.end = IRQ_PF4,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},{
+		.start = 6, /* Card Detect PF6 */
+		.end = 6,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+	.name = "bfin_cf_pcmcia",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+	.resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x20300300,
+		.end = 0x20300300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+	{
+		.start = 0x20340000,
+		.end = 0x20340000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20340004,
+		.end = 0x20340004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = CONFIG_USB_SL811_BFIN_IRQ,
+		.end = CONFIG_USB_SL811_BFIN_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+	unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+	bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+	if (is_on)
+		bfin_write_FIO_FLAG_S(mask);
+	else
+		bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+	.potpg = 10,
+	.power = 250,       /* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+	.port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+	.name = "sl811-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &sl811_priv,
+	},
+	.num_resources = ARRAY_SIZE(sl811_hcd_resources),
+	.resource = sl811_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20360000,
+		.end = 0x20360000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20360004,
+		.end = 0x20360004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+		.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20300000,
+		.end = 0x20300000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+	.ctl_reg	= 0x4, /* send zero */
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+	.cs_change_per_word = 1,
+};
+#endif
+
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+	.cs_change_per_word = 1,
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+	.model			= 7877,
+	.vref_delay_usecs	= 50,	/* internal, no capacitor */
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.pressure_max		= 1000,
+	.pressure_min		= 0,
+	.stopacq_polarity 	= 1,
+	.first_conversion_delay = 3,
+	.acquisition_time 	= 1,
+	.averaging 		= 1,
+	.pen_down_acc_interval 	= 1,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+	{
+		.modalias = "ad9960-spi",
+		.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 1,
+		.controller_data = &ad9960_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc_dummy",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 7,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_PBX)
+	{
+		.modalias	= "fxs-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 3,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias	= "fxo-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 2,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+{
+	.modalias		= "ad7877",
+	.platform_data		= &bfin_ad7877_ts_info,
+	.irq			= IRQ_PF2,
+	.max_speed_hz		= 12500000,     /* max spi clock (SCK) speed in HZ */
+	.bus_num		= 1,
+	.chip_select  		= 5,
+	.controller_data = &spi_ad7877_chip_info,
+},
+#endif
+
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+	.name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+	&bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+	&sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+	&bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info,
+				ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
new file mode 100644
index 0000000..ba2f875
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -0,0 +1,615 @@
+/*
+ * File:         arch/blackfin/mach-bf537/boards/stamp.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF537-STAMP";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#define ISP1761_BASE       0x203C0000
+#define ISP1761_IRQ        IRQ_PF7
+
+#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
+static struct resource bfin_isp1761_resources[] = {
+	[0] = {
+		.name	= "isp1761-regs",
+		.start  = ISP1761_BASE + 0x00000000,
+		.end    = ISP1761_BASE + 0x000fffff,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = ISP1761_IRQ,
+		.end    = ISP1761_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_isp1761_device = {
+	.name           = "isp1761",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(bfin_isp1761_resources),
+	.resource       = bfin_isp1761_resources,
+};
+
+static struct platform_device *bfin_isp1761_devices[] = {
+	&bfin_isp1761_device,
+};
+
+int __init bfin_isp1761_init(void)
+{
+	unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices);
+
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
+
+	return platform_add_devices(bfin_isp1761_devices, num_devices);
+}
+
+void __exit bfin_isp1761_exit(void)
+{
+	platform_device_unregister(&bfin_isp1761_device);
+}
+
+arch_initcall(bfin_isp1761_init);
+#endif
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+	{
+		.start = 0x20310000, /* IO PORT */
+		.end = 0x20312000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20311000, /* Attribute Memeory */
+		.end = 0x20311FFF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF4,
+		.end = IRQ_PF4,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},{
+		.start = 6, /* Card Detect PF6 */
+		.end = 6,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+	.name = "bfin_cf_pcmcia",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+	.resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x20300300,
+		.end = 0x20300300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+	{
+		.start = 0x20340000,
+		.end = 0x20340000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20340004,
+		.end = 0x20340004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = CONFIG_USB_SL811_BFIN_IRQ,
+		.end = CONFIG_USB_SL811_BFIN_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+	unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+	bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+	bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+	if (is_on)
+		bfin_write_FIO_FLAG_S(mask);
+	else
+		bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+	.potpg = 10,
+	.power = 250,       /* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+	.port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+	.name = "sl811-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &sl811_priv,
+	},
+	.num_resources = ARRAY_SIZE(sl811_hcd_resources),
+	.resource = sl811_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x20360000,
+		.end = 0x20360000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x20360004,
+		.end = 0x20360004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+		.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+	{
+		.start = 0x20300000,
+		.end = 0x20300000 + 0x100,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF7,
+		.end = IRQ_PF7,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device net2272_bfin_device = {
+	.name = "net2272",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(net2272_bfin_resources),
+	.resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+	.ctl_reg	= 0x4, /* send zero */
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+	.cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+static struct bfin5xx_spi_chip ad5304_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+//	.cs_change_per_word = 1,
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+	.model			= 7877,
+	.vref_delay_usecs	= 50,	/* internal, no capacitor */
+	.x_plate_ohms		= 419,
+	.y_plate_ohms		= 486,
+	.pressure_max		= 1000,
+	.pressure_min		= 0,
+	.stopacq_polarity 	= 1,
+	.first_conversion_delay = 3,
+	.acquisition_time 	= 1,
+	.averaging 		= 1,
+	.pen_down_acc_interval 	= 1,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+	|| defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+	{
+		.modalias = "ad9960-spi",
+		.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 1,
+		.controller_data = &ad9960_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc_dummy",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 0,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_PBX)
+	{
+		.modalias	= "fxs-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 3,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+	{
+		.modalias	= "fxo-spi",
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select	= 2,
+		.controller_data= &spi_si3xxx_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+	{
+		.modalias = "ad5304_spi",
+		.max_speed_hz = 1250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 2,
+		.platform_data = NULL,
+		.controller_data = &ad5304_chip_info,
+		.mode = SPI_MODE_2,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+	{
+		.modalias		= "ad7877",
+		.platform_data		= &bfin_ad7877_ts_info,
+		.irq			= IRQ_PF6,
+		.max_speed_hz	= 12500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num	= 1,
+		.chip_select  = 1,
+		.controller_data = &spi_ad7877_chip_info,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+	.name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device bfin_uart_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart_resources),
+	.resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+	&bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+	&sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+	&net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+	&bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+	&bfin_uart_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+	&bfin_sport0_uart_device,
+	&bfin_sport1_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info,
+				ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/cpu.c b/arch/blackfin/mach-bf537/cpu.c
new file mode 100644
index 0000000..2d83b7e
--- /dev/null
+++ b/arch/blackfin/mach-bf537/cpu.c
@@ -0,0 +1,161 @@
+/*
+ * File:         arch/blackfin/mach-bf537/cpu.c
+ * Based on:
+ * Author:       michael.kang@analog.com
+ *
+ * Created:
+ * Description:  clock scaling for the bf537
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=11059200 */
+#define VCO5 (CONFIG_CLKIN_HZ*45)	/*497664000 */
+#define VCO4 (CONFIG_CLKIN_HZ*36)	/*398131200 */
+#define VCO3 (CONFIG_CLKIN_HZ*27)	/*298598400 */
+#define VCO2 (CONFIG_CLKIN_HZ*18)	/*199065600 */
+#define VCO1 (CONFIG_CLKIN_HZ*9)	/*99532800 */
+#define VCO(x) VCO##x
+
+#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf537_freq_table[] = {
+	FREQ(1),
+	FREQ(3),
+	{VCO4, VCO4 / 2}, {VCO4, VCO4},
+	FREQ(5),
+	{0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf537_getfreq(unsigned int cpu)
+{
+	unsigned long cclk_mhz, vco_mhz;
+
+	/* The driver only support single cpu */
+	if (cpu == 0)
+		dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+	else
+		cclk_mhz = -1;
+	return cclk_mhz;
+}
+
+static int bf537_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq, unsigned int relation)
+{
+	unsigned long cclk_mhz;
+	unsigned long vco_mhz;
+	unsigned long flags;
+	unsigned int index, vco_index;
+	int i;
+
+	struct cpufreq_freqs freqs;
+	if (cpufreq_frequency_table_target
+	    (policy, bf537_freq_table, target_freq, relation, &index))
+		return -EINVAL;
+	cclk_mhz = bf537_freq_table[index].frequency;
+	vco_mhz = bf537_freq_table[index].index;
+
+	dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+	freqs.old = bf537_getfreq(0);
+	freqs.new = cclk_mhz;
+	freqs.cpu = 0;
+
+	pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+	         cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	local_irq_save(flags);
+	dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+	local_irq_restore(flags);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	vco_mhz = get_vco();
+	cclk_mhz = get_cclk();
+	return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf537_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &bf537_freq_table);
+}
+
+static int __init __bf537_cpu_init(struct cpufreq_policy *policy)
+{
+	int result;
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	/*Now ,only support one cpu */
+	policy->cur = bf537_getfreq(0);
+	cpufreq_frequency_table_get_attr(bf537_freq_table, policy->cpu);
+	return cpufreq_frequency_table_cpuinfo(policy, bf537_freq_table);
+}
+
+static struct freq_attr *bf537_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver bf537_driver = {
+	.verify = bf537_verify_speed,
+	.target = bf537_target,
+	.get = bf537_getfreq,
+	.init = __bf537_cpu_init,
+	.name = "bf537",
+	.owner = THIS_MODULE,
+	.attr = bf537_freq_attr,
+};
+
+static int __init bf537_cpu_init(void)
+{
+	return cpufreq_register_driver(&bf537_driver);
+}
+
+static void __exit bf537_cpu_exit(void)
+{
+	cpufreq_unregister_driver(&bf537_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for BF537 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf537_cpu_init);
+module_exit(bf537_cpu_exit);
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
new file mode 100644
index 0000000..d104e1d
--- /dev/null
+++ b/arch/blackfin/mach-bf537/head.S
@@ -0,0 +1,602 @@
+/*
+ * File:         arch/blackfin/mach-bf537/head.S
+ * Based on:     arch/blackfin/mach-bf533/head.S
+ * Author:       Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created:      1998
+ * Description:  Startup code for Blackfin BF537
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK   0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+	/* R0: argument of command line string, passed from uboot, save it */
+	R7 = R0;
+	/* Set the SYSCFG register */
+	R0 = 0x36;
+	SYSCFG = R0;   /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+	R0 = 0;
+
+	/* Clear Out All the data and pointer  Registers*/
+	R1 = R0;
+	R2 = R0;
+	R3 = R0;
+	R4 = R0;
+	R5 = R0;
+	R6 = R0;
+
+	P0 = R0;
+	P1 = R0;
+	P2 = R0;
+	P3 = R0;
+	P4 = R0;
+	P5 = R0;
+
+	LC0 = r0;
+	LC1 = r0;
+	L0 = r0;
+	L1 = r0;
+	L2 = r0;
+	L3 = r0;
+
+	/* Clear Out All the DAG Registers*/
+	B0 = r0;
+	B1 = r0;
+	B2 = r0;
+	B3 = r0;
+
+	I0 = r0;
+	I1 = r0;
+	I2 = r0;
+	I3 = r0;
+
+	M0 = r0;
+	M1 = r0;
+	M2 = r0;
+	M3 = r0;
+
+	/* Turn off the icache */
+	p0.l = (IMEM_CONTROL & 0xFFFF);
+	p0.h = (IMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENICPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Turn off the dcache */
+	p0.l = (DMEM_CONTROL & 0xFFFF);
+	p0.h = (DMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENDCPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Initialise General-Purpose I/O Modules on BF537 */
+	/* Rev 0.0 Anomaly 05000212 - PORTx_FER,
+	 * PORT_MUX Registers Do Not accept "writes" correctly:
+	 */
+	p0.h = hi(BFIN_PORT_MUX);
+	p0.l = lo(BFIN_PORT_MUX);
+#ifdef ANOMALY_05000212
+	R0.L = W[P0]; /* Read */
+	SSYNC;
+#endif
+	R0 = (PGDE_UART | PFTE_UART)(Z);
+#ifdef ANOMALY_05000212
+	W[P0] = R0.L; /* Write */
+	SSYNC;
+#endif
+	W[P0] = R0.L; /* Enable both UARTS */
+	SSYNC;
+
+	p0.h = hi(PORTF_FER);
+	p0.l = lo(PORTF_FER);
+#ifdef ANOMALY_05000212
+	R0.L = W[P0]; /* Read */
+	SSYNC;
+#endif
+	R0 = 0x000F(Z);
+#ifdef ANOMALY_05000212
+	W[P0] = R0.L; /* Write */
+	SSYNC;
+#endif
+	/* Enable peripheral function of PORTF for UART0 and UART1 */
+	W[P0] = R0.L;
+	SSYNC;
+
+#if !defined(CONFIG_BF534)
+	p0.h = hi(EMAC_SYSTAT);
+	p0.l = lo(EMAC_SYSTAT);
+	R0.h = 0xFFFF; /* Clear EMAC Interrupt Status bits */
+	R0.l = 0xFFFF;
+	[P0] = R0;
+	SSYNC;
+#endif
+
+#ifdef CONFIG_BF537_PORT_H
+	p0.h = hi(PORTH_FER);
+	p0.l = lo(PORTH_FER);
+	R0.L = W[P0]; /* Read */
+	SSYNC;
+	R0 = 0x0000;
+	W[P0] = R0.L; /* Write */
+	SSYNC;
+	W[P0] = R0.L; /* Disable peripheral function of PORTH */
+	SSYNC;
+#endif
+
+	/*Initialise UART*/
+	p0.h = hi(UART_LCR);
+	p0.l = lo(UART_LCR);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable DLL writes */
+	ssync;
+
+	p0.h = hi(UART_DLL);
+	p0.l = lo(UART_DLL);
+	r0 = 0x00(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_DLH);
+	p0.l = lo(UART_DLH);
+	r0 = 0x00(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable UART clock */
+	ssync;
+
+	/* Initialize stack pointer */
+	sp.l = lo(INITIAL_STACK);
+	sp.h = hi(INITIAL_STACK);
+	fp = sp;
+	usp = sp;
+
+	/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+	call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+	call _start_dma_code;
+#endif
+	/* Code for initializing Async memory banks */
+
+	p2.h = hi(EBIU_AMBCTL1);
+	p2.l = lo(EBIU_AMBCTL1);
+	r0.h = hi(AMBCTL1VAL);
+	r0.l = lo(AMBCTL1VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMBCTL0);
+	p2.l = lo(EBIU_AMBCTL0);
+	r0.h = hi(AMBCTL0VAL);
+	r0.l = lo(AMBCTL0VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMGCTL);
+	p2.l = lo(EBIU_AMGCTL);
+	r0 = AMGCTLVAL;
+	w[p2] = r0;
+	ssync;
+
+	/* This section keeps the processor in supervisor mode
+	 * during kernel boot.  Switches to user mode at end of boot.
+	 * See page 3-9 of Hardware Reference manual for documentation.
+	 */
+
+	/* EVT15 = _real_start */
+
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _real_start;
+	p1.h = _real_start;
+	[p0] = p1;
+	csync;
+
+	p0.l = lo(IMASK);
+	p0.h = hi(IMASK);
+	p1.l = IMASK_IVG15;
+	p1.h = 0x0;
+	[p0] = p1;
+	csync;
+
+	raise 15;
+	p0.l = .LWAIT_HERE;
+	p0.h = .LWAIT_HERE;
+	reti = p0;
+#if defined(ANOMALY_05000281)
+	nop; nop; nop;
+#endif
+	rti;
+
+.LWAIT_HERE:
+	jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+	[ -- sp ] = reti;
+	p0.l = lo(WDOG_CTL);
+	p0.h = hi(WDOG_CTL);
+	r0 = 0xAD6(z);
+	w[p0] = r0;	/* watchdog off for now */
+	ssync;
+
+	/* Code update for BSS size == 0
+	 * Zero out the bss region.
+	 */
+
+	p1.l = ___bss_start;
+	p1.h = ___bss_start;
+	p2.l = ___bss_stop;
+	p2.h = ___bss_stop;
+	r0 = 0;
+	p2 -= p1;
+	lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
+.L_clear_bss:
+	B[p1++] = r0;
+
+	/* In case there is a NULL pointer reference
+	 * Zero out region before stext
+	 */
+
+	p1.l = 0x0;
+	p1.h = 0x0;
+	r0.l = __stext;
+	r0.h = __stext;
+	r0 = r0 >> 1;
+	p2 = r0;
+	r0 = 0;
+	lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
+.L_clear_zero:
+	W[p1++] = r0;
+
+	/* pass the uboot arguments to the global value command line */
+	R0 = R7;
+	call _cmdline_init;
+
+	p1.l = __rambase;
+	p1.h = __rambase;
+	r0.l = __sdata;
+	r0.h = __sdata;
+	[p1] = r0;
+
+	p1.l = __ramstart;
+	p1.h = __ramstart;
+	p3.l = ___bss_stop;
+	p3.h = ___bss_stop;
+
+	r1 = p3;
+	[p1] = r1;
+
+
+	/*
+	 *  load the current thread pointer and stack
+	 */
+	r1.l = _init_thread_union;
+	r1.h = _init_thread_union;
+
+	r2.l = 0x2000;
+	r2.h = 0x0000;
+	r1 = r1 + r2;
+	sp = r1;
+	usp = sp;
+	fp = sp;
+	call _start_kernel;
+.L_exit:
+	jump.s	.L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+
+	/* Enable PHY CLK buffer output */
+	p0.h = hi(VR_CTL);
+	p0.l = lo(VR_CTL);
+	r0.l = w[p0];
+	bitset(r0, 14);
+	w[p0] = r0.l;
+	ssync;
+
+	p0.h = hi(SIC_IWR);
+	p0.l = lo(SIC_IWR);
+	r0.l = 0x1;
+	r0.h = 0x0;
+	[p0] = r0;
+	SSYNC;
+
+	/*
+	 *  Set PLL_CTL
+	 *   - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+	 *   - [8]     = BYPASS    : BYPASS the PLL, run CLKIN into CCLK/SCLK
+	 *   - [7]     = output delay (add 200ps of delay to mem signals)
+	 *   - [6]     = input delay (add 200ps of input delay to mem signals)
+	 *   - [5]     = PDWN      : 1=All Clocks off
+	 *   - [3]     = STOPCK    : 1=Core Clock off
+	 *   - [1]     = PLL_OFF   : 1=Disable Power to PLL
+	 *   - [0]     = DF        : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+	 *   all other bits set to zero
+	 */
+
+	p0.h = hi(PLL_LOCKCNT);
+	p0.l = lo(PLL_LOCKCNT);
+	r0 = 0x300(Z);
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITSET (R0, 24);
+	[P2] = R0;
+	SSYNC;
+
+	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
+	r0 = r0 << 9;                    /* Shift it over,                  */
+	r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
+	r0 = r1 | r0;
+	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
+	r1 = r1 << 8;                    /* Shift it over                   */
+	r0 = r1 | r0;                    /* add them all together           */
+
+	p0.h = hi(PLL_CTL);
+	p0.l = lo(PLL_CTL);              /* Load the address                */
+	cli r2;                          /* Disable interrupts              */
+	ssync;
+	w[p0] = r0.l;                    /* Set the value                   */
+	idle;                            /* Wait for the PLL to stablize    */
+	sti r2;                          /* Enable interrupts               */
+
+.Lcheck_again:
+	p0.h = hi(PLL_STAT);
+	p0.l = lo(PLL_STAT);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,5);
+	if ! CC jump .Lcheck_again;
+
+	/* Configure SCLK & CCLK Dividers */
+	r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+	p0.h = hi(PLL_DIV);
+	p0.l = lo(PLL_DIV);
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = lo(EBIU_SDRRC);
+	p0.h = hi(EBIU_SDRRC);
+	r0 = mem_SDRRC;
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = (EBIU_SDBCTL & 0xFFFF);
+	p0.h = (EBIU_SDBCTL >> 16);     /* SDRAM Memory Bank Control Register */
+	r0 = mem_SDBCTL;
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITCLR (R0, 24);
+	p0.h = hi(EBIU_SDSTAT);
+	p0.l = lo(EBIU_SDSTAT);
+	r2.l = w[p0];
+	cc = bittst(r2,3);
+	if !cc jump .Lskip;
+	NOP;
+	BITSET (R0, 23);
+.Lskip:
+	[P2] = R0;
+	SSYNC;
+
+	R0.L = lo(mem_SDGCTL);
+	R0.H = hi(mem_SDGCTL);
+	R1 = [p2];
+	R1 = R1 | R0;
+	[P2] = R1;
+	SSYNC;
+
+	p0.h = hi(SIC_IWR);
+	p0.l = lo(SIC_IWR);
+	r0.l = lo(IWR_ENABLE_ALL);
+	r0.h = hi(IWR_ENABLE_ALL);
+	[p0] = r0;
+	SSYNC;
+
+	RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+	/* No more interrupts to be handled*/
+	CLI R6;
+	SSYNC;
+
+#if defined(CONFIG_MTD_M25P80)
+/*
+ * The following code fix the SPI flash reboot issue,
+ * /CS signal of the chip which is using PF10 return to GPIO mode
+ */
+	p0.h = hi(PORTF_FER);
+	p0.l = lo(PORTF_FER);
+	r0.l = 0x0000;
+	w[p0] = r0.l;
+	SSYNC;
+
+/* /CS return to high */
+	p0.h = hi(PORTFIO);
+	p0.l = lo(PORTFIO);
+	r0.l = 0xFFFF;
+	w[p0] = r0.l;
+	SSYNC;
+
+/* Delay some time, This is necessary */
+	r1.h = 0;
+	r1.l = 0x400;
+	p1   = r1;
+	lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1;
+_delay_lab1:
+	r0.h = 0;
+	r0.l = 0x8000;
+	p0   = r0;
+	lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0;
+_delay_lab0:
+	nop;
+_delay_lab0_end:
+	nop;
+_delay_lab1_end:
+	nop;
+#endif
+
+	/* Clear the bits 13-15 in SWRST if they werent cleared */
+	p0.h = hi(SWRST);
+	p0.l = lo(SWRST);
+	csync;
+	r0.l = w[p0];
+
+	/* Clear the IMASK register */
+	p0.h = hi(IMASK);
+	p0.l = lo(IMASK);
+	r0 = 0x0;
+	[p0] = r0;
+
+	/* Clear the ILAT register */
+	p0.h = hi(ILAT);
+	p0.l = lo(ILAT);
+	r0 = [p0];
+	[p0] = r0;
+	SSYNC;
+
+	/* Disable the WDOG TIMER */
+	p0.h = hi(WDOG_CTL);
+	p0.l = lo(WDOG_CTL);
+	r0.l = 0xAD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Clear the sticky bit incase it is already set */
+	p0.h = hi(WDOG_CTL);
+	p0.l = lo(WDOG_CTL);
+	r0.l = 0x8AD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Program the count value */
+	R0.l = 0x100;
+	R0.h = 0x0;
+	P0.h = hi(WDOG_CNT);
+	P0.l = lo(WDOG_CNT);
+	[P0] = R0;
+	SSYNC;
+
+	/* Program WDOG_STAT if necessary */
+	P0.h = hi(WDOG_CTL);
+	P0.l = lo(WDOG_CTL);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,1);
+	if !CC JUMP .LWRITESTAT;
+	CC = BITTST(R0,2);
+	if !CC JUMP .LWRITESTAT;
+	JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+	/* When watch dog timer is enabled,
+	 * a write to STAT will load the contents of CNT to STAT
+	 */
+	R0 = 0x0000(z);
+	P0.h = hi(WDOG_STAT);
+	P0.l = lo(WDOG_STAT)
+	[P0] = R0;
+	SSYNC;
+
+.LSKIP_WRITE:
+	/* Enable the reset event */
+	P0.h = hi(WDOG_CTL);
+	P0.l = lo(WDOG_CTL);
+	R0 = W[P0](Z);
+	BITCLR(R0,1);
+	BITCLR(R0,2);
+	W[P0] = R0.L;
+	SSYNC;
+	NOP;
+
+	/* Enable the wdog counter */
+	R0 = W[P0](Z);
+	BITCLR(R0,4);
+	W[P0] = R0.L;
+	SSYNC;
+
+	IDLE;
+
+	RTS;
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long   0
+__ramstart:
+.long   0
+__ramend:
+.long   0
diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c
new file mode 100644
index 0000000..fd6308e
--- /dev/null
+++ b/arch/blackfin/mach-bf537/ints-priority.c
@@ -0,0 +1,74 @@
+/*
+ * File:         arch/blackfin/mach-bf537/ints-priority.c
+ * Based on:     arch/blackfin/mach-bf533/ints-priority.c
+ * Author:       Michael Hennerich
+ *
+ * Created:
+ * Description:  Set up the interupt priorities
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+	/* Program the IAR0 Register with the configured priority */
+	bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+			    ((CONFIG_IRQ_DMA_ERROR - 7) << IRQ_DMA_ERROR_POS) |
+			    ((CONFIG_IRQ_ERROR - 7) << IRQ_ERROR_POS) |
+			    ((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS) |
+			    ((CONFIG_IRQ_PPI - 7) << IRQ_PPI_POS) |
+			    ((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) |
+			    ((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) |
+			    ((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS));
+
+	bfin_write_SIC_IAR1(((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) |
+			    ((CONFIG_IRQ_TWI - 7) << IRQ_TWI_POS) |
+			    ((CONFIG_IRQ_SPI - 7) << IRQ_SPI_POS) |
+			    ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) |
+			    ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS) |
+			    ((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) |
+			    ((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) |
+			    ((CONFIG_IRQ_CAN_RX - 7) << IRQ_CAN_RX_POS));
+
+	bfin_write_SIC_IAR2(((CONFIG_IRQ_CAN_TX - 7) << IRQ_CAN_TX_POS) |
+			    ((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) |
+			    ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) |
+			    ((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) |
+			    ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) |
+			    ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) |
+			    ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) |
+			    ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS));
+
+	bfin_write_SIC_IAR3(((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) |
+			    ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) |
+			    ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS) |
+			    ((CONFIG_IRQ_PROG_INTA - 7) << IRQ_PROG_INTA_POS) |
+			    ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) |
+			    ((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) |
+			    ((CONFIG_IRQ_MEM_DMA1 - 7) << IRQ_MEM_DMA1_POS) |
+			    ((CONFIG_IRQ_WATCH - 7) << IRQ_WATCH_POS));
+
+	SSYNC();
+}
diff --git a/arch/blackfin/mach-bf561/Kconfig b/arch/blackfin/mach-bf561/Kconfig
new file mode 100644
index 0000000..0a17c4c
--- /dev/null
+++ b/arch/blackfin/mach-bf561/Kconfig
@@ -0,0 +1,222 @@
+if BF561
+
+menu "BF561 Specific Configuration"
+
+comment "Core B Support"
+
+menu "Core B Support"
+
+config BF561_COREB
+	bool "Enable Core B support"
+	default y
+
+config BF561_COREB_RESET
+	bool "Enable Core B reset support"
+	default n
+	help
+	  This requires code in the application that is loaded
+	  into Core B. In order to reset, the application needs
+	  to install an interrupt handler for Supplemental
+	  Interrupt 0, that sets RETI to 0xff600000 and writes
+	  bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
+	  This causes Core B to stall when Supplemental Interrupt
+	  0 is set, and will reset PC to 0xff600000 when
+	  COREB_SRAM_INIT is cleared.
+
+endmenu
+
+comment "Interrupt Priority Assignment"
+
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+	int "PLL Wakeup Interrupt"
+	default 7
+config IRQ_DMA1_ERROR
+	int "DMA1 Error (generic)"
+	default 7
+config IRQ_DMA2_ERROR
+	int "DMA2 Error (generic)"
+	default 7
+config IRQ_IMDMA_ERROR
+	int "IMDMA Error (generic)"
+	default 7
+config IRQ_PPI0_ERROR
+	int "PPI0 Error Interrupt"
+	default 7
+config IRQ_PPI1_ERROR
+	int "PPI1 Error Interrupt"
+	default 7
+config IRQ_SPORT0_ERROR
+	int "SPORT0 Error Interrupt"
+	default 7
+config IRQ_SPORT1_ERROR
+	int "SPORT1 Error Interrupt"
+	default 7
+config IRQ_SPI_ERROR
+	int "SPI Error Interrupt"
+	default 7
+config IRQ_UART_ERROR
+	int "UART Error Interrupt"
+	default 7
+config IRQ_RESERVED_ERROR
+	int "Reserved Interrupt"
+	default 7
+config IRQ_DMA1_0
+	int "DMA1 0  Interrupt(PPI1)"
+	default 8
+config IRQ_DMA1_1
+	int "DMA1 1  Interrupt(PPI2)"
+	default 8
+config IRQ_DMA1_2
+	int "DMA1 2  Interrupt"
+	default 8
+config IRQ_DMA1_3
+	int "DMA1 3  Interrupt"
+	default 8
+config IRQ_DMA1_4
+	int "DMA1 4  Interrupt"
+	default 8
+config IRQ_DMA1_5
+	int "DMA1 5  Interrupt"
+	default 8
+config IRQ_DMA1_6
+	int "DMA1 6  Interrupt"
+	default 8
+config IRQ_DMA1_7
+	int "DMA1 7  Interrupt"
+	default 8
+config IRQ_DMA1_8
+	int "DMA1 8  Interrupt"
+	default 8
+config IRQ_DMA1_9
+	int "DMA1 9  Interrupt"
+	default 8
+config IRQ_DMA1_10
+	int "DMA1 10 Interrupt"
+	default 8
+config IRQ_DMA1_11
+	int "DMA1 11 Interrupt"
+	default 8
+config IRQ_DMA2_0
+	int "DMA2 0  (SPORT0 RX)"
+	default 9
+config IRQ_DMA2_1
+	int "DMA2 1  (SPORT0 TX)"
+	default 9
+config IRQ_DMA2_2
+	int "DMA2 2  (SPORT1 RX)"
+	default 9
+config IRQ_DMA2_3
+	int "DMA2 3  (SPORT2 TX)"
+	default 9
+config IRQ_DMA2_4
+	int "DMA2 4  (SPI)"
+	default 9
+config IRQ_DMA2_5
+	int "DMA2 5  (UART RX)"
+	default 9
+config IRQ_DMA2_6
+	int "DMA2 6  (UART TX)"
+	default 9
+config IRQ_DMA2_7
+	int "DMA2 7  Interrupt"
+	default 9
+config IRQ_DMA2_8
+	int "DMA2 8  Interrupt"
+	default 9
+config IRQ_DMA2_9
+	int "DMA2 9  Interrupt"
+	default 9
+config IRQ_DMA2_10
+	int "DMA2 10 Interrupt"
+	default 9
+config IRQ_DMA2_11
+	int "DMA2 11 Interrupt"
+	default 9
+config IRQ_TIMER0
+	int "TIMER 0  Interrupt"
+	default 10
+config IRQ_TIMER1
+	int "TIMER 1  Interrupt"
+	default 10
+config IRQ_TIMER2
+	int "TIMER 2  Interrupt"
+	default 10
+config IRQ_TIMER3
+	int "TIMER 3  Interrupt"
+	default 10
+config IRQ_TIMER4
+	int "TIMER 4  Interrupt"
+	default 10
+config IRQ_TIMER5
+	int "TIMER 5  Interrupt"
+	default 10
+config IRQ_TIMER6
+	int "TIMER 6  Interrupt"
+	default 10
+config IRQ_TIMER7
+	int "TIMER 7  Interrupt"
+	default 10
+config IRQ_TIMER8
+	int "TIMER 8  Interrupt"
+	default 10
+config IRQ_TIMER9
+	int "TIMER 9  Interrupt"
+	default 10
+config IRQ_TIMER10
+	int "TIMER 10 Interrupt"
+	default 10
+config IRQ_TIMER11
+	int "TIMER 11 Interrupt"
+	default 10
+config IRQ_PROG0_INTA
+	int "Programmable Flags0 A (8)"
+	default 11
+config IRQ_PROG0_INTB
+	int "Programmable Flags0 B (8)"
+	default 11
+config IRQ_PROG1_INTA
+	int "Programmable Flags1 A (8)"
+	default 11
+config IRQ_PROG1_INTB
+	int "Programmable Flags1 B (8)"
+	default 11
+config IRQ_PROG2_INTA
+	int "Programmable Flags2 A (8)"
+	default 11
+config IRQ_PROG2_INTB
+	int "Programmable Flags2 B (8)"
+	default 11
+config IRQ_DMA1_WRRD0
+	int "MDMA1 0 write/read INT"
+	default 8
+config IRQ_DMA1_WRRD1
+	int "MDMA1 1 write/read INT"
+	default 8
+config IRQ_DMA2_WRRD0
+	int "MDMA2 0 write/read INT"
+	default 9
+config IRQ_DMA2_WRRD1
+	int "MDMA2 1 write/read INT"
+	default 9
+config IRQ_IMDMA_WRRD0
+	int "IMDMA 0 write/read INT"
+	default 12
+config IRQ_IMDMA_WRRD1
+	int "IMDMA 1 write/read INT"
+	default 12
+config IRQ_WDTIMER
+	int "Watch Dog Timer"
+	default 13
+
+	help
+	  Enter the priority numbers between 7-13 ONLY.  Others are Reserved.
+	  This applies to all the above.  It is not recommended to assign the
+	  highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf561/Makefile b/arch/blackfin/mach-bf561/Makefile
new file mode 100644
index 0000000..57f475a
--- /dev/null
+++ b/arch/blackfin/mach-bf561/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf561/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_BF561_COREB) += coreb.o
diff --git a/arch/blackfin/mach-bf561/boards/Makefile b/arch/blackfin/mach-bf561/boards/Makefile
new file mode 100644
index 0000000..886edc7
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/Makefile
@@ -0,0 +1,7 @@
+#
+# arch/blackfin/mach-bf561/boards/Makefile
+#
+
+obj-$(CONFIG_GENERIC_BOARD)            += generic_board.o
+obj-$(CONFIG_BFIN561_EZKIT)            += ezkit.o
+obj-$(CONFIG_BFIN561_BLUETECHNIX_CM)   += cm_bf561.o
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
new file mode 100644
index 0000000..6824e95
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -0,0 +1,289 @@
+/*
+ * File:         arch/blackfin/mach-bf533/boards/cm_bf561.c
+ * Based on:     arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au> Copright 2005
+ *
+ * Created:      2006
+ * Description:  Board description file
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF561";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI perpherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader",
+		.size = 0x00020000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	},{
+		.name = "kernel",
+		.size = 0xe0000,
+		.offset = 0x20000
+	},{
+		.name = "file system",
+		.size = 0x700000,
+		.offset = 0x00100000,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 1,         /* use dma transfer with this chip*/
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+	.enable_dma = 1,
+	.bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+	{
+		.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+	},
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+	{
+		.modalias = "ad9960-spi",
+		.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = 1,
+		.controller_data = &ad9960_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+	{
+		.modalias = "spi_mmc",
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SPI_MMC_CS_CHAN,
+		.platform_data = NULL,
+		.controller_data = &spi_mmc_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x28000300,
+		.end = 0x28000300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF0,
+		.end = IRQ_PF0,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+	{
+		.start = 0x24008000,
+		.end = 0x24008000,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = 0x24008004,
+		.end = 0x24008004,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PF47,
+		.end = IRQ_PF47,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+	.sel15Kres = 1,
+	.clknotstop = 0,
+	.oc_enable = 0,
+	.int_act_high = 0,
+	.int_edge_triggered = 0,
+	.remote_wakeup_connected = 0,
+	.no_power_switching = 1,
+	.power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+	.name = "isp1362-hcd",
+	.id = 0,
+	.dev = {
+		.platform_data = &isp1362_priv,
+	},
+	.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+	.resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+        {
+                .start = 0xFFC00400,
+                .end = 0xFFC004FF,
+                .flags = IORESOURCE_MEM,
+        },
+};
+
+static struct platform_device bfin_uart_device = {
+        .name = "bfin-uart",
+        .id = 1,
+        .num_resources = ARRAY_SIZE(bfin_uart_resources),
+        .resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *cm_bf561_devices[] __initdata = {
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+        &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+	&isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+
+};
+
+static int __init cm_bf561_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+	return 0;
+}
+
+arch_initcall(cm_bf561_init);
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
new file mode 100644
index 0000000..14eb4f9
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -0,0 +1,147 @@
+/*
+ * File:         arch/blackfin/mach-bf561/ezkit.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF561-EZKIT";
+
+/*
+ *  USB-LAN EzExtender board
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.name = "smc91x-regs",
+		.start = 0x2C010300,
+		.end = 0x2C010300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+
+		.start = IRQ_PF9,
+		.end = IRQ_PF9,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+        {
+                .start = 0xFFC00400,
+                .end = 0xFFC004FF,
+                .flags = IORESOURCE_MEM,
+        },
+};
+
+static struct platform_device bfin_uart_device = {
+        .name = "bfin-uart",
+        .id = 1,
+        .num_resources = ARRAY_SIZE(bfin_uart_resources),
+        .resource = bfin_uart_resources,
+};
+#endif
+
+#ifdef CONFIG_SPI_BFIN
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+#endif
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+	.num_chipselect = 8,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+	.name = "bfin-spi-master",
+	.id = 1, /* Bus number */
+	.dev = {
+		.platform_data = &spi_bfin_master_info, /* Passed to driver */
+	},
+};
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+	|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+	{
+		.modalias = "ad1836-spi",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 1,
+		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+};
+
+static struct platform_device *ezkit_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&spi_bfin_master_device,
+#endif
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+        &bfin_uart_device,
+#endif
+};
+
+static int __init ezkit_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	ret = platform_add_devices(ezkit_devices,
+		 ARRAY_SIZE(ezkit_devices));
+	if (ret < 0)
+		return ret;
+	return spi_register_board_info(bfin_spi_board_info,
+				ARRAY_SIZE(bfin_spi_board_info));
+}
+
+arch_initcall(ezkit_init);
diff --git a/arch/blackfin/mach-bf561/boards/generic_board.c b/arch/blackfin/mach-bf561/boards/generic_board.c
new file mode 100644
index 0000000..585ecdd
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/generic_board.c
@@ -0,0 +1,82 @@
+/*
+ * File:         arch/blackfin/mach-bf561/generic_board.c
+ * Based on:     arch/blackfin/mach-bf533/ezkit.c
+ * Author:       Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2005 National ICT Australia (NICTA)
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+
+char *bfin_board_name = "UNKNOWN BOARD";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+	{
+		.start = 0x2C010300,
+		.end = 0x2C010300 + 16,
+		.flags = IORESOURCE_MEM,
+	},{
+		.start = IRQ_PROG_INTB,
+		.end = IRQ_PROG_INTB,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},{
+		/*
+		 *  denotes the flag pin and is used directly if
+		 *  CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+		 */
+		.start = IRQ_PF9,
+		.end = IRQ_PF9,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name = "smc91x",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(smc91x_resources),
+	.resource = smc91x_resources,
+};
+#endif
+
+static struct platform_device *generic_board_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+	&smc91x_device,
+#endif
+};
+
+static int __init generic_board_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+	return platform_add_devices(generic_board_devices,
+				    ARRAY_SIZE(generic_board_devices));
+}
+
+arch_initcall(generic_board_init);
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
new file mode 100644
index 0000000..b28582f
--- /dev/null
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -0,0 +1,402 @@
+/*
+ * File:         arch/blackfin/mach-bf561/coreb.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  Handle CoreB on a BF561
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#define MODULE_VER		"v0.1"
+
+static spinlock_t coreb_lock;
+static wait_queue_head_t coreb_dma_wait;
+
+#define COREB_IS_OPEN		0x00000001
+#define COREB_IS_RUNNING	0x00000010
+
+#define CMD_COREB_INDEX		1
+#define CMD_COREB_START		2
+#define CMD_COREB_STOP		3
+#define CMD_COREB_RESET		4
+
+#define COREB_MINOR		229
+
+static unsigned long coreb_status = 0;
+static unsigned long coreb_base = 0xff600000;
+static unsigned long coreb_size = 0x4000;
+int coreb_dma_done;
+
+static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
+static ssize_t coreb_read(struct file *file, char *buf, size_t count,
+			  loff_t * ppos);
+static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
+			   loff_t * ppos);
+static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		       unsigned long arg);
+static int coreb_open(struct inode *inode, struct file *file);
+static int coreb_release(struct inode *inode, struct file *file);
+
+static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
+{
+	clear_dma_irqstat(CH_MEM_STREAM2_DEST);
+	coreb_dma_done = 1;
+	wake_up_interruptible(&coreb_dma_wait);
+	return IRQ_HANDLED;
+}
+
+static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
+			   loff_t * ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t wrote = 0;
+
+	if (p + count > coreb_size)
+		return -EFAULT;
+
+	while (count > 0) {
+		int len = count;
+
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+
+		coreb_dma_done = 0;
+
+		/* Source Channel */
+		set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
+		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+		/* Destination Channel */
+		set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
+		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+		set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
+		set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
+
+		enable_dma(CH_MEM_STREAM2_SRC);
+		enable_dma(CH_MEM_STREAM2_DEST);
+
+		wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
+
+		disable_dma(CH_MEM_STREAM2_SRC);
+		disable_dma(CH_MEM_STREAM2_DEST);
+
+		count -= len;
+		wrote += len;
+		buf += len;
+		p += len;
+	}
+	*ppos = p;
+	return wrote;
+}
+
+static ssize_t coreb_read(struct file *file, char *buf, size_t count,
+			  loff_t * ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read = 0;
+
+	if ((p + count) > coreb_size)
+		return -EFAULT;
+
+	while (count > 0) {
+		int len = count;
+
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+
+		coreb_dma_done = 0;
+
+		/* Source Channel */
+		set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
+		set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+		set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+		set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+		/* Destination Channel */
+		set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
+		set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+		set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
+		set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
+
+		enable_dma(CH_MEM_STREAM2_SRC);
+		enable_dma(CH_MEM_STREAM2_DEST);
+
+		wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
+
+		disable_dma(CH_MEM_STREAM2_SRC);
+		disable_dma(CH_MEM_STREAM2_DEST);
+
+		count -= len;
+		read += len;
+		buf += len;
+		p += len;
+	}
+
+	return read;
+}
+
+static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
+{
+	loff_t ret;
+
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
+
+	switch (origin) {
+	case 0 /* SEEK_SET */ :
+		if (offset < coreb_size) {
+			file->f_pos = offset;
+			ret = file->f_pos;
+		} else
+			ret = -EINVAL;
+		break;
+	case 1 /* SEEK_CUR */ :
+		if ((offset + file->f_pos) < coreb_size) {
+			file->f_pos += offset;
+			ret = file->f_pos;
+		} else
+			ret = -EINVAL;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+	return ret;
+}
+
+static int coreb_open(struct inode *inode, struct file *file)
+{
+	spin_lock_irq(&coreb_lock);
+
+	if (coreb_status & COREB_IS_OPEN)
+		goto out_busy;
+
+	coreb_status |= COREB_IS_OPEN;
+
+	spin_unlock_irq(&coreb_lock);
+	return 0;
+
+      out_busy:
+	spin_unlock_irq(&coreb_lock);
+	return -EBUSY;
+}
+
+static int coreb_release(struct inode *inode, struct file *file)
+{
+	spin_lock_irq(&coreb_lock);
+	coreb_status &= ~COREB_IS_OPEN;
+	spin_unlock_irq(&coreb_lock);
+	return 0;
+}
+
+static int coreb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+	int coreb_index = 0;
+
+	switch (cmd) {
+	case CMD_COREB_INDEX:
+		if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
+			retval = -EFAULT;
+			break;
+		}
+
+		spin_lock_irq(&coreb_lock);
+		switch (coreb_index) {
+		case 0:
+			coreb_base = 0xff600000;
+			coreb_size = 0x4000;
+			break;
+		case 1:
+			coreb_base = 0xff610000;
+			coreb_size = 0x4000;
+			break;
+		case 2:
+			coreb_base = 0xff500000;
+			coreb_size = 0x8000;
+			break;
+		case 3:
+			coreb_base = 0xff400000;
+			coreb_size = 0x8000;
+			break;
+		default:
+			retval = -EINVAL;
+			break;
+		}
+		spin_unlock_irq(&coreb_lock);
+
+		mutex_lock(&file->f_dentry->d_inode->i_mutex);
+		file->f_pos = 0;
+		mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+		break;
+	case CMD_COREB_START:
+		spin_lock_irq(&coreb_lock);
+		if (coreb_status & COREB_IS_RUNNING) {
+			retval = -EBUSY;
+			break;
+		}
+		printk(KERN_INFO "Starting Core B\n");
+		coreb_status |= COREB_IS_RUNNING;
+		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
+		SSYNC();
+		spin_lock_irq(&coreb_lock);
+		break;
+#if defined(CONFIG_BF561_COREB_RESET)
+	case CMD_COREB_STOP:
+		spin_lock_irq(&coreb_lock);
+		printk(KERN_INFO "Stopping Core B\n");
+		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
+		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+		coreb_status &= ~COREB_IS_RUNNING;
+		spin_lock_irq(&coreb_lock);
+		break;
+	case CMD_COREB_RESET:
+		printk(KERN_INFO "Resetting Core B\n");
+		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+		break;
+#endif
+	}
+
+	return retval;
+}
+
+static struct file_operations coreb_fops = {
+	.owner = THIS_MODULE,
+	.llseek = coreb_lseek,
+	.read = coreb_read,
+	.write = coreb_write,
+	.ioctl = coreb_ioctl,
+	.open = coreb_open,
+	.release = coreb_release
+};
+
+static struct miscdevice coreb_dev = {
+	COREB_MINOR,
+	"coreb",
+	&coreb_fops
+};
+
+static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf,
+		       "Base Address:\t0x%08lx\n"
+		       "Core B is %s\n"
+		       "SICA_SYSCR:\t%04x\n"
+		       "SICB_SYSCR:\t%04x\n"
+		       "\n"
+		       "IRQ Status:\tCore A\t\tCore B\n"
+		       "ISR0:\t\t%08x\t\t%08x\n"
+		       "ISR1:\t\t%08x\t\t%08x\n"
+		       "IMASK0:\t\t%08x\t\t%08x\n"
+		       "IMASK1:\t\t%08x\t\t%08x\n",
+		       coreb_base,
+		       coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
+		       bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
+		       bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
+		       bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
+		       bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
+		       bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
+}
+
+static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
+
+int __init bf561_coreb_init(void)
+{
+	init_waitqueue_head(&coreb_dma_wait);
+
+	spin_lock_init(&coreb_lock);
+	/* Request the core memory regions for Core B */
+	if (request_mem_region(0xff600000, 0x4000,
+			       "Core B - Instruction SRAM") == NULL)
+		goto exit;
+
+	if (request_mem_region(0xFF610000, 0x4000,
+			       "Core B - Instruction SRAM") == NULL)
+		goto release_instruction_a_sram;
+
+	if (request_mem_region(0xFF500000, 0x8000,
+			       "Core B - Data Bank B SRAM") == NULL)
+		goto release_instruction_b_sram;
+
+	if (request_mem_region(0xff400000, 0x8000,
+			       "Core B - Data Bank A SRAM") == NULL)
+		goto release_data_b_sram;
+
+	if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
+		goto release_data_a_sram;
+
+	if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
+		goto release_dma_dest;
+
+	set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
+
+	misc_register(&coreb_dev);
+
+	if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
+		goto release_dma_src;
+
+	printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
+	return 0;
+
+      release_dma_src:
+	free_dma(CH_MEM_STREAM2_SRC);
+      release_dma_dest:
+	free_dma(CH_MEM_STREAM2_DEST);
+      release_data_a_sram:
+	release_mem_region(0xff400000, 0x8000);
+      release_data_b_sram:
+	release_mem_region(0xff500000, 0x8000);
+      release_instruction_b_sram:
+	release_mem_region(0xff610000, 0x4000);
+      release_instruction_a_sram:
+	release_mem_region(0xff600000, 0x4000);
+      exit:
+	return -ENOMEM;
+}
+
+void __exit bf561_coreb_exit(void)
+{
+	device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
+	misc_deregister(&coreb_dev);
+
+	release_mem_region(0xff610000, 0x4000);
+	release_mem_region(0xff600000, 0x4000);
+	release_mem_region(0xff500000, 0x8000);
+	release_mem_region(0xff400000, 0x8000);
+
+	free_dma(CH_MEM_STREAM2_DEST);
+	free_dma(CH_MEM_STREAM2_SRC);
+}
+
+module_init(bf561_coreb_init);
+module_exit(bf561_coreb_exit);
+
+MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
+MODULE_DESCRIPTION("BF561 Core B Support");
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
new file mode 100644
index 0000000..7bca478
--- /dev/null
+++ b/arch/blackfin/mach-bf561/head.S
@@ -0,0 +1,512 @@
+/*
+ * File:         arch/blackfin/mach-bf561/head.S
+ * Based on:     arch/blackfin/mach-bf533/head.S
+ * Author:
+ *
+ * Created:
+ * Description:  BF561 startup file
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK	0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+	/*  R0: argument of command line string, passed from uboot, save it */
+	R7 = R0;
+	/* Set the SYSCFG register */
+	R0 = 0x36;
+	SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+	R0 = 0;
+
+	/*Clear Out All the data and pointer  Registers*/
+	R1 = R0;
+	R2 = R0;
+	R3 = R0;
+	R4 = R0;
+	R5 = R0;
+	R6 = R0;
+
+	P0 = R0;
+	P1 = R0;
+	P2 = R0;
+	P3 = R0;
+	P4 = R0;
+	P5 = R0;
+
+	LC0 = r0;
+	LC1 = r0;
+	L0 = r0;
+	L1 = r0;
+	L2 = r0;
+	L3 = r0;
+
+	/* Clear Out All the DAG Registers*/
+	B0 = r0;
+	B1 = r0;
+	B2 = r0;
+	B3 = r0;
+
+	I0 = r0;
+	I1 = r0;
+	I2 = r0;
+	I3 = r0;
+
+	M0 = r0;
+	M1 = r0;
+	M2 = r0;
+	M3 = r0;
+
+	/* Turn off the icache */
+	p0.l = (IMEM_CONTROL & 0xFFFF);
+	p0.h = (IMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENICPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Turn off the dcache */
+	p0.l = (DMEM_CONTROL & 0xFFFF);
+	p0.h = (DMEM_CONTROL >> 16);
+	R1 = [p0];
+	R0 = ~ENDCPLB;
+	R0 = R0 & R1;
+
+	/* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+	CLI R2;
+	SSYNC;
+#endif
+	[p0] = R0;
+	SSYNC;
+#ifdef ANOMALY_05000125
+	STI R2;
+#endif
+
+	/* Initialise UART*/
+	p0.h = hi(UART_LCR);
+	p0.l = lo(UART_LCR);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable DLL writes */
+	ssync;
+
+	p0.h = hi(UART_DLL);
+	p0.l = lo(UART_DLL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_DLH);
+	p0.l = lo(UART_DLH);
+	r0 = 0x00(Z);
+	w[p0] = r0.L;
+	ssync;
+
+	p0.h = hi(UART_GCTL);
+	p0.l = lo(UART_GCTL);
+	r0 = 0x0(Z);
+	w[p0] = r0.L;	/* To enable UART clock */
+	ssync;
+
+	/* Initialize stack pointer */
+	sp.l = lo(INITIAL_STACK);
+	sp.h = hi(INITIAL_STACK);
+	fp = sp;
+	usp = sp;
+
+	/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+	call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+	call _start_dma_code;
+#endif
+
+	/* Code for initializing Async memory banks */
+
+	p2.h = hi(EBIU_AMBCTL1);
+	p2.l = lo(EBIU_AMBCTL1);
+	r0.h = hi(AMBCTL1VAL);
+	r0.l = lo(AMBCTL1VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMBCTL0);
+	p2.l = lo(EBIU_AMBCTL0);
+	r0.h = hi(AMBCTL0VAL);
+	r0.l = lo(AMBCTL0VAL);
+	[p2] = r0;
+	ssync;
+
+	p2.h = hi(EBIU_AMGCTL);
+	p2.l = lo(EBIU_AMGCTL);
+	r0 = AMGCTLVAL;
+	w[p2] = r0;
+	ssync;
+
+	/* This section keeps the processor in supervisor mode
+	 * during kernel boot.  Switches to user mode at end of boot.
+	 * See page 3-9 of Hardware Reference manual for documentation.
+	 */
+
+	/* EVT15 = _real_start */
+
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _real_start;
+	p1.h = _real_start;
+	[p0] = p1;
+	csync;
+
+	p0.l = lo(IMASK);
+	p0.h = hi(IMASK);
+	p1.l = IMASK_IVG15;
+	p1.h = 0x0;
+	[p0] = p1;
+	csync;
+
+	raise 15;
+	p0.l = .LWAIT_HERE;
+	p0.h = .LWAIT_HERE;
+	reti = p0;
+#if defined(ANOMALY_05000281)
+	nop; nop; nop;
+#endif
+	rti;
+
+.LWAIT_HERE:
+	jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+	[ -- sp ] = reti;
+	p0.l = lo(WDOGA_CTL);
+	p0.h = hi(WDOGA_CTL);
+	r0 = 0xAD6(z);
+	w[p0] = r0;	/* watchdog off for now */
+	ssync;
+
+	/* Code update for BSS size == 0
+	 * Zero out the bss region.
+	 */
+
+	p1.l = ___bss_start;
+	p1.h = ___bss_start;
+	p2.l = ___bss_stop;
+	p2.h = ___bss_stop;
+	r0 = 0;
+	p2 -= p1;
+	lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
+.L_clear_bss:
+	B[p1++] = r0;
+
+	/* In case there is a NULL pointer reference
+	 * Zero out region before stext
+	 */
+
+	p1.l = 0x0;
+	p1.h = 0x0;
+	r0.l = __stext;
+	r0.h = __stext;
+	r0 = r0 >> 1;
+	p2 = r0;
+	r0 = 0;
+	lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
+.L_clear_zero:
+	W[p1++] = r0;
+
+/* pass the uboot arguments to the global value command line */
+	R0 = R7;
+	call _cmdline_init;
+
+	p1.l = __rambase;
+	p1.h = __rambase;
+	r0.l = __sdata;
+	r0.h = __sdata;
+	[p1] = r0;
+
+	p1.l = __ramstart;
+	p1.h = __ramstart;
+	p3.l = ___bss_stop;
+	p3.h = ___bss_stop;
+
+	r1 = p3;
+	[p1] = r1;
+
+	/*
+	 * load the current thread pointer and stack
+	 */
+	r1.l = _init_thread_union;
+	r1.h = _init_thread_union;
+
+	r2.l = 0x2000;
+	r2.h = 0x0000;
+	r1 = r1 + r2;
+	sp = r1;
+	usp = sp;
+	fp = sp;
+	call _start_kernel;
+.L_exit:
+	jump.s	.L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+	p0.h = hi(SICA_IWR0);
+	p0.l = lo(SICA_IWR0);
+	r0.l = 0x1;
+	[p0] = r0;
+	SSYNC;
+
+	/*
+	 *  Set PLL_CTL
+	 *   - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+	 *   - [8]     = BYPASS    : BYPASS the PLL, run CLKIN into CCLK/SCLK
+	 *   - [7]     = output delay (add 200ps of delay to mem signals)
+	 *   - [6]     = input delay (add 200ps of input delay to mem signals)
+	 *   - [5]     = PDWN      : 1=All Clocks off
+	 *   - [3]     = STOPCK    : 1=Core Clock off
+	 *   - [1]     = PLL_OFF   : 1=Disable Power to PLL
+	 *   - [0]     = DF        : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+	 *   all other bits set to zero
+	 */
+
+	p0.h = hi(PLL_LOCKCNT);
+	p0.l = lo(PLL_LOCKCNT);
+	r0 = 0x300(Z);
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITSET (R0, 24);
+	[P2] = R0;
+	SSYNC;
+
+	r0 = CONFIG_VCO_MULT & 63;       /* Load the VCO multiplier         */
+	r0 = r0 << 9;                    /* Shift it over,                  */
+	r1 = CLKIN_HALF;                 /* Do we need to divide CLKIN by 2?*/
+	r0 = r1 | r0;
+	r1 = PLL_BYPASS;                 /* Bypass the PLL?                 */
+	r1 = r1 << 8;                    /* Shift it over                   */
+	r0 = r1 | r0;                    /* add them all together           */
+
+	p0.h = hi(PLL_CTL);
+	p0.l = lo(PLL_CTL);              /* Load the address                */
+	cli r2;                          /* Disable interrupts              */
+	ssync;
+	w[p0] = r0.l;                    /* Set the value                   */
+	idle;                            /* Wait for the PLL to stablize    */
+	sti r2;                          /* Enable interrupts               */
+
+.Lcheck_again:
+	p0.h = hi(PLL_STAT);
+	p0.l = lo(PLL_STAT);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,5);
+	if ! CC jump .Lcheck_again;
+
+	/* Configure SCLK & CCLK Dividers */
+	   	r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+	p0.h = hi(PLL_DIV);
+	p0.l = lo(PLL_DIV);
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = lo(EBIU_SDRRC);
+	p0.h = hi(EBIU_SDRRC);
+	r0 = mem_SDRRC;
+	w[p0] = r0.l;
+	ssync;
+
+	p0.l = (EBIU_SDBCTL & 0xFFFF);
+	p0.h = (EBIU_SDBCTL >> 16);     /* SDRAM Memory Bank Control Register */
+	r0 = mem_SDBCTL;
+	w[p0] = r0.l;
+	ssync;
+
+	P2.H = hi(EBIU_SDGCTL);
+	P2.L = lo(EBIU_SDGCTL);
+	R0 = [P2];
+	BITCLR (R0, 24);
+	p0.h = hi(EBIU_SDSTAT);
+	p0.l = lo(EBIU_SDSTAT);
+	r2.l = w[p0];
+	cc = bittst(r2,3);
+	if !cc jump .Lskip;
+	NOP;
+	BITSET (R0, 23);
+.Lskip:
+	[P2] = R0;
+	SSYNC;
+
+	R0.L = lo(mem_SDGCTL);
+	R0.H = hi(mem_SDGCTL);
+	R1 = [p2];
+	R1 = R1 | R0;
+	[P2] = R1;
+	SSYNC;
+
+	RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+	/* No more interrupts to be handled*/
+	CLI R6;
+	SSYNC;
+
+#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+	p0.h = hi(FIO_INEN);
+	p0.l = lo(FIO_INEN);
+	r0.l = ~(PF1 | PF0);
+	w[p0] = r0.l;
+
+	p0.h = hi(FIO_DIR);
+	p0.l = lo(FIO_DIR);
+	r0.l = (PF1 | PF0);
+	w[p0] = r0.l;
+
+	p0.h = hi(FIO_FLAG_C);
+	p0.l = lo(FIO_FLAG_C);
+	r0.l = (PF1 | PF0);
+	w[p0] = r0.l;
+#endif
+
+	/* Clear the bits 13-15 in SWRST if they werent cleared */
+	p0.h = hi(SICA_SWRST);
+	p0.l = lo(SICA_SWRST);
+	csync;
+	r0.l = w[p0];
+
+	/* Clear the IMASK register */
+	p0.h = hi(IMASK);
+	p0.l = lo(IMASK);
+	r0 = 0x0;
+	[p0] = r0;
+
+	/* Clear the ILAT register */
+	p0.h = hi(ILAT);
+	p0.l = lo(ILAT);
+	r0 = [p0];
+	[p0] = r0;
+	SSYNC;
+
+	/* Disable the WDOG TIMER */
+	p0.h = hi(WDOGA_CTL);
+	p0.l = lo(WDOGA_CTL);
+	r0.l = 0xAD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Clear the sticky bit incase it is already set */
+	p0.h = hi(WDOGA_CTL);
+	p0.l = lo(WDOGA_CTL);
+	r0.l = 0x8AD6;
+	w[p0] = r0.l;
+	SSYNC;
+
+	/* Program the count value */
+	R0.l = 0x100;
+	R0.h = 0x0;
+	P0.h = hi(WDOGA_CNT);
+	P0.l = lo(WDOGA_CNT);
+	[P0] = R0;
+	SSYNC;
+
+	/* Program WDOG_STAT if necessary */
+	P0.h = hi(WDOGA_CTL);
+	P0.l = lo(WDOGA_CTL);
+	R0 = W[P0](Z);
+	CC = BITTST(R0,1);
+	if !CC JUMP .LWRITESTAT;
+	CC = BITTST(R0,2);
+	if !CC JUMP .LWRITESTAT;
+	JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+	/* When watch dog timer is enabled,
+	 * a write to STAT will load the contents of CNT to STAT
+	 */
+	R0 = 0x0000(z);
+	P0.h = hi(WDOGA_STAT);
+	P0.l = lo(WDOGA_STAT)
+	[P0] = R0;
+	SSYNC;
+
+.LSKIP_WRITE:
+	/* Enable the reset event */
+	P0.h = hi(WDOGA_CTL);
+	P0.l = lo(WDOGA_CTL);
+	R0 = W[P0](Z);
+	BITCLR(R0,1);
+	BITCLR(R0,2);
+	W[P0] = R0.L;
+	SSYNC;
+	NOP;
+
+	/* Enable the wdog counter */
+	R0 = W[P0](Z);
+	BITCLR(R0,4);
+	W[P0] = R0.L;
+	SSYNC;
+
+	IDLE;
+
+	RTS;
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long   0
+__ramstart:
+.long   0
+__ramend:
+.long   0
diff --git a/arch/blackfin/mach-bf561/ints-priority.c b/arch/blackfin/mach-bf561/ints-priority.c
new file mode 100644
index 0000000..89c52ff
--- /dev/null
+++ b/arch/blackfin/mach-bf561/ints-priority.c
@@ -0,0 +1,108 @@
+/*
+ * File:         arch/blackfin/mach-bf561/ints-priority.c
+ * Based on:     arch/blackfin/mach-bf537/ints-priority.c
+ * Author:       Michael Hennerich
+ *
+ * Created:
+ * Description:  Set up the interupt priorities
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+	/* Program the IAR0 Register with the configured priority */
+	bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+			     ((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) |
+			     ((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) |
+			     ((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) |
+			     ((CONFIG_IRQ_PPI0_ERROR - 7) << IRQ_PPI0_ERROR_POS) |
+			     ((CONFIG_IRQ_PPI1_ERROR - 7) << IRQ_PPI1_ERROR_POS) |
+			     ((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
+			     ((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS));
+
+	bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
+			     ((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) |
+			     ((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) |
+			     ((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) |
+			     ((CONFIG_IRQ_DMA1_1 - 7) << IRQ_DMA1_1_POS) |
+			     ((CONFIG_IRQ_DMA1_2 - 7) << IRQ_DMA1_2_POS) |
+			     ((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) |
+			     ((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS));
+
+	bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
+			     ((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) |
+			     ((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) |
+			     ((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) |
+			     ((CONFIG_IRQ_DMA1_9 - 7) << IRQ_DMA1_9_POS) |
+			     ((CONFIG_IRQ_DMA1_10 - 7) << IRQ_DMA1_10_POS) |
+			     ((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) |
+			     ((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS));
+
+	bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
+			     ((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) |
+			     ((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) |
+			     ((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) |
+			     ((CONFIG_IRQ_DMA2_5 - 7) << IRQ_DMA2_5_POS) |
+			     ((CONFIG_IRQ_DMA2_6 - 7) << IRQ_DMA2_6_POS) |
+			     ((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) |
+			     ((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS));
+
+	bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
+			     ((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) |
+			     ((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) |
+			     ((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
+			     ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) |
+			     ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) |
+			     ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
+			     ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS));
+
+	bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
+			     ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
+			     ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
+			     ((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
+			     ((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) |
+			     ((CONFIG_IRQ_TIMER10 - 7) << IRQ_TIMER10_POS) |
+			     ((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) |
+			     ((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS));
+
+	bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
+			     ((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) |
+			     ((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) |
+			     ((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) |
+			     ((CONFIG_IRQ_PROG2_INTB - 7) << IRQ_PROG2_INTB_POS) |
+			     ((CONFIG_IRQ_DMA1_WRRD0 - 7) << IRQ_DMA1_WRRD0_POS) |
+			     ((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) |
+			     ((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS));
+
+	bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
+			     ((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) |
+			     ((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) |
+			     ((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) |
+			     (0 << IRQ_RESERVED_1_POS) | (0 << IRQ_RESERVED_2_POS) |
+			     (0 << IRQ_SUPPLE_0_POS) | (0 << IRQ_SUPPLE_1_POS));
+
+	SSYNC();
+}
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
new file mode 100644
index 0000000..d3a4907
--- /dev/null
+++ b/arch/blackfin/mach-common/Makefile
@@ -0,0 +1,12 @@
+#
+# arch/blackfin/mach-common/Makefile
+#
+
+obj-y := \
+	cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
+	interrupt.o lock.o dpmc.o irqpanic.o
+
+obj-$(CONFIG_CPLB_INFO)          += cplbinfo.o
+obj-$(CONFIG_BFIN_SINGLE_CORE)   += ints-priority-sc.o
+obj-$(CONFIG_BFIN_DUAL_CORE)     += ints-priority-dc.o
+obj-$(CONFIG_PM)                 += pm.o
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
new file mode 100644
index 0000000..bb9446e
--- /dev/null
+++ b/arch/blackfin/mach-common/cache.S
@@ -0,0 +1,253 @@
+/*
+ * File:         arch/blackfin/mach-common/cache.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:
+ * Description:  cache control support
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/entry.h>
+#include <asm/blackfin.h>
+#include <asm/cache.h>
+
+.text
+.align 2
+ENTRY(_cache_invalidate)
+
+	/*
+	 * Icache or DcacheA or DcacheB Invalidation
+	 * or any combination thereof
+	 * R0 has bits
+	 * CPLB_ENABLE_ICACHE_P,CPLB_ENABLE_DCACHE_P,CPLB_ENABLE_DCACHE2_P
+	 * set as required
+	 */
+	[--SP] = R7;
+
+	R7 = R0;
+	CC = BITTST(R7,CPLB_ENABLE_ICACHE_P);
+	IF !CC JUMP .Lno_icache;
+	[--SP] = RETS;
+	CALL _icache_invalidate;
+	RETS = [SP++];
+.Lno_icache:
+	CC = BITTST(R7,CPLB_ENABLE_DCACHE_P);
+	IF !CC JUMP .Lno_dcache_a;
+	R0 = 0;         /* specifies bank A */
+	[--SP] = RETS;
+	CALL _dcache_invalidate;
+	RETS = [SP++];
+.Lno_dcache_a:
+	CC = BITTST(R7,CPLB_ENABLE_DCACHE2_P);
+	IF !CC JUMP .Lno_dcache_b;
+	R0 = 0;
+	BITSET(R0, 23);		/* specifies bank B */
+	[--SP] = RETS;
+	CALL  _dcache_invalidate;
+	RETS = [SP++];
+.Lno_dcache_b:
+	R7 = [SP++];
+	RTS;
+
+/* Invalidate the Entire Instruction cache by
+ * disabling IMC bit
+ */
+ENTRY(_icache_invalidate)
+ENTRY(_invalidate_entire_icache)
+	[--SP] = ( R7:5);
+
+	P0.L = (IMEM_CONTROL & 0xFFFF);
+	P0.H = (IMEM_CONTROL >> 16);
+	R7 = [P0];
+
+	/* Clear the IMC bit , All valid bits in the instruction
+	 * cache are set to the invalid state
+	 */
+	BITCLR(R7,IMC_P);
+	CLI R6;
+	SSYNC;		/* SSYNC required before invalidating cache. */
+	.align 8;
+	[P0] = R7;
+	SSYNC;
+	STI R6;
+
+	/* Configures the instruction cache agian */
+	R6 = (IMC | ENICPLB);
+	R7 = R7 | R6;
+
+	CLI R6;
+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+	.align 8;
+	[P0] = R7;
+	SSYNC;
+	STI R6;
+
+	( R7:5) = [SP++];
+	RTS;
+
+/*
+ * blackfin_cache_flush_range(start, end)
+ * Invalidate all cache lines assocoiated with this
+ * area of memory.
+ *
+ * start:	Start address
+ * end:		End address
+ */
+ENTRY(_blackfin_icache_flush_range)
+	R2 = -L1_CACHE_BYTES;
+	R2 = R0 & R2;
+	P0 = R2;
+	P1 = R1;
+	CSYNC;
+	IFLUSH [P0];
+1:
+	IFLUSH [P0++];
+	CC = P0 < P1 (iu);
+	IF CC JUMP 1b (bp);
+	IFLUSH [P0];
+	SSYNC;
+	RTS;
+
+/*
+ * blackfin_icache_dcache_flush_range(start, end)
+ * FLUSH all cache lines assocoiated with this
+ * area of memory.
+ *
+ * start:	Start address
+ * end:		End address
+ */
+
+ENTRY(_blackfin_icache_dcache_flush_range)
+	R2 = -L1_CACHE_BYTES;
+	R2 = R0 & R2;
+	P0 = R2;
+	P1 = R1;
+	CSYNC;
+	IFLUSH [P0];
+1:
+	FLUSH [P0];
+	IFLUSH [P0++];
+	CC = P0 < P1 (iu);
+	IF CC JUMP 1b (bp);
+	IFLUSH [P0];
+	FLUSH [P0];
+	SSYNC;
+	RTS;
+
+/* Throw away all D-cached data in specified region without any obligation to
+ * write them back. However, we must clean the D-cached entries around the
+ * boundaries of the start and/or end address is not cache aligned.
+ *
+ * Start: start address,
+ * end  : end address.
+ */
+
+ENTRY(_blackfin_dcache_invalidate_range)
+	R2 = -L1_CACHE_BYTES;
+	R2 = R0 & R2;
+	P0 = R2;
+	P1 = R1;
+	CSYNC;
+	FLUSHINV[P0];
+1:
+	FLUSHINV[P0++];
+	CC = P0 < P1 (iu);
+	IF CC JUMP 1b (bp);
+
+	/* If the data crosses a cache line, then we'll be pointing to
+	 * the last cache line, but won't have flushed/invalidated it yet,
+	 * so do one more.
+	 */
+	FLUSHINV[P0];
+	SSYNC;
+	RTS;
+
+/* Invalidate the Entire Data cache by
+ * clearing DMC[1:0] bits
+ */
+ENTRY(_invalidate_entire_dcache)
+ENTRY(_dcache_invalidate)
+	[--SP] = ( R7:6);
+
+	P0.L = (DMEM_CONTROL & 0xFFFF);
+	P0.H = (DMEM_CONTROL >> 16);
+	R7 = [P0];
+
+	/* Clear the DMC[1:0] bits, All valid bits in the data
+	 * cache are set to the invalid state
+	 */
+	BITCLR(R7,DMC0_P);
+	BITCLR(R7,DMC1_P);
+	CLI R6;
+	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
+	.align 8;
+	[P0] = R7;
+	SSYNC;
+	STI R6;
+
+	/* Configures the data cache again */
+
+	R6 = DMEM_CNTR;
+	R7 = R7 | R6;
+
+	CLI R6;
+	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
+	.align 8;
+	[P0] = R7;
+	SSYNC;
+	STI R6;
+
+	( R7:6) = [SP++];
+	RTS;
+
+ENTRY(_blackfin_dcache_flush_range)
+	R2 = -L1_CACHE_BYTES;
+	R2 = R0 & R2;
+	P0 = R2;
+	P1 = R1;
+	CSYNC;
+	FLUSH[P0];
+1:
+	FLUSH[P0++];
+	CC = P0 < P1 (iu);
+	IF CC JUMP 1b (bp);
+
+	/* If the data crosses a cache line, then we'll be pointing to
+	 * the last cache line, but won't have flushed it yet, so do
+	 * one more.
+	 */
+	FLUSH[P0];
+	SSYNC;
+	RTS;
+
+ENTRY(_blackfin_dflush_page)
+	P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
+	P0 = R0;
+	CSYNC;
+	FLUSH[P0];
+	LSETUP (.Lfl1, .Lfl1) LC0 = P1;
+.Lfl1:	FLUSH [P0++];
+	SSYNC;
+	RTS;
diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S
new file mode 100644
index 0000000..8c17f09
--- /dev/null
+++ b/arch/blackfin/mach-common/cacheinit.S
@@ -0,0 +1,137 @@
+/*
+ * File:         arch/blackfin/mach-common/cacheinit.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:      ?
+ * Description:  cache initialization
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This function sets up the data and instruction cache. The
+ * tables like icplb table, dcplb table and Page Descriptor table
+ * are defined in cplbtab.h. You can configure those tables for
+ * your suitable requirements
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+.text
+
+#if defined(CONFIG_BLKFIN_CACHE)
+ENTRY(_bfin_icache_init)
+
+	/* Initialize Instruction CPLBS */
+
+	I0.L = (ICPLB_ADDR0 & 0xFFFF);
+	I0.H = (ICPLB_ADDR0 >> 16);
+
+	I1.L = (ICPLB_DATA0 & 0xFFFF);
+	I1.H = (ICPLB_DATA0 >> 16);
+
+	I2.L = _icplb_table;
+	I2.H = _icplb_table;
+
+	r1 = -1;	/* end point comparison */
+	r3 = 15;	/* max counter */
+
+/* read entries from table */
+
+.Lread_iaddr:
+	R0 = [I2++];
+	CC = R0 == R1;
+	IF CC JUMP .Lidone;
+	[I0++] = R0;
+
+.Lread_idata:
+	R2 = [I2++];
+	[I1++] = R2;
+	R3 = R3 + R1;
+	CC = R3 == R1;
+	IF !CC JUMP .Lread_iaddr;
+
+.Lidone:
+	/* Enable Instruction Cache */
+	P0.l = (IMEM_CONTROL & 0xFFFF);
+	P0.h = (IMEM_CONTROL >> 16);
+	R1 = [P0];
+	R0 = (IMC | ENICPLB);
+	R0 = R0 | R1;
+
+	/* Anomaly 05000125 */
+	CLI R2;
+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+	.align 8;
+	[P0] = R0;
+	SSYNC;
+	STI R2;
+	RTS;
+#endif
+
+#if defined(CONFIG_BLKFIN_DCACHE)
+ENTRY(_bfin_dcache_init)
+
+	/* Initialize Data CPLBS */
+
+	I0.L = (DCPLB_ADDR0 & 0xFFFF);
+	I0.H = (DCPLB_ADDR0 >> 16);
+
+	I1.L = (DCPLB_DATA0 & 0xFFFF);
+	I1.H = (DCPLB_DATA0 >> 16);
+
+	I2.L = _dcplb_table;
+	I2.H = _dcplb_table;
+
+	R1 = -1;	/* end point comparison */
+	R3 = 15;	/* max counter */
+
+	/* read entries from table */
+.Lread_daddr:
+	R0 = [I2++];
+	cc = R0 == R1;
+	IF CC JUMP .Lddone;
+	[I0++] = R0;
+
+.Lread_ddata:
+	R2 = [I2++];
+	[I1++] = R2;
+	R3 = R3 + R1;
+	CC = R3 == R1;
+	IF !CC JUMP .Lread_daddr;
+.Lddone:
+	P0.L = (DMEM_CONTROL & 0xFFFF);
+	P0.H = (DMEM_CONTROL >> 16);
+	R1 = [P0];
+
+	R0 = DMEM_CNTR;
+
+	R0 = R0 | R1;
+	/* Anomaly 05000125 */
+	CLI R2;
+	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
+	.align 8;
+	[P0] = R0;
+	SSYNC;
+	STI R2;
+	RTS;
+#endif
diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S
new file mode 100644
index 0000000..b979067
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbhdlr.S
@@ -0,0 +1,130 @@
+/*
+ * File:         arch/blackfin/mach-common/cplbhdlr.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:      ?
+ * Description:  CPLB exception handler
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/entry.h>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.type _cplb_mgr, STT_FUNC;
+.type _panic_cplb_error, STT_FUNC;
+
+.align 2
+
+.global __cplb_hdr;
+.type __cplb_hdr, STT_FUNC;
+ENTRY(__cplb_hdr)
+	R2 = SEQSTAT;
+
+	/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
+	R2 <<= 26;
+	R2 >>= 26;
+
+	R1 = 0x23; /* Data access CPLB protection violation */
+	CC = R2 == R1;
+	IF !CC JUMP .Lnot_data_write;
+	R0 = 2;		/* is a write to data space*/
+	JUMP .Lis_icplb_miss;
+
+.Lnot_data_write:
+	R1 = 0x2C; /* CPLB miss on an instruction fetch */
+	CC = R2 == R1;
+	R0 = 0;		/* is_data_miss == False*/
+	IF CC JUMP .Lis_icplb_miss;
+
+	R1 = 0x26;
+	CC = R2 == R1;
+	IF !CC JUMP .Lunknown;
+
+	R0 = 1;		/* is_data_miss == True*/
+
+.Lis_icplb_miss:
+
+#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE)
+# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE)
+	R1 = CPLB_ENABLE_ICACHE;
+# endif
+# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
+	R1 = CPLB_ENABLE_DCACHE;
+# endif
+# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
+	R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
+# endif
+#else
+	R1 = 0;
+#endif
+
+	[--SP] = RETS;
+	CALL _cplb_mgr;
+	RETS = [SP++];
+	CC = R0 == 0;
+	IF !CC JUMP .Lnot_replaced;
+	RTS;
+
+/*
+ * Diagnostic exception handlers
+ */
+.Lunknown:
+	R0 = CPLB_UNKNOWN_ERR;
+	JUMP .Lcplb_error;
+
+.Lnot_replaced:
+	CC = R0 == CPLB_NO_UNLOCKED;
+	IF !CC JUMP .Lnext_check;
+	R0 = CPLB_NO_UNLOCKED;
+	JUMP .Lcplb_error;
+
+.Lnext_check:
+	CC = R0 == CPLB_NO_ADDR_MATCH;
+	IF !CC JUMP .Lnext_check2;
+	R0 = CPLB_NO_ADDR_MATCH;
+	JUMP .Lcplb_error;
+
+.Lnext_check2:
+	CC = R0 == CPLB_PROT_VIOL;
+	IF !CC JUMP .Lstrange_return_from_cplb_mgr;
+	R0 = CPLB_PROT_VIOL;
+	JUMP .Lcplb_error;
+
+.Lstrange_return_from_cplb_mgr:
+	IDLE;
+	CSYNC;
+	JUMP .Lstrange_return_from_cplb_mgr;
+
+.Lcplb_error:
+	R1 = sp;
+	SP += -12;
+	call _panic_cplb_error;
+	SP += 12;
+	JUMP _handle_bad_cplb;
diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
new file mode 100644
index 0000000..d65fac3
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbinfo.c
@@ -0,0 +1,211 @@
+/*
+ * File:         arch/blackfin/mach-common/cplbinfo.c
+ * Based on:
+ * Author:       Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:      Jan. 2005
+ * Description:  Display CPLB status
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <asm/cplb.h>
+#include <asm/blackfin.h>
+
+#define CPLB_I 1
+#define CPLB_D 2
+
+#define SYNC_SYS    SSYNC()
+#define SYNC_CORE   CSYNC()
+
+#define CPLB_BIT_PAGESIZE 0x30000
+
+static int page_size_table[4] = {
+	0x00000400,		/* 1K */
+	0x00001000,		/* 4K */
+	0x00100000,		/* 1M */
+	0x00400000		/* 4M */
+};
+
+static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+
+static int cplb_find_entry(unsigned long *cplb_addr,
+			   unsigned long *cplb_data, unsigned long addr,
+			   unsigned long data)
+{
+	int ii;
+
+	for (ii = 0; ii < 16; ii++)
+		if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
+		    page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
+			&& (cplb_data[ii] == data))
+			return ii;
+
+	return -1;
+}
+
+static char *cplb_print_entry(char *buf, int type)
+{
+	unsigned long *p_addr = dpdt_table;
+	unsigned long *p_data = dpdt_table + 1;
+	unsigned long *p_icount = dpdt_swapcount_table;
+	unsigned long *p_ocount = dpdt_swapcount_table + 1;
+	unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
+	unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
+	int entry = 0, used_cplb = 0;
+
+	if (type == CPLB_I) {
+		buf += sprintf(buf, "Instrction CPLB entry:\n");
+		p_addr = ipdt_table;
+		p_data = ipdt_table + 1;
+		p_icount = ipdt_swapcount_table;
+		p_ocount = ipdt_swapcount_table + 1;
+		cplb_addr = (unsigned long *)ICPLB_ADDR0;
+		cplb_data = (unsigned long *)ICPLB_DATA0;
+	} else
+		buf += sprintf(buf, "Data CPLB entry:\n");
+
+	buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\
+\tiCount\toCount\n");
+
+	while (*p_addr != 0xffffffff) {
+		entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
+		if (entry >= 0)
+			used_cplb |= 1 << entry;
+
+		buf +=
+		    sprintf(buf,
+			    "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
+			    *p_addr, *p_data,
+			    page_size_string_table[(*p_data & 0x30000) >> 16],
+			    (*p_data & CPLB_VALID) ? 'Y' : 'N',
+			    (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
+			    *p_ocount);
+
+		p_addr += 2;
+		p_data += 2;
+		p_icount += 2;
+		p_ocount += 2;
+	}
+
+	if (used_cplb != 0xffff) {
+		buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
+
+		for (entry = 0; entry < 16; entry++)
+			if (0 == ((1 << entry) & used_cplb)) {
+				int flags = cplb_data[entry];
+				buf +=
+				    sprintf(buf,
+					    "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
+					    entry, cplb_addr[entry], flags,
+					    page_size_string_table[(flags &
+								    0x30000) >>
+								   16],
+					    (flags & CPLB_VALID) ? 'Y' : 'N',
+					    (flags & CPLB_LOCK) ? 'Y' : 'N');
+			}
+	}
+
+	buf += sprintf(buf, "\n");
+
+	return buf;
+}
+
+static int cplbinfo_proc_output(char *buf)
+{
+	char *p;
+
+	p = buf;
+
+	p += sprintf(p,
+		     "------------------ CPLB Information ------------------\n\n");
+
+	if (bfin_read_IMEM_CONTROL() & ENICPLB)
+		p = cplb_print_entry(p, CPLB_I);
+	else
+		p += sprintf(p, "Instruction CPLB is disabled.\n\n");
+
+	if (bfin_read_DMEM_CONTROL() & ENDCPLB)
+		p = cplb_print_entry(p, CPLB_D);
+	else
+		p += sprintf(p, "Data CPLB is disabled.\n");
+
+	return p - buf;
+}
+
+static int cplbinfo_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	int len;
+
+	len = cplbinfo_proc_output(page);
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
+			       unsigned long count, void *data)
+{
+	printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
+	memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
+	memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
+
+	return count;
+}
+
+static int __init cplbinfo_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	if ((entry = create_proc_entry("cplbinfo", 0, NULL)) == NULL) {
+		return -ENOMEM;
+	}
+
+	entry->read_proc = cplbinfo_read_proc;
+	entry->write_proc = cplbinfo_write_proc;
+	entry->data = NULL;
+
+	return 0;
+}
+
+static void __exit cplbinfo_exit(void)
+{
+	remove_proc_entry("cplbinfo", NULL);
+}
+
+module_init(cplbinfo_init);
+module_exit(cplbinfo_exit);
diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
new file mode 100644
index 0000000..f5efc4b
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbmgr.S
@@ -0,0 +1,607 @@
+/*
+ * File:         arch/blackfin/mach-common/cplbmgtr.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:      ?
+ * Description:  CPLB replacement routine for CPLB mismatch
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
+ * is_data_miss==2 => Mark as Dirty, write to the clean data page
+ * is_data_miss==1 => Replace a data CPLB.
+ * is_data_miss==0 => Replace an instruction CPLB.
+ *
+ * Returns:
+ * CPLB_RELOADED	=> Successfully updated CPLB table.
+ * CPLB_NO_UNLOCKED	=> All CPLBs are locked, so cannot be evicted.
+ *			   This indicates that the CPLBs in the configuration
+ *			   tablei are badly configured, as this should never
+ *			   occur.
+ * CPLB_NO_ADDR_MATCH	=> The address being accessed, that triggered the
+ *			   exception, is not covered by any of the CPLBs in
+ *			   the configuration table. The application is
+ *			   presumably misbehaving.
+ * CPLB_PROT_VIOL	=> The address being accessed, that triggered the
+ *			   exception, was not a first-write to a clean Write
+ *			   Back Data page, and so presumably is a genuine
+ *			   violation of the page's protection attributes.
+ *			   The application is misbehaving.
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2;
+ENTRY(_cplb_mgr)
+
+	[--SP]=( R7:4,P5:3 );
+
+	CC = R0 == 2;
+	IF CC JUMP .Ldcplb_write;
+
+	CC = R0 == 0;
+	IF !CC JUMP .Ldcplb_miss_compare;
+
+	/* ICPLB Miss Exception. We need to choose one of the
+	* currently-installed CPLBs, and replace it with one
+	* from the configuration table.
+ 	*/
+
+	P4.L = (ICPLB_FAULT_ADDR & 0xFFFF);
+	P4.H = (ICPLB_FAULT_ADDR >> 16);
+
+	P1 = 16;
+	P5.L = _page_size_table;
+	P5.H = _page_size_table;
+
+	P0.L = (ICPLB_DATA0 & 0xFFFF);
+	P0.H = (ICPLB_DATA0 >> 16);
+	R4 = [P4];		/* Get faulting address*/
+	R6 = 64;		/* Advance past the fault address, which*/
+	R6 = R6 + R4;		/* we'll use if we find a match*/
+	R3 = ((16 << 8) | 2);	/* Extract mask, bits 16 and 17.*/
+
+	R5 = 0;
+.Lisearch:
+
+	R1 = [P0-0x100];	/* Address for this CPLB */
+
+	R0 = [P0++];		/* Info for this CPLB*/
+	CC = BITTST(R0,0);	/* Is the CPLB valid?*/
+	IF !CC JUMP .Lnomatch;	/* Skip it, if not.*/
+	CC = R4 < R1(IU);	/* If fault address less than page start*/
+	IF CC JUMP .Lnomatch;	/* then skip this one.*/
+	R2 = EXTRACT(R0,R3.L) (Z);	/* Get page size*/
+	P1 = R2;
+	P1 = P5 + (P1<<2);	/* index into page-size table*/
+	R2 = [P1];		/* Get the page size*/
+	R1 = R1 + R2;		/* and add to page start, to get page end*/
+	CC = R4 < R1(IU);	/* and see whether fault addr is in page.*/
+	IF !CC R4 = R6;		/* If so, advance the address and finish loop.*/
+	IF !CC JUMP .Lisearch_done;
+.Lnomatch:
+	/* Go around again*/
+	R5 += 1;
+	CC = BITTST(R5, 4);	/* i.e CC = R5 >= 16*/
+	IF !CC JUMP .Lisearch;
+
+.Lisearch_done:
+	I0 = R4;		/* Fault address we'll search for*/
+
+	/* set up pointers */
+	P0.L = (ICPLB_DATA0 & 0xFFFF);
+	P0.H = (ICPLB_DATA0 >> 16);
+
+	/* The replacement procedure for ICPLBs */
+
+	P4.L = (IMEM_CONTROL & 0xFFFF);
+	P4.H = (IMEM_CONTROL >> 16);
+
+	/* disable cplbs */
+	R5 = [P4];		/* Control Register*/
+	BITCLR(R5,ENICPLB_P);
+	CLI R1;
+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+	.align 8;
+	[P4] = R5;
+	SSYNC;
+	STI R1;
+
+	R1 = -1;		/* end point comparison */
+	R3 = 16;		/* counter */
+
+	/* Search through CPLBs for first non-locked entry */
+	/* Overwrite it by moving everyone else up by 1 */
+.Licheck_lock:
+	R0 = [P0++];
+	R3 = R3 + R1;
+	CC = R3 == R1;
+	IF CC JUMP .Lall_locked;
+	CC = BITTST(R0, 0);		/* an invalid entry is good */
+	IF !CC JUMP .Lifound_victim;
+	CC = BITTST(R0,1);		/* but a locked entry isn't */
+	IF CC JUMP .Licheck_lock;
+
+.Lifound_victim:
+#ifdef CONFIG_CPLB_INFO
+	R7 = [P0 - 0x104];
+	P2.L = _ipdt_table;
+	P2.H = _ipdt_table;
+	P3.L = _ipdt_swapcount_table;
+	P3.H = _ipdt_swapcount_table;
+	P3 += -4;
+.Licount:
+	R2 = [P2];	/* address from config table */
+	P2 += 8;
+	P3 += 8;
+	CC = R2==-1;
+	IF CC JUMP .Licount_done;
+	CC = R7==R2;
+	IF !CC JUMP .Licount;
+	R7 = [P3];
+	R7 += 1;
+	[P3] = R7;
+	CSYNC;
+.Licount_done:
+#endif
+	LC0=R3;
+	LSETUP(.Lis_move,.Lie_move) LC0;
+.Lis_move:
+	R0 = [P0];
+	[P0 - 4] = R0;
+	R0 = [P0 - 0x100];
+	[P0-0x104] = R0;
+.Lie_move:P0+=4;
+
+	/* We've made space in the ICPLB table, so that ICPLB15
+	 * is now free to be overwritten. Next, we have to determine
+	 * which CPLB we need to install, from the configuration
+	 * table. This is a matter of getting the start-of-page
+	 * addresses and page-lengths from the config table, and
+	 * determining whether the fault address falls within that
+	 * range.
+ 	 */
+
+	P2.L = _ipdt_table;
+	P2.H = _ipdt_table;
+#ifdef	CONFIG_CPLB_INFO
+	P3.L = _ipdt_swapcount_table;
+	P3.H = _ipdt_swapcount_table;
+	P3 += -8;
+#endif
+	P0.L = _page_size_table;
+	P0.H = _page_size_table;
+
+	/* Retrieve our fault address (which may have been advanced
+	 * because the faulting instruction crossed a page boundary).
+	 */
+
+	R0 = I0;
+
+	/* An extraction pattern, to get the page-size bits from
+	 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
+	 */
+
+	R1 = ((16<<8)|2);
+.Linext:	R4 = [P2++];	/* address from config table */
+	R2 = [P2++];	/* data from config table */
+#ifdef	CONFIG_CPLB_INFO
+	P3 += 8;
+#endif
+
+	CC = R4 == -1;	/* End of config table*/
+	IF CC JUMP .Lno_page_in_table;
+
+	/* See if failed address > start address */
+	CC = R4 <= R0(IU);
+ 	IF !CC JUMP .Linext;
+
+	/* extract page size (17:16)*/
+	R3 = EXTRACT(R2, R1.L) (Z);
+
+	/* add page size to addr to get range */
+
+	P5 = R3;
+	P5 = P0 + (P5 << 2);	/* scaled, for int access*/
+	R3 = [P5];
+	R3 = R3 + R4;
+
+	/* See if failed address < (start address + page size) */
+	CC = R0 < R3(IU);
+	IF !CC JUMP .Linext;
+
+	/* We've found a CPLB in the config table that covers
+	 * the faulting address, so install this CPLB into the
+	 * last entry of the table.
+	 */
+
+	P1.L = (ICPLB_DATA15 & 0xFFFF);		/* ICPLB_DATA15 */
+	P1.H = (ICPLB_DATA15 >> 16);
+	[P1] = R2;
+	[P1-0x100] = R4;
+#ifdef	CONFIG_CPLB_INFO
+	R3 = [P3];
+	R3 += 1;
+	[P3] = R3;
+#endif
+
+	/* P4 points to IMEM_CONTROL, and R5 contains its old
+	 * value, after we disabled ICPLBS. Re-enable them.
+	 */
+
+	BITSET(R5,ENICPLB_P);
+	CLI R2;
+	SSYNC;		/* SSYNC required before writing to IMEM_CONTROL. */
+	.align 8;
+	[P4] = R5;
+	SSYNC;
+	STI R2;
+
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_RELOADED;
+	RTS;
+
+/* FAILED CASES*/
+.Lno_page_in_table:
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_NO_ADDR_MATCH;
+	RTS;
+.Lall_locked:
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_NO_UNLOCKED;
+	RTS;
+.Lprot_violation:
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_PROT_VIOL;
+	RTS;
+
+.Ldcplb_write:
+
+	/* if a DCPLB is marked as write-back (CPLB_WT==0), and
+	 * it is clean (CPLB_DIRTY==0), then a write to the
+	 * CPLB's page triggers a protection violation. We have to
+	 * mark the CPLB as dirty, to indicate that there are
+	 * pending writes associated with the CPLB.
+	 */
+
+	P4.L = (DCPLB_STATUS & 0xFFFF);
+	P4.H = (DCPLB_STATUS >> 16);
+	P3.L = (DCPLB_DATA0 & 0xFFFF);
+	P3.H = (DCPLB_DATA0 >> 16);
+	R5 = [P4];
+
+	/* A protection violation can be caused by more than just writes
+	 * to a clean WB page, so we have to ensure that:
+	 * - It's a write
+	 * - to a clean WB page
+	 * - and is allowed in the mode the access occurred.
+	 */
+
+	CC = BITTST(R5, 16);	/* ensure it was a write*/
+	IF !CC JUMP .Lprot_violation;
+
+	/* to check the rest, we have to retrieve the DCPLB.*/
+
+	/* The low half of DCPLB_STATUS is a bit mask*/
+
+	R2 = R5.L (Z);	/* indicating which CPLB triggered the event.*/
+	R3 = 30;	/* so we can use this to determine the offset*/
+	R2.L = SIGNBITS R2;
+	R2 = R2.L (Z);	/* into the DCPLB table.*/
+	R3 = R3 - R2;
+	P4 = R3;
+	P3 = P3 + (P4<<2);
+	R3 = [P3];	/* Retrieve the CPLB*/
+
+	/* Now we can check whether it's a clean WB page*/
+
+	CC = BITTST(R3, 14);	/* 0==WB, 1==WT*/
+	IF CC JUMP .Lprot_violation;
+	CC = BITTST(R3, 7);	/* 0 == clean, 1 == dirty*/
+	IF CC JUMP .Lprot_violation;
+
+	/* Check whether the write is allowed in the mode that was active.*/
+
+	R2 = 1<<3;		/* checking write in user mode*/
+	CC = BITTST(R5, 17);	/* 0==was user, 1==was super*/
+	R5 = CC;
+	R2 <<= R5;		/* if was super, check write in super mode*/
+	R2 = R3 & R2;
+	CC = R2 == 0;
+	IF CC JUMP .Lprot_violation;
+
+	/* It's a genuine write-to-clean-page.*/
+
+	BITSET(R3, 7);		/* mark as dirty*/
+	[P3] = R3;		/* and write back.*/
+	NOP;
+	CSYNC;
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_RELOADED;
+	RTS;
+
+.Ldcplb_miss_compare:
+
+	/* Data CPLB Miss event. We need to choose a CPLB to
+	 * evict, and then locate a new CPLB to install from the
+	 * config table, that covers the faulting address.
+	 */
+
+	P1.L = (DCPLB_DATA15 & 0xFFFF);
+	P1.H = (DCPLB_DATA15 >> 16);
+
+	P4.L = (DCPLB_FAULT_ADDR & 0xFFFF);
+	P4.H = (DCPLB_FAULT_ADDR >> 16);
+	R4 = [P4];
+	I0 = R4;
+
+	/* The replacement procedure for DCPLBs*/
+
+	R6 = R1;	/* Save for later*/
+
+	/* Turn off CPLBs while we work.*/
+	P4.L = (DMEM_CONTROL & 0xFFFF);
+	P4.H = (DMEM_CONTROL >> 16);
+	R5 = [P4];
+	BITCLR(R5,ENDCPLB_P);
+	CLI R0;
+	SSYNC;		/* SSYNC required before writing to DMEM_CONTROL. */
+	.align 8;
+	[P4] = R5;
+	SSYNC;
+	STI R0;
+
+	/* Start looking for a CPLB to evict. Our order of preference
+	 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
+	 * are no good.
+	 */
+
+	I1.L = (DCPLB_DATA0 & 0xFFFF);
+	I1.H = (DCPLB_DATA0 >> 16);
+	P1 = 2;
+	P2 = 16;
+	I2.L = _dcplb_preference;
+	I2.H = _dcplb_preference;
+	LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
+.Lsdsearch1:
+	R0 = [I2++];		/* Get the bits we're interested in*/
+	P0 = I1;		/* Go back to start of table*/
+	LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
+.Lsdsearch2:
+	R1 = [P0++];		/* Fetch each installed CPLB in turn*/
+	R2 = R1 & R0;		/* and test for interesting bits.*/
+	CC = R2 == 0;		/* If none are set, it'll do.*/
+	IF !CC JUMP .Lskip_stack_check;
+
+	R2 = [P0 - 0x104]; 	/* R2 - PageStart */
+	P3.L = _page_size_table; /* retrieve end address */
+	P3.H = _page_size_table; /* retrieve end address */
+	R3 = 0x1002;		/* 16th - position, 2 bits -length */
+#ifdef ANOMALY_05000209
+	nop;			/* Anomaly 05000209 */
+#endif
+	R7 = EXTRACT(R1,R3.l);
+	R7 = R7 << 2;		/* Page size index offset */
+	P5 = R7;
+	P3 = P3 + P5;
+	R7 = [P3];		/* page size in bytes */
+
+	R7 = R2 + R7;		/* R7 - PageEnd */
+	R4 = SP; 		/* Test SP is in range */
+
+	CC = R7 < R4;		/* if PageEnd < SP */
+	IF CC JUMP .Ldfound_victim;
+	R3 = 0x284;		/* stack length from start of trap till
+				 * the point.
+				 * 20 stack locations for future modifications
+				 */
+	R4 = R4 + R3;
+	CC = R4 < R2;		/* if SP + stacklen < PageStart */
+	IF CC JUMP .Ldfound_victim;
+.Lskip_stack_check:
+
+.Ledsearch2: NOP;
+.Ledsearch1: NOP;
+
+	/* If we got here, we didn't find a DCPLB we considered
+	 * replacable, which means all of them were locked.
+	 */
+
+	JUMP .Lall_locked;
+.Ldfound_victim:
+
+#ifdef CONFIG_CPLB_INFO
+	R7 = [P0 - 0x104];
+	P2.L = _dpdt_table;
+	P2.H = _dpdt_table;
+	P3.L = _dpdt_swapcount_table;
+	P3.H = _dpdt_swapcount_table;
+	P3 += -4;
+.Ldicount:
+	R2 = [P2];
+	P2 += 8;
+	P3 += 8;
+	CC = R2==-1;
+	IF CC JUMP .Ldicount_done;
+	CC = R7==R2;
+	IF !CC JUMP .Ldicount;
+	R7 = [P3];
+	R7 += 1;
+	[P3] = R7;
+.Ldicount_done:
+#endif
+
+	/* Clean down the hardware loops*/
+	R2 = 0;
+	LC1 = R2;
+	LC0 = R2;
+
+	/* There's a suitable victim in [P0-4] (because we've
+	 * advanced already).
+	 */
+
+.LDdoverwrite:
+
+	/* [P0-4] is a suitable victim CPLB, so we want to
+	 * overwrite it by moving all the following CPLBs
+	 * one space closer to the start.
+	 */
+
+	R1.L = (DCPLB_DATA16 & 0xFFFF);		/* DCPLB_DATA15 + 4 */
+	R1.H = (DCPLB_DATA16 >> 16);
+	R0 = P0;
+
+	/* If the victim happens to be in DCPLB15,
+	 * we don't need to move anything.
+	 */
+
+	CC = R1 == R0;
+	IF CC JUMP .Lde_moved;
+	R1 = R1 - R0;
+	R1 >>= 2;
+	P1 = R1;
+	LSETUP(.Lds_move, .Lde_move) LC0=P1;
+.Lds_move:
+	R0 = [P0++];	/* move data */
+	[P0 - 8] = R0;
+	R0 = [P0-0x104]	/* move address */
+.Lde_move: [P0-0x108] = R0;
+
+	/* We've now made space in DCPLB15 for the new CPLB to be
+	 * installed. The next stage is to locate a CPLB in the
+	 * config table that covers the faulting address.
+	 */
+
+.Lde_moved:NOP;
+	R0 = I0;		/* Our faulting address */
+
+	P2.L = _dpdt_table;
+	P2.H = _dpdt_table;
+#ifdef	CONFIG_CPLB_INFO
+	P3.L = _dpdt_swapcount_table;
+	P3.H = _dpdt_swapcount_table;
+	P3 += -8;
+#endif
+
+	P1.L = _page_size_table;
+	P1.H = _page_size_table;
+
+	/* An extraction pattern, to retrieve bits 17:16.*/
+
+	R1 = (16<<8)|2;
+.Ldnext:	R4 = [P2++];	/* address */
+	R2 = [P2++];	/* data */
+#ifdef	CONFIG_CPLB_INFO
+	P3 += 8;
+#endif
+
+	CC = R4 == -1;
+	IF CC JUMP .Lno_page_in_table;
+
+	/* See if failed address > start address */
+	CC = R4 <= R0(IU);
+	IF !CC JUMP .Ldnext;
+
+	/* extract page size (17:16)*/
+	R3 = EXTRACT(R2, R1.L) (Z);
+
+	/* add page size to addr to get range */
+
+	P5 = R3;
+	P5 = P1 + (P5 << 2);
+	R3 = [P5];
+	R3 = R3 + R4;
+
+	/* See if failed address < (start address + page size) */
+	CC = R0 < R3(IU);
+	IF !CC JUMP .Ldnext;
+
+	/* We've found the CPLB that should be installed, so
+	 * write it into CPLB15, masking off any caching bits
+	 * if necessary.
+	 */
+
+	P1.L = (DCPLB_DATA15 & 0xFFFF);
+	P1.H = (DCPLB_DATA15 >> 16);
+
+	/* If the DCPLB has cache bits set, but caching hasn't
+	 * been enabled, then we want to mask off the cache-in-L1
+	 * bit before installing. Moreover, if caching is off, we
+	 * also want to ensure that the DCPLB has WT mode set, rather
+	 * than WB, since WB pages still trigger first-write exceptions
+	 * even when not caching is off, and the page isn't marked as
+	 * cachable. Finally, we could mark the page as clean, not dirty,
+	 * but we choose to leave that decision to the user; if the user
+	 * chooses to have a CPLB pre-defined as dirty, then they always
+	 * pay the cost of flushing during eviction, but don't pay the
+	 * cost of first-write exceptions to mark the page as dirty.
+	 */
+
+#ifdef CONFIG_BLKFIN_WT
+	BITSET(R6, 14);		/* Set WT*/
+#endif
+
+	[P1] = R2;
+	[P1-0x100] = R4;
+#ifdef	CONFIG_CPLB_INFO
+	R3 = [P3];
+	R3 += 1;
+	[P3] = R3;
+#endif
+
+	/* We've installed the CPLB, so re-enable CPLBs. P4
+	 * points to DMEM_CONTROL, and R5 is the value we
+	 * last wrote to it, when we were disabling CPLBs.
+	 */
+
+	BITSET(R5,ENDCPLB_P);
+	CLI R2;
+	.align 8;
+	[P4] = R5;
+	SSYNC;
+	STI R2;
+
+	( R7:4,P5:3 ) = [SP++];
+	R0 = CPLB_RELOADED;
+	RTS;
+
+.data
+.align 4;
+_page_size_table:
+.byte4	0x00000400;	/* 1K */
+.byte4	0x00001000;	/* 4K */
+.byte4	0x00100000;	/* 1M */
+.byte4	0x00400000;	/* 4M */
+
+.align 4;
+_dcplb_preference:
+.byte4	0x00000001;	/* valid bit */
+.byte4	0x00000002;	/* lock bit */
diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
new file mode 100644
index 0000000..97cdcd6
--- /dev/null
+++ b/arch/blackfin/mach-common/dpmc.S
@@ -0,0 +1,418 @@
+/*
+ * File:         arch/blackfin/mach-common/dpmc.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:      ?
+ * Description:  Watchdog Timer APIs
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/mach/irq.h>
+
+.text
+
+ENTRY(_unmask_wdog_wakeup_evt)
+	[--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+	P0.H = hi(SICA_IWR1);
+	P0.L = lo(SICA_IWR1);
+#else
+	P0.h = (SIC_IWR >> 16);
+	P0.l = (SIC_IWR & 0xFFFF);
+#endif
+	R7 = [P0];
+#if defined(CONFIG_BF561)
+	BITSET(R7, 27);
+#else
+	BITSET(R7,(IRQ_WATCH - IVG7));
+#endif
+	[P0] = R7;
+	SSYNC;
+
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+.LWRITE_TO_STAT:
+	/* When watch dog timer is enabled, a write to STAT will load the
+	 * contents of CNT to STAT
+	 */
+	R7 = 0x0000(z);
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_STAT >> 16);
+	P0.l = (WDOGA_STAT & 0xFFFF);
+#else
+	P0.h = (WDOG_STAT >> 16);
+	P0.l = (WDOG_STAT & 0xFFFF);
+#endif
+	[P0] = R7;
+	SSYNC;
+	JUMP .LSKIP_WRITE_TO_STAT;
+
+ENTRY(_program_wdog_timer)
+	[--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_CNT >> 16);
+	P0.l = (WDOGA_CNT & 0xFFFF);
+#else
+	P0.h = (WDOG_CNT >> 16);
+	P0.l = (WDOG_CNT & 0xFFFF);
+#endif
+	[P0] = R0;
+	SSYNC;
+
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_CTL >> 16);
+	P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+	P0.h = (WDOG_CTL >> 16);
+	P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+	R7 = W[P0](Z);
+	CC = BITTST(R7,1);
+	if !CC JUMP .LWRITE_TO_STAT;
+	CC = BITTST(R7,2);
+	if !CC JUMP .LWRITE_TO_STAT;
+
+.LSKIP_WRITE_TO_STAT:
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_CTL >> 16);
+	    P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+	P0.h = (WDOG_CTL >> 16);
+	    P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+	R7 = W[P0](Z);
+	BITCLR(R7,1);   /* Enable GP event */
+	BITSET(R7,2);
+	W[P0] = R7.L;
+	SSYNC;
+	NOP;
+
+	R7 = W[P0](Z);
+	BITCLR(R7,4);   /* Enable the wdog counter */
+	W[P0] = R7.L;
+	SSYNC;
+
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+ENTRY(_clear_wdog_wakeup_evt)
+	[--SP] = ( R7:0, P5:0 );
+
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_CTL >> 16);
+	P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+	P0.h = (WDOG_CTL >> 16);
+	P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+	R7 = 0x0AD6(Z);
+	W[P0] = R7.L;
+	SSYNC;
+
+	R7 = W[P0](Z);
+	BITSET(R7,15);
+	W[P0] = R7.L;
+	SSYNC;
+
+	R7 = W[P0](Z);
+	BITSET(R7,1);
+	BITSET(R7,2);
+	W[P0] = R7.L;
+	SSYNC;
+
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+ENTRY(_disable_wdog_timer)
+	[--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+	P0.h = (WDOGA_CTL >> 16);
+	P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+	P0.h = (WDOG_CTL >> 16);
+	P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+	R7 = 0xAD6(Z);
+	W[P0] = R7.L;
+	SSYNC;
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+#if !defined(CONFIG_BF561)
+
+.section .l1.text
+
+ENTRY(_sleep_mode)
+	[--SP] = ( R7:0, P5:0 );
+	[--SP] =  RETS;
+
+	call _set_sic_iwr;
+
+	R0 = 0xFFFF (Z);
+	call _set_rtc_istat
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R1 = W[P0](z);
+	BITSET (R1, 3);
+	W[P0] = R1.L;
+
+	CLI R2;
+	SSYNC;
+	IDLE;
+	STI R2;
+
+	call _test_pll_locked;
+
+	R0 = IWR_ENABLE(0);
+	call _set_sic_iwr;
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R7 = w[p0](z);
+	BITCLR (R7, 3);
+	BITCLR (R7, 5);
+	w[p0] = R7.L;
+	IDLE;
+	call _test_pll_locked;
+
+	RETS = [SP++];
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+ENTRY(_hibernate_mode)
+	[--SP] = ( R7:0, P5:0 );
+	[--SP] =  RETS;
+
+	call _set_sic_iwr;
+
+	R0 = 0xFFFF (Z);
+	call _set_rtc_istat
+
+	P0.H = hi(VR_CTL);
+	P0.L = lo(VR_CTL);
+	R1 = W[P0](z);
+	BITSET (R1, 8);
+	BITCLR (R1, 0);
+	BITCLR (R1, 1);
+	W[P0] = R1.L;
+	SSYNC;
+
+	CLI R2;
+	IDLE;
+
+	/* Actually, adding anything may not be necessary...SDRAM contents
+	 * are lost
+	 */
+
+ENTRY(_deep_sleep)
+	[--SP] = ( R7:0, P5:0 );
+	[--SP] =  RETS;
+
+	CLI R4;
+
+	call _set_sic_iwr;
+
+	call _set_sdram_srfs;
+
+	/* Clear all the interrupts,bits sticky */
+	R0 = 0xFFFF (Z);
+	call _set_rtc_istat
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R0 = W[P0](z);
+	BITSET (R0, 5);
+	W[P0] = R0.L;
+
+	call _test_pll_locked;
+
+	SSYNC;
+	IDLE;
+
+	call _unset_sdram_srfs;
+
+	call _test_pll_locked;
+
+	R0 = IWR_ENABLE(0);
+	call _set_sic_iwr;
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R0 = w[p0](z);
+	BITCLR (R0, 3);
+	BITCLR (R0, 5);
+	BITCLR (R0, 8);
+	w[p0] = R0;
+	IDLE;
+	call _test_pll_locked;
+
+	STI R4;
+
+	RETS = [SP++];
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+ENTRY(_sleep_deeper)
+	[--SP] = ( R7:0, P5:0 );
+	[--SP] =  RETS;
+
+	CLI R4;
+
+	P3 = R0;
+	R0 = IWR_ENABLE(0);
+	call _set_sic_iwr;
+	call _set_sdram_srfs;
+
+	/* Clear all the interrupts,bits sticky */
+	R0 = 0xFFFF (Z);
+	call _set_rtc_istat
+
+	P0.H = hi(PLL_DIV);
+	P0.L = lo(PLL_DIV);
+	R6 = W[P0](z);
+	R0.L = 0xF;
+	W[P0] = R0.l;
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R5 = W[P0](z);
+	R0.L = (MIN_VC/CONFIG_CLKIN_HZ) << 9;
+	W[P0] = R0.l;
+
+	SSYNC;
+	IDLE;
+
+	call _test_pll_locked;
+
+	P0.H = hi(VR_CTL);
+	P0.L = lo(VR_CTL);
+	R7 = W[P0](z);
+	R1 = 0x6;
+	R1 <<= 16;
+	R2 = 0x0404(Z);
+	R1 = R1|R2;
+
+	R2 = DEPOSIT(R7, R1);
+	W[P0] = R2;
+
+	SSYNC;
+	IDLE;
+
+	call _test_pll_locked;
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	R0 = W[P0](z);
+	BITSET (R0, 3);
+	W[P0] = R0.L;
+
+	R0 = P3;
+	call _set_sic_iwr;
+
+	SSYNC;
+	IDLE;
+
+	call _test_pll_locked;
+
+	R0 = IWR_ENABLE(0);
+	call _set_sic_iwr;
+
+	P0.H = hi(VR_CTL);
+	P0.L = lo(VR_CTL);
+	W[P0]= R7;
+
+	SSYNC;
+	IDLE;
+
+	call _test_pll_locked;
+
+	P0.H = hi(PLL_DIV);
+	P0.L = lo(PLL_DIV);
+	W[P0]= R6;
+
+	P0.H = hi(PLL_CTL);
+	P0.L = lo(PLL_CTL);
+	w[p0] = R5;
+	IDLE;
+	call _test_pll_locked;
+
+	call _unset_sdram_srfs;
+
+	STI R4;
+
+	RETS = [SP++];
+	( R7:0, P5:0 ) = [SP++];
+	RTS;
+
+ENTRY(_set_sdram_srfs)
+	/*  set the sdram to self refresh mode */
+	P0.H = hi(EBIU_SDGCTL);
+	P0.L = lo(EBIU_SDGCTL);
+	R2 = [P0];
+	R3.H = hi(SRFS);
+	R3.L = lo(SRFS);
+	R2 = R2|R3;
+	[P0] = R2;
+	ssync;
+	RTS;
+
+ENTRY(_unset_sdram_srfs)
+	/*  set the sdram out of self refresh mode */
+	P0.H = hi(EBIU_SDGCTL);
+	P0.L = lo(EBIU_SDGCTL);
+	R2 = [P0];
+	R3.H = hi(SRFS);
+	R3.L = lo(SRFS);
+	R3 = ~R3;
+	R2 = R2&R3;
+	[P0] = R2;
+	ssync;
+	RTS;
+
+ENTRY(_set_sic_iwr)
+	P0.H = hi(SIC_IWR);
+	P0.L = lo(SIC_IWR);
+	[P0] = R0;
+	SSYNC;
+	RTS;
+
+ENTRY(_set_rtc_istat)
+	P0.H = hi(RTC_ISTAT);
+	P0.L = lo(RTC_ISTAT);
+	w[P0] = R0.L;
+	SSYNC;
+	RTS;
+
+ENTRY(_test_pll_locked)
+	P0.H = hi(PLL_STAT);
+	P0.L = lo(PLL_STAT);
+1:
+	R0 = W[P0] (Z);
+	CC = BITTST(R0,5);
+	IF !CC JUMP 1b;
+	RTS;
+#endif
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
new file mode 100644
index 0000000..8eb0a90
--- /dev/null
+++ b/arch/blackfin/mach-common/entry.S
@@ -0,0 +1,1207 @@
+/*
+ * File:         arch/blackfin/mach-common/entry.S
+ * Based on:
+ * Author:       Linus Torvalds
+ *
+ * Created:      ?
+ * Description:  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.
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * 25-Dec-2004 - LG Soft India
+ * 	1. Fix in return_from_int, to make sure any pending
+ *	system call in ILAT for this process to get
+ *	executed, otherwise in case context switch happens,
+ *	system call of first process (i.e in ILAT) will be
+ *	carried forward to the switched process.
+ *	2. Removed Constant references for the following
+ *		a.  IPEND
+ *		b.  EXCAUSE mask
+ *		c.  PAGE Mask
+ */
+
+/*
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ */
+
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h>  /* TIF_NEED_RESCHED */
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
+	/*
+	 * TODO: this should be proper save/restore, but for now
+	 * we'll just cheat and use 0x1/0x13
+	 */
+# define DEBUG_START_HWTRACE \
+	P5.l = LO(TBUFCTL); \
+	P5.h = HI(TBUFCTL); \
+	R7 = 0x13; \
+	[P5] = R7;
+# define DEBUG_STOP_HWTRACE \
+	P5.l = LO(TBUFCTL); \
+	P5.h = HI(TBUFCTL); \
+	R7 = 0x01; \
+	[P5] = R7;
+#else
+# define DEBUG_START_HWTRACE
+# define DEBUG_STOP_HWTRACE
+#endif
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/* Slightly simplified and streamlined entry point for CPLB misses.
+ * This one does not lower the level to IRQ5, and thus can be used to
+ * patch up CPLB misses on the kernel stack.
+ */
+ENTRY(_ex_dcplb)
+#if defined(ANOMALY_05000261)
+	/*
+	 * Work around an anomaly: if we see a new DCPLB fault, return
+	 * without doing anything.  Then, if we get the same fault again,
+	 * handle it.
+	 */
+	p5.l = _last_cplb_fault_retx;
+	p5.h = _last_cplb_fault_retx;
+	r7 = [p5];
+	r6 = retx;
+	[p5] = r6;
+	cc = r6 == r7;
+	if !cc jump _return_from_exception;
+	/* fall through */
+#endif
+
+ENTRY(_ex_icplb)
+	(R7:6,P5:4) = [sp++];
+	ASTAT = [sp++];
+	SAVE_ALL_SYS
+	call __cplb_hdr;
+	DEBUG_START_HWTRACE
+	RESTORE_ALL_SYS
+	SP = RETN;
+	rtx;
+
+ENTRY(_ex_spinlock)
+	/* Transform this into a syscall - twiddle the syscall vector.  */
+	p5.l = lo(EVT15);
+	p5.h = hi(EVT15);
+	r7.l = _spinlock_bh;
+	r7.h = _spinlock_bh;
+	[p5] = r7;
+	csync;
+	/* Fall through.  */
+
+ENTRY(_ex_syscall)
+	DEBUG_START_HWTRACE
+	(R7:6,P5:4) = [sp++];
+	ASTAT = [sp++];
+	raise 15;		/* invoked by TRAP #0, for sys call */
+	sp = retn;
+	rtx
+
+ENTRY(_spinlock_bh)
+	SAVE_ALL_SYS
+	/* To end up here, vector 15 was changed - so we have to change it
+	 * back.
+	 */
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _evt_system_call;
+	p1.h = _evt_system_call;
+	[p0] = p1;
+	csync;
+	r0 = [sp + PT_R0];
+	sp += -12;
+	call _sys_bfin_spinlock;
+	sp += 12;
+	[SP + PT_R0] = R0;
+	RESTORE_ALL_SYS
+	rti;
+
+ENTRY(_ex_soft_bp)
+	r7 = retx;
+	r7 += -2;
+	retx = r7;
+	jump.s _ex_trap_c;
+
+ENTRY(_ex_single_step)
+	r7 = retx;
+	r6 = reti;
+	cc = r7 == r6;
+	if cc jump _return_from_exception
+	r7 = syscfg;
+	bitclr (r7, 0);
+	syscfg = R7;
+
+	p5.l = lo(IPEND);
+	p5.h = hi(IPEND);
+	r6 = [p5];
+	cc = bittst(r6, 5);
+	if !cc jump _ex_trap_c;
+	p4.l = lo(EVT5);
+	p4.h = hi(EVT5);
+	r6.h = _exception_to_level5;
+	r6.l = _exception_to_level5;
+	r7 = [p4];
+	cc = r6 == r7;
+	if !cc jump _ex_trap_c;
+
+_return_from_exception:
+	DEBUG_START_HWTRACE
+	(R7:6,P5:4) = [sp++];
+	ASTAT = [sp++];
+	sp = retn;
+	rtx;
+
+ENTRY(_handle_bad_cplb)
+	/* To get here, we just tried and failed to change a CPLB
+	 * so, handle things in trap_c (C code), by lowering to
+	 * IRQ5, just like we normally do. Since this is not a
+	 * "normal" return path, we have a do alot of stuff to
+	 * the stack to get ready so, we can fall through - we
+	 * need to make a CPLB exception look like a normal exception
+	 */
+
+	DEBUG_START_HWTRACE
+	RESTORE_ALL_SYS
+	[--sp] = ASTAT;
+	[--sp] = (R7:6, P5:4);
+
+ENTRY(_ex_trap_c)
+	/* Call C code (trap_c) to handle the exception, which most
+	 * likely involves sending a signal to the current process.
+	 * To avoid double faults, lower our priority to IRQ5 first.
+	 */
+	P5.h = _exception_to_level5;
+	P5.l = _exception_to_level5;
+	p4.l = lo(EVT5);
+	p4.h = hi(EVT5);
+	[p4] = p5;
+	csync;
+
+	/* Disable all interrupts, but make sure level 5 is enabled so
+	 * we can switch to that level.  Save the old mask.  */
+	cli r6;
+	p4.l = _excpt_saved_imask;
+	p4.h = _excpt_saved_imask;
+	[p4] = r6;
+	r6 = 0x3f;
+	sti r6;
+
+	/* Save the excause into a circular buffer, in case the instruction
+	 * which caused this excecptions causes others.
+	 */
+	P5.l = _in_ptr_excause;
+	P5.h = _in_ptr_excause;
+	R7 = [P5];
+	R7 += 4;
+	R6 = 0xF;
+	R7 = R7 & R6;
+	[P5] = R7;
+	R6.l = _excause_circ_buf;
+	R6.h = _excause_circ_buf;
+	R7 = R7 + R6;
+	p5 = R7;
+	R6 = SEQSTAT;
+	[P5] = R6;
+
+	DEBUG_START_HWTRACE
+	(R7:6,P5:4) = [sp++];
+	ASTAT = [sp++];
+	SP = RETN;
+	raise 5;
+	rtx;
+
+ENTRY(_exception_to_level5)
+	SAVE_ALL_SYS
+
+	/* Restore interrupt mask.  We haven't pushed RETI, so this
+	 * doesn't enable interrupts until we return from this handler.  */
+	p4.l = _excpt_saved_imask;
+	p4.h = _excpt_saved_imask;
+	r6 = [p4];
+	sti r6;
+
+	/* Restore the hardware error vector.  */
+	P5.h = _evt_ivhw;
+	P5.l = _evt_ivhw;
+	p4.l = lo(EVT5);
+	p4.h = hi(EVT5);
+	[p4] = p5;
+	csync;
+
+	p2.l = lo(IPEND);
+	p2.h = hi(IPEND);
+	csync;
+	r0 = [p2];              /* Read current IPEND */
+	[sp + PT_IPEND] = r0;   /* Store IPEND */
+
+	/* Pop the excause from the circular buffer and push it on the stack
+	 * (in the right place - if you change the location of SEQSTAT, you
+	 * must change this offset.
+	 */
+.L_excep_to_5_again:
+	P5.l = _out_ptr_excause;
+	P5.h = _out_ptr_excause;
+	R7 = [P5];
+	R7 += 4;
+	R6 = 0xF;
+	R7 = R7 & R6;
+	[P5] = R7;
+	R6.l = _excause_circ_buf;
+	R6.h = _excause_circ_buf;
+	R7 = R7 + R6;
+	P5 = R7;
+	R1 = [P5];
+	[SP + 8] = r1;
+
+	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */
+	SP += -12;
+	call _trap_c;
+	SP += 12;
+
+	/* See if anything else is in the exception buffer
+	 * if there is, process it
+	 */
+	P5.l = _out_ptr_excause;
+	P5.h = _out_ptr_excause;
+	P4.l = _in_ptr_excause;
+	P4.h = _in_ptr_excause;
+	R6 = [P5];
+	R7 = [P4];
+	CC = R6 == R7;
+	if ! CC JUMP .L_excep_to_5_again
+
+	call _ret_from_exception;
+	RESTORE_ALL_SYS
+	rti;
+
+ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
+	/* Since the kernel stack can be anywhere, it's not guaranteed to be
+	 * covered by a CPLB.  Switch to an exception stack; use RETN as a
+	 * scratch register (for want of a better option).
+	 */
+	retn = sp;
+	sp.l = _exception_stack_top;
+	sp.h = _exception_stack_top;
+	/* Try to deal with syscalls quickly.  */
+	[--sp] = ASTAT;
+	[--sp] = (R7:6, P5:4);
+	DEBUG_STOP_HWTRACE
+	r7 = SEQSTAT;		/* reason code is in bit 5:0 */
+	r6.l = lo(SEQSTAT_EXCAUSE);
+	r6.h = hi(SEQSTAT_EXCAUSE);
+	r7 = r7 & r6;
+	p5.h = _extable;
+	p5.l = _extable;
+	p4 = r7;
+	p5 = p5 + (p4 << 2);
+	p4 = [p5];
+	jump (p4);
+
+.Lbadsys:
+	r7 = -ENOSYS; 		/* signextending enough */
+	[sp + PT_R0] = r7;	/* return value from system call */
+	jump .Lsyscall_really_exit;
+
+ENTRY(_kernel_execve)
+	link SIZEOF_PTREGS;
+	p0 = sp;
+	r3 = SIZEOF_PTREGS / 4;
+	r4 = 0(x);
+0:
+	[p0++] = r4;
+	r3 += -1;
+	cc = r3 == 0;
+	if !cc jump 0b (bp);
+
+	p0 = sp;
+	sp += -16;
+	[sp + 12] = p0;
+	call _do_execve;
+	SP += 16;
+	cc = r0 == 0;
+	if ! cc jump 1f;
+	/* Success.  Copy our temporary pt_regs to the top of the kernel
+	 * stack and do a normal exception return.
+	 */
+	r1 = sp;
+	r0 = (-KERNEL_STACK_SIZE) (x);
+	r1 = r1 & r0;
+	p2 = r1;
+	p3 = [p2];
+	r0 = KERNEL_STACK_SIZE - 4 (z);
+	p1 = r0;
+	p1 = p1 + p2;
+
+	p0 = fp;
+	r4 = [p0--];
+	r3 = SIZEOF_PTREGS / 4;
+0:
+	r4 = [p0--];
+	[p1--] = r4;
+	r3 += -1;
+	cc = r3 == 0;
+	if ! cc jump 0b (bp);
+
+	r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
+	p1 = r0;
+	p1 = p1 + p2;
+	sp = p1;
+	r0 = syscfg;
+	[SP + PT_SYSCFG] = r0;
+	[p3 + (TASK_THREAD + THREAD_KSP)] = sp;
+
+	RESTORE_CONTEXT;
+	rti;
+1:
+	unlink;
+	rts;
+
+ENTRY(_system_call)
+	/* Store IPEND */
+	p2.l = lo(IPEND);
+	p2.h = hi(IPEND);
+	csync;
+	r0 = [p2];
+	[sp + PT_IPEND] = r0;
+
+	/* Store RETS for now */
+	r0 = rets;
+	[sp + PT_RESERVED] = r0;
+	/* Set the stack for the current process */
+	r7 = sp;
+	r6.l = lo(ALIGN_PAGE_MASK);
+	r6.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r6;  		/* thread_info */
+	p2 = r7;
+	p2 = [p2];
+
+	[p2+(TASK_THREAD+THREAD_KSP)] = sp;
+
+	/* Check the System Call */
+	r7 = __NR_syscall;
+	/* System call number is passed in P0 */
+	r6 = p0;
+	cc = r6 < r7;
+	if ! cc jump .Lbadsys;
+
+	/* are we tracing syscalls?*/
+	r7 = sp;
+	r6.l = lo(ALIGN_PAGE_MASK);
+	r6.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r6;
+	p2 = r7;
+	r7 = [p2+TI_FLAGS];
+	CC = BITTST(r7,TIF_SYSCALL_TRACE);
+	if CC JUMP _sys_trace;
+
+	/* Execute the appropriate system call */
+
+	p4 = p0;
+	p5.l = _sys_call_table;
+	p5.h = _sys_call_table;
+	p5 = p5 + (p4 << 2);
+	r0 = [sp + PT_R0];
+	r1 = [sp + PT_R1];
+	r2 = [sp + PT_R2];
+	p5 = [p5];
+
+	[--sp] = r5;
+	[--sp] = r4;
+	[--sp] = r3;
+	SP += -12;
+	call (p5);
+	SP += 24;
+	[sp + PT_R0] = r0;
+
+.Lresume_userspace:
+	r7 = sp;
+	r4.l = lo(ALIGN_PAGE_MASK);
+	r4.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r4;		/* thread_info->flags */
+	p5 = r7;
+.Lresume_userspace_1:
+	/* Disable interrupts.  */
+	[--sp] = reti;
+	reti = [sp++];
+
+	r7 = [p5 + TI_FLAGS];
+	r4.l = lo(_TIF_WORK_MASK);
+	r4.h = hi(_TIF_WORK_MASK);
+	r7 =  r7 & r4;
+
+.Lsyscall_resched:
+	cc = BITTST(r7, TIF_NEED_RESCHED);
+	if !cc jump .Lsyscall_sigpending;
+
+	/* Reenable interrupts.  */
+	[--sp] = reti;
+	r0 = [sp++];
+
+	SP += -12;
+	call _schedule;
+	SP += 12;
+
+	jump .Lresume_userspace_1;
+
+.Lsyscall_sigpending:
+	cc = BITTST(r7, TIF_RESTORE_SIGMASK);
+	if cc jump .Lsyscall_do_signals;
+	cc = BITTST(r7, TIF_SIGPENDING);
+	if !cc jump .Lsyscall_really_exit;
+.Lsyscall_do_signals:
+	/* Reenable interrupts.  */
+	[--sp] = reti;
+	r0 = [sp++];
+
+	r0 = sp;
+	SP += -12;
+	call _do_signal;
+	SP += 12;
+
+.Lsyscall_really_exit:
+	r5 = [sp + PT_RESERVED];
+	rets = r5;
+	rts;
+
+_sys_trace:
+	call _syscall_trace;
+
+	/* Execute the appropriate system call */
+
+	p4 = [SP + PT_P0];
+	p5.l = _sys_call_table;
+	p5.h = _sys_call_table;
+	p5 = p5 + (p4 << 2);
+	r0 = [sp + PT_R0];
+	r1 = [sp + PT_R1];
+	r2 = [sp + PT_R2];
+	r3 = [sp + PT_R3];
+	r4 = [sp + PT_R4];
+	r5 = [sp + PT_R5];
+	p5 = [p5];
+
+	[--sp] = r5;
+	[--sp] = r4;
+	[--sp] = r3;
+	SP += -12;
+	call (p5);
+	SP += 24;
+	[sp + PT_R0] = r0;
+
+	call _syscall_trace;
+	jump .Lresume_userspace;
+
+ENTRY(_resume)
+	/*
+	 * Beware - when entering resume, prev (the current task) is
+	 * in r0, next (the new task) is in r1.
+	 */
+	p0 = r0;
+	p1 = r1;
+	[--sp] = rets;
+	[--sp] = fp;
+	[--sp] = (r7:4, p5:3);
+
+	/* save usp */
+	p2 = usp;
+	[p0+(TASK_THREAD+THREAD_USP)] = p2;
+
+	/* save current kernel stack pointer */
+	[p0+(TASK_THREAD+THREAD_KSP)] = sp;
+
+	/* save program counter */
+	r1.l = _new_old_task;
+	r1.h = _new_old_task;
+	[p0+(TASK_THREAD+THREAD_PC)] = r1;
+
+	/* restore the kernel stack pointer */
+	sp = [p1+(TASK_THREAD+THREAD_KSP)];
+
+	/* restore user stack pointer */
+	p0 = [p1+(TASK_THREAD+THREAD_USP)];
+	usp = p0;
+
+	/* restore pc */
+	p0 = [p1+(TASK_THREAD+THREAD_PC)];
+	jump (p0);
+
+	/*
+	 * Following code actually lands up in a new (old) task.
+	 */
+
+_new_old_task:
+	(r7:4, p5:3) = [sp++];
+	fp = [sp++];
+	rets = [sp++];
+
+	/*
+	 * When we come out of resume, r0 carries "old" task, becuase we are
+	 * in "new" task.
+	 */
+	rts;
+
+ENTRY(_ret_from_exception)
+	p2.l = lo(IPEND);
+	p2.h = hi(IPEND);
+
+	csync;
+	r0 = [p2];
+	[sp + PT_IPEND] = r0;
+
+1:
+	r1 = 0x37(Z);
+	r2 = ~r1;
+	r2.h = 0;
+	r0 = r2 & r0;
+	cc = r0 == 0;
+	if !cc jump 4f;	/* if not return to user mode, get out */
+
+	/* Make sure any pending system call or deferred exception
+	 * return in ILAT for this process to get executed, otherwise
+	 * in case context switch happens, system call of
+	 * first process (i.e in ILAT) will be carried
+	 * forward to the switched process
+	 */
+
+	p2.l = lo(ILAT);
+	p2.h = hi(ILAT);
+	r0 = [p2];
+	r1 = (EVT_IVG14 | EVT_IVG15) (z);
+	r0 = r0 & r1;
+	cc = r0 == 0;
+	if !cc jump 5f;
+
+	/* Set the stack for the current process */
+	r7 = sp;
+	r4.l = lo(ALIGN_PAGE_MASK);
+	r4.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r4;		/* thread_info->flags */
+	p5 = r7;
+	r7 = [p5 + TI_FLAGS];
+	r4.l = lo(_TIF_WORK_MASK);
+	r4.h = hi(_TIF_WORK_MASK);
+	r7 =  r7 & r4;
+	cc = r7 == 0;
+	if cc jump 4f;
+
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _schedule_and_signal;
+	p1.h = _schedule_and_signal;
+	[p0] = p1;
+	csync;
+	raise 15;		/* raise evt14 to do signal or reschedule */
+4:
+	r0 = syscfg;
+	bitclr(r0, 0);
+	syscfg = r0;
+5:
+	rts;
+
+ENTRY(_return_from_int)
+	/* If someone else already raised IRQ 15, do nothing.  */
+	csync;
+	p2.l = lo(ILAT);
+	p2.h = hi(ILAT);
+	r0 = [p2];
+	cc = bittst (r0, EVT_IVG15_P);
+	if cc jump 2f;
+
+	/* if not return to user mode, get out */
+	p2.l = lo(IPEND);
+	p2.h = hi(IPEND);
+	r0 = [p2];
+	r1 = 0x17(Z);
+	r2 = ~r1;
+	r2.h = 0;
+	r0 = r2 & r0;
+	r1 = 1;
+	r1 = r0 - r1;
+	r2 = r0 & r1;
+	cc = r2 == 0;
+	if !cc jump 2f;
+
+	/* Lower the interrupt level to 15.  */
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _schedule_and_signal_from_int;
+	p1.h = _schedule_and_signal_from_int;
+	[p0] = p1;
+	csync;
+#if defined(ANOMALY_05000281)
+	r0.l = lo(CONFIG_BOOT_LOAD);
+	r0.h = hi(CONFIG_BOOT_LOAD);
+	reti = r0;
+#endif
+	r0 = 0x801f (z);
+	STI r0;
+	raise 15;	/* raise evt15 to do signal or reschedule */
+	rti;
+2:
+	rts;
+
+ENTRY(_lower_to_irq14)
+#if defined(ANOMALY_05000281)
+	r0.l = lo(CONFIG_BOOT_LOAD);
+	r0.h = hi(CONFIG_BOOT_LOAD);
+	reti = r0;
+#endif
+	r0 = 0x401f;
+	sti r0;
+	raise 14;
+	rti;
+ENTRY(_evt14_softirq)
+#ifdef CONFIG_DEBUG_HWERR
+	r0 = 0x3f;
+	sti r0;
+#else
+	cli r0;
+#endif
+	[--sp] = RETI;
+	SP += 4;
+	rts;
+
+_schedule_and_signal_from_int:
+	/* To end up here, vector 15 was changed - so we have to change it
+	 * back.
+	 */
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _evt_system_call;
+	p1.h = _evt_system_call;
+	[p0] = p1;
+	csync;
+	p1 = rets;
+	[sp + PT_RESERVED] = p1;
+
+	p0.l = _irq_flags;
+	p0.h = _irq_flags;
+	r0 = [p0];
+	sti r0;
+
+	jump.s .Lresume_userspace;
+
+_schedule_and_signal:
+	SAVE_CONTEXT_SYSCALL
+	/* To end up here, vector 15 was changed - so we have to change it
+	 * back.
+	 */
+	p0.l = lo(EVT15);
+	p0.h = hi(EVT15);
+	p1.l = _evt_system_call;
+	p1.h = _evt_system_call;
+	[p0] = p1;
+	csync;
+	p0.l = 1f;
+	p0.h = 1f;
+	[sp + PT_RESERVED] = P0;
+	call .Lresume_userspace;
+1:
+	RESTORE_CONTEXT
+	rti;
+
+/* Make sure when we start, that the circular buffer is initialized properly
+ * R0 and P0 are call clobbered, so we can use them here.
+ */
+ENTRY(_init_exception_buff)
+	r0 = 0;
+	p0.h = _in_ptr_excause;
+	p0.l = _in_ptr_excause;
+	[p0] = r0;
+	p0.h = _out_ptr_excause;
+	p0.l = _out_ptr_excause;
+	[p0] = r0;
+	rts;
+
+/*
+ * Put these in the kernel data section - that should always be covered by
+ * a CPLB. This is needed to ensure we don't get double fault conditions
+ */
+
+#ifdef CONFIG_SYSCALL_TAB_L1
+.section .l1.data
+#else
+.data
+#endif
+ALIGN
+_extable:
+	/* entry for each EXCAUSE[5:0]
+	 * This table bmust be in sync with the table in ./kernel/traps.c
+	 * EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined
+	 */
+	.long _ex_syscall;      /* 0x00 - User Defined - Linux Syscall */
+	.long _ex_soft_bp       /* 0x01 - User Defined - Software breakpoint */
+	.long _ex_trap_c        /* 0x02 - User Defined */
+	.long _ex_trap_c        /* 0x03 - User Defined  - Atomic test and set service */
+	.long _ex_spinlock      /* 0x04 - User Defined */
+	.long _ex_trap_c        /* 0x05 - User Defined */
+	.long _ex_trap_c        /* 0x06 - User Defined */
+	.long _ex_trap_c        /* 0x07 - User Defined */
+	.long _ex_trap_c        /* 0x08 - User Defined */
+	.long _ex_trap_c        /* 0x09 - User Defined */
+	.long _ex_trap_c        /* 0x0A - User Defined */
+	.long _ex_trap_c        /* 0x0B - User Defined */
+	.long _ex_trap_c        /* 0x0C - User Defined */
+	.long _ex_trap_c        /* 0x0D - User Defined */
+	.long _ex_trap_c        /* 0x0E - User Defined */
+	.long _ex_trap_c        /* 0x0F - User Defined */
+	.long _ex_single_step   /* 0x10 - HW Single step */
+	.long _ex_trap_c        /* 0x11 - Trace Buffer Full */
+	.long _ex_trap_c        /* 0x12 - Reserved */
+	.long _ex_trap_c        /* 0x13 - Reserved */
+	.long _ex_trap_c        /* 0x14 - Reserved */
+	.long _ex_trap_c        /* 0x15 - Reserved */
+	.long _ex_trap_c        /* 0x16 - Reserved */
+	.long _ex_trap_c        /* 0x17 - Reserved */
+	.long _ex_trap_c        /* 0x18 - Reserved */
+	.long _ex_trap_c        /* 0x19 - Reserved */
+	.long _ex_trap_c        /* 0x1A - Reserved */
+	.long _ex_trap_c        /* 0x1B - Reserved */
+	.long _ex_trap_c        /* 0x1C - Reserved */
+	.long _ex_trap_c        /* 0x1D - Reserved */
+	.long _ex_trap_c        /* 0x1E - Reserved */
+	.long _ex_trap_c        /* 0x1F - Reserved */
+	.long _ex_trap_c        /* 0x20 - Reserved */
+	.long _ex_trap_c        /* 0x21 - Undefined Instruction */
+	.long _ex_trap_c        /* 0x22 - Illegal Instruction Combination */
+	.long _ex_dcplb         /* 0x23 - Data CPLB Protection Violation */
+	.long _ex_trap_c        /* 0x24 - Data access misaligned */
+	.long _ex_trap_c        /* 0x25 - Unrecoverable Event */
+	.long _ex_dcplb         /* 0x26 - Data CPLB Miss */
+	.long _ex_trap_c        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */
+	.long _ex_trap_c        /* 0x28 - Emulation Watchpoint */
+	.long _ex_trap_c        /* 0x29 - Instruction fetch access error (535 only) */
+	.long _ex_trap_c        /* 0x2A - Instruction fetch misaligned */
+	.long _ex_icplb         /* 0x2B - Instruction CPLB protection Violation */
+	.long _ex_icplb         /* 0x2C - Instruction CPLB miss */
+	.long _ex_trap_c        /* 0x2D - Instruction CPLB Multiple Hits */
+	.long _ex_trap_c        /* 0x2E - Illegal use of Supervisor Resource */
+	.long _ex_trap_c        /* 0x2E - Illegal use of Supervisor Resource */
+	.long _ex_trap_c        /* 0x2F - Reserved */
+	.long _ex_trap_c        /* 0x30 - Reserved */
+	.long _ex_trap_c        /* 0x31 - Reserved */
+	.long _ex_trap_c        /* 0x32 - Reserved */
+	.long _ex_trap_c        /* 0x33 - Reserved */
+	.long _ex_trap_c        /* 0x34 - Reserved */
+	.long _ex_trap_c        /* 0x35 - Reserved */
+	.long _ex_trap_c        /* 0x36 - Reserved */
+	.long _ex_trap_c        /* 0x37 - Reserved */
+	.long _ex_trap_c        /* 0x38 - Reserved */
+	.long _ex_trap_c        /* 0x39 - Reserved */
+	.long _ex_trap_c        /* 0x3A - Reserved */
+	.long _ex_trap_c        /* 0x3B - Reserved */
+	.long _ex_trap_c        /* 0x3C - Reserved */
+	.long _ex_trap_c        /* 0x3D - Reserved */
+	.long _ex_trap_c        /* 0x3E - Reserved */
+	.long _ex_trap_c        /* 0x3F - Reserved */
+
+ALIGN
+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_ni_syscall	/* old 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_chown	/* chown16 */
+	.long _sys_ni_syscall	/* old break syscall holder */
+	.long _sys_ni_syscall	/* old stat */
+	.long _sys_lseek
+	.long _sys_getpid	/* 20 */
+	.long _sys_mount
+	.long _sys_ni_syscall	/* old umount */
+	.long _sys_setuid
+	.long _sys_getuid
+	.long _sys_stime		/* 25 */
+	.long _sys_ptrace
+	.long _sys_alarm
+	.long _sys_ni_syscall	/* old fstat */
+	.long _sys_pause
+	.long _sys_ni_syscall	/* old 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_setgid
+	.long _sys_getgid
+	.long _sys_ni_syscall	/* old sys_signal */
+	.long _sys_geteuid	/* geteuid16 */
+	.long _sys_getegid	/* 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	/* old old uname */
+	.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_ni_syscall	/* old sys_sigaction */
+	.long _sys_sgetmask
+	.long _sys_ssetmask
+	.long _sys_setreuid	/* setreuid16 */	/* 70 */
+	.long _sys_setregid	/* setregid16 */
+	.long _sys_ni_syscall	/* old sys_sigsuspend */
+	.long _sys_ni_syscall	/* old sys_sigpending */
+	.long _sys_sethostname
+	.long _sys_setrlimit	/* 75 */
+	.long _sys_ni_syscall	/* old getrlimit */
+	.long _sys_getrusage
+	.long _sys_gettimeofday
+	.long _sys_settimeofday
+	.long _sys_getgroups	/* getgroups16 */	/* 80 */
+	.long _sys_setgroups	/* setgroups16 */
+	.long _sys_ni_syscall	/* old_select */
+	.long _sys_symlink
+	.long _sys_ni_syscall	/* old lstat */
+	.long _sys_readlink	/* 85 */
+	.long _sys_uselib
+	.long _sys_ni_syscall	/* sys_swapon */
+	.long _sys_reboot
+	.long _sys_ni_syscall	/* old_readdir */
+	.long _sys_ni_syscall	/* sys_mmap */	/* 90 */
+	.long _sys_munmap
+	.long _sys_truncate
+	.long _sys_ftruncate
+	.long _sys_fchmod
+	.long _sys_fchown	/* 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
+	.long _sys_ni_syscall	/* old sys_socketcall */
+	.long _sys_syslog
+	.long _sys_setitimer
+	.long _sys_getitimer	/* 105 */
+	.long _sys_newstat
+	.long _sys_newlstat
+	.long _sys_newfstat
+	.long _sys_ni_syscall	/* old uname */
+	.long _sys_ni_syscall	/* iopl for i386 */ /* 110 */
+	.long _sys_vhangup
+	.long _sys_ni_syscall	/* obsolete idle() syscall */
+	.long _sys_ni_syscall	/* vm86old for i386 */
+	.long _sys_wait4
+	.long _sys_ni_syscall	/* 115 */ /* sys_swapoff */
+	.long _sys_sysinfo
+	.long _sys_ni_syscall	/* old sys_ipc */
+	.long _sys_fsync
+	.long _sys_ni_syscall	/* old sys_sigreturn */
+	.long _sys_clone		/* 120 */
+	.long _sys_setdomainname
+	.long _sys_newuname
+	.long _sys_ni_syscall	/* old sys_modify_ldt */
+	.long _sys_adjtimex
+	.long _sys_ni_syscall	/* 125 */ /* sys_mprotect */
+	.long _sys_ni_syscall	/* old sys_sigprocmask */
+	.long _sys_ni_syscall	/* old "creat_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_ni_syscall	/* 135 */ /* sys_sysfs */
+	.long _sys_personality
+	.long _sys_ni_syscall	/* for afs_syscall */
+	.long _sys_setfsuid	/* setfsuid16 */
+	.long _sys_setfsgid	/* setfsgid16 */
+	.long _sys_llseek	/* 140 */
+	.long _sys_getdents
+	.long _sys_ni_syscall	/* sys_select */
+	.long _sys_flock
+	.long _sys_ni_syscall	/* sys_msync */
+	.long _sys_readv		/* 145 */
+	.long _sys_writev
+	.long _sys_getsid
+	.long _sys_fdatasync
+	.long _sys_sysctl
+	.long _sys_ni_syscall	/* 150 */ /* sys_mlock */
+	.long _sys_ni_syscall	/* sys_munlock */
+	.long _sys_ni_syscall	/* sys_mlockall */
+	.long _sys_ni_syscall	/* 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_ni_syscall	/* sys_mremap */
+	.long _sys_setresuid	/* setresuid16 */
+	.long _sys_getresuid	/* getresuid16 */	/* 165 */
+	.long _sys_ni_syscall	/* for vm86 */
+	.long _sys_ni_syscall	/* old "query_module" */
+	.long _sys_ni_syscall	/* sys_poll */
+	.long _sys_ni_syscall	/* sys_nfsservctl */
+	.long _sys_setresgid	/* setresgid16 */	/* 170 */
+	.long _sys_getresgid	/* 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_pread64	/* 180 */
+	.long _sys_pwrite64
+	.long _sys_lchown	/* lchown16 */
+	.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_chown
+	.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_lchown
+	.long _sys_setuid
+	.long _sys_setgid
+	.long _sys_setfsuid	/* 215 */
+	.long _sys_setfsgid
+	.long _sys_pivot_root
+	.long _sys_ni_syscall	/* sys_mincore */
+	.long _sys_ni_syscall	/* sys_madvise */
+	.long _sys_getdents64	/* 220 */
+	.long _sys_fcntl64
+	.long _sys_ni_syscall	/* reserved for TUX */
+	.long _sys_ni_syscall
+	.long _sys_gettid
+	.long _sys_ni_syscall	/* 225 */ /* sys_readahead */
+	.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	/* sys_set_thread_area */
+	.long _sys_ni_syscall	/* sys_get_thread_area */
+	.long _sys_io_setup	/* 245 */
+	.long _sys_io_destroy
+	.long _sys_io_getevents
+	.long _sys_io_submit
+	.long _sys_io_cancel
+	.long _sys_ni_syscall	/* 250 */ /* sys_alloc_hugepages */
+	.long _sys_ni_syscall	/* sys_freec_hugepages */
+	.long _sys_exit_group
+	.long _sys_lookup_dcookie
+	.long _sys_bfin_spinlock
+	.long _sys_epoll_create	/* 255 */
+	.long _sys_epoll_ctl
+	.long _sys_epoll_wait
+	.long _sys_ni_syscall /* remap_file_pages */
+	.long _sys_set_tid_address
+	.long _sys_timer_create	/* 260 */
+	.long _sys_timer_settime
+	.long _sys_timer_gettime
+	.long _sys_timer_getoverrun
+	.long _sys_timer_delete
+	.long _sys_clock_settime /* 265 */
+	.long _sys_clock_gettime
+	.long _sys_clock_getres
+	.long _sys_clock_nanosleep
+	.long _sys_statfs64
+	.long _sys_fstatfs64	/* 270 */
+	.long _sys_tgkill
+	.long _sys_utimes
+	.long _sys_fadvise64_64
+	.long _sys_ni_syscall /* vserver */
+	.long _sys_ni_syscall /* 275, mbind */
+	.long _sys_ni_syscall /* get_mempolicy */
+	.long _sys_ni_syscall /* set_mempolicy */
+	.long _sys_mq_open
+	.long _sys_mq_unlink
+	.long _sys_mq_timedsend	/* 280 */
+	.long _sys_mq_timedreceive
+	.long _sys_mq_notify
+	.long _sys_mq_getsetattr
+	.long _sys_ni_syscall /* kexec_load */
+	.long _sys_waitid	/* 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_ni_syscall /* 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_sram_alloc
+	.long _sys_sram_free
+	.long _sys_dma_memcpy
+	.long _sys_accept
+	.long _sys_bind		/* 315 */
+	.long _sys_connect
+	.long _sys_getpeername
+	.long _sys_getsockname
+	.long _sys_getsockopt
+	.long _sys_listen	/* 320 */
+	.long _sys_recv
+	.long _sys_recvfrom
+	.long _sys_recvmsg
+	.long _sys_send
+	.long _sys_sendmsg	/* 325 */
+	.long _sys_sendto
+	.long _sys_setsockopt
+	.long _sys_shutdown
+	.long _sys_socket
+	.long _sys_socketpair	/* 330 */
+	.long _sys_semctl
+	.long _sys_semget
+	.long _sys_semop
+	.long _sys_msgctl
+	.long _sys_msgget	/* 335 */
+	.long _sys_msgrcv
+	.long _sys_msgsnd
+	.long _sys_shmat
+	.long _sys_shmctl
+	.long _sys_shmdt	/* 340 */
+	.long _sys_shmget
+	.rept NR_syscalls-(.-_sys_call_table)/4
+	.long _sys_ni_syscall
+	.endr
+_excpt_saved_imask:
+	.long 0;
+
+_exception_stack:
+	.rept 1024
+	.long 0;
+	.endr
+_exception_stack_top:
+
+#if defined(ANOMALY_05000261)
+/* Used by the assembly entry point to work around an anomaly.  */
+_last_cplb_fault_retx:
+	.long 0;
+#endif
+/*
+ * Single instructions can have multiple faults, which need to be
+ * handled by traps.c, in irq5. We store the exception cause to ensure
+ * we don't miss a double fault condition
+ */
+ENTRY(_in_ptr_excause)
+	.long 0;
+ENTRY(_out_ptr_excause)
+	.long 0;
+ALIGN
+ENTRY(_excause_circ_buf)
+	.rept 4
+	.long 0
+	.endr
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
new file mode 100644
index 0000000..dd45664
--- /dev/null
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -0,0 +1,253 @@
+/*
+ * File:         arch/blackfin/mach-common/interrupt.S
+ * Based on:
+ * Author:       D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
+ *               Kenneth Albanowski <kjahds@kjahds.com>
+ *
+ * Created:      ?
+ * Description:  Interrupt Entries
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <asm/blackfin.h>
+#include <asm/mach/irq.h>
+#include <linux/autoconf.h>
+#include <linux/linkage.h>
+#include <asm/entry.h>
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_I_ENTRY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 4 	/* just in case */
+
+/*
+ * initial interrupt handlers
+ */
+
+#ifndef CONFIG_KGDB
+ 	/* interrupt routine for emulation - 0 */
+	/* Currently used only if GDB stub is not in - invalid */
+	/* gdb-stub set the evt itself */
+	/* save registers for post-mortem only */
+ENTRY(_evt_emulation)
+	SAVE_ALL_SYS
+#ifdef CONFIG_FRAME_POINTER
+	fp = 0;
+#endif
+	r0 = IRQ_EMU;
+	r1 = sp;
+	SP += -12;
+	call _irq_panic;
+	SP += 12;
+	/* - GDB stub fills this in by itself (if defined) */
+	rte;
+#endif
+
+/* Common interrupt entry code.	 First we do CLI, then push
+ * RETI, to keep interrupts disabled, but to allow this state to be changed
+ * by local_bh_enable.
+ * R0 contains the interrupt number, while R1 may contain the value of IPEND,
+ * or garbage if IPEND won't be needed by the ISR.  */
+__common_int_entry:
+	[--sp] = fp;
+	[--sp] = usp;
+
+	[--sp] = i0;
+	[--sp] = i1;
+	[--sp] = i2;
+	[--sp] = i3;
+
+	[--sp] = m0;
+	[--sp] = m1;
+	[--sp] = m2;
+	[--sp] = m3;
+
+	[--sp] = l0;
+	[--sp] = l1;
+	[--sp] = l2;
+	[--sp] = l3;
+
+	[--sp] = b0;
+	[--sp] = b1;
+	[--sp] = b2;
+	[--sp] = b3;
+	[--sp] = a0.x;
+	[--sp] = a0.w;
+	[--sp] = a1.x;
+	[--sp] = a1.w;
+
+	[--sp] = LC0;
+	[--sp] = LC1;
+	[--sp] = LT0;
+	[--sp] = LT1;
+	[--sp] = LB0;
+	[--sp] = LB1;
+
+	[--sp] = ASTAT;
+
+	[--sp] = r0;	/* Skip reserved */
+	[--sp] = RETS;
+	r2 = RETI;
+	[--sp] = r2;
+	[--sp] = RETX;
+	[--sp] = RETN;
+	[--sp] = RETE;
+	[--sp] = SEQSTAT;
+	[--sp] = r1;	/* IPEND - R1 may or may not be set up before jumping here. */
+
+	/* Switch to other method of keeping interrupts disabled.  */
+#ifdef CONFIG_DEBUG_HWERR
+	r1 = 0x3f;
+	sti r1;
+#else
+	cli r1;
+#endif
+	[--sp] = RETI;  /* orig_pc */
+	/* Clear all L registers.  */
+	r1 = 0 (x);
+	l0 = r1;
+	l1 = r1;
+	l2 = r1;
+	l3 = r1;
+#ifdef CONFIG_FRAME_POINTER
+	fp = 0;
+#endif
+
+#ifdef	ANOMALY_05000283
+	cc = r7 == r7;
+	p5.h = 0xffc0;
+	p5.l = 0x0014;
+	if cc jump 1f;
+	r7.l = W[p5];
+1:
+#endif
+	r1 =  sp;
+	SP += -12;
+	call _do_irq;
+	SP += 12;
+	call _return_from_int;
+.Lcommon_restore_context:
+	RESTORE_CONTEXT
+	rti;
+
+/* interrupt routine for ivhw - 5 */
+ENTRY(_evt_ivhw)
+	SAVE_CONTEXT
+#ifdef CONFIG_FRAME_POINTER
+	fp = 0;
+#endif
+#ifdef	ANOMALY_05000283
+	cc = r7 == r7;
+	p5.h = 0xffc0;
+	p5.l = 0x0014;
+	if cc jump 1f;
+	r7.l = W[p5];
+1:
+#endif
+	p0.l = lo(TBUFCTL);
+	p0.h = hi(TBUFCTL);
+	r0 = 1;
+	[p0] = r0;
+	r0 = IRQ_HWERR;
+	r1 = sp;
+
+#ifdef CONFIG_HARDWARE_PM
+	r7 = SEQSTAT;
+	r7 = r7 >>> 0xe;
+	r6 = 0x1F;
+	r7 = r7 & r6;
+	r5 = 0x12;
+	cc = r7 == r5;
+	if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
+#endif
+
+	SP += -12;
+	call _irq_panic;
+	SP += 12;
+	rti;
+#ifdef CONFIG_HARDWARE_PM
+.Lcall_do_ovf:
+
+	SP += -12;
+	call _pm_overflow;
+	SP += 12;
+
+	jump .Lcommon_restore_context;
+#endif
+
+/* interrupt routine for evt2 - 2.  This is NMI.  */
+ENTRY(_evt_evt2)
+	SAVE_CONTEXT
+#ifdef CONFIG_FRAME_POINTER
+	fp = 0;
+#endif
+#ifdef	ANOMALY_05000283
+	cc = r7 == r7;
+	p5.h = 0xffc0;
+	p5.l = 0x0014;
+	if cc jump 1f;
+	r7.l = W[p5];
+1:
+#endif
+	r0 = IRQ_NMI;
+	r1 =  sp;
+	SP += -12;
+	call _asm_do_IRQ;
+	SP += 12;
+	RESTORE_CONTEXT
+	rtn;
+
+/* interrupt routine for core timer - 6 */
+ENTRY(_evt_timer)
+	TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)
+
+/* interrupt routine for evt7 - 7 */
+ENTRY(_evt_evt7)
+	INTERRUPT_ENTRY(EVT_IVG7_P)
+ENTRY(_evt_evt8)
+	INTERRUPT_ENTRY(EVT_IVG8_P)
+ENTRY(_evt_evt9)
+	INTERRUPT_ENTRY(EVT_IVG9_P)
+ENTRY(_evt_evt10)
+	INTERRUPT_ENTRY(EVT_IVG10_P)
+ENTRY(_evt_evt11)
+	INTERRUPT_ENTRY(EVT_IVG11_P)
+ENTRY(_evt_evt12)
+	INTERRUPT_ENTRY(EVT_IVG12_P)
+ENTRY(_evt_evt13)
+	INTERRUPT_ENTRY(EVT_IVG13_P)
+
+
+ /* interrupt routine for system_call - 15 */
+ENTRY(_evt_system_call)
+	SAVE_CONTEXT_SYSCALL
+#ifdef CONFIG_FRAME_POINTER
+	fp = 0;
+#endif
+	call _system_call;
+	jump .Lcommon_restore_context;
diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
new file mode 100644
index 0000000..f3cf070
--- /dev/null
+++ b/arch/blackfin/mach-common/ints-priority-dc.c
@@ -0,0 +1,476 @@
+/*
+ * File:         arch/blackfin/mach-common/ints-priority-dc.c
+ * Based on:
+ * Author:
+ *
+ * Created:      ?
+ * Description:  Set up the interupt priorities
+ *
+ * Modified:
+ *               1996 Roman Zippel
+ *               1999 D. Jeff Dionne <jeff@uclinux.org>
+ *               2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ *               2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ *               2003 Metrowerks/Motorola
+ *               2003 Bas Vermeulen <bas@buyways.nl>
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <linux/kgdb.h>
+#endif
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/irq_handler.h>
+
+/*
+ * NOTES:
+ * - we have separated the physical Hardware interrupt from the
+ * levels that the LINUX kernel sees (see the description in irq.h)
+ * -
+ */
+
+unsigned long irq_flags = 0;
+
+/* The number of spurious interrupts */
+atomic_t num_spurious;
+
+struct ivgx {
+	/* irq number for request_irq, available in mach-bf561/irq.h */
+	int irqno;
+	/* corresponding bit in the SICA_ISR0 register */
+	int isrflag0;
+	/* corresponding bit in the SICA_ISR1 register */
+	int isrflag1;
+} ivg_table[NR_PERI_INTS];
+
+struct ivg_slice {
+	/* position of first irq in ivg_table for given ivg */
+	struct ivgx *ifirst;
+	struct ivgx *istop;
+} ivg7_13[IVG13 - IVG7 + 1];
+
+static void search_IAR(void);
+
+/*
+ * Search SIC_IAR and fill tables with the irqvalues
+ * and their positions in the SIC_ISR register.
+ */
+static void __init search_IAR(void)
+{
+	unsigned ivg, irq_pos = 0;
+	for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
+		int irqn;
+
+		ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
+
+		for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
+			int iar_shift = (irqn & 7) * 4;
+			if (ivg ==
+			    (0xf &
+			     bfin_read32((unsigned long *)SICA_IAR0 +
+					 (irqn >> 3)) >> iar_shift)) {
+				ivg_table[irq_pos].irqno = IVG7 + irqn;
+				ivg_table[irq_pos].isrflag0 =
+				    (irqn < 32 ? (1 << irqn) : 0);
+				ivg_table[irq_pos].isrflag1 =
+				    (irqn < 32 ? 0 : (1 << (irqn - 32)));
+				ivg7_13[ivg].istop++;
+				irq_pos++;
+			}
+		}
+	}
+}
+
+/*
+ * This is for BF561 internal IRQs
+ */
+
+static void ack_noop(unsigned int irq)
+{
+	/* Dummy function.  */
+}
+
+static void bf561_core_mask_irq(unsigned int irq)
+{
+	irq_flags &= ~(1 << irq);
+	if (!irqs_disabled())
+		local_irq_enable();
+}
+
+static void bf561_core_unmask_irq(unsigned int irq)
+{
+	irq_flags |= 1 << irq;
+	/*
+	 * If interrupts are enabled, IMASK must contain the same value
+	 * as irq_flags.  Make sure that invariant holds.  If interrupts
+	 * are currently disabled we need not do anything; one of the
+	 * callers will take care of setting IMASK to the proper value
+	 * when reenabling interrupts.
+	 * local_irq_enable just does "STI irq_flags", so it's exactly
+	 * what we need.
+	 */
+	if (!irqs_disabled())
+		local_irq_enable();
+	return;
+}
+
+static void bf561_internal_mask_irq(unsigned int irq)
+{
+	unsigned long irq_mask;
+	if ((irq - (IRQ_CORETMR + 1)) < 32) {
+		irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
+		bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() & ~irq_mask);
+	} else {
+		irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
+		bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() & ~irq_mask);
+	}
+}
+
+static void bf561_internal_unmask_irq(unsigned int irq)
+{
+	unsigned long irq_mask;
+
+	if ((irq - (IRQ_CORETMR + 1)) < 32) {
+		irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
+		bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() | irq_mask);
+	} else {
+		irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
+		bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() | irq_mask);
+	}
+	SSYNC();
+}
+
+static struct irq_chip bf561_core_irqchip = {
+	.ack = ack_noop,
+	.mask = bf561_core_mask_irq,
+	.unmask = bf561_core_unmask_irq,
+};
+
+static struct irq_chip bf561_internal_irqchip = {
+	.ack = ack_noop,
+	.mask = bf561_internal_mask_irq,
+	.unmask = bf561_internal_unmask_irq,
+};
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+static void bf561_gpio_ack_irq(unsigned int irq)
+{
+	u16 gpionr = irq - IRQ_PF0;
+
+	if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+		set_gpio_data(gpionr, 0);
+		SSYNC();
+	}
+}
+
+static void bf561_gpio_mask_ack_irq(unsigned int irq)
+{
+	u16 gpionr = irq - IRQ_PF0;
+
+	if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+		set_gpio_data(gpionr, 0);
+		SSYNC();
+	}
+
+	set_gpio_maska(gpionr, 0);
+	SSYNC();
+}
+
+static void bf561_gpio_mask_irq(unsigned int irq)
+{
+	set_gpio_maska(irq - IRQ_PF0, 0);
+	SSYNC();
+}
+
+static void bf561_gpio_unmask_irq(unsigned int irq)
+{
+	set_gpio_maska(irq - IRQ_PF0, 1);
+	SSYNC();
+}
+
+static unsigned int bf561_gpio_irq_startup(unsigned int irq)
+{
+	unsigned int ret;
+	u16 gpionr = irq - IRQ_PF0;
+
+	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+
+		ret = gpio_request(gpionr, NULL);
+		if(ret)
+			return ret;
+
+	}
+
+	gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+	bf561_gpio_unmask_irq(irq);
+
+  return ret;
+
+}
+
+static void bf561_gpio_irq_shutdown(unsigned int irq)
+{
+	bf561_gpio_mask_irq(irq);
+	gpio_free(irq - IRQ_PF0);
+	gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+}
+
+static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+
+	unsigned int ret;
+	u16 gpionr = irq - IRQ_PF0;
+
+
+		if (type == IRQ_TYPE_PROBE) {
+			/* only probe unenabled GPIO interrupt lines */
+			if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+				return 0;
+			type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+		}
+
+		if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+			    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+
+		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+
+			ret = gpio_request(gpionr, NULL);
+			if(ret)
+				return ret;
+
+		}
+
+			gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+		} else {
+			gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+			return 0;
+		}
+
+
+		set_gpio_dir(gpionr, 0);
+		set_gpio_inen(gpionr, 1);
+
+
+		if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+			gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+			set_gpio_edge(gpionr, 1);
+		} else {
+			set_gpio_edge(gpionr, 0);
+			gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+		}
+
+		if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		    == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+			set_gpio_both(gpionr, 1);
+		else
+			set_gpio_both(gpionr, 0);
+
+		if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+			set_gpio_polar(gpionr, 1);	/* low or falling edge denoted by one */
+		else
+			set_gpio_polar(gpionr, 0);	/* high or rising edge denoted by zero */
+
+	SSYNC();
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		set_irq_handler(irq, handle_edge_irq);
+	else
+		set_irq_handler(irq, handle_level_irq);
+
+	return 0;
+}
+
+static struct irq_chip bf561_gpio_irqchip = {
+	.ack = bf561_gpio_ack_irq,
+	.mask = bf561_gpio_mask_irq,
+	.mask_ack = bf561_gpio_mask_ack_irq,
+	.unmask = bf561_gpio_unmask_irq,
+	.set_type = bf561_gpio_irq_type,
+	.startup = bf561_gpio_irq_startup,
+	.shutdown = bf561_gpio_irq_shutdown
+};
+
+static void bf561_demux_gpio_irq(unsigned int inta_irq,
+				 struct irq_desc *intb_desc)
+{
+	int irq, flag_d, mask;
+	u16 gpio;
+
+	switch (inta_irq) {
+	case IRQ_PROG0_INTA:
+		irq = IRQ_PF0;
+		break;
+	case IRQ_PROG1_INTA:
+		irq = IRQ_PF16;
+		break;
+	case IRQ_PROG2_INTA:
+		irq = IRQ_PF32;
+		break;
+	default:
+		dump_stack();
+		return;
+	}
+
+	gpio = irq - IRQ_PF0;
+
+		flag_d = get_gpiop_data(gpio);
+		mask = flag_d & (gpio_enabled[gpio_bank(gpio)] &
+			      get_gpiop_maska(gpio));
+
+			do {
+				if (mask & 1) {
+					struct irq_desc *desc = irq_desc + irq;
+					desc->handle_irq(irq, desc);
+				}
+				irq++;
+				mask >>= 1;
+			} while (mask);
+
+
+}
+
+#endif				/* CONFIG_IRQCHIP_DEMUX_GPIO */
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the BFin IRQ handling routines.
+ */
+int __init init_arch_irq(void)
+{
+	int irq;
+	unsigned long ilat = 0;
+	/*  Disable all the peripheral intrs  - page 4-29 HW Ref manual */
+	bfin_write_SICA_IMASK0(SIC_UNMASK_ALL);
+	bfin_write_SICA_IMASK1(SIC_UNMASK_ALL);
+	SSYNC();
+
+	local_irq_disable();
+
+	init_exception_buff();
+
+#ifndef CONFIG_KGDB
+	bfin_write_EVT0(evt_emulation);
+#endif
+	bfin_write_EVT2(evt_evt2);
+	bfin_write_EVT3(trap);
+	bfin_write_EVT5(evt_ivhw);
+	bfin_write_EVT6(evt_timer);
+	bfin_write_EVT7(evt_evt7);
+	bfin_write_EVT8(evt_evt8);
+	bfin_write_EVT9(evt_evt9);
+	bfin_write_EVT10(evt_evt10);
+	bfin_write_EVT11(evt_evt11);
+	bfin_write_EVT12(evt_evt12);
+	bfin_write_EVT13(evt_evt13);
+	bfin_write_EVT14(evt14_softirq);
+	bfin_write_EVT15(evt_system_call);
+	CSYNC();
+
+	for (irq = 0; irq < SYS_IRQS; irq++) {
+		if (irq <= IRQ_CORETMR)
+			set_irq_chip(irq, &bf561_core_irqchip);
+		else
+			set_irq_chip(irq, &bf561_internal_irqchip);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+		if ((irq != IRQ_PROG0_INTA) &&
+		    (irq != IRQ_PROG1_INTA) && (irq != IRQ_PROG2_INTA)) {
+#endif
+			set_irq_handler(irq, handle_simple_irq);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+		} else {
+			set_irq_chained_handler(irq, bf561_demux_gpio_irq);
+		}
+#endif
+
+	}
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+	for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) {
+		set_irq_chip(irq, &bf561_gpio_irqchip);
+		/* if configured as edge, then will be changed to do_edge_IRQ */
+		set_irq_handler(irq, handle_level_irq);
+	}
+#endif
+	bfin_write_IMASK(0);
+	CSYNC();
+	ilat = bfin_read_ILAT();
+	CSYNC();
+	bfin_write_ILAT(ilat);
+	CSYNC();
+
+	printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
+	/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
+	 * local_irq_enable()
+	 */
+	program_IAR();
+	/* Therefore it's better to setup IARs before interrupts enabled */
+	search_IAR();
+
+	/* Enable interrupts IVG7-15 */
+	irq_flags = irq_flags | IMASK_IVG15 |
+	    IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
+	    IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
+
+	return 0;
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
+#endif
+
+void do_irq(int vec, struct pt_regs *fp)
+{
+	if (vec == EVT_IVTMR_P) {
+		vec = IRQ_CORETMR;
+	} else {
+		struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+		struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+		unsigned long sic_status0, sic_status1;
+
+		SSYNC();
+		sic_status0 = bfin_read_SICA_IMASK0() & bfin_read_SICA_ISR0();
+		sic_status1 = bfin_read_SICA_IMASK1() & bfin_read_SICA_ISR1();
+
+		for (;; ivg++) {
+			if (ivg >= ivg_stop) {
+				atomic_inc(&num_spurious);
+				return;
+			} else if ((sic_status0 & ivg->isrflag0) ||
+				   (sic_status1 & ivg->isrflag1))
+				break;
+		}
+		vec = ivg->irqno;
+	}
+	asm_do_IRQ(vec, fp);
+
+#ifdef CONFIG_KGDB
+	kgdb_process_breakpoint();
+#endif
+}
diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
new file mode 100644
index 0000000..34b6228
--- /dev/null
+++ b/arch/blackfin/mach-common/ints-priority-sc.c
@@ -0,0 +1,577 @@
+/*
+ * File:         arch/blackfin/mach-common/ints-priority-sc.c
+ * Based on:
+ * Author:
+ *
+ * Created:      ?
+ * Description:  Set up the interupt priorities
+ *
+ * Modified:
+ *               1996 Roman Zippel
+ *               1999 D. Jeff Dionne <jeff@uclinux.org>
+ *               2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ *               2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ *               2003 Metrowerks/Motorola
+ *               2003 Bas Vermeulen <bas@buyways.nl>
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <linux/kgdb.h>
+#endif
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/irq_handler.h>
+
+#ifdef BF537_FAMILY
+# define BF537_GENERIC_ERROR_INT_DEMUX
+#else
+# undef BF537_GENERIC_ERROR_INT_DEMUX
+#endif
+
+/*
+ * NOTES:
+ * - we have separated the physical Hardware interrupt from the
+ * levels that the LINUX kernel sees (see the description in irq.h)
+ * -
+ */
+
+unsigned long irq_flags = 0;
+
+/* The number of spurious interrupts */
+atomic_t num_spurious;
+
+struct ivgx {
+	/* irq number for request_irq, available in mach-bf533/irq.h */
+	int irqno;
+	/* corresponding bit in the SIC_ISR register */
+	int isrflag;
+} ivg_table[NR_PERI_INTS];
+
+struct ivg_slice {
+	/* position of first irq in ivg_table for given ivg */
+	struct ivgx *ifirst;
+	struct ivgx *istop;
+} ivg7_13[IVG13 - IVG7 + 1];
+
+static void search_IAR(void);
+
+/*
+ * Search SIC_IAR and fill tables with the irqvalues
+ * and their positions in the SIC_ISR register.
+ */
+static void __init search_IAR(void)
+{
+	unsigned ivg, irq_pos = 0;
+	for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
+		int irqn;
+
+		ivg7_13[ivg].istop = ivg7_13[ivg].ifirst =
+		    &ivg_table[irq_pos];
+
+		for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
+			int iar_shift = (irqn & 7) * 4;
+			if (ivg ==
+			    (0xf &
+			     bfin_read32((unsigned long *) SIC_IAR0 +
+					 (irqn >> 3)) >> iar_shift)) {
+				ivg_table[irq_pos].irqno = IVG7 + irqn;
+				ivg_table[irq_pos].isrflag = 1 << irqn;
+				ivg7_13[ivg].istop++;
+				irq_pos++;
+			}
+		}
+	}
+}
+
+/*
+ * This is for BF533 internal IRQs
+ */
+
+static void ack_noop(unsigned int irq)
+{
+	/* Dummy function.  */
+}
+
+static void bfin_core_mask_irq(unsigned int irq)
+{
+	irq_flags &= ~(1 << irq);
+	if (!irqs_disabled())
+		local_irq_enable();
+}
+
+static void bfin_core_unmask_irq(unsigned int irq)
+{
+	irq_flags |= 1 << irq;
+	/*
+	 * If interrupts are enabled, IMASK must contain the same value
+	 * as irq_flags.  Make sure that invariant holds.  If interrupts
+	 * are currently disabled we need not do anything; one of the
+	 * callers will take care of setting IMASK to the proper value
+	 * when reenabling interrupts.
+	 * local_irq_enable just does "STI irq_flags", so it's exactly
+	 * what we need.
+	 */
+	if (!irqs_disabled())
+		local_irq_enable();
+	return;
+}
+
+static void bfin_internal_mask_irq(unsigned int irq)
+{
+	bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+			     ~(1 << (irq - (IRQ_CORETMR + 1))));
+	SSYNC();
+}
+
+static void bfin_internal_unmask_irq(unsigned int irq)
+{
+	bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+			     (1 << (irq - (IRQ_CORETMR + 1))));
+	SSYNC();
+}
+
+static struct irq_chip bfin_core_irqchip = {
+	.ack = ack_noop,
+	.mask = bfin_core_mask_irq,
+	.unmask = bfin_core_unmask_irq,
+};
+
+static struct irq_chip bfin_internal_irqchip = {
+	.ack = ack_noop,
+	.mask = bfin_internal_mask_irq,
+	.unmask = bfin_internal_unmask_irq,
+};
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+static int error_int_mask;
+
+static void bfin_generic_error_ack_irq(unsigned int irq)
+{
+
+}
+
+static void bfin_generic_error_mask_irq(unsigned int irq)
+{
+	error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
+
+	if (!error_int_mask) {
+		local_irq_disable();
+		bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+				     ~(1 <<
+				       (IRQ_GENERIC_ERROR -
+					(IRQ_CORETMR + 1))));
+		SSYNC();
+		local_irq_enable();
+	}
+}
+
+static void bfin_generic_error_unmask_irq(unsigned int irq)
+{
+	local_irq_disable();
+	bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 1 <<
+			     (IRQ_GENERIC_ERROR - (IRQ_CORETMR + 1)));
+	SSYNC();
+	local_irq_enable();
+
+	error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bfin_generic_error_irqchip = {
+	.ack = bfin_generic_error_ack_irq,
+	.mask = bfin_generic_error_mask_irq,
+	.unmask = bfin_generic_error_unmask_irq,
+};
+
+static void bfin_demux_error_irq(unsigned int int_err_irq,
+				  struct irq_desc *intb_desc)
+{
+	int irq = 0;
+
+	SSYNC();
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+	if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+		irq = IRQ_MAC_ERROR;
+	else
+#endif
+	if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+		irq = IRQ_SPORT0_ERROR;
+	else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+		irq = IRQ_SPORT1_ERROR;
+	else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+		irq = IRQ_PPI_ERROR;
+	else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+		irq = IRQ_CAN_ERROR;
+	else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+		irq = IRQ_SPI_ERROR;
+	else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) &&
+		 (bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0))
+		irq = IRQ_UART0_ERROR;
+	else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) &&
+		 (bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0))
+		irq = IRQ_UART1_ERROR;
+
+	if (irq) {
+		if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) {
+			struct irq_desc *desc = irq_desc + irq;
+			desc->handle_irq(irq, desc);
+		} else {
+
+			switch (irq) {
+			case IRQ_PPI_ERROR:
+				bfin_write_PPI_STATUS(PPI_ERR_MASK);
+				break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+			case IRQ_MAC_ERROR:
+				bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+				break;
+#endif
+			case IRQ_SPORT0_ERROR:
+				bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+				break;
+
+			case IRQ_SPORT1_ERROR:
+				bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+				break;
+
+			case IRQ_CAN_ERROR:
+				bfin_write_CAN_GIS(CAN_ERR_MASK);
+				break;
+
+			case IRQ_SPI_ERROR:
+				bfin_write_SPI_STAT(SPI_ERR_MASK);
+				break;
+
+			default:
+				break;
+			}
+
+			pr_debug("IRQ %d:"
+				" MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+				irq);
+		}
+	} else
+		printk(KERN_ERR
+		       "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
+		       " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+		       __FUNCTION__, __FILE__, __LINE__);
+
+
+}
+#endif				/* BF537_GENERIC_ERROR_INT_DEMUX */
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+static void bfin_gpio_ack_irq(unsigned int irq)
+{
+	u16 gpionr = irq - IRQ_PF0;
+
+	if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+		set_gpio_data(gpionr, 0);
+		SSYNC();
+	}
+}
+
+static void bfin_gpio_mask_ack_irq(unsigned int irq)
+{
+	u16 gpionr = irq - IRQ_PF0;
+
+	if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+		set_gpio_data(gpionr, 0);
+		SSYNC();
+	}
+
+	set_gpio_maska(gpionr, 0);
+	SSYNC();
+}
+
+static void bfin_gpio_mask_irq(unsigned int irq)
+{
+	set_gpio_maska(irq - IRQ_PF0, 0);
+	SSYNC();
+}
+
+static void bfin_gpio_unmask_irq(unsigned int irq)
+{
+	set_gpio_maska(irq - IRQ_PF0, 1);
+	SSYNC();
+}
+
+static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+{
+	unsigned int ret;
+	u16 gpionr = irq - IRQ_PF0;
+
+	if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+		ret = gpio_request(gpionr, NULL);
+		if (ret)
+			return ret;
+	}
+
+	gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+	bfin_gpio_unmask_irq(irq);
+
+	return ret;
+}
+
+static void bfin_gpio_irq_shutdown(unsigned int irq)
+{
+	bfin_gpio_mask_irq(irq);
+	gpio_free(irq - IRQ_PF0);
+	gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+}
+
+static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+
+	unsigned int ret;
+	u16 gpionr = irq - IRQ_PF0;
+
+	if (type == IRQ_TYPE_PROBE) {
+		/* only probe unenabled GPIO interrupt lines */
+		if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+			return 0;
+		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+	}
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+	            IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+	{
+		if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+			ret = gpio_request(gpionr, NULL);
+			if (ret)
+				return ret;
+		}
+
+		gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+	} else {
+		gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+		return 0;
+	}
+
+	set_gpio_dir(gpionr, 0);
+	set_gpio_inen(gpionr, 1);
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+		gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+		set_gpio_edge(gpionr, 1);
+	} else {
+		set_gpio_edge(gpionr, 0);
+		gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+	}
+
+	if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+	    == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		set_gpio_both(gpionr, 1);
+	else
+		set_gpio_both(gpionr, 0);
+
+	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+		set_gpio_polar(gpionr, 1);	/* low or falling edge denoted by one */
+	else
+		set_gpio_polar(gpionr, 0);	/* high or rising edge denoted by zero */
+
+	SSYNC();
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		set_irq_handler(irq, handle_edge_irq);
+	else
+		set_irq_handler(irq, handle_level_irq);
+
+	return 0;
+}
+
+
+static struct irq_chip bfin_gpio_irqchip = {
+	.ack = bfin_gpio_ack_irq,
+	.mask = bfin_gpio_mask_irq,
+	.mask_ack = bfin_gpio_mask_ack_irq,
+	.unmask = bfin_gpio_unmask_irq,
+	.set_type = bfin_gpio_irq_type,
+	.startup = bfin_gpio_irq_startup,
+	.shutdown = bfin_gpio_irq_shutdown
+};
+
+static void bfin_demux_gpio_irq(unsigned int intb_irq,
+				 struct irq_desc *intb_desc)
+{
+	u16 i;
+
+	for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=16) {
+		int irq = IRQ_PF0 + i;
+		int flag_d = get_gpiop_data(i);
+		int mask =
+			flag_d & (gpio_enabled[gpio_bank(i)] &
+			      get_gpiop_maska(i));
+
+		while (mask) {
+			if (mask & 1) {
+				struct irq_desc *desc = irq_desc + irq;
+				desc->handle_irq(irq, desc);
+			}
+			irq++;
+			mask >>= 1;
+		}
+	}
+}
+
+#endif				/* CONFIG_IRQCHIP_DEMUX_GPIO */
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the BFin IRQ handling routines.
+ */
+int __init init_arch_irq(void)
+{
+	int irq;
+	unsigned long ilat = 0;
+	/*  Disable all the peripheral intrs  - page 4-29 HW Ref manual */
+	bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
+	SSYNC();
+
+	local_irq_disable();
+
+#ifndef CONFIG_KGDB
+	bfin_write_EVT0(evt_emulation);
+#endif
+	bfin_write_EVT2(evt_evt2);
+	bfin_write_EVT3(trap);
+	bfin_write_EVT5(evt_ivhw);
+	bfin_write_EVT6(evt_timer);
+	bfin_write_EVT7(evt_evt7);
+	bfin_write_EVT8(evt_evt8);
+	bfin_write_EVT9(evt_evt9);
+	bfin_write_EVT10(evt_evt10);
+	bfin_write_EVT11(evt_evt11);
+	bfin_write_EVT12(evt_evt12);
+	bfin_write_EVT13(evt_evt13);
+	bfin_write_EVT14(evt14_softirq);
+	bfin_write_EVT15(evt_system_call);
+	CSYNC();
+
+	for (irq = 0; irq < SYS_IRQS; irq++) {
+		if (irq <= IRQ_CORETMR)
+			set_irq_chip(irq, &bfin_core_irqchip);
+		else
+			set_irq_chip(irq, &bfin_internal_irqchip);
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+		if (irq != IRQ_GENERIC_ERROR) {
+#endif
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+			if ((irq != IRQ_PROG_INTA) /*PORT F & G MASK_A Interrupt*/
+# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+				&& (irq != IRQ_MAC_RX) /*PORT H MASK_A Interrupt*/
+# endif
+			    ) {
+#endif
+				set_irq_handler(irq, handle_simple_irq);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+			} else {
+				set_irq_chained_handler(irq,
+							bfin_demux_gpio_irq);
+			}
+#endif
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+		} else {
+			set_irq_handler(irq, bfin_demux_error_irq);
+		}
+#endif
+	}
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+	for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) {
+		set_irq_chip(irq, &bfin_generic_error_irqchip);
+		set_irq_handler(irq, handle_level_irq);
+	}
+#endif
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+	for (irq = IRQ_PF0; irq < NR_IRQS; irq++) {
+		set_irq_chip(irq, &bfin_gpio_irqchip);
+		/* if configured as edge, then will be changed to do_edge_IRQ */
+		set_irq_handler(irq, handle_level_irq);
+	}
+#endif
+	bfin_write_IMASK(0);
+	CSYNC();
+	ilat = bfin_read_ILAT();
+	CSYNC();
+	bfin_write_ILAT(ilat);
+	CSYNC();
+
+	printk(KERN_INFO
+	       "Configuring Blackfin Priority Driven Interrupts\n");
+	/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
+	 * local_irq_enable()
+	 */
+	program_IAR();
+	/* Therefore it's better to setup IARs before interrupts enabled */
+	search_IAR();
+
+	/* Enable interrupts IVG7-15 */
+	irq_flags = irq_flags | IMASK_IVG15 |
+	    IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
+	    IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 |
+	    IMASK_IVGHW;
+
+	return 0;
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
+#endif
+
+void do_irq(int vec, struct pt_regs *fp)
+{
+	if (vec == EVT_IVTMR_P) {
+		vec = IRQ_CORETMR;
+	} else {
+		struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+		struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+		unsigned long sic_status;
+
+		SSYNC();
+		sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+
+		for (;; ivg++) {
+			if (ivg >= ivg_stop) {
+				atomic_inc(&num_spurious);
+				return;
+			} else if (sic_status & ivg->isrflag)
+				break;
+		}
+		vec = ivg->irqno;
+	}
+	asm_do_IRQ(vec, fp);
+
+#ifdef CONFIG_KGDB
+	kgdb_process_breakpoint();
+#endif
+}
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
new file mode 100644
index 0000000..f05e3da
--- /dev/null
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -0,0 +1,194 @@
+/*
+ * File:         arch/blackfin/mach-common/irqpanic.c
+ * Based on:
+ * Author:
+ *
+ * Created:      ?
+ * Description:  panic kernel with dump information
+ *
+ * Modified:     rgetz - added cache checking code 14Feb06
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+
+#include "../oprofile/op_blackfin.h"
+
+#ifdef CONFIG_DEBUG_ICACHE_CHECK
+#define L1_ICACHE_START 0xffa10000
+#define L1_ICACHE_END   0xffa13fff
+void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
+#endif
+
+/*
+ * irq_panic - calls panic with string setup
+ */
+asmlinkage void irq_panic(int reason, struct pt_regs *regs)
+{
+	int sig = 0;
+	siginfo_t info;
+
+#ifdef CONFIG_DEBUG_ICACHE_CHECK
+	unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
+	unsigned short i, j, die;
+	unsigned int bad[10][6];
+
+	/* check entire cache for coherency
+	 * Since printk is in cacheable memory,
+	 * don't call it until you have checked everything
+	*/
+
+	die = 0;
+	i = 0;
+
+	/* check icache */
+
+	for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
+
+		/* Grab various address bits for the itest_cmd fields                      */
+		cmd = (((ca & 0x3000) << 4) |	/* ca[13:12] for SBNK[1:0]             */
+		       ((ca & 0x0c00) << 16) |	/* ca[11:10] for WAYSEL[1:0]           */
+		       ((ca & 0x3f8)) |	/* ca[09:03] for SET[4:0] and DW[1:0]  */
+		       0);	/* Access Tag, Read access             */
+
+		SSYNC();
+		bfin_write_ITEST_COMMAND(cmd);
+		SSYNC();
+		tag = bfin_read_ITEST_DATA0();
+		SSYNC();
+
+		/* if tag is marked as valid, check it */
+		if (tag & 1) {
+			/* The icache is arranged in 4 groups of 64-bits */
+			for (j = 0; j < 32; j += 8) {
+				cmd = ((((ca + j) & 0x3000) << 4) |	/* ca[13:12] for SBNK[1:0]             */
+				       (((ca + j) & 0x0c00) << 16) |	/* ca[11:10] for WAYSEL[1:0]           */
+				       (((ca + j) & 0x3f8)) |	/* ca[09:03] for SET[4:0] and DW[1:0]  */
+				       4);	/* Access Data, Read access             */
+
+				SSYNC();
+				bfin_write_ITEST_COMMAND(cmd);
+				SSYNC();
+
+				cache_hi = bfin_read_ITEST_DATA1();
+				cache_lo = bfin_read_ITEST_DATA0();
+
+				pa = ((unsigned int *)((tag & 0xffffcc00) |
+						       ((ca + j) & ~(0xffffcc00))));
+
+				/*
+				 * Debugging this, enable
+				 *
+				 * printk("addr: %08x %08x%08x | %08x%08x\n",
+				 *  ((unsigned int *)((tag & 0xffffcc00)  | ((ca+j) & ~(0xffffcc00)))),
+				 *   cache_hi, cache_lo, *(pa+1), *pa);
+				 */
+
+				if (cache_hi != *(pa + 1) || cache_lo != *pa) {
+					/* Since icache is not working, stay out of it, by not printing */
+					die = 1;
+					bad[i][0] = (ca + j);
+					bad[i][1] = cache_hi;
+					bad[i][2] = cache_lo;
+					bad[i][3] = ((tag & 0xffffcc00) |
+					     	((ca + j) & ~(0xffffcc00)));
+					bad[i][4] = *(pa + 1);
+					bad[i][5] = *(pa);
+					i++;
+				}
+			}
+		}
+	}
+	if (die) {
+		printk(KERN_EMERG "icache coherency error\n");
+		for (j = 0; j <= i; j++) {
+			printk(KERN_EMERG
+			    "cache address   : %08x  cache value : %08x%08x\n",
+			     bad[j][0], bad[j][1], bad[j][2]);
+			printk(KERN_EMERG
+			    "physical address: %08x  SDRAM value : %08x%08x\n",
+			     bad[j][3], bad[j][4], bad[j][5]);
+		}
+		panic("icache coherency error");
+	} else {
+		printk(KERN_EMERG "icache checked, and OK\n");
+	}
+#endif
+
+	printk(KERN_EMERG "\n");
+	printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
+	printk(KERN_EMERG " code=[0x%08lx],   stack frame=0x%08lx,  "
+	    " bad PC=0x%08lx\n",
+	    (unsigned long)regs->seqstat,
+	    (unsigned long)regs,
+	    (unsigned long)regs->pc);
+	if (reason == 0x5) {
+		printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
+
+		/* There is only need to check for Hardware Errors, since other
+		 * EXCEPTIONS are handled in TRAPS.c (MH)
+		 */
+		switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
+		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):	/* System MMR Error */
+			info.si_code = BUS_ADRALN;
+			sig = SIGBUS;
+			printk(KERN_EMERG HWC_x2);
+			break;
+		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):	/* External Memory Addressing Error */
+			info.si_code = BUS_ADRERR;
+			sig = SIGBUS;
+			printk(KERN_EMERG HWC_x3);
+			break;
+		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):	/* Performance Monitor Overflow */
+			printk(KERN_EMERG HWC_x12);
+			break;
+		case (SEQSTAT_HWERRCAUSE_RAISE_5):	/* RAISE 5 instruction */
+			printk(KERN_EMERG HWC_x18);
+			break;
+		default:	/* Reserved */
+			printk(KERN_EMERG HWC_default);
+			break;
+		}
+	}
+
+	regs->ipend = bfin_read_IPEND();
+	dump_bfin_regs(regs, (void *)regs->pc);
+	if (0 == (info.si_signo = sig) || 0 == user_mode(regs))	/* in kernelspace */
+		panic("Unhandled IRQ or exceptions!\n");
+	else {			/* in userspace */
+		info.si_errno = 0;
+		info.si_addr = (void *)regs->pc;
+		force_sig_info(sig, &info, current);
+	}
+}
+
+#ifdef CONFIG_HARDWARE_PM
+/*
+ * call the handler of Performance overflow
+ */
+asmlinkage void pm_overflow(int irq, struct pt_regs *regs)
+{
+	pm_overflow_handler(irq, regs);
+}
+#endif
diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S
new file mode 100644
index 0000000..2cbb15b
--- /dev/null
+++ b/arch/blackfin/mach-common/lock.S
@@ -0,0 +1,204 @@
+/*
+ * File:         arch/blackfin/mach-common/lock.S
+ * Based on:
+ * Author:       LG Soft India
+ *
+ * Created:      ?
+ * Description:  kernel locks
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/blackfin.h>
+
+.text
+
+#ifdef CONFIG_BLKFIN_CACHE_LOCK
+
+/* When you come here, it is assumed that
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_grab_lock)
+
+	[--SP]=( R7:0,P5:0 );
+
+	P1.H = (IMEM_CONTROL >> 16);
+	P1.L = (IMEM_CONTROL & 0xFFFF);
+	P5.H = (ICPLB_ADDR0 >> 16);
+	P5.L = (ICPLB_ADDR0 & 0xFFFF);
+	P4.H = (ICPLB_DATA0 >> 16);
+	P4.L = (ICPLB_DATA0 & 0xFFFF);
+	R7 = R0;
+
+	/* If the code of interest already resides in the cache
+	 * invalidate the entire cache itself.
+	 * invalidate_entire_icache;
+	 */
+
+	SP += -12;
+	[--SP] = RETS;
+	CALL _invalidate_entire_icache;
+	RETS = [SP++];
+	SP += 12;
+
+	/* Disable the Interrupts*/
+
+	CLI R3;
+
+.LLOCK_WAY:
+
+	/* Way0 - 0xFFA133E0
+	 * Way1 - 0xFFA137E0
+	 * Way2 - 0xFFA13BE0	Total Way Size = 4K
+	 * Way3 - 0xFFA13FE0
+	 */
+
+	/* Procedure Ex. -Set the locks for other ways by setting ILOC[3:1]
+	 * Only Way0 of the instruction cache can now be
+	 * replaced by a new code
+	 */
+
+	R5 = R7;
+	CC = BITTST(R7,0);
+	IF CC JUMP .LCLEAR1;
+	R7 = 0;
+	BITSET(R7,0);
+	JUMP .LDONE1;
+
+.LCLEAR1:
+	R7 = 0;
+	BITCLR(R7,0);
+.LDONE1:	R4 = R7 << 3;
+	R7 = [P1];
+	R7 = R7 | R4;
+	SSYNC;		/* SSYNC required writing to IMEM_CONTROL. */
+	.align 8;
+	[P1] = R7;
+	SSYNC;
+
+	R7 = R5;
+	CC = BITTST(R7,1);
+	IF CC JUMP .LCLEAR2;
+	R7 = 0;
+	BITSET(R7,1);
+	JUMP .LDONE2;
+
+.LCLEAR2:
+	R7 = 0;
+	BITCLR(R7,1);
+.LDONE2:	R4 = R7 << 3;
+	R7 = [P1];
+	R7 = R7 | R4;
+	SSYNC;		/* SSYNC required writing to IMEM_CONTROL. */
+	.align 8;
+	[P1] = R7;
+	SSYNC;
+
+	R7 = R5;
+	CC = BITTST(R7,2);
+	IF CC JUMP .LCLEAR3;
+	R7 = 0;
+	BITSET(R7,2);
+	JUMP .LDONE3;
+.LCLEAR3:
+	R7 = 0;
+	BITCLR(R7,2);
+.LDONE3:	R4 = R7 << 3;
+	R7 = [P1];
+	R7 = R7 | R4;
+	SSYNC;		/* SSYNC required writing to IMEM_CONTROL. */
+	.align 8;
+	[P1] = R7;
+	SSYNC;
+
+
+	R7 = R5;
+	CC = BITTST(R7,3);
+	IF CC JUMP .LCLEAR4;
+	R7 = 0;
+	BITSET(R7,3);
+	JUMP .LDONE4;
+.LCLEAR4:
+	R7 = 0;
+	BITCLR(R7,3);
+.LDONE4:	R4 = R7 << 3;
+	R7 = [P1];
+	R7 = R7 | R4;
+	SSYNC;		/* SSYNC required writing to IMEM_CONTROL. */
+	.align 8;
+	[P1] = R7;
+	SSYNC;
+
+	STI R3;
+
+	( R7:0,P5:0 ) = [SP++];
+
+	RTS;
+
+/* After the execution of critical code, the code is now locked into
+ * the cache way. Now we need to set ILOC.
+ *
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_lock)
+
+	[--SP]=( R7:0,P5:0 );
+
+	P1.H = (IMEM_CONTROL >> 16);
+	P1.L = (IMEM_CONTROL & 0xFFFF);
+
+	/* Disable the Interrupts*/
+	CLI R3;
+
+	R7 = [P1];
+	R2 = 0xFFFFFF87 (X);
+	R7 = R7 & R2;
+	R0 = R0 << 3;
+	R7 = R0 | R7;
+	SSYNC;		/* SSYNC required writing to IMEM_CONTROL. */
+	.align 8;
+	[P1] = R7;
+	SSYNC;
+	/* Renable the Interrupts */
+	STI R3;
+
+	( R7:0,P5:0 ) = [SP++];
+	RTS;
+
+#endif	/* BLKFIN_CACHE_LOCK */
+
+/* Return the ILOC bits of IMEM_CONTROL
+ */
+
+ENTRY(_read_iloc)
+
+	P1.H = (IMEM_CONTROL >> 16);
+	P1.L = (IMEM_CONTROL & 0xFFFF);
+	R1 = 0xF;
+	R0 = [P1];
+	R0 = R0 >> 3;
+	R0 = R0 & R1;
+
+	RTS;
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
new file mode 100644
index 0000000..deb2727
--- /dev/null
+++ b/arch/blackfin/mach-common/pm.c
@@ -0,0 +1,181 @@
+/*
+ * File:         arch/blackfin/mach-common/pm.c
+ * Based on:     arm/mach-omap/pm.c
+ * Author:       Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
+ *
+ * Created:      2001
+ * Description:  Power management for the bfin
+ *
+ * Modified:     Nicolas Pitre - PXA250 support
+ *                Copyright (c) 2002 Monta Vista Software, Inc.
+ *               David Singleton - OMAP1510
+ *                Copyright (c) 2002 Monta Vista Software, Inc.
+ *               Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
+ *                Copyright 2004
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/dpmc.h>
+#include <asm/irq.h>
+
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
+#define WAKEUP_TYPE	PM_WAKE_HIGH
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L
+#define WAKEUP_TYPE	PM_WAKE_LOW
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F
+#define WAKEUP_TYPE	PM_WAKE_FALLING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R
+#define WAKEUP_TYPE	PM_WAKE_RISING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B
+#define WAKEUP_TYPE	PM_WAKE_BOTH_EDGES
+#endif
+
+void bfin_pm_suspend_standby_enter(void)
+{
+#ifdef CONFIG_PM_WAKEUP_BY_GPIO
+	gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
+#endif
+
+#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API)
+	{
+		u32 flags;
+
+		local_irq_save(flags);
+
+		sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/
+
+		gpio_pm_restore();
+
+		bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+
+		local_irq_restore(flags);
+	}
+#endif
+
+#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
+	sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
+	bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+#endif				/* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
+}
+
+
+/*
+ *	bfin_pm_prepare - Do preliminary suspend work.
+ *	@state:		suspend state we're entering.
+ *
+ */
+static int bfin_pm_prepare(suspend_state_t state)
+{
+	int error = 0;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		break;
+	case PM_SUSPEND_MEM:
+		return -ENOTSUPP;
+
+	case PM_SUSPEND_DISK:
+		return -ENOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+
+	return error;
+}
+
+/*
+ *	bfin_pm_enter - Actually enter a sleep state.
+ *	@state:		State we're entering.
+ *
+ */
+static int bfin_pm_enter(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		bfin_pm_suspend_standby_enter();
+		break;
+	case PM_SUSPEND_MEM:
+		return -ENOTSUPP;
+
+	case PM_SUSPEND_DISK:
+		return -ENOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ *	bfin_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 bfin_pm_finish(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		break;
+
+	case PM_SUSPEND_MEM:
+		return -ENOTSUPP;
+
+	case PM_SUSPEND_DISK:
+		return -ENOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct pm_ops bfin_pm_ops = {
+	.pm_disk_mode = PM_DISK_PLATFORM,
+	.prepare = bfin_pm_prepare,
+	.enter = bfin_pm_enter,
+	.finish = bfin_pm_finish,
+};
+
+static int __init bfin_pm_init(void)
+{
+	pm_set_ops(&bfin_pm_ops);
+	return 0;
+}
+
+__initcall(bfin_pm_init);
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
new file mode 100644
index 0000000..2a7202c
--- /dev/null
+++ b/arch/blackfin/mm/Makefile
@@ -0,0 +1,5 @@
+#
+# arch/blackfin/mm/Makefile
+#
+
+obj-y := blackfin_sram.o init.o
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
new file mode 100644
index 0000000..dd0c650
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.c
@@ -0,0 +1,540 @@
+/*
+ * File:         arch/blackfin/mm/blackfin_sram.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  SRAM driver for Blackfin ADSP-BF5xx
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <asm/blackfin.h>
+#include "blackfin_sram.h"
+
+spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
+
+#if CONFIG_L1_MAX_PIECE < 16
+#undef CONFIG_L1_MAX_PIECE
+#define CONFIG_L1_MAX_PIECE        16
+#endif
+
+#if CONFIG_L1_MAX_PIECE > 1024
+#undef CONFIG_L1_MAX_PIECE
+#define CONFIG_L1_MAX_PIECE        1024
+#endif
+
+#define SRAM_SLT_NULL      0
+#define SRAM_SLT_FREE      1
+#define SRAM_SLT_ALLOCATED 2
+
+/* the data structure for L1 scratchpad and DATA SRAM */
+struct l1_sram_piece {
+	void *paddr;
+	int size;
+	int flag;
+};
+
+static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE];
+
+#if L1_DATA_A_LENGTH != 0
+static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+#if L1_DATA_B_LENGTH != 0
+static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+#if L1_CODE_LENGTH != 0
+static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+/* L1 Scratchpad SRAM initialization function */
+void l1sram_init(void)
+{
+	printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
+	       L1_SCRATCH_LENGTH >> 10);
+
+	memset(&l1_ssram, 0x00, sizeof(l1_ssram));
+	l1_ssram[0].paddr = (void*)L1_SCRATCH_START;
+	l1_ssram[0].size = L1_SCRATCH_LENGTH;
+	l1_ssram[0].flag = SRAM_SLT_FREE;
+
+	/* mutex initialize */
+	spin_lock_init(&l1sram_lock);
+}
+
+void l1_data_sram_init(void)
+{
+#if L1_DATA_A_LENGTH != 0
+	printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n",
+	       L1_DATA_A_LENGTH >> 10);
+
+	memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram));
+	l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START +
+		(_ebss_l1 - _sdata_l1);
+	l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
+	l1_data_A_sram[0].flag = SRAM_SLT_FREE;
+#endif
+#if L1_DATA_B_LENGTH != 0
+	printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n",
+	       L1_DATA_B_LENGTH >> 10);
+
+	memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram));
+	l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START;
+	l1_data_B_sram[0].size = L1_DATA_B_LENGTH;
+	l1_data_B_sram[0].flag = SRAM_SLT_FREE;
+#endif
+
+	/* mutex initialize */
+	spin_lock_init(&l1_data_sram_lock);
+}
+
+void l1_inst_sram_init(void)
+{
+#if L1_CODE_LENGTH != 0
+	printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n",
+	       L1_CODE_LENGTH >> 10);
+
+	memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram));
+	l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1);
+	l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
+	l1_inst_sram[0].flag = SRAM_SLT_FREE;
+#endif
+
+	/* mutex initialize */
+	spin_lock_init(&l1_inst_sram_lock);
+}
+
+/* L1 memory allocate function */
+static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count)
+{
+	int i, index = 0;
+	void *addr = NULL;
+
+	if (size <= 0)
+		return NULL;
+
+	/* Align the size */
+	size = (size + 3) & ~3;
+
+	/* not use the good method to match the best slot !!! */
+	/* search an available memeory slot */
+	for (i = 0; i < count; i++) {
+		if ((pfree[i].flag == SRAM_SLT_FREE)
+		    && (pfree[i].size >= size)) {
+			addr = pfree[i].paddr;
+			pfree[i].flag = SRAM_SLT_ALLOCATED;
+			index = i;
+			break;
+		}
+	}
+	if (i >= count)
+		return NULL;
+
+	/* updated the NULL memeory slot !!! */
+	if (pfree[i].size > size) {
+		for (i = 0; i < count; i++) {
+			if (pfree[i].flag == SRAM_SLT_NULL) {
+				pfree[i].flag = SRAM_SLT_FREE;
+				pfree[i].paddr = addr + size;
+				pfree[i].size = pfree[index].size - size;
+				pfree[index].size = size;
+				break;
+			}
+		}
+	}
+
+	return addr;
+}
+
+/* Allocate the largest available block.  */
+static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count,
+				unsigned long *psize)
+{
+	unsigned long best = 0;
+	int i, index = -1;
+	void *addr = NULL;
+
+	/* search an available memeory slot */
+	for (i = 0; i < count; i++) {
+		if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) {
+			addr = pfree[i].paddr;
+			index = i;
+			best = pfree[i].size;
+		}
+	}
+	if (index < 0)
+		return NULL;
+	*psize = best;
+
+	pfree[index].flag = SRAM_SLT_ALLOCATED;
+	return addr;
+}
+
+/* L1 memory free function */
+static int _l1_sram_free(const void *addr,
+			 struct l1_sram_piece *pfree, int count)
+{
+	int i, index = 0;
+
+	/* search the relevant memory slot */
+	for (i = 0; i < count; i++) {
+		if (pfree[i].paddr == addr) {
+			if (pfree[i].flag != SRAM_SLT_ALLOCATED) {
+				/* error log */
+				return -1;
+			}
+			index = i;
+			break;
+		}
+	}
+	if (i >= count)
+		return -1;
+
+	pfree[index].flag = SRAM_SLT_FREE;
+
+	/* link the next address slot */
+	for (i = 0; i < count; i++) {
+		if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr)
+		    && (pfree[i].flag == SRAM_SLT_FREE)) {
+			pfree[i].flag = SRAM_SLT_NULL;
+			pfree[index].size += pfree[i].size;
+			pfree[index].flag = SRAM_SLT_FREE;
+			break;
+		}
+	}
+
+	/* link the last address slot */
+	for (i = 0; i < count; i++) {
+		if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) &&
+		    (pfree[i].flag == SRAM_SLT_FREE)) {
+			pfree[index].flag = SRAM_SLT_NULL;
+			pfree[i].size += pfree[index].size;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int sram_free(const void *addr)
+{
+	if (0) {}
+#if L1_CODE_LENGTH != 0
+	else if (addr >= (void *)L1_CODE_START
+		 && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
+		return l1_inst_sram_free(addr);
+#endif
+#if L1_DATA_A_LENGTH != 0
+	else if (addr >= (void *)L1_DATA_A_START
+		 && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
+		return l1_data_A_sram_free(addr);
+#endif
+#if L1_DATA_B_LENGTH != 0
+	else if (addr >= (void *)L1_DATA_B_START
+		 && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
+		return l1_data_B_sram_free(addr);
+#endif
+	else
+		return -1;
+}
+EXPORT_SYMBOL(sram_free);
+
+void *l1_data_A_sram_alloc(size_t size)
+{
+	unsigned flags;
+	void *addr = NULL;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+	addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
+#endif
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_A_sram_alloc);
+
+int l1_data_A_sram_free(const void *addr)
+{
+	unsigned flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+	ret = _l1_sram_free(addr,
+			   l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
+#else
+	ret = -1;
+#endif
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(l1_data_A_sram_free);
+
+void *l1_data_B_sram_alloc(size_t size)
+{
+#if L1_DATA_B_LENGTH != 0
+	unsigned flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+	addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+#else
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_alloc);
+
+int l1_data_B_sram_free(const void *addr)
+{
+#if L1_DATA_B_LENGTH != 0
+	unsigned flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+	ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+	return ret;
+#else
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_free);
+
+void *l1_data_sram_alloc(size_t size)
+{
+	void *addr = l1_data_A_sram_alloc(size);
+
+	if (!addr)
+		addr = l1_data_B_sram_alloc(size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_alloc);
+
+void *l1_data_sram_zalloc(size_t size)
+{
+	void *addr = l1_data_sram_alloc(size);
+
+	if (addr)
+		memset(addr, 0x00, size);
+
+	return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_zalloc);
+
+int l1_data_sram_free(const void *addr)
+{
+	int ret;
+	ret = l1_data_A_sram_free(addr);
+	if (ret == -1)
+		ret = l1_data_B_sram_free(addr);
+	return ret;
+}
+EXPORT_SYMBOL(l1_data_sram_free);
+
+void *l1_inst_sram_alloc(size_t size)
+{
+#if L1_DATA_A_LENGTH != 0
+	unsigned flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+	addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+	pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
+		 (long unsigned int)addr, size);
+
+	return addr;
+#else
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_alloc);
+
+int l1_inst_sram_free(const void *addr)
+{
+#if L1_CODE_LENGTH != 0
+	unsigned flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+	ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+	return ret;
+#else
+	return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_free);
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc(size_t size)
+{
+	unsigned flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return addr;
+}
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc_max(size_t *psize)
+{
+	unsigned flags;
+	void *addr;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize);
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return addr;
+}
+
+/* L1 Scratchpad memory free function */
+int l1sram_free(const void *addr)
+{
+	unsigned flags;
+	int ret;
+
+	/* add mutex operation */
+	spin_lock_irqsave(&l1sram_lock, flags);
+
+	ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram));
+
+	/* add mutex operation */
+	spin_unlock_irqrestore(&l1sram_lock, flags);
+
+	return ret;
+}
+
+int sram_free_with_lsl(const void *addr)
+{
+	struct sram_list_struct *lsl, **tmp;
+	struct mm_struct *mm = current->mm;
+
+	for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
+		if ((*tmp)->addr == addr)
+			goto found;
+	return -1;
+found:
+	lsl = *tmp;
+	sram_free(addr);
+	*tmp = lsl->next;
+	kfree(lsl);
+
+	return 0;
+}
+EXPORT_SYMBOL(sram_free_with_lsl);
+
+void *sram_alloc_with_lsl(size_t size, unsigned long flags)
+{
+	void *addr = NULL;
+	struct sram_list_struct *lsl = NULL;
+	struct mm_struct *mm = current->mm;
+
+	lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+	if (!lsl)
+		return NULL;
+	memset(lsl, 0, sizeof(*lsl));
+
+	if (flags & L1_INST_SRAM)
+		addr = l1_inst_sram_alloc(size);
+
+	if (addr == NULL && (flags & L1_DATA_A_SRAM))
+		addr = l1_data_A_sram_alloc(size);
+
+	if (addr == NULL && (flags & L1_DATA_B_SRAM))
+		addr = l1_data_B_sram_alloc(size);
+
+	if (addr == NULL) {
+		kfree(lsl);
+		return NULL;
+	}
+	lsl->addr = addr;
+	lsl->length = size;
+	lsl->next = mm->context.sram_list;
+	mm->context.sram_list = lsl;
+	return addr;
+}
+EXPORT_SYMBOL(sram_alloc_with_lsl);
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
new file mode 100644
index 0000000..0fb73b7
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -0,0 +1,38 @@
+/*
+ * File:         arch/blackfin/mm/blackfin_sram.h
+ * Based on:     arch/blackfin/mm/blackfin_sram.c
+ * Author:       Mike Frysinger
+ *
+ * Created:      Aug 2006
+ * Description:  Local prototypes meant for internal use only
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __BLACKFIN_SRAM_H__
+#define __BLACKFIN_SRAM_H__
+
+extern void l1sram_init(void);
+extern void l1_inst_sram_init(void);
+extern void l1_data_sram_init(void);
+extern void *l1sram_alloc(size_t);
+
+#endif
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
new file mode 100644
index 0000000..73f72ab
--- /dev/null
+++ b/arch/blackfin/mm/init.c
@@ -0,0 +1,208 @@
+/*
+ * File:         arch/blackfin/mm/init.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <asm/bfin-global.h>
+#include <asm/uaccess.h>
+#include <asm/l1layout.h>
+#include "blackfin_sram.h"
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+
+static unsigned long empty_bad_page;
+
+unsigned long empty_zero_page;
+
+void show_mem(void)
+{
+	unsigned long i;
+	int free = 0, total = 0, reserved = 0, shared = 0;
+
+	int cached = 0;
+	printk(KERN_INFO "Mem-info:\n");
+	show_free_areas();
+	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(KERN_INFO "%d pages of RAM\n", total);
+	printk(KERN_INFO "%d free pages\n", free);
+	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);
+}
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses  of available kernel virtual memory.
+ */
+void paging_init(void)
+{
+	/*
+	 * make sure start_mem is page aligned,  otherwise bootmem and
+	 * page_alloc get different views og the world
+	 */
+	unsigned long end_mem = memory_end & PAGE_MASK;
+
+	pr_debug("start_mem is %#lx   virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
+
+	/*
+	 * initialize the bad page table and bad page to point
+	 * to a couple of allocated pages
+	 */
+	empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+	empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+	empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+	/*
+	 * Set up SFC/DFC registers (user data space)
+	 */
+	set_fs(KERNEL_DS);
+
+	pr_debug("free_area_init -> start_mem is %#lx   virtual_end is %#lx\n",
+	        PAGE_ALIGN(memory_start), end_mem);
+
+	{
+		unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+
+		zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+#ifdef CONFIG_HIGHMEM
+		zones_size[ZONE_HIGHMEM] = 0;
+#endif
+		free_area_init(zones_size);
+	}
+}
+
+void mem_init(void)
+{
+	unsigned int codek = 0, datak = 0, initk = 0;
+	unsigned long tmp;
+	unsigned int len = _ramend - _rambase;
+	unsigned long start_mem = memory_start;
+	unsigned long end_mem = memory_end;
+
+	end_mem &= PAGE_MASK;
+	high_memory = (void *)end_mem;
+
+	start_mem = PAGE_ALIGN(start_mem);
+	max_mapnr = num_physpages = MAP_NR(high_memory);
+	printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
+
+	/* This will put all memory onto the freelists. */
+	totalram_pages = free_all_bootmem();
+
+	codek = (_etext - _stext) >> 10;
+	datak = (__bss_stop - __bss_start) >> 10;
+	initk = (__init_end - __init_begin) >> 10;
+
+	tmp = nr_free_pages() << PAGE_SHIFT;
+	printk(KERN_INFO
+	     "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
+	     tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
+
+	/* Initialize the blackfin L1 Memory. */
+	l1sram_init();
+	l1_data_sram_init();
+	l1_inst_sram_init();
+
+	/* Allocate this once; never free it.  We assume this gives us a
+	   pointer to the start of L1 scratchpad memory; panic if it
+	   doesn't.  */
+	tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info));
+	if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) {
+		printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n",
+			tmp, (unsigned long)L1_SCRATCH_TASK_INFO);
+		panic("No L1, time to give up\n");
+	}
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	int pages = 0;
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(start));
+		init_page_count(virt_to_page(start));
+		free_page(start);
+		totalram_pages++;
+		pages++;
+	}
+	printk(KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+}
+#endif
+
+void free_initmem(void)
+{
+#ifdef CONFIG_RAMKERNEL
+	unsigned long addr;
+/*
+ *	the following code should be cool even if these sections
+ *	are not page aligned.
+ */
+	addr = PAGE_ALIGN((unsigned long)(__init_begin));
+	/* next to check that the page we free is not a partial page */
+	for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
+	     addr += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(addr));
+		init_page_count(virt_to_page(addr));
+		free_page(addr);
+		totalram_pages++;
+	}
+	printk(KERN_NOTICE
+	       "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
+	       (addr - PAGE_ALIGN((long)__init_begin)) >> 10,
+	       (int)(PAGE_ALIGN((unsigned long)(__init_begin))),
+	       (int)(addr - PAGE_SIZE));
+#endif
+}
diff --git a/arch/blackfin/oprofile/Kconfig b/arch/blackfin/oprofile/Kconfig
new file mode 100644
index 0000000..0a2fd99
--- /dev/null
+++ b/arch/blackfin/oprofile/Kconfig
@@ -0,0 +1,29 @@
+menu "Profiling support"
+depends on EXPERIMENTAL
+
+config PROFILING
+	bool "Profiling support (EXPERIMENTAL)"
+	help
+	  Say Y here to enable the extended profiling support mechanisms used
+	  by profilers such as OProfile.
+
+config OPROFILE
+	tristate "OProfile system profiling (EXPERIMENTAL)"
+	depends on PROFILING
+	help
+	  OProfile is a profiling system capable of profiling the
+	  whole system, include the kernel, kernel modules, libraries,
+	  and applications.
+
+	  If unsure, say N.
+
+config HARDWARE_PM
+	tristate "Hardware Performance Monitor Profiling"
+	depends on PROFILING
+	help
+	  take use of hardware performance monitor to profiling the kernel
+	  and application.
+
+	  If unsure, say N.
+
+endmenu
diff --git a/arch/blackfin/oprofile/Makefile b/arch/blackfin/oprofile/Makefile
new file mode 100644
index 0000000..634e300
--- /dev/null
+++ b/arch/blackfin/oprofile/Makefile
@@ -0,0 +1,14 @@
+#
+# arch/blackfin/oprofile/Makefile
+#
+
+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) common.o
+oprofile-$(CONFIG_HARDWARE_PM) += op_model_bf533.o
diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c
new file mode 100644
index 0000000..009a170
--- /dev/null
+++ b/arch/blackfin/oprofile/common.c
@@ -0,0 +1,168 @@
+/*
+ * File:         arch/blackfin/oprofile/common.c
+ * Based on:     arch/alpha/oprofile/common.c
+ * Author:       Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "op_blackfin.h"
+
+#define BFIN_533_ID  0xE5040003
+#define BFIN_537_ID  0xE5040002
+
+static int pfmon_enabled;
+static struct mutex pfmon_lock;
+
+struct op_bfin533_model *model;
+
+struct op_counter_config ctr[OP_MAX_COUNTER];
+
+static int op_bfin_setup(void)
+{
+	int ret;
+
+	/* Pre-compute the values to stuff in the hardware registers.  */
+	spin_lock(&oprofilefs_lock);
+	ret = model->reg_setup(ctr);
+	spin_unlock(&oprofilefs_lock);
+
+	return ret;
+}
+
+static void op_bfin_shutdown(void)
+{
+#if 0
+	/* what is the difference between shutdown and stop? */
+#endif
+}
+
+static int op_bfin_start(void)
+{
+	int ret = -EBUSY;
+
+	printk(KERN_INFO "KSDBG:in %s\n", __FUNCTION__);
+	mutex_lock(&pfmon_lock);
+	if (!pfmon_enabled) {
+		ret = model->start(ctr);
+		pfmon_enabled = !ret;
+	}
+	mutex_unlock(&pfmon_lock);
+
+	return ret;
+}
+
+static void op_bfin_stop(void)
+{
+	mutex_lock(&pfmon_lock);
+	if (pfmon_enabled) {
+		model->stop();
+		pfmon_enabled = 0;
+	}
+	mutex_unlock(&pfmon_lock);
+}
+
+static int op_bfin_create_files(struct super_block *sb, struct dentry *root)
+{
+	int i;
+
+	for (i = 0; i < model->num_counters; ++i) {
+		struct dentry *dir;
+		char buf[3];
+		printk(KERN_INFO "Oprofile: creating files... \n");
+
+		snprintf(buf, sizeof buf, "%d", i);
+		dir = oprofilefs_mkdir(sb, root, buf);
+
+		oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
+		oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
+		oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
+		/*
+		 * We dont support per counter user/kernel selection, but
+		 * we leave the entries because userspace expects them
+		 */
+		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
+		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
+		oprofilefs_create_ulong(sb, dir, "unit_mask",
+					&ctr[i].unit_mask);
+	}
+
+	return 0;
+}
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+#ifdef CONFIG_HARDWARE_PM
+	unsigned int dspid;
+
+	mutex_init(&pfmon_lock);
+
+	dspid = bfin_read_DSPID();
+
+	printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid);
+
+	switch (dspid) {
+	case BFIN_533_ID:
+		model = &op_model_bfin533;
+		model->num_counters = 2;
+		break;
+	case BFIN_537_ID:
+		model = &op_model_bfin533;
+		model->num_counters = 2;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ops->cpu_type = model->name;
+	ops->create_files = op_bfin_create_files;
+	ops->setup = op_bfin_setup;
+	ops->shutdown = op_bfin_shutdown;
+	ops->start = op_bfin_start;
+	ops->stop = op_bfin_stop;
+
+	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
+	       ops->cpu_type);
+
+	return 0;
+#else
+	return -1;
+#endif
+}
+
+void oprofile_arch_exit(void)
+{
+}
diff --git a/arch/blackfin/oprofile/op_blackfin.h b/arch/blackfin/oprofile/op_blackfin.h
new file mode 100644
index 0000000..f88f446
--- /dev/null
+++ b/arch/blackfin/oprofile/op_blackfin.h
@@ -0,0 +1,98 @@
+/*
+ * File:         arch/blackfin/oprofile/op_blackfin.h
+ * Based on:
+ * Author:       Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef OP_BLACKFIN_H
+#define OP_BLACKFIN_H 1
+
+#define OP_MAX_COUNTER 2
+
+#include <asm/blackfin.h>
+
+/* Per-counter configuration as set via oprofilefs.  */
+struct op_counter_config {
+	unsigned long valid;
+	unsigned long enabled;
+	unsigned long event;
+	unsigned long count;
+	unsigned long kernel;
+	unsigned long user;
+	unsigned long unit_mask;
+};
+
+/* System-wide configuration as set via oprofilefs.  */
+struct op_system_config {
+	unsigned long enable_kernel;
+	unsigned long enable_user;
+};
+
+/* Per-arch configuration */
+struct op_bfin533_model {
+	int (*reg_setup) (struct op_counter_config *);
+	int (*start) (struct op_counter_config *);
+	void (*stop) (void);
+	int num_counters;
+	char *name;
+};
+
+extern struct op_bfin533_model op_model_bfin533;
+
+static inline unsigned int ctr_read(void)
+{
+	unsigned int tmp;
+
+	tmp = bfin_read_PFCTL();
+	__builtin_bfin_csync();
+
+	return tmp;
+}
+
+static inline void ctr_write(unsigned int val)
+{
+	bfin_write_PFCTL(val);
+	__builtin_bfin_csync();
+}
+
+static inline void count_read(unsigned int *count)
+{
+	count[0] = bfin_read_PFCNTR0();
+	count[1] = bfin_read_PFCNTR1();
+	__builtin_bfin_csync();
+}
+
+static inline void count_write(unsigned int *count)
+{
+	bfin_write_PFCNTR0(count[0]);
+	bfin_write_PFCNTR1(count[1]);
+	__builtin_bfin_csync();
+}
+
+extern int pm_overflow_handler(int irq, struct pt_regs *regs);
+
+#endif
diff --git a/arch/blackfin/oprofile/op_model_bf533.c b/arch/blackfin/oprofile/op_model_bf533.c
new file mode 100644
index 0000000..b7a20a0
--- /dev/null
+++ b/arch/blackfin/oprofile/op_model_bf533.c
@@ -0,0 +1,161 @@
+/*
+ * File:         arch/blackfin/oprofile/op_model_bf533.c
+ * Based on:
+ * Author:       Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "op_blackfin.h"
+
+#define PM_ENABLE 0x01;
+#define PM_CTL1_ENABLE  0x18
+#define PM_CTL0_ENABLE  0xC000
+#define COUNT_EDGE_ONLY 0x3000000
+
+static int oprofile_running;
+
+static unsigned curr_pfctl, curr_count[2];
+
+static int bfin533_reg_setup(struct op_counter_config *ctr)
+{
+	unsigned int pfctl = ctr_read();
+	unsigned int count[2];
+
+	/* set Blackfin perf monitor regs with ctr */
+	if (ctr[0].enabled) {
+		pfctl |= (PM_CTL0_ENABLE | ((char)ctr[0].event << 5));
+		count[0] = 0xFFFFFFFF - ctr[0].count;
+		curr_count[0] = count[0];
+	}
+	if (ctr[1].enabled) {
+		pfctl |= (PM_CTL1_ENABLE | ((char)ctr[1].event << 16));
+		count[1] = 0xFFFFFFFF - ctr[1].count;
+		curr_count[1] = count[1];
+	}
+
+	pr_debug("ctr[0].enabled=%d,ctr[1].enabled=%d,ctr[0].event<<5=0x%x,ctr[1].event<<16=0x%x\n", ctr[0].enabled, ctr[1].enabled, ctr[0].event << 5, ctr[1].event << 16);
+	pfctl |= COUNT_EDGE_ONLY;
+	curr_pfctl = pfctl;
+
+	pr_debug("write 0x%x to pfctl\n", pfctl);
+	ctr_write(pfctl);
+	count_write(count);
+
+	return 0;
+}
+
+static int bfin533_start(struct op_counter_config *ctr)
+{
+	unsigned int pfctl = ctr_read();
+
+	pfctl |= PM_ENABLE;
+	curr_pfctl = pfctl;
+
+	ctr_write(pfctl);
+
+	oprofile_running = 1;
+	pr_debug("start oprofile counter \n");
+
+	return 0;
+}
+
+static void bfin533_stop(void)
+{
+	int pfctl;
+
+	pfctl = ctr_read();
+	pfctl &= ~PM_ENABLE;
+	/* freeze counters */
+	ctr_write(pfctl);
+
+	oprofile_running = 0;
+	pr_debug("stop oprofile counter \n");
+}
+
+static int get_kernel(void)
+{
+	int ipend, is_kernel;
+
+	ipend = bfin_read_IPEND();
+
+	/* test bit 15 */
+	is_kernel = ((ipend & 0x8000) != 0);
+
+	return is_kernel;
+}
+
+int pm_overflow_handler(int irq, struct pt_regs *regs)
+{
+	int is_kernel;
+	int i, cpu;
+	unsigned int pc, pfctl;
+	unsigned int count[2];
+
+	pr_debug("get interrupt in %s\n", __FUNCTION__);
+	if (oprofile_running == 0) {
+		pr_debug("error: entering interrupt when oprofile is stopped.\n\r");
+		return -1;
+	}
+
+	is_kernel = get_kernel();
+	cpu = smp_processor_id();
+	pc = regs->pc;
+	pfctl = ctr_read();
+
+	/* read the two event counter regs */
+	count_read(count);
+
+	/* if the counter overflows, add sample to oprofile buffer */
+	for (i = 0; i < 2; ++i) {
+		if (oprofile_running) {
+			oprofile_add_sample(regs, i);
+		}
+	}
+
+	/* reset the perfmon counter */
+	ctr_write(curr_pfctl);
+	count_write(curr_count);
+	return 0;
+}
+
+struct op_bfin533_model op_model_bfin533 = {
+	.reg_setup = bfin533_reg_setup,
+	.start = bfin533_start,
+	.stop = bfin533_stop,
+	.num_counters = 2,
+	.name = "blackfin/bf533"
+};
diff --git a/arch/blackfin/oprofile/timer_int.c b/arch/blackfin/oprofile/timer_int.c
new file mode 100644
index 0000000..8fba16c
--- /dev/null
+++ b/arch/blackfin/oprofile/timer_int.c
@@ -0,0 +1,74 @@
+/*
+ * File:         arch/blackfin/oprofile/timer_int.c
+ * Based on:
+ * Author:       Michael Kang
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/oprofile.h>
+
+#include <asm/ptrace.h>
+
+static void enable_sys_timer0()
+{
+}
+static void disable_sys_timer0()
+{
+}
+
+static irqreturn_t sys_timer0_int_handler(int irq, void *dev_id,
+					  struct pt_regs *regs)
+{
+	oprofile_add_sample(regs, 0);
+	return IRQ_HANDLED;
+}
+
+static int sys_timer0_start(void)
+{
+	enable_sys_timer0();
+	return request_irq(IVG11, sys_timer0_int_handler, 0, "sys_timer0", NULL);
+}
+
+static void sys_timer0_stop(void)
+{
+	disable_sys_timer();
+}
+
+int __init sys_timer0_init(struct oprofile_operations *ops)
+{
+	extern int nmi_active;
+
+	if (nmi_active <= 0)
+		return -ENODEV;
+
+	ops->start = timer_start;
+	ops->stop = timer_stop;
+	ops->cpu_type = "timer";
+	printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
+	return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index 961c0d5..fd2129a 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -6,7 +6,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 19bcad0..41d4a5f 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c
index 70d3bf0..832fc63 100644
--- a/arch/cris/arch-v32/drivers/pci/dma.c
+++ b/arch/cris/arch-v32/drivers/pci/dma.c
@@ -76,7 +76,7 @@ int dma_declare_coherent_memory(struct d
 {
 	void __iomem *mem_base;
 	int pages = size >> PAGE_SHIFT;
-	int bitmap_size = (pages + 31)/32;
+	int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
 
 	if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
 		goto out;
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index 5daeb6f..79e1e4c 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -603,23 +603,8 @@ #endif
 
 #ifdef CONFIG_PROC_FS
 static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-                       ,int *eof, void *data_unused
-#else
-                        ,int unused
-#endif
-                               );
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused);
 static struct proc_dir_entry *fasttimer_proc_entry;
-#else
-static struct proc_dir_entry fasttimer_proc_entry =
-{
-  0, 9, "fasttimer",
-  S_IFREG | S_IRUGO, 1, 0, 0,
-  0, NULL /* ops -- default to array */,
-  &proc_fasttimer_read /* get_info */,
-};
-#endif
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_PROC_FS
@@ -628,12 +613,7 @@ #ifdef CONFIG_PROC_FS
 #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
 
 static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-                       ,int *eof, void *data_unused
-#else
-                        ,int unused
-#endif
-                               )
+                       ,int *eof, void *data_unused)
 {
   unsigned long flags;
   int i = 0;
@@ -808,9 +788,7 @@ #endif
 
   memcpy(buf, bigbuf + offset, len);
   *start = buf;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
   *eof = 1;
-#endif
 
   return len;
 }
@@ -974,12 +952,8 @@ void fast_timer_init(void)
     printk("fast_timer_init()\n");
 
 #ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
    if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
      fasttimer_proc_entry->read_proc = proc_fasttimer_read;
-#else
-    proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
-#endif
 #endif /* PROC_FS */
     if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED,
                    "fast timer int", NULL))
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 82cf2e3..d4d57b7 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -6,7 +6,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S
index e124fcd..dfa25e1 100644
--- a/arch/cris/arch-v32/vmlinux.lds.S
+++ b/arch/cris/arch-v32/vmlinux.lds.S
@@ -91,6 +91,7 @@ SECTIONS
 	}
 	SECURITY_INIT
 
+	. =  ALIGN (8192);
 	__per_cpu_start = .;
 	.data.percpu  : { *(.data.percpu) }
 	__per_cpu_end = .;
diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c
index 1f20c16..105bb5e 100644
--- a/arch/cris/kernel/crisksyms.c
+++ b/arch/cris/kernel/crisksyms.c
@@ -4,7 +4,6 @@ #include <linux/elfcore.h>
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/pm.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c
index 4cfcae6..aad0a9e 100644
--- a/arch/cris/kernel/profile.c
+++ b/arch/cris/kernel/profile.c
@@ -15,39 +15,47 @@ static int prof_running = 0;
 void
 cris_profile_sample(struct pt_regs* regs)
 {
-  if (!prof_running)
-    return;
-  if (user_mode(regs))
-    *(unsigned int*)sample_buffer_pos = current->pid;
-  else
-    *(unsigned int*)sample_buffer_pos = 0;
-  *(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs);
-  sample_buffer_pos += 8;
-  if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE)
-    sample_buffer_pos = sample_buffer;
+	if (!prof_running)
+		return;
+
+	if (user_mode(regs))
+		*(unsigned int*)sample_buffer_pos = current->pid;
+	else
+		*(unsigned int*)sample_buffer_pos = 0;
+
+	*(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs);
+	sample_buffer_pos += 8;
+
+	if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE)
+		sample_buffer_pos = sample_buffer;
 }
 
 static ssize_t
-read_cris_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+read_cris_profile(struct file *file, char __user *buf,
+		  size_t count, loff_t *ppos)
 {
-  unsigned long p = *ppos;
-  if (p > SAMPLE_BUFFER_SIZE)
-    return 0;
-  if (p + count > SAMPLE_BUFFER_SIZE)
-    count = SAMPLE_BUFFER_SIZE - p;
-  if (copy_to_user(buf, sample_buffer + p,count))
+	unsigned long p = *ppos;
+
+	if (p > SAMPLE_BUFFER_SIZE)
+		return 0;
+
+	if (p + count > SAMPLE_BUFFER_SIZE)
+		count = SAMPLE_BUFFER_SIZE - p;
+	if (copy_to_user(buf, sample_buffer + p,count))
 		return -EFAULT;
-  memset(sample_buffer + p, 0, count);
-  *ppos += count;
-  return count;
+
+	memset(sample_buffer + p, 0, count);
+	*ppos += count;
+
+	return count;
 }
 
 static ssize_t
 write_cris_profile(struct file *file, const char __user *buf,
-              size_t count, loff_t *ppos)
+		   size_t count, loff_t *ppos)
 {
-  sample_buffer_pos = sample_buffer;
-  memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE);
+	sample_buffer_pos = sample_buffer;
+	memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE);
 }
 
 static const struct file_operations cris_proc_profile_operations = {
@@ -58,16 +66,23 @@ static const struct file_operations cris
 static int
 __init init_cris_profile(void)
 {
-  struct proc_dir_entry *entry;
-  sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
-  sample_buffer_pos = sample_buffer;
-  entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
-  if (entry) {
-    entry->proc_fops = &cris_proc_profile_operations;
-    entry->size = SAMPLE_BUFFER_SIZE;
-  }
-  prof_running = 1;
-  return 0;
+	struct proc_dir_entry *entry;
+
+	sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
+	if (!sample_buffer) {
+		return -ENOMEM;
+	}
+
+	sample_buffer_pos = sample_buffer;
+
+	entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
+	if (entry) {
+		entry->proc_fops = &cris_proc_profile_operations;
+		entry->size = SAMPLE_BUFFER_SIZE;
+	}
+	prof_running = 1;
+
+	return 0;
 }
 
 __initcall(init_cris_profile);
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index 2b6363c..1085d03 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -67,7 +67,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index cea2374..eed6943 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -53,6 +53,10 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default y
 
+config ARCH_USES_SLAB_PAGE_STRUCT
+	bool
+	default y
+
 mainmenu "Fujitsu FR-V Kernel Configuration"
 
 source "init/Kconfig"
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
index 87f360a..c7e59dc 100644
--- a/arch/frv/kernel/irq.c
+++ b/arch/frv/kernel/irq.c
@@ -18,7 +18,6 @@ #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/irq.h>
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index fcff819..ce88fb9 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -14,7 +14,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/frv/kernel/semaphore.c b/arch/frv/kernel/semaphore.c
index f278cdf..8e182ce 100644
--- a/arch/frv/kernel/semaphore.c
+++ b/arch/frv/kernel/semaphore.c
@@ -19,7 +19,7 @@ struct sem_waiter {
 	struct task_struct	*task;
 };
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 void semtrace(struct semaphore *sem, const char *str)
 {
 	if (sem->debug)
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 85baeae..d64bcaf 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c
index c4d4348..26b3df3 100644
--- a/arch/frv/kernel/sys_frv.c
+++ b/arch/frv/kernel/sys_frv.c
@@ -14,7 +14,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 97910e0..28eae97 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -57,6 +57,7 @@ #endif
   __alt_instructions_end = .;
  .altinstr_replacement : { *(.altinstr_replacement) }
 
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c
index 9477ccc..cac2c01 100644
--- a/arch/frv/mm/elf-fdpic.c
+++ b/arch/frv/mm/elf-fdpic.c
@@ -64,6 +64,10 @@ unsigned long arch_get_unmapped_area(str
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	/* handle MAP_FIXED */
+	if (flags & MAP_FIXED)
+		return addr;
+
 	/* only honour a hint if we're not going to clobber something doing so */
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c
index 19b13be..598a26a 100644
--- a/arch/frv/mm/pgalloc.c
+++ b/arch/frv/mm/pgalloc.c
@@ -151,9 +151,7 @@ void __init pgtable_cache_init(void)
 	pgd_cache = kmem_cache_create("pgd",
 				      PTRS_PER_PGD * sizeof(pgd_t),
 				      PTRS_PER_PGD * sizeof(pgd_t),
-				      0,
+				      SLAB_PANIC,
 				      pgd_ctor,
 				      pgd_dtor);
-	if (!pgd_cache)
-		panic("pgtable_cache_init(): Cannot create pgd cache");
 }
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 1734d96..618dbad 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -49,10 +49,18 @@ config GENERIC_HWEIGHT
 	bool
 	default y
 
+config GENERIC_HARDIRQS
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
 
+config GENERIC_TIME
+	bool
+	default y
+
 config TIME_LOW_RES
 	bool
 	default y
diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile
index 40b3f56..b2d896a 100644
--- a/arch/h8300/Makefile
+++ b/arch/h8300/Makefile
@@ -41,7 +41,7 @@ LDFLAGS += $(ldflags-y)
 CROSS_COMPILE = h8300-elf-
 LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(CFLAGS) -print-libgcc-file-name)
 
-head-y := arch/$(ARCH)/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o
+head-y := arch/$(ARCH)/platform/$(PLATFORM)/$(BOARD)/crt0_$(MODEL).o
 
 core-y	+= arch/$(ARCH)/kernel/ \
 	   arch/$(ARCH)/mm/
diff --git a/arch/h8300/boot/Makefile b/arch/h8300/boot/Makefile
index 65086d9..0bb62e0 100644
--- a/arch/h8300/boot/Makefile
+++ b/arch/h8300/boot/Makefile
@@ -1,12 +1,22 @@
 # arch/h8300/boot/Makefile
 
-targets := vmlinux.srec vmlinux.bin
+targets := vmlinux.srec vmlinux.bin zImage
+subdir- := compressed
 
 OBJCOPYFLAGS_vmlinux.srec := -Osrec
 OBJCOPYFLAGS_vmlinux.bin  := -Obinary
+OBJCOPYFLAGS_zImage := -O binary -R .note -R .comment -R .stab -R .stabstr -S
 
 $(obj)/vmlinux.srec $(obj)/vmlinux.bin:  vmlinux FORCE
 	$(call if_changed,objcopy)
 	@echo '  Kernel: $@ is ready'
 
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+	$(call if_changed,objcopy)
+	@echo 'Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
 CLEAN_FILES += arch/$(ARCH)/vmlinux.bin arch/$(ARCH)/vmlinux.srec
+
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
new file mode 100644
index 0000000..71aac82
--- /dev/null
+++ b/arch/h8300/boot/compressed/Makefile
@@ -0,0 +1,37 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS	:= -traditional
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+# Assign dummy values if these 2 variables are not defined,
+# in order to suppress error message.
+#
+CONFIG_MEMORY_START     ?= 0x00400000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00400000
+IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
+
+LDFLAGS_vmlinux := -T $(obj)/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+	$(call if_changed,ld)
+	@:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+	$(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300 -T
+OBJCOPYFLAGS := -O binary
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+	$(call if_changed,ld)
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
new file mode 100644
index 0000000..b8e90d1
--- /dev/null
+++ b/arch/h8300/boot/compressed/head.S
@@ -0,0 +1,47 @@
+/*
+ *  linux/arch/h8300/boot/compressed/head.S
+ *
+ *  Copyright (C) 2006 Yoshinori Sato
+ */
+
+.h8300h
+#include <linux/linkage.h>
+
+#define SRAM_START 0xff4000
+
+	.section	.text.startup
+	.global	startup
+startup:
+	mov.l	#SRAM_START+0x8000, sp
+	mov.l	#__sbss, er0
+	mov.l	#__ebss, er1
+	sub.l	er0, er1
+	shlr	er1
+	shlr	er1
+	sub.l	er2, er2
+1:
+	mov.l	er2, @er0
+	adds	#4, er0
+	dec.l	#1, er1
+	bne	1b
+	jsr	@_decompress_kernel
+	jmp	@0x400000
+
+	.align	9
+fake_headers_as_bzImage:
+	.word	0
+	.ascii	"HdrS"		; header signature
+	.word	0x0202		; header version number (>= 0x0105)
+				; or else old loadlin-1.5 will fail)
+	.word	0		; default_switch
+	.word	0		; SETUPSEG
+	.word	0x1000
+	.word	0		; pointing to kernel version string
+	.byte	0		; = 0, old one (LILO, Loadlin,
+				; 0xTV: T=0 for LILO
+				;       V = version
+	.byte	1		; Load flags bzImage=1
+	.word	0x8000		; size to move, when setup is not
+	.long	0x100000	; 0x100000 = default for big kernel
+	.long	0		; address of loaded ramdisk image
+	.long	0		; its size in bytes
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
new file mode 100644
index 0000000..8450745
--- /dev/null
+++ b/arch/h8300/boot/compressed/misc.c
@@ -0,0 +1,219 @@
+/*
+ * arch/h8300/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for h8300 by Yoshinori Sato 2006
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n)     memset ((s), 0, (n))
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000		/* Window size must be at least 32k, */
+				/* and a power of two */
+
+static uch *inbuf;	     /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+static unsigned insize = 0;  /* valid bytes in inbuf */
+static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+int puts(const char *);
+
+extern int _text;		/* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE             0x10000
+
+#include "../../../../lib/inflate.c"
+
+#define SCR *((volatile unsigned char *)0xffff8a)
+#define TDR *((volatile unsigned char *)0xffff8b)
+#define SSR *((volatile unsigned char *)0xffff8c)
+
+static void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error");
+	if (free_mem_ptr == 0) error("Memory error");
+
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	if (free_mem_ptr >= free_mem_end_ptr)
+		error("Out of memory");
+
+	return p;
+}
+
+static void free(void *where)
+{	/* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+	*ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+	free_mem_ptr = (long) *ptr;
+}
+
+int puts(const char *s)
+{
+	return 0;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+	return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+	return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+	if (insize != 0) {
+		error("ran out of input data");
+	}
+
+	inbuf = input_data;
+	insize = input_len;
+	inptr = 1;
+	return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+
+    in = window;
+    out = &output_data[output_ptr];
+    for (n = 0; n < outcnt; n++) {
+	    ch = *out++ = *in++;
+	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted");
+
+	while(1);	/* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack [STACK_SIZE];
+long* stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+	output_data = 0;
+	output_ptr = (unsigned long)0x400000;
+	free_mem_ptr = (unsigned long)&_end;
+	free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+	makecrc();
+	puts("Uncompressing Linux... ");
+	gunzip();
+	puts("Ok, booting the kernel.\n");
+}
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
index 4edbc2e..ccc1a7f 100644
--- a/arch/h8300/kernel/Makefile
+++ b/arch/h8300/kernel/Makefile
@@ -4,10 +4,8 @@ #
 
 extra-y := vmlinux.lds
 
-obj-y := process.o traps.o ptrace.o ints.o \
+obj-y := process.o traps.o ptrace.o irq.o \
 	 sys_h8300.o time.o semaphore.o signal.o \
-         setup.o gpio.o init_task.o syscalls.o devres.o
-
-devres-y = ../../../kernel/irq/devres.o
+         setup.o gpio.o init_task.o syscalls.o
 
 obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o 
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
new file mode 100644
index 0000000..43d21e9
--- /dev/null
+++ b/arch/h8300/kernel/irq.c
@@ -0,0 +1,211 @@
+/*
+ * linux/arch/h8300/kernel/irq.c
+ *
+ * Copyright 2007 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/errno.h>
+
+/*#define DEBUG*/
+
+extern unsigned long *interrupt_redirect_table;
+extern const int h8300_saved_vectors[];
+extern const unsigned long h8300_trap_table[];
+int h8300_enable_irq_pin(unsigned int irq);
+void h8300_disable_irq_pin(unsigned int irq);
+
+#define CPU_VECTOR ((unsigned long *)0x000000)
+#define ADDR_MASK (0xffffff)
+
+static inline int is_ext_irq(unsigned int irq)
+{
+	return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS));
+}
+
+static void h8300_enable_irq(unsigned int irq)
+{
+	if (is_ext_irq(irq))
+		IER_REGS |= 1 << (irq - EXT_IRQ0);
+}
+
+static void h8300_disable_irq(unsigned int irq)
+{
+	if (is_ext_irq(irq))
+		IER_REGS &= ~(1 << (irq - EXT_IRQ0));
+}
+
+static void h8300_end_irq(unsigned int irq)
+{
+}
+
+static unsigned int h8300_startup_irq(unsigned int irq)
+{
+	if (is_ext_irq(irq))
+		return h8300_enable_irq_pin(irq);
+	else
+		return 0;
+}
+
+static void h8300_shutdown_irq(unsigned int irq)
+{
+	if (is_ext_irq(irq))
+		h8300_disable_irq_pin(irq);
+}
+
+/*
+ * h8300 interrupt controler implementation
+ */
+struct irq_chip h8300irq_chip = {
+	.name		= "H8300-INTC",
+	.startup	= h8300_startup_irq,
+	.shutdown	= h8300_shutdown_irq,
+	.enable		= h8300_enable_irq,
+	.disable	= h8300_disable_irq,
+	.ack		= NULL,
+	.end		= h8300_end_irq,
+};
+
+void ack_bad_irq(unsigned int irq)
+{
+	printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+#if defined(CONFIG_RAMKERNEL)
+static unsigned long __init *get_vector_address(void)
+{
+	unsigned long *rom_vector = CPU_VECTOR;
+	unsigned long base,tmp;
+	int vec_no;
+
+	base = rom_vector[EXT_IRQ0] & ADDR_MASK;
+
+	/* check romvector format */
+	for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
+		if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
+			return NULL;
+	}
+
+	/* ramvector base address */
+	base -= EXT_IRQ0*4;
+
+	/* writerble check */
+	tmp = ~(*(volatile unsigned long *)base);
+	(*(volatile unsigned long *)base) = tmp;
+	if ((*(volatile unsigned long *)base) != tmp)
+		return NULL;
+	return (unsigned long *)base;
+}
+
+static void __init setup_vector(void)
+{
+	int i;
+	unsigned long *ramvec,*ramvec_p;
+	const unsigned long *trap_entry;
+	const int *saved_vector;
+
+	ramvec = get_vector_address();
+	if (ramvec == NULL)
+		panic("interrupt vector serup failed.");
+	else
+		printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec);
+
+	/* create redirect table */
+	ramvec_p = ramvec;
+	trap_entry = h8300_trap_table;
+	saved_vector = h8300_saved_vectors;
+	for ( i = 0; i < NR_IRQS; i++) {
+		if (i == *saved_vector) {
+			ramvec_p++;
+			saved_vector++;
+		} else {
+			if ( i < NR_TRAPS ) {
+				if (*trap_entry)
+					*ramvec_p = VECTOR(*trap_entry);
+				ramvec_p++;
+				trap_entry++;
+			} else
+				*ramvec_p++ = REDIRECT(interrupt_entry);
+		}
+	}
+	interrupt_redirect_table = ramvec;
+#ifdef DEBUG
+	ramvec_p = ramvec;
+	for (i = 0; i < NR_IRQS; i++) {
+		if ((i % 8) == 0)
+			printk(KERN_DEBUG "\n%p: ",ramvec_p);
+		printk(KERN_DEBUG "%p ",*ramvec_p);
+		ramvec_p++;
+	}
+	printk(KERN_DEBUG "\n");
+#endif
+}
+#else
+#define setup_vector() do { } while(0)
+#endif
+
+void __init init_IRQ(void)
+{
+	int c;
+
+	setup_vector();
+
+	for (c = 0; c < NR_IRQS; c++) {
+		irq_desc[c].status = IRQ_DISABLED;
+		irq_desc[c].action = NULL;
+		irq_desc[c].depth = 1;
+		irq_desc[c].chip = &h8300irq_chip;
+	}
+}
+
+asmlinkage void do_IRQ(int irq)
+{
+	irq_enter();
+	__do_IRQ(irq);
+	irq_exit();
+}
+
+#if defined(CONFIG_PROC_FS)
+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_puts(p, "           CPU0");
+
+	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);
+		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)
+			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/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index f603137..8f2411d 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -19,7 +19,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c
index 313cd80..b2e86d0 100644
--- a/arch/h8300/kernel/setup.c
+++ b/arch/h8300/kernel/setup.c
@@ -33,10 +33,7 @@ #include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
-
-#ifdef CONFIG_BLK_DEV_INITRD
 #include <asm/pgtable.h>
-#endif
 
 #if defined(__H8300H__)
 #define CPU "H8/300H"
diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c
index 302a2df..11ba75a 100644
--- a/arch/h8300/kernel/sys_h8300.c
+++ b/arch/h8300/kernel/sys_h8300.c
@@ -10,7 +10,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index d1ef615..3306382 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -44,7 +44,7 @@ static void timer_interrupt(int irq, voi
 #ifndef CONFIG_SMP
 	update_process_times(user_mode(regs));
 #endif
-	profile_tick(CPU_PROFILING, regs);
+	profile_tick(CPU_PROFILING);
 }
 
 void time_init(void)
@@ -66,55 +66,3 @@ void time_init(void)
 
 	platform_timer_setup(timer_interrupt);
 }
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-	unsigned long usec, sec;
-
-	read_lock_irqsave(&xtime_lock, flags);
-	usec = 0;
-	sec = xtime.tv_sec;
-	usec += (xtime.tv_nsec / 1000);
-	read_unlock_irqrestore(&xtime_lock, 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)
-{
-	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-		return -EINVAL;
-
-	write_lock_irq(&xtime_lock);
-	/* This is revolting. We need to set the xtime.tv_usec
-	 * 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!
-	 */
-	while (tv->tv_nsec < 0) {
-		tv->tv_nsec += NSEC_PER_SEC;
-		tv->tv_sec--;
-	}
-
-	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_nsec = tv->tv_nsec;
-	ntp_clear();
-	write_sequnlock_irq(&xtime_lock);
-	clock_was_set();
-	return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
diff --git a/arch/h8300/mm/kmap.c b/arch/h8300/mm/kmap.c
index 26ab172..5c7af09 100644
--- a/arch/h8300/mm/kmap.c
+++ b/arch/h8300/mm/kmap.c
@@ -24,12 +24,14 @@ #include <asm/system.h>
 
 #undef DEBUG
 
+#define VIRT_OFFSET (0x01000000)
+
 /*
  * Map some physical address range into the kernel address space.
  */
 void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
 {
-	return (void *)physaddr;
+	return (void *)(physaddr + VIRT_OFFSET);
 }
 
 /*
diff --git a/arch/h8300/platform/h8300h/Makefile b/arch/h8300/platform/h8300h/Makefile
index 5d42c77..b24ea08 100644
--- a/arch/h8300/platform/h8300h/Makefile
+++ b/arch/h8300/platform/h8300h/Makefile
@@ -4,4 +4,4 @@ #
 # Reuse any files we can from the H8/300H
 #
 
-obj-y := entry.o ints_h8300h.o ptrace_h8300h.o
+obj-y := entry.o irq_pin.o ptrace_h8300h.o
diff --git a/arch/h8300/platform/h8300h/entry.S b/arch/h8300/platform/h8300h/entry.S
index d2dea24..f86ac3b 100644
--- a/arch/h8300/platform/h8300h/entry.S
+++ b/arch/h8300/platform/h8300h/entry.S
@@ -30,12 +30,12 @@ #include <asm/errno.h>
 	mov.l	er0,@-sp
 
 	stc	ccr,r0l				/* check kernel mode */
-	orc	#0x10,ccr
 	btst	#4,r0l
 	bne	5f
 
 	mov.l	sp,@SYMBOL_NAME(sw_usp)		/* user mode */
 	mov.l	@sp,er0
+	orc	#0x10,ccr
 	mov.l	@SYMBOL_NAME(sw_ksp),sp
 	sub.l	#(LRET-LORIG),sp		/* allocate LORIG - LRET */ 
 	mov.l	er0,@-sp
@@ -165,7 +165,7 @@ #endif
 	dec.l	#1,er0
 	mov.l	sp,er1
 	subs	#4,er1				/* adjust ret_pc */
-	jsr	@SYMBOL_NAME(process_int)
+	jsr	@SYMBOL_NAME(do_IRQ)
 	mov.l	@SYMBOL_NAME(irq_stat)+CPUSTAT_SOFTIRQ_PENDING,er0
 	beq	1f
 	jsr	@SYMBOL_NAME(do_softirq)
diff --git a/arch/h8300/platform/h8300h/generic/Makefile b/arch/h8300/platform/h8300h/generic/Makefile
index b6ea768..32b964a 100644
--- a/arch/h8300/platform/h8300h/generic/Makefile
+++ b/arch/h8300/platform/h8300h/generic/Makefile
@@ -2,5 +2,5 @@ #
 # Makefile for the linux kernel.
 #
 
+extra-y :=  crt0_$(MODEL).o
 obj-y := timer.o
-extra-y =  crt0_$(MODEL).o
diff --git a/arch/h8300/platform/h8300h/ints_h8300h.c b/arch/h8300/platform/h8300h/ints_h8300h.c
deleted file mode 100644
index f177711..0000000
--- a/arch/h8300/platform/h8300h/ints_h8300h.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/ints_h8300h.c
- * Interrupt handling CPU variants
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/regs306x.h>
-
-/* saved vector list */
-const int __initdata h8300_saved_vectors[]={
-#if defined(CONFIG_GDB_DEBUG)
-	TRAP3_VEC,
-#endif
-	-1
-};
-
-/* trap entry table */
-const unsigned long __initdata h8300_trap_table[NR_TRAPS]={
-	0,0,0,0,0,0,0,0,
-	(unsigned long)system_call,  /* TRAPA #0 */
-	0,0,
-	(unsigned long)trace_break,  /* TRAPA #3 */
-};
-
-int h8300_enable_irq_pin(unsigned int irq)
-{
-	int bitmask;
-	if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
-		return 0;
-
-	/* initialize IRQ pin */
-	bitmask = 1 << (irq - EXT_IRQ0);
-	switch(irq) {
-	case EXT_IRQ0:
-	case EXT_IRQ1:
-	case EXT_IRQ2:
-	case EXT_IRQ3:
-		if (H8300_GPIO_RESERVE(H8300_GPIO_P8, bitmask) == 0)
-			return -EBUSY;
-		H8300_GPIO_DDR(H8300_GPIO_P8, bitmask, H8300_GPIO_INPUT);
-		break;
-	case EXT_IRQ4:
-	case EXT_IRQ5:
-		if (H8300_GPIO_RESERVE(H8300_GPIO_P9, bitmask) == 0)
-			return -EBUSY;
-		H8300_GPIO_DDR(H8300_GPIO_P9, bitmask, H8300_GPIO_INPUT);
-		break;
-	}
-
-	return 0;
-}
-
-void h8300_disable_irq_pin(unsigned int irq)
-{
-	int bitmask;
-	if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
-		return;
-
-	/* disable interrupt & release IRQ pin */
-	bitmask = 1 << (irq - EXT_IRQ0);
-	switch(irq) {
-	case EXT_IRQ0:
-	case EXT_IRQ1:
-	case EXT_IRQ2:
-	case EXT_IRQ3:
-		*(volatile unsigned char *)IER &= ~bitmask;
-		H8300_GPIO_FREE(H8300_GPIO_P8, bitmask);
-		break ;
-	case EXT_IRQ4:
-	case EXT_IRQ5:
-		*(volatile unsigned char *)IER &= ~bitmask;
-		H8300_GPIO_FREE(H8300_GPIO_P9, bitmask);
-		break;
-	}
-}
diff --git a/arch/h8300/platform/h8s/entry.S b/arch/h8300/platform/h8s/entry.S
index aeb2e9f..f3d6b8e 100644
--- a/arch/h8300/platform/h8s/entry.S
+++ b/arch/h8300/platform/h8s/entry.S
@@ -31,12 +31,13 @@ #include <asm/errno.h>
 	mov.l	er0,@-sp
 
 	stc	ccr,r0l				/* check kernel mode */
-	orc	#0x10,ccr
 	btst	#4,r0l
 	bne	5f
 
-	mov.l	sp,@SYMBOL_NAME(sw_usp)		/* user mode */
-	mov.l	@sp,er0
+	/* user mode */
+	mov.l	sp,@SYMBOL_NAME(sw_usp)
+	mov.l	@sp,er0				/* restore saved er0 */
+	orc	#0x10,ccr			/* switch kernel stack */
 	mov.l	@SYMBOL_NAME(sw_ksp),sp
 	sub.l	#(LRET-LORIG),sp		/* allocate LORIG - LRET */ 
 	stm.l	er0-er3,@-sp
@@ -55,8 +56,9 @@ #include <asm/errno.h>
 	mov.l	er0,@(LER0-LER3:16,sp)		/* copy ER0 */
 	bra	6f
 5:
-	mov.l	@sp,er0				/* kernel mode */
-	subs	#2,sp				/* dummy ccr */
+	/* kernel mode */
+	mov.l	@sp,er0				/* restore saved er0 */
+	subs	#2,sp				/* set dummy ccr */
 	stm.l	er0-er3,@-sp
 	mov.w	@(LRET-LER3:16,sp),r1		/* copy old ccr */
 	mov.b	r1h,r1l
@@ -94,6 +96,7 @@ #include <asm/errno.h>
 	mov.l	@sp+,er1
 	add.l	#(LRET-LER1),sp			/* remove LORIG - LRET */ 
 	mov.l	sp,@SYMBOL_NAME(sw_ksp)
+	andc	#0xef,ccr			/* switch to user mode */
 	mov.l	er0,sp
 	bra	8f
 7:
@@ -173,9 +176,6 @@ #endif
 SYMBOL_NAME_LABEL(system_call)
 	subs	#4,sp				/* dummy LVEC */
 	SAVE_ALL
-	mov.w	@(LCCR:16,sp),r1
-	bset	#4,r1l
-	ldc	r1l,ccr				/* restore ccr */
 	mov.l	er0,er4
 	mov.l	#-ENOSYS,er0
 	mov.l	er0,@(LER0:16,sp)
@@ -198,6 +198,7 @@ SYMBOL_NAME_LABEL(system_call)
 	mov.l	@(LER1:16,sp),er0
 	mov.l	@(LER2:16,sp),er1
 	mov.l	@(LER3:16,sp),er2
+	andc	#0x7f,ccr
 	jsr	@er4
 	mov.l	er0,@(LER0:16,sp)			/* save the return value */
 #if defined(CONFIG_SYSCALL_PRINT)
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 53d6237..64ad10f 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -79,6 +79,10 @@ config ARCH_MAY_HAVE_PC_FDC
 	bool
 	default y
 
+config ARCH_USES_SLAB_PAGE_STRUCT
+	bool
+	default y
+
 config DMI
 	bool
 	default y
@@ -220,7 +224,7 @@ config PARAVIRT
 
 config VMI
 	bool "VMI Paravirt-ops support"
-	depends on PARAVIRT && !COMPAT_VDSO
+	depends on PARAVIRT
 	help
 	  VMI provides a paravirtualized interface to the VMware ESX server
 	  (it could be used by other hypervisors in theory too, but is not
@@ -571,6 +575,9 @@ choice
 		bool "3G/1G user/kernel split (for full 1G low memory)"
 	config VMSPLIT_2G
 		bool "2G/2G user/kernel split"
+	config VMSPLIT_2G_OPT
+		depends on !HIGHMEM
+		bool "2G/2G user/kernel split (for full 2G low memory)"
 	config VMSPLIT_1G
 		bool "1G/3G user/kernel split"
 endchoice
@@ -578,7 +585,8 @@ endchoice
 config PAGE_OFFSET
 	hex
 	default 0xB0000000 if VMSPLIT_3G_OPT
-	default 0x78000000 if VMSPLIT_2G
+	default 0x80000000 if VMSPLIT_2G
+	default 0x78000000 if VMSPLIT_2G_OPT
 	default 0x40000000 if VMSPLIT_1G
 	default 0xC0000000
 
@@ -915,12 +923,9 @@ source kernel/power/Kconfig
 
 source "drivers/acpi/Kconfig"
 
-menu "APM (Advanced Power Management) BIOS Support"
-depends on PM && !X86_VISWS
-
-config APM
+menuconfig APM
 	tristate "APM (Advanced Power Management) BIOS support"
-	depends on PM
+	depends on PM && !X86_VISWS
 	---help---
 	  APM is a BIOS specification for saving power using several different
 	  techniques. This is mostly useful for battery powered laptops with
@@ -977,9 +982,10 @@ config APM
 	  To compile this driver as a module, choose M here: the
 	  module will be called apm.
 
+if APM
+
 config APM_IGNORE_USER_SUSPEND
 	bool "Ignore USER SUSPEND"
-	depends on APM
 	help
 	  This option will ignore USER SUSPEND requests. On machines with a
 	  compliant APM BIOS, you want to say N. However, on the NEC Versa M
@@ -987,7 +993,6 @@ config APM_IGNORE_USER_SUSPEND
 
 config APM_DO_ENABLE
 	bool "Enable PM at boot time"
-	depends on APM
 	---help---
 	  Enable APM features at boot time. From page 36 of the APM BIOS
 	  specification: "When disabled, the APM BIOS does not automatically
@@ -1005,7 +1010,6 @@ config APM_DO_ENABLE
 
 config APM_CPU_IDLE
 	bool "Make CPU Idle calls when idle"
-	depends on APM
 	help
 	  Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
 	  On some machines, this can activate improved power savings, such as
@@ -1017,7 +1021,6 @@ config APM_CPU_IDLE
 
 config APM_DISPLAY_BLANK
 	bool "Enable console blanking using APM"
-	depends on APM
 	help
 	  Enable console blanking using the APM. Some laptops can use this to
 	  turn off the LCD backlight when the screen blanker of the Linux
@@ -1029,22 +1032,8 @@ config APM_DISPLAY_BLANK
 	  backlight at all, or it might print a lot of errors to the console,
 	  especially if you are using gpm.
 
-config APM_RTC_IS_GMT
-	bool "RTC stores time in GMT"
-	depends on APM
-	help
-	  Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
-	  stores the time in GMT (Greenwich Mean Time). Say N if your RTC
-	  stores localtime.
-
-	  It is in fact recommended to store GMT in your RTC, because then you
-	  don't have to worry about daylight savings time changes. The only
-	  reason not to use GMT in your RTC is if you also run a broken OS
-	  that doesn't understand GMT.
-
 config APM_ALLOW_INTS
 	bool "Allow interrupts during APM BIOS calls"
-	depends on APM
 	help
 	  Normally we disable external interrupts while we are making calls to
 	  the APM BIOS as a measure to lessen the effects of a badly behaving
@@ -1055,13 +1044,12 @@ config APM_ALLOW_INTS
 
 config APM_REAL_MODE_POWER_OFF
 	bool "Use real mode APM BIOS call to power off"
-	depends on APM
 	help
 	  Use real mode APM BIOS calls to switch off the computer. This is
 	  a work-around for a number of buggy BIOSes. Switch this option on if
 	  your computer crashes instead of powering off properly.
 
-endmenu
+endif # APM
 
 source "arch/i386/kernel/cpu/cpufreq/Kconfig"
 
@@ -1073,6 +1061,7 @@ config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
 	default y if X86_VISWS
+	select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
 	help
 	  Find out whether you have a PCI motherboard. PCI is the name of a
 	  bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index b99c0e2..dce6124 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -43,6 +43,7 @@ config M386
 	  - "Geode GX/LX" For AMD Geode GX and LX processors.
 	  - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
 	  - "VIA C3-2" for VIA C3-2 "Nehemiah" (model 9 and above).
+	  - "VIA C7" for VIA C7.
 
 	  If you don't know what to do, choose "386".
 
@@ -203,6 +204,12 @@ config MVIAC3_2
 	  of SSE and tells gcc to treat the CPU as a 686.
 	  Note, this kernel will not boot on older (pre model 9) C3s.
 
+config MVIAC7
+	bool "VIA C7"
+	help
+	  Select this for a VIA C7.  Selecting this uses the correct cache
+	  shift and tells gcc to treat the CPU as a 686.
+
 endchoice
 
 config X86_GENERIC
@@ -231,16 +238,21 @@ config X86_L1_CACHE_SHIFT
 	default "7" if MPENTIUM4 || X86_GENERIC
 	default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
 	default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
-	default "6" if MK7 || MK8 || MPENTIUMM || MCORE2
+	default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
+
+config X86_XADD
+	bool
+	depends on !M386
+	default y
 
 config RWSEM_GENERIC_SPINLOCK
 	bool
-	depends on M386
+	depends on !X86_XADD
 	default y
 
 config RWSEM_XCHGADD_ALGORITHM
 	bool
-	depends on !M386
+	depends on X86_XADD
 	default y
 
 config ARCH_HAS_ILOG2_U32
@@ -297,7 +309,7 @@ config X86_ALIGNMENT_16
 
 config X86_GOOD_APIC
 	bool
-	depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2
+	depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 || MVIAC7
 	default y
 
 config X86_INTEL_USERCOPY
@@ -322,5 +334,18 @@ config X86_OOSTORE
 
 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 || MCORE2) && !X86_NUMAQ
+	depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ
 	default y
+
+# this should be set for all -march=.. options where the compiler
+# generates cmov.
+config X86_CMOV
+	bool
+	depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
+	default y
+
+config X86_MINIMUM_CPU_MODEL
+	int
+	default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP
+	default "0"
+
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug
index 458bc16..b31c080 100644
--- a/arch/i386/Kconfig.debug
+++ b/arch/i386/Kconfig.debug
@@ -85,14 +85,4 @@ config DOUBLEFAULT
           option saves about 4k and might cause you much additional grey
           hair.
 
-config DEBUG_PARAVIRT
-	bool "Enable some paravirtualization debugging"
-	default n
-	depends on PARAVIRT && DEBUG_KERNEL
-	help
-	  Currently deliberately clobbers regs which are allowed to be
-	  clobbered in inlined paravirt hooks, even in native mode.
-	  If turning this off solves a problem, then DISABLE_INTERRUPTS() or
-	  ENABLE_INTERRUPTS() is lying about what registers can be clobbered.
-
 endmenu
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index bd28f9f..6dc5e5d 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -34,7 +34,7 @@ CHECKFLAGS	+= -D__i386__
 CFLAGS += -pipe -msoft-float -mregparm=3 -freg-struct-return
 
 # prevent gcc from keeping the stack 16 byte aligned
-CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
+CFLAGS += -mpreferred-stack-boundary=4
 
 # CPU-specific tuning. Anything which can be shared with UML should go here.
 include $(srctree)/arch/i386/Makefile.cpu
diff --git a/arch/i386/Makefile.cpu b/arch/i386/Makefile.cpu
index a32c031..e372b58 100644
--- a/arch/i386/Makefile.cpu
+++ b/arch/i386/Makefile.cpu
@@ -4,9 +4,9 @@ # Must change only cflags-y (or [yn]), n
 #-mtune exists since gcc 3.4
 HAS_MTUNE	:= $(call cc-option-yn, -mtune=i386)
 ifeq ($(HAS_MTUNE),y)
-tune		= $(call cc-option,-mtune=$(1),)
+tune		= $(call cc-option,-mtune=$(1),$(2))
 else
-tune		= $(call cc-option,-mcpu=$(1),)
+tune		= $(call cc-option,-mcpu=$(1),$(2))
 endif
 
 align := $(cc-option-align)
@@ -32,7 +32,8 @@ cflags-$(CONFIG_MWINCHIP2)	+= $(call cc-
 cflags-$(CONFIG_MWINCHIP3D)	+= $(call cc-option,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MCYRIXIII)	+= $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
 cflags-$(CONFIG_MVIAC3_2)	+= $(call cc-option,-march=c3-2,-march=i686)
-cflags-$(CONFIG_MCORE2)		+= -march=i686 $(call cc-option,-mtune=core2,$(call cc-option,-mtune=generic,-mtune=i686))
+cflags-$(CONFIG_MVIAC7)		+= -march=i686
+cflags-$(CONFIG_MCORE2)		+= -march=i686 $(call tune,core2)
 
 # AMD Elan support
 cflags-$(CONFIG_X86_ELAN)	+= -march=i486
@@ -42,5 +43,5 @@ cflags-$(CONFIG_MGEODEGX1)	+= -march=pen
 
 # add at the end to overwrite eventual tuning options from earlier
 # cpu entries
-cflags-$(CONFIG_X86_GENERIC) 	+= $(call tune,generic)
+cflags-$(CONFIG_X86_GENERIC) 	+= $(call tune,generic,$(call tune,i686))
 
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index e979466..bfbc320 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -36,9 +36,9 @@ HOSTCFLAGS_build.o := $(LINUXINCLUDE)
 # ---------------------------------------------------------------------------
 
 $(obj)/zImage:  IMAGE_OFFSET := 0x1000
-$(obj)/zImage:  EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
+$(obj)/zImage:  EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK)
 $(obj)/bzImage: IMAGE_OFFSET := 0x100000
-$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
 
 quiet_cmd_image = BUILD   $@
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index 1ce7017..b28505c 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -189,7 +189,7 @@ static void putstr(const char *);
 static unsigned long free_mem_ptr;
 static unsigned long free_mem_end_ptr;
 
-#define HEAP_SIZE             0x3000
+#define HEAP_SIZE             0x4000
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 06edf1c..f8b3b9c 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -52,6 +52,7 @@ #include <linux/compile.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
 #include <asm/page.h>
+#include <asm/setup.h>
 	
 /* Signature words to ensure LILO loaded us right */
 #define SIG1	0xAA55
@@ -81,7 +82,7 @@ start:
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
 		.ascii	"HdrS"		# header signature
-		.word	0x0205		# header version number (>= 0x0105)
+		.word	0x0206		# header version number (>= 0x0105)
 					# or else old loadlin-1.5 will fail)
 realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
 start_sys_seg:	.word	SYSSEG
@@ -171,6 +172,10 @@ #endif
 pad2:			.byte 0
 pad3:			.word 0
 
+cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
+                                                #added with boot protocol
+                                                #version 2.06
+
 trampoline:	call	start_of_setup
 		.align 16
 					# The offset at this point is 0x240
@@ -297,7 +302,24 @@ # Check if an old loader tries to load a
 
 loader_panic_mess: .string "Wrong loader, giving up..."
 
+# check minimum cpuid
+# we do this here because it is the last place we can actually
+# show a user visible error message. Later the video modus
+# might be already messed up.
 loader_ok:
+	call verify_cpu
+	testl  %eax,%eax
+	jz	cpu_ok
+	lea	cpu_panic_mess,%si
+	call	prtstr
+1:	jmp	1b
+
+cpu_panic_mess:
+	.asciz  "PANIC: CPU too old for this kernel."
+
+#include "../kernel/verify_cpu.S"
+
+cpu_ok:
 # Get memory size (extended mem, kB)
 
 	xorl	%eax, %eax
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 8143c95..5e2280c 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -496,9 +496,11 @@ mode_set:
 	cmpb	$VIDEO_FIRST_V7>>8, %ah
 	jz	setv7
 	
+#ifdef CONFIG_FB
 	cmpb	$VIDEO_FIRST_VESA>>8, %ah
 	jnc	check_vesa
-	
+#endif
+
 	orb	%ah, %ah
 	jz	setmenu
 	
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index f4efd66..9da8441 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Wed Mar  7 15:29:47 2007
+# Linux kernel version: 2.6.21-git3
+# Tue May  1 07:30:51 2007
 #
 CONFIG_X86_32=y
 CONFIG_GENERIC_TIME=y
@@ -108,9 +108,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 # Processor type and features
 #
-# CONFIG_TICK_ONESHOT is not set
-# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_X86_PC is not set
 # CONFIG_X86_ELAN is not set
@@ -146,9 +146,11 @@ # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
 CONFIG_X86_GENERIC=y
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_XADD=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -162,6 +164,8 @@ CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_MODEL=4
 CONFIG_HPET_TIMER=y
 CONFIG_HPET_EMULATE_RTC=y
 CONFIG_NR_CPUS=32
@@ -248,7 +252,6 @@ # 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=2001
 CONFIG_ACPI_DEBUG=y
@@ -257,10 +260,7 @@ CONFIG_ACPI_POWER=y
 CONFIG_ACPI_SYSTEM=y
 CONFIG_X86_PM_TIMER=y
 # CONFIG_ACPI_CONTAINER is not set
-
-#
-# APM (Advanced Power Management) BIOS Support
-#
+# CONFIG_ACPI_SBS is not set
 # CONFIG_APM is not set
 
 #
@@ -277,7 +277,7 @@ 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
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -349,7 +349,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -388,6 +387,7 @@ # CONFIG_TCP_MD5SIG is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
@@ -443,6 +443,13 @@ # CONFIG_NET_TCPPROBE is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
 # CONFIG_IEEE80211 is not set
 
 #
@@ -463,10 +470,6 @@ #
 # Connector - unified userspace <-> kernelspace linker
 #
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
 
 #
@@ -513,6 +516,7 @@ # CONFIG_IBM_ASM is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
+# CONFIG_THINKPAD_ACPI is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -548,7 +552,6 @@ # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_RZ1000 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
@@ -580,7 +583,6 @@ # CONFIG_BLK_DEV_TC86C001 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
 
 #
@@ -669,6 +671,7 @@ # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 
 #
@@ -692,12 +695,12 @@ # CONFIG_SATA_ULI is not set
 CONFIG_SATA_VIA=y
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
 CONFIG_SATA_ACPI=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_CMD640_PCI is not set
 # CONFIG_PATA_CMD64X is not set
 # CONFIG_PATA_CS5520 is not set
 # CONFIG_PATA_CS5530 is not set
@@ -763,10 +766,9 @@ #
 # Subsystem Options
 #
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
 
 #
-# Device Drivers
+# Controllers
 #
 
 #
@@ -775,10 +777,11 @@ #
 CONFIG_IEEE1394_OHCI1394=y
 
 #
-# Protocol Drivers
+# Protocols
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 # CONFIG_IEEE1394_SBP2 is not set
+# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
@@ -821,7 +824,9 @@ 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_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 
 #
 # Tulip family network device support
@@ -902,9 +907,10 @@ #
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Wan interfaces
@@ -918,7 +924,6 @@ # CONFIG_NET_FC is not set
 # CONFIG_SHAPER 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
 
@@ -1051,7 +1056,7 @@ CONFIG_MAX_RAW_DEVS=256
 CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
-CONFIG_HANGCHECK_TIMER=y
+# CONFIG_HANGCHECK_TIMER is not set
 
 #
 # TPM devices
@@ -1143,6 +1148,14 @@ CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
 # USB support
 #
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1155,6 +1168,7 @@ #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
@@ -1205,10 +1219,6 @@ # CONFIG_USB_LIBUSUAL is not set
 #
 # USB Input Devices
 #
-CONFIG_USB_HID=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
@@ -1529,7 +1539,7 @@ # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 4ae3dcf..91cff8d 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -34,17 +34,16 @@ obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault.o
+obj-$(CONFIG_SERIAL_8250)	+= legacy_serial.o
 obj-$(CONFIG_VM86)		+= vm86.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
 
-obj-$(CONFIG_VMI)		+= vmi.o vmitime.o
+obj-$(CONFIG_VMI)		+= vmi.o vmiclock.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o
 obj-y				+= pcspeaker.o
 
-EXTRA_AFLAGS   := -traditional
-
 obj-$(CONFIG_SCx200)		+= scx200.o
 
 # vsyscall.o contains the vsyscall DSO images as __initdata.
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 9ea5b8e..280898b 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -874,7 +874,7 @@ #endif
 				acpi_ioapic = 1;
 
 				smp_found_config = 1;
-				clustered_apic_check();
+				setup_apic_routing();
 			}
 		}
 		if (error == -EINVAL) {
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index a7d22d9..23f78ef 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -10,7 +10,6 @@ #include <linux/acpi.h>
 #include <asm/pci-direct.h>
 #include <asm/acpi.h>
 #include <asm/apic.h>
-#include <asm/irq.h>
 
 #ifdef CONFIG_ACPI
 
@@ -23,10 +22,13 @@ #endif
 static int __init check_bridge(int vendor, int device)
 {
 #ifdef CONFIG_ACPI
+	static int warned;
 	/* According to Nvidia all timer overrides are bogus unless HPET
 	   is enabled. */
 	if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
-		if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
+		if (!warned && acpi_table_parse(ACPI_SIG_HPET,
+						nvidia_hpet_check)) {
+			warned = 1;
 			acpi_skip_timer_override = 1;
 			  printk(KERN_INFO "Nvidia board "
                        "detected. Ignoring ACPI "
@@ -45,24 +47,6 @@ #endif
 	return 0;
 }
 
-static void check_intel(void)
-{
-	u16 vendor, device;
-
-	vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
-
-	if (vendor != PCI_VENDOR_ID_INTEL)
-		return;
-
-	device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
-#ifdef CONFIG_SMP
-	if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
-	    device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
-	    device == PCI_DEVICE_ID_INTEL_E7525_MCH)
-		quirk_intel_irqbalance();
-#endif
-}
-
 void __init check_acpi_pci(void)
 {
 	int num, slot, func;
@@ -74,8 +58,6 @@ void __init check_acpi_pci(void)
 	if (!early_pci_allowed())
 		return;
 
-	check_intel();
-
 	/* Poor man's PCI discovery */
 	for (num = 0; num < 32; num++) {
 		for (slot = 0; slot < 32; slot++) {
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index 426f59b..d8cda14 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -5,6 +5,7 @@ #include <linux/list.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
 
+static int noreplace_smp     = 0;
 static int smp_alt_once      = 0;
 static int debug_alternative = 0;
 
@@ -13,15 +14,33 @@ static int __init bootonly(char *str)
 	smp_alt_once = 1;
 	return 1;
 }
+__setup("smp-alt-boot", bootonly);
+
 static int __init debug_alt(char *str)
 {
 	debug_alternative = 1;
 	return 1;
 }
-
-__setup("smp-alt-boot", bootonly);
 __setup("debug-alternative", debug_alt);
 
+static int __init setup_noreplace_smp(char *str)
+{
+	noreplace_smp = 1;
+	return 1;
+}
+__setup("noreplace-smp", setup_noreplace_smp);
+
+#ifdef CONFIG_PARAVIRT
+static int noreplace_paravirt = 0;
+
+static int __init setup_noreplace_paravirt(char *str)
+{
+	noreplace_paravirt = 1;
+	return 1;
+}
+__setup("noreplace-paravirt", setup_noreplace_paravirt);
+#endif
+
 #define DPRINTK(fmt, args...) if (debug_alternative) \
 	printk(KERN_DEBUG fmt, args)
 
@@ -132,11 +151,8 @@ static void nop_out(void *insns, unsigne
 }
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
-extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[];
 extern u8 *__smp_locks[], *__smp_locks_end[];
 
-extern u8 __smp_alt_begin[], __smp_alt_end[];
-
 /* Replace instructions with better alternatives for this CPU type.
    This runs before SMP is initialized to avoid SMP problems with
    self modifying code. This implies that assymetric systems where
@@ -171,29 +187,6 @@ #endif
 
 #ifdef CONFIG_SMP
 
-static void alternatives_smp_save(struct alt_instr *start, struct alt_instr *end)
-{
-	struct alt_instr *a;
-
-	DPRINTK("%s: alt table %p-%p\n", __FUNCTION__, start, end);
-	for (a = start; a < end; a++) {
-		memcpy(a->replacement + a->replacementlen,
-		       a->instr,
-		       a->instrlen);
-	}
-}
-
-static void alternatives_smp_apply(struct alt_instr *start, struct alt_instr *end)
-{
-	struct alt_instr *a;
-
-	for (a = start; a < end; a++) {
-		memcpy(a->instr,
-		       a->replacement + a->replacementlen,
-		       a->instrlen);
-	}
-}
-
 static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
 {
 	u8 **ptr;
@@ -211,6 +204,9 @@ static void alternatives_smp_unlock(u8 *
 {
 	u8 **ptr;
 
+	if (noreplace_smp)
+		return;
+
 	for (ptr = start; ptr < end; ptr++) {
 		if (*ptr < text)
 			continue;
@@ -245,6 +241,9 @@ void alternatives_smp_module_add(struct 
 	struct smp_alt_module *smp;
 	unsigned long flags;
 
+	if (noreplace_smp)
+		return;
+
 	if (smp_alt_once) {
 		if (boot_cpu_has(X86_FEATURE_UP))
 			alternatives_smp_unlock(locks, locks_end,
@@ -279,7 +278,7 @@ void alternatives_smp_module_del(struct 
 	struct smp_alt_module *item;
 	unsigned long flags;
 
-	if (smp_alt_once)
+	if (smp_alt_once || noreplace_smp)
 		return;
 
 	spin_lock_irqsave(&smp_alt, flags);
@@ -310,7 +309,7 @@ #ifdef CONFIG_LOCKDEP
 	return;
 #endif
 
-	if (smp_alt_once)
+	if (noreplace_smp || smp_alt_once)
 		return;
 	BUG_ON(!smp && (num_online_cpus() > 1));
 
@@ -319,8 +318,6 @@ #endif
 		printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
 		clear_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
 		clear_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
-		alternatives_smp_apply(__smp_alt_instructions,
-				       __smp_alt_instructions_end);
 		list_for_each_entry(mod, &smp_alt_modules, next)
 			alternatives_smp_lock(mod->locks, mod->locks_end,
 					      mod->text, mod->text_end);
@@ -328,8 +325,6 @@ #endif
 		printk(KERN_INFO "SMP alternatives: switching to UP code\n");
 		set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
 		set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
-		apply_alternatives(__smp_alt_instructions,
-				   __smp_alt_instructions_end);
 		list_for_each_entry(mod, &smp_alt_modules, next)
 			alternatives_smp_unlock(mod->locks, mod->locks_end,
 						mod->text, mod->text_end);
@@ -340,36 +335,31 @@ #endif
 #endif
 
 #ifdef CONFIG_PARAVIRT
-void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
+void apply_paravirt(struct paravirt_patch_site *start,
+		    struct paravirt_patch_site *end)
 {
-	struct paravirt_patch *p;
+	struct paravirt_patch_site *p;
+
+	if (noreplace_paravirt)
+		return;
 
 	for (p = start; p < end; p++) {
 		unsigned int used;
 
 		used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr,
 					  p->len);
-#ifdef CONFIG_DEBUG_PARAVIRT
-		{
-		int i;
-		/* Deliberately clobber regs using "not %reg" to find bugs. */
-		for (i = 0; i < 3; i++) {
-			if (p->len - used >= 2 && (p->clobbers & (1 << i))) {
-				memcpy(p->instr + used, "\xf7\xd0", 2);
-				p->instr[used+1] |= i;
-				used += 2;
-			}
-		}
-		}
-#endif
+
+		BUG_ON(used > p->len);
+
 		/* Pad the rest with nops */
 		nop_out(p->instr + used, p->len - used);
 	}
 
-	/* Sync to be conservative, in case we patched following instructions */
+	/* Sync to be conservative, in case we patched following
+	 * instructions */
 	sync_core();
 }
-extern struct paravirt_patch __start_parainstructions[],
+extern struct paravirt_patch_site __start_parainstructions[],
 	__stop_parainstructions[];
 #endif	/* CONFIG_PARAVIRT */
 
@@ -396,23 +386,19 @@ #ifdef CONFIG_SMP
 			printk(KERN_INFO "SMP alternatives: switching to UP code\n");
 			set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
 			set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
-			apply_alternatives(__smp_alt_instructions,
-					   __smp_alt_instructions_end);
 			alternatives_smp_unlock(__smp_locks, __smp_locks_end,
 						_text, _etext);
 		}
 		free_init_pages("SMP alternatives",
-				(unsigned long)__smp_alt_begin,
-				(unsigned long)__smp_alt_end);
+				(unsigned long)__smp_locks,
+				(unsigned long)__smp_locks_end);
 	} else {
-		alternatives_smp_save(__smp_alt_instructions,
-				      __smp_alt_instructions_end);
 		alternatives_smp_module_add(NULL, "core kernel",
 					    __smp_locks, __smp_locks_end,
 					    _text, _etext);
 		alternatives_smp_switch(0);
 	}
 #endif
- 	apply_paravirt(__start_parainstructions, __stop_parainstructions);
+ 	apply_paravirt(__parainstructions, __parainstructions_end);
 	local_irq_restore(flags);
 }
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 93aa911..67824f3 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -19,7 +19,6 @@ #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>
@@ -129,6 +128,28 @@ static int modern_apic(void)
 	return lapic_get_version() >= 0x14;
 }
 
+void apic_wait_icr_idle(void)
+{
+	while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+		cpu_relax();
+}
+
+unsigned long safe_apic_wait_icr_idle(void)
+{
+	unsigned long send_status;
+	int timeout;
+
+	timeout = 0;
+	do {
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+		if (!send_status)
+			break;
+		udelay(100);
+	} while (timeout++ < 1000);
+
+	return send_status;
+}
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 064bbf2..4112afe 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -223,7 +223,6 @@ #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
 #include <linux/kthread.h>
@@ -233,11 +232,10 @@ #include <asm/uaccess.h>
 #include <asm/desc.h>
 #include <asm/i8253.h>
 #include <asm/paravirt.h>
+#include <asm/reboot.h>
 
 #include "io_ports.h"
 
-extern void machine_real_restart(unsigned char *, int);
-
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 extern int (*console_blank_hook)(int);
 #endif
@@ -384,13 +382,6 @@ static int			ignore_sys_suspend;
 static int			ignore_normal_resume;
 static int			bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
 
-#ifdef CONFIG_APM_RTC_IS_GMT
-#	define	clock_cmos_diff	0
-#	define	got_clock_diff	1
-#else
-static long			clock_cmos_diff;
-static int			got_clock_diff;
-#endif
 static int			debug __read_mostly;
 static int			smp __read_mostly;
 static int			apm_disabled = -1;
@@ -1181,7 +1172,7 @@ #ifdef INIT_TIMER_AFTER_SUSPEND
 	unsigned long flags;
 
 	spin_lock_irqsave(&i8253_lock, flags);
-	/* set the clock to 100 Hz */
+	/* set the clock to HZ */
 	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
 	udelay(10);
 	outb_p(LATCH & 0xff, PIT_CH0);	/* LSB */
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
index c375351..27a776c 100644
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -11,11 +11,11 @@ #include <linux/personality.h>
 #include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include "sigframe.h"
+#include <asm/pgtable.h>
 #include <asm/fixmap.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
 #include <asm/elf.h>
-#include <asm/pda.h>
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -25,6 +25,9 @@ #define BLANK() asm volatile("\n->" : : 
 #define OFFSET(sym, str, mem) \
 	DEFINE(sym, offsetof(struct str, mem));
 
+/* workaround for a warning with -Wmissing-prototypes */
+void foo(void);
+
 void foo(void)
 {
 	OFFSET(SIGCONTEXT_eax, sigcontext, eax);
@@ -90,17 +93,18 @@ void foo(void)
 	OFFSET(pbe_next, pbe, next);
 
 	/* Offset from the sysenter stack to tss.esp0 */
-	DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) -
+	DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, x86_tss.esp0) -
 		 sizeof(struct tss_struct));
 
 	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
-	DEFINE(VDSO_PRELINK, VDSO_PRELINK);
+	DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
+	DEFINE(PTRS_PER_PTE, PTRS_PER_PTE);
+	DEFINE(PTRS_PER_PMD, PTRS_PER_PMD);
+	DEFINE(PTRS_PER_PGD, PTRS_PER_PGD);
 
-	OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
+	DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK);
 
-	BLANK();
- 	OFFSET(PDA_cpu, i386_pda, cpu_number);
-	OFFSET(PDA_pcurrent, i386_pda, pcurrent);
+	OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
 
 #ifdef CONFIG_PARAVIRT
 	BLANK();
diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
index 010aecf..74f27a4 100644
--- a/arch/i386/kernel/cpu/Makefile
+++ b/arch/i386/kernel/cpu/Makefile
@@ -2,7 +2,7 @@ #
 # Makefile for x86-compatible CPU details and quirks
 #
 
-obj-y	:=	common.o proc.o
+obj-y	:=	common.o proc.o bugs.o
 
 obj-y	+=	amd.o
 obj-y	+=	cyrix.o
@@ -17,3 +17,5 @@ obj-$(CONFIG_X86_MCE)	+=	mcheck/
 
 obj-$(CONFIG_MTRR)	+= 	mtrr/
 obj-$(CONFIG_CPU_FREQ)	+=	cpufreq/
+
+obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 2d47db4..4fec702 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -53,6 +53,8 @@ static __cpuinit int amd_apic_timer_brok
 	return 0;
 }
 
+int force_mwait __cpuinitdata;
+
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
@@ -275,6 +277,9 @@ #endif
 
 	if (amd_apic_timer_broken())
 		set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
+
+	if (c->x86 == 0x10 && !force_mwait)
+		clear_bit(X86_FEATURE_MWAIT, c->x86_capability);
 }
 
 static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
@@ -314,13 +319,3 @@ int __init amd_init_cpu(void)
 	cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
 	return 0;
 }
-
-//early_arch_initcall(amd_init_cpu);
-
-static int __init amd_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_AMD] = NULL;
-	return 0;
-}
-
-late_initcall(amd_exit_cpu);
diff --git a/arch/i386/kernel/cpu/bugs.c b/arch/i386/kernel/cpu/bugs.c
new file mode 100644
index 0000000..54428a2
--- /dev/null
+++ b/arch/i386/kernel/cpu/bugs.c
@@ -0,0 +1,191 @@
+/*
+ *  arch/i386/cpu/bugs.c
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ *
+ *  Cyrix stuff, June 1998 by:
+ *	- Rafael R. Reilova (moved everything from head.S),
+ *        <rreilova@ececs.uc.edu>
+ *	- Channing Corn (tests & fixes),
+ *	- Andrew D. Balsa (code cleanup).
+ */
+#include <linux/init.h>
+#include <linux/utsname.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/msr.h>
+#include <asm/paravirt.h>
+#include <asm/alternative.h>
+
+static int __init no_halt(char *s)
+{
+	boot_cpu_data.hlt_works_ok = 0;
+	return 1;
+}
+
+__setup("no-hlt", no_halt);
+
+static int __init mca_pentium(char *s)
+{
+	mca_pentium_flag = 1;
+	return 1;
+}
+
+__setup("mca-pentium", mca_pentium);
+
+static int __init no_387(char *s)
+{
+	boot_cpu_data.hard_math = 0;
+	write_cr0(0xE | read_cr0());
+	return 1;
+}
+
+__setup("no387", no_387);
+
+static double __initdata x = 4195835.0;
+static double __initdata y = 3145727.0;
+
+/*
+ * This used to check for exceptions..
+ * However, it turns out that to support that,
+ * the XMM trap handlers basically had to
+ * be buggy. So let's have a correct XMM trap
+ * handler, and forget about printing out
+ * some status at boot.
+ *
+ * We should really only care about bugs here
+ * anyway. Not features.
+ */
+static void __init check_fpu(void)
+{
+	if (!boot_cpu_data.hard_math) {
+#ifndef CONFIG_MATH_EMULATION
+		printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
+		printk(KERN_EMERG "Giving up.\n");
+		for (;;) ;
+#endif
+		return;
+	}
+
+/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
+	/* Test for the divl bug.. */
+	__asm__("fninit\n\t"
+		"fldl %1\n\t"
+		"fdivl %2\n\t"
+		"fmull %2\n\t"
+		"fldl %1\n\t"
+		"fsubp %%st,%%st(1)\n\t"
+		"fistpl %0\n\t"
+		"fwait\n\t"
+		"fninit"
+		: "=m" (*&boot_cpu_data.fdiv_bug)
+		: "m" (*&x), "m" (*&y));
+	if (boot_cpu_data.fdiv_bug)
+		printk("Hmm, FPU with FDIV bug.\n");
+}
+
+static void __init check_hlt(void)
+{
+	if (paravirt_enabled())
+		return;
+
+	printk(KERN_INFO "Checking 'hlt' instruction... ");
+	if (!boot_cpu_data.hlt_works_ok) {
+		printk("disabled\n");
+		return;
+	}
+	halt();
+	halt();
+	halt();
+	halt();
+	printk("OK.\n");
+}
+
+/*
+ *	Most 386 processors have a bug where a POPAD can lock the
+ *	machine even from user space.
+ */
+
+static void __init check_popad(void)
+{
+#ifndef CONFIG_X86_POPAD_OK
+	int res, inp = (int) &res;
+
+	printk(KERN_INFO "Checking for popad bug... ");
+	__asm__ __volatile__(
+	  "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
+	  : "=&a" (res)
+	  : "d" (inp)
+	  : "ecx", "edi" );
+	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
+	if (res != 12345678) printk( "Buggy.\n" );
+		        else printk( "OK.\n" );
+#endif
+}
+
+/*
+ * Check whether we are able to run this kernel safely on SMP.
+ *
+ * - In order to run on a i386, we need to be compiled for i386
+ *   (for due to lack of "invlpg" and working WP on a i386)
+ * - In order to run on anything without a TSC, we need to be
+ *   compiled for a i486.
+ * - In order to support the local APIC on a buggy Pentium machine,
+ *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
+ *   which happens implicitly if compiled for a Pentium or lower
+ *   (unless an advanced selection of CPU features is used) as an
+ *   otherwise config implies a properly working local APIC without
+ *   the need to do extra reads from the APIC.
+*/
+
+static void __init check_config(void)
+{
+/*
+ * We'd better not be a i386 if we're configured to use some
+ * i486+ only features! (WP works in supervisor mode and the
+ * new "invlpg" and "bswap" instructions)
+ */
+#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
+	if (boot_cpu_data.x86 == 3)
+		panic("Kernel requires i486+ for 'invlpg' and other features");
+#endif
+
+/*
+ * If we configured ourselves for a TSC, we'd better have one!
+ */
+#ifdef CONFIG_X86_TSC
+	if (!cpu_has_tsc && !tsc_disable)
+		panic("Kernel compiled for Pentium+, requires TSC feature!");
+#endif
+
+/*
+ * If we were told we had a good local APIC, check for buggy Pentia,
+ * i.e. all B steppings and the C2 stepping of P54C when using their
+ * integrated APIC (see 11AP erratum in "Pentium Processor
+ * Specification Update").
+ */
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
+	    && cpu_has_apic
+	    && boot_cpu_data.x86 == 5
+	    && boot_cpu_data.x86_model == 2
+	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
+		panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
+#endif
+}
+
+
+void __init check_bugs(void)
+{
+	identify_boot_cpu();
+#ifndef CONFIG_SMP
+	printk("CPU: ");
+	print_cpu_info(&boot_cpu_data);
+#endif
+	check_config();
+	check_fpu();
+	check_hlt();
+	check_popad();
+	init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+	alternative_instructions();
+}
diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
index 8c25047..473eac8 100644
--- a/arch/i386/kernel/cpu/centaur.c
+++ b/arch/i386/kernel/cpu/centaur.c
@@ -469,13 +469,3 @@ int __init centaur_init_cpu(void)
 	cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
 	return 0;
 }
-
-//early_arch_initcall(centaur_init_cpu);
-
-static int __init centaur_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_CENTAUR] = NULL;
-	return 0;
-}
-
-late_initcall(centaur_exit_cpu);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index dcbbd0a..794d593 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -18,15 +18,37 @@ #include <asm/mpspec.h>
 #include <asm/apic.h>
 #include <mach_apic.h>
 #endif
-#include <asm/pda.h>
 
 #include "cpu.h"
 
-DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
-EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
+DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
+	[GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 },
+	[GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 },
+	[GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 },
+	[GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 },
+	/*
+	 * 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.
+	 */
+	[GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
+	[GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */
+	[GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */
+	[GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */
+	[GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */
+	/*
+	 * The APM segments have byte granularity and their bases
+	 * are set at run time.  All have 64k limits.
+	 */
+	[GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
+	/* 16-bit code */
+	[GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 },
+	[GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
 
-struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly;
-EXPORT_SYMBOL(_cpu_pda);
+	[GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
+	[GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 },
+} };
+EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
 
 static int cachesize_override __cpuinitdata = -1;
 static int disable_x86_fxsr __cpuinitdata;
@@ -368,7 +390,7 @@ __setup("serialnumber", x86_serial_nr_se
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
-void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 {
 	int i;
 
@@ -479,15 +501,22 @@ void __cpuinit identify_cpu(struct cpuin
 
 	/* Init Machine Check Exception if available. */
 	mcheck_init(c);
+}
 
-	if (c == &boot_cpu_data)
-		sysenter_setup();
+void __init identify_boot_cpu(void)
+{
+	identify_cpu(&boot_cpu_data);
+	sysenter_setup();
 	enable_sep_cpu();
+	mtrr_bp_init();
+}
 
-	if (c == &boot_cpu_data)
-		mtrr_bp_init();
-	else
-		mtrr_ap_init();
+void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
+{
+	BUG_ON(c == &boot_cpu_data);
+	identify_cpu(c);
+	enable_sep_cpu();
+	mtrr_ap_init();
 }
 
 #ifdef CONFIG_X86_HT
@@ -601,129 +630,36 @@ #ifdef CONFIG_DEBUG_PAGEALLOC
 #endif
 }
 
-/* Make sure %gs is initialized properly in idle threads */
+/* Make sure %fs is initialized properly in idle threads */
 struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
 {
 	memset(regs, 0, sizeof(struct pt_regs));
-	regs->xfs = __KERNEL_PDA;
+	regs->xfs = __KERNEL_PERCPU;
 	return regs;
 }
 
-static __cpuinit int alloc_gdt(int cpu)
+/* Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one. */
+void switch_to_new_gdt(void)
 {
-	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-	struct desc_struct *gdt;
-	struct i386_pda *pda;
-
-	gdt = (struct desc_struct *)cpu_gdt_descr->address;
-	pda = cpu_pda(cpu);
-
-	/*
-	 * 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) {
-		BUG_ON(gdt != NULL || pda != NULL);
-
-		gdt = alloc_bootmem_pages(PAGE_SIZE);
-		pda = alloc_bootmem(sizeof(*pda));
-		/* alloc_bootmem(_pages) panics on failure, so no check */
-
-		memset(gdt, 0, PAGE_SIZE);
-		memset(pda, 0, sizeof(*pda));
-	} else {
-		/* GDT and PDA might already have been allocated if
-		   this is a CPU hotplug re-insertion. */
-		if (gdt == NULL)
-			gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
-
-		if (pda == NULL)
-			pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu));
-
-		if (unlikely(!gdt || !pda)) {
-			free_pages((unsigned long)gdt, 0);
-			kfree(pda);
-			return 0;
-		}
-	}
-
- 	cpu_gdt_descr->address = (unsigned long)gdt;
-	cpu_pda(cpu) = pda;
-
-	return 1;
-}
+	struct Xgt_desc_struct gdt_descr;
 
-/* Initial PDA used by boot CPU */
-struct i386_pda boot_pda = {
-	._pda = &boot_pda,
-	.cpu_number = 0,
-	.pcurrent = &init_task,
-};
-
-static inline void set_kernel_fs(void)
-{
-	/* Set %fs for this CPU's PDA.  Memory clobber is to create a
-	   barrier with respect to any PDA operations, so the compiler
-	   doesn't move any before here. */
-	asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory");
+	gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
+	asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
 }
 
-/* Initialize the CPU's GDT and PDA.  The boot CPU does this for
-   itself, but secondaries find this done for them. */
-__cpuinit int init_gdt(int cpu, struct task_struct *idle)
-{
-	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-	struct desc_struct *gdt;
-	struct i386_pda *pda;
-
-	/* For non-boot CPUs, the GDT and PDA should already have been
-	   allocated. */
-	if (!alloc_gdt(cpu)) {
-		printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu);
-		return 0;
-	}
-
-	gdt = (struct desc_struct *)cpu_gdt_descr->address;
-	pda = cpu_pda(cpu);
-
-	BUG_ON(gdt == NULL || pda == NULL);
-
-	/*
-	 * Initialize the per-CPU GDT with the boot GDT,
-	 * and set up the GDT descriptor:
-	 */
- 	memcpy(gdt, cpu_gdt_table, GDT_SIZE);
-	cpu_gdt_descr->size = GDT_SIZE - 1;
-
-	pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
-			(u32 *)&gdt[GDT_ENTRY_PDA].b,
-			(unsigned long)pda, sizeof(*pda) - 1,
-			0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
-
-	memset(pda, 0, sizeof(*pda));
-	pda->_pda = pda;
-	pda->cpu_number = cpu;
-	pda->pcurrent = idle;
-
-	return 1;
-}
-
-void __cpuinit cpu_set_gdt(int cpu)
-{
-	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-
-	/* Reinit these anyway, even if they've already been done (on
-	   the boot CPU, this will transition from the boot gdt+pda to
-	   the real ones). */
-	load_gdt(cpu_gdt_descr);
-	set_kernel_fs();
-}
-
-/* Common CPU init for both boot and secondary CPUs */
-static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
+/*
+ * 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();
+	struct task_struct *curr = current;
 	struct tss_struct * t = &per_cpu(init_tss, cpu);
 	struct thread_struct *thread = &curr->thread;
 
@@ -744,6 +680,7 @@ static void __cpuinit _cpu_init(int cpu,
 	}
 
 	load_idt(&idt_descr);
+	switch_to_new_gdt();
 
 	/*
 	 * Set up and load the per-CPU TSS and LDT
@@ -783,38 +720,6 @@ #endif
 	mxcsr_feature_mask_init();
 }
 
-/* Entrypoint to initialize secondary CPU */
-void __cpuinit secondary_cpu_init(void)
-{
-	int cpu = smp_processor_id();
-	struct task_struct *curr = current;
-
-	_cpu_init(cpu, curr);
-}
-
-/*
- * 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();
-	struct task_struct *curr = current;
-
-	/* Set up the real GDT and PDA, so we can transition from the
-	   boot versions. */
-	if (!init_gdt(cpu, curr)) {
-		/* failed to allocate something; not much we can do... */
-		for (;;)
-			local_irq_enable();
-	}
-
-	cpu_set_gdt(cpu);
-	_cpu_init(cpu, curr);
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
 void __cpuinit cpu_uninit(void)
 {
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 2b030d6..a3df9c0 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -590,20 +590,23 @@ static acpi_status longhaul_walk_callbac
 static int enable_arbiter_disable(void)
 {
 	struct pci_dev *dev;
+	int status;
 	int reg;
 	u8 pci_cmd;
 
+	status = 1;
 	/* Find PLE133 host bridge */
 	reg = 0x78;
-	dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
+	dev = pci_get_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);
+		dev = pci_get_device(PCI_VENDOR_ID_VIA,
+				     PCI_DEVICE_ID_VIA_862X_0, NULL);
 		/* Find CN400 V-Link host bridge */
 		if (dev == NULL)
-			dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
-
+			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
 	}
 	if (dev != NULL) {
 		/* Enable access to port 0x22 */
@@ -615,10 +618,11 @@ static int enable_arbiter_disable(void)
 			if (!(pci_cmd & 1<<7)) {
 				printk(KERN_ERR PFX
 					"Can't enable access to port 0x22.\n");
-				return 0;
+				status = 0;
 			}
 		}
-		return 1;
+		pci_dev_put(dev);
+		return status;
 	}
 	return 0;
 }
@@ -629,7 +633,7 @@ static int longhaul_setup_vt8235(void)
 	u8 pci_cmd;
 
 	/* Find VT8235 southbridge */
-	dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
+	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
 	if (dev != NULL) {
 		/* Set transition time to max */
 		pci_read_config_byte(dev, 0xec, &pci_cmd);
@@ -641,6 +645,7 @@ static int longhaul_setup_vt8235(void)
 		pci_read_config_byte(dev, 0xe5, &pci_cmd);
 		pci_cmd |= 1 << 7;
 		pci_write_config_byte(dev, 0xe5, pci_cmd);
+		pci_dev_put(dev);
 		return 1;
 	}
 	return 0;
@@ -678,7 +683,7 @@ static int __init longhaul_cpu_init(stru
 				sizeof(samuel2_eblcr));
 			break;
 		case 1 ... 15:
-			longhaul_version = TYPE_LONGHAUL_V2;
+			longhaul_version = TYPE_LONGHAUL_V1;
 			if (c->x86_mask < 8) {
 				cpu_model = CPU_SAMUEL2;
 				cpuname = "C3 'Samuel 2' [C5B]";
diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
index 4786fed..4c76b51 100644
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
@@ -27,7 +27,6 @@ #include <linux/smp.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
 #include <linux/cpumask.h>
-#include <linux/sched.h>	/* current / set_cpus_allowed() */
 
 #include <asm/processor.h>
 #include <asm/msr.h>
@@ -62,7 +61,7 @@ static int cpufreq_p4_setdc(unsigned int
 	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
 		return -EINVAL;
 
-	rdmsr(MSR_IA32_THERM_STATUS, l, h);
+	rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
 
 	if (l & 0x01)
 		dprintk("CPU#%d currently thermal throttled\n", cpu);
@@ -70,10 +69,10 @@ static int cpufreq_p4_setdc(unsigned int
 	if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT))
 		newstate = DC_38PT;
 
-	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+	rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
 	if (newstate == DC_DISABLE) {
 		dprintk("CPU#%d disabling modulation\n", cpu);
-		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+		wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
 	} else {
 		dprintk("CPU#%d setting duty cycle to %d%%\n",
 			cpu, ((125 * newstate) / 10));
@@ -84,7 +83,7 @@ static int cpufreq_p4_setdc(unsigned int
 		 */
 		l = (l & ~14);
 		l = l | (1<<4) | ((newstate & 0x7)<<1);
-		wrmsr(MSR_IA32_THERM_CONTROL, l, h);
+		wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h);
 	}
 
 	return 0;
@@ -111,7 +110,6 @@ static int cpufreq_p4_target(struct cpuf
 {
 	unsigned int    newstate = DC_RESV;
 	struct cpufreq_freqs freqs;
-	cpumask_t cpus_allowed;
 	int i;
 
 	if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
@@ -132,17 +130,8 @@ static int cpufreq_p4_target(struct cpuf
 	/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
 	 * Developer's Manual, Volume 3
 	 */
-	cpus_allowed = current->cpus_allowed;
-
-	for_each_cpu_mask(i, policy->cpus) {
-		cpumask_t this_cpu = cpumask_of_cpu(i);
-
-		set_cpus_allowed(current, this_cpu);
-		BUG_ON(smp_processor_id() != i);
-
+	for_each_cpu_mask(i, policy->cpus)
 		cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
-	}
-	set_cpus_allowed(current, cpus_allowed);
 
 	/* notifiers */
 	for_each_cpu_mask(i, policy->cpus) {
@@ -256,17 +245,9 @@ static int cpufreq_p4_cpu_exit(struct cp
 
 static unsigned int cpufreq_p4_get(unsigned int cpu)
 {
-	cpumask_t cpus_allowed;
 	u32 l, h;
 
-	cpus_allowed = current->cpus_allowed;
-
-	set_cpus_allowed(current, cpumask_of_cpu(cpu));
-	BUG_ON(smp_processor_id() != cpu);
-
-	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
-
-	set_cpus_allowed(current, cpus_allowed);
+	rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
 
 	if (l & 0x10) {
 		l = l >> 1;
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index fe3b670..7cf3d20 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -661,7 +661,8 @@ static int fill_powernow_table(struct po
 
 	dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
 	data->powernow_table = powernow_table;
-	print_basics(data);
+	if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
+		print_basics(data);
 
 	for (j = 0; j < data->numps; j++)
 		if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))
@@ -814,7 +815,8 @@ static int powernow_k8_cpu_init_acpi(str
 
 	/* fill in data */
 	data->numps = data->acpi_data.state_count;
-	print_basics(data);
+	if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
+		print_basics(data);
 	powernow_k8_acpi_pst_values(data, 0);
 
 	/* notify BIOS that we exist */
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index 0fb2a30..95be501 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -215,8 +215,10 @@ static int core_frequency_transition(str
 
 static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
 
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
 static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
 static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
+#endif
 
 #ifdef CONFIG_SMP
 static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index f43b987..35489fd 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -720,6 +720,7 @@ #endif
 			cpu_set(j, set_mask);
 
 		set_cpus_allowed(current, set_mask);
+		preempt_disable();
 		if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
 			dprintk("couldn't limit to CPUs in this domain\n");
 			retval = -EAGAIN;
@@ -727,6 +728,7 @@ #endif
 				/* We haven't started the transition yet. */
 				goto migrate_end;
 			}
+			preempt_enable();
 			break;
 		}
 
@@ -761,10 +763,13 @@ #endif
 		}
 
 		wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
-		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+		if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+			preempt_enable();
 			break;
+		}
 
 		cpu_set(j, covered_cpus);
+		preempt_enable();
 	}
 
 	for_each_cpu_mask(k, online_policy_cpus) {
@@ -796,8 +801,11 @@ #endif
 			cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 		}
 	}
+	set_cpus_allowed(current, saved_mask);
+	return 0;
 
 migrate_end:
+	preempt_enable();
 	set_cpus_allowed(current, saved_mask);
 	return 0;
 }
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
index d59277c..b1acc8c 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
@@ -13,7 +13,6 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 
 #include <asm/msr.h>
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
index ff0d898..e1c509a 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
@@ -17,10 +17,10 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/ist.h>
+#include <asm/io.h>
 
 #include "speedstep-lib.h"
 
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index de27bd0..0b8411a 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -279,7 +279,7 @@ #ifdef CONFIG_PCI
 		 */  
 		if (vendor == PCI_VENDOR_ID_CYRIX &&
 	 (device == PCI_DEVICE_ID_CYRIX_5510 || device == PCI_DEVICE_ID_CYRIX_5520))
-			pit_latch_buggy = 1;
+			mark_tsc_unstable("cyrix 5510/5520 detected");
 	}
 #endif
 		c->x86_cache_size=16;	/* Yep 16K integrated cache thats it */
@@ -448,16 +448,6 @@ int __init cyrix_init_cpu(void)
 	return 0;
 }
 
-//early_arch_initcall(cyrix_init_cpu);
-
-static int __init cyrix_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_CYRIX] = NULL;
-	return 0;
-}
-
-late_initcall(cyrix_exit_cpu);
-
 static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
 	.c_vendor	= "NSC",
 	.c_ident 	= { "Geode by NSC" },
@@ -470,12 +460,3 @@ int __init nsc_init_cpu(void)
 	return 0;
 }
 
-//early_arch_initcall(nsc_init_cpu);
-
-static int __init nsc_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_NSC] = NULL;
-	return 0;
-}
-
-late_initcall(nsc_exit_cpu);
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 56fe265..dc4e081 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -188,8 +188,10 @@ #ifdef CONFIG_X86_INTEL_USERCOPY
 	}
 #endif
 
-	if (c->x86 == 15)
+	if (c->x86 == 15) {
 		set_bit(X86_FEATURE_P4, c->x86_capability);
+		set_bit(X86_FEATURE_SYNC_RDTSC, c->x86_capability);
+	}
 	if (c->x86 == 6) 
 		set_bit(X86_FEATURE_P3, c->x86_capability);
 	if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c
index b0862af..f9fa414 100644
--- a/arch/i386/kernel/cpu/mcheck/k7.c
+++ b/arch/i386/kernel/cpu/mcheck/k7.c
@@ -75,6 +75,9 @@ void amd_mcheck_init(struct cpuinfo_x86 
 	machine_check_vector = k7_machine_check;
 	wmb();
 
+	if (!cpu_has(c, X86_FEATURE_MCE))
+		return;
+
 	printk (KERN_INFO "Intel machine check architecture supported.\n");
 	rdmsr (MSR_IA32_MCG_CAP, l, h);
 	if (l & (1<<8))	/* Control register present ? */
@@ -82,9 +85,13 @@ void amd_mcheck_init(struct cpuinfo_x86 
 	nr_mce_banks = l & 0xff;
 
 	/* Clear status for MC index 0 separately, we don't touch CTL,
-	 * as some Athlons cause spurious MCEs when its enabled. */
-	wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
-	for (i=1; i<nr_mce_banks; i++) {
+	 * as some K7 Athlons cause spurious MCEs when its enabled. */
+	if (boot_cpu_data.x86 == 6) {
+		wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
+		i = 1;
+	} else
+		i = 0;
+	for (; i<nr_mce_banks; i++) {
 		wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
 		wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
 	}
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index 4f10c62..56cd485 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -38,8 +38,7 @@ void mcheck_init(struct cpuinfo_x86 *c)
 
 	switch (c->x86_vendor) {
 		case X86_VENDOR_AMD:
-			if (c->x86==6 || c->x86==15)
-				amd_mcheck_init(c);
+			amd_mcheck_init(c);
 			break;
 
 		case X86_VENDOR_INTEL:
diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
index 504434a..1509edf 100644
--- a/arch/i386/kernel/cpu/mcheck/p4.c
+++ b/arch/i386/kernel/cpu/mcheck/p4.c
@@ -124,13 +124,10 @@ #endif /* CONFIG_X86_MCE_P4THERMAL */
 
 
 /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
-static inline int intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
 {
 	u32 h;
 
-	if (mce_num_extended_msrs == 0)
-		goto done;
-
 	rdmsr (MSR_IA32_MCG_EAX, r->eax, h);
 	rdmsr (MSR_IA32_MCG_EBX, r->ebx, h);
 	rdmsr (MSR_IA32_MCG_ECX, r->ecx, h);
@@ -141,12 +138,6 @@ static inline int intel_get_extended_msr
 	rdmsr (MSR_IA32_MCG_ESP, r->esp, h);
 	rdmsr (MSR_IA32_MCG_EFLAGS, r->eflags, h);
 	rdmsr (MSR_IA32_MCG_EIP, r->eip, h);
-
-	/* can we rely on kmalloc to do a dynamic
-	 * allocation for the reserved registers?
-	 */
-done:
-	return mce_num_extended_msrs;
 }
 
 static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
@@ -155,7 +146,6 @@ static fastcall void intel_machine_check
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
 	int i;
-	struct intel_mce_extended_msrs dbg;
 
 	rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 	if (mcgstl & (1<<0))	/* Recoverable ? */
@@ -164,7 +154,9 @@ static fastcall void intel_machine_check
 	printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
 		smp_processor_id(), mcgsth, mcgstl);
 
-	if (intel_get_extended_msrs(&dbg)) {
+	if (mce_num_extended_msrs > 0) {
+		struct intel_mce_extended_msrs dbg;
+		intel_get_extended_msrs(&dbg);
 		printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
 			smp_processor_id(), dbg.eip, dbg.eflags);
 		printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index f77fc53..5367e32 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -20,13 +20,25 @@ struct mtrr_state {
 	mtrr_type def_type;
 };
 
+struct fixed_range_block {
+	int base_msr; /* start address of an MTRR block */
+	int ranges;   /* number of MTRRs in this block  */
+};
+
+static struct fixed_range_block fixed_range_blocks[] = {
+	{ MTRRfix64K_00000_MSR, 1 }, /* one  64k MTRR  */
+	{ MTRRfix16K_80000_MSR, 2 }, /* two  16k MTRRs */
+	{ MTRRfix4K_C0000_MSR,  8 }, /* eight 4k MTRRs */
+	{}
+};
+
 static unsigned long smp_changes_mask;
 static struct mtrr_state mtrr_state = {};
 
 #undef MODULE_PARAM_PREFIX
 #define MODULE_PARAM_PREFIX "mtrr."
 
-static __initdata int mtrr_show;
+static int mtrr_show;
 module_param_named(show, mtrr_show, bool, 0);
 
 /*  Get the MSR pair relating to a var range  */
@@ -37,7 +49,7 @@ get_mtrr_var_range(unsigned int index, s
 	rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
 }
 
-static void __init
+static void
 get_fixed_ranges(mtrr_type * frs)
 {
 	unsigned int *p = (unsigned int *) frs;
@@ -51,12 +63,18 @@ get_fixed_ranges(mtrr_type * frs)
 		rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
 }
 
-static void __init print_fixed(unsigned base, unsigned step, const mtrr_type*types)
+void mtrr_save_fixed_ranges(void *info)
+{
+	get_fixed_ranges(mtrr_state.fixed_ranges);
+}
+
+static void __cpuinit print_fixed(unsigned base, unsigned step, const mtrr_type*types)
 {
 	unsigned i;
 
 	for (i = 0; i < 8; ++i, ++types, base += step)
-		printk(KERN_INFO "MTRR %05X-%05X %s\n", base, base + step - 1, mtrr_attrib_to_str(*types));
+		printk(KERN_INFO "MTRR %05X-%05X %s\n",
+			base, base + step - 1, mtrr_attrib_to_str(*types));
 }
 
 /*  Grab all of the MTRR state for this CPU into *state  */
@@ -147,6 +165,44 @@ void mtrr_wrmsr(unsigned msr, unsigned a
 			smp_processor_id(), msr, a, b);
 }
 
+/**
+ * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs
+ * see AMD publication no. 24593, chapter 3.2.1 for more information
+ */
+static inline void k8_enable_fixed_iorrs(void)
+{
+	unsigned lo, hi;
+
+	rdmsr(MSR_K8_SYSCFG, lo, hi);
+	mtrr_wrmsr(MSR_K8_SYSCFG, lo
+				| K8_MTRRFIXRANGE_DRAM_ENABLE
+				| K8_MTRRFIXRANGE_DRAM_MODIFY, hi);
+}
+
+/**
+ * Checks and updates an fixed-range MTRR if it differs from the value it
+ * should have. If K8 extenstions are wanted, update the K8 SYSCFG MSR also.
+ * see AMD publication no. 24593, chapter 7.8.1, page 233 for more information
+ * \param msr MSR address of the MTTR which should be checked and updated
+ * \param changed pointer which indicates whether the MTRR needed to be changed
+ * \param msrwords pointer to the MSR values which the MSR should have
+ */
+static void set_fixed_range(int msr, int * changed, unsigned int * msrwords)
+{
+	unsigned lo, hi;
+
+	rdmsr(msr, lo, hi);
+
+	if (lo != msrwords[0] || hi != msrwords[1]) {
+		if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+		    boot_cpu_data.x86 == 15 &&
+		    ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK))
+			k8_enable_fixed_iorrs();
+		mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
+		*changed = TRUE;
+	}
+}
+
 int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
 /*  [SUMMARY] Get a free MTRR.
     <base> The starting (base) address of the region.
@@ -196,36 +252,21 @@ static void generic_get_mtrr(unsigned in
 	*type = base_lo & 0xff;
 }
 
+/**
+ * Checks and updates the fixed-range MTRRs if they differ from the saved set
+ * \param frs pointer to fixed-range MTRR values, saved by get_fixed_ranges()
+ */
 static int set_fixed_ranges(mtrr_type * frs)
 {
-	unsigned int *p = (unsigned int *) frs;
+	unsigned long long *saved = (unsigned long long *) frs;
 	int changed = FALSE;
-	int i;
-	unsigned int lo, hi;
+	int block=-1, range;
 
-	rdmsr(MTRRfix64K_00000_MSR, lo, hi);
-	if (p[0] != lo || p[1] != hi) {
-		mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
-		changed = TRUE;
-	}
+	while (fixed_range_blocks[++block].ranges)
+	    for (range=0; range < fixed_range_blocks[block].ranges; range++)
+		set_fixed_range(fixed_range_blocks[block].base_msr + range,
+		    &changed, (unsigned int *) saved++);
 
-	for (i = 0; i < 2; i++) {
-		rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
-		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
-			mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
-			      p[3 + i * 2]);
-			changed = TRUE;
-		}
-	}
-
-	for (i = 0; i < 8; i++) {
-		rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
-		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
-			mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
-			      p[7 + i * 2]);
-			changed = TRUE;
-		}
-	}
 	return changed;
 }
 
@@ -428,7 +469,7 @@ int generic_validate_add_page(unsigned l
 		}
 	}
 
-	if (base + size < 0x100) {
+	if (base < 0x100) {
 		printk(KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
 		       base, size);
 		return -EINVAL;
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 0acfb6a..02a2f39 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -729,6 +729,17 @@ void mtrr_ap_init(void)
 	local_irq_restore(flags);
 }
 
+/**
+ * Save current fixed-range MTRR state of the BSP
+ */
+void mtrr_save_state(void)
+{
+	if (smp_processor_id() == 0)
+		mtrr_save_fixed_ranges(NULL);
+	else
+		smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1);
+}
+
 static int __init mtrr_init_finialize(void)
 {
 	if (!mtrr_if)
diff --git a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
index 8bf23cc..961fbe1 100644
--- a/arch/i386/kernel/cpu/nexgen.c
+++ b/arch/i386/kernel/cpu/nexgen.c
@@ -58,13 +58,3 @@ int __init nexgen_init_cpu(void)
 	cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev;
 	return 0;
 }
-
-//early_arch_initcall(nexgen_init_cpu);
-
-static int __init nexgen_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_NEXGEN] = NULL;
-	return 0;
-}
-
-late_initcall(nexgen_exit_cpu);
diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/i386/kernel/cpu/perfctr-watchdog.c
new file mode 100644
index 0000000..2b04c8f
--- /dev/null
+++ b/arch/i386/kernel/cpu/perfctr-watchdog.c
@@ -0,0 +1,658 @@
+/* local apic based NMI watchdog for various CPUs.
+   This file also handles reservation of performance counters for coordination
+   with other users (like oprofile).
+
+   Note that these events normally don't tick when the CPU idles. This means
+   the frequency varies with CPU load.
+
+   Original code for K7/P6 written by Keith Owens */
+
+#include <linux/percpu.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/smp.h>
+#include <linux/nmi.h>
+#include <asm/apic.h>
+#include <asm/intel_arch_perfmon.h>
+
+struct nmi_watchdog_ctlblk {
+	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 */
+};
+
+/* Interface defining a CPU specific perfctr watchdog */
+struct wd_ops {
+	int (*reserve)(void);
+	void (*unreserve)(void);
+	int (*setup)(unsigned nmi_hz);
+	void (*rearm)(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz);
+	void (*stop)(void *);
+	unsigned perfctr;
+	unsigned evntsel;
+	u64 checkbit;
+};
+
+static struct wd_ops *wd_ops;
+
+/* 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
+
+/* 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 DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);
+static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);
+
+static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+
+/* converts an msr to an appropriate reservation bit */
+static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
+{
+	return wd_ops ? msr - wd_ops->perfctr : 0;
+}
+
+/* converts an msr to an appropriate reservation bit */
+/* returns the bit offset of the event selection register */
+static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
+{
+	return wd_ops ? msr - wd_ops->evntsel : 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, 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, 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, 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, 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, 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, evntsel_nmi_owner);
+}
+
+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);
+
+void disable_lapic_nmi_watchdog(void)
+{
+	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+	if (atomic_read(&nmi_active) <= 0)
+		return;
+
+	on_each_cpu(wd_ops->stop, NULL, 0, 1);
+	wd_ops->unreserve();
+
+	BUG_ON(atomic_read(&nmi_active) != 0);
+}
+
+void enable_lapic_nmi_watchdog(void)
+{
+	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+	/* are we already enabled */
+	if (atomic_read(&nmi_active) != 0)
+		return;
+
+	/* are we lapic aware */
+	if (!wd_ops)
+		return;
+	if (!wd_ops->reserve()) {
+		printk(KERN_ERR "NMI watchdog: cannot reserve perfctrs\n");
+		return;
+	}
+
+	on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
+	touch_nmi_watchdog();
+}
+
+/*
+ * Activate the NMI watchdog via the local APIC.
+ */
+
+static unsigned int adjust_for_32bit_ctr(unsigned int hz)
+{
+	u64 counter_val;
+	unsigned int retval = hz;
+
+	/*
+	 * On Intel CPUs with P6/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
+	 */
+	counter_val = (u64)cpu_khz * 1000;
+	do_div(counter_val, retval);
+ 	if (counter_val > 0x7fffffffULL) {
+		u64 count = (u64)cpu_khz * 1000;
+		do_div(count, 0x7fffffffUL);
+		retval = count + 1;
+	}
+	return retval;
+}
+
+static void
+write_watchdog_counter(unsigned int perfctr_msr, const char *descr, unsigned nmi_hz)
+{
+	u64 count = (u64)cpu_khz * 1000;
+
+	do_div(count, nmi_hz);
+	if(descr)
+		Dprintk("setting %s to -0x%08Lx\n", descr, count);
+	wrmsrl(perfctr_msr, 0 - count);
+}
+
+static void write_watchdog_counter32(unsigned int perfctr_msr,
+		const char *descr, unsigned nmi_hz)
+{
+	u64 count = (u64)cpu_khz * 1000;
+
+	do_div(count, nmi_hz);
+	if(descr)
+		Dprintk("setting %s to -0x%08Lx\n", descr, count);
+	wrmsr(perfctr_msr, (u32)(-count), 0);
+}
+
+/* AMD K7/K8/Family10h/Family11h support. AMD keeps this interface
+   nicely stable so there is not much variety */
+
+#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(unsigned nmi_hz)
+{
+	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;
+
+	wrmsrl(perfctr_msr, 0UL);
+
+	evntsel = K7_EVNTSEL_INT
+		| K7_EVNTSEL_OS
+		| K7_EVNTSEL_USR
+		| K7_NMI_EVENT;
+
+	/* setup the timer */
+	wrmsr(evntsel_msr, evntsel, 0);
+	write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= K7_EVNTSEL_ENABLE;
+	wrmsr(evntsel_msr, evntsel, 0);
+
+	wd->perfctr_msr = perfctr_msr;
+	wd->evntsel_msr = evntsel_msr;
+	wd->cccr_msr = 0;  //unused
+	return 1;
+}
+
+static void single_msr_stop_watchdog(void *arg)
+{
+	struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+	wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int single_msr_reserve(void)
+{
+	if (!reserve_perfctr_nmi(wd_ops->perfctr))
+		return 0;
+
+	if (!reserve_evntsel_nmi(wd_ops->evntsel)) {
+		release_perfctr_nmi(wd_ops->perfctr);
+		return 0;
+	}
+	return 1;
+}
+
+static void single_msr_unreserve(void)
+{
+	release_evntsel_nmi(wd_ops->perfctr);
+	release_perfctr_nmi(wd_ops->evntsel);
+}
+
+static void single_msr_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+	/* start the cycle over again */
+	write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static struct wd_ops k7_wd_ops = {
+	.reserve = single_msr_reserve,
+	.unreserve = single_msr_unreserve,
+	.setup = setup_k7_watchdog,
+	.rearm = single_msr_rearm,
+	.stop = single_msr_stop_watchdog,
+	.perfctr = MSR_K7_PERFCTR0,
+	.evntsel = MSR_K7_EVNTSEL0,
+	.checkbit = 1ULL<<63,
+};
+
+/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
+
+#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(unsigned nmi_hz)
+{
+	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;
+
+	wrmsrl(perfctr_msr, 0UL);
+
+	evntsel = P6_EVNTSEL_INT
+		| P6_EVNTSEL_OS
+		| P6_EVNTSEL_USR
+		| P6_NMI_EVENT;
+
+	/* setup the timer */
+	wrmsr(evntsel_msr, evntsel, 0);
+	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+	write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= P6_EVNTSEL0_ENABLE;
+	wrmsr(evntsel_msr, evntsel, 0);
+
+	wd->perfctr_msr = perfctr_msr;
+	wd->evntsel_msr = evntsel_msr;
+	wd->cccr_msr = 0;  //unused
+	return 1;
+}
+
+static void p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+	/* 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);
+	/* P6/ARCH_PERFMON has 32 bit counter write */
+	write_watchdog_counter32(wd->perfctr_msr, NULL,nmi_hz);
+}
+
+static struct wd_ops p6_wd_ops = {
+	.reserve = single_msr_reserve,
+	.unreserve = single_msr_unreserve,
+	.setup = setup_p6_watchdog,
+	.rearm = p6_rearm,
+	.stop = single_msr_stop_watchdog,
+	.perfctr = MSR_P6_PERFCTR0,
+	.evntsel = MSR_P6_EVNTSEL0,
+	.checkbit = 1ULL<<39,
+};
+
+/* Intel P4 performance counters. By far the most complicated of all. */
+
+#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(unsigned nmi_hz)
+{
+	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)
+	 */
+	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);
+	}
+
+	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", 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;
+	return 1;
+}
+
+static void stop_p4_watchdog(void *arg)
+{
+	struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+	wrmsr(wd->cccr_msr, 0, 0);
+	wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int p4_reserve(void)
+{
+	if (!reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR0))
+		return 0;
+#ifdef CONFIG_SMP
+	if (smp_num_siblings > 1 && !reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR1))
+		goto fail1;
+#endif
+	if (!reserve_evntsel_nmi(MSR_P4_CRU_ESCR0))
+		goto fail2;
+	/* RED-PEN why is ESCR1 not reserved here? */
+	return 1;
+ fail2:
+#ifdef CONFIG_SMP
+	if (smp_num_siblings > 1)
+		release_perfctr_nmi(MSR_P4_IQ_PERFCTR1);
+ fail1:
+#endif
+	release_perfctr_nmi(MSR_P4_IQ_PERFCTR0);
+	return 0;
+}
+
+static void p4_unreserve(void)
+{
+#ifdef CONFIG_SMP
+	if (smp_num_siblings > 1)
+		release_evntsel_nmi(MSR_P4_IQ_PERFCTR1);
+#endif
+	release_evntsel_nmi(MSR_P4_IQ_PERFCTR0);
+	release_perfctr_nmi(MSR_P4_CRU_ESCR0);
+}
+
+static void p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+	unsigned dummy;
+	/*
+ 	 * 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);
+	/* start the cycle over again */
+	write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static struct wd_ops p4_wd_ops = {
+	.reserve = p4_reserve,
+	.unreserve = p4_unreserve,
+	.setup = setup_p4_watchdog,
+	.rearm = p4_rearm,
+	.stop = stop_p4_watchdog,
+	/* RED-PEN this is wrong for the other sibling */
+	.perfctr = MSR_P4_BPU_PERFCTR0,
+	.evntsel = MSR_P4_BSU_ESCR0,
+	.checkbit = 1ULL<<39,
+};
+
+/* Watchdog using the Intel architected PerfMon. Used for Core2 and hopefully
+   all future Intel CPUs. */
+
+#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(unsigned nmi_hz)
+{
+	unsigned int ebx;
+	union cpuid10_eax eax;
+	unsigned int unused;
+	unsigned int perfctr_msr, evntsel_msr;
+	unsigned int evntsel;
+	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 0;
+
+	perfctr_msr = MSR_ARCH_PERFMON_PERFCTR1;
+	evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL1;
+
+	wrmsrl(perfctr_msr, 0UL);
+
+	evntsel = ARCH_PERFMON_EVENTSEL_INT
+		| ARCH_PERFMON_EVENTSEL_OS
+		| ARCH_PERFMON_EVENTSEL_USR
+		| ARCH_PERFMON_NMI_EVENT_SEL
+		| ARCH_PERFMON_NMI_EVENT_UMASK;
+
+	/* setup the timer */
+	wrmsr(evntsel_msr, evntsel, 0);
+	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+	write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+	wrmsr(evntsel_msr, evntsel, 0);
+
+	wd->perfctr_msr = perfctr_msr;
+	wd->evntsel_msr = evntsel_msr;
+	wd->cccr_msr = 0;  //unused
+	wd_ops->checkbit = 1ULL << (eax.split.bit_width - 1);
+	return 1;
+}
+
+static struct wd_ops intel_arch_wd_ops = {
+	.reserve = single_msr_reserve,
+	.unreserve = single_msr_unreserve,
+	.setup = setup_intel_arch_watchdog,
+	.rearm = p6_rearm,
+	.stop = single_msr_stop_watchdog,
+	.perfctr = MSR_ARCH_PERFMON_PERFCTR0,
+	.evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
+};
+
+static void probe_nmi_watchdog(void)
+{
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
+		    boot_cpu_data.x86 != 16)
+			return;
+		wd_ops = &k7_wd_ops;
+		break;
+	case X86_VENDOR_INTEL:
+		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+			wd_ops = &intel_arch_wd_ops;
+			break;
+		}
+		switch (boot_cpu_data.x86) {
+		case 6:
+			if (boot_cpu_data.x86_model > 0xd)
+				return;
+
+			wd_ops = &p6_wd_ops;
+			break;
+		case 15:
+			if (boot_cpu_data.x86_model > 0x4)
+				return;
+
+			wd_ops = &p4_wd_ops;
+			break;
+		default:
+			return;
+		}
+		break;
+	}
+}
+
+/* Interface to nmi.c */
+
+int lapic_watchdog_init(unsigned nmi_hz)
+{
+	if (!wd_ops) {
+		probe_nmi_watchdog();
+		if (!wd_ops)
+			return -1;
+	}
+
+	if (!(wd_ops->setup(nmi_hz))) {
+		printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n",
+		       raw_smp_processor_id());
+		return -1;
+	}
+
+	return 0;
+}
+
+void lapic_watchdog_stop(void)
+{
+	if (wd_ops)
+		wd_ops->stop(NULL);
+}
+
+unsigned lapic_adjust_nmi_hz(unsigned hz)
+{
+	struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+	if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
+	    wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR1)
+		hz = adjust_for_32bit_ctr(hz);
+	return hz;
+}
+
+int lapic_wd_event(unsigned nmi_hz)
+{
+	struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+	u64 ctr;
+	rdmsrl(wd->perfctr_msr, ctr);
+	if (ctr & wd_ops->checkbit) { /* perfctr still running? */
+		return 0;
+	}
+	wd_ops->rearm(wd, nmi_hz);
+	return 1;
+}
+
+int lapic_watchdog_ok(void)
+{
+	return wd_ops != NULL;
+}
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index 47e3ebb..89d91e6 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -72,8 +72,7 @@ static int show_cpuinfo(struct seq_file 
 		"stc",
 		"100mhzsteps",
 		"hwpstate",
-		NULL,
-		NULL,	/* constant_tsc - moved to flags */
+		"",	/* constant_tsc - moved to flags */
 		/* nothing */
 	};
 	struct cpuinfo_x86 *c = v;
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
index 9317f74..50076f2 100644
--- a/arch/i386/kernel/cpu/rise.c
+++ b/arch/i386/kernel/cpu/rise.c
@@ -50,12 +50,3 @@ int __init rise_init_cpu(void)
 	return 0;
 }
 
-//early_arch_initcall(rise_init_cpu);
-
-static int __init rise_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_RISE] = NULL;
-	return 0;
-}
-
-late_initcall(rise_exit_cpu);
diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
index 5678d46..6471a5a 100644
--- a/arch/i386/kernel/cpu/transmeta.c
+++ b/arch/i386/kernel/cpu/transmeta.c
@@ -112,13 +112,3 @@ int __init transmeta_init_cpu(void)
 	cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
 	return 0;
 }
-
-//early_arch_initcall(transmeta_init_cpu);
-
-static int __init transmeta_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_TRANSMETA] = NULL;
-	return 0;
-}
-
-late_initcall(transmeta_exit_cpu);
diff --git a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
index 1bf3f87..a7a4e75 100644
--- a/arch/i386/kernel/cpu/umc.c
+++ b/arch/i386/kernel/cpu/umc.c
@@ -24,13 +24,3 @@ int __init umc_init_cpu(void)
 	cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev;
 	return 0;
 }
-
-//early_arch_initcall(umc_init_cpu);
-
-static int __init umc_exit_cpu(void)
-{
-	cpu_devs[X86_VENDOR_UMC] = NULL;
-	return 0;
-}
-
-late_initcall(umc_exit_cpu);
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index a5e0e99..53589d1 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -22,7 +22,7 @@ #include <asm/hardirq.h>
 #include <asm/nmi.h>
 #include <asm/hw_irq.h>
 #include <asm/apic.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/smp.h>
 
 #include <mach_ipi.h>
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index b4d14c2..265c559 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -33,7 +33,7 @@ static void doublefault_fn(void)
 		printk("double fault, tss at %08lx\n", tss);
 
 		if (ptr_ok(tss)) {
-			struct tss_struct *t = (struct tss_struct *)tss;
+			struct i386_hw_tss *t = (struct i386_hw_tss *)tss;
 
 			printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
 
@@ -49,18 +49,21 @@ static void doublefault_fn(void)
 }
 
 struct tss_struct doublefault_tss __cacheline_aligned = {
-	.esp0		= STACK_START,
-	.ss0		= __KERNEL_DS,
-	.ldt		= 0,
-	.io_bitmap_base	= INVALID_IO_BITMAP_OFFSET,
+	.x86_tss = {
+		.esp0		= STACK_START,
+		.ss0		= __KERNEL_DS,
+		.ldt		= 0,
+		.io_bitmap_base	= INVALID_IO_BITMAP_OFFSET,
 
-	.eip		= (unsigned long) doublefault_fn,
-	.eflags		= X86_EFLAGS_SF | 0x2,	/* 0x2 bit is always set */
-	.esp		= STACK_START,
-	.es		= __USER_DS,
-	.cs		= __KERNEL_CS,
-	.ss		= __KERNEL_DS,
-	.ds		= __USER_DS,
+		.eip		= (unsigned long) doublefault_fn,
+		/* 0x2 bit is always set */
+		.eflags		= X86_EFLAGS_SF | 0x2,
+		.esp		= STACK_START,
+		.es		= __USER_DS,
+		.cs		= __KERNEL_CS,
+		.ss		= __KERNEL_DS,
+		.ds		= __USER_DS,
 
-	.__cr3		= __pa(swapper_pg_dir)
+		.__cr3		= __pa(swapper_pg_dir)
+	}
 };
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index 70f3956..9645bb5 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -161,26 +161,27 @@ #define ROMSIGNATURE 0xaa55
 
 static int __init romsignature(const unsigned char *rom)
 {
+	const unsigned short * const ptr = (const unsigned short *)rom;
 	unsigned short sig;
 
-	return probe_kernel_address((const unsigned short *)rom, sig) == 0 &&
-	       sig == ROMSIGNATURE;
+	return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;
 }
 
-static int __init romchecksum(unsigned char *rom, unsigned long length)
+static int __init romchecksum(const unsigned char *rom, unsigned long length)
 {
-	unsigned char sum;
+	unsigned char sum, c;
 
-	for (sum = 0; length; length--)
-		sum += *rom++;
-	return sum == 0;
+	for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--)
+		sum += c;
+	return !length && !sum;
 }
 
 static void __init probe_roms(void)
 {
+	const unsigned char *rom;
 	unsigned long start, length, upper;
-	unsigned char *rom;
-	int	      i;
+	unsigned char c;
+	int i;
 
 	/* video rom */
 	upper = adapter_rom_resources[0].start;
@@ -191,8 +192,11 @@ static void __init probe_roms(void)
 
 		video_rom_resource.start = start;
 
+		if (probe_kernel_address(rom + 2, c) != 0)
+			continue;
+
 		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
+		length = c * 512;
 
 		/* if checksum okay, trust length byte */
 		if (length && romchecksum(rom, length))
@@ -226,8 +230,11 @@ static void __init probe_roms(void)
 		if (!romsignature(rom))
 			continue;
 
+		if (probe_kernel_address(rom + 2, c) != 0)
+			continue;
+
 		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
+		length = c * 512;
 
 		/* but accept any length that fits if checksum okay */
 		if (!length || start + length > upper || !romchecksum(rom, length))
@@ -386,10 +393,8 @@ int __init sanitize_e820_map(struct e820
 		   ____________________33__
 		   ______________________4_
 	*/
-	printk("sanitize start\n");
 	/* if there's only one memory region, don't bother */
 	if (*pnr_map < 2) {
-		printk("sanitize bail 0\n");
 		return -1;
 	}
 
@@ -398,7 +403,6 @@ int __init sanitize_e820_map(struct e820
 	/* 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) {
-			printk("sanitize bail 1\n");
 			return -1;
 		}
 
@@ -494,7 +498,6 @@ int __init sanitize_e820_map(struct e820
 	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
 	*pnr_map = new_nr;
 
-	printk("sanitize end\n");
 	return 0;
 }
 
@@ -525,7 +528,6 @@ int __init copy_e820_map(struct e820entr
 		unsigned long long size = biosmap->size;
 		unsigned long long end = start + size;
 		unsigned long type = biosmap->type;
-		printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type);
 
 		/* Overflow in 64 bits? Ignore the memory map. */
 		if (start > end)
@@ -536,17 +538,11 @@ int __init copy_e820_map(struct e820entr
 		 * Not right. Fix it up.
 		 */
 		if (type == E820_RAM) {
-			printk("copy_e820_map() type is E820_RAM\n");
 			if (start < 0x100000ULL && end > 0xA0000ULL) {
-				printk("copy_e820_map() lies in range...\n");
-				if (start < 0xA0000ULL) {
-					printk("copy_e820_map() start < 0xA0000ULL\n");
+				if (start < 0xA0000ULL)
 					add_memory_region(start, 0xA0000ULL-start, type);
-				}
-				if (end <= 0x100000ULL) {
-					printk("copy_e820_map() end <= 0x100000ULL\n");
+				if (end <= 0x100000ULL)
 					continue;
-				}
 				start = 0x100000ULL;
 				size = end - start;
 			}
@@ -818,6 +814,26 @@ void __init limit_regions(unsigned long 
 	print_memory_map("limit_regions endfunc");
 }
 
+/*
+ * This function checks if any part of the range <start,end> is mapped
+ * with type.
+ */
+int
+e820_any_mapped(u64 start, u64 end, unsigned type)
+{
+	int i;
+	for (i = 0; i < e820.nr_map; i++) {
+		const 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;
+}
+EXPORT_SYMBOL_GPL(e820_any_mapped);
+
  /*
   * This function checks if the entire range <start,end> is mapped with type.
   *
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index 8f9c624..a180802 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -69,13 +69,11 @@ static void efi_call_phys_prelog(void) _
 {
 	unsigned long cr4;
 	unsigned long temp;
-	struct Xgt_desc_struct *cpu_gdt_descr;
+	struct Xgt_desc_struct gdt_descr;
 
 	spin_lock(&efi_rt_lock);
 	local_irq_save(efi_rt_eflags);
 
-	cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
-
 	/*
 	 * If I don't have PSE, I should just duplicate two entries in page
 	 * directory. If I have PSE, I just need to duplicate one entry in
@@ -105,17 +103,19 @@ static void efi_call_phys_prelog(void) _
 	 */
 	local_flush_tlb();
 
-	cpu_gdt_descr->address = __pa(cpu_gdt_descr->address);
-	load_gdt(cpu_gdt_descr);
+	gdt_descr.address = __pa(get_cpu_gdt_table(0));
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
 }
 
 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);
+	struct Xgt_desc_struct gdt_descr;
 
-	cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address);
-	load_gdt(cpu_gdt_descr);
+	gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
 
 	cr4 = read_cr4();
 
@@ -347,14 +347,12 @@ void __init efi_init(void)
 		printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n");
 	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
 		printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n");
-	if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
-		printk(KERN_ERR PFX
-		       "Warning: EFI system table major version mismatch: "
-		       "got %d.%02d, expected %d.%02d\n",
+	if ((efi.systab->hdr.revision >> 16) == 0)
+		printk(KERN_ERR PFX "Warning: EFI system table version "
+		       "%d.%02d, expected 1.00 or greater\n",
 		       efi.systab->hdr.revision >> 16,
-		       efi.systab->hdr.revision & 0xffff,
-		       EFI_SYSTEM_TABLE_REVISION >> 16,
-		       EFI_SYSTEM_TABLE_REVISION & 0xffff);
+		       efi.systab->hdr.revision & 0xffff);
+
 	/*
 	 * Grab some details from the system table
 	 */
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 18bddcb..b1f16ee 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -15,7 +15,7 @@
  * 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':
+ * Stack layout in 'syscall_exit':
  * 	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,
@@ -132,7 +132,7 @@ #define SAVE_ALL \
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
 	movl %edx, %es; \
-	movl $(__KERNEL_PDA), %edx; \
+	movl $(__KERNEL_PERCPU), %edx; \
 	movl %edx, %fs
 
 #define RESTORE_INT_REGS \
@@ -305,16 +305,12 @@ sysenter_past_esp:
 	pushl $(__USER_CS)
 	CFI_ADJUST_CFA_OFFSET 4
 	/*CFI_REL_OFFSET cs, 0*/
-#ifndef CONFIG_COMPAT_VDSO
 	/*
 	 * 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)
-#else
-	pushl $SYSENTER_RETURN
-#endif
 	CFI_ADJUST_CFA_OFFSET 4
 	CFI_REL_OFFSET eip, 0
 
@@ -342,7 +338,7 @@ #endif
 	jae syscall_badsys
 	call *sys_call_table(,%eax,4)
 	movl %eax,PT_EAX(%esp)
-	DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX)
+	DISABLE_INTERRUPTS(CLBR_ANY)
 	TRACE_IRQS_OFF
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
@@ -560,9 +556,7 @@ END(syscall_badsys)
 
 #define FIXUP_ESPFIX_STACK \
 	/* since we are on a wrong stack, we cant make it a C code :( */ \
-	movl %fs:PDA_cpu, %ebx; \
-	PER_CPU(cpu_gdt_descr, %ebx); \
-	movl GDS_address(%ebx), %ebx; \
+	PER_CPU(gdt_page, %ebx); \
 	GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
 	addl %esp, %eax; \
 	pushl $__KERNEL_DS; \
@@ -635,7 +629,7 @@ ENTRY(name)				\
 	SAVE_ALL;			\
 	TRACE_IRQS_OFF			\
 	movl %esp,%eax;			\
-	call smp_/**/name;		\
+	call smp_##name;		\
 	jmp ret_from_intr;		\
 	CFI_ENDPROC;			\
 ENDPROC(name)
@@ -643,11 +637,6 @@ ENDPROC(name)
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
-/* This alternate entry is needed because we hijack the apic LVTT */
-#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC)
-BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR)
-#endif
-
 KPROBE_ENTRY(page_fault)
 	RING0_EC_FRAME
 	pushl $do_page_fault
@@ -686,7 +675,7 @@ error_code:
 	pushl %fs
 	CFI_ADJUST_CFA_OFFSET 4
 	/*CFI_REL_OFFSET fs, 0*/
-	movl $(__KERNEL_PDA), %ecx
+	movl $(__KERNEL_PERCPU), %ecx
 	movl %ecx, %fs
 	UNWIND_ESPFIX_STACK
 	popl %ecx
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 3fa7f93..9b10af6 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -34,17 +34,32 @@ #define X86_VENDOR_ID	new_cpu_data+CPUIN
 
 /*
  * This is how much memory *in addition to the memory covered up to
- * and including _end* we need mapped initially.  We need one bit for
- * each possible page, but only in low memory, which means
- * 2^32/4096/8 = 128K worst case (4G/4G split.)
+ * and including _end* we need mapped initially.
+ * We need:
+ *  - one bit for each possible page, but only in low memory, which means
+ *     2^32/4096/8 = 128K worst case (4G/4G split.)
+ *  - enough space to map all low memory, which means
+ *     (2^32/4096) / 1024 pages (worst case, non PAE)
+ *     (2^32/4096) / 512 + 4 pages (worst case for PAE)
+ *  - a few pages for allocator use before the kernel pagetable has
+ *     been set up
  *
  * Modulo rounding, each megabyte assigned here requires a kilobyte of
  * memory, which is currently unreclaimed.
  *
  * This should be a multiple of a page.
  */
-#define INIT_MAP_BEYOND_END	(128*1024)
+LOW_PAGES = 1<<(32-PAGE_SHIFT_asm)
 
+#if PTRS_PER_PMD > 1
+PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD
+#else
+PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD)
+#endif
+BOOTBITMAP_SIZE = LOW_PAGES / 8
+ALLOCATOR_SLOP = 4
+
+INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm
 
 /*
  * 32-bit kernel entrypoint; only used by the boot CPU.  On entry,
@@ -147,8 +162,7 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
 /*
  * Non-boot CPU entry point; entered from trampoline.S
  * We can't lgdt here, because lgdt itself uses a data segment, but
- * we know the trampoline has already loaded the boot_gdt_table GDT
- * for us.
+ * we know the trampoline has already loaded the boot_gdt for us.
  *
  * If cpu hotplug is not supported then this code can go in init section
  * which will be freed later
@@ -318,12 +332,12 @@ is386:	movl $2,%ecx		# set MP
 	movl %eax,%cr0
 
 	call check_x87
-	call setup_pda
 	lgdt early_gdt_descr
 	lidt idt_descr
 	ljmp $(__KERNEL_CS),$1f
 1:	movl $(__KERNEL_DS),%eax	# reload all the segment registers
 	movl %eax,%ss			# after changing gdt.
+	movl %eax,%fs			# gets reset once there's real percpu
 
 	movl $(__USER_DS),%eax		# DS/ES contains default USER segment
 	movl %eax,%ds
@@ -333,16 +347,17 @@ is386:	movl $2,%ecx		# set MP
 	movl %eax,%gs
 	lldt %ax
 
-	movl $(__KERNEL_PDA),%eax
-	mov  %eax,%fs
-
 	cld			# gcc2 wants the direction flag cleared at all times
 	pushl $0		# fake return address for unwinder
 #ifdef CONFIG_SMP
 	movb ready, %cl
 	movb $1, ready
 	cmpb $0,%cl		# the first CPU calls start_kernel
-	jne initialize_secondary # all other CPUs call initialize_secondary
+	je   1f
+	movl $(__KERNEL_PERCPU), %eax
+	movl %eax,%fs		# set this cpu's percpu
+	jmp initialize_secondary # all other CPUs call initialize_secondary
+1:
 #endif /* CONFIG_SMP */
 	jmp start_kernel
 
@@ -366,23 +381,6 @@ check_x87:
 	ret
 
 /*
- * Point the GDT at this CPU's PDA.  On boot this will be
- * cpu_gdt_table and boot_pda; for secondary CPUs, these will be
- * that CPU's GDT and PDA.
- */
-ENTRY(setup_pda)
-	/* get the PDA pointer */
-	movl start_pda, %eax
-
-	/* slot the PDA address into the GDT */
-	mov early_gdt_descr+2, %ecx
-	mov %ax, (__KERNEL_PDA+0+2)(%ecx)		/* base & 0x0000ffff */
-	shr $16, %eax
-	mov %al, (__KERNEL_PDA+4+0)(%ecx)		/* base & 0x00ff0000 */
-	mov %ah, (__KERNEL_PDA+4+3)(%ecx)		/* base & 0xff000000 */
-	ret
-
-/*
  *  setup_idt
  *
  *  sets up a idt with 256 entries pointing to
@@ -554,9 +552,6 @@ ENTRY(empty_zero_page)
  * This starts the data section.
  */
 .data
-ENTRY(start_pda)
-	.long boot_pda
-
 ENTRY(stack_start)
 	.long init_thread_union+THREAD_SIZE
 	.long __BOOT_DS
@@ -588,7 +583,7 @@ # early boot GDT descriptor (must use 1:
 	.word 0				# 32 bit align gdt_desc.address
 boot_gdt_descr:
 	.word __BOOT_DS+7
-	.long boot_gdt_table - __PAGE_OFFSET
+	.long boot_gdt - __PAGE_OFFSET
 
 	.word 0				# 32-bit align idt_desc.address
 idt_descr:
@@ -599,67 +594,14 @@ # boot GDT descriptor (later on used by 
 	.word 0				# 32 bit align gdt_desc.address
 ENTRY(early_gdt_descr)
 	.word GDT_ENTRIES*8-1
-	.long cpu_gdt_table
+	.long per_cpu__gdt_page		/* Overwritten for secondary CPUs */
 
 /*
- * The boot_gdt_table must mirror the equivalent in setup.S and is
+ * The boot_gdt must mirror the equivalent in setup.S and is
  * used only for booting.
  */
 	.align L1_CACHE_BYTES
-ENTRY(boot_gdt_table)
+ENTRY(boot_gdt)
 	.fill GDT_ENTRY_BOOT_CS,8,0
 	.quad 0x00cf9a000000ffff	/* kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* kernel 4GB data at 0x00000000 */
-
-/*
- * The Global Descriptor Table contains 28 quadwords, per-CPU.
- */
-	.align L1_CACHE_BYTES
-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 0x00409a000000ffff	/* 0x90 32-bit code */
-	.quad 0x00009a000000ffff	/* 0x98 16-bit code */
-	.quad 0x000092000000ffff	/* 0xa0 16-bit data */
-	.quad 0x0000920000000000	/* 0xa8 16-bit data */
-	.quad 0x0000920000000000	/* 0xb0 16-bit data */
-
-	/*
-	 * The APM segments have byte granularity and their bases
-	 * are set at run time.  All have 64k limits.
-	 */
-	.quad 0x00409a000000ffff	/* 0xb8 APM CS    code */
-	.quad 0x00009a000000ffff	/* 0xc0 APM CS 16 code (16 bit) */
-	.quad 0x004092000000ffff	/* 0xc8 APM DS    data */
-
-	.quad 0x00c0920000000000	/* 0xd0 - ESPFIX SS */
-	.quad 0x00cf92000000ffff	/* 0xd8 - PDA */
-	.quad 0x0000000000000000	/* 0xe0 - unused */
-	.quad 0x0000000000000000	/* 0xe8 - unused */
-	.quad 0x0000000000000000	/* 0xf0 - unused */
-	.quad 0x0000000000000000	/* 0xf8 - GDT entry 31: double-fault TSS */
-
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 4afe26e..e3d4b73 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed);
 #endif
 
 EXPORT_SYMBOL(csum_partial);
-
-EXPORT_SYMBOL(_proxy_pda);
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index 10cef5c..f8a3c40 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -110,7 +110,7 @@ void __init setup_pit_timer(void)
 	 * Start pit with the boot cpu mask and make it global after the
 	 * IO_APIC has been initialized.
 	 */
-	pit_clockevent.cpumask = cpumask_of_cpu(0);
+	pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
 	pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
 	pit_clockevent.max_delta_ns =
 		clockevent_delta2ns(0x7FFF, &pit_clockevent);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 03abfdb..0499cbe 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -5,7 +5,6 @@ #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index b3ab8ff..7f8b7af 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -25,7 +25,6 @@ #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>
@@ -35,6 +34,7 @@ #include <linux/pci.h>
 #include <linux/msi.h>
 #include <linux/htirq.h>
 #include <linux/freezer.h>
+#include <linux/kthread.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -661,8 +661,6 @@ static int balanced_irq(void *unused)
 	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 = cpumask_of_cpu(0);
@@ -722,10 +720,9 @@ static int __init balanced_irq_init(void
 	}
 	
 	printk(KERN_INFO "Starting balanced_irq\n");
-	if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) 
+	if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd")))
 		return 0;
-	else 
-		printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
+	printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
 failed:
 	for_each_possible_cpu(i) {
 		kfree(irq_cpu_data[i].irq_delta);
@@ -1403,10 +1400,6 @@ static void __init setup_ExtINT_IRQ0_pin
 	enable_8259A_irq(0);
 }
 
-static inline void UNEXPECTED_IO_APIC(void)
-{
-}
-
 void __init print_IO_APIC(void)
 {
 	int apic, i;
@@ -1446,34 +1439,12 @@ void __init print_IO_APIC(void)
 	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,
@@ -1483,8 +1454,6 @@ void __init print_IO_APIC(void)
 	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();
 	}
 
 	/*
@@ -1496,8 +1465,6 @@ void __init print_IO_APIC(void)
 	    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");
@@ -2611,19 +2578,19 @@ int arch_setup_msi_irq(struct pci_dev *d
 	if (irq < 0)
 		return irq;
 
-	set_irq_msi(irq, desc);
 	ret = msi_compose_msg(dev, irq, &msg);
 	if (ret < 0) {
 		destroy_irq(irq);
 		return ret;
 	}
 
+	set_irq_msi(irq, desc);
 	write_msi_msg(irq, &msg);
 
 	set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
 				      "edge");
 
-	return irq;
+	return 0;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index 498e8bc..3d310a9 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -12,10 +12,10 @@ #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 <linux/syscalls.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)
@@ -113,7 +113,7 @@ asmlinkage long sys_ioperm(unsigned long
 	 * Reset the owner so that a process switch will not set
 	 * tss->io_bitmap_base to IO_BITMAP_OFFSET.
 	 */
-	tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
+	tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 	tss->io_bitmap_owner = NULL;
 
 	put_cpu();
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 8db8d51..d2daf67 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -24,6 +24,9 @@ #include <asm/uaccess.h>
 DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
 EXPORT_PER_CPU_SYMBOL(irq_stat);
 
+DEFINE_PER_CPU(struct pt_regs *, irq_regs);
+EXPORT_PER_CPU_SYMBOL(irq_regs);
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index b545bc7..dde828a 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -31,8 +31,8 @@
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
+#include <linux/kdebug.h>
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
 #include <asm/desc.h>
 #include <asm/uaccess.h>
 
@@ -226,24 +226,15 @@ static void __kprobes prepare_singlestep
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 				      struct pt_regs *regs)
 {
 	unsigned long *sara = (unsigned long *)&regs->esp;
 
-	struct kretprobe_instance *ri;
+	ri->ret_addr = (kprobe_opcode_t *) *sara;
 
-	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++;
-	}
+	/* Replace the return addr with trampoline addr */
+	*sara = (unsigned long) &kretprobe_trampoline;
 }
 
 /*
@@ -449,8 +440,7 @@ fastcall void *__kprobes trampoline_hand
 			break;
 	}
 
-	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
-
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
 	spin_unlock_irqrestore(&kretprobe_lock, flags);
 
 	hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
@@ -753,6 +743,11 @@ int __kprobes longjmp_break_handler(stru
 	return 0;
 }
 
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	return 0;
+}
+
 int __init arch_init_kprobes(void)
 {
 	return 0;
diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
index b410e5f..e0b2d17 100644
--- a/arch/i386/kernel/ldt.c
+++ b/arch/i386/kernel/ldt.c
@@ -10,7 +10,6 @@ #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>
 
diff --git a/arch/i386/kernel/legacy_serial.c b/arch/i386/kernel/legacy_serial.c
new file mode 100644
index 0000000..2151011
--- /dev/null
+++ b/arch/i386/kernel/legacy_serial.c
@@ -0,0 +1,67 @@
+/*
+ * Legacy COM port devices for x86 platforms without PNPBIOS or ACPI.
+ * Data taken from include/asm-i386/serial.h.
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *	Bjorn Helgaas <bjorn.helgaas@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/init.h>
+#include <linux/pnp.h>
+#include <linux/serial_8250.h>
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
+#else
+#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define COM4_FLAGS UPF_BOOT_AUTOCONF
+#endif
+
+#define PORT(_base,_irq,_flags)				\
+	{						\
+		.iobase		= _base,		\
+		.irq		= _irq,			\
+		.uartclk	= 1843200,		\
+		.iotype		= UPIO_PORT,		\
+		.flags		= _flags,		\
+	}
+
+static struct plat_serial8250_port x86_com_data[] = {
+	PORT(0x3F8, 4, COM_FLAGS),
+	PORT(0x2F8, 3, COM_FLAGS),
+	PORT(0x3E8, 4, COM_FLAGS),
+	PORT(0x2E8, 3, COM4_FLAGS),
+	{ },
+};
+
+static struct platform_device x86_com_device = {
+	.name			= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev			= {
+		.platform_data	= x86_com_data,
+	},
+};
+
+static int force_legacy_probe;
+module_param_named(force, force_legacy_probe, bool, 0);
+MODULE_PARM_DESC(force, "Force legacy serial port probe");
+
+static int __init serial8250_x86_com_init(void)
+{
+	if (pnp_platform_devices && !force_legacy_probe)
+		return -ENODEV;
+
+	return platform_device_register(&x86_com_device);
+}
+
+module_init(serial8250_x86_com_init);
+
+MODULE_AUTHOR("Bjorn Helgaas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 legacy probe module");
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 4f5983c..13abb4e 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -18,7 +18,6 @@ #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>
@@ -477,7 +476,7 @@ static int __init smp_read_mpc(struct mp
 		}
 		++mpc_record;
 	}
-	clustered_apic_check();
+	setup_apic_routing();
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index bcaa6e9..8cd0a91 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -45,104 +45,6 @@ #include <asm/system.h>
 
 static struct class *msr_class;
 
-static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
-{
-	int err;
-
-	err = wrmsr_safe(reg, eax, edx);
-	if (err)
-		err = -EIO;
-	return err;
-}
-
-static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
-{
-	int err;
-
-	err = rdmsr_safe(reg, eax, edx);
-	if (err)
-		err = -EIO;
-	return err;
-}
-
-#ifdef CONFIG_SMP
-
-struct msr_command {
-	int err;
-	u32 reg;
-	u32 data[2];
-};
-
-static void msr_smp_wrmsr(void *cmd_block)
-{
-	struct msr_command *cmd = (struct msr_command *)cmd_block;
-
-	cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
-}
-
-static void msr_smp_rdmsr(void *cmd_block)
-{
-	struct msr_command *cmd = (struct msr_command *)cmd_block;
-
-	cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
-}
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
-	struct msr_command cmd;
-	int ret;
-
-	preempt_disable();
-	if (cpu == smp_processor_id()) {
-		ret = wrmsr_eio(reg, eax, edx);
-	} else {
-		cmd.reg = reg;
-		cmd.data[0] = eax;
-		cmd.data[1] = edx;
-
-		smp_call_function_single(cpu, msr_smp_wrmsr, &cmd, 1, 1);
-		ret = cmd.err;
-	}
-	preempt_enable();
-	return ret;
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx)
-{
-	struct msr_command cmd;
-	int ret;
-
-	preempt_disable();
-	if (cpu == smp_processor_id()) {
-		ret = rdmsr_eio(reg, eax, edx);
-	} else {
-		cmd.reg = reg;
-
-		smp_call_function_single(cpu, msr_smp_rdmsr, &cmd, 1, 1);
-
-		*eax = cmd.data[0];
-		*edx = cmd.data[1];
-
-		ret = cmd.err;
-	}
-	preempt_enable();
-	return ret;
-}
-
-#else				/* ! CONFIG_SMP */
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
-	return wrmsr_eio(reg, eax, edx);
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
-{
-	return rdmsr_eio(reg, eax, edx);
-}
-
-#endif				/* ! CONFIG_SMP */
-
 static loff_t msr_seek(struct file *file, loff_t offset, int orig)
 {
 	loff_t ret = -EINVAL;
@@ -174,9 +76,9 @@ static ssize_t msr_read(struct file *fil
 		return -EINVAL;	/* Invalid chunk size */
 
 	for (; count; count -= 8) {
-		err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+		err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
 		if (err)
-			return err;
+			return -EIO;
 		if (copy_to_user(tmp, &data, 8))
 			return -EFAULT;
 		tmp += 2;
@@ -200,9 +102,9 @@ static ssize_t msr_write(struct file *fi
 	for (; count; count -= 8) {
 		if (copy_from_user(&data, tmp, 8))
 			return -EFAULT;
-		err = do_wrmsr(cpu, reg, data[0], data[1]);
+		err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
 		if (err)
-			return err;
+			return -EIO;
 		tmp += 2;
 	}
 
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 84c3497..fba121f 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -20,38 +20,21 @@ #include <linux/nmi.h>
 #include <linux/sysdev.h>
 #include <linux/sysctl.h>
 #include <linux/percpu.h>
-#include <linux/dmi.h>
 #include <linux/kprobes.h>
 #include <linux/cpumask.h>
 #include <linux/kernel_stat.h>
+#include <linux/kdebug.h>
 
 #include <asm/smp.h>
 #include <asm/nmi.h>
-#include <asm/kdebug.h>
-#include <asm/intel_arch_perfmon.h>
 
 #include "mach_traps.h"
 
 int unknown_nmi_panic;
 int nmi_watchdog_enabled;
 
-/* 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
- */
-
-/* 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
-#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS)
-
-static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-
 static cpumask_t backtrace_mask = CPU_MASK_NONE;
+
 /* nmi_active:
  * >0: the lapic NMI watchdog is active, but can be disabled
  * <0: the lapic NMI watchdog has not been set up, and cannot
@@ -63,206 +46,11 @@ atomic_t nmi_active = ATOMIC_INIT(0);		/
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
 
-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);
+static DEFINE_PER_CPU(short, wd_enabled);
 
 /* local prototypes */
 static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
 
-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)
-{
-	int cpu;
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-	for_each_possible_cpu (cpu) {
-		if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
-			return 0;
-	}
-	return 1;
-}
-
-/* checks the an msr for availability */
-int avail_to_resrv_perfctr_nmi(unsigned int msr)
-{
-	unsigned int counter;
-	int cpu;
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	for_each_possible_cpu (cpu) {
-		if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
-			return 0;
-	}
-	return 1;
-}
-
-static int __reserve_perfctr_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
-		return 1;
-	return 0;
-}
-
-static void __release_perfctr_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]);
-}
-
-int reserve_perfctr_nmi(unsigned int msr)
-{
-	int cpu, i;
-	for_each_possible_cpu (cpu) {
-		if (!__reserve_perfctr_nmi(cpu, msr)) {
-			for_each_possible_cpu (i) {
-				if (i >= cpu)
-					break;
-				__release_perfctr_nmi(i, msr);
-			}
-			return 0;
-		}
-	}
-	return 1;
-}
-
-void release_perfctr_nmi(unsigned int msr)
-{
-	int cpu;
-	for_each_possible_cpu (cpu) {
-		__release_perfctr_nmi(cpu, msr);
-	}
-}
-
-int __reserve_evntsel_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_evntsel_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]))
-		return 1;
-	return 0;
-}
-
-static void __release_evntsel_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_evntsel_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]);
-}
-
-int reserve_evntsel_nmi(unsigned int msr)
-{
-	int cpu, i;
-	for_each_possible_cpu (cpu) {
-		if (!__reserve_evntsel_nmi(cpu, msr)) {
-			for_each_possible_cpu (i) {
-				if (i >= cpu)
-					break;
-				__release_evntsel_nmi(i, msr);
-			}
-			return 0;
-		}
-	}
-	return 1;
-}
-
-void release_evntsel_nmi(unsigned int msr)
-{
-	int cpu;
-	for_each_possible_cpu (cpu) {
-		__release_evntsel_nmi(cpu, msr);
-	}
-}
-
-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)
-			|| (boot_cpu_data.x86 == 16));
-	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;
-}
-
 static int endflag __initdata = 0;
 
 #ifdef CONFIG_SMP
@@ -284,28 +72,6 @@ static __init void nmi_cpu_busy(void *da
 }
 #endif
 
-static unsigned int adjust_for_32bit_ctr(unsigned int hz)
-{
-	u64 counter_val;
-	unsigned int retval = hz;
-
-	/*
-	 * On Intel CPUs with P6/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
-	 */
-	counter_val = (u64)cpu_khz * 1000;
-	do_div(counter_val, retval);
- 	if (counter_val > 0x7fffffffULL) {
-		u64 count = (u64)cpu_khz * 1000;
-		do_div(count, 0x7fffffffUL);
-		retval = count + 1;
-	}
-	return retval;
-}
-
 static int __init check_nmi_watchdog(void)
 {
 	unsigned int *prev_nmi_count;
@@ -338,14 +104,14 @@ #ifdef CONFIG_SMP
 		if (!cpu_isset(cpu, cpu_callin_map))
 			continue;
 #endif
-		if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
+		if (!per_cpu(wd_enabled, cpu))
 			continue;
 		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
 				cpu,
 				prev_nmi_count[cpu],
 				nmi_count(cpu));
-			per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
+			per_cpu(wd_enabled, cpu) = 0;
 			atomic_dec(&nmi_active);
 		}
 	}
@@ -359,16 +125,8 @@ #endif
 
 	/* 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) {
-		struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
-		nmi_hz = 1;
-
-		if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
-		    wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
-			nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-		}
-	}
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		nmi_hz = lapic_adjust_nmi_hz(1);
 
 	kfree(prev_nmi_count);
 	return 0;
@@ -391,85 +149,8 @@ static int __init setup_nmi_watchdog(cha
 
 __setup("nmi_watchdog=", setup_nmi_watchdog);
 
-static void disable_lapic_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
-	if (atomic_read(&nmi_active) <= 0)
-		return;
-
-	on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
-	BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-static void enable_lapic_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
-	/* are we already enabled */
-	if (atomic_read(&nmi_active) != 0)
-		return;
-
-	/* are we lapic aware */
-	if (nmi_known_cpu() <= 0)
-		return;
 
-	on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
-	touch_nmi_watchdog();
-}
-
-void disable_timer_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
-	if (atomic_read(&nmi_active) <= 0)
-		return;
-
-	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)
-{
-	BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
-	if (atomic_read(&nmi_active) == 0) {
-		touch_nmi_watchdog();
-		on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
-		enable_irq(0);
-	}
-}
-
-static void __acpi_nmi_disable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
-/*
- * Disable timer based NMIs on all CPUs:
- */
-void acpi_nmi_disable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
-}
-
-static void __acpi_nmi_enable(void *__unused)
-{
-	apic_write_around(APIC_LVT0, APIC_DM_NMI);
-}
-
-/*
- * Enable timer based NMIs on all CPUs:
- */
-void acpi_nmi_enable(void)
-{
-	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
-		on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
-}
+/* Suspend/resume support */
 
 #ifdef CONFIG_PM
 
@@ -516,7 +197,7 @@ static int __init init_lapic_nmi_sysfs(v
 	if (nmi_watchdog != NMI_LOCAL_APIC)
 		return 0;
 
-	if ( atomic_read(&nmi_active) < 0 )
+	if (atomic_read(&nmi_active) < 0)
 		return 0;
 
 	error = sysdev_class_register(&nmi_sysclass);
@@ -529,433 +210,69 @@ late_initcall(init_lapic_nmi_sysfs);
 
 #endif	/* CONFIG_PM */
 
-/*
- * Activate the NMI watchdog via the local APIC.
- * Original code written by Keith Owens.
- */
-
-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(perfctr_msr, 0 - count);
-}
-
-static void write_watchdog_counter32(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);
-	wrmsr(perfctr_msr, (u32)(-count), 0);
-}
-
-/* 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(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, evntsel_msr))
-		goto fail1;
-
-	wrmsrl(perfctr_msr, 0UL);
-
-	evntsel = K7_EVNTSEL_INT
-		| K7_EVNTSEL_OS
-		| K7_EVNTSEL_USR
-		| K7_NMI_EVENT;
-
-	/* 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(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(-1, 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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
-#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(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, evntsel_msr))
-		goto fail1;
-
-	wrmsrl(perfctr_msr, 0UL);
-
-	evntsel = P6_EVNTSEL_INT
-		| P6_EVNTSEL_OS
-		| P6_EVNTSEL_USR
-		| P6_NMI_EVENT;
-
-	/* setup the timer */
-	wrmsr(evntsel_msr, evntsel, 0);
-	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-	write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0");
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	evntsel |= P6_EVNTSEL0_ENABLE;
-	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(-1, 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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, 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)
+static void __acpi_nmi_enable(void *__unused)
 {
-	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)
-	 */
-	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(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, 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);
-	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(-1, perfctr_msr);
-fail:
-	return 0;
+	apic_write_around(APIC_LVT0, APIC_DM_NMI);
 }
 
-static void stop_p4_watchdog(void)
+/*
+ * Enable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_enable(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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, wd->perfctr_msr);
+	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+		on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
 }
 
-#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)
+static void __acpi_nmi_disable(void *__unused)
 {
-	unsigned int ebx;
-	union cpuid10_eax eax;
-	unsigned int unused;
-	unsigned int perfctr_msr, evntsel_msr;
-	unsigned int evntsel;
-	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))
-		goto fail;
-
-	perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
-	evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
-
-	if (!__reserve_perfctr_nmi(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, evntsel_msr))
-		goto fail1;
-
-	wrmsrl(perfctr_msr, 0UL);
-
-	evntsel = ARCH_PERFMON_EVENTSEL_INT
-		| ARCH_PERFMON_EVENTSEL_OS
-		| ARCH_PERFMON_EVENTSEL_USR
-		| ARCH_PERFMON_NMI_EVENT_SEL
-		| ARCH_PERFMON_NMI_EVENT_UMASK;
-
-	/* setup the timer */
-	wrmsr(evntsel_msr, evntsel, 0);
-	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-	write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0");
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
-	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(-1, perfctr_msr);
-fail:
-	return 0;
+	apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
 }
 
-static void stop_intel_arch_watchdog(void)
+/*
+ * Disable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_disable(void)
 {
-	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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, wd->perfctr_msr);
+	if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+		on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
 }
 
 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;
+	if (__get_cpu_var(wd_enabled))
+ 		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 &&
-				boot_cpu_data.x86 != 16)
-				return;
-			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;
-			}
-			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())
-					return;
-				break;
-			default:
-				return;
-			}
-			break;
-		default:
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		__get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */
+		if (lapic_watchdog_init(nmi_hz) < 0) {
+			__get_cpu_var(wd_enabled) = 0;
 			return;
 		}
+		/* FALL THROUGH */
+	case NMI_IO_APIC:
+		__get_cpu_var(wd_enabled) = 1;
+		atomic_inc(&nmi_active);
 	}
-	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)
+	if (__get_cpu_var(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;
-		}
-	}
-	wd->enabled = 0;
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		lapic_watchdog_stop();
+	__get_cpu_var(wd_enabled) = 0;
 	atomic_dec(&nmi_active);
 }
 
@@ -1011,8 +328,6 @@ __kprobes int nmi_watchdog_tick(struct p
 	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 */
@@ -1055,53 +370,20 @@ __kprobes int nmi_watchdog_tick(struct p
 		alert_counter[cpu] = 0;
 	}
 	/* 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);
-				/* start the cycle over again */
-				write_watchdog_counter(wd->perfctr_msr, NULL);
-	 		}
-			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);
-				/* P6/ARCH_PERFMON has 32 bit counter write */
-				write_watchdog_counter32(wd->perfctr_msr, NULL);
-			} else {
-				/* 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.
-			 */
-			rc = 1;
-		}
+	if (!__get_cpu_var(wd_enabled))
+		return rc;
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		rc |= lapic_wd_event(nmi_hz);
+		break;
+	case 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.
+		 */
+		rc = 1;
+		break;
 	}
-done:
 	return rc;
 }
 
@@ -1146,7 +428,7 @@ int proc_nmi_enabled(struct ctl_table *t
 	}
 
 	if (nmi_watchdog == NMI_DEFAULT) {
-		if (nmi_known_cpu() > 0)
+		if (lapic_watchdog_ok())
 			nmi_watchdog = NMI_LOCAL_APIC;
 		else
 			nmi_watchdog = NMI_IO_APIC;
@@ -1182,11 +464,3 @@ void __trigger_all_cpu_backtrace(void)
 
 EXPORT_SYMBOL(nmi_active);
 EXPORT_SYMBOL(nmi_watchdog);
-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/paravirt.c b/arch/i386/kernel/paravirt.c
index 2ec331e..5c10f37 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -20,6 +20,7 @@ #include <linux/module.h>
 #include <linux/efi.h>
 #include <linux/bcd.h>
 #include <linux/start_kernel.h>
+#include <linux/highmem.h>
 
 #include <asm/bug.h>
 #include <asm/paravirt.h>
@@ -35,7 +36,7 @@ #include <asm/tlbflush.h>
 #include <asm/timer.h>
 
 /* nop stub */
-static void native_nop(void)
+void _paravirt_nop(void)
 {
 }
 
@@ -54,331 +55,148 @@ char *memory_setup(void)
 #define DEF_NATIVE(name, code)					\
 	extern const char start_##name[], end_##name[];		\
 	asm("start_" #name ": " code "; end_" #name ":")
-DEF_NATIVE(cli, "cli");
-DEF_NATIVE(sti, "sti");
-DEF_NATIVE(popf, "push %eax; popf");
-DEF_NATIVE(pushf, "pushf; pop %eax");
-DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli");
+
+DEF_NATIVE(irq_disable, "cli");
+DEF_NATIVE(irq_enable, "sti");
+DEF_NATIVE(restore_fl, "push %eax; popf");
+DEF_NATIVE(save_fl, "pushf; pop %eax");
 DEF_NATIVE(iret, "iret");
-DEF_NATIVE(sti_sysexit, "sti; sysexit");
+DEF_NATIVE(irq_enable_sysexit, "sti; sysexit");
+DEF_NATIVE(read_cr2, "mov %cr2, %eax");
+DEF_NATIVE(write_cr3, "mov %eax, %cr3");
+DEF_NATIVE(read_cr3, "mov %cr3, %eax");
+DEF_NATIVE(clts, "clts");
+DEF_NATIVE(read_tsc, "rdtsc");
 
-static const struct native_insns
-{
-	const char *start, *end;
-} native_insns[] = {
-	[PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli },
-	[PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti },
-	[PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf },
-	[PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf },
-	[PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli },
-	[PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret },
-	[PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit },
-};
+DEF_NATIVE(ud2a, "ud2a");
 
 static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len)
 {
-	unsigned int insn_len;
-
-	/* Don't touch it if we don't have a replacement */
-	if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start)
-		return len;
-
-	insn_len = native_insns[type].end - native_insns[type].start;
-
-	/* Similarly if we can't fit replacement. */
-	if (len < insn_len)
-		return len;
+	const unsigned char *start, *end;
+	unsigned ret;
+
+	switch(type) {
+#define SITE(x)	case PARAVIRT_PATCH(x):	start = start_##x; end = end_##x; goto patch_site
+		SITE(irq_disable);
+		SITE(irq_enable);
+		SITE(restore_fl);
+		SITE(save_fl);
+		SITE(iret);
+		SITE(irq_enable_sysexit);
+		SITE(read_cr2);
+		SITE(read_cr3);
+		SITE(write_cr3);
+		SITE(clts);
+		SITE(read_tsc);
+#undef SITE
+
+	patch_site:
+		ret = paravirt_patch_insns(insns, len, start, end);
+		break;
 
-	memcpy(insns, native_insns[type].start, insn_len);
-	return insn_len;
-}
+	case PARAVIRT_PATCH(make_pgd):
+	case PARAVIRT_PATCH(make_pte):
+	case PARAVIRT_PATCH(pgd_val):
+	case PARAVIRT_PATCH(pte_val):
+#ifdef CONFIG_X86_PAE
+	case PARAVIRT_PATCH(make_pmd):
+	case PARAVIRT_PATCH(pmd_val):
+#endif
+		/* These functions end up returning exactly what
+		   they're passed, in the same registers. */
+		ret = paravirt_patch_nop();
+		break;
 
-static unsigned long native_get_debugreg(int regno)
-{
-	unsigned long val = 0; 	/* Damn you, gcc! */
-
-	switch (regno) {
-	case 0:
-		asm("movl %%db0, %0" :"=r" (val)); break;
-	case 1:
-		asm("movl %%db1, %0" :"=r" (val)); break;
-	case 2:
-		asm("movl %%db2, %0" :"=r" (val)); break;
-	case 3:
-		asm("movl %%db3, %0" :"=r" (val)); break;
-	case 6:
-		asm("movl %%db6, %0" :"=r" (val)); break;
-	case 7:
-		asm("movl %%db7, %0" :"=r" (val)); break;
 	default:
-		BUG();
-	}
-	return val;
-}
-
-static void native_set_debugreg(int regno, unsigned long value)
-{
-	switch (regno) {
-	case 0:
-		asm("movl %0,%%db0"	: /* no output */ :"r" (value));
-		break;
-	case 1:
-		asm("movl %0,%%db1"	: /* no output */ :"r" (value));
-		break;
-	case 2:
-		asm("movl %0,%%db2"	: /* no output */ :"r" (value));
+		ret = paravirt_patch_default(type, clobbers, insns, len);
 		break;
-	case 3:
-		asm("movl %0,%%db3"	: /* no output */ :"r" (value));
-		break;
-	case 6:
-		asm("movl %0,%%db6"	: /* no output */ :"r" (value));
-		break;
-	case 7:
-		asm("movl %0,%%db7"	: /* no output */ :"r" (value));
-		break;
-	default:
-		BUG();
 	}
-}
-
-void init_IRQ(void)
-{
-	paravirt_ops.init_IRQ();
-}
-
-static void native_clts(void)
-{
-	asm volatile ("clts");
-}
-
-static unsigned long native_read_cr0(void)
-{
-	unsigned long val;
-	asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
-	return val;
-}
-
-static void native_write_cr0(unsigned long val)
-{
-	asm volatile("movl %0,%%cr0": :"r" (val));
-}
-
-static unsigned long native_read_cr2(void)
-{
-	unsigned long val;
-	asm volatile("movl %%cr2,%0\n\t" :"=r" (val));
-	return val;
-}
-
-static void native_write_cr2(unsigned long val)
-{
-	asm volatile("movl %0,%%cr2": :"r" (val));
-}
-
-static unsigned long native_read_cr3(void)
-{
-	unsigned long val;
-	asm volatile("movl %%cr3,%0\n\t" :"=r" (val));
-	return val;
-}
-
-static void native_write_cr3(unsigned long val)
-{
-	asm volatile("movl %0,%%cr3": :"r" (val));
-}
-
-static unsigned long native_read_cr4(void)
-{
-	unsigned long val;
-	asm volatile("movl %%cr4,%0\n\t" :"=r" (val));
-	return val;
-}
-
-static unsigned long native_read_cr4_safe(void)
-{
-	unsigned long val;
-	/* 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" (val): "0" (0));
-	return val;
-}
-
-static void native_write_cr4(unsigned long val)
-{
-	asm volatile("movl %0,%%cr4": :"r" (val));
-}
-
-static unsigned long native_save_fl(void)
-{
-	unsigned long f;
-	asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);
-	return f;
-}
-
-static void native_restore_fl(unsigned long f)
-{
-	asm volatile("pushl %0 ; popfl": /* no output */
-			     :"g" (f)
-			     :"memory", "cc");
-}
-
-static void native_irq_disable(void)
-{
-	asm volatile("cli": : :"memory");
-}
-
-static void native_irq_enable(void)
-{
-	asm volatile("sti": : :"memory");
-}
-
-static void native_safe_halt(void)
-{
-	asm volatile("sti; hlt": : :"memory");
-}
 
-static void native_halt(void)
-{
-	asm volatile("hlt": : :"memory");
+	return ret;
 }
 
-static void native_wbinvd(void)
+unsigned paravirt_patch_nop(void)
 {
-	asm volatile("wbinvd": : :"memory");
+	return 0;
 }
 
-static unsigned long long native_read_msr(unsigned int msr, int *err)
+unsigned paravirt_patch_ignore(unsigned len)
 {
-	unsigned long long val;
-
-	asm volatile("2: rdmsr ; xorl %0,%0\n"
-		     "1:\n\t"
-		     ".section .fixup,\"ax\"\n\t"
-		     "3:  movl %3,%0 ; jmp 1b\n\t"
-		     ".previous\n\t"
- 		     ".section __ex_table,\"a\"\n"
-		     "   .align 4\n\t"
-		     "   .long 	2b,3b\n\t"
-		     ".previous"
-		     : "=r" (*err), "=A" (val)
-		     : "c" (msr), "i" (-EFAULT));
-
-	return val;
+	return len;
 }
 
-static int native_write_msr(unsigned int msr, unsigned long long val)
+unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
+			     void *site, u16 site_clobbers,
+			     unsigned len)
 {
-	int err;
-	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 4\n\t"
-		     "   .long 	2b,3b\n\t"
-		     ".previous"
-		     : "=a" (err)
-		     : "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)),
-		       "i" (-EFAULT));
-	return err;
-}
+	unsigned char *call = site;
+	unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
 
-static unsigned long long native_read_tsc(void)
-{
-	unsigned long long val;
-	asm volatile("rdtsc" : "=A" (val));
-	return val;
-}
+	if (tgt_clobbers & ~site_clobbers)
+		return len;	/* target would clobber too much for this site */
+	if (len < 5)
+		return len;	/* call too long for patch site */
 
-static unsigned long long native_read_pmc(void)
-{
-	unsigned long long val;
-	asm volatile("rdpmc" : "=A" (val));
-	return val;
-}
+	*call++ = 0xe8;		/* call */
+	*(unsigned long *)call = delta;
 
-static void native_load_tr_desc(void)
-{
-	asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
+	return 5;
 }
 
-static void native_load_gdt(const struct Xgt_desc_struct *dtr)
+unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
 {
-	asm volatile("lgdt %0"::"m" (*dtr));
-}
+	unsigned char *jmp = site;
+	unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);
 
-static void native_load_idt(const struct Xgt_desc_struct *dtr)
-{
-	asm volatile("lidt %0"::"m" (*dtr));
-}
+	if (len < 5)
+		return len;	/* call too long for patch site */
 
-static void native_store_gdt(struct Xgt_desc_struct *dtr)
-{
-	asm ("sgdt %0":"=m" (*dtr));
-}
+	*jmp++ = 0xe9;		/* jmp */
+	*(unsigned long *)jmp = delta;
 
-static void native_store_idt(struct Xgt_desc_struct *dtr)
-{
-	asm ("sidt %0":"=m" (*dtr));
+	return 5;
 }
 
-static unsigned long native_store_tr(void)
+unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
 {
-	unsigned long tr;
-	asm ("str %0":"=r" (tr));
-	return tr;
-}
+	void *opfunc = *((void **)&paravirt_ops + type);
+	unsigned ret;
 
-static void native_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
-}
+	if (opfunc == NULL)
+		/* If there's no function, patch it with a ud2a (BUG) */
+		ret = paravirt_patch_insns(site, len, start_ud2a, end_ud2a);
+	else if (opfunc == paravirt_nop)
+		/* If the operation is a nop, then nop the callsite */
+		ret = paravirt_patch_nop();
+	else if (type == PARAVIRT_PATCH(iret) ||
+		 type == PARAVIRT_PATCH(irq_enable_sysexit))
+		/* If operation requires a jmp, then jmp */
+		ret = paravirt_patch_jmp(opfunc, site, len);
+	else
+		/* Otherwise call the function; assume target could
+		   clobber any caller-save reg */
+		ret = paravirt_patch_call(opfunc, CLBR_ANY,
+					  site, clobbers, len);
 
-static inline void native_write_dt_entry(void *dt, int entry, u32 entry_low, u32 entry_high)
-{
-	u32 *lp = (u32 *)((char *)dt + entry*8);
-	lp[0] = entry_low;
-	lp[1] = entry_high;
+	return ret;
 }
 
-static void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high)
+unsigned paravirt_patch_insns(void *site, unsigned len,
+			      const char *start, const char *end)
 {
-	native_write_dt_entry(dt, entrynum, low, high);
-}
+	unsigned insn_len = end - start;
 
-static void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high)
-{
-	native_write_dt_entry(dt, entrynum, low, high);
-}
-
-static void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high)
-{
-	native_write_dt_entry(dt, entrynum, low, high);
-}
+	if (insn_len > len || start == NULL)
+		insn_len = len;
+	else
+		memcpy(site, start, insn_len);
 
-static void native_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);
-	}
+	return insn_len;
 }
 
-static void native_io_delay(void)
+void init_IRQ(void)
 {
-	asm volatile("outb %al,$0x80");
+	paravirt_ops.init_IRQ();
 }
 
 static void native_flush_tlb(void)
@@ -395,83 +213,11 @@ static void native_flush_tlb_global(void
 	__native_flush_tlb_global();
 }
 
-static void native_flush_tlb_single(u32 addr)
+static void native_flush_tlb_single(unsigned long addr)
 {
 	__native_flush_tlb_single(addr);
 }
 
-#ifndef CONFIG_X86_PAE
-static void native_set_pte(pte_t *ptep, pte_t pteval)
-{
-	*ptep = pteval;
-}
-
-static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval)
-{
-	*ptep = pteval;
-}
-
-static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
-	*pmdp = pmdval;
-}
-
-#else /* CONFIG_X86_PAE */
-
-static void native_set_pte(pte_t *ptep, pte_t pte)
-{
-	ptep->pte_high = pte.pte_high;
-	smp_wmb();
-	ptep->pte_low = pte.pte_low;
-}
-
-static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte)
-{
-	ptep->pte_high = pte.pte_high;
-	smp_wmb();
-	ptep->pte_low = pte.pte_low;
-}
-
-static void native_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;
-}
-
-static void native_set_pte_atomic(pte_t *ptep, pte_t pteval)
-{
-	set_64bit((unsigned long long *)ptep,pte_val(pteval));
-}
-
-static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
-	set_64bit((unsigned long long *)pmdp,pmd_val(pmdval));
-}
-
-static void native_set_pud(pud_t *pudp, pud_t pudval)
-{
-	*pudp = pudval;
-}
-
-static void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-	ptep->pte_low = 0;
-	smp_wmb();
-	ptep->pte_high = 0;
-}
-
-static void native_pmd_clear(pmd_t *pmd)
-{
-	u32 *tmp = (u32 *)pmd;
-	*tmp = 0;
-	smp_wmb();
-	*(tmp + 1) = 0;
-}
-#endif /* CONFIG_X86_PAE */
-
 /* These are in entry.S */
 extern void native_iret(void);
 extern void native_irq_enable_sysexit(void);
@@ -487,10 +233,11 @@ struct paravirt_ops paravirt_ops = {
 	.name = "bare hardware",
 	.paravirt_enabled = 0,
 	.kernel_rpl = 0,
+	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
 
  	.patch = native_patch,
 	.banner = default_banner,
-	.arch_setup = native_nop,
+	.arch_setup = paravirt_nop,
 	.memory_setup = machine_specific_memory_setup,
 	.get_wallclock = native_get_wallclock,
 	.set_wallclock = native_set_wallclock,
@@ -517,8 +264,8 @@ struct paravirt_ops paravirt_ops = {
 	.safe_halt = native_safe_halt,
 	.halt = native_halt,
 	.wbinvd = native_wbinvd,
-	.read_msr = native_read_msr,
-	.write_msr = native_write_msr,
+	.read_msr = native_read_msr_safe,
+	.write_msr = native_write_msr_safe,
 	.read_tsc = native_read_tsc,
 	.read_pmc = native_read_pmc,
 	.get_scheduled_cycles = native_read_tsc,
@@ -531,9 +278,9 @@ struct paravirt_ops paravirt_ops = {
 	.store_idt = native_store_idt,
 	.store_tr = native_store_tr,
 	.load_tls = native_load_tls,
-	.write_ldt_entry = native_write_ldt_entry,
-	.write_gdt_entry = native_write_gdt_entry,
-	.write_idt_entry = native_write_idt_entry,
+	.write_ldt_entry = write_dt_entry,
+	.write_gdt_entry = write_dt_entry,
+	.write_idt_entry = write_dt_entry,
 	.load_esp0 = native_load_esp0,
 
 	.set_iopl_mask = native_set_iopl_mask,
@@ -545,44 +292,57 @@ #ifdef CONFIG_X86_LOCAL_APIC
 	.apic_read = native_apic_read,
 	.setup_boot_clock = setup_boot_APIC_clock,
 	.setup_secondary_clock = setup_secondary_APIC_clock,
+	.startup_ipi_hook = paravirt_nop,
 #endif
-	.set_lazy_mode = (void *)native_nop,
+	.set_lazy_mode = paravirt_nop,
+
+	.pagetable_setup_start = native_pagetable_setup_start,
+	.pagetable_setup_done = native_pagetable_setup_done,
 
 	.flush_tlb_user = native_flush_tlb,
 	.flush_tlb_kernel = native_flush_tlb_global,
 	.flush_tlb_single = native_flush_tlb_single,
+	.flush_tlb_others = native_flush_tlb_others,
 
-	.map_pt_hook = (void *)native_nop,
-
-	.alloc_pt = (void *)native_nop,
-	.alloc_pd = (void *)native_nop,
-	.alloc_pd_clone = (void *)native_nop,
-	.release_pt = (void *)native_nop,
-	.release_pd = (void *)native_nop,
+	.alloc_pt = paravirt_nop,
+	.alloc_pd = paravirt_nop,
+	.alloc_pd_clone = paravirt_nop,
+	.release_pt = paravirt_nop,
+	.release_pd = paravirt_nop,
 
 	.set_pte = native_set_pte,
 	.set_pte_at = native_set_pte_at,
 	.set_pmd = native_set_pmd,
-	.pte_update = (void *)native_nop,
-	.pte_update_defer = (void *)native_nop,
+	.pte_update = paravirt_nop,
+	.pte_update_defer = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+	.kmap_atomic_pte = kmap_atomic,
+#endif
+
 #ifdef CONFIG_X86_PAE
 	.set_pte_atomic = native_set_pte_atomic,
 	.set_pte_present = native_set_pte_present,
 	.set_pud = native_set_pud,
 	.pte_clear = native_pte_clear,
 	.pmd_clear = native_pmd_clear,
+
+	.pmd_val = native_pmd_val,
+	.make_pmd = native_make_pmd,
 #endif
 
+	.pte_val = native_pte_val,
+	.pgd_val = native_pgd_val,
+
+	.make_pte = native_make_pte,
+	.make_pgd = native_make_pgd,
+
 	.irq_enable_sysexit = native_irq_enable_sysexit,
 	.iret = native_iret,
 
-	.startup_ipi_hook = (void *)native_nop,
+	.dup_mmap = paravirt_nop,
+	.exit_mmap = paravirt_nop,
+	.activate_mm = paravirt_nop,
 };
 
-/*
- * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops
- * semantics are subject to change. Hence we only do this
- * internal-only export of this, until it gets sorted out and
- * all lowlevel CPU ops used by modules are separately exported.
- */
-EXPORT_SYMBOL_GPL(paravirt_ops);
+EXPORT_SYMBOL(paravirt_ops);
diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
index 3ebcea0..30b754f 100644
--- a/arch/i386/kernel/pci-dma.c
+++ b/arch/i386/kernel/pci-dma.c
@@ -77,7 +77,7 @@ int dma_declare_coherent_memory(struct d
 {
 	void __iomem *mem_base = NULL;
 	int pages = size >> PAGE_SHIFT;
-	int bitmap_size = (pages + 31)/32;
+	int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
 
 	if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
 		goto out;
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 393a67d..d76d9bc 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -21,7 +21,6 @@ #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>
@@ -39,6 +38,7 @@ #include <linux/ptrace.h>
 #include <linux/random.h>
 #include <linux/personality.h>
 #include <linux/tick.h>
+#include <linux/percpu.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -57,7 +57,6 @@ #include <linux/err.h>
 
 #include <asm/tlbflush.h>
 #include <asm/cpu.h>
-#include <asm/pda.h>
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
@@ -66,6 +65,12 @@ static int hlt_counter;
 unsigned long boot_option_idle_override = 0;
 EXPORT_SYMBOL(boot_option_idle_override);
 
+DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
+EXPORT_PER_CPU_SYMBOL(current_task);
+
+DEFINE_PER_CPU(int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
+
 /*
  * Return saved PC of a blocked thread.
  */
@@ -272,25 +277,24 @@ void __devinit select_idle_routine(const
 	}
 }
 
-static int __init idle_setup (char *str)
+static int __init idle_setup(char *str)
 {
-	if (!strncmp(str, "poll", 4)) {
+	if (!strcmp(str, "poll")) {
 		printk("using polling idle threads.\n");
 		pm_idle = poll_idle;
 #ifdef CONFIG_X86_SMP
 		if (smp_num_siblings > 1)
 			printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
 #endif
-	} else if (!strncmp(str, "halt", 4)) {
-		printk("using halt in idle threads.\n");
-		pm_idle = default_idle;
-	}
+	} else if (!strcmp(str, "mwait"))
+		force_mwait = 1;
+	else
+		return -1;
 
 	boot_option_idle_override = 1;
-	return 1;
+	return 0;
 }
-
-__setup("idle=", idle_setup);
+early_param("idle", idle_setup);
 
 void show_regs(struct pt_regs * regs)
 {
@@ -343,7 +347,7 @@ int kernel_thread(int (*fn)(void *), voi
 
 	regs.xds = __USER_DS;
 	regs.xes = __USER_DS;
-	regs.xfs = __KERNEL_PDA;
+	regs.xfs = __KERNEL_PERCPU;
 	regs.orig_eax = -1;
 	regs.eip = (unsigned long) kernel_thread_helper;
 	regs.xcs = __KERNEL_CS | get_kernel_rpl();
@@ -376,7 +380,7 @@ void exit_thread(void)
 		t->io_bitmap_max = 0;
 		tss->io_bitmap_owner = NULL;
 		tss->io_bitmap_max = 0;
-		tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		put_cpu();
 	}
 }
@@ -555,7 +559,7 @@ static noinline void __switch_to_xtra(st
 		 * Disable the bitmap via an invalid offset. We still cache
 		 * the previous bitmap owner and the IO bitmap contents:
 		 */
-		tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		return;
 	}
 
@@ -565,7 +569,7 @@ static noinline void __switch_to_xtra(st
 		 * matches the next task, we dont have to do anything but
 		 * to set a valid offset in the TSS:
 		 */
-		tss->io_bitmap_base = IO_BITMAP_OFFSET;
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
 		return;
 	}
 	/*
@@ -577,7 +581,7 @@ static noinline void __switch_to_xtra(st
 	 * redundant copies when the currently switched task does not
 	 * perform any I/O during its timeslice.
 	 */
-	tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
+	tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 }
 
 /*
@@ -712,7 +716,7 @@ struct task_struct fastcall * __switch_t
 	if (prev->gs | next->gs)
 		loadsegment(gs, next->gs);
 
-	write_pda(pcurrent, next_p);
+	x86_write_percpu(current_task, next_p);
 
 	return prev_p;
 }
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 4a8f8a2..0c0ceec 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -9,7 +9,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
index 34874c3..9f6ab17 100644
--- a/arch/i386/kernel/quirks.c
+++ b/arch/i386/kernel/quirks.c
@@ -3,12 +3,10 @@
  */
 #include <linux/pci.h>
 #include <linux/irq.h>
-#include <asm/pci-direct.h>
-#include <asm/genapic.h>
-#include <asm/cpu.h>
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
-static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
+
+static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
 {
 	u8 config, rev;
 	u32 word;
@@ -16,12 +14,14 @@ static void __devinit verify_quirk_intel
 	/* BIOS may enable hardware IRQ balancing for
 	 * E7520/E7320/E7525(revision ID 0x9 and below)
 	 * based platforms.
-	 * For those platforms, make sure that the genapic is set to 'flat'
+	 * 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);
@@ -30,44 +30,6 @@ static void __devinit verify_quirk_intel
 	raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
 
 	if (!(word & (1 << 13))) {
-#ifdef CONFIG_X86_64
-		if (genapic !=  &apic_flat)
-			panic("APIC mode must be flat on this system\n");
-#elif defined(CONFIG_X86_GENERICARCH)
-		if (genapic != &apic_default)
-			panic("APIC mode must be default(flat) on this system. Use apic=default\n");
-#endif
-	}
-
-	/* put back the original value for config space*/
-	if (!(config & 0x2))
-		pci_write_config_byte(dev, 0xf4, config);
-}
-
-void __init quirk_intel_irqbalance(void)
-{
-	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.
-	 */
-	rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION);
-	if (rev > 0x9)
-		return;
-
-	printk(KERN_INFO "Intel E7520/7320/7525 detected.");
-
-	/* enable access to config space */
-	config = read_pci_config_byte(0, 0, 0, 0xf4);
-	write_pci_config_byte(0, 0, 0, 0xf4, config|0x2);
-
-	/* read xTPR register */
-	word = read_pci_config_16(0, 0, 0x40, 0x4c);
-
-	if (!(word & (1 << 13))) {
 		printk(KERN_INFO "Disabling irq balancing and affinity\n");
 #ifdef CONFIG_IRQBALANCE
 		irqbalance_disable("");
@@ -76,24 +38,13 @@ #endif
 #ifdef CONFIG_PROC_FS
 		no_irq_affinity = 1;
 #endif
-#ifdef CONFIG_HOTPLUG_CPU
-		printk(KERN_INFO "Disabling cpu hotplug control\n");
-		enable_cpu_hotplug = 0;
-#endif
-#ifdef CONFIG_X86_64
-		/* force the genapic selection to flat mode so that
-		 * interrupts can be redirected to more than one CPU.
-		 */
-		genapic_force = &apic_flat;
-#endif
 	}
 
-	/* put back the original value for config space */
+	/* put back the original value for config space*/
 	if (!(config & 0x2))
-		write_pci_config_byte(0, 0, 0, 0xf4, config);
+		pci_write_config_byte(dev, 0xf4, config);
 }
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7320_MCH,  verify_quirk_intel_irqbalance);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  verify_quirk_intel_irqbalance);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  verify_quirk_intel_irqbalance);
-
+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 --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 3514b41..50dfc65 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -17,7 +17,8 @@ #include <asm/uaccess.h>
 #include <asm/apic.h>
 #include <asm/desc.h>
 #include "mach_reboot.h"
-#include <linux/reboot_fixups.h>
+#include <asm/reboot_fixups.h>
+#include <asm/reboot.h>
 
 /*
  * Power off function, if any
@@ -197,8 +198,6 @@ static unsigned char jump_to_bios [] =
  */
 void machine_real_restart(unsigned char *code, int length)
 {
-	unsigned long flags;
-
 	local_irq_disable();
 
 	/* Write zero to CMOS register number 0x0f, which the BIOS POST
@@ -211,9 +210,9 @@ void machine_real_restart(unsigned char 
 	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
 	 */
 
-	spin_lock_irqsave(&rtc_lock, flags);
+	spin_lock(&rtc_lock);
 	CMOS_WRITE(0x00, 0x8f);
-	spin_unlock_irqrestore(&rtc_lock, flags);
+	spin_unlock(&rtc_lock);
 
 	/* Remap the kernel at virtual address zero, as well as offset zero
 	   from the kernel segment.  This assumes the kernel segment starts at
@@ -280,7 +279,7 @@ #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(machine_real_restart);
 #endif
 
-void machine_shutdown(void)
+static void native_machine_shutdown(void)
 {
 #ifdef CONFIG_SMP
 	int reboot_cpu_id;
@@ -316,7 +315,11 @@ #ifdef CONFIG_X86_IO_APIC
 #endif
 }
 
-void machine_emergency_restart(void)
+void __attribute__((weak)) mach_reboot_fixups(void)
+{
+}
+
+static void native_machine_emergency_restart(void)
 {
 	if (!reboot_thru_bios) {
 		if (efi_enabled) {
@@ -340,17 +343,17 @@ void machine_emergency_restart(void)
 	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 }
 
-void machine_restart(char * __unused)
+static void native_machine_restart(char * __unused)
 {
 	machine_shutdown();
 	machine_emergency_restart();
 }
 
-void machine_halt(void)
+static void native_machine_halt(void)
 {
 }
 
-void machine_power_off(void)
+static void native_machine_power_off(void)
 {
 	if (pm_power_off) {
 		machine_shutdown();
@@ -359,3 +362,35 @@ void machine_power_off(void)
 }
 
 
+struct machine_ops machine_ops = {
+	.power_off = native_machine_power_off,
+	.shutdown = native_machine_shutdown,
+	.emergency_restart = native_machine_emergency_restart,
+	.restart = native_machine_restart,
+	.halt = native_machine_halt,
+};
+
+void machine_power_off(void)
+{
+	machine_ops.power_off();
+}
+
+void machine_shutdown(void)
+{
+	machine_ops.shutdown();
+}
+
+void machine_emergency_restart(void)
+{
+	machine_ops.emergency_restart();
+}
+
+void machine_restart(char *cmd)
+{
+	machine_ops.restart(cmd);
+}
+
+void machine_halt(void)
+{
+	machine_ops.halt();
+}
diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c
index 99aab41..2d78d91 100644
--- a/arch/i386/kernel/reboot_fixups.c
+++ b/arch/i386/kernel/reboot_fixups.c
@@ -10,7 +10,7 @@
 
 #include <asm/delay.h>
 #include <linux/pci.h>
-#include <linux/reboot_fixups.h>
+#include <asm/reboot_fixups.h>
 
 static void cs5530a_warm_reset(struct pci_dev *dev)
 {
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 4f99e87..d574e38 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 0e89778..93f202a 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -13,7 +13,6 @@ #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>
@@ -165,20 +164,20 @@ void fastcall send_IPI_self(int vector)
 }
 
 /*
- * This is only used on smaller machines.
+ * This is used to send an IPI with no shorthand notation (the destination is
+ * specified in bits 56 to 63 of the ICR).
  */
-void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
+static inline void __send_IPI_dest_field(unsigned long mask, int vector)
 {
-	unsigned long mask = cpus_addr(cpumask)[0];
 	unsigned long cfg;
-	unsigned long flags;
 
-	local_irq_save(flags);
-	WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
 	/*
 	 * Wait for idle.
 	 */
-	apic_wait_icr_idle();
+	if (unlikely(vector == NMI_VECTOR))
+		safe_apic_wait_icr_idle();
+	else
+		apic_wait_icr_idle();
 		
 	/*
 	 * prepare target chip field
@@ -195,13 +194,25 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write_around(APIC_ICR, cfg);
+}
+
+/*
+ * This is only used on smaller machines.
+ */
+void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
+{
+	unsigned long mask = cpus_addr(cpumask)[0];
+	unsigned long flags;
 
+	local_irq_save(flags);
+	WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
+	__send_IPI_dest_field(mask, vector);
 	local_irq_restore(flags);
 }
 
 void send_IPI_mask_sequence(cpumask_t mask, int vector)
 {
-	unsigned long cfg, flags;
+	unsigned long flags;
 	unsigned int query_cpu;
 
 	/*
@@ -211,30 +222,10 @@ void send_IPI_mask_sequence(cpumask_t ma
 	 */ 
 
 	local_irq_save(flags);
-
 	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
 		if (cpu_isset(query_cpu, mask)) {
-		
-			/*
-			 * Wait for idle.
-			 */
-			apic_wait_icr_idle();
-		
-			/*
-			 * prepare target chip field
-			 */
-			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
-			apic_write_around(APIC_ICR2, cfg);
-		
-			/*
-			 * program the ICR 
-			 */
-			cfg = __prepare_ICR(0, vector);
-			
-			/*
-			 * Send the IPI. The write to APIC_ICR fires this off.
-			 */
-			apic_write_around(APIC_ICR, cfg);
+			__send_IPI_dest_field(cpu_to_logical_apicid(query_cpu),
+					      vector);
 		}
 	}
 	local_irq_restore(flags);
@@ -256,7 +247,6 @@ 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, 
@@ -338,7 +328,7 @@ fastcall void smp_invalidate_interrupt(s
 		 
 	if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
 		if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
-			if (flush_va == FLUSH_ALL)
+			if (flush_va == TLB_FLUSH_ALL)
 				local_flush_tlb();
 			else
 				__flush_tlb_one(flush_va);
@@ -353,9 +343,11 @@ out:
 	put_cpu_no_resched();
 }
 
-static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
-						unsigned long va)
+void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
+			     unsigned long va)
 {
+	cpumask_t cpumask = *cpumaskp;
+
 	/*
 	 * A couple of (to be removed) sanity checks:
 	 *
@@ -366,10 +358,12 @@ static void flush_tlb_others(cpumask_t c
 	BUG_ON(cpu_isset(smp_processor_id(), cpumask));
 	BUG_ON(!mm);
 
+#ifdef CONFIG_HOTPLUG_CPU
 	/* If a CPU which we ran on has gone down, OK. */
 	cpus_and(cpumask, cpumask, cpu_online_map);
-	if (cpus_empty(cpumask))
+	if (unlikely(cpus_empty(cpumask)))
 		return;
+#endif
 
 	/*
 	 * i'm not happy about this global shared spinlock in the
@@ -380,17 +374,7 @@ static void flush_tlb_others(cpumask_t c
 	
 	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
+	cpus_or(flush_cpumask, cpumask, flush_cpumask);
 	/*
 	 * We have to send the IPI only to
 	 * CPUs affected.
@@ -417,7 +401,7 @@ void flush_tlb_current_task(void)
 
 	local_flush_tlb();
 	if (!cpus_empty(cpu_mask))
-		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+		flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL);
 	preempt_enable();
 }
 
@@ -436,7 +420,7 @@ void flush_tlb_mm (struct mm_struct * mm
 			leave_mm(smp_processor_id());
 	}
 	if (!cpus_empty(cpu_mask))
-		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+		flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL);
 
 	preempt_enable();
 }
@@ -483,7 +467,7 @@ void flush_tlb_all(void)
  * it goes straight through and wastes no time serializing
  * anything. Worst case is that we lose a reschedule ...
  */
-void smp_send_reschedule(int cpu)
+void native_smp_send_reschedule(int cpu)
 {
 	WARN_ON(cpu_is_offline(cpu));
 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
@@ -515,36 +499,78 @@ void unlock_ipi_call_lock(void)
 
 static struct call_data_struct *call_data;
 
+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;
+	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)
+		cpu_relax();
+
+	if (wait)
+		while (atomic_read(&data.finished) != cpus)
+			cpu_relax();
+}
+
+
 /**
- * smp_call_function(): Run a function on all other CPUs.
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
+ * @mask: The set of cpus to run on.  Must not include the current 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 (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.
+  * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
  *
  * 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)
+int native_smp_call_function_mask(cpumask_t mask,
+				  void (*func)(void *), void *info,
+				  int wait)
 {
 	struct call_data_struct data;
+	cpumask_t allbutself;
 	int cpus;
 
+	/* Can deadlock when called with interrupts disabled */
+	WARN_ON(irqs_disabled());
+
 	/* Holding any lock stops cpus from going down. */
 	spin_lock(&call_lock);
-	cpus = num_online_cpus() - 1;
+
+	allbutself = cpu_online_map;
+	cpu_clear(smp_processor_id(), allbutself);
+
+	cpus_and(mask, mask, allbutself);
+	cpus = cpus_weight(mask);
+
 	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);
@@ -554,9 +580,12 @@ int smp_call_function (void (*func) (voi
 
 	call_data = &data;
 	mb();
-	
-	/* Send a message to all other CPUs and wait for them to respond */
-	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+
+	/* Send a message to other CPUs */
+	if (cpus_equal(mask, allbutself))
+		send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+	else
+		send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
 
 	/* Wait for response */
 	while (atomic_read(&data.started) != cpus)
@@ -569,15 +598,68 @@ int smp_call_function (void (*func) (voi
 
 	return 0;
 }
+
+/**
+ * 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: Unused.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ *
+ * 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)
+{
+	return smp_call_function_mask(cpu_online_map, func, info, wait);
+}
 EXPORT_SYMBOL(smp_call_function);
 
+/**
+ * smp_call_function_single - Run a function on another CPU
+ * @cpu: The target CPU.  Cannot be the calling CPU.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Unused.
+ * @wait: If true, wait until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ */
+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 ret;
+	int me = get_cpu();
+	if (cpu == me) {
+		WARN_ON(1);
+		put_cpu();
+		return -EBUSY;
+	}
+
+	ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);
+
+	put_cpu();
+	return ret;
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
 static void stop_this_cpu (void * dummy)
 {
+	local_irq_disable();
 	/*
 	 * Remove this CPU:
 	 */
 	cpu_clear(smp_processor_id(), cpu_online_map);
-	local_irq_disable();
 	disable_local_APIC();
 	if (cpu_data[smp_processor_id()].hlt_works_ok)
 		for(;;) halt();
@@ -588,13 +670,18 @@ static void stop_this_cpu (void * dummy)
  * this function calls the 'stop' function on all other CPUs in the system.
  */
 
-void smp_send_stop(void)
+void native_smp_send_stop(void)
 {
-	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	/* Don't deadlock on the call lock in panic */
+	int nolock = !spin_trylock(&call_lock);
+	unsigned long flags;
 
-	local_irq_disable();
+	local_irq_save(flags);
+	__smp_call_function(stop_this_cpu, NULL, 0, 0);
+	if (!nolock)
+		spin_unlock(&call_lock);
 	disable_local_APIC();
-	local_irq_enable();
+	local_irq_restore(flags);
 }
 
 /*
@@ -633,77 +720,6 @@ fastcall void smp_call_function_interrup
 	}
 }
 
-/*
- * 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;
-	}
-
-	/* Can deadlock when called with interrupts disabled */
-	WARN_ON(irqs_disabled());
-
-	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;
@@ -730,3 +746,14 @@ int safe_smp_processor_id(void)
 
 	return cpuid >= 0 ? cpuid : 0;
 }
+
+struct smp_ops smp_ops = {
+	.smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
+	.smp_prepare_cpus = native_smp_prepare_cpus,
+	.cpu_up = native_cpu_up,
+	.smp_cpus_done = native_smp_cpus_done,
+
+	.smp_send_stop = native_smp_send_stop,
+	.smp_send_reschedule = native_smp_send_reschedule,
+	.smp_call_function_mask = native_smp_call_function_mask,
+};
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 4ff55e6..b92cc4e 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -40,7 +40,6 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
@@ -53,13 +52,12 @@ #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
 #include <asm/nmi.h>
-#include <asm/pda.h>
-#include <asm/genapic.h>
 
 #include <mach_apic.h>
 #include <mach_wakecpu.h>
 #include <smpboot_hooks.h>
 #include <asm/vmi.h>
+#include <asm/mtrr.h>
 
 /* Set if we find a B stepping CPU */
 static int __devinitdata smp_b_stepping;
@@ -100,6 +98,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid);
 
 u8 apicid_2_node[MAX_APICID];
 
+DEFINE_PER_CPU(unsigned long, this_cpu_off);
+EXPORT_PER_CPU_SYMBOL(this_cpu_off);
+
 /*
  * Trampoline 80x86 program as an array.
  */
@@ -156,7 +157,7 @@ static void __cpuinit smp_store_cpu_info
 
 	*c = boot_cpu_data;
 	if (id!=0)
-		identify_cpu(c);
+		identify_secondary_cpu(c);
 	/*
 	 * Mask B, Pentium, but not Pentium MMX
 	 */
@@ -379,14 +380,14 @@ set_cpu_sibling_map(int cpu)
 static void __cpuinit start_secondary(void *unused)
 {
 	/*
-	 * Don't put *anything* before secondary_cpu_init(), SMP
-	 * booting is too fragile that we want to limit the
-	 * things done here to the most necessary things.
+	 * Don't put *anything* before cpu_init(), SMP booting is too
+	 * fragile that we want to limit the things done here to the
+	 * most necessary things.
 	 */
 #ifdef CONFIG_VMI
 	vmi_bringup();
 #endif
-	secondary_cpu_init();
+	cpu_init();
 	preempt_disable();
 	smp_callin();
 	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
@@ -441,12 +442,6 @@ #endif
 void __devinit initialize_secondary(void)
 {
 	/*
-	 * switch to the per CPU GDT we already set up
-	 * in do_boot_cpu()
-	 */
-	cpu_set_gdt(current_thread_info()->cpu);
-
-	/*
 	 * We don't actually need to load the full TSS,
 	 * basically just the stack pointer and the eip.
 	 */
@@ -463,7 +458,6 @@ extern struct {
 	void * esp;
 	unsigned short ss;
 } stack_start;
-extern struct i386_pda *start_pda;
 
 #ifdef CONFIG_NUMA
 
@@ -521,12 +515,12 @@ static void unmap_cpu_to_logical_apicid(
 	unmap_cpu_to_node(cpu);
 }
 
-#if APIC_DEBUG
 static inline void __inquire_remote_apic(int apicid)
 {
 	int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
 	char *names[] = { "ID", "VERSION", "SPIV" };
-	int timeout, status;
+	int timeout;
+	unsigned long status;
 
 	printk("Inquiring remote APIC #%d...\n", apicid);
 
@@ -536,7 +530,9 @@ static inline void __inquire_remote_apic
 		/*
 		 * Wait for idle.
 		 */
-		apic_wait_icr_idle();
+		status = safe_apic_wait_icr_idle();
+		if (status)
+			printk("a previous APIC delivery may have failed\n");
 
 		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 		apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
@@ -550,14 +546,13 @@ static inline void __inquire_remote_apic
 		switch (status) {
 		case APIC_ICR_RR_VALID:
 			status = apic_read(APIC_RRR);
-			printk("%08x\n", status);
+			printk("%lx\n", status);
 			break;
 		default:
 			printk("failed\n");
 		}
 	}
 }
-#endif
 
 #ifdef WAKE_SECONDARY_VIA_NMI
 /* 
@@ -568,8 +563,8 @@ #ifdef WAKE_SECONDARY_VIA_NMI
 static int __devinit
 wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
 {
-	unsigned long send_status = 0, accept_status = 0;
-	int timeout, maxlvt;
+	unsigned long send_status, accept_status = 0;
+	int maxlvt;
 
 	/* Target chip */
 	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
@@ -579,12 +574,7 @@ wakeup_secondary_cpu(int logical_apicid,
 	apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
 
 	Dprintk("Waiting for send to finish...\n");
-	timeout = 0;
-	do {
-		Dprintk("+");
-		udelay(100);
-		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-	} while (send_status && (timeout++ < 1000));
+	send_status = safe_apic_wait_icr_idle();
 
 	/*
 	 * Give the other CPU some time to accept the IPI.
@@ -614,8 +604,8 @@ #ifdef WAKE_SECONDARY_VIA_INIT
 static int __devinit
 wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
 {
-	unsigned long send_status = 0, accept_status = 0;
-	int maxlvt, timeout, num_starts, j;
+	unsigned long send_status, accept_status = 0;
+	int maxlvt, num_starts, j;
 
 	/*
 	 * Be paranoid about clearing APIC errors.
@@ -640,12 +630,7 @@ wakeup_secondary_cpu(int phys_apicid, un
 				| APIC_DM_INIT);
 
 	Dprintk("Waiting for send to finish...\n");
-	timeout = 0;
-	do {
-		Dprintk("+");
-		udelay(100);
-		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-	} while (send_status && (timeout++ < 1000));
+	send_status = safe_apic_wait_icr_idle();
 
 	mdelay(10);
 
@@ -658,12 +643,7 @@ wakeup_secondary_cpu(int phys_apicid, un
 	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
 
 	Dprintk("Waiting for send to finish...\n");
-	timeout = 0;
-	do {
-		Dprintk("+");
-		udelay(100);
-		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-	} while (send_status && (timeout++ < 1000));
+	send_status = safe_apic_wait_icr_idle();
 
 	atomic_set(&init_deasserted, 1);
 
@@ -719,12 +699,7 @@ wakeup_secondary_cpu(int phys_apicid, un
 		Dprintk("Startup point 1.\n");
 
 		Dprintk("Waiting for send to finish...\n");
-		timeout = 0;
-		do {
-			Dprintk("+");
-			udelay(100);
-			send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-		} while (send_status && (timeout++ < 1000));
+		send_status = safe_apic_wait_icr_idle();
 
 		/*
 		 * Give the other CPU some time to accept the IPI.
@@ -788,6 +763,25 @@ #else
 #define alloc_idle_task(cpu) fork_idle(cpu)
 #endif
 
+/* Initialize the CPU's GDT.  This is either the boot CPU doing itself
+   (still using the master per-cpu area), or a CPU doing it for a
+   secondary which will soon come up. */
+static __cpuinit void init_gdt(int cpu)
+{
+	struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+
+	pack_descriptor((u32 *)&gdt[GDT_ENTRY_PERCPU].a,
+			(u32 *)&gdt[GDT_ENTRY_PERCPU].b,
+			__per_cpu_offset[cpu], 0xFFFFF,
+			0x80 | DESCTYPE_S | 0x2, 0x8);
+
+	per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu];
+	per_cpu(cpu_number, cpu) = cpu;
+}
+
+/* Defined in head.S */
+extern struct Xgt_desc_struct early_gdt_descr;
+
 static int __cpuinit do_boot_cpu(int apicid, int cpu)
 /*
  * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -802,6 +796,12 @@ static int __cpuinit do_boot_cpu(int api
 	unsigned short nmi_high = 0, nmi_low = 0;
 
 	/*
+	 * Save current MTRR state in case it was changed since early boot
+	 * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+	 */
+	mtrr_save_state();
+
+	/*
 	 * We can't use kernel_thread since we must avoid to
 	 * reschedule the child.
 	 */
@@ -809,13 +809,9 @@ static int __cpuinit do_boot_cpu(int api
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
 
-	/* Pre-allocate and initialize the CPU's GDT and PDA so it
-	   doesn't have to do any memory allocation during the
-	   delicate CPU-bringup phase. */
-	if (!init_gdt(cpu, idle)) {
-		printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
-		return -1;	/* ? */
-	}
+	init_gdt(cpu);
+ 	per_cpu(current_task, cpu) = idle;
+	early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
 
 	idle->thread.eip = (unsigned long) start_secondary;
 	/* start_eip had better be page-aligned! */
@@ -941,7 +937,6 @@ static int __cpuinit __smp_prepare_cpu(i
 	DECLARE_COMPLETION_ONSTACK(done);
 	struct warm_boot_cpu_info info;
 	int	apicid, ret;
-	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
 
 	apicid = x86_cpu_to_apicid[cpu];
 	if (apicid == BAD_APICID) {
@@ -949,18 +944,6 @@ static int __cpuinit __smp_prepare_cpu(i
 		goto exit;
 	}
 
-	/*
-	 * the CPU isn't initialized at boot time, allocate gdt table here.
-	 * cpu_init will initialize it
-	 */
-	if (!cpu_gdt_descr->address) {
-		cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL);
-		if (!cpu_gdt_descr->address)
-			printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
-			ret = -ENOMEM;
-			goto exit;
-	}
-
 	info.complete = &done;
 	info.apicid = apicid;
 	info.cpu = cpu;
@@ -1173,7 +1156,7 @@ static void __init smp_boot_cpus(unsigne
 
 /* These are wrappers to interface to the new boot process.  Someone
    who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init native_smp_prepare_cpus(unsigned int max_cpus)
 {
 	smp_commenced_mask = cpumask_of_cpu(0);
 	cpu_callin_map = cpumask_of_cpu(0);
@@ -1181,13 +1164,18 @@ void __init smp_prepare_cpus(unsigned in
 	smp_boot_cpus(max_cpus);
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+void __init native_smp_prepare_boot_cpu(void)
 {
-	cpu_set(smp_processor_id(), cpu_online_map);
-	cpu_set(smp_processor_id(), cpu_callout_map);
-	cpu_set(smp_processor_id(), cpu_present_map);
-	cpu_set(smp_processor_id(), cpu_possible_map);
-	per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+	unsigned int cpu = smp_processor_id();
+
+	init_gdt(cpu);
+	switch_to_new_gdt();
+
+	cpu_set(cpu, cpu_online_map);
+	cpu_set(cpu, cpu_callout_map);
+	cpu_set(cpu, cpu_present_map);
+	cpu_set(cpu, cpu_possible_map);
+	__get_cpu_var(cpu_state) = CPU_ONLINE;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1277,7 +1265,7 @@ void __cpu_die(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-int __cpuinit __cpu_up(unsigned int cpu)
+int __cpuinit native_cpu_up(unsigned int cpu)
 {
 	unsigned long flags;
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1319,15 +1307,10 @@ #endif
 		touch_nmi_watchdog();
 	}
 
-#ifdef CONFIG_X86_GENERICARCH
-	if (num_online_cpus() > 8 && genapic == &apic_default)
-		panic("Default flat APIC routing can't be used with > 8 cpus\n");
-#endif
-
 	return 0;
 }
 
-void __init smp_cpus_done(unsigned int max_cpus)
+void __init native_smp_cpus_done(unsigned int max_cpus)
 {
 #ifdef CONFIG_X86_IO_APIC
 	setup_ioapic_dest();
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index 4048397..e5dcb93 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -10,7 +10,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 2697e92..0772678 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -319,3 +319,4 @@ ENTRY(sys_call_table)
 	.long sys_move_pages
 	.long sys_getcpu
 	.long sys_epoll_pwait
+	.long sys_utimensat		/* 320 */
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index 13ca54a..ff4ee6f 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -22,16 +22,26 @@ #include <asm/cpufeature.h>
 #include <asm/msr.h>
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
+#include <asm/elf.h>
+#include <asm/tlbflush.h>
+
+enum {
+	VDSO_DISABLED = 0,
+	VDSO_ENABLED = 1,
+	VDSO_COMPAT = 2,
+};
+
+#ifdef CONFIG_COMPAT_VDSO
+#define VDSO_DEFAULT	VDSO_COMPAT
+#else
+#define VDSO_DEFAULT	VDSO_ENABLED
+#endif
 
 /*
  * Should the kernel map a VDSO page into processes and pass its
  * address down to glibc upon exec()?
  */
-#ifdef CONFIG_PARAVIRT
-unsigned int __read_mostly vdso_enabled = 0;
-#else
-unsigned int __read_mostly vdso_enabled = 1;
-#endif
+unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT;
 
 EXPORT_SYMBOL_GPL(vdso_enabled);
 
@@ -46,6 +56,123 @@ __setup("vdso=", vdso_setup);
 
 extern asmlinkage void sysenter_entry(void);
 
+static __init void reloc_symtab(Elf32_Ehdr *ehdr,
+				unsigned offset, unsigned size)
+{
+	Elf32_Sym *sym = (void *)ehdr + offset;
+	unsigned nsym = size / sizeof(*sym);
+	unsigned i;
+
+	for(i = 0; i < nsym; i++, sym++) {
+		if (sym->st_shndx == SHN_UNDEF ||
+		    sym->st_shndx == SHN_ABS)
+			continue;  /* skip */
+
+		if (sym->st_shndx > SHN_LORESERVE) {
+			printk(KERN_INFO "VDSO: unexpected st_shndx %x\n",
+			       sym->st_shndx);
+			continue;
+		}
+
+		switch(ELF_ST_TYPE(sym->st_info)) {
+		case STT_OBJECT:
+		case STT_FUNC:
+		case STT_SECTION:
+		case STT_FILE:
+			sym->st_value += VDSO_HIGH_BASE;
+		}
+	}
+}
+
+static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset)
+{
+	Elf32_Dyn *dyn = (void *)ehdr + offset;
+
+	for(; dyn->d_tag != DT_NULL; dyn++)
+		switch(dyn->d_tag) {
+		case DT_PLTGOT:
+		case DT_HASH:
+		case DT_STRTAB:
+		case DT_SYMTAB:
+		case DT_RELA:
+		case DT_INIT:
+		case DT_FINI:
+		case DT_REL:
+		case DT_DEBUG:
+		case DT_JMPREL:
+		case DT_VERSYM:
+		case DT_VERDEF:
+		case DT_VERNEED:
+		case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+			/* definitely pointers needing relocation */
+			dyn->d_un.d_ptr += VDSO_HIGH_BASE;
+			break;
+
+		case DT_ENCODING ... OLD_DT_LOOS-1:
+		case DT_LOOS ... DT_HIOS-1:
+			/* Tags above DT_ENCODING are pointers if
+			   they're even */
+			if (dyn->d_tag >= DT_ENCODING &&
+			    (dyn->d_tag & 1) == 0)
+				dyn->d_un.d_ptr += VDSO_HIGH_BASE;
+			break;
+
+		case DT_VERDEFNUM:
+		case DT_VERNEEDNUM:
+		case DT_FLAGS_1:
+		case DT_RELACOUNT:
+		case DT_RELCOUNT:
+		case DT_VALRNGLO ... DT_VALRNGHI:
+			/* definitely not pointers */
+			break;
+
+		case OLD_DT_LOOS ... DT_LOOS-1:
+		case DT_HIOS ... DT_VALRNGLO-1:
+		default:
+			if (dyn->d_tag > DT_ENCODING)
+				printk(KERN_INFO "VDSO: unexpected DT_tag %x\n",
+				       dyn->d_tag);
+			break;
+		}
+}
+
+static __init void relocate_vdso(Elf32_Ehdr *ehdr)
+{
+	Elf32_Phdr *phdr;
+	Elf32_Shdr *shdr;
+	int i;
+
+	BUG_ON(memcmp(ehdr->e_ident, ELFMAG, 4) != 0 ||
+	       !elf_check_arch(ehdr) ||
+	       ehdr->e_type != ET_DYN);
+
+	ehdr->e_entry += VDSO_HIGH_BASE;
+
+	/* rebase phdrs */
+	phdr = (void *)ehdr + ehdr->e_phoff;
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		phdr[i].p_vaddr += VDSO_HIGH_BASE;
+
+		/* relocate dynamic stuff */
+		if (phdr[i].p_type == PT_DYNAMIC)
+			reloc_dyn(ehdr, phdr[i].p_offset);
+	}
+
+	/* rebase sections */
+	shdr = (void *)ehdr + ehdr->e_shoff;
+	for(i = 0; i < ehdr->e_shnum; i++) {
+		if (!(shdr[i].sh_flags & SHF_ALLOC))
+			continue;
+
+		shdr[i].sh_addr += VDSO_HIGH_BASE;
+
+		if (shdr[i].sh_type == SHT_SYMTAB ||
+		    shdr[i].sh_type == SHT_DYNSYM)
+			reloc_symtab(ehdr, shdr[i].sh_offset,
+				     shdr[i].sh_size);
+	}
+}
+
 void enable_sep_cpu(void)
 {
 	int cpu = get_cpu();
@@ -56,14 +183,33 @@ void enable_sep_cpu(void)
 		return;
 	}
 
-	tss->ss1 = __KERNEL_CS;
-	tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
+	tss->x86_tss.ss1 = __KERNEL_CS;
+	tss->x86_tss.esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
 	wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
-	wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
+	wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.esp1, 0);
 	wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
 	put_cpu();	
 }
 
+static struct vm_area_struct gate_vma;
+
+static int __init gate_vma_init(void)
+{
+	gate_vma.vm_mm = NULL;
+	gate_vma.vm_start = FIXADDR_USER_START;
+	gate_vma.vm_end = FIXADDR_USER_END;
+	gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
+	gate_vma.vm_page_prot = __P101;
+	/*
+	 * Make sure the vDSO gets into every core dump.
+	 * Dumping its contents makes post-mortem fully interpretable later
+	 * without matching up the same kernel and hardware config to see
+	 * what PC values meant.
+	 */
+	gate_vma.vm_flags |= VM_ALWAYSDUMP;
+	return 0;
+}
+
 /*
  * These symbols are defined by vsyscall.o to mark the bounds
  * of the ELF DSO images included therein.
@@ -72,31 +218,48 @@ extern const char vsyscall_int80_start, 
 extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
 static struct page *syscall_pages[1];
 
+static void map_compat_vdso(int map)
+{
+	static int vdso_mapped;
+
+	if (map == vdso_mapped)
+		return;
+
+	vdso_mapped = map;
+
+	__set_fixmap(FIX_VDSO, page_to_pfn(syscall_pages[0]) << PAGE_SHIFT,
+		     map ? PAGE_READONLY_EXEC : PAGE_NONE);
+
+	/* flush stray tlbs */
+	flush_tlb_all();
+}
+
 int __init sysenter_setup(void)
 {
 	void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+	const void *vsyscall;
+	size_t vsyscall_len;
+
 	syscall_pages[0] = virt_to_page(syscall_page);
 
-#ifdef CONFIG_COMPAT_VDSO
-	__set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC);
+	gate_vma_init();
+
 	printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
-#endif
 
 	if (!boot_cpu_has(X86_FEATURE_SEP)) {
-		memcpy(syscall_page,
-		       &vsyscall_int80_start,
-		       &vsyscall_int80_end - &vsyscall_int80_start);
-		return 0;
+		vsyscall = &vsyscall_int80_start;
+		vsyscall_len = &vsyscall_int80_end - &vsyscall_int80_start;
+	} else {
+		vsyscall = &vsyscall_sysenter_start;
+		vsyscall_len = &vsyscall_sysenter_end - &vsyscall_sysenter_start;
 	}
 
-	memcpy(syscall_page,
-	       &vsyscall_sysenter_start,
-	       &vsyscall_sysenter_end - &vsyscall_sysenter_start);
+	memcpy(syscall_page, vsyscall, vsyscall_len);
+	relocate_vdso(syscall_page);
 
 	return 0;
 }
 
-#ifndef CONFIG_COMPAT_VDSO
 /* Defined in vsyscall-sysenter.S */
 extern void SYSENTER_RETURN;
 
@@ -105,36 +268,52 @@ int arch_setup_additional_pages(struct l
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr;
-	int ret;
+	int ret = 0;
+	bool compat;
 
 	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;
-	}
 
-	/*
-	 * MAYWRITE to allow gdb to COW and set breakpoints
-	 *
-	 * Make sure the vDSO gets into every core dump.
-	 * Dumping its contents makes post-mortem fully interpretable later
-	 * without matching up the same kernel and hardware config to see
-	 * what PC values meant.
-	 */
-	ret = install_special_mapping(mm, addr, PAGE_SIZE,
-				      VM_READ|VM_EXEC|
-				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
-				      VM_ALWAYSDUMP,
-				      syscall_pages);
-	if (ret)
-		goto up_fail;
+	/* Test compat mode once here, in case someone
+	   changes it via sysctl */
+	compat = (vdso_enabled == VDSO_COMPAT);
+
+	map_compat_vdso(compat);
+
+	if (compat)
+		addr = VDSO_HIGH_BASE;
+	else {
+		addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+		if (IS_ERR_VALUE(addr)) {
+			ret = addr;
+			goto up_fail;
+		}
+
+		/*
+		 * MAYWRITE to allow gdb to COW and set breakpoints
+		 *
+		 * Make sure the vDSO gets into every core dump.
+		 * Dumping its contents makes post-mortem fully
+		 * interpretable later without matching up the same
+		 * kernel and hardware config to see what PC values
+		 * meant.
+		 */
+		ret = install_special_mapping(mm, addr, PAGE_SIZE,
+					      VM_READ|VM_EXEC|
+					      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+					      VM_ALWAYSDUMP,
+					      syscall_pages);
+
+		if (ret)
+			goto up_fail;
+	}
 
 	current->mm->context.vdso = (void *)addr;
 	current_thread_info()->sysenter_return =
-				    (void *)VDSO_SYM(&SYSENTER_RETURN);
-up_fail:
+		(void *)VDSO_SYM(&SYSENTER_RETURN);
+
+  up_fail:
 	up_write(&mm->mmap_sem);
+
 	return ret;
 }
 
@@ -147,6 +326,11 @@ const char *arch_vma_name(struct vm_area
 
 struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
 {
+	struct mm_struct *mm = tsk->mm;
+
+	/* Check to see if this task was created in compat vdso mode */
+	if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
+		return &gate_vma;
 	return NULL;
 }
 
@@ -159,4 +343,3 @@ int in_gate_area_no_task(unsigned long a
 {
 	return 0;
 }
-#endif
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 94e5cb0..a665df6 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -70,8 +70,6 @@ #include "io_ports.h"
 
 #include <asm/i8259.h>
 
-int pit_latch_buggy;              /* extern */
-
 #include "do_timer.h"
 
 unsigned int cpu_khz;	/* Detected as we calibrate the TSC */
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index 2f1814c..f62815f 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -29,7 +29,7 @@
  *
  *	TYPE              VALUE
  *	R_386_32          startup_32_smp
- *	R_386_32          boot_gdt_table
+ *	R_386_32          boot_gdt
  */
 
 #include <linux/linkage.h>
@@ -62,8 +62,8 @@ r_base = .
 	 * to 32 bit.
 	 */
 
-	lidtl	boot_idt - r_base	# load idt with 0, 0
-	lgdtl	boot_gdt - r_base	# load gdt with whatever is appropriate
+	lidtl	boot_idt_descr - r_base	# load idt with 0, 0
+	lgdtl	boot_gdt_descr - r_base	# load gdt with whatever is appropriate
 
 	xor	%ax, %ax
 	inc	%ax		# protected mode (PE) bit
@@ -73,11 +73,11 @@ r_base = .
 
 	# These need to be in the same 64K segment as the above;
 	# hence we don't use the boot_gdt_descr defined in head.S
-boot_gdt:
+boot_gdt_descr:
 	.word	__BOOT_DS + 7			# gdt limit
-	.long	boot_gdt_table-__PAGE_OFFSET	# gdt base
+	.long	boot_gdt - __PAGE_OFFSET	# gdt base
 
-boot_idt:
+boot_idt_descr:
 	.word	0				# idt limit = 0
 	.long	0				# idt base = 0L
 
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index af0d3f7..4bec0cb 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -52,7 +52,7 @@ #include <asm/nmi.h>
 #include <asm/unwind.h>
 #include <asm/smp.h>
 #include <asm/arch_hooks.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/stacktrace.h>
 
 #include <linux/module.h>
@@ -95,20 +95,6 @@ asmlinkage void machine_check(void);
 
 int kstack_depth_to_print = 24;
 static unsigned int code_bytes = 64;
-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)
 {
@@ -476,8 +462,6 @@ static void __kprobes do_trap(int trapnr
 			      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)
@@ -489,6 +473,18 @@ static void __kprobes do_trap(int trapnr
 		goto kernel_trap;
 
 	trap_signal: {
+		/*
+		 * We want error_code and trap_no set for userspace faults and
+		 * kernelspace faults which result in die(), but not
+		 * kernelspace faults which are fixed up.  die() gives the
+		 * process no chance to handle the signal and notice the
+		 * kernel fault information, so that won't result in polluting
+		 * the information about previously queued, but not yet
+		 * delivered, faults.  See also do_general_protection below.
+		 */
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = trapnr;
+
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -497,8 +493,11 @@ static void __kprobes do_trap(int trapnr
 	}
 
 	kernel_trap: {
-		if (!fixup_exception(regs))
+		if (!fixup_exception(regs)) {
+			tsk->thread.error_code = error_code;
+			tsk->thread.trap_no = trapnr;
 			die(str, regs, error_code);
+		}
 		return;
 	}
 
@@ -583,7 +582,7 @@ fastcall void __kprobes do_general_prote
 	 * and we set the offset field correctly. Then we let the CPU to
 	 * restart the faulting instruction.
 	 */
-	if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
 	    thread->io_bitmap_ptr) {
 		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
 		       thread->io_bitmap_max);
@@ -596,16 +595,13 @@ fastcall void __kprobes do_general_prote
 				thread->io_bitmap_max, 0xff,
 				tss->io_bitmap_max - thread->io_bitmap_max);
 		tss->io_bitmap_max = thread->io_bitmap_max;
-		tss->io_bitmap_base = IO_BITMAP_OFFSET;
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
 		tss->io_bitmap_owner = thread;
 		put_cpu();
 		return;
 	}
 	put_cpu();
 
-	current->thread.error_code = error_code;
-	current->thread.trap_no = 13;
-
 	if (regs->eflags & VM_MASK)
 		goto gp_in_vm86;
 
@@ -624,6 +620,8 @@ gp_in_vm86:
 
 gp_in_kernel:
 	if (!fixup_exception(regs)) {
+		current->thread.error_code = error_code;
+		current->thread.trap_no = 13;
 		if (notify_die(DIE_GPF, "general protection fault", regs,
 				error_code, 13, SIGSEGV) == NOTIFY_STOP)
 			return;
@@ -735,6 +733,11 @@ #ifdef CONFIG_X86_LOCAL_APIC
 		 */
 		if (nmi_watchdog_tick(regs, reason))
 			return;
+#endif
+		if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
+							== NOTIFY_STOP)
+			return;
+#ifdef CONFIG_X86_LOCAL_APIC
 		if (!do_nmi_callback(regs, smp_processor_id()))
 #endif
 			unknown_nmi_error(reason, regs);
@@ -1018,9 +1021,7 @@ #endif
 fastcall unsigned long patch_espfix_desc(unsigned long uesp,
 					  unsigned long kesp)
 {
-	int cpu = smp_processor_id();
-	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-	struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address;
+	struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
 	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
 	unsigned long new_kesp = kesp - base;
 	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 6cb8f53..f64b81f 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -200,13 +200,10 @@ time_cpufreq_notifier(struct notifier_bl
 {
 	struct cpufreq_freqs *freq = data;
 
-	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
-		write_seqlock_irq(&xtime_lock);
-
 	if (!ref_freq) {
 		if (!freq->old){
 			ref_freq = freq->new;
-			goto end;
+			return 0;
 		}
 		ref_freq = freq->old;
 		loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
@@ -233,13 +230,10 @@ time_cpufreq_notifier(struct notifier_bl
 				 * TSC based sched_clock turns
 				 * to junk w/ cpufreq
 				 */
-				mark_tsc_unstable();
+				mark_tsc_unstable("cpufreq changes");
 			}
 		}
 	}
-end:
-	if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
-		write_sequnlock_irq(&xtime_lock);
 
 	return 0;
 }
@@ -281,11 +275,12 @@ static struct clocksource clocksource_ts
 				  CLOCK_SOURCE_MUST_VERIFY,
 };
 
-void mark_tsc_unstable(void)
+void mark_tsc_unstable(char *reason)
 {
 	if (!tsc_unstable) {
 		tsc_unstable = 1;
 		tsc_enabled = 0;
+		printk("Marking TSC unstable due to: %s.\n", reason);
 		/* Can be called before registration */
 		if (clocksource_tsc.mult)
 			clocksource_change_rating(&clocksource_tsc, 0);
diff --git a/arch/i386/kernel/verify_cpu.S b/arch/i386/kernel/verify_cpu.S
new file mode 100644
index 0000000..e51a869
--- /dev/null
+++ b/arch/i386/kernel/verify_cpu.S
@@ -0,0 +1,65 @@
+/* Check if CPU has some minimum CPUID bits
+   This runs in 16bit mode so that the caller can still use the BIOS
+   to output errors on the screen */
+#include <asm/cpufeature.h>
+
+verify_cpu:
+	pushfl				# Save caller passed flags
+	pushl	$0			# Kill any dangerous flags
+	popfl
+
+#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4
+	pushfl
+	orl	$(1<<18),(%esp)		# try setting AC
+	popfl
+	pushfl
+	popl    %eax
+	testl	$(1<<18),%eax
+	jz	bad
+#endif
+#if REQUIRED_MASK1 != 0
+	pushfl				# standard way to check for cpuid
+	popl	%eax
+	movl	%eax,%ebx
+	xorl	$0x200000,%eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	cmpl	%eax,%ebx
+	pushfl				# standard way to check for cpuid
+	popl	%eax
+	movl	%eax,%ebx
+	xorl	$0x200000,%eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	cmpl	%eax,%ebx
+	jz	bad			# REQUIRED_MASK1 != 0 requires CPUID
+
+	movl	$0x0,%eax		# See if cpuid 1 is implemented
+	cpuid
+	cmpl	$0x1,%eax
+	jb	bad			# no cpuid 1
+
+	movl    $0x1,%eax		# Does the cpu have what it takes
+	cpuid
+
+#if CONFIG_X86_MINIMUM_CPU_MODEL > 4
+#error	add proper model checking here
+#endif
+
+	andl	$REQUIRED_MASK1,%edx
+	xorl	$REQUIRED_MASK1,%edx
+	jnz	bad
+#endif /* REQUIRED_MASK1 */
+
+	popfl
+	xor	%eax,%eax
+	ret
+
+bad:
+	popfl
+	movl	$1,%eax
+	ret
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index d1b8f2b..f2dcd1d 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -39,7 +39,6 @@ #include <linux/signal.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/highmem.h>
 #include <linux/ptrace.h>
 #include <linux/audit.h>
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c
index 697a70e..c8726c4 100644
--- a/arch/i386/kernel/vmi.c
+++ b/arch/i386/kernel/vmi.c
@@ -26,6 +26,7 @@ #include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/bootmem.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 #include <asm/vmi.h>
 #include <asm/io.h>
 #include <asm/fixmap.h>
@@ -56,7 +57,7 @@ static int disable_noidle;
 static int disable_vmi_timer;
 
 /* Cached VMI operations */
-struct {
+static struct {
 	void (*cpuid)(void /* non-c */);
 	void (*_set_ldt)(u32 selector);
 	void (*set_tr)(u32 selector);
@@ -65,16 +66,15 @@ struct {
 	void (*release_page)(u32, u32);
 	void (*set_pte)(pte_t, pte_t *, unsigned);
 	void (*update_pte)(pte_t *, unsigned);
-	void (*set_linear_mapping)(int, u32, u32, u32);
-	void (*flush_tlb)(int);
+	void (*set_linear_mapping)(int, void *, u32, u32);
+	void (*_flush_tlb)(int);
 	void (*set_initial_ap_state)(int, int);
 	void (*halt)(void);
   	void (*set_lazy_mode)(int mode);
 } vmi_ops;
 
-/* XXX move this to alternative.h */
-extern struct paravirt_patch __start_parainstructions[],
-	__stop_parainstructions[];
+/* Cached VMI operations */
+struct vmi_timer_ops vmi_timer_ops;
 
 /*
  * VMI patching routines.
@@ -83,11 +83,6 @@ #define MNEM_CALL 0xe8
 #define MNEM_JMP  0xe9
 #define MNEM_RET  0xc3
 
-static char irq_save_disable_callout[] = {
-	MNEM_CALL, 0, 0, 0, 0,
-	MNEM_CALL, 0, 0, 0, 0,
-	MNEM_RET
-};
 #define IRQ_PATCH_INT_MASK 0
 #define IRQ_PATCH_DISABLE  5
 
@@ -135,33 +130,17 @@ static unsigned patch_internal(int call,
 static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len)
 {
 	switch (type) {
-		case PARAVIRT_IRQ_DISABLE:
+		case PARAVIRT_PATCH(irq_disable):
 			return patch_internal(VMI_CALL_DisableInterrupts, len, insns);
-		case PARAVIRT_IRQ_ENABLE:
+		case PARAVIRT_PATCH(irq_enable):
 			return patch_internal(VMI_CALL_EnableInterrupts, len, insns);
-		case PARAVIRT_RESTORE_FLAGS:
+		case PARAVIRT_PATCH(restore_fl):
 			return patch_internal(VMI_CALL_SetInterruptMask, len, insns);
-		case PARAVIRT_SAVE_FLAGS:
+		case PARAVIRT_PATCH(save_fl):
 			return patch_internal(VMI_CALL_GetInterruptMask, len, insns);
-        	case PARAVIRT_SAVE_FLAGS_IRQ_DISABLE:
-			if (len >= 10) {
-				patch_internal(VMI_CALL_GetInterruptMask, len, insns);
-				patch_internal(VMI_CALL_DisableInterrupts, len-5, insns+5);
-				return 10;
-			} else {
-				/*
-				 * You bastards didn't leave enough room to
-				 * patch save_flags_irq_disable inline.  Patch
-				 * to a helper
-				 */
-				BUG_ON(len < 5);
-				*(char *)insns = MNEM_CALL;
-				patch_offset(insns, irq_save_disable_callout);
-				return 5;
-			}
-		case PARAVIRT_INTERRUPT_RETURN:
+		case PARAVIRT_PATCH(iret):
 			return patch_internal(VMI_CALL_IRET, len, insns);
-		case PARAVIRT_STI_SYSEXIT:
+		case PARAVIRT_PATCH(irq_enable_sysexit):
 			return patch_internal(VMI_CALL_SYSEXIT, len, insns);
 		default:
 			break;
@@ -230,24 +209,24 @@ static void vmi_set_tr(void)
 static void vmi_load_esp0(struct tss_struct *tss,
 				   struct thread_struct *thread)
 {
-	tss->esp0 = thread->esp0;
+	tss->x86_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;
+	if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
+		tss->x86_tss.ss1 = thread->sysenter_cs;
 		wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
 	}
-	vmi_ops.set_kernel_stack(__KERNEL_DS, tss->esp0);
+	vmi_ops.set_kernel_stack(__KERNEL_DS, tss->x86_tss.esp0);
 }
 
 static void vmi_flush_tlb_user(void)
 {
-	vmi_ops.flush_tlb(VMI_FLUSH_TLB);
+	vmi_ops._flush_tlb(VMI_FLUSH_TLB);
 }
 
 static void vmi_flush_tlb_kernel(void)
 {
-	vmi_ops.flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
+	vmi_ops._flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
 }
 
 /* Stub to do nothing at all; used for delays and unimplemented calls */
@@ -255,18 +234,6 @@ static void vmi_nop(void)
 {
 }
 
-/* For NO_IDLE_HZ, we stop the clock when halting the kernel */
-static fastcall void vmi_safe_halt(void)
-{
-	int idle = vmi_stop_hz_timer();
-	vmi_ops.halt();
-	if (idle) {
-		local_irq_disable();
-		vmi_account_time_restart_hz_timer();
-		local_irq_enable();
-	}
-}
-
 #ifdef CONFIG_DEBUG_PAGE_TYPE
 
 #ifdef CONFIG_X86_PAE
@@ -370,8 +337,11 @@ #define vmi_set_page_type(p,t) do { } wh
 #define vmi_check_page_type(p,t) do { } while (0)
 #endif
 
-static void vmi_map_pt_hook(int type, pte_t *va, u32 pfn)
+#ifdef CONFIG_HIGHPTE
+static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
 {
+	void *va = kmap_atomic(page, type);
+
 	/*
 	 * Internally, the VMI ROM must map virtual addresses to physical
 	 * addresses for processing MMU updates.  By the time MMU updates
@@ -385,8 +355,11 @@ static void vmi_map_pt_hook(int type, pt
 	 *  args:                 SLOT                 VA    COUNT PFN
 	 */
 	BUG_ON(type != KM_PTE0 && type != KM_PTE1);
-	vmi_ops.set_linear_mapping((type - KM_PTE0)+1, (u32)va, 1, pfn);
+	vmi_ops.set_linear_mapping((type - KM_PTE0)+1, va, 1, page_to_pfn(page));
+
+	return va;
 }
+#endif
 
 static void vmi_allocate_pt(u32 pfn)
 {
@@ -443,13 +416,13 @@ #define vmi_flags_addr_defer(mm, addr, l
         ((level) | (is_current_as(mm, user) ?                           \
                 (VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
 
-static void vmi_update_pte(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
 }
 
-static void vmi_update_pte_defer(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0));
@@ -462,7 +435,7 @@ static void vmi_set_pte(pte_t *ptep, pte
 	vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT);
 }
 
-static void vmi_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte)
+static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
 {
 	vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
 	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
@@ -516,7 +489,7 @@ static void vmi_pte_clear(struct mm_stru
 	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
 }
 
-void vmi_pmd_clear(pmd_t *pmd)
+static void vmi_pmd_clear(pmd_t *pmd)
 {
 	const pte_t pte = { 0 };
 	vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD);
@@ -525,8 +498,6 @@ void vmi_pmd_clear(pmd_t *pmd)
 #endif
 
 #ifdef CONFIG_SMP
-extern void setup_pda(void);
-
 static void __devinit
 vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
 		     unsigned long start_esp)
@@ -551,13 +522,11 @@ vmi_startup_ipi_hook(int phys_apicid, un
 
 	ap.ds = __USER_DS;
 	ap.es = __USER_DS;
-	ap.fs = __KERNEL_PDA;
+	ap.fs = __KERNEL_PERCPU;
 	ap.gs = 0;
 
 	ap.eflags = 0;
 
-	setup_pda();
-
 #ifdef CONFIG_X86_PAE
 	/* efer should match BSP efer. */
 	if (cpu_has_nx) {
@@ -575,9 +544,9 @@ #endif
 }
 #endif
 
-static void vmi_set_lazy_mode(int mode)
+static void vmi_set_lazy_mode(enum paravirt_lazy_mode mode)
 {
-	static DEFINE_PER_CPU(int, lazy_mode);
+	static DEFINE_PER_CPU(enum paravirt_lazy_mode, lazy_mode);
 
 	if (!vmi_ops.set_lazy_mode)
 		return;
@@ -685,7 +654,7 @@ void vmi_bringup(void)
 {
  	/* We must establish the lowmem mapping for MMU ops to work */
 	if (vmi_ops.set_linear_mapping)
-		vmi_ops.set_linear_mapping(0, __PAGE_OFFSET, max_low_pfn, 0);
+		vmi_ops.set_linear_mapping(0, (void *)__PAGE_OFFSET, max_low_pfn, 0);
 }
 
 /*
@@ -740,7 +709,6 @@ do {								\
 	}							\
 } while (0)
 
-
 /*
  * Activate the VMI interface and switch into paravirtualized mode
  */
@@ -796,12 +764,6 @@ static inline int __init activate_vmi(vo
 	para_fill(irq_disable, DisableInterrupts);
 	para_fill(irq_enable, EnableInterrupts);
 
-	/* irq_save_disable !!! sheer pain */
-	patch_offset(&irq_save_disable_callout[IRQ_PATCH_INT_MASK],
-		     (char *)paravirt_ops.save_fl);
-	patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE],
-		     (char *)paravirt_ops.irq_disable);
-
 	para_fill(wbinvd, WBINVD);
 	para_fill(read_tsc, RDTSC);
 
@@ -831,8 +793,8 @@ static inline int __init activate_vmi(vo
 	para_wrap(set_lazy_mode, vmi_set_lazy_mode, set_lazy_mode, SetLazyMode);
 
 	/* user and kernel flush are just handled with different flags to FlushTLB */
-	para_wrap(flush_tlb_user, vmi_flush_tlb_user, flush_tlb, FlushTLB);
-	para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, flush_tlb, FlushTLB);
+	para_wrap(flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB);
+	para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB);
 	para_fill(flush_tlb_single, InvalPage);
 
 	/*
@@ -878,8 +840,13 @@ #endif
 		paravirt_ops.release_pt = vmi_release_pt;
 		paravirt_ops.release_pd = vmi_release_pd;
 	}
-	para_wrap(map_pt_hook, vmi_map_pt_hook, set_linear_mapping,
-		  SetLinearMapping);
+
+	/* Set linear is needed in all cases */
+	vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping);
+#ifdef CONFIG_HIGHPTE
+	if (vmi_ops.set_linear_mapping)
+		paravirt_ops.kmap_atomic_pte = vmi_kmap_atomic_pte;
+#endif
 
 	/*
 	 * These MUST always be patched.  Don't support indirect jumps
@@ -920,8 +887,8 @@ #endif
 		paravirt_ops.get_wallclock = vmi_get_wallclock;
 		paravirt_ops.set_wallclock = vmi_set_wallclock;
 #ifdef CONFIG_X86_LOCAL_APIC
-		paravirt_ops.setup_boot_clock = vmi_timer_setup_boot_alarm;
-		paravirt_ops.setup_secondary_clock = vmi_timer_setup_secondary_alarm;
+		paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
+		paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
 #endif
 		paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
  		paravirt_ops.get_cpu_khz = vmi_cpu_khz;
@@ -933,11 +900,7 @@ #endif
 		disable_vmi_timer = 1;
 	}
 
-	/* No idle HZ mode only works if VMI timer and no idle is enabled */
-	if (disable_noidle || disable_vmi_timer)
-		para_fill(safe_halt, Halt);
-	else
-		para_wrap(safe_halt, vmi_safe_halt, halt, Halt);
+	para_fill(safe_halt, Halt);
 
 	/*
 	 * Alternative instruction rewriting doesn't happen soon enough
@@ -945,7 +908,7 @@ #endif
 	 * to do this before IRQs get reenabled.  Fortunately, it is
 	 * idempotent.
 	 */
-	apply_paravirt(__start_parainstructions, __stop_parainstructions);
+	apply_paravirt(__parainstructions, __parainstructions_end);
 
 	vmi_bringup();
 
diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock.c
new file mode 100644
index 0000000..26a37f8
--- /dev/null
+++ b/arch/i386/kernel/vmiclock.c
@@ -0,0 +1,318 @@
+/*
+ * VMI paravirtual timer support routines.
+ *
+ * Copyright (C) 2007, VMware, 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, 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.
+ *
+ */
+
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <asm/vmi.h>
+#include <asm/vmi_time.h>
+#include <asm/arch_hooks.h>
+#include <asm/apicdef.h>
+#include <asm/apic.h>
+#include <asm/timer.h>
+
+#include <irq_vectors.h>
+#include "io_ports.h"
+
+#define VMI_ONESHOT  (VMI_ALARM_IS_ONESHOT  | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
+#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
+
+static DEFINE_PER_CPU(struct clock_event_device, local_events);
+
+static inline u32 vmi_counter(u32 flags)
+{
+	/* Given VMI_ONESHOT or VMI_PERIODIC, return the corresponding
+	 * cycle counter. */
+	return flags & VMI_ALARM_COUNTER_MASK;
+}
+
+/* paravirt_ops.get_wallclock = vmi_get_wallclock */
+unsigned long vmi_get_wallclock(void)
+{
+	unsigned long long wallclock;
+	wallclock = vmi_timer_ops.get_wallclock(); // nsec
+	(void)do_div(wallclock, 1000000000);       // sec
+
+	return wallclock;
+}
+
+/* paravirt_ops.set_wallclock = vmi_set_wallclock */
+int vmi_set_wallclock(unsigned long now)
+{
+	return 0;
+}
+
+/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
+unsigned long long vmi_get_sched_cycles(void)
+{
+	return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+}
+
+/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
+unsigned long vmi_cpu_khz(void)
+{
+	unsigned long long khz;
+	khz = vmi_timer_ops.get_cycle_frequency();
+	(void)do_div(khz, 1000);
+	return khz;
+}
+
+static inline unsigned int vmi_get_timer_vector(void)
+{
+#ifdef CONFIG_X86_IO_APIC
+	return FIRST_DEVICE_VECTOR;
+#else
+	return FIRST_EXTERNAL_VECTOR;
+#endif
+}
+
+/** vmi clockchip */
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned int startup_timer_irq(unsigned int irq)
+{
+	unsigned long val = apic_read(APIC_LVTT);
+	apic_write(APIC_LVTT, vmi_get_timer_vector());
+
+	return (val & APIC_SEND_PENDING);
+}
+
+static void mask_timer_irq(unsigned int irq)
+{
+	unsigned long val = apic_read(APIC_LVTT);
+	apic_write(APIC_LVTT, val | APIC_LVT_MASKED);
+}
+
+static void unmask_timer_irq(unsigned int irq)
+{
+	unsigned long val = apic_read(APIC_LVTT);
+	apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED);
+}
+
+static void ack_timer_irq(unsigned int irq)
+{
+	ack_APIC_irq();
+}
+
+static struct irq_chip vmi_chip __read_mostly = {
+	.name 		= "VMI-LOCAL",
+	.startup 	= startup_timer_irq,
+	.mask	 	= mask_timer_irq,
+	.unmask	 	= unmask_timer_irq,
+	.ack 		= ack_timer_irq
+};
+#endif
+
+/** vmi clockevent */
+#define VMI_ALARM_WIRED_IRQ0    0x00000000
+#define VMI_ALARM_WIRED_LVTT    0x00010000
+static int vmi_wiring = VMI_ALARM_WIRED_IRQ0;
+
+static inline int vmi_get_alarm_wiring(void)
+{
+	return vmi_wiring;
+}
+
+static void vmi_timer_set_mode(enum clock_event_mode mode,
+			       struct clock_event_device *evt)
+{
+	cycle_t now, cycles_per_hz;
+	BUG_ON(!irqs_disabled());
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+		cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
+		(void)do_div(cycles_per_hz, HZ);
+		now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC));
+		vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		switch (evt->mode) {
+		case CLOCK_EVT_MODE_ONESHOT:
+			vmi_timer_ops.cancel_alarm(VMI_ONESHOT);
+			break;
+		case CLOCK_EVT_MODE_PERIODIC:
+			vmi_timer_ops.cancel_alarm(VMI_PERIODIC);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int vmi_timer_next_event(unsigned long delta,
+				struct clock_event_device *evt)
+{
+	/* Unfortunately, set_next_event interface only passes relative
+	 * expiry, but we want absolute expiry.  It'd be better if were
+	 * were passed an aboslute expiry, since a bunch of time may
+	 * have been stolen between the time the delta is computed and
+	 * when we set the alarm below. */
+	cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT));
+
+	BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+	vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0);
+	return 0;
+}
+
+static struct clock_event_device vmi_clockevent = {
+	.name		= "vmi-timer",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 22,
+	.set_mode	= vmi_timer_set_mode,
+	.set_next_event = vmi_timer_next_event,
+	.rating         = 1000,
+	.irq		= 0,
+};
+
+static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &__get_cpu_var(local_events);
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction vmi_clock_action  = {
+	.name 		= "vmi-timer",
+	.handler 	= vmi_timer_interrupt,
+	.flags 		= IRQF_DISABLED | IRQF_NOBALANCING,
+	.mask 		= CPU_MASK_ALL,
+};
+
+static void __devinit vmi_time_init_clockevent(void)
+{
+	cycle_t cycles_per_msec;
+	struct clock_event_device *evt;
+
+	int cpu = smp_processor_id();
+	evt = &__get_cpu_var(local_events);
+
+	/* Use cycles_per_msec since div_sc params are 32-bits. */
+	cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
+	(void)do_div(cycles_per_msec, 1000);
+
+	memcpy(evt, &vmi_clockevent, sizeof(*evt));
+	/* Must pick .shift such that .mult fits in 32-bits.  Choosing
+	 * .shift to be 22 allows 2^(32-22) cycles per nano-seconds
+	 * before overflow. */
+	evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift);
+	/* Upper bound is clockevent's use of ulong for cycle deltas. */
+	evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt);
+	evt->min_delta_ns = clockevent_delta2ns(1, evt);
+	evt->cpumask = cpumask_of_cpu(cpu);
+
+	printk(KERN_WARNING "vmi: registering clock event %s. mult=%lu shift=%u\n",
+	       evt->name, evt->mult, evt->shift);
+	clockevents_register_device(evt);
+}
+
+void __init vmi_time_init(void)
+{
+	/* Disable PIT: BIOSes start PIT CH0 with 18.2hz peridic. */
+	outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
+
+	vmi_time_init_clockevent();
+	setup_irq(0, &vmi_clock_action);
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+void __devinit vmi_time_bsp_init(void)
+{
+	/*
+	 * On APIC systems, we want local timers to fire on each cpu.  We do
+	 * this by programming LVTT to deliver timer events to the IRQ handler
+	 * for IRQ-0, since we can't re-use the APIC local timer handler
+	 * without interfering with that code.
+	 */
+	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+	local_irq_disable();
+#ifdef CONFIG_X86_SMP
+	/*
+	 * XXX handle_percpu_irq only defined for SMP; we need to switch over
+	 * to using it, since this is a local interrupt, which each CPU must
+	 * handle individually without locking out or dropping simultaneous
+	 * local timers on other CPUs.  We also don't want to trigger the
+	 * quirk workaround code for interrupts which gets invoked from
+	 * handle_percpu_irq via eoi, so we use our own IRQ chip.
+	 */
+	set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt");
+#else
+	set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt");
+#endif
+	vmi_wiring = VMI_ALARM_WIRED_LVTT;
+	apic_write(APIC_LVTT, vmi_get_timer_vector());
+	local_irq_enable();
+	clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+}
+
+void __devinit vmi_time_ap_init(void)
+{
+	vmi_time_init_clockevent();
+	apic_write(APIC_LVTT, vmi_get_timer_vector());
+}
+#endif
+
+/** vmi clocksource */
+
+static cycle_t read_real_cycles(void)
+{
+	return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
+}
+
+static struct clocksource clocksource_vmi = {
+	.name			= "vmi-timer",
+	.rating			= 450,
+	.read			= read_real_cycles,
+	.mask			= CLOCKSOURCE_MASK(64),
+	.mult			= 0, /* to be set */
+	.shift			= 22,
+	.flags			= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init init_vmi_clocksource(void)
+{
+	cycle_t cycles_per_msec;
+
+	if (!vmi_timer_ops.get_cycle_frequency)
+		return 0;
+	/* Use khz2mult rather than hz2mult since hz arg is only 32-bits. */
+	cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
+	(void)do_div(cycles_per_msec, 1000);
+
+	/* Note that clocksource.{mult, shift} converts in the opposite direction
+	 * as clockevents.  */
+	clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
+						    clocksource_vmi.shift);
+
+	printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec);
+	return clocksource_register(&clocksource_vmi);
+
+}
+module_init(init_vmi_clocksource);
diff --git a/arch/i386/kernel/vmitime.c b/arch/i386/kernel/vmitime.c
deleted file mode 100644
index 9dfb177..0000000
--- a/arch/i386/kernel/vmitime.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * VMI paravirtual timer support routines.
- *
- * Copyright (C) 2005, VMware, 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, 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 dhecht@vmware.com
- *
- */
-
-/*
- * Portions of this code from arch/i386/kernel/timers/timer_tsc.c.
- * Portions of the CONFIG_NO_IDLE_HZ code from arch/s390/kernel/time.c.
- * See comments there for proper credits.
- */
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/rcupdate.h>
-#include <linux/clocksource.h>
-
-#include <asm/timer.h>
-#include <asm/io.h>
-#include <asm/apic.h>
-#include <asm/div64.h>
-#include <asm/timer.h>
-#include <asm/desc.h>
-
-#include <asm/vmi.h>
-#include <asm/vmi_time.h>
-
-#include <mach_timer.h>
-#include <io_ports.h>
-
-#ifdef CONFIG_X86_LOCAL_APIC
-#define VMI_ALARM_WIRING VMI_ALARM_WIRED_LVTT
-#else
-#define VMI_ALARM_WIRING VMI_ALARM_WIRED_IRQ0
-#endif
-
-/* Cached VMI operations */
-struct vmi_timer_ops vmi_timer_ops;
-
-#ifdef CONFIG_NO_IDLE_HZ
-
-/* /proc/sys/kernel/hz_timer state. */
-int sysctl_hz_timer;
-
-/* Some stats */
-static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_irqs);
-static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_jiffies);
-static DEFINE_PER_CPU(unsigned long, idle_start_jiffies);
-
-#endif /* CONFIG_NO_IDLE_HZ */
-
-/* Number of alarms per second. By default this is CONFIG_VMI_ALARM_HZ. */
-static int alarm_hz = CONFIG_VMI_ALARM_HZ;
-
-/* Cache of the value get_cycle_frequency / HZ. */
-static signed long long cycles_per_jiffy;
-
-/* Cache of the value get_cycle_frequency / alarm_hz. */
-static signed long long cycles_per_alarm;
-
-/* The number of cycles accounted for by the 'jiffies'/'xtime' count.
- * Protected by xtime_lock. */
-static unsigned long long real_cycles_accounted_system;
-
-/* The number of cycles accounted for by update_process_times(), per cpu. */
-static DEFINE_PER_CPU(unsigned long long, process_times_cycles_accounted_cpu);
-
-/* The number of stolen cycles accounted, per cpu. */
-static DEFINE_PER_CPU(unsigned long long, stolen_cycles_accounted_cpu);
-
-/* Clock source. */
-static cycle_t read_real_cycles(void)
-{
-	return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
-}
-
-static cycle_t read_available_cycles(void)
-{
-	return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
-}
-
-#if 0
-static cycle_t read_stolen_cycles(void)
-{
-	return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_STOLEN);
-}
-#endif  /*  0  */
-
-static struct clocksource clocksource_vmi = {
-	.name			= "vmi-timer",
-	.rating			= 450,
-	.read			= read_real_cycles,
-	.mask			= CLOCKSOURCE_MASK(64),
-	.mult			= 0, /* to be set */
-	.shift			= 22,
-	.flags			= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-
-/* Timer interrupt handler. */
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id);
-
-static struct irqaction vmi_timer_irq  = {
-	.handler = vmi_timer_interrupt,
-	.flags = IRQF_DISABLED,
-	.mask = CPU_MASK_NONE,
-	.name = "VMI-alarm",
-};
-
-/* Alarm rate */
-static int __init vmi_timer_alarm_rate_setup(char* str)
-{
-	int alarm_rate;
-	if (get_option(&str, &alarm_rate) == 1 && alarm_rate > 0) {
-		alarm_hz = alarm_rate;
-		printk(KERN_WARNING "VMI timer alarm HZ set to %d\n", alarm_hz);
-	}
-	return 1;
-}
-__setup("vmi_timer_alarm_hz=", vmi_timer_alarm_rate_setup);
-
-
-/* Initialization */
-static void vmi_get_wallclock_ts(struct timespec *ts)
-{
-	unsigned long long wallclock;
-	wallclock = vmi_timer_ops.get_wallclock(); // nsec units
-	ts->tv_nsec = do_div(wallclock, 1000000000);
-	ts->tv_sec = wallclock;
-}
-
-unsigned long vmi_get_wallclock(void)
-{
-	struct timespec ts;
-	vmi_get_wallclock_ts(&ts);
-	return ts.tv_sec;
-}
-
-int vmi_set_wallclock(unsigned long now)
-{
-	return -1;
-}
-
-unsigned long long vmi_get_sched_cycles(void)
-{
-	return read_available_cycles();
-}
-
-unsigned long vmi_cpu_khz(void)
-{
-	unsigned long long khz;
-
-	khz = vmi_timer_ops.get_cycle_frequency();
-	(void)do_div(khz, 1000);
-	return khz;
-}
-
-void __init vmi_time_init(void)
-{
-	unsigned long long cycles_per_sec, cycles_per_msec;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	setup_irq(0, &vmi_timer_irq);
-#ifdef CONFIG_X86_LOCAL_APIC
-	set_intr_gate(LOCAL_TIMER_VECTOR, apic_vmi_timer_interrupt);
-#endif
-
-	real_cycles_accounted_system = read_real_cycles();
-	per_cpu(process_times_cycles_accounted_cpu, 0) = read_available_cycles();
-
-	cycles_per_sec = vmi_timer_ops.get_cycle_frequency();
-	cycles_per_jiffy = cycles_per_sec;
-	(void)do_div(cycles_per_jiffy, HZ);
-	cycles_per_alarm = cycles_per_sec;
-	(void)do_div(cycles_per_alarm, alarm_hz);
-	cycles_per_msec = cycles_per_sec;
-	(void)do_div(cycles_per_msec, 1000);
-
-	printk(KERN_WARNING "VMI timer cycles/sec = %llu ; cycles/jiffy = %llu ;"
-	       "cycles/alarm = %llu\n", cycles_per_sec, cycles_per_jiffy,
-	       cycles_per_alarm);
-
-	clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
-						    clocksource_vmi.shift);
-	if (clocksource_register(&clocksource_vmi))
-		printk(KERN_WARNING "Error registering VMITIME clocksource.");
-
-	/* Disable PIT. */
-	outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
-
-	/* schedule the alarm. do this in phase with process_times_cycles_accounted_cpu
-	 * reduce the latency calling update_process_times. */
-	vmi_timer_ops.set_alarm(
-		      VMI_ALARM_WIRED_IRQ0 | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
-		      per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm,
-		      cycles_per_alarm);
-
-	local_irq_restore(flags);
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-void __init vmi_timer_setup_boot_alarm(void)
-{
-	local_irq_disable();
-
-	/* Route the interrupt to the correct vector. */
-	apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR);
-
-	/* Cancel the IRQ0 wired alarm, and setup the LVTT alarm. */
-	vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE);
-	vmi_timer_ops.set_alarm(
-		      VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
-		      per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm,
-		      cycles_per_alarm);
-	local_irq_enable();
-}
-
-/* Initialize the time accounting variables for an AP on an SMP system.
- * Also, set the local alarm for the AP. */
-void __devinit vmi_timer_setup_secondary_alarm(void)
-{
-	int cpu = smp_processor_id();
-
-	/* Route the interrupt to the correct vector. */
-	apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR);
-
-	per_cpu(process_times_cycles_accounted_cpu, cpu) = read_available_cycles();
-
-	vmi_timer_ops.set_alarm(
-		      VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
-		      per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm,
-		      cycles_per_alarm);
-}
-
-#endif
-
-/* Update system wide (real) time accounting (e.g. jiffies, xtime). */
-static void vmi_account_real_cycles(unsigned long long cur_real_cycles)
-{
-	long long cycles_not_accounted;
-
-	write_seqlock(&xtime_lock);
-
-	cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system;
-	while (cycles_not_accounted >= cycles_per_jiffy) {
-		/* systems wide jiffies. */
-		do_timer(1);
-
-		cycles_not_accounted -= cycles_per_jiffy;
-		real_cycles_accounted_system += cycles_per_jiffy;
-	}
-
-	write_sequnlock(&xtime_lock);
-}
-
-/* Update per-cpu process times. */
-static void vmi_account_process_times_cycles(struct pt_regs *regs, int cpu,
-					     unsigned long long cur_process_times_cycles)
-{
-	long long cycles_not_accounted;
-	cycles_not_accounted = cur_process_times_cycles -
-		per_cpu(process_times_cycles_accounted_cpu, cpu);
-
-	while (cycles_not_accounted >= cycles_per_jiffy) {
-		/* Account time to the current process.  This includes
-		 * calling into the scheduler to decrement the timeslice
-		 * and possibly reschedule.*/
-		update_process_times(user_mode(regs));
-		/* XXX handle /proc/profile multiplier.  */
-		profile_tick(CPU_PROFILING);
-
-		cycles_not_accounted -= cycles_per_jiffy;
-		per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
-	}
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-/* Update per-cpu idle times.  Used when a no-hz halt is ended. */
-static void vmi_account_no_hz_idle_cycles(int cpu,
-					  unsigned long long cur_process_times_cycles)
-{
-	long long cycles_not_accounted;
-	unsigned long no_idle_hz_jiffies = 0;
-
-	cycles_not_accounted = cur_process_times_cycles -
-		per_cpu(process_times_cycles_accounted_cpu, cpu);
-
-	while (cycles_not_accounted >= cycles_per_jiffy) {
-		no_idle_hz_jiffies++;
-		cycles_not_accounted -= cycles_per_jiffy;
-		per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
-	}
-	/* Account time to the idle process. */
-	account_steal_time(idle_task(cpu), jiffies_to_cputime(no_idle_hz_jiffies));
-}
-#endif
-
-/* Update per-cpu stolen time. */
-static void vmi_account_stolen_cycles(int cpu,
-				      unsigned long long cur_real_cycles,
-				      unsigned long long cur_avail_cycles)
-{
-	long long stolen_cycles_not_accounted;
-	unsigned long stolen_jiffies = 0;
-
-	if (cur_real_cycles < cur_avail_cycles)
-		return;
-
-	stolen_cycles_not_accounted = cur_real_cycles - cur_avail_cycles -
-		per_cpu(stolen_cycles_accounted_cpu, cpu);
-
-	while (stolen_cycles_not_accounted >= cycles_per_jiffy) {
-		stolen_jiffies++;
-		stolen_cycles_not_accounted -= cycles_per_jiffy;
-		per_cpu(stolen_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
-	}
-	/* HACK: pass NULL to force time onto cpustat->steal. */
-	account_steal_time(NULL, jiffies_to_cputime(stolen_jiffies));
-}
-
-/* Body of either IRQ0 interrupt handler (UP no local-APIC) or
- * local-APIC LVTT interrupt handler (UP & local-APIC or SMP). */
-static void vmi_local_timer_interrupt(int cpu)
-{
-	unsigned long long cur_real_cycles, cur_process_times_cycles;
-
-	cur_real_cycles = read_real_cycles();
-	cur_process_times_cycles = read_available_cycles();
-	/* Update system wide (real) time state (xtime, jiffies). */
-	vmi_account_real_cycles(cur_real_cycles);
-	/* Update per-cpu process times. */
-	vmi_account_process_times_cycles(get_irq_regs(), cpu, cur_process_times_cycles);
-        /* Update time stolen from this cpu by the hypervisor. */
-	vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles);
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-
-/* Must be called only from idle loop, with interrupts disabled. */
-int vmi_stop_hz_timer(void)
-{
-	/* Note that cpu_set, cpu_clear are (SMP safe) atomic on x86. */
-
-	unsigned long seq, next;
-	unsigned long long real_cycles_expiry;
-	int cpu = smp_processor_id();
-
-	BUG_ON(!irqs_disabled());
-	if (sysctl_hz_timer != 0)
-		return 0;
-
-	cpu_set(cpu, nohz_cpu_mask);
-	smp_mb();
-
-	if (rcu_needs_cpu(cpu) || local_softirq_pending() ||
-	    (next = next_timer_interrupt(),
-	     time_before_eq(next, jiffies + HZ/CONFIG_VMI_ALARM_HZ))) {
-		cpu_clear(cpu, nohz_cpu_mask);
-		return 0;
-	}
-
-	/* Convert jiffies to the real cycle counter. */
-	do {
-		seq = read_seqbegin(&xtime_lock);
-		real_cycles_expiry = real_cycles_accounted_system +
-			(long)(next - jiffies) * cycles_per_jiffy;
-	} while (read_seqretry(&xtime_lock, seq));
-
-	/* This cpu is going idle. Disable the periodic alarm. */
-	vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE);
-	per_cpu(idle_start_jiffies, cpu) = jiffies;
-	/* Set the real time alarm to expire at the next event. */
-	vmi_timer_ops.set_alarm(
-		VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL,
-		real_cycles_expiry, 0);
-	return 1;
-}
-
-static void vmi_reenable_hz_timer(int cpu)
-{
-	/* For /proc/vmi/info idle_hz stat. */
-	per_cpu(vmi_idle_no_hz_jiffies, cpu) += jiffies - per_cpu(idle_start_jiffies, cpu);
-	per_cpu(vmi_idle_no_hz_irqs, cpu)++;
-
-	/* Don't bother explicitly cancelling the one-shot alarm -- at
-	 * worse we will receive a spurious timer interrupt. */
-	vmi_timer_ops.set_alarm(
-		      VMI_ALARM_WIRING | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
-		      per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm,
-		      cycles_per_alarm);
-	/* Indicate this cpu is no longer nohz idle. */
-	cpu_clear(cpu, nohz_cpu_mask);
-}
-
-/* Called from interrupt handlers when (local) HZ timer is disabled. */
-void vmi_account_time_restart_hz_timer(void)
-{
-	unsigned long long cur_real_cycles, cur_process_times_cycles;
-	int cpu = smp_processor_id();
-
-	BUG_ON(!irqs_disabled());
-	/* Account the time during which the HZ timer was disabled. */
-	cur_real_cycles = read_real_cycles();
-	cur_process_times_cycles = read_available_cycles();
-	/* Update system wide (real) time state (xtime, jiffies). */
-	vmi_account_real_cycles(cur_real_cycles);
-	/* Update per-cpu idle times. */
-	vmi_account_no_hz_idle_cycles(cpu, cur_process_times_cycles);
-        /* Update time stolen from this cpu by the hypervisor. */
-	vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles);
-	/* Reenable the hz timer. */
-	vmi_reenable_hz_timer(cpu);
-}
-
-#endif /* CONFIG_NO_IDLE_HZ */
-
-/* UP (and no local-APIC) VMI-timer alarm interrupt handler.
- * Handler for IRQ0. Not used when SMP or X86_LOCAL_APIC after
- * APIC setup and setup_boot_vmi_alarm() is called.  */
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
-{
-	vmi_local_timer_interrupt(smp_processor_id());
-	return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-/* SMP VMI-timer alarm interrupt handler. Handler for LVTT vector.
- * Also used in UP when CONFIG_X86_LOCAL_APIC.
- * The wrapper code is from arch/i386/kernel/apic.c#smp_apic_timer_interrupt. */
-void smp_apic_vmi_timer_interrupt(struct pt_regs *regs)
-{
-	struct pt_regs *old_regs = set_irq_regs(regs);
-	int cpu = smp_processor_id();
-
-	/*
-	 * the NMI deadlock-detector uses this.
-	 */
-        per_cpu(irq_stat,cpu).apic_timer_irqs++;
-
-	/*
-	 * 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.
-	 */
-	irq_enter();
-	vmi_local_timer_interrupt(cpu);
-	irq_exit();
-	set_irq_regs(old_regs);
-}
-
-#endif  /* CONFIG_X86_LOCAL_APIC */
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 6f38f81..23e8614 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -26,12 +26,11 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386"
 OUTPUT_ARCH(i386)
 ENTRY(phys_startup_32)
 jiffies = jiffies_64;
-_proxy_pda = 1;
 
 PHDRS {
 	text PT_LOAD FLAGS(5);	/* R_E */
 	data PT_LOAD FLAGS(7);	/* RWE */
-	note PT_NOTE FLAGS(4);	/* R__ */
+	note PT_NOTE FLAGS(0);	/* ___ */
 }
 SECTIONS
 {
@@ -61,8 +60,6 @@ SECTIONS
   	__stop___ex_table = .;
   }
 
-  RODATA
-
   BUG_TABLE
 
   . = ALIGN(4);
@@ -72,6 +69,8 @@ SECTIONS
   	__tracedata_end = .;
   }
 
+  RODATA
+
   /* writeable */
   . = ALIGN(4096);
   .data : AT(ADDR(.data) - LOAD_OFFSET) {	/* Data */
@@ -117,22 +116,11 @@ SECTIONS
 
   /* might get freed after init */
   . = ALIGN(4096);
-  .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
-	__smp_alt_begin = .;
-	__smp_alt_instructions = .;
-	*(.smp_altinstructions)
-	__smp_alt_instructions_end = .;
-  }
-  . = ALIGN(4);
   .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
   	__smp_locks = .;
 	*(.smp_locks)
 	__smp_locks_end = .;
   }
-  .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
-	*(.smp_altinstr_replacement)
-  	__smp_alt_end = .;
-  }
   /* will be freed after init
    * Following ALIGN() is required to make sure no other data falls on the
    * same page where __smp_alt_end is pointing as that page might be freed
@@ -178,9 +166,9 @@ SECTIONS
   }
   . = ALIGN(4);
   .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
-  	__start_parainstructions = .;
+  	__parainstructions = .;
 	*(.parainstructions)
-  	__stop_parainstructions = .;
+  	__parainstructions_end = .;
   }
   /* .exit.text is discard at runtime, not link time, to deal with references
      from .altinstructions and .eh_frame */
@@ -194,7 +182,7 @@ #if defined(CONFIG_BLK_DEV_INITRD)
 	__initramfs_end = .;
   }
 #endif
-  . = ALIGN(L1_CACHE_BYTES);
+  . = ALIGN(4096);
   .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
 	__per_cpu_start = .;
 	*(.data.percpu)
diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S
index f66cd11..4a8b0ed 100644
--- a/arch/i386/kernel/vsyscall.lds.S
+++ b/arch/i386/kernel/vsyscall.lds.S
@@ -7,7 +7,7 @@ #include <asm/asm-offsets.h>
 
 SECTIONS
 {
-  . = VDSO_PRELINK + SIZEOF_HEADERS;
+  . = VDSO_PRELINK_asm + SIZEOF_HEADERS;
 
   .hash           : { *(.hash) }		:text
   .gnu.hash       : { *(.gnu.hash) }
@@ -21,7 +21,7 @@ SECTIONS
      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.  */
-  . = VDSO_PRELINK + 0x400;
+  . = VDSO_PRELINK_asm + 0x400;
 
   .text           : { *(.text) }		:text =0x90909090
   .note		  : { *(.note.*) }		:text :note
diff --git a/arch/i386/lib/bitops.c b/arch/i386/lib/bitops.c
index 97db385..afd0045 100644
--- a/arch/i386/lib/bitops.c
+++ b/arch/i386/lib/bitops.c
@@ -43,7 +43,7 @@ EXPORT_SYMBOL(find_next_bit);
  */
 int find_next_zero_bit(const unsigned long *addr, int size, int offset)
 {
-	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	const unsigned long *p = addr + (offset >> 5);
 	int set = 0, bit = offset & 31, res;
 
 	if (bit) {
@@ -64,7 +64,7 @@ int find_next_zero_bit(const unsigned lo
 	/*
 	 * No zero yet, search remaining full bytes for a zero
 	 */
-	res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+	res = find_first_zero_bit(p, size - 32 * (p - addr));
 	return (offset + set + res);
 }
 EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
index 75ffd02..adbccd0 100644
--- a/arch/i386/lib/checksum.S
+++ b/arch/i386/lib/checksum.S
@@ -25,6 +25,8 @@
  *		2 of the License, or (at your option) any later version.
  */
 
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
 #include <asm/errno.h>
 				
 /*
@@ -36,8 +38,6 @@ unsigned int csum_partial(const unsigned
  */
 		
 .text
-.align 4
-.globl csum_partial								
 		
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
@@ -48,9 +48,14 @@ #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
 	   * alignment for the unrolled loop.
 	   */		
-csum_partial:	
+ENTRY(csum_partial)
+	CFI_STARTPROC
 	pushl %esi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET esi, 0
 	pushl %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 0
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg: unsigned char *buff
@@ -128,16 +133,27 @@ csum_partial:	
 	roll $8, %eax
 8:
 	popl %ebx
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE ebx
 	popl %esi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE esi
 	ret
+	CFI_ENDPROC
+ENDPROC(csum_partial)
 
 #else
 
 /* Version for PentiumII/PPro */
 
-csum_partial:
+ENTRY(csum_partial)
+	CFI_STARTPROC
 	pushl %esi
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET esi, 0
 	pushl %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 0
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg:	const unsigned char *buf
@@ -245,8 +261,14 @@ csum_partial:
 	roll $8, %eax
 90: 
 	popl %ebx
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE ebx
 	popl %esi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE esi
 	ret
+	CFI_ENDPROC
+ENDPROC(csum_partial)
 				
 #endif
 
@@ -278,19 +300,24 @@ #define DST(y...)			\
 	.long 9999b, 6002f	;	\
 	.previous
 
-.align 4
-.globl csum_partial_copy_generic
-				
 #ifndef CONFIG_X86_USE_PPRO_CHECKSUM
 
 #define ARGBASE 16		
 #define FP		12
 		
-csum_partial_copy_generic:
+ENTRY(csum_partial_copy_generic)
+	CFI_STARTPROC
 	subl  $4,%esp	
+	CFI_ADJUST_CFA_OFFSET 4
 	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 %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 0
 	movl ARGBASE+16(%esp),%eax	# sum
 	movl ARGBASE+12(%esp),%ecx	# len
 	movl ARGBASE+4(%esp),%esi	# src
@@ -400,10 +427,19 @@ # Exception handler:
 .previous
 
 	popl %ebx
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE ebx
 	popl %esi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE esi
 	popl %edi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE edi
 	popl %ecx			# equivalent to addl $4,%esp
+	CFI_ADJUST_CFA_OFFSET -4
 	ret	
+	CFI_ENDPROC
+ENDPROC(csum_partial_copy_generic)
 
 #else
 
@@ -421,10 +457,17 @@ #define ROUND(x) \
 
 #define ARGBASE 12
 		
-csum_partial_copy_generic:
+ENTRY(csum_partial_copy_generic)
+	CFI_STARTPROC
 	pushl %ebx
+	CFI_ADJUST_CFA_OFFSET 4
+	CFI_REL_OFFSET ebx, 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
 	movl ARGBASE+4(%esp),%esi	#src
 	movl ARGBASE+8(%esp),%edi	#dst	
 	movl ARGBASE+12(%esp),%ecx	#len
@@ -485,9 +528,17 @@ DST(	movb %dl, (%edi)         )
 .previous				
 
 	popl %esi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE esi
 	popl %edi
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE edi
 	popl %ebx
+	CFI_ADJUST_CFA_OFFSET -4
+	CFI_RESTORE ebx
 	ret
+	CFI_ENDPROC
+ENDPROC(csum_partial_copy_generic)
 				
 #undef ROUND
 #undef ROUND1		
diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser.S
index 62d7f17..6d84b53 100644
--- a/arch/i386/lib/getuser.S
+++ b/arch/i386/lib/getuser.S
@@ -8,6 +8,8 @@
  * return an error value in addition to the "real"
  * return value.
  */
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
 #include <asm/thread_info.h>
 
 
@@ -24,19 +26,19 @@ #include <asm/thread_info.h>
  */
 
 .text
-.align 4
-.globl __get_user_1
-__get_user_1:
+ENTRY(__get_user_1)
+	CFI_STARTPROC
 	GET_THREAD_INFO(%edx)
 	cmpl TI_addr_limit(%edx),%eax
 	jae bad_get_user
 1:	movzbl (%eax),%edx
 	xorl %eax,%eax
 	ret
+	CFI_ENDPROC
+ENDPROC(__get_user_1)
 
-.align 4
-.globl __get_user_2
-__get_user_2:
+ENTRY(__get_user_2)
+	CFI_STARTPROC
 	addl $1,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
@@ -45,10 +47,11 @@ __get_user_2:
 2:	movzwl -1(%eax),%edx
 	xorl %eax,%eax
 	ret
+	CFI_ENDPROC
+ENDPROC(__get_user_2)
 
-.align 4
-.globl __get_user_4
-__get_user_4:
+ENTRY(__get_user_4)
+	CFI_STARTPROC
 	addl $3,%eax
 	jc bad_get_user
 	GET_THREAD_INFO(%edx)
@@ -57,11 +60,16 @@ __get_user_4:
 3:	movl -3(%eax),%edx
 	xorl %eax,%eax
 	ret
+	CFI_ENDPROC
+ENDPROC(__get_user_4)
 
 bad_get_user:
+	CFI_STARTPROC
 	xorl %edx,%edx
 	movl $-14,%eax
 	ret
+	CFI_ENDPROC
+END(bad_get_user)
 
 .section __ex_table,"a"
 	.long 1b,bad_get_user
diff --git a/arch/i386/lib/msr-on-cpu.c b/arch/i386/lib/msr-on-cpu.c
index 1c46bda..7767962 100644
--- a/arch/i386/lib/msr-on-cpu.c
+++ b/arch/i386/lib/msr-on-cpu.c
@@ -6,6 +6,7 @@ #include <asm/msr.h>
 struct msr_info {
 	u32 msr_no;
 	u32 l, h;
+	int err;
 };
 
 static void __rdmsr_on_cpu(void *info)
@@ -15,20 +16,38 @@ static void __rdmsr_on_cpu(void *info)
 	rdmsr(rv->msr_no, rv->l, rv->h);
 }
 
-void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+static void __rdmsr_safe_on_cpu(void *info)
 {
+	struct msr_info *rv = info;
+
+	rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
+}
+
+static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe)
+{
+	int err = 0;
 	preempt_disable();
 	if (smp_processor_id() == cpu)
-		rdmsr(msr_no, *l, *h);
+		if (safe)
+			err = rdmsr_safe(msr_no, l, h);
+		else
+			rdmsr(msr_no, *l, *h);
 	else {
 		struct msr_info rv;
 
 		rv.msr_no = msr_no;
-		smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
+		if (safe) {
+			smp_call_function_single(cpu, __rdmsr_safe_on_cpu,
+						 &rv, 0, 1);
+			err = rv.err;
+		} else {
+			smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
+		}
 		*l = rv.l;
 		*h = rv.h;
 	}
 	preempt_enable();
+	return err;
 }
 
 static void __wrmsr_on_cpu(void *info)
@@ -38,21 +57,63 @@ static void __wrmsr_on_cpu(void *info)
 	wrmsr(rv->msr_no, rv->l, rv->h);
 }
 
-void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+static void __wrmsr_safe_on_cpu(void *info)
 {
+	struct msr_info *rv = info;
+
+	rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
+}
+
+static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
+{
+	int err = 0;
 	preempt_disable();
 	if (smp_processor_id() == cpu)
-		wrmsr(msr_no, l, h);
+		if (safe)
+			err = wrmsr_safe(msr_no, l, h);
+		else
+			wrmsr(msr_no, l, h);
 	else {
 		struct msr_info rv;
 
 		rv.msr_no = msr_no;
 		rv.l = l;
 		rv.h = h;
-		smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
+		if (safe) {
+			smp_call_function_single(cpu, __wrmsr_safe_on_cpu,
+						 &rv, 0, 1);
+			err = rv.err;
+		} else {
+			smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
+		}
 	}
 	preempt_enable();
+	return err;
+}
+
+void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	_wrmsr_on_cpu(cpu, msr_no, l, h, 0);
+}
+
+void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+	_rdmsr_on_cpu(cpu, msr_no, l, h, 0);
+}
+
+/* These "safe" variants are slower and should be used when the target MSR
+   may not actually exist. */
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	return _wrmsr_on_cpu(cpu, msr_no, l, h, 1);
+}
+
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+	return _rdmsr_on_cpu(cpu, msr_no, l, h, 1);
 }
 
 EXPORT_SYMBOL(rdmsr_on_cpu);
 EXPORT_SYMBOL(wrmsr_on_cpu);
+EXPORT_SYMBOL(rdmsr_safe_on_cpu);
+EXPORT_SYMBOL(wrmsr_safe_on_cpu);
diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S
index a32d9f5..f58fba1 100644
--- a/arch/i386/lib/putuser.S
+++ b/arch/i386/lib/putuser.S
@@ -8,6 +8,8 @@
  * return an error value in addition to the "real"
  * return value.
  */
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
 #include <asm/thread_info.h>
 
 
@@ -23,23 +25,28 @@ #include <asm/thread_info.h>
  * as they get called from within inline assembly.
  */
 
-#define ENTER	pushl %ebx ; GET_THREAD_INFO(%ebx)
-#define EXIT	popl %ebx ; ret
+#define ENTER	CFI_STARTPROC ; \
+		pushl %ebx ; \
+		CFI_ADJUST_CFA_OFFSET 4 ; \
+		CFI_REL_OFFSET ebx, 0 ; \
+		GET_THREAD_INFO(%ebx)
+#define EXIT	popl %ebx ; \
+		CFI_ADJUST_CFA_OFFSET -4 ; \
+		CFI_RESTORE ebx ; \
+		ret ; \
+		CFI_ENDPROC
 
 .text
-.align 4
-.globl __put_user_1
-__put_user_1:
+ENTRY(__put_user_1)
 	ENTER
 	cmpl TI_addr_limit(%ebx),%ecx
 	jae bad_put_user
 1:	movb %al,(%ecx)
 	xorl %eax,%eax
 	EXIT
+ENDPROC(__put_user_1)
 
-.align 4
-.globl __put_user_2
-__put_user_2:
+ENTRY(__put_user_2)
 	ENTER
 	movl TI_addr_limit(%ebx),%ebx
 	subl $1,%ebx
@@ -48,10 +55,9 @@ __put_user_2:
 2:	movw %ax,(%ecx)
 	xorl %eax,%eax
 	EXIT
+ENDPROC(__put_user_2)
 
-.align 4
-.globl __put_user_4
-__put_user_4:
+ENTRY(__put_user_4)
 	ENTER
 	movl TI_addr_limit(%ebx),%ebx
 	subl $3,%ebx
@@ -60,10 +66,9 @@ __put_user_4:
 3:	movl %eax,(%ecx)
 	xorl %eax,%eax
 	EXIT
+ENDPROC(__put_user_4)
 
-.align 4
-.globl __put_user_8
-__put_user_8:
+ENTRY(__put_user_8)
 	ENTER
 	movl TI_addr_limit(%ebx),%ebx
 	subl $7,%ebx
@@ -73,10 +78,16 @@ __put_user_8:
 5:	movl %edx,4(%ecx)
 	xorl %eax,%eax
 	EXIT
+ENDPROC(__put_user_8)
 
 bad_put_user:
+	CFI_STARTPROC simple
+	CFI_DEF_CFA esp, 2*4
+	CFI_OFFSET eip, -1*4
+	CFI_OFFSET ebx, -2*4
 	movl $-14,%eax
 	EXIT
+END(bad_put_user)
 
 .section __ex_table,"a"
 	.long 1b,bad_put_user
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index 086b372..9f38b12 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -716,7 +716,6 @@ do {									\
 unsigned long __copy_to_user_ll(void __user *to, const void *from,
 				unsigned long n)
 {
-	BUG_ON((long) n < 0);
 #ifndef CONFIG_X86_WP_WORKS_OK
 	if (unlikely(boot_cpu_data.wp_works_ok == 0) &&
 			((unsigned long )to) < TASK_SIZE) {
@@ -785,7 +784,6 @@ EXPORT_SYMBOL(__copy_to_user_ll);
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
 					unsigned long n)
 {
-	BUG_ON((long)n < 0);
 	if (movsl_is_ok(to, from, n))
 		__copy_user_zeroing(to, from, n);
 	else
@@ -797,7 +795,6 @@ EXPORT_SYMBOL(__copy_from_user_ll);
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
 					 unsigned long n)
 {
-	BUG_ON((long)n < 0);
 	if (movsl_is_ok(to, from, n))
 		__copy_user(to, from, n);
 	else
@@ -810,7 +807,6 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
 					unsigned long n)
 {
-	BUG_ON((long)n < 0);
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if ( n > 64 && cpu_has_xmm2)
                 n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -825,7 +821,6 @@ #endif
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
 					unsigned long n)
 {
-	BUG_ON((long)n < 0);
 #ifdef CONFIG_X86_INTEL_USERCOPY
 	if ( n > 64 && cpu_has_xmm2)
                 n = __copy_user_intel_nocache(to, from, n);
@@ -853,7 +848,6 @@ #endif
 unsigned long
 copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-	BUG_ON((long) n < 0);
 	if (access_ok(VERIFY_WRITE, to, n))
 		n = __copy_to_user(to, from, n);
 	return n;
@@ -879,7 +873,6 @@ EXPORT_SYMBOL(copy_to_user);
 unsigned long
 copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	BUG_ON((long) n < 0);
 	if (access_ok(VERIFY_READ, from, n))
 		n = __copy_from_user(to, from, n);
 	else
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index c788162..7f635c7 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -81,7 +81,7 @@ void __init trap_init_hook(void)
 
 static struct irqaction irq0  = {
 	.handler = timer_interrupt,
-	.flags = IRQF_DISABLED | IRQF_NOBALANCING,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
 	.mask = CPU_MASK_NONE,
 	.name = "timer"
 };
diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
index 8a210fa..e932d34 100644
--- a/arch/i386/mach-generic/bigsmp.c
+++ b/arch/i386/mach-generic/bigsmp.c
@@ -45,7 +45,7 @@ static struct dmi_system_id __initdata b
 };
 
 
-static int probe_bigsmp(void)
+static int __init probe_bigsmp(void)
 { 
 	if (def_to_bigsmp)
         	dmi_bigsmp = 1;
diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c
index b8963a5..b47f951 100644
--- a/arch/i386/mach-generic/es7000.c
+++ b/arch/i386/mach-generic/es7000.c
@@ -25,4 +25,45 @@ static int probe_es7000(void)
 	return 0;
 }
 
+extern void es7000_sw_apic(void);
+static void __init enable_apic_mode(void)
+{
+	es7000_sw_apic();
+	return;
+}
+
+static __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
+		char *productid)
+{
+	if (mpc->mpc_oemptr) {
+		struct mp_config_oemtable *oem_table =
+			(struct mp_config_oemtable *)mpc->mpc_oemptr;
+		if (!strncmp(oem, "UNISYS", 6))
+			return parse_unisys_oem((char *)oem_table);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_ACPI
+/* Hook from generic ACPI tables.c */
+static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	unsigned long oem_addr;
+	if (!find_unisys_acpi_oem_table(&oem_addr)) {
+		if (es7000_check_dsdt())
+			return parse_unisys_oem((char *)oem_addr);
+		else {
+			setup_unisys();
+			return 1;
+		}
+	}
+	return 0;
+}
+#else
+static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	return 0;
+}
+#endif
+
 struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000);
diff --git a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
index 233ee20..1f81f10 100644
--- a/arch/i386/mach-visws/setup.c
+++ b/arch/i386/mach-visws/setup.c
@@ -116,7 +116,7 @@ void __init pre_setup_arch_hook()
 
 static struct irqaction irq0 = {
 	.handler =	timer_interrupt,
-	.flags =	IRQF_DISABLED,
+	.flags =	IRQF_DISABLED | IRQF_IRQPOLL,
 	.name =		"timer",
 };
 
diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
index 38c2b13..710faf7 100644
--- a/arch/i386/mach-visws/visws_apic.c
+++ b/arch/i386/mach-visws/visws_apic.c
@@ -18,7 +18,6 @@
 
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
diff --git a/arch/i386/mach-voyager/setup.c b/arch/i386/mach-voyager/setup.c
index cfa16c1..2b55694 100644
--- a/arch/i386/mach-voyager/setup.c
+++ b/arch/i386/mach-voyager/setup.c
@@ -40,10 +40,16 @@ void __init trap_init_hook(void)
 {
 }
 
-static struct irqaction irq0  = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
+static struct irqaction irq0  = {
+	.handler = timer_interrupt,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
+	.mask = CPU_MASK_NONE,
+	.name = "timer"
+};
 
 void __init time_init_hook(void)
 {
+	irq0.mask = cpumask_of_cpu(safe_smp_processor_id());
 	setup_irq(0, &irq0);
 }
 
diff --git a/arch/i386/mach-voyager/voyager_cat.c b/arch/i386/mach-voyager/voyager_cat.c
index 943a947..26a2d4c 100644
--- a/arch/i386/mach-voyager/voyager_cat.c
+++ b/arch/i386/mach-voyager/voyager_cat.c
@@ -1111,7 +1111,7 @@ #endif
 				printk(KERN_ERR "Voyager front panel switch turned off\n");
 				voyager_status.switch_off = 1;
 				voyager_status.request_from_kernel = 1;
-				up(&kvoyagerd_sem);
+				wake_up_process(voyager_thread);
 			}
 			/* Tell the hardware we're taking care of the
 			 * shutdown, otherwise it will power the box off
@@ -1157,7 +1157,7 @@ #endif
 			outb(VOYAGER_CAT_END, CAT_CMD);
 			voyager_status.power_fail = 1;
 			voyager_status.request_from_kernel = 1;
-			up(&kvoyagerd_sem);
+			wake_up_process(voyager_thread);
 		}
 		
 		
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 74aeedf..50d9c52 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -16,7 +16,6 @@ #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/bootmem.h>
@@ -536,15 +535,6 @@ do_boot_cpu(__u8 cpu)
 		& ~( voyager_extended_vic_processors
 		     & voyager_allowed_boot_processors);
 
-	/* For the 486, we can't use the 4Mb page table trick, so
-	 * must map a region of memory */
-#ifdef CONFIG_M486
-	int i;
-	unsigned long *page_table_copies = (unsigned long *)
-		__get_free_page(GFP_KERNEL);
-#endif
-	pgd_t orig_swapper_pg_dir0;
-
 	/* This is an area in head.S which was used to set up the
 	 * initial kernel stack.  We need to alter this to give the
 	 * booting CPU a new stack (taken from its idle process) */
@@ -573,6 +563,8 @@ #endif
 	hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
 
 	cpucount++;
+	alternatives_smp_switch(1);
+
 	idle = fork_idle(cpu);
 	if(IS_ERR(idle))
 		panic("failed fork for CPU%d", cpu);
@@ -580,39 +572,18 @@ #endif
 	/* init_tasks (in sched.c) is indexed logically */
 	stack_start.esp = (void *) idle->thread.esp;
 
-	/* Pre-allocate and initialize the CPU's GDT and PDA so it
-	   doesn't have to do any memory allocation during the
-	   delicate CPU-bringup phase. */
-	if (!init_gdt(cpu, idle)) {
-		printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
-		cpucount--;
-		return;
-	}
-
+	init_gdt(cpu, idle);
 	irq_ctx_init(cpu);
 
 	/* Note: Don't modify initial ss override */
 	VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu, 
 		(unsigned long)hijack_source.val, hijack_source.idt.Segment,
 		hijack_source.idt.Offset, stack_start.esp));
-	/* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently
-	 * (so that the booting CPU can find start_32 */
-	orig_swapper_pg_dir0 = swapper_pg_dir[0];
-#ifdef CONFIG_M486
-	if(page_table_copies == NULL)
-		panic("No free memory for 486 page tables\n");
-	for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++)
-		page_table_copies[i] = (i * PAGE_SIZE) 
-			| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-
-	((unsigned long *)swapper_pg_dir)[0] = 
-		((virt_to_phys(page_table_copies)) & PAGE_MASK)
-		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#else
-	((unsigned long *)swapper_pg_dir)[0] = 
-		(virt_to_phys(pg0) & PAGE_MASK)
-		| _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#endif
+
+	/* init lowmem identity mapping */
+	clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+			min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+	flush_tlb_all();
 
 	if(quad_boot) {
 		printk("CPU %d: non extended Quad boot\n", cpu);
@@ -655,11 +626,7 @@ #endif
 		udelay(100);
 	}
 	/* reset the page table */
-	swapper_pg_dir[0] = orig_swapper_pg_dir0;
-	local_flush_tlb();
-#ifdef CONFIG_M486
-	free_page((unsigned long)page_table_copies);
-#endif
+	zap_low_mappings();
 	  
 	if (cpu_booted_map) {
 		VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
@@ -773,12 +740,6 @@ #if 0
 #endif
 
 	/*
-	 * switch to the per CPU GDT we already set up
-	 * in do_boot_cpu()
-	 */
-	cpu_set_gdt(current_thread_info()->cpu);
-
-	/*
 	 * We don't actually need to load the full TSS,
 	 * basically just the stack pointer and the eip.
 	 */
@@ -1082,20 +1043,11 @@ smp_call_function_interrupt(void)
 	}
 }
 
-/* Call this function on all CPUs using the function_interrupt above 
-    <func> The function to run. This must be fast and non-blocking.
-    <info> An arbitrary pointer to pass to the function.
-    <retry> If true, keep retrying until ready.
-    <wait> If true, wait 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.
-*/
-int
-smp_call_function (void (*func) (void *info), void *info, int retry,
-		   int wait)
+static int
+__smp_call_function_mask (void (*func) (void *info), void *info, int retry,
+			  int wait, __u32 mask)
 {
 	struct call_data_struct data;
-	__u32 mask = cpus_addr(cpu_online_map)[0];
 
 	mask &= ~(1<<smp_processor_id());
 
@@ -1116,7 +1068,7 @@ smp_call_function (void (*func) (void *i
 	call_data = &data;
 	wmb();
 	/* Send a message to all other CPUs and wait for them to respond */
-	send_CPI_allbutself(VIC_CALL_FUNCTION_CPI);
+	send_CPI(mask, VIC_CALL_FUNCTION_CPI);
 
 	/* Wait for response */
 	while (data.started)
@@ -1130,8 +1082,48 @@ smp_call_function (void (*func) (void *i
 
 	return 0;
 }
+
+/* Call this function on all CPUs using the function_interrupt above
+    <func> The function to run. This must be fast and non-blocking.
+    <info> An arbitrary pointer to pass to the function.
+    <retry> If true, keep retrying until ready.
+    <wait> If true, wait 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.
+*/
+int
+smp_call_function(void (*func) (void *info), void *info, int retry,
+		   int wait)
+{
+	__u32 mask = cpus_addr(cpu_online_map)[0];
+
+	return __smp_call_function_mask(func, info, retry, wait, mask);
+}
 EXPORT_SYMBOL(smp_call_function);
 
+/*
+ * 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)
+{
+	__u32 mask = 1 << cpu;
+
+	return __smp_call_function_mask(func, info, nonatomic, wait, mask);
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
 /* Sorry about the name.  In an APIC based system, the APICs
  * themselves are programmed to send a timer interrupt.  This is used
  * by linux to reschedule the processor.  Voyager doesn't have this,
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
index f398873..b4b24e0 100644
--- a/arch/i386/mach-voyager/voyager_thread.c
+++ b/arch/i386/mach-voyager/voyager_thread.c
@@ -18,39 +18,21 @@ #include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/kmod.h>
 #include <linux/completion.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 
-#define THREAD_NAME "kvoyagerd"
 
-/* external variables */
-int kvoyagerd_running = 0;
-DECLARE_MUTEX_LOCKED(kvoyagerd_sem);
-
-static int thread(void *);
-
-static __u8 set_timeout = 0;
-
-/* Start the machine monitor thread.  Return 1 if OK, 0 if fail */
-static int __init
-voyager_thread_start(void)
-{
-	if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) {
-		/* This is serious, but not fatal */
-		printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n");
-		return 1;
-	}
-	return 0;
-}
+struct task_struct *voyager_thread;
+static __u8 set_timeout;
 
 static int
 execute(const char *string)
@@ -110,31 +92,15 @@ check_continuing_condition(void)
 	}
 }
 
-static void
-wakeup(unsigned long unused)
-{
-	up(&kvoyagerd_sem);
-}
-
 static int
 thread(void *unused)
 {
-	struct timer_list wakeup_timer;
-
-	kvoyagerd_running = 1;
-
-	daemonize(THREAD_NAME);
-
-	set_timeout = 0;
-
-	init_timer(&wakeup_timer);
-
-	sigfillset(&current->blocked);
-
 	printk(KERN_NOTICE "Voyager starting monitor thread\n");
 
-	for(;;) {
-		down_interruptible(&kvoyagerd_sem);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT);
+
 		VDEBUG(("Voyager Daemon awoken\n"));
 		if(voyager_status.request_from_kernel == 0) {
 			/* probably awoken from timeout */
@@ -143,20 +109,26 @@ thread(void *unused)
 			check_from_kernel();
 			voyager_status.request_from_kernel = 0;
 		}
-		if(set_timeout) {
-			del_timer(&wakeup_timer);
-			wakeup_timer.expires = HZ + jiffies;
-			wakeup_timer.function = wakeup;
-			add_timer(&wakeup_timer);
-		}
 	}
 }
 
+static int __init
+voyager_thread_start(void)
+{
+	voyager_thread = kthread_run(thread, NULL, "kvoyagerd");
+	if (IS_ERR(voyager_thread)) {
+		printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n");
+		return PTR_ERR(voyager_thread);
+	}
+	return 0;
+}
+
+
 static void __exit
 voyager_thread_stop(void)
 {
-	/* FIXME: do nothing at the moment */
+	kthread_stop(voyager_thread);
 }
 
 module_init(voyager_thread_start);
-//module_exit(voyager_thread_stop);
+module_exit(voyager_thread_stop);
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index b8c4e25..29d7d61 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -14,19 +14,20 @@ #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/bootmem.h>		/* for max_low_pfn */
+#include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
+#include <linux/kdebug.h>
 
 #include <asm/system.h>
 #include <asm/desc.h>
-#include <asm/kdebug.h>
 #include <asm/segment.h>
 
 extern void die(const char *,struct pt_regs *,long);
@@ -301,7 +302,6 @@ fastcall void __kprobes do_page_fault(st
 	struct mm_struct *mm;
 	struct vm_area_struct * vma;
 	unsigned long address;
-	unsigned long page;
 	int write, si_code;
 
 	/* get the address */
@@ -510,7 +510,9 @@ no_context:
 	bust_spinlocks(1);
 
 	if (oops_may_print()) {
-	#ifdef CONFIG_X86_PAE
+		__typeof__(pte_val(__pte(0))) page;
+
+#ifdef CONFIG_X86_PAE
 		if (error_code & 16) {
 			pte_t *pte = lookup_address(address);
 
@@ -519,7 +521,7 @@ no_context:
 					"NX-protected page - exploit attempt? "
 					"(uid: %d)\n", current->uid);
 		}
-	#endif
+#endif
 		if (address < PAGE_SIZE)
 			printk(KERN_ALERT "BUG: unable to handle kernel NULL "
 					"pointer dereference");
@@ -529,25 +531,38 @@ no_context:
 		printk(" at virtual address %08lx\n",address);
 		printk(KERN_ALERT " printing eip:\n");
 		printk("%08lx\n", regs->eip);
-	}
-	page = read_cr3();
-	page = ((unsigned long *) __va(page))[address >> 22];
-	if (oops_may_print())
+
+		page = read_cr3();
+		page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT];
+#ifdef CONFIG_X86_PAE
+		printk(KERN_ALERT "*pdpt = %016Lx\n", page);
+		if ((page >> PAGE_SHIFT) < max_low_pfn
+		    && page & _PAGE_PRESENT) {
+			page &= PAGE_MASK;
+			page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT)
+			                                         & (PTRS_PER_PMD - 1)];
+			printk(KERN_ALERT "*pde = %016Lx\n", page);
+			page &= ~_PAGE_NX;
+		}
+#else
 		printk(KERN_ALERT "*pde = %08lx\n", 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 = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
-		printk(KERN_ALERT "*pte = %08lx\n", page);
-	}
 #endif
+
+		/*
+		 * We must not directly access the pte in the highpte
+		 * case if the page table is located in highmem.
+		 * And let's rather not kmap-atomic the pte, just in case
+		 * it's allocated already.
+		 */
+		if ((page >> PAGE_SHIFT) < max_low_pfn
+		    && (page & _PAGE_PRESENT)) {
+			page &= PAGE_MASK;
+			page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT)
+			                                         & (PTRS_PER_PTE - 1)];
+			printk(KERN_ALERT "*pte = %0*Lx\n", sizeof(page)*2, (u64)page);
+		}
+	}
+
 	tsk->thread.cr2 = address;
 	tsk->thread.trap_no = 14;
 	tsk->thread.error_code = error_code;
@@ -588,7 +603,6 @@ do_sigbus:
 	force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
 }
 
-#ifndef CONFIG_X86_PAE
 void vmalloc_sync_all(void)
 {
 	/*
@@ -601,6 +615,9 @@ void vmalloc_sync_all(void)
 	static unsigned long start = TASK_SIZE;
 	unsigned long address;
 
+	if (SHARED_KERNEL_PMD)
+		return;
+
 	BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
 	for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
 		if (!test_bit(pgd_index(address), insync)) {
@@ -623,4 +640,3 @@ void vmalloc_sync_all(void)
 			start = address + PGDIR_SIZE;
 	}
 }
-#endif
diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
index ac70d09..ad8d86c 100644
--- a/arch/i386/mm/highmem.c
+++ b/arch/i386/mm/highmem.c
@@ -26,7 +26,7 @@ void kunmap(struct page *page)
  * However when holding an atomic kmap is is not legal to sleep, so atomic
  * kmaps are appropriate for short, tight code paths only.
  */
-void *kmap_atomic(struct page *page, enum km_type type)
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
 {
 	enum fixed_addresses idx;
 	unsigned long vaddr;
@@ -41,12 +41,17 @@ void *kmap_atomic(struct page *page, enu
 		return page_address(page);
 
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-	set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+	set_pte(kmap_pte-idx, mk_pte(page, prot));
 	arch_flush_lazy_mmu_mode();
 
 	return (void*) vaddr;
 }
 
+void *kmap_atomic(struct page *page, enum km_type type)
+{
+	return kmap_atomic_prot(page, type, kmap_prot);
+}
+
 void kunmap_atomic(void *kvaddr, enum km_type type)
 {
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
@@ -67,6 +72,7 @@ #ifdef CONFIG_DEBUG_HIGHMEM
 #endif
 	}
 
+	arch_flush_lazy_mmu_mode();
 	pagefault_enable();
 }
 
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
index 34728e4..efdf95a 100644
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -9,7 +9,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
@@ -367,6 +366,12 @@ hugetlb_get_unmapped_area(struct file *f
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(addr, len, pgoff))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (addr) {
 		addr = ALIGN(addr, HPAGE_SIZE);
 		vma = find_vma(mm, addr);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index ae43688..c50782e 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -22,6 +22,7 @@ #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
@@ -42,6 +43,7 @@ #include <asm/apic.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
+#include <asm/paravirt.h>
 
 unsigned int __VMALLOC_RESERVE = 128 << 20;
 
@@ -61,17 +63,18 @@ static pmd_t * __init one_md_table_init(
 	pmd_t *pmd_table;
 		
 #ifdef CONFIG_X86_PAE
-	pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-	paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT);
-	set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
-	pud = pud_offset(pgd, 0);
-	if (pmd_table != pmd_offset(pud, 0)) 
-		BUG();
-#else
+	if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
+		pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+
+		paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT);
+		set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
+		pud = pud_offset(pgd, 0);
+		if (pmd_table != pmd_offset(pud, 0))
+			BUG();
+	}
+#endif
 	pud = pud_offset(pgd, 0);
 	pmd_table = pmd_offset(pud, 0);
-#endif
-
 	return pmd_table;
 }
 
@@ -81,14 +84,12 @@ #endif
  */
 static pte_t * __init one_page_table_init(pmd_t *pmd)
 {
-	if (pmd_none(*pmd)) {
+	if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
 		pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+
 		paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
 		set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
-		if (page_table != pte_offset_kernel(pmd, 0))
-			BUG();	
-
-		return page_table;
+		BUG_ON(page_table != pte_offset_kernel(pmd, 0));
 	}
 	
 	return pte_offset_kernel(pmd, 0);
@@ -108,7 +109,6 @@ static pte_t * __init one_page_table_ini
 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;
@@ -119,13 +119,10 @@ static void __init page_table_range_init
 	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);
+		pmd = one_md_table_init(pgd);
+		pmd = pmd + pmd_index(vaddr);
 		for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
-			if (pmd_none(*pmd)) 
-				one_page_table_init(pmd);
+			one_page_table_init(pmd);
 
 			vaddr += PMD_SIZE;
 		}
@@ -167,20 +164,22 @@ static void __init kernel_physical_mappi
 			/* 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);
 
-				for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {
-						if (is_kernel_text(address))
-							set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
-						else
-							set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
+				for (pte_ofs = 0;
+				     pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn;
+				     pte++, pfn++, pte_ofs++, address += PAGE_SIZE) {
+					if (is_kernel_text(address))
+						set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+					else
+						set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
 				}
 			}
 		}
@@ -337,24 +336,78 @@ #else
 #define remap_numa_kva() do {} while (0)
 #endif
 
-static void __init pagetable_init (void)
+void __init native_pagetable_setup_start(pgd_t *base)
 {
-	unsigned long vaddr;
-	pgd_t *pgd_base = swapper_pg_dir;
-
 #ifdef CONFIG_X86_PAE
 	int i;
-	/* Init entries of the first-level page table to the zero page */
-	for (i = 0; i < PTRS_PER_PGD; i++)
-		set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
+
+	/*
+	 * Init entries of the first-level page table to the
+	 * zero page, if they haven't already been set up.
+	 *
+	 * In a normal native boot, we'll be running on a
+	 * pagetable rooted in swapper_pg_dir, but not in PAE
+	 * mode, so this will end up clobbering the mappings
+	 * for the lower 24Mbytes of the address space,
+	 * without affecting the kernel address space.
+	 */
+	for (i = 0; i < USER_PTRS_PER_PGD; i++)
+		set_pgd(&base[i],
+			__pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
+
+	/* Make sure kernel address space is empty so that a pagetable
+	   will be allocated for it. */
+	memset(&base[USER_PTRS_PER_PGD], 0,
+	       KERNEL_PGD_PTRS * sizeof(pgd_t));
 #else
 	paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT);
 #endif
+}
+
+void __init native_pagetable_setup_done(pgd_t *base)
+{
+#ifdef CONFIG_X86_PAE
+	/*
+	 * Add low memory identity-mappings - SMP needs it when
+	 * starting up on an AP from real-mode. In the non-PAE
+	 * case we already have these mappings through head.S.
+	 * All user-space mappings are explicitly cleared after
+	 * SMP startup.
+	 */
+	set_pgd(&base[0], base[USER_PTRS_PER_PGD]);
+#endif
+}
+
+/*
+ * Build a proper pagetable for the kernel mappings.  Up until this
+ * point, we've been running on some set of pagetables constructed by
+ * the boot process.
+ *
+ * If we're booting on native hardware, this will be a pagetable
+ * constructed in arch/i386/kernel/head.S, and not running in PAE mode
+ * (even if we'll end up running in PAE).  The root of the pagetable
+ * will be swapper_pg_dir.
+ *
+ * If we're booting paravirtualized under a hypervisor, then there are
+ * more options: we may already be running PAE, and the pagetable may
+ * or may not be based in swapper_pg_dir.  In any case,
+ * paravirt_pagetable_setup_start() will set up swapper_pg_dir
+ * appropriately for the rest of the initialization to work.
+ *
+ * In general, pagetable_init() assumes that the pagetable may already
+ * be partially populated, and so it avoids stomping on any existing
+ * mappings.
+ */
+static void __init pagetable_init (void)
+{
+	unsigned long vaddr, end;
+	pgd_t *pgd_base = swapper_pg_dir;
+
+	paravirt_pagetable_setup_start(pgd_base);
 
 	/* Enable PSE if available */
-	if (cpu_has_pse) {
+	if (cpu_has_pse)
 		set_in_cr4(X86_CR4_PSE);
-	}
 
 	/* Enable PGE if available */
 	if (cpu_has_pge) {
@@ -371,20 +424,12 @@ #endif
 	 * 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);
+	end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
+	page_table_range_init(vaddr, end, pgd_base);
 
 	permanent_kmaps_init(pgd_base);
 
-#ifdef CONFIG_X86_PAE
-	/*
-	 * Add low memory identity-mappings - SMP needs it when
-	 * starting up on an AP from real-mode. In the non-PAE
-	 * case we already have these mappings through head.S.
-	 * All user-space mappings are explicitly cleared after
-	 * SMP startup.
-	 */
-	set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]);
-#endif
+	paravirt_pagetable_setup_done(pgd_base);
 }
 
 #if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
@@ -700,24 +745,31 @@ struct kmem_cache *pmd_cache;
 
 void __init pgtable_cache_init(void)
 {
+	size_t pgd_size = PTRS_PER_PGD*sizeof(pgd_t);
+
 	if (PTRS_PER_PMD > 1) {
 		pmd_cache = kmem_cache_create("pmd",
 					PTRS_PER_PMD*sizeof(pmd_t),
 					PTRS_PER_PMD*sizeof(pmd_t),
-					0,
+					SLAB_PANIC,
 					pmd_ctor,
 					NULL);
-		if (!pmd_cache)
-			panic("pgtable_cache_init(): cannot create pmd cache");
+		if (!SHARED_KERNEL_PMD) {
+			/* If we're in PAE mode and have a non-shared
+			   kernel pmd, then the pgd size must be a
+			   page size.  This is because the pgd_list
+			   links through the page structure, so there
+			   can only be one pgd per page for this to
+			   work. */
+			pgd_size = PAGE_SIZE;
+		}
 	}
 	pgd_cache = kmem_cache_create("pgd",
-				PTRS_PER_PGD*sizeof(pgd_t),
-				PTRS_PER_PGD*sizeof(pgd_t),
-				0,
+				pgd_size,
+				pgd_size,
+				SLAB_PANIC,
 				pgd_ctor,
-				PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
-	if (!pgd_cache)
-		panic("pgtable_cache_init(): Cannot create pgd cache");
+				(!SHARED_KERNEL_PMD) ? pgd_dtor : NULL);
 }
 
 /*
@@ -751,13 +803,25 @@ #ifdef CONFIG_DEBUG_RODATA
 
 void mark_rodata_ro(void)
 {
-	unsigned long addr = (unsigned long)__start_rodata;
+	unsigned long start = PFN_ALIGN(_text);
+	unsigned long size = PFN_ALIGN(_etext) - start;
 
-	for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
-		change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO);
+#ifdef CONFIG_HOTPLUG_CPU
+	/* It must still be possible to apply SMP alternatives. */
+	if (num_possible_cpus() <= 1)
+#endif
+	{
+		change_page_attr(virt_to_page(start),
+		                 size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+		printk("Write protecting the kernel text: %luk\n", size >> 10);
+	}
 
-	printk("Write protecting the kernel read-only data: %uk\n",
-			(__end_rodata - __start_rodata) >> 10);
+	start += size;
+	size = (unsigned long)__end_rodata - start;
+	change_page_attr(virt_to_page(start),
+	                 size >> PAGE_SHIFT, PAGE_KERNEL_RO);
+	printk("Write protecting the kernel read-only data: %luk\n",
+	       size >> 10);
 
 	/*
 	 * change_page_attr() requires a global_flush_tlb() call after it.
@@ -780,7 +844,7 @@ void free_init_pages(char *what, unsigne
 		free_page(addr);
 		totalram_pages++;
 	}
-	printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+	printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
 }
 
 void free_initmem(void)
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 412ebbd..47bd477 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -91,7 +91,7 @@ static void set_pmd_pte(pte_t *kpte, uns
 	unsigned long flags;
 
 	set_pte_atomic(kpte, pte); 	/* change init_mm */
-	if (PTRS_PER_PMD > 1)
+	if (SHARED_KERNEL_PMD)
 		return;
 
 	spin_lock_irqsave(&pgd_lock, flags);
@@ -142,7 +142,7 @@ __change_page_attr(struct page *page, pg
 		return -EINVAL;
 	kpte_page = virt_to_page(kpte);
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
-		if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+		if (!pte_huge(*kpte)) {
 			set_pte_atomic(kpte, mk_pte(page, prot)); 
 		} else {
 			pgprot_t ref_prot;
@@ -158,7 +158,7 @@ __change_page_attr(struct page *page, pg
 			kpte_page = split;
 		}
 		page_private(kpte_page)++;
-	} else if ((pte_val(*kpte) & _PAGE_PSE) == 0) { 
+	} else if (!pte_huge(*kpte)) {
 		set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
 		BUG_ON(page_private(kpte_page) == 0);
 		page_private(kpte_page)--;
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index fa0cfbd..9a96c16 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -144,10 +144,8 @@ void set_pmd_pfn(unsigned long vaddr, un
 }
 
 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)
 {
@@ -173,12 +171,8 @@ void reserve_top_address(unsigned long r
 	BUG_ON(fixmaps > 0);
 	printk(KERN_INFO "Reserving virtual address space above 0x%08x\n",
 	       (int)-reserve);
-#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)
@@ -238,42 +232,92 @@ static inline void pgd_list_del(pgd_t *p
 		set_page_private(next, (unsigned long)pprev);
 }
 
+#if (PTRS_PER_PMD == 1)
+/* Non-PAE pgd constructor */
 void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
 {
 	unsigned long flags;
 
-	if (PTRS_PER_PMD == 1) {
-		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
-		spin_lock_irqsave(&pgd_lock, flags);
-	}
+	/* !PAE, no pagetable sharing */
+	memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+
+	spin_lock_irqsave(&pgd_lock, flags);
 
+	/* must happen under lock */
 	clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
 			swapper_pg_dir + USER_PTRS_PER_PGD,
 			KERNEL_PGD_PTRS);
-
-	if (PTRS_PER_PMD > 1)
-		return;
-
-	/* must happen under lock */
 	paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
-			__pa(swapper_pg_dir) >> PAGE_SHIFT,
-			USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD);
-
+				__pa(swapper_pg_dir) >> PAGE_SHIFT,
+				USER_PTRS_PER_PGD,
+				KERNEL_PGD_PTRS);
 	pgd_list_add(pgd);
 	spin_unlock_irqrestore(&pgd_lock, flags);
 }
+#else  /* PTRS_PER_PMD > 1 */
+/* PAE pgd constructor */
+void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+{
+	/* PAE, kernel PMD may be shared */
+
+	if (SHARED_KERNEL_PMD) {
+		clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+				swapper_pg_dir + USER_PTRS_PER_PGD,
+				KERNEL_PGD_PTRS);
+	} else {
+		unsigned long flags;
+
+		memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+		spin_lock_irqsave(&pgd_lock, flags);
+		pgd_list_add(pgd);
+		spin_unlock_irqrestore(&pgd_lock, flags);
+	}
+}
+#endif	/* PTRS_PER_PMD */
 
-/* never called when PTRS_PER_PMD > 1 */
 void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
 {
 	unsigned long flags; /* can be called from interrupt context */
 
+	BUG_ON(SHARED_KERNEL_PMD);
+
 	paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT);
 	spin_lock_irqsave(&pgd_lock, flags);
 	pgd_list_del(pgd);
 	spin_unlock_irqrestore(&pgd_lock, flags);
 }
 
+#define UNSHARED_PTRS_PER_PGD				\
+	(SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
+
+/* If we allocate a pmd for part of the kernel address space, then
+   make sure its initialized with the appropriate kernel mappings.
+   Otherwise use a cached zeroed pmd.  */
+static pmd_t *pmd_cache_alloc(int idx)
+{
+	pmd_t *pmd;
+
+	if (idx >= USER_PTRS_PER_PGD) {
+		pmd = (pmd_t *)__get_free_page(GFP_KERNEL);
+
+		if (pmd)
+			memcpy(pmd,
+			       (void *)pgd_page_vaddr(swapper_pg_dir[idx]),
+			       sizeof(pmd_t) * PTRS_PER_PMD);
+	} else
+		pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+
+	return pmd;
+}
+
+static void pmd_cache_free(pmd_t *pmd, int idx)
+{
+	if (idx >= USER_PTRS_PER_PGD)
+		free_page((unsigned long)pmd);
+	else
+		kmem_cache_free(pmd_cache, pmd);
+}
+
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	int i;
@@ -282,10 +326,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 	if (PTRS_PER_PMD == 1 || !pgd)
 		return pgd;
 
-	for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
-		pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+ 	for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
+		pmd_t *pmd = pmd_cache_alloc(i);
+
 		if (!pmd)
 			goto out_oom;
+
 		paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT);
 		set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
 	}
@@ -296,7 +342,7 @@ out_oom:
 		pgd_t pgdent = pgd[i];
 		void* pmd = (void *)__va(pgd_val(pgdent)-1);
 		paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
-		kmem_cache_free(pmd_cache, pmd);
+		pmd_cache_free(pmd, i);
 	}
 	kmem_cache_free(pgd_cache, pgd);
 	return NULL;
@@ -308,11 +354,11 @@ void pgd_free(pgd_t *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) {
+		for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
 			pgd_t pgdent = pgd[i];
 			void* pmd = (void *)__va(pgd_val(pgdent)-1);
 			paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
-			kmem_cache_free(pmd_cache, pmd);
+			pmd_cache_free(pmd, i);
 		}
 	/* in the non-PAE case, free_pgtables() clears user pgd entries */
 	kmem_cache_free(pgd_cache, pgd);
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 8fda7be..8e18520 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -14,10 +14,10 @@ #include <linux/oprofile.h>
 #include <linux/sysdev.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/kdebug.h>
 #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"
@@ -414,6 +414,10 @@ int __init op_nmi_init(struct oprofile_o
 				   user space an consistent name. */
 				cpu_type = "x86-64/hammer";
 				break;
+			case 0x10:
+				model = &op_athlon_spec;
+				cpu_type = "x86-64/family10";
+				break;
 			}
 			break;
  
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
index abf0ba5..1418e36 100644
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -12,12 +12,11 @@ #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/oprofile.h>
 #include <linux/rcupdate.h>
-
+#include <linux/kdebug.h>
 
 #include <asm/nmi.h>
 #include <asm/apic.h>
 #include <asm/ptrace.h>
-#include <asm/kdebug.h>
  
 static int profile_timer_exceptions_notify(struct notifier_block *self,
 					   unsigned long val, void *data)
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index 8053b17..b62eafb 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -354,7 +354,7 @@ static void __devinit pci_fixup_video(st
 		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);
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
 
 /*
  * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index 43005f0..bcd2f94 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -246,8 +246,8 @@ int pcibios_enable_resources(struct pci_
 			continue;
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available "
-				"because of resource collisions\n",
-				pci_name(dev));
+				"because of resource %d collisions\n",
+				pci_name(dev), idx);
 			return -EINVAL;
 		}
 		if (r->flags & IORESOURCE_IO)
diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
index b21b6da..1cf11af 100644
--- a/arch/i386/pci/init.c
+++ b/arch/i386/pci/init.c
@@ -6,7 +6,7 @@ #include "pci.h"
    in the right sequence from here. */
 static __init int pci_access_init(void)
 {
-	int type = 0;
+	int type __attribute__((unused)) = 0;
 
 #ifdef CONFIG_PCI_DIRECT
 	type = pci_direct_probe();
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 747d8c6..c7cabee 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -60,14 +60,19 @@ static const char __init *pci_mmcfg_e752
 	u32 win;
 	pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
 
-	pci_mmcfg_config_num = 1;
-	pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
-	if (!pci_mmcfg_config)
-		return NULL;
-	pci_mmcfg_config[0].address = (win & 0xf000) << 16;
-	pci_mmcfg_config[0].pci_segment = 0;
-	pci_mmcfg_config[0].start_bus_number = 0;
-	pci_mmcfg_config[0].end_bus_number = 255;
+	win = win & 0xf000;
+	if(win == 0x0000 || win == 0xf000)
+		pci_mmcfg_config_num = 0;
+	else {
+		pci_mmcfg_config_num = 1;
+		pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
+		if (!pci_mmcfg_config)
+			return NULL;
+		pci_mmcfg_config[0].address = win << 16;
+		pci_mmcfg_config[0].pci_segment = 0;
+		pci_mmcfg_config[0].start_bus_number = 0;
+		pci_mmcfg_config[0].end_bus_number = 255;
+	}
 
 	return "Intel Corporation E7520 Memory Controller Hub";
 }
@@ -108,6 +113,10 @@ static const char __init *pci_mmcfg_inte
 	if ((pciexbar & mask) & 0x0fffffffU)
 		pci_mmcfg_config_num = 0;
 
+	/* Don't hit the APIC registers and their friends */
+	if ((pciexbar & mask) >= 0xf0000000U)
+		pci_mmcfg_config_num = 0;
+
 	if (pci_mmcfg_config_num) {
 		pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
 		if (!pci_mmcfg_config)
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 2c15500..998fd3e 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -21,6 +21,7 @@ unsigned long saved_context_eflags;
 
 void __save_processor_state(struct saved_context *ctxt)
 {
+	mtrr_save_fixed_ranges(NULL);
 	kernel_fpu_begin();
 
 	/*
diff --git a/arch/i386/power/suspend.c b/arch/i386/power/suspend.c
index db5e98d..a0020b9 100644
--- a/arch/i386/power/suspend.c
+++ b/arch/i386/power/suspend.c
@@ -16,6 +16,9 @@ #include <asm/pgtable.h>
 /* Defined in arch/i386/power/swsusp.S */
 extern int restore_image(void);
 
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
+
 /* Pointer to the temporary resume page tables */
 pgd_t *resume_pg_dir;
 
@@ -156,3 +159,14 @@ int swsusp_arch_resume(void)
 	restore_image();
 	return 0;
 }
+
+/*
+ *	pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+int pfn_is_nosave(unsigned long pfn)
+{
+	unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+	unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
+	return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e19185d..e23af4b 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -14,6 +14,7 @@ config IA64
 	select PCI if (!IA64_HP_SIM)
 	select ACPI if (!IA64_HP_SIM)
 	select PM if (!IA64_HP_SIM)
+	select ARCH_SUPPORTS_MSI
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
@@ -438,6 +439,16 @@ config IA64_PALINFO
 	  To use this option, you have to ensure that the "/proc file system
 	  support" (CONFIG_PROC_FS) is enabled, too.
 
+config IA64_MC_ERR_INJECT
+	tristate "MC error injection support"
+	help
+	  Selets whether support for MC error injection. By enabling the
+	  support, kernel provide sysfs interface for user application to
+	  call MC error injection PAL procedure to inject various errors.
+	  This is a useful tool for MCA testing.
+
+	  If you're unsure, do not select this option.
+
 config SGI_SN
 	def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
 
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 153bfdc..90bd960 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -164,6 +164,7 @@ CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+# CONFIG_MC_ERR_INJECT is not set
 CONFIG_SGI_SN=y
 # CONFIG_IA64_ESI is not set
 
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 5a0a7af..300acd9 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -287,7 +287,7 @@ #	define MAKE_MD(typ, attr, start, end)	
 
 	memset(efi_systab, 0, sizeof(efi_systab));
 	efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
-	efi_systab->hdr.revision  = EFI_SYSTEM_TABLE_REVISION;
+	efi_systab->hdr.revision  = ((1 << 16) | 00);
 	efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
 	efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0");
 	efi_systab->fw_revision = 1;
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index 424e925..f26077a 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -427,7 +427,6 @@ make_new_skb(struct net_device *dev)
 		printk(KERN_NOTICE "%s: memory squeeze. dropping packet.\n", dev->name);
 		return NULL;
 	}
-	nskb->dev = dev;
 
 	skb_reserve(nskb, 2);	/* Align IP on 16 byte boundaries */
 
@@ -474,7 +473,7 @@ #if 0
 		 * XXX Fix me
 		 * Should really do a csum+copy here
 		 */
-		memcpy(skb->data, frame, len);
+		skb_copy_to_linear_data(skb, frame, len);
 #endif
 		skb->protocol = eth_type_trans(skb, dev);
 
diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c
index a152738..16d51c1 100644
--- a/arch/ia64/ia32/ia32_ldt.c
+++ b/arch/ia64/ia32/ia32_ldt.c
@@ -10,7 +10,6 @@ #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 <asm/uaccess.h>
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index b3355a9..10510e5 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -18,7 +18,6 @@ #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
index 6af400a..beea7a0 100644
--- a/arch/ia64/ia32/ia32_support.c
+++ b/arch/ia64/ia32/ia32_support.c
@@ -252,10 +252,8 @@ #if PAGE_SHIFT > IA32_PAGE_SHIFT
 		extern struct kmem_cache *partial_page_cachep;
 
 		partial_page_cachep = kmem_cache_create("partial_page_cache",
-							sizeof(struct partial_page), 0, 0,
-							NULL, NULL);
-		if (!partial_page_cachep)
-			panic("Cannot create partial page SLAB cache");
+						sizeof(struct partial_page),
+						0, SLAB_PANIC, NULL, NULL);
 	}
 #endif
 	return 0;
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 098ee60..33e5a59 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+=
 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_MC_ERR_INJECT)+= err_inject.o
 
 obj-$(CONFIG_IA64_ESI)		+= esi.o
 ifneq ($(CONFIG_IA64_ESI),)
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 80a94e7..aeb79fb 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -16,8 +16,8 @@ #include <linux/kexec.h>
 #include <linux/elfcore.h>
 #include <linux/sysctl.h>
 #include <linux/init.h>
+#include <linux/kdebug.h>
 
-#include <asm/kdebug.h>
 #include <asm/mca.h>
 
 int kdump_status[NR_CPUS];
@@ -74,7 +74,7 @@ crash_save_this_cpu(void)
 	buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
 	if (!buf)
 		return;
-	buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus,
+	buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, prstatus,
 			sizeof(*prstatus));
 	final_note(buf);
 }
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f45f91d..75ec347 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -445,11 +445,11 @@ efi_init (void)
 		panic("Woah! Can't find EFI system table.\n");
 	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
 		panic("Woah! EFI system table signature incorrect\n");
-	if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
-		printk(KERN_WARNING "Warning: EFI system table major version mismatch: "
-		       "got %d.%02d, expected %d.%02d\n",
-		       efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff,
-		       EFI_SYSTEM_TABLE_REVISION >> 16, EFI_SYSTEM_TABLE_REVISION & 0xffff);
+	if ((efi.systab->hdr.revision >> 16) == 0)
+		printk(KERN_WARNING "Warning: EFI system table version "
+		       "%d.%02d, expected 1.00 or greater\n",
+		       efi.systab->hdr.revision >> 16,
+		       efi.systab->hdr.revision & 0xffff);
 
 	config_tables = __va(efi.systab->tables);
 
@@ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phy
 	return NULL;
 }
 
+static int
+efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
+{
+	void *efi_map_start, *efi_map_end, *p;
+	efi_memory_desc_t *md;
+	u64 efi_desc_size;
+	unsigned long end;
+
+	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;
+
+	end = phys_addr + size;
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		md = p;
+
+		if (md->phys_addr < end && efi_md_end(md) > phys_addr)
+			return 1;
+	}
+	return 0;
+}
+
 u32
 efi_mem_type (unsigned long phys_addr)
 {
@@ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phy
 int
 valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
 {
+	unsigned long phys_addr = pfn << PAGE_SHIFT;
+	u64 attr;
+
+	attr = efi_mem_attribute(phys_addr, size);
+
 	/*
-	 * MMIO regions are often missing from the EFI memory map.
-	 * We must allow mmap of them for programs like X, so we
-	 * currently can't do any useful validation.
+	 * /dev/mem mmap uses normal user pages, so we don't need the entire
+	 * granule, but the entire region we're mapping must support the same
+	 * attribute.
 	 */
+	if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
+		return 1;
+
+	/*
+	 * Intel firmware doesn't tell us about all the MMIO regions, so
+	 * in general we have to allow mmap requests.  But if EFI *does*
+	 * tell us about anything inside this region, we should deny it.
+	 * The user can always map a smaller region to avoid the overlap.
+	 */
+	if (efi_memmap_intersects(phys_addr, size))
+		return 0;
+
 	return 1;
 }
 
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index e7873ee..55fd2d5 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -767,7 +767,7 @@ (pUStk) st1 [r14]=r17				// M2|3
 	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
+	LOAD_PHYS_STACK_REG_SIZE(r17)
 	mov f9=f0					// F    clear f9
 (pKStk) br.cond.dpnt.many skip_rbs_switch		// B
 
@@ -775,7 +775,6 @@ (pKStk) br.cond.dpnt.many skip_rbs_switc
 	shr.u r18=r19,16		// I0|1 get byte size of existing "dirty" partition
 	cover				// B    add current frame into dirty partition & set cr.ifs
 	;;
-(pUStk) ld4 r17=[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
 
@@ -953,9 +952,7 @@ (pUStk)	st1 [r18]=r17		// restore curren
 	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
+	LOAD_PHYS_STACK_REG_SIZE(r17)
 (pKStk)	br.cond.dpnt skip_rbs_switch
 
 	/*
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
new file mode 100644
index 0000000..d3e9f33
--- /dev/null
+++ b/arch/ia64/kernel/err_inject.c
@@ -0,0 +1,293 @@
+/*
+ * err_inject.c -
+ *	1.) Inject errors to a processor.
+ *	2.) Query error injection capabilities.
+ * This driver along with user space code can be acting as an error
+ * injection tool.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ *
+ * Written by: Fenghua Yu <fenghua.yu@intel.com>, Intel Corporation
+ * Copyright (C) 2006, Intel Corp.  All rights reserved.
+ *
+ */
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+
+#define ERR_INJ_DEBUG
+
+#define ERR_DATA_BUFFER_SIZE 3 		// Three 8-byte;
+
+#define define_one_ro(name) 						\
+static SYSDEV_ATTR(name, 0444, show_##name, NULL)
+
+#define define_one_rw(name) 						\
+static SYSDEV_ATTR(name, 0644, show_##name, store_##name)
+
+static u64 call_start[NR_CPUS];
+static u64 phys_addr[NR_CPUS];
+static u64 err_type_info[NR_CPUS];
+static u64 err_struct_info[NR_CPUS];
+static struct {
+	u64 data1;
+	u64 data2;
+	u64 data3;
+} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
+static s64 status[NR_CPUS];
+static u64 capabilities[NR_CPUS];
+static u64 resources[NR_CPUS];
+
+#define show(name) 							\
+static ssize_t 								\
+show_##name(struct sys_device *dev, char *buf)				\
+{									\
+	u32 cpu=dev->id;						\
+	return sprintf(buf, "%lx\n", name[cpu]);			\
+}
+
+#define store(name)							\
+static ssize_t 								\
+store_##name(struct sys_device *dev, const char *buf, size_t size)	\
+{									\
+	unsigned int cpu=dev->id;					\
+	name[cpu] = simple_strtoull(buf, NULL, 16);			\
+	return size;							\
+}
+
+show(call_start)
+
+/* It's user's responsibility to call the PAL procedure on a specific
+ * processor. The cpu number in driver is only used for storing data.
+ */
+static ssize_t
+store_call_start(struct sys_device *dev, const char *buf, size_t size)
+{
+	unsigned int cpu=dev->id;
+	unsigned long call_start = simple_strtoull(buf, NULL, 16);
+
+#ifdef ERR_INJ_DEBUG
+	printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
+	printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
+	printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
+	printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
+			  err_data_buffer[cpu].data1,
+			  err_data_buffer[cpu].data2,
+			  err_data_buffer[cpu].data3);
+#endif
+	switch (call_start) {
+	    case 0: /* Do nothing. */
+		break;
+	    case 1: /* Call pal_mc_error_inject in physical mode. */
+		status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
+					err_struct_info[cpu],
+					ia64_tpa(&err_data_buffer[cpu]),
+					&capabilities[cpu],
+			 		&resources[cpu]);
+		break;
+	    case 2: /* Call pal_mc_error_inject in virtual mode. */
+		status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
+					err_struct_info[cpu],
+					ia64_tpa(&err_data_buffer[cpu]),
+					&capabilities[cpu],
+			 		&resources[cpu]);
+		break;
+	    default:
+		status[cpu] = -EINVAL;
+		break;
+	}
+
+#ifdef ERR_INJ_DEBUG
+	printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
+	printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
+	printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
+#endif
+	return size;
+}
+
+show(err_type_info)
+store(err_type_info)
+
+static ssize_t
+show_virtual_to_phys(struct sys_device *dev, char *buf)
+{
+	unsigned int cpu=dev->id;
+	return sprintf(buf, "%lx\n", phys_addr[cpu]);
+}
+
+static ssize_t
+store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size)
+{
+	unsigned int cpu=dev->id;
+	u64 virt_addr=simple_strtoull(buf, NULL, 16);
+	int ret;
+
+        ret = get_user_pages(current, current->mm, virt_addr,
+                        1, VM_READ, 0, NULL, NULL);
+	if (ret<=0) {
+#ifdef ERR_INJ_DEBUG
+		printk("Virtual address %lx is not existing.\n",virt_addr);
+#endif
+		return -EINVAL;
+	}
+
+	phys_addr[cpu] = ia64_tpa(virt_addr);
+	return size;
+}
+
+show(err_struct_info)
+store(err_struct_info)
+
+static ssize_t
+show_err_data_buffer(struct sys_device *dev, char *buf)
+{
+	unsigned int cpu=dev->id;
+
+	return sprintf(buf, "%lx, %lx, %lx\n",
+			err_data_buffer[cpu].data1,
+			err_data_buffer[cpu].data2,
+			err_data_buffer[cpu].data3);
+}
+
+static ssize_t
+store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size)
+{
+	unsigned int cpu=dev->id;
+	int ret;
+
+#ifdef ERR_INJ_DEBUG
+	printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
+		 err_data_buffer[cpu].data1,
+		 err_data_buffer[cpu].data2,
+		 err_data_buffer[cpu].data3,
+		 cpu);
+#endif
+	ret=sscanf(buf, "%lx, %lx, %lx",
+			&err_data_buffer[cpu].data1,
+			&err_data_buffer[cpu].data2,
+			&err_data_buffer[cpu].data3);
+	if (ret!=ERR_DATA_BUFFER_SIZE)
+		return -EINVAL;
+
+	return size;
+}
+
+show(status)
+show(capabilities)
+show(resources)
+
+define_one_rw(call_start);
+define_one_rw(err_type_info);
+define_one_rw(err_struct_info);
+define_one_rw(err_data_buffer);
+define_one_rw(virtual_to_phys);
+define_one_ro(status);
+define_one_ro(capabilities);
+define_one_ro(resources);
+
+static struct attribute *default_attrs[] = {
+	&attr_call_start.attr,
+	&attr_virtual_to_phys.attr,
+	&attr_err_type_info.attr,
+	&attr_err_struct_info.attr,
+	&attr_err_data_buffer.attr,
+	&attr_status.attr,
+	&attr_capabilities.attr,
+	&attr_resources.attr,
+	NULL
+};
+
+static struct attribute_group err_inject_attr_group = {
+	.attrs = default_attrs,
+	.name = "err_inject"
+};
+/* Add/Remove err_inject interface for CPU device */
+static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
+{
+	return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
+}
+
+static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
+{
+	sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
+	return 0;
+}
+static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
+		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:
+		err_inject_add_dev(sys_dev);
+		break;
+	case CPU_DEAD:
+		err_inject_remove_dev(sys_dev);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
+{
+	.notifier_call = err_inject_cpu_callback,
+};
+
+static int __init
+err_inject_init(void)
+{
+	int i;
+
+#ifdef ERR_INJ_DEBUG
+	printk(KERN_INFO "Enter error injection driver.\n");
+#endif
+	for_each_online_cpu(i) {
+		err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
+				(void *)(long)i);
+	}
+
+	register_hotcpu_notifier(&err_inject_cpu_notifier);
+
+	return 0;
+}
+
+static void __exit
+err_inject_exit(void)
+{
+	int i;
+	struct sys_device *sys_dev;
+
+#ifdef ERR_INJ_DEBUG
+	printk(KERN_INFO "Exit error injection driver.\n");
+#endif
+	for_each_online_cpu(i) {
+		sys_dev = get_cpu_sysdev(i);
+		sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
+	}
+	unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
+MODULE_DESCRIPTION("MC error injection kenrel sysfs interface");
+MODULE_LICENSE("GPL");
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index dcfbf3e..93d9ab1 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -87,7 +87,6 @@ #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/pci.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/bootmem.h>
 
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 456f57b..1c5044a 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -27,7 +27,6 @@ #include <linux/ptrace.h>
 #include <linux/random.h>	/* for rand_initialize_irq() */
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/threads.h>
 #include <linux/bitops.h>
 #include <linux/irq.h>
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 6b7fcbd..34f44d8 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -374,6 +374,7 @@ ENTRY(alt_dtlb_miss)
 	movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
 	mov r21=cr.ipsr
 	mov r31=pr
+	mov r24=PERCPU_ADDR
 	;;
 #ifdef CONFIG_DISABLE_VHPT
 	shr.u r22=r16,61			// get the region number into r21
@@ -386,22 +387,30 @@ (p8)	mov cr.iha=r17
 (p8)	mov r29=b0				// save b0
 (p8)	br.cond.dptk dtlb_fault
 #endif
+	cmp.ge p10,p11=r16,r24			// access to per_cpu_data?
+	tbit.z p12,p0=r16,61			// access to region 6?
+	mov r25=PERCPU_PAGE_SHIFT << 2
+	mov r26=PERCPU_PAGE_SIZE
+	nop.m 0
+	nop.b 0
+	;;
+(p10)	mov r19=IA64_KR(PER_CPU_DATA)
+(p11)	and r19=r19,r16				// clear non-ppn fields
 	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)
+(p10)	sub r19=r19,r26
+(p10)	mov cr.itir=r25
 	cmp.ne p8,p0=r0,r23
 (p9)	cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22	// check isr.code field
+(p12)	dep r17=-1,r17,4,1			// set ma=UC for region 6 addr
 (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
+	or r19=r19,r17		// insert PTE control bits into r19
 (p6)	mov cr.ipsr=r21
 	;;
 (p7)	itc.d r19		// insert the TLB entry
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 6cb56dd..4f5fd09 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -29,9 +29,9 @@ #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
 #include <linux/moduleloader.h>
+#include <linux/kdebug.h>
 
 #include <asm/pgtable.h>
-#include <asm/kdebug.h>
 #include <asm/sections.h>
 #include <asm/uaccess.h>
 
@@ -444,7 +444,8 @@ int __kprobes trampoline_probe_handler(s
 			break;
 	}
 
-	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
 	regs->cr_iip = orig_ret_address;
 
 	reset_current_kprobe();
@@ -464,23 +465,13 @@ int __kprobes trampoline_probe_handler(s
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 				      struct pt_regs *regs)
 {
-	struct kretprobe_instance *ri;
-
-	if ((ri = get_free_rp_inst(rp)) != NULL) {
-		ri->rp = rp;
-		ri->task = current;
-		ri->ret_addr = (kprobe_opcode_t *)regs->b0;
-
-		/* Replace the return addr with trampoline addr */
-		regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
+	ri->ret_addr = (kprobe_opcode_t *)regs->b0;
 
-		add_rp_inst(ri);
-	} else {
-		rp->nmissed++;
-	}
+	/* Replace the return addr with trampoline addr */
+	regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
 }
 
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
@@ -1021,3 +1012,12 @@ int __init arch_init_kprobes(void)
 		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
 	return register_kprobe(&trampoline_p);
 }
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	if (p->addr ==
+		(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip)
+		return 1;
+
+	return 0;
+}
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 491687f..1d7cc7e 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -63,7 +63,6 @@ #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
 #include <linux/timer.h>
@@ -72,9 +71,9 @@ #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/workqueue.h>
 #include <linux/cpumask.h>
+#include <linux/kdebug.h>
 
 #include <asm/delay.h>
-#include <asm/kdebug.h>
 #include <asm/machvec.h>
 #include <asm/meminit.h>
 #include <asm/page.h>
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index c6b607c..8c9c26a 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -101,14 +101,6 @@ (p7)	br.cond.dpnt.few 4f
 	;;
 	srlz.d
 	;;
-	// 2. Purge DTR for PERCPU data.
-	movl r16=PERCPU_ADDR
-	mov r18=PERCPU_PAGE_SHIFT<<2
-	;;
-	ptr.d r16,r18
-	;;
-	srlz.d
-	;;
 	// 3. Purge ITR for PAL code.
 	GET_THIS_PADDR(r2, ia64_mca_pal_base)
 	;;
@@ -196,22 +188,6 @@ ia64_reload_tr:
 	srlz.i
 	srlz.d
 	;;
-	// 2. Reload DTR register for PERCPU data.
-	GET_THIS_PADDR(r2, ia64_mca_per_cpu_pte)
-	;;
-	movl r16=PERCPU_ADDR		// vaddr
-	movl r18=PERCPU_PAGE_SHIFT<<2
-	;;
-	mov cr.itir=r18
-	mov cr.ifa=r16
-	;;
-	ld8 r18=[r2]			// load per-CPU PTE
-	mov r16=IA64_TR_PERCPU_DATA;
-	;;
-	itr.d dtr[r16]=r18
-	;;
-	srlz.d
-	;;
 	// 3. Reload ITR for PAL code.
 	GET_THIS_PADDR(r2, ia64_mca_pal_pte)
 	;;
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 832cf1e..70b8bdb 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -14,7 +14,6 @@ #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kallsyms.h>
-#include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
 #include <linux/timer.h>
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index bc11bb0..e796e29 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -195,3 +195,23 @@ #	define END(name)	((unsigned long)__end
 	ia64_patch_vtop(START(vtop), END(vtop));
 	ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
 }
+
+void ia64_patch_phys_stack_reg(unsigned long val)
+{
+	s32 * offp = (s32 *) __start___phys_stack_reg_patchlist;
+	s32 * end = (s32 *) __end___phys_stack_reg_patchlist;
+	u64 ip, mask, imm;
+
+	/* see instruction format A4: adds r1 = imm13, r3 */
+	mask = (0x3fUL << 27) | (0x7f << 13);
+	imm = (((val >> 7) & 0x3f) << 27) | (val & 0x7f) << 13;
+
+	while (offp < end) {
+		ip = (u64) offp + *offp;
+		ia64_patch(ip, mask, imm);
+		ia64_fc(ip);
+		++offp;
+	}
+	ia64_sync_i();
+	ia64_srlz_i();
+}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index abc7ad0..e7191ca 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -23,7 +23,6 @@ #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index ae96d41..8bb571a 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -20,20 +20,19 @@ #include <linux/notifier.h>
 #include <linux/personality.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/thread_info.h>
 #include <linux/unistd.h>
 #include <linux/efi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/kdebug.h>
 
 #include <asm/cpu.h>
 #include <asm/delay.h>
 #include <asm/elf.h>
 #include <asm/ia32.h>
 #include <asm/irq.h>
-#include <asm/kdebug.h>
 #include <asm/kexec.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index af9f875..a51f1d0 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -42,7 +42,6 @@ #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/vmalloc.h>
 
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index dc7dd76..6e19da1 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -75,7 +75,6 @@ extern void ia64_setup_printk_clock(void
 
 DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
 DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
-DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
@@ -869,6 +868,7 @@ void __cpuinit
 cpu_init (void)
 {
 	extern void __cpuinit ia64_mmu_init (void *);
+	static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
 	unsigned long num_phys_stacked;
 	pal_vm_info_2_u_t vmi;
 	unsigned int max_ctx;
@@ -982,7 +982,10 @@ #endif
 		num_phys_stacked = 96;
 	}
 	/* size of physical stacked register partition plus 8 bytes: */
-	__get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8;
+	if (num_phys_stacked > max_num_phys_stacked) {
+		ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8);
+		max_num_phys_stacked = num_phys_stacked;
+	}
 	platform_cpu_init();
 	pm_idle = default_idle;
 }
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 77f8b49..0dcd56d 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -14,7 +14,6 @@ #include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index ff7df43..a44792d 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -35,7 +35,6 @@ #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/efi.h>
 #include <linux/percpu.h>
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 9ef62a3..1eda194 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -13,7 +13,6 @@ #include <linux/sched.h>
 #include <linux/shm.h>
 #include <linux/file.h>		/* doh, must come after sched.h... */
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/highuid.h>
 #include <linux/hugetlb.h>
@@ -33,6 +32,13 @@ arch_get_unmapped_area (struct file *fil
 	if (len > RGN_MAP_LIMIT)
 		return -ENOMEM;
 
+	/* handle fixed mapping: prevent overlap with huge pages */
+	if (flags & MAP_FIXED) {
+		if (is_hugepage_only_range(mm, addr, len))
+			return -EINVAL;
+		return addr;
+	}
+
 #ifdef CONFIG_HUGETLB_PAGE
 	if (REGION_NUMBER(addr) == RGN_HPAGE)
 		addr = 0;
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 39e0cd3..a06667c 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -235,7 +235,7 @@ #endif
 
 static struct irqaction timer_irqaction = {
 	.handler =	timer_interrupt,
-	.flags =	IRQF_DISABLED,
+	.flags =	IRQF_DISABLED | IRQF_IRQPOLL,
 	.name =		"timer"
 };
 
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 765cbe5..5bfb8be 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -16,33 +16,17 @@ #include <linux/module.h>       /* for E
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
 #include <linux/delay.h>		/* for ssleep() */
+#include <linux/kdebug.h>
 
 #include <asm/fpswa.h>
 #include <asm/ia32.h>
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
-#include <asm/kdebug.h>
 
 fpswa_interface_t *fpswa_interface;
 EXPORT_SYMBOL(fpswa_interface);
 
-ATOMIC_NOTIFIER_HEAD(ia64die_chain);
-
-int
-register_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&ia64die_chain, nb);
-}
-EXPORT_SYMBOL_GPL(register_die_notifier);
-
-int
-unregister_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&ia64die_chain, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_die_notifier);
-
 void __init
 trap_init (void)
 {
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index 1e35755..fe6aa5a 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -15,7 +15,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/tty.h>
 
 #include <asm/intrinsics.h>
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 25dd55e..6923826 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -78,6 +78,13 @@ #endif
 	  __stop___mca_table = .;
 	}
 
+  .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET)
+	{
+	  __start___phys_stack_reg_patchlist = .;
+	  *(.data.patch.phys_stack_reg)
+	  __end___phys_stack_reg_patchlist = .;
+	}
+
   /* Global data */
   _data = .;
 
diff --git a/arch/ia64/lib/csum_partial_copy.c b/arch/ia64/lib/csum_partial_copy.c
index 503dfe6..118daf5 100644
--- a/arch/ia64/lib/csum_partial_copy.c
+++ b/arch/ia64/lib/csum_partial_copy.c
@@ -128,6 +128,8 @@ csum_partial_copy_from_user(const void _
 	return (__force __wsum)result;
 }
 
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
 __wsum
 csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 {
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 872da7a..9484444 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -693,6 +693,7 @@ #endif
 	zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
 pg_data_t *arch_alloc_nodedata(int nid)
 {
 	unsigned long size = compute_pernodesize(nid);
@@ -710,3 +711,4 @@ void arch_refresh_nodedata(int update_no
 	pgdat_list[update_node] = update_pgdat;
 	scatter_node_data();
 }
+#endif
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 59f3ab9..21658e0 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -7,15 +7,14 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kprobes.h>
+#include <linux/kdebug.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/kdebug.h>
 
 extern void die (char *, struct pt_regs *, long);
 
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 0c7e94e..1346b7f 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -13,7 +13,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 #include <asm/mman.h>
@@ -148,6 +147,14 @@ unsigned long hugetlb_get_unmapped_area(
 		return -ENOMEM;
 	if (len & ~HPAGE_MASK)
 		return -EINVAL;
+
+	/* Handle MAP_FIXED */
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(addr, len, pgoff))
+			return -EINVAL;
+		return addr;
+	}
+
 	/* This code assumes that RGN_HPAGE != 0. */
 	if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
 		addr = HPAGE_REGION_BASE;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 4f36987..cffb1e8 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -121,7 +121,7 @@ lazy_mmu_prot_update (pte_t pte)
 		return;				/* i-cache is already coherent with d-cache */
 
 	if (PageCompound(page)) {
-		order = (unsigned long) (page[1].lru.prev);
+		order = compound_order(page);
 		flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT));
 	}
 	else
@@ -355,7 +355,7 @@ #endif
 void __devinit
 ia64_mmu_init (void *my_cpu_data)
 {
-	unsigned long psr, pta, impl_va_bits;
+	unsigned long pta, impl_va_bits;
 	extern void __devinit tlb_init (void);
 
 #ifdef CONFIG_DISABLE_VHPT
@@ -364,15 +364,6 @@ #else
 #	define VHPT_ENABLE_BIT	1
 #endif
 
-	/* Pin mapping for percpu area into TLB */
-	psr = ia64_clear_ic();
-	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
-		 pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)),
-		 PERCPU_PAGE_SHIFT);
-
-	ia64_set_psr(psr);
-	ia64_srlz_i();
-
 	/*
 	 * Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
 	 * address space.  The IA-64 architecture guarantees that at least 50 bits of
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
index 4280c07..2a14062 100644
--- a/arch/ia64/mm/ioremap.c
+++ b/arch/ia64/mm/ioremap.c
@@ -1,5 +1,5 @@
 /*
- * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
+ * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P.
  *	Bjorn Helgaas <bjorn.helgaas@hp.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -10,51 +10,101 @@
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/meminit.h>
 
 static inline void __iomem *
-__ioremap (unsigned long offset, unsigned long size)
+__ioremap (unsigned long phys_addr)
 {
-	return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
+	return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
 }
 
 void __iomem *
-ioremap (unsigned long offset, unsigned long size)
+ioremap (unsigned long phys_addr, unsigned long size)
 {
+	void __iomem *addr;
+	struct vm_struct *area;
+	unsigned long offset;
+	pgprot_t prot;
 	u64 attr;
 	unsigned long gran_base, gran_size;
+	unsigned long page_base;
 
 	/*
 	 * For things in kern_memmap, we must use the same attribute
 	 * as the rest of the kernel.  For more details, see
 	 * Documentation/ia64/aliasing.txt.
 	 */
-	attr = kern_mem_attribute(offset, size);
+	attr = kern_mem_attribute(phys_addr, size);
 	if (attr & EFI_MEMORY_WB)
-		return (void __iomem *) phys_to_virt(offset);
+		return (void __iomem *) phys_to_virt(phys_addr);
 	else if (attr & EFI_MEMORY_UC)
-		return __ioremap(offset, size);
+		return __ioremap(phys_addr);
 
 	/*
 	 * Some chipsets don't support UC access to memory.  If
 	 * WB is supported for the whole granule, we prefer that.
 	 */
-	gran_base = GRANULEROUNDDOWN(offset);
-	gran_size = GRANULEROUNDUP(offset + size) - gran_base;
+	gran_base = GRANULEROUNDDOWN(phys_addr);
+	gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base;
 	if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
-		return (void __iomem *) phys_to_virt(offset);
+		return (void __iomem *) phys_to_virt(phys_addr);
 
-	return __ioremap(offset, size);
+	/*
+	 * WB is not supported for the whole granule, so we can't use
+	 * the region 7 identity mapping.  If we can safely cover the
+	 * area with kernel page table mappings, we can use those
+	 * instead.
+	 */
+	page_base = phys_addr & PAGE_MASK;
+	size = PAGE_ALIGN(phys_addr + size) - page_base;
+	if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) {
+		prot = PAGE_KERNEL;
+
+		/*
+		 * Mappings have to be page-aligned
+		 */
+		offset = phys_addr & ~PAGE_MASK;
+		phys_addr &= PAGE_MASK;
+
+		/*
+		 * Ok, go for it..
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area)
+			return NULL;
+
+		area->phys_addr = phys_addr;
+		addr = (void __iomem *) area->addr;
+		if (ioremap_page_range((unsigned long) addr,
+				(unsigned long) addr + size, phys_addr, prot)) {
+			vunmap((void __force *) addr);
+			return NULL;
+		}
+
+		return (void __iomem *) (offset + (char __iomem *)addr);
+	}
+
+	return __ioremap(phys_addr);
 }
 EXPORT_SYMBOL(ioremap);
 
 void __iomem *
-ioremap_nocache (unsigned long offset, unsigned long size)
+ioremap_nocache (unsigned long phys_addr, unsigned long size)
 {
-	if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB)
+	if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
 		return NULL;
 
-	return __ioremap(offset, size);
+	return __ioremap(phys_addr);
 }
 EXPORT_SYMBOL(ioremap_nocache);
+
+void
+iounmap (volatile void __iomem *addr)
+{
+	if (REGION_NUMBER(addr) == RGN_GATE)
+		vunmap((void *) ((unsigned long) addr & PAGE_MASK));
+}
+EXPORT_SYMBOL(iounmap);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 0e83f3b..3549f3b 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -18,7 +18,6 @@ #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
 #include <asm/machvec.h>
@@ -659,8 +658,6 @@ pci_mmap_legacy_page_range(struct pci_bu
 		return -EINVAL;
 	prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
 				    vma->vm_page_prot);
-	if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot)))
-		return -EINVAL;
 
 	addr = pci_get_legacy_mem(bus);
 	if (IS_ERR(addr))
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index fcf7f93..2c3f9df 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -8,7 +8,6 @@
 
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <asm/delay.h>
 #include <asm/sn/sn_sal.h>
 #include "ioerror.h"
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 49873aa..83f190f 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -87,7 +87,6 @@ int sn_setup_msi_irq(struct pci_dev *pde
 	if (irq < 0)
 		return irq;
 
-	set_irq_msi(irq, entry);
 	/*
 	 * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
 	 * decide which cpu to direct this msi at by default.
@@ -144,10 +143,11 @@ int sn_setup_msi_irq(struct pci_dev *pde
 	 */
 	msg.data = 0x100 + irq;
 
+	set_irq_msi(irq, entry);
 	write_msi_msg(irq, &msg);
 	set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
 
-	return irq;
+	return 0;
 }
 
 #ifdef CONFIG_SMP
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index 68355ef..e336e16 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -55,9 +55,9 @@ #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/completion.h>
+#include <linux/kdebug.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn_sal.h>
-#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 #include <asm/sn/xpc.h>
 
@@ -1332,7 +1332,7 @@ xpc_init(void)
 		dev_warn(xpc_part, "can't register reboot notifier\n");
 	}
 
-	/* add ourselves to the die_notifier list (i.e., ia64die_chain) */
+	/* add ourselves to the die_notifier list */
 	ret = register_die_notifier(&xpc_die_notifier);
 	if (ret != 0) {
 		dev_warn(xpc_part, "can't register die notifier\n");
diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c
index c8173db..88fad85 100644
--- a/arch/ia64/sn/kernel/xpnet.c
+++ b/arch/ia64/sn/kernel/xpnet.c
@@ -24,7 +24,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
@@ -233,7 +232,7 @@ xpnet_receive(partid_t partid, int chann
 			"%lu)\n", skb->data, &msg->data,
 			(size_t) msg->embedded_bytes);
 
-		memcpy(skb->data, &msg->data, (size_t) msg->embedded_bytes);
+		skb_copy_to_linear_data(skb, &msg->data, (size_t)msg->embedded_bytes);
 	} else {
 		dev_dbg(xpnet, "transferring buffer to the skb->data area;\n\t"
 			"bte_copy(0x%p, 0x%p, %hu)\n", (void *)msg->buf_pa,
@@ -264,17 +263,16 @@ xpnet_receive(partid_t partid, int chann
 
 	dev_dbg(xpnet, "<skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
 		"skb->end=0x%p skb->len=%d\n", (void *) skb->head,
-		(void *) skb->data, (void *) skb->tail, (void *) skb->end,
+		(void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb),
 		skb->len);
 
-	skb->dev = xpnet_device;
 	skb->protocol = eth_type_trans(skb, xpnet_device);
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 
 	dev_dbg(xpnet, "passing skb to network layer; \n\tskb->head=0x%p "
 		"skb->data=0x%p skb->tail=0x%p skb->end=0x%p skb->len=%d\n",
-		(void *) skb->head, (void *) skb->data, (void *) skb->tail,
-		(void *) skb->end, skb->len);
+		(void *)skb->head, (void *)skb->data, skb_tail_pointer(skb),
+		skb_end_pointer(skb), skb->len);
 
 
 	xpnet_device->last_rx = jiffies;
@@ -476,7 +474,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff
 
 	dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
 		"skb->end=0x%p skb->len=%d\n", (void *) skb->head,
-		(void *) skb->data, (void *) skb->tail, (void *) skb->end,
+		(void *)skb->data, skb_tail_pointer(skb), skb_end_pointer(skb),
 		skb->len);
 
 
@@ -498,7 +496,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff
 
 	/* get the beginning of the first cacheline and end of last */
 	start_addr = ((u64) skb->data & ~(L1_CACHE_BYTES - 1));
-	end_addr = L1_CACHE_ALIGN((u64) skb->tail);
+	end_addr = L1_CACHE_ALIGN((u64)skb_tail_pointer(skb));
 
 	/* calculate how many bytes to embed in the XPC message */
 	embedded_bytes = 0;
@@ -567,14 +565,15 @@ xpnet_dev_hard_start_xmit(struct sk_buff
 			msg->version = XPNET_VERSION_EMBED;
 			dev_dbg(xpnet, "calling memcpy(0x%p, 0x%p, 0x%lx)\n",
 				&msg->data, skb->data, (size_t) embedded_bytes);
-			memcpy(&msg->data, skb->data, (size_t) embedded_bytes);
+			skb_copy_from_linear_data(skb, &msg->data,
+						  (size_t)embedded_bytes);
 		} else {
 			msg->version = XPNET_VERSION;
 		}
 		msg->magic = XPNET_MAGIC;
 		msg->size = end_addr - start_addr;
 		msg->leadin_ignore = (u64) skb->data - start_addr;
-		msg->tailout_ignore = end_addr - (u64) skb->tail;
+		msg->tailout_ignore = end_addr - (u64)skb_tail_pointer(skb);
 		msg->buf_pa = __pa(start_addr);
 
 		dev_dbg(xpnet, "sending XPC message to %d:%d\nmsg->buf_pa="
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
index 8cbbb0b..41a4c95 100644
--- a/arch/m32r/kernel/m32r_ksyms.c
+++ b/arch/m32r/kernel/m32r_ksyms.c
@@ -5,7 +5,6 @@ #include <linux/elfcore.h>
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 
 #include <asm/semaphore.h>
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index 4b15605..916faf6 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -13,7 +13,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 48d376f..3eb3059 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -43,7 +43,6 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/irq.h>
 #include <linux/bootmem.h>
 #include <linux/delay.h>
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
index b4e7bcb..bda8554 100644
--- a/arch/m32r/kernel/sys_m32r.c
+++ b/arch/m32r/kernel/sys_m32r.c
@@ -11,7 +11,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 439cc25..6c73bca 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -110,7 +110,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(32);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
index 9880aba..8846917 100644
--- a/arch/m32r/mm/fault-nommu.c
+++ b/arch/m32r/mm/fault-nommu.c
@@ -17,7 +17,6 @@ #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/vt_kern.h>              /* For unblank_screen() */
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index 037d58e..f3935ba 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -18,7 +18,6 @@ #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>
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index a8e1e60..b8536c7 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -409,6 +409,9 @@ config STRAM_PROC
 	help
 	  Say Y here to report ST-RAM usage statistics in /proc/stram.
 
+config ATARI_KBD_CORE
+	bool
+
 config HEARTBEAT
 	bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
 	default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 34d826d..c20831a 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -21,7 +21,7 @@ AS += -m68020
 LDFLAGS := -m m68kelf
 ifneq ($(COMPILE_ARCH),$(ARCH))
 	# prefix for cross-compiling binaries
-	CROSS_COMPILE = m68k-linux-
+	CROSS_COMPILE = m68k-linux-gnu-
 endif
 
 ifdef CONFIG_SUN3
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index 28d95cf..907a553 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -54,7 +54,7 @@ static irqreturn_t ami_int5(int irq, voi
 
 static struct irq_controller amiga_irq_controller = {
 	.name		= "amiga",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock),
 	.enable		= amiga_enable_irq,
 	.disable	= amiga_disable_irq,
 };
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 7a20058..c4a4ffd 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -123,7 +123,7 @@ static void cia_disable_irq(unsigned int
 
 static struct irq_controller cia_irq_controller = {
 	.name		= "cia",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(cia_irq_controller.lock),
 	.enable		= cia_enable_irq,
 	.disable	= cia_disable_irq,
 };
@@ -160,7 +160,7 @@ static void auto_disable_irq(unsigned in
 
 static struct irq_controller auto_irq_controller = {
 	.name		= "auto",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
 	.enable		= auto_enable_irq,
 	.disable	= auto_disable_irq,
 };
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 3204f41..3574853 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -22,9 +22,7 @@ #include <linux/init.h>
 #include <linux/vt_kern.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
-#endif
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -62,55 +60,51 @@ static char s_cdtv[] __initdata = "CDTV"
 static char s_cd32[] __initdata = "CD32";
 static char s_draco[] __initdata = "Draco";
 static char *amiga_models[] __initdata = {
-    [AMI_500-AMI_500]		= s_a500,
-    [AMI_500PLUS-AMI_500]	= s_a500p,
-    [AMI_600-AMI_500]		= s_a600,
-    [AMI_1000-AMI_500]		= s_a1000,
-    [AMI_1200-AMI_500]		= s_a1200,
-    [AMI_2000-AMI_500]		= s_a2000,
-    [AMI_2500-AMI_500]		= s_a2500,
-    [AMI_3000-AMI_500]		= s_a3000,
-    [AMI_3000T-AMI_500]		= s_a3000t,
-    [AMI_3000PLUS-AMI_500]	= s_a3000p,
-    [AMI_4000-AMI_500]		= s_a4000,
-    [AMI_4000T-AMI_500]		= s_a4000t,
-    [AMI_CDTV-AMI_500]		= s_cdtv,
-    [AMI_CD32-AMI_500]		= s_cd32,
-    [AMI_DRACO-AMI_500]		= s_draco,
+	[AMI_500-AMI_500]	= s_a500,
+	[AMI_500PLUS-AMI_500]	= s_a500p,
+	[AMI_600-AMI_500]	= s_a600,
+	[AMI_1000-AMI_500]	= s_a1000,
+	[AMI_1200-AMI_500]	= s_a1200,
+	[AMI_2000-AMI_500]	= s_a2000,
+	[AMI_2500-AMI_500]	= s_a2500,
+	[AMI_3000-AMI_500]	= s_a3000,
+	[AMI_3000T-AMI_500]	= s_a3000t,
+	[AMI_3000PLUS-AMI_500]	= s_a3000p,
+	[AMI_4000-AMI_500]	= s_a4000,
+	[AMI_4000T-AMI_500]	= s_a4000t,
+	[AMI_CDTV-AMI_500]	= s_cdtv,
+	[AMI_CD32-AMI_500]	= s_cd32,
+	[AMI_DRACO-AMI_500]	= s_draco,
 };
 
 static char amiga_model_name[13] = "Amiga ";
 
-extern char m68k_debug_device[];
-
 static void amiga_sched_init(irq_handler_t handler);
 /* amiga specific irq functions */
-extern void amiga_init_IRQ (void);
+extern void amiga_init_IRQ(void);
 static void amiga_get_model(char *model);
 static int amiga_get_hardware_list(char *buffer);
 /* amiga specific timer functions */
-static unsigned long amiga_gettimeoffset (void);
-static int a3000_hwclk (int, struct rtc_time *);
-static int a2000_hwclk (int, struct rtc_time *);
-static int amiga_set_clock_mmss (unsigned long);
-static unsigned int amiga_get_ss (void);
-extern void amiga_mksound( unsigned int count, unsigned int ticks );
-static void amiga_reset (void);
+static unsigned long amiga_gettimeoffset(void);
+static int a3000_hwclk(int, struct rtc_time *);
+static int a2000_hwclk(int, struct rtc_time *);
+static int amiga_set_clock_mmss(unsigned long);
+static unsigned int amiga_get_ss(void);
+extern void amiga_mksound(unsigned int count, unsigned int ticks);
+static void amiga_reset(void);
 extern void amiga_init_sound(void);
-static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(struct console *co, const char *b,
 				    unsigned int count);
 void amiga_serial_console_write(struct console *co, const char *s,
 				unsigned int count);
-static void amiga_debug_init(void);
 #ifdef CONFIG_HEARTBEAT
 static void amiga_heartbeat(int on);
 #endif
 
 static struct console amiga_console_driver = {
-	.name =		"debug",
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
+	.name	= "debug",
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
 };
 
 
@@ -119,24 +113,24 @@ static struct console amiga_console_driv
      */
 
 static struct {
-    struct resource _ciab, _ciaa, _custom, _kickstart;
+	struct resource _ciab, _ciaa, _custom, _kickstart;
 } mb_resources = {
-    ._ciab = {
-	.name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
-    },
-    ._ciaa = {
-	.name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
-    },
-    ._custom = {
-	.name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
-    },
-    ._kickstart = {
-	.name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
-    }
+	._ciab = {
+		.name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
+	},
+	._ciaa = {
+		.name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
+	},
+	._custom = {
+		.name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
+	},
+	._kickstart = {
+		.name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
+	}
 };
 
 static struct resource rtc_resource = {
-    .start = 0x00dc0000, .end = 0x00dcffff
+	.start = 0x00dc0000, .end = 0x00dcffff
 };
 
 static struct resource ram_resource[NUM_MEMINFO];
@@ -148,57 +142,57 @@ static struct resource ram_resource[NUM_
 
 int amiga_parse_bootinfo(const struct bi_record *record)
 {
-    int unknown = 0;
-    const unsigned long *data = record->data;
+	int unknown = 0;
+	const unsigned long *data = record->data;
 
-    switch (record->tag) {
+	switch (record->tag) {
 	case BI_AMIGA_MODEL:
-	    amiga_model = *data;
-	    break;
+		amiga_model = *data;
+		break;
 
 	case BI_AMIGA_ECLOCK:
-	    amiga_eclock = *data;
-	    break;
+		amiga_eclock = *data;
+		break;
 
 	case BI_AMIGA_CHIPSET:
-	    amiga_chipset = *data;
-	    break;
+		amiga_chipset = *data;
+		break;
 
 	case BI_AMIGA_CHIP_SIZE:
-	    amiga_chip_size = *(const int *)data;
-	    break;
+		amiga_chip_size = *(const int *)data;
+		break;
 
 	case BI_AMIGA_VBLANK:
-	    amiga_vblank = *(const unsigned char *)data;
-	    break;
+		amiga_vblank = *(const unsigned char *)data;
+		break;
 
 	case BI_AMIGA_PSFREQ:
-	    amiga_psfreq = *(const unsigned char *)data;
-	    break;
+		amiga_psfreq = *(const unsigned char *)data;
+		break;
 
 	case BI_AMIGA_AUTOCON:
 #ifdef CONFIG_ZORRO
-	    if (zorro_num_autocon < ZORRO_NUM_AUTO) {
-		const struct ConfigDev *cd = (struct ConfigDev *)data;
-		struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
-		dev->rom = cd->cd_Rom;
-		dev->slotaddr = cd->cd_SlotAddr;
-		dev->slotsize = cd->cd_SlotSize;
-		dev->resource.start = (unsigned long)cd->cd_BoardAddr;
-		dev->resource.end = dev->resource.start+cd->cd_BoardSize-1;
-	    } else
-		printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
+		if (zorro_num_autocon < ZORRO_NUM_AUTO) {
+			const struct ConfigDev *cd = (struct ConfigDev *)data;
+			struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
+			dev->rom = cd->cd_Rom;
+			dev->slotaddr = cd->cd_SlotAddr;
+			dev->slotsize = cd->cd_SlotSize;
+			dev->resource.start = (unsigned long)cd->cd_BoardAddr;
+			dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1;
+		} else
+			printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
 #endif /* CONFIG_ZORRO */
-	    break;
+		break;
 
 	case BI_AMIGA_SERPER:
-	    /* serial port period: ignored here */
-	    break;
+		/* serial port period: ignored here */
+		break;
 
 	default:
-	    unknown = 1;
-    }
-    return(unknown);
+		unknown = 1;
+	}
+	return unknown;
 }
 
     /*
@@ -207,159 +201,159 @@ #endif /* CONFIG_ZORRO */
 
 static void __init amiga_identify(void)
 {
-  /* Fill in some default values, if necessary */
-  if (amiga_eclock == 0)
-    amiga_eclock = 709379;
-
-  memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
-
-  printk("Amiga hardware found: ");
-  if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
-    printk("[%s] ", amiga_models[amiga_model-AMI_500]);
-    strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
-  }
-
-  switch(amiga_model) {
-  case AMI_UNKNOWN:
-    goto Generic;
-
-  case AMI_600:
-  case AMI_1200:
-    AMIGAHW_SET(A1200_IDE);
-    AMIGAHW_SET(PCMCIA);
-  case AMI_500:
-  case AMI_500PLUS:
-  case AMI_1000:
-  case AMI_2000:
-  case AMI_2500:
-    AMIGAHW_SET(A2000_CLK);	/* Is this correct for all models? */
-    goto Generic;
-
-  case AMI_3000:
-  case AMI_3000T:
-    AMIGAHW_SET(AMBER_FF);
-    AMIGAHW_SET(MAGIC_REKICK);
-    /* fall through */
-  case AMI_3000PLUS:
-    AMIGAHW_SET(A3000_SCSI);
-    AMIGAHW_SET(A3000_CLK);
-    AMIGAHW_SET(ZORRO3);
-    goto Generic;
-
-  case AMI_4000T:
-    AMIGAHW_SET(A4000_SCSI);
-    /* fall through */
-  case AMI_4000:
-    AMIGAHW_SET(A4000_IDE);
-    AMIGAHW_SET(A3000_CLK);
-    AMIGAHW_SET(ZORRO3);
-    goto Generic;
-
-  case AMI_CDTV:
-  case AMI_CD32:
-    AMIGAHW_SET(CD_ROM);
-    AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
-    goto Generic;
-
-  Generic:
-    AMIGAHW_SET(AMI_VIDEO);
-    AMIGAHW_SET(AMI_BLITTER);
-    AMIGAHW_SET(AMI_AUDIO);
-    AMIGAHW_SET(AMI_FLOPPY);
-    AMIGAHW_SET(AMI_KEYBOARD);
-    AMIGAHW_SET(AMI_MOUSE);
-    AMIGAHW_SET(AMI_SERIAL);
-    AMIGAHW_SET(AMI_PARALLEL);
-    AMIGAHW_SET(CHIP_RAM);
-    AMIGAHW_SET(PAULA);
-
-    switch(amiga_chipset) {
-    case CS_OCS:
-    case CS_ECS:
-    case CS_AGA:
-      switch (amiga_custom.deniseid & 0xf) {
-      case 0x0c:
-	AMIGAHW_SET(DENISE_HR);
-	break;
-      case 0x08:
-	AMIGAHW_SET(LISA);
-	break;
-      }
-      break;
-    default:
-      AMIGAHW_SET(DENISE);
-      break;
-    }
-    switch ((amiga_custom.vposr>>8) & 0x7f) {
-    case 0x00:
-      AMIGAHW_SET(AGNUS_PAL);
-      break;
-    case 0x10:
-      AMIGAHW_SET(AGNUS_NTSC);
-      break;
-    case 0x20:
-    case 0x21:
-      AMIGAHW_SET(AGNUS_HR_PAL);
-      break;
-    case 0x30:
-    case 0x31:
-      AMIGAHW_SET(AGNUS_HR_NTSC);
-      break;
-    case 0x22:
-    case 0x23:
-      AMIGAHW_SET(ALICE_PAL);
-      break;
-    case 0x32:
-    case 0x33:
-      AMIGAHW_SET(ALICE_NTSC);
-      break;
-    }
-    AMIGAHW_SET(ZORRO);
-    break;
-
-  case AMI_DRACO:
-    panic("No support for Draco yet");
-
-  default:
-    panic("Unknown Amiga Model");
-  }
+	/* Fill in some default values, if necessary */
+	if (amiga_eclock == 0)
+		amiga_eclock = 709379;
 
-#define AMIGAHW_ANNOUNCE(name, str)			\
-  if (AMIGAHW_PRESENT(name))				\
-    printk(str)
-
-  AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
-  AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
-  AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
-  AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
-  AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
-  AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
-  AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
-  AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
-  AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
-  AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
-  AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
-  AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
-  AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
-  AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
-  AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
-  AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
-  AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
-  AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
-  AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
-  AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
-  AMIGAHW_ANNOUNCE(LISA, "LISA ");
-  AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
-  AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
-  AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
-  AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
-  AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
-  AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
-  AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
-  AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
-  if (AMIGAHW_PRESENT(ZORRO))
-    printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
-  printk("\n");
+	memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
+
+	printk("Amiga hardware found: ");
+	if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
+		printk("[%s] ", amiga_models[amiga_model-AMI_500]);
+		strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
+	}
+
+	switch (amiga_model) {
+	case AMI_UNKNOWN:
+		goto Generic;
+
+	case AMI_600:
+	case AMI_1200:
+		AMIGAHW_SET(A1200_IDE);
+		AMIGAHW_SET(PCMCIA);
+	case AMI_500:
+	case AMI_500PLUS:
+	case AMI_1000:
+	case AMI_2000:
+	case AMI_2500:
+		AMIGAHW_SET(A2000_CLK);	/* Is this correct for all models? */
+		goto Generic;
+
+	case AMI_3000:
+	case AMI_3000T:
+		AMIGAHW_SET(AMBER_FF);
+		AMIGAHW_SET(MAGIC_REKICK);
+		/* fall through */
+	case AMI_3000PLUS:
+		AMIGAHW_SET(A3000_SCSI);
+		AMIGAHW_SET(A3000_CLK);
+		AMIGAHW_SET(ZORRO3);
+		goto Generic;
+
+	case AMI_4000T:
+		AMIGAHW_SET(A4000_SCSI);
+		/* fall through */
+	case AMI_4000:
+		AMIGAHW_SET(A4000_IDE);
+		AMIGAHW_SET(A3000_CLK);
+		AMIGAHW_SET(ZORRO3);
+		goto Generic;
+
+	case AMI_CDTV:
+	case AMI_CD32:
+		AMIGAHW_SET(CD_ROM);
+		AMIGAHW_SET(A2000_CLK);             /* Is this correct? */
+		goto Generic;
+
+	Generic:
+		AMIGAHW_SET(AMI_VIDEO);
+		AMIGAHW_SET(AMI_BLITTER);
+		AMIGAHW_SET(AMI_AUDIO);
+		AMIGAHW_SET(AMI_FLOPPY);
+		AMIGAHW_SET(AMI_KEYBOARD);
+		AMIGAHW_SET(AMI_MOUSE);
+		AMIGAHW_SET(AMI_SERIAL);
+		AMIGAHW_SET(AMI_PARALLEL);
+		AMIGAHW_SET(CHIP_RAM);
+		AMIGAHW_SET(PAULA);
+
+		switch (amiga_chipset) {
+		case CS_OCS:
+		case CS_ECS:
+		case CS_AGA:
+			switch (amiga_custom.deniseid & 0xf) {
+			case 0x0c:
+				AMIGAHW_SET(DENISE_HR);
+				break;
+			case 0x08:
+				AMIGAHW_SET(LISA);
+				break;
+			}
+			break;
+		default:
+			AMIGAHW_SET(DENISE);
+			break;
+		}
+		switch ((amiga_custom.vposr>>8) & 0x7f) {
+		case 0x00:
+			AMIGAHW_SET(AGNUS_PAL);
+			break;
+		case 0x10:
+			AMIGAHW_SET(AGNUS_NTSC);
+			break;
+		case 0x20:
+		case 0x21:
+			AMIGAHW_SET(AGNUS_HR_PAL);
+			break;
+		case 0x30:
+		case 0x31:
+			AMIGAHW_SET(AGNUS_HR_NTSC);
+			break;
+		case 0x22:
+		case 0x23:
+			AMIGAHW_SET(ALICE_PAL);
+			break;
+		case 0x32:
+		case 0x33:
+			AMIGAHW_SET(ALICE_NTSC);
+			break;
+		}
+		AMIGAHW_SET(ZORRO);
+		break;
+
+	case AMI_DRACO:
+		panic("No support for Draco yet");
+
+	default:
+		panic("Unknown Amiga Model");
+	}
+
+#define AMIGAHW_ANNOUNCE(name, str)		\
+	if (AMIGAHW_PRESENT(name))		\
+		printk(str)
+
+	AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
+	AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
+	AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
+	AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
+	AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
+	AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
+	AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
+	AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
+	AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
+	AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
+	AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
+	AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
+	AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
+	AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
+	AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
+	AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
+	AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
+	AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
+	AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
+	AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
+	AMIGAHW_ANNOUNCE(LISA, "LISA ");
+	AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
+	AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
+	AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
+	AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
+	AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
+	AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
+	AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
+	AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
+	if (AMIGAHW_PRESENT(ZORRO))
+		printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
+	printk("\n");
 
 #undef AMIGAHW_ANNOUNCE
 }
@@ -370,119 +364,105 @@ #undef AMIGAHW_ANNOUNCE
 
 void __init config_amiga(void)
 {
-  int i;
-
-  amiga_debug_init();
-  amiga_identify();
-
-  /* Yuk, we don't have PCI memory */
-  iomem_resource.name = "Memory";
-  for (i = 0; i < 4; i++)
-    request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
-
-  mach_sched_init      = amiga_sched_init;
-  mach_init_IRQ        = amiga_init_IRQ;
-  mach_get_model       = amiga_get_model;
-  mach_get_hardware_list = amiga_get_hardware_list;
-  mach_gettimeoffset   = amiga_gettimeoffset;
-  if (AMIGAHW_PRESENT(A3000_CLK)){
-    mach_hwclk         = a3000_hwclk;
-    rtc_resource.name = "A3000 RTC";
-    request_resource(&iomem_resource, &rtc_resource);
-  }
-  else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
-    mach_hwclk         = a2000_hwclk;
-    rtc_resource.name = "A2000 RTC";
-    request_resource(&iomem_resource, &rtc_resource);
-  }
-
-  mach_max_dma_address = 0xffffffff; /*
-				      * default MAX_DMA=0xffffffff
-				      * on all machines. If we don't
-				      * do so, the SCSI code will not
-				      * be able to allocate any mem
-				      * for transfers, unless we are
-				      * dealing with a Z2 mem only
-				      * system.                  /Jes
-				      */
-
-  mach_set_clock_mmss  = amiga_set_clock_mmss;
-  mach_get_ss          = amiga_get_ss;
-  mach_reset           = amiga_reset;
+	int i;
+
+	amiga_identify();
+
+	/* Yuk, we don't have PCI memory */
+	iomem_resource.name = "Memory";
+	for (i = 0; i < 4; i++)
+		request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
+
+	mach_sched_init      = amiga_sched_init;
+	mach_init_IRQ        = amiga_init_IRQ;
+	mach_get_model       = amiga_get_model;
+	mach_get_hardware_list = amiga_get_hardware_list;
+	mach_gettimeoffset   = amiga_gettimeoffset;
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		mach_hwclk         = a3000_hwclk;
+		rtc_resource.name = "A3000 RTC";
+		request_resource(&iomem_resource, &rtc_resource);
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+		mach_hwclk         = a2000_hwclk;
+		rtc_resource.name = "A2000 RTC";
+		request_resource(&iomem_resource, &rtc_resource);
+	}
+
+	/*
+	 * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
+	 * code will not be able to allocate any mem for transfers, unless we are
+	 * dealing with a Z2 mem only system.                  /Jes
+	 */
+	mach_max_dma_address = 0xffffffff;
+
+	mach_set_clock_mmss  = amiga_set_clock_mmss;
+	mach_get_ss          = amiga_get_ss;
+	mach_reset           = amiga_reset;
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
-  mach_beep            = amiga_mksound;
+	mach_beep            = amiga_mksound;
 #endif
 
 #ifdef CONFIG_HEARTBEAT
-  mach_heartbeat = amiga_heartbeat;
+	mach_heartbeat = amiga_heartbeat;
 #endif
 
-  /* Fill in the clock values (based on the 700 kHz E-Clock) */
-  amiga_masterclock = 40*amiga_eclock;	/* 28 MHz */
-  amiga_colorclock = 5*amiga_eclock;	/* 3.5 MHz */
-
-  /* clear all DMA bits */
-  amiga_custom.dmacon = DMAF_ALL;
-  /* ensure that the DMA master bit is set */
-  amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
-
-  /* don't use Z2 RAM as system memory on Z3 capable machines */
-  if (AMIGAHW_PRESENT(ZORRO3)) {
-    int i, j;
-    u32 disabled_z2mem = 0;
-    for (i = 0; i < m68k_num_memory; i++)
-      if (m68k_memory[i].addr < 16*1024*1024) {
-	if (i == 0) {
-	  /* don't cut off the branch we're sitting on */
-	  printk("Warning: kernel runs in Zorro II memory\n");
-	  continue;
+	/* Fill in the clock values (based on the 700 kHz E-Clock) */
+	amiga_masterclock = 40*amiga_eclock;	/* 28 MHz */
+	amiga_colorclock = 5*amiga_eclock;	/* 3.5 MHz */
+
+	/* clear all DMA bits */
+	amiga_custom.dmacon = DMAF_ALL;
+	/* ensure that the DMA master bit is set */
+	amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
+
+	/* don't use Z2 RAM as system memory on Z3 capable machines */
+	if (AMIGAHW_PRESENT(ZORRO3)) {
+		int i, j;
+		u32 disabled_z2mem = 0;
+
+		for (i = 0; i < m68k_num_memory; i++) {
+			if (m68k_memory[i].addr < 16*1024*1024) {
+				if (i == 0) {
+					/* don't cut off the branch we're sitting on */
+					printk("Warning: kernel runs in Zorro II memory\n");
+					continue;
+				}
+				disabled_z2mem += m68k_memory[i].size;
+				m68k_num_memory--;
+				for (j = i; j < m68k_num_memory; j++)
+					m68k_memory[j] = m68k_memory[j+1];
+				i--;
+			}
+		}
+		if (disabled_z2mem)
+		printk("%dK of Zorro II memory will not be used as system memory\n",
+		disabled_z2mem>>10);
 	}
-	disabled_z2mem += m68k_memory[i].size;
-	m68k_num_memory--;
-	for (j = i; j < m68k_num_memory; j++)
-	  m68k_memory[j] = m68k_memory[j+1];
-	i--;
-      }
-    if (disabled_z2mem)
-      printk("%dK of Zorro II memory will not be used as system memory\n",
-	     disabled_z2mem>>10);
-  }
-
-  /* request all RAM */
-  for (i = 0; i < m68k_num_memory; i++) {
-    ram_resource[i].name =
-      (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
-      (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
-      "16-bit Slow RAM";
-    ram_resource[i].start = m68k_memory[i].addr;
-    ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
-    request_resource(&iomem_resource, &ram_resource[i]);
-  }
-
-  /* initialize chipram allocator */
-  amiga_chip_init ();
-
-  /* debugging using chipram */
-  if (!strcmp( m68k_debug_device, "mem" )){
-	  if (!AMIGAHW_PRESENT(CHIP_RAM))
-		  printk("Warning: no chipram present for debugging\n");
-	  else {
-		  amiga_savekmsg_init();
-		  amiga_console_driver.write = amiga_mem_console_write;
-		  register_console(&amiga_console_driver);
-	  }
-  }
-
-  /* our beloved beeper */
-  if (AMIGAHW_PRESENT(AMI_AUDIO))
-	  amiga_init_sound();
-
-  /*
-   * if it is an A3000, set the magic bit that forces
-   * a hard rekick
-   */
-  if (AMIGAHW_PRESENT(MAGIC_REKICK))
-	  *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
+
+	/* request all RAM */
+	for (i = 0; i < m68k_num_memory; i++) {
+		ram_resource[i].name =
+			(m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
+			(m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
+			"16-bit Slow RAM";
+		ram_resource[i].start = m68k_memory[i].addr;
+		ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
+		request_resource(&iomem_resource, &ram_resource[i]);
+	}
+
+	/* initialize chipram allocator */
+	amiga_chip_init();
+
+	/* our beloved beeper */
+	if (AMIGAHW_PRESENT(AMI_AUDIO))
+		amiga_init_sound();
+
+	/*
+	 * if it is an A3000, set the magic bit that forces
+	 * a hard rekick
+	 */
+	if (AMIGAHW_PRESENT(MAGIC_REKICK))
+		*(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
 }
 
 static unsigned short jiffy_ticks;
@@ -490,12 +470,12 @@ static unsigned short jiffy_ticks;
 static void __init amiga_sched_init(irq_handler_t timer_routine)
 {
 	static struct resource sched_res = {
-	    .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
+		.name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
 	};
 	jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
 	if (request_resource(&mb_resources._ciab, &sched_res))
-	    printk("Cannot allocate ciab.ta{lo,hi}\n");
+		printk("Cannot allocate ciab.ta{lo,hi}\n");
 	ciab.cra &= 0xC0;   /* turn off timer A, continuous mode, from Eclk */
 	ciab.talo = jiffy_ticks % 256;
 	ciab.tahi = jiffy_ticks / 256;
@@ -513,7 +493,7 @@ static void __init amiga_sched_init(irq_
 #define TICK_SIZE 10000
 
 /* This is always executed with interrupts disabled.  */
-static unsigned long amiga_gettimeoffset (void)
+static unsigned long amiga_gettimeoffset(void)
 {
 	unsigned short hi, lo, hi2;
 	unsigned long ticks, offset = 0;
@@ -585,15 +565,15 @@ static int a2000_hwclk(int op, struct rt
 
 	tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
 
-	while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
-	{
-	        tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-	        udelay(70);
-	        tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		udelay(70);
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
 	}
 
 	if (!cnt)
-		printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
+		printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n",
+			tod_2000.cntrl1);
 
 	if (!op) { /* read */
 		t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
@@ -606,7 +586,7 @@ static int a2000_hwclk(int op, struct rt
 		if (t->tm_year <= 69)
 			t->tm_year += 100;
 
-		if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+		if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) {
 			if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
 				t->tm_hour = 0;
 			else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
@@ -642,7 +622,7 @@ static int a2000_hwclk(int op, struct rt
 	return 0;
 }
 
-static int amiga_set_clock_mmss (unsigned long nowtime)
+static int amiga_set_clock_mmss(unsigned long nowtime)
 {
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
@@ -660,8 +640,7 @@ static int amiga_set_clock_mmss (unsigne
 
 		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
 
-		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
-		{
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
 			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 			udelay(70);
 			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
@@ -681,7 +660,7 @@ static int amiga_set_clock_mmss (unsigne
 	return 0;
 }
 
-static unsigned int amiga_get_ss( void )
+static unsigned int amiga_get_ss(void)
 {
 	unsigned int s;
 
@@ -695,71 +674,72 @@ static unsigned int amiga_get_ss( void )
 	return s;
 }
 
-static NORET_TYPE void amiga_reset( void )
+static NORET_TYPE void amiga_reset(void)
     ATTRIB_NORET;
 
-static void amiga_reset (void)
+static void amiga_reset(void)
 {
-  unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
-  unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
-
-  local_irq_disable();
-  if (CPU_IS_040_OR_060)
-    /* Setup transparent translation registers for mapping
-     * of 16 MB kernel segment before disabling translation
-     */
-    __asm__ __volatile__
-      ("movel    %0,%/d0\n\t"
-       "andl     #0xff000000,%/d0\n\t"
-       "orw      #0xe020,%/d0\n\t"   /* map 16 MB, enable, cacheable */
-       ".chip    68040\n\t"
-       "movec    %%d0,%%itt0\n\t"
-       "movec    %%d0,%%dtt0\n\t"
-       ".chip    68k\n\t"
-       "jmp      %0@\n\t"
-       : /* no outputs */
-       : "a" (jmp_addr040));
-  else
-    /* for 680[23]0, just disable translation and jump to the physical
-     * address of the label
-     */
-    __asm__ __volatile__
-      ("pmove  %/tc,%@\n\t"
-       "bclr   #7,%@\n\t"
-       "pmove  %@,%/tc\n\t"
-       "jmp    %0@\n\t"
-       : /* no outputs */
-       : "a" (jmp_addr));
- jmp_addr_label040:
-  /* disable translation on '040 now */
-  __asm__ __volatile__
-    ("moveq #0,%/d0\n\t"
-     ".chip 68040\n\t"
-     "movec %%d0,%%tc\n\t"	/* disable MMU */
-     ".chip 68k\n\t"
-     : /* no outputs */
-     : /* no inputs */
-     : "d0");
-
- jmp_addr_label:
-  /* pickup reset address from AmigaOS ROM, reset devices and jump
-   * to reset address
-   */
-  __asm__ __volatile__
-    ("movew #0x2700,%/sr\n\t"
-     "leal  0x01000000,%/a0\n\t"
-     "subl  %/a0@(-0x14),%/a0\n\t"
-     "movel %/a0@(4),%/a0\n\t"
-     "subql #2,%/a0\n\t"
-     "bra   1f\n\t"
-     /* align on a longword boundary */
-     __ALIGN_STR "\n"
-     "1:\n\t"
-     "reset\n\t"
-     "jmp   %/a0@" : /* Just that gcc scans it for % escapes */ );
-
-  for (;;);
-
+	unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+	unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
+
+	local_irq_disable();
+	if (CPU_IS_040_OR_060)
+		/* Setup transparent translation registers for mapping
+		 * of 16 MB kernel segment before disabling translation
+		 */
+		asm volatile ("\n"
+			"	move.l	%0,%%d0\n"
+			"	and.l	#0xff000000,%%d0\n"
+			"	or.w	#0xe020,%%d0\n"   /* map 16 MB, enable, cacheable */
+			"	.chip	68040\n"
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%dtt0\n"
+			"	.chip	68k\n"
+			"	jmp	%0@\n"
+			: /* no outputs */
+			: "a" (jmp_addr040)
+			: "d0");
+	else
+		/* for 680[23]0, just disable translation and jump to the physical
+		 * address of the label
+		 */
+		asm volatile ("\n"
+			"	pmove	%%tc,%@\n"
+			"	bclr	#7,%@\n"
+			"	pmove	%@,%%tc\n"
+			"	jmp	%0@\n"
+			: /* no outputs */
+			: "a" (jmp_addr));
+jmp_addr_label040:
+	/* disable translation on '040 now */
+	asm volatile ("\n"
+		"	moveq	#0,%%d0\n"
+		"	.chip	68040\n"
+		"	movec	%%d0,%%tc\n"	/* disable MMU */
+		"	.chip	68k\n"
+		: /* no outputs */
+		: /* no inputs */
+		: "d0");
+
+	jmp_addr_label:
+	/* pickup reset address from AmigaOS ROM, reset devices and jump
+	 * to reset address
+	 */
+	asm volatile ("\n"
+		"	move.w	#0x2700,%sr\n"
+		"	lea	0x01000000,%a0\n"
+		"	sub.l	%a0@(-0x14),%a0\n"
+		"	move.l	%a0@(4),%a0\n"
+		"	subq.l	#2,%a0\n"
+		"	jra	1f\n"
+		/* align on a longword boundary */
+		"	" __ALIGN_STR "\n"
+		"1:\n"
+		"	reset\n"
+		"	jmp   %a0@");
+
+	for (;;)
+		;
 }
 
 
@@ -773,11 +753,11 @@ #define SAVEKMSG_MAGIC1		0x53415645	/* '
 #define SAVEKMSG_MAGIC2		0x4B4D5347	/* 'KMSG' */
 
 struct savekmsg {
-    unsigned long magic1;		/* SAVEKMSG_MAGIC1 */
-    unsigned long magic2;		/* SAVEKMSG_MAGIC2 */
-    unsigned long magicptr;		/* address of magic1 */
-    unsigned long size;
-    char data[0];
+	unsigned long magic1;		/* SAVEKMSG_MAGIC1 */
+	unsigned long magic2;		/* SAVEKMSG_MAGIC2 */
+	unsigned long magicptr;		/* address of magic1 */
+	unsigned long size;
+	char data[0];
 };
 
 static struct savekmsg *savekmsg;
@@ -785,113 +765,132 @@ static struct savekmsg *savekmsg;
 static void amiga_mem_console_write(struct console *co, const char *s,
 				    unsigned int count)
 {
-    if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
-        memcpy(savekmsg->data+savekmsg->size, s, count);
-        savekmsg->size += count;
-    }
+	if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
+		memcpy(savekmsg->data + savekmsg->size, s, count);
+		savekmsg->size += count;
+	}
 }
 
-static void amiga_savekmsg_init(void)
+static int __init amiga_savekmsg_setup(char *arg)
 {
-    static struct resource debug_res = { .name = "Debug" };
+	static struct resource debug_res = { .name = "Debug" };
+
+	if (!MACH_IS_AMIGA || strcmp(arg, "mem"))
+		goto done;
+
+	if (!AMIGAHW_PRESENT(CHIP_RAM)) {
+		printk("Warning: no chipram present for debugging\n");
+		goto done;
+	}
 
-    savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
-    savekmsg->magic1 = SAVEKMSG_MAGIC1;
-    savekmsg->magic2 = SAVEKMSG_MAGIC2;
-    savekmsg->magicptr = ZTWO_PADDR(savekmsg);
-    savekmsg->size = 0;
+	savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
+	savekmsg->magic1 = SAVEKMSG_MAGIC1;
+	savekmsg->magic2 = SAVEKMSG_MAGIC2;
+	savekmsg->magicptr = ZTWO_PADDR(savekmsg);
+	savekmsg->size = 0;
+
+	amiga_console_driver.write = amiga_mem_console_write;
+	register_console(&amiga_console_driver);
+
+done:
+	return 0;
 }
 
+early_param("debug", amiga_savekmsg_setup);
+
 static void amiga_serial_putc(char c)
 {
-    amiga_custom.serdat = (unsigned char)c | 0x100;
-    while (!(amiga_custom.serdatr & 0x2000))
-	;
+	amiga_custom.serdat = (unsigned char)c | 0x100;
+	while (!(amiga_custom.serdatr & 0x2000))
+		;
 }
 
 void amiga_serial_console_write(struct console *co, const char *s,
-				       unsigned int count)
+				unsigned int count)
 {
-    while (count--) {
-	if (*s == '\n')
-	    amiga_serial_putc('\r');
-	amiga_serial_putc(*s++);
-    }
+	while (count--) {
+		if (*s == '\n')
+			amiga_serial_putc('\r');
+		amiga_serial_putc(*s++);
+	}
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
 void amiga_serial_puts(const char *s)
 {
-    amiga_serial_console_write(NULL, s, strlen(s));
+	amiga_serial_console_write(NULL, s, strlen(s));
 }
 
 int amiga_serial_console_wait_key(struct console *co)
 {
-    int ch;
-
-    while (!(amiga_custom.intreqr & IF_RBF))
-	barrier();
-    ch = amiga_custom.serdatr & 0xff;
-    /* clear the interrupt, so that another character can be read */
-    amiga_custom.intreq = IF_RBF;
-    return ch;
+	int ch;
+
+	while (!(amiga_custom.intreqr & IF_RBF))
+		barrier();
+	ch = amiga_custom.serdatr & 0xff;
+	/* clear the interrupt, so that another character can be read */
+	amiga_custom.intreq = IF_RBF;
+	return ch;
 }
 
 void amiga_serial_gets(struct console *co, char *s, int len)
 {
-    int ch, cnt = 0;
-
-    while (1) {
-	ch = amiga_serial_console_wait_key(co);
-
-	/* Check for backspace. */
-	if (ch == 8 || ch == 127) {
-	    if (cnt == 0) {
-		amiga_serial_putc('\007');
-		continue;
-	    }
-	    cnt--;
-	    amiga_serial_puts("\010 \010");
-	    continue;
-	}
+	int ch, cnt = 0;
+
+	while (1) {
+		ch = amiga_serial_console_wait_key(co);
+
+		/* Check for backspace. */
+		if (ch == 8 || ch == 127) {
+			if (cnt == 0) {
+				amiga_serial_putc('\007');
+				continue;
+			}
+			cnt--;
+			amiga_serial_puts("\010 \010");
+			continue;
+		}
 
-	/* Check for enter. */
-	if (ch == 10 || ch == 13)
-	    break;
+		/* Check for enter. */
+		if (ch == 10 || ch == 13)
+			break;
 
-	/* See if line is too long. */
-	if (cnt >= len + 1) {
-	    amiga_serial_putc(7);
-	    cnt--;
-	    continue;
-	}
+		/* See if line is too long. */
+		if (cnt >= len + 1) {
+			amiga_serial_putc(7);
+			cnt--;
+			continue;
+		}
 
-	/* Store and echo character. */
-	s[cnt++] = ch;
-	amiga_serial_putc(ch);
-    }
-    /* Print enter. */
-    amiga_serial_puts("\r\n");
-    s[cnt] = 0;
+		/* Store and echo character. */
+		s[cnt++] = ch;
+		amiga_serial_putc(ch);
+	}
+	/* Print enter. */
+	amiga_serial_puts("\r\n");
+	s[cnt] = 0;
 }
 #endif
 
-static void __init amiga_debug_init(void)
+static int __init amiga_debug_setup(char *arg)
 {
-	if (!strcmp( m68k_debug_device, "ser" )) {
+	if (MACH_IS_AMIGA && !strcmp(arg, "ser")) {
 		/* no initialization required (?) */
 		amiga_console_driver.write = amiga_serial_console_write;
 		register_console(&amiga_console_driver);
 	}
+	return 0;
 }
 
+early_param("debug", amiga_debug_setup);
+
 #ifdef CONFIG_HEARTBEAT
 static void amiga_heartbeat(int on)
 {
-    if (on)
-	ciaa.pra &= ~2;
-    else
-	ciaa.pra |= 2;
+	if (on)
+		ciaa.pra &= ~2;
+	else
+		ciaa.pra |= 2;
 }
 #endif
 
@@ -901,81 +900,81 @@ #endif
 
 static void amiga_get_model(char *model)
 {
-    strcpy(model, amiga_model_name);
+	strcpy(model, amiga_model_name);
 }
 
 
 static int amiga_get_hardware_list(char *buffer)
 {
-    int len = 0;
-
-    if (AMIGAHW_PRESENT(CHIP_RAM))
-	len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
-    len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
-		   amiga_psfreq, amiga_eclock);
-    if (AMIGAHW_PRESENT(AMI_VIDEO)) {
-	char *type;
-	switch(amiga_chipset) {
-	    case CS_OCS:
-		type = "OCS";
-		break;
-	    case CS_ECS:
-		type = "ECS";
-		break;
-	    case CS_AGA:
-		type = "AGA";
-		break;
-	    default:
-		type = "Old or Unknown";
-		break;
+	int len = 0;
+
+	if (AMIGAHW_PRESENT(CHIP_RAM))
+		len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
+	len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
+			amiga_psfreq, amiga_eclock);
+	if (AMIGAHW_PRESENT(AMI_VIDEO)) {
+		char *type;
+		switch (amiga_chipset) {
+		case CS_OCS:
+			type = "OCS";
+			break;
+		case CS_ECS:
+			type = "ECS";
+			break;
+		case CS_AGA:
+			type = "AGA";
+			break;
+		default:
+			type = "Old or Unknown";
+			break;
+		}
+		len += sprintf(buffer+len, "Graphics:\t%s\n", type);
 	}
-	len += sprintf(buffer+len, "Graphics:\t%s\n", type);
-    }
 
 #define AMIGAHW_ANNOUNCE(name, str)			\
-    if (AMIGAHW_PRESENT(name))				\
-	len += sprintf (buffer+len, "\t%s\n", str)
-
-    len += sprintf (buffer + len, "Detected hardware:\n");
-
-    AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
-    AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
-    AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
-    AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
-    AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
-    AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
-    AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
-    AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
-    AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
-    AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
-    AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
-    AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
-    AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
-    AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
-    AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
-    AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
-    AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
-    AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
-    AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
-    AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
-    AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
-    AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
-    AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
-    AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
-    AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
-    AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
-    AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
-    AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
-    AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
+	if (AMIGAHW_PRESENT(name))			\
+		len += sprintf (buffer+len, "\t%s\n", str)
+
+	len += sprintf (buffer + len, "Detected hardware:\n");
+
+	AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
+	AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
+	AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
+	AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
+	AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
+	AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
+	AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
+	AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
+	AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
+	AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
+	AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
+	AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
+	AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
+	AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
+	AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
+	AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
+	AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
+	AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
+	AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
+	AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
+	AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
+	AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
+	AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
+	AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
+	AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
+	AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
+	AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
+	AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
+	AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
 #ifdef CONFIG_ZORRO
-    if (AMIGAHW_PRESENT(ZORRO))
-	len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
-				   "Device%s\n",
-		       AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
-		       zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+	if (AMIGAHW_PRESENT(ZORRO))
+		len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
+				"Device%s\n",
+				AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
+				zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
 #endif /* CONFIG_ZORRO */
 
 #undef AMIGAHW_ANNOUNCE
 
-    return(len);
+	return len;
 }
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 4274af1..13bd41b 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -31,7 +31,7 @@ void apollo_irq_shutdown(unsigned int ir
 
 static struct irq_controller apollo_irq_controller = {
 	.name           = "apollo",
-	.lock           = SPIN_LOCK_UNLOCKED,
+	.lock           = __SPIN_LOCK_UNLOCKED(apollo_irq_controller.lock),
 	.startup        = apollo_irq_startup,
 	.shutdown       = apollo_irq_shutdown,
 };
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 8cb6236..2cb8619 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -8,3 +8,4 @@ obj-y		:= config.o time.o debug.o ataint
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_HADES)	+= hades-pci.o
 endif
+obj-$(CONFIG_ATARI_KBD_CORE)	+= atakeyb.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 7f81264..b85ca22 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -339,7 +339,7 @@ static void atari_shutdown_irq(unsigned 
 
 static struct irq_controller atari_irq_controller = {
 	.name		= "atari",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock),
 	.startup	= atari_startup_irq,
 	.shutdown	= atari_shutdown_irq,
 	.enable		= atari_enable_irq,
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
new file mode 100644
index 0000000..1c29603
--- /dev/null
+++ b/arch/m68k/atari/atakeyb.c
@@ -0,0 +1,730 @@
+/*
+ * linux/atari/atakeyb.c
+ *
+ * Atari Keyboard driver for 680x0 Linux
+ *
+ * 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.
+ */
+
+/*
+ * Atari support by Robert de Vries
+ * enhanced by Bjoern Brauel and Roman Hodek
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/keyboard.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kd.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/kbd_kern.h>
+
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atari_joystick.h>
+#include <asm/irq.h>
+
+static void atakeyb_rep(unsigned long ignore);
+extern unsigned int keymap_count;
+
+/* Hook for MIDI serial driver */
+void (*atari_MIDI_interrupt_hook) (void);
+/* Hook for mouse driver */
+void (*atari_mouse_interrupt_hook) (char *);
+/* Hook for keyboard inputdev  driver */
+void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
+/* Hook for mouse inputdev  driver */
+void (*atari_input_mouse_interrupt_hook) (char *);
+
+/* variables for IKBD self test: */
+
+/* state: 0: off; >0: in progress; >1: 0xf1 received */
+static volatile int ikbd_self_test;
+/* timestamp when last received a char */
+static volatile unsigned long self_test_last_rcv;
+/* bitmap of keys reported as broken */
+static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
+
+#define BREAK_MASK	(0x80)
+
+/*
+ * ++roman: The following changes were applied manually:
+ *
+ *  - The Alt (= Meta) key works in combination with Shift and
+ *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
+ *    Meta-Ctrl-A (0x81) ...
+ *
+ *  - The parentheses on the keypad send '(' and ')' with all
+ *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
+ *    application keys (i.e. sending Esc O c).
+ *
+ *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
+ *    codes "\E[M" and "\E[P". (This is better than the old mapping to
+ *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
+ *    way, applications that allow their own keyboard mappings
+ *    (e.g. tcsh, X Windows) can be configured to use them in the way
+ *    the label suggests (providing help or undoing).
+ *
+ *  - Console switching is done with Alt+Fx (consoles 1..10) and
+ *    Shift+Alt+Fx (consoles 11..20).
+ *
+ *  - The misc. special function implemented in the kernel are mapped
+ *    to the following key combinations:
+ *
+ *      ClrHome          -> Home/Find
+ *      Shift + ClrHome  -> End/Select
+ *      Shift + Up       -> Page Up
+ *      Shift + Down     -> Page Down
+ *      Alt + Help       -> show system status
+ *      Shift + Help     -> show memory info
+ *      Ctrl + Help      -> show registers
+ *      Ctrl + Alt + Del -> Reboot
+ *      Alt + Undo       -> switch to last console
+ *      Shift + Undo     -> send interrupt
+ *      Alt + Insert     -> stop/start output (same as ^S/^Q)
+ *      Alt + Up         -> Scroll back console (if implemented)
+ *      Alt + Down       -> Scroll forward console (if implemented)
+ *      Alt + CapsLock   -> NumLock
+ *
+ * ++Andreas:
+ *
+ *  - Help mapped to K_HELP
+ *  - Undo mapped to K_UNDO (= K_F246)
+ *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
+ */
+
+static u_short ataplain_map[NR_KEYS] __initdata = {
+	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+	0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+	0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
+	0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+typedef enum kb_state_t {
+	KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
+} KB_STATE_T;
+
+#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
+
+typedef struct keyboard_state {
+	unsigned char buf[6];
+	int len;
+	KB_STATE_T state;
+} KEYBOARD_STATE;
+
+KEYBOARD_STATE kb_state;
+
+#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
+#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
+
+/* These could be settable by some ioctl() in future... */
+static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
+static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
+
+static unsigned char rep_scancode;
+static struct timer_list atakeyb_rep_timer = {
+	.function = atakeyb_rep,
+};
+
+static void atakeyb_rep(unsigned long ignore)
+{
+	/* Disable keyboard for the time we call handle_scancode(), else a race
+	 * in the keyboard tty queue may happen */
+	atari_disable_irq(IRQ_MFP_ACIA);
+	del_timer(&atakeyb_rep_timer);
+
+	/* A keyboard int may have come in before we disabled the irq, so
+	 * double-check whether rep_scancode is still != 0 */
+	if (rep_scancode) {
+		init_timer(&atakeyb_rep_timer);
+		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
+		add_timer(&atakeyb_rep_timer);
+
+		//handle_scancode(rep_scancode, 1);
+		if (atari_input_keyboard_interrupt_hook)
+			atari_input_keyboard_interrupt_hook(rep_scancode, 1);
+	}
+
+	atari_enable_irq(IRQ_MFP_ACIA);
+}
+
+
+/* ++roman: If a keyboard overrun happened, we can't tell in general how much
+ * bytes have been lost and in which state of the packet structure we are now.
+ * This usually causes keyboards bytes to be interpreted as mouse movements
+ * and vice versa, which is very annoying. It seems better to throw away some
+ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
+ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
+ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
+ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
+ * speeds up the resynchronization of the event structure, even if maybe a
+ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
+ * it's really hard to decide whether they're mouse or keyboard bytes. Since
+ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
+ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
+ * lost, which isn't too bad. Loosing a break code would be disastrous,
+ * because then the keyboard repeat strikes...
+ */
+
+static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
+{
+	u_char acia_stat;
+	int scancode;
+	int break_flag;
+
+repeat:
+	if (acia.mid_ctrl & ACIA_IRQ)
+		if (atari_MIDI_interrupt_hook)
+			atari_MIDI_interrupt_hook();
+	acia_stat = acia.key_ctrl;
+	/* check out if the interrupt came from this ACIA */
+	if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
+		return IRQ_HANDLED;
+
+	if (acia_stat & ACIA_OVRN) {
+		/* a very fast typist or a slow system, give a warning */
+		/* ...happens often if interrupts were disabled for too long */
+		printk(KERN_DEBUG "Keyboard overrun\n");
+		scancode = acia.key_data;
+		/* Turn off autorepeating in case a break code has been lost */
+		del_timer(&atakeyb_rep_timer);
+		rep_scancode = 0;
+		if (ikbd_self_test)
+			/* During self test, don't do resyncing, just process the code */
+			goto interpret_scancode;
+		else if (IS_SYNC_CODE(scancode)) {
+			/* This code seem already to be the start of a new packet or a
+			 * single scancode */
+			kb_state.state = KEYBOARD;
+			goto interpret_scancode;
+		} else {
+			/* Go to RESYNC state and skip this byte */
+			kb_state.state = RESYNC;
+			kb_state.len = 1;	/* skip max. 1 another byte */
+			goto repeat;
+		}
+	}
+
+	if (acia_stat & ACIA_RDRF) {
+		/* received a character */
+		scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
+		tasklet_schedule(&keyboard_tasklet);
+	interpret_scancode:
+		switch (kb_state.state) {
+		case KEYBOARD:
+			switch (scancode) {
+			case 0xF7:
+				kb_state.state = AMOUSE;
+				kb_state.len = 0;
+				break;
+
+			case 0xF8:
+			case 0xF9:
+			case 0xFA:
+			case 0xFB:
+				kb_state.state = RMOUSE;
+				kb_state.len = 1;
+				kb_state.buf[0] = scancode;
+				break;
+
+			case 0xFC:
+				kb_state.state = CLOCK;
+				kb_state.len = 0;
+				break;
+
+			case 0xFE:
+			case 0xFF:
+				kb_state.state = JOYSTICK;
+				kb_state.len = 1;
+				kb_state.buf[0] = scancode;
+				break;
+
+			case 0xF1:
+				/* during self-test, note that 0xf1 received */
+				if (ikbd_self_test) {
+					++ikbd_self_test;
+					self_test_last_rcv = jiffies;
+					break;
+				}
+				/* FALL THROUGH */
+
+			default:
+				break_flag = scancode & BREAK_MASK;
+				scancode &= ~BREAK_MASK;
+				if (ikbd_self_test) {
+					/* Scancodes sent during the self-test stand for broken
+					 * keys (keys being down). The code *should* be a break
+					 * code, but nevertheless some AT keyboard interfaces send
+					 * make codes instead. Therefore, simply ignore
+					 * break_flag...
+					 */
+					int keyval = plain_map[scancode], keytyp;
+
+					set_bit(scancode, broken_keys);
+					self_test_last_rcv = jiffies;
+					keyval = plain_map[scancode];
+					keytyp = KTYP(keyval) - 0xf0;
+					keyval = KVAL(keyval);
+
+					printk(KERN_WARNING "Key with scancode %d ", scancode);
+					if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
+						if (keyval < ' ')
+							printk("('^%c') ", keyval + '@');
+						else
+							printk("('%c') ", keyval);
+					}
+					printk("is broken -- will be ignored.\n");
+					break;
+				} else if (test_bit(scancode, broken_keys))
+					break;
+
+#if 0	// FIXME; hangs at boot
+				if (break_flag) {
+					del_timer(&atakeyb_rep_timer);
+					rep_scancode = 0;
+				} else {
+					del_timer(&atakeyb_rep_timer);
+					rep_scancode = scancode;
+					atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
+					add_timer(&atakeyb_rep_timer);
+				}
+#endif
+
+				// handle_scancode(scancode, !break_flag);
+				if (atari_input_keyboard_interrupt_hook)
+					atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
+				break;
+			}
+			break;
+
+		case AMOUSE:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 5) {
+				kb_state.state = KEYBOARD;
+				/* not yet used */
+				/* wake up someone waiting for this */
+			}
+			break;
+
+		case RMOUSE:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 3) {
+				kb_state.state = KEYBOARD;
+				if (atari_mouse_interrupt_hook)
+					atari_mouse_interrupt_hook(kb_state.buf);
+			}
+			break;
+
+		case JOYSTICK:
+			kb_state.buf[1] = scancode;
+			kb_state.state = KEYBOARD;
+#ifdef FIXED_ATARI_JOYSTICK
+			atari_joystick_interrupt(kb_state.buf);
+#endif
+			break;
+
+		case CLOCK:
+			kb_state.buf[kb_state.len++] = scancode;
+			if (kb_state.len == 6) {
+				kb_state.state = KEYBOARD;
+				/* wake up someone waiting for this.
+				   But will this ever be used, as Linux keeps its own time.
+				   Perhaps for synchronization purposes? */
+				/* wake_up_interruptible(&clock_wait); */
+			}
+			break;
+
+		case RESYNC:
+			if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
+				kb_state.state = KEYBOARD;
+				goto interpret_scancode;
+			}
+			kb_state.len--;
+			break;
+		}
+	}
+
+#if 0
+	if (acia_stat & ACIA_CTS)
+		/* cannot happen */;
+#endif
+
+	if (acia_stat & (ACIA_FE | ACIA_PE)) {
+		printk("Error in keyboard communication\n");
+	}
+
+	/* handle_scancode() can take a lot of time, so check again if
+	 * some character arrived
+	 */
+	goto repeat;
+}
+
+/*
+ * I write to the keyboard without using interrupts, I poll instead.
+ * This takes for the maximum length string allowed (7) at 7812.5 baud
+ * 8 data 1 start 1 stop bit: 9.0 ms
+ * If this takes too long for normal operation, interrupt driven writing
+ * is the solution. (I made a feeble attempt in that direction but I
+ * kept it simple for now.)
+ */
+void ikbd_write(const char *str, int len)
+{
+	u_char acia_stat;
+
+	if ((len < 1) || (len > 7))
+		panic("ikbd: maximum string length exceeded");
+	while (len) {
+		acia_stat = acia.key_ctrl;
+		if (acia_stat & ACIA_TDRE) {
+			acia.key_data = *str++;
+			len--;
+		}
+	}
+}
+
+/* Reset (without touching the clock) */
+void ikbd_reset(void)
+{
+	static const char cmd[2] = { 0x80, 0x01 };
+
+	ikbd_write(cmd, 2);
+
+	/*
+	 * if all's well code 0xF1 is returned, else the break codes of
+	 * all keys making contact
+	 */
+}
+
+/* Set mouse button action */
+void ikbd_mouse_button_action(int mode)
+{
+	char cmd[2] = { 0x07, mode };
+
+	ikbd_write(cmd, 2);
+}
+
+/* Set relative mouse position reporting */
+void ikbd_mouse_rel_pos(void)
+{
+	static const char cmd[1] = { 0x08 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set absolute mouse position reporting */
+void ikbd_mouse_abs_pos(int xmax, int ymax)
+{
+	char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
+
+	ikbd_write(cmd, 5);
+}
+
+/* Set mouse keycode mode */
+void ikbd_mouse_kbd_mode(int dx, int dy)
+{
+	char cmd[3] = { 0x0A, dx, dy };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Set mouse threshold */
+void ikbd_mouse_thresh(int x, int y)
+{
+	char cmd[3] = { 0x0B, x, y };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Set mouse scale */
+void ikbd_mouse_scale(int x, int y)
+{
+	char cmd[3] = { 0x0C, x, y };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Interrogate mouse position */
+void ikbd_mouse_pos_get(int *x, int *y)
+{
+	static const char cmd[1] = { 0x0D };
+
+	ikbd_write(cmd, 1);
+
+	/* wait for returning bytes */
+}
+
+/* Load mouse position */
+void ikbd_mouse_pos_set(int x, int y)
+{
+	char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
+
+	ikbd_write(cmd, 6);
+}
+
+/* Set Y=0 at bottom */
+void ikbd_mouse_y0_bot(void)
+{
+	static const char cmd[1] = { 0x0F };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set Y=0 at top */
+void ikbd_mouse_y0_top(void)
+{
+	static const char cmd[1] = { 0x10 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Resume */
+void ikbd_resume(void)
+{
+	static const char cmd[1] = { 0x11 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Disable mouse */
+void ikbd_mouse_disable(void)
+{
+	static const char cmd[1] = { 0x12 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Pause output */
+void ikbd_pause(void)
+{
+	static const char cmd[1] = { 0x13 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set joystick event reporting */
+void ikbd_joystick_event_on(void)
+{
+	static const char cmd[1] = { 0x14 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Set joystick interrogation mode */
+void ikbd_joystick_event_off(void)
+{
+	static const char cmd[1] = { 0x15 };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Joystick interrogation */
+void ikbd_joystick_get_state(void)
+{
+	static const char cmd[1] = { 0x16 };
+
+	ikbd_write(cmd, 1);
+}
+
+#if 0
+/* This disables all other ikbd activities !!!! */
+/* Set joystick monitoring */
+void ikbd_joystick_monitor(int rate)
+{
+	static const char cmd[2] = { 0x17, rate };
+
+	ikbd_write(cmd, 2);
+
+	kb_state.state = JOYSTICK_MONITOR;
+}
+#endif
+
+/* some joystick routines not in yet (0x18-0x19) */
+
+/* Disable joysticks */
+void ikbd_joystick_disable(void)
+{
+	static const char cmd[1] = { 0x1A };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Time-of-day clock set */
+void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
+{
+	char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
+
+	ikbd_write(cmd, 7);
+}
+
+/* Interrogate time-of-day clock */
+void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
+{
+	static const char cmd[1] = { 0x1C };
+
+	ikbd_write(cmd, 1);
+}
+
+/* Memory load */
+void ikbd_mem_write(int address, int size, char *data)
+{
+	panic("Attempt to write data into keyboard memory");
+}
+
+/* Memory read */
+void ikbd_mem_read(int address, char data[6])
+{
+	char cmd[3] = { 0x21, address>>8, address&0xFF };
+
+	ikbd_write(cmd, 3);
+
+	/* receive data and put it in data */
+}
+
+/* Controller execute */
+void ikbd_exec(int address)
+{
+	char cmd[3] = { 0x22, address>>8, address&0xFF };
+
+	ikbd_write(cmd, 3);
+}
+
+/* Status inquiries (0x87-0x9A) not yet implemented */
+
+/* Set the state of the caps lock led. */
+void atari_kbd_leds(unsigned int leds)
+{
+	char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
+
+	ikbd_write(cmd, 6);
+}
+
+/*
+ * The original code sometimes left the interrupt line of
+ * the ACIAs low forever. I hope, it is fixed now.
+ *
+ * Martin Rogge, 20 Aug 1995
+ */
+
+static int atari_keyb_done = 0;
+
+int __init atari_keyb_init(void)
+{
+	if (atari_keyb_done)
+		return 0;
+
+	/* setup key map */
+	memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+
+	kb_state.state = KEYBOARD;
+	kb_state.len = 0;
+
+	request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW,
+		    "keyboard/mouse/MIDI", atari_keyboard_interrupt);
+
+	atari_turnoff_irq(IRQ_MFP_ACIA);
+	do {
+		/* reset IKBD ACIA */
+		acia.key_ctrl = ACIA_RESET |
+				(atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
+		(void)acia.key_ctrl;
+		(void)acia.key_data;
+
+		/* reset MIDI ACIA */
+		acia.mid_ctrl = ACIA_RESET |
+				(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
+		(void)acia.mid_ctrl;
+		(void)acia.mid_data;
+
+		/* divide 500kHz by 64 gives 7812.5 baud */
+		/* 8 data no parity 1 start 1 stop bit */
+		/* receive interrupt enabled */
+		/* RTS low (except if switch selected), transmit interrupt disabled */
+		acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
+				((atari_switches & ATARI_SWITCH_IKBD) ?
+				 ACIA_RHTID : ACIA_RLTID);
+
+		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
+				(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
+
+	/* make sure the interrupt line is up */
+	} while ((mfp.par_dt_reg & 0x10) == 0);
+
+	/* enable ACIA Interrupts */
+	mfp.active_edge &= ~0x10;
+	atari_turnon_irq(IRQ_MFP_ACIA);
+
+	ikbd_self_test = 1;
+	ikbd_reset();
+	/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
+	 * self-test is finished */
+	self_test_last_rcv = jiffies;
+	while (time_before(jiffies, self_test_last_rcv + HZ/4))
+		barrier();
+	/* if not incremented: no 0xf1 received */
+	if (ikbd_self_test == 1)
+		printk(KERN_ERR "WARNING: keyboard self test failed!\n");
+	ikbd_self_test = 0;
+
+	ikbd_mouse_disable();
+	ikbd_joystick_disable();
+
+#ifdef FIXED_ATARI_JOYSTICK
+	atari_joystick_init();
+#endif
+
+	// flag init done
+	atari_keyb_done = 1;
+	return 0;
+}
+
+
+int atari_kbdrate(struct kbd_repeat *k)
+{
+	if (k->delay > 0) {
+		/* convert from msec to jiffies */
+		key_repeat_delay = (k->delay * HZ + 500) / 1000;
+		if (key_repeat_delay < 1)
+			key_repeat_delay = 1;
+	}
+	if (k->period > 0) {
+		key_repeat_rate = (k->period * HZ + 500) / 1000;
+		if (key_repeat_rate < 1)
+			key_repeat_rate = 1;
+	}
+
+	k->delay  = key_repeat_delay * 1000 / HZ;
+	k->period = key_repeat_rate  * 1000 / HZ;
+
+	return 0;
+}
+
+int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
+{
+#ifdef CONFIG_MAGIC_SYSRQ
+	/* ALT+HELP pressed? */
+	if ((keycode == 98) && ((shift_state & 0xff) == 8))
+		*keycodep = 0xff;
+	else
+#endif
+		*keycodep = keycode;
+	return 1;
+}
diff --git a/arch/m68k/atari/atasound.h b/arch/m68k/atari/atasound.h
deleted file mode 100644
index 1362762..0000000
--- a/arch/m68k/atari/atasound.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS	256	/* Number of supported devices */
-#define SND_DEV_CTL	0	/* Control port /dev/mixer */
-#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
-				   synthesizer and MIDI output) */
-#define SND_DEV_MIDIN	2	/* Raw midi access */
-#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS	6	/* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS	SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED	8000
-
-#define ON		1
-#define OFF		0
-
-#define MAX_AUDIO_DEV	5
-#define MAX_MIXER_DEV	2
-#define MAX_SYNTH_DEV	3
-#define MAX_MIDI_DEV	6
-#define MAX_TIMER_DEV	3
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index ca5cd43..e40e5dc 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -50,70 +50,25 @@ int atari_dont_touch_floppy_select;
 int atari_rtc_year_offset;
 
 /* local function prototypes */
-static void atari_reset( void );
+static void atari_reset(void);
 static void atari_get_model(char *model);
 static int atari_get_hardware_list(char *buffer);
 
 /* atari specific irq functions */
 extern void atari_init_IRQ (void);
-extern void atari_mksound( unsigned int count, unsigned int ticks );
+extern void atari_mksound(unsigned int count, unsigned int ticks);
 #ifdef CONFIG_HEARTBEAT
-static void atari_heartbeat( int on );
+static void atari_heartbeat(int on);
 #endif
 
 /* atari specific timer functions (in time.c) */
-extern void atari_sched_init(irq_handler_t );
+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 *);
 extern int atari_mste_set_clock_mmss (unsigned long);
 extern int atari_tt_set_clock_mmss (unsigned long);
 
-/* atari specific debug functions (in debug.c) */
-extern void atari_debug_init(void);
-
-
-/* I've moved hwreg_present() and hwreg_present_bywrite() out into
- * mm/hwtest.c, to avoid having multiple copies of the same routine
- * in the kernel [I wanted them in hp300 and they were already used
- * in the nubus code. NB: I don't have an Atari so this might (just
- * conceivably) break something.
- * I've preserved the #if 0 version of hwreg_present_bywrite() here
- * for posterity.
- *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
- */
-
-#if 0
-static int __init
-hwreg_present_bywrite(volatile void *regp, unsigned char val)
-{
-    int		ret;
-    long	save_sp, save_vbr;
-    static long tmp_vectors[3] = { [2] = (long)&&after_test };
-
-    __asm__ __volatile__
-	(	"movec	%/vbr,%2\n\t"	/* save vbr value            */
-                "movec	%4,%/vbr\n\t"	/* set up temporary vectors  */
-		"movel	%/sp,%1\n\t"	/* save sp                   */
-		"moveq	#0,%0\n\t"	/* assume not present        */
-		"moveb	%5,%3@\n\t"	/* write the hardware reg    */
-		"cmpb	%3@,%5\n\t"	/* compare it                */
-		"seq	%0"		/* comes here only if reg    */
-                                        /* is present                */
-		: "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
-		: "a" (regp), "r" (tmp_vectors), "d" (val)
-                );
-  after_test:
-    __asm__ __volatile__
-      (	"movel	%0,%/sp\n\t"		/* restore sp                */
-        "movec	%1,%/vbr"			/* restore vbr               */
-        : : "r" (save_sp), "r" (save_vbr) : "sp"
-	);
-
-    return( ret );
-}
-#endif
-
 
 /* ++roman: This is a more elaborate test for an SCC chip, since the plain
  * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
@@ -123,26 +78,34 @@ #endif
  * should be readable without trouble (from channel A!).
  */
 
-static int __init scc_test( volatile char *ctla )
+static int __init scc_test(volatile char *ctla)
 {
-	if (!hwreg_present( ctla ))
-		return( 0 );
+	if (!hwreg_present(ctla))
+		return 0;
 	MFPDELAY();
 
-	*ctla = 2; MFPDELAY();
-	*ctla = 0x40; MFPDELAY();
+	*ctla = 2;
+	MFPDELAY();
+	*ctla = 0x40;
+	MFPDELAY();
 
-	*ctla = 2; MFPDELAY();
-	if (*ctla != 0x40) return( 0 );
+	*ctla = 2;
+	MFPDELAY();
+	if (*ctla != 0x40)
+		return 0;
 	MFPDELAY();
 
-	*ctla = 2; MFPDELAY();
-	*ctla = 0x60; MFPDELAY();
+	*ctla = 2;
+	MFPDELAY();
+	*ctla = 0x60;
+	MFPDELAY();
 
-	*ctla = 2; MFPDELAY();
-	if (*ctla != 0x60) return( 0 );
+	*ctla = 2;
+	MFPDELAY();
+	if (*ctla != 0x60)
+		return 0;
 
-	return( 1 );
+	return 1;
 }
 
 
@@ -152,61 +115,66 @@ static int __init scc_test( volatile cha
 
 int __init atari_parse_bootinfo(const struct bi_record *record)
 {
-    int unknown = 0;
-    const u_long *data = record->data;
+	int unknown = 0;
+	const u_long *data = record->data;
 
-    switch (record->tag) {
+	switch (record->tag) {
 	case BI_ATARI_MCH_COOKIE:
-	    atari_mch_cookie = *data;
-	    break;
+		atari_mch_cookie = *data;
+		break;
 	case BI_ATARI_MCH_TYPE:
-	    atari_mch_type = *data;
-	    break;
+		atari_mch_type = *data;
+		break;
 	default:
-	    unknown = 1;
-    }
-    return(unknown);
+		unknown = 1;
+		break;
+	}
+	return unknown;
 }
 
 
 /* Parse the Atari-specific switches= option. */
-void __init atari_switches_setup( const char *str, unsigned len )
+static int __init atari_switches_setup(char *str)
 {
-    char switches[len+1];
-    char *p;
-    int ovsc_shift;
-    char *args = switches;
-
-    /* copy string to local array, strsep works destructively... */
-    strlcpy( switches, str, sizeof(switches) );
-    atari_switches = 0;
-
-    /* parse the options */
-    while ((p = strsep(&args, ",")) != NULL) {
-	if (!*p) continue;
-	ovsc_shift = 0;
-	if (strncmp( p, "ov_", 3 ) == 0) {
-	    p += 3;
-	    ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
-	}
-
-	if (strcmp( p, "ikbd" ) == 0) {
-	    /* RTS line of IKBD ACIA */
-	    atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
-	}
-	else if (strcmp( p, "midi" ) == 0) {
-	    /* RTS line of MIDI ACIA */
-	    atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+	char switches[strlen(str) + 1];
+	char *p;
+	int ovsc_shift;
+	char *args = switches;
+
+	if (!MACH_IS_ATARI)
+		return 0;
+
+	/* copy string to local array, strsep works destructively... */
+	strcpy(switches, str);
+	atari_switches = 0;
+
+	/* parse the options */
+	while ((p = strsep(&args, ",")) != NULL) {
+		if (!*p)
+			continue;
+		ovsc_shift = 0;
+		if (strncmp(p, "ov_", 3) == 0) {
+			p += 3;
+			ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
+		}
+
+		if (strcmp(p, "ikbd") == 0) {
+			/* RTS line of IKBD ACIA */
+			atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
+		} else if (strcmp(p, "midi") == 0) {
+			/* RTS line of MIDI ACIA */
+			atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+		} else if (strcmp(p, "snd6") == 0) {
+			atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
+		} else if (strcmp(p, "snd7") == 0) {
+			atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+		}
 	}
-	else if (strcmp( p, "snd6" ) == 0) {
-	    atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
-	}
-	else if (strcmp( p, "snd7" ) == 0) {
-	    atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
-	}
-    }
+	return 0;
 }
 
+early_param("switches", atari_switches_setup);
+
 
     /*
      *  Setup the Atari configuration info
@@ -214,284 +182,281 @@ void __init atari_switches_setup( const 
 
 void __init config_atari(void)
 {
-    unsigned short tos_version;
+	unsigned short tos_version;
 
-    memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+	memset(&atari_hw_present, 0, sizeof(atari_hw_present));
 
-    atari_debug_init();
+	/* Change size of I/O space from 64KB to 4GB. */
+	ioport_resource.end  = 0xFFFFFFFF;
 
-    ioport_resource.end  = 0xFFFFFFFF;  /* Change size of I/O space from 64KB
-                                           to 4GB. */
-
-    mach_sched_init      = atari_sched_init;
-    mach_init_IRQ        = atari_init_IRQ;
-    mach_get_model	 = atari_get_model;
-    mach_get_hardware_list = atari_get_hardware_list;
-    mach_gettimeoffset   = atari_gettimeoffset;
-    mach_reset           = atari_reset;
-    mach_max_dma_address = 0xffffff;
+	mach_sched_init      = atari_sched_init;
+	mach_init_IRQ        = atari_init_IRQ;
+	mach_get_model	 = atari_get_model;
+	mach_get_hardware_list = atari_get_hardware_list;
+	mach_gettimeoffset   = atari_gettimeoffset;
+	mach_reset           = atari_reset;
+	mach_max_dma_address = 0xffffff;
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
-    mach_beep          = atari_mksound;
+	mach_beep          = atari_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
-    mach_heartbeat = atari_heartbeat;
+	mach_heartbeat = atari_heartbeat;
 #endif
 
-    /* Set switches as requested by the user */
-    if (atari_switches & ATARI_SWITCH_IKBD)
-	acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
-    if (atari_switches & ATARI_SWITCH_MIDI)
-	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
-    if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
-	sound_ym.rd_data_reg_sel = 14;
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel |
-			   ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
-			   ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
-    }
-
-    /* ++bjoern:
-     * Determine hardware present
-     */
+	/* Set switches as requested by the user */
+	if (atari_switches & ATARI_SWITCH_IKBD)
+		acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
+	if (atari_switches & ATARI_SWITCH_MIDI)
+		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+	if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+				   ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
+				   ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
+	}
 
-    printk( "Atari hardware found: " );
-    if (MACH_IS_MEDUSA || MACH_IS_HADES) {
-        /* There's no Atari video hardware on the Medusa, but all the
-         * addresses below generate a DTACK so no bus error occurs! */
-    }
-    else if (hwreg_present( f030_xreg )) {
-	ATARIHW_SET(VIDEL_SHIFTER);
-        printk( "VIDEL " );
-        /* This is a temporary hack: If there is Falcon video
-         * hardware, we assume that the ST-DMA serves SCSI instead of
-         * ACSI. In the future, there should be a better method for
-         * this...
-         */
-	ATARIHW_SET(ST_SCSI);
-        printk( "STDMA-SCSI " );
-    }
-    else if (hwreg_present( tt_palette )) {
-	ATARIHW_SET(TT_SHIFTER);
-        printk( "TT_SHIFTER " );
-    }
-    else if (hwreg_present( &shifter.bas_hi )) {
-        if (hwreg_present( &shifter.bas_lo ) &&
-	    (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
-	    ATARIHW_SET(EXTD_SHIFTER);
-            printk( "EXTD_SHIFTER " );
-        }
-        else {
-	    ATARIHW_SET(STND_SHIFTER);
-            printk( "STND_SHIFTER " );
-        }
-    }
-    if (hwreg_present( &mfp.par_dt_reg )) {
-	ATARIHW_SET(ST_MFP);
-        printk( "ST_MFP " );
-    }
-    if (hwreg_present( &tt_mfp.par_dt_reg )) {
-	ATARIHW_SET(TT_MFP);
-        printk( "TT_MFP " );
-    }
-    if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
-	ATARIHW_SET(SCSI_DMA);
-        printk( "TT_SCSI_DMA " );
-    }
-    if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) {
-	ATARIHW_SET(STND_DMA);
-        printk( "STND_DMA " );
-    }
-    if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable
-			   * on all Medusas, so the test below may fail */
-        (hwreg_present( &st_dma.dma_vhi ) &&
-         (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
-         st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
-         (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
-         st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
-	ATARIHW_SET(EXTD_DMA);
-        printk( "EXTD_DMA " );
-    }
-    if (hwreg_present( &tt_scsi.scsi_data )) {
-	ATARIHW_SET(TT_SCSI);
-        printk( "TT_SCSI " );
-    }
-    if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
-	ATARIHW_SET(YM_2149);
-        printk( "YM2149 " );
-    }
-    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-	hwreg_present( &tt_dmasnd.ctrl )) {
-	ATARIHW_SET(PCM_8BIT);
-        printk( "PCM " );
-    }
-    if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) {
-	ATARIHW_SET(CODEC);
-        printk( "CODEC " );
-    }
-    if (hwreg_present( &dsp56k_host_interface.icr )) {
-	ATARIHW_SET(DSP56K);
-        printk( "DSP56K " );
-    }
-    if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
+	/* ++bjoern:
+	 * Determine hardware present
+	 */
+
+	printk("Atari hardware found: ");
+	if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+		/* There's no Atari video hardware on the Medusa, but all the
+		 * addresses below generate a DTACK so no bus error occurs! */
+	} else if (hwreg_present(f030_xreg)) {
+		ATARIHW_SET(VIDEL_SHIFTER);
+		printk("VIDEL ");
+		/* This is a temporary hack: If there is Falcon video
+		 * hardware, we assume that the ST-DMA serves SCSI instead of
+		 * ACSI. In the future, there should be a better method for
+		 * this...
+		 */
+		ATARIHW_SET(ST_SCSI);
+		printk("STDMA-SCSI ");
+	} else if (hwreg_present(tt_palette)) {
+		ATARIHW_SET(TT_SHIFTER);
+		printk("TT_SHIFTER ");
+	} else if (hwreg_present(&shifter.bas_hi)) {
+		if (hwreg_present(&shifter.bas_lo) &&
+		    (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+			ATARIHW_SET(EXTD_SHIFTER);
+			printk("EXTD_SHIFTER ");
+		} else {
+			ATARIHW_SET(STND_SHIFTER);
+			printk("STND_SHIFTER ");
+		}
+	}
+	if (hwreg_present(&mfp.par_dt_reg)) {
+		ATARIHW_SET(ST_MFP);
+		printk("ST_MFP ");
+	}
+	if (hwreg_present(&tt_mfp.par_dt_reg)) {
+		ATARIHW_SET(TT_MFP);
+		printk("TT_MFP ");
+	}
+	if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) {
+		ATARIHW_SET(SCSI_DMA);
+		printk("TT_SCSI_DMA ");
+	}
+	if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
+		ATARIHW_SET(STND_DMA);
+		printk("STND_DMA ");
+	}
+	/*
+	 * The ST-DMA address registers aren't readable
+	 * on all Medusas, so the test below may fail
+	 */
+	if (MACH_IS_MEDUSA ||
+	    (hwreg_present(&st_dma.dma_vhi) &&
+	     (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
+	     st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
+	     (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
+	     st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
+		ATARIHW_SET(EXTD_DMA);
+		printk("EXTD_DMA ");
+	}
+	if (hwreg_present(&tt_scsi.scsi_data)) {
+		ATARIHW_SET(TT_SCSI);
+		printk("TT_SCSI ");
+	}
+	if (hwreg_present(&sound_ym.rd_data_reg_sel)) {
+		ATARIHW_SET(YM_2149);
+		printk("YM2149 ");
+	}
+	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+		hwreg_present(&tt_dmasnd.ctrl)) {
+		ATARIHW_SET(PCM_8BIT);
+		printk("PCM ");
+	}
+	if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
+		ATARIHW_SET(CODEC);
+		printk("CODEC ");
+	}
+	if (hwreg_present(&dsp56k_host_interface.icr)) {
+		ATARIHW_SET(DSP56K);
+		printk("DSP56K ");
+	}
+	if (hwreg_present(&tt_scc_dma.dma_ctrl) &&
 #if 0
-	/* This test sucks! Who knows some better? */
-	(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
-	(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
+	    /* This test sucks! Who knows some better? */
+	    (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
+	    (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
 #else
-	!MACH_IS_MEDUSA && !MACH_IS_HADES
+	    !MACH_IS_MEDUSA && !MACH_IS_HADES
 #endif
-	) {
-	ATARIHW_SET(SCC_DMA);
-        printk( "SCC_DMA " );
-    }
-    if (scc_test( &scc.cha_a_ctrl )) {
-	ATARIHW_SET(SCC);
-        printk( "SCC " );
-    }
-    if (scc_test( &st_escc.cha_b_ctrl )) {
-	ATARIHW_SET( ST_ESCC );
-	printk( "ST_ESCC " );
-    }
-    if (MACH_IS_HADES)
-    {
-        ATARIHW_SET( VME );
-        printk( "VME " );
-    }
-    else if (hwreg_present( &tt_scu.sys_mask )) {
-	ATARIHW_SET(SCU);
-	/* Assume a VME bus if there's a SCU */
-	ATARIHW_SET( VME );
-        printk( "VME SCU " );
-    }
-    if (hwreg_present( (void *)(0xffff9210) )) {
-	ATARIHW_SET(ANALOG_JOY);
-        printk( "ANALOG_JOY " );
-    }
-    if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) {
-	ATARIHW_SET(BLITTER);
-        printk( "BLITTER " );
-    }
-    if (hwreg_present((void *)0xfff00039)) {
-	ATARIHW_SET(IDE);
-        printk( "IDE " );
-    }
+	    ) {
+		ATARIHW_SET(SCC_DMA);
+		printk("SCC_DMA ");
+	}
+	if (scc_test(&scc.cha_a_ctrl)) {
+		ATARIHW_SET(SCC);
+		printk("SCC ");
+	}
+	if (scc_test(&st_escc.cha_b_ctrl)) {
+		ATARIHW_SET(ST_ESCC);
+		printk("ST_ESCC ");
+	}
+	if (MACH_IS_HADES) {
+		ATARIHW_SET(VME);
+		printk("VME ");
+	} else if (hwreg_present(&tt_scu.sys_mask)) {
+		ATARIHW_SET(SCU);
+		/* Assume a VME bus if there's a SCU */
+		ATARIHW_SET(VME);
+		printk("VME SCU ");
+	}
+	if (hwreg_present((void *)(0xffff9210))) {
+		ATARIHW_SET(ANALOG_JOY);
+		printk("ANALOG_JOY ");
+	}
+	if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
+		ATARIHW_SET(BLITTER);
+		printk("BLITTER ");
+	}
+	if (hwreg_present((void *)0xfff00039)) {
+		ATARIHW_SET(IDE);
+		printk("IDE ");
+	}
 #if 1 /* This maybe wrong */
-    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-	hwreg_present( &tt_microwire.data ) &&
-	hwreg_present( &tt_microwire.mask ) &&
-	(tt_microwire.mask = 0x7ff,
-	 udelay(1),
-	 tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
-	 udelay(1),
-	 tt_microwire.data != 0)) {
-	ATARIHW_SET(MICROWIRE);
-	while (tt_microwire.mask != 0x7ff) ;
-        printk( "MICROWIRE " );
-    }
+	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+	    hwreg_present(&tt_microwire.data) &&
+	    hwreg_present(&tt_microwire.mask) &&
+	    (tt_microwire.mask = 0x7ff,
+	     udelay(1),
+	     tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+	     udelay(1),
+	     tt_microwire.data != 0)) {
+		ATARIHW_SET(MICROWIRE);
+		while (tt_microwire.mask != 0x7ff)
+			;
+		printk("MICROWIRE ");
+	}
 #endif
-    if (hwreg_present( &tt_rtc.regsel )) {
-	ATARIHW_SET(TT_CLK);
-        printk( "TT_CLK " );
-        mach_hwclk = atari_tt_hwclk;
-        mach_set_clock_mmss = atari_tt_set_clock_mmss;
-    }
-    if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) {
-	ATARIHW_SET(MSTE_CLK);
-        printk( "MSTE_CLK ");
-        mach_hwclk = atari_mste_hwclk;
-        mach_set_clock_mmss = atari_mste_set_clock_mmss;
-    }
-    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
-	hwreg_present( &dma_wd.fdc_speed ) &&
-	hwreg_write( &dma_wd.fdc_speed, 0 )) {
-	    ATARIHW_SET(FDCSPEED);
-	    printk( "FDC_SPEED ");
-    }
-    if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
-	ATARIHW_SET(ACSI);
-        printk( "ACSI " );
-    }
-    printk("\n");
-
-    if (CPU_IS_040_OR_060)
-        /* Now it seems to be safe to turn of the tt0 transparent
-         * translation (the one that must not be turned off in
-         * head.S...)
-         */
-        __asm__ volatile ("moveq #0,%/d0\n\t"
-                          ".chip 68040\n\t"
-			  "movec %%d0,%%itt0\n\t"
-			  "movec %%d0,%%dtt0\n\t"
-			  ".chip 68k"
-						  : /* no outputs */
-						  : /* no inputs */
-						  : "d0");
-
-    /* allocator for memory that must reside in st-ram */
-    atari_stram_init ();
-
-    /* Set up a mapping for the VMEbus address region:
-     *
-     * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
-     * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
-     * 0xfe000000 virt., because this can be done with a single
-     * transparent translation. On the 68040, lots of often unused
-     * page tables would be needed otherwise. On a MegaSTE or similar,
-     * the highest byte is stripped off by hardware due to the 24 bit
-     * design of the bus.
-     */
+	if (hwreg_present(&tt_rtc.regsel)) {
+		ATARIHW_SET(TT_CLK);
+		printk("TT_CLK ");
+		mach_hwclk = atari_tt_hwclk;
+		mach_set_clock_mmss = atari_tt_set_clock_mmss;
+	}
+	if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
+		ATARIHW_SET(MSTE_CLK);
+		printk("MSTE_CLK ");
+		mach_hwclk = atari_mste_hwclk;
+		mach_set_clock_mmss = atari_mste_set_clock_mmss;
+	}
+	if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+	    hwreg_present(&dma_wd.fdc_speed) &&
+	    hwreg_write(&dma_wd.fdc_speed, 0)) {
+		ATARIHW_SET(FDCSPEED);
+		printk("FDC_SPEED ");
+	}
+	if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+		ATARIHW_SET(ACSI);
+		printk("ACSI ");
+	}
+	printk("\n");
+
+	if (CPU_IS_040_OR_060)
+		/* Now it seems to be safe to turn of the tt0 transparent
+		 * translation (the one that must not be turned off in
+		 * head.S...)
+		 */
+		asm volatile ("\n"
+			"	moveq	#0,%%d0\n"
+			"	.chip	68040\n"
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%dtt0\n"
+			"	.chip	68k"
+			: /* no outputs */
+			: /* no inputs */
+			: "d0");
+
+	/* allocator for memory that must reside in st-ram */
+	atari_stram_init();
+
+	/* Set up a mapping for the VMEbus address region:
+	 *
+	 * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
+	 * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
+	 * 0xfe000000 virt., because this can be done with a single
+	 * transparent translation. On the 68040, lots of often unused
+	 * page tables would be needed otherwise. On a MegaSTE or similar,
+	 * the highest byte is stripped off by hardware due to the 24 bit
+	 * design of the bus.
+	 */
+
+	if (CPU_IS_020_OR_030) {
+		unsigned long tt1_val;
+		tt1_val = 0xfe008543;	/* Translate 0xfexxxxxx, enable, cache
+					 * inhibit, read and write, FDC mask = 3,
+					 * FDC val = 4 -> Supervisor only */
+		asm volatile ("\n"
+			"	.chip	68030\n"
+			"	pmove	%0@,%/tt1\n"
+			"	.chip	68k"
+			: : "a" (&tt1_val));
+	} else {
+	        asm volatile ("\n"
+			"	.chip	68040\n"
+			"	movec	%0,%%itt1\n"
+			"	movec	%0,%%dtt1\n"
+			"	.chip	68k"
+			:
+			: "d" (0xfe00a040));	/* Translate 0xfexxxxxx, enable,
+						 * supervisor only, non-cacheable/
+						 * serialized, writable */
+
+	}
 
-    if (CPU_IS_020_OR_030) {
-        unsigned long	tt1_val;
-        tt1_val = 0xfe008543;	/* Translate 0xfexxxxxx, enable, cache
-                                 * inhibit, read and write, FDC mask = 3,
-                                 * FDC val = 4 -> Supervisor only */
-        __asm__ __volatile__ ( ".chip 68030\n\t"
-				"pmove	%0@,%/tt1\n\t"
-				".chip 68k"
-				: : "a" (&tt1_val) );
-    }
-    else {
-        __asm__ __volatile__
-            ( "movel %0,%/d0\n\t"
-	      ".chip 68040\n\t"
-	      "movec %%d0,%%itt1\n\t"
-	      "movec %%d0,%%dtt1\n\t"
-	      ".chip 68k"
-              :
-              : "g" (0xfe00a040)	/* Translate 0xfexxxxxx, enable,
-                                         * supervisor only, non-cacheable/
-                                         * serialized, writable */
-              : "d0" );
-
-    }
-
-    /* Fetch tos version at Physical 2 */
-    /* We my not be able to access this address if the kernel is
-       loaded to st ram, since the first page is unmapped.  On the
-       Medusa this is always the case and there is nothing we can do
-       about this, so we just assume the smaller offset.  For the TT
-       we use the fact that in head.S we have set up a mapping
-       0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
-       in the last 16MB of the address space. */
-    tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
-		  0xfff : *(unsigned short *)0xff000002;
-    atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
+	/* Fetch tos version at Physical 2 */
+	/*
+	 * We my not be able to access this address if the kernel is
+	 * loaded to st ram, since the first page is unmapped.  On the
+	 * Medusa this is always the case and there is nothing we can do
+	 * about this, so we just assume the smaller offset.  For the TT
+	 * we use the fact that in head.S we have set up a mapping
+	 * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
+	 * in the last 16MB of the address space.
+	 */
+	tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+			0xfff : *(unsigned short *)0xff000002;
+	atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
 }
 
 #ifdef CONFIG_HEARTBEAT
-static void atari_heartbeat( int on )
+static void atari_heartbeat(int on)
 {
-    unsigned char tmp;
-    unsigned long flags;
+	unsigned char tmp;
+	unsigned long flags;
 
-    if (atari_dont_touch_floppy_select)
-	return;
+	if (atari_dont_touch_floppy_select)
+		return;
 
-    local_irq_save(flags);
-    sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
-    tmp = sound_ym.rd_data_reg_sel;
-    sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
-    local_irq_restore(flags);
+	local_irq_save(flags);
+	sound_ym.rd_data_reg_sel = 14;	/* Select PSG Port A */
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
+	local_irq_restore(flags);
 }
 #endif
 
@@ -526,180 +491,171 @@ #endif
 
 /* ++andreas: no need for complicated code, just depend on prefetch */
 
-static void atari_reset (void)
+static void atari_reset(void)
 {
-    long tc_val = 0;
-    long reset_addr;
-
-    /* On the Medusa, phys. 0x4 may contain garbage because it's no
-       ROM.  See above for explanation why we cannot use PTOV(4). */
-    reset_addr = MACH_IS_HADES ? 0x7fe00030 :
-                 MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
-		 *(unsigned long *) 0xff000004;
-
-    /* reset ACIA for switch off OverScan, if it's active */
-    if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
-	acia.key_ctrl = ACIA_RESET;
-    if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
-	acia.mid_ctrl = ACIA_RESET;
-
-    /* processor independent: turn off interrupts and reset the VBR;
-     * the caches must be left enabled, else prefetching the final jump
-     * instruction doesn't work. */
-    local_irq_disable();
-    __asm__ __volatile__
-	("moveq	#0,%/d0\n\t"
-	 "movec	%/d0,%/vbr"
-	 : : : "d0" );
-
-    if (CPU_IS_040_OR_060) {
-        unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
-	if (CPU_IS_060) {
-	    /* 68060: clear PCR to turn off superscalar operation */
-	    __asm__ __volatile__
-		("moveq	#0,%/d0\n\t"
-		 ".chip 68060\n\t"
-		 "movec %%d0,%%pcr\n\t"
-		 ".chip 68k"
-		 : : : "d0" );
-	}
-
-        __asm__ __volatile__
-            ("movel    %0,%/d0\n\t"
-             "andl     #0xff000000,%/d0\n\t"
-             "orw      #0xe020,%/d0\n\t"   /* map 16 MB, enable, cacheable */
-             ".chip 68040\n\t"
-	     "movec    %%d0,%%itt0\n\t"
-             "movec    %%d0,%%dtt0\n\t"
-	     ".chip 68k\n\t"
-             "jmp   %0@\n\t"
-             : /* no outputs */
-             : "a" (jmp_addr040)
-             : "d0" );
-      jmp_addr_label040:
-        __asm__ __volatile__
-          ("moveq #0,%/d0\n\t"
-	   "nop\n\t"
-	   ".chip 68040\n\t"
-	   "cinva %%bc\n\t"
-	   "nop\n\t"
-	   "pflusha\n\t"
-	   "nop\n\t"
-	   "movec %%d0,%%tc\n\t"
-	   "nop\n\t"
-	   /* the following setup of transparent translations is needed on the
-	    * Afterburner040 to successfully reboot. Other machines shouldn't
-	    * care about a different tt regs setup, they also didn't care in
-	    * the past that the regs weren't turned off. */
-	   "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */
-	   "movec %%d0,%%itt0\n\t"
-	   "movec %%d0,%%itt1\n\t"
-	   "orw   #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */
-	   "movec %%d0,%%dtt0\n\t"
-	   "movec %%d0,%%dtt1\n\t"
-	   ".chip 68k\n\t"
-           "jmp %0@"
-           : /* no outputs */
-           : "a" (reset_addr)
-           : "d0");
-    }
-    else
-        __asm__ __volatile__
-            ("pmove %0@,%/tc\n\t"
-             "jmp %1@"
-             : /* no outputs */
-             : "a" (&tc_val), "a" (reset_addr));
+	long tc_val = 0;
+	long reset_addr;
+
+	/*
+	 * On the Medusa, phys. 0x4 may contain garbage because it's no
+	 * ROM.  See above for explanation why we cannot use PTOV(4).
+	 */
+	reset_addr = MACH_IS_HADES ? 0x7fe00030 :
+		     MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+		     *(unsigned long *) 0xff000004;
+
+	/* reset ACIA for switch off OverScan, if it's active */
+	if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+		acia.key_ctrl = ACIA_RESET;
+	if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+		acia.mid_ctrl = ACIA_RESET;
+
+	/* processor independent: turn off interrupts and reset the VBR;
+	 * the caches must be left enabled, else prefetching the final jump
+	 * instruction doesn't work.
+	 */
+	local_irq_disable();
+	asm volatile ("movec	%0,%%vbr"
+			: : "d" (0));
+
+	if (CPU_IS_040_OR_060) {
+		unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+		if (CPU_IS_060) {
+			/* 68060: clear PCR to turn off superscalar operation */
+			asm volatile ("\n"
+				"	.chip 68060\n"
+				"	movec %0,%%pcr\n"
+				"	.chip 68k"
+				: : "d" (0));
+		}
+
+		asm volatile ("\n"
+			"	move.l	%0,%%d0\n"
+			"	and.l	#0xff000000,%%d0\n"
+			"	or.w	#0xe020,%%d0\n"   /* map 16 MB, enable, cacheable */
+			"	.chip	68040\n"
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%dtt0\n"
+			"	.chip	68k\n"
+			"	jmp	%0@"
+			: : "a" (jmp_addr040)
+			: "d0");
+	jmp_addr_label040:
+		asm volatile ("\n"
+			"	moveq	#0,%%d0\n"
+			"	nop\n"
+			"	.chip	68040\n"
+			"	cinva	%%bc\n"
+			"	nop\n"
+			"	pflusha\n"
+			"	nop\n"
+			"	movec	%%d0,%%tc\n"
+			"	nop\n"
+			/* the following setup of transparent translations is needed on the
+			 * Afterburner040 to successfully reboot. Other machines shouldn't
+			 * care about a different tt regs setup, they also didn't care in
+			 * the past that the regs weren't turned off. */
+			"	move.l	#0xffc000,%%d0\n" /* whole insn space cacheable */
+			"	movec	%%d0,%%itt0\n"
+			"	movec	%%d0,%%itt1\n"
+			"	or.w	#0x40,%/d0\n" /* whole data space non-cacheable/ser. */
+			"	movec	%%d0,%%dtt0\n"
+			"	movec	%%d0,%%dtt1\n"
+			"	.chip	68k\n"
+			"	jmp	%0@"
+			: /* no outputs */
+			: "a" (reset_addr)
+			: "d0");
+	} else
+		asm volatile ("\n"
+			"	pmove	%0@,%%tc\n"
+			"	jmp	%1@"
+			: /* no outputs */
+			: "a" (&tc_val), "a" (reset_addr));
 }
 
 
 static void atari_get_model(char *model)
 {
-    strcpy(model, "Atari ");
-    switch (atari_mch_cookie >> 16) {
+	strcpy(model, "Atari ");
+	switch (atari_mch_cookie >> 16) {
 	case ATARI_MCH_ST:
-	    if (ATARIHW_PRESENT(MSTE_CLK))
-		strcat (model, "Mega ST");
-	    else
-		strcat (model, "ST");
-	    break;
+		if (ATARIHW_PRESENT(MSTE_CLK))
+			strcat(model, "Mega ST");
+		else
+			strcat(model, "ST");
+		break;
 	case ATARI_MCH_STE:
-	    if (MACH_IS_MSTE)
-		strcat (model, "Mega STE");
-	    else
-		strcat (model, "STE");
-	    break;
+		if (MACH_IS_MSTE)
+			strcat(model, "Mega STE");
+		else
+			strcat(model, "STE");
+		break;
 	case ATARI_MCH_TT:
-	    if (MACH_IS_MEDUSA)
-		/* Medusa has TT _MCH cookie */
-		strcat (model, "Medusa");
-	    else if (MACH_IS_HADES)
-		strcat(model, "Hades");
-	    else
-		strcat (model, "TT");
-	    break;
+		if (MACH_IS_MEDUSA)
+			/* Medusa has TT _MCH cookie */
+			strcat(model, "Medusa");
+		else if (MACH_IS_HADES)
+			strcat(model, "Hades");
+		else
+			strcat(model, "TT");
+		break;
 	case ATARI_MCH_FALCON:
-	    strcat (model, "Falcon");
-	    if (MACH_IS_AB40)
-		strcat (model, " (with Afterburner040)");
-	    break;
+		strcat(model, "Falcon");
+		if (MACH_IS_AB40)
+			strcat(model, " (with Afterburner040)");
+		break;
 	default:
-	    sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
-		     atari_mch_cookie);
-	    break;
-    }
+		sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)",
+			atari_mch_cookie);
+		break;
+	}
 }
 
 
 static int atari_get_hardware_list(char *buffer)
 {
-    int len = 0, i;
-
-    for (i = 0; i < m68k_num_memory; i++)
-	len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
-			m68k_memory[i].size >> 20, m68k_memory[i].addr,
-			(m68k_memory[i].addr & 0xff000000 ?
-			 "alternate RAM" : "ST-RAM"));
-
-#define ATARIHW_ANNOUNCE(name,str)				\
-    if (ATARIHW_PRESENT(name))			\
-	len += sprintf (buffer + len, "\t%s\n", str)
-
-    len += sprintf (buffer + len, "Detected hardware:\n");
-    ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
-    ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
-    ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
-    ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
-    ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
-    ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
-    ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
-    ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
-    ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
-    ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
-    ATARIHW_ANNOUNCE(IDE, "IDE Interface");
-    ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
-    ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
-    ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
-    ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
-    ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
-    ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
-    ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
-    ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
-    ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
-    ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
-    ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
-    ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
-    ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
-    ATARIHW_ANNOUNCE(SCU, "System Control Unit");
-    ATARIHW_ANNOUNCE(BLITTER, "Blitter");
-    ATARIHW_ANNOUNCE(VME, "VME Bus");
-    ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
-
-    return(len);
+	int len = 0, i;
+
+	for (i = 0; i < m68k_num_memory; i++)
+		len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
+				m68k_memory[i].size >> 20, m68k_memory[i].addr,
+				(m68k_memory[i].addr & 0xff000000 ?
+				 "alternate RAM" : "ST-RAM"));
+
+#define ATARIHW_ANNOUNCE(name, str)			\
+	if (ATARIHW_PRESENT(name))			\
+		len += sprintf(buffer + len, "\t%s\n", str)
+
+	len += sprintf(buffer + len, "Detected hardware:\n");
+	ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
+	ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
+	ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
+	ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
+	ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
+	ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
+	ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
+	ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
+	ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
+	ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
+	ATARIHW_ANNOUNCE(IDE, "IDE Interface");
+	ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
+	ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
+	ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
+	ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
+	ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
+	ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
+	ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
+	ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
+	ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
+	ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
+	ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
+	ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
+	ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
+	ATARIHW_ANNOUNCE(SCU, "System Control Unit");
+	ATARIHW_ANNOUNCE(BLITTER, "Blitter");
+	ATARIHW_ANNOUNCE(VME, "VME Bus");
+	ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
+
+	return len;
 }
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 8
- * End:
- */
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c
index 4ae0100..fbeed8c 100644
--- a/arch/m68k/atari/debug.c
+++ b/arch/m68k/atari/debug.c
@@ -19,8 +19,6 @@ #include <linux/delay.h>
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 
-extern char m68k_debug_device[];
-
 /* Flag that Modem1 port is already initialized and used */
 int atari_MFP_init_done;
 /* Flag that Modem1 port is already initialized and used */
@@ -30,317 +28,317 @@ int atari_SCC_init_done;
 int atari_SCC_reset_done;
 
 static struct console atari_console_driver = {
-	.name =		"debug",
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
+	.name	= "debug",
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
 };
 
 
-static inline void ata_mfp_out (char c)
+static inline void ata_mfp_out(char c)
 {
-    while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
-	barrier ();
-    mfp.usart_dta = c;
+	while (!(mfp.trn_stat & 0x80))	/* wait for tx buf empty */
+		barrier();
+	mfp.usart_dta = c;
 }
 
-void atari_mfp_console_write (struct console *co, const char *str,
-			      unsigned int count)
+void atari_mfp_console_write(struct console *co, const char *str,
+			     unsigned int count)
 {
-    while (count--) {
-	if (*str == '\n')
-	    ata_mfp_out( '\r' );
-	ata_mfp_out( *str++ );
-    }
+	while (count--) {
+		if (*str == '\n')
+			ata_mfp_out('\r');
+		ata_mfp_out(*str++);
+	}
 }
 
-static inline void ata_scc_out (char c)
+static inline void ata_scc_out(char c)
 {
-    do {
+	do {
+		MFPDELAY();
+	} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
 	MFPDELAY();
-    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
-    MFPDELAY();
-    scc.cha_b_data = c;
+	scc.cha_b_data = c;
 }
 
-void atari_scc_console_write (struct console *co, const char *str,
-			      unsigned int count)
+void atari_scc_console_write(struct console *co, const char *str,
+			     unsigned int count)
 {
-    while (count--) {
-	if (*str == '\n')
-	    ata_scc_out( '\r' );
-	ata_scc_out( *str++ );
-    }
+	while (count--) {
+		if (*str == '\n')
+			ata_scc_out('\r');
+		ata_scc_out(*str++);
+	}
 }
 
-static inline void ata_midi_out (char c)
+static inline void ata_midi_out(char c)
 {
-    while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
-	barrier ();
-    acia.mid_data = c;
+	while (!(acia.mid_ctrl & ACIA_TDRE))	/* wait for tx buf empty */
+		barrier();
+	acia.mid_data = c;
 }
 
-void atari_midi_console_write (struct console *co, const char *str,
-			       unsigned int count)
+void atari_midi_console_write(struct console *co, const char *str,
+			      unsigned int count)
 {
-    while (count--) {
-	if (*str == '\n')
-	    ata_midi_out( '\r' );
-	ata_midi_out( *str++ );
-    }
+	while (count--) {
+		if (*str == '\n')
+			ata_midi_out('\r');
+		ata_midi_out(*str++);
+	}
 }
 
-static int ata_par_out (char c)
+static int ata_par_out(char c)
 {
-    unsigned char tmp;
-    /* This a some-seconds timeout in case no printer is connected */
-    unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
-
-    while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
-	;
-    if (!i) return( 0 );
-
-    sound_ym.rd_data_reg_sel = 15;  /* select port B */
-    sound_ym.wd_data = c;           /* put char onto port */
-    sound_ym.rd_data_reg_sel = 14;  /* select port A */
-    tmp = sound_ym.rd_data_reg_sel;
-    sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
-    MFPDELAY();                     /* wait a bit */
-    sound_ym.wd_data = tmp | 0x20;  /* set strobe H */
-    return( 1 );
+	unsigned char tmp;
+	/* This a some-seconds timeout in case no printer is connected */
+	unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
+
+	while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
+		;
+	if (!i)
+		return 0;
+
+	sound_ym.rd_data_reg_sel = 15;	/* select port B */
+	sound_ym.wd_data = c;		/* put char onto port */
+	sound_ym.rd_data_reg_sel = 14;	/* select port A */
+	tmp = sound_ym.rd_data_reg_sel;
+	sound_ym.wd_data = tmp & ~0x20;	/* set strobe L */
+	MFPDELAY();			/* wait a bit */
+	sound_ym.wd_data = tmp | 0x20;	/* set strobe H */
+	return 1;
 }
 
-static void atari_par_console_write (struct console *co, const char *str,
-				     unsigned int count)
+static void atari_par_console_write(struct console *co, const char *str,
+				    unsigned int count)
 {
-    static int printer_present = 1;
+	static int printer_present = 1;
 
-    if (!printer_present)
-	return;
-
-    while (count--) {
-	if (*str == '\n')
-	    if (!ata_par_out( '\r' )) {
-		printer_present = 0;
+	if (!printer_present)
 		return;
-	    }
-	if (!ata_par_out( *str++ )) {
-	    printer_present = 0;
-	    return;
+
+	while (count--) {
+		if (*str == '\n') {
+			if (!ata_par_out('\r')) {
+				printer_present = 0;
+				return;
+			}
+		}
+		if (!ata_par_out(*str++)) {
+			printer_present = 0;
+			return;
+		}
 	}
-    }
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
 int atari_mfp_console_wait_key(struct console *co)
 {
-    while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
-	barrier();
-    return( mfp.usart_dta );
+	while (!(mfp.rcv_stat & 0x80))	/* wait for rx buf filled */
+		barrier();
+	return mfp.usart_dta;
 }
 
 int atari_scc_console_wait_key(struct console *co)
 {
-    do {
+	do {
+		MFPDELAY();
+	} while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
 	MFPDELAY();
-    } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
-    MFPDELAY();
-    return( scc.cha_b_data );
+	return scc.cha_b_data;
 }
 
 int atari_midi_console_wait_key(struct console *co)
 {
-    while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */
-	barrier();
-    return( acia.mid_data );
+	while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */
+		barrier();
+	return acia.mid_data;
 }
 #endif
 
-/* The following two functions do a quick'n'dirty initialization of the MFP or
+/*
+ * The following two functions do a quick'n'dirty initialization of the MFP or
  * SCC serial ports. They're used by the debugging interface, kgdb, and the
- * serial console code. */
+ * serial console code.
+ */
 #ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_mfp_port( int cflag )
+static void __init atari_init_mfp_port(int cflag)
 #else
-void atari_init_mfp_port( int cflag )
+void atari_init_mfp_port(int cflag)
 #endif
 {
-    /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
-     * bps, resp., and work only correct if there's a RSVE or RSSPEED */
-    static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
-    int baud = cflag & CBAUD;
-    int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
-    int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
-
-    if (cflag & CBAUDEX)
-	baud += B38400;
-    if (baud < B1200 || baud > B38400+2)
-	baud = B9600; /* use default 9600bps for non-implemented rates */
-    baud -= B1200; /* baud_table[] starts at 1200bps */
-
-    mfp.trn_stat &= ~0x01; /* disable TX */
-    mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
-    mfp.tim_ct_cd &= 0x70;  /* stop timer D */
-    mfp.tim_dt_d = baud_table[baud];
-    mfp.tim_ct_cd |= 0x01;  /* start timer D, 1:4 */
-    mfp.trn_stat |= 0x01;  /* enable TX */
-
-    atari_MFP_init_done = 1;
+	/*
+	 * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
+	 * bps, resp., and work only correct if there's a RSVE or RSSPEED
+	 */
+	static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
+	int baud = cflag & CBAUD;
+	int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
+	int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
+
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud < B1200 || baud > B38400+2)
+		baud = B9600;		/* use default 9600bps for non-implemented rates */
+	baud -= B1200;			/* baud_table[] starts at 1200bps */
+
+	mfp.trn_stat &= ~0x01;		/* disable TX */
+	mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+	mfp.tim_ct_cd &= 0x70;		/* stop timer D */
+	mfp.tim_dt_d = baud_table[baud];
+	mfp.tim_ct_cd |= 0x01;		/* start timer D, 1:4 */
+	mfp.trn_stat |= 0x01;		/* enable TX */
+
+	atari_MFP_init_done = 1;
 }
 
-#define SCC_WRITE(reg,val)				\
-    do {						\
-	scc.cha_b_ctrl = (reg);				\
-	MFPDELAY();					\
-	scc.cha_b_ctrl = (val);				\
-	MFPDELAY();					\
-    } while(0)
+#define SCC_WRITE(reg, val)				\
+	do {						\
+		scc.cha_b_ctrl = (reg);			\
+		MFPDELAY();				\
+		scc.cha_b_ctrl = (val);			\
+		MFPDELAY();				\
+	} while (0)
 
 /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
  * delay of ~ 60us. */
-#define LONG_DELAY()				\
-    do {					\
-	int i;					\
-	for( i = 100; i > 0; --i )		\
-	    MFPDELAY();				\
-    } while(0)
+#define LONG_DELAY()					\
+	do {						\
+		int i;					\
+		for (i = 100; i > 0; --i)		\
+			MFPDELAY();			\
+	} while (0)
 
 #ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_scc_port( int cflag )
+static void __init atari_init_scc_port(int cflag)
 #else
-void atari_init_scc_port( int cflag )
+void atari_init_scc_port(int cflag)
 #endif
 {
-    extern int atari_SCC_reset_done;
-    static int clksrc_table[9] =
-	/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
-	{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
-    static int brgsrc_table[9] =
-	/* reg 14: 0 = RTxC, 2 = PCLK */
-	{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
-    static int clkmode_table[9] =
-	/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
-	{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
-    static int div_table[9] =
-	/* reg12 (BRG low) */
-	{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
-
-    int baud = cflag & CBAUD;
-    int clksrc, clkmode, div, reg3, reg5;
-
-    if (cflag & CBAUDEX)
-	baud += B38400;
-    if (baud < B1200 || baud > B38400+2)
-	baud = B9600; /* use default 9600bps for non-implemented rates */
-    baud -= B1200; /* tables starts at 1200bps */
-
-    clksrc  = clksrc_table[baud];
-    clkmode = clkmode_table[baud];
-    div     = div_table[baud];
-    if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
-	/* special treatment for TT, where rates >= 38400 are done via TRxC */
-	clksrc = 0x28; /* TRxC */
-	clkmode = baud == 6 ? 0xc0 :
-		  baud == 7 ? 0x80 : /* really 76800bps */
-			      0x40;  /* really 153600bps */
-	div = 0;
-    }
-
-    reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
-    reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
-
-    (void)scc.cha_b_ctrl;	/* reset reg pointer */
-    SCC_WRITE( 9, 0xc0 );	/* reset */
-    LONG_DELAY();		/* extra delay after WR9 access */
-    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
-		  0x04 /* 1 stopbit */ |
-		  clkmode );
-    SCC_WRITE( 3, reg3 );
-    SCC_WRITE( 5, reg5 );
-    SCC_WRITE( 9, 0 );		/* no interrupts */
-    LONG_DELAY();		/* extra delay after WR9 access */
-    SCC_WRITE( 10, 0 );		/* NRZ mode */
-    SCC_WRITE( 11, clksrc );	/* main clock source */
-    SCC_WRITE( 12, div );	/* BRG value */
-    SCC_WRITE( 13, 0 );		/* BRG high byte */
-    SCC_WRITE( 14, brgsrc_table[baud] );
-    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
-    SCC_WRITE( 3, reg3 | 1 );
-    SCC_WRITE( 5, reg5 | 8 );
-
-    atari_SCC_reset_done = 1;
-    atari_SCC_init_done = 1;
+	extern int atari_SCC_reset_done;
+	static int clksrc_table[9] =
+		/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+		{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+	static int brgsrc_table[9] =
+		/* reg 14: 0 = RTxC, 2 = PCLK */
+		{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+	static int clkmode_table[9] =
+		/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+		{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+	static int div_table[9] =
+		/* reg12 (BRG low) */
+		{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+	int baud = cflag & CBAUD;
+	int clksrc, clkmode, div, reg3, reg5;
+
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud < B1200 || baud > B38400+2)
+		baud = B9600;		/* use default 9600bps for non-implemented rates */
+	baud -= B1200;			/* tables starts at 1200bps */
+
+	clksrc  = clksrc_table[baud];
+	clkmode = clkmode_table[baud];
+	div     = div_table[baud];
+	if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
+		/* special treatment for TT, where rates >= 38400 are done via TRxC */
+		clksrc = 0x28;		/* TRxC */
+		clkmode = baud == 6 ? 0xc0 :
+			  baud == 7 ? 0x80 : /* really 76800bps */
+				      0x40;  /* really 153600bps */
+		div = 0;
+	}
+
+	reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+	reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+
+	(void)scc.cha_b_ctrl;		/* reset reg pointer */
+	SCC_WRITE(9, 0xc0);		/* reset */
+	LONG_DELAY();			/* extra delay after WR9 access */
+	SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
+				      : 0 | 0x04 /* 1 stopbit */ | clkmode);
+	SCC_WRITE(3, reg3);
+	SCC_WRITE(5, reg5);
+	SCC_WRITE(9, 0);		/* no interrupts */
+	LONG_DELAY();			/* extra delay after WR9 access */
+	SCC_WRITE(10, 0);		/* NRZ mode */
+	SCC_WRITE(11, clksrc);		/* main clock source */
+	SCC_WRITE(12, div);		/* BRG value */
+	SCC_WRITE(13, 0);		/* BRG high byte */
+	SCC_WRITE(14, brgsrc_table[baud]);
+	SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
+	SCC_WRITE(3, reg3 | 1);
+	SCC_WRITE(5, reg5 | 8);
+
+	atari_SCC_reset_done = 1;
+	atari_SCC_init_done = 1;
 }
 
 #ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_midi_port( int cflag )
+static void __init atari_init_midi_port(int cflag)
 #else
-void atari_init_midi_port( int cflag )
+void atari_init_midi_port(int cflag)
 #endif
 {
-    int baud = cflag & CBAUD;
-    int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
-    /* warning 7N1 isn't possible! (instead 7O2 is used...) */
-    int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
-    int div;
-
-    /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
-     * default) the standard MIDI speed 31250. */
-    if (cflag & CBAUDEX)
-	baud += B38400;
-    if (baud == B4800)
-	div = ACIA_DIV64; /* really 7812.5 bps */
-    else if (baud == B38400+2 /* 115200 */)
-	div = ACIA_DIV1; /* really 500 kbps (does that work??) */
-    else
-	div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
-
-    /* RTS low, ints disabled */
-    acia.mid_ctrl = div | csize | parity |
+	int baud = cflag & CBAUD;
+	int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
+	/* warning 7N1 isn't possible! (instead 7O2 is used...) */
+	int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
+	int div;
+
+	/* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
+	 * default) the standard MIDI speed 31250. */
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud == B4800)
+		div = ACIA_DIV64;	/* really 7812.5 bps */
+	else if (baud == B38400+2 /* 115200 */)
+		div = ACIA_DIV1;	/* really 500 kbps (does that work??) */
+	else
+		div = ACIA_DIV16;	/* 31250 bps, standard for MIDI */
+
+	/* RTS low, ints disabled */
+	acia.mid_ctrl = div | csize | parity |
 		    ((atari_switches & ATARI_SWITCH_MIDI) ?
 		     ACIA_RHTID : ACIA_RLTID);
 }
 
-void __init atari_debug_init(void)
+static int __init atari_debug_setup(char *arg)
 {
-    if (!strcmp( m68k_debug_device, "ser" )) {
-	/* defaults to ser2 for a Falcon and ser1 otherwise */
-	strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" );
-
-    }
-
-    if (!strcmp( m68k_debug_device, "ser1" )) {
-	/* ST-MFP Modem1 serial port */
-	atari_init_mfp_port( B9600|CS8 );
-	atari_console_driver.write = atari_mfp_console_write;
-    }
-    else if (!strcmp( m68k_debug_device, "ser2" )) {
-	/* SCC Modem2 serial port */
-	atari_init_scc_port( B9600|CS8 );
-	atari_console_driver.write = atari_scc_console_write;
-    }
-    else if (!strcmp( m68k_debug_device, "midi" )) {
-	/* MIDI port */
-	atari_init_midi_port( B9600|CS8 );
-	atari_console_driver.write = atari_midi_console_write;
-    }
-    else if (!strcmp( m68k_debug_device, "par" )) {
-	/* parallel printer */
-	atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
-	sound_ym.rd_data_reg_sel = 7;  /* select mixer control */
-	sound_ym.wd_data = 0xff;       /* sound off, ports are output */
-	sound_ym.rd_data_reg_sel = 15; /* select port B */
-	sound_ym.wd_data = 0;          /* no char */
-	sound_ym.rd_data_reg_sel = 14; /* select port A */
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
-	atari_console_driver.write = atari_par_console_write;
-    }
-    if (atari_console_driver.write)
-	register_console(&atari_console_driver);
+	if (!MACH_IS_ATARI)
+		return 0;
+
+	if (!strcmp(arg, "ser"))
+		/* defaults to ser2 for a Falcon and ser1 otherwise */
+		arg = MACH_IS_FALCON ? "ser2" : "ser1";
+
+	if (!strcmp(arg, "ser1")) {
+		/* ST-MFP Modem1 serial port */
+		atari_init_mfp_port(B9600|CS8);
+		atari_console_driver.write = atari_mfp_console_write;
+	} else if (!strcmp(arg, "ser2")) {
+		/* SCC Modem2 serial port */
+		atari_init_scc_port(B9600|CS8);
+		atari_console_driver.write = atari_scc_console_write;
+	} else if (!strcmp(arg, "midi")) {
+		/* MIDI port */
+		atari_init_midi_port(B9600|CS8);
+		atari_console_driver.write = atari_midi_console_write;
+	} else if (!strcmp(arg, "par")) {
+		/* parallel printer */
+		atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
+		sound_ym.rd_data_reg_sel = 7;	/* select mixer control */
+		sound_ym.wd_data = 0xff;	/* sound off, ports are output */
+		sound_ym.rd_data_reg_sel = 15;	/* select port B */
+		sound_ym.wd_data = 0;		/* no char */
+		sound_ym.rd_data_reg_sel = 14;	/* select port A */
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
+		atari_console_driver.write = atari_par_console_write;
+	}
+	if (atari_console_driver.write)
+		register_console(&atari_console_driver);
+
+	return 0;
 }
 
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 8
- * End:
- */
+early_param("debug", atari_debug_setup);
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 222ce42..e162ee6 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -692,7 +692,7 @@ sys_call_table:
 	.long sys_tgkill	/* 265 */
 	.long sys_utimes
 	.long sys_fadvise64_64
-	.long sys_mbind	
+	.long sys_mbind
 	.long sys_get_mempolicy
 	.long sys_set_mempolicy	/* 270 */
 	.long sys_mq_open
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 6739e87..05741f2 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -3195,7 +3195,7 @@ #ifdef CONFIG_HP300
 	jbra	L(serial_putc_done)
 3:
 #endif
-	
+
 L(serial_putc_done):
 func_return	serial_putc
 
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index b66c97c..60d4d75 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -59,14 +59,14 @@ static int m68k_first_user_vec;
 
 static struct irq_controller auto_irq_controller = {
 	.name		= "auto",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
 	.startup	= m68k_irq_startup,
 	.shutdown	= m68k_irq_shutdown,
 };
 
 static struct irq_controller user_irq_controller = {
 	.name		= "user",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(user_irq_controller.lock),
 	.startup	= m68k_irq_startup,
 	.shutdown	= m68k_irq_shutdown,
 };
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 7fd2720..cdba9fd 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -14,7 +14,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 42b8fd0..6103193 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -71,9 +71,6 @@ 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) (irq_handler_t handler) __initdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
@@ -133,78 +130,78 @@ extern void config_hp300(void);
 extern void config_q40(void);
 extern void config_sun3x(void);
 
-extern void mac_debugging_short (int, short);
-extern void mac_debugging_long  (int, long);
-
 #define MASK_256K 0xfffc0000
 
 extern void paging_init(void);
 
 static void __init m68k_parse_bootinfo(const struct bi_record *record)
 {
-    while (record->tag != BI_LAST) {
-	int unknown = 0;
-	const unsigned long *data = record->data;
-	switch (record->tag) {
-	    case BI_MACHTYPE:
-	    case BI_CPUTYPE:
-	    case BI_FPUTYPE:
-	    case BI_MMUTYPE:
-		/* Already set up by head.S */
-		break;
-
-	    case BI_MEMCHUNK:
-		if (m68k_num_memory < NUM_MEMINFO) {
-		    m68k_memory[m68k_num_memory].addr = data[0];
-		    m68k_memory[m68k_num_memory].size = data[1];
-		    m68k_num_memory++;
-		} else
-		    printk("m68k_parse_bootinfo: too many memory chunks\n");
-		break;
-
-	    case BI_RAMDISK:
-		m68k_ramdisk.addr = data[0];
-		m68k_ramdisk.size = data[1];
-		break;
-
-	    case BI_COMMAND_LINE:
-		strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line));
-		break;
-
-	    default:
-		if (MACH_IS_AMIGA)
-		    unknown = amiga_parse_bootinfo(record);
-		else if (MACH_IS_ATARI)
-		    unknown = atari_parse_bootinfo(record);
-		else if (MACH_IS_MAC)
-		    unknown = mac_parse_bootinfo(record);
-		else if (MACH_IS_Q40)
-		    unknown = q40_parse_bootinfo(record);
-		else if (MACH_IS_BVME6000)
-		    unknown = bvme6000_parse_bootinfo(record);
-		else if (MACH_IS_MVME16x)
-		    unknown = mvme16x_parse_bootinfo(record);
-		else if (MACH_IS_MVME147)
-		    unknown = mvme147_parse_bootinfo(record);
-		else if (MACH_IS_HP300)
-		    unknown = hp300_parse_bootinfo(record);
-		else
-		    unknown = 1;
+	while (record->tag != BI_LAST) {
+		int unknown = 0;
+		const unsigned long *data = record->data;
+
+		switch (record->tag) {
+		case BI_MACHTYPE:
+		case BI_CPUTYPE:
+		case BI_FPUTYPE:
+		case BI_MMUTYPE:
+			/* Already set up by head.S */
+			break;
+
+		case BI_MEMCHUNK:
+			if (m68k_num_memory < NUM_MEMINFO) {
+				m68k_memory[m68k_num_memory].addr = data[0];
+				m68k_memory[m68k_num_memory].size = data[1];
+				m68k_num_memory++;
+			} else
+				printk("m68k_parse_bootinfo: too many memory chunks\n");
+			break;
+
+		case BI_RAMDISK:
+			m68k_ramdisk.addr = data[0];
+			m68k_ramdisk.size = data[1];
+			break;
+
+		case BI_COMMAND_LINE:
+			strlcpy(m68k_command_line, (const char *)data,
+				sizeof(m68k_command_line));
+			break;
+
+		default:
+			if (MACH_IS_AMIGA)
+				unknown = amiga_parse_bootinfo(record);
+			else if (MACH_IS_ATARI)
+				unknown = atari_parse_bootinfo(record);
+			else if (MACH_IS_MAC)
+				unknown = mac_parse_bootinfo(record);
+			else if (MACH_IS_Q40)
+				unknown = q40_parse_bootinfo(record);
+			else if (MACH_IS_BVME6000)
+				unknown = bvme6000_parse_bootinfo(record);
+			else if (MACH_IS_MVME16x)
+				unknown = mvme16x_parse_bootinfo(record);
+			else if (MACH_IS_MVME147)
+				unknown = mvme147_parse_bootinfo(record);
+			else if (MACH_IS_HP300)
+				unknown = hp300_parse_bootinfo(record);
+			else
+				unknown = 1;
+		}
+		if (unknown)
+			printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
+			       record->tag);
+		record = (struct bi_record *)((unsigned long)record +
+					      record->size);
 	}
-	if (unknown)
-	    printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
-		   record->tag);
-	record = (struct bi_record *)((unsigned long)record+record->size);
-    }
 
-    m68k_realnum_memory = m68k_num_memory;
+	m68k_realnum_memory = m68k_num_memory;
 #ifdef CONFIG_SINGLE_MEMORY_CHUNK
-    if (m68k_num_memory > 1) {
-	printk("Ignoring last %i chunks of physical memory\n",
-	       (m68k_num_memory - 1));
-	m68k_num_memory = 1;
-    }
-    m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
+	if (m68k_num_memory > 1) {
+		printk("Ignoring last %i chunks of physical memory\n",
+		       (m68k_num_memory - 1));
+		m68k_num_memory = 1;
+	}
+	m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
 #endif
 }
 
@@ -215,7 +212,6 @@ #ifndef CONFIG_SUN3
 	unsigned long endmem, startmem;
 #endif
 	int i;
-	char *p, *q;
 
 	/* The bootinfo is located right after the kernel bss */
 	m68k_parse_bootinfo((const struct bi_record *)&_end);
@@ -234,7 +230,7 @@ #ifndef CONFIG_M68KFPU_EMU_ONLY
 	/* clear the fpu if we have one */
 	if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
 		volatile int zero = 0;
-		asm __volatile__ ("frestore %0" : : "m" (zero));
+		asm volatile ("frestore %0" : : "m" (zero));
 	}
 #endif
 
@@ -258,37 +254,7 @@ #endif
 	*cmdline_p = m68k_command_line;
 	memcpy(boot_command_line, *cmdline_p, CL_SIZE);
 
-	/* Parse the command line for arch-specific options.
-	 * For the m68k, this is currently only "debug=xxx" to enable printing
-	 * certain kernel messages to some machine-specific device.
-	 */
-	for( p = *cmdline_p; p && *p; ) {
-	    i = 0;
-	    if (!strncmp( p, "debug=", 6 )) {
-		strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) );
-		if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
-		i = 1;
-	    }
-#ifdef CONFIG_ATARI
-	    /* This option must be parsed very early */
-	    if (!strncmp( p, "switches=", 9 )) {
-		extern void atari_switches_setup( const char *, int );
-		atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
-				           (q - (p+9)) : strlen(p+9) );
-		i = 1;
-	    }
-#endif
-
-	    if (i) {
-		/* option processed, delete it */
-		if ((q = strchr( p, ' ' )))
-		    strcpy( p, q+1 );
-		else
-		    *p = 0;
-	    } else {
-		if ((p = strchr( p, ' ' ))) ++p;
-	    }
-	}
+	parse_early_param();
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -296,62 +262,62 @@ #endif
 
 	switch (m68k_machtype) {
 #ifdef CONFIG_AMIGA
-	    case MACH_AMIGA:
+	case MACH_AMIGA:
 		config_amiga();
 		break;
 #endif
 #ifdef CONFIG_ATARI
-	    case MACH_ATARI:
+	case MACH_ATARI:
 		config_atari();
 		break;
 #endif
 #ifdef CONFIG_MAC
-	    case MACH_MAC:
+	case MACH_MAC:
 		config_mac();
 		break;
 #endif
 #ifdef CONFIG_SUN3
-	    case MACH_SUN3:
+	case MACH_SUN3:
 		config_sun3();
 		break;
 #endif
 #ifdef CONFIG_APOLLO
-	    case MACH_APOLLO:
+	case MACH_APOLLO:
 		config_apollo();
 		break;
 #endif
 #ifdef CONFIG_MVME147
-	    case MACH_MVME147:
+	case MACH_MVME147:
 		config_mvme147();
 		break;
 #endif
 #ifdef CONFIG_MVME16x
-	    case MACH_MVME16x:
+	case MACH_MVME16x:
 		config_mvme16x();
 		break;
 #endif
 #ifdef CONFIG_BVME6000
-	    case MACH_BVME6000:
+	case MACH_BVME6000:
 		config_bvme6000();
 		break;
 #endif
 #ifdef CONFIG_HP300
-	    case MACH_HP300:
+	case MACH_HP300:
 		config_hp300();
 		break;
 #endif
 #ifdef CONFIG_Q40
-	    case MACH_Q40:
-	        config_q40();
+	case MACH_Q40:
+		config_q40();
 		break;
 #endif
 #ifdef CONFIG_SUN3X
-	    case MACH_SUN3X:
+	case MACH_SUN3X:
 		config_sun3x();
 		break;
 #endif
-	    default:
-		panic ("No configuration setup");
+	default:
+		panic("No configuration setup");
 	}
 
 #ifndef CONFIG_SUN3
@@ -380,7 +346,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
 		reserve_bootmem(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);
+		printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
 	}
 #endif
 
@@ -402,18 +368,18 @@ #endif /* !CONFIG_SUN3 */
 #if defined(CONFIG_ISA) && defined(MULTI_ISA)
 #if defined(CONFIG_Q40)
 	if (MACH_IS_Q40) {
-	    isa_type = Q40_ISA;
-	    isa_sex = 0;
+		isa_type = Q40_ISA;
+		isa_sex = 0;
 	}
 #elif defined(CONFIG_GG2)
-	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){
-	    isa_type = GG2_ISA;
-	    isa_sex = 0;
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) {
+		isa_type = GG2_ISA;
+		isa_sex = 0;
 	}
 #elif defined(CONFIG_AMIGA_PCMCIA)
-	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){
-	    isa_type = AG_ISA;
-	    isa_sex = 1;
+	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
+		isa_type = AG_ISA;
+		isa_sex = 1;
 	}
 #endif
 #endif
@@ -421,66 +387,66 @@ #endif
 
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-    const char *cpu, *mmu, *fpu;
-    unsigned long clockfreq, clockfactor;
+	const char *cpu, *mmu, *fpu;
+	unsigned long clockfreq, clockfactor;
 
 #define LOOP_CYCLES_68020	(8)
 #define LOOP_CYCLES_68030	(8)
 #define LOOP_CYCLES_68040	(3)
 #define LOOP_CYCLES_68060	(1)
 
-    if (CPU_IS_020) {
-	cpu = "68020";
-	clockfactor = LOOP_CYCLES_68020;
-    } else if (CPU_IS_030) {
-	cpu = "68030";
-	clockfactor = LOOP_CYCLES_68030;
-    } else if (CPU_IS_040) {
-	cpu = "68040";
-	clockfactor = LOOP_CYCLES_68040;
-    } else if (CPU_IS_060) {
-	cpu = "68060";
-	clockfactor = LOOP_CYCLES_68060;
-    } else {
-	cpu = "680x0";
-	clockfactor = 0;
-    }
+	if (CPU_IS_020) {
+		cpu = "68020";
+		clockfactor = LOOP_CYCLES_68020;
+	} else if (CPU_IS_030) {
+		cpu = "68030";
+		clockfactor = LOOP_CYCLES_68030;
+	} else if (CPU_IS_040) {
+		cpu = "68040";
+		clockfactor = LOOP_CYCLES_68040;
+	} else if (CPU_IS_060) {
+		cpu = "68060";
+		clockfactor = LOOP_CYCLES_68060;
+	} else {
+		cpu = "680x0";
+		clockfactor = 0;
+	}
 
 #ifdef CONFIG_M68KFPU_EMU_ONLY
-    fpu="none(soft float)";
+	fpu = "none(soft float)";
 #else
-    if (m68k_fputype & FPU_68881)
-	fpu = "68881";
-    else if (m68k_fputype & FPU_68882)
-	fpu = "68882";
-    else if (m68k_fputype & FPU_68040)
-	fpu = "68040";
-    else if (m68k_fputype & FPU_68060)
-	fpu = "68060";
-    else if (m68k_fputype & FPU_SUNFPA)
-	fpu = "Sun FPA";
-    else
-	fpu = "none";
+	if (m68k_fputype & FPU_68881)
+		fpu = "68881";
+	else if (m68k_fputype & FPU_68882)
+		fpu = "68882";
+	else if (m68k_fputype & FPU_68040)
+		fpu = "68040";
+	else if (m68k_fputype & FPU_68060)
+		fpu = "68060";
+	else if (m68k_fputype & FPU_SUNFPA)
+		fpu = "Sun FPA";
+	else
+		fpu = "none";
 #endif
 
-    if (m68k_mmutype & MMU_68851)
-	mmu = "68851";
-    else if (m68k_mmutype & MMU_68030)
-	mmu = "68030";
-    else if (m68k_mmutype & MMU_68040)
-	mmu = "68040";
-    else if (m68k_mmutype & MMU_68060)
-	mmu = "68060";
-    else if (m68k_mmutype & MMU_SUN3)
-	mmu = "Sun-3";
-    else if (m68k_mmutype & MMU_APOLLO)
-	mmu = "Apollo";
-    else
-	mmu = "unknown";
-
-    clockfreq = loops_per_jiffy*HZ*clockfactor;
-
-    seq_printf(m, "CPU:\t\t%s\n"
+	if (m68k_mmutype & MMU_68851)
+		mmu = "68851";
+	else if (m68k_mmutype & MMU_68030)
+		mmu = "68030";
+	else if (m68k_mmutype & MMU_68040)
+		mmu = "68040";
+	else if (m68k_mmutype & MMU_68060)
+		mmu = "68060";
+	else if (m68k_mmutype & MMU_SUN3)
+		mmu = "Sun-3";
+	else if (m68k_mmutype & MMU_APOLLO)
+		mmu = "Apollo";
+	else
+		mmu = "unknown";
+
+	clockfreq = loops_per_jiffy * HZ * clockfactor;
+
+	seq_printf(m, "CPU:\t\t%s\n"
 		   "MMU:\t\t%s\n"
 		   "FPU:\t\t%s\n"
 		   "Clocking:\t%lu.%1luMHz\n"
@@ -490,7 +456,7 @@ #endif
 		   clockfreq/1000000,(clockfreq/100000)%10,
 		   loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
 		   loops_per_jiffy);
-    return 0;
+	return 0;
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
@@ -506,44 +472,54 @@ 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,
 };
 
 int get_hardware_list(char *buffer)
 {
-    int len = 0;
-    char model[80];
-    unsigned long mem;
-    int i;
+	int len = 0;
+	char model[80];
+	unsigned long mem;
+	int i;
 
-    if (mach_get_model)
-	mach_get_model(model);
-    else
-	strcpy(model, "Unknown m68k");
+	if (mach_get_model)
+		mach_get_model(model);
+	else
+		strcpy(model, "Unknown m68k");
 
-    len += sprintf(buffer+len, "Model:\t\t%s\n", model);
-    for (mem = 0, i = 0; i < m68k_num_memory; i++)
-	mem += m68k_memory[i].size;
-    len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
+	len += sprintf(buffer + len, "Model:\t\t%s\n", model);
+	for (mem = 0, i = 0; i < m68k_num_memory; i++)
+		mem += m68k_memory[i].size;
+	len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10);
 
-    if (mach_get_hardware_list)
-	len += mach_get_hardware_list(buffer+len);
+	if (mach_get_hardware_list)
+		len += mach_get_hardware_list(buffer + len);
 
-    return(len);
+	return len;
 }
 
 void check_bugs(void)
 {
 #ifndef CONFIG_M68KFPU_EMU
 	if (m68k_fputype == 0) {
-		printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
-				"WHICH IS REQUIRED BY LINUX/M68K ***\n" );
-		printk( KERN_EMERG "Upgrade your hardware or join the FPU "
-				"emulation project\n" );
-		panic( "no FPU" );
+		printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+			"WHICH IS REQUIRED BY LINUX/M68K ***\n");
+		printk(KERN_EMERG "Upgrade your hardware or join the FPU "
+			"emulation project\n");
+		panic("no FPU");
 	}
 #endif /* !CONFIG_M68KFPU_EMU */
 }
+
+#ifdef CONFIG_ADB
+static int __init adb_probe_sync_enable (char *str) {
+	extern int __adb_probe_sync;
+	__adb_probe_sync = 1;
+	return 1;
+}
+
+__setup("adb_sync", adb_probe_sync_enable);
+#endif /* CONFIG_ADB */
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
index aed3be2..cf6bb51 100644
--- a/arch/m68k/lib/checksum.c
+++ b/arch/m68k/lib/checksum.c
@@ -320,6 +320,9 @@ #define STR1(X) #X
 	return(sum);
 }
 
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+
 /*
  * copy from kernel space while checksumming, otherwise like csum_partial
  */
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index a1c7ec7..673a108 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -22,7 +22,7 @@ #include <asm/mac_baboon.h>
 /* #define DEBUG_BABOON */
 /* #define DEBUG_IRQS */
 
-int baboon_present,baboon_active;
+int baboon_present;
 volatile struct baboon *baboon;
 
 irqreturn_t baboon_irq(int, void *);
@@ -45,7 +45,6 @@ void __init baboon_init(void)
 
 	baboon = (struct baboon *) BABOON_BASE;
 	baboon_present = 1;
-	baboon_active = 0;
 
 	printk("Baboon detected at %p\n", baboon);
 }
@@ -66,26 +65,28 @@ void __init baboon_register_interrupts(v
 
 irqreturn_t baboon_irq(int irq, void *dev_id)
 {
-	int irq_bit,i;
+	int irq_bit, irq_num;
 	unsigned char events;
 
 #ifdef DEBUG_IRQS
-	printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n",
+	printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n",
 		(uint) baboon->mb_control, (uint) baboon->mb_ifr,
-		(uint) baboon->mb_status,  baboon_active);
+		(uint) baboon->mb_status);
 #endif
 
 	if (!(events = baboon->mb_ifr & 0x07))
 		return IRQ_NONE;
 
-	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);
-			baboon_active |= irq_bit;
+	irq_num = IRQ_BABOON_0;
+	irq_bit = 1;
+	do {
+	        if (events & irq_bit) {
 			baboon->mb_ifr &= ~irq_bit;
+			m68k_handle_int(irq_num);
 		}
-	}
+		irq_bit <<= 1;
+		irq_num++;
+	} while(events >= irq_bit);
 #if 0
 	if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
 	/* for now we need to smash all interrupts */
@@ -95,21 +96,18 @@ #endif
 }
 
 void baboon_irq_enable(int irq) {
-	int irq_idx	= IRQ_IDX(irq);
-
 #ifdef DEBUG_IRQUSE
 	printk("baboon_irq_enable(%d)\n", irq);
 #endif
-	baboon_active |= (1 << irq_idx);
+	/* FIXME: figure out how to mask and unmask baboon interrupt sources */
+	enable_irq(IRQ_NUBUS_C);
 }
 
 void baboon_irq_disable(int irq) {
-	int irq_idx	= IRQ_IDX(irq);
-
 #ifdef DEBUG_IRQUSE
 	printk("baboon_irq_disable(%d)\n", irq);
 #endif
-	baboon_active &= ~(1 << irq_idx);
+	disable_irq(IRQ_NUBUS_C);
 }
 
 void baboon_irq_clear(int irq) {
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 562b38d..5fd4132 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk;
 
 extern char m68k_command_line[CL_SIZE];
 
-void *mac_env;		/* Loaded by the boot asm */
+void *mac_env;					/* Loaded by the boot asm */
 
 /* The phys. video addr. - might be bogus on some machines */
 unsigned long mac_orig_videoaddr;
 
 /* Mac specific timer functions */
-extern unsigned long mac_gettimeoffset (void);
-extern int mac_hwclk (int, struct rtc_time *);
-extern int mac_set_clock_mmss (unsigned long);
+extern unsigned long mac_gettimeoffset(void);
+extern int mac_hwclk(int, struct rtc_time *);
+extern int mac_set_clock_mmss(unsigned long);
 extern int show_mac_interrupts(struct seq_file *, void *);
 extern void iop_preinit(void);
 extern void iop_init(void);
@@ -82,10 +82,6 @@ extern void mac_mksound(unsigned int, un
 
 extern void nubus_sweep_video(void);
 
-/* Mac specific debug functions (in debug.c) */
-extern void mac_debug_init(void);
-extern void mac_debugging_long(int, long);
-
 static void mac_get_model(char *str);
 
 static void mac_sched_init(irq_handler_t vector)
@@ -99,51 +95,52 @@ static void mac_sched_init(irq_handler_t
 
 int __init mac_parse_bootinfo(const struct bi_record *record)
 {
-    int unknown = 0;
-    const u_long *data = record->data;
+	int unknown = 0;
+	const u_long *data = record->data;
 
-    switch (record->tag) {
+	switch (record->tag) {
 	case BI_MAC_MODEL:
-	    mac_bi_data.id = *data;
-	    break;
+		mac_bi_data.id = *data;
+		break;
 	case BI_MAC_VADDR:
-	    mac_bi_data.videoaddr = *data;
-	    break;
+		mac_bi_data.videoaddr = *data;
+		break;
 	case BI_MAC_VDEPTH:
-	    mac_bi_data.videodepth = *data;
-	    break;
+		mac_bi_data.videodepth = *data;
+		break;
 	case BI_MAC_VROW:
-	    mac_bi_data.videorow = *data;
-	    break;
+		mac_bi_data.videorow = *data;
+		break;
 	case BI_MAC_VDIM:
-	    mac_bi_data.dimensions = *data;
-	    break;
+		mac_bi_data.dimensions = *data;
+		break;
 	case BI_MAC_VLOGICAL:
-	    mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
-	    mac_orig_videoaddr = *data;
-	    break;
+		mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+		mac_orig_videoaddr = *data;
+		break;
 	case BI_MAC_SCCBASE:
-	    mac_bi_data.sccbase = *data;
-	    break;
+		mac_bi_data.sccbase = *data;
+		break;
 	case BI_MAC_BTIME:
-	    mac_bi_data.boottime = *data;
-	    break;
+		mac_bi_data.boottime = *data;
+		break;
 	case BI_MAC_GMTBIAS:
-	    mac_bi_data.gmtbias = *data;
-	    break;
+		mac_bi_data.gmtbias = *data;
+		break;
 	case BI_MAC_MEMSIZE:
-	    mac_bi_data.memsize = *data;
-	    break;
+		mac_bi_data.memsize = *data;
+		break;
 	case BI_MAC_CPUID:
-	    mac_bi_data.cpuid = *data;
-	    break;
-        case BI_MAC_ROMBASE:
-	    mac_bi_data.rombase = *data;
-	    break;
+		mac_bi_data.cpuid = *data;
+		break;
+	case BI_MAC_ROMBASE:
+		mac_bi_data.rombase = *data;
+		break;
 	default:
-	    unknown = 1;
-    }
-    return(unknown);
+		unknown = 1;
+		break;
+	}
+	return unknown;
 }
 
 /*
@@ -155,6 +152,7 @@ int __init mac_parse_bootinfo(const stru
 static void mac_cache_card_flush(int writeback)
 {
 	unsigned long flags;
+
 	local_irq_save(flags);
 	via_flush_cache();
 	local_irq_restore(flags);
@@ -162,28 +160,24 @@ static void mac_cache_card_flush(int wri
 
 void __init config_mac(void)
 {
-	if (!MACH_IS_MAC) {
-	  printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
-	}
+	if (!MACH_IS_MAC)
+		printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
 
-	mach_sched_init      = mac_sched_init;
-	mach_init_IRQ        = mac_init_IRQ;
-	mach_get_model	 = mac_get_model;
-	mach_gettimeoffset   = mac_gettimeoffset;
+	mach_sched_init = mac_sched_init;
+	mach_init_IRQ = mac_init_IRQ;
+	mach_get_model = mac_get_model;
+	mach_gettimeoffset = mac_gettimeoffset;
 #warning move to adb/via init
 #if 0
-	mach_hwclk           = mac_hwclk;
+	mach_hwclk = mac_hwclk;
 #endif
-	mach_set_clock_mmss	 = mac_set_clock_mmss;
-	mach_reset           = mac_reset;
-	mach_halt            = mac_poweroff;
-	mach_power_off       = mac_poweroff;
+	mach_set_clock_mmss = mac_set_clock_mmss;
+	mach_reset = mac_reset;
+	mach_halt = mac_poweroff;
+	mach_power_off = mac_poweroff;
 	mach_max_dma_address = 0xffffffff;
-#if 0
-	mach_debug_init	 = mac_debug_init;
-#endif
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
-        mach_beep            = mac_mksound;
+	mach_beep = mac_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
 #if 0
@@ -199,21 +193,22 @@ #endif
 	mac_identify();
 	mac_report_hardware();
 
-	/* AFAIK only the IIci takes a cache card.  The IIfx has onboard
-	   cache ... someone needs to figure out how to tell if it's on or
-	   not. */
+	/*
+	 * AFAIK only the IIci takes a cache card.  The IIfx has onboard
+	 * cache ... someone needs to figure out how to tell if it's on or
+	 * not.
+	 */
 
 	if (macintosh_config->ident == MAC_MODEL_IICI
-	    || macintosh_config->ident == MAC_MODEL_IIFX) {
+	    || macintosh_config->ident == MAC_MODEL_IIFX)
 		mach_l2_flush = mac_cache_card_flush;
-	}
 
 	/*
 	 * Check for machine specific fixups.
 	 */
 
 #ifdef OLD_NUBUS_CODE
-	 nubus_sweep_video();
+	nubus_sweep_video();
 #endif
 }
 
@@ -233,8 +228,7 @@ #endif
 struct mac_model *macintosh_config;
 EXPORT_SYMBOL(macintosh_config);
 
-static struct mac_model mac_data_table[]=
-{
+static struct mac_model mac_data_table[] = {
 	/*
 	 *	We'll pretend to be a Macintosh II, that's pretty safe.
 	 */
@@ -784,12 +778,12 @@ void mac_identify(void)
 	if (!model) {
 		/* no bootinfo model id -> NetBSD booter was used! */
 		/* XXX FIXME: breaks for model > 31 */
-		model=(mac_bi_data.cpuid>>2)&63;
-		printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+		model = (mac_bi_data.cpuid >> 2) & 63;
+		printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
 	}
 
 	macintosh_config = mac_data_table;
-	for (m = macintosh_config ; m->ident != -1 ; m++) {
+	for (m = macintosh_config; m->ident != -1; m++) {
 		if (m->ident == model) {
 			macintosh_config = m;
 			break;
@@ -801,27 +795,26 @@ void mac_identify(void)
 	/* the serial ports set to "Faster" mode in MacOS. */
 
 	iop_preinit();
-	mac_debug_init();
 
-	printk (KERN_INFO "Detected Macintosh model: %d \n", model);
+	printk(KERN_INFO "Detected Macintosh model: %d \n", model);
 
 	/*
 	 * Report booter data:
 	 */
-	printk (KERN_DEBUG " Penguin bootinfo data:\n");
-	printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
+	printk(KERN_DEBUG " Penguin bootinfo data:\n");
+	printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
 		mac_bi_data.videoaddr, mac_bi_data.videorow,
 		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
 		mac_bi_data.dimensions >> 16);
-	printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+	printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
 		mac_bi_data.videological, mac_orig_videoaddr,
 		mac_bi_data.sccbase);
-	printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
+	printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
 		mac_bi_data.boottime, mac_bi_data.gmtbias);
-	printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+	printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
 		mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
 #if 0
-	printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
+	printk("Ramdisk: addr 0x%lx size 0x%lx\n",
 		m68k_ramdisk.addr, m68k_ramdisk.size);
 #endif
 
@@ -830,22 +823,22 @@ #endif
 	 */
 	switch (macintosh_config->scsi_type) {
 	case MAC_SCSI_OLD:
-	  MACHW_SET(MAC_SCSI_80);
-	  break;
+		MACHW_SET(MAC_SCSI_80);
+		break;
 	case MAC_SCSI_QUADRA:
 	case MAC_SCSI_QUADRA2:
 	case MAC_SCSI_QUADRA3:
-	  MACHW_SET(MAC_SCSI_96);
-	  if ((macintosh_config->ident == MAC_MODEL_Q900) ||
-	      (macintosh_config->ident == MAC_MODEL_Q950))
-	    MACHW_SET(MAC_SCSI_96_2);
-	  break;
+		MACHW_SET(MAC_SCSI_96);
+		if ((macintosh_config->ident == MAC_MODEL_Q900) ||
+		    (macintosh_config->ident == MAC_MODEL_Q950))
+			MACHW_SET(MAC_SCSI_96_2);
+		break;
 	default:
-	  printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
-	  MACHW_SET(MAC_SCSI_80);
-	  break;
-
+		printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
+		MACHW_SET(MAC_SCSI_80);
+		break;
 	}
+
 	iop_init();
 	via_init();
 	oss_init();
@@ -860,6 +853,6 @@ void mac_report_hardware(void)
 
 static void mac_get_model(char *str)
 {
-	strcpy(str,"Macintosh ");
+	strcpy(str, "Macintosh ");
 	strcat(str, macintosh_config->name);
 }
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 4eeb09d..7a5bed5 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -27,10 +27,6 @@ #include <asm/bootinfo.h>
 #include <asm/machw.h>
 #include <asm/macints.h>
 
-extern char m68k_debug_device[];
-
-extern struct compat_bootinfo compat_boot_info;
-
 extern unsigned long mac_videobase;
 extern unsigned long mac_videodepth;
 extern unsigned long mac_rowbytes;
@@ -52,7 +48,7 @@ #define DEBUG_SERIAL
  */
 
 #ifdef DEBUG_SCREEN
-static int peng=0, line=0;
+static int peng, line;
 #endif
 
 void mac_debugging_short(int pos, short num)
@@ -74,15 +70,14 @@ #ifdef DEBUG_SCREEN
 	}
 
 	/* calculate current offset */
-	pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
-		    +80*peng;
+	pengoffset = (unsigned char *)mac_videobase +
+		(150+line*2) * mac_rowbytes) + 80 * peng;
 
-	pptr=pengoffset;
+	pptr = pengoffset;
 
-	for(i=0;i<8*sizeof(short);i++) /* # of bits */
-	{
+	for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */
 		/*        value        mask for bit i, reverse order */
-		*pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
+		*pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00);
 	}
 
 	peng++;
@@ -115,11 +110,10 @@ #ifdef DEBUG_SCREEN
 	pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
 		    +80*peng;
 
-	pptr=pengoffset;
+	pptr = pengoffset;
 
-	for(i=0;i<8*sizeof(long);i++) /* # of bits */
-	{
-		*pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
+	for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */
+		*pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00);
 	}
 
 	peng++;
@@ -136,16 +130,15 @@ #ifdef DEBUG_SERIAL
  * TODO: serial debug code
  */
 
-struct mac_SCC
- {
-  u_char cha_b_ctrl;
-  u_char char_dummy1;
-  u_char cha_a_ctrl;
-  u_char char_dummy2;
-  u_char cha_b_data;
-  u_char char_dummy3;
-  u_char cha_a_data;
- };
+struct mac_SCC {
+	u_char cha_b_ctrl;
+	u_char char_dummy1;
+	u_char cha_a_ctrl;
+	u_char char_dummy2;
+	u_char cha_b_data;
+	u_char char_dummy3;
+	u_char cha_a_data;
+};
 
 # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
 
@@ -158,9 +151,9 @@ int mac_SCC_reset_done;
 static int scc_port = -1;
 
 static struct console mac_console_driver = {
-	.name =		"debug",
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
+	.name	= "debug",
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
 };
 
 /*
@@ -178,8 +171,8 @@ static struct console mac_console_driver
  * this driver if Mac.
  */
 
-void mac_debug_console_write (struct console *co, const char *str,
-			      unsigned int count)
+void mac_debug_console_write(struct console *co, const char *str,
+			     unsigned int count)
 {
 	mac_serial_print(str);
 }
@@ -190,48 +183,50 @@ void mac_debug_console_write (struct con
 
 #define uSEC 1
 
-static inline void mac_sccb_out (char c)
+static inline void mac_sccb_out(char c)
 {
-    int i;
-    do {
-	for( i = uSEC; i > 0; --i )
+	int i;
+
+	do {
+		for (i = uSEC; i > 0; --i)
+			barrier();
+	} while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+	for (i = uSEC; i > 0; --i)
 		barrier();
-    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
-    for( i = uSEC; i > 0; --i )
-	barrier();
-    scc.cha_b_data = c;
+	scc.cha_b_data = c;
 }
 
-static inline void mac_scca_out (char c)
+static inline void mac_scca_out(char c)
 {
-    int i;
-    do {
-	for( i = uSEC; i > 0; --i )
+	int i;
+
+	do {
+		for (i = uSEC; i > 0; --i)
+			barrier();
+	} while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+	for (i = uSEC; i > 0; --i)
 		barrier();
-    } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
-    for( i = uSEC; i > 0; --i )
-	barrier();
-    scc.cha_a_data = c;
+	scc.cha_a_data = c;
 }
 
-void mac_sccb_console_write (struct console *co, const char *str,
-			      unsigned int count)
+void mac_sccb_console_write(struct console *co, const char *str,
+			    unsigned int count)
 {
-    while (count--) {
-	if (*str == '\n')
-	    mac_sccb_out( '\r' );
-	mac_sccb_out( *str++ );
-    }
+	while (count--) {
+		if (*str == '\n')
+			mac_sccb_out('\r');
+		mac_sccb_out(*str++);
+	}
 }
 
-void mac_scca_console_write (struct console *co, const char *str,
-			      unsigned int count)
+void mac_scca_console_write(struct console *co, const char *str,
+			    unsigned int count)
 {
-    while (count--) {
-	if (*str == '\n')
-	    mac_scca_out( '\r' );
-	mac_scca_out( *str++ );
-    }
+	while (count--) {
+		if (*str == '\n')
+			mac_scca_out('\r');
+		mac_scca_out(*str++);
+	}
 }
 
 
@@ -239,41 +234,41 @@ void mac_scca_console_write (struct cons
  * SCC serial ports. They're used by the debugging interface, kgdb, and the
  * serial console code. */
 #define SCCB_WRITE(reg,val)				\
-    do {						\
-	int i;						\
-	scc.cha_b_ctrl = (reg);				\
-	for( i = uSEC; i > 0; --i )			\
-		barrier();				\
-	scc.cha_b_ctrl = (val);				\
-	for( i = uSEC; i > 0; --i )			\
-		barrier();				\
-    } while(0)
+	do {						\
+		int i;					\
+		scc.cha_b_ctrl = (reg);			\
+		for (i = uSEC; i > 0; --i)		\
+			barrier();			\
+		scc.cha_b_ctrl = (val);			\
+		for (i = uSEC; i > 0; --i)		\
+			barrier();			\
+	} while(0)
 
 #define SCCA_WRITE(reg,val)				\
-    do {						\
-	int i;						\
-	scc.cha_a_ctrl = (reg);				\
-	for( i = uSEC; i > 0; --i )			\
-		barrier();				\
-	scc.cha_a_ctrl = (val);				\
-	for( i = uSEC; i > 0; --i )			\
-		barrier();				\
-    } while(0)
+	do {						\
+		int i;					\
+		scc.cha_a_ctrl = (reg);			\
+		for (i = uSEC; i > 0; --i)		\
+			barrier();			\
+		scc.cha_a_ctrl = (val);			\
+		for (i = uSEC; i > 0; --i)		\
+			barrier();			\
+	} while(0)
 
 /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
  * delay of ~ 60us. */
 /* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
-#define LONG_DELAY()				\
-    do {					\
-	int i;					\
-	for( i = 60*uSEC; i > 0; --i )		\
-	    barrier();				\
-    } while(0)
+#define LONG_DELAY()					\
+	do {						\
+		int i;					\
+		for (i = 60*uSEC; i > 0; --i)		\
+		    barrier();				\
+	} while(0)
 
 #ifndef CONFIG_SERIAL_CONSOLE
-static void __init mac_init_scc_port( int cflag, int port )
+static void __init mac_init_scc_port(int cflag, int port)
 #else
-void mac_init_scc_port( int cflag, int port )
+void mac_init_scc_port(int cflag, int port)
 #endif
 {
 	extern int mac_SCC_reset_done;
@@ -292,106 +287,102 @@ #endif
 		/* reg12 (BRG low) */
 		{ 94, 62, 46, 22, 10, 4, 1, 0, 0 };
 
-    int baud = cflag & CBAUD;
-    int clksrc, clkmode, div, reg3, reg5;
-
-    if (cflag & CBAUDEX)
-	baud += B38400;
-    if (baud < B1200 || baud > B38400+2)
-	baud = B9600; /* use default 9600bps for non-implemented rates */
-    baud -= B1200; /* tables starts at 1200bps */
-
-    clksrc  = clksrc_table[baud];
-    clkmode = clkmode_table[baud];
-    div     = div_table[baud];
-
-    reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
-    reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
-
-    if (port == 1) {
-	    (void)scc.cha_b_ctrl;	/* reset reg pointer */
-	    SCCB_WRITE( 9, 0xc0 );	/* reset */
-	    LONG_DELAY();		/* extra delay after WR9 access */
-	    SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+	int baud = cflag & CBAUD;
+	int clksrc, clkmode, div, reg3, reg5;
+
+	if (cflag & CBAUDEX)
+		baud += B38400;
+	if (baud < B1200 || baud > B38400+2)
+		baud = B9600; /* use default 9600bps for non-implemented rates */
+	baud -= B1200; /* tables starts at 1200bps */
+
+	clksrc  = clksrc_table[baud];
+	clkmode = clkmode_table[baud];
+	div     = div_table[baud];
+
+	reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
+	reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
+
+	if (port == 1) {
+		(void)scc.cha_b_ctrl;	/* reset reg pointer */
+		SCCB_WRITE(9, 0xc0);	/* reset */
+		LONG_DELAY();		/* extra delay after WR9 access */
+		SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+			   0x04 /* 1 stopbit */ |
+			   clkmode);
+		SCCB_WRITE(3, reg3);
+		SCCB_WRITE(5, reg5);
+		SCCB_WRITE(9, 0);	/* no interrupts */
+		LONG_DELAY();		/* extra delay after WR9 access */
+		SCCB_WRITE(10, 0);	/* NRZ mode */
+		SCCB_WRITE(11, clksrc);	/* main clock source */
+		SCCB_WRITE(12, div);	/* BRG value */
+		SCCB_WRITE(13, 0);	/* BRG high byte */
+		SCCB_WRITE(14, 1);
+		SCCB_WRITE(3, reg3 | 1);
+		SCCB_WRITE(5, reg5 | 8);
+	} else if (port == 0) {
+		(void)scc.cha_a_ctrl;	/* reset reg pointer */
+		SCCA_WRITE(9, 0xc0);	/* reset */
+		LONG_DELAY();		/* extra delay after WR9 access */
+		SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
 			  0x04 /* 1 stopbit */ |
-			  clkmode );
-	    SCCB_WRITE( 3, reg3 );
-	    SCCB_WRITE( 5, reg5 );
-	    SCCB_WRITE( 9, 0 );		/* no interrupts */
-	    LONG_DELAY();		/* extra delay after WR9 access */
-	    SCCB_WRITE( 10, 0 );	/* NRZ mode */
-	    SCCB_WRITE( 11, clksrc );	/* main clock source */
-	    SCCB_WRITE( 12, div );	/* BRG value */
-	    SCCB_WRITE( 13, 0 );		/* BRG high byte */
-	    SCCB_WRITE( 14, 1 );
-	    SCCB_WRITE( 3, reg3 | 1 );
-	    SCCB_WRITE( 5, reg5 | 8 );
-    } else if (port == 0) {
-	    (void)scc.cha_a_ctrl;	/* reset reg pointer */
-	    SCCA_WRITE( 9, 0xc0 );	/* reset */
-	    LONG_DELAY();		/* extra delay after WR9 access */
-	    SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
-			  0x04 /* 1 stopbit */ |
-			  clkmode );
-	    SCCA_WRITE( 3, reg3 );
-	    SCCA_WRITE( 5, reg5 );
-	    SCCA_WRITE( 9, 0 );		/* no interrupts */
-	    LONG_DELAY();		/* extra delay after WR9 access */
-	    SCCA_WRITE( 10, 0 );	/* NRZ mode */
-	    SCCA_WRITE( 11, clksrc );	/* main clock source */
-	    SCCA_WRITE( 12, div );	/* BRG value */
-	    SCCA_WRITE( 13, 0 );		/* BRG high byte */
-	    SCCA_WRITE( 14, 1 );
-	    SCCA_WRITE( 3, reg3 | 1 );
-	    SCCA_WRITE( 5, reg5 | 8 );
-    }
-
-    mac_SCC_reset_done = 1;
-    mac_SCC_init_done = 1;
+			  clkmode);
+		SCCA_WRITE(3, reg3);
+		SCCA_WRITE(5, reg5);
+		SCCA_WRITE(9, 0);	/* no interrupts */
+		LONG_DELAY();		/* extra delay after WR9 access */
+		SCCA_WRITE(10, 0);	/* NRZ mode */
+		SCCA_WRITE(11, clksrc);	/* main clock source */
+		SCCA_WRITE(12, div);	/* BRG value */
+		SCCA_WRITE(13, 0);	/* BRG high byte */
+		SCCA_WRITE(14, 1);
+		SCCA_WRITE(3, reg3 | 1);
+		SCCA_WRITE(5, reg5 | 8);
+	}
+
+	mac_SCC_reset_done = 1;
+	mac_SCC_init_done = 1;
 }
 #endif /* DEBUG_SERIAL */
 
-void mac_init_scca_port( int cflag )
+void mac_init_scca_port(int cflag)
 {
 	mac_init_scc_port(cflag, 0);
 }
 
-void mac_init_sccb_port( int cflag )
+void mac_init_sccb_port(int cflag)
 {
 	mac_init_scc_port(cflag, 1);
 }
 
-void __init mac_debug_init(void)
+static int __init mac_debug_setup(char *arg)
 {
+	if (!MACH_IS_MAC)
+		return 0;
+
 #ifdef DEBUG_SERIAL
-    if (   !strcmp( m68k_debug_device, "ser"  )
-        || !strcmp( m68k_debug_device, "ser1" )) {
-	/* Mac modem port */
-	mac_init_scc_port( B9600|CS8, 0 );
-	mac_console_driver.write = mac_scca_console_write;
-	scc_port = 0;
-    }
-    else if (!strcmp( m68k_debug_device, "ser2" )) {
-	/* Mac printer port */
-	mac_init_scc_port( B9600|CS8, 1 );
-	mac_console_driver.write = mac_sccb_console_write;
-	scc_port = 1;
-    }
+	if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) {
+		/* Mac modem port */
+		mac_init_scc_port(B9600|CS8, 0);
+		mac_console_driver.write = mac_scca_console_write;
+		scc_port = 0;
+	} else if (!strcmp(arg, "ser2")) {
+		/* Mac printer port */
+		mac_init_scc_port(B9600|CS8, 1);
+		mac_console_driver.write = mac_sccb_console_write;
+		scc_port = 1;
+	}
 #endif
 #ifdef DEBUG_HEADS
-    if (   !strcmp( m68k_debug_device, "scn"  )
-        || !strcmp( m68k_debug_device, "con" )) {
-	/* display, using head.S console routines */
-	mac_console_driver.write = mac_debug_console_write;
-    }
+	if (!strcmp(arg, "scn") || !strcmp(arg, "con")) {
+		/* display, using head.S console routines */
+		mac_console_driver.write = mac_debug_console_write;
+	}
 #endif
-    if (mac_console_driver.write)
-	register_console(&mac_console_driver);
+	if (mac_console_driver.write)
+		register_console(&mac_console_driver);
+	return 0;
 }
 
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 8
- * End:
- */
+early_param("debug", mac_debug_setup);
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index f6fcd75..0fc72d8 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -219,7 +219,7 @@ static void mac_disable_irq(unsigned int
 
 static struct irq_controller mac_irq_controller = {
 	.name		= "mac",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),
 	.enable		= mac_enable_irq,
 	.disable	= mac_disable_irq,
 };
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 6369081..d7be169 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -109,13 +109,11 @@ #endif
 	/* FIXME: how do you clear a pending IRQ?    */
 
 	if (events & OSS_IP_SOUND) {
-		/* FIXME: call sound handler */
 		oss->irq_pending &= ~OSS_IP_SOUND;
+		/* FIXME: call sound handler */
 	} else if (events & OSS_IP_SCSI) {
-		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
-		m68k_handle_int(IRQ_MAC_SCSI);
 		oss->irq_pending &= ~OSS_IP_SCSI;
-		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+		m68k_handle_int(IRQ_MAC_SCSI);
 	} else {
 		/* FIXME: error check here? */
 	}
@@ -143,14 +141,16 @@ #ifdef DEBUG_NUBUS_INT
 #endif
 	/* There are only six slots on the OSS, not seven */
 
-	for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+	i = 6;
+	irq_bit = 0x40;
+	do {
+		--i;
+		irq_bit >>= 1;
 		if (events & irq_bit) {
-			oss->irq_level[i] = OSS_IRQLEV_DISABLED;
-			m68k_handle_int(NUBUS_SOURCE_BASE + i);
 			oss->irq_pending &= ~irq_bit;
-			oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+			m68k_handle_int(NUBUS_SOURCE_BASE + i);
 		}
-	}
+	} while(events & (irq_bit - 1));
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index 15378a5..d66f723 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -131,11 +131,8 @@ irqreturn_t psc_irq(int irq, void *dev_i
 {
 	int pIFR	= pIFRbase + ((int) dev_id);
 	int pIER	= pIERbase + ((int) dev_id);
-	int base_irq;
-	int irq_bit,i;
-	unsigned char events;
-
-	base_irq = irq << 3;
+	int irq_num;
+	unsigned char irq_bit, events;
 
 #ifdef DEBUG_IRQS
 	printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
@@ -146,14 +143,16 @@ #endif
 	if (!events)
 		return IRQ_NONE;
 
-	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);
+	irq_num = irq << 3;
+	irq_bit = 1;
+	do {
+		if (events & irq_bit) {
 			psc_write_byte(pIFR, irq_bit);
-			psc_write_byte(pIER, irq_bit | 0x80);
+			m68k_handle_int(irq_num);
 		}
-	}
+		irq_num++;
+		irq_bit <<= 1;
+	} while (events >= irq_bit);
 	return IRQ_HANDLED;
 }
 
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index e27735b..d5cac72 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -13,6 +13,10 @@
  * for info.  A full-text web search on 6522 AND VIA will probably also
  * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
  *
+ * Additional data is here (the SY6522 was used in the Mac II etc):
+ *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
+ *     http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
+ *
  * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
  * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
  *
@@ -37,7 +41,7 @@ #if 0
 /* See note in mac_via.h about how this is possibly not useful */
 volatile long *via_memory_bogon=(long *)&via_memory_bogon;
 #endif
-int  rbv_present,via_alt_mapping;
+int rbv_present, via_alt_mapping;
 __u8 rbv_clear;
 
 /*
@@ -60,7 +64,19 @@ #define MAC_CLOCK_TICK		(783300/HZ)		/* 
 #define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
 
-static int  nubus_active;
+/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
+ * high. On RBV we just use the slot interrupt enable register. On Macs with
+ * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
+ * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
+ * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
+ * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
+ * because closing one of those drivers can mask all of the NuBus interrupts.
+ * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
+ * possible to get interrupts from cards that MacOS or the ROM has configured
+ * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
+ * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
+ */
+static u8 nubus_disabled;
 
 void via_debug_dump(void);
 irqreturn_t via1_irq(int, void *);
@@ -138,11 +154,11 @@ void __init via_init(void)
 
 	printk(KERN_INFO "VIA2 at %p is ", via2);
 	if (rbv_present) {
-		printk(KERN_INFO "an RBV\n");
+		printk("an RBV\n");
 	} else if (oss_present) {
-		printk(KERN_INFO "an OSS\n");
+		printk("an OSS\n");
 	} else {
-		printk(KERN_INFO "a 6522 or clone\n");
+		printk("a 6522 or clone\n");
 	}
 
 #ifdef DEBUG_VIA
@@ -163,6 +179,7 @@ #endif
 	via1[vT2CL] = 0;
 	via1[vT2CH] = 0;
 	via1[vACR] &= 0x3F;
+	via1[vACR] &= ~0x03; /* disable port A & B latches */
 
 	/*
 	 * SE/30: disable video IRQ
@@ -193,8 +210,14 @@ #if 1
 	/* that the IIfx emulates this alternate mapping using the OSS. */
 
 	switch(macintosh_config->ident) {
+		case MAC_MODEL_P475:
+		case MAC_MODEL_P475F:
+		case MAC_MODEL_P575:
+		case MAC_MODEL_Q605:
+		case MAC_MODEL_Q605_ACC:
 		case MAC_MODEL_C610:
 		case MAC_MODEL_Q610:
+		case MAC_MODEL_Q630:
 		case MAC_MODEL_C650:
 		case MAC_MODEL_Q650:
 		case MAC_MODEL_Q700:
@@ -228,6 +251,22 @@ #endif
 		via2[vT2CL] = 0;
 		via2[vT2CH] = 0;
 		via2[vACR] &= 0x3F;
+		via2[vACR] &= ~0x03; /* disable port A & B latches */
+	}
+
+	/*
+	 * Set vPCR for SCSI interrupts (but not on RBV)
+	 */
+	if (!rbv_present) {
+		if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
+			/* CB2 (IRQ) indep. input, positive edge */
+			/* CA2 (DRQ) indep. input, positive edge */
+			via2[vPCR] = 0x66;
+		} else {
+			/* CB2 (IRQ) indep. input, negative edge */
+			/* CA2 (DRQ) indep. input, negative edge */
+			via2[vPCR] = 0x22;
+		}
 	}
 }
 
@@ -356,78 +395,75 @@ int via_get_cache_disable(void)
 
 void __init via_nubus_init(void)
 {
-	/* don't set nubus_active = 0 here, it kills the Baboon */
-	/* interrupt that we've already registered.		*/
-
 	/* unlock nubus transactions */
 
-	if (!rbv_present) {
+	if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+	    (macintosh_config->adb_type != MAC_ADB_PB2)) {
 		/* set the line to be an output on non-RBV machines */
-		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+		if (!rbv_present)
 			via2[vDirB] |= 0x02;
-		}
-	}
 
-	/* this seems to be an ADB bit on PMU machines */
-	/* according to MkLinux.  -- jmt               */
-
-	if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-	    (macintosh_config->adb_type != MAC_ADB_PB2)) {
+		/* this seems to be an ADB bit on PMU machines */
+		/* according to MkLinux.  -- jmt               */
 		via2[gBufB] |= 0x02;
 	}
 
-	/* disable nubus slot interrupts. */
-	if (rbv_present) {
+	/* Disable all the slot interrupts (where possible). */
+
+	switch (macintosh_config->via_type) {
+	case MAC_VIA_II:
+		/* Just make the port A lines inputs. */
+		switch(macintosh_config->ident) {
+		case MAC_MODEL_II:
+		case MAC_MODEL_IIX:
+		case MAC_MODEL_IICX:
+		case MAC_MODEL_SE30:
+			/* The top two bits are RAM size outputs. */
+			via2[vDirA] &= 0xC0;
+			break;
+		default:
+			via2[vDirA] &= 0x80;
+		}
+		break;
+	case MAC_VIA_IIci:
+		/* RBV. Disable all the slot interrupts. SIER works like IER. */
 		via2[rSIER] = 0x7F;
-		via2[rSIER] = nubus_active | 0x80;
-	} else {
-		/* These are ADB bits on PMU */
+		break;
+	case MAC_VIA_QUADRA:
+		/* Disable the inactive slot interrupts by making those lines outputs. */
 		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
-			switch(macintosh_config->ident)
-			{
-				case MAC_MODEL_II:
-				case MAC_MODEL_IIX:
-				case MAC_MODEL_IICX:
-				case MAC_MODEL_SE30:
-					via2[vBufA] |= 0x3F;
-					via2[vDirA] = ~nubus_active | 0xc0;
-					break;
-				default:
-					via2[vBufA] = 0xFF;
-					via2[vDirA] = ~nubus_active;
-			}
+		    (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			via2[vBufA] |= 0x7F;
+			via2[vDirA] |= 0x7F;
 		}
+		break;
 	}
 }
 
 /*
  * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
  * via6522.c :-), disable/pending masks added.
- *
- * The new interrupt architecture in macints.c takes care of a lot of the
- * gruntwork for us, including tallying the interrupts and calling the
- * handlers on the linked list. All we need to do here is basically generate
- * the machspec interrupt number after clearing the interrupt.
  */
 
 irqreturn_t via1_irq(int irq, void *dev_id)
 {
-	int irq_bit, i;
-	unsigned char events, mask;
+	int irq_num;
+	unsigned char irq_bit, events;
 
-	mask = via1[vIER] & 0x7F;
-	if (!(events = via1[vIFR] & mask))
+	events = via1[vIFR] & via1[vIER] & 0x7F;
+	if (!events)
 		return IRQ_NONE;
 
-	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+	irq_num = VIA1_SOURCE_BASE;
+	irq_bit = 1;
+	do {
 		if (events & irq_bit) {
-			via1[vIER] = irq_bit;
-			m68k_handle_int(VIA1_SOURCE_BASE + i);
 			via1[vIFR] = irq_bit;
-			via1[vIER] = irq_bit | 0x80;
+			m68k_handle_int(irq_num);
 		}
+		++irq_num;
+		irq_bit <<= 1;
+	} while (events >= irq_bit);
 
 #if 0 /* freakin' pmu is doing weird stuff */
 	if (!oss_present) {
@@ -448,20 +484,23 @@ #endif
 
 irqreturn_t via2_irq(int irq, void *dev_id)
 {
-	int irq_bit, i;
-	unsigned char events, mask;
+	int irq_num;
+	unsigned char irq_bit, events;
 
-	mask = via2[gIER] & 0x7F;
-	if (!(events = via2[gIFR] & mask))
+	events = via2[gIFR] & via2[gIER] & 0x7F;
+	if (!events)
 		return IRQ_NONE;
 
-	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+	irq_num = VIA2_SOURCE_BASE;
+	irq_bit = 1;
+	do {
 		if (events & irq_bit) {
-			via2[gIER] = irq_bit;
 			via2[gIFR] = irq_bit | rbv_clear;
-			m68k_handle_int(VIA2_SOURCE_BASE + i);
-			via2[gIER] = irq_bit | 0x80;
+			m68k_handle_int(irq_num);
 		}
+		++irq_num;
+		irq_bit <<= 1;
+	} while (events >= irq_bit);
 	return IRQ_HANDLED;
 }
 
@@ -472,71 +511,75 @@ irqreturn_t via2_irq(int irq, void *dev_
 
 irqreturn_t via_nubus_irq(int irq, void *dev_id)
 {
-	int irq_bit, i;
-	unsigned char events;
-
-	if (!(events = ~via2[gBufA] & nubus_active))
+	int slot_irq;
+	unsigned char slot_bit, events;
+
+	events = ~via2[gBufA] & 0x7F;
+	if (rbv_present)
+		events &= via2[rSIER];
+	else
+		events &= ~via2[vDirA];
+	if (!events)
 		return IRQ_NONE;
 
-	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);
-			via_irq_enable(NUBUS_SOURCE_BASE + i);
-		}
-	}
+	do {
+		slot_irq = IRQ_NUBUS_F;
+		slot_bit = 0x40;
+		do {
+			if (events & slot_bit) {
+				events &= ~slot_bit;
+				m68k_handle_int(slot_irq);
+			}
+			--slot_irq;
+			slot_bit >>= 1;
+		} while (events);
+
+ 		/* clear the CA1 interrupt and make certain there's no more. */
+		via2[gIFR] = 0x02 | rbv_clear;
+		events = ~via2[gBufA] & 0x7F;
+		if (rbv_present)
+			events &= via2[rSIER];
+		else
+			events &= ~via2[vDirA];
+	} while (events);
 	return IRQ_HANDLED;
 }
 
 void via_irq_enable(int irq) {
 	int irq_src	= IRQ_SRC(irq);
 	int irq_idx	= IRQ_IDX(irq);
-	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
 	printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
-		via1[vIER] = irq_bit | 0x80;
+		via1[vIER] = IER_SET_BIT(irq_idx);
 	} else if (irq_src == 2) {
-		/*
-		 * Set vPCR for SCSI interrupts (but not on RBV)
-		 */
-		if ((irq_idx == 0) && !rbv_present) {
-			if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
-				/* CB2 (IRQ) indep. input, positive edge */
-				/* CA2 (DRQ) indep. input, positive edge */
-				via2[vPCR] = 0x66;
-			} else {
-				/* CB2 (IRQ) indep. input, negative edge */
-				/* CA2 (DRQ) indep. input, negative edge */
-				via2[vPCR] = 0x22;
-			}
-		}
-		via2[gIER] = irq_bit | 0x80;
+		if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
+			via2[gIER] = IER_SET_BIT(irq_idx);
 	} else if (irq_src == 7) {
-		nubus_active |= irq_bit;
-		if (rbv_present) {
-			/* enable the slot interrupt. SIER works like IER. */
+		switch (macintosh_config->via_type) {
+		case MAC_VIA_II:
+			nubus_disabled &= ~(1 << irq_idx);
+			/* Enable the CA1 interrupt when no slot is disabled. */
+			if (!nubus_disabled)
+				via2[gIER] = IER_SET_BIT(1);
+			break;
+		case MAC_VIA_IIci:
+			/* On RBV, enable the slot interrupt.
+			 * SIER works like IER.
+			 */
 			via2[rSIER] = IER_SET_BIT(irq_idx);
-		} else {
-			/* Make sure the bit is an input, to enable the irq */
-			/* But not on PowerBooks, that's ADB... */
+			break;
+		case MAC_VIA_QUADRA:
+			/* Make the port A line an input to enable the slot irq.
+			 * But not on PowerBooks, that's ADB.
+			 */
 			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
-				switch(macintosh_config->ident)
-				{
-					case MAC_MODEL_II:
-					case MAC_MODEL_IIX:
-					case MAC_MODEL_IICX:
-					case MAC_MODEL_SE30:
-						via2[vDirA] &= (~irq_bit | 0xc0);
-						break;
-					default:
-						via2[vDirA] &= ~irq_bit;
-				}
-			}
+			    (macintosh_config->adb_type != MAC_ADB_PB2))
+				via2[vDirA] &= ~(1 << irq_idx);
+			break;
 		}
 	}
 }
@@ -544,29 +587,31 @@ #endif
 void via_irq_disable(int irq) {
 	int irq_src	= IRQ_SRC(irq);
 	int irq_idx	= IRQ_IDX(irq);
-	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
 	printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
-		via1[vIER] = irq_bit;
+		via1[vIER] = IER_CLR_BIT(irq_idx);
 	} else if (irq_src == 2) {
-		via2[gIER] = irq_bit;
+		via2[gIER] = IER_CLR_BIT(irq_idx);
 	} else if (irq_src == 7) {
-		if (rbv_present) {
-			/* disable the slot interrupt.  SIER works like IER. */
+		switch (macintosh_config->via_type) {
+		case MAC_VIA_II:
+			nubus_disabled |= 1 << irq_idx;
+			if (nubus_disabled)
+				via2[gIER] = IER_CLR_BIT(1);
+			break;
+		case MAC_VIA_IIci:
 			via2[rSIER] = IER_CLR_BIT(irq_idx);
-		} else {
-			/* disable the nubus irq by changing dir to output */
-			/* except on PMU */
+			break;
+		case MAC_VIA_QUADRA:
 			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
-				via2[vDirA] |= irq_bit;
-			}
+			    (macintosh_config->adb_type != MAC_ADB_PB2))
+				via2[vDirA] |= 1 << irq_idx;
+			break;
 		}
-		nubus_active &= ~irq_bit;
 	}
 }
 
@@ -580,7 +625,9 @@ void via_irq_clear(int irq) {
 	} else if (irq_src == 2) {
 		via2[gIFR] = irq_bit | rbv_clear;
 	} else if (irq_src == 7) {
-		/* FIXME: hmm.. */
+		/* FIXME: There is no way to clear an individual nubus slot
+		 * IRQ flag, other than getting the device to do it.
+		 */
 	}
 }
 
@@ -600,6 +647,7 @@ int via_irq_pending(int irq)
 	} else if (irq_src == 2) {
 		return via2[gIFR] & irq_bit;
 	} else if (irq_src == 7) {
+		/* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
 		return ~via2[gBufA] & irq_bit;
 	}
 	return 0;
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 272d47e..e341387 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -16,7 +16,6 @@ #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/mc146818rtc.h>	/* For struct rtc_time and ioctls, etc */
-#include <linux/smp_lock.h>
 #include <linux/bcd.h>
 #include <asm/mvme16xhw.h>
 
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 92f873c..476e18e 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -35,35 +35,35 @@ #include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/q40_master.h>
 
-extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern void q40_init_IRQ (void);
+extern irqreturn_t q40_process_int(int level, struct pt_regs *regs);
+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(irq_handler_t handler);
 
-extern unsigned long q40_gettimeoffset (void);
-extern int q40_hwclk (int, struct rtc_time *);
-extern unsigned int q40_get_ss (void);
-extern int q40_set_clock_mmss (unsigned long);
+extern unsigned long q40_gettimeoffset(void);
+extern int q40_hwclk(int, struct rtc_time *);
+extern unsigned int q40_get_ss(void);
+extern int q40_set_clock_mmss(unsigned long);
 static int q40_get_rtc_pll(struct rtc_pll_info *pll);
 static int q40_set_rtc_pll(struct rtc_pll_info *pll);
-extern void q40_reset (void);
+extern void q40_reset(void);
 void q40_halt(void);
 extern void q40_waitbut(void);
-void q40_set_vectors (void);
+void q40_set_vectors(void);
 
-extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/);
 
-extern char m68k_debug_device[];
 static void q40_mem_console_write(struct console *co, const char *b,
-				    unsigned int count);
+				  unsigned int count);
 
 extern int ql_ticks;
 
 static struct console q40_console_driver = {
-	.name =		"debug",
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
+	.name	= "debug",
+	.write	= q40_mem_console_write,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
 };
 
 
@@ -74,150 +74,162 @@ static int _cpleft;
 static void q40_mem_console_write(struct console *co, const char *s,
 				  unsigned int count)
 {
-  char *p=(char *)s;
-
-  if (count<_cpleft)
-    while (count-- >0){
-      *q40_mem_cptr=*p++;
-      q40_mem_cptr+=4;
-      _cpleft--;
-    }
+	const char *p = s;
+
+	if (count < _cpleft) {
+		while (count-- > 0) {
+			*q40_mem_cptr = *p++;
+			q40_mem_cptr += 4;
+			_cpleft--;
+		}
+	}
+}
+
+static int __init q40_debug_setup(char *arg)
+{
+	/* useful for early debugging stages - writes kernel messages into SRAM */
+	if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) {
+		/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+		_cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4;
+		register_console(&q40_console_driver);
+	}
+	return 0;
 }
+
+early_param("debug", q40_debug_setup);
+
 #if 0
 void printq40(char *str)
 {
-  int l=strlen(str);
-  char *p=q40_mem_cptr;
-
-  while (l-- >0 && _cpleft-- >0)
-    {
-      *p=*str++;
-      p+=4;
-    }
-  q40_mem_cptr=p;
+	int l = strlen(str);
+	char *p = q40_mem_cptr;
+
+	while (l-- > 0 && _cpleft-- > 0) {
+		*p = *str++;
+		p += 4;
+	}
+	q40_mem_cptr = p;
 }
 #endif
 
-static int halted=0;
+static int halted;
 
 #ifdef CONFIG_HEARTBEAT
 static void q40_heartbeat(int on)
 {
-  if (halted) return;
+	if (halted)
+		return;
 
-  if (on)
-    Q40_LED_ON();
-  else
-    Q40_LED_OFF();
+	if (on)
+		Q40_LED_ON();
+	else
+		Q40_LED_OFF();
 }
 #endif
 
 void q40_reset(void)
 {
-        halted=1;
-        printk ("\n\n*******************************************\n"
+        halted = 1;
+        printk("\n\n*******************************************\n"
 		"Called q40_reset : press the RESET button!! \n"
 		"*******************************************\n");
 	Q40_LED_ON();
-	while(1) ;
+	while (1)
+		;
 }
 void q40_halt(void)
 {
-        halted=1;
-        printk ("\n\n*******************\n"
-		    "  Called q40_halt\n"
-		    "*******************\n");
+        halted = 1;
+        printk("\n\n*******************\n"
+		   "  Called q40_halt\n"
+		   "*******************\n");
 	Q40_LED_ON();
-	while(1) ;
+	while (1)
+		;
 }
 
 static void q40_get_model(char *model)
 {
-    sprintf(model, "Q40");
+	sprintf(model, "Q40");
 }
 
 /* No hardware options on Q40? */
 
 static int q40_get_hardware_list(char *buffer)
 {
-    *buffer = '\0';
-    return 0;
+	*buffer = '\0';
+	return 0;
 }
 
-static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0};
+static unsigned int serports[] =
+{
+	0x3f8,0x2f8,0x3e8,0x2e8,0
+};
 void q40_disable_irqs(void)
 {
-  unsigned i,j;
+	unsigned i, j;
 
-  j=0;
-  while((i=serports[j++])) outb(0,i+UART_IER);
-  master_outb(0,EXT_ENABLE_REG);
-  master_outb(0,KEY_IRQ_ENABLE_REG);
+	j = 0;
+	while ((i = serports[j++]))
+		outb(0, i + UART_IER);
+	master_outb(0, EXT_ENABLE_REG);
+	master_outb(0, KEY_IRQ_ENABLE_REG);
 }
 
 void __init config_q40(void)
 {
-    mach_sched_init      = q40_sched_init;
+	mach_sched_init = q40_sched_init;
 
-    mach_init_IRQ        = q40_init_IRQ;
-    mach_gettimeoffset   = q40_gettimeoffset;
-    mach_hwclk           = q40_hwclk;
-    mach_get_ss          = q40_get_ss;
-    mach_get_rtc_pll     = q40_get_rtc_pll;
-    mach_set_rtc_pll     = q40_set_rtc_pll;
-    mach_set_clock_mmss	 = q40_set_clock_mmss;
+	mach_init_IRQ = q40_init_IRQ;
+	mach_gettimeoffset = q40_gettimeoffset;
+	mach_hwclk = q40_hwclk;
+	mach_get_ss = q40_get_ss;
+	mach_get_rtc_pll = q40_get_rtc_pll;
+	mach_set_rtc_pll = q40_set_rtc_pll;
+	mach_set_clock_mmss = q40_set_clock_mmss;
 
-    mach_reset		 = q40_reset;
-    mach_get_model       = q40_get_model;
-    mach_get_hardware_list = q40_get_hardware_list;
+	mach_reset = q40_reset;
+	mach_get_model = q40_get_model;
+	mach_get_hardware_list = q40_get_hardware_list;
 
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
-    mach_beep            = q40_mksound;
+	mach_beep = q40_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
-    mach_heartbeat = q40_heartbeat;
+	mach_heartbeat = q40_heartbeat;
 #endif
-    mach_halt = q40_halt;
-
-    /* disable a few things that SMSQ might have left enabled */
-    q40_disable_irqs();
-
-    /* no DMA at all, but ide-scsi requires it.. make sure
-     * all physical RAM fits into the boundary - otherwise
-     * allocator may play costly and useless tricks */
-    mach_max_dma_address = 1024*1024*1024;
-
-    /* useful for early debugging stages - writes kernel messages into SRAM */
-    if (!strncmp( m68k_debug_device,"mem",3 ))
-      {
-	/*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
-	_cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
-	q40_console_driver.write = q40_mem_console_write;
-	register_console(&q40_console_driver);
-      }
+	mach_halt = q40_halt;
+
+	/* disable a few things that SMSQ might have left enabled */
+	q40_disable_irqs();
+
+	/* no DMA at all, but ide-scsi requires it.. make sure
+	 * all physical RAM fits into the boundary - otherwise
+	 * allocator may play costly and useless tricks */
+	mach_max_dma_address = 1024*1024*1024;
 }
 
 
 int q40_parse_bootinfo(const struct bi_record *rec)
 {
-  return 1;
+	return 1;
 }
 
 
-static inline unsigned char bcd2bin (unsigned char b)
+static inline unsigned char bcd2bin(unsigned char b)
 {
-	return ((b>>4)*10 + (b&15));
+	return (b >> 4) * 10 + (b & 15);
 }
 
-static inline unsigned char bin2bcd (unsigned char b)
+static inline unsigned char bin2bcd(unsigned char b)
 {
-	return (((b/10)*16) + (b%10));
+	return (b / 10) * 16 + (b % 10);
 }
 
 
-unsigned long q40_gettimeoffset (void)
+unsigned long q40_gettimeoffset(void)
 {
-    return 5000*(ql_ticks!=0);
+	return 5000 * (ql_ticks != 0);
 }
 
 
@@ -238,9 +250,9 @@ unsigned long q40_gettimeoffset (void)
 
 int q40_hwclk(int op, struct rtc_time *t)
 {
-        if (op)
-	{	/* Write.... */
-	        Q40_RTC_CTRL |= Q40_RTC_WRITE;
+	if (op) {
+		/* Write.... */
+		Q40_RTC_CTRL |= Q40_RTC_WRITE;
 
 		Q40_RTC_SECS = bin2bcd(t->tm_sec);
 		Q40_RTC_MINS = bin2bcd(t->tm_min);
@@ -251,25 +263,23 @@ int q40_hwclk(int op, struct rtc_time *t
 		if (t->tm_wday >= 0)
 			Q40_RTC_DOW = bin2bcd(t->tm_wday+1);
 
-	        Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
-	}
-	else
-	{	/* Read....  */
-	  Q40_RTC_CTRL |= Q40_RTC_READ;
-
-	  t->tm_year = bcd2bin (Q40_RTC_YEAR);
-	  t->tm_mon  = bcd2bin (Q40_RTC_MNTH)-1;
-	  t->tm_mday = bcd2bin (Q40_RTC_DATE);
-	  t->tm_hour = bcd2bin (Q40_RTC_HOUR);
-	  t->tm_min  = bcd2bin (Q40_RTC_MINS);
-	  t->tm_sec  = bcd2bin (Q40_RTC_SECS);
-
-	  Q40_RTC_CTRL &= ~(Q40_RTC_READ);
-
-	  if (t->tm_year < 70)
-	    t->tm_year += 100;
-	  t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
-
+		Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+	} else {
+		/* Read....  */
+		Q40_RTC_CTRL |= Q40_RTC_READ;
+
+		t->tm_year = bcd2bin (Q40_RTC_YEAR);
+		t->tm_mon  = bcd2bin (Q40_RTC_MNTH)-1;
+		t->tm_mday = bcd2bin (Q40_RTC_DATE);
+		t->tm_hour = bcd2bin (Q40_RTC_HOUR);
+		t->tm_min  = bcd2bin (Q40_RTC_MINS);
+		t->tm_sec  = bcd2bin (Q40_RTC_SECS);
+
+		Q40_RTC_CTRL &= ~(Q40_RTC_READ);
+
+		if (t->tm_year < 70)
+			t->tm_year += 100;
+		t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
 	}
 
 	return 0;
@@ -285,29 +295,25 @@ unsigned int q40_get_ss(void)
  * clock is out by > 30 minutes.  Logic lifted from atari code.
  */
 
-int q40_set_clock_mmss (unsigned long nowtime)
+int q40_set_clock_mmss(unsigned long nowtime)
 {
 	int retval = 0;
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
 	int rtc_minutes;
 
+	rtc_minutes = bcd2bin(Q40_RTC_MINS);
 
-	rtc_minutes = bcd2bin (Q40_RTC_MINS);
-
-	if ((rtc_minutes < real_minutes
-		? real_minutes - rtc_minutes
-			: rtc_minutes - real_minutes) < 30)
-	{
-	        Q40_RTC_CTRL |= Q40_RTC_WRITE;
+	if ((rtc_minutes < real_minutes ?
+	     real_minutes - rtc_minutes :
+	     rtc_minutes - real_minutes) < 30) {
+		Q40_RTC_CTRL |= Q40_RTC_WRITE;
 		Q40_RTC_MINS = bin2bcd(real_minutes);
 		Q40_RTC_SECS = bin2bcd(real_seconds);
 		Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
-	}
-	else
+	} else
 		retval = -1;
 
-
 	return retval;
 }
 
@@ -318,21 +324,23 @@ #define Q40_RTC_PLL_SIGN (1<<5)
 
 static int q40_get_rtc_pll(struct rtc_pll_info *pll)
 {
-	int tmp=Q40_RTC_CTRL;
+	int tmp = Q40_RTC_CTRL;
+
 	pll->pll_value = tmp & Q40_RTC_PLL_MASK;
 	if (tmp & Q40_RTC_PLL_SIGN)
 		pll->pll_value = -pll->pll_value;
-	pll->pll_max=31;
-	pll->pll_min=-31;
-	pll->pll_posmult=512;
-	pll->pll_negmult=256;
-	pll->pll_clock=125829120;
+	pll->pll_max = 31;
+	pll->pll_min = -31;
+	pll->pll_posmult = 512;
+	pll->pll_negmult = 256;
+	pll->pll_clock = 125829120;
+
 	return 0;
 }
 
 static int q40_set_rtc_pll(struct rtc_pll_info *pll)
 {
-	if (!pll->pll_ctrl){
+	if (!pll->pll_ctrl) {
 		/* the docs are a bit unclear so I am doublesetting */
 		/* RTC_WRITE here ... */
 		int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) |
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 31cc07d..2fb25ae 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -59,7 +59,7 @@ static void q40_irq_shutdown(unsigned in
 
 static struct irq_controller q40_irq_controller = {
 	.name		= "q40",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(q40_irq_controller.lock),
 	.startup	= q40_irq_startup,
 	.shutdown	= q40_irq_shutdown,
 	.enable		= q40_enable_irq,
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index baf74e8..50df34b 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -90,7 +90,7 @@ static void sun3_inthandle(unsigned int 
 
 static struct irq_controller sun3_irq_controller = {
 	.name		= "sun3",
-	.lock		= SPIN_LOCK_UNLOCKED,
+	.lock		= __SPIN_LOCK_UNLOCKED(sun3_irq_controller.lock),
 	.startup	= m68k_irq_startup,
 	.shutdown	= m68k_irq_shutdown,
 	.enable		= sun3_enable_irq,
@@ -103,7 +103,7 @@ void sun3_init_IRQ(void)
 
 	m68k_setup_auto_interrupt(sun3_inthandle);
 	m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
-	m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+	m68k_setup_user_interrupt(VEC_USER, 128, NULL);
 
 	request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
 	request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
index 574cf06..48f8eb7 100644
--- a/arch/m68k/sun3x/prom.c
+++ b/arch/m68k/sun3x/prom.c
@@ -34,100 +34,101 @@ e_vector *sun3x_prom_vbr;
 /* Handle returning to the prom */
 void sun3x_halt(void)
 {
-    unsigned long flags;
+	unsigned long flags;
 
-    /* Disable interrupts while we mess with things */
-    local_irq_save(flags);
+	/* Disable interrupts while we mess with things */
+	local_irq_save(flags);
 
-    /* Restore prom vbr */
-    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+	/* Restore prom vbr */
+	asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
 
-    /* Restore prom NMI clock */
-//    sun3x_disable_intreg(5);
-    sun3_enable_irq(7);
+	/* Restore prom NMI clock */
+//	sun3x_disable_intreg(5);
+	sun3_enable_irq(7);
 
-    /* Let 'er rip */
-    __asm__ volatile ("trap #14" : : );
+	/* Let 'er rip */
+	asm volatile ("trap #14");
 
-    /* Restore everything */
-    sun3_disable_irq(7);
-    sun3_enable_irq(5);
+	/* Restore everything */
+	sun3_disable_irq(7);
+	sun3_enable_irq(5);
 
-    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
-    local_irq_restore(flags);
+	asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+	local_irq_restore(flags);
 }
 
 void sun3x_reboot(void)
 {
-    /* This never returns, don't bother saving things */
-    local_irq_disable();
+	/* This never returns, don't bother saving things */
+	local_irq_disable();
 
-    /* Restore prom vbr */
-    __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+	/* Restore prom vbr */
+	asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
 
-    /* Restore prom NMI clock */
-    sun3_disable_irq(5);
-    sun3_enable_irq(7);
+	/* Restore prom NMI clock */
+	sun3_disable_irq(5);
+	sun3_enable_irq(7);
 
-    /* Let 'er rip */
-    (*romvec->pv_reboot)("vmlinux");
+	/* Let 'er rip */
+	(*romvec->pv_reboot)("vmlinux");
 }
 
-extern char m68k_debug_device[];
-
 static void sun3x_prom_write(struct console *co, const char *s,
                              unsigned int count)
 {
-    while (count--) {
-        if (*s == '\n')
-            sun3x_putchar('\r');
-        sun3x_putchar(*s++);
-    }
+	while (count--) {
+		if (*s == '\n')
+			sun3x_putchar('\r');
+		sun3x_putchar(*s++);
+	}
 }
 
 /* debug console - write-only */
 
 static struct console sun3x_debug = {
-	.name  =	"debug",
-	.write =	sun3x_prom_write,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
+	.name	= "debug",
+	.write	= sun3x_prom_write,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
 };
 
 void sun3x_prom_init(void)
 {
-    /* Read the vector table */
-
-    sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
-    sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
-    sun3x_mayget = *(int (**)(void))  (SUN3X_P_MAYGET);
-    sun3x_mayput = *(int (**)(int))   (SUN3X_P_MAYPUT);
-    sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
-    sun3x_prom_abort = *(e_vector *)  (SUN3X_P_ABORT);
-    romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
-
-    idprom_init();
-
-    if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
-	    printk("Warning: machine reports strange type %02x\n",
-		   idprom->id_machtype);
-	    printk("Pretending it's a 3/80, but very afraid...\n");
-	    idprom->id_machtype = SM_SUN3X | SM_3_80;
-    }
-
-    /* point trap #14 at abort.
-     * XXX this is futile since we restore the vbr first - oops
-     */
-    vectors[VEC_TRAP14] = sun3x_prom_abort;
-
-    /* If debug=prom was specified, start the debug console */
-
-    if (!strcmp(m68k_debug_device, "prom"))
-        register_console(&sun3x_debug);
-
+	/* Read the vector table */
+
+	sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
+	sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
+	sun3x_mayget = *(int (**)(void))  (SUN3X_P_MAYGET);
+	sun3x_mayput = *(int (**)(int))   (SUN3X_P_MAYPUT);
+	sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
+	sun3x_prom_abort = *(e_vector *)  (SUN3X_P_ABORT);
+	romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
+
+	idprom_init();
+
+	if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
+		printk("Warning: machine reports strange type %02x\n",
+			idprom->id_machtype);
+		printk("Pretending it's a 3/80, but very afraid...\n");
+		idprom->id_machtype = SM_SUN3X | SM_3_80;
+	}
+
+	/* point trap #14 at abort.
+	 * XXX this is futile since we restore the vbr first - oops
+	 */
+	vectors[VEC_TRAP14] = sun3x_prom_abort;
+}
 
+static int __init sun3x_debug_setup(char *arg)
+{
+	/* If debug=prom was specified, start the debug console */
+	if (MACH_IS_SUN3X && !strcmp(arg, "prom"))
+		register_console(&sun3x_debug);
+	return 0;
 }
 
+early_param("debug", sun3x_debug_setup);
+
 /* some prom functions to export */
 int prom_getintdefault(int node, char *property, int deflt)
 {
@@ -141,7 +142,6 @@ int prom_getbool (int node, char *prop)
 
 void prom_printf(char *fmt, ...)
 {
-
 }
 
 void prom_halt (void)
@@ -159,7 +159,7 @@ prom_get_idprom(char *idbuf, int num_byt
         int i;
 
 	/* make a copy of the idprom structure */
-	for(i = 0; i < num_bytes; i++)
+	for (i = 0; i < num_bytes; i++)
 		idbuf[i] = ((char *)SUN3X_IDPROM)[i];
 
         return idbuf[0];
diff --git a/arch/m68knommu/kernel/dma.c b/arch/m68knommu/kernel/dma.c
index 14b19c4..0a25874 100644
--- a/arch/m68knommu/kernel/dma.c
+++ b/arch/m68knommu/kernel/dma.c
@@ -8,7 +8,6 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/string.h>
-#include <linux/pci.h>
 #include <asm/io.h>
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index 72d3496..f54b6a3 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -14,7 +14,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
index 3265b2d..48e6b33 100644
--- a/arch/m68knommu/kernel/sys_m68k.c
+++ b/arch/m68knommu/kernel/sys_m68k.c
@@ -10,7 +10,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index c78b143..b7cb048 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -10,7 +10,6 @@ menu "Machine selection"
 
 config ZONE_DMA
 	bool
-	default y
 
 choice
 	prompt "System type"
@@ -165,7 +164,7 @@ config MIPS_COBALT
 	select HW_HAS_PCI
 	select I8259
 	select IRQ_CPU
-	select MIPS_GT64111
+	select PCI_GT64XXX_PCI0
 	select SYS_HAS_CPU_NEVADA
 	select SYS_HAS_EARLY_PRINTK
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -207,7 +206,7 @@ config MIPS_EV64120
 	depends on EXPERIMENTAL
 	select DMA_NONCOHERENT
 	select HW_HAS_PCI
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select SYS_HAS_CPU_R5000
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_64BIT_KERNEL
@@ -245,7 +244,7 @@ config LASAT
 	select DMA_NONCOHERENT
 	select SYS_HAS_EARLY_PRINTK
 	select HW_HAS_PCI
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select MIPS_NILE4
 	select R5000_CPU_SCACHE
 	select SYS_HAS_CPU_R5000
@@ -263,7 +262,7 @@ config MIPS_ATLAS
 	select HW_HAS_PCI
 	select MIPS_BOARDS_GEN
 	select MIPS_BONITO64
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select MIPS_MSC
 	select RM7000_CPU_SCACHE
 	select SWAP_IO_SPACE
@@ -296,7 +295,7 @@ config MIPS_MALTA
 	select MIPS_BOARDS_GEN
 	select MIPS_BONITO64
 	select MIPS_CPU_SCACHE
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select MIPS_MSC
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_MIPS32_R1
@@ -340,7 +339,7 @@ config WR_PPMC
 	select BOOT_ELF32
 	select DMA_NONCOHERENT
 	select HW_HAS_PCI
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_MIPS32_R1
 	select SYS_HAS_CPU_MIPS32_R2
@@ -398,7 +397,7 @@ config MOMENCO_OCELOT
 	select HW_HAS_PCI
 	select IRQ_CPU
 	select IRQ_CPU_RM7K
-	select MIPS_GT64120
+	select PCI_GT64XXX_PCI0
 	select RM7000_CPU_SCACHE
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_RM7000
@@ -501,10 +500,8 @@ config DDB5477
 	  ether port USB, AC97, PCI, etc.
 
 config MACH_VR41XX
-	bool "NEC VR41XX-based machines"
+	bool "NEC VR4100 series based machines"
 	select SYS_HAS_CPU_VR41XX
-	select SYS_SUPPORTS_32BIT_KERNEL
-	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
 	select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config PMC_YOSEMITE
@@ -779,6 +776,7 @@ config TOSHIBA_JMR3927
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select TOSHIBA_BOARDS
+	select GENERIC_HARDIRQS_NO__DO_IRQ
 
 config TOSHIBA_RBTX4927
 	bool "Toshiba TBTX49[23]7 board"
@@ -786,7 +784,6 @@ config TOSHIBA_RBTX4927
 	select HAS_TXX9_SERIAL
 	select HW_HAS_PCI
 	select I8259
-	select ISA
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_TX49XX
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -808,7 +805,6 @@ config TOSHIBA_RBTX4938
 	select HAS_TXX9_SERIAL
 	select HW_HAS_PCI
 	select I8259
-	select ISA
 	select SWAP_IO_SPACE
 	select SYS_HAS_CPU_TX49XX
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -922,6 +918,7 @@ config SYS_HAS_EARLY_PRINTK
 
 config GENERIC_ISA_DMA
 	bool
+	select ZONE_DMA
 
 config I8259
 	bool
@@ -945,6 +942,7 @@ config MIPS_DISABLE_OBSOLETE_IDE
 
 config GENERIC_ISA_DMA_SUPPORT_BROKEN
 	bool
+	select ZONE_DMA
 
 #
 # Endianess selection.  Sufficiently obscure so many users don't know what to
@@ -999,10 +997,7 @@ config DDB5XXX_COMMON
 config MIPS_BOARDS_GEN
 	bool
 
-config MIPS_GT64111
-	bool
-
-config MIPS_GT64120
+config PCI_GT64XXX_PCI0
 	bool
 
 config MIPS_TX3927
@@ -1045,6 +1040,9 @@ config SOC_AU1X00
 	select SYS_SUPPORTS_APM_EMULATION
 	select SYS_SUPPORTS_KGDB
 
+config SERIAL_RM9000
+	bool
+
 config PNX8550
 	bool
 	select SOC_PNX8550
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 92bca6a..f2f742d 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -530,25 +530,29 @@ cflags-$(CONFIG_SGI_IP32)	+= -Iinclude/a
 load-$(CONFIG_SGI_IP32)		+= 0xffffffff80004000
 
 #
-# Sibyte SB1250 SOC
+# Sibyte SB1250/BCM1480 SOC
 #
 # This is a LIB so that it links at the end, and initcalls are later
 # the sequence; but it is built as an object so that modules don't get
 # removed (as happens, even if they have __initcall/module_init)
 #
 core-$(CONFIG_SIBYTE_BCM112X)	+= arch/mips/sibyte/sb1250/
+core-$(CONFIG_SIBYTE_BCM112X)	+= arch/mips/sibyte/common/
 cflags-$(CONFIG_SIBYTE_BCM112X)	+= -Iinclude/asm-mips/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
 
 core-$(CONFIG_SIBYTE_SB1250)	+= arch/mips/sibyte/sb1250/
+core-$(CONFIG_SIBYTE_SB1250)	+= arch/mips/sibyte/common/
 cflags-$(CONFIG_SIBYTE_SB1250)	+= -Iinclude/asm-mips/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
 
 core-$(CONFIG_SIBYTE_BCM1x55)	+= arch/mips/sibyte/bcm1480/
+core-$(CONFIG_SIBYTE_BCM1x55)	+= arch/mips/sibyte/common/
 cflags-$(CONFIG_SIBYTE_BCM1x55)	+= -Iinclude/asm-mips/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
 
 core-$(CONFIG_SIBYTE_BCM1x80)	+= arch/mips/sibyte/bcm1480/
+core-$(CONFIG_SIBYTE_BCM1x80)	+= arch/mips/sibyte/common/
 cflags-$(CONFIG_SIBYTE_BCM1x80)	+= -Iinclude/asm-mips/mach-sibyte \
 			-DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
 
diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c
index 42f0eda..2f0e4c0 100644
--- a/arch/mips/basler/excite/excite_setup.c
+++ b/arch/mips/basler/excite/excite_setup.c
@@ -63,7 +63,7 @@ volatile void __iomem * const ocd_base =
 volatile void __iomem * const titan_base = (void *) (EXCITE_ADDR_TITAN);
 
 /* Protect access to shared GPI registers */
-spinlock_t titan_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(titan_lock);
 int titan_irqflags;
 
 
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index b36dd8f..9565b21 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,8 @@ #
 # Makefile for the Cobalt micro systems family specific parts of the kernel
 #
 
-obj-y	 := irq.o reset.o setup.o
+obj-y	 := irq.o reset.o setup.o buttons.o
 
+obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_EARLY_PRINTK)	+= console.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= mtd.o
diff --git a/arch/mips/cobalt/buttons.c b/arch/mips/cobalt/buttons.c
new file mode 100644
index 0000000..9e14398
--- /dev/null
+++ b/arch/mips/cobalt/buttons.c
@@ -0,0 +1,54 @@
+/*
+ *  Cobalt buttons platform device.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+static struct resource cobalt_buttons_resource __initdata = {
+	.start	= 0x1d000000,
+	.end	= 0x1d000003,
+	.flags	= IORESOURCE_MEM,
+};
+
+static __init int cobalt_add_buttons(void)
+{
+	struct platform_device *pd;
+	int error;
+
+	pd = platform_device_alloc("Cobalt buttons", -1);
+	if (!pd)
+		return -ENOMEM;
+
+	error = platform_device_add_resources(pd, &cobalt_buttons_resource, 1);
+	if (error)
+		goto err_free_device;
+
+	error = platform_device_add(pd);
+	if (error)
+		goto err_free_device;
+
+	return 0;
+
+ err_free_device:
+	platform_device_put(pd);
+	return error;
+}
+device_initcall(cobalt_add_buttons);
diff --git a/arch/mips/cobalt/console.c b/arch/mips/cobalt/console.c
index ca56b41..0485d51 100644
--- a/arch/mips/cobalt/console.c
+++ b/arch/mips/cobalt/console.c
@@ -1,13 +1,11 @@
 /*
  * (C) P. Horton 2006
  */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/console.h>
 #include <linux/serial_reg.h>
+
 #include <asm/addrspace.h>
-#include <asm/mach-cobalt/cobalt.h>
+
+#include <cobalt.h>
 
 void prom_putchar(char c)
 {
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index fe93b84..950ad1e 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -17,7 +17,7 @@ #include <asm/i8259.h>
 #include <asm/irq_cpu.h>
 #include <asm/gt64120.h>
 
-#include <asm/mach-cobalt/cobalt.h>
+#include <cobalt.h>
 
 /*
  * We have two types of interrupts that we handle, ones that come in through
diff --git a/arch/mips/cobalt/pci.c b/arch/mips/cobalt/pci.c
new file mode 100644
index 0000000..d91027f
--- /dev/null
+++ b/arch/mips/cobalt/pci.c
@@ -0,0 +1,47 @@
+/*
+ * Register PCI controller.
+ *
+ * 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) 1996, 1997, 2004, 05 by Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ *
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/gt64120.h>
+
+extern struct pci_ops gt64xxx_pci0_ops;
+
+static struct resource cobalt_mem_resource = {
+	.start	= GT_DEF_PCI0_MEM0_BASE,
+	.end	= GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1,
+	.name	= "PCI memory",
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource cobalt_io_resource = {
+	.start	= 0x1000,
+	.end	= GT_DEF_PCI0_IO_SIZE - 1,
+	.name	= "PCI I/O",
+	.flags	= IORESOURCE_IO,
+};
+
+static struct pci_controller cobalt_pci_controller = {
+	.pci_ops	= &gt64xxx_pci0_ops,
+	.mem_resource	= &cobalt_mem_resource,
+	.io_resource	= &cobalt_io_resource,
+	.io_offset	= 0 - GT_DEF_PCI0_IO_BASE,
+};
+
+static int __init cobalt_pci_init(void)
+{
+	register_pci_controller(&cobalt_pci_controller);
+
+	return 0;
+}
+
+arch_initcall(cobalt_pci_init);
diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c
index 753dfcc..43cca21 100644
--- a/arch/mips/cobalt/reset.c
+++ b/arch/mips/cobalt/reset.c
@@ -8,15 +8,12 @@
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
  */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/cacheflush.h>
+#include <linux/jiffies.h>
+
 #include <asm/io.h>
-#include <asm/processor.h>
 #include <asm/reboot.h>
-#include <asm/system.h>
-#include <asm/mipsregs.h>
-#include <asm/mach-cobalt/cobalt.h>
+
+#include <cobalt.h>
 
 void cobalt_machine_halt(void)
 {
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index 88d34f1..d0dd817 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -19,12 +19,10 @@ #include <linux/serial_core.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/gt64120.h>
 
-#include <asm/mach-cobalt/cobalt.h>
+#include <cobalt.h>
 
 extern void cobalt_machine_restart(char *command);
 extern void cobalt_machine_halt(void);
@@ -63,22 +61,6 @@ void __init plat_timer_setup(struct irqa
 	GT_WRITE(GT_INTRMASK_OFS, GT_INTR_T0EXP_MSK | GT_READ(GT_INTRMASK_OFS));
 }
 
-extern struct pci_ops gt64111_pci_ops;
-
-static struct resource cobalt_mem_resource = {
-	.start	= GT_DEF_PCI0_MEM0_BASE,
-	.end	= GT_DEF_PCI0_MEM0_BASE + GT_DEF_PCI0_MEM0_SIZE - 1,
-	.name	= "PCI memory",
-	.flags	= IORESOURCE_MEM
-};
-
-static struct resource cobalt_io_resource = {
-	.start	= 0x1000,
-	.end	= 0xffff,
-	.name	= "PCI I/O",
-	.flags	= IORESOURCE_IO
-};
-
 /*
  * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
  * keyboard conntroller is never used.
@@ -111,14 +93,6 @@ static struct resource cobalt_reserved_r
 	},
 };
 
-static struct pci_controller cobalt_pci_controller = {
-	.pci_ops	= &gt64111_pci_ops,
-	.mem_resource	= &cobalt_mem_resource,
-	.mem_offset	= 0,
-	.io_resource	= &cobalt_io_resource,
-	.io_offset	= 0 - GT_DEF_PCI0_IO_BASE,
-};
-
 void __init plat_mem_setup(void)
 {
 	static struct uart_port uart;
@@ -146,10 +120,6 @@ void __init plat_mem_setup(void)
 
 	printk("Cobalt board ID: %d\n", cobalt_board_id);
 
-#ifdef CONFIG_PCI
-	register_pci_controller(&cobalt_pci_controller);
-#endif
-
 	if (cobalt_board_id > COBALT_BRD_ID_RAQ1) {
 #ifdef CONFIG_SERIAL_8250
 		uart.line	= 0;
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index 21a0947..068e48e 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:34 2007
+# Linux kernel version: 2.6.21-rc3
+# Thu Mar 15 00:40:40 2007
 #
 CONFIG_MIPS=y
 
@@ -70,7 +70,7 @@ CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_TIME=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_DMA_NONCOHERENT=y
 CONFIG_DMA_NEED_PCI_MAP_STATE=y
 CONFIG_CPU_BIG_ENDIAN=y
@@ -138,12 +138,12 @@ CONFIG_ZONE_DMA_FLAG=1
 # 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
@@ -175,14 +175,15 @@ # CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_SYSFS_DEPRECATED=y
-CONFIG_RELAY=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
+# CONFIG_HOTPLUG is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
@@ -217,11 +218,11 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_AS is not set
 # CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_DEFAULT_IOSCHED="cfq"
 
 #
 # Bus options (PCI, PCMCIA, EISA, ISA, TC)
@@ -233,12 +234,10 @@ CONFIG_MMU=y
 #
 # PCCARD (PCMCIA/CardBus) support
 #
-# CONFIG_PCCARD is not set
 
 #
 # PCI Hotplug Support
 #
-# CONFIG_HOTPLUG_PCI is not set
 
 #
 # Executable file formats
@@ -250,10 +249,7 @@ CONFIG_TRAD_SIGNALS=y
 #
 # Power management options
 #
-CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
+# CONFIG_PM is not set
 
 #
 # Networking
@@ -267,12 +263,7 @@ # CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=y
-# CONFIG_XFRM_SUB_POLICY is not set
-CONFIG_XFRM_MIGRATE=y
-CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -290,19 +281,18 @@ # 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_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 is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_TCP_MD5SIG=y
+# CONFIG_TCP_MD5SIG is not set
 # 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
 
 #
@@ -343,13 +333,7 @@ # 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_SOFTMAC=y
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_IEEE80211 is not set
 
 #
 # Device Drivers
@@ -360,14 +344,12 @@ # 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=y
-CONFIG_PROC_EVENTS=y
+# CONFIG_CONNECTOR is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -396,16 +378,13 @@ # 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=y
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-CONFIG_ATA_OVER_ETH=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # Misc devices
 #
-CONFIG_SGI_IOC4=y
+# CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 
 #
@@ -416,7 +395,7 @@ # CONFIG_IDE is not set
 #
 # SCSI device support
 #
-CONFIG_RAID_ATTRS=y
+# CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
 # CONFIG_SCSI_NETLINK is not set
 
@@ -462,26 +441,13 @@ # 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=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_FIXED_PHY is not set
+# CONFIG_PHYLIB is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
@@ -493,7 +459,27 @@ # Tulip family network device support
 #
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
-# CONFIG_NET_PCI 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_TC35815=y
+# 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
+# CONFIG_SC92031 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -509,20 +495,21 @@ # 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=y
+# CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_CHELSIO_T1 is not set
-CONFIG_CHELSIO_T3=y
+# CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
-CONFIG_NETXEN_NIC=y
+# CONFIG_NETXEN_NIC is not set
 
 #
 # Token Ring devices
@@ -566,10 +553,7 @@ # 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_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
@@ -587,21 +571,13 @@ # 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=y
+# 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=y
+# CONFIG_VT is not set
 CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
@@ -609,7 +585,7 @@ # CONFIG_CYCLADES is not set
 # CONFIG_DIGIEPCA is not set
 # CONFIG_MOXA_INTELLIO is not set
 # CONFIG_MOXA_SMARTIO is not set
-CONFIG_MOXA_SMARTIO_NEW=y
+# CONFIG_MOXA_SMARTIO_NEW is not set
 # CONFIG_ISI is not set
 # CONFIG_SYNCLINKMP is not set
 # CONFIG_SYNCLINK_GT is not set
@@ -629,11 +605,12 @@ #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_TXX9=y
 CONFIG_HAS_TXX9_SERIAL=y
 CONFIG_SERIAL_TXX9_NR_UARTS=6
-# CONFIG_SERIAL_TXX9_CONSOLE is not set
-# CONFIG_SERIAL_TXX9_STDSERIAL is not set
+CONFIG_SERIAL_TXX9_CONSOLE=y
+CONFIG_SERIAL_TXX9_STDSERIAL=y
 # CONFIG_SERIAL_JSM is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_LEGACY_PTYS=y
@@ -685,6 +662,11 @@ # CONFIG_HWMON is not set
 # CONFIG_HWMON_VID is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -697,51 +679,8 @@ # CONFIG_DVB is not set
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
-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_SVGALIB 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_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_S3 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_DUMMY_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
 
 #
 # Sound
@@ -864,7 +803,7 @@ # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=y
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
@@ -889,14 +828,13 @@ CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
 #
 # 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
@@ -944,10 +882,7 @@ # CONFIG_NLS is not set
 #
 # Distributed Lock Manager
 #
-CONFIG_DLM=y
-CONFIG_DLM_TCP=y
-# CONFIG_DLM_SCTP is not set
-# CONFIG_DLM_DEBUG is not set
+# CONFIG_DLM is not set
 
 #
 # Profiling support
@@ -972,65 +907,22 @@ CONFIG_CMDLINE=""
 #
 # 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=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_XCBC=y
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_WP512=y
-CONFIG_CRYPTO_TGR192=y
-CONFIG_CRYPTO_GF128MUL=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_LRW=y
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_FCRYPT=y
-CONFIG_CRYPTO_BLOWFISH=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_TWOFISH_COMMON=y
-CONFIG_CRYPTO_SERPENT=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_CAST5=y
-CONFIG_CRYPTO_CAST6=y
-CONFIG_CRYPTO_TEA=y
-CONFIG_CRYPTO_ARC4=y
-CONFIG_CRYPTO_KHAZAD=y
-CONFIG_CRYPTO_ANUBIS=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_CAMELLIA=y
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO is not set
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=y
+# CONFIG_CRC16 is not set
 CONFIG_CRC32=y
-CONFIG_LIBCRC32C=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
+# CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
deleted file mode 100644
index 3d6c2d7..0000000
--- a/arch/mips/configs/pnx8550-v2pci_defconfig
+++ /dev/null
@@ -1,1540 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:39 2007
-#
-CONFIG_MIPS=y
-
-#
-# Machine selection
-#
-CONFIG_ZONE_DMA=y
-# 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 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_JBS is not set
-# CONFIG_PNX8550_STB810 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_RM 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_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-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_GENERIC_HARDIRQS_NO__DO_IRQ=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_PNX8550=y
-CONFIG_SOC_PNX8550=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# 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_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
-# 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_ZONE_DMA_FLAG=1
-# 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_KEXEC 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_SYSVIPC_SYSCTL=y
-# 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=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED=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
-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 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"
-
-#
-# 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
-
-#
-# Power management options
-#
-CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED 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_XFRM_MIGRATE=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 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=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_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_TCP_MD5SIG=y
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-CONFIG_IPV6=m
-# CONFIG_IPV6_PRIVACY is not set
-CONFIG_IPV6_ROUTER_PREF=y
-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_IPV6_MULTIPLE_TABLES 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_NF_CONNTRACK_ENABLED=m
-CONFIG_NF_CONNTRACK_SUPPORT=y
-# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CT_ACCT=y
-CONFIG_NF_CONNTRACK_MARK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_GRE=m
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SANE=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-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_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=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 is not set
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=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
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-
-#
-# IP: Netfilter Configuration
-#
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_NF_CONNTRACK_PROC_COMPAT=y
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# IPv6: Netfilter Configuration (EXPERIMENTAL)
-#
-CONFIG_NF_CONNTRACK_IPV6=m
-# CONFIG_IP6_NF_QUEUE is not set
-# CONFIG_IP6_NF_IPTABLES 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
-CONFIG_NET_CLS_ROUTE=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 is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI 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=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
-
-#
-# Misc devices
-#
-CONFIG_SGI_IOC4=m
-# CONFIG_TIFM_CORE 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=y
-# 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=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_IT8213=m
-# 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_TC86C001=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 is not set
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=m
-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 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
-CONFIG_SCSI_SCAN_ASYNC=y
-
-#
-# 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_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
-# CONFIG_SCSI_SRP 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_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_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 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_SC92031 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
-# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-CONFIG_CHELSIO_T3=m
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-CONFIG_NETXEN_NIC=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 is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-# CONFIG_PPP_BSDCOMP is not set
-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
-# 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=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=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_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 is not set
-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
-# CONFIG_CYCLADES is not set
-# CONFIG_DIGIEPCA is not set
-# CONFIG_MOXA_INTELLIO is not set
-# CONFIG_MOXA_SMARTIO is not set
-CONFIG_MOXA_SMARTIO_NEW=m
-# 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
-# CONFIG_SX is not set
-# CONFIG_RIO is not set
-# CONFIG_STALDRV is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_PNX8XXX=y
-CONFIG_SERIAL_PNX8XXX_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_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-# 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=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_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_PASEMI 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
-#
-# 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_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 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_PC87427 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
-# CONFIG_SENSORS_W83793 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
-
-#
-# 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=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
-# CONFIG_FB_SVGALIB 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_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_S3 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_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
-
-#
-# HID Devices
-#
-CONFIG_HID=y
-# CONFIG_HID_DEBUG 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_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_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_KARMA is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=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_GTCO 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_MII 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_BERRY_CHARGE 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_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_CLASS is not set
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
-# 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 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 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
-#
-# 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_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=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 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=m
-# 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=m
-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 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 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
-
-#
-# Distributed Lock Manager
-#
-CONFIG_DLM=m
-CONFIG_DLM_TCP=y
-# CONFIG_DLM_SCTP is not set
-# CONFIG_DLM_DEBUG is not set
-
-#
-# 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_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE=""
-CONFIG_SYS_SUPPORTS_KGDB=y
-
-#
-# 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_HASH=m
-CONFIG_CRYPTO_MANAGER=m
-# CONFIG_CRYPTO_HMAC is not set
-CONFIG_CRYPTO_XCBC=m
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_MD4 is not set
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=m
-# 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_GF128MUL=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_LRW=m
-# CONFIG_CRYPTO_DES is not set
-CONFIG_CRYPTO_FCRYPT=m
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_CAST5 is not set
-# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-CONFIG_CRYPTO_ARC4=m
-# 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=m
-CONFIG_CRYPTO_CAMELLIA=m
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-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_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 29e0df9..7d0f217 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -245,7 +245,6 @@ # Bus options (PCI, PCMCIA, EISA, ISA, T
 #
 CONFIG_HW_HAS_PCI=y
 CONFIG_PCI=y
-CONFIG_ISA=y
 CONFIG_MMU=y
 
 #
@@ -573,7 +572,6 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 # CONFIG_PNPACPI is not set
 
 #
@@ -658,7 +656,6 @@ # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 CONFIG_BLK_DEV_TC86C001=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 is not set
@@ -677,11 +674,6 @@ #
 # 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 is not set
@@ -742,37 +734,20 @@ # 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_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=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=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
@@ -833,8 +808,6 @@ #
 # Obsolete Wireless cards support (pre-802.11)
 #
 # CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-# CONFIG_WAVELAN is not set
 
 #
 # Wireless 802.11b ISA/PCI cards support
@@ -920,9 +893,6 @@ # 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
@@ -1072,7 +1042,6 @@ # 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_FRAMEBUFFER_CONSOLE is not set
 
diff --git a/arch/mips/gt64120/wrppmc/pci.c b/arch/mips/gt64120/wrppmc/pci.c
index 2fbe934..0d5289b 100644
--- a/arch/mips/gt64120/wrppmc/pci.c
+++ b/arch/mips/gt64120/wrppmc/pci.c
@@ -13,7 +13,7 @@ #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <asm/gt64120.h>
 
-extern struct pci_ops gt64120_pci_ops;
+extern struct pci_ops gt64xxx_pci0_ops;
 
 static struct resource pci0_io_resource = {
 	.name  = "pci_0 io",
@@ -30,7 +30,7 @@ static struct resource pci0_mem_resource
 };
 
 static struct pci_controller hose_0 = {
-	.pci_ops	= &gt64120_pci_ops,
+	.pci_ops	= &gt64xxx_pci0_ops,
 	.io_resource	= &pci0_io_resource,
 	.mem_resource	= &pci0_mem_resource,
 };
diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c
index aa481b7..5398813 100644
--- a/arch/mips/jmr3927/common/prom.c
+++ b/arch/mips/jmr3927/common/prom.c
@@ -41,16 +41,6 @@ #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]);
@@ -60,6 +50,8 @@ void  __init prom_init_cmdline(void)
 {
 	char *cp;
 	int actr;
+	int prom_argc = fw_arg0;
+	char **prom_argv = (char **) fw_arg1;
 
 	actr = 1; /* Always ignore argv[0] */
 
diff --git a/arch/mips/jmr3927/common/puts.c b/arch/mips/jmr3927/common/puts.c
index 1c1cad9..c611ab4 100644
--- a/arch/mips/jmr3927/common/puts.c
+++ b/arch/mips/jmr3927/common/puts.c
@@ -32,137 +32,29 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/types.h>
-#include <asm/jmr3927/txx927.h>
 #include <asm/jmr3927/tx3927.h>
-#include <asm/jmr3927/jmr3927.h>
 
 #define TIMEOUT       0xffffff
-#define SLOW_DOWN
-
-static const char digits[16] = "0123456789abcdef";
-
-#ifdef SLOW_DOWN
-#define slow_down() { int k; for (k=0; k<10000; k++); }
-#else
-#define slow_down()
-#endif
 
 void
-putch(const unsigned char c)
+prom_putchar(char c)
 {
         int i = 0;
 
         do {
-            slow_down();
             i++;
-            if (i>TIMEOUT) {
+            if (i>TIMEOUT)
                 break;
-            }
         } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS));
 	tx3927_sioptr(1)->tfifo = c;
 	return;
 }
 
-unsigned char getch(void)
-{
-        int i = 0;
-	int dicr;
-	char c;
-
-	/* diable RX int. */
-	dicr = tx3927_sioptr(1)->dicr;
-	tx3927_sioptr(1)->dicr = 0;
-
-        do {
-            slow_down();
-            i++;
-            if (i>TIMEOUT) {
-                break;
-            }
-        } while (tx3927_sioptr(1)->disr & TXx927_SIDISR_UVALID)
-		;
-	c = tx3927_sioptr(1)->rfifo;
-
-	/* clear RX int. status */
-	tx3927_sioptr(1)->disr &= ~TXx927_SIDISR_RDIS;
-	/* enable RX int. */
-	tx3927_sioptr(1)->dicr = dicr;
-
-	return c;
-}
-void
-do_jmr3927_led_set(char n)
-{
-    /* and with current leds */
-    jmr3927_led_and_set(n);
-}
-
 void
-puts(unsigned char *cp)
+puts(const char *cp)
 {
-    int i = 0;
-
-    while (*cp) {
-        do {
-            slow_down();
-            i++;
-            if (i>TIMEOUT) {
-                break;
-            }
-        } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS));
-	tx3927_sioptr(1)->tfifo = *cp++;
-    }
-    putch('\r');
-    putch('\n');
-}
-
-void
-fputs(unsigned char *cp)
-{
-    int i = 0;
-
-    while (*cp) {
-        do {
-             slow_down();
-            i++;
-            if (i>TIMEOUT) {
-                break;
-            }
-        } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS));
-	tx3927_sioptr(1)->tfifo = *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);
+    while (*cp)
+	prom_putchar(*cp++);
+    prom_putchar('\r');
+    prom_putchar('\n');
 }
diff --git a/arch/mips/jmr3927/rbhma3100/Makefile b/arch/mips/jmr3927/rbhma3100/Makefile
index 18fe9a8..8d00ba4 100644
--- a/arch/mips/jmr3927/rbhma3100/Makefile
+++ b/arch/mips/jmr3927/rbhma3100/Makefile
@@ -3,5 +3,4 @@ # Makefile for TOSHIBA JMR-TX3927 board
 #
 
 obj-y	 			+= init.o irq.o setup.o
-obj-$(CONFIG_RUNTIME_DEBUG) 	+= debug.o
 obj-$(CONFIG_KGDB)		+= kgdb_io.o
diff --git a/arch/mips/jmr3927/rbhma3100/init.c b/arch/mips/jmr3927/rbhma3100/init.c
index a55cb45..9169fab 100644
--- a/arch/mips/jmr3927/rbhma3100/init.c
+++ b/arch/mips/jmr3927/rbhma3100/init.c
@@ -28,20 +28,10 @@
  *  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 <asm/mipsregs.h>
 #include <asm/jmr3927/jmr3927.h>
 
-int prom_argc;
-char **prom_argv, **prom_envp;
 extern void  __init prom_init_cmdline(void);
-extern char *prom_getenv(char *envname);
-unsigned long mips_nofpu = 0;
 
 const char *get_system_type(void)
 {
@@ -52,7 +42,7 @@ #endif
 	;
 }
 
-extern void puts(unsigned char *cp);
+extern void puts(const char *cp);
 
 void __init prom_init(void)
 {
@@ -61,10 +51,6 @@ #ifdef CONFIG_TOSHIBA_JMR3927
 	if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0)
 		puts("Warning: TX3927 TLB off\n");
 #endif
-	prom_argc = fw_arg0;
-	prom_argv = (char **) fw_arg1;
-	prom_envp = (char **) fw_arg2;
-
 	mips_machgroup = MACH_GROUP_TOSHIBA;
 
 #ifdef CONFIG_TOSHIBA_JMR3927
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 7d2c203..1187b44 100644
--- a/arch/mips/jmr3927/rbhma3100/irq.c
+++ b/arch/mips/jmr3927/rbhma3100/irq.c
@@ -30,53 +30,21 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include <linux/init.h>
-
-#include <linux/errno.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.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/smp.h>
-#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>
 
-#include <asm/ptrace.h>
 #include <asm/processor.h>
-#include <asm/jmr3927/irq.h>
-#include <asm/debug.h>
 #include <asm/jmr3927/jmr3927.h>
 
 #if JMR3927_IRQ_END > NR_IRQS
 #error JMR3927_IRQ_END > NR_IRQS
 #endif
 
-struct tb_irq_space* tb_irq_spaces;
-
-static int jmr3927_irq_base = -1;
-
-#ifdef CONFIG_PCI
-static int jmr3927_gen_iack(void)
-{
-	/* generate ACK cycle */
-#ifdef __BIG_ENDIAN
-	return (tx3927_pcicptr->iiadp >> 24) & 0xff;
-#else
-	return tx3927_pcicptr->iiadp & 0xff;
-#endif
-}
-#endif
-
 #define irc_dlevel	0
 #define irc_elevel	1
 
@@ -87,89 +55,24 @@ static unsigned char irc_level[TX3927_NU
 	6, 6, 6			/* TMR */
 };
 
-static void jmr3927_irq_disable(unsigned int irq_nr);
-static void jmr3927_irq_enable(unsigned int irq_nr);
-
-static void jmr3927_irq_ack(unsigned int irq)
-{
-	if (irq == JMR3927_IRQ_IRC_TMR0)
-		jmr3927_tmrptr->tisr = 0;       /* ack interrupt */
-
-	jmr3927_irq_disable(irq);
-}
-
-static void jmr3927_irq_end(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-		jmr3927_irq_enable(irq);
-}
-
-static void jmr3927_irq_disable(unsigned int irq_nr)
-{
-	struct tb_irq_space* sp;
-
-	for (sp = tb_irq_spaces; sp; sp = sp->next) {
-		if (sp->start_irqno <= irq_nr &&
-		    irq_nr < sp->start_irqno + sp->nr_irqs) {
-			if (sp->mask_func)
-				sp->mask_func(irq_nr - sp->start_irqno,
-					      sp->space_id);
-			break;
-		}
-	}
-}
-
-static void jmr3927_irq_enable(unsigned int irq_nr)
-{
-	struct tb_irq_space* sp;
-
-	for (sp = tb_irq_spaces; sp; sp = sp->next) {
-		if (sp->start_irqno <= irq_nr &&
-		    irq_nr < sp->start_irqno + sp->nr_irqs) {
-			if (sp->unmask_func)
-				sp->unmask_func(irq_nr - sp->start_irqno,
-						sp->space_id);
-			break;
-		}
-	}
-}
-
 /*
  * CP0_STATUS is a thread's resource (saved/restored on context switch).
- * So disable_irq/enable_irq MUST handle IOC/ISAC/IRC registers.
+ * So disable_irq/enable_irq MUST handle IOC/IRC registers.
  */
-static void mask_irq_isac(int irq_nr, int space_id)
-{
-	/* 0: mask */
-	unsigned char imask =
-		jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR);
-	unsigned int bit  = 1 << irq_nr;
-	jmr3927_isac_reg_out(imask & ~bit, JMR3927_ISAC_INTM_ADDR);
-	/* flush write buffer */
-	(void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR);
-}
-static void unmask_irq_isac(int irq_nr, int space_id)
-{
-	/* 0: mask */
-	unsigned char imask = jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR);
-	unsigned int bit  = 1 << irq_nr;
-	jmr3927_isac_reg_out(imask | bit, JMR3927_ISAC_INTM_ADDR);
-	/* flush write buffer */
-	(void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR);
-}
-
-static void mask_irq_ioc(int irq_nr, int space_id)
+static void mask_irq_ioc(unsigned int irq)
 {
 	/* 0: mask */
+	unsigned int irq_nr = irq - JMR3927_IRQ_IOC;
 	unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR);
 	unsigned int bit = 1 << irq_nr;
 	jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR);
 	/* flush write buffer */
 	(void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR);
 }
-static void unmask_irq_ioc(int irq_nr, int space_id)
+static void unmask_irq_ioc(unsigned int irq)
 {
 	/* 0: mask */
+	unsigned int irq_nr = irq - JMR3927_IRQ_IOC;
 	unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR);
 	unsigned int bit = 1 << irq_nr;
 	jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR);
@@ -177,8 +80,9 @@ static void unmask_irq_ioc(int irq_nr, i
 	(void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR);
 }
 
-static void mask_irq_irc(int irq_nr, int space_id)
+static void mask_irq_irc(unsigned int irq)
 {
+	unsigned int irq_nr = irq - JMR3927_IRQ_IRC;
 	volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2];
 	if (irq_nr & 1)
 		*ilrp = (*ilrp & 0x00ff) | (irc_dlevel << 8);
@@ -191,8 +95,9 @@ static void mask_irq_irc(int irq_nr, int
 	(void)tx3927_ircptr->ssr;
 }
 
-static void unmask_irq_irc(int irq_nr, int space_id)
+static void unmask_irq_irc(unsigned int irq)
 {
+	unsigned int irq_nr = irq - JMR3927_IRQ_IRC;
 	volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2];
 	if (irq_nr & 1)
 		*ilrp = (*ilrp & 0x00ff) | (irc_level[irq_nr] << 8);
@@ -203,98 +108,14 @@ static void unmask_irq_irc(int irq_nr, i
 	tx3927_ircptr->imr = irc_elevel;
 }
 
-struct tb_irq_space jmr3927_isac_irqspace = {
-	.next = NULL,
-	.start_irqno = JMR3927_IRQ_ISAC,
-	nr_irqs : JMR3927_NR_IRQ_ISAC,
-	.mask_func = mask_irq_isac,
-	.unmask_func = unmask_irq_isac,
-	.name = "ISAC",
-	.space_id = 0,
-	can_share : 0
-};
-struct tb_irq_space jmr3927_ioc_irqspace = {
-	.next = NULL,
-	.start_irqno = JMR3927_IRQ_IOC,
-	nr_irqs : JMR3927_NR_IRQ_IOC,
-	.mask_func = mask_irq_ioc,
-	.unmask_func = unmask_irq_ioc,
-	.name = "IOC",
-	.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
-};
-
-
-#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();
-#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(void)
 {
-	struct pt_regs * regs = get_irq_regs();
+	unsigned long cp0_cause = read_c0_cause();
 	int irq;
 
-#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
-	tx_branch_likely_bug_fixup();
-#endif
-	if ((regs->cp0_cause & CAUSEF_IP7) == 0) {
-#if 0
-		jmr3927_spurious();
-#endif
+	if ((cp0_cause & CAUSEF_IP7) == 0)
 		return;
-	}
-	irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f;
+	irq = (cp0_cause >> CAUSEB_IP2) & 0x0f;
 
 	do_IRQ(irq + JMR3927_IRQ_IRC);
 }
@@ -317,35 +138,6 @@ 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)
-{
-	unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR);
-	int i;
-
-	for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) {
-		if (istat & (1 << i)) {
-			irq = JMR3927_IRQ_ISAC + i;
-			do_IRQ(irq);
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-static struct irqaction isac_action = {
-	jmr3927_isac_interrupt, 0, CPU_MASK_NONE, "ISAC", NULL, NULL,
-};
-
-
-static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id)
-{
-	printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq);
-
-	return IRQ_HANDLED;
-}
-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)
 {
 	printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq);
@@ -358,54 +150,19 @@ static struct irqaction pcierr_action = 
 	jmr3927_pcierr_interrupt, 0, CPU_MASK_NONE, "PCI error", NULL, NULL,
 };
 
-int jmr3927_ether1_irq = 0;
-
-void jmr3927_irq_init(u32 irq_base);
+static void __init jmr3927_irq_init(void);
 
 void __init arch_init_irq(void)
 {
-	/* look for io board's presence */
-	int have_isac = jmr3927_have_isac();
-
 	/* Now, interrupt control disabled, */
 	/* all IRC interrupts are masked, */
 	/* all IRC interrupt mode are Low Active. */
 
-	if (have_isac) {
-
-		/* ETHER1 (NE2000 compatible 10M-Ether) parameter setup */
-		/* temporary enable interrupt control */
-		tx3927_ircptr->cer = 1;
-		/* ETHER1 Int. Is High-Active. */
-		if (tx3927_ircptr->ssr & (1 << 0))
-			jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT0;
-#if 0	/* INT3 may be asserted by ether0 (even after reboot...) */
-		else if (tx3927_ircptr->ssr & (1 << 3))
-			jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT3;
-#endif
-		/* disable interrupt control */
-		tx3927_ircptr->cer = 0;
-
-		/* Ether1: High Active */
-		if (jmr3927_ether1_irq) {
-			int ether1_irc = jmr3927_ether1_irq - JMR3927_IRQ_IRC;
-			tx3927_ircptr->cr[ether1_irc / 8] |=
-				TX3927_IRCR_HIGH << ((ether1_irc % 8) * 2);
-		}
-	}
-
 	/* mask all IOC interrupts */
 	jmr3927_ioc_reg_out(0, JMR3927_IOC_INTM_ADDR);
 	/* setup IOC interrupt mode (SOFT:High Active, Others:Low Active) */
 	jmr3927_ioc_reg_out(JMR3927_IOC_INTF_SOFT, JMR3927_IOC_INTP_ADDR);
 
-	if (have_isac) {
-		/* mask all ISAC interrupts */
-		jmr3927_isac_reg_out(0, JMR3927_ISAC_INTM_ADDR);
-		/* setup ISAC interrupt mode (ISAIRQ3,ISAIRQ5:Low Active ???) */
-		jmr3927_isac_reg_out(JMR3927_ISAC_INTF_IRQ3|JMR3927_ISAC_INTF_IRQ5, JMR3927_ISAC_INTP_ADDR);
-	}
-
 	/* clear PCI Soft interrupts */
 	jmr3927_ioc_reg_out(0, JMR3927_IOC_INTS1_ADDR);
 	/* clear PCI Reset interrupts */
@@ -415,21 +172,11 @@ #endif
 	tx3927_ircptr->cer = TX3927_IRCER_ICE;
 	tx3927_ircptr->imr = irc_elevel;
 
-	jmr3927_irq_init(NR_ISA_IRQS);
-
-	/* setup irq space */
-	add_tb_irq_space(&jmr3927_isac_irqspace);
-	add_tb_irq_space(&jmr3927_ioc_irqspace);
-	add_tb_irq_space(&jmr3927_irc_irqspace);
+	jmr3927_irq_init();
 
 	/* setup IOC interrupt 1 (PCI, MODEM) */
 	setup_irq(JMR3927_IRQ_IOCINT, &ioc_action);
 
-	if (have_isac) {
-		setup_irq(JMR3927_IRQ_ISACINT, &isac_action);
-		setup_irq(JMR3927_IRQ_ISAC_ISAER, &isaerr_action);
-	}
-
 #ifdef CONFIG_PCI
 	setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action);
 #endif
@@ -438,21 +185,28 @@ #endif
 	set_c0_status(ST0_IM);	/* IE bit is still 0. */
 }
 
-static struct irq_chip jmr3927_irq_controller = {
-	.name = "jmr3927_irq",
-	.ack = jmr3927_irq_ack,
-	.mask = jmr3927_irq_disable,
-	.mask_ack = jmr3927_irq_ack,
-	.unmask = jmr3927_irq_enable,
-	.end = jmr3927_irq_end,
+static struct irq_chip jmr3927_irq_ioc = {
+	.name = "jmr3927_ioc",
+	.ack = mask_irq_ioc,
+	.mask = mask_irq_ioc,
+	.mask_ack = mask_irq_ioc,
+	.unmask = unmask_irq_ioc,
 };
 
-void jmr3927_irq_init(u32 irq_base)
+static struct irq_chip jmr3927_irq_irc = {
+	.name = "jmr3927_irc",
+	.ack = mask_irq_irc,
+	.mask = mask_irq_irc,
+	.mask_ack = mask_irq_irc,
+	.unmask = unmask_irq_irc,
+};
+
+static void __init jmr3927_irq_init(void)
 {
 	u32 i;
 
-	for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++)
-		set_irq_chip(i, &jmr3927_irq_controller);
-
-	jmr3927_irq_base = irq_base;
+	for (i = JMR3927_IRQ_IRC; i < JMR3927_IRQ_IRC + JMR3927_NR_IRQ_IRC; i++)
+		set_irq_chip_and_handler(i, &jmr3927_irq_irc, handle_level_irq);
+	for (i = JMR3927_IRQ_IOC; i < JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC; i++)
+		set_irq_chip_and_handler(i, &jmr3927_irq_ioc, handle_level_irq);
 }
diff --git a/arch/mips/jmr3927/rbhma3100/kgdb_io.c b/arch/mips/jmr3927/rbhma3100/kgdb_io.c
index 269a42d..2604f2c 100644
--- a/arch/mips/jmr3927/rbhma3100/kgdb_io.c
+++ b/arch/mips/jmr3927/rbhma3100/kgdb_io.c
@@ -31,23 +31,12 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/types.h>
-#include <asm/jmr3927/txx927.h>
-#include <asm/jmr3927/tx3927.h>
 #include <asm/jmr3927/jmr3927.h>
 
 #define TIMEOUT       0xffffff
-#define SLOW_DOWN
-
-static const char digits[16] = "0123456789abcdef";
-
-#ifdef SLOW_DOWN
-#define slow_down() { int k; for (k=0; k<10000; k++); }
-#else
-#define slow_down()
-#endif
 
 static int remoteDebugInitialized = 0;
+static void debugInit(int baud)
 
 int putDebugChar(unsigned char c)
 {
@@ -103,20 +92,8 @@ unsigned char getDebugChar(void)
 	return c;
 }
 
-void debugInit(int baud)
+static void debugInit(int baud)
 {
-	/*
-	volatile unsigned long lcr;
-	volatile unsigned long dicr;
-	volatile unsigned long disr;
-	volatile unsigned long cisr;
-	volatile unsigned long fcr;
-	volatile unsigned long flcr;
-	volatile unsigned long bgr;
-	volatile unsigned long tfifo;
-	volatile unsigned long rfifo;
-	*/
-
 	tx3927_sioptr(0)->lcr = 0x020;
 	tx3927_sioptr(0)->dicr = 0;
 	tx3927_sioptr(0)->disr = 0x4100;
@@ -125,31 +102,4 @@ void debugInit(int baud)
 	tx3927_sioptr(0)->flcr = 0x02;
 	tx3927_sioptr(0)->bgr = ((JMR3927_BASE_BAUD + baud / 2) / baud) |
 		TXx927_SIBGR_BCLK_T0;
-#if 0
-	/*
-	 * Reset the UART.
-	 */
-	tx3927_sioptr(0)->fcr = TXx927_SIFCR_SWRST;
-	while (tx3927_sioptr(0)->fcr & TXx927_SIFCR_SWRST)
-		;
-
-	/*
-	 * and set the speed of the serial port
-	 * (currently hardwired to 9600 8N1
-	 */
-
-	tx3927_sioptr(0)->lcr = TXx927_SILCR_UMODE_8BIT |
-		TXx927_SILCR_USBL_1BIT |
-		TXx927_SILCR_SCS_IMCLK_BG;
-	tx3927_sioptr(0)->bgr =
-		((JMR3927_BASE_BAUD + baud / 2) / baud) |
-		TXx927_SIBGR_BCLK_T0;
-
-	/* HW RTS/CTS control */
-	if (ser->flags & ASYNC_HAVE_CTS_LINE)
-		tx3927_sioptr(0)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES |
-			TXx927_SIFLCR_RTSTL_MAX /* 15 */;
-	/* Enable RX/TX */
-	tx3927_sioptr(0)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE);
-#endif
 }
diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c
index fc523bd..d1ef289 100644
--- a/arch/mips/jmr3927/rbhma3100/setup.c
+++ b/arch/mips/jmr3927/rbhma3100/setup.c
@@ -54,87 +54,18 @@ #endif
 
 #include <asm/addrspace.h>
 #include <asm/time.h>
-#include <asm/bcache.h>
-#include <asm/irq.h>
 #include <asm/reboot.h>
-#include <asm/gdb-stub.h>
 #include <asm/jmr3927/jmr3927.h>
 #include <asm/mipsregs.h>
-#include <asm/traps.h>
 
-extern void puts(unsigned char *cp);
+extern void puts(const char *cp);
 
 /* Tick Timer divider */
 #define JMR3927_TIMER_CCD	0	/* 1/2 */
 #define JMR3927_TIMER_CLK	(JMR3927_IMCLK / (2 << JMR3927_TIMER_CCD))
 
-unsigned char led_state = 0xf;
-
-struct {
-    struct resource ram0;
-    struct resource ram1;
-    struct resource pcimem;
-    struct resource iob;
-    struct resource ioc;
-    struct resource pciio;
-    struct resource jmy1394;
-    struct resource rom1;
-    struct resource rom0;
-    struct resource sio0;
-    struct resource sio1;
-} jmr3927_resources = {
-	{
-		.start	= 0,
-		.end	= 0x01FFFFFF,
-		.name	= "RAM0",
-		.flags = IORESOURCE_MEM
-	}, {
-		.start	= 0x02000000,
-		.end	= 0x03FFFFFF,
-		.name	= "RAM1",
-		.flags = IORESOURCE_MEM
-	}, {
-		.start	= 0x08000000,
-		.end	= 0x07FFFFFF,
-		.name	= "PCIMEM",
-		.flags = IORESOURCE_MEM
-	}, {
-		.start	= 0x10000000,
-		.end	= 0x13FFFFFF,
-		.name	= "IOB"
-	}, {
-		.start	= 0x14000000,
-		.end	= 0x14FFFFFF,
-		.name	= "IOC"
-	}, {
-		.start	= 0x15000000,
-		.end	= 0x15FFFFFF,
-		.name	= "PCIIO"
-	}, {
-		.start	= 0x1D000000,
-		.end	= 0x1D3FFFFF,
-		.name	= "JMY1394"
-	}, {
-		.start	= 0x1E000000,
-		.end	= 0x1E3FFFFF,
-		.name	= "ROM1"
-	}, {
-		.start	= 0x1FC00000,
-		.end	= 0x1FFFFFFF,
-		.name	= "ROM0"
-	}, {
-		.start	= 0xFFFEF300,
-		.end	= 0xFFFEF3FF,
-		.name	= "SIO0"
-	}, {
-		.start	= 0xFFFEF400,
-		.end	= 0xFFFEF4FF,
-		.name	= "SIO1"
-	},
-};
-
 /* don't enable - see errata */
-int jmr3927_ccfg_toeon = 0;
+static int jmr3927_ccfg_toeon;
 
 static inline void do_reset(void)
 {
@@ -173,9 +104,15 @@ static cycle_t jmr3927_hpt_read(void)
 	return jiffies * (JMR3927_TIMER_CLK / HZ) + jmr3927_tmrptr->trr;
 }
 
+static void jmr3927_timer_ack(void)
+{
+	jmr3927_tmrptr->tisr = 0;       /* ack interrupt */
+}
+
 static void __init jmr3927_time_init(void)
 {
 	clocksource_mips.read = jmr3927_hpt_read;
+	mips_timer_ack = jmr3927_timer_ack;
 	mips_hpt_frequency = JMR3927_TIMER_CLK;
 }
 
@@ -190,9 +127,6 @@ void __init plat_timer_setup(struct irqa
 	setup_irq(JMR3927_IRQ_TICK, irq);
 }
 
-#define USECS_PER_JIFFY (1000000/HZ)
-
-//#undef DO_WRITE_THROUGH
 #define DO_WRITE_THROUGH
 #define DO_ENABLE_CACHE
 
@@ -224,12 +158,6 @@ void __init plat_mem_setup(void)
 	/* Reboot on panic */
 	panic_timeout = 180;
 
-	{
-		unsigned int conf;
-		conf = read_c0_conf();
-	}
-
-#if 1
 	/* cache setup */
 	{
 		unsigned int conf;
@@ -256,16 +184,14 @@ #endif
 		write_c0_conf(conf);
 		write_c0_cache(0);
 	}
-#endif
 
 	/* initialize board */
 	jmr3927_board_init();
 
 	argptr = prom_getcmdline();
 
-	if ((argptr = strstr(argptr, "toeon")) != NULL) {
-			jmr3927_ccfg_toeon = 1;
-	}
+	if ((argptr = strstr(argptr, "toeon")) != NULL)
+		jmr3927_ccfg_toeon = 1;
 	argptr = prom_getcmdline();
 	if ((argptr = strstr(argptr, "ip=")) == NULL) {
 		argptr = prom_getcmdline();
@@ -281,7 +207,7 @@ #ifdef CONFIG_SERIAL_TXX9
 			memset(&req, 0, sizeof(req));
 			req.line = i;
 			req.iotype = UPIO_MEM;
-			req.membase = (char *)TX3927_SIO_REG(i);
+			req.membase = (unsigned char __iomem *)TX3927_SIO_REG(i);
 			req.mapbase = TX3927_SIO_REG(i);
 			req.irq = i == 0 ?
 				JMR3927_IRQ_IRC_SIO0 : JMR3927_IRQ_IRC_SIO1;
@@ -303,65 +229,33 @@ #endif
 
 static void tx3927_setup(void);
 
-#ifdef CONFIG_PCI
-unsigned long mips_pci_io_base;
-unsigned long mips_pci_io_size;
-unsigned long mips_pci_mem_base;
-unsigned long mips_pci_mem_size;
-/* for legacy I/O, PCI I/O PCI Bus address must be 0 */
-unsigned long mips_pci_io_pciaddr = 0;
-#endif
-
 static void __init jmr3927_board_init(void)
 {
-	char *argptr;
-
-#ifdef CONFIG_PCI
-	mips_pci_io_base = JMR3927_PCIIO;
-	mips_pci_io_size = JMR3927_PCIIO_SIZE;
-	mips_pci_mem_base = JMR3927_PCIMEM;
-	mips_pci_mem_size = JMR3927_PCIMEM_SIZE;
-#endif
-
 	tx3927_setup();
 
-	if (jmr3927_have_isac()) {
-
-#ifdef CONFIG_FB_E1355
-		argptr = prom_getcmdline();
-		if ((argptr = strstr(argptr, "video=")) == NULL) {
-			argptr = prom_getcmdline();
-			strcat(argptr, " video=e1355fb:crt16h");
-		}
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDE
-		/* overrides PCI-IDE */
-#endif
-	}
-
 	/* SIO0 DTR on */
 	jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR);
 
 	jmr3927_led_set(0);
 
-
-	if (jmr3927_have_isac())
-		jmr3927_io_led_set(0);
 	printk("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n",
 	       jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK,
 	       jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK,
 	       jmr3927_dipsw1(), jmr3927_dipsw2(),
 	       jmr3927_dipsw3(), jmr3927_dipsw4());
-	if (jmr3927_have_isac())
-		printk("JMI-3927IO2 --- ISAC(Rev %d) DIPSW:%01x\n",
-		       jmr3927_isac_reg_in(JMR3927_ISAC_REV_ADDR) & JMR3927_REV_MASK,
-		       jmr3927_io_dipsw());
 }
 
-void __init tx3927_setup(void)
+static void __init tx3927_setup(void)
 {
 	int i;
+#ifdef CONFIG_PCI
+	unsigned long mips_pci_io_base = JMR3927_PCIIO;
+	unsigned long mips_pci_io_size = JMR3927_PCIIO_SIZE;
+	unsigned long mips_pci_mem_base = JMR3927_PCIMEM;
+	unsigned long mips_pci_mem_size = JMR3927_PCIMEM_SIZE;
+	/* for legacy I/O, PCI I/O PCI Bus address must be 0 */
+	unsigned long mips_pci_io_pciaddr = 0;
+#endif
 
 	/* SDRAMC are configured by PROM */
 
@@ -475,10 +369,8 @@ #endif
 		tx3927_pcicptr->mbas = ~(mips_pci_mem_size - 1);
 		tx3927_pcicptr->mba = 0;
 		tx3927_pcicptr->tlbmma = 0;
-#ifndef JMR3927_INIT_INDIRECT_PCI
 		/* Enable Direct mapping Address Space Decoder */
 		tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE;
-#endif
 
 		/* Clear All Local Bus Status */
 		tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
@@ -491,22 +383,15 @@ #endif
 
 		/* PCIC Int => IRC IRQ10 */
 		tx3927_pcicptr->il = TX3927_IR_PCI;
-#if 1
 		/* Target Control (per errata) */
 		tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E;
-#endif
 
 		/* Enable Bus Arbiter */
-#if 0
-		tx3927_pcicptr->req_trace = 0x73737373;
-#endif
 		tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN;
 
 		tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER |
 			PCI_COMMAND_MEMORY |
-#if 1
 			PCI_COMMAND_IO |
-#endif
 			PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
 	}
 #endif /* CONFIG_PCI */
@@ -555,8 +440,6 @@ static int __init jmr3927_rtc_init(void)
 		.flags	= IORESOURCE_MEM,
 	};
 	struct platform_device *dev;
-	if (!jmr3927_have_nvram())
-		return -ENODEV;
 	dev = platform_device_register_simple("ds1742", -1, &res, 1);
 	return IS_ERR(dev) ? PTR_ERR(dev) : 0;
 }
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 222de46..761a779 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -102,7 +102,6 @@ void output_thread_info_defines(void)
 	offset("#define TI_ADDR_LIMIT      ", struct thread_info, addr_limit);
 	offset("#define TI_RESTART_BLOCK   ", struct thread_info, restart_block);
 	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);
 	linefeed;
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 304efdc..4fa54b2 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -33,8 +33,3 @@ void __init setup_early_printk(void)
 {
 	register_console(&early_console);
 }
-
-void __init disable_early_printk(void)
-{
-	unregister_console(&early_console);
-}
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index 9c79703..2345160 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -328,8 +328,8 @@ void __init init_i8259_irqs (void)
 {
 	int i;
 
-	request_resource(&ioport_resource, &pic1_io_resource);
-	request_resource(&ioport_resource, &pic2_io_resource);
+	insert_resource(&ioport_resource, &pic1_io_resource);
+	insert_resource(&ioport_resource, &pic2_io_resource);
 
 	init_8259A(0);
 
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 3cc25c0..403d96f 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -31,7 +31,6 @@ #include <linux/slab.h>
 #include <linux/shm.h>
 #include <linux/personality.h>
 #include <linux/elfcore.h>
-#include <linux/smp_lock.h>
 
 #include <asm/mipsregs.h>
 #include <asm/namei.h>
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index e286382..30f9eb0 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -9,7 +9,6 @@ #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sockios.h>
 #include <linux/syscalls.h>
 #include <linux/tty.h>
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 2132485..6980deb 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -10,7 +10,6 @@ #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/ptrace.h>
 #include <linux/resource.h>
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 29eadd4..c658001 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -17,6 +17,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/unistd.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -198,7 +199,6 @@ void sp_work_handle_request(void)
 	int cmd;
 
 	char *vcwd;
-	mm_segment_t old_fs;
 	int size;
 
 	ret.retval = -1;
@@ -241,8 +241,6 @@ void sp_work_handle_request(void)
  		if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv,
  		                             (int)&tz, 0,0)) == 0)
 		ret.retval = tv.tv_sec;
-
-		ret.errno = errno;
 		break;
 
  	case MTSP_SYSCALL_EXIT:
@@ -279,7 +277,6 @@ void sp_work_handle_request(void)
 		if (cmd >= 0) {
 			ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1,
 			                        generic.arg2, generic.arg3);
-			ret.errno = errno;
 		} else
  			printk(KERN_WARNING
 			       "KSPD: Unknown SP syscall number %d\n", sc.cmd);
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 201ae19..b5a7b46 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -22,7 +22,6 @@ #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/audit.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
 #include <linux/signal.h>
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index e6e3047..bfc8ca1 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -289,7 +289,7 @@ unsigned int rtlx_write_poll(int index)
 	return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
 }
 
-ssize_t rtlx_read(int index, void __user *buff, size_t count, int user)
+ssize_t rtlx_read(int index, void __user *buff, size_t count)
 {
 	size_t lx_write, fl = 0L;
 	struct rtlx_channel *lx;
@@ -331,9 +331,10 @@ out:
 	return count;
 }
 
-ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user)
+ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
 {
 	struct rtlx_channel *rt;
+	unsigned long failed;
 	size_t rt_read;
 	size_t fl;
 
@@ -363,7 +364,7 @@ ssize_t rtlx_write(int index, const void
 	}
 
 out:
-	count -= cailed;
+	count -= failed;
 
 	smp_wmb();
 	rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 07d6730..2a08ce4 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -12,7 +12,6 @@ #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/personality.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index b9a0144..003f815 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -12,7 +12,6 @@ #include <linux/compat.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/syscalls.h>
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index a9202fa..4cf9ff2 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -19,7 +19,6 @@ #include <linux/cache.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index a586aba..ebd9db8 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -31,8 +31,7 @@ static void save_raw_context_stack(struc
 	}
 }
 
-static void save_context_stack(struct stack_trace *trace,
-	struct task_struct *task, struct pt_regs *regs)
+static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)
 {
 	unsigned long sp = regs->regs[29];
 #ifdef CONFIG_KALLSYMS
@@ -41,7 +40,7 @@ #ifdef CONFIG_KALLSYMS
 
 	if (raw_show_trace || !__kernel_text_address(pc)) {
 		unsigned long stack_page =
-			(unsigned long)task_stack_page(task);
+			(unsigned long)task_stack_page(current);
 		if (stack_page && sp >= stack_page &&
 		    sp <= stack_page + THREAD_SIZE - 32)
 			save_raw_context_stack(trace, sp);
@@ -54,7 +53,7 @@ #ifdef CONFIG_KALLSYMS
 			trace->entries[trace->nr_entries++] = pc;
 		if (trace->nr_entries >= trace->max_entries)
 			break;
-		pc = unwind_stack(task, &sp, pc, &ra);
+		pc = unwind_stack(current, &sp, pc, &ra);
 	} while (pc);
 #else
 	save_raw_context_stack(trace, sp);
@@ -64,22 +63,13 @@ #endif
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
  */
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
 	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);
+	prepare_frametrace(regs);
+	save_context_stack(trace, regs);
 }
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e..9dd5a2d 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -13,7 +13,6 @@ #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/mman.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 493cb29..ff45a4b 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -16,7 +16,6 @@ #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/kallsyms.h>
 #include <linux/bootmem.h>
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 24b7b05..a7d49ae 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -76,7 +76,6 @@ #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 
 #include <asm/asm.h>
 #include <asm/branch.h>
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index c76b793..043f637 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -119,7 +119,7 @@ #if defined(CONFIG_BLK_DEV_INITRD)
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
-  . = ALIGN(32);
+  . = ALIGN(_PAGE_SIZE);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/mips/lib/iomap.c b/arch/mips/lib/iomap.c
index d51d5cb..e3acb2d 100644
--- a/arch/mips/lib/iomap.c
+++ b/arch/mips/lib/iomap.c
@@ -6,7 +6,6 @@
  * (C) Copyright 2007 MIPS Technologies, Inc.
  *     written by Ralf Baechle <ralf@linux-mips.org>
  */
-#include <linux/pci.h>
 #include <linux/module.h>
 #include <asm/io.h>
 
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index 8079f3d..ea6ba72 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -2,7 +2,6 @@ #include <linux/compiler.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
diff --git a/arch/mips/mips-boards/generic/display.c b/arch/mips/mips-boards/generic/display.c
index f653946..548dbe5 100644
--- a/arch/mips/mips-boards/generic/display.c
+++ b/arch/mips/mips-boards/generic/display.c
@@ -24,16 +24,16 @@ #include <asm/mips-boards/generic.h>
 
 void mips_display_message(const char *str)
 {
-	static volatile unsigned int *display = NULL;
+	static unsigned int __iomem *display = NULL;
 	int i;
 
 	if (unlikely(display == NULL))
-		display = (volatile unsigned int *)ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int));
+		display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int));
 
 	for (i = 0; i <= 14; i=i+2) {
 	         if (*str)
-		         display[i] = *str++;
+		         writel(*str++, display + i);
 		 else
-		         display[i] = ' ';
+		         writel(' ', display + i);
 	}
 }
diff --git a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c
index 3192a14..f98d60f 100644
--- a/arch/mips/mips-boards/generic/pci.c
+++ b/arch/mips/mips-boards/generic/pci.c
@@ -65,7 +65,7 @@ static struct resource msc_io_resource =
 };
 
 extern struct pci_ops bonito64_pci_ops;
-extern struct pci_ops gt64120_pci_ops;
+extern struct pci_ops gt64xxx_pci0_ops;
 extern struct pci_ops msc_pci_ops;
 
 static struct pci_controller bonito64_controller = {
@@ -76,7 +76,7 @@ static struct pci_controller bonito64_co
 };
 
 static struct pci_controller gt64120_controller = {
-	.pci_ops	= &gt64120_pci_ops,
+	.pci_ops	= &gt64xxx_pci0_ops,
 	.io_resource	= &gt64120_io_resource,
 	.mem_resource	= &gt64120_mem_resource,
 };
diff --git a/arch/mips/mips-boards/generic/reset.c b/arch/mips/mips-boards/generic/reset.c
index 0996ba3..7a1bb51 100644
--- a/arch/mips/mips-boards/generic/reset.c
+++ b/arch/mips/mips-boards/generic/reset.c
@@ -39,24 +39,24 @@ #endif
 
 static void mips_machine_restart(char *command)
 {
-        volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int));
+	unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int));
 
-	*softres_reg = GORESET;
+	writew(GORESET, softres_reg);
 }
 
 static void mips_machine_halt(void)
 {
-        volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int));
+        unsigned int __iomem *softres_reg = ioremap(SOFTRES_REG, sizeof(unsigned int));
 
-	*softres_reg = GORESET;
+	writew(GORESET, softres_reg);
 }
 
 #if defined(CONFIG_MIPS_ATLAS)
 static void atlas_machine_power_off(void)
 {
-        volatile unsigned int *psustby_reg = (unsigned int *)ioremap(ATLAS_PSUSTBY_REG, sizeof(unsigned int));
+	unsigned int __iomem *psustby_reg = ioremap(ATLAS_PSUSTBY_REG, sizeof(unsigned int));
 
-	*psustby_reg = ATLAS_GOSTBY;
+	writew(ATLAS_GOSTBY, psustby_reg);
 }
 #endif
 
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 3c206bb..83d7602 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -42,8 +42,6 @@ #include <asm/mips-boards/generic.h>
 #include <asm/mips-boards/msc01_pci.h>
 #include <asm/msc01_ic.h>
 
-extern void mips_timer_interrupt(void);
-
 static DEFINE_SPINLOCK(mips_irq_lock);
 
 static inline int mips_pcibios_iack(void)
@@ -85,7 +83,7 @@ static inline int mips_pcibios_iack(void
 		dummy = BONITO_PCIMAP_CFG;
 		iob();    /* sync */
 
-		irq = *(volatile u32 *)(_pcictrl_bonito_pcicfg);
+		irq = readl((u32 *)_pcictrl_bonito_pcicfg);
 		iob();    /* sync */
 		irq &= 0xff;
 		BONITO_PCIMAP_CFG = 0;
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
index 56ea766..7873932 100644
--- a/arch/mips/mips-boards/malta/malta_setup.c
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -145,7 +145,8 @@ #endif
 #ifdef CONFIG_BLK_DEV_IDE
 	/* Check PCI clock */
 	{
-		int jmpr = (*((volatile unsigned int *)ioremap(MALTA_JMPRS_REG, sizeof(unsigned int))) >> 2) & 0x07;
+		unsigned int __iomem *jmpr_p = (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
+		int jmpr = (readw(jmpr_p) >> 2) & 0x07;
 		static const int pciclocks[] __initdata = {
 			33, 20, 25, 30, 12, 16, 37, 10
 		};
@@ -179,7 +180,6 @@ #if defined(CONFIG_VGA_CONSOLE)
 	};
 #endif
 #endif
-
 	mips_reboot_setup();
 
 	board_time_init = mips_time_init;
diff --git a/arch/mips/mips-boards/sim/Makefile b/arch/mips/mips-boards/sim/Makefile
index 6aeebc9..dc0bfda 100644
--- a/arch/mips/mips-boards/sim/Makefile
+++ b/arch/mips/mips-boards/sim/Makefile
@@ -17,7 +17,8 @@ # with this program; if not, write to th
 # 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 #
 
-obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o
+obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \
+	 sim_cmdline.o
 
 obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
 obj-$(CONFIG_SMP) += sim_smp.o
diff --git a/arch/mips/mips-boards/sim/sim_platform.c b/arch/mips/mips-boards/sim/sim_platform.c
new file mode 100644
index 0000000..53210a8
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_platform.c
@@ -0,0 +1,35 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+static char mipsnet_string[] = "mipsnet";
+
+static struct platform_device eth1_device = {
+	.name		= mipsnet_string,
+	.id		= 0,
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init mipsnet_devinit(void)
+{
+	int err;
+
+	err = platform_device_register(&eth1_device);
+	if (err)
+		printk(KERN_ERR "%s: registration failed\n", mipsnet_string);
+
+	return err;
+}
+
+device_initcall(mipsnet_devinit);
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 4e8f1b6..abf99b1 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -96,7 +96,7 @@ void __flush_anon_page(struct page *page
 
 		kaddr = kmap_coherent(page, vmaddr);
 		flush_data_cache_page((unsigned long)kaddr);
-		kunmap_coherent(kaddr);
+		kunmap_coherent();
 	}
 }
 
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index f9c595d..7ebea33 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -16,7 +16,6 @@ #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/module.h>
 
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index e9951c0..2d1c2c0 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -177,7 +177,7 @@ #endif
 
 #define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
 
-void kunmap_coherent(struct page *page)
+void kunmap_coherent(void)
 {
 #ifndef CONFIG_MIPS_MT_SMTC
 	unsigned int wired;
@@ -210,7 +210,7 @@ void copy_user_highpage(struct page *to,
 	if (cpu_has_dc_aliases) {
 		vfrom = kmap_coherent(from, vaddr);
 		copy_page(vto, vfrom);
-		kunmap_coherent(from);
+		kunmap_coherent();
 	} else {
 		vfrom = kmap_atomic(from, KM_USER0);
 		copy_page(vto, vfrom);
@@ -233,7 +233,7 @@ void copy_to_user_page(struct vm_area_st
 	if (cpu_has_dc_aliases) {
 		void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
 		memcpy(vto, src, len);
-		kunmap_coherent(page);
+		kunmap_coherent();
 	} else
 		memcpy(dst, src, len);
 	if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc)
@@ -250,7 +250,7 @@ void copy_from_user_page(struct vm_area_
 		void *vfrom =
 			kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
 		memcpy(dst, vfrom, len);
-		kunmap_coherent(page);
+		kunmap_coherent();
 	} else
 		memcpy(dst, src, len);
 }
@@ -351,18 +351,15 @@ #ifdef CONFIG_HIGHMEM
 #endif
 	kmap_coherent_init();
 
-#ifdef CONFIG_ISA
-	if (max_low_pfn >= MAX_DMA_PFN)
-		if (min_low_pfn >= MAX_DMA_PFN) {
-			zones_size[ZONE_DMA] = 0;
-			zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
-		} else {
-			zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
-			zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
-		}
+#ifdef CONFIG_ZONE_DMA
+	if (min_low_pfn < MAX_DMA_PFN && MAX_DMA_PFN <= max_low_pfn) {
+		zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
+		zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
+	} else if (max_low_pfn < MAX_DMA_PFN)
+		zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
 	else
 #endif
-	zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
+	zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
 
 #ifdef CONFIG_HIGHMEM
 	zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index bf85995..df487c0 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -8,8 +8,7 @@ #
 # PCI bus host bridge specific code
 #
 obj-$(CONFIG_MIPS_BONITO64)	+= ops-bonito64.o
-obj-$(CONFIG_MIPS_GT64111)	+= ops-gt64111.o
-obj-$(CONFIG_MIPS_GT64120)	+= ops-gt64120.o
+obj-$(CONFIG_PCI_GT64XXX_PCI0)	+= ops-gt64xxx_pci0.o
 obj-$(CONFIG_PCI_MARVELL)	+= ops-marvell.o
 obj-$(CONFIG_MIPS_MSC)		+= ops-msc.o
 obj-$(CONFIG_MIPS_NILE4)	+= ops-nile4.o
diff --git a/arch/mips/pci/fixup-jmr3927.c b/arch/mips/pci/fixup-jmr3927.c
index 6e72d21..73d1850 100644
--- a/arch/mips/pci/fixup-jmr3927.c
+++ b/arch/mips/pci/fixup-jmr3927.c
@@ -29,7 +29,6 @@
  */
 #include <linux/types.h>
 #include <linux/pci.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/jmr3927/jmr3927.h>
@@ -81,14 +80,8 @@ int __init pcibios_map_irq(struct pci_de
 
 	/* Check OnBoard Ethernet (IDSEL=A24, DevNu=13) */
 	if (dev->bus->parent == NULL &&
-	    slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(24)) {
-		extern int jmr3927_ether1_irq;
-		/* check this irq line was reserved for ether1 */
-		if (jmr3927_ether1_irq != JMR3927_IRQ_ETHER0)
-			irq = JMR3927_IRQ_ETHER0;
-		else
-			irq = 0;	/* disable */
-	}
+	    slot == TX3927_PCIC_IDSEL_AD_TO_SLOT(24))
+		irq = JMR3927_IRQ_ETHER0;
 	return irq;
 }
 
diff --git a/arch/mips/pci/ops-gt64111.c b/arch/mips/pci/ops-gt64111.c
deleted file mode 100644
index ecd3991..0000000
--- a/arch/mips/pci/ops-gt64111.c
+++ /dev/null
@@ -1,100 +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) 1995, 1996, 1997, 2002 by Ralf Baechle
- * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/pci.h>
-#include <asm/io.h>
-#include <asm/gt64120.h>
-
-#include <asm/mach-cobalt/cobalt.h>
-
-/*
- * Device 31 on the GT64111 is used to generate PCI special
- * cycles, so we shouldn't expected to find a device there ...
- */
-static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn)
-{
-	if (bus->number == 0 && PCI_SLOT(devfn) < 31)
-		return 0;
-
-	return -1;
-}
-
-static int gt64111_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-	int where, int size, u32 * val)
-{
-	if (pci_range_ck(bus, devfn))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	switch (size) {
-	case 4:
-		PCI_CFG_SET(devfn, where);
-		*val = GT_READ(GT_PCI0_CFGDATA_OFS);
-		return PCIBIOS_SUCCESSFUL;
-
-	case 2:
-		PCI_CFG_SET(devfn, (where & ~0x3));
-		*val = GT_READ(GT_PCI0_CFGDATA_OFS)
-		    >> ((where & 3) * 8);
-		return PCIBIOS_SUCCESSFUL;
-
-	case 1:
-		PCI_CFG_SET(devfn, (where & ~0x3));
-		*val = GT_READ(GT_PCI0_CFGDATA_OFS)
-		    >> ((where & 3) * 8);
-		return PCIBIOS_SUCCESSFUL;
-	}
-
-	return PCIBIOS_BAD_REGISTER_NUMBER;
-}
-
-static int gt64111_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-	int where, int size, u32 val)
-{
-	u32 tmp;
-
-	if (pci_range_ck(bus, devfn))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	switch (size) {
-	case 4:
-		PCI_CFG_SET(devfn, where);
-		GT_WRITE(GT_PCI0_CFGDATA_OFS, val);
-
-		return PCIBIOS_SUCCESSFUL;
-
-	case 2:
-		PCI_CFG_SET(devfn, (where & ~0x3));
-		tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
-		tmp &= ~(0xffff << ((where & 0x3) * 8));
-		tmp |= (val << ((where & 0x3) * 8));
-		GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp);
-
-		return PCIBIOS_SUCCESSFUL;
-
-	case 1:
-		PCI_CFG_SET(devfn, (where & ~0x3));
-		tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
-		tmp &= ~(0xff << ((where & 0x3) * 8));
-		tmp |= (val << ((where & 0x3) * 8));
-		GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp);
-
-		return PCIBIOS_SUCCESSFUL;
-	}
-
-	return PCIBIOS_BAD_REGISTER_NUMBER;
-}
-
-struct pci_ops gt64111_pci_ops = {
-	.read = gt64111_pci_read_config,
-	.write = gt64111_pci_write_config,
-};
diff --git a/arch/mips/pci/ops-gt64120.c b/arch/mips/pci/ops-gt64120.c
deleted file mode 100644
index 6335844..0000000
--- a/arch/mips/pci/ops-gt64120.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 1999, 2000, 2004  MIPS Technologies, Inc.
- *	All rights reserved.
- *	Authors: Carsten Langgaard <carstenl@mips.com>
- *		 Maciej W. Rozycki <macro@mips.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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-
-#include <asm/gt64120.h>
-
-#define PCI_ACCESS_READ  0
-#define PCI_ACCESS_WRITE 1
-
-/*
- *  PCI configuration cycle AD bus definition
- */
-/* Type 0 */
-#define PCI_CFG_TYPE0_REG_SHF           0
-#define PCI_CFG_TYPE0_FUNC_SHF          8
-
-/* Type 1 */
-#define PCI_CFG_TYPE1_REG_SHF           0
-#define PCI_CFG_TYPE1_FUNC_SHF          8
-#define PCI_CFG_TYPE1_DEV_SHF           11
-#define PCI_CFG_TYPE1_BUS_SHF           16
-
-static int gt64120_pcibios_config_access(unsigned char access_type,
-	struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
-{
-	unsigned char busnum = bus->number;
-	u32 intr;
-
-	if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
-		return -1;	/* Because of a bug in the galileo (for slot 31). */
-
-	/* 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,
-		 (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
-		 (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
-		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
-		 GT_PCI0_CFGADDR_CONFIGEN_BIT);
-
-	if (access_type == PCI_ACCESS_WRITE) {
-		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
-			/*
-			 * The Galileo system controller is acting
-			 * differently than other devices.
-			 */
-			GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
-		} else
-			__GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
-	} else {
-		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
-			/*
-			 * The Galileo system controller is acting
-			 * differently than other devices.
-			 */
-			*data = GT_READ(GT_PCI0_CFGDATA_OFS);
-		} else
-			*data = __GT_READ(GT_PCI0_CFGDATA_OFS);
-	}
-
-	/* Check for master or target abort */
-	intr = GT_READ(GT_INTRCAUSE_OFS);
-
-	if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
-		/* Error occurred */
-
-		/* 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 gt64120_pcibios_read(struct pci_bus *bus, unsigned int devfn,
-                                int where, int size, u32 * val)
-{
-	u32 data = 0;
-
-	if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
-				          &data))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	if (size == 1)
-		*val = (data >> ((where & 3) << 3)) & 0xff;
-	else if (size == 2)
-		*val = (data >> ((where & 3) << 3)) & 0xffff;
-	else
-		*val = data;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int gt64120_pcibios_write(struct pci_bus *bus, unsigned int devfn,
-			      int where, int size, u32 val)
-{
-	u32 data = 0;
-
-	if (size == 4)
-		data = val;
-	else {
-		if (gt64120_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
-		                                  where, &data))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-		if (size == 1)
-			data = (data & ~(0xff << ((where & 3) << 3))) |
-				(val << ((where & 3) << 3));
-		else if (size == 2)
-			data = (data & ~(0xffff << ((where & 3) << 3))) |
-				(val << ((where & 3) << 3));
-	}
-
-	if (gt64120_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
-				       &data))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-struct pci_ops gt64120_pci_ops = {
-	.read = gt64120_pcibios_read,
-	.write = gt64120_pcibios_write
-};
diff --git a/arch/mips/pci/ops-gt64xxx_pci0.c b/arch/mips/pci/ops-gt64xxx_pci0.c
new file mode 100644
index 0000000..3d896c5
--- /dev/null
+++ b/arch/mips/pci/ops-gt64xxx_pci0.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 1999, 2000, 2004  MIPS Technologies, Inc.
+ *	All rights reserved.
+ *	Authors: Carsten Langgaard <carstenl@mips.com>
+ *		 Maciej W. Rozycki <macro@mips.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.
+ */
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+
+#include <asm/gt64120.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+/*
+ *  PCI configuration cycle AD bus definition
+ */
+/* Type 0 */
+#define PCI_CFG_TYPE0_REG_SHF           0
+#define PCI_CFG_TYPE0_FUNC_SHF          8
+
+/* Type 1 */
+#define PCI_CFG_TYPE1_REG_SHF           0
+#define PCI_CFG_TYPE1_FUNC_SHF          8
+#define PCI_CFG_TYPE1_DEV_SHF           11
+#define PCI_CFG_TYPE1_BUS_SHF           16
+
+static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,
+		struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
+{
+	unsigned char busnum = bus->number;
+	u32 intr;
+
+	if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
+		return -1;	/* Because of a bug in the galileo (for slot 31). */
+
+	/* 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,
+		 (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+		 (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+		 GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+	if (access_type == PCI_ACCESS_WRITE) {
+		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+			/*
+			 * The Galileo system controller is acting
+			 * differently than other devices.
+			 */
+			GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+		} else
+			__GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+	} else {
+		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+			/*
+			 * The Galileo system controller is acting
+			 * differently than other devices.
+			 */
+			*data = GT_READ(GT_PCI0_CFGDATA_OFS);
+		} else
+			*data = __GT_READ(GT_PCI0_CFGDATA_OFS);
+	}
+
+	/* Check for master or target abort */
+	intr = GT_READ(GT_INTRCAUSE_OFS);
+
+	if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+		/* Error occurred */
+
+		/* 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 gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 * val)
+{
+	u32 data = 0;
+
+	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+	                                       where, &data))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (size == 1)
+		*val = (data >> ((where & 3) << 3)) & 0xff;
+	else if (size == 2)
+		*val = (data >> ((where & 3) << 3)) & 0xffff;
+	else
+		*val = data;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 val)
+{
+	u32 data = 0;
+
+	if (size == 4)
+		data = val;
+	else {
+		if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus,
+		                                       devfn, where, &data))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		if (size == 1)
+			data = (data & ~(0xff << ((where & 3) << 3))) |
+				(val << ((where & 3) << 3));
+		else if (size == 2)
+			data = (data & ~(0xffff << ((where & 3) << 3))) |
+				(val << ((where & 3) << 3));
+	}
+
+	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn,
+	                                       where, &data))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops gt64xxx_pci0_ops = {
+	.read	= gt64xxx_pci0_pcibios_read,
+	.write	= gt64xxx_pci0_pcibios_write
+};
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c
index 42530a0..aa698bd 100644
--- a/arch/mips/pci/ops-tx3927.c
+++ b/arch/mips/pci/ops-tx3927.c
@@ -40,7 +40,6 @@ #include <linux/init.h>
 
 #include <asm/addrspace.h>
 #include <asm/jmr3927/jmr3927.h>
-#include <asm/debug.h>
 
 static inline int mkaddr(unsigned char bus, unsigned char dev_fn,
 	unsigned char where)
@@ -130,234 +129,3 @@ struct pci_ops jmr3927_pci_ops = {
 	jmr3927_pci_read_config,
 	jmr3927_pci_write_config,
 };
-
-
-#ifndef JMR3927_INIT_INDIRECT_PCI
-
-inline unsigned long tc_readl(volatile __u32 * addr)
-{
-	return readl(addr);
-}
-
-inline void tc_writel(unsigned long data, volatile __u32 * addr)
-{
-	writel(data, addr);
-}
-#else
-
-unsigned long tc_readl(volatile __u32 * addr)
-{
-	unsigned long val;
-
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) CPHYSADDR(addr);
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_MEMREAD << PCI_IPCIBE_ICMD_SHIFT) |
-	    PCI_IPCIBE_IBE_LONG;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	val =
-	    le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr->
-			ipcidata);
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-	return val;
-}
-
-void tc_writel(unsigned long data, volatile __u32 * addr)
-{
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata =
-	    cpu_to_le32(data);
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) CPHYSADDR(addr);
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_MEMWRITE << PCI_IPCIBE_ICMD_SHIFT) |
-	    PCI_IPCIBE_IBE_LONG;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned char tx_ioinb(unsigned char *addr)
-{
-	unsigned long val;
-	__u32 ioaddr;
-	int offset;
-	int byte;
-
-	ioaddr = (unsigned long) addr;
-	offset = ioaddr & 0x3;
-	byte = 0xf & ~(8 >> offset);
-
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	val =
-	    le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr->
-			ipcidata);
-	val = val & 0xff;
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-	return val;
-}
-
-void tx_iooutb(unsigned long data, unsigned char *addr)
-{
-	__u32 ioaddr;
-	int offset;
-	int byte;
-
-	data = data | (data << 8) | (data << 16) | (data << 24);
-	ioaddr = (unsigned long) addr;
-	offset = ioaddr & 0x3;
-	byte = 0xf & ~(8 >> offset);
-
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = data;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned short tx_ioinw(unsigned short *addr)
-{
-	unsigned long val;
-	__u32 ioaddr;
-	int offset;
-	int byte;
-
-	ioaddr = (unsigned long) addr;
-	offset = ioaddr & 0x2;
-	byte = 3 << offset;
-
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	val =
-	    le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr->
-			ipcidata);
-	val = val & 0xffff;
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-	return val;
-
-}
-
-void tx_iooutw(unsigned long data, unsigned short *addr)
-{
-	__u32 ioaddr;
-	int offset;
-	int byte;
-
-	data = data | (data << 16);
-	ioaddr = (unsigned long) addr;
-	offset = ioaddr & 0x2;
-	byte = 3 << offset;
-
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata = data;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned long tx_ioinl(unsigned int *addr)
-{
-	unsigned long val;
-	__u32 ioaddr;
-
-	ioaddr = (unsigned long) addr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) |
-	    PCI_IPCIBE_IBE_LONG;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	val =
-	    le32_to_cpu(*(volatile u32 *) (unsigned long) & tx3927_pcicptr->
-			ipcidata);
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-	return val;
-}
-
-void tx_iooutl(unsigned long data, unsigned int *addr)
-{
-	__u32 ioaddr;
-
-	ioaddr = (unsigned long) addr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcidata =
-	    cpu_to_le32(data);
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipciaddr =
-	    (unsigned long) ioaddr;
-	*(volatile u32 *) (unsigned long) & tx3927_pcicptr->ipcibe =
-	    (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) |
-	    PCI_IPCIBE_IBE_LONG;
-	while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
-	/* clear by setting */
-	tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-void tx_insbyte(unsigned char *addr, void *buffer, unsigned int count)
-{
-	unsigned char *ptr = (unsigned char *) buffer;
-
-	while (count--) {
-		*ptr++ = tx_ioinb(addr);
-	}
-}
-
-void tx_insword(unsigned short *addr, void *buffer, unsigned int count)
-{
-	unsigned short *ptr = (unsigned short *) buffer;
-
-	while (count--) {
-		*ptr++ = tx_ioinw(addr);
-	}
-}
-
-void tx_inslong(unsigned int *addr, void *buffer, unsigned int count)
-{
-	unsigned long *ptr = (unsigned long *) buffer;
-
-	while (count--) {
-		*ptr++ = tx_ioinl(addr);
-	}
-}
-
-void tx_outsbyte(unsigned char *addr, void *buffer, unsigned int count)
-{
-	unsigned char *ptr = (unsigned char *) buffer;
-
-	while (count--) {
-		tx_iooutb(*ptr++, addr);
-	}
-}
-
-void tx_outsword(unsigned short *addr, void *buffer, unsigned int count)
-{
-	unsigned short *ptr = (unsigned short *) buffer;
-
-	while (count--) {
-		tx_iooutw(*ptr++, addr);
-	}
-}
-
-void tx_outslong(unsigned int *addr, void *buffer, unsigned int count)
-{
-	unsigned long *ptr = (unsigned long *) buffer;
-
-	while (count--) {
-		tx_iooutl(*ptr++, addr);
-	}
-}
-#endif
diff --git a/arch/mips/pci/pci-lasat.c b/arch/mips/pci/pci-lasat.c
index 88fb191..985784a 100644
--- a/arch/mips/pci/pci-lasat.c
+++ b/arch/mips/pci/pci-lasat.c
@@ -12,7 +12,7 @@ #include <linux/types.h>
 #include <asm/bootinfo.h>
 
 extern struct pci_ops nile4_pci_ops;
-extern struct pci_ops gt64120_pci_ops;
+extern struct pci_ops gt64xxx_pci0_ops;
 static struct resource lasat_pci_mem_resource = {
 	.name	= "LASAT PCI MEM",
 	.start	= 0x18000000,
@@ -38,7 +38,7 @@ static int __init lasat_pci_setup(void)
 
 	switch (mips_machtype) {
 	case MACH_LASAT_100:
-                lasat_pci_controller.pci_ops = &gt64120_pci_ops;
+                lasat_pci_controller.pci_ops = &gt64xxx_pci0_ops;
                 break;
 	case MACH_LASAT_200:
                 lasat_pci_controller.pci_ops = &nile4_pci_ops;
diff --git a/arch/mips/pci/pci-ocelot.c b/arch/mips/pci/pci-ocelot.c
index 2b9495d..7f94f26 100644
--- a/arch/mips/pci/pci-ocelot.c
+++ b/arch/mips/pci/pci-ocelot.c
@@ -81,7 +81,7 @@ static struct resource ocelot_io_resourc
 };
 
 static struct pci_controller ocelot_pci_controller = {
-	.pci_ops	= gt64120_pci_ops;
+	.pci_ops	= gt64xxx_pci0_ops;
 	.mem_resource	= &ocelot_mem_resource;
 	.io_resource	= &ocelot_io_resource;
 };
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index de7cfc5..8108231 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -77,6 +77,13 @@ pcibios_align_resource(void *data, struc
 
 void __init register_pci_controller(struct pci_controller *hose)
 {
+	if (request_resource(&iomem_resource, hose->mem_resource) < 0)
+		goto out;
+	if (request_resource(&ioport_resource, hose->io_resource) < 0) {
+		release_resource(hose->mem_resource);
+		goto out;
+	}
+
 	*hose_tail = hose;
 	hose_tail = &hose->next;
 
@@ -87,6 +94,11 @@ void __init register_pci_controller(stru
 		printk(KERN_WARNING
 		       "registering PCI controller with io_map_base unset\n");
 	}
+	return;
+
+out:
+	printk(KERN_WARNING
+	       "Skipping PCI bus scan due to resource conflict\n");
 }
 
 /* Most MIPS systems have straight-forward swizzling needs.  */
@@ -121,11 +133,6 @@ static int __init pcibios_init(void)
 	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
 
-		if (request_resource(&iomem_resource, hose->mem_resource) < 0)
-			goto out;
-		if (request_resource(&ioport_resource, hose->io_resource) < 0)
-			goto out_free_mem_resource;
-
 		if (!hose->iommu)
 			PCI_DMA_BUS_IS_PHYS = 1;
 
@@ -144,14 +151,6 @@ static int __init pcibios_init(void)
 				need_domain_info = 1;
 			}
 		}
-		continue;
-
-out_free_mem_resource:
-		release_resource(hose->mem_resource);
-
-out:
-		printk(KERN_WARNING
-		       "Skipping PCI bus scan due to resource conflict\n");
 	}
 
 	if (!pci_probe_only)
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
new file mode 100644
index 0000000..c41b53f
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
@@ -0,0 +1,165 @@
+/*
+ * The setup file for serial related hardware on PMC-Sierra MSP processors.
+ *
+ * Copyright 2005 PMC-Sierra, 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/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/serial.h>
+
+#include <msp_prom.h>
+#include <msp_int.h>
+#include <msp_regs.h>
+
+#ifdef CONFIG_KGDB
+/*
+ * kgdb uses serial port 1 so the console can remain on port 0.
+ * To use port 0 change the definition to read as follows:
+ * #define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART0_BASE)
+ */
+#define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART1_BASE)
+
+int putDebugChar(char c)
+{
+	volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE;
+	uint32_t val = (uint32_t)c;
+
+	local_irq_disable();
+	while( !(uart[5] & 0x20) ); /* Wait for TXRDY */
+	uart[0] = val;
+	while( !(uart[5] & 0x20) ); /* Wait for TXRDY */
+	local_irq_enable();
+
+	return 1;
+}
+
+char getDebugChar(void)
+{
+	volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE;
+	uint32_t val;
+
+	while( !(uart[5] & 0x01) ); /* Wait for RXRDY */
+	val = uart[0];
+
+	return (char)val;
+}
+
+void initDebugPort(unsigned int uartclk, unsigned int baudrate)
+{
+	unsigned int baud_divisor = (uartclk + 8 * baudrate)/(16 * baudrate);
+
+	/* Enable FIFOs */
+	writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+			UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_4,
+		(char *)DEBUG_PORT_BASE + (UART_FCR * 4));
+
+	/* Select brtc divisor */
+	writeb(UART_LCR_DLAB, (char *)DEBUG_PORT_BASE + (UART_LCR * 4));
+
+	/* Store divisor lsb */
+	writeb(baud_divisor, (char *)DEBUG_PORT_BASE + (UART_TX * 4));
+
+	/* Store divisor msb */
+	writeb(baud_divisor >> 8, (char *)DEBUG_PORT_BASE + (UART_IER * 4));
+
+	/* Set 8N1 mode */
+	writeb(UART_LCR_WLEN8, (char *)DEBUG_PORT_BASE + (UART_LCR * 4));
+
+	/* Disable flow control */
+	writeb(0, (char *)DEBUG_PORT_BASE + (UART_MCR * 4));
+
+	/* Disable receive interrupt(!) */
+	writeb(0, (char *)DEBUG_PORT_BASE + (UART_IER * 4));
+}
+#endif
+
+void __init msp_serial_setup(void)
+{
+	char    *s;
+	char    *endp;
+	struct uart_port up;
+	unsigned int uartclk;
+
+	memset(&up, 0, sizeof(up));
+
+	/* Check if clock was specified in environment */
+	s = prom_getenv("uartfreqhz");
+	if(!(s && *s && (uartclk = simple_strtoul(s, &endp, 10)) && *endp == 0))
+		uartclk = MSP_BASE_BAUD;
+	ppfinit("UART clock set to %d\n", uartclk);
+
+	/* Initialize first serial port */
+	up.mapbase      = MSP_UART0_BASE;
+	up.membase      = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN);
+	up.irq          = MSP_INT_UART0;
+	up.uartclk      = uartclk;
+	up.regshift     = 2;
+	up.iotype       = UPIO_DWAPB; /* UPIO_MEM like */
+	up.flags        = STD_COM_FLAGS;
+	up.type         = PORT_16550A;
+	up.line         = 0;
+	up.private_data		= (void*)UART0_STATUS_REG;
+	if (early_serial_setup(&up))
+		printk(KERN_ERR "Early serial init of port 0 failed\n");
+
+	/* Initialize the second serial port, if one exists */
+	switch (mips_machtype) {
+		case MACH_MSP4200_EVAL:
+		case MACH_MSP4200_GW:
+		case MACH_MSP4200_FPGA:
+		case MACH_MSP7120_EVAL:
+		case MACH_MSP7120_GW:
+		case MACH_MSP7120_FPGA:
+			/* Enable UART1 on MSP4200 and MSP7120 */
+			*GPIO_CFG2_REG = 0x00002299;
+
+#ifdef CONFIG_KGDB
+			/* Initialize UART1 for kgdb since PMON doesn't */
+			if( DEBUG_PORT_BASE == KSEG1ADDR(MSP_UART1_BASE) ) {
+				if( mips_machtype == MACH_MSP4200_FPGA
+				 || mips_machtype == MACH_MSP7120_FPGA )
+					initDebugPort(uartclk,19200);
+				else
+					initDebugPort(uartclk,57600);
+			}
+#endif
+			break;
+
+		default:
+			return; /* No second serial port, good-bye. */
+	}
+
+	up.mapbase      = MSP_UART1_BASE;
+	up.membase      = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN);
+	up.irq          = MSP_INT_UART1;
+	up.line         = 1;
+	up.private_data		= (void*)UART1_STATUS_REG;
+	if (early_serial_setup(&up))
+		printk(KERN_ERR "Early serial init of port 1 failed\n");
+}
diff --git a/arch/mips/sgi-ip22/ip22-nvram.c b/arch/mips/sgi-ip22/ip22-nvram.c
index fd29fd4..e19d60d 100644
--- a/arch/mips/sgi-ip22/ip22-nvram.c
+++ b/arch/mips/sgi-ip22/ip22-nvram.c
@@ -52,8 +52,7 @@ #define	BITS_IN_COMMAND	11
  * national semiconductor nv ram chip the op code is 3 bits and
  * the address is 6/8 bits.
  */
-static inline void eeprom_cmd(volatile unsigned int *ctrl, unsigned cmd,
-			      unsigned reg)
+static inline void eeprom_cmd(unsigned int *ctrl, unsigned cmd, unsigned reg)
 {
 	unsigned short ser_cmd;
 	int i;
@@ -61,33 +60,34 @@ static inline void eeprom_cmd(volatile u
 	ser_cmd = cmd | (reg << (16 - BITS_IN_COMMAND));
 	for (i = 0; i < BITS_IN_COMMAND; i++) {
 		if (ser_cmd & (1<<15))	/* if high order bit set */
-			*ctrl |= EEPROM_DATO;
+			writel(readl(ctrl) | EEPROM_DATO, ctrl);
 		else
-			*ctrl &= ~EEPROM_DATO;
-		*ctrl &= ~EEPROM_ECLK;
-		*ctrl |= EEPROM_ECLK;
+			writel(readl(ctrl) & ~EEPROM_DATO, ctrl);
+		writel(readl(ctrl) & ~EEPROM_ECLK, ctrl);
+		writel(readl(ctrl) | EEPROM_ECLK, ctrl);
 		ser_cmd <<= 1;
 	}
-	*ctrl &= ~EEPROM_DATO;	/* see data sheet timing diagram */
+	/* see data sheet timing diagram */
+	writel(readl(ctrl) & ~EEPROM_DATO, ctrl);
 }
 
-unsigned short ip22_eeprom_read(volatile unsigned int *ctrl, int reg)
+unsigned short ip22_eeprom_read(unsigned int *ctrl, int reg)
 {
 	unsigned short res = 0;
 	int i;
 
-	*ctrl &= ~EEPROM_EPROT;
+	writel(readl(ctrl) & ~EEPROM_EPROT, ctrl);
 	eeprom_cs_on(ctrl);
 	eeprom_cmd(ctrl, EEPROM_READ, reg);
 
 	/* clock the data ouf of serial mem */
 	for (i = 0; i < 16; i++) {
-		*ctrl &= ~EEPROM_ECLK;
+		writel(readl(ctrl) & ~EEPROM_ECLK, ctrl);
 		delay();
-		*ctrl |= EEPROM_ECLK;
+		writel(readl(ctrl) | EEPROM_ECLK, ctrl);
 		delay();
 		res <<= 1;
-		if (*ctrl & EEPROM_DATI)
+		if (readl(ctrl) & EEPROM_DATI)
 			res |= 1;
 	}
 
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 2055547..8e88a44 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -94,7 +94,7 @@ static int indy_rtc_set_time(unsigned lo
 static unsigned long dosample(void)
 {
 	u32 ct0, ct1;
-	volatile u8 msb, lsb;
+	u8 msb, lsb;
 
 	/* Start the counter. */
 	sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
@@ -107,21 +107,21 @@ static unsigned long dosample(void)
 
 	/* Latch and spin until top byte of counter2 is zero */
 	do {
-		sgint->tcword = SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT;
-		lsb = sgint->tcnt2;
-		msb = sgint->tcnt2;
+		writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword);
+		lsb = readb(&sgint->tcnt2);
+		msb = readb(&sgint->tcnt2);
 		ct1 = read_c0_count();
 	} while (msb);
 
 	/* Stop the counter. */
-	sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
-			 SGINT_TCWORD_MSWST);
+	writeb(sgint->tcword, (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
+			       SGINT_TCWORD_MSWST));
 	/*
 	 * Return the difference, this is how far the r4k counter increments
 	 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
 	 * clock (= 1000000 / HZ / 2).
 	 */
-	/*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
+
 	return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
 }
 
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 60ade76..ba8e079 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -19,7 +19,6 @@ #include <linux/ioport.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig
index bdf24a7..e6b003e 100644
--- a/arch/mips/sibyte/Kconfig
+++ b/arch/mips/sibyte/Kconfig
@@ -2,6 +2,7 @@ config SIBYTE_SB1250
 	bool
 	select HW_HAS_PCI
 	select SIBYTE_ENABLE_LDT_IF_PCI
+	select SIBYTE_HAS_ZBUS_PROFILING
 	select SIBYTE_SB1xxx_SOC
 	select SYS_SUPPORTS_SMP
 
@@ -34,6 +35,7 @@ config SIBYTE_BCM112X
 config SIBYTE_BCM1x80
 	bool
 	select HW_HAS_PCI
+	select SIBYTE_HAS_ZBUS_PROFILING
 	select SIBYTE_SB1xxx_SOC
 	select SYS_SUPPORTS_SMP
 
diff --git a/arch/mips/sibyte/common/Makefile b/arch/mips/sibyte/common/Makefile
new file mode 100644
index 0000000..8a06a4f
--- /dev/null
+++ b/arch/mips/sibyte/common/Makefile
@@ -0,0 +1,5 @@
+obj-y :=
+
+obj-$(CONFIG_SIBYTE_TBPROF)		+= sb_tbprof.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
new file mode 100644
index 0000000..4fcdaa8
--- /dev/null
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -0,0 +1,601 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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) 2001, 2002, 2003 Broadcom Corporation
+ * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2007 MIPS Technologies, Inc.
+ *    written by Ralf Baechle <ralf@linux-mips.org>
+ */
+
+#undef DEBUG
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <asm/io.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_scd.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_scd.h>
+#include <asm/sibyte/sb1250_int.h>
+#else
+#error invalid SiByte UART configuation
+#endif
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#undef K_INT_TRACE_FREEZE
+#define K_INT_TRACE_FREEZE K_BCM1480_INT_TRACE_FREEZE
+#undef K_INT_PERF_CNT
+#define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT
+#endif
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define SBPROF_TB_MAJOR 240
+
+typedef u64 tb_sample_t[6*256];
+
+enum open_status {
+	SB_CLOSED,
+	SB_OPENING,
+	SB_OPEN
+};
+
+struct sbprof_tb {
+	wait_queue_head_t	tb_sync;
+	wait_queue_head_t	tb_read;
+	struct mutex		lock;
+	enum open_status	open;
+	tb_sample_t		*sbprof_tbbuf;
+	int			next_tb_sample;
+
+	volatile int		tb_enable;
+	volatile int		tb_armed;
+
+};
+
+static struct sbprof_tb sbp;
+
+#define MAX_SAMPLE_BYTES (24*1024*1024)
+#define MAX_TBSAMPLE_BYTES (12*1024*1024)
+
+#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
+#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
+#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
+
+/* ioctls */
+#define SBPROF_ZBSTART		_IOW('s', 0, int)
+#define SBPROF_ZBSTOP		_IOW('s', 1, int)
+#define SBPROF_ZBWAITFULL	_IOW('s', 2, int)
+
+/*
+ * Routines for using 40-bit SCD cycle counter
+ *
+ * Client responsible for either handling interrupts or making sure
+ * the cycles counter never saturates, e.g., by doing
+ * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
+ */
+
+/*
+ * Configures SCD counter 0 to count ZCLKs starting from val;
+ * Configures SCD counters1,2,3 to count nothing.
+ * Must not be called while gathering ZBbus profiles.
+ */
+
+#define zclk_timer_init(val) \
+  __asm__ __volatile__ (".set push;" \
+			".set mips64;" \
+			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+			"sd   %0, 0x10($8);"   /* write val to counter0 */ \
+			"sd   %1, 0($8);"      /* config counter0 for zclks*/ \
+			".set pop" \
+			: /* no outputs */ \
+						     /* enable, counter0 */ \
+			: /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
+			: /* modifies */ "$8" )
+
+
+/* Reads SCD counter 0 and puts result in value
+   unsigned long long val; */
+#define zclk_get(val) \
+  __asm__ __volatile__ (".set push;" \
+			".set mips64;" \
+			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
+			"ld   %0, 0x10($8);"   /* write val to counter0 */ \
+			".set pop" \
+			: /* outputs */ "=r"(val) \
+			: /* inputs */ \
+			: /* modifies */ "$8" )
+
+#define DEVNAME "sb_tbprof"
+
+#define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES)
+
+/*
+ * Support for ZBbus sampling using the trace buffer
+ *
+ * We use the SCD performance counter interrupt, caused by a Zclk counter
+ * overflow, to trigger the start of tracing.
+ *
+ * We set the trace buffer to sample everything and freeze on
+ * overflow.
+ *
+ * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
+ *
+ */
+
+static u64 tb_period;
+
+static void arm_tb(void)
+{
+        u64 scdperfcnt;
+	u64 next = (1ULL << 40) - tb_period;
+	u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
+
+	/*
+	 * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to
+	 * trigger start of trace.  XXX vary sampling period
+	 */
+	__raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
+	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
+
+	/*
+	 * Unfortunately, in Pass 2 we must clear all counters to knock down
+	 * a previous interrupt request.  This means that bus profiling
+	 * requires ALL of the SCD perf counters.
+	 */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
+						/* keep counters 0,2,3,4,5,6,7 as is */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_BCM1480_SCD_PERF_CNT_CFG0));
+	__raw_writeq(
+		     M_SPC_CFG_ENABLE |		/* enable counting */
+		     M_SPC_CFG_CLEAR |		/* clear all counters */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_BCM1480_SCD_PERF_CNT_CFG1));
+#else
+	__raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
+						/* keep counters 0,2,3 as is */
+		     M_SPC_CFG_ENABLE |		/* enable counting */
+		     M_SPC_CFG_CLEAR |		/* clear all counters */
+		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
+		     IOADDR(A_SCD_PERF_CNT_CFG));
+#endif
+	__raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
+	/* Reset the trace buffer */
+	__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
+	/* XXXKW may want to expose control to the data-collector */
+	tb_options |= M_SCD_TRACE_CFG_FORCECNT;
+#endif
+	__raw_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG));
+	sbp.tb_armed = 1;
+}
+
+static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
+{
+	int i;
+
+	pr_debug(DEVNAME ": tb_intr\n");
+
+	if (sbp.next_tb_sample < MAX_TB_SAMPLES) {
+		/* XXX should use XKPHYS to make writes bypass L2 */
+		u64 *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
+		/* Read out trace */
+		__raw_writeq(M_SCD_TRACE_CFG_START_READ,
+			     IOADDR(A_SCD_TRACE_CFG));
+		__asm__ __volatile__ ("sync" : : : "memory");
+		/* Loop runs backwards because bundles are read out in reverse order */
+		for (i = 256 * 6; i > 0; i -= 6) {
+			/* Subscripts decrease to put bundle in the order */
+			/*   t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */
+			p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t2 hi */
+			p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t2 lo */
+			p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t1 hi */
+			p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t1 lo */
+			p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t0 hi */
+			p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
+			/* read t0 lo */
+		}
+		if (!sbp.tb_enable) {
+			pr_debug(DEVNAME ": tb_intr shutdown\n");
+			__raw_writeq(M_SCD_TRACE_CFG_RESET,
+				     IOADDR(A_SCD_TRACE_CFG));
+			sbp.tb_armed = 0;
+			wake_up_interruptible(&sbp.tb_sync);
+		} else {
+			/* knock down current interrupt and get another one later */
+			arm_tb();
+		}
+	} else {
+		/* No more trace buffer samples */
+		pr_debug(DEVNAME ": tb_intr full\n");
+		__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
+		sbp.tb_armed = 0;
+		if (!sbp.tb_enable)
+			wake_up_interruptible(&sbp.tb_sync);
+		wake_up_interruptible(&sbp.tb_read);
+	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
+{
+	printk(DEVNAME ": unexpected pc_intr");
+	return IRQ_NONE;
+}
+
+/*
+ * Requires: Already called zclk_timer_init with a value that won't
+ *           saturate 40 bits.  No subsequent use of SCD performance counters
+ *           or trace buffer.
+ */
+
+static int sbprof_zbprof_start(struct file *filp)
+{
+	u64 scdperfcnt;
+	int err;
+
+	if (xchg(&sbp.tb_enable, 1))
+		return -EBUSY;
+
+	pr_debug(DEVNAME ": starting\n");
+
+	sbp.next_tb_sample = 0;
+	filp->f_pos = 0;
+
+	err = request_irq (K_INT_TRACE_FREEZE, sbprof_tb_intr, 0,
+			   DEVNAME " trace freeze", &sbp);
+	if (err)
+		return -EBUSY;
+
+	/* Make sure there isn't a perf-cnt interrupt waiting */
+	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
+	/* Disable and clear counters, override SRC_1 */
+	__raw_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) |
+		     M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
+		     IOADDR(A_SCD_PERF_CNT_CFG));
+
+	/*
+	 * We grab this interrupt to prevent others from trying to use
+         * it, even though we don't want to service the interrupts
+         * (they only feed into the trace-on-interrupt mechanism)
+	 */
+	if (request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0, DEVNAME " scd perfcnt", &sbp)) {
+		free_irq(K_INT_TRACE_FREEZE, &sbp);
+		return -EBUSY;
+	}
+
+	/*
+	 * I need the core to mask these, but the interrupt mapper to
+	 *  pass them through.  I am exploiting my knowledge that
+	 *  cp0_status masks out IP[5]. krw
+	 */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq(K_BCM1480_INT_MAP_I3,
+		     IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_L) +
+			    ((K_BCM1480_INT_PERF_CNT & 0x3f) << 3)));
+#else
+	__raw_writeq(K_INT_MAP_I3,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
+			    (K_INT_PERF_CNT << 3)));
+#endif
+
+	/* Initialize address traps */
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_3));
+
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3));
+
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2));
+	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
+
+	/* Initialize Trace Event 0-7 */
+	/*				when interrupt  */
+	__raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
+
+	/* Initialize Trace Sequence 0-7 */
+	/*				     Start on event 0 (interrupt) */
+	__raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
+		     IOADDR(A_SCD_TRACE_SEQUENCE_0));
+	/*			  dsamp when d used | asamp when a used */
+	__raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
+		     K_SCD_TRSEQ_TRIGGER_ALL,
+		     IOADDR(A_SCD_TRACE_SEQUENCE_1));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6));
+	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7));
+
+	/* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+	__raw_writeq(1ULL << (K_BCM1480_INT_PERF_CNT & 0x3f),
+		     IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_TRACE_L)));
+#else
+	__raw_writeq(1ULL << K_INT_PERF_CNT,
+		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)));
+#endif
+	arm_tb();
+
+	pr_debug(DEVNAME ": done starting\n");
+
+	return 0;
+}
+
+static int sbprof_zbprof_stop(void)
+{
+	int err = 0;
+
+	pr_debug(DEVNAME ": stopping\n");
+
+	if (sbp.tb_enable) {
+		/*
+		 * XXXKW there is a window here where the intr handler may run,
+		 * see the disable, and do the wake_up before this sleep
+		 * happens.
+		 */
+		pr_debug(DEVNAME ": wait for disarm\n");
+		err = wait_event_interruptible(sbp.tb_sync, !sbp.tb_armed);
+		pr_debug(DEVNAME ": disarm complete, stat %d\n", err);
+
+		if (err)
+			return err;
+
+		sbp.tb_enable = 0;
+		free_irq(K_INT_TRACE_FREEZE, &sbp);
+		free_irq(K_INT_PERF_CNT, &sbp);
+	}
+
+	pr_debug(DEVNAME ": done stopping\n");
+
+	return err;
+}
+
+static int sbprof_tb_open(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = iminor(inode);
+	if (minor != 0)
+		return -ENODEV;
+
+	if (xchg(&sbp.open, SB_OPENING) != SB_CLOSED)
+		return -EBUSY;
+
+	memset(&sbp, 0, sizeof(struct sbprof_tb));
+	sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES);
+	if (!sbp.sbprof_tbbuf)
+		return -ENOMEM;
+	memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES);
+	init_waitqueue_head(&sbp.tb_sync);
+	init_waitqueue_head(&sbp.tb_read);
+	mutex_init(&sbp.lock);
+
+	sbp.open = SB_OPEN;
+
+	return 0;
+}
+
+static int sbprof_tb_release(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = iminor(inode);
+	if (minor != 0 || !sbp.open)
+		return -ENODEV;
+
+	mutex_lock(&sbp.lock);
+
+	if (sbp.tb_armed || sbp.tb_enable)
+		sbprof_zbprof_stop();
+
+	vfree(sbp.sbprof_tbbuf);
+	sbp.open = 0;
+
+	mutex_unlock(&sbp.lock);
+
+	return 0;
+}
+
+static ssize_t sbprof_tb_read(struct file *filp, char *buf,
+			      size_t size, loff_t *offp)
+{
+	int cur_sample, sample_off, cur_count, sample_left;
+	char *src;
+	int   count   =	 0;
+	char *dest    =	 buf;
+	long  cur_off = *offp;
+
+	if (!access_ok(VERIFY_WRITE, buf, size))
+		return -EFAULT;
+
+	mutex_lock(&sbp.lock);
+
+	count = 0;
+	cur_sample = cur_off / TB_SAMPLE_SIZE;
+	sample_off = cur_off % TB_SAMPLE_SIZE;
+	sample_left = TB_SAMPLE_SIZE - sample_off;
+
+	while (size && (cur_sample < sbp.next_tb_sample)) {
+		int err;
+
+		cur_count = size < sample_left ? size : sample_left;
+		src = (char *)(((long)sbp.sbprof_tbbuf[cur_sample])+sample_off);
+		err = __copy_to_user(dest, src, cur_count);
+		if (err) {
+			*offp = cur_off + cur_count - err;
+			mutex_unlock(&sbp.lock);
+			return err;
+		}
+		pr_debug(DEVNAME ": read from sample %d, %d bytes\n",
+		         cur_sample, cur_count);
+		size -= cur_count;
+		sample_left -= cur_count;
+		if (!sample_left) {
+			cur_sample++;
+			sample_off = 0;
+			sample_left = TB_SAMPLE_SIZE;
+		} else {
+			sample_off += cur_count;
+		}
+		cur_off += cur_count;
+		dest += cur_count;
+		count += cur_count;
+	}
+	*offp = cur_off;
+	mutex_unlock(&sbp.lock);
+
+	return count;
+}
+
+static long sbprof_tb_ioctl(struct file *filp,
+			    unsigned int command,
+			    unsigned long arg)
+{
+	int err = 0;
+
+	switch (command) {
+	case SBPROF_ZBSTART:
+		mutex_lock(&sbp.lock);
+		err = sbprof_zbprof_start(filp);
+		mutex_unlock(&sbp.lock);
+		break;
+
+	case SBPROF_ZBSTOP:
+		mutex_lock(&sbp.lock);
+		err = sbprof_zbprof_stop();
+		mutex_unlock(&sbp.lock);
+		break;
+
+	case SBPROF_ZBWAITFULL: {
+		err = wait_event_interruptible(sbp.tb_read, TB_FULL);
+		if (err)
+			break;
+
+		err = put_user(TB_FULL, (int *) arg);
+		break;
+	}
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static const struct file_operations sbprof_tb_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sbprof_tb_open,
+	.release	= sbprof_tb_release,
+	.read		= sbprof_tb_read,
+	.unlocked_ioctl	= sbprof_tb_ioctl,
+	.compat_ioctl	= sbprof_tb_ioctl,
+	.mmap		= NULL,
+};
+
+static struct class *tb_class;
+static struct device *tb_dev;
+
+static int __init sbprof_tb_init(void)
+{
+	struct device *dev;
+	struct class *tbc;
+	int err;
+
+	if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
+		printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
+		       SBPROF_TB_MAJOR);
+		return -EIO;
+	}
+
+	tbc = class_create(THIS_MODULE, "sb_tracebuffer");
+	if (IS_ERR(tbc)) {
+		err = PTR_ERR(tbc);
+		goto out_chrdev;
+	}
+
+	tb_class = tbc;
+
+	dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), "tb");
+	if (IS_ERR(dev)) {
+		err = PTR_ERR(dev);
+		goto out_class;
+	}
+	tb_dev = dev;
+
+	sbp.open = 0;
+	tb_period = zbbus_mhz * 10000LL;
+	pr_info(DEVNAME ": initialized - tb_period = %lld\n",
+		(long long) tb_period);
+	return 0;
+
+out_class:
+	class_destroy(tb_class);
+out_chrdev:
+	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+
+	return err;
+}
+
+static void __exit sbprof_tb_cleanup(void)
+{
+	device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0));
+	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
+	class_destroy(tb_class);
+}
+
+module_init(sbprof_tb_init);
+module_exit(sbprof_tb_cleanup);
+
+MODULE_ALIAS_CHARDEV_MAJOR(SBPROF_TB_MAJOR);
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
index 04c0f1a..df662c6 100644
--- a/arch/mips/sibyte/sb1250/Makefile
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -1,6 +1,5 @@
 obj-y := setup.o irq.o time.o
 
 obj-$(CONFIG_SMP)			+= smp.o
-obj-$(CONFIG_SIBYTE_TBPROF)		+= bcm1250_tbprof.o
 obj-$(CONFIG_SIBYTE_STANDALONE)		+= prom.o
 obj-$(CONFIG_SIBYTE_BUS_WATCHER)	+= bus_watcher.o
diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
deleted file mode 100644
index ea0ca13..0000000
--- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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) 2001, 2002, 2003 Broadcom Corporation
- * Copyright (C) 2007 Ralf Baechle <ralf@linux-mips.org>
- * Copyright (C) 2007 MIPS Technologies, Inc.
- *    written by Ralf Baechle <ralf@linux-mips.org>
- */
-
-#undef DEBUG
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#include <asm/io.h>
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_scd.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#define SBPROF_TB_MAJOR 240
-
-typedef u64 tb_sample_t[6*256];
-
-enum open_status {
-	SB_CLOSED,
-	SB_OPENING,
-	SB_OPEN
-};
-
-struct sbprof_tb {
-	wait_queue_head_t	tb_sync;
-	wait_queue_head_t	tb_read;
-	struct mutex		lock;
-	enum open_status	open;
-	tb_sample_t		*sbprof_tbbuf;
-	int			next_tb_sample;
-
-	volatile int		tb_enable;
-	volatile int		tb_armed;
-
-};
-
-static struct sbprof_tb sbp;
-
-#define MAX_SAMPLE_BYTES (24*1024*1024)
-#define MAX_TBSAMPLE_BYTES (12*1024*1024)
-
-#define MAX_SAMPLES (MAX_SAMPLE_BYTES/sizeof(u_int32_t))
-#define TB_SAMPLE_SIZE (sizeof(tb_sample_t))
-#define MAX_TB_SAMPLES (MAX_TBSAMPLE_BYTES/TB_SAMPLE_SIZE)
-
-/* ioctls */
-#define SBPROF_ZBSTART		_IOW('s', 0, int)
-#define SBPROF_ZBSTOP		_IOW('s', 1, int)
-#define SBPROF_ZBWAITFULL	_IOW('s', 2, int)
-
-/*
- * Routines for using 40-bit SCD cycle counter
- *
- * Client responsible for either handling interrupts or making sure
- * the cycles counter never saturates, e.g., by doing
- * zclk_timer_init(0) at least every 2^40 - 1 ZCLKs.
- */
-
-/*
- * Configures SCD counter 0 to count ZCLKs starting from val;
- * Configures SCD counters1,2,3 to count nothing.
- * Must not be called while gathering ZBbus profiles.
- */
-
-#define zclk_timer_init(val) \
-  __asm__ __volatile__ (".set push;" \
-			".set mips64;" \
-			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
-			"sd   %0, 0x10($8);"   /* write val to counter0 */ \
-			"sd   %1, 0($8);"      /* config counter0 for zclks*/ \
-			".set pop" \
-			: /* no outputs */ \
-						     /* enable, counter0 */ \
-			: /* inputs */ "r"(val), "r" ((1ULL << 33) | 1ULL) \
-			: /* modifies */ "$8" )
-
-
-/* Reads SCD counter 0 and puts result in value
-   unsigned long long val; */
-#define zclk_get(val) \
-  __asm__ __volatile__ (".set push;" \
-			".set mips64;" \
-			"la   $8, 0xb00204c0;" /* SCD perf_cnt_cfg */ \
-			"ld   %0, 0x10($8);"   /* write val to counter0 */ \
-			".set pop" \
-			: /* outputs */ "=r"(val) \
-			: /* inputs */ \
-			: /* modifies */ "$8" )
-
-#define DEVNAME "bcm1250_tbprof"
-
-#define TB_FULL (sbp.next_tb_sample == MAX_TB_SAMPLES)
-
-/*
- * Support for ZBbus sampling using the trace buffer
- *
- * We use the SCD performance counter interrupt, caused by a Zclk counter
- * overflow, to trigger the start of tracing.
- *
- * We set the trace buffer to sample everything and freeze on
- * overflow.
- *
- * We map the interrupt for trace_buffer_freeze to handle it on CPU 0.
- */
-
-static u64 tb_period;
-
-static void arm_tb(void)
-{
-        u64 scdperfcnt;
-	u64 next = (1ULL << 40) - tb_period;
-	u64 tb_options = M_SCD_TRACE_CFG_FREEZE_FULL;
-
-	/*
-	 * Generate an SCD_PERFCNT interrupt in TB_PERIOD Zclks to trigger
-	 *start of trace.  XXX vary sampling period
-	 */
-	__raw_writeq(0, IOADDR(A_SCD_PERF_CNT_1));
-	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
-
-	/*
-	 * Unfortunately, in Pass 2 we must clear all counters to knock down a
-	 * previous interrupt request.  This means that bus profiling requires
-	 * ALL of the SCD perf counters.
-	 */
-	__raw_writeq((scdperfcnt & ~M_SPC_CFG_SRC1) |
-						/* keep counters 0,2,3 as is */
-		     M_SPC_CFG_ENABLE |		/* enable counting */
-		     M_SPC_CFG_CLEAR |		/* clear all counters */
-		     V_SPC_CFG_SRC1(1),		/* counter 1 counts cycles */
-		     IOADDR(A_SCD_PERF_CNT_CFG));
-	__raw_writeq(next, IOADDR(A_SCD_PERF_CNT_1));
-
-	/* Reset the trace buffer */
-	__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
-#if 0 && defined(M_SCD_TRACE_CFG_FORCECNT)
-	/* XXXKW may want to expose control to the data-collector */
-	tb_options |= M_SCD_TRACE_CFG_FORCECNT;
-#endif
-	__raw_writeq(tb_options, IOADDR(A_SCD_TRACE_CFG));
-	sbp.tb_armed = 1;
-}
-
-static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
-{
-	int i;
-
-	pr_debug(DEVNAME ": tb_intr\n");
-
-	if (sbp.next_tb_sample < MAX_TB_SAMPLES) {
-		/* XXX should use XKPHYS to make writes bypass L2 */
-		u64 *p = sbp.sbprof_tbbuf[sbp.next_tb_sample++];
-		/* Read out trace */
-		__raw_writeq(M_SCD_TRACE_CFG_START_READ,
-			     IOADDR(A_SCD_TRACE_CFG));
-		__asm__ __volatile__ ("sync" : : : "memory");
-		/* Loop runs backwards because bundles are read out in reverse order */
-		for (i = 256 * 6; i > 0; i -= 6) {
-			/* Subscripts decrease to put bundle in the order */
-			/*   t0 lo, t0 hi, t1 lo, t1 hi, t2 lo, t2 hi */
-			p[i - 1] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t2 hi */
-			p[i - 2] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t2 lo */
-			p[i - 3] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t1 hi */
-			p[i - 4] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t1 lo */
-			p[i - 5] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t0 hi */
-			p[i - 6] = __raw_readq(IOADDR(A_SCD_TRACE_READ));
-								/* read t0 lo */
-		}
-		if (!sbp.tb_enable) {
-			pr_debug(DEVNAME ": tb_intr shutdown\n");
-			__raw_writeq(M_SCD_TRACE_CFG_RESET,
-				     IOADDR(A_SCD_TRACE_CFG));
-			sbp.tb_armed = 0;
-			wake_up(&sbp.tb_sync);
-		} else {
-			arm_tb();	/* knock down current interrupt and get another one later */
-		}
-	} else {
-		/* No more trace buffer samples */
-		pr_debug(DEVNAME ": tb_intr full\n");
-		__raw_writeq(M_SCD_TRACE_CFG_RESET, IOADDR(A_SCD_TRACE_CFG));
-		sbp.tb_armed = 0;
-		if (!sbp.tb_enable) {
-			wake_up(&sbp.tb_sync);
-		}
-		wake_up(&sbp.tb_read);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
-{
-	printk(DEVNAME ": unexpected pc_intr");
-	return IRQ_NONE;
-}
-
-/*
- * Requires: Already called zclk_timer_init with a value that won't
- *           saturate 40 bits.  No subsequent use of SCD performance counters
- *           or trace buffer.
- */
-
-static int sbprof_zbprof_start(struct file *filp)
-{
-	u64 scdperfcnt;
-	int err;
-
-	if (xchg(&sbp.tb_enable, 1))
-		return -EBUSY;
-
-	pr_debug(DEVNAME ": starting\n");
-
-	sbp.next_tb_sample = 0;
-	filp->f_pos = 0;
-
-	err = request_irq(K_INT_TRACE_FREEZE, sbprof_tb_intr, 0,
-	                DEVNAME " trace freeze", &sbp);
-	if (err)
-		return -EBUSY;
-
-	/* Make sure there isn't a perf-cnt interrupt waiting */
-	scdperfcnt = __raw_readq(IOADDR(A_SCD_PERF_CNT_CFG));
-	/* Disable and clear counters, override SRC_1 */
-	__raw_writeq((scdperfcnt & ~(M_SPC_CFG_SRC1 | M_SPC_CFG_ENABLE)) |
-		     M_SPC_CFG_ENABLE | M_SPC_CFG_CLEAR | V_SPC_CFG_SRC1(1),
-		     IOADDR(A_SCD_PERF_CNT_CFG));
-
-	/*
-	 * We grab this interrupt to prevent others from trying to use it, even
-	 * though we don't want to service the interrupts (they only feed into
-	 * the trace-on-interrupt mechanism)
-	 */
-	err = request_irq(K_INT_PERF_CNT, sbprof_pc_intr, 0,
-	                DEVNAME " scd perfcnt", &sbp);
-	if (err)
-		goto out_free_irq;
-
-	/*
-	 * I need the core to mask these, but the interrupt mapper to pass them
-	 * through.  I am exploiting my knowledge that cp0_status masks out
-	 * IP[5]. krw
-	 */
-	__raw_writeq(K_INT_MAP_I3,
-		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +
-			    (K_INT_PERF_CNT << 3)));
-
-	/* Initialize address traps */
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_0));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_1));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_2));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_UP_3));
-
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_0));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_1));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_2));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_DOWN_3));
-
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_0));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_1));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_2));
-	__raw_writeq(0, IOADDR(A_ADDR_TRAP_CFG_3));
-
-	/* Initialize Trace Event 0-7 */
-	/*				when interrupt */
-	__raw_writeq(M_SCD_TREVT_INTERRUPT, IOADDR(A_SCD_TRACE_EVENT_0));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_1));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_2));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_3));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_4));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_5));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_6));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_EVENT_7));
-
-	/* Initialize Trace Sequence 0-7 */
-	/*				     Start on event 0 (interrupt) */
-	__raw_writeq(V_SCD_TRSEQ_FUNC_START | 0x0fff,
-		     IOADDR(A_SCD_TRACE_SEQUENCE_0));
-	/*			  dsamp when d used | asamp when a used */
-	__raw_writeq(M_SCD_TRSEQ_ASAMPLE | M_SCD_TRSEQ_DSAMPLE |
-		     K_SCD_TRSEQ_TRIGGER_ALL,
-		     IOADDR(A_SCD_TRACE_SEQUENCE_1));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_2));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_3));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_4));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_5));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_6));
-	__raw_writeq(0, IOADDR(A_SCD_TRACE_SEQUENCE_7));
-
-	/* Now indicate the PERF_CNT interrupt as a trace-relevant interrupt */
-	__raw_writeq(1ULL << K_INT_PERF_CNT,
-		     IOADDR(A_IMR_REGISTER(0, R_IMR_INTERRUPT_TRACE)));
-
-	arm_tb();
-
-	pr_debug(DEVNAME ": done starting\n");
-
-	return 0;
-
-out_free_irq:
-	free_irq(K_INT_TRACE_FREEZE, &sbp);
-
-	return err;
-}
-
-static int sbprof_zbprof_stop(void)
-{
-	int err;
-
-	pr_debug(DEVNAME ": stopping\n");
-
-	if (sbp.tb_enable) {
-		/*
-		 * XXXKW there is a window here where the intr handler may run,
-		 * see the disable, and do the wake_up before this sleep
-		 * happens.
-		 */
-		pr_debug(DEVNAME ": wait for disarm\n");
-		err = wait_event_interruptible(sbp.tb_sync, !sbp.tb_armed);
-		pr_debug(DEVNAME ": disarm complete, stat %d\n", err);
-
-		if (err)
-			return err;
-
-		sbp.tb_enable = 0;
-		free_irq(K_INT_TRACE_FREEZE, &sbp);
-		free_irq(K_INT_PERF_CNT, &sbp);
-	}
-
-	pr_debug(DEVNAME ": done stopping\n");
-
-	return 0;
-}
-
-static int sbprof_tb_open(struct inode *inode, struct file *filp)
-{
-	int minor;
-
-	minor = iminor(inode);
-	if (minor != 0)
-		return -ENODEV;
-
-	if (xchg(&sbp.open, SB_OPENING) != SB_CLOSED)
-		return -EBUSY;
-
-	memset(&sbp, 0, sizeof(struct sbprof_tb));
-
-	sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES);
-	if (!sbp.sbprof_tbbuf)
-		return -ENOMEM;
-
-	memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES);
-	init_waitqueue_head(&sbp.tb_sync);
-	init_waitqueue_head(&sbp.tb_read);
-	mutex_init(&sbp.lock);
-
-	sbp.open = SB_OPEN;
-
-	return 0;
-}
-
-static int sbprof_tb_release(struct inode *inode, struct file *filp)
-{
-	int minor = iminor(inode);
-
-	if (minor != 0 || !sbp.open)
-		return -ENODEV;
-
-	mutex_lock(&sbp.lock);
-
-	if (sbp.tb_armed || sbp.tb_enable)
-		sbprof_zbprof_stop();
-
-	vfree(sbp.sbprof_tbbuf);
-	sbp.open = 0;
-
-	mutex_unlock(&sbp.lock);
-
-	return 0;
-}
-
-static ssize_t sbprof_tb_read(struct file *filp, char *buf,
-			      size_t size, loff_t *offp)
-{
-	int cur_sample, sample_off, cur_count, sample_left;
-	long  cur_off = *offp;
-	char *dest    =	 buf;
-	int   count   =	 0;
-	char *src;
-
-	if (!access_ok(VERIFY_WRITE, buf, size))
-		return -EFAULT;
-
-	mutex_lock(&sbp.lock);
-
-	count = 0;
-	cur_sample = cur_off / TB_SAMPLE_SIZE;
-	sample_off = cur_off % TB_SAMPLE_SIZE;
-	sample_left = TB_SAMPLE_SIZE - sample_off;
-
-	while (size && (cur_sample < sbp.next_tb_sample)) {
-		int err;
-
-		cur_count = size < sample_left ? size : sample_left;
-		src = (char *)(((long)sbp.sbprof_tbbuf[cur_sample])+sample_off);
-		err = __copy_to_user(dest, src, cur_count);
-		if (err) {
-			*offp = cur_off + cur_count - err;
-			mutex_unlock(&sbp.lock);
-			return err;
-		}
-
-		pr_debug(DEVNAME ": read from sample %d, %d bytes\n",
-		         cur_sample, cur_count);
-		size -= cur_count;
-		sample_left -= cur_count;
-		if (!sample_left) {
-			cur_sample++;
-			sample_off = 0;
-			sample_left = TB_SAMPLE_SIZE;
-		} else {
-			sample_off += cur_count;
-		}
-		cur_off += cur_count;
-		dest += cur_count;
-		count += cur_count;
-	}
-
-	*offp = cur_off;
-	mutex_unlock(&sbp.lock);
-
-	return count;
-}
-
-static long sbprof_tb_ioctl(struct file *filp, unsigned int command,
-	unsigned long arg)
-{
-	int error = 0;
-
-	switch (command) {
-	case SBPROF_ZBSTART:
-		mutex_lock(&sbp.lock);
-		error = sbprof_zbprof_start(filp);
-		mutex_unlock(&sbp.lock);
-		break;
-
-	case SBPROF_ZBSTOP:
-		mutex_lock(&sbp.lock);
-		error = sbprof_zbprof_stop();
-		mutex_unlock(&sbp.lock);
-		break;
-
-	case SBPROF_ZBWAITFULL:
-		error = wait_event_interruptible(sbp.tb_read, TB_FULL);
-		if (error)
-			break;
-
-		error = put_user(TB_FULL, (int *) arg);
-		break;
-
-	default:
-		error = -EINVAL;
-		break;
-	}
-
-	return error;
-}
-
-static const struct file_operations sbprof_tb_fops = {
-	.owner		= THIS_MODULE,
-	.open		= sbprof_tb_open,
-	.release	= sbprof_tb_release,
-	.read		= sbprof_tb_read,
-	.unlocked_ioctl	= sbprof_tb_ioctl,
-	.compat_ioctl	= sbprof_tb_ioctl,
-	.mmap		= NULL,
-};
-
-static struct class *tb_class;
-static struct device *tb_dev;
-
-static int __init sbprof_tb_init(void)
-{
-	struct device *dev;
-	struct class *tbc;
-	int err;
-
-	if (register_chrdev(SBPROF_TB_MAJOR, DEVNAME, &sbprof_tb_fops)) {
-		printk(KERN_WARNING DEVNAME ": initialization failed (dev %d)\n",
-		       SBPROF_TB_MAJOR);
-		return -EIO;
-	}
-
-	tbc = class_create(THIS_MODULE, "sb_tracebuffer");
-	if (IS_ERR(tbc)) {
-		err = PTR_ERR(tbc);
-		goto out_chrdev;
-	}
-
-	tb_class = tbc;
-
-	dev = device_create(tbc, NULL, MKDEV(SBPROF_TB_MAJOR, 0), "tb");
-	if (IS_ERR(dev)) {
-		err = PTR_ERR(dev);
-		goto out_class;
-	}
-	tb_dev = dev;
-
-	sbp.open = 0;
-	tb_period = zbbus_mhz * 10000LL;
-	pr_info(DEVNAME ": initialized - tb_period = %lld\n", tb_period);
-
-	return 0;
-
-out_class:
-	class_destroy(tb_class);
-out_chrdev:
-	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
-
-	return err;
-}
-
-static void __exit sbprof_tb_cleanup(void)
-{
-	device_destroy(tb_class, MKDEV(SBPROF_TB_MAJOR, 0));
-	unregister_chrdev(SBPROF_TB_MAJOR, DEVNAME);
-	class_destroy(tb_class);
-}
-
-module_init(sbprof_tb_init);
-module_exit(sbprof_tb_cleanup);
-
-MODULE_ALIAS_CHARDEV_MAJOR(SBPROF_TB_MAJOR);
-MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
-MODULE_LICENSE("GPL");
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index ad5fc47..9ccffdf 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(i
 struct irqaction sni_isa_irq = {
 	.handler = sni_isa_irq_handler,
 	.name = "ISA",
-	.flags = SA_SHIRQ
+	.flags = IRQF_SHARED
 };
 
 /*
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
index 8e8593b..9ee208d 100644
--- a/arch/mips/sni/pcimt.c
+++ b/arch/mips/sni/pcimt.c
@@ -91,7 +91,7 @@ static struct platform_device pcimt_seri
 };
 
 static struct resource sni_io_resource = {
-	.start	= 0x00001000UL,
+	.start	= 0x00000000UL,
 	.end	= 0x03bfffffUL,
 	.name	= "PCIMT IO MEM",
 	.flags	= IORESOURCE_IO,
@@ -132,107 +132,19 @@ static struct resource pcimt_io_resource
 };
 
 static struct resource sni_mem_resource = {
-	.start	= 0x10000000UL,
-	.end	= 0xffffffffUL,
+	.start	= 0x18000000UL,
+	.end	= 0x1fbfffffUL,
 	.name	= "PCIMT PCI MEM",
 	.flags	= IORESOURCE_MEM
 };
 
-/*
- * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
- * for other purposes.  Be paranoid and allocate all of the before the PCI
- * code gets a chance to to map anything else there ...
- *
- * This leaves the following areas available:
- *
- * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
- * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
- * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
- * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
- * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
- */
-static struct resource pcimt_mem_resources[] = {
-	{
-		.start	= 0x100a0000,
-		.end	= 0x100bffff,
-		.name	= "Video RAM area",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x100c0000,
-		.end	= 0x100fffff,
-		.name	= "ISA Reserved",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x14000000,
-		.end	= 0x17bfffff,
-		.name	= "PCI IO",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x17c00000,
-		.end	= 0x17ffffff,
-		.name	= "Cache Replacement Area",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1a000000,
-		.end	= 0x1a000003,
-		.name	= "PCI INT Acknowledge",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fc00000,
-		.end	= 0x1fc7ffff,
-		.name	= "Boot PROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fc80000,
-		.end	= 0x1fcfffff,
-		.name	= "Diag PROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fd00000,
-		.end	= 0x1fdfffff,
-		.name	= "X-Bus",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fe00000,
-		.end	= 0x1fefffff,
-		.name	= "BIOS map",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1ff00000,
-		.end	= 0x1ff7ffff,
-		.name	= "NVRAM / EEPROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fff0000,
-		.end	= 0x1fffefff,
-		.name	= "ASIC PCI",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1ffff000,
-		.end	= 0x1fffffff,
-		.name	= "MP Agent",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x20000000,
-		.end	= 0x9fffffff,
-		.name	= "Main Memory",
-		.flags	= IORESOURCE_BUSY
-	}
-};
-
 static void __init sni_pcimt_resource_init(void)
 {
 	int i;
 
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
-		request_resource(&ioport_resource, pcimt_io_resources + i);
-
-	/* request mem space for pcimt-specific devices */
-	for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
-		request_resource(&sni_mem_resource, pcimt_mem_resources + i);
-
-	ioport_resource.end = sni_io_resource.end;
+		request_resource(&sni_io_resource, pcimt_io_resources + i);
 }
 
 extern struct pci_ops sni_pcimt_ops;
@@ -240,9 +152,10 @@ extern struct pci_ops sni_pcimt_ops;
 static struct pci_controller sni_controller = {
 	.pci_ops	= &sni_pcimt_ops,
 	.mem_resource	= &sni_mem_resource,
-	.mem_offset	= 0x10000000UL,
+	.mem_offset	= 0x00000000UL,
 	.io_resource	= &sni_io_resource,
-	.io_offset	= 0x00000000UL
+	.io_offset	= 0x00000000UL,
+	.io_map_base    = SNI_PORT_BASE
 };
 
 static void enable_pcimt_irq(unsigned int irq)
@@ -363,15 +276,17 @@ void __init sni_pcimt_irq_init(void)
 
 void sni_pcimt_init(void)
 {
-	sni_pcimt_resource_init();
 	sni_pcimt_detect();
 	sni_pcimt_sc_init();
 	rtc_mips_get_time = mc146818_get_cmos_time;
 	rtc_mips_set_time = mc146818_set_rtc_mmss;
 	board_time_init = sni_cpu_time_init;
+	ioport_resource.end = sni_io_resource.end;
 #ifdef CONFIG_PCI
+	PCIBIOS_MIN_IO = 0x9000;
 	register_pci_controller(&sni_controller);
 #endif
+	sni_pcimt_resource_init();
 }
 
 static int __init snirm_pcimt_setup_devinit(void)
diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c
index 1dfc3f0..00d151f 100644
--- a/arch/mips/sni/pcit.c
+++ b/arch/mips/sni/pcit.c
@@ -43,7 +43,7 @@ static struct platform_device pcit_seria
 };
 
 static struct plat_serial8250_port pcit_cplus_data[] = {
-	PORT(0x3f8, 4),
+	PORT(0x3f8, 0),
 	PORT(0x2f8, 3),
 	PORT(0x3e8, 4),
 	PORT(0x2e8, 3),
@@ -59,9 +59,9 @@ static struct platform_device pcit_cplus
 };
 
 static struct resource sni_io_resource = {
-	.start	= 0x00001000UL,
+	.start	= 0x00000000UL,
 	.end	= 0x03bfffffUL,
-	.name	= "PCIT IO MEM",
+	.name	= "PCIT IO",
 	.flags	= IORESOURCE_IO,
 };
 
@@ -92,6 +92,11 @@ static struct resource pcit_io_resources
 		.name	= "dma2",
 		.flags	= IORESOURCE_BUSY
 	}, {
+		.start	=  0xcf8,
+		.end	= 0xcfb,
+		.name	= "PCI config addr",
+		.flags	= IORESOURCE_BUSY
+	}, {
 		.start	=  0xcfc,
 		.end	= 0xcff,
 		.name	= "PCI config data",
@@ -100,107 +105,19 @@ static struct resource pcit_io_resources
 };
 
 static struct resource sni_mem_resource = {
-	.start	= 0x10000000UL,
-	.end	= 0xffffffffUL,
+	.start	= 0x18000000UL,
+	.end	= 0x1fbfffffUL,
 	.name	= "PCIT PCI MEM",
 	.flags	= IORESOURCE_MEM
 };
 
-/*
- * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
- * for other purposes.  Be paranoid and allocate all of the before the PCI
- * code gets a chance to to map anything else there ...
- *
- * This leaves the following areas available:
- *
- * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
- * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
- * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
- * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
- * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
- */
-static struct resource pcit_mem_resources[] = {
-	{
-		.start	= 0x14000000,
-		.end	= 0x17bfffff,
-		.name	= "PCI IO",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x17c00000,
-		.end	= 0x17ffffff,
-		.name	= "Cache Replacement Area",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x180a0000,
-		.end	= 0x180bffff,
-		.name	= "Video RAM area",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x180c0000,
-		.end	= 0x180fffff,
-		.name	= "ISA Reserved",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x19000000,
-		.end	= 0x1fbfffff,
-		.name	= "PCI MEM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fc00000,
-		.end	= 0x1fc7ffff,
-		.name	= "Boot PROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fc80000,
-		.end	= 0x1fcfffff,
-		.name	= "Diag PROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fd00000,
-		.end	= 0x1fdfffff,
-		.name	= "X-Bus",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fe00000,
-		.end	= 0x1fefffff,
-		.name	= "BIOS map",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1ff00000,
-		.end	= 0x1ff7ffff,
-		.name	= "NVRAM / EEPROM",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1fff0000,
-		.end	= 0x1fffefff,
-		.name	= "MAUI ASIC",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x1ffff000,
-		.end	= 0x1fffffff,
-		.name	= "MP Agent",
-		.flags	= IORESOURCE_BUSY
-	}, {
-		.start	= 0x20000000,
-		.end	= 0x9fffffff,
-		.name	= "Main Memory",
-		.flags	= IORESOURCE_BUSY
-	}
-};
-
 static void __init sni_pcit_resource_init(void)
 {
 	int i;
 
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
-		request_resource(&ioport_resource, pcit_io_resources + i);
-
-	/* request mem space for pcimt-specific devices */
-	for (i = 0; i < ARRAY_SIZE(pcit_mem_resources); i++)
-		request_resource(&sni_mem_resource, pcit_mem_resources + i);
-
-	ioport_resource.end = sni_io_resource.end;
+		request_resource(&sni_io_resource, pcit_io_resources + i);
 }
 
 
@@ -209,9 +126,10 @@ extern struct pci_ops sni_pcit_ops;
 static struct pci_controller sni_pcit_controller = {
 	.pci_ops	= &sni_pcit_ops,
 	.mem_resource	= &sni_mem_resource,
-	.mem_offset	= 0x10000000UL,
+	.mem_offset	= 0x00000000UL,
 	.io_resource	= &sni_io_resource,
-	.io_offset	= 0x00000000UL
+	.io_offset	= 0x00000000UL,
+	.io_map_base    = SNI_PORT_BASE
 };
 
 static void enable_pcit_irq(unsigned int irq)
@@ -262,7 +180,7 @@ static void pcit_hwint0(void)
 	int irq;
 
 	clear_c0_status(IE_IRQ0);
-	irq = ffs((pending >> 16) & 0x7f);
+	irq = ffs((pending >> 16) & 0x3f);
 
 	if (likely(irq > 0))
 		do_IRQ (irq + SNI_PCIT_INT_START - 1);
@@ -289,6 +207,8 @@ static void sni_pcit_hwint_cplus(void)
 
 	if (pending & C_IRQ0)
 		pcit_hwint0();
+	else if (pending & C_IRQ1)
+		do_IRQ (MIPS_CPU_IRQ_BASE + 3);
 	else if (pending & C_IRQ2)
 		do_IRQ (MIPS_CPU_IRQ_BASE + 4);
 	else if (pending & C_IRQ3)
@@ -317,21 +237,23 @@ void __init sni_pcit_cplus_irq_init(void
 	mips_cpu_irq_init();
 	for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
 		set_irq_chip(i, &pcit_irq_type);
-	*(volatile u32 *)SNI_PCIT_INT_REG = 0;
+	*(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
 	sni_hwint = sni_pcit_hwint_cplus;
 	change_c0_status(ST0_IM, IE_IRQ0);
-	setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
+	setup_irq (MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
 }
 
 void sni_pcit_init(void)
 {
-	sni_pcit_resource_init();
 	rtc_mips_get_time = mc146818_get_cmos_time;
 	rtc_mips_set_time = mc146818_set_rtc_mmss;
 	board_time_init = sni_cpu_time_init;
+	ioport_resource.end = sni_io_resource.end;
 #ifdef CONFIG_PCI
+	PCIBIOS_MIN_IO = 0x9000;
 	register_pci_controller(&sni_pcit_controller);
 #endif
+	sni_pcit_resource_init();
 }
 
 static int __init snirm_pcit_setup_devinit(void)
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index 0f7576d..a0c11ef 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -1049,3 +1049,22 @@ static int __init toshiba_rbtx4927_rtc_i
 	return IS_ERR(dev) ? PTR_ERR(dev) : 0;
 }
 device_initcall(toshiba_rbtx4927_rtc_init);
+
+static int __init rbtx4927_ne_init(void)
+{
+	static struct resource __initdata res[] = {
+		{
+			.start	= RBTX4927_RTL_8019_BASE,
+			.end	= RBTX4927_RTL_8019_BASE + 0x20 - 1,
+			.flags	= IORESOURCE_IO,
+		}, {
+			.start	= RBTX4927_RTL_8019_IRQ,
+			.flags	= IORESOURCE_IRQ,
+		}
+	};
+	struct platform_device *dev =
+		platform_device_register_simple("ne", -1,
+						res, ARRAY_SIZE(res));
+	return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+device_initcall(rbtx4927_ne_init);
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
index 66163ba..f5d1ce7 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
@@ -20,6 +20,7 @@ #include <linux/interrupt.h>
 #include <linux/console.h>
 #include <linux/pci.h>
 #include <linux/pm.h>
+#include <linux/platform_device.h>
 
 #include <asm/wbflush.h>
 #include <asm/reboot.h>
@@ -1037,3 +1038,22 @@ static int __init tx4938_spi_proc_setup(
 
 __initcall(tx4938_spi_proc_setup);
 #endif
+
+static int __init rbtx4938_ne_init(void)
+{
+	struct resource res[] = {
+		{
+			.start	= RBTX4938_RTL_8019_BASE,
+			.end	= RBTX4938_RTL_8019_BASE + 0x20 - 1,
+			.flags	= IORESOURCE_IO,
+		}, {
+			.start	= RBTX4938_RTL_8019_IRQ,
+			.flags	= IORESOURCE_IRQ,
+		}
+	};
+	struct platform_device *dev =
+		platform_device_register_simple("ne", -1,
+						res, ARRAY_SIZE(res));
+	return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+device_initcall(rbtx4938_ne_init);
diff --git a/arch/mips/vr41xx/Kconfig b/arch/mips/vr41xx/Kconfig
index 92f41f6..8f4d3e7 100644
--- a/arch/mips/vr41xx/Kconfig
+++ b/arch/mips/vr41xx/Kconfig
@@ -1,6 +1,10 @@
-config CASIO_E55
-	bool "Support for CASIO CASSIOPEIA E-10/15/55/65"
+choice
+	prompt "Machine type"
 	depends on MACH_VR41XX
+	default TANBAC_TB022X
+
+config CASIO_E55
+	bool "CASIO CASSIOPEIA E-10/15/55/65"
 	select DMA_NONCOHERENT
 	select IRQ_CPU
 	select ISA
@@ -8,8 +12,7 @@ config CASIO_E55
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 
 config IBM_WORKPAD
-	bool "Support for IBM WorkPad z50"
-	depends on MACH_VR41XX
+	bool "IBM WorkPad z50"
 	select DMA_NONCOHERENT
 	select IRQ_CPU
 	select ISA
@@ -17,26 +20,18 @@ config IBM_WORKPAD
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 
 config NEC_CMBVR4133
-	bool "Support for NEC CMB-VR4133"
-	depends on MACH_VR41XX
+	bool "NEC CMB-VR4133"
 	select DMA_NONCOHERENT
 	select IRQ_CPU
 	select HW_HAS_PCI
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 
-config ROCKHOPPER
-	bool "Support for Rockhopper baseboard"
-	depends on NEC_CMBVR4133
-	select I8259
-	select HAVE_STD_PC_SERIAL_PORT
-
 config TANBAC_TB022X
-	bool "Support for TANBAC VR4131 multichip module and TANBAC VR4131DIMM"
-	depends on MACH_VR41XX
+	bool "TANBAC VR4131 multichip module and TANBAC VR4131DIMM"
 	select DMA_NONCOHERENT
-	select HW_HAS_PCI
 	select IRQ_CPU
+	select HW_HAS_PCI
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	help
@@ -46,40 +41,65 @@ config TANBAC_TB022X
 	  Please refer to <http://www.tanbac.co.jp/>
 	  about VR4131 multichip module and VR4131DIMM.
 
-config TANBAC_TB0226
-	bool "Support for TANBAC Mbase(TB0226)"
+config VICTOR_MPC30X
+	bool "Victor MP-C303/304"
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select HW_HAS_PCI
+	select PCI_VR41XX
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config ZAO_CAPCELLA
+	bool "ZAO Networks Capcella"
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select HW_HAS_PCI
+	select PCI_VR41XX
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+
+endchoice
+
+config ROCKHOPPER
+	bool "Support for Rockhopper base board"
+	depends on NEC_CMBVR4133
+	select PCI_VR41XX
+	select I8259
+	select HAVE_STD_PC_SERIAL_PORT
+
+choice
+	prompt "Base board type"
 	depends on TANBAC_TB022X
+	default TANBAC_TB0287
+
+config TANBAC_TB0219
+	bool "TANBAC DIMM Evaluation Kit(TB0219)"
 	select GPIO_VR41XX
+	select PCI_VR41XX
+	help
+	  The TANBAC DIMM Evaluation Kit(TB0219) is a MIPS-based platform
+	  manufactured by TANBAC.
+	  Please refer to <http://www.tanbac.co.jp/> about DIMM Evaluation Kit.
+
+config TANBAC_TB0226
+	bool "TANBAC Mbase(TB0226)"
+	select GPIO_VR41XX
+	select PCI_VR41XX
 	help
 	  The TANBAC Mbase(TB0226) is a MIPS-based platform
 	  manufactured by TANBAC.
 	  Please refer to <http://www.tanbac.co.jp/> about Mbase.
 
 config TANBAC_TB0287
-	bool "Support for TANBAC Mini-ITX DIMM base(TB0287)"
-	depends on TANBAC_TB022X
+	bool "TANBAC Mini-ITX DIMM base(TB0287)"
+	select PCI_VR41XX
 	help
 	  The TANBAC Mini-ITX DIMM base(TB0287) is a MIPS-based platform
 	  manufactured by TANBAC.
 	  Please refer to <http://www.tanbac.co.jp/> about Mini-ITX DIMM base.
 
-config VICTOR_MPC30X
-	bool "Support for Victor MP-C303/304"
-	depends on MACH_VR41XX
-	select DMA_NONCOHERENT
-	select HW_HAS_PCI
-	select IRQ_CPU
-	select SYS_SUPPORTS_32BIT_KERNEL
-	select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config ZAO_CAPCELLA
-	bool "Support for ZAO Networks Capcella"
-	depends on MACH_VR41XX
-	select DMA_NONCOHERENT
-	select HW_HAS_PCI
-	select IRQ_CPU
-	select SYS_SUPPORTS_32BIT_KERNEL
-	select SYS_SUPPORTS_LITTLE_ENDIAN
+endchoice
 
 config PCI_VR41XX
 	bool "Add PCI control unit support of NEC VR4100 series"
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index 782906b..eb2f9a3 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -435,7 +435,6 @@ # CONFIG_SCSI_SATA_SIS is not set
 # CONFIG_SCSI_SATA_ULI is not set
 CONFIG_SCSI_SATA_VIA=m
 # CONFIG_SCSI_SATA_VITESSE is not set
-CONFIG_SCSI_SATA_INTEL_COMBINED=y
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_IPS is not set
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index c7a81a2..d86e157 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -24,7 +24,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/file.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/ptrace.h>
 #include <asm/errno.h>
diff --git a/arch/parisc/hpux/ioctl.c b/arch/parisc/hpux/ioctl.c
index b34b4f3..dede476 100644
--- a/arch/parisc/hpux/ioctl.c
+++ b/arch/parisc/hpux/ioctl.c
@@ -34,7 +34,6 @@
  */
 
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <asm/errno.h>
 #include <asm/ioctl.h>
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index e9d09b0..c5c9125 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -388,7 +388,7 @@ #endif
 static struct irqaction timer_action = {
 	.handler = timer_interrupt,
 	.name = "timer",
-	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
+	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
 };
 
 #ifdef CONFIG_SMP
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 0d0d617..8a0db37 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -10,7 +10,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 9784e40..fb35ebc 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 1c1a37f..db94aff 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -26,7 +26,6 @@ #include <linux/compat.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/unistd.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 512642d..4f58921 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -29,7 +29,6 @@ #include <linux/linkage.h>
 #include <linux/mm.h>
 #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>
@@ -106,6 +105,11 @@ unsigned long arch_get_unmapped_area(str
 {
 	if (len > TASK_SIZE)
 		return -ENOMEM;
+	/* Might want to check for cache aliasing issues for MAP_FIXED case
+	 * like ARM or MIPS ??? --BenH.
+	 */
+	if (flags & MAP_FIXED)
+		return addr;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 55bc147..745ff74 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -20,7 +20,6 @@ #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index 5f75b3e..89c0370 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -216,11 +216,8 @@ #ifdef CONFIG_KALLSYMS
 		/* Handle some frequent special cases.... */
 		{
 			char symname[KSYM_NAME_LEN+1];
-			char *modname;
-			unsigned long symsize, offset;
 
-			kallsyms_lookup(info->ip, &symsize, &offset,
-					&modname, symname);
+			kallsyms_lookup(info->ip, NULL, NULL, NULL, symname);
 
 			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
 
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 2a82533..c745859 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -181,7 +181,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
   .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
 #endif
-  . = ALIGN(32);
+  . = ALIGN(ASM_PAGE_SIZE);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6dfbd52..808d2ef 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -11,6 +11,11 @@ config PPC64
 	  This option selects whether a 32-bit or a 64-bit kernel
 	  will be built.
 
+config PPC_PM_NEEDS_RTC_LIB
+	bool
+	select RTC_LIB
+	default y if PM
+
 config PPC32
 	bool
 	default y if !PPC64
@@ -89,7 +94,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
 
 config ARCH_MAY_HAVE_PC_FDC
 	bool
-	default y
+	default !PPC_PSERIES || PCI
 
 config PPC_OF
 	def_bool y
@@ -112,12 +117,33 @@ config GENERIC_BUG
 	default y
 	depends on BUG
 
+config SYS_SUPPORTS_APM_EMULATION
+	bool
+
+#
+# Powerpc uses the slab allocator to manage its ptes and the
+# page structs of ptes are used for splitting the page table
+# lock for configurations supporting more than SPLIT_PTLOCK_CPUS.
+#
+# In that special configuration the page structs of slabs are modified.
+# This setting disables the selection of SLUB as a slab allocator.
+#
+config ARCH_USES_SLAB_PAGE_STRUCT
+	bool
+	default y
+	depends on SPLIT_PTLOCK_CPUS <= NR_CPUS
+
 config DEFAULT_UIMAGE
 	bool
 	help
 	  Used to allow a board to specify it wants a uImage built by default
 	default n
 
+config PPC64_SWSUSP
+	bool
+	depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
+	default y
+
 menu "Processor support"
 choice
 	prompt "Processor Type"
@@ -157,17 +183,20 @@ config PPC_83xx
 	select FSL_SOC
 	select 83xx
 	select PPC_FPU
+	select WANT_DEVICE_TREE
 
 config PPC_85xx
 	bool "Freescale 85xx"
 	select E500
 	select FSL_SOC
 	select 85xx
+	select WANT_DEVICE_TREE
 
 config PPC_86xx
 	bool "Freescale 86xx"
 	select 6xx
 	select FSL_SOC
+	select FSL_PCIE
 	select PPC_FPU
 	select ALTIVEC
 	help
@@ -185,7 +214,7 @@ config 40x
 config 44x
 	bool "AMCC 44x"
 	select PPC_DCR_NATIVE
-
+	select WANT_DEVICE_TREE
 
 config E200
 	bool "Freescale e200"
@@ -250,9 +279,14 @@ config PPC_OF_PLATFORM_PCI
 	depends on PPC64 # not supported on 32 bits yet
 	default n
 
+config 4xx
+	bool
+	depends on 40x || 44x
+	default y
+
 config BOOKE
 	bool
-	depends on E200 || E500
+	depends on E200 || E500 || 44x
 	default y
 
 config FSL_BOOKE
@@ -367,394 +401,7 @@ endmenu
 
 source "init/Kconfig"
 
-menu "Platform support"
-	depends on PPC64 || CLASSIC32
-
-choice
-	prompt "Machine type"
-	default PPC_MULTIPLATFORM
-
-config PPC_MULTIPLATFORM
-	bool "Generic desktop/server/laptop"
-	help
-	  Select this option if configuring for an IBM pSeries or
-	  RS/6000 machine, an Apple machine, or a PReP, CHRP,
-	  Maple or Cell-based machine.
-
-config EMBEDDED6xx
-	bool "Embedded 6xx/7xx/7xxx-based board"
-	depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
-
-config APUS
-	bool "Amiga-APUS"
-	depends on PPC32 && BROKEN
-	help
-	  Select APUS if configuring for a PowerUP Amiga.
-	  More information is available at:
-	  <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"
-	select MPIC
-	select PPC_I8259
-	select PPC_RTAS
-	select RTAS_ERROR_LOGGING
-	select PPC_UDBG_16550
-	select PPC_NATIVE
-	default y
-
-config PPC_ISERIES
-	bool "IBM Legacy iSeries"
-	depends on PPC_MULTIPLATFORM && PPC64
-	select PPC_INDIRECT_IO
-
-config PPC_CHRP
-	bool "Common Hardware Reference Platform (CHRP) based machines"
-	depends on PPC_MULTIPLATFORM && PPC32
-	select MPIC
-	select PPC_I8259
-	select PPC_INDIRECT_PCI
-	select PPC_RTAS
-	select PPC_MPC106
-	select PPC_UDBG_16550
-	select PPC_NATIVE
-	default y
-
-config PPC_MPC52xx
-	bool
-	default n
-
-config PPC_MPC5200
-	bool
-	select PPC_MPC52xx
-	default n
-
-config PPC_MPC5200_BUGFIX
-	bool "MPC5200 (L25R) bugfix support"
-	depends on PPC_MPC5200
-	default n
-	help
-	  Enable workarounds for original MPC5200 errata.  This is not required
-	  for MPC5200B based boards.
-
-	  It is safe to say 'Y' here
-
-config PPC_EFIKA
-	bool "bPlan Efika 5k2. MPC5200B based computer"
-	depends on PPC_MULTIPLATFORM && PPC32
-	select PPC_RTAS
-	select RTAS_PROC
-	select PPC_MPC52xx
-	select PPC_NATIVE
-	default n
-
-config PPC_LITE5200
-	bool "Freescale Lite5200 Eval Board"
-	depends on PPC_MULTIPLATFORM && PPC32
-	select PPC_MPC5200
-	default n
-
-config PPC_PMAC
-	bool "Apple PowerMac based machines"
-	depends on PPC_MULTIPLATFORM
-	select MPIC
-	select PPC_INDIRECT_PCI if PPC32
-	select PPC_MPC106 if PPC32
-	select PPC_NATIVE
-	default y
-
-config PPC_PMAC64
-	bool
-	depends on PPC_PMAC && POWER4
-	select MPIC
-	select U3_DART
-	select MPIC_BROKEN_U3
-	select GENERIC_TBSYNC
-	select PPC_970_NAP
-	default y
-
-config PPC_PREP
-	bool "PowerPC Reference Platform (PReP) based machines"
-	depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
-	select MPIC
-	select PPC_I8259
-	select PPC_INDIRECT_PCI
-	select PPC_UDBG_16550
-	select PPC_NATIVE
-	default n
-
-config PPC_MAPLE
-	depends on PPC_MULTIPLATFORM && PPC64
-	bool "Maple 970FX Evaluation Board"
-	select MPIC
-	select U3_DART
-	select MPIC_BROKEN_U3
-	select GENERIC_TBSYNC
-	select PPC_UDBG_16550
-	select PPC_970_NAP
-	select PPC_NATIVE
-	select PPC_RTAS
-	select MMIO_NVRAM
-	select ATA_NONSTANDARD if ATA
-	default n
-	help
-          This option enables support for the Maple 970FX Evaluation Board.
-	  For more information, 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
-	select PPC_NATIVE
-	help
-	  This option enables support for PA Semi's PWRficient line
-	  of SoC processors, including PA6T-1682M
-
-config PPC_CELL
-	bool
-	default n
-
-config PPC_CELL_NATIVE
-	bool
-	select PPC_CELL
-	select PPC_DCR_MMIO
-	select PPC_OF_PLATFORM_PCI
-	select PPC_INDIRECT_IO
-	select PPC_NATIVE
-	select MPIC
-	default n
-
-config PPC_IBM_CELL_BLADE
-	bool "IBM Cell Blade"
-	depends on PPC_MULTIPLATFORM && PPC64
-	select PPC_CELL_NATIVE
-	select PPC_RTAS
-	select MMIO_NVRAM
-	select PPC_UDBG_16550
-	select UDBG_RTAS_CONSOLE
-
-config PPC_PS3
-	bool "Sony PS3 (incomplete)"
-	depends on PPC_MULTIPLATFORM && PPC64
-	select PPC_CELL
-	select USB_ARCH_HAS_OHCI
-	select USB_OHCI_LITTLE_ENDIAN
-	select USB_OHCI_BIG_ENDIAN_MMIO
-	select USB_ARCH_HAS_EHCI
-	select USB_EHCI_BIG_ENDIAN_MMIO
-	help
-	  This option enables support for the Sony PS3 game console
-	  and other platforms using the PS3 hypervisor.
-	  Support for this platform is not yet complete, so
-	  enabling this will not result in a bootable kernel on a
-	  PS3 system.
-
-config PPC_CELLEB
-	bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
-	depends on PPC_MULTIPLATFORM && PPC64
-	select PPC_CELL
-	select PPC_OF_PLATFORM_PCI
-	select HAS_TXX9_SERIAL
-	select PPC_UDBG_BEAT
-	select USB_OHCI_BIG_ENDIAN_MMIO
-	select USB_EHCI_BIG_ENDIAN_MMIO
-
-config PPC_NATIVE
-	bool
-	depends on PPC_MULTIPLATFORM
-	help
-	  Support for running natively on the hardware, i.e. without
-	  a hypervisor. This option is not user-selectable but should
-	  be selected by all platforms that need it.
-
-config UDBG_RTAS_CONSOLE
-	bool "RTAS based debug console"
-	depends on PPC_RTAS
-	default n
-
-config PPC_UDBG_BEAT
-	bool "BEAT based debug console"
-	depends on PPC_CELLEB
-	default n
-
-config XICS
-	depends on PPC_PSERIES
-	bool
-	default y
-
-config U3_DART
-	bool 
-	depends on PPC_MULTIPLATFORM && PPC64
-	default n
-
-config PPC_RTAS
-	bool
-	default n
-
-config RTAS_ERROR_LOGGING
-	bool
-	depends on PPC_RTAS
-	default n
-
-config RTAS_PROC
-	bool "Proc interface to RTAS"
-	depends on PPC_RTAS
-	default y
-
-config RTAS_FLASH
-	tristate "Firmware flash interface"
-	depends on PPC64 && RTAS_PROC
-
-config PPC_PMI
-	tristate "Support for PMI"
-	depends PPC_IBM_CELL_BLADE
-	help
-	  PMI (Platform Management Interrupt) is a way to
-	  communicate with the BMC (Baseboard Mangement Controller).
-	  It is used in some IBM Cell blades.
-	default m
-
-config MMIO_NVRAM
-	bool
-	default n
-
-config MPIC_BROKEN_U3
-	bool
-	depends on PPC_MAPLE
-	default y
-
-config IBMVIO
-	depends on PPC_PSERIES || PPC_ISERIES
-	bool
-	default y
-
-config IBMEBUS
-	depends on PPC_PSERIES
-	bool "Support for GX bus based adapters"
-	help
-	  Bus device driver for GX bus based adapters.
-
-config PPC_MPC106
-	bool
-	default n
-
-config PPC_970_NAP
-	bool
-	default n
-
-config PPC_INDIRECT_IO
-	bool
-	select GENERIC_IOMAP
-	default n
-
-config GENERIC_IOMAP
-	bool
-	default n
-
-source "drivers/cpufreq/Kconfig"
-
-config CPU_FREQ_PMAC
-	bool "Support for Apple PowerBooks"
-	depends on CPU_FREQ && ADB_PMU && PPC32
-	select CPU_FREQ_TABLE
-	help
-	  This adds support for frequency switching on Apple PowerBooks,
-	  this currently includes some models of iBook & Titanium
-	  PowerBook.
-
-config CPU_FREQ_PMAC64
-	bool "Support for some Apple G5s"
-	depends on CPU_FREQ && PPC64
-	select CPU_FREQ_TABLE
-	help
-	  This adds support for frequency switching on Apple iMac G5,
-	  and some of the more recent desktop G5 machines as well.
-
-config PPC601_SYNC_FIX
-	bool "Workarounds for PPC601 bugs"
-	depends on 6xx && (PPC_PREP || PPC_PMAC)
-	help
-	  Some versions of the PPC601 (the first PowerPC chip) have bugs which
-	  mean that extra synchronization instructions are required near
-	  certain instructions, typically those that make major changes to the
-	  CPU state.  These extra instructions reduce performance slightly.
-	  If you say N here, these extra instructions will not be included,
-	  resulting in a kernel which will run faster but may not run at all
-	  on some systems with the PPC601 chip.
-
-	  If in doubt, say Y here.
-
-config TAU
-	bool "On-chip CPU temperature sensor support"
-	depends on 6xx
-	help
-	  G3 and G4 processors have an on-chip temperature sensor called the
-	  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
-	  temperature within 2-4 degrees Celsius. This option shows the current
-	  on-die temperature in /proc/cpuinfo if the cpu supports it.
-
-	  Unfortunately, on some chip revisions, this sensor is very inaccurate
-	  and in many cases, does not work at all, so don't assume the cpu
-	  temp is actually what /proc/cpuinfo says it is.
-
-config TAU_INT
-	bool "Interrupt driven TAU driver (DANGEROUS)"
-	depends on TAU
-	---help---
-	  The TAU supports an interrupt driven mode which causes an interrupt
-	  whenever the temperature goes out of range. This is the fastest way
-	  to get notified the temp has exceeded a range. With this option off,
-	  a timer is used to re-check the temperature periodically.
-
-	  However, on some cpus it appears that the TAU interrupt hardware
-	  is buggy and can cause a situation which would lead unexplained hard
-	  lockups.
-
-	  Unless you are extending the TAU driver, or enjoy kernel/hardware
-	  debugging, leave this option off.
-
-config TAU_AVERAGE
-	bool "Average high and low temp"
-	depends on TAU
-	---help---
-	  The TAU hardware can compare the temperature to an upper and lower
-	  bound.  The default behavior is to show both the upper and lower
-	  bound in /proc/cpuinfo. If the range is large, the temperature is
-	  either changing a lot, or the TAU hardware is broken (likely on some
-	  G4's). If the range is small (around 4 degrees), the temperature is
-	  relatively stable.  If you say Y here, a single temperature value,
-	  halfway between the upper and lower bounds, will be reported in
-	  /proc/cpuinfo.
-
-	  If in doubt, say N here.
-
-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
-source arch/powerpc/platforms/8xx/Kconfig
-source arch/powerpc/platforms/cell/Kconfig
-source arch/powerpc/platforms/ps3/Kconfig
-source arch/powerpc/platforms/pasemi/Kconfig
+source "arch/powerpc/platforms/Kconfig"
 
 menu "Kernel options"
 
@@ -837,15 +484,6 @@ config CRASH_DUMP
 
 	  Don't change this unless you know what you are doing.
 
-config EMBEDDEDBOOT
-	bool
-	depends on 8xx || 8260
-	default y
-
-config PC_KEYBOARD
-	bool "PC PS/2 style Keyboard"
-	depends on 4xx || CPM2
-
 config PPCBUG_NVRAM
 	bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC
 	default y if PPC_PREP
@@ -859,8 +497,6 @@ config IRQ_ALL_CPUS
 	  CPU.  Generally saying Y is safe, although some problems have been
 	  reported with SMP Power Macintoshes with this option enabled.
 
-source "arch/powerpc/platforms/pseries/Kconfig"
-
 config NUMA
 	bool "NUMA support"
 	depends on PPC64
@@ -910,10 +546,10 @@ config PPC_64K_PAGES
 	depends on PPC64
 	help
 	  This option changes the kernel logical page size to 64k. On machines
-          without processor support for 64k pages, the kernel will simulate
-          them by loading each individual 4k page on demand transparently,
-          while on hardware with such support, it will be used to map
-          normal application pages.
+	  without processor support for 64k pages, the kernel will simulate
+	  them by loading each individual 4k page on demand transparently,
+	  while on hardware with such support, it will be used to map
+	  normal application pages.
 
 config SCHED_SMT
 	bool "SMT (Hyperthreading) scheduler support"
@@ -931,8 +567,6 @@ config PROC_DEVICETREE
 	  an image of the device tree that the kernel copies from Open
 	  Firmware or other boot firmware. If unsure, say Y here.
 
-source "arch/powerpc/platforms/prep/Kconfig"
-
 config CMDLINE_BOOL
 	bool "Default bootloader kernel arguments"
 
@@ -967,6 +601,29 @@ config SECCOMP
 
 	  If unsure, say Y. Only embedded should say N here.
 
+config WANT_DEVICE_TREE
+	bool
+	default n
+
+config DEVICE_TREE
+	string "Static device tree source file"
+	depends on WANT_DEVICE_TREE
+	help
+	  This specifies the device tree source (.dts) file to be
+	  compiled and included when building the bootwrapper.  If a
+	  relative filename is given, then it will be relative to
+	  arch/powerpc/boot/dts.  If you are not using the bootwrapper,
+	  or do not need to build a dts into the bootwrapper, this
+	  field is ignored.
+
+	  For example, this is required when building a cuImage target
+	  for an older U-Boot, which cannot pass a device tree itself.
+	  Such a kernel will not work with a newer U-Boot that tries to
+	  pass a device tree (unless you tell it not to).  If your U-Boot
+	  does not mention a device tree in "help bootm", then use the
+	  cuImage target and specify a device tree here.  Otherwise, use
+	  the uImage target and leave this field blank.
+
 endmenu
 
 config ISA_DMA_API
@@ -995,24 +652,17 @@ config GENERIC_ISA_DMA
 	depends on PPC64 || POWER4 || 6xx && !CPM2
 	default y
 
-config MPIC
-	bool
-	default n
-
-config MPIC_WEIRD
-	bool
-	default n
-
-config PPC_I8259
-	bool
-	default n
-
 config PPC_INDIRECT_PCI
 	bool
 	depends on PCI
 	default y if 40x || 44x
 	default n
 
+config PPC_INDIRECT_PCI_BE
+	bool
+	depends PPC_INDIRECT_PCI
+	default n
+
 config EISA
 	bool
 
@@ -1022,17 +672,23 @@ config SBUS
 config FSL_SOC
 	bool
 
+config FSL_PCIE
+	bool
+	depends on PPC_86xx
+
 # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
 config MCA
 	bool
 
 config PCI
 	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
-		|| PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2 || PPC_PS3
+		|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
+		|| MPC7448HPC2 || PPC_PS3 || PPC_HOLLY
 	default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
 		&& !PPC_85xx && !PPC_86xx
 	default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
 	default PCI_QSPAN if !4xx && !CPM2 && 8xx
+	select ARCH_SUPPORTS_MSI
 	help
 	  Find out whether your system includes a PCI bus. PCI is the name of
 	  a bus system, i.e. the way the CPU talks to the other stuff inside
@@ -1228,12 +884,10 @@ # XXX source "arch/ppc/8260_io/Kconfig"
 
 source "arch/powerpc/sysdev/qe_lib/Kconfig"
 
-source "arch/powerpc/platforms/iseries/Kconfig"
-
 source "lib/Kconfig"
 
 menu "Instrumentation Support"
-        depends on EXPERIMENTAL
+	depends on EXPERIMENTAL
 
 source "arch/powerpc/oprofile/Kconfig"
 
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index d39d133..f70e795 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -18,6 +18,15 @@ config DEBUG_STACK_USAGE
 
 	  This option will slow down process creation somewhat.
 
+config DEBUG_PAGEALLOC
+        bool "Debug page memory allocations"
+        depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
+        help
+          Unmap pages from the kernel linear mapping after free_pages().
+          This results in a large slowdown, but helps to find certain types
+          of memory corruptions.
+
+
 config HCALL_STATS
 	bool "Hypervisor call instrumentation"
 	depends on PPC_PSERIES && DEBUG_FS
@@ -130,11 +139,6 @@ config BOOTX_TEXT
 	  Say Y here to see progress messages from the boot firmware in text
 	  mode. Requires either BootX or Open Firmware.
 
-config SERIAL_TEXT_DEBUG
-	bool "Support for early boot texts over serial port"
-	depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
-		PPC_GEN550 || PPC_MPC52xx
-
 config PPC_EARLY_DEBUG
 	bool "Early debugging (dangerous)"
 
@@ -199,6 +203,24 @@ config PPC_EARLY_DEBUG_BEAT
 	help
 	  Select this to enable early debugging for Celleb with Beat.
 
+config PPC_EARLY_DEBUG_44x
+	bool "Early serial debugging for IBM/AMCC 44x CPUs"
+	depends on 44x
+	select PPC_UDBG_16550
+	help
+	  Select this to enable early debugging for IBM 44x chips via the
+	  inbuilt serial port.
+
 endchoice
 
+config PPC_EARLY_DEBUG_44x_PHYSLOW
+	hex "Low 32 bits of early debug UART physical address"
+	depends PPC_EARLY_DEBUG_44x
+	default "0x40000200"
+
+config PPC_EARLY_DEBUG_44x_PHYSHIGH
+	hex "EPRN of early debug UART physical address"
+	depends PPC_EARLY_DEBUG_44x
+	default "0x1"
+
 endmenu
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a00fe72..81a531d 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -102,9 +102,9 @@ # Enable unit-at-a-time mode when possib
 # kernel considerably.
 CFLAGS += $(call cc-option,-funit-at-a-time)
 
-ifndef CONFIG_FSL_BOOKE
-CFLAGS		+= -mstring
-endif
+# Never use string load/store instructions as they are
+# often slow when they are implemented at all
+CFLAGS		+= -mno-string
 
 ifeq ($(CONFIG_6xx),y)
 CFLAGS		+= -mcpu=powerpc
@@ -166,6 +166,9 @@ define archhelp
   @echo '  *_defconfig     - Select default config from arch/$(ARCH)/configs'
 endef
 
+install:
+	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
 
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 0734b2f..eec7af7 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -18,6 +18,9 @@ kernel-vmlinux.strip.c
 kernel-vmlinux.strip.gz
 mktree
 uImage
+cuImage
+cuImage.bin.gz
+cuImage.elf
 zImage
 zImage.chrp
 zImage.coff
diff --git a/arch/powerpc/boot/44x.c b/arch/powerpc/boot/44x.c
new file mode 100644
index 0000000..d51377d
--- /dev/null
+++ b/arch/powerpc/boot/44x.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Based on earlier code:
+ *   Matt Porter <mporter@kernel.crashing.org>
+ *   Copyright 2002-2005 MontaVista Software Inc.
+ *
+ *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *   Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "reg.h"
+#include "dcr.h"
+
+/* Read the 44x memory controller to get size of system memory. */
+void ibm44x_fixup_memsize(void)
+{
+	int i;
+	unsigned long memsize, bank_config;
+
+	memsize = 0;
+	for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
+		mtdcr(DCRN_SDRAM0_CFGADDR, sdram_bxcr[i]);
+		bank_config = mfdcr(DCRN_SDRAM0_CFGDATA);
+
+		if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
+			memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
+	}
+
+	dt_fixup_memory(0, memsize);
+}
diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h
new file mode 100644
index 0000000..7b129ad
--- /dev/null
+++ b/arch/powerpc/boot/44x.h
@@ -0,0 +1,16 @@
+/*
+ * PowerPC 44x related functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * 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_44X_H_
+#define _PPC_BOOT_44X_H_
+
+void ibm44x_fixup_memsize(void);
+void ebony_init(void *mac0, void *mac1);
+
+#endif /* _PPC_BOOT_44X_H_ */
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index dc77940..5c384aa 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -37,13 +37,16 @@ zlib       := inffast.c inflate.c inftre
 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)/,$(zlib) gunzip_util.o main.o): \
+	$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 
-src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
-		ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib)
-src-plat := of.c
-src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
+src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+		ns16550.c serial.c simple_alloc.c div64.S util.S \
+		gunzip_util.c elf_util.c $(zlib) devtree.c \
+		44x.c ebony.c
+src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
+		cuboot-ebony.c treeboot-ebony.c
+src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -75,7 +78,7 @@ quiet_cmd_copy_zliblinuxheader = COPY   
 	@cp $< $@
 
 clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
-		empty.c zImage zImage.coff.lds zImage.lds zImage.sandpoint
+		empty.c zImage.coff.lds zImage.lds
 
 quiet_cmd_bootcc = BOOTCC  $@
       cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -84,23 +87,25 @@ quiet_cmd_bootas = BOOTAS  $@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootar = BOOTAR  $@
-      cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@
+      cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
 
-$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
+$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
 	$(call if_changed_dep,bootcc)
-$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
+$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
 	$(call if_changed_dep,bootas)
 
-$(obj)/wrapper.a: $(obj-wlib)
-	$(call cmd,bootar)
+$(obj)/wrapper.a: $(obj-wlib) FORCE
+	$(call if_changed,bootar)
 
 hostprogs-y	:= addnote addRamDisk hack-coff mktree
 
-extra-y		:= $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
+targets		+= $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
+extra-y		:= $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
 		   $(obj)/zImage.lds $(obj)/zImage.coff.lds
 
 wrapper		:=$(srctree)/$(src)/wrapper
-wrapperbits	:= $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree)
+wrapperbits	:= $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \
+			$(wrapper) FORCE
 
 #############
 # Bits for building various flavours of zImage
@@ -113,41 +118,50 @@ CROSSWRAP := -C "$(CROSS_COMPILE)"
 endif
 endif
 
+# args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd
 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
+      cmd_wrap	=$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
+		$(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
 
-$(obj)/zImage.chrp: vmlinux $(wrapperbits)
-	$(call cmd,wrap,chrp)
-
-$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits)
-	$(call cmd,wrap_initrd,chrp)
-
-$(obj)/zImage.pseries:	vmlinux $(wrapperbits)
-	$(call cmd,wrap,pseries)
-
-$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits)
-	$(call cmd,wrap_initrd,pseries)
+image-$(CONFIG_PPC_PSERIES)		+= zImage.pseries
+image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
+image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
+image-$(CONFIG_PPC_PS3)			+= zImage.ps3
+image-$(CONFIG_PPC_CELLEB)		+= zImage.pseries
+image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
+image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
+image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
+image-$(CONFIG_PPC_HOLLY)		+= zImage.holly-elf
+image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
 
-$(obj)/zImage.pmac: vmlinux $(wrapperbits)
-	$(call cmd,wrap,pmac)
+ifneq ($(CONFIG_DEVICE_TREE),"")
+image-$(CONFIG_PPC_83xx)		+= cuImage.83xx
+image-$(CONFIG_PPC_85xx)		+= cuImage.85xx
+image-$(CONFIG_EBONY)			+= treeImage.ebony cuImage.ebony
+endif
 
-$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits)
-	$(call cmd,wrap_initrd,pmac)
+# For 32-bit powermacs, build the COFF and miboot images
+# as well as the ELF images.
+ifeq ($(CONFIG_PPC32),y)
+image-$(CONFIG_PPC_PMAC)	+= zImage.coff zImage.miboot
+endif
 
-$(obj)/zImage.coff: vmlinux $(wrapperbits)
-	$(call cmd,wrap,pmaccoff)
+initrd-  := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
+initrd-y := $(patsubst zImage%, zImage.initrd%, \
+		$(patsubst treeImage%, treeImage.initrd%, $(image-y)))
+initrd-y := $(filter-out $(image-y), $(initrd-y))
+targets	+= $(image-y) $(initrd-y)
 
-$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits)
-	$(call cmd,wrap_initrd,pmaccoff)
+$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
 
-$(obj)/zImage.miboot: vmlinux $(wrapperbits)
-	$(call cmd,wrap,miboot)
+# Don't put the ramdisk on the pattern rule; when its missing make will try
+# the pattern rule with less dependencies that also matches (even with the
+# hard dependency listed).
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
+	$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
 
-$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
-	$(call cmd,wrap_initrd,miboot)
+$(obj)/zImage.%: vmlinux $(wrapperbits)
+	$(call if_changed,wrap,$*)
 
 $(obj)/zImage.ps3: vmlinux
 	$(STRIP) -s -R .comment $< -o $@
@@ -155,35 +169,42 @@ quiet_cmd_wrap_initrd = WRAP    $@
 $(obj)/zImage.initrd.ps3: vmlinux
 	@echo "  WARNING zImage.initrd.ps3 not supported (yet)"
 
+$(obj)/zImage.holly-elf: vmlinux $(wrapperbits)
+	$(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,)
+
+$(obj)/zImage.initrd.holly-elf: vmlinux $(wrapperbits) $(obj)/ramdisk.image.gz
+	$(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,$(obj)/ramdisk.image.gz)
+
 $(obj)/uImage: vmlinux $(wrapperbits)
-	$(call cmd,wrap,uboot)
+	$(call if_changed,wrap,uboot)
 
-image-$(CONFIG_PPC_PSERIES)		+= zImage.pseries
-image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
-image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
-image-$(CONFIG_PPC_PS3)			+= zImage.ps3
-image-$(CONFIG_PPC_CELLEB)		+= zImage.pseries
-image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
-image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
-image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
-image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
+# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
+dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
+	,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
 
-# For 32-bit powermacs, build the COFF and miboot images
-# as well as the ELF images.
-ifeq ($(CONFIG_PPC32),y)
-image-$(CONFIG_PPC_PMAC)	+= zImage.coff zImage.miboot
-endif
+$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
+	$(call if_changed,wrap,cuboot-$*,$(dts))
 
-initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y))
+$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
+	$(call if_changed,wrap,treeboot-$*,$(dts))
+
+$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
+	$(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
 
 $(obj)/zImage:		$(addprefix $(obj)/, $(image-y))
 	@rm -f $@; ln $< $@
 $(obj)/zImage.initrd:	$(addprefix $(obj)/, $(initrd-y))
 	@rm -f $@; ln $< $@
 
-install: $(CONFIGURE) $(image-y)
+install: $(CONFIGURE) $(addprefix $(obj)/, $(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)
-clean-files += $(image-)
+# anything not in $(targets)
+clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* \
+	treeImage.*
+
+# clean up files cached by wrapper
+clean-kernel := vmlinux.strip vmlinux.bin
+clean-kernel += $(addsuffix .gz,$(clean-kernel))
+# If not absolute clean-files are relative to $(obj).
+clean-files += $(addprefix $(objtree)/, $(clean-kernel))
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index 70e65b1..5a4215c 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -16,8 +16,11 @@ #include "ppc_asm.h"
 _zimage_start_opd:
 	.long	_zimage_start, 0, 0, 0
 
+	.weak	_zimage_start
 	.globl	_zimage_start
 _zimage_start:
+	.globl	_zimage_start_lib
+_zimage_start_lib:
 	/* Work out the offset between the address we were linked at
 	   and the address where we're running. */
 	bl	1f
@@ -44,7 +47,7 @@ _zimage_start:
 	addi	r9,r9,4
 	bdnz	2b
 
-	/* Do a cache flush for our text, in case OF didn't */
+	/* Do a cache flush for our text, in case the loader didn't */
 3:	lis	r9,_start@ha
 	addi	r9,r9,_start@l
 	add	r9,r0,r9
@@ -59,6 +62,34 @@ _zimage_start:
 	sync
 	isync
 
-	mr	r6,r1
-	b	start
+	/* Clear the BSS */
+	lis	r9,__bss_start@ha
+	addi	r9,r9,__bss_start@l
+	add	r9,r0,r9
+	lis	r8,_end@ha
+	addi	r8,r8,_end@l
+	add	r8,r0,r8
+	li	r10,0
+5:	stw	r10,0(r9)
+	addi	r9,r9,4
+	cmplw	cr0,r9,r8
+	blt	5b
 
+	/* Possibly set up a custom stack */
+.weak	_platform_stack_top
+	lis	r8,_platform_stack_top@ha
+	addi	r8,r8,_platform_stack_top@l
+	cmpwi	r8,0
+	beq	6f
+	add	r8,r0,r8
+	lwz	r1,0(r8)
+	add	r1,r0,r1
+	li	r0,0
+	stwu	r0,-16(r1)	/* establish a stack frame */
+6:
+
+	/* Call platform_init() */
+	bl	platform_init
+
+	/* Call start */
+	b	start
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
new file mode 100644
index 0000000..6cbc20a
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -0,0 +1,68 @@
+/*
+ * Old U-boot compatibility for 83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_83xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+	void *soc;
+
+	dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+	dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+	dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+
+	/* Unfortunately, the specific model number is encoded in the
+	 * soc node name in existing dts files -- once that is fixed,
+	 * this can do a simple path lookup.
+	 */
+	soc = find_node_by_devtype(NULL, "soc");
+	if (soc) {
+		void *serial = NULL;
+
+		setprop(soc, "bus-frequency", &bd.bi_busfreq,
+		        sizeof(bd.bi_busfreq));
+
+		while ((serial = find_node_by_devtype(serial, "serial"))) {
+			if (get_parent(serial) != soc)
+				continue;
+
+			setprop(serial, "clock-frequency", &bd.bi_busfreq,
+			        sizeof(bd.bi_busfreq));
+		}
+	}
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+	unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+	unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+	memcpy(&bd, (bd_t *)r3, sizeof(bd));
+	loader_info.initrd_addr = r4;
+	loader_info.initrd_size = r4 ? r5 : 0;
+	loader_info.cmdline = (char *)r6;
+	loader_info.cmdline_len = r7 - r6;
+
+	simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+	ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+	serial_console_init();
+	platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
new file mode 100644
index 0000000..f88ba00
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-85xx.c
@@ -0,0 +1,69 @@
+/*
+ * Old U-boot compatibility for 85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#define TARGET_85xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+	void *soc;
+
+	dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+	dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr,
+	                       bd.bi_enet2addr);
+	dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 8, bd.bi_busfreq);
+
+	/* Unfortunately, the specific model number is encoded in the
+	 * soc node name in existing dts files -- once that is fixed,
+	 * this can do a simple path lookup.
+	 */
+	soc = find_node_by_devtype(NULL, "soc");
+	if (soc) {
+		void *serial = NULL;
+
+		setprop(soc, "bus-frequency", &bd.bi_busfreq,
+		        sizeof(bd.bi_busfreq));
+
+		while ((serial = find_node_by_devtype(serial, "serial"))) {
+			if (get_parent(serial) != soc)
+				continue;
+
+			setprop(serial, "clock-frequency", &bd.bi_busfreq,
+			        sizeof(bd.bi_busfreq));
+		}
+	}
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+	unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+	unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+	memcpy(&bd, (bd_t *)r3, sizeof(bd));
+	loader_info.initrd_addr = r4;
+	loader_info.initrd_size = r4 ? r5 : 0;
+	loader_info.cmdline = (char *)r6;
+	loader_info.cmdline_len = r7 - r6;
+
+	simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+	ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+	serial_console_init();
+	platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-ebony.c b/arch/powerpc/boot/cuboot-ebony.c
new file mode 100644
index 0000000..4464c5f
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-ebony.c
@@ -0,0 +1,42 @@
+/*
+ * Old U-boot compatibility for Ebony
+ *
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Copyright 2007 David Gibson, IBM Corporatio.
+ *   Based on cuboot-83xx.c, which is:
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "44x.h"
+
+#define TARGET_44x
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+                   unsigned long r6, unsigned long r7)
+{
+	unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+	unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+	memcpy(&bd, (bd_t *)r3, sizeof(bd));
+	loader_info.initrd_addr = r4;
+	loader_info.initrd_size = r4 ? r5 : 0;
+	loader_info.cmdline = (char *)r6;
+	loader_info.cmdline_len = r7 - r6;
+
+	simple_alloc_init(_end, avail_ram, 32, 64);
+
+	ebony_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
+}
diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h
new file mode 100644
index 0000000..877bc97
--- /dev/null
+++ b/arch/powerpc/boot/dcr.h
@@ -0,0 +1,87 @@
+#ifndef _PPC_BOOT_DCR_H_
+#define _PPC_BOOT_DCR_H_
+
+#define mfdcr(rn) \
+	({	\
+		unsigned long rval; \
+		asm volatile("mfdcr %0,%1" : "=r"(rval) : "i"(rn)); \
+		rval; \
+	})
+#define mtdcr(rn, val) \
+	asm volatile("mtdcr %0,%1" : : "i"(rn), "r"(val))
+
+/* 440GP/440GX SDRAM controller DCRs */
+#define DCRN_SDRAM0_CFGADDR				0x010
+#define DCRN_SDRAM0_CFGDATA				0x011
+
+#define 	SDRAM0_B0CR				0x40
+#define 	SDRAM0_B1CR				0x44
+#define 	SDRAM0_B2CR				0x48
+#define 	SDRAM0_B3CR				0x4c
+
+static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2CR, SDRAM0_B3CR };
+
+#define			SDRAM_CONFIG_BANK_ENABLE        0x00000001
+#define			SDRAM_CONFIG_SIZE_MASK          0x000e0000
+#define			SDRAM_CONFIG_BANK_SIZE(reg)	\
+	(0x00400000 << ((reg & SDRAM_CONFIG_SIZE_MASK) >> 17))
+
+/* 440GP Clock, PM, chip control */
+#define DCRN_CPC0_SR					0x0b0
+#define DCRN_CPC0_ER					0x0b1
+#define DCRN_CPC0_FR					0x0b2
+#define DCRN_CPC0_SYS0					0x0e0
+#define	  CPC0_SYS0_TUNE				  0xffc00000
+#define	  CPC0_SYS0_FBDV_MASK				  0x003c0000
+#define	  CPC0_SYS0_FWDVA_MASK				  0x00038000
+#define	  CPC0_SYS0_FWDVB_MASK				  0x00007000
+#define	  CPC0_SYS0_OPDV_MASK				  0x00000c00
+#define	  CPC0_SYS0_EPDV_MASK				  0x00000300
+/* Helper macros to compute the actual clock divider values from the
+ * encodings in the CPC0 register */
+#define	  CPC0_SYS0_FBDV(reg) \
+		((((((reg) & CPC0_SYS0_FBDV_MASK) >> 18) - 1) & 0xf) + 1)
+#define	  CPC0_SYS0_FWDVA(reg) \
+		(8 - (((reg) & CPC0_SYS0_FWDVA_MASK) >> 15))
+#define	  CPC0_SYS0_FWDVB(reg) \
+		(8 - (((reg) & CPC0_SYS0_FWDVB_MASK) >> 12))
+#define	  CPC0_SYS0_OPDV(reg) \
+		((((reg) & CPC0_SYS0_OPDV_MASK) >> 10) + 1)
+#define	  CPC0_SYS0_EPDV(reg) \
+		((((reg) & CPC0_SYS0_EPDV_MASK) >> 8) + 1)
+#define	  CPC0_SYS0_EXTSL				  0x00000080
+#define	  CPC0_SYS0_RW_MASK				  0x00000060
+#define	  CPC0_SYS0_RL					  0x00000010
+#define	  CPC0_SYS0_ZMIISL_MASK				  0x0000000c
+#define	  CPC0_SYS0_BYPASS				  0x00000002
+#define	  CPC0_SYS0_NTO1				  0x00000001
+#define DCRN_CPC0_SYS1					0x0e1
+#define DCRN_CPC0_CUST0					0x0e2
+#define DCRN_CPC0_CUST1					0x0e3
+#define DCRN_CPC0_STRP0					0x0e4
+#define DCRN_CPC0_STRP1					0x0e5
+#define DCRN_CPC0_STRP2					0x0e6
+#define DCRN_CPC0_STRP3					0x0e7
+#define DCRN_CPC0_GPIO					0x0e8
+#define DCRN_CPC0_PLB					0x0e9
+#define DCRN_CPC0_CR1					0x0ea
+#define DCRN_CPC0_CR0					0x0eb
+#define	  CPC0_CR0_SWE					  0x80000000
+#define	  CPC0_CR0_CETE					  0x40000000
+#define	  CPC0_CR0_U1FCS				  0x20000000
+#define	  CPC0_CR0_U0DTE				  0x10000000
+#define	  CPC0_CR0_U0DRE				  0x08000000
+#define	  CPC0_CR0_U0DC					  0x04000000
+#define	  CPC0_CR0_U1DTE				  0x02000000
+#define	  CPC0_CR0_U1DRE				  0x01000000
+#define	  CPC0_CR0_U1DC					  0x00800000
+#define	  CPC0_CR0_U0EC					  0x00400000
+#define	  CPC0_CR0_U1EC					  0x00200000
+#define	  CPC0_CR0_UDIV_MASK				  0x001f0000
+#define	  CPC0_CR0_UDIV(reg) \
+		((((reg) & CPC0_CR0_UDIV_MASK) >> 16) + 1)
+#define DCRN_CPC0_MIRQ0					0x0ec
+#define DCRN_CPC0_MIRQ1					0x0ed
+#define DCRN_CPC0_JTAGID				0x0ef
+
+#endif	/* _PPC_BOOT_DCR_H_ */
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
new file mode 100644
index 0000000..c995155
--- /dev/null
+++ b/arch/powerpc/boot/devtree.c
@@ -0,0 +1,307 @@
+/*
+ * devtree.c - convenience functions for device tree manipulation
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * Authors: David Gibson <david@gibson.dropbear.id.au>
+ *	    Scott Wood <scottwood@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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+void dt_fixup_memory(u64 start, u64 size)
+{
+	void *root, *memory;
+	int naddr, nsize, i;
+	u32 memreg[4];
+
+	root = finddevice("/");
+	if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
+		naddr = 2;
+	if (naddr < 1 || naddr > 2)
+		fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
+
+	if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
+		nsize = 1;
+	if (nsize < 1 || nsize > 2)
+		fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
+
+	i = 0;
+	if (naddr == 2)
+		memreg[i++] = start >> 32;
+	memreg[i++] = start & 0xffffffff;
+	if (nsize == 2)
+		memreg[i++] = size >> 32;
+	memreg[i++] = size & 0xffffffff;
+
+	memory = finddevice("/memory");
+	if (! memory) {
+		memory = create_node(NULL, "memory");
+		setprop_str(memory, "device_type", "memory");
+	}
+
+	printf("Memory <- <0x%x", memreg[0]);
+	for (i = 1; i < (naddr + nsize); i++)
+		printf(" 0x%x", memreg[i]);
+	printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
+
+	setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
+}
+
+#define MHZ(x)	((x + 500000) / 1000000)
+
+void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus)
+{
+	void *devp = NULL;
+
+	printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu));
+	printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb));
+	if (bus > 0)
+		printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
+
+	while ((devp = find_node_by_devtype(devp, "cpu"))) {
+		setprop_val(devp, "clock-frequency", cpu);
+		setprop_val(devp, "timebase-frequency", tb);
+		if (bus > 0)
+			setprop_val(devp, "bus-frequency", bus);
+	}
+}
+
+void dt_fixup_clock(const char *path, u32 freq)
+{
+	void *devp = finddevice(path);
+
+	if (devp) {
+		printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
+		setprop_val(devp, "clock-frequency", freq);
+	}
+}
+
+void __dt_fixup_mac_addresses(u32 startindex, ...)
+{
+	va_list ap;
+	u32 index = startindex;
+	void *devp;
+	const u8 *addr;
+
+	va_start(ap, startindex);
+	while ((addr = va_arg(ap, const u8 *))) {
+		devp = find_node_by_prop_value(NULL, "linux,network-index",
+					       (void*)&index, sizeof(index));
+
+		printf("ENET%d: local-mac-address <-"
+		       " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
+		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+		if (devp)
+			setprop(devp, "local-mac-address", addr, 6);
+
+		index++;
+	}
+	va_end(ap);
+}
+
+#define MAX_ADDR_CELLS 4
+#define MAX_RANGES 8
+
+static void get_reg_format(void *node, u32 *naddr, u32 *nsize)
+{
+	if (getprop(node, "#address-cells", naddr, 4) != 4)
+		*naddr = 2;
+	if (getprop(node, "#size-cells", nsize, 4) != 4)
+		*nsize = 1;
+}
+
+static void copy_val(u32 *dest, u32 *src, int naddr)
+{
+	int pad = MAX_ADDR_CELLS - naddr;
+
+	memset(dest, 0, pad * 4);
+	memcpy(dest + pad, src, naddr * 4);
+}
+
+static int sub_reg(u32 *reg, u32 *sub)
+{
+	int i, borrow = 0;
+
+	for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
+		int prev_borrow = borrow;
+		borrow = reg[i] < sub[i] + prev_borrow;
+		reg[i] -= sub[i] + prev_borrow;
+	}
+
+	return !borrow;
+}
+
+static int add_reg(u32 *reg, u32 *add, int naddr)
+{
+	int i, carry = 0;
+
+	for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
+		u64 tmp = (u64)reg[i] + add[i] + carry;
+		carry = tmp >> 32;
+		reg[i] = (u32)tmp;
+	}
+
+	return !carry;
+}
+
+/* It is assumed that if the first byte of reg fits in a
+ * range, then the whole reg block fits.
+ */
+static int compare_reg(u32 *reg, u32 *range, u32 *rangesize)
+{
+	int i;
+	u32 end;
+
+	for (i = 0; i < MAX_ADDR_CELLS; i++) {
+		if (reg[i] < range[i])
+			return 0;
+		if (reg[i] > range[i])
+			break;
+	}
+
+	for (i = 0; i < MAX_ADDR_CELLS; i++) {
+		end = range[i] + rangesize[i];
+
+		if (reg[i] < end)
+			break;
+		if (reg[i] > end)
+			return 0;
+	}
+
+	return reg[i] != end;
+}
+
+/* reg must be MAX_ADDR_CELLS */
+static int find_range(u32 *reg, u32 *ranges, int nregaddr,
+                      int naddr, int nsize, int buflen)
+{
+	int nrange = nregaddr + naddr + nsize;
+	int i;
+
+	for (i = 0; i + nrange <= buflen; i += nrange) {
+		u32 range_addr[MAX_ADDR_CELLS];
+		u32 range_size[MAX_ADDR_CELLS];
+
+		copy_val(range_addr, ranges + i, naddr);
+		copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
+
+		if (compare_reg(reg, range_addr, range_size))
+			return i;
+	}
+
+	return -1;
+}
+
+/* Currently only generic buses without special encodings are supported.
+ * In particular, PCI is not supported.  Also, only the beginning of the
+ * reg block is tracked; size is ignored except in ranges.
+ */
+static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
+
+static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
+		unsigned long *size)
+{
+	u32 last_addr[MAX_ADDR_CELLS];
+	u32 this_addr[MAX_ADDR_CELLS];
+	void *parent;
+	u64 ret_addr, ret_size;
+	u32 naddr, nsize, prev_naddr;
+	int buflen, offset;
+
+	parent = get_parent(node);
+	if (!parent)
+		return 0;
+
+	get_reg_format(parent, &naddr, &nsize);
+
+	if (nsize > 2)
+		return 0;
+
+	offset = (naddr + nsize) * res;
+
+	if (reglen < offset + naddr + nsize ||
+	    sizeof(dt_xlate_buf) < offset + naddr + nsize)
+		return 0;
+
+	copy_val(last_addr, dt_xlate_buf + offset, naddr);
+
+	ret_size = dt_xlate_buf[offset + naddr];
+	if (nsize == 2) {
+		ret_size <<= 32;
+		ret_size |= dt_xlate_buf[offset + naddr + 1];
+	}
+
+	while ((node = get_parent(node))) {
+		prev_naddr = naddr;
+
+		get_reg_format(node, &naddr, &nsize);
+
+		buflen = getprop(node, "ranges", dt_xlate_buf,
+				sizeof(dt_xlate_buf));
+		if (buflen < 0)
+			continue;
+		if (buflen > sizeof(dt_xlate_buf))
+			return 0;
+
+		offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
+		                    naddr, nsize, buflen / 4);
+
+		if (offset < 0)
+			return 0;
+
+		copy_val(this_addr, dt_xlate_buf + offset, prev_naddr);
+
+		if (!sub_reg(last_addr, this_addr))
+			return 0;
+
+		copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr);
+
+		if (!add_reg(last_addr, this_addr, naddr))
+			return 0;
+	}
+
+	if (naddr > 2)
+		return 0;
+
+	ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
+
+	if (sizeof(void *) == 4 &&
+	    (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
+	     ret_addr + ret_size > 0x100000000ULL))
+		return 0;
+
+	*addr = ret_addr;
+	if (size)
+		*size = ret_size;
+
+	return 1;
+}
+
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
+{
+	int reglen;
+
+	reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4;
+	return dt_xlate(node, res, reglen, addr, size);
+}
+
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
+{
+
+	if (buflen > sizeof(dt_xlate_buf))
+		return 0;
+
+	memcpy(dt_xlate_buf, buf, buflen);
+	return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
+}
diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts
new file mode 100644
index 0000000..b679186
--- /dev/null
+++ b/arch/powerpc/boot/dts/ebony.dts
@@ -0,0 +1,307 @@
+/*
+ * Device Tree Source for IBM Ebony
+ *
+ * Copyright (c) 2006, 2007 IBM Corp.
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>, David Gibson <dwg@au1.ibm.com>
+ *
+ * FIXME: Draft only!
+ *
+ * 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.
+ *
+ * To build:
+ *   dtc -I dts -O asm -o ebony.S -b 0 ebony.dts
+ *   dtc -I dts -O dtb -o ebony.dtb -b 0 ebony.dts
+ */
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	model = "ibm,ebony";
+	compatible = "ibm,ebony";
+	dcr-parent = <&/cpus/PowerPC,440GP@0>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,440GP@0 {
+			device_type = "cpu";
+			reg = <0>;
+			clock-frequency = <0>; // Filled in by zImage
+			timebase-frequency = <0>; // Filled in by zImage
+			i-cache-line-size = <32>;
+			d-cache-line-size = <32>;
+			i-cache-size = <0>;
+			d-cache-size = <0>;
+			dcr-controller;
+			dcr-access-method = "native";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0 0>; // Filled in by zImage
+	};
+
+	UIC0: interrupt-controller0 {
+		device_type = "ibm,uic";
+		compatible = "ibm,uic-440gp", "ibm,uic";
+		interrupt-controller;
+		cell-index = <0>;
+		dcr-reg = <0c0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+
+	};
+
+	UIC1: interrupt-controller1 {
+		device_type = "ibm,uic";
+		compatible = "ibm,uic-440gp", "ibm,uic";
+		interrupt-controller;
+		cell-index = <1>;
+		dcr-reg = <0d0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <1e 4 1f 4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	CPC0: cpc {
+		device_type = "ibm,cpc";
+		compatible = "ibm,cpc-440gp";
+		dcr-reg = <0b0 003 0e0 010>;
+		// FIXME: anything else?
+	};
+
+	plb {
+		device_type = "ibm,plb";
+		compatible = "ibm,plb-440gp", "ibm,plb4";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges;
+		clock-frequency = <0>; // Filled in by zImage
+
+		SDRAM0: sdram {
+			device_type = "memory-controller";
+			compatible = "ibm,sdram-440gp", "ibm,sdram";
+			dcr-reg = <010 2>;
+			// FIXME: anything else?
+		};
+
+		DMA0: dma {
+			// FIXME: ???
+			device_type = "ibm,dma-4xx";
+			compatible = "ibm,dma-440gp", "ibm,dma-4xx";
+			dcr-reg = <100 027>;
+		};
+
+		MAL0: mcmal {
+			device_type = "mcmal-dma";
+			compatible = "ibm,mcmal-440gp", "ibm,mcmal";
+			dcr-reg = <180 62>;
+			num-tx-chans = <4>;
+			num-rx-chans = <4>;
+			interrupt-parent = <&MAL0>;
+			interrupts = <0 1 2 3 4>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-map = </*TXEOB*/ 0 &UIC0 a 4
+					 /*RXEOB*/ 1 &UIC0 b 4
+					 /*SERR*/  2 &UIC1 0 4
+					 /*TXDE*/  3 &UIC1 1 4
+					 /*RXDE*/  4 &UIC1 2 4>;
+			interrupt-map-mask = <ffffffff>;
+		};
+
+		POB0: opb {
+			device_type = "ibm,opb";
+			compatible = "ibm,opb-440gp", "ibm,opb";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			/* Wish there was a nicer way of specifying a full 32-bit
+			   range */
+			ranges = <00000000 1 00000000 80000000
+				  80000000 1 80000000 80000000>;
+			dcr-reg = <090 00b>;
+			interrupt-parent = <&UIC1>;
+			interrupts = <7 4>;
+			clock-frequency = <0>; // Filled in by zImage
+
+			EBC0: ebc {
+				device_type = "ibm,ebc";
+				compatible = "ibm,ebc-440gp";
+				dcr-reg = <012 2>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				clock-frequency = <0>; // Filled in by zImage
+				ranges = <0 00000000 fff00000 100000
+					  1 00000000 48000000 100000
+					  2 00000000 ff800000 400000
+					  3 00000000 48200000 100000
+					  7 00000000 48300000 100000>;
+				interrupts = <5 4>;
+				interrupt-parent = <&UIC1>;
+
+				small-flash@0,0 {
+					device_type = "rom";
+					compatible = "direct-mapped";
+					probe-type = "JEDEC";
+					bank-width = <1>;
+					partitions = <0 80000>;
+					partition-names = "OpenBIOS";
+					reg = <0 80000 80000>;
+				};
+
+				ds1743@1,0 {
+					/* NVRAM & RTC */
+					device_type = "nvram";
+					compatible = "ds1743";
+					reg = <1 0 2000>;
+				};
+
+				large-flash@2,0 {
+					device_type = "rom";
+					compatible = "direct-mapped";
+					probe-type = "JEDEC";
+					bank-width = <1>;
+					partitions = <0 380000
+						      280000 80000>;
+					partition-names = "fs", "firmware";
+					reg = <2 0 400000>;
+				};
+
+				ir@3,0 {
+					reg = <3 0 10>;
+				};
+
+				fpga@7,0 {
+					compatible = "Ebony-FPGA";
+					reg = <7 0 10>;
+				};
+			};
+
+			UART0: serial@40000200 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <40000200 8>;
+				virtual-reg = <e0000200>;
+				clock-frequency = <A8C000>;
+				current-speed = <2580>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0 4>;
+			};
+
+			UART1: serial@40000300 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <40000300 8>;
+				virtual-reg = <e0000300>;
+				clock-frequency = <A8C000>;
+				current-speed = <2580>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <1 4>;
+			};
+
+			IIC0: i2c@40000400 {
+				/* FIXME */
+				device_type = "i2c";
+				compatible = "ibm,iic-440gp", "ibm,iic";
+				reg = <40000400 14>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <2 4>;
+			};
+			IIC1: i2c@40000500 {
+				/* FIXME */
+				device_type = "i2c";
+				compatible = "ibm,iic-440gp", "ibm,iic";
+				reg = <40000500 14>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <3 4>;
+			};
+
+			GPIO0: gpio@40000700 {
+				/* FIXME */
+				device_type = "gpio";
+				compatible = "ibm,gpio-440gp";
+				reg = <40000700 20>;
+			};
+
+			ZMII0: emac-zmii@40000780 {
+				device_type = "emac-zmii";
+				compatible = "ibm,zmii-440gp", "ibm,zmii";
+				reg = <40000780 c>;
+			};
+
+			EMAC0: ethernet@40000800 {
+				linux,network-index = <0>;
+				device_type = "network";
+				compatible = "ibm,emac-440gp", "ibm,emac";
+				interrupt-parent = <&UIC1>;
+				interrupts = <1c 4 1d 4>;
+				reg = <40000800 70>;
+				local-mac-address = [000000000000]; // Filled in by zImage
+				mal-device = <&MAL0>;
+				mal-tx-channel = <0 1>;
+				mal-rx-channel = <0>;
+				cell-index = <0>;
+				max-frame-size = <5dc>;
+				rx-fifo-size = <1000>;
+				tx-fifo-size = <800>;
+				phy-mode = "rmii";
+				phy-map = <00000001>;
+				zmii-device = <&ZMII0>;
+				zmii-channel = <0>;
+			};
+			EMAC1: ethernet@40000900 {
+				linux,network-index = <1>;
+				device_type = "network";
+				compatible = "ibm,emac-440gp", "ibm,emac";
+				interrupt-parent = <&UIC1>;
+				interrupts = <1e 4 1f 4>;
+				reg = <40000900 70>;
+				local-mac-address = [000000000000]; // Filled in by zImage
+				mal-device = <&MAL0>;
+				mal-tx-channel = <2 3>;
+				mal-rx-channel = <1>;
+				cell-index = <1>;
+				max-frame-size = <5dc>;
+				rx-fifo-size = <1000>;
+				tx-fifo-size = <800>;
+				phy-mode = "rmii";
+				phy-map = <00000001>;
+				zmii-device = <&ZMII0>;
+				zmii-channel = <1>;
+			};
+
+
+			GPT0: gpt@40000a00 {
+				/* FIXME */
+				reg = <40000a00 d4>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <12 4 13 4 14 4 15 4 16 4>;
+			};
+
+		};
+
+		PCIX0: pci@1234 {
+			device_type = "pci";
+			/* FIXME */
+			reg = <2 0ec00000 8
+			       2 0ec80000 f0
+			       2 0ec80100 fc>;
+		};
+	};
+
+	chosen {
+		linux,stdout-path = "/plb/opb/serial@40000200";
+//		linux,initrd-start = <0>; /* FIXME */
+//		linux,initrd-end = <0>;
+//		bootargs = "";
+	};
+};
+
diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts
new file mode 100644
index 0000000..254499b
--- /dev/null
+++ b/arch/powerpc/boot/dts/holly.dts
@@ -0,0 +1,198 @@
+/*
+ * Device Tree Source for IBM Holly (PPC 750CL with TSI controller)
+ * Copyright 2007, IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.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.
+ *
+ * To build:
+ *   dtc -I dts -O asm -o holly.S -b 0 holly.dts
+ *   dtc -I dts -O dtb -o holly.dtb -b 0 holly.dts
+ */
+
+/ {
+	model = "41K7339";
+	compatible = "ibm,holly";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells =<0>;
+		PowerPC,750CL@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;
+			i-cache-line-size = <20>;
+			d-cache-size = <8000>;
+			i-cache-size = <8000>;
+			d-cache-sets = <80>;
+			i-cache-sets = <80>;
+			timebase-frequency = <2faf080>;
+			clock-frequency = <23c34600>;
+			bus-frequency = <bebc200>;
+			32-bit;
+		};
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <00000000 20000000>;
+	};
+
+  	tsi109@c0000000 {
+		device_type = "tsi-bridge";
+		compatible = "tsi-bridge";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <00000000 c0000000 00010000>;
+		reg = <c0000000 00010000>;
+
+		i2c@7000 {
+			device_type = "i2c";
+			compatible  = "tsi-i2c";
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <e 2>;
+			reg = <7000 400>;
+		};
+
+		mdio@6000 {
+			device_type = "mdio";
+			compatible = "tsi-ethernet";
+
+			PHY1: ethernet-phy@6000 {
+				device_type = "ethernet-phy";
+				compatible = "bcm54xx";
+				reg = <6000 50>;
+				phy-id = <1>;
+			};
+
+			PHY2: ethernet-phy@6400 {
+				device_type = "ethernet-phy";
+				compatible = "bcm54xx";
+				reg = <6000 50>;
+				phy-id = <2>;
+			};
+		};
+
+		ethernet@6200 {
+			device_type = "network";
+			compatible = "tsi-ethernet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6000 200>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <10 2>;
+			phy-handle = <&PHY1>;
+		};
+
+		ethernet@6600 {
+			device_type = "network";
+			compatible = "tsi-ethernet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <6400 200>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <11 2>;
+			phy-handle = <&PHY2>;
+		};
+
+		serial@7808 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <7808 200>;
+			virtual-reg = <c0007808>;
+			clock-frequency = <3F9C6000>;
+			current-speed = <1c200>;
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <c 2>;
+		};
+
+		serial@7c08 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <7c08 200>;
+			virtual-reg = <c0007c08>;
+			clock-frequency = <3F9C6000>;
+			current-speed = <1c200>;
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <d 2>;
+		};
+
+	  	MPIC: pic@7400 {
+			device_type = "open-pic";
+			compatible = "chrp,open-pic";
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			reg = <7400 400>;
+			big-endian;
+		};
+
+		pci@1000 {
+			device_type = "pci";
+			compatible = "tsi109";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <1000 1000>;
+			bus-range = <0 0>;
+			/*----------------------------------------------------+
+			| PCI memory range.
+			| 01 denotes I/O space
+			| 02 denotes 32-bit memory space
+			+----------------------------------------------------*/
+			ranges = <02000000 0 40000000 40000000 0 10000000
+				  01000000 0 00000000 7e000000 0 00010000>;
+			clock-frequency = <7f28154>;
+			interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			interrupts = <17 2>;
+			interrupt-map-mask = <f800 0 0 7>;
+			/*----------------------------------------------------+
+			| The INTA, INTB, INTC, INTD are shared.
+			+----------------------------------------------------*/
+			interrupt-map = <
+				0800 0 0 1 &RT0 24 0
+				0800 0 0 2 &RT0 25 0
+				0800 0 0 3 &RT0 26 0
+				0800 0 0 4 &RT0 27 0
+
+				1000 0 0 1 &RT0 25 0
+				1000 0 0 2 &RT0 26 0
+				1000 0 0 3 &RT0 27 0
+				1000 0 0 4 &RT0 24 0
+
+				1800 0 0 1 &RT0 26 0
+				1800 0 0 2 &RT0 27 0
+				1800 0 0 3 &RT0 24 0
+				1800 0 0 4 &RT0 25 0
+
+				2000 0 0 1 &RT0 27 0
+				2000 0 0 2 &RT0 24 0
+				2000 0 0 3 &RT0 25 0
+				2000 0 0 4 &RT0 26 0
+				>;
+
+			RT0: router@1180 {
+ 				device_type = "pic-router";
+ 				interrupt-controller;
+ 				big-endian;
+ 				clock-frequency = <0>;
+ 				#address-cells = <0>;
+ 				#interrupt-cells = <2>;
+ 				interrupts = <17 2>;
+				interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+			};
+		};
+	};
+
+	chosen {
+		linux,stdout-path = "/tsi109@c0000000/serial@7808";
+		bootargs = "console=ttyS0,115200";
+	};
+};
diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts
index b897918..157dc98 100644
--- a/arch/powerpc/boot/dts/kuroboxHD.dts
+++ b/arch/powerpc/boot/dts/kuroboxHD.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kur
 
 	cpus {
 		linux,phandle = <2000>;
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kur
 			interrupt-parent = <4400>;
 			interrupt-map-mask = <f800 0 0 7>;
 			interrupt-map = <
-				/* IDSEL 0x11 - IRQ0 ETH */
+				/* IDSEL 11 - IRQ0 ETH */
 				5800 0 0 1 4400 0 1
 				5800 0 0 2 4400 1 1
 				5800 0 0 3 4400 2 1
 				5800 0 0 4 4400 3 1
-				/* IDSEL 0x12 - IRQ1 IDE0 */
+				/* IDSEL 12 - IRQ1 IDE0 */
 				6000 0 0 1 4400 1 1
 				6000 0 0 2 4400 2 1
 				6000 0 0 3 4400 3 1
 				6000 0 0 4 4400 0 1
-				/* IDSEL 0x14 - IRQ3 USB2.0 */
+				/* IDSEL 14 - IRQ3 USB2.0 */
 				7000 0 0 1 4400 3 1
 				7000 0 0 2 4400 3 1
 				7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts
index 7531027..919eb29 100644
--- a/arch/powerpc/boot/dts/kuroboxHG.dts
+++ b/arch/powerpc/boot/dts/kuroboxHG.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kur
 
 	cpus {
 		linux,phandle = <2000>;
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kur
 			interrupt-parent = <4400>;
 			interrupt-map-mask = <f800 0 0 7>;
 			interrupt-map = <
-				/* IDSEL 0x11 - IRQ0 ETH */
+				/* IDSEL 11 - IRQ0 ETH */
 				5800 0 0 1 4400 0 1
 				5800 0 0 2 4400 1 1
 				5800 0 0 3 4400 2 1
 				5800 0 0 4 4400 3 1
-				/* IDSEL 0x12 - IRQ1 IDE0 */
+				/* IDSEL 12 - IRQ1 IDE0 */
 				6000 0 0 1 4400 1 1
 				6000 0 0 2 4400 2 1
 				6000 0 0 3 4400 3 1
 				6000 0 0 4 4400 0 1
-				/* IDSEL 0x14 - IRQ3 USB2.0 */
+				/* IDSEL 14 - IRQ3 USB2.0 */
 				7000 0 0 1 4400 3 1
 				7000 0 0 2 4400 3 1
 				7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index c03103c..e13ac6e 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -24,7 +24,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -49,6 +48,7 @@
 
 	soc5200@f0000000 {
 		model = "fsl,mpc5200";
+		compatible = "mpc5200";
 		revision = ""			// from bootloader
 		#interrupt-cells = <3>;
 		device_type = "soc";
@@ -167,7 +167,7 @@
 			device_type = "mscan";
 			compatible = "mpc5200-mscan";
 			cell-index = <1>;
-			interrupts = <1 12 0>;
+			interrupts = <2 12 0>;
 			interrupt-parent = <500>;
 			reg = <980 80>;
 		};
@@ -179,7 +179,7 @@
 			interrupt-parent = <500>;
 		};
 
-		gpio-wkup@b00 {
+		gpio-wkup@c00 {
 			compatible = "mpc5200-gpio-wkup";
 			reg = <c00 40>;
 			interrupts = <1 8 0 0 3 0>;
@@ -318,20 +318,22 @@
 
 		i2c@3d00 {
 			device_type = "i2c";
-			compatible = "mpc5200-i2c";
+			compatible = "mpc5200-i2c\0fsl-i2c";
 			cell-index = <0>;
 			reg = <3d00 40>;
 			interrupts = <2 f 0>;
 			interrupt-parent = <500>;
+			fsl5200-clocking;
 		};
 
 		i2c@3d40 {
 			device_type = "i2c";
-			compatible = "mpc5200-i2c";
+			compatible = "mpc5200-i2c\0fsl-i2c";
 			cell-index = <1>;
 			reg = <3d40 40>;
 			interrupts = <2 10 0>;
 			interrupt-parent = <500>;
+			fsl5200-clocking;
 		};
 		sram@8000 {
 			device_type = "sram";
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index 3875ca9..00211b3 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -24,7 +24,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -49,6 +48,7 @@
 
 	soc5200@f0000000 {
 		model = "fsl,mpc5200b";
+		compatible = "mpc5200";
 		revision = "";			// from bootloader
 		#interrupt-cells = <3>;
 		device_type = "soc";
@@ -167,7 +167,7 @@
 			device_type = "mscan";
 			compatible = "mpc5200b-mscan\0mpc5200-mscan";
 			cell-index = <1>;
-			interrupts = <1 12 0>;
+			interrupts = <2 12 0>;
 			interrupt-parent = <500>;
 			reg = <980 80>;
 		};
@@ -179,7 +179,7 @@
 			interrupt-parent = <500>;
 		};
 
-		gpio-wkup@b00 {
+		gpio-wkup@c00 {
 			compatible = "mpc5200b-gpio-wkup\0mpc5200-gpio-wkup";
 			reg = <c00 40>;
 			interrupts = <1 8 0 0 3 0>;
@@ -323,20 +323,22 @@
 
 		i2c@3d00 {
 			device_type = "i2c";
-			compatible = "mpc5200b-i2c\0mpc5200-i2c";
+			compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c";
 			cell-index = <0>;
 			reg = <3d00 40>;
 			interrupts = <2 f 0>;
 			interrupt-parent = <500>;
+			fsl5200-clocking;
 		};
 
 		i2c@3d40 {
 			device_type = "i2c";
-			compatible = "mpc5200b-i2c\0mpc5200-i2c";
+			compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c";
 			cell-index = <1>;
 			reg = <3d40 40>;
 			interrupts = <2 10 0>;
 			interrupt-parent = <500>;
+			fsl5200-clocking;
 		};
 		sram@8000 {
 			device_type = "sram";
diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts
index 41d0720..6fa3754 100644
--- a/arch/powerpc/boot/dts/mpc7448hpc2.dts
+++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts
@@ -19,7 +19,6 @@
 	linux,phandle = <100>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells =<0>;
 		linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 260b2e4..423eedc 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -17,7 +17,6 @@
        linux,phandle = <100>;
 
        cpus {
-               #cpus = <1>;
                #address-cells = <1>;
                #size-cells = <0>;
                linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 6d72190..a1533cc 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -16,7 +16,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 06b3106..93b7606 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -16,7 +16,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -307,14 +306,12 @@
 				interrupts = <11 8>;
 				reg = <3>;
 				device_type = "ethernet-phy";
-				interface = <3>; //ENET_100_MII
 			};
 			phy4: ethernet-phy@04 {
 				interrupt-parent = < &ipic >;
 				interrupts = <12 8>;
 				reg = <4>;
 				device_type = "ethernet-phy";
-				interface = <3>;
 			};
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
new file mode 100644
index 0000000..be4c357
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -0,0 +1,289 @@
+/*
+ * MPC832x RDB Device Tree Source
+ *
+ * Copyright 2007 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 = "MPC8323ERDB";
+	compatible = "MPC8323ERDB", "MPC832xRDB", "MPC83xxRDB";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8323@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;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <00000000 04000000>;
+	};
+
+	soc8323@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00000200>;
+		bus-frequency = <0>;
+
+		wdt@200 {
+			device_type = "watchdog";
+			compatible = "mpc83xx_wdt";
+			reg = <200 100>;
+		};
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <e 8>;
+			interrupt-parent = <&pic>;
+			dfsrr;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>;
+			clock-frequency = <0>;
+			interrupts = <9 8>;
+			interrupt-parent = <&pic>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;
+			clock-frequency = <0>;
+			interrupts = <a 8>;
+			interrupt-parent = <&pic>;
+		};
+
+		crypto@30000 {
+			device_type = "crypto";
+			model = "SEC2";
+			compatible = "talitos";
+			reg = <30000 7000>;
+			interrupts = <b 8>;
+			interrupt-parent = <&pic>;
+			/* Rev. 2.2 */
+			num-channels = <1>;
+			channel-fifo-len = <18>;
+			exec-units-mask = <0000004c>;
+			descriptor-types-mask = <0122003f>;
+		};
+
+		pci@8500 {
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+					/* IDSEL 0x10 AD16 (USB) */
+					 8000 0 0 1 &pic 11 8
+
+					/* IDSEL 0x11 AD17 (Mini1)*/
+					 8800 0 0 1 &pic 12 8
+					 8800 0 0 2 &pic 13 8
+					 8800 0 0 3 &pic 14 8
+					 8800 0 0 4 &pic 30 8
+
+					/* IDSEL 0x12 AD18 (PCI/Mini2) */
+					 9000 0 0 1 &pic 13 8
+					 9000 0 0 2 &pic 14 8
+					 9000 0 0 3 &pic 30 8
+					 9000 0 0 4 &pic 11 8>;
+
+			interrupt-parent = <&pic>;
+			interrupts = <42 8>;
+			bus-range = <0 0>;
+			ranges = <42000000 0 80000000 80000000 0 10000000
+			          02000000 0 90000000 90000000 0 10000000
+			          01000000 0 d0000000 d0000000 0 04000000>;
+			clock-frequency = <0>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8500 100>;
+			compatible = "83xx";
+			device_type = "pci";
+		};
+
+		pic:pic@700 {
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <700 100>;
+			built-in;
+			device_type = "ipic";
+		};
+
+		par_io@1400 {
+			reg = <1400 100>;
+			device_type = "par_io";
+			num-ports = <7>;
+
+			ucc2pio:ucc_pin@02 {
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					3  4  3  0  2  0 	/* MDIO */
+					3  5  1  0  2  0 	/* MDC */
+					3 15  2  0  1  0 	/* RX_CLK (CLK16) */
+					3 17  2  0  1  0 	/* TX_CLK (CLK3) */
+					0 12  1  0  1  0 	/* TxD0 */
+					0 13  1  0  1  0 	/* TxD1 */
+					0 14  1  0  1  0 	/* TxD2 */
+					0 15  1  0  1  0 	/* TxD3 */
+					0 16  2  0  1  0 	/* RxD0 */
+					0 17  2  0  1  0 	/* RxD1 */
+					0 18  2  0  1  0 	/* RxD2 */
+					0 19  2  0  1  0 	/* RxD3 */
+					0 1a  2  0  1  0 	/* RX_ER */
+					0 1b  1  0  1  0 	/* TX_ER */
+					0 1c  2  0  1  0 	/* RX_DV */
+					0 1d  2  0  1  0 	/* COL */
+					0 1e  1  0  1  0 	/* TX_EN */
+					0 1f  2  0  1  0>;      /* CRS */
+			};
+			ucc3pio:ucc_pin@03 {
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					0  d  2  0  1  0 	/* RX_CLK (CLK9) */
+					3 18  2  0  1  0 	/* TX_CLK (CLK10) */
+					1  0  1  0  1  0 	/* TxD0 */
+					1  1  1  0  1  0 	/* TxD1 */
+					1  2  1  0  1  0 	/* TxD2 */
+					1  3  1  0  1  0 	/* TxD3 */
+					1  4  2  0  1  0 	/* RxD0 */
+					1  5  2  0  1  0 	/* RxD1 */
+					1  6  2  0  1  0 	/* RxD2 */
+					1  7  2  0  1  0 	/* RxD3 */
+					1  8  2  0  1  0 	/* RX_ER */
+					1  9  1  0  1  0 	/* TX_ER */
+					1  a  2  0  1  0 	/* RX_DV */
+					1  b  2  0  1  0 	/* COL */
+					1  c  1  0  1  0 	/* TX_EN */
+					1  d  2  0  1  0>;      /* CRS */
+			};
+		};
+	};
+
+	qe@e0100000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "qe";
+		model = "QE";
+		ranges = <0 e0100000 00100000>;
+		reg = <e0100000 480>;
+		brg-frequency = <0>;
+		bus-frequency = <BCD3D80>;
+
+		muram@10000 {
+			device_type = "muram";
+			ranges = <0 00010000 00004000>;
+
+			data-only@0 {
+				reg = <0 4000>;
+			};
+		};
+
+		spi@4c0 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <4c0 40>;
+			interrupts = <2>;
+			interrupt-parent = <&qeic>;
+			mode = "cpu";
+		};
+
+		spi@500 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <500 40>;
+			interrupts = <1>;
+			interrupt-parent = <&qeic>;
+			mode = "cpu";
+		};
+
+		ucc@3000 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <2>;
+			reg = <3000 200>;
+			interrupts = <21>;
+			interrupt-parent = <&qeic>;
+			mac-address = [ 00 04 9f ef 03 02 ];
+			rx-clock = <20>;
+			tx-clock = <13>;
+			phy-handle = <&phy00>;
+			pio-handle = <&ucc2pio>;
+		};
+
+		ucc@2200 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <3>;
+			reg = <2200 200>;
+			interrupts = <22>;
+			interrupt-parent = <&qeic>;
+			mac-address = [ 00 04 9f ef 03 01 ];
+			rx-clock = <19>;
+			tx-clock = <1a>;
+			phy-handle = <&phy04>;
+			pio-handle = <&ucc3pio>;
+		};
+
+		mdio@3120 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <3120 18>;
+			device_type = "mdio";
+			compatible = "ucc_geth_phy";
+
+			phy00:ethernet-phy@00 {
+				interrupt-parent = <&pic>;
+				interrupts = <0>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			phy04:ethernet-phy@04 {
+				interrupt-parent = <&pic>;
+				interrupts = <0>;
+				reg = <4>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		qeic:qeic@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 = <&pic>;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 61b550b..db0d003 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -15,7 +15,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index b2e1a5e..f636528 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -15,7 +15,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index e4b43c2..07bcc51 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -16,7 +16,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 4fe45c0..38c8594 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -21,7 +21,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -306,6 +305,7 @@
 			rx-clock = <0>;
 			tx-clock = <19>;
 			phy-handle = < &phy0 >;
+			phy-connection-type = "rgmii-id";
 			pio-handle = < &pio1 >;
 		};
 
@@ -321,6 +321,7 @@
 			rx-clock = <0>;
 			tx-clock = <14>;
 			phy-handle = < &phy1 >;
+			phy-connection-type = "rgmii-id";
 			pio-handle = < &pio2 >;
 		};
 
@@ -336,14 +337,12 @@
 				interrupts = <11 8>;
 				reg = <0>;
 				device_type = "ethernet-phy";
-				interface = <6>; //ENET_1000_GMII
 			};
 			phy1: ethernet-phy@01 {
 				interrupt-parent = < &ipic >;
 				interrupts = <12 8>;
 				reg = <1>;
 				device_type = "ethernet-phy";
-				interface = <6>;
 			};
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 3c0917f..f261d64 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 2a1ae76..5fdcb69 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
new file mode 100644
index 0000000..6b08460
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -0,0 +1,136 @@
+/*
+ * MPC8544 DS Device Tree Source
+ *
+ * Copyright 2007 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 = "MPC8544DS";
+	compatible = "MPC8544DS", "MPC85xxDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8544@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 = <0>;
+			bus-frequency = <0>;
+			clock-frequency = <0>;
+			32-bit;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <00000000 00000000>;	// Filled by U-Boot
+	};
+
+	soc8544@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;		// Filled out by uboot.
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <&mpic>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			phy0: ethernet-phy@0 {
+				interrupt-parent = <&mpic>;
+				interrupts = <3a 1>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			phy1: ethernet-phy@1 {
+				interrupt-parent = <&mpic>;
+				interrupts = <3a 1>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <d 2 e 2 12 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy0>;
+		};
+
+		ethernet@26000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <26000 1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <f 2 10 2 11 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy1>;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>;
+			clock-frequency = <0>;
+			interrupts = <1a 2>;
+			interrupt-parent = <&mpic>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;
+			clock-frequency = <0>;
+			interrupts = <1a 2>;
+			interrupt-parent = <&mpic>;
+		};
+
+		mpic: pic@40000 {
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			big-endian;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 7eb5d81..b2b2200 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 5f9c102..68a4795 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 1050263..1f2afe9 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index bf49d8c..948a3b6 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -21,7 +21,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -289,6 +288,7 @@
 			rx-clock = <0>;
 			tx-clock = <19>;
 			phy-handle = <&qe_phy0>;
+			phy-connection-type = "gmii";
 			pio-handle = <&pio1>;
 		};
 
@@ -304,6 +304,7 @@
 			rx-clock = <0>;
 			tx-clock = <14>;
 			phy-handle = <&qe_phy1>;
+			phy-connection-type = "gmii";
 			pio-handle = <&pio2>;
 		};
 
@@ -321,28 +322,24 @@
 				interrupts = <31 1>;
 				reg = <0>;
 				device_type = "ethernet-phy";
-				interface = <6>; //ENET_1000_GMII
 			};
 			qe_phy1: ethernet-phy@01 {
 				interrupt-parent = <&mpic>;
 				interrupts = <32 1>;
 				reg = <1>;
 				device_type = "ethernet-phy";
-				interface = <6>;
 			};
 			qe_phy2: ethernet-phy@02 {
 				interrupt-parent = <&mpic>;
 				interrupts = <31 1>;
 				reg = <2>;
 				device_type = "ethernet-phy";
-				interface = <6>; //ENET_1000_GMII
 			};
 			qe_phy3: ethernet-phy@03 {
 				interrupt-parent = <&mpic>;
 				interrupts = <32 1>;
 				reg = <3>;
 				device_type = "ethernet-phy";
-				interface = <6>; //ENET_1000_GMII
 			};
 		};
 
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 8a4995a..260b264 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -17,7 +17,6 @@
 	#size-cells = <1>;
 
 	cpus {
-		#cpus = <2>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 
@@ -300,6 +299,30 @@
 			};
 
 		};
+
+		pci@9000 {
+			compatible = "86xx";
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <9000 1000>;
+			bus-range = <0 ff>;
+			ranges = <02000000 0 a0000000 a0000000 0 20000000
+				  01000000 0 00000000 e3000000 0 00100000>;
+			clock-frequency = <1fca055>;
+			interrupt-parent = <&mpic>;
+			interrupts = <19 2>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 44 1
+				0000 0 0 2 &mpic 45 1
+				0000 0 0 3 &mpic 46 1
+				0000 0 0 4 &mpic 47 1
+				>;
+		};
+
 		mpic: pic@40000 {
 			clock-frequency = <0>;
 			interrupt-controller;
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index 2b56b5d..c0d06fd 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -18,7 +18,6 @@
 	linux,phandle = <100>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index faecd08..110bf61 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -18,7 +18,6 @@
 	linux,phandle = <100>;
 
 	cpus {
-		#cpus = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		linux,phandle = <200>;
diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c
new file mode 100644
index 0000000..b1251ee
--- /dev/null
+++ b/arch/powerpc/boot/ebony.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Based on earlier code:
+ *   Copyright (C) Paul Mackerras 1997.
+ *
+ *   Matt Porter <mporter@kernel.crashing.org>
+ *   Copyright 2002-2005 MontaVista Software Inc.
+ *
+ *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *   Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your 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"
+#include "reg.h"
+#include "dcr.h"
+#include "44x.h"
+
+extern char _dtb_start[];
+extern char _dtb_end[];
+
+static u8 *ebony_mac0, *ebony_mac1;
+
+/* Calculate 440GP clocks */
+void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
+{
+	u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
+	u32 cr0 = mfdcr(DCRN_CPC0_CR0);
+	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
+	u32 opdv = CPC0_SYS0_OPDV(sys0);
+	u32 epdv = CPC0_SYS0_EPDV(sys0);
+
+	if (sys0 & CPC0_SYS0_BYPASS) {
+		/* Bypass system PLL */
+		cpu = plb = sysclk;
+	} else {
+		if (sys0 & CPC0_SYS0_EXTSL)
+			/* PerClk */
+			m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
+		else
+			/* CPU clock */
+			m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
+		cpu = sysclk * m / CPC0_SYS0_FWDVA(sys0);
+		plb = sysclk * m / CPC0_SYS0_FWDVB(sys0);
+	}
+
+	opb = plb / opdv;
+	ebc = opb / epdv;
+
+	/* FIXME: Check if this is for all 440GP, or just Ebony */
+	if ((mfpvr() & 0xf0000fff) == 0x40000440)
+		/* Rev. B 440GP, use external system clock */
+		tb = sysclk;
+	else
+		/* Rev. C 440GP, errata force us to use internal clock */
+		tb = cpu;
+
+	if (cr0 & CPC0_CR0_U0EC)
+		/* External UART clock */
+		uart0 = ser_clk;
+	else
+		/* Internal UART clock */
+		uart0 = plb / CPC0_CR0_UDIV(cr0);
+
+	if (cr0 & CPC0_CR0_U1EC)
+		/* External UART clock */
+		uart1 = ser_clk;
+	else
+		/* Internal UART clock */
+		uart1 = plb / CPC0_CR0_UDIV(cr0);
+
+	printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
+	       (sysclk + 500000) / 1000000, sysclk);
+
+	dt_fixup_cpu_clocks(cpu, tb, 0);
+
+	dt_fixup_clock("/plb", plb);
+	dt_fixup_clock("/plb/opb", opb);
+	dt_fixup_clock("/plb/opb/ebc", ebc);
+	dt_fixup_clock("/plb/opb/serial@40000200", uart0);
+	dt_fixup_clock("/plb/opb/serial@40000300", uart1);
+}
+
+static void ebony_fixups(void)
+{
+	// FIXME: sysclk should be derived by reading the FPGA registers
+	unsigned long sysclk = 33000000;
+
+	ibm440gp_fixup_clocks(sysclk, 6 * 1843200);
+	ibm44x_fixup_memsize();
+	dt_fixup_mac_addresses(ebony_mac0, ebony_mac1);
+}
+
+#define SPRN_DBCR0		0x134
+#define   DBCR0_RST_SYSTEM	0x30000000
+
+static void ebony_exit(void)
+{
+	unsigned long tmp;
+
+	asm volatile (
+		"mfspr	%0,%1\n"
+		"oris	%0,%0,%2@h\n"
+		"mtspr	%1,%0"
+		: "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM)
+		);
+
+}
+
+void ebony_init(void *mac0, void *mac1)
+{
+	platform_ops.fixups = ebony_fixups;
+	platform_ops.exit = ebony_exit;
+	ebony_mac0 = mac0;
+	ebony_mac1 = mac1;
+	ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+	serial_console_init();
+}
diff --git a/arch/powerpc/boot/elf.h b/arch/powerpc/boot/elf.h
index d4828fc..1941bc5 100644
--- a/arch/powerpc/boot/elf.h
+++ b/arch/powerpc/boot/elf.h
@@ -146,4 +146,12 @@ #define EV_NUM		2
 #define ELFOSABI_NONE	0
 #define ELFOSABI_LINUX	3
 
+struct elf_info {
+	unsigned long loadsize;
+	unsigned long memsize;
+	unsigned long elfoffset;
+};
+int parse_elf64(void *hdr, struct elf_info *info);
+int parse_elf32(void *hdr, struct elf_info *info);
+
 #endif				/* _PPC_BOOT_ELF_H_ */
diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c
new file mode 100644
index 0000000..7454aa4
--- /dev/null
+++ b/arch/powerpc/boot/elf_util.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+
+int parse_elf64(void *hdr, struct elf_info *info)
+{
+	Elf64_Ehdr *elf64 = hdr;
+	Elf64_Phdr *elf64ph;
+	unsigned int i;
+
+	if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0	&&
+	      elf64->e_ident[EI_MAG1]  == ELFMAG1	&&
+	      elf64->e_ident[EI_MAG2]  == ELFMAG2	&&
+	      elf64->e_ident[EI_MAG3]  == ELFMAG3	&&
+	      elf64->e_ident[EI_CLASS] == ELFCLASS64	&&
+	      elf64->e_ident[EI_DATA]  == ELFDATA2MSB	&&
+	      elf64->e_type            == ET_EXEC	&&
+	      elf64->e_machine         == EM_PPC64))
+		return 0;
+
+	elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
+				 (unsigned long)elf64->e_phoff);
+	for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
+		if (elf64ph->p_type == PT_LOAD)
+			break;
+	if (i >= (unsigned int)elf64->e_phnum)
+		return 0;
+
+	info->loadsize = (unsigned long)elf64ph->p_filesz;
+	info->memsize = (unsigned long)elf64ph->p_memsz;
+	info->elfoffset = (unsigned long)elf64ph->p_offset;
+
+	return 1;
+}
+
+int parse_elf32(void *hdr, struct elf_info *info)
+{
+	Elf32_Ehdr *elf32 = hdr;
+	Elf32_Phdr *elf32ph;
+	unsigned int i;
+
+	if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0	&&
+	      elf32->e_ident[EI_MAG1]  == ELFMAG1	&&
+	      elf32->e_ident[EI_MAG2]  == ELFMAG2	&&
+	      elf32->e_ident[EI_MAG3]  == ELFMAG3	&&
+	      elf32->e_ident[EI_CLASS] == ELFCLASS32	&&
+	      elf32->e_ident[EI_DATA]  == ELFDATA2MSB	&&
+	      elf32->e_type            == ET_EXEC	&&
+	      elf32->e_machine         == EM_PPC))
+		return 0;
+
+	elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
+	for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
+		if (elf32ph->p_type == PT_LOAD)
+			break;
+	if (i >= elf32->e_phnum)
+		return 0;
+
+	info->loadsize = elf32ph->p_filesz;
+	info->memsize = elf32ph->p_memsz;
+	info->elfoffset = elf32ph->p_offset;
+	return 1;
+}
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
index c76c194..d00fbd9 100644
--- a/arch/powerpc/boot/flatdevtree.c
+++ b/arch/powerpc/boot/flatdevtree.c
@@ -29,12 +29,20 @@ #include "flatdevtree_env.h"
 
 #define _ALIGN(x, al)	(((x) + (al) - 1) & ~((al) - 1))
 
+static char *ft_root_node(struct ft_cxt *cxt)
+{
+	return cxt->rgn[FT_STRUCT].start;
+}
+
 /* Routines for keeping node ptrs returned by ft_find_device current */
 /* First entry not used b/c it would return 0 and be taken as NULL/error */
-static void *ft_node_add(struct ft_cxt *cxt, char *node)
+static void *ft_get_phandle(struct ft_cxt *cxt, char *node)
 {
 	unsigned int i;
 
+	if (!node)
+		return NULL;
+
 	for (i = 1; i < cxt->nodes_used; i++)	/* already there? */
 		if (cxt->node_tbl[i] == node)
 			return (void *)i;
@@ -238,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt
 			if (rgn == FT_STRUCT)
 				ft_node_update_before(cxt, p, -nextra);
 		}
-		*p -= nextra;
+		*pp -= nextra;
 		cxt->rgn[rgn].start -= nextra;
 		cxt->rgn[rgn].size += nextra;
 		return 1;
@@ -253,8 +261,14 @@ static int ft_make_space(struct ft_cxt *
 	char *str, *next;
 	enum ft_rgn_id r;
 
-	if (!cxt->isordered && !ft_reorder(cxt, nextra))
-		return 0;
+	if (!cxt->isordered) {
+		unsigned long rgn_off = *pp - cxt->rgn[rgn].start;
+
+		if (!ft_reorder(cxt, nextra))
+			return 0;
+
+		*pp = cxt->rgn[rgn].start + rgn_off;
+	}
 	if (ft_shuffle(cxt, pp, rgn, nextra))
 		return 1;
 
@@ -415,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const ch
 {
 	int off, len;
 
-	off = lookup_string(cxt, name);
+	off = map_string(cxt, name);
 	if (off == NO_STRING)
 		return -1;
 
@@ -590,7 +604,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u6
 
 void ft_begin_tree(struct ft_cxt *cxt)
 {
-	cxt->p = cxt->rgn[FT_STRUCT].start;
+	cxt->p = ft_root_node(cxt);
 }
 
 void ft_end_tree(struct ft_cxt *cxt)
@@ -636,8 +650,21 @@ void *ft_find_device(struct ft_cxt *cxt,
 	/* require absolute path */
 	if (srch_path[0] != '/')
 		return NULL;
-	node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path);
-	return ft_node_add(cxt, node);
+	node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path);
+	return ft_get_phandle(cxt, node);
+}
+
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+                         const char *srch_path)
+{
+	char *node;
+
+	node = ft_node_ph2node(cxt, top);
+	if (node == NULL)
+		return NULL;
+
+	node = ft_find_descendent(cxt, node, srch_path);
+	return ft_get_phandle(cxt, node);
 }
 
 void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
@@ -701,23 +728,18 @@ void *ft_find_descendent(struct ft_cxt *
 	return NULL;
 }
 
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+void *__ft_get_parent(struct ft_cxt *cxt, void *node)
 {
-	void *node;
 	int d;
 	struct ft_atom atom;
 	char *p;
 
-	node = ft_node_ph2node(cxt, phandle);
-	if (node == NULL)
-		return NULL;
-
 	for (d = 0; cxt->genealogy[d] != NULL; ++d)
 		if (cxt->genealogy[d] == node)
-			return cxt->genealogy[d > 0 ? d - 1 : 0];
+			return d > 0 ? cxt->genealogy[d - 1] : NULL;
 
 	/* have to do it the hard way... */
-	p = cxt->rgn[FT_STRUCT].start;
+	p = ft_root_node(cxt);
 	d = 0;
 	while ((p = ft_next(cxt, p, &atom)) != NULL) {
 		switch (atom.tag) {
@@ -726,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, 
 			if (node == atom.data) {
 				/* found it */
 				cxt->genealogy[d + 1] = NULL;
-				return d > 0 ? cxt->genealogy[d - 1] : node;
+				return d > 0 ? cxt->genealogy[d - 1] : NULL;
 			}
 			++d;
 			break;
@@ -738,41 +760,131 @@ void *ft_get_parent(struct ft_cxt *cxt, 
 	return NULL;
 }
 
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
-		void *buf, const unsigned int buflen)
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
 {
-	struct ft_atom atom;
-	void *node;
-	char *p;
-	int depth;
-	unsigned int size;
-
-	node = ft_node_ph2node(cxt, phandle);
+	void *node = ft_node_ph2node(cxt, phandle);
 	if (node == NULL)
-		return -1;
+		return NULL;
 
-	depth = 0;
-	p = (char *)node;
+	node = __ft_get_parent(cxt, node);
+	return ft_get_phandle(cxt, node);
+}
 
-	while ((p = ft_next(cxt, p, &atom)) != NULL) {
+static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
+                                 const char *propname, unsigned int *len)
+{
+	struct ft_atom atom;
+	int depth = 0;
+
+	while ((node = ft_next(cxt, node, &atom)) != NULL) {
 		switch (atom.tag) {
 		case OF_DT_BEGIN_NODE:
 			++depth;
 			break;
+
 		case OF_DT_PROP:
-			if ((depth != 1) || strcmp(atom.name, propname))
+			if (depth != 1 || strcmp(atom.name, propname))
 				break;
-			size = min(atom.size, buflen);
-			memcpy(buf, atom.data, size);
-			return atom.size;
+
+			if (len)
+				*len = atom.size;
+
+			return atom.data;
+
 		case OF_DT_END_NODE:
 			if (--depth <= 0)
-				return -1;
+				return NULL;
 		}
 	}
+
+	return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+		void *buf, const unsigned int buflen)
+{
+	const void *data;
+	unsigned int size;
+
+	void *node = ft_node_ph2node(cxt, phandle);
+	if (!node)
+		return -1;
+
+	data = __ft_get_prop(cxt, node, propname, &size);
+	if (data) {
+		unsigned int clipped_size = min(size, buflen);
+		memcpy(buf, data, clipped_size);
+		return size;
+	}
+
 	return -1;
 }
 
+void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
+                                   const char *propname, const char *propval,
+                                   unsigned int proplen)
+{
+	struct ft_atom atom;
+	char *p = ft_root_node(cxt);
+	char *next;
+	int past_prev = prev ? 0 : 1;
+	int depth = -1;
+
+	while ((next = ft_next(cxt, p, &atom)) != NULL) {
+		const void *data;
+		unsigned int size;
+
+		switch (atom.tag) {
+		case OF_DT_BEGIN_NODE:
+			depth++;
+
+			if (prev == p) {
+				past_prev = 1;
+				break;
+			}
+
+			if (!past_prev || depth < 1)
+				break;
+
+			data = __ft_get_prop(cxt, p, propname, &size);
+			if (!data || size != proplen)
+				break;
+			if (memcmp(data, propval, size))
+				break;
+
+			return p;
+
+		case OF_DT_END_NODE:
+			if (depth-- == 0)
+				return NULL;
+
+			break;
+		}
+
+		p = next;
+	}
+
+	return NULL;
+}
+
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+                                 const char *propname, const char *propval,
+                                 int proplen)
+{
+	void *node = NULL;
+
+	if (prev) {
+		node = ft_node_ph2node(cxt, prev);
+
+		if (!node)
+			return NULL;
+	}
+
+	node = __ft_find_node_by_prop_value(cxt, node, propname,
+	                                    propval, proplen);
+	return ft_get_phandle(cxt, node);
+}
+
 int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
 		const void *buf, const unsigned int buflen)
 {
@@ -849,19 +961,26 @@ int ft_del_prop(struct ft_cxt *cxt, cons
 	return -1;
 }
 
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
 {
 	struct ft_atom atom;
 	char *p, *next;
 	int depth = 0;
 
-	p = cxt->rgn[FT_STRUCT].start;
+	if (parent) {
+		p = ft_node_ph2node(cxt, parent);
+		if (!p)
+			return NULL;
+	} else {
+		p = ft_root_node(cxt);
+	}
+
 	while ((next = ft_next(cxt, p, &atom)) != NULL) {
 		switch (atom.tag) {
 		case OF_DT_BEGIN_NODE:
 			++depth;
-			if (depth == 1 && strcmp(atom.name, path) == 0)
-				/* duplicate node path, return error */
+			if (depth == 1 && strcmp(atom.name, name) == 0)
+				/* duplicate node name, return error */
 				return NULL;
 			break;
 		case OF_DT_END_NODE:
@@ -870,7 +989,7 @@ void *ft_create_node(struct ft_cxt *cxt,
 				break;
 			/* end of node, insert here */
 			cxt->p = p;
-			ft_begin_node(cxt, path);
+			ft_begin_node(cxt, name);
 			ft_end_node(cxt);
 			return p;
 		}
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
index b9cd9f6..cb26325 100644
--- a/arch/powerpc/boot/flatdevtree.h
+++ b/arch/powerpc/boot/flatdevtree.h
@@ -97,10 +97,17 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u6
 void ft_dump_blob(const void *bphp);
 void ft_merge_blob(struct ft_cxt *cxt, void *blob);
 void *ft_find_device(struct ft_cxt *cxt, const char *srch_path);
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+                         const char *srch_path);
 void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
 int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
 		void *buf, const unsigned int buflen);
 int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
 		const void *buf, const unsigned int buflen);
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle);
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+                                 const char *propname, const char *propval,
+                                 int proplen);
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name);
 
 #endif /* FLATDEVTREE_H */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
index 04da38f..4341e65 100644
--- a/arch/powerpc/boot/flatdevtree_misc.c
+++ b/arch/powerpc/boot/flatdevtree_misc.c
@@ -16,24 +16,43 @@ #include "ops.h"
 
 static struct ft_cxt cxt;
 
-static void *ft_finddevice(const char *name)
+static void *fdtm_finddevice(const char *name)
 {
 	return ft_find_device(&cxt, name);
 }
 
-static int ft_getprop(const void *phandle, const char *propname, void *buf,
-		const int buflen)
+static int fdtm_getprop(const void *phandle, const char *propname,
+                        void *buf, const int buflen)
 {
 	return ft_get_prop(&cxt, phandle, propname, buf, buflen);
 }
 
-static int ft_setprop(const void *phandle, const char *propname,
-		const void *buf, const int buflen)
+static int fdtm_setprop(const void *phandle, const char *propname,
+                        const void *buf, const int buflen)
 {
 	return ft_set_prop(&cxt, phandle, propname, buf, buflen);
 }
 
-static unsigned long ft_finalize(void)
+static void *fdtm_get_parent(const void *phandle)
+{
+	return ft_get_parent(&cxt, phandle);
+}
+
+static void *fdtm_create_node(const void *phandle, const char *name)
+{
+	return ft_create_node(&cxt, phandle, name);
+}
+
+static void *fdtm_find_node_by_prop_value(const void *prev,
+                                          const char *propname,
+                                          const char *propval,
+                                          int proplen)
+{
+	return ft_find_node_by_prop_value(&cxt, prev, propname,
+	                                  propval, proplen);
+}
+
+static unsigned long fdtm_finalize(void)
 {
 	ft_end_tree(&cxt);
 	return (unsigned long)cxt.bph;
@@ -41,10 +60,13 @@ static unsigned long ft_finalize(void)
 
 int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
 {
-	dt_ops.finddevice = ft_finddevice;
-	dt_ops.getprop = ft_getprop;
-	dt_ops.setprop = ft_setprop;
-	dt_ops.finalize = ft_finalize;
+	dt_ops.finddevice = fdtm_finddevice;
+	dt_ops.getprop = fdtm_getprop;
+	dt_ops.setprop = fdtm_setprop;
+	dt_ops.get_parent = fdtm_get_parent;
+	dt_ops.create_node = fdtm_create_node;
+	dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value;
+	dt_ops.finalize = fdtm_finalize;
 
 	return ft_open(&cxt, dt_blob, max_size, max_find_device,
 			platform_ops.realloc);
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
new file mode 100644
index 0000000..df8ab07
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on earlier work, 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 <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+/**
+ * gunzip_start - prepare to decompress gzip data
+ * @state:     decompressor state structure to be initialized
+ * @src:       buffer containing gzip compressed or uncompressed data
+ * @srclen:    size in bytes of the buffer at src
+ *
+ * If the buffer at @src contains a gzip header, this function
+ * initializes zlib to decompress the data, storing the decompression
+ * state in @state.  The other functions in this file can then be used
+ * to decompress data from the gzipped stream.
+ *
+ * If the buffer at @src does not contain a gzip header, it is assumed
+ * to contain uncompressed data.  The buffer information is recorded
+ * in @state and the other functions in this file will simply copy
+ * data from the uncompressed data stream at @src.
+ *
+ * Any errors, such as bad compressed data, cause an error to be
+ * printed an the platform's exit() function to be called.
+ */
+void gunzip_start(struct gunzip_state *state, void *src, int srclen)
+{
+	char *hdr = src;
+	int hdrlen = 0;
+
+	memset(state, 0, sizeof(*state));
+
+	/* Check for gzip magic number */
+	if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
+		/* gzip data, initialize zlib parameters */
+		int r, flags;
+
+		state->s.workspace = state->scratch;
+		if (zlib_inflate_workspacesize() > sizeof(state->scratch))
+			fatal("insufficient scratch space for gunzip\n\r");
+
+		/* skip header */
+		hdrlen = 10;
+		flags = hdr[3];
+		if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
+			fatal("bad gzipped data\n\r");
+		if ((flags & EXTRA_FIELD) != 0)
+			hdrlen = 12 + hdr[10] + (hdr[11] << 8);
+		if ((flags & ORIG_NAME) != 0)
+			while (hdr[hdrlen++] != 0)
+				;
+		if ((flags & COMMENT) != 0)
+			while (hdr[hdrlen++] != 0)
+				;
+		if ((flags & HEAD_CRC) != 0)
+			hdrlen += 2;
+		if (hdrlen >= srclen)
+			fatal("gunzip_start: ran out of data in header\n\r");
+
+		r = zlib_inflateInit2(&state->s, -MAX_WBITS);
+		if (r != Z_OK)
+			fatal("inflateInit2 returned %d\n\r", r);
+	}
+
+	state->s.next_in = src + hdrlen;
+	state->s.avail_in = srclen - hdrlen;
+}
+
+/**
+ * gunzip_partial - extract bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    maximum number of bytes to extract
+ *
+ * This function extracts at most @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.  Exactly @dstlen bytes are extracted unless the data
+ * stream doesn't contain enough bytes, in which case the entire
+ * remainder of the stream is decompressed.
+ *
+ * Returns the actual number of bytes extracted.  If any errors occur,
+ * such as a corrupted compressed stream, an error is printed an the
+ * platform's exit() function is called.
+ */
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	if (state->s.workspace) {
+		/* gunzipping */
+		int r;
+
+		state->s.next_out = dst;
+		state->s.avail_out = dstlen;
+		r = zlib_inflate(&state->s, Z_FULL_FLUSH);
+		if (r != Z_OK && r != Z_STREAM_END)
+			fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
+		len = state->s.next_out - (unsigned char *)dst;
+	} else {
+		/* uncompressed image */
+		len = min(state->s.avail_in, (unsigned)dstlen);
+		memcpy(dst, state->s.next_in, len);
+		state->s.next_in += len;
+		state->s.avail_in -= len;
+	}
+	return len;
+}
+
+/**
+ * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    number of bytes to extract
+ *
+ * This function extracts exactly @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.
+ *
+ * If there are less @dstlen bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	len  = gunzip_partial(state, dst, dstlen);
+	if (len < dstlen)
+		fatal("\n\rgunzip_exactly: ran out of data!"
+				" Wanted %d, got %d.\n\r", dstlen, len);
+}
+
+/**
+ * gunzip_discard - discard bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @len:       number of bytes to discard
+ *
+ * This function extracts, then discards exactly @len bytes from the
+ * data stream previously associated with @state by gunzip_start().
+ * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
+ * calls will extract the data following the discarded bytes in the
+ * data stream.
+ *
+ * If there are less @len bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_discard(struct gunzip_state *state, int len)
+{
+	static char discard_buf[128];
+
+	while (len > sizeof(discard_buf)) {
+		gunzip_exactly(state, discard_buf, sizeof(discard_buf));
+		len -= sizeof(discard_buf);
+	}
+
+	if (len > 0)
+		gunzip_exactly(state, discard_buf, len);
+}
+
+/**
+ * gunzip_finish - extract all remaining bytes from a gzip data stream
+ * @state:     gzip state structure previously initialized by gunzip_start()
+ * @dst:       buffer to store extracted data
+ * @dstlen:    maximum number of bytes to extract
+ *
+ * This function extracts all remaining data, or at most @dstlen
+ * bytes, from the stream previously associated with @state by
+ * gunzip_start().  zlib is then shut down, so it is an error to use
+ * any of the functions in this file on @state until it is
+ * re-initialized with another call to gunzip_start().
+ *
+ * If any errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
+{
+	int len;
+
+	if (state->s.workspace) {
+		len = gunzip_partial(state, dst, dstlen);
+		zlib_inflateEnd(&state->s);
+	} else {
+		/* uncompressed image */
+		len = min(state->s.avail_in, (unsigned)dstlen);
+		memcpy(dst, state->s.next_in, len);
+	}
+
+	return len;
+}
diff --git a/arch/powerpc/boot/gunzip_util.h b/arch/powerpc/boot/gunzip_util.h
new file mode 100644
index 0000000..b3dfa6e
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.h
@@ -0,0 +1,45 @@
+/*
+ * Decompression convenience functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * 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_GUNZIP_UTIL_H_
+#define _PPC_BOOT_GUNZIP_UTIL_H_
+
+#include "zlib.h"
+
+/*
+ * These functions are designed to make life easy for decompressing
+ * kernel images, initrd images or any other gzip compressed image,
+ * particularly if its useful to decompress part of the image (e.g. to
+ * examine headers) before decompressing the remainder.
+ *
+ * To use:
+ *     - declare a gunzip_state structure
+ *     - use gunzip_start() to initialize the state, associating it
+ *       with a stream of compressed data
+ *     - use gunzip_partial(), gunzip_exactly() and gunzip_discard()
+ *       in any combination to extract pieces of data from the stream
+ *     - Finally use gunzip_finish() to extract the tail of the
+ *       compressed stream and wind up zlib
+ */
+
+/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
+#define GUNZIP_SCRATCH_SIZE	46912
+
+struct gunzip_state {
+	z_stream s;
+	char scratch[46912];
+};
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen);
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
+void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
+void gunzip_discard(struct gunzip_state *state, int len);
+int gunzip_finish(struct gunzip_state *state, void *dst, int len);
+
+#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
diff --git a/arch/powerpc/boot/holly.c b/arch/powerpc/boot/holly.c
new file mode 100644
index 0000000..7d6539f
--- /dev/null
+++ b/arch/powerpc/boot/holly.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007 IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * Based on earlier code:
+ * 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
+ * version 2 as published by the Free Software Foundation.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+#include "io.h"
+
+extern char _start[];
+extern char _end[];
+extern char _dtb_start[];
+extern char _dtb_end[];
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
+{
+	u32 heapsize = 0x8000000 - (u32)_end; /* 128M */
+
+	simple_alloc_init(_end, heapsize, 32, 64);
+	ft_init(_dtb_start, 0, 4);
+	serial_console_init();
+}
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 6f6b50d..56b56a8 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -14,11 +14,10 @@ #include "elf.h"
 #include "page.h"
 #include "string.h"
 #include "stdio.h"
-#include "zlib.h"
 #include "ops.h"
+#include "gunzip_util.h"
 #include "flatdevtree.h"
-
-extern void flush_cache(void *, unsigned long);
+#include "reg.h"
 
 extern char _start[];
 extern char __bss_start[];
@@ -30,304 +29,173 @@ extern char _initrd_end[];
 extern char _dtb_start[];
 extern char _dtb_end[];
 
+static struct gunzip_state gzstate;
+
 struct addr_range {
-	unsigned long addr;
+	void *addr;
 	unsigned long size;
-	unsigned long memsize;
 };
-static struct addr_range vmlinux;
-static struct addr_range vmlinuz;
-static struct addr_range initrd;
-
-static unsigned long elfoffset;
-static int is_64bit;
-
-/* 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 *);
 
 #undef DEBUG
 
-#define HEAD_CRC	2
-#define EXTRA_FIELD	4
-#define ORIG_NAME	8
-#define COMMENT		0x10
-#define RESERVED	0xe0
-
-static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static struct addr_range prep_kernel(void)
 {
-	z_stream s;
-	int r, i, flags;
-
-	/* skip header */
-	i = 10;
-	flags = src[3];
-	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
-		printf("bad gzipped data\n\r");
-		exit();
-	}
-	if ((flags & EXTRA_FIELD) != 0)
-		i = 12 + src[10] + (src[11] << 8);
-	if ((flags & ORIG_NAME) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & COMMENT) != 0)
-		while (src[i++] != 0)
-			;
-	if ((flags & HEAD_CRC) != 0)
-		i += 2;
-	if (i >= *lenp) {
-		printf("gunzip: ran out of data in header\n\r");
-		exit();
-	}
+	char elfheader[256];
+	void *vmlinuz_addr = _vmlinux_start;
+	unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+	void *addr = 0;
+	struct elf_info ei;
+	int len;
 
-	if (zlib_inflate_workspacesize() > sizeof(scratch)) {
-		printf("gunzip needs more mem\n");
-		exit();
-	}
-	memset(&s, 0, sizeof(s));
-	s.workspace = scratch;
-	r = zlib_inflateInit2(&s, -MAX_WBITS);
-	if (r != Z_OK) {
-		printf("inflateInit2 returned %d\n\r", r);
-		exit();
-	}
-	s.next_in = src + i;
-	s.avail_in = *lenp - i;
-	s.next_out = dst;
-	s.avail_out = dstlen;
-	r = zlib_inflate(&s, Z_FULL_FLUSH);
-	if (r != Z_OK && r != Z_STREAM_END) {
-		printf("inflate returned %d msg: %s\n\r", r, s.msg);
-		exit();
+	/* gunzip the ELF header of the kernel */
+	gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+	if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
+		fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
+
+	if (platform_ops.image_hdr)
+		platform_ops.image_hdr(elfheader);
+
+	/* We need to alloc the memsize: gzip will expand the kernel
+	 * text/data, 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", ei.memsize);
+
+	if (platform_ops.vmlinux_alloc) {
+		addr = platform_ops.vmlinux_alloc(ei.memsize);
+	} else {
+		if ((unsigned long)_start < ei.memsize)
+			fatal("Insufficient memory for kernel at address 0!"
+			       " (_start=%p)\n\r", _start);
 	}
-	*lenp = s.next_out - (unsigned char *) dst;
-	zlib_inflateEnd(&s);
-}
 
-static int is_elf64(void *hdr)
-{
-	Elf64_Ehdr *elf64 = hdr;
-	Elf64_Phdr *elf64ph;
-	unsigned int i;
-
-	if (!(elf64->e_ident[EI_MAG0]  == ELFMAG0	&&
-	      elf64->e_ident[EI_MAG1]  == ELFMAG1	&&
-	      elf64->e_ident[EI_MAG2]  == ELFMAG2	&&
-	      elf64->e_ident[EI_MAG3]  == ELFMAG3	&&
-	      elf64->e_ident[EI_CLASS] == ELFCLASS64	&&
-	      elf64->e_ident[EI_DATA]  == ELFDATA2MSB	&&
-	      elf64->e_type            == ET_EXEC	&&
-	      elf64->e_machine         == EM_PPC64))
-		return 0;
-
-	elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
-				 (unsigned long)elf64->e_phoff);
-	for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
-		if (elf64ph->p_type == PT_LOAD)
-			break;
-	if (i >= (unsigned int)elf64->e_phnum)
-		return 0;
-
-	elfoffset = (unsigned long)elf64ph->p_offset;
-	vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
-	vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
-
-	is_64bit = 1;
-	return 1;
-}
+	/* Finally, gunzip the kernel */
+	printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
+	       vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
+	/* discard up to the actual load data */
+	gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
+	len = gunzip_finish(&gzstate, addr, ei.loadsize);
+	if (len != ei.loadsize)
+		fatal("ran out of data!  only got 0x%x of 0x%lx bytes.\n\r",
+				len, ei.loadsize);
+	printf("done 0x%x bytes\n\r", len);
 
-static int is_elf32(void *hdr)
-{
-	Elf32_Ehdr *elf32 = hdr;
-	Elf32_Phdr *elf32ph;
-	unsigned int i;
-
-	if (!(elf32->e_ident[EI_MAG0]  == ELFMAG0	&&
-	      elf32->e_ident[EI_MAG1]  == ELFMAG1	&&
-	      elf32->e_ident[EI_MAG2]  == ELFMAG2	&&
-	      elf32->e_ident[EI_MAG3]  == ELFMAG3	&&
-	      elf32->e_ident[EI_CLASS] == ELFCLASS32	&&
-	      elf32->e_ident[EI_DATA]  == ELFDATA2MSB	&&
-	      elf32->e_type            == ET_EXEC	&&
-	      elf32->e_machine         == EM_PPC))
-		return 0;
-
-	elf32 = (Elf32_Ehdr *)elfheader;
-	elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
-	for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
-		if (elf32ph->p_type == PT_LOAD)
-			break;
-	if (i >= elf32->e_phnum)
-		return 0;
-
-	elfoffset = elf32ph->p_offset;
-	vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
-	vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
-	return 1;
+	flush_cache(addr, ei.loadsize);
+
+	return (struct addr_range){addr, ei.memsize};
 }
 
-static void prep_kernel(unsigned long a1, unsigned long a2)
+static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
+				     unsigned long initrd_addr,
+				     unsigned long initrd_size)
 {
-	int len;
-
-	vmlinuz.addr = (unsigned long)_vmlinux_start;
-	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
-
-	/* gunzip the ELF header of the kernel */
-	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-		len = vmlinuz.size;
-		gunzip(elfheader, sizeof(elfheader),
-				(unsigned char *)vmlinuz.addr, &len);
-	} else
-		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 we have an image attached to us, it overrides anything
+	 * supplied by the loader. */
+	if (_initrd_end > _initrd_start) {
+		printf("Attached initrd image at 0x%p-0x%p\n\r",
+		       _initrd_start, _initrd_end);
+		initrd_addr = (unsigned long)_initrd_start;
+		initrd_size = _initrd_end - _initrd_start;
+	} else if (initrd_size > 0) {
+		printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r",
+		       initrd_addr, initrd_addr + initrd_size);
 	}
-	if (platform_ops.image_hdr)
-		platform_ops.image_hdr(elfheader);
 
-	/* 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 = (unsigned long)malloc(vmlinux.memsize);
-	if (vmlinux.addr == 0) {
-		printf("Can't allocate memory for kernel image !\n\r");
-		exit();
-	}
+	/* If there's no initrd at all, we're done */
+	if (! initrd_size)
+		return (struct addr_range){0, 0};
 
 	/*
-	 * Now find the initrd
-	 *
-	 * First see if we have an image attached to us.  If so
-	 * allocate memory for it and copy it there.
+	 * If the initrd is too low it will be clobbered when the
+	 * kernel relocates to its final location.  In this case,
+	 * allocate a safer place and move it.
 	 */
-	initrd.size = (unsigned long)(_initrd_end - _initrd_start);
-	initrd.memsize = initrd.size;
-	if (initrd.size > 0) {
+	if (initrd_addr < vmlinux.size) {
+		void *old_addr = (void *)initrd_addr;
+
 		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");
-			exit();
-		}
-		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));
-	} else if (a2 != 0) {
-		/* Otherwise, see if yaboot or another loader gave us an initrd */
-		initrd.addr = a1;
-		initrd.memsize = initrd.size = a2;
-		printf("Using loader supplied initrd at 0x%lx (0x%lx bytes)\n\r",
-		       initrd.addr, initrd.size);
+		       initrd_size);
+		initrd_addr = (unsigned long)malloc(initrd_size);
+		if (! initrd_addr)
+			fatal("Can't allocate memory for initial "
+			       "ramdisk !\n\r");
+		printf("Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r",
+		       initrd_addr, old_addr, initrd_size);
+		memmove((void *)initrd_addr, old_addr, initrd_size);
 	}
 
-	/* Eventually gunzip the kernel */
-	if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
-		printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
-		       vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
-		len = vmlinuz.size;
-		gunzip((void *)vmlinux.addr, vmlinux.memsize,
-			(unsigned char *)vmlinuz.addr, &len);
-		printf("done 0x%lx bytes\n\r", len);
-	} else {
-		memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
-			vmlinuz.size);
-	}
+	printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd_addr));
 
-	/* Skip over the ELF header */
-#ifdef DEBUG
-	printf("... skipping 0x%lx bytes of ELF header\n\r",
-			elfoffset);
-#endif
-	vmlinux.addr += elfoffset;
+	/* Tell the kernel initrd address via device tree */
+	setprop_val(chosen, "linux,initrd-start", (u32)(initrd_addr));
+	setprop_val(chosen, "linux,initrd-end", (u32)(initrd_addr+initrd_size));
 
-	flush_cache((void *)vmlinux.addr, vmlinux.size);
+	return (struct addr_range){(void *)initrd_addr, initrd_size};
 }
 
 /* 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]
+static char cmdline[COMMAND_LINE_SIZE]
 	__attribute__((__section__("__builtin_cmdline")));
 
-static void get_cmdline(char *buf, int size)
+static void prep_cmdline(void *chosen)
 {
-	void *devp;
-	int len = strlen(builtin_cmdline);
-
-	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);
-}
+	if (cmdline[0] == '\0')
+		getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
 
-static void set_cmdline(char *buf)
-{
-	void *devp;
+	printf("\n\rLinux/PowerPC load: %s", cmdline);
+	/* If possible, edit the command line */
+	if (console_ops.edit_cmdline)
+		console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+	printf("\n\r");
 
-	if ((devp = finddevice("/chosen")))
-		setprop(devp, "bootargs", buf, strlen(buf) + 1);
+	/* Put the command line back into the devtree for the kernel */
+	setprop_str(chosen, "bootargs", cmdline);
 }
 
 struct platform_ops platform_ops;
 struct dt_ops dt_ops;
 struct console_ops console_ops;
+struct loader_info loader_info;
 
-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+void start(void)
 {
+	struct addr_range vmlinux, initrd;
 	kernel_entry_t kentry;
-	char cmdline[COMMAND_LINE_SIZE];
 	unsigned long ft_addr = 0;
+	void *chosen;
 
-	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));
+	/* Do this first, because malloc() could clobber the loader's
+	 * command line.  Only use the loader command line if a
+	 * built-in command line wasn't set by an external tool */
+	if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+		memmove(cmdline, loader_info.cmdline,
+			min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
 
-	if (platform_init(promptr, _dtb_start, _dtb_end))
-		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);
+	       _start, get_sp());
 
-	prep_kernel(a1, a2);
+	/* Ensure that the device tree has a /chosen node */
+	chosen = finddevice("/chosen");
+	if (!chosen)
+		chosen = create_node(NULL, "chosen");
 
-	/* 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);
-	}
+	vmlinux = prep_kernel();
+	initrd = prep_initrd(vmlinux, chosen,
+			     loader_info.initrd_addr, loader_info.initrd_size);
+	prep_cmdline(chosen);
 
 	printf("Finalizing device tree...");
 	if (dt_ops.finalize)
@@ -335,7 +203,7 @@ void start(unsigned long a1, unsigned lo
 	if (ft_addr)
 		printf(" flat tree at 0x%lx\n\r", ft_addr);
 	else
-		printf(" using OF tree (promptr=%p)\n\r", promptr);
+		printf(" using OF tree (promptr=%p)\n\r", loader_info.promptr);
 
 	if (console_ops.close)
 		console_ops.close();
@@ -344,10 +212,9 @@ void start(unsigned long a1, unsigned lo
 	if (ft_addr)
 		kentry(ft_addr, 0, NULL);
 	else
-		/* XXX initrd addr/size should be passed in properties */
-		kentry(initrd.addr, initrd.size, promptr);
+		kentry((unsigned long)initrd.addr, initrd.size,
+		       loader_info.promptr);
 
-	/* console closed so printf below may not work */
-	printf("Error: Linux kernel returned to zImage boot wrapper!\n\r");
-	exit();
+	/* console closed so printf in fatal below may not work */
+	fatal("Error: Linux kernel returned to zImage boot wrapper!\n\r");
 }
diff --git a/arch/powerpc/boot/mktree.c b/arch/powerpc/boot/mktree.c
index 4cb8929..45d06a8 100644
--- a/arch/powerpc/boot/mktree.c
+++ b/arch/powerpc/boot/mktree.c
@@ -46,8 +46,8 @@ int main(int argc, char *argv[])
 	struct	stat	st;
 	boot_block_t	bt;
 
-	if (argc < 3) {
-		fprintf(stderr, "usage: %s <zImage-file> <boot-image> [entry-point]\n",argv[0]);
+	if (argc < 5) {
+		fprintf(stderr, "usage: %s <zImage-file> <boot-image> <load address> <entry point>\n",argv[0]);
 		exit(1);
 	}
 
@@ -61,10 +61,8 @@ int main(int argc, char *argv[])
 	bt.bb_magic = htonl(0x0052504F);
 
 	/* If we have the optional entry point parameter, use it */
-	if (argc == 4)
-		bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0));
-	else
-		bt.bb_dest = bt.bb_entry_point = htonl(0x500000);
+	bt.bb_dest = htonl(strtoul(argv[3], NULL, 0));
+	bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0));
 
 	/* We know these from the linker command.
 	 * ...and then move it up into memory a little more so the
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
index 1ffe72e..f8f1b2f 100644
--- a/arch/powerpc/boot/ns16550.c
+++ b/arch/powerpc/boot/ns16550.c
@@ -55,10 +55,15 @@ static u8 ns16550_tstc(void)
 int ns16550_console_init(void *devp, struct serial_console_data *scdp)
 {
 	int n;
+	unsigned long reg_phys;
 
 	n = getprop(devp, "virtual-reg", &reg_base, sizeof(reg_base));
-	if (n != sizeof(reg_base))
-		return -1;
+	if (n != sizeof(reg_base)) {
+		if (!dt_xlate_reg(devp, 0, &reg_phys, NULL))
+			return -1;
+
+		reg_base = (void *)reg_phys;
+	}
 
 	n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
 	if (n != sizeof(reg_shift))
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index 0182f38..d16ee3e 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -173,7 +173,7 @@ static void *claim(unsigned long virt, u
 	return (void *) virt;
 }
 
-static void *of_try_claim(u32 size)
+static void *of_try_claim(unsigned long size)
 {
 	unsigned long addr = 0;
 
@@ -208,6 +208,16 @@ static void of_image_hdr(const void *hdr
 	}
 }
 
+static void *of_vmlinux_alloc(unsigned long size)
+{
+	void *p = malloc(size);
+
+	if (!p)
+		fatal("Can't allocate memory for kernel image!\n\r");
+
+	return p;
+}
+
 static void of_exit(void)
 {
 	call_prom("exit", 0, 0);
@@ -256,11 +266,12 @@ static void of_console_write(char *buf, 
 	call_prom("write", 3, 1, of_stdout_handle, buf, len);
 }
 
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
+void platform_init(unsigned long a1, unsigned long a2, void *promptr)
 {
 	platform_ops.image_hdr = of_image_hdr;
 	platform_ops.malloc = of_try_claim;
 	platform_ops.exit = of_exit;
+	platform_ops.vmlinux_alloc = of_vmlinux_alloc;
 
 	dt_ops.finddevice = of_finddevice;
 	dt_ops.getprop = of_getprop;
@@ -270,5 +281,9 @@ int platform_init(void *promptr, char *d
 	console_ops.write = of_console_write;
 
 	prom = (int (*)(void *))promptr;
-	return 0;
+	loader_info.promptr = promptr;
+	if (a1 && a2 && a2 != 0xdeadbeef) {
+		loader_info.initrd_addr = a1;
+		loader_info.initrd_size = a2;
+	}
 }
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 8abb651..73bd47a 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -11,7 +11,9 @@
 #ifndef _PPC_BOOT_OPS_H_
 #define _PPC_BOOT_OPS_H_
 
+#include <stddef.h>
 #include "types.h"
+#include "string.h"
 
 #define	COMMAND_LINE_SIZE	512
 #define	MAX_PATH_LEN		256
@@ -21,10 +23,11 @@ #define	MAX_PROP_LEN		256 /* What should
 struct platform_ops {
 	void	(*fixups)(void);
 	void	(*image_hdr)(const void *);
-	void *	(*malloc)(u32 size);
+	void *	(*malloc)(unsigned long size);
 	void	(*free)(void *ptr);
 	void *	(*realloc)(void *ptr, unsigned long size);
 	void	(*exit)(void);
+	void *	(*vmlinux_alloc)(unsigned long size);
 };
 extern struct platform_ops platform_ops;
 
@@ -35,6 +38,12 @@ struct dt_ops {
 			const int buflen);
 	int	(*setprop)(const void *phandle, const char *name,
 			const void *buf, const int buflen);
+	void *(*get_parent)(const void *phandle);
+	/* The node must not already exist. */
+	void *(*create_node)(const void *parent, const char *name);
+	void *(*find_node_by_prop_value)(const void *prev,
+	                                 const char *propname,
+	                                 const char *propval, int proplen);
 	unsigned long (*finalize)(void);
 };
 extern struct dt_ops dt_ops;
@@ -58,13 +67,23 @@ struct serial_console_data {
 	void		(*close)(void);
 };
 
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end);
+struct loader_info {
+	void *promptr;
+	unsigned long initrd_addr, initrd_size;
+	char *cmdline;
+	int cmdline_len;
+};
+extern struct loader_info loader_info;
+
+void start(void);
 int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
 int serial_console_init(void);
 int ns16550_console_init(void *devp, struct serial_console_data *scdp);
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
-		u32 max_allocs);
-
+void *simple_alloc_init(char *base, unsigned long heap_size,
+			unsigned long granularity, unsigned long max_allocs);
+extern void flush_cache(void *, unsigned long);
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
 
 static inline void *finddevice(const char *name)
 {
@@ -76,12 +95,76 @@ static inline int getprop(void *devp, co
 	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)
+static inline int setprop(void *devp, const char *name,
+                          const void *buf, int buflen)
 {
 	return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
 }
+#define setprop_val(devp, name, val) \
+	do { \
+		typeof(val) x = (val); \
+		setprop((devp), (name), &x, sizeof(x)); \
+	} while (0)
+
+static inline int setprop_str(void *devp, const char *name, const char *buf)
+{
+	if (dt_ops.setprop)
+		return dt_ops.setprop(devp, name, buf, strlen(buf) + 1);
+
+	return -1;
+}
+
+static inline void *get_parent(const char *devp)
+{
+	return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL;
+}
+
+static inline void *create_node(const void *parent, const char *name)
+{
+	return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL;
+}
+
 
-static inline void *malloc(u32 size)
+static inline void *find_node_by_prop_value(const void *prev,
+                                            const char *propname,
+                                            const char *propval, int proplen)
+{
+	if (dt_ops.find_node_by_prop_value)
+		return dt_ops.find_node_by_prop_value(prev, propname,
+		                                      propval, proplen);
+
+	return NULL;
+}
+
+static inline void *find_node_by_prop_value_str(const void *prev,
+                                                const char *propname,
+                                                const char *propval)
+{
+	return find_node_by_prop_value(prev, propname, propval,
+	                               strlen(propval) + 1);
+}
+
+static inline void *find_node_by_devtype(const void *prev,
+                                         const char *type)
+{
+	return find_node_by_prop_value_str(prev, "device_type", type);
+}
+
+void dt_fixup_memory(u64 start, u64 size);
+void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq);
+void dt_fixup_clock(const char *path, u32 freq);
+void __dt_fixup_mac_addresses(u32 startindex, ...);
+#define dt_fixup_mac_addresses(...) \
+	__dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+
+
+static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
+{
+	return find_node_by_prop_value(NULL, "linux,phandle",
+			(char *)&linuxphandle, sizeof(u32));
+}
+
+static inline void *malloc(unsigned long size)
 {
 	return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
 }
@@ -98,5 +181,11 @@ static inline void exit(void)
 		platform_ops.exit();
 	for(;;);
 }
+#define fatal(args...) { printf(args); exit(); }
+
+
+#define BSS_STACK(size) \
+	static char _bss_stack[size]; \
+	void *_platform_stack_top = _bss_stack + sizeof(_bss_stack);
 
 #endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h
new file mode 100644
index 0000000..5290ff2
--- /dev/null
+++ b/arch/powerpc/boot/ppcboot.h
@@ -0,0 +1,108 @@
+/*
+ * This interface is used for compatibility with old U-boots *ONLY*.
+ * Please do not imitate or extend this.
+ */
+
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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
+ */
+
+#ifndef __PPCBOOT_H__
+#define __PPCBOOT_H__
+
+/*
+ * Board information passed to kernel from PPCBoot
+ *
+ * include/asm-ppc/ppcboot.h
+ */
+
+#include "types.h"
+
+typedef struct bd_info {
+	unsigned long	bi_memstart;	/* start of DRAM memory */
+	unsigned long	bi_memsize;	/* size	 of DRAM memory in bytes */
+	unsigned long	bi_flashstart;	/* start of FLASH memory */
+	unsigned long	bi_flashsize;	/* size	 of FLASH memory */
+	unsigned long	bi_flashoffset; /* reserved area for startup monitor */
+	unsigned long	bi_sramstart;	/* start of SRAM memory */
+	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
+#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
+	defined(TARGET_83xx)
+	unsigned long	bi_immr_base;	/* base of IMMR register */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+	unsigned long   bi_mbar_base;   /* base of internal registers */
+#endif
+	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
+	unsigned long	bi_ip_addr;	/* IP Address */
+	unsigned char	bi_enetaddr[6];	/* Ethernet address */
+	unsigned short	bi_ethspeed;	/* Ethernet speed in Mbps */
+	unsigned long	bi_intfreq;	/* Internal Freq, in MHz */
+	unsigned long	bi_busfreq;	/* Bus Freq, in MHz */
+#if defined(TARGET_CPM2)
+	unsigned long	bi_cpmfreq;	/* CPM_CLK Freq, in MHz */
+	unsigned long	bi_brgfreq;	/* BRG_CLK Freq, in MHz */
+	unsigned long	bi_sccfreq;	/* SCC_CLK Freq, in MHz */
+	unsigned long	bi_vco;		/* VCO Out from PLL, in MHz */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+	unsigned long   bi_ipbfreq;     /* IPB Bus Freq, in MHz */
+	unsigned long   bi_pcifreq;     /* PCI Bus Freq, in MHz */
+#endif
+	unsigned long	bi_baudrate;	/* Console Baudrate */
+#if defined(TARGET_4xx)
+	unsigned char	bi_s_version[4];	/* Version of this structure */
+	unsigned char	bi_r_version[32];	/* Version of the ROM (IBM) */
+	unsigned int	bi_procfreq;	/* CPU (Internal) Freq, in Hz */
+	unsigned int	bi_plb_busfreq;	/* PLB Bus speed, in Hz */
+	unsigned int	bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+	unsigned char	bi_pci_enetaddr[6];	/* PCI Ethernet MAC address */
+#endif
+#if defined(TARGET_HYMOD)
+	hymod_conf_t	bi_hymod_conf;	/* hymod configuration information */
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
+	defined(TARGET_85xx) ||	defined(TARGET_83xx)
+	/* second onboard ethernet port */
+	unsigned char	bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx)
+	/* third onboard ethernet ports */
+	unsigned char	bi_enet2addr[6];
+#define HAVE_ENET2ADDR
+#endif
+#if defined(TARGET_440GX)
+	/* fourth onboard ethernet ports */
+	unsigned char	bi_enet3addr[6];
+#define HAVE_ENET3ADDR
+#endif
+#if defined(TARGET_4xx)
+	unsigned int	bi_opbfreq;		/* OB clock in Hz */
+	int		bi_iic_fast[2];		/* Use fast i2c mode */
+#endif
+#if defined(TARGET_440GX)
+	int		bi_phynum[4];		/* phy mapping */
+	int		bi_phymode[4];		/* phy mode */
+#endif
+} bd_t;
+
+#define bi_tbfreq	bi_intfreq
+
+#endif	/* __PPCBOOT_H__ */
diff --git a/arch/powerpc/boot/reg.h b/arch/powerpc/boot/reg.h
new file mode 100644
index 0000000..d3cd9ee
--- /dev/null
+++ b/arch/powerpc/boot/reg.h
@@ -0,0 +1,22 @@
+#ifndef _PPC_BOOT_REG_H
+#define _PPC_BOOT_REG_H
+/*
+ * Copyright 2007 Davud Gibson, 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.
+ */
+
+static inline u32 mfpvr(void)
+{
+	u32 pvr;
+	asm volatile ("mfpvr	%0" : "=r"(pvr));
+	return pvr;
+}
+
+register void *__stack_pointer asm("r1");
+#define get_sp()	(__stack_pointer)
+
+#endif	/* _PPC_BOOT_REG_H */
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c
index cfe3a75..65ec135 100644
--- a/arch/powerpc/boot/simple_alloc.c
+++ b/arch/powerpc/boot/simple_alloc.c
@@ -19,24 +19,24 @@ #define	ENTRY_BEEN_USED	0x01
 #define	ENTRY_IN_USE	0x02
 
 static struct alloc_info {
-	u32	flags;
-	u32	base;
-	u32	size;
+	unsigned long	flags;
+	unsigned long	base;
+	unsigned long	size;
 } *alloc_tbl;
 
-static u32 tbl_entries;
-static u32 alloc_min;
-static u32 next_base;
-static u32 space_left;
+static unsigned long tbl_entries;
+static unsigned long alloc_min;
+static unsigned long next_base;
+static unsigned long space_left;
 
 /*
  * First time an entry is used, its base and size are set.
  * An entry can be freed and re-malloc'd but its base & size don't change.
  * Should be smart enough for needs of bootwrapper.
  */
-static void *simple_malloc(u32 size)
+static void *simple_malloc(unsigned long size)
 {
-	u32 i;
+	unsigned long i;
 	struct alloc_info *p = alloc_tbl;
 
 	if (size == 0)
@@ -67,13 +67,14 @@ err_out:
 
 static struct alloc_info *simple_find_entry(void *ptr)
 {
-	u32 i;
+	unsigned long i;
 	struct alloc_info *p = alloc_tbl;
 
 	for (i=0; i<tbl_entries; i++,p++) {
 		if (!(p->flags & ENTRY_BEEN_USED))
 			break;
-		if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr))
+		if ((p->flags & ENTRY_IN_USE) &&
+		    (p->base == (unsigned long)ptr))
 			return p;
 	}
 	return NULL;
@@ -122,10 +123,10 @@ static void *simple_realloc(void *ptr, u
  * Returns addr of first byte after heap so caller can see if it took
  * too much space.  If so, change args & try again.
  */
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
-		u32 max_allocs)
+void *simple_alloc_init(char *base, unsigned long heap_size,
+			unsigned long granularity, unsigned long max_allocs)
 {
-	u32 heap_base, tbl_size;
+	unsigned long heap_base, tbl_size;
 
 	heap_size = _ALIGN_UP(heap_size, granularity);
 	alloc_min = granularity;
@@ -136,7 +137,7 @@ void *simple_alloc_init(char *base, u32 
 	alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
 	memset(alloc_tbl, 0, tbl_size);
 
-	heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
+	heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min);
 
 	next_base = heap_base;
 	space_left = heap_size;
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
index 73b8a91..adffc58 100644
--- a/arch/powerpc/boot/stdio.h
+++ b/arch/powerpc/boot/stdio.h
@@ -7,11 +7,12 @@ #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, ...);
+extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 
 #define fprintf(fmt, args...)	printf(args)
 
-extern int sprintf(char *buf, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...)
+	__attribute__((format(printf, 2, 3)));
 
 extern int vsprintf(char *buf, const char *fmt, va_list args);
 
diff --git a/arch/powerpc/boot/treeboot-ebony.c b/arch/powerpc/boot/treeboot-ebony.c
new file mode 100644
index 0000000..8436a9c
--- /dev/null
+++ b/arch/powerpc/boot/treeboot-ebony.c
@@ -0,0 +1,34 @@
+/*
+ * Old U-boot compatibility for Ebony
+ *
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Copyright 2007 David Gibson, IBM Corporatio.
+ *   Based on cuboot-83xx.c, which is:
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "44x.h"
+
+extern char _end[];
+
+BSS_STACK(4096);
+
+#define OPENBIOS_MAC_BASE	0xfffffe0c
+#define OPENBIOS_MAC_OFFSET	0xc
+
+void platform_init(void)
+{
+	unsigned long end_of_ram = 0x8000000;
+	unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+	simple_alloc_init(_end, avail_ram, 32, 64);
+	ebony_init((u8 *)OPENBIOS_MAC_BASE,
+		   (u8 *)(OPENBIOS_MAC_BASE + OPENBIOS_MAC_OFFSET));
+}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 024e4d4..2ed8b8b 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -29,6 +29,7 @@ initrd=
 dtb=
 dts=
 cacheit=
+gzip=.gz
 
 # cross-compilation prefix
 CROSS=
@@ -42,7 +43,7 @@ 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
+    echo '       [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2
     exit 1
 }
 
@@ -91,6 +92,9 @@ while [ "$#" -gt 0 ]; do
 	[ "$#" -gt 0 ] || usage
 	tmpdir="$1"
 	;;
+    --no-gzip)
+        gzip=
+        ;;
     -?)
 	usage
 	;;
@@ -137,31 +141,43 @@ miboot|uboot)
     ksection=image
     isection=initrd
     ;;
+cuboot*)
+    gzip=
+    ;;
 esac
 
 vmz="$tmpdir/`basename \"$kernel\"`.$ext"
-if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then
+if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then
     ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
-    gzip -f -9 "$vmz.$$"
+
+    if [ -n "$gzip" ]; then
+        gzip -f -9 "$vmz.$$"
+    fi
+
     if [ -n "$cacheit" ]; then
-	mv -f "$vmz.$$.gz" "$vmz.gz"
+	mv -f "$vmz.$$$gzip" "$vmz$gzip"
     else
 	vmz="$vmz.$$"
     fi
 fi
 
+vmz="$vmz$gzip"
+
+# Extract kernel version information, some platforms want to include
+# it in the image header
+version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
+    cut -d' ' -f3`
+if [ -n "$version" ]; then
+    uboot_version="-n Linux-$version"
+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"
+	$uboot_version -d "$vmz" "$ofile"
     if [ -z "$cacheit" ]; then
-	rm -f $vmz.gz
+	rm -f "$vmz"
     fi
     exit 0
     ;;
@@ -173,9 +189,9 @@ addsec() {
 	--set-section-flags=$3=contents,alloc,load,readonly,data
 }
 
-addsec $tmp "$vmz.gz" $ksection $object/empty.o
+addsec $tmp "$vmz" $ksection $object/empty.o
 if [ -z "$cacheit" ]; then
-    rm -f "$vmz.gz"
+    rm -f "$vmz"
 fi
 
 if [ -n "$initrd" ]; then
@@ -191,17 +207,36 @@ fi
 
 if [ "$platform" != "miboot" ]; then
     ${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \
-	$object/crt0.o $platformo $tmp $object/wrapper.a
+	$platformo $tmp $object/wrapper.a
     rm $tmp
 fi
 
+# Some platforms need the zImage's entry point and base address
+base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1`
+entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
+
 # post-processing needed for some platforms
 case "$platform" in
 pseries|chrp)
     $object/addnote "$ofile"
     ;;
 pmaccoff)
-    ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile"
+    ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
     $object/hack-coff "$ofile"
     ;;
+cuboot*)
+    mv "$ofile" "$ofile".elf
+    ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
+    gzip -f -9 "$ofile".bin
+    mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
+            $uboot_version -d "$ofile".bin.gz "$ofile"
+    ;;
+treeboot*)
+    mv "$ofile" "$ofile.elf"
+    $object/mktree "$ofile.elf" "$ofile" "$base" "$entry"
+    if [ -z "$cacheit" ]; then
+	rm -f "$ofile.elf"
+    fi
+    exit 0
+    ;;
 esac
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
index a360905..fe87a90 100644
--- a/arch/powerpc/boot/zImage.coff.lds.S
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -1,5 +1,6 @@
 OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
+ENTRY(_zimage_start_opd)
+EXTERN(_zimage_start_opd)
 SECTIONS
 {
   . = (5*1024*1024);
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index 4be3c64..f6e380f 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -1,5 +1,6 @@
 OUTPUT_ARCH(powerpc:common)
 ENTRY(_zimage_start)
+EXTERN(_zimage_start)
 SECTIONS
 {
   . = (4*1024*1024);
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index cf7e316..6061e5f 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.21-rc3
-# Fri Mar  9 23:34:53 2007
+# Linux kernel version: 2.6.21-rc6
+# Mon Apr 23 20:46:48 2007
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -139,11 +139,31 @@ # CONFIG_PPC_MPC5200 is not set
 # CONFIG_PPC_PMAC is not set
 # CONFIG_PPC_MAPLE is not set
 # CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
 CONFIG_PPC_CELL=y
 CONFIG_PPC_CELL_NATIVE=y
 CONFIG_PPC_IBM_CELL_BLADE=y
-CONFIG_PPC_PS3=y
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=m
+CONFIG_SPU_BASE=y
+CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
 CONFIG_PPC_NATIVE=y
 CONFIG_UDBG_RTAS_CONSOLE=y
 CONFIG_PPC_UDBG_BEAT=y
@@ -175,26 +195,6 @@ # CONFIG_WANT_EARLY_SERIAL is not set
 CONFIG_MPIC=y
 
 #
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=m
-CONFIG_SPU_BASE=y
-CONFIG_CBE_RAS=y
-CONFIG_CBE_THERM=m
-CONFIG_CBE_CPUFREQ=m
-
-#
-# PS3 Platform Options
-#
-# CONFIG_PS3_ADVANCED is not set
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
-CONFIG_PS3_SYS_MANAGER=y
-
-#
 # Kernel options
 #
 # CONFIG_HZ_100 is not set
@@ -534,7 +534,6 @@ CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_AEC62XX=y
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -561,11 +560,10 @@ # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+CONFIG_BLK_DEV_CELLEB=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
 
 #
@@ -937,7 +935,7 @@ CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_HVC_DRIVER=y
 CONFIG_HVC_RTAS=y
-# CONFIG_HVC_BEAT is not set
+CONFIG_HVC_BEAT=y
 
 #
 # IPMI
@@ -1482,6 +1480,8 @@ #
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
 
 #
 # Library routines
@@ -1540,6 +1540,7 @@ # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
diff --git a/arch/powerpc/configs/ebony_defconfig b/arch/powerpc/configs/ebony_defconfig
new file mode 100644
index 0000000..c3b96ef
--- /dev/null
+++ b/arch/powerpc/configs/ebony_defconfig
@@ -0,0 +1,905 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21
+# Fri May  4 13:47:08 2007
+#
+# 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_ARCH_HAS_ILOG2_U32=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_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+CONFIG_NOT_COHERENT_CACHE=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_SYSVIPC_SYSCTL=y
+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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=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 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=y
+# 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"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_EBONY=y
+CONFIG_440GP=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPM2 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=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 is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_SECCOMP=y
+CONFIG_WANT_DEVICE_TREE=y
+CONFIG_DEVICE_TREE="ebony.dts"
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+# CONFIG_PPC_INDIRECT_PCI_BE is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG 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_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x01000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_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_TCP_MD5SIG 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 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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT 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_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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=35000
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# 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
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS 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
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 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_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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 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 is not set
+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 is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=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_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# 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 is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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=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_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=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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# 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
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH 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_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC 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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 7724847..3ccf19d 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -143,7 +143,7 @@ CONFIG_PPC_NATIVE=y
 CONFIG_U3_DART=y
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 # CONFIG_PPC_MPC106 is not set
 CONFIG_PPC_970_NAP=y
 # CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig
new file mode 100644
index 0000000..be633b9
--- /dev/null
+++ b/arch/powerpc/configs/holly_defconfig
@@ -0,0 +1,1070 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21
+# Sat May  5 11:02:35 2007
+#
+# 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_ARCH_HAS_ILOG2_U32=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_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_ALTIVEC is not set
+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_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# 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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=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_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_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+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=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"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+CONFIG_EMBEDDED6xx=y
+# CONFIG_APUS is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_LINKSTATION is not set
+# CONFIG_MPC7448HPC2 is not set
+CONFIG_PPC_HOLLY=y
+CONFIG_TSI108_BRIDGE=y
+CONFIG_MPIC=y
+CONFIG_MPIC_WEIRD=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_CPM2 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=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 is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_WANT_DEVICE_TREE is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG 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_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE 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_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_TCP_MD5SIG 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 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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT 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_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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=131072
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# 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_TGT is not set
+# 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 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_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_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
+# CONFIG_SCSI_ESP_CORE is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# 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_SATA_INIC162X 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_CMD640_PCI 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_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL 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
+# CONFIG_PATA_PLATFORM 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
+# CONFIG_MACINTOSH_DRIVERS 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 is not set
+# CONFIG_DAVICOM_PHY is not set
+# 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_BROADCOM_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=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON 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_TSI108_ETH=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 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 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 is not set
+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 is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=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_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
+# CONFIG_AGP is not set
+# 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_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 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=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_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=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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+# 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
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index de97f2f..15366f0 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -146,7 +146,7 @@ # CONFIG_RTAS_ERROR_LOGGING is not set
 CONFIG_RTAS_PROC=y
 # CONFIG_RTAS_FLASH is not set
 # CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 # CONFIG_PPC_MPC106 is not set
 CONFIG_PPC_970_NAP=y
 # CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/mpc832x_mds_defconfig b/arch/powerpc/configs/mpc832x_mds_defconfig
index e1b36de..83192c0 100644
--- a/arch/powerpc/configs/mpc832x_mds_defconfig
+++ b/arch/powerpc/configs/mpc832x_mds_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc5
-# Tue Jan 30 14:27:25 2007
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr  9 16:09:16 2007
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -34,9 +34,9 @@ # CONFIG_PPC_82xx is not set
 CONFIG_PPC_83xx=y
 # CONFIG_PPC_85xx is not set
 # CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx 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
@@ -63,6 +63,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -71,6 +72,7 @@ # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
@@ -123,16 +125,17 @@ # 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_MPC8313_RDB is not set
 CONFIG_MPC832x_MDS=y
-# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC832x_RDB is not set
+# CONFIG_MPC834x_MDS is not set
 # CONFIG_MPC834x_ITX is not set
-# CONFIG_MPC8360E_PB is not set
+# CONFIG_MPC836x_MDS is not set
 CONFIG_PPC_MPC832x=y
 # CONFIG_MPIC is not set
 
@@ -163,6 +166,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 # CONFIG_PM is not set
@@ -172,6 +176,7 @@ CONFIG_ISA_DMA_API=y
 #
 # Bus options
 #
+CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_ISA_DMA=y
 # CONFIG_MPIC_WEIRD is not set
 # CONFIG_PPC_I8259 is not set
@@ -220,6 +225,7 @@ CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -324,6 +330,7 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -342,7 +349,6 @@ 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
 
@@ -482,7 +488,21 @@ # CONFIG_ARCNET is not set
 #
 # PHY device support
 #
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+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_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -524,11 +544,13 @@ # CONFIG_UGETH_MAGIC_PACKET is not set
 # CONFIG_UGETH_FILTERING is not set
 # CONFIG_UGETH_TX_ON_DEMOND is not set
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
@@ -621,6 +643,7 @@ # CONFIG_SERIAL_UARTLITE is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -691,6 +714,7 @@ 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_PASEMI is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_I2C_SIS5595 is not set
@@ -738,6 +762,7 @@ # 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_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
@@ -779,6 +804,11 @@ # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -791,10 +821,9 @@ # CONFIG_DVB is not set
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 # CONFIG_FB is not set
 # CONFIG_FB_IBM_GXT4500 is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -805,6 +834,7 @@ #
 # HID Devices
 #
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
 
 #
 # USB support
@@ -869,6 +899,10 @@ # DMA Devices
 #
 
 #
+# Auxiliary Display support
+#
+
+#
 # Virtualization
 #
 
@@ -995,11 +1029,7 @@ #
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
-
-#
-# QE Options
-#
-CONFIG_UCC_SLOW=y
+# CONFIG_UCC_SLOW is not set
 CONFIG_UCC_FAST=y
 CONFIG_UCC=y
 
@@ -1012,7 +1042,8 @@ # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
 
 #
 # Instrumentation Support
@@ -1032,7 +1063,6 @@ # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_BOOTX_TEXT is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
 # CONFIG_PPC_EARLY_DEBUG is not set
 
 #
@@ -1061,8 +1091,10 @@ # CONFIG_CRYPTO_TGR192 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
 CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -1076,6 +1108,7 @@ # 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_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
diff --git a/arch/powerpc/configs/mpc832x_rdb_defconfig b/arch/powerpc/configs/mpc832x_rdb_defconfig
new file mode 100644
index 0000000..4a4da87
--- /dev/null
+++ b/arch/powerpc/configs/mpc832x_rdb_defconfig
@@ -0,0 +1,1300 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr  9 16:12:43 2007
+#
+# 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_ARCH_HAS_ILOG2_U32=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_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 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_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+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_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# 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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=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_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"
+CONFIG_QUICC_ENGINE=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8313_RDB is not set
+# CONFIG_MPC832x_MDS is not set
+CONFIG_MPC832x_RDB=y
+# CONFIG_MPC834x_MDS is not set
+# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC836x_MDS is not set
+CONFIG_PPC_MPC832x=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_300 is not set
+# 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_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=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 is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+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_ZONE_DMA=y
+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_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE 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_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_TCP_MD5SIG 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 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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_UB 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_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_TGT is not set
+# 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 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_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_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
+# CONFIG_SCSI_SRP 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
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# 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 is not set
+# CONFIG_DAVICOM_PHY is not set
+# 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_BROADCOM_PHY is not set
+CONFIG_ICPLUS_PHY=y
+# 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
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K 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_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=y
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC 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
+# 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=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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM 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
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG 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
+# CONFIG_AGP is not set
+# 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_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_PASEMI 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
+#
+# 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_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 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_PC87427 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
+# CONFIG_SENSORS_W83793 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
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 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_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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_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_EHCI_BIG_ENDIAN_MMIO is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+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 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
+# CONFIG_USB_GTCO 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_MII 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_BERRY_CHARGE 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_IOWARRIOR 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 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=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 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 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=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=y
+# CONFIG_LDM_DEBUG 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=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=y
+# 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE 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=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC 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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc836x_mds_defconfig b/arch/powerpc/configs/mpc836x_mds_defconfig
index 8eb475c..921a151 100644
--- a/arch/powerpc/configs/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/mpc836x_mds_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Sat Feb 17 10:09:26 2007
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr  9 16:14:05 2007
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -72,6 +72,7 @@ # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
@@ -124,7 +125,6 @@ # 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
 
 #
@@ -132,6 +132,7 @@ # Platform support
 #
 # CONFIG_MPC8313_RDB is not set
 # CONFIG_MPC832x_MDS is not set
+# CONFIG_MPC832x_RDB is not set
 # CONFIG_MPC834x_MDS is not set
 # CONFIG_MPC834x_ITX is not set
 CONFIG_MPC836x_MDS=y
@@ -328,6 +329,7 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -346,7 +348,6 @@ 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
 
@@ -486,7 +487,21 @@ # CONFIG_ARCNET is not set
 #
 # PHY device support
 #
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# 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_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
 
 #
 # Ethernet (10 or 100Mbit)
@@ -528,6 +543,7 @@ # CONFIG_UGETH_MAGIC_PACKET is not set
 # CONFIG_UGETH_FILTERING is not set
 # CONFIG_UGETH_TX_ON_DEMOND is not set
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -745,6 +761,7 @@ # 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_ADM1029 is not set
 # CONFIG_SENSORS_ADM1031 is not set
 # CONFIG_SENSORS_ADM9240 is not set
 # CONFIG_SENSORS_ASB100 is not set
@@ -786,6 +803,11 @@ # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -798,10 +820,9 @@ # CONFIG_DVB is not set
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 # CONFIG_FB is not set
 # CONFIG_FB_IBM_GXT4500 is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -1007,11 +1028,7 @@ #
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
-
-#
-# QE Options
-#
-CONFIG_UCC_SLOW=y
+# CONFIG_UCC_SLOW is not set
 CONFIG_UCC_FAST=y
 CONFIG_UCC=y
 
@@ -1045,7 +1062,6 @@ # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_BOOTX_TEXT is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
 # CONFIG_PPC_EARLY_DEBUG is not set
 
 #
diff --git a/arch/powerpc/configs/mpc8544_ds_defconfig b/arch/powerpc/configs/mpc8544_ds_defconfig
new file mode 100644
index 0000000..b563513
--- /dev/null
+++ b/arch/powerpc/configs/mpc8544_ds_defconfig
@@ -0,0 +1,1077 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 19 17:18:49 2007
+#
+# 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_ARCH_HAS_ILOG2_U32=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_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 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_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+# CONFIG_SPE 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_IPC_NS=y
+CONFIG_SYSVIPC_SYSCTL=y
+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=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=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_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_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=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"
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+CONFIG_MPC8544_DS=y
+CONFIG_MPC85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+CONFIG_MPIC=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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=m
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=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 is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/sda3 rw console=ttyS0,115200"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_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 is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# 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=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE 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=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=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=y
+# 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=y
+# 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_TCP_MD5SIG 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 is not set
+
+#
+# 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 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_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# 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=y
+# 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=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC 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_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_PLATFORM 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
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# 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
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+CONFIG_VITESSE_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# 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=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=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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_OF_PLATFORM 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_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 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 is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+# CONFIG_DVB_CORE_ATTACH is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+
+#
+# DVB-T (terrestrial) frontends
+#
+
+#
+# DVB-C (cable) frontends
+#
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+
+#
+# Tuners/PLL support
+#
+
+#
+# Miscellaneous devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=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_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 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=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=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+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 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_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=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=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-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=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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 is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUGGER 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=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC 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_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index a8da0ae..126b9f8 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -152,7 +152,7 @@ CONFIG_RTAS_ERROR_LOGGING=y
 CONFIG_RTAS_PROC=y
 CONFIG_RTAS_FLASH=m
 CONFIG_MMIO_NVRAM=y
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
 CONFIG_IBMVIO=y
 # CONFIG_IBMEBUS is not set
 # CONFIG_PPC_MPC106 is not set
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 0345a2c..fd60496 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc6
-# Thu Jan 25 13:35:34 2007
+# Linux kernel version: 2.6.21
+# Mon Apr 30 12:03:35 2007
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -60,6 +60,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -69,6 +70,7 @@ # CONFIG_IKCONFIG is not set
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
@@ -131,13 +133,36 @@ # CONFIG_APUS is not set
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_ISERIES is not set
 # CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
 # CONFIG_PPC_PMAC is not set
 # CONFIG_PPC_MAPLE is not set
 # CONFIG_PPC_PASEMI is not set
+# CONFIG_PPC_CELLEB is not set
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
 CONFIG_PPC_CELL=y
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_IBM_CELL_BLADE is not set
-CONFIG_PPC_PS3=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_PQ2ADS is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
 # CONFIG_U3_DART is not set
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
@@ -146,24 +171,7 @@ # CONFIG_PPC_970_NAP is not set
 # CONFIG_PPC_INDIRECT_IO is not set
 # CONFIG_GENERIC_IOMAP is not set
 # CONFIG_CPU_FREQ is not set
-# CONFIG_WANT_EARLY_SERIAL is not set
-# CONFIG_MPIC is not set
-
-#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=y
-CONFIG_SPU_BASE=y
-# CONFIG_CBE_RAS is not set
-
-#
-# PS3 Platform Options
-#
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
+# CONFIG_CPM2 is not set
 
 #
 # Kernel options
@@ -179,10 +187,10 @@ # CONFIG_PREEMPT is not set
 # CONFIG_PREEMPT_BKL is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
-CONFIG_FORCE_MAX_ZONEORDER=9
+CONFIG_FORCE_MAX_ZONEORDER=13
 # CONFIG_IOMMU_VMERGE is not set
 CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-# CONFIG_KEXEC is not set
+CONFIG_KEXEC=y
 # CONFIG_CRASH_DUMP is not set
 # CONFIG_IRQ_ALL_CPUS is not set
 # CONFIG_NUMA is not set
@@ -203,22 +211,22 @@ CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTPLUG_SPARSE=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
 CONFIG_ARCH_MEMORY_PROBE=y
-CONFIG_PPC_64K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
 # CONFIG_SCHED_SMT is not set
 CONFIG_PROC_DEVICETREE=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp"
+# CONFIG_CMDLINE_BOOL is not set
 # CONFIG_PM is not set
 # CONFIG_SECCOMP is not set
+# CONFIG_WANT_DEVICE_TREE is not set
 CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
 #
+CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_ISA_DMA=y
-# CONFIG_MPIC_WEIRD is not set
-# CONFIG_PPC_I8259 is not set
 # CONFIG_PCI is not set
 # CONFIG_PCI_DOMAINS is not set
 
@@ -240,10 +248,13 @@ 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_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -261,7 +272,7 @@ # 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_TUNNEL=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
@@ -270,9 +281,23 @@ # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD 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_MULTIPLE_TABLES is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 
@@ -313,7 +338,31 @@ #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
-# CONFIG_BT 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 is not set
+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 is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
 # CONFIG_IEEE80211 is not set
 
 #
@@ -327,16 +376,13 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES 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
 
 #
@@ -347,24 +393,27 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # 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_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_UB is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65535
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 
 #
 # Misc devices
 #
-# CONFIG_TIFM_CORE is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -388,7 +437,7 @@ # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 # CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=m
 # CONFIG_CHR_DEV_SCH is not set
 
 #
@@ -413,6 +462,7 @@ # SCSI low-level drivers
 #
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
 
 #
 # Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -460,7 +510,7 @@ #
 # Ethernet (10 or 100Mbit)
 #
 # CONFIG_NET_ETHERNET is not set
-CONFIG_MII=y
+CONFIG_MII=m
 
 #
 # Ethernet (1000 Mbit)
@@ -475,9 +525,10 @@ # Token Ring devices
 #
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Wan interfaces
@@ -551,7 +602,8 @@ #
 # Non-8250 serial port support
 #
 CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
 
 #
 # IPMI
@@ -598,6 +650,11 @@ # CONFIG_HWMON is not set
 # CONFIG_HWMON_VID is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -611,15 +668,22 @@ # CONFIG_USB_DABUSB is not set
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SVGALIB 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
+
+#
+# Frame buffer hardware drivers
+#
 # CONFIG_FB_OF is not set
 # CONFIG_FB_VGA16 is not set
 # CONFIG_FB_S1D13XXX is not set
@@ -634,7 +698,7 @@ #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 # CONFIG_FONTS is not set
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
@@ -646,17 +710,62 @@ 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
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# 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
+
+#
+# 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 PowerMac devices
+#
+
+#
+# ALSA PowerMac requires I2C
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# SoC audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
 
 #
 # HID Devices
 #
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
 
 #
 # USB support
@@ -665,13 +774,13 @@ 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
+# CONFIG_USB_DEBUG is not set
 
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 
@@ -704,7 +813,7 @@ #
 #
 # may also be needed; see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=y
+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
@@ -720,10 +829,16 @@ # CONFIG_USB_LIBUSUAL is not set
 #
 # USB Input Devices
 #
-CONFIG_USB_HID=y
+CONFIG_USB_HID=m
 # 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
@@ -736,6 +851,7 @@ # 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_GTCO is not set
 
 #
 # USB Imaging devices
@@ -748,15 +864,16 @@ # USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
 # CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_PEGASUS=m
 # CONFIG_USB_RTL8150 is not set
-CONFIG_USB_USBNET_MII=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_USBNET_MII=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_DM9601 is not set
 # CONFIG_USB_NET_GL620A is not set
 # CONFIG_USB_NET_NET1080 is not set
 # CONFIG_USB_NET_PLUSB is not set
-CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_MCS7830=m
 # CONFIG_USB_NET_RNDIS_HOST is not set
 # CONFIG_USB_NET_CDC_SUBSET is not set
 # CONFIG_USB_NET_ZAURUS is not set
@@ -781,6 +898,7 @@ # 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_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -791,6 +909,8 @@ # 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_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
 
 #
 # USB DSL modem support
@@ -846,13 +966,19 @@ # DMA Devices
 #
 
 #
+# Auxiliary Display support
+#
+
+#
 # Virtualization
 #
 
 #
 # File systems
 #
-# CONFIG_EXT2_FS is not set
+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
@@ -871,27 +997,30 @@ # 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_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
 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
 
 #
 # CD-ROM/DVD Filesystems
 #
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=y
+CONFIG_UDF_FS=m
 CONFIG_UDF_NLS=y
 
 #
 # DOS/FAT/NT Filesystems
 #
-CONFIG_FAT_FS=y
+CONFIG_FAT_FS=m
 # CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
@@ -933,7 +1062,7 @@ #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
+CONFIG_NFS_V4=y
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
@@ -941,10 +1070,16 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+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_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
 # CONFIG_AFS_FS is not set
@@ -1004,6 +1139,8 @@ #
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
 
 #
 # Library routines
@@ -1014,7 +1151,8 @@ # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
 
 #
 # Instrumentation Support
@@ -1032,16 +1170,16 @@ # CONFIG_UNUSED_SYMBOLS is not set
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=17
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-CONFIG_DEBUG_SLAB=y
-# CONFIG_DEBUG_SLAB_LEAK is not set
+# CONFIG_TIMER_STATS 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=y
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1051,8 +1189,10 @@ # CONFIG_DEBUG_VM is not set
 CONFIG_DEBUG_LIST=y
 CONFIG_FORCED_INLINING=y
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_DEBUGGER is not set
 CONFIG_IRQSTACKS=y
 # CONFIG_BOOTX_TEXT is not set
@@ -1063,6 +1203,8 @@ # CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is n
 # CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
 # CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
 # CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
+# CONFIG_PPC_EARLY_DEBUG_BEAT is not set
 
 #
 # Security options
@@ -1073,4 +1215,43 @@ # CONFIG_SECURITY is not set
 #
 # Cryptographic options
 #
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC 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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8120d42..3e779f0 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP)	+= idle_power4
 obj-$(CONFIG_PPC_OF)		+= of_device.o of_platform.o prom_parse.o
 procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
 obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
-rtaspci-$(CONFIG_PPC64)		:= rtas_pci.o
-obj-$(CONFIG_PPC_RTAS)		+= rtas.o rtas-rtc.o $(rtaspci-y)
+rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI)	:= rtas_pci.o
+obj-$(CONFIG_PPC_RTAS)		+= rtas.o rtas-rtc.o $(rtaspci-y-y)
 obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_RTAS_PROC)		+= rtas-proc.o
 obj-$(CONFIG_LPARCFG)		+= lparcfg.o
@@ -36,7 +36,9 @@ obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsy
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o suspend.o
 obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
+obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
 obj32-$(CONFIG_MODULES)		+= module_32.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
@@ -66,6 +68,7 @@ obj-$(CONFIG_MODULES)		+= $(module-y)
 pci64-$(CONFIG_PPC64)		+= pci_64.o pci_dn.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
+obj-$(CONFIG_PCI_MSI)		+= msi.o
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
 kexec-$(CONFIG_PPC32)		:= machine_kexec_32.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o crash.o $(kexec-y)
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 4734b5d..5c9ff7f 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -241,7 +241,7 @@ #endif
 	if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
 		return -EFAULT;
 	for (i = 0; i < size / sizeof(long); ++i)
-		if (__put_user(0, p+i))
+		if (__put_user_inatomic(0, p+i))
 			return -EFAULT;
 	return 1;
 }
@@ -288,7 +288,8 @@ static int emulate_multiple(struct pt_re
 		} else {
 			unsigned long pc = regs->nip ^ (swiz & 4);
 
-			if (__get_user(instr, (unsigned int __user *)pc))
+			if (__get_user_inatomic(instr,
+						(unsigned int __user *)pc))
 				return -EFAULT;
 			if (swiz == 0 && (flags & SW))
 				instr = cpu_to_le32(instr);
@@ -324,27 +325,31 @@ static int emulate_multiple(struct pt_re
 			       ((nb0 + 3) / 4) * sizeof(unsigned long));
 
 		for (i = 0; i < nb; ++i, ++p)
-			if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+			if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+						SWIZ_PTR(p)))
 				return -EFAULT;
 		if (nb0 > 0) {
 			rptr = &regs->gpr[0];
 			addr += nb;
 			for (i = 0; i < nb0; ++i, ++p)
-				if (__get_user(REG_BYTE(rptr, i ^ bswiz),
-					       SWIZ_PTR(p)))
+				if (__get_user_inatomic(REG_BYTE(rptr,
+								 i ^ bswiz),
+							SWIZ_PTR(p)))
 					return -EFAULT;
 		}
 
 	} else {
 		for (i = 0; i < nb; ++i, ++p)
-			if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+			if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+						SWIZ_PTR(p)))
 				return -EFAULT;
 		if (nb0 > 0) {
 			rptr = &regs->gpr[0];
 			addr += nb;
 			for (i = 0; i < nb0; ++i, ++p)
-				if (__put_user(REG_BYTE(rptr, i ^ bswiz),
-					       SWIZ_PTR(p)))
+				if (__put_user_inatomic(REG_BYTE(rptr,
+								 i ^ bswiz),
+							SWIZ_PTR(p)))
 					return -EFAULT;
 		}
 	}
@@ -398,7 +403,8 @@ int fix_alignment(struct pt_regs *regs)
 
 		if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
 			pc ^= 4;
-		if (unlikely(__get_user(instr, (unsigned int __user *)pc)))
+		if (unlikely(__get_user_inatomic(instr,
+						 (unsigned int __user *)pc)))
 			return -EFAULT;
 		if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
 			instr = cpu_to_le32(instr);
@@ -474,16 +480,16 @@ int fix_alignment(struct pt_regs *regs)
 		p = (unsigned long) addr;
 		switch (nb) {
 		case 8:
-			ret |= __get_user(data.v[0], SWIZ_PTR(p++));
-			ret |= __get_user(data.v[1], SWIZ_PTR(p++));
-			ret |= __get_user(data.v[2], SWIZ_PTR(p++));
-			ret |= __get_user(data.v[3], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
 		case 4:
-			ret |= __get_user(data.v[4], SWIZ_PTR(p++));
-			ret |= __get_user(data.v[5], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
 		case 2:
-			ret |= __get_user(data.v[6], SWIZ_PTR(p++));
-			ret |= __get_user(data.v[7], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
+			ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
 			if (unlikely(ret))
 				return -EFAULT;
 		}
@@ -551,16 +557,16 @@ #endif
 		p = (unsigned long) addr;
 		switch (nb) {
 		case 8:
-			ret |= __put_user(data.v[0], SWIZ_PTR(p++));
-			ret |= __put_user(data.v[1], SWIZ_PTR(p++));
-			ret |= __put_user(data.v[2], SWIZ_PTR(p++));
-			ret |= __put_user(data.v[3], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
 		case 4:
-			ret |= __put_user(data.v[4], SWIZ_PTR(p++));
-			ret |= __put_user(data.v[5], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
 		case 2:
-			ret |= __put_user(data.v[6], SWIZ_PTR(p++));
-			ret |= __put_user(data.v[7], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
+			ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
 		}
 		if (unlikely(ret))
 			return -EFAULT;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 030d300..8f48560 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -21,12 +21,12 @@ #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/suspend.h>
 #ifdef CONFIG_PPC64
 #include <linux/time.h>
 #include <linux/hardirq.h>
 #else
 #include <linux/ptrace.h>
-#include <linux/suspend.h>
 #endif
 
 #include <asm/io.h>
@@ -77,7 +77,6 @@ #ifdef CONFIG_PPC64
 	DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
 #else /* CONFIG_PPC64 */
 	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
 	DEFINE(PT_PTRACED, PT_PTRACED);
@@ -140,6 +139,7 @@ #endif /* CONFIG_HUGETLB_PAGE */
 	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(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
 
 	DEFINE(SLBSHADOW_STACKVSID,
 	       offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
@@ -257,11 +257,11 @@ #endif /* ! CONFIG_PPC64 */
 	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));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
 	DEFINE(pbe_next, offsetof(struct pbe, next));
 
+#ifndef CONFIG_PPC64
 	DEFINE(TASK_SIZE, TASK_SIZE);
 	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
 #endif /* ! CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index 3678997..e7b6846 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -161,33 +161,33 @@ int btext_initialize(struct device_node 
 	unsigned long address = 0;
 	const u32 *prop;
 
-	prop = get_property(np, "linux,bootx-width", NULL);
+	prop = of_get_property(np, "linux,bootx-width", NULL);
 	if (prop == NULL)
-		prop = get_property(np, "width", NULL);
+		prop = of_get_property(np, "width", NULL);
 	if (prop == NULL)
 		return -EINVAL;
 	width = *prop;
-	prop = get_property(np, "linux,bootx-height", NULL);
+	prop = of_get_property(np, "linux,bootx-height", NULL);
 	if (prop == NULL)
-		prop = get_property(np, "height", NULL);
+		prop = of_get_property(np, "height", NULL);
 	if (prop == NULL)
 		return -EINVAL;
 	height = *prop;
-	prop = get_property(np, "linux,bootx-depth", NULL);
+	prop = of_get_property(np, "linux,bootx-depth", NULL);
 	if (prop == NULL)
-		prop = get_property(np, "depth", NULL);
+		prop = of_get_property(np, "depth", NULL);
 	if (prop == NULL)
 		return -EINVAL;
 	depth = *prop;
 	pitch = width * ((depth + 7) / 8);
-	prop = get_property(np, "linux,bootx-linebytes", NULL);
+	prop = of_get_property(np, "linux,bootx-linebytes", NULL);
 	if (prop == NULL)
-		prop = get_property(np, "linebytes", NULL);
+		prop = of_get_property(np, "linebytes", NULL);
 	if (prop && *prop != 0xffffffffu)
 		pitch = *prop;
 	if (pitch == 1)
 		pitch = 0x1000;
-	prop = get_property(np, "address", NULL);
+	prop = of_get_property(np, "address", NULL);
 	if (prop)
 		address = *prop;
 
@@ -219,7 +219,7 @@ int __init btext_find_display(int allow_
 	struct device_node *np = NULL; 
 	int rc = -ENODEV;
 
-	name = get_property(of_chosen, "linux,stdout-path", NULL);
+	name = of_get_property(of_chosen, "linux,stdout-path", NULL);
 	if (name != NULL) {
 		np = of_find_node_by_path(name);
 		if (np != NULL) {
@@ -236,7 +236,7 @@ int __init btext_find_display(int allow_
 		return rc;
 
 	for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
-		if (get_property(np, "linux,opened", NULL)) {
+		if (of_get_property(np, "linux,opened", NULL)) {
 			printk("trying %s ...\n", np->full_name);
 			rc = btext_initialize(np);
 			printk("result: %d\n", rc);
diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S
index 4047be2..d62cb9c 100644
--- a/arch/powerpc/kernel/cpu_setup_pa6t.S
+++ b/arch/powerpc/kernel/cpu_setup_pa6t.S
@@ -34,7 +34,7 @@ _GLOBAL(__setup_cpu_pa6t)
 	beqlr
 
 	mfspr	r0,SPRN_HID5
-	ori	r0,r0,0x30
+	ori	r0,r0,0x38
 	mtspr	SPRN_HID5,r0
 
 	mfspr	r0,SPRN_LPCR
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index e4006dc..9cb24d2 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -389,6 +389,8 @@ #ifdef CONFIG_PPC64
 		.pmc_type		= PPC_PMC_PA6T,
 		.cpu_setup		= __setup_cpu_pa6t,
 		.cpu_restore		= __restore_cpu_pa6t,
+		.oprofile_cpu_type	= "ppc64/pa6t",
+		.oprofile_type		= PPC_OPROFILE_PA6T,
 		.platform		= "pa6t",
 	},
 	{	/* default match */
@@ -558,6 +560,18 @@ #if CLASSIC_PPC
 		.cpu_setup		= __setup_cpu_750cx,
 		.platform		= "ppc750",
 	},
+	{	/* 750CL */
+		.pvr_mask		= 0xfffff0f0,
+		.pvr_value		= 0x00087010,
+		.cpu_name		= "750CL",
+		.cpu_features		= CPU_FTRS_750CL,
+		.cpu_user_features	= COMMON_USER | PPC_FEATURE_PPC_LE,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+		.num_pmcs		= 4,
+		.cpu_setup		= __setup_cpu_750,
+		.platform		= "ppc750",
+	},
 	{	/* 745/755 */
 		.pvr_mask		= 0xfffff000,
 		.pvr_value		= 0x00083000,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c03e829..c29d165 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -191,7 +191,6 @@ stack_ovf:
 0:
 
 _GLOBAL(DoSyscall)
-	stw	r0,THREAD+LAST_SYSCALL(r2)
 	stw	r3,ORIG_GPR3(r1)
 	li	r12,0
 	stw	r12,RESULT(r1)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index a15d4b8..8869596 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -120,8 +120,8 @@ skpinv:	addi	r4,r4,1				/* Increment */
  * Configure and load pinned entry into TLB slot 63.
  */
 
-	lis	r3,KERNELBASE@h		/* Load the kernel virtual address */
-	ori	r3,r3,KERNELBASE@l
+	lis	r3,PAGE_OFFSET@h
+	ori	r3,r3,PAGE_OFFSET@l
 
 	/* Kernel is at the base of RAM */
 	li r4, 0			/* Load the kernel physical address */
@@ -172,36 +172,28 @@ skpinv:	addi	r4,r4,1				/* Increment */
 	isync
 
 4:
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-	/*
-	 * Add temporary UART mapping for early debug.
-	 * We can map UART registers wherever we want as long as they don't
-	 * interfere with other system mappings (e.g. with pinned entries).
-	 * For an example of how we handle this - see ocotea.h.       --ebs
-	 */
+#ifdef CONFIG_PPC_EARLY_DEBUG_44x
+	/* Add UART mapping for early debug. */
+
  	/* pageid fields */
-	lis	r3,UART0_IO_BASE@h
-	ori	r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K
+	lis	r3,PPC44x_EARLY_DEBUG_VIRTADDR@h
+	ori	r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K
 
 	/* xlat fields */
-	lis	r4,UART0_PHYS_IO_BASE@h		/* RPN depends on SoC */
-#ifndef CONFIG_440EP
-	ori	r4,r4,0x0001		/* ERPN is 1 for second 4GB page */
-#endif
+	lis	r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h
+	ori	r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH
 
 	/* attrib fields */
-	li	r5,0
-	ori	r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
+	li	r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G)
+        li      r0,62                    /* TLB slot 0 */
 
-        li      r0,0                    /* TLB slot 0 */
-
-	tlbwe	r3,r0,PPC44x_TLB_PAGEID	/* Load the pageid fields */
-	tlbwe	r4,r0,PPC44x_TLB_XLAT	/* Load the translation fields */
-	tlbwe	r5,r0,PPC44x_TLB_ATTRIB	/* Load the attrib/access fields */
+	tlbwe	r3,r0,PPC44x_TLB_PAGEID
+	tlbwe	r4,r0,PPC44x_TLB_XLAT
+	tlbwe	r5,r0,PPC44x_TLB_ATTRIB
 
 	/* Force context change */
 	isync
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
 
 	/* Establish the interrupt vector offsets */
 	SET_IVOR(0,  CriticalInput);
@@ -709,16 +701,6 @@ _GLOBAL(giveup_fpu)
 	blr
 #endif
 
-/*
- * extern void abort(void)
- *
- * At present, this routine just applies a system reset.
- */
-_GLOBAL(abort)
-        mfspr   r13,SPRN_DBCR0
-        oris    r13,r13,DBCR0_RST_SYSTEM@h
-        mtspr   SPRN_DBCR0,r13
-
 _GLOBAL(set_context)
 
 #ifdef CONFIG_BDI_SWITCH
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 97cedcd..1111fce 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -278,8 +278,12 @@ #define EXCEPTION_PROLOG_COMMON(n, area)
 	beq-	1f;							   \
 	ld	r1,PACAKSAVE(r13);	/* kernel stack to use		*/ \
 1:	cmpdi	cr1,r1,0;		/* check if r1 is in userspace	*/ \
-	bge-	cr1,bad_stack;		/* abort if it is		*/ \
-	std	r9,_CCR(r1);		/* save CR in stackframe	*/ \
+	bge-	cr1,2f;			/* abort if it is		*/ \
+	b	3f;							   \
+2:	li	r1,(n);			/* will be reloaded later	*/ \
+	sth	r1,PACA_TRAP_SAVE(r13);					   \
+	b	bad_stack;						   \
+3:	std	r9,_CCR(r1);		/* save CR in stackframe	*/ \
 	std	r11,_NIP(r1);		/* save SRR0 in stackframe	*/ \
 	std	r12,_MSR(r1);		/* save SRR1 in stackframe	*/ \
 	std	r10,0(r1);		/* make stack chain pointer	*/ \
@@ -940,6 +944,8 @@ bad_stack:
 	SAVE_2GPRS(7,r1)
 	SAVE_10GPRS(12,r1)
 	SAVE_10GPRS(22,r1)
+	lhz	r12,PACA_TRAP_SAVE(r13)
+	std	r12,_TRAP(r1)
 	addi	r11,r1,INT_FRAME_SIZE
 	std	r11,0(r1)
 	li	r12,0
@@ -1555,7 +1561,6 @@ _GLOBAL(generic_secondary_smp_init)
 	
 	/* turn on 64-bit mode */
 	bl	.enable_64b_mode
-	isync
 
 	/* 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
@@ -1735,10 +1740,6 @@ _STATIC(__boot_from_prom)
 	/* We never return */
 	trap
 
-/*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
 _STATIC(__after_prom_start)
 
 /*
@@ -1851,7 +1852,6 @@ __secondary_start_pmac_0:
 _GLOBAL(pmac_secondary_start)
 	/* turn on 64-bit mode */
 	bl	.enable_64b_mode
-	isync
 
 	/* Copy some CPU settings from CPU 0 */
 	bl	.__restore_cpu_ppc970
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 82bd2f1..9a8c9af 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -2,36 +2,37 @@
  * IBM PowerPC IBM eBus Infrastructure Support.
  *
  * Copyright (c) 2005 IBM Corporation
+ *  Joachim Fenkes <fenkes@de.ibm.com>
  *  Heiko J Schick <schickhj@de.ibm.com>
- *    
+ *
  * All rights reserved.
  *
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
- * BSD. 
+ * 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: 
+ * 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 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 
+ * 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. 
+ * 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 
+ * 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 
+ * 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.
  */
 
@@ -43,19 +44,19 @@ #include <linux/interrupt.h>
 #include <asm/ibmebus.h>
 #include <asm/abs_addr.h>
 
-static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
-	.name = ibmebus_bus_device.ofdev.dev.bus_id,
-	.ofdev.dev.bus_id = "ibmebus",
-	.ofdev.dev.bus    = &ibmebus_bus_type,
+static struct device ibmebus_bus_device = { /* fake "parent" device */
+	.bus_id = "ibmebus",
 };
 
+struct bus_type ibmebus_bus_type;
+
 static void *ibmebus_alloc_coherent(struct device *dev,
 				    size_t size,
 				    dma_addr_t *dma_handle,
 				    gfp_t flag)
 {
 	void *mem;
-	
+
 	mem = kmalloc(size, flag);
 	*dma_handle = (dma_addr_t)mem;
 
@@ -63,7 +64,7 @@ static void *ibmebus_alloc_coherent(stru
 }
 
 static void ibmebus_free_coherent(struct device *dev,
-				  size_t size, void *vaddr, 
+				  size_t size, void *vaddr,
 				  dma_addr_t dma_handle)
 {
 	kfree(vaddr);
@@ -79,7 +80,7 @@ static dma_addr_t ibmebus_map_single(str
 
 static void ibmebus_unmap_single(struct device *dev,
 				 dma_addr_t dma_addr,
-				 size_t size, 
+				 size_t size,
 				 enum dma_data_direction direction)
 {
 	return;
@@ -90,13 +91,13 @@ static int ibmebus_map_sg(struct device 
 			  int nents, enum dma_data_direction direction)
 {
 	int i;
-	
+
 	for (i = 0; i < nents; i++) {
-		sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) 
+		sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
 			+ sg[i].offset;
 		sg[i].dma_length = sg[i].length;
 	}
-	
+
 	return nents;
 }
 
@@ -128,15 +129,15 @@ static int ibmebus_bus_probe(struct devi
 	struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
 	const struct of_device_id *id;
 	int error = -ENODEV;
-	
+
 	if (!ibmebusdrv->probe)
 		return error;
-	
+
 	id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
 	if (id) {
 		error = ibmebusdrv->probe(ibmebusdev, id);
 	}
-	
+
 	return error;
 }
 
@@ -144,11 +145,11 @@ static int ibmebus_bus_remove(struct dev
 {
 	struct ibmebus_dev *ibmebusdev    = to_ibmebus_dev(dev);
 	struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
-	
+
 	if (ibmebusdrv->remove) {
 		return ibmebusdrv->remove(ibmebusdev);
 	}
-	
+
 	return 0;
 }
 
@@ -158,21 +159,12 @@ static void __devinit ibmebus_dev_releas
 	kfree(to_ibmebus_dev(dev));
 }
 
-static ssize_t ibmebusdev_show_name(struct device *dev, 
-				    struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
-}
-static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, 
-		   NULL);
-
-static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+static int __devinit ibmebus_register_device_common(
 	struct ibmebus_dev *dev, const char *name)
 {
 	int err = 0;
 
-	dev->name = name;
-	dev->ofdev.dev.parent  = &ibmebus_bus_device.ofdev.dev;
+	dev->ofdev.dev.parent  = &ibmebus_bus_device;
 	dev->ofdev.dev.bus     = &ibmebus_bus_type;
 	dev->ofdev.dev.release = ibmebus_dev_release;
 
@@ -181,17 +173,15 @@ static struct ibmebus_dev* __devinit ibm
 	dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node);
 
 	/* An ibmebusdev is based on a of_device. We have to change the
-	 * bus type to use our own DMA mapping operations. 
-	 */       
+	 * bus type to use our own DMA mapping operations.
+	 */
 	if ((err = of_device_register(&dev->ofdev)) != 0) {
 		printk(KERN_ERR "%s: failed to register device (%d).\n",
 		       __FUNCTION__, err);
-		return NULL;
+		return -ENODEV;
 	}
-	
-	device_create_file(&dev->ofdev.dev, &dev_attr_name);
-	
-	return dev;
+
+	return 0;
 }
 
 static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -201,35 +191,35 @@ static struct ibmebus_dev* __devinit ibm
 	const char *loc_code;
 	int length;
 
-	loc_code = get_property(dn, "ibm,loc-code", NULL);
+	loc_code = of_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>");
-		return NULL;
+		return ERR_PTR(-EINVAL);
         }
-	
+
 	if (strlen(loc_code) == 0) {
 	        printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
 		       __FUNCTION__);
-		return NULL;
+		return ERR_PTR(-EINVAL);
 	}
 
 	dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
 	if (!dev) {
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	dev->ofdev.node = of_node_get(dn);
-       
+
 	length = strlen(loc_code);
-	memcpy(dev->ofdev.dev.bus_id, loc_code 
-		+ (length - min(length, BUS_ID_SIZE - 1)), 
+	memcpy(dev->ofdev.dev.bus_id, loc_code
+		+ (length - min(length, BUS_ID_SIZE - 1)),
 		min(length, BUS_ID_SIZE - 1));
 
 	/* Register with generic device framework. */
-	if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+	if (ibmebus_register_device_common(dev, dn->name) != 0) {
 		kfree(dev);
-		return NULL;
+		return ERR_PTR(-ENODEV);
 	}
 
 	return dev;
@@ -238,17 +228,16 @@ static struct ibmebus_dev* __devinit ibm
 static void ibmebus_probe_of_nodes(char* name)
 {
 	struct device_node *dn = NULL;
-	
+
 	while ((dn = of_find_node_by_name(dn, name))) {
-		if (ibmebus_register_device_node(dn) == NULL) {
+		if (IS_ERR(ibmebus_register_device_node(dn))) {
 			of_node_put(dn);
-			
 			return;
 		}
 	}
-	
+
 	of_node_put(dn);
-	
+
 	return;
 }
 
@@ -262,17 +251,21 @@ static void ibmebus_add_devices_by_id(st
 	return;
 }
 
-static int ibmebus_match_helper(struct device *dev, void *data)
+static int ibmebus_match_name(struct device *dev, void *data)
 {
-	if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+	const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+	const char *name;
+
+	name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+
+	if (name && (strcmp(data, name) == 0))
 		return 1;
-	
+
 	return 0;
 }
 
 static int ibmebus_unregister_device(struct device *dev)
 {
-	device_remove_file(dev, &dev_attr_name);
 	of_device_unregister(to_of_device(dev));
 
 	return 0;
@@ -281,17 +274,16 @@ static int ibmebus_unregister_device(str
 static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
 {
 	struct device *dev;
-	
+
 	while (strlen(idt->name) > 0) {
-		while ((dev = bus_find_device(&ibmebus_bus_type, NULL, 
+		while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
 					      (void*)idt->name,
-					      ibmebus_match_helper))) {
+					      ibmebus_match_name))) {
 			ibmebus_unregister_device(dev);
 		}
 		idt++;
-		
 	}
-	
+
 	return;
 }
 
@@ -307,30 +299,33 @@ int ibmebus_register_driver(struct ibmeb
 	if ((err = driver_register(&drv->driver) != 0))
 		return err;
 
+	/* remove all supported devices first, in case someone
+	 * probed them manually before registering the driver */
+	ibmebus_remove_devices_by_id(drv->id_table);
 	ibmebus_add_devices_by_id(drv->id_table);
-	
+
 	return 0;
 }
 EXPORT_SYMBOL(ibmebus_register_driver);
 
 void ibmebus_unregister_driver(struct ibmebus_driver *drv)
-{	
+{
 	driver_unregister(&drv->driver);
 	ibmebus_remove_devices_by_id(drv->id_table);
 }
 EXPORT_SYMBOL(ibmebus_unregister_driver);
 
 int ibmebus_request_irq(struct ibmebus_dev *dev,
-			u32 ist, 
+			u32 ist,
 			irq_handler_t handler,
 			unsigned long irq_flags, const char * devname,
 			void *dev_id)
 {
 	unsigned int irq = irq_create_mapping(NULL, ist);
-	
+
 	if (irq == NO_IRQ)
 		return -EINVAL;
-	
+
 	return request_irq(irq, handler,
 			   irq_flags, devname, dev_id);
 }
@@ -339,56 +334,163 @@ EXPORT_SYMBOL(ibmebus_request_irq);
 void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
 {
 	unsigned int irq = irq_find_mapping(NULL, ist);
-	
+
 	free_irq(irq, dev_id);
 }
 EXPORT_SYMBOL(ibmebus_free_irq);
 
 static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
-{	
+{
 	const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
 	struct ibmebus_driver *ebus_drv    = to_ibmebus_driver(drv);
 	const struct of_device_id *ids     = ebus_drv->id_table;
 	const struct of_device_id *found_id;
-	
+
 	if (!ids)
 		return 0;
-	
+
 	found_id = of_match_device(ids, &ebus_dev->ofdev);
 	if (found_id)
 		return 1;
-	
+
 	return 0;
 }
 
+static ssize_t name_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+	const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+	return sprintf(buf, "%s\n", name);
+}
+
+static struct device_attribute ibmebus_dev_attrs[] = {
+	__ATTR_RO(name),
+	__ATTR_NULL
+};
+
+static int ibmebus_match_path(struct device *dev, void *data)
+{
+	int rc;
+	struct device_node *dn =
+		of_node_get(to_ibmebus_dev(dev)->ofdev.node);
+
+	rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));
+
+	of_node_put(dn);
+	return rc;
+}
+
+static char *ibmebus_chomp(const char *in, size_t count)
+{
+	char *out = (char*)kmalloc(count + 1, GFP_KERNEL);
+	if (!out)
+		return NULL;
+
+	memcpy(out, in, count);
+	out[count] = '\0';
+	if (out[count - 1] == '\n')
+		out[count - 1] = '\0';
+
+	return out;
+}
+
+static ssize_t ibmebus_store_probe(struct bus_type *bus,
+				   const char *buf, size_t count)
+{
+	struct device_node *dn = NULL;
+	struct ibmebus_dev *dev;
+	char *path;
+	ssize_t rc;
+
+	path = ibmebus_chomp(buf, count);
+	if (!path)
+		return -ENOMEM;
+
+	if (bus_find_device(&ibmebus_bus_type, NULL, path,
+			     ibmebus_match_path)) {
+		printk(KERN_WARNING "%s: %s has already been probed\n",
+		       __FUNCTION__, path);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	if ((dn = of_find_node_by_path(path))) {
+		dev = ibmebus_register_device_node(dn);
+		of_node_put(dn);
+		rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
+	} else {
+		printk(KERN_WARNING "%s: no such device node: %s\n",
+		       __FUNCTION__, path);
+		rc = -ENODEV;
+	}
+
+out:
+	kfree(path);
+	return rc;
+}
+
+static ssize_t ibmebus_store_remove(struct bus_type *bus,
+				    const char *buf, size_t count)
+{
+	struct device *dev;
+	char *path;
+
+	path = ibmebus_chomp(buf, count);
+	if (!path)
+		return -ENOMEM;
+
+	if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
+				   ibmebus_match_path))) {
+		ibmebus_unregister_device(dev);
+
+		kfree(path);
+		return count;
+	} else {
+		printk(KERN_WARNING "%s: %s not on the bus\n",
+		       __FUNCTION__, path);
+
+		kfree(path);
+		return -ENODEV;
+	}
+}
+
+static struct bus_attribute ibmebus_bus_attrs[] = {
+	__ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
+	__ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
+	__ATTR_NULL
+};
+
 struct bus_type ibmebus_bus_type = {
-	.name = "ibmebus",
-	.match = ibmebus_bus_match,
+	.name      = "ibmebus",
+	.match     = ibmebus_bus_match,
+	.dev_attrs = ibmebus_dev_attrs,
+	.bus_attrs = ibmebus_bus_attrs
 };
 EXPORT_SYMBOL(ibmebus_bus_type);
 
 static int __init ibmebus_bus_init(void)
 {
 	int err;
-	
+
 	printk(KERN_INFO "IBM eBus Device Driver\n");
-	
+
 	err = bus_register(&ibmebus_bus_type);
 	if (err) {
 		printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
 		       __FUNCTION__);
 		return err;
 	}
-	
-	err = device_register(&ibmebus_bus_device.ofdev.dev);
+
+	err = device_register(&ibmebus_bus_device);
 	if (err) {
-		printk(KERN_WARNING "%s: device_register returned %i\n", 
+		printk(KERN_WARNING "%s: device_register returned %i\n",
 		       __FUNCTION__, err);
 		bus_unregister(&ibmebus_bus_type);
 
 		return err;
 	}
-	
+
 	return 0;
 }
 __initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 6e7f509..a9e9cbd 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -33,8 +33,11 @@ #include <asm/machdep.h>
 #include <asm/smp.h>
 
 #ifdef CONFIG_HOTPLUG_CPU
+/* this is used for software suspend, and that shuts down
+ * CPUs even while the system is still booting... */
 #define cpu_should_die()	(cpu_is_offline(smp_processor_id()) && \
-				 system_state == SYSTEM_RUNNING)
+				   (system_state == SYSTEM_RUNNING     \
+				 || system_state == SYSTEM_BOOTING))
 #else
 #define cpu_should_die()	0
 #endif
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index ba31954..5328709 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	isync
 	b	1b
 
+_GLOBAL(power4_cpu_offline_powersave)
+	/* Go to NAP now */
+	mfmsr	r7
+	rldicl	r0,r7,48,1
+	rotldi	r0,r0,16
+	mtmsrd	r0,1			/* hard-disable interrupts */
+	li	r0,1
+	li	r6,0
+	stb	r0,PACAHARDIRQEN(r13)	/* we'll hard-enable shortly */
+	stb	r6,PACASOFTIRQEN(r13)	/* soft-disable irqs */
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	ori	r7,r7,MSR_EE
+	oris	r7,r7,MSR_POW@h
+	sync
+	isync
+	mtmsrd	r7
+	isync
+	blr
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 95edad4..c08ceca 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -47,6 +47,8 @@ #else
 static int novmerge = 1;
 #endif
 
+static int protect4gb = 1;
+
 static inline unsigned long iommu_num_pages(unsigned long vaddr,
 					    unsigned long slen)
 {
@@ -58,6 +60,16 @@ static inline unsigned long iommu_num_pa
 	return npages;
 }
 
+static int __init setup_protect4gb(char *str)
+{
+	if (strcmp(str, "on") == 0)
+		protect4gb = 1;
+	else if (strcmp(str, "off") == 0)
+		protect4gb = 0;
+
+	return 1;
+}
+
 static int __init setup_iommu(char *str)
 {
 	if (!strcmp(str, "novmerge"))
@@ -67,6 +79,7 @@ static int __init setup_iommu(char *str)
 	return 1;
 }
 
+__setup("protect4gb=", setup_protect4gb);
 __setup("iommu=", setup_iommu);
 
 static unsigned long iommu_range_alloc(struct iommu_table *tbl,
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *
 struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 {
 	unsigned long sz;
+	unsigned long start_index, end_index;
+	unsigned long entries_per_4g;
+	unsigned long index;
 	static int welcomed = 0;
 	struct page *page;
 
@@ -450,7 +466,7 @@ struct iommu_table *iommu_init_table(str
 
 #ifdef CONFIG_CRASH_DUMP
 	if (ppc_md.tce_get) {
-		unsigned long index, tceval;
+		unsigned long tceval;
 		unsigned long tcecount = 0;
 
 		/*
@@ -480,6 +496,23 @@ #else
 	ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
 #endif
 
+	/*
+	 * DMA cannot cross 4 GB boundary.  Mark last entry of each 4
+	 * GB chunk as reserved.
+	 */
+	if (protect4gb) {
+		entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
+
+		/* Mark the last bit before a 4GB boundary as used */
+		start_index = tbl->it_offset | (entries_per_4g - 1);
+		start_index -= tbl->it_offset;
+
+		end_index = tbl->it_size;
+
+		for (index = start_index; index < end_index - 1; index += entries_per_4g)
+			__set_bit(index, tbl->it_map);
+	}
+
 	if (!welcomed) {
 		printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
 		       novmerge ? "disabled" : "enabled");
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 1009308..9ed4931 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -67,6 +67,7 @@ #include <asm/udbg.h>
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 #include <asm/firmware.h>
+#include <asm/lv1call.h>
 #endif
 
 int __irq_offset_value;
@@ -162,6 +163,16 @@ void local_irq_restore(unsigned long en)
 	local_paca->hard_enabled = en;
 	if ((int)mfspr(SPRN_DEC) < 0)
 		mtspr(SPRN_DEC, 1);
+
+	/*
+	 * Force the delivery of pending soft-disabled interrupts on PS3.
+	 * Any HV call will have this side effect.
+	 */
+	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+		u64 tmp;
+		lv1_get_version_info(&tmp);
+	}
+
 	hard_irq_enable();
 }
 #endif /* CONFIG_PPC64 */
@@ -394,7 +405,7 @@ EXPORT_SYMBOL(do_softirq);
 #ifdef CONFIG_PPC_MERGE
 
 static LIST_HEAD(irq_hosts);
-static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(irq_big_lock);
 static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
 static unsigned int irq_radix_writer;
 struct irq_map_entry irq_map[NR_IRQS];
@@ -947,33 +958,6 @@ arch_initcall(irq_late_init);
 
 #endif /* CONFIG_PPC_MERGE */
 
-#ifdef CONFIG_PCI_MSI
-int pci_enable_msi(struct pci_dev * pdev)
-{
-	if (ppc_md.enable_msi)
-		return ppc_md.enable_msi(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;}
-void pci_disable_msix(struct pci_dev *dev) {}
-void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
-void pci_no_msi(void) {}
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
-
-#endif
-
 #ifdef CONFIG_PPC64
 static int __init setup_noirqdistrib(char *str)
 {
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index dd2886f..0c96611 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -30,8 +30,8 @@ #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
 #include <linux/module.h>
+#include <linux/kdebug.h>
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
 #include <asm/sstep.h>
 #include <asm/uaccess.h>
 
@@ -59,12 +59,14 @@ int __kprobes arch_prepare_kprobe(struct
 	}
 
 	if (!ret) {
-		memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+		memcpy(p->ainsn.insn, p->addr,
+				MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
 		p->opcode = *p->addr;
 		flush_icache_range((unsigned long)p->ainsn.insn,
 			(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
 	}
 
+	p->ainsn.boostable = 0;
 	return ret;
 }
 
@@ -124,22 +126,13 @@ static void __kprobes set_current_kprobe
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 				      struct pt_regs *regs)
 {
-	struct kretprobe_instance *ri;
-
-	if ((ri = get_free_rp_inst(rp)) != NULL) {
-		ri->rp = rp;
-		ri->task = current;
-		ri->ret_addr = (kprobe_opcode_t *)regs->link;
-
-		/* Replace the return addr with trampoline addr */
-		regs->link = (unsigned long)kretprobe_trampoline;
-		add_rp_inst(ri);
-	} else {
-		rp->nmissed++;
-	}
+	ri->ret_addr = (kprobe_opcode_t *)regs->link;
+
+	/* Replace the return addr with trampoline addr */
+	regs->link = (unsigned long)kretprobe_trampoline;
 }
 
 static int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -232,6 +225,38 @@ static int __kprobes kprobe_handler(stru
 		return 1;
 
 ss_probe:
+	if (p->ainsn.boostable >= 0) {
+		unsigned int insn = *p->ainsn.insn;
+
+		/* regs->nip is also adjusted if emulate_step returns 1 */
+		ret = emulate_step(regs, insn);
+		if (ret > 0) {
+			/*
+			 * Once this instruction has been boosted
+			 * successfully, set the boostable flag
+			 */
+			if (unlikely(p->ainsn.boostable == 0))
+				p->ainsn.boostable = 1;
+
+			if (p->post_handler)
+				p->post_handler(p, regs, 0);
+
+			kcb->kprobe_status = KPROBE_HIT_SSDONE;
+			reset_current_kprobe();
+			preempt_enable_no_resched();
+			return 1;
+		} else if (ret < 0) {
+			/*
+			 * We don't allow kprobes on mtmsr(d)/rfi(d), etc.
+			 * So, we should never get here... but, its still
+			 * good to catch them, just in case...
+			 */
+			printk("Can't step on instruction %x\n", insn);
+			BUG();
+		} else if (ret == 0)
+			/* This instruction can't be boosted */
+			p->ainsn.boostable = -1;
+	}
 	prepare_singlestep(p, regs);
 	kcb->kprobe_status = KPROBE_HIT_SS;
 	return 1;
@@ -302,7 +327,7 @@ int __kprobes trampoline_probe_handler(s
 			break;
 	}
 
-	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
 	regs->nip = orig_ret_address;
 
 	reset_current_kprobe();
@@ -376,7 +401,7 @@ out:
 	return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -461,14 +486,6 @@ int __kprobes kprobe_exceptions_notify(s
 		if (post_kprobe_handler(args->regs))
 			ret = NOTIFY_STOP;
 		break;
-	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;
 	}
@@ -525,3 +542,11 @@ int __init arch_init_kprobes(void)
 {
 	return register_kprobe(&trampoline_p);
 }
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+		return 1;
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 325f490..cea8045 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -44,12 +44,12 @@ static int __init add_legacy_port(struct
 	int index;
 
 	/* get clock freq. if present */
-	clk = get_property(np, "clock-frequency", NULL);
+	clk = of_get_property(np, "clock-frequency", NULL);
 	if (clk && *clk)
 		clock = *clk;
 
 	/* get default speed if present */
-	spd = get_property(np, "current-speed", NULL);
+	spd = of_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)
@@ -115,17 +115,18 @@ static int __init add_legacy_soc_port(st
 {
 	u64 addr;
 	const u32 *addrp;
-	upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+	upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ
+		| UPF_FIXED_PORT;
 	struct device_node *tsi = of_get_parent(np);
 
 	/* We only support ports that have a clock frequency properly
 	 * encoded in the device-tree.
 	 */
-	if (get_property(np, "clock-frequency", NULL) == NULL)
+	if (of_get_property(np, "clock-frequency", NULL) == NULL)
 		return -1;
 
 	/* if rtas uses this device, don't try to use it as well */
-	if (get_property(np, "used-by-rtas", NULL) != NULL)
+	if (of_get_property(np, "used-by-rtas", NULL) != NULL)
 		return -1;
 
 	/* Get the address */
@@ -157,7 +158,7 @@ static int __init add_legacy_isa_port(st
 	DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
 
 	/* Get the ISA port number */
-	reg = get_property(np, "reg", NULL);
+	reg = of_get_property(np, "reg", NULL);
 	if (reg == NULL)
 		return -1;
 
@@ -168,7 +169,7 @@ static int __init add_legacy_isa_port(st
 	/* Now look for an "ibm,aix-loc" property that gives us ordering
 	 * if any...
 	 */
-	typep = get_property(np, "ibm,aix-loc", NULL);
+	typep = of_get_property(np, "ibm,aix-loc", NULL);
 
 	/* If we have a location index, then use it */
 	if (typep && *typep == 'S')
@@ -206,7 +207,7 @@ static int __init add_legacy_pci_port(st
 	 * compatible UARTs on PCI need all sort of quirks (port offsets
 	 * etc...) that this code doesn't know about
 	 */
-	if (get_property(np, "clock-frequency", NULL) == NULL)
+	if (of_get_property(np, "clock-frequency", NULL) == NULL)
 		return -1;
 
 	/* Get the PCI address. Assume BAR 0 */
@@ -232,7 +233,7 @@ static int __init add_legacy_pci_port(st
 	 * we get to their "reg" property
 	 */
 	if (np != pci_dev) {
-		const u32 *reg = get_property(np, "reg", NULL);
+		const u32 *reg = of_get_property(np, "reg", NULL);
 		if (reg && (*reg < 4))
 			index = lindex = *reg;
 	}
@@ -243,9 +244,9 @@ static int __init add_legacy_pci_port(st
 	 * doesn't work for these settings, you'll have to add your own special
 	 * cases here
 	 */
-	if (device_is_compatible(pci_dev, "pci13a8,152") ||
-	    device_is_compatible(pci_dev, "pci13a8,154") ||
-	    device_is_compatible(pci_dev, "pci13a8,158")) {
+	if (of_device_is_compatible(pci_dev, "pci13a8,152") ||
+	    of_device_is_compatible(pci_dev, "pci13a8,154") ||
+	    of_device_is_compatible(pci_dev, "pci13a8,158")) {
 		addr += 0x200 * lindex;
 		base += 0x200 * lindex;
 	} else {
@@ -296,7 +297,7 @@ void __init find_legacy_serial_ports(voi
 	DBG(" -> find_legacy_serial_port()\n");
 
 	/* Now find out if one of these is out firmware console */
-	path = get_property(of_chosen, "linux,stdout-path", NULL);
+	path = of_get_property(of_chosen, "linux,stdout-path", NULL);
 	if (path != NULL) {
 		stdout = of_find_node_by_path(path);
 		if (stdout)
@@ -364,11 +365,11 @@ #ifdef CONFIG_PCI
 		/* Check for known pciclass, and also check wether we have
 		 * a device with child nodes for ports or not
 		 */
-		if (device_is_compatible(np, "pciclass,0700") ||
-		    device_is_compatible(np, "pciclass,070002"))
+		if (of_device_is_compatible(np, "pciclass,0700") ||
+		    of_device_is_compatible(np, "pciclass,070002"))
 			pci = np;
-		else if (device_is_compatible(parent, "pciclass,0700") ||
-			 device_is_compatible(parent, "pciclass,070002"))
+		else if (of_device_is_compatible(parent, "pciclass,0700") ||
+			 of_device_is_compatible(parent, "pciclass,070002"))
 			pci = parent;
 		else {
 			of_node_put(parent);
@@ -529,7 +530,7 @@ static int __init check_legacy_serial_co
 	}
 	/* We are getting a weird phandle from OF ... */
 	/* ... So use the full path instead */
-	name = get_property(of_chosen, "linux,stdout-path", NULL);
+	name = of_get_property(of_chosen, "linux,stdout-path", NULL);
 	if (name == NULL) {
 		DBG(" no linux,stdout-path !\n");
 		return -ENODEV;
@@ -541,12 +542,12 @@ static int __init check_legacy_serial_co
 	}
 	DBG("stdout is %s\n", prom_stdout->full_name);
 
-	name = get_property(prom_stdout, "name", NULL);
+	name = of_get_property(prom_stdout, "name", NULL);
 	if (!name) {
 		DBG(" stdout package has no name !\n");
 		goto not_found;
 	}
-	spd = get_property(prom_stdout, "current-speed", NULL);
+	spd = of_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 89486b6..c492cee 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -130,30 +130,31 @@ #ifdef CONFIG_PPC_PSERIES
 /*
  * Methods used to fetch LPAR data when running on a pSeries platform.
  */
-/* find a better place for this function... */
 static void log_plpar_hcall_return(unsigned long rc, char *tag)
 {
-	if (rc == 0)		/* success, return */
+	switch(rc) {
+	case 0:
 		return;
-/* check for null tag ? */
-	if (rc == H_HARDWARE)
-		printk(KERN_INFO
-		       "plpar-hcall (%s) failed with hardware fault\n", tag);
-	else if (rc == H_FUNCTION)
-		printk(KERN_INFO
-		       "plpar-hcall (%s) failed; function not allowed\n", tag);
-	else if (rc == H_AUTHORITY)
-		printk(KERN_INFO
-		       "plpar-hcall (%s) failed; not authorized to this"
-		       " function\n", tag);
-	else if (rc == H_PARAMETER)
-		printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
-		       tag);
-	else
-		printk(KERN_INFO
-		       "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
-		       tag, rc);
-
+	case H_HARDWARE:
+		printk(KERN_INFO "plpar-hcall (%s) "
+				"Hardware fault\n", tag);
+		return;
+	case H_FUNCTION:
+		printk(KERN_INFO "plpar-hcall (%s) "
+				"Function not allowed\n", tag);
+		return;
+	case H_AUTHORITY:
+		printk(KERN_INFO "plpar-hcall (%s) "
+				"Not authorized to this function\n", tag);
+		return;
+	case H_PARAMETER:
+		printk(KERN_INFO "plpar-hcall (%s) "
+				"Bad parameter(s)\n",tag);
+		return;
+	default:
+		printk(KERN_INFO "plpar-hcall (%s) "
+				"Unexpected rc(0x%lx)\n", tag, rc);
+	}
 }
 
 /*
@@ -321,15 +322,16 @@ static int pseries_lparcfg_data(struct s
 	struct device_node *rtas_node;
 	const int *lrdrp = NULL;
 
-	rtas_node = find_path_device("/rtas");
+	rtas_node = of_find_node_by_path("/rtas");
 	if (rtas_node)
-		lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+		lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
 
 	if (lrdrp == NULL) {
 		partition_potential_processors = vdso_data->processorCount;
 	} else {
 		partition_potential_processors = *(lrdrp + 4);
 	}
+	of_node_put(rtas_node);
 
 	partition_active_processors = lparcfg_count_active_processors();
 
@@ -537,25 +539,27 @@ static int lparcfg_data(struct seq_file 
 
 	seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
 
-	rootdn = find_path_device("/");
+	rootdn = of_find_node_by_path("/");
 	if (rootdn) {
-		tmp = get_property(rootdn, "model", NULL);
+		tmp = of_get_property(rootdn, "model", NULL);
 		if (tmp) {
 			model = tmp;
 			/* Skip "IBM," - see platforms/iseries/dt.c */
 			if (firmware_has_feature(FW_FEATURE_ISERIES))
 				model += 4;
 		}
-		tmp = get_property(rootdn, "system-id", NULL);
+		tmp = of_get_property(rootdn, "system-id", NULL);
 		if (tmp) {
 			system_id = tmp;
 			/* Skip "IBM," - see platforms/iseries/dt.c */
 			if (firmware_has_feature(FW_FEATURE_ISERIES))
 				system_id += 4;
 		}
-		lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+		lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
+					NULL);
 		if (lp_index_ptr)
 			lp_index = *lp_index_ptr;
+		of_node_put(rootdn);
 	}
 	seq_printf(m, "serial_number=%s\n", system_id);
 	seq_printf(m, "system_type=%s\n", model);
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index a24b09c..704375b 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -72,8 +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 = get_property(node, "linux,tce-base", NULL);
-		sizep = get_property(node, "linux,tce-size", NULL);
+		basep = of_get_property(node, "linux,tce-base", NULL);
+		sizep = of_get_property(node, "linux,tce-size", NULL);
 		if (basep == NULL || sizep == NULL)
 			continue;
 
@@ -294,19 +294,19 @@ static unsigned long htab_base, kernel_e
 static struct property htab_base_prop = {
 	.name = "linux,htab-base",
 	.length = sizeof(unsigned long),
-	.value = (unsigned char *)&htab_base,
+	.value = &htab_base,
 };
 
 static struct property htab_size_prop = {
 	.name = "linux,htab-size",
 	.length = sizeof(unsigned long),
-	.value = (unsigned char *)&htab_size_bytes,
+	.value = &htab_size_bytes,
 };
 
 static struct property kernel_end_prop = {
 	.name = "linux,kernel-end",
 	.length = sizeof(unsigned long),
-	.value = (unsigned char *)&kernel_end,
+	.value = &kernel_end,
 };
 
 static void __init export_htab_values(void)
@@ -335,7 +335,7 @@ static void __init export_htab_values(vo
 static struct property crashk_base_prop = {
 	.name = "linux,crashkernel-base",
 	.length = sizeof(unsigned long),
-	.value = (unsigned char *)&crashk_res.start,
+	.value = &crashk_res.start,
 };
 
 static unsigned long crashk_size;
@@ -343,7 +343,7 @@ static unsigned long crashk_size;
 static struct property crashk_size_prop = {
 	.name = "linux,crashkernel-size",
 	.length = sizeof(unsigned long),
-	.value = (unsigned char *)&crashk_size,
+	.value = &crashk_size,
 };
 
 static void __init export_crashk_values(void)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 412bea3..98decf8 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -734,10 +734,6 @@ _GLOBAL(abs)
 	sub	r3,r3,r4
 	blr
 
-_GLOBAL(_get_SP)
-	mr	r3,r1		/* Close enough */
-	blr
-
 /*
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
new file mode 100644
index 0000000..c62d101
--- /dev/null
+++ b/arch/powerpc/kernel/msi.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/msi.h>
+
+#include <asm/machdep.h>
+
+int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+{
+	if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
+		pr_debug("msi: Platform doesn't provide MSI callbacks.\n");
+		return -ENOSYS;
+	}
+
+	if (ppc_md.msi_check_device) {
+		pr_debug("msi: Using platform check routine.\n");
+		return ppc_md.msi_check_device(dev, nvec, type);
+	}
+
+        return 0;
+}
+
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	return ppc_md.setup_msi_irqs(dev, nvec, type);
+}
+
+void arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+	return ppc_md.teardown_msi_irqs(dev);
+}
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index e921514..a464d67 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -27,7 +27,7 @@ const struct of_device_id *of_match_node
 			match &= node->type
 				&& !strcmp(matches->type, node->type);
 		if (matches->compatible[0])
-			match &= device_is_compatible(node,
+			match &= of_device_is_compatible(node,
 						      matches->compatible);
 		if (match)
 			return matches;
@@ -120,6 +120,117 @@ void of_device_unregister(struct of_devi
 }
 
 
+ssize_t of_device_get_modalias(struct of_device *ofdev,
+				char *str, ssize_t len)
+{
+	const char *compat;
+	int cplen, i;
+	ssize_t tsize, csize, repend;
+
+	/* Name & Type */
+	csize = snprintf(str, len, "of:N%sT%s",
+				ofdev->node->name, ofdev->node->type);
+
+	/* Get compatible property if any */
+	compat = of_get_property(ofdev->node, "compatible", &cplen);
+	if (!compat)
+		return csize;
+
+	/* Find true end (we tolerate multiple \0 at the end */
+	for (i=(cplen-1); i>=0 && !compat[i]; i--)
+		cplen--;
+	if (!cplen)
+		return csize;
+	cplen++;
+
+	/* Check space (need cplen+1 chars including final \0) */
+	tsize = csize + cplen;
+	repend = tsize;
+
+	if (csize>=len)		/* @ the limit, all is already filled */
+		return tsize;
+
+	if (tsize>=len) {		/* limit compat list */
+		cplen = len-csize-1;
+		repend = len;
+	}
+
+	/* Copy and do char replacement */
+	memcpy(&str[csize+1], compat, cplen);
+	for (i=csize; i<repend; i++) {
+		char c = str[i];
+		if (c=='\0')
+			str[i] = 'C';
+		else if (c==' ')
+			str[i] = '_';
+	}
+
+	return tsize;
+}
+
+int of_device_uevent(struct device *dev,
+		char **envp, int num_envp, char *buffer, int buffer_size)
+{
+	struct of_device *ofdev;
+	const char *compat;
+	int i = 0, length = 0, seen = 0, cplen, sl;
+
+	if (!dev)
+		return -ENODEV;
+
+	ofdev = to_of_device(dev);
+
+	if (add_uevent_var(envp, num_envp, &i,
+			   buffer, buffer_size, &length,
+			   "OF_NAME=%s", ofdev->node->name))
+		return -ENOMEM;
+
+	if (add_uevent_var(envp, num_envp, &i,
+			   buffer, buffer_size, &length,
+			   "OF_TYPE=%s", ofdev->node->type))
+		return -ENOMEM;
+
+        /* Since the compatible field can contain pretty much anything
+         * it's not really legal to split it out with commas. We split it
+         * up using a number of environment variables instead. */
+
+	compat = of_get_property(ofdev->node, "compatible", &cplen);
+	while (compat && *compat && cplen > 0) {
+		if (add_uevent_var(envp, num_envp, &i,
+				   buffer, buffer_size, &length,
+				   "OF_COMPATIBLE_%d=%s", seen, compat))
+			return -ENOMEM;
+
+		sl = strlen (compat) + 1;
+		compat += sl;
+		cplen -= sl;
+		seen++;
+	}
+
+	if (add_uevent_var(envp, num_envp, &i,
+			   buffer, buffer_size, &length,
+			   "OF_COMPATIBLE_N=%d", seen))
+		return -ENOMEM;
+
+	/* modalias is trickier, we add it in 2 steps */
+	if (add_uevent_var(envp, num_envp, &i,
+			   buffer, buffer_size, &length,
+			   "MODALIAS="))
+		return -ENOMEM;
+
+	sl = of_device_get_modalias(ofdev, &buffer[length-1],
+					buffer_size-length);
+	if (sl >= (buffer_size-length))
+		return -ENOMEM;
+
+	length += sl;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+
 EXPORT_SYMBOL(of_match_node);
 EXPORT_SYMBOL(of_match_device);
 EXPORT_SYMBOL(of_device_register);
@@ -127,3 +238,5 @@ EXPORT_SYMBOL(of_device_unregister);
 EXPORT_SYMBOL(of_dev_get);
 EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_release_dev);
+EXPORT_SYMBOL(of_device_uevent);
+EXPORT_SYMBOL(of_device_get_modalias);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index b734517..84c34d9 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -29,7 +29,6 @@ #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
 #include <asm/atomic.h>
 
-
 /*
  * The list of OF IDs below is used for matching bus types in the
  * system whose devices are to be exposed as of_platform_devices.
@@ -133,6 +132,7 @@ static int of_platform_device_resume(str
 struct bus_type of_platform_bus_type = {
        .name	= "of_platform",
        .match	= of_platform_bus_match,
+       .uevent	= of_device_uevent,
        .probe	= of_platform_device_probe,
        .remove	= of_platform_device_remove,
        .suspend	= of_platform_device_suspend,
@@ -177,7 +177,7 @@ static void of_platform_make_bus_id(stru
 	 * and 'D' for MMIO DCRs.
 	 */
 #ifdef CONFIG_PPC_DCR
-	reg = get_property(node, "dcr-reg", NULL);
+	reg = of_get_property(node, "dcr-reg", NULL);
 	if (reg) {
 #ifdef CONFIG_PPC_DCR_NATIVE
 		snprintf(name, BUS_ID_SIZE, "d%x.%s",
@@ -197,7 +197,7 @@ #endif /* CONFIG_PPC_DCR */
 	/*
 	 * For MMIO, get the physical address
 	 */
-	reg = get_property(node, "reg", NULL);
+	reg = of_get_property(node, "reg", NULL);
 	if (reg) {
 		addr = of_translate_address(node, reg);
 		if (addr != OF_BAD_ADDR) {
@@ -475,9 +475,6 @@ static struct of_platform_driver of_pci_
        .name = "of-pci",
        .match_table = of_pci_phb_ids,
        .probe = of_pci_phb_probe,
-       .driver = {
-	       .multithread_probe = 1,
-       },
 };
 
 static __init int of_pci_phb_init(void)
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index d8ef2e1..e66064b 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -637,7 +637,7 @@ make_one_node_map(struct device_node* no
 
 	if (pci_bus >= pci_bus_count)
 		return;
-	bus_range = get_property(node, "bus-range", &len);
+	bus_range = of_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);
@@ -649,17 +649,20 @@ make_one_node_map(struct device_node* no
 		struct pci_dev* dev;
 		const unsigned int *class_code, *reg;
 	
-		class_code = get_property(node, "class-code", NULL);
+		class_code = of_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 = get_property(node, "reg", NULL);
+		reg = of_get_property(node, "reg", NULL);
 		if (!reg)
 			continue;
-		dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
-		if (!dev || !dev->subordinate)
+		dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+		if (!dev || !dev->subordinate) {
+			pci_dev_put(dev);
 			continue;
+		}
 		make_one_node_map(node, dev->subordinate->number);
+		pci_dev_put(dev);
 	}
 }
 	
@@ -669,6 +672,7 @@ pcibios_make_OF_bus_map(void)
 	int i;
 	struct pci_controller* hose;
 	struct property *map_prop;
+	struct device_node *dn;
 
 	pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
 	if (!pci_to_OF_bus_map) {
@@ -690,12 +694,13 @@ pcibios_make_OF_bus_map(void)
 			continue;
 		make_one_node_map(node, hose->first_busno);
 	}
-	map_prop = of_find_property(find_path_device("/"),
-			"pci-OF-bus-map", NULL);
+	dn = of_find_node_by_path("/");
+	map_prop = of_find_property(dn, "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);
 	}
+	of_node_put(dn);
 #ifdef DEBUG
 	printk("PCI->OF bus map:\n");
 	for (i=0; i<pci_bus_count; i++) {
@@ -724,7 +729,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 = get_property(node, "class-code", NULL);
+		class_code = of_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"))
@@ -744,7 +749,7 @@ static struct device_node *scan_OF_for_p
 	unsigned int psize;
 
 	while ((np = of_get_next_child(parent, np)) != NULL) {
-		reg = get_property(np, "reg", &psize);
+		reg = of_get_property(np, "reg", &psize);
 		if (reg == NULL || psize < 4)
 			continue;
 		if (((reg[0] >> 8) & 0xff) == devfn)
@@ -859,7 +864,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 = get_property(node, "reg", NULL);
+	reg = of_get_property(node, "reg", NULL);
 	if (!reg)
 		return -ENODEV;
 	*bus = (reg[0] >> 16) & 0xff;
@@ -895,14 +900,14 @@ pci_process_bridge_OF_ranges(struct pci_
 	int rlen = 0, orig_rlen;
 	int memno = 0;
 	struct resource *res;
-	int np, na = prom_n_addr_cells(dev);
+	int np, na = of_n_addr_cells(dev);
 	np = na + 5;
 
 	/* First we try to merge ranges to fix a problem with some pmacs
 	 * that can have more than 3 ranges, fortunately using contiguous
 	 * addresses -- BenH
 	 */
-	dt_ranges = get_property(dev, "ranges", &rlen);
+	dt_ranges = of_get_property(dev, "ranges", &rlen);
 	if (!dt_ranges)
 		return;
 	/* Sanity check, though hopefully that never happens */
@@ -1006,14 +1011,19 @@ void __init
 pci_create_OF_bus_map(void)
 {
 	struct property* of_prop;
-	
+	struct device_node *dn;
+
 	of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
-	if (of_prop && find_path_device("/")) {
+	if (!of_prop)
+		return;
+	dn = of_find_node_by_path("/");
+	if (dn) {
 		memset(of_prop, -1, sizeof(struct property) + 256);
 		of_prop->name = "pci-OF-bus-map";
 		of_prop->length = 256;
-		of_prop->value = (unsigned char *)&of_prop[1];
-		prom_add_property(find_path_device("/"), of_prop);
+		of_prop->value = &of_prop[1];
+		prom_add_property(dn, of_prop);
+		of_node_put(dn);
 	}
 }
 
@@ -1648,7 +1658,7 @@ pgprot_t pci_phys_mem_access_prot(struct
 	int i;
 
 	if (page_is_ram(pfn))
-		return prot;
+		return __pgprot(prot);
 
 	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
 
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 7e97d71..6d05a1f 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -61,8 +61,7 @@ void iSeries_pcibios_init(void);
 
 LIST_HEAD(hose_list);
 
-struct dma_mapping_ops *pci_dma_ops;
-EXPORT_SYMBOL(pci_dma_ops);
+static struct dma_mapping_ops *pci_dma_ops;
 
 int global_phb_number;		/* Global phb counter */
 
@@ -70,6 +69,17 @@ int global_phb_number;		/* Global phb co
 struct pci_dev *ppc64_isabridge_dev = NULL;
 EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
 
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+	pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+	return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
 static void fixup_broken_pcnet32(struct pci_dev* dev)
 {
 	if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -258,7 +268,7 @@ static u32 get_int_prop(struct device_no
 	const u32 *prop;
 	int len;
 
-	prop = get_property(np, name, &len);
+	prop = of_get_property(np, name, &len);
 	if (prop && len >= 4)
 		return *prop;
 	return def;
@@ -291,7 +301,7 @@ static void pci_parse_of_addrs(struct de
 	u32 i;
 	int proplen;
 
-	addrs = get_property(node, "assigned-addresses", &proplen);
+	addrs = of_get_property(node, "assigned-addresses", &proplen);
 	if (!addrs)
 		return;
 	DBG("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
@@ -330,10 +340,10 @@ struct pci_dev *of_create_pci_dev(struct
 	struct pci_dev *dev;
 	const char *type;
 
-	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	dev = alloc_pci_dev();
 	if (!dev)
 		return NULL;
-	type = get_property(node, "device_type", NULL);
+	type = of_get_property(node, "device_type", NULL);
 	if (type == NULL)
 		type = "";
 
@@ -397,7 +407,7 @@ void __devinit of_scan_bus(struct device
 
 	while ((child = of_get_next_child(node, child)) != NULL) {
 		DBG("  * %s\n", child->full_name);
-		reg = get_property(child, "reg", &reglen);
+		reg = of_get_property(child, "reg", &reglen);
 		if (reg == NULL || reglen < 20)
 			continue;
 		devfn = (reg[0] >> 8) & 0xff;
@@ -430,13 +440,13 @@ void __devinit of_scan_pci_bridge(struct
 	DBG("of_scan_pci_bridge(%s)\n", node->full_name);
 
 	/* parse bus-range property */
-	busrange = get_property(node, "bus-range", &len);
+	busrange = of_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 = get_property(node, "ranges", &len);
+	ranges = of_get_property(node, "ranges", &len);
 	if (ranges == NULL) {
 		printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
 		       node->full_name);
@@ -900,7 +910,7 @@ static void __devinit pci_process_ISA_OF
 	unsigned int size;
 	int rlen = 0;
 
-	range = get_property(isa_node, "ranges", &rlen);
+	range = of_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");
@@ -947,7 +957,7 @@ void __devinit pci_process_bridge_OF_ran
 	int rlen = 0;
 	int memno = 0;
 	struct resource *res;
-	int np, na = prom_n_addr_cells(dev);
+	int np, na = of_n_addr_cells(dev);
 	unsigned long pci_addr, cpu_phys_addr;
 
 	np = na + 5;
@@ -960,7 +970,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 = get_property(dev, "ranges", &rlen);
+	ranges = of_get_property(dev, "ranges", &rlen);
 	if (ranges == NULL)
 		return;
 	hose->io_base_phys = 0;
@@ -996,8 +1006,9 @@ void __devinit pci_process_bridge_OF_ran
 
 		switch ((pci_space >> 24) & 0x3) {
 		case 1:		/* I/O space */
-			hose->io_base_phys = cpu_phys_addr;
-			hose->pci_io_size = size;
+			hose->io_base_phys = cpu_phys_addr - pci_addr;
+			/* handle from 0 to top of I/O window */
+			hose->pci_io_size = pci_addr + size;
 
 			res = &hose->io_resource;
 			res->flags = IORESOURCE_IO;
@@ -1107,8 +1118,8 @@ static int get_bus_io_range(struct pci_b
 	} else {
 		/* Root Bus */
 		res = &hose->io_resource;
-		*start_phys = hose->io_base_phys;
-		*start_virt = (unsigned long) hose->io_base_virt;
+		*start_phys = hose->io_base_phys + res->start;
+		*start_virt = (unsigned long) hose->io_base_virt + res->start;
 		if (res->end > res->start)
 			*size = res->end - res->start + 1;
 		else {
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 68df018..d7d36df 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -40,7 +40,8 @@ #include <asm/firmware.h>
 static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
 {
 	struct pci_controller *phb = data;
-	const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
+	const int *type =
+		of_get_property(dn, "ibm,pci-config-space-type", NULL);
 	const u32 *regs;
 	struct pci_dn *pdn;
 
@@ -54,14 +55,14 @@ static void * __devinit update_dn_pci_in
 	dn->data = pdn;
 	pdn->node = dn;
 	pdn->phb = phb;
-	regs = get_property(dn, "reg", NULL);
+	regs = of_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)) {
-		const u32 *busp = get_property(dn, "linux,subbus", NULL);
+		const u32 *busp = of_get_property(dn, "linux,subbus", NULL);
 		if (busp)
 			pdn->bussubno = *busp;
 	}
@@ -100,7 +101,7 @@ void *traverse_pci_devices(struct device
 		u32 class;
 
 		nextdn = NULL;
-		classp = get_property(dn, "class-code", NULL);
+		classp = of_get_property(dn, "class-code", NULL);
 		class = classp ? *classp : 0;
 
 		if (pre && ((ret = pre(dn, data)) != NULL))
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index ecee596..c96fa9b 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -20,7 +20,6 @@ #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/ide.h>
 #include <asm/atomic.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
@@ -67,7 +66,6 @@ EXPORT_SYMBOL(clear_pages);
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
-EXPORT_SYMBOL(__div64_32);
 
 EXPORT_SYMBOL(do_signal);
 EXPORT_SYMBOL(transfer_to_handler);
@@ -84,8 +82,6 @@ EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcasecmp);
-EXPORT_SYMBOL(strncasecmp);
 
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e53b298..6e2f035 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -19,7 +19,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -305,9 +304,7 @@ #ifdef CONFIG_PPC64	/* for now */
 		set_dabr(new->thread.dabr);
 		__get_cpu_var(current_dabr) = new->thread.dabr;
 	}
-
-	flush_tlb_pending();
-#endif
+#endif /* CONFIG_PPC64 */
 
 	new_thread = &new->thread;
 	old_thread = &current->thread;
@@ -402,11 +399,11 @@ static void printbits(unsigned long val,
 }
 
 #ifdef CONFIG_PPC64
-#define REG		"%016lX"
+#define REG		"%016lx"
 #define REGS_PER_LINE	4
 #define LAST_VOLATILE	13
 #else
-#define REG		"%08lX"
+#define REG		"%08lx"
 #define REGS_PER_LINE	8
 #define LAST_VOLATILE	12
 #endif
@@ -421,7 +418,7 @@ void show_regs(struct pt_regs * regs)
 	       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);
+	printk("  CR: %08lx  XER: %08lx\n", regs->ccr, regs->xer);
 	trap = TRAP(regs);
 	if (trap == 0x300 || trap == 0x600)
 		printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -572,7 +569,6 @@ #ifdef CONFIG_PPC64
 	kregs->nip = *((unsigned long *)ret_from_fork);
 #else
 	kregs->nip = (unsigned long)ret_from_fork;
-	p->thread.last_syscall = -1;
 #endif
 
 	return 0;
@@ -823,6 +819,35 @@ out:
 	return error;
 }
 
+#ifdef CONFIG_IRQSTACKS
+static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
+				  unsigned long nbytes)
+{
+	unsigned long stack_page;
+	unsigned long cpu = task_cpu(p);
+
+	/*
+	 * Avoid crashing if the stack has overflowed and corrupted
+	 * task_cpu(p), which is in the thread_info struct.
+	 */
+	if (cpu < NR_CPUS && cpu_possible(cpu)) {
+		stack_page = (unsigned long) hardirq_ctx[cpu];
+		if (sp >= stack_page + sizeof(struct thread_struct)
+		    && sp <= stack_page + THREAD_SIZE - nbytes)
+			return 1;
+
+		stack_page = (unsigned long) softirq_ctx[cpu];
+		if (sp >= stack_page + sizeof(struct thread_struct)
+		    && sp <= stack_page + THREAD_SIZE - nbytes)
+			return 1;
+	}
+	return 0;
+}
+
+#else
+#define valid_irq_stack(sp, p, nb)	0
+#endif /* CONFIG_IRQSTACKS */
+
 int validate_sp(unsigned long sp, struct task_struct *p,
 		       unsigned long nbytes)
 {
@@ -832,19 +857,7 @@ int validate_sp(unsigned long sp, struct
 	    && sp <= stack_page + THREAD_SIZE - nbytes)
 		return 1;
 
-#ifdef CONFIG_IRQSTACKS
-	stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
-	if (sp >= stack_page + sizeof(struct thread_struct)
-	    && sp <= stack_page + THREAD_SIZE - nbytes)
-		return 1;
-
-	stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
-	if (sp >= stack_page + sizeof(struct thread_struct)
-	    && sp <= stack_page + THREAD_SIZE - nbytes)
-		return 1;
-#endif
-
-	return 0;
+	return valid_irq_stack(sp, p, nbytes);
 }
 
 #ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 8d52b23..caef555 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -390,18 +390,19 @@ #endif
 		if (allnextpp) {
 			pp->name = "name";
 			pp->length = sz;
-			pp->value = (unsigned char *)(pp + 1);
+			pp->value = pp + 1;
 			*prev_pp = pp;
 			prev_pp = &pp->next;
 			memcpy(pp->value, ps, sz - 1);
 			((char *)pp->value)[sz - 1] = 0;
-			DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+			DBG("fixed up name for %s -> %s\n", pathp,
+				(char *)pp->value);
 		}
 	}
 	if (allnextpp) {
 		*prev_pp = NULL;
-		np->name = get_property(np, "name", NULL);
-		np->type = get_property(np, "device_type", NULL);
+		np->name = of_get_property(np, "name", NULL);
+		np->type = of_get_property(np, "device_type", NULL);
 
 		if (!np->name)
 			np->name = "<NULL>";
@@ -719,6 +720,7 @@ static int __init early_init_dt_scan_cho
 					    const char *uname, int depth, void *data)
 {
 	unsigned long *lprop;
+	u32 *prop;
 	unsigned long l;
 	char *p;
 
@@ -760,6 +762,22 @@ #ifdef CONFIG_KEXEC
                crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	DBG("Looking for initrd properties... ");
+	prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+	if (prop) {
+		initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+		prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+		if (prop) {
+			initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
+			initrd_below_start_ok = 1;
+		} else {
+			initrd_start = 0;
+		}
+	}
+	DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 	/* Retreive command line */
  	p = of_get_flat_dt_prop(node, "bootargs", &l);
 	if (p != NULL && l > 0)
@@ -926,6 +944,12 @@ static void __init early_reserve_mem(voi
 	self_size = initial_boot_params->totalsize;
 	lmb_reserve(self_base, self_size);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* then reserve the initrd, if any */
+	if (initrd_start && (initrd_end > initrd_start))
+		lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 #ifdef CONFIG_PPC32
 	/* 
 	 * Handle the case where we might be booting from an old kexec
@@ -954,9 +978,6 @@ #endif
 		size = *(reserve_map++);
 		if (size == 0)
 			break;
-		/* skip if the reservation is for the blob */
-		if (base == self_base && size == self_size)
-			continue;
 		DBG("reserving: %llx -> %llx\n", base, size);
 		lmb_reserve(base, size);
 	}
@@ -1021,102 +1042,46 @@ #endif
 
 #undef printk
 
-int
-prom_n_addr_cells(struct device_node* np)
+int of_n_addr_cells(struct device_node* np)
 {
 	const int *ip;
 	do {
 		if (np->parent)
 			np = np->parent;
-		ip = get_property(np, "#address-cells", NULL);
+		ip = of_get_property(np, "#address-cells", NULL);
 		if (ip != NULL)
 			return *ip;
 	} while (np->parent);
 	/* No #address-cells property for the root node, default to 1 */
 	return 1;
 }
-EXPORT_SYMBOL(prom_n_addr_cells);
+EXPORT_SYMBOL(of_n_addr_cells);
 
-int
-prom_n_size_cells(struct device_node* np)
+int of_n_size_cells(struct device_node* np)
 {
 	const int* ip;
 	do {
 		if (np->parent)
 			np = np->parent;
-		ip = get_property(np, "#size-cells", NULL);
+		ip = of_get_property(np, "#size-cells", NULL);
 		if (ip != NULL)
 			return *ip;
 	} while (np->parent);
 	/* No #size-cells property for the root node, default to 1 */
 	return 1;
 }
-EXPORT_SYMBOL(prom_n_size_cells);
-
-/**
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *find_devices(const char *name)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-EXPORT_SYMBOL(find_devices);
-
-/**
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *find_type_devices(const char *type)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-EXPORT_SYMBOL(find_type_devices);
-
-/**
- * Returns all nodes linked together
- */
-struct device_node *find_all_nodes(void)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		*prevp = np;
-		prevp = &np->next;
-	}
-	*prevp = NULL;
-	return head;
-}
-EXPORT_SYMBOL(find_all_nodes);
+EXPORT_SYMBOL(of_n_size_cells);
 
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
-int device_is_compatible(const struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+		const char *compat)
 {
 	const char* cp;
 	int cplen, l;
 
-	cp = get_property(device, "compatible", &cplen);
+	cp = of_get_property(device, "compatible", &cplen);
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
@@ -1129,7 +1094,7 @@ int device_is_compatible(const struct de
 
 	return 0;
 }
-EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(of_device_is_compatible);
 
 
 /**
@@ -1143,51 +1108,13 @@ int machine_is_compatible(const char *co
 
 	root = of_find_node_by_path("/");
 	if (root) {
-		rc = device_is_compatible(root, compat);
+		rc = of_device_is_compatible(root, compat);
 		of_node_put(root);
 	}
 	return rc;
 }
 EXPORT_SYMBOL(machine_is_compatible);
 
-/**
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *find_compatible_devices(const char *type,
-					    const char *compat)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-			continue;
-		if (device_is_compatible(np, compat)) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = NULL;
-	return head;
-}
-EXPORT_SYMBOL(find_compatible_devices);
-
-/**
- * Find the device_node with a given full_name.
- */
-struct device_node *find_path_device(const char *path)
-{
-	struct device_node *np;
-
-	for (np = allnodes; np != 0; np = np->allnext)
-		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
-			return np;
-	return NULL;
-}
-EXPORT_SYMBOL(find_path_device);
-
 /*******
  *
  * New implementation of the OF "find" APIs, return a refcounted
@@ -1280,7 +1207,7 @@ struct device_node *of_find_compatible_n
 		if (type != NULL
 		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
 			continue;
-		if (device_is_compatible(np, compatible) && of_node_get(np))
+		if (of_device_is_compatible(np, compatible) && of_node_get(np))
 			break;
 	}
 	of_node_put(from);
@@ -1527,8 +1454,8 @@ static int of_finish_dynamic_node(struct
 	int err = 0;
 	const phandle *ibm_phandle;
 
-	node->name = get_property(node, "name", NULL);
-	node->type = get_property(node, "device_type", NULL);
+	node->name = of_get_property(node, "name", NULL);
+	node->type = of_get_property(node, "device_type", NULL);
 
 	if (!parent) {
 		err = -ENODEV;
@@ -1542,7 +1469,7 @@ static int of_finish_dynamic_node(struct
 		return -ENODEV;
 
 	/* fix up new node's linux_phandle field */
-	if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
+	if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
 		node->linux_phandle = *ibm_phandle;
 
 out:
@@ -1605,13 +1532,13 @@ EXPORT_SYMBOL(of_find_property);
  * Find a property with a given name for a given node
  * and return the value.
  */
-const void *get_property(const struct device_node *np, const char *name,
+const void *of_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;
 }
-EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(of_get_property);
 
 /*
  * Add a property to a node
@@ -1742,10 +1669,10 @@ struct device_node *of_get_cpu_node(int 
 		/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
 		 * fallback to "reg" property and assume no threads
 		 */
-		intserv = get_property(np, "ibm,ppc-interrupt-server#s",
+		intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
 				&plen);
 		if (intserv == NULL) {
-			const u32 *reg = get_property(np, "reg", NULL);
+			const u32 *reg = of_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 4fb5938..d6047c4 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -635,6 +635,12 @@ #define OV5_SPLPAR		0x40	/* shared-proce
 /* ibm,dynamic-reconfiguration-memory property supported */
 #define OV5_DRCONF_MEMORY	0x20
 #define OV5_LARGE_PAGES		0x10	/* large pages supported */
+/* PCIe/MSI support.  Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI			0x01	/* PCIe/MSI support */
+#else
+#define OV5_MSI			0x00
+#endif /* CONFIG_PCI_MSI */
 
 /*
  * The architecture vector has an array of PVR mask/value pairs,
@@ -679,7 +685,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 2,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
@@ -967,7 +973,7 @@ #endif
  * If problems seem to show up, it would be a good start to track
  * them down.
  */
-static void reserve_mem(u64 base, u64 size)
+static void __init reserve_mem(u64 base, u64 size)
 {
 	u64 top = base + size;
 	unsigned long cnt = RELOC(mem_reserve_cnt);
@@ -2035,39 +2041,50 @@ #define fixup_device_tree_maple()
 #endif
 
 #ifdef CONFIG_PPC_CHRP
-/* Pegasos and BriQ lacks the "ranges" property in the isa node */
+/*
+ * Pegasos and BriQ lacks the "ranges" property in the isa node
+ * Pegasos needs decimal IRQ 14/15, not hexadecimal
+ */
 static void __init fixup_device_tree_chrp(void)
 {
-	phandle isa;
-	u32 isa_ranges[6];
+	phandle ph;
+	u32 prop[6];
 	u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
 	char *name;
 	int rc;
 
 	name = "/pci@80000000/isa@c";
-	isa = call_prom("finddevice", 1, 1, ADDR(name));
-	if (!PHANDLE_VALID(isa)) {
+	ph = call_prom("finddevice", 1, 1, ADDR(name));
+	if (!PHANDLE_VALID(ph)) {
 		name = "/pci@ff500000/isa@6";
-		isa = call_prom("finddevice", 1, 1, ADDR(name));
+		ph = call_prom("finddevice", 1, 1, ADDR(name));
 		rloc = 0x01003000; /* IO space; PCI device = 6 */
 	}
-	if (!PHANDLE_VALID(isa))
-		return;
-
-	rc = prom_getproplen(isa, "ranges");
-	if (rc != 0 && rc != PROM_ERROR)
-		return;
-
-	prom_printf("Fixing up missing ISA range on Pegasos...\n");
+	if (PHANDLE_VALID(ph)) {
+		rc = prom_getproplen(ph, "ranges");
+		if (rc == 0 || rc == PROM_ERROR) {
+			prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+			prop[0] = 0x1;
+			prop[1] = 0x0;
+			prop[2] = rloc;
+			prop[3] = 0x0;
+			prop[4] = 0x0;
+			prop[5] = 0x00010000;
+			prom_setprop(ph, name, "ranges", prop, sizeof(prop));
+		}
+	}
 
-	isa_ranges[0] = 0x1;
-	isa_ranges[1] = 0x0;
-	isa_ranges[2] = rloc;
-	isa_ranges[3] = 0x0;
-	isa_ranges[4] = 0x0;
-	isa_ranges[5] = 0x00010000;
-	prom_setprop(isa, name, "ranges",
-			isa_ranges, sizeof(isa_ranges));
+	name = "/pci@80000000/ide@C,1";
+	ph = call_prom("finddevice", 1, 1, ADDR(name));
+	if (PHANDLE_VALID(ph)) {
+		prom_printf("Fixing up IDE interrupt on Pegasos...\n");
+		prop[0] = 14;
+		prop[1] = 0x0;
+		prop[2] = 15;
+		prop[3] = 0x0;
+		prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32));
+	}
 }
 #else
 #define fixup_device_tree_chrp()
@@ -2142,7 +2159,7 @@ static void __init fixup_device_tree_efi
 	                             3,12,0, 3,13,0, 3,14,0, 3,15,0 };
 	struct subst_entry efika_subst_table[] = {
 		{ "/",			"device_type",	prop_cstr("efika") },
-		{ "/builtin",		"compatible",	prop_cstr("soc") },
+		{ "/builtin",		"device_type",	prop_cstr("soc") },
 		{ "/builtin/ata",	"compatible",	prop_cstr("mpc5200b-ata\0mpc5200-ata"), },
 		{ "/builtin/bestcomm",	"compatible",	prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") },
 		{ "/builtin/bestcomm",	"interrupts",	prop_bcomm_irq, sizeof(prop_bcomm_irq) },
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 91b443c..b5c96af 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -68,9 +68,9 @@ static void of_bus_default_count_cells(s
 				       int *addrc, int *sizec)
 {
 	if (addrc)
-		*addrc = prom_n_addr_cells(dev);
+		*addrc = of_n_addr_cells(dev);
 	if (sizec)
-		*sizec = prom_n_size_cells(dev);
+		*sizec = of_n_size_cells(dev);
 }
 
 static u64 of_bus_default_map(u32 *addr, const u32 *range,
@@ -196,7 +196,7 @@ const u32 *of_get_pci_address(struct dev
 		return NULL;
 
 	/* Get "reg" or "assigned-addresses" property */
-	prop = get_property(dev, bus->addresses, &psize);
+	prop = of_get_property(dev, bus->addresses, &psize);
 	if (prop == NULL)
 		return NULL;
 	psize /= 4;
@@ -438,7 +438,7 @@ static int of_translate_one(struct devic
 	 * to translate addresses that aren't supposed to be translated in
 	 * the first place. --BenH.
 	 */
-	ranges = get_property(parent, "ranges", &rlen);
+	ranges = of_get_property(parent, "ranges", &rlen);
 	if (ranges == NULL || rlen == 0) {
 		offset = of_read_number(addr, na);
 		memset(addr, 0, pna * 4);
@@ -578,7 +578,7 @@ const u32 *of_get_address(struct device_
 		return NULL;
 
 	/* Get "reg" or "assigned-addresses" property */
-	prop = get_property(dev, bus->addresses, &psize);
+	prop = of_get_property(dev, bus->addresses, &psize);
 	if (prop == NULL)
 		return NULL;
 	psize /= 4;
@@ -650,17 +650,17 @@ void of_parse_dma_window(struct device_n
 	/* busno is always one cell */
 	*busno = *(dma_window++);
 
-	prop = get_property(dn, "ibm,#dma-address-cells", NULL);
+	prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
 	if (!prop)
-		prop = get_property(dn, "#address-cells", NULL);
+		prop = of_get_property(dn, "#address-cells", NULL);
 
-	cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
+	cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
 	*phys = of_read_number(dma_window, cells);
 
 	dma_window += cells;
 
-	prop = get_property(dn, "ibm,#dma-size-cells", NULL);
-	cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
+	prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
+	cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
 	*size = of_read_number(dma_window, cells);
 }
 
@@ -680,7 +680,7 @@ static struct device_node *of_irq_find_p
 		return NULL;
 
 	do {
-		parp = get_property(child, "interrupt-parent", NULL);
+		parp = of_get_property(child, "interrupt-parent", NULL);
 		if (parp == NULL)
 			p = of_get_parent(child);
 		else {
@@ -691,7 +691,7 @@ static struct device_node *of_irq_find_p
 		}
 		of_node_put(child);
 		child = p;
-	} while (p && get_property(p, "#interrupt-cells", NULL) == NULL);
+	} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
 
 	return p;
 }
@@ -716,7 +716,7 @@ void of_irq_map_init(unsigned int flags)
 		struct device_node *np;
 
 		for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
-			if (get_property(np, "interrupt-controller", NULL)
+			if (of_get_property(np, "interrupt-controller", NULL)
 			    == NULL)
 				continue;
 			/* Skip /chosen/interrupt-controller */
@@ -755,7 +755,7 @@ int of_irq_map_raw(struct device_node *p
 	 * is none, we are nice and just walk up the tree
 	 */
 	do {
-		tmp = get_property(ipar, "#interrupt-cells", NULL);
+		tmp = of_get_property(ipar, "#interrupt-cells", NULL);
 		if (tmp != NULL) {
 			intsize = *tmp;
 			break;
@@ -779,7 +779,7 @@ int of_irq_map_raw(struct device_node *p
 	 */
 	old = of_node_get(ipar);
 	do {
-		tmp = get_property(old, "#address-cells", NULL);
+		tmp = of_get_property(old, "#address-cells", NULL);
 		tnode = of_get_parent(old);
 		of_node_put(old);
 		old = tnode;
@@ -795,7 +795,8 @@ int of_irq_map_raw(struct device_node *p
 		/* Now check if cursor is an interrupt-controller and if it is
 		 * then we are done
 		 */
-		if (get_property(ipar, "interrupt-controller", NULL) != NULL) {
+		if (of_get_property(ipar, "interrupt-controller", NULL) !=
+				NULL) {
 			DBG(" -> got it !\n");
 			memcpy(out_irq->specifier, intspec,
 			       intsize * sizeof(u32));
@@ -806,7 +807,7 @@ int of_irq_map_raw(struct device_node *p
 		}
 
 		/* Now look for an interrupt-map */
-		imap = get_property(ipar, "interrupt-map", &imaplen);
+		imap = of_get_property(ipar, "interrupt-map", &imaplen);
 		/* No interrupt map, check for an interrupt parent */
 		if (imap == NULL) {
 			DBG(" -> no map, getting parent\n");
@@ -816,7 +817,7 @@ int of_irq_map_raw(struct device_node *p
 		imaplen /= sizeof(u32);
 
 		/* Look for a mask */
-		imask = get_property(ipar, "interrupt-map-mask", NULL);
+		imask = of_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.
@@ -863,15 +864,13 @@ int of_irq_map_raw(struct device_node *p
 			/* Get #interrupt-cells and #address-cells of new
 			 * parent
 			 */
-			tmp = get_property(newpar, "#interrupt-cells",
-						  NULL);
+			tmp = of_get_property(newpar, "#interrupt-cells", NULL);
 			if (tmp == NULL) {
 				DBG(" -> parent lacks #interrupt-cells !\n");
 				goto fail;
 			}
 			newintsize = *tmp;
-			tmp = get_property(newpar, "#address-cells",
-						  NULL);
+			tmp = of_get_property(newpar, "#address-cells", NULL);
 			newaddrsize = (tmp == NULL) ? 0 : *tmp;
 
 			DBG(" -> newintsize=%d, newaddrsize=%d\n",
@@ -928,7 +927,7 @@ static int of_irq_map_oldworld(struct de
 	 * everything together on these)
 	 */
 	while (device) {
-		ints = get_property(device, "AAPL,interrupts", &intlen);
+		ints = of_get_property(device, "AAPL,interrupts", &intlen);
 		if (ints != NULL)
 			break;
 		device = device->parent;
@@ -970,13 +969,13 @@ int of_irq_map_one(struct device_node *d
 		return of_irq_map_oldworld(device, index, out_irq);
 
 	/* Get the interrupts property */
-	intspec = get_property(device, "interrupts", &intlen);
+	intspec = of_get_property(device, "interrupts", &intlen);
 	if (intspec == NULL)
 		return -EINVAL;
 	intlen /= sizeof(u32);
 
 	/* Get the reg property (if any) */
-	addr = get_property(device, "reg", NULL);
+	addr = of_get_property(device, "reg", NULL);
 
 	/* Look for the interrupt parent. */
 	p = of_irq_find_parent(device);
@@ -984,7 +983,7 @@ int of_irq_map_one(struct device_node *d
 		return -EINVAL;
 
 	/* Get size of interrupt specifier */
-	tmp = get_property(p, "#interrupt-cells", NULL);
+	tmp = of_get_property(p, "#interrupt-cells", NULL);
 	if (tmp == NULL) {
 		of_node_put(p);
 		return -EINVAL;
@@ -1043,3 +1042,28 @@ const void *of_get_mac_address(struct de
 }
 EXPORT_SYMBOL(of_get_mac_address);
 
+int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
+{
+	int irq = irq_of_parse_and_map(dev, index);
+
+	/* Only dereference the resource if both the
+	 * resource and the irq are valid. */
+	if (r && irq != NO_IRQ) {
+		r->start = r->end = irq;
+		r->flags = IORESOURCE_IRQ;
+	}
+
+	return irq;
+}
+EXPORT_SYMBOL_GPL(of_irq_to_resource);
+
+void __iomem *of_iomap(struct device_node *np, int index)
+{
+	struct resource res;
+
+	if (of_address_to_resource(np, index, &res))
+		return NULL;
+
+	return ioremap(res.start, 1 + res.end - res.start);
+}
+EXPORT_SYMBOL(of_iomap);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index cc44c7b..f4f391c 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -19,7 +19,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 6cbf2ae..190b7ed 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -450,7 +450,7 @@ static int ppc_rtas_sensors_show(struct 
 		int llen, offs;
 
 		sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
-		loc = get_property(rtas_node, rstr, &llen);
+		loc = of_get_property(rtas_node, rstr, &llen);
 
 		/* A sensor may have multiple instances */
 		for (j = 0, offs = 0; j <= p->quant; j++) {
@@ -477,7 +477,7 @@ static int ppc_rtas_find_all_sensors(voi
 	const unsigned int *utmp;
 	int len, i;
 
-	utmp = get_property(rtas_node, "rtas-sensors", &len);
+	utmp = of_get_property(rtas_node, "rtas-sensors", &len);
 	if (utmp == NULL) {
 		printk (KERN_ERR "error: could not get rtas-sensors\n");
 		return 1;
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 9d0735a..2147807 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -192,18 +192,19 @@ void rtas_progress(char *s, unsigned sho
 
 	if (display_width == 0) {
 		display_width = 0x10;
-		if ((root = find_path_device("/rtas"))) {
-			if ((p = get_property(root,
+		if ((root = of_find_node_by_path("/rtas"))) {
+			if ((p = of_get_property(root,
 					"ibm,display-line-length", NULL)))
 				display_width = *p;
-			if ((p = get_property(root,
+			if ((p = of_get_property(root,
 					"ibm,form-feed", NULL)))
 				form_feed = *p;
-			if ((p = get_property(root,
+			if ((p = of_get_property(root,
 					"ibm,display-number-of-lines", NULL)))
 				display_lines = *p;
-			row_width = get_property(root,
+			row_width = of_get_property(root,
 					"ibm,display-truncation-length", NULL);
+			of_node_put(root);
 		}
 		display_character = rtas_token("display-character");
 		set_indicator = rtas_token("set-indicator");
@@ -298,7 +299,7 @@ int rtas_token(const char *service)
 	const int *tokp;
 	if (rtas.dev == NULL)
 		return RTAS_UNKNOWN_SERVICE;
-	tokp = get_property(rtas.dev, service, NULL);
+	tokp = of_get_property(rtas.dev, service, NULL);
 	return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
 }
 EXPORT_SYMBOL(rtas_token);
@@ -832,12 +833,12 @@ void __init rtas_initialize(void)
 	if (rtas.dev) {
 		const u32 *basep, *entryp, *sizep;
 
-		basep = get_property(rtas.dev, "linux,rtas-base", NULL);
-		sizep = get_property(rtas.dev, "rtas-size", NULL);
+		basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
+		sizep = of_get_property(rtas.dev, "rtas-size", NULL);
 		if (basep != NULL && sizep != NULL) {
 			rtas.base = *basep;
 			rtas.size = *sizep;
-			entryp = get_property(rtas.dev,
+			entryp = of_get_property(rtas.dev,
 					"linux,rtas-entry", NULL);
 			if (entryp == NULL) /* Ugh */
 				rtas.entry = rtas.base;
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index ace9f4c..f228682 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -60,7 +60,7 @@ static int of_device_available(struct de
 {
         const char *status;
 
-        status = get_property(dn, "status", NULL);
+        status = of_get_property(dn, "status", NULL);
 
         if (!status)
                 return 1;
@@ -177,7 +177,7 @@ struct pci_ops rtas_pci_ops = {
 
 int is_python(struct device_node *dev)
 {
-	const char *model = get_property(dev, "model", NULL);
+	const char *model = of_get_property(dev, "model", NULL);
 
 	if (model && strstr(model, "Python"))
 		return 1;
@@ -247,7 +247,7 @@ static int phb_set_bus_ranges(struct dev
 	const int *bus_range;
 	unsigned int len;
 
-	bus_range = get_property(dev, "bus-range", &len);
+	bus_range = of_get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		return 1;
  	}
@@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_
 	return 0;
 }
 
-unsigned long __init find_and_init_phbs(void)
+void __init find_and_init_phbs(void)
 {
 	struct device_node *node;
 	struct pci_controller *phb;
@@ -309,18 +309,16 @@ unsigned long __init find_and_init_phbs(
 	if (of_chosen) {
 		const int *prop;
 
-		prop = get_property(of_chosen,
+		prop = of_get_property(of_chosen,
 				"linux,pci-probe-only", NULL);
 		if (prop)
 			pci_probe_only = *prop;
 
-		prop = get_property(of_chosen,
+		prop = of_get_property(of_chosen,
 				"linux,pci-assign-all-buses", NULL);
 		if (prop)
 			pci_assign_all_buses = *prop;
 	}
-
-	return 0;
 }
 
 /* RPA-specific bits for removing PHBs */
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 89cfaf4..3708037 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -21,7 +21,6 @@ #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
 #include <linux/platform_device.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
@@ -304,26 +303,8 @@ struct seq_operations cpuinfo_op = {
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
-	const unsigned int *prop;
-	int len;
-
-	DBG(" -> check_for_initrd()\n");
-
-	if (of_chosen) {
-		prop = get_property(of_chosen, "linux,initrd-start", &len);
-		if (prop != 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(of_read_ulong(prop, len / 4));
-				initrd_below_start_ok = 1;
-			} else
-				initrd_start = 0;
-		}
-	}
+	DBG(" -> check_for_initrd()  initrd_start=0x%lx  initrd_end=0x%lx\n",
+	    initrd_start, initrd_end);
 
 	/* If we were passed an initrd, set the ROOT_DEV properly if the values
 	 * look sensible. If not, clear initrd reference.
@@ -371,11 +352,12 @@ void __init smp_setup_cpu_maps(void)
 		const int *intserv;
 		int j, len = sizeof(u32), nthreads = 1;
 
-		intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+		intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
+				&len);
 		if (intserv)
 			nthreads = len / sizeof(int);
 		else {
-			intserv = get_property(dn, "reg", NULL);
+			intserv = of_get_property(dn, "reg", NULL);
 			if (!intserv)
 				intserv = &cpu;	/* assume logical == phys */
 		}
@@ -398,10 +380,10 @@ #ifdef CONFIG_PPC64
 		int num_addr_cell, num_size_cell, maxcpus;
 		const unsigned int *ireg;
 
-		num_addr_cell = prom_n_addr_cells(dn);
-		num_size_cell = prom_n_size_cells(dn);
+		num_addr_cell = of_n_addr_cells(dn);
+		num_size_cell = of_n_size_cells(dn);
 
-		ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
+		ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL);
 
 		if (!ireg)
 			goto out;
@@ -496,11 +478,39 @@ void probe_machine(void)
 	printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
 }
 
+/* Match a class of boards, not a specific device configuration. */
 int check_legacy_ioport(unsigned long base_port)
 {
-	if (ppc_md.check_legacy_ioport == NULL)
-		return 0;
-	return ppc_md.check_legacy_ioport(base_port);
+	struct device_node *parent, *np = NULL;
+	int ret = -ENODEV;
+
+	switch(base_port) {
+	case I8042_DATA_REG:
+		np = of_find_node_by_type(NULL, "8042");
+		break;
+	case FDC_BASE: /* FDC1 */
+		np = of_find_node_by_type(NULL, "fdc");
+		break;
+#ifdef CONFIG_PPC_PREP
+	case _PIDXR:
+	case _PNPWRP:
+	case PNPBIOS_BASE:
+		/* implement me */
+#endif
+	default:
+		/* ipmi is supposed to fail here */
+		break;
+	}
+	if (!np)
+		return ret;
+	parent = of_get_parent(np);
+	if (parent) {
+		if (strcmp(parent->type, "isa") == 0)
+			ret = 0;
+		of_node_put(parent);
+	}
+	of_node_put(np);
+	return ret;
 }
 EXPORT_SYMBOL(check_legacy_ioport);
 
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 44a6a3c..35f8f44 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -92,7 +92,8 @@ unsigned long __init early_init(unsigned
 
 	/* First zero the BSS -- use memset_io, some platforms don't have
 	 * caches on yet */
-	memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
+	memset_io((void __iomem *)PTRRELOC(&__bss_start), 0,
+			__bss_stop - __bss_start);
 
 	/*
 	 * Identify the CPU type and fix up code sections
@@ -195,18 +196,22 @@ EXPORT_SYMBOL(nvram_sync);
 
 #endif /* CONFIG_NVRAM */
 
-static struct cpu cpu_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 int __init ppc_init(void)
 {
-	int i;
+	int cpu;
 
 	/* clear the progress line */
-	if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
+	if (ppc_md.progress)
+		ppc_md.progress("             ", 0xffff);
 
 	/* register CPU devices */
-	for_each_possible_cpu(i)
-		register_cpu(&cpu_devices[i], i);
+	for_each_possible_cpu(cpu) {
+		struct cpu *c = &per_cpu(cpu_devices, cpu);
+		c->hotpluggable = 1;
+		register_cpu(c, cpu);
+	}
 
 	/* call platform init */
 	if (ppc_md.init != NULL) {
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 3733de3..6018178 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -20,7 +20,6 @@ #include <linux/kernel.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/initrd.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
@@ -110,7 +109,7 @@ static void check_smt_enabled(void)
 	dn = of_find_node_by_path("/options");
 
 	if (dn) {
-		smt_option = get_property(dn, "ibm,smt-enabled", NULL);
+		smt_option = of_get_property(dn, "ibm,smt-enabled", NULL);
 
                 if (smt_option) {
 			if (!strcmp(smt_option, "on"))
@@ -305,10 +304,10 @@ static void __init initialize_cache_info
 
 			size = 0;
 			lsize = cur_cpu_spec->dcache_bsize;
-			sizep = get_property(np, "d-cache-size", NULL);
+			sizep = of_get_property(np, "d-cache-size", NULL);
 			if (sizep != NULL)
 				size = *sizep;
-			lsizep = get_property(np, dc, NULL);
+			lsizep = of_get_property(np, dc, NULL);
 			if (lsizep != NULL)
 				lsize = *lsizep;
 			if (sizep == 0 || lsizep == 0)
@@ -322,10 +321,10 @@ static void __init initialize_cache_info
 
 			size = 0;
 			lsize = cur_cpu_spec->icache_bsize;
-			sizep = get_property(np, "i-cache-size", NULL);
+			sizep = of_get_property(np, "i-cache-size", NULL);
 			if (sizep != NULL)
 				size = *sizep;
-			lsizep = get_property(np, ic, NULL);
+			lsizep = of_get_property(np, ic, NULL);
 			if (lsizep != NULL)
 				lsize = *lsizep;
 			if (sizep == 0 || lsizep == 0)
@@ -583,14 +582,14 @@ void __init setup_per_cpu_areas(void)
 	char *ptr;
 
 	/* Copy section for each CPU (we discard the original) */
-	size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
+	size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
 #ifdef CONFIG_MODULES
 	if (size < PERCPU_ENOUGH_ROOM)
 		size = PERCPU_ENOUGH_ROOM;
 #endif
 
 	for_each_possible_cpu(i) {
-		ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
+		ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
 		if (!ptr)
 			panic("Cannot allocate cpu data for CPU %d\n", i);
 
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 6b405a3..dd1dca5 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -20,7 +20,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index f72e8e8..1ce0ae3 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -15,7 +15,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 924d692..22f1ef1 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -176,10 +176,10 @@ static struct call_data_struct {
 #define SMP_CALL_TIMEOUT	8
 
 /*
- * This function sends a 'generic call function' IPI to all other CPUs
- * in the system.
+ * These functions send a 'generic call function' IPI to other online
+ * CPUS in the system.
  *
- * [SUMMARY] Run a function on all other CPUs.
+ * [SUMMARY] Run a function on 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.
@@ -190,18 +190,26 @@ #define SMP_CALL_TIMEOUT	8
  * 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)
-{ 
+int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
+			int wait, cpumask_t map)
+{
 	struct call_data_struct data;
-	int ret = -1, cpus;
+	int ret = -1, num_cpus;
+	int cpu;
 	u64 timeout;
 
 	/* Can deadlock when called with interrupts disabled */
 	WARN_ON(irqs_disabled());
 
+	/* remove 'self' from the map */
+	if (cpu_isset(smp_processor_id(), map))
+		cpu_clear(smp_processor_id(), map);
+
+	/* sanity check the map, remove any non-online processors. */
+	cpus_and(map, map, cpu_online_map);
+
 	if (unlikely(smp_ops == NULL))
-		return -1;
+		return ret;
 
 	data.func = func;
 	data.info = info;
@@ -213,40 +221,42 @@ int smp_call_function (void (*func) (voi
 	spin_lock(&call_lock);
 	/* Must grab online cpu count with preempt disabled, otherwise
 	 * it can change. */
-	cpus = num_online_cpus() - 1;
-	if (!cpus) {
+	num_cpus = num_online_cpus() - 1;
+	if (!num_cpus || cpus_empty(map)) {
 		ret = 0;
 		goto out;
 	}
 
 	call_data = &data;
 	smp_wmb();
-	/* Send a message to all other CPUs and wait for them to respond */
-	smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION);
+	/* Send a message to all CPUs in the map */
+	for_each_cpu_mask(cpu, map)
+		smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
 
 	timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec;
 
-	/* Wait for response */
-	while (atomic_read(&data.started) != cpus) {
+	/* Wait for indication that they have received the message */
+	while (atomic_read(&data.started) != num_cpus) {
 		HMT_low();
 		if (get_tb() >= timeout) {
 			printk("smp_call_function on cpu %d: other cpus not "
-			       "responding (%d)\n", smp_processor_id(),
-			       atomic_read(&data.started));
+				"responding (%d)\n", smp_processor_id(),
+				atomic_read(&data.started));
 			debugger(NULL);
 			goto out;
 		}
 	}
 
+	/* optionally wait for the CPUs to complete */
 	if (wait) {
-		while (atomic_read(&data.finished) != cpus) {
+		while (atomic_read(&data.finished) != num_cpus) {
 			HMT_low();
 			if (get_tb() >= timeout) {
 				printk("smp_call_function on cpu %d: other "
-				       "cpus not finishing (%d/%d)\n",
-				       smp_processor_id(),
-				       atomic_read(&data.finished),
-				       atomic_read(&data.started));
+					"cpus not finishing (%d/%d)\n",
+					smp_processor_id(),
+					atomic_read(&data.finished),
+					atomic_read(&data.started));
 				debugger(NULL);
 				goto out;
 			}
@@ -262,8 +272,29 @@ int smp_call_function (void (*func) (voi
 	return ret;
 }
 
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+{
+	return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map);
+}
 EXPORT_SYMBOL(smp_call_function);
 
+int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic,
+			int wait)
+{
+	cpumask_t map=CPU_MASK_NONE;
+
+	if (!cpu_online(cpu))
+		return -EINVAL;
+
+	if (cpu == smp_processor_id())
+		return -EBUSY;
+
+	cpu_set(cpu, map);
+	return smp_call_function_map(func,info,nonatomic,wait,map);
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
 void smp_call_function_interrupt(void)
 {
 	void (*func) (void *info);
@@ -428,10 +459,6 @@ void generic_mach_cpu_die(void)
 	smp_wmb();
 	while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
 		cpu_relax();
-
-#ifdef CONFIG_PPC64
-	flush_tlb_pending();
-#endif
 	cpu_set(cpu, cpu_online_map);
 	local_irq_enable();
 }
diff --git a/arch/powerpc/kernel/suspend.c b/arch/powerpc/kernel/suspend.c
new file mode 100644
index 0000000..8cee571
--- /dev/null
+++ b/arch/powerpc/kernel/suspend.c
@@ -0,0 +1,24 @@
+/*
+ * Suspend support specific for power.
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
+ */
+
+#include <asm/page.h>
+
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
+
+/*
+ *	pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+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);
+}
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
new file mode 100644
index 0000000..064a7ba
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp.c
@@ -0,0 +1,43 @@
+/*
+ * Common powerpc suspend code for 32 and 64 bits
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <asm/suspend.h>
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/mmu_context.h>
+
+void save_processor_state(void)
+{
+	/*
+	 * flush out all the special registers so we don't need
+	 * to save them in the snapshot
+	 */
+	flush_fp_to_thread(current);
+	flush_altivec_to_thread(current);
+	flush_spe_to_thread(current);
+
+#ifdef CONFIG_PPC64
+	hard_irq_disable();
+#endif
+
+}
+
+void restore_processor_state(void)
+{
+#ifdef CONFIG_PPC32
+	set_context(current->active_mm->context.id, current->active_mm->pgd);
+#endif
+
+#ifdef CONFIG_PPC64
+	hard_irq_enable();
+#endif
+}
diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c
new file mode 100644
index 0000000..6f3f069
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_64.c
@@ -0,0 +1,24 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <asm/system.h>
+#include <asm/iommu.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+void do_after_copyback(void)
+{
+	iommu_restore();
+	touch_softlockup_watchdog();
+	mb();
+}
+
+void _iommu_save(void)
+{
+	iommu_save();
+}
diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S
new file mode 100644
index 0000000..e092c3c
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_asm64.S
@@ -0,0 +1,228 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_r1		0x00	/* stack pointer */
+#define SL_PC		0x08
+#define SL_MSR		0x10
+#define SL_SDR1		0x18
+#define SL_XER		0x20
+#define SL_TB		0x40
+#define SL_r2		0x48
+#define SL_CR		0x50
+#define SL_LR		0x58
+#define SL_r12		0x60
+#define SL_r13		0x68
+#define SL_r14		0x70
+#define SL_r15		0x78
+#define SL_r16		0x80
+#define SL_r17		0x88
+#define SL_r18		0x90
+#define SL_r19		0x98
+#define SL_r20		0xa0
+#define SL_r21		0xa8
+#define SL_r22		0xb0
+#define SL_r23		0xb8
+#define SL_r24		0xc0
+#define SL_r25		0xc8
+#define SL_r26		0xd0
+#define SL_r27		0xd8
+#define SL_r28		0xe0
+#define SL_r29		0xe8
+#define SL_r30		0xf0
+#define SL_r31		0xf8
+#define SL_SIZE		SL_r31+8
+
+/* these macros rely on the save area being
+ * pointed to by r11 */
+#define SAVE_SPECIAL(special)		\
+	mf##special	r0		;\
+	std	r0, SL_##special(r11)
+#define RESTORE_SPECIAL(special)	\
+	ld	r0, SL_##special(r11)	;\
+	mt##special	r0
+#define SAVE_REGISTER(reg)		\
+	std	reg, SL_##reg(r11)
+#define RESTORE_REGISTER(reg)		\
+	ld	reg, SL_##reg(r11)
+
+/* space for storing cpu state */
+	.section .data
+	.align  5
+swsusp_save_area:
+	.space SL_SIZE
+
+	.section ".toc","aw"
+swsusp_save_area_ptr:
+	.tc	swsusp_save_area[TC],swsusp_save_area
+restore_pblist_ptr:
+	.tc	restore_pblist[TC],restore_pblist
+
+	.section .text
+	.align  5
+_GLOBAL(swsusp_arch_suspend)
+	ld	r11,swsusp_save_area_ptr@toc(r2)
+	SAVE_SPECIAL(LR)
+	SAVE_REGISTER(r1)
+	SAVE_SPECIAL(CR)
+	SAVE_SPECIAL(TB)
+	SAVE_REGISTER(r2)
+	SAVE_REGISTER(r12)
+	SAVE_REGISTER(r13)
+	SAVE_REGISTER(r14)
+	SAVE_REGISTER(r15)
+	SAVE_REGISTER(r16)
+	SAVE_REGISTER(r17)
+	SAVE_REGISTER(r18)
+	SAVE_REGISTER(r19)
+	SAVE_REGISTER(r20)
+	SAVE_REGISTER(r21)
+	SAVE_REGISTER(r22)
+	SAVE_REGISTER(r23)
+	SAVE_REGISTER(r24)
+	SAVE_REGISTER(r25)
+	SAVE_REGISTER(r26)
+	SAVE_REGISTER(r27)
+	SAVE_REGISTER(r28)
+	SAVE_REGISTER(r29)
+	SAVE_REGISTER(r30)
+	SAVE_REGISTER(r31)
+	SAVE_SPECIAL(MSR)
+	SAVE_SPECIAL(SDR1)
+	SAVE_SPECIAL(XER)
+
+	/* we push the stack up 128 bytes but don't store the
+	 * stack pointer on the stack like a real stackframe */
+	addi	r1,r1,-128
+
+	bl _iommu_save
+	bl swsusp_save
+
+	/* restore LR */
+	ld	r11,swsusp_save_area_ptr@toc(r2)
+	RESTORE_SPECIAL(LR)
+	addi	r1,r1,128
+
+	blr
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	sync
+
+	ld	r12,restore_pblist_ptr@toc(r2)
+	ld	r12,0(r12)
+
+	cmpdi	r12,0
+	beq-	nothing_to_copy
+	li	r15,512
+copyloop:
+	ld	r13,pbe_address(r12)
+	ld	r14,pbe_orig_address(r12)
+
+	mtctr	r15
+	li	r10,0
+copy_page_loop:
+	ldx	r0,r10,r13
+	stdx	r0,r10,r14
+	addi	r10,r10,8
+	bdnz copy_page_loop
+
+	ld	r12,pbe_next(r12)
+	cmpdi	r12,0
+	bne+	copyloop
+nothing_to_copy:
+
+	/* flush caches */
+	lis	r3, 0x10
+	mtctr	r3
+	li	r3, 0
+	ori	r3, r3, CONFIG_KERNEL_START>>48
+	li	r0, 48
+	sld	r3, r3, r0
+	li	r0, 0
+1:
+	dcbf	r0,r3
+	addi	r3,r3,0x20
+	bdnz	1b
+
+	sync
+
+	tlbia
+
+	ld	r11,swsusp_save_area_ptr@toc(r2)
+
+	RESTORE_SPECIAL(CR)
+
+	/* restore timebase */
+	/* load saved tb */
+	ld	r1, SL_TB(r11)
+	/* get upper 32 bits of it */
+	srdi	r2, r1, 32
+	/* clear tb lower to avoid wrap */
+	li	r0, 0
+	mttbl	r0
+	/* set tb upper */
+	mttbu	r2
+	/* set tb lower */
+	mttbl	r1
+
+	/* restore registers */
+	RESTORE_REGISTER(r1)
+	RESTORE_REGISTER(r2)
+	RESTORE_REGISTER(r12)
+	RESTORE_REGISTER(r13)
+	RESTORE_REGISTER(r14)
+	RESTORE_REGISTER(r15)
+	RESTORE_REGISTER(r16)
+	RESTORE_REGISTER(r17)
+	RESTORE_REGISTER(r18)
+	RESTORE_REGISTER(r19)
+	RESTORE_REGISTER(r20)
+	RESTORE_REGISTER(r21)
+	RESTORE_REGISTER(r22)
+	RESTORE_REGISTER(r23)
+	RESTORE_REGISTER(r24)
+	RESTORE_REGISTER(r25)
+	RESTORE_REGISTER(r26)
+	RESTORE_REGISTER(r27)
+	RESTORE_REGISTER(r28)
+	RESTORE_REGISTER(r29)
+	RESTORE_REGISTER(r30)
+	RESTORE_REGISTER(r31)
+	/* can't use RESTORE_SPECIAL(MSR) */
+	ld	r0, SL_MSR(r11)
+	mtmsrd	r0, 0
+	RESTORE_SPECIAL(SDR1)
+	RESTORE_SPECIAL(XER)
+
+	sync
+
+	addi	r1,r1,-128
+	bl	slb_flush_and_rebolt
+	bl	do_after_copyback
+	addi	r1,r1,128
+
+	ld	r11,swsusp_save_area_ptr@toc(r2)
+	RESTORE_SPECIAL(LR)
+
+	li	r3, 0
+	blr
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 673e8d9..047246a 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -53,10 +53,6 @@ #include <asm/mmu_context.h>
 #include <asm/ppc-pci.h>
 #include <asm/syscalls.h>
 
-/* readdir & getdents */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
-
 struct old_linux_dirent32 {
 	u32		d_ino;
 	u32		d_offset;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index d358866..fc6647d 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -24,7 +24,6 @@ #include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index d57818a..cae39d9 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -66,16 +66,17 @@ static int __init smt_setup(void)
 	if (!cpu_has_feature(CPU_FTR_SMT))
 		return -ENODEV;
 
-	options = find_path_device("/options");
+	options = of_find_node_by_path("/options");
 	if (!options)
 		return -ENODEV;
 
-	val = get_property(options, "ibm,smt-snooze-delay", NULL);
+	val = of_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;
 	}
 
+	of_node_put(options);
 	return 0;
 }
 __initcall(smt_setup);
@@ -189,12 +190,12 @@ SYSFS_PMCSETUP(purr, SPRN_PURR);
 SYSFS_PMCSETUP(spurr, SPRN_SPURR);
 SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 
-SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
-SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
-SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
-SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
-SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
-SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
 
 
 static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
@@ -498,4 +499,4 @@ static int __init topology_init(void)
 
 	return 0;
 }
-__initcall(topology_init);
+subsys_initcall(topology_init);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f6f0c6b..7cedef8 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -834,7 +834,7 @@ static int __init get_freq(char *name, i
 	cpu = of_find_node_by_type(NULL, "cpu");
 
 	if (cpu) {
-		fp = get_property(cpu, name, NULL);
+		fp = of_get_property(cpu, name, NULL);
 		if (fp) {
 			found = 1;
 			*val = of_read_ulong(fp, cells);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 17724fb..bf6445a 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -33,8 +33,8 @@ #include <linux/kprobes.h>
 #include <linux/kexec.h>
 #include <linux/backlight.h>
 #include <linux/bug.h>
+#include <linux/kdebug.h>
 
-#include <asm/kdebug.h>
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -72,39 +72,15 @@ EXPORT_SYMBOL(__debugger_dabr_match);
 EXPORT_SYMBOL(__debugger_fault_handler);
 #endif
 
-ATOMIC_NOTIFIER_HEAD(powerpc_die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&powerpc_die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&powerpc_die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
 /*
  * Trap & Exception support
  */
 
-static DEFINE_SPINLOCK(die_lock);
-
-int die(const char *str, struct pt_regs *regs, long err)
-{
-	static int die_counter;
-
-	if (debugger(regs))
-		return 1;
-
-	console_verbose();
-	spin_lock_irq(&die_lock);
-	bust_spinlocks(1);
 #ifdef CONFIG_PMAC_BACKLIGHT
+static void pmac_backlight_unblank(void)
+{
 	mutex_lock(&pmac_backlight_mutex);
-	if (machine_is(powermac) && pmac_backlight) {
+	if (pmac_backlight) {
 		struct backlight_properties *props;
 
 		props = &pmac_backlight->props;
@@ -113,26 +89,67 @@ #ifdef CONFIG_PMAC_BACKLIGHT
 		backlight_update_status(pmac_backlight);
 	}
 	mutex_unlock(&pmac_backlight_mutex);
+}
+#else
+static inline void pmac_backlight_unblank(void) { }
 #endif
-	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
+
+int 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(die.lock),
+		.lock_owner =		-1,
+		.lock_owner_depth =	0
+	};
+	static int die_counter;
+	unsigned long flags;
+
+	if (debugger(regs))
+		return 1;
+
+	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);
+		if (machine_is(powermac))
+			pmac_backlight_unblank();
+	} else {
+		local_save_flags(flags);
+	}
+
+	if (++die.lock_owner_depth < 3) {
+		printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
-	printk("PREEMPT ");
+		printk("PREEMPT ");
 #endif
 #ifdef CONFIG_SMP
-	printk("SMP NR_CPUS=%d ", NR_CPUS);
+		printk("SMP NR_CPUS=%d ", NR_CPUS);
 #endif
 #ifdef CONFIG_DEBUG_PAGEALLOC
-	printk("DEBUG_PAGEALLOC ");
+		printk("DEBUG_PAGEALLOC ");
 #endif
 #ifdef CONFIG_NUMA
-	printk("NUMA ");
+		printk("NUMA ");
 #endif
-	printk("%s\n", ppc_md.name ? "" : ppc_md.name);
+		printk("%s\n", ppc_md.name ? ppc_md.name : "");
+
+		print_modules();
+		show_regs(regs);
+	} else {
+		printk("Recursive die() failure, output suppressed\n");
+	}
 
-	print_modules();
-	show_regs(regs);
 	bust_spinlocks(0);
-	spin_unlock_irq(&die_lock);
+	die.lock_owner = -1;
+	spin_unlock_irqrestore(&die.lock, flags);
 
 	if (kexec_should_crash(current) ||
 		kexec_sr_activated(smp_processor_id()))
@@ -145,6 +162,7 @@ #endif
 	if (panic_on_oops)
 		panic("Fatal exception");
 
+	oops_exit();
 	do_exit(err);
 
 	return 0;
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 7e09718..87703df 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -51,6 +51,9 @@ #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS
 	udbg_init_pas_realmode();
 #elif defined(CONFIG_BOOTX_TEXT)
 	udbg_init_btext();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_44x)
+	/* PPC44x debug */
+	udbg_init_44x_as1();
 #endif
 }
 
@@ -142,29 +145,22 @@ static void udbg_console_write(struct co
 static struct console udbg_console = {
 	.name	= "udbg",
 	.write	= udbg_console_write,
-	.flags	= CON_PRINTBUFFER | CON_ENABLED,
+	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_BOOT,
 	.index	= -1,
 };
 
 static int early_console_initialized;
 
-void __init disable_early_printk(void)
-{
-	if (!early_console_initialized)
-		return;
-	if (strstr(boot_command_line, "udbg-immortal")) {
-		printk(KERN_INFO "early console immortal !\n");
-		return;
-	}
-	unregister_console(&udbg_console);
-	early_console_initialized = 0;
-}
-
 /* called by setup_system */
 void register_early_udbg_console(void)
 {
 	if (early_console_initialized)
 		return;
+
+	if (strstr(boot_command_line, "udbg-immortal")) {
+		printk(KERN_INFO "early console immortal !\n");
+		udbg_console.flags &= ~CON_BOOT;
+	}
 	early_console_initialized = 1;
 	register_console(&udbg_console);
 }
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index a963f65..7afab5b 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -191,3 +191,26 @@ void udbg_init_pas_realmode(void)
 	udbg_getc_poll = NULL;
 }
 #endif /* CONFIG_PPC_MAPLE */
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_44x
+#include <platforms/44x/44x.h>
+
+static void udbg_44x_as1_putc(char c)
+{
+	if (udbg_comport) {
+		while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+			/* wait for idle */;
+		as1_writeb(c, &udbg_comport->thr); eieio();
+		if (c == '\n')
+			udbg_44x_as1_putc('\r');
+	}
+}
+
+void __init udbg_init_44x_as1(void)
+{
+	udbg_comport =
+		(volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
+
+	udbg_putc = udbg_44x_as1_putc;
+}
+#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index e46c31b..4245579 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -14,7 +14,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/slab.h>
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 2968ffe..62c1bc1 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -37,7 +37,7 @@ #include <asm/iseries/hv_lp_config.h>
 #include <asm/iseries/hv_call_xm.h>
 #include <asm/iseries/iommu.h>
 
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+extern struct kset devices_subsys; /* needed for vio_find_name() */
 
 static struct vio_dev vio_bus_device  = { /* fake "parent" device */
 	.name = vio_bus_device.dev.bus_id,
@@ -81,7 +81,7 @@ #endif
 		struct iommu_table *tbl;
 		unsigned long offset, size;
 
-		dma_window = get_property(dev->dev.archdata.of_node,
+		dma_window = of_get_property(dev->dev.archdata.of_node,
 					  "ibm,my-dma-window", NULL);
 		if (!dma_window)
 			return NULL;
@@ -117,7 +117,7 @@ static const struct vio_device_id *vio_m
 {
 	while (ids->type[0] != '\0') {
 		if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
-		    device_is_compatible(dev->dev.archdata.of_node,
+		    of_device_is_compatible(dev->dev.archdata.of_node,
 					 ids->compat))
 			return ids;
 		ids++;
@@ -226,7 +226,7 @@ struct vio_dev * __devinit vio_register_
 		return NULL;
 	}
 
-	unit_address = get_property(of_node, "reg", NULL);
+	unit_address = of_get_property(of_node, "reg", NULL);
 	if (unit_address == NULL) {
 		printk(KERN_WARNING "%s: node %s missing 'reg'\n",
 				__FUNCTION__,
@@ -246,7 +246,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 = get_property(of_node,
+		unit_address = of_get_property(of_node,
 				"linux,unit_address", NULL);
 		if (unit_address != NULL)
 			viodev->unit_address = *unit_address;
@@ -308,7 +308,7 @@ #endif /* CONFIG_PPC_ISERIES */
 		return err;
 	}
 
-	node_vroot = find_devices("vdevice");
+	node_vroot = of_find_node_by_name(NULL, "vdevice");
 	if (node_vroot) {
 		struct device_node *of_node;
 
@@ -322,6 +322,7 @@ #endif /* CONFIG_PPC_ISERIES */
 					__FUNCTION__, of_node);
 			vio_register_device_node(of_node);
 		}
+		of_node_put(node_vroot);
 	}
 
 	return 0;
@@ -377,7 +378,7 @@ static int vio_hotplug(struct device *de
 	dn = dev->archdata.of_node;
 	if (!dn)
 		return -ENODEV;
-	cp = get_property(dn, "compatible", &length);
+	cp = of_get_property(dn, "compatible", &length);
 	if (!cp)
 		return -ENODEV;
 
@@ -406,12 +407,12 @@ struct bus_type vio_bus_type = {
  * @which:	The property/attribute to be extracted.
  * @length:	Pointer to length of returned data size (unused if NULL).
  *
- * Calls prom.c's get_property() to return the value of the
+ * Calls prom.c's of_get_property() to return the value of the
  * attribute specified by @which
 */
 const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
 {
-	return get_property(vdev->dev.archdata.of_node, which, length);
+	return of_get_property(vdev->dev.archdata.of_node, which, length);
 }
 EXPORT_SYMBOL(vio_get_attribute);
 
@@ -426,7 +427,7 @@ static struct vio_dev *vio_find_name(con
 {
 	struct kobject *found;
 
-	found = kset_find_obj(&devices_subsys.kset, kobj_name);
+	found = kset_find_obj(&devices_subsys, kobj_name);
 	if (!found)
 		return NULL;
 
@@ -443,7 +444,7 @@ struct vio_dev *vio_find_node(struct dev
 	char kobj_name[BUS_ID_SIZE];
 
 	/* construct the kobject name from the device node */
-	unit_address = get_property(vnode, "reg", NULL);
+	unit_address = of_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 7eefeb4..1320673 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -139,11 +139,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
 		__initramfs_end = .;
 	}
 #endif
-#ifdef CONFIG_PPC32
-	. = ALIGN(32);
-#else
-	. = ALIGN(128);
-#endif
+	. = ALIGN(PAGE_SIZE);
 	.data.percpu : {
 		__per_cpu_start = .;
 		*(.data.percpu)
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 4b1ba49..450258d 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -7,13 +7,12 @@ EXTRA_CFLAGS		+= -mno-minimal-toc
 endif
 
 ifeq ($(CONFIG_PPC_MERGE),y)
-obj-y			:= string.o strcase.o
+obj-y			:= string.o
 obj-$(CONFIG_PPC32)	+= div64.o copy_32.o checksum_32.o
 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
+			   memcpy_64.o usercopy_64.o mem_64.o string.o
 obj-$(CONFIG_QUICC_ENGINE) += rheap.o
 obj-$(CONFIG_XMON)	+= sstep.o
 obj-$(CONFIG_KPROBES)	+= sstep.o
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index a6b54cb..25ec537 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -24,7 +24,7 @@ _GLOBAL(__copy_tofrom_user)
 	dcbt	0,r4
 	beq	.Lcopy_page_4K
 	andi.	r6,r6,7
-	mtcrf	0x01,r5
+	PPC_MTOCRF	0x01,r5
 	blt	cr1,.Lshort_copy
 	bne	.Ldst_unaligned
 .Ldst_aligned:
@@ -135,7 +135,7 @@ _GLOBAL(__copy_tofrom_user)
 	b	.Ldo_tail
 
 .Ldst_unaligned:
-	mtcrf	0x01,r6		/* put #bytes to 8B bdry into cr7 */
+	PPC_MTOCRF	0x01,r6		/* put #bytes to 8B bdry into cr7 */
 	subf	r5,r6,r5
 	li	r7,0
 	cmpldi	r1,r5,16
@@ -150,7 +150,7 @@ _GLOBAL(__copy_tofrom_user)
 2:	bf	cr7*4+1,3f
 37:	lwzx	r0,r7,r4
 83:	stwx	r0,r7,r3
-3:	mtcrf	0x01,r5
+3:	PPC_MTOCRF	0x01,r5
 	add	r4,r6,r4
 	add	r3,r6,r3
 	b	.Ldst_aligned
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 48f3d13..6656d47 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -306,13 +306,15 @@ EXPORT_SYMBOL(__dma_free_coherent);
 static int __init dma_alloc_init(void)
 {
 	pgd_t *pgd;
+	pud_t *pud;
 	pmd_t *pmd;
 	pte_t *pte;
 	int ret = 0;
 
 	do {
 		pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
-		pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
+		pud = pud_alloc(&init_mm, pgd, CONSISTENT_BASE);
+		pmd = pmd_alloc(&init_mm, pud, CONSISTENT_BASE);
 		if (!pmd) {
 			printk(KERN_ERR "%s: no pmd tables\n", __func__);
 			ret = -ENOMEM;
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index 80b482c..79d0fa3 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -43,9 +43,11 @@ void __spin_yield(raw_spinlock_t *lock)
 	if (firmware_has_feature(FW_FEATURE_ISERIES))
 		HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
 			((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
 	else
 		plpar_hcall_norets(H_CONFER,
 			get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
 }
 
 /*
@@ -72,9 +74,11 @@ void __rw_yield(raw_rwlock_t *rw)
 	if (firmware_has_feature(FW_FEATURE_ISERIES))
 		HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
 			((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
 	else
 		plpar_hcall_norets(H_CONFER,
 			get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
 }
 #endif
 
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 68df202..11ce045 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -19,7 +19,7 @@ _GLOBAL(memset)
 	rlwimi	r4,r4,16,0,15
 	cmplw	cr1,r5,r0		/* do we get that far? */
 	rldimi	r4,r4,32,0
-	mtcrf	1,r0
+	PPC_MTOCRF	1,r0
 	mr	r6,r3
 	blt	cr1,8f
 	beq+	3f			/* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
 	bdnz	4b
 5:	srwi.	r0,r5,3
 	clrlwi	r5,r5,29
-	mtcrf	1,r0
+	PPC_MTOCRF	1,r0
 	beq	8f
 	bf	29,6f
 	std	r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
 	std	r4,0(r6)
 	addi	r6,r6,8
 8:	cmpwi	r5,0
-	mtcrf	1,r5
+	PPC_MTOCRF	1,r5
 	beqlr+
 	bf	29,9f
 	stw	r4,0(r6)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index 7173ba9..3f13112 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -12,7 +12,7 @@ #include <asm/ppc_asm.h>
 	.align	7
 _GLOBAL(memcpy)
 	std	r3,48(r1)	/* save destination pointer for return value */
-	mtcrf	0x01,r5
+	PPC_MTOCRF	0x01,r5
 	cmpldi	cr1,r5,16
 	neg	r6,r3		# LS 3 bits = # bytes to 8-byte dest bdry
 	andi.	r6,r6,7
@@ -128,7 +128,7 @@ _GLOBAL(memcpy)
 	b	.Ldo_tail
 
 .Ldst_unaligned:
-	mtcrf	0x01,r6		# put #bytes to 8B bdry into cr7
+	PPC_MTOCRF	0x01,r6		# put #bytes to 8B bdry into cr7
 	subf	r5,r6,r5
 	li	r7,0
 	cmpldi	r1,r5,16
@@ -143,7 +143,7 @@ _GLOBAL(memcpy)
 2:	bf	cr7*4+1,3f
 	lwzx	r0,r7,r4
 	stwx	r0,r7,r3
-3:	mtcrf	0x01,r5
+3:	PPC_MTOCRF	0x01,r5
 	add	r4,r6,r4
 	add	r3,r6,r3
 	b	.Ldst_aligned
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7e8ded0..4aae0c3 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -54,7 +54,7 @@ static int __kprobes branch_taken(unsign
  */
 int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
 {
-	unsigned int opcode, rd;
+	unsigned int opcode, rs, rb, rd, spr;
 	unsigned long int imm;
 
 	opcode = instr >> 26;
@@ -152,6 +152,49 @@ #ifdef CONFIG_PPC64
 				regs->nip &= 0xffffffffUL;
 			return 1;
 #endif
+		case 0x26:	/* mfcr */
+			regs->gpr[rd] = regs->ccr;
+			regs->gpr[rd] &= 0xffffffffUL;
+			goto mtspr_out;
+		case 0x2a6:	/* mfspr */
+			spr = (instr >> 11) & 0x3ff;
+			switch (spr) {
+			case 0x20:	/* mfxer */
+				regs->gpr[rd] = regs->xer;
+				regs->gpr[rd] &= 0xffffffffUL;
+				goto mtspr_out;
+			case 0x100:	/* mflr */
+				regs->gpr[rd] = regs->link;
+				goto mtspr_out;
+			case 0x120:	/* mfctr */
+				regs->gpr[rd] = regs->ctr;
+				goto mtspr_out;
+			}
+			break;
+		case 0x378:	/* orx */
+			rs = (instr >> 21) & 0x1f;
+			rb = (instr >> 11) & 0x1f;
+			if (rs == rb) {		/* mr */
+				rd = (instr >> 16) & 0x1f;
+				regs->gpr[rd] = regs->gpr[rs];
+				goto mtspr_out;
+			}
+			break;
+		case 0x3a6:	/* mtspr */
+			spr = (instr >> 11) & 0x3ff;
+			switch (spr) {
+			case 0x20:	/* mtxer */
+				regs->xer = (regs->gpr[rd] & 0xffffffffUL);
+				goto mtspr_out;
+			case 0x100:	/* mtlr */
+				regs->link = regs->gpr[rd];
+				goto mtspr_out;
+			case 0x120:	/* mtctr */
+				regs->ctr = regs->gpr[rd];
+mtspr_out:
+				regs->nip += 4;
+				return 1;
+			}
 		}
 	}
 	return 0;
diff --git a/arch/powerpc/lib/strcase.c b/arch/powerpc/lib/strcase.c
deleted file mode 100644
index f8ec1eb..0000000
--- a/arch/powerpc/lib/strcase.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
-	int c1, c2;
-
-	do {
-		c1 = tolower(*s1++);
-		c2 = tolower(*s2++);
-	} while (c1 == c2 && c1 != 0);
-	return c1 - c2;
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	int c1, c2;
-
-	do {
-		c1 = tolower(*s1++);
-		c2 = tolower(*s2++);
-	} while ((--n > 0) && c1 == c2 && c1 != 0);
-	return c1 - c2;
-}
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index 0a0a048..ca4dcb0 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -24,73 +24,38 @@
  *
  */
 
-#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/stddef.h>
-#include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/highmem.h>
-
-#include <asm/pgalloc.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
 #include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/page.h>
 
 #include "mmu_decl.h"
 
-extern char etext[], _stext[];
-
 /* Used by the 44x TLB replacement exception handler.
  * Just needed it declared someplace.
  */
-unsigned int tlb_44x_index = 0;
-unsigned int tlb_44x_hwater = 62;
+unsigned int tlb_44x_index; /* = 0 */
+unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS;
 
 /*
  * "Pins" a 256MB TLB entry in AS0 for kernel lowmem
  */
-static void __init
-ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys)
+static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
 {
-	unsigned long attrib = 0;
-
-	__asm__ __volatile__("\
-	clrrwi	%2,%2,10\n\
-	ori	%2,%2,%4\n\
-	clrrwi	%1,%1,10\n\
-	li	%0,0\n\
-	ori	%0,%0,%5\n\
-	tlbwe	%2,%3,%6\n\
-	tlbwe	%1,%3,%7\n\
-	tlbwe	%0,%3,%8"
+	__asm__ __volatile__(
+		"tlbwe	%2,%3,%4\n"
+		"tlbwe	%1,%3,%5\n"
+		"tlbwe	%0,%3,%6\n"
 	:
-	: "r" (attrib), "r" (phys), "r" (virt), "r" (slot),
-	  "i" (PPC44x_TLB_VALID | PPC44x_TLB_256M),
-	  "i" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
+	: "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
+	  "r" (phys),
+	  "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M),
+	  "r" (tlb_44x_hwater--), /* slot for this TLB entry */
 	  "i" (PPC44x_TLB_PAGEID),
 	  "i" (PPC44x_TLB_XLAT),
 	  "i" (PPC44x_TLB_ATTRIB));
 }
 
-/*
- * MMU_init_hw does the chip-specific initialization of the MMU hardware.
- */
 void __init MMU_init_hw(void)
 {
 	flush_instruction_cache();
@@ -98,22 +63,13 @@ void __init MMU_init_hw(void)
 
 unsigned long __init mmu_mapin_ram(void)
 {
-	unsigned int pinned_tlbs = 1;
-	int i;
-
-	/* Determine number of entries necessary to cover lowmem */
-	pinned_tlbs = (unsigned int)
-		(_ALIGN(total_lowmem, PPC_PIN_SIZE) >> PPC44x_PIN_SHIFT);
-
-	/* Write upper watermark to save location */
-	tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs;
+	unsigned long addr;
 
-	/* If necessary, set additional pinned TLBs */
-	if (pinned_tlbs > 1)
-		for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) {
-			unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC_PIN_SIZE;
-			ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr);
-		}
+	/* Pin in enough TLBs to cover any lowmem not covered by the
+	 * initial 256M mapping established in head_44x.S */
+	for (addr = PPC_PIN_SIZE; addr < total_lowmem;
+	     addr += PPC_PIN_SIZE)
+		ppc44x_pin_tlb(addr + PAGE_OFFSET, addr);
 
 	return total_lowmem;
 }
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 03aeb3a..bfe9013 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -28,6 +28,7 @@ #include <linux/interrupt.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
+#include <linux/kdebug.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -36,40 +37,28 @@ #include <asm/mmu_context.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
-#include <asm/kdebug.h>
 #include <asm/siginfo.h>
 
-#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(&notify_page_fault_chain, nb);
-}
-
-int unregister_page_fault_notifier(struct notifier_block *nb)
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
+	int ret = 0;
+
+	/* kprobe_running() needs smp_processor_id() */
+	if (!user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, 11))
+			ret = 1;
+		preempt_enable();
+	}
 
-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(&notify_page_fault_chain, val, &args);
+	return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, const char *str,
-			struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-	return NOTIFY_DONE;
+	return 0;
 }
 #endif
 
@@ -175,8 +164,7 @@ #else
 	is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
-	if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, error_code,
-				11, SIGSEGV) == NOTIFY_STOP)
+	if (notify_page_fault(regs))
 		return 0;
 
 	if (trap == 0x300) {
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index bd68df5..ddceefc 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -283,6 +283,7 @@ #define PTE_SIZE	8
 #define PTEG_SIZE	64
 #define LG_PTEG_SIZE	6
 #define LDPTEu		lwzu
+#define LDPTE		lwz
 #define STPTE		stw
 #define CMPPTE		cmpw
 #define PTE_H		0x40
@@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C)
 	 * and we know there is a definite (although small) speed
 	 * advantage to putting the PTE in the primary PTEG, we always
 	 * put the PTE in the primary PTEG.
+	 *
+	 * In addition, we skip any slot that is mapping kernel text in
+	 * order to avoid a deadlock when not using BAT mappings if
+	 * trying to hash in the kernel hash code itself after it has
+	 * already taken the hash table lock. This works in conjunction
+	 * with pre-faulting of the kernel text.
+	 *
+	 * If the hash table bucket is full of kernel text entries, we'll
+	 * lockup here but that shouldn't happen
 	 */
-	addis	r4,r7,next_slot@ha
+
+1:	addis	r4,r7,next_slot@ha		/* get next evict slot */
 	lwz	r6,next_slot@l(r4)
-	addi	r6,r6,PTE_SIZE
+	addi	r6,r6,PTE_SIZE			/* search for candidate */
 	andi.	r6,r6,7*PTE_SIZE
 	stw	r6,next_slot@l(r4)
 	add	r4,r3,r6
+	LDPTE	r0,PTE_SIZE/2(r4)		/* get PTE second word */
+	clrrwi	r0,r0,12
+	lis	r6,etext@h
+	ori	r6,r6,etext@l			/* get etext */
+	tophys(r6,r6)
+	cmpl	cr0,r0,r6			/* compare and try again */
+	blt	1b
 
 #ifndef CONFIG_SMP
 	/* Store PTE in PTEG */
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 9bc0a9c..e64ce3e 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -445,9 +445,12 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FT
 
 htab_insert_pte:
 	/* real page number in r5, PTE RPN value + index */
-	rldicl	r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
+	andis.	r0,r31,_PAGE_4K_PFN@h
+	srdi	r5,r31,PTE_RPN_SHIFT
+	bne-	htab_special_pfn
 	sldi	r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
 	add	r5,r5,r25
+htab_special_pfn:
 	sldi	r5,r5,HW_PAGE_SHIFT
 
 	/* Calculate primary group hash */
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 6f1016a..7b7fe2d 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -26,6 +26,7 @@ #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 #include <asm/cputable.h>
 #include <asm/udbg.h>
+#include <asm/kexec.h>
 
 #ifdef DEBUG_LOW
 #define DBG_LOW(fmt...) udbg_printf(fmt)
@@ -340,31 +341,70 @@ static void native_hpte_invalidate(unsig
 	local_irq_restore(flags);
 }
 
-/*
- * XXX This need fixing based on page size. It's only used by
- * native_hpte_clear() for now which needs fixing too so they
- * make a good pair...
- */
-static unsigned long slot2va(unsigned long hpte_v, unsigned long slot)
-{
-	unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v);
-	unsigned long va;
+#define LP_SHIFT	12
+#define LP_BITS		8
+#define LP_MASK(i)	((0xFF >> (i)) << LP_SHIFT)
 
-	va = avpn << 23;
+static void hpte_decode(hpte_t *hpte, unsigned long slot,
+			int *psize, unsigned long *va)
+{
+	unsigned long hpte_r = hpte->r;
+	unsigned long hpte_v = hpte->v;
+	unsigned long avpn;
+	int i, size, shift, penc, avpnm_bits;
+
+	if (!(hpte_v & HPTE_V_LARGE))
+		size = MMU_PAGE_4K;
+	else {
+		for (i = 0; i < LP_BITS; i++) {
+			if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1))
+				break;
+		}
+		penc = LP_MASK(i+1) >> LP_SHIFT;
+		for (size = 0; size < MMU_PAGE_COUNT; size++) {
 
-	if (! (hpte_v & HPTE_V_LARGE)) {
-		unsigned long vpi, pteg;
+			/* 4K pages are not represented by LP */
+			if (size == MMU_PAGE_4K)
+				continue;
 
-		pteg = slot / HPTES_PER_GROUP;
-		if (hpte_v & HPTE_V_SECONDARY)
-			pteg = ~pteg;
+			/* valid entries have a shift value */
+			if (!mmu_psize_defs[size].shift)
+				continue;
 
-		vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+			if (penc == mmu_psize_defs[size].penc)
+				break;
+		}
+	}
 
-		va |= vpi << PAGE_SHIFT;
+	/*
+	 * FIXME, the code below works for 16M, 64K, and 4K pages as these
+	 * fall under the p<=23 rules for calculating the virtual address.
+	 * In the case of 16M pages, an extra bit is stolen from the AVPN
+	 * field to achieve the requisite 24 bits.
+	 *
+	 * Does not work for 16G pages or 1 TB segments.
+	 */
+	shift = mmu_psize_defs[size].shift;
+	if (mmu_psize_defs[size].avpnm)
+		avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1;
+	else
+		avpnm_bits = 0;
+	if (shift - avpnm_bits <= 23) {
+		avpn = HPTE_V_AVPN_VAL(hpte_v) << 23;
+
+		if (shift < 23) {
+			unsigned long vpi, pteg;
+
+			pteg = slot / HPTES_PER_GROUP;
+			if (hpte_v & HPTE_V_SECONDARY)
+				pteg = ~pteg;
+			vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask;
+			avpn |= (vpi << mmu_psize_defs[size].shift);
+		}
 	}
 
-	return va;
+	*va = avpn;
+	*psize = size;
 }
 
 /*
@@ -374,15 +414,14 @@ static unsigned long slot2va(unsigned lo
  *
  * TODO: add batching support when enabled.  remember, no dynamic memory here,
  * athough there is the control page available...
- *
- * XXX FIXME: 4k only for now !
  */
 static void native_hpte_clear(void)
 {
 	unsigned long slot, slots, flags;
 	hpte_t *hptep = htab_address;
-	unsigned long hpte_v;
+	unsigned long hpte_v, va;
 	unsigned long pteg_count;
+	int psize;
 
 	pteg_count = htab_hash_mask + 1;
 
@@ -408,8 +447,9 @@ static void native_hpte_clear(void)
 		 * already hold the native_tlbie_lock.
 		 */
 		if (hpte_v & HPTE_V_VALID) {
+			hpte_decode(hptep, slot, &psize, &va);
 			hptep->v = 0;
-			__tlbie(slot2va(hpte_v, slot), MMU_PAGE_4K);
+			__tlbie(va, psize);
 		}
 	}
 
@@ -505,7 +545,7 @@ static inline int tlb_batching_enabled(v
 	int enabled = 1;
 
 	if (root) {
-		const char *model = get_property(root, "model", NULL);
+		const char *model = of_get_property(root, "model", NULL);
 		if (model && !strcmp(model, "IBM,9076-N81"))
 			enabled = 0;
 		of_node_put(root);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3c7fe2c..9b226fa 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -100,6 +100,11 @@ #endif
 #ifdef CONFIG_PPC_64K_PAGES
 int mmu_ci_restrictions;
 #endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static u8 *linear_map_hash_slots;
+static unsigned long linear_map_hash_count;
+static DEFINE_SPINLOCK(linear_map_hash_lock);
+#endif /* CONFIG_DEBUG_PAGEALLOC */
 
 /* There are definitions of page sizes arrays to be used when none
  * is provided by the firmware.
@@ -152,11 +157,10 @@ int htab_bolt_mapping(unsigned long vsta
 
 	for (vaddr = vstart, paddr = pstart; vaddr < vend;
 	     vaddr += step, paddr += step) {
-		unsigned long vpn, hash, hpteg;
+		unsigned long hash, hpteg;
 		unsigned long vsid = get_kernel_vsid(vaddr);
 		unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
 
-		vpn = va >> shift;
 		tmp_mode = mode;
 		
 		/* Make non-kernel text non-executable */
@@ -174,6 +178,10 @@ int htab_bolt_mapping(unsigned long vsta
 
 		if (ret < 0)
 			break;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+		if ((paddr >> PAGE_SHIFT) < linear_map_hash_count)
+			linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
 	}
 	return ret < 0 ? ret : 0;
 }
@@ -281,6 +289,7 @@ static void __init htab_init_page_sizes(
 		memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
 		       sizeof(mmu_psize_defaults_gp));
  found:
+#ifndef CONFIG_DEBUG_PAGEALLOC
 	/*
 	 * Pick a size for the linear mapping. Currently, we only support
 	 * 16M, 1M and 4K which is the default
@@ -289,6 +298,7 @@ static void __init htab_init_page_sizes(
 		mmu_linear_psize = MMU_PAGE_16M;
 	else if (mmu_psize_defs[MMU_PAGE_1M].shift)
 		mmu_linear_psize = MMU_PAGE_1M;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
 
 #ifdef CONFIG_PPC_64K_PAGES
 	/*
@@ -303,12 +313,14 @@ #ifdef CONFIG_PPC_64K_PAGES
 	if (mmu_psize_defs[MMU_PAGE_64K].shift) {
 		mmu_virtual_psize = MMU_PAGE_64K;
 		mmu_vmalloc_psize = MMU_PAGE_64K;
+		if (mmu_linear_psize == MMU_PAGE_4K)
+			mmu_linear_psize = MMU_PAGE_64K;
 		if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE))
 			mmu_io_psize = MMU_PAGE_64K;
 		else
 			mmu_ci_restrictions = 1;
 	}
-#endif
+#endif /* CONFIG_PPC_64K_PAGES */
 
 	printk(KERN_DEBUG "Page orders: linear mapping = %d, "
 	       "virtual = %d, io = %d\n",
@@ -476,6 +488,13 @@ void __init htab_initialize(void)
 
 	mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT;
+	linear_map_hash_slots = __va(lmb_alloc_base(linear_map_hash_count,
+						    1, lmb.rmo_size));
+	memset(linear_map_hash_slots, 0, linear_map_hash_count);
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
 	/* On U3 based machines, we need to reserve the DART area and
 	 * _NOT_ map it to avoid cache paradoxes as it's remapped non
 	 * cacheable later on
@@ -573,6 +592,27 @@ unsigned int hash_page_do_lazy_icache(un
 	return pp;
 }
 
+/*
+ * Demote a segment to using 4k pages.
+ * For now this makes the whole process use 4k pages.
+ */
+void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
+#ifdef CONFIG_PPC_64K_PAGES
+	if (mm->context.user_psize == MMU_PAGE_4K)
+		return;
+	mm->context.user_psize = MMU_PAGE_4K;
+	mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
+	get_paca()->context = mm->context;
+	slb_flush_and_rebolt();
+#ifdef CONFIG_SPE_BASE
+	spu_flush_all_slbs(mm);
+#endif
+#endif
+}
+
+EXPORT_SYMBOL_GPL(demote_segment_4k);
+
 /* Result code is:
  *  0 - handled
  *  1 - normal page fault
@@ -665,15 +705,19 @@ #endif
 #ifndef CONFIG_PPC_64K_PAGES
 	rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
 #else
+	/* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
+	if (pte_val(*ptep) & _PAGE_4K_PFN) {
+		demote_segment_4k(mm, ea);
+		psize = MMU_PAGE_4K;
+	}
+
 	if (mmu_ci_restrictions) {
 		/* If this PTE is non-cacheable, switch to 4k */
 		if (psize == MMU_PAGE_64K &&
 		    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
 			if (user_region) {
+				demote_segment_4k(mm, ea);
 				psize = MMU_PAGE_4K;
-				mm->context.user_psize = MMU_PAGE_4K;
-				mm->context.sllp = SLB_VSID_USER |
-					mmu_psize_defs[MMU_PAGE_4K].sllp;
 			} else if (ea < VMALLOC_END) {
 				/*
 				 * some driver did a non-cacheable mapping
@@ -756,16 +800,8 @@ #else
 	if (mmu_ci_restrictions) {
 		/* If this PTE is non-cacheable, switch to 4k */
 		if (mm->context.user_psize == MMU_PAGE_64K &&
-		    (pte_val(*ptep) & _PAGE_NO_CACHE)) {
-			mm->context.user_psize = MMU_PAGE_4K;
-			mm->context.sllp = SLB_VSID_USER |
-				mmu_psize_defs[MMU_PAGE_4K].sllp;
-			get_paca()->context = mm->context;
-			slb_flush_and_rebolt();
-#ifdef CONFIG_SPE_BASE
-			spu_flush_all_slbs(mm);
-#endif
-		}
+		    (pte_val(*ptep) & _PAGE_NO_CACHE))
+			demote_segment_4k(mm, ea);
 	}
 	if (mm->context.user_psize == MMU_PAGE_64K)
 		__hash_page_64K(ea, access, vsid, ptep, trap, local);
@@ -825,3 +861,62 @@ void low_hash_fault(struct pt_regs *regs
 	}
 	bad_page_fault(regs, address, SIGBUS);
 }
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+	unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr);
+	unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+	unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY |
+		_PAGE_COHERENT | PP_RWXX | HPTE_R_N;
+	int ret;
+
+	hash = hpt_hash(va, PAGE_SHIFT);
+	hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+
+	ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr),
+				 mode, HPTE_V_BOLTED, mmu_linear_psize);
+	BUG_ON (ret < 0);
+	spin_lock(&linear_map_hash_lock);
+	BUG_ON(linear_map_hash_slots[lmi] & 0x80);
+	linear_map_hash_slots[lmi] = ret | 0x80;
+	spin_unlock(&linear_map_hash_lock);
+}
+
+static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+	unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr);
+	unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+
+	hash = hpt_hash(va, PAGE_SHIFT);
+	spin_lock(&linear_map_hash_lock);
+	BUG_ON(!(linear_map_hash_slots[lmi] & 0x80));
+	hidx = linear_map_hash_slots[lmi] & 0x7f;
+	linear_map_hash_slots[lmi] = 0;
+	spin_unlock(&linear_map_hash_lock);
+	if (hidx & _PTEIDX_SECONDARY)
+		hash = ~hash;
+	slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+	slot += hidx & _PTEIDX_GROUP_IX;
+	ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0);
+}
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+	unsigned long flags, vaddr, lmi;
+	int i;
+
+	local_irq_save(flags);
+	for (i = 0; i < numpages; i++, page++) {
+		vaddr = (unsigned long)page_address(page);
+		lmi = __pa(vaddr) >> PAGE_SHIFT;
+		if (lmi >= linear_map_hash_count)
+			continue;
+		if (enable)
+			kernel_map_linear_page(vaddr, lmi);
+		else
+			kernel_unmap_linear_page(vaddr, lmi);
+	}
+	local_irq_restore(flags);
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f6ffaaa..fb95926 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -12,7 +12,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
@@ -316,12 +315,11 @@ void set_huge_pte_at(struct mm_struct *m
 {
 	if (pte_present(*ptep)) {
 		/* We open-code pte_clear because we need to pass the right
-		 * argument to hpte_update (huge / !huge)
+		 * argument to hpte_need_flush (huge / !huge). Might not be
+		 * necessary anymore if we make hpte_need_flush() get the
+		 * page size from the slices
 		 */
-		unsigned long old = pte_update(ptep, ~0UL);
-		if (old & _PAGE_HASHPTE)
-			hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
-		flush_tlb_pending();
+		pte_update(mm, addr & HPAGE_MASK, ptep, ~0UL, 1);
 	}
 	*ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
 }
@@ -329,12 +327,7 @@ void set_huge_pte_at(struct mm_struct *m
 pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep)
 {
-	unsigned long old = pte_update(ptep, ~0UL);
-
-	if (old & _PAGE_HASHPTE)
-		hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
-	*ptep = __pte(0);
-
+	unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1);
 	return __pte(old);
 }
 
@@ -572,6 +565,13 @@ unsigned long arch_get_unmapped_area(str
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	/* handle fixed mapping: prevent overlap with huge pages */
+	if (flags & MAP_FIXED) {
+		if (is_hugepage_only_range(mm, addr, len))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
@@ -647,6 +647,13 @@ arch_get_unmapped_area_topdown(struct fi
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	/* handle fixed mapping: prevent overlap with huge pages */
+	if (flags & MAP_FIXED) {
+		if (is_hugepage_only_range(mm, addr, len))
+			return -EINVAL;
+		return addr;
+	}
+
 	/* dont allow allocations above current base */
 	if (mm->free_area_cache > base)
 		mm->free_area_cache = base;
@@ -829,6 +836,13 @@ unsigned long hugetlb_get_unmapped_area(
 	/* Paranoia, caller should have dealt with this */
 	BUG_ON((addr + len)  < addr);
 
+	/* Handle MAP_FIXED */
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(addr, len, pgoff))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (test_thread_flag(TIF_32BIT)) {
 		curareas = current->mm->context.low_htlb_areas;
 
@@ -1063,8 +1077,7 @@ static int __init hugetlbpage_init(void)
 	huge_pgtable_cache = kmem_cache_create("hugepte_cache",
 					       HUGEPTE_TABLE_SIZE,
 					       HUGEPTE_TABLE_SIZE,
-					       SLAB_HWCACHE_ALIGN |
-					       SLAB_MUST_HWCACHE_ALIGN,
+					       0,
 					       zero_ctor, NULL);
 	if (! huge_pgtable_cache)
 		panic("hugetlbpage_init(): could not create hugepte cache\n");
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 0e53ca8..5fce6cc 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -115,6 +115,10 @@ void MMU_setup(void)
 	if (strstr(cmd_line, "noltlbs")) {
 		__map_without_ltlbs = 1;
 	}
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	__map_without_bats = 1;
+	__map_without_ltlbs = 1;
+#endif
 }
 
 /*
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index d12a87e..fe1fe85 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -183,12 +183,8 @@ void pgtable_cache_init(void)
 		    "for size: %08x...\n", name, i, size);
 		pgtable_cache[i] = kmem_cache_create(name,
 						     size, size,
-						     SLAB_HWCACHE_ALIGN |
-						     SLAB_MUST_HWCACHE_ALIGN,
+						     SLAB_PANIC,
 						     zero_ctor,
 						     NULL);
-		if (! pgtable_cache[i])
-			panic("pgtable_cache_init(): could not create %s!\n",
-			      name);
 	}
 }
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c
index 716a290..e3a1e8d 100644
--- a/arch/powerpc/mm/lmb.c
+++ b/arch/powerpc/mm/lmb.c
@@ -146,6 +146,10 @@ static long __init lmb_add_region(struct
 		unsigned long rgnbase = rgn->region[i].base;
 		unsigned long rgnsize = rgn->region[i].size;
 
+		if ((rgnbase == base) && (rgnsize == size))
+			/* Already have this region, so we're done */
+			return 0;
+
 		adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
 		if ( adjacent > 0 ) {
 			rgn->region[i].base -= size;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 52f397c..1a6e08f 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -58,9 +58,6 @@ int init_bootmem_done;
 int mem_init_done;
 unsigned long memory_limit;
 
-extern void hash_preload(struct mm_struct *mm, unsigned long ea,
-			 unsigned long access, unsigned long trap);
-
 int page_is_ram(unsigned long pfn)
 {
 	unsigned long paddr = (pfn << PAGE_SHIFT);
@@ -83,7 +80,6 @@ #else
 	return 0;
 #endif
 }
-EXPORT_SYMBOL(page_is_ram);
 
 pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 			      unsigned long size, pgprot_t vma_prot)
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index bea2d21..2558c34 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -19,9 +19,14 @@
  *  2 of the License, or (at your option) any later version.
  *
  */
+#include <linux/mm.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu.h>
 
+extern void hash_preload(struct mm_struct *mm, unsigned long ea,
+			 unsigned long access, unsigned long trap);
+
+
 #ifdef CONFIG_PPC32
 extern void mapin_ram(void);
 extern int map_page(unsigned long va, phys_addr_t pa, int flags);
@@ -35,7 +40,8 @@ extern int __map_without_bats;
 extern unsigned long ioremap_base;
 extern unsigned int rtas_data, rtas_size;
 
-extern PTE *Hash, *Hash_end;
+struct _PTE;
+extern struct _PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 
 extern unsigned int num_tlbcam_entries;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e86c37c..b3a592b 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -74,7 +74,7 @@ static struct device_node * __cpuinit fi
 
 	while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
 		/* Try interrupt server first */
-		interrupt_server = get_property(cpu_node,
+		interrupt_server = of_get_property(cpu_node,
 					"ibm,ppc-interrupt-server#s", &len);
 
 		len = len / sizeof(u32);
@@ -85,7 +85,7 @@ static struct device_node * __cpuinit fi
 					return cpu_node;
 			}
 		} else {
-			reg = get_property(cpu_node, "reg", &len);
+			reg = of_get_property(cpu_node, "reg", &len);
 			if (reg && (len > 0) && (reg[0] == hw_cpuid))
 				return cpu_node;
 		}
@@ -97,7 +97,7 @@ static struct device_node * __cpuinit fi
 /* must hold reference to node during call */
 static const int *of_get_associativity(struct device_node *dev)
 {
-	return get_property(dev, "ibm,associativity", NULL);
+	return of_get_property(dev, "ibm,associativity", NULL);
 }
 
 /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
@@ -179,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 = get_property(rtas_root,
+	ref_points = of_get_property(rtas_root,
 			"ibm,associativity-reference-points", &len);
 
 	if ((len >= 1) && ref_points) {
@@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *
 	if (!memory)
 		panic("numa.c: No memory nodes found!");
 
-	*n_addr_cells = prom_n_addr_cells(memory);
-	*n_size_cells = prom_n_size_cells(memory);
+	*n_addr_cells = of_n_addr_cells(memory);
+	*n_size_cells = of_n_size_cells(memory);
 	of_node_put(memory);
 }
 
@@ -308,9 +308,9 @@ static void __init parse_drconf_memory(s
 	int nid, default_nid = 0;
 	unsigned int start, ai, flags;
 
-	lm = get_property(memory, "ibm,lmb-size", &ls);
-	dm = get_property(memory, "ibm,dynamic-memory", &ld);
-	aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+	lm = of_get_property(memory, "ibm,lmb-size", &ls);
+	dm = of_get_property(memory, "ibm,dynamic-memory", &ld);
+	aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la);
 	if (!lm || !dm || !aa ||
 	    ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
 	    la < 2 * sizeof(unsigned int))
@@ -404,10 +404,10 @@ static int __init parse_numa_properties(
 		const unsigned int *memcell_buf;
 		unsigned int len;
 
-		memcell_buf = get_property(memory,
+		memcell_buf = of_get_property(memory,
 			"linux,usable-memory", &len);
 		if (!memcell_buf || len <= 0)
-			memcell_buf = get_property(memory, "reg", &len);
+			memcell_buf = of_get_property(memory, "reg", &len);
 		if (!memcell_buf || len <= 0)
 			continue;
 
@@ -725,7 +725,7 @@ int hot_add_scn_to_nid(unsigned long scn
 		const unsigned int *memcell_buf;
 		unsigned int len;
 
-		memcell_buf = get_property(memory, "reg", &len);
+		memcell_buf = of_get_property(memory, "reg", &len);
 		if (!memcell_buf || len <= 0)
 			continue;
 
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index c284bda..d8232b7 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned lon
 	 * mem_init() sets high_memory so only do the check after that.
 	 */
 	if (mem_init_done && (p < virt_to_phys(high_memory))) {
-		printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
-		       __builtin_return_address(0));
+		printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+		       (unsigned long long)p, __builtin_return_address(0));
 		return NULL;
 	}
 
@@ -261,14 +261,17 @@ int map_page(unsigned long va, phys_addr
 	int err = -ENOMEM;
 
 	/* Use upper 10 bits of VA to index the first level map */
-	pd = pmd_offset(pgd_offset_k(va), va);
+	pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va);
 	/* Use middle 10 bits of VA to index the second-level map */
 	pg = pte_alloc_kernel(pd, va);
 	if (pg != 0) {
 		err = 0;
-		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
-		if (mem_init_done)
-			flush_HPTE(0, va, pmd_val(*pd));
+		/* The PTE should never be already set nor present in the
+		 * hash table
+		 */
+		BUG_ON(pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE));
+		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+						     __pgprot(flags)));
 	}
 	return err;
 }
@@ -279,16 +282,19 @@ int map_page(unsigned long va, phys_addr
 void __init mapin_ram(void)
 {
 	unsigned long v, p, s, f;
+	int ktext;
 
 	s = mmu_mapin_ram();
 	v = KERNELBASE + s;
 	p = PPC_MEMSTART + s;
 	for (; s < total_lowmem; s += PAGE_SIZE) {
-		if ((char *) v >= _stext && (char *) v < etext)
-			f = _PAGE_RAM_TEXT;
-		else
-			f = _PAGE_RAM;
+		ktext = ((char *) v >= _stext && (char *) v < etext);
+		f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM;
 		map_page(v, p, f);
+#ifdef CONFIG_PPC_STD_MMU_32
+		if (ktext)
+			hash_preload(&init_mm, v, 0, 0x300);
+#endif
 		v += PAGE_SIZE;
 		p += PAGE_SIZE;
 	}
@@ -348,23 +354,27 @@ int
 get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
 {
         pgd_t	*pgd;
+	pud_t	*pud;
         pmd_t	*pmd;
         pte_t	*pte;
         int     retval = 0;
 
         pgd = pgd_offset(mm, addr & PAGE_MASK);
         if (pgd) {
-                pmd = pmd_offset(pgd, addr & PAGE_MASK);
-                if (pmd_present(*pmd)) {
-                        pte = pte_offset_map(pmd, addr & PAGE_MASK);
-                        if (pte) {
-				retval = 1;
-				*ptep = pte;
-				if (pmdp)
-					*pmdp = pmd;
-				/* XXX caller needs to do pte_unmap, yuck */
-                        }
-                }
+		pud = pud_offset(pgd, addr & PAGE_MASK);
+		if (pud && pud_present(*pud)) {
+			pmd = pmd_offset(pud, addr & PAGE_MASK);
+			if (pmd_present(*pmd)) {
+				pte = pte_offset_map(pmd, addr & PAGE_MASK);
+				if (pte) {
+					retval = 1;
+					*ptep = pte;
+					if (pmdp)
+						*pmdp = pmd;
+					/* XXX caller needs to do pte_unmap, yuck */
+				}
+			}
+		}
         }
         return(retval);
 }
@@ -445,3 +455,55 @@ #endif
 	return ret;
 }
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+
+static int __change_page_attr(struct page *page, pgprot_t prot)
+{
+	pte_t *kpte;
+	pmd_t *kpmd;
+	unsigned long address;
+
+	BUG_ON(PageHighMem(page));
+	address = (unsigned long)page_address(page);
+
+	if (v_mapped_by_bats(address) || v_mapped_by_tlbcam(address))
+		return 0;
+	if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
+		return -EINVAL;
+	set_pte_at(&init_mm, address, kpte, mk_pte(page, prot));
+	wmb();
+	flush_HPTE(0, address, pmd_val(*kpmd));
+	pte_unmap(kpte);
+
+	return 0;
+}
+
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * THIS CONFLICTS WITH BAT MAPPINGS, DEBUG USE ONLY
+ */
+static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+	int i, err = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < numpages; i++, page++) {
+		err = __change_page_attr(page, prot);
+		if (err)
+			break;
+	}
+	local_irq_restore(flags);
+	return err;
+}
+
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+	if (PageHighMem(page))
+		return;
+
+	change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 7cceb2c..0506667 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -85,8 +85,10 @@ #else
 	unsigned long max_size = (256<<20);
 	unsigned long align;
 
-	if (__map_without_bats)
+	if (__map_without_bats) {
+		printk(KERN_DEBUG "RAM mapped without BATs\n");
 		return 0;
+	}
 
 	/* Set up BAT2 and if necessary BAT3 to cover RAM. */
 
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index eeeacab..132c6bc 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -227,7 +227,7 @@ void switch_stab(struct task_struct *tsk
  * the first (bolted) segment, so that do_stab_bolted won't get a
  * recursive segment miss on the segment table itself.
  */
-void stabs_alloc(void)
+void __init stabs_alloc(void)
 {
 	int cpu;
 
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index b58baa6..fd8d08c 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -120,17 +120,20 @@ void pgtable_free_tlb(struct mmu_gather 
 }
 
 /*
- * Update the MMU hash table to correspond with a change to
- * a Linux PTE.  If wrprot is true, it is permissible to
- * change the existing HPTE to read-only rather than removing it
- * (if we remove it we should clear the _PTE_HPTEFLAGS bits).
+ * A linux PTE was changed and the corresponding hash table entry
+ * neesd to be flushed. This function will either perform the flush
+ * immediately or will batch it up if the current CPU has an active
+ * batch on it.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
  */
-void hpte_update(struct mm_struct *mm, unsigned long addr,
-		 pte_t *ptep, unsigned long pte, int huge)
+void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+		     pte_t *ptep, unsigned long pte, int huge)
 {
 	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
-	unsigned long vsid;
+	unsigned long vsid, vaddr;
 	unsigned int psize;
+	real_pte_t rpte;
 	int i;
 
 	i = batch->index;
@@ -151,6 +154,26 @@ #endif
 	} else
 		psize = pte_pagesize_index(pte);
 
+	/* Build full vaddr */
+	if (!is_kernel_addr(addr)) {
+		vsid = get_vsid(mm->context.id, addr);
+		WARN_ON(vsid == 0);
+	} else
+		vsid = get_kernel_vsid(addr);
+	vaddr = (vsid << 28 ) | (addr & 0x0fffffff);
+	rpte = __real_pte(__pte(pte), ptep);
+
+	/*
+	 * Check if we have an active batch on this CPU. If not, just
+	 * flush now and return. For now, we don global invalidates
+	 * in that case, might be worth testing the mm cpu mask though
+	 * and decide to use local invalidates instead...
+	 */
+	if (!batch->active) {
+		flush_hash_page(vaddr, rpte, psize, 0);
+		return;
+	}
+
 	/*
 	 * This can happen when we are in the middle of a TLB batch and
 	 * we encounter memory pressure (eg copy_page_range when it tries
@@ -162,47 +185,42 @@ #endif
 	 * batch
 	 */
 	if (i != 0 && (mm != batch->mm || batch->psize != psize)) {
-		flush_tlb_pending();
+		__flush_tlb_pending(batch);
 		i = 0;
 	}
 	if (i == 0) {
 		batch->mm = mm;
 		batch->psize = psize;
 	}
-	if (!is_kernel_addr(addr)) {
-		vsid = get_vsid(mm->context.id, addr);
-		WARN_ON(vsid == 0);
-	} else
-		vsid = get_kernel_vsid(addr);
-	batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff);
-	batch->pte[i] = __real_pte(__pte(pte), ptep);
+	batch->pte[i] = rpte;
+	batch->vaddr[i] = vaddr;
 	batch->index = ++i;
 	if (i >= PPC64_TLB_BATCH_NR)
-		flush_tlb_pending();
+		__flush_tlb_pending(batch);
 }
 
+/*
+ * This function is called when terminating an mmu batch or when a batch
+ * is full. It will perform the flush of all the entries currently stored
+ * in a batch.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
+ */
 void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
 {
-	int i;
-	int cpu;
 	cpumask_t tmp;
-	int local = 0;
+	int i, local = 0;
 
-	BUG_ON(in_interrupt());
-
-	cpu = get_cpu();
 	i = batch->index;
-	tmp = cpumask_of_cpu(cpu);
+	tmp = cpumask_of_cpu(smp_processor_id());
 	if (cpus_equal(batch->mm->cpu_vm_mask, tmp))
 		local = 1;
-
 	if (i == 1)
 		flush_hash_page(batch->vaddr[0], batch->pte[0],
 				batch->psize, local);
 	else
 		flush_hash_range(i, local);
 	batch->index = 0;
-	put_cpu();
 }
 
 void pte_free_finish(void)
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 4ccef2d..4b5f952 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -12,6 +12,6 @@ DRIVER_OBJS := $(addprefix ../../../driv
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
-oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
+oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index fbd62ea..1a7ef7e 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -160,6 +160,9 @@ #endif
 		case PPC_OPROFILE_POWER4:
 			model = &op_model_power4;
 			break;
+		case PPC_OPROFILE_PA6T:
+			model = &op_model_pa6t;
+			break;
 #endif
 #ifdef CONFIG_6xx
 		case PPC_OPROFILE_G4:
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index e08e1d7..626b29f 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -37,6 +37,7 @@ #include <asm/rtas.h>
 #include <asm/system.h>
 
 #include "../platforms/cell/interrupt.h"
+#include "../platforms/cell/cbe_regs.h"
 
 #define PPU_CYCLES_EVENT_NUM 1	/*  event number for CYCLES */
 #define PPU_CYCLES_GRP_NUM   1  /* special group number for identifying
@@ -130,7 +131,7 @@ static int pm_rtas_token;
 static u32 reset_value[NR_PHYS_CTRS];
 static int num_counters;
 static int oprofile_running;
-static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(virt_cntr_lock);
 
 static u32 ctr_enabled;
 
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
new file mode 100644
index 0000000..e8a56b0
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Shashi Rao, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/oprofile/op_model_power4.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/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
+#include <asm/reg.h>
+
+static unsigned char oprofile_running;
+
+/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
+static u64 mmcr0_val;
+static u64 mmcr1_val;
+
+/* inited in pa6t_reg_setup */
+static u64 reset_value[OP_MAX_COUNTER];
+
+static inline u64 ctr_read(unsigned int i)
+{
+	switch (i) {
+	case 0:
+		return mfspr(SPRN_PA6T_PMC0);
+	case 1:
+		return mfspr(SPRN_PA6T_PMC1);
+	case 2:
+		return mfspr(SPRN_PA6T_PMC2);
+	case 3:
+		return mfspr(SPRN_PA6T_PMC3);
+	case 4:
+		return mfspr(SPRN_PA6T_PMC4);
+	case 5:
+		return mfspr(SPRN_PA6T_PMC5);
+	default:
+		printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
+		return 0;
+	}
+}
+
+static inline void ctr_write(unsigned int i, u64 val)
+{
+	switch (i) {
+	case 0:
+		mtspr(SPRN_PA6T_PMC0, val);
+		break;
+	case 1:
+		mtspr(SPRN_PA6T_PMC1, val);
+		break;
+	case 2:
+		mtspr(SPRN_PA6T_PMC2, val);
+		break;
+	case 3:
+		mtspr(SPRN_PA6T_PMC3, val);
+		break;
+	case 4:
+		mtspr(SPRN_PA6T_PMC4, val);
+		break;
+	case 5:
+		mtspr(SPRN_PA6T_PMC5, val);
+		break;
+	default:
+		printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
+		break;
+	}
+}
+
+
+/* precompute the values to stuff in the hardware registers */
+static void pa6t_reg_setup(struct op_counter_config *ctr,
+			   struct op_system_config *sys,
+			   int num_ctrs)
+{
+	int pmc;
+
+	/*
+	 * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
+	 * event_mappings file by turning off the counters that the user doesn't
+	 * care about
+	 *
+	 * setup user and kernel profiling
+	 */
+	for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
+		if (!ctr[pmc].enabled) {
+			sys->mmcr0 &= ~(0x1UL << pmc);
+			sys->mmcr0 &= ~(0x1UL << (pmc+12));
+			pr_debug("turned off counter %u\n", pmc);
+		}
+
+	if (sys->enable_kernel)
+		sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
+	else
+		sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);
+
+	if (sys->enable_user)
+		sys->mmcr0 |= PA6T_MMCR0_PREN;
+	else
+		sys->mmcr0 &= ~PA6T_MMCR0_PREN;
+
+	/*
+	 * The performance counter event settings are given in the mmcr0 and
+	 * mmcr1 values passed from the user in the op_system_config
+	 * structure (sys variable).
+	 */
+	mmcr0_val = sys->mmcr0;
+	mmcr1_val = sys->mmcr1;
+	pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
+	pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);
+
+	for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
+		/* counters are 40 bit. Move to cputable at some point? */
+		reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
+		pr_debug("reset_value for pmc%u inited to 0x%lx\n",
+				 pmc, reset_value[pmc]);
+	}
+}
+
+/* configure registers on this cpu */
+static void pa6t_cpu_setup(struct op_counter_config *ctr)
+{
+	u64 mmcr0 = mmcr0_val;
+	u64 mmcr1 = mmcr1_val;
+
+	/* Default is all PMCs off */
+	mmcr0 &= ~(0x3FUL);
+	mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+	/* program selected programmable events in */
+	mtspr(SPRN_PA6T_MMCR1, mmcr1);
+
+	pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
+		mfspr(SPRN_PA6T_MMCR0));
+	pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
+		mfspr(SPRN_PA6T_MMCR1));
+}
+
+static void pa6t_start(struct op_counter_config *ctr)
+{
+	int i;
+
+	/* Hold off event counting until rfid */
+	u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+
+	for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+		if (ctr[i].enabled)
+			ctr_write(i, reset_value[i]);
+		else
+			ctr_write(i, 0UL);
+
+	mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+	oprofile_running = 1;
+
+	pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+static void pa6t_stop(void)
+{
+	u64 mmcr0;
+
+	/* freeze counters */
+	mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+	mmcr0 |= PA6T_MMCR0_FCM0;
+	mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+	oprofile_running = 0;
+
+	pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+/* handle the perfmon overflow vector */
+static void pa6t_handle_interrupt(struct pt_regs *regs,
+				  struct op_counter_config *ctr)
+{
+	unsigned long pc = mfspr(SPRN_PA6T_SIAR);
+	int is_kernel = is_kernel_addr(pc);
+	u64 val;
+	int i;
+	u64 mmcr0;
+
+	/* disable perfmon counting until rfid */
+	mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+	mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);
+
+	/* Record samples. We've got one global bit for whether a sample
+	 * was taken, so add it for any counter that triggered overflow.
+	 */
+	for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
+		val = ctr_read(i);
+		if (val & (0x1UL << 39)) { /* Overflow bit set */
+			if (oprofile_running && ctr[i].enabled) {
+				if (mmcr0 & PA6T_MMCR0_SIARLOG)
+					oprofile_add_ext_sample(pc, regs, i, is_kernel);
+				ctr_write(i, reset_value[i]);
+			} else {
+				ctr_write(i, 0UL);
+			}
+		}
+	}
+
+	/* Restore mmcr0 to a good known value since the PMI changes it */
+	mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+	mtspr(SPRN_PA6T_MMCR0, mmcr0);
+}
+
+struct op_powerpc_model op_model_pa6t = {
+	.reg_setup		= pa6t_reg_setup,
+	.cpu_setup		= pa6t_cpu_setup,
+	.start			= pa6t_start,
+	.stop			= pa6t_stop,
+	.handle_interrupt	= pa6t_handle_interrupt,
+};
diff --git a/arch/powerpc/platforms/44x/44x.h b/arch/powerpc/platforms/44x/44x.h
new file mode 100644
index 0000000..42eabf8
--- /dev/null
+++ b/arch/powerpc/platforms/44x/44x.h
@@ -0,0 +1,8 @@
+#ifndef __POWERPC_PLATFORMS_44X_44X_H
+#define __POWERPC_PLATFORMS_44X_44X_H
+
+extern u8 as1_readb(volatile u8 __iomem  *addr);
+extern void as1_writeb(u8 data, volatile u8 __iomem *addr);
+extern void ppc44x_reset_system(char *cmd);
+
+#endif /* __POWERPC_PLATFORMS_44X_44X_H */
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
new file mode 100644
index 0000000..8e66949
--- /dev/null
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -0,0 +1,56 @@
+#config BAMBOO
+#	bool "Bamboo"
+#	depends on 44x
+#	default n
+#	select 440EP
+#	help
+#	  This option enables support for the IBM PPC440EP evaluation board.
+
+config EBONY
+	bool "Ebony"
+	depends on 44x
+	default y
+	select 440GP
+	help
+	  This option enables support for the IBM PPC440GP evaluation board.
+
+#config LUAN
+#	bool "Luan"
+#	depends on 44x
+#	default n
+#	select 440SP
+#	help
+#	  This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+#	bool "Ocotea"
+#	depends on 44x
+#	default n
+#	select 440GX
+#	help
+#	  This option enables support for the IBM PPC440GX evaluation board.
+
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
+	bool
+	select PPC_FPU
+	select IBM440EP_ERR42
+
+config 440GP
+	bool
+	select IBM_NEW_EMAC_ZMII
+
+config 440GX
+	bool
+
+config 440SP
+	bool
+
+config 440A
+	bool
+	depends on 440GX
+	default y
+
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
+	bool
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
new file mode 100644
index 0000000..41d0a18
--- /dev/null
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_44x)	:= misc_44x.o
+obj-$(CONFIG_EBONY)	+= ebony.o
diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c
new file mode 100644
index 0000000..ad526ea
--- /dev/null
+++ b/arch/powerpc/platforms/44x/ebony.c
@@ -0,0 +1,73 @@
+/*
+ * Ebony board specific routines
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003-2005 Zultys Technologies
+ *
+ * Rewritten and ported to the merged powerpc tree:
+ * Copyright 2007 David Gibson <dwg@au1.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.
+ */
+
+#include <linux/init.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/time.h>
+#include <asm/uic.h>
+#include <asm/of_platform.h>
+
+#include "44x.h"
+
+static struct of_device_id ebony_of_bus[] = {
+	{ .type = "ibm,plb", },
+	{ .type = "ibm,opb", },
+	{ .type = "ibm,ebc", },
+	{},
+};
+
+static int __init ebony_device_probe(void)
+{
+	if (!machine_is(ebony))
+		return 0;
+
+	of_platform_bus_probe(NULL, ebony_of_bus, NULL);
+
+	return 0;
+}
+device_initcall(ebony_device_probe);
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init ebony_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "ibm,ebony"))
+		return 0;
+
+	return 1;
+}
+
+static void __init ebony_setup_arch(void)
+{
+}
+
+define_machine(ebony) {
+	.name			= "Ebony",
+	.probe			= ebony_probe,
+	.setup_arch		= ebony_setup_arch,
+	.progress		= udbg_progress,
+	.init_IRQ		= uic_init_tree,
+	.get_irq		= uic_get_irq,
+	.restart		= ppc44x_reset_system,
+	.calibrate_decr		= generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/44x/misc_44x.S b/arch/powerpc/platforms/44x/misc_44x.S
new file mode 100644
index 0000000..3bce71d
--- /dev/null
+++ b/arch/powerpc/platforms/44x/misc_44x.S
@@ -0,0 +1,57 @@
+/*
+ * This file contains miscellaneous low-level functions for PPC 44x.
+ *    Copyright 2007 David Gibson <dwg@au1.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.
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+
+	.text
+
+/*
+ * Do an IO access in AS1
+ */
+_GLOBAL(as1_readb)
+	mfmsr	r7
+	ori	r0,r7,MSR_DS
+	sync
+	mtmsr	r0
+	sync
+	isync
+	lbz	r3,0(r3)
+	sync
+	mtmsr	r7
+	sync
+	isync
+	blr
+
+_GLOBAL(as1_writeb)
+	mfmsr	r7
+	ori	r0,r7,MSR_DS
+	sync
+	mtmsr	r0
+	sync
+	isync
+	stb	r3,0(r4)
+	sync
+	mtmsr	r7
+	sync
+	isync
+	blr
+
+/*
+ * void ppc44x_reset_system(char *cmd)
+ *
+ * At present, this routine just applies a system reset.
+ */
+_GLOBAL(ppc44x_reset_system)
+	mfspr	r13,SPRN_DBCR0
+	oris	r13,r13,DBCR0_RST_SYSTEM@h
+	mtspr	SPRN_DBCR0,r13
+	b	.			/* Just in case the reset doesn't work */
diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/4xx/Kconfig
index 2f2a13e..ded357c 100644
--- a/arch/powerpc/platforms/4xx/Kconfig
+++ b/arch/powerpc/platforms/4xx/Kconfig
@@ -3,278 +3,206 @@ config 4xx
 	depends on 40x || 44x
 	default y
 
-config WANT_EARLY_SERIAL
+config BOOKE
 	bool
-	select SERIAL_8250
-	default n
-
-menu "AMCC 4xx options"
-	depends on 4xx
-
-choice
-	prompt "Machine Type"
-	depends on 40x
-	default WALNUT
-
-config BUBINGA
-	bool "Bubinga"
-	select WANT_EARLY_SERIAL
-	help
-	  This option enables support for the IBM 405EP evaluation board.
-
-config CPCI405
-	bool "CPCI405"
-	help
-	  This option enables support for the CPCI405 board.
-
-config EP405
-	bool "EP405/EP405PC"
-	help
-	  This option enables support for the EP405/EP405PC boards.
-
-config REDWOOD_5
-	bool "Redwood-5"
-	help
-	  This option enables support for the IBM STB04 evaluation board.
-
-config REDWOOD_6
-	bool "Redwood-6"
-	help
-	  This option enables support for the IBM STBx25xx evaluation board.
-
-config SYCAMORE
-	bool "Sycamore"
-	help
-	  This option enables support for the IBM PPC405GPr evaluation board.
-
-config WALNUT
-	bool "Walnut"
-	help
-	  This option enables support for the IBM PPC405GP evaluation board.
-
-config XILINX_ML300
-	bool "Xilinx-ML300"
-	help
-	  This option enables support for the Xilinx ML300 evaluation board.
-
-endchoice
-
-choice
-	prompt "Machine Type"
 	depends on 44x
-	default EBONY
-
-config BAMBOO
-	bool "Bamboo"
-	select WANT_EARLY_SERIAL
-	help
-	  This option enables support for the IBM PPC440EP evaluation board.
-
-config EBONY
-	bool "Ebony"
-	select WANT_EARLY_SERIAL
-	help
-	  This option enables support for the IBM PPC440GP evaluation board.
-
-config LUAN
-	bool "Luan"
-	select WANT_EARLY_SERIAL
-	help
-	  This option enables support for the IBM PPC440SP evaluation board.
-
-config OCOTEA
-	bool "Ocotea"
-	select WANT_EARLY_SERIAL
-	help
-	  This option enables support for the IBM PPC440GX evaluation board.
+	default y
 
-endchoice
+menu "AMCC 40x options"
+	depends on 40x
 
-config EP405PC
-	bool "EP405PC Support"
-	depends on EP405
+#config BUBINGA
+#	bool "Bubinga"
+#	depends on 40x
+#	default n
+#	select 405EP
+#	help
+#	  This option enables support for the IBM 405EP evaluation board.
+
+#config CPCI405
+#	bool "CPCI405"
+#	depends on 40x
+#	default n
+#	select 405GP
+#	help
+#	  This option enables support for the CPCI405 board.
+
+#config EP405
+#	bool "EP405/EP405PC"
+#	depends on 40x
+#	default n
+#	select 405GP
+#	help
+#	  This option enables support for the EP405/EP405PC boards.
+
+#config EP405PC
+#	bool "EP405PC Support"
+#	depends on EP405
+#	default y
+#	help
+#	  This option enables support for the extra features of the EP405PC board.
+
+#config REDWOOD_5
+#	bool "Redwood-5"
+#	depends on 40x
+#	default n
+#	select STB03xxx
+#	help
+#	  This option enables support for the IBM STB04 evaluation board.
+
+#config REDWOOD_6
+#	bool "Redwood-6"
+#	depends on 40x
+#	default n
+#	select STB03xxx
+#	help
+#	  This option enables support for the IBM STBx25xx evaluation board.
+
+#config SYCAMORE
+#	bool "Sycamore"
+#	depends on 40x
+#	default n
+#	select 405GPR
+#	help
+#	  This option enables support for the IBM PPC405GPr evaluation board.
+
+#config WALNUT
+#	bool "Walnut"
+#	depends on 40x
+#	default y
+#	select 405GP
+#	help
+#	  This option enables support for the IBM PPC405GP evaluation board.
+
+#config XILINX_ML300
+#	bool "Xilinx-ML300"
+#	depends on 40x
+#	default y
+#	select VIRTEX_II_PRO
+#	help
+#	  This option enables support for the Xilinx ML300 evaluation board.
 
+endmenu
 
-# It's often necessary to know the specific 4xx processor type.
-# Fortunately, it is impled (so far) from the board type, so we
-# don't need to ask more redundant questions.
+# 40x specific CPU modules, selected based on the board above.
 config NP405H
 	bool
-	depends on ASH
-	default y
+	#depends on ASH
 
-config 440EP
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+config 403GCX
 	bool
-	depends on BAMBOO
-	select PPC_FPU
-	default y
+	#depends on OAK
+	select IBM405_ERR51
 
-config 440GP
+config 405GP
 	bool
-	depends on EBONY
-	default y
+	select IBM405_ERR77
+	select IBM405_ERR51
 
-config 440GX
+config 405EP
 	bool
-	depends on OCOTEA
-	default y
 
-config 440SP
+config 405GPR
 	bool
-	depends on LUAN
-	default y
 
-config 440
+config VIRTEX_II_PRO
 	bool
-	depends on 440GP || 440SP || 440EP
-	default y
+	select IBM405_ERR77
+	select IBM405_ERR51
 
-config 440A
+config STB03xxx
 	bool
-	depends on 440GX
-	default y
+	select IBM405_ERR77
+	select IBM405_ERR51
 
-config IBM440EP_ERR42
-	bool
-	depends on 440EP
-	default y
+# 40x errata/workaround config symbols, selected by the CPU models above
 
 # All 405-based cores up until the 405GPR and 405EP have this errata.
 config IBM405_ERR77
 	bool
-	depends on 40x && !403GCX && !405GPR && !405EP
-	default y
 
 # All 40x-based cores, up until the 405GPR and 405EP have this errata.
 config IBM405_ERR51
 	bool
-	depends on 40x && !405GPR && !405EP
-	default y
 
-config BOOKE
-	bool
+menu "AMCC 44x options"
 	depends on 44x
-	default y
-
-config IBM_OCP
-	bool
-	depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
-	default y
 
-config XILINX_OCP
-	bool
-	depends on XILINX_ML300
-	default y
+#config BAMBOO
+#	bool "Bamboo"
+#	depends on 44x
+#	default n
+#	select 440EP
+#	help
+#	  This option enables support for the IBM PPC440EP evaluation board.
 
-config IBM_EMAC4
-	bool
-	depends on 440GX || 440SP
-	default y
-
-config BIOS_FIXUP
-	bool
-	depends on BUBINGA || EP405 || SYCAMORE || WALNUT
-	default y
-
-# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
-config 403GCX
-	bool
-	depends on OAK
-	default y
-
-config 405EP
-	bool
-	depends on BUBINGA
-	default y
-
-config 405GP
-	bool
-	depends on CPCI405 || EP405 || WALNUT
-	default y
-
-config 405GPR
-	bool
-	depends on SYCAMORE
+config EBONY
+	bool "Ebony"
+	depends on 44x
 	default y
+	select 440GP
+	help
+	  This option enables support for the IBM PPC440GP evaluation board.
 
-config VIRTEX_II_PRO
-	bool
-	depends on XILINX_ML300
-	default y
+#config LUAN
+#	bool "Luan"
+#	depends on 44x
+#	default n
+#	select 440SP
+#	help
+#	  This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+#	bool "Ocotea"
+#	depends on 44x
+#	default n
+#	select 440GX
+#	help
+#	  This option enables support for the IBM PPC440GX evaluation board.
 
-config STB03xxx
-	bool
-	depends on REDWOOD_5 || REDWOOD_6
-	default y
+endmenu
 
-config EMBEDDEDBOOT
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
 	bool
-	depends on EP405 || XILINX_ML300
-	default y
+	select PPC_FPU
+	select IBM440EP_ERR42
 
-config IBM_OPENBIOS
+config 440GP
 	bool
-	depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
-	default y
+	select IBM_NEW_EMAC_ZMII
 
-config PPC4xx_DMA
-	bool "PPC4xx DMA controller support"
-	depends on 4xx
-
-config PPC4xx_EDMA
+config 440GX
 	bool
-	depends on !STB03xxx && PPC4xx_DMA
-	default y
 
-config PPC_GEN550
+config 440SP
 	bool
-	depends on 4xx
-	default y
-
-choice
-	prompt "TTYS0 device and default console"
-	depends on 40x
-	default UART0_TTYS0
-
-config UART0_TTYS0
-	bool "UART0"
 
-config UART0_TTYS1
-	bool "UART1"
-
-endchoice
-
-config SERIAL_SICC
-	bool "SICC Serial port support"
-	depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
+config 440A
 	bool
-	depends on SERIAL_SICC && UART0_TTYS1
+	depends on 440GX
 	default y
 
-config SERIAL_SICC_CONSOLE
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
 	bool
-	depends on SERIAL_SICC && UART0_TTYS1
-	default y
-endmenu
 
+#config XILINX_OCP
+#	bool
+#	depends on XILINX_ML300
+#	default y
 
-menu "IBM 40x options"
-	depends on 40x
-
-config SERIAL_SICC
-	bool "SICC Serial port"
-	depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
-	bool
-	depends on SERIAL_SICC && UART0_TTYS1
-	default y
+#config BIOS_FIXUP
+#	bool
+#	depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+#	default y
 
-config SERIAL_SICC_CONSOLE
-	bool
-	depends on SERIAL_SICC && UART0_TTYS1
-	default y
+#config PPC4xx_DMA
+#	bool "PPC4xx DMA controller support"
+#	depends on 4xx
 
-endmenu
+#config PPC4xx_EDMA
+#	bool
+#	depends on !STB03xxx && PPC4xx_DMA
+#	default y
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig
new file mode 100644
index 0000000..3ffaa06
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/Kconfig
@@ -0,0 +1,36 @@
+config PPC_MPC52xx
+	bool
+	select FSL_SOC
+	default n
+
+config PPC_MPC5200
+	bool
+	select PPC_MPC52xx
+	default n
+
+config PPC_MPC5200_BUGFIX
+	bool "MPC5200 (L25R) bugfix support"
+	depends on PPC_MPC5200
+	default n
+	help
+	  Enable workarounds for original MPC5200 errata.  This is not required
+	  for MPC5200B based boards.
+
+	  It is safe to say 'Y' here
+
+config PPC_EFIKA
+	bool "bPlan Efika 5k2. MPC5200B based computer"
+	depends on PPC_MULTIPLATFORM && PPC32
+	select PPC_RTAS
+	select RTAS_PROC
+	select PPC_MPC52xx
+	select PPC_NATIVE
+	default n
+
+config PPC_LITE5200
+	bool "Freescale Lite5200 Eval Board"
+	depends on PPC_MULTIPLATFORM && PPC32
+	select PPC_MPC5200
+	default n
+
+
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index 07cdbca..b91e39c 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -8,3 +8,5 @@ endif
 
 obj-$(CONFIG_PPC_EFIKA)		+= efika.o
 obj-$(CONFIG_PPC_LITE5200)	+= lite5200.o
+
+obj-$(CONFIG_PM)		+= mpc52xx_sleep.o mpc52xx_pm.o
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index 8de0341..f591a9f 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -112,7 +112,7 @@ void __init efika_pcisetup(void)
 		return;
 	}
 
-	bus_range = get_property(pcictrl, "bus-range", &len);
+	bus_range = of_get_property(pcictrl, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING EFIKA_PLATFORM_NAME
 		       ": Can't get bus-range for %s\n", pcictrl->full_name);
@@ -158,18 +158,17 @@ #endif
 static void efika_show_cpuinfo(struct seq_file *m)
 {
 	struct device_node *root;
-	const char *revision = NULL;
-	const char *codegendescription = NULL;
-	const char *codegenvendor = NULL;
+	const char *revision;
+	const char *codegendescription;
+	const char *codegenvendor;
 
 	root = of_find_node_by_path("/");
 	if (!root)
 		return;
 
-	revision = get_property(root, "revision", NULL);
-	codegendescription =
-		    get_property(root, "CODEGEN,description", NULL);
-	codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+	revision = of_get_property(root, "revision", NULL);
+	codegendescription = of_get_property(root, "CODEGEN,description", NULL);
+	codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL);
 
 	if (codegendescription)
 		seq_printf(m, "machine\t\t: %s\n", codegendescription);
@@ -185,6 +184,16 @@ static void efika_show_cpuinfo(struct se
 	of_node_put(root);
 }
 
+#ifdef CONFIG_PM
+static void efika_suspend_prepare(void __iomem *mbar)
+{
+	u8 pin = 4;	/* GPIO_WKUP_4 (GPIO_PSC6_0 - IRDA_RX) */
+	u8 level = 1;	/* wakeup on high level */
+	/* IOW. to wake it up, short pins 1 and 3 on IRDA connector */
+	mpc52xx_set_wakeup_gpio(pin, level);
+}
+#endif
+
 static void __init efika_setup_arch(void)
 {
 	rtas_initialize();
@@ -200,6 +209,11 @@ #endif
 
 	efika_pcisetup();
 
+#ifdef CONFIG_PM
+	mpc52xx_suspend.board_suspend_prepare = efika_suspend_prepare;
+	mpc52xx_pm_init();
+#endif
+
 	if (ppc_md.progress)
 		ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0);
 }
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index cc3b40d..1cfc00d 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -85,6 +85,28 @@ error:
 	iounmap(gpio);
 }
 
+#ifdef CONFIG_PM
+static u32 descr_a;
+static void lite5200_suspend_prepare(void __iomem *mbar)
+{
+	u8 pin = 1;	/* GPIO_WKUP_1 (GPIO_PSC2_4) */
+	u8 level = 0;	/* wakeup on low level */
+	mpc52xx_set_wakeup_gpio(pin, level);
+
+	/*
+	 * power down usb port
+	 * this needs to be called before of-ohci suspend code
+	 */
+	descr_a = in_be32(mbar + 0x1048);
+	out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100);
+}
+
+static void lite5200_resume_finish(void __iomem *mbar)
+{
+	out_be32(mbar + 0x1048, descr_a);
+}
+#endif
+
 static void __init lite5200_setup_arch(void)
 {
 	struct device_node *np;
@@ -94,8 +116,8 @@ static void __init lite5200_setup_arch(v
 
 	np = of_find_node_by_type(NULL, "cpu");
 	if (np) {
-		unsigned int *fp =
-		    (int *)get_property(np, "clock-frequency", NULL);
+		const unsigned int *fp =
+			of_get_property(np, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
@@ -107,10 +129,18 @@ static void __init lite5200_setup_arch(v
 	mpc52xx_setup_cpu();	/* Generic */
 	lite5200_setup_cpu();	/* Platorm specific */
 
+#ifdef CONFIG_PM
+	mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
+	mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
+	mpc52xx_pm_init();
+#endif
+
 #ifdef CONFIG_PCI
-	np = of_find_node_by_type(np, "pci");
-	if (np)
+	np = of_find_node_by_type(NULL, "pci");
+	if (np) {
 		mpc52xx_add_bridge(np);
+		of_node_put(np);
+	}
 #endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -132,7 +162,7 @@ void lite5200_show_cpuinfo(struct seq_fi
 	const char *model = NULL;
 
 	if (np)
-		model = get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 
 	seq_printf(m, "vendor\t\t:	Freescale Semiconductor\n");
 	seq_printf(m, "machine\t\t:	%s\n", model ? model : "unknown");
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index ed0cb69..2dd415f 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -60,7 +60,7 @@ mpc52xx_find_ipb_freq(struct device_node
 
 	of_node_get(node);
 	while (node) {
-		p_ipb_freq = get_property(node, "bus-frequency", NULL);
+		p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
 		if (p_ipb_freq)
 			break;
 
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index faf161b..34d34a2 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -370,7 +370,7 @@ mpc52xx_add_bridge(struct device_node *n
 		return -EINVAL;
 	}
 
-	bus_range = get_property(node, "bus-range", &len);
+	bus_range = of_get_property(node, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
 		       node->full_name);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
new file mode 100644
index 0000000..fd40044
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -0,0 +1,191 @@
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/mpc52xx.h>
+
+#include "mpc52xx_pic.h"
+
+
+/* these are defined in mpc52xx_sleep.S, and only used here */
+extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs,
+		struct mpc52xx_cdm *, struct mpc52xx_intr *);
+extern void mpc52xx_ds_sram(void);
+extern const long mpc52xx_ds_sram_size;
+extern void mpc52xx_ds_cached(void);
+extern const long mpc52xx_ds_cached_size;
+
+static void __iomem *mbar;
+static void __iomem *sdram;
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_gpio_wkup __iomem *gpiow;
+static void *sram;
+static int sram_size;
+
+struct mpc52xx_suspend mpc52xx_suspend;
+
+static int mpc52xx_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
+{
+	u16 tmp;
+
+	/* enable gpio */
+	out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
+	/* set as input */
+	out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
+	/* enable deep sleep interrupt */
+	out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
+	/* low/high level creates wakeup interrupt */
+	tmp = in_be16(&gpiow->wkup_itype);
+	tmp &= ~(0x3 << (pin * 2));
+	tmp |= (!level + 1) << (pin * 2);
+	out_be16(&gpiow->wkup_itype, tmp);
+	/* master enable */
+	out_8(&gpiow->wkup_maste, 1);
+
+	return 0;
+}
+
+int mpc52xx_pm_prepare(suspend_state_t state)
+{
+	if (state != PM_SUSPEND_STANDBY)
+		return -EINVAL;
+
+	/* map the whole register space */
+	mbar = mpc52xx_find_and_map("mpc5200");
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+	/* these offsets are from mpc5200 users manual */
+	sdram	= mbar + 0x100;
+	cdm	= mbar + 0x200;
+	intr	= mbar + 0x500;
+	gpiow	= mbar + 0xc00;
+	sram	= mbar + 0x8000;	/* Those will be handled by the */
+	sram_size = 0x4000;		/* bestcomm driver soon */
+
+	/* call board suspend code, if applicable */
+	if (mpc52xx_suspend.board_suspend_prepare)
+		mpc52xx_suspend.board_suspend_prepare(mbar);
+	else {
+		printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
+				__func__, __LINE__);
+		goto out_unmap;
+	}
+
+	return 0;
+
+ out_unmap:
+	iounmap(mbar);
+	return -ENOSYS;
+}
+
+
+char saved_sram[0x4000];
+
+int mpc52xx_pm_enter(suspend_state_t state)
+{
+	u32 clk_enables;
+	u32 msr, hid0;
+	u32 intr_main_mask;
+	void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500;
+	unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
+	char saved_0x500[mpc52xx_ds_cached_size];
+
+	/* disable all interrupts in PIC */
+	intr_main_mask = in_be32(&intr->main_mask);
+	out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
+
+	/* don't let DEC expire any time soon */
+	mtspr(SPRN_DEC, 0x7fffffff);
+
+	/* save SRAM */
+	memcpy(saved_sram, sram, sram_size);
+
+	/* copy low level suspend code to sram */
+	memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
+
+	out_8(&cdm->ccs_sleep_enable, 1);
+	out_8(&cdm->osc_sleep_enable, 1);
+	out_8(&cdm->ccs_qreq_test, 1);
+
+	/* disable all but SDRAM and bestcomm (SRAM) clocks */
+	clk_enables = in_be32(&cdm->clk_enables);
+	out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
+
+	/* disable power management */
+	msr = mfmsr();
+	mtmsr(msr & ~MSR_POW);
+
+	/* enable sleep mode, disable others */
+	hid0 = mfspr(SPRN_HID0);
+	mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
+
+	/* save original, copy our irq handler, flush from dcache and invalidate icache */
+	memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
+	memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
+	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+	/* call low-level sleep code */
+	mpc52xx_deep_sleep(sram, sdram, cdm, intr);
+
+	/* restore original irq handler */
+	memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
+	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+	/* restore old power mode */
+	mtmsr(msr & ~MSR_POW);
+	mtspr(SPRN_HID0, hid0);
+	mtmsr(msr);
+
+	out_be32(&cdm->clk_enables, clk_enables);
+	out_8(&cdm->ccs_sleep_enable, 0);
+	out_8(&cdm->osc_sleep_enable, 0);
+
+	/* restore SRAM */
+	memcpy(sram, saved_sram, sram_size);
+
+	/* restart jiffies */
+	wakeup_decrementer();
+
+	/* reenable interrupts in PIC */
+	out_be32(&intr->main_mask, intr_main_mask);
+
+	return 0;
+}
+
+int mpc52xx_pm_finish(suspend_state_t state)
+{
+	/* call board resume code */
+	if (mpc52xx_suspend.board_resume_finish)
+		mpc52xx_suspend.board_resume_finish(mbar);
+
+	iounmap(mbar);
+
+	return 0;
+}
+
+static struct pm_ops mpc52xx_pm_ops = {
+	.valid		= mpc52xx_pm_valid,
+	.prepare	= mpc52xx_pm_prepare,
+	.enter		= mpc52xx_pm_enter,
+	.finish		= mpc52xx_pm_finish,
+};
+
+int __init mpc52xx_pm_init(void)
+{
+	pm_set_ops(&mpc52xx_pm_ops);
+	return 0;
+}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_sleep.S b/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
new file mode 100644
index 0000000..4dc170b
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
@@ -0,0 +1,154 @@
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+
+.text
+
+_GLOBAL(mpc52xx_deep_sleep)
+mpc52xx_deep_sleep: /* args r3-r6: SRAM, SDRAM regs, CDM regs, INTR regs */
+
+	/* enable interrupts */
+	mfmsr	r7
+	ori	r7, r7, 0x8000 /* EE */
+	mtmsr	r7
+	sync; isync;
+
+	li	r10, 0 /* flag that irq handler sets */
+
+	/* enable tmr7 (or any other) interrupt */
+	lwz	r8, 0x14(r6) /* intr->main_mask */
+	ori	r8, r8, 0x1
+	xori	r8, r8, 0x1
+	stw	r8, 0x14(r6)
+	sync
+
+	/* emulate tmr7 interrupt */
+	li	r8, 0x1
+	stw	r8, 0x40(r6) /* intr->main_emulate */
+	sync
+
+	/* wait for it to happen */
+1:
+	cmpi	cr0, r10, 1
+	bne	cr0, 1b
+
+	/* lock icache */
+	mfspr	r10, SPRN_HID0
+	ori	r10, r10, 0x2000
+	sync; isync;
+	mtspr	SPRN_HID0, r10
+	sync; isync;
+
+
+	mflr	r9 /* save LR */
+
+	/* jump to sram */
+	mtlr	r3
+	blrl
+
+	mtlr	r9 /* restore LR */
+
+	/* unlock icache */
+	mfspr	r10, SPRN_HID0
+	ori	r10, r10, 0x2000
+	xori	r10, r10, 0x2000
+	sync; isync;
+	mtspr	SPRN_HID0, r10
+	sync; isync;
+
+
+	/* return to C code */
+	blr
+
+
+_GLOBAL(mpc52xx_ds_sram)
+mpc52xx_ds_sram:
+	/* put SDRAM into self-refresh */
+	lwz	r8, 0x4(r4)	/* sdram->ctrl */
+
+	oris	r8, r8, 0x8000 /* mode_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	ori	r8, r8, 0x0002 /* soft_pre */
+	stw	r8, 0x4(r4)
+	sync
+	xori	r8, r8, 0x0002
+
+	xoris	r8, r8, 0x8000 /* !mode_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	oris	r8, r8, 0x5000
+	xoris	r8, r8, 0x4000 /* ref_en !cke */
+	stw	r8, 0x4(r4)
+	sync
+
+	/* disable SDRAM clock */
+	lwz	r8, 0x14(r5) /* cdm->clkenable */
+	ori	r8, r8, 0x0008
+	xori	r8, r8, 0x0008
+	stw	r8, 0x14(r5)
+	sync
+
+
+	/* put mpc5200 to sleep */
+	mfmsr	r10
+	oris	r10, r10, 0x0004	/* POW = 1 */
+	sync; isync;
+	mtmsr	r10
+	sync; isync;
+
+
+	/* enable clock */
+	lwz	r8, 0x14(r5)
+	ori	r8, r8, 0x0008
+	stw	r8, 0x14(r5)
+	sync
+
+	/* get ram out of self-refresh */
+	lwz	r8, 0x4(r4)
+	oris	r8, r8, 0x5000 /* cke ref_en */
+	stw	r8, 0x4(r4)
+	sync
+
+	blr
+_GLOBAL(mpc52xx_ds_sram_size)
+mpc52xx_ds_sram_size:
+	.long $-mpc52xx_ds_sram
+
+
+/* ### interrupt handler for wakeup from deep-sleep ### */
+_GLOBAL(mpc52xx_ds_cached)
+mpc52xx_ds_cached:
+	mtspr	SPRN_SPRG0, r7
+	mtspr	SPRN_SPRG1, r8
+
+	/* disable emulated interrupt */
+	mfspr	r7, 311 /* MBAR */
+	addi	r7, r7, 0x540	/* intr->main_emul */
+	li	r8, 0
+	stw	r8, 0(r7)
+	sync
+	dcbf	0, r7
+
+	/* acknowledge wakeup, so CCS releases power pown */
+	mfspr	r7, 311	/* MBAR */
+	addi	r7, r7, 0x524	/* intr->enc_status */
+	lwz	r8, 0(r7)
+	ori	r8, r8, 0x0400
+	stw	r8, 0(r7)
+	sync
+	dcbf	0, r7
+
+	/* flag - we handled the interrupt */
+	li	r10, 1
+
+	mfspr	r8, SPRN_SPRG1
+	mfspr	r7, SPRN_SPRG0
+
+	rfi
+_GLOBAL(mpc52xx_ds_cached_size)
+mpc52xx_ds_cached_size:
+	.long $-mpc52xx_ds_cached
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
index 47d841e..de7fce9 100644
--- a/arch/powerpc/platforms/82xx/Kconfig
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -1,21 +1,36 @@
-menu "Platform support"
-       depends on PPC_82xx
-
 choice
-       prompt "Machine Type"
-       default MPC82xx_ADS
+	prompt "Machine Type"
+	depends on PPC_82xx
+	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
+	bool "Freescale MPC82xx ADS"
+	select DEFAULT_UIMAGE
+	select PQ2ADS
+	select 8272
+	select 8260
+	select FSL_SOC
+	help
+	This option enables support for the MPC8272 ADS board
 
 endchoice
 
-endmenu
+config PQ2ADS
+	bool
+	default n
+
+config 8260
+	bool
+	depends on 6xx
+	select CPM2
+	help
+	  The MPC8260 is a typical embedded CPU made by Freescale.  Selecting
+	  this option means that you wish to build a kernel for a machine with
+	  an 8260 class CPU.
+
+config 8272
+	bool
+	select 8260
+	help
+	  The MPC8272 CPM has a different internal dpram setup than other CPM2
+	  devices
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 74e7892..cc9900d 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -55,17 +55,17 @@ #include "pq2ads.h"
 static int __init get_freq(char *name, 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 = of_get_property(cpu, name, NULL);
 		if (fp) {
 			found = 1;
-			*val = *fp++;
+			*val = *fp;
 		}
 
 		of_node_put(cpu);
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 7334c1a..47cb09f 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -456,7 +456,7 @@ void m82xx_pci_init_irq(void)
 		iounmap(immap);
 		return;
 	}
-	irq_map = get_property(np, "interrupt-map", &size);
+	irq_map = of_get_property(np, "interrupt-map", &size);
 	if ((!irq_map) || (size <= 7)) {
 		printk(KERN_INFO "No interrupt-map property of pci node\n");
 		iounmap(immap);
@@ -481,7 +481,7 @@ void m82xx_pci_init_irq(void)
 	}
 	pci_pic_node = of_node_get(np);
 	/* PCI interrupt controller registers: status and mask */
-	regs = get_property(np, "reg", &size);
+	regs = of_get_property(np, "reg", &size);
 	if ((!regs) || (size <= 2)) {
 		printk(KERN_INFO "No reg property in pci pic node\n");
 		iounmap(immap);
@@ -521,20 +521,20 @@ void __init add_bridge(struct device_nod
 	struct pci_controller *hose;
 	struct resource r;
 	const int *bus_range;
-	const void *ptr;
+	const uint *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))) {
+	if (!(ptr = of_get_property(np, "clock-frequency", NULL))) {
 		printk(KERN_INFO "No clock-frequency property in PCI node");
 		return;
 	}
-	pci_clk_frq = *(uint *) ptr;
+	pci_clk_frq = *ptr;
 	of_node_put(np);
-	bus_range = get_property(np, "bus-range", &len);
+	bus_range = of_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);
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 713b31a..19cafdf 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
-	depends on PPC_83xx
-
 choice
 	prompt "Machine Type"
+	depends on PPC_83xx
 	default MPC834x_MDS
 
 config MPC8313_RDB
@@ -18,6 +16,13 @@ config MPC832x_MDS
 	help
 	  This option enables support for the MPC832x MDS evaluation board.
 
+config MPC832x_RDB
+	bool "Freescale MPC832x RDB"
+	select DEFAULT_UIMAGE
+	select QUICC_ENGINE
+	help
+	  This option enables support for the MPC8323 RDB board.
+
 config MPC834x_MDS
 	bool "Freescale MPC834x MDS"
 	select DEFAULT_UIMAGE
@@ -57,7 +62,7 @@ config PPC_MPC832x
 	bool
 	select PPC_UDBG_16550
 	select PPC_INDIRECT_PCI
-	default y if MPC832x_MDS
+	default y if MPC832x_MDS || MPC832x_RDB
 
 config MPC834x
 	bool
@@ -70,5 +75,3 @@ config PPC_MPC836x
 	select PPC_UDBG_16550
 	select PPC_INDIRECT_PCI
 	default y if MPC836x_MDS
-
-endmenu
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index dfc970d..31a91b5 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@ #
 obj-y				:= misc.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_MPC8313_RDB)	+= mpc8313_rdb.o
+obj-$(CONFIG_MPC832x_RDB)	+= mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)	+= mpc834x_mds.o
 obj-$(CONFIG_MPC834x_ITX)	+= mpc834x_itx.o
 obj-$(CONFIG_MPC836x_MDS)	+= mpc836x_mds.o
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 17e3a3c..94843ed 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -41,7 +41,6 @@ #include <asm/qe.h>
 #include <asm/qe_ic.h>
 
 #include "mpc83xx.h"
-#include "mpc832x_mds.h"
 
 #undef DEBUG
 #ifdef DEBUG
@@ -112,6 +111,7 @@ static struct of_device_id mpc832x_ids[]
 	{ .type = "soc", },
 	{ .compatible = "soc", },
 	{ .type = "qe", },
+	{ .type = "mdio", },
 	{},
 };
 
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
deleted file mode 100644
index a495889..0000000
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
new file mode 100644
index 0000000..b0b22bb
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -0,0 +1,139 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc832x_rdb.c
+ *
+ * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
+ *
+ * Description:
+ * MPC832x RDB board specific routines.
+ * This file is based on mpc832x_mds.c and mpc8313_rdb.c
+ * Author: Michael Barkowski <michael.barkowski@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/pci.h>
+
+#include <asm/of_platform.h>
+#include <asm/time.h>
+#include <asm/ipic.h>
+#include <asm/udbg.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
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc832x_rdb_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc832x_rdb_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+		add_bridge(np);
+
+	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);
+	}
+#endif				/* CONFIG_QUICC_ENGINE */
+}
+
+static struct of_device_id mpc832x_ids[] = {
+	{ .type = "soc", },
+	{ .compatible = "soc", },
+	{ .type = "qe", },
+	{ .type = "mdio", },
+	{},
+};
+
+static int __init mpc832x_declare_of_platform_devices(void)
+{
+	if (!machine_is(mpc832x_rdb))
+		return 0;
+
+	/* Publish the QE devices */
+	of_platform_bus_probe(NULL, mpc832x_ids, NULL);
+
+	return 0;
+}
+device_initcall(mpc832x_declare_of_platform_devices);
+
+void __init mpc832x_rdb_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 */
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc832x_rdb_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "MPC832xRDB");
+}
+
+define_machine(mpc832x_rdb) {
+	.name		= "MPC832x RDB",
+	.probe		= mpc832x_rdb_probe,
+	.setup_arch	= mpc832x_rdb_setup_arch,
+	.init_IRQ	= mpc832x_rdb_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/mpc834x_itx.h b/arch/powerpc/platforms/83xx/mpc834x_itx.h
deleted file mode 100644
index 174ca4e..0000000
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/powerpc/platforms/83xx/mpc834x_itx.h
- *
- * MPC834X ITX common board definitions
- *
- * Maintainer: Kumar Gala <galak@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.
- *
- */
-
-#ifndef __MACH_MPC83XX_ITX_H__
-#define __MACH_MPC83XX_ITX_H__
-
-#define PIRQA	MPC83xx_IRQ_EXT4
-#define PIRQB	MPC83xx_IRQ_EXT5
-#define PIRQC	MPC83xx_IRQ_EXT6
-#define PIRQD	MPC83xx_IRQ_EXT7
-
-#endif				/* __MACH_MPC83XX_ITX_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index 526ed09..bceeff8 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -118,6 +118,7 @@ static struct of_device_id mpc836x_ids[]
 	{ .type = "soc", },
 	{ .compatible = "soc", },
 	{ .type = "qe", },
+	{ .type = "mdio", },
 	{},
 };
 
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 9c36505..774457d 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -60,7 +60,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 = get_property(dev, "bus-range", &len);
+	bus_range = of_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 e764c0a..629926e 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
-	depends on PPC_85xx
-
 choice
 	prompt "Machine Type"
+	depends on PPC_85xx
 	default MPC8540_ADS
 
 config MPC8540_ADS
@@ -30,6 +28,12 @@ #	select QUICC_ENGINE
 	help
 	  This option enables support for the MPC85xx MDS board
 
+config MPC8544_DS
+	bool "Freescale MPC8544 DS"
+	select DEFAULT_UIMAGE
+	help
+	  This option enables support for the MPC8544 DS board
+
 endchoice
 
 config MPC8540
@@ -40,33 +44,15 @@ config MPC8540
 
 config MPC8560
 	bool
-	select PPC_INDIRECT_PCI
+	select CPM2
 	default y if MPC8560_ADS
 
 config MPC85xx
 	bool
 	select PPC_UDBG_16550
 	select PPC_INDIRECT_PCI
+	select PPC_INDIRECT_PCI_BE
+	select MPIC
 	select SERIAL_8250_SHARE_IRQ if SERIAL_8250
-	default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS
-
-config PPC_INDIRECT_PCI_BE
-	bool
-	depends on PPC_85xx
-	default y
-
-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
+	default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \
+		|| MPC85xx_MDS || MPC8544_DS
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 4e63917..4e02cbb 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -5,4 +5,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
+obj-$(CONFIG_MPC8544_DS)  += mpc8544_ds.o
 obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c
new file mode 100644
index 0000000..bec84ff
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c
@@ -0,0 +1,144 @@
+/*
+ * MPC8544 DS Board Setup
+ *
+ * Author Xianghua Xiao (x.xiao@freescale.com)
+ * Copyright 2007 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/mpc85xx.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/i8259.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+
+void __init mpc8544_ds_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");
+
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Failed to map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	/* Alloc mpic structure and per isu has 16 INT entries. */
+	mpic = mpic_alloc(np, r.start,
+			  MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			  16, 64, " OPENPIC     ");
+	BUG_ON(mpic == NULL);
+
+	/*
+	 * 48 Internal Interrupts
+	 */
+	mpic_assign_isu(mpic, 0, r.start + 0x10200);
+	mpic_assign_isu(mpic, 1, r.start + 0x10400);
+	mpic_assign_isu(mpic, 2, r.start + 0x10600);
+
+	/*
+	 * 16 External interrupts
+	 */
+	mpic_assign_isu(mpic, 3, r.start + 0x10000);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_PPC_I8259
+	/* Initialize the i8259 controller */
+	for_each_node_by_type(np, "interrupt-controller")
+	    if (of_device_is_compatible(np, "chrp,iic")) {
+		cascade_node = np;
+		break;
+	}
+
+	if (cascade_node == NULL) {
+		printk(KERN_DEBUG "Could not find i8259 PIC\n");
+		return;
+	}
+
+	cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+	if (cascade_irq == NO_IRQ) {
+		printk(KERN_ERR "Failed to map cascade interrupt\n");
+		return;
+	}
+
+	DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq);
+
+	i8259_init(cascade_node, 0);
+	of_node_put(cascade_node);
+
+	set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade);
+#endif	/* CONFIG_PPC_I8259 */
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc8544_ds_setup_arch(void)
+{
+	if (ppc_md.progress)
+		ppc_md.progress("mpc8544_ds_setup_arch()", 0);
+
+	printk("MPC8544 DS board from Freescale Semiconductor\n");
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc8544_ds_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "MPC8544DS");
+}
+
+define_machine(mpc8544_ds) {
+	.name			= "MPC8544 DS",
+	.probe			= mpc8544_ds_probe,
+	.setup_arch		= mpc8544_ds_setup_arch,
+	.init_IRQ		= mpc8544_ds_pic_init,
+	.get_irq		= mpic_get_irq,
+	.restart		= mpc85xx_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 8ed034a..5d27621 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -227,7 +227,7 @@ #endif
 	if (cpu != 0) {
 		const unsigned int *fp;
 
-		fp = get_property(cpu, "clock-frequency", NULL);
+		fp = of_get_property(cpu, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 4232686..1490eb3 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -197,7 +197,7 @@ #endif
 #ifdef CONFIG_PPC_I8259
 	/* Initialize the i8259 controller */
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "chrp,iic")) {
+		if (of_device_is_compatible(np, "chrp,iic")) {
 			cascade_node = np;
 			break;
 		}
@@ -237,7 +237,7 @@ #endif
 	if (cpu != 0) {
 		const unsigned int *fp;
 
-		fp = get_property(cpu, "clock-frequency", NULL);
+		fp = of_get_property(cpu, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 81144d2..e3dddbf 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -80,7 +80,7 @@ static void __init mpc85xx_mds_setup_arc
 	np = of_find_node_by_type(NULL, "cpu");
 	if (np != NULL) {
 		const unsigned int *fp =
-		    get_property(np, "clock-frequency", NULL);
+		    of_get_property(np, "clock-frequency", NULL);
 		if (fp != NULL)
 			loops_per_jiffy = *fp / HZ;
 		else
@@ -147,6 +147,7 @@ static struct of_device_id mpc85xx_ids[]
 	{ .type = "soc", },
 	{ .compatible = "soc", },
 	{ .type = "qe", },
+	{ .type = "mdio", },
 	{},
 };
 
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index 05930ee..48f17e2 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -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 = get_property(dev, "bus-range", &len);
+	bus_range = of_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/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 0c70944..d1bcff5 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform Support"
-	depends on PPC_86xx
-
 choice
 	prompt "Machine Type"
+	depends on PPC_86xx
 	default MPC8641_HPCN
 
 config MPC8641_HPCN
@@ -14,20 +12,10 @@ config MPC8641_HPCN
 
 endchoice
 
-
 config MPC8641
 	bool
 	select PPC_INDIRECT_PCI
+	select PPC_INDIRECT_PCI_BE
 	select PPC_UDBG_16550
+	select MPIC
 	default y if MPC8641_HPCN
-
-config MPIC
-	bool
-	default y
-
-config PPC_INDIRECT_PCI_BE
-	bool
-	depends on PPC_86xx
-	default y
-
-endmenu
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 476a6ee..418fd8f 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -4,4 +4,4 @@ #
 
 obj-$(CONFIG_SMP)		+= mpc86xx_smp.o
 obj-$(CONFIG_MPC8641_HPCN)	+= mpc86xx_hpcn.o
-obj-$(CONFIG_PCI)		+= pci.o mpc86xx_pcie.o
+obj-$(CONFIG_PCI)		+= pci.o
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index f42f801..9087756 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -102,7 +102,7 @@ #endif
 #ifdef CONFIG_PCI
 	/* Initialize i8259 controller */
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "chrp,iic")) {
+		if (of_device_is_compatible(np, "chrp,iic")) {
 			cascade_node = np;
 			break;
 		}
@@ -349,7 +349,7 @@ mpc86xx_hpcn_setup_arch(void)
 	if (np != 0) {
 		const unsigned int *fp;
 
-		fp = get_property(np, "clock-frequency", NULL);
+		fp = of_get_property(np, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
@@ -384,7 +384,7 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_fil
 
 	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "Machine\t\t: %s\n", model);
 	of_node_put(root);
 
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c b/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
deleted file mode 100644
index a2f4f73..0000000
--- a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Support for indirect PCI bridges.
- *
- * Copyright (C) 1998 Gabriel Paubert.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * "Temporary" MPC8548 Errata file -
- * The standard indirect_pci code should work with future silicon versions.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-#include "mpc86xx.h"
-
-#define PCI_CFG_OUT out_be32
-
-/* ERRATA PCI-Ex 14 PCIE Controller timeout */
-#define PCIE_FIX		out_be32(hose->cfg_addr+0x4, 0x0400ffff)
-
-
-static int
-indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
-		     int len, u32 *val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile void __iomem *cfg_data;
-	u32 temp;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/* Possible artifact of CDCpp50937 needs further investigation */
-	if (devfn != 0x0 && bus->number == 0xff)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	PCIE_FIX;
-	if (bus->number == 0xff) {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	} else {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	}
-
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
-	cfg_data = hose->cfg_data;
-	PCIE_FIX;
-	temp = in_le32(cfg_data);
-	switch (len) {
-	case 1:
-		*val = (temp >> (((offset & 3))*8)) & 0xff;
-		break;
-	case 2:
-		*val = (temp >> (((offset & 3))*8)) & 0xffff;
-		break;
-	default:
-		*val = temp;
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
-		      int len, u32 val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile void __iomem *cfg_data;
-	u32 temp;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-	/* Possible artifact of CDCpp50937 needs further investigation */
-	if (devfn != 0x0 && bus->number == 0xff)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	PCIE_FIX;
-	if (bus->number == 0xff) {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000000 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-	} else {
-		PCI_CFG_OUT(hose->cfg_addr,
-			    (0x80000001 | ((offset & 0xf00) << 16) |
-			     ((bus->number - hose->bus_offset) << 16)
-			     | (devfn << 8) | ((offset & 0xfc) )));
-        }
-
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
-	cfg_data = hose->cfg_data;
-	switch (len) {
-	case 1:
-		PCIE_FIX;
-		temp = in_le32(cfg_data);
-		temp = (temp & ~(0xff << ((offset & 3) * 8))) |
-			(val << ((offset & 3) * 8));
-		PCIE_FIX;
-		out_le32(cfg_data, temp);
-		break;
-	case 2:
-		PCIE_FIX;
-		temp = in_le32(cfg_data);
-		temp = (temp & ~(0xffff << ((offset & 3) * 8)));
-		temp |= (val << ((offset & 3) * 8)) ;
-		PCIE_FIX;
-		out_le32(cfg_data, temp);
-		break;
-	default:
-		PCIE_FIX;
-		out_le32(cfg_data, val);
-		break;
-	}
-	PCIE_FIX;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops indirect_pcie_ops = {
-	indirect_read_config_pcie,
-	indirect_write_config_pcie
-};
-
-void __init
-setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
-	void __iomem * cfg_data)
-{
-	hose->cfg_addr = cfg_addr;
-	hose->cfg_data = cfg_data;
-	hose->ops = &indirect_pcie_ops;
-}
-
-void __init
-setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
-{
-	unsigned long base = cfg_addr & PAGE_MASK;
-	void __iomem *mbase, *addr, *data;
-
-	mbase = ioremap(base, PAGE_SIZE);
-	addr = mbase + (cfg_addr & ~PAGE_MASK);
-	if ((cfg_data & PAGE_MASK) != base)
-		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
-	data = mbase + (cfg_data & ~PAGE_MASK);
-	setup_indirect_pcie_nomap(hose, addr, data);
-}
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 481e18e..8235c56 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -22,9 +22,9 @@ #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/prom.h>
-#include <asm/immap_86xx.h>
 #include <asm/pci-bridge.h>
 #include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pcie.h>
 
 #include "mpc86xx.h"
 
@@ -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 = get_property(dev, "bus-range", &len);
+	bus_range = of_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/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index beea683..39bb8c5 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,6 +1,3 @@
-menu "Platform support"
-        depends on PPC_8xx
-
 config FADS
 	bool
 
@@ -9,6 +6,7 @@ config CPM1
 
 choice
 	prompt "8xx Machine Type"
+	depends on PPC_8xx
 	depends on 8xx
 	default MPC885ADS
 
@@ -36,38 +34,36 @@ config MPC885ADS
 endchoice
 
 menu "Freescale Ethernet driver platform-specific options"
-        depends on (FS_ENET && MPC885ADS)
-
-        config MPC8xx_SECOND_ETH
-        bool "Second Ethernet channel"
-        depends on MPC885ADS
-        default y
-        help
-          This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
-          The latter will use SCC1, for 885ADS you can select it below.
-
-        choice
-                prompt "Second Ethernet channel"
-                depends on MPC8xx_SECOND_ETH
-                default MPC8xx_SECOND_ETH_FEC2
-
-                config MPC8xx_SECOND_ETH_FEC2
-                bool "FEC2"
-                depends on MPC885ADS
-                help
-                  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
-                  (often 2-nd UART) will not work if this is enabled.
-
-                config MPC8xx_SECOND_ETH_SCC3
-                bool "SCC3"
-                depends on MPC885ADS
-                help
-                  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
-                  (often 1-nd UART) will not work if this is enabled.
-
-        endchoice
+	depends on (FS_ENET && MPC885ADS)
 
-endmenu
+	config MPC8xx_SECOND_ETH
+	bool "Second Ethernet channel"
+	depends on MPC885ADS
+	default y
+	help
+	  This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+	  The latter will use SCC1, for 885ADS you can select it below.
+
+	choice
+		prompt "Second Ethernet channel"
+		depends on MPC8xx_SECOND_ETH
+		default MPC8xx_SECOND_ETH_FEC2
+
+		config MPC8xx_SECOND_ETH_FEC2
+		bool "FEC2"
+		depends on MPC885ADS
+		help
+		  Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+		  (often 2-nd UART) will not work if this is enabled.
+
+		config MPC8xx_SECOND_ETH_SCC3
+		bool "SCC3"
+		depends on MPC885ADS
+		help
+		  Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+		  (often 1-nd UART) will not work if this is enabled.
+
+	endchoice
 
 endmenu
 
@@ -98,7 +94,7 @@ config 8xx_CPU6
 	  require workarounds for Linux (and most other OSes to work).  If you
 	  get a BUG() very early in boot, this might fix the problem.  For
 	  more details read the document entitled "MPC860 Family Device Errata
-	  Reference" on Motorola's website.  This option also incurs a
+	  Reference" on Freescale's website.  This option also incurs a
 	  performance hit.
 
 	  If in doubt, say N here.
@@ -135,4 +131,3 @@ config UCODE_PATCH
 	depends on !NO_UCODE_PATCH
 
 endmenu
-
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 9ed7125..0901dba 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -85,17 +85,17 @@ init_internal_rtc(void)
 static int __init get_freq(char *name, 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 = of_get_property(cpu, name, NULL);
                 if (fp) {
                         found = 1;
-                        *val = *fp++;
+                        *val = *fp;
                 }
 
                 of_node_put(cpu);
@@ -262,7 +262,7 @@ void mpc8xx_show_cpuinfo(struct seq_file
 
 	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "Machine\t\t: %s\n", model);
 	of_node_put(root);
 
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
index b5d19dd..59bad2f 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads.h
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -37,7 +37,7 @@ #define MPC8xx_CPM_OFFSET	(0x9c0)
 #define CPM_MAP_ADDR		(get_immrbase() + MPC8xx_CPM_OFFSET)
 #define CPM_IRQ_OFFSET		16     // for compability with cpm_uart driver
 
-#define PCMCIA_MEM_ADDR		(uint)0xff020000)
+#define PCMCIA_MEM_ADDR		((uint)0xff020000)
 #define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
 
 /* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index ef52ce7..a35315a 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -247,7 +247,7 @@ void init_smc_ioports(struct fs_uart_pla
 	}
 }
 
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
 {
 	return 0;
 }
@@ -260,7 +260,7 @@ static void __init mpc86xads_setup_arch(
 	if (cpu != 0) {
 		const unsigned int *fp;
 
-		fp = get_property(cpu, "clock-frequency", NULL);
+		fp = of_get_property(cpu, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 30cbebf..7c31aec 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -37,7 +37,7 @@ #define MPC8xx_CPM_OFFSET	(0x9c0)
 #define CPM_MAP_ADDR		(get_immrbase() + MPC8xx_CPM_OFFSET)
 #define CPM_IRQ_OFFSET		16     // for compability with cpm_uart driver
 
-#define PCMCIA_MEM_ADDR		(uint)0xff020000)
+#define PCMCIA_MEM_ADDR		((uint)0xff020000)
 #define PCMCIA_MEM_SIZE		((uint)(64 * 1024))
 
 /* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index c5fefdf..a57b577 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -322,7 +322,7 @@ void init_smc_ioports(struct fs_uart_pla
 	}
 }
 
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
 {
 #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
 	const char *dev = "FEC";
@@ -346,7 +346,7 @@ static void __init mpc885ads_setup_arch(
 	if (cpu != 0) {
 		const unsigned int *fp;
 
-		fp = get_property(cpu, "clock-frequency", NULL);
+		fp = of_get_property(cpu, "clock-frequency", NULL);
 		if (fp != 0)
 			loops_per_jiffy = *fp / HZ;
 		else
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
new file mode 100644
index 0000000..361acfa
--- /dev/null
+++ b/arch/powerpc/platforms/Kconfig
@@ -0,0 +1,260 @@
+menu "Platform support"
+
+choice
+	prompt "Machine type"
+	depends on PPC64 || CLASSIC32
+	default PPC_MULTIPLATFORM
+
+config PPC_MULTIPLATFORM
+	bool "Generic desktop/server/laptop"
+	help
+	  Select this option if configuring for an IBM pSeries or
+	  RS/6000 machine, an Apple machine, or a PReP, CHRP,
+	  Maple or Cell-based machine.
+
+config EMBEDDED6xx
+	bool "Embedded 6xx/7xx/7xxx-based board"
+	depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
+
+config APUS
+	bool "Amiga-APUS"
+	depends on PPC32 && BROKEN
+	help
+	  Select APUS if configuring for a PowerUP Amiga.
+	  More information is available at:
+	  <http://linux-apus.sourceforge.net/>.
+endchoice
+
+source "arch/powerpc/platforms/pseries/Kconfig"
+source "arch/powerpc/platforms/iseries/Kconfig"
+source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/52xx/Kconfig"
+source "arch/powerpc/platforms/powermac/Kconfig"
+source "arch/powerpc/platforms/prep/Kconfig"
+source "arch/powerpc/platforms/maple/Kconfig"
+source "arch/powerpc/platforms/pasemi/Kconfig"
+source "arch/powerpc/platforms/celleb/Kconfig"
+source "arch/powerpc/platforms/ps3/Kconfig"
+source "arch/powerpc/platforms/cell/Kconfig"
+source "arch/powerpc/platforms/8xx/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"
+source "arch/powerpc/platforms/embedded6xx/Kconfig"
+source "arch/powerpc/platforms/44x/Kconfig"
+#source "arch/powerpc/platforms/4xx/Kconfig
+
+config PPC_NATIVE
+	bool
+	depends on PPC_MULTIPLATFORM
+	help
+	  Support for running natively on the hardware, i.e. without
+	  a hypervisor. This option is not user-selectable but should
+	  be selected by all platforms that need it.
+
+config UDBG_RTAS_CONSOLE
+	bool "RTAS based debug console"
+	depends on PPC_RTAS
+	default n
+
+config PPC_UDBG_BEAT
+	bool "BEAT based debug console"
+	depends on PPC_CELLEB
+	default n
+
+config XICS
+	depends on PPC_PSERIES
+	bool
+	default y
+
+config MPIC
+	bool
+	default n
+
+config MPIC_WEIRD
+	bool
+	default n
+
+config PPC_I8259
+	bool
+	default n
+
+config U3_DART
+	bool
+	depends on PPC_MULTIPLATFORM && PPC64
+	default n
+
+config PPC_RTAS
+	bool
+	default n
+
+config RTAS_ERROR_LOGGING
+	bool
+	depends on PPC_RTAS
+	default n
+
+config RTAS_PROC
+	bool "Proc interface to RTAS"
+	depends on PPC_RTAS
+	default y
+
+config RTAS_FLASH
+	tristate "Firmware flash interface"
+	depends on PPC64 && RTAS_PROC
+
+config PPC_PMI
+	tristate "Support for PMI"
+	depends PPC_IBM_CELL_BLADE
+	help
+	  PMI (Platform Management Interrupt) is a way to
+	  communicate with the BMC (Baseboard Mangement Controller).
+	  It is used in some IBM Cell blades.
+	default m
+
+config MMIO_NVRAM
+	bool
+	default n
+
+config MPIC_U3_HT_IRQS
+	bool
+	depends on PPC_MAPLE
+	default y
+
+config IBMVIO
+	depends on PPC_PSERIES || PPC_ISERIES
+	bool
+	default y
+
+config IBMEBUS
+	depends on PPC_PSERIES
+	bool "Support for GX bus based adapters"
+	help
+	  Bus device driver for GX bus based adapters.
+
+config PPC_MPC106
+	bool
+	default n
+
+config PPC_970_NAP
+	bool
+	default n
+
+config PPC_INDIRECT_IO
+	bool
+	select GENERIC_IOMAP
+	default n
+
+config GENERIC_IOMAP
+	bool
+	default n
+
+source "drivers/cpufreq/Kconfig"
+
+menu "CPU Frequency drivers"
+	depends on CPU_FREQ
+
+config CPU_FREQ_PMAC
+	bool "Support for Apple PowerBooks"
+	depends on ADB_PMU && PPC32
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for frequency switching on Apple PowerBooks,
+	  this currently includes some models of iBook & Titanium
+	  PowerBook.
+
+config CPU_FREQ_PMAC64
+	bool "Support for some Apple G5s"
+	depends on PPC_PMAC && PPC64
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for frequency switching on Apple iMac G5,
+	  and some of the more recent desktop G5 machines as well.
+
+config PPC_PASEMI_CPUFREQ
+	bool "Support for PA Semi PWRficient"
+	depends on PPC_PASEMI
+	default y
+	select CPU_FREQ_TABLE
+	help
+	  This adds the support for frequency switching on PA Semi
+	  PWRficient processors.
+
+endmenu
+
+config PPC601_SYNC_FIX
+	bool "Workarounds for PPC601 bugs"
+	depends on 6xx && (PPC_PREP || PPC_PMAC)
+	help
+	  Some versions of the PPC601 (the first PowerPC chip) have bugs which
+	  mean that extra synchronization instructions are required near
+	  certain instructions, typically those that make major changes to the
+	  CPU state.  These extra instructions reduce performance slightly.
+	  If you say N here, these extra instructions will not be included,
+	  resulting in a kernel which will run faster but may not run at all
+	  on some systems with the PPC601 chip.
+
+	  If in doubt, say Y here.
+
+config TAU
+	bool "On-chip CPU temperature sensor support"
+	depends on CLASSIC32
+	help
+	  G3 and G4 processors have an on-chip temperature sensor called the
+	  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
+	  temperature within 2-4 degrees Celsius. This option shows the current
+	  on-die temperature in /proc/cpuinfo if the cpu supports it.
+
+	  Unfortunately, on some chip revisions, this sensor is very inaccurate
+	  and in many cases, does not work at all, so don't assume the cpu
+	  temp is actually what /proc/cpuinfo says it is.
+
+config TAU_INT
+	bool "Interrupt driven TAU driver (DANGEROUS)"
+	depends on TAU
+	---help---
+	  The TAU supports an interrupt driven mode which causes an interrupt
+	  whenever the temperature goes out of range. This is the fastest way
+	  to get notified the temp has exceeded a range. With this option off,
+	  a timer is used to re-check the temperature periodically.
+
+	  However, on some cpus it appears that the TAU interrupt hardware
+	  is buggy and can cause a situation which would lead unexplained hard
+	  lockups.
+
+	  Unless you are extending the TAU driver, or enjoy kernel/hardware
+	  debugging, leave this option off.
+
+config TAU_AVERAGE
+	bool "Average high and low temp"
+	depends on TAU
+	---help---
+	  The TAU hardware can compare the temperature to an upper and lower
+	  bound.  The default behavior is to show both the upper and lower
+	  bound in /proc/cpuinfo. If the range is large, the temperature is
+	  either changing a lot, or the TAU hardware is broken (likely on some
+	  G4's). If the range is small (around 4 degrees), the temperature is
+	  relatively stable.  If you say Y here, a single temperature value,
+	  halfway between the upper and lower bounds, will be reported in
+	  /proc/cpuinfo.
+
+	  If in doubt, say N here.
+
+config QUICC_ENGINE
+	bool
+	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 CPM2
+	bool
+	default n
+	help
+	  The CPM2 (Communications Processor Module) is a coprocessor on
+	  embedded CPUs made by Freescale.  Selecting this option means that
+	  you wish to build a kernel for a machine with a CPM2 coprocessor
+	  on it (826x, 827x, 8560).
+
+endmenu
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 4520042..d6e041a 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -6,7 +6,8 @@ obj-$(CONFIG_PPC_PMAC)		+= powermac/
 endif
 endif
 obj-$(CONFIG_PPC_CHRP)		+= chrp/
-obj-$(CONFIG_4xx)		+= 4xx/
+#obj-$(CONFIG_4xx)		+= 4xx/
+obj-$(CONFIG_44x)		+= 44x/
 obj-$(CONFIG_PPC_MPC52xx)	+= 52xx/
 obj-$(CONFIG_PPC_8xx)		+= 8xx/
 obj-$(CONFIG_PPC_82xx)		+= 82xx/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 06a85b7..8255177 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -1,3 +1,26 @@
+config PPC_CELL
+	bool
+	default n
+
+config PPC_CELL_NATIVE
+	bool
+	select PPC_CELL
+	select PPC_DCR_MMIO
+	select PPC_OF_PLATFORM_PCI
+	select PPC_INDIRECT_IO
+	select PPC_NATIVE
+	select MPIC
+	default n
+
+config PPC_IBM_CELL_BLADE
+	bool "IBM Cell Blade"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_CELL_NATIVE
+	select PPC_RTAS
+	select MMIO_NVRAM
+	select PPC_UDBG_16550
+	select UDBG_RTAS_CONSOLE
+
 menu "Cell Broadband Engine options"
 	depends on PPC_CELL
 
@@ -18,6 +41,7 @@ config SPU_BASE
 
 config CBE_RAS
 	bool "RAS features for bare metal Cell BE"
+	depends on PPC_CELL_NATIVE
 	default y
 
 config CBE_THERM
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index a3850fd..f9ac3fe 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -25,9 +25,12 @@ #include <linux/timer.h>
 
 #include <asm/hw_irq.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
 #include <asm/processor.h>
 #include <asm/prom.h>
 #include <asm/time.h>
+#include <asm/pmi.h>
+#include <asm/of_platform.h>
 
 #include "cbe_regs.h"
 
@@ -68,6 +71,38 @@ static u64 MIC_Slow_Next_Timer_table[] =
  * hardware specific functions
  */
 
+static struct of_device *pmi_dev;
+
+static int set_pmode_pmi(int cpu, unsigned int pmode)
+{
+	int ret;
+	pmi_message_t pmi_msg;
+#ifdef DEBUG
+	u64 time;
+#endif
+
+	pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+	pmi_msg.data1 =	cbe_cpu_to_node(cpu);
+	pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+	time = (u64) get_cycles();
+#endif
+
+	pmi_send_message(pmi_dev, pmi_msg);
+	ret = pmi_msg.data2;
+
+	pr_debug("PMI returned slow mode %d\n", ret);
+
+#ifdef DEBUG
+	time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
+	time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
+	pr_debug("had to wait %lu ns for a transition\n", time);
+#endif
+	return ret;
+}
+
+
 static int get_pmode(int cpu)
 {
 	int ret;
@@ -79,7 +114,7 @@ static int get_pmode(int cpu)
 	return ret;
 }
 
-static int set_pmode(int cpu, unsigned int pmode)
+static int set_pmode_reg(int cpu, unsigned int pmode)
 {
 	struct cbe_pmd_regs __iomem *pmd_regs;
 	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,37 +155,71 @@ static int set_pmode(int cpu, unsigned i
 	return 0;
 }
 
+static int set_pmode(int cpu, unsigned int slow_mode) {
+	if (pmi_dev)
+		return set_pmode_pmi(cpu, slow_mode);
+	else
+		return set_pmode_reg(cpu, slow_mode);
+}
+
+static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
+{
+	struct cpufreq_policy policy;
+	u8 cpu;
+	u8 cbe_pmode_new;
+
+	BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+	cpu = cbe_node_to_cpu(pmi_msg.data1);
+	cbe_pmode_new = pmi_msg.data2;
+
+	cpufreq_get_policy(&policy, cpu);
+
+	policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
+	policy.min = min(policy.min, policy.max);
+
+	pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
+	cpufreq_set_policy(&policy);
+}
+
+static struct pmi_handler cbe_pmi_handler = {
+	.type			= PMI_TYPE_FREQ_CHANGE,
+	.handle_pmi_message	= cbe_cpufreq_handle_pmi,
+};
+
+
 /*
  * cpufreq functions
  */
 
-static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-	u32 *max_freq;
+	const u32 *max_freqp;
+	u32 max_freq;
 	int i, cur_pmode;
 	struct device_node *cpu;
 
 	cpu = of_get_cpu_node(policy->cpu, NULL);
 
-	if(!cpu)
+	if (!cpu)
 		return -ENODEV;
 
 	pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 
-	max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 
-	if(!max_freq)
+	if (!max_freqp)
 		return -EINVAL;
 
-	// we need the freq in kHz
-	*max_freq /= 1000;
+	/* we need the freq in kHz */
+	max_freq = *max_freqp / 1000;
 
-	pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+	pr_debug("max clock-frequency is at %u kHz\n", max_freq);
 	pr_debug("initializing frequency table\n");
 
-	// initialize frequency table
+	/* initialize frequency table */
 	for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
-		cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+		cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
 		pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
 	}
 
@@ -167,10 +236,10 @@ #ifdef CONFIG_SMP
 	policy->cpus = cpu_sibling_map[policy->cpu];
 #endif
 
-	cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+	cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 
 	/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
-	return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+	return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 }
 
 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -202,7 +271,7 @@ static int cbe_cpufreq_target(struct cpu
 	freqs.new = cbe_freqs[cbe_pmode_new].frequency;
 	freqs.cpu = policy->cpu;
 
-	mutex_lock (&cbe_switch_mutex);
+	mutex_lock(&cbe_switch_mutex);
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
 	pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
@@ -233,11 +302,26 @@ static struct cpufreq_driver cbe_cpufreq
 
 static int __init cbe_cpufreq_init(void)
 {
+	struct device_node *np;
+
+	if (!machine_is(cell))
+		return -ENODEV;
+
+	np = of_find_node_by_type(NULL, "ibm,pmi");
+
+	pmi_dev = of_find_device_by_node(np);
+
+	if (pmi_dev)
+		pmi_register_handler(pmi_dev, &cbe_pmi_handler);
+
 	return cpufreq_register_driver(&cbe_cpufreq_driver);
 }
 
 static void __exit cbe_cpufreq_exit(void)
 {
+	if (pmi_dev)
+		pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
+
 	cpufreq_unregister_driver(&cbe_cpufreq_driver);
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 9a0ee62..12c9674 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -14,6 +14,8 @@ #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/ptrace.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
 
 #include "cbe_regs.h"
 
@@ -27,6 +29,7 @@ #include "cbe_regs.h"
 static struct cbe_regs_map
 {
 	struct device_node *cpu_node;
+	struct device_node *be_node;
 	struct cbe_pmd_regs __iomem *pmd_regs;
 	struct cbe_iic_regs __iomem *iic_regs;
 	struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -37,30 +40,43 @@ static int cbe_regs_map_count;
 static struct cbe_thread_map
 {
 	struct device_node *cpu_node;
+	struct device_node *be_node;
 	struct cbe_regs_map *regs;
+	unsigned int thread_id;
+	unsigned int cbe_id;
 } cbe_thread_map[NR_CPUS];
 
+static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
+static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
+
 static struct cbe_regs_map *cbe_find_map(struct device_node *np)
 {
 	int i;
 	struct device_node *tmp_np;
 
-	if (strcasecmp(np->type, "spe") == 0) {
-		if (np->data == NULL) {
-			/* walk up path until cpu node was found */
-			tmp_np = np->parent;
-			while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
-				tmp_np = tmp_np->parent;
+	if (strcasecmp(np->type, "spe")) {
+		for (i = 0; i < cbe_regs_map_count; i++)
+			if (cbe_regs_maps[i].cpu_node == np ||
+			    cbe_regs_maps[i].be_node == np)
+				return &cbe_regs_maps[i];
+		return NULL;
+	}
 
-			np->data = cbe_find_map(tmp_np);
-		}
+	if (np->data)
 		return np->data;
-	}
 
-	for (i = 0; i < cbe_regs_map_count; i++)
-		if (cbe_regs_maps[i].cpu_node == np)
-			return &cbe_regs_maps[i];
-	return NULL;
+	/* walk up path until cpu or be node was found */
+	tmp_np = np;
+	do {
+		tmp_np = tmp_np->parent;
+		/* on a correct devicetree we wont get up to root */
+		BUG_ON(!tmp_np);
+	} while (strcasecmp(tmp_np->type, "cpu") &&
+		 strcasecmp(tmp_np->type, "be"));
+
+	np->data = cbe_find_map(tmp_np);
+
+	return np->data;
 }
 
 struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
@@ -130,38 +146,105 @@ struct cbe_mic_tm_regs __iomem *cbe_get_
 }
 EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
 
-/* FIXME
- * This is little more than a stub at the moment.  It should be
- * fleshed out so that it works for both SMT and non-SMT, no
- * matter if the passed cpu is odd or even.
- * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
- * For SMT disabled, returns 0 for all cpus.
- */
 u32 cbe_get_hw_thread_id(int cpu)
 {
-	return (cpu & 1);
+	return cbe_thread_map[cpu].thread_id;
 }
 EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
 
-void __init cbe_regs_init(void)
+u32 cbe_cpu_to_node(int cpu)
 {
-	int i;
-	struct device_node *cpu;
+	return cbe_thread_map[cpu].cbe_id;
+}
+EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
 
-	/* Build local fast map of CPUs */
-	for_each_possible_cpu(i)
-		cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
+u32 cbe_node_to_cpu(int node)
+{
+	return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
+}
+EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
 
-	/* Find maps for each device tree CPU */
-	for_each_node_by_type(cpu, "cpu") {
-		struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+static struct device_node *cbe_get_be_node(int cpu_id)
+{
+	struct device_node *np;
+
+	for_each_node_by_type (np, "be") {
+		int len,i;
+		const phandle *cpu_handle;
+
+		cpu_handle = of_get_property(np, "cpus", &len);
+
+		for (i=0; i<len; i++)
+			if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
+				return np;
+	}
+
+	return NULL;
+}
+
+void __init cbe_fill_regs_map(struct cbe_regs_map *map)
+{
+	if(map->be_node) {
+		struct device_node *be, *np;
+
+		be = map->be_node;
+
+		for_each_node_by_type(np, "pervasive")
+			if (of_get_parent(np) == be)
+				map->pmd_regs = of_iomap(np, 0);
+
+		for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller")
+			if (of_get_parent(np) == be)
+				map->iic_regs = of_iomap(np, 2);
 
+		for_each_node_by_type(np, "mic-tm")
+			if (of_get_parent(np) == be)
+				map->mic_tm_regs = of_iomap(np, 0);
+	} else {
+		struct device_node *cpu;
 		/* That hack must die die die ! */
 		const struct address_prop {
 			unsigned long address;
 			unsigned int len;
 		} __attribute__((packed)) *prop;
 
+		cpu = map->cpu_node;
+
+		prop = of_get_property(cpu, "pervasive", NULL);
+		if (prop != NULL)
+			map->pmd_regs = ioremap(prop->address, prop->len);
+
+		prop = of_get_property(cpu, "iic", NULL);
+		if (prop != NULL)
+			map->iic_regs = ioremap(prop->address, prop->len);
+
+		prop = of_get_property(cpu, "mic-tm", NULL);
+		if (prop != NULL)
+			map->mic_tm_regs = ioremap(prop->address, prop->len);
+	}
+}
+
+
+void __init cbe_regs_init(void)
+{
+	int i;
+	unsigned int thread_id;
+	struct device_node *cpu;
+
+	/* Build local fast map of CPUs */
+	for_each_possible_cpu(i) {
+		cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
+		cbe_thread_map[i].be_node = cbe_get_be_node(i);
+		cbe_thread_map[i].thread_id = thread_id;
+	}
+
+	/* Find maps for each device tree CPU */
+	for_each_node_by_type(cpu, "cpu") {
+		struct cbe_regs_map *map;
+		unsigned int cbe_id;
+
+		cbe_id = cbe_regs_map_count++;
+		map = &cbe_regs_maps[cbe_id];
 
 		if (cbe_regs_map_count > MAX_CBE) {
 			printk(KERN_ERR "cbe_regs: More BE chips than supported"
@@ -170,22 +253,21 @@ void __init cbe_regs_init(void)
 			return;
 		}
 		map->cpu_node = cpu;
-		for_each_possible_cpu(i)
-			if (cbe_thread_map[i].cpu_node == cpu)
-				cbe_thread_map[i].regs = map;
 
-		prop = get_property(cpu, "pervasive", NULL);
-		if (prop != NULL)
-			map->pmd_regs = ioremap(prop->address, prop->len);
+		for_each_possible_cpu(i) {
+			struct cbe_thread_map *thread = &cbe_thread_map[i];
 
-		prop = get_property(cpu, "iic", NULL);
-		if (prop != NULL)
-			map->iic_regs = ioremap(prop->address, prop->len);
+			if (thread->cpu_node == cpu) {
+				thread->regs = map;
+				thread->cbe_id = cbe_id;
+				map->be_node = thread->be_node;
+				cpu_set(i, cbe_local_mask[cbe_id]);
+				if(thread->thread_id == 0)
+					cpu_set(i, cbe_first_online_cpu);
+			}
+		}
 
-		prop = (struct address_prop *)get_property(cpu, "mic-tm",
-							   NULL);
-		if (prop != NULL)
-			map->mic_tm_regs = ioremap(prop->address, prop->len);
+		cbe_fill_regs_map(map);
 	}
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
index 440a7ec..17d5971 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.h
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -255,6 +255,11 @@ #define CBE_MIC_DISABLE_PWR_SAV_1	0x8000
 extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
 extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
 
+/* some utility functions to deal with SMT */
+extern u32 cbe_get_hw_thread_id(int cpu);
+extern u32 cbe_cpu_to_node(int cpu);
+extern u32 cbe_node_to_cpu(int node);
+
 /* Init this module early */
 extern void cbe_regs_init(void);
 
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index 70e0d96..f370f0f 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -1,6 +1,31 @@
 /*
  * thermal support for the cell processor
  *
+ * This module adds some sysfs attributes to cpu and spu nodes.
+ * Base for measurements are the digital thermal sensors (DTS)
+ * located on the chip.
+ * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
+ * The attributes can be found under
+ * /sys/devices/system/cpu/cpuX/thermal
+ * /sys/devices/system/spu/spuX/thermal
+ *
+ * The following attributes are added for each node:
+ * temperature:
+ *	contains the current temperature measured by the DTS
+ * throttle_begin:
+ *	throttling begins when temperature is greater or equal to
+ *	throttle_begin. Setting this value to 125 prevents throttling.
+ * throttle_end:
+ *	throttling is being ceased, if the temperature is lower than
+ *	throttle_end. Due to a delay between applying throttling and
+ *	a reduced temperature this value should be less than throttle_begin.
+ *	A value equal to throttle_begin provides only a very little hysteresis.
+ * throttle_full_stop:
+ *	If the temperatrue is greater or equal to throttle_full_stop,
+ *	full throttling is applied to the cpu or spu. This value should be
+ *	greater than throttle_begin and throttle_end. Setting this value to
+ *	65 prevents the unit from running code at all.
+ *
  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
  *
  * Author: Christian Krafft <krafft@de.ibm.com>
@@ -31,6 +56,26 @@ #include <asm/prom.h>
 #include "cbe_regs.h"
 #include "spu_priv1_mmio.h"
 
+#define TEMP_MIN 65
+#define TEMP_MAX 125
+
+#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode)			\
+struct sysdev_attribute attr_ ## _prefix ## _ ## _name = {	\
+	.attr = { .name = __stringify(_name), .mode = _mode },	\
+	.show	= _prefix ## _show_ ## _name,			\
+	.store	= _prefix ## _store_ ## _name,			\
+};
+
+static inline u8 reg_to_temp(u8 reg_value)
+{
+	return ((reg_value & 0x3f) << 1) + TEMP_MIN;
+}
+
+static inline u8 temp_to_reg(u8 temp)
+{
+	return ((temp - TEMP_MIN) >> 1) & 0x3f;
+}
+
 static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
 {
 	struct spu *spu;
@@ -43,14 +88,14 @@ static struct cbe_pmd_regs __iomem *get_
 /* returns the value for a given spu in a given register */
 static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
 {
-	unsigned int *id;
+	const unsigned int *id;
 	union spe_reg value;
 	struct spu *spu;
 
 	/* getting the id from the reg attribute will not work on future device-tree layouts
 	 * in future we should store the id to the spu struct and use it here */
 	spu = container_of(sysdev, struct spu, sysdev);
-	id = (unsigned int *)get_property(spu_devnode(spu), "reg", NULL);
+	id = of_get_property(spu_devnode(spu), "reg", NULL);
 	value.val = in_be64(&reg->val);
 
 	return value.spe[*id];
@@ -58,20 +103,81 @@ static u8 spu_read_register_value(struct
 
 static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
 {
-	int value;
+	u8 value;
 	struct cbe_pmd_regs __iomem *pmd_regs;
 
 	pmd_regs = get_pmd_regs(sysdev);
 
 	value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
-	/* clear all other bits */
+
+	return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
+{
+	u64 value;
+
+	value = in_be64(&pmd_regs->tm_tpr.val);
+	/* access the corresponding byte */
+	value >>= pos;
 	value &= 0x3F;
-	/* temp is stored in steps of 2 degrees */
-	value *= 2;
-	/* base temp is 65 degrees */
-	value += 65;
 
-	return sprintf(buf, "%d\n", (int) value);
+	return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
+{
+	u64 reg_value;
+	int temp;
+	u64 new_value;
+	int ret;
+
+	ret = sscanf(buf, "%u", &temp);
+
+	if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
+		return -EINVAL;
+
+	new_value = temp_to_reg(temp);
+
+	reg_value = in_be64(&pmd_regs->tm_tpr.val);
+
+	/* zero out bits for new value */
+	reg_value &= ~(0xffull << pos);
+	/* set bits to new value */
+	reg_value |= new_value << pos;
+
+	out_be64(&pmd_regs->tm_tpr.val, reg_value);
+	return size;
+}
+
+static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(get_pmd_regs(sysdev), buf, 0);
+}
+
+static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(get_pmd_regs(sysdev), buf, 8);
+}
+
+static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(get_pmd_regs(sysdev), buf, 16);
+}
+
+static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(get_pmd_regs(sysdev), buf, size, 0);
+}
+
+static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(get_pmd_regs(sysdev), buf, size, 8);
+}
+
+static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(get_pmd_regs(sysdev), buf, size, 16);
 }
 
 static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
@@ -82,16 +188,9 @@ static ssize_t ppe_show_temp(struct sys_
 	pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
 	value = in_be64(&pmd_regs->ts_ctsr2);
 
-	/* access the corresponding byte */
-	value >>= pos;
-	/* clear all other bits */
-	value &= 0x3F;
-	/* temp is stored in steps of 2 degrees */
-	value *= 2;
-	/* base temp is 65 degrees */
-	value += 65;
+	value = (value >> pos) & 0x3f;
 
-	return sprintf(buf, "%d\n", (int) value);
+	return sprintf(buf, "%d\n", reg_to_temp(value));
 }
 
 
@@ -108,13 +207,52 @@ static ssize_t ppe_show_temp1(struct sys
 	return ppe_show_temp(sysdev, buf, 0);
 }
 
+static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32);
+}
+
+static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40);
+}
+
+static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+	return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48);
+}
+
+static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32);
+}
+
+static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40);
+}
+
+static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+	return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48);
+}
+
+
 static struct sysdev_attribute attr_spu_temperature = {
 	.attr = {.name = "temperature", .mode = 0400 },
 	.show = spu_show_temp,
 };
 
+static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600);
+
+
 static struct attribute *spu_attributes[] = {
 	&attr_spu_temperature.attr,
+	&attr_spu_throttle_end.attr,
+	&attr_spu_throttle_begin.attr,
+	&attr_spu_throttle_full_stop.attr,
 	NULL,
 };
 
@@ -133,9 +271,16 @@ static struct sysdev_attribute attr_ppe_
 	.show = ppe_show_temp1,
 };
 
+static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
+
 static struct attribute *ppe_attributes[] = {
 	&attr_ppe_temperature0.attr,
 	&attr_ppe_temperature1.attr,
+	&attr_ppe_throttle_end.attr,
+	&attr_ppe_throttle_begin.attr,
+	&attr_ppe_throttle_full_stop.attr,
 	NULL,
 };
 
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6666d03..47264e7 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -227,7 +227,7 @@ #endif /* CONFIG_SMP */
 
 static int iic_host_match(struct irq_host *h, struct device_node *node)
 {
-	return device_is_compatible(node,
+	return of_device_is_compatible(node,
 				    "IBM,CBEA-Internal-Interrupt-Controller");
 }
 
@@ -256,12 +256,12 @@ static int iic_host_xlate(struct irq_hos
 	unsigned int node, ext, unit, class;
 	const u32 *val;
 
-	if (!device_is_compatible(ct,
+	if (!of_device_is_compatible(ct,
 				     "IBM,CBEA-Internal-Interrupt-Controller"))
 		return -ENODEV;
 	if (intsize != 1)
 		return -ENODEV;
-	val = get_property(ct, "#interrupt-cells", NULL);
+	val = of_get_property(ct, "#interrupt-cells", NULL);
 	if (val == NULL || *val != 1)
 		return -ENODEV;
 
@@ -324,10 +324,10 @@ static int __init setup_iic(void)
 
 	for (dn = NULL;
 	     (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
-		if (!device_is_compatible(dn,
+		if (!of_device_is_compatible(dn,
 				     "IBM,CBEA-Internal-Interrupt-Controller"))
 			continue;
-		np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
+		np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL);
 		if (np == NULL) {
 			printk(KERN_WARNING "IIC: CPU association not found\n");
 			of_node_put(dn);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 7c73128..d68d920 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -318,7 +318,7 @@ static int __init spider_pci_workaround_
 	 */
 	list_for_each_entry(phb, &hose_list, list_node) {
 		struct device_node *np = phb->arch_data;
-		const char *model = get_property(np, "model", NULL);
+		const char *model = of_get_property(np, "model", NULL);
 
 		/* If no model property or name isn't exactly "pci", skip */
 		if (model == NULL || strcmp(np->name, "pci"))
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 67d617b..760caa7 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -291,9 +291,9 @@ static int cell_iommu_find_ioc(int nid, 
 		const unsigned int *nidp;
 		const unsigned long *tmp;
 
-		nidp = get_property(np, "node-id", NULL);
+		nidp = of_get_property(np, "node-id", NULL);
 		if (nidp && *nidp == nid) {
-			tmp = get_property(np, "ioc-translation", NULL);
+			tmp = of_get_property(np, "ioc-translation", NULL);
 			if (tmp) {
 				*base = *tmp;
 				of_node_put(np);
@@ -430,7 +430,7 @@ cell_iommu_setup_window(struct cbe_iommu
 	struct iommu_window *window;
 	const unsigned int *ioid;
 
-	ioid = get_property(np, "ioid", NULL);
+	ioid = of_get_property(np, "ioid", NULL);
 	if (ioid == NULL)
 		printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
 		       np->full_name);
@@ -496,7 +496,7 @@ static void cell_dma_dev_setup(struct de
 	struct dev_archdata *archdata = &dev->archdata;
 
 	/* If we run without iommu, no need to do anything */
-	if (pci_dma_ops == &dma_direct_ops)
+	if (get_pci_dma_ops() == &dma_direct_ops)
 		return;
 
 	/* Current implementation uses the first window available in that
@@ -530,7 +530,7 @@ static int cell_of_bus_notify(struct not
 		return 0;
 
 	/* We use the PCI DMA ops */
-	dev->archdata.dma_ops = pci_dma_ops;
+	dev->archdata.dma_ops = get_pci_dma_ops();
 
 	cell_dma_dev_setup(dev);
 
@@ -549,7 +549,7 @@ static int __init cell_iommu_get_window(
 	unsigned long index;
 
 	/* Use ibm,dma-window if available, else, hard code ! */
-	dma_window = get_property(np, "ibm,dma-window", NULL);
+	dma_window = of_get_property(np, "ibm,dma-window", NULL);
 	if (dma_window == NULL) {
 		*base = 0;
 		*size = 0x80000000u;
@@ -646,7 +646,7 @@ static int __init cell_iommu_init_disabl
 	unsigned long base = 0, size;
 
 	/* When no iommu is present, we use direct DMA ops */
-	pci_dma_ops = &dma_direct_ops;
+	set_pci_dma_ops(&dma_direct_ops);
 
 	/* First make sure all IOC translation is turned off */
 	cell_disable_iommus();
@@ -734,7 +734,7 @@ static int __init cell_iommu_init(void)
 	}
 
 	/* Setup default PCI iommu ops */
-	pci_dma_ops = &dma_iommu_ops;
+	set_pci_dma_ops(&dma_iommu_ops);
 
  bail:
 	/* Register callbacks on OF platform device addition/removal
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 0984c70..3961a08 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -3,11 +3,13 @@ #define DEBUG
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
+#include <linux/reboot.h>
 
 #include <asm/reg.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
+#include <asm/rtas.h>
 
 #include "ras.h"
 #include "cbe_regs.h"
@@ -82,6 +84,164 @@ static int cbe_machine_check_handler(str
 	return 0;
 }
 
+struct ptcal_area {
+	struct list_head list;
+	int nid;
+	int order;
+	struct page *pages;
+};
+
+static LIST_HEAD(ptcal_list);
+
+static int ptcal_start_tok, ptcal_stop_tok;
+
+static int __init cbe_ptcal_enable_on_node(int nid, int order)
+{
+	struct ptcal_area *area;
+	int ret = -ENOMEM;
+	unsigned long addr;
+
+#ifdef CONFIG_CRASH_DUMP
+	rtas_call(ptcal_stop_tok, 1, 1, NULL, nid);
+#endif
+
+	area = kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area)
+		goto out_err;
+
+	area->nid = nid;
+	area->order = order;
+	area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order);
+
+	if (!area->pages)
+		goto out_free_area;
+
+	addr = __pa(page_address(area->pages));
+
+	ret = -EIO;
+	if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid,
+				(unsigned int)(addr >> 32),
+				(unsigned int)(addr & 0xffffffff))) {
+		printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n",
+				__FUNCTION__, nid);
+		goto out_free_pages;
+	}
+
+	list_add(&area->list, &ptcal_list);
+
+	return 0;
+
+out_free_pages:
+	__free_pages(area->pages, area->order);
+out_free_area:
+	kfree(area);
+out_err:
+	return ret;
+}
+
+static int __init cbe_ptcal_enable(void)
+{
+	const u32 *size;
+	struct device_node *np;
+	int order, found_mic = 0;
+
+	np = of_find_node_by_path("/rtas");
+	if (!np)
+		return -ENODEV;
+
+	size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
+	if (!size)
+		return -ENODEV;
+
+	pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size);
+	order = get_order(*size);
+	of_node_put(np);
+
+	/* support for malta device trees, with be@/mic@ nodes */
+	for_each_node_by_type(np, "mic-tm") {
+		cbe_ptcal_enable_on_node(of_node_to_nid(np), order);
+		found_mic = 1;
+	}
+
+	if (found_mic)
+		return 0;
+
+	/* support for older device tree - use cpu nodes */
+	for_each_node_by_type(np, "cpu") {
+		const u32 *nid = of_get_property(np, "node-id", NULL);
+		if (!nid) {
+			printk(KERN_ERR "%s: node %s is missing node-id?\n",
+					__FUNCTION__, np->full_name);
+			continue;
+		}
+		cbe_ptcal_enable_on_node(*nid, order);
+		found_mic = 1;
+	}
+
+	return found_mic ? 0 : -ENODEV;
+}
+
+static int cbe_ptcal_disable(void)
+{
+	struct ptcal_area *area, *tmp;
+	int ret = 0;
+
+	pr_debug("%s: disabling PTCAL\n", __FUNCTION__);
+
+	list_for_each_entry_safe(area, tmp, &ptcal_list, list) {
+		/* disable ptcal on this node */
+		if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) {
+			printk(KERN_ERR "%s: error disabling PTCAL "
+					"on node %d!\n", __FUNCTION__,
+					area->nid);
+			ret = -EIO;
+			continue;
+		}
+
+		/* ensure we can access the PTCAL area */
+		memset(page_address(area->pages), 0,
+				1 << (area->order + PAGE_SHIFT));
+
+		/* clean up */
+		list_del(&area->list);
+		__free_pages(area->pages, area->order);
+		kfree(area);
+	}
+
+	return ret;
+}
+
+static int cbe_ptcal_notify_reboot(struct notifier_block *nb,
+		unsigned long code, void *data)
+{
+	return cbe_ptcal_disable();
+}
+
+static struct notifier_block cbe_ptcal_reboot_notifier = {
+	.notifier_call = cbe_ptcal_notify_reboot
+};
+
+int __init cbe_ptcal_init(void)
+{
+	int ret;
+	ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
+	ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
+
+	if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
+			|| ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)
+		return -ENODEV;
+
+	ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier);
+	if (ret) {
+		printk(KERN_ERR "Can't disable PTCAL, so not enabling\n");
+		return ret;
+	}
+
+	return cbe_ptcal_enable();
+}
+
+arch_initcall(cbe_ptcal_init);
+
 void __init cbe_ras_init(void)
 {
 	unsigned long hid0;
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 36989c2..db66542 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -71,7 +71,7 @@ static void cell_show_cpuinfo(struct seq
 
 	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "machine\t\t: CHRP %s\n", model);
 	of_node_put(root);
 }
@@ -112,7 +112,7 @@ static void __init mpic_init_IRQ(void)
 
 	for (dn = NULL;
 	     (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
-		if (!device_is_compatible(dn, "CBEA,platform-open-pic"))
+		if (!of_device_is_compatible(dn, "CBEA,platform-open-pic"))
 			continue;
 
 		/* The MPIC driver will get everything it needs from the
@@ -190,15 +190,6 @@ static int __init cell_probe(void)
 	return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int cell_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 define_machine(cell) {
 	.name			= "Cell",
 	.probe			= cell_probe,
@@ -211,7 +202,6 @@ define_machine(cell) {
 	.get_rtc_time		= rtas_get_rtc_time,
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport	= cell_check_legacy_ioport,
 	.progress		= cell_progress,
 	.init_IRQ       	= cell_init_irq,
 	.pci_setup_phb		= rtas_setup_phb,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 21a9ebd..05f4b3d 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -254,25 +254,25 @@ static unsigned int __init spider_find_c
 	}
 
 	/* Now do the horrible hacks */
-	tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
+	tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL);
 	if (tmp == NULL)
 		return NO_IRQ;
 	intsize = *tmp;
-	imap = get_property(pic->of_node, "interrupt-map", &imaplen);
+	imap = of_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 = get_property(iic, "#interrupt-cells", NULL);
+	tmp = of_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 = get_property(iic, "ibm,interrupt-server-ranges", NULL);
+	tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL);
 	if (tmp == NULL) {
 		of_node_put(iic);
 		return NO_IRQ;
@@ -358,12 +358,12 @@ void __init spider_init_IRQ(void)
 	 */
 	for (dn = NULL;
 	     (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
-		if (device_is_compatible(dn, "CBEA,platform-spider-pic")) {
+		if (of_device_is_compatible(dn, "CBEA,platform-spider-pic")) {
 			if (of_address_to_resource(dn, 0, &r)) {
 				printk(KERN_WARNING "spider-pic: Failed\n");
 				continue;
 			}
-		} else if (device_is_compatible(dn, "sti,platform-spider-pic")
+		} else if (of_device_is_compatible(dn, "sti,platform-spider-pic")
 			   && (chip < 2)) {
 			static long hard_coded_pics[] =
 				{ 0x24000008000ul, 0x34000008000ul};
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index eba7a26..fec5152 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -36,12 +36,14 @@ #include <asm/spu_priv1.h>
 #include <asm/xmon.h>
 
 const struct spu_management_ops *spu_management_ops;
+EXPORT_SYMBOL_GPL(spu_management_ops);
+
 const struct spu_priv1_ops *spu_priv1_ops;
 
 static struct list_head spu_list[MAX_NUMNODES];
 static LIST_HEAD(spu_full_list);
 static DEFINE_MUTEX(spu_mutex);
-static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(spu_list_lock);
 
 EXPORT_SYMBOL_GPL(spu_priv1_ops);
 
@@ -290,7 +292,6 @@ spu_irq_class_1(int irq, void *data)
 
 	return stat ? IRQ_HANDLED : IRQ_NONE;
 }
-EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
 
 static irqreturn_t
 spu_irq_class_2(int irq, void *data)
@@ -431,10 +432,11 @@ struct spu *spu_alloc_node(int node)
 		spu = list_entry(spu_list[node].next, struct spu, list);
 		list_del_init(&spu->list);
 		pr_debug("Got SPU %d %d\n", 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);
@@ -461,108 +463,6 @@ void spu_free(struct spu *spu)
 }
 EXPORT_SYMBOL_GPL(spu_free);
 
-static int spu_handle_mm_fault(struct spu *spu)
-{
-	struct mm_struct *mm = spu->mm;
-	struct vm_area_struct *vma;
-	u64 ea, dsisr, is_write;
-	int ret;
-
-	ea = spu->dar;
-	dsisr = spu->dsisr;
-#if 0
-	if (!IS_VALID_EA(ea)) {
-		return -EFAULT;
-	}
-#endif /* XXX */
-	if (mm == NULL) {
-		return -EFAULT;
-	}
-	if (mm->pgd == NULL) {
-		return -EFAULT;
-	}
-
-	down_read(&mm->mmap_sem);
-	vma = find_vma(mm, ea);
-	if (!vma)
-		goto bad_area;
-	if (vma->vm_start <= ea)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-#if 0
-	if (expand_stack(vma, ea))
-		goto bad_area;
-#endif /* XXX */
-good_area:
-	is_write = dsisr & MFC_DSISR_ACCESS_PUT;
-	if (is_write) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		if (dsisr & MFC_DSISR_ACCESS_DENIED)
-			goto bad_area;
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-			goto bad_area;
-	}
-	ret = 0;
-	switch (handle_mm_fault(mm, vma, ea, is_write)) {
-	case VM_FAULT_MINOR:
-		current->min_flt++;
-		break;
-	case VM_FAULT_MAJOR:
-		current->maj_flt++;
-		break;
-	case VM_FAULT_SIGBUS:
-		ret = -EFAULT;
-		goto bad_area;
-	case VM_FAULT_OOM:
-		ret = -ENOMEM;
-		goto bad_area;
-	default:
-		BUG();
-	}
-	up_read(&mm->mmap_sem);
-	return ret;
-
-bad_area:
-	up_read(&mm->mmap_sem);
-	return -EFAULT;
-}
-
-int spu_irq_class_1_bottom(struct spu *spu)
-{
-	u64 ea, dsisr, access, error = 0UL;
-	int ret = 0;
-
-	ea = spu->dar;
-	dsisr = spu->dsisr;
-	if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
-		u64 flags;
-
-		access = (_PAGE_PRESENT | _PAGE_USER);
-		access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
-		local_irq_save(flags);
-		if (hash_page(ea, access, 0x300) != 0)
-			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
-		local_irq_restore(flags);
-	}
-	if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
-		if ((ret = spu_handle_mm_fault(spu)) != 0)
-			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
-		else
-			error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
-	}
-	spu->dar = 0UL;
-	spu->dsisr = 0UL;
-	if (!error) {
-		spu_restart_dma(spu);
-	} else {
-		spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE);
-	}
-	return ret;
-}
-
 struct sysdev_class spu_sysdev_class = {
 	set_kset_name("spu")
 };
@@ -636,12 +536,6 @@ static int spu_create_sysdev(struct spu 
 	return 0;
 }
 
-static void spu_destroy_sysdev(struct spu *spu)
-{
-	sysfs_remove_device_from_node(&spu->sysdev, spu->node);
-	sysdev_unregister(&spu->sysdev);
-}
-
 static int __init create_spu(void *data)
 {
 	struct spu *spu;
@@ -693,58 +587,37 @@ out:
 	return ret;
 }
 
-static void destroy_spu(struct spu *spu)
-{
-	list_del_init(&spu->list);
-	list_del_init(&spu->full_list);
-
-	spu_destroy_sysdev(spu);
-	spu_free_irqs(spu);
-	spu_destroy_spu(spu);
-	kfree(spu);
-}
-
-static void cleanup_spu_base(void)
-{
-	struct spu *spu, *tmp;
-	int node;
-
-	mutex_lock(&spu_mutex);
-	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);
-}
-module_exit(cleanup_spu_base);
-
 static int __init init_spu_base(void)
 {
-	int i, ret;
+	int i, ret = 0;
+
+	for (i = 0; i < MAX_NUMNODES; i++)
+		INIT_LIST_HEAD(&spu_list[i]);
 
 	if (!spu_management_ops)
-		return 0;
+		goto out;
 
 	/* 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]);
+		goto out;
 
 	ret = spu_enumerate_spus(create_spu);
 
 	if (ret) {
 		printk(KERN_WARNING "%s: Error initializing spus\n",
 			__FUNCTION__);
-		cleanup_spu_base();
-		return ret;
+		goto out_unregister_sysdev_class;
 	}
 
 	xmon_register_spus(&spu_full_list);
 
+	return 0;
+
+ out_unregister_sysdev_class:
+	sysdev_class_unregister(&spu_sysdev_class);
+ out:
+
 	return ret;
 }
 module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c
index 6915b41..4fd37ff 100644
--- a/arch/powerpc/platforms/cell/spu_coredump.c
+++ b/arch/powerpc/platforms/cell/spu_coredump.c
@@ -26,19 +26,18 @@ #include <linux/syscalls.h>
 
 #include <asm/spu.h>
 
-static struct spu_coredump_calls spu_coredump_calls;
+static struct spu_coredump_calls *spu_coredump_calls;
 static DEFINE_MUTEX(spu_coredump_mutex);
 
 int arch_notes_size(void)
 {
 	long ret;
-	struct module *owner = spu_coredump_calls.owner;
 
 	ret = -ENOSYS;
 	mutex_lock(&spu_coredump_mutex);
-	if (owner && try_module_get(owner)) {
-		ret = spu_coredump_calls.arch_notes_size();
-		module_put(owner);
+	if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+		ret = spu_coredump_calls->arch_notes_size();
+		module_put(spu_coredump_calls->owner);
 	}
 	mutex_unlock(&spu_coredump_mutex);
 	return ret;
@@ -46,36 +45,35 @@ int arch_notes_size(void)
 
 void arch_write_notes(struct file *file)
 {
-	struct module *owner = spu_coredump_calls.owner;
-
 	mutex_lock(&spu_coredump_mutex);
-	if (owner && try_module_get(owner)) {
-		spu_coredump_calls.arch_write_notes(file);
-		module_put(owner);
+	if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+		spu_coredump_calls->arch_write_notes(file);
+		module_put(spu_coredump_calls->owner);
 	}
 	mutex_unlock(&spu_coredump_mutex);
 }
 
 int register_arch_coredump_calls(struct spu_coredump_calls *calls)
 {
-	if (spu_coredump_calls.owner)
-		return -EBUSY;
+	int ret = 0;
+
 
 	mutex_lock(&spu_coredump_mutex);
-	spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
-	spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
-	spu_coredump_calls.owner = calls->owner;
+	if (spu_coredump_calls)
+		ret = -EBUSY;
+	else
+		spu_coredump_calls = calls;
 	mutex_unlock(&spu_coredump_mutex);
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(register_arch_coredump_calls);
 
 void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
 {
-	BUG_ON(spu_coredump_calls.owner != calls->owner);
+	BUG_ON(spu_coredump_calls != calls);
 
 	mutex_lock(&spu_coredump_mutex);
-	spu_coredump_calls.owner = NULL;
+	spu_coredump_calls = NULL;
 	mutex_unlock(&spu_coredump_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index e34599f..1d4562a 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -48,11 +48,11 @@ static u64 __init find_spu_unit_number(s
 {
 	const unsigned int *prop;
 	int proplen;
-	prop = get_property(spe, "unit-id", &proplen);
+	prop = of_get_property(spe, "unit-id", &proplen);
 	if (proplen == 4)
 		return (u64)*prop;
 
-	prop = get_property(spe, "reg", &proplen);
+	prop = of_get_property(spe, "reg", &proplen);
 	if (proplen == 4)
 		return (u64)*prop;
 
@@ -76,12 +76,12 @@ static int __init spu_map_interrupts_old
 	int nid;
 
 	/* Get the interrupt source unit from the device-tree */
-	tmp = get_property(np, "isrc", NULL);
+	tmp = of_get_property(np, "isrc", NULL);
 	if (!tmp)
 		return -ENODEV;
 	isrc = tmp[0];
 
-	tmp = get_property(np->parent->parent, "node-id", NULL);
+	tmp = of_get_property(np->parent->parent, "node-id", NULL);
 	if (!tmp) {
 		printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
 		nid = spu->node;
@@ -110,7 +110,7 @@ static void __iomem * __init spu_map_pro
 	} __attribute__((packed)) *prop;
 	int proplen;
 
-	prop = get_property(n, name, &proplen);
+	prop = of_get_property(n, name, &proplen);
 	if (prop == NULL || proplen != sizeof (struct address_prop))
 		return NULL;
 
@@ -124,11 +124,11 @@ static int __init spu_map_device_old(str
 	int ret;
 
 	ret = -ENODEV;
-	spu->name = get_property(node, "name", NULL);
+	spu->name = of_get_property(node, "name", NULL);
 	if (!spu->name)
 		goto out;
 
-	prop = get_property(node, "local-store", NULL);
+	prop = of_get_property(node, "local-store", NULL);
 	if (!prop)
 		goto out;
 	spu->local_store_phys = *(unsigned long *)prop;
@@ -139,7 +139,7 @@ static int __init spu_map_device_old(str
 	if (!spu->local_store)
 		goto out;
 
-	prop = get_property(node, "problem", NULL);
+	prop = of_get_property(node, "problem", NULL);
 	if (!prop)
 		goto out_unmap;
 	spu->problem_phys = *(unsigned long *)prop;
@@ -226,7 +226,7 @@ static int __init spu_map_device(struct 
 	struct device_node *np = spu->devnode;
 	int ret = -ENODEV;
 
-	spu->name = get_property(np, "name", NULL);
+	spu->name = of_get_property(np, "name", NULL);
 	if (!spu->name)
 		goto out;
 
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index 472217d..2cd89c1 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,4 +1,4 @@
-obj-y += switch.o
+obj-y += switch.o fault.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o syscalls.o coredump.o
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index 1898f0d..d32db9f 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -28,7 +28,6 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/poll.h>
@@ -350,6 +349,11 @@ static int spu_backing_send_mfc_command(
 	return ret;
 }
 
+static void spu_backing_restart_dma(struct spu_context *ctx)
+{
+	/* nothing to do here */
+}
+
 struct spu_context_ops spu_backing_ops = {
 	.mbox_read = spu_backing_mbox_read,
 	.mbox_stat_read = spu_backing_mbox_stat_read,
@@ -376,4 +380,5 @@ struct spu_context_ops spu_backing_ops =
 	.read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
 	.get_mfc_free_elements = spu_backing_get_mfc_free_elements,
 	.send_mfc_command = spu_backing_send_mfc_command,
+	.restart_dma = spu_backing_restart_dma,
 };
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 04ad2e3..a87d9ca 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -41,9 +41,10 @@ struct spu_context *alloc_spu_context(st
 		goto out_free;
 	}
 	spin_lock_init(&ctx->mmio_lock);
+	spin_lock_init(&ctx->mapping_lock);
 	kref_init(&ctx->kref);
 	mutex_init(&ctx->state_mutex);
-	init_MUTEX(&ctx->run_sema);
+	mutex_init(&ctx->run_mutex);
 	init_waitqueue_head(&ctx->ibox_wq);
 	init_waitqueue_head(&ctx->wbox_wq);
 	init_waitqueue_head(&ctx->stop_wq);
@@ -51,6 +52,7 @@ struct spu_context *alloc_spu_context(st
 	ctx->state = SPU_STATE_SAVED;
 	ctx->ops = &spu_backing_ops;
 	ctx->owner = get_task_mm(current);
+	INIT_LIST_HEAD(&ctx->rq);
 	if (gang)
 		spu_gang_add_ctx(gang, ctx);
 	ctx->rt_priority = current->rt_priority;
@@ -75,6 +77,7 @@ void destroy_spu_context(struct kref *kr
 	spu_fini_csa(&ctx->csa);
 	if (ctx->gang)
 		spu_gang_remove_ctx(ctx->gang, ctx);
+	BUG_ON(!list_empty(&ctx->rq));
 	kfree(ctx);
 }
 
@@ -119,46 +122,6 @@ void spu_unmap_mappings(struct spu_conte
 }
 
 /**
- * spu_acquire_exclusive - lock spu contex and protect against userspace access
- * @ctx:	spu contex to lock
- *
- * Note:
- *	Returns 0 and with the context locked on success
- *	Returns negative error and with the context _unlocked_ on failure.
- */
-int spu_acquire_exclusive(struct spu_context *ctx)
-{
-	int ret = -EINVAL;
-
-	spu_acquire(ctx);
-	/*
-	 * Context is about to be freed, so we can't acquire it anymore.
-	 */
-	if (!ctx->owner)
-		goto out_unlock;
-
-	if (ctx->state == SPU_STATE_SAVED) {
-		ret = spu_activate(ctx, 0);
-		if (ret)
-			goto out_unlock;
-	} else {
-		/*
-		 * We need to exclude userspace access to the context.
-		 *
-		 * To protect against memory access we invalidate all ptes
-		 * and make sure the pagefault handlers block on the mutex.
-		 */
-		spu_unmap_mappings(ctx);
-	}
-
-	return 0;
-
- out_unlock:
-	spu_release(ctx);
-	return ret;
-}
-
-/**
  * spu_acquire_runnable - lock spu contex and make sure it is in runnable state
  * @ctx:	spu contex to lock
  *
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 725e195..5d9ad5a 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct
 	struct spu_context *ctx;
 	loff_t pos = 0;
 	int sz, dfd, rc, total = 0;
-	const int bufsz = 4096;
+	const int bufsz = PAGE_SIZE;
 	char *name;
 	char fullname[80], *buf;
 	struct elf_note en;
 
-	buf = kmalloc(bufsz, GFP_KERNEL);
+	buf = (void *)get_zeroed_page(GFP_KERNEL);
 	if (!buf)
 		return;
 
@@ -187,9 +187,8 @@ static void spufs_arch_write_note(struct
 		sz = spufs_coredump_read[i].size;
 
 	ctx = ctx_info->ctx;
-	if (!ctx) {
-		return;
-	}
+	if (!ctx)
+		goto out;
 
 	sprintf(fullname, "SPU/%d/%s", dfd, name);
 	en.n_namesz = strlen(fullname) + 1;
@@ -197,23 +196,25 @@ static void spufs_arch_write_note(struct
 	en.n_type = NT_SPU;
 
 	if (!spufs_dump_write(file, &en, sizeof(en)))
-		return;
+		goto out;
 	if (!spufs_dump_write(file, fullname, en.n_namesz))
-		return;
+		goto out;
 	if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
-		return;
+		goto out;
 
 	do {
 		rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
 		if (rc > 0) {
 			if (!spufs_dump_write(file, buf, rc))
-				return;
+				goto out;
 			total += rc;
 		}
 	} while (rc == bufsz && total < sz);
 
 	spufs_dump_seek(file, roundup((unsigned long)file->f_pos
 						- total + sz, 4));
+out:
+	free_page((unsigned long)buf);
 }
 
 static void spufs_arch_write_notes(struct file *file)
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
new file mode 100644
index 0000000..0f75c07
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -0,0 +1,211 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@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/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+#include "spufs.h"
+
+/*
+ * This ought to be kept in sync with the powerpc specific do_page_fault
+ * function. Currently, there are a few corner cases that we haven't had
+ * to handle fortunately.
+ */
+static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr)
+{
+	struct vm_area_struct *vma;
+	unsigned long is_write;
+	int ret;
+
+#if 0
+	if (!IS_VALID_EA(ea)) {
+		return -EFAULT;
+	}
+#endif /* XXX */
+	if (mm == NULL) {
+		return -EFAULT;
+	}
+	if (mm->pgd == NULL) {
+		return -EFAULT;
+	}
+
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, ea);
+	if (!vma)
+		goto bad_area;
+	if (vma->vm_start <= ea)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if (expand_stack(vma, ea))
+		goto bad_area;
+good_area:
+	is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+	if (is_write) {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	} else {
+		if (dsisr & MFC_DSISR_ACCESS_DENIED)
+			goto bad_area;
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+			goto bad_area;
+	}
+	ret = 0;
+	switch (handle_mm_fault(mm, vma, ea, is_write)) {
+	case VM_FAULT_MINOR:
+		current->min_flt++;
+		break;
+	case VM_FAULT_MAJOR:
+		current->maj_flt++;
+		break;
+	case VM_FAULT_SIGBUS:
+		ret = -EFAULT;
+		goto bad_area;
+	case VM_FAULT_OOM:
+		ret = -ENOMEM;
+		goto bad_area;
+	default:
+		BUG();
+	}
+	up_read(&mm->mmap_sem);
+	return ret;
+
+bad_area:
+	up_read(&mm->mmap_sem);
+	return -EFAULT;
+}
+
+static void spufs_handle_dma_error(struct spu_context *ctx,
+				unsigned long ea, int type)
+{
+	if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+		ctx->event_return |= type;
+		wake_up_all(&ctx->stop_wq);
+	} else {
+		siginfo_t info;
+		memset(&info, 0, sizeof(info));
+
+		switch (type) {
+		case SPE_EVENT_INVALID_DMA:
+			info.si_signo = SIGBUS;
+			info.si_code = BUS_OBJERR;
+			break;
+		case SPE_EVENT_SPE_DATA_STORAGE:
+			info.si_signo = SIGBUS;
+			info.si_addr = (void __user *)ea;
+			info.si_code = BUS_ADRERR;
+			break;
+		case SPE_EVENT_DMA_ALIGNMENT:
+			info.si_signo = SIGBUS;
+			/* DAR isn't set for an alignment fault :( */
+			info.si_code = BUS_ADRALN;
+			break;
+		case SPE_EVENT_SPE_ERROR:
+			info.si_signo = SIGILL;
+			info.si_addr = (void __user *)(unsigned long)
+				ctx->ops->npc_read(ctx) - 4;
+			info.si_code = ILL_ILLOPC;
+			break;
+		}
+		if (info.si_signo)
+			force_sig_info(info.si_signo, &info, current);
+	}
+}
+
+void spufs_dma_callback(struct spu *spu, int type)
+{
+	spufs_handle_dma_error(spu->ctx, spu->dar, type);
+}
+EXPORT_SYMBOL_GPL(spufs_dma_callback);
+
+/*
+ * bottom half handler for page faults, we can't do this from
+ * interrupt context, since we might need to sleep.
+ * we also need to give up the mutex so we can get scheduled
+ * out while waiting for the backing store.
+ *
+ * TODO: try calling hash_page from the interrupt handler first
+ *       in order to speed up the easy case.
+ */
+int spufs_handle_class1(struct spu_context *ctx)
+{
+	u64 ea, dsisr, access;
+	unsigned long flags;
+	int ret;
+
+	/*
+	 * dar and dsisr get passed from the registers
+	 * to the spu_context, to this function, but not
+	 * back to the spu if it gets scheduled again.
+	 *
+	 * if we don't handle the fault for a saved context
+	 * in time, we can still expect to get the same fault
+	 * the immediately after the context restore.
+	 */
+	if (ctx->state == SPU_STATE_RUNNABLE) {
+		ea = ctx->spu->dar;
+		dsisr = ctx->spu->dsisr;
+		ctx->spu->dar= ctx->spu->dsisr = 0;
+	} else {
+		ea = ctx->csa.priv1.mfc_dar_RW;
+		dsisr = ctx->csa.priv1.mfc_dsisr_RW;
+		ctx->csa.priv1.mfc_dar_RW = 0;
+		ctx->csa.priv1.mfc_dsisr_RW = 0;
+	}
+
+	if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
+		return 0;
+
+	pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
+		dsisr, ctx->state);
+
+	/* we must not hold the lock when entering spu_handle_mm_fault */
+	spu_release(ctx);
+
+	access = (_PAGE_PRESENT | _PAGE_USER);
+	access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+	local_irq_save(flags);
+	ret = hash_page(ea, access, 0x300);
+	local_irq_restore(flags);
+
+	/* hashing failed, so try the actual fault handler */
+	if (ret)
+		ret = spu_handle_mm_fault(current->mm, ea, dsisr);
+
+	spu_acquire(ctx);
+	/*
+	 * If we handled the fault successfully and are in runnable
+	 * state, restart the DMA.
+	 * In case of unhandled error report the problem to user space.
+	 */
+	if (!ret) {
+		if (ctx->spu)
+			ctx->ops->restart_dma(ctx);
+	} else
+		spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 505266a..d010b24 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, stru
 {
 	struct spufs_inode_info *i = SPUFS_I(inode);
 	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = ctx;
-	ctx->local_store = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->local_store = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->local_store = NULL;
+	spin_unlock(&ctx->mapping_lock);
 	return 0;
 }
 
@@ -149,6 +165,7 @@ spufs_mem_mmap(struct file *file, struct
 
 static const struct file_operations spufs_mem_fops = {
 	.open	 = spufs_mem_open,
+	.release = spufs_mem_release,
 	.read    = spufs_mem_read,
 	.write   = spufs_mem_write,
 	.llseek  = generic_file_llseek,
@@ -238,16 +255,33 @@ static int spufs_cntl_open(struct inode 
 	struct spufs_inode_info *i = SPUFS_I(inode);
 	struct spu_context *ctx = i->i_ctx;
 
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = ctx;
-	ctx->cntl = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->cntl = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return simple_attr_open(inode, file, spufs_cntl_get,
 					spufs_cntl_set, "0x%08lx");
 }
 
+static int
+spufs_cntl_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	simple_attr_close(inode, file);
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->cntl = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 static const struct file_operations spufs_cntl_fops = {
 	.open = spufs_cntl_open,
-	.release = simple_attr_close,
+	.release = spufs_cntl_release,
 	.read = simple_attr_read,
 	.write = simple_attr_write,
 	.mmap = spufs_cntl_mmap,
@@ -723,12 +757,28 @@ static int spufs_signal1_open(struct ino
 {
 	struct spufs_inode_info *i = SPUFS_I(inode);
 	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = ctx;
-	ctx->signal1 = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->signal1 = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal1_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->signal1 = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
 			size_t len, loff_t *pos)
 {
@@ -821,6 +871,7 @@ static int spufs_signal1_mmap(struct fil
 
 static const struct file_operations spufs_signal1_fops = {
 	.open = spufs_signal1_open,
+	.release = spufs_signal1_release,
 	.read = spufs_signal1_read,
 	.write = spufs_signal1_write,
 	.mmap = spufs_signal1_mmap,
@@ -830,12 +881,28 @@ static int spufs_signal2_open(struct ino
 {
 	struct spufs_inode_info *i = SPUFS_I(inode);
 	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = ctx;
-	ctx->signal2 = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->signal2 = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal2_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->signal2 = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
 			size_t len, loff_t *pos)
 {
@@ -932,6 +999,7 @@ #endif /* !SPUFS_MMAP_4K */
 
 static const struct file_operations spufs_signal2_fops = {
 	.open = spufs_signal2_open,
+	.release = spufs_signal2_release,
 	.read = spufs_signal2_read,
 	.write = spufs_signal2_write,
 	.mmap = spufs_signal2_mmap,
@@ -1031,13 +1099,30 @@ static int spufs_mss_open(struct inode *
 	struct spu_context *ctx = i->i_ctx;
 
 	file->private_data = i->i_ctx;
-	ctx->mss = inode->i_mapping;
-	smp_wmb();
+
+	spin_lock(&ctx->mapping_lock);
+	if (!i->i_openers++)
+		ctx->mss = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mss_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->mss = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 static const struct file_operations spufs_mss_fops = {
 	.open	 = spufs_mss_open,
+	.release = spufs_mss_release,
 	.mmap	 = spufs_mss_mmap,
 };
 
@@ -1072,14 +1157,30 @@ static int spufs_psmap_open(struct inode
 	struct spufs_inode_info *i = SPUFS_I(inode);
 	struct spu_context *ctx = i->i_ctx;
 
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = i->i_ctx;
-	ctx->psmap = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->psmap = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return nonseekable_open(inode, file);
 }
 
+static int
+spufs_psmap_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->psmap = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 static const struct file_operations spufs_psmap_fops = {
 	.open	 = spufs_psmap_open,
+	.release = spufs_psmap_release,
 	.mmap	 = spufs_psmap_mmap,
 };
 
@@ -1126,12 +1227,27 @@ static int spufs_mfc_open(struct inode *
 	if (atomic_read(&inode->i_count) != 1)
 		return -EBUSY;
 
+	spin_lock(&ctx->mapping_lock);
 	file->private_data = ctx;
-	ctx->mfc = inode->i_mapping;
-	smp_wmb();
+	if (!i->i_openers++)
+		ctx->mfc = inode->i_mapping;
+	spin_unlock(&ctx->mapping_lock);
 	return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mfc_release(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+	struct spu_context *ctx = i->i_ctx;
+
+	spin_lock(&ctx->mapping_lock);
+	if (!--i->i_openers)
+		ctx->mfc = NULL;
+	spin_unlock(&ctx->mapping_lock);
+	return 0;
+}
+
 /* interrupt-level mfc callback function. */
 void spufs_mfc_callback(struct spu *spu)
 {
@@ -1313,7 +1429,10 @@ static ssize_t spufs_mfc_write(struct fi
 	if (ret)
 		goto out;
 
-	spu_acquire_runnable(ctx, 0);
+	ret = spu_acquire_runnable(ctx, 0);
+	if (ret)
+		goto out;
+
 	if (file->f_flags & O_NONBLOCK) {
 		ret = ctx->ops->send_mfc_command(ctx, &cmd);
 	} else {
@@ -1399,6 +1518,7 @@ static int spufs_mfc_fasync(int fd, stru
 
 static const struct file_operations spufs_mfc_fops = {
 	.open	 = spufs_mfc_open,
+	.release = spufs_mfc_release,
 	.read	 = spufs_mfc_read,
 	.write	 = spufs_mfc_write,
 	.poll	 = spufs_mfc_poll,
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index ae42e03..fc4ed1f 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -25,7 +25,6 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 
@@ -296,6 +295,14 @@ static int spu_hw_send_mfc_command(struc
 	}
 }
 
+static void spu_hw_restart_dma(struct spu_context *ctx)
+{
+	struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
+
+	if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
+		out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
 struct spu_context_ops spu_hw_ops = {
 	.mbox_read = spu_hw_mbox_read,
 	.mbox_stat_read = spu_hw_mbox_stat_read,
@@ -320,4 +327,5 @@ struct spu_context_ops spu_hw_ops = {
 	.read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
 	.get_mfc_free_elements = spu_hw_get_mfc_free_elements,
 	.send_mfc_command = spu_hw_send_mfc_command,
+	.restart_dma = spu_hw_restart_dma,
 };
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 8079983..a93f328 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -36,6 +36,7 @@ #include <linux/parser.h>
 #include <asm/prom.h>
 #include <asm/semaphore.h>
 #include <asm/spu.h>
+#include <asm/spu_priv1.h>
 #include <asm/uaccess.h>
 
 #include "spufs.h"
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb
 
 	ei->i_gang = NULL;
 	ei->i_ctx = NULL;
+	ei->i_openers = 0;
 
 	return &ei->vfs_inode;
 }
@@ -69,8 +71,7 @@ spufs_init_once(void *p, struct kmem_cac
 {
 	struct spufs_inode_info *ei = p;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -520,13 +521,14 @@ out:
 
 /* File system initialization */
 enum {
-	Opt_uid, Opt_gid, Opt_err,
+	Opt_uid, Opt_gid, Opt_mode, Opt_err,
 };
 
 static match_table_t spufs_tokens = {
-	{ Opt_uid, "uid=%d" },
-	{ Opt_gid, "gid=%d" },
-	{ Opt_err, NULL  },
+	{ Opt_uid,  "uid=%d" },
+	{ Opt_gid,  "gid=%d" },
+	{ Opt_mode, "mode=%o" },
+	{ Opt_err,   NULL  },
 };
 
 static int
@@ -553,6 +555,11 @@ spufs_parse_options(char *options, struc
 				return 0;
 			root->i_gid = option;
 			break;
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				return 0;
+			root->i_mode = option | S_IFDIR;
+			break;
 		default:
 			return 0;
 		}
@@ -560,6 +567,11 @@ spufs_parse_options(char *options, struc
 	return 1;
 }
 
+static void spufs_exit_isolated_loader(void)
+{
+	kfree(isolated_loader);
+}
+
 static void
 spufs_init_isolated_loader(void)
 {
@@ -571,7 +583,7 @@ spufs_init_isolated_loader(void)
 	if (!dn)
 		return;
 
-	loader = get_property(dn, "loader", &size);
+	loader = of_get_property(dn, "loader", &size);
 	if (!loader)
 		return;
 
@@ -653,6 +665,10 @@ static int __init spufs_init(void)
 {
 	int ret;
 
+	ret = -ENODEV;
+	if (!spu_management_ops)
+		goto out;
+
 	ret = -ENOMEM;
 	spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
 			sizeof(struct spufs_inode_info), 0,
@@ -660,25 +676,29 @@ static int __init spufs_init(void)
 
 	if (!spufs_inode_cache)
 		goto out;
-	if (spu_sched_init() != 0) {
-		kmem_cache_destroy(spufs_inode_cache);
-		goto out;
-	}
-	ret = register_filesystem(&spufs_type);
+	ret = spu_sched_init();
 	if (ret)
 		goto out_cache;
+	ret = register_filesystem(&spufs_type);
+	if (ret)
+		goto out_sched;
 	ret = register_spu_syscalls(&spufs_calls);
 	if (ret)
 		goto out_fs;
 	ret = register_arch_coredump_calls(&spufs_coredump_calls);
 	if (ret)
-		goto out_fs;
+		goto out_syscalls;
 
 	spufs_init_isolated_loader();
 
 	return 0;
+
+out_syscalls:
+	unregister_spu_syscalls(&spufs_calls);
 out_fs:
 	unregister_filesystem(&spufs_type);
+out_sched:
+	spu_sched_exit();
 out_cache:
 	kmem_cache_destroy(spufs_inode_cache);
 out:
@@ -689,6 +709,7 @@ module_init(spufs_init);
 static void __exit spufs_exit(void)
 {
 	spu_sched_exit();
+	spufs_exit_isolated_loader();
 	unregister_arch_coredump_calls(&spufs_coredump_calls);
 	unregister_spu_syscalls(&spufs_calls);
 	unregister_filesystem(&spufs_type);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index f95a611..5762660 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,27 +18,6 @@ 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_SPE_DATA_STORAGE:
-		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;
@@ -63,13 +42,18 @@ static int spu_setup_isolated(struct spu
 	const u32 status_loading = SPU_STATUS_RUNNING
 		| SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
 
+	ret = -ENODEV;
 	if (!isolated_loader)
-		return -ENODEV;
-
-	ret = spu_acquire_exclusive(ctx);
-	if (ret)
 		goto out;
 
+	/*
+	 * We need to exclude userspace access to the context.
+	 *
+	 * To protect against memory access we invalidate all ptes
+	 * and make sure the pagefault handlers block on the mutex.
+	 */
+	spu_unmap_mappings(ctx);
+
 	mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
 
 	/* purge the MFC DMA queue to ensure no spurious accesses before we
@@ -82,7 +66,7 @@ static int spu_setup_isolated(struct spu
 			printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
 					__FUNCTION__);
 			ret = -EIO;
-			goto out_unlock;
+			goto out;
 		}
 		cond_resched();
 	}
@@ -119,12 +103,15 @@ static int spu_setup_isolated(struct spu
 		pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
 		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
 		ret = -EACCES;
+		goto out_drop_priv;
+	}
 
-	} else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+	if (!(status & SPU_STATUS_ISOLATED_STATE)) {
 		/* This isn't allowed by the CBEA, but check anyway */
 		pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
 		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
 		ret = -EINVAL;
+		goto out_drop_priv;
 	}
 
 out_drop_priv:
@@ -132,30 +119,19 @@ out_drop_priv:
 	sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
 	spu_mfc_sr1_set(ctx->spu, sr1);
 
-out_unlock:
-	spu_release(ctx);
 out:
 	return ret;
 }
 
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 * npc)
 {
-	int ret;
-	unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
-
-	ret = spu_acquire_runnable(ctx, 0);
-	if (ret)
-		return ret;
-
 	if (ctx->flags & SPU_CREATE_ISOLATE) {
+		unsigned long runcntl;
+
 		if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
-			/* Need to release ctx, because spu_setup_isolated will
-			 * acquire it exclusively.
-			 */
-			spu_release(ctx);
-			ret = spu_setup_isolated(ctx);
-			if (!ret)
-				ret = spu_acquire_runnable(ctx, 0);
+			int ret = spu_setup_isolated(ctx);
+			if (ret)
+				return ret;
 		}
 
 		/* if userspace has set the runcntrl register (eg, to issue an
@@ -164,16 +140,17 @@ static inline int spu_run_init(struct sp
 			(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
 		if (runcntl == 0)
 			runcntl = SPU_RUNCNTL_RUNNABLE;
+		ctx->ops->runcntl_write(ctx, runcntl);
 	} else {
 		spu_start_tick(ctx);
 		ctx->ops->npc_write(ctx, *npc);
+		ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
 	}
 
-	ctx->ops->runcntl_write(ctx, runcntl);
-	return ret;
+	return 0;
 }
 
-static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+static int spu_run_fini(struct spu_context *ctx, u32 * npc,
 			       u32 * status)
 {
 	int ret = 0;
@@ -189,19 +166,27 @@ static inline int spu_run_fini(struct sp
 	return ret;
 }
 
-static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
 				         u32 *status)
 {
 	int ret;
 
-	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+	ret = spu_run_fini(ctx, npc, status);
+	if (ret)
 		return ret;
-	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
-		       SPU_STATUS_STOPPED_BY_HALT)) {
+
+	if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
 		return *status;
-	}
-	if ((ret = spu_run_init(ctx, npc)) != 0)
+
+	ret = spu_acquire_runnable(ctx, 0);
+	if (ret)
+		return ret;
+
+	ret = spu_run_init(ctx, npc);
+	if (ret) {
+		spu_release(ctx);
 		return ret;
+	}
 	return 0;
 }
 
@@ -253,17 +238,17 @@ int spu_process_callback(struct spu_cont
 {
 	struct spu_syscall_block s;
 	u32 ls_pointer, npc;
-	char *ls;
+	void __iomem *ls;
 	long spu_ret;
 	int ret;
 
 	/* get syscall block from local store */
-	npc = ctx->ops->npc_read(ctx);
-	ls = ctx->ops->get_ls(ctx);
-	ls_pointer = *(u32*)(ls + npc);
+	npc = ctx->ops->npc_read(ctx) & ~3;
+	ls = (void __iomem *)ctx->ops->get_ls(ctx);
+	ls_pointer = in_be32(ls + npc);
 	if (ls_pointer > (LS_SIZE - sizeof(s)))
 		return -EFAULT;
-	memcpy(&s, ls + ls_pointer, sizeof (s));
+	memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
 
 	/* do actual syscall without pinning the spu */
 	ret = 0;
@@ -283,7 +268,7 @@ int spu_process_callback(struct spu_cont
 	}
 
 	/* write result, jump over indirect pointer */
-	memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+	memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
 	ctx->ops->npc_write(ctx, npc);
 	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
 	return ret;
@@ -292,11 +277,8 @@ int spu_process_callback(struct spu_cont
 static inline int spu_process_events(struct spu_context *ctx)
 {
 	struct spu *spu = ctx->spu;
-	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
 	int ret = 0;
 
-	if (spu->dsisr & pte_fault)
-		ret = spu_irq_class_1_bottom(spu);
 	if (spu->class_0_pending)
 		ret = spu_irq_class_0_bottom(spu);
 	if (!ret && signal_pending(current))
@@ -310,14 +292,21 @@ long spufs_run_spu(struct file *file, st
 	int ret;
 	u32 status;
 
-	if (down_interruptible(&ctx->run_sema))
+	if (mutex_lock_interruptible(&ctx->run_mutex))
 		return -ERESTARTSYS;
 
 	ctx->ops->master_start(ctx);
 	ctx->event_return = 0;
-	ret = spu_run_init(ctx, npc);
+
+	ret = spu_acquire_runnable(ctx, 0);
 	if (ret)
+		return ret;
+
+	ret = spu_run_init(ctx, npc);
+	if (ret) {
+		spu_release(ctx);
 		goto out;
+	}
 
 	do {
 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
@@ -330,6 +319,10 @@ long spufs_run_spu(struct file *file, st
 				break;
 			status &= ~SPU_STATUS_STOPPED_BY_STOP;
 		}
+		ret = spufs_handle_class1(ctx);
+		if (ret)
+			break;
+
 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
 			ret = spu_reacquire_runnable(ctx, npc, &status);
 			if (ret) {
@@ -363,6 +356,6 @@ out2:
 
 out:
 	*event = ctx->event_return;
-	up(&ctx->run_sema);
+	mutex_unlock(&ctx->run_mutex);
 	return ret;
 }
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 39823ce..b6ecb30 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -30,7 +30,6 @@ #include <linux/mm.h>
 #include <linux/completion.h>
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/numa.h>
@@ -71,14 +70,27 @@ static inline int node_allowed(int node)
 
 void spu_start_tick(struct spu_context *ctx)
 {
-	if (ctx->policy == SCHED_RR)
+	if (ctx->policy == SCHED_RR) {
+		/*
+		 * Make sure the exiting bit is cleared.
+		 */
+		clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+		mb();
 		queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
+	}
 }
 
 void spu_stop_tick(struct spu_context *ctx)
 {
-	if (ctx->policy == SCHED_RR)
+	if (ctx->policy == SCHED_RR) {
+		/*
+		 * While the work can be rearming normally setting this flag
+		 * makes sure it does not rearm itself anymore.
+		 */
+		set_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+		mb();
 		cancel_delayed_work(&ctx->sched_work);
+	}
 }
 
 void spu_sched_tick(struct work_struct *work)
@@ -86,7 +98,15 @@ void spu_sched_tick(struct work_struct *
 	struct spu_context *ctx =
 		container_of(work, struct spu_context, sched_work.work);
 	struct spu *spu;
-	int rearm = 1;
+	int preempted = 0;
+
+	/*
+	 * If this context is being stopped avoid rescheduling from the
+	 * scheduler tick because we would block on the state_mutex.
+	 * The caller will yield the spu later on anyway.
+	 */
+	if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags))
+		return;
 
 	mutex_lock(&ctx->state_mutex);
 	spu = ctx->spu;
@@ -94,12 +114,19 @@ void spu_sched_tick(struct work_struct *
 		int best = sched_find_first_bit(spu_prio->bitmap);
 		if (best <= ctx->prio) {
 			spu_deactivate(ctx);
-			rearm = 0;
+			preempted = 1;
 		}
 	}
 	mutex_unlock(&ctx->state_mutex);
 
-	if (rearm)
+	if (preempted) {
+		/*
+		 * We need to break out of the wait loop in spu_run manually
+		 * to ensure this context gets put on the runqueue again
+		 * ASAP.
+		 */
+		wake_up(&ctx->stop_wq);
+	} else
 		spu_start_tick(ctx);
 }
 
@@ -208,58 +235,40 @@ static void spu_unbind_context(struct sp
  * spu_add_to_rq - add a context to the runqueue
  * @ctx:       context to add
  */
-static void spu_add_to_rq(struct spu_context *ctx)
+static void __spu_add_to_rq(struct spu_context *ctx)
 {
-	spin_lock(&spu_prio->runq_lock);
-	list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
-	set_bit(ctx->prio, spu_prio->bitmap);
-	spin_unlock(&spu_prio->runq_lock);
-}
+	int prio = ctx->prio;
 
-/**
- * spu_del_from_rq - remove a context from the runqueue
- * @ctx:       context to remove
- */
-static void spu_del_from_rq(struct spu_context *ctx)
-{
-	spin_lock(&spu_prio->runq_lock);
-	list_del_init(&ctx->rq);
-	if (list_empty(&spu_prio->runq[ctx->prio]))
-		clear_bit(ctx->prio, spu_prio->bitmap);
-	spin_unlock(&spu_prio->runq_lock);
+	list_add_tail(&ctx->rq, &spu_prio->runq[prio]);
+	set_bit(prio, spu_prio->bitmap);
 }
 
-/**
- * spu_grab_context - remove one context from the runqueue
- * @prio:      priority of the context to be removed
- *
- * This function removes one context from the runqueue for priority @prio.
- * If there is more than one context with the given priority the first
- * task on the runqueue will be taken.
- *
- * Returns the spu_context it just removed.
- *
- * Must be called with spu_prio->runq_lock held.
- */
-static struct spu_context *spu_grab_context(int prio)
+static void __spu_del_from_rq(struct spu_context *ctx)
 {
-	struct list_head *rq = &spu_prio->runq[prio];
+	int prio = ctx->prio;
 
-	if (list_empty(rq))
-		return NULL;
-	return list_entry(rq->next, struct spu_context, rq);
+	if (!list_empty(&ctx->rq))
+		list_del_init(&ctx->rq);
+	if (list_empty(&spu_prio->runq[prio]))
+		clear_bit(prio, spu_prio->bitmap);
 }
 
 static void spu_prio_wait(struct spu_context *ctx)
 {
 	DEFINE_WAIT(wait);
 
+	spin_lock(&spu_prio->runq_lock);
 	prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
 	if (!signal_pending(current)) {
+		__spu_add_to_rq(ctx);
+		spin_unlock(&spu_prio->runq_lock);
 		mutex_unlock(&ctx->state_mutex);
 		schedule();
 		mutex_lock(&ctx->state_mutex);
+		spin_lock(&spu_prio->runq_lock);
+		__spu_del_from_rq(ctx);
 	}
+	spin_unlock(&spu_prio->runq_lock);
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&ctx->stop_wq, &wait);
 }
@@ -280,9 +289,14 @@ static void spu_reschedule(struct spu *s
 	spin_lock(&spu_prio->runq_lock);
 	best = sched_find_first_bit(spu_prio->bitmap);
 	if (best < MAX_PRIO) {
-		struct spu_context *ctx = spu_grab_context(best);
-		if (ctx)
-			wake_up(&ctx->stop_wq);
+		struct list_head *rq = &spu_prio->runq[best];
+		struct spu_context *ctx;
+
+		BUG_ON(list_empty(rq));
+
+		ctx = list_entry(rq->next, struct spu_context, rq);
+		__spu_del_from_rq(ctx);
+		wake_up(&ctx->stop_wq);
 	}
 	spin_unlock(&spu_prio->runq_lock);
 }
@@ -365,6 +379,12 @@ static struct spu *find_victim(struct sp
 			}
 			spu_unbind_context(spu, victim);
 			mutex_unlock(&victim->state_mutex);
+			/*
+			 * We need to break out of the wait loop in spu_run
+			 * manually to ensure this context gets put on the
+			 * runqueue again ASAP.
+			 */
+			wake_up(&victim->stop_wq);
 			return spu;
 		}
 	}
@@ -377,7 +397,7 @@ static struct spu *find_victim(struct sp
  * @ctx:	spu context to schedule
  * @flags:	flags (currently ignored)
  *
- * Tries to find a free spu to run @ctx.  If no free spu is availble
+ * Tries to find a free spu to run @ctx.  If no free spu is available
  * add the context to the runqueue so it gets woken up once an spu
  * is available.
  */
@@ -402,9 +422,7 @@ int spu_activate(struct spu_context *ctx
 			return 0;
 		}
 
-		spu_add_to_rq(ctx);
 		spu_prio_wait(ctx);
-		spu_del_from_rq(ctx);
 	} while (!signal_pending(current));
 
 	return -ERESTARTSYS;
@@ -438,7 +456,6 @@ void spu_deactivate(struct spu_context *
 void spu_yield(struct spu_context *ctx)
 {
 	struct spu *spu;
-	int need_yield = 0;
 
 	if (mutex_trylock(&ctx->state_mutex)) {
 		if ((spu = ctx->spu) != NULL) {
@@ -447,13 +464,10 @@ void spu_yield(struct spu_context *ctx)
 				pr_debug("%s: yielding SPU %d NODE %d\n",
 					 __FUNCTION__, spu->number, spu->node);
 				spu_deactivate(ctx);
-				need_yield = 1;
 			}
 		}
 		mutex_unlock(&ctx->state_mutex);
 	}
-	if (unlikely(need_yield))
-		yield();
 }
 
 int __init spu_sched_init(void)
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 5c4e47d..0a947fd 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -41,7 +41,7 @@ struct spu_gang;
 
 /* ctx->sched_flags */
 enum {
-	SPU_SCHED_WAKE = 0, /* currently unused */
+	SPU_SCHED_EXITING = 0,
 };
 
 struct spu_context {
@@ -50,16 +50,17 @@ struct spu_context {
 	spinlock_t mmio_lock;		  /* protects mmio access */
 	struct address_space *local_store; /* local store mapping.  */
 	struct address_space *mfc;	   /* 'mfc' area mappings. */
-	struct address_space *cntl; 	   /* 'control' area mappings. */
-	struct address_space *signal1; 	   /* 'signal1' area mappings. */
-	struct address_space *signal2; 	   /* 'signal2' area mappings. */
-	struct address_space *mss; 	   /* 'mss' area mappings. */
-	struct address_space *psmap; 	   /* 'psmap' area mappings. */
+	struct address_space *cntl;	   /* 'control' area mappings. */
+	struct address_space *signal1;	   /* 'signal1' area mappings. */
+	struct address_space *signal2;	   /* 'signal2' area mappings. */
+	struct address_space *mss;	   /* 'mss' area mappings. */
+	struct address_space *psmap;	   /* 'psmap' area mappings. */
+	spinlock_t mapping_lock;
 	u64 object_id;		   /* user space pointer for oprofile */
 
 	enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
 	struct mutex state_mutex;
-	struct semaphore run_sema;
+	struct mutex run_mutex;
 
 	struct mm_struct *owner;
 
@@ -140,6 +141,7 @@ struct spu_context_ops {
 			       struct spu_dma_info * info);
 	void (*proxydma_info_read) (struct spu_context * ctx,
 				    struct spu_proxydma_info * info);
+	void (*restart_dma)(struct spu_context *ctx);
 };
 
 extern struct spu_context_ops spu_hw_ops;
@@ -149,6 +151,7 @@ struct spufs_inode_info {
 	struct spu_context *i_ctx;
 	struct spu_gang *i_gang;
 	struct inode vfs_inode;
+	int i_openers;
 };
 #define SPUFS_I(inode) \
 	container_of(inode, struct spufs_inode_info, vfs_inode)
@@ -170,6 +173,9 @@ 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);
 
+/* fault handling */
+int spufs_handle_class1(struct spu_context *ctx);
+
 /* context management */
 static inline void spu_acquire(struct spu_context *ctx)
 {
@@ -190,7 +196,6 @@ void spu_unmap_mappings(struct spu_conte
 void spu_forget(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
 void spu_acquire_saved(struct spu_context *ctx);
-int spu_acquire_exclusive(struct spu_context *ctx);
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
@@ -218,14 +223,13 @@ ({									\
 		prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE);	\
 		if (condition)						\
 			break;						\
-		if (!signal_pending(current)) {				\
-			spu_release(ctx);				\
-			schedule();					\
-			spu_acquire(ctx);				\
-			continue;					\
+		if (signal_pending(current)) {				\
+			__ret = -ERESTARTSYS;				\
+			break;						\
 		}							\
-		__ret = -ERESTARTSYS;					\
-		break;							\
+		spu_release(ctx);					\
+		schedule();						\
+		spu_acquire(ctx);					\
 	}								\
 	finish_wait(&(wq), &__wait);					\
 	__ret;								\
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index fd91c73..29dc59c 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -39,7 +39,6 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 
@@ -2084,6 +2083,10 @@ int spu_save(struct spu_state *prev, str
 	int rc;
 
 	acquire_spu_lock(spu);	        /* Step 1.     */
+	prev->dar = spu->dar;
+	prev->dsisr = spu->dsisr;
+	spu->dar = 0;
+	spu->dsisr = 0;
 	rc = __do_spu_save(prev, spu);	/* Steps 2-53. */
 	release_spu_lock(spu);
 	if (rc != 0 && rc != 2 && rc != 6) {
@@ -2109,9 +2112,9 @@ int spu_restore(struct spu_state *new, s
 
 	acquire_spu_lock(spu);
 	harvest(NULL, spu);
-	spu->dar = 0;
-	spu->dsisr = 0;
 	spu->slb_replace = 0;
+	new->dar = 0;
+	new->dsisr = 0;
 	spu->class_0_pending = 0;
 	rc = __do_spu_restore(new, spu);
 	release_spu_lock(spu);
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig
new file mode 100644
index 0000000..2db1e29
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Kconfig
@@ -0,0 +1,9 @@
+config PPC_CELLEB
+	bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_CELL
+	select PPC_OF_PLATFORM_PCI
+	select HAS_TXX9_SERIAL
+	select PPC_UDBG_BEAT
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_EHCI_BIG_ENDIAN_MMIO
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
index f63b94c..755d869 100644
--- a/arch/powerpc/platforms/celleb/iommu.c
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -37,7 +37,7 @@ static int __init find_dma_window(u64 *i
 	const unsigned long *dma_window;
 
 	for_each_node_by_type(dn, "ioif") {
-		dma_window = get_property(dn, "toshiba,dma-window", NULL);
+		dma_window = of_get_property(dn, "toshiba,dma-window", NULL);
 		if (dma_window) {
 			*io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
 			*ioid = dma_window[0] & 0x7ffUL;
@@ -80,7 +80,7 @@ static int celleb_of_bus_notify(struct n
 	if (action != BUS_NOTIFY_ADD_DEVICE)
 		return 0;
 
-	dev->archdata.dma_ops = pci_dma_ops;
+	dev->archdata.dma_ops = get_pci_dma_ops();
 
 	return 0;
 }
@@ -95,7 +95,7 @@ static int __init celleb_init_iommu(void
 		return -ENODEV;
 
 	celleb_init_direct_mapping();
-	pci_dma_ops = &dma_direct_ops;
+	set_pci_dma_ops(&dma_direct_ops);
 	bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
 
 	return 0;
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index 98de836..d1adf34 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -309,13 +309,13 @@ static int __devinit celleb_setup_fake_p
 		goto error;
 	}
 
-	name = get_property(node, "model", &rlen);
+	name = of_get_property(node, "model", &rlen);
 	if (!name) {
 		printk(KERN_ERR "PCI: model property not found.\n");
 		goto error;
 	}
 
-	wi4 = get_property(node, "reg", &rlen);
+	wi4 = of_get_property(node, "reg", &rlen);
 	if (wi4 == NULL)
 		goto error;
 
@@ -352,10 +352,10 @@ static int __devinit celleb_setup_fake_p
 	}
 	pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
 
-	wi0 = get_property(node, "device-id", NULL);
-	wi1 = get_property(node, "vendor-id", NULL);
-	wi2 = get_property(node, "class-code", NULL);
-	wi3 = get_property(node, "revision-id", NULL);
+	wi0 = of_get_property(node, "device-id", NULL);
+	wi1 = of_get_property(node, "vendor-id", NULL);
+	wi2 = of_get_property(node, "class-code", NULL);
+	wi3 = of_get_property(node, "revision-id", NULL);
 
 	celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
 	celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
@@ -376,7 +376,7 @@ static int __devinit celleb_setup_fake_p
 
 	celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
 
-	li = get_property(node, "interrupts", &rlen);
+	li = of_get_property(node, "interrupts", &rlen);
 	val = li[0];
 	celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
 	celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
@@ -424,7 +424,7 @@ static int __devinit phb_set_bus_ranges(
 	const int *bus_range;
 	unsigned int len;
 
-	bus_range = get_property(dev, "bus-range", &len);
+	bus_range = of_get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int))
 		return 1;
 
@@ -451,7 +451,7 @@ int __devinit celleb_setup_phb(struct pc
 	struct device_node *node;
 	unsigned int rlen;
 
-	name = get_property(dev, "name", &rlen);
+	name = of_get_property(dev, "name", &rlen);
 	if (!name)
 		return 1;
 
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index 5f4d0d9..596ab2a 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -67,7 +67,7 @@ static void celleb_show_cpuinfo(struct s
 
 	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	/* using "CHRP" is to trick anaconda into installing FCx into Celleb */
 	seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
 	of_node_put(root);
@@ -128,15 +128,6 @@ static int __init celleb_probe(void)
 	return 1;
 }
 
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int celleb_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 #ifdef CONFIG_KEXEC
 static void celleb_kexec_cpu_down(int crash, int secondary)
 {
@@ -173,7 +164,6 @@ define_machine(celleb) {
 	.get_rtc_time		= beat_get_rtc_time,
 	.set_rtc_time		= beat_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport	= celleb_check_legacy_ioport,
 	.progress		= celleb_progress,
 	.power_save		= beat_power_save,
 	.nvram_size		= beat_nvram_get_size,
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig
new file mode 100644
index 0000000..d2c6905
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/Kconfig
@@ -0,0 +1,11 @@
+config PPC_CHRP
+	bool "Common Hardware Reference Platform (CHRP) based machines"
+	depends on PPC_MULTIPLATFORM && PPC32
+	select MPIC
+	select PPC_I8259
+	select PPC_INDIRECT_PCI
+	select PPC_RTAS
+	select PPC_MPC106
+	select PPC_UDBG_16550
+	select PPC_NATIVE
+	default y
diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c
index 0dd4a64..8efd424 100644
--- a/arch/powerpc/platforms/chrp/nvram.c
+++ b/arch/powerpc/platforms/chrp/nvram.c
@@ -74,7 +74,7 @@ void __init chrp_nvram_init(void)
 	if (nvram == NULL)
 		return;
 
-	nbytes_p = get_property(nvram, "#bytes", &proplen);
+	nbytes_p = of_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 ddb4a11..d32fedc 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -7,7 +7,6 @@ #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -137,9 +136,11 @@ hydra_init(void)
 	struct device_node *np;
 	struct resource r;
 
-	np = find_devices("mac-io");
-	if (np == NULL || of_address_to_resource(np, 0, &r))
+	np = of_find_node_by_name(NULL, "mac-io");
+	if (np == NULL || of_address_to_resource(np, 0, &r)) {
+		of_node_put(np);
 		return 0;
+	}
 	Hydra = ioremap(r.start, r.end-r.start);
 	printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
 	printk("Hydra Feature_Control was %x",
@@ -186,10 +187,9 @@ setup_python(struct pci_controller *hose
 /* Marvell Discovery II based Pegasos 2 */
 static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
 {
-	struct device_node *root = find_path_device("/");
+	struct device_node *root = of_find_node_by_path("/");
 	struct device_node *rtas;
 
-	of_node_get(root);
 	rtas = of_find_node_by_name (root, "rtas");
 	if (rtas) {
 		hose->ops = &rtas_pci_ops;
@@ -199,6 +199,7 @@ static void __init setup_peg2(struct pci
 			" your firmware\n");
 	}
 	pci_assign_all_buses = 1;
+	/* keep the reference to the root node */
 }
 
 void __init
@@ -211,14 +212,14 @@ chrp_find_bridges(void)
 	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 device_node *root = of_find_node_by_path("/");
 	struct resource r;
 	/*
 	 * The PCI host bridge nodes on some machines don't have
 	 * properties to adequately identify them, so we have to
 	 * look at what sort of machine this is as well.
 	 */
-	machine = get_property(root, "model", NULL);
+	machine = of_get_property(root, "model", NULL);
 	if (machine != NULL) {
 		is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
 		is_mot = strncmp(machine, "MOT", 3) == 0;
@@ -237,7 +238,7 @@ chrp_find_bridges(void)
 			       dev->full_name);
 			continue;
 		}
-		bus_range = get_property(dev, "bus-range", &len);
+		bus_range = of_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);
@@ -263,10 +264,10 @@ chrp_find_bridges(void)
 		hose->first_busno = bus_range[0];
 		hose->last_busno = bus_range[1];
 
-		model = get_property(dev, "model", NULL);
+		model = of_get_property(dev, "model", NULL);
 		if (model == NULL)
 			model = "<none>";
-		if (device_is_compatible(dev, "IBM,python")) {
+		if (of_device_is_compatible(dev, "IBM,python")) {
 			setup_python(hose, dev);
 		} else if (is_mot
 			   || strncmp(model, "Motorola, Grackle", 17) == 0) {
@@ -285,7 +286,8 @@ chrp_find_bridges(void)
 					   r.start + 0x000f8000,
 					   r.start + 0x000f8010);
 			if (index == 0) {
-				dma = get_property(dev, "system-dma-base",&len);
+				dma = of_get_property(dev, "system-dma-base",
+							&len);
 				if (dma && len >= sizeof(*dma)) {
 					dma = (unsigned int *)
 						(((unsigned long)dma) +
@@ -303,12 +305,13 @@ chrp_find_bridges(void)
 
 		/* check the first bridge for a property that we can
 		   use to set pci_dram_offset */
-		dma = get_property(dev, "ibm,dma-ranges", &len);
+		dma = of_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);
 		}
 	}
+	of_node_put(root);
 }
 
 /* SL82C105 IDE Control/Status Register */
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 117c9a0..373de4c 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -28,7 +28,6 @@ #include <linux/utsrelease.h>
 #include <linux/adb.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/ide.h>
 #include <linux/console.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
@@ -111,9 +110,9 @@ void chrp_show_cpuinfo(struct seq_file *
 	struct device_node *root;
 	const char *model = "";
 
-	root = find_path_device("/");
+	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "machine\t\t: CHRP %s\n", model);
 
 	/* longtrail (goldengate) stuff */
@@ -161,6 +160,7 @@ void chrp_show_cpuinfo(struct seq_file *
 			   gg2_cachetypes[(t>>2) & 3],
 			   gg2_cachemodes[t & 3]);
 	}
+	of_node_put(root);
 }
 
 /*
@@ -205,13 +205,15 @@ static void __init sio_init(void)
 {
 	struct device_node *root;
 
-	if ((root = find_path_device("/")) &&
-	    !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+	if ((root = of_find_node_by_path("/")) &&
+	    !strncmp(of_get_property(root, "model", NULL),
+			"IBM,LongTrail", 13)) {
 		/* logical device 0 (KBC/Keyboard) */
 		sio_fixup_irq("keyboard", 0, 1, 2);
 		/* select logical device 1 (KBC/Mouse) */
 		sio_fixup_irq("mouse", 1, 12, 2);
 	}
+	of_node_put(root);
 }
 
 
@@ -224,12 +226,12 @@ static void __init pegasos_set_l2cr(void
 		return;
 
 	/* Enable L2 cache if needed */
-	np = find_type_devices("cpu");
+	np = of_find_node_by_type(NULL, "cpu");
 	if (np != NULL) {
-		const unsigned int *l2cr = get_property(np, "l2cr", NULL);
+		const unsigned int *l2cr = of_get_property(np, "l2cr", NULL);
 		if (l2cr == NULL) {
 			printk ("Pegasos l2cr : no cpu l2cr property found\n");
-			return;
+			goto out;
 		}
 		if (!((*l2cr) & 0x80000000)) {
 			printk ("Pegasos l2cr : L2 cache was not active, "
@@ -238,6 +240,8 @@ static void __init pegasos_set_l2cr(void
 			_set_L2CR((*l2cr) | 0x80000000);
 		}
 	}
+out:
+	of_node_put(np);
 }
 
 static void briq_restart(char *cmd)
@@ -250,14 +254,14 @@ static void briq_restart(char *cmd)
 
 void __init chrp_setup_arch(void)
 {
-	struct device_node *root = find_path_device ("/");
+	struct device_node *root = of_find_node_by_path("/");
 	const char *machine = NULL;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000/HZ;
 
 	if (root)
-		machine = get_property(root, "model", NULL);
+		machine = of_get_property(root, "model", NULL);
 	if (machine && strncmp(machine, "Pegasos", 7) == 0) {
 		_chrp_type = _CHRP_Pegasos;
 	} else if (machine && strncmp(machine, "IBM", 3) == 0) {
@@ -273,6 +277,7 @@ void __init chrp_setup_arch(void)
 		/* Let's assume it is an IBM chrp if all else fails */
 		_chrp_type = _CHRP_IBM;
 	}
+	of_node_put(root);
 	printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
 
 	rtas_initialize();
@@ -361,8 +366,8 @@ static void __init chrp_find_openpic(voi
 		return;
 	root = of_find_node_by_path("/");
 	if (root) {
-		opprop = get_property(root, "platform-open-pic", &oplen);
-		na = prom_n_addr_cells(root);
+		opprop = of_get_property(root, "platform-open-pic", &oplen);
+		na = of_n_addr_cells(root);
 	}
 	if (opprop && oplen >= na * sizeof(unsigned int)) {
 		opaddr = opprop[na-1];	/* assume 32-bit */
@@ -378,7 +383,7 @@ static void __init chrp_find_openpic(voi
 
 	printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
 
-	iranges = get_property(np, "interrupt-ranges", &len);
+	iranges = of_get_property(np, "interrupt-ranges", &len);
 	if (iranges == NULL)
 		len = 0;	/* non-distributed mpic */
 	else
@@ -427,7 +432,7 @@ static void __init chrp_find_openpic(voi
 	of_node_put(np);
 }
 
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 static struct irqaction xmon_irqaction = {
 	.handler = xmon_irq,
 	.mask = CPU_MASK_NONE,
@@ -443,7 +448,7 @@ static void __init chrp_find_8259(void)
 
 	/* Look for cascade */
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "chrp,iic")) {
+		if (of_device_is_compatible(np, "chrp,iic")) {
 			pic = np;
 			break;
 		}
@@ -463,15 +468,16 @@ static void __init chrp_find_8259(void)
 	 * Also, Pegasos-type platforms don't have a proper node to start
 	 * from anyway
 	 */
-	for (np = find_devices("pci"); np != NULL; np = np->next) {
-		const unsigned int *addrp = get_property(np,
+	for_each_node_by_name(np, "pci") {
+		const unsigned int *addrp = of_get_property(np,
 				"8259-interrupt-acknowledge", NULL);
 
 		if (addrp == NULL)
 			continue;
-		chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
+		chrp_int_ack = addrp[of_n_addr_cells(np)-1];
 		break;
 	}
+	of_node_put(np);
 	if (np == NULL)
 		printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
 		       " address, polling\n");
@@ -493,7 +499,7 @@ static void __init chrp_find_8259(void)
 
 void __init chrp_init_IRQ(void)
 {
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 	struct device_node *kbd;
 #endif
 	chrp_find_openpic();
@@ -510,13 +516,14 @@ #endif /* CONFIG_SMP */
 	if (_chrp_type == _CHRP_Pegasos)
 		ppc_md.get_irq        = i8259_irq;
 
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
 	/* see if there is a keyboard in the device tree
 	   with a parent of type "adb" */
-	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+	for_each_node_by_name(kbd, "keyboard")
 		if (kbd->parent && kbd->parent->type
 		    && strcmp(kbd->parent->type, "adb") == 0)
 			break;
+	of_node_put(kbd);
 	if (kbd)
 		setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
 #endif
@@ -542,9 +549,9 @@ #endif
 	/* Get the event scan rate for the rtas so we know how
 	 * often it expects a heartbeat. -- Cort
 	 */
-	device = find_devices("rtas");
+	device = of_find_node_by_name(NULL, "rtas");
 	if (device)
-		p = get_property(device, "rtas-event-scan-rate", NULL);
+		p = of_get_property(device, "rtas-event-scan-rate", NULL);
 	if (p && *p) {
 		/*
 		 * Arrange to call chrp_event_scan at least *p times
@@ -571,6 +578,7 @@ #endif
 		printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
 		       *p, interval);
 	}
+	of_node_put(device);
 
 	if (ppc_md.progress)
 		ppc_md.progress("  Have fun!    ", 0x7777);
diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c
index 1d2307e..3ea0eb7 100644
--- a/arch/powerpc/platforms/chrp/smp.c
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 7d78890..96d1e4b 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -39,12 +39,17 @@ long __init chrp_time_init(void)
 	struct resource r;
 	int base;
 
-	rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+	rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
 	if (rtcs == NULL)
-		rtcs = find_compatible_devices("rtc", "ds1385-rtc");
-	if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
+		rtcs = of_find_compatible_node(NULL, "rtc", "ds1385-rtc");
+	if (rtcs == NULL)
+		return 0;
+	if (of_address_to_resource(rtcs, 0, &r)) {
+		of_node_put(rtcs);
 		return 0;
-	
+	}
+	of_node_put(rtcs);
+
 	base = r.start;
 	nvram_as1 = 0;
 	nvram_as0 = base;
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 3410bcb..8f3c2a7 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -2,78 +2,6 @@ choice
 	prompt "Machine Type"
 	depends on EMBEDDED6xx
 
-config KATANA
-	bool "Artesyn-Katana"
-	help
-	  Select KATANA if configuring an Artesyn KATANA 750i or 3750
-	  cPCI board.
-
-config WILLOW
-	bool "Cogent-Willow"
-
-config CPCI690
-	bool "Force-CPCI690"
-	help
-	  Select CPCI690 if configuring a Force CPCI690 cPCI board.
-
-config POWERPMC250
-	bool "Force-PowerPMC250"
-
-config CHESTNUT
-	bool "IBM 750FX Eval board or 750GX Eval board"
-	help
-	  Select CHESTNUT if configuring an IBM 750FX Eval Board or a
-	  IBM 750GX Eval board.
-
-config SPRUCE
-	bool "IBM-Spruce"
-	select PPC_INDIRECT_PCI
-
-config HDPU
-	bool "Sky-HDPU"
-	help
-	  Select HDPU if configuring a Sky Computers Compute Blade.
-
-config HDPU_FEATURES
-	depends on HDPU
-	tristate "HDPU-Features"
-	help
-	  Select to enable HDPU enhanced features.
-
-config EV64260
-	bool "Marvell-EV64260BP"
-	help
-	  Select EV64260 if configuring a Marvell (formerly Galileo)
-	  EV64260BP Evaluation platform.
-
-config LOPEC
-	bool "Motorola-LoPEC"
-	select PPC_I8259
-
-config MVME5100
-	bool "Motorola-MVME5100"
-	select PPC_INDIRECT_PCI
-
-config PPLUS
-	bool "Motorola-PowerPlus"
-	select PPC_I8259
-	select PPC_INDIRECT_PCI
-
-config PRPMC750
-	bool "Motorola-PrPMC750"
-	select PPC_INDIRECT_PCI
-
-config PRPMC800
-	bool "Motorola-PrPMC800"
-	select PPC_INDIRECT_PCI
-
-config SANDPOINT
-	bool "Motorola-Sandpoint"
-	select PPC_I8259
-	help
-	  Select SANDPOINT if configuring for a Motorola Sandpoint X3
-	  (any flavor).
-
 config LINKSTATION
 	bool "Linkstation / Kurobox(HG) from Buffalo"
 	select MPIC
@@ -92,217 +20,37 @@ config MPC7448HPC2
 	select TSI108_BRIDGE
 	select DEFAULT_UIMAGE
 	select PPC_UDBG_16550
-	select MPIC
-	select MPIC_WEIRD
 	help
 	  Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
 	  platform
 
-config RADSTONE_PPC7D
-	bool "Radstone Technology PPC7D board"
-	select PPC_I8259
-
-config PAL4
-	bool "SBS-Palomar4"
-
-config EST8260
-	bool "EST8260"
-	---help---
-	  The EST8260 is a single-board computer manufactured by Wind River
-	  Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
-	  the MPC8260.  Wind River Systems has a website at
-	  <http://www.windriver.com/>, but the EST8260 cannot be found on it
-	  and has probably been discontinued or rebadged.
-
-config SBC82xx
-	bool "SBC82xx"
-	---help---
-	  SBC PowerQUICC II, single-board computer with MPC82xx CPU
-	  Manufacturer: Wind River Systems, Inc.
-	  Date of Release: May 2003
-	  End of Life: -
-	  URL: <http://www.windriver.com/>
-
-config SBS8260
-	bool "SBS8260"
-
-config RPX8260
-	bool "RPXSUPER"
-
-config TQM8260
-	bool "TQM8260"
-	---help---
-	  MPC8260 based module, little larger than credit card,
-	  up to 128 MB global + 64 MB local RAM, 32 MB Flash,
-	  32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet,
-	  2 x serial ports, ...
-	  Manufacturer: TQ Components, www.tq-group.de
-	  Date of Release: June 2001
-	  End of Life: not yet :-)
-	  URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
-
-config ADS8272
-	bool "ADS8272"
-
-config PQ2FADS
-	bool "Freescale-PQ2FADS"
-	help
-	  Select PQ2FADS if you wish to configure for a Freescale
-	  PQ2FADS board (-VR or -ZU).
-
-config EV64360
-	bool "Marvell-EV64360BP"
+config PPC_HOLLY
+	bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)"
+	select TSI108_BRIDGE
+	select PPC_UDBG_16550
 	help
-	  Select EV64360 if configuring a Marvell EV64360BP Evaluation
-	  platform.
+	  Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
+	  Board with TSI108/9 bridge (Hickory/Holly)
 endchoice
 
-config PQ2ADS
-	bool
-	depends on ADS8272
-	default y
-
-config TQM8xxL
-	bool
-	depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
-	default y
-
-config 8260
-	bool "CPM2 Support" if WILLOW
-	depends on 6xx
-	default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS
-	help
-	  The MPC8260 is a typical embedded CPU made by Motorola.  Selecting
-	  this option means that you wish to build a kernel for a machine with
-	  an 8260 class CPU.
-
-config 8272
-	bool
-	depends on 6xx
-	default y if ADS8272
-	select 8260
-	help
-	  The MPC8272 CPM has a different internal dpram setup than other CPM2
-	  devices
-
-config CPM2
-	bool
-	depends on 8260 || MPC8560 || MPC8555
-	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 (826x, 827x, 8560).
-
-config PPC_GEN550
-	bool
-	depends on SANDPOINT || SPRUCE || PPLUS || \
-		PRPMC750 || PRPMC800 || LOPEC || \
-		(EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
-		83xx || LINKSTATION
-	default y
-
-config FORCE
-	bool
-	depends on 6xx && POWERPMC250
-	default y
-
-config GT64260
-	bool
-	depends on EV64260 || CPCI690
-	default y
-
-config MV64360		# Really MV64360 & MV64460
-	bool
-	depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
-	default y
-
-config MV64X60
-	bool
-	depends on (GT64260 || MV64360)
-	select PPC_INDIRECT_PCI
-	default y
-
 config TSI108_BRIDGE
 	bool
-	depends on MPC7448HPC2
-	default y
-
-menu "Set bridge options"
-	depends on MV64X60
-
-config NOT_COHERENT_CACHE
-	bool "Turn off Cache Coherency"
-	default n
-	help
-	  Some 64x60 bridges lock up when trying to enforce cache coherency.
-	  When this option is selected, cache coherency will be turned off.
-	  Note that this can cause other problems (e.g., stale data being
-	  speculatively loaded via a cached mapping).  Use at your own risk.
-
-config MV64X60_BASE
-	hex "Set bridge base used by firmware"
-	default "0xf1000000"
-	help
-	  A firmware can leave the base address of the bridge's registers at
-	  a non-standard location.  If so, set this value to reflect the
-	  address of that non-standard location.
-
-config MV64X60_NEW_BASE
-	hex "Set bridge base used by kernel"
-	default "0xf1000000"
-	help
-	  If the current base address of the bridge's registers is not where
-	  you want it, set this value to the address that you want it moved to.
-
-endmenu
-
-config NONMONARCH_SUPPORT
-	bool "Enable Non-Monarch Support"
-	depends on PRPMC800
-
-config HARRIER
-	bool
-	depends on PRPMC800
-	default y
-
-config EPIC_SERIAL_MODE
-	bool
-	depends on 6xx && (LOPEC || SANDPOINT)
+	depends on MPC7448HPC2 || PPC_HOLLY
+	select MPIC
+	select MPIC_WEIRD
 	default y
 
 config MPC10X_BRIDGE
 	bool
-	depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+	depends on LINKSTATION
 	select PPC_INDIRECT_PCI
 	default y
 
 config MPC10X_OPENPIC
 	bool
-	depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+	depends on LINKSTATION
 	default y
 
 config MPC10X_STORE_GATHERING
 	bool "Enable MPC10x store gathering"
 	depends on MPC10X_BRIDGE
-
-config SANDPOINT_ENABLE_UART1
-	bool "Enable DUART mode on Sandpoint"
-	depends on SANDPOINT
-	help
-	  If this option is enabled then the MPC824x processor will run
-	  in DUART mode instead of UART mode.
-
-config HARRIER_STORE_GATHERING
-	bool "Enable Harrier store gathering"
-	depends on HARRIER
-
-config MVME5100_IPMC761_PRESENT
-	bool "MVME5100 configured with an IPMC761"
-	depends on MVME5100
-	select PPC_I8259
-
-config SPRUCE_BAUD_33M
-	bool "Spruce baud clock support"
-	depends on SPRUCE
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index d3d11a3..b39fe4f 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -3,3 +3,4 @@ # Makefile for the 6xx/7xx/7xxxx linux k
 #
 obj-$(CONFIG_MPC7448HPC2)	+= mpc7448_hpc2.o
 obj-$(CONFIG_LINKSTATION)	+= linkstation.o ls_uart.o
+obj-$(CONFIG_PPC_HOLLY)		+= holly.o
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
new file mode 100644
index 0000000..3a0b4a0
--- /dev/null
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -0,0 +1,317 @@
+/*
+ * Board setup routines for the IBM 750GX/CL platform w/ TSI10x bridge
+ *
+ * Copyright 2007 IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * Based on code from mpc7448_hpc2.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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/tsi108.h>
+#include <asm/pci-bridge.h>
+#include <asm/reg.h>
+#include <mm/mmu_decl.h>
+#include <asm/tsi108_irq.h>
+#include <asm/tsi108_pci.h>
+#include <asm/mpic.h>
+#include <asm/of_platform.h>
+
+#undef DEBUG
+
+#define HOLLY_PCI_CFG_PHYS 0x7c000000
+
+int holly_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 holly_remap_bridge(void)
+{
+	u32 lut_val, lut_addr;
+	int i;
+
+	printk(KERN_INFO "Remapping PCI bridge\n");
+
+	/* Re-init the PCI bridge and LUT registers to have mappings that don't
+	 * rely on PIBS
+	 */
+	lut_addr = 0x900;
+	for (i = 0; i < 31; i++) {
+		tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000201);
+		lut_addr += 4;
+		tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
+		lut_addr += 4;
+	}
+
+	/* Reserve the last LUT entry for PCI I/O space */
+	tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000241);
+	lut_addr += 4;
+	tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
+
+	/* Map PCI I/O space */
+	tsi108_write_reg(TSI108_PCI_PFAB_IO_UPPER, 0x0);
+	tsi108_write_reg(TSI108_PCI_PFAB_IO, 0x1);
+
+	/* Map PCI CFG space */
+	tsi108_write_reg(TSI108_PCI_PFAB_BAR0_UPPER, 0x0);
+	tsi108_write_reg(TSI108_PCI_PFAB_BAR0, 0x7c000000 | 0x01);
+
+	/* We don't need MEM32 and PRM remapping so disable them */
+	tsi108_write_reg(TSI108_PCI_PFAB_MEM32, 0x0);
+	tsi108_write_reg(TSI108_PCI_PFAB_PFM3, 0x0);
+	tsi108_write_reg(TSI108_PCI_PFAB_PFM4, 0x0);
+
+	/* Set P2O_BAR0 */
+	tsi108_write_reg(TSI108_PCI_P2O_BAR0_UPPER, 0x0);
+	tsi108_write_reg(TSI108_PCI_P2O_BAR0, 0xc0000000);
+
+	/* Init the PCI LUTs to do no remapping */
+	lut_addr = 0x500;
+	lut_val = 0x00000002;
+
+	for (i = 0; i < 32; i++) {
+		tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, lut_val);
+		lut_addr += 4;
+		tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, 0x40000000);
+		lut_addr += 4;
+		lut_val += 0x02000000;
+	}
+	tsi108_write_reg(TSI108_PCI_P2O_PAGE_SIZES, 0x00007900);
+
+	/* Set 64-bit PCI bus address for system memory */
+	tsi108_write_reg(TSI108_PCI_P2O_BAR2_UPPER, 0x0);
+	tsi108_write_reg(TSI108_PCI_P2O_BAR2, 0x0);
+}
+
+static void __init holly_setup_arch(void)
+{
+	struct device_node *cpu;
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("holly_setup_arch():set_bridge", 0);
+
+	cpu = of_find_node_by_type(NULL, "cpu");
+	if (cpu) {
+		const unsigned int *fp;
+
+		fp = of_get_property(cpu, "clock-frequency", NULL);
+		if (fp)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(cpu);
+	}
+	tsi108_csr_vir_base = get_vir_csrbase();
+
+	/* setup PCI host bridge */
+	holly_remap_bridge();
+
+	np = of_find_node_by_type(NULL, "pci");
+	if (np)
+		tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1);
+
+	ppc_md.pci_exclude_device = holly_exclude_device;
+	if (ppc_md.progress)
+		ppc_md.progress("tsi108: resources set", 0x100);
+
+	printk(KERN_INFO "PPC750GX/CL Platform\n");
+}
+
+/*
+ * Interrupt setup and service.  Interrrupts on the holly come
+ * from the four external INT pins, PCI interrupts are routed via
+ * PCI interrupt control registers, it generates internal IRQ23
+ *
+ * Interrupt routing on the Holly Board:
+ * TSI108:PB_INT[0] -> CPU0:INT#
+ * TSI108:PB_INT[1] -> CPU0:MCP#
+ * TSI108:PB_INT[2] -> N/C
+ * TSI108:PB_INT[3] -> N/C
+ */
+static void __init holly_init_IRQ(void)
+{
+	struct mpic *mpic;
+	phys_addr_t mpic_paddr = 0;
+	struct device_node *tsi_pic;
+#ifdef CONFIG_PCI
+	unsigned int cascade_pci_irq;
+	struct device_node *tsi_pci;
+	struct device_node *cascade_node = NULL;
+#endif
+
+	tsi_pic = of_find_node_by_type(NULL, "open-pic");
+	if (tsi_pic) {
+		unsigned int size;
+		const void *prop = of_get_property(tsi_pic, "reg", &size);
+		mpic_paddr = of_translate_address(tsi_pic, prop);
+	}
+
+	if (mpic_paddr == 0) {
+		printk(KERN_ERR "%s: No tsi108 PIC found !\n", __func__);
+		return;
+	}
+
+	pr_debug("%s: tsi108 pic phys_addr = 0x%x\n", __func__, (u32) mpic_paddr);
+
+	mpic = mpic_alloc(tsi_pic, mpic_paddr,
+			MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+			MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
+			24,
+			NR_IRQS-4, /* num_sources used */
+			"Tsi108_PIC");
+
+	BUG_ON(mpic == NULL);
+
+	mpic_assign_isu(mpic, 0, mpic_paddr + 0x100);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_PCI
+	tsi_pci = of_find_node_by_type(NULL, "pci");
+	if (tsi_pci == NULL) {
+		printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__);
+		return;
+	}
+
+	cascade_node = of_find_node_by_type(NULL, "pic-router");
+	if (cascade_node == NULL) {
+		printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__);
+		return;
+	}
+
+	cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
+	pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq);
+	tsi108_pci_int_init(cascade_node);
+	set_irq_data(cascade_pci_irq, mpic);
+	set_irq_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
+#endif
+	/* Configure MPIC outputs to CPU0 */
+	tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
+	of_node_put(tsi_pic);
+}
+
+void holly_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: PPC750 GX/CL\n");
+}
+
+void holly_restart(char *cmd)
+{
+	__be32 __iomem *ocn_bar1 = NULL;
+	unsigned long bar;
+	struct device_node *bridge = NULL;
+	const void *prop;
+	int size;
+	phys_addr_t addr = 0xc0000000;
+
+	local_irq_disable();
+
+	bridge = of_find_node_by_type(NULL, "tsi-bridge");
+	if (bridge) {
+		prop = of_get_property(bridge, "reg", &size);
+		addr = of_translate_address(bridge, prop);
+	}
+	addr += (TSI108_PB_OFFSET + 0x414);
+
+	ocn_bar1 = ioremap(addr, 0x4);
+
+	/* Turn on the BOOT bit so the addresses are correctly
+	 * routed to the HLP interface */
+	bar = ioread32be(ocn_bar1);
+	bar |= 2;
+	iowrite32be(bar, ocn_bar1);
+	iosync();
+
+	/* Set SRR0 to the reset vector and turn on MSR_IP */
+	mtspr(SPRN_SRR0, 0xfff00100);
+	mtspr(SPRN_SRR1, MSR_IP);
+
+	/* Do an rfi to jump back to firmware.  Somewhat evil,
+	 * but it works
+	 */
+	__asm__ __volatile__("rfi" : : : "memory");
+
+	/* Spin until reset happens.  Shouldn't really get here */
+	for (;;) ;
+}
+
+void holly_power_off(void)
+{
+	local_irq_disable();
+	/* No way to shut power off with software */
+	for (;;) ;
+}
+
+void holly_halt(void)
+{
+	holly_power_off();
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init holly_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "ibm,holly"))
+		return 0;
+	return 1;
+}
+
+static int ppc750_machine_check_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *entry;
+
+	/* Are we prepared to handle this fault */
+	if ((entry = search_exception_tables(regs->nip)) != NULL) {
+		tsi108_clear_pci_cfg_error();
+		regs->msr |= MSR_RI;
+		regs->nip = entry->fixup;
+		return 1;
+	}
+	return 0;
+}
+
+define_machine(holly){
+	.name                   	= "PPC750 GX/CL TSI",
+	.probe                  	= holly_probe,
+	.setup_arch             	= holly_setup_arch,
+	.init_IRQ               	= holly_init_IRQ,
+	.show_cpuinfo           	= holly_show_cpuinfo,
+	.get_irq                	= mpic_get_irq,
+	.restart                	= holly_restart,
+	.calibrate_decr         	= generic_calibrate_decr,
+	.machine_check_exception	= ppc750_machine_check_exception,
+	.progress               	= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index 3f6c411..b412f00 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -58,11 +58,11 @@ static int __init add_bridge(struct devi
 {
 	int len;
 	struct pci_controller *hose;
-	int *bus_range;
+	const int *bus_range;
 
 	printk("Adding PCI host bridge %s\n", dev->full_name);
 
-	bus_range = (int *) get_property(dev, "bus-range", &len);
+	bus_range = of_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);
@@ -106,7 +106,7 @@ static void __init linkstation_init_IRQ(
 {
 	struct mpic *mpic;
 	struct device_node *dnp;
-	void *prop;
+	const u32 *prop;
 	int size;
 	phys_addr_t paddr;
 
@@ -114,7 +114,7 @@ static void __init linkstation_init_IRQ(
 	if (dnp == NULL)
 		return;
 
-	prop = (struct device_node *)get_property(dnp, "reg", &size);
+	prop = of_get_property(dnp, "reg", &size);
 	paddr = (phys_addr_t)of_translate_address(dnp, prop);
 
 	mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC     ");
diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c
index 0e83776..d0bee9f 100644
--- a/arch/powerpc/platforms/embedded6xx/ls_uart.c
+++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c
@@ -110,8 +110,8 @@ static int __init ls_uarts_init(void)
 	if (!avr)
 		return -EINVAL;
 
-	avr_clock = *(u32*)get_property(avr, "clock-frequency", &len);
-	phys_addr = ((u32*)get_property(avr, "reg", &len))[0];
+	avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
+	phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
 
 	if (!avr_clock || !phys_addr)
 		return -EINVAL;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 3fcc85f..4542e0c 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -25,7 +25,6 @@ #include <linux/kdev_t.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/ide.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/serial.h>
@@ -42,6 +41,7 @@ #include <asm/pci-bridge.h>
 #include <asm/reg.h>
 #include <mm/mmu_decl.h>
 #include "mpc7448_hpc2.h"
+#include <asm/tsi108_pci.h>
 #include <asm/tsi108_irq.h>
 #include <asm/mpic.h>
 
@@ -52,16 +52,15 @@ #else
 #define DBG(fmt...) do { } while(0)
 #endif
 
+#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000
+
 #ifndef CONFIG_PCI
 isa_io_base = MPC7448_HPC2_ISA_IO_BASE;
 isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE;
 pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET;
 #endif
 
-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(struct device_node *node);
-extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
 
 int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
 {
@@ -73,38 +72,16 @@ int mpc7448_hpc2_exclude_device(u_char b
 
 static void __init mpc7448_hpc2_setup_arch(void)
 {
-	struct device_node *cpu;
 	struct device_node *np;
 	if (ppc_md.progress)
 		ppc_md.progress("mpc7448_hpc2_setup_arch():set_bridge", 0);
 
-	cpu = of_find_node_by_type(NULL, "cpu");
-	if (cpu != 0) {
-		const unsigned int *fp;
-
-		fp = get_property(cpu, "clock-frequency", NULL);
-		if (fp != 0)
-			loops_per_jiffy = *fp / HZ;
-		else
-			loops_per_jiffy = 50000000 / HZ;
-		of_node_put(cpu);
-	}
 	tsi108_csr_vir_base = get_vir_csrbase();
 
-#ifdef	CONFIG_ROOT_NFS
-	ROOT_DEV = Root_NFS;
-#else
-	ROOT_DEV = Root_HDA1;
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	ROOT_DEV = Root_RAM0;
-#endif
-
 	/* setup PCI host bridge */
 #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
-		tsi108_setup_pci(np);
+		tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0);
 
 	ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device;
 	if (ppc_md.progress)
@@ -143,7 +120,7 @@ #endif
 	tsi_pic = of_find_node_by_type(NULL, "open-pic");
 	if (tsi_pic) {
 		unsigned int size;
-		const void *prop = get_property(tsi_pic, "reg", &size);
+		const void *prop = of_get_property(tsi_pic, "reg", &size);
 		mpic_paddr = of_translate_address(tsi_pic, prop);
 	}
 
@@ -233,7 +210,6 @@ static int __init mpc7448_hpc2_probe(voi
 
 static int mpc7448_machine_check_exception(struct pt_regs *regs)
 {
-	extern void tsi108_clear_pci_cfg_error(void);
 	const struct exception_table_entry *entry;
 
 	/* Are we prepared to handle this fault */
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 54e6b3b..46c3a8e 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -1,3 +1,7 @@
+config PPC_ISERIES
+	bool "IBM Legacy iSeries"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_INDIRECT_IO
 
 menu "iSeries device drivers"
 	depends on PPC_ISERIES
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index d7a756d..3b6a966 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -171,7 +171,7 @@ void iommu_devnode_init_iSeries(struct p
 {
 	struct iommu_table *tbl;
 	struct pci_dn *pdn = PCI_DN(dn);
-	const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
+	const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
 
 	BUG_ON(lsn == NULL);
 
@@ -194,5 +194,5 @@ void iommu_init_early_iSeries(void)
 	ppc_md.tce_build = tce_build_iSeries;
 	ppc_md.tce_free  = tce_free_iSeries;
 
-	pci_dma_ops = &dma_iommu_ops;
+	set_pci_dma_ops(&dma_iommu_ops);
 }
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 5225abf..63b3367 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -30,7 +30,6 @@ #include <linux/smp.h>
 #include <linux/param.h>
 #include <linux/string.h>
 #include <linux/bootmem.h>
-#include <linux/ide.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 
@@ -337,6 +336,8 @@ #endif
 	return irq;
 }
 
+#ifdef CONFIG_PCI
+
 static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
 				irq_hw_number_t hw)
 {
@@ -384,3 +385,4 @@ void __init iSeries_init_IRQ(void)
 				"failed with rc 0x%x\n", ret);
 }
 
+#endif	/* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 4a06d9c..9c97422 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -24,7 +24,6 @@ #include <linux/list.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 
 #include <asm/io.h>
@@ -177,7 +176,7 @@ void __init iSeries_pci_final_fixup(void
 			struct pci_dn *pdn = PCI_DN(node);
 			const u32 *agent;
 
-			agent = get_property(node, "linux,agent-id", NULL);
+			agent = of_get_property(node, "linux,agent-id", NULL);
 			if ((pdn != NULL) && (agent != NULL)) {
 				u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
 						pdn->bussubno);
@@ -755,7 +754,7 @@ void __init iSeries_pcibios_init(void)
 		if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
 			continue;
 
-		busp = get_property(node, "bus-range", NULL);
+		busp = of_get_property(node, "bus-range", NULL);
 		if (busp == NULL)
 			continue;
 		bus = *busp;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index cce7e30..7f5dcee 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -628,15 +628,6 @@ static void iseries_iounmap(volatile voi
 {
 }
 
-/*
- * 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();
@@ -667,7 +658,6 @@ define_machine(iseries) {
 	.calibrate_decr	= generic_calibrate_decr,
 	.progress	= iSeries_progress,
 	.probe		= iseries_probe,
-	.check_legacy_ioport	= iseries_check_legacy_ioport,
 	.ioremap	= iseries_ioremap,
 	.iounmap	= iseries_iounmap,
 	/* XXX Implement enable_pmcs for iSeries */
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index aee5908..722335e 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -18,7 +18,6 @@ #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index e2100ec..354b8dd 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -36,7 +36,6 @@ #include <linux/proc_fs.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
 #include <asm/system.h>
@@ -155,7 +154,7 @@ static int proc_viopath_show(struct seq_
 	node = of_find_node_by_path("/");
 	sysid = NULL;
 	if (node != NULL)
-		sysid = get_property(node, "system-id", NULL);
+		sysid = of_get_property(node, "system-id", NULL);
 
 	if (sysid == NULL)
 		seq_printf(m, "SRLNBR=<UNKNOWN>\n");
diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig
new file mode 100644
index 0000000..f7c95eb
--- /dev/null
+++ b/arch/powerpc/platforms/maple/Kconfig
@@ -0,0 +1,17 @@
+config PPC_MAPLE
+	depends on PPC_MULTIPLATFORM && PPC64
+	bool "Maple 970FX Evaluation Board"
+	select MPIC
+	select U3_DART
+	select MPIC_U3_HT_IRQS
+	select GENERIC_TBSYNC
+	select PPC_UDBG_16550
+	select PPC_970_NAP
+	select PPC_NATIVE
+	select PPC_RTAS
+	select MMIO_NVRAM
+	select ATA_NONSTANDARD if ATA
+	default n
+	help
+          This option enables support for the Maple 970FX Evaluation Board.
+	  For more information, refer to <http://www.970eval.com>
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 73c5990..7aaa5bb 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -44,11 +44,11 @@ static int __init fixup_one_level_bus_ra
 		int len;
 
 		/* For PCI<->PCI bridges or CardBus bridges, we go down */
-		class_code = get_property(node, "class-code", NULL);
+		class_code = of_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 = get_property(node, "bus-range", &len);
+		bus_range = of_get_property(node, "bus-range", &len);
 		if (bus_range != NULL && len > 2 * sizeof(int)) {
 			if (bus_range[1] > higher)
 				higher = bus_range[1];
@@ -77,7 +77,7 @@ static void __init fixup_bus_range(struc
 			       bridge->full_name);
 		return;
 	}
-	bus_range = (int *)prop->value;
+	bus_range = prop->value;
 	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -454,7 +454,7 @@ static int __init add_bridge(struct devi
 
 	DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-	bus_range = get_property(dev, "bus-range", &len);
+	bus_range = of_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);
@@ -467,15 +467,15 @@ static int __init add_bridge(struct devi
 	hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
 	disp_name = NULL;
-	if (device_is_compatible(dev, "u3-agp")) {
+	if (of_device_is_compatible(dev, "u3-agp")) {
 		setup_u3_agp(hose);
 		disp_name = "U3-AGP";
 		primary = 0;
-	} else if (device_is_compatible(dev, "u3-ht")) {
+	} else if (of_device_is_compatible(dev, "u3-ht")) {
 		setup_u3_ht(hose);
 		disp_name = "U3-HT";
 		primary = 1;
-        } else if (device_is_compatible(dev, "u4-pcie")) {
+        } else if (of_device_is_compatible(dev, "u4-pcie")) {
                 setup_u4_pcie(hose);
                 disp_name = "U4-PCIE";
                 primary = 0;
@@ -556,12 +556,12 @@ void __init maple_pci_init(void)
 			continue;
 		if (strcmp(np->type, "pci") && strcmp(np->type, "ht"))
 			continue;
-		if ((device_is_compatible(np, "u4-pcie") ||
-		     device_is_compatible(np, "u3-agp")) &&
+		if ((of_device_is_compatible(np, "u4-pcie") ||
+		     of_device_is_compatible(np, "u3-agp")) &&
 		    add_bridge(np) == 0)
 			of_node_get(np);
 
-		if (device_is_compatible(np, "u3-ht")) {
+		if (of_device_is_compatible(np, "u3-ht")) {
 			of_node_get(np);
 			ht = np;
 		}
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 82d3f9e..354c058 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -32,7 +32,6 @@ #include <linux/major.h>
 #include <linux/initrd.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
@@ -114,8 +113,8 @@ static void maple_restart(char *cmd)
 		printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
 		goto fail;
 	}
-	maple_nvram_offset = get_property(sp, "restart-addr", NULL);
-	maple_nvram_command = get_property(sp, "restart-value", NULL);
+	maple_nvram_offset = of_get_property(sp, "restart-addr", NULL);
+	maple_nvram_command = of_get_property(sp, "restart-value", NULL);
 	of_node_put(sp);
 
 	/* send command */
@@ -141,8 +140,8 @@ static void maple_power_off(void)
 		printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
 		goto fail;
 	}
-	maple_nvram_offset = get_property(sp, "power-off-addr", NULL);
-	maple_nvram_command = get_property(sp, "power-off-value", NULL);
+	maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL);
+	maple_nvram_command = of_get_property(sp, "power-off-value", NULL);
 	of_node_put(sp);
 
 	/* send command */
@@ -232,7 +231,7 @@ static void __init maple_init_IRQ(void)
 	 */
 
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "open-pic")) {
+		if (of_device_is_compatible(np, "open-pic")) {
 			mpic_node = np;
 			break;
 		}
@@ -249,8 +248,8 @@ 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 = get_property(root, "platform-open-pic", &opplen);
+	naddr = of_n_addr_cells(root);
+	opprop = of_get_property(root, "platform-open-pic", &opplen);
 	if (opprop != 0) {
 		openpic_addr = of_read_number(opprop, naddr);
 		has_isus = (opplen > naddr);
@@ -261,11 +260,11 @@ static void __init maple_init_IRQ(void)
 	BUG_ON(openpic_addr == 0);
 
 	/* Check for a big endian MPIC */
-	if (get_property(np, "big-endian", NULL) != NULL)
+	if (of_get_property(np, "big-endian", NULL) != NULL)
 		flags |= MPIC_BIG_ENDIAN;
 
 	/* XXX Maple specific bits */
-	flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET;
+	flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
 	/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
 	flags |= MPIC_BIG_ENDIAN;
 
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 68dc529..eb4dbc7 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -1,3 +1,15 @@
+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
+	select PPC_NATIVE
+	help
+	  This option enables support for PA Semi's PWRficient line
+	  of SoC processors, including PA6T-1682M
+
 menu "PA Semi PWRficient options"
 	depends on PPC_PASEMI
 
@@ -7,4 +19,11 @@ config PPC_PASEMI_IOMMU
 	help
 	  IOMMU support for PA6T-1682M
 
+config PPC_PASEMI_MDIO
+	depends on PHYLIB
+	tristate "MDIO support via GPIO"
+	default y
+	help
+	  Driver for MDIO via GPIO on PWRficient platforms
+
 endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index e657cca..2cd2a4f 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,2 +1,3 @@
 obj-y	+= setup.o pci.o time.o idle.o powersave.o iommu.o
-
+obj-$(CONFIG_PPC_PASEMI_MDIO)	+= gpio_mdio.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
new file mode 100644
index 0000000..3ae0838
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Authors: Egor Martovetsky <egor@pasemi.com>
+ *	    Olof Johansson <olof@lixom.net>
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c:
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/cpufreq.h>
+#include <linux/timer.h>
+
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+#define SDCASR_REG		0x0100
+#define SDCASR_REG_STRIDE	0x1000
+#define SDCPWR_CFGA0_REG	0x0100
+#define SDCPWR_PWST0_REG	0x0000
+#define SDCPWR_GIZTIME_REG	0x0440
+
+/* SDCPWR_GIZTIME_REG fields */
+#define SDCPWR_GIZTIME_GR	0x80000000
+#define SDCPWR_GIZTIME_LONGLOCK	0x000000ff
+
+/* Offset of ASR registers from SDC base */
+#define SDCASR_OFFSET		0x120000
+
+static void __iomem *sdcpwr_mapbase;
+static void __iomem *sdcasr_mapbase;
+
+static DEFINE_MUTEX(pas_switch_mutex);
+
+/* Current astate, is used when waking up from power savings on
+ * one core, in case the other core has switched states during
+ * the idle time.
+ */
+static int current_astate;
+
+/* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */
+static struct cpufreq_frequency_table pas_freqs[] = {
+	{0,	0},
+	{1,	0},
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+static struct freq_attr *pas_cpu_freqs_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+/*
+ * hardware specific functions
+ */
+
+static int get_astate_freq(int astate)
+{
+	u32 ret;
+	ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10));
+
+	return ret & 0x3f;
+}
+
+static int get_cur_astate(int cpu)
+{
+	u32 ret;
+
+	ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG);
+	ret = (ret >> (cpu * 4)) & 0x7;
+
+	return ret;
+}
+
+static int get_gizmo_latency(void)
+{
+	u32 giztime, ret;
+
+	giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG);
+
+	/* just provide the upper bound */
+	if (giztime & SDCPWR_GIZTIME_GR)
+		ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000;
+	else
+		ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000;
+
+	return ret;
+}
+
+static void set_astate(int cpu, unsigned int astate)
+{
+	u64 flags;
+
+	/* Return if called before init has run */
+	if (unlikely(!sdcasr_mapbase))
+		return;
+
+	local_irq_save(flags);
+
+	out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate);
+
+	local_irq_restore(flags);
+}
+
+void restore_astate(int cpu)
+{
+	set_astate(cpu, current_astate);
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	const u32 *max_freqp;
+	u32 max_freq;
+	int i, cur_astate;
+	struct resource res;
+	struct device_node *cpu, *dn;
+	int err = -ENODEV;
+
+	cpu = of_get_cpu_node(policy->cpu, NULL);
+
+	if (!cpu)
+		goto out;
+
+	dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc");
+	if (!dn)
+		goto out;
+	err = of_address_to_resource(dn, 0, &res);
+	of_node_put(dn);
+	if (err)
+		goto out;
+	sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000);
+	if (!sdcasr_mapbase) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo");
+	if (!dn) {
+		err = -ENODEV;
+		goto out_unmap_sdcasr;
+	}
+	err = of_address_to_resource(dn, 0, &res);
+	of_node_put(dn);
+	if (err)
+		goto out_unmap_sdcasr;
+	sdcpwr_mapbase = ioremap(res.start, 0x1000);
+	if (!sdcpwr_mapbase) {
+		err = -EINVAL;
+		goto out_unmap_sdcasr;
+	}
+
+	pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+
+	max_freqp = of_get_property(cpu, "clock-frequency", NULL);
+	if (!max_freqp) {
+		err = -EINVAL;
+		goto out_unmap_sdcpwr;
+	}
+
+	/* we need the freq in kHz */
+	max_freq = *max_freqp / 1000;
+
+	pr_debug("max clock-frequency is at %u kHz\n", max_freq);
+	pr_debug("initializing frequency table\n");
+
+	/* initialize frequency table */
+	for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
+		pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000;
+		pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+	}
+
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	policy->cpuinfo.transition_latency = get_gizmo_latency();
+
+	cur_astate = get_cur_astate(policy->cpu);
+	pr_debug("current astate is at %d\n",cur_astate);
+
+	policy->cur = pas_freqs[cur_astate].frequency;
+	policy->cpus = cpu_online_map;
+
+	ppc_proc_freq = policy->cur * 1000ul;
+
+	cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu);
+
+	/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max
+	 * are set correctly
+	 */
+	return cpufreq_frequency_table_cpuinfo(policy, pas_freqs);
+
+out_unmap_sdcpwr:
+	iounmap(sdcpwr_mapbase);
+
+out_unmap_sdcasr:
+	iounmap(sdcasr_mapbase);
+out:
+	return err;
+}
+
+static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	if (sdcasr_mapbase)
+		iounmap(sdcasr_mapbase);
+	if (sdcpwr_mapbase)
+		iounmap(sdcpwr_mapbase);
+
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static int pas_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, pas_freqs);
+}
+
+static int pas_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	int pas_astate_new;
+	int i;
+
+	cpufreq_frequency_table_target(policy,
+				       pas_freqs,
+				       target_freq,
+				       relation,
+				       &pas_astate_new);
+
+	freqs.old = policy->cur;
+	freqs.new = pas_freqs[pas_astate_new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&pas_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+		 policy->cpu,
+		 pas_freqs[pas_astate_new].frequency,
+		 pas_freqs[pas_astate_new].index);
+
+	current_astate = pas_astate_new;
+
+	for_each_online_cpu(i)
+		set_astate(i, pas_astate_new);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&pas_switch_mutex);
+
+	ppc_proc_freq = freqs.new * 1000ul;
+	return 0;
+}
+
+static struct cpufreq_driver pas_cpufreq_driver = {
+	.name		= "pas-cpufreq",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+	.init		= pas_cpufreq_cpu_init,
+	.exit		= pas_cpufreq_cpu_exit,
+	.verify		= pas_cpufreq_verify,
+	.target		= pas_cpufreq_target,
+	.attr		= pas_cpu_freqs_attr,
+};
+
+/*
+ * module init and destoy
+ */
+
+static int __init pas_cpufreq_init(void)
+{
+	if (!machine_is_compatible("PA6T-1682M"))
+		return -ENODEV;
+
+	return cpufreq_register_driver(&pas_cpufreq_driver);
+}
+
+static void __exit pas_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&pas_cpufreq_driver);
+}
+
+module_init(pas_cpufreq_init);
+module_exit(pas_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
new file mode 100644
index 0000000..c91a335
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Olof Johansson, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/net/fs_enet/mii-bitbang.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/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <asm/of_platform.h>
+
+#define DELAY 1
+
+static void __iomem *gpio_regs;
+
+struct gpio_priv {
+	int mdc_pin;
+	int mdio_pin;
+};
+
+#define MDC_PIN(bus)	(((struct gpio_priv *)bus->priv)->mdc_pin)
+#define MDIO_PIN(bus)	(((struct gpio_priv *)bus->priv)->mdio_pin)
+
+static inline void mdio_lo(struct mii_bus *bus)
+{
+	out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdio_hi(struct mii_bus *bus)
+{
+	out_le32(gpio_regs, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdc_lo(struct mii_bus *bus)
+{
+	out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
+}
+
+static inline void mdc_hi(struct mii_bus *bus)
+{
+	out_le32(gpio_regs, 1 << MDC_PIN(bus));
+}
+
+static inline void mdio_active(struct mii_bus *bus)
+{
+	out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
+}
+
+static inline void mdio_tristate(struct mii_bus *bus)
+{
+	out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
+}
+
+static inline int mdio_read(struct mii_bus *bus)
+{
+	return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
+}
+
+static void clock_out(struct mii_bus *bus, int bit)
+{
+	if (bit)
+		mdio_hi(bus);
+	else
+		mdio_lo(bus);
+	udelay(DELAY);
+	mdc_hi(bus);
+	udelay(DELAY);
+	mdc_lo(bus);
+}
+
+/* Utility to send the preamble, address, and register (common to read and write). */
+static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
+{
+	int i;
+
+	/* CFE uses a really long preamble (40 bits). We'll do the same. */
+	mdio_active(bus);
+	for (i = 0; i < 40; i++) {
+		clock_out(bus, 1);
+	}
+
+	/* send the start bit (01) and the read opcode (10) or write (10) */
+	clock_out(bus, 0);
+	clock_out(bus, 1);
+
+	clock_out(bus, read);
+	clock_out(bus, !read);
+
+	/* send the PHY address */
+	for (i = 0; i < 5; i++) {
+		clock_out(bus, (addr & 0x10) != 0);
+		addr <<= 1;
+	}
+
+	/* send the register address */
+	for (i = 0; i < 5; i++) {
+		clock_out(bus, (reg & 0x10) != 0);
+		reg <<= 1;
+	}
+}
+
+static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
+{
+	u16 rdreg;
+	int ret, i;
+	u8 addr = phy_id & 0xff;
+	u8 reg = location & 0xff;
+
+	bitbang_pre(bus, 1, addr, reg);
+
+	/* tri-state our MDIO I/O pin so we can read */
+	mdio_tristate(bus);
+	udelay(DELAY);
+	mdc_hi(bus);
+	udelay(DELAY);
+	mdc_lo(bus);
+
+	/* read 16 bits of register data, MSB first */
+	rdreg = 0;
+	for (i = 0; i < 16; i++) {
+		mdc_lo(bus);
+		udelay(DELAY);
+		mdc_hi(bus);
+		udelay(DELAY);
+		mdc_lo(bus);
+		udelay(DELAY);
+		rdreg <<= 1;
+		rdreg |= mdio_read(bus);
+	}
+
+	mdc_hi(bus);
+	udelay(DELAY);
+	mdc_lo(bus);
+	udelay(DELAY);
+
+	ret = rdreg;
+
+	return ret;
+}
+
+static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+	int i;
+
+	u8 addr = phy_id & 0xff;
+	u8 reg = location & 0xff;
+	u16 value = val & 0xffff;
+
+	bitbang_pre(bus, 0, addr, reg);
+
+	/* send the turnaround (10) */
+	mdc_lo(bus);
+	mdio_hi(bus);
+	udelay(DELAY);
+	mdc_hi(bus);
+	udelay(DELAY);
+	mdc_lo(bus);
+	mdio_lo(bus);
+	udelay(DELAY);
+	mdc_hi(bus);
+	udelay(DELAY);
+
+	/* write 16 bits of register data, MSB first */
+	for (i = 0; i < 16; i++) {
+		mdc_lo(bus);
+		if (value & 0x8000)
+			mdio_hi(bus);
+		else
+			mdio_lo(bus);
+		udelay(DELAY);
+		mdc_hi(bus);
+		udelay(DELAY);
+		value <<= 1;
+	}
+
+	/*
+	 * Tri-state the MDIO line.
+	 */
+	mdio_tristate(bus);
+	mdc_lo(bus);
+	udelay(DELAY);
+	mdc_hi(bus);
+	udelay(DELAY);
+	return 0;
+}
+
+static int gpio_mdio_reset(struct mii_bus *bus)
+{
+	/*nothing here - dunno how to reset it*/
+	return 0;
+}
+
+
+static int __devinit gpio_mdio_probe(struct of_device *ofdev,
+				     const struct of_device_id *match)
+{
+	struct device *dev = &ofdev->dev;
+	struct device_node *np = ofdev->node;
+	struct device_node *gpio_np;
+	struct mii_bus *new_bus;
+	struct resource res;
+	struct gpio_priv *priv;
+	const unsigned int *prop;
+	int err = 0;
+	int i;
+
+	gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
+
+	if (!gpio_np)
+		return -ENODEV;
+
+	err = of_address_to_resource(gpio_np, 0, &res);
+	of_node_put(gpio_np);
+
+	if (err)
+		return -EINVAL;
+
+	if (!gpio_regs)
+		gpio_regs = ioremap(res.start, 0x100);
+
+	if (!gpio_regs)
+		return -EPERM;
+
+	priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+	if (new_bus == NULL)
+		return -ENOMEM;
+
+	new_bus->name = "pasemi gpio mdio bus",
+	new_bus->read = &gpio_mdio_read,
+	new_bus->write = &gpio_mdio_write,
+	new_bus->reset = &gpio_mdio_reset,
+
+	prop = of_get_property(np, "reg", NULL);
+	new_bus->id = *prop;
+	new_bus->priv = priv;
+
+	new_bus->phy_mask = 0;
+
+	new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	for(i = 0; i < PHY_MAX_ADDR; ++i)
+		new_bus->irq[i] = irq_create_mapping(NULL, 10);
+
+
+	prop = of_get_property(np, "mdc-pin", NULL);
+	priv->mdc_pin = *prop;
+
+	prop = of_get_property(np, "mdio-pin", NULL);
+	priv->mdio_pin = *prop;
+
+	new_bus->dev = dev;
+	dev_set_drvdata(dev, new_bus);
+
+	err = mdiobus_register(new_bus);
+
+	if (0 != err) {
+		printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
+				new_bus->name, err);
+		goto bus_register_fail;
+	}
+
+	return 0;
+
+bus_register_fail:
+	kfree(new_bus);
+
+	return err;
+}
+
+
+static int gpio_mdio_remove(struct of_device *dev)
+{
+	struct mii_bus *bus = dev_get_drvdata(&dev->dev);
+
+	mdiobus_unregister(bus);
+
+	dev_set_drvdata(&dev->dev, NULL);
+
+	kfree(bus->priv);
+	bus->priv = NULL;
+	kfree(bus);
+
+	return 0;
+}
+
+static struct of_device_id gpio_mdio_match[] =
+{
+	{
+		.compatible      = "gpio-mdio",
+	},
+	{},
+};
+
+static struct of_platform_driver gpio_mdio_driver =
+{
+	.name		= "gpio-mdio-bitbang",
+	.match_table	= gpio_mdio_match,
+	.probe		= gpio_mdio_probe,
+	.remove		= gpio_mdio_remove,
+};
+
+int gpio_mdio_init(void)
+{
+	return of_register_platform_driver(&gpio_mdio_driver);
+}
+
+void gpio_mdio_exit(void)
+{
+	of_unregister_platform_driver(&gpio_mdio_driver);
+}
+device_initcall(gpio_mdio_init);
+
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
index 1ca3ff3..5985ce0 100644
--- a/arch/powerpc/platforms/pasemi/idle.c
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -61,6 +61,10 @@ static int pasemi_system_reset_exception
 		/* do system reset */
 		return 0;
 	}
+
+	/* Set higher astate since we come out of power savings at 0 */
+	restore_astate(hard_smp_processor_id());
+
 	/* everything handled */
 	regs->msr |= MSR_RI;
 	return 1;
@@ -68,6 +72,11 @@ static int pasemi_system_reset_exception
 
 void __init pasemi_idle_init(void)
 {
+#ifndef CONFIG_PPC_PASEMI_CPUFREQ
+	printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n");
+	current_mode = 0;
+#endif
+
 	ppc_md.system_reset_exception = pasemi_system_reset_exception;
 	ppc_md.power_save = modes[current_mode].entry;
 	printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
index 71dbf1a..95fa6a7 100644
--- a/arch/powerpc/platforms/pasemi/iommu.c
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -249,13 +249,13 @@ #ifndef CONFIG_PPC_PASEMI_IOMMU
 	iommu_off = 1;
 #else
 	iommu_off = of_chosen &&
-			get_property(of_chosen, "linux,iommu-off", NULL);
+			of_get_property(of_chosen, "linux,iommu-off", NULL);
 #endif
 	if (iommu_off) {
 		/* Direct I/O, IOMMU off */
 		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
 		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
-		pci_dma_ops = &dma_direct_ops;
+		set_pci_dma_ops(&dma_direct_ops);
 
 		return;
 	}
@@ -266,7 +266,7 @@ #endif
 	ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
 	ppc_md.tce_build = iobmap_build;
 	ppc_md.tce_free  = iobmap_free;
-	pci_dma_ops = &dma_iommu_ops;
+	set_pci_dma_ops(&dma_iommu_ops);
 }
 
 void __init alloc_iobmap_l2(void)
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 2d3927e..be84954 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void
 extern void idle_spin(void);
 extern void idle_doze(void);
 
+/* Restore astate to last set */
+#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+extern void restore_astate(int cpu);
+#else
+static inline void restore_astate(int cpu)
+{
+}
+#endif
 
 
 #endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index 7ecb2ba..bbc6dfc 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -33,7 +33,17 @@ #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 inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
+{
+	/* Device 0 Function 0 is special: It's config space spans function 1 as
+	 * well, so allow larger offset. It's really a two-function device but the
+	 * second function does not probe.
+	 */
+	if (bus == 0 && devfn == 0)
+		return offset < 8192;
+	else
+		return offset < 4096;
+}
 
 static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
 				       u8 bus, u8 devfn, int offset)
@@ -51,7 +61,7 @@ static int pa_pxp_read_config(struct pci
 	if (!hose)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	if (!CONFIG_OFFSET_VALID(offset))
+	if (!pa_pxp_offset_valid(bus->number, devfn, offset))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
 	addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -85,7 +95,7 @@ static int pa_pxp_write_config(struct pc
 	if (!hose)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	if (!CONFIG_OFFSET_VALID(offset))
+	if (!pa_pxp_offset_valid(bus->number, devfn, offset))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
 	addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -163,19 +173,6 @@ static void __init pas_fixup_phb_resourc
 }
 
 
-void __devinit pas_pci_irq_fixup(struct pci_dev *dev)
-{
-	/* DMA is special, 84 interrupts (128 -> 211), all but 128
-	 * need to be mapped by hand here.
-	 */
-	if (dev->vendor == 0x1959 && dev->device == 0xa007) {
-		int i;
-		for (i = 129; i < 212; i++)
-			irq_create_mapping(NULL, i);
-	}
-}
-
-
 void __init pas_pci_init(void)
 {
 	struct device_node *np, *root;
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 449cf1a..c5a3f61 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -35,6 +35,7 @@ #include <asm/machdep.h>
 #include <asm/mpic.h>
 #include <asm/smp.h>
 #include <asm/time.h>
+#include <asm/of_platform.h>
 
 #include "pasemi.h"
 
@@ -101,12 +102,6 @@ #endif
 	pasemi_idle_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;
@@ -119,7 +114,7 @@ static __init void pas_init_IRQ(void)
 	mpic_node = NULL;
 
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "open-pic")) {
+		if (of_device_is_compatible(np, "open-pic")) {
 			mpic_node = np;
 			break;
 		}
@@ -136,8 +131,8 @@ static __init void pas_init_IRQ(void)
 
 	/* 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);
+	naddr = of_n_addr_cells(root);
+	opprop = of_get_property(root, "platform-open-pic", &opplen);
 	if (!opprop) {
 		printk(KERN_ERR "No platform-open-pic property.\n");
 		of_node_put(root);
@@ -147,7 +142,7 @@ static __init void pas_init_IRQ(void)
 	printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
 
 	mpic = mpic_alloc(mpic_node, openpic_addr,
-			  MPIC_PRIMARY|MPIC_LARGE_VECTORS,
+			  MPIC_PRIMARY|MPIC_LARGE_VECTORS|MPIC_WANTS_RESET,
 			  0, 0, " PAS-OPIC  ");
 	BUG_ON(!mpic);
 
@@ -209,6 +204,23 @@ static void __init pas_init_early(void)
 	iommu_init_early_pasemi();
 }
 
+static struct of_device_id pasemi_bus_ids[] = {
+	{ .type = "sdc", },
+	{},
+};
+
+static int __init pasemi_publish_devices(void)
+{
+	if (!machine_is(pasemi))
+		return 0;
+
+	/* Publish OF platform devices for SDC and other non-PCI devices */
+	of_platform_bus_probe(NULL, pasemi_bus_ids, NULL);
+
+	return 0;
+}
+device_initcall(pasemi_publish_devices);
+
 
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
@@ -237,8 +249,6 @@ define_machine(pas) {
 	.restart		= pas_restart,
 	.get_boot_time		= pas_get_boot_time,
 	.calibrate_decr		= generic_calibrate_decr,
-	.check_legacy_ioport    = pas_check_legacy_ioport,
 	.progress		= pas_progress,
 	.machine_check_exception = pas_machine_check_handler,
-	.pci_irq_fixup		= pas_pci_irq_fixup,
 };
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
new file mode 100644
index 0000000..5b7afe5
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -0,0 +1,20 @@
+config PPC_PMAC
+	bool "Apple PowerMac based machines"
+	depends on PPC_MULTIPLATFORM
+	select MPIC
+	select PPC_INDIRECT_PCI if PPC32
+	select PPC_MPC106 if PPC32
+	select PPC_NATIVE
+	default y
+
+config PPC_PMAC64
+	bool
+	depends on PPC_PMAC && POWER4
+	select MPIC
+	select U3_DART
+	select MPIC_U3_HT_IRQS
+	select GENERIC_TBSYNC
+	select PPC_970_NAP
+	default y
+
+
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index de7440e..d679964 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -56,13 +56,16 @@ struct backlight_device *pmac_backlight;
 
 int pmac_has_backlight_type(const char *type)
 {
-	struct device_node* bk_node = find_devices("backlight");
+	struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
 
 	if (bk_node) {
-		const char *prop = get_property(bk_node,
+		const char *prop = of_get_property(bk_node,
 				"backlight-control", NULL);
-		if (prop && strncmp(prop, type, strlen(type)) == 0)
+		if (prop && strncmp(prop, type, strlen(type)) == 0) {
+			of_node_put(bk_node);
 			return 1;
+		}
+		of_node_put(bk_node);
 	}
 
 	return 0;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index c2b6b41..1fe35da 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -25,7 +25,6 @@ #include <linux/slab.h>
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
-#include <linux/i2c.h>
 #include <linux/hardirq.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
@@ -421,7 +420,7 @@ static int pmac_cpufreq_cpu_init(struct 
 
 static u32 read_gpio(struct device_node *np)
 {
-	const u32 *reg = get_property(np, "reg", NULL);
+	const u32 *reg = of_get_property(np, "reg", NULL);
 	u32 offset;
 
 	if (reg == NULL)
@@ -521,13 +520,14 @@ static int pmac_cpufreq_init_MacRISC3(st
 		int lenp, rc;
 		const u32 *freqs, *ratio;
 
-		freqs = get_property(cpunode, "bus-frequencies", &lenp);
+		freqs = of_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 = get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+		ratio = of_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 = get_property(cpunode, "min-clock-frequency", NULL);
+	value = of_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 = get_property(cpunode, "max-clock-frequency", NULL);
+	value = of_get_property(cpunode, "max-clock-frequency", NULL);
 	if (!value)
 		return 1;
 	hi_freq = (*value) / 1000;
@@ -585,7 +585,7 @@ static int pmac_cpufreq_init_7447A(struc
 {
 	struct device_node *volt_gpio_np;
 
-	if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+	if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
 		return 1;
 
 	volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
@@ -614,11 +614,11 @@ static int pmac_cpufreq_init_750FX(struc
 	u32 pvr;
 	const u32 *value;
 
-	if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+	if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
 		return 1;
 
 	hi_freq = cur_freq;
-	value = get_property(cpunode, "reduced-clock-frequency", NULL);
+	value = of_get_property(cpunode, "reduced-clock-frequency", NULL);
 	if (!value)
 		return 1;
 	low_freq = (*value) / 1000;
@@ -657,19 +657,19 @@ static int __init pmac_cpufreq_setup(voi
 		return 0;
 
 	/* Assume only one CPU */
-	cpunode = find_type_devices("cpu");
+	cpunode = of_find_node_by_type(NULL, "cpu");
 	if (!cpunode)
 		goto out;
 
 	/* Get current cpu clock freq */
-	value = get_property(cpunode, "clock-frequency", NULL);
+	value = of_get_property(cpunode, "clock-frequency", NULL);
 	if (!value)
 		goto out;
 	cur_freq = (*value) / 1000;
 
 	/*  Check for 7447A based MacRISC3 */
 	if (machine_is_compatible("MacRISC3") &&
-	    get_property(cpunode, "dynamic-power-step", NULL) &&
+	    of_get_property(cpunode, "dynamic-power-step", NULL) &&
 	    PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
 		pmac_cpufreq_init_7447A(cpunode);
 	/* Check for other MacRISC3 machines */
@@ -707,6 +707,7 @@ static int __init pmac_cpufreq_setup(voi
 	else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
 		pmac_cpufreq_init_750FX(cpunode);
 out:
+	of_node_put(cpunode);
 	if (set_speed_proc == NULL)
 		return -ENODEV;
 
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 9d22361..00f5029 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -357,13 +357,13 @@ static unsigned int g5_cpufreq_get_speed
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-	if (policy->cpu != 0)
-		return -ENODEV;
-
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
-	policy->cpus = cpu_possible_map;
+	/* secondary CPUs are tied to the primary one by the
+	 * cpufreq core if in the secondary policy we tell it that
+	 * it actually must be one policy together with all others. */
+	policy->cpus = cpu_online_map;
 	cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
 
 	return cpufreq_frequency_table_cpuinfo(policy,
@@ -410,7 +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;) {
-		const u32 *reg = get_property(cpunode, "reg", NULL);
+		const u32 *reg = of_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 = get_property(cpunode, "cpu-version", NULL);
+	valp = of_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 = get_property(cpunode, "power-mode-data",&psize);
+	g5_pmode_data = of_get_property(cpunode, "power-mode-data",&psize);
 	if (!g5_pmode_data) {
 		DBG("No power-mode-data !\n");
 		goto bail_noprops;
@@ -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 = get_property(cpunode, "clock-frequency", NULL);
+	valp = of_get_property(cpunode, "clock-frequency", NULL);
 	if (!valp)
 		return -ENODEV;
 	max_freq = (*valp)/1000;
@@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(s
 	/* Lookup the cpuid eeprom node */
         cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
 	if (cpuid != NULL)
-		eeprom = get_property(cpuid, "cpuid", NULL);
+		eeprom = of_get_property(cpuid, "cpuid", NULL);
 	if (eeprom == NULL) {
 		printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
 		rc = -ENODEV;
@@ -573,13 +573,13 @@ 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;){
-		const char *loc = get_property(hwclock,
+		const char *loc = of_get_property(hwclock,
 				"hwctrl-location", NULL);
 		if (loc == NULL)
 			continue;
 		if (strcmp(loc, "CPU CLOCK"))
 			continue;
-		if (!get_property(hwclock, "platform-get-frequency", NULL))
+		if (!of_get_property(hwclock, "platform-get-frequency", NULL))
 			continue;
 		break;
 	}
@@ -638,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(s
 	 */
 
 	/* Get max frequency from device-tree */
-	valp = get_property(cpunode, "clock-frequency", NULL);
+	valp = of_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 24cc50c..f29705f 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -1044,6 +1044,7 @@ core99_reset_cpu(struct device_node *nod
 	unsigned long flags;
 	struct macio_chip *macio;
 	struct device_node *np;
+	struct device_node *cpus;
 	const int dflt_reset_lines[] = {	KL_GPIO_RESET_CPU0,
 						KL_GPIO_RESET_CPU1,
 						KL_GPIO_RESET_CPU2,
@@ -1053,12 +1054,12 @@ core99_reset_cpu(struct device_node *nod
 	if (macio->type != macio_keylargo)
 		return -ENODEV;
 
-	np = find_path_device("/cpus");
-	if (np == NULL)
+	cpus = of_find_node_by_path("/cpus");
+	if (cpus == NULL)
 		return -ENODEV;
-	for (np = np->child; np != NULL; np = np->sibling) {
-		const u32 *num = get_property(np, "reg", NULL);
-		const u32 *rst = get_property(np, "soft-reset", NULL);
+	for (np = cpus->child; np != NULL; np = np->sibling) {
+		const u32 *num = of_get_property(np, "reg", NULL);
+		const u32 *rst = of_get_property(np, "soft-reset", NULL);
 		if (num == NULL || rst == NULL)
 			continue;
 		if (param == *num) {
@@ -1066,6 +1067,7 @@ core99_reset_cpu(struct device_node *nod
 			break;
 		}
 	}
+	of_node_put(cpus);
 	if (np == NULL || reset_io == 0)
 		reset_io = dflt_reset_lines[param];
 
@@ -1095,7 +1097,7 @@ core99_usb_enable(struct device_node *no
 	    macio->type != macio_intrepid)
 		return -ENODEV;
 
-	prop = get_property(node, "AAPL,clock-id", NULL);
+	prop = of_get_property(node, "AAPL,clock-id", NULL);
 	if (!prop)
 		return -ENODEV;
 	if (strncmp(prop, "usb0u048", 8) == 0)
@@ -1416,7 +1418,7 @@ static long g5_eth_phy_reset(struct devi
 	phy = of_get_next_child(node, NULL);
 	if (!phy)
 		return -ENODEV;
-	need_reset = device_is_compatible(phy, "B5221");
+	need_reset = of_device_is_compatible(phy, "B5221");
 	of_node_put(phy);
 	if (!need_reset)
 		return 0;
@@ -1497,17 +1499,18 @@ static long g5_reset_cpu(struct device_n
 	unsigned long flags;
 	struct macio_chip *macio;
 	struct device_node *np;
+	struct device_node *cpus;
 
 	macio = &macio_chips[0];
 	if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
 		return -ENODEV;
 
-	np = find_path_device("/cpus");
-	if (np == NULL)
+	cpus = of_find_node_by_path("/cpus");
+	if (cpus == NULL)
 		return -ENODEV;
-	for (np = np->child; np != NULL; np = np->sibling) {
-		const u32 *num = get_property(np, "reg", NULL);
-		const u32 *rst = get_property(np, "soft-reset", NULL);
+	for (np = cpus->child; np != NULL; np = np->sibling) {
+		const u32 *num = of_get_property(np, "reg", NULL);
+		const u32 *rst = of_get_property(np, "soft-reset", NULL);
 		if (num == NULL || rst == NULL)
 			continue;
 		if (param == *num) {
@@ -1515,6 +1518,7 @@ static long g5_reset_cpu(struct device_n
 			break;
 		}
 	}
+	of_node_put(cpus);
 	if (np == NULL || reset_io == 0)
 		return -ENODEV;
 
@@ -2404,14 +2408,15 @@ static int __init probe_motherboard(void
 	struct macio_chip *macio = &macio_chips[0];
 	const char *model = NULL;
 	struct device_node *dt;
+	int ret = 0;
 
 	/* Lookup known motherboard type in device-tree. First try an
 	 * exact match on the "model" property, then try a "compatible"
 	 * match is none is found.
 	 */
-	dt = find_devices("device-tree");
+	dt = of_find_node_by_name(NULL, "device-tree");
 	if (dt != NULL)
-		model = get_property(dt, "model", NULL);
+		model = of_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];
@@ -2474,15 +2479,18 @@ #else /* CONFIG_POWER4 */
 		break;
 #endif /* CONFIG_POWER4 */
 	default:
-		return -ENODEV;
+		ret = -ENODEV;
+		goto done;
 	}
 found:
 #ifndef CONFIG_POWER4
 	/* Fixup Hooper vs. Comet */
 	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
 		u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
-		if (!mach_id_ptr)
-			return -ENODEV;
+		if (!mach_id_ptr) {
+			ret = -ENODEV;
+			goto done;
+		}
 		/* Here, I used to disable the media-bay on comet. It
 		 * appears this is wrong, the floppy connector is actually
 		 * a kind of media-bay and works with the current driver.
@@ -2499,18 +2507,26 @@ #ifndef CONFIG_POWER4
 	 * that all Apple OF revs did it properly, I do it the paranoid way.
 	 */
 	while (uninorth_base && uninorth_rev > 3) {
-		struct device_node *np = find_path_device("/cpus");
-		if (!np || !np->child) {
+		struct device_node *cpus = of_find_node_by_path("/cpus");
+		struct device_node *np;
+
+		if (!cpus || !cpus->child) {
 			printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+			of_node_put(cpus);
 			break;
 		}
-		np = np->child;
+		np = cpus->child;
 		/* Nap mode not supported on SMP */
-		if (np->sibling)
+		if (np->sibling) {
+			of_node_put(cpus);
 			break;
+		}
 		/* Nap mode not supported if flush-on-lock property is present */
-		if (get_property(np, "flush-on-lock", NULL))
+		if (of_get_property(np, "flush-on-lock", NULL)) {
+			of_node_put(cpus);
 			break;
+		}
+		of_node_put(cpus);
 		powersave_nap = 1;
 		printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
 		break;
@@ -2532,7 +2548,9 @@ #endif  /* CONFIG_POWER4 */
 
 
 	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-	return 0;
+done:
+	of_node_put(dt);
+	return ret;
 }
 
 /* Initialize the Core99 UniNorth host bridge and memory controller
@@ -2558,7 +2576,7 @@ static void __init probe_uninorth(void)
 	if (uninorth_node == NULL)
 		return;
 
-	addrp = get_property(uninorth_node, "reg", NULL);
+	addrp = of_get_property(uninorth_node, "reg", NULL);
 	if (addrp == NULL)
 		return;
 	address = of_translate_address(uninorth_node, addrp);
@@ -2606,7 +2624,7 @@ static void __init probe_one_macio(const
 	for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
 		if (!compat)
 			break;
-		if (device_is_compatible(node, compat))
+		if (of_device_is_compatible(node, compat))
 			break;
 	}
 	if (!node)
@@ -2642,7 +2660,7 @@ static void __init probe_one_macio(const
 		return;
 	}
 	if (type == macio_keylargo || type == macio_keylargo2) {
-		const u32 *did = get_property(node, "device-id", NULL);
+		const u32 *did = of_get_property(node, "device-id", NULL);
 		if (*did == 0x00000025)
 			type = macio_pangea;
 		if (*did == 0x0000003e)
@@ -2655,7 +2673,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 = get_property(node, "revision-id", NULL);
+	revp = of_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",
@@ -2706,11 +2724,11 @@ initial_serial_shutdown(struct device_no
 	int port_type = PMAC_SCC_ASYNC;
 	int modem = 0;
 
-	slots = get_property(np, "slot-names", &len);
-	conn = get_property(np, "AAPL,connector", &len);
+	slots = of_get_property(np, "slot-names", &len);
+	conn = of_get_property(np, "AAPL,connector", &len);
 	if (conn && (strcmp(conn, "infrared") == 0))
 		port_type = PMAC_SCC_IRDA;
-	else if (device_is_compatible(np, "cobalt"))
+	else if (of_device_is_compatible(np, "cobalt"))
 		modem = 1;
 	else if (slots && slots->count > 0) {
 		if (strcmp(slots->name, "IrDA") == 0)
@@ -2735,12 +2753,14 @@ set_initial_features(void)
 	 * differenciate them all and since that hack was there for a long
 	 * time, I'll keep it around
 	 */
-	if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+	if (macio_chips[0].type == macio_ohare) {
 		struct macio_chip *macio = &macio_chips[0];
-		MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
-	} else if (macio_chips[0].type == macio_ohare) {
-		struct macio_chip *macio = &macio_chips[0];
-		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+		np = of_find_node_by_name(NULL, "via-pmu");
+		if (np)
+			MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+		else
+			MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+		of_node_put(np);
 	} else if (macio_chips[1].type == macio_ohare) {
 		struct macio_chip *macio = &macio_chips[1];
 		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
@@ -2767,7 +2787,7 @@ #endif /* CONFIG_SMP */
 		 */
 		np = of_find_node_by_name(NULL, "ethernet");
 		while(np) {
-			if (device_is_compatible(np, "K2-GMAC"))
+			if (of_device_is_compatible(np, "K2-GMAC"))
 				g5_gmac_enable(np, 0, 1);
 			np = of_find_node_by_name(np, "ethernet");
 		}
@@ -2779,7 +2799,7 @@ #endif /* CONFIG_SMP */
 		 */
 		np = of_find_node_by_name(NULL, "firewire");
 		while(np) {
-			if (device_is_compatible(np, "pci106b,5811")) {
+			if (of_device_is_compatible(np, "pci106b,5811")) {
 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
 				g5_fw_enable(np, 0, 1);
 			}
@@ -2797,8 +2817,8 @@ #else /* CONFIG_POWER4 */
 		np = of_find_node_by_name(NULL, "ethernet");
 		while(np) {
 			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && device_is_compatible(np, "gmac"))
+			    && of_device_is_compatible(np->parent, "uni-north")
+			    && of_device_is_compatible(np, "gmac"))
 				core99_gmac_enable(np, 0, 1);
 			np = of_find_node_by_name(np, "ethernet");
 		}
@@ -2811,10 +2831,10 @@ #else /* CONFIG_POWER4 */
 		np = of_find_node_by_name(NULL, "firewire");
 		while(np) {
 			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && (device_is_compatible(np, "pci106b,18") ||
-			        device_is_compatible(np, "pci106b,30") ||
-			        device_is_compatible(np, "pci11c1,5811"))) {
+			    && of_device_is_compatible(np->parent, "uni-north")
+			    && (of_device_is_compatible(np, "pci106b,18") ||
+			        of_device_is_compatible(np, "pci106b,30") ||
+			        of_device_is_compatible(np, "pci11c1,5811"))) {
 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
 				core99_firewire_enable(np, 0, 1);
 			}
@@ -2825,22 +2845,21 @@ #else /* CONFIG_POWER4 */
 		np = of_find_node_by_name(NULL, "ata-6");
 		while(np) {
 			if (np->parent
-			    && device_is_compatible(np->parent, "uni-north")
-			    && device_is_compatible(np, "kauai-ata")) {
+			    && of_device_is_compatible(np->parent, "uni-north")
+			    && of_device_is_compatible(np, "kauai-ata")) {
 				core99_ata100_enable(np, 1);
 			}
 			np = of_find_node_by_name(np, "ata-6");
 		}
 
 		/* Switch airport off */
-		np = find_devices("radio");
-		while(np) {
+		for_each_node_by_name(np, "radio") {
 			if (np && np->parent == macio_chips[0].of_node) {
 				macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
 				core99_airport_enable(np, 0, 0);
 			}
-			np = np->next;
 		}
+		of_node_put(np);
 	}
 
 	/* On all machines that support sound PM, switch sound off */
@@ -2860,16 +2879,12 @@ #else /* CONFIG_POWER4 */
 #endif /* CONFIG_POWER4 */
 
 	/* On all machines, switch modem & serial ports off */
-	np = find_devices("ch-a");
-	while(np) {
+	for_each_node_by_name(np, "ch-a")
 		initial_serial_shutdown(np);
-		np = np->next;
-	}
-	np = find_devices("ch-b");
-	while(np) {
+	of_node_put(np);
+	for_each_node_by_name(np, "ch-b")
 		initial_serial_shutdown(np);
-		np = np->next;
-	}
+	of_node_put(np);
 }
 
 void __init
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index bfc4829..3f507ab 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -491,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 = get_property(np, "AAPL,address", NULL);
+	addrp = of_get_property(np, "AAPL,address", NULL);
 	if (addrp == NULL) {
 		printk(KERN_ERR "low_i2c: Can't find address for %s\n",
 		       np->full_name);
@@ -505,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 = get_property(np, "AAPL,address-step", NULL);
+	psteps = of_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 = get_property(np, "AAPL,i2c-rate", NULL);
+	prate = of_get_property(np, "AAPL,i2c-rate", NULL);
 	if (prate) switch(*prate) {
 	case 100:
 		host->speed = KW_I2C_MODE_100KHZ;
@@ -619,7 +619,7 @@ static void __init kw_i2c_probe(void)
 		} else {
 			for (child = NULL;
 			     (child = of_get_next_child(np, child)) != NULL;) {
-				const u32 *reg = get_property(child,
+				const u32 *reg = of_get_property(child,
 						"reg", NULL);
 				if (reg == NULL)
 					continue;
@@ -905,7 +905,7 @@ static void __init smu_i2c_probe(void)
 		if (strcmp(busnode->type, "i2c") &&
 		    strcmp(busnode->type, "i2c-bus"))
 			continue;
-		reg = get_property(busnode, "reg", NULL);
+		reg = of_get_property(busnode, "reg", NULL);
 		if (reg == NULL)
 			continue;
 
@@ -950,7 +950,8 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(s
 			if (p == bus->busnode) {
 				if (prev && bus->flags & pmac_i2c_multibus) {
 					const u32 *reg;
-					reg = get_property(prev, "reg", NULL);
+					reg = of_get_property(prev, "reg",
+								NULL);
 					if (!reg)
 						continue;
 					if (((*reg) >> 8) != bus->channel)
@@ -971,7 +972,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
 
 u8 pmac_i2c_get_dev_addr(struct device_node *device)
 {
-	const u32 *reg = get_property(device, "reg", NULL);
+	const u32 *reg = of_get_property(device, "reg", NULL);
 
 	if (reg == NULL)
 		return 0;
@@ -1206,7 +1207,7 @@ static void pmac_i2c_devscan(void (*call
 				if (strcmp(np->name, p->name))
 					continue;
 				if (p->compatible &&
-				    !device_is_compatible(np, p->compatible))
+				    !of_device_is_compatible(np, p->compatible))
 					continue;
 				if (p->quirks & pmac_i2c_quirk_skip)
 					break;
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 692945c..c6f0f9e 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -553,7 +553,7 @@ static int __init core99_nvram_setup(str
 	 * identify the chip using flash id commands and base ourselves on
 	 * a list of known chips IDs
 	 */
-	if (device_is_compatible(dp, "amd-0137")) {
+	if (of_device_is_compatible(dp, "amd-0137")) {
 		core99_erase_bank = amd_erase_bank;
 		core99_write_bank = amd_write_bank;
 	} else {
@@ -588,7 +588,7 @@ int __init pmac_nvram_init(void)
 		}
 	}
 
-	is_core_99 = device_is_compatible(dp, "nvram,flash");
+	is_core_99 = of_device_is_compatible(dp, "nvram,flash");
 	if (is_core_99) {
 		err = core99_nvram_setup(dp, r1.start);
 		goto bail;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 6fbac30..c4af9e2 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -70,11 +70,11 @@ static int __init fixup_one_level_bus_ra
 		int len;
 
 		/* For PCI<->PCI bridges or CardBus bridges, we go down */
-		class_code = get_property(node, "class-code", NULL);
+		class_code = of_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 = get_property(node, "bus-range", &len);
+		bus_range = of_get_property(node, "bus-range", &len);
 		if (bus_range != NULL && len > 2 * sizeof(int)) {
 			if (bus_range[1] > higher)
 				higher = bus_range[1];
@@ -100,7 +100,7 @@ static void __init fixup_bus_range(struc
 	if (prop == NULL || prop->length < 2 * sizeof(int))
 		return;
 
-	bus_range = (int *)prop->value;
+	bus_range = prop->value;
 	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
 }
 
@@ -246,8 +246,8 @@ static int chaos_validate_dev(struct pci
 	if (np == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
-	vendor = get_property(np, "vendor-id", NULL);
-	device = get_property(np, "device-id", NULL);
+	vendor = of_get_property(np, "vendor-id", NULL);
+	device = of_get_property(np, "device-id", NULL);
 	if (vendor == NULL || device == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
@@ -622,13 +622,14 @@ static void __init init_p2pbridge(void)
 
 	/* XXX it would be better here to identify the specific
 	   PCI-PCI bridge chip we have. */
-	if ((p2pbridge = find_devices("pci-bridge")) == 0
+	p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
+	if (p2pbridge == NULL
 	    || p2pbridge->parent == NULL
 	    || strcmp(p2pbridge->parent->name, "pci") != 0)
-		return;
+		goto done;
 	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
 		DBG("Can't find PCI infos for PCI<->PCI bridge\n");
-		return;
+		goto done;
 	}
 	/* Warning: At this point, we have not yet renumbered all busses.
 	 * So we must use OF walking to find out hose
@@ -636,16 +637,18 @@ static void __init init_p2pbridge(void)
 	hose = pci_find_hose_for_OF_device(p2pbridge);
 	if (!hose) {
 		DBG("Can't find hose for PCI<->PCI bridge\n");
-		return;
+		goto done;
 	}
 	if (early_read_config_word(hose, bus, devfn,
 				   PCI_BRIDGE_CONTROL, &val) < 0) {
 		printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
 		       " control\n");
-		return;
+		goto done;
 	}
 	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
 	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+done:
+	of_node_put(p2pbridge);
 }
 
 static void __init init_second_ohare(void)
@@ -691,17 +694,17 @@ static void __init fixup_nec_usb2(void)
 		const u32 *prop;
 		u8 bus, devfn;
 
-		prop = get_property(nec, "vendor-id", NULL);
+		prop = of_get_property(nec, "vendor-id", NULL);
 		if (prop == NULL)
 			continue;
 		if (0x1033 != *prop)
 			continue;
-		prop = get_property(nec, "device-id", NULL);
+		prop = of_get_property(nec, "device-id", NULL);
 		if (prop == NULL)
 			continue;
 		if (0x0035 != *prop)
 			continue;
-		prop = get_property(nec, "reg", NULL);
+		prop = of_get_property(nec, "reg", NULL);
 		if (prop == NULL)
 			continue;
 		devfn = (prop[0] >> 8) & 0xff;
@@ -909,7 +912,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 = get_property(dev, "bus-range", &len);
+	bus_range = of_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);
@@ -931,15 +934,15 @@ #endif
 
 	/* 64 bits only bridges */
 #ifdef CONFIG_PPC64
-	if (device_is_compatible(dev, "u3-agp")) {
+	if (of_device_is_compatible(dev, "u3-agp")) {
 		setup_u3_agp(hose);
 		disp_name = "U3-AGP";
 		primary = 0;
-	} else if (device_is_compatible(dev, "u3-ht")) {
+	} else if (of_device_is_compatible(dev, "u3-ht")) {
 		setup_u3_ht(hose);
 		disp_name = "U3-HT";
 		primary = 1;
-	} else if (device_is_compatible(dev, "u4-pcie")) {
+	} else if (of_device_is_compatible(dev, "u4-pcie")) {
 		setup_u4_pcie(hose);
 		disp_name = "U4-PCIE";
 		primary = 0;
@@ -950,7 +953,7 @@ #endif /* CONFIG_PPC64 */
 
 	/* 32 bits only bridges */
 #ifdef CONFIG_PPC32
-	if (device_is_compatible(dev, "uni-north")) {
+	if (of_device_is_compatible(dev, "uni-north")) {
 		primary = setup_uninorth(hose, &rsrc);
 		disp_name = "UniNorth";
 	} else if (strcmp(dev->name, "pci") == 0) {
@@ -1126,21 +1129,21 @@ pmac_pci_enable_device_hook(struct pci_d
 		return 0;
 
 	uninorth_child = node->parent &&
-		device_is_compatible(node->parent, "uni-north");
+		of_device_is_compatible(node->parent, "uni-north");
 
 	/* Firewire & GMAC were disabled after PCI probe, the driver is
 	 * claiming them, we must re-enable them now.
 	 */
 	if (uninorth_child && !strcmp(node->name, "firewire") &&
-	    (device_is_compatible(node, "pci106b,18") ||
-	     device_is_compatible(node, "pci106b,30") ||
-	     device_is_compatible(node, "pci11c1,5811"))) {
+	    (of_device_is_compatible(node, "pci106b,18") ||
+	     of_device_is_compatible(node, "pci106b,30") ||
+	     of_device_is_compatible(node, "pci11c1,5811"))) {
 		pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
 		pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
 		updatecfg = 1;
 	}
 	if (uninorth_child && !strcmp(node->name, "ethernet") &&
-	    device_is_compatible(node, "gmac")) {
+	    of_device_is_compatible(node, "gmac")) {
 		pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
 		updatecfg = 1;
 	}
@@ -1199,24 +1202,22 @@ #ifdef CONFIG_BLK_DEV_IDE
 	}
 #endif /* CONFIG_BLK_DEV_IDE */
 
-	nd = find_devices("firewire");
-	while (nd) {
-		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
-				   device_is_compatible(nd, "pci106b,30") ||
-				   device_is_compatible(nd, "pci11c1,5811"))
-		    && device_is_compatible(nd->parent, "uni-north")) {
+	for_each_node_by_name(nd, "firewire") {
+		if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") ||
+				   of_device_is_compatible(nd, "pci106b,30") ||
+				   of_device_is_compatible(nd, "pci11c1,5811"))
+		    && of_device_is_compatible(nd->parent, "uni-north")) {
 			pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
 			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
 		}
-		nd = nd->next;
 	}
-	nd = find_devices("ethernet");
-	while (nd) {
-		if (nd->parent && device_is_compatible(nd, "gmac")
-		    && device_is_compatible(nd->parent, "uni-north"))
+	of_node_put(nd);
+	for_each_node_by_name(nd, "ethernet") {
+		if (nd->parent && of_device_is_compatible(nd, "gmac")
+		    && of_device_is_compatible(nd->parent, "uni-north"))
 			pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-		nd = nd->next;
 	}
+	of_node_put(nd);
 }
 
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 5c6c15c..45d54b9 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -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;) {
-		const u32 *reg = get_property(gp, "reg", NULL);
+		const u32 *reg = of_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 7651f27..8543423 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -692,8 +692,7 @@ #define PP_PREFIX "platform-do-"
 		name = pp->name + plen;
 		if (strlen(name) && pp->length >= 12)
 			count += pmf_add_function_prop(dev, driverdata, name,
-						       (u32 *)pp->value,
-						       pp->length);
+						       pp->value, pp->length);
 	}
 	return count;
 }
@@ -821,7 +820,7 @@ struct pmf_function *__pmf_find_function
 	 * one, then we fallback to a direct call attempt
 	 */
 	snprintf(fname, 63, "platform-%s", name);
-	prop = get_property(target, fname, NULL);
+	prop = of_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 5e5c0e4..87cd680 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -364,7 +364,7 @@ static void __init pmac_pic_probe_oldsty
 		slave = of_find_node_by_name(master, "mac-io");
 
 		/* Check ordering of master & slave */
-		if (device_is_compatible(master, "gatwick")) {
+		if (of_device_is_compatible(master, "gatwick")) {
 			struct device_node *tmp;
 			BUG_ON(slave == NULL);
 			tmp = master;
@@ -482,14 +482,14 @@ static struct mpic * __init pmac_setup_o
 	pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
 
 	flags |= MPIC_WANTS_RESET;
-	if (get_property(np, "big-endian", NULL))
+	if (of_get_property(np, "big-endian", NULL))
 		flags |= MPIC_BIG_ENDIAN;
 
 	/* Primary Big Endian means HT interrupts. This is quite dodgy
 	 * but works until I find a better way
 	 */
 	if (master && (flags & MPIC_BIG_ENDIAN))
-		flags |= MPIC_BROKEN_U3;
+		flags |= MPIC_U3_HT_IRQS;
 
 	mpic = mpic_alloc(np, r.start, flags, 0, 0, name);
 	if (mpic == NULL)
@@ -510,7 +510,7 @@ static int __init pmac_pic_probe_mpic(vo
 	for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
 		     != NULL;) {
 		if (master == NULL &&
-		    get_property(np, "interrupts", NULL) == NULL)
+		    of_get_property(np, "interrupts", NULL) == NULL)
 			master = of_node_get(np);
 		else if (slave == NULL)
 			slave = of_node_get(np);
@@ -575,7 +575,7 @@ void __init pmac_pic_init(void)
 #ifdef CONFIG_PPC32
 	if (!pmac_newworld)
 		flags |= OF_IMAP_OLDWORLD_MAC;
-	if (get_property(of_chosen, "linux,bootx", NULL) != NULL)
+	if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
 		flags |= OF_IMAP_NO_PHANDLE;
 #endif /* CONFIG_PPC_32 */
 
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 651fa42..a410bc7 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -42,7 +42,6 @@ #include <linux/major.h>
 #include <linux/initrd.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
-#include <linux/ide.h>
 #include <linux/pci.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
@@ -135,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 = get_property(np, "model", NULL);
+		pp = of_get_property(np, "model", NULL);
 		if (pp != NULL)
 			seq_printf(m, "%s\n", pp);
 		else
 			seq_printf(m, "PowerMac\n");
-		pp = get_property(np, "compatible", &plen);
+		pp = of_get_property(np, "compatible", &plen);
 		if (pp != NULL) {
 			seq_printf(m, "motherboard\t:");
 			while (plen > 0) {
@@ -164,11 +163,13 @@ static void pmac_show_cpuinfo(struct seq
 	if (np == NULL)
 		np = of_find_node_by_type(NULL, "cache");
 	if (np != NULL) {
-		const unsigned int *ic = get_property(np, "i-cache-size", NULL);
-		const unsigned int *dc = get_property(np, "d-cache-size", NULL);
+		const unsigned int *ic =
+			of_get_property(np, "i-cache-size", NULL);
+		const unsigned int *dc =
+			of_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) {
+		if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {
 			seq_printf(m, " %dK unified", *dc / 1024);
 		} else {
 			if (ic)
@@ -177,7 +178,7 @@ static void pmac_show_cpuinfo(struct seq
 				seq_printf(m, "%s %dK data",
 					   (ic? " +": ""), *dc / 1024);
 		}
-		pp = get_property(np, "ram-type", NULL);
+		pp = of_get_property(np, "ram-type", NULL);
 		if (pp)
 			seq_printf(m, " %s", pp);
 		seq_printf(m, "\n");
@@ -192,8 +193,11 @@ static void pmac_show_cpuinfo(struct seq
 #ifndef CONFIG_ADB_CUDA
 int find_via_cuda(void)
 {
-	if (!find_devices("via-cuda"))
+	struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");
+
+	if (!dn)
 		return 0;
+	of_node_put(dn);
 	printk("WARNING ! Your machine is CUDA-based but your kernel\n");
 	printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
 	return 0;
@@ -203,8 +207,11 @@ #endif
 #ifndef CONFIG_ADB_PMU
 int find_via_pmu(void)
 {
-	if (!find_devices("via-pmu"))
+	struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");
+
+	if (!dn)
 		return 0;
+	of_node_put(dn);
 	printk("WARNING ! Your machine is PMU-based but your kernel\n");
 	printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
 	return 0;
@@ -224,6 +231,8 @@ static volatile u32 *sysctrl_regs;
 
 static void __init ohare_init(void)
 {
+	struct device_node *dn;
+
 	/* this area has the CPU identification register
 	   and some registers used by smp boards */
 	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
@@ -233,7 +242,9 @@ static void __init ohare_init(void)
 	 * We assume that we have a PSX memory controller iff
 	 * we have an ohare I/O controller.
 	 */
-	if (find_devices("ohare") != NULL) {
+	dn = of_find_node_by_name(NULL, "ohare");
+	if (dn) {
+		of_node_put(dn);
 		if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
 			if (sysctrl_regs[4] & 0x10)
 				sysctrl_regs[4] |= 0x04000020;
@@ -249,18 +260,19 @@ static void __init l2cr_init(void)
 {
 	/* Checks "l2cr-value" property in the registry */
 	if (cpu_has_feature(CPU_FTR_L2CR)) {
-		struct device_node *np = find_devices("cpus");
+		struct device_node *np = of_find_node_by_name(NULL, "cpus");
 		if (np == 0)
-			np = find_type_devices("cpu");
+			np = of_find_node_by_type(NULL, "cpu");
 		if (np != 0) {
 			const unsigned int *l2cr =
-				get_property(np, "l2cr-value", NULL);
+				of_get_property(np, "l2cr-value", NULL);
 			if (l2cr != 0) {
 				ppc_override_l2cr = 1;
 				ppc_override_l2cr_value = *l2cr;
 				_set_L2CR(0);
 				_set_L2CR(ppc_override_l2cr_value);
 			}
+			of_node_put(np);
 		}
 	}
 
@@ -286,7 +298,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 = get_property(cpu, "clock-frequency", NULL);
+		fp = of_get_property(cpu, "clock-frequency", NULL);
 		if (fp != NULL) {
 			if (pvr >= 0x30 && pvr < 0x80)
 				/* PPC970 etc. */
@@ -303,7 +315,7 @@ static void __init pmac_setup_arch(void)
 
 	/* See if newworld or oldworld */
 	for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
-		if (get_property(ic, "interrupt-controller", NULL))
+		if (of_get_property(ic, "interrupt-controller", NULL))
 			break;
 	if (ic) {
 		pmac_newworld = 1;
@@ -341,8 +353,15 @@ #endif
 
 #ifdef CONFIG_SMP
 	/* Check for Core99 */
-	if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
+	ic = of_find_node_by_name(NULL, "uni-n");
+	if (!ic)
+		ic = of_find_node_by_name(NULL, "u3");
+	if (!ic)
+		ic = of_find_node_by_name(NULL, "u4");
+	if (ic) {
+		of_node_put(ic);
 		smp_ops = &core99_smp_ops;
+	}
 #ifdef CONFIG_PPC32
 	else
 		smp_ops = &psurge_smp_ops;
@@ -420,76 +439,14 @@ #if defined(CONFIG_BLK_DEV_IDE) && defin
 #endif
 }
 
-/* TODO: Merge the suspend-to-ram with the common code !!!
- * currently, this is a stub implementation for suspend-to-disk
- * only
- */
-
-#ifdef CONFIG_SOFTWARE_SUSPEND
-
-static int pmac_pm_prepare(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	return 0;
-}
-
-static int pmac_pm_enter(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	/* Giveup the lazy FPU & vec so we don't have to back them
-	 * up from the low level code
-	 */
-	enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
-	if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
-		enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
-	return 0;
-}
-
-static int pmac_pm_finish(suspend_state_t state)
-{
-	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
-	/* Restore userland MMU context */
-	set_context(current->active_mm->context.id, current->active_mm->pgd);
-
-	return 0;
-}
-
-static int pmac_pm_valid(suspend_state_t state)
-{
-	switch (state) {
-	case PM_SUSPEND_DISK:
-		return 1;
-	/* can't do any other states via generic mechanism yet */
-	default:
-		return 0;
-	}
-}
-
-static struct pm_ops pmac_pm_ops = {
-	.pm_disk_mode	= PM_DISK_SHUTDOWN,
-	.prepare	= pmac_pm_prepare,
-	.enter		= pmac_pm_enter,
-	.finish		= pmac_pm_finish,
-	.valid		= pmac_pm_valid,
-};
-
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
 static int initializing = 1;
 
 static int pmac_late_init(void)
 {
 	initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
-	pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
+	/* this is udbg (which is __init) and we can later use it during
+	 * cpu hotplug (in smp_core99_kick_cpu) */
+	ppc_md.progress = NULL;
 	return 0;
 }
 
@@ -616,15 +573,6 @@ #ifdef CONFIG_PPC64
 #endif
 }
 
-/*
- * pmac has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int pmac_check_legacy_ioport(unsigned int baseport)
-{
-	return -ENODEV;
-}
-
 static int __init pmac_declare_of_platform_devices(void)
 {
 	struct device_node *np;
@@ -711,12 +659,57 @@ static int pmac_pci_probe_mode(struct pc
 	/* We need to use normal PCI probing for the AGP bus,
 	 * since the device for the AGP bridge isn't in the tree.
 	 */
-	if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
-				  device_is_compatible(node, "u4-pcie")))
+	if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") ||
+				  of_device_is_compatible(node, "u4-pcie")))
 		return PCI_PROBE_NORMAL;
 	return PCI_PROBE_DEVTREE;
 }
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* access per cpu vars from generic smp.c */
+DECLARE_PER_CPU(int, cpu_state);
+
+static void pmac_cpu_die(void)
+{
+	/*
+	 * turn off as much as possible, we'll be
+	 * kicked out as this will only be invoked
+	 * on core99 platforms for now ...
+	 */
+
+	printk(KERN_INFO "CPU#%d offline\n", smp_processor_id());
+	__get_cpu_var(cpu_state) = CPU_DEAD;
+	smp_wmb();
+
+	/*
+	 * during the path that leads here preemption is disabled,
+	 * reenable it now so that when coming up preempt count is
+	 * zero correctly
+	 */
+	preempt_enable();
+
+	/*
+	 * hard-disable interrupts for the non-NAP case, the NAP code
+	 * needs to re-enable interrupts (but soft-disables them)
+	 */
+	hard_irq_disable();
+
+	while (1) {
+		/* let's not take timer interrupts too often ... */
+		set_dec(0x7fffffff);
+
+		/* should always be true at this point */
+		if (cpu_has_feature(CPU_FTR_CAN_NAP))
+			power4_cpu_offline_powersave();
+		else {
+			HMT_low();
+			HMT_very_low();
+		}
+	}
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#endif /* CONFIG_PPC64 */
 
 define_machine(powermac) {
 	.name			= "PowerMac",
@@ -736,7 +729,6 @@ define_machine(powermac) {
 	.get_rtc_time		= pmac_get_rtc_time,
 	.calibrate_decr		= pmac_calibrate_decr,
 	.feature_call		= pmac_do_feature_call,
-	.check_legacy_ioport	= pmac_check_legacy_ioport,
 	.progress		= udbg_progress,
 #ifdef CONFIG_PPC64
 	.pci_probe_mode		= pmac_pci_probe_mode,
@@ -754,6 +746,6 @@ #ifdef CONFIG_PPC32
 	.phys_mem_access_prot	= pci_phys_mem_access_prot,
 #endif
 #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
-	.cpu_die		= generic_mach_cpu_die,
+	.cpu_die		= pmac_cpu_die,
 #endif
 };
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index d73fb73..686ed82 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
@@ -264,6 +263,7 @@ static void __init psurge_quad_init(void
 static int __init smp_psurge_probe(void)
 {
 	int i, ncpus;
+	struct device_node *dn;
 
 	/* We don't do SMP on the PPC601 -- paulus */
 	if (PVR_VER(mfspr(SPRN_PVR)) == 1)
@@ -279,8 +279,10 @@ static int __init smp_psurge_probe(void)
 	 * in the hammerhead memory controller in the case of the
 	 * dual-cpu powersurge board.  -- paulus.
 	 */
-	if (find_devices("hammerhead") == NULL)
+	dn = of_find_node_by_name(NULL, "hammerhead");
+	if (dn == NULL)
 		return 1;
+	of_node_put(dn);
 
 	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
 	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
@@ -559,7 +561,7 @@ static void __init smp_core99_setup_i2c_
 	/* Look for the clock chip */
 	while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
 		p = of_get_parent(cc);
-		ok = p && device_is_compatible(p, "uni-n-i2c");
+		ok = p && of_device_is_compatible(p, "uni-n-i2c");
 		of_node_put(p);
 		if (!ok)
 			continue;
@@ -567,16 +569,16 @@ 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 = get_property(cc, "reg", NULL);
+		reg = of_get_property(cc, "reg", NULL);
 		if (reg == NULL)
 			continue;
 		switch (*reg) {
 		case 0xd2:
-			if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
+			if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {
 				pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
 				pmac_tb_pulsar_addr = 0xd2;
 				name = "Pulsar";
-			} else if (device_is_compatible(cc, "cy28508")) {
+			} else if (of_device_is_compatible(cc, "cy28508")) {
 				pmac_tb_freeze = smp_core99_cypress_tb_freeze;
 				name = "Cypress";
 			}
@@ -695,7 +697,7 @@ #ifdef CONFIG_PPC64
 		struct device_node *cpus =
 			of_find_node_by_path("/cpus");
 		if (cpus &&
-		    get_property(cpus, "platform-cpu-timebase", NULL)) {
+		    of_get_property(cpus, "platform-cpu-timebase", NULL)) {
 			pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
 			printk(KERN_INFO "Processor timebase sync using"
 			       " platform function\n");
@@ -712,7 +714,7 @@ #else /* CONFIG_PPC64 */
 		core99_tb_gpio = KL_GPIO_TB_ENABLE;	/* default value */
 		cpu = of_find_node_by_type(NULL, "cpu");
 		if (cpu != NULL) {
-			tbprop = get_property(cpu, "timebase-enable", NULL);
+			tbprop = of_get_property(cpu, "timebase-enable", NULL);
 			if (tbprop)
 				core99_tb_gpio = *tbprop;
 			of_node_put(cpu);
@@ -897,7 +899,7 @@ void smp_core99_cpu_die(unsigned int cpu
 	cpu_dead[cpu] = 0;
 }
 
-#endif
+#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */
 
 /* Core99 Macs (dual G4s and G5s) */
 struct smp_ops_t core99_smp_ops = {
@@ -907,8 +909,16 @@ struct smp_ops_t core99_smp_ops = {
 	.setup_cpu	= smp_core99_setup_cpu,
 	.give_timebase	= smp_core99_give_timebase,
 	.take_timebase	= smp_core99_take_timebase,
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+#if defined(CONFIG_HOTPLUG_CPU)
+# if defined(CONFIG_PPC32)
 	.cpu_disable	= smp_core99_cpu_disable,
 	.cpu_die	= smp_core99_cpu_die,
+# endif
+# if defined(CONFIG_PPC64)
+	.cpu_disable	= generic_cpu_disable,
+	.cpu_die	= generic_cpu_die,
+	/* intentionally do *NOT* assign cpu_enable,
+	 * the generic code will use kick_cpu then! */
+# endif
 #endif
 };
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index a417390..bf9da56 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
 }
 #endif
 
-#ifdef CONFIG_PM
-/*
- * Reset the time after a sleep.
- */
-static int
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	static unsigned long time_diff;
-	unsigned long flags;
-	unsigned long seq;
-	struct timespec tv;
-
-	switch (when) {
-	case PBOOK_SLEEP_NOW:
-		do {
-			seq = read_seqbegin_irqsave(&xtime_lock, flags);
-			time_diff = xtime.tv_sec - pmac_get_boot_time();
-		} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-		break;
-	case PBOOK_WAKE:
-		tv.tv_sec = pmac_get_boot_time() + time_diff;
-		tv.tv_nsec = 0;
-		do_settimeofday(&tv);
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier = {
-	time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PM */
-
 /*
  * Query the OF and get the decr frequency.
  */
 void __init pmac_calibrate_decr(void)
 {
-#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
-	/* XXX why here? */
-	pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif
-
 	generic_calibrate_decr();
 
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 379db05..47de4d3 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc)
 	macio = of_get_parent(escc);
 	if (macio == NULL)
 		goto bail;
-	path = get_property(of_chosen, "linux,stdout-path", NULL);
+	path = of_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 = get_property(escc, "reg", NULL);
+	reg = of_get_property(escc, "reg", NULL);
 	if (reg == NULL)
 		goto bail;
 	addr = reg[0];
 
 	/* Get address of mac-io PCI itself */
-	reg = get_property(macio, "assigned-addresses", NULL);
+	reg = of_get_property(macio, "assigned-addresses", NULL);
 	if (reg == NULL)
 		goto bail;
 	addr += reg[2];
diff --git a/arch/powerpc/platforms/prep/Kconfig b/arch/powerpc/platforms/prep/Kconfig
index 673ac47..29d4112 100644
--- a/arch/powerpc/platforms/prep/Kconfig
+++ b/arch/powerpc/platforms/prep/Kconfig
@@ -1,3 +1,12 @@
+config PPC_PREP
+	bool "PowerPC Reference Platform (PReP) based machines"
+	depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
+	select MPIC
+	select PPC_I8259
+	select PPC_INDIRECT_PCI
+	select PPC_UDBG_16550
+	select PPC_NATIVE
+	default n
 
 config PREP_RESIDUAL
 	bool "Support for PReP Residual Data"
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 1a481a6..40f0008 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -1,3 +1,19 @@
+config PPC_PS3
+	bool "Sony PS3 (incomplete)"
+	depends on PPC_MULTIPLATFORM && PPC64
+	select PPC_CELL
+	select USB_ARCH_HAS_OHCI
+	select USB_OHCI_LITTLE_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_ARCH_HAS_EHCI
+	select USB_EHCI_BIG_ENDIAN_MMIO
+	help
+	  This option enables support for the Sony PS3 game console
+	  and other platforms using the PS3 hypervisor.
+	  Support for this platform is not yet complete, so
+	  enabling this will not result in a bootable kernel on a
+	  PS3 system.
+
 menu "PS3 Platform Options"
 	depends on PPC_PS3
 
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index e12e59f..a1409e4 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -39,7 +39,7 @@ static unsigned long htab_addr;
 static unsigned char *bolttab;
 static unsigned char *inusetab;
 
-static spinlock_t ps3_bolttab_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ps3_bolttab_lock);
 
 #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
 	_debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
@@ -273,7 +273,8 @@ void __init ps3_map_htab(void)
 
 	result = lv1_map_htab(0, &htab_addr);
 
-	htab = (hpte_t *)__ioremap(htab_addr, htab_size, PAGE_READONLY_X);
+	htab = (hpte_t *)__ioremap(htab_addr, htab_size,
+				   pgprot_val(PAGE_READONLY_X));
 
 	DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__,
 		htab_addr, (unsigned long)htab);
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 631c300..9da82c2 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -89,7 +89,18 @@ struct ps3_private {
 
 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
 
-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+/**
+ * ps3_virq_setup - virq related setup.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @outlet: The HV outlet from the various create outlet routines.
+ * @virq: The assigned Linux virq.
+ *
+ * Calls irq_create_mapping() to get a virq and sets the chip data to
+ * ps3_private data.
+ */
+
+int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
 	unsigned int *virq)
 {
 	int result;
@@ -111,17 +122,6 @@ int ps3_alloc_irq(enum ps3_cpu_binding c
 		goto fail_create;
 	}
 
-	/* Binds outlet to cpu + virq. */
-
-	result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
-
-	if (result) {
-		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
-		__func__, __LINE__, ps3_result(result));
-		result = -EPERM;
-		goto fail_connect;
-	}
-
 	pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
 		outlet, cpu, *virq);
 
@@ -136,94 +136,118 @@ int ps3_alloc_irq(enum ps3_cpu_binding c
 	return result;
 
 fail_set:
-	lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
-fail_connect:
 	irq_dispose_mapping(*virq);
 fail_create:
 	return result;
 }
-EXPORT_SYMBOL_GPL(ps3_alloc_irq);
 
-int ps3_free_irq(unsigned int virq)
+/**
+ * ps3_virq_destroy - virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Clears chip data and calls irq_dispose_mapping() for the virq.
+ */
+
+int ps3_virq_destroy(unsigned int virq)
 {
-	int result;
 	const struct ps3_private *pd = get_irq_chip_data(virq);
 
 	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
 		pd->node, pd->cpu, virq);
 
-	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
-
-	if (result)
-		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
-		__func__, __LINE__, ps3_result(result));
-
 	set_irq_chip_data(virq, NULL);
 	irq_dispose_mapping(virq);
-	return result;
+
+	pr_debug("%s:%d <-\n", __func__, __LINE__);
+	return 0;
 }
-EXPORT_SYMBOL_GPL(ps3_free_irq);
 
 /**
- * ps3_alloc_io_irq - Assign a virq to a system bus device.
+ * ps3_irq_plug_setup - Generic outlet and virq related setup.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @outlet: The HV outlet from the various create outlet routines.
  * @virq: The assigned Linux virq.
  *
- * An io irq represents a non-virtualized device interrupt.  interrupt_id
- * coresponds to the interrupt number of the interrupt controller.
+ * Sets up virq and connects the irq plug.
  */
 
-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
 	unsigned int *virq)
 {
 	int result;
-	unsigned long outlet;
+	struct ps3_private *pd;
 
-	result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+	result = ps3_virq_setup(cpu, outlet, virq);
 
 	if (result) {
-		pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
-			__func__, __LINE__, ps3_result(result));
-		return result;
+		pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
+		goto fail_setup;
 	}
 
-	result = ps3_alloc_irq(cpu, outlet, virq);
-	BUG_ON(result);
+	pd = get_irq_chip_data(*virq);
+
+	/* Binds outlet to cpu + virq. */
+
+	result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
 
+	if (result) {
+		pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+		__func__, __LINE__, ps3_result(result));
+		result = -EPERM;
+		goto fail_connect;
+	}
+
+	return result;
+
+fail_connect:
+	ps3_virq_destroy(*virq);
+fail_setup:
 	return result;
 }
-EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
+
+/**
+ * ps3_irq_plug_destroy - Generic outlet and virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Disconnects the irq plug and tears down virq.
+ * Do not call for system bus event interrupts setup with
+ * ps3_sb_event_receive_port_setup().
+ */
 
-int ps3_free_io_irq(unsigned int virq)
+int ps3_irq_plug_destroy(unsigned int virq)
 {
 	int result;
+	const struct ps3_private *pd = get_irq_chip_data(virq);
 
-	result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+	pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+		pd->node, pd->cpu, virq);
+
+	result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
 
 	if (result)
-		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
-			__func__, __LINE__, ps3_result(result));
+		pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+		__func__, __LINE__, ps3_result(result));
 
-	ps3_free_irq(virq);
+	ps3_virq_destroy(virq);
 
 	return result;
 }
-EXPORT_SYMBOL_GPL(ps3_free_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
 
 /**
- * ps3_alloc_event_irq - Allocate a virq for use with a system event.
+ * ps3_event_receive_port_setup - Setup an event receive port.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @virq: The assigned Linux virq.
  *
  * The virq can be used with lv1_connect_interrupt_event_receive_port() to
- * arrange to receive events, or with ps3_send_event_locally() to signal
- * events.
+ * arrange to receive interrupts from system-bus devices, or with
+ * ps3_send_event_locally() to signal events.
  */
 
-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
+int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
 {
 	int result;
 	unsigned long outlet;
@@ -237,17 +261,27 @@ int ps3_alloc_event_irq(enum ps3_cpu_bin
 		return result;
 	}
 
-	result = ps3_alloc_irq(cpu, outlet, virq);
+	result = ps3_irq_plug_setup(cpu, outlet, virq);
 	BUG_ON(result);
 
 	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
+
+/**
+ * ps3_event_receive_port_destroy - Destroy an event receive port.
+ * @virq: The assigned Linux virq.
+ *
+ * Since ps3_event_receive_port_destroy destroys the receive port outlet,
+ * SB devices need to call disconnect_interrupt_event_receive_port() before
+ * this.
+ */
 
-int ps3_free_event_irq(unsigned int virq)
+int ps3_event_receive_port_destroy(unsigned int virq)
 {
 	int result;
 
-	pr_debug(" -> %s:%d\n", __func__, __LINE__);
+	pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq);
 
 	result = lv1_destruct_event_receive_port(virq_to_hw(virq));
 
@@ -255,11 +289,17 @@ int ps3_free_event_irq(unsigned int virq
 		pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
 			__func__, __LINE__, ps3_result(result));
 
-	ps3_free_irq(virq);
+	/* lv1_destruct_event_receive_port() destroys the IRQ plug,
+	 * so don't call ps3_irq_plug_destroy() here.
+	 */
+
+	result = ps3_virq_destroy(virq);
+	BUG_ON(result);
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 	return result;
 }
+EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
 
 int ps3_send_event_locally(unsigned int virq)
 {
@@ -267,7 +307,7 @@ int ps3_send_event_locally(unsigned int 
 }
 
 /**
- * ps3_connect_event_irq - Assign a virq to a system bus device.
+ * ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @did: The HV device identifier read from the system repository.
@@ -278,13 +318,15 @@ int ps3_send_event_locally(unsigned int 
  * coresponds to the software interrupt number.
  */
 
-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
 	const struct ps3_device_id *did, unsigned int interrupt_id,
 	unsigned int *virq)
 {
+	/* this should go in system-bus.c */
+
 	int result;
 
-	result = ps3_alloc_event_irq(cpu, virq);
+	result = ps3_event_receive_port_setup(cpu, virq);
 
 	if (result)
 		return result;
@@ -296,7 +338,7 @@ int ps3_connect_event_irq(enum ps3_cpu_b
 		pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
 			" failed: %s\n", __func__, __LINE__,
 			ps3_result(result));
-		ps3_free_event_irq(*virq);
+		ps3_event_receive_port_destroy(*virq);
 		*virq = NO_IRQ;
 		return result;
 	}
@@ -306,10 +348,13 @@ int ps3_connect_event_irq(enum ps3_cpu_b
 
 	return 0;
 }
+EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
 
-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
+int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
 	unsigned int interrupt_id, unsigned int virq)
 {
+	/* this should go in system-bus.c */
+
 	int result;
 
 	pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
@@ -323,14 +368,65 @@ int ps3_disconnect_event_irq(const struc
 			" failed: %s\n", __func__, __LINE__,
 			ps3_result(result));
 
-	ps3_free_event_irq(virq);
+	result = ps3_event_receive_port_destroy(virq);
+	BUG_ON(result);
 
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 	return result;
 }
+EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
 
 /**
- * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
+ * ps3_io_irq_setup - Setup a system bus io irq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @interrupt_id: The device interrupt id read from the system repository.
+ * @virq: The assigned Linux virq.
+ *
+ * An io irq represents a non-virtualized device interrupt.  interrupt_id
+ * coresponds to the interrupt number of the interrupt controller.
+ */
+
+int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+	unsigned int *virq)
+{
+	int result;
+	unsigned long outlet;
+
+	result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+
+	if (result) {
+		pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		return result;
+	}
+
+	result = ps3_irq_plug_setup(cpu, outlet, virq);
+	BUG_ON(result);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
+
+int ps3_io_irq_destroy(unsigned int virq)
+{
+	int result;
+
+	result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+
+	if (result)
+		pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+
+	result = ps3_irq_plug_destroy(virq);
+	BUG_ON(result);
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
+
+/**
+ * ps3_vuart_irq_setup - Setup the system virtual uart virq.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
@@ -340,7 +436,7 @@ int ps3_disconnect_event_irq(const struc
  * freeing the interrupt will return a wrong state error.
  */
 
-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
 	unsigned int *virq)
 {
 	int result;
@@ -359,13 +455,13 @@ int ps3_alloc_vuart_irq(enum ps3_cpu_bin
 		return result;
 	}
 
-	result = ps3_alloc_irq(cpu, outlet, virq);
+	result = ps3_irq_plug_setup(cpu, outlet, virq);
 	BUG_ON(result);
 
 	return result;
 }
 
-int ps3_free_vuart_irq(unsigned int virq)
+int ps3_vuart_irq_destroy(unsigned int virq)
 {
 	int result;
 
@@ -377,13 +473,14 @@ int ps3_free_vuart_irq(unsigned int virq
 		return result;
 	}
 
-	ps3_free_irq(virq);
+	result = ps3_irq_plug_destroy(virq);
+	BUG_ON(result);
 
 	return result;
 }
 
 /**
- * ps3_alloc_spe_irq - Configure an spe virq.
+ * ps3_spe_irq_setup - Setup an spe virq.
  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
  * serviced on.
  * @spe_id: The spe_id returned from lv1_construct_logical_spe().
@@ -392,7 +489,7 @@ int ps3_free_vuart_irq(unsigned int virq
  *
  */
 
-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
 	unsigned int class, unsigned int *virq)
 {
 	int result;
@@ -408,15 +505,16 @@ int ps3_alloc_spe_irq(enum ps3_cpu_bindi
 		return result;
 	}
 
-	result = ps3_alloc_irq(cpu, outlet, virq);
+	result = ps3_irq_plug_setup(cpu, outlet, virq);
 	BUG_ON(result);
 
 	return result;
 }
 
-int ps3_free_spe_irq(unsigned int virq)
+int ps3_spe_irq_destroy(unsigned int virq)
 {
-	ps3_free_irq(virq);
+	int result = ps3_irq_plug_destroy(virq);
+	BUG_ON(result);
 	return 0;
 }
 
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 2014d2b..f8a3e20 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -826,5 +826,4 @@ void __init ps3_mm_init(void)
 void ps3_mm_shutdown(void)
 {
 	ps3_mm_region_destroy(&map.r1);
-	map.total = map.rm.size;
 }
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index ac5df96..c989493 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -137,6 +137,12 @@ #else
 #define prealloc_ps3fb_videomemory()	do { } while (0)
 #endif
 
+static int ps3_set_dabr(u64 dabr)
+{
+	enum {DABR_USER = 1, DABR_KERNEL = 2,};
+
+	return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0;
+}
 
 static void __init ps3_setup_arch(void)
 {
@@ -234,6 +240,7 @@ define_machine(ps3) {
 	.get_boot_time			= ps3_get_boot_time,
 	.set_rtc_time			= ps3_set_rtc_time,
 	.get_rtc_time			= ps3_get_rtc_time,
+	.set_dabr			= ps3_set_dabr,
 	.calibrate_decr			= ps3_calibrate_decr,
 	.progress			= ps3_progress,
 	.restart			= ps3_restart,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 6fb8879..8729348 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -110,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int
 	BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
 
 	for (i = 0; i < MSG_COUNT; i++) {
-		result = ps3_alloc_event_irq(cpu, &virqs[i]);
+		result = ps3_event_receive_port_setup(cpu, &virqs[i]);
 
 		if (result)
 			continue;
@@ -134,11 +134,13 @@ void ps3_smp_cleanup_cpu(int cpu)
 	int i;
 
 	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
+
 	for (i = 0; i < MSG_COUNT; i++) {
-		ps3_free_event_irq(virqs[i]);
 		free_irq(virqs[i], (void*)(long)i);
+		ps3_event_receive_port_destroy(virqs[i]);
 		virqs[i] = NO_IRQ;
 	}
+
 	DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 }
 
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index a397e4e..651437c 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -184,7 +184,7 @@ static int __init setup_areas(struct spu
 
 	spu_pdata(spu)->shadow = __ioremap(
 		spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow),
-		PAGE_READONLY | _PAGE_NO_CACHE | _PAGE_GUARDED);
+		pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED);
 	if (!spu_pdata(spu)->shadow) {
 		pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__);
 		goto fail_ioremap;
@@ -230,19 +230,19 @@ static int __init setup_interrupts(struc
 {
 	int result;
 
-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
 		0, &spu->irqs[0]);
 
 	if (result)
 		goto fail_alloc_0;
 
-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
 		1, &spu->irqs[1]);
 
 	if (result)
 		goto fail_alloc_1;
 
-	result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
 		2, &spu->irqs[2]);
 
 	if (result)
@@ -251,9 +251,9 @@ static int __init setup_interrupts(struc
 	return result;
 
 fail_alloc_2:
-	ps3_free_spe_irq(spu->irqs[1]);
+	ps3_spe_irq_destroy(spu->irqs[1]);
 fail_alloc_1:
-	ps3_free_spe_irq(spu->irqs[0]);
+	ps3_spe_irq_destroy(spu->irqs[0]);
 fail_alloc_0:
 	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
 	return result;
@@ -301,9 +301,9 @@ static int ps3_destroy_spu(struct spu *s
 	result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0);
 	BUG_ON(result);
 
-	ps3_free_spe_irq(spu->irqs[2]);
-	ps3_free_spe_irq(spu->irqs[1]);
-	ps3_free_spe_irq(spu->irqs[0]);
+	ps3_spe_irq_destroy(spu->irqs[2]);
+	ps3_spe_irq_destroy(spu->irqs[1]);
+	ps3_spe_irq_destroy(spu->irqs[0]);
 
 	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
 
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index a57032c..16e4e40 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -1,3 +1,13 @@
+config PPC_PSERIES
+	depends on PPC_MULTIPLATFORM && PPC64
+	bool "IBM pSeries & new (POWER5-based) iSeries"
+	select MPIC
+	select PPC_I8259
+	select PPC_RTAS
+	select RTAS_ERROR_LOGGING
+	select PPC_UDBG_16550
+	select PPC_NATIVE
+	default y
 
 config PPC_SPLPAR
 	depends on PPC_PSERIES
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 2dfd050..ae1fc92 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -2,14 +2,16 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS		+= -mno-minimal-toc
 endif
 
-obj-y			:= pci.o lpar.o hvCall.o nvram.o reconfig.o \
-			   setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
+obj-y			:= lpar.o hvCall.o nvram.o reconfig.o \
+			   setup.o iommu.o ras.o rtasd.o \
 			   firmware.o power.o
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_XICS)	+= xics.o
 obj-$(CONFIG_SCANLOG)	+= scanlog.o
 obj-$(CONFIG_EEH)	+= eeh.o eeh_cache.o eeh_driver.o eeh_event.o
 obj-$(CONFIG_KEXEC)	+= kexec.o
+obj-$(CONFIG_PCI)	+= pci.o pci_dlpar.o
+obj-$(CONFIG_PCI_MSI)	+= msi.o
 
 obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug-cpu.o
 
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 6cedbc0..63e2306 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -74,7 +74,10 @@ #undef DEBUG
  * is broken and panic.  This sets the threshold for how many read
  * attempts we allow before panicking.
  */
-#define EEH_MAX_FAILS	100000
+#define EEH_MAX_FAILS	2100000
+
+/* Time to wait for a PCI slot to retport status, in milliseconds */
+#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
 /* RTAS tokens */
 static int ibm_set_eeh_option;
@@ -83,6 +86,7 @@ static int ibm_read_slot_reset_state;
 static int ibm_read_slot_reset_state2;
 static int ibm_slot_error_detail;
 static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
 static int ibm_configure_bridge;
 
 int eeh_subsystem_enabled;
@@ -168,6 +172,55 @@ static int read_slot_reset_state(struct 
 }
 
 /**
+ * eeh_wait_for_slot_status - returns error status of slot
+ * @pdn pci device node
+ * @max_wait_msecs maximum number to millisecs to wait
+ *
+ * Return negative value if a permanent error, else return
+ * Partition Endpoint (PE) status value.
+ *
+ * If @max_wait_msecs is positive, then this routine will
+ * sleep until a valid status can be obtained, or until
+ * the max allowed wait time is exceeded, in which case
+ * a -2 is returned.
+ */
+int
+eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
+{
+	int rc;
+	int rets[3];
+	int mwait;
+
+	while (1) {
+		rc = read_slot_reset_state(pdn, rets);
+		if (rc) return rc;
+		if (rets[1] == 0) return -1;  /* EEH is not supported */
+
+		if (rets[0] != 5) return rets[0]; /* return actual status */
+
+		if (rets[2] == 0) return -1; /* permanently unavailable */
+
+		if (max_wait_msecs <= 0) return -1;
+
+		mwait = rets[2];
+		if (mwait <= 0) {
+			printk (KERN_WARNING
+			        "EEH: Firmware returned bad wait value=%d\n", mwait);
+			mwait = 1000;
+		} else if (mwait > 300*1000) {
+			printk (KERN_WARNING
+			        "EEH: Firmware is taking too long, time=%d\n", mwait);
+			mwait = 300*1000;
+		}
+		max_wait_msecs -= mwait;
+		msleep (mwait);
+	}
+
+	printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
+	return -2;
+}
+
+/**
  * eeh_token_to_phys - convert EEH address token to phys address
  * @token i/o token, should be address in the form 0xA....
  */
@@ -229,7 +282,7 @@ void eeh_mark_slot (struct device_node *
 	dn = find_device_pe (dn);
 
 	/* Back up one, since config addrs might be shared */
-	if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
 		dn = dn->parent;
 
 	PCI_DN(dn)->eeh_mode |= mode_flag;
@@ -263,7 +316,7 @@ void eeh_clear_slot (struct device_node 
 	dn = find_device_pe (dn);
 	
 	/* Back up one, since config addrs might be shared */
-	if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
 		dn = dn->parent;
 
 	PCI_DN(dn)->eeh_mode &= ~mode_flag;
@@ -293,7 +346,6 @@ int eeh_dn_check_failure(struct device_n
 	int rets[3];
 	unsigned long flags;
 	struct pci_dn *pdn;
-	enum pci_channel_state state;
 	int rc = 0;
 
 	total_mmio_ffs++;
@@ -367,25 +419,25 @@ #endif
 		goto dn_unlock;
 	}
 
-	/* If EEH is not supported on this device, punt. */
-	if (rets[1] != 1) {
-		printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
-		       ret, dn->full_name);
+	/* Note that config-io to empty slots may fail;
+	 * they are empty when they don't have children. */
+	if ((rets[0] == 5) && (dn->child == NULL)) {
 		false_positives++;
 		rc = 0;
 		goto dn_unlock;
 	}
 
-	/* If not the kind of error we know about, punt. */
-	if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
+	/* If EEH is not supported on this device, punt. */
+	if (rets[1] != 1) {
+		printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
+		       ret, dn->full_name);
 		false_positives++;
 		rc = 0;
 		goto dn_unlock;
 	}
 
-	/* Note that config-io to empty slots may fail;
-	 * we recognize empty because they don't have children. */
-	if ((rets[0] == 5) && (dn->child == NULL)) {
+	/* If not the kind of error we know about, punt. */
+	if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
 		false_positives++;
 		rc = 0;
 		goto dn_unlock;
@@ -399,17 +451,12 @@ #endif
 	eeh_mark_slot (dn, EEH_MODE_ISOLATED);
 	spin_unlock_irqrestore(&confirm_error_lock, flags);
 
-	state = pci_channel_io_normal;
-	if ((rets[0] == 2) || (rets[0] == 4))
-		state = pci_channel_io_frozen;
-	if (rets[0] == 5)
-		state = pci_channel_io_perm_failure;
-	eeh_send_failure_event (dn, dev, state, rets[2]);
+	eeh_send_failure_event (dn, dev);
 
 	/* Most EEH events are due to device driver bugs.  Having
 	 * a stack trace will help the device-driver authors figure
 	 * out what happened.  So print that out. */
-	if (rets[0] != 5) dump_stack();
+	dump_stack();
 	return 1;
 
 dn_unlock:
@@ -458,38 +505,6 @@ EXPORT_SYMBOL(eeh_check_failure);
 /* The code below deals with error recovery */
 
 /**
- * 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.
- */
-static int
-eeh_slot_availability(struct pci_dn *pdn)
-{
-	int rc;
-	int rets[3];
-
-	rc = read_slot_reset_state(pdn, rets);
-
-	if (rc) return rc;
-
-	if (rets[1] == 0) return -1;  /* EEH is not supported */
-	if (rets[0] == 0) return 0;   /* Oll Korrect */
-	if (rets[0] == 5) {
-		if (rets[2] == 0) return -1; /* permanently unavailable */
-		return rets[2]; /* number of millisecs to wait */
-	}
-	if (rets[0] == 1)
-		return 250;
-
-	printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
-		rc, rets[0], rets[1], rets[2]);
-	return -2;
-}
-
-/**
  * rtas_pci_enable - enable MMIO or DMA transfers for this slot
  * @pdn pci device node
  */
@@ -512,9 +527,13 @@ rtas_pci_enable(struct pci_dn *pdn, int 
 		            function);
 
 	if (rc)
-		printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n",
+		printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
 		        function, rc, pdn->node->full_name);
 
+	rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC);
+	if ((rc == 4) && (function == EEH_THAW_MMIO))
+		return 0;
+
 	return rc;
 }
 
@@ -561,6 +580,36 @@ rtas_pci_slot_reset(struct pci_dn *pdn, 
 }
 
 /**
+ * pcibios_set_pcie_slot_reset - Set PCI-E reset state
+ * @dev:	pci device struct
+ * @state:	reset state to enter
+ *
+ * Return value:
+ * 	0 if success
+ **/
+int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+{
+	struct device_node *dn = pci_device_to_OF_node(dev);
+	struct pci_dn *pdn = PCI_DN(dn);
+
+	switch (state) {
+	case pcie_deassert_reset:
+		rtas_pci_slot_reset(pdn, 0);
+		break;
+	case pcie_hot_reset:
+		rtas_pci_slot_reset(pdn, 1);
+		break;
+	case pcie_warm_reset:
+		rtas_pci_slot_reset(pdn, 3);
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+/**
  * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
  * @pdn: pci device node to be reset.
  *
@@ -595,36 +644,24 @@ int rtas_set_slot_reset(struct pci_dn *p
 {
 	int i, rc;
 
-	__rtas_set_slot_reset(pdn);
+	/* Take three shots at resetting the bus */
+	for (i=0; i<3; i++) {
+		__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);
+		rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
 		if (rc == 0)
 			return 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);
+		printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n",
+		        i+1, pdn->node->full_name);
 	}
 
-	rc = eeh_slot_availability (pdn);
-	if (rc)
-		printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name);
-
-	return rc;
+	return -1;
 }
 
 /* ------------------------------------------------------- */
@@ -744,16 +781,48 @@ struct eeh_early_enable_info {
 	unsigned int buid_lo;
 };
 
+static int get_pe_addr (int config_addr,
+                        struct eeh_early_enable_info *info)
+{
+	unsigned int rets[3];
+	int ret;
+
+	/* Use latest config-addr token on power6 */
+	if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
+		/* Make sure we have a PE in hand */
+		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+			config_addr, info->buid_hi, info->buid_lo, 1);
+		if (ret || (rets[0]==0))
+			return 0;
+
+		ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+			config_addr, info->buid_hi, info->buid_lo, 0);
+		if (ret)
+			return 0;
+		return rets[0];
+	}
+
+	/* Use older config-addr token on power5 */
+	if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
+		ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
+			config_addr, info->buid_hi, info->buid_lo, 0);
+		if (ret)
+			return 0;
+		return rets[0];
+	}
+	return 0;
+}
+
 /* Enable eeh for the given device node. */
 static void *early_enable_eeh(struct device_node *dn, void *data)
 {
 	unsigned int rets[3];
 	struct eeh_early_enable_info *info = data;
 	int ret;
-	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 char *status = of_get_property(dn, "status", NULL);
+	const u32 *class_code = of_get_property(dn, "class-code", NULL);
+	const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
+	const u32 *device_id = of_get_property(dn, "device-id", NULL);
 	const u32 *regs;
 	int enable;
 	struct pci_dn *pdn = PCI_DN(dn);
@@ -796,7 +865,7 @@ #endif
 
 	/* 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 = get_property(dn, "reg", NULL);
+	regs = of_get_property(dn, "reg", NULL);
 	if (regs) {
 		/* First register entry is addr (00BBSS00)  */
 		/* Try to enable eeh */
@@ -810,15 +879,7 @@ #endif
 
 			/* If the newer, better, ibm,get-config-addr-info is supported, 
 			 * then use that instead. */
-			pdn->eeh_pe_config_addr = 0;
-			if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
-				ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, 
-					pdn->eeh_config_addr, 
-					info->buid_hi, info->buid_lo,
-					0);
-				if (ret == 0)
-					pdn->eeh_pe_config_addr = rets[0];
-			}
+			pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);
 
 			/* Some older systems (Power4) allow the
 			 * ibm,set-eeh-option call to succeed even on nodes
@@ -889,6 +950,7 @@ void __init eeh_init(void)
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
 	ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
 	ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
+	ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
 	ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
 
 	if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index a4c0bf8..3170e00 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -158,7 +158,8 @@ static void eeh_report_reset(struct pci_
 		return;
 
 	rc = driver->err_handler->slot_reset(dev);
-	if (*res == PCI_ERS_RESULT_NONE) *res = rc;
+	if ((*res == PCI_ERS_RESULT_NONE) ||
+	    (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
 	if (*res == PCI_ERS_RESULT_DISCONNECT &&
 	     rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
 }
@@ -248,6 +249,7 @@ static void eeh_report_failure(struct pc
 
 static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
 {
+	struct device_node *dn;
 	int cnt, rc;
 
 	/* pcibios will clear the counter; save the value */
@@ -263,23 +265,20 @@ static int eeh_reset_device (struct pci_
 	if (rc)
 		return rc;
 
- 	/* New-style config addrs might be shared across multiple devices,
- 	 * Walk over all functions on this device */
- 	if (pe_dn->eeh_pe_config_addr) {
- 		struct device_node *pe = pe_dn->node;
- 		pe = pe->parent->child;
- 		while (pe) {
- 			struct pci_dn *ppe = PCI_DN(pe);
- 			if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
- 				rtas_configure_bridge(ppe);
- 				eeh_restore_bars(ppe);
- 			}
- 			pe = pe->sibling;
+	/* Walk over all functions on this device.  */
+	dn = pe_dn->node;
+	if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+		dn = dn->parent->child;
+
+	while (dn) {
+		struct pci_dn *ppe = PCI_DN(dn);
+		/* On Power4, always true because eeh_pe_config_addr=0 */
+		if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
+			rtas_configure_bridge(ppe);
+			eeh_restore_bars(ppe);
  		}
- 	} else {
- 		rtas_configure_bridge(pe_dn);
- 		eeh_restore_bars(pe_dn);
- 	}
+		dn = dn->sibling;
+	}
 
 	/* Give the system 5 seconds to finish running the user-space
 	 * hotplug shutdown scripts, e.g. ifdown for ethernet.  Yes, 
@@ -299,7 +298,7 @@ static int eeh_reset_device (struct pci_
 /* The longest amount of time to wait for a pci device
  * to come back on line, in seconds.
  */
-#define MAX_WAIT_FOR_RECOVERY 15
+#define MAX_WAIT_FOR_RECOVERY 150
 
 struct pci_dn * handle_eeh_events (struct eeh_event *event)
 {
@@ -315,14 +314,14 @@ struct pci_dn * handle_eeh_events (struc
 
 	if (!frozen_dn) {
 
-		location = get_property(event->dn, "ibm,loc-code", NULL);
+		location = of_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 = get_property(frozen_dn, "ibm,loc-code", NULL);
+	location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
 	location = location ? location : "unknown";
 
 	/* There are two different styles for coming up with the PE.
@@ -341,13 +340,6 @@ struct pci_dn * handle_eeh_events (struc
 		return NULL;
 	}
 
-#if 0
-	/* We may get "permanent failure" messages on empty slots.
-	 * These are false alarms. Empty slots have no child dn. */
-	if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL))
-		return;
-#endif
-
 	frozen_pdn = PCI_DN(frozen_dn);
 	frozen_pdn->eeh_freeze_count++;
 
@@ -362,13 +354,12 @@ #endif
 	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
 		goto excess_failures;
 
-	/* If the reset state is a '5' and the time to reset is 0 (infinity)
-	 * or is more then 15 seconds, then mark this as a permanent failure.
-	 */
-	if ((event->state == pci_channel_io_perm_failure) &&
-	    ((event->time_unavail <= 0) ||
-	     (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000)))
+	/* Get the current PCI slot state. */
+	rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
+	if (rc < 0) {
+		printk(KERN_WARNING "EEH: Permanent failure\n");
 		goto hard_fail;
+	}
 
 	eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
 	printk(KERN_WARNING
@@ -390,14 +381,18 @@ #endif
 	 */
 	if (result == PCI_ERS_RESULT_NONE) {
 		rc = eeh_reset_device(frozen_pdn, frozen_bus);
-		if (rc)
+		if (rc) {
+			printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
 			goto hard_fail;
+		}
 	}
 
 	/* 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 < 0)
+			goto hard_fail;
 		if (rc) {
 			result = PCI_ERS_RESULT_NEED_RESET;
 		} else {
@@ -410,6 +405,8 @@ #endif
 	if (result == PCI_ERS_RESULT_CAN_RECOVER) {
 		rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
 
+		if (rc < 0)
+			goto hard_fail;
 		if (rc)
 			result = PCI_ERS_RESULT_NEED_RESET;
 		else
@@ -417,21 +414,28 @@ #endif
 	}
 
 	/* If any device has a hard failure, then shut off everything. */
-	if (result == PCI_ERS_RESULT_DISCONNECT)
+	if (result == PCI_ERS_RESULT_DISCONNECT) {
+		printk(KERN_WARNING "EEH: Device driver gave up\n");
 		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)
+		if (rc) {
+			printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
 			goto hard_fail;
+		}
 		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)
+	if ((result != PCI_ERS_RESULT_RECOVERED) &&
+	    (result != PCI_ERS_RESULT_NONE)) {
+		printk(KERN_WARNING "EEH: Not recovered\n");
 		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 49037ed..ddb80f5 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -118,9 +118,7 @@ static void eeh_thread_launcher(struct w
  * (from a workqueue).
  */
 int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev,
-                            enum pci_channel_state state,
-                            int time_unavail)
+                            struct pci_dev *dev)
 {
 	unsigned long flags;
 	struct eeh_event *event;
@@ -128,7 +126,7 @@ int eeh_send_failure_event (struct devic
 
 	if (!mem_init_done) {
 		printk(KERN_ERR "EEH: event during early boot not handled\n");
-		location = get_property(dn, "ibm,loc-code", NULL);
+		location = of_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;
@@ -144,8 +142,6 @@ int eeh_send_failure_event (struct devic
 
 	event->dn = dn;
 	event->dev = dev;
-	event->state = state;
-	event->time_unavail = time_unavail;
 
 	/* We may or may not be called in an interrupt context */
 	spin_lock_irqsave(&eeh_eventlist_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 90522e3..29bf83b 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -80,7 +80,7 @@ void __init fw_feature_init(void)
 		goto out;
 	}
 
-	hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+	hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
 	if (hypertas == NULL)
 		goto out;
 
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index f460b9c..9711eb0 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -143,7 +143,7 @@ static int pseries_add_processor(struct 
 	int err = -ENOSPC, len, nthreads, i;
 	const u32 *intserv;
 
-	intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+	intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
 	if (!intserv)
 		return 0;
 
@@ -203,7 +203,7 @@ static void pseries_remove_processor(str
 	int len, nthreads, i;
 	const u32 *intserv;
 
-	intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+	intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
 	if (!intserv)
 		return;
 
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index e6653a8..eec684a 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -242,6 +242,7 @@ static unsigned long tce_get_pSeriesLP(s
 	return tce_ret;
 }
 
+#ifdef CONFIG_PCI
 static void iommu_table_setparms(struct pci_controller *phb,
 				 struct device_node *dn,
 				 struct iommu_table *tbl)
@@ -252,8 +253,8 @@ static void iommu_table_setparms(struct 
 
 	node = (struct device_node *)phb->arch_data;
 
-	basep = get_property(node, "linux,tce-base", NULL);
-	sizep = get_property(node, "linux,tce-size", NULL);
+	basep = of_get_property(node, "linux,tce-base", NULL);
+	sizep = of_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);
@@ -403,7 +404,7 @@ static void pci_dma_bus_setup_pSeriesLP(
 
 	/* Find nearest ibm,dma-window, walking up the device tree */
 	for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
-		dma_window = get_property(pdn, "ibm,dma-window", NULL);
+		dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
 		if (dma_window != NULL)
 			break;
 	}
@@ -478,29 +479,6 @@ static void pci_dma_dev_setup_pSeries(st
 		       pci_name(dev));
 }
 
-static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
-	int err = NOTIFY_OK;
-	struct device_node *np = node;
-	struct pci_dn *pci = PCI_DN(np);
-
-	switch (action) {
-	case PSERIES_RECONFIG_REMOVE:
-		if (pci && pci->iommu_table &&
-		    get_property(np, "ibm,dma-window", NULL))
-			iommu_free_table(np);
-		break;
-	default:
-		err = NOTIFY_DONE;
-		break;
-	}
-	return err;
-}
-
-static struct notifier_block iommu_reconfig_nb = {
-	.notifier_call = iommu_reconfig_notifier,
-};
-
 static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 {
 	struct device_node *pdn, *dn;
@@ -521,11 +499,17 @@ static void pci_dma_dev_setup_pSeriesLP(
 
 	for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
 	     pdn = pdn->parent) {
-		dma_window = get_property(pdn, "ibm,dma-window", NULL);
+		dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
 		if (dma_window)
 			break;
 	}
 
+	if (!pdn || !PCI_DN(pdn)) {
+		printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: "
+		       "no DMA window found for pci dev=%s dn=%s\n",
+				 pci_name(dev), dn? dn->full_name : "<null>");
+		return;
+	}
 	DBG("  parent is %s\n", pdn->full_name);
 
 	/* Check for parent == NULL so we don't try to setup the empty EADS
@@ -554,15 +538,44 @@ static void pci_dma_dev_setup_pSeriesLP(
 
 	dev->dev.archdata.dma_data = pci->iommu_table;
 }
+#else  /* CONFIG_PCI */
+#define pci_dma_bus_setup_pSeries	NULL
+#define pci_dma_dev_setup_pSeries	NULL
+#define pci_dma_bus_setup_pSeriesLP	NULL
+#define pci_dma_dev_setup_pSeriesLP	NULL
+#endif /* !CONFIG_PCI */
+
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+	int err = NOTIFY_OK;
+	struct device_node *np = node;
+	struct pci_dn *pci = PCI_DN(np);
+
+	switch (action) {
+	case PSERIES_RECONFIG_REMOVE:
+		if (pci && pci->iommu_table &&
+		    of_get_property(np, "ibm,dma-window", NULL))
+			iommu_free_table(np);
+		break;
+	default:
+		err = NOTIFY_DONE;
+		break;
+	}
+	return err;
+}
+
+static struct notifier_block iommu_reconfig_nb = {
+	.notifier_call = iommu_reconfig_notifier,
+};
 
 /* These are called very early. */
 void iommu_init_early_pSeries(void)
 {
-	if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {
+	if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) {
 		/* Direct I/O, IOMMU off */
 		ppc_md.pci_dma_dev_setup = NULL;
 		ppc_md.pci_dma_bus_setup = NULL;
-		pci_dma_ops = &dma_direct_ops;
+		set_pci_dma_ops(&dma_direct_ops);
 		return;
 	}
 
@@ -588,6 +601,6 @@ void iommu_init_early_pSeries(void)
 
 	pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
 
-	pci_dma_ops = &dma_iommu_ops;
+	set_pci_dma_ops(&dma_iommu_ops);
 }
 
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 843ee96..362dfbc 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -209,13 +209,13 @@ void __init find_udbg_vterm(void)
 	/* find the boot console from /chosen/stdout */
 	if (!of_chosen)
 		return;
-	name = get_property(of_chosen, "linux,stdout-path", NULL);
+	name = of_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 = get_property(stdout_node, "name", NULL);
+	name = of_get_property(stdout_node, "name", NULL);
 	if (!name) {
 		printk(KERN_WARNING "stdout node missing 'name' property!\n");
 		goto out;
@@ -226,18 +226,18 @@ void __init find_udbg_vterm(void)
 	/* Check if it's a virtual terminal */
 	if (strncmp(name, "vty", 3) != 0)
 		goto out;
-	termno = get_property(stdout_node, "reg", NULL);
+	termno = of_get_property(stdout_node, "reg", NULL);
 	if (termno == NULL)
 		goto out;
 	vtermno = termno[0];
 
-	if (device_is_compatible(stdout_node, "hvterm1")) {
+	if (of_device_is_compatible(stdout_node, "hvterm1")) {
 		udbg_putc = udbg_putcLP;
 		udbg_getc = udbg_getcLP;
 		udbg_getc_poll = udbg_getc_pollLP;
 		if (add_console)
 			add_preferred_console("hvc", termno[0] & 0xff, NULL);
-	} else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+	} else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) {
 		vtermno = termno[0];
 		udbg_putc = udbg_hvsi_putc;
 		udbg_getc = udbg_hvsi_getc;
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
new file mode 100644
index 0000000..6063ea2
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright 2006-2007 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
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_FN		0
+#define RTAS_CHANGE_FN		1
+#define RTAS_RESET_FN		2
+#define RTAS_CHANGE_MSI_FN	3
+#define RTAS_CHANGE_MSIX_FN	4
+
+static struct pci_dn *get_pdn(struct pci_dev *pdev)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n");
+		return NULL;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n");
+		return NULL;
+	}
+
+	return pdn;
+}
+
+/* RTAS Helpers */
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
+{
+	u32 addr, seq_num, rtas_ret[3];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	seq_num = 1;
+	do {
+		if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN)
+			rc = rtas_call(change_token, 6, 4, rtas_ret, addr,
+					BUID_HI(buid), BUID_LO(buid),
+					func, num_irqs, seq_num);
+		else
+			rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+					BUID_HI(buid), BUID_LO(buid),
+					func, num_irqs, seq_num);
+
+		seq_num = rtas_ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc == 0) /* Success */
+		rc = rtas_ret[0];
+
+	pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n",
+		 func, num_irqs, rc);
+
+	return rc;
+}
+
+static void rtas_disable_msi(struct pci_dev *pdev)
+{
+	struct pci_dn *pdn;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return;
+
+	if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0)
+		pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+	u32 addr, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	do {
+		rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+			       BUID_HI(buid), BUID_LO(buid), offset);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		pr_debug("rtas_msi: error (%d) querying source number\n", rc);
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
+{
+	struct msi_desc *entry;
+
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+
+		set_irq_msi(entry->irq, NULL);
+		irq_dispose_mapping(entry->irq);
+	}
+
+	rtas_disable_msi(pdev);
+}
+
+static int check_req_msi(struct pci_dev *pdev, int nvec)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+	const u32 *req_msi;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return -ENODEV;
+
+	dn = pdn->node;
+
+	req_msi = of_get_property(dn, "ibm,req#msi", NULL);
+	if (!req_msi) {
+		pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name);
+		return -ENOENT;
+	}
+
+	if (*req_msi < nvec) {
+		pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	if (type == PCI_CAP_ID_MSIX)
+		pr_debug("rtas_msi: MSI-X untested, trying anyway.\n");
+
+	return check_req_msi(pdev, nvec);
+}
+
+static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+	struct pci_dn *pdn;
+	int hwirq, virq, i, rc;
+	struct msi_desc *entry;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return -ENODEV;
+
+	/*
+	 * Try the new more explicit firmware interface, if that fails fall
+	 * back to the old interface. The old interface is known to never
+	 * return MSI-Xs.
+	 */
+	if (type == PCI_CAP_ID_MSI) {
+		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
+
+		if (rc != nvec) {
+			pr_debug("rtas_msi: trying the old firmware call.\n");
+			rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
+		}
+	} else
+		rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
+
+	if (rc != nvec) {
+		pr_debug("rtas_msi: rtas_change_msi() failed\n");
+
+		/*
+		 * In case of an error it's not clear whether the device is
+		 * left with MSI enabled or not, so we explicitly disable.
+		 */
+		goto out_free;
+	}
+
+	i = 0;
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		hwirq = rtas_query_irq_number(pdn, i);
+		if (hwirq < 0) {
+			rc = hwirq;
+			pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
+			goto out_free;
+		}
+
+		virq = irq_create_mapping(NULL, hwirq);
+
+		if (virq == NO_IRQ) {
+			pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq);
+		set_irq_msi(virq, entry);
+		unmask_msi_irq(virq);
+	}
+
+	return 0;
+
+ out_free:
+	rtas_teardown_msi_irqs(pdev);
+	return rc;
+}
+
+static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
+{
+	/* No LSI -> leave MSIs (if any) configured */
+	if (pdev->irq == NO_IRQ) {
+		dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n");
+		return;
+	}
+
+	/* No MSI -> MSIs can't have been assigned by fw, leave LSI */
+	if (check_req_msi(pdev, 1)) {
+		dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n");
+		return;
+	}
+
+	dev_dbg(&pdev->dev, "rtas_msi: disabling existing MSI.\n");
+	rtas_disable_msi(pdev);
+}
+
+static int rtas_msi_init(void)
+{
+	query_token  = rtas_token("ibm,query-interrupt-source-number");
+	change_token = rtas_token("ibm,change-msi");
+
+	if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+			(change_token == RTAS_UNKNOWN_SERVICE)) {
+		pr_debug("rtas_msi: no RTAS tokens, no MSI support.\n");
+		return -1;
+	}
+
+	pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
+
+	WARN_ON(ppc_md.setup_msi_irqs);
+	ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
+	ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
+	ppc_md.msi_check_device = rtas_msi_check_device;
+
+	WARN_ON(ppc_md.pci_irq_fixup);
+	ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
+
+	return 0;
+}
+arch_initcall(rtas_msi_init);
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 64163ce..f68903e 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -130,7 +130,7 @@ int __init pSeries_nvram_init(void)
 	if (nvram == NULL)
 		return -ENODEV;
 
-	nbytes_p = get_property(nvram, "#bytes", &proplen);
+	nbytes_p = of_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 fa59124..2c6ded2 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -25,6 +25,7 @@ #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 
+#include <asm/eeh.h>
 #include <asm/pci-bridge.h>
 #include <asm/prom.h>
 #include <asm/ppc-pci.h>
@@ -39,7 +40,7 @@ void pcibios_name_device(struct pci_dev 
 	 */
 	dn = pci_device_to_OF_node(dev);
 	if (dn) {
-		char *loc_code = get_property(dn, "ibm,loc-code", 0);
+		const char *loc_code = of_get_property(dn, "ibm,loc-code", 0);
 		if (loc_code) {
 			int loc_len = strlen(loc_code);
 			if (loc_len < sizeof(dev->dev.name)) {
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index ac56b86..ffaf6c5 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -29,6 +29,7 @@ #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
 #include <asm/firmware.h>
+#include <asm/eeh.h>
 
 static struct pci_bus *
 find_bus_among_children(struct pci_bus *bus,
@@ -78,6 +79,7 @@ pcibios_remove_pci_devices(struct pci_bu
 		pci_remove_bus_device(dev);
 	}
 }
+EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
 
 /* Must be called before pci_bus_add_devices */
 void
diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c
index 2624b71..73e6902 100644
--- a/arch/powerpc/platforms/pseries/power.c
+++ b/arch/powerpc/platforms/pseries/power.c
@@ -28,13 +28,13 @@ #include <linux/init.h>
 
 unsigned long rtas_poweron_auto; /* default and normal state is 0 */
 
-static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf)
+static ssize_t auto_poweron_show(struct kset *kset, char *buf)
 {
         return sprintf(buf, "%lu\n", rtas_poweron_auto);
 }
 
 static ssize_t
-auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n)
+auto_poweron_store(struct kset *kset, const char *buf, size_t n)
 {
 	int ret;
 	unsigned long ups_restart;
@@ -72,12 +72,12 @@ static int __init pm_init(void)
 {
         int error = subsystem_register(&power_subsys);
         if (!error)
-                error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+                error = sysfs_create_group(&power_subsys.kobj, &attr_group);
         return error;
 }
 core_initcall(pm_init);
 #else
-extern struct subsystem power_subsys;
+extern struct kset power_subsys;
 
 static int __init apo_pm_init(void)
 {
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index edc0388..3a393c7 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -31,7 +31,6 @@ #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/random.h>
@@ -85,7 +84,7 @@ static void request_ras_irqs(struct devi
 	 * map those interrupts using the default interrupt host and default
 	 * trigger
 	 */
-	opicprop = get_property(np, "open-pic-interrupt", &opicplen);
+	opicprop = of_get_property(np, "open-pic-interrupt", &opicplen);
 	if (opicprop) {
 		opicplen /= sizeof(u32);
 		for (i = 0; i < opicplen; i++) {
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index 77d0937..9797b10 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -363,7 +363,7 @@ static int get_eventscan_parms(void)
 
 	node = of_find_node_by_path("/rtas");
 
-	ip = get_property(node, "rtas-event-scan-rate", NULL);
+	ip = of_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 34aff47..470db6e 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -65,6 +65,7 @@ #include <asm/i8259.h>
 #include <asm/udbg.h>
 #include <asm/smp.h>
 #include <asm/firmware.h>
+#include <asm/eeh.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
@@ -92,7 +93,7 @@ static void pSeries_show_cpuinfo(struct 
 
 	root = of_find_node_by_path("/");
 	if (root)
-		model = get_property(root, "model", NULL);
+		model = of_get_property(root, "model", NULL);
 	seq_printf(m, "machine\t\t: CHRP %s\n", model);
 	of_node_put(root);
 }
@@ -138,8 +139,8 @@ static void __init pseries_mpic_init_IRQ
 	struct mpic *mpic;
 
 	np = of_find_node_by_path("/");
-	naddr = prom_n_addr_cells(np);
-	opprop = get_property(np, "platform-open-pic", &opplen);
+	naddr = of_n_addr_cells(np);
+	opprop = of_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);
@@ -167,7 +168,7 @@ static void __init pseries_mpic_init_IRQ
 
 	/* Look for cascade */
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "chrp,iic")) {
+		if (of_device_is_compatible(np, "chrp,iic")) {
 			cascade = np;
 			break;
 		}
@@ -188,11 +189,11 @@ static void __init pseries_mpic_init_IRQ
 			break;
 		if (strcmp(np->name, "pci") != 0)
 			continue;
-		addrp = get_property(np, "8259-interrupt-acknowledge",
+		addrp = of_get_property(np, "8259-interrupt-acknowledge",
 					    NULL);
 		if (addrp == NULL)
 			continue;
-		naddr = prom_n_addr_cells(np);
+		naddr = of_n_addr_cells(np);
 		intack = addrp[naddr-1];
 		if (naddr > 1)
 			intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -225,7 +226,7 @@ static void __init pseries_discover_pic(
 
 	for (np = NULL; (np = of_find_node_by_name(np,
 						   "interrupt-controller"));) {
-		typep = get_property(np, "compatible", NULL);
+		typep = of_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;
@@ -334,32 +335,6 @@ static void __init pSeries_init_early(vo
 	DBG(" <- pSeries_init_early()\n");
 }
 
-
-static int pSeries_check_legacy_ioport(unsigned int baseport)
-{
-	struct device_node *np;
-
-#define I8042_DATA_REG	0x60
-#define FDC_BASE	0x3f0
-
-
-	switch(baseport) {
-	case I8042_DATA_REG:
-		np = of_find_node_by_type(NULL, "8042");
-		if (np == NULL)
-			return -ENODEV;
-		of_node_put(np);
-		break;
-	case FDC_BASE:
-		np = of_find_node_by_type(NULL, "fdc");
-		if (np == NULL)
-			return -ENODEV;
-		of_node_put(np);
-		break;
-	}
-	return 0;
-}
-
 /*
  * Called very early, MMU is off, device-tree isn't unflattened
  */
@@ -514,6 +489,10 @@ void pSeries_power_off(void)
 	for (;;);
 }
 
+#ifndef CONFIG_PCI
+void pSeries_final_fixup(void) { }
+#endif
+
 define_machine(pseries) {
 	.name			= "pSeries",
 	.probe			= pSeries_probe,
@@ -532,7 +511,6 @@ define_machine(pseries) {
 	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= rtas_progress,
-	.check_legacy_ioport	= pSeries_check_legacy_ioport,
 	.system_reset_exception = pSeries_system_reset_exception,
 	.machine_check_exception = pSeries_machine_check_exception,
 };
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 81d172d..b854e7f 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -477,7 +477,7 @@ static int xics_host_match(struct irq_ho
 	 * like vdevices, events, etc... The trick we use here is to match
 	 * everything here except the legacy 8259 which is compatible "chrp,iic"
 	 */
-	return !device_is_compatible(node, "chrp,iic");
+	return !of_device_is_compatible(node, "chrp,iic");
 }
 
 static int xics_host_map_direct(struct irq_host *h, unsigned int virq,
@@ -576,7 +576,7 @@ static void __init xics_init_one_node(st
 	 * This happens to be the case so far but we are playing with fire...
 	 * should be fixed one of these days. -BenH.
 	 */
-	ireg = get_property(np, "ibm,interrupt-server-ranges", NULL);
+	ireg = of_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 ..
@@ -588,7 +588,7 @@ static void __init xics_init_one_node(st
 		 */
 		*indx = *ireg;
 	}
-	ireg = get_property(np, "reg", &ilen);
+	ireg = of_get_property(np, "reg", &ilen);
 	if (!ireg)
 		panic("xics_init_IRQ: can't find interrupt reg property");
 
@@ -618,7 +618,7 @@ static void __init xics_setup_8259_casca
 	unsigned long intack = 0;
 
 	for_each_node_by_type(np, "interrupt-controller")
-		if (device_is_compatible(np, "chrp,iic")) {
+		if (of_device_is_compatible(np, "chrp,iic")) {
 			found = np;
 			break;
 		}
@@ -640,10 +640,10 @@ static void __init xics_setup_8259_casca
 			break;
 		if (strcmp(np->name, "pci") != 0)
 			continue;
-		addrp = get_property(np, "8259-interrupt-acknowledge", NULL);
+		addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL);
 		if (addrp == NULL)
 			continue;
-		naddr = prom_n_addr_cells(np);
+		naddr = of_n_addr_cells(np);
 		intack = addrp[naddr-1];
 		if (naddr > 1)
 			intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -664,10 +664,11 @@ static struct device_node *cpuid_to_of_n
 		int i, len;
 		const u32 *intserv;
 
-		intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+		intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
+					&len);
 
 		if (!intserv)
-			intserv = get_property(np, "reg", &len);
+			intserv = of_get_property(np, "reg", &len);
 
 		i = len / sizeof(u32);
 
@@ -709,7 +710,7 @@ void __init xics_init_IRQ(void)
 	/* Find the server numbers for the boot cpu. */
 	np = cpuid_to_of_node(boot_cpuid);
 	BUG_ON(!np);
-	ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+	ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
 	if (!ireg)
 		goto skip_gserver_check;
 	i = ilen / sizeof(int);
@@ -725,7 +726,7 @@ void __init xics_init_IRQ(void)
 			default_server = hcpuid;
 			default_distrib_server = ireg[j+1];
 
-			isize = get_property(np,
+			isize = of_get_property(np,
 					"ibm,interrupt-server#-size", NULL);
 			if (isize)
 				interrupt_server_size = *isize;
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 26ca3ff..9ce775c 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,9 @@ ifeq ($(CONFIG_PPC64),y)
 EXTRA_CFLAGS			+= -mno-minimal-toc
 endif
 
-obj-$(CONFIG_MPIC)		+= mpic.o
+mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o
+obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
+
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+= indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+= grackle.o
 obj-$(CONFIG_PPC_DCR)		+= dcr.o
@@ -11,17 +13,21 @@ obj-$(CONFIG_PPC_PMI)		+= pmi.o
 obj-$(CONFIG_U3_DART)		+= dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
+obj-$(CONFIG_FSL_PCIE)		+= fsl_pcie.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
 
+# contains only the suspend handler for time
+obj-$(CONFIG_PM)		+= timer.o
+
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
+obj-$(CONFIG_4xx)		+= uic.o
 endif
 
 # Temporary hack until we have migrated to asm-powerpc
 ifeq ($(ARCH),powerpc)
-obj-$(CONFIG_MTD)		+= rom.o
 obj-$(CONFIG_CPM2)		+= cpm2_common.o cpm2_pic.o
 obj-$(CONFIG_8xx)		+= mpc8xx_pic.o commproc.o
 obj-$(CONFIG_UCODE_PATCH)	+= micropatch.o
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 1488535..a1d2042 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -36,6 +36,7 @@ #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
+#include <linux/suspend.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -54,6 +55,9 @@ static unsigned long dart_tablesize;
 
 /* Virtual base address of the DART table */
 static u32 *dart_vbase;
+#ifdef CONFIG_PM
+static u32 *dart_copy;
+#endif
 
 /* Mapped base address for the dart */
 static unsigned int __iomem *dart;
@@ -333,7 +337,7 @@ void iommu_init_early_dart(void)
 		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
 
 		/* Setup pci_dma ops */
-		pci_dma_ops = &dma_iommu_ops;
+		set_pci_dma_ops(&dma_iommu_ops);
 		return;
 	}
 
@@ -343,9 +347,51 @@ void iommu_init_early_dart(void)
 	ppc_md.pci_dma_bus_setup = NULL;
 
 	/* Setup pci_dma ops */
-	pci_dma_ops = &dma_direct_ops;
+	set_pci_dma_ops(&dma_direct_ops);
 }
 
+#ifdef CONFIG_PM
+static void iommu_dart_save(void)
+{
+	memcpy(dart_copy, dart_vbase, 2*1024*1024);
+}
+
+static void iommu_dart_restore(void)
+{
+	memcpy(dart_vbase, dart_copy, 2*1024*1024);
+	dart_tlb_invalidate_all();
+}
+
+static int __init iommu_init_late_dart(void)
+{
+	unsigned long tbasepfn;
+	struct page *p;
+
+	/* if no dart table exists then we won't need to save it
+	 * and the area has also not been reserved */
+	if (!dart_tablebase)
+		return 0;
+
+	tbasepfn = __pa(dart_tablebase) >> PAGE_SHIFT;
+	register_nosave_region_late(tbasepfn,
+				    tbasepfn + ((1<<24) >> PAGE_SHIFT));
+
+	/* For suspend we need to copy the dart contents because
+	 * it is not part of the regular mapping (see above) and
+	 * thus not saved automatically. The memory for this copy
+	 * must be allocated early because we need 2 MB. */
+	p = alloc_pages(GFP_KERNEL, 21 - PAGE_SHIFT);
+	BUG_ON(!p);
+	dart_copy = page_address(p);
+
+	ppc_md.iommu_save = iommu_dart_save;
+	ppc_md.iommu_restore = iommu_dart_restore;
+
+	return 0;
+}
+
+late_initcall(iommu_init_late_dart);
+#endif
 
 void __init alloc_dart_table(void)
 {
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index 1fc5819..574b6ef 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -26,7 +26,7 @@ #include <asm/dcr.h>
 unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
 {
 	unsigned int ds;
-	const u32 *dr = get_property(np, "dcr-reg", &ds);
+	const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 
 	if (dr == NULL || ds & 1 || index >= (ds / 8))
 		return 0;
@@ -37,7 +37,7 @@ unsigned int dcr_resource_start(struct d
 unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
 {
 	unsigned int ds;
-	const u32 *dr = get_property(np, "dcr-reg", &ds);
+	const u32 *dr = of_get_property(np, "dcr-reg", &ds);
 
 	if (dr == NULL || ds & 1 || index >= (ds / 8))
 		return 0;
@@ -53,9 +53,9 @@ static struct device_node * find_dcr_par
 	const u32 *p;
 
 	for (par = of_node_get(node); par;) {
-		if (get_property(par, "dcr-controller", NULL))
+		if (of_get_property(par, "dcr-controller", NULL))
 			break;
-		p = get_property(par, "dcr-parent", NULL);
+		p = of_get_property(par, "dcr-parent", NULL);
 		tmp = par;
 		if (p == NULL)
 			par = of_get_parent(par);
@@ -80,13 +80,13 @@ u64 of_translate_dcr_address(struct devi
 		return OF_BAD_ADDR;
 
 	/* Stride is not properly defined yet, default to 0x10 for Axon */
-	p = get_property(dp, "dcr-mmio-stride", NULL);
+	p = of_get_property(dp, "dcr-mmio-stride", NULL);
 	stride = (p == NULL) ? 0x10 : *p;
 
 	/* XXX FIXME: Which property name is to use of the 2 following ? */
-	p = get_property(dp, "dcr-mmio-range", NULL);
+	p = of_get_property(dp, "dcr-mmio-range", NULL);
 	if (p == NULL)
-		p = get_property(dp, "dcr-mmio-space", NULL);
+		p = of_get_property(dp, "dcr-mmio-space", NULL);
 	if (p == NULL)
 		return OF_BAD_ADDR;
 
diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
new file mode 100644
index 0000000..041c07e
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_pcie.c
@@ -0,0 +1,171 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * "Temporary" MPC8548 Errata file -
+ * The standard indirect_pci code should work with future silicon versions.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#define PCI_CFG_OUT out_be32
+
+/* ERRATA PCI-Ex 14 PCIE Controller timeout */
+#define PCIE_FIX		out_be32(hose->cfg_addr+0x4, 0x0400ffff)
+
+
+static int
+indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
+		     int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile void __iomem *cfg_data;
+	u32 temp;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Possible artifact of CDCpp50937 needs further investigation */
+	if (devfn != 0x0 && bus->number == 0xff)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	PCIE_FIX;
+	if (bus->number == 0xff) {
+		PCI_CFG_OUT(hose->cfg_addr,
+			    (0x80000000 | ((offset & 0xf00) << 16) |
+			     ((bus->number - hose->bus_offset) << 16)
+			     | (devfn << 8) | ((offset & 0xfc) )));
+	} else {
+		PCI_CFG_OUT(hose->cfg_addr,
+			    (0x80000001 | ((offset & 0xf00) << 16) |
+			     ((bus->number - hose->bus_offset) << 16)
+			     | (devfn << 8) | ((offset & 0xfc) )));
+	}
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+	cfg_data = hose->cfg_data;
+	PCIE_FIX;
+	temp = in_le32(cfg_data);
+	switch (len) {
+	case 1:
+		*val = (temp >> (((offset & 3))*8)) & 0xff;
+		break;
+	case 2:
+		*val = (temp >> (((offset & 3))*8)) & 0xffff;
+		break;
+	default:
+		*val = temp;
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
+		      int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile void __iomem *cfg_data;
+	u32 temp;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Possible artifact of CDCpp50937 needs further investigation */
+	if (devfn != 0x0 && bus->number == 0xff)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	PCIE_FIX;
+	if (bus->number == 0xff) {
+		PCI_CFG_OUT(hose->cfg_addr,
+			    (0x80000000 | ((offset & 0xf00) << 16) |
+			     ((bus->number - hose->bus_offset) << 16)
+			     | (devfn << 8) | ((offset & 0xfc) )));
+	} else {
+		PCI_CFG_OUT(hose->cfg_addr,
+			    (0x80000001 | ((offset & 0xf00) << 16) |
+			     ((bus->number - hose->bus_offset) << 16)
+			     | (devfn << 8) | ((offset & 0xfc) )));
+        }
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	/* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
+	cfg_data = hose->cfg_data;
+	switch (len) {
+	case 1:
+		PCIE_FIX;
+		temp = in_le32(cfg_data);
+		temp = (temp & ~(0xff << ((offset & 3) * 8))) |
+			(val << ((offset & 3) * 8));
+		PCIE_FIX;
+		out_le32(cfg_data, temp);
+		break;
+	case 2:
+		PCIE_FIX;
+		temp = in_le32(cfg_data);
+		temp = (temp & ~(0xffff << ((offset & 3) * 8)));
+		temp |= (val << ((offset & 3) * 8)) ;
+		PCIE_FIX;
+		out_le32(cfg_data, temp);
+		break;
+	default:
+		PCIE_FIX;
+		out_le32(cfg_data, val);
+		break;
+	}
+	PCIE_FIX;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pcie_ops = {
+	indirect_read_config_pcie,
+	indirect_write_config_pcie
+};
+
+void __init
+setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
+	void __iomem * cfg_data)
+{
+	hose->cfg_addr = cfg_addr;
+	hose->cfg_data = cfg_data;
+	hose->ops = &indirect_pcie_ops;
+}
+
+void __init
+setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+	unsigned long base = cfg_addr & PAGE_MASK;
+	void __iomem *mbase, *addr, *data;
+
+	mbase = ioremap(base, PAGE_SIZE);
+	addr = mbase + (cfg_addr & ~PAGE_MASK);
+	if ((cfg_data & PAGE_MASK) != base)
+		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+	data = mbase + (cfg_data & ~PAGE_MASK);
+	setup_indirect_pcie_nomap(hose, addr, data);
+}
diff --git a/arch/powerpc/sysdev/fsl_pcie.h b/arch/powerpc/sysdev/fsl_pcie.h
new file mode 100644
index 0000000..8d9779c
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_pcie.h
@@ -0,0 +1,94 @@
+/*
+ * MPC85xx/86xx PCI Express structure define
+ *
+ * Copyright 2007 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 __POWERPC_FSL_PCIE_H
+#define __POWERPC_FSL_PCIE_H
+
+/* PCIE Express IO block registers in 85xx/86xx */
+
+struct ccsr_pex {
+	__be32 __iomem    pex_config_addr;	/* 0x.000 - PCI Express Configuration Address Register */
+	__be32 __iomem    pex_config_data;	/* 0x.004 - PCI Express Configuration Data Register */
+	u8 __iomem    res1[4];
+	__be32 __iomem    pex_otb_cpl_tor;	/* 0x.00c - PCI Express Outbound completion timeout register */
+	__be32 __iomem    pex_conf_tor;		/* 0x.010 - PCI Express configuration timeout register */
+	u8 __iomem    res2[12];
+	__be32 __iomem    pex_pme_mes_dr;	/* 0x.020 - PCI Express PME and message detect register */
+	__be32 __iomem    pex_pme_mes_disr;	/* 0x.024 - PCI Express PME and message disable register */
+	__be32 __iomem    pex_pme_mes_ier;	/* 0x.028 - PCI Express PME and message interrupt enable register */
+	__be32 __iomem    pex_pmcr;		/* 0x.02c - PCI Express power management command register */
+	u8 __iomem    res3[3024];
+	__be32 __iomem    pexotar0;		/* 0x.c00 - PCI Express outbound translation address register 0 */
+	__be32 __iomem    pexotear0;		/* 0x.c04 - PCI Express outbound translation extended address register 0*/
+	u8 __iomem    res4[8];
+	__be32 __iomem    pexowar0;		/* 0x.c10 - PCI Express outbound window attributes register 0*/
+	u8 __iomem    res5[12];
+	__be32 __iomem    pexotar1;		/* 0x.c20 - PCI Express outbound translation address register 1 */
+	__be32 __iomem    pexotear1;		/* 0x.c24 - PCI Express outbound translation extended address register 1*/
+	__be32 __iomem    pexowbar1;		/* 0x.c28 - PCI Express outbound window base address register 1*/
+	u8 __iomem    res6[4];
+	__be32 __iomem    pexowar1;		/* 0x.c30 - PCI Express outbound window attributes register 1*/
+	u8 __iomem    res7[12];
+	__be32 __iomem    pexotar2;		/* 0x.c40 - PCI Express outbound translation address register 2 */
+	__be32 __iomem    pexotear2;		/* 0x.c44 - PCI Express outbound translation extended address register 2*/
+	__be32 __iomem    pexowbar2;		/* 0x.c48 - PCI Express outbound window base address register 2*/
+	u8 __iomem    res8[4];
+	__be32 __iomem    pexowar2;		/* 0x.c50 - PCI Express outbound window attributes register 2*/
+	u8 __iomem    res9[12];
+	__be32 __iomem    pexotar3;		/* 0x.c60 - PCI Express outbound translation address register 3 */
+	__be32 __iomem    pexotear3;		/* 0x.c64 - PCI Express outbound translation extended address register 3*/
+	__be32 __iomem    pexowbar3;		/* 0x.c68 - PCI Express outbound window base address register 3*/
+	u8 __iomem    res10[4];
+	__be32 __iomem    pexowar3;		/* 0x.c70 - PCI Express outbound window attributes register 3*/
+	u8 __iomem    res11[12];
+	__be32 __iomem    pexotar4;		/* 0x.c80 - PCI Express outbound translation address register 4 */
+	__be32 __iomem    pexotear4;		/* 0x.c84 - PCI Express outbound translation extended address register 4*/
+	__be32 __iomem    pexowbar4;		/* 0x.c88 - PCI Express outbound window base address register 4*/
+	u8 __iomem    res12[4];
+	__be32 __iomem    pexowar4;		/* 0x.c90 - PCI Express outbound window attributes register 4*/
+	u8 __iomem    res13[12];
+	u8 __iomem    res14[256];
+	__be32 __iomem    pexitar3;		/* 0x.da0 - PCI Express inbound translation address register 3 */
+	u8 __iomem    res15[4];
+	__be32 __iomem    pexiwbar3;		/* 0x.da8 - PCI Express inbound window base address register 3 */
+	__be32 __iomem    pexiwbear3;		/* 0x.dac - PCI Express inbound window base extended address register 3 */
+	__be32 __iomem    pexiwar3;		/* 0x.db0 - PCI Express inbound window attributes register 3 */
+	u8 __iomem    res16[12];
+	__be32 __iomem    pexitar2;		/* 0x.dc0 - PCI Express inbound translation address register 2 */
+	u8 __iomem    res17[4];
+	__be32 __iomem    pexiwbar2;		/* 0x.dc8 - PCI Express inbound window base address register 2 */
+	__be32 __iomem    pexiwbear2;		/* 0x.dcc - PCI Express inbound window base extended address register 2 */
+	__be32 __iomem    pexiwar2;		/* 0x.dd0 - PCI Express inbound window attributes register 2 */
+	u8 __iomem    res18[12];
+	__be32 __iomem    pexitar1;		/* 0x.de0 - PCI Express inbound translation address register 2 */
+	u8 __iomem    res19[4];
+	__be32 __iomem    pexiwbar1;		/* 0x.de8 - PCI Express inbound window base address register 2 */
+	__be32 __iomem    pexiwbear1;		/* 0x.dec - PCI Express inbound window base extended address register 2 */
+	__be32 __iomem    pexiwar1;		/* 0x.df0 - PCI Express inbound window attributes register 2 */
+	u8 __iomem    res20[12];
+	__be32 __iomem    pex_err_dr;		/* 0x.e00 - PCI Express error detect register */
+	u8 __iomem    res21[4];
+	__be32 __iomem    pex_err_en;		/* 0x.e08 - PCI Express error interrupt enable register */
+	u8 __iomem    res22[4];
+	__be32 __iomem    pex_err_disr;		/* 0x.e10 - PCI Express error disable register */
+	u8 __iomem    res23[12];
+	__be32 __iomem    pex_err_cap_stat;	/* 0x.e20 - PCI Express error capture status register */
+	u8 __iomem    res24[4];
+	__be32 __iomem    pex_err_cap_r0;	/* 0x.e28 - PCI Express error capture register 0 */
+	__be32 __iomem    pex_err_cap_r1;	/* 0x.e2c - PCI Express error capture register 0 */
+	__be32 __iomem    pex_err_cap_r2;	/* 0x.e30 - PCI Express error capture register 0 */
+	__be32 __iomem    pex_err_cap_r3;	/* 0x.e34 - PCI Express error capture register 0 */
+};
+
+#endif /* __POWERPC_FSL_PCIE_H */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index d20f029..8a123c7 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -52,7 +52,7 @@ phys_addr_t get_immrbase(void)
 	soc = of_find_node_by_type(NULL, "soc");
 	if (soc) {
 		unsigned int size;
-		const void *prop = get_property(soc, "reg", &size);
+		const void *prop = of_get_property(soc, "reg", &size);
 
 		if (prop)
 			immrbase = of_translate_address(soc, prop);
@@ -78,8 +78,8 @@ u32 get_brgfreq(void)
 	node = of_find_node_by_type(NULL, "cpm");
 	if (node) {
 		unsigned int size;
-		const unsigned int *prop = get_property(node, "brg-frequency",
-					&size);
+		const unsigned int *prop = of_get_property(node,
+					"brg-frequency", &size);
 
 		if (prop)
 			brgfreq = *prop;
@@ -103,8 +103,8 @@ u32 get_baudrate(void)
 	node = of_find_node_by_type(NULL, "serial");
 	if (node) {
 		unsigned int size;
-		const unsigned int *prop = get_property(node, "current-speed",
-				&size);
+		const unsigned int *prop = of_get_property(node,
+				"current-speed", &size);
 
 		if (prop)
 			fs_baudrate = *prop;
@@ -153,7 +153,8 @@ static int __init gfar_mdio_of_init(void
 		while ((child = of_get_next_child(np, child)) != NULL) {
 			int irq = irq_of_parse_and_map(child, 0);
 			if (irq != NO_IRQ) {
-				const u32 *id = get_property(child, "reg", NULL);
+				const u32 *id = of_get_property(child,
+							"reg", NULL);
 				mdio_data.irq[*id] = irq;
 			}
 		}
@@ -209,7 +210,7 @@ static int __init gfar_of_init(void)
 
 		of_irq_to_resource(np, 0, &r[1]);
 
-		model = get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 
 		/* If we aren't the FEC we have multiple interrupts */
 		if (model && strcasecmp(model, "FEC")) {
@@ -253,7 +254,7 @@ static int __init gfar_of_init(void)
 			    FSL_GIANFAR_DEV_HAS_VLAN |
 			    FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
 
-		ph = get_property(np, "phy-handle", NULL);
+		ph = of_get_property(np, "phy-handle", NULL);
 		phy = of_find_node_by_phandle(*ph);
 
 		if (phy == NULL) {
@@ -263,7 +264,7 @@ static int __init gfar_of_init(void)
 
 		mdio = of_get_parent(phy);
 
-		id = get_property(phy, "reg", NULL);
+		id = of_get_property(phy, "reg", NULL);
 		ret = of_address_to_resource(mdio, 0, &res);
 		if (ret) {
 			of_node_put(phy);
@@ -325,11 +326,11 @@ static int __init fsl_i2c_of_init(void)
 		}
 
 		i2c_data.device_flags = 0;
-		flags = get_property(np, "dfsrr", NULL);
+		flags = of_get_property(np, "dfsrr", NULL);
 		if (flags)
 			i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
 
-		flags = get_property(np, "fsl5200-clocking", NULL);
+		flags = of_get_property(np, "fsl5200-clocking", NULL);
 		if (flags)
 			i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
 
@@ -374,7 +375,7 @@ static int __init mpc83xx_wdt_init(void)
 		goto nosoc;
 	}
 
-	freq = get_property(soc, "bus-frequency", NULL);
+	freq = of_get_property(soc, "bus-frequency", NULL);
 	if (!freq) {
 		ret = -ENODEV;
 		goto err;
@@ -466,15 +467,15 @@ static int __init fsl_usb_of_init(void)
 
 		usb_data.operating_mode = FSL_USB2_MPH_HOST;
 
-		prop = get_property(np, "port0", NULL);
+		prop = of_get_property(np, "port0", NULL);
 		if (prop)
 			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
 
-		prop = get_property(np, "port1", NULL);
+		prop = of_get_property(np, "port1", NULL);
 		if (prop)
 			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
 
-		prop = get_property(np, "phy_type", NULL);
+		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
 		ret =
@@ -501,7 +502,7 @@ static int __init fsl_usb_of_init(void)
 
 		of_irq_to_resource(np, 0, &r[1]);
 
-		prop = get_property(np, "dr_mode", NULL);
+		prop = of_get_property(np, "dr_mode", NULL);
 
 		if (!prop || !strcmp(prop, "host")) {
 			usb_data.operating_mode = FSL_USB2_DR_HOST;
@@ -538,7 +539,7 @@ static int __init fsl_usb_of_init(void)
 			goto err;
 		}
 
-		prop = get_property(np, "phy_type", NULL);
+		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
 		if (usb_dev_dr_host) {
@@ -633,7 +634,7 @@ static int __init fs_enet_of_init(void)
 			goto err;
 		}
 
-		model = get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 		if (model == NULL) {
 			ret = -ENODEV;
 			goto unreg;
@@ -643,7 +644,7 @@ static int __init fs_enet_of_init(void)
 		if (mac_addr)
 			memcpy(fs_enet_data.macaddr, mac_addr, 6);
 
-		ph = get_property(np, "phy-handle", NULL);
+		ph = of_get_property(np, "phy-handle", NULL);
 		phy = of_find_node_by_phandle(*ph);
 
 		if (phy == NULL) {
@@ -651,12 +652,12 @@ static int __init fs_enet_of_init(void)
 			goto unreg;
 		}
 
-		phy_addr = get_property(phy, "reg", NULL);
+		phy_addr = of_get_property(phy, "reg", NULL);
 		fs_enet_data.phy_addr = *phy_addr;
 
-		phy_irq = get_property(phy, "interrupts", NULL);
+		phy_irq = of_get_property(phy, "interrupts", NULL);
 
-		id = get_property(np, "device-id", NULL);
+		id = of_get_property(np, "device-id", NULL);
 		fs_enet_data.fs_no = *id;
 		strcpy(fs_enet_data.fs_type, model);
 
@@ -668,8 +669,10 @@ static int __init fs_enet_of_init(void)
                         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));
+		fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
+						"rx-clock", NULL));
+		fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
+						"tx-clock", NULL));
 
 		if (strstr(model, "FCC")) {
 			int fcc_index = *id - 1;
@@ -690,7 +693,7 @@ static int __init fs_enet_of_init(void)
 			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);
+			mdio_bb_prop = of_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;
@@ -796,10 +799,10 @@ static int __init cpm_uart_of_init(void)
 			goto err;
 		}
 
-		id = get_property(np, "device-id", NULL);
+		id = of_get_property(np, "device-id", NULL);
 		cpm_uart_data.fs_no = *id;
 
-		model = (char*)get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 		strcpy(cpm_uart_data.fs_type, model);
 
 		cpm_uart_data.uart_clk = ppc_proc_freq;
@@ -808,8 +811,10 @@ static int __init cpm_uart_of_init(void)
 		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));
+		cpm_uart_data.clk_rx = *((u32 *)of_get_property(np,
+						"rx-clock", NULL));
+		cpm_uart_data.clk_tx = *((u32 *)of_get_property(np,
+						"tx-clock", NULL));
 
 		ret =
 		    platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
@@ -833,7 +838,7 @@ #endif /* CONFIG_CPM2 */
 #ifdef CONFIG_8xx
 
 extern void init_scc_ioports(struct fs_platform_info*);
-extern int platform_device_skip(char *model, int id);
+extern int platform_device_skip(const char *model, int id);
 
 static int __init fs_enet_mdio_of_init(void)
 {
@@ -900,21 +905,22 @@ static int __init fs_enet_of_init(void)
 		struct resource r[4];
 		struct device_node *phy = NULL, *mdio = NULL;
 		struct fs_platform_info fs_enet_data;
-		unsigned int *id, *phy_addr;
+		const unsigned int *id;
+		const unsigned int *phy_addr;
 		void *mac_addr;
-		phandle *ph;
-		char *model;
+		const phandle *ph;
+		const char *model;
 
 		memset(r, 0, sizeof(r));
 		memset(&fs_enet_data, 0, sizeof(fs_enet_data));
 
-		model = (char *)get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 		if (model == NULL) {
 			ret = -ENODEV;
 			goto unreg;
 		}
 
-		id = (u32 *) get_property(np, "device-id", NULL);
+		id = of_get_property(np, "device-id", NULL);
 		fs_enet_data.fs_no = *id;
 
 		if (platform_device_skip(model, *id))
@@ -929,12 +935,12 @@ static int __init fs_enet_of_init(void)
 		if (mac_addr)
 			memcpy(fs_enet_data.macaddr, mac_addr, 6);
 
-		ph = (phandle *) get_property(np, "phy-handle", NULL);
+		ph = of_get_property(np, "phy-handle", NULL);
 		if (ph != NULL)
 			phy = of_find_node_by_phandle(*ph);
 
 		if (phy != NULL) {
-			phy_addr = (u32 *) get_property(phy, "reg", NULL);
+			phy_addr = of_get_property(phy, "reg", NULL);
 			fs_enet_data.phy_addr = *phy_addr;
 			fs_enet_data.has_phy = 1;
 
@@ -947,7 +953,7 @@ static int __init fs_enet_of_init(void)
 			}
 		}
 
-		model = (char*)get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 		strcpy(fs_enet_data.fs_type, model);
 
 		if (strstr(model, "FEC")) {
@@ -1038,8 +1044,8 @@ static int __init cpm_smc_uart_of_init(v
 	     i++) {
 		struct resource r[3];
 		struct fs_uart_platform_info cpm_uart_data;
-		int *id;
-		char *model;
+		const int *id;
+		const char *model;
 
 		memset(r, 0, sizeof(r));
 		memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
@@ -1066,10 +1072,10 @@ static int __init cpm_smc_uart_of_init(v
 			goto err;
 		}
 
-		model = (char*)get_property(np, "model", NULL);
+		model = of_get_property(np, "model", NULL);
 		strcpy(cpm_uart_data.fs_type, model);
 
-		id = (int*)get_property(np, "device-id", NULL);
+		id = of_get_property(np, "device-id", NULL);
 		cpm_uart_data.fs_no = *id;
 		cpm_uart_data.uart_clk = ppc_proc_freq;
 
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index bcfb900..4fd2bec 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -36,6 +36,8 @@ #include <asm/machdep.h>
 #include <asm/mpic.h>
 #include <asm/smp.h>
 
+#include "mpic.h"
+
 #ifdef DEBUG
 #define DBG(fmt...) printk(fmt)
 #else
@@ -304,7 +306,7 @@ static void __init mpic_test_broken_ipi(
 	}
 }
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 
 /* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
  * to force the edge setting on the MPIC and do the ack workaround.
@@ -354,6 +356,12 @@ static void mpic_startup_ht_interrupt(st
 		tmp |= 0x22;
 	writel(tmp, fixup->base + 4);
 	spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+	/* use the lowest bit inverted to the actual HW,
+	 * set if this fixup was enabled, clear otherwise */
+	mpic->save_data[source].fixup_data = tmp | 1;
+#endif
 }
 
 static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
@@ -375,7 +383,57 @@ static void mpic_shutdown_ht_interrupt(s
 	tmp |= 1;
 	writel(tmp, fixup->base + 4);
 	spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+	/* use the lowest bit inverted to the actual HW,
+	 * set if this fixup was enabled, clear otherwise */
+	mpic->save_data[source].fixup_data = tmp & ~1;
+#endif
+}
+
+#ifdef CONFIG_PCI_MSI
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+				    unsigned int devfn)
+{
+	u8 __iomem *base;
+	u8 pos, flags;
+	u64 addr = 0;
+
+	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) {
+			id = readb(devbase + pos + 3);
+			if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING)
+				break;
+		}
+	}
+
+	if (pos == 0)
+		return;
+
+	base = devbase + pos;
+
+	flags = readb(base + HT_MSI_FLAGS);
+	if (!(flags & HT_MSI_FLAGS_FIXED)) {
+		addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK;
+		addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32);
+	}
+
+	printk(KERN_DEBUG "mpic:   - HT:%02x.%x %s MSI mapping found @ 0x%lx\n",
+		PCI_SLOT(devfn), PCI_FUNC(devfn),
+		flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr);
+
+	if (!(flags & HT_MSI_FLAGS_ENABLE))
+		writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS);
 }
+#else
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+				    unsigned int devfn)
+{
+	return;
+}
+#endif
 
 static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
 				    unsigned int devfn, u32 vdid)
@@ -468,6 +526,7 @@ static void __init mpic_scan_ht_pics(str
 			goto next;
 
 		mpic_scan_ht_pic(mpic, devbase, devfn, l);
+		mpic_scan_ht_msi(mpic, devbase, devfn);
 
 	next:
 		/* next device, if function 0 */
@@ -476,7 +535,7 @@ static void __init mpic_scan_ht_pics(str
 	}
 }
 
-#else /* CONFIG_MPIC_BROKEN_U3 */
+#else /* CONFIG_MPIC_U3_HT_IRQS */
 
 static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
 {
@@ -487,7 +546,7 @@ static void __init mpic_scan_ht_pics(str
 {
 }
 
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 #define mpic_irq_to_hw(virq)	((unsigned int)irq_map[virq].hwirq)
@@ -559,7 +618,7 @@ #endif /* CONFIG_SMP */
  */
 
 
-static void mpic_unmask_irq(unsigned int irq)
+void mpic_unmask_irq(unsigned int irq)
 {
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
@@ -579,7 +638,7 @@ static void mpic_unmask_irq(unsigned int
 	} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
 }
 
-static void mpic_mask_irq(unsigned int irq)
+void mpic_mask_irq(unsigned int irq)
 {
 	unsigned int loops = 100000;
 	struct mpic *mpic = mpic_from_irq(irq);
@@ -600,7 +659,7 @@ static void mpic_mask_irq(unsigned int i
 	} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
 }
 
-static void mpic_end_irq(unsigned int irq)
+void mpic_end_irq(unsigned int irq)
 {
 	struct mpic *mpic = mpic_from_irq(irq);
 
@@ -615,7 +674,7 @@ #endif
 	mpic_eoi(mpic);
 }
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 
 static void mpic_unmask_ht_irq(unsigned int irq)
 {
@@ -665,7 +724,7 @@ #endif
 		mpic_ht_end_irq(mpic, src);
 	mpic_eoi(mpic);
 }
-#endif /* !CONFIG_MPIC_BROKEN_U3 */
+#endif /* !CONFIG_MPIC_U3_HT_IRQS */
 
 #ifdef CONFIG_SMP
 
@@ -733,7 +792,7 @@ static unsigned int mpic_type_to_vecpri(
 	}
 }
 
-static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
+int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
 {
 	struct mpic *mpic = mpic_from_irq(virq);
 	unsigned int src = mpic_irq_to_hw(virq);
@@ -788,7 +847,7 @@ static struct irq_chip mpic_ipi_chip = {
 };
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 static struct irq_chip mpic_irq_ht_chip = {
 	.startup	= mpic_startup_ht_irq,
 	.shutdown	= mpic_shutdown_ht_irq,
@@ -797,7 +856,7 @@ static struct irq_chip mpic_irq_ht_chip 
 	.eoi		= mpic_end_ht_irq,
 	.set_type	= mpic_set_irq_type,
 };
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 static int mpic_host_match(struct irq_host *h, struct device_node *node)
@@ -834,14 +893,16 @@ #endif /* CONFIG_SMP */
 	if (hw >= mpic->irq_count)
 		return -EINVAL;
 
+	mpic_msi_reserve_hwirq(mpic, hw);
+
 	/* Default chip */
 	chip = &mpic->hc_irq;
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 	/* Check for HT interrupts, override vecpri */
 	if (mpic_is_ht_interrupt(mpic, hw))
 		chip = &mpic->hc_ht_irq;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 	DBG("mpic: mapping to irq chip @%p\n", chip);
 
@@ -937,12 +998,12 @@ struct mpic * __init mpic_alloc(struct d
 	mpic->hc_irq.typename = name;
 	if (flags & MPIC_PRIMARY)
 		mpic->hc_irq.set_affinity = mpic_set_affinity;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 	mpic->hc_ht_irq = mpic_irq_ht_chip;
 	mpic->hc_ht_irq.typename = name;
 	if (flags & MPIC_PRIMARY)
 		mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 #ifdef CONFIG_SMP
 	mpic->hc_ipi = mpic_ipi_chip;
@@ -970,7 +1031,7 @@ #endif /* CONFIG_SMP */
 	mpic->spurious_vec  = intvec_top;
 
 	/* Check for "big-endian" in device-tree */
-	if (node && get_property(node, "big-endian", NULL) != NULL)
+	if (node && of_get_property(node, "big-endian", NULL) != NULL)
 		mpic->flags |= MPIC_BIG_ENDIAN;
 
 
@@ -986,13 +1047,13 @@ #endif
 	BUG_ON(paddr == 0 && node == NULL);
 
 	/* If no physical address passed in, check if it's dcr based */
-	if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL)
+	if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL)
 		mpic->flags |= MPIC_USES_DCR;
 
 #ifdef CONFIG_PPC_DCR
 	if (mpic->flags & MPIC_USES_DCR) {
 		const u32 *dbasep;
-		dbasep = get_property(node, "dcr-reg", NULL);
+		dbasep = of_get_property(node, "dcr-reg", NULL);
 		BUG_ON(dbasep == NULL);
 		mpic->dcr_base = *dbasep;
 		mpic->reg_type = mpic_access_dcr;
@@ -1006,7 +1067,7 @@ #endif /* CONFIG_PPC_DCR */
 	 */
 	if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) {
 		const u32 *reg;
-		reg = get_property(node, "reg", NULL);
+		reg = of_get_property(node, "reg", NULL);
 		BUG_ON(reg == NULL);
 		paddr = of_translate_address(node, reg);
 		BUG_ON(paddr == OF_BAD_ADDR);
@@ -1142,8 +1203,10 @@ void __init mpic_init(struct mpic *mpic)
 
 	/* Do the HT PIC fixups on U3 broken mpic */
 	DBG("MPIC flags: %x\n", mpic->flags);
-	if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
- 		mpic_scan_ht_pics(mpic);
+	if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) {
+		mpic_scan_ht_pics(mpic);
+		mpic_u3msi_init(mpic);
+	}
 
 	for (i = 0; i < mpic->num_sources; i++) {
 		/* start with vector = source number, and masked */
@@ -1167,6 +1230,12 @@ void __init mpic_init(struct mpic *mpic)
 
 	/* Set current processor priority to 0 */
 	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
+
+#ifdef CONFIG_PM
+	/* allocate memory to save mpic state */
+	mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
+	BUG_ON(mpic->save_data == NULL);
+#endif
 }
 
 void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
@@ -1333,8 +1402,11 @@ unsigned int mpic_get_one_irq(struct mpi
 #ifdef DEBUG_LOW
 	DBG("%s: get_one_irq(): %d\n", mpic->name, src);
 #endif
-	if (unlikely(src == mpic->spurious_vec))
+	if (unlikely(src == mpic->spurious_vec)) {
+		if (mpic->flags & MPIC_SPV_EOI)
+			mpic_eoi(mpic);
 		return NO_IRQ;
+	}
 	return irq_linear_revmap(mpic->irqhost, src);
 }
 
@@ -1417,3 +1489,79 @@ void __devinit smp_mpic_setup_cpu(int cp
 	mpic_setup_this_cpu();
 }
 #endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PM
+static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+	int i;
+
+	for (i = 0; i < mpic->num_sources; i++) {
+		mpic->save_data[i].vecprio =
+			mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI));
+		mpic->save_data[i].dest =
+			mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
+	}
+
+	return 0;
+}
+
+static int mpic_resume(struct sys_device *dev)
+{
+	struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+	int i;
+
+	for (i = 0; i < mpic->num_sources; i++) {
+		mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI),
+			       mpic->save_data[i].vecprio);
+		mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+			       mpic->save_data[i].dest);
+
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+	{
+		struct mpic_irq_fixup *fixup = &mpic->fixups[i];
+
+		if (fixup->base) {
+			/* we use the lowest bit in an inverted meaning */
+			if ((mpic->save_data[i].fixup_data & 1) == 0)
+				continue;
+
+			/* Enable and configure */
+			writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+
+			writel(mpic->save_data[i].fixup_data & ~1,
+			       fixup->base + 4);
+		}
+	}
+#endif
+	} /* end for loop */
+
+	return 0;
+}
+#endif
+
+static struct sysdev_class mpic_sysclass = {
+#ifdef CONFIG_PM
+	.resume = mpic_resume,
+	.suspend = mpic_suspend,
+#endif
+	set_kset_name("mpic"),
+};
+
+static int mpic_init_sys(void)
+{
+	struct mpic *mpic = mpics;
+	int error, id = 0;
+
+	error = sysdev_class_register(&mpic_sysclass);
+
+	while (mpic && !error) {
+		mpic->sysdev.cls = &mpic_sysclass;
+		mpic->sysdev.id = id++;
+		error = sysdev_register(&mpic->sysdev);
+		mpic = mpic->next;
+	}
+	return error;
+}
+
+device_initcall(mpic_init_sys);
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
new file mode 100644
index 0000000..3a1c3d2
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic.h
@@ -0,0 +1,38 @@
+#ifndef _POWERPC_SYSDEV_MPIC_H
+#define _POWERPC_SYSDEV_MPIC_H
+
+/*
+ * Copyright 2006-2007, Michael Ellerman, 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; version 2 of the
+ * License.
+ *
+ */
+
+#ifdef CONFIG_PCI_MSI
+extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
+extern int mpic_msi_init_allocator(struct mpic *mpic);
+extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
+extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
+extern int mpic_u3msi_init(struct mpic *mpic);
+#else
+static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
+					  irq_hw_number_t hwirq)
+{
+	return;
+}
+
+static inline int mpic_u3msi_init(struct mpic *mpic)
+{
+	return -1;
+}
+#endif
+
+extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_end_irq(unsigned int irq);
+extern void mpic_mask_irq(unsigned int irq);
+extern void mpic_unmask_irq(unsigned int irq);
+
+#endif /* _POWERPC_SYSDEV_MPIC_H */
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
new file mode 100644
index 0000000..b076793
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/bitmap.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+
+static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
+	bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
+}
+
+void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+	unsigned long flags;
+
+	/* The mpic calls this even when there is no allocator setup */
+	if (!mpic->hwirq_bitmap)
+		return;
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	__mpic_msi_reserve_hwirq(mpic, hwirq);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
+{
+	unsigned long flags;
+	int offset, order = get_count_order(num);
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	/*
+	 * This is fast, but stricter than we need. We might want to add
+	 * a fallback routine which does a linear search with no alignment.
+	 */
+	offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count,
+					 order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+
+	pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	return offset;
+}
+
+void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
+{
+	unsigned long flags;
+	int order = get_count_order(num);
+
+	pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
+		 num, order, offset);
+
+	spin_lock_irqsave(&mpic->bitmap_lock, flags);
+	bitmap_release_region(mpic->hwirq_bitmap, offset, order);
+	spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+	irq_hw_number_t hwirq;
+	struct irq_host_ops *ops = mpic->irqhost->ops;
+	struct device_node *np;
+	int flags, index, i;
+	struct of_irq oirq;
+
+	pr_debug("mpic: found U3, guessing msi allocator setup\n");
+
+	/* Reserve source numbers we know are reserved in the HW */
+	for (i = 0;   i < 8;   i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	for (i = 42;  i < 46;  i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	for (i = 100; i < 105; i++)
+		__mpic_msi_reserve_hwirq(mpic, i);
+
+	np = NULL;
+	while ((np = of_find_all_nodes(np))) {
+		pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
+
+		index = 0;
+		while (of_irq_map_one(np, index++, &oirq) == 0) {
+			ops->xlate(mpic->irqhost, NULL, oirq.specifier,
+						oirq.size, &hwirq, &flags);
+			__mpic_msi_reserve_hwirq(mpic, hwirq);
+		}
+	}
+
+	return 0;
+}
+#else
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+	return -1;
+}
+#endif
+
+static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
+{
+	int i, len;
+	const u32 *p;
+
+	p = of_get_property(mpic->of_node, "msi-available-ranges", &len);
+	if (!p) {
+		pr_debug("mpic: no msi-available-ranges property found on %s\n",
+			  mpic->of_node->full_name);
+		return -ENODEV;
+	}
+
+	if (len % 8 != 0) {
+		printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
+		       "property on %s\n", mpic->of_node->full_name);
+		return -EINVAL;
+	}
+
+	bitmap_allocate_region(mpic->hwirq_bitmap, 0,
+			       get_count_order(mpic->irq_count));
+
+	/* Format is: (<u32 start> <u32 count>)+ */
+	len /= sizeof(u32);
+	for (i = 0; i < len / 2; i++, p += 2)
+		mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
+
+	return 0;
+}
+
+int mpic_msi_init_allocator(struct mpic *mpic)
+{
+	int rc, size;
+
+	BUG_ON(mpic->hwirq_bitmap);
+	spin_lock_init(&mpic->bitmap_lock);
+
+	size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
+	pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+
+	if (mem_init_done)
+		mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL);
+	else
+		mpic->hwirq_bitmap = alloc_bootmem(size);
+
+	if (!mpic->hwirq_bitmap) {
+		pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
+		return -ENOMEM;
+	}
+
+	memset(mpic->hwirq_bitmap, 0, size);
+
+	rc = mpic_msi_reserve_dt_hwirqs(mpic);
+	if (rc) {
+		if (mpic->flags & MPIC_U3_HT_IRQS)
+			rc = mpic_msi_reserve_u3_hwirqs(mpic);
+
+		if (rc)
+			goto out_free;
+	}
+
+	return 0;
+
+ out_free:
+	if (mem_init_done)
+		kfree(mpic->hwirq_bitmap);
+
+	mpic->hwirq_bitmap = NULL;
+	return rc;
+}
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
new file mode 100644
index 0000000..305b864
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2006, Segher Boessenkool, IBM Corporation.
+ * Copyright 2006-2007, Michael Ellerman, 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+#include "mpic.h"
+
+/* A bit ugly, can we get this from the pci_dev somehow? */
+static struct mpic *msi_mpic;
+
+static void mpic_u3msi_mask_irq(unsigned int irq)
+{
+	mask_msi_irq(irq);
+	mpic_mask_irq(irq);
+}
+
+static void mpic_u3msi_unmask_irq(unsigned int irq)
+{
+	mpic_unmask_irq(irq);
+	unmask_msi_irq(irq);
+}
+
+static struct irq_chip mpic_u3msi_chip = {
+	.shutdown	= mpic_u3msi_mask_irq,
+	.mask		= mpic_u3msi_mask_irq,
+	.unmask		= mpic_u3msi_unmask_irq,
+	.eoi		= mpic_end_irq,
+	.set_type	= mpic_set_irq_type,
+	.typename	= "MPIC-U3MSI",
+};
+
+static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
+{
+	u8 flags;
+	u32 tmp;
+	u64 addr;
+
+	pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags);
+
+	if (flags & HT_MSI_FLAGS_FIXED)
+		return HT_MSI_FIXED_ADDR;
+
+	pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp);
+	addr = tmp & HT_MSI_ADDR_LO_MASK;
+	pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp);
+	addr = addr | ((u64)tmp << 32);
+
+	return addr;
+}
+
+static u64 find_ht_magic_addr(struct pci_dev *pdev)
+{
+	struct pci_bus *bus;
+	unsigned int pos;
+
+	for (bus = pdev->bus; bus; bus = bus->parent) {
+		pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING);
+		if (pos)
+			return read_ht_magic_addr(bus->self, pos);
+	}
+
+	return 0;
+}
+
+static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	if (type == PCI_CAP_ID_MSIX)
+		pr_debug("u3msi: MSI-X untested, trying anyway.\n");
+
+	/* If we can't find a magic address then MSI ain't gonna work */
+	if (find_ht_magic_addr(pdev) == 0) {
+		pr_debug("u3msi: no magic address found for %s\n",
+			 pci_name(pdev));
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
+{
+	struct msi_desc *entry;
+
+        list_for_each_entry(entry, &pdev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+
+		set_irq_msi(entry->irq, NULL);
+		mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
+		irq_dispose_mapping(entry->irq);
+	}
+
+	return;
+}
+
+static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq,
+				  struct msi_msg *msg)
+{
+	u64 addr;
+
+	addr = find_ht_magic_addr(pdev);
+	msg->address_lo = addr & 0xFFFFFFFF;
+	msg->address_hi = addr >> 32;
+	msg->data = virq_to_hw(virq);
+
+	pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n",
+		 virq, virq_to_hw(virq), addr);
+}
+
+static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+	irq_hw_number_t hwirq;
+	int rc;
+	unsigned int virq;
+	struct msi_desc *entry;
+	struct msi_msg msg;
+
+	list_for_each_entry(entry, &pdev->msi_list, list) {
+		hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1);
+		if (hwirq < 0) {
+			rc = hwirq;
+			pr_debug("u3msi: failed allocating hwirq\n");
+			goto out_free;
+		}
+
+		virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
+		if (virq == NO_IRQ) {
+			pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
+			mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		set_irq_msi(virq, entry);
+		set_irq_chip(virq, &mpic_u3msi_chip);
+		set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+
+		u3msi_compose_msi_msg(pdev, virq, &msg);
+		write_msi_msg(virq, &msg);
+
+		hwirq++;
+	}
+
+	return 0;
+
+ out_free:
+	u3msi_teardown_msi_irqs(pdev);
+	return rc;
+}
+
+int mpic_u3msi_init(struct mpic *mpic)
+{
+	int rc;
+
+	rc = mpic_msi_init_allocator(mpic);
+	if (rc) {
+		pr_debug("u3msi: Error allocating bitmap!\n");
+		return rc;
+	}
+
+	pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n");
+
+	BUG_ON(msi_mpic);
+	msi_mpic = mpic;
+
+	WARN_ON(ppc_md.setup_msi_irqs);
+	ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs;
+	ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs;
+	ppc_md.msi_check_device = u3msi_msi_check_device;
+
+	return 0;
+}
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index a528201..85a7c99 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -33,7 +33,7 @@ #include <asm/of_device.h>
 #include <asm/of_platform.h>
 #include <asm/io.h>
 #include <asm/pmi.h>
-
+#include <asm/prom.h>
 
 struct pmi_data {
 	struct list_head	handler;
@@ -49,21 +49,6 @@ struct pmi_data {
 };
 
 
-
-static void __iomem *of_iomap(struct device_node *np)
-{
-	struct resource res;
-
-	if (of_address_to_resource(np, 0, &res))
-		return NULL;
-
-	pr_debug("Resource start: 0x%lx\n", res.start);
-	pr_debug("Resource end: 0x%lx\n", res.end);
-
-	return ioremap(res.start, 1 + res.end - res.start);
-}
-
-
 static int pmi_irq_handler(int irq, void *dev_id)
 {
 	struct pmi_data *data;
@@ -118,6 +103,7 @@ out:
 
 static struct of_device_id pmi_match[] = {
 	{ .type = "ibm,pmi", .name = "ibm,pmi" },
+	{ .type = "ibm,pmi" },
 	{},
 };
 
@@ -153,7 +139,7 @@ static int pmi_of_probe(struct of_device
 		goto out;
 	}
 
-	data->pmi_reg = of_iomap(np);
+	data->pmi_reg = of_iomap(np, 0);
 	if (!data->pmi_reg) {
 		printk(KERN_ERR "pmi: invalid register address.\n");
 		rc = -EFAULT;
@@ -279,6 +265,9 @@ void pmi_register_handler(struct of_devi
 	struct pmi_data *data;
 	data = device->dev.driver_data;
 
+	if (!data)
+		return;
+
 	spin_lock(&data->handler_spinlock);
 	list_add_tail(&handler->node, &data->handler);
 	spin_unlock(&data->handler_spinlock);
@@ -289,10 +278,12 @@ void pmi_unregister_handler(struct of_de
 			    struct pmi_handler *handler)
 {
 	struct pmi_data *data;
+	data = device->dev.driver_data;
 
-	pr_debug("pmi: unregistering handler %p\n", handler);
+	if (!data)
+		return;
 
-	data = device->dev.driver_data;
+	pr_debug("pmi: unregistering handler %p\n", handler);
 
 	spin_lock(&data->handler_spinlock);
 	list_del(&handler->node);
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index a725e80..887739f 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -2,11 +2,8 @@ #
 # QE Communication options
 #
 
-menu "QE Options"
-	depends on QUICC_ENGINE
-
 config UCC_SLOW
-	bool "UCC Slow Protocols Support"
+	bool
 	default n
 	select UCC
 	help
@@ -14,10 +11,9 @@ config UCC_SLOW
 	  protocols: UART, BISYNC, QMC
 
 config UCC_FAST
-	bool "UCC Fast Protocols Support"
+	bool
 	default n
 	select UCC
-	select UCC_SLOW
 	help
 	  This option provides qe_lib support to UCC fast
 	  protocols: HDLC, Ethernet, ATM, transparent
@@ -26,5 +22,3 @@ config UCC
 	bool
 	default y if UCC_FAST || UCC_SLOW
 
-endmenu
-
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 43f6cc9..7f4c075 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -71,7 +71,7 @@ phys_addr_t get_qe_base(void)
 	qe = of_find_node_by_type(NULL, "qe");
 	if (qe) {
 		unsigned int size;
-		const void *prop = get_property(qe, "reg", &size);
+		const void *prop = of_get_property(qe, "reg", &size);
 		qebase = of_translate_address(qe, prop);
 		of_node_put(qe);
 	};
@@ -158,7 +158,7 @@ unsigned int get_brg_clk(void)
 	qe = of_find_node_by_type(NULL, "qe");
 	if (qe) {
 		unsigned int size;
-		const u32 *prop = get_property(qe, "brg-frequency", &size);
+		const u32 *prop = of_get_property(qe, "brg-frequency", &size);
 		brg_clk = *prop;
 		of_node_put(qe);
 	};
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index 0afe6bf..e32b45b 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -53,7 +53,7 @@ int par_io_init(struct device_node *np)
 		return ret;
 	par_io = ioremap(res.start, res.end - res.start + 1);
 
-	num_ports = get_property(np, "num-ports", NULL);
+	num_ports = of_get_property(np, "num-ports", NULL);
 	if (num_ports)
 		num_par_io_ports = *num_ports;
 
@@ -161,7 +161,7 @@ int par_io_of_config(struct device_node 
 		return -1;
 	}
 
-	ph = get_property(np, "pio-handle", NULL);
+	ph = of_get_property(np, "pio-handle", NULL);
 	if (ph == 0) {
 		printk(KERN_ERR "pio-handle not available \n");
 		return -1;
@@ -169,7 +169,7 @@ int par_io_of_config(struct device_node 
 
 	pio = of_find_node_by_phandle(*ph);
 
-	pio_map = get_property(pio, "pio-map", &pio_map_len);
+	pio_map = of_get_property(pio, "pio-map", &pio_map_len);
 	if (pio_map == NULL) {
 		printk(KERN_ERR "pio-map is not set! \n");
 		return -1;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index a457ac1..66137bf 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -210,6 +210,9 @@ int ucc_fast_init(struct ucc_fast_info *
 	uf_regs = uccf->uf_regs;
 	uccf->p_ucce = (u32 *) & (uf_regs->ucce);
 	uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+	uccf->p_utodr = (u16 *) & (uf_regs->utodr);
+#endif
 #ifdef STATISTICS
 	uccf->tx_frames = 0;
 	uccf->rx_frames = 0;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
index 817df73..b930d68 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -187,7 +187,7 @@ #endif				/* STATISTICS */
 	uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
 
 	/* Init Guemr register */
-	if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) {
+	if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) {
 		printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__);
 		ucc_slow_free(uccs);
 		return ret;
@@ -195,7 +195,7 @@ #endif				/* STATISTICS */
 
 	/* Set UCC to slow type */
 	if ((ret = ucc_set_type(us_info->ucc_num,
-				(struct ucc_common *) (us_info->regs),
+				(struct ucc_common *) us_regs,
 				UCC_SPEED_TYPE_SLOW))) {
 		printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__);
 		ucc_slow_free(uccs);
diff --git a/arch/powerpc/sysdev/rom.c b/arch/powerpc/sysdev/rom.c
deleted file mode 100644
index c855a3b..0000000
--- a/arch/powerpc/sysdev/rom.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * ROM device registration
- *
- * (C) 2006 MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/kernel.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
-
-static int __init powerpc_flash_init(void)
-{
-	struct device_node *node = NULL;
-
-	/*
-	 * Register all the devices which type is "rom"
-	 */
-	while ((node = of_find_node_by_type(node, "rom")) != NULL) {
-		if (node->name == NULL) {
-			printk(KERN_WARNING "powerpc_flash_init: found 'rom' "
-				"device, but with no name, skipping...\n");
-			continue;
-		}
-		of_platform_device_create(node, node->name, NULL);
-	}
-	return 0;
-}
-
-arch_initcall(powerpc_flash_init);
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644
index 0000000..4a01748
--- /dev/null
+++ b/arch/powerpc/sysdev/timer.c
@@ -0,0 +1,71 @@
+/*
+ * Common code to keep time when machine suspends.
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/time.h>
+#include <linux/sysdev.h>
+#include <asm/rtc.h>
+
+static unsigned long suspend_rtc_time;
+
+/*
+ * Reset the time after a sleep.
+ */
+static int timer_resume(struct sys_device *dev)
+{
+	struct timeval tv;
+	struct timespec ts;
+	struct rtc_time cur_rtc_tm;
+	unsigned long cur_rtc_time, diff;
+
+	/* get current RTC time and convert to seconds */
+	get_rtc_time(&cur_rtc_tm);
+	rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
+
+	diff = cur_rtc_time - suspend_rtc_time;
+
+	/* adjust time of day by seconds that elapsed while
+	 * we were suspended */
+	do_gettimeofday(&tv);
+	ts.tv_sec = tv.tv_sec + diff;
+	ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+	do_settimeofday(&ts);
+
+	return 0;
+}
+
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct rtc_time suspend_rtc_tm;
+	WARN_ON(!ppc_md.get_rtc_time);
+
+	get_rtc_time(&suspend_rtc_tm);
+	rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
+
+	return 0;
+}
+
+static struct sysdev_class timer_sysclass = {
+	.resume = timer_resume,
+	.suspend = timer_suspend,
+	set_kset_name("timer"),
+};
+
+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);
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 97f37ef..7d3b09b 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -48,7 +48,7 @@ phys_addr_t get_csrbase(void)
 	tsi = of_find_node_by_type(NULL, "tsi-bridge");
 	if (tsi) {
 		unsigned int size;
-		const void *prop = get_property(tsi, "reg", &size);
+		const void *prop = of_get_property(tsi, "reg", &size);
 		tsi108_csr_base = of_translate_address(tsi, prop);
 		of_node_put(tsi);
 	};
@@ -77,10 +77,10 @@ static int __init tsi108_eth_of_init(voi
 		struct resource r[2];
 		struct device_node *phy;
 		hw_info tsi_eth_data;
-		unsigned int *id;
-		unsigned int *phy_id;
+		const unsigned int *id;
+		const unsigned int *phy_id;
 		const void *mac_addr;
-		phandle *ph;
+		const phandle *ph;
 
 		memset(r, 0, sizeof(r));
 		memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
@@ -107,10 +107,11 @@ static int __init tsi108_eth_of_init(voi
 			goto err;
 		}
 
-		mac_addr = get_property(np, "address", NULL);
-		memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+		mac_addr = of_get_mac_address(np);
+		if (mac_addr)
+			memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
 
-		ph = (phandle *) get_property(np, "phy-handle", NULL);
+		ph = of_get_property(np, "phy-handle", NULL);
 		phy = of_find_node_by_phandle(*ph);
 
 		if (phy == NULL) {
@@ -118,8 +119,8 @@ static int __init tsi108_eth_of_init(voi
 			goto unreg;
 		}
 
-		id = (u32 *) get_property(phy, "reg", NULL);
-		phy_id = (u32 *) get_property(phy, "phy-id", NULL);
+		id = of_get_property(phy, "reg", NULL);
+		phy_id = of_get_property(phy, "phy-id", NULL);
 		ret = of_address_to_resource(phy, 0, &res);
 		if (ret) {
 			of_node_put(phy);
@@ -129,6 +130,8 @@ static int __init tsi108_eth_of_init(voi
 		tsi_eth_data.phyregs = res.start;
 		tsi_eth_data.phy = *phy_id;
 		tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0);
+		if (of_device_is_compatible(phy, "bcm54xx"))
+			tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
 		of_node_put(phy);
 		ret =
 		    platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index ae249c6..2153163 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -35,6 +35,7 @@ #include <asm/uaccess.h>
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
 #include <asm/tsi108.h>
+#include <asm/tsi108_pci.h>
 #include <asm/tsi108_irq.h>
 #include <asm/prom.h>
 
@@ -49,6 +50,7 @@ #define tsi_mk_config_addr(bus, devfunc,
 	((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base)
 
 u32 tsi108_pci_cfg_base;
+static u32 tsi108_pci_cfg_phys;
 u32 tsi108_csr_vir_base;
 static struct device_node *pci_irq_node;
 static struct irq_host *pci_irq_host;
@@ -185,7 +187,7 @@ #endif
 
 void tsi108_clear_pci_cfg_error(void)
 {
-	tsi108_clear_pci_error(TSI108_PCI_CFG_BASE_PHYS);
+	tsi108_clear_pci_error(tsi108_pci_cfg_phys);
 }
 
 static struct pci_ops tsi108_direct_pci_ops = {
@@ -193,17 +195,17 @@ static struct pci_ops tsi108_direct_pci_
 	tsi108_direct_write_config
 };
 
-int __init tsi108_setup_pci(struct device_node *dev)
+int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
 {
 	int len;
 	struct pci_controller *hose;
 	struct resource rsrc;
 	const int *bus_range;
-	int primary = 0, has_address = 0;
+	int has_address = 0;
 
 	/* PCI Config mapping */
-	tsi108_pci_cfg_base = (u32)ioremap(TSI108_PCI_CFG_BASE_PHYS,
-			TSI108_PCI_CFG_SIZE);
+	tsi108_pci_cfg_base = (u32)ioremap(cfg_phys, TSI108_PCI_CFG_SIZE);
+	tsi108_pci_cfg_phys = cfg_phys;
 	DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __FUNCTION__,
 	    tsi108_pci_cfg_base);
 
@@ -211,7 +213,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 = get_property(dev, "bus-range", &len);
+	bus_range = of_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/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
new file mode 100644
index 0000000..8905989
--- /dev/null
+++ b/arch/powerpc/sysdev/uic.c
@@ -0,0 +1,342 @@
+/*
+ * arch/powerpc/sysdev/uic.c
+ *
+ * IBM PowerPC 4xx Universal Interrupt Controller
+ *
+ * Copyright 2007 David Gibson <dwg@au1.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.
+ */
+#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 <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NR_UIC_INTS	32
+
+#define UIC_SR		0x0
+#define UIC_ER		0x2
+#define UIC_CR		0x3
+#define UIC_PR		0x4
+#define UIC_TR		0x5
+#define UIC_MSR		0x6
+#define UIC_VR		0x7
+#define UIC_VCR		0x8
+
+#define uic_irq_to_hw(virq)	(irq_map[virq].hwirq)
+
+struct uic *primary_uic;
+
+struct uic {
+	int index;
+	int dcrbase;
+
+	spinlock_t lock;
+
+	/* The remapper for this UIC */
+	struct irq_host	*irqhost;
+
+	/* For secondary UICs, the cascade interrupt's irqaction */
+	struct irqaction cascade;
+
+	/* The device node of the interrupt controller */
+	struct device_node *of_node;
+};
+
+static void uic_unmask_irq(unsigned int virq)
+{
+	struct uic *uic = get_irq_chip_data(virq);
+	unsigned int src = uic_irq_to_hw(virq);
+	unsigned long flags;
+	u32 er;
+
+	spin_lock_irqsave(&uic->lock, flags);
+	er = mfdcr(uic->dcrbase + UIC_ER);
+	er |= 1 << (31 - src);
+	mtdcr(uic->dcrbase + UIC_ER, er);
+	spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_mask_irq(unsigned int virq)
+{
+	struct uic *uic = get_irq_chip_data(virq);
+	unsigned int src = uic_irq_to_hw(virq);
+	unsigned long flags;
+	u32 er;
+
+	spin_lock_irqsave(&uic->lock, flags);
+	er = mfdcr(uic->dcrbase + UIC_ER);
+	er &= ~(1 << (31 - src));
+	mtdcr(uic->dcrbase + UIC_ER, er);
+	spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_ack_irq(unsigned int virq)
+{
+	struct uic *uic = get_irq_chip_data(virq);
+	unsigned int src = uic_irq_to_hw(virq);
+	unsigned long flags;
+
+	spin_lock_irqsave(&uic->lock, flags);
+	mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
+	spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+	struct uic *uic = get_irq_chip_data(virq);
+	unsigned int src = uic_irq_to_hw(virq);
+	struct irq_desc *desc = get_irq_desc(virq);
+	unsigned long flags;
+	int trigger, polarity;
+	u32 tr, pr, mask;
+
+	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_NONE:
+		uic_mask_irq(virq);
+		return 0;
+
+	case IRQ_TYPE_EDGE_RISING:
+		trigger = 1; polarity = 1;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		trigger = 1; polarity = 0;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		trigger = 0; polarity = 1;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		trigger = 0; polarity = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = ~(1 << (31 - src));
+
+	spin_lock_irqsave(&uic->lock, flags);
+	tr = mfdcr(uic->dcrbase + UIC_TR);
+	pr = mfdcr(uic->dcrbase + UIC_PR);
+	tr = (tr & mask) | (trigger << (31-src));
+	pr = (pr & mask) | (polarity << (31-src));
+
+	mtdcr(uic->dcrbase + UIC_PR, pr);
+	mtdcr(uic->dcrbase + UIC_TR, tr);
+
+	desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+	desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+	if (trigger)
+		desc->status |= IRQ_LEVEL;
+
+	spin_unlock_irqrestore(&uic->lock, flags);
+
+	return 0;
+}
+
+static struct irq_chip uic_irq_chip = {
+	.typename	= " UIC  ",
+	.unmask		= uic_unmask_irq,
+	.mask		= uic_mask_irq,
+/* 	.mask_ack	= uic_mask_irq_and_ack, */
+	.ack		= uic_ack_irq,
+	.set_type	= uic_set_irq_type,
+};
+
+static int uic_host_match(struct irq_host *h, struct device_node *node)
+{
+	struct uic *uic = h->host_data;
+	return uic->of_node == node;
+}
+
+static int uic_host_map(struct irq_host *h, unsigned int virq,
+			irq_hw_number_t hw)
+{
+	struct uic *uic = h->host_data;
+
+	set_irq_chip_data(virq, uic);
+	/* Despite the name, handle_level_irq() works for both level
+	 * and edge irqs on UIC.  FIXME: check this is correct */
+	set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
+
+	/* Set default irq type */
+	set_irq_type(virq, IRQ_TYPE_NONE);
+
+	return 0;
+}
+
+static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
+			  u32 *intspec, unsigned int intsize,
+			  irq_hw_number_t *out_hwirq, unsigned int *out_type)
+
+{
+	/* UIC intspecs must have 2 cells */
+	BUG_ON(intsize != 2);
+	*out_hwirq = intspec[0];
+	*out_type = intspec[1];
+	return 0;
+}
+
+static struct irq_host_ops uic_host_ops = {
+	.match	= uic_host_match,
+	.map	= uic_host_map,
+	.xlate	= uic_host_xlate,
+};
+
+irqreturn_t uic_cascade(int virq, void *data)
+{
+	struct uic *uic = data;
+	u32 msr;
+	int src;
+	int subvirq;
+
+	msr = mfdcr(uic->dcrbase + UIC_MSR);
+	src = 32 - ffs(msr);
+
+	subvirq = irq_linear_revmap(uic->irqhost, src);
+	generic_handle_irq(subvirq);
+
+	return IRQ_HANDLED;
+}
+
+static struct uic * __init uic_init_one(struct device_node *node)
+{
+	struct uic *uic;
+	const u32 *indexp, *dcrreg;
+	int len;
+
+	BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
+
+	uic = alloc_bootmem(sizeof(*uic));
+	if (! uic)
+		return NULL; /* FIXME: panic? */
+
+	memset(uic, 0, sizeof(*uic));
+	spin_lock_init(&uic->lock);
+	uic->of_node = of_node_get(node);
+	indexp = of_get_property(node, "cell-index", &len);
+	if (!indexp || (len != sizeof(u32))) {
+		printk(KERN_ERR "uic: Device node %s has missing or invalid "
+		       "cell-index property\n", node->full_name);
+		return NULL;
+	}
+	uic->index = *indexp;
+
+	dcrreg = of_get_property(node, "dcr-reg", &len);
+	if (!dcrreg || (len != 2*sizeof(u32))) {
+		printk(KERN_ERR "uic: Device node %s has missing or invalid "
+		       "dcr-reg property\n", node->full_name);
+		return NULL;
+	}
+	uic->dcrbase = *dcrreg;
+
+	uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS,
+				      &uic_host_ops, -1);
+	if (! uic->irqhost) {
+		of_node_put(node);
+		return NULL; /* FIXME: panic? */
+	}
+
+	uic->irqhost->host_data = uic;
+
+	/* Start with all interrupts disabled, level and non-critical */
+	mtdcr(uic->dcrbase + UIC_ER, 0);
+	mtdcr(uic->dcrbase + UIC_CR, 0);
+	mtdcr(uic->dcrbase + UIC_TR, 0);
+	/* Clear any pending interrupts, in case the firmware left some */
+	mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
+
+	printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
+		NR_UIC_INTS, uic->dcrbase);
+
+	return uic;
+}
+
+void __init uic_init_tree(void)
+{
+	struct device_node *np;
+	struct uic *uic;
+	const u32 *interrupts;
+
+	/* First locate and initialize the top-level UIC */
+
+	np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+	while (np) {
+		interrupts = of_get_property(np, "interrupts", NULL);
+		if (! interrupts)
+			break;
+
+		np = of_find_compatible_node(np, NULL, "ibm,uic");
+	}
+
+	BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
+		      * top-level interrupt controller */
+	primary_uic = uic_init_one(np);
+	if (! primary_uic)
+		panic("Unable to initialize primary UIC %s\n", np->full_name);
+
+	irq_set_default_host(primary_uic->irqhost);
+	of_node_put(np);
+
+	/* The scan again for cascaded UICs */
+	np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+	while (np) {
+		interrupts = of_get_property(np, "interrupts", NULL);
+		if (interrupts) {
+			/* Secondary UIC */
+			int cascade_virq;
+			int ret;
+
+			uic = uic_init_one(np);
+			if (! uic)
+				panic("Unable to initialize a secondary UIC %s\n",
+				      np->full_name);
+
+			cascade_virq = irq_of_parse_and_map(np, 0);
+
+			uic->cascade.handler = uic_cascade;
+			uic->cascade.name = "UIC cascade";
+			uic->cascade.dev_id = uic;
+
+			ret = setup_irq(cascade_virq, &uic->cascade);
+			if (ret)
+				printk(KERN_ERR "Failed to setup_irq(%d) for "
+				       "UIC%d cascade\n", cascade_virq,
+				       uic->index);
+
+			/* FIXME: setup critical cascade?? */
+		}
+
+		np = of_find_compatible_node(np, NULL, "ibm,uic");
+	}
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int uic_get_irq(void)
+{
+	u32 msr;
+	int src;
+
+	BUG_ON(! primary_uic);
+
+	msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
+	src = 32 - ffs(msr);
+
+	return irq_linear_revmap(primary_uic->irqhost, src);
+}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index bf299b6..28fdf4f 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -330,18 +330,17 @@ #endif
 static int xmon_core(struct pt_regs *regs, int fromipi)
 {
 	int cmd = 0;
-	unsigned long msr;
 	struct bpt *bp;
 	long recurse_jmp[JMP_BUF_LEN];
 	unsigned long offset;
+	unsigned long flags;
 #ifdef CONFIG_SMP
 	int cpu;
 	int secondary;
 	unsigned long timeout;
 #endif
 
-	msr = mfmsr();
-	mtmsr(msr & ~MSR_EE);	/* disable interrupts */
+	local_irq_save(flags);
 
 	bp = in_breakpoint_table(regs->nip, &offset);
 	if (bp != NULL) {
@@ -516,7 +515,7 @@ #endif
 
 	insert_cpu_bpts();
 
-	mtmsr(msr);		/* restore interrupt enable */
+	local_irq_restore(flags);
 
 	return cmd != 'X' && cmd != EOF;
 }
@@ -1218,7 +1217,6 @@ static void get_function_bounds(unsigned
 {
 	unsigned long size, offset;
 	const char *name;
-	char *modname;
 
 	*startp = *endp = 0;
 	if (pc == 0)
@@ -1226,7 +1224,7 @@ static void get_function_bounds(unsigned
 	if (setjmp(bus_error_jmp) == 0) {
 		catch_memory_errors = 1;
 		sync();
-		name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
+		name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
 		if (name != NULL) {
 			*startp = pc - offset;
 			*endp = pc - offset + size;
@@ -1360,8 +1358,12 @@ static void print_bug_trap(struct pt_reg
 	if (is_warning_bug(bug))
 		return;
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
 	printf("kernel BUG at %s:%u!\n",
 	       bug->file, bug->line);
+#else
+	printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
+#endif
 }
 
 void excprint(struct pt_regs *fp)
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index a6056c2..4c0a7d7 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -32,7 +32,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -477,7 +476,6 @@ #endif
 			cep->stats.rx_dropped++;
 		}
 		else {
-			skb->dev = dev;
 			skb_put(skb,pkt_len-4);	/* Make room */
 			eth_copy_and_sum(skb,
 				(unsigned char *)__va(bdp->cbd_bufaddr),
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index 06b84c3..cab395d 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -29,7 +29,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -734,7 +733,6 @@ #endif
 			cep->stats.rx_dropped++;
 		}
 		else {
-			skb->dev = dev;
 			skb_put(skb,pkt_len);	/* Make room */
 			eth_copy_and_sum(skb,
 				(unsigned char *)__va(bdp->cbd_bufaddr),
diff --git a/arch/ppc/8xx_io/Kconfig b/arch/ppc/8xx_io/Kconfig
index 57dacf9..c623e44 100644
--- a/arch/ppc/8xx_io/Kconfig
+++ b/arch/ppc/8xx_io/Kconfig
@@ -74,10 +74,6 @@ config ENET_BIG_BUFFERS
 	  Allocate large buffers for MPC8xx Ethernet. Increases throughput
 	  and decreases the likelihood of dropped packets, but costs memory.
 
-config HTDMSOUND
-	bool "Embedded Planet HIOX Audio"
-	depends on SOUND=y
-
 # This doesn't really belong here, but it is convenient to ask
 # 8xx specific questions.
 comment "Generic MPC8xx Options"
diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
index d876018..1051a06 100644
--- a/arch/ppc/8xx_io/Makefile
+++ b/arch/ppc/8xx_io/Makefile
@@ -7,4 +7,3 @@ obj-y			:= commproc.o
 obj-$(CONFIG_FEC_ENET)	+= fec.o
 obj-$(CONFIG_SCC_ENET)	+= enet.o
 obj-$(CONFIG_UCODE_PATCH) += micropatch.o
-obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o
diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h
deleted file mode 100644
index e5f9430..0000000
--- a/arch/ppc/8xx_io/cs4218.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _cs4218_h_
-/*
- *  Hacked version of linux/drivers/sound/dmasound/dmasound.h
- *
- *
- *  Minor numbers for the sound driver.
- *
- *  Unfortunately Creative called the codec chip of SB as a DSP. For this
- *  reason the /dev/dsp is reserved for digitized audio use. There is a
- *  device for true DSP processors but it will be called something else.
- *  In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-#define _cs4218_h_
-
-#include <linux/types.h>
-
-#define SND_NDEVS	256	/* Number of supported devices */
-#define SND_DEV_CTL	0	/* Control port /dev/mixer */
-#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
-				   synthesizer and MIDI output) */
-#define SND_DEV_MIDIN	2	/* Raw midi access */
-#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS	6	/* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS	SND_DEV_SNDPROC
-
-/* switch on various prinks */
-#define DEBUG_DMASOUND 1
-
-#define MAX_AUDIO_DEV	5
-#define MAX_MIXER_DEV	4
-#define MAX_SYNTH_DEV	3
-#define MAX_MIDI_DEV	6
-#define MAX_TIMER_DEV	3
-
-#define MAX_CATCH_RADIUS	10
-
-#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
-	do { int error = get_user(ret, (int *)(arg)); \
-		if (error) return error; \
-	} while (0)
-#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
-
-static inline int ioctl_return(int *addr, int value)
-{
-	return value < 0 ? value : put_user(value, addr);
-}
-
-#define HAS_RECORD
-
-    /*
-     *  Initialization
-     */
-
-/* description of the set-up applies to either hard or soft settings */
-
-typedef struct {
-    int format;		/* AFMT_* */
-    int stereo;		/* 0 = mono, 1 = stereo */
-    int size;		/* 8/16 bit*/
-    int speed;		/* speed */
-} SETTINGS;
-
-    /*
-     *  Machine definitions
-     */
-
-typedef struct {
-    const char *name;
-    const char *name2;
-    void (*open)(void);
-    void (*release)(void);
-    void *(*dma_alloc)(unsigned int, gfp_t);
-    void (*dma_free)(void *, unsigned int);
-    int (*irqinit)(void);
-#ifdef MODULE
-    void (*irqcleanup)(void);
-#endif
-    void (*init)(void);
-    void (*silence)(void);
-    int (*setFormat)(int);
-    int (*setVolume)(int);
-    int (*setBass)(int);
-    int (*setTreble)(int);
-    int (*setGain)(int);
-    void (*play)(void);
-    void (*record)(void);		/* optional */
-    void (*mixer_init)(void);		/* optional */
-    int (*mixer_ioctl)(u_int, u_long);	/* optional */
-    int (*write_sq_setup)(void);	/* optional */
-    int (*read_sq_setup)(void);		/* optional */
-    int (*sq_open)(mode_t);		/* optional */
-    int (*state_info)(char *, size_t);	/* optional */
-    void (*abort_read)(void);		/* optional */
-    int min_dsp_speed;
-    int max_dsp_speed;
-    int version ;
-    int hardware_afmts ;		/* OSS says we only return h'ware info */
-					/* when queried via SNDCTL_DSP_GETFMTS */
-    int capabilities ;		/* low-level reply to SNDCTL_DSP_GETCAPS */
-    SETTINGS default_hard ;	/* open() or init() should set something valid */
-    SETTINGS default_soft ;	/* you can make it look like old OSS, if you want to */
-} MACHINE;
-
-    /*
-     *  Low level stuff
-     */
-
-typedef struct {
-    ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-    ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-
-    /*
-     * Sound queue stuff, the heart of the driver
-     */
-
-struct sound_queue {
-    /* buffers allocated for this queue */
-    int numBufs;		/* real limits on what the user can have */
-    int bufSize;		/* in bytes */
-    char **buffers;
-
-    /* current parameters */
-    int locked ;		/* params cannot be modified when != 0 */
-    int user_frags ;		/* user requests this many */
-    int user_frag_size ;	/* of this size */
-    int max_count;		/* actual # fragments <= numBufs */
-    int block_size;		/* internal block size in bytes */
-    int max_active;		/* in-use fragments <= max_count */
-
-    /* it shouldn't be necessary to declare any of these volatile */
-    int front, rear, count;
-    int rear_size;
-    /*
-     *	The use of the playing field depends on the hardware
-     *
-     *	Atari, PMac: The number of frames that are loaded/playing
-     *
-     *	Amiga: Bit 0 is set: a frame is loaded
-     *	       Bit 1 is set: a frame is playing
-     */
-    int active;
-    wait_queue_head_t action_queue, open_queue, sync_queue;
-    int open_mode;
-    int busy, syncing, xruns, died;
-};
-
-#define SLEEP(queue)		interruptible_sleep_on_timeout(&queue, HZ)
-#define WAKE_UP(queue)		(wake_up_interruptible(&queue))
-
-#endif /* _cs4218_h_ */
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
deleted file mode 100644
index a956f28..0000000
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ /dev/null
@@ -1,2833 +0,0 @@
-
-/* This is a modified version of linux/drivers/sound/dmasound.c to
- * support the CS4218 codec on the 8xx TDM port.  Thanks to everyone
- * that contributed to the dmasound software (which includes me :-).
- *
- * The CS4218 is configured in Mode 4, sub-mode 0.  This provides
- * left/right data only on the TDM port, as a 32-bit word, per frame
- * pulse.  The control of the CS4218 is provided by some other means,
- * like the SPI port.
- * Dan Malek (dmalek@jlc.net)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/* Should probably do something different with this path name.....
- * Actually, I should just stop using it...
- */
-#include "cs4218.h"
-#include <linux/soundcard.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#include <asm/commproc.h>
-
-#define DMASND_CS4218		5
-
-#define MAX_CATCH_RADIUS	10
-#define MIN_BUFFERS		4
-#define MIN_BUFSIZE 		4
-#define MAX_BUFSIZE		128
-
-#define HAS_8BIT_TABLES
-
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-static char **sound_buffers = NULL;
-static char **sound_read_buffers = NULL;
-
-static DEFINE_SPINLOCK(cs4218_lock);
-
-/* Local copies of things we put in the control register.  Output
- * volume, like most codecs is really attenuation.
- */
-static int cs4218_rate_index;
-
-/*
- * Stuff for outputting a beep.  The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
-	0,	40,	79,	117,	153,	187,	218,	245,
-	269,	288,	304,	316,	323,	327,	327,	324,
-	318,	310,	299,	288,	275,	262,	249,	236,
-	224,	213,	204,	196,	190,	186,	183,	182,
-	182,	183,	186,	189,	192,	196,	200,	203,
-	206,	208,	209,	209,	209,	207,	204,	201,
-	197,	193,	188,	183,	179,	174,	170,	166,
-	163,	161,	160,	159,	159,	160,	161,	162,
-	164,	166,	168,	169,	171,	171,	171,	170,
-	169,	167,	163,	159,	155,	150,	144,	139,
-	133,	128,	122,	117,	113,	110,	107,	105,
-	103,	103,	103,	103,	104,	104,	105,	105,
-	105,	103,	101,	97,	92,	86,	78,	68,
-	58,	45,	32,	18,	3,	-11,	-26,	-41,
-	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
-	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
-	0,	16,	33,	48,	62,	75,	85,	93,
-	99,	102,	102,	100,	95,	88,	79,	68,
-	55,	41,	26,	11,	-3,	-18,	-32,	-45,
-	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
-	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
-	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
-	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
-	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
-	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
-	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
-	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
-	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
-	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
-	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
-	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
-	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
-};
-
-#define BEEP_SPEED	5	/* 22050 Hz sample rate */
-#define BEEP_BUFLEN	512
-#define BEEP_VOLUME	15	/* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int beep_state = 0;
-static short *beep_buf;
-static void (*orig_mksound)(unsigned int, unsigned int);
-
-/* This is found someplace else......I guess in the keyboard driver
- * we don't include.
- */
-static void (*kd_mksound)(unsigned int, unsigned int);
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-static int numReadBufs = 4, readbufSize = 32;
-
-
-/* TDM/Serial transmit and receive buffer descriptors.
-*/
-static volatile cbd_t	*rx_base, *rx_cur, *tx_base, *tx_cur;
-
-module_param(catchRadius, int, 0);
-module_param(numBufs, int, 0);
-module_param(bufSize, int, 0);
-module_param(numreadBufs, int, 0);
-module_param(readbufSize, int, 0);
-
-#define arraysize(x)	(sizeof(x)/sizeof(*(x)))
-#define le2be16(x)	(((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x)	(((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
-	do { int error = get_user(ret, (int *)(arg)); \
-		if (error) return error; \
-	} while (0)
-#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
-
-/* CS4218 serial port control in mode 4.
-*/
-#define CS_INTMASK	((uint)0x40000000)
-#define CS_DO1		((uint)0x20000000)
-#define CS_LATTEN	((uint)0x1f000000)
-#define CS_RATTEN	((uint)0x00f80000)
-#define CS_MUTE		((uint)0x00040000)
-#define CS_ISL		((uint)0x00020000)
-#define CS_ISR		((uint)0x00010000)
-#define CS_LGAIN	((uint)0x0000f000)
-#define CS_RGAIN	((uint)0x00000f00)
-
-#define CS_LATTEN_SET(X)	(((X) & 0x1f) << 24)
-#define CS_RATTEN_SET(X)	(((X) & 0x1f) << 19)
-#define CS_LGAIN_SET(X)		(((X) & 0x0f) << 12)
-#define CS_RGAIN_SET(X)		(((X) & 0x0f) << 8)
-
-#define CS_LATTEN_GET(X)	(((X) >> 24) & 0x1f)
-#define CS_RATTEN_GET(X)	(((X) >> 19) & 0x1f)
-#define CS_LGAIN_GET(X)		(((X) >> 12) & 0x0f)
-#define CS_RGAIN_GET(X)		(((X) >> 8) & 0x0f)
-
-/* The control register is effectively write only.  We have to keep a copy
- * of what we write.
- */
-static	uint	cs4218_control;
-
-/* A place to store expanding information.
-*/
-static int	expand_bal;
-static int	expand_data;
-
-/* Since I can't make the microcode patch work for the SPI, I just
- * clock the bits using software.
- */
-static	void	sw_spi_init(void);
-static	void	sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt);
-static	uint	cs4218_ctl_write(uint ctlreg);
-
-/*** Some low level helpers **************************************************/
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
-	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
-	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
-	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
-	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
-	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
-	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
-	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
-	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
-	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
-	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
-	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
-	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
-	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
-	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
-	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
-	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
-	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
-	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
-	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
-	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
-	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
-	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
-	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
-	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
-	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
-	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
-	876,	844,	812,	780,	748,	716,	684,	652,
-	620,	588,	556,	524,	492,	460,	428,	396,
-	372,	356,	340,	324,	308,	292,	276,	260,
-	244,	228,	212,	196,	180,	164,	148,	132,
-	120,	112,	104,	96,	88,	80,	72,	64,
-	56,	48,	40,	32,	24,	16,	8,	0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
-	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
-	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
-	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
-	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
-	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
-	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
-	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
-	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
-	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
-	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
-	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
-	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
-	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
-	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
-	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
-	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
-	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
-	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
-	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
-	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
-	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
-	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
-	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
-	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
-	344,	328,	376,	360,	280,	264,	312,	296,
-	472,	456,	504,	488,	408,	392,	440,	424,
-	88,	72,	120,	104,	24,	8,	56,	40,
-	216,	200,	248,	232,	152,	136,	184,	168,
-	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
-	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
-	688,	656,	752,	720,	560,	528,	624,	592,
-	944,	912,	1008,	976,	816,	784,	880,	848,
-};
-
-
-/*** Translations ************************************************************/
-
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-
-
-/*** Low level stuff *********************************************************/
-
-struct cs_sound_settings {
-	MACHINE mach;		/* machine dependent things */
-	SETTINGS hard;		/* hardware settings */
-	SETTINGS soft;		/* software settings */
-	SETTINGS dsp;		/* /dev/dsp default settings */
-	TRANS *trans_write;	/* supported translations for playback */
-	TRANS *trans_read;	/* supported translations for record */
-	int volume_left;	/* volume (range is machine dependent) */
-	int volume_right;
-	int bass;		/* tone (range is machine dependent) */
-	int treble;
-	int gain;
-	int minDev;		/* minor device number currently open */
-};
-
-static struct cs_sound_settings sound;
-
-static void *CS_Alloc(unsigned int size, gfp_t flags);
-static void CS_Free(void *ptr, unsigned int size);
-static int CS_IrqInit(void);
-#ifdef MODULE
-static void CS_IrqCleanup(void);
-#endif /* MODULE */
-static void CS_Silence(void);
-static void CS_Init(void);
-static void CS_Play(void);
-static void CS_Record(void);
-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);
-static int cs_get_volume(uint reg);
-static int cs_volume_setter(int volume, int mute);
-static int cs_get_gain(uint reg);
-static int cs_set_gain(int gain);
-static void cs_mksound(unsigned int hz, unsigned int ticks);
-static void cs_nosound(unsigned long xx);
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft);
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft);
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
-    int busy;
-    int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-static struct sound_queue sq;
-static struct sound_queue read_sq;
-
-#define sq_block_address(i)	(sq.buffers[i])
-#define SIGNAL_RECEIVED	(signal_pending(current))
-#define NON_BLOCKING(open_mode)	(open_mode & O_NONBLOCK)
-#define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT	0xffffffff
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
-	int busy;
-	char buf[512];
-	int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-
-/*** Config & Setup **********************************************************/
-
-void dmasound_setup(char *str, int *ints);
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = table[data];
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = table[data];
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = data << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = data << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-		if (get_user(data, userPtr++))
-			return -EFAULT;
-		val = (data ^ 0x80) << 8;
-		*p++ = val;
-		if (stereo) {
-			if (get_user(data, userPtr++))
-				return -EFAULT;
-			val = (data ^ 0x80) << 8;
-		}
-		*p++ = val;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-/* This is the default format of the codec.  Signed, 16-bit stereo
- * generated by an application shouldn't have to be copied at all.
- * We should just get the phsical address of the buffers and update
- * the TDM BDs directly.
- */
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			if (get_user(data, up++))
-				return -EFAULT;
-			*fp++ = data;
-			*fp++ = data;
-			count--;
-		}
-	} else {
-		if (copy_from_user(fp, userPtr, count * 4))
-			return -EFAULT;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		int data;
-		if (get_user(data, up++))
-			return -EFAULT;
-		data ^= mask;
-		*fp++ = data;
-		if (stereo) {
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-		}
-		*fp++ = data;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned short *table = (unsigned short *)
-		(sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
-	unsigned int data = expand_data;
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	int bal = expand_bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int utotal, ftotal;
-	int stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = table[c];
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + table[c];
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	int bal = expand_bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = c << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + (c << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	int bal = expand_bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		u_char c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(c, userPtr++))
-				return -EFAULT;
-			data = (c ^ 0x80) << 8;
-			if (stereo) {
-				if (get_user(c, userPtr++))
-					return -EFAULT;
-				data = (data << 16) + ((c ^ 0x80) << 8);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = expand_bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + c;
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft)
-{
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	unsigned int *p = (unsigned int *) &frame[*frameUsed];
-	unsigned int data = expand_data;
-	unsigned short *up = (unsigned short *) userPtr;
-	int bal = expand_bal;
-	int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	int stereo = sound.soft.stereo;
-	int utotal, ftotal;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	ftotal = frameLeft;
-	utotal = userCount;
-	while (frameLeft) {
-		unsigned short c;
-		if (bal < 0) {
-			if (userCount == 0)
-				break;
-			if (get_user(data, up++))
-				return -EFAULT;
-			data ^= mask;
-			if (stereo) {
-				if (get_user(c, up++))
-					return -EFAULT;
-				data = (data << 16) + (c ^ mask);
-			} else
-				data = (data << 16) + data;
-			userCount--;
-			bal += hSpeed;
-		}
-		*p++ = data;
-		frameLeft--;
-		bal -= sSpeed;
-	}
-	expand_bal = bal;
-	expand_data = data;
-	*frameUsed += (ftotal - frameLeft) * 4;
-	utotal -= userCount;
-	return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = val >> 8;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = val >> 8;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft)
-{
-	ssize_t count, used;
-	short *p = (short *) &frame[*frameUsed];
-	int val, stereo = sound.soft.stereo;
-
-	frameLeft >>= 2;
-	if (stereo)
-		userCount >>= 1;
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		u_char data;
-
-		val = *p++;
-		data = (val >> 8) ^ 0x80;
-		if (put_user(data, (u_char *)userPtr++))
-			return -EFAULT;
-		if (stereo) {
-			val = *p;
-			data = (val >> 8) ^ 0x80;
-			if (put_user(data, (u_char *)userPtr++))
-				return -EFAULT;
-		}
-		p++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	if (!stereo) {
-		short *up = (short *) userPtr;
-		while (count > 0) {
-			short data;
-			data = *fp;
-			if (put_user(data, up++))
-				return -EFAULT;
-			fp+=2;
-			count--;
-		}
-	} else {
-		if (copy_to_user((u_char *)userPtr, fp, count * 4))
-			return -EFAULT;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft)
-{
-	ssize_t count, used;
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
-	int stereo = sound.soft.stereo;
-	short *fp = (short *) &frame[*frameUsed];
-	short *up = (short *) userPtr;
-
-	frameLeft >>= 2;
-	userCount >>= (stereo? 2: 1);
-	used = count = min(userCount, frameLeft);
-	while (count > 0) {
-		int data;
-
-		data = *fp++;
-		data ^= mask;
-		if (put_user(data, up++))
-			return -EFAULT;
-		if (stereo) {
-			data = *fp;
-			data ^= mask;
-			if (put_user(data, up++))
-				return -EFAULT;
-		}
-		fp++;
-		count--;
-	}
-	*frameUsed += used * 4;
-	return stereo? used * 4: used * 2;
-}
-
-static TRANS transCSNormal = {
-	cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8,
-	cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16
-};
-
-static TRANS transCSExpand = {
-	cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8,
-	cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16
-};
-
-static TRANS transCSNormalRead = {
-	NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read,
-	cs4218_ct_s16_read, cs4218_ct_u16_read,
-	cs4218_ct_s16_read, cs4218_ct_u16_read
-};
-
-/*** Low level stuff *********************************************************/
-
-static void *CS_Alloc(unsigned int size, gfp_t flags)
-{
-	int	order;
-
-	size >>= 13;
-	for (order=0; order < 5; order++) {
-		if (size == 0)
-			break;
-		size >>= 1;
-	}
-	return (void *)__get_free_pages(flags, order);
-}
-
-static void CS_Free(void *ptr, unsigned int size)
-{
-	int	order;
-
-	size >>= 13;
-	for (order=0; order < 5; order++) {
-		if (size == 0)
-			break;
-		size >>= 1;
-	}
-	free_pages((ulong)ptr, order);
-}
-
-static int __init CS_IrqInit(void)
-{
-	cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL);
-	return 1;
-}
-
-#ifdef MODULE
-static void CS_IrqCleanup(void)
-{
-	volatile smc_t		*sp;
-	volatile cpm8xx_t	*cp;
-
-	/* First disable transmitter and receiver.
-	*/
-	sp = &cpmp->cp_smc[1];
-	sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-
-	/* And now shut down the SMC.
-	*/
-	cp = cpmp;	/* Get pointer to Communication Processor */
-	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-				CPM_CR_STOP_TX) | CPM_CR_FLG;
-	while (cp->cp_cpcr & CPM_CR_FLG);
-
-	/* Release the interrupt handler.
-	*/
-	cpm_free_handler(CPMVEC_SMC2);
-
-	kfree(beep_buf);
-	kd_mksound = orig_mksound;
-}
-#endif /* MODULE */
-
-static void CS_Silence(void)
-{
-	volatile smc_t		*sp;
-
-	/* Disable transmitter.
-	*/
-	sp = &cpmp->cp_smc[1];
-	sp->smc_smcmr &= ~SMCMR_TEN;
-}
-
-/* Frequencies depend upon external oscillator.  There are two
- * choices, 12.288 and 11.2896 MHz.  The RPCG audio supports both through
- * and external control register selection bit.
- */
-static int cs4218_freqs[] = {
-    /* 12.288  11.2896  */
-	48000, 44100,
-	32000, 29400,
-	24000, 22050,
-	19200, 17640,
-	16000, 14700,
-	12000, 11025,
-	 9600,  8820,
-	 8000,  7350
-};
-
-static void CS_Init(void)
-{
-	int i, tolerance;
-
-	switch (sound.soft.format) {
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		sound.hard.format = AFMT_S16_LE;
-		break;
-	default:
-		sound.hard.format = AFMT_S16_BE;
-		break;
-	}
-	sound.hard.stereo = 1;
-	sound.hard.size = 16;
-
-	/*
-	 * If we have a sample rate which is within catchRadius percent
-	 * of the requested value, we don't have to expand the samples.
-	 * Otherwise choose the next higher rate.
-	 */
-	i = (sizeof(cs4218_freqs) / sizeof(int));
-	do {
-		tolerance = catchRadius * cs4218_freqs[--i] / 100;
-	} while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0);
-	if (sound.soft.speed >= cs4218_freqs[i] - tolerance)
-		sound.trans_write = &transCSNormal;
-	else
-		sound.trans_write = &transCSExpand;
-	sound.trans_read = &transCSNormalRead;
-	sound.hard.speed = cs4218_freqs[i];
-	cs4218_rate_index = i;
-
-	/* The CS4218 has seven selectable clock dividers for the sample
-	 * clock.  The HIOX then provides one of two external rates.
-	 * An even numbered frequency table index uses the high external
-	 * clock rate.
-	 */
-	*(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL);
-	if ((i & 1) == 0)
-		*(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI;
-	i >>= 1;
-	*(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL);
-
-	expand_bal = -sound.soft.speed;
-}
-
-static int CS_SetFormat(int format)
-{
-	int size;
-
-	switch (format) {
-	case AFMT_QUERY:
-		return sound.soft.format;
-	case AFMT_MU_LAW:
-	case AFMT_A_LAW:
-	case AFMT_U8:
-	case AFMT_S8:
-		size = 8;
-		break;
-	case AFMT_S16_BE:
-	case AFMT_U16_BE:
-	case AFMT_S16_LE:
-	case AFMT_U16_LE:
-		size = 16;
-		break;
-	default: /* :-) */
-		printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
-		       format);
-		size = 8;
-		format = AFMT_U8;
-	}
-
-	sound.soft.format = format;
-	sound.soft.size = size;
-	if (sound.minDev == SND_DEV_DSP) {
-		sound.dsp.format = format;
-		sound.dsp.size = size;
-	}
-
-	CS_Init();
-
-	return format;
-}
-
-/* Volume is the amount of attenuation we tell the codec to impose
- * on the outputs.  There are 32 levels, with 0 the "loudest".
- */
-#define CS_VOLUME_TO_MASK(x)	(31 - ((((x) - 1) * 31) / 99))
-#define CS_MASK_TO_VOLUME(y)	(100 - ((y) * 99 / 31))
-
-static int cs_get_volume(uint reg)
-{
-	int volume;
-
-	volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg));
-	volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8;
-	return volume;
-}
-
-static int cs_volume_setter(int volume, int mute)
-{
-	uint tempctl;
-
-	if (mute && volume == 0) {
-		tempctl = cs4218_control | CS_MUTE;
-	} else {
-		tempctl = cs4218_control & ~CS_MUTE;
-		tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN);
-		tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff));
-		tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff));
-		volume = cs_get_volume(tempctl);
-	}
-	if (tempctl != cs4218_control) {
-		cs4218_ctl_write(tempctl);
-	}
-	return volume;
-}
-
-
-/* Gain has 16 steps from 0 to 15.  These are in 1.5dB increments from
- * 0 (no gain) to 22.5 dB.
- */
-#define CS_RECLEVEL_TO_GAIN(v) \
-	((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3)
-
-static int cs_get_gain(uint reg)
-{
-	int gain;
-
-	gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg));
-	gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8;
-	return gain;
-}
-
-static int cs_set_gain(int gain)
-{
-	uint tempctl;
-
-	tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN);
-	tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff));
-	tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff));
-	gain = cs_get_gain(tempctl);
-
-	if (tempctl != cs4218_control) {
-		cs4218_ctl_write(tempctl);
-	}
-	return gain;
-}
-
-static int CS_SetVolume(int volume)
-{
-	return cs_volume_setter(volume, CS_MUTE);
-}
-
-static void CS_Play(void)
-{
-	int i, count;
-	unsigned long flags;
-	volatile cbd_t	*bdp;
-	volatile cpm8xx_t *cp;
-
-	/* Protect buffer */
-	spin_lock_irqsave(&cs4218_lock, flags);
-#if 0
-	if (awacs_beep_state) {
-		/* sound takes precedence over beeps */
-		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-		out_le32(&awacs->control,
-			 (in_le32(&awacs->control) & ~0x1f00)
-			 | (awacs_rate_index << 8));
-		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
-		beep_playing = 0;
-		awacs_beep_state = 0;
-	}
-#endif
-	i = sq.front + sq.active;
-	if (i >= sq.max_count)
-		i -= sq.max_count;
-	while (sq.active < 2 && sq.active < sq.count) {
-		count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
-		if (count < sq.block_size && !sq.syncing)
-			/* last block not yet filled, and we're not syncing. */
-			break;
-
-		bdp = &tx_base[i];
-		bdp->cbd_datlen = count;
-
-		flush_dcache_range((ulong)sound_buffers[i],
-					(ulong)(sound_buffers[i] + count));
-
-		if (++i >= sq.max_count)
-			i = 0;
-
-		if (sq.active == 0) {
-			/* The SMC does not load its fifo until the first
-			 * TDM frame pulse, so the transmit data gets shifted
-			 * by one word.  To compensate for this, we incorrectly
-			 * transmit the first buffer and shorten it by one
-			 * word.  Subsequent buffers are then aligned properly.
-			 */
-			bdp->cbd_datlen -= 2;
-
-			/* Start up the SMC Transmitter.
-			*/
-			cp = cpmp;
-			cp->cp_smc[1].smc_smcmr |= SMCMR_TEN;
-			cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-					CPM_CR_RESTART_TX) | CPM_CR_FLG;
-			while (cp->cp_cpcr & CPM_CR_FLG);
-		}
-
-		/* Buffer is ready now.
-		*/
-		bdp->cbd_sc |= BD_SC_READY;
-
-		++sq.active;
-	}
-	spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void CS_Record(void)
-{
-	unsigned long flags;
-	volatile smc_t		*sp;
-
-	if (read_sq.active)
-		return;
-
-	/* Protect buffer */
-	spin_lock_irqsave(&cs4218_lock, flags);
-
-	/* This is all we have to do......Just start it up.
-	*/
-	sp = &cpmp->cp_smc[1];
-	sp->smc_smcmr |= SMCMR_REN;
-
-	read_sq.active = 1;
-
-        spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void
-cs4218_tdm_tx_intr(void *devid)
-{
-	int i = sq.front;
-	volatile cbd_t *bdp;
-
-	while (sq.active > 0) {
-		bdp = &tx_base[i];
-		if (bdp->cbd_sc & BD_SC_READY)
-			break;	/* this frame is still going */
-		--sq.count;
-		--sq.active;
-		if (++i >= sq.max_count)
-			i = 0;
-	}
-	if (i != sq.front)
-		WAKE_UP(sq.action_queue);
-	sq.front = i;
-
-	CS_Play();
-
-	if (!sq.active)
-		WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-cs4218_tdm_rx_intr(void *devid)
-{
-
-	/* We want to blow 'em off when shutting down.
-	*/
-	if (read_sq.active == 0)
-		return;
-
-	/* Check multiple buffers in case we were held off from
-	 * interrupt processing for a long time.  Geeze, I really hope
-	 * this doesn't happen.
-	 */
-	while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) {
-
-		/* Invalidate the data cache range for this buffer.
-		*/
-		invalidate_dcache_range(
-		    (uint)(sound_read_buffers[read_sq.rear]),
-		    (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size));
-
-		/* Make buffer available again and move on.
-		*/
-		rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY;
-		read_sq.rear++;
-
-		/* Wrap the buffer ring.
-		*/
-		if (read_sq.rear >= read_sq.max_active)
-			read_sq.rear = 0;
-
-		/* If we have caught up to the front buffer, bump it.
-		 * This will cause weird (but not fatal) results if the
-		 * read loop is currently using this buffer.  The user is
-		 * behind in this case anyway, so weird things are going
-		 * to happen.
-		 */
-		if (read_sq.rear == read_sq.front) {
-			read_sq.front++;
-			if (read_sq.front >= read_sq.max_active)
-				read_sq.front = 0;
-		}
-	}
-
-	WAKE_UP(read_sq.action_queue);
-}
-
-static void cs_nosound(unsigned long xx)
-{
-	unsigned long flags;
-
-	/* not sure if this is needed, since hardware command is #if 0'd */
-	spin_lock_irqsave(&cs4218_lock, flags);
-	if (beep_playing) {
-#if 0
-		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-#endif
-		beep_playing = 0;
-	}
-	spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-
-static void cs_mksound(unsigned int hz, unsigned int ticks)
-{
-	unsigned long flags;
-	int beep_speed = BEEP_SPEED;
-	int srate = cs4218_freqs[beep_speed];
-	int period, ncycles, nsamples;
-	int i, j, f;
-	short *p;
-	static int beep_hz_cache;
-	static int beep_nsamples_cache;
-	static int beep_volume_cache;
-
-	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
-		/* this is a hack for broken X server code */
-		hz = 750;
-		ticks = 12;
-#else
-		/* cancel beep currently playing */
-		awacs_nosound(0);
-		return;
-#endif
-	}
-	/* lock while modifying beep_timer */
-	spin_lock_irqsave(&cs4218_lock, flags);
-	del_timer(&beep_timer);
-	if (ticks) {
-		beep_timer.expires = jiffies + ticks;
-		add_timer(&beep_timer);
-	}
-	if (beep_playing || sq.active || beep_buf == NULL) {
-		spin_unlock_irqrestore(&cs4218_lock, flags);
-		return;		/* too hard, sorry :-( */
-	}
-	beep_playing = 1;
-#if 0
-	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-#endif
-	spin_unlock_irqrestore(&cs4218_lock, flags);
-
-	if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
-		nsamples = beep_nsamples_cache;
-	} else {
-		period = srate * 256 / hz;	/* fixed point */
-		ncycles = BEEP_BUFLEN * 256 / period;
-		nsamples = (period * ncycles) >> 8;
-		f = ncycles * 65536 / nsamples;
-		j = 0;
-		p = beep_buf;
-		for (i = 0; i < nsamples; ++i, p += 2) {
-			p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
-			j = (j + f) & 0xffff;
-		}
-		beep_hz_cache = hz;
-		beep_volume_cache = beep_volume;
-		beep_nsamples_cache = nsamples;
-	}
-
-#if 0
-	st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
-	st_le16(&beep_dbdma_cmd->xfer_status, 0);
-	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
-	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
-	awacs_beep_state = 1;
-
-	spin_lock_irqsave(&cs4218_lock, flags);
-	if (beep_playing) {	/* i.e. haven't been terminated already */
-		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
-		out_le32(&awacs->control,
-			 (in_le32(&awacs->control) & ~0x1f00)
-			 | (beep_speed << 8));
-		out_le32(&awacs->byteswap, 0);
-		out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
-		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-	}
-	spin_unlock_irqrestore(&cs4218_lock, flags);
-#endif
-}
-
-static MACHINE mach_cs4218 = {
-	.owner =	THIS_MODULE,
-	.name =		"HIOX CS4218",
-	.name2 =	"Built-in Sound",
-	.dma_alloc =	CS_Alloc,
-	.dma_free =	CS_Free,
-	.irqinit =	CS_IrqInit,
-#ifdef MODULE
-	.irqcleanup =	CS_IrqCleanup,
-#endif /* MODULE */
-	.init =		CS_Init,
-	.silence =	CS_Silence,
-	.setFormat =	CS_SetFormat,
-	.setVolume =	CS_SetVolume,
-	.play =		CS_Play
-};
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
-	/* update hardware settings one more */
-	(*sound.mach.init)();
-
-	(*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
-	(*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
-	return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
-	if (speed < 0)
-		return(sound.soft.speed);
-
-	sound.soft.speed = speed;
-	(*sound.mach.init)();
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.speed = sound.soft.speed;
-
-	return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
-	if (stereo < 0)
-		return(sound.soft.stereo);
-
-	stereo = !!stereo;    /* should be 0 or 1 now */
-
-	sound.soft.stereo = stereo;
-	if (sound.minDev == SND_DEV_DSP)
-		sound.dsp.stereo = stereo;
-	(*sound.mach.init)();
-
-	return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
-	return(*sound.mach.setVolume)(volume);
-}
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft)
-{
-	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		ct_func = sound.trans_write->ct_ulaw;
-		break;
-	case AFMT_A_LAW:
-		ct_func = sound.trans_write->ct_alaw;
-		break;
-	case AFMT_S8:
-		ct_func = sound.trans_write->ct_s8;
-		break;
-	case AFMT_U8:
-		ct_func = sound.trans_write->ct_u8;
-		break;
-	case AFMT_S16_BE:
-		ct_func = sound.trans_write->ct_s16be;
-		break;
-	case AFMT_U16_BE:
-		ct_func = sound.trans_write->ct_u16be;
-		break;
-	case AFMT_S16_LE:
-		ct_func = sound.trans_write->ct_s16le;
-		break;
-	case AFMT_U16_LE:
-		ct_func = sound.trans_write->ct_u16le;
-		break;
-	}
-	if (ct_func)
-		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-	else
-		return 0;
-}
-
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
-				    size_t userCount,
-				    u_char frame[], ssize_t *frameUsed,
-				    ssize_t frameLeft)
-{
-	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		ct_func = sound.trans_read->ct_ulaw;
-		break;
-	case AFMT_A_LAW:
-		ct_func = sound.trans_read->ct_alaw;
-		break;
-	case AFMT_S8:
-		ct_func = sound.trans_read->ct_s8;
-		break;
-	case AFMT_U8:
-		ct_func = sound.trans_read->ct_u8;
-		break;
-	case AFMT_S16_BE:
-		ct_func = sound.trans_read->ct_s16be;
-		break;
-	case AFMT_U16_BE:
-		ct_func = sound.trans_read->ct_u16be;
-		break;
-	case AFMT_S16_LE:
-		ct_func = sound.trans_read->ct_s16le;
-		break;
-	case AFMT_U16_LE:
-		ct_func = sound.trans_read->ct_u16le;
-		break;
-	}
-	if (ct_func)
-		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
-	else
-		return 0;
-}
-
-
-/*
- * /dev/mixer abstraction
- */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
-	mixer.busy = 1;
-	return nonseekable_open(inode, file);
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
-	mixer.busy = 0;
-	return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg)
-{
-	int data;
-	uint tmpcs;
-
-	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-	    mixer.modify_counter++;
-	if (cmd == OSS_GETVERSION)
-	    return IOCTL_OUT(arg, SOUND_VERSION);
-	switch (cmd) {
-		case SOUND_MIXER_INFO: {
-		    mixer_info info;
-		    strlcpy(info.id, "CS4218_TDM", sizeof(info.id));
-		    strlcpy(info.name, "CS4218_TDM", sizeof(info.name));
-		    info.name[sizeof(info.name)-1] = 0;
-		    info.modify_counter = mixer.modify_counter;
-		    if (copy_to_user((int *)arg, &info, sizeof(info)))
-		    		return -EFAULT;
-		    return 0;
-		}
-		case SOUND_MIXER_READ_DEVMASK:
-			data = SOUND_MASK_VOLUME | SOUND_MASK_LINE
-				| SOUND_MASK_MIC | SOUND_MASK_RECLEV
-				| SOUND_MASK_ALTPCM;
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_READ_RECMASK:
-			data = SOUND_MASK_LINE | SOUND_MASK_MIC;
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_READ_RECSRC:
-			if (cs4218_control & CS_DO1)
-				data = SOUND_MASK_LINE;
-			else
-				data = SOUND_MASK_MIC;
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_WRITE_RECSRC:
-			IOCTL_IN(arg, data);
-			data &= (SOUND_MASK_LINE | SOUND_MASK_MIC);
-			if (data & SOUND_MASK_LINE)
-				tmpcs = cs4218_control |
-						(CS_ISL | CS_ISR | CS_DO1);
-			if (data & SOUND_MASK_MIC)
-				tmpcs = cs4218_control &
-						~(CS_ISL | CS_ISR | CS_DO1);
-			if (tmpcs != cs4218_control)
-				cs4218_ctl_write(tmpcs);
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_READ_STEREODEVS:
-			data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV;
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_READ_CAPS:
-			return IOCTL_OUT(arg, 0);
-		case SOUND_MIXER_READ_VOLUME:
-			data = (cs4218_control & CS_MUTE)? 0:
-				cs_get_volume(cs4218_control);
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_WRITE_VOLUME:
-			IOCTL_IN(arg, data);
-			return IOCTL_OUT(arg, sound_set_volume(data));
-		case SOUND_MIXER_WRITE_ALTPCM:	/* really bell volume */
-			IOCTL_IN(arg, data);
-			beep_volume = data & 0xff;
-			/* fall through */
-		case SOUND_MIXER_READ_ALTPCM:
-			return IOCTL_OUT(arg, beep_volume);
-		case SOUND_MIXER_WRITE_RECLEV:
-			IOCTL_IN(arg, data);
-			data = cs_set_gain(data);
-			return IOCTL_OUT(arg, data);
-		case SOUND_MIXER_READ_RECLEV:
-			data = cs_get_gain(cs4218_control);
-			return IOCTL_OUT(arg, data);
-	}
-
-	return -EINVAL;
-}
-
-
-static const struct file_operations mixer_fops =
-{
-	.owner =	THIS_MODULE,
-	.llseek =	sound_lseek,
-	.ioctl =	mixer_ioctl,
-	.open =		mixer_open,
-	.release =	mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
-	mixer_unit = register_sound_mixer(&mixer_fops, -1);
-	if (mixer_unit < 0)
-		return;
-
-	mixer.busy = 0;
-	sound.treble = 0;
-	sound.bass = 0;
-
-	/* Set Line input, no gain, no attenuation.
-	*/
-	cs4218_control = CS_ISL | CS_ISR | CS_DO1;
-	cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0);
-	cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0);
-	cs4218_ctl_write(cs4218_control);
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
-	int i;
-
-	if (sound_buffers)
-		return 0;
-	sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
-	if (!sound_buffers)
-		return -ENOMEM;
-	for (i = 0; i < numBufs; i++) {
-		sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
-		if (!sound_buffers[i]) {
-			while (i--)
-				sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-			kfree (sound_buffers);
-			sound_buffers = 0;
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
-	int i;
-
-	if (sound_buffers) {
-		for (i = 0; i < numBufs; i++)
-			sound.mach.dma_free (sound_buffers[i], bufSize << 10);
-		kfree (sound_buffers);
-		sound_buffers = 0;
-	}
-}
-
-
-static int sq_allocate_read_buffers(void)
-{
-	int i;
-
-	if (sound_read_buffers)
-		return 0;
-	sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
-	if (!sound_read_buffers)
-		return -ENOMEM;
-	for (i = 0; i < numBufs; i++) {
-		sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
-							      GFP_KERNEL);
-		if (!sound_read_buffers[i]) {
-			while (i--)
-				sound.mach.dma_free (sound_read_buffers[i],
-						     readbufSize << 10);
-			kfree (sound_read_buffers);
-			sound_read_buffers = 0;
-			return -ENOMEM;
-		}
-	}
-	return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
-	int i;
-
-	if (sound_read_buffers) {
-		cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN;
-		for (i = 0; i < numReadBufs; i++)
-			sound.mach.dma_free (sound_read_buffers[i],
-					     bufSize << 10);
-		kfree (sound_read_buffers);
-		sound_read_buffers = 0;
-	}
-}
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
-	int i;
-	volatile cbd_t *bdp;
-	volatile cpm8xx_t	*cp;
-	volatile smc_t	*sp;
-
-	/* Make sure the SMC transmit is shut down.
-	*/
-	cp = cpmp;
-	sp = &cpmp->cp_smc[1];
-	sp->smc_smcmr &= ~SMCMR_TEN;
-
-	sq.max_count = numBufs;
-	sq.max_active = numBufs;
-	sq.block_size = bufSize;
-	sq.buffers = write_buffers;
-
-	sq.front = sq.count = 0;
-	sq.rear = -1;
-	sq.syncing = 0;
-	sq.active = 0;
-
-	bdp = tx_base;
-	for (i=0; i<numBufs; i++) {
-		bdp->cbd_bufaddr = virt_to_bus(write_buffers[i]);
-		bdp++;
-	}
-
-	/* This causes the SMC to sync up with the first buffer again.
-	*/
-	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG;
-	while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
-	int i;
-	volatile cbd_t *bdp;
-	volatile cpm8xx_t	*cp;
-	volatile smc_t	*sp;
-
-	/* Make sure the SMC receive is shut down.
-	*/
-	cp = cpmp;
-	sp = &cpmp->cp_smc[1];
-	sp->smc_smcmr &= ~SMCMR_REN;
-
-	read_sq.max_count = numBufs;
-	read_sq.max_active = numBufs;
-	read_sq.block_size = bufSize;
-	read_sq.buffers = read_buffers;
-
-	read_sq.front = read_sq.count = 0;
-	read_sq.rear = 0;
-	read_sq.rear_size = 0;
-	read_sq.syncing = 0;
-	read_sq.active = 0;
-
-	bdp = rx_base;
-	for (i=0; i<numReadBufs; i++) {
-		bdp->cbd_bufaddr = virt_to_bus(read_buffers[i]);
-		bdp->cbd_datlen = read_sq.block_size;
-		bdp++;
-	}
-
-	/* This causes the SMC to sync up with the first buffer again.
-	*/
-	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG;
-	while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-
-static void sq_play(void)
-{
-	(*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
-			loff_t *ppos)
-{
-	ssize_t uWritten = 0;
-	u_char *dest;
-	ssize_t uUsed, bUsed, bLeft;
-
-	/* ++TeSche: Is something like this necessary?
-	 * Hey, that's an honest question! Or does any other part of the
-	 * filesystem already checks this situation? I really don't know.
-	 */
-	if (uLeft == 0)
-		return 0;
-
-	/* The interrupt doesn't start to play the last, incomplete frame.
-	 * Thus we can append to it without disabling the interrupts! (Note
-	 * also that sq.rear isn't affected by the interrupt.)
-	 */
-
-	if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
-		dest = sq_block_address(sq.rear);
-		bUsed = sq.rear_size;
-		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		if (uUsed <= 0)
-			return uUsed;
-		src += uUsed;
-		uWritten += uUsed;
-		uLeft -= uUsed;
-		sq.rear_size = bUsed;
-	}
-
-	do {
-		while (sq.count == sq.max_active) {
-			sq_play();
-			if (NON_BLOCKING(sq.open_mode))
-				return uWritten > 0 ? uWritten : -EAGAIN;
-			SLEEP(sq.action_queue);
-			if (SIGNAL_RECEIVED)
-				return uWritten > 0 ? uWritten : -EINTR;
-		}
-
-		/* Here, we can avoid disabling the interrupt by first
-		 * copying and translating the data, and then updating
-		 * the sq variables. Until this is done, the interrupt
-		 * won't see the new frame and we can work on it
-		 * undisturbed.
-		 */
-
-		dest = sq_block_address((sq.rear+1) % sq.max_count);
-		bUsed = 0;
-		bLeft = sq.block_size;
-		uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
-		if (uUsed <= 0)
-			break;
-		src += uUsed;
-		uWritten += uUsed;
-		uLeft -= uUsed;
-		if (bUsed) {
-			sq.rear = (sq.rear+1) % sq.max_count;
-			sq.rear_size = bUsed;
-			sq.count++;
-		}
-	} while (bUsed);   /* uUsed may have been 0 */
-
-	sq_play();
-
-	return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running.  This is
- * done so the driver semantics are DMA starts when the first read is
- * posted.  The value 'front' indicates the buffer we should next
- * send to the user.  The value 'rear' indicates the buffer the DMA is
- * currently filling.  When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available).  The 'rear_size' is used
- * to track partial offsets into the current buffer.  Right now, I just keep
- * The DMA running.  If the reader can't keep up, the interrupt tosses
- * the oldest buffer.  We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
-                       loff_t *ppos)
-{
-
-	ssize_t	uRead, bLeft, bUsed, uUsed;
-
-	if (uLeft == 0)
-		return 0;
-
-	if (!read_sq.active)
-		CS_Record();	/* Kick off the record process. */
-
-	uRead = 0;
-
-	/* Move what the user requests, depending upon other options.
-	*/
-	while (uLeft > 0) {
-
-		/* When front == rear, the DMA is not done yet.
-		*/
-		while (read_sq.front == read_sq.rear) {
-			if (NON_BLOCKING(read_sq.open_mode)) {
-			       return uRead > 0 ? uRead : -EAGAIN;
-			}
-			SLEEP(read_sq.action_queue);
-			if (SIGNAL_RECEIVED)
-				return uRead > 0 ? uRead : -EINTR;
-		}
-
-		/* The amount we move is either what is left in the
-		 * current buffer or what the user wants.
-		 */
-		bLeft = read_sq.block_size - read_sq.rear_size;
-		bUsed = read_sq.rear_size;
-		uUsed = sound_copy_translate_read(dst, uLeft,
-			read_sq.buffers[read_sq.front], &bUsed, bLeft);
-		if (uUsed <= 0)
-			return uUsed;
-		dst += uUsed;
-		uRead += uUsed;
-		uLeft -= uUsed;
-		read_sq.rear_size += bUsed;
-		if (read_sq.rear_size >= read_sq.block_size) {
-			read_sq.rear_size = 0;
-			read_sq.front++;
-			if (read_sq.front >= read_sq.max_active)
-				read_sq.front = 0;
-		}
-	}
-	return uRead;
-}
-
-static int sq_open(struct inode *inode, struct file *file)
-{
-	int rc = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (sq.busy) {
-			rc = -EBUSY;
-			if (NON_BLOCKING(file->f_flags))
-				goto err_out;
-			rc = -EINTR;
-			while (sq.busy) {
-				SLEEP(sq.open_queue);
-				if (SIGNAL_RECEIVED)
-					goto err_out;
-			}
-		}
-		sq.busy = 1; /* Let's play spot-the-race-condition */
-
-		if (sq_allocate_buffers()) goto err_out_nobusy;
-
-		sq_setup(numBufs, bufSize<<10,sound_buffers);
-		sq.open_mode = file->f_mode;
-	}
-
-
-	if (file->f_mode & FMODE_READ) {
-		if (read_sq.busy) {
-			rc = -EBUSY;
-			if (NON_BLOCKING(file->f_flags))
-				goto err_out;
-			rc = -EINTR;
-			while (read_sq.busy) {
-				SLEEP(read_sq.open_queue);
-				if (SIGNAL_RECEIVED)
-					goto err_out;
-			}
-			rc = 0;
-		}
-		read_sq.busy = 1;
-		if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
-		read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
-		read_sq.open_mode = file->f_mode;
-	}
-
-	/* Start up the 4218 by:
-	 * Reset.
-	 * Enable, unreset.
-	 */
-	*((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO;
-	eieio();
-	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO;
-	mdelay(50);
-	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-
-	/* We need to send the current control word in case someone
-	 * opened /dev/mixer and changed things while we were shut
-	 * down.  Chances are good the initialization that follows
-	 * would have done this, but it is still possible it wouldn't.
-	 */
-	cs4218_ctl_write(cs4218_control);
-
-	sound.minDev = iminor(inode) & 0x0f;
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-	sound_init();
-	if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) {
-		sound_set_speed(8000);
-		sound_set_stereo(0);
-		sound_set_format(AFMT_MU_LAW);
-	}
-
-	return nonseekable_open(inode, file);
-
-err_out_nobusy:
-	if (file->f_mode & FMODE_WRITE) {
-		sq.busy = 0;
-		WAKE_UP(sq.open_queue);
-	}
-	if (file->f_mode & FMODE_READ) {
-		read_sq.busy = 0;
-		WAKE_UP(read_sq.open_queue);
-	}
-err_out:
-	return rc;
-}
-
-
-static void sq_reset(void)
-{
-	sound_silence();
-	sq.active = 0;
-	sq.count = 0;
-	sq.front = (sq.rear+1) % sq.max_count;
-#if 0
-	init_tdm_buffers();
-#endif
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
-	int rc = 0;
-
-	sq.syncing = 1;
-	sq_play();	/* there may be an incomplete frame waiting */
-
-	while (sq.active) {
-		SLEEP(sq.sync_queue);
-		if (SIGNAL_RECEIVED) {
-			/* While waiting for audio output to drain, an
-			 * interrupt occurred.  Stop audio output immediately
-			 * and clear the queue. */
-			sq_reset();
-			rc = -EINTR;
-			break;
-		}
-	}
-
-	sq.syncing = 0;
-	return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
-	int rc = 0;
-
-	if (sq.busy)
-		rc = sq_fsync(file, file->f_path.dentry);
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-	sound_silence();
-
-	sq_release_read_buffers();
-	sq_release_buffers();
-
-	if (file->f_mode & FMODE_READ) {
-		read_sq.busy = 0;
-		WAKE_UP(read_sq.open_queue);
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		sq.busy = 0;
-		WAKE_UP(sq.open_queue);
-	}
-
-	/* Shut down the SMC.
-	*/
-	cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN);
-
-	/* Shut down the codec.
-	*/
-	*((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-	eieio();
-	*((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO;
-
-	/* Wake up a process waiting for the queue being released.
-	 * Note: There may be several processes waiting for a call
-	 * to open() returning. */
-
-	return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		    u_long arg)
-{
-	u_long fmt;
-	int data;
-#if 0
-	int size, nbufs;
-#else
-	int size;
-#endif
-
-	switch (cmd) {
-	case SNDCTL_DSP_RESET:
-		sq_reset();
-		return 0;
-	case SNDCTL_DSP_POST:
-	case SNDCTL_DSP_SYNC:
-		return sq_fsync(file, file->f_path.dentry);
-
-		/* ++TeSche: before changing any of these it's
-		 * probably wise to wait until sound playing has
-		 * settled down. */
-	case SNDCTL_DSP_SPEED:
-		sq_fsync(file, file->f_path.dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_speed(data));
-	case SNDCTL_DSP_STEREO:
-		sq_fsync(file, file->f_path.dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data));
-	case SOUND_PCM_WRITE_CHANNELS:
-		sq_fsync(file, file->f_path.dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
-	case SNDCTL_DSP_SETFMT:
-		sq_fsync(file, file->f_path.dentry);
-		IOCTL_IN(arg, data);
-		return IOCTL_OUT(arg, sound_set_format(data));
-	case SNDCTL_DSP_GETFMTS:
-		fmt = 0;
-		if (sound.trans_write) {
-			if (sound.trans_write->ct_ulaw)
-				fmt |= AFMT_MU_LAW;
-			if (sound.trans_write->ct_alaw)
-				fmt |= AFMT_A_LAW;
-			if (sound.trans_write->ct_s8)
-				fmt |= AFMT_S8;
-			if (sound.trans_write->ct_u8)
-				fmt |= AFMT_U8;
-			if (sound.trans_write->ct_s16be)
-				fmt |= AFMT_S16_BE;
-			if (sound.trans_write->ct_u16be)
-				fmt |= AFMT_U16_BE;
-			if (sound.trans_write->ct_s16le)
-				fmt |= AFMT_S16_LE;
-			if (sound.trans_write->ct_u16le)
-				fmt |= AFMT_U16_LE;
-		}
-		return IOCTL_OUT(arg, fmt);
-	case SNDCTL_DSP_GETBLKSIZE:
-		size = sq.block_size
-			* sound.soft.size * (sound.soft.stereo + 1)
-			/ (sound.hard.size * (sound.hard.stereo + 1));
-		return IOCTL_OUT(arg, size);
-	case SNDCTL_DSP_SUBDIVIDE:
-		break;
-#if 0	/* Sorry can't do this at the moment.  The CPM allocated buffers
-	 * long ago that can't be changed.
-	 */
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (sq.count || sq.active || sq.syncing)
-			return -EINVAL;
-		IOCTL_IN(arg, size);
-		nbufs = size >> 16;
-		if (nbufs < 2 || nbufs > numBufs)
-			nbufs = numBufs;
-		size &= 0xffff;
-		if (size >= 8 && size <= 30) {
-			size = 1 << size;
-			size *= sound.hard.size * (sound.hard.stereo + 1);
-			size /= sound.soft.size * (sound.soft.stereo + 1);
-			if (size > (bufSize << 10))
-				size = bufSize << 10;
-		} else
-			size = bufSize << 10;
-		sq_setup(numBufs, size, sound_buffers);
-		sq.max_active = nbufs;
-		return 0;
-#endif
-
-	default:
-		return mixer_ioctl(inode, file, cmd, arg);
-	}
-	return -EINVAL;
-}
-
-
-
-static const struct file_operations sq_fops =
-{
-	.owner =	THIS_MODULE,
-	.llseek =	sound_lseek,
-	.read =		sq_read,			/* sq_read */
-	.write =	sq_write,
-	.ioctl =	sq_ioctl,
-	.open =		sq_open,
-	.release =	sq_release,
-};
-
-
-static void __init sq_init(void)
-{
-	sq_unit = register_sound_dsp(&sq_fops, -1);
-	if (sq_unit < 0)
-		return;
-
-	init_waitqueue_head(&sq.action_queue);
-	init_waitqueue_head(&sq.open_queue);
-	init_waitqueue_head(&sq.sync_queue);
-	init_waitqueue_head(&read_sq.action_queue);
-	init_waitqueue_head(&read_sq.open_queue);
-	init_waitqueue_head(&read_sq.sync_queue);
-
-	sq.busy = 0;
-	read_sq.busy = 0;
-
-	/* whatever you like as startup mode for /dev/dsp,
-	 * (/dev/audio hasn't got a startup mode). note that
-	 * once changed a new open() will *not* restore these!
-	 */
-	sound.dsp.format = AFMT_S16_BE;
-	sound.dsp.stereo = 1;
-	sound.dsp.size = 16;
-
-	/* set minimum rate possible without expanding */
-	sound.dsp.speed = 8000;
-
-	/* before the first open to /dev/dsp this wouldn't be set */
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-
-	sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
-	char *buffer = state.buf, *mach = "", cs4218_buf[50];
-	int len = 0;
-
-	if (state.busy)
-		return -EBUSY;
-
-	state.ptr = 0;
-	state.busy = 1;
-
-	sprintf(cs4218_buf, "Crystal CS4218 on TDM, ");
-	mach = cs4218_buf;
-
-	len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
-	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
-	switch (sound.soft.format) {
-	case AFMT_MU_LAW:
-		len += sprintf(buffer+len, " (mu-law)");
-		break;
-	case AFMT_A_LAW:
-		len += sprintf(buffer+len, " (A-law)");
-		break;
-	case AFMT_U8:
-		len += sprintf(buffer+len, " (unsigned 8 bit)");
-		break;
-	case AFMT_S8:
-		len += sprintf(buffer+len, " (signed 8 bit)");
-		break;
-	case AFMT_S16_BE:
-		len += sprintf(buffer+len, " (signed 16 bit big)");
-		break;
-	case AFMT_U16_BE:
-		len += sprintf(buffer+len, " (unsigned 16 bit big)");
-		break;
-	case AFMT_S16_LE:
-		len += sprintf(buffer+len, " (signed 16 bit little)");
-		break;
-	case AFMT_U16_LE:
-		len += sprintf(buffer+len, " (unsigned 16 bit little)");
-		break;
-	}
-	len += sprintf(buffer+len, "\n");
-	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
-		       sound.soft.speed, sound.hard.speed);
-	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
-		       sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
-	len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
-		       " sq.max_active = %d\n",
-		       sq.block_size, sq.max_count, sq.max_active);
-	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
-		       sq.rear_size);
-	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
-		       sq.active, sq.syncing);
-	state.len = len;
-	return nonseekable_open(inode, file);
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
-	state.busy = 0;
-	return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
-			  loff_t *ppos)
-{
-	int n = state.len - state.ptr;
-	if (n > count)
-		n = count;
-	if (n <= 0)
-		return 0;
-	if (copy_to_user(buf, &state.buf[state.ptr], n))
-		return -EFAULT;
-	state.ptr += n;
-	return n;
-}
-
-
-static const struct file_operations state_fops =
-{
-	.owner =	THIS_MODULE,
-	.llseek =	sound_lseek,
-	.read =		state_read,
-	.open =		state_open,
-	.release =	state_release,
-};
-
-
-static void __init state_init(void)
-{
-	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
-	if (state_unit < 0)
-		return;
-	state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
-	return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-int __init tdm8xx_sound_init(void)
-{
-	int i, has_sound;
-	uint			dp_offset;
-	volatile uint		*sirp;
-	volatile cbd_t		*bdp;
-	volatile cpm8xx_t	*cp;
-	volatile smc_t		*sp;
-	volatile smc_uart_t	*up;
-	volatile immap_t	*immap;
-
-	has_sound = 0;
-
-	/* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes.
-	*/
-	cp = cpmp;	/* Get pointer to Communication Processor */
-	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
-
-	/* Set all TDMa control bits to zero.  This enables most features
-	 * we want.
-	 */
-	cp->cp_simode &= ~0x00000fff;
-
-	/* Enable common receive/transmit clock pins, use IDL format.
-	 * Sync on falling edge, transmit rising clock, receive falling
-	 * clock, delay 1 bit on both Tx and Rx.  Common Tx/Rx clocks and
-	 * sync.
-	 * Connect SMC2 to TSA.
-	 */
-	cp->cp_simode |= 0x80000141;
-
-	/* Configure port A pins for TDMa operation.
-	 * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used.
-	 */
-	immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */
-	immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */
-	immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */
-
-	immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */
-	immap->im_ioport.iop_pcdir &= ~0x0800;
-
-	/* Initialize the SI TDM routing table.  We use TDMa only.
-	 * The receive table and transmit table each have only one
-	 * entry, to capture/send four bytes after each frame pulse.
-	 * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2)
-	 */
-	cp->cp_sigmr = 0;
-	sirp = (uint *)cp->cp_siram;
-
-	*sirp = 0x018f0000;		/* Receive entry */
-	sirp += 64;
-	*sirp = 0x018f0000;		/* Tramsmit entry */
-
-	/* Enable single TDMa routing.
-	*/
-	cp->cp_sigmr = 0x04;
-
-	/* Initialize the SMC for transparent operation.
-	*/
-	sp = &cpmp->cp_smc[1];
-	up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
-
-	/* We need to allocate a transmit and receive buffer
-	 * descriptors from dual port ram.
-	 */
-	dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8);
-
-	/* Set the physical address of the host memory
-	 * buffers in the buffer descriptors, and the
-	 * virtual address for us to work with.
-	 */
-	bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
-	up->smc_rbase = dp_offset;
-	rx_cur = rx_base = (cbd_t *)bdp;
-
-	for (i=0; i<(numReadBufs-1); i++) {
-		bdp->cbd_bufaddr = 0;
-		bdp->cbd_datlen = 0;
-		bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
-		bdp++;
-	}
-	bdp->cbd_bufaddr = 0;
-	bdp->cbd_datlen = 0;
-	bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-	/* Now, do the same for the transmit buffers.
-	*/
-	dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8);
-
-	bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
-	up->smc_tbase = dp_offset;
-	tx_cur = tx_base = (cbd_t *)bdp;
-
-	for (i=0; i<(numBufs-1); i++) {
-		bdp->cbd_bufaddr = 0;
-		bdp->cbd_datlen = 0;
-		bdp->cbd_sc = BD_SC_INTRPT;
-		bdp++;
-	}
-	bdp->cbd_bufaddr = 0;
-	bdp->cbd_datlen = 0;
-	bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
-
-	/* Set transparent SMC mode.
-	 * A few things are specific to our application.  The codec interface
-	 * is MSB first, hence the REVD selection.  The CD/CTS pulse are
-	 * used by the TSA to indicate the frame start to the SMC.
-	 */
-	up->smc_rfcr = SCC_EB;
-	up->smc_tfcr = SCC_EB;
-	up->smc_mrblr = readbufSize * 1024;
-
-	/* Set 16-bit reversed data, transparent mode.
-	*/
-	sp->smc_smcmr = smcr_mk_clen(15) |
-		SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS;
-
-	/* Enable and clear events.
-	 * Because of FIFO delays, all we need is the receive interrupt
-	 * and we can process both the current receive and current
-	 * transmit interrupt within a few microseconds of the transmit.
-	 */
-	sp->smc_smce = 0xff;
-	sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX;
-
-	/* Send the CPM an initialize command.
-	*/
-	cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-				CPM_CR_INIT_TRX) | CPM_CR_FLG;
-	while (cp->cp_cpcr & CPM_CR_FLG);
-
-	sound.mach = mach_cs4218;
-	has_sound = 1;
-
-	/* Initialize beep stuff */
-	orig_mksound = kd_mksound;
-	kd_mksound = cs_mksound;
-	beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
-	if (beep_buf == NULL)
-		printk(KERN_WARNING "dmasound: no memory for "
-		       "beep buffer\n");
-
-	if (!has_sound)
-		return -ENODEV;
-
-	/* Initialize the software SPI.
-	*/
-	sw_spi_init();
-
-	/* Set up sound queue, /dev/audio and /dev/dsp. */
-
-	/* Set default settings. */
-	sq_init();
-
-	/* Set up /dev/sndstat. */
-	state_init();
-
-	/* Set up /dev/mixer. */
-	mixer_init();
-
-	if (!sound.mach.irqinit()) {
-		printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
-		return -ENODEV;
-	}
-#ifdef MODULE
-	irq_installed = 1;
-#endif
-
-	printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
-	       numBufs, bufSize);
-
-	return 0;
-}
-
-/* Due to FIFOs and bit delays, the transmit interrupt occurs a few
- * microseconds ahead of the receive interrupt.
- * When we get an interrupt, we service the transmit first, then
- * check for a receive to prevent the overhead of returning through
- * the interrupt handler only to get back here right away during
- * full duplex operation.
- */
-static void
-cs4218_intr(void *dev_id)
-{
-	volatile smc_t	*sp;
-	volatile cpm8xx_t	*cp;
-
-	sp = &cpmp->cp_smc[1];
-
-	if (sp->smc_smce & SCCM_TX) {
-		sp->smc_smce = SCCM_TX;
-		cs4218_tdm_tx_intr((void *)sp);
-	}
-
-	if (sp->smc_smce & SCCM_RX) {
-		sp->smc_smce = SCCM_RX;
-		cs4218_tdm_rx_intr((void *)sp);
-	}
-
-	if (sp->smc_smce & SCCM_TXE) {
-		/* Transmit underrun.  This happens with the application
-		 * didn't keep up sending buffers.  We tell the SMC to
-		 * restart, which will cause it to poll the current (next)
-		 * BD.  If the user supplied data since this occurred,
-		 * we just start running again.  If they didn't, the SMC
-		 * will poll the descriptor until data is placed there.
-		 */
-		sp->smc_smce = SCCM_TXE;
-		cp = cpmp;	/* Get pointer to Communication Processor */
-		cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
-					CPM_CR_RESTART_TX) | CPM_CR_FLG;
-		while (cp->cp_cpcr & CPM_CR_FLG);
-	}
-}
-
-
-#define MAXARGS		8	/* Should be sufficient for now */
-
-void __init dmasound_setup(char *str, int *ints)
-{
-	/* check the bootstrap parameter for "dmasound=" */
-
-	switch (ints[0]) {
-	case 3:
-		if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
-			printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
-		else
-			catchRadius = ints[3];
-		/* fall through */
-	case 2:
-		if (ints[1] < MIN_BUFFERS)
-			printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs);
-		else
-			numBufs = ints[1];
-		if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
-			printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize);
-		else
-			bufSize = ints[2];
-		break;
-	case 0:
-		break;
-	default:
-		printk("dmasound_setup: invalid number of arguments\n");
-	}
-}
-
-/* Software SPI functions.
- * These are on Port B.
- */
-#define PB_SPICLK	((uint)0x00000002)
-#define PB_SPIMOSI	((uint)0x00000004)
-#define PB_SPIMISO	((uint)0x00000008)
-
-static
-void	sw_spi_init(void)
-{
-	volatile cpm8xx_t	*cp;
-	volatile uint		*hcsr4;
-
-	hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
-	cp = cpmp;	/* Get pointer to Communication Processor */
-
-	*hcsr4 &= ~HIOX_CSR4_AUDSPISEL;	/* Disable SPI select */
-
-	/* Make these Port B signals general purpose I/O.
-	 * First, make sure the clock is low.
-	 */
-	cp->cp_pbdat &= ~PB_SPICLK;
-	cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO);
-
-	/* Clock and Master Output are outputs.
-	*/
-	cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI);
-
-	/* Master Input.
-	*/
-	cp->cp_pbdir &= ~PB_SPIMISO;
-
-}
-
-/* Write the CS4218 control word out the SPI port.  While the
- * the control word is going out, the status word is arriving.
- */
-static
-uint	cs4218_ctl_write(uint ctlreg)
-{
-	uint	status;
-
-	sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4);
-
-	/* Shadow the control register.....I guess we could do
-	 * the same for the status, but for now we just return it
-	 * and let the caller decide.
-	 */
-	cs4218_control = ctlreg;
-	return status;
-}
-
-static
-void	sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt)
-{
-	int	bits, i;
-	u_char	outbyte, inbyte;
-	volatile cpm8xx_t	*cp;
-	volatile uint		*hcsr4;
-
-	hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
-	cp = cpmp;	/* Get pointer to Communication Processor */
-
-	/* The timing on the bus is pretty slow.  Code inefficiency
-	 * and eieio() is our friend here :-).
-	 */
-	cp->cp_pbdat &= ~PB_SPICLK;
-	*hcsr4 |= HIOX_CSR4_AUDSPISEL;	/* Enable SPI select */
-	eieio();
-
-	/* Clock in/out the bytes.  Data is valid on the falling edge
-	 * of the clock.  Data is MSB first.
-	 */
-	for (i=0; i<bcnt; i++) {
-		outbyte = *obuf++;
-		inbyte = 0;
-		for (bits=0; bits<8; bits++) {
-			eieio();
-			cp->cp_pbdat |= PB_SPICLK;
-			eieio();
-			if (outbyte & 0x80)
-				cp->cp_pbdat |= PB_SPIMOSI;
-			else
-				cp->cp_pbdat &= ~PB_SPIMOSI;
-			eieio();
-			cp->cp_pbdat &= ~PB_SPICLK;
-			eieio();
-			outbyte <<= 1;
-			inbyte <<= 1;
-			if (cp->cp_pbdat & PB_SPIMISO)
-				inbyte |= 1;
-		}
-		*ibuf++ = inbyte;
-	}
-
-	*hcsr4 &= ~HIOX_CSR4_AUDSPISEL;	/* Disable SPI select */
-	eieio();
-}
-
-void cleanup_module(void)
-{
-	if (irq_installed) {
-		sound_silence();
-#ifdef MODULE
-		sound.mach.irqcleanup();
-#endif
-	}
-
-	sq_release_read_buffers();
-	sq_release_buffers();
-
-	if (mixer_unit >= 0)
-		unregister_sound_mixer(mixer_unit);
-	if (state_unit >= 0)
-		unregister_sound_special(state_unit);
-	if (sq_unit >= 0)
-		unregister_sound_dsp(sq_unit);
-}
-
-module_init(tdm8xx_sound_init);
-module_exit(cleanup_module);
-
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index b23c45b..e58288e 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -30,7 +30,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -506,7 +505,6 @@ #endif
 			cep->stats.rx_dropped++;
 		}
 		else {
-			skb->dev = dev;
 			skb_put(skb,pkt_len-4);	/* Make room */
 			eth_copy_and_sum(skb,
 				cep->rx_vaddr[bdp - cep->rx_bd_base],
diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
index e6c28fb..57a9a61 100644
--- a/arch/ppc/8xx_io/fec.c
+++ b/arch/ppc/8xx_io/fec.c
@@ -724,7 +724,6 @@ #endif
 		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
 		fep->stats.rx_dropped++;
 	} else {
-		skb->dev = dev;
 		skb_put(skb,pkt_len-4);	/* Make room */
 		eth_copy_and_sum(skb, data, pkt_len-4, 0);
 		skb->protocol=eth_type_trans(skb,dev);
diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c
index 8e1fccd..9589969 100644
--- a/arch/ppc/boot/common/misc-common.c
+++ b/arch/ppc/boot/common/misc-common.c
@@ -57,7 +57,8 @@ unsigned char *ISA_io = NULL;
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+	|| defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 extern unsigned long com_port;
 
 extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@ int tstc(void)
 {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+	|| defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 	if(keyb_present)
 		return (CRT_tstc() || serial_tstc(com_port));
 	else
@@ -95,7 +97,8 @@ int getc(void)
 	while (1) {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+	|| defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 		if (serial_tstc(com_port))
 			return (serial_getc(com_port));
 #endif /* serial console */
@@ -112,7 +115,8 @@ putc(const char c)
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+	|| defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 	serial_putc(com_port, c);
 	if ( c == '\n' )
 		serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@ void puts(const char *s)
 	while ( ( c = *s++ ) != '\0' ) {
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
 	|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
-	|| defined(CONFIG_SERIAL_MPSC_CONSOLE)
+	|| defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+	|| defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 	        serial_putc(com_port, c);
 	        if ( c == '\n' ) serial_putc(com_port, '\r');
 #endif /* serial console */
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index bcfb6cd..5b87779 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -201,6 +201,7 @@ boot-$(CONFIG_8260)		+= m8260_tty.o
 endif
 boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE)	+= mpc52xx_tty.o
 boot-$(CONFIG_SERIAL_MPSC_CONSOLE)	+= mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE)	+= uartlite_tty.o
 
 LIBS				:= $(common)/lib.a $(bootlib)/lib.a
 ifeq ($(CONFIG_PPC_PREP),y)
diff --git a/arch/ppc/boot/simple/uartlite_tty.c b/arch/ppc/boot/simple/uartlite_tty.c
new file mode 100644
index 0000000..0eae1ea
--- /dev/null
+++ b/arch/ppc/boot/simple/uartlite_tty.c
@@ -0,0 +1,37 @@
+/*
+ * Xilinx UARTLITE bootloader driver
+ *
+ * Copyright (c) 2007 Secret Lab Technologies 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/types.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR))
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+	while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x08) != 0); /* spin */
+	out_be32(UARTLITE_BASEADDR + 0x4, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+	while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) == 0); /* spin */
+	return in_be32(UARTLITE_BASEADDR);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+	return ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) != 0);
+}
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index 1f91eca..c5850a2 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -40,7 +40,6 @@ main(void)
 	DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
 	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
 	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index a9d4553..ab64256 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -191,7 +191,6 @@ stack_ovf:
 0:
 
 _GLOBAL(DoSyscall)
-	stw	r0,THREAD+LAST_SYSCALL(r2)
 	stw	r3,ORIG_GPR3(r1)
 	li	r12,0
 	stw	r12,RESULT(r1)
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 0a7e42d..aa07b63 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -18,7 +18,6 @@ #include <linux/sysctl.h>
 #include <linux/capability.h>
 #include <linux/ctype.h>
 #include <linux/threads.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 1318b6f..4ad4996 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -93,8 +93,6 @@ EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strcasecmp);
-EXPORT_SYMBOL(strncasecmp);
 EXPORT_SYMBOL(__div64_32);
 
 EXPORT_SYMBOL(csum_partial);
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 96a5597..0559985 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -12,7 +12,6 @@ #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index a062556..44cd128 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -130,7 +130,7 @@ SECTIONS
   __ftr_fixup : { *(__ftr_fixup) }
   __stop___ftr_fixup = .;
 
-  . = ALIGN(32);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 50358e4..422bef9 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -2,7 +2,7 @@ #
 # Makefile for ppc-specific library files..
 #
 
-obj-y			:= checksum.o string.o strcase.o div64.o
+obj-y			:= checksum.o string.o div64.o
 
 obj-$(CONFIG_8xx)	+= rheap.o
 obj-$(CONFIG_CPM2)	+= rheap.o
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
deleted file mode 100644
index 3b0094c..0000000
--- a/arch/ppc/lib/strcase.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <linux/ctype.h>
-#include <linux/types.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
-	int c1, c2;
-
-	do {
-		c1 = tolower(*s1++);
-		c2 = tolower(*s2++);
-	} while (c1 == c2 && c1 != 0);
-	return c1 - c2;
-}
-
-int strncasecmp(const char *s1, const char *s2, size_t n)
-{
-	int c1, c2;
-
-	do {
-		c1 = tolower(*s1++);
-		c2 = tolower(*s2++);
-	} while ((--n > 0) && c1 == c2 && c1 != 0);
-	return c1 - c2;
-}
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 705ae56..76551b6 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -29,6 +29,7 @@ config CPCI405
 
 config EP405
 	bool "EP405/EP405PC"
+	select EMBEDDEDBOOT
 	help
 	  This option enables support for the EP405/EP405PC boards.
 
@@ -54,11 +55,15 @@ config WALNUT
 
 config XILINX_ML300
 	bool "Xilinx-ML300"
+	select XILINX_VIRTEX_II_PRO
+	select EMBEDDEDBOOT
 	help
 	  This option enables support for the Xilinx ML300 evaluation board.
 
 config XILINX_ML403
 	bool "Xilinx-ML403"
+	select XILINX_VIRTEX_4_FX
+	select EMBEDDEDBOOT
 	help
 	  This option enables support for the Xilinx ML403 evaluation board.
 endchoice
@@ -215,18 +220,14 @@ config 405GPR
 
 config XILINX_VIRTEX_II_PRO
 	bool
-	depends on XILINX_ML300
-	default y
+	select XILINX_VIRTEX
 
 config XILINX_VIRTEX_4_FX
 	bool
-	depends on XILINX_ML403
-	default y
+	select XILINX_VIRTEX
 
 config XILINX_VIRTEX
 	bool
-	depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX
-	default y
 
 config STB03xxx
 	bool
@@ -235,8 +236,6 @@ config STB03xxx
 
 config EMBEDDEDBOOT
 	bool
-	depends on EP405 || XILINX_ML300 || XILINX_ML403
-	default y
 
 config IBM_OPENBIOS
 	bool
diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
index fa6610b..723ad79 100644
--- a/arch/ppc/platforms/4xx/Makefile
+++ b/arch/ppc/platforms/4xx/Makefile
@@ -28,5 +28,4 @@ obj-$(CONFIG_440SP)		+= ibm440sp.o
 obj-$(CONFIG_440SPE)		+= ppc440spe.o
 obj-$(CONFIG_405EP)		+= ibm405ep.o
 obj-$(CONFIG_405GPR)		+= ibm405gpr.o
-obj-$(CONFIG_XILINX_VIRTEX)	+= virtex.o
 
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 84e999d..5e994e1 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -178,7 +178,7 @@ ocotea_setup_pcix(void)
 	/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
 	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
 	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
-	PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+	PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
 
 	eieio();
 }
@@ -289,7 +289,7 @@ ocotea_setup_arch(void)
 	 * from FPGA, because it can be changed by on-board switches
 	 * --ebs
 	 */
-	ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+	ibm440gx_get_clocks(&clocks, 33300000, 6 * 1843200);
 	ocp_sys_info.opb_bus_freq = clocks.opb;
 
 	/* Setup TODC access */
diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c
index bb0253e..5d9af8d 100644
--- a/arch/ppc/platforms/4xx/taishan.c
+++ b/arch/ppc/platforms/4xx/taishan.c
@@ -235,7 +235,7 @@ taishan_setup_pcix(void)
 	/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
 	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
 	PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
-	PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+	PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
 	PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH);
 
 	iounmap(pcix_reg_base);
diff --git a/arch/ppc/platforms/4xx/virtex.c b/arch/ppc/platforms/4xx/virtex.c
deleted file mode 100644
index 133a831..0000000
--- a/arch/ppc/platforms/4xx/virtex.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Virtex-II Pro & Virtex-4 FX common infrastructure
- *
- * Maintainer: Grant Likely <grant.likely@secretlab.ca>
- *
- * Copyright 2005 Secret Lab Technologies Ltd.
- * Copyright 2005 General Dynamics Canada Ltd.
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <asm/ppc_sys.h>
-#include <platforms/4xx/virtex.h>
-#include <platforms/4xx/xparameters/xparameters.h>
-
-#define XPAR_UART(num) { \
-		.mapbase  = XPAR_UARTNS550_##num##_BASEADDR + 3, \
-		.irq	  = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
-		.iotype	  = UPIO_MEM, \
-		.uartclk  = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
-		.flags	  = UPF_BOOT_AUTOCONF, \
-		.regshift = 2, \
-	}
-
-struct plat_serial8250_port serial_platform_data[] = {
-#ifdef XPAR_UARTNS550_0_BASEADDR
-	XPAR_UART(0),
-#endif
-#ifdef XPAR_UARTNS550_1_BASEADDR
-	XPAR_UART(1),
-#endif
-#ifdef XPAR_UARTNS550_2_BASEADDR
-	XPAR_UART(2),
-#endif
-#ifdef XPAR_UARTNS550_3_BASEADDR
-	XPAR_UART(3),
-#endif
-	{ }, /* terminated by empty record */
-};
-
-struct platform_device ppc_sys_platform_devices[] = {
-	[VIRTEX_UART] = {
-		.name		= "serial8250",
-		.id		= 0,
-		.dev.platform_data = serial_platform_data,
-	},
-};
-
diff --git a/arch/ppc/platforms/4xx/virtex.h b/arch/ppc/platforms/4xx/virtex.h
index c14325d..7382804 100644
--- a/arch/ppc/platforms/4xx/virtex.h
+++ b/arch/ppc/platforms/4xx/virtex.h
@@ -1,35 +1,35 @@
 /*
- * arch/ppc/platforms/4xx/virtex.h
+ * Basic Virtex platform defines, included by <asm/ibm4xx.h>
  *
- * Include file that defines the Xilinx Virtex-II Pro processor
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
  *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  */
 
 #ifdef __KERNEL__
 #ifndef __ASM_VIRTEX_H__
 #define __ASM_VIRTEX_H__
 
-/* serial defines */
-
 #include <asm/ibm405.h>
+#include <asm/ppcboot.h>
 
 /* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */
 #if !defined(BASE_BAUD)
  #define BASE_BAUD		(0) /* dummy value; not used */
 #endif
-  
-/* Device type enumeration for platform bus definitions */
+
 #ifndef __ASSEMBLY__
-enum ppc_sys_devices {
-	VIRTEX_UART, NUM_PPC_SYS_DEVS,
-};
-#endif
-  
+extern const char* virtex_machine_name;
+#define PPC4xx_MACHINE_NAME (virtex_machine_name)
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped.  Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR	0u
+#define PPC4xx_ONB_IO_VADDR	0u
+#define PPC4xx_ONB_IO_SIZE	0u
+
 #endif				/* __ASM_VIRTEX_H__ */
 #endif				/* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
index fb5f0b5..6e522fe 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml300.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -18,9 +18,9 @@ #include <linux/serial_8250.h>
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/ppc_sys.h>
 
 #include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
 #include <platforms/4xx/xparameters/xparameters.h>
 
 /*
@@ -53,24 +53,9 @@ #include <platforms/4xx/xparameters/xpar
  *          ppc4xx_pic_init			arch/ppc/syslib/xilinx_pic.c
  */
 
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
-	{
-		/* Only one entry, always assume the same design */
-		.ppc_sys_name	= "Xilinx ML300 Reference Design",
-		.mask 		= 0x00000000,
-		.value 		= 0x00000000,
-		.num_devices	= 1,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			VIRTEX_UART,
-		},
-	},
-};
+const char* virtex_machine_name = "ML300 Reference Design";
 
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
 static volatile unsigned *powerdown_base =
     (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
 
@@ -95,52 +80,14 @@ #if defined(XPAR_POWER_0_POWERDOWN_BASEA
 #endif
 }
 
-/* Early serial support functions */
-static void __init
-ml300_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-	struct uart_port serial_req;
-
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.mapbase	= pdata->mapbase;
-	serial_req.membase	= pdata->membase;
-	serial_req.irq		= pdata->irq;
-	serial_req.uartclk	= pdata->uartclk;
-	serial_req.regshift	= pdata->regshift;
-	serial_req.iotype	= pdata->iotype;
-	serial_req.flags	= pdata->flags;
-	gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml300_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	struct plat_serial8250_port *pdata;
-	int i = 0;
-
-	pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
-	while(pdata && pdata->flags)
-	{
-		pdata->membase = ioremap(pdata->mapbase, 0x100);
-		ml300_early_serial_init(i, pdata);
-		pdata++;
-		i++;
-	}
-#endif /* CONFIG_SERIAL_8250 */
-}
-
 void __init
 ml300_setup_arch(void)
 {
-	ml300_early_serial_map();
+	virtex_early_serial_map();
 	ppc4xx_setup_arch();	/* calls ppc4xx_find_bridges() */
 
 	/* Identify the system */
-	printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
-	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+	printk(KERN_INFO "Xilinx ML300 Reference System (Virtex-II Pro)\n");
 }
 
 /* Called after board_setup_irq from ppc4xx_init_IRQ(). */
@@ -156,8 +103,6 @@ platform_init(unsigned long r3, unsigned
 {
 	ppc4xx_init(r3, r4, r5, r6, r7);
 
-	identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
 	ppc_md.setup_arch = ml300_setup_arch;
 	ppc_md.setup_io_mappings = ml300_map_io;
 	ppc_md.init_IRQ = ml300_init_irq;
@@ -167,7 +112,7 @@ #if defined(XPAR_POWER_0_POWERDOWN_BASEA
 #endif
 
 #ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = ml300_early_serial_map;
+	ppc_md.early_serial_map = virtex_early_serial_map;
 #endif
 }
 
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
deleted file mode 100644
index 3d57332..0000000
--- a/arch/ppc/platforms/4xx/xilinx_ml300.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Include file that defines the Xilinx ML300 evaluation board
- *
- * Author: MontaVista Software, Inc.
- *         source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML300_H__
-#define __ASM_XILINX_ML300_H__
-
-/* ML300 has a Xilinx Virtex-II Pro processor */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped.  Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR	0u
-#define PPC4xx_ONB_IO_VADDR	0u
-#define PPC4xx_ONB_IO_SIZE	0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System"
-
-#endif /* __ASM_XILINX_ML300_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.c b/arch/ppc/platforms/4xx/xilinx_ml403.c
index cb3bf7a..bc3ace3 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml403.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml403.c
@@ -1,11 +1,9 @@
 /*
- * arch/ppc/platforms/4xx/xilinx_ml403.c
- *
  * Xilinx ML403 evaluation board initialization
  *
  * Author: Grant Likely <grant.likely@secretlab.ca>
  *
- * 2005 (c) Secret Lab Technologies Ltd.
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
  * 2002-2004 (c) MontaVista Software, Inc.
  *
  * This file is licensed under the terms of the GNU General Public License
@@ -22,9 +20,9 @@ #include <linux/serial_8250.h>
 #include <linux/serialP.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/ppc_sys.h>
 
 #include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
 #include <platforms/4xx/xparameters/xparameters.h>
 
 /*
@@ -57,24 +55,9 @@ #include <platforms/4xx/xparameters/xpar
  *          ppc4xx_pic_init			arch/ppc/syslib/xilinx_pic.c
  */
 
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
-	{
-		/* Only one entry, always assume the same design */
-		.ppc_sys_name	= "Xilinx ML403 Reference Design",
-		.mask 		= 0x00000000,
-		.value 		= 0x00000000,
-		.num_devices	= 1,
-		.device_list	= (enum ppc_sys_devices[])
-		{
-			VIRTEX_UART,
-		},
-	},
-};
+const char* virtex_machine_name = "ML403 Reference Design";
 
 #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
 static volatile unsigned *powerdown_base =
     (volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
 
@@ -99,47 +82,10 @@ #if defined(XPAR_POWER_0_POWERDOWN_BASEA
 #endif
 }
 
-/* Early serial support functions */
-static void __init
-ml403_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
-	struct uart_port serial_req;
-
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.mapbase	= pdata->mapbase;
-	serial_req.membase	= pdata->membase;
-	serial_req.irq		= pdata->irq;
-	serial_req.uartclk	= pdata->uartclk;
-	serial_req.regshift	= pdata->regshift;
-	serial_req.iotype	= pdata->iotype;
-	serial_req.flags	= pdata->flags;
-	gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml403_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
-	struct plat_serial8250_port *pdata;
-	int i = 0;
-
-	pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
-	while(pdata && pdata->flags)
-	{
-		pdata->membase = ioremap(pdata->mapbase, 0x100);
-		ml403_early_serial_init(i, pdata);
-		pdata++;
-		i++;
-	}
-#endif /* CONFIG_SERIAL_8250 */
-}
-
 void __init
 ml403_setup_arch(void)
 {
-	ml403_early_serial_map();
+	virtex_early_serial_map();
 	ppc4xx_setup_arch();	/* calls ppc4xx_find_bridges() */
 
 	/* Identify the system */
@@ -159,8 +105,6 @@ platform_init(unsigned long r3, unsigned
 {
 	ppc4xx_init(r3, r4, r5, r6, r7);
 
-	identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
 	ppc_md.setup_arch = ml403_setup_arch;
 	ppc_md.setup_io_mappings = ml403_map_io;
 	ppc_md.init_IRQ = ml403_init_irq;
@@ -170,7 +114,7 @@ #if defined(XPAR_POWER_0_POWERDOWN_BASEA
 #endif
 
 #ifdef CONFIG_KGDB
-	ppc_md.early_serial_map = ml403_early_serial_map;
+	ppc_md.early_serial_map = virtex_early_serial_map;
 #endif
 }
 
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.h b/arch/ppc/platforms/4xx/xilinx_ml403.h
deleted file mode 100644
index 4735969..0000000
--- a/arch/ppc/platforms/4xx/xilinx_ml403.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/xilinx_ml403.h
- *
- * Include file that defines the Xilinx ML403 reference design
- *
- * Author: Grant Likely <grant.likely@secretlab.ca>
- *
- * 2005 (c) Secret Lab Technologies Ltd.
- * 2002-2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2.  This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML403_H__
-#define __ASM_XILINX_ML403_H__
-
-/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped.  Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR	0u
-#define PPC4xx_ONB_IO_VADDR	0u
-#define PPC4xx_ONB_IO_SIZE	0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design"
-
-#endif /* __ASM_XILINX_ML403_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h
index 66ec5f3..01aa043 100644
--- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
+++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
@@ -34,3 +34,63 @@ #ifndef SERIAL_PORT_DFNS
 	.io_type	 = SERIAL_IO_MEM,				\
   },
 #endif
+
+/*
+ * A few reasonable defaults for the #defines which could be missing depending
+ * on the IP version or variant (e.g. OPB vs PLB)
+ */
+
+#ifndef XPAR_EMAC_0_CAM_EXIST
+#define XPAR_EMAC_0_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_JUMBO_EXIST
+#define XPAR_EMAC_0_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_TX_DRE_TYPE
+#define XPAR_EMAC_0_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_RX_DRE_TYPE
+#define XPAR_EMAC_0_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_TX_INCLUDE_CSUM
+#define XPAR_EMAC_0_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_0_RX_INCLUDE_CSUM
+#define XPAR_EMAC_0_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_EMAC_1_CAM_EXIST
+#define XPAR_EMAC_1_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_JUMBO_EXIST
+#define XPAR_EMAC_1_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_TX_DRE_TYPE
+#define XPAR_EMAC_1_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_RX_DRE_TYPE
+#define XPAR_EMAC_1_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_TX_INCLUDE_CSUM
+#define XPAR_EMAC_1_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_1_RX_INCLUDE_CSUM
+#define XPAR_EMAC_1_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_GPIO_0_IS_DUAL
+#define XPAR_GPIO_0_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_1_IS_DUAL
+#define XPAR_GPIO_1_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_2_IS_DUAL
+#define XPAR_GPIO_2_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_3_IS_DUAL
+#define XPAR_GPIO_3_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_4_IS_DUAL
+#define XPAR_GPIO_4_IS_DUAL 0
+#endif
+
diff --git a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
index 57a2a55..a3c1118 100644
--- a/arch/ppc/platforms/rpxclassic.h
+++ b/arch/ppc/platforms/rpxclassic.h
@@ -69,10 +69,6 @@ #define BCSR2_EN232XCVR		((uint)0x000080
 #define BCSR2_QSPACESEL		((uint)0x00004000)
 #define BCSR2_FETHLEDMODE	((uint)0x00000800)	/* CLLF */
 
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
 /* define IO_BASE for pcmcia, CLLF only */
 #if !defined(CONFIG_PCI)
 #define _IO_BASE 0x80000000
diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
deleted file mode 100644
index c3fa5a6..0000000
--- a/arch/ppc/platforms/rpxhiox.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR		((uint)0xfac00000)
-#define HIOX_CSR_SIZE		((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR		HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR		((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT	((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2	((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2	((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK	((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL	((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL	((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL	((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL	((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH	((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100	((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10	((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1	((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI	((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT	((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2	((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3	((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO	((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO	((uint)0x00000040)	/* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI	((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL	((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT	((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL	((uint)0x00000007)
-
-#endif
diff --git a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
index 7197806..b615501 100644
--- a/arch/ppc/platforms/rpxlite.h
+++ b/arch/ppc/platforms/rpxlite.h
@@ -57,10 +57,6 @@ #define BCSR1_PCVCTL5          ((uint)0x
 #define BCSR1_PCVCTL6          ((uint)0x00020000)
 #define BCSR1_PCVCTL7          ((uint)0x00010000)
 
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
 /* define IO_BASE for pcmcia */
 #define _IO_BASE 0x80000000
 #define _IO_BASE_SIZE 0x1000
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 0991111..9569415 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -18,7 +18,8 @@ obj-$(CONFIG_440SP)		+= ibm440gx_common.
 obj-$(CONFIG_440SPE)		+= ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o
 ifeq ($(CONFIG_4xx),y)
 ifeq ($(CONFIG_XILINX_VIRTEX),y)
-obj-$(CONFIG_40x)		+= xilinx_pic.o ppc_sys.o
+obj-$(CONFIG_40x)		+= xilinx_pic.o
+obj-y				+= virtex_devices.o
 else
 ifeq ($(CONFIG_403),y)
 obj-$(CONFIG_40x)		+= ppc403_pic.o
diff --git a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
deleted file mode 100644
index 5299bf8..0000000
--- a/arch/ppc/syslib/cpc710.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Definitions for the IBM CPC710 PCI Host Bridge
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __PPC_PLATFORMS_CPC710_H
-#define __PPC_PLATFORMS_CPC710_H
-
-/* General bridge and memory controller registers */
-#define PIDR	0xff000008
-#define	CNFR	0xff00000c
-#define	RSTR	0xff000010
-#define UCTL	0xff001000
-#define	MPSR	0xff001010
-#define	SIOC	0xff001020
-#define	ABCNTL	0xff001030
-#define SRST	0xff001040
-#define	ERRC	0xff001050
-#define	SESR	0xff001060
-#define	SEAR	0xff001070
-#define	SIOC1	0xff001090
-#define	PGCHP	0xff001100
-#define	GPDIR	0xff001130
-#define	GPOUT	0xff001150
-#define	ATAS	0xff001160
-#define	AVDG	0xff001170
-#define	MCCR	0xff001200
-#define	MESR	0xff001220
-#define	MEAR	0xff001230
-#define	MCER0	0xff001300
-#define	MCER1	0xff001310
-#define	MCER2	0xff001320
-#define	MCER3	0xff001330
-#define	MCER4	0xff001340
-#define	MCER5	0xff001350
-#define	MCER6	0xff001360
-#define	MCER7	0xff001370
-
-/*
- * PCI32/64 configuration registers
- * Given as offsets from their
- * respective physical segment BAR
- */
-#define PIBAR	0x000f7800
-#define PMBAR	0x000f7810
-#define MSIZE	0x000f7f40
-#define IOSIZE	0x000f7f60
-#define SMBAR	0x000f7f80
-#define SIBAR	0x000f7fc0
-#define PSSIZE	0x000f8100
-#define PPSIZE	0x000f8110
-#define BARPS	0x000f8120
-#define BARPP	0x000f8130
-#define PSBAR	0x000f8140
-#define PPBAR	0x000f8150
-#define BPMDLK	0x000f8200      /* Bottom of Peripheral Memory Space */
-#define TPMDLK	0x000f8210      /* Top of Peripheral Memory Space */
-#define BIODLK	0x000f8220      /* Bottom of Peripheral I/O Space */
-#define TIODLK	0x000f8230      /* Top of Perioheral I/O Space */
-#define DLKCTRL	0x000f8240      /* Deadlock control */
-#define DLKDEV	0x000f8250      /* Deadlock device */
-
-/* System standard configuration registers space */
-#define	DCR	0xff200000
-#define	DID	0xff200004
-#define	BAR	0xff200018
-
-/* Device specific configuration space */
-#define	PCIENB	0xff201000
-
-/* Configuration space registers */
-#define CPC710_BUS_NUMBER	0x40
-#define CPC710_SUB_BUS_NUMBER	0x41
-
-#endif /* __PPC_PLATFORMS_CPC710_H */
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 01e48d8..9caf850 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -413,7 +413,7 @@ #if !defined(CONFIG_PCI)
 	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
 #endif
 #endif
-#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
+#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
 	io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
 #endif
 #ifdef CONFIG_FADS
diff --git a/arch/ppc/syslib/ppc4xx_sgdma.c b/arch/ppc/syslib/ppc4xx_sgdma.c
index 2f83e16..c4b369b 100644
--- a/arch/ppc/syslib/ppc4xx_sgdma.c
+++ b/arch/ppc/syslib/ppc4xx_sgdma.c
@@ -23,7 +23,7 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c
new file mode 100644
index 0000000..1654678
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.c
@@ -0,0 +1,233 @@
+/*
+ * Virtex hard ppc405 core common device listing
+ *
+ * Copyright 2005-2007 Secret Lab Technologies Ltd.
+ * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2002-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <syslib/virtex_devices.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+#include <asm/io.h>
+
+/*
+ * UARTLITE: shortcut macro for single instance
+ */
+#define XPAR_UARTLITE(num) { \
+	.name = "uartlite", \
+	.id = num, \
+	.num_resources = 2, \
+	.resource = (struct resource[]) { \
+		{ \
+			.start = XPAR_UARTLITE_##num##_BASEADDR + 3, \
+			.end = XPAR_UARTLITE_##num##_HIGHADDR, \
+			.flags = IORESOURCE_MEM, \
+		}, \
+		{ \
+			.start = XPAR_INTC_0_UARTLITE_##num##_VEC_ID, \
+			.flags = IORESOURCE_IRQ, \
+		}, \
+	}, \
+}
+
+/*
+ * Full UART: shortcut macro for single instance + platform data structure
+ */
+#define XPAR_UART(num) { \
+	.mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
+	.irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+	.iotype = UPIO_MEM, \
+	.uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
+	.flags = UPF_BOOT_AUTOCONF, \
+	.regshift = 2, \
+}
+
+/*
+ * SystemACE: shortcut macro for single instance
+ */
+#define XPAR_SYSACE(num) { \
+	.name		= "xsysace", \
+	.id		= XPAR_SYSACE_##num##_DEVICE_ID, \
+	.num_resources	= 2, \
+	.resource = (struct resource[]) { \
+		{ \
+			.start	= XPAR_SYSACE_##num##_BASEADDR, \
+			.end	= XPAR_SYSACE_##num##_HIGHADDR, \
+			.flags	= IORESOURCE_MEM, \
+		}, \
+		{ \
+			.start	= XPAR_INTC_0_SYSACE_##num##_VEC_ID, \
+			.flags	= IORESOURCE_IRQ, \
+		}, \
+	}, \
+}
+
+
+/* UART 8250 driver platform data table */
+struct plat_serial8250_port virtex_serial_platform_data[] = {
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+	XPAR_UART(0),
+#endif
+#if defined(XPAR_UARTNS550_1_BASEADDR)
+	XPAR_UART(1),
+#endif
+#if defined(XPAR_UARTNS550_2_BASEADDR)
+	XPAR_UART(2),
+#endif
+#if defined(XPAR_UARTNS550_3_BASEADDR)
+	XPAR_UART(3),
+#endif
+#if defined(XPAR_UARTNS550_4_BASEADDR)
+	XPAR_UART(4),
+#endif
+#if defined(XPAR_UARTNS550_5_BASEADDR)
+	XPAR_UART(5),
+#endif
+#if defined(XPAR_UARTNS550_6_BASEADDR)
+	XPAR_UART(6),
+#endif
+#if defined(XPAR_UARTNS550_7_BASEADDR)
+	XPAR_UART(7),
+#endif
+	{ }, /* terminated by empty record */
+};
+
+
+struct platform_device virtex_platform_devices[] = {
+	/* UARTLITE instances */
+#if defined(XPAR_UARTLITE_0_BASEADDR)
+	XPAR_UARTLITE(0),
+#endif
+#if defined(XPAR_UARTLITE_1_BASEADDR)
+	XPAR_UARTLITE(1),
+#endif
+#if defined(XPAR_UARTLITE_2_BASEADDR)
+	XPAR_UARTLITE(2),
+#endif
+#if defined(XPAR_UARTLITE_3_BASEADDR)
+	XPAR_UARTLITE(3),
+#endif
+#if defined(XPAR_UARTLITE_4_BASEADDR)
+	XPAR_UARTLITE(4),
+#endif
+#if defined(XPAR_UARTLITE_5_BASEADDR)
+	XPAR_UARTLITE(5),
+#endif
+#if defined(XPAR_UARTLITE_6_BASEADDR)
+	XPAR_UARTLITE(6),
+#endif
+#if defined(XPAR_UARTLITE_7_BASEADDR)
+	XPAR_UARTLITE(7),
+#endif
+
+	/* Full UART instances */
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+	{
+		.name		= "serial8250",
+		.id		= 0,
+		.dev.platform_data = virtex_serial_platform_data,
+	},
+#endif
+
+	/* SystemACE instances */
+#if defined(XPAR_SYSACE_0_BASEADDR)
+	XPAR_SYSACE(0),
+#endif
+#if defined(XPAR_SYSACE_1_BASEADDR)
+	XPAR_SYSACE(1),
+#endif
+
+	/* ML300/403 reference design framebuffer */
+#if defined(XPAR_TFT_0_BASEADDR)
+	{
+		.name		= "xilinxfb",
+		.id		= 0,
+		.num_resources	= 1,
+		.resource = (struct resource[]) {
+			{
+				.start	= XPAR_TFT_0_BASEADDR,
+				.end	= XPAR_TFT_0_BASEADDR+7,
+				.flags	= IORESOURCE_IO,
+			},
+		},
+	},
+#endif
+};
+
+/* Early serial support functions */
+static void __init
+virtex_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	struct uart_port serial_req;
+
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.mapbase	= pdata->mapbase;
+	serial_req.membase	= pdata->membase;
+	serial_req.irq		= pdata->irq;
+	serial_req.uartclk	= pdata->uartclk;
+	serial_req.regshift	= pdata->regshift;
+	serial_req.iotype	= pdata->iotype;
+	serial_req.flags	= pdata->flags;
+	gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
+virtex_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+	struct plat_serial8250_port *pdata;
+	int i = 0;
+
+	pdata = virtex_serial_platform_data;
+	while(pdata && pdata->flags) {
+		pdata->membase = ioremap(pdata->mapbase, 0x100);
+		virtex_early_serial_init(i, pdata);
+		pdata++;
+		i++;
+	}
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+/*
+ * default fixup routine; do nothing and return success.
+ *
+ * Reimplement this routine in your custom board support file to
+ * override the default behaviour
+ */
+int __attribute__ ((weak))
+virtex_device_fixup(struct platform_device *dev)
+{
+	return 0;
+}
+
+static int __init virtex_init(void)
+{
+	struct platform_device *index = virtex_platform_devices;
+	unsigned int ret = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(virtex_platform_devices); i++, index++) {
+		if (virtex_device_fixup(index) != 0)
+			continue;
+
+		if (platform_device_register(index)) {
+			ret = 1;
+			printk(KERN_ERR "cannot register dev %s:%d\n",
+			       index->name, index->id);
+		}
+	}
+	return ret;
+}
+
+subsys_initcall(virtex_init);
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
new file mode 100644
index 0000000..3d4be14
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -0,0 +1,34 @@
+/*
+ * Common support header for virtex ppc405 platforms
+ *
+ * Copyright 2007 Secret Lab Technologies Ltd.
+ *
+ * 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 __ASM_VIRTEX_DEVICES_H__
+#define __ASM_VIRTEX_DEVICES_H__
+
+#include <linux/platform_device.h>
+
+/* ML300/403 reference design framebuffer driver platform data struct */
+struct xilinxfb_platform_data {
+	u32 rotate_screen;
+	u32 screen_height_mm;
+	u32 screen_width_mm;
+};
+
+void __init virtex_early_serial_map(void);
+
+/* Prototype for device fixup routine.  Implement this routine in the
+ * board specific fixup code and the generic setup code will call it for
+ * each device is the platform device list.
+ *
+ * If the hook returns a non-zero value, then the device will not get
+ * registered with the platform bus
+ */
+int virtex_device_fixup(struct platform_device *dev);
+
+#endif  /* __ASM_VIRTEX_DEVICES_H__ */
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 0f293aa..1a84719 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -41,9 +41,17 @@ config GENERIC_HWEIGHT
 config GENERIC_TIME
 	def_bool y
 
+config GENERIC_BUG
+	bool
+	depends on BUG
+	default y
+
 config NO_IOMEM
 	def_bool y
 
+config NO_DMA
+	def_bool y
+
 mainmenu "Linux Kernel Configuration"
 
 config S390
@@ -514,6 +522,14 @@ config KEXEC
 	  current kernel, and to start another kernel.  It is like a reboot
 	  but is independent of hardware/microcode support.
 
+config ZFCPDUMP
+	tristate "zfcpdump support"
+	select SMP
+	default n
+	help
+	  Select this option if you want to build an zfcpdump enabled kernel.
+	  Refer to "Documentation/s390/zfcpdump.txt" for more details on this.
+
 endmenu
 
 source "net/Kconfig"
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index b1e5584..68441e0 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -67,8 +67,10 @@ endif
 
 ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
 cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE)
+ifneq ($(call cc-option-yn,-mstack-size=8192),y)
 cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD)
 endif
+endif
 
 ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
 cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack
@@ -103,6 +105,9 @@ install: vmlinux
 image: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
+zfcpdump:
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
 
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 0c3cf4b..ee89b33 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -668,45 +668,7 @@ EXPORT_SYMBOL_GPL(appldata_register_ops)
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
 
-#ifdef MODULE
-/*
- * Kernel symbols needed by appldata_mem and appldata_os modules.
- * However, if this file is compiled as a module (for testing only), these
- * symbols are not exported. In this case, we define them locally and export
- * those.
- */
-void si_swapinfo(struct sysinfo *val)
-{
-	val->freeswap = -1ul;
-	val->totalswap = -1ul;
-}
-
-unsigned long avenrun[3] = {-1 - FIXED_1/200, -1 - FIXED_1/200,
-				-1 - FIXED_1/200};
-int nr_threads = -1;
-
-void get_full_page_state(struct page_state *ps)
-{
-	memset(ps, -1, sizeof(struct page_state));
-}
-
-unsigned long nr_running(void)
-{
-	return -1;
-}
-
-unsigned long nr_iowait(void)
-{
-	return -1;
-}
-
-/*unsigned long nr_context_switches(void)
-{
-	return -1;
-}*/
-#endif /* MODULE */
 EXPORT_SYMBOL_GPL(si_swapinfo);
 EXPORT_SYMBOL_GPL(nr_threads);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
-//EXPORT_SYMBOL_GPL(nr_context_switches);
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index f64b8c8..2180ac1 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -107,10 +107,7 @@ static void appldata_get_net_sum_data(vo
 	tx_dropped = 0;
 	collisions = 0;
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (dev->get_stats == NULL) {
-			continue;
-		}
+	for_each_netdev(dev) {
 		stats = dev->get_stats(dev);
 		rx_packets += stats->rx_packets;
 		tx_packets += stats->tx_packets;
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 9163635..3660ca6 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -119,7 +119,8 @@ 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_flags		=	CRYPTO_ALG_TYPE_CIPHER |
+					CRYPTO_ALG_NEED_FALLBACK,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_module		=	THIS_MODULE,
@@ -206,7 +207,8 @@ 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_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER |
+					CRYPTO_ALG_NEED_FALLBACK,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
@@ -300,7 +302,8 @@ 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_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER |
+					CRYPTO_ALG_NEED_FALLBACK,
 	.cra_blocksize		=	AES_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct s390_aes_ctx),
 	.cra_type		=	&crypto_blkcipher_type,
@@ -333,10 +336,14 @@ static int __init aes_init(void)
 		return -EOPNOTSUPP;
 
 	/* z9 109 and z9 BC/EC only support 128 bit key length */
-	if (keylen_flag == AES_KEYLEN_128)
+	if (keylen_flag == AES_KEYLEN_128) {
+		aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
+		ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
+		cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
 		printk(KERN_INFO
 		       "aes_s390: hardware acceleration only available for"
 		       "128 bit keys\n");
+	}
 
 	ret = crypto_register_alg(&aes_alg);
 	if (ret)
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index 969639f..af4460e 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -25,99 +25,100 @@
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
 #include <linux/crypto.h>
-#include <asm/scatterlist.h>
-#include <asm/byteorder.h>
+
 #include "crypt_s390.h"
 
 #define SHA1_DIGEST_SIZE	20
 #define SHA1_BLOCK_SIZE		64
 
-struct crypt_s390_sha1_ctx {
-	u64 count;
+struct s390_sha1_ctx {
+	u64 count;		/* message length */
 	u32 state[5];
-	u32 buf_len;
-	u8 buffer[2 * SHA1_BLOCK_SIZE];
+	u8 buf[2 * SHA1_BLOCK_SIZE];
 };
 
 static void sha1_init(struct crypto_tfm *tfm)
 {
-	struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
-
-	ctx->state[0] = 0x67452301;
-	ctx->state[1] =	0xEFCDAB89;
-	ctx->state[2] =	0x98BADCFE;
-	ctx->state[3] = 0x10325476;
-	ctx->state[4] =	0xC3D2E1F0;
-
-	ctx->count = 0;
-	ctx->buf_len = 0;
+	struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+
+	sctx->state[0] = 0x67452301;
+	sctx->state[1] = 0xEFCDAB89;
+	sctx->state[2] = 0x98BADCFE;
+	sctx->state[3] = 0x10325476;
+	sctx->state[4] = 0xC3D2E1F0;
+	sctx->count = 0;
 }
 
 static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
 			unsigned int len)
 {
-	struct crypt_s390_sha1_ctx *sctx;
-	long imd_len;
-
-	sctx = crypto_tfm_ctx(tfm);
-	sctx->count += len * 8; /* message bit length */
-
-	/* anything in buffer yet? -> must be completed */
-	if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
-		/* complete full block and hash */
-		memcpy(sctx->buffer + sctx->buf_len, data,
-		       SHA1_BLOCK_SIZE - sctx->buf_len);
-		crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
-				SHA1_BLOCK_SIZE);
-		data += SHA1_BLOCK_SIZE - sctx->buf_len;
-		len -= SHA1_BLOCK_SIZE - sctx->buf_len;
-		sctx->buf_len = 0;
+	struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	unsigned int index;
+	int ret;
+
+	/* how much is already in the buffer? */
+	index = sctx->count & 0x3f;
+
+	sctx->count += len;
+
+	if (index + len < SHA1_BLOCK_SIZE)
+		goto store;
+
+	/* process one stored block */
+	if (index) {
+		memcpy(sctx->buf + index, data, SHA1_BLOCK_SIZE - index);
+		ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf,
+				      SHA1_BLOCK_SIZE);
+		BUG_ON(ret != SHA1_BLOCK_SIZE);
+		data += SHA1_BLOCK_SIZE - index;
+		len -= SHA1_BLOCK_SIZE - index;
 	}
 
-	/* rest of data contains full blocks? */
-	imd_len = len & ~0x3ful;
-	if (imd_len) {
-		crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
-		data += imd_len;
-		len -= imd_len;
+	/* process as many blocks as possible */
+	if (len >= SHA1_BLOCK_SIZE) {
+		ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, data,
+				      len & ~(SHA1_BLOCK_SIZE - 1));
+		BUG_ON(ret != (len & ~(SHA1_BLOCK_SIZE - 1)));
+		data += ret;
+		len -= ret;
 	}
-	/* anything left? store in buffer */
-	if (len) {
-		memcpy(sctx->buffer + sctx->buf_len , data, len);
-		sctx->buf_len += len;
-	}
-}
 
+store:
+	/* anything left? */
+	if (len)
+		memcpy(sctx->buf + index , data, len);
+}
 
-static void pad_message(struct crypt_s390_sha1_ctx* sctx)
+/* Add padding and return the message digest. */
+static void sha1_final(struct crypto_tfm *tfm, u8 *out)
 {
-	int index;
+	struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	u64 bits;
+	unsigned int index, end;
+	int ret;
+
+	/* must perform manual padding */
+	index = sctx->count & 0x3f;
+	end =  (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE);
 
-	index = sctx->buf_len;
-	sctx->buf_len = (sctx->buf_len < 56) ?
-			 SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
 	/* start pad with 1 */
-	sctx->buffer[index] = 0x80;
+	sctx->buf[index] = 0x80;
+
 	/* pad with zeros */
 	index++;
-	memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
-	/* append length */
-	memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
-	       sizeof sctx->count);
-}
+	memset(sctx->buf + index, 0x00, end - index - 8);
 
-/* Add padding and return the message digest. */
-static void sha1_final(struct crypto_tfm *tfm, u8 *out)
-{
-	struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+	/* append message length */
+	bits = sctx->count * 8;
+	memcpy(sctx->buf + end - 8, &bits, sizeof(bits));
+
+	ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf, end);
+	BUG_ON(ret != end);
 
-	/* must perform manual padding */
-	pad_message(sctx);
-	crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
 	/* copy digest to out */
 	memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
+
 	/* wipe context */
 	memset(sctx, 0, sizeof *sctx);
 }
@@ -128,7 +129,7 @@ static struct crypto_alg alg = {
 	.cra_priority	=	CRYPT_S390_PRIORITY,
 	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
 	.cra_blocksize	=	SHA1_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct crypt_s390_sha1_ctx),
+	.cra_ctxsize	=	sizeof(struct s390_sha1_ctx),
 	.cra_module	=	THIS_MODULE,
 	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
 	.cra_u		=	{ .digest = {
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index 78436c6..2ced333 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -26,7 +26,7 @@ #define SHA256_DIGEST_SIZE	32
 #define SHA256_BLOCK_SIZE	64
 
 struct s390_sha256_ctx {
-	u64 count;
+	u64 count;		/* message length */
 	u32 state[8];
 	u8 buf[2 * SHA256_BLOCK_SIZE];
 };
@@ -54,10 +54,9 @@ static void sha256_update(struct crypto_
 	int ret;
 
 	/* how much is already in the buffer? */
-	index = sctx->count / 8 & 0x3f;
+	index = sctx->count & 0x3f;
 
-	/* update message bit length */
-	sctx->count += len * 8;
+	sctx->count += len;
 
 	if ((index + len) < SHA256_BLOCK_SIZE)
 		goto store;
@@ -87,12 +86,17 @@ store:
 		memcpy(sctx->buf + index , data, len);
 }
 
-static void pad_message(struct s390_sha256_ctx* sctx)
+/* Add padding and return the message digest */
+static void sha256_final(struct crypto_tfm *tfm, u8 *out)
 {
-	int index, end;
+	struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+	u64 bits;
+	unsigned int index, end;
+	int ret;
 
-	index = sctx->count / 8 & 0x3f;
-	end = index < 56 ? SHA256_BLOCK_SIZE : 2 * SHA256_BLOCK_SIZE;
+	/* must perform manual padding */
+	index = sctx->count & 0x3f;
+	end = (index < 56) ? SHA256_BLOCK_SIZE : (2 * SHA256_BLOCK_SIZE);
 
 	/* start pad with 1 */
 	sctx->buf[index] = 0x80;
@@ -102,21 +106,11 @@ static void pad_message(struct s390_sha2
 	memset(sctx->buf + index, 0x00, end - index - 8);
 
 	/* append message length */
-	memcpy(sctx->buf + end - 8, &sctx->count, sizeof sctx->count);
-
-	sctx->count = end * 8;
-}
-
-/* Add padding and return the message digest */
-static void sha256_final(struct crypto_tfm *tfm, u8 *out)
-{
-	struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
-
-	/* must perform manual padding */
-	pad_message(sctx);
+	bits = sctx->count * 8;
+	memcpy(sctx->buf + end - 8, &bits, sizeof(bits));
 
-	crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
-			sctx->count / 8);
+	ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf, end);
+	BUG_ON(ret != end);
 
 	/* copy digest to out */
 	memcpy(out, sctx->state, SHA256_DIGEST_SIZE);
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 741d2bb..0e4da8a 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -12,6 +12,7 @@ # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_BUG=y
 CONFIG_NO_IOMEM=y
 CONFIG_S390=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -166,6 +167,7 @@ CONFIG_NO_IDLE_HZ=y
 CONFIG_NO_IDLE_HZ_INIT=y
 CONFIG_S390_HYPFS_FS=y
 CONFIG_KEXEC=y
+# CONFIG_ZFCPDUMP is not set
 
 #
 # Networking
@@ -705,6 +707,7 @@ # CONFIG_PROVE_LOCKING is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # 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_VM is not set
 # CONFIG_DEBUG_LIST is not set
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 5492d25..3195d37 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 base.o early.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-	    semaphore.o s390_ext.o debug.o irq.o ipl.o
+	    semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o
 
 obj-y	+= $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y	+= $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 664c669..5236fdb 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -495,29 +495,34 @@ sys32_rt_sigqueueinfo(int pid, int sig, 
  * sys32_execve() executes a new program after the asm stub has set
  * things up for us.  This should basically do what I want it to.
  */
-asmlinkage long
-sys32_execve(struct pt_regs regs)
+asmlinkage long sys32_execve(void)
 {
-        int error;
-        char * filename;
+	struct pt_regs *regs = task_pt_regs(current);
+	char *filename;
+	unsigned long result;
+	int rc;
 
-        filename = getname(compat_ptr(regs.orig_gpr2));
-        error = PTR_ERR(filename);
-        if (IS_ERR(filename))
+	filename = getname(compat_ptr(regs->orig_gpr2));
+	if (IS_ERR(filename)) {
+		result = PTR_ERR(filename);
                 goto out;
-        error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
-				 compat_ptr(regs.gprs[4]), &regs);
-	if (error == 0)
-	{
-		task_lock(current);
-		current->ptrace &= ~PT_DTRACE;
-		task_unlock(current);
-		current->thread.fp_regs.fpc=0;
-		asm volatile("sfpc %0,0" : : "d" (0));
 	}
+	rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]),
+			      compat_ptr(regs->gprs[4]), regs);
+	if (rc) {
+		result = rc;
+		goto out_putname;
+	}
+	task_lock(current);
+	current->ptrace &= ~PT_DTRACE;
+	task_unlock(current);
+	current->thread.fp_regs.fpc=0;
+	asm volatile("sfpc %0,0" : : "d" (0));
+	result = regs->gprs[2];
+out_putname:
         putname(filename);
 out:
-        return error;
+	return result;
 }
 
 
@@ -918,19 +923,20 @@ asmlinkage long sys32_write(unsigned int
 	return sys_write(fd, buf, count);
 }
 
-asmlinkage long sys32_clone(struct pt_regs regs)
+asmlinkage long sys32_clone(void)
 {
-        unsigned long clone_flags;
-        unsigned long newsp;
+	struct pt_regs *regs = task_pt_regs(current);
+	unsigned long clone_flags;
+	unsigned long newsp;
 	int __user *parent_tidptr, *child_tidptr;
 
-        clone_flags = regs.gprs[3] & 0xffffffffUL;
-        newsp = regs.orig_gpr2 & 0x7fffffffUL;
-	parent_tidptr = compat_ptr(regs.gprs[4]);
-	child_tidptr = compat_ptr(regs.gprs[5]);
-        if (!newsp)
-                newsp = regs.gprs[15];
-        return do_fork(clone_flags, newsp, &regs, 0,
+	clone_flags = regs->gprs[3] & 0xffffffffUL;
+	newsp = regs->orig_gpr2 & 0x7fffffffUL;
+	parent_tidptr = compat_ptr(regs->gprs[4]);
+	child_tidptr = compat_ptr(regs->gprs[5]);
+	if (!newsp)
+		newsp = regs->gprs[15];
+	return do_fork(clone_flags, newsp, regs, 0,
 		       parent_tidptr, child_tidptr);
 }
 
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 887a988..a5692c4 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -14,7 +14,6 @@ #include <linux/compat.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -255,9 +254,9 @@ sys32_rt_sigaction(int sig, const struct
 }
 
 asmlinkage long
-sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
-							struct pt_regs *regs)
+sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	stack_t kss, koss;
 	unsigned long ss_sp;
 	int ret, err = 0;
@@ -344,8 +343,9 @@ static int restore_sigregs32(struct pt_r
 	return 0;
 }
 
-asmlinkage long sys32_sigreturn(struct pt_regs *regs)
+asmlinkage long sys32_sigreturn(void)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
 	sigset_t set;
 
@@ -370,8 +370,9 @@ badframe:
 	return 0;
 }
 
-asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys32_rt_sigreturn(void)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
 	sigset_t set;
 	stack_t st;
@@ -407,8 +408,8 @@ asmlinkage long sys32_rt_sigreturn(struc
 	return regs->gprs[2];
 
 badframe:
-        force_sig(SIGSEGV, current);
-        return 0;
+	force_sig(SIGSEGV, current);
+	return 0;
 }	
 
 /*
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
new file mode 100644
index 0000000..a057ebf
--- /dev/null
+++ b/arch/s390/kernel/dis.c
@@ -0,0 +1,1278 @@
+/*
+ * arch/s390/kernel/dis.c
+ *
+ * Disassemble s390 instructions.
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#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/interrupt.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/reboot.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/mathemu.h>
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
+#include <asm/lowcore.h>
+#include <asm/debug.h>
+
+#ifndef CONFIG_64BIT
+#define ONELONG "%08lx: "
+#else /* CONFIG_64BIT */
+#define ONELONG "%016lx: "
+#endif /* CONFIG_64BIT */
+
+#define OPERAND_GPR	0x1	/* Operand printed as %rx */
+#define OPERAND_FPR	0x2	/* Operand printed as %fx */
+#define OPERAND_AR	0x4	/* Operand printed as %ax */
+#define OPERAND_CR	0x8	/* Operand printed as %cx */
+#define OPERAND_DISP	0x10	/* Operand printed as displacement */
+#define OPERAND_BASE	0x20	/* Operand printed as base register */
+#define OPERAND_INDEX	0x40	/* Operand printed as index register */
+#define OPERAND_PCREL	0x80	/* Operand printed as pc-relative symbol */
+#define OPERAND_SIGNED	0x100	/* Operand printed as signed value */
+#define OPERAND_LENGTH	0x200	/* Operand printed as length (+1) */
+
+enum {
+	UNUSED,	/* Indicates the end of the operand list */
+	R_8,	/* GPR starting at position 8 */
+	R_12,	/* GPR starting at position 12 */
+	R_16,	/* GPR starting at position 16 */
+	R_20,	/* GPR starting at position 20 */
+	R_24,	/* GPR starting at position 24 */
+	R_28,	/* GPR starting at position 28 */
+	R_32,	/* GPR starting at position 32 */
+	F_8,	/* FPR starting at position 8 */
+	F_12,	/* FPR starting at position 12 */
+	F_16,	/* FPR starting at position 16 */
+	F_20,	/* FPR starting at position 16 */
+	F_24,	/* FPR starting at position 24 */
+	F_28,	/* FPR starting at position 28 */
+	F_32,	/* FPR starting at position 32 */
+	A_8,	/* Access reg. starting at position 8 */
+	A_12,	/* Access reg. starting at position 12 */
+	A_24,	/* Access reg. starting at position 24 */
+	A_28,	/* Access reg. starting at position 28 */
+	C_8,	/* Control reg. starting at position 8 */
+	C_12,	/* Control reg. starting at position 12 */
+	B_16,	/* Base register starting at position 16 */
+	B_32,	/* Base register starting at position 32 */
+	X_12,	/* Index register starting at position 12 */
+	D_20,	/* Displacement starting at position 20 */
+	D_36,	/* Displacement starting at position 36 */
+	D20_20,	/* 20 bit displacement starting at 20 */
+	L4_8,	/* 4 bit length starting at position 8 */
+	L4_12,	/* 4 bit length starting at position 12 */
+	L8_8,	/* 8 bit length starting at position 8 */
+	U4_8,	/* 4 bit unsigned value starting at 8 */
+	U4_12,	/* 4 bit unsigned value starting at 12 */
+	U4_16,	/* 4 bit unsigned value starting at 16 */
+	U4_20,	/* 4 bit unsigned value starting at 20 */
+	U8_8,	/* 8 bit unsigned value starting at 8 */
+	U8_16,	/* 8 bit unsigned value starting at 16 */
+	I16_16,	/* 16 bit signed value starting at 16 */
+	U16_16,	/* 16 bit unsigned value starting at 16 */
+	J16_16,	/* PC relative jump offset at 16 */
+	J32_16,	/* PC relative long offset at 16 */
+	I32_16,	/* 32 bit signed value starting at 16 */
+	U32_16,	/* 32 bit unsigned value starting at 16 */
+	M_16,	/* 4 bit optional mask starting at 16 */
+	RO_28,	/* optional GPR starting at position 28 */
+};
+
+/*
+ * Enumeration of the different instruction formats.
+ * For details consult the principles of operation.
+ */
+enum {
+	INSTR_INVALID,
+	INSTR_E, INSTR_RIE_RRP, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU,
+	INSTR_RIL_UP, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
+	INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0,
+	INSTR_RRE_FF, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, INSTR_RRE_RR,
+	INSTR_RRE_RR_OPT, INSTR_RRF_F0FF, INSTR_RRF_FUFF, INSTR_RRF_M0RR,
+	INSTR_RRF_R0RR, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF,
+	INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
+	INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, INSTR_RSI_RRP,
+	INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD,
+	INSTR_RSY_RURD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD,
+	INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD,
+	INSTR_RXF_FRRDF, INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RX_FRRD,
+	INSTR_RX_RRRD, INSTR_RX_URRD, INSTR_SIY_URD, INSTR_SI_URD,
+	INSTR_SSE_RDRD, INSTR_SSF_RRDRD, INSTR_SS_L0RDRD, INSTR_SS_LIRDRD,
+	INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
+	INSTR_S_00, INSTR_S_RD,
+};
+
+struct operand {
+	int bits;		/* The number of bits in the operand. */
+	int shift;		/* The number of bits to shift. */
+	int flags;		/* One bit syntax flags. */
+};
+
+struct insn {
+	const char name[5];
+	unsigned char opfrag;
+	unsigned char format;
+};
+
+static const struct operand operands[] =
+{
+	[UNUSED]  = { 0, 0, 0 },
+	[R_8]	 = {  4,  8, OPERAND_GPR },
+	[R_12]	 = {  4, 12, OPERAND_GPR },
+	[R_16]	 = {  4, 16, OPERAND_GPR },
+	[R_20]	 = {  4, 20, OPERAND_GPR },
+	[R_24]	 = {  4, 24, OPERAND_GPR },
+	[R_28]	 = {  4, 28, OPERAND_GPR },
+	[R_32]	 = {  4, 32, OPERAND_GPR },
+	[F_8]	 = {  4,  8, OPERAND_FPR },
+	[F_12]	 = {  4, 12, OPERAND_FPR },
+	[F_16]	 = {  4, 16, OPERAND_FPR },
+	[F_20]	 = {  4, 16, OPERAND_FPR },
+	[F_24]	 = {  4, 24, OPERAND_FPR },
+	[F_28]	 = {  4, 28, OPERAND_FPR },
+	[F_32]	 = {  4, 32, OPERAND_FPR },
+	[A_8]	 = {  4,  8, OPERAND_AR },
+	[A_12]	 = {  4, 12, OPERAND_AR },
+	[A_24]	 = {  4, 24, OPERAND_AR },
+	[A_28]	 = {  4, 28, OPERAND_AR },
+	[C_8]	 = {  4,  8, OPERAND_CR },
+	[C_12]	 = {  4, 12, OPERAND_CR },
+	[B_16]	 = {  4, 16, OPERAND_BASE | OPERAND_GPR },
+	[B_32]	 = {  4, 32, OPERAND_BASE | OPERAND_GPR },
+	[X_12]	 = {  4, 12, OPERAND_INDEX | OPERAND_GPR },
+	[D_20]	 = { 12, 20, OPERAND_DISP },
+	[D_36]	 = { 12, 36, OPERAND_DISP },
+	[D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
+	[L4_8]	 = {  4,  8, OPERAND_LENGTH },
+	[L4_12]  = {  4, 12, OPERAND_LENGTH },
+	[L8_8]	 = {  8,  8, OPERAND_LENGTH },
+	[U4_8]	 = {  4,  8, 0 },
+	[U4_12]  = {  4, 12, 0 },
+	[U4_16]  = {  4, 16, 0 },
+	[U4_20]  = {  4, 20, 0 },
+	[U8_8]	 = {  8,  8, 0 },
+	[U8_16]  = {  8, 16, 0 },
+	[I16_16] = { 16, 16, OPERAND_SIGNED },
+	[U16_16] = { 16, 16, 0 },
+	[J16_16] = { 16, 16, OPERAND_PCREL },
+	[J32_16] = { 32, 16, OPERAND_PCREL },
+	[I32_16] = { 32, 16, OPERAND_SIGNED },
+	[U32_16] = { 32, 16, 0 },
+	[M_16]	 = {  4, 16, 0 },
+	[RO_28]  = {  4, 28, OPERAND_GPR }
+};
+
+static const unsigned char formats[][7] = {
+	[INSTR_E]	  = { 0xff, 0,0,0,0,0,0 },	       /* e.g. pr    */
+	[INSTR_RIE_RRP]	  = { 0xff, R_8,R_12,J16_16,0,0,0 },   /* e.g. brxhg */
+	[INSTR_RIL_RP]	  = { 0x0f, R_8,J32_16,0,0,0,0 },      /* e.g. brasl */
+	[INSTR_RIL_UP]	  = { 0x0f, U4_8,J32_16,0,0,0,0 },     /* e.g. brcl  */
+	[INSTR_RIL_RI]	  = { 0x0f, R_8,I32_16,0,0,0,0 },      /* e.g. afi   */
+	[INSTR_RIL_RU]	  = { 0x0f, R_8,U32_16,0,0,0,0 },      /* e.g. alfi  */
+	[INSTR_RI_RI]	  = { 0x0f, R_8,I16_16,0,0,0,0 },      /* e.g. ahi   */
+	[INSTR_RI_RP]	  = { 0x0f, R_8,J16_16,0,0,0,0 },      /* e.g. brct  */
+	[INSTR_RI_RU]	  = { 0x0f, R_8,U16_16,0,0,0,0 },      /* e.g. tml   */
+	[INSTR_RI_UP]	  = { 0x0f, U4_8,J16_16,0,0,0,0 },     /* e.g. brc   */
+	[INSTR_RRE_00]	  = { 0xff, 0,0,0,0,0,0 },	       /* e.g. palb  */
+	[INSTR_RRE_0R]	  = { 0xff, R_28,0,0,0,0,0 },	       /* e.g. tb    */
+	[INSTR_RRE_AA]	  = { 0xff, A_24,A_28,0,0,0,0 },       /* e.g. cpya  */
+	[INSTR_RRE_AR]	  = { 0xff, A_24,R_28,0,0,0,0 },       /* e.g. sar   */
+	[INSTR_RRE_F0]	  = { 0xff, F_24,0,0,0,0,0 },	       /* e.g. sqer  */
+	[INSTR_RRE_FF]	  = { 0xff, F_24,F_28,0,0,0,0 },       /* e.g. debr  */
+	[INSTR_RRE_R0]	  = { 0xff, R_24,0,0,0,0,0 },	       /* e.g. ipm   */
+	[INSTR_RRE_RA]	  = { 0xff, R_24,A_28,0,0,0,0 },       /* e.g. ear   */
+	[INSTR_RRE_RF]	  = { 0xff, R_24,F_28,0,0,0,0 },       /* e.g. cefbr */
+	[INSTR_RRE_RR]	  = { 0xff, R_24,R_28,0,0,0,0 },       /* e.g. lura  */
+	[INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 },      /* efpc, sfpc */
+	[INSTR_RRF_F0FF]  = { 0xff, F_16,F_24,F_28,0,0,0 },    /* e.g. madbr */
+	[INSTR_RRF_FUFF]  = { 0xff, F_24,F_16,F_28,U4_20,0,0 },/* e.g. didbr */
+	[INSTR_RRF_RURR]  = { 0xff, R_24,R_28,R_16,U4_20,0,0 },/* e.g. .insn */
+	[INSTR_RRF_R0RR]  = { 0xff, R_24,R_28,R_16,0,0,0 },    /* e.g. idte  */
+	[INSTR_RRF_U0FF]  = { 0xff, F_24,U4_16,F_28,0,0,0 },   /* e.g. fixr  */
+	[INSTR_RRF_U0RF]  = { 0xff, R_24,U4_16,F_28,0,0,0 },   /* e.g. cfebr */
+	[INSTR_RRF_M0RR]  = { 0xff, R_24,R_28,M_16,0,0,0 },    /* e.g. sske  */
+	[INSTR_RR_FF]	  = { 0xff, F_8,F_12,0,0,0,0 },        /* e.g. adr   */
+	[INSTR_RR_R0]	  = { 0xff, R_8, 0,0,0,0,0 },	       /* e.g. spm   */
+	[INSTR_RR_RR]	  = { 0xff, R_8,R_12,0,0,0,0 },        /* e.g. lr    */
+	[INSTR_RR_U0]	  = { 0xff, U8_8, 0,0,0,0,0 },	       /* e.g. svc   */
+	[INSTR_RR_UR]	  = { 0xff, U4_8,R_12,0,0,0,0 },       /* e.g. bcr   */
+	[INSTR_RSE_RRRD]  = { 0xff, R_8,R_12,D_20,B_16,0,0 },  /* e.g. lmh   */
+	[INSTR_RSE_CCRD]  = { 0xff, C_8,C_12,D_20,B_16,0,0 },  /* e.g. lmh   */
+	[INSTR_RSE_RURD]  = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icmh  */
+	[INSTR_RSL_R0RD]  = { 0xff, R_8,D_20,B_16,0,0,0 },     /* e.g. tp    */
+	[INSTR_RSI_RRP]	  = { 0xff, R_8,R_12,J16_16,0,0,0 },   /* e.g. brxh  */
+	[INSTR_RSY_RRRD]  = { 0xff, R_8,R_12,D20_20,B_16,0,0 },/* e.g. stmy  */
+	[INSTR_RSY_RURD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
+							       /* e.g. icmh  */
+	[INSTR_RSY_AARD]  = { 0xff, A_8,A_12,D20_20,B_16,0,0 },/* e.g. lamy  */
+	[INSTR_RSY_CCRD]  = { 0xff, C_8,C_12,D20_20,B_16,0,0 },/* e.g. lamy  */
+	[INSTR_RS_AARD]	  = { 0xff, A_8,A_12,D_20,B_16,0,0 },  /* e.g. lam   */
+	[INSTR_RS_CCRD]	  = { 0xff, C_8,C_12,D_20,B_16,0,0 },  /* e.g. lctl  */
+	[INSTR_RS_R0RD]	  = { 0xff, R_8,D_20,B_16,0,0,0 },     /* e.g. sll   */
+	[INSTR_RS_RRRD]	  = { 0xff, R_8,R_12,D_20,B_16,0,0 },  /* e.g. cs    */
+	[INSTR_RS_RURD]	  = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icm   */
+	[INSTR_RXE_FRRD]  = { 0xff, F_8,D_20,X_12,B_16,0,0 },  /* e.g. axbr  */
+	[INSTR_RXE_RRRD]  = { 0xff, R_8,D_20,X_12,B_16,0,0 },  /* e.g. lg    */
+	[INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 },
+							       /* e.g. madb  */
+	[INSTR_RXY_RRRD]  = { 0xff, R_8,D20_20,X_12,B_16,0,0 },/* e.g. ly    */
+	[INSTR_RXY_FRRD]  = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley   */
+	[INSTR_RX_FRRD]	  = { 0xff, F_8,D_20,X_12,B_16,0,0 },  /* e.g. ae    */
+	[INSTR_RX_RRRD]	  = { 0xff, R_8,D_20,X_12,B_16,0,0 },  /* e.g. l     */
+	[INSTR_RX_URRD]	  = { 0x00, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc    */
+	[INSTR_SI_URD]	  = { 0x00, D_20,B_16,U8_8,0,0,0 },    /* e.g. cli   */
+	[INSTR_SIY_URD]	  = { 0xff, D20_20,B_16,U8_8,0,0,0 },  /* e.g. tmy   */
+	[INSTR_SSE_RDRD]  = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */
+	[INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
+							       /* e.g. mvc   */
+	[INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
+							       /* e.g. srp   */
+	[INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
+							       /* e.g. pack  */
+	[INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 },
+							       /* e.g. mvck  */
+	[INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 },
+							       /* e.g. plo   */
+	[INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 },
+							       /* e.g. lmd   */
+	[INSTR_S_00]	  = { 0xff, 0,0,0,0,0,0 },	       /* e.g. hsch  */
+	[INSTR_S_RD]	  = { 0xff, D_20,B_16,0,0,0,0 },       /* e.g. lpsw  */
+	[INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 },
+							       /* e.g. mvcos */
+};
+
+static struct insn opcode[] = {
+#ifdef CONFIG_64BIT
+	{ "lmd", 0xef, INSTR_SS_RRRDRD3 },
+#endif
+	{ "spm", 0x04, INSTR_RR_R0 },
+	{ "balr", 0x05, INSTR_RR_RR },
+	{ "bctr", 0x06, INSTR_RR_RR },
+	{ "bcr", 0x07, INSTR_RR_UR },
+	{ "svc", 0x0a, INSTR_RR_U0 },
+	{ "bsm", 0x0b, INSTR_RR_RR },
+	{ "bassm", 0x0c, INSTR_RR_RR },
+	{ "basr", 0x0d, INSTR_RR_RR },
+	{ "mvcl", 0x0e, INSTR_RR_RR },
+	{ "clcl", 0x0f, INSTR_RR_RR },
+	{ "lpr", 0x10, INSTR_RR_RR },
+	{ "lnr", 0x11, INSTR_RR_RR },
+	{ "ltr", 0x12, INSTR_RR_RR },
+	{ "lcr", 0x13, INSTR_RR_RR },
+	{ "nr", 0x14, INSTR_RR_RR },
+	{ "clr", 0x15, INSTR_RR_RR },
+	{ "or", 0x16, INSTR_RR_RR },
+	{ "xr", 0x17, INSTR_RR_RR },
+	{ "lr", 0x18, INSTR_RR_RR },
+	{ "cr", 0x19, INSTR_RR_RR },
+	{ "ar", 0x1a, INSTR_RR_RR },
+	{ "sr", 0x1b, INSTR_RR_RR },
+	{ "mr", 0x1c, INSTR_RR_RR },
+	{ "dr", 0x1d, INSTR_RR_RR },
+	{ "alr", 0x1e, INSTR_RR_RR },
+	{ "slr", 0x1f, INSTR_RR_RR },
+	{ "lpdr", 0x20, INSTR_RR_FF },
+	{ "lndr", 0x21, INSTR_RR_FF },
+	{ "ltdr", 0x22, INSTR_RR_FF },
+	{ "lcdr", 0x23, INSTR_RR_FF },
+	{ "hdr", 0x24, INSTR_RR_FF },
+	{ "ldxr", 0x25, INSTR_RR_FF },
+	{ "lrdr", 0x25, INSTR_RR_FF },
+	{ "mxr", 0x26, INSTR_RR_FF },
+	{ "mxdr", 0x27, INSTR_RR_FF },
+	{ "ldr", 0x28, INSTR_RR_FF },
+	{ "cdr", 0x29, INSTR_RR_FF },
+	{ "adr", 0x2a, INSTR_RR_FF },
+	{ "sdr", 0x2b, INSTR_RR_FF },
+	{ "mdr", 0x2c, INSTR_RR_FF },
+	{ "ddr", 0x2d, INSTR_RR_FF },
+	{ "awr", 0x2e, INSTR_RR_FF },
+	{ "swr", 0x2f, INSTR_RR_FF },
+	{ "lper", 0x30, INSTR_RR_FF },
+	{ "lner", 0x31, INSTR_RR_FF },
+	{ "lter", 0x32, INSTR_RR_FF },
+	{ "lcer", 0x33, INSTR_RR_FF },
+	{ "her", 0x34, INSTR_RR_FF },
+	{ "ledr", 0x35, INSTR_RR_FF },
+	{ "lrer", 0x35, INSTR_RR_FF },
+	{ "axr", 0x36, INSTR_RR_FF },
+	{ "sxr", 0x37, INSTR_RR_FF },
+	{ "ler", 0x38, INSTR_RR_FF },
+	{ "cer", 0x39, INSTR_RR_FF },
+	{ "aer", 0x3a, INSTR_RR_FF },
+	{ "ser", 0x3b, INSTR_RR_FF },
+	{ "mder", 0x3c, INSTR_RR_FF },
+	{ "mer", 0x3c, INSTR_RR_FF },
+	{ "der", 0x3d, INSTR_RR_FF },
+	{ "aur", 0x3e, INSTR_RR_FF },
+	{ "sur", 0x3f, INSTR_RR_FF },
+	{ "sth", 0x40, INSTR_RX_RRRD },
+	{ "la", 0x41, INSTR_RX_RRRD },
+	{ "stc", 0x42, INSTR_RX_RRRD },
+	{ "ic", 0x43, INSTR_RX_RRRD },
+	{ "ex", 0x44, INSTR_RX_RRRD },
+	{ "bal", 0x45, INSTR_RX_RRRD },
+	{ "bct", 0x46, INSTR_RX_RRRD },
+	{ "bc", 0x47, INSTR_RX_URRD },
+	{ "lh", 0x48, INSTR_RX_RRRD },
+	{ "ch", 0x49, INSTR_RX_RRRD },
+	{ "ah", 0x4a, INSTR_RX_RRRD },
+	{ "sh", 0x4b, INSTR_RX_RRRD },
+	{ "mh", 0x4c, INSTR_RX_RRRD },
+	{ "bas", 0x4d, INSTR_RX_RRRD },
+	{ "cvd", 0x4e, INSTR_RX_RRRD },
+	{ "cvb", 0x4f, INSTR_RX_RRRD },
+	{ "st", 0x50, INSTR_RX_RRRD },
+	{ "lae", 0x51, INSTR_RX_RRRD },
+	{ "n", 0x54, INSTR_RX_RRRD },
+	{ "cl", 0x55, INSTR_RX_RRRD },
+	{ "o", 0x56, INSTR_RX_RRRD },
+	{ "x", 0x57, INSTR_RX_RRRD },
+	{ "l", 0x58, INSTR_RX_RRRD },
+	{ "c", 0x59, INSTR_RX_RRRD },
+	{ "a", 0x5a, INSTR_RX_RRRD },
+	{ "s", 0x5b, INSTR_RX_RRRD },
+	{ "m", 0x5c, INSTR_RX_RRRD },
+	{ "d", 0x5d, INSTR_RX_RRRD },
+	{ "al", 0x5e, INSTR_RX_RRRD },
+	{ "sl", 0x5f, INSTR_RX_RRRD },
+	{ "std", 0x60, INSTR_RX_FRRD },
+	{ "mxd", 0x67, INSTR_RX_FRRD },
+	{ "ld", 0x68, INSTR_RX_FRRD },
+	{ "cd", 0x69, INSTR_RX_FRRD },
+	{ "ad", 0x6a, INSTR_RX_FRRD },
+	{ "sd", 0x6b, INSTR_RX_FRRD },
+	{ "md", 0x6c, INSTR_RX_FRRD },
+	{ "dd", 0x6d, INSTR_RX_FRRD },
+	{ "aw", 0x6e, INSTR_RX_FRRD },
+	{ "sw", 0x6f, INSTR_RX_FRRD },
+	{ "ste", 0x70, INSTR_RX_FRRD },
+	{ "ms", 0x71, INSTR_RX_RRRD },
+	{ "le", 0x78, INSTR_RX_FRRD },
+	{ "ce", 0x79, INSTR_RX_FRRD },
+	{ "ae", 0x7a, INSTR_RX_FRRD },
+	{ "se", 0x7b, INSTR_RX_FRRD },
+	{ "mde", 0x7c, INSTR_RX_FRRD },
+	{ "me", 0x7c, INSTR_RX_FRRD },
+	{ "de", 0x7d, INSTR_RX_FRRD },
+	{ "au", 0x7e, INSTR_RX_FRRD },
+	{ "su", 0x7f, INSTR_RX_FRRD },
+	{ "ssm", 0x80, INSTR_S_RD },
+	{ "lpsw", 0x82, INSTR_S_RD },
+	{ "diag", 0x83, INSTR_RS_RRRD },
+	{ "brxh", 0x84, INSTR_RSI_RRP },
+	{ "brxle", 0x85, INSTR_RSI_RRP },
+	{ "bxh", 0x86, INSTR_RS_RRRD },
+	{ "bxle", 0x87, INSTR_RS_RRRD },
+	{ "srl", 0x88, INSTR_RS_R0RD },
+	{ "sll", 0x89, INSTR_RS_R0RD },
+	{ "sra", 0x8a, INSTR_RS_R0RD },
+	{ "sla", 0x8b, INSTR_RS_R0RD },
+	{ "srdl", 0x8c, INSTR_RS_R0RD },
+	{ "sldl", 0x8d, INSTR_RS_R0RD },
+	{ "srda", 0x8e, INSTR_RS_R0RD },
+	{ "slda", 0x8f, INSTR_RS_R0RD },
+	{ "stm", 0x90, INSTR_RS_RRRD },
+	{ "tm", 0x91, INSTR_SI_URD },
+	{ "mvi", 0x92, INSTR_SI_URD },
+	{ "ts", 0x93, INSTR_S_RD },
+	{ "ni", 0x94, INSTR_SI_URD },
+	{ "cli", 0x95, INSTR_SI_URD },
+	{ "oi", 0x96, INSTR_SI_URD },
+	{ "xi", 0x97, INSTR_SI_URD },
+	{ "lm", 0x98, INSTR_RS_RRRD },
+	{ "trace", 0x99, INSTR_RS_RRRD },
+	{ "lam", 0x9a, INSTR_RS_AARD },
+	{ "stam", 0x9b, INSTR_RS_AARD },
+	{ "mvcle", 0xa8, INSTR_RS_RRRD },
+	{ "clcle", 0xa9, INSTR_RS_RRRD },
+	{ "stnsm", 0xac, INSTR_SI_URD },
+	{ "stosm", 0xad, INSTR_SI_URD },
+	{ "sigp", 0xae, INSTR_RS_RRRD },
+	{ "mc", 0xaf, INSTR_SI_URD },
+	{ "lra", 0xb1, INSTR_RX_RRRD },
+	{ "stctl", 0xb6, INSTR_RS_CCRD },
+	{ "lctl", 0xb7, INSTR_RS_CCRD },
+	{ "cs", 0xba, INSTR_RS_RRRD },
+	{ "cds", 0xbb, INSTR_RS_RRRD },
+	{ "clm", 0xbd, INSTR_RS_RURD },
+	{ "stcm", 0xbe, INSTR_RS_RURD },
+	{ "icm", 0xbf, INSTR_RS_RURD },
+	{ "mvn", 0xd1, INSTR_SS_L0RDRD },
+	{ "mvc", 0xd2, INSTR_SS_L0RDRD },
+	{ "mvz", 0xd3, INSTR_SS_L0RDRD },
+	{ "nc", 0xd4, INSTR_SS_L0RDRD },
+	{ "clc", 0xd5, INSTR_SS_L0RDRD },
+	{ "oc", 0xd6, INSTR_SS_L0RDRD },
+	{ "xc", 0xd7, INSTR_SS_L0RDRD },
+	{ "mvck", 0xd9, INSTR_SS_RRRDRD },
+	{ "mvcp", 0xda, INSTR_SS_RRRDRD },
+	{ "mvcs", 0xdb, INSTR_SS_RRRDRD },
+	{ "tr", 0xdc, INSTR_SS_L0RDRD },
+	{ "trt", 0xdd, INSTR_SS_L0RDRD },
+	{ "ed", 0xde, INSTR_SS_L0RDRD },
+	{ "edmk", 0xdf, INSTR_SS_L0RDRD },
+	{ "pku", 0xe1, INSTR_SS_L0RDRD },
+	{ "unpku", 0xe2, INSTR_SS_L0RDRD },
+	{ "mvcin", 0xe8, INSTR_SS_L0RDRD },
+	{ "pka", 0xe9, INSTR_SS_L0RDRD },
+	{ "unpka", 0xea, INSTR_SS_L0RDRD },
+	{ "plo", 0xee, INSTR_SS_RRRDRD2 },
+	{ "srp", 0xf0, INSTR_SS_LIRDRD },
+	{ "mvo", 0xf1, INSTR_SS_LLRDRD },
+	{ "pack", 0xf2, INSTR_SS_LLRDRD },
+	{ "unpk", 0xf3, INSTR_SS_LLRDRD },
+	{ "zap", 0xf8, INSTR_SS_LLRDRD },
+	{ "cp", 0xf9, INSTR_SS_LLRDRD },
+	{ "ap", 0xfa, INSTR_SS_LLRDRD },
+	{ "sp", 0xfb, INSTR_SS_LLRDRD },
+	{ "mp", 0xfc, INSTR_SS_LLRDRD },
+	{ "dp", 0xfd, INSTR_SS_LLRDRD },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_01[] = {
+#ifdef CONFIG_64BIT
+	{ "sam64", 0x0e, INSTR_E },
+#endif
+	{ "pr", 0x01, INSTR_E },
+	{ "upt", 0x02, INSTR_E },
+	{ "sckpf", 0x07, INSTR_E },
+	{ "tam", 0x0b, INSTR_E },
+	{ "sam24", 0x0c, INSTR_E },
+	{ "sam31", 0x0d, INSTR_E },
+	{ "trap2", 0xff, INSTR_E },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_a5[] = {
+#ifdef CONFIG_64BIT
+	{ "iihh", 0x00, INSTR_RI_RU },
+	{ "iihl", 0x01, INSTR_RI_RU },
+	{ "iilh", 0x02, INSTR_RI_RU },
+	{ "iill", 0x03, INSTR_RI_RU },
+	{ "nihh", 0x04, INSTR_RI_RU },
+	{ "nihl", 0x05, INSTR_RI_RU },
+	{ "nilh", 0x06, INSTR_RI_RU },
+	{ "nill", 0x07, INSTR_RI_RU },
+	{ "oihh", 0x08, INSTR_RI_RU },
+	{ "oihl", 0x09, INSTR_RI_RU },
+	{ "oilh", 0x0a, INSTR_RI_RU },
+	{ "oill", 0x0b, INSTR_RI_RU },
+	{ "llihh", 0x0c, INSTR_RI_RU },
+	{ "llihl", 0x0d, INSTR_RI_RU },
+	{ "llilh", 0x0e, INSTR_RI_RU },
+	{ "llill", 0x0f, INSTR_RI_RU },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_a7[] = {
+#ifdef CONFIG_64BIT
+	{ "tmhh", 0x02, INSTR_RI_RU },
+	{ "tmhl", 0x03, INSTR_RI_RU },
+	{ "brctg", 0x07, INSTR_RI_RP },
+	{ "lghi", 0x09, INSTR_RI_RI },
+	{ "aghi", 0x0b, INSTR_RI_RI },
+	{ "mghi", 0x0d, INSTR_RI_RI },
+	{ "cghi", 0x0f, INSTR_RI_RI },
+#endif
+	{ "tmlh", 0x00, INSTR_RI_RU },
+	{ "tmll", 0x01, INSTR_RI_RU },
+	{ "brc", 0x04, INSTR_RI_UP },
+	{ "bras", 0x05, INSTR_RI_RP },
+	{ "brct", 0x06, INSTR_RI_RP },
+	{ "lhi", 0x08, INSTR_RI_RI },
+	{ "ahi", 0x0a, INSTR_RI_RI },
+	{ "mhi", 0x0c, INSTR_RI_RI },
+	{ "chi", 0x0e, INSTR_RI_RI },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b2[] = {
+#ifdef CONFIG_64BIT
+	{ "sske", 0x2b, INSTR_RRF_M0RR },
+	{ "stckf", 0x7c, INSTR_S_RD },
+	{ "cu21", 0xa6, INSTR_RRF_M0RR },
+	{ "cuutf", 0xa6, INSTR_RRF_M0RR },
+	{ "cu12", 0xa7, INSTR_RRF_M0RR },
+	{ "cutfu", 0xa7, INSTR_RRF_M0RR },
+	{ "stfle", 0xb0, INSTR_S_RD },
+	{ "lpswe", 0xb2, INSTR_S_RD },
+#endif
+	{ "stidp", 0x02, INSTR_S_RD },
+	{ "sck", 0x04, INSTR_S_RD },
+	{ "stck", 0x05, INSTR_S_RD },
+	{ "sckc", 0x06, INSTR_S_RD },
+	{ "stckc", 0x07, INSTR_S_RD },
+	{ "spt", 0x08, INSTR_S_RD },
+	{ "stpt", 0x09, INSTR_S_RD },
+	{ "spka", 0x0a, INSTR_S_RD },
+	{ "ipk", 0x0b, INSTR_S_00 },
+	{ "ptlb", 0x0d, INSTR_S_00 },
+	{ "spx", 0x10, INSTR_S_RD },
+	{ "stpx", 0x11, INSTR_S_RD },
+	{ "stap", 0x12, INSTR_S_RD },
+	{ "sie", 0x14, INSTR_S_RD },
+	{ "pc", 0x18, INSTR_S_RD },
+	{ "sac", 0x19, INSTR_S_RD },
+	{ "cfc", 0x1a, INSTR_S_RD },
+	{ "ipte", 0x21, INSTR_RRE_RR },
+	{ "ipm", 0x22, INSTR_RRE_R0 },
+	{ "ivsk", 0x23, INSTR_RRE_RR },
+	{ "iac", 0x24, INSTR_RRE_R0 },
+	{ "ssar", 0x25, INSTR_RRE_R0 },
+	{ "epar", 0x26, INSTR_RRE_R0 },
+	{ "esar", 0x27, INSTR_RRE_R0 },
+	{ "pt", 0x28, INSTR_RRE_RR },
+	{ "iske", 0x29, INSTR_RRE_RR },
+	{ "rrbe", 0x2a, INSTR_RRE_RR },
+	{ "sske", 0x2b, INSTR_RRE_RR },
+	{ "tb", 0x2c, INSTR_RRE_0R },
+	{ "dxr", 0x2d, INSTR_RRE_F0 },
+	{ "pgin", 0x2e, INSTR_RRE_RR },
+	{ "pgout", 0x2f, INSTR_RRE_RR },
+	{ "csch", 0x30, INSTR_S_00 },
+	{ "hsch", 0x31, INSTR_S_00 },
+	{ "msch", 0x32, INSTR_S_RD },
+	{ "ssch", 0x33, INSTR_S_RD },
+	{ "stsch", 0x34, INSTR_S_RD },
+	{ "tsch", 0x35, INSTR_S_RD },
+	{ "tpi", 0x36, INSTR_S_RD },
+	{ "sal", 0x37, INSTR_S_00 },
+	{ "rsch", 0x38, INSTR_S_00 },
+	{ "stcrw", 0x39, INSTR_S_RD },
+	{ "stcps", 0x3a, INSTR_S_RD },
+	{ "rchp", 0x3b, INSTR_S_00 },
+	{ "schm", 0x3c, INSTR_S_00 },
+	{ "bakr", 0x40, INSTR_RRE_RR },
+	{ "cksm", 0x41, INSTR_RRE_RR },
+	{ "sqdr", 0x44, INSTR_RRE_F0 },
+	{ "sqer", 0x45, INSTR_RRE_F0 },
+	{ "stura", 0x46, INSTR_RRE_RR },
+	{ "msta", 0x47, INSTR_RRE_R0 },
+	{ "palb", 0x48, INSTR_RRE_00 },
+	{ "ereg", 0x49, INSTR_RRE_RR },
+	{ "esta", 0x4a, INSTR_RRE_RR },
+	{ "lura", 0x4b, INSTR_RRE_RR },
+	{ "tar", 0x4c, INSTR_RRE_AR },
+	{ "cpya", INSTR_RRE_AA },
+	{ "sar", 0x4e, INSTR_RRE_AR },
+	{ "ear", 0x4f, INSTR_RRE_RA },
+	{ "csp", 0x50, INSTR_RRE_RR },
+	{ "msr", 0x52, INSTR_RRE_RR },
+	{ "mvpg", 0x54, INSTR_RRE_RR },
+	{ "mvst", 0x55, INSTR_RRE_RR },
+	{ "cuse", 0x57, INSTR_RRE_RR },
+	{ "bsg", 0x58, INSTR_RRE_RR },
+	{ "bsa", 0x5a, INSTR_RRE_RR },
+	{ "clst", 0x5d, INSTR_RRE_RR },
+	{ "srst", 0x5e, INSTR_RRE_RR },
+	{ "cmpsc", 0x63, INSTR_RRE_RR },
+	{ "cmpsc", 0x63, INSTR_RRE_RR },
+	{ "siga", 0x74, INSTR_S_RD },
+	{ "xsch", 0x76, INSTR_S_00 },
+	{ "rp", 0x77, INSTR_S_RD },
+	{ "stcke", 0x78, INSTR_S_RD },
+	{ "sacf", 0x79, INSTR_S_RD },
+	{ "stsi", 0x7d, INSTR_S_RD },
+	{ "srnm", 0x99, INSTR_S_RD },
+	{ "stfpc", 0x9c, INSTR_S_RD },
+	{ "lfpc", 0x9d, INSTR_S_RD },
+	{ "tre", 0xa5, INSTR_RRE_RR },
+	{ "cuutf", 0xa6, INSTR_RRE_RR },
+	{ "cutfu", 0xa7, INSTR_RRE_RR },
+	{ "stfl", 0xb1, INSTR_S_RD },
+	{ "trap4", 0xff, INSTR_S_RD },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b3[] = {
+#ifdef CONFIG_64BIT
+	{ "maylr", 0x38, INSTR_RRF_F0FF },
+	{ "mylr", 0x39, INSTR_RRF_F0FF },
+	{ "mayr", 0x3a, INSTR_RRF_F0FF },
+	{ "myr", 0x3b, INSTR_RRF_F0FF },
+	{ "mayhr", 0x3c, INSTR_RRF_F0FF },
+	{ "myhr", 0x3d, INSTR_RRF_F0FF },
+	{ "cegbr", 0xa4, INSTR_RRE_RR },
+	{ "cdgbr", 0xa5, INSTR_RRE_RR },
+	{ "cxgbr", 0xa6, INSTR_RRE_RR },
+	{ "cgebr", 0xa8, INSTR_RRF_U0RF },
+	{ "cgdbr", 0xa9, INSTR_RRF_U0RF },
+	{ "cgxbr", 0xaa, INSTR_RRF_U0RF },
+	{ "cfer", 0xb8, INSTR_RRF_U0RF },
+	{ "cfdr", 0xb9, INSTR_RRF_U0RF },
+	{ "cfxr", 0xba, INSTR_RRF_U0RF },
+	{ "cegr", 0xc4, INSTR_RRE_RR },
+	{ "cdgr", 0xc5, INSTR_RRE_RR },
+	{ "cxgr", 0xc6, INSTR_RRE_RR },
+	{ "cger", 0xc8, INSTR_RRF_U0RF },
+	{ "cgdr", 0xc9, INSTR_RRF_U0RF },
+	{ "cgxr", 0xca, INSTR_RRF_U0RF },
+#endif
+	{ "lpebr", 0x00, INSTR_RRE_FF },
+	{ "lnebr", 0x01, INSTR_RRE_FF },
+	{ "ltebr", 0x02, INSTR_RRE_FF },
+	{ "lcebr", 0x03, INSTR_RRE_FF },
+	{ "ldebr", 0x04, INSTR_RRE_FF },
+	{ "lxdbr", 0x05, INSTR_RRE_FF },
+	{ "lxebr", 0x06, INSTR_RRE_FF },
+	{ "mxdbr", 0x07, INSTR_RRE_FF },
+	{ "kebr", 0x08, INSTR_RRE_FF },
+	{ "cebr", 0x09, INSTR_RRE_FF },
+	{ "aebr", 0x0a, INSTR_RRE_FF },
+	{ "sebr", 0x0b, INSTR_RRE_FF },
+	{ "mdebr", 0x0c, INSTR_RRE_FF },
+	{ "debr", 0x0d, INSTR_RRE_FF },
+	{ "maebr", 0x0e, INSTR_RRF_F0FF },
+	{ "msebr", 0x0f, INSTR_RRF_F0FF },
+	{ "lpdbr", 0x10, INSTR_RRE_FF },
+	{ "lndbr", 0x11, INSTR_RRE_FF },
+	{ "ltdbr", 0x12, INSTR_RRE_FF },
+	{ "lcdbr", 0x13, INSTR_RRE_FF },
+	{ "sqebr", 0x14, INSTR_RRE_FF },
+	{ "sqdbr", 0x15, INSTR_RRE_FF },
+	{ "sqxbr", 0x16, INSTR_RRE_FF },
+	{ "meebr", 0x17, INSTR_RRE_FF },
+	{ "kdbr", 0x18, INSTR_RRE_FF },
+	{ "cdbr", 0x19, INSTR_RRE_FF },
+	{ "adbr", 0x1a, INSTR_RRE_FF },
+	{ "sdbr", 0x1b, INSTR_RRE_FF },
+	{ "mdbr", 0x1c, INSTR_RRE_FF },
+	{ "ddbr", 0x1d, INSTR_RRE_FF },
+	{ "madbr", 0x1e, INSTR_RRF_F0FF },
+	{ "msdbr", 0x1f, INSTR_RRF_F0FF },
+	{ "lder", 0x24, INSTR_RRE_FF },
+	{ "lxdr", 0x25, INSTR_RRE_FF },
+	{ "lxer", 0x26, INSTR_RRE_FF },
+	{ "maer", 0x2e, INSTR_RRF_F0FF },
+	{ "mser", 0x2f, INSTR_RRF_F0FF },
+	{ "sqxr", 0x36, INSTR_RRE_FF },
+	{ "meer", 0x37, INSTR_RRE_FF },
+	{ "madr", 0x3e, INSTR_RRF_F0FF },
+	{ "msdr", 0x3f, INSTR_RRF_F0FF },
+	{ "lpxbr", 0x40, INSTR_RRE_FF },
+	{ "lnxbr", 0x41, INSTR_RRE_FF },
+	{ "ltxbr", 0x42, INSTR_RRE_FF },
+	{ "lcxbr", 0x43, INSTR_RRE_FF },
+	{ "ledbr", 0x44, INSTR_RRE_FF },
+	{ "ldxbr", 0x45, INSTR_RRE_FF },
+	{ "lexbr", 0x46, INSTR_RRE_FF },
+	{ "fixbr", 0x47, INSTR_RRF_U0FF },
+	{ "kxbr", 0x48, INSTR_RRE_FF },
+	{ "cxbr", 0x49, INSTR_RRE_FF },
+	{ "axbr", 0x4a, INSTR_RRE_FF },
+	{ "sxbr", 0x4b, INSTR_RRE_FF },
+	{ "mxbr", 0x4c, INSTR_RRE_FF },
+	{ "dxbr", 0x4d, INSTR_RRE_FF },
+	{ "tbedr", 0x50, INSTR_RRF_U0FF },
+	{ "tbdr", 0x51, INSTR_RRF_U0FF },
+	{ "diebr", 0x53, INSTR_RRF_FUFF },
+	{ "fiebr", 0x57, INSTR_RRF_U0FF },
+	{ "thder", 0x58, INSTR_RRE_RR },
+	{ "thdr", 0x59, INSTR_RRE_RR },
+	{ "didbr", 0x5b, INSTR_RRF_FUFF },
+	{ "fidbr", 0x5f, INSTR_RRF_U0FF },
+	{ "lpxr", 0x60, INSTR_RRE_FF },
+	{ "lnxr", 0x61, INSTR_RRE_FF },
+	{ "ltxr", 0x62, INSTR_RRE_FF },
+	{ "lcxr", 0x63, INSTR_RRE_FF },
+	{ "lxr", 0x65, INSTR_RRE_RR },
+	{ "lexr", 0x66, INSTR_RRE_FF },
+	{ "fixr", 0x67, INSTR_RRF_U0FF },
+	{ "cxr", 0x69, INSTR_RRE_FF },
+	{ "lzer", 0x74, INSTR_RRE_R0 },
+	{ "lzdr", 0x75, INSTR_RRE_R0 },
+	{ "lzxr", 0x76, INSTR_RRE_R0 },
+	{ "fier", 0x77, INSTR_RRF_U0FF },
+	{ "fidr", 0x7f, INSTR_RRF_U0FF },
+	{ "sfpc", 0x84, INSTR_RRE_RR_OPT },
+	{ "efpc", 0x8c, INSTR_RRE_RR_OPT },
+	{ "cefbr", 0x94, INSTR_RRE_RF },
+	{ "cdfbr", 0x95, INSTR_RRE_RF },
+	{ "cxfbr", 0x96, INSTR_RRE_RF },
+	{ "cfebr", 0x98, INSTR_RRF_U0RF },
+	{ "cfdbr", 0x99, INSTR_RRF_U0RF },
+	{ "cfxbr", 0x9a, INSTR_RRF_U0RF },
+	{ "cefr", 0xb4, INSTR_RRE_RF },
+	{ "cdfr", 0xb5, INSTR_RRE_RF },
+	{ "cxfr", 0xb6, INSTR_RRE_RF },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b9[] = {
+#ifdef CONFIG_64BIT
+	{ "lpgr", 0x00, INSTR_RRE_RR },
+	{ "lngr", 0x01, INSTR_RRE_RR },
+	{ "ltgr", 0x02, INSTR_RRE_RR },
+	{ "lcgr", 0x03, INSTR_RRE_RR },
+	{ "lgr", 0x04, INSTR_RRE_RR },
+	{ "lurag", 0x05, INSTR_RRE_RR },
+	{ "lgbr", 0x06, INSTR_RRE_RR },
+	{ "lghr", 0x07, INSTR_RRE_RR },
+	{ "agr", 0x08, INSTR_RRE_RR },
+	{ "sgr", 0x09, INSTR_RRE_RR },
+	{ "algr", 0x0a, INSTR_RRE_RR },
+	{ "slgr", 0x0b, INSTR_RRE_RR },
+	{ "msgr", 0x0c, INSTR_RRE_RR },
+	{ "dsgr", 0x0d, INSTR_RRE_RR },
+	{ "eregg", 0x0e, INSTR_RRE_RR },
+	{ "lrvgr", 0x0f, INSTR_RRE_RR },
+	{ "lpgfr", 0x10, INSTR_RRE_RR },
+	{ "lngfr", 0x11, INSTR_RRE_RR },
+	{ "ltgfr", 0x12, INSTR_RRE_RR },
+	{ "lcgfr", 0x13, INSTR_RRE_RR },
+	{ "lgfr", 0x14, INSTR_RRE_RR },
+	{ "llgfr", 0x16, INSTR_RRE_RR },
+	{ "llgtr", 0x17, INSTR_RRE_RR },
+	{ "agfr", 0x18, INSTR_RRE_RR },
+	{ "sgfr", 0x19, INSTR_RRE_RR },
+	{ "algfr", 0x1a, INSTR_RRE_RR },
+	{ "slgfr", 0x1b, INSTR_RRE_RR },
+	{ "msgfr", 0x1c, INSTR_RRE_RR },
+	{ "dsgfr", 0x1d, INSTR_RRE_RR },
+	{ "cgr", 0x20, INSTR_RRE_RR },
+	{ "clgr", 0x21, INSTR_RRE_RR },
+	{ "sturg", 0x25, INSTR_RRE_RR },
+	{ "lbr", 0x26, INSTR_RRE_RR },
+	{ "lhr", 0x27, INSTR_RRE_RR },
+	{ "cgfr", 0x30, INSTR_RRE_RR },
+	{ "clgfr", 0x31, INSTR_RRE_RR },
+	{ "bctgr", 0x46, INSTR_RRE_RR },
+	{ "ngr", 0x80, INSTR_RRE_RR },
+	{ "ogr", 0x81, INSTR_RRE_RR },
+	{ "xgr", 0x82, INSTR_RRE_RR },
+	{ "flogr", 0x83, INSTR_RRE_RR },
+	{ "llgcr", 0x84, INSTR_RRE_RR },
+	{ "llghr", 0x85, INSTR_RRE_RR },
+	{ "mlgr", 0x86, INSTR_RRE_RR },
+	{ "dlgr", 0x87, INSTR_RRE_RR },
+	{ "alcgr", 0x88, INSTR_RRE_RR },
+	{ "slbgr", 0x89, INSTR_RRE_RR },
+	{ "cspg", 0x8a, INSTR_RRE_RR },
+	{ "idte", 0x8e, INSTR_RRF_R0RR },
+	{ "llcr", 0x94, INSTR_RRE_RR },
+	{ "llhr", 0x95, INSTR_RRE_RR },
+	{ "esea", 0x9d, INSTR_RRE_R0 },
+	{ "lptea", 0xaa, INSTR_RRF_RURR },
+	{ "cu14", 0xb0, INSTR_RRF_M0RR },
+	{ "cu24", 0xb1, INSTR_RRF_M0RR },
+	{ "cu41", 0xb2, INSTR_RRF_M0RR },
+	{ "cu42", 0xb3, INSTR_RRF_M0RR },
+#endif
+	{ "kmac", 0x1e, INSTR_RRE_RR },
+	{ "lrvr", 0x1f, INSTR_RRE_RR },
+	{ "km", 0x2e, INSTR_RRE_RR },
+	{ "kmc", 0x2f, INSTR_RRE_RR },
+	{ "kimd", 0x3e, INSTR_RRE_RR },
+	{ "klmd", 0x3f, INSTR_RRE_RR },
+	{ "epsw", 0x8d, INSTR_RRE_RR },
+	{ "trtt", 0x90, INSTR_RRE_RR },
+	{ "trtt", 0x90, INSTR_RRF_M0RR },
+	{ "trto", 0x91, INSTR_RRE_RR },
+	{ "trto", 0x91, INSTR_RRF_M0RR },
+	{ "trot", 0x92, INSTR_RRE_RR },
+	{ "trot", 0x92, INSTR_RRF_M0RR },
+	{ "troo", 0x93, INSTR_RRE_RR },
+	{ "troo", 0x93, INSTR_RRF_M0RR },
+	{ "mlr", 0x96, INSTR_RRE_RR },
+	{ "dlr", 0x97, INSTR_RRE_RR },
+	{ "alcr", 0x98, INSTR_RRE_RR },
+	{ "slbr", 0x99, INSTR_RRE_RR },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c0[] = {
+#ifdef CONFIG_64BIT
+	{ "lgfi", 0x01, INSTR_RIL_RI },
+	{ "xihf", 0x06, INSTR_RIL_RU },
+	{ "xilf", 0x07, INSTR_RIL_RU },
+	{ "iihf", 0x08, INSTR_RIL_RU },
+	{ "iilf", 0x09, INSTR_RIL_RU },
+	{ "nihf", 0x0a, INSTR_RIL_RU },
+	{ "nilf", 0x0b, INSTR_RIL_RU },
+	{ "oihf", 0x0c, INSTR_RIL_RU },
+	{ "oilf", 0x0d, INSTR_RIL_RU },
+	{ "llihf", 0x0e, INSTR_RIL_RU },
+	{ "llilf", 0x0f, INSTR_RIL_RU },
+#endif
+	{ "larl", 0x00, INSTR_RIL_RP },
+	{ "brcl", 0x04, INSTR_RIL_UP },
+	{ "brasl", 0x05, INSTR_RIL_RP },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c2[] = {
+#ifdef CONFIG_64BIT
+	{ "slgfi", 0x04, INSTR_RIL_RU },
+	{ "slfi", 0x05, INSTR_RIL_RU },
+	{ "agfi", 0x08, INSTR_RIL_RI },
+	{ "afi", 0x09, INSTR_RIL_RI },
+	{ "algfi", 0x0a, INSTR_RIL_RU },
+	{ "alfi", 0x0b, INSTR_RIL_RU },
+	{ "cgfi", 0x0c, INSTR_RIL_RI },
+	{ "cfi", 0x0d, INSTR_RIL_RI },
+	{ "clgfi", 0x0e, INSTR_RIL_RU },
+	{ "clfi", 0x0f, INSTR_RIL_RU },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c8[] = {
+#ifdef CONFIG_64BIT
+	{ "mvcos", 0x00, INSTR_SSF_RRDRD },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_e3[] = {
+#ifdef CONFIG_64BIT
+	{ "ltg", 0x02, INSTR_RXY_RRRD },
+	{ "lrag", 0x03, INSTR_RXY_RRRD },
+	{ "lg", 0x04, INSTR_RXY_RRRD },
+	{ "cvby", 0x06, INSTR_RXY_RRRD },
+	{ "ag", 0x08, INSTR_RXY_RRRD },
+	{ "sg", 0x09, INSTR_RXY_RRRD },
+	{ "alg", 0x0a, INSTR_RXY_RRRD },
+	{ "slg", 0x0b, INSTR_RXY_RRRD },
+	{ "msg", 0x0c, INSTR_RXY_RRRD },
+	{ "dsg", 0x0d, INSTR_RXY_RRRD },
+	{ "cvbg", 0x0e, INSTR_RXY_RRRD },
+	{ "lrvg", 0x0f, INSTR_RXY_RRRD },
+	{ "lt", 0x12, INSTR_RXY_RRRD },
+	{ "lray", 0x13, INSTR_RXY_RRRD },
+	{ "lgf", 0x14, INSTR_RXY_RRRD },
+	{ "lgh", 0x15, INSTR_RXY_RRRD },
+	{ "llgf", 0x16, INSTR_RXY_RRRD },
+	{ "llgt", 0x17, INSTR_RXY_RRRD },
+	{ "agf", 0x18, INSTR_RXY_RRRD },
+	{ "sgf", 0x19, INSTR_RXY_RRRD },
+	{ "algf", 0x1a, INSTR_RXY_RRRD },
+	{ "slgf", 0x1b, INSTR_RXY_RRRD },
+	{ "msgf", 0x1c, INSTR_RXY_RRRD },
+	{ "dsgf", 0x1d, INSTR_RXY_RRRD },
+	{ "cg", 0x20, INSTR_RXY_RRRD },
+	{ "clg", 0x21, INSTR_RXY_RRRD },
+	{ "stg", 0x24, INSTR_RXY_RRRD },
+	{ "cvdy", 0x26, INSTR_RXY_RRRD },
+	{ "cvdg", 0x2e, INSTR_RXY_RRRD },
+	{ "strvg", 0x2f, INSTR_RXY_RRRD },
+	{ "cgf", 0x30, INSTR_RXY_RRRD },
+	{ "clgf", 0x31, INSTR_RXY_RRRD },
+	{ "strvh", 0x3f, INSTR_RXY_RRRD },
+	{ "bctg", 0x46, INSTR_RXY_RRRD },
+	{ "sty", 0x50, INSTR_RXY_RRRD },
+	{ "msy", 0x51, INSTR_RXY_RRRD },
+	{ "ny", 0x54, INSTR_RXY_RRRD },
+	{ "cly", 0x55, INSTR_RXY_RRRD },
+	{ "oy", 0x56, INSTR_RXY_RRRD },
+	{ "xy", 0x57, INSTR_RXY_RRRD },
+	{ "ly", 0x58, INSTR_RXY_RRRD },
+	{ "cy", 0x59, INSTR_RXY_RRRD },
+	{ "ay", 0x5a, INSTR_RXY_RRRD },
+	{ "sy", 0x5b, INSTR_RXY_RRRD },
+	{ "aly", 0x5e, INSTR_RXY_RRRD },
+	{ "sly", 0x5f, INSTR_RXY_RRRD },
+	{ "sthy", 0x70, INSTR_RXY_RRRD },
+	{ "lay", 0x71, INSTR_RXY_RRRD },
+	{ "stcy", 0x72, INSTR_RXY_RRRD },
+	{ "icy", 0x73, INSTR_RXY_RRRD },
+	{ "lb", 0x76, INSTR_RXY_RRRD },
+	{ "lgb", 0x77, INSTR_RXY_RRRD },
+	{ "lhy", 0x78, INSTR_RXY_RRRD },
+	{ "chy", 0x79, INSTR_RXY_RRRD },
+	{ "ahy", 0x7a, INSTR_RXY_RRRD },
+	{ "shy", 0x7b, INSTR_RXY_RRRD },
+	{ "ng", 0x80, INSTR_RXY_RRRD },
+	{ "og", 0x81, INSTR_RXY_RRRD },
+	{ "xg", 0x82, INSTR_RXY_RRRD },
+	{ "mlg", 0x86, INSTR_RXY_RRRD },
+	{ "dlg", 0x87, INSTR_RXY_RRRD },
+	{ "alcg", 0x88, INSTR_RXY_RRRD },
+	{ "slbg", 0x89, INSTR_RXY_RRRD },
+	{ "stpq", 0x8e, INSTR_RXY_RRRD },
+	{ "lpq", 0x8f, INSTR_RXY_RRRD },
+	{ "llgc", 0x90, INSTR_RXY_RRRD },
+	{ "llgh", 0x91, INSTR_RXY_RRRD },
+	{ "llc", 0x94, INSTR_RXY_RRRD },
+	{ "llh", 0x95, INSTR_RXY_RRRD },
+#endif
+	{ "lrv", 0x1e, INSTR_RXY_RRRD },
+	{ "lrvh", 0x1f, INSTR_RXY_RRRD },
+	{ "strv", 0x3e, INSTR_RXY_RRRD },
+	{ "ml", 0x96, INSTR_RXY_RRRD },
+	{ "dl", 0x97, INSTR_RXY_RRRD },
+	{ "alc", 0x98, INSTR_RXY_RRRD },
+	{ "slb", 0x99, INSTR_RXY_RRRD },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_e5[] = {
+#ifdef CONFIG_64BIT
+	{ "strag", 0x02, INSTR_SSE_RDRD },
+#endif
+	{ "lasp", 0x00, INSTR_SSE_RDRD },
+	{ "tprot", 0x01, INSTR_SSE_RDRD },
+	{ "mvcsk", 0x0e, INSTR_SSE_RDRD },
+	{ "mvcdk", 0x0f, INSTR_SSE_RDRD },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_eb[] = {
+#ifdef CONFIG_64BIT
+	{ "lmg", 0x04, INSTR_RSY_RRRD },
+	{ "srag", 0x0a, INSTR_RSY_RRRD },
+	{ "slag", 0x0b, INSTR_RSY_RRRD },
+	{ "srlg", 0x0c, INSTR_RSY_RRRD },
+	{ "sllg", 0x0d, INSTR_RSY_RRRD },
+	{ "tracg", 0x0f, INSTR_RSY_RRRD },
+	{ "csy", 0x14, INSTR_RSY_RRRD },
+	{ "rllg", 0x1c, INSTR_RSY_RRRD },
+	{ "clmh", 0x20, INSTR_RSY_RURD },
+	{ "clmy", 0x21, INSTR_RSY_RURD },
+	{ "stmg", 0x24, INSTR_RSY_RRRD },
+	{ "stctg", 0x25, INSTR_RSY_CCRD },
+	{ "stmh", 0x26, INSTR_RSY_RRRD },
+	{ "stcmh", 0x2c, INSTR_RSY_RURD },
+	{ "stcmy", 0x2d, INSTR_RSY_RURD },
+	{ "lctlg", 0x2f, INSTR_RSY_CCRD },
+	{ "csg", 0x30, INSTR_RSY_RRRD },
+	{ "cdsy", 0x31, INSTR_RSY_RRRD },
+	{ "cdsg", 0x3e, INSTR_RSY_RRRD },
+	{ "bxhg", 0x44, INSTR_RSY_RRRD },
+	{ "bxleg", 0x45, INSTR_RSY_RRRD },
+	{ "tmy", 0x51, INSTR_SIY_URD },
+	{ "mviy", 0x52, INSTR_SIY_URD },
+	{ "niy", 0x54, INSTR_SIY_URD },
+	{ "cliy", 0x55, INSTR_SIY_URD },
+	{ "oiy", 0x56, INSTR_SIY_URD },
+	{ "xiy", 0x57, INSTR_SIY_URD },
+	{ "icmh", 0x80, INSTR_RSE_RURD },
+	{ "icmh", 0x80, INSTR_RSY_RURD },
+	{ "icmy", 0x81, INSTR_RSY_RURD },
+	{ "clclu", 0x8f, INSTR_RSY_RRRD },
+	{ "stmy", 0x90, INSTR_RSY_RRRD },
+	{ "lmh", 0x96, INSTR_RSY_RRRD },
+	{ "lmy", 0x98, INSTR_RSY_RRRD },
+	{ "lamy", 0x9a, INSTR_RSY_AARD },
+	{ "stamy", 0x9b, INSTR_RSY_AARD },
+#endif
+	{ "rll", 0x1d, INSTR_RSY_RRRD },
+	{ "mvclu", 0x8e, INSTR_RSY_RRRD },
+	{ "tp", 0xc0, INSTR_RSL_R0RD },
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_ec[] = {
+#ifdef CONFIG_64BIT
+	{ "brxhg", 0x44, INSTR_RIE_RRP },
+	{ "brxlg", 0x45, INSTR_RIE_RRP },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_ed[] = {
+#ifdef CONFIG_64BIT
+	{ "mayl", 0x38, INSTR_RXF_FRRDF },
+	{ "myl", 0x39, INSTR_RXF_FRRDF },
+	{ "may", 0x3a, INSTR_RXF_FRRDF },
+	{ "my", 0x3b, INSTR_RXF_FRRDF },
+	{ "mayh", 0x3c, INSTR_RXF_FRRDF },
+	{ "myh", 0x3d, INSTR_RXF_FRRDF },
+	{ "ley", 0x64, INSTR_RXY_FRRD },
+	{ "ldy", 0x65, INSTR_RXY_FRRD },
+	{ "stey", 0x66, INSTR_RXY_FRRD },
+	{ "stdy", 0x67, INSTR_RXY_FRRD },
+#endif
+	{ "ldeb", 0x04, INSTR_RXE_FRRD },
+	{ "lxdb", 0x05, INSTR_RXE_FRRD },
+	{ "lxeb", 0x06, INSTR_RXE_FRRD },
+	{ "mxdb", 0x07, INSTR_RXE_FRRD },
+	{ "keb", 0x08, INSTR_RXE_FRRD },
+	{ "ceb", 0x09, INSTR_RXE_FRRD },
+	{ "aeb", 0x0a, INSTR_RXE_FRRD },
+	{ "seb", 0x0b, INSTR_RXE_FRRD },
+	{ "mdeb", 0x0c, INSTR_RXE_FRRD },
+	{ "deb", 0x0d, INSTR_RXE_FRRD },
+	{ "maeb", 0x0e, INSTR_RXF_FRRDF },
+	{ "mseb", 0x0f, INSTR_RXF_FRRDF },
+	{ "tceb", 0x10, INSTR_RXE_FRRD },
+	{ "tcdb", 0x11, INSTR_RXE_FRRD },
+	{ "tcxb", 0x12, INSTR_RXE_FRRD },
+	{ "sqeb", 0x14, INSTR_RXE_FRRD },
+	{ "sqdb", 0x15, INSTR_RXE_FRRD },
+	{ "meeb", 0x17, INSTR_RXE_FRRD },
+	{ "kdb", 0x18, INSTR_RXE_FRRD },
+	{ "cdb", 0x19, INSTR_RXE_FRRD },
+	{ "adb", 0x1a, INSTR_RXE_FRRD },
+	{ "sdb", 0x1b, INSTR_RXE_FRRD },
+	{ "mdb", 0x1c, INSTR_RXE_FRRD },
+	{ "ddb", 0x1d, INSTR_RXE_FRRD },
+	{ "madb", 0x1e, INSTR_RXF_FRRDF },
+	{ "msdb", 0x1f, INSTR_RXF_FRRDF },
+	{ "lde", 0x24, INSTR_RXE_FRRD },
+	{ "lxd", 0x25, INSTR_RXE_FRRD },
+	{ "lxe", 0x26, INSTR_RXE_FRRD },
+	{ "mae", 0x2e, INSTR_RXF_FRRDF },
+	{ "mse", 0x2f, INSTR_RXF_FRRDF },
+	{ "sqe", 0x34, INSTR_RXE_FRRD },
+	{ "mee", 0x37, INSTR_RXE_FRRD },
+	{ "mad", 0x3e, INSTR_RXF_FRRDF },
+	{ "msd", 0x3f, INSTR_RXF_FRRDF },
+	{ "", 0, INSTR_INVALID }
+};
+
+/* Extracts an operand value from an instruction.  */
+static unsigned int extract_operand(unsigned char *code,
+				    const struct operand *operand)
+{
+	unsigned int val;
+	int bits;
+
+	/* Extract fragments of the operand byte for byte.  */
+	code += operand->shift / 8;
+	bits = (operand->shift & 7) + operand->bits;
+	val = 0;
+	do {
+		val <<= 8;
+		val |= (unsigned int) *code++;
+		bits -= 8;
+	} while (bits > 0);
+	val >>= -bits;
+	val &= ((1U << (operand->bits - 1)) << 1) - 1;
+
+	/* Check for special long displacement case.  */
+	if (operand->bits == 20 && operand->shift == 20)
+		val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
+
+	/* Sign extend value if the operand is signed or pc relative.  */
+	if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) &&
+	    (val & (1U << (operand->bits - 1))))
+		val |= (-1U << (operand->bits - 1)) << 1;
+
+	/* Double value if the operand is pc relative.	*/
+	if (operand->flags & OPERAND_PCREL)
+		val <<= 1;
+
+	/* Length x in an instructions has real length x + 1.  */
+	if (operand->flags & OPERAND_LENGTH)
+		val++;
+	return val;
+}
+
+static inline int insn_length(unsigned char code)
+{
+	return ((((int) code + 64) >> 7) + 1) << 1;
+}
+
+static struct insn *find_insn(unsigned char *code)
+{
+	unsigned char opfrag = code[1];
+	unsigned char opmask;
+	struct insn *table;
+
+	switch (code[0]) {
+	case 0x01:
+		table = opcode_01;
+		break;
+	case 0xa5:
+		table = opcode_a5;
+		break;
+	case 0xa7:
+		table = opcode_a7;
+		break;
+	case 0xb2:
+		table = opcode_b2;
+		break;
+	case 0xb3:
+		table = opcode_b3;
+		break;
+	case 0xb9:
+		table = opcode_b9;
+		break;
+	case 0xc0:
+		table = opcode_c0;
+		break;
+	case 0xc2:
+		table = opcode_c2;
+		break;
+	case 0xc8:
+		table = opcode_c8;
+		break;
+	case 0xe3:
+		table = opcode_e3;
+		opfrag = code[5];
+		break;
+	case 0xe5:
+		table = opcode_e5;
+		break;
+	case 0xeb:
+		table = opcode_eb;
+		opfrag = code[5];
+		break;
+	case 0xec:
+		table = opcode_ec;
+		opfrag = code[5];
+		break;
+	case 0xed:
+		table = opcode_ed;
+		opfrag = code[5];
+		break;
+	default:
+		table = opcode;
+		opfrag = code[0];
+		break;
+	}
+	while (table->format != INSTR_INVALID) {
+		opmask = formats[table->format][0];
+		if (table->opfrag == (opfrag & opmask))
+			return table;
+		table++;
+	}
+	return NULL;
+}
+
+static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
+{
+	struct insn *insn;
+	const unsigned char *ops;
+	const struct operand *operand;
+	unsigned int value;
+	char separator;
+	char *ptr;
+
+	ptr = buffer;
+	insn = find_insn(code);
+	if (insn) {
+		ptr += sprintf(ptr, "%.5s\t", insn->name);
+		/* Extract the operands. */
+		separator = 0;
+		for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
+			operand = operands + *ops;
+			value = extract_operand(code, operand);
+			if ((operand->flags & OPERAND_INDEX)  && value == 0)
+				continue;
+			if ((operand->flags & OPERAND_BASE) &&
+			    value == 0 && separator == '(') {
+				separator = ',';
+				continue;
+			}
+			if (separator)
+				ptr += sprintf(ptr, "%c", separator);
+			if (operand->flags & OPERAND_GPR)
+				ptr += sprintf(ptr, "%%r%i", value);
+			else if (operand->flags & OPERAND_FPR)
+				ptr += sprintf(ptr, "%%f%i", value);
+			else if (operand->flags & OPERAND_AR)
+				ptr += sprintf(ptr, "%%a%i", value);
+			else if (operand->flags & OPERAND_CR)
+				ptr += sprintf(ptr, "%%c%i", value);
+			else if (operand->flags & OPERAND_PCREL)
+				ptr += sprintf(ptr, "%lx", value + addr);
+			else if (operand->flags & OPERAND_SIGNED)
+				ptr += sprintf(ptr, "%i", value);
+			else
+				ptr += sprintf(ptr, "%u", value);
+			if (operand->flags & OPERAND_DISP)
+				separator = '(';
+			else if (operand->flags & OPERAND_BASE) {
+				ptr += sprintf(ptr, ")");
+				separator = ',';
+			} else
+				separator = ',';
+		}
+	} else
+		ptr += sprintf(ptr, "unknown");
+	return (int) (ptr - buffer);
+}
+
+void show_code(struct pt_regs *regs)
+{
+	char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+	unsigned char code[64];
+	char buffer[64], *ptr;
+	mm_segment_t old_fs;
+	unsigned long addr;
+	int start, end, opsize, hops, i;
+
+	/* Get a snapshot of the 64 bytes surrounding the fault address. */
+	old_fs = get_fs();
+	set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS);
+	for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
+		addr = regs->psw.addr - 34 + start;
+		if (__copy_from_user(code + start - 2,
+				     (char __user *) addr, 2))
+			break;
+	}
+	for (end = 32; end < 64; end += 2) {
+		addr = regs->psw.addr + end - 32;
+		if (__copy_from_user(code + end,
+				     (char __user *) addr, 2))
+			break;
+	}
+	set_fs(old_fs);
+	/* Code snapshot useable ? */
+	if ((regs->psw.addr & 1) || start >= end) {
+		printk("%s Code: Bad PSW.\n", mode);
+		return;
+	}
+	/* Find a starting point for the disassembly. */
+	while (start < 32) {
+		hops = 0;
+		for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
+			if (!find_insn(code + start + i))
+				break;
+			i += insn_length(code[start + i]);
+		}
+		if (start + i == 32)
+			/* Looks good, sequence ends at PSW. */
+			break;
+		start += 2;
+	}
+	/* Decode the instructions. */
+	ptr = buffer;
+	ptr += sprintf(ptr, "%s Code:", mode);
+	hops = 0;
+	while (start < end && hops < 8) {
+		*ptr++ = (start == 32) ? '>' : ' ';
+		addr = regs->psw.addr + start - 32;
+		ptr += sprintf(ptr, ONELONG, addr);
+		opsize = insn_length(code[start]);
+		if (start + opsize >= end)
+			break;
+		for (i = 0; i < opsize; i++)
+			ptr += sprintf(ptr, "%02x", code[start + i]);
+		*ptr++ = '\t';
+		if (i < 6)
+			*ptr++ = '\t';
+		ptr += print_insn(ptr, code + start, addr);
+		start += opsize;
+		printk(buffer);
+		ptr = buffer;
+		ptr += sprintf(ptr, "\n          ");
+		hops++;
+	}
+	printk("\n");
+}
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 5e47936..50538e5 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -253,11 +253,10 @@ #ifndef CONFIG_64BIT
 			break;
 #endif
 		/*
-		 * Finish memory detection at the first hole, unless
-		 * - we reached the hsa -> skip it.
-		 * - we know there must be more.
+		 * Finish memory detection at the first hole
+		 * if storage size is unknown.
 		 */
-		if (cc == -1UL && !memsize && old_addr != ADDR2G)
+		if (cc == -1UL && !memsize)
 			break;
 		if (memsize && addr >= memsize)
 			break;
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index dddc3de..c8a2212 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -249,8 +249,6 @@ sysc_do_restart:
 	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 ?
@@ -381,50 +379,37 @@ ret_from_fork:
 	b	BASED(sysc_return)
 
 #
-# clone, fork, vfork, exec and sigreturn need glue,
-# because they all expect pt_regs as parameter,
-# but are called with different parameter.
-# return-address is set up above
+# kernel_execve function needs to deal with pt_regs that is not
+# at the usual place
 #
-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_sigaltstack_glue:
-	la	%r4,SP_PTREGS(%r15)	# load pt_regs as parameter
-	l	%r1,BASED(.Lsigaltstack)
-	br	%r1			# branch to sys_sigreturn
+	.globl	kernel_execve
+kernel_execve:
+	stm	%r12,%r15,48(%r15)
+	lr	%r14,%r15
+	l	%r13,__LC_SVC_NEW_PSW+4
+	s	%r15,BASED(.Lc_spsize)
+	st	%r14,__SF_BACKCHAIN(%r15)
+	la	%r12,SP_PTREGS(%r15)
+	xc	0(__PT_SIZE,%r12),0(%r12)
+	l	%r1,BASED(.Ldo_execve)
+	lr	%r5,%r12
+	basr	%r14,%r1
+	ltr	%r2,%r2
+	be	BASED(0f)
+	a	%r15,BASED(.Lc_spsize)
+	lm	%r12,%r15,48(%r15)
+	br	%r14
+	# execve succeeded.
+0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
+	l	%r15,__LC_KERNEL_STACK	# load ksp
+	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
+	l	%r9,__LC_THREAD_INFO
+	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
+	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	l	%r1,BASED(.Lexecve_tail)
+	basr	%r14,%r1
+	b	BASED(sysc_return)
 
 /*
  * Program check handler routine
@@ -1031,19 +1016,11 @@ #endif
 .Ldo_extint:	.long	do_extint
 .Ldo_signal:	.long	do_signal
 .Lhandle_per:	.long	do_single_step
+.Ldo_execve:	.long	do_execve
+.Lexecve_tail:	.long	execve_tail
 .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
 #ifdef CONFIG_TRACE_IRQFLAGS
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 0f758c3..93745fd 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -244,8 +244,6 @@ #endif
 	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 ?
@@ -371,77 +369,35 @@ ret_from_fork:
 	j	sysc_return
 
 #
-# clone, fork, vfork, exec and sigreturn need glue,
-# because they all expect pt_regs as parameter,
-# but are called with different parameter.
-# return-address is set up above
+# kernel_execve function needs to deal with pt_regs that is not
+# at the usual place
 #
-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
-#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
-#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
-#endif
-
-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
-#endif
-
-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
-#endif
-
-sys_sigaltstack_glue:
-	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
-#endif
+	.globl	kernel_execve
+kernel_execve:
+	stmg	%r12,%r15,96(%r15)
+	lgr	%r14,%r15
+	aghi	%r15,-SP_SIZE
+	stg	%r14,__SF_BACKCHAIN(%r15)
+	la	%r12,SP_PTREGS(%r15)
+	xc	0(__PT_SIZE,%r12),0(%r12)
+	lgr	%r5,%r12
+	brasl	%r14,do_execve
+	ltgfr	%r2,%r2
+	je	0f
+	aghi	%r15,SP_SIZE
+	lmg	%r12,%r15,96(%r15)
+	br	%r14
+	# execve succeeded.
+0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
+	lg	%r15,__LC_KERNEL_STACK	# load ksp
+	aghi	%r15,-SP_SIZE		# make room for registers & psw
+	lg	%r13,__LC_SVC_NEW_PSW+8
+	lg	%r9,__LC_THREAD_INFO
+	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
+	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	brasl	%r14,execve_tail
+	j	sysc_return
 
 /*
  * Program check handler routine
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 3701070..a87b197 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -39,7 +39,69 @@ startup_continue:
 	basr	%r13,0			# get base
 .LPG1:	sll	%r13,1			# remove high order bit
 	srl	%r13,1
-	lhi	%r1,1			# mode 1 = esame
+
+#ifdef CONFIG_ZFCPDUMP
+
+	# check if we have been ipled using zfcp dump:
+
+	tm	0xb9,0x01		# test if subchannel is enabled
+	jno	.nodump			# subchannel disabled
+	l	%r1,0xb8
+	la	%r5,.Lipl_schib-.LPG1(%r13)
+	stsch	0(%r5)			# get schib of subchannel
+	jne	.nodump			# schib not available
+	tm	5(%r5),0x01		# devno valid?
+	jno	.nodump
+	tm	4(%r5),0x80		# qdio capable device?
+	jno	.nodump
+	l	%r2,20(%r0)		# address of ipl parameter block
+	lhi	%r3,0
+	ic	%r3,0x148(%r2)		# get opt field
+	chi	%r3,0x20		# load with dump?
+	jne	.nodump
+
+	# store all prefix registers in case of load with dump:
+
+	la	%r7,0			# base register for 0 page
+	la	%r8,0			# first cpu
+	l	%r11,.Lpref_arr_ptr-.LPG1(%r13)	# address of prefix array
+	ahi	%r11,4			# skip boot cpu
+	lr	%r12,%r11
+	ahi	%r12,(CONFIG_NR_CPUS*4)	# end of prefix array
+	stap	.Lcurrent_cpu+2-.LPG1(%r13)	# store current cpu addr
+1:
+	cl	%r8,.Lcurrent_cpu-.LPG1(%r13)	# is ipl cpu ?
+	je	4f				# if yes get next cpu
+2:
+	lr	%r9,%r7
+	sigp	%r9,%r8,0x9		# stop & store status of cpu
+	brc	8,3f			# accepted
+	brc	4,4f			# status stored: next cpu
+	brc	2,2b			# busy: 	 try again
+	brc	1,4f			# not op:	 next cpu
+3:
+	mvc	0(4,%r11),264(%r7)	# copy prefix register to prefix array
+	ahi	%r11,4			# next element in prefix array
+	clr	%r11,%r12
+	je	5f			# no more space in prefix array
+4:
+	ahi	%r8,1				# next cpu (r8 += 1)
+	cl	%r8,.Llast_cpu-.LPG1(%r13)	# is last possible cpu ?
+	jl	1b				# jump if not last cpu
+5:
+	lhi	%r1,2			# mode 2 = esame (dump)
+	j	6f
+	.align 4
+.Lipl_schib:
+	.rept 13
+	.long 0
+	.endr
+.nodump:
+	lhi	%r1,1			# mode 1 = esame (normal ipl)
+6:
+#else
+	lhi	%r1,1			# mode 1 = esame (normal ipl)
+#endif /* CONFIG_ZFCPDUMP */
 	mvi	__LC_AR_MODE_ID,1	# set esame flag
 	slr	%r0,%r0 		# set cpuid to zero
 	sigp	%r1,%r0,0x12		# switch to esame mode
@@ -149,6 +211,14 @@ #
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad	0x80000000 + 0x20000 - 8	# 2GB + 128K - 8
 .Lnop:	.long	0x07000700
+#ifdef CONFIG_ZFCPDUMP
+.Lcurrent_cpu:
+	.long 0x0
+.Llast_cpu:
+	.long 0x0000ffff
+.Lpref_arr_ptr:
+	.long zfcpdump_prefix_array
+#endif /* CONFIG_ZFCPDUMP */
 .Lparmaddr:
 	.quad	PARMAREA
 	.align	64
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index f731185..0ea048d 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -29,36 +29,21 @@ #define SCCB_VALID (s390_readinfo_sccb.h
 #define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
 #define SCCB_FLAG (s390_readinfo_sccb.flags)
 
-enum ipl_type {
-	IPL_TYPE_NONE	 = 1,
-	IPL_TYPE_UNKNOWN = 2,
-	IPL_TYPE_CCW	 = 4,
-	IPL_TYPE_FCP	 = 8,
-	IPL_TYPE_NSS	 = 16,
-};
-
-#define IPL_NONE_STR	 "none"
-#define IPL_UNKNOWN_STR  "unknown"
-#define IPL_CCW_STR	 "ccw"
-#define IPL_FCP_STR	 "fcp"
-#define IPL_NSS_STR	 "nss"
-
-/*
- * Must be in data section since the bss section
- * is not cleared when these are accessed.
- */
-u16 ipl_devno __attribute__((__section__(".data"))) = 0;
-u32 ipl_flags __attribute__((__section__(".data"))) = 0;
+#define IPL_UNKNOWN_STR		"unknown"
+#define IPL_CCW_STR		"ccw"
+#define IPL_FCP_STR		"fcp"
+#define IPL_FCP_DUMP_STR	"fcp_dump"
+#define IPL_NSS_STR		"nss"
 
 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_FCP_DUMP:
+		return IPL_FCP_DUMP_STR;
 	case IPL_TYPE_NSS:
 		return IPL_NSS_STR;
 	case IPL_TYPE_UNKNOWN:
@@ -67,15 +52,55 @@ static char *ipl_type_str(enum ipl_type 
 	}
 }
 
+enum dump_type {
+	DUMP_TYPE_NONE	= 1,
+	DUMP_TYPE_CCW	= 2,
+	DUMP_TYPE_FCP	= 4,
+};
+
+#define DUMP_NONE_STR	 "none"
+#define DUMP_CCW_STR	 "ccw"
+#define DUMP_FCP_STR	 "fcp"
+
+static char *dump_type_str(enum dump_type type)
+{
+	switch (type) {
+	case DUMP_TYPE_NONE:
+		return DUMP_NONE_STR;
+	case DUMP_TYPE_CCW:
+		return DUMP_CCW_STR;
+	case DUMP_TYPE_FCP:
+		return DUMP_FCP_STR;
+	default:
+		return NULL;
+	}
+}
+
+/*
+ * Must be in data section since the bss section
+ * is not cleared when these are accessed.
+ */
+static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
+u32 ipl_flags __attribute__((__section__(".data"))) = 0;
+
 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,
-	IPL_METHOD_NSS,
+	REIPL_METHOD_CCW_CIO,
+	REIPL_METHOD_CCW_DIAG,
+	REIPL_METHOD_CCW_VM,
+	REIPL_METHOD_FCP_RO_DIAG,
+	REIPL_METHOD_FCP_RW_DIAG,
+	REIPL_METHOD_FCP_RO_VM,
+	REIPL_METHOD_FCP_DUMP,
+	REIPL_METHOD_NSS,
+	REIPL_METHOD_DEFAULT,
+};
+
+enum dump_method {
+	DUMP_METHOD_NONE,
+	DUMP_METHOD_CCW_CIO,
+	DUMP_METHOD_CCW_DIAG,
+	DUMP_METHOD_CCW_VM,
+	DUMP_METHOD_FCP_DIAG,
 };
 
 enum shutdown_action {
@@ -107,15 +132,15 @@ 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 enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
 
 static char reipl_nss_name[NSS_NAME_SIZE + 1];
 
-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 int dump_capabilities = DUMP_TYPE_NONE;
+static enum dump_type dump_type = DUMP_TYPE_NONE;
+static enum dump_method dump_method = DUMP_METHOD_NONE;
 static struct ipl_parameter_block *dump_block_fcp;
 static struct ipl_parameter_block *dump_block_ccw;
 
@@ -134,11 +159,12 @@ int diag308(unsigned long subcode, void 
 		: "d" (subcode) : "cc", "memory");
 	return _rc;
 }
+EXPORT_SYMBOL_GPL(diag308);
 
 /* SYSFS */
 
 #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value)		\
-static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys,	\
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
 		char *page)						\
 {									\
 	return sprintf(page, _format, _value);				\
@@ -147,13 +173,13 @@ static struct subsys_attribute sys_##_pr
 	__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,	\
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
 		char *page)						\
 {									\
 	return sprintf(page, _fmt_out,					\
 			(unsigned long long) _value);			\
 }									\
-static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
 		const char *buf, size_t len)				\
 {									\
 	unsigned long long value;					\
@@ -168,12 +194,12 @@ static struct subsys_attribute sys_##_pr
 			sys_##_prefix##_##_name##_store);
 
 #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
-static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys,	\
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset,	\
 		char *page)						\
 {									\
 	return sprintf(page, _fmt_out, _value);				\
 }									\
-static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset,	\
 		const char *buf, size_t len)				\
 {									\
 	if (sscanf(buf, _fmt_in, _value) != 1)				\
@@ -197,7 +223,7 @@ static void make_attrs_ro(struct attribu
  * ipl section
  */
 
-static enum ipl_type ipl_get_type(void)
+static __init enum ipl_type get_ipl_type(void)
 {
 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
@@ -211,24 +237,57 @@ static enum ipl_type ipl_get_type(void)
 		return IPL_TYPE_UNKNOWN;
 	if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
 		return IPL_TYPE_UNKNOWN;
+	if (ipl->ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP)
+		return IPL_TYPE_FCP_DUMP;
 	return IPL_TYPE_FCP;
 }
 
-static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
+void __init setup_ipl_info(void)
+{
+	ipl_info.type = get_ipl_type();
+	switch (ipl_info.type) {
+	case IPL_TYPE_CCW:
+		ipl_info.data.ccw.dev_id.devno = ipl_devno;
+		ipl_info.data.ccw.dev_id.ssid = 0;
+		break;
+	case IPL_TYPE_FCP:
+	case IPL_TYPE_FCP_DUMP:
+		ipl_info.data.fcp.dev_id.devno =
+			IPL_PARMBLOCK_START->ipl_info.fcp.devno;
+		ipl_info.data.fcp.dev_id.ssid = 0;
+		ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
+		ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
+		break;
+	case IPL_TYPE_NSS:
+		strncpy(ipl_info.data.nss.name, kernel_nss_name,
+			sizeof(ipl_info.data.nss.name));
+		break;
+	case IPL_TYPE_UNKNOWN:
+	default:
+		/* We have no info to copy */
+		break;
+	}
+}
+
+struct ipl_info ipl_info;
+EXPORT_SYMBOL_GPL(ipl_info);
+
+static ssize_t ipl_type_show(struct kset *kset, char *page)
 {
-	return sprintf(page, "%s\n", ipl_type_str(ipl_get_type()));
+	return sprintf(page, "%s\n", ipl_type_str(ipl_info.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)
+static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
 {
 	struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
-	switch (ipl_get_type()) {
+	switch (ipl_info.type) {
 	case IPL_TYPE_CCW:
 		return sprintf(page, "0.0.%04x\n", ipl_devno);
 	case IPL_TYPE_FCP:
+	case IPL_TYPE_FCP_DUMP:
 		return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
 	default:
 		return 0;
@@ -312,7 +371,7 @@ static struct attribute_group ipl_fcp_at
 
 /* CCW ipl device attributes */
 
-static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
+static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
 {
 	char loadparm[LOADPARM_LEN + 1] = {};
 
@@ -410,7 +469,7 @@ static void reipl_get_ascii_loadparm(cha
 	strstrip(loadparm);
 }
 
-static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
+static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
 {
 	char buf[LOADPARM_LEN + 1];
 
@@ -418,7 +477,7 @@ static ssize_t reipl_ccw_loadparm_show(s
 	return sprintf(page, "%s\n", buf);
 }
 
-static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
+static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
 					const char *buf, size_t len)
 {
 	int i, lp_len;
@@ -485,34 +544,40 @@ static int reipl_set_type(enum ipl_type 
 	switch(type) {
 	case IPL_TYPE_CCW:
 		if (MACHINE_IS_VM)
-			reipl_method = IPL_METHOD_CCW_VM;
+			reipl_method = REIPL_METHOD_CCW_VM;
 		else
-			reipl_method = IPL_METHOD_CCW_CIO;
+			reipl_method = REIPL_METHOD_CCW_CIO;
 		break;
 	case IPL_TYPE_FCP:
 		if (diag308_set_works)
-			reipl_method = IPL_METHOD_FCP_RW_DIAG;
+			reipl_method = REIPL_METHOD_FCP_RW_DIAG;
 		else if (MACHINE_IS_VM)
-			reipl_method = IPL_METHOD_FCP_RO_VM;
+			reipl_method = REIPL_METHOD_FCP_RO_VM;
 		else
-			reipl_method = IPL_METHOD_FCP_RO_DIAG;
+			reipl_method = REIPL_METHOD_FCP_RO_DIAG;
+		break;
+	case IPL_TYPE_FCP_DUMP:
+		reipl_method = REIPL_METHOD_FCP_DUMP;
 		break;
 	case IPL_TYPE_NSS:
-		reipl_method = IPL_METHOD_NSS;
+		reipl_method = REIPL_METHOD_NSS;
+		break;
+	case IPL_TYPE_UNKNOWN:
+		reipl_method = REIPL_METHOD_DEFAULT;
 		break;
 	default:
-		reipl_method = IPL_METHOD_NONE;
+		BUG();
 	}
 	reipl_type = type;
 	return 0;
 }
 
-static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
+static ssize_t reipl_type_show(struct kset *kset, char *page)
 {
 	return sprintf(page, "%s\n", ipl_type_str(reipl_type));
 }
 
-static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
+static ssize_t reipl_type_store(struct kset *kset, const char *buf,
 				size_t len)
 {
 	int rc = -EINVAL;
@@ -579,43 +644,43 @@ static struct attribute_group dump_ccw_a
 
 /* dump type */
 
-static int dump_set_type(enum ipl_type type)
+static int dump_set_type(enum dump_type type)
 {
 	if (!(dump_capabilities & type))
 		return -EINVAL;
 	switch(type) {
-	case IPL_TYPE_CCW:
+	case DUMP_TYPE_CCW:
 		if (MACHINE_IS_VM)
-			dump_method = IPL_METHOD_CCW_VM;
+			dump_method = DUMP_METHOD_CCW_VM;
 		else
-			dump_method = IPL_METHOD_CCW_CIO;
+			dump_method = DUMP_METHOD_CCW_CIO;
 		break;
-	case IPL_TYPE_FCP:
-		dump_method = IPL_METHOD_FCP_RW_DIAG;
+	case DUMP_TYPE_FCP:
+		dump_method = DUMP_METHOD_FCP_DIAG;
 		break;
 	default:
-		dump_method = IPL_METHOD_NONE;
+		dump_method = DUMP_METHOD_NONE;
 	}
 	dump_type = type;
 	return 0;
 }
 
-static ssize_t dump_type_show(struct subsystem *subsys, char *page)
+static ssize_t dump_type_show(struct kset *kset, char *page)
 {
-	return sprintf(page, "%s\n", ipl_type_str(dump_type));
+	return sprintf(page, "%s\n", dump_type_str(dump_type));
 }
 
-static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
+static ssize_t dump_type_store(struct kset *kset, 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);
+	if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
+		rc = dump_set_type(DUMP_TYPE_NONE);
+	else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
+		rc = dump_set_type(DUMP_TYPE_CCW);
+	else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
+		rc = dump_set_type(DUMP_TYPE_FCP);
 	return (rc != 0) ? rc : len;
 }
 
@@ -632,12 +697,12 @@ static decl_subsys(shutdown_actions, NUL
 
 /* on panic */
 
-static ssize_t on_panic_show(struct subsystem *subsys, char *page)
+static ssize_t on_panic_show(struct kset *kset, 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,
+static ssize_t on_panic_store(struct kset *kset, const char *buf,
 			      size_t len)
 {
 	if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
@@ -664,14 +729,14 @@ void do_reipl(void)
 	char loadparm[LOADPARM_LEN + 1];
 
 	switch (reipl_method) {
-	case IPL_METHOD_CCW_CIO:
+	case REIPL_METHOD_CCW_CIO:
 		devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
-		if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno)
+		if (ipl_info.type == IPL_TYPE_CCW && devid.devno == ipl_devno)
 			diag308(DIAG308_IPL, NULL);
 		devid.ssid  = 0;
 		reipl_ccw_dev(&devid);
 		break;
-	case IPL_METHOD_CCW_VM:
+	case REIPL_METHOD_CCW_VM:
 		reipl_get_ascii_loadparm(loadparm);
 		if (strlen(loadparm) == 0)
 			sprintf(buf, "IPL %X",
@@ -681,30 +746,32 @@ void do_reipl(void)
 				reipl_block_ccw->ipl_info.ccw.devno, loadparm);
 		__cpcmd(buf, NULL, 0, NULL);
 		break;
-	case IPL_METHOD_CCW_DIAG:
+	case REIPL_METHOD_CCW_DIAG:
 		diag308(DIAG308_SET, reipl_block_ccw);
 		diag308(DIAG308_IPL, NULL);
 		break;
-	case IPL_METHOD_FCP_RW_DIAG:
+	case REIPL_METHOD_FCP_RW_DIAG:
 		diag308(DIAG308_SET, reipl_block_fcp);
 		diag308(DIAG308_IPL, NULL);
 		break;
-	case IPL_METHOD_FCP_RO_DIAG:
+	case REIPL_METHOD_FCP_RO_DIAG:
 		diag308(DIAG308_IPL, NULL);
 		break;
-	case IPL_METHOD_FCP_RO_VM:
+	case REIPL_METHOD_FCP_RO_VM:
 		__cpcmd("IPL", NULL, 0, NULL);
 		break;
-	case IPL_METHOD_NSS:
+	case REIPL_METHOD_NSS:
 		sprintf(buf, "IPL %s", reipl_nss_name);
 		__cpcmd(buf, NULL, 0, NULL);
 		break;
-	case IPL_METHOD_NONE:
-	default:
+	case REIPL_METHOD_DEFAULT:
 		if (MACHINE_IS_VM)
 			__cpcmd("IPL", NULL, 0, NULL);
 		diag308(DIAG308_IPL, NULL);
 		break;
+	case REIPL_METHOD_FCP_DUMP:
+	default:
+		break;
 	}
 	signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
@@ -715,28 +782,28 @@ static void do_dump(void)
 	static char buf[100];
 
 	switch (dump_method) {
-	case IPL_METHOD_CCW_CIO:
+	case DUMP_METHOD_CCW_CIO:
 		smp_send_stop();
 		devid.devno = dump_block_ccw->ipl_info.ccw.devno;
 		devid.ssid  = 0;
 		reipl_ccw_dev(&devid);
 		break;
-	case IPL_METHOD_CCW_VM:
+	case DUMP_METHOD_CCW_VM:
 		smp_send_stop();
 		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:
+	case DUMP_METHOD_CCW_DIAG:
 		diag308(DIAG308_SET, dump_block_ccw);
 		diag308(DIAG308_DUMP, NULL);
 		break;
-	case IPL_METHOD_FCP_RW_DIAG:
+	case DUMP_METHOD_FCP_DIAG:
 		diag308(DIAG308_SET, dump_block_fcp);
 		diag308(DIAG308_DUMP, NULL);
 		break;
-	case IPL_METHOD_NONE:
+	case DUMP_METHOD_NONE:
 	default:
 		return;
 	}
@@ -777,12 +844,13 @@ static int __init ipl_init(void)
 	rc = firmware_register(&ipl_subsys);
 	if (rc)
 		return rc;
-	switch (ipl_get_type()) {
+	switch (ipl_info.type) {
 	case IPL_TYPE_CCW:
 		rc = sysfs_create_group(&ipl_subsys.kset.kobj,
 					&ipl_ccw_attr_group);
 		break;
 	case IPL_TYPE_FCP:
+	case IPL_TYPE_FCP_DUMP:
 		rc = ipl_register_fcp_files();
 		break;
 	case IPL_TYPE_NSS:
@@ -852,7 +920,7 @@ static int __init reipl_ccw_init(void)
 	/* FIXME: check for diag308_set_works when enabling diag ccw reipl */
 	if (!MACHINE_IS_VM)
 		sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
-	if (ipl_get_type() == IPL_TYPE_CCW)
+	if (ipl_info.type == IPL_TYPE_CCW)
 		reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
 	reipl_capabilities |= IPL_TYPE_CCW;
 	return 0;
@@ -862,9 +930,9 @@ static int __init reipl_fcp_init(void)
 {
 	int rc;
 
-	if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP))
+	if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP))
 		return 0;
-	if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP))
+	if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP))
 		make_attrs_ro(reipl_fcp_attrs);
 
 	reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
@@ -875,7 +943,7 @@ static int __init reipl_fcp_init(void)
 		free_page((unsigned long)reipl_block_fcp);
 		return rc;
 	}
-	if (ipl_get_type() == IPL_TYPE_FCP) {
+	if (ipl_info.type == IPL_TYPE_FCP) {
 		memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
 	} else {
 		reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
@@ -909,7 +977,7 @@ static int __init reipl_init(void)
 	rc = reipl_nss_init();
 	if (rc)
 		return rc;
-	rc = reipl_set_type(ipl_get_type());
+	rc = reipl_set_type(ipl_info.type);
 	if (rc)
 		return rc;
 	return 0;
@@ -931,7 +999,7 @@ static int __init dump_ccw_init(void)
 	dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
 	dump_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
 	dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
-	dump_capabilities |= IPL_TYPE_CCW;
+	dump_capabilities |= DUMP_TYPE_CCW;
 	return 0;
 }
 
@@ -956,7 +1024,7 @@ static int __init dump_fcp_init(void)
 	dump_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
 	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;
+	dump_capabilities |= DUMP_TYPE_FCP;
 	return 0;
 }
 
@@ -995,7 +1063,7 @@ static int __init dump_init(void)
 	rc = dump_fcp_init();
 	if (rc)
 		return rc;
-	dump_set_type(IPL_TYPE_NONE);
+	dump_set_type(DUMP_TYPE_NONE);
 	return 0;
 }
 
@@ -1038,6 +1106,27 @@ static int __init s390_ipl_init(void)
 
 __initcall(s390_ipl_init);
 
+void __init ipl_save_parameters(void)
+{
+	struct cio_iplinfo iplinfo;
+	unsigned int *ipl_ptr;
+	void *src, *dst;
+
+	if (cio_get_iplinfo(&iplinfo))
+		return;
+
+	ipl_devno = iplinfo.devno;
+	ipl_flags |= IPL_DEVNO_VALID;
+	if (!iplinfo.is_qdio)
+		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;
+}
+
 static LIST_HEAD(rcall);
 static DEFINE_MUTEX(rcall_mutex);
 
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 993f353..e39333a 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -24,8 +24,8 @@ #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
 #include <linux/stop_machine.h>
+#include <linux/kdebug.h>
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
 #include <asm/sections.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
@@ -271,23 +271,13 @@ static void __kprobes set_current_kprobe
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 					struct pt_regs *regs)
 {
-	struct kretprobe_instance *ri;
+	ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
 
-	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++;
-	}
+	/* Replace the return addr with trampoline addr */
+	regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
 }
 
 static int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -516,7 +506,7 @@ out:
 	return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -603,7 +593,6 @@ int __kprobes kprobe_exceptions_notify(s
 			ret = NOTIFY_STOP;
 		break;
 	case DIE_TRAP:
-	case DIE_PAGE_FAULT:
 		/* kprobe_running() needs smp_processor_id() */
 		preempt_disable();
 		if (kprobe_running() &&
@@ -672,3 +661,10 @@ int __init arch_init_kprobes(void)
 {
 	return register_kprobe(&trampoline_p);
 }
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)
+		return 1;
+	return 0;
+}
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 39d1dd7..59b4e79 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -31,6 +31,7 @@ #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/moduleloader.h>
+#include <linux/bug.h>
 
 #if 0
 #define DEBUGP printk
@@ -398,9 +399,10 @@ int module_finalize(const Elf_Ehdr *hdr,
 		    struct module *me)
 {
 	vfree(me->arch.syminfo);
-	return 0;
+	return module_bug_finalize(hdr, sechdrs, me);
 }
 
 void module_arch_cleanup(struct module *mod)
 {
+	module_bug_cleanup(mod);
 }
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 5acfac6..eb43c3b 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -22,7 +22,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -280,24 +279,26 @@ #endif /* CONFIG_64BIT */
         return 0;
 }
 
-asmlinkage long sys_fork(struct pt_regs regs)
+asmlinkage long sys_fork(void)
 {
-	return do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL, NULL);
+	struct pt_regs *regs = task_pt_regs(current);
+	return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL);
 }
 
-asmlinkage long sys_clone(struct pt_regs regs)
+asmlinkage long sys_clone(void)
 {
-        unsigned long clone_flags;
-        unsigned long newsp;
+	struct pt_regs *regs = task_pt_regs(current);
+	unsigned long clone_flags;
+	unsigned long newsp;
 	int __user *parent_tidptr, *child_tidptr;
 
-        clone_flags = regs.gprs[3];
-        newsp = regs.orig_gpr2;
-	parent_tidptr = (int __user *) regs.gprs[4];
-	child_tidptr = (int __user *) regs.gprs[5];
-        if (!newsp)
-                newsp = regs.gprs[15];
-        return do_fork(clone_flags, newsp, &regs, 0,
+	clone_flags = regs->gprs[3];
+	newsp = regs->orig_gpr2;
+	parent_tidptr = (int __user *) regs->gprs[4];
+	child_tidptr = (int __user *) regs->gprs[5];
+	if (!newsp)
+		newsp = regs->gprs[15];
+	return do_fork(clone_flags, newsp, regs, 0,
 		       parent_tidptr, child_tidptr);
 }
 
@@ -311,40 +312,52 @@ asmlinkage long sys_clone(struct pt_regs
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage long sys_vfork(struct pt_regs regs)
+asmlinkage long sys_vfork(void)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
-		       regs.gprs[15], &regs, 0, NULL, NULL);
+		       regs->gprs[15], regs, 0, NULL, NULL);
+}
+
+asmlinkage void execve_tail(void)
+{
+	task_lock(current);
+	current->ptrace &= ~PT_DTRACE;
+	task_unlock(current);
+	current->thread.fp_regs.fpc = 0;
+	if (MACHINE_HAS_IEEE)
+		asm volatile("sfpc %0,%0" : : "d" (0));
 }
 
 /*
  * sys_execve() executes a new program.
  */
-asmlinkage long sys_execve(struct pt_regs regs)
+asmlinkage long sys_execve(void)
 {
-        int error;
-        char * filename;
-
-        filename = getname((char __user *) regs.orig_gpr2);
-        error = PTR_ERR(filename);
-        if (IS_ERR(filename))
-                goto out;
-        error = do_execve(filename, (char __user * __user *) regs.gprs[3],
-			  (char __user * __user *) regs.gprs[4], &regs);
-	if (error == 0) {
-		task_lock(current);
-		current->ptrace &= ~PT_DTRACE;
-		task_unlock(current);
-		current->thread.fp_regs.fpc = 0;
-		if (MACHINE_HAS_IEEE)
-			asm volatile("sfpc %0,%0" : : "d" (0));
+	struct pt_regs *regs = task_pt_regs(current);
+	char *filename;
+	unsigned long result;
+	int rc;
+
+	filename = getname((char __user *) regs->orig_gpr2);
+	if (IS_ERR(filename)) {
+		result = PTR_ERR(filename);
+		goto out;
 	}
-        putname(filename);
+	rc = do_execve(filename, (char __user * __user *) regs->gprs[3],
+		       (char __user * __user *) regs->gprs[4], regs);
+	if (rc) {
+		result = rc;
+		goto out_putname;
+	}
+	execve_tail();
+	result = regs->gprs[2];
+out_putname:
+	putname(filename);
 out:
-        return error;
+	return result;
 }
 
-
 /*
  * fill in the FPU structure for a core dump.
  */
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 863c8d0..6bfb088 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -65,7 +65,7 @@ long psw_user_bits	= (PSW_BASE_BITS | PS
  * User copy operations.
  */
 struct uaccess_ops uaccess;
-EXPORT_SYMBOL_GPL(uaccess);
+EXPORT_SYMBOL(uaccess);
 
 /*
  * Machine setup..
@@ -74,6 +74,8 @@ unsigned int console_mode = 0;
 unsigned int console_devno = -1;
 unsigned int console_irq = -1;
 unsigned long machine_flags = 0;
+unsigned long elf_hwcap = 0;
+char elf_platform[ELF_PLATFORM_SIZE];
 
 struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
@@ -285,6 +287,26 @@ #endif
 	}
 }
 
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+static void __init setup_zfcpdump(unsigned int console_devno)
+{
+	static char str[64];
+
+	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+		return;
+	if (console_devno != -1)
+		sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x",
+			ipl_info.data.fcp.dev_id.devno, console_devno);
+	else
+		sprintf(str, "cio_ignore=all,!0.0.%04x",
+			ipl_info.data.fcp.dev_id.devno);
+	strcat(COMMAND_LINE, str);
+	console_loglevel = 2;
+}
+#else
+static inline void setup_zfcpdump(unsigned int console_devno) {}
+#endif /* CONFIG_ZFCPDUMP */
+
 #ifdef CONFIG_SMP
 void (*_machine_restart)(char *command) = machine_restart_smp;
 void (*_machine_halt)(void) = machine_halt_smp;
@@ -586,13 +608,20 @@ setup_resources(void)
 	}
 }
 
+unsigned long real_memory_size;
+EXPORT_SYMBOL_GPL(real_memory_size);
+
 static void __init setup_memory_end(void)
 {
-	unsigned long real_size, memory_size;
+	unsigned long memory_size;
 	unsigned long max_mem, max_phys;
 	int i;
 
-	memory_size = real_size = 0;
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+	if (ipl_info.type == IPL_TYPE_FCP_DUMP)
+		memory_end = ZFCPDUMP_HSA_SIZE;
+#endif
+	memory_size = 0;
 	max_phys = VMALLOC_END_INIT - VMALLOC_MIN_SIZE;
 	memory_end &= PAGE_MASK;
 
@@ -601,7 +630,8 @@ static void __init setup_memory_end(void
 	for (i = 0; i < MEMORY_CHUNKS; i++) {
 		struct mem_chunk *chunk = &memory_chunk[i];
 
-		real_size = max(real_size, chunk->addr + chunk->size);
+		real_memory_size = max(real_memory_size,
+				       chunk->addr + chunk->size);
 		if (chunk->addr >= max_mem) {
 			memset(chunk, 0, sizeof(*chunk));
 			continue;
@@ -721,6 +751,98 @@ #ifdef CONFIG_BLK_DEV_INITRD
 #endif
 }
 
+static __init unsigned int stfl(void)
+{
+	asm volatile(
+		"	.insn	s,0xb2b10000,0(0)\n" /* stfl */
+		"0:\n"
+		EX_TABLE(0b,0b));
+	return S390_lowcore.stfl_fac_list;
+}
+
+static __init int stfle(unsigned long long *list, int doublewords)
+{
+	typedef struct { unsigned long long _[doublewords]; } addrtype;
+	register unsigned long __nr asm("0") = doublewords - 1;
+
+	asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+		     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
+	return __nr + 1;
+}
+
+/*
+ * Setup hardware capabilities.
+ */
+static void __init setup_hwcaps(void)
+{
+	static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
+	struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+	unsigned long long facility_list_extended;
+	unsigned int facility_list;
+	int i;
+
+	facility_list = stfl();
+	/*
+	 * The store facility list bits numbers as found in the principles
+	 * of operation are numbered with bit 1UL<<31 as number 0 to
+	 * bit 1UL<<0 as number 31.
+	 *   Bit 0: instructions named N3, "backported" to esa-mode
+	 *   Bit 2: z/Architecture mode is active
+	 *   Bit 7: the store-facility-list-extended facility is installed
+	 *   Bit 17: the message-security assist is installed
+	 *   Bit 19: the long-displacement facility is installed
+	 *   Bit 21: the extended-immediate facility is installed
+	 * These get translated to:
+	 *   HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1,
+	 *   HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3,
+	 *   HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5.
+	 */
+	for (i = 0; i < 6; i++)
+		if (facility_list & (1UL << (31 - stfl_bits[i])))
+			elf_hwcap |= 1UL << i;
+
+	/*
+	 * Check for additional facilities with store-facility-list-extended.
+	 * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0
+	 * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information
+	 * as stored by stfl, bits 32-xxx contain additional facilities.
+	 * How many facility words are stored depends on the number of
+	 * doublewords passed to the instruction. The additional facilites
+	 * are:
+	 *   Bit 43: decimal floating point facility is installed
+	 * translated to:
+	 *   HWCAP_S390_DFP bit 6.
+	 */
+	if ((elf_hwcap & (1UL << 2)) &&
+	    stfle(&facility_list_extended, 1) > 0) {
+		if (facility_list_extended & (1ULL << (64 - 43)))
+			elf_hwcap |= 1UL << 6;
+	}
+
+	switch (cpuinfo->cpu_id.machine) {
+	case 0x9672:
+#if !defined(CONFIG_64BIT)
+	default:	/* Use "g5" as default for 31 bit kernels. */
+#endif
+		strcpy(elf_platform, "g5");
+		break;
+	case 0x2064:
+	case 0x2066:
+#if defined(CONFIG_64BIT)
+	default:	/* Use "z900" as default for 64 bit kernels. */
+#endif
+		strcpy(elf_platform, "z900");
+		break;
+	case 0x2084:
+	case 0x2086:
+		strcpy(elf_platform, "z990");
+		break;
+	case 0x2094:
+		strcpy(elf_platform, "z9-109");
+		break;
+	}
+}
+
 /*
  * Setup function called from init/main.c just after the banner
  * was printed.
@@ -765,6 +887,7 @@ #endif /* CONFIG_64BIT */
 
 	parse_early_param();
 
+	setup_ipl_info();
 	setup_memory_end();
 	setup_addressing_mode();
 	setup_memory();
@@ -776,12 +899,20 @@ #endif /* CONFIG_64BIT */
 	smp_setup_cpu_possible_map();
 
 	/*
+	 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
+	 */
+	setup_hwcaps();
+
+	/*
 	 * Create kernel page tables and switch to virtual addressing.
 	 */
         paging_init();
 
         /* Setup default console */
 	conmode_default();
+
+	/* Setup zfcpdump support */
+	setup_zfcpdump(console_devno);
 }
 
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
@@ -807,8 +938,12 @@ #endif
 
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
+	static const char *hwcap_str[7] = {
+		"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp"
+	};
         struct cpuinfo_S390 *cpuinfo;
 	unsigned long n = (unsigned long) v - 1;
+	int i;
 
 	s390_adjust_jiffies();
 	preempt_disable();
@@ -818,7 +953,13 @@ static int show_cpuinfo(struct seq_file 
 			       "bogomips per cpu: %lu.%02lu\n",
 			       num_online_cpus(), loops_per_jiffy/(500000/HZ),
 			       (loops_per_jiffy/(5000/HZ))%100);
+		seq_puts(m, "features\t: ");
+		for (i = 0; i < 7; i++)
+			if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
+				seq_printf(m, "%s ", hwcap_str[i]);
+		seq_puts(m, "\n");
 	}
+
 	if (cpu_online(n)) {
 #ifdef CONFIG_SMP
 		if (smp_processor_id() == n)
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 554f9cf..d264671 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -102,9 +101,9 @@ sys_sigaction(int sig, const struct old_
 }
 
 asmlinkage long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
-					struct pt_regs *regs)
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	return do_sigaltstack(uss, uoss, regs->gprs[15]);
 }
 
@@ -163,8 +162,9 @@ static int restore_sigregs(struct pt_reg
 	return 0;
 }
 
-asmlinkage long sys_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_sigreturn(void)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	sigframe __user *frame = (sigframe __user *)regs->gprs[15];
 	sigset_t set;
 
@@ -189,8 +189,9 @@ badframe:
 	return 0;
 }
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+asmlinkage long sys_rt_sigreturn(void)
 {
+	struct pt_regs *regs = task_pt_regs(current);
 	rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
 	sigset_t set;
 
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 97764f7..b797702 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -1,12 +1,12 @@
 /*
  *  arch/s390/kernel/smp.c
  *
- *    Copyright (C) IBM Corp. 1999,2006
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
- *               Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Heiko Carstens (heiko.carstens@de.ibm.com)
+ *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *		 Heiko Carstens (heiko.carstens@de.ibm.com)
  *
- *  based on other smp stuff by 
+ *  based on other smp stuff by
  *    (c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
  *    (c) 1998 Ingo Molnar
  *
@@ -25,12 +25,12 @@ #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
 #include <linux/timex.h>
+#include <linux/bootmem.h>
 #include <asm/ipl.h>
 #include <asm/setup.h>
 #include <asm/sigp.h>
@@ -40,17 +40,19 @@ #include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
 #include <asm/timer.h>
-
-extern volatile int __cpu_logical_map[];
+#include <asm/lowcore.h>
 
 /*
  * An array with a pointer the lowcore of every CPU.
  */
-
 struct _lowcore *lowcore_ptr[NR_CPUS];
+EXPORT_SYMBOL(lowcore_ptr);
 
 cpumask_t cpu_online_map = CPU_MASK_NONE;
+EXPORT_SYMBOL(cpu_online_map);
+
 cpumask_t cpu_possible_map = CPU_MASK_NONE;
+EXPORT_SYMBOL(cpu_possible_map);
 
 static struct task_struct *current_set[NR_CPUS];
 
@@ -70,7 +72,7 @@ struct call_data_struct {
 	int wait;
 };
 
-static struct call_data_struct * call_data;
+static struct call_data_struct *call_data;
 
 /*
  * 'Call function' interrupt callback
@@ -150,8 +152,8 @@ out:
  *
  * Run a function on all other CPUs.
  *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler. You may call it from a bottom half.
+ * You must not call this function with disabled interrupts, from a
+ * hardware interrupt handler or from a bottom half.
  */
 int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
 		      int wait)
@@ -177,11 +179,11 @@ EXPORT_SYMBOL(smp_call_function);
  *
  * Run a function on one processor.
  *
- * You must not call this function with disabled interrupts or from a
- * hardware interrupt handler. You may call it from a bottom half.
+ * You must not call this function with disabled interrupts, from a
+ * hardware interrupt handler or from a bottom half.
  */
 int smp_call_function_on(void (*func) (void *info), void *info, int nonatomic,
-			  int wait, int cpu)
+			 int wait, int cpu)
 {
 	cpumask_t map = CPU_MASK_NONE;
 
@@ -195,9 +197,9 @@ EXPORT_SYMBOL(smp_call_function_on);
 
 static void do_send_stop(void)
 {
-        int cpu, rc;
+	int cpu, rc;
 
-        /* stop all processors */
+	/* stop all processors */
 	for_each_online_cpu(cpu) {
 		if (cpu == smp_processor_id())
 			continue;
@@ -209,9 +211,9 @@ static void do_send_stop(void)
 
 static void do_store_status(void)
 {
-        int cpu, rc;
+	int cpu, rc;
 
-        /* store status of all processors in their lowcores (real 0) */
+	/* store status of all processors in their lowcores (real 0) */
 	for_each_online_cpu(cpu) {
 		if (cpu == smp_processor_id())
 			continue;
@@ -219,8 +221,8 @@ static void do_store_status(void)
 			rc = signal_processor_p(
 				(__u32)(unsigned long) lowcore_ptr[cpu], cpu,
 				sigp_store_status_at_address);
-		} while(rc == sigp_busy);
-        }
+		} while (rc == sigp_busy);
+	}
 }
 
 static void do_wait_for_stop(void)
@@ -231,7 +233,7 @@ static void do_wait_for_stop(void)
 	for_each_online_cpu(cpu) {
 		if (cpu == smp_processor_id())
 			continue;
-		while(!smp_cpu_not_running(cpu))
+		while (!smp_cpu_not_running(cpu))
 			cpu_relax();
 	}
 }
@@ -245,7 +247,7 @@ void smp_send_stop(void)
 	/* Disable all interrupts/machine checks */
 	__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 
-        /* write magic number to zero page (absolute 0) */
+	/* write magic number to zero page (absolute 0) */
 	lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
 
 	/* stop other processors. */
@@ -261,8 +263,7 @@ void smp_send_stop(void)
 /*
  * Reboot, halt and power_off routines for SMP.
  */
-
-void machine_restart_smp(char * __unused) 
+void machine_restart_smp(char *__unused)
 {
 	smp_send_stop();
 	do_reipl();
@@ -293,17 +294,17 @@ void machine_power_off_smp(void)
 
 static void do_ext_call_interrupt(__u16 code)
 {
-        unsigned long bits;
+	unsigned long bits;
 
-        /*
-         * handle bit signal external calls
-         *
-         * For the ec_schedule signal we have to do nothing. All the work
-         * is done automatically when we return from the interrupt.
-         */
+	/*
+	 * handle bit signal external calls
+	 *
+	 * For the ec_schedule signal we have to do nothing. All the work
+	 * is done automatically when we return from the interrupt.
+	 */
 	bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
-	if (test_bit(ec_call_function, &bits)) 
+	if (test_bit(ec_call_function, &bits))
 		do_call_function();
 }
 
@@ -313,11 +314,11 @@ static void do_ext_call_interrupt(__u16 
  */
 static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
 {
-        /*
-         * Set signaling bit in lowcore of target cpu and kick it
-         */
+	/*
+	 * Set signaling bit in lowcore of target cpu and kick it
+	 */
 	set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
-	while(signal_processor(cpu, sigp_emergency_signal) == sigp_busy)
+	while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy)
 		udelay(10);
 }
 
@@ -332,7 +333,7 @@ void smp_ptlb_callback(void *info)
 
 void smp_ptlb_all(void)
 {
-        on_each_cpu(smp_ptlb_callback, NULL, 0, 1);
+	on_each_cpu(smp_ptlb_callback, NULL, 0, 1);
 }
 EXPORT_SYMBOL(smp_ptlb_all);
 #endif /* ! CONFIG_64BIT */
@@ -344,7 +345,7 @@ #endif /* ! CONFIG_64BIT */
  */
 void smp_send_reschedule(int cpu)
 {
-        smp_ext_bitcall(cpu, ec_schedule);
+	smp_ext_bitcall(cpu, ec_schedule);
 }
 
 /*
@@ -358,11 +359,12 @@ struct ec_creg_mask_parms {
 /*
  * callback for setting/clearing control bits
  */
-static void smp_ctl_bit_callback(void *info) {
+static void smp_ctl_bit_callback(void *info)
+{
 	struct ec_creg_mask_parms *pp = info;
 	unsigned long cregs[16];
 	int i;
-	
+
 	__ctl_store(cregs, 0, 15);
 	for (i = 0; i <= 15; i++)
 		cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
@@ -381,6 +383,7 @@ void smp_ctl_set_bit(int cr, int bit)
 	parms.orvals[cr] = 1 << bit;
 	on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
 }
+EXPORT_SYMBOL(smp_ctl_set_bit);
 
 /*
  * Clear a bit in a control register of all cpus
@@ -394,13 +397,72 @@ void smp_ctl_clear_bit(int cr, int bit)
 	parms.andvals[cr] = ~(1L << bit);
 	on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
 }
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+
+/*
+ * zfcpdump_prefix_array holds prefix registers for the following scenario:
+ * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to
+ * save its prefix registers, since they get lost, when switching from 31 bit
+ * to 64 bit.
+ */
+unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \
+	__attribute__((__section__(".data")));
+
+static void __init smp_get_save_areas(void)
+{
+	unsigned int cpu, cpu_num, rc;
+	__u16 boot_cpu_addr;
+
+	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+		return;
+	boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+	cpu_num = 1;
+	for (cpu = 0; cpu <= 65535; cpu++) {
+		if ((u16) cpu == boot_cpu_addr)
+			continue;
+		__cpu_logical_map[1] = (__u16) cpu;
+		if (signal_processor(1, sigp_sense) == sigp_not_operational)
+			continue;
+		if (cpu_num >= NR_CPUS) {
+			printk("WARNING: Registers for cpu %i are not "
+			       "saved, since dump kernel was compiled with"
+			       "NR_CPUS=%i!\n", cpu_num, NR_CPUS);
+			continue;
+		}
+		zfcpdump_save_areas[cpu_num] =
+			alloc_bootmem(sizeof(union save_area));
+		while (1) {
+			rc = signal_processor(1, sigp_stop_and_store_status);
+			if (rc != sigp_busy)
+				break;
+			cpu_relax();
+		}
+		memcpy(zfcpdump_save_areas[cpu_num],
+		       (void *)(unsigned long) store_prefix() +
+		       SAVE_AREA_BASE, SAVE_AREA_SIZE);
+#ifdef __s390x__
+		/* copy original prefix register */
+		zfcpdump_save_areas[cpu_num]->s390x.pref_reg =
+			zfcpdump_prefix_array[cpu_num];
+#endif
+		cpu_num++;
+	}
+}
+
+union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+EXPORT_SYMBOL_GPL(zfcpdump_save_areas);
+
+#else
+#define smp_get_save_areas() do { } while (0)
+#endif
 
 /*
  * Lets check how many CPUs we have.
  */
 
-static unsigned int
-__init smp_count_cpus(void)
+static unsigned int __init smp_count_cpus(void)
 {
 	unsigned int cpu, num_cpus;
 	__u16 boot_cpu_addr;
@@ -416,31 +478,30 @@ __init smp_count_cpus(void)
 		if ((__u16) cpu == boot_cpu_addr)
 			continue;
 		__cpu_logical_map[1] = (__u16) cpu;
-		if (signal_processor(1, sigp_sense) ==
-		    sigp_not_operational)
+		if (signal_processor(1, sigp_sense) == sigp_not_operational)
 			continue;
 		num_cpus++;
 	}
 
-	printk("Detected %d CPU's\n",(int) num_cpus);
+	printk("Detected %d CPU's\n", (int) num_cpus);
 	printk("Boot cpu address %2X\n", boot_cpu_addr);
 
 	return num_cpus;
 }
 
 /*
- *      Activate a secondary processor.
+ *	Activate a secondary processor.
  */
 int __devinit start_secondary(void *cpuvoid)
 {
-        /* Setup the cpu */
-        cpu_init();
+	/* Setup the cpu */
+	cpu_init();
 	preempt_disable();
 	/* Enable TOD clock interrupts on the secondary cpu. */
-        init_cpu_timer();
+	init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
 	/* Enable cpu timer interrupts on the secondary cpu. */
-        init_cpu_vtimer();
+	init_cpu_vtimer();
 #endif
 	/* Enable pfault pseudo page faults on this cpu. */
 	pfault_init();
@@ -449,11 +510,11 @@ #endif
 	cpu_set(smp_processor_id(), cpu_online_map);
 	/* Switch on interrupts */
 	local_irq_enable();
-        /* Print info about this processor */
-        print_cpu_info(&S390_lowcore.cpu_data);
-        /* cpu_idle will call schedule for us */
-        cpu_idle();
-        return 0;
+	/* Print info about this processor */
+	print_cpu_info(&S390_lowcore.cpu_data);
+	/* cpu_idle will call schedule for us */
+	cpu_idle();
+	return 0;
 }
 
 static void __init smp_create_idle(unsigned int cpu)
@@ -470,56 +531,13 @@ static void __init smp_create_idle(unsig
 	current_set[cpu] = p;
 }
 
-/* Reserving and releasing of CPUs */
-
-static DEFINE_SPINLOCK(smp_reserve_lock);
-static int smp_cpu_reserved[NR_CPUS];
-
-int
-smp_get_cpu(cpumask_t cpu_mask)
-{
-	unsigned long flags;
-	int cpu;
-
-	spin_lock_irqsave(&smp_reserve_lock, flags);
-	/* Try to find an already reserved cpu. */
-	for_each_cpu_mask(cpu, cpu_mask) {
-		if (smp_cpu_reserved[cpu] != 0) {
-			smp_cpu_reserved[cpu]++;
-			/* Found one. */
-			goto out;
-		}
-	}
-	/* Reserve a new cpu from cpu_mask. */
-	for_each_cpu_mask(cpu, cpu_mask) {
-		if (cpu_online(cpu)) {
-			smp_cpu_reserved[cpu]++;
-			goto out;
-		}
-	}
-	cpu = -ENODEV;
-out:
-	spin_unlock_irqrestore(&smp_reserve_lock, flags);
-	return cpu;
-}
-
-void
-smp_put_cpu(int cpu)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&smp_reserve_lock, flags);
-	smp_cpu_reserved[cpu]--;
-	spin_unlock_irqrestore(&smp_reserve_lock, flags);
-}
-
-static int
-cpu_stopped(int cpu)
+static int cpu_stopped(int cpu)
 {
 	__u32 status;
 
 	/* Check for stopped state */
-	if (signal_processor_ps(&status, 0, cpu, sigp_sense) == sigp_status_stored) {
+	if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
+	    sigp_status_stored) {
 		if (status & 0x40)
 			return 1;
 	}
@@ -528,14 +546,13 @@ cpu_stopped(int cpu)
 
 /* Upping and downing of CPUs */
 
-int
-__cpu_up(unsigned int cpu)
+int __cpu_up(unsigned int cpu)
 {
 	struct task_struct *idle;
-        struct _lowcore    *cpu_lowcore;
+	struct _lowcore *cpu_lowcore;
 	struct stack_frame *sf;
-        sigp_ccode          ccode;
-	int                 curr_cpu;
+	sigp_ccode ccode;
+	int curr_cpu;
 
 	for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
 		__cpu_logical_map[cpu] = (__u16) curr_cpu;
@@ -548,7 +565,7 @@ __cpu_up(unsigned int cpu)
 
 	ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
 				   cpu, sigp_set_prefix);
-	if (ccode){
+	if (ccode) {
 		printk("sigp_set_prefix failed for cpu %d "
 		       "with condition code %d\n",
 		       (int) cpu, (int) ccode);
@@ -556,9 +573,9 @@ __cpu_up(unsigned int cpu)
 	}
 
 	idle = current_set[cpu];
-        cpu_lowcore = lowcore_ptr[cpu];
+	cpu_lowcore = lowcore_ptr[cpu];
 	cpu_lowcore->kernel_stack = (unsigned long)
-		task_stack_page(idle) + (THREAD_SIZE);
+		task_stack_page(idle) + THREAD_SIZE;
 	sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
 				     - sizeof(struct pt_regs)
 				     - sizeof(struct stack_frame));
@@ -570,11 +587,11 @@ __cpu_up(unsigned int cpu)
 		"	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;
+	cpu_lowcore->current_task = (unsigned long) idle;
+	cpu_lowcore->cpu_data.cpu_nr = cpu;
 	eieio();
 
-	while (signal_processor(cpu,sigp_restart) == sigp_busy)
+	while (signal_processor(cpu, sigp_restart) == sigp_busy)
 		udelay(10);
 
 	while (!cpu_online(cpu))
@@ -589,6 +606,7 @@ void __init smp_setup_cpu_possible_map(v
 {
 	unsigned int phy_cpus, pos_cpus, cpu;
 
+	smp_get_save_areas();
 	phy_cpus = smp_count_cpus();
 	pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS);
 
@@ -620,18 +638,11 @@ static int __init setup_possible_cpus(ch
 }
 early_param("possible_cpus", setup_possible_cpus);
 
-int
-__cpu_disable(void)
+int __cpu_disable(void)
 {
-	unsigned long flags;
 	struct ec_creg_mask_parms cr_parms;
 	int cpu = smp_processor_id();
 
-	spin_lock_irqsave(&smp_reserve_lock, flags);
-	if (smp_cpu_reserved[cpu] != 0) {
-		spin_unlock_irqrestore(&smp_reserve_lock, flags);
-		return -EBUSY;
-	}
 	cpu_clear(cpu, cpu_online_map);
 
 	/* Disable pfault pseudo page faults on this cpu. */
@@ -642,24 +653,23 @@ __cpu_disable(void)
 
 	/* 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);
+	cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 |
+				1 << 11 | 1 << 10 | 1 <<  6 | 1 <<  4);
 	/* disable all I/O interrupts */
 	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);
+	cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
+				1 << 27 | 1 << 26 | 1 << 25 | 1 << 24);
 	/* disable most machine checks */
 	cr_parms.orvals[14] = 0;
-	cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24);
+	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);
 	return 0;
 }
 
-void
-__cpu_die(unsigned int cpu)
+void __cpu_die(unsigned int cpu)
 {
 	/* Wait until target cpu is down */
 	while (!smp_cpu_not_running(cpu))
@@ -667,13 +677,12 @@ __cpu_die(unsigned int cpu)
 	printk("Processor %d spun down\n", cpu);
 }
 
-void
-cpu_die(void)
+void cpu_die(void)
 {
 	idle_task_exit();
 	signal_processor(smp_processor_id(), sigp_stop);
 	BUG();
-	for(;;);
+	for (;;);
 }
 
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -686,36 +695,36 @@ void __init smp_prepare_cpus(unsigned in
 {
 	unsigned long stack;
 	unsigned int cpu;
-        int i;
-
-        /* request the 0x1201 emergency signal external interrupt */
-        if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
-                panic("Couldn't request external interrupt 0x1201");
-        memset(lowcore_ptr,0,sizeof(lowcore_ptr));  
-        /*
-         *  Initialize prefix pages and stacks for all possible cpus
-         */
+	int i;
+
+	/* request the 0x1201 emergency signal external interrupt */
+	if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
+		panic("Couldn't request external interrupt 0x1201");
+	memset(lowcore_ptr, 0, sizeof(lowcore_ptr));
+	/*
+	 *  Initialize prefix pages and stacks for all possible cpus
+	 */
 	print_cpu_info(&S390_lowcore.cpu_data);
 
-        for_each_possible_cpu(i) {
+	for_each_possible_cpu(i) {
 		lowcore_ptr[i] = (struct _lowcore *)
-			__get_free_pages(GFP_KERNEL|GFP_DMA, 
-					sizeof(void*) == 8 ? 1 : 0);
-		stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER);
-		if (lowcore_ptr[i] == NULL || stack == 0ULL)
+			__get_free_pages(GFP_KERNEL | GFP_DMA,
+					 sizeof(void*) == 8 ? 1 : 0);
+		stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+		if (!lowcore_ptr[i] || !stack)
 			panic("smp_boot_cpus failed to allocate memory\n");
 
 		*(lowcore_ptr[i]) = S390_lowcore;
-		lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
-		stack = __get_free_pages(GFP_KERNEL,0);
-		if (stack == 0ULL)
+		lowcore_ptr[i]->async_stack = stack + ASYNC_SIZE;
+		stack = __get_free_pages(GFP_KERNEL, 0);
+		if (!stack)
 			panic("smp_boot_cpus failed to allocate memory\n");
-		lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
+		lowcore_ptr[i]->panic_stack = stack + PAGE_SIZE;
 #ifndef CONFIG_64BIT
 		if (MACHINE_HAS_IEEE) {
 			lowcore_ptr[i]->extended_save_area_addr =
-				(__u32) __get_free_pages(GFP_KERNEL,0);
-			if (lowcore_ptr[i]->extended_save_area_addr == 0)
+				(__u32) __get_free_pages(GFP_KERNEL, 0);
+			if (!lowcore_ptr[i]->extended_save_area_addr)
 				panic("smp_boot_cpus failed to "
 				      "allocate memory\n");
 		}
@@ -754,34 +763,63 @@ void smp_cpus_done(unsigned int max_cpus
  */
 int setup_profiling_timer(unsigned int multiplier)
 {
-        return 0;
+	return 0;
 }
 
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
+static ssize_t show_capability(struct sys_device *dev, char *buf)
+{
+	unsigned int capability;
+	int rc;
+
+	rc = get_cpu_capability(&capability);
+	if (rc)
+		return rc;
+	return sprintf(buf, "%u\n", capability);
+}
+static SYSDEV_ATTR(capability, 0444, show_capability, NULL);
+
+static int __cpuinit smp_cpu_notify(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned int)(long)hcpu;
+	struct cpu *c = &per_cpu(cpu_devices, cpu);
+	struct sys_device *s = &c->sysdev;
+
+	switch (action) {
+	case CPU_ONLINE:
+		if (sysdev_create_file(s, &attr_capability))
+			return NOTIFY_BAD;
+		break;
+	case CPU_DEAD:
+		sysdev_remove_file(s, &attr_capability);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata smp_cpu_nb = {
+	.notifier_call = smp_cpu_notify,
+};
+
 static int __init topology_init(void)
 {
 	int cpu;
-	int ret;
+
+	register_cpu_notifier(&smp_cpu_nb);
 
 	for_each_possible_cpu(cpu) {
 		struct cpu *c = &per_cpu(cpu_devices, cpu);
+		struct sys_device *s = &c->sysdev;
 
 		c->hotpluggable = 1;
-		ret = register_cpu(c, cpu);
-		if (ret)
-			printk(KERN_WARNING "topology_init: register_cpu %d "
-			       "failed (%d)\n", cpu, ret);
+		register_cpu(c, cpu);
+		if (!cpu_online(cpu))
+			continue;
+		s = &c->sysdev;
+		sysdev_create_file(s, &attr_capability);
 	}
 	return 0;
 }
-
 subsys_initcall(topology_init);
-
-EXPORT_SYMBOL(cpu_online_map);
-EXPORT_SYMBOL(cpu_possible_map);
-EXPORT_SYMBOL(lowcore_ptr);
-EXPORT_SYMBOL(smp_ctl_set_bit);
-EXPORT_SYMBOL(smp_ctl_clear_bit);
-EXPORT_SYMBOL(smp_get_cpu);
-EXPORT_SYMBOL(smp_put_cpu);
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 2e5c65a..515ff90 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -59,7 +59,7 @@ static unsigned long save_context_stack(
 	}
 }
 
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
 	register unsigned long sp asm ("15");
 	unsigned long orig_sp, new_sp;
@@ -69,20 +69,16 @@ void save_stack_trace(struct stack_trace
 	new_sp = save_context_stack(trace, &trace->skip, orig_sp,
 				S390_lowcore.panic_stack - PAGE_SIZE,
 				S390_lowcore.panic_stack);
-	if ((new_sp != orig_sp) && !trace->all_contexts)
+	if (new_sp != orig_sp)
 		return;
 	new_sp = save_context_stack(trace, &trace->skip, new_sp,
 				S390_lowcore.async_stack - ASYNC_SIZE,
 				S390_lowcore.async_stack);
-	if ((new_sp != orig_sp) && !trace->all_contexts)
+	if (new_sp != orig_sp)
 		return;
-	if (task)
-		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, &trace->skip, new_sp,
-				   S390_lowcore.thread_info,
-				   S390_lowcore.thread_info + THREAD_SIZE);
+
+	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 584ed95..1c90c7e 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -17,7 +17,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -266,23 +265,3 @@ s390_fadvise64_64(struct fadvise64_64_ar
 		return -EFAULT;
 	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 c774f10..cd8d321 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -10,7 +10,7 @@ #define NI_SYSCALL SYSCALL(sys_ni_syscal
 
 NI_SYSCALL							/* 0 */
 SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
-SYSCALL(sys_fork_glue,sys_fork_glue,sys_fork_glue)
+SYSCALL(sys_fork,sys_fork,sys_fork)
 SYSCALL(sys_read,sys_read,sys32_read_wrapper)
 SYSCALL(sys_write,sys_write,sys32_write_wrapper)
 SYSCALL(sys_open,sys_open,sys32_open_wrapper)			/* 5 */
@@ -19,7 +19,7 @@ SYSCALL(sys_restart_syscall,sys_restart_
 SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
 SYSCALL(sys_link,sys_link,sys32_link_wrapper)
 SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper)		/* 10 */
-SYSCALL(sys_execve_glue,sys_execve_glue,sys32_execve_glue)
+SYSCALL(sys_execve,sys_execve,sys32_execve)
 SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
 SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper)		/* old time syscall */
 SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
@@ -127,8 +127,8 @@ SYSCALL(sys_swapoff,sys_swapoff,sys32_sw
 SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
 SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper)
 SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
-SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue)
-SYSCALL(sys_clone_glue,sys_clone_glue,sys32_clone_glue)		/* 120 */
+SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
+SYSCALL(sys_clone,sys_clone,sys32_clone)			/* 120 */
 SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
 SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper)
 NI_SYSCALL							/* modify_ldt for i386 */
@@ -181,7 +181,7 @@ SYSCALL(sys_nfsservctl,sys_nfsservctl,co
 SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper)	/* 170 old setresgid16 syscall */
 SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper)	/* old getresgid16 syscall */
 SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
-SYSCALL(sys_rt_sigreturn_glue,sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue)
+SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
 SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper)
 SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper)	/* 175 */
 SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper)
@@ -194,11 +194,11 @@ SYSCALL(sys_chown16,sys_ni_syscall,sys32
 SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
 SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
 SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper)		/* 185 */
-SYSCALL(sys_sigaltstack_glue,sys_sigaltstack_glue,sys32_sigaltstack_glue)
+SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack)
 SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
 NI_SYSCALL							/* streams1 */
 NI_SYSCALL							/* streams2 */
-SYSCALL(sys_vfork_glue,sys_vfork_glue,sys_vfork_glue)		/* 190 */
+SYSCALL(sys_vfork,sys_vfork,sys_vfork)				/* 190 */
 SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
 SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
 SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index e1ad464..9c2872a 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -21,6 +21,7 @@ #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
+#include <linux/sysdev.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
@@ -280,7 +281,6 @@ static void clock_comparator_interrupt(_
 }
 
 static void etr_reset(void);
-static void etr_init(void);
 static void etr_ext_handler(__u16);
 
 /*
@@ -355,7 +355,6 @@ #endif
 #ifdef CONFIG_VIRT_TIMER
 	vtime_init();
 #endif
-	etr_init();
 }
 
 /*
@@ -426,11 +425,11 @@ static struct etr_aib etr_port1;
 static int etr_port1_uptodate;
 static unsigned long etr_events;
 static struct timer_list etr_timer;
-static struct tasklet_struct etr_tasklet;
 static DEFINE_PER_CPU(atomic_t, etr_sync_word);
 
 static void etr_timeout(unsigned long dummy);
-static void etr_tasklet_fn(unsigned long dummy);
+static void etr_work_fn(struct work_struct *work);
+static DECLARE_WORK(etr_work, etr_work_fn);
 
 /*
  * The etr get_clock function. It will write the current clock value
@@ -507,29 +506,31 @@ static void etr_reset(void)
 	}
 }
 
-static void etr_init(void)
+static int __init etr_init(void)
 {
 	struct etr_aib aib;
 
 	if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
-		return;
+		return 0;
 	/* Check if this machine has the steai instruction. */
 	if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
 		set_bit(ETR_FLAG_STEAI, &etr_flags);
 	setup_timer(&etr_timer, etr_timeout, 0UL);
-	tasklet_init(&etr_tasklet, etr_tasklet_fn, 0);
 	if (!etr_port0_online && !etr_port1_online)
 		set_bit(ETR_FLAG_EACCES, &etr_flags);
 	if (etr_port0_online) {
 		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
-		tasklet_hi_schedule(&etr_tasklet);
+		schedule_work(&etr_work);
 	}
 	if (etr_port1_online) {
 		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
-		tasklet_hi_schedule(&etr_tasklet);
+		schedule_work(&etr_work);
 	}
+	return 0;
 }
 
+arch_initcall(etr_init);
+
 /*
  * Two sorts of ETR machine checks. The architecture reads:
  * "When a machine-check niterruption occurs and if a switch-to-local or
@@ -549,7 +550,7 @@ void etr_switch_to_local(void)
 		return;
 	etr_disable_sync_clock(NULL);
 	set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
-	tasklet_hi_schedule(&etr_tasklet);
+	schedule_work(&etr_work);
 }
 
 /*
@@ -564,7 +565,7 @@ void etr_sync_check(void)
 		return;
 	etr_disable_sync_clock(NULL);
 	set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
-	tasklet_hi_schedule(&etr_tasklet);
+	schedule_work(&etr_work);
 }
 
 /*
@@ -591,13 +592,13 @@ static void etr_ext_handler(__u16 code)
 		 * Both ports are not up-to-date now.
 		 */
 		set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
-	tasklet_hi_schedule(&etr_tasklet);
+	schedule_work(&etr_work);
 }
 
 static void etr_timeout(unsigned long dummy)
 {
 	set_bit(ETR_EVENT_UPDATE, &etr_events);
-	tasklet_hi_schedule(&etr_tasklet);
+	schedule_work(&etr_work);
 }
 
 /*
@@ -927,7 +928,7 @@ static struct etr_eacr etr_handle_update
 	if (!eacr.e0 && !eacr.e1)
 		return eacr;
 
-	/* Update port0 or port1 with aib stored in etr_tasklet_fn. */
+	/* Update port0 or port1 with aib stored in etr_work_fn. */
 	if (aib->esw.q == 0) {
 		/* Information for port 0 stored. */
 		if (eacr.p0 && !etr_port0_uptodate) {
@@ -1007,7 +1008,7 @@ static void etr_update_eacr(struct etr_e
  * particular this is the only function that calls etr_update_eacr(),
  * it "controls" the etr control register.
  */
-static void etr_tasklet_fn(unsigned long dummy)
+static void etr_work_fn(struct work_struct *work)
 {
 	unsigned long long now;
 	struct etr_eacr eacr;
@@ -1220,13 +1221,13 @@ static ssize_t etr_online_store(struct s
 			return count;	/* Nothing to do. */
 		etr_port0_online = value;
 		set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
-		tasklet_hi_schedule(&etr_tasklet);
+		schedule_work(&etr_work);
 	} else {
 		if (etr_port1_online == value)
 			return count;	/* Nothing to do. */
 		etr_port1_online = value;
 		set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
-		tasklet_hi_schedule(&etr_tasklet);
+		schedule_work(&etr_work);
 	}
 	return count;
 }
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index f0e5a32..cbfe730 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -22,15 +22,15 @@ #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/interrupt.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/kdebug.h>
 #include <linux/kallsyms.h>
 #include <linux/reboot.h>
 #include <linux/kprobes.h>
-
+#include <linux/bug.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -40,7 +40,6 @@ #include <asm/cpcmd.h>
 #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);
@@ -70,20 +69,6 @@ #define FOURLONG "%016lx %016lx %016lx %
 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
@@ -188,18 +173,31 @@ void dump_stack(void)
 
 EXPORT_SYMBOL(dump_stack);
 
+static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
+{
+	return (regs->psw.mask & bits) / ((~bits + 1) & bits);
+}
+
 void show_registers(struct pt_regs *regs)
 {
-	mm_segment_t old_fs;
 	char *mode;
-	int i;
 
 	mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
 	printk("%s PSW : %p %p",
 	       mode, (void *) regs->psw.mask,
 	       (void *) regs->psw.addr);
 	print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
-	printk("%s GPRS: " FOURLONG, mode,
+	printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
+	       "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
+	       mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
+	       mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
+	       mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
+	       mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
+	       mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
+#ifdef CONFIG_64BIT
+	printk(" EA:%x", mask_bits(regs, PSW_BASE_BITS));
+#endif
+	printk("\n%s GPRS: " FOURLONG, mode,
 	       regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
 	printk("           " FOURLONG,
 	       regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
@@ -208,41 +206,7 @@ void show_registers(struct pt_regs *regs
 	printk("           " FOURLONG,
 	       regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
 
-#if 0
-	/* FIXME: this isn't needed any more but it changes the ksymoops
-	 * input. To remove or not to remove ... */
-	save_access_regs(regs->acrs);
-	printk("%s ACRS: %08x %08x %08x %08x\n", mode,
-	       regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
-	printk("           %08x %08x %08x %08x\n",
-	       regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
-	printk("           %08x %08x %08x %08x\n",
-	       regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
-	printk("           %08x %08x %08x %08x\n",
-	       regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
-#endif
-
-	/*
-	 * Print the first 20 byte of the instruction stream at the
-	 * time of the fault.
-	 */
-	old_fs = get_fs();
-	if (regs->psw.mask & PSW_MASK_PSTATE)
-		set_fs(USER_DS);
-	else
-		set_fs(KERNEL_DS);
-	printk("%s Code: ", mode);
-	for (i = 0; i < 20; i++) {
-		unsigned char c;
-		if (__get_user(c, (char __user *)(regs->psw.addr + i))) {
-			printk(" Bad PSW.");
-			break;
-		}
-		printk("%02x ", c);
-	}
-	set_fs(old_fs);
-
-	printk("\n");
+	show_code(regs);
 }	
 
 /* This is called from fs/proc/array.c */
@@ -318,6 +282,11 @@ #if defined(CONFIG_SYSCTL) || defined(CO
 #endif
 }
 
+int is_valid_bugaddr(unsigned long addr)
+{
+	return 1;
+}
+
 static void __kprobes inline do_trap(long interruption_code, int signr,
 					char *str, struct pt_regs *regs,
 					siginfo_t *info)
@@ -344,8 +313,14 @@ static void __kprobes inline do_trap(lon
                 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
                 if (fixup)
                         regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
-                else
-                        die(str, regs, interruption_code);
+		else {
+			enum bug_trap_type btt;
+
+			btt = report_bug(regs->psw.addr & PSW_ADDR_INSN);
+			if (btt == BUG_TRAP_TYPE_WARN)
+				return;
+			die(str, regs, interruption_code);
+		}
         }
 }
 
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index c30716a..e9d3432 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -45,6 +45,8 @@ #endif
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
+  BUG_TABLE
+
   .data : {			/* Data */
 	*(.data)
 	CONSTRUCTORS
@@ -77,6 +79,12 @@ #endif
 	*(.init.text)
 	_einittext = .;
   }
+  /*
+   * .exit.text is discarded at runtime, not link time,
+   * to deal with references from __bug_table
+   */
+  .exit.text :	 { *(.exit.text) }
+
   .init.data : { *(.init.data) }
   . = ALIGN(256);
   __setup_start = .;
@@ -99,7 +107,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
   . = ALIGN(2);
   __initramfs_end = .;
 #endif
-  . = ALIGN(256);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
@@ -116,7 +124,7 @@ #endif
 
   /* Sections to be discarded */
   /DISCARD/ : {
-	*(.exit.text) *(.exit.data) *(.exitcall.exit)
+	*(.exit.data) *(.exitcall.exit)
 	}
 
   /* Stabs debugging sections.  */
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 9d5b028..1e1a6ee 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -128,7 +128,7 @@ static inline void set_vtimer(__u64 expi
 	S390_lowcore.last_update_timer = expires;
 
 	/* store expire time for this CPU timer */
-	per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
+	__get_cpu_var(virt_cpu_timer).to_expire = expires;
 }
 #else
 static inline void set_vtimer(__u64 expires)
@@ -137,7 +137,7 @@ static inline void set_vtimer(__u64 expi
 	asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
 
 	/* store expire time for this CPU timer */
-	per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
+	__get_cpu_var(virt_cpu_timer).to_expire = expires;
 }
 #endif
 
@@ -145,7 +145,7 @@ static void start_cpu_timer(void)
 {
 	struct vtimer_queue *vt_list;
 
-	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+	vt_list = &__get_cpu_var(virt_cpu_timer);
 
 	/* CPU timer interrupt is pending, don't reprogramm it */
 	if (vt_list->idle & 1LL<<63)
@@ -159,7 +159,7 @@ static void stop_cpu_timer(void)
 {
 	struct vtimer_queue *vt_list;
 
-	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+	vt_list = &__get_cpu_var(virt_cpu_timer);
 
 	/* nothing to do */
 	if (list_empty(&vt_list->list)) {
@@ -219,7 +219,7 @@ static void do_callbacks(struct list_hea
 	if (list_empty(cb_list))
 		return;
 
-	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+	vt_list = &__get_cpu_var(virt_cpu_timer);
 
 	list_for_each_entry_safe(event, tmp, cb_list, entry) {
 		fn = event->function;
@@ -244,7 +244,6 @@ static void do_callbacks(struct list_hea
  */
 static void do_cpu_timer_interrupt(__u16 error_code)
 {
-	int cpu;
 	__u64 next, delta;
 	struct vtimer_queue *vt_list;
 	struct vtimer_list *event, *tmp;
@@ -253,8 +252,7 @@ static void do_cpu_timer_interrupt(__u16
 	struct list_head cb_list;
 
 	INIT_LIST_HEAD(&cb_list);
-	cpu = smp_processor_id();
-	vt_list = &per_cpu(virt_cpu_timer, cpu);
+	vt_list = &__get_cpu_var(virt_cpu_timer);
 
 	/* walk timer list, fire all expired events */
 	spin_lock(&vt_list->lock);
@@ -534,7 +532,7 @@ void init_cpu_vtimer(void)
 	/* enable cpu timer interrupts */
 	__ctl_set_bit(0,10);
 
-	vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+	vt_list = &__get_cpu_var(virt_cpu_timer);
 	INIT_LIST_HEAD(&vt_list->list);
 	spin_lock_init(&vt_list->lock);
 	vt_list->to_expire = 0;
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index 7a44fed..59aea65 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -5,6 +5,6 @@ #
 EXTRA_AFLAGS := -traditional
 
 lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
-lib-$(CONFIG_32BIT) += div64.o
+obj-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/div64.c b/arch/s390/lib/div64.c
index 0481f34..a5f8300 100644
--- a/arch/s390/lib/div64.c
+++ b/arch/s390/lib/div64.c
@@ -147,5 +147,3 @@ uint32_t __div64_32(uint64_t *n, uint32_
 }
 
 #endif /* MARCH_G5 */
-
-EXPORT_SYMBOL(__div64_32);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 7462aeb..8b924b3 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -20,17 +20,17 @@ #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
+#include <linux/kdebug.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
+#include <linux/uaccess.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/kdebug.h>
 #include <asm/s390_ext.h>
 
 #ifndef CONFIG_64BIT
@@ -52,34 +52,24 @@ #endif
 extern void die(const char *,struct pt_regs *,long);
 
 #ifdef CONFIG_KPROBES
-static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs, long err)
 {
-	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
+	int ret = 0;
+
+	/* kprobe_running() needs smp_processor_id() */
+	if (!user_mode(regs)) {
+		preempt_disable();
+		if (kprobe_running() && kprobe_fault_handler(regs, 14))
+			ret = 1;
+		preempt_enable();
+	}
 
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&notify_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(&notify_page_fault_chain, val, &args);
+	return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, const char *str,
-			struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs, long err)
 {
-	return NOTIFY_DONE;
+	return 0;
 }
 #endif
 
@@ -170,74 +160,127 @@ #endif
 	force_sig_info(SIGSEGV, &si, current);
 }
 
+static void do_no_context(struct pt_regs *regs, unsigned long error_code,
+			  unsigned long address)
+{
+	const struct exception_table_entry *fixup;
+
+	/* Are we prepared to handle this kernel fault?  */
+	fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+	if (fixup) {
+		regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+		return;
+	}
+
+	/*
+	 * Oops. The kernel tried to access some bad page. We'll have to
+	 * terminate things with extreme prejudice.
+	 */
+	if (check_space(current) == 0)
+		printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+		       " at virtual kernel address %p\n", (void *)address);
+	else
+		printk(KERN_ALERT "Unable to handle kernel paging request"
+		       " at virtual user address %p\n", (void *)address);
+
+	die("Oops", regs, error_code);
+	do_exit(SIGKILL);
+}
+
+static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+{
+	/* Low-address protection hit in kernel mode means
+	   NULL pointer write access in kernel mode.  */
+	if (regs->psw.mask & PSW_MASK_PSTATE) {
+		/* Low-address protection hit in user mode 'cannot happen'. */
+		die ("Low-address protection", regs, error_code);
+		do_exit(SIGKILL);
+	}
+
+	do_no_context(regs, error_code, 0);
+}
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code,
+			    unsigned long address)
+{
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
+
+	up_read(&mm->mmap_sem);
+	if (is_init(tsk)) {
+		yield();
+		down_read(&mm->mmap_sem);
+		return 1;
+	}
+	printk("VM: killing process %s\n", tsk->comm);
+	if (regs->psw.mask & PSW_MASK_PSTATE)
+		do_exit(SIGKILL);
+	do_no_context(regs, error_code, address);
+	return 0;
+}
+
+static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
+		      unsigned long address)
+{
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
+
+	up_read(&mm->mmap_sem);
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	tsk->thread.prot_addr = address;
+	tsk->thread.trap_no = error_code;
+	force_sig(SIGBUS, tsk);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!(regs->psw.mask & PSW_MASK_PSTATE))
+		do_no_context(regs, error_code, address);
+}
+
 #ifdef CONFIG_S390_EXEC_PROTECT
 extern long sys_sigreturn(struct pt_regs *regs);
 extern long sys_rt_sigreturn(struct pt_regs *regs);
 extern long sys32_sigreturn(struct pt_regs *regs);
 extern long sys32_rt_sigreturn(struct pt_regs *regs);
 
-static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
-				int rt)
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+			 unsigned long address, unsigned long error_code)
 {
+	u16 instruction;
+	int rc, compat;
+
+	pagefault_disable();
+	rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
+	pagefault_enable();
+	if (rc)
+		return -EFAULT;
+
 	up_read(&mm->mmap_sem);
 	clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
 #ifdef CONFIG_COMPAT
-	if (test_tsk_thread_flag(current, TIF_31BIT)) {
-		if (rt)
-			sys32_rt_sigreturn(regs);
-		else
-			sys32_sigreturn(regs);
-		return;
-	}
-#endif /* CONFIG_COMPAT */
-	if (rt)
-		sys_rt_sigreturn(regs);
+	compat = test_tsk_thread_flag(current, TIF_31BIT);
+	if (compat && instruction == 0x0a77)
+		sys32_sigreturn(regs);
+	else if (compat && instruction == 0x0aad)
+		sys32_rt_sigreturn(regs);
 	else
+#endif
+	if (instruction == 0x0a77)
 		sys_sigreturn(regs);
-	return;
-}
-
-static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
-			 unsigned long address, unsigned long error_code)
-{
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	u16 *instruction;
-	unsigned long pfn, uaddr = regs->psw.addr;
-
-	spin_lock(&mm->page_table_lock);
-	pgd = pgd_offset(mm, uaddr);
-	if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-		goto out_fault;
-	pmd = pmd_offset(pgd, uaddr);
-	if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
-		goto out_fault;
-	pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
-	if (!pte || !pte_present(*pte))
-		goto out_fault;
-	pfn = pte_pfn(*pte);
-	if (!pfn_valid(pfn))
-		goto out_fault;
-	spin_unlock(&mm->page_table_lock);
-
-	instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
-	if (*instruction == 0x0a77)
-		do_sigreturn(mm, regs, 0);
-	else if (*instruction == 0x0aad)
-		do_sigreturn(mm, regs, 1);
+	else if (instruction == 0x0aad)
+		sys_rt_sigreturn(regs);
 	else {
-		printk("- XXX - do_exception: task = %s, primary, NO EXEC "
-		       "-> SIGSEGV\n", current->comm);
-		up_read(&mm->mmap_sem);
 		current->thread.prot_addr = address;
 		current->thread.trap_no = error_code;
 		do_sigsegv(regs, error_code, SEGV_MAPERR, address);
 	}
 	return 0;
-out_fault:
-	spin_unlock(&mm->page_table_lock);
-	return -EFAULT;
 }
 #endif /* CONFIG_S390_EXEC_PROTECT */
 
@@ -253,49 +296,23 @@ #endif /* CONFIG_S390_EXEC_PROTECT */
  *   3b       Region third trans.  ->  Not present       (nullification)
  */
 static inline void
-do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
+do_exception(struct pt_regs *regs, unsigned long error_code, int write)
 {
-        struct task_struct *tsk;
-        struct mm_struct *mm;
-        struct vm_area_struct * vma;
-        unsigned long address;
-	const struct exception_table_entry *fixup;
-	int si_code;
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	unsigned long address;
 	int space;
+	int si_code;
 
-        tsk = current;
-        mm = tsk->mm;
-	
-	if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
-					SIGSEGV) == NOTIFY_STOP)
+	if (notify_page_fault(regs, error_code))
 		return;
 
-	/* 
-         * Check for low-address protection.  This needs to be treated
-	 * as a special case because the translation exception code 
-	 * field is not guaranteed to contain valid data in this case.
-	 */
-	if (is_protection && !(S390_lowcore.trans_exc_code & 4)) {
-
-		/* Low-address protection hit in kernel mode means 
-		   NULL pointer write access in kernel mode.  */
- 		if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
-			address = 0;
-			space = 0;
-			goto no_context;
-		}
-
-		/* Low-address protection hit in user mode 'cannot happen'.  */
-		die ("Low-address protection", regs, error_code);
-        	do_exit(SIGKILL);
-	}
+	tsk = current;
+	mm = tsk->mm;
 
-        /* 
-         * get the failing address 
-         * more specific the segment and page table portion of 
-         * the address 
-         */
-        address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
+	/* get the failing address and the affected space */
+	address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
 	space = check_space(tsk);
 
 	/*
@@ -313,7 +330,7 @@ do_exception(struct pt_regs *regs, unsig
 	 */
 	local_irq_enable();
 
-        down_read(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	si_code = SEGV_MAPERR;
 	vma = find_vma(mm, address);
@@ -330,19 +347,19 @@ #ifdef CONFIG_S390_EXEC_PROTECT
 			return;
 #endif
 
-        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;
+	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:
 	si_code = SEGV_ACCERR;
-	if (!is_protection) {
+	if (!write) {
 		/* page not present, check vm flags */
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
 			goto bad_area;
@@ -357,7 +374,7 @@ survive:
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, is_protection)) {
+	switch (handle_mm_fault(mm, vma, address, write)) {
 	case VM_FAULT_MINOR:
 		tsk->min_flt++;
 		break;
@@ -365,9 +382,12 @@ survive:
 		tsk->maj_flt++;
 		break;
 	case VM_FAULT_SIGBUS:
-		goto do_sigbus;
+		do_sigbus(regs, error_code, address);
+		return;
 	case VM_FAULT_OOM:
-		goto out_of_memory;
+		if (do_out_of_memory(regs, error_code, address))
+			goto survive;
+		return;
 	default:
 		BUG();
 	}
@@ -385,75 +405,34 @@ survive:
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-        up_read(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
-        /* User mode accesses just cause a SIGSEGV */
-        if (regs->psw.mask & PSW_MASK_PSTATE) {
-                tsk->thread.prot_addr = address;
-                tsk->thread.trap_no = error_code;
+	/* User mode accesses just cause a SIGSEGV */
+	if (regs->psw.mask & PSW_MASK_PSTATE) {
+		tsk->thread.prot_addr = address;
+		tsk->thread.trap_no = error_code;
 		do_sigsegv(regs, error_code, si_code, address);
-                return;
+		return;
 	}
 
 no_context:
-        /* Are we prepared to handle this kernel fault?  */
-	fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
-	if (fixup) {
-		regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
-                return;
-        }
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
-	if (space == 0)
-                printk(KERN_ALERT "Unable to handle kernel pointer dereference"
-        	       " at virtual kernel address %p\n", (void *)address);
-        else
-                printk(KERN_ALERT "Unable to handle kernel paging request"
-		       " at virtual user address %p\n", (void *)address);
-
-        die("Oops", regs, error_code);
-        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 (is_init(tsk)) {
-		yield();
-		down_read(&mm->mmap_sem);
-		goto survive;
-	}
-	printk("VM: killing process %s\n", tsk->comm);
-	if (regs->psw.mask & PSW_MASK_PSTATE)
-		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.
-	 */
-        tsk->thread.prot_addr = address;
-        tsk->thread.trap_no = error_code;
-	force_sig(SIGBUS, tsk);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!(regs->psw.mask & PSW_MASK_PSTATE))
-		goto no_context;
+	do_no_context(regs, error_code, address);
 }
 
 void __kprobes do_protection_exception(struct pt_regs *regs,
 				       unsigned long error_code)
 {
+	/* Protection exception is supressing, decrement psw address. */
 	regs->psw.addr -= (error_code >> 16);
+	/*
+	 * Check for low-address protection.  This needs to be treated
+	 * as a special case because the translation exception code
+	 * field is not guaranteed to contain valid data in this case.
+	 */
+	if (unlikely(!(S390_lowcore.trans_exc_code & 4))) {
+		do_low_address(regs, error_code);
+		return;
+	}
 	do_exception(regs, 4, 1);
 }
 
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 4d16d89..d74eb12 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -22,6 +22,10 @@ config RWSEM_GENERIC_SPINLOCK
 config RWSEM_XCHGADD_ALGORITHM
 	bool
 
+config GENERIC_BUG
+	def_bool y
+	depends on BUG
+
 config GENERIC_FIND_NEXT_BIT
 	bool
 	default y
@@ -88,6 +92,14 @@ config SH_SOLUTION_ENGINE
 	  Select SolutionEngine if configuring for a Hitachi SH7709
 	  or SH7750 evaluation board.
 
+config SH_7722_SOLUTION_ENGINE
+	bool "SolutionEngine7722"
+	select SOLUTION_ENGINE
+	select CPU_SUBTYPE_SH7722
+	help
+	  Select 7722 SolutionEngine if configuring for a Hitachi SH772
+	  evaluation board.
+
 config SH_7751_SOLUTION_ENGINE
 	bool "SolutionEngine7751"
 	select SOLUTION_ENGINE
@@ -95,6 +107,14 @@ config SH_7751_SOLUTION_ENGINE
 	help
 	  Select 7751 SolutionEngine if configuring for a Hitachi SH7751
 	  evaluation board.
+	  
+config SH_7780_SOLUTION_ENGINE
+	bool "SolutionEngine7780"
+	select SOLUTION_ENGINE
+	select CPU_SUBTYPE_SH7780
+	help
+	  Select 7780 SolutionEngine if configuring for a Renesas SH7780
+	  evaluation board.
 
 config SH_7300_SOLUTION_ENGINE
 	bool "SolutionEngine7300"
@@ -193,12 +213,8 @@ config SH_RTS7751R2D
 	  Select RTS7751R2D if configuring for a Renesas Technology
 	  Sales SH-Graphics board.
 
-config SH_R7780RP
-	bool "R7780RP-1"
-	select CPU_SUBTYPE_SH7780
-	help
-	  Select R7780RP-1 if configuring for a Renesas Solutions
-	  HIGHLANDER board.
+config SH_HIGHLANDER
+	bool "Highlander"
 
 config SH_EDOSK7705
 	bool "EDOSK7705"
@@ -243,6 +259,12 @@ config SH_7619_SOLUTION_ENGINE
 	help
 	  Select 7619 SolutionEngine if configuring for a Hitachi SH7619
 	  evaluation board.
+	
+config SH_LBOX_RE2
+	bool "L-BOX RE2"
+	select CPU_SUBTYPE_SH7751R
+	help
+	  Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2.
 
 config SH_UNKNOWN
 	bool "BareCPU"
@@ -258,6 +280,10 @@ config SH_UNKNOWN
 
 endchoice
 
+source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
+source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
+source "arch/sh/boards/renesas/r7780rp/Kconfig"
+
 source "arch/sh/mm/Kconfig"
 
 config CF_ENABLER
@@ -366,6 +392,16 @@ config SH_STORE_QUEUES
 	  Selecting this option will enable an in-kernel API for manipulating
 	  the store queues integrated in the SH-4 processors.
 
+config SPECULATIVE_EXECUTION
+	bool "Speculative subroutine return"
+	depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
+	help
+	  This enables support for a speculative instruction fetch for
+	  subroutine return. There are various pitfalls associated with
+	  this, as outlined in the SH7780 hardware manual.
+
+	  If unsure, say N.
+
 config CPU_HAS_INTEVT
 	bool
 
@@ -398,8 +434,9 @@ config CPU_HAS_PTEA
 
 endmenu
 
-menu "Timer support"
-depends on !GENERIC_TIME
+menu "Timer and clock configuration"
+
+if !GENERIC_TIME
 
 config SH_TMU
 	bool "TMU timer support"
@@ -422,17 +459,11 @@ config SH_MTU2
 	help
 	  This enables the use of the MTU2 as the system timer.
 
-endmenu
-
-source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
-
-source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
-
-source "arch/sh/boards/renesas/r7780rp/Kconfig"
+endif
 
 config SH_TIMER_IRQ
 	int
-	default "28" if CPU_SUBTYPE_SH7780
+	default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
 	default "86" if CPU_SUBTYPE_SH7619
 	default "140" if CPU_SUBTYPE_SH7206
 	default "16"
@@ -462,7 +493,8 @@ config SH_PCLK_FREQ
 	default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
 			      CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
 			      CPU_SUBTYPE_SH7206
-	default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
+	default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 || \
+			      CPU_SUBTYPE_SH7785
 	default "60000000" if CPU_SUBTYPE_SH7751
 	default "66000000" if CPU_SUBTYPE_SH4_202
 	help
@@ -477,6 +509,8 @@ config SH_CLK_MD
 	help
 	  MD2 - MD0 pin setting.
 
+endmenu
+
 menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
@@ -495,21 +529,6 @@ config SH_CPU_FREQ
 
 endmenu
 
-source "arch/sh/drivers/dma/Kconfig"
-
-source "arch/sh/cchips/Kconfig"
-
-config HEARTBEAT
-	bool "Heartbeat LED"
-	depends on SH_MPC1211 || SH_SH03 || \
-		   SOLUTION_ENGINE || \
-		   SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK || \
-		   SH_R7780RP
-	help
-	  Use the power-on LED on your machine as a load meter.  The exact
-	  behavior is platform-dependent, but normally the flash frequency is
-	  a hyperbolic function of the 5-minute load average.
-
 source "arch/sh/drivers/Kconfig"
 
 endmenu
@@ -540,6 +559,20 @@ config KEXEC
 	  support.  As of this writing the exact hardware interface is
 	  strongly in flux, so no good recommendation can be made.
 
+config CRASH_DUMP
+	bool "kernel crash dumps (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	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 using
+	  MEMORY_START.
+
+	  For more details see Documentation/kdump/kdump.txt
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 87902e0..b563072 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -33,6 +33,7 @@ config EARLY_SCIF_CONSOLE_PORT
 	default "0xffe00000" if CPU_SUBTYPE_SH7780
 	default "0xfffe9800" if CPU_SUBTYPE_SH7206
 	default "0xf8420000" if CPU_SUBTYPE_SH7619
+	default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
 	default "0xffe80000" if CPU_SH4
 
 config EARLY_PRINTK
@@ -77,16 +78,17 @@ config 4KSTACKS
 	  on the VM subsystem for higher order allocations. This option
 	  will also use IRQ stacks to compensate for the reduced stackspace.
 
-config KGDB
+config SH_KGDB
 	bool "Include KGDB kernel debugger"
 	select FRAME_POINTER
+	select DEBUG_INFO
 	help
 	  Include in-kernel hooks for kgdb, the Linux kernel source level
 	  debugger.  See <http://kgdb.sourceforge.net/> for more information.
 	  Unless you are intending to debug the kernel, say N here.
 
 menu "KGDB configuration options"
-	depends on KGDB
+	depends on SH_KGDB
 
 config MORE_COMPILE_OPTIONS
 	bool "Add any additional compile options"
@@ -103,22 +105,16 @@ config KGDB_NMI
 	bool "Enter KGDB on NMI"
 	default n
 
-config KGDB_THREAD
-	bool "Include KGDB thread support"
-	default y
-
 config SH_KGDB_CONSOLE
 	bool "Console messages through GDB"
+	depends on !SERIAL_SH_SCI_CONSOLE
+	select SERIAL_CORE_CONSOLE
 	default n
 
 config KGDB_SYSRQ
 	bool "Allow SysRq 'G' to enter KGDB"
 	default y
 
-config KGDB_KERNEL_ASSERTS
-	bool "Include KGDB kernel assertions"
-	default n
-
 comment "Serial port setup"
 
 config KGDB_DEFPORT
@@ -131,7 +127,7 @@ config KGDB_DEFBAUD
 
 choice
 	prompt "Parity"
-	depends on KGDB
+	depends on SH_KGDB
 	default KGDB_DEFPARITY_N
 
 config KGDB_DEFPARITY_N
@@ -147,7 +143,7 @@ endchoice
 
 choice
 	prompt "Data bits"
-	depends on KGDB
+	depends on SH_KGDB
 	default KGDB_DEFBITS_8
 
 config KGDB_DEFBITS_8
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index bd9b172..7b11224 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN)	+= -m
 cflags-y	+= $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding
 
 cflags-$(CONFIG_SH_DSP)			+= -Wa,-dsp
-cflags-$(CONFIG_SH_KGDB)		+= -g
 
 cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
 	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
@@ -89,7 +88,9 @@ core-$(CONFIG_SH_FPU_EMU)	+= arch/sh/mat
 
 # Boards
 machdir-$(CONFIG_SH_SOLUTION_ENGINE)		:= se/770x
+machdir-$(CONFIG_SH_7722_SOLUTION_ENGINE)	:= se/7722
 machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE)	:= se/7751
+machdir-$(CONFIG_SH_7780_SOLUTION_ENGINE)	:= se/7780
 machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE)	:= se/7300
 machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE)	:= se/7343
 machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE)	:= se/73180
@@ -103,7 +104,7 @@ 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_HIGHLANDER)			:= renesas/r7780rp
 machdir-$(CONFIG_SH_7710VOIPGW)			:= renesas/sh7710voipgw
 machdir-$(CONFIG_SH_SH4202_MICRODEV)		:= superh/microdev
 machdir-$(CONFIG_SH_LANDISK)			:= landisk
@@ -111,6 +112,7 @@ machdir-$(CONFIG_SH_TITAN)			:= titan
 machdir-$(CONFIG_SH_SHMIN)			:= shmin
 machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE)	:= se/7206
 machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE)	:= se/7619
+machdir-$(CONFIG_SH_LBOX_RE2)			:= lboxre2
 machdir-$(CONFIG_SH_UNKNOWN)			:= unknown
 
 incdir-y			:= $(notdir $(machdir-y))
diff --git a/arch/sh/boards/hp6xx/Makefile b/arch/sh/boards/hp6xx/Makefile
index ff1b7f5..b312427 100644
--- a/arch/sh/boards/hp6xx/Makefile
+++ b/arch/sh/boards/hp6xx/Makefile
@@ -2,6 +2,6 @@ #
 # Makefile for the HP6xx specific parts of the kernel
 #
 
-obj-y	 		:= setup.o
+obj-y			:= setup.o
 obj-$(CONFIG_PM)	+= pm.o pm_wakeup.o
-obj-$(CONFIG_APM)	+= hp6xx_apm.o
+obj-$(CONFIG_APM_EMULATION)	+= hp6xx_apm.o
diff --git a/arch/sh/boards/hp6xx/pm.c b/arch/sh/boards/hp6xx/pm.c
index d194773..8143d1b 100644
--- a/arch/sh/boards/hp6xx/pm.c
+++ b/arch/sh/boards/hp6xx/pm.c
@@ -27,9 +27,6 @@ #ifdef CONFIG_HD64461_ENABLER
 	u16 hd64461_stbcr;
 #endif
 
-	if (state != PM_SUSPEND_MEM)
-		return -EINVAL;
-
 #ifdef CONFIG_HD64461_ENABLER
 	outb(0, HD64461_PCC1CSCIER);
 
@@ -70,12 +67,9 @@ #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,
+	.valid		= pm_valid_only_mem,
 };
 
 static int __init hp6x0_pm_init(void)
diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
index b5a9664..6aeee85 100644
--- a/arch/sh/boards/hp6xx/setup.c
+++ b/arch/sh/boards/hp6xx/setup.c
@@ -2,6 +2,7 @@
  * linux/arch/sh/boards/hp6xx/setup.c
  *
  * Copyright (C) 2002 Andriy Skulysh
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer_e1@hotmail.com>
  *
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
@@ -10,6 +11,7 @@
  */
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <asm/hd64461.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -19,6 +21,40 @@ #include <asm/cpu/dac.h>
 #define	SCPCR	0xa4000116
 #define SCPDR	0xa4000136
 
+/* CF Slot */
+static struct resource cf_ide_resources[] = {
+	[0] = {
+		.start = 0x15000000 + 0x1f0,
+		.end   = 0x15000000 + 0x1f0 + 0x08 - 0x01,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = 0x15000000 + 0x1fe,
+		.end   = 0x15000000 + 0x1fe + 0x01,
+		.flags = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start = 93,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_ide_device = {
+	.name		=  "pata_platform",
+	.id		=  -1,
+	.num_resources	= ARRAY_SIZE(cf_ide_resources),
+	.resource	= cf_ide_resources,
+};
+
+static struct platform_device *hp6xx_devices[] __initdata = {
+       &cf_ide_device,
+};
+
+static int __init hp6xx_devices_setup(void)
+{
+	return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices));
+}
+
 static void __init hp6xx_setup(char **cmdline_p)
 {
 	u8 v8;
@@ -60,41 +96,12 @@ #endif
 	v |= SCPCR_TS_ENABLE;
 	ctrl_outw(v, SCPCR);
 }
+device_initcall(hp6xx_devices_setup);
 
-/*
- * 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
index 89e4beb..a696b42 100644
--- a/arch/sh/boards/landisk/Makefile
+++ b/arch/sh/boards/landisk/Makefile
@@ -2,4 +2,4 @@ #
 # Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
 #
 
-obj-y	 := setup.o io.o irq.o rtc.o landisk_pwb.o
+obj-y	 := setup.o irq.o psw.o gio.o
diff --git a/arch/sh/boards/landisk/gio.c b/arch/sh/boards/landisk/gio.c
new file mode 100644
index 0000000..50d38be
--- /dev/null
+++ b/arch/sh/boards/landisk/gio.c
@@ -0,0 +1,167 @@
+/*
+ * arch/sh/boards/landisk/gio.c - driver for landisk
+ *
+ * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
+ * LANDISK and USL-5P Button, LED and GIO driver drive function.
+ *
+ *   Copylight (C) 2006 kogiidena
+ *   Copylight (C) 2002 Atom Create Engineering Co., Ltd. *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/landisk/gio.h>
+#include <asm/landisk/iodata_landisk.h>
+
+#define DEVCOUNT                4
+#define GIO_MINOR	        2	/* GIO minor no. */
+
+static dev_t dev;
+static struct cdev *cdev_p;
+static int openCnt;
+
+static int gio_open(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor < DEVCOUNT) {
+		if (openCnt > 0) {
+			return -EALREADY;
+		} else {
+			openCnt++;
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+static int gio_close(struct inode *inode, struct file *filp)
+{
+	int minor;
+
+	minor = MINOR(inode->i_rdev);
+	if (minor < DEVCOUNT) {
+		openCnt--;
+	}
+	return 0;
+}
+
+static int gio_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg)
+{
+	unsigned int data;
+	static unsigned int addr = 0;
+
+	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;
+	default:
+		return -EFAULT;
+		break;
+	}
+
+	if ((cmd & 0x01) == 0) {	/* read */
+		if (copy_to_user((int *)arg, &data, sizeof(int))) {
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+static struct file_operations gio_fops = {
+	.owner = THIS_MODULE,
+	.open = gio_open,	/* open */
+	.release = gio_close,	/* release */
+	.ioctl = gio_ioctl,	/* ioctl */
+};
+
+static int __init gio_init(void)
+{
+	int error;
+
+	printk(KERN_INFO "gio: driver initialized\n");
+
+	openCnt = 0;
+
+	if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {
+		printk(KERN_ERR
+		       "gio: Couldn't alloc_chrdev_region, error=%d\n",
+		       error);
+		return 1;
+	}
+
+	cdev_p = cdev_alloc();
+	cdev_p->ops = &gio_fops;
+	error = cdev_add(cdev_p, dev, DEVCOUNT);
+	if (error) {
+		printk(KERN_ERR
+		       "gio: Couldn't cdev_add, error=%d\n", error);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void __exit gio_exit(void)
+{
+	cdev_del(cdev_p);
+	unregister_chrdev_region(dev, DEVCOUNT);
+}
+
+module_init(gio_init);
+module_exit(gio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/sh/boards/landisk/io.c b/arch/sh/boards/landisk/io.c
deleted file mode 100644
index 92498b4..0000000
--- a/arch/sh/boards/landisk/io.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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
index 3eba6d0..2586494 100644
--- a/arch/sh/boards/landisk/irq.c
+++ b/arch/sh/boards/landisk/irq.c
@@ -1,18 +1,16 @@
 /*
  * arch/sh/boards/landisk/irq.c
  *
+ * I-O DATA Device, Inc. LANDISK Support
+ *
+ * Copyright (C) 2005-2007 kogiidena
+ *
  * 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
+ * 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>
@@ -20,71 +18,27 @@ #include <linux/interrupt.h>
 #include <linux/io.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);
+	ctrl_outb(ctrl_inb(PA_IMASK) & mask, 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);
+	ctrl_outb(ctrl_inb(PA_IMASK) | value, PA_IMASK);
 }
 
-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 struct irq_chip landisk_irq_chip __read_mostly = {
+	.name		= "LANDISK",
+	.mask		= disable_landisk_irq,
+	.unmask		= enable_landisk_irq,
+	.mask_ack	= disable_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
  */
@@ -92,6 +46,11 @@ void __init init_landisk_IRQ(void)
 {
 	int i;
 
-	for (i = 5; i < 14; i++)
-		make_landisk_irq(i);
+	for (i = 5; i < 14; i++) {
+		disable_irq_nosync(i);
+		set_irq_chip_and_handler_name(i, &landisk_irq_chip,
+					      handle_level_irq, "level");
+		enable_landisk_irq(i);
+	}
+	ctrl_outb(0x00, PA_PWRINT_CLR);
 }
diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c
deleted file mode 100644
index 47a63c6..0000000
--- a/arch/sh/boards/landisk/landisk_pwb.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * 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 const 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/psw.c b/arch/sh/boards/landisk/psw.c
new file mode 100644
index 0000000..5a9b70b
--- /dev/null
+++ b/arch/sh/boards/landisk/psw.c
@@ -0,0 +1,143 @@
+/*
+ * arch/sh/boards/landisk/psw.c
+ *
+ * push switch support for LANDISK and USL-5P
+ *
+ * Copyright (C) 2006-2007  Paul Mundt
+ * Copyright (C) 2007  kogiidena
+ *
+ * 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/io.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/landisk/iodata_landisk.h>
+#include <asm/push-switch.h>
+
+static irqreturn_t psw_irq_handler(int irq, void *arg)
+{
+	struct platform_device *pdev = arg;
+	struct push_switch *psw = platform_get_drvdata(pdev);
+	struct push_switch_platform_info *psw_info = pdev->dev.platform_data;
+	unsigned int sw_value;
+	int ret = 0;
+
+	sw_value = (0x0ff & (~ctrl_inb(PA_STATUS)));
+
+	/* Nothing to do if there's no state change */
+	if (psw->state) {
+		ret = 1;
+		goto out;
+	}
+
+	/* Figure out who raised it */
+	if (sw_value & (1 << psw_info->bit)) {
+		psw->state = 1;
+		mod_timer(&psw->debounce, jiffies + 50);
+		ret = 1;
+	}
+
+out:
+	/* Clear the switch IRQs */
+	ctrl_outb(0x00, PA_PWRINT_CLR);
+
+	return IRQ_RETVAL(ret);
+}
+
+static struct resource psw_power_resources[] = {
+	[0] = {
+		.start = IRQ_POWER,
+		.flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource psw_usl5p_resources[] = {
+	[0] = {
+		.start = IRQ_BUTTON,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct push_switch_platform_info psw_power_platform_data = {
+	.name		= "psw_power",
+	.bit		= 4,
+	.irq_flags	= IRQF_SHARED,
+	.irq_handler	= psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw1_platform_data = {
+	.name		= "psw1",
+	.bit		= 0,
+	.irq_flags	= IRQF_SHARED,
+	.irq_handler	= psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw2_platform_data = {
+	.name		= "psw2",
+	.bit		= 2,
+	.irq_flags	= IRQF_SHARED,
+	.irq_handler	= psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw3_platform_data = {
+	.name		= "psw3",
+	.bit		= 1,
+	.irq_flags	= IRQF_SHARED,
+	.irq_handler	= psw_irq_handler,
+};
+
+static struct platform_device psw_power_switch_device = {
+	.name		= "push-switch",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(psw_power_resources),
+	.resource	= psw_power_resources,
+	.dev		= {
+		.platform_data = &psw_power_platform_data,
+	},
+};
+
+static struct platform_device psw1_switch_device = {
+	.name		= "push-switch",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
+	.resource	= psw_usl5p_resources,
+	.dev		= {
+		.platform_data = &psw1_platform_data,
+	},
+};
+
+static struct platform_device psw2_switch_device = {
+	.name		= "push-switch",
+	.id		= 2,
+	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
+	.resource	= psw_usl5p_resources,
+	.dev		= {
+		.platform_data = &psw2_platform_data,
+	},
+};
+
+static struct platform_device psw3_switch_device = {
+	.name		= "push-switch",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(psw_usl5p_resources),
+	.resource	= psw_usl5p_resources,
+	.dev = {
+		.platform_data = &psw3_platform_data,
+	},
+};
+
+static struct platform_device *psw_devices[] = {
+	&psw_power_switch_device,
+	&psw1_switch_device,
+	&psw2_switch_device,
+	&psw3_switch_device,
+};
+
+static int __init psw_init(void)
+{
+	return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices));
+}
+module_init(psw_init);
diff --git a/arch/sh/boards/landisk/rtc.c b/arch/sh/boards/landisk/rtc.c
deleted file mode 100644
index 0a9a2a2..0000000
--- a/arch/sh/boards/landisk/rtc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * arch/sh/boards/landisk/rtc.c --  RTC support
- *
- *  Copyright (C) 2000  Philipp Rumpf <prumpf@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
index 122d699..a83a5d9 100644
--- a/arch/sh/boards/landisk/setup.c
+++ b/arch/sh/boards/landisk/setup.c
@@ -1,144 +1,90 @@
 /*
  * 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
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2002 Paul Mundt
+ * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2005-2007 kogiidena
  *
  * 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/pata_platform.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;
+static struct resource cf_ide_resources[3];
 
-        tmp1 = *p;
-        *p = 0x40;
-        tmp2 = *p;
-        *p = tmp1;
+static struct pata_platform_info pata_info = {
+	.ioport_shift	= 1,
+};
 
-        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;
-        }
-}
+static struct platform_device cf_ide_device = {
+	.name		= "pata_platform",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(cf_ide_resources),
+	.resource	= cf_ide_resources,
+	.dev		= {
+		.platform_data = &pata_info,
+	},
+};
 
-void *area5_io_base;
-void *area6_io_base;
+static struct platform_device *landisk_devices[] __initdata = {
+	&cf_ide_device,
+};
 
-static int __init landisk_cf_init(void)
+static int __init landisk_devices_setup(void)
 {
 	pgprot_t prot;
-	unsigned long paddrbase, psize;
+	unsigned long paddrbase;
+	void *cf_ide_base;
 
 	/* 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) {
+	cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+	if (!cf_ide_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;
+	/* IDE cmd address : 0x1f0-0x1f7 and 0x3f6 */
+	cf_ide_resources[0].start = (unsigned long)cf_ide_base + 0x40;
+	cf_ide_resources[0].end   = (unsigned long)cf_ide_base + 0x40 + 0x0f;
+	cf_ide_resources[0].flags = IORESOURCE_IO;
+	cf_ide_resources[1].start = (unsigned long)cf_ide_base + 0x2c;
+	cf_ide_resources[1].end   = (unsigned long)cf_ide_base + 0x2c + 0x03;
+	cf_ide_resources[1].flags = IORESOURCE_IO;
+	cf_ide_resources[2].start = IRQ_FATA;
+	cf_ide_resources[2].flags = IORESOURCE_IRQ;
+
+	return platform_add_devices(landisk_devices,
+				    ARRAY_SIZE(landisk_devices));
 }
 
+__initcall(landisk_devices_setup);
+
 static void __init landisk_setup(char **cmdline_p)
 {
-	device_initcall(landisk_cf_init);
-
-	landisk_buzzerparam = 0;
-	check_usl5p();
+        /* LED ON */
+	ctrl_outb(ctrl_inb(PA_LED) | 0x03, PA_LED);
 
 	printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n");
-
-	board_time_init = landisk_time_init;
 	pm_power_off = landisk_power_off;
 }
 
@@ -148,29 +94,6 @@ static void __init landisk_setup(char **
 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/lboxre2/Makefile b/arch/sh/boards/lboxre2/Makefile
new file mode 100644
index 0000000..e9ed140
--- /dev/null
+++ b/arch/sh/boards/lboxre2/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the L-BOX RE2 specific parts of the kernel
+# Copyright (c) 2007 Nobuhiro Iwamatsu
+
+obj-y	 := setup.o irq.o
diff --git a/arch/sh/boards/lboxre2/irq.c b/arch/sh/boards/lboxre2/irq.c
new file mode 100644
index 0000000..5a1c3bb
--- /dev/null
+++ b/arch/sh/boards/lboxre2/irq.c
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/sh/boards/lboxre2/irq.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 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/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/lboxre2.h>
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_lboxre2_IRQ(void)
+{
+	make_imask_irq(IRQ_CF1);
+	make_imask_irq(IRQ_CF0);
+	make_imask_irq(IRQ_INTD);
+	make_imask_irq(IRQ_ETH1);
+	make_imask_irq(IRQ_ETH0);
+	make_imask_irq(IRQ_INTA);
+}
diff --git a/arch/sh/boards/lboxre2/setup.c b/arch/sh/boards/lboxre2/setup.c
new file mode 100644
index 0000000..4e20f7c
--- /dev/null
+++ b/arch/sh/boards/lboxre2/setup.c
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/sh/boards/lbox/setup.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 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 <linux/pata_platform.h>
+#include <asm/machvec.h>
+#include <asm/addrspace.h>
+#include <asm/lboxre2.h>
+#include <asm/io.h>
+
+static struct resource cf_ide_resources[] = {
+	[0] = {
+		.start  = 0x1f0,
+		.end    = 0x1f0 + 8 ,
+		.flags  = IORESOURCE_IO,
+	},
+	[1] = {
+		.start  = 0x1f0 + 0x206,
+		.end    = 0x1f0 +8 + 0x206 + 8,
+		.flags  = IORESOURCE_IO,
+	},
+	[2] = {
+		.start  = IRQ_CF0,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_ide_device  = {
+	.name           = "pata_platform",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(cf_ide_resources),
+	.resource       = cf_ide_resources,
+};
+
+static struct platform_device *lboxre2_devices[] __initdata = {
+       &cf_ide_device,
+};
+
+static int __init lboxre2_devices_setup(void)
+{
+	u32 cf0_io_base;	/* Boot CF base address */
+	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);
+	cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot.pgprot);
+	if (!cf0_io_base) {
+		printk(KERN_ERR "%s : can't open CF I/O window!\n" , __func__ );
+		return -ENOMEM;
+	}
+
+	cf_ide_resources[0].start += cf0_io_base ;
+	cf_ide_resources[0].end   += cf0_io_base ;
+	cf_ide_resources[1].start += cf0_io_base ;
+	cf_ide_resources[1].end   += cf0_io_base ;
+
+	return platform_add_devices(lboxre2_devices,
+			ARRAY_SIZE(lboxre2_devices));
+
+}
+device_initcall(lboxre2_devices_setup);
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_lboxre2 __initmv = {
+	.mv_name		= "L-BOX RE2",
+	.mv_nr_irqs		= 72,
+	.mv_init_irq		= init_lboxre2_IRQ,
+};
+ALIAS_MV(lboxre2)
diff --git a/arch/sh/boards/renesas/r7780rp/Kconfig b/arch/sh/boards/renesas/r7780rp/Kconfig
index c26d981..9fb1164 100644
--- a/arch/sh/boards/renesas/r7780rp/Kconfig
+++ b/arch/sh/boards/renesas/r7780rp/Kconfig
@@ -1,14 +1,24 @@
-if SH_R7780RP
+if SH_HIGHLANDER
 
-menu "R7780RP options"
+choice
+	prompt "Highlander options"
+	default SH_R7780MP
+
+config SH_R7780RP
+	bool "R7780RP-1 board support"
+	select CPU_SUBTYPE_SH7780
 
 config SH_R7780MP
 	bool "R7780MP board support"
-	default y
+	select CPU_SUBTYPE_SH7780
 	help
 	  Selecting this option will enable support for the mass-production
 	  version of the R7780RP. If in doubt, say Y.
 
-endmenu
+config SH_R7785RP
+	bool "R7785RP board support"
+	select CPU_SUBTYPE_SH7785
+
+endchoice
 
 endif
diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
index ed5f5a9..609e5d5 100644
--- a/arch/sh/boards/renesas/r7780rp/Makefile
+++ b/arch/sh/boards/renesas/r7780rp/Makefile
@@ -1,7 +1,7 @@
 #
 # Makefile for the R7780RP-1 specific parts of the kernel
 #
-
-obj-y	 := setup.o irq.o
-
+irqinit-y			:= irq-r7780rp.o
+irqinit-$(CONFIG_SH_R7785RP)	:= irq-r7785rp.o
 obj-$(CONFIG_PUSH_SWITCH)	+= psw.o
+obj-y	 			:= setup.o irq.o $(irqinit-y)
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
new file mode 100644
index 0000000..f5f3587
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
@@ -0,0 +1,21 @@
+/*
+ * 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 <asm/io.h>
+#include <asm/r7780rp.h>
+
+void __init highlander_init_irq(void)
+{
+	int i;
+
+	for (i = 0; i < 15; i++)
+		make_r7780rp_irq(i);
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
new file mode 100644
index 0000000..dd6ec4c
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
@@ -0,0 +1,29 @@
+/*
+ * 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 <asm/io.h>
+#include <asm/r7780rp.h>
+
+void __init highlander_init_irq(void)
+{
+	ctrl_outw(0x0000, PA_IRLSSR1);	/* FPGA IRLSSR1(CF_CD clear) */
+
+	/* Setup the FPGA IRL */
+	ctrl_outw(0x0000, PA_IRLPRA);	/* FPGA IRLA */
+	ctrl_outw(0xe598, PA_IRLPRB);	/* FPGA IRLB */
+	ctrl_outw(0x7060, PA_IRLPRC);	/* FPGA IRLC */
+	ctrl_outw(0x0000, PA_IRLPRD);	/* FPGA IRLD */
+	ctrl_outw(0x4321, PA_IRLPRE);	/* FPGA IRLE */
+	ctrl_outw(0x0000, PA_IRLPRF);	/* FPGA IRLF */
+
+	make_r7780rp_irq(1);	/* CF card */
+	make_r7780rp_irq(10);	/* On-board ethernet */
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
index cc381e1..e0b8eb5 100644
--- a/arch/sh/boards/renesas/r7780rp/irq.c
+++ b/arch/sh/boards/renesas/r7780rp/irq.c
@@ -14,10 +14,12 @@ #include <linux/interrupt.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
+#ifdef CONFIG_SH_R7780RP
 static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
+#elif defined(CONFIG_SH_R7780MP)
+static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
+#elif defined(CONFIG_SH_R7785RP)
+static int mask_pos[] = {2, 11, 2, 2, 2, 2, 9, 8, 7, 5, 10, 2, 2, 2, 2, 2};
 #endif
 
 static void enable_r7780rp_irq(unsigned int irq)
@@ -40,17 +42,10 @@ static struct irq_chip r7780rp_irq_chip 
 	.mask_ack	= disable_r7780rp_irq,
 };
 
-/*
- * Initialize IRQ setting
- */
-void __init init_r7780rp_IRQ(void)
+void make_r7780rp_irq(unsigned int irq)
 {
-	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);
-	}
+	disable_irq_nosync(irq);
+	set_irq_chip_and_handler_name(irq, &r7780rp_irq_chip,
+				      handle_level_irq, "level");
+	enable_r7780rp_irq(irq);
 }
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index 2faba66..0727ef9 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -1,10 +1,13 @@
 /*
  * arch/sh/boards/renesas/r7780rp/setup.c
  *
+ * Renesas Solutions Highlander Support.
+ *
  * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
  * Copyright (C) 2005 - 2007 Paul Mundt
  *
- * Renesas Solutions Highlander R7780RP-1 Support.
+ * This contains support for the R7780RP-1, R7780MP, and R7785RP
+ * Highlander modules.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -18,32 +21,6 @@ #include <asm/r7780rp.h>
 #include <asm/clock.h>
 #include <asm/io.h>
 
-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 resource cf_ide_resources[] = {
 	[0] = {
 		.start	= PA_AREA5_IO + 0x1000,
@@ -56,10 +33,10 @@ static struct resource cf_ide_resources[
 		.flags	= IORESOURCE_MEM,
 	},
 	[2] = {
-#ifdef CONFIG_SH_R7780MP
-		.start	= 1,
-#else
+#ifdef CONFIG_SH_R7780RP
 		.start	= 4,
+#else
+		.start	= 1,
 #endif
 		.flags	= IORESOURCE_IRQ,
 	},
@@ -92,15 +69,18 @@ static struct resource heartbeat_resourc
 static struct platform_device heartbeat_device = {
 	.name		= "heartbeat",
 	.id		= -1,
+
+	/* R7785RP has a slightly more sensible FPGA.. */
+#ifndef CONFIG_SH_R7785RP
 	.dev	= {
 		.platform_data	= heartbeat_bit_pos,
 	},
+#endif
 	.num_resources	= ARRAY_SIZE(heartbeat_resources),
 	.resource	= heartbeat_resources,
 };
 
 static struct platform_device *r7780rp_devices[] __initdata = {
-	&m66596_usb_host_device,
 	&cf_ide_device,
 	&heartbeat_device,
 };
@@ -110,18 +90,19 @@ static int __init r7780rp_devices_setup(
 	return platform_add_devices(r7780rp_devices,
 				    ARRAY_SIZE(r7780rp_devices));
 }
+device_initcall(r7780rp_devices_setup);
 
 /*
  * Platform specific clocks
  */
 static void ivdr_clk_enable(struct clk *clk)
 {
-	ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << 8), PA_IVDRCTL);
+	ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL);
 }
 
 static void ivdr_clk_disable(struct clk *clk)
 {
-	ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << 8), PA_IVDRCTL);
+	ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL);
 }
 
 static struct clk_ops ivdr_clk_ops = {
@@ -140,22 +121,22 @@ static struct clk *r7780rp_clocks[] = {
 
 static void r7780rp_power_off(void)
 {
-#ifdef CONFIG_SH_R7780MP
-	ctrl_outw(0x0001, PA_POFF);
-#endif
+	if (mach_is_r7780mp() || mach_is_r7785rp())
+		ctrl_outw(0x0001, PA_POFF);
 }
 
 /*
  * Initialize the board
  */
-static void __init r7780rp_setup(char **cmdline_p)
+static void __init highlander_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 "Renesas Solutions Highlander %s support.\n",
+			 mach_is_r7780rp() ? "R7780RP-1" :
+			 mach_is_r7780mp() ? "R7780MP"	 :
+					     "R7785RP");
 
 	printk(KERN_INFO "Board version: %d (revision %d), "
 			 "FPGA version: %d (revision %d)\n",
@@ -173,9 +154,10 @@ static void __init r7780rp_setup(char **
 	}
 
 	ctrl_outw(0x0000, PA_OBLED);	/* Clear LED. */
-#ifndef CONFIG_SH_R7780MP
-	ctrl_outw(0x0001, PA_SDPOW);	/* SD Power ON */
-#endif
+
+	if (mach_is_r7780rp())
+		ctrl_outw(0x0001, PA_SDPOW);	/* SD Power ON */
+
 	ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x01, PA_IVDRCTL);	/* Si13112 */
 
 	pm_power_off = r7780rp_power_off;
@@ -184,10 +166,10 @@ #endif
 /*
  * The Machine Vector
  */
-struct sh_machine_vector mv_r7780rp __initmv = {
-	.mv_name		= "Highlander R7780RP-1",
-	.mv_setup		= r7780rp_setup,
+struct sh_machine_vector mv_highlander __initmv = {
+	.mv_name		= "Highlander",
 	.mv_nr_irqs		= 109,
-	.mv_init_irq		= init_r7780rp_IRQ,
+	.mv_setup		= highlander_setup,
+	.mv_init_irq		= highlander_init_irq,
 };
-ALIAS_MV(r7780rp)
+ALIAS_MV(highlander)
diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
index 9941949..c455047 100644
--- a/arch/sh/boards/se/770x/io.c
+++ b/arch/sh/boards/se/770x/io.c
@@ -27,6 +27,8 @@ int sh_pcic_io_dummy;
 static inline volatile __u16 *
 port2adr(unsigned int port)
 {
+	if (port & 0xff000000)
+		return ( volatile __u16 *) port;
 	if (port >= 0x2000)
 		return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
 	else if (port >= 0x1000)
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
index 307ca5d..c8eccff 100644
--- a/arch/sh/boards/se/770x/irq.c
+++ b/arch/sh/boards/se/770x/irq.c
@@ -55,23 +55,34 @@ void make_se770x_irq(struct ipr_data *ta
 }
 
 static struct ipr_data se770x_ipr_map[] = {
+	/*
+	* Super I/O (Just mimic PC):
+	*  1: keyboard
+	*  3: serial 0
+	*  4: serial 1
+	*  5: printer
+	*  6: floppy
+	*  8: rtc
+	* 12: mouse
+	* 14: ide0
+	*/
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
 	/* This is default value */
-	{ 0xf-0x2, 0, 8,  0x2 , BCR_ILCRA},
-	{ 0xf-0xa, 0, 4,  0xa , BCR_ILCRA},
-	{ 0xf-0x5, 0, 0,  0x5 , BCR_ILCRB},
-	{ 0xf-0x8, 0, 4,  0x8 , BCR_ILCRC},
-	{ 0xf-0xc, 0, 0,  0xc , BCR_ILCRC},
-	{ 0xf-0xe, 0, 12, 0xe , BCR_ILCRD},
-	{ 0xf-0x3, 0, 4,  0x3 , BCR_ILCRD}, /* LAN */
-	{ 0xf-0xd, 0, 8,  0xd , BCR_ILCRE},
-	{ 0xf-0x9, 0, 4,  0x9 , BCR_ILCRE},
-	{ 0xf-0x1, 0, 0,  0x1 , BCR_ILCRE},
-	{ 0xf-0xf, 0, 12, 0xf , BCR_ILCRF},
-	{ 0xf-0xb, 0, 4,  0xb , BCR_ILCRF},
-	{ 0xf-0x7, 0, 12, 0x7 , BCR_ILCRG},
-	{ 0xf-0x6, 0, 8,  0x6 , BCR_ILCRG},
-	{ 0xf-0x4, 0, 4,  0x4 , BCR_ILCRG},
+	{ 13, 0, 8,  0x0f-13 ,BCR_ILCRA},
+	{ 5 , 0, 4,  0x0f- 5 ,BCR_ILCRA},
+	{ 10, 0, 0,  0x0f-10, BCR_ILCRB},
+	{ 7 , 0, 4,  0x0f- 7, BCR_ILCRC},
+	{ 3 , 0, 0,  0x0f- 3, BCR_ILCRC},
+	{ 1 , 0, 12, 0x0f- 1, BCR_ILCRD},
+	{ 12, 0, 4,  0x0f-12, BCR_ILCRD}, /* LAN */
+	{ 2 , 0, 8,  0x0f- 2, BCR_ILCRE}, /* PCIRQ2 */
+	{ 6 , 0, 4,  0x0f- 6, BCR_ILCRE}, /* PCIRQ1 */
+	{ 14, 0, 0,  0x0f-14, BCR_ILCRE}, /* PCIRQ0 */
+	{ 0 , 0, 12, 0x0f   , BCR_ILCRF}, 
+	{ 4 , 0, 4,  0x0f- 4, BCR_ILCRF},
+	{ 8 , 0, 12, 0x0f- 8, BCR_ILCRG},
+	{ 9 , 0, 8,  0x0f- 9, BCR_ILCRG},
+	{ 11, 0, 4,  0x0f-11, BCR_ILCRG},
 #else
 	{ 14, 0,  8, 0x0f-14 ,BCR_ILCRA},
 	{ 12, 0,  4, 0x0f-12 ,BCR_ILCRA},
@@ -81,8 +92,10 @@ #else
 	{  4, 0,  4, 0x0f- 4 ,BCR_ILCRC},
 	{  3, 0,  0, 0x0f- 3 ,BCR_ILCRC},
 	{  1, 0, 12, 0x0f- 1 ,BCR_ILCRD},
+#if defined(CONFIG_STNIC)
 	/* ST NIC */
 	{ 10, 0,  4, 0x0f-10 ,BCR_ILCRD}, 	/* LAN */
+#endif
 	/* MRSHPC IRQs setting */
 	{  0, 0, 12, 0x0f- 0 ,BCR_ILCRE},	/* PCIRQ3 */
 	{ 11, 0,  8, 0x0f-11 ,BCR_ILCRE}, 	/* PCIRQ2 */
@@ -100,18 +113,6 @@ #endif
  */
 void __init init_se_IRQ(void)
 {
-        /*
-         * Super I/O (Just mimic PC):
-         *  1: keyboard
-         *  3: serial 0
-         *  4: serial 1
-         *  5: printer
-         *  6: floppy
-         *  8: rtc
-         * 12: mouse
-         * 14: ide0
-         */
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
 	/* Disable all interrupts */
 	ctrl_outw(0, BCR_ILCRA);
 	ctrl_outw(0, BCR_ILCRB);
@@ -120,6 +121,6 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7705)
 	ctrl_outw(0, BCR_ILCRE);
 	ctrl_outw(0, BCR_ILCRF);
 	ctrl_outw(0, BCR_ILCRG);
-#endif
+
 	make_se770x_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map));
 }
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
index 45cbc36..17a2631 100644
--- a/arch/sh/boards/se/770x/setup.c
+++ b/arch/sh/boards/se/770x/setup.c
@@ -63,6 +63,31 @@ static void __init smsc_setup(char **cmd
 	outb_p(CONFIG_EXIT, CONFIG_PORT);
 }
 
+
+static struct resource cf_ide_resources[] = {
+	[0] = {
+		.start  = PA_MRSHPC_IO + 0x1f0,
+		.end    = PA_MRSHPC_IO + 0x1f0 + 8,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = PA_MRSHPC_IO + 0x1f0 + 0x206,
+		.end    = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start  = IRQ_CFCARD,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_ide_device  = {
+	.name           = "pata_platform",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(cf_ide_resources),
+	.resource       = cf_ide_resources,
+};
+
 static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
 
 static struct resource heartbeat_resources[] = {
@@ -85,13 +110,14 @@ static struct platform_device heartbeat_
 
 static struct platform_device *se_devices[] __initdata = {
 	&heartbeat_device,
+	&cf_ide_device,
 };
 
 static int __init se_devices_setup(void)
 {
 	return platform_add_devices(se_devices, ARRAY_SIZE(se_devices));
 }
-__initcall(se_devices_setup);
+device_initcall(se_devices_setup);
 
 /*
  * The Machine Vector
@@ -107,6 +133,8 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
 	.mv_nr_irqs		= 61,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705)
 	.mv_nr_irqs		= 86,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+	.mv_nr_irqs             = 104,
 #endif
 
 	.mv_inb			= se_inb,
diff --git a/arch/sh/boards/se/7722/Makefile b/arch/sh/boards/se/7722/Makefile
new file mode 100644
index 0000000..8694373
--- /dev/null
+++ b/arch/sh/boards/se/7722/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the HITACHI UL SolutionEngine 7722 specific parts of the kernel
+#
+# 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.
+#
+#
+
+obj-y	 := setup.o irq.o
diff --git a/arch/sh/boards/se/7722/irq.c b/arch/sh/boards/se/7722/irq.c
new file mode 100644
index 0000000..099e5de
--- /dev/null
+++ b/arch/sh/boards/se/7722/irq.c
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/sh/boards/se/7722/irq.c
+ *
+ * Copyright (C) 2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 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/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/se7722.h>
+
+#define INTC_INTMSK0             0xFFD00044
+#define INTC_INTMSKCLR0          0xFFD00064
+
+static void disable_se7722_irq(unsigned int irq)
+{
+	struct ipr_data *p = get_irq_chip_data(irq);
+	ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+}
+
+static void enable_se7722_irq(unsigned int irq)
+{
+	struct ipr_data *p = get_irq_chip_data(irq);
+	ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+}
+
+static struct irq_chip se7722_irq_chip __read_mostly = {
+	.name           = "SE7722",
+	.mask           = disable_se7722_irq,
+	.unmask         = enable_se7722_irq,
+	.mask_ack       = disable_se7722_irq,
+};
+
+static struct ipr_data ipr_irq_table[] = {
+	/* irq        ,idx,sft, priority     , addr   */
+	{ MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
+	{ MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
+	{ MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
+	{ MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
+	{ SMC_IRQ     , 0 , 0 , SMC_BIT     , IRQ01_MASK } ,
+	{ EXT_IRQ     , 0 , 0 , EXT_BIT     , IRQ01_MASK } ,
+};
+
+int se7722_irq_demux(int irq)
+{
+
+	if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
+		volatile unsigned short intv =
+			*(volatile unsigned short *)IRQ01_STS;
+		if (irq == IRQ0_IRQ){
+			if(intv & SMC_BIT ) {
+				return SMC_IRQ;
+			} else if(intv & USB_BIT) {
+				return USB_IRQ;
+			} else {
+				printk("intv =%04x\n", intv);
+				return SMC_IRQ;
+			}
+		} else if(irq == IRQ1_IRQ){
+			if(intv & MRSHPC_BIT0) {
+				return MRSHPC_IRQ0;
+			} else if(intv & MRSHPC_BIT1) {
+				return MRSHPC_IRQ1;
+			} else if(intv & MRSHPC_BIT2) {
+				return MRSHPC_IRQ2;
+			} else if(intv & MRSHPC_BIT3) {
+				return MRSHPC_IRQ3;
+			} else {
+				printk("BIT_EXTENTION =%04x\n", intv);
+				return EXT_IRQ;
+			}
+		}
+	}
+	return irq;
+
+}
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se7722_IRQ(void)
+{
+	int i = 0;
+	ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
+	ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0);     /* irq0 pri=3,irq1,pri=3 */
+	ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1);        /* irq0,1 low-level irq */
+
+	for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
+		disable_irq_nosync(ipr_irq_table[i].irq);
+		set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
+			handle_level_irq, "level");
+		set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
+		disable_se7722_irq(ipr_irq_table[i].irq);
+	}
+}
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
new file mode 100644
index 0000000..636ca6c
--- /dev/null
+++ b/arch/sh/boards/se/7722/setup.c
@@ -0,0 +1,148 @@
+/*
+ * linux/arch/sh/boards/se/7722/setup.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 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 <linux/pata_platform.h>
+#include <asm/machvec.h>
+#include <asm/se7722.h>
+#include <asm/io.h>
+
+/* Heartbeat */
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static struct resource heartbeat_resources[] = {
+	[0] = {
+		.start  = PA_LED,
+		.end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device heartbeat_device = {
+	.name           = "heartbeat",
+	.id             = -1,
+	.dev    = {
+		.platform_data  = heartbeat_bit_pos,
+	},
+	.num_resources  = ARRAY_SIZE(heartbeat_resources),
+	.resource       = heartbeat_resources,
+};
+
+/* SMC91x */
+static struct resource smc91x_eth_resources[] = {
+	[0] = {
+		.name   = "smc91x-regs" ,
+		.start  = PA_LAN + 0x300,
+		.end    = PA_LAN + 0x300 + 0x10 ,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = SMC_IRQ,
+		.end    = SMC_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_eth_device = {
+	.name           = "smc91x",
+	.id             = 0,
+	.dev = {
+		.dma_mask               = NULL,         /* don't use dma */
+		.coherent_dma_mask      = 0xffffffff,
+	},
+	.num_resources  = ARRAY_SIZE(smc91x_eth_resources),
+	.resource       = smc91x_eth_resources,
+};
+
+static struct resource cf_ide_resources[] = {
+	[0] = {
+		.start  = PA_MRSHPC_IO + 0x1f0,
+		.end    = PA_MRSHPC_IO + 0x1f0 + 8 ,
+		.flags  = IORESOURCE_IO,
+	},
+	[1] = {
+		.start  = PA_MRSHPC_IO + 0x1f0 + 0x206,
+		.end    = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8,
+		.flags  = IORESOURCE_IO,
+	},
+	[2] = {
+		.start  = MRSHPC_IRQ0,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_ide_device  = {
+	.name           = "pata_platform",
+	.id             = -1,
+	.num_resources  = ARRAY_SIZE(cf_ide_resources),
+	.resource       = cf_ide_resources,
+};
+
+static struct platform_device *se7722_devices[] __initdata = {
+	&heartbeat_device,
+	&smc91x_eth_device,
+	&cf_ide_device,
+};
+
+static int __init se7722_devices_setup(void)
+{
+	return platform_add_devices(se7722_devices,
+		ARRAY_SIZE(se7722_devices));
+}
+device_initcall(se7722_devices_setup);
+
+static void __init se7722_setup(char **cmdline_p)
+{
+	ctrl_outw(0x010D, FPGA_OUT);    /* FPGA */
+
+	ctrl_outl(0x00051001, MSTPCR0);
+	ctrl_outl(0x00000000, MSTPCR1);
+	/* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */
+	ctrl_outl(0xffffbfC0, MSTPCR2); 
+
+	ctrl_outw(0x0000, PORT_PECR);   /* PORT E 1 = IRQ5 ,E 0 = BS */
+	ctrl_outw(0x1000, PORT_PJCR);   /* PORT J 1 = IRQ1,J 0 =IRQ0 */
+
+	/* LCDC I/O */
+	ctrl_outw(0x0020, PORT_PSELD);
+
+	/* SIOF1*/
+	ctrl_outw(0x0003, PORT_PSELB);
+	ctrl_outw(0xe000, PORT_PSELC);
+	ctrl_outw(0x0000, PORT_PKCR);
+
+	/* LCDC */
+	ctrl_outw(0x4020, PORT_PHCR);
+	ctrl_outw(0x0000, PORT_PLCR);
+	ctrl_outw(0x0000, PORT_PMCR);
+	ctrl_outw(0x0002, PORT_PRCR);
+	ctrl_outw(0x0000, PORT_PXCR);   /* LCDC,CS6A */
+
+	/* KEYSC */
+	ctrl_outw(0x0A10, PORT_PSELA); /* BS,SHHID2 */
+	ctrl_outw(0x0000, PORT_PYCR);
+	ctrl_outw(0x0000, PORT_PZCR);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_se7722 __initmv = {
+	.mv_name                = "Solution Engine 7722" ,
+	.mv_setup               = se7722_setup ,
+	.mv_nr_irqs		= 109 ,
+	.mv_init_irq		= init_se7722_IRQ,
+	.mv_irq_demux           = se7722_irq_demux,
+
+};
+ALIAS_MV(se7722)
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index e3feae6..770defe 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -14,153 +14,6 @@ #include <asm/machvec.h>
 #include <asm/se7751.h>
 #include <asm/io.h>
 
-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 };
-#endif
- 
-/*
- * Initialize the board
- */
-static void __init sh7751se_setup(char **cmdline_p)
-{
-	/* Call init_smsc() replacement to set up SuperIO. */
-	/* XXX: RTC setting comes here */
-#ifdef CONFIG_SH_KGDB
-	kgdb_register_sermap(&kgdb_uart_sermap);
-#endif
-}
-
-/*********************************************************************
- * Currently a hack (e.g. does not interact well w/serial.c, lots of *
- * hardcoded stuff) but may be useful if SCI/F needs debugging.      *
- * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and  *
- * arch/i386/lib/kgdb_serial.c).                                     *
- *********************************************************************/
-
-#ifdef CONFIG_SH_KGDB
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-
-#define COM1_PORT 0x3f8  /* Base I/O address */
-#define COM1_IRQ  4      /* IRQ not used yet */
-#define COM2_PORT 0x2f8  /* Base I/O address */
-#define COM2_IRQ  3      /* IRQ not used yet */
-
-#define SB_CLOCK 1843200 /* Serial baud clock */
-#define SB_BASE (SB_CLOCK/16)
-#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
-
-struct uart_port {
-	int base;
-};
-#define UART_NPORTS 2
-struct uart_port uart_ports[] = {
-	{ COM1_PORT },
-	{ COM2_PORT },
-};
-struct uart_port *kgdb_uart_port;
-
-#define UART_IN(reg)	inb_p(kgdb_uart_port->base + reg)
-#define UART_OUT(reg,v)	outb_p((v), kgdb_uart_port->base + reg)
-
-/* Basic read/write functions for the UART */
-#define UART_LSR_RXCERR    (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
-static int kgdb_uart_getchar(void)
-{
-	int lsr;
-	int c = -1;
-
-	while (c == -1) {
-		lsr = UART_IN(UART_LSR);
-		if (lsr & UART_LSR_DR) 
-			c = UART_IN(UART_RX);
-		if ((lsr & UART_LSR_RXCERR))
-			c = -1;
-	}
-	return c;
-}
-
-static void kgdb_uart_putchar(int c)
-{
-	while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
-		;
-	UART_OUT(UART_TX, c);
-}
-
-/*
- * Initialize UART to configured/requested values.
- * (But we don't interrupts yet, or interact w/serial.c)
- */
-static int kgdb_uart_setup(void)
-{
-	int port;
-	int lcr = 0;
-	int bdiv = 0;
-
-	if (kgdb_portnum >= UART_NPORTS) {
-		KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
-		return -1;
-	}
-
-	kgdb_uart_port = &uart_ports[kgdb_portnum];
-
-	/* Init sequence from gdb_hook_interrupt */
-	UART_IN(UART_RX);
-	UART_OUT(UART_IER, 0);
-
-	UART_IN(UART_RX);	/* Serial driver comments say */
-	UART_IN(UART_IIR);	/* this clears interrupt regs */
-	UART_IN(UART_MSR);
-
-	/* Figure basic LCR values */
-	switch (kgdb_bits) {
-	case '7':
-		lcr |= UART_LCR_WLEN7;
-		break;
-	default: case '8': 
-		lcr |= UART_LCR_WLEN8;
-		break;
-	}
-	switch (kgdb_parity) {
-	case 'O':
-		lcr |= UART_LCR_PARITY;
-		break;
-	case 'E':
-		lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
-		break;
-	default: break;
-	}
-
-	/* Figure the baud rate divisor */
-	bdiv = (SB_BASE/kgdb_baud);
-	
-	/* Set the baud rate and LCR values */
-	UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
-	UART_OUT(UART_DLL, (bdiv & 0xff));
-	UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
-	UART_OUT(UART_LCR, lcr);
-
-	/* Set the MCR */
-	UART_OUT(UART_MCR, SB_MCR);
-
-	/* Turn off FIFOs for now */
-	UART_OUT(UART_FCR, 0);
-
-	/* Setup complete: initialize function pointers */
-	kgdb_getchar = kgdb_uart_getchar;
-	kgdb_putchar = kgdb_uart_putchar;
-
-	return 0;
-}
-#endif /* CONFIG_SH_KGDB */
-
 static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
 
 static struct resource heartbeat_resources[] = {
@@ -197,7 +50,6 @@ __initcall(se7751_devices_setup);
  */
 struct sh_machine_vector mv_7751se __initmv = {
 	.mv_name		= "7751 SolutionEngine",
-	.mv_setup		= sh7751se_setup,
 	.mv_nr_irqs		= 72,
 
 	.mv_inb			= sh7751se_inb,
diff --git a/arch/sh/boards/se/7780/Makefile b/arch/sh/boards/se/7780/Makefile
new file mode 100644
index 0000000..6b88ada
--- /dev/null
+++ b/arch/sh/boards/se/7780/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the HITACHI UL SolutionEngine 7780 specific parts of the kernel
+#
+# 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.
+#
+#
+
+obj-y	 := setup.o irq.o
diff --git a/arch/sh/boards/se/7780/irq.c b/arch/sh/boards/se/7780/irq.c
new file mode 100644
index 0000000..3d0625c
--- /dev/null
+++ b/arch/sh/boards/se/7780/irq.c
@@ -0,0 +1,89 @@
+/*
+ * linux/arch/sh/boards/se/7780/irq.c
+ *
+ * Copyright (C) 2006,2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 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/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/se7780.h>
+
+#define INTC_INTMSK0             0xFFD00044
+#define INTC_INTMSKCLR0          0xFFD00064
+
+static void disable_se7780_irq(unsigned int irq)
+{
+	struct intc2_data *p = get_irq_chip_data(irq);
+	ctrl_outl(1 << p->msk_shift, INTC_INTMSK0 + p->msk_offset);
+}
+
+static void enable_se7780_irq(unsigned int irq)
+{
+	struct intc2_data *p = get_irq_chip_data(irq);
+	ctrl_outl(1 << p->msk_shift, INTC_INTMSKCLR0 + p->msk_offset);
+}
+
+static struct irq_chip se7780_irq_chip __read_mostly = {
+	.name           = "SE7780",
+	.mask           = disable_se7780_irq,
+	.unmask         = enable_se7780_irq,
+	.mask_ack       = disable_se7780_irq,
+};
+
+static struct intc2_data intc2_irq_table[] = {
+	{ 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */
+	{ 4,  0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */
+	{ 6,  0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */
+	{ 8,  0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */
+	{ 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */
+	{ 4,  0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */
+	{ 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */
+	{ 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */
+	{ 2,  0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */
+	{ 0 , 0, 24, 0, 24, 3 }, /* SM501 */
+};
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se7780_IRQ(void)
+{
+	int i ;
+
+	/* enable all interrupt at FPGA */
+	ctrl_outw(0, FPGA_INTMSK1);
+	/* mask SM501 interrupt */
+	ctrl_outw((ctrl_inw(FPGA_INTMSK1) | 0x0002), FPGA_INTMSK1);
+	/* enable all interrupt at FPGA */
+	ctrl_outw(0, FPGA_INTMSK2);
+
+	/* set FPGA INTSEL register */
+	/* FPGA + 0x06 */
+	ctrl_outw( ((IRQPIN_SM501 << IRQPOS_SM501) |
+		(IRQPIN_SMC91CX << IRQPOS_SMC91CX)), FPGA_INTSEL1);
+
+	/* FPGA + 0x08 */
+	ctrl_outw(((IRQPIN_EXTINT4 << IRQPOS_EXTINT4) |
+		(IRQPIN_EXTINT3 << IRQPOS_EXTINT3) |
+		(IRQPIN_EXTINT2 << IRQPOS_EXTINT2) |
+		(IRQPIN_EXTINT1 << IRQPOS_EXTINT1)), FPGA_INTSEL2);
+
+	/* FPGA + 0x0A */
+	ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
+
+	for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) {
+		disable_irq_nosync(intc2_irq_table[i].irq);
+		set_irq_chip_and_handler_name( intc2_irq_table[i].irq, &se7780_irq_chip,
+			handle_level_irq, "level");
+		set_irq_chip_data( intc2_irq_table[i].irq, &intc2_irq_table[i] );
+		disable_se7780_irq(intc2_irq_table[i].irq);
+	}
+}
diff --git a/arch/sh/boards/se/7780/setup.c b/arch/sh/boards/se/7780/setup.c
new file mode 100644
index 0000000..df7d08a
--- /dev/null
+++ b/arch/sh/boards/se/7780/setup.c
@@ -0,0 +1,122 @@
+/*
+ * linux/arch/sh/boards/se/7780/setup.c
+ *
+ * Copyright (C) 2006,2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 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/se7780.h>
+#include <asm/io.h>
+
+/* Heartbeat */
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static struct resource heartbeat_resources[] = {
+	[0] = {
+		.start  = PA_LED,
+		.end    = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device heartbeat_device = {
+	.name           = "heartbeat",
+	.id             = -1,
+	.dev    = {
+		.platform_data  = heartbeat_bit_pos,
+	},
+	.num_resources  = ARRAY_SIZE(heartbeat_resources),
+	.resource       = heartbeat_resources,
+};
+
+/* SMC91x */
+static struct resource smc91x_eth_resources[] = {
+	[0] = {
+		.name   = "smc91x-regs" ,
+		.start  = PA_LAN + 0x300,
+		.end    = PA_LAN + 0x300 + 0x10 ,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = SMC_IRQ,
+		.end    = SMC_IRQ,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_eth_device = {
+	.name           = "smc91x",
+	.id             = 0,
+	.dev = {
+		.dma_mask               = NULL,         /* don't use dma */
+		.coherent_dma_mask      = 0xffffffff,
+	},
+	.num_resources  = ARRAY_SIZE(smc91x_eth_resources),
+	.resource       = smc91x_eth_resources,
+};
+
+static struct platform_device *se7780_devices[] __initdata = {
+	&heartbeat_device,
+	&smc91x_eth_device,
+};
+
+static int __init se7780_devices_setup(void)
+{
+	return platform_add_devices(se7780_devices,
+		ARRAY_SIZE(se7780_devices));
+}
+device_initcall(se7780_devices_setup);
+
+#define GPIO_PHCR        0xFFEA000E
+#define GPIO_PMSELR      0xFFEA0080
+#define GPIO_PECR        0xFFEA0008
+
+static void __init se7780_setup(char **cmdline_p)
+{
+	/* "SH-Linux" on LED Display */
+	ctrl_outw( 'S' , PA_LED_DISP + (DISP_SEL0_ADDR << 1) );
+	ctrl_outw( 'H' , PA_LED_DISP + (DISP_SEL1_ADDR << 1) );
+	ctrl_outw( '-' , PA_LED_DISP + (DISP_SEL2_ADDR << 1) );
+	ctrl_outw( 'L' , PA_LED_DISP + (DISP_SEL3_ADDR << 1) );
+	ctrl_outw( 'i' , PA_LED_DISP + (DISP_SEL4_ADDR << 1) );
+	ctrl_outw( 'n' , PA_LED_DISP + (DISP_SEL5_ADDR << 1) );
+	ctrl_outw( 'u' , PA_LED_DISP + (DISP_SEL6_ADDR << 1) );
+	ctrl_outw( 'x' , PA_LED_DISP + (DISP_SEL7_ADDR << 1) );
+
+	printk(KERN_INFO "Hitachi UL Solutions Engine 7780SE03 support.\n");
+
+	/*
+	 * PCI REQ/GNT setting
+	 *   REQ0/GNT0 -> USB
+	 *   REQ1/GNT1 -> PC Card
+	 *   REQ2/GNT2 -> Serial ATA
+	 *   REQ3/GNT3 -> PCI slot
+	 */
+	ctrl_outw(0x0213, FPGA_REQSEL);
+
+	/* GPIO setting */
+	ctrl_outw(0x0000, GPIO_PECR);
+	ctrl_outw(ctrl_inw(GPIO_PHCR)&0xfff3, GPIO_PHCR);
+	ctrl_outw(0x0c00, GPIO_PMSELR);
+
+	/* iVDR Power ON */
+	ctrl_outw(0x0001, FPGA_IVDRPW);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_se7780 __initmv = {
+	.mv_name                = "Solution Engine 7780" ,
+	.mv_setup               = se7780_setup ,
+	.mv_nr_irqs		= 111 ,
+	.mv_init_irq		= init_se7780_IRQ,
+};
+ALIAS_MV(se7780)
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
new file mode 100644
index 0000000..be86414
--- /dev/null
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -0,0 +1,1271 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Sat Mar 24 22:04:27 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 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_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# 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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+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_SATURN is not set
+# CONFIG_SH_DREAMCAST 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_HIGHLANDER 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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+CONFIG_SH_LBOX_RE2=y
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 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_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB 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_ZONE_DMA_FLAG=0
+
+#
+# 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_CPU_BIG_ENDIAN is not set
+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_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=40000000
+
+#
+# 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
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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=y
+CONFIG_CMDLINE="console=ttySC1,115200 root=/dev/sda1"
+
+#
+# Bus options
+#
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_DEBUG=y
+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 is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# 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_XFRM_MIGRATE 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_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_TCP_MD5SIG is not set
+
+#
+# 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_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES 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 is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+# CONFIG_PNPACPI 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# 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_TGT is not set
+# 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 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_QLA_ISCSI 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
+# CONFIG_SCSI_SRP 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=y
+# CONFIG_ATA_NONSTANDARD is not set
+# 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_SATA_INIC162X 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_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL 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_PCMCIA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_QDI 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
+# CONFIG_PATA_WINBOND_VLB is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI 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_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=y
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+CONFIG_8139TOO_PIO=y
+CONFIG_8139TOO_TUNE_TWISTER=y
+# 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_SC92031 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
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC 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=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=y
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_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
+# 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
+
+#
+# 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_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 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
+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 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_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=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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL 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
+# CONFIG_SH_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_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
index 2b75b48..48c6a21 100644
--- a/arch/sh/configs/r7780rp_defconfig
+++ b/arch/sh/configs/r7780rp_defconfig
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Wed Dec  6 11:59:38 2006
+# Linux kernel version: 2.6.21-rc7
+# Tue May  1 12:28:39 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -13,6 +14,8 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 # CONFIG_GENERIC_TIME is not set
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -31,6 +34,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
@@ -41,7 +45,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_SYSFS_DEPRECATED is not set
 # CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
@@ -99,23 +103,23 @@ #
 # System type
 #
 # CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7722_SOLUTION_ENGINE is not set
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_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_HIGHLANDER=y
 # CONFIG_SH_EDOSK7705 is not set
 # CONFIG_SH_SH4202_MICRODEV is not set
 # CONFIG_SH_LANDISK is not set
@@ -123,7 +127,11 @@ # CONFIG_SH_TITAN is not set
 # CONFIG_SH_SHMIN is not set
 # CONFIG_SH_7206_SOLUTION_ENGINE is not set
 # CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
 # CONFIG_SH_UNKNOWN is not set
+CONFIG_SH_R7780RP=y
+# CONFIG_SH_R7780MP is not set
+# CONFIG_SH_R7785RP is not set
 
 #
 # Processor selection
@@ -152,6 +160,7 @@ # 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
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
 
 #
 # SH-4 Processor Support
@@ -183,6 +192,7 @@ # SH4AL-DSP Processor Support
 #
 # CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
 
 #
 # Memory management options
@@ -193,6 +203,8 @@ CONFIG_MEMORY_START=0x08000000
 CONFIG_MEMORY_SIZE=0x08000000
 # CONFIG_32BIT is not set
 CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
@@ -210,6 +222,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 
 #
 # Cache configuration
@@ -226,20 +239,15 @@ # CONFIG_CPU_BIG_ENDIAN is not set
 CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 CONFIG_SH_STORE_QUEUES=y
+CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_INTC2_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
-CONFIG_CPU_HAS_PTEA=y
 
 #
-# Timer support
+# Timer and clock configuration
 #
 CONFIG_SH_TMU=y
-
-#
-# R7780RP options
-#
-CONFIG_SH_R7780MP=y
 CONFIG_SH_TIMER_IRQ=28
 CONFIG_NO_IDLE_HZ=y
 CONFIG_SH_PCLK_FREQ=32000000
@@ -262,6 +270,7 @@ # CONFIG_HD6446X_SERIES is not set
 #
 # Additional SuperH Device Drivers
 #
+# CONFIG_HEARTBEAT is not set
 CONFIG_PUSH_SWITCH=y
 
 #
@@ -269,9 +278,11 @@ # Kernel features
 #
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT_NONE is not set
 # CONFIG_PREEMPT_VOLUNTARY is not set
@@ -294,7 +305,6 @@ 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
 
 #
@@ -334,6 +344,7 @@ CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -425,6 +436,7 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 
 #
@@ -445,6 +457,7 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -461,7 +474,6 @@ 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
 
@@ -481,6 +493,7 @@ # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
 
@@ -500,6 +513,7 @@ #
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
 
 #
 # SCSI Transports
@@ -544,11 +558,13 @@ # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
 
 #
 # Serial ATA (prod) and Parallel ATA (experimental) drivers
 #
 CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
 # CONFIG_SATA_AHCI is not set
 # CONFIG_SATA_SVW is not set
 # CONFIG_ATA_PIIX is not set
@@ -564,6 +580,7 @@ # 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_SATA_INIC162X is not set
 # CONFIG_PATA_ALI is not set
 # CONFIG_PATA_AMD is not set
 # CONFIG_PATA_ARTOP is not set
@@ -579,6 +596,7 @@ # 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_IT8213 is not set
 # CONFIG_PATA_JMICRON is not set
 # CONFIG_PATA_TRIFLEX is not set
 # CONFIG_PATA_MARVELL is not set
@@ -685,6 +703,7 @@ # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
 CONFIG_VIA_RHINE_MMIO=y
 # CONFIG_VIA_RHINE_NAPI is not set
+# CONFIG_SC92031 is not set
 
 #
 # Ethernet (1000 Mbit)
@@ -707,11 +726,13 @@ # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
@@ -889,10 +910,16 @@ CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -905,9 +932,8 @@ # CONFIG_DVB is not set
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
 
 #
 # Sound
@@ -923,9 +949,8 @@ #
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=m
-# CONFIG_OSS_OBSOLETE_DRIVER is not set
+# CONFIG_OBSOLETE_OSS 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
@@ -933,6 +958,12 @@ # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_VIA82CXXX is not set
 
 #
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
 # USB support
 #
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1017,6 +1048,14 @@ # DMA Devices
 #
 
 #
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -1175,6 +1214,11 @@ # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
 # Profiling support
 #
 CONFIG_PROFILING=y
@@ -1184,19 +1228,22 @@ #
 # Kernel hacking
 #
 CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_TIME is not set
 CONFIG_ENABLE_MUST_CHECK=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_PREEMPT 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
@@ -1204,19 +1251,19 @@ # CONFIG_DEBUG_LOCKING_API_SELFTESTS is 
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_LIST is not set
-CONFIG_FRAME_POINTER=y
+# CONFIG_FRAME_POINTER is not set
 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_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
 # CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_4KSTACKS is not set
-# CONFIG_KGDB is not set
+# CONFIG_SH_KGDB is not set
 
 #
 # Security options
@@ -1233,6 +1280,7 @@ CONFIG_CRYPTO_BLKCIPHER=y
 CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
@@ -1241,9 +1289,13 @@ # 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_GF128MUL is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
 CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
@@ -1257,6 +1309,7 @@ # 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_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
@@ -1266,7 +1319,10 @@ #
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
new file mode 100644
index 0000000..0f5ec64
--- /dev/null
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -0,0 +1,1334 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 12 14:26:33 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 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_SYSVIPC_SYSCTL=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_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+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=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=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_SATURN is not set
+# CONFIG_SH_DREAMCAST 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_HIGHLANDER=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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_R7780MP is not set
+CONFIG_SH_R7785RP=y
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+CONFIG_CPU_SUBTYPE_SH7785=y
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_32BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+CONFIG_HUGETLB_PAGE_SIZE_1MB=y
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB 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_ZONE_DMA_FLAG=0
+
+#
+# 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_CPU_BIG_ENDIAN is not set
+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
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+CONFIG_NO_IDLE_HZ=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
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+CONFIG_PUSH_SWITCH=y
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=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
+#
+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 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_DEBUG is not set
+
+#
+# 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_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_XFRM_MIGRATE 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_TCP_MD5SIG 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 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_DEBUG_DEVRES 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
+#
+# CONFIG_PNPACPI 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 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_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_TGT is not set
+# 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
+# CONFIG_SCSI_SCAN_ASYNC 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
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# 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_SATA_INIC162X 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_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL 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
+CONFIG_PATA_PLATFORM=y
+
+#
+# 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 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=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_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC 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 is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+# CONFIG_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=6
+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
+# 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_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# 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
+# CONFIG_FB_SVGALIB 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
+
+#
+# Frambuffer hardware drivers
+#
+# 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_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 is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 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
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OBSOLETE_OSS is not set
+# CONFIG_SOUND_BT878 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
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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=m
+
+#
+# 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=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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=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_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_PROVE_LOCKING is not set
+CONFIG_LOCKDEP=y
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_4KSTACKS is not set
+# CONFIG_SH_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_XCBC 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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
index 06ebd6e..87ae5c1 100644
--- a/arch/sh/configs/se7705_defconfig
+++ b/arch/sh/configs/se7705_defconfig
@@ -1,15 +1,21 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct  3 12:03:04 2006
+# Linux kernel version: 2.6.21-rc5
+# Thu Apr 26 09:16:31 2007
 #
 CONFIG_SUPERH=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -33,7 +39,9 @@ # CONFIG_TASKSTATS is not set
 # CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
@@ -91,27 +99,30 @@ #
 CONFIG_SOLUTION_ENGINE=y
 CONFIG_SH_SOLUTION_ENGINE=y
 # CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_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_7722_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_HIGHLANDER 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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
 # CONFIG_SH_UNKNOWN is not set
 
 #
@@ -123,6 +134,12 @@ #
 # SH-2 Processor Support
 #
 # CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
 
 #
 # SH-3 Processor Support
@@ -134,6 +151,7 @@ # 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
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
 
 #
 # SH-4 Processor Support
@@ -158,12 +176,14 @@ # SH-4A Processor Support
 #
 # CONFIG_CPU_SUBTYPE_SH7770 is not set
 # CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
 
 #
 # SH4AL-DSP Processor Support
 #
 # CONFIG_CPU_SUBTYPE_SH73180 is not set
 # CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
 
 #
 # Memory management options
@@ -173,6 +193,11 @@ CONFIG_PAGE_OFFSET=0x80000000
 CONFIG_MEMORY_START=0x0c000000
 CONFIG_MEMORY_SIZE=0x02000000
 CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -182,6 +207,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 
 #
 # Cache configuration
@@ -190,23 +216,31 @@ 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_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+# CONFIG_CF_AREA4 is not set
+CONFIG_CF_BASE_ADDR=0xb8000000
 
 #
 # Processor features
 #
 CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
 # 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_PINT_IRQ=y
+CONFIG_CPU_HAS_IPR_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
-# Timer support
+# Timer and clock configuration
 #
 CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
 CONFIG_SH_PCLK_FREQ=33333333
 
 #
@@ -223,13 +257,19 @@ #
 # Companion Chips
 #
 # CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
 CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
 
 #
 # Kernel features
 #
 # CONFIG_HZ_100 is not set
 CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 # CONFIG_KEXEC is not set
@@ -287,6 +327,7 @@ CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -307,11 +348,13 @@ # 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_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
@@ -388,6 +431,7 @@ #
 # User Modules And Translation Layers
 #
 CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
@@ -461,6 +505,7 @@ # CONFIG_PARPORT is not set
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -472,11 +517,14 @@ 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
 
 #
+# Misc devices
+#
+
+#
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -649,17 +697,12 @@ 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
@@ -675,6 +718,7 @@ # CONFIG_SPI_MASTER is not set
 #
 # Dallas's 1-wire bus
 #
+# CONFIG_W1 is not set
 
 #
 # Hardware Monitoring support
@@ -683,18 +727,19 @@ CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_VT1211 is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
-# Misc devices
+# Multifunction device drivers
 #
+# CONFIG_MFD_SM501 is not set
 
 #
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
 
 #
 # Digital Video Broadcasting Devices
@@ -704,7 +749,7 @@ # CONFIG_DVB is not set
 #
 # Graphics support
 #
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 # CONFIG_FB is not set
 
 #
@@ -713,6 +758,12 @@ #
 # CONFIG_SOUND is not set
 
 #
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
 # USB support
 #
 # CONFIG_USB_ARCH_HAS_HCD is not set
@@ -773,16 +824,26 @@ # DMA Devices
 #
 
 #
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
 # 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_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_INOTIFY=y
@@ -828,7 +889,6 @@ # 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
@@ -878,6 +938,10 @@ #
 # CONFIG_NLS is not set
 
 #
+# Distributed Lock Manager
+#
+
+#
 # Profiling support
 #
 # CONFIG_PROFILING is not set
@@ -885,15 +949,18 @@ # 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_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL 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
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
 
 #
 # Security options
@@ -908,6 +975,7 @@ # CONFIG_CRYPTO is not set
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=y
 # CONFIG_CRC16 is not set
 CONFIG_CRC32=y
@@ -915,3 +983,5 @@ # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
 CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
new file mode 100644
index 0000000..a5e37db
--- /dev/null
+++ b/arch/sh/configs/se7712_defconfig
@@ -0,0 +1,1088 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Wed Mar 28 10:19:02 2007
+#
+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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 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 is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_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_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=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_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST 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_HIGHLANDER 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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 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
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+CONFIG_CPU_SUBTYPE_SH7712=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
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB 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_ZONE_DMA_FLAG=0
+
+#
+# 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
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# 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_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# 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
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# 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=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
+
+#
+# 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_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE 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=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=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_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 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG 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 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_FIFO=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=y
+CONFIG_NET_SCH_HFSC=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_RED=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TEQL=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_GRED=y
+CONFIG_NET_SCH_DSMARK=y
+CONFIG_NET_SCH_NETEM=y
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_ROUTE4=y
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=y
+# CONFIG_NET_CLS_U32 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 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 is not set
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES 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=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_BLKDEVS=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 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# 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 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# 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
+#
+
+#
+# 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 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 is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 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 is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# 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=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+
+#
+# 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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 is not set
+# CONFIG_EXT4DEV_FS 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 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_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=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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# 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_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS 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_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=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION 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_SH_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_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+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_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# 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=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+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
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
new file mode 100644
index 0000000..ca4c663
--- /dev/null
+++ b/arch/sh/configs/se7722_defconfig
@@ -0,0 +1,980 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc7
+# Fri Apr 27 16:30:30 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 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_SYSVIPC_SYSCTL=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_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=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 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_SOLUTION_ENGINE=y
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_7722_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_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_SATURN is not set
+# CONFIG_SH_DREAMCAST 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_HIGHLANDER 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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SH4AL_DSP=y
+CONFIG_CPU_SHX2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+# CONFIG_CPU_SUBTYPE_SH7712 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
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+CONFIG_CPU_SUBTYPE_SH7722=y
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+# CONFIG_32BIT is not set
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB 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_ZONE_DMA_FLAG=0
+
+#
+# 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
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_NO_IDLE_HZ=y
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# 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
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP 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 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_XFRM_MIGRATE 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_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_TCP_MD5SIG 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 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
+#
+# CONFIG_PNPACPI is not set
+
+#
+# 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=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# 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 is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC 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_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# 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=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_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_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_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_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=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
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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 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=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=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 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
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_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_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
new file mode 100644
index 0000000..538661e
--- /dev/null
+++ b/arch/sh/configs/se7780_defconfig
@@ -0,0 +1,1309 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Thu Mar 15 14:06:20 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=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_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+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_SYSVIPC_SYSCTL=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_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# 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 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_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 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_7780_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_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST 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_HIGHLANDER 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_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE 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
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 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
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_32BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB 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_ZONE_DMA_FLAG=0
+
+#
+# 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_CPU_BIG_ENDIAN is not set
+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_INTC2_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# 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
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# 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=0x00810000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+
+#
+# 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
+
+#
+# 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 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_IP_MROUTE 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=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_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT 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
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK 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_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_BLKDEVS=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=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 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+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 is not set
+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 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=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_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
+#
+# CONFIG_PNPACPI 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_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 is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 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=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
+# CONFIG_SCSI_SCAN_ASYNC 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_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX 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_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_AMD is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM 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=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# 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=y
+# CONFIG_BROADCOM_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=y
+
+#
+# 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_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_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_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC 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_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC 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 is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# 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_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 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_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=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
+# CONFIG_FB_SVGALIB 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
+
+#
+# Frambuffer hardware drivers
+#
+# 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_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 is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 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_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_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS is not set
+# CONFIG_SOUND_BT878 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
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG 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=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO 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_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM 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_POWERBOOK 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_TOUCHSCREEN 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_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_USBNET_MII 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_LCD is not set
+# CONFIG_USB_BERRY_CHARGE 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_IOWARRIOR 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
+#
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# 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_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 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=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE 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_HFSPLUS_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_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_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# 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_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# 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
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/drivers/Kconfig b/arch/sh/drivers/Kconfig
index c54c758..420c6b2 100644
--- a/arch/sh/drivers/Kconfig
+++ b/arch/sh/drivers/Kconfig
@@ -1,5 +1,15 @@
+source "arch/sh/drivers/dma/Kconfig"
+source "arch/sh/cchips/Kconfig"
+
 menu "Additional SuperH Device Drivers"
 
+config HEARTBEAT
+	bool "Heartbeat LED"
+	help
+	  Use the power-on LED on your machine as a load meter.  The exact
+	  behavior is platform-dependent, but normally the flash frequency is
+	  a hyperbolic function of the 5-minute load average.
+
 config PUSH_SWITCH
 	tristate "Push switch support"
 	help
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index bc59cb6..23dd608 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -40,16 +40,9 @@ static void heartbeat_timer(unsigned lon
 	static unsigned bit = 0, up = 1;
 
 	ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base);
-	if (up)
-		if (bit == (ARRAY_SIZE(hd->bit_pos) - 1)) {
-			bit--;
-			up = 0;
-		} else
-			bit++;
-	else if (bit == 0)
-		up = 1;
-	else
-		bit--;
+	bit += up;
+	if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1))
+		up = -up;
 
 	mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
 			((avenrun[0] / 5) + (3 << FSHIFT)))));
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index cc8d0d0..0e9b532 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -8,12 +8,15 @@ obj-$(CONFIG_PCI_AUTO)			+= pci-auto.o
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= pci-st40.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_CPU_SUBTYPE_SH7785)	+= pci-sh7780.o ops-sh4.o
 
 obj-$(CONFIG_SH_DREAMCAST)		+= ops-dreamcast.o fixups-dreamcast.o \
 					   dma-dreamcast.o
 obj-$(CONFIG_SH_SECUREEDGE5410)		+= ops-snapgear.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_HIGHLANDER)		+= ops-r7780rp.o fixups-r7780rp.o
 obj-$(CONFIG_SH_TITAN)			+= ops-titan.o
 obj-$(CONFIG_SH_LANDISK)		+= ops-landisk.o
+obj-$(CONFIG_SH_LBOX_RE2)		+= ops-lboxre2.o fixups-lboxre2.o
+obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)	+= ops-se7780.o fixups-se7780.o
diff --git a/arch/sh/drivers/pci/fixups-lboxre2.c b/arch/sh/drivers/pci/fixups-lboxre2.c
new file mode 100644
index 0000000..40b19bd
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-lboxre2.c
@@ -0,0 +1,41 @@
+/*
+ * arch/sh/drivers/pci/fixups-lboxre2.c
+ *
+ * L-BOX RE2 PCI fixups
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * 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 "pci-sh4.h"
+
+#define PCIMCR_MRSET_OFF	0xBFFFFFFF
+#define PCIMCR_RFSH_OFF		0xFFFFFFFB
+
+int pci_fixup_pcic(void)
+{
+	unsigned long bcr1, mcr;
+
+	bcr1 = inl(SH7751_BCR1);
+	bcr1 |= 0x40080000;	/* Enable Bit 19 BREQEN, set PCIC to slave */
+	pci_write_reg(bcr1, SH4_PCIBCR1);
+
+	/* Enable all interrupts, so we known what to fix */
+	pci_write_reg(0x0000c3ff, SH4_PCIINTM);
+	pci_write_reg(0x0000380f, SH4_PCIAINTM);
+	pci_write_reg(0xfb900047, SH7751_PCICONF1);
+	pci_write_reg(0xab000001, SH7751_PCICONF4);
+
+	mcr = inl(SH7751_MCR);
+	mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+	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);
+
+	return 0;
+}
diff --git a/arch/sh/drivers/pci/fixups-se7780.c b/arch/sh/drivers/pci/fixups-se7780.c
new file mode 100644
index 0000000..880cea1
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-se7780.c
@@ -0,0 +1,60 @@
+/*
+ * arch/sh/drivers/pci/fixups-se7780.c
+ *
+ * HITACHI UL Solution Engine 7780  PCI fixups
+ *
+ * Copyright (C) 2003  Lineo uSolutions, Inc.
+ * Copyright (C) 2004 - 2006  Paul Mundt
+ * Copyright (C) 2006  Nobuhiro Iwamatsu
+ *
+ * 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)
+{
+	ctrl_outl(0x00000001, SH7780_PCI_VCR2);
+
+	/* Enable all interrupts, so we know what to fix */
+	pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
+	pci_write_reg(0x0000380F, SH7780_PCIAINTM);
+
+	/* Set up standard PCI config registers */
+	ctrl_outw(0xFB00, PCI_REG(SH7780_PCISTATUS));
+	ctrl_outw(0x0047, PCI_REG(SH7780_PCICMD));
+	ctrl_outb(  0x00, PCI_REG(SH7780_PCIPIF));
+	ctrl_outb(  0x00, PCI_REG(SH7780_PCISUB));
+	ctrl_outb(  0x06, PCI_REG(SH7780_PCIBCC));
+	ctrl_outw(0x1912, PCI_REG(SH7780_PCISVID));
+	ctrl_outw(0x0001, PCI_REG(SH7780_PCISID));
+
+	pci_write_reg(0x08000000, SH7780_PCIMBAR0);     /* PCI */
+	pci_write_reg(0x08000000, SH7780_PCILAR0);     /* SHwy */
+	pci_write_reg(0x07F00001, SH7780_PCILSR);      /* size 128M w/ MBAR */
+
+	pci_write_reg(0x00000000, SH7780_PCIMBAR1);
+	pci_write_reg(0x00000000, SH7780_PCILAR1);
+	pci_write_reg(0x00000000, SH7780_PCILSR1);
+
+	pci_write_reg(0xAB000801, SH7780_PCIIBAR);
+
+	/*
+	 * Set the MBR so PCI address is one-to-one with window,
+	 * meaning all calls go straight through... use ifdef to
+	 * catch erroneous assumption.
+	 */
+	pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
+	pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0);    /* 16M */
+
+	/* Set IOBR for window 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);
+
+	pci_write_reg(0xA5000C01, SH7780_PCICR);
+
+	return 0;
+}
diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c
index d060308..bff09ec 100644
--- a/arch/sh/drivers/pci/ops-landisk.c
+++ b/arch/sh/drivers/pci/ops-landisk.c
@@ -17,8 +17,8 @@ #include "pci-sh4.h"
 
 static struct resource sh7751_io_resource = {
 	.name = "SH7751 IO",
-	.start = 0x4000,
-	.end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
+	.start = SH7751_PCI_IO_BASE,
+	.end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
 	.flags = IORESOURCE_IO
 };
 
diff --git a/arch/sh/drivers/pci/ops-lboxre2.c b/arch/sh/drivers/pci/ops-lboxre2.c
new file mode 100644
index 0000000..a13cb76
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-lboxre2.c
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-lboxre2.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * PCI initialization for the NTT COMWARE L-BOX RE2
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <asm/lboxre2.h>
+#include "pci-sh4.h"
+
+static char lboxre2_irq_tab[] __initdata = {
+	IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+	return lboxre2_irq_tab[slot];
+}
+
+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
+};
+
+extern struct pci_ops sh7751_pci_ops;
+
+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_CS3_BASE_ADDR,
+		.size	= 0x04000000,
+	},
+	.window1	= {
+		.base	= 0x00000000,	/* Unused */
+		.size	= 0x00000000,	/* Unused */
+	},
+	.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/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
index eeea157..f221608 100644
--- a/arch/sh/drivers/pci/ops-r7780rp.c
+++ b/arch/sh/drivers/pci/ops-r7780rp.c
@@ -17,18 +17,25 @@ #include <asm/r7780rp.h>
 #include <asm/io.h>
 #include "pci-sh4.h"
 
+static char r7780rp_irq_tab[] __initdata = {
+	0, 1, 2, 3,
+};
+
+static char r7780mp_irq_tab[] __initdata = {
+	65, 66, 67, 68,
+};
+
 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;
-	}
+	if (mach_is_r7780rp())
+		return r7780rp_irq_tab[slot];
+	if (mach_is_r7780mp() || mach_is_r7785rp())
+		return r7780mp_irq_tab[slot];
+
+	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 = {
diff --git a/arch/sh/drivers/pci/ops-se7780.c b/arch/sh/drivers/pci/ops-se7780.c
new file mode 100644
index 0000000..212674d
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-se7780.c
@@ -0,0 +1,96 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-se7780.c
+ *
+ * Copyright (C) 2006  Nobuhiro Iwamatsu
+ *
+ * PCI initialization for the Hitachi UL Solution Engine 7780SE03
+ *
+ * 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 <asm/se7780.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
+
+/*
+ * IDSEL = AD16  PCI slot
+ * IDSEL = AD17  PCI slot
+ * IDSEL = AD18  Serial ATA Controller (Silicon Image SiL3512A)
+ * IDSEL = AD19  USB Host Controller (NEC uPD7210100A)
+ */
+
+/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
+static char se7780_irq_tab[4][16] __initdata = {
+	/* INTA */
+	{ 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	/* INTB */
+	{ 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	/* INTC */
+	{ 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+	/* INTD */
+	{ 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+       return se7780_irq_tab[pin-1][slot];
+}
+
+static struct resource se7780_io_resource = {
+	.name	= "SH7780_IO",
+	.start	= 0x2000,
+	.end	= 0x2000 + SH7780_PCI_IO_SIZE - 1,
+	.flags	= IORESOURCE_IO
+};
+
+static struct resource se7780_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 se7780_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+	{ &sh4_pci_ops, &se7780_io_resource, &se7780_mem_resource, 0, 0xff },
+	{ NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map se7780_pci_map = {
+	.window0	= {
+		.base	= SH7780_CS2_BASE_ADDR,
+		.size	= 0x04000000,
+	},
+	.flags  = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+	printk("SH7780 PCI: Finished initialization of the PCI controller\n");
+
+	/*
+	 * FPGA PCISEL register initialize
+	 *
+	 *  CPU  || SLOT1 | SLOT2 | S-ATA | USB
+	 *  -------------------------------------
+	 *  INTA || INTA  | INTD  |  --   | INTB
+	 *  -------------------------------------
+	 *  INTB || INTB  | INTA  |  --   | INTC
+	 *  -------------------------------------
+	 *  INTC || INTC  | INTB  | INTA  |  --
+	 *  -------------------------------------
+	 *  INTD || INTD  | INTC  |  --   | INTA
+	 *  -------------------------------------
+	 */
+	ctrl_outw(0x0013, FPGA_PCI_INTSEL1);
+	ctrl_outw(0xE402, FPGA_PCI_INTSEL2);
+
+	return sh7780_pcic_init(&se7780_pci_map);
+}
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 2d43710..54232f1 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -162,3 +162,9 @@ char * __init pcibios_setup(char *str)
 
 	return str;
 }
+
+int __attribute__((weak)) pci_fixup_pcic(void)
+{
+	/* Nothing to do. */
+	return 0;
+}
diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
index 5a61d60..1901c33 100644
--- a/arch/sh/drivers/pci/pci-sh4.h
+++ b/arch/sh/drivers/pci/pci-sh4.h
@@ -1,7 +1,7 @@
 #ifndef __PCI_SH4_H
 #define __PCI_SH4_H
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
 #include "pci-sh7780.h"
 #else
 #include "pci-sh7751.h"
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
index 9ddff76..1aca7fe 100644
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -12,7 +12,6 @@
  *  License.  See linux/COPYING for more information.
  *
  */
-
 #undef DEBUG
 
 #include <linux/init.h>
@@ -28,7 +27,7 @@ #include <asm/io.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().
@@ -115,7 +114,7 @@ int __init sh7751_pcic_init(struct sh4_p
 	 * Wait Cycle Control + Parity Enable + Bus Master +
 	 * Mem space enable
 	 */
-	word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | 
+	word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
 	       SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
 	pci_write_reg(word, SH7751_PCICONF1);
 
@@ -123,10 +122,10 @@ int __init sh7751_pcic_init(struct sh4_p
 	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 
+	/* 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 
+	 * Window1 = map->window1.size @ cached area base = SDRAM
 	 */
 	word = map->window0.size - 1;
 	pci_write_reg(word, SH4_PCILSR0);
@@ -175,7 +174,7 @@ int __init sh7751_pcic_init(struct sh4_p
 	case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break;
 	case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break;
 	}
-	
+
 	if (!word)
 		return 0;
 
@@ -194,9 +193,7 @@ int __init sh7751_pcic_init(struct sh4_p
 	 * DMA interrupts...
 	 */
 
-#ifdef CONFIG_SH_RTS7751R2D
 	pci_fixup_pcic();
-#endif
 
 	/* SH7751 init done, set central function init complete */
 	/* use round robin mode to stop a device starving/overruning */
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index 602b644..5508e45 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -48,7 +48,7 @@ #define INTC_INT2MSKCR	(INTC_BASE+0x4003
 static int __init sh7780_pci_init(void)
 {
 	unsigned int id;
-	int ret;
+	int ret, match = 0;
 
 	pr_debug("PCI: Starting intialization.\n");
 
@@ -56,19 +56,43 @@ static int __init sh7780_pci_init(void)
 
 	/* 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))) {
+	if ((id & 0xffff) == SH7780_VENDOR_ID) {
+		switch ((id >> 16) & 0xffff) {
+		case SH7780_DEVICE_ID:
+		case SH7781_DEVICE_ID:
+		case SH7785_DEVICE_ID:
+			match = 1;
+			break;
+		}
+	}
+
+	if (unlikely(!match)) {
 		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 (mach_is_7780se()) {
+		/* ICR0: IRL=use separately */
+		ctrl_outl(0x00C00020, INTC_ICR0);
+		/* ICR1: detect low level(for 2ndcut) */
+		ctrl_outl(0xAAAA0000, INTC_ICR1);
+		/* INTPRI: priority=3(all) */
+		ctrl_outl(0x33333333, INTC_INTPRI);
+	} else {
+		/* INTC SH-4 Mode */
+		ctrl_outl(0x00200000, INTC_ICR0);
+		/* enable PCIINTA - PCIINTD */
+		ctrl_outl(0x00078000, INTC_INT2MSKCR);
+		/* disable IRL4-7 Interrupt */
+		ctrl_outl(0x40000000, INTC_INTMSK1);
+		/* disable IRL4-7 Interrupt */
+		ctrl_outl(0x0000fffe, INTC_INTMSK2);
+		/* enable IRL0-3 Interrupt */
+		ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+		/* enable IRL0-3 Interrupt */
+		ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+	}
 
 	if ((ret = sh4_pci_check_direct()) != 0)
 		return ret;
@@ -138,9 +162,8 @@ int __init sh7780_pcic_init(struct sh4_p
 	 * DMA interrupts...
 	 */
 
-#ifdef CONFIG_SH_R7780RP
+	/* Apply any last-minute PCIC fixups */
 	pci_fixup_pcic();
-#endif
 
 	/* SH7780 init done, set central function init complete */
 	/* use round robin mode to stop a device starving/overruning */
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
index f02d218..00d12d0 100644
--- a/arch/sh/drivers/pci/pci-sh7780.h
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -14,8 +14,9 @@ #define _PCI_SH7780_H_
 
 /* Platform Specific Values */
 #define SH7780_VENDOR_ID	0x1912
-#define SH7780_DEVICE_ID	0x0002
 #define SH7781_DEVICE_ID	0x0001
+#define SH7780_DEVICE_ID	0x0002
+#define SH7785_DEVICE_ID	0x0007
 
 /* SH7780 Control Registers */
 #define	SH7780_PCI_VCR0		0xFE000000
@@ -65,6 +66,22 @@ #define SH7780_PCIPMCSR		0x044
 #define SH7780_PCIPMCSR_BSE	0x046
 #define SH7780_PCICDD		0x047
 
+#define SH7780_PCICR		0x100		/* PCI Control Register */
+#define SH7780_PCILSR		0x104		/* PCI Local Space Register0 */
+#define SH7780_PCILSR1		0x108		/* PCI Local Space Register1 */
+#define SH7780_PCILAR0		0x10C		/* PCI Local Address Register1 */
+#define SH7780_PCILAR1		0x110		/* PCI Local Address Register1 */
+#define SH7780_PCIIR		0x114		/* PCI Interrupt Register */
+#define SH7780_PCIIMR		0x118		/* PCI Interrupt Mask Register */
+#define SH7780_PCIAIR		0x11C		/* Error Address Register */
+#define SH7780_PCICIR		0x120		/* Error Command/Data Register */
+#define SH7780_PCIAINT		0x130		/* Arbiter Interrupt Register */
+#define SH7780_PCIAINTM		0x134		/* Arbiter Int. Mask Register */
+#define SH7780_PCIBMIR		0x138		/* Error Bus Master Register */
+#define SH7780_PCIPAR		0x1C0		/* PIO Address Register */
+#define SH7780_PCIPINT		0x1CC		/* Power Mgmnt Int. Register */
+#define SH7780_PCIPINTM		0x1D0		/* Power Mgmnt Mask Register */
+
 #define SH7780_PCIMBR0		0x1E0
 #define SH7780_PCIMBMR0		0x1E4
 #define SH7780_PCIMBR2		0x1F0
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
index efecb3d..d67656a 100644
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -9,7 +9,6 @@
 
 #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>
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index ff30d7f..9104b62 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -20,5 +20,6 @@ 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_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index 3e5fa1e..0758d48 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -29,7 +29,7 @@ #include <asm/irq.h>
  * 0xB8001000 : Common Memory
  * 0xBA000000 : I/O
  */
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
 /* 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 */
@@ -71,7 +71,7 @@ static int __init cf_init_default(void)
 /* You must have enabled the card, and set the level interrupt
  * before reaching this point. Possibly in boot ROM or boot loader.
  */
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
 	allocate_cf_area();
 #endif
 #if defined(CONFIG_SH_UNKNOWN)
@@ -84,15 +84,25 @@ #endif
 
 #if defined(CONFIG_SH_SOLUTION_ENGINE)
 #include <asm/se.h>
+#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+#include <asm/se7722.h>
+#endif
 
 /*
- * SolutionEngine
+ * SolutionEngine Seriese
  *
+ * about MS770xSE
  * 0xB8400000 : Common Memory
  * 0xB8500000 : Attribute
  * 0xB8600000 : I/O
+ *
+ * about MS7722SE
+ * 0xB0400000 : Common Memory
+ * 0xB0500000 : Attribute
+ * 0xB0600000 : I/O
  */
 
+#if defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE) 
 static int __init cf_init_se(void)
 {
 	if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0)
@@ -109,7 +119,7 @@ static int __init cf_init_se(void)
 	 *  flag == COMMON/ATTRIBUTE/IO
 	 */
 	/* common window open */
-	ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */
+	ctrl_outw(0x8a84, MRSHPC_MW0CR1);
 	if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
 		/* common mode & bus width 16bit SWAP = 1*/
 		ctrl_outw(0x0b00, MRSHPC_MW0CR2);
@@ -118,7 +128,7 @@ static int __init cf_init_se(void)
 		ctrl_outw(0x0300, MRSHPC_MW0CR2); 
 
 	/* attribute window open */
-	ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */
+	ctrl_outw(0x8a85, MRSHPC_MW1CR1);
 	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
 		/* attribute mode & bus width 16bit SWAP = 1*/
 		ctrl_outw(0x0a00, MRSHPC_MW1CR2);
@@ -127,7 +137,7 @@ static int __init cf_init_se(void)
 		ctrl_outw(0x0200, MRSHPC_MW1CR2);
 
 	/* I/O window open */
-	ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */
+	ctrl_outw(0x8a86, MRSHPC_IOWCR1);
 	ctrl_outw(0x0008, MRSHPC_CDCR);	 /* I/O card mode */
 	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
 		ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
@@ -143,10 +153,10 @@ #endif
 
 int __init cf_init(void)
 {
-#if defined(CONFIG_SH_SOLUTION_ENGINE)
-	if (MACH_SE)
+	if( mach_is_se() || mach_is_7722se() ){
 		return cf_init_se();
-#endif
+	}
+	
 	return cf_init_default();
 }
 
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index abb586b..014f318 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, 2006  Paul Mundt
+ *  Copyright (C) 2005, 2006, 2007  Paul Mundt
  *
  * This clock framework is derived from the OMAP version by:
  *
@@ -23,6 +23,7 @@ #include <linux/kref.h>
 #include <linux/seq_file.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
+#include <linux/proc_fs.h>
 #include <asm/clock.h>
 #include <asm/timer.h>
 
@@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk)
 		if (clk->ops && clk->ops->init)
 			clk->ops->init(clk);
 
+	kref_get(&clk->kref);
+
 	if (clk->flags & CLK_ALWAYS_ENABLED)
 		return 0;
 
 	if (likely(clk->ops && clk->ops->enable))
 		clk->ops->enable(clk);
 
-	kref_get(&clk->kref);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(__clk_enable);
 
 int clk_enable(struct clk *clk)
 {
@@ -119,6 +122,7 @@ int clk_enable(struct clk *clk)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(clk_enable);
 
 static void clk_kref_release(struct kref *kref)
 {
@@ -127,11 +131,17 @@ static void clk_kref_release(struct kref
 
 void __clk_disable(struct clk *clk)
 {
+	int count = kref_put(&clk->kref, clk_kref_release);
+
 	if (clk->flags & CLK_ALWAYS_ENABLED)
 		return;
 
-	kref_put(&clk->kref, clk_kref_release);
+	if (!count) {	/* count reaches zero, disable the clock */
+		if (likely(clk->ops && clk->ops->disable))
+			clk->ops->disable(clk);
+	}
 }
+EXPORT_SYMBOL_GPL(__clk_disable);
 
 void clk_disable(struct clk *clk)
 {
@@ -141,6 +151,7 @@ void clk_disable(struct clk *clk)
 	__clk_disable(clk);
 	spin_unlock_irqrestore(&clock_lock, flags);
 }
+EXPORT_SYMBOL_GPL(clk_disable);
 
 int clk_register(struct clk *clk)
 {
@@ -151,8 +162,18 @@ int clk_register(struct clk *clk)
 
 	mutex_unlock(&clock_list_sem);
 
+	if (clk->flags & CLK_ALWAYS_ENABLED) {
+		pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
+		if (clk->ops && clk->ops->init)
+			clk->ops->init(clk);
+		if (clk->ops && clk->ops->enable)
+			clk->ops->enable(clk);
+		pr_debug( "Enabled.");
+	}
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(clk_register);
 
 void clk_unregister(struct clk *clk)
 {
@@ -160,21 +181,29 @@ void clk_unregister(struct clk *clk)
 	list_del(&clk->node);
 	mutex_unlock(&clock_list_sem);
 }
+EXPORT_SYMBOL_GPL(clk_unregister);
 
-inline unsigned long clk_get_rate(struct clk *clk)
+unsigned long clk_get_rate(struct clk *clk)
 {
 	return clk->rate;
 }
+EXPORT_SYMBOL_GPL(clk_get_rate);
 
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
+	return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
 	int ret = -EOPNOTSUPP;
 
 	if (likely(clk->ops && clk->ops->set_rate)) {
 		unsigned long flags;
 
 		spin_lock_irqsave(&clock_lock, flags);
-		ret = clk->ops->set_rate(clk, rate);
+		ret = clk->ops->set_rate(clk, rate, algo_id);
 		spin_unlock_irqrestore(&clock_lock, flags);
 	}
 
@@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsign
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
 
 void clk_recalc_rate(struct clk *clk)
 {
@@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk)
 	if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
 		propagate_rate(clk);
 }
+EXPORT_SYMBOL_GPL(clk_recalc_rate);
 
 /*
  * Returns a clock. Note that we first try to use device id on the bus
@@ -233,18 +264,43 @@ found:
 
 	return clk;
 }
+EXPORT_SYMBOL_GPL(clk_get);
 
 void clk_put(struct clk *clk)
 {
 	if (clk && !IS_ERR(clk))
 		module_put(clk->owner);
 }
+EXPORT_SYMBOL_GPL(clk_put);
 
 void __init __attribute__ ((weak))
 arch_init_clk_ops(struct clk_ops **ops, int type)
 {
 }
 
+static int show_clocks(char *buf, char **start, off_t off,
+		       int len, int *eof, void *data)
+{
+	struct clk *clk;
+	char *p = buf;
+
+	list_for_each_entry_reverse(clk, &clock_list, node) {
+		unsigned long rate = clk_get_rate(clk);
+
+		/*
+		 * Don't bother listing dummy clocks with no ancestry
+		 * that only support enable and disable ops.
+		 */
+		if (unlikely(!rate && !clk->parent))
+			continue;
+
+		p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name,
+			     rate / 1000000, (rate % 1000000) / 10000);
+	}
+
+	return p - buf;
+}
+
 int __init clk_init(void)
 {
 	int i, ret = 0;
@@ -256,7 +312,6 @@ int __init clk_init(void)
 
 		arch_init_clk_ops(&clk->ops, i);
 		ret |= clk_register(clk);
-		clk_enable(clk);
 	}
 
 	/* Kick the child clocks.. */
@@ -266,35 +321,14 @@ int __init clk_init(void)
 	return ret;
 }
 
-int show_clocks(struct seq_file *m)
+static int __init clk_proc_init(void)
 {
-	struct clk *clk;
-
-	list_for_each_entry_reverse(clk, &clock_list, node) {
-		unsigned long rate = clk_get_rate(clk);
-
-		/*
-		 * Don't bother listing dummy clocks with no ancestry
-		 * that only support enable and disable ops.
-		 */
-		if (unlikely(!rate && !clk->parent))
-			continue;
-
-		seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name,
-			   rate / 1000000, (rate % 1000000) / 10000);
-	}
+	struct proc_dir_entry *p;
+	p = create_proc_read_entry("clocks", S_IRUSR, NULL,
+				   show_clocks, NULL);
+	if (unlikely(!p))
+		return -EINVAL;
 
 	return 0;
 }
-
-EXPORT_SYMBOL_GPL(clk_register);
-EXPORT_SYMBOL_GPL(clk_unregister);
-EXPORT_SYMBOL_GPL(clk_get);
-EXPORT_SYMBOL_GPL(clk_put);
-EXPORT_SYMBOL_GPL(clk_enable);
-EXPORT_SYMBOL_GPL(clk_disable);
-EXPORT_SYMBOL_GPL(__clk_enable);
-EXPORT_SYMBOL_GPL(__clk_disable);
-EXPORT_SYMBOL_GPL(clk_get_rate);
-EXPORT_SYMBOL_GPL(clk_set_rate);
-EXPORT_SYMBOL_GPL(clk_recalc_rate);
+subsys_initcall(clk_proc_init);
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 726acfc..6451ad6 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -41,6 +41,23 @@ __setup("no" __stringify(x), x##_setup);
 onchip_setup(fpu);
 onchip_setup(dsp);
 
+#ifdef CONFIG_SPECULATIVE_EXECUTION
+#define CPUOPM		0xff2f0000
+#define CPUOPM_RABD	(1 << 5)
+
+static void __init speculative_execution_init(void)
+{
+	/* Clear RABD */
+	ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM);
+
+	/* Flush the update */
+	(void)ctrl_inl(CPUOPM);
+	ctrl_barrier();
+}
+#else
+#define speculative_execution_init()	do { } while (0)
+#endif
+
 /*
  * Generic first-level cache init
  */
@@ -261,4 +278,6 @@ #ifdef CONFIG_UBC_WAKEUP
 	 */
 	ubc_wakeup();
 #endif
+
+	speculative_execution_init();
 }
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 0049d21..1c23308 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -4,6 +4,6 @@ #
 obj-y	+= imask.o
 
 obj-$(CONFIG_CPU_HAS_IPR_IRQ)		+= ipr.o
-obj-$(CONFIG_CPU_HAS_PINT_IRQ)		+= pint.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 74defe7..d8e22f4 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -18,7 +18,8 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7760)
 #define INTC2_BASE	0xfe080000
 #define INTC2_INTMSK	(INTC2_BASE + 0x40)
 #define INTC2_INTMSKCLR	(INTC2_BASE + 0x60)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define INTC2_BASE	0xffd40000
 #define INTC2_INTMSK	(INTC2_BASE + 0x38)
 #define INTC2_INTMSKCLR	(INTC2_BASE + 0x3c)
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index f600077..6760268 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -18,6 +18,58 @@ #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/machvec.h>
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define INTC_INTER      0xA4000014UL
+#define INTC_IPRD       0xA4000018UL
+#define INTC_ICR2       0xA4000012UL
+
+/* PFC */
+#define PORT_PACR       0xA4000100UL
+#define PORT_PBCR       0xA4000102UL
+#define PORT_PCCR       0xA4000104UL
+#define PORT_PDCR       0xA4000106UL
+#define PORT_PECR       0xA4000108UL
+#define PORT_PFCR       0xA400010AUL
+#define PORT_PGCR       0xA400010CUL
+#define PORT_PHCR       0xA400010EUL
+#define PORT_PJCR       0xA4000110UL
+#define PORT_PKCR       0xA4000112UL
+#define PORT_PLCR       0xA4000114UL
+#define PORT_PMCR       0xA4000118UL
+#define PORT_PNCR       0xA400011AUL
+#define PORT_PECR2      0xA4050148UL
+#define PORT_PFCR2      0xA405014AUL
+#define PORT_PNCR2      0xA405015AUL
+
+/* I/O port */
+#define PORT_PADR       0xA4000120UL
+#define PORT_PBDR       0xA4000122UL
+#define PORT_PCDR       0xA4000124UL
+#define PORT_PDDR       0xA4000126UL
+#define PORT_PEDR       0xA4000128UL
+#define PORT_PFDR       0xA400012AUL
+#define PORT_PGDR       0xA400012CUL
+#define PORT_PHDR       0xA400012EUL
+#define PORT_PJDR       0xA4000130UL
+#define PORT_PKDR       0xA4000132UL
+#define PORT_PLDR       0xA4000134UL
+#define PORT_PMDR       0xA4000138UL
+#define PORT_PNDR       0xA400013AUL
+
+#define PINT0_IRQ       40
+#define PINT8_IRQ       41
+#define PINT_IRQ_BASE   86
+
+#define PINT0_IPR_ADDR          INTC_IPRD
+#define PINT0_IPR_POS           3
+#define PINT0_PRIORITY      2
+
+#define PINT8_IPR_ADDR          INTC_IPRD
+#define PINT8_IPR_POS           2
+#define PINT8_PRIORITY      2
+
+#endif /* CONFIG_CPU_SUBTYPE_SH7705 */
+
 static unsigned char pint_map[256];
 static unsigned long portcr_mask;
 
@@ -126,7 +178,7 @@ int ipr_irq_demux(int irq)
 	unsigned long creg, dreg, d, sav;
 
 	if (irq == PINT0_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
 		creg = PORT_PACR;
 		dreg = PORT_PADR;
 #else
@@ -144,7 +196,7 @@ #endif
 
 		return PINT_IRQ_BASE + pint_map[d];
 	} else if (irq == PINT8_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
 		creg = PORT_PBCR;
 		dreg = PORT_PBDR;
 #else
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 83905e4..09faa05 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7708)	+= setu
 obj-$(CONFIG_CPU_SUBTYPE_SH7709)	+= setup-sh7709.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7300)	+= setup-sh7300.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7710)	+= setup-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7712)	+= setup-sh7710.o
 
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SH3)			:= clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 821b0ab..647623b 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -78,6 +78,9 @@ #endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7710)
 		current_cpu_data.type = CPU_SH7710;
 #endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7712)
+		current_cpu_data.type = CPU_SH7712;
+#endif
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
 		current_cpu_data.type = CPU_SH7705;
 
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index a8e41c5..1983fb7 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -2,6 +2,7 @@
  * SH7705 Setup
  *
  *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * 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
@@ -14,15 +15,15 @@ #include <asm/sci.h>
 
 static struct plat_sci_port sci_platform_data[] = {
 	{
-		.mapbase	= 0xa4400000,
+		.mapbase	= 0xa4410000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCIF,
-		.irqs		= { 52, 53, 55, 54 },
+		.irqs		= { 56, 57, 59 },
 	}, {
-		.mapbase	= 0xa4410000,
+		.mapbase	= 0xa4400000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCIF,
-		.irqs		= { 56, 57, 59, 58 },
+		.irqs		= { 52, 53, 55 },
 	}, {
 		.flags = 0,
 	}
@@ -46,3 +47,48 @@ static int __init sh7705_devices_setup(v
 				    ARRAY_SIZE(sh7705_devices));
 }
 __initcall(sh7705_devices_setup);
+
+static struct ipr_data sh7705_ipr_map[] = {
+	/* IRQ, IPR-idx, shift, priority */
+	{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
+	{ 17, 0,  8, 2 }, /* TMU1 TUNI */
+	{ 18, 0,  4, 2 }, /* TMU2 TUNI */
+	{ 27, 1, 12, 2 }, /* WDT ITI */
+	{ 20, 0,  0, 2 }, /* RTC ATI (alarm) */
+	{ 21, 0,  0, 2 }, /* RTC PRI (period) */
+	{ 22, 0,  0, 2 }, /* RTC CUI (carry) */
+	{ 48, 4, 12, 7 }, /* DMAC DMTE0 */
+	{ 49, 4, 12, 7 }, /* DMAC DMTE1 */
+	{ 50, 4, 12, 7 }, /* DMAC DMTE2 */
+	{ 51, 4, 12, 7 }, /* DMAC DMTE3 */
+	{ 52, 4,  8, 3 }, /* SCIF0 ERI */
+	{ 53, 4,  8, 3 }, /* SCIF0 RXI */
+	{ 55, 4,  8, 3 }, /* SCIF0 TXI */
+	{ 56, 4,  4, 3 }, /* SCIF1 ERI */
+	{ 57, 4,  4, 3 }, /* SCIF1 RXI */
+	{ 59, 4,  4, 3 }, /* SCIF1 TXI */
+};
+
+static unsigned long ipr_offsets[] = {
+	0xFFFFFEE2	/* 0: IPRA */
+,	0xFFFFFEE4	/* 1: IPRB */
+,	0xA4000016	/* 2: IPRC */
+,	0xA4000018	/* 3: IPRD */
+,	0xA400001A	/* 4: IPRE */
+,	0xA4080000	/* 5: IPRF */
+,	0xA4080002	/* 6: IPRG */
+,	0xA4080004	/* 7: IPRH */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+	if (idx >= ARRAY_SIZE(ipr_offsets))
+		return 0;
+	return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+	make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index dc9b211..c7d7c35 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -48,24 +48,33 @@ static struct platform_device *sh7709_de
 static int __init sh7709_devices_setup(void)
 {
 	return platform_add_devices(sh7709_devices,
-				    ARRAY_SIZE(sh7709_devices));
+		ARRAY_SIZE(sh7709_devices));
 }
 __initcall(sh7709_devices_setup);
 
-#define IPRx(A,N) .addr=A, .shift=0*N*-1
+#define IPRx(A,N)	.addr=A, .shift=N
 #define IPRA(N)	IPRx(0xfffffee2UL,N)
 #define IPRB(N)	IPRx(0xfffffee4UL,N)
+#define IPRC(N)	IPRx(0xa4000016UL,N)
+#define IPRD(N)	IPRx(0xa4000018UL,N)
 #define IPRE(N)	IPRx(0xa400001aUL,N)
 
 static struct ipr_data sh7709_ipr_map[] = {
-	[16]		= { IPRA(15-12), 2 }, /* TMU TUNI0 */
-	[17]		= { IPRA(11-8),  4 }, /* TMU TUNI1 */
-	[22]		= { IPRA(3-0),   2 }, /* RTC CUI */
-	[23 ... 26]	= { IPRB(7-4),   3 }, /* SCI */
-	[27]		= { IPRB(15-12), 2 }, /* WDT ITI */
-	[48 ... 51]	= { IPRE(15-12), 7 }, /* DMA */
-	[52 ... 55]	= { IPRE(11-8),  3 }, /* IRDA */
-	[56 ... 59]	= { IPRE(7-4),   3 }, /* SCIF */
+	[16]		= { IPRA(12), 2 }, /* TMU TUNI0 */
+	[17]		= { IPRA(8),  4 }, /* TMU TUNI1 */
+	[18 ... 19]	= { IPRA(4),  1 }, /* TMU TUNI1 */
+	[20 ... 22]	= { IPRA(0),  2 }, /* RTC CUI */
+	[23 ... 26]	= { IPRB(4),  3 }, /* SCI */
+	[27]		= { IPRB(12), 2 }, /* WDT ITI */
+	[32]		= { IPRC(0),  1 }, /* IRQ 0 */
+	[33]		= { IPRC(4),  1 }, /* IRQ 1 */
+	[34]		= { IPRC(8),  1 }, /* IRQ 2 APM */
+	[35]		= { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */
+	[36]		= { IPRD(0),  1 }, /* IRQ 4 */
+	[37]		= { IPRD(4),  1 }, /* IRQ 5 */
+	[48 ... 51]	= { IPRE(12), 7 }, /* DMA */
+	[52 ... 55]	= { IPRE(8),  3 }, /* IRDA */
+	[56 ... 59]	= { IPRE(4),  3 }, /* SCIF */
 };
 
 void __init init_IRQ_ipr()
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 895f99e..51760a7 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -2,6 +2,7 @@
  * SH7710 Setup
  *
  *  Copyright (C) 2006  Paul Mundt
+ *  Copyright (C) 2007  Nobuhiro Iwamatsu
  *
  * 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
@@ -19,6 +20,12 @@ static struct plat_sci_port sci_platform
 		.type		= PORT_SCIF,
 		.irqs		= { 52, 53, 55, 54 },
 	}, {
+		.mapbase	= 0xa4420000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs           = { 56, 57, 59, 58 },
+	}, {
+
 		.flags = 0,
 	}
 };
@@ -41,3 +48,56 @@ static int __init sh7710_devices_setup(v
 				    ARRAY_SIZE(sh7710_devices));
 }
 __initcall(sh7710_devices_setup);
+
+static struct ipr_data sh7710_ipr_map[] = {
+	/* IRQ, IPR-idx, shift, priority */
+	{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
+	{ 17, 0,  8, 2 }, /* TMU1 TUNI */
+	{ 18, 0,  4, 2 }, /* TMU2 TUNI */
+	{ 27, 1, 12, 2 }, /* WDT ITI */
+	{ 20, 0,  0, 2 }, /* RTC ATI (alarm) */
+	{ 21, 0,  0, 2 }, /* RTC PRI (period) */
+	{ 22, 0,  0, 2 }, /* RTC CUI (carry) */
+	{ 48, 4, 12, 7 }, /* DMAC DMTE0 */
+	{ 49, 4, 12, 7 }, /* DMAC DMTE1 */
+	{ 50, 4, 12, 7 }, /* DMAC DMTE2 */
+	{ 51, 4, 12, 7 }, /* DMAC DMTE3 */
+	{ 52, 4,  8, 3 }, /* SCIF0 ERI */
+	{ 53, 4,  8, 3 }, /* SCIF0 RXI */
+	{ 54, 4,  8, 3 }, /* SCIF0 BRI */
+	{ 55, 4,  8, 3 }, /* SCIF0 TXI */
+	{ 56, 4,  4, 3 }, /* SCIF1 ERI */
+	{ 57, 4,  4, 3 }, /* SCIF1 RXI */
+	{ 58, 4,  4, 3 }, /* SCIF1 BRI */
+	{ 59, 4,  4, 3 }, /* SCIF1 TXI */
+	{ 76, 5,  8, 7 }, /* DMAC DMTE4 */
+	{ 77, 5,  8, 7 }, /* DMAC DMTE5 */
+	{ 80, 6, 12, 5 }, /* EDMAC EINT0 */
+	{ 81, 6,  8, 5 }, /* EDMAC EINT1 */
+	{ 82, 6,  4, 5 }, /* EDMAC EINT2 */
+};
+
+static unsigned long ipr_offsets[] = {
+	0xA414FEE2	/* 0: IPRA */
+,	0xA414FEE4	/* 1: IPRB */
+,	0xA4140016	/* 2: IPRC */
+,	0xA4140018	/* 3: IPRD */
+,	0xA414001A	/* 4: IPRE */
+,	0xA4080000	/* 5: IPRF */
+,	0xA4080002	/* 6: IPRG */
+,	0xA4080004	/* 7: IPRH */
+,	0xA4080006	/* 8: IPRI */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+	if (idx >= ARRAY_SIZE(ipr_offsets))
+		return 0;
+	return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+	make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
index fa2019a..fcb2c41 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
@@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *cl
 	for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
 		int divisor = frqcr3_divisors[i];
 
-		if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
+		if (clk->ops->set_rate(clk, clk->parent->rate /
+						divisor, 0) == 0)
 			break;
 	}
 
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 58950de..8cd0490 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -124,6 +124,14 @@ int __init detect_cpu_and_cache_system(v
 		current_cpu_data.dcache.ways = 4;
 		current_cpu_data.flags |= CPU_HAS_LLSC;
 		break;
+	case 0x3004:
+	case 0x3007:
+		current_cpu_data.type = CPU_SH7785;
+		current_cpu_data.icache.ways = 4;
+		current_cpu_data.dcache.ways = 4;
+		current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+					  CPU_HAS_LLSC;
+		break;
 	case 0x3008:
 		if (prr == 0xa0) {
 			current_cpu_data.type = CPU_SH7722;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index a8f493f..ab7422f 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -5,6 +5,7 @@ #
 # CPU subtype setup
 obj-$(CONFIG_CPU_SUBTYPE_SH7770)	+= setup-sh7770.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)	+= setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7785)	+= setup-sh7785.o
 obj-$(CONFIG_CPU_SUBTYPE_SH73180)	+= setup-sh73180.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)	+= setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)	+= setup-sh7722.o
@@ -13,7 +14,8 @@ # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SUBTYPE_SH73180)	:= clock-sh73180.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7770)	:= clock-sh7770.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7780)	:= clock-sh7780.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7785)	:= clock-sh7785.o
 clock-$(CONFIG_CPU_SUBTYPE_SH7343)	:= clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722)	:= clock-sh7343.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722)	:= clock-sh7722.o
 
 obj-y	+= $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
new file mode 100644
index 0000000..2909003
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -0,0 +1,600 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+ *
+ * SH7722 support for the clock framework
+ *
+ * Copyright (c) 2006-2007 Nomad Global Solutions Inc
+ * Based on code for sh7343 by 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/kernel.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+#define SH7722_PLL_FREQ (32000000/8)
+#define N  (-1)
+#define NM (-2)
+#define ROUND_NEAREST 0
+#define ROUND_DOWN -1
+#define ROUND_UP   +1
+
+static int adjust_algos[][3] = {
+	{},	/* NO_CHANGE */
+	{ NM, N, 1 },   /* N:1, N:1 */
+	{ 3, 2, 2 },	/* 3:2:2 */
+	{ 5, 2, 2 },    /* 5:2:2 */
+	{ N, 1, 1 },	/* N:1:1 */
+
+	{ N, 1 },	/* N:1 */
+
+	{ N, 1 },	/* N:1 */
+	{ 3, 2 },
+	{ 4, 3 },
+	{ 5, 4 },
+
+	{ N, 1 }
+};
+
+static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
+			int m1, int m2, int round_flag)
+{
+	unsigned long rem, div;
+	int the_one = 0;
+
+	pr_debug( "Actual values: r1 = %ld\n", r1);
+	pr_debug( "...............r2 = %ld\n", r2);
+
+	if (m1 == m2) {
+		r2 = r1;
+		pr_debug( "setting equal rates: r2 now %ld\n", r2);
+	} else if ((m2 == N  && m1 == 1) ||
+		   (m2 == NM && m1 == N)) { /* N:1 or NM:N */
+		pr_debug( "Setting rates as 1:N (N:N*M)\n");
+		rem = r2 % r1;
+		pr_debug( "...remainder = %ld\n", rem);
+		if (rem) {
+			div = r2 / r1;
+			pr_debug( "...div = %ld\n", div);
+			switch (round_flag) {
+			case ROUND_NEAREST:
+				the_one = rem >= r1/2 ? 1 : 0; break;
+			case ROUND_UP:
+				the_one = 1; break;
+			case ROUND_DOWN:
+				the_one = 0; break;
+			}
+
+			r2 = r1 * (div + the_one);
+			pr_debug( "...setting r2 to %ld\n", r2);
+		}
+	} else if ((m2 == 1  && m1 == N) ||
+		   (m2 == N && m1 == NM)) { /* 1:N or N:NM */
+		pr_debug( "Setting rates as N:1 (N*M:N)\n");
+		rem = r1 % r2;
+		pr_debug( "...remainder = %ld\n", rem);
+		if (rem) {
+			div = r1 / r2;
+			pr_debug( "...div = %ld\n", div);
+			switch (round_flag) {
+			case ROUND_NEAREST:
+				the_one = rem > r2/2 ? 1 : 0; break;
+			case ROUND_UP:
+				the_one = 0; break;
+			case ROUND_DOWN:
+				the_one = 1; break;
+			}
+
+			r2 = r1 / (div + the_one);
+			pr_debug( "...setting r2 to %ld\n", r2);
+		}
+	} else { /* value:value */
+		pr_debug( "Setting rates as %d:%d\n", m1, m2);
+		div = r1 / m1;
+		r2 = div * m2;
+		pr_debug( "...div = %ld\n", div);
+		pr_debug( "...setting r2 to %ld\n", r2);
+	}
+
+	return r2;
+}
+
+static void adjust_clocks(int originate, int *l, unsigned long v[],
+			  int n_in_line)
+{
+	int x;
+
+	pr_debug( "Go down from %d...\n", originate);
+	/* go up recalculation clocks */
+	for (x = originate; x>0; x -- )
+		v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
+					l[x], l[x-1],
+					ROUND_UP);
+
+	pr_debug( "Go up from %d...\n", originate);
+	/* go down recalculation clocks */
+	for (x = originate; x<n_in_line - 1; x ++ )
+		v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
+					l[x], l[x+1],
+					ROUND_UP);
+}
+
+
+/*
+ * SH7722 uses a common set of multipliers and divisors, so this
+ * is quite simple..
+ */
+
+/*
+ * Instead of having two separate multipliers/divisors set, like this:
+ *
+ * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+ *
+ * I created the divisors2 array, which is used to calculate rate like
+ *   rate = parent * 2 / divisors2[ divisor ];
+*/
+static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
+
+static void master_clk_init(struct clk *clk)
+{
+	clk_set_rate(clk, clk_get_rate(clk));
+}
+
+static void master_clk_recalc(struct clk *clk)
+{
+	unsigned long frqcr = ctrl_inl(FRQCR);
+
+	clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF));
+}
+
+static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
+{
+	int div = rate / SH7722_PLL_FREQ;
+	int master_divs[] = { 2, 3, 4, 6, 8, 16 };
+	int index;
+	unsigned long frqcr;
+
+	if (rate < SH7722_PLL_FREQ * 2)
+		return -EINVAL;
+
+	for (index = 1; index < ARRAY_SIZE(master_divs); index++)
+		if (div >= master_divs[index - 1] && div < master_divs[index])
+			break;
+
+	if (index >= ARRAY_SIZE(master_divs))
+		index = ARRAY_SIZE(master_divs);
+	div = master_divs[index - 1];
+
+	frqcr = ctrl_inl(FRQCR);
+	frqcr &= ~(0xF << 24);
+	frqcr |= ( (div-1) << 24);
+	ctrl_outl(frqcr, FRQCR);
+
+	return 0;
+}
+
+static struct clk_ops sh7722_master_clk_ops = {
+	.init = master_clk_init,
+	.recalc = master_clk_recalc,
+	.set_rate = master_clk_setrate,
+};
+
+struct frqcr_context {
+	unsigned mask;
+	unsigned shift;
+};
+
+struct frqcr_context sh7722_get_clk_context(const char *name)
+{
+	struct frqcr_context ctx = { 0, };
+
+	if (!strcmp(name, "peripheral_clk")) {
+		ctx.shift = 0;
+		ctx.mask = 0xF;
+	} else if (!strcmp(name, "sdram_clk")) {
+		ctx.shift = 4;
+		ctx.mask = 0xF;
+	} else if (!strcmp(name, "bus_clk")) {
+		ctx.shift = 8;
+		ctx.mask = 0xF;
+	} else if (!strcmp(name, "sh_clk")) {
+		ctx.shift = 12;
+		ctx.mask = 0xF;
+	} else if (!strcmp(name, "umem_clk")) {
+		ctx.shift = 16;
+		ctx.mask = 0xF;
+	} else if (!strcmp(name, "cpu_clk")) {
+		ctx.shift = 20;
+		ctx.mask = 7;
+	}
+	return ctx;
+}
+
+/**
+ * sh7722_find_divisors - find divisor for setting rate
+ *
+ * All sh7722 clocks use the same set of multipliers/divisors. This function
+ * chooses correct divisor to set the rate of clock with parent clock that
+ * generates frequency of 'parent_rate'
+ *
+ * @parent_rate: rate of parent clock
+ * @rate: requested rate to be set
+ */
+static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
+{
+	unsigned div2 = parent_rate * 2 / rate;
+	int index;
+
+	if (rate > parent_rate)
+		return -EINVAL;
+
+	for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
+		if (div2 > divisors2[index] && div2 <= divisors2[index])
+			break;
+	}
+	if (index >= ARRAY_SIZE(divisors2))
+		index = ARRAY_SIZE(divisors2) - 1;
+	return divisors2[index];
+}
+
+static void sh7722_frqcr_recalc(struct clk *clk)
+{
+	struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+	unsigned long frqcr = ctrl_inl(FRQCR);
+	int index;
+
+	index = (frqcr >> ctx.shift) & ctx.mask;
+	clk->rate = clk->parent->rate * 2 / divisors2[index];
+}
+
+static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
+				 int algo_id)
+{
+	struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+	unsigned long parent_rate = clk->parent->rate;
+	int div;
+	unsigned long frqcr;
+	int err = 0;
+
+	/* pretty invalid */
+	if (parent_rate < rate)
+		return -EINVAL;
+
+	/* look for multiplier/divisor pair */
+	div = sh7722_find_divisors(parent_rate, rate);
+	if (div<0)
+		return div;
+
+	/* calculate new value of clock rate */
+	clk->rate = parent_rate * 2 / div;
+	frqcr = ctrl_inl(FRQCR);
+
+	/* FIXME: adjust as algo_id specifies */
+	if (algo_id != NO_CHANGE) {
+		int originator;
+		char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
+		char *algo_group_2[] = { "sh_clk", "bus_clk" };
+		char *algo_group_3[] = { "sh_clk", "sdram_clk" };
+		char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
+		char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
+		char **algo_current = NULL;
+		/* 3 is the maximum number of clocks in relation */
+		struct clk *ck[3];
+		unsigned long values[3]; /* the same comment as above */
+		int part_length = -1;
+		int i;
+
+		/*
+		 * all the steps below only required if adjustion was
+		 * requested
+		 */
+		if (algo_id == IUS_N1_N1 ||
+		    algo_id == IUS_322 ||
+		    algo_id == IUS_522 ||
+		    algo_id == IUS_N11) {
+			algo_current = algo_group_1;
+			part_length = 3;
+		}
+		if (algo_id == SB_N1) {
+			algo_current = algo_group_2;
+			part_length = 2;
+		}
+		if (algo_id == SB3_N1 ||
+		    algo_id == SB3_32 ||
+		    algo_id == SB3_43 ||
+		    algo_id == SB3_54) {
+			algo_current = algo_group_3;
+			part_length = 2;
+		}
+		if (algo_id == BP_N1) {
+			algo_current = algo_group_4;
+			part_length = 2;
+		}
+		if (algo_id == IP_N1) {
+			algo_current = algo_group_5;
+			part_length = 2;
+		}
+		if (!algo_current)
+			goto incorrect_algo_id;
+
+		originator = -1;
+		for (i = 0; i < part_length; i ++ ) {
+			if (originator >= 0 && !strcmp(clk->name,
+						       algo_current[i]))
+				originator = i;
+			ck[i] = clk_get(NULL, algo_current[i]);
+			values[i] = clk_get_rate(ck[i]);
+		}
+
+		if (originator >= 0)
+			adjust_clocks(originator, adjust_algos[algo_id],
+				      values, part_length);
+
+		for (i = 0; i < part_length; i ++ ) {
+			struct frqcr_context part_ctx;
+			int part_div;
+
+			if (likely(!err)) {
+				part_div = sh7722_find_divisors(parent_rate,
+								rate);
+				if (part_div > 0) {
+					part_ctx = sh7722_get_clk_context(
+								ck[i]->name);
+					frqcr &= ~(part_ctx.mask <<
+						   part_ctx.shift);
+					frqcr |= part_div << part_ctx.shift;
+				} else
+					err = part_div;
+			}
+
+			ck[i]->ops->recalc(ck[i]);
+			clk_put(ck[i]);
+		}
+	}
+
+	/* was there any error during recalculation ? If so, bail out.. */
+	if (unlikely(err!=0))
+		goto out_err;
+
+	/* clear FRQCR bits */
+	frqcr &= ~(ctx.mask << ctx.shift);
+	frqcr |= div << ctx.shift;
+
+	/* ...and perform actual change */
+	ctrl_outl(frqcr, FRQCR);
+	return 0;
+
+incorrect_algo_id:
+	return -EINVAL;
+out_err:
+	return err;
+}
+
+static struct clk_ops sh7722_frqcr_clk_ops = {
+	.recalc = sh7722_frqcr_recalc,
+	.set_rate = sh7722_frqcr_set_rate,
+};
+
+/*
+ * clock ops methods for SIU A/B and IrDA clock
+ *
+ */
+static int sh7722_siu_which(struct clk *clk)
+{
+	if (!strcmp(clk->name, "siu_a_clk"))
+		return 0;
+	if (!strcmp(clk->name, "siu_b_clk"))
+		return 1;
+	if (!strcmp(clk->name, "irda_clk"))
+		return 2;
+	return -EINVAL;
+}
+
+static unsigned long sh7722_siu_regs[] = {
+	[0] = SCLKACR,
+	[1] = SCLKBCR,
+	[2] = IrDACLKCR,
+};
+
+static int sh7722_siu_start_stop(struct clk *clk, int enable)
+{
+	int siu = sh7722_siu_which(clk);
+	unsigned long r;
+
+	if (siu < 0)
+		return siu;
+	BUG_ON(siu > 2);
+	r = ctrl_inl(sh7722_siu_regs[siu]);
+	if (enable)
+		ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]);
+	else
+		ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]);
+	return 0;
+}
+
+static void sh7722_siu_enable(struct clk *clk)
+{
+	sh7722_siu_start_stop(clk, 1);
+}
+
+static void sh7722_siu_disable(struct clk *clk)
+{
+	sh7722_siu_start_stop(clk, 0);
+}
+
+static void sh7722_video_enable(struct clk *clk)
+{
+	unsigned long r;
+
+	r = ctrl_inl(VCLKCR);
+	ctrl_outl( r & ~(1<<8), VCLKCR);
+}
+
+static void sh7722_video_disable(struct clk *clk)
+{
+	unsigned long r;
+
+	r = ctrl_inl(VCLKCR);
+	ctrl_outl( r | (1<<8), VCLKCR);
+}
+
+static int sh7722_video_set_rate(struct clk *clk, unsigned long rate,
+				 int algo_id)
+{
+	unsigned long r;
+
+	r = ctrl_inl(VCLKCR);
+	r &= ~0x3F;
+	r |= ((clk->parent->rate / rate - 1) & 0x3F);
+	ctrl_outl(r, VCLKCR);
+	return 0;
+}
+
+static void sh7722_video_recalc(struct clk *clk)
+{
+	unsigned long r;
+
+	r = ctrl_inl(VCLKCR);
+	clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
+}
+
+static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+	int siu = sh7722_siu_which(clk);
+	unsigned long r;
+	int div;
+
+	if (siu < 0)
+		return siu;
+	BUG_ON(siu > 2);
+	r = ctrl_inl(sh7722_siu_regs[siu]);
+	div = sh7722_find_divisors(clk->parent->rate, rate);
+	if (div < 0)
+		return div;
+	r = (r & ~0xF) | div;
+	ctrl_outl(r, sh7722_siu_regs[siu]);
+	return 0;
+}
+
+static void sh7722_siu_recalc(struct clk *clk)
+{
+	int siu = sh7722_siu_which(clk);
+	unsigned long r;
+
+	if (siu < 0)
+		return /* siu */ ;
+	BUG_ON(siu > 1);
+	r = ctrl_inl(sh7722_siu_regs[siu]);
+	clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
+}
+
+static struct clk_ops sh7722_siu_clk_ops = {
+	.recalc = sh7722_siu_recalc,
+	.set_rate = sh7722_siu_set_rate,
+	.enable = sh7722_siu_enable,
+	.disable = sh7722_siu_disable,
+};
+
+static struct clk_ops sh7722_video_clk_ops = {
+	.recalc = sh7722_video_recalc,
+	.set_rate = sh7722_video_set_rate,
+	.enable = sh7722_video_enable,
+	.disable = sh7722_video_disable,
+};
+/*
+ * and at last, clock definitions themselves
+ */
+static struct clk sh7722_umem_clock = {
+	.name = "umem_clk",
+	.ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sh_clock = {
+	.name = "sh_clk",
+	.ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_peripheral_clock = {
+	.name = "peripheral_clk",
+	.ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sdram_clock = {
+	.name = "sdram_clk",
+	.ops = &sh7722_frqcr_clk_ops,
+};
+
+/*
+ * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
+ * methods of clk_ops determine which register they should access by
+ * examining clk->name field
+ */
+static struct clk sh7722_siu_a_clock = {
+	.name = "siu_a_clk",
+	.ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_siu_b_clock = {
+	.name = "siu_b_clk",
+	.ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_irda_clock = {
+	.name = "irda_clk",
+	.ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_video_clock = {
+	.name = "video_clk",
+	.ops = &sh7722_video_clk_ops,
+};
+
+static struct clk *sh7722_clocks[] = {
+	&sh7722_umem_clock,
+	&sh7722_sh_clock,
+	&sh7722_peripheral_clock,
+	&sh7722_sdram_clock,
+	&sh7722_siu_a_clock,
+	&sh7722_siu_b_clock,
+	&sh7722_irda_clock,
+	&sh7722_video_clock,
+};
+
+/*
+ * init in order: master, module, bus, cpu
+ */
+struct clk_ops *onchip_ops[] = {
+	&sh7722_master_clk_ops,
+	&sh7722_frqcr_clk_ops,
+	&sh7722_frqcr_clk_ops,
+	&sh7722_frqcr_clk_ops,
+};
+
+void __init
+arch_init_clk_ops(struct clk_ops **ops, int type)
+{
+	BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops));
+	*ops = onchip_ops[type];
+}
+
+int __init sh7722_clock_init(void)
+{
+	struct clk *master;
+	int i;
+
+	master = clk_get(NULL, "master_clk");
+	for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
+		pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
+		sh7722_clocks[i]->parent = master;
+		clk_register(sh7722_clocks[i]);
+	}
+	clk_put(master);
+	return 0;
+}
+arch_initcall(sh7722_clock_init);
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
new file mode 100644
index 0000000..805535a
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -0,0 +1,162 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+ *
+ * SH7785 support for the clock framework
+ *
+ *  Copyright (C) 2007  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/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4, 6 };
+static int ufc_divisors[] = { 1, 1, 4, 6 };
+static int sfc_divisors[] = { 1, 1, 4, 6 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
+			     24, 32, 36, 48, 1, 1, 1, 1 };
+static int mfc_divisors[] = { 1, 1, 4, 6 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
+			      24, 32, 36, 48, 1, 1, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+	clk->rate *= 36;
+}
+
+static struct clk_ops sh7785_master_clk_ops = {
+	.init		= master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+	int idx = (ctrl_inl(FRQMR1) & 0x000f);
+	clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_module_clk_ops = {
+	.recalc		= module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
+	clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_bus_clk_ops = {
+	.recalc		= bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
+	clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7785_cpu_clk_ops = {
+	.recalc		= cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7785_clk_ops[] = {
+	&sh7785_master_clk_ops,
+	&sh7785_module_clk_ops,
+	&sh7785_bus_clk_ops,
+	&sh7785_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+	if (idx < ARRAY_SIZE(sh7785_clk_ops))
+		*ops = sh7785_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
+	clk->rate = clk->parent->rate / sfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_shyway_clk_ops = {
+	.recalc		= shyway_clk_recalc,
+};
+
+static struct clk sh7785_shyway_clk = {
+	.name		= "shyway_clk",
+	.flags		= CLK_ALWAYS_ENABLED,
+	.ops		= &sh7785_shyway_clk_ops,
+};
+
+static void ddr_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
+	clk->rate = clk->parent->rate / mfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ddr_clk_ops = {
+	.recalc		= ddr_clk_recalc,
+};
+
+static struct clk sh7785_ddr_clk = {
+	.name		= "ddr_clk",
+	.flags		= CLK_ALWAYS_ENABLED,
+	.ops		= &sh7785_ddr_clk_ops,
+};
+
+static void ram_clk_recalc(struct clk *clk)
+{
+	int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
+	clk->rate = clk->parent->rate / ufc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ram_clk_ops = {
+	.recalc		= ram_clk_recalc,
+};
+
+static struct clk sh7785_ram_clk = {
+	.name		= "ram_clk",
+	.flags		= CLK_ALWAYS_ENABLED,
+	.ops		= &sh7785_ram_clk_ops,
+};
+
+/*
+ * Additional SH7785-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *sh7785_onchip_clocks[] = {
+	&sh7785_shyway_clk,
+	&sh7785_ddr_clk,
+	&sh7785_ram_clk,
+};
+
+static int __init sh7785_clk_init(void)
+{
+	struct clk *clk = clk_get(NULL, "master_clk");
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
+		struct clk *clkp = sh7785_onchip_clocks[i];
+
+		clkp->parent = clk;
+		clk_register(clkp);
+		clk_enable(clkp);
+	}
+
+	/*
+	 * Now that we have the rest of the clocks registered, we need to
+	 * force the parent clock to propagate so that these clocks will
+	 * automatically figure out their rate. We cheat by handing the
+	 * parent clock its current rate and forcing child propagation.
+	 */
+	clk_set_rate(clk, clk_get_rate(clk));
+
+	clk_put(clk);
+
+	return 0;
+}
+arch_initcall(sh7785_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
new file mode 100644
index 0000000..07b0de8
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -0,0 +1,103 @@
+/*
+ * SH7785 Setup
+ *
+ *  Copyright (C) 2007  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	= 0xffea0000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 40, 41, 43, 42 },
+	}, {
+		.mapbase	= 0xffeb0000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 44, 45, 47, 46 },
+	},
+
+	/*
+	 * The rest of these all have multiplexed IRQs
+	 */
+	{
+		.mapbase	= 0xffec0000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 60, 60, 60, 60 },
+	}, {
+		.mapbase	= 0xffed0000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 61, 61, 61, 61 },
+	}, {
+		.mapbase	= 0xffee0000,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.type		= PORT_SCIF,
+		.irqs		= { 62, 62, 62, 62 },
+	}, {
+		.mapbase	= 0xffef0000,
+		.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 *sh7785_devices[] __initdata = {
+	&sci_device,
+};
+
+static int __init sh7785_devices_setup(void)
+{
+	return platform_add_devices(sh7785_devices,
+				    ARRAY_SIZE(sh7785_devices));
+}
+__initcall(sh7785_devices_setup);
+
+static struct intc2_data intc2_irq_table[] = {
+	{ 28, 0, 24, 0, 0, 2 },		/* TMU0 */
+
+	{ 40, 8, 24, 0, 2, 3 },		/* SCIF0 ERI */
+	{ 41, 8, 24, 0, 2, 3 },		/* SCIF0 RXI */
+	{ 42, 8, 24, 0, 2, 3 },		/* SCIF0 BRI */
+	{ 43, 8, 24, 0, 2, 3 },		/* SCIF0 TXI */
+
+	{ 44, 8, 16, 0, 3, 3 },		/* SCIF1 ERI */
+	{ 45, 8, 16, 0, 3, 3 },		/* SCIF1 RXI */
+	{ 46, 8, 16, 0, 3, 3 },		/* SCIF1 BRI */
+	{ 47, 8, 16, 0, 3, 3 },		/* SCIF1 TXI */
+
+	{ 64, 0x14,  8, 0, 14, 2 },	/* PCIC0 */
+	{ 65, 0x14,  0, 0, 15, 2 },	/* PCIC1 */
+	{ 66, 0x18, 24, 0, 16, 2 },	/* PCIC2 */
+	{ 67, 0x18, 16, 0, 17, 2 },	/* PCIC3 */
+	{ 68, 0x18,  8, 0, 18, 2 },	/* PCIC4 */
+
+	{ 60,  8,  8, 0, 4, 3 },	/* SCIF2 ERI, RXI, BRI, TXI */
+	{ 60,  8,  0, 0, 5, 3 },	/* SCIF3 ERI, RXI, BRI, TXI */
+	{ 60, 12, 24, 0, 6, 3 },	/* SCIF4 ERI, RXI, BRI, TXI */
+	{ 60, 12, 16, 0, 7, 3 },	/* SCIF5 ERI, RXI, BRI, TXI */
+};
+
+void __init init_IRQ_intc2(void)
+{
+	make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
+}
diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c
new file mode 100644
index 0000000..4a2ecbe
--- /dev/null
+++ b/arch/sh/kernel/crash_dump.c
@@ -0,0 +1,46 @@
+/*
+ *	crash_dump.c - Memory preserving reboot related code.
+ *
+ *	Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *	Copyright (C) IBM Corporation, 2004. All rights reserved
+ */
+
+#include <linux/errno.h>
+#include <linux/crash_dump.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+
+/**
+ * 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
+ *	space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ *	otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+                               size_t csize, unsigned long offset, int userbuf)
+{
+	void  *vaddr;
+
+	if (!csize)
+		return 0;
+
+	vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+
+	if (userbuf) {
+		if (copy_to_user(buf, (vaddr + offset), csize)) {
+			iounmap(vaddr);
+			return -EFAULT;
+		}
+	} else
+	memcpy(buf, (vaddr + offset), csize);
+
+	iounmap(vaddr);
+	return csize;
+}
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 9048c03..9833493 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -192,20 +192,14 @@ #endif
 	}
 #endif
 
-	if (likely(early_console))
+	if (likely(early_console)) {
+		if (keep_early)
+			early_console->flags &= ~CON_BOOT;
+		else
+			early_console->flags |= CON_BOOT;
 		register_console(early_console);
+	}
 
 	return 0;
 }
 early_param("earlyprintk", setup_early_printk);
-
-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);
-	} else
-		printk("keeping early console\n");
-}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 9bdd8a0..27b923c 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -13,6 +13,7 @@ #include <linux/kernel_stat.h>
 #include <linux/seq_file.h>
 #include <linux/irq.h>
 #include <asm/processor.h>
+#include <asm/machvec.h>
 #include <asm/uaccess.h>
 #include <asm/thread_info.h>
 #include <asm/cpu/mmu_context.h>
@@ -44,7 +45,7 @@ int show_interrupts(struct seq_file *p, 
 		seq_putc(p, '\n');
 	}
 
-	if (i < NR_IRQS) {
+	if (i < sh_mv.mv_nr_irqs) {
 		spin_lock_irqsave(&irq_desc[i].lock, flags);
 		action = irq_desc[i].action;
 		if (!action)
@@ -61,7 +62,7 @@ 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)
+	} else if (i == sh_mv.mv_nr_irqs)
 		seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
 
 	return 0;
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index d8927d8..a532336 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -6,11 +6,11 @@
  * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
  * Amit S. Kale <akale@veritas.com>,  William Gatliff <bgat@open-widgets.com>,
  * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
- * 
+ *
  * This version by Henry Bell <henry.bell@st.com>
  * Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
- * 
- * Contains low-level support for remote debug using GDB. 
+ *
+ * Contains low-level support for remote debug using GDB.
  *
  * To enable debugger support, two things need to happen. A call to
  * set_debug_traps() is necessary in order to allow any breakpoints
@@ -48,7 +48,7 @@
  *    k             kill (Detach GDB)
  *
  *    d             Toggle debug flag
- *    D             Detach GDB 
+ *    D             Detach GDB
  *
  *    Hct           Set thread t for operations,           OK or ENN
  *                  c = 'c' (step, cont), c = 'g' (other
@@ -58,7 +58,7 @@
  *    qfThreadInfo  Get list of current threads (first)    m<id>
  *    qsThreadInfo   "    "  "     "      "   (subsequent)
  *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z
- * 
+ *
  *    TXX           Find if thread XX is alive             OK or ENN
  *    ?             What was the last sigval ?             SNN   (signal NN)
  *    O             Output to GDB console
@@ -74,7 +74,7 @@
  *       '$' or '#'.  If <data> starts with two characters followed by
  *       ':', then the existing stubs interpret this as a sequence number.
  *
- *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
+ *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit
  *       checksum of <data>, the most significant nibble is sent first.
  *       the hex digits 0-9,a-f are used.
  *
@@ -86,8 +86,8 @@
  * Responses can be run-length encoded to save space.  A '*' means that
  * the next character is an ASCII encoding giving a repeat count which
  * stands for that many repititions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3 
- * (which is where RLE starts to win).  Don't use an n > 126. 
+ * The encoding is n+29, yielding a printable character where n >=3
+ * (which is where RLE starts to win).  Don't use an n > 126.
  *
  * So "0* " means the same as "0000".
  */
@@ -100,12 +100,10 @@ #include <linux/spinlock.h>
 #include <linux/delay.h>
 #include <linux/linkage.h>
 #include <linux/init.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
 #include <linux/console.h>
-#endif
-
+#include <linux/sysrq.h>
 #include <asm/system.h>
+#include <asm/cacheflush.h>
 #include <asm/current.h>
 #include <asm/signal.h>
 #include <asm/pgtable.h>
@@ -153,7 +151,6 @@ char kgdb_in_gdb_mode;
 char in_nmi;			/* Set during NMI to prevent reentry */
 int kgdb_nofault;		/* Boolean to ignore bus errs (i.e. in GDB) */
 int kgdb_enabled = 1;		/* Default to enabled, cmdline can disable */
-int kgdb_halt;
 
 /* Exposed for user access */
 struct task_struct *kgdb_current;
@@ -246,14 +243,6 @@ static char out_buffer[OUTBUFMAX];
 
 static void kgdb_to_gdb(const char *s);
 
-#ifdef CONFIG_KGDB_THREAD
-static struct task_struct *trapped_thread;
-static struct task_struct *current_thread;
-typedef unsigned char threadref[8];
-#define BUF_THREAD_ID_SIZE 16
-#endif
-
-
 /* Convert ch to hex */
 static int hex(const char ch)
 {
@@ -328,7 +317,7 @@ static int hex_to_int(char **ptr, int *i
 }
 
 /*  Copy the binary array pointed to by buf into mem.  Fix $, #,
-    and 0x7d escaped with 0x7d.  Return a pointer to the character 
+    and 0x7d escaped with 0x7d.  Return a pointer to the character
     after the last byte written. */
 static char *ebin_to_mem(const char *buf, char *mem, int count)
 {
@@ -349,66 +338,6 @@ static char *pack_hex_byte(char *pkt, in
 	return pkt;
 }
 
-#ifdef CONFIG_KGDB_THREAD
-
-/* Pack a thread ID */
-static char *pack_threadid(char *pkt, threadref * id)
-{
-	char *limit;
-	unsigned char *altid;
-
-	altid = (unsigned char *) id;
-
-	limit = pkt + BUF_THREAD_ID_SIZE;
-	while (pkt < limit)
-		pkt = pack_hex_byte(pkt, *altid++);
-	return pkt;
-}
-
-/* Convert an integer into our threadref */
-static void int_to_threadref(threadref * id, const int value)
-{
-	unsigned char *scan = (unsigned char *) id;
-	int i = 4;
-
-	while (i--)
-		*scan++ = 0;
-
-	*scan++ = (value >> 24) & 0xff;
-	*scan++ = (value >> 16) & 0xff;
-	*scan++ = (value >> 8) & 0xff;
-	*scan++ = (value & 0xff);
-}
-
-/* Return a task structure ptr for a particular pid */
-static struct task_struct *get_thread(int pid)
-{
-	struct task_struct *thread;
-
-	/* Use PID_MAX w/gdb for pid 0 */
-	if (pid == PID_MAX) pid = 0;
-
-	/* First check via PID */
-	thread = find_task_by_pid(pid);
-
-	if (thread)
-		return thread;
-
-	/* Start at the start */
-	thread = init_tasks[0];
-
-	/* Walk along the linked list of tasks */
-	do {
-		if (thread->pid == pid)
-			return thread;
-		thread = thread->next_task;
-	} while (thread != init_tasks[0]);
-
-	return NULL;
-}
-
-#endif /* CONFIG_KGDB_THREAD */
-
 /* Scan for the start char '$', read the packet and check the checksum */
 static void get_packet(char *buffer, int buflen)
 {
@@ -452,7 +381,7 @@ static void get_packet(char *buffer, int
 				/* Ack successful transfer */
 				put_debug_char('+');
 
-				/* If a sequence char is present, reply 
+				/* If a sequence char is present, reply
 				   the sequence ID */
 				if (buffer[2] == ':') {
 					put_debug_char(buffer[0]);
@@ -611,74 +540,6 @@ static void gdb_regs_to_kgdb_regs(const 
 	regs->vbr = gdb_regs[VBR];
 }
 
-#ifdef CONFIG_KGDB_THREAD
-/* Make a local copy of registers from the specified thread */
-asmlinkage void ret_from_fork(void);
-static void thread_regs_to_gdb_regs(const struct task_struct *thread,
-				    int *gdb_regs)
-{
-	int regno;
-	int *tregs;
-
-	/* Initialize to zero */
-	for (regno = 0; regno < MAXREG; regno++)
-		gdb_regs[regno] = 0;
-
-	/* Just making sure... */
-	if (thread == NULL)
-		return;
-
-	/* A new fork has pt_regs on the stack from a fork() call */
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-
-		int vbr_val;
-		struct pt_regs *kregs;
-		kregs = (struct pt_regs*)thread->thread.sp;
-
-		gdb_regs[R0] = kregs->regs[R0];
-		gdb_regs[R1] = kregs->regs[R1];
-		gdb_regs[R2] = kregs->regs[R2];
-		gdb_regs[R3] = kregs->regs[R3];
-		gdb_regs[R4] = kregs->regs[R4];
-		gdb_regs[R5] = kregs->regs[R5];
-		gdb_regs[R6] = kregs->regs[R6];
-		gdb_regs[R7] = kregs->regs[R7];
-		gdb_regs[R8] = kregs->regs[R8];
-		gdb_regs[R9] = kregs->regs[R9];
-		gdb_regs[R10] = kregs->regs[R10];
-		gdb_regs[R11] = kregs->regs[R11];
-		gdb_regs[R12] = kregs->regs[R12];
-		gdb_regs[R13] = kregs->regs[R13];
-		gdb_regs[R14] = kregs->regs[R14];
-		gdb_regs[R15] = kregs->regs[R15];
-		gdb_regs[PC] = kregs->pc;
-		gdb_regs[PR] = kregs->pr;
-		gdb_regs[GBR] = kregs->gbr;
-		gdb_regs[MACH] = kregs->mach;
-		gdb_regs[MACL] = kregs->macl;
-		gdb_regs[SR] = kregs->sr;
-
-		asm("stc vbr, %0":"=r"(vbr_val));
-		gdb_regs[VBR] = vbr_val;
-		return;
-	}
-
-	/* Otherwise, we have only some registers from switch_to() */
-	tregs = (int *)thread->thread.sp;
-	gdb_regs[R15] = (int)tregs;
-	gdb_regs[R14] = *tregs++;
-	gdb_regs[R13] = *tregs++;
-	gdb_regs[R12] = *tregs++;
-	gdb_regs[R11] = *tregs++;
-	gdb_regs[R10] = *tregs++;
-	gdb_regs[R9] = *tregs++;
-	gdb_regs[R8] = *tregs++;
-	gdb_regs[PR] = *tregs++;
-	gdb_regs[GBR] = *tregs++;
-	gdb_regs[PC] = thread->thread.pc;
-}
-#endif /* CONFIG_KGDB_THREAD */
-
 /* Calculate the new address for after a step */
 static short *get_step_address(void)
 {
@@ -759,7 +620,7 @@ static short *get_step_address(void)
 	return (short *) addr;
 }
 
-/* Set up a single-step.  Replace the instruction immediately after the 
+/* Set up a single-step.  Replace the instruction immediately after the
    current instruction (i.e. next in the expected flow of control) with a
    trap instruction, so that returning will cause only a single instruction
    to be executed. Note that this model is slightly broken for instructions
@@ -797,37 +658,11 @@ static void undo_single_step(void)
 /* Send a signal message */
 static void send_signal_msg(const int signum)
 {
-#ifndef CONFIG_KGDB_THREAD
 	out_buffer[0] = 'S';
 	out_buffer[1] = highhex(signum);
 	out_buffer[2] = lowhex(signum);
 	out_buffer[3] = 0;
 	put_packet(out_buffer);
-#else /* CONFIG_KGDB_THREAD */
-	int threadid;
-	threadref thref;
-	char *out = out_buffer;
-	const char *tstring = "thread";
-
-	*out++ = 'T';
-	*out++ = highhex(signum);
-	*out++ = lowhex(signum);
-
-	while (*tstring) {
-		*out++ = *tstring++;
-	}
-	*out++ = ':';
-
-	threadid = trapped_thread->pid;
-	if (threadid == 0) threadid = PID_MAX;
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out, &thref);
-	out += BUF_THREAD_ID_SIZE;
-	*out++ = ';';
-
-	*out = 0;
-	put_packet(out_buffer);
-#endif /* CONFIG_KGDB_THREAD */
 }
 
 /* Reply that all was well */
@@ -962,15 +797,7 @@ static void step_with_sig_msg(void)
 /* Send register contents */
 static void send_regs_msg(void)
 {
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread)
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-	else
-		thread_regs_to_gdb_regs(current_thread, registers);
-#else
 	kgdb_regs_to_gdb_regs(&trap_registers, registers);
-#endif
-
 	mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
 	put_packet(out_buffer);
 }
@@ -978,201 +805,13 @@ #endif
 /* Set register contents - currently can't set other thread's registers */
 static void set_regs_msg(void)
 {
-#ifdef CONFIG_KGDB_THREAD
-	if (!current_thread) {
-#endif
-		kgdb_regs_to_gdb_regs(&trap_registers, registers);
-		hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
-		gdb_regs_to_kgdb_regs(registers, &trap_registers);
-		send_ok_msg();
-#ifdef CONFIG_KGDB_THREAD
-	} else
-		send_err_msg();
-#endif
-}
-
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Set the status for a thread */
-void set_thread_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char *ptr;
-
-	switch (in_buffer[1]) {
-
-       	/* To select which thread for gG etc messages, i.e. supported */
-	case 'g':
-
-		ptr = &in_buffer[2];
-		hex_to_int(&ptr, &threadid);
-		thread = get_thread(threadid);
-
-		/* If we haven't found it */
-		if (!thread) {
-			send_err_msg();
-			break;
-		}
-
-		/* Set current_thread (or not) */
-		if (thread == trapped_thread)
-			current_thread = NULL;
-		else
-			current_thread = thread;
-		send_ok_msg();
-		break;
-
-	/* To select which thread for cCsS messages, i.e. unsupported */
-	case 'c':
-		send_ok_msg();
-		break;
-
-	default:
-		send_empty_msg();
-		break;
-	}
-}
-
-/* Is a thread alive? */
-static void thread_status_msg(void)
-{
-	char *ptr;
-	int threadid;
-	struct task_struct *thread = NULL;
-
-	ptr = &in_buffer[1];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-	if (thread)
-		send_ok_msg();
-	else
-		send_err_msg();
-}
-/* Send the current thread ID */
-static void thread_id_msg(void)
-{
-	int threadid;
-	threadref thref;
-
-	out_buffer[0] = 'Q';
-	out_buffer[1] = 'C';
-
-	if (current_thread)
-		threadid = current_thread->pid;
-	else if (trapped_thread)
-		threadid = trapped_thread->pid;
-	else /* Impossible, but just in case! */
-	{
-		send_err_msg();
-		return;
-	}
-
-	/* Translate pid 0 to PID_MAX for gdb */
-	if (threadid == 0) threadid = PID_MAX;
-
-	int_to_threadref(&thref, threadid);
-	pack_threadid(out_buffer + 2, &thref);
-	out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
-	put_packet(out_buffer);
-}
-
-/* Send thread info */
-static void thread_info_msg(void)
-{
-	struct task_struct *thread = NULL;
-	int threadid;
-	char *pos;
-	threadref thref;
-
-	/* Start with 'm' */
-	out_buffer[0] = 'm';
-	pos = &out_buffer[1];
-
-	/* For all possible thread IDs - this will overrun if > 44 threads! */
-	/* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
-	for (threadid = 1; threadid <= PID_MAX; threadid++) {
-
-		read_lock(&tasklist_lock);
-		thread = get_thread(threadid);
-		read_unlock(&tasklist_lock);
-
-		/* If it's a valid thread */
-		if (thread) {
-			int_to_threadref(&thref, threadid);
-			pack_threadid(pos, &thref);
-			pos += BUF_THREAD_ID_SIZE;
-			*pos++ = ',';
-		}
-	}
-	*--pos = 0;		/* Lose final comma */
-	put_packet(out_buffer);
-
-}
-
-/* Return printable info for gdb's 'info threads' command */
-static void thread_extra_info_msg(void)
-{
-	int threadid;
-	struct task_struct *thread = NULL;
-	char buffer[20], *ptr;
-	int i;
-
-	/* Extract thread ID */
-	ptr = &in_buffer[17];
-	hex_to_int(&ptr, &threadid);
-	thread = get_thread(threadid);
-
-	/* If we don't recognise it, say so */
-	if (thread == NULL)
-		strcpy(buffer, "(unknown)");
-	else
-		strcpy(buffer, thread->comm);
-
-	/* Construct packet */
-	for (i = 0, ptr = out_buffer; buffer[i]; i++)
-		ptr = pack_hex_byte(ptr, buffer[i]);
-
-	if (thread->thread.pc == (unsigned long)ret_from_fork) {
-		strcpy(buffer, "<new fork>");
-		for (i = 0; buffer[i]; i++)
-			ptr = pack_hex_byte(ptr, buffer[i]);
-	}
-
-	*ptr = '\0';
-	put_packet(out_buffer);
-}
-
-/* Handle all qFooBarBaz messages - have to use an if statement as
-   opposed to a switch because q messages can have > 1 char id. */
-static void query_msg(void)
-{
-	const char *q_start = &in_buffer[1];
-
-	/* qC = return current thread ID */
-	if (strncmp(q_start, "C", 1) == 0)
-		thread_id_msg();
-
-	/* qfThreadInfo = query all threads (first) */
-	else if (strncmp(q_start, "fThreadInfo", 11) == 0)
-		thread_info_msg();
-
-	/* qsThreadInfo = query all threads (subsequent). We know we have sent
-	   them all after the qfThreadInfo message, so there are no to send */
-	else if (strncmp(q_start, "sThreadInfo", 11) == 0)
-		put_packet("l");	/* el = last */
-
-	/* qThreadExtraInfo = supply printable information per thread */
-	else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
-		thread_extra_info_msg();
-
-	/* Unsupported - empty message as per spec */
-	else
-		send_empty_msg();
+	kgdb_regs_to_gdb_regs(&trap_registers, registers);
+	hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
+	gdb_regs_to_kgdb_regs(registers, &trap_registers);
+	send_ok_msg();
 }
-#endif /* CONFIG_KGDB_THREAD */
 
+#ifdef CONFIG_SH_KGDB_CONSOLE
 /*
  * Bring up the ports..
  */
@@ -1185,6 +824,9 @@ static int kgdb_serial_setup(void)
 
 	return 0;
 }
+#else
+#define kgdb_serial_setup()	0
+#endif
 
 /* The command loop, read and act on requests */
 static void kgdb_command_loop(const int excep_code, const int trapa_value)
@@ -1193,7 +835,7 @@ static void kgdb_command_loop(const int 
 
 	if (excep_code == NMI_VEC) {
 #ifndef CONFIG_KGDB_NMI
-		KGDB_PRINTK("Ignoring unexpected NMI?\n");
+		printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
 		return;
 #else /* CONFIG_KGDB_NMI */
 		if (!kgdb_enabled) {
@@ -1207,19 +849,10 @@ #endif /* CONFIG_KGDB_NMI */
 	if (!kgdb_enabled)
 		return;
 
-#ifdef CONFIG_KGDB_THREAD
-	/* Until GDB specifies a thread */
-	current_thread = NULL;
-	trapped_thread = current;
-#endif
-
 	/* Enter GDB mode (e.g. after detach) */
 	if (!kgdb_in_gdb_mode) {
 		/* Do serial setup, notify user, issue preemptive ack */
-		kgdb_serial_setup();
-		KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
-			    (kgdb_porttype ? kgdb_porttype->name : ""),
-			    kgdb_portnum, kgdb_baud);
+		printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
 		kgdb_in_gdb_mode = 1;
 		put_debug_char('+');
 	}
@@ -1233,21 +866,18 @@ #endif
 	   will later be replaced by its original one.  Do NOT do this for
 	   trap 0xff, since that indicates a compiled-in breakpoint which
 	   will not be replaced (and we would retake the trap forever) */
-	if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
+	if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2)))
 		trap_registers.pc -= 2;
-	}
 
 	/* Undo any stepping we may have done */
 	undo_single_step();
 
 	while (1) {
-
 		out_buffer[0] = 0;
 		get_packet(in_buffer, BUFMAX);
 
 		/* Examine first char of buffer to see what we need to do */
 		switch (in_buffer[0]) {
-
 		case '?':	/* Send which signal we've received */
 			send_signal_msg(sigval);
 			break;
@@ -1291,21 +921,6 @@ #endif
 			step_msg();
 			return;
 
-#ifdef CONFIG_KGDB_THREAD
-
-		case 'H':	/* Task related */
-			set_thread_msg();
-			break;
-
-		case 'T':	/* Query thread status */
-			thread_status_msg();
-			break;
-
-		case 'q':	/* Handle query - currently thread-related */
-			query_msg();
-			break;
-#endif
-
 		case 'k':	/* 'Kill the program' with a kernel ? */
 			break;
 
@@ -1323,11 +938,8 @@ #endif
 }
 
 /* There has been an exception, most likely a breakpoint. */
-asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
-				      unsigned long r6, unsigned long r7,
-				      struct pt_regs __regs)
+static void handle_exception(struct pt_regs *regs)
 {
-	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 	int excep_code, vbr_val;
 	int count;
 	int trapa_value = ctrl_inl(TRA);
@@ -1355,7 +967,7 @@ asmlinkage void kgdb_handle_exception(un
 	kgdb_trapa_val = trapa_value;
 
 	/* Act on the exception */
-	kgdb_command_loop(excep_code >> 5, trapa_value);
+	kgdb_command_loop(excep_code, trapa_value);
 
 	kgdb_current = NULL;
 
@@ -1373,14 +985,12 @@ asmlinkage void kgdb_handle_exception(un
 	asm("ldc %0, vbr": :"r"(vbr_val));
 }
 
-/* Trigger a breakpoint by function */
-void breakpoint(void)
+asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
+				      unsigned long r6, unsigned long r7,
+				      struct pt_regs __regs)
 {
-	if (!kgdb_enabled) {
-		kgdb_enabled = 1;
-		kgdb_init();
-	}
-	BREAKPOINT();
+	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+	handle_exception(regs);
 }
 
 /* Initialise the KGDB data structures and serial configuration */
@@ -1395,24 +1005,16 @@ int kgdb_init(void)
 	kgdb_in_gdb_mode = 0;
 
 	if (kgdb_serial_setup() != 0) {
-		KGDB_PRINTK("serial setup error\n");
+		printk(KERN_NOTICE "KGDB: serial setup error\n");
 		return -1;
 	}
 
 	/* Init ptr to exception handler */
-	kgdb_debug_hook = kgdb_handle_exception;
+	kgdb_debug_hook = handle_exception;
 	kgdb_bus_err_hook = kgdb_handle_bus_error;
 
 	/* Enter kgdb now if requested, or just report init done */
-	if (kgdb_halt) {
-		kgdb_in_gdb_mode = 1;
-		put_debug_char('+');
-		breakpoint();
-	}
-	else
-	{
-		KGDB_PRINTK("stub is initialized.\n");
-	}
+	printk(KERN_NOTICE "KGDB: stub is initialized.\n");
 
 	return 0;
 }
@@ -1437,7 +1039,7 @@ static void kgdb_msg_write(const char *s
 
 		/* Calculate how many this time */
 		wcount = (count > MAXOUT) ? MAXOUT : count;
-		
+
 		/* Pack in hex chars */
 		for (i = 0; i < wcount; i++)
 			bufptr = pack_hex_byte(bufptr, s[i]);
@@ -1467,3 +1069,25 @@ void kgdb_console_write(struct console *
 	kgdb_msg_write(s, count);
 }
 #endif
+
+#ifdef CONFIG_KGDB_SYSRQ
+static void sysrq_handle_gdb(int key, struct tty_struct *tty)
+{
+	printk("Entering GDB stub\n");
+	breakpoint();
+}
+
+static struct sysrq_key_op sysrq_gdb_op = {
+        .handler        = sysrq_handle_gdb,
+        .help_msg       = "Gdb",
+        .action_msg     = "GDB",
+};
+
+static int gdb_register_sysrq(void)
+{
+	printk("Registering GDB sysrq handler\n");
+	register_sysrq_key('g', &sysrq_gdb_op);
+	return 0;
+}
+module_init(gdb_register_sysrq);
+#endif
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 08587cd..790ed69 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -59,13 +59,13 @@ static void kexec_info(struct kimage *im
 	        printk("  segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
 		       i,
 		       (unsigned int)image->segment[i].mem,
-		       (unsigned int)image->segment[i].mem + image->segment[i].memsz,
+		       (unsigned int)image->segment[i].mem +
+				     image->segment[i].memsz,
 		       (unsigned int)image->segment[i].memsz);
- 	}
+	}
 	printk("  start     : 0x%08x\n\n", (unsigned int)image->start);
 }
 
-
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
@@ -101,6 +101,27 @@ #endif
 
 	/* now call it */
 	rnk = (relocate_new_kernel_t) reboot_code_buffer;
-       	(*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
+	(*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
 }
 
+/* crashkernel=size@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/sh/kernel/process.c b/arch/sh/kernel/process.c
index e760736..329b3f3 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -7,7 +7,7 @@
  *
  *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  *		     Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- *		     Copyright (C) 2002 - 2006  Paul Mundt
+ *		     Copyright (C) 2002 - 2007  Paul Mundt
  */
 #include <linux/module.h>
 #include <linux/mm.h>
@@ -15,6 +15,7 @@ #include <linux/elfcore.h>
 #include <linux/pm.h>
 #include <linux/kallsyms.h>
 #include <linux/kexec.h>
+#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/ubc.h>
@@ -299,7 +300,8 @@ #endif
 	ctrl_outl(0, UBC_BAMRA);
 
 	if (current_cpu_data.type == CPU_SH7729 ||
-	    current_cpu_data.type == CPU_SH7710) {
+	    current_cpu_data.type == CPU_SH7710 ||
+	    current_cpu_data.type == CPU_SH7712) {
 		ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
 		ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
 	} else {
@@ -495,6 +497,10 @@ asmlinkage void debug_trap_handler(unsig
 	/* Rewind */
 	regs->pc -= 2;
 
+	if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
+		       SIGTRAP) == NOTIFY_STOP)
+		return;
+
 	force_sig(SIGTRAP, current);
 }
 
@@ -510,6 +516,10 @@ asmlinkage void bug_trap_handler(unsigne
 	/* Rewind */
 	regs->pc -= 2;
 
+	if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
+		       SIGTRAP) == NOTIFY_STOP)
+		return;
+
 #ifdef CONFIG_BUG
 	if (__kernel_text_address(instruction_pointer(regs))) {
 		u16 insn = *(u16 *)instruction_pointer(regs);
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index 855f724..3fb5fc0 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -12,7 +12,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 98802ab..477d2a8 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -4,7 +4,7 @@
  * This file handles the architecture-dependent parts of initialization
  *
  *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2002 - 2006 Paul Mundt
+ *  Copyright (C) 2002 - 2007 Paul Mundt
  */
 #include <linux/screen_info.h>
 #include <linux/ioport.h>
@@ -15,21 +15,22 @@ #include <linux/console.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/utsname.h>
+#include <linux/nodemask.h>
 #include <linux/cpu.h>
 #include <linux/pfn.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/clock.h>
+#include <asm/mmu_context.h>
 
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_parse_options(char *options);
-#endif
 extern void * __rd_start, * __rd_end;
+
 /*
  * Machine setup..
  */
@@ -205,53 +206,33 @@ #endif
 	return 0;
 }
 
-void __init setup_arch(char **cmdline_p)
+/*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+static void __init register_bootmem_low_pages(void)
 {
-	unsigned long bootmap_size;
-	unsigned long start_pfn, max_pfn, max_low_pfn;
-
-#ifdef CONFIG_CMDLINE_BOOL
-        strcpy(COMMAND_LINE, CONFIG_CMDLINE);
-#endif
-
-	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
-
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-
-	if (!MOUNT_ROOT_RDONLY)
-		root_mountflags &= ~MS_RDONLY;
-	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 = (unsigned long)virt_to_phys(_text);
-	code_resource.end = (unsigned long)virt_to_phys(_etext)-1;
-	data_resource.start = (unsigned long)virt_to_phys(_etext);
-	data_resource.end = (unsigned long)virt_to_phys(_edata)-1;
-
-	sh_mv_setup(cmdline_p);
-
+	unsigned long curr_pfn, last_pfn, pages;
 
 	/*
-	 * Find the highest page frame number we have available
+	 * We are rounding up the start address of usable memory:
 	 */
-	max_pfn = PFN_DOWN(__pa(memory_end));
+	curr_pfn = PFN_UP(__MEMORY_START);
 
 	/*
-	 * Determine low and high memory ranges:
+	 * ... and at the end of the usable range downwards:
 	 */
-	max_low_pfn = max_pfn;
+	last_pfn = PFN_DOWN(__pa(memory_end));
 
-	/*
-	 * Partially used pages are not usable - thus
-	 * we are rounding upwards:
-	 */
-	start_pfn = PFN_UP(__pa(_end));
+	if (last_pfn > max_low_pfn)
+		last_pfn = max_low_pfn;
+
+	pages = last_pfn - curr_pfn;
+	free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
+}
+
+void __init setup_bootmem_allocator(unsigned long start_pfn)
+{
+	unsigned long bootmap_size;
 
 	/*
 	 * Find a proper area for the bootmem bitmap. After this
@@ -259,31 +240,11 @@ #endif
 	 * is intact) must be done via bootmem_alloc().
 	 */
 	bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
-					 __MEMORY_START>>PAGE_SHIFT,
-					 max_low_pfn);
-	/*
-	 * Register fully available low RAM pages with the bootmem allocator.
-	 */
-	{
-		unsigned long curr_pfn, last_pfn, pages;
-
-		/*
-		 * We are rounding up the start address of usable memory:
-		 */
-		curr_pfn = PFN_UP(__MEMORY_START);
-		/*
-		 * ... and at the end of the usable range downwards:
-		 */
-		last_pfn = PFN_DOWN(__pa(memory_end));
+					 min_low_pfn, max_low_pfn);
 
-		if (last_pfn > max_low_pfn)
-			last_pfn = max_low_pfn;
-
-		pages = last_pfn - curr_pfn;
-		free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
-				  PFN_PHYS(pages));
-	}
+	register_bootmem_low_pages();
 
+	node_set_online(0);
 
 	/*
 	 * Reserve the kernel text and
@@ -292,14 +253,14 @@ #endif
 	 * case of us accidentally initializing the bootmem allocator with
 	 * an invalid RAM area.
 	 */
-	reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE,
+	reserve_bootmem(__MEMORY_START+PAGE_SIZE,
 		(PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
 
 	/*
 	 * reserve physical page 0 - it's a special BIOS page on many boxes,
 	 * enabling clean reboots, SMP operation, laptop functions.
 	 */
-	reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE);
+	reserve_bootmem(__MEMORY_START, PAGE_SIZE);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
@@ -313,8 +274,8 @@ #ifdef CONFIG_BLK_DEV_INITRD
 
 	if (LOADER_TYPE && INITRD_START) {
 		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
-			reserve_bootmem_node(NODE_DATA(0), INITRD_START +
-						__MEMORY_START, INITRD_SIZE);
+			reserve_bootmem(INITRD_START + __MEMORY_START,
+					INITRD_SIZE);
 			initrd_start = INITRD_START + PAGE_OFFSET +
 					__MEMORY_START;
 			initrd_end = initrd_start + INITRD_SIZE;
@@ -327,6 +288,76 @@ #ifdef CONFIG_BLK_DEV_INITRD
 		}
 	}
 #endif
+#ifdef CONFIG_KEXEC
+	if (crashk_res.start != crashk_res.end)
+		reserve_bootmem(crashk_res.start,
+			crashk_res.end - crashk_res.start + 1);
+#endif
+}
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+static void __init setup_memory(void)
+{
+	unsigned long start_pfn;
+
+	/*
+	 * Partially used pages are not usable - thus
+	 * we are rounding upwards:
+	 */
+	start_pfn = PFN_UP(__pa(_end));
+	setup_bootmem_allocator(start_pfn);
+}
+#else
+extern void __init setup_memory(void);
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+	enable_mmu();
+
+#ifdef CONFIG_CMDLINE_BOOL
+	strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+#endif
+
+	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
+	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_early_param();
+
+	sh_mv_setup(cmdline_p);
+
+	/*
+	 * Find the highest page frame number we have available
+	 */
+	max_pfn = PFN_DOWN(__pa(memory_end));
+
+	/*
+	 * Determine low and high memory ranges:
+	 */
+	max_low_pfn = max_pfn;
+	min_low_pfn = __MEMORY_START >> PAGE_SHIFT;
+
+	nodes_clear(node_online_map);
+	setup_memory();
+	paging_init();
+	sparse_init();
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -335,8 +366,6 @@ #endif
 	/* Perform the machine specific initialisation */
 	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)
@@ -380,6 +409,7 @@ static const char *cpu_name[] = {
 	[CPU_SH7705]	= "SH7705",	[CPU_SH7706]	= "SH7706",
 	[CPU_SH7707]	= "SH7707",	[CPU_SH7708]	= "SH7708",
 	[CPU_SH7709]	= "SH7709",	[CPU_SH7710]	= "SH7710",
+	[CPU_SH7712]	= "SH7712",
 	[CPU_SH7729]	= "SH7729",	[CPU_SH7750]	= "SH7750",
 	[CPU_SH7750S]	= "SH7750S",	[CPU_SH7750R]	= "SH7750R",
 	[CPU_SH7751]	= "SH7751",	[CPU_SH7751R]	= "SH7751R",
@@ -477,7 +507,7 @@ static int show_cpuinfo(struct seq_file 
 		     c->loops_per_jiffy/(500000/HZ),
 		     (c->loops_per_jiffy/(5000/HZ)) % 100);
 
-	return show_clocks(m);
+	return 0;
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
@@ -499,92 +529,3 @@ struct seq_operations cpuinfo_op = {
 	.show	= show_cpuinfo,
 };
 #endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_SH_KGDB
-/*
- * Parse command-line kgdb options.  By default KGDB is enabled,
- * entered on error (or other action) using default serial info.
- * The command-line option can include a serial port specification
- * and an action to override default or configured behavior.
- */
-struct kgdb_sermap kgdb_sci_sermap =
-{ "ttySC", 5, kgdb_sci_setup, NULL };
-
-struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
-struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
-
-void kgdb_register_sermap(struct kgdb_sermap *map)
-{
-	struct kgdb_sermap *last;
-
-	for (last = kgdb_serlist; last->next; last = last->next)
-		;
-	last->next = map;
-	if (!map->namelen) {
-		map->namelen = strlen(map->name);
-	}
-}
-
-static int __init kgdb_parse_options(char *options)
-{
-	char c;
-	int baud;
-
-	/* Check for port spec (or use default) */
-
-	/* Determine port type and instance */
-	if (!memcmp(options, "tty", 3)) {
-		struct kgdb_sermap *map = kgdb_serlist;
-
-		while (map && memcmp(options, map->name, map->namelen))
-			map = map->next;
-
-		if (!map) {
-			KGDB_PRINTK("unknown port spec in %s\n", options);
-			return -1;
-		}
-
-		kgdb_porttype = map;
-		kgdb_serial_setup = map->setup_fn;
-		kgdb_portnum = options[map->namelen] - '0';
-		options += map->namelen + 1;
-
-		options = (*options == ',') ? options+1 : options;
-
-		/* Read optional parameters (baud/parity/bits) */
-		baud = simple_strtoul(options, &options, 10);
-		if (baud != 0) {
-			kgdb_baud = baud;
-
-			c = toupper(*options);
-			if (c == 'E' || c == 'O' || c == 'N') {
-				kgdb_parity = c;
-				options++;
-			}
-
-			c = *options;
-			if (c == '7' || c == '8') {
-				kgdb_bits = c;
-				options++;
-			}
-			options = (*options == ',') ? options+1 : options;
-		}
-	}
-
-	/* Check for action specification */
-	if (!memcmp(options, "halt", 4)) {
-		kgdb_halt = 1;
-		options += 4;
-	} else if (!memcmp(options, "disabled", 8)) {
-		kgdb_enabled = 0;
-		options += 8;
-	}
-
-	if (*options) {
-                KGDB_PRINTK("ignored unknown options: %s\n", options);
-		return 0;
-	}
-	return 1;
-}
-__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 6e0d10f..fa91641 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -5,7 +5,6 @@ #include <linux/elfcore.h>
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/pci.h>
 #include <linux/irq.h>
@@ -65,7 +64,6 @@ #define DECLARE_EXPORT(name) extern void
 
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
-DECLARE_EXPORT(__udivdi3);
 DECLARE_EXPORT(__sdivsi3);
 DECLARE_EXPORT(__ashrdi3);
 DECLARE_EXPORT(__ashldi3);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 9f39ef1..eb0191c 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
index 0d5268a..4bdd2f8 100644
--- a/arch/sh/kernel/stacktrace.c
+++ b/arch/sh/kernel/stacktrace.c
@@ -19,14 +19,7 @@ #include <asm/ptrace.h>
  */
 void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
 {
-	unsigned long *sp;
-
-	if (!task)
-		task = current;
-	if (task == current)
-		sp = (unsigned long *)current_stack_pointer;
-	else
-		sp = (unsigned long *)task->thread.sp;
+	unsigned long *sp = (unsigned long *)current_stack_pointer;
 
 	while (!kstack_end(sp)) {
 		unsigned long addr = *sp++;
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index e18f183..76b1bc7 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -12,7 +12,6 @@ #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
index a574b93..82de689 100644
--- a/arch/sh/kernel/timers/timer-cmt.c
+++ b/arch/sh/kernel/timers/timer-cmt.c
@@ -115,7 +115,7 @@ static irqreturn_t cmt_timer_interrupt(i
 static struct irqaction cmt_irq = {
 	.name		= "timer",
 	.handler	= cmt_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.mask		= CPU_MASK_NONE,
 };
 
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
index fffcd1c..b7499a2 100644
--- a/arch/sh/kernel/timers/timer-mtu2.c
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -110,7 +110,7 @@ static irqreturn_t mtu2_timer_interrupt(
 static struct irqaction mtu2_irq = {
 	.name		= "timer",
 	.handler	= mtu2_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.mask		= CPU_MASK_NONE,
 };
 
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index e060e71..d9e3151 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -99,7 +99,7 @@ static irqreturn_t tmu_timer_interrupt(i
 static struct irqaction tmu_irq = {
 	.name		= "timer",
 	.handler	= tmu_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
 	.mask		= CPU_MASK_NONE,
 };
 
@@ -148,7 +148,9 @@ static int tmu_timer_init(void)
 
 	/* Start TMU0 */
 	tmu_timer_stop();
-#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+    !defined(CONFIG_CPU_SUBTYPE_SH7785)
 	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
 #endif
 
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index e9f168f..7b40f0f 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -5,7 +5,7 @@
  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  *                  Copyright (C) 2000 Philipp Rumpf
  *                  Copyright (C) 2000 David Howells
- *                  Copyright (C) 2002 - 2006 Paul Mundt
+ *                  Copyright (C) 2002 - 2007 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
@@ -18,10 +18,12 @@ #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/io.h>
+#include <linux/bug.h>
 #include <linux/debug_locks.h>
 #include <linux/limits.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/kdebug.h>
 
 #ifdef CONFIG_SH_KGDB
 #include <asm/kgdb.h>
@@ -74,7 +76,21 @@ static void dump_mem(const char *str, un
 	}
 }
 
-DEFINE_SPINLOCK(die_lock);
+ATOMIC_NOTIFIER_HEAD(shdie_chain);
+
+int register_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&shdie_chain, nb);
+}
+EXPORT_SYMBOL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&shdie_chain, nb);
+}
+EXPORT_SYMBOL(unregister_die_notifier);
+
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
@@ -130,40 +146,6 @@ static int die_if_no_fixup(const char * 
 	return -EFAULT;
 }
 
-#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
-	struct bug_frame f;
-	long len;
-
-	if (__copy_from_user(&f, (const void __user *)regs->pc,
-			     sizeof(struct bug_frame)))
-		return;
-
-	len = __strnlen_user(f.file, PATH_MAX) - 1;
-	if (unlikely(len < 0 || len >= PATH_MAX))
-		f.file = "<bad filename>";
-	len = __strnlen_user(f.func, PATH_MAX) - 1;
-	if (unlikely(len < 0 || len >= PATH_MAX))
-		f.func = "<bad function>";
-
-	printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
-	       f.func, f.file, f.line);
-}
-#else
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
-}
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
-
-void handle_BUG(struct pt_regs *regs)
-{
-	do_bug_verbose(regs);
-	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
-}
-#endif /* CONFIG_BUG */
-
 /*
  * handle an instruction that does an unaligned memory access by emulating the
  * desired behaviour
@@ -888,6 +870,25 @@ #endif
 	per_cpu_trap_init();
 }
 
+#ifdef CONFIG_BUG
+void handle_BUG(struct pt_regs *regs)
+{
+	enum bug_trap_type tt;
+	tt = report_bug(regs->pc);
+	if (tt == BUG_TRAP_TYPE_WARN) {
+		regs->pc += 2;
+		return;
+	}
+
+	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+	return addr >= PAGE_OFFSET;
+}
+#endif
+
 void show_trace(struct task_struct *tsk, unsigned long *sp,
 		struct pt_regs *regs)
 {
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 78a6c09..d83143c 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -34,9 +34,11 @@ SECTIONS
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
 
+  _etext = .;			/* End of text section */
+
   RODATA
 
-  _etext = .;			/* End of text section */
+  BUG_TABLE
 
   .data : {			/* Data */
 	*(.data)
@@ -53,8 +55,12 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
   .data.page_aligned : { *(.data.page_aligned) }
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(PAGE_SIZE);
+  __nosave_end = .;
 
-  . = ALIGN(L1_CACHE_BYTES);
+  . = ALIGN(PAGE_SIZE);
   __per_cpu_start = .;
   .data.percpu : { *(.data.percpu) }
   __per_cpu_end = .;
@@ -110,43 +116,10 @@ #endif
    * it's a module.
    */
   /DISCARD/ : {
-	*(.exit.text)
-	*(.exit.data)
 	*(.exitcall.exit)
 	}
 
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging section are relative to the beginning
-     of the section so we begin .debug at 0.  */
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-  /* These must appear regardless of  .  */
+  STABS_DEBUG
+
+  DWARF_DEBUG
 }
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index b5681e3..e23dd1a 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -3,11 +3,9 @@ # Makefile for SuperH-specific library f
 #
 
 lib-y  = delay.o memset.o memmove.o memchr.o \
-	 checksum.o strcasecmp.o strlen.o div64.o udivdi3.o \
-	 div64-generic.o
+	 checksum.o strlen.o div64.o div64-generic.o
 
 memcpy-y			:= memcpy.o
 memcpy-$(CONFIG_CPU_SH4)	:= memcpy-sh4.o
 
 lib-y	+= $(memcpy-y)
-
diff --git a/arch/sh/lib/strcasecmp.c b/arch/sh/lib/strcasecmp.c
deleted file mode 100644
index 4e57a21..0000000
--- a/arch/sh/lib/strcasecmp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  linux/arch/alpha/lib/strcasecmp.c
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale.  Since this is used in
-   only one place, on strings known to contain only 7 bit ASCII, this
-   is ok.  */
-
-int strcasecmp(const char *a, const char *b)
-{
-	int ca, cb;
-
-	do {
-		ca = *a++ & 0xff;
-		cb = *b++ & 0xff;
-		if (ca >= 'A' && ca <= 'Z')
-			ca += 'a' - 'A';
-		if (cb >= 'A' && cb <= 'Z')
-			cb += 'a' - 'A';
-	} while (ca == cb && ca != '\0');
-
-	return ca - cb;
-}
diff --git a/arch/sh/lib/udivdi3.c b/arch/sh/lib/udivdi3.c
deleted file mode 100644
index 68f038b..0000000
--- a/arch/sh/lib/udivdi3.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Simple __udivdi3 function which doesn't use FPU.
- */
-
-#include <linux/types.h>
-
-extern u64 __xdiv64_32(u64 n, u32 d);
-extern void panic(const char * fmt, ...);
-
-u64 __udivdi3(u64 n, u64 d)
-{
-	if (d & ~0xffffffff)
-		panic("Need true 64-bit/64-bit division");
-	return __xdiv64_32(n, (u32)d);
-}
-
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 6b0d28a..12f3d39 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -67,6 +67,7 @@ config CPU_SUBTYPE_SH7300
 config CPU_SUBTYPE_SH7705
 	bool "Support SH7705 processor"
 	select CPU_SH3
+	select CPU_HAS_IPR_IRQ
 	select CPU_HAS_PINT_IRQ
 
 config CPU_SUBTYPE_SH7706
@@ -101,9 +102,17 @@ config CPU_SUBTYPE_SH7709
 config CPU_SUBTYPE_SH7710
 	bool "Support SH7710 processor"
 	select CPU_SH3
+	select CPU_HAS_IPR_IRQ
 	help
 	  Select SH7710 if you have a SH3-DSP SH7710 CPU.
 
+config CPU_SUBTYPE_SH7712
+	bool "Support SH7712 processor"
+	select CPU_SH3
+	select CPU_HAS_IPR_IRQ
+	help
+	  Select SH7712 if you have a SH3-DSP SH7712 CPU.
+
 comment "SH-4 Processor Support"
 
 config CPU_SUBTYPE_SH7750
@@ -283,6 +292,17 @@ config VSYSCALL
 	  For systems with an MMU that can afford to give up a page,
 	  (the default value) say Y.
 
+config NODES_SHIFT
+	int
+	default "1"
+	depends on NEED_MULTIPLE_NODES
+
+config ARCH_FLATMEM_ENABLE
+	def_bool y
+
+config ARCH_POPULATES_NODE_MAP
+	def_bool y
+
 choice
 	prompt "Kernel page size"
 	default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c
index 34d4e0c..923cb45 100644
--- a/arch/sh/mm/fault-nommu.c
+++ b/arch/sh/mm/fault-nommu.c
@@ -19,7 +19,6 @@ #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 <asm/system.h>
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index fa5d7f0..0ecc117 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -2,7 +2,7 @@
  * Page fault handler for SH with an MMU.
  *
  *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2003  Paul Mundt
+ *  Copyright (C) 2003 - 2007  Paul Mundt
  *
  *  Based on linux/arch/i386/mm/fault.c:
  *   Copyright (C) 1995  Linus Torvalds
@@ -15,12 +15,42 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
+#include <asm/kdebug.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 #include <asm/kgdb.h>
 
-extern void die(const char *,struct pt_regs *,long);
+#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(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&notify_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(&notify_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,
@@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(
 	siginfo_t info;
 
 	trace_hardirqs_on();
+
+	if (notify_page_fault(DIE_PAGE_FAULT, regs,
+			      writeaccess, SIGSEGV) == NOTIFY_STOP)
+		return;
+
 	local_irq_enable();
 
 #ifdef CONFIG_SH_KGDB
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index cf2c2ee..ae8c321 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -13,7 +13,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index ae957a9..4d03098 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -1,37 +1,20 @@
-/* $Id: init.c,v 1.19 2004/02/21 04:42:16 kkojima Exp $
- *
- *  linux/arch/sh/mm/init.c
+/*
+ * linux/arch/sh/mm/init.c
  *
  *  Copyright (C) 1999  Niibe Yutaka
- *  Copyright (C) 2002, 2004  Paul Mundt
+ *  Copyright (C) 2002 - 2007  Paul Mundt
  *
  *  Based on linux/arch/i386/mm/init.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/swap.h>
-#include <linux/smp.h>
 #include <linux/init.h>
-#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>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
+#include <linux/percpu.h>
+#include <linux/io.h>
 #include <asm/mmu_context.h>
-#include <asm/io.h>
 #include <asm/tlb.h>
 #include <asm/cacheflush.h>
 #include <asm/cache.h>
@@ -39,37 +22,51 @@ #include <asm/cache.h>
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
-#ifdef CONFIG_MMU
-/* It'd be good if these lines were in the standard header file. */
-#define START_PFN	(NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
-#define MAX_LOW_PFN	(NODE_DATA(0)->bdata->node_low_pfn)
-#endif
-
 void (*copy_page)(void *from, void *to);
 void (*clear_page)(void *to);
 
 void show_mem(void)
 {
-	int i, total = 0, reserved = 0;
-	int shared = 0, cached = 0;
+	int total = 0, reserved = 0, free = 0;
+	int shared = 0, cached = 0, slab = 0;
+	pg_data_t *pgdat;
 
 	printk("Mem-info:\n");
 	show_free_areas();
-	printk("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
-	i = max_mapnr;
-	while (i-- > 0) {
-		total++;
-		if (PageReserved(mem_map+i))
-			reserved++;
-		else if (PageSwapCache(mem_map+i))
-			cached++;
-		else if (page_count(mem_map+i))
-			shared += page_count(mem_map+i) - 1;
+
+	for_each_online_pgdat(pgdat) {
+		struct page *page, *end;
+		unsigned long flags;
+
+		pgdat_resize_lock(pgdat, &flags);
+		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);
+
+		pgdat_resize_unlock(pgdat, &flags);
 	}
-	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("Free swap:       %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+	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);
 }
 
 #ifdef CONFIG_MMU
@@ -147,52 +144,38 @@ extern char __init_begin, __init_end;
  */
 void __init paging_init(void)
 {
-	unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+	int nid;
 
-	/*
-	 * Setup some defaults for the zone sizes.. these should be safe
-	 * regardless of distcontiguous memory or MMU settings.
-	 */
-	zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
-	zones_size[ZONE_HIGHMEM] = 0 >> PAGE_SHIFT;
-#endif
-
-#ifdef CONFIG_MMU
-	/*
-	 * If we have an MMU, and want to be using it .. we need to adjust
-	 * the zone sizes accordingly, in addition to turning it on.
-	 */
-	{
-		/* We don't need to map the kernel through the TLB, as
-		 * it is permanatly mapped using P1. So clear the
-		 * entire pgd. */
-		memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
-
-		/* Turn on the MMU */
-		enable_mmu();
-		zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN;
-	}
+	/* We don't need to map the kernel through the TLB, as
+	 * it is permanatly mapped using P1. So clear the
+	 * entire pgd. */
+	memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
 
 	/* Set an initial value for the MMU.TTB so we don't have to
 	 * check for a null value. */
 	set_TTB(swapper_pg_dir);
 
-#elif defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
-	/*
-	 * If we don't have CONFIG_MMU set and the processor in question
-	 * still has an MMU, care needs to be taken to make sure it doesn't
-	 * stay on.. Since the boot loader could have potentially already
-	 * turned it on, and we clearly don't want it, we simply turn it off.
-	 *
-	 * We don't need to do anything special for the zone sizes, since the
-	 * default values that were already configured up above should be
-	 * satisfactory.
-	 */
-	disable_mmu();
-#endif
-	NODE_DATA(0)->node_mem_map = NULL;
-	free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+	for_each_online_node(nid) {
+		pg_data_t *pgdat = NODE_DATA(nid);
+		unsigned long max_zone_pfns[MAX_NR_ZONES];
+		unsigned long low, start_pfn;
+
+		memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+		start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT;
+		low = pgdat->bdata->node_low_pfn;
+
+		max_zone_pfns[ZONE_NORMAL] = low;
+		add_active_range(nid, start_pfn, low);
+
+		printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
+		       nid, start_pfn, low);
+
+		free_area_init_nodes(max_zone_pfns);
+
+		printk("Node %u: mem_map starts at %p\n",
+		       pgdat->node_id, pgdat->node_mem_map);
+	}
 }
 
 static struct kcore_list kcore_mem, kcore_vmalloc;
@@ -200,18 +183,33 @@ static struct kcore_list kcore_mem, kcor
 void __init mem_init(void)
 {
 	int codesize, reservedpages, datasize, initsize;
-	int tmp;
-	extern unsigned long memory_start;
+	int nid;
 
-#ifdef CONFIG_MMU
-	high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
-#else
-	extern unsigned long memory_end;
+	reservedpages = 0;
 
-	high_memory = (void *)(memory_end & PAGE_MASK);
-#endif
+	for_each_online_node(nid) {
+		pg_data_t *pgdat = NODE_DATA(nid);
+		unsigned long node_pages = 0;
+		void *node_high_memory;
+		int i;
+
+		num_physpages += pgdat->node_present_pages;
+
+		if (pgdat->node_spanned_pages)
+			node_pages = free_all_bootmem_node(pgdat);
+
+		totalram_pages += node_pages;
 
-	max_mapnr = num_physpages = MAP_NR(high_memory) - MAP_NR(memory_start);
+		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;
+	}
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
@@ -229,16 +227,6 @@ #else
 	clear_page = clear_page_nommu;
 #endif
 
-	/* this will put all low memory onto the freelists */
-	totalram_pages += free_all_bootmem_node(NODE_DATA(0));
-	reservedpages = 0;
-	for (tmp = 0; tmp < num_physpages; tmp++)
-		/*
-		 * Only count reserved RAM pages
-		 */
-		if (PageReserved(mem_map+tmp))
-			reservedpages++;
-
 	codesize =  (unsigned long) &_etext - (unsigned long) &_text;
 	datasize =  (unsigned long) &_edata - (unsigned long) &_etext;
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
@@ -250,7 +238,7 @@ #endif
 	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),
+		totalram_pages << (PAGE_SHIFT-10),
 		codesize >> 10,
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
@@ -289,4 +277,3 @@ void free_initrd_mem(unsigned long start
 	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 }
 #endif
-
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index d0d45e2..02aae06 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -311,9 +311,9 @@ static int __init pmb_init(void)
 
 	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);
+	pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
+				      SLAB_PANIC, pmb_cache_ctor,
+				      pmb_cache_dtor);
 
 	jump_to_P2();
 
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index 4fe0f94..554f801 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -9,6 +9,7 @@ SE			SH_SOLUTION_ENGINE
 7751SE			SH_7751_SOLUTION_ENGINE		
 7300SE			SH_7300_SOLUTION_ENGINE
 7343SE			SH_7343_SOLUTION_ENGINE
+7780SE			SH_7780_SOLUTION_ENGINE
 73180SE			SH_73180_SOLUTION_ENGINE
 7751SYSTEMH		SH_7751_SYSTEMH
 HP6XX			SH_HP6XX
@@ -26,6 +27,7 @@ SH03			SH_SH03
 LANDISK			SH_LANDISK
 R7780RP			SH_R7780RP
 R7780MP			SH_R7780MP
+R7785RP			SH_R7785RP
 TITAN			SH_TITAN
 SHMIN			SH_SHMIN
 7710VOIPGW		SH_7710VOIPGW
diff --git a/arch/sh64/kernel/early_printk.c b/arch/sh64/kernel/early_printk.c
index 8c8a76e..4f91311 100644
--- a/arch/sh64/kernel/early_printk.c
+++ b/arch/sh64/kernel/early_printk.c
@@ -79,7 +79,7 @@ static struct console sh_console = {
 	.name		= "scifcon",
 	.write		= sh_console_write,
 	.setup		= sh_console_setup,
-	.flags		= CON_PRINTBUFFER,
+	.flags		= CON_PRINTBUFFER | CON_BOOT,
 	.index		= -1,
 };
 
@@ -97,9 +97,3 @@ void __init enable_early_printk(void)
 
 	register_console(&sh_console);
 }
-
-void disable_early_printk(void)
-{
-	unregister_console(&sh_console);
-}
-
diff --git a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c
index e7e07f8..f68b4f6 100644
--- a/arch/sh64/kernel/irq.c
+++ b/arch/sh64/kernel/irq.c
@@ -26,7 +26,6 @@ #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
index 9dae689..49862e1 100644
--- a/arch/sh64/kernel/pci_sh5.c
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/rwsem.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/errno.h>
diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
index 7aa4b4f..461ea3d 100644
--- a/arch/sh64/kernel/sh_ksyms.c
+++ b/arch/sh64/kernel/sh_ksyms.c
@@ -17,7 +17,6 @@ #include <linux/elfcore.h>
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/screen_info.h>
 
 #include <asm/semaphore.h>
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
index 1666d3e..b76bdfa 100644
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -16,7 +16,6 @@ #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
index ad0fa4e..19126da 100644
--- a/arch/sh64/kernel/sys_sh64.c
+++ b/arch/sh64/kernel/sys_sh64.c
@@ -20,7 +20,6 @@ #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff --git a/arch/sh64/kernel/traps.c b/arch/sh64/kernel/traps.c
index c346d7e..9d0d58f 100644
--- a/arch/sh64/kernel/traps.c
+++ b/arch/sh64/kernel/traps.c
@@ -23,7 +23,6 @@ #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>
diff --git a/arch/sh64/kernel/unwind.c b/arch/sh64/kernel/unwind.c
index f934f97..1214c78 100644
--- a/arch/sh64/kernel/unwind.c
+++ b/arch/sh64/kernel/unwind.c
@@ -46,15 +46,15 @@ static int lookup_prev_stack_frame(unsig
 		      struct pt_regs *regs)
 {
 	const char *sym;
-	char *modname, namebuf[128];
-	unsigned long offset, size;
+	char namebuf[128];
+	unsigned long offset;
 	unsigned long prologue = 0;
 	unsigned long fp_displacement = 0;
 	unsigned long fp_prev = 0;
 	unsigned long offset_r14 = 0, offset_r18 = 0;
 	int i, found_prologue_end = 0;
 
-	sym = kallsyms_lookup(pc, &size, &offset, &modname, namebuf);
+	sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf);
 	if (!sym)
 		return -EINVAL;
 
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index a59c5e9..4f9616f 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -85,7 +85,7 @@ #endif
   . = ALIGN(PAGE_SIZE);
   .data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) }
 
-  . = ALIGN(L1_CACHE_BYTES);
+  . = ALIGN(PAGE_SIZE);
   __per_cpu_start = .;
   .data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) }
   __per_cpu_end = . ;
diff --git a/arch/sh64/mach-cayman/iomap.c b/arch/sh64/mach-cayman/iomap.c
index 2d06e9a..a5c645f 100644
--- a/arch/sh64/mach-cayman/iomap.c
+++ b/arch/sh64/mach-cayman/iomap.c
@@ -9,7 +9,6 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
-#include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/cayman.h>
 
diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
index 4f72ab3..4dd8ee8 100644
--- a/arch/sh64/mm/fault.c
+++ b/arch/sh64/mm/fault.c
@@ -22,7 +22,6 @@ #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 <asm/system.h>
diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c
index 4b455f6..fa66daa 100644
--- a/arch/sh64/mm/hugetlbpage.c
+++ b/arch/sh64/mm/hugetlbpage.c
@@ -13,7 +13,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 
diff --git a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c
index c861595..d4c5334 100644
--- a/arch/sh64/mm/tlbmiss.c
+++ b/arch/sh64/mm/tlbmiss.c
@@ -32,7 +32,6 @@ #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 <asm/system.h>
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index ba58c3a..7bb86b9 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -25,7 +25,7 @@ #include <asm/bpp.h>
 struct linux_ebus *ebus_chain = NULL;
 
 /* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
+extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
 
 /*
  * IRQ Blacklist
@@ -69,7 +69,7 @@ static inline unsigned long ebus_alloc(s
 
 /*
  */
-int __init ebus_blacklist_irq(char *name)
+int __init ebus_blacklist_irq(const char *name)
 {
 	struct ebus_device_irq *dp;
 
@@ -86,8 +86,8 @@ int __init ebus_blacklist_irq(char *name
 void __init fill_ebus_child(struct device_node *dp,
 			    struct linux_ebus_child *dev)
 {
-	int *regs;
-	int *irqs;
+	const int *regs;
+	const int *irqs;
 	int i, len;
 
 	dev->prom_node = dp;
@@ -146,9 +146,9 @@ void __init fill_ebus_child(struct devic
 
 void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
-	struct linux_prom_registers *regs;
+	const struct linux_prom_registers *regs;
 	struct linux_ebus_child *child;
-	int *irqs;
+	const int *irqs;
 	int i, n, len;
 	unsigned long baseaddr;
 
@@ -269,7 +269,7 @@ void __init fill_ebus_device(struct devi
 
 void __init ebus_init(void)
 {
-	struct linux_prom_pci_registers *regs;
+	const struct linux_prom_pci_registers *regs;
 	struct linux_pbm_info *pbm;
 	struct linux_ebus_device *dev;
 	struct linux_ebus *ebus;
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 9a219e8..97da13c 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -19,7 +19,7 @@ #include <asm/contregs.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
 #include <asm/page.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/winmacro.h>
 #include <asm/thread_info.h>	/* TI_UWINMASK */
 #include <asm/errno.h>
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 5b4841d..bdbefa8 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -24,7 +24,6 @@ #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/threads.h>
 #include <linux/spinlock.h>
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 48c24f7..fd7f8cb 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -210,7 +210,7 @@ struct of_bus {
 				       int *addrc, int *sizec);
 	int		(*map)(u32 *addr, const u32 *range,
 			       int na, int ns, int pna);
-	unsigned int	(*get_flags)(u32 *addr);
+	unsigned int	(*get_flags)(const u32 *addr);
 };
 
 /*
@@ -270,7 +270,7 @@ static int of_bus_default_map(u32 *addr,
 	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;
 }
@@ -334,7 +334,7 @@ static int of_bus_pci_map(u32 *addr, con
 	return 0;
 }
 
-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];
@@ -375,7 +375,7 @@ static int of_bus_sbus_map(u32 *addr, co
 	return of_bus_default_map(addr, range, na, ns, pna);
 }
 
-static unsigned int of_bus_sbus_get_flags(u32 *addr)
+static unsigned int of_bus_sbus_get_flags(const u32 *addr)
 {
 	return IORESOURCE_MEM;
 }
@@ -432,7 +432,7 @@ static int __init build_one_resource(str
 				     u32 *addr,
 				     int na, int ns, int pna)
 {
-	u32 *ranges;
+	const u32 *ranges;
 	unsigned int rlen;
 	int rone;
 
@@ -470,7 +470,7 @@ static void __init build_device_resource
 	struct of_bus *bus;
 	int na, ns;
 	int index, num_reg;
-	void *preg;
+	const void *preg;
 
 	if (!parent)
 		return;
@@ -492,7 +492,7 @@ static void __init build_device_resource
 	for (index = 0; index < num_reg; index++) {
 		struct resource *r = &op->resource[index];
 		u32 addr[OF_MAX_ADDR_CELLS];
-		u32 *reg = (preg + (index * ((na + ns) * 4)));
+		const u32 *reg = (preg + (index * ((na + ns) * 4)));
 		struct device_node *dp = op->node;
 		struct device_node *pp = p_op->node;
 		struct of_bus *pbus, *dbus;
@@ -559,7 +559,7 @@ static struct of_device * __init scan_on
 						 struct device *parent)
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
-	struct linux_prom_irqs *intr;
+	const struct linux_prom_irqs *intr;
 	int len, i;
 
 	if (!op)
@@ -579,7 +579,8 @@ static struct of_device * __init scan_on
 		for (i = 0; i < op->num_irqs; i++)
 			op->irqs[i] = intr[i].pri;
 	} else {
-		unsigned int *irq = of_get_property(dp, "interrupts", &len);
+		const unsigned int *irq =
+			of_get_property(dp, "interrupts", &len);
 
 		if (irq) {
 			op->num_irqs = len / sizeof(unsigned int);
@@ -594,7 +595,7 @@ static struct of_device * __init scan_on
 			0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
 		};
 		struct device_node *io_unit, *sbi = dp->parent;
-		struct linux_prom_registers *regs;
+		const struct linux_prom_registers *regs;
 		int board, slot;
 
 		while (sbi) {
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 1c927c5..5ca7e8f 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -37,8 +37,6 @@ #include <asm/uaccess.h>
 #include <asm/irq_regs.h>
 
 
-unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
-
 /*
  * I studied different documents and many live PROMs both from 2.30
  * family and 3.xx versions. I came to the amazing conclusion: there is
@@ -681,7 +679,7 @@ void __devinit pcibios_fixup_bus(struct 
  * pcic_pin_to_irq() is exported to ebus.c.
  */
 unsigned int
-pcic_pin_to_irq(unsigned int pin, char *name)
+pcic_pin_to_irq(unsigned int pin, const char *name)
 {
 	struct linux_pcic *pcic = &pcic0;
 	unsigned int irq;
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index fc874e6..2940d2c 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -23,7 +23,6 @@ #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 2cc302b..eed140b 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -32,12 +32,13 @@ static struct device_node *allnodes;
  */
 static DEFINE_RWLOCK(devtree_lock);
 
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+			    const char *compat)
 {
 	const char* cp;
 	int cplen, l;
 
-	cp = (char *) of_get_property(device, "compatible", &cplen);
+	cp = of_get_property(device, "compatible", &cplen);
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
@@ -150,13 +151,14 @@ struct device_node *of_find_compatible_n
 }
 EXPORT_SYMBOL(of_find_compatible_node);
 
-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;
 
 	for (pp = np->properties; pp != 0; pp = pp->next) {
-		if (strcmp(pp->name, name) == 0) {
+		if (strcasecmp(pp->name, name) == 0) {
 			if (lenp != 0)
 				*lenp = pp->length;
 			break;
@@ -170,7 +172,8 @@ EXPORT_SYMBOL(of_find_property);
  * Find a property with a given name for a given node
  * and return the value.
  */
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
+const void *of_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;
@@ -192,7 +195,7 @@ EXPORT_SYMBOL(of_getintprop_default);
 
 int of_n_addr_cells(struct device_node *np)
 {
-	int* ip;
+	const int* ip;
 	do {
 		if (np->parent)
 			np = np->parent;
@@ -207,7 +210,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
 
 int of_n_size_cells(struct device_node *np)
 {
-	int* ip;
+	const int* ip;
 	do {
 		if (np->parent)
 			np = np->parent;
@@ -239,7 +242,7 @@ int of_set_property(struct device_node *
 	while (*prevp) {
 		struct property *prop = *prevp;
 
-		if (!strcmp(prop->name, name)) {
+		if (!strcasecmp(prop->name, name)) {
 			void *old_val = prop->value;
 			int ret;
 
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index eccd8e8..64c0ed9 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -31,6 +31,7 @@ #include <linux/console.h>
 #include <linux/spinlock.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
+#include <linux/kdebug.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -40,7 +41,6 @@ #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/traps.h>
 #include <asm/vaddrs.h>
-#include <asm/kdebug.h>
 #include <asm/mbus.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index c9301b9..9994cac 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -17,7 +17,6 @@ #include <linux/unistd.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/binfmts.h>	/* do_coredum */
 #include <linux/bitops.h>
 
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 6b5f26b..4d9ad59 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -11,7 +11,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 0e27e22..116d6a2 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -17,7 +17,6 @@ #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
 
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index c69de5d..098c94f 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -12,7 +12,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index e2d9c01..63ed19b 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -9,7 +9,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
@@ -405,7 +404,7 @@ void __init smp4m_blackbox_current(unsig
 	
 	addr[0] = 0x81580000 | rd;		/* rd %tbr, reg */
 	addr[2] = 0x8130200a | rd | rs1;    	/* srl reg, 0xa, reg */
-	addr[4] = 0x8008200c | rd | rs1;	/* and reg, 3, reg */
+	addr[4] = 0x8008200c | rd | rs1;	/* and reg, 0xc, reg */
 }
 
 void __init sun4m_init_smp(void)
diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c
index 32e8274..e613cc6 100644
--- a/arch/sparc/kernel/sunos_ioctl.c
+++ b/arch/sparc/kernel/sunos_ioctl.c
@@ -21,7 +21,6 @@ #include <linux/if_arp.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
 
diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
index 01b07bb..2226a59 100644
--- a/arch/sparc/kernel/sys_solaris.c
+++ b/arch/sparc/kernel/sys_solaris.c
@@ -12,7 +12,6 @@ #include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/module.h>
 
 asmlinkage int
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 9bb1240..f1401b5 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -301,7 +301,7 @@ #ifndef CONFIG_SUN4
 static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	char *model = of_get_property(dp, "model", NULL);
+	const char *model = of_get_property(dp, "model", NULL);
 
 	if (!model)
 		return -ENODEV;
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 527687a..dc9ffea 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -15,6 +15,7 @@ #include <linux/kallsyms.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/kdebug.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -22,7 +23,6 @@ #include <asm/ptrace.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/kdebug.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
 
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index e5c24e0..f0bb6e6 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -65,7 +65,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
   __initramfs_end = .;
 #endif
 
-  . = ALIGN(32);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 2e168d1..764b3eb 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -9,7 +9,6 @@
  * fragmentation.
  */
 
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 9eeed33..c348336 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -18,9 +18,9 @@ #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/kdebug.h>
 
 #include <asm/system.h>
 #include <asm/page.h>
@@ -30,7 +30,6 @@ #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/smp.h>
 #include <asm/traps.h>
-#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 
 extern int prom_node_root;
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 0df7121..e5eaa80 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -18,13 +18,13 @@ #include <linux/spinlock.h>
 #include <linux/bootmem.h>
 #include <linux/fs.h>
 #include <linux/seq_file.h>
+#include <linux/kdebug.h>
 
 #include <asm/bitext.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/kdebug.h>
 #include <asm/vaddrs.h>
 #include <asm/traps.h>
 #include <asm/smp.h>
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 1a6348b..ad8d6b2 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -19,6 +19,14 @@ config SPARC64
 	  SPARC64 ports; its web page is available at
 	  <http://www.ultralinux.org/>.
 
+config GENERIC_TIME
+	bool
+	default y
+
+config GENERIC_CLOCKEVENTS
+	bool
+	default y
+
 config 64BIT
 	def_bool y
 
@@ -26,15 +34,15 @@ config MMU
 	bool
 	default y
 
-config STACKTRACE_SUPPORT
+config QUICKLIST
 	bool
 	default y
 
-config LOCKDEP_SUPPORT
+config STACKTRACE_SUPPORT
 	bool
 	default y
 
-config TIME_INTERPOLATION
+config LOCKDEP_SUPPORT
 	bool
 	default y
 
@@ -113,6 +121,8 @@ config GENERIC_HARDIRQS
 
 menu "General machine setup"
 
+source "kernel/time/Kconfig"
+
 config SMP
 	bool "Symmetric multi-processing support"
 	---help---
@@ -214,6 +224,7 @@ config ARCH_SPARSEMEM_ENABLE
 
 config ARCH_SPARSEMEM_DEFAULT
 	def_bool y
+	select SPARSEMEM_STATIC
 
 config LARGE_ALLOCS
 	def_bool y
@@ -299,6 +310,7 @@ config SUN_IO
 
 config PCI
 	bool "PCI support"
+	select ARCH_SUPPORTS_MSI
 	help
 	  Find out whether you have a PCI motherboard. PCI is the name of a
 	  bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 120c9c3..37c2d36 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,15 +1,16 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc4
-# Sat Mar 17 14:18:44 2007
+# Linux kernel version: 2.6.21
+# Sun May  6 22:46:54 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_64BIT=y
 CONFIG_MMU=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_TIME_INTERPOLATION=y
 CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -108,6 +109,9 @@ CONFIG_GENERIC_HARDIRQS=y
 #
 # General machine setup
 #
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 # CONFIG_SMP is not set
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=m
@@ -140,8 +144,7 @@ # 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_SPARSEMEM_STATIC=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
@@ -151,6 +154,7 @@ CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
 # CONFIG_PCI_DEBUG is not set
 CONFIG_SUN_OPENPROMFS=m
@@ -178,7 +182,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -219,6 +222,7 @@ CONFIG_IPV6=m
 CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -292,6 +296,14 @@ CONFIG_NET_TCPPROBE=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 
 #
@@ -312,10 +324,6 @@ #
 # Connector - unified userspace <-> kernelspace linker
 #
 CONFIG_CONNECTOR=m
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
 
 #
@@ -383,7 +391,6 @@ # 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=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 CONFIG_BLK_DEV_ALI15X3=y
@@ -413,7 +420,6 @@ # CONFIG_BLK_DEV_TC86C001 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
 
 #
@@ -443,6 +449,7 @@ CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -485,6 +492,7 @@ # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SUNESP is not set
 # CONFIG_SCSI_SRP is not set
 
@@ -628,9 +636,10 @@ #
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Wan interfaces
@@ -695,6 +704,12 @@ # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 CONFIG_MOUSE_SERIAL=y
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
@@ -702,6 +717,7 @@ # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_SPARCSPKR=y
 # CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Hardware I/O ports
@@ -763,11 +779,8 @@ #
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
 CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
 # CONFIG_I2C_CHARDEV is not set
 
 #
@@ -791,17 +804,17 @@ # 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_PASEMI is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC 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_TINY_USB 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
@@ -912,7 +925,7 @@ CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
 
 #
-# Frambuffer hardware drivers
+# Frame buffer hardware drivers
 #
 # CONFIG_FB_CIRRUS is not set
 # CONFIG_FB_PM2 is not set
@@ -937,6 +950,8 @@ # 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_XVR500 is not set
+# CONFIG_FB_XVR2500 is not set
 # CONFIG_FB_PCI is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -1094,6 +1109,14 @@ CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
 # USB support
 #
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1106,6 +1129,7 @@ #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
 
@@ -1156,10 +1180,6 @@ # CONFIG_USB_LIBUSUAL is not set
 #
 # USB Input Devices
 #
-CONFIG_USB_HID=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
@@ -1524,6 +1544,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_LRW=m
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_FCRYPT=m
 CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index eff0c01..6bf6fb6 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -17,7 +17,7 @@ obj-y		:= process.o setup.o cpu.o idprom
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-$(CONFIG_PCI)	 += ebus.o isa.o pci_common.o pci_iommu.o \
 			    pci_psycho.o pci_sabre.o pci_schizo.o \
-			    pci_sun4v.o pci_sun4v_asm.o
+			    pci_sun4v.o pci_sun4v_asm.o pci_fire.o
 obj-$(CONFIG_SMP)	 += smp.o trampoline.o
 obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
 obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index e724c54..8230099 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -32,7 +32,7 @@ static void central_probe_failure(int li
 static void central_ranges_init(struct linux_central *central)
 {
 	struct device_node *dp = central->prom_node;
-	void *pval;
+	const void *pval;
 	int len;
 	
 	central->num_central_ranges = 0;
@@ -47,7 +47,7 @@ static void central_ranges_init(struct l
 static void fhc_ranges_init(struct linux_fhc *fhc)
 {
 	struct device_node *dp = fhc->prom_node;
-	void *pval;
+	const void *pval;
 	int len;
 	
 	fhc->num_fhc_ranges = 0;
@@ -98,7 +98,7 @@ void apply_central_ranges(struct linux_c
 			    central->num_central_ranges);
 }
 
-void * __init central_alloc_bootmem(unsigned long size)
+static void * __init central_alloc_bootmem(unsigned long size)
 {
 	void *ret;
 
@@ -116,10 +116,10 @@ static unsigned long prom_reg_to_paddr(s
 	return ret | (unsigned long) r->phys_addr;
 }
 
-static void probe_other_fhcs(void)
+static void __init probe_other_fhcs(void)
 {
 	struct device_node *dp;
-	struct linux_prom64_registers *fpregs;
+	const struct linux_prom64_registers *fpregs;
 
 	for_each_node_by_name(dp, "fhc") {
 		struct linux_fhc *fhc;
@@ -190,7 +190,8 @@ static void probe_clock_board(struct lin
 			      struct device_node *fp)
 {
 	struct device_node *dp;
-	struct linux_prom_registers cregs[3], *pr;
+	struct linux_prom_registers cregs[3];
+	const struct linux_prom_registers *pr;
 	int nslots, tmp, nregs;
 
 	dp = fp->child;
@@ -297,9 +298,10 @@ static void init_all_fhc_hw(void)
 
 }
 
-void central_probe(void)
+void __init central_probe(void)
 {
-	struct linux_prom_registers fpregs[6], *pr;
+	struct linux_prom_registers fpregs[6];
+	const struct linux_prom_registers *pr;
 	struct linux_fhc *fhc;
 	struct device_node *dp, *fp;
 	int err;
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 9699abe..777d345 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -343,8 +343,8 @@ static int init_one_mctrl(struct device_
 {
 	struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
 	int portid = of_getintprop_default(dp, "portid", -1);
-	struct linux_prom64_registers *regs;
-	void *pval;
+	const struct linux_prom64_registers *regs;
+	const void *pval;
 	int len;
 
 	if (!mp)
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 35bf895..0ace17b 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -285,7 +285,7 @@ static void __init fill_ebus_child(struc
 				   int non_standard_regs)
 {
 	struct of_device *op;
-	int *regs;
+	const int *regs;
 	int i, len;
 
 	dev->prom_node = dp;
@@ -438,11 +438,9 @@ static struct pci_dev *find_next_ebus(st
 
 void __init ebus_init(void)
 {
-	struct pci_pbm_info *pbm;
 	struct linux_ebus_device *dev;
 	struct linux_ebus *ebus;
 	struct pci_dev *pdev;
-	struct pcidev_cookie *cookie;
 	struct device_node *dp;
 	int is_rio;
 	int num_ebus = 0;
@@ -453,8 +451,7 @@ void __init ebus_init(void)
 		return;
 	}
 
-	cookie = pdev->sysdata;
-	dp = cookie->prom_node;
+	dp = pci_device_to_OF_node(pdev);
 
 	ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
 	ebus->next = NULL;
@@ -480,8 +477,7 @@ void __init ebus_init(void)
 				break;
 			}
 			ebus->is_rio = is_rio;
-			cookie = pdev->sysdata;
-			dp = cookie->prom_node;
+			dp = pci_device_to_OF_node(pdev);
 			continue;
 		}
 		printk("ebus%d:", num_ebus);
@@ -489,7 +485,6 @@ void __init ebus_init(void)
 		ebus->index = num_ebus;
 		ebus->prom_node = dp;
 		ebus->self = pdev;
-		ebus->parent = pbm = cookie->pbm;
 
 		ebus->ofdev.node = dp;
 		ebus->ofdev.dev.parent = &pdev->dev;
@@ -531,8 +526,7 @@ void __init ebus_init(void)
 		if (!pdev)
 			break;
 
-		cookie = pdev->sysdata;
-		dp = cookie->prom_node;
+		dp = pci_device_to_OF_node(pdev);
 
 		ebus->next = ebus_alloc(sizeof(struct linux_ebus));
 		ebus = ebus->next;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c443db1..3edc18e 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -279,7 +279,7 @@ static void sun4u_irq_enable(unsigned in
 	struct irq_handler_data *data = get_irq_chip_data(virt_irq);
 
 	if (likely(data)) {
-		unsigned long cpuid, imap;
+		unsigned long cpuid, imap, val;
 		unsigned int tid;
 
 		cpuid = irq_choose_cpu(virt_irq);
@@ -287,7 +287,11 @@ static void sun4u_irq_enable(unsigned in
 
 		tid = sun4u_compute_tid(imap, cpuid);
 
-		upa_writel(tid | IMAP_VALID, imap);
+		val = upa_readq(imap);
+		val &= ~(IMAP_TID_UPA | IMAP_TID_JBUS |
+			 IMAP_AID_SAFARI | IMAP_NID_SAFARI);
+		val |= tid | IMAP_VALID;
+		upa_writeq(val, imap);
 	}
 }
 
@@ -297,10 +301,10 @@ static void sun4u_irq_disable(unsigned i
 
 	if (likely(data)) {
 		unsigned long imap = data->imap;
-		u32 tmp = upa_readl(imap);
+		u32 tmp = upa_readq(imap);
 
 		tmp &= ~IMAP_VALID;
-		upa_writel(tmp, imap);
+		upa_writeq(tmp, imap);
 	}
 }
 
@@ -309,7 +313,7 @@ static void sun4u_irq_end(unsigned int v
 	struct irq_handler_data *data = get_irq_chip_data(virt_irq);
 
 	if (likely(data))
-		upa_writel(ICLR_IDLE, data->iclr);
+		upa_writeq(ICLR_IDLE, data->iclr);
 }
 
 static void sun4v_irq_enable(unsigned int virt_irq)
@@ -465,7 +469,7 @@ unsigned int build_irq(int inofixup, uns
 
 	BUG_ON(tlb_type == hypervisor);
 
-	ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
+	ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
 	bucket = &ivector_table[ino];
 	if (!bucket->virt_irq) {
 		bucket->virt_irq = virt_irq_alloc(__irq(bucket));
@@ -589,32 +593,6 @@ void ack_bad_irq(unsigned int virt_irq)
 	       ino, virt_irq);
 }
 
-#ifndef CONFIG_SMP
-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;
-		clr_mask = tick_mask;
-	}
-	clear_softint(clr_mask);
-
-	old_regs = set_irq_regs(regs);
-	irq_enter();
-
-	kstat_this_cpu.irqs[0]++;
-	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;
@@ -653,7 +631,7 @@ static u64 prom_limit0, prom_limit1;
 static void map_prom_timers(void)
 {
 	struct device_node *dp;
-	unsigned int *addr;
+	const unsigned int *addr;
 
 	/* PROM timer node hangs out in the top level of device siblings... */
 	dp = of_find_node_by_path("/");
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 98721a8..6a6882e 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -24,27 +24,9 @@ static void __init report_dev(struct spa
 
 static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev)
 {
-	struct linux_prom_registers *pregs;
-	unsigned long base, len;
-	int prop_len;
-
-	pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
-	if (!pregs)
-		return;
-
-	/* Only the first one is interesting. */
-	len = pregs[0].reg_size;
-	base = (((unsigned long)pregs[0].which_io << 32) |
-		(unsigned long)pregs[0].phys_addr);
-	base += isa_dev->bus->parent->io_space.start;
-
-	isa_dev->resource.start = base;
-	isa_dev->resource.end   = (base + len - 1UL);
-	isa_dev->resource.flags = IORESOURCE_IO;
-	isa_dev->resource.name  = isa_dev->prom_node->name;
+	struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
 
-	request_resource(&isa_dev->bus->parent->io_space,
-			 &isa_dev->resource);
+	memcpy(&isa_dev->resource, &op->resource[0], sizeof(struct resource));
 }
 
 static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev)
@@ -158,19 +140,10 @@ void __init isa_init(void)
 
 	pdev = NULL;
 	while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) {
-		struct pcidev_cookie *pdev_cookie;
-		struct pci_pbm_info *pbm;
 		struct sparc_isa_bridge *isa_br;
 		struct device_node *dp;
 
-		pdev_cookie = pdev->sysdata;
-		if (!pdev_cookie) {
-			printk("ISA: Warning, ISA bridge ignored due to "
-			       "lack of OBP data.\n");
-			continue;
-		}
-		pbm = pdev_cookie->pbm;
-		dp = pdev_cookie->prom_node;
+		dp = pci_device_to_OF_node(pdev);
 
 		isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
 		if (!isa_br) {
@@ -195,10 +168,9 @@ void __init isa_init(void)
 		isa_br->next = isa_chain;
 		isa_chain = isa_br;
 
-		isa_br->parent = pbm;
 		isa_br->self = pdev;
 		isa_br->index = index++;
-		isa_br->prom_node = pdev_cookie->prom_node;
+		isa_br->prom_node = dp;
 
 		printk("isa%d:", isa_br->index);
 
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index ae221f0..a44fe47 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -6,7 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/kprobes.h>
 #include <linux/module.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/signal.h>
 #include <asm/cacheflush.h>
 #include <asm/uaccess.h>
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index fb9bf1e..9ac9a30 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -245,7 +245,7 @@ struct of_bus {
 				       int *addrc, int *sizec);
 	int		(*map)(u32 *addr, const u32 *range,
 			       int na, int ns, int pna);
-	unsigned int	(*get_flags)(u32 *addr);
+	unsigned int	(*get_flags)(const u32 *addr);
 };
 
 /*
@@ -305,7 +305,7 @@ static int of_bus_default_map(u32 *addr,
 	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;
 }
@@ -317,6 +317,11 @@ static unsigned int of_bus_default_get_f
 static int of_bus_pci_match(struct device_node *np)
 {
 	if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+		const char *model = of_get_property(np, "model", NULL);
+
+		if (model && !strcmp(model, "SUNW,simba"))
+			return 0;
+
 		/* Do not do PCI specific frobbing if the
 		 * PCI bridge lacks a ranges property.  We
 		 * want to pass it through up to the next
@@ -332,6 +337,21 @@ static int of_bus_pci_match(struct devic
 	return 0;
 }
 
+static int of_bus_simba_match(struct device_node *np)
+{
+	const char *model = of_get_property(np, "model", NULL);
+
+	if (model && !strcmp(model, "SUNW,simba"))
+		return 1;
+	return 0;
+}
+
+static int of_bus_simba_map(u32 *addr, const u32 *range,
+			    int na, int ns, int pna)
+{
+	return 0;
+}
+
 static void of_bus_pci_count_cells(struct device_node *np,
 				   int *addrc, int *sizec)
 {
@@ -369,7 +389,7 @@ static int of_bus_pci_map(u32 *addr, con
 	return 0;
 }
 
-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];
@@ -436,6 +456,15 @@ static struct of_bus of_busses[] = {
 		.map = of_bus_pci_map,
 		.get_flags = of_bus_pci_get_flags,
 	},
+	/* SIMBA */
+	{
+		.name = "simba",
+		.addr_prop_name = "assigned-addresses",
+		.match = of_bus_simba_match,
+		.count_cells = of_bus_pci_count_cells,
+		.map = of_bus_simba_map,
+		.get_flags = of_bus_pci_get_flags,
+	},
 	/* SBUS */
 	{
 		.name = "sbus",
@@ -482,7 +511,7 @@ static int __init build_one_resource(str
 				     u32 *addr,
 				     int na, int ns, int pna)
 {
-	u32 *ranges;
+	const u32 *ranges;
 	unsigned int rlen;
 	int rone;
 
@@ -513,7 +542,7 @@ static int __init build_one_resource(str
 
 static int __init use_1to1_mapping(struct device_node *pp)
 {
-	char *model;
+	const char *model;
 
 	/* If this is on the PMU bus, don't try to translate it even
 	 * if a ranges property exists.
@@ -548,7 +577,7 @@ static void __init build_device_resource
 	struct of_bus *bus;
 	int na, ns;
 	int index, num_reg;
-	void *preg;
+	const void *preg;
 
 	if (!parent)
 		return;
@@ -578,7 +607,7 @@ static void __init build_device_resource
 	for (index = 0; index < num_reg; index++) {
 		struct resource *r = &op->resource[index];
 		u32 addr[OF_MAX_ADDR_CELLS];
-		u32 *reg = (preg + (index * ((na + ns) * 4)));
+		const u32 *reg = (preg + (index * ((na + ns) * 4)));
 		struct device_node *dp = op->node;
 		struct device_node *pp = p_op->node;
 		struct of_bus *pbus, *dbus;
@@ -643,14 +672,14 @@ static void __init build_device_resource
 
 static struct device_node * __init
 apply_interrupt_map(struct device_node *dp, struct device_node *pp,
-		    u32 *imap, int imlen, u32 *imask,
+		    const u32 *imap, int imlen, const u32 *imask,
 		    unsigned int *irq_p)
 {
 	struct device_node *cp;
 	unsigned int irq = *irq_p;
 	struct of_bus *bus;
 	phandle handle;
-	u32 *reg;
+	const u32 *reg;
 	int na, num_reg, i;
 
 	bus = of_match_bus(pp);
@@ -705,7 +734,7 @@ static unsigned int __init pci_irq_swizz
 					   struct device_node *pp,
 					   unsigned int irq)
 {
-	struct linux_prom_pci_registers *regs;
+	const struct linux_prom_pci_registers *regs;
 	unsigned int bus, devfn, slot, ret;
 
 	if (irq < 1 || irq > 4)
@@ -730,12 +759,6 @@ static unsigned int __init pci_irq_swizz
 		 * D: 2-bit slot number, derived from PCI device number as
 		 *    (dev - 1) for bus A, or (dev - 2) for bus B
 		 * L: 2-bit line number
-		 *
-		 * Actually, more "portable" way to calculate the funky
-		 * slot number is to subtract pbm->pci_first_slot from the
-		 * device number, and that's exactly what the pre-OF
-		 * sparc64 code did, but we're building this stuff generically
-		 * using the OBP tree, not in the PCI controller layer.
 		 */
 		if (bus & 0x80) {
 			/* PBM-A */
@@ -794,7 +817,7 @@ static unsigned int __init build_one_dev
 	pp = dp->parent;
 	ip = NULL;
 	while (pp) {
-		void *imap, *imsk;
+		const void *imap, *imsk;
 		int imlen;
 
 		imap = of_get_property(pp, "interrupt-map", &imlen);
@@ -859,7 +882,7 @@ static struct of_device * __init scan_on
 						 struct device *parent)
 {
 	struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
-	unsigned int *irq;
+	const unsigned int *irq;
 	int len, i;
 
 	if (!op)
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 1210988..966861b 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -1,9 +1,11 @@
-/* $Id: pci.c,v 1.39 2002/01/05 01:13:43 davem Exp $
- * pci.c: UltraSparc PCI controller support.
+/* pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
  * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be)
  * Copyright (C) 1999 Jakub Jelinek   (jj@ultra.linux.cz)
+ *
+ * OF tree based PCI bus probing taken from the PowerPC port
+ * with minor modifications, see there for credits.
  */
 
 #include <linux/module.h>
@@ -12,7 +14,6 @@ #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -24,6 +25,9 @@ #include <asm/irq.h>
 #include <asm/ebus.h>
 #include <asm/isa.h>
 #include <asm/prom.h>
+#include <asm/apb.h>
+
+#include "pci_impl.h"
 
 unsigned long pci_memspace_mask = 0xffffffffUL;
 
@@ -185,6 +189,7 @@ extern void schizo_init(struct device_no
 extern void schizo_plus_init(struct device_node *, const char *);
 extern void tomatillo_init(struct device_node *, const char *);
 extern void sun4v_pci_init(struct device_node *, const char *);
+extern void fire_pci_init(struct device_node *, const char *);
 
 static struct {
 	char *model_name;
@@ -202,6 +207,7 @@ static struct {
 	{ "SUNW,tomatillo", tomatillo_init },
 	{ "pci108e,a801", tomatillo_init },
 	{ "SUNW,sun4v-pci", sun4v_pci_init },
+	{ "pciex108e,80f0", fire_pci_init },
 };
 #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
 				  sizeof(pci_controller_table[0]))
@@ -277,10 +283,10 @@ int __init pcic_present(void)
 	return pci_controller_scan(pci_is_controller);
 }
 
-struct pci_iommu_ops *pci_iommu_ops;
+const struct pci_iommu_ops *pci_iommu_ops;
 EXPORT_SYMBOL(pci_iommu_ops);
 
-extern struct pci_iommu_ops pci_sun4u_iommu_ops,
+extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
 	pci_sun4v_iommu_ops;
 
 /* Find each controller in the system, attach and initialize
@@ -300,6 +306,474 @@ static void __init pci_controller_probe(
 	pci_controller_scan(pci_controller_init);
 }
 
+static unsigned long pci_parse_of_flags(u32 addr0)
+{
+	unsigned long flags = 0;
+
+	if (addr0 & 0x02000000) {
+		flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
+		flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
+		flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
+		if (addr0 & 0x40000000)
+			flags |= IORESOURCE_PREFETCH
+				 | PCI_BASE_ADDRESS_MEM_PREFETCH;
+	} else if (addr0 & 0x01000000)
+		flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
+	return flags;
+}
+
+/* The of_device layer has translated all of the assigned-address properties
+ * into physical address resources, we only have to figure out the register
+ * mapping.
+ */
+static void pci_parse_of_addrs(struct of_device *op,
+			       struct device_node *node,
+			       struct pci_dev *dev)
+{
+	struct resource *op_res;
+	const u32 *addrs;
+	int proplen;
+
+	addrs = of_get_property(node, "assigned-addresses", &proplen);
+	if (!addrs)
+		return;
+	printk("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
+	op_res = &op->resource[0];
+	for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) {
+		struct resource *res;
+		unsigned long flags;
+		int i;
+
+		flags = pci_parse_of_flags(addrs[0]);
+		if (!flags)
+			continue;
+		i = addrs[0] & 0xff;
+		printk("  start: %lx, end: %lx, i: %x\n",
+		       op_res->start, op_res->end, i);
+
+		if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
+			res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
+		} else if (i == dev->rom_base_reg) {
+			res = &dev->resource[PCI_ROM_RESOURCE];
+			flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+		} else {
+			printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i);
+			continue;
+		}
+		res->start = op_res->start;
+		res->end = op_res->end;
+		res->flags = flags;
+		res->name = pci_name(dev);
+	}
+}
+
+struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+				  struct device_node *node,
+				  struct pci_bus *bus, int devfn,
+				  int host_controller)
+{
+	struct dev_archdata *sd;
+	struct pci_dev *dev;
+	const char *type;
+	u32 class;
+
+	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	sd = &dev->dev.archdata;
+	sd->iommu = pbm->iommu;
+	sd->stc = &pbm->stc;
+	sd->host_controller = pbm;
+	sd->prom_node = node;
+	sd->op = of_find_device_by_node(node);
+	sd->msi_num = 0xffffffff;
+
+	type = of_get_property(node, "device_type", NULL);
+	if (type == NULL)
+		type = "";
+
+	printk("    create device, devfn: %x, type: %s hostcontroller(%d)\n",
+	       devfn, type, host_controller);
+
+	dev->bus = bus;
+	dev->sysdata = node;
+	dev->dev.parent = bus->bridge;
+	dev->dev.bus = &pci_bus_type;
+	dev->devfn = devfn;
+	dev->multifunction = 0;		/* maybe a lie? */
+
+	if (host_controller) {
+		dev->vendor = 0x108e;
+		dev->device = 0x8000;
+		dev->subsystem_vendor = 0x0000;
+		dev->subsystem_device = 0x0000;
+		dev->cfg_size = 256;
+		dev->class = PCI_CLASS_BRIDGE_HOST << 8;
+		sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+			0x00, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	} else {
+		dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
+		dev->device = of_getintprop_default(node, "device-id", 0xffff);
+		dev->subsystem_vendor =
+			of_getintprop_default(node, "subsystem-vendor-id", 0);
+		dev->subsystem_device =
+			of_getintprop_default(node, "subsystem-id", 0);
+
+		dev->cfg_size = pci_cfg_space_size(dev);
+
+		/* We can't actually use the firmware value, we have
+		 * to read what is in the register right now.  One
+		 * reason is that in the case of IDE interfaces the
+		 * firmware can sample the value before the the IDE
+		 * interface is programmed into native mode.
+		 */
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+		dev->class = class >> 8;
+
+		sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+			dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	}
+	printk("    class: 0x%x device name: %s\n",
+	       dev->class, pci_name(dev));
+
+	/* I have seen IDE devices which will not respond to
+	 * the bmdma simplex check reads if bus mastering is
+	 * disabled.
+	 */
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
+		pci_set_master(dev);
+
+	dev->current_state = 4;		/* unknown power state */
+	dev->error_state = pci_channel_io_normal;
+
+	if (host_controller) {
+		dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+		dev->rom_base_reg = PCI_ROM_ADDRESS1;
+		dev->irq = PCI_IRQ_NONE;
+	} else {
+		if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+			/* a PCI-PCI bridge */
+			dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+			dev->rom_base_reg = PCI_ROM_ADDRESS1;
+		} else if (!strcmp(type, "cardbus")) {
+			dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+		} else {
+			dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+			dev->rom_base_reg = PCI_ROM_ADDRESS;
+
+			dev->irq = sd->op->irqs[0];
+			if (dev->irq == 0xffffffff)
+				dev->irq = PCI_IRQ_NONE;
+		}
+	}
+	pci_parse_of_addrs(sd->op, node, dev);
+
+	printk("    adding to system ...\n");
+
+	pci_device_add(dev, bus);
+
+	return dev;
+}
+
+static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
+{
+	u32 idx, first, last;
+
+	first = 8;
+	last = 0;
+	for (idx = 0; idx < 8; idx++) {
+		if ((map & (1 << idx)) != 0) {
+			if (first > idx)
+				first = idx;
+			if (last < idx)
+				last = idx;
+		}
+	}
+
+	*first_p = first;
+	*last_p = last;
+}
+
+static void __init pci_resource_adjust(struct resource *res,
+				       struct resource *root)
+{
+	res->start += root->start;
+	res->end += root->start;
+}
+
+/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
+ * a proper 'ranges' property.
+ */
+static void __devinit apb_fake_ranges(struct pci_dev *dev,
+				      struct pci_bus *bus,
+				      struct pci_pbm_info *pbm)
+{
+	struct resource *res;
+	u32 first, last;
+	u8 map;
+
+	pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map);
+	apb_calc_first_last(map, &first, &last);
+	res = bus->resource[0];
+	res->start = (first << 21);
+	res->end = (last << 21) + ((1 << 21) - 1);
+	res->flags = IORESOURCE_IO;
+	pci_resource_adjust(res, &pbm->io_space);
+
+	pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
+	apb_calc_first_last(map, &first, &last);
+	res = bus->resource[1];
+	res->start = (first << 21);
+	res->end = (last << 21) + ((1 << 21) - 1);
+	res->flags = IORESOURCE_MEM;
+	pci_resource_adjust(res, &pbm->mem_space);
+}
+
+static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
+				      struct device_node *node,
+				      struct pci_bus *bus);
+
+#define GET_64BIT(prop, i)	((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
+
+static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
+					 struct device_node *node,
+					 struct pci_dev *dev)
+{
+	struct pci_bus *bus;
+	const u32 *busrange, *ranges;
+	int len, i, simba;
+	struct resource *res;
+	unsigned int flags;
+	u64 size;
+
+	printk("of_scan_pci_bridge(%s)\n", node->full_name);
+
+	/* parse bus-range property */
+	busrange = of_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 = of_get_property(node, "ranges", &len);
+	simba = 0;
+	if (ranges == NULL) {
+		const char *model = of_get_property(node, "model", NULL);
+		if (model && !strcmp(model, "SUNW,simba")) {
+			simba = 1;
+		} else {
+			printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
+			       node->full_name);
+			return;
+		}
+	}
+
+	bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
+	if (!bus) {
+		printk(KERN_ERR "Failed to create pci bus for %s\n",
+		       node->full_name);
+		return;
+	}
+
+	bus->primary = dev->bus->number;
+	bus->subordinate = busrange[1];
+	bus->bridge_ctl = 0;
+
+	/* parse ranges property, or cook one up by hand for Simba */
+	/* PCI #address-cells == 3 and #size-cells == 2 always */
+	res = &dev->resource[PCI_BRIDGE_RESOURCES];
+	for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) {
+		res->flags = 0;
+		bus->resource[i] = res;
+		++res;
+	}
+	if (simba) {
+		apb_fake_ranges(dev, bus, pbm);
+		goto simba_cont;
+	}
+	i = 1;
+	for (; len >= 32; len -= 32, ranges += 8) {
+		struct resource *root;
+
+		flags = pci_parse_of_flags(ranges[0]);
+		size = GET_64BIT(ranges, 6);
+		if (flags == 0 || size == 0)
+			continue;
+		if (flags & IORESOURCE_IO) {
+			res = bus->resource[0];
+			if (res->flags) {
+				printk(KERN_ERR "PCI: ignoring extra I/O range"
+				       " for bridge %s\n", node->full_name);
+				continue;
+			}
+			root = &pbm->io_space;
+		} else {
+			if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) {
+				printk(KERN_ERR "PCI: too many memory ranges"
+				       " for bridge %s\n", node->full_name);
+				continue;
+			}
+			res = bus->resource[i];
+			++i;
+			root = &pbm->mem_space;
+		}
+
+		res->start = GET_64BIT(ranges, 1);
+		res->end = res->start + size - 1;
+		res->flags = flags;
+
+		/* Another way to implement this would be to add an of_device
+		 * layer routine that can calculate a resource for a given
+		 * range property value in a PCI device.
+		 */
+		pci_resource_adjust(res, root);
+	}
+simba_cont:
+	sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
+		bus->number);
+	printk("    bus name: %s\n", bus->name);
+
+	pci_of_scan_bus(pbm, node, bus);
+}
+
+static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
+				      struct device_node *node,
+				      struct pci_bus *bus)
+{
+	struct device_node *child;
+	const u32 *reg;
+	int reglen, devfn;
+	struct pci_dev *dev;
+
+	printk("PCI: scan_bus[%s] bus no %d\n",
+	       node->full_name, bus->number);
+
+	child = NULL;
+	while ((child = of_get_next_child(node, child)) != NULL) {
+		printk("  * %s\n", child->full_name);
+		reg = of_get_property(child, "reg", &reglen);
+		if (reg == NULL || reglen < 20)
+			continue;
+		devfn = (reg[0] >> 8) & 0xff;
+
+		/* create a new pci_dev for this device */
+		dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
+		if (!dev)
+			continue;
+		printk("PCI: dev header type: %x\n", dev->hdr_type);
+
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			of_scan_pci_bridge(pbm, child, dev);
+	}
+}
+
+static ssize_t
+show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
+{
+	struct pci_dev *pdev;
+	struct device_node *dp;
+
+	pdev = to_pci_dev(dev);
+	dp = pdev->dev.archdata.prom_node;
+
+	return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
+}
+
+static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
+
+static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	struct pci_bus *child_bus;
+	int err;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/* we don't really care if we can create this file or
+		 * not, but we need to assign the result of the call
+		 * or the world will fall under alien invasion and
+		 * everybody will be frozen on a spaceship ready to be
+		 * eaten on alpha centauri by some green and jelly
+		 * humanoid.
+		 */
+		err = sysfs_create_file(&dev->dev.kobj, &dev_attr_obppath.attr);
+	}
+	list_for_each_entry(child_bus, &bus->children, node)
+		pci_bus_register_of_sysfs(child_bus);
+}
+
+int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+				 unsigned int devfn,
+				 int where, int size,
+				 u32 *value)
+{
+	static u8 fake_pci_config[] = {
+		0x8e, 0x10, /* Vendor: 0x108e (Sun) */
+		0x00, 0x80, /* Device: 0x8000 (PBM) */
+		0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
+		0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
+		0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
+		0x00, /* Cacheline: 0x00 */
+		0x40, /* Latency: 0x40 */
+		0x00, /* Header-Type: 0x00 normal */
+	};
+
+	*value = 0;
+	if (where >= 0 && where < sizeof(fake_pci_config) &&
+	    (where + size) >= 0 &&
+	    (where + size) < sizeof(fake_pci_config) &&
+	    size <= sizeof(u32)) {
+		while (size--) {
+			*value <<= 8;
+			*value |= fake_pci_config[where + size];
+		}
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+				  unsigned int devfn,
+				  int where, int size,
+				  u32 value)
+{
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+{
+	struct pci_controller_info *p = pbm->parent;
+	struct device_node *node = pbm->prom_node;
+	struct pci_dev *host_pdev;
+	struct pci_bus *bus;
+
+	printk("PCI: Scanning PBM %s\n", node->full_name);
+
+	/* XXX parent device? XXX */
+	bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
+	if (!bus) {
+		printk(KERN_ERR "Failed to create bus for %s\n",
+		       node->full_name);
+		return NULL;
+	}
+	bus->secondary = pbm->pci_first_busno;
+	bus->subordinate = pbm->pci_last_busno;
+
+	bus->resource[0] = &pbm->io_space;
+	bus->resource[1] = &pbm->mem_space;
+
+	/* Create the dummy host bridge and link it in.  */
+	host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1);
+	bus->self = host_pdev;
+
+	pci_of_scan_bus(pbm, node, bus);
+	pci_bus_add_devices(bus);
+	pci_bus_register_of_sysfs(bus);
+
+	return bus;
+}
+
 static void __init pci_scan_each_controller_bus(void)
 {
 	struct pci_controller_info *p;
@@ -360,8 +834,33 @@ void pcibios_align_resource(void *data, 
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev, int mask)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
+	u16 cmd, oldcmd;
+	int i;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	oldcmd = cmd;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = &dev->resource[i];
+
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<i)))
+			continue;
+
+		if (res->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (res->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+
+	if (cmd != oldcmd) {
+		printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n",
+		       pci_name(dev), cmd);
+                /* Enable the appropriate bits in the PCI command register.  */
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
 	return 0;
 }
 
@@ -380,7 +879,7 @@ void pcibios_resource_to_bus(struct pci_
 	else
 		root = &pbm->mem_space;
 
-	pbm->parent->resource_adjust(pdev, &zero_res, root);
+	pci_resource_adjust(&zero_res, root);
 
 	region->start = res->start - zero_res.start;
 	region->end = res->end - zero_res.start;
@@ -401,7 +900,7 @@ void pcibios_bus_to_resource(struct pci_
 	else
 		root = &pbm->mem_space;
 
-	pbm->parent->resource_adjust(pdev, res, root);
+	pci_resource_adjust(res, root);
 }
 EXPORT_SYMBOL(pcibios_bus_to_resource);
 
@@ -422,55 +921,17 @@ char * __devinit pcibios_setup(char *str
 static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma,
 				      enum pci_mmap_state mmap_state)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm;
+	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 	struct pci_controller_info *p;
 	unsigned long space_size, user_offset, user_size;
 
-	if (!pcp)
-		return -ENXIO;
-	pbm = pcp->pbm;
-	if (!pbm)
-		return -ENXIO;
-
 	p = pbm->parent;
-	if (p->pbms_same_domain) {
-		unsigned long lowest, highest;
-
-		lowest = ~0UL; highest = 0UL;
-		if (mmap_state == pci_mmap_io) {
-			if (p->pbm_A.io_space.flags) {
-				lowest = p->pbm_A.io_space.start;
-				highest = p->pbm_A.io_space.end + 1;
-			}
-			if (p->pbm_B.io_space.flags) {
-				if (lowest > p->pbm_B.io_space.start)
-					lowest = p->pbm_B.io_space.start;
-				if (highest < p->pbm_B.io_space.end + 1)
-					highest = p->pbm_B.io_space.end + 1;
-			}
-			space_size = highest - lowest;
-		} else {
-			if (p->pbm_A.mem_space.flags) {
-				lowest = p->pbm_A.mem_space.start;
-				highest = p->pbm_A.mem_space.end + 1;
-			}
-			if (p->pbm_B.mem_space.flags) {
-				if (lowest > p->pbm_B.mem_space.start)
-					lowest = p->pbm_B.mem_space.start;
-				if (highest < p->pbm_B.mem_space.end + 1)
-					highest = p->pbm_B.mem_space.end + 1;
-			}
-			space_size = highest - lowest;
-		}
+	if (mmap_state == pci_mmap_io) {
+		space_size = (pbm->io_space.end -
+			      pbm->io_space.start) + 1;
 	} else {
-		if (mmap_state == pci_mmap_io) {
-			space_size = (pbm->io_space.end -
-				      pbm->io_space.start) + 1;
-		} else {
-			space_size = (pbm->mem_space.end -
-				      pbm->mem_space.start) + 1;
-		}
+		space_size = (pbm->mem_space.end -
+			      pbm->mem_space.start) + 1;
 	}
 
 	/* Make sure the request is in range. */
@@ -481,31 +942,12 @@ static int __pci_mmap_make_offset_bus(st
 	    (user_offset + user_size) > space_size)
 		return -EINVAL;
 
-	if (p->pbms_same_domain) {
-		unsigned long lowest = ~0UL;
-
-		if (mmap_state == pci_mmap_io) {
-			if (p->pbm_A.io_space.flags)
-				lowest = p->pbm_A.io_space.start;
-			if (p->pbm_B.io_space.flags &&
-			    lowest > p->pbm_B.io_space.start)
-				lowest = p->pbm_B.io_space.start;
-		} else {
-			if (p->pbm_A.mem_space.flags)
-				lowest = p->pbm_A.mem_space.start;
-			if (p->pbm_B.mem_space.flags &&
-			    lowest > p->pbm_B.mem_space.start)
-				lowest = p->pbm_B.mem_space.start;
-		}
-		vma->vm_pgoff = (lowest + user_offset) >> PAGE_SHIFT;
+	if (mmap_state == pci_mmap_io) {
+		vma->vm_pgoff = (pbm->io_space.start +
+				 user_offset) >> PAGE_SHIFT;
 	} else {
-		if (mmap_state == pci_mmap_io) {
-			vma->vm_pgoff = (pbm->io_space.start +
-					 user_offset) >> PAGE_SHIFT;
-		} else {
-			vma->vm_pgoff = (pbm->mem_space.start +
-					 user_offset) >> PAGE_SHIFT;
-		}
+		vma->vm_pgoff = (pbm->mem_space.start +
+				 user_offset) >> PAGE_SHIFT;
 	}
 
 	return 0;
@@ -639,9 +1081,8 @@ int pci_domain_nr(struct pci_bus *pbus)
 		struct pci_controller_info *p = pbm->parent;
 
 		ret = p->index;
-		if (p->pbms_same_domain == 0)
-			ret = ((ret << 1) +
-			       ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
+		ret = ((ret << 1) +
+		       ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
 	}
 
 	return ret;
@@ -651,8 +1092,7 @@ EXPORT_SYMBOL(pci_domain_nr);
 #ifdef CONFIG_PCI_MSI
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
+	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 	struct pci_controller_info *p = pbm->parent;
 	int virt_irq, err;
 
@@ -660,18 +1100,17 @@ int arch_setup_msi_irq(struct pci_dev *p
 		return -EINVAL;
 
 	err = p->setup_msi_irq(&virt_irq, pdev, desc);
-	if (err < 0)
+	if (err)
 		return err;
 
-	return virt_irq;
+	return 0;
 }
 
 void arch_teardown_msi_irq(unsigned int virt_irq)
 {
 	struct msi_desc *entry = get_irq_msi(virt_irq);
 	struct pci_dev *pdev = entry->dev;
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
+	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 	struct pci_controller_info *p = pbm->parent;
 
 	if (!pbm->msi_num || !p->setup_msi_irq)
@@ -683,9 +1122,7 @@ #endif /* !(CONFIG_PCI_MSI) */
 
 struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
 {
-	struct pcidev_cookie *pc = pdev->sysdata;
-
-	return pc->op->node;
+	return pdev->dev.archdata.prom_node;
 }
 EXPORT_SYMBOL(pci_device_to_OF_node);
 
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 5a92cb9..1e6aeed 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,7 +1,6 @@
-/* $Id: pci_common.c,v 1.29 2002/02/01 00:56:03 davem Exp $
- * pci_common.c: PCI controller common support.
+/* pci_common.c: PCI controller common support.
  *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/string.h>
@@ -16,748 +15,137 @@ #include <asm/of_device.h>
 
 #include "pci_impl.h"
 
-/* Fix self device of BUS and hook it into BUS->self.
- * The pci_scan_bus does not do this for the host bridge.
- */
-void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
-{
-	struct pci_dev *pdev;
-
-	list_for_each_entry(pdev, &pbus->devices, bus_list) {
-		if (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) {
-			pbus->self = pdev;
-			return;
-		}
-	}
-
-	prom_printf("PCI: Critical error, cannot find host bridge PDEV.\n");
-	prom_halt();
-}
-
-/* Find the OBP PROM device tree node for a PCI device.  */
-static struct device_node * __init
-find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
-		      struct device_node *bus_node,
-		      struct linux_prom_pci_registers **pregs,
-		      int *nregs)
+static void pci_register_legacy_regions(struct resource *io_res,
+					struct resource *mem_res)
 {
-	struct device_node *dp;
-
-	*nregs = 0;
-
-	/*
-	 * Return the PBM's PROM node in case we are it's PCI device,
-	 * as the PBM's reg property is different to standard PCI reg
-	 * properties. We would delete this device entry otherwise,
-	 * which confuses XFree86's device probing...
-	 */
-	if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) &&
-	    (pdev->vendor == PCI_VENDOR_ID_SUN) &&
-	    (pdev->device == PCI_DEVICE_ID_SUN_PBM ||
-	     pdev->device == PCI_DEVICE_ID_SUN_SCHIZO ||
-	     pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
-	     pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
-	     pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
-		return bus_node;
-
-	dp = bus_node->child;
-	while (dp) {
-		struct linux_prom_pci_registers *regs;
-		struct property *prop;
-		int len;
-
-		prop = of_find_property(dp, "reg", &len);
-		if (!prop)
-			goto do_next_sibling;
-
-		regs = prop->value;
-		if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
-			*pregs = regs;
-			*nregs = len / sizeof(struct linux_prom_pci_registers);
-			return dp;
-		}
-
-	do_next_sibling:
-		dp = dp->sibling;
-	}
-
-	return NULL;
-}
+	struct resource *p;
 
-/* Older versions of OBP on PCI systems encode 64-bit MEM
- * space assignments incorrectly, this fixes them up.  We also
- * take the opportunity here to hide other kinds of bogus
- * assignments.
- */
-static void __init fixup_obp_assignments(struct pci_dev *pdev,
-					 struct pcidev_cookie *pcp)
-{
-	int i;
-
-	if (pdev->vendor == PCI_VENDOR_ID_AL &&
-	    (pdev->device == PCI_DEVICE_ID_AL_M7101 ||
-	     pdev->device == PCI_DEVICE_ID_AL_M1533)) {
-		int i;
-
-		/* Zap all of the normal resources, they are
-		 * meaningless and generate bogus resource collision
-		 * messages.  This is OpenBoot's ill-fated attempt to
-		 * represent the implicit resources that these devices
-		 * have.
-		 */
-		pcp->num_prom_assignments = 0;
-		for (i = 0; i < 6; i++) {
-			pdev->resource[i].start =
-				pdev->resource[i].end =
-				pdev->resource[i].flags = 0;
-		}
-		pdev->resource[PCI_ROM_RESOURCE].start =
-			pdev->resource[PCI_ROM_RESOURCE].end =
-			pdev->resource[PCI_ROM_RESOURCE].flags = 0;
+	/* VGA Video RAM. */
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
 		return;
-	}
-
-	for (i = 0; i < pcp->num_prom_assignments; i++) {
-		struct linux_prom_pci_registers *ap;
-		int space;
 
-		ap = &pcp->prom_assignments[i];
-		space = ap->phys_hi >> 24;
-		if ((space & 0x3) == 2 &&
-		    (space & 0x4) != 0) {
-			ap->phys_hi &= ~(0x7 << 24);
-			ap->phys_hi |= 0x3 << 24;
-		}
-	}
-}
-
-static ssize_t
-show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
-	struct pci_dev *pdev;
-	struct pcidev_cookie *sysdata;
-
-	pdev = to_pci_dev(dev);
-	sysdata = pdev->sysdata;
-
-	return snprintf (buf, PAGE_SIZE, "%s\n", sysdata->prom_node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
+	p->name = "Video RAM area";
+	p->start = mem_res->start + 0xa0000UL;
+	p->end = p->start + 0x1ffffUL;
+	p->flags = IORESOURCE_BUSY;
+	request_resource(mem_res, p);
 
-/* Fill in the PCI device cookie sysdata for the given
- * PCI device.  This cookie is the means by which one
- * can get to OBP and PCI controller specific information
- * for a PCI device.
- */
-static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
-				      struct pci_dev *pdev,
-				      struct device_node *bus_node)
-{
-	struct linux_prom_pci_registers *pregs = NULL;
-	struct pcidev_cookie *pcp;
-	struct device_node *dp;
-	struct property *prop;
-	int nregs, len, err;
-
-	dp = find_device_prom_node(pbm, pdev, bus_node,
-				   &pregs, &nregs);
-	if (!dp) {
-		/* If it is not in the OBP device tree then
-		 * there must be a damn good reason for it.
-		 *
-		 * So what we do is delete the device from the
-		 * PCI device tree completely.  This scenario
-		 * is seen, for example, on CP1500 for the
-		 * second EBUS/HappyMeal pair if the external
-		 * connector for it is not present.
-		 */
-		pci_remove_bus_device(pdev);
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
 		return;
-	}
-
-	pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC);
-	if (pcp == NULL) {
-		prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
-		prom_halt();
-	}
-	pcp->pbm = pbm;
-	pcp->prom_node = dp;
-	pcp->op = of_find_device_by_node(dp);
-	memcpy(pcp->prom_regs, pregs,
-	       nregs * sizeof(struct linux_prom_pci_registers));
-	pcp->num_prom_regs = nregs;
-
-	/* We can't have the pcidev_cookie assignments be just
-	 * direct pointers into the property value, since they
-	 * are potentially modified by the probing process.
-	 */
-	prop = of_find_property(dp, "assigned-addresses", &len);
-	if (!prop) {
-		pcp->num_prom_assignments = 0;
-	} else {
-		memcpy(pcp->prom_assignments, prop->value, len);
-		pcp->num_prom_assignments =
-			(len / sizeof(pcp->prom_assignments[0]));
-	}
-
-	if (strcmp(dp->name, "ebus") == 0) {
-		struct linux_prom_ebus_ranges *erng;
-		int iter;
-
-		/* EBUS is special... */
-		prop = of_find_property(dp, "ranges", &len);
-		if (!prop) {
-			prom_printf("EBUS: Fatal error, no range property\n");
-			prom_halt();
-		}
-		erng = prop->value;
-		len = (len / sizeof(erng[0]));
-		for (iter = 0; iter < len; iter++) {
-			struct linux_prom_ebus_ranges *ep = &erng[iter];
-			struct linux_prom_pci_registers *ap;
-
-			ap = &pcp->prom_assignments[iter];
-
-			ap->phys_hi = ep->parent_phys_hi;
-			ap->phys_mid = ep->parent_phys_mid;
-			ap->phys_lo = ep->parent_phys_lo;
-			ap->size_hi = 0;
-			ap->size_lo = ep->size;
-		}
-		pcp->num_prom_assignments = len;
-	}
-
-	fixup_obp_assignments(pdev, pcp);
-
-	pdev->sysdata = pcp;
-
-	/* we don't really care if we can create this file or not,
-	 * but we need to assign the result of the call or the world will fall
-	 * under alien invasion and everybody will be frozen on a spaceship
-	 * ready to be eaten on alpha centauri by some green and jelly humanoid.
-	 */
-	err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_obppath.attr);
-}
-
-void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
-				    struct pci_pbm_info *pbm,
-				    struct device_node *dp)
-{
-	struct pci_dev *pdev, *pdev_next;
-	struct pci_bus *this_pbus, *pbus_next;
-
-	/* This must be _safe because the cookie fillin
-	   routine can delete devices from the tree.  */
-	list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
-		pdev_cookie_fillin(pbm, pdev, dp);
-
-	list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
-		struct pcidev_cookie *pcp = this_pbus->self->sysdata;
-
-		pci_fill_in_pbm_cookies(this_pbus, pbm, pcp->prom_node);
-	}
-}
 
-static void __init bad_assignment(struct pci_dev *pdev,
-				  struct linux_prom_pci_registers *ap,
-				  struct resource *res,
-				  int do_prom_halt)
-{
-	prom_printf("PCI: Bogus PROM assignment. BUS[%02x] DEVFN[%x]\n",
-		    pdev->bus->number, pdev->devfn);
-	if (ap)
-		prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n",
-			    ap->phys_hi, ap->phys_mid, ap->phys_lo,
-			    ap->size_hi, ap->size_lo);
-	if (res)
-		prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
-			    res->start, res->end, res->flags);
-	if (do_prom_halt)
-		prom_halt();
-}
-
-static struct resource *
-__init get_root_resource(struct linux_prom_pci_registers *ap,
-			 struct pci_pbm_info *pbm)
-{
-	int space = (ap->phys_hi >> 24) & 3;
-
-	switch (space) {
-	case 0:
-		/* Configuration space, silently ignore it. */
-		return NULL;
-
-	case 1:
-		/* 16-bit IO space */
-		return &pbm->io_space;
-
-	case 2:
-		/* 32-bit MEM space */
-		return &pbm->mem_space;
-
-	case 3:
-		/* 64-bit MEM space, these are allocated out of
-		 * the 32-bit mem_space range for the PBM, ie.
-		 * we just zero out the upper 32-bits.
-		 */
-		return &pbm->mem_space;
-
-	default:
-		printk("PCI: What is resource space %x?\n", space);
-		return NULL;
-	};
-}
-
-static struct resource *
-__init get_device_resource(struct linux_prom_pci_registers *ap,
-			   struct pci_dev *pdev)
-{
-	struct resource *res;
-	int breg = (ap->phys_hi & 0xff);
-
-	switch (breg) {
-	case  PCI_ROM_ADDRESS:
-		/* Unfortunately I have seen several cases where
-		 * buggy FCODE uses a space value of '1' (I/O space)
-		 * in the register property for the ROM address
-		 * so disable this sanity check for now.
-		 */
-#if 0
-	{
-		int space = (ap->phys_hi >> 24) & 3;
-
-		/* It had better be MEM space. */
-		if (space != 2)
-			bad_assignment(pdev, ap, NULL, 0);
-	}
-#endif
-		res = &pdev->resource[PCI_ROM_RESOURCE];
-		break;
-
-	case PCI_BASE_ADDRESS_0:
-	case PCI_BASE_ADDRESS_1:
-	case PCI_BASE_ADDRESS_2:
-	case PCI_BASE_ADDRESS_3:
-	case PCI_BASE_ADDRESS_4:
-	case PCI_BASE_ADDRESS_5:
-		res = &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4];
-		break;
-
-	default:
-		bad_assignment(pdev, ap, NULL, 0);
-		res = NULL;
-		break;
-	};
-
-	return res;
-}
-
-static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
-					   struct pci_dev *pdev)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	int i;
-
-	for (i = 0; i < pcp->num_prom_assignments; i++) {
-		struct linux_prom_pci_registers *ap;
-		struct resource *root, *res;
-
-		/* The format of this property is specified in
-		 * the PCI Bus Binding to IEEE1275-1994.
-		 */
-		ap = &pcp->prom_assignments[i];
-		root = get_root_resource(ap, pbm);
-		res = get_device_resource(ap, pdev);
-		if (root == NULL || res == NULL ||
-		    res->flags == 0)
-			continue;
-
-		/* Ok we know which resource this PROM assignment is
-		 * for, sanity check it.
-		 */
-		if ((res->start & 0xffffffffUL) != ap->phys_lo)
-			bad_assignment(pdev, ap, res, 1);
-
-		/* If it is a 64-bit MEM space assignment, verify that
-		 * the resource is too and that the upper 32-bits match.
-		 */
-		if (((ap->phys_hi >> 24) & 3) == 3) {
-			if (((res->flags & IORESOURCE_MEM) == 0) ||
-			    ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
-			     != PCI_BASE_ADDRESS_MEM_TYPE_64))
-				bad_assignment(pdev, ap, res, 1);
-			if ((res->start >> 32) != ap->phys_mid)
-				bad_assignment(pdev, ap, res, 1);
-
-			/* PBM cannot generate cpu initiated PIOs
-			 * to the full 64-bit space.  Therefore the
-			 * upper 32-bits better be zero.  If it is
-			 * not, just skip it and we will assign it
-			 * properly ourselves.
-			 */
-			if ((res->start >> 32) != 0UL) {
-				printk(KERN_ERR "PCI: OBP assigns out of range MEM address "
-				       "%016lx for region %ld on device %s\n",
-				       res->start, (res - &pdev->resource[0]), pci_name(pdev));
-				continue;
-			}
-		}
-
-		/* Adjust the resource into the physical address space
-		 * of this PBM.
-		 */
-		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.
-			 *
-			 * Do not print the warning for ROM resources
-			 * as such a conflict is quite common and
-			 * harmless as the ROM bar is disabled.
-			 */
-			rnum = (res - &pdev->resource[0]);
-			if (rnum != PCI_ROM_RESOURCE)
-				printk(KERN_ERR "PCI: Resource collision, "
-				       "region %d "
-				       "[%016lx:%016lx] of device %s\n",
-				       rnum,
-				       res->start, res->end,
-				       pci_name(pdev));
-		}
-	}
-}
-
-void __init pci_record_assignments(struct pci_pbm_info *pbm,
-				   struct pci_bus *pbus)
-{
-	struct pci_dev *dev;
-	struct pci_bus *bus;
+	p->name = "System ROM";
+	p->start = mem_res->start + 0xf0000UL;
+	p->end = p->start + 0xffffUL;
+	p->flags = IORESOURCE_BUSY;
+	request_resource(mem_res, p);
 
-	list_for_each_entry(dev, &pbus->devices, bus_list)
-		pdev_record_assignments(pbm, dev);
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return;
 
-	list_for_each_entry(bus, &pbus->children, node)
-		pci_record_assignments(pbm, bus);
+	p->name = "Video ROM";
+	p->start = mem_res->start + 0xc0000UL;
+	p->end = p->start + 0x7fffUL;
+	p->flags = IORESOURCE_BUSY;
+	request_resource(mem_res, p);
 }
 
-/* Return non-zero if PDEV has implicit I/O resources even
- * though it may not have an I/O base address register
- * active.
- */
-static int __init has_implicit_io(struct pci_dev *pdev)
+static void pci_register_iommu_region(struct pci_pbm_info *pbm)
 {
-	int class = pdev->class >> 8;
+	const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
 
-	if (class == PCI_CLASS_NOT_DEFINED ||
-	    class == PCI_CLASS_NOT_DEFINED_VGA ||
-	    class == PCI_CLASS_STORAGE_IDE ||
-	    (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		return 1;
+	if (vdma) {
+		struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
 
-	return 0;
-}
-
-static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
-					  struct pci_dev *pdev)
-{
-	u32 reg;
-	u16 cmd;
-	int i, io_seen, mem_seen;
-
-	io_seen = mem_seen = 0;
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		struct resource *root, *res;
-		unsigned long size, min, max, align;
-
-		res = &pdev->resource[i];
-
-		if (res->flags & IORESOURCE_IO)
-			io_seen++;
-		else if (res->flags & IORESOURCE_MEM)
-			mem_seen++;
-
-		/* If it is already assigned or the resource does
-		 * not exist, there is nothing to do.
-		 */
-		if (res->parent != NULL || res->flags == 0UL)
-			continue;
-
-		/* Determine the root we allocate from. */
-		if (res->flags & IORESOURCE_IO) {
-			root = &pbm->io_space;
-			min = root->start + 0x400UL;
-			max = root->end;
-		} else {
-			root = &pbm->mem_space;
-			min = root->start;
-			max = min + 0x80000000UL;
-		}
-
-		size = res->end - res->start;
-		align = size + 1;
-		if (allocate_resource(root, res, size + 1, min, max, align, NULL, NULL) < 0) {
-			/* uh oh */
-			prom_printf("PCI: Failed to allocate resource %d for %s\n",
-				    i, pci_name(pdev));
+		if (!rp) {
+			prom_printf("Cannot allocate IOMMU resource.\n");
 			prom_halt();
 		}
-
-		/* Update PCI config space. */
-		pbm->parent->base_address_update(pdev, i);
-	}
-
-	/* Special case, disable the ROM.  Several devices
-	 * act funny (ie. do not respond to memory space writes)
-	 * when it is left enabled.  A good example are Qlogic,ISP
-	 * adapters.
-	 */
-	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &reg);
-	reg &= ~PCI_ROM_ADDRESS_ENABLE;
-	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg);
-
-	/* If we saw I/O or MEM resources, enable appropriate
-	 * bits in PCI command register.
-	 */
-	if (io_seen || mem_seen) {
-		pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-		if (io_seen || has_implicit_io(pdev))
-			cmd |= PCI_COMMAND_IO;
-		if (mem_seen)
-			cmd |= PCI_COMMAND_MEMORY;
-		pci_write_config_word(pdev, PCI_COMMAND, cmd);
-	}
-
-	/* If this is a PCI bridge or an IDE controller,
-	 * enable bus mastering.  In the former case also
-	 * set the cache line size correctly.
-	 */
-	if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) ||
-	    (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) &&
-	     ((pdev->class & 0x80) != 0))) {
-		pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-		cmd |= PCI_COMMAND_MASTER;
-		pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
-		if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
-			pci_write_config_byte(pdev,
-					      PCI_CACHE_LINE_SIZE,
-					      (64 / sizeof(u32)));
+		rp->name = "IOMMU";
+		rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
+		rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
+		rp->flags = IORESOURCE_BUSY;
+		request_resource(&pbm->mem_space, rp);
 	}
 }
 
-void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
-				  struct pci_bus *pbus)
+void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 {
-	struct pci_dev *dev;
-	struct pci_bus *bus;
-
-	list_for_each_entry(dev, &pbus->devices, bus_list)
-		pdev_assign_unassigned(pbm, dev);
+	const struct linux_prom_pci_ranges *pbm_ranges;
+	int i, saw_mem, saw_io;
+	int num_pbm_ranges;
 
-	list_for_each_entry(bus, &pbus->children, node)
-		pci_assign_unassigned(pbm, bus);
-}
+	saw_mem = saw_io = 0;
+	pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+	num_pbm_ranges = i / sizeof(*pbm_ranges);
 
-static void __init pdev_fixup_irq(struct pci_dev *pdev)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct of_device *op = pcp->op;
+	for (i = 0; i < num_pbm_ranges; i++) {
+		const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
+		unsigned long a;
+		u32 parent_phys_hi, parent_phys_lo;
+		int type;
 
-	if (op->irqs[0] == 0xffffffff) {
-		pdev->irq = PCI_IRQ_NONE;
-		return;
-	}
+		parent_phys_hi = pr->parent_phys_hi;
+		parent_phys_lo = pr->parent_phys_lo;
+		if (tlb_type == hypervisor)
+			parent_phys_hi &= 0x0fffffff;
 
-	pdev->irq = op->irqs[0];
+		type = (pr->child_phys_hi >> 24) & 0x3;
+		a = (((unsigned long)parent_phys_hi << 32UL) |
+		     ((unsigned long)parent_phys_lo  <<  0UL));
 
-	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
-			      pdev->irq & PCI_IRQ_INO);
-}
-
-void __init pci_fixup_irq(struct pci_pbm_info *pbm,
-			  struct pci_bus *pbus)
-{
-	struct pci_dev *dev;
-	struct pci_bus *bus;
-
-	list_for_each_entry(dev, &pbus->devices, bus_list)
-		pdev_fixup_irq(dev);
-
-	list_for_each_entry(bus, &pbus->children, node)
-		pci_fixup_irq(pbm, bus);
-}
-
-static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
-{
-	u16 cmd;
-	u8 hdr_type, min_gnt, ltimer;
-
-	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_MASTER;
-	pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
-	/* Read it back, if the mastering bit did not
-	 * get set, the device does not support bus
-	 * mastering so we have nothing to do here.
-	 */
-	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-	if ((cmd & PCI_COMMAND_MASTER) == 0)
-		return;
-
-	/* Set correct cache line size, 64-byte on all
-	 * Sparc64 PCI systems.  Note that the value is
-	 * measured in 32-bit words.
-	 */
-	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
-			      64 / sizeof(u32));
-
-	pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
-	hdr_type &= ~0x80;
-	if (hdr_type != PCI_HEADER_TYPE_NORMAL)
-		return;
-
-	/* If the latency timer is already programmed with a non-zero
-	 * value, assume whoever set it (OBP or whoever) knows what
-	 * they are doing.
-	 */
-	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
-	if (ltimer != 0)
-		return;
-
-	/* XXX Since I'm tipping off the min grant value to
-	 * XXX choose a suitable latency timer value, I also
-	 * XXX considered making use of the max latency value
-	 * XXX as well.  Unfortunately I've seen too many bogusly
-	 * XXX low settings for it to the point where it lacks
-	 * XXX any usefulness.  In one case, an ethernet card
-	 * XXX claimed a min grant of 10 and a max latency of 5.
-	 * XXX Now, if I had two such cards on the same bus I
-	 * XXX could not set the desired burst period (calculated
-	 * XXX from min grant) without violating the max latency
-	 * XXX bound.  Duh...
-	 * XXX
-	 * XXX I blame dumb PC bios implementors for stuff like
-	 * XXX this, most of them don't even try to do something
-	 * XXX sensible with latency timer values and just set some
-	 * XXX default value (usually 32) into every device.
-	 */
-
-	pci_read_config_byte(pdev, PCI_MIN_GNT, &min_gnt);
-
-	if (min_gnt == 0) {
-		/* If no min_gnt setting then use a default
-		 * value.
-		 */
-		if (is_66mhz)
-			ltimer = 16;
-		else
-			ltimer = 32;
-	} else {
-		int shift_factor;
-
-		if (is_66mhz)
-			shift_factor = 2;
-		else
-			shift_factor = 3;
-
-		/* Use a default value when the min_gnt value
-		 * is erroneously high.
-		 */
-		if (((unsigned int) min_gnt << shift_factor) > 512 ||
-		    ((min_gnt << shift_factor) & 0xff) == 0) {
-			ltimer = 8 << shift_factor;
-		} else {
-			ltimer = min_gnt << shift_factor;
-		}
-	}
+		switch (type) {
+		case 0:
+			/* PCI config space, 16MB */
+			pbm->config_space = a;
+			break;
 
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
-}
+		case 1:
+			/* 16-bit IO space, 16MB */
+			pbm->io_space.start = a;
+			pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
+			pbm->io_space.flags = IORESOURCE_IO;
+			saw_io = 1;
+			break;
 
-void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
-				     struct pci_bus *pbus)
-{
-	struct pci_dev *pdev;
-	int all_are_66mhz;
-	u16 status;
+		case 2:
+			/* 32-bit MEM space, 2GB */
+			pbm->mem_space.start = a;
+			pbm->mem_space.end = a + (0x80000000UL - 1UL);
+			pbm->mem_space.flags = IORESOURCE_MEM;
+			saw_mem = 1;
+			break;
 
-	if (pbm->is_66mhz_capable == 0) {
-		all_are_66mhz = 0;
-		goto out;
-	}
+		case 3:
+			/* XXX 64-bit MEM handling XXX */
 
-	all_are_66mhz = 1;
-	list_for_each_entry(pdev, &pbus->devices, bus_list) {
-		pci_read_config_word(pdev, PCI_STATUS, &status);
-		if (!(status & PCI_STATUS_66MHZ)) {
-			all_are_66mhz = 0;
+		default:
 			break;
-		}
+		};
 	}
-out:
-	pbm->all_devs_66mhz = all_are_66mhz;
-
-	printk("PCI%d(PBM%c): Bus running at %dMHz\n",
-	       pbm->parent->index,
-	       (pbm == &pbm->parent->pbm_A) ? 'A' : 'B',
-	       (all_are_66mhz ? 66 : 33));
-}
-
-void pci_setup_busmastering(struct pci_pbm_info *pbm,
-			    struct pci_bus *pbus)
-{
-	struct pci_dev *dev;
-	struct pci_bus *bus;
-	int is_66mhz;
-
-	is_66mhz = pbm->is_66mhz_capable && pbm->all_devs_66mhz;
-
-	list_for_each_entry(dev, &pbus->devices, bus_list)
-		pdev_setup_busmastering(dev, is_66mhz);
-
-	list_for_each_entry(bus, &pbus->children, node)
-		pci_setup_busmastering(pbm, bus);
-}
-
-void pci_register_legacy_regions(struct resource *io_res,
-				 struct resource *mem_res)
-{
-	struct resource *p;
-
-	/* VGA Video RAM. */
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return;
 
-	p->name = "Video RAM area";
-	p->start = mem_res->start + 0xa0000UL;
-	p->end = p->start + 0x1ffffUL;
-	p->flags = IORESOURCE_BUSY;
-	request_resource(mem_res, p);
+	if (!saw_io || !saw_mem) {
+		prom_printf("%s: Fatal error, missing %s PBM range.\n",
+			    pbm->name,
+			    (!saw_io ? "IO" : "MEM"));
+		prom_halt();
+	}
 
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return;
+	printk("%s: PCI IO[%lx] MEM[%lx]\n",
+	       pbm->name,
+	       pbm->io_space.start,
+	       pbm->mem_space.start);
 
-	p->name = "System ROM";
-	p->start = mem_res->start + 0xf0000UL;
-	p->end = p->start + 0xffffUL;
-	p->flags = IORESOURCE_BUSY;
-	request_resource(mem_res, p);
+	pbm->io_space.name = pbm->mem_space.name = pbm->name;
 
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return;
+	request_resource(&ioport_resource, &pbm->io_space);
+	request_resource(&iomem_resource, &pbm->mem_space);
 
-	p->name = "Video ROM";
-	p->start = mem_res->start + 0xc0000UL;
-	p->end = p->start + 0x7fffUL;
-	p->flags = IORESOURCE_BUSY;
-	request_resource(mem_res, p);
+	pci_register_legacy_regions(&pbm->io_space,
+				    &pbm->mem_space);
+	pci_register_iommu_region(pbm);
 }
 
 /* Generic helper routines for PCI error reporting. */
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
new file mode 100644
index 0000000..0fe6266
--- /dev/null
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -0,0 +1,418 @@
+/* pci_fire.c: Sun4u platform PCI-E controller support.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <asm/pbm.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+#include "pci_impl.h"
+
+#define fire_read(__reg) \
+({	u64 __ret; \
+	__asm__ __volatile__("ldxa [%1] %2, %0" \
+			     : "=r" (__ret) \
+			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory"); \
+	__ret; \
+})
+#define fire_write(__reg, __val) \
+	__asm__ __volatile__("stxa %0, [%1] %2" \
+			     : /* no outputs */ \
+			     : "r" (__val), "r" (__reg), \
+			       "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory")
+
+/* Fire config space address format is nearly identical to
+ * that of SCHIZO and PSYCHO, except that in order to accomodate
+ * PCI-E extended config space the encoding can handle 12 bits
+ * of register address:
+ *
+ *  32     28 27 20 19    15 14      12 11  2  1 0
+ * -------------------------------------------------
+ * |0 0 0 0 0| bus | device | function | reg | 0 0 |
+ * -------------------------------------------------
+ */
+#define FIRE_CONFIG_BASE(PBM)	((PBM)->config_space)
+#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
+	(((unsigned long)(BUS)   << 20) |	\
+	 ((unsigned long)(DEVFN) << 12)  |	\
+	 ((unsigned long)(REG)))
+
+static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
+				      unsigned char bus,
+				      unsigned int devfn,
+				      int where)
+{
+	if (!pbm)
+		return NULL;
+	return (void *)
+		(FIRE_CONFIG_BASE(pbm) |
+		 FIRE_CONFIG_ENCODE(bus, devfn, where));
+}
+
+/* FIRE PCI configuration space accessors. */
+
+static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			     int where, int size, u32 *value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned char bus = bus_dev->number;
+	u32 *addr;
+	u16 tmp16;
+	u8 tmp8;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
+	switch (size) {
+	case 1:
+		*value = 0xff;
+		break;
+	case 2:
+		*value = 0xffff;
+		break;
+	case 4:
+		*value = 0xffffffff;
+		break;
+	}
+
+	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	switch (size) {
+	case 1:
+		pci_config_read8((u8 *)addr, &tmp8);
+		*value = tmp8;
+		break;
+
+	case 2:
+		if (where & 0x01) {
+			printk("pci_read_config_word: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_read16((u16 *)addr, &tmp16);
+		*value = tmp16;
+		break;
+
+	case 4:
+		if (where & 0x03) {
+			printk("pci_read_config_dword: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+
+		pci_config_read32(addr, value);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+			      int where, int size, u32 value)
+{
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned char bus = bus_dev->number;
+	u32 *addr;
+
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
+	addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	switch (size) {
+	case 1:
+		pci_config_write8((u8 *)addr, value);
+		break;
+
+	case 2:
+		if (where & 0x01) {
+			printk("pci_write_config_word: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+		pci_config_write16((u16 *)addr, value);
+		break;
+
+	case 4:
+		if (where & 0x03) {
+			printk("pci_write_config_dword: misaligned reg [%x]\n",
+			       where);
+			return PCIBIOS_SUCCESSFUL;
+		}
+
+		pci_config_write32(addr, value);
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_fire_ops = {
+	.read	=	fire_read_pci_cfg,
+	.write	=	fire_write_pci_cfg,
+};
+
+static void pbm_scan_bus(struct pci_controller_info *p,
+			 struct pci_pbm_info *pbm)
+{
+	pbm->pci_bus = pci_scan_one_pbm(pbm);
+}
+
+static void pci_fire_scan_bus(struct pci_controller_info *p)
+{
+	struct device_node *dp;
+
+	if ((dp = p->pbm_A.prom_node) != NULL)
+		pbm_scan_bus(p, &p->pbm_A);
+
+	if ((dp = p->pbm_B.prom_node) != NULL)
+		pbm_scan_bus(p, &p->pbm_B);
+
+	/* XXX register error interrupt handlers XXX */
+}
+
+#define FIRE_IOMMU_CONTROL	0x40000UL
+#define FIRE_IOMMU_TSBBASE	0x40008UL
+#define FIRE_IOMMU_FLUSH	0x40100UL
+#define FIRE_IOMMU_FLUSHINV	0x40100UL
+
+static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
+{
+	struct iommu *iommu = pbm->iommu;
+	u32 vdma[2], dma_mask;
+	u64 control;
+	int tsbsize;
+
+	/* No virtual-dma property on these guys, use largest size.  */
+	vdma[0] = 0xc0000000; /* base */
+	vdma[1] = 0x40000000; /* size */
+	dma_mask = 0xffffffff;
+	tsbsize = 128;
+
+	/* Register addresses. */
+	iommu->iommu_control  = pbm->pbm_regs + FIRE_IOMMU_CONTROL;
+	iommu->iommu_tsbbase  = pbm->pbm_regs + FIRE_IOMMU_TSBBASE;
+	iommu->iommu_flush    = pbm->pbm_regs + FIRE_IOMMU_FLUSH;
+	iommu->iommu_flushinv = pbm->pbm_regs + FIRE_IOMMU_FLUSHINV;
+
+	/* We use the main control/status register of FIRE as the write
+	 * completion register.
+	 */
+	iommu->write_complete_reg = pbm->controller_regs + 0x410000UL;
+
+	/*
+	 * Invalidate TLB Entries.
+	 */
+	fire_write(iommu->iommu_flushinv, ~(u64)0);
+
+	pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+
+	fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+
+	control = fire_read(iommu->iommu_control);
+	control |= (0x00000400 /* TSB cache snoop enable */	|
+		    0x00000300 /* Cache mode */			|
+		    0x00000002 /* Bypass enable */		|
+		    0x00000001 /* Translation enable */);
+	fire_write(iommu->iommu_control, control);
+}
+
+/* Based at pbm->controller_regs */
+#define FIRE_PARITY_CONTROL	0x470010UL
+#define  FIRE_PARITY_ENAB	0x8000000000000000UL
+#define FIRE_FATAL_RESET_CTL	0x471028UL
+#define  FIRE_FATAL_RESET_SPARE	0x0000000004000000UL
+#define  FIRE_FATAL_RESET_MB	0x0000000002000000UL
+#define  FIRE_FATAL_RESET_CPE	0x0000000000008000UL
+#define  FIRE_FATAL_RESET_APE	0x0000000000004000UL
+#define  FIRE_FATAL_RESET_PIO	0x0000000000000040UL
+#define  FIRE_FATAL_RESET_JW	0x0000000000000004UL
+#define  FIRE_FATAL_RESET_JI	0x0000000000000002UL
+#define  FIRE_FATAL_RESET_JR	0x0000000000000001UL
+#define FIRE_CORE_INTR_ENABLE	0x471800UL
+
+/* Based at pbm->pbm_regs */
+#define FIRE_TLU_CTRL		0x80000UL
+#define  FIRE_TLU_CTRL_TIM	0x00000000da000000UL
+#define  FIRE_TLU_CTRL_QDET	0x0000000000000100UL
+#define  FIRE_TLU_CTRL_CFG	0x0000000000000001UL
+#define FIRE_TLU_DEV_CTRL	0x90008UL
+#define FIRE_TLU_LINK_CTRL	0x90020UL
+#define FIRE_TLU_LINK_CTRL_CLK	0x0000000000000040UL
+#define FIRE_LPU_RESET		0xe2008UL
+#define FIRE_LPU_LLCFG		0xe2200UL
+#define  FIRE_LPU_LLCFG_VC0	0x0000000000000100UL
+#define FIRE_LPU_FCTRL_UCTRL	0xe2240UL
+#define  FIRE_LPU_FCTRL_UCTRL_N	0x0000000000000002UL
+#define  FIRE_LPU_FCTRL_UCTRL_P	0x0000000000000001UL
+#define FIRE_LPU_TXL_FIFOP	0xe2430UL
+#define FIRE_LPU_LTSSM_CFG2	0xe2788UL
+#define FIRE_LPU_LTSSM_CFG3	0xe2790UL
+#define FIRE_LPU_LTSSM_CFG4	0xe2798UL
+#define FIRE_LPU_LTSSM_CFG5	0xe27a0UL
+#define FIRE_DMC_IENAB		0x31800UL
+#define FIRE_DMC_DBG_SEL_A	0x53000UL
+#define FIRE_DMC_DBG_SEL_B	0x53008UL
+#define FIRE_PEC_IENAB		0x51800UL
+
+static void pci_fire_hw_init(struct pci_pbm_info *pbm)
+{
+	u64 val;
+
+	fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
+		   FIRE_PARITY_ENAB);
+
+	fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
+		   (FIRE_FATAL_RESET_SPARE |
+		    FIRE_FATAL_RESET_MB |
+		    FIRE_FATAL_RESET_CPE |
+		    FIRE_FATAL_RESET_APE |
+		    FIRE_FATAL_RESET_PIO |
+		    FIRE_FATAL_RESET_JW |
+		    FIRE_FATAL_RESET_JI |
+		    FIRE_FATAL_RESET_JR));
+
+	fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+
+	val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+	val |= (FIRE_TLU_CTRL_TIM |
+		FIRE_TLU_CTRL_QDET |
+		FIRE_TLU_CTRL_CFG);
+	fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
+	fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
+	fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
+		   FIRE_TLU_LINK_CTRL_CLK);
+
+	fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
+	fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
+		   FIRE_LPU_LLCFG_VC0);
+	fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
+		   (FIRE_LPU_FCTRL_UCTRL_N |
+		    FIRE_LPU_FCTRL_UCTRL_P));
+	fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
+		   ((0xffff << 16) | (0x0000 << 0)));
+	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
+	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
+	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
+		   (2 << 16) | (140 << 8));
+	fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
+
+	fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
+	fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
+	fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
+
+	fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+}
+
+static void pci_fire_pbm_init(struct pci_controller_info *p,
+				struct device_node *dp, u32 portid)
+{
+	const struct linux_prom64_registers *regs;
+	struct pci_pbm_info *pbm;
+	const u32 *ino_bitmap;
+	const unsigned int *busrange;
+
+	if ((portid & 1) == 0)
+		pbm = &p->pbm_A;
+	else
+		pbm = &p->pbm_B;
+
+	pbm->portid = portid;
+	pbm->parent = p;
+	pbm->prom_node = dp;
+	pbm->name = dp->full_name;
+
+	regs = of_get_property(dp, "reg", NULL);
+	pbm->pbm_regs = regs[0].phys_addr;
+	pbm->controller_regs = regs[1].phys_addr - 0x410000UL;
+
+	printk("%s: SUN4U PCIE Bus Module\n", pbm->name);
+
+	pci_determine_mem_io_space(pbm);
+
+	ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
+	pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
+			   ((u64)ino_bitmap[0] <<  0UL));
+
+	busrange = of_get_property(dp, "bus-range", NULL);
+	pbm->pci_first_busno = busrange[0];
+	pbm->pci_last_busno = busrange[1];
+
+	pci_fire_hw_init(pbm);
+	pci_fire_pbm_iommu_init(pbm);
+}
+
+static inline int portid_compare(u32 x, u32 y)
+{
+	if (x == (y ^ 1))
+		return 1;
+	return 0;
+}
+
+void fire_pci_init(struct device_node *dp, const char *model_name)
+{
+	struct pci_controller_info *p;
+	u32 portid = of_getintprop_default(dp, "portid", 0xff);
+	struct iommu *iommu;
+
+	for (p = pci_controller_root; p; p = p->next) {
+		struct pci_pbm_info *pbm;
+
+		if (p->pbm_A.prom_node && p->pbm_B.prom_node)
+			continue;
+
+		pbm = (p->pbm_A.prom_node ?
+		       &p->pbm_A :
+		       &p->pbm_B);
+
+		if (portid_compare(pbm->portid, portid)) {
+			pci_fire_pbm_init(p, dp, portid);
+			return;
+		}
+	}
+
+	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+	if (!p)
+		goto fatal_memory_error;
+
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto fatal_memory_error;
+
+	p->pbm_A.iommu = iommu;
+
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto fatal_memory_error;
+
+	p->pbm_B.iommu = iommu;
+
+	p->next = pci_controller_root;
+	pci_controller_root = p;
+
+	p->index = pci_num_controllers++;
+
+	p->scan_bus = pci_fire_scan_bus;
+	/* XXX MSI support XXX */
+	p->pci_ops = &pci_fire_ops;
+
+	/* Like PSYCHO and SCHIZO we have a 2GB aligned area
+	 * for memory space.
+	 */
+	pci_memspace_mask = 0x7fffffffUL;
+
+	pci_fire_pbm_init(p, dp, portid);
+	return;
+
+fatal_memory_error:
+	prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
+	prom_halt();
+}
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 971e2be..1208583 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -1,7 +1,6 @@
-/* $Id: pci_impl.h,v 1.9 2001/06/13 06:34:30 davem Exp $
- * pci_impl.h: Helper definitions for PCI controller support.
+/* pci_impl.h: Helper definitions for PCI controller support.
  *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #ifndef PCI_IMPL_H
@@ -13,26 +12,22 @@ #include <asm/io.h>
 #include <asm/prom.h>
 
 extern struct pci_controller_info *pci_controller_root;
+extern unsigned long pci_memspace_mask;
 
 extern int pci_num_controllers;
 
 /* PCI bus scanning and fixup support. */
-extern void pci_fixup_host_bridge_self(struct pci_bus *pbus);
-extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
-				    struct pci_pbm_info *pbm,
-				    struct device_node *prom_node);
-extern void pci_record_assignments(struct pci_pbm_info *pbm,
-				   struct pci_bus *pbus);
-extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
-				  struct pci_bus *pbus);
-extern void pci_fixup_irq(struct pci_pbm_info *pbm,
-			  struct pci_bus *pbus);
-extern void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
-					    struct pci_bus *pbus);
-extern void pci_setup_busmastering(struct pci_pbm_info *pbm,
-				   struct pci_bus *pbus);
-extern void pci_register_legacy_regions(struct resource *io_res,
-					struct resource *mem_res);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
+
+extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+					unsigned int devfn,
+					int where, int size,
+					u32 *value);
+extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+					 unsigned int devfn,
+					 int where, int size,
+					 u32 value);
 
 /* Error reporting support. */
 extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 7aca0f3..9e405cb 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -1,7 +1,6 @@
-/* $Id: pci_iommu.c,v 1.17 2001/12/17 07:05:09 davem Exp $
- * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
+/* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com)
  */
 
@@ -36,19 +35,23 @@ #define pci_iommu_write(__reg, __val) \
 			       "i" (ASI_PHYS_BYPASS_EC_E))
 
 /* Must be invoked under the IOMMU lock. */
-static void __iommu_flushall(struct pci_iommu *iommu)
+static void __iommu_flushall(struct iommu *iommu)
 {
-	unsigned long tag;
-	int entry;
+	if (iommu->iommu_flushinv) {
+		pci_iommu_write(iommu->iommu_flushinv, ~(u64)0);
+	} else {
+		unsigned long tag;
+		int entry;
 
-	tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-	for (entry = 0; entry < 16; entry++) {
-		pci_iommu_write(tag, 0);
-		tag += 8;
-	}
+		tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+		for (entry = 0; entry < 16; entry++) {
+			pci_iommu_write(tag, 0);
+			tag += 8;
+		}
 
-	/* Ensure completion of previous PIO writes. */
-	(void) pci_iommu_read(iommu->write_complete_reg);
+		/* Ensure completion of previous PIO writes. */
+		(void) pci_iommu_read(iommu->write_complete_reg);
+	}
 }
 
 #define IOPTE_CONSISTENT(CTX) \
@@ -64,7 +67,7 @@ #define IOPTE_STREAMING(CTX) \
 #define IOPTE_IS_DUMMY(iommu, iopte)	\
 	((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)
 
-static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)
+static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
 {
 	unsigned long val = iopte_val(*iopte);
 
@@ -75,9 +78,9 @@ static inline void iopte_make_dummy(stru
 }
 
 /* Based largely upon the ppc64 iommu allocator.  */
-static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages)
+static long pci_arena_alloc(struct iommu *iommu, unsigned long npages)
 {
-	struct pci_iommu_arena *arena = &iommu->arena;
+	struct iommu_arena *arena = &iommu->arena;
 	unsigned long n, i, start, end, limit;
 	int pass;
 
@@ -116,7 +119,7 @@ again:
 	return n;
 }
 
-static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
 {
 	unsigned long i;
 
@@ -124,7 +127,7 @@ static void pci_arena_free(struct pci_io
 		__clear_bit(i, arena->map);
 }
 
-void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
+void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
 {
 	unsigned long i, tsbbase, order, sz, num_tsb_entries;
 
@@ -170,7 +173,7 @@ void pci_iommu_table_init(struct pci_iom
 		iopte_make_dummy(iommu, &iommu->page_table[i]);
 }
 
-static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages)
+static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
 {
 	long entry;
 
@@ -181,12 +184,12 @@ static inline iopte_t *alloc_npages(stru
 	return iommu->page_table + entry;
 }
 
-static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages)
+static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
 {
 	pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
 }
 
-static int iommu_alloc_ctx(struct pci_iommu *iommu)
+static int iommu_alloc_ctx(struct iommu *iommu)
 {
 	int lowest = iommu->ctx_lowest_free;
 	int sz = IOMMU_NUM_CTXS - lowest;
@@ -205,7 +208,7 @@ static int iommu_alloc_ctx(struct pci_io
 	return n;
 }
 
-static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
+static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
 {
 	if (likely(ctx)) {
 		__clear_bit(ctx, iommu->ctx_bitmap);
@@ -220,8 +223,7 @@ static inline void iommu_free_ctx(struct
  */
 static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	iopte_t *iopte;
 	unsigned long flags, order, first_page;
 	void *ret;
@@ -237,8 +239,7 @@ static void *pci_4u_alloc_consistent(str
 		return NULL;
 	memset((char *)first_page, 0, PAGE_SIZE << order);
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
+	iommu = pdev->dev.archdata.iommu;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
@@ -268,14 +269,12 @@ static void *pci_4u_alloc_consistent(str
 /* Free and unmap a consistent DMA translation. */
 static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	iopte_t *iopte;
 	unsigned long flags, order, npages;
 
 	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
+	iommu = pdev->dev.archdata.iommu;
 	iopte = iommu->page_table +
 		((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
@@ -295,18 +294,16 @@ static void pci_4u_free_consistent(struc
  */
 static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	iopte_t *base;
 	unsigned long flags, npages, oaddr;
 	unsigned long i, base_paddr, ctx;
 	u32 bus_addr, ret;
 	unsigned long iopte_protection;
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 
 	if (unlikely(direction == PCI_DMA_NONE))
 		goto bad_no_ctx;
@@ -349,7 +346,7 @@ bad_no_ctx:
 	return PCI_DMA_ERROR_CODE;
 }
 
-static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
+static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
 {
 	int limit;
 
@@ -416,9 +413,8 @@ do_flush_sync:
 /* Unmap a single streaming mode DMA translation. */
 static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	iopte_t *base;
 	unsigned long flags, npages, ctx, i;
 
@@ -428,9 +424,8 @@ static void pci_4u_unmap_single(struct p
 		return;
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 
 	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
@@ -549,9 +544,8 @@ static inline void fill_sg(iopte_t *iopt
  */
 static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	unsigned long flags, ctx, npages, iopte_protection;
 	iopte_t *base;
 	u32 dma_base;
@@ -570,9 +564,8 @@ static int pci_4u_map_sg(struct pci_dev 
 		return 1;
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 	
 	if (unlikely(direction == PCI_DMA_NONE))
 		goto bad_no_ctx;
@@ -636,9 +629,8 @@ bad_no_ctx:
 /* Unmap a set of streaming mode DMA translations. */
 static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	iopte_t *base;
 	unsigned long flags, ctx, i, npages;
 	u32 bus_addr;
@@ -648,9 +640,8 @@ static void pci_4u_unmap_sg(struct pci_d
 			WARN_ON(1);
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 	
 	bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
@@ -696,14 +687,12 @@ #endif
  */
 static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	unsigned long flags, ctx, npages;
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 
 	if (!strbuf->strbuf_enabled)
 		return;
@@ -736,15 +725,13 @@ static void pci_4u_dma_sync_single_for_c
  */
 static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
-	struct pci_strbuf *strbuf;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	unsigned long flags, ctx, npages, i;
 	u32 bus_addr;
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	strbuf = &pcp->pbm->stc;
+	iommu = pdev->dev.archdata.iommu;
+	strbuf = pdev->dev.archdata.stc;
 
 	if (!strbuf->strbuf_enabled)
 		return;
@@ -775,7 +762,7 @@ static void pci_4u_dma_sync_sg_for_cpu(s
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-struct pci_iommu_ops pci_sun4u_iommu_ops = {
+const struct pci_iommu_ops pci_sun4u_iommu_ops = {
 	.alloc_consistent		= pci_4u_alloc_consistent,
 	.free_consistent		= pci_4u_free_consistent,
 	.map_single			= pci_4u_map_single,
@@ -809,13 +796,12 @@ static void ali_sound_dma_hack(struct pc
 
 int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
 	u64 dma_addr_mask;
 
 	if (pdev == NULL) {
 		dma_addr_mask = 0xffffffff;
 	} else {
-		struct pci_iommu *iommu = pcp->pbm->iommu;
+		struct iommu *iommu = pdev->dev.archdata.iommu;
 
 		dma_addr_mask = iommu->dma_addr_mask;
 
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index fda5db2..253d40e 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,7 +1,6 @@
-/* $Id: pci_psycho.c,v 1.33 2002/02/01 00:58:33 davem Exp $
- * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
+/* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be)
  * Copyright (C) 1999 Jakub Jelinek   (jakub@redhat.com)
  */
@@ -119,6 +118,10 @@ static int psycho_read_pci_cfg(struct pc
 	u16 tmp16;
 	u8 tmp8;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
+
 	switch (size) {
 	case 1:
 		*value = 0xff;
@@ -172,6 +175,9 @@ static int psycho_write_pci_cfg(struct p
 	unsigned char bus = bus_dev->number;
 	u32 *addr;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
 	addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
 	if (!addr)
 		return PCIBIOS_SUCCESSFUL;
@@ -263,7 +269,7 @@ static void __psycho_check_one_stc(struc
 				   struct pci_pbm_info *pbm,
 				   int is_pbm_a)
 {
-	struct pci_strbuf *strbuf = &pbm->stc;
+	struct strbuf *strbuf = &pbm->stc;
 	unsigned long regbase = p->pbm_A.controller_regs;
 	unsigned long err_base, tag_base, line_base;
 	u64 control;
@@ -412,7 +418,7 @@ static void psycho_check_iommu_error(str
 				     unsigned long afar,
 				     enum psycho_error_type type)
 {
-	struct pci_iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = p->pbm_A.iommu;
 	unsigned long iommu_tag[16];
 	unsigned long iommu_data[16];
 	unsigned long flags;
@@ -895,59 +901,6 @@ static void psycho_register_error_handle
 }
 
 /* PSYCHO boot time probing and initialization. */
-static void psycho_resource_adjust(struct pci_dev *pdev,
-				   struct resource *res,
-				   struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
-static void psycho_base_address_update(struct pci_dev *pdev, int resource)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
-	struct resource *res, *root;
-	u32 reg;
-	int where, size, is_64bit;
-
-	res = &pdev->resource[resource];
-	if (resource < 6) {
-		where = PCI_BASE_ADDRESS_0 + (resource * 4);
-	} else if (resource == PCI_ROM_RESOURCE) {
-		where = pdev->rom_base_reg;
-	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
-		return;
-	}
-
-	is_64bit = 0;
-	if (res->flags & IORESOURCE_IO)
-		root = &pbm->io_space;
-	else {
-		root = &pbm->mem_space;
-		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
-		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
-			is_64bit = 1;
-	}
-
-	size = res->end - res->start;
-	pci_read_config_dword(pdev, where, &reg);
-	reg = ((reg & size) |
-	       (((u32)(res->start - root->start)) & ~size));
-	if (resource == PCI_ROM_RESOURCE) {
-		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= IORESOURCE_ROM_ENABLE;
-	}
-	pci_write_config_dword(pdev, where, reg);
-
-	/* This knows that the upper 32-bits of the address
-	 * must be zero.  Our PCI common layer enforces this.
-	 */
-	if (is_64bit)
-		pci_write_config_dword(pdev, where + 4, 0);
-}
-
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
 {
 	u8 *addr;
@@ -968,28 +921,7 @@ static void pbm_config_busmastering(stru
 static void pbm_scan_bus(struct pci_controller_info *p,
 			 struct pci_pbm_info *pbm)
 {
-	struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
-	if (!cookie) {
-		prom_printf("PSYCHO: Critical allocation failure.\n");
-		prom_halt();
-	}
-
-	/* All we care about is the PBM. */
-	cookie->pbm = pbm;
-
-	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
-				    p->pci_ops,
-				    pbm);
-	pci_fixup_host_bridge_self(pbm->pci_bus);
-	pbm->pci_bus->self->sysdata = cookie;
-
-	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
-	pci_record_assignments(pbm, pbm->pci_bus);
-	pci_assign_unassigned(pbm, pbm->pci_bus);
-	pci_fixup_irq(pbm, pbm->pci_bus);
-	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
-	pci_setup_busmastering(pbm, pbm->pci_bus);
+	pbm->pci_bus = pci_scan_one_pbm(pbm);
 }
 
 static void psycho_scan_bus(struct pci_controller_info *p)
@@ -1009,7 +941,7 @@ static void psycho_scan_bus(struct pci_c
 
 static void psycho_iommu_init(struct pci_controller_info *p)
 {
-	struct pci_iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = p->pbm_A.iommu;
 	unsigned long i;
 	u64 control;
 
@@ -1094,19 +1026,6 @@ static void psycho_controller_hwinit(str
 	psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
 }
 
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
-					    struct pci_pbm_info *pbm)
-{
-	char *name = pbm->name;
-
-	pbm->io_space.name = pbm->mem_space.name = name;
-
-	request_resource(&ioport_resource, &pbm->io_space);
-	request_resource(&iomem_resource, &pbm->mem_space);
-	pci_register_legacy_regions(&pbm->io_space,
-				    &pbm->mem_space);
-}
-
 static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
 				   struct pci_pbm_info *pbm,
 				   int is_pbm_a)
@@ -1172,19 +1091,11 @@ static void psycho_pbm_init(struct pci_c
 	unsigned int *busrange;
 	struct property *prop;
 	struct pci_pbm_info *pbm;
-	int len;
 
-	if (is_pbm_a) {
+	if (is_pbm_a)
 		pbm = &p->pbm_A;
-		pbm->pci_first_slot = 1;
-		pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_A;
-		pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_A;
-	} else {
+	else
 		pbm = &p->pbm_B;
-		pbm->pci_first_slot = 2;
-		pbm->io_space.start = pbm->controller_regs + PSYCHO_IOSPACE_B;
-		pbm->mem_space.start = pbm->controller_regs + PSYCHO_MEMSPACE_B;
-	}
 
 	pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
 	pbm->chip_version = 0;
@@ -1196,41 +1107,15 @@ static void psycho_pbm_init(struct pci_c
 	if (prop)
 		pbm->chip_revision = *(int *) prop->value;
 
-	pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
-	pbm->io_space.flags = IORESOURCE_IO;
-	pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE;
-	pbm->mem_space.flags = IORESOURCE_MEM;
-
 	pbm->parent = p;
 	pbm->prom_node = dp;
 	pbm->name = dp->full_name;
 
-	pbm_register_toplevel_resources(p, pbm);
-
 	printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
 	       pbm->name,
 	       pbm->chip_version, pbm->chip_revision);
 
-	prop = of_find_property(dp, "ranges", &len);
-	if (prop) {
-		pbm->pbm_ranges = prop->value;
-		pbm->num_pbm_ranges =
-			(len / sizeof(struct linux_prom_pci_ranges));
-	} else {
-		pbm->num_pbm_ranges = 0;
-	}
-
-	prop = of_find_property(dp, "interrupt-map", &len);
-	if (prop) {
-		pbm->pbm_intmap = prop->value;
-		pbm->num_pbm_intmap =
-			(len / sizeof(struct linux_prom_pci_intmap));
-
-		prop = of_find_property(dp, "interrupt-map-mask", NULL);
-		pbm->pbm_intmask = prop->value;
-	} else {
-		pbm->num_pbm_intmap = 0;
-	}
+	pci_determine_mem_io_space(pbm);
 
 	prop = of_find_property(dp, "bus-range", NULL);
 	busrange = prop->value;
@@ -1246,7 +1131,7 @@ void psycho_init(struct device_node *dp,
 {
 	struct linux_prom64_registers *pr_regs;
 	struct pci_controller_info *p;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	struct property *prop;
 	u32 upa_portid;
 	int is_pbm_a;
@@ -1269,7 +1154,7 @@ void psycho_init(struct device_node *dp,
 		prom_printf("PSYCHO: Fatal memory allocation error.\n");
 		prom_halt();
 	}
-	iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
 	if (!iommu) {
 		prom_printf("PSYCHO: Fatal memory allocation error.\n");
 		prom_halt();
@@ -1282,10 +1167,7 @@ void psycho_init(struct device_node *dp,
 	p->pbm_A.portid = upa_portid;
 	p->pbm_B.portid = upa_portid;
 	p->index = pci_num_controllers++;
-	p->pbms_same_domain = 0;
 	p->scan_bus = psycho_scan_bus;
-	p->base_address_update = psycho_base_address_update;
-	p->resource_adjust = psycho_resource_adjust;
 	p->pci_ops = &psycho_ops;
 
 	prop = of_find_property(dp, "reg", NULL);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 94bb681..397862f 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,7 +1,6 @@
-/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
- * pci_sabre.c: Sabre specific PCI controller support.
+/* pci_sabre.c: Sabre specific PCI controller support.
  *
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be)
  * Copyright (C) 1999 Jakub Jelinek   (jakub@redhat.com)
  */
@@ -254,9 +253,6 @@ static int __sabre_out_of_range(struct p
 		return 0;
 
 	return ((pbm->parent == 0) ||
-		((pbm == &pbm->parent->pbm_B) &&
-		 (bus == pbm->pci_first_busno) &&
-		 PCI_SLOT(devfn) > 8) ||
 		((pbm == &pbm->parent->pbm_A) &&
 		 (bus == pbm->pci_first_busno) &&
 		 PCI_SLOT(devfn) > 8));
@@ -322,6 +318,12 @@ static int __sabre_read_pci_cfg(struct p
 static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
 			      int where, int size, u32 *value)
 {
+	struct pci_pbm_info *pbm = bus->sysdata;
+
+	if (bus == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus, devfn, where,
+						    size, value);
+
 	if (!bus->number && sabre_out_of_range(devfn)) {
 		switch (size) {
 		case 1:
@@ -438,6 +440,12 @@ static int __sabre_write_pci_cfg(struct 
 static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
 			       int where, int size, u32 value)
 {
+	struct pci_pbm_info *pbm = bus->sysdata;
+
+	if (bus == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus, devfn, where,
+						     size, value);
+
 	if (bus->number)
 		return __sabre_write_pci_cfg(bus, devfn, where, size, value);
 
@@ -490,7 +498,7 @@ static void sabre_check_iommu_error(stru
 				    unsigned long afsr,
 				    unsigned long afar)
 {
-	struct pci_iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = p->pbm_A.iommu;
 	unsigned long iommu_tag[16];
 	unsigned long iommu_data[16];
 	unsigned long flags;
@@ -710,8 +718,8 @@ static irqreturn_t sabre_pcierr_intr_oth
 			       p->index);
 		ret = IRQ_HANDLED;
 	}
-	pci_read_config_word(sabre_root_bus->self,
-			     PCI_STATUS, &stat);
+	pci_bus_read_config_word(sabre_root_bus, 0,
+				 PCI_STATUS, &stat);
 	if (stat & (PCI_STATUS_PARITY |
 		    PCI_STATUS_SIG_TARGET_ABORT |
 		    PCI_STATUS_REC_TARGET_ABORT |
@@ -719,8 +727,8 @@ static irqreturn_t sabre_pcierr_intr_oth
 		    PCI_STATUS_SIG_SYSTEM_ERROR)) {
 		printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
 		       p->index, stat);
-		pci_write_config_word(sabre_root_bus->self,
-				      PCI_STATUS, 0xffff);
+		pci_bus_write_config_word(sabre_root_bus, 0,
+					  PCI_STATUS, 0xffff);
 		ret = IRQ_HANDLED;
 	}
 	return ret;
@@ -800,12 +808,10 @@ static irqreturn_t sabre_pcierr_intr(int
 	if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
 		sabre_check_iommu_error(p, afsr, afar);
 		pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
-		pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
 	}
-	if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) {
+	if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
 		pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
-		pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
-	}
+
 	/* For excessive retries, SABRE/PBM will abort the device
 	 * and there is no way to specifically check for excessive
 	 * retries in the config space status registers.  So what
@@ -813,10 +819,8 @@ static irqreturn_t sabre_pcierr_intr(int
 	 * abort events.
 	 */
 
-	if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) {
+	if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
 		pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
-		pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus);
-	}
 
 	return IRQ_HANDLED;
 }
@@ -869,144 +873,52 @@ static void sabre_register_error_handler
 	sabre_write(base + SABRE_PCICTRL, tmp);
 }
 
-static void sabre_resource_adjust(struct pci_dev *pdev,
-				  struct resource *res,
-				  struct resource *root)
-{
-	struct pci_pbm_info *pbm = pdev->bus->sysdata;
-	unsigned long base;
-
-	if (res->flags & IORESOURCE_IO)
-		base = pbm->controller_regs + SABRE_IOSPACE;
-	else
-		base = pbm->controller_regs + SABRE_MEMSPACE;
-
-	res->start += base;
-	res->end += base;
-}
-
-static void sabre_base_address_update(struct pci_dev *pdev, int resource)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
-	struct resource *res;
-	unsigned long base;
-	u32 reg;
-	int where, size, is_64bit;
-
-	res = &pdev->resource[resource];
-	if (resource < 6) {
-		where = PCI_BASE_ADDRESS_0 + (resource * 4);
-	} else if (resource == PCI_ROM_RESOURCE) {
-		where = pdev->rom_base_reg;
-	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
-		return;
-	}
-
-	is_64bit = 0;
-	if (res->flags & IORESOURCE_IO)
-		base = pbm->controller_regs + SABRE_IOSPACE;
-	else {
-		base = pbm->controller_regs + SABRE_MEMSPACE;
-		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
-		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
-			is_64bit = 1;
-	}
-
-	size = res->end - res->start;
-	pci_read_config_dword(pdev, where, &reg);
-	reg = ((reg & size) |
-	       (((u32)(res->start - base)) & ~size));
-	if (resource == PCI_ROM_RESOURCE) {
-		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= IORESOURCE_ROM_ENABLE;
-	}
-	pci_write_config_dword(pdev, where, reg);
-
-	/* This knows that the upper 32-bits of the address
-	 * must be zero.  Our PCI common layer enforces this.
-	 */
-	if (is_64bit)
-		pci_write_config_dword(pdev, where + 4, 0);
-}
-
 static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
 {
 	struct pci_dev *pdev;
 
 	list_for_each_entry(pdev, &sabre_bus->devices, bus_list) {
-
 		if (pdev->vendor == PCI_VENDOR_ID_SUN &&
 		    pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
-			u32 word32;
 			u16 word16;
 
-			sabre_read_pci_cfg(pdev->bus, pdev->devfn,
-					   PCI_COMMAND, 2, &word32);
-			word16 = (u16) word32;
+			pci_read_config_word(pdev, PCI_COMMAND, &word16);
 			word16 |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
 				PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
 				PCI_COMMAND_IO;
-			word32 = (u32) word16;
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_COMMAND, 2, word32);
+			pci_write_config_word(pdev, PCI_COMMAND, word16);
 
 			/* Status register bits are "write 1 to clear". */
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_STATUS, 2, 0xffff);
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_SEC_STATUS, 2, 0xffff);
+			pci_write_config_word(pdev, PCI_STATUS, 0xffff);
+			pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
 
 			/* Use a primary/seconday latency timer value
 			 * of 64.
 			 */
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_LATENCY_TIMER, 1, 64);
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_SEC_LATENCY_TIMER, 1, 64);
+			pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+			pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
 
 			/* Enable reporting/forwarding of master aborts,
 			 * parity, and SERR.
 			 */
-			sabre_write_pci_cfg(pdev->bus, pdev->devfn,
-					    PCI_BRIDGE_CONTROL, 1,
-					    (PCI_BRIDGE_CTL_PARITY |
-					     PCI_BRIDGE_CTL_SERR |
-					     PCI_BRIDGE_CTL_MASTER_ABORT));
+			pci_write_config_byte(pdev, PCI_BRIDGE_CONTROL,
+					      (PCI_BRIDGE_CTL_PARITY |
+					       PCI_BRIDGE_CTL_SERR |
+					       PCI_BRIDGE_CTL_MASTER_ABORT));
 		}
 	}
 }
 
-static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm)
-{
-	struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
-	if (!cookie) {
-		prom_printf("SABRE: Critical allocation failure.\n");
-		prom_halt();
-	}
-
-	/* All we care about is the PBM. */
-	cookie->pbm = pbm;
-
-	return cookie;
-}
-
 static void sabre_scan_bus(struct pci_controller_info *p)
 {
 	static int once;
-	struct pci_bus *sabre_bus, *pbus;
-	struct pci_pbm_info *pbm;
-	struct pcidev_cookie *cookie;
-	int sabres_scanned;
+	struct pci_bus *pbus;
 
 	/* The APB bridge speaks to the Sabre host PCI bridge
 	 * at 66Mhz, but the front side of APB runs at 33Mhz
 	 * for both segments.
 	 */
 	p->pbm_A.is_66mhz_capable = 0;
-	p->pbm_B.is_66mhz_capable = 0;
 
 	/* This driver has not been verified to handle
 	 * multiple SABREs yet, so trap this.
@@ -1020,56 +932,13 @@ static void sabre_scan_bus(struct pci_co
 	}
 	once++;
 
-	cookie = alloc_bridge_cookie(&p->pbm_A);
-
-	sabre_bus = pci_scan_bus(p->pci_first_busno,
-				 p->pci_ops,
-				 &p->pbm_A);
-	pci_fixup_host_bridge_self(sabre_bus);
-	sabre_bus->self->sysdata = cookie;
-
-	sabre_root_bus = sabre_bus;
-
-	apb_init(p, sabre_bus);
-
-	sabres_scanned = 0;
-
-	list_for_each_entry(pbus, &sabre_bus->children, node) {
-
-		if (pbus->number == p->pbm_A.pci_first_busno) {
-			pbm = &p->pbm_A;
-		} else if (pbus->number == p->pbm_B.pci_first_busno) {
-			pbm = &p->pbm_B;
-		} else
-			continue;
-
-		cookie = alloc_bridge_cookie(pbm);
-		pbus->self->sysdata = cookie;
-
-		sabres_scanned++;
+	pbus = pci_scan_one_pbm(&p->pbm_A);
+	if (!pbus)
+		return;
 
-		pbus->sysdata = pbm;
-		pbm->pci_bus = pbus;
-		pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node);
-		pci_record_assignments(pbm, pbus);
-		pci_assign_unassigned(pbm, pbus);
-		pci_fixup_irq(pbm, pbus);
-		pci_determine_66mhz_disposition(pbm, pbus);
-		pci_setup_busmastering(pbm, pbus);
-	}
+	sabre_root_bus = pbus;
 
-	if (!sabres_scanned) {
-		/* Hummingbird, no APBs. */
-		pbm = &p->pbm_A;
-		sabre_bus->sysdata = pbm;
-		pbm->pci_bus = sabre_bus;
-		pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node);
-		pci_record_assignments(pbm, sabre_bus);
-		pci_assign_unassigned(pbm, sabre_bus);
-		pci_fixup_irq(pbm, sabre_bus);
-		pci_determine_66mhz_disposition(pbm, sabre_bus);
-		pci_setup_busmastering(pbm, sabre_bus);
-	}
+	apb_init(p, pbus);
 
 	sabre_register_error_handlers(p);
 }
@@ -1078,7 +947,7 @@ static void sabre_iommu_init(struct pci_
 			     int tsbsize, unsigned long dvma_offset,
 			     u32 dma_mask)
 {
-	struct pci_iommu *iommu = p->pbm_A.iommu;
+	struct iommu *iommu = p->pbm_A.iommu;
 	unsigned long i;
 	u64 control;
 
@@ -1126,224 +995,31 @@ static void sabre_iommu_init(struct pci_
 	sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
 }
 
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
-					    struct pci_pbm_info *pbm)
-{
-	char *name = pbm->name;
-	unsigned long ibase = p->pbm_A.controller_regs + SABRE_IOSPACE;
-	unsigned long mbase = p->pbm_A.controller_regs + SABRE_MEMSPACE;
-	unsigned int devfn;
-	unsigned long first, last, i;
-	u8 *addr, map;
-
-	sprintf(name, "SABRE%d PBM%c",
-		p->index,
-		(pbm == &p->pbm_A ? 'A' : 'B'));
-	pbm->io_space.name = pbm->mem_space.name = name;
-
-	devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1);
-	addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP);
-	map = 0;
-	pci_config_read8(addr, &map);
-
-	first = 8;
-	last = 0;
-	for (i = 0; i < 8; i++) {
-		if ((map & (1 << i)) != 0) {
-			if (first > i)
-				first = i;
-			if (last < i)
-				last = i;
-		}
-	}
-	pbm->io_space.start = ibase + (first << 21UL);
-	pbm->io_space.end   = ibase + (last << 21UL) + ((1 << 21UL) - 1);
-	pbm->io_space.flags = IORESOURCE_IO;
-
-	addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP);
-	map = 0;
-	pci_config_read8(addr, &map);
-
-	first = 8;
-	last = 0;
-	for (i = 0; i < 8; i++) {
-		if ((map & (1 << i)) != 0) {
-			if (first > i)
-				first = i;
-			if (last < i)
-				last = i;
-		}
-	}
-	pbm->mem_space.start = mbase + (first << 29UL);
-	pbm->mem_space.end   = mbase + (last << 29UL) + ((1 << 29UL) - 1);
-	pbm->mem_space.flags = IORESOURCE_MEM;
-
-	if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
-		prom_printf("Cannot register PBM-%c's IO space.\n",
-			    (pbm == &p->pbm_A ? 'A' : 'B'));
-		prom_halt();
-	}
-	if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {
-		prom_printf("Cannot register PBM-%c's MEM space.\n",
-			    (pbm == &p->pbm_A ? 'A' : 'B'));
-		prom_halt();
-	}
-
-	/* Register legacy regions if this PBM covers that area. */
-	if (pbm->io_space.start == ibase &&
-	    pbm->mem_space.start == mbase)
-		pci_register_legacy_regions(&pbm->io_space,
-					    &pbm->mem_space);
-}
-
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
 {
 	struct pci_pbm_info *pbm;
-	struct device_node *node;
-	struct property *prop;
-	u32 *busrange;
-	int len, simbas_found;
-
-	simbas_found = 0;
-	node = dp->child;
-	while (node != NULL) {
-		if (strcmp(node->name, "pci"))
-			goto next_pci;
-
-		prop = of_find_property(node, "model", NULL);
-		if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
-			goto next_pci;
-
-		simbas_found++;
-
-		prop = of_find_property(node, "bus-range", NULL);
-		busrange = prop->value;
-		if (busrange[0] == 1)
-			pbm = &p->pbm_B;
-		else
-			pbm = &p->pbm_A;
-
-		pbm->name = node->full_name;
-		printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
-		pbm->chip_type = PBM_CHIP_TYPE_SABRE;
-		pbm->parent = p;
-		pbm->prom_node = node;
-		pbm->pci_first_slot = 1;
-		pbm->pci_first_busno = busrange[0];
-		pbm->pci_last_busno = busrange[1];
-
-		prop = of_find_property(node, "ranges", &len);
-		if (prop) {
-			pbm->pbm_ranges = prop->value;
-			pbm->num_pbm_ranges =
-				(len / sizeof(struct linux_prom_pci_ranges));
-		} else {
-			pbm->num_pbm_ranges = 0;
-		}
 
-		prop = of_find_property(node, "interrupt-map", &len);
-		if (prop) {
-			pbm->pbm_intmap = prop->value;
-			pbm->num_pbm_intmap =
-				(len / sizeof(struct linux_prom_pci_intmap));
-
-			prop = of_find_property(node, "interrupt-map-mask",
-						NULL);
-			pbm->pbm_intmask = prop->value;
-		} else {
-			pbm->num_pbm_intmap = 0;
-		}
+	pbm = &p->pbm_A;
+	pbm->name = dp->full_name;
+	printk("%s: SABRE PCI Bus Module\n", pbm->name);
 
-		pbm_register_toplevel_resources(p, pbm);
-
-	next_pci:
-		node = node->sibling;
-	}
-	if (simbas_found == 0) {
-		struct resource *rp;
+	pbm->chip_type = PBM_CHIP_TYPE_SABRE;
+	pbm->parent = p;
+	pbm->prom_node = dp;
+	pbm->pci_first_busno = p->pci_first_busno;
+	pbm->pci_last_busno = p->pci_last_busno;
 
-		/* No APBs underneath, probably this is a hummingbird
-		 * system.
-		 */
-		pbm = &p->pbm_A;
-		pbm->parent = p;
-		pbm->prom_node = dp;
-		pbm->pci_first_busno = p->pci_first_busno;
-		pbm->pci_last_busno = p->pci_last_busno;
-
-		prop = of_find_property(dp, "ranges", &len);
-		if (prop) {
-			pbm->pbm_ranges = prop->value;
-			pbm->num_pbm_ranges =
-				(len / sizeof(struct linux_prom_pci_ranges));
-		} else {
-			pbm->num_pbm_ranges = 0;
-		}
-
-		prop = of_find_property(dp, "interrupt-map", &len);
-		if (prop) {
-			pbm->pbm_intmap = prop->value;
-			pbm->num_pbm_intmap =
-				(len / sizeof(struct linux_prom_pci_intmap));
-
-			prop = of_find_property(dp, "interrupt-map-mask",
-						NULL);
-			pbm->pbm_intmask = prop->value;
-		} else {
-			pbm->num_pbm_intmap = 0;
-		}
-
-		pbm->name = dp->full_name;
-		printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
-		pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
-		/* Hack up top-level resources. */
-		pbm->io_space.start = p->pbm_A.controller_regs + SABRE_IOSPACE;
-		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 + ((1UL << 32UL) - 1UL));
-		pbm->mem_space.flags = IORESOURCE_MEM;
-
-		if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
-			prom_printf("Cannot register Hummingbird's IO space.\n");
-			prom_halt();
-		}
-		if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {
-			prom_printf("Cannot register Hummingbird's MEM space.\n");
-			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);
-	}
+	pci_determine_mem_io_space(pbm);
 }
 
 void sabre_init(struct device_node *dp, char *model_name)
 {
-	struct linux_prom64_registers *pr_regs;
+	const struct linux_prom64_registers *pr_regs;
 	struct pci_controller_info *p;
-	struct pci_iommu *iommu;
-	struct property *prop;
+	struct iommu *iommu;
 	int tsbsize;
-	u32 *busrange;
-	u32 *vdma;
+	const u32 *busrange;
+	const u32 *vdma;
 	u32 upa_portid, dma_mask;
 	u64 clear_irq;
 
@@ -1351,13 +1027,9 @@ void sabre_init(struct device_node *dp, 
 	if (!strcmp(model_name, "pci108e,a001"))
 		hummingbird_p = 1;
 	else if (!strcmp(model_name, "SUNW,sabre")) {
-		prop = of_find_property(dp, "compatible", NULL);
-		if (prop) {
-			const char *compat = prop->value;
-
-			if (!strcmp(compat, "pci108e,a001"))
-				hummingbird_p = 1;
-		}
+		const char *compat = of_get_property(dp, "compatible", NULL);
+		if (compat && !strcmp(compat, "pci108e,a001"))
+			hummingbird_p = 1;
 		if (!hummingbird_p) {
 			struct device_node *dp;
 
@@ -1381,37 +1053,28 @@ void sabre_init(struct device_node *dp, 
 		prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
 		prom_halt();
 	}
-	p->pbm_A.iommu = p->pbm_B.iommu = iommu;
+	p->pbm_A.iommu = iommu;
 
-	upa_portid = 0xff;
-	prop = of_find_property(dp, "upa-portid", NULL);
-	if (prop)
-		upa_portid = *(u32 *) prop->value;
+	upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
 	p->next = pci_controller_root;
 	pci_controller_root = p;
 
 	p->pbm_A.portid = upa_portid;
-	p->pbm_B.portid = upa_portid;
 	p->index = pci_num_controllers++;
-	p->pbms_same_domain = 1;
 	p->scan_bus = sabre_scan_bus;
-	p->base_address_update = sabre_base_address_update;
-	p->resource_adjust = sabre_resource_adjust;
 	p->pci_ops = &sabre_ops;
 
 	/*
 	 * Map in SABRE register set and report the presence of this SABRE.
 	 */
 	
-	prop = of_find_property(dp, "reg", NULL);
-	pr_regs = prop->value;
+	pr_regs = of_get_property(dp, "reg", NULL);
 
 	/*
 	 * First REG in property is base of entire SABRE register space.
 	 */
 	p->pbm_A.controller_regs = pr_regs[0].phys_addr;
-	p->pbm_B.controller_regs = pr_regs[0].phys_addr;
 
 	/* Clear interrupts */
 
@@ -1429,11 +1092,10 @@ void sabre_init(struct device_node *dp, 
 		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
 
 	/* Now map in PCI config space for entire SABRE. */
-	p->pbm_A.config_space = p->pbm_B.config_space =
+	p->pbm_A.config_space =
 		(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
 
-	prop = of_find_property(dp, "virtual-dma", NULL);
-	vdma = prop->value;
+	vdma = of_get_property(dp, "virtual-dma", NULL);
 
 	dma_mask = vdma[0];
 	switch(vdma[1]) {
@@ -1457,13 +1119,12 @@ void sabre_init(struct device_node *dp, 
 
 	sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
 
-	prop = of_find_property(dp, "bus-range", NULL);
-	busrange = prop->value;
+	busrange = of_get_property(dp, "bus-range", NULL);
 	p->pci_first_busno = busrange[0];
 	p->pci_last_busno = busrange[1];
 
 	/*
 	 * Look for APB underneath.
 	 */
-	sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]);
+	sabre_pbm_init(p, dp);
 }
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 66911b1..91a7385 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,7 +1,6 @@
-/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
- * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
+/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -126,6 +125,9 @@ static int schizo_read_pci_cfg(struct pc
 	u16 tmp16;
 	u8 tmp8;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
 	switch (size) {
 	case 1:
 		*value = 0xff;
@@ -179,6 +181,9 @@ static int schizo_write_pci_cfg(struct p
 	unsigned char bus = bus_dev->number;
 	u32 *addr;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
 	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
 	if (!addr)
 		return PCIBIOS_SUCCESSFUL;
@@ -274,7 +279,7 @@ #define SCHIZO_STCLINE_FOFN	0x0000000000
 static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
 					 enum schizo_error_type type)
 {
-	struct pci_strbuf *strbuf = &pbm->stc;
+	struct strbuf *strbuf = &pbm->stc;
 	unsigned long regbase = pbm->pbm_regs;
 	unsigned long err_base, tag_base, line_base;
 	u64 control;
@@ -382,7 +387,7 @@ #define SCHIZO_IOMMU_DATA_PPAGE	0x000000
 static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
 					 enum schizo_error_type type)
 {
-	struct pci_iommu *iommu = pbm->iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long iommu_tag[16];
 	unsigned long iommu_data[16];
 	unsigned long flags;
@@ -1229,42 +1234,8 @@ static void pbm_config_busmastering(stru
 	pci_config_write8(addr, 64);
 }
 
-static void pbm_scan_bus(struct pci_controller_info *p,
-			 struct pci_pbm_info *pbm)
-{
-	struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
-	if (!cookie) {
-		prom_printf("%s: Critical allocation failure.\n", pbm->name);
-		prom_halt();
-	}
-
-	/* All we care about is the PBM. */
-	cookie->pbm = pbm;
-
-	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
-				    p->pci_ops,
-				    pbm);
-	pci_fixup_host_bridge_self(pbm->pci_bus);
-	pbm->pci_bus->self->sysdata = cookie;
-
-	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
-	pci_record_assignments(pbm, pbm->pci_bus);
-	pci_assign_unassigned(pbm, pbm->pci_bus);
-	pci_fixup_irq(pbm, pbm->pci_bus);
-	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
-	pci_setup_busmastering(pbm, pbm->pci_bus);
-}
-
-static void __schizo_scan_bus(struct pci_controller_info *p,
-			      int chip_type)
+static void schizo_scan_bus(struct pci_controller_info *p)
 {
-	if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) {
-		printk("PCI: Only one PCI bus module of controller found.\n");
-		printk("PCI: Ignoring entire controller.\n");
-		return;
-	}
-
 	pbm_config_busmastering(&p->pbm_B);
 	p->pbm_B.is_66mhz_capable =
 		(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
@@ -1273,154 +1244,19 @@ static void __schizo_scan_bus(struct pci
 	p->pbm_A.is_66mhz_capable =
 		(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
 		 != NULL);
-	pbm_scan_bus(p, &p->pbm_B);
-	pbm_scan_bus(p, &p->pbm_A);
+
+	p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
+	p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
 
 	/* After the PCI bus scan is complete, we can register
 	 * the error interrupt handlers.
 	 */
-	if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+	if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
 		tomatillo_register_error_handlers(p);
 	else
 		schizo_register_error_handlers(p);
 }
 
-static void schizo_scan_bus(struct pci_controller_info *p)
-{
-	__schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);
-}
-
-static void tomatillo_scan_bus(struct pci_controller_info *p)
-{
-	__schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);
-}
-
-static void schizo_base_address_update(struct pci_dev *pdev, int resource)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
-	struct resource *res, *root;
-	u32 reg;
-	int where, size, is_64bit;
-
-	res = &pdev->resource[resource];
-	if (resource < 6) {
-		where = PCI_BASE_ADDRESS_0 + (resource * 4);
-	} else if (resource == PCI_ROM_RESOURCE) {
-		where = pdev->rom_base_reg;
-	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
-		return;
-	}
-
-	is_64bit = 0;
-	if (res->flags & IORESOURCE_IO)
-		root = &pbm->io_space;
-	else {
-		root = &pbm->mem_space;
-		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
-		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
-			is_64bit = 1;
-	}
-
-	size = res->end - res->start;
-	pci_read_config_dword(pdev, where, &reg);
-	reg = ((reg & size) |
-	       (((u32)(res->start - root->start)) & ~size));
-	if (resource == PCI_ROM_RESOURCE) {
-		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= IORESOURCE_ROM_ENABLE;
-	}
-	pci_write_config_dword(pdev, where, reg);
-
-	/* This knows that the upper 32-bits of the address
-	 * must be zero.  Our PCI common layer enforces this.
-	 */
-	if (is_64bit)
-		pci_write_config_dword(pdev, where + 4, 0);
-}
-
-static void schizo_resource_adjust(struct pci_dev *pdev,
-				   struct resource *res,
-				   struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
-/* Use ranges property to determine where PCI MEM, I/O, and Config
- * space are for this PCI bus module.
- */
-static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm)
-{
-	int i, saw_cfg, saw_mem, saw_io;
-
-	saw_cfg = saw_mem = saw_io = 0;
-	for (i = 0; i < pbm->num_pbm_ranges; i++) {
-		struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
-		unsigned long a;
-		int type;
-
-		type = (pr->child_phys_hi >> 24) & 0x3;
-		a = (((unsigned long)pr->parent_phys_hi << 32UL) |
-		     ((unsigned long)pr->parent_phys_lo  <<  0UL));
-
-		switch (type) {
-		case 0:
-			/* PCI config space, 16MB */
-			pbm->config_space = a;
-			saw_cfg = 1;
-			break;
-
-		case 1:
-			/* 16-bit IO space, 16MB */
-			pbm->io_space.start = a;
-			pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
-			pbm->io_space.flags = IORESOURCE_IO;
-			saw_io = 1;
-			break;
-
-		case 2:
-			/* 32-bit MEM space, 2GB */
-			pbm->mem_space.start = a;
-			pbm->mem_space.end = a + (0x80000000UL - 1UL);
-			pbm->mem_space.flags = IORESOURCE_MEM;
-			saw_mem = 1;
-			break;
-
-		default:
-			break;
-		};
-	}
-
-	if (!saw_cfg || !saw_io || !saw_mem) {
-		prom_printf("%s: Fatal error, missing %s PBM range.\n",
-			    pbm->name,
-			    ((!saw_cfg ?
-			      "CFG" :
-			      (!saw_io ?
-			       "IO" : "MEM"))));
-		prom_halt();
-	}
-
-	printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n",
-	       pbm->name,
-	       pbm->config_space,
-	       pbm->io_space.start,
-	       pbm->mem_space.start);
-}
-
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
-					    struct pci_pbm_info *pbm)
-{
-	pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
-	request_resource(&ioport_resource, &pbm->io_space);
-	request_resource(&iomem_resource, &pbm->mem_space);
-	pci_register_legacy_regions(&pbm->io_space,
-				    &pbm->mem_space);
-}
-
 #define SCHIZO_STRBUF_CONTROL		(0x02800UL)
 #define SCHIZO_STRBUF_FLUSH		(0x02808UL)
 #define SCHIZO_STRBUF_FSYNC		(0x02810UL)
@@ -1472,7 +1308,7 @@ #define SCHIZO_IOMMU_CTXFLUSH		(0x00218U
 
 static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
-	struct pci_iommu *iommu = pbm->iommu;
+	struct iommu *iommu = pbm->iommu;
 	unsigned long i, tagbase, database;
 	struct property *prop;
 	u32 vdma[2], dma_mask;
@@ -1654,14 +1490,12 @@ static void schizo_pbm_init(struct pci_c
 			    struct device_node *dp, u32 portid,
 			    int chip_type)
 {
-	struct linux_prom64_registers *regs;
-	struct property *prop;
-	unsigned int *busrange;
+	const struct linux_prom64_registers *regs;
+	const unsigned int *busrange;
 	struct pci_pbm_info *pbm;
 	const char *chipset_name;
-	u32 *ino_bitmap;
+	const u32 *ino_bitmap;
 	int is_pbm_a;
-	int len;
 
 	switch (chip_type) {
 	case PBM_CHIP_TYPE_TOMATILLO:
@@ -1689,11 +1523,9 @@ static void schizo_pbm_init(struct pci_c
 	 * 3) PBM PCI config space
 	 * 4) Ichip regs
 	 */
-	prop = of_find_property(dp, "reg", NULL);
-	regs = prop->value;
+	regs = of_get_property(dp, "reg", NULL);
 
 	is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-
 	if (is_pbm_a)
 		pbm = &p->pbm_A;
 	else
@@ -1702,17 +1534,10 @@ static void schizo_pbm_init(struct pci_c
 	pbm->portid = portid;
 	pbm->parent = p;
 	pbm->prom_node = dp;
-	pbm->pci_first_slot = 1;
 
 	pbm->chip_type = chip_type;
-	pbm->chip_version = 0;
-	prop = of_find_property(dp, "version#", NULL);
-	if (prop)
-		pbm->chip_version = *(int *) prop->value;
-	pbm->chip_revision = 0;
-	prop = of_find_property(dp, "module-revision#", NULL);
-	if (prop)
-		pbm->chip_revision = *(int *) prop->value;
+	pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+	pbm->chip_revision = of_getintprop_default(dp, "module-version#", 0);
 
 	pbm->pbm_regs = regs[0].phys_addr;
 	pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
@@ -1723,40 +1548,18 @@ static void schizo_pbm_init(struct pci_c
 	pbm->name = dp->full_name;
 
 	printk("%s: %s PCI Bus Module ver[%x:%x]\n",
-	       pbm->name,
-	       (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
-		"TOMATILLO" : "SCHIZO"),
+	       pbm->name, chipset_name,
 	       pbm->chip_version, pbm->chip_revision);
 
 	schizo_pbm_hw_init(pbm);
 
-	prop = of_find_property(dp, "ranges", &len);
-	pbm->pbm_ranges = prop->value;
-	pbm->num_pbm_ranges =
-		(len / sizeof(struct linux_prom_pci_ranges));
+	pci_determine_mem_io_space(pbm);
 
-	schizo_determine_mem_io_space(pbm);
-	pbm_register_toplevel_resources(p, pbm);
-
-	prop = of_find_property(dp, "interrupt-map", &len);
-	if (prop) {
-		pbm->pbm_intmap = prop->value;
-		pbm->num_pbm_intmap =
-			(len / sizeof(struct linux_prom_pci_intmap));
-
-		prop = of_find_property(dp, "interrupt-map-mask", NULL);
-		pbm->pbm_intmask = prop->value;
-	} else {
-		pbm->num_pbm_intmap = 0;
-	}
-
-	prop = of_find_property(dp, "ino-bitmap", NULL);
-	ino_bitmap = prop->value;
+	ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
 	pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
 			   ((u64)ino_bitmap[0] <<  0UL));
 
-	prop = of_find_property(dp, "bus-range", NULL);
-	busrange = prop->value;
+	busrange = of_get_property(dp, "bus-range", NULL);
 	pbm->pci_first_busno = busrange[0];
 	pbm->pci_last_busno = busrange[1];
 
@@ -1777,15 +1580,10 @@ static inline int portid_compare(u32 x, 
 static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
 {
 	struct pci_controller_info *p;
-	struct pci_iommu *iommu;
-	struct property *prop;
-	int is_pbm_a;
+	struct iommu *iommu;
 	u32 portid;
 
-	portid = 0xff;
-	prop = of_find_property(dp, "portid", NULL);
-	if (prop)
-		portid = *(u32 *) prop->value;
+	portid = of_getintprop_default(dp, "portid", 0xff);
 
 	for (p = pci_controller_root; p; p = p->next) {
 		struct pci_pbm_info *pbm;
@@ -1798,48 +1596,43 @@ static void __schizo_init(struct device_
 		       &p->pbm_B);
 
 		if (portid_compare(pbm->portid, portid, chip_type)) {
-			is_pbm_a = (p->pbm_A.prom_node == NULL);
 			schizo_pbm_init(p, dp, portid, chip_type);
 			return;
 		}
 	}
 
 	p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-	if (!p) {
-		prom_printf("SCHIZO: Fatal memory allocation error.\n");
-		prom_halt();
-	}
+	if (!p)
+		goto memfail;
+
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto memfail;
 
-	iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
-	if (!iommu) {
-		prom_printf("SCHIZO: Fatal memory allocation error.\n");
-		prom_halt();
-	}
 	p->pbm_A.iommu = iommu;
 
-	iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
-	if (!iommu) {
-		prom_printf("SCHIZO: Fatal memory allocation error.\n");
-		prom_halt();
-	}
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+	if (!iommu)
+		goto memfail;
+
 	p->pbm_B.iommu = iommu;
 
 	p->next = pci_controller_root;
 	pci_controller_root = p;
 
 	p->index = pci_num_controllers++;
-	p->pbms_same_domain = 0;
-	p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
-		       tomatillo_scan_bus :
-		       schizo_scan_bus);
-	p->base_address_update = schizo_base_address_update;
-	p->resource_adjust = schizo_resource_adjust;
+	p->scan_bus = schizo_scan_bus;
 	p->pci_ops = &schizo_ops;
 
 	/* Like PSYCHO we have a 2GB aligned area for memory space. */
 	pci_memspace_mask = 0x7fffffffUL;
 
 	schizo_pbm_init(p, dp, portid, chip_type);
+	return;
+
+memfail:
+	prom_printf("SCHIZO: Fatal memory allocation error.\n");
+	prom_halt();
 }
 
 void schizo_init(struct device_node *dp, char *model_name)
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index ec22cd6..1ccf4c9 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -1,6 +1,6 @@
 /* pci_sun4v.c: SUN4V specific PCI controller support.
  *
- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -29,7 +29,7 @@ #include "pci_sun4v.h"
 
 #define PGLIST_NENTS	(PAGE_SIZE / sizeof(u64))
 
-struct pci_iommu_batch {
+struct iommu_batch {
 	struct pci_dev	*pdev;		/* Device mapping is for.	*/
 	unsigned long	prot;		/* IOMMU page protections	*/
 	unsigned long	entry;		/* Index into IOTSB.		*/
@@ -37,12 +37,12 @@ struct pci_iommu_batch {
 	unsigned long	npages;		/* Number of pages in list.	*/
 };
 
-static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch);
+static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch);
 
 /* Interrupts must be disabled.  */
 static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry)
 {
-	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+	struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
 
 	p->pdev		= pdev;
 	p->prot		= prot;
@@ -51,10 +51,10 @@ static inline void pci_iommu_batch_start
 }
 
 /* Interrupts must be disabled.  */
-static long pci_iommu_batch_flush(struct pci_iommu_batch *p)
+static long pci_iommu_batch_flush(struct iommu_batch *p)
 {
-	struct pcidev_cookie *pcp = p->pdev->sysdata;
-	unsigned long devhandle = pcp->pbm->devhandle;
+	struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller;
+	unsigned long devhandle = pbm->devhandle;
 	unsigned long prot = p->prot;
 	unsigned long entry = p->entry;
 	u64 *pglist = p->pglist;
@@ -89,7 +89,7 @@ static long pci_iommu_batch_flush(struct
 /* Interrupts must be disabled.  */
 static inline long pci_iommu_batch_add(u64 phys_page)
 {
-	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+	struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
 
 	BUG_ON(p->npages >= PGLIST_NENTS);
 
@@ -103,14 +103,14 @@ static inline long pci_iommu_batch_add(u
 /* Interrupts must be disabled.  */
 static inline long pci_iommu_batch_end(void)
 {
-	struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+	struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
 
 	BUG_ON(p->npages >= PGLIST_NENTS);
 
 	return pci_iommu_batch_flush(p);
 }
 
-static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages)
+static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages)
 {
 	unsigned long n, i, start, end, limit;
 	int pass;
@@ -149,7 +149,7 @@ again:
 	return n;
 }
 
-static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
 {
 	unsigned long i;
 
@@ -159,8 +159,7 @@ static void pci_arena_free(struct pci_io
 
 static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	unsigned long flags, order, first_page, npages, n;
 	void *ret;
 	long entry;
@@ -178,8 +177,7 @@ static void *pci_4v_alloc_consistent(str
 
 	memset((char *)first_page, 0, PAGE_SIZE << order);
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
+	iommu = pdev->dev.archdata.iommu;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	entry = pci_arena_alloc(&iommu->arena, npages);
@@ -226,15 +224,15 @@ arena_alloc_fail:
 
 static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct pci_pbm_info *pbm;
+	struct iommu *iommu;
 	unsigned long flags, order, npages, entry;
 	u32 devhandle;
 
 	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	devhandle = pcp->pbm->devhandle;
+	iommu = pdev->dev.archdata.iommu;
+	pbm = pdev->dev.archdata.host_controller;
+	devhandle = pbm->devhandle;
 	entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 	spin_lock_irqsave(&iommu->lock, flags);
@@ -259,16 +257,14 @@ static void pci_4v_free_consistent(struc
 
 static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	unsigned long flags, npages, oaddr;
 	unsigned long i, base_paddr;
 	u32 bus_addr, ret;
 	unsigned long prot;
 	long entry;
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
+	iommu = pdev->dev.archdata.iommu;
 
 	if (unlikely(direction == PCI_DMA_NONE))
 		goto bad;
@@ -324,8 +320,8 @@ iommu_map_fail:
 
 static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct pci_pbm_info *pbm;
+	struct iommu *iommu;
 	unsigned long flags, npages;
 	long entry;
 	u32 devhandle;
@@ -336,9 +332,9 @@ static void pci_4v_unmap_single(struct p
 		return;
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	devhandle = pcp->pbm->devhandle;
+	iommu = pdev->dev.archdata.iommu;
+	pbm = pdev->dev.archdata.host_controller;
+	devhandle = pbm->devhandle;
 
 	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
@@ -460,8 +456,7 @@ iommu_map_failed:
 
 static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	unsigned long flags, npages, prot;
 	u32 dma_base;
 	struct scatterlist *sgtmp;
@@ -480,8 +475,7 @@ static int pci_4v_map_sg(struct pci_dev 
 		return 1;
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
+	iommu = pdev->dev.archdata.iommu;
 	
 	if (unlikely(direction == PCI_DMA_NONE))
 		goto bad;
@@ -537,8 +531,8 @@ iommu_map_failed:
 
 static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct pcidev_cookie *pcp;
-	struct pci_iommu *iommu;
+	struct pci_pbm_info *pbm;
+	struct iommu *iommu;
 	unsigned long flags, i, npages;
 	long entry;
 	u32 devhandle, bus_addr;
@@ -548,9 +542,9 @@ static void pci_4v_unmap_sg(struct pci_d
 			WARN_ON(1);
 	}
 
-	pcp = pdev->sysdata;
-	iommu = pcp->pbm->iommu;
-	devhandle = pcp->pbm->devhandle;
+	iommu = pdev->dev.archdata.iommu;
+	pbm = pdev->dev.archdata.host_controller;
+	devhandle = pbm->devhandle;
 	
 	bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
@@ -589,7 +583,7 @@ static void pci_4v_dma_sync_sg_for_cpu(s
 	/* Nothing to do... */
 }
 
-struct pci_iommu_ops pci_sun4v_iommu_ops = {
+const struct pci_iommu_ops pci_sun4v_iommu_ops = {
 	.alloc_consistent		= pci_4v_alloc_consistent,
 	.free_consistent		= pci_4v_free_consistent,
 	.map_single			= pci_4v_map_single,
@@ -600,132 +594,12 @@ struct pci_iommu_ops pci_sun4v_iommu_ops
 	.dma_sync_sg_for_cpu		= pci_4v_dma_sync_sg_for_cpu,
 };
 
-/* SUN4V PCI configuration space accessors. */
-
-struct pdev_entry {
-	struct pdev_entry	*next;
-	u32			devhandle;
-	unsigned int		bus;
-	unsigned int		device;
-	unsigned int		func;
-};
-
-#define PDEV_HTAB_SIZE	16
-#define PDEV_HTAB_MASK	(PDEV_HTAB_SIZE - 1)
-static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE];
-
-static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
-	unsigned int val;
-
-	val = (devhandle ^ (devhandle >> 4));
-	val ^= bus;
-	val ^= device;
-	val ^= func;
-
-	return val & PDEV_HTAB_MASK;
-}
-
-static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
-	struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL);
-	struct pdev_entry **slot;
-
-	if (!p)
-		return -ENOMEM;
-
-	slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)];
-	p->next = *slot;
-	*slot = p;
-
-	p->devhandle = devhandle;
-	p->bus = bus;
-	p->device = device;
-	p->func = func;
-
-	return 0;
-}
-
-/* Recursively descend into the OBP device tree, rooted at toplevel_node,
- * looking for a PCI device matching bus and devfn.
- */
-static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn)
-{
-	toplevel_node = toplevel_node->child;
-
-	while (toplevel_node != NULL) {
-		struct linux_prom_pci_registers *regs;
-		struct property *prop;
-		int ret;
-
-		ret = obp_find(toplevel_node, bus, devfn);
-		if (ret != 0)
-			return ret;
-
-		prop = of_find_property(toplevel_node, "reg", NULL);
-		if (!prop)
-			goto next_sibling;
-
-		regs = prop->value;
-		if (((regs->phys_hi >> 16) & 0xff) == bus &&
-		    ((regs->phys_hi >> 8) & 0xff) == devfn)
-			break;
-
-	next_sibling:
-		toplevel_node = toplevel_node->sibling;
-	}
-
-	return toplevel_node != NULL;
-}
-
-static int pdev_htab_populate(struct pci_pbm_info *pbm)
-{
-	u32 devhandle = pbm->devhandle;
-	unsigned int bus;
-
-	for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) {
-		unsigned int devfn;
-
-		for (devfn = 0; devfn < 256; devfn++) {
-			unsigned int device = PCI_SLOT(devfn);
-			unsigned int func = PCI_FUNC(devfn);
-
-			if (obp_find(pbm->prom_node, bus, devfn)) {
-				int err = pdev_htab_add(devhandle, bus,
-							device, func);
-				if (err)
-					return err;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func)
-{
-	struct pdev_entry *p;
-
-	p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)];
-	while (p) {
-		if (p->devhandle == devhandle &&
-		    p->bus == bus &&
-		    p->device == device &&
-		    p->func == func)
-			break;
-
-		p = p->next;
-	}
-
-	return p;
-}
-
 static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
 {
 	if (bus < pbm->pci_first_busno ||
 	    bus > pbm->pci_last_busno)
 		return 1;
-	return pdev_find(pbm->devhandle, bus, device, func) == NULL;
+	return 0;
 }
 
 static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
@@ -738,6 +612,9 @@ static int pci_sun4v_read_pci_cfg(struct
 	unsigned int func = PCI_FUNC(devfn);
 	unsigned long ret;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
 	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
 		ret = ~0UL;
 	} else {
@@ -776,6 +653,9 @@ static int pci_sun4v_write_pci_cfg(struc
 	unsigned int func = PCI_FUNC(devfn);
 	unsigned long ret;
 
+	if (bus_dev == pbm->pci_bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
 	if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
 		/* Do nothing. */
 	} else {
@@ -800,27 +680,7 @@ static struct pci_ops pci_sun4v_ops = {
 static void pbm_scan_bus(struct pci_controller_info *p,
 			 struct pci_pbm_info *pbm)
 {
-	struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
-
-	if (!cookie) {
-		prom_printf("%s: Critical allocation failure.\n", pbm->name);
-		prom_halt();
-	}
-
-	/* All we care about is the PBM. */
-	cookie->pbm = pbm;
-
-	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
-#if 0
-	pci_fixup_host_bridge_self(pbm->pci_bus);
-	pbm->pci_bus->self->sysdata = cookie;
-#endif
-	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
-	pci_record_assignments(pbm, pbm->pci_bus);
-	pci_assign_unassigned(pbm, pbm->pci_bus);
-	pci_fixup_irq(pbm, pbm->pci_bus);
-	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
-	pci_setup_busmastering(pbm, pbm->pci_bus);
+	pbm->pci_bus = pci_scan_one_pbm(pbm);
 }
 
 static void pci_sun4v_scan_bus(struct pci_controller_info *p)
@@ -844,130 +704,10 @@ static void pci_sun4v_scan_bus(struct pc
 	/* XXX register error interrupt handlers XXX */
 }
 
-static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource)
-{
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
-	struct resource *res, *root;
-	u32 reg;
-	int where, size, is_64bit;
-
-	res = &pdev->resource[resource];
-	if (resource < 6) {
-		where = PCI_BASE_ADDRESS_0 + (resource * 4);
-	} else if (resource == PCI_ROM_RESOURCE) {
-		where = pdev->rom_base_reg;
-	} else {
-		/* Somebody might have asked allocation of a non-standard resource */
-		return;
-	}
-
-	/* XXX 64-bit MEM handling is not %100 correct... XXX */
-	is_64bit = 0;
-	if (res->flags & IORESOURCE_IO)
-		root = &pbm->io_space;
-	else {
-		root = &pbm->mem_space;
-		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
-		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
-			is_64bit = 1;
-	}
-
-	size = res->end - res->start;
-	pci_read_config_dword(pdev, where, &reg);
-	reg = ((reg & size) |
-	       (((u32)(res->start - root->start)) & ~size));
-	if (resource == PCI_ROM_RESOURCE) {
-		reg |= PCI_ROM_ADDRESS_ENABLE;
-		res->flags |= IORESOURCE_ROM_ENABLE;
-	}
-	pci_write_config_dword(pdev, where, reg);
-
-	/* This knows that the upper 32-bits of the address
-	 * must be zero.  Our PCI common layer enforces this.
-	 */
-	if (is_64bit)
-		pci_write_config_dword(pdev, where + 4, 0);
-}
-
-static void pci_sun4v_resource_adjust(struct pci_dev *pdev,
-				      struct resource *res,
-				      struct resource *root)
-{
-	res->start += root->start;
-	res->end += root->start;
-}
-
-/* Use ranges property to determine where PCI MEM, I/O, and Config
- * space are for this PCI bus module.
- */
-static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm)
-{
-	int i, saw_mem, saw_io;
-
-	saw_mem = saw_io = 0;
-	for (i = 0; i < pbm->num_pbm_ranges; i++) {
-		struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i];
-		unsigned long a;
-		int type;
-
-		type = (pr->child_phys_hi >> 24) & 0x3;
-		a = (((unsigned long)pr->parent_phys_hi << 32UL) |
-		     ((unsigned long)pr->parent_phys_lo  <<  0UL));
-
-		switch (type) {
-		case 1:
-			/* 16-bit IO space, 16MB */
-			pbm->io_space.start = a;
-			pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL);
-			pbm->io_space.flags = IORESOURCE_IO;
-			saw_io = 1;
-			break;
-
-		case 2:
-			/* 32-bit MEM space, 2GB */
-			pbm->mem_space.start = a;
-			pbm->mem_space.end = a + (0x80000000UL - 1UL);
-			pbm->mem_space.flags = IORESOURCE_MEM;
-			saw_mem = 1;
-			break;
-
-		case 3:
-			/* XXX 64-bit MEM handling XXX */
-
-		default:
-			break;
-		};
-	}
-
-	if (!saw_io || !saw_mem) {
-		prom_printf("%s: Fatal error, missing %s PBM range.\n",
-			    pbm->name,
-			    (!saw_io ? "IO" : "MEM"));
-		prom_halt();
-	}
-
-	printk("%s: PCI IO[%lx] MEM[%lx]\n",
-	       pbm->name,
-	       pbm->io_space.start,
-	       pbm->mem_space.start);
-}
-
-static void pbm_register_toplevel_resources(struct pci_controller_info *p,
-					    struct pci_pbm_info *pbm)
-{
-	pbm->io_space.name = pbm->mem_space.name = pbm->name;
-
-	request_resource(&ioport_resource, &pbm->io_space);
-	request_resource(&iomem_resource, &pbm->mem_space);
-	pci_register_legacy_regions(&pbm->io_space,
-				    &pbm->mem_space);
-}
-
 static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
-					    struct pci_iommu *iommu)
+					    struct iommu *iommu)
 {
-	struct pci_iommu_arena *arena = &iommu->arena;
+	struct iommu_arena *arena = &iommu->arena;
 	unsigned long i, cnt = 0;
 	u32 devhandle;
 
@@ -994,7 +734,7 @@ static unsigned long probe_existing_entr
 
 static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
-	struct pci_iommu *iommu = pbm->iommu;
+	struct iommu *iommu = pbm->iommu;
 	struct property *prop;
 	unsigned long num_tsb_entries, sz;
 	u32 vdma[2], dma_mask, dma_offset;
@@ -1281,7 +1021,7 @@ h_error:
 
 static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 {
-	u32 *val;
+	const u32 *val;
 	int len;
 
 	val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
@@ -1289,16 +1029,16 @@ static void pci_sun4v_msi_init(struct pc
 		goto no_msi;
 	pbm->msiq_num = *val;
 	if (pbm->msiq_num) {
-		struct msiq_prop {
+		const struct msiq_prop {
 			u32 first_msiq;
 			u32 num_msiq;
 			u32 first_devino;
 		} *mqp;
-		struct msi_range_prop {
+		const struct msi_range_prop {
 			u32 first_msi;
 			u32 num_msi;
 		} *mrng;
-		struct addr_range_prop {
+		const struct addr_range_prop {
 			u32 msi32_high;
 			u32 msi32_low;
 			u32 msi32_len;
@@ -1410,8 +1150,7 @@ static int pci_sun4v_setup_msi_irq(unsig
 				   struct pci_dev *pdev,
 				   struct msi_desc *entry)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
+	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 	unsigned long devino, msiqid;
 	struct msi_msg msg;
 	int msi_num, err;
@@ -1430,8 +1169,6 @@ static int pci_sun4v_setup_msi_irq(unsig
 	if (!devino)
 		goto out_err;
 
-	set_irq_msi(*virt_irq_p, entry);
-
 	msiqid = ((devino - pbm->msiq_first_devino) +
 		  pbm->msiq_first);
 
@@ -1455,7 +1192,7 @@ static int pci_sun4v_setup_msi_irq(unsig
 	if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
 		goto out_err;
 
-	pcp->msi_num = msi_num;
+	pdev->dev.archdata.msi_num = msi_num;
 
 	if (entry->msi_attrib.is_64) {
 		msg.address_hi = pbm->msi64_start >> 32;
@@ -1465,6 +1202,8 @@ static int pci_sun4v_setup_msi_irq(unsig
 		msg.address_lo = pbm->msi32_start;
 	}
 	msg.data = msi_num;
+
+	set_irq_msi(*virt_irq_p, entry);
 	write_msi_msg(*virt_irq_p, &msg);
 
 	irq_install_pre_handler(*virt_irq_p,
@@ -1484,12 +1223,11 @@ out_err:
 static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
 				       struct pci_dev *pdev)
 {
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	struct pci_pbm_info *pbm = pcp->pbm;
+	struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 	unsigned long msiqid, err;
 	unsigned int msi_num;
 
-	msi_num = pcp->msi_num;
+	msi_num = pdev->dev.archdata.msi_num;
 	err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
 	if (err) {
 		printk(KERN_ERR "%s: getmsiq gives error %lu\n",
@@ -1516,8 +1254,6 @@ #endif /* !(CONFIG_PCI_MSI) */
 static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
 {
 	struct pci_pbm_info *pbm;
-	struct property *prop;
-	int len, i;
 
 	if (devhandle & 0x40)
 		pbm = &p->pbm_B;
@@ -1526,7 +1262,6 @@ static void pci_sun4v_pbm_init(struct pc
 
 	pbm->parent = p;
 	pbm->prom_node = dp;
-	pbm->pci_first_slot = 1;
 
 	pbm->devhandle = devhandle;
 
@@ -1534,39 +1269,17 @@ static void pci_sun4v_pbm_init(struct pc
 
 	printk("%s: SUN4V PCI Bus Module\n", pbm->name);
 
-	prop = of_find_property(dp, "ranges", &len);
-	pbm->pbm_ranges = prop->value;
-	pbm->num_pbm_ranges =
-		(len / sizeof(struct linux_prom_pci_ranges));
-
-	/* Mask out the top 8 bits of the ranges, leaving the real
-	 * physical address.
-	 */
-	for (i = 0; i < pbm->num_pbm_ranges; i++)
-		pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff;
-
-	pci_sun4v_determine_mem_io_space(pbm);
-	pbm_register_toplevel_resources(p, pbm);
-
-	prop = of_find_property(dp, "interrupt-map", &len);
-	pbm->pbm_intmap = prop->value;
-	pbm->num_pbm_intmap =
-		(len / sizeof(struct linux_prom_pci_intmap));
-
-	prop = of_find_property(dp, "interrupt-map-mask", NULL);
-	pbm->pbm_intmask = prop->value;
+	pci_determine_mem_io_space(pbm);
 
 	pci_sun4v_get_bus_range(pbm);
 	pci_sun4v_iommu_init(pbm);
 	pci_sun4v_msi_init(pbm);
-
-	pdev_htab_populate(pbm);
 }
 
 void sun4v_pci_init(struct device_node *dp, char *model_name)
 {
 	struct pci_controller_info *p;
-	struct pci_iommu *iommu;
+	struct iommu *iommu;
 	struct property *prop;
 	struct linux_prom64_registers *regs;
 	u32 devhandle;
@@ -1606,13 +1319,13 @@ void sun4v_pci_init(struct device_node *
 	if (!p)
 		goto fatal_memory_error;
 
-	iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
 	if (!iommu)
 		goto fatal_memory_error;
 
 	p->pbm_A.iommu = iommu;
 
-	iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+	iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
 	if (!iommu)
 		goto fatal_memory_error;
 
@@ -1622,11 +1335,8 @@ void sun4v_pci_init(struct device_node *
 	pci_controller_root = p;
 
 	p->index = pci_num_controllers++;
-	p->pbms_same_domain = 0;
 
 	p->scan_bus = pci_sun4v_scan_bus;
-	p->base_address_update = pci_sun4v_base_address_update;
-	p->resource_adjust = pci_sun4v_resource_adjust;
 #ifdef CONFIG_PCI_MSI
 	p->setup_msi_irq = pci_sun4v_setup_msi_irq;
 	p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index b291060..8e3c6e4 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -19,7 +19,6 @@ #include <linux/kernel.h>
 #include <linux/kallsyms.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
@@ -28,6 +27,7 @@ #include <linux/a.out.h>
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/compat.h>
+#include <linux/tick.h>
 #include <linux/init.h>
 
 #include <asm/oplib.h>
@@ -88,12 +88,14 @@ void cpu_idle(void)
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	while(1) {
-		if (need_resched()) {
-			preempt_enable_no_resched();
-			schedule();
-			preempt_disable();
-		}
-		sparc64_yield();
+		tick_nohz_stop_sched_tick();
+		while (!need_resched())
+			sparc64_yield();
+		tick_nohz_restart_sched_tick();
+
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
 	}
 }
 
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 0917c24..c54d4d8 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -36,12 +36,13 @@ static struct device_node *allnodes;
  */
 static DEFINE_RWLOCK(devtree_lock);
 
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+			    const char *compat)
 {
 	const char* cp;
 	int cplen, l;
 
-	cp = (char *) of_get_property(device, "compatible", &cplen);
+	cp = of_get_property(device, "compatible", &cplen);
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
@@ -154,13 +155,14 @@ struct device_node *of_find_compatible_n
 }
 EXPORT_SYMBOL(of_find_compatible_node);
 
-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;
 
 	for (pp = np->properties; pp != 0; pp = pp->next) {
-		if (strcmp(pp->name, name) == 0) {
+		if (strcasecmp(pp->name, name) == 0) {
 			if (lenp != 0)
 				*lenp = pp->length;
 			break;
@@ -174,7 +176,8 @@ EXPORT_SYMBOL(of_find_property);
  * Find a property with a given name for a given node
  * and return the value.
  */
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
+const void *of_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;
@@ -196,7 +199,7 @@ EXPORT_SYMBOL(of_getintprop_default);
 
 int of_n_addr_cells(struct device_node *np)
 {
-	int* ip;
+	const int* ip;
 	do {
 		if (np->parent)
 			np = np->parent;
@@ -211,7 +214,7 @@ EXPORT_SYMBOL(of_n_addr_cells);
 
 int of_n_size_cells(struct device_node *np)
 {
-	int* ip;
+	const int* ip;
 	do {
 		if (np->parent)
 			np = np->parent;
@@ -243,7 +246,7 @@ int of_set_property(struct device_node *
 	while (*prevp) {
 		struct property *prop = *prevp;
 
-		if (!strcmp(prop->name, name)) {
+		if (!strcasecmp(prop->name, name)) {
 			void *old_val = prop->value;
 			int ret;
 
@@ -383,11 +386,9 @@ static unsigned int psycho_irq_build(str
 
 	/* Now build the IRQ bucket. */
 	imap = controller_regs + imap_off;
-	imap += 4;
 
 	iclr_off = psycho_iclr_offset(ino);
 	iclr = controller_regs + iclr_off;
-	iclr += 4;
 
 	if ((ino & 0x20) == 0)
 		inofixup = ino & 0x03;
@@ -395,9 +396,9 @@ static unsigned int psycho_irq_build(str
 	return build_irq(inofixup, iclr, imap);
 }
 
-static void psycho_irq_trans_init(struct device_node *dp)
+static void __init psycho_irq_trans_init(struct device_node *dp)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = psycho_irq_build;
@@ -547,7 +548,7 @@ #define sabre_iclr_offset(ino)					     
 static int sabre_device_needs_wsync(struct device_node *dp)
 {
 	struct device_node *parent = dp->parent;
-	char *parent_model, *parent_compat;
+	const char *parent_model, *parent_compat;
 
 	/* This traversal up towards the root is meant to
 	 * handle two cases:
@@ -589,7 +590,7 @@ static unsigned int sabre_irq_build(stru
 {
 	struct sabre_irq_data *irq_data = _data;
 	unsigned long controller_regs = irq_data->controller_regs;
-	struct linux_prom_pci_registers *regs;
+	const struct linux_prom_pci_registers *regs;
 	unsigned long imap, iclr;
 	unsigned long imap_off, iclr_off;
 	int inofixup = 0;
@@ -610,11 +611,9 @@ static unsigned int sabre_irq_build(stru
 
 	/* Now build the IRQ bucket. */
 	imap = controller_regs + imap_off;
-	imap += 4;
 
 	iclr_off = sabre_iclr_offset(ino);
 	iclr = controller_regs + iclr_off;
-	iclr += 4;
 
 	if ((ino & 0x20) == 0)
 		inofixup = ino & 0x03;
@@ -637,11 +636,11 @@ static unsigned int sabre_irq_build(stru
 	return virt_irq;
 }
 
-static void sabre_irq_trans_init(struct device_node *dp)
+static void __init sabre_irq_trans_init(struct device_node *dp)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 	struct sabre_irq_data *irq_data;
-	u32 *busrange;
+	const u32 *busrange;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = sabre_irq_build;
@@ -676,13 +675,14 @@ static unsigned long schizo_iclr_offset(
 static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
 					unsigned int ino)
 {
-	return pbm_regs + schizo_iclr_offset(ino) + 4;
+
+	return pbm_regs + schizo_iclr_offset(ino);
 }
 
 static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
 					unsigned int ino)
 {
-	return pbm_regs + schizo_imap_offset(ino) + 4;
+	return pbm_regs + schizo_imap_offset(ino);
 }
 
 #define schizo_read(__reg) \
@@ -793,9 +793,10 @@ static unsigned int schizo_irq_build(str
 	return virt_irq;
 }
 
-static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
+static void __init __schizo_irq_trans_init(struct device_node *dp,
+					   int is_tomatillo)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 	struct schizo_irq_data *irq_data;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
@@ -815,12 +816,12 @@ static void __schizo_irq_trans_init(stru
 	irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
 }
 
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __init schizo_irq_trans_init(struct device_node *dp)
 {
 	__schizo_irq_trans_init(dp, 0);
 }
 
-static void tomatillo_irq_trans_init(struct device_node *dp)
+static void __init tomatillo_irq_trans_init(struct device_node *dp)
 {
 	__schizo_irq_trans_init(dp, 1);
 }
@@ -834,9 +835,9 @@ static unsigned int pci_sun4v_irq_build(
 	return sun4v_build_irq(devhandle, devino);
 }
 
-static void pci_sun4v_irq_trans_init(struct device_node *dp)
+static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = pci_sun4v_irq_build;
@@ -845,6 +846,85 @@ static void pci_sun4v_irq_trans_init(str
 	dp->irq_trans->data = (void *) (unsigned long)
 		((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
+
+struct fire_irq_data {
+	unsigned long pbm_regs;
+	u32 portid;
+};
+
+#define FIRE_IMAP_BASE	0x001000
+#define FIRE_ICLR_BASE	0x001400
+
+static unsigned long fire_imap_offset(unsigned long ino)
+{
+	return FIRE_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_iclr_offset(unsigned long ino)
+{
+	return FIRE_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
+					    unsigned int ino)
+{
+	return pbm_regs + fire_iclr_offset(ino);
+}
+
+static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
+					    unsigned int ino)
+{
+	return pbm_regs + fire_imap_offset(ino);
+}
+
+static unsigned int fire_irq_build(struct device_node *dp,
+					 unsigned int ino,
+					 void *_data)
+{
+	struct fire_irq_data *irq_data = _data;
+	unsigned long pbm_regs = irq_data->pbm_regs;
+	unsigned long imap, iclr;
+	unsigned long int_ctrlr;
+
+	ino &= 0x3f;
+
+	/* Now build the IRQ bucket. */
+	imap = fire_ino_to_imap(pbm_regs, ino);
+	iclr = fire_ino_to_iclr(pbm_regs, ino);
+
+	/* Set the interrupt controller number.  */
+	int_ctrlr = 1 << 6;
+	upa_writeq(int_ctrlr, imap);
+
+	/* The interrupt map registers do not have an INO field
+	 * like other chips do.  They return zero in the INO
+	 * field, and the interrupt controller number is controlled
+	 * in bits 6 thru 9.  So in order for build_irq() to get
+	 * the INO right we pass it in as part of the fixup
+	 * which will get added to the map register zero value
+	 * read by build_irq().
+	 */
+	ino |= (irq_data->portid << 6);
+	ino -= int_ctrlr;
+	return build_irq(ino, iclr, imap);
+}
+
+static void __init fire_irq_trans_init(struct device_node *dp)
+{
+	const struct linux_prom64_registers *regs;
+	struct fire_irq_data *irq_data;
+
+	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+	dp->irq_trans->irq_build = fire_irq_build;
+
+	irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
+
+	regs = of_get_property(dp, "reg", NULL);
+	dp->irq_trans->data = irq_data;
+
+	irq_data->pbm_regs = regs[0].phys_addr;
+	irq_data->portid = of_getintprop_default(dp, "portid", 0);
+}
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
@@ -940,7 +1020,7 @@ static unsigned int sbus_of_build_irq(st
 				      void *_data)
 {
 	unsigned long reg_base = (unsigned long) _data;
-	struct linux_prom_registers *regs;
+	const struct linux_prom_registers *regs;
 	unsigned long imap, iclr;
 	int sbus_slot = 0;
 	int sbus_level = 0;
@@ -992,9 +1072,9 @@ static unsigned int sbus_of_build_irq(st
 	return build_irq(sbus_level, iclr, imap);
 }
 
-static void sbus_irq_trans_init(struct device_node *dp)
+static void __init sbus_irq_trans_init(struct device_node *dp)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = sbus_of_build_irq;
@@ -1039,7 +1119,7 @@ static unsigned int central_build_irq(st
 	return build_irq(0, iclr, imap);
 }
 
-static void central_irq_trans_init(struct device_node *dp)
+static void __init central_irq_trans_init(struct device_node *dp)
 {
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = central_build_irq;
@@ -1053,7 +1133,7 @@ struct irq_trans {
 };
 
 #ifdef CONFIG_PCI
-static struct irq_trans pci_irq_trans_table[] = {
+static struct irq_trans __initdata pci_irq_trans_table[] = {
 	{ "SUNW,sabre", sabre_irq_trans_init },
 	{ "pci108e,a000", sabre_irq_trans_init },
 	{ "pci108e,a001", sabre_irq_trans_init },
@@ -1066,6 +1146,7 @@ static struct irq_trans pci_irq_trans_ta
 	{ "SUNW,tomatillo", tomatillo_irq_trans_init },
 	{ "pci108e,a801", tomatillo_irq_trans_init },
 	{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+	{ "pciex108e,80f0", fire_irq_trans_init },
 };
 #endif
 
@@ -1078,9 +1159,9 @@ static unsigned int sun4v_vdev_irq_build
 	return sun4v_build_irq(devhandle, devino);
 }
 
-static void sun4v_vdev_irq_trans_init(struct device_node *dp)
+static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
 {
-	struct linux_prom64_registers *regs;
+	const struct linux_prom64_registers *regs;
 
 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
 	dp->irq_trans->irq_build = sun4v_vdev_irq_build;
@@ -1090,7 +1171,7 @@ static void sun4v_vdev_irq_trans_init(st
 		((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
 
-static void irq_trans_init(struct device_node *dp)
+static void __init irq_trans_init(struct device_node *dp)
 {
 #ifdef CONFIG_PCI
 	const char *model;
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 14f78fb..3b05428 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -26,23 +26,9 @@ #include "iommu_common.h"
 
 #define MAP_BASE	((u32)0xc0000000)
 
-struct sbus_iommu_arena {
-	unsigned long	*map;
-	unsigned int	hint;
-	unsigned int	limit;
-};
-
-struct sbus_iommu {
-	spinlock_t		lock;
-
-	struct sbus_iommu_arena	arena;
-
-	iopte_t			*page_table;
-	unsigned long		strbuf_regs;
-	unsigned long		iommu_regs;
-	unsigned long		sbus_control_reg;
-
-	volatile unsigned long	strbuf_flushflag;
+struct sbus_info {
+	struct iommu	iommu;
+	struct strbuf	strbuf;
 };
 
 /* Offsets from iommu_regs */
@@ -58,16 +44,17 @@ #define IOMMU_DRAMDIAG	(0x4600UL - 0x240
 
 #define IOMMU_DRAM_VALID	(1UL << 30UL)
 
-static void __iommu_flushall(struct sbus_iommu *iommu)
+static void __iommu_flushall(struct iommu *iommu)
 {
-	unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+	unsigned long tag;
 	int entry;
 
+	tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
 	for (entry = 0; entry < 16; entry++) {
 		upa_writeq(0, tag);
 		tag += 8UL;
 	}
-	upa_readq(iommu->sbus_control_reg);
+	upa_readq(iommu->write_complete_reg);
 }
 
 /* Offsets from strbuf_regs */
@@ -82,15 +69,14 @@ #define STRBUF_LTAGDIAG	(0x5900UL - 0x28
 
 #define STRBUF_TAG_VALID	0x02UL
 
-static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction)
+static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction)
 {
 	unsigned long n;
 	int limit;
 
 	n = npages;
 	while (n--)
-		upa_writeq(base + (n << IO_PAGE_SHIFT),
-			   iommu->strbuf_regs + STRBUF_PFLUSH);
+		upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush);
 
 	/* If the device could not have possibly put dirty data into
 	 * the streaming cache, no flush-flag synchronization needs
@@ -99,15 +85,14 @@ static void sbus_strbuf_flush(struct sbu
 	if (direction == SBUS_DMA_TODEVICE)
 		return;
 
-	iommu->strbuf_flushflag = 0UL;
+	*(strbuf->strbuf_flushflag) = 0UL;
 
 	/* Whoopee cushion! */
-	upa_writeq(__pa(&iommu->strbuf_flushflag),
-		   iommu->strbuf_regs + STRBUF_FSYNC);
-	upa_readq(iommu->sbus_control_reg);
+	upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync);
+	upa_readq(iommu->write_complete_reg);
 
 	limit = 100000;
-	while (iommu->strbuf_flushflag == 0UL) {
+	while (*(strbuf->strbuf_flushflag) == 0UL) {
 		limit--;
 		if (!limit)
 			break;
@@ -121,9 +106,9 @@ static void sbus_strbuf_flush(struct sbu
 }
 
 /* Based largely upon the ppc64 iommu allocator.  */
-static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages)
+static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages)
 {
-	struct sbus_iommu_arena *arena = &iommu->arena;
+	struct iommu_arena *arena = &iommu->arena;
 	unsigned long n, i, start, end, limit;
 	int pass;
 
@@ -162,7 +147,7 @@ again:
 	return n;
 }
 
-static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages)
+static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
 {
 	unsigned long i;
 
@@ -170,7 +155,7 @@ static void sbus_arena_free(struct sbus_
 		__clear_bit(i, arena->map);
 }
 
-static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize)
+static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize)
 {
 	unsigned long tsbbase, order, sz, num_tsb_entries;
 
@@ -178,13 +163,14 @@ static void sbus_iommu_table_init(struct
 
 	/* Setup initial software IOMMU state. */
 	spin_lock_init(&iommu->lock);
+	iommu->page_table_map_base = MAP_BASE;
 
 	/* Allocate and initialize the free area map.  */
 	sz = num_tsb_entries / 8;
 	sz = (sz + 7UL) & ~7UL;
 	iommu->arena.map = kzalloc(sz, GFP_KERNEL);
 	if (!iommu->arena.map) {
-		prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
+		prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n");
 		prom_halt();
 	}
 	iommu->arena.limit = num_tsb_entries;
@@ -200,7 +186,7 @@ static void sbus_iommu_table_init(struct
 	memset(iommu->page_table, 0, tsbsize);
 }
 
-static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages)
+static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
 {
 	long entry;
 
@@ -211,14 +197,15 @@ static inline iopte_t *alloc_npages(stru
 	return iommu->page_table + entry;
 }
 
-static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages)
+static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
 {
 	sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
 }
 
 void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
 	iopte_t *iopte;
 	unsigned long flags, order, first_page;
 	void *ret;
@@ -234,7 +221,8 @@ void *sbus_alloc_consistent(struct sbus_
 		return NULL;
 	memset((char *)first_page, 0, PAGE_SIZE << order);
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 	iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
@@ -245,7 +233,7 @@ void *sbus_alloc_consistent(struct sbus_
 		return NULL;
 	}
 
-	*dvma_addr = (MAP_BASE +
+	*dvma_addr = (iommu->page_table_map_base +
 		      ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
 	ret = (void *) first_page;
 	npages = size >> IO_PAGE_SHIFT;
@@ -263,18 +251,20 @@ void *sbus_alloc_consistent(struct sbus_
 
 void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
 	iopte_t *iopte;
 	unsigned long flags, order, npages;
 
 	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
 	iopte = iommu->page_table +
-		((dvma - MAP_BASE) >> IO_PAGE_SHIFT);
+		((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
-	free_npages(iommu, dvma - MAP_BASE, npages);
+	free_npages(iommu, dvma - iommu->page_table_map_base, npages);
 
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
@@ -285,14 +275,16 @@ void sbus_free_consistent(struct sbus_de
 
 dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
 	iopte_t *base;
 	unsigned long flags, npages, oaddr;
 	unsigned long i, base_paddr;
 	u32 bus_addr, ret;
 	unsigned long iopte_protection;
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
 
 	if (unlikely(direction == SBUS_DMA_NONE))
 		BUG();
@@ -308,7 +300,7 @@ dma_addr_t sbus_map_single(struct sbus_d
 	if (unlikely(!base))
 		BUG();
 
-	bus_addr = (MAP_BASE +
+	bus_addr = (iommu->page_table_map_base +
 		    ((base - iommu->page_table) << IO_PAGE_SHIFT));
 	ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
 	base_paddr = __pa(oaddr & IO_PAGE_MASK);
@@ -325,7 +317,9 @@ dma_addr_t sbus_map_single(struct sbus_d
 
 void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
-	struct sbus_iommu *iommu = sdev->bus->iommu;
+	struct sbus_info *info = sdev->bus->iommu;
+	struct iommu *iommu = &info->iommu;
+	struct strbuf *strbuf = &info->strbuf;
 	iopte_t *base;
 	unsigned long flags, npages, i;
 
@@ -335,15 +329,15 @@ void sbus_unmap_single(struct sbus_dev *
 	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
 	base = iommu->page_table +
-		((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 	bus_addr &= IO_PAGE_MASK;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+	sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
 	for (i = 0; i < npages; i++)
 		iopte_val(base[i]) = 0UL;
-	free_npages(iommu, bus_addr - MAP_BASE, npages);
+	free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -425,7 +419,8 @@ static inline void fill_sg(iopte_t *iopt
 
 int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
 	unsigned long flags, npages, iopte_protection;
 	iopte_t *base;
 	u32 dma_base;
@@ -442,7 +437,8 @@ int sbus_map_sg(struct sbus_dev *sdev, s
 		return 1;
 	}
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
 
 	if (unlikely(direction == SBUS_DMA_NONE))
 		BUG();
@@ -456,7 +452,7 @@ int sbus_map_sg(struct sbus_dev *sdev, s
 	if (unlikely(base == NULL))
 		BUG();
 
-	dma_base = MAP_BASE +
+	dma_base = iommu->page_table_map_base +
 		((base - iommu->page_table) << IO_PAGE_SHIFT);
 
 	/* Normalize DVMA addresses. */
@@ -485,7 +481,9 @@ #endif
 
 void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	iopte_t *base;
 	unsigned long flags, i, npages;
 	u32 bus_addr;
@@ -493,7 +491,9 @@ void sbus_unmap_sg(struct sbus_dev *sdev
 	if (unlikely(direction == SBUS_DMA_NONE))
 		BUG();
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
+	strbuf = &info->strbuf;
 
 	bus_addr = sglist->dma_address & IO_PAGE_MASK;
 
@@ -505,29 +505,33 @@ void sbus_unmap_sg(struct sbus_dev *sdev
 		  bus_addr) >> IO_PAGE_SHIFT;
 
 	base = iommu->page_table +
-		((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);
+		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+	sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
 	for (i = 0; i < npages; i++)
 		iopte_val(base[i]) = 0UL;
-	free_npages(iommu, bus_addr - MAP_BASE, npages);
+	free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
 void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	unsigned long flags, npages;
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
+	strbuf = &info->strbuf;
 
 	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
 	bus_addr &= IO_PAGE_MASK;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+	sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -537,11 +541,15 @@ void sbus_dma_sync_single_for_device(str
 
 void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
 {
-	struct sbus_iommu *iommu;
+	struct sbus_info *info;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
 	unsigned long flags, npages, i;
 	u32 bus_addr;
 
-	iommu = sdev->bus->iommu;
+	info = sdev->bus->iommu;
+	iommu = &info->iommu;
+	strbuf = &info->strbuf;
 
 	bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
 	for (i = 0; i < nelems; i++) {
@@ -553,7 +561,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbu
 		  - bus_addr) >> IO_PAGE_SHIFT;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	sbus_strbuf_flush(iommu, bus_addr, npages, direction);
+	sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -564,12 +572,13 @@ void sbus_dma_sync_sg_for_device(struct 
 /* Enable 64-bit DVMA mode for the given device. */
 void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
 {
-	struct sbus_iommu *iommu = sdev->bus->iommu;
+	struct sbus_info *info = sdev->bus->iommu;
+	struct iommu *iommu = &info->iommu;
 	int slot = sdev->slot;
 	unsigned long cfg_reg;
 	u64 val;
 
-	cfg_reg = iommu->sbus_control_reg;
+	cfg_reg = iommu->write_complete_reg;
 	switch (slot) {
 	case 0:
 		cfg_reg += 0x20UL;
@@ -704,8 +713,9 @@ static unsigned long sysio_imap_to_iclr(
 unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
 {
 	struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
-	struct sbus_iommu *iommu = sbus->iommu;
-	unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+	struct sbus_info *info = sbus->iommu;
+	struct iommu *iommu = &info->iommu;
+	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long imap, iclr;
 	int sbus_level = 0;
 
@@ -766,8 +776,9 @@ #define  SYSIO_UEAFSR_RESV2 0x0000001fff
 static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 {
 	struct sbus_bus *sbus = dev_id;
-	struct sbus_iommu *iommu = sbus->iommu;
-	unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+	struct sbus_info *info = sbus->iommu;
+	struct iommu *iommu = &info->iommu;
+	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long afsr_reg, afar_reg;
 	unsigned long afsr, afar, error_bits;
 	int reported;
@@ -838,8 +849,9 @@ #define  SYSIO_CEAFSR_RESV2 0x0000001fff
 static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 {
 	struct sbus_bus *sbus = dev_id;
-	struct sbus_iommu *iommu = sbus->iommu;
-	unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+	struct sbus_info *info = sbus->iommu;
+	struct iommu *iommu = &info->iommu;
+	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned long afsr_reg, afar_reg;
 	unsigned long afsr, afar, error_bits;
 	int reported;
@@ -915,12 +927,13 @@ #define  SYSIO_SBAFSR_RESV3 0x0000001fff
 static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 {
 	struct sbus_bus *sbus = dev_id;
-	struct sbus_iommu *iommu = sbus->iommu;
+	struct sbus_info *info = sbus->iommu;
+	struct iommu *iommu = &info->iommu;
 	unsigned long afsr_reg, afar_reg, reg_base;
 	unsigned long afsr, afar, error_bits;
 	int reported;
 
-	reg_base = iommu->sbus_control_reg - 0x2000UL;
+	reg_base = iommu->write_complete_reg - 0x2000UL;
 	afsr_reg = reg_base + SYSIO_SBUS_AFSR;
 	afar_reg = reg_base + SYSIO_SBUS_AFAR;
 
@@ -982,8 +995,9 @@ #define SYSIO_SBUSERR_INO	0x36
 
 static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
 {
-	struct sbus_iommu *iommu = sbus->iommu;
-	unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
+	struct sbus_info *info = sbus->iommu;
+	struct iommu *iommu = &info->iommu;
+	unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
 	unsigned int irq;
 	u64 control;
 
@@ -1017,18 +1031,20 @@ static void __init sysio_register_error_
 		    SYSIO_ECNTRL_CEEN),
 		   reg_base + ECC_CONTROL);
 
-	control = upa_readq(iommu->sbus_control_reg);
+	control = upa_readq(iommu->write_complete_reg);
 	control |= 0x100UL; /* SBUS Error Interrupt Enable */
-	upa_writeq(control, iommu->sbus_control_reg);
+	upa_writeq(control, iommu->write_complete_reg);
 }
 
 /* Boot time initialization. */
 static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
 {
-	struct linux_prom64_registers *pr;
+	const struct linux_prom64_registers *pr;
 	struct device_node *dp;
-	struct sbus_iommu *iommu;
-	unsigned long regs;
+	struct sbus_info *info;
+	struct iommu *iommu;
+	struct strbuf *strbuf;
+	unsigned long regs, reg_base;
 	u64 control;
 	int i;
 
@@ -1043,33 +1059,42 @@ static void __init sbus_iommu_init(int _
 	}
 	regs = pr->phys_addr;
 
-	iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
-	if (iommu == NULL) {
-		prom_printf("sbus_iommu_init: Fatal error, kmalloc(iommu) failed\n");
+	info = kzalloc(sizeof(*info), GFP_ATOMIC);
+	if (info == NULL) {
+		prom_printf("sbus_iommu_init: Fatal error, "
+			    "kmalloc(info) failed\n");
 		prom_halt();
 	}
 
-	/* Align on E$ line boundary. */
-	iommu = (struct sbus_iommu *)
-		(((unsigned long)iommu + (SMP_CACHE_BYTES - 1UL)) &
-		 ~(SMP_CACHE_BYTES - 1UL));
+	iommu = &info->iommu;
+	strbuf = &info->strbuf;
 
-	memset(iommu, 0, sizeof(*iommu));
+	reg_base = regs + SYSIO_IOMMUREG_BASE;
+	iommu->iommu_control = reg_base + IOMMU_CONTROL;
+	iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE;
+	iommu->iommu_flush = reg_base + IOMMU_FLUSH;
 
-	/* Setup spinlock. */
-	spin_lock_init(&iommu->lock);
+	reg_base = regs + SYSIO_STRBUFREG_BASE;
+	strbuf->strbuf_control = reg_base + STRBUF_CONTROL;
+	strbuf->strbuf_pflush = reg_base + STRBUF_PFLUSH;
+	strbuf->strbuf_fsync = reg_base + STRBUF_FSYNC;
 
-	/* Init register offsets. */
-	iommu->iommu_regs = regs + SYSIO_IOMMUREG_BASE;
-	iommu->strbuf_regs = regs + SYSIO_STRBUFREG_BASE;
+	strbuf->strbuf_enabled = 1;
+
+	strbuf->strbuf_flushflag = (volatile unsigned long *)
+		((((unsigned long)&strbuf->__flushflag_buf[0])
+		  + 63UL)
+		 & ~63UL);
+	strbuf->strbuf_flushflag_pa = (unsigned long)
+		__pa(strbuf->strbuf_flushflag);
 
 	/* The SYSIO SBUS control register is used for dummy reads
 	 * in order to ensure write completion.
 	 */
-	iommu->sbus_control_reg = regs + 0x2000UL;
+	iommu->write_complete_reg = regs + 0x2000UL;
 
 	/* Link into SYSIO software state. */
-	sbus->iommu = iommu;
+	sbus->iommu = info;
 
 	printk("SYSIO: UPA portID %x, at %016lx\n",
 	       sbus->portid, regs);
@@ -1077,40 +1102,44 @@ static void __init sbus_iommu_init(int _
 	/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
 	sbus_iommu_table_init(iommu, IO_TSB_SIZE);
 
-	control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL);
+	control = upa_readq(iommu->iommu_control);
 	control = ((7UL << 16UL)	|
 		   (0UL << 2UL)		|
 		   (1UL << 1UL)		|
 		   (1UL << 0UL));
-	upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);
+	upa_writeq(control, iommu->iommu_control);
 
 	/* Clean out any cruft in the IOMMU using
 	 * diagnostic accesses.
 	 */
 	for (i = 0; i < 16; i++) {
-		unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
-		unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+		unsigned long dram, tag;
+
+		dram = iommu->iommu_control + (IOMMU_DRAMDIAG - IOMMU_CONTROL);
+		tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
 
 		dram += (unsigned long)i * 8UL;
 		tag += (unsigned long)i * 8UL;
 		upa_writeq(0, dram);
 		upa_writeq(0, tag);
 	}
-	upa_readq(iommu->sbus_control_reg);
+	upa_readq(iommu->write_complete_reg);
 
 	/* Give the TSB to SYSIO. */
-	upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE);
+	upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
 
 	/* Setup streaming buffer, DE=1 SB_EN=1 */
 	control = (1UL << 1UL) | (1UL << 0UL);
-	upa_writeq(control, iommu->strbuf_regs + STRBUF_CONTROL);
+	upa_writeq(control, strbuf->strbuf_control);
 
 	/* Clear out the tags using diagnostics. */
 	for (i = 0; i < 16; i++) {
 		unsigned long ptag, ltag;
 
-		ptag = iommu->strbuf_regs + STRBUF_PTAGDIAG;
-		ltag = iommu->strbuf_regs + STRBUF_LTAGDIAG;
+		ptag = strbuf->strbuf_control +
+			(STRBUF_PTAGDIAG - STRBUF_CONTROL);
+		ltag = strbuf->strbuf_control +
+			(STRBUF_LTAGDIAG - STRBUF_CONTROL);
 		ptag += (unsigned long)i * 8UL;
 		ltag += (unsigned long)i * 8UL;
 
@@ -1119,9 +1148,9 @@ static void __init sbus_iommu_init(int _
 	}
 
 	/* Enable DVMA arbitration for all devices/slots. */
-	control = upa_readq(iommu->sbus_control_reg);
+	control = upa_readq(iommu->write_complete_reg);
 	control |= 0x3fUL;
-	upa_writeq(control, iommu->sbus_control_reg);
+	upa_writeq(control, iommu->write_complete_reg);
 
 	/* Now some Xfire specific grot... */
 	if (this_is_starfire)
@@ -1133,7 +1162,7 @@ static void __init sbus_iommu_init(int _
 void sbus_fill_device_irq(struct sbus_dev *sdev)
 {
 	struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
-	struct linux_prom_irqs *irqs;
+	const struct linux_prom_irqs *irqs;
 
 	irqs = of_get_property(dp, "interrupts", NULL);
 	if (!irqs) {
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 96d56a8..203e873 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -20,7 +20,6 @@ #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
-#include <linux/smp_lock.h>
 #include <linux/binfmts.h>
 #include <linux/bitops.h>
 
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index c45f21b..8c1c121 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -17,7 +17,6 @@ #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
-#include <linux/smp_lock.h>
 #include <linux/binfmts.h>
 #include <linux/compat.h>
 #include <linux/bitops.h>
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index fc99f7b..8087d67 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -10,7 +10,6 @@ #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
@@ -45,7 +44,7 @@ #include <asm/prom.h>
 extern void calibrate_delay(void);
 
 /* Please don't make this stuff initdata!!!  --DaveM */
-static unsigned char boot_cpu_id;
+unsigned char boot_cpu_id;
 
 cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
 cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
@@ -81,8 +80,6 @@ void __init smp_store_cpu_info(int id)
 	struct device_node *dp;
 	int def;
 
-	/* multiplier and counter set by
-	   smp_setup_percpu_timer()  */
 	cpu_data(id).udelay_val			= loops_per_jiffy;
 
 	cpu_find_by_mid(id, &dp);
@@ -125,7 +122,7 @@ void __init smp_store_cpu_info(int id)
 	       cpu_data(id).ecache_size, cpu_data(id).ecache_line_size);
 }
 
-static void smp_setup_percpu_timer(void);
+extern void setup_sparc64_timer(void);
 
 static volatile unsigned long callin_flag = 0;
 
@@ -140,7 +137,7 @@ void __init smp_callin(void)
 
 	__flush_tlb_all();
 
-	smp_setup_percpu_timer();
+	setup_sparc64_timer();
 
 	if (cheetah_pcache_forced_on)
 		cheetah_enable_pcache();
@@ -177,8 +174,6 @@ void cpu_panic(void)
 	panic("SMP bolixed\n");
 }
 
-static unsigned long current_tick_offset __read_mostly;
-
 /* This tick register synchronization scheme is taken entirely from
  * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
  *
@@ -261,7 +256,7 @@ #endif
 				} else
 					adj = -delta;
 
-				tick_ops->add_tick(adj, current_tick_offset);
+				tick_ops->add_tick(adj);
 			}
 #if DEBUG_TICK_SYNC
 			t[i].rt = rt;
@@ -1180,117 +1175,15 @@ void smp_penguin_jailcell(int irq, struc
 	preempt_enable();
 }
 
-#define prof_multiplier(__cpu)		cpu_data(__cpu).multiplier
-#define prof_counter(__cpu)		cpu_data(__cpu).counter
-
-void smp_percpu_timer_interrupt(struct pt_regs *regs)
-{
-	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.
-	 */
-	{
-		unsigned long tick_mask = tick_ops->softint_mask;
-
-		if (!(get_softint() & tick_mask)) {
-			extern void handler_irq(int, struct pt_regs *);
-
-			handler_irq(14, regs);
-			return;
-		}
-		clear_softint(tick_mask);
-	}
-
-	old_regs = set_irq_regs(regs);
-	do {
-		profile_tick(CPU_PROFILING);
-		if (!--prof_counter(cpu)) {
-			irq_enter();
-
-			if (cpu == boot_cpu_id) {
-				kstat_this_cpu.irqs[0]++;
-				timer_tick_interrupt(regs);
-			}
-
-			update_process_times(user);
-
-			irq_exit();
-
-			prof_counter(cpu) = prof_multiplier(cpu);
-		}
-
-		/* Guarantee that the following sequences execute
-		 * uninterrupted.
-		 */
-		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-				     "wrpr	%0, %1, %%pstate"
-				     : "=r" (pstate)
-				     : "i" (PSTATE_IE));
-
-		compare = tick_ops->add_compare(current_tick_offset);
-		tick = tick_ops->get_tick();
-
-		/* Restore PSTATE_IE. */
-		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-				     : /* no outputs */
-				     : "r" (pstate));
-	} while (time_after_eq(tick, compare));
-	set_irq_regs(old_regs);
-}
-
-static void __init smp_setup_percpu_timer(void)
-{
-	int cpu = smp_processor_id();
-	unsigned long pstate;
-
-	prof_counter(cpu) = prof_multiplier(cpu) = 1;
-
-	/* Guarantee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	tick_ops->init_tick(current_tick_offset);
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-}
-
 void __init smp_tick_init(void)
 {
 	boot_cpu_id = hard_smp_processor_id();
-	current_tick_offset = timer_tick_offset;
-
-	prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
 }
 
 /* /proc/profile writes can call this, don't __init it please. */
-static DEFINE_SPINLOCK(prof_setup_lock);
-
 int setup_profiling_timer(unsigned int multiplier)
 {
-	unsigned long flags;
-	int i;
-
-	if ((!multiplier) || (timer_tick_offset / multiplier) < 1000)
-		return -EINVAL;
-
-	spin_lock_irqsave(&prof_setup_lock, flags);
-	for_each_possible_cpu(i)
-		prof_multiplier(i) = multiplier;
-	current_tick_offset = (timer_tick_offset / multiplier);
-	spin_unlock_irqrestore(&prof_setup_lock, flags);
-
-	return 0;
+	return -EINVAL;
 }
 
 static void __init smp_tune_scheduling(void)
@@ -1449,11 +1342,11 @@ void __init setup_per_cpu_areas(void)
 	/* Copy section for each CPU (we discard the original) */
 	goal = PERCPU_ENOUGH_ROOM;
 
-	__per_cpu_shift = 0;
-	for (size = 1UL; size < goal; size <<= 1UL)
+	__per_cpu_shift = PAGE_SHIFT;
+	for (size = PAGE_SIZE; size < goal; size <<= 1UL)
 		__per_cpu_shift++;
 
-	ptr = alloc_bootmem(size * NR_CPUS);
+	ptr = alloc_bootmem_pages(size * NR_CPUS);
 
 	__per_cpu_base = ptr - __per_cpu_start;
 
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index beffc82..d00f51a 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -212,7 +212,6 @@ EXPORT_SYMBOL(insl);
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(isa_chain);
-EXPORT_SYMBOL(pci_memspace_mask);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
index c4d15f2..47f92a5 100644
--- a/arch/sparc64/kernel/stacktrace.c
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -3,22 +3,16 @@ #include <linux/stacktrace.h>
 #include <linux/thread_info.h>
 #include <asm/ptrace.h>
 
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
 	unsigned long ksp, fp, thread_base;
-	struct thread_info *tp;
+	struct thread_info *tp = task_thread_info(current);
 
-	if (!task)
-		task = current;
-	tp = task_thread_info(task);
-	if (task == current) {
-		flushw_all();
-		__asm__ __volatile__(
-			"mov	%%fp, %0"
-			: "=r" (ksp)
-		);
-	} else
-		ksp = tp->ksp;
+	flushw_all();
+	__asm__ __volatile__(
+		"mov	%%fp, %0"
+		: "=r" (ksp)
+	);
 
 	fp = ksp + STACK_BIAS;
 	thread_base = (unsigned long) tp;
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
index a05e43d..75d2bad 100644
--- a/arch/sparc64/kernel/sunos_ioctl32.c
+++ b/arch/sparc64/kernel/sunos_ioctl32.c
@@ -22,7 +22,6 @@ #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
 
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index a53d4ab..d108eeb 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -19,7 +19,6 @@ #include <linux/stat.h>
 #include <linux/mman.h>
 #include <linux/utsname.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 #include <linux/ipc.h>
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 7876a02..692e46a 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -775,15 +775,25 @@ asmlinkage long sys32_settimeofday(struc
 asmlinkage long sys32_utimes(char __user *filename,
 			     struct compat_timeval __user *tvs)
 {
-	struct timeval ktvs[2];
+	struct timespec tv[2];
 
 	if (tvs) {
+		struct timeval ktvs[2];
 		if (get_tv32(&ktvs[0], tvs) ||
 		    get_tv32(&ktvs[1], 1+tvs))
 			return -EFAULT;
+
+		if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
+		    ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
+			return -EINVAL;
+
+		tv[0].tv_sec = ktvs[0].tv_sec;
+		tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
+		tv[1].tv_sec = ktvs[1].tv_sec;
+		tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
 	}
 
-	return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
+	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL);
 }
 
 /* These are here just in case some old sparc32 binary calls it. */
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index f84da4f..259063f 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -31,6 +31,9 @@ #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/miscdevice.h>
 #include <linux/rtc.h>
+#include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -60,6 +63,7 @@ static void __iomem *mstk48t59_regs;
 static int set_rtc_mmss(unsigned long);
 
 #define TICK_PRIV_BIT	(1UL << 63)
+#define TICKCMP_IRQ_BIT	(1UL << 63)
 
 #ifdef CONFIG_SMP
 unsigned long profile_pc(struct pt_regs *regs)
@@ -93,21 +97,22 @@ static void tick_disable_protection(void
 	: "g2");
 }
 
-static void tick_init_tick(unsigned long offset)
+static void tick_disable_irq(void)
 {
-	tick_disable_protection();
-
 	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	andn	%%g1, %1, %%g1\n"
 	"	ba,pt	%%xcc, 1f\n"
-	"	 add	%%g1, %0, %%g1\n"
+	"	 nop\n"
 	"	.align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
+	"1:	wr	%0, 0x0, %%tick_cmpr\n"
 	"	rd	%%tick_cmpr, %%g0"
 	: /* no outputs */
-	: "r" (offset), "r" (TICK_PRIV_BIT)
-	: "g1");
+	: "r" (TICKCMP_IRQ_BIT));
+}
+
+static void tick_init_tick(void)
+{
+	tick_disable_protection();
+	tick_disable_irq();
 }
 
 static unsigned long tick_get_tick(void)
@@ -121,20 +126,14 @@ static unsigned long tick_get_tick(void)
 	return ret & ~TICK_PRIV_BIT;
 }
 
-static unsigned long tick_get_compare(void)
+static int tick_add_compare(unsigned long adj)
 {
-	unsigned long ret;
+	unsigned long orig_tick, new_tick, new_compare;
 
-	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-			     "mov	%0, %0"
-			     : "=r" (ret));
+	__asm__ __volatile__("rd	%%tick, %0"
+			     : "=r" (orig_tick));
 
-	return ret;
-}
-
-static unsigned long tick_add_compare(unsigned long adj)
-{
-	unsigned long new_compare;
+	orig_tick &= ~TICKCMP_IRQ_BIT;
 
 	/* Workaround for Spitfire Errata (#54 I think??), I discovered
 	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
@@ -145,44 +144,41 @@ static unsigned long tick_add_compare(un
 	 * at the start of an I-cache line, and perform a dummy
 	 * read back from %tick_cmpr right after writing to it. -DaveM
 	 */
-	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-			     "ba,pt	%%xcc, 1f\n\t"
-			     " add	%0, %1, %0\n\t"
+	__asm__ __volatile__("ba,pt	%%xcc, 1f\n\t"
+			     " add	%1, %2, %0\n\t"
 			     ".align	64\n"
 			     "1:\n\t"
 			     "wr	%0, 0, %%tick_cmpr\n\t"
-			     "rd	%%tick_cmpr, %%g0"
-			     : "=&r" (new_compare)
-			     : "r" (adj));
+			     "rd	%%tick_cmpr, %%g0\n\t"
+			     : "=r" (new_compare)
+			     : "r" (orig_tick), "r" (adj));
 
-	return new_compare;
+	__asm__ __volatile__("rd	%%tick, %0"
+			     : "=r" (new_tick));
+	new_tick &= ~TICKCMP_IRQ_BIT;
+
+	return ((long)(new_tick - (orig_tick+adj))) > 0L;
 }
 
-static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
+static unsigned long tick_add_tick(unsigned long adj)
 {
-	unsigned long new_tick, tmp;
+	unsigned long new_tick;
 
 	/* Also need to handle Blackbird bug here too. */
 	__asm__ __volatile__("rd	%%tick, %0\n\t"
-			     "add	%0, %2, %0\n\t"
+			     "add	%0, %1, %0\n\t"
 			     "wrpr	%0, 0, %%tick\n\t"
-			     "andn	%0, %4, %1\n\t"
-			     "ba,pt	%%xcc, 1f\n\t"
-			     " add	%1, %3, %1\n\t"
-			     ".align	64\n"
-			     "1:\n\t"
-			     "wr	%1, 0, %%tick_cmpr\n\t"
-			     "rd	%%tick_cmpr, %%g0"
-			     : "=&r" (new_tick), "=&r" (tmp)
-			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+			     : "=&r" (new_tick)
+			     : "r" (adj));
 
 	return new_tick;
 }
 
 static struct sparc64_tick_ops tick_operations __read_mostly = {
+	.name		=	"tick",
 	.init_tick	=	tick_init_tick,
+	.disable_irq	=	tick_disable_irq,
 	.get_tick	=	tick_get_tick,
-	.get_compare	=	tick_get_compare,
 	.add_tick	=	tick_add_tick,
 	.add_compare	=	tick_add_compare,
 	.softint_mask	=	1UL << 0,
@@ -190,7 +186,15 @@ static struct sparc64_tick_ops tick_oper
 
 struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations;
 
-static void stick_init_tick(unsigned long offset)
+static void stick_disable_irq(void)
+{
+	__asm__ __volatile__(
+	"wr	%0, 0x0, %%asr25"
+	: /* no outputs */
+	: "r" (TICKCMP_IRQ_BIT));
+}
+
+static void stick_init_tick(void)
 {
 	/* Writes to the %tick and %stick register are not
 	 * allowed on sun4v.  The Hypervisor controls that
@@ -198,6 +202,7 @@ static void stick_init_tick(unsigned lon
 	 */
 	if (tlb_type != hypervisor) {
 		tick_disable_protection();
+		tick_disable_irq();
 
 		/* Let the user get at STICK too. */
 		__asm__ __volatile__(
@@ -209,14 +214,7 @@ static void stick_init_tick(unsigned lon
 		: "g1", "g2");
 	}
 
-	__asm__ __volatile__(
-	"	rd	%%asr24, %%g1\n"
-	"	andn	%%g1, %1, %%g1\n"
-	"	add	%%g1, %0, %%g1\n"
-	"	wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (offset), "r" (TICK_PRIV_BIT)
-	: "g1");
+	stick_disable_irq();
 }
 
 static unsigned long stick_get_tick(void)
@@ -229,49 +227,43 @@ static unsigned long stick_get_tick(void
 	return ret & ~TICK_PRIV_BIT;
 }
 
-static unsigned long stick_get_compare(void)
+static unsigned long stick_add_tick(unsigned long adj)
 {
-	unsigned long ret;
-
-	__asm__ __volatile__("rd	%%asr25, %0"
-			     : "=r" (ret));
-
-	return ret;
-}
-
-static unsigned long stick_add_tick(unsigned long adj, unsigned long offset)
-{
-	unsigned long new_tick, tmp;
+	unsigned long new_tick;
 
 	__asm__ __volatile__("rd	%%asr24, %0\n\t"
-			     "add	%0, %2, %0\n\t"
+			     "add	%0, %1, %0\n\t"
 			     "wr	%0, 0, %%asr24\n\t"
-			     "andn	%0, %4, %1\n\t"
-			     "add	%1, %3, %1\n\t"
-			     "wr	%1, 0, %%asr25"
-			     : "=&r" (new_tick), "=&r" (tmp)
-			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+			     : "=&r" (new_tick)
+			     : "r" (adj));
 
 	return new_tick;
 }
 
-static unsigned long stick_add_compare(unsigned long adj)
+static int stick_add_compare(unsigned long adj)
 {
-	unsigned long new_compare;
+	unsigned long orig_tick, new_tick;
 
-	__asm__ __volatile__("rd	%%asr25, %0\n\t"
-			     "add	%0, %1, %0\n\t"
-			     "wr	%0, 0, %%asr25"
-			     : "=&r" (new_compare)
-			     : "r" (adj));
+	__asm__ __volatile__("rd	%%asr24, %0"
+			     : "=r" (orig_tick));
+	orig_tick &= ~TICKCMP_IRQ_BIT;
+
+	__asm__ __volatile__("wr	%0, 0, %%asr25"
+			     : /* no outputs */
+			     : "r" (orig_tick + adj));
+
+	__asm__ __volatile__("rd	%%asr24, %0"
+			     : "=r" (new_tick));
+	new_tick &= ~TICKCMP_IRQ_BIT;
 
-	return new_compare;
+	return ((long)(new_tick - (orig_tick+adj))) > 0L;
 }
 
 static struct sparc64_tick_ops stick_operations __read_mostly = {
+	.name		=	"stick",
 	.init_tick	=	stick_init_tick,
+	.disable_irq	=	stick_disable_irq,
 	.get_tick	=	stick_get_tick,
-	.get_compare	=	stick_get_compare,
 	.add_tick	=	stick_add_tick,
 	.add_compare	=	stick_add_compare,
 	.softint_mask	=	1UL << 16,
@@ -320,20 +312,6 @@ static unsigned long __hbird_read_stick(
 	return ret;
 }
 
-static unsigned long __hbird_read_compare(void)
-{
-	unsigned long low, high;
-	unsigned long addr = HBIRD_STICKCMP_ADDR;
-
-	__asm__ __volatile__("ldxa	[%2] %3, %0\n\t"
-			     "add	%2, 0x8, %2\n\t"
-			     "ldxa	[%2] %3, %1"
-			     : "=&r" (low), "=&r" (high), "=&r" (addr)
-			     : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));
-
-	return (high << 32UL) | low;
-}
-
 static void __hbird_write_stick(unsigned long val)
 {
 	unsigned long low = (val & 0xffffffffUL);
@@ -364,10 +342,13 @@ static void __hbird_write_compare(unsign
 			       "i" (ASI_PHYS_BYPASS_EC_E));
 }
 
-static void hbtick_init_tick(unsigned long offset)
+static void hbtick_disable_irq(void)
 {
-	unsigned long val;
+	__hbird_write_compare(TICKCMP_IRQ_BIT);
+}
 
+static void hbtick_init_tick(void)
+{
 	tick_disable_protection();
 
 	/* XXX This seems to be necessary to 'jumpstart' Hummingbird
@@ -377,8 +358,7 @@ static void hbtick_init_tick(unsigned lo
 	 */
 	__hbird_write_stick(__hbird_read_stick());
 
-	val = __hbird_read_stick() & ~TICK_PRIV_BIT;
-	__hbird_write_compare(val + offset);
+	hbtick_disable_irq();
 }
 
 static unsigned long hbtick_get_tick(void)
@@ -386,122 +366,95 @@ static unsigned long hbtick_get_tick(voi
 	return __hbird_read_stick() & ~TICK_PRIV_BIT;
 }
 
-static unsigned long hbtick_get_compare(void)
-{
-	return __hbird_read_compare();
-}
-
-static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset)
+static unsigned long hbtick_add_tick(unsigned long adj)
 {
 	unsigned long val;
 
 	val = __hbird_read_stick() + adj;
 	__hbird_write_stick(val);
 
-	val &= ~TICK_PRIV_BIT;
-	__hbird_write_compare(val + offset);
-
 	return val;
 }
 
-static unsigned long hbtick_add_compare(unsigned long adj)
+static int hbtick_add_compare(unsigned long adj)
 {
-	unsigned long val = __hbird_read_compare() + adj;
+	unsigned long val = __hbird_read_stick();
+	unsigned long val2;
 
-	val &= ~TICK_PRIV_BIT;
+	val &= ~TICKCMP_IRQ_BIT;
+	val += adj;
 	__hbird_write_compare(val);
 
-	return val;
+	val2 = __hbird_read_stick() & ~TICKCMP_IRQ_BIT;
+
+	return ((long)(val2 - val)) > 0L;
 }
 
 static struct sparc64_tick_ops hbtick_operations __read_mostly = {
+	.name		=	"hbtick",
 	.init_tick	=	hbtick_init_tick,
+	.disable_irq	=	hbtick_disable_irq,
 	.get_tick	=	hbtick_get_tick,
-	.get_compare	=	hbtick_get_compare,
 	.add_tick	=	hbtick_add_tick,
 	.add_compare	=	hbtick_add_compare,
 	.softint_mask	=	1UL << 0,
 };
 
-/* timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- *
- * NOTE: On SUN5 systems the ticker interrupt comes in using 2
- *       interrupts, one at level14 and one with softint bit 0.
- */
-unsigned long timer_tick_offset __read_mostly;
-
 static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-static inline void timer_check_rtc(void)
-{
-	/* last time the cmos clock got updated */
-	static long last_rtc_update;
-
-	/* Determine when to update the Mostek clock. */
-	if (ntp_synced() &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
-	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600;
-			/* do it again in 60 s */
-	}
-}
+#define USEC_AFTER	500000
+#define USEC_BEFORE	500000
 
-irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-	unsigned long ticks, compare, pstate;
+static void sync_cmos_clock(unsigned long dummy);
 
-	write_seqlock(&xtime_lock);
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
 
-	do {
-#ifndef CONFIG_SMP
-		profile_tick(CPU_PROFILING);
-		update_process_times(user_mode(get_irq_regs()));
-#endif
-		do_timer(1);
+static void sync_cmos_clock(unsigned long dummy)
+{
+	struct timeval now, next;
+	int fail = 1;
 
-		/* Guarantee that the following sequences execute
-		 * uninterrupted.
+	/*
+	 * 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).
 		 */
-		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-				     "wrpr	%0, %1, %%pstate"
-				     : "=r" (pstate)
-				     : "i" (PSTATE_IE));
+		return;
 
-		compare = tick_ops->add_compare(timer_tick_offset);
-		ticks = tick_ops->get_tick();
+	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);
 
-		/* Restore PSTATE_IE. */
-		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-				     : /* no outputs */
-				     : "r" (pstate));
-	} while (time_after_eq(ticks, compare));
+	next.tv_usec = USEC_AFTER - now.tv_usec;
+	if (next.tv_usec <= 0)
+		next.tv_usec += USEC_PER_SEC;
 
-	timer_check_rtc();
+	if (!fail)
+		next.tv_sec = 659;
+	else
+		next.tv_sec = 0;
 
-	write_sequnlock(&xtime_lock);
-
-	return IRQ_HANDLED;
+	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));
 }
 
-#ifdef CONFIG_SMP
-void timer_tick_interrupt(struct pt_regs *regs)
+void notify_arch_cmos_timer(void)
 {
-	write_seqlock(&xtime_lock);
-
-	do_timer(1);
-
-	timer_check_rtc();
-
-	write_sequnlock(&xtime_lock);
+	mod_timer(&sync_cmos_timer, jiffies + 1);
 }
-#endif
 
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
 static void __init kick_start_clock(void)
@@ -751,7 +704,7 @@ retry:
 	return -EOPNOTSUPP;
 }
 
-static int __init clock_model_matches(char *model)
+static int __init clock_model_matches(const char *model)
 {
 	if (strcmp(model, "mk48t02") &&
 	    strcmp(model, "mk48t08") &&
@@ -768,7 +721,7 @@ static int __init clock_model_matches(ch
 static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	char *model = of_get_property(dp, "model", NULL);
+	const char *model = of_get_property(dp, "model", NULL);
 	unsigned long size, flags;
 	void __iomem *regs;
 
@@ -900,7 +853,6 @@ #endif
 		prop = of_find_property(dp, "stick-frequency", NULL);
 	}
 	clock = *(unsigned int *) prop->value;
-	timer_tick_offset = clock / HZ;
 
 #ifdef CONFIG_SMP
 	smp_tick_init();
@@ -909,26 +861,6 @@ #endif
 	return clock;
 }
 
-static void sparc64_start_timers(void)
-{
-	unsigned long pstate;
-
-	/* Guarantee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	tick_ops->init_tick(timer_tick_offset);
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-}
-
 struct freq_table {
 	unsigned long clock_tick_ref;
 	unsigned int ref_freq;
@@ -975,29 +907,148 @@ static struct notifier_block sparc64_cpu
 
 #endif /* CONFIG_CPU_FREQ */
 
-static struct time_interpolator sparc64_cpu_interpolator = {
-	.source		=	TIME_SOURCE_CPU,
-	.shift		=	16,
-	.mask		=	0xffffffffffffffffLL
+static int sparc64_next_event(unsigned long delta,
+			      struct clock_event_device *evt)
+{
+	return tick_ops->add_compare(delta) ? -ETIME : 0;
+}
+
+static void sparc64_timer_setup(enum clock_event_mode mode,
+				struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+		break;
+
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		tick_ops->disable_irq();
+		break;
+
+	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_UNUSED:
+		WARN_ON(1);
+		break;
+	};
+}
+
+static struct clock_event_device sparc64_clockevent = {
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= sparc64_timer_setup,
+	.set_next_event	= sparc64_next_event,
+	.rating		= 100,
+	.shift		= 30,
+	.irq		= -1,
 };
+static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
 
-/* The quotient formula is taken from the IA64 port. */
-#define SPARC64_NSEC_PER_CYC_SHIFT	10UL
-void __init time_init(void)
+void timer_interrupt(int irq, struct pt_regs *regs)
 {
-	unsigned long clock = sparc64_init_timers();
+	struct pt_regs *old_regs = set_irq_regs(regs);
+	unsigned long tick_mask = tick_ops->softint_mask;
+	int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(sparc64_events, cpu);
+
+	clear_softint(tick_mask);
+
+	irq_enter();
 
-	sparc64_cpu_interpolator.frequency = clock;
-	register_time_interpolator(&sparc64_cpu_interpolator);
+	kstat_this_cpu.irqs[0]++;
 
-	/* Now that the interpolator is registered, it is
-	 * safe to start the timer ticking.
+	if (unlikely(!evt->event_handler)) {
+		printk(KERN_WARNING
+		       "Spurious SPARC64 timer interrupt on cpu %d\n", cpu);
+	} else
+		evt->event_handler(evt);
+
+	irq_exit();
+
+	set_irq_regs(old_regs);
+}
+
+void __devinit setup_sparc64_timer(void)
+{
+	struct clock_event_device *sevt;
+	unsigned long pstate;
+
+	/* Guarantee that the following sequences execute
+	 * uninterrupted.
 	 */
-	sparc64_start_timers();
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	tick_ops->init_tick();
+
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
+	sevt = &__get_cpu_var(sparc64_events);
+
+	memcpy(sevt, &sparc64_clockevent, sizeof(*sevt));
+	sevt->cpumask = cpumask_of_cpu(smp_processor_id());
+
+	clockevents_register_device(sevt);
+}
+
+#define SPARC64_NSEC_PER_CYC_SHIFT	32UL
+
+static struct clocksource clocksource_tick = {
+	.rating		= 100,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.shift		= 16,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init setup_clockevent_multiplier(unsigned long hz)
+{
+	unsigned long mult, shift = 32;
+
+	while (1) {
+		mult = div_sc(hz, NSEC_PER_SEC, shift);
+		if (mult && (mult >> 32UL) == 0UL)
+			break;
+
+		shift--;
+	}
+
+	sparc64_clockevent.shift = shift;
+	sparc64_clockevent.mult = mult;
+}
+
+void __init time_init(void)
+{
+	unsigned long clock = sparc64_init_timers();
 
 	timer_ticks_per_nsec_quotient =
-		(((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) +
-		  (clock / 2)) / clock);
+		clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+
+	clocksource_tick.name = tick_ops->name;
+	clocksource_tick.mult =
+		clocksource_hz2mult(clock,
+				    clocksource_tick.shift);
+	clocksource_tick.read = tick_ops->get_tick;
+
+	printk("clocksource: mult[%x] shift[%d]\n",
+	       clocksource_tick.mult, clocksource_tick.shift);
+
+	clocksource_register(&clocksource_tick);
+
+	sparc64_clockevent.name = tick_ops->name;
+
+	setup_clockevent_multiplier(clock);
+
+	sparc64_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x7fffffffffffffff, &sparc64_clockevent);
+	sparc64_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xF, &sparc64_clockevent);
+
+	printk("clockevent: mult[%lx] shift[%d]\n",
+	       sparc64_clockevent.mult, sparc64_clockevent.shift);
+
+	setup_sparc64_timer();
 
 #ifdef CONFIG_CPU_FREQ
 	cpufreq_register_notifier(&sparc64_cpufreq_notifier_block,
@@ -1126,10 +1177,6 @@ #endif
 #define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
 static unsigned char mini_rtc_status;	/* bitmapped status byte.	*/
 
-/* months start at 0 now */
-static unsigned char days_in_mo[] =
-{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
 #define FEBRUARY	2
 #define	STARTOFTIME	1970
 #define SECDAY		86400L
@@ -1278,8 +1325,7 @@ static int mini_rtc_ioctl(struct inode *
 
 	case RTC_SET_TIME:	/* Set the RTC */
 	    {
-		int year;
-		unsigned char leap_yr;
+		int year, days;
 
 		if (!capable(CAP_SYS_TIME))
 			return -EACCES;
@@ -1288,14 +1334,14 @@ static int mini_rtc_ioctl(struct inode *
 			return -EFAULT;
 
 		year = wtime.tm_year + 1900;
-		leap_yr = ((!(year % 4) && (year % 100)) ||
-			   !(year % 400));
+		days = month_days[wtime.tm_mon] +
+		       ((wtime.tm_mon == 1) && leapyear(year));
 
-		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
+		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
+		    (wtime.tm_mday < 1))
 			return -EINVAL;
 
-		if (wtime.tm_mday < 0 || wtime.tm_mday >
-		    (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
+		if (wtime.tm_mday < 0 || wtime.tm_mday > days)
 			return -EINVAL;
 
 		if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index ad67784..dc652f2 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -15,9 +15,9 @@ #include <linux/kernel.h>
 #include <linux/kallsyms.h>
 #include <linux/signal.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/kdebug.h>
 
 #include <asm/delay.h>
 #include <asm/system.h>
@@ -36,26 +36,12 @@ #include <asm/sfafsr.h>
 #include <asm/psrcompat.h>
 #include <asm/processor.h>
 #include <asm/timer.h>
-#include <asm/kdebug.h>
 #include <asm/head.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
 #include <asm/prom.h>
 
-ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
 
 /* When an irrecoverable trap occurs at tl > 0, the trap entry
  * code logs the trap state registers at every level in the trap
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index d7d2a8b..7575aa3 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -60,11 +60,7 @@ #endif
 tl0_irq5:	TRAP_IRQ(handler_irq, 5)
 tl0_irq6:	BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
 tl0_irq10:	BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d)
-#ifndef CONFIG_SMP
-tl0_irq14:	TRAP_IRQ(timer_irq, 14)
-#else
-tl0_irq14:	TICK_SMP_IRQ
-#endif
+tl0_irq14:	TRAP_IRQ(timer_interrupt, 14)
 tl0_irq15:	TRAP_IRQ(handler_irq, 15)
 tl0_resv050:	BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:	BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index bc18d48..953be81 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -18,7 +18,6 @@ #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/bitops.h>
 #include <linux/kallsyms.h>
 #include <asm/fpumacro.h>
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 55ae802..c32e309 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -15,11 +15,11 @@ #include <linux/mman.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kprobes.h>
 #include <linux/kallsyms.h>
+#include <linux/kdebug.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -29,7 +29,6 @@ #include <asm/uaccess.h>
 #include <asm/asi.h>
 #include <asm/lsu.h>
 #include <asm/sections.h>
-#include <asm/kdebug.h>
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_KPROBES
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
index 00677b5..eaba9b7 100644
--- a/arch/sparc64/mm/hugetlbpage.c
+++ b/arch/sparc64/mm/hugetlbpage.c
@@ -10,7 +10,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
 
@@ -175,6 +174,12 @@ hugetlb_get_unmapped_area(struct file *f
 	if (len > task_size)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(addr, len, pgoff))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (addr) {
 		addr = ALIGN(addr, HPAGE_SIZE);
 		vma = find_vma(mm, addr);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index f146071..d7004ea 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -122,24 +122,19 @@ static void __init read_obp_memory(const
 				size = 0UL;
 			base = new_base;
 		}
-		regs[i].phys_addr = base;
-		regs[i].reg_size = size;
-	}
-
-	for (i = 0; i < ents; i++) {
-		if (regs[i].reg_size == 0UL) {
-			int j;
-
-			for (j = i; j < ents - 1; j++) {
-				regs[j].phys_addr =
-					regs[j+1].phys_addr;
-				regs[j].reg_size =
-					regs[j+1].reg_size;
-			}
-
-			ents--;
+		if (size == 0UL) {
+			/* If it is empty, simply get rid of it.
+			 * This simplifies the logic of the other
+			 * functions that process these arrays.
+			 */
+			memmove(&regs[i], &regs[i + 1],
+				(ents - i - 1) * sizeof(regs[0]));
 			i--;
+			ents--;
+			continue;
 		}
+		regs[i].phys_addr = base;
+		regs[i].reg_size = size;
 	}
 
 	*num_ents = ents;
@@ -154,15 +149,6 @@ unsigned long *sparc64_valid_addr_bitmap
 unsigned long kern_base __read_mostly;
 unsigned long kern_size __read_mostly;
 
-/* get_new_mmu_context() uses "cache + 1".  */
-DEFINE_SPINLOCK(ctx_alloc_lock);
-unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
-#define CTX_BMAP_SLOTS (1UL << (CTX_NR_BITS - 6))
-unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
-
-/* References to special section boundaries */
-extern char  _start[], _end[];
-
 /* Initial ramdisk setup */
 extern unsigned long sparc_ramdisk_image64;
 extern unsigned int sparc_ramdisk_image;
@@ -178,30 +164,6 @@ unsigned long sparc64_kern_sec_context _
 
 int bigkernel = 0;
 
-struct kmem_cache *pgtable_cache __read_mostly;
-
-static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
-{
-	clear_page(addr);
-}
-
-extern void tsb_cache_init(void);
-
-void pgtable_cache_init(void)
-{
-	pgtable_cache = kmem_cache_create("pgtable_cache",
-					  PAGE_SIZE, PAGE_SIZE,
-					  SLAB_HWCACHE_ALIGN |
-					  SLAB_MUST_HWCACHE_ALIGN,
-					  zero_ctor,
-					  NULL);
-	if (!pgtable_cache) {
-		prom_printf("Could not create pgtable_cache\n");
-		prom_halt();
-	}
-	tsb_cache_init();
-}
-
 #ifdef CONFIG_DEBUG_DCFLUSH
 atomic_t dcpage_flushes = ATOMIC_INIT(0);
 #ifdef CONFIG_SMP
@@ -406,19 +368,70 @@ void __kprobes flush_icache_range(unsign
 	if (tlb_type == spitfire) {
 		unsigned long kaddr;
 
-		for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE)
-			__flush_icache_page(__get_phys(kaddr));
+		/* This code only runs on Spitfire cpus so this is
+		 * why we can assume _PAGE_PADDR_4U.
+		 */
+		for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) {
+			unsigned long paddr, mask = _PAGE_PADDR_4U;
+
+			if (kaddr >= PAGE_OFFSET)
+				paddr = kaddr & mask;
+			else {
+				pgd_t *pgdp = pgd_offset_k(kaddr);
+				pud_t *pudp = pud_offset(pgdp, kaddr);
+				pmd_t *pmdp = pmd_offset(pudp, kaddr);
+				pte_t *ptep = pte_offset_kernel(pmdp, kaddr);
+
+				paddr = pte_val(*ptep) & mask;
+			}
+			__flush_icache_page(paddr);
+		}
 	}
 }
 
 void show_mem(void)
 {
-	printk("Mem-info:\n");
+	unsigned long total = 0, reserved = 0;
+	unsigned long shared = 0, cached = 0;
+	pg_data_t *pgdat;
+
+	printk(KERN_INFO "Mem-info:\n");
 	show_free_areas();
-	printk("Free swap:       %6ldkB\n",
+	printk(KERN_INFO "Free swap:       %6ldkB\n",
 	       nr_swap_pages << (PAGE_SHIFT-10));
-	printk("%ld pages of RAM\n", num_physpages);
-	printk("%lu free pages\n", nr_free_pages());
+	for_each_online_pgdat(pgdat) {
+		unsigned long i, flags;
+
+		pgdat_resize_lock(pgdat, &flags);
+		for (i = 0; i < pgdat->node_spanned_pages; i++) {
+			struct page *page = pgdat_page_nr(pgdat, i);
+			total++;
+			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 "%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);
+
+	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_RECLAIMABLE) +
+		global_page_state(NR_SLAB_UNRECLAIMABLE));
+	printk(KERN_INFO "%lu pages pagetables\n",
+	       global_page_state(NR_PAGETABLE));
 }
 
 void mmu_info(struct seq_file *m)
@@ -658,6 +671,13 @@ void __flush_dcache_range(unsigned long 
 }
 #endif /* DCACHE_ALIASING_POSSIBLE */
 
+/* get_new_mmu_context() uses "cache + 1".  */
+DEFINE_SPINLOCK(ctx_alloc_lock);
+unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
+#define MAX_CTX_NR	(1UL << CTX_NR_BITS)
+#define CTX_BMAP_SLOTS	BITS_TO_LONGS(MAX_CTX_NR)
+DECLARE_BITMAP(mmu_context_bmap, MAX_CTX_NR);
+
 /* Caller does TLB context flushing on local CPU if necessary.
  * The caller also ensures that CTX_VALID(mm->context) is false.
  *
@@ -717,95 +737,6 @@ out:
 		smp_new_mmu_context_version();
 }
 
-void sparc_ultra_dump_itlb(void)
-{
-        int slot;
-
-	if (tlb_type == spitfire) {
-		printk ("Contents of itlb: ");
-		for (slot = 0; slot < 14; slot++) printk ("    ");
-		printk ("%2x:%016lx,%016lx\n",
-			0,
-			spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
-		for (slot = 1; slot < 64; slot+=3) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
-				slot,
-				spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
-				slot+1,
-				spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
-				slot+2,
-				spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
-		}
-	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		printk ("Contents of itlb0:\n");
-		for (slot = 0; slot < 16; slot+=2) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
-				slot,
-				cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot),
-				slot+1,
-				cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1));
-		}
-		printk ("Contents of itlb2:\n");
-		for (slot = 0; slot < 128; slot+=2) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
-				slot,
-				cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot),
-				slot+1,
-				cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1));
-		}
-	}
-}
-
-void sparc_ultra_dump_dtlb(void)
-{
-        int slot;
-
-	if (tlb_type == spitfire) {
-		printk ("Contents of dtlb: ");
-		for (slot = 0; slot < 14; slot++) printk ("    ");
-		printk ("%2x:%016lx,%016lx\n", 0,
-			spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
-		for (slot = 1; slot < 64; slot+=3) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
-				slot,
-				spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
-				slot+1,
-				spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
-				slot+2,
-				spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
-		}
-	} else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-		printk ("Contents of dtlb0:\n");
-		for (slot = 0; slot < 16; slot+=2) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
-				slot,
-				cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot),
-				slot+1,
-				cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1));
-		}
-		printk ("Contents of dtlb2:\n");
-		for (slot = 0; slot < 512; slot+=2) {
-			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
-				slot,
-				cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
-				slot+1,
-				cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
-		}
-		if (tlb_type == cheetah_plus) {
-			printk ("Contents of dtlb3:\n");
-			for (slot = 0; slot < 512; slot+=2) {
-				printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
-					slot,
-					cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
-					slot+1,
-					cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
-			}
-		}
-	}
-}
-
-extern unsigned long cmdline_memory_size;
-
 /* Find a free area for the bootmem map, avoiding the kernel image
  * and the initial ramdisk.
  */
@@ -815,8 +746,8 @@ static unsigned long __init choose_bootm
 	unsigned long avoid_start, avoid_end, bootmap_size;
 	int i;
 
-	bootmap_size = ((end_pfn - start_pfn) + 7) / 8;
-	bootmap_size = ALIGN(bootmap_size, sizeof(long));
+	bootmap_size = bootmem_bootmap_pages(end_pfn - start_pfn);
+	bootmap_size <<= PAGE_SHIFT;
 
 	avoid_start = avoid_end = 0;
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -983,6 +914,20 @@ #endif
 	}
 }
 
+/* About pages_avail, this is the value we will use to calculate
+ * the zholes_size[] argument given to free_area_init_node().  The
+ * page allocator uses this to calculate nr_kernel_pages,
+ * nr_all_pages and zone->present_pages.  On NUMA it is used
+ * to calculate zone->min_unmapped_pages and zone->min_slab_pages.
+ *
+ * So this number should really be set to what the page allocator
+ * actually ends up with.  This means:
+ * 1) It should include bootmem map pages, we'll release those.
+ * 2) It should not include the kernel image, except for the
+ *    __init sections which we will also release.
+ * 3) It should include the initrd image, since we'll release
+ *    that too.
+ */
 static unsigned long __init bootmem_init(unsigned long *pages_avail,
 					 unsigned long phys_base)
 {
@@ -1069,7 +1014,6 @@ #ifdef CONFIG_DEBUG_BOOTMEM
 			initrd_start, initrd_end);
 #endif
 		reserve_bootmem(initrd_start, size);
-		*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
 		initrd_start += PAGE_OFFSET;
 		initrd_end += PAGE_OFFSET;
@@ -1082,6 +1026,11 @@ #endif
 	reserve_bootmem(kern_base, kern_size);
 	*pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT;
 
+	/* Add back in the initmem pages. */
+	size = ((unsigned long)(__init_end) & PAGE_MASK) -
+		PAGE_ALIGN((unsigned long)__init_begin);
+	*pages_avail += size >> PAGE_SHIFT;
+
 	/* Reserve the bootmem map.   We do not account for it
 	 * in pages_avail because we will release that memory
 	 * in free_all_bootmem.
@@ -1092,7 +1041,6 @@ #ifdef CONFIG_DEBUG_BOOTMEM
 		    (bootmap_pfn << PAGE_SHIFT), size);
 #endif
 	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
-	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
 	for (i = 0; i < pavail_ents; i++) {
 		unsigned long start_pfn, end_pfn;
@@ -1584,6 +1532,10 @@ void __init mem_init(void)
 #ifdef CONFIG_DEBUG_BOOTMEM
 	prom_printf("mem_init: Calling free_all_bootmem().\n");
 #endif
+
+	/* We subtract one to account for the mem_map_zero page
+	 * allocated below.
+	 */
 	totalram_pages = num_physpages = free_all_bootmem() - 1;
 
 	/*
@@ -1883,62 +1835,6 @@ static unsigned long kern_large_tte(unsi
 	return val | paddr;
 }
 
-/*
- * Translate PROM's mapping we capture at boot time into physical address.
- * The second parameter is only set from prom_callback() invocations.
- */
-unsigned long prom_virt_to_phys(unsigned long promva, int *error)
-{
-	unsigned long mask;
-	int i;
-
-	mask = _PAGE_PADDR_4U;
-	if (tlb_type == hypervisor)
-		mask = _PAGE_PADDR_4V;
-
-	for (i = 0; i < prom_trans_ents; i++) {
-		struct linux_prom_translation *p = &prom_trans[i];
-
-		if (promva >= p->virt &&
-		    promva < (p->virt + p->size)) {
-			unsigned long base = p->data & mask;
-
-			if (error)
-				*error = 0;
-			return base + (promva & (8192 - 1));
-		}
-	}
-	if (error)
-		*error = 1;
-	return 0UL;
-}
-
-/* XXX We should kill off this ugly thing at so me point. XXX */
-unsigned long sun4u_get_pte(unsigned long addr)
-{
-	pgd_t *pgdp;
-	pud_t *pudp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-	unsigned long mask = _PAGE_PADDR_4U;
-
-	if (tlb_type == hypervisor)
-		mask = _PAGE_PADDR_4V;
-
-	if (addr >= PAGE_OFFSET)
-		return addr & mask;
-
-	if ((addr >= LOW_OBP_ADDRESS) && (addr < HI_OBP_ADDRESS))
-		return prom_virt_to_phys(addr, NULL);
-
-	pgdp = pgd_offset_k(addr);
-	pudp = pud_offset(pgdp, addr);
-	pmdp = pmd_offset(pudp, addr);
-	ptep = pte_offset_kernel(pmdp, addr);
-
-	return pte_val(*ptep) & mask;
-}
-
 /* If not locked, zap it. */
 void __flush_tlb_all(void)
 {
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c
index 236d02f..8eb8a7c 100644
--- a/arch/sparc64/mm/tsb.c
+++ b/arch/sparc64/mm/tsb.c
@@ -252,7 +252,7 @@ static const char *tsb_cache_names[8] = 
 	"tsb_1MB",
 };
 
-void __init tsb_cache_init(void)
+void __init pgtable_cache_init(void)
 {
 	unsigned long i;
 
@@ -262,8 +262,7 @@ void __init tsb_cache_init(void)
 
 		tsb_caches[i] = kmem_cache_create(name,
 						  size, size,
-						  SLAB_HWCACHE_ALIGN |
-						  SLAB_MUST_HWCACHE_ALIGN,
+						  0,
 						  NULL, NULL);
 		if (!tsb_caches[i]) {
 			prom_printf("Could not create %s cache\n", name);
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
index 330743c..18352a4 100644
--- a/arch/sparc64/solaris/ioctl.c
+++ b/arch/sparc64/solaris/ioctl.c
@@ -686,7 +686,8 @@ #endif		
 			int i = 0;
 			
 			read_lock_bh(&dev_base_lock);
-			for (d = dev_base; d; d = d->next) i++;
+			for_each_netdev(d)
+				i++;
 			read_unlock_bh(&dev_base_lock);
 
 			if (put_user (i, (int __user *)A(arg)))
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
index 8cef5fd..a531a2c 100644
--- a/arch/sparc64/solaris/ipc.c
+++ b/arch/sparc64/solaris/ipc.c
@@ -6,7 +6,6 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
 #include <linux/shm.h>
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 9fcaad6..3b67de7 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -6,7 +6,6 @@
 
 #include <linux/module.h> 
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/utsname.h>
 #include <linux/limits.h>
 #include <linux/mm.h>
@@ -224,7 +223,8 @@ static char *serial(char *buffer, int sz
 
 	*buffer = 0;
 	if (dp) {
-		char *val = of_get_property(dp, "system-board-serial#", &len);
+		const char *val =
+			of_get_property(dp, "system-board-serial#", &len);
 
 		if (val && len > 0) {
 			if (len > sz)
diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
index 7fa2634..de10c97 100644
--- a/arch/sparc64/solaris/signal.c
+++ b/arch/sparc64/solaris/signal.c
@@ -5,7 +5,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 
 #include <asm/uaccess.h>
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
index d3a66ea..cc69847 100644
--- a/arch/sparc64/solaris/socket.c
+++ b/arch/sparc64/solaris/socket.c
@@ -8,7 +8,6 @@
  */
 
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/socket.h>
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index c286444..e94f6e5 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -17,7 +17,6 @@ #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/fs.h>
 #include <linux/file.h>
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 780cc0a..f938fa8 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -41,6 +41,7 @@ # CONFIG_MGEODEGX1 is not set
 # CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
 # CONFIG_X86_GENERIC is not set
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_XADD=y
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 9fdfad6..3aa3516 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -12,7 +12,6 @@ #include <linux/string.h>
 #include <linux/tty_flip.h>
 #include <asm/irq.h>
 #include "chan_kern.h"
-#include "user_util.h"
 #include "kern.h"
 #include "irq_user.h"
 #include "sigio.h"
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 0cad354..13f0bf8 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -14,7 +14,6 @@ #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include "kern_util.h"
-#include "user_util.h"
 #include "chan_user.h"
 #include "user.h"
 #include "os.h"
@@ -158,7 +157,7 @@ static int winch_tramp(int fd, struct tt
 	 */
 	err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
 	if(err < 0){
-		printk("fork of winch_thread failed - errno = %d\n", errno);
+		printk("fork of winch_thread failed - errno = %d\n", -err);
 		goto out_close;
 	}
 
@@ -204,14 +203,3 @@ void register_winch(int fd, struct tty_s
 		}
 	}
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index c6a3084..1545384 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -2,14 +2,13 @@ #ifndef __COW_SYS_H__
 #define __COW_SYS_H__
 
 #include "kern_util.h"
-#include "user_util.h"
 #include "os.h"
 #include "user.h"
 #include "um_malloc.h"
 
 static inline void *cow_malloc(int size)
 {
-	return(um_kmalloc(size));
+	return um_kmalloc(size);
 }
 
 static inline void cow_free(void *ptr)
@@ -21,29 +20,22 @@ #define cow_printf printk
 
 static inline char *cow_strdup(char *str)
 {
-	return(uml_strdup(str));
+	return uml_strdup(str);
 }
 
 static inline int cow_seek_file(int fd, __u64 offset)
 {
-	return(os_seek_file(fd, offset));
+	return os_seek_file(fd, offset);
 }
 
 static inline int cow_file_size(char *file, unsigned long long *size_out)
 {
-	return(os_file_size(file, size_out));
+	return os_file_size(file, size_out);
 }
 
 static inline int cow_write_file(int fd, void *buf, int size)
 {
-	return(os_write_file(fd, buf, size));
+	return os_write_file(fd, buf, size);
 }
 
 #endif
-
-/*
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 9c2e7a7..adeece1 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -46,7 +46,7 @@ static int daemon_read(int fd, struct sk
 {
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
 	if(*skb == NULL) return(-ENOMEM);
-	return(net_recvfrom(fd, (*skb)->mac.raw, 
+	return(net_recvfrom(fd, skb_mac_header(*skb),
 			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
 }
 
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index 021b82c..b869e38 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -14,7 +14,6 @@ #include <sys/time.h>
 #include "net_user.h"
 #include "daemon.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 #include "um_malloc.h"
@@ -39,11 +38,11 @@ static struct sockaddr_un *new_addr(void
 	sun = um_kmalloc(sizeof(struct sockaddr_un));
 	if(sun == NULL){
 		printk("new_addr: allocation of sockaddr_un failed\n");
-		return(NULL);
+		return NULL;
 	}
 	sun->sun_family = AF_UNIX;
 	memcpy(sun->sun_path, name, len);
-	return(sun);
+	return sun;
 }
 
 static int connect_to_switch(struct daemon_data *pri)
@@ -112,7 +111,7 @@ static int connect_to_switch(struct daem
 	}
 
 	pri->data_addr = sun;
-	return(fd);
+	return fd;
 
  out_free:
 	kfree(sun);
@@ -120,10 +119,10 @@ static int connect_to_switch(struct daem
 	os_close_file(fd);
  out:
 	os_close_file(pri->control);
-	return(err);
+	return err;
 }
 
-static void daemon_user_init(void *data, void *dev)
+static int daemon_user_init(void *data, void *dev)
 {
 	struct daemon_data *pri = data;
 	struct timeval tv;
@@ -146,13 +145,16 @@ static void daemon_user_init(void *data,
 	if(pri->fd < 0){
 		kfree(pri->local_addr);
 		pri->local_addr = NULL;
+		return pri->fd;
 	}
+
+	return 0;
 }
 
 static int daemon_open(void *data)
 {
 	struct daemon_data *pri = data;
-	return(pri->fd);
+	return pri->fd;
 }
 
 static void daemon_remove(void *data)
@@ -176,12 +178,12 @@ int daemon_user_write(int fd, void *buf,
 {
 	struct sockaddr_un *data_addr = pri->data_addr;
 
-	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+	return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
 }
 
 static int daemon_set_mtu(int mtu, void *data)
 {
-	return(mtu);
+	return mtu;
 }
 
 const struct net_user_info daemon_user_info = {
@@ -194,14 +196,3 @@ const struct net_user_info daemon_user_i
 	.delete_address = NULL,
 	.max_packet	= MAX_PACKET - ETH_HEADER_OTHER
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 218aa0e..7f083ec 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -9,7 +9,6 @@ #include <unistd.h>
 #include <termios.h>
 #include <errno.h>
 #include "user.h"
-#include "user_util.h"
 #include "chan_user.h"
 #include "os.h"
 #include "um_malloc.h"
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
index c495ecf..5eeecf8 100644
--- a/arch/um/drivers/harddog_user.c
+++ b/arch/um/drivers/harddog_user.c
@@ -6,7 +6,6 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
-#include "user_util.h"
 #include "user.h"
 #include "mconsole.h"
 #include "os.h"
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index f75d7b0..ced9910 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -13,7 +13,6 @@ #include "chan_kern.h"
 #include "irq_user.h"
 #include "line.h"
 #include "kern.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "os.h"
 #include "irq_kern.h"
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 52ccb7b..e6b8e0d 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -50,7 +50,7 @@ static int mcast_read(int fd, struct sk_
 {
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
 	if(*skb == NULL) return(-ENOMEM);
-	return(net_recvfrom(fd, (*skb)->mac.raw, 
+	return(net_recvfrom(fd, skb_mac_header(*skb),
 			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
 }
 
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index b827e82..d319db1 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -20,7 +20,6 @@ #include <netinet/in.h>
 #include "net_user.h"
 #include "mcast.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 #include "um_malloc.h"
@@ -34,20 +33,21 @@ static struct sockaddr_in *new_addr(char
 	sin = um_kmalloc(sizeof(struct sockaddr_in));
 	if(sin == NULL){
 		printk("new_addr: allocation of sockaddr_in failed\n");
-		return(NULL);
+		return NULL;
 	}
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = in_aton(addr);
 	sin->sin_port = htons(port);
-	return(sin);
+	return sin;
 }
 
-static void mcast_user_init(void *data, void *dev)
+static int mcast_user_init(void *data, void *dev)
 {
 	struct mcast_data *pri = data;
 
 	pri->mcast_addr = new_addr(pri->addr, pri->port);
 	pri->dev = dev;
+	return 0;
 }
 
 static void mcast_remove(void *data)
@@ -107,8 +107,8 @@ static int mcast_open(void *data)
 		err = -errno;
 		printk("mcast_open : data bind failed, errno = %d\n", errno);
 		goto out_close;
-	}		
-	
+	}
+
 	/* subscribe to the multicast group */
 	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
 	mreq.imr_interface.s_addr = 0;
@@ -153,12 +153,12 @@ int mcast_user_write(int fd, void *buf, 
 {
 	struct sockaddr_in *data_addr = pri->mcast_addr;
 
-	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+	return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
 }
 
 static int mcast_set_mtu(int mtu, void *data)
 {
-	return(mtu);
+	return mtu;
 }
 
 const struct net_user_info mcast_user_info = {
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 65ad293..542c9ef 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -25,7 +25,6 @@ #include "linux/mm.h"
 #include "linux/console.h"
 #include "asm/irq.h"
 #include "asm/uaccess.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "mconsole.h"
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index f02634f..62e5ad6 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -17,7 +17,6 @@ #include "user.h"
 #include "sysdep/ptrace.h"
 #include "mconsole.h"
 #include "os.h"
-#include "user_util.h"
 
 static struct mconsole_command commands[] = {
 	/* With uts namespaces, uts information becomes process-specific, so
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index df3516e..e41a08f 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -15,7 +15,6 @@ #include <linux/mm.h> 
 #include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 #include "mem_user.h"
-#include "user_util.h"
  
 /* These are set in mmapper_init, which is called at boot time */
 static unsigned long mmapper_size;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 04e31f8..72773dd 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -21,7 +21,6 @@ #include "linux/bootmem.h"
 #include "linux/ethtool.h"
 #include "linux/platform_device.h"
 #include "asm/uaccess.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "net_kern.h"
 #include "net_user.h"
@@ -55,7 +54,7 @@ static int uml_net_rx(struct net_device 
 
 	skb->dev = dev;
 	skb_put(skb, dev->mtu);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	pkt_len = (*lp->read)(lp->fd, &skb, lp);
 
 	if (pkt_len > 0) {
@@ -284,7 +283,7 @@ #ifdef undef
 #endif
 }
 
-static void setup_etheraddr(char *str, unsigned char *addr)
+static void setup_etheraddr(char *str, unsigned char *addr, char *name)
 {
 	char *end;
 	int i;
@@ -303,15 +302,34 @@ static void setup_etheraddr(char *str, u
 		}
 		str = end + 1;
 	}
-	if(addr[0] & 1){
+	if (is_multicast_ether_addr(addr)) {
 		printk(KERN_ERR
-		       "Attempt to assign a broadcast ethernet address to a "
+		       "Attempt to assign a multicast ethernet address to a "
 		       "device disallowed\n");
 		goto random;
 	}
+	if (!is_valid_ether_addr(addr)) {
+		printk(KERN_ERR
+		       "Attempt to assign an invalid ethernet address to a "
+		       "device disallowed\n");
+		goto random;
+	}
+	if (!is_local_ether_addr(addr)) {
+		printk(KERN_WARNING
+		       "Warning: attempt to assign a globally valid ethernet "
+		       "address to a device\n");
+		printk(KERN_WARNING "You should better enable the 2nd "
+		       "rightmost bit in the first byte of the MAC,\n");
+		printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
+		       addr[5]);
+		goto random;
+	}
 	return;
 
 random:
+	printk(KERN_INFO
+	       "Choosing a random ethernet address for device %s\n", name);
 	random_ether_addr(addr);
 }
 
@@ -325,31 +343,53 @@ static struct platform_driver uml_net_dr
 };
 static int driver_registered;
 
-static int eth_configure(int n, void *init, char *mac,
-			 struct transport *transport)
+static void net_device_release(struct device *dev)
+{
+	struct uml_net *device = dev->driver_data;
+	struct net_device *netdev = device->dev;
+	struct uml_net_private *lp = netdev->priv;
+
+	if(lp->remove != NULL)
+		(*lp->remove)(&lp->user);
+	list_del(&device->list);
+	kfree(device);
+	free_netdev(netdev);
+}
+
+static void eth_configure(int n, void *init, char *mac,
+			  struct transport *transport)
 {
 	struct uml_net *device;
 	struct net_device *dev;
 	struct uml_net_private *lp;
-	int save, err, size;
+	int err, size;
 
-	size = transport->private_size + sizeof(struct uml_net_private) +
-		sizeof(((struct uml_net_private *) 0)->user);
+	size = transport->private_size + sizeof(struct uml_net_private);
 
 	device = kzalloc(sizeof(*device), GFP_KERNEL);
 	if (device == NULL) {
-		printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
-		return(1);
+		printk(KERN_ERR "eth_configure failed to allocate struct "
+		       "uml_net\n");
+		return;
+	}
+
+	dev = alloc_etherdev(size);
+	if (dev == NULL) {
+		printk(KERN_ERR "eth_configure: failed to allocate struct "
+		       "net_device for eth%d\n", n);
+		goto out_free_device;
 	}
 
 	INIT_LIST_HEAD(&device->list);
 	device->index = n;
 
-	spin_lock(&devices_lock);
-	list_add(&device->list, &devices);
-	spin_unlock(&devices_lock);
+	/* If this name ends up conflicting with an existing registered
+	 * netdevice, that is OK, register_netdev{,ice}() will notice this
+	 * and fail.
+	 */
+	snprintf(dev->name, sizeof(dev->name), "eth%d", n);
 
-	setup_etheraddr(mac, device->mac);
+	setup_etheraddr(mac, device->mac, dev->name);
 
 	printk(KERN_INFO "Netdevice %d ", n);
 	printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
@@ -357,11 +397,6 @@ static int eth_configure(int n, void *in
 	       device->mac[2], device->mac[3],
 	       device->mac[4], device->mac[5]);
 	printk(": ");
-	dev = alloc_etherdev(size);
-	if (dev == NULL) {
-		printk(KERN_ERR "eth_configure: failed to allocate device\n");
-		return 1;
-	}
 
 	lp = dev->priv;
 	/* This points to the transport private data. It's still clear, but we
@@ -376,47 +411,20 @@ static int eth_configure(int n, void *in
 	}
 	device->pdev.id = n;
 	device->pdev.name = DRIVER_NAME;
-	platform_device_register(&device->pdev);
+	device->pdev.dev.release = net_device_release;
+	device->pdev.dev.driver_data = device;
+	if(platform_device_register(&device->pdev))
+		goto out_free_netdev;
 	SET_NETDEV_DEV(dev,&device->pdev.dev);
 
-	/* If this name ends up conflicting with an existing registered
-	 * netdevice, that is OK, register_netdev{,ice}() will notice this
-	 * and fail.
-	 */
-	snprintf(dev->name, sizeof(dev->name), "eth%d", n);
 	device->dev = dev;
 
+	/*
+	 * These just fill in a data structure, so there's no failure
+	 * to be worried about.
+	 */
 	(*transport->kern->init)(dev, init);
 
-	dev->mtu = transport->user->max_packet;
-	dev->open = uml_net_open;
-	dev->hard_start_xmit = uml_net_start_xmit;
-	dev->stop = uml_net_close;
-	dev->get_stats = uml_net_get_stats;
-	dev->set_multicast_list = uml_net_set_multicast_list;
-	dev->tx_timeout = uml_net_tx_timeout;
-	dev->set_mac_address = uml_net_set_mac;
-	dev->change_mtu = uml_net_change_mtu;
-	dev->ethtool_ops = &uml_net_ethtool_ops;
-	dev->watchdog_timeo = (HZ >> 1);
-	dev->irq = UM_ETH_IRQ;
-
-	rtnl_lock();
-	err = register_netdevice(dev);
-	rtnl_unlock();
-	if (err) {
-		device->dev = NULL;
-		/* XXX: should we call ->remove() here? */
-		free_netdev(dev);
-		return 1;
-	}
-
-	/* lp.user is the first four bytes of the transport data, which
-	 * has already been initialized.  This structure assignment will
-	 * overwrite that, so we make sure that .user gets overwritten with
-	 * what it already has.
-	 */
-	save = lp->user[0];
 	*lp = ((struct uml_net_private)
 		{ .list  		= LIST_HEAD_INIT(lp->list),
 		  .dev 			= dev,
@@ -430,20 +438,53 @@ static int eth_configure(int n, void *in
 		  .write 		= transport->kern->write,
 		  .add_address 		= transport->user->add_address,
 		  .delete_address  	= transport->user->delete_address,
-		  .set_mtu 		= transport->user->set_mtu,
-		  .user  		= { save } });
+		  .set_mtu 		= transport->user->set_mtu });
 
 	init_timer(&lp->tl);
 	spin_lock_init(&lp->lock);
 	lp->tl.function = uml_net_user_timer_expire;
 	memcpy(lp->mac, device->mac, sizeof(lp->mac));
 
-	if (transport->user->init)
-		(*transport->user->init)(&lp->user, dev);
+	if ((transport->user->init != NULL) &&
+	    ((*transport->user->init)(&lp->user, dev) != 0))
+		goto out_unregister;
 
 	set_ether_mac(dev, device->mac);
+	dev->mtu = transport->user->max_packet;
+	dev->open = uml_net_open;
+	dev->hard_start_xmit = uml_net_start_xmit;
+	dev->stop = uml_net_close;
+	dev->get_stats = uml_net_get_stats;
+	dev->set_multicast_list = uml_net_set_multicast_list;
+	dev->tx_timeout = uml_net_tx_timeout;
+	dev->set_mac_address = uml_net_set_mac;
+	dev->change_mtu = uml_net_change_mtu;
+	dev->ethtool_ops = &uml_net_ethtool_ops;
+	dev->watchdog_timeo = (HZ >> 1);
+	dev->irq = UM_ETH_IRQ;
 
-	return 0;
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err)
+		goto out_undo_user_init;
+
+	spin_lock(&devices_lock);
+	list_add(&device->list, &devices);
+	spin_unlock(&devices_lock);
+
+	return;
+
+out_undo_user_init:
+	if (transport->user->remove != NULL)
+		(*transport->user->remove)(&lp->user);
+out_unregister:
+	platform_device_unregister(&device->pdev);
+	return; /* platform_device_unregister frees dev and device */
+out_free_netdev:
+	free_netdev(dev);
+out_free_device:
+	kfree(device);
 }
 
 static struct uml_net *find_device(int n)
@@ -666,13 +707,9 @@ static int net_remove(int n, char **erro
 	lp = dev->priv;
 	if(lp->fd > 0)
 		return -EBUSY;
-	if(lp->remove != NULL) (*lp->remove)(&lp->user);
 	unregister_netdev(dev);
 	platform_device_unregister(&device->pdev);
 
-	list_del(&device->list);
-	kfree(device);
-	free_netdev(dev);
 	return 0;
 }
 
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 0ffd7ac..3503cff 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -14,11 +14,11 @@ #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"
+#include "kern_constants.h"
 
 int tap_open_common(void *dev, char *gate_addr)
 {
@@ -216,7 +216,7 @@ static void change(char *dev, char *what
 	sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 
 		netmask[2], netmask[3]);
 
-	output_len = page_size();
+	output_len = UM_KERN_PAGE_SIZE;
 	output = um_kmalloc(output_len);
 	if(output == NULL)
 		printk("change : failed to allocate output buffer\n");
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index e67362a..c329931 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -29,21 +29,25 @@ void pcap_init(struct net_device *dev, v
 	ppri->promisc = init->promisc;
 	ppri->optimize = init->optimize;
 	ppri->filter = init->filter;
+
+	printk("pcap backend, host interface %s\n", ppri->host_if);
 }
 
-static int pcap_read(int fd, struct sk_buff **skb, 
+static int pcap_read(int fd, struct sk_buff **skb,
 		       struct uml_net_private *lp)
 {
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
-	if(*skb == NULL) return(-ENOMEM);
-	return(pcap_user_read(fd, (*skb)->mac.raw, 
+	if(*skb == NULL)
+		return -ENOMEM;
+
+	return pcap_user_read(fd, skb_mac_header(*skb),
 			      (*skb)->dev->mtu + ETH_HEADER_OTHER,
-			      (struct pcap_data *) &lp->user));
+			      (struct pcap_data *) &lp->user);
 }
 
 static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
 {
-	return(-EPERM);
+	return -EPERM;
 }
 
 static const struct net_kern_info pcap_kern_info = {
@@ -65,12 +69,12 @@ int pcap_setup(char *str, char **mac_out
 		  .optimize 	= 0,
 		  .filter 	= NULL });
 
-	remain = split_if_spec(str, &host_if, &init->filter, 
-			       &options[0], &options[1], NULL);
+	remain = split_if_spec(str, &host_if, &init->filter,
+			       &options[0], &options[1], mac_out, NULL);
 	if(remain != NULL){
 		printk(KERN_ERR "pcap_setup - Extra garbage on "
 		       "specification : '%s'\n", remain);
-		return(0);
+		return 0;
 	}
 
 	if(host_if != NULL)
@@ -87,10 +91,13 @@ int pcap_setup(char *str, char **mac_out
 			init->optimize = 1;
 		else if(!strcmp(options[i], "nooptimize"))
 			init->optimize = 0;
-		else printk("pcap_setup : bad option - '%s'\n", options[i]);
+		else {
+			printk("pcap_setup : bad option - '%s'\n", options[i]);
+			return 0;
+		}
 	}
 
-	return(1);
+	return 1;
 }
 
 static struct transport pcap_transport = {
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
index 11921a7..483aa15 100644
--- a/arch/um/drivers/pcap_user.c
+++ b/arch/um/drivers/pcap_user.c
@@ -13,12 +13,13 @@ #include "net_user.h"
 #include "pcap_user.h"
 #include "user.h"
 #include "um_malloc.h"
+#include "kern_constants.h"
 
 #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
 
 #define PCAP_FD(p) (*(int *)(p))
 
-static void pcap_user_init(void *data, void *dev)
+static int pcap_user_init(void *data, void *dev)
 {
 	struct pcap_data *pri = data;
 	pcap_t *p;
@@ -26,13 +27,14 @@ static void pcap_user_init(void *data, v
 
 	p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
 	if(p == NULL){
-		printk("pcap_user_init : pcap_open_live failed - '%s'\n", 
-		       errors);
-		return;
+		printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - "
+		       "'%s'\n", errors);
+		return -EINVAL;
 	}
 
 	pri->dev = dev;
 	pri->pcap = p;
+	return 0;
 }
 
 static int pcap_open(void *data)
@@ -42,39 +44,39 @@ static int pcap_open(void *data)
 	int err;
 
 	if(pri->pcap == NULL)
-		return(-ENODEV);
+		return -ENODEV;
 
 	if(pri->filter != NULL){
 		err = dev_netmask(pri->dev, &netmask);
 		if(err < 0){
-			printk("pcap_open : dev_netmask failed\n");
-			return(-EIO);
+			printk(UM_KERN_ERR "pcap_open : dev_netmask failed\n");
+			return -EIO;
 		}
 
 		pri->compiled = um_kmalloc(sizeof(struct bpf_program));
 		if(pri->compiled == NULL){
-			printk("pcap_open : kmalloc failed\n");
-			return(-ENOMEM);
+			printk(UM_KERN_ERR "pcap_open : kmalloc failed\n");
+			return -ENOMEM;
 		}
-		
+
 		err = pcap_compile(pri->pcap, 
 				   (struct bpf_program *) pri->compiled, 
 				   pri->filter, pri->optimize, netmask);
 		if(err < 0){
-			printk("pcap_open : pcap_compile failed - '%s'\n", 
-			       pcap_geterr(pri->pcap));
-			return(-EIO);
+			printk(UM_KERN_ERR "pcap_open : pcap_compile failed - "
+			       "'%s'\n", pcap_geterr(pri->pcap));
+			return -EIO;
 		}
 
 		err = pcap_setfilter(pri->pcap, pri->compiled);
 		if(err < 0){
-			printk("pcap_open : pcap_setfilter failed - '%s'\n", 
-			       pcap_geterr(pri->pcap));
-			return(-EIO);
+			printk(UM_KERN_ERR "pcap_open : pcap_setfilter "
+			       "failed - '%s'\n", pcap_geterr(pri->pcap));
+			return -EIO;
 		}
 	}
-	
-	return(PCAP_FD(pri->pcap));
+
+	return PCAP_FD(pri->pcap);
 }
 
 static void pcap_remove(void *data)
@@ -84,7 +86,8 @@ static void pcap_remove(void *data)
 	if(pri->compiled != NULL)
 		pcap_freecode(pri->compiled);
 
-	pcap_close(pri->pcap);
+	if(pri->pcap != NULL)
+		pcap_close(pri->pcap);
 }
 
 struct pcap_handler_data {
@@ -113,12 +116,13 @@ int pcap_user_read(int fd, void *buffer,
 
 	n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
 	if(n < 0){
-		printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
-		return(-EIO);
+		printk(UM_KERN_ERR "pcap_dispatch failed - %s\n",
+		       pcap_geterr(pri->pcap));
+		return -EIO;
 	}
 	else if(n == 0) 
-		return(0);
-	return(hdata.len);
+		return 0;
+	return hdata.len;
 }
 
 const struct net_user_info pcap_user_info = {
@@ -131,14 +135,3 @@ const struct net_user_info pcap_user_inf
 	.delete_address = NULL,
 	.max_packet	= MAX_PACKET - ETH_HEADER_OTHER
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 8050802..3f6357d 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -13,7 +13,6 @@ #include <termios.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "chan_user.h"
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 829a5ec..df4976c 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -4,13 +4,13 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <termios.h>
 #include "chan_user.h"
 #include "user.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "os.h"
 #include "um_malloc.h"
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 25634bd..125c44f 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -49,7 +49,7 @@ static unsigned short slip_protocol(stru
 static int slip_read(int fd, struct sk_buff **skb, 
 		       struct uml_net_private *lp)
 {
-	return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
+	return(slip_user_read(fd, skb_mac_header(*skb), (*skb)->dev->mtu,
 			      (struct slip_data *) &lp->user));
 }
 
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 7eddacc..78f0e51 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -8,7 +8,6 @@ #include <errno.h>
 #include <sys/termios.h>
 #include <sys/wait.h>
 #include <sys/signal.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "net_user.h"
@@ -16,12 +15,14 @@ #include "slip.h"
 #include "slip_common.h"
 #include "os.h"
 #include "um_malloc.h"
+#include "kern_constants.h"
 
-void slip_user_init(void *data, void *dev)
+static int slip_user_init(void *data, void *dev)
 {
 	struct slip_data *pri = data;
 
 	pri->dev = dev;
+	return 0;
 }
 
 static int set_up_tty(int fd)
@@ -89,7 +90,7 @@ static int slip_tramp(char **argv, int f
 		goto out_close;
 	pid = err;
 
-	output_len = page_size();
+	output_len = UM_KERN_PAGE_SIZE;
 	output = um_kmalloc(output_len);
 	if(output == NULL){
 		printk("slip_tramp : failed to allocate output buffer\n");
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index b3ed8fb..0a0324a 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -53,7 +53,7 @@ static unsigned short slirp_protocol(str
 static int slirp_read(int fd, struct sk_buff **skb, 
 		       struct uml_net_private *lp)
 {
-	return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
+	return(slirp_user_read(fd, skb_mac_header(*skb), (*skb)->dev->mtu,
 			      (struct slirp_data *) &lp->user));
 }
 
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index ce5e85d..39f889f 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -7,7 +7,6 @@ #include <string.h>
 #include <errno.h>
 #include <sys/wait.h>
 #include <sys/signal.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "net_user.h"
@@ -15,11 +14,12 @@ #include "slirp.h"
 #include "slip_common.h"
 #include "os.h"
 
-void slirp_user_init(void *data, void *dev)
+static int slirp_user_init(void *data, void *dev)
 {
 	struct slirp_data *pri = data;
 
 	pri->dev = dev;
+	return 0;
 }
 
 struct slirp_pre_exec_data {
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 4b382a6..fd09ad9 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -15,7 +15,6 @@ #include "asm/irq.h"
 #include "line.h"
 #include "ssl.h"
 #include "chan_kern.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "init.h"
@@ -192,12 +191,12 @@ static int ssl_init(void)
 	ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
 				    ARRAY_SIZE(serial_lines));
 
-	lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
-
 	new_title = add_xterm_umid(opts.xterm_title);
 	if (new_title != NULL)
 		opts.xterm_title = new_title;
 
+	lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
+
 	ssl_init_done = 1;
 	register_console(&ssl_cons);
 	return 0;
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 76d1f1c..2bb4193 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -22,7 +22,6 @@ #include "asm/irq.h"
 #include "stdio_console.h"
 #include "line.h"
 #include "chan_kern.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "irq_user.h"
 #include "mconsole_kern.h"
@@ -167,12 +166,12 @@ int stdio_init(void)
 		return -1;
 	printk(KERN_INFO "Initialized stdio console driver\n");
 
-	lines_init(vts, ARRAY_SIZE(vts), &opts);
-
 	new_title = add_xterm_umid(opts.xterm_title);
 	if(new_title != NULL)
 		opts.xterm_title = new_title;
 
+	lines_init(vts, ARRAY_SIZE(vts), &opts);
+
 	con_init_done = 1;
 	register_console(&stdiocons);
 	return 0;
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index d95d643..c07d0d5 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -8,7 +8,6 @@ #include <termios.h>
 #include <errno.h>
 #include <unistd.h>
 #include "chan_user.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 #include "um_malloc.h"
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 8bd9204..70509dd 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -39,7 +39,6 @@ #include "asm/uaccess.h"
 #include "asm/irq.h"
 #include "asm/types.h"
 #include "asm/tlbflush.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "kern_util.h"
 #include "kern.h"
@@ -90,7 +89,7 @@ static inline int ubd_test_bit(__u64 bit
 	bits = sizeof(data[0]) * 8;
 	n = bit / bits;
 	off = bit % bits;
-	return((data[n] & (1 << off)) != 0);
+	return (data[n] & (1 << off)) != 0;
 }
 
 static inline void ubd_set_bit(__u64 bit, unsigned char *data)
@@ -147,10 +146,13 @@ struct cow {
 	unsigned long *bitmap;
 	unsigned long bitmap_len;
 	int bitmap_offset;
-        int data_offset;
+	int data_offset;
 };
 
+#define MAX_SG 64
+
 struct ubd {
+	struct list_head restart;
 	/* name (and fd, below) of the file opened for writing, either the
 	 * backing or the cow file. */
 	char *file;
@@ -165,15 +167,17 @@ struct ubd {
 	struct platform_device pdev;
 	struct request_queue *queue;
 	spinlock_t lock;
-	int active;
+	struct scatterlist sg[MAX_SG];
+	struct request *request;
+	int start_sg, end_sg;
 };
 
 #define DEFAULT_COW { \
 	.file =			NULL, \
-        .fd =			-1, \
-        .bitmap =		NULL, \
+	.fd =			-1,	\
+	.bitmap =		NULL, \
 	.bitmap_offset =	0, \
-        .data_offset =		0, \
+	.data_offset =		0, \
 }
 
 #define DEFAULT_UBD { \
@@ -183,11 +187,13 @@ #define DEFAULT_UBD { \
 	.size =			-1, \
 	.boot_openflags =	OPEN_FLAGS, \
 	.openflags =		OPEN_FLAGS, \
-        .no_cow =               0, \
+	.no_cow =               0, \
 	.shared =		0, \
-        .cow =			DEFAULT_COW, \
+	.cow =			DEFAULT_COW, \
 	.lock =			SPIN_LOCK_UNLOCKED,	\
-	.active =		0, \
+	.request =		NULL, \
+	.start_sg =		0, \
+	.end_sg =		0, \
 }
 
 /* Protected by ubd_lock */
@@ -243,7 +249,7 @@ static void make_ide_entries(char *dev_n
 static int fake_ide_setup(char *str)
 {
 	fake_ide = 1;
-	return(1);
+	return 1;
 }
 
 __setup("fake_ide", fake_ide_setup);
@@ -261,7 +267,7 @@ static int parse_unit(char **ptr)
 	if(isdigit(*str)) {
 		n = simple_strtoul(str, &end, 0);
 		if(end == str)
-			return(-1);
+			return -1;
 		*ptr = end;
 	}
 	else if (('a' <= *str) && (*str <= 'z')) {
@@ -269,7 +275,7 @@ static int parse_unit(char **ptr)
 		str++;
 		*ptr = str;
 	}
-	return(n);
+	return n;
 }
 
 /* If *index_out == -1 at exit, the passed option was a general one;
@@ -436,7 +442,7 @@ static int udb_setup(char *str)
 {
 	printk("udb%s specified on command line is almost certainly a ubd -> "
 	       "udb TYPO\n", str);
-	return(1);
+	return 1;
 }
 
 __setup("udb", udb_setup);
@@ -467,66 +473,75 @@ static void do_ubd_request(request_queue
 /* Only changed by ubd_init, which is an initcall. */
 int thread_fd = -1;
 
-/* call ubd_finish if you need to serialize */
-static void __ubd_finish(struct request *req, int error)
+static void ubd_end_request(struct request *req, int bytes, int uptodate)
 {
-	int nsect;
-
-	if(error){
-		end_request(req, 0);
-		return;
+	if (!end_that_request_first(req, uptodate, bytes >> 9)) {
+		struct ubd *dev = req->rq_disk->private_data;
+		unsigned long flags;
+
+		add_disk_randomness(req->rq_disk);
+		spin_lock_irqsave(&dev->lock, flags);
+		end_that_request_last(req, uptodate);
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	nsect = req->current_nr_sectors;
-	req->sector += nsect;
-	req->buffer += nsect << 9;
-	req->errors = 0;
-	req->nr_sectors -= nsect;
-	req->current_nr_sectors = 0;
-	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)
+static inline void ubd_finish(struct request *req, int bytes)
 {
-	struct ubd *dev = req->rq_disk->private_data;
-
-	spin_lock(&dev->lock);
-	__ubd_finish(req, error);
-	spin_unlock(&dev->lock);
+	if(bytes < 0){
+		ubd_end_request(req, 0, 0);
+		return;
+	}
+	ubd_end_request(req, bytes, 1);
 }
 
+static LIST_HEAD(restart);
+
 /* XXX - move this inside ubd_intr. */
 /* Called without dev->lock held, and only in interrupt context. */
 static void ubd_handler(void)
 {
-	struct io_thread_req req;
+	struct io_thread_req *req;
 	struct request *rq;
-	struct ubd *dev;
+	struct ubd *ubd;
+	struct list_head *list, *next_ele;
+	unsigned long flags;
 	int n;
 
-	n = os_read_file(thread_fd, &req, sizeof(req));
-	if(n != sizeof(req)){
-		printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
-		       "err = %d\n", os_getpid(), -n);
-		return;
-	}
-
-	rq = req.req;
-	dev = rq->rq_disk->private_data;
-	dev->active = 0;
+	while(1){
+		n = os_read_file(thread_fd, &req,
+				 sizeof(struct io_thread_req *));
+		if(n != sizeof(req)){
+			if(n == -EAGAIN)
+				break;
+			printk(KERN_ERR "spurious interrupt in ubd_handler, "
+			       "err = %d\n", -n);
+			return;
+		}
 
-	ubd_finish(rq, req.error);
+		rq = req->req;
+		rq->nr_sectors -= req->length >> 9;
+		if(rq->nr_sectors == 0)
+			ubd_finish(rq, rq->hard_nr_sectors << 9);
+		kfree(req);
+	}
 	reactivate_fd(thread_fd, UBD_IRQ);
-	spin_lock(&dev->lock);
-	do_ubd_request(dev->queue);
-	spin_unlock(&dev->lock);
+
+	list_for_each_safe(list, next_ele, &restart){
+		ubd = container_of(list, struct ubd, restart);
+		list_del_init(&ubd->restart);
+		spin_lock_irqsave(&ubd->lock, flags);
+		do_ubd_request(ubd->queue);
+		spin_unlock_irqrestore(&ubd->lock, flags);
+	}
 }
 
 static irqreturn_t ubd_intr(int irq, void *dev)
 {
 	ubd_handler();
-	return(IRQ_HANDLED);
+	return IRQ_HANDLED;
 }
 
 /* Only changed by ubd_init, which is an initcall. */
@@ -545,7 +560,7 @@ static inline int ubd_file_size(struct u
 	char *file;
 
 	file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
-	return(os_file_size(file, size_out));
+	return os_file_size(file, size_out);
 }
 
 static void ubd_close_dev(struct ubd *ubd_dev)
@@ -617,10 +632,18 @@ static int ubd_open_dev(struct ubd *ubd_
 		if(err < 0) goto error;
 		ubd_dev->cow.fd = err;
 	}
-	return(0);
+	return 0;
  error:
 	os_close_file(ubd_dev->fd);
-	return(err);
+	return err;
+}
+
+static void ubd_device_release(struct device *dev)
+{
+	struct ubd *ubd_dev = dev->driver_data;
+
+	blk_cleanup_queue(ubd_dev->queue);
+	*ubd_dev = ((struct ubd) DEFAULT_UBD);
 }
 
 static int ubd_disk_register(int major, u64 size, int unit,
@@ -630,7 +653,7 @@ static int ubd_disk_register(int major, 
 
 	disk = alloc_disk(1 << UBD_SHIFT);
 	if(disk == NULL)
-		return(-ENOMEM);
+		return -ENOMEM;
 
 	disk->major = major;
 	disk->first_minor = unit << UBD_SHIFT;
@@ -645,6 +668,8 @@ static int ubd_disk_register(int major, 
 	if (major == MAJOR_NR) {
 		ubd_devs[unit].pdev.id   = unit;
 		ubd_devs[unit].pdev.name = DRIVER_NAME;
+		ubd_devs[unit].pdev.dev.release = ubd_device_release;
+		ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
 		platform_device_register(&ubd_devs[unit].pdev);
 		disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
 	}
@@ -675,6 +700,8 @@ static int ubd_add(int n, char **error_o
 
 	ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
 
+	INIT_LIST_HEAD(&ubd_dev->restart);
+
 	err = -ENOMEM;
 	ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
 	if (ubd_dev->queue == NULL) {
@@ -683,6 +710,7 @@ static int ubd_add(int n, char **error_o
 	}
 	ubd_dev->queue->queuedata = ubd_dev;
 
+	blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
 	err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
 	if(err){
 		*error_out = "Failed to register device";
@@ -730,14 +758,14 @@ static int ubd_config(char *str, char **
 		goto err_free;
 	}
 
- 	mutex_lock(&ubd_lock);
+	mutex_lock(&ubd_lock);
 	ret = ubd_add(n, error_out);
 	if (ret)
 		ubd_devs[n].file = NULL;
- 	mutex_unlock(&ubd_lock);
+	mutex_unlock(&ubd_lock);
 
 out:
- 	return ret;
+	return ret;
 
 err_free:
 	kfree(str);
@@ -752,7 +780,7 @@ static int ubd_get_config(char *name, ch
 	n = parse_unit(&name);
 	if((n >= MAX_DEV) || (n < 0)){
 		*error_out = "ubd_get_config : device number out of range";
-		return(-1);
+		return -1;
 	}
 
 	ubd_dev = &ubd_devs[n];
@@ -773,29 +801,27 @@ static int ubd_get_config(char *name, ch
 
  out:
 	mutex_unlock(&ubd_lock);
-	return(len);
+	return len;
 }
 
 static int ubd_id(char **str, int *start_out, int *end_out)
 {
-        int n;
+	int n;
 
 	n = parse_unit(str);
-        *start_out = 0;
-        *end_out = MAX_DEV - 1;
-        return n;
+	*start_out = 0;
+	*end_out = MAX_DEV - 1;
+	return n;
 }
 
 static int ubd_remove(int n, char **error_out)
 {
+	struct gendisk *disk = ubd_gendisk[n];
 	struct ubd *ubd_dev;
 	int err = -ENODEV;
 
 	mutex_lock(&ubd_lock);
 
-	if(ubd_gendisk[n] == NULL)
-		goto out;
-
 	ubd_dev = &ubd_devs[n];
 
 	if(ubd_dev->file == NULL)
@@ -806,9 +832,11 @@ static int ubd_remove(int n, char **erro
 	if(ubd_dev->count > 0)
 		goto out;
 
-	del_gendisk(ubd_gendisk[n]);
-	put_disk(ubd_gendisk[n]);
 	ubd_gendisk[n] = NULL;
+	if(disk != NULL){
+		del_gendisk(disk);
+		put_disk(disk);
+	}
 
 	if(fake_gendisk[n] != NULL){
 		del_gendisk(fake_gendisk[n]);
@@ -816,10 +844,8 @@ static int ubd_remove(int n, char **erro
 		fake_gendisk[n] = NULL;
 	}
 
-	blk_cleanup_queue(ubd_dev->queue);
-	platform_device_unregister(&ubd_dev->pdev);
-	*ubd_dev = ((struct ubd) DEFAULT_UBD);
 	err = 0;
+	platform_device_unregister(&ubd_dev->pdev);
 out:
 	mutex_unlock(&ubd_lock);
 	return err;
@@ -832,7 +858,7 @@ static struct mc_device ubd_mc = {
 	.list		= LIST_HEAD_INIT(ubd_mc.list),
 	.name		= "ubd",
 	.config		= ubd_config,
- 	.get_config	= ubd_get_config,
+	.get_config	= ubd_get_config,
 	.id		= ubd_id,
 	.remove		= ubd_remove,
 };
@@ -854,7 +880,7 @@ static int __init ubd0_init(void)
 		ubd_dev->file = "root_fs";
 	mutex_unlock(&ubd_lock);
 
-	return(0);
+	return 0;
 }
 
 __initcall(ubd0_init);
@@ -882,14 +908,14 @@ static int __init ubd_init(void)
 			return -1;
 	}
 	platform_driver_register(&ubd_driver);
- 	mutex_lock(&ubd_lock);
+	mutex_lock(&ubd_lock);
 	for (i = 0; i < MAX_DEV; i++){
 		err = ubd_add(i, &error);
 		if(err)
 			printk(KERN_ERR "Failed to initialize ubd device %d :"
 			       "%s\n", i, error);
 	}
- 	mutex_unlock(&ubd_lock);
+	mutex_unlock(&ubd_lock);
 	return 0;
 }
 
@@ -913,7 +939,7 @@ static int __init ubd_driver_init(void){
 		       "ubd : Failed to start I/O thread (errno = %d) - "
 		       "falling back to synchronous I/O\n", -io_pid);
 		io_pid = -1;
-		return(0);
+		return 0;
 	}
 	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
 			     IRQF_DISABLED, "ubd", ubd_devs);
@@ -948,7 +974,7 @@ static int ubd_open(struct inode *inode,
 	        err = -EROFS;
 	}*/
  out:
-	return(err);
+	return err;
 }
 
 static int ubd_release(struct inode * inode, struct file * file)
@@ -958,7 +984,7 @@ static int ubd_release(struct inode * in
 
 	if(--ubd_dev->count == 0)
 		ubd_close_dev(ubd_dev);
-	return(0);
+	return 0;
 }
 
 static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
@@ -1014,7 +1040,7 @@ static void cowify_req(struct io_thread_
 			if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
 				ubd_set_bit(i, (unsigned char *)
 					    &req->sector_mask);
-                }
+		}
 	}
 	else cowify_bitmap(req->offset, req->length, &req->sector_mask,
 			   &req->cow_offset, bitmap, bitmap_offset,
@@ -1022,26 +1048,16 @@ static void cowify_req(struct io_thread_
 }
 
 /* Called with dev->lock held */
-static int prepare_request(struct request *req, struct io_thread_req *io_req)
+static void prepare_request(struct request *req, struct io_thread_req *io_req,
+			    unsigned long long offset, int page_offset,
+			    int len, struct page *page)
 {
 	struct gendisk *disk = req->rq_disk;
 	struct ubd *ubd_dev = disk->private_data;
-	__u64 offset;
-	int len;
-
-	/* This should be impossible now */
-	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);
-		return(1);
-	}
-
-	offset = ((__u64) req->sector) << 9;
-	len = req->current_nr_sectors << 9;
 
 	io_req->req = req;
-	io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_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;
@@ -1052,45 +1068,66 @@ 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] = ubd_dev->cow.data_offset;
-	io_req->buffer = req->buffer;
+	io_req->buffer = page_address(page) + page_offset;
 	io_req->sectorsize = 1 << 9;
 
 	if(ubd_dev->cow.file != NULL)
-		cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
-			   ubd_dev->cow.bitmap_len);
+		cowify_req(io_req, ubd_dev->cow.bitmap,
+			   ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
 
-	return(0);
 }
 
 /* Called with dev->lock held */
 static void do_ubd_request(request_queue_t *q)
 {
-	struct io_thread_req io_req;
+	struct io_thread_req *io_req;
 	struct request *req;
-	int err, n;
-
-	if(thread_fd == -1){
-		while((req = elv_next_request(q)) != NULL){
-			err = prepare_request(req, &io_req);
-			if(!err){
-				do_io(&io_req);
-				__ubd_finish(req, io_req.error);
-			}
-		}
-	}
-	else {
+	int n;
+
+	while(1){
 		struct ubd *dev = q->queuedata;
-		if(dev->active || (req = elv_next_request(q)) == NULL)
-			return;
-		err = prepare_request(req, &io_req);
-		if(!err){
-			dev->active = 1;
-			n = os_write_file(thread_fd, (char *) &io_req,
-					 sizeof(io_req));
-			if(n != sizeof(io_req))
-				printk("write to io thread failed, "
-				       "errno = %d\n", -n);
+		if(dev->end_sg == 0){
+			struct request *req = elv_next_request(q);
+			if(req == NULL)
+				return;
+
+			dev->request = req;
+			blkdev_dequeue_request(req);
+			dev->start_sg = 0;
+			dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
 		}
+
+		req = dev->request;
+		while(dev->start_sg < dev->end_sg){
+			struct scatterlist *sg = &dev->sg[dev->start_sg];
+
+			io_req = kmalloc(sizeof(struct io_thread_req),
+					 GFP_ATOMIC);
+			if(io_req == NULL){
+				if(list_empty(&dev->restart))
+					list_add(&dev->restart, &restart);
+				return;
+			}
+			prepare_request(req, io_req,
+					(unsigned long long) req->sector << 9,
+					sg->offset, sg->length, sg->page);
+
+			n = os_write_file(thread_fd, &io_req,
+					  sizeof(struct io_thread_req *));
+			if(n != sizeof(struct io_thread_req *)){
+				if(n != -EAGAIN)
+					printk("write to io thread failed, "
+					       "errno = %d\n", -n);
+				else if(list_empty(&dev->restart))
+					list_add(&dev->restart, &restart);
+				return;
+			}
+
+			req->sector += sg->length >> 9;
+			dev->start_sg++;
+		}
+		dev->end_sg = 0;
+		dev->request = NULL;
 	}
 }
 
@@ -1120,21 +1157,21 @@ static int ubd_ioctl(struct inode * inod
 		ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
 		if(copy_to_user((char __user *) arg, (char *) &ubd_id,
 				 sizeof(ubd_id)))
-			return(-EFAULT);
-		return(0);
+			return -EFAULT;
+		return 0;
 
 	case CDROMVOLREAD:
 		if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
-			return(-EFAULT);
+			return -EFAULT;
 		volume.channel0 = 255;
 		volume.channel1 = 255;
 		volume.channel2 = 255;
 		volume.channel3 = 255;
 		if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
-			return(-EFAULT);
-		return(0);
+			return -EFAULT;
+		return 0;
 	}
-	return(-EINVAL);
+	return -EINVAL;
 }
 
 static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
@@ -1176,29 +1213,29 @@ static int backing_file_mismatch(char *f
 	if(err < 0){
 		printk("Failed to get modification time of backing file "
 		       "\"%s\", err = %d\n", file, -err);
-		return(err);
+		return err;
 	}
 
 	err = os_file_size(file, &actual);
 	if(err < 0){
 		printk("Failed to get size of backing file \"%s\", "
 		       "err = %d\n", file, -err);
-		return(err);
+		return err;
 	}
 
-  	if(actual != size){
+	if(actual != size){
 		/*__u64 can be a long on AMD64 and with %lu GCC complains; so
 		 * the typecast.*/
 		printk("Size mismatch (%llu vs %llu) of COW header vs backing "
 		       "file\n", (unsigned long long) size, actual);
-		return(-EINVAL);
+		return -EINVAL;
 	}
 	if(modtime != mtime){
 		printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
 		       "file\n", mtime, modtime);
-		return(-EINVAL);
+		return -EINVAL;
 	}
-	return(0);
+	return 0;
 }
 
 int read_cow_bitmap(int fd, void *buf, int offset, int len)
@@ -1207,13 +1244,13 @@ int read_cow_bitmap(int fd, void *buf, i
 
 	err = os_seek_file(fd, offset);
 	if(err < 0)
-		return(err);
+		return err;
 
 	err = os_read_file(fd, buf, len);
 	if(err < 0)
-		return(err);
+		return err;
 
-	return(0);
+	return 0;
 }
 
 int open_ubd_file(char *file, struct openflags *openflags, int shared,
@@ -1231,14 +1268,14 @@ int open_ubd_file(char *file, struct ope
 	if (fd < 0) {
 		if ((fd == -ENOENT) && (create_cow_out != NULL))
 			*create_cow_out = 1;
-                if (!openflags->w ||
-                   ((fd != -EROFS) && (fd != -EACCES)))
+		if (!openflags->w ||
+		    ((fd != -EROFS) && (fd != -EACCES)))
 			return fd;
 		openflags->w = 0;
 		fd = os_open_file(file, *openflags, mode);
 		if (fd < 0)
 			return fd;
-        }
+	}
 
 	if(shared)
 		printk("Not locking \"%s\" on the host\n", file);
@@ -1252,7 +1289,7 @@ int open_ubd_file(char *file, struct ope
 
 	/* Successful return case! */
 	if(backing_file_out == NULL)
-		return(fd);
+		return fd;
 
 	err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
 			      &size, &sectorsize, &align, bitmap_offset_out);
@@ -1262,7 +1299,7 @@ int open_ubd_file(char *file, struct ope
 		goto out_close;
 	}
 	if(err)
-		return(fd);
+		return fd;
 
 	asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
 
@@ -1285,7 +1322,7 @@ int open_ubd_file(char *file, struct ope
 	cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
 		  bitmap_len_out, data_offset_out);
 
-        return fd;
+	return fd;
  out_close:
 	os_close_file(fd);
 	return err;
@@ -1310,10 +1347,10 @@ int create_cow_file(char *cow_file, char
 			    bitmap_offset_out, bitmap_len_out,
 			    data_offset_out);
 	if(!err)
-		return(fd);
+		return fd;
 	os_close_file(fd);
  out:
-	return(err);
+	return err;
 }
 
 static int update_bitmap(struct io_thread_req *req)
@@ -1321,23 +1358,23 @@ static int update_bitmap(struct io_threa
 	int n;
 
 	if(req->cow_offset == -1)
-		return(0);
+		return 0;
 
 	n = os_seek_file(req->fds[1], req->cow_offset);
 	if(n < 0){
 		printk("do_io - bitmap lseek failed : err = %d\n", -n);
-		return(1);
+		return 1;
 	}
 
 	n = os_write_file(req->fds[1], &req->bitmap_words,
-		          sizeof(req->bitmap_words));
+			  sizeof(req->bitmap_words));
 	if(n != sizeof(req->bitmap_words)){
 		printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
 		       req->fds[1]);
-		return(1);
+		return 1;
 	}
 
-	return(0);
+	return 0;
 }
 
 void do_io(struct io_thread_req *req)
@@ -1409,13 +1446,14 @@ static int io_count = 0;
 
 int io_thread(void *arg)
 {
-	struct io_thread_req req;
+	struct io_thread_req *req;
 	int n;
 
 	ignore_sigwinch_sig();
 	while(1){
-		n = os_read_file(kernel_fd, &req, sizeof(req));
-		if(n != sizeof(req)){
+		n = os_read_file(kernel_fd, &req,
+				 sizeof(struct io_thread_req *));
+		if(n != sizeof(struct io_thread_req *)){
 			if(n < 0)
 				printk("io_thread - read failed, fd = %d, "
 				       "err = %d\n", kernel_fd, -n);
@@ -1426,9 +1464,10 @@ int io_thread(void *arg)
 			continue;
 		}
 		io_count++;
-		do_io(&req);
-		n = os_write_file(kernel_fd, &req, sizeof(req));
-		if(n != sizeof(req))
+		do_io(req);
+		n = os_write_file(kernel_fd, &req,
+				  sizeof(struct io_thread_req *));
+		if(n != sizeof(struct io_thread_req *))
 			printk("io_thread - write failed, fd = %d, err = %d\n",
 			       kernel_fd, -n);
 	}
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index b94d2bc..4707b3f 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -16,7 +16,6 @@ #include <sys/socket.h>
 #include <sys/mman.h>
 #include <sys/param.h>
 #include "asm/types.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "ubd_user.h"
@@ -47,8 +46,8 @@ int start_io_thread(unsigned long sp, in
 	pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
 		    NULL);
 	if(pid < 0){
-		printk("start_io_thread - clone failed : errno = %d\n", errno);
 		err = -errno;
+		printk("start_io_thread - clone failed : errno = %d\n", errno);
 		goto out_close;
 	}
 
@@ -60,16 +59,5 @@ int start_io_thread(unsigned long sp, in
 	kernel_fd = -1;
 	*fd_out = -1;
  out:
-	return(err);
+	return err;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 850221d..571c2b3 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -14,7 +14,6 @@ #include <sched.h>
 #include <sys/socket.h>
 #include "kern_util.h"
 #include "chan_user.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 #include "xterm.h"
diff --git a/arch/um/include/arch.h b/arch/um/include/arch.h
new file mode 100644
index 0000000..10ad52d
--- /dev/null
+++ b/arch/um/include/arch.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __ARCH_H__
+#define __ARCH_H__
+
+#include "sysdep/ptrace.h"
+
+extern void arch_check_bugs(void);
+extern int arch_fixup(unsigned long address, union uml_pt_regs *regs);
+extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
+
+#endif
diff --git a/arch/um/include/as-layout.h b/arch/um/include/as-layout.h
new file mode 100644
index 0000000..fccf187
--- /dev/null
+++ b/arch/um/include/as-layout.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __START_H__
+#define __START_H__
+
+#include "sysdep/ptrace.h"
+
+struct cpu_task {
+	int pid;
+	void *task;
+};
+
+extern struct cpu_task cpu_tasks[];
+
+extern unsigned long low_physmem;
+extern unsigned long high_physmem;
+extern unsigned long uml_physmem;
+extern unsigned long uml_reserved;
+extern unsigned long end_vm;
+extern unsigned long start_vm;
+extern unsigned long long highmem;
+
+extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
+extern unsigned long _unprotected_end;
+extern unsigned long brk_start;
+
+extern int linux_main(int argc, char **argv);
+extern void set_cmdline(char *cmd);
+
+extern void (*sig_info[])(int, union uml_pt_regs *);
+
+#endif
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 461175f..5593a80 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -24,5 +24,7 @@ DEFINE(UM_ELF_CLASS, ELF_CLASS);
 DEFINE(UM_ELFCLASS32, ELFCLASS32);
 DEFINE(UM_ELFCLASS64, ELFCLASS64);
 
+DEFINE(UM_NR_CPUS, NR_CPUS);
+
 /* For crypto assembler code. */
 DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 173af02..50a4969 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -8,6 +8,7 @@ #define __KERN_UTIL_H__
 
 #include "sysdep/ptrace.h"
 #include "sysdep/faultinfo.h"
+#include "uml-config.h"
 
 typedef void (*kern_hndl)(int, union uml_pt_regs *);
 
@@ -23,7 +24,6 @@ struct kern_handlers {
 extern const struct kern_handlers handlinfo_kern;
 
 extern int ncpus;
-extern char *linux_prog;
 extern char *gdb_init;
 extern int kmalloc_ok;
 extern int jail;
@@ -34,7 +34,9 @@ #define UML_ROUND_UP(addr) \
 	UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
 
 extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
+#ifdef UML_CONFIG_MODE_TT
 extern unsigned long stack_sp(unsigned long page);
+#endif
 extern int kernel_thread_proc(void *data);
 extern void syscall_segv(int sig);
 extern int current_pid(void);
@@ -42,7 +44,7 @@ extern unsigned long alloc_stack(int ord
 extern int do_signal(void);
 extern int is_stack_fault(unsigned long sp);
 extern unsigned long segv(struct faultinfo fi, unsigned long ip,
-			  int is_user, void *sc);
+			  int is_user, union uml_pt_regs *regs);
 extern int handle_page_fault(unsigned long address, unsigned long ip,
 			     int is_write, int is_user, int *code_out);
 extern void syscall_ready(void);
@@ -50,7 +52,6 @@ extern void set_tracing(void *t, int tra
 extern int is_tracing(void *task);
 extern int segv_syscall(void);
 extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
-extern int page_size(void);
 extern unsigned long page_mask(void);
 extern int need_finish_fork(void);
 extern void free_stack(unsigned long stack, int order);
@@ -58,7 +59,6 @@ extern void add_input_request(int op, vo
 extern char *current_cmd(void);
 extern void timer_handler(int sig, union uml_pt_regs *regs);
 extern int set_signals(int enable);
-extern void force_sigbus(void);
 extern int pid_to_processor_id(int pid);
 extern void deliver_signals(void *t);
 extern int next_trap_index(int max);
@@ -70,7 +70,6 @@ extern void *syscall_sp(void *t);
 extern void syscall_trace(union uml_pt_regs *regs, int entryexit);
 extern int hz(void);
 extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
-extern int external_pid(void *t);
 extern void interrupt_end(void);
 extern void initial_thread_cb(void (*proc)(void *), void *arg);
 extern int debugger_signal(int status, int pid);
@@ -81,7 +80,6 @@ extern int init_parent_proxy(int pid);
 extern int singlestepping(void *t);
 extern void check_stack_overflow(void *ptr);
 extern void relay_signal(int sig, union uml_pt_regs *regs);
-extern void not_implemented(void);
 extern int user_context(unsigned long sp);
 extern void timer_irq(union uml_pt_regs *regs);
 extern void unprotect_stack(unsigned long stack);
@@ -93,7 +91,6 @@ extern char *uml_strdup(char *string);
 extern void unprotect_kernel_mem(void);
 extern void protect_kernel_mem(void);
 extern void uml_cleanup(void);
-extern void set_current(void *t);
 extern void lock_signalled_task(void *t);
 extern void IPI_handler(int cpu);
 extern int jail_setup(char *line, int *add);
@@ -118,4 +115,6 @@ extern void time_init_kern(void);
 extern int __cant_sleep(void);
 extern void sigio_handler(int sig, union uml_pt_regs *regs);
 
+extern void copy_sc(union uml_pt_regs *regs, void *from);
+
 #endif
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index 125ab42..9237056 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -40,7 +40,7 @@ struct uml_net_private {
 	void (*add_address)(unsigned char *, unsigned char *, void *);
 	void (*delete_address)(unsigned char *, unsigned char *, void *);
 	int (*set_mtu)(int mtu, void *);
-	int user[1];
+	char user[0];
 };
 
 struct net_kern_info {
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
index 19f207c..cfe7c50 100644
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -14,7 +14,7 @@ #define ETH_MAX_PACKET (1500)
 #define UML_NET_VERSION (4)
 
 struct net_user_info {
-	void (*init)(void *, void *);
+	int (*init)(void *, void *);
 	int (*open)(void *);
 	void (*close)(int, void *);
 	void (*remove)(void *);
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 5c74da4..688d181 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -16,6 +16,8 @@ #include "irq_user.h"
 #include "sysdep/tls.h"
 #include "sysdep/archsetjmp.h"
 
+#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
+
 #define OS_TYPE_FILE 1
 #define OS_TYPE_DIR 2
 #define OS_TYPE_SYMLINK 3
@@ -273,8 +275,9 @@ extern void stack_protections(unsigned l
 extern void task_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
-extern void setup_hostinfo(void);
+extern void setup_hostinfo(char *buf, int len);
 extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
+extern void os_dump_core(void);
 
 /* time.c */
 #define BILLION (1000 * 1000 * 1000)
@@ -297,13 +300,12 @@ extern long syscall_stub_data(struct mm_
 			      unsigned long *data, int data_count,
 			      void **addr, void **stub_addr);
 extern int map(struct mm_id * mm_idp, unsigned long virt,
-	       unsigned long len, int r, int w, int x, int phys_fd,
+	       unsigned long len, int prot, int phys_fd,
 	       unsigned long long offset, int done, void **data);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
 		 int done, void **data);
 extern int protect(struct mm_id * mm_idp, unsigned long addr,
-		   unsigned long len, int r, int w, int x, int done,
-		   void **data);
+		   unsigned long len, unsigned int prot, int done, void **data);
 
 /* skas/process.c */
 extern int is_skas_winch(int pid, int fd, void *data);
@@ -339,8 +341,11 @@ extern void maybe_sigio_broken(int fd, i
 
 /* skas/trap */
 extern void sig_handler_common_skas(int sig, void *sc_ptr);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
 
+/* sys-x86_64/prctl.c */
 extern int os_arch_prctl(int pid, int code, unsigned long *addr);
 
+/* tty.c */
+int get_pty(void);
+
 #endif
diff --git a/arch/um/include/skas/mode_kern_skas.h b/arch/um/include/skas/mode_kern_skas.h
index 9cd9c6e..8ee6285 100644
--- a/arch/um/include/skas/mode_kern_skas.h
+++ b/arch/um/include/skas/mode_kern_skas.h
@@ -33,6 +33,8 @@ extern unsigned long set_task_sizes_skas
 extern int start_uml_skas(void);
 extern int external_pid_skas(struct task_struct *task);
 extern int thread_pid_skas(struct task_struct *task);
+extern void flush_tlb_page_skas(struct vm_area_struct *vma,
+				unsigned long address);
 
 #define kmem_end_skas (host_task_size - 1024 * 1024)
 
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index 8efc1e0..bcd1a4a 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -14,9 +14,7 @@ struct host_vm_op {
 		struct {
 			unsigned long addr;
 			unsigned long len;
-			unsigned int r:1;
-			unsigned int w:1;
-			unsigned int x:1;
+			unsigned int prot;
 			int fd;
 			__u64 offset;
 		} mmap;
@@ -27,9 +25,7 @@ struct host_vm_op {
 		struct {
 			unsigned long addr;
 			unsigned long len;
-			unsigned int r:1;
-			unsigned int w:1;
-			unsigned int x:1;
+			unsigned int prot;
 		} mprotect;
 	} u;
 };
diff --git a/arch/um/include/tt/uaccess-tt.h b/arch/um/include/tt/uaccess-tt.h
index b19645f..13a64f6 100644
--- a/arch/um/include/tt/uaccess-tt.h
+++ b/arch/um/include/tt/uaccess-tt.h
@@ -27,8 +27,6 @@ #define is_stack(addr, size) \
 #define access_ok_tt(type, addr, size) \
 	(is_stack(addr, size))
 
-extern unsigned long get_fault_addr(void);
-
 extern int __do_copy_from_user(void *to, const void *from, int n,
 			       void **fault_addr, void **fault_catcher);
 extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
index 0363a9b..e6d7c5a 100644
--- a/arch/um/include/um_malloc.h
+++ b/arch/um/include/um_malloc.h
@@ -11,7 +11,6 @@ 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/user.h b/arch/um/include/user.h
index acadce3..d380e6d 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -6,6 +6,19 @@
 #ifndef __USER_H__
 #define __USER_H__
 
+/*
+ * The usual definition - copied here because the kernel provides its own,
+ * fancier, type-safe, definition.  Using that one would require
+ * copying too much infrastructure for my taste, so userspace files
+ * get less checking than kernel files.
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * This will provide the size_t definition in both kernel and userspace builds
+ */
+#include <linux/types.h>
+
 extern void panic(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 extern int printk(const char *fmt, ...)
@@ -13,19 +26,7 @@ extern int printk(const char *fmt, ...)
 extern void schedule(void);
 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 size_t strlcpy(char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
 
 #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/user_util.h b/arch/um/include/user_util.h
deleted file mode 100644
index 023575f..0000000
--- a/arch/um/include/user_util.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __USER_UTIL_H__
-#define __USER_UTIL_H__
-
-#include "sysdep/ptrace.h"
-
-/* Copied from kernel.h */
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
-
-extern int mode_tt;
-
-extern int grantpt(int __fd);
-extern int unlockpt(int __fd);
-extern char *ptsname(int __fd);
-
-struct cpu_task {
-	int pid;
-	void *task;
-};
-
-extern struct cpu_task cpu_tasks[];
-
-extern void (*sig_info[])(int, union uml_pt_regs *);
-
-extern unsigned long low_physmem;
-extern unsigned long high_physmem;
-extern unsigned long uml_physmem;
-extern unsigned long uml_reserved;
-extern unsigned long end_vm;
-extern unsigned long start_vm;
-extern unsigned long long highmem;
-
-extern char host_info[];
-
-extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
-extern unsigned long _unprotected_end;
-extern unsigned long brk_start;
-
-extern int pty_output_sigio;
-extern int pty_close_sigio;
-
-extern void *add_signal_handler(int sig, void (*handler)(int));
-extern int linux_main(int argc, char **argv);
-extern void set_cmdline(char *cmd);
-extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
-extern int get_pty(void);
-extern 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, ...)
-	__attribute__ ((format (printf, 1, 2)));
-extern int detach(int pid, int sig);
-extern int attach(int pid);
-extern void kill_child_dead(int pid);
-extern int cont(int pid);
-extern void check_sigio(void);
-extern void arch_check_bugs(void);
-extern int cpu_feature(char *what, char *buf, int len);
-extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
-extern int arch_fixup(unsigned long address, void *sc_ptr);
-extern void arch_init_thread(void);
-extern int raw(int fd);
-
-#endif
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 1211664..356e50f 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -10,8 +10,8 @@ #include "asm/ptrace.h"
 #include "asm/pgtable.h"
 #include "asm/tlbflush.h"
 #include "asm/uaccess.h"
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
 #include "mem_user.h"
 #include "kern.h"
 #include "irq_user.h"
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 8cde431..cda91aa 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -10,7 +10,6 @@ #include "linux/init_task.h"
 #include "linux/mqueue.h"
 #include "asm/uaccess.h"
 #include "asm/pgtable.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "os.h"
 
diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c
index 82ecf90..16dc43e 100644
--- a/arch/um/kernel/initrd.c
+++ b/arch/um/kernel/initrd.c
@@ -7,7 +7,6 @@ #include "linux/init.h"
 #include "linux/bootmem.h"
 #include "linux/initrd.h"
 #include "asm/types.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "initrd.h"
 #include "init.h"
@@ -22,12 +21,20 @@ static int __init read_initrd(void)
 	long long size;
 	int err;
 
-	if(initrd == NULL) return 0;
+	if(initrd == NULL)
+		return 0;
+
 	err = os_file_size(initrd, &size);
-	if(err) return 0;
+	if(err)
+		return 0;
+
 	area = alloc_bootmem(size);
-	if(area == NULL) return 0;
-	if(load_initrd(initrd, area, size) == -1) return 0;
+	if(area == NULL)
+		return 0;
+
+	if(load_initrd(initrd, area, size) == -1)
+		return 0;
+
 	initrd_start = (unsigned long) area;
 	initrd_end = initrd_start + size;
 	return 0;
@@ -54,25 +61,15 @@ int load_initrd(char *filename, void *bu
 	fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
 	if(fd < 0){
 		printk("Opening '%s' failed - err = %d\n", filename, -fd);
-		return(-1);
+		return -1;
 	}
 	n = os_read_file(fd, buf, size);
 	if(n != size){
 		printk("Read of %d bytes from '%s' failed, err = %d\n", size,
 		       filename, -n);
-		return(-1);
+		return -1;
 	}
 
 	os_close_file(fd);
-	return(0);
+	return 0;
 }
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * 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/irq.c b/arch/um/kernel/irq.c
index dbf2f5b..8f2ed36 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -25,7 +25,6 @@ #include "asm/signal.h"
 #include "asm/system.h"
 #include "asm/errno.h"
 #include "asm/uaccess.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "irq_user.h"
 #include "irq_kern.h"
@@ -79,6 +78,14 @@ skip:
 	return 0;
 }
 
+/*
+ * This list is accessed under irq_lock, except in sigio_handler,
+ * where it is safe from being modified.  IRQ handlers won't change it -
+ * if an IRQ source has vanished, it will be freed by free_irqs just
+ * before returning from sigio_handler.  That will process a separate
+ * list of irqs to free, with its own locking, coming back here to
+ * remove list elements, taking the irq_lock to do so.
+ */
 static struct irq_fd *active_fds = NULL;
 static struct irq_fd **last_irq_ptr = &active_fds;
 
@@ -244,6 +251,7 @@ void free_irq_by_fd(int fd)
 	free_irq_by_cb(same_fd, &fd);
 }
 
+/* Must be called with irq_lock held */
 static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
 {
 	struct irq_fd *irq;
@@ -309,6 +317,12 @@ void deactivate_fd(int fd, int irqnum)
 	ignore_sigio_fd(fd);
 }
 
+/*
+ * Called just before shutdown in order to provide a clean exec
+ * environment in case the system is rebooting.  No locking because
+ * that would cause a pointless shutdown hang if something hadn't
+ * released the lock.
+ */
 int deactivate_all_fds(void)
 {
 	struct irq_fd *irq;
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 0e00cf9..7b3e53f 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -16,7 +16,7 @@ #include "asm/pgtable.h"
 #include "asm/page.h"
 #include "asm/tlbflush.h"
 #include "kern_util.h"
-#include "user_util.h"
+#include "as-layout.h"
 #include "mem_user.h"
 #include "os.h"
 
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index df7d662..72ff856 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -13,8 +13,8 @@ #include "linux/gfp.h"
 #include "asm/page.h"
 #include "asm/fixmap.h"
 #include "asm/pgalloc.h"
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
 #include "kern.h"
 #include "mem_user.h"
 #include "uml_uaccess.h"
@@ -216,7 +216,7 @@ #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_A
 #endif
 }
 
-void paging_init(void)
+void __init paging_init(void)
 {
 	unsigned long zones_size[MAX_NR_ZONES], vaddr;
 	int i;
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 638f3b5..3ba6e4c 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -13,7 +13,7 @@ #include "linux/pfn.h"
 #include "asm/types.h"
 #include "asm/pgtable.h"
 #include "kern_util.h"
-#include "user_util.h"
+#include "as-layout.h"
 #include "mode_kern.h"
 #include "mem.h"
 #include "mem_user.h"
@@ -21,229 +21,8 @@ #include "os.h"
 #include "kern.h"
 #include "init.h"
 
-struct phys_desc {
-	struct rb_node rb;
-	int fd;
-	__u64 offset;
-	void *virt;
-	unsigned long phys;
-	struct list_head list;
-};
-
-static struct rb_root phys_mappings = RB_ROOT;
-
-static struct rb_node **find_rb(void *virt)
-{
-	struct rb_node **n = &phys_mappings.rb_node;
-	struct phys_desc *d;
-
-	while(*n != NULL){
-		d = rb_entry(*n, struct phys_desc, rb);
-		if(d->virt == virt)
-			return n;
-
-		if(d->virt > virt)
-			n = &(*n)->rb_left;
-		else
-			n = &(*n)->rb_right;
-	}
-
-	return n;
-}
-
-static struct phys_desc *find_phys_mapping(void *virt)
-{
-	struct rb_node **n = find_rb(virt);
-
-	if(*n == NULL)
-		return NULL;
-
-	return rb_entry(*n, struct phys_desc, rb);
-}
-
-static void insert_phys_mapping(struct phys_desc *desc)
-{
-	struct rb_node **n = find_rb(desc->virt);
-
-	if(*n != NULL)
-		panic("Physical remapping for %p already present",
-		      desc->virt);
-
-	rb_link_node(&desc->rb, rb_parent(*n), n);
-	rb_insert_color(&desc->rb, &phys_mappings);
-}
-
-LIST_HEAD(descriptor_mappings);
-
-struct desc_mapping {
-	int fd;
-	struct list_head list;
-	struct list_head pages;
-};
-
-static struct desc_mapping *find_mapping(int fd)
-{
-	struct desc_mapping *desc;
-	struct list_head *ele;
-
-	list_for_each(ele, &descriptor_mappings){
-		desc = list_entry(ele, struct desc_mapping, list);
-		if(desc->fd == fd)
-			return desc;
-	}
-
-	return NULL;
-}
-
-static struct desc_mapping *descriptor_mapping(int fd)
-{
-	struct desc_mapping *desc;
-
-	desc = find_mapping(fd);
-	if(desc != NULL)
-		return desc;
-
-	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
-	if(desc == NULL)
-		return NULL;
-
-	*desc = ((struct desc_mapping)
-		{ .fd =		fd,
-		  .list =	LIST_HEAD_INIT(desc->list),
-		  .pages =	LIST_HEAD_INIT(desc->pages) });
-	list_add(&desc->list, &descriptor_mappings);
-
-	return desc;
-}
-
-int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
-{
-	struct desc_mapping *fd_maps;
-	struct phys_desc *desc;
-	unsigned long phys;
-	int err;
-
-	fd_maps = descriptor_mapping(fd);
-	if(fd_maps == NULL)
-		return -ENOMEM;
-
-	phys = __pa(virt);
-	desc = find_phys_mapping(virt);
-	if(desc != NULL)
-		panic("Address 0x%p is already substituted\n", virt);
-
-	err = -ENOMEM;
-	desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
-	if(desc == NULL)
-		goto out;
-
-	*desc = ((struct phys_desc)
-		{ .fd =			fd,
-		  .offset =		offset,
-		  .virt =		virt,
-		  .phys =		__pa(virt),
-		  .list = 		LIST_HEAD_INIT(desc->list) });
-	insert_phys_mapping(desc);
-
-	list_add(&desc->list, &fd_maps->pages);
-
-	virt = (void *) ((unsigned long) virt & PAGE_MASK);
-	err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
-	if(!err)
-		goto out;
-
-	rb_erase(&desc->rb, &phys_mappings);
-	kfree(desc);
- out:
-	return err;
-}
-
 static int physmem_fd = -1;
 
-static void remove_mapping(struct phys_desc *desc)
-{
-	void *virt = desc->virt;
-	int err;
-
-	rb_erase(&desc->rb, &phys_mappings);
-	list_del(&desc->list);
-	kfree(desc);
-
-	err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
-	if(err)
-		panic("Failed to unmap block device page from physical memory, "
-		      "errno = %d", -err);
-}
-
-int physmem_remove_mapping(void *virt)
-{
-	struct phys_desc *desc;
-
-	virt = (void *) ((unsigned long) virt & PAGE_MASK);
-	desc = find_phys_mapping(virt);
-	if(desc == NULL)
-		return 0;
-
-	remove_mapping(desc);
-	return 1;
-}
-
-void physmem_forget_descriptor(int fd)
-{
-	struct desc_mapping *desc;
-	struct phys_desc *page;
-	struct list_head *ele, *next;
-	__u64 offset;
-	void *addr;
-	int err;
-
-	desc = find_mapping(fd);
-	if(desc == NULL)
-		return;
-
-	list_for_each_safe(ele, next, &desc->pages){
-		page = list_entry(ele, struct phys_desc, list);
-		offset = page->offset;
-		addr = page->virt;
-		remove_mapping(page);
-		err = os_seek_file(fd, offset);
-		if(err)
-			panic("physmem_forget_descriptor - failed to seek "
-			      "to %lld in fd %d, error = %d\n",
-			      offset, fd, -err);
-		err = os_read_file(fd, addr, PAGE_SIZE);
-		if(err < 0)
-			panic("physmem_forget_descriptor - failed to read "
-			      "from fd %d to 0x%p, error = %d\n",
-			      fd, addr, -err);
-	}
-
-	list_del(&desc->list);
-	kfree(desc);
-}
-
-EXPORT_SYMBOL(physmem_forget_descriptor);
-EXPORT_SYMBOL(physmem_remove_mapping);
-EXPORT_SYMBOL(physmem_subst_mapping);
-
-void arch_free_page(struct page *page, int order)
-{
-	void *virt;
-	int i;
-
-	for(i = 0; i < (1 << order); i++){
-		virt = __va(page_to_phys(page + i));
-		physmem_remove_mapping(virt);
-	}
-}
-
-int is_remapped(void *virt)
-{
- 	struct phys_desc *desc = find_phys_mapping(virt);
-
-	return desc != NULL;
-}
-
 /* Changed during early boot */
 unsigned long high_physmem;
 
@@ -350,14 +129,9 @@ void setup_physmem(unsigned long start, 
 
 int phys_mapping(unsigned long phys, __u64 *offset_out)
 {
-	struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
 	int fd = -1;
 
-	if(desc != NULL){
-		fd = desc->fd;
-		*offset_out = desc->offset;
-	}
-	else if(phys < physmem_size){
+	if(phys < physmem_size){
 		fd = physmem_fd;
 		*offset_out = phys;
 	}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 348b272..8d2c549 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,8 +32,8 @@ #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 "as-layout.h"
 #include "kern.h"
 #include "signal_kern.h"
 #include "init.h"
@@ -54,11 +54,9 @@ #include "um_malloc.h"
  */
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
-int external_pid(void *t)
+static inline int external_pid(struct task_struct *task)
 {
-	struct task_struct *task = t ? t : current;
-
-	return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
+	return CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task);
 }
 
 int pid_to_processor_id(int pid)
@@ -66,9 +64,10 @@ int pid_to_processor_id(int pid)
 	int i;
 
 	for(i = 0; i < ncpus; i++){
-		if(cpu_tasks[i].pid == pid) return(i);
+		if(cpu_tasks[i].pid == pid)
+			return i;
 	}
-	return(-1);
+	return -1;
 }
 
 void free_stack(unsigned long stack, int order)
@@ -85,9 +84,9 @@ unsigned long alloc_stack(int order, int
 		flags = GFP_ATOMIC;
 	page = __get_free_pages(flags, order);
 	if(page == 0)
-		return(0);
+		return 0;
 	stack_protections(page);
-	return(page);
+	return page;
 }
 
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
@@ -98,15 +97,11 @@ int kernel_thread(int (*fn)(void *), voi
 	current->thread.request.u.thread.arg = arg;
 	pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
 		      &current->thread.regs, 0, NULL, NULL);
-	if(pid < 0)
-		panic("do_fork failed in kernel_thread, errno = %d", pid);
-	return(pid);
+	return pid;
 }
 
-void set_current(void *t)
+static inline void set_current(struct task_struct *task)
 {
-	struct task_struct *task = t;
-
 	cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
 		{ external_pid(task), task });
 }
@@ -128,14 +123,16 @@ void *_switch_to(void *prev, void *next,
 		prev= current;
 	} while(current->thread.saved_task);
 
-	return(current->thread.prev_sched);
+	return current->thread.prev_sched;
 
 }
 
 void interrupt_end(void)
 {
-	if(need_resched()) schedule();
-	if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
+	if(need_resched())
+		schedule();
+	if(test_tsk_thread_flag(current, TIF_SIGPENDING))
+		do_signal();
 }
 
 void release_thread(struct task_struct *task)
@@ -150,7 +147,7 @@ void exit_thread(void)
 
 void *get_current(void)
 {
-	return(current);
+	return current;
 }
 
 int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
@@ -188,15 +185,12 @@ void initial_thread_cb(void (*proc)(void
 	kmalloc_ok = save_kmalloc_ok;
 }
 
+#ifdef CONFIG_MODE_TT
 unsigned long stack_sp(unsigned long page)
 {
-	return(page + PAGE_SIZE - sizeof(void *));
-}
-
-int current_pid(void)
-{
-	return(current->pid);
+	return page + PAGE_SIZE - sizeof(void *);
 }
+#endif
 
 void default_idle(void)
 {
@@ -221,11 +215,6 @@ 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)
 {
@@ -236,68 +225,43 @@ void *um_virt_to_phys(struct task_struct
 	pte_t ptent;
 
 	if(task->mm == NULL)
-		return(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 	pgd = pgd_offset(task->mm, addr);
 	if(!pgd_present(*pgd))
-		return(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	pud = pud_offset(pgd, addr);
 	if(!pud_present(*pud))
-		return(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	pmd = pmd_offset(pud, addr);
 	if(!pmd_present(*pmd))
-		return(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	pte = pte_offset_kernel(pmd, addr);
 	ptent = *pte;
 	if(!pte_present(ptent))
-		return(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	if(pte_out != NULL)
 		*pte_out = ptent;
-	return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
+	return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK);
 }
 
 char *current_cmd(void)
 {
 #if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
-	return("(Unknown)");
+	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(&current->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);
@@ -313,36 +277,17 @@ 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);
+	return stack != (unsigned long) current_thread;
 }
 
 extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -363,22 +308,22 @@ char *uml_strdup(char *string)
 
 int copy_to_user_proc(void __user *to, void *from, int size)
 {
-	return(copy_to_user(to, from, 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));
+	return copy_from_user(to, from, size);
 }
 
 int clear_user_proc(void __user *buf, int size)
 {
-	return(clear_user(buf, size));
+	return clear_user(buf, size);
 }
 
 int strlen_user_proc(char __user *str)
 {
-	return(strlen_user(str));
+	return strlen_user(str);
 }
 
 int smp_sigio_handler(void)
@@ -387,14 +332,14 @@ #ifdef CONFIG_SMP
 	int cpu = current_thread->cpu;
 	IPI_handler(cpu);
 	if(cpu != 0)
-		return(1);
+		return 1;
 #endif
-	return(0);
+	return 0;
 }
 
 int cpu(void)
 {
-	return(current_thread->cpu);
+	return current_thread->cpu;
 }
 
 static atomic_t using_sysemu = ATOMIC_INIT(0);
@@ -443,7 +388,7 @@ int __init make_proc_sysemu(void)
 	if (ent == NULL)
 	{
 		printk(KERN_WARNING "Failed to register /proc/sysemu\n");
-		return(0);
+		return 0;
 	}
 
 	ent->read_proc  = proc_read_sysemu;
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index f602623..7e4305a 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -6,7 +6,6 @@
 #include "linux/module.h"
 #include "linux/sched.h"
 #include "asm/smp.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "os.h"
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 3c798cd..c4020c3 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -17,7 +17,6 @@ #include "linux/ptrace.h"
 #include "asm/signal.h"
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
-#include "user_util.h"
 #include "asm/ucontext.h"
 #include "kern_util.h"
 #include "signal_kern.h"
diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c
index 54b7959..580eb64 100644
--- a/arch/um/kernel/skas/exec.c
+++ b/arch/um/kernel/skas/exec.c
@@ -17,7 +17,17 @@ #include "os.h"
 
 void flush_thread_skas(void)
 {
-	force_flush_all();
+	void *data = NULL;
+	unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+	int ret;
+
+	ret = unmap(&current->mm->context.skas.id, 0, end, 1, &data);
+	if(ret){
+		printk("flush_thread_skas - clearing address space failed, "
+		       "err = %d\n", ret);
+		force_sig(SIGKILL, current);
+	}
+
 	switch_mm_skas(&current->mm->context.skas.id);
 }
 
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index ae4fa71..ef36fac 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -13,9 +13,9 @@ #include "linux/init.h"
 #include "asm/uaccess.h"
 #include "asm/atomic.h"
 #include "kern_util.h"
+#include "as-layout.h"
 #include "skas.h"
 #include "os.h"
-#include "user_util.h"
 #include "tlb.h"
 #include "kern.h"
 #include "mode.h"
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 27eb29c..c0f0693 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -10,7 +10,6 @@ #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "asm/mmu.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "mem.h"
 #include "skas.h"
@@ -28,19 +27,17 @@ static int do_ops(union mm_context *mmu,
 		switch(op->type){
 		case MMAP:
 			ret = map(&mmu->skas.id, op->u.mmap.addr,
-				  op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
-				  op->u.mmap.x, op->u.mmap.fd,
-				  op->u.mmap.offset, finished, flush);
+				  op->u.mmap.len, op->u.mmap.prot,
+				  op->u.mmap.fd, op->u.mmap.offset, finished,
+				  flush);
 			break;
 		case MUNMAP:
-			ret = unmap(&mmu->skas.id,
-				    (void *) op->u.munmap.addr,
+			ret = unmap(&mmu->skas.id, op->u.munmap.addr,
 				    op->u.munmap.len, finished, flush);
 			break;
 		case MPROTECT:
 			ret = protect(&mmu->skas.id, op->u.mprotect.addr,
-				      op->u.mprotect.len, op->u.mprotect.r,
-				      op->u.mprotect.w, op->u.mprotect.x,
+				      op->u.mprotect.len, op->u.mprotect.prot,
 				      finished, flush);
 			break;
 		default:
@@ -92,6 +89,76 @@ void flush_tlb_mm_skas(struct mm_struct 
 
 void force_flush_all_skas(void)
 {
-	unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
-        fix_range(current->mm, 0, end, 1);
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma = mm->mmap;
+
+	while(vma != NULL) {
+		fix_range(mm, vma->vm_start, vma->vm_end, 1);
+		vma = vma->vm_next;
+	}
+}
+
+void flush_tlb_page_skas(struct vm_area_struct *vma, unsigned long address)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	struct mm_struct *mm = vma->vm_mm;
+	void *flush = NULL;
+	int r, w, x, prot, err = 0;
+	struct mm_id *mm_id;
+
+	pgd = pgd_offset(mm, address);
+	if(!pgd_present(*pgd))
+		goto kill;
+
+	pud = pud_offset(pgd, address);
+	if(!pud_present(*pud))
+		goto kill;
+
+	pmd = pmd_offset(pud, address);
+	if(!pmd_present(*pmd))
+		goto kill;
+
+	pte = pte_offset_kernel(pmd, address);
+
+	r = pte_read(*pte);
+	w = pte_write(*pte);
+	x = pte_exec(*pte);
+	if (!pte_young(*pte)) {
+		r = 0;
+		w = 0;
+	} else if (!pte_dirty(*pte)) {
+		w = 0;
+	}
+
+	mm_id = &mm->context.skas.id;
+	prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+		(x ? UM_PROT_EXEC : 0));
+	if(pte_newpage(*pte)){
+		if(pte_present(*pte)){
+			unsigned long long offset;
+			int fd;
+
+			fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
+			err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
+				  1, &flush);
+		}
+		else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
+	}
+	else if(pte_newprot(*pte))
+		err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+
+	if(err)
+		goto kill;
+
+	*pte = pte_mkuptodate(*pte);
+
+	return;
+
+kill:
+	printk("Failed to flush page for address 0x%lx\n", address);
+	force_sig(SIGKILL, current);
 }
+
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 759b070..e6a7778 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -21,7 +21,6 @@ #include "linux/hardirq.h"
 #include "asm/smp.h"
 #include "asm/processor.h"
 #include "asm/spinlock.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "irq_user.h"
@@ -90,7 +89,7 @@ static int idle_proc(void *cpup)
 
 	cpu_set(cpu, cpu_online_map);
 	default_idle();
-	return(0);
+	return 0;
 }
 
 static struct task_struct *idle_thread(int cpu)
@@ -98,8 +97,8 @@ static struct task_struct *idle_thread(i
 	struct task_struct *new_task;
 	unsigned char c;
 
-        current->thread.request.u.thread.proc = idle_proc;
-        current->thread.request.u.thread.arg = (void *) cpu;
+	current->thread.request.u.thread.proc = idle_proc;
+	current->thread.request.u.thread.arg = (void *) cpu;
 	new_task = fork_idle(cpu);
 	if(IS_ERR(new_task))
 		panic("copy_process failed in idle_thread, error = %ld",
@@ -110,9 +109,9 @@ static struct task_struct *idle_thread(i
 			    .task = 	new_task } );
 	idle_threads[cpu] = new_task;
 	CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
-			  sizeof(c)),
+				  sizeof(c)),
 		    ({ panic("skas mode doesn't support SMP"); }));
-	return(new_task);
+	return new_task;
 }
 
 void smp_prepare_cpus(unsigned int maxcpus)
@@ -163,13 +162,13 @@ int __cpu_up(unsigned int cpu)
 	cpu_set(cpu, smp_commenced_mask);
 	while (!cpu_isset(cpu, cpu_online_map))
 		mb();
-	return(0);
+	return 0;
 }
 
 int setup_profiling_timer(unsigned int multiplier)
 {
 	printk(KERN_INFO "setup_profiling_timer\n");
-	return(0);
+	return 0;
 }
 
 void smp_call_function_slave(int cpu);
@@ -205,7 +204,7 @@ void IPI_handler(int cpu)
 
 int hard_smp_processor_id(void)
 {
-	return(pid_to_processor_id(os_getpid()));
+	return pid_to_processor_id(os_getpid());
 }
 
 static DEFINE_SPINLOCK(call_lock);
@@ -254,14 +253,3 @@ int smp_call_function(void (*_func)(void
 }
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index 2828c52..237c4ea 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -18,7 +18,6 @@ #include "linux/utime.h"
 #include "asm/mman.h"
 #include "asm/uaccess.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "sysdep/syscalls.h"
 #include "mode_kern.h"
 #include "choose-mode.h"
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index f9e02b3..9326357 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -10,7 +10,6 @@ #include "linux/kallsyms.h"
 #include "asm/page.h"
 #include "asm/processor.h"
 #include "sysrq.h"
-#include "user_util.h"
 
 /* Catch non-i386 SUBARCH's. */
 #if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index b1f8b07..259c49d 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -18,7 +18,6 @@ #include "asm/irq.h"
 #include "asm/param.h"
 #include "asm/current.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "mode.h"
 #include "os.h"
 
@@ -35,8 +34,8 @@ unsigned long long sched_clock(void)
 	return (unsigned long long)jiffies_64 * (1000000000 / HZ);
 }
 
-static unsigned long long prev_nsecs[NR_CPUS];
 #ifdef CONFIG_UML_REAL_TIME_CLOCK
+static unsigned long long prev_nsecs[NR_CPUS];
 static long long delta[NR_CPUS];		/* Deviation per interval */
 #endif
 
@@ -95,7 +94,12 @@ irqreturn_t um_timer(int irq, void *dev)
 
 	do_timer(1);
 
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
 	nsecs = get_time();
+#else
+	nsecs = (unsigned long long) xtime.tv_sec * BILLION + xtime.tv_nsec +
+		BILLION / HZ;
+#endif
 	xtime.tv_sec = nsecs / NSEC_PER_SEC;
 	xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
 
@@ -128,13 +132,18 @@ void time_init(void)
 	nsecs = os_nsecs();
 	set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
 				-nsecs % BILLION);
+	set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION);
 	late_time_init = register_timer;
 }
 
 void do_gettimeofday(struct timeval *tv)
 {
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
 	unsigned long long nsecs = get_time();
-
+#else
+	unsigned long long nsecs = (unsigned long long) xtime.tv_sec * BILLION +
+		xtime.tv_nsec;
+#endif
 	tv->tv_sec = nsecs / NSEC_PER_SEC;
 	/* Careful about calculations here - this was originally done as
 	 * (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC
@@ -168,6 +177,8 @@ int do_settimeofday(struct timespec *tv)
 
 void timer_handler(int sig, union uml_pt_regs *regs)
 {
+	if(current_thread->cpu == 0)
+		timer_irq(regs);
 	local_irq_disable();
 	irq_enter();
 	update_process_times(CHOOSE_MODE(
@@ -175,6 +186,4 @@ void timer_handler(int sig, union uml_pt
 			     (regs)->skas.is_user));
 	irq_exit();
 	local_irq_enable();
-	if(current_thread->cpu == 0)
-		timer_irq(regs);
 }
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 54a5ff2..8a8d528 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -6,17 +6,18 @@
 #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgalloc.h"
+#include "asm/pgtable.h"
 #include "asm/tlbflush.h"
 #include "choose-mode.h"
 #include "mode_kern.h"
-#include "user_util.h"
+#include "as-layout.h"
 #include "tlb.h"
 #include "mem.h"
 #include "mem_user.h"
 #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,
+		    unsigned int prot, 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 **))
@@ -30,8 +31,7 @@ static int add_mmap(unsigned long virt, 
 		last = &ops[*index];
 		if((last->type == MMAP) &&
 		   (last->u.mmap.addr + last->u.mmap.len == virt) &&
-		   (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
-		   (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+		   (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) &&
 		   (last->u.mmap.offset + last->u.mmap.len == offset)){
 			last->u.mmap.len += len;
 			return 0;
@@ -47,9 +47,7 @@ static int add_mmap(unsigned long virt, 
 			     			.u = { .mmap = {
 						       .addr	= virt,
 						       .len	= len,
-						       .r	= r,
-						       .w	= w,
-						       .x	= x,
+						       .prot	= prot,
 						       .fd	= fd,
 						       .offset	= offset }
 			   } });
@@ -86,8 +84,8 @@ static int add_munmap(unsigned long addr
 	return ret;
 }
 
-static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
-			int x, struct host_vm_op *ops, int *index,
+static int add_mprotect(unsigned long addr, unsigned long len,
+			unsigned int prot, 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 **))
@@ -99,8 +97,7 @@ static int add_mprotect(unsigned long ad
 		last = &ops[*index];
 		if((last->type == MPROTECT) &&
 		   (last->u.mprotect.addr + last->u.mprotect.len == addr) &&
-		   (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
-		   (last->u.mprotect.x == x)){
+		   (last->u.mprotect.prot == prot)){
 			last->u.mprotect.len += len;
 			return 0;
 		}
@@ -115,114 +112,145 @@ static int add_mprotect(unsigned long ad
 			     		       .u = { .mprotect = {
 						       .addr	= addr,
 						       .len	= len,
-						       .r	= r,
-						       .w	= w,
-						       .x	= x } } });
+						       .prot	= prot } } });
 	return ret;
 }
 
 #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
 
+static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
+				   unsigned long end, struct host_vm_op *ops,
+				   int last_op, int *op_index, int force,
+				   union mm_context *mmu, void **flush,
+				   int (*do_ops)(union mm_context *,
+						 struct host_vm_op *, int, int,
+						 void **))
+{
+	pte_t *pte;
+	int r, w, x, prot, ret = 0;
+
+	pte = pte_offset_kernel(pmd, addr);
+	do {
+		r = pte_read(*pte);
+		w = pte_write(*pte);
+		x = pte_exec(*pte);
+		if (!pte_young(*pte)) {
+			r = 0;
+			w = 0;
+		} else if (!pte_dirty(*pte)) {
+			w = 0;
+		}
+		prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+			(x ? UM_PROT_EXEC : 0));
+		if(force || pte_newpage(*pte)){
+			if(pte_present(*pte))
+				ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK,
+					       PAGE_SIZE, prot, 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(*pte))
+			ret = add_mprotect(addr, PAGE_SIZE, prot, ops, op_index,
+					   last_op, mmu, flush, do_ops);
+		*pte = pte_mkuptodate(*pte);
+	} while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret));
+	return ret;
+}
+
+static inline int update_pmd_range(pud_t *pud, unsigned long addr,
+				   unsigned long end, struct host_vm_op *ops,
+				   int last_op, int *op_index, int force,
+				   union mm_context *mmu, void **flush,
+				   int (*do_ops)(union mm_context *,
+						 struct host_vm_op *, int, int,
+						 void **))
+{
+	pmd_t *pmd;
+	unsigned long next;
+	int ret = 0;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+		if(!pmd_present(*pmd)){
+			if(force || pmd_newpage(*pmd)){
+				ret = add_munmap(addr, next - addr, ops,
+						 op_index, last_op, mmu,
+						 flush, do_ops);
+				pmd_mkuptodate(*pmd);
+			}
+		}
+		else ret = update_pte_range(pmd, addr, next, ops, last_op,
+					    op_index, force, mmu, flush,
+					    do_ops);
+	} while (pmd++, addr = next, ((addr != end) && !ret));
+	return ret;
+}
+
+static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
+				   unsigned long end, struct host_vm_op *ops,
+				   int last_op, int *op_index, int force,
+				   union mm_context *mmu, void **flush,
+				   int (*do_ops)(union mm_context *,
+						 struct host_vm_op *, int, int,
+						 void **))
+{
+	pud_t *pud;
+	unsigned long next;
+	int ret = 0;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if(!pud_present(*pud)){
+			if(force || pud_newpage(*pud)){
+				ret = add_munmap(addr, next - addr, ops,
+						 op_index, last_op, mmu,
+						 flush, do_ops);
+				pud_mkuptodate(*pud);
+			}
+		}
+		else ret = update_pmd_range(pud, addr, next, ops, last_op,
+					    op_index, force, mmu, flush,
+					    do_ops);
+	} while (pud++, addr = next, ((addr != end) && !ret));
+	return ret;
+}
+
 void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
 		      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;
+	pgd_t *pgd;
 	union mm_context *mmu = &mm->context;
-	unsigned long addr, end;
-	int r, w, x;
 	struct host_vm_op ops[1];
+	unsigned long addr = start_addr, next;
+	int ret = 0, last_op = ARRAY_SIZE(ops) - 1, op_index = -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,
+	pgd = pgd_offset(mm, addr);
+	do {
+		next = pgd_addr_end(addr, end_addr);
+		if(!pgd_present(*pgd)){
+			if (force || pgd_newpage(*pgd)){
+				ret = add_munmap(addr, next - addr, ops,
 						 &op_index, last_op, mmu,
 						 &flush, do_ops);
-				pmd_mkuptodate(*npmd);
+				pgd_mkuptodate(*pgd);
 			}
-			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);
-			else ret = add_munmap(addr, PAGE_SIZE, ops,
-					      &op_index, last_op, mmu,
-					      &flush, do_ops);
 		}
-		else if(pte_newprot(*npte))
-			ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
-					   &op_index, last_op, mmu,
-					   &flush, do_ops);
+		else ret = update_pud_range(pgd, addr, next, ops, last_op,
+					    &op_index, force, mmu, &flush,
+					    do_ops);
+	} while (pgd++, addr = next, ((addr != end_addr) && !ret));
 
-		*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);
@@ -343,12 +371,6 @@ pte_t *addr_pte(struct task_struct *task
 	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);
-}
-
 void flush_tlb_all(void)
 {
 	flush_tlb_mm(current->mm);
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 26f15c4..abab90c 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -18,8 +18,9 @@ #include "asm/a.out.h"
 #include "asm/current.h"
 #include "asm/irq.h"
 #include "sysdep/sigcontext.h"
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
+#include "arch.h"
 #include "kern.h"
 #include "chan_kern.h"
 #include "mconsole_kern.h"
@@ -71,8 +72,8 @@ good_area:
 		goto out;
 
 	/* Don't require VM_READ|VM_EXEC for write faults! */
-        if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
-                goto out;
+	if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
+		goto out;
 
 	do {
 survive:
@@ -156,20 +157,23 @@ static void segv_handler(int sig, union 
  * the info in the regs. A pointer to the info then would
  * give us bad data!
  */
-unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
+unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
+		   union uml_pt_regs *regs)
 {
 	struct siginfo si;
 	void *catcher;
 	int err;
-        int is_write = FAULT_WRITE(fi);
-        unsigned long address = FAULT_ADDRESS(fi);
+	int is_write = FAULT_WRITE(fi);
+	unsigned long address = FAULT_ADDRESS(fi);
 
-        if(!is_user && (address >= start_vm) && (address < end_vm)){
-                flush_tlb_kernel_vm();
-                return(0);
-        }
-	else if(current->mm == NULL)
-		panic("Segfault with no mm");
+	if(!is_user && (address >= start_vm) && (address < end_vm)){
+		flush_tlb_kernel_vm();
+		return 0;
+	}
+	else if(current->mm == NULL) {
+		show_regs(container_of(regs, struct pt_regs, regs));
+  		panic("Segfault with no mm");
+	}
 
 	if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
 		err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -182,26 +186,28 @@ unsigned long segv(struct faultinfo fi, 
 
 	catcher = current->thread.fault_catcher;
 	if(!err)
-		return(0);
+		return 0;
 	else if(catcher != NULL){
 		current->thread.fault_addr = (void *) address;
 		do_longjmp(catcher, 1);
 	}
 	else if(current->thread.fault_addr != NULL)
 		panic("fault_addr set but no fault catcher");
-        else if(!is_user && arch_fixup(ip, sc))
-		return(0);
+	else if(!is_user && arch_fixup(ip, regs))
+		return 0;
 
- 	if(!is_user)
+	if(!is_user) {
+		show_regs(container_of(regs, struct pt_regs, regs));
 		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
 		      address, ip);
+	}
 
 	if (err == -EACCES) {
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;
 		si.si_code = BUS_ADRERR;
 		si.si_addr = (void __user *)address;
-                current->thread.arch.faultinfo = fi;
+		current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGBUS, &si, current);
 	} else if (err == -ENOMEM) {
 		printk("VM: killing process %s\n", current->comm);
@@ -210,10 +216,10 @@ unsigned long segv(struct faultinfo fi, 
 		BUG_ON(err != -EFAULT);
 		si.si_signo = SIGSEGV;
 		si.si_addr = (void __user *) address;
-                current->thread.arch.faultinfo = fi;
+		current->thread.arch.faultinfo = fi;
 		force_sig_info(SIGSEGV, &si, current);
 	}
-	return(0);
+	return 0;
 }
 
 void relay_signal(int sig, union uml_pt_regs *regs)
@@ -223,12 +229,12 @@ void relay_signal(int sig, union uml_pt_
 
 	if(!UPT_IS_USER(regs)){
 		if(sig == SIGBUS)
-			printk("Bus error - the /dev/shm or /tmp mount likely "
-			       "just ran out of space\n");
+			printk("Bus error - the host /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);
+	current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
 	force_sig(sig, current);
 }
 
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index ad66df1..98e2174 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -10,7 +10,6 @@ #include "asm/ptrace.h"
 #include "asm/uaccess.h"
 #include "asm/pgalloc.h"
 #include "asm/tlbflush.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "irq_user.h"
 #include "mem_user.h"
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
index a92c02f..7b5f218 100644
--- a/arch/um/kernel/tt/exec_user.c
+++ b/arch/um/kernel/tt/exec_user.c
@@ -10,7 +10,6 @@ #include <sched.h>
 #include <errno.h>
 #include <sys/wait.h>
 #include <signal.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "ptrace_user.h"
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
index 8eba8f7..030e465 100644
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -17,7 +17,6 @@ #include "init.h"
 #include "user.h"
 #include "debug.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "tt.h"
 #include "sysdep/thread.h"
 #include "os.h"
@@ -115,6 +114,8 @@ struct gdb_data {
 	int err;
 };
 
+extern char *linux_prog;
+
 static void config_gdb_cb(void *arg)
 {
 	struct gdb_data *data = arg;
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
deleted file mode 100644
index 2a35b15..0000000
--- a/arch/um/kernel/tt/include/mode_kern-tt.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_MODE_KERN_H__
-#define __TT_MODE_KERN_H__
-
-#include "linux/sched.h"
-#include "asm/page.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-
-extern void switch_to_tt(void *prev, void *next);
-extern void flush_thread_tt(void);
-extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
-			   unsigned long esp);
-extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
-			  unsigned long stack_top, struct task_struct *p,
-			  struct pt_regs *regs);
-extern void release_thread_tt(struct task_struct *task);
-extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
-extern void init_idle_tt(void);
-extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
-extern void flush_tlb_kernel_vm_tt(void);
-extern void __flush_tlb_one_tt(unsigned long addr);
-extern void flush_tlb_range_tt(struct vm_area_struct *vma,
-			       unsigned long start, unsigned long end);
-extern void flush_tlb_mm_tt(struct mm_struct *mm);
-extern void force_flush_all_tt(void);
-extern long execute_syscall_tt(void *r);
-extern void before_mem_tt(unsigned long brk_start);
-extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
-				       unsigned long *task_size_out);
-extern int start_uml_tt(void);
-extern int external_pid_tt(struct task_struct *task);
-extern int thread_pid_tt(struct task_struct *task);
-
-#define kmem_end_tt (host_task_size - ABOVE_KMEM)
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
index 4d1929d..d0c3c49 100644
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -8,7 +8,6 @@ #include "linux/mm.h"
 #include "asm/uaccess.h"
 #include "mem_user.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "kern.h"
 #include "tt.h"
 
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
index 03e5898..9774f63 100644
--- a/arch/um/kernel/tt/mem_user.c
+++ b/arch/um/kernel/tt/mem_user.c
@@ -11,7 +11,6 @@ #include <errno.h>
 #include <sys/mman.h>
 #include "tt.h"
 #include "mem_user.h"
-#include "user_util.h"
 #include "os.h"
 
 void remap_data(void *segment_start, void *segment_end, int w)
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 1e86f0b..c631303 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -14,7 +14,6 @@ #include "asm/ptrace.h"
 #include "asm/tlbflush.h"
 #include "irq_user.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "os.h"
 #include "kern.h"
 #include "sigcontext.h"
@@ -65,7 +64,8 @@ #endif
 	if(from->thread.mode.tt.switch_pipe[0] == -1)
 		os_kill_process(os_getpid(), 0);
 
-	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
+	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c,
+			     sizeof(c));
 	if(err != sizeof(c))
 		panic("read of switch_pipe failed, errno = %d", -err);
 
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
index 58800c5..420c23f 100644
--- a/arch/um/kernel/tt/ptproxy/proxy.c
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -26,7 +26,6 @@ #include "ptproxy.h"
 #include "sysdep.h"
 #include "wait.h"
 
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 #include "tempfile.h"
@@ -339,11 +338,12 @@ #endif
 			       "err = %d\n", -fd);
 			exit(1);
 		}
-		os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+		os_write_file(fd, gdb_init_string,
+			      sizeof(gdb_init_string) - 1);
 		if(startup){
 			if(stop){
 				os_write_file(fd, "b start_kernel\n",
-				      strlen("b start_kernel\n"));
+						strlen("b start_kernel\n"));
 			}
 			os_write_file(fd, "c\n", strlen("c\n"));
 		}
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
index 0377442..4b4f617 100644
--- a/arch/um/kernel/tt/ptproxy/ptrace.c
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -16,7 +16,6 @@ #include <sys/wait.h>
 
 #include "ptproxy.h"
 #include "debug.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "ptrace_user.h"
 #include "tt.h"
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
index 99f1783..e0e1ab0 100644
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -13,7 +13,6 @@ #include <errno.h>
 #include <sys/types.h>
 #include <linux/unistd.h>
 #include "ptrace_user.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
index 12f6319..bdd4af4 100644
--- a/arch/um/kernel/tt/ptproxy/wait.c
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -13,7 +13,6 @@ #include <sys/wait.h>
 #include "ptproxy.h"
 #include "sysdep.h"
 #include "wait.h"
-#include "user_util.h"
 #include "ptrace_user.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
index 902987b..f52b47a 100644
--- a/arch/um/kernel/tt/syscall_user.c
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -11,7 +11,6 @@ #include "sysdep/ptrace.h"
 #include "sigcontext.h"
 #include "ptrace_user.h"
 #include "task.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "syscall.h"
 #include "tt.h"
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index ae6217c..7caa24f 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -12,7 +12,6 @@ #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "asm/uaccess.h"
 #include "asm/tlbflush.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "os.h"
 #include "tlb.h"
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
index b919535..c235883 100644
--- a/arch/um/kernel/tt/tracer.c
+++ b/arch/um/kernel/tt/tracer.c
@@ -19,7 +19,6 @@ #include "sysdep/ptrace.h"
 #include "sigcontext.h"
 #include "sysdep/sigcontext.h"
 #include "os.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "process.h"
 #include "kern_util.h"
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
index b5d9d64..3032eb5 100644
--- a/arch/um/kernel/tt/trap_user.c
+++ b/arch/um/kernel/tt/trap_user.c
@@ -8,7 +8,6 @@ #include <errno.h>
 #include <signal.h>
 #include "sysdep/ptrace.h"
 #include "sysdep/sigcontext.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "task.h"
 #include "tt.h"
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index ed1abcf..0e5c82c 100644
--- a/arch/um/kernel/tt/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -5,7 +5,6 @@
  */
 
 #include <string.h>
-#include "user_util.h"
 #include "uml_uaccess.h"
 #include "task.h"
 #include "kern_util.h"
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 89c6dba..1cf954a 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -17,6 +17,7 @@ #include "linux/sysrq.h"
 #include "linux/seq_file.h"
 #include "linux/delay.h"
 #include "linux/module.h"
+#include "linux/utsname.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
 #include "asm/ptrace.h"
@@ -25,8 +26,9 @@ #include "asm/user.h"
 #include "asm/setup.h"
 #include "ubd_user.h"
 #include "asm/current.h"
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
+#include "arch.h"
 #include "kern.h"
 #include "mem_user.h"
 #include "mem.h"
@@ -42,7 +44,7 @@ #endif
 
 #define DEFAULT_COMMAND_LINE "root=98:0"
 
-/* Changed in linux_main and setup_arch, which run before SMP is started */
+/* Changed in add_arg and setup_arch, which run before SMP is started */
 static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
 
 static void __init add_arg(char *arg)
@@ -56,17 +58,25 @@ static void __init add_arg(char *arg)
 	strcat(command_line, arg);
 }
 
-struct cpuinfo_um boot_cpu_data = { 
+/*
+ * These fields are initialized at boot time and not changed.
+ * XXX This structure is used only in the non-SMP case.  Maybe this
+ * should be moved to smp.c.
+ */
+struct cpuinfo_um boot_cpu_data = {
 	.loops_per_jiffy	= 0,
 	.ipi_pipe		= { -1, -1 }
 };
 
 unsigned long thread_saved_pc(struct task_struct *task)
 {
-	return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
-					      task)));
+	return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+					      task));
 }
 
+/* Changed in setup_arch, which is called in early boot */
+static char host_info[(__NEW_UTS_LEN + 1) * 5];
+
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
 	int index = 0;
@@ -86,7 +96,7 @@ #endif
 		   loops_per_jiffy/(500000/HZ),
 		   (loops_per_jiffy/(5000/HZ)) % 100);
 
-	return(0);
+	return 0;
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
@@ -114,14 +124,12 @@ const struct seq_operations cpuinfo_op =
 /* Set in linux_main */
 unsigned long host_task_size;
 unsigned long task_size;
-
-unsigned long uml_start;
-
-/* Set in early boot */
 unsigned long uml_physmem;
-unsigned long uml_reserved;
+unsigned long uml_reserved; /* Also modified in mem_init */
 unsigned long start_vm;
 unsigned long end_vm;
+
+/* Set in uml_ncpus_setup */
 int ncpus = 1;
 
 #ifdef CONFIG_CMDLINE_ON_HOST
@@ -135,6 +143,8 @@ #endif
 
 /* Set in early boot */
 static int have_root __initdata = 0;
+
+/* Set in uml_mem_setup and modified in linux_main */
 long long physmem_size = 32 * 1024 * 1024;
 
 void set_cmdline(char *cmd)
@@ -212,12 +222,12 @@ #endif
 #ifdef CONFIG_SMP
 static int __init uml_ncpus_setup(char *line, int *add)
 {
-       if (!sscanf(line, "%d", &ncpus)) {
-               printf("Couldn't parse [%s]\n", line);
-               return -1;
-       }
+	if (!sscanf(line, "%d", &ncpus)) {
+		printf("Couldn't parse [%s]\n", line);
+		return -1;
+	}
 
-       return 0;
+	return 0;
 }
 
 __uml_setup("ncpus=", uml_ncpus_setup,
@@ -234,7 +244,7 @@ #define DEFAULT_TT 0
 static int __init mode_tt_setup(char *line, int *add)
 {
 	force_tt = 1;
-	return(0);
+	return 0;
 }
 
 #else
@@ -245,7 +255,7 @@ #define DEFAULT_TT 0
 static int __init mode_tt_setup(char *line, int *add)
 {
 	printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
-	return(0);
+	return 0;
 }
 
 #else
@@ -256,7 +266,7 @@ #define DEFAULT_TT 1
 static int __init mode_tt_setup(char *line, int *add)
 {
 	printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
-	return(0);
+	return 0;
 }
 
 #endif
@@ -274,16 +284,15 @@ int mode_tt = DEFAULT_TT;
 
 static int __init Usage(char *line, int *add)
 {
- 	const char **p;
+	const char **p;
 
 	printf(usage_string, init_utsname()->release);
- 	p = &__uml_help_start;
- 	while (p < &__uml_help_end) {
- 		printf("%s", *p);
- 		p++;
- 	}
+	p = &__uml_help_start;
+	while (p < &__uml_help_end) {
+		printf("%s", *p);
+		p++;
+	}
 	exit(0);
-
 	return 0;
 }
 
@@ -374,13 +383,12 @@ #endif
 
 	printf("UML running in %s mode\n", mode);
 
-	uml_start = (unsigned long) &__binary_start;
 	host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
 					  set_task_sizes_skas, &task_size);
 
 	/*
- 	 * Setting up handlers to 'sig_info' struct
- 	 */
+	 * Setting up handlers to 'sig_info' struct
+	 */
 	os_fill_handlinfo(handlinfo_kern);
 
 	brk_start = (unsigned long) sbrk(0);
@@ -396,7 +404,7 @@ #endif
 		physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
 	}
 
-	uml_physmem = uml_start & PAGE_MASK;
+	uml_physmem = (unsigned long) &__binary_start & PAGE_MASK;
 
 	/* Reserve up to 4M after the current brk */
 	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
@@ -407,7 +415,7 @@ #ifdef CONFIG_CMDLINE_ON_HOST
 	argv1_begin = argv[1];
 	argv1_end = &argv[1][strlen(argv[1])];
 #endif
-  
+
 	highmem = 0;
 	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
 	max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
@@ -449,12 +457,12 @@ #endif
 		printf("Kernel virtual memory size shrunk to %lu bytes\n",
 		       virtmem_size);
 
-  	uml_postsetup();
+	uml_postsetup();
 
 	task_protections((unsigned long) &init_thread_info);
 	os_flush_stdout();
 
-	return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+	return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
 }
 
 extern int uml_exitcode;
@@ -466,8 +474,8 @@ static int panic_exit(struct notifier_bl
 	show_regs(&(current->thread.regs));
 	bust_spinlocks(0);
 	uml_exitcode = 1;
-	machine_halt();
-	return(0);
+	os_dump_core();
+	return 0;
 }
 
 static struct notifier_block panic_exit_notifier = {
@@ -482,14 +490,14 @@ void __init setup_arch(char **cmdline_p)
 			&panic_exit_notifier);
 	paging_init();
 	strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
- 	*cmdline_p = command_line;
-	setup_hostinfo();
+	*cmdline_p = command_line;
+	setup_hostinfo(host_info, sizeof host_info);
 }
 
 void __init check_bugs(void)
 {
 	arch_check_bugs();
- 	os_check_bugs();
+	os_check_bugs();
 }
 
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index 6ff1274..9bf944f 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -132,10 +132,10 @@ static int aio_thread(void *arg)
 				{ .data = (void *) (long) event.data,
 						.err	= event.res });
 			reply_fd = ((struct aio_context *) reply.data)->reply_fd;
-			err = os_write_file(reply_fd, &reply, sizeof(reply));
+			err = write(reply_fd, &reply, sizeof(reply));
 			if(err != sizeof(reply))
 				printk("aio_thread - write failed, fd = %d, "
-				       "err = %d\n", reply_fd, -err);
+				       "err = %d\n", reply_fd, errno);
 		}
 	}
 	return 0;
@@ -146,38 +146,31 @@ #endif
 static int do_not_aio(struct aio_thread_req *req)
 {
 	char c;
-	int err;
+	unsigned long long actual;
+	int n;
+
+	actual = lseek64(req->io_fd, req->offset, SEEK_SET);
+	if(actual != req->offset)
+		return -errno;
 
 	switch(req->type){
 	case AIO_READ:
-		err = os_seek_file(req->io_fd, req->offset);
-		if(err)
-			goto out;
-
-		err = os_read_file(req->io_fd, req->buf, req->len);
+		n = read(req->io_fd, req->buf, req->len);
 		break;
 	case AIO_WRITE:
-		err = os_seek_file(req->io_fd, req->offset);
-		if(err)
-			goto out;
-
-		err = os_write_file(req->io_fd, req->buf, req->len);
+		n = write(req->io_fd, req->buf, req->len);
 		break;
 	case AIO_MMAP:
-		err = os_seek_file(req->io_fd, req->offset);
-		if(err)
-			goto out;
-
-		err = os_read_file(req->io_fd, &c, sizeof(c));
+		n = read(req->io_fd, &c, sizeof(c));
 		break;
 	default:
 		printk("do_not_aio - bad request type : %d\n", req->type);
-		err = -EINVAL;
-		break;
+		return -EINVAL;
 	}
 
-out:
-	return err;
+	if(n < 0)
+		return -errno;
+	return 0;
 }
 
 /* These are initialized in initcalls and not changed */
@@ -193,12 +186,12 @@ static int not_aio_thread(void *arg)
 
 	signal(SIGWINCH, SIG_IGN);
 	while(1){
-		err = os_read_file(aio_req_fd_r, &req, sizeof(req));
+		err = read(aio_req_fd_r, &req, sizeof(req));
 		if(err != sizeof(req)){
 			if(err < 0)
 				printk("not_aio_thread - read failed, "
 				       "fd = %d, err = %d\n", aio_req_fd_r,
-				       -err);
+				       errno);
 			else {
 				printk("not_aio_thread - short read, fd = %d, "
 				       "length = %d\n", aio_req_fd_r, err);
@@ -207,11 +200,11 @@ static int not_aio_thread(void *arg)
 		}
 		err = do_not_aio(&req);
 		reply = ((struct aio_thread_reply) { .data 	= req.aio,
-					 .err	= err });
-		err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
+						     .err	= err });
+		err = write(req.aio->reply_fd, &reply, sizeof(reply));
 		if(err != sizeof(reply))
 			printk("not_aio_thread - write failed, fd = %d, "
-			       "err = %d\n", req.aio->reply_fd, -err);
+			       "err = %d\n", req.aio->reply_fd, errno);
 	}
 
 	return 0;
@@ -228,6 +221,11 @@ static int init_aio_24(void)
 
 	aio_req_fd_w = fds[0];
 	aio_req_fd_r = fds[1];
+
+	err = os_set_fd_block(aio_req_fd_w, 0);
+	if(err)
+		goto out_close_pipe;
+
 	err = run_helper_thread(not_aio_thread, NULL,
 				CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
 	if(err < 0)
@@ -285,10 +283,12 @@ static int submit_aio_26(enum aio_type t
 	if(err){
 		reply = ((struct aio_thread_reply) { .data = aio,
 					 .err  = err });
-		err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
-		if(err != sizeof(reply))
+		err = write(aio->reply_fd, &reply, sizeof(reply));
+		if(err != sizeof(reply)){
+			err = -errno;
 			printk("submit_aio_26 - write failed, "
 			       "fd = %d, err = %d\n", aio->reply_fd, -err);
+		}
 		else err = 0;
 	}
 
@@ -383,9 +383,10 @@ static int submit_aio_24(enum aio_type t
 	};
 	int err;
 
-	err = os_write_file(aio_req_fd_w, &req, sizeof(req));
+	err = write(aio_req_fd_w, &req, sizeof(req));
 	if(err == sizeof(req))
 		err = 0;
+	else err = -errno;
 
 	return err;
 }
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 7054182..1268914 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -43,7 +43,7 @@ static int etap_read(int fd, struct sk_b
 
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
 	if(*skb == NULL) return(-ENOMEM);
-	len = net_recvfrom(fd, (*skb)->mac.raw, 
+	len = net_recvfrom(fd, skb_mac_header(*skb),
 			   (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
 	if(len <= 0) return(len);
 	skb_pull(*skb, 2);
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index 863981b..acba301 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
  * James Leu (jleu@mindspring.net).
  * Copyright (C) 2001 by various other people who didn't put their name here.
  * Licensed under the GPL.
@@ -16,19 +16,20 @@ #include <sys/un.h>
 #include <net/if.h>
 #include "user.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "net_user.h"
 #include "etap.h"
 #include "os.h"
 #include "um_malloc.h"
+#include "kern_constants.h"
 
 #define MAX_PACKET ETH_MAX_PACKET
 
-void etap_user_init(void *data, void *dev)
+static int etap_user_init(void *data, void *dev)
 {
 	struct ethertap_data *pri = data;
 
 	pri->dev = dev;
+	return 0;
 }
 
 struct addr_change {
@@ -47,13 +48,16 @@ static void etap_change(int op, unsigned
 	change.what = op;
 	memcpy(change.addr, addr, sizeof(change.addr));
 	memcpy(change.netmask, netmask, sizeof(change.netmask));
-	n = os_write_file(fd, &change, sizeof(change));
-	if(n != sizeof(change))
-		printk("etap_change - request failed, err = %d\n", -n);
-	output = um_kmalloc(page_size());
+	CATCH_EINTR(n = write(fd, &change, sizeof(change)));
+	if(n != sizeof(change)){
+		printk("etap_change - request failed, err = %d\n", errno);
+		return;
+	}
+
+	output = um_kmalloc(UM_KERN_PAGE_SIZE);
 	if(output == NULL)
 		printk("etap_change : Failed to allocate output buffer\n");
-	read_output(fd, output, page_size());
+	read_output(fd, output, UM_KERN_PAGE_SIZE);
 	if(output != NULL){
 		printk("%s", output);
 		kfree(output);
@@ -115,13 +119,15 @@ static int etap_tramp(char *dev, char *g
 	pe_data.data_me = data_me;
 	pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
 
-	if(pid < 0) err = pid;
+	if(pid < 0)
+		err = pid;
 	os_close_file(data_remote);
 	os_close_file(control_remote);
-	n = os_read_file(control_me, &c, sizeof(c));
+	CATCH_EINTR(n = read(control_me, &c, sizeof(c)));
 	if(n != sizeof(c)){
-		printk("etap_tramp : read of status failed, err = %d\n", -n);
-		return(-EINVAL);
+		err = -errno;
+		printk("etap_tramp : read of status failed, err = %d\n", -err);
+		return err;
 	}
 	if(c != 1){
 		printk("etap_tramp : uml_net failed\n");
@@ -132,7 +138,7 @@ static int etap_tramp(char *dev, char *g
 		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
 			printk("uml_net didn't exit with status 1\n");
 	}
-	return(err);
+	return err;
 }
 
 static int etap_open(void *data)
@@ -142,23 +148,24 @@ static int etap_open(void *data)
 	int data_fds[2], control_fds[2], err, output_len;
 
 	err = tap_open_common(pri->dev, pri->gate_addr);
-	if(err) return(err);
+	if(err)
+		return err;
 
 	err = os_pipe(data_fds, 0, 0);
 	if(err < 0){
 		printk("data os_pipe failed - err = %d\n", -err);
-		return(err);
+		return err;
 	}
 
 	err = os_pipe(control_fds, 1, 0);
 	if(err < 0){
 		printk("control os_pipe failed - err = %d\n", -err);
-		return(err);
+		return err;
 	}
-	
+
 	err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 
 			 control_fds[1], data_fds[0], data_fds[1]);
-	output_len = page_size();
+	output_len = UM_KERN_PAGE_SIZE;
 	output = um_kmalloc(output_len);
 	read_output(control_fds[0], output, output_len);
 
@@ -171,13 +178,13 @@ static int etap_open(void *data)
 
 	if(err < 0){
 		printk("etap_tramp failed - err = %d\n", -err);
-		return(err);
+		return err;
 	}
 
 	pri->data_fd = data_fds[0];
 	pri->control_fd = control_fds[0];
 	iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
-	return(data_fds[0]);
+	return data_fds[0];
 }
 
 static void etap_close(int fd, void *data)
@@ -195,7 +202,7 @@ static void etap_close(int fd, void *dat
 
 static int etap_set_mtu(int mtu, void *data)
 {
-	return(mtu);
+	return mtu;
 }
 
 static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
@@ -204,7 +211,8 @@ static void etap_add_addr(unsigned char 
 	struct ethertap_data *pri = data;
 
 	tap_check_ips(pri->gate_addr, addr);
-	if(pri->control_fd == -1) return;
+	if(pri->control_fd == -1)
+		return;
 	etap_open_addr(addr, netmask, &pri->control_fd);
 }
 
@@ -213,7 +221,8 @@ static void etap_del_addr(unsigned char 
 {
 	struct ethertap_data *pri = data;
 
-	if(pri->control_fd == -1) return;
+	if(pri->control_fd == -1)
+		return;
 	etap_close_addr(addr, netmask, &pri->control_fd);
 }
 
@@ -227,14 +236,3 @@ const struct net_user_info ethertap_user
 	.delete_address = etap_del_addr,
 	.max_packet	= MAX_PACKET - ETH_HEADER_ETHERTAP
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
index 76570a2..f1714e7 100644
--- a/arch/um/os-Linux/drivers/tuntap_kern.c
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -43,7 +43,7 @@ static int tuntap_read(int fd, struct sk
 {
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
 	if(*skb == NULL) return(-ENOMEM);
-	return(net_read(fd, (*skb)->mac.raw, 
+	return(net_read(fd, skb_mac_header(*skb),
 			(*skb)->dev->mtu + ETH_HEADER_OTHER));
 }
 
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index e846b23..11a9779 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -18,17 +18,17 @@ #include <linux/if_tun.h>
 #include "net_user.h"
 #include "tuntap.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "user.h"
 #include "os.h"
 
 #define MAX_PACKET ETH_MAX_PACKET
 
-void tuntap_user_init(void *data, void *dev)
+static int tuntap_user_init(void *data, void *dev)
 {
 	struct tuntap_data *pri = data;
 
 	pri->dev = dev;
+	return 0;
 }
 
 static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
@@ -37,7 +37,8 @@ static void tuntap_add_addr(unsigned cha
 	struct tuntap_data *pri = data;
 
 	tap_check_ips(pri->gate_addr, addr);
-	if((pri->fd == -1) || pri->fixed_config) return;
+	if((pri->fd == -1) || pri->fixed_config)
+		return;
 	open_addr(addr, netmask, pri->dev_name);
 }
 
@@ -46,7 +47,8 @@ static void tuntap_del_addr(unsigned cha
 {
 	struct tuntap_data *pri = data;
 
-	if((pri->fd == -1) || pri->fixed_config) return;
+	if((pri->fd == -1) || pri->fixed_config)
+		return;
 	close_addr(addr, netmask, pri->dev_name);
 }
 
@@ -58,7 +60,7 @@ struct tuntap_pre_exec_data {
 static void tuntap_pre_exec(void *arg)
 {
 	struct tuntap_pre_exec_data *data = arg;
-	
+
 	dup2(data->stdout, 1);
 	os_close_file(data->close_me);
 }
@@ -83,7 +85,8 @@ static int tuntap_open_tramp(char *gate,
 
 	pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
 
-	if(pid < 0) return(-pid);
+	if(pid < 0)
+		return -pid;
 
 	os_close_file(remote);
 
@@ -114,16 +117,16 @@ static int tuntap_open_tramp(char *gate,
 	cmsg = CMSG_FIRSTHDR(&msg);
 	if(cmsg == NULL){
 		printk("tuntap_open_tramp : didn't receive a message\n");
-		return(-EINVAL);
+		return -EINVAL;
 	}
 	if((cmsg->cmsg_level != SOL_SOCKET) || 
 	   (cmsg->cmsg_type != SCM_RIGHTS)){
 		printk("tuntap_open_tramp : didn't receive a descriptor\n");
-		return(-EINVAL);
+		return -EINVAL;
 	}
 	*fd_out = ((int *) CMSG_DATA(cmsg))[0];
 	os_set_exec_close(*fd_out, 1);
-	return(0);
+	return 0;
 }
 
 static int tuntap_open(void *data)
@@ -135,7 +138,7 @@ static int tuntap_open(void *data)
 
 	err = tap_open_common(pri->dev, pri->gate_addr);
 	if(err < 0)
-		return(err);
+		return err;
 
 	if(pri->fixed_config){
 		pri->fd = os_open_file("/dev/net/tun",
@@ -143,7 +146,7 @@ static int tuntap_open(void *data)
 		if(pri->fd < 0){
 			printk("Failed to open /dev/net/tun, err = %d\n",
 			       -pri->fd);
-			return(pri->fd);
+			return pri->fd;
 		}
 		memset(&ifr, 0, sizeof(ifr));
 		ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -160,7 +163,7 @@ static int tuntap_open(void *data)
 		if(err < 0){
 			printk("tuntap_open : os_pipe failed - err = %d\n",
 			       -err);
-			return(err);
+			return err;
 		}
 
 		buffer = get_output_buffer(&len);
@@ -175,7 +178,7 @@ static int tuntap_open(void *data)
 			printk("%s", output);
 			free_output_buffer(buffer);
 			printk("tuntap_open_tramp failed - err = %d\n", -err);
-			return(err);
+			return err;
 		}
 
 		pri->dev_name = uml_strdup(buffer);
@@ -187,7 +190,7 @@ static int tuntap_open(void *data)
 		iter_addresses(pri->dev, open_addr, pri->dev_name);
 	}
 
-	return(pri->fd);
+	return pri->fd;
 }
 
 static void tuntap_close(int fd, void *data)
@@ -202,7 +205,7 @@ static void tuntap_close(int fd, void *d
 
 static int tuntap_set_mtu(int mtu, void *data)
 {
-	return(mtu);
+	return mtu;
 }
 
 const struct net_user_info tuntap_user_info = {
@@ -215,14 +218,3 @@ const struct net_user_info tuntap_user_i
 	.delete_address = tuntap_del_addr,
 	.max_packet	= MAX_PACKET
 };
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 371b433..6f92f73 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -18,7 +18,6 @@ #include <sys/uio.h>
 #include "os.h"
 #include "user.h"
 #include "kern_util.h"
-#include "user_util.h"
 
 static void copy_stat(struct uml_stat *dst, struct stat64 *src)
 {
@@ -291,54 +290,22 @@ int os_seek_file(int fd, __u64 offset)
 	return 0;
 }
 
-static int fault_buffer(void *start, int len,
-			int (*copy_proc)(void *addr, void *buf, int len))
-{
-	int page = getpagesize(), i;
-	char c;
-
-	for(i = 0; i < len; i += page){
-		if((*copy_proc)(start + i, &c, sizeof(c)))
-			return -EFAULT;
-	}
-	if((len % page) != 0){
-		if((*copy_proc)(start + len - 1, &c, sizeof(c)))
-			return -EFAULT;
-	}
-	return 0;
-}
-
-static int file_io(int fd, void *buf, int len,
-		   int (*io_proc)(int fd, void *buf, int len),
-		   int (*copy_user_proc)(void *addr, void *buf, int len))
+int os_read_file(int fd, void *buf, int len)
 {
-	int n, err;
-
-	do {
-		n = (*io_proc)(fd, buf, len);
-		if((n < 0) && (errno == EFAULT)){
-			err = fault_buffer(buf, len, copy_user_proc);
-			if(err)
-				return err;
-			n = (*io_proc)(fd, buf, len);
-		}
-	} while((n < 0) && (errno == EINTR));
+	int n = read(fd, buf, len);
 
 	if(n < 0)
 		return -errno;
 	return n;
 }
 
-int os_read_file(int fd, void *buf, int len)
-{
-	return file_io(fd, buf, len, (int (*)(int, void *, int)) read,
-		       copy_from_user_proc);
-}
-
 int os_write_file(int fd, const void *buf, int len)
 {
-	return file_io(fd, (void *) buf, len,
-		       (int (*)(int, void *, int)) write, copy_to_user_proc);
+	int n = write(fd, (void *) buf, len);
+
+	if(n < 0)
+		return -errno;
+	return n;
 }
 
 int os_file_size(char *file, unsigned long long *size_out)
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index c7ad630..97bed16 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -13,9 +13,9 @@ #include <sys/signal.h>
 #include <sys/wait.h>
 #include "user.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "os.h"
 #include "um_malloc.h"
+#include "kern_constants.h"
 
 struct helper_data {
 	void (*pre_exec)(void*);
@@ -25,28 +25,18 @@ struct helper_data {
 	char *buf;
 };
 
-/* Debugging aid, changed only from gdb */
-int helper_pause = 0;
-
-static void helper_hup(int sig)
-{
-}
-
 static int helper_child(void *arg)
 {
 	struct helper_data *data = arg;
 	char **argv = data->argv;
 	int errval;
 
-	if (helper_pause){
-		signal(SIGHUP, helper_hup);
-		pause();
-	}
 	if (data->pre_exec != NULL)
 		(*data->pre_exec)(data->pre_data);
 	errval = execvp_noalloc(data->buf, argv[0], argv);
-	printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], -errval);
-	os_write_file(data->fd, &errval, sizeof(errval));
+	printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0],
+	       -errval);
+	write(data->fd, &errval, sizeof(errval));
 	kill(os_getpid(), SIGKILL);
 	return 0;
 }
@@ -81,7 +71,7 @@ int run_helper(void (*pre_exec)(void *),
 		goto out_close;
 	}
 
-	sp = stack + page_size() - sizeof(void *);
+	sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
 	data.pre_exec = pre_exec;
 	data.pre_data = pre_data;
 	data.argv = argv;
@@ -98,13 +88,16 @@ int run_helper(void (*pre_exec)(void *),
 	close(fds[1]);
 	fds[1] = -1;
 
-	/* 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));
+	/*
+	 * 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 = read(fds[0], &ret, sizeof(ret));
 	if (n == 0) {
 		ret = pid;
 	} else {
 		if (n < 0) {
+			n = -errno;
 			printk("run_helper : read on pipe failed, ret = %d\n",
 			       -n);
 			ret = n;
@@ -135,7 +128,7 @@ int run_helper_thread(int (*proc)(void *
 	if (stack == 0)
 		return -ENOMEM;
 
-	sp = stack + (page_size() << stack_order) - sizeof(void *);
+	sp = stack + (UM_KERN_PAGE_SIZE << stack_order) - sizeof(void *);
 	pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
 	if (pid < 0) {
 		err = -errno;
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index d1b61d4..a633fa8 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -11,7 +11,6 @@ #include <string.h>
 #include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/time.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "process.h"
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 685feaa..ea9a236 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -13,8 +13,8 @@ #include <sys/resource.h>
 #include <sys/mman.h>
 #include <sys/user.h>
 #include <asm/page.h>
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
 #include "mem_user.h"
 #include "irq_user.h"
 #include "user.h"
@@ -25,12 +25,7 @@ #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.
- */
-unsigned long stacksizelim;
-
-/* Set in main */
+/* Set in main, unchanged thereafter */
 char *linux_prog;
 
 #define PGD_BOUND (4 * 1024 * 1024)
@@ -52,7 +47,6 @@ static void set_stklim(void)
 			exit(1);
 		}
 	}
-	stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
 }
 
 static __init void do_uml_initcalls(void)
@@ -126,7 +120,7 @@ extern int uml_exitcode;
 
 extern void scan_elf_aux( char **envp);
 
-int main(int argc, char **argv, char **envp)
+int __init main(int argc, char **argv, char **envp)
 {
 	char **new_argv;
 	int ret, i, err;
@@ -224,7 +218,7 @@ #endif
 		ret = 1;
 	}
 	printf("\n");
-	return(uml_exitcode);
+	return uml_exitcode;
 }
 
 #define CAN_KMALLOC() \
@@ -237,7 +231,7 @@ void *__wrap_malloc(int size)
 	void *ret;
 
 	if(!CAN_KMALLOC())
-		return(__real_malloc(size));
+		return __real_malloc(size);
 	else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
 		ret = um_kmalloc(size);
 	else ret = um_vmalloc(size);
@@ -248,16 +242,17 @@ void *__wrap_malloc(int size)
 	if(ret == NULL)
 		errno = ENOMEM;
 
-	return(ret);
+	return ret;
 }
 
 void *__wrap_calloc(int n, int size)
 {
 	void *ptr = __wrap_malloc(n * size);
 
-	if(ptr == NULL) return(NULL);
+	if(ptr == NULL)
+		return NULL;
 	memset(ptr, 0, n * size);
-	return(ptr);
+	return ptr;
 }
 
 extern void __real_free(void *);
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index f1ea169..c6378c6 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -11,7 +11,6 @@ #include <sys/mman.h>
 #include <sys/statfs.h>
 #include "kern_util.h"
 #include "user.h"
-#include "user_util.h"
 #include "mem_user.h"
 #include "init.h"
 #include "os.h"
@@ -165,7 +164,8 @@ found:
  * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger).
  * So it isn't 'static' yet.
  */
-int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+int __init make_tempfile(const char *template, char **out_tempname,
+			 int do_unlink)
 {
 	char *tempname;
 	int fd;
@@ -206,7 +206,7 @@ #define TEMPNAME_TEMPLATE "vm_file-XXXXX
  * This proc is used in start_up.c
  * So it isn't 'static'.
  */
-int create_tmp_file(unsigned long long len)
+int __init create_tmp_file(unsigned long long len)
 {
 	int fd, err;
 	char zero;
@@ -232,17 +232,16 @@ int create_tmp_file(unsigned long long l
 
 	zero = 0;
 
-	err = os_write_file(fd, &zero, 1);
+	err = write(fd, &zero, 1);
 	if(err != 1){
-		errno = -err;
-		perror("os_write_file");
+		perror("write");
 		exit(1);
 	}
 
 	return fd;
 }
 
-int create_mem_file(unsigned long long len)
+int __init create_mem_file(unsigned long long len)
 {
 	int err, fd;
 
@@ -257,7 +256,7 @@ int create_mem_file(unsigned long long l
 }
 
 
-void check_tmpexec(void)
+void __init check_tmpexec(void)
 {
 	void *addr;
 	int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 76bdd67..92a7b59 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -14,7 +14,6 @@ #include <sys/syscall.h>
 #include "ptrace_user.h"
 #include "os.h"
 #include "user.h"
-#include "user_util.h"
 #include "process.h"
 #include "irq_user.h"
 #include "kern_util.h"
@@ -22,6 +21,7 @@ #include "longjmp.h"
 #include "skas_ptrace.h"
 #include "kern_constants.h"
 #include "uml-config.h"
+#include "init.h"
 
 #define ARBITRARY_ADDR -1
 #define FAILURE_PID    -1
@@ -40,14 +40,14 @@ unsigned long os_process_pc(int pid)
 	if(fd < 0){
 		printk("os_process_pc - couldn't open '%s', err = %d\n",
 		       proc_stat, -fd);
-		return(ARBITRARY_ADDR);
+		return ARBITRARY_ADDR;
 	}
-	err = os_read_file(fd, buf, sizeof(buf));
+	CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
 	if(err < 0){
 		printk("os_process_pc - couldn't read '%s', err = %d\n",
-		       proc_stat, -err);
+		       proc_stat, errno);
 		os_close_file(fd);
-		return(ARBITRARY_ADDR);
+		return ARBITRARY_ADDR;
 	}
 	os_close_file(fd);
 	pc = ARBITRARY_ADDR;
@@ -56,7 +56,7 @@ unsigned long os_process_pc(int pid)
 		  "%*d %*d %*d %*d %*d %lu", &pc) != 1){
 		printk("os_process_pc - couldn't find pc in '%s'\n", buf);
 	}
-	return(pc);
+	return pc;
 }
 
 int os_process_parent(int pid)
@@ -65,21 +65,22 @@ int os_process_parent(int pid)
 	char data[256];
 	int parent, n, fd;
 
-	if(pid == -1) return(-1);
+	if(pid == -1)
+		return -1;
 
 	snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
 	fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
 	if(fd < 0){
 		printk("Couldn't open '%s', err = %d\n", stat, -fd);
-		return(FAILURE_PID);
+		return FAILURE_PID;
 	}
 
-	n = os_read_file(fd, data, sizeof(data));
+	CATCH_EINTR(n = read(fd, data, sizeof(data)));
 	os_close_file(fd);
 
 	if(n < 0){
-		printk("Couldn't read '%s', err = %d\n", stat, -n);
-		return(FAILURE_PID);
+		printk("Couldn't read '%s', err = %d\n", stat, errno);
+		return FAILURE_PID;
 	}
 
 	parent = FAILURE_PID;
@@ -87,7 +88,7 @@ int os_process_parent(int pid)
 	if(n != 1)
 		printk("Failed to scan '%s'\n", data);
 
-	return(parent);
+	return parent;
 }
 
 void os_stop_process(int pid)
@@ -145,7 +146,7 @@ #endif
 
 int os_getpid(void)
 {
-	return(syscall(__NR_getpid));
+	return syscall(__NR_getpid);
 }
 
 int os_getpgrp(void)
@@ -165,8 +166,8 @@ int os_map_memory(void *virt, int fd, un
 	loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
 		     fd, off);
 	if(loc == MAP_FAILED)
-		return(-errno);
-	return(0);
+		return -errno;
+	return 0;
 }
 
 int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
@@ -175,8 +176,8 @@ int os_protect_memory(void *addr, unsign
 		    (x ? PROT_EXEC : 0));
 
         if(mprotect(addr, len, prot) < 0)
-		return(-errno);
-        return(0);
+		return -errno;
+        return 0;
 }
 
 int os_unmap_memory(void *addr, int len)
@@ -185,15 +186,15 @@ int os_unmap_memory(void *addr, int len)
 
         err = munmap(addr, len);
 	if(err < 0)
-		return(-errno);
-        return(0);
+		return -errno;
+        return 0;
 }
 
 #ifndef MADV_REMOVE
 #define MADV_REMOVE KERNEL_MADV_REMOVE
 #endif
 
-int os_drop_memory(void *addr, int length)
+int __init os_drop_memory(void *addr, int length)
 {
 	int err;
 
@@ -203,7 +204,7 @@ int os_drop_memory(void *addr, int lengt
 	return err;
 }
 
-int can_drop_memory(void)
+int __init can_drop_memory(void)
 {
 	void *addr;
 	int fd, ok = 0;
@@ -244,7 +245,7 @@ void init_new_thread_stack(void *sig_sta
 
 	if(sig_stack != NULL){
 		pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
-		set_sigstack(sig_stack, pages * page_size());
+		set_sigstack(sig_stack, pages * UM_KERN_PAGE_SIZE);
 		flags = SA_ONSTACK;
 	}
 	if(usr1_handler){
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index 3fc43b3..8d4e0c6 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -8,6 +8,7 @@ #include <stdlib.h>
 #include <termios.h>
 #include <pty.h>
 #include <signal.h>
+#include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <sched.h>
@@ -16,10 +17,10 @@ #include <sys/poll.h>
 #include "init.h"
 #include "user.h"
 #include "kern_util.h"
-#include "user_util.h"
 #include "sigio.h"
 #include "os.h"
 #include "um_malloc.h"
+#include "init.h"
 
 /* Protected by sigio_lock(), also used by sigio_cleanup, which is an
  * exitcall.
@@ -68,11 +69,12 @@ static int write_sigio_thread(void *unus
 			p = &fds->poll[i];
 			if(p->revents == 0) continue;
 			if(p->fd == sigio_private[1]){
-				n = os_read_file(sigio_private[1], &c, sizeof(c));
+				CATCH_EINTR(n = read(sigio_private[1], &c,
+						     sizeof(c)));
 				if(n != sizeof(c))
 					printk("write_sigio_thread : "
 					       "read on socket failed, "
-					       "err = %d\n", -n);
+					       "err = %d\n", errno);
 				tmp = current_poll;
 				current_poll = next_poll;
 				next_poll = tmp;
@@ -85,10 +87,10 @@ static int write_sigio_thread(void *unus
 					(fds->used - i) * sizeof(*fds->poll));
 			}
 
-			n = os_write_file(respond_fd, &c, sizeof(c));
+			CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
 			if(n != sizeof(c))
 				printk("write_sigio_thread : write on socket "
-				       "failed, err = %d\n", -n);
+				       "failed, err = %d\n", errno);
 		}
 	}
 
@@ -126,15 +128,15 @@ static void update_thread(void)
 	char c;
 
 	flags = set_signals(0);
-	n = os_write_file(sigio_private[0], &c, sizeof(c));
+	n = write(sigio_private[0], &c, sizeof(c));
 	if(n != sizeof(c)){
-		printk("update_thread : write failed, err = %d\n", -n);
+		printk("update_thread : write failed, err = %d\n", errno);
 		goto fail;
 	}
 
-	n = os_read_file(sigio_private[0], &c, sizeof(c));
+	CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
 	if(n != sizeof(c)){
-		printk("update_thread : read failed, err = %d\n", -n);
+		printk("update_thread : read failed, err = %d\n", errno);
 		goto fail;
 	}
 
@@ -320,6 +322,10 @@ out_close1:
 	close(l_write_sigio_fds[1]);
 }
 
+/* Changed during early boot */
+static int pty_output_sigio = 0;
+static int pty_close_sigio = 0;
+
 void maybe_sigio_broken(int fd, int read)
 {
 	int err;
@@ -357,3 +363,143 @@ static void sigio_cleanup(void)
 }
 
 __uml_exitcall(sigio_cleanup);
+
+/* Used as a flag during SIGIO testing early in boot */
+static volatile int got_sigio = 0;
+
+static void __init handler(int sig)
+{
+	got_sigio = 1;
+}
+
+struct openpty_arg {
+	int master;
+	int slave;
+	int err;
+};
+
+static void openpty_cb(void *arg)
+{
+	struct openpty_arg *info = arg;
+
+	info->err = 0;
+	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+		info->err = -errno;
+}
+
+static int async_pty(int master, int slave)
+{
+	int flags;
+
+	flags = fcntl(master, F_GETFL);
+	if(flags < 0)
+		return -errno;
+
+	if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+	   (fcntl(master, F_SETOWN, os_getpid()) < 0))
+		return -errno;
+
+	if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+		return -errno;
+
+	return(0);
+}
+
+static void __init check_one_sigio(void (*proc)(int, int))
+{
+	struct sigaction old, new;
+	struct openpty_arg pty = { .master = -1, .slave = -1 };
+	int master, slave, err;
+
+	initial_thread_cb(openpty_cb, &pty);
+	if(pty.err){
+		printk("openpty failed, errno = %d\n", -pty.err);
+		return;
+	}
+
+	master = pty.master;
+	slave = pty.slave;
+
+	if((master == -1) || (slave == -1)){
+		printk("openpty failed to allocate a pty\n");
+		return;
+	}
+
+	/* Not now, but complain so we now where we failed. */
+	err = raw(master);
+	if (err < 0)
+		panic("check_sigio : __raw failed, errno = %d\n", -err);
+
+	err = async_pty(master, slave);
+	if(err < 0)
+		panic("tty_fds : sigio_async failed, err = %d\n", -err);
+
+	if(sigaction(SIGIO, NULL, &old) < 0)
+		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+	new = old;
+	new.sa_handler = handler;
+	if(sigaction(SIGIO, &new, NULL) < 0)
+		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+
+	got_sigio = 0;
+	(*proc)(master, slave);
+
+	close(master);
+	close(slave);
+
+	if(sigaction(SIGIO, &old, NULL) < 0)
+		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+	int n;
+	char buf[512];
+
+	printk("Checking that host ptys support output SIGIO...");
+
+	memset(buf, 0, sizeof(buf));
+
+	while(write(master, buf, sizeof(buf)) > 0) ;
+	if(errno != EAGAIN)
+		panic("tty_output : write failed, errno = %d\n", errno);
+	while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+	if(got_sigio){
+		printk("Yes\n");
+		pty_output_sigio = 1;
+	}
+	else if(n == -EAGAIN)
+		printk("No, enabling workaround\n");
+	else panic("tty_output : read failed, err = %d\n", n);
+}
+
+static void tty_close(int master, int slave)
+{
+	printk("Checking that host ptys support SIGIO on close...");
+
+	close(slave);
+	if(got_sigio){
+		printk("Yes\n");
+		pty_close_sigio = 1;
+	}
+	else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+		printk("No pseudo-terminals available - skipping pty SIGIO "
+		       "check\n");
+		return;
+	}
+	check_one_sigio(tty_output);
+	check_one_sigio(tty_close);
+}
+
+/* Here because it only does the SIGIO testing for now */
+void __init os_check_bugs(void)
+{
+	check_sigio();
+}
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 2667686..48d4934 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -11,7 +11,6 @@ #include <errno.h>
 #include <stdarg.h>
 #include <string.h>
 #include <sys/mman.h>
-#include "user_util.h"
 #include "user.h"
 #include "signal_kern.h"
 #include "sysdep/sigcontext.h"
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 9383e87..8e490ff 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -6,6 +6,7 @@
 #include <signal.h>
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
 #include <asm/page.h>
@@ -17,17 +18,17 @@ #include "user.h"
 #include "os.h"
 #include "proc_mm.h"
 #include "ptrace_user.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "task.h"
 #include "registers.h"
 #include "uml-config.h"
 #include "sysdep/ptrace.h"
 #include "sysdep/stub.h"
+#include "init.h"
 
 extern unsigned long batch_syscall_stub, __syscall_stub_start;
 
-extern void wait_stub_done(int pid, int sig, char * fname);
+extern void wait_stub_done(int pid);
 
 static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
 					      unsigned long *stack)
@@ -39,6 +40,19 @@ static inline unsigned long *check_init_
 	return stack;
 }
 
+static unsigned long syscall_regs[MAX_REG_NR];
+
+static int __init init_syscall_regs(void)
+{
+	get_safe_registers(syscall_regs, NULL);
+	syscall_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+		((unsigned long) &batch_syscall_stub -
+		 (unsigned long) &__syscall_stub_start);
+	return 0;
+}
+
+__initcall(init_syscall_regs);
+
 extern int proc_mm;
 
 int single_count = 0;
@@ -47,12 +61,11 @@ int multi_op_count = 0;
 
 static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
 {
-	unsigned long regs[MAX_REG_NR];
 	int n, i;
 	long ret, offset;
 	unsigned long * data;
 	unsigned long * syscall;
-	int pid = mm_idp->u.pid;
+	int err, pid = mm_idp->u.pid;
 
 	if(proc_mm)
 #warning Need to look up userspace_pid by cpu
@@ -60,21 +73,21 @@ #warning Need to look up userspace_pid b
 
 	multi_count++;
 
-	get_safe_registers(regs, NULL);
-	regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
-		((unsigned long) &batch_syscall_stub -
-		 (unsigned long) &__syscall_stub_start);
-
-	n = ptrace_setregs(pid, regs);
+	n = ptrace_setregs(pid, syscall_regs);
 	if(n < 0){
 		printk("Registers - \n");
 		for(i = 0; i < MAX_REG_NR; i++)
-			printk("\t%d\t0x%lx\n", i, regs[i]);
+			printk("\t%d\t0x%lx\n", i, syscall_regs[i]);
 		panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
 		      -n);
 	}
 
-	wait_stub_done(pid, 0, "do_syscall_stub");
+	err = ptrace(PTRACE_CONT, pid, 0, 0);
+	if(err)
+		panic("Failed to continue stub, pid = %d, errno = %d\n", pid,
+		      errno);
+
+	wait_stub_done(pid);
 
 	/* When the stub stops, we find the following values on the
 	 * beginning of the stack:
@@ -176,14 +189,10 @@ long syscall_stub_data(struct mm_id * mm
 	return 0;
 }
 
-int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
-	int r, int w, int x, int phys_fd, unsigned long long offset,
-	int done, void **data)
+int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot,
+	int phys_fd, unsigned long long offset, int done, void **data)
 {
-	int prot, ret;
-
-	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
-		(x ? PROT_EXEC : 0);
+	int ret;
 
 	if(proc_mm){
 		struct proc_mm_op map;
@@ -200,9 +209,11 @@ int map(struct mm_id * mm_idp, unsigned 
 					   .fd	= phys_fd,
 					   .offset= offset
 					 } } } );
-		ret = os_write_file(fd, &map, sizeof(map));
-		if(ret != sizeof(map))
+		CATCH_EINTR(ret = write(fd, &map, sizeof(map)));
+		if(ret != sizeof(map)){
+			ret = -errno;
 			printk("map : /proc/mm map failed, err = %d\n", -ret);
+		}
 		else ret = 0;
 	}
 	else {
@@ -217,8 +228,8 @@ int map(struct mm_id * mm_idp, unsigned 
 	return ret;
 }
 
-int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
-	  void **data)
+int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
+	  int done, void **data)
 {
 	int ret;
 
@@ -232,9 +243,11 @@ int unmap(struct mm_id * mm_idp, void *a
 					   { .addr	=
 					     (unsigned long) addr,
 					     .len		= len } } } );
-		ret = os_write_file(fd, &unmap, sizeof(unmap));
-		if(ret != sizeof(unmap))
+		CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap)));
+		if(ret != sizeof(unmap)){
+			ret = -errno;
 			printk("unmap - proc_mm write returned %d\n", ret);
+		}
 		else ret = 0;
 	}
 	else {
@@ -249,13 +262,11 @@ int unmap(struct mm_id * mm_idp, void *a
 }
 
 int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
-	    int r, int w, int x, int done, void **data)
+	    unsigned int prot, int done, void **data)
 {
 	struct proc_mm_op protect;
-	int prot, ret;
+	int ret;
 
-	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
-		(x ? PROT_EXEC : 0);
 	if(proc_mm){
 		int fd = mm_idp->u.mm_fd;
 
@@ -267,9 +278,11 @@ int protect(struct mm_id * mm_idp, unsig
 					       .len	= len,
 					       .prot	= prot } } } );
 
-		ret = os_write_file(fd, &protect, sizeof(protect));
-		if(ret != sizeof(protect))
+		CATCH_EINTR(ret = write(fd, &protect, sizeof(protect)));
+		if(ret != sizeof(protect)){
+			ret = -errno;
 			printk("protect failed, err = %d", -ret);
+		}
 		else ret = 0;
 	}
 	else {
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 0564422..5c088a5 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -18,7 +18,6 @@ #include <sys/syscall.h>
 #include <asm/types.h>
 #include "user.h"
 #include "sysdep/ptrace.h"
-#include "user_util.h"
 #include "kern_util.h"
 #include "skas.h"
 #include "stub-data.h"
@@ -34,6 +33,8 @@ #include "mem.h"
 #include "uml-config.h"
 #include "process.h"
 #include "longjmp.h"
+#include "kern_constants.h"
+#include "as-layout.h"
 
 int is_skas_winch(int pid, int fd, void *data)
 {
@@ -44,45 +45,58 @@ int is_skas_winch(int pid, int fd, void 
 	return(1);
 }
 
-void wait_stub_done(int pid, int sig, char * fname)
+static int ptrace_dump_regs(int pid)
 {
-	int n, status, err;
+        unsigned long regs[MAX_REG_NR];
+        int i;
+
+        if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
+                return -errno;
+        else {
+                printk("Stub registers -\n");
+                for(i = 0; i < ARRAY_SIZE(regs); i++)
+                        printk("\t%d - %lx\n", i, regs[i]);
+        }
+
+        return 0;
+}
 
-	do {
-		if ( sig != -1 ) {
-			err = ptrace(PTRACE_CONT, pid, 0, sig);
-			if(err)
-				panic("%s : continue failed, errno = %d\n",
-				      fname, errno);
-		}
-		sig = 0;
+/*
+ * Signals that are OK to receive in the stub - we'll just continue it.
+ * SIGWINCH will happen when UML is inside a detached screen.
+ */
+#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
+
+/* Signals that the stub will finish with - anything else is an error */
+#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))
+
+void wait_stub_done(int pid)
+{
+	int n, status, err;
 
+	while(1){
 		CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
-	} while((n >= 0) && WIFSTOPPED(status) &&
-	        ((WSTOPSIG(status) == SIGVTALRM) ||
-		 /* running UML inside a detached screen can cause
-		  * SIGWINCHes
-		  */
-		 (WSTOPSIG(status) == SIGWINCH)));
-
-	if((n < 0) || !WIFSTOPPED(status) ||
-	   (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
-		unsigned long regs[MAX_REG_NR];
-
-		if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
-			printk("Failed to get registers from stub, "
-			       "errno = %d\n", errno);
-		else {
-			int i;
-
-			printk("Stub registers -\n");
-			for(i = 0; i < ARRAY_SIZE(regs); i++)
-				printk("\t%d - %lx\n", i, regs[i]);
-		}
-		panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
-		      "pid = %d, n = %d, errno = %d, status = 0x%x\n",
-		      fname, pid, n, errno, status);
+		if((n < 0) || !WIFSTOPPED(status))
+			goto bad_wait;
+
+		if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
+			break;
+
+		err = ptrace(PTRACE_CONT, pid, 0, 0);
+		if(err)
+			panic("wait_stub_done : continue failed, errno = %d\n",
+			      errno);
 	}
+
+	if(((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
+		return;
+
+bad_wait:
+	err = ptrace_dump_regs(pid);
+	if(err)
+		printk("Failed to get registers from stub, errno = %d\n", -err);
+	panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, "
+	      "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);
 }
 
 extern unsigned long current_stub_stack(void);
@@ -104,7 +118,11 @@ void get_skas_faultinfo(int pid, struct 
 			       sizeof(struct ptrace_faultinfo));
 	}
 	else {
-		wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+		err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
+		if(err)
+			panic("Failed to continue stub, pid = %d, errno = %d\n",
+			      pid, errno);
+		wait_stub_done(pid);
 
 		/* faultinfo is prepared by the stub-segv-handler at start of
 		 * the stub stack page. We just have to copy it.
@@ -142,9 +160,14 @@ static void handle_trap(int pid, union u
 
 		CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
 		if((err < 0) || !WIFSTOPPED(status) ||
-		   (WSTOPSIG(status) != SIGTRAP + 0x80))
+		   (WSTOPSIG(status) != SIGTRAP + 0x80)){
+                        err = ptrace_dump_regs(pid);
+                        if(err)
+                                printk("Failed to get registers from process, "
+                                       "errno = %d\n", -err);
 			panic("handle_trap - failed to wait at end of syscall, "
 			      "errno = %d, status = %d\n", errno, status);
+                }
 	}
 
 	handle_syscall(regs);
@@ -172,7 +195,7 @@ static int userspace_tramp(void *stack)
 		int fd;
 		__u64 offset;
 		fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
-		addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+		addr = mmap64((void *) UML_CONFIG_STUB_CODE, UM_KERN_PAGE_SIZE,
 			      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
 		if(addr == MAP_FAILED){
 			printk("mapping mmap stub failed, errno = %d\n",
@@ -182,8 +205,8 @@ static int userspace_tramp(void *stack)
 
 		if(stack != NULL){
 			fd = phys_mapping(to_phys(stack), &offset);
-			addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
-				    PROT_READ | PROT_WRITE,
+			addr = mmap((void *) UML_CONFIG_STUB_DATA,
+				    UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
 				    MAP_FIXED | MAP_SHARED, fd, offset);
 			if(addr == MAP_FAILED){
 				printk("mapping segfault stack failed, "
@@ -199,7 +222,7 @@ static int userspace_tramp(void *stack)
 				  (unsigned long) stub_segv_handler -
 				  (unsigned long) &__syscall_stub_start;
 
-		set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+		set_sigstack((void *) UML_CONFIG_STUB_DATA, UM_KERN_PAGE_SIZE);
 		sigemptyset(&sa.sa_mask);
 		sigaddset(&sa.sa_mask, SIGIO);
 		sigaddset(&sa.sa_mask, SIGWINCH);
@@ -291,10 +314,13 @@ void userspace(union uml_pt_regs *regs)
 		UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
 
 		if(WIFSTOPPED(status)){
-		  	switch(WSTOPSIG(status)){
+			int sig = WSTOPSIG(status);
+		  	switch(sig){
 			case SIGSEGV:
-				if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
-					user_signal(SIGSEGV, regs, pid);
+				if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){
+					get_skas_faultinfo(pid, &regs->skas.faultinfo);
+					(*sig_info[SIGSEGV])(SIGSEGV, regs);
+				}
 				else handle_segv(pid, regs);
 				break;
 			case SIGTRAP + 0x80:
@@ -309,11 +335,13 @@ void userspace(union uml_pt_regs *regs)
 			case SIGBUS:
 			case SIGFPE:
 			case SIGWINCH:
-				user_signal(WSTOPSIG(status), regs, pid);
+				block_signals();
+				(*sig_info[sig])(sig, regs);
+				unblock_signals();
 				break;
 			default:
 			        printk("userspace - child stopped with signal "
-				       "%d\n", WSTOPSIG(status));
+				       "%d\n", sig);
 			}
 			pid = userspace_pid[0];
 			interrupt_end();
@@ -325,11 +353,29 @@ void userspace(union uml_pt_regs *regs)
 	}
 }
 
+static unsigned long thread_regs[MAX_REG_NR];
+static unsigned long thread_fp_regs[HOST_FP_SIZE];
+
+static int __init init_thread_regs(void)
+{
+	get_safe_registers(thread_regs, thread_fp_regs);
+	/* Set parent's instruction pointer to start of clone-stub */
+	thread_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+				(unsigned long) stub_clone_handler -
+				(unsigned long) &__syscall_stub_start;
+	thread_regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+		sizeof(void *);
+#ifdef __SIGNAL_FRAMESIZE
+	thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
+#endif
+	return 0;
+}
+
+__initcall(init_thread_regs);
+
 int copy_context_skas0(unsigned long new_stack, int pid)
 {
 	int err;
-	unsigned long regs[MAX_REG_NR];
-	unsigned long fp_regs[HOST_FP_SIZE];
 	unsigned long current_stack = current_stub_stack();
 	struct stub_data *data = (struct stub_data *) current_stack;
 	struct stub_data *child_data = (struct stub_data *) new_stack;
@@ -344,23 +390,12 @@ int copy_context_skas0(unsigned long new
 				      .timer    = ((struct itimerval)
 					            { { 0, 1000000 / hz() },
 						      { 0, 1000000 / hz() }})});
-	get_safe_registers(regs, fp_regs);
-
-	/* Set parent's instruction pointer to start of clone-stub */
-	regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
-				(unsigned long) stub_clone_handler -
-				(unsigned long) &__syscall_stub_start;
-	regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
-		sizeof(void *);
-#ifdef __SIGNAL_FRAMESIZE
-	regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
-#endif
-	err = ptrace_setregs(pid, regs);
+	err = ptrace_setregs(pid, thread_regs);
 	if(err < 0)
 		panic("copy_context_skas0 : PTRACE_SETREGS failed, "
 		      "pid = %d, errno = %d\n", pid, -err);
 
-	err = ptrace_setfpregs(pid, fp_regs);
+	err = ptrace_setfpregs(pid, thread_fp_regs);
 	if(err < 0)
 		panic("copy_context_skas0 : PTRACE_SETFPREGS failed, "
 		      "pid = %d, errno = %d\n", pid, -err);
@@ -371,7 +406,11 @@ #endif
 	/* Wait, until parent has finished its work: read child's pid from
 	 * parent's stack, and check, if bad result.
 	 */
-	wait_stub_done(pid, 0, "copy_context_skas0");
+	err = ptrace(PTRACE_CONT, pid, 0, 0);
+	if(err)
+		panic("Failed to continue new process, pid = %d, "
+		      "errno = %d\n", pid, errno);
+	wait_stub_done(pid);
 
 	pid = data->err;
 	if(pid < 0)
@@ -381,7 +420,7 @@ #endif
 	/* Wait, until child has finished too: read child's result from
 	 * child's stack and check it.
 	 */
-	wait_stub_done(pid, -1, "copy_context_skas0");
+	wait_stub_done(pid);
 	if (child_data->err != UML_CONFIG_STUB_DATA)
 		panic("copy_context_skas0 - stub-child reports error %ld\n",
 		      child_data->err);
@@ -396,7 +435,7 @@ #endif
 
 /*
  * This is used only, if stub pages are needed, while proc_mm is
- * availabl. Opening /proc/mm creates a new mm_context, which lacks
+ * available. Opening /proc/mm creates a new mm_context, which lacks
  * the stub-pages. Thus, we map them using /proc/mm-fd
  */
 void map_stub_pages(int fd, unsigned long code,
@@ -418,12 +457,13 @@ void map_stub_pages(int fd, unsigned lon
 					  .fd      = code_fd,
 					  .offset  = code_offset
 	} } });
-	n = os_write_file(fd, &mmop, sizeof(mmop));
+	CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
 	if(n != sizeof(mmop)){
+		n = errno;
 		printk("mmap args - addr = 0x%lx, fd = %d, offset = %llx\n",
 		       code, code_fd, (unsigned long long) code_offset);
 		panic("map_stub_pages : /proc/mm map for code failed, "
-		      "err = %d\n", -n);
+		      "err = %d\n", n);
 	}
 
 	if ( stack ) {
@@ -440,10 +480,10 @@ void map_stub_pages(int fd, unsigned lon
 				      .fd      = map_fd,
 				      .offset  = map_offset
 		} } });
-		n = os_write_file(fd, &mmop, sizeof(mmop));
+		CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
 		if(n != sizeof(mmop))
 			panic("map_stub_pages : /proc/mm map for data failed, "
-			      "err = %d\n", -n);
+			      "err = %d\n", errno);
 	}
 }
 
@@ -480,7 +520,15 @@ int start_idle_thread(void *stack, jmp_b
 		    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
 		    SIGVTALRM, -1);
 
-	n = UML_SETJMP(&initial_jmpbuf);
+	/*
+	 * Can't use UML_SETJMP or UML_LONGJMP here because they save
+	 * and restore signals, with the possible side-effect of
+	 * trying to handle any signals which came when they were
+	 * blocked, which can't be done on this stack.
+	 * Signals must be blocked when jumping back here and restored
+	 * after returning to the jumper.
+	 */
+	n = setjmp(initial_jmpbuf);
 	switch(n){
 	case INIT_JMP_NEW_THREAD:
 		(*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
@@ -490,7 +538,7 @@ int start_idle_thread(void *stack, jmp_b
 		break;
 	case INIT_JMP_CALLBACK:
 		(*cb_proc)(cb_arg);
-		UML_LONGJMP(cb_back, 1);
+		longjmp(*cb_back, 1);
 		break;
 	case INIT_JMP_HALT:
 		kmalloc_ok = 0;
@@ -501,7 +549,7 @@ int start_idle_thread(void *stack, jmp_b
 	default:
 		panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
 	}
-	UML_LONGJMP(switch_buf, 1);
+	longjmp(*switch_buf, 1);
 }
 
 void initial_thread_cb_skas(void (*proc)(void *), void *arg)
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
index 9ad5fbe..3b600c2 100644
--- a/arch/um/os-Linux/skas/trap.c
+++ b/arch/um/os-Linux/skas/trap.c
@@ -5,8 +5,8 @@
 
 #include <signal.h>
 #include <errno.h>
-#include "user_util.h"
 #include "kern_util.h"
+#include "as-layout.h"
 #include "task.h"
 #include "sigcontext.h"
 #include "skas.h"
@@ -15,29 +15,39 @@ #include "sysdep/ptrace.h"
 #include "sysdep/ptrace_user.h"
 #include "os.h"
 
+static union uml_pt_regs ksig_regs[UM_NR_CPUS];
+
 void sig_handler_common_skas(int sig, void *sc_ptr)
 {
 	struct sigcontext *sc = sc_ptr;
-	struct skas_regs *r;
+	union uml_pt_regs *r;
 	void (*handler)(int, union uml_pt_regs *);
-	int save_errno = errno;
-	int save_user;
+	int save_user, save_errno = errno;
 
 	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
 	 * handler.  This can happen in copy_user, and if SEGV is disabled,
 	 * the process will die.
 	 * XXX Figure out why this is better than SA_NODEFER
 	 */
-	if(sig == SIGSEGV)
+	if(sig == SIGSEGV) {
 		change_sig(SIGSEGV, 1);
+		/* For segfaults, we want the data from the
+		 * sigcontext.  In this case, we don't want to mangle
+		 * the process registers, so use a static set of
+		 * registers.  For other signals, the process
+		 * registers are OK.
+		 */
+		r = &ksig_regs[cpu()];
+		copy_sc(r, sc_ptr);
+	}
+	else r = TASK_REGS(get_current());
 
-	r = &TASK_REGS(get_current())->skas;
-	save_user = r->is_user;
-	r->is_user = 0;
+	save_user = r->skas.is_user;
+	r->skas.is_user = 0;
 	if ( sig == SIGFPE || sig == SIGSEGV ||
 	     sig == SIGBUS || sig == SIGILL ||
 	     sig == SIGTRAP ) {
-		GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+		GET_FAULTINFO_FROM_SC(r->skas.faultinfo, sc);
 	}
 
 	change_sig(SIGUSR1, 1);
@@ -49,25 +59,8 @@ void sig_handler_common_skas(int sig, vo
 	    sig != SIGVTALRM && sig != SIGALRM)
 		unblock_signals();
 
-	handler(sig, (union uml_pt_regs *) r);
+	handler(sig, r);
 
 	errno = save_errno;
-	r->is_user = save_user;
-}
-
-extern int ptrace_faultinfo;
-
-void user_signal(int sig, union uml_pt_regs *regs, int pid)
-{
-	void (*handler)(int, union uml_pt_regs *);
-	int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
-		    (sig == SIGILL) || (sig == SIGTRAP));
-
-	if (segv)
-		get_skas_faultinfo(pid, &regs->skas.faultinfo);
-
-	handler = sig_info[sig];
-	handler(sig, (union uml_pt_regs *) regs);
-
-	unblock_signals();
+	r->skas.is_user = save_user;
 }
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 5178eba..79471f8 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -17,10 +17,10 @@ #include <errno.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <sys/mman.h>
+#include <sys/resource.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <sys/types.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "signal_kern.h"
@@ -329,8 +329,32 @@ static void __init check_ptrace(void)
 
 extern void check_tmpexec(void);
 
-void os_early_checks(void)
+static void __init check_coredump_limit(void)
 {
+	struct rlimit lim;
+	int err = getrlimit(RLIMIT_CORE, &lim);
+
+	if(err){
+		perror("Getting core dump limit");
+		return;
+	}
+
+	printf("Core dump limits :\n\tsoft - ");
+	if(lim.rlim_cur == RLIM_INFINITY)
+		printf("NONE\n");
+	else printf("%lu\n", lim.rlim_cur);
+
+	printf("\thard - ");
+	if(lim.rlim_max == RLIM_INFINITY)
+		printf("NONE\n");
+	else printf("%lu\n", lim.rlim_max);
+}
+
+void __init os_early_checks(void)
+{
+	/* Print out the core dump limits early */
+	check_coredump_limit();
+
 	check_ptrace();
 
 	/* Need to check this early because mmapping happens before the
@@ -528,148 +552,3 @@ int __init parse_iomem(char *str, int *a
  out:
 	return 1;
 }
-
-
-/* Changed during early boot */
-int pty_output_sigio = 0;
-int pty_close_sigio = 0;
-
-/* Used as a flag during SIGIO testing early in boot */
-static volatile int got_sigio = 0;
-
-static void __init handler(int sig)
-{
-	got_sigio = 1;
-}
-
-struct openpty_arg {
-	int master;
-	int slave;
-	int err;
-};
-
-static void openpty_cb(void *arg)
-{
-	struct openpty_arg *info = arg;
-
-	info->err = 0;
-	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
-		info->err = -errno;
-}
-
-static int async_pty(int master, int slave)
-{
-	int flags;
-
-	flags = fcntl(master, F_GETFL);
-	if(flags < 0)
-		return -errno;
-
-	if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
-	   (fcntl(master, F_SETOWN, os_getpid()) < 0))
-		return -errno;
-
-	if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
-		return -errno;
-
-	return(0);
-}
-
-static void __init check_one_sigio(void (*proc)(int, int))
-{
-	struct sigaction old, new;
-	struct openpty_arg pty = { .master = -1, .slave = -1 };
-	int master, slave, err;
-
-	initial_thread_cb(openpty_cb, &pty);
-	if(pty.err){
-		printk("openpty failed, errno = %d\n", -pty.err);
-		return;
-	}
-
-	master = pty.master;
-	slave = pty.slave;
-
-	if((master == -1) || (slave == -1)){
-		printk("openpty failed to allocate a pty\n");
-		return;
-	}
-
-	/* Not now, but complain so we now where we failed. */
-	err = raw(master);
-	if (err < 0)
-		panic("check_sigio : __raw failed, errno = %d\n", -err);
-
-	err = async_pty(master, slave);
-	if(err < 0)
-		panic("tty_fds : sigio_async failed, err = %d\n", -err);
-
-	if(sigaction(SIGIO, NULL, &old) < 0)
-		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
-	new = old;
-	new.sa_handler = handler;
-	if(sigaction(SIGIO, &new, NULL) < 0)
-		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
-
-	got_sigio = 0;
-	(*proc)(master, slave);
-
-	close(master);
-	close(slave);
-
-	if(sigaction(SIGIO, &old, NULL) < 0)
-		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
-}
-
-static void tty_output(int master, int slave)
-{
-	int n;
-	char buf[512];
-
-	printk("Checking that host ptys support output SIGIO...");
-
-	memset(buf, 0, sizeof(buf));
-
-	while(os_write_file(master, buf, sizeof(buf)) > 0) ;
-	if(errno != EAGAIN)
-		panic("check_sigio : write failed, errno = %d\n", errno);
-	while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
-
-	if(got_sigio){
-		printk("Yes\n");
-		pty_output_sigio = 1;
-	}
-	else if(n == -EAGAIN) printk("No, enabling workaround\n");
-	else panic("check_sigio : read failed, err = %d\n", n);
-}
-
-static void tty_close(int master, int slave)
-{
-	printk("Checking that host ptys support SIGIO on close...");
-
-	close(slave);
-	if(got_sigio){
-		printk("Yes\n");
-		pty_close_sigio = 1;
-	}
-	else printk("No, enabling workaround\n");
-}
-
-void __init check_sigio(void)
-{
-	if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
-	   (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
-		printk("No pseudo-terminals available - skipping pty SIGIO "
-		       "check\n");
-		return;
-	}
-	check_one_sigio(tty_output);
-	check_one_sigio(tty_close);
-}
-
-void os_check_bugs(void)
-{
-	check_ptrace();
-	check_sigio();
-}
-
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c
index 2565320..32ed41e 100644
--- a/arch/um/os-Linux/sys-i386/tls.c
+++ b/arch/um/os-Linux/sys-i386/tls.c
@@ -5,7 +5,7 @@ #include <sys/syscall.h>
 #include <unistd.h>
 
 #include "sysdep/tls.h"
-#include "user_util.h"
+#include "user.h"
 
 /* Checks whether host supports TLS, and sets *tls_min according to the value
  * valid on the host.
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 2115b8b..5de169b 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -10,7 +10,6 @@ #include <time.h>
 #include <sys/time.h>
 #include <signal.h>
 #include <errno.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "process.h"
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
index d221214..295da65 100644
--- a/arch/um/os-Linux/trap.c
+++ b/arch/um/os-Linux/trap.c
@@ -6,7 +6,6 @@
 #include <stdlib.h>
 #include <signal.h>
 #include "kern_util.h"
-#include "user_util.h"
 #include "os.h"
 #include "mode.h"
 #include "longjmp.h"
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
index 3dc3a02..bcf9359 100644
--- a/arch/um/os-Linux/tt.c
+++ b/arch/um/os-Linux/tt.c
@@ -18,7 +18,6 @@ #include <sys/mman.h>
 #include <asm/ptrace.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "signal_kern.h"
@@ -32,6 +31,7 @@ #include "uml-config.h"
 #include "choose-mode.h"
 #include "mode.h"
 #include "tempfile.h"
+#include "kern_constants.h"
 
 int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
 		   int must_succeed)
@@ -143,7 +143,7 @@ int outer_tramp(void *arg)
 	int sig = sigkill;
 
 	t = arg;
-	t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+	t->pid = clone(t->tramp, (void *) t->temp_stack + UM_KERN_PAGE_SIZE/2,
 		       t->flags, t->tramp_data);
 	if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
 	kill(os_getpid(), sig);
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
index c6ba56c..d11a55b 100644
--- a/arch/um/os-Linux/tty_log.c
+++ b/arch/um/os-Linux/tty_log.c
@@ -53,9 +53,9 @@ int open_tty_log(void *tty, void *curren
 					       .direction = 0,
 					       .sec = tv.tv_sec,
 					       .usec = tv.tv_usec } );
-		os_write_file(tty_log_fd, &data, sizeof(data));
-		os_write_file(tty_log_fd, &current_tty, data.len);
-		return(tty_log_fd);
+		write(tty_log_fd, &data, sizeof(data));
+		write(tty_log_fd, &current_tty, data.len);
+		return tty_log_fd;
 	}
 
 	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
@@ -67,7 +67,7 @@ int open_tty_log(void *tty, void *curren
 		printk("open_tty_log : couldn't open '%s', errno = %d\n",
 		       buf, -fd);
 	}
-	return(fd);
+	return fd;
 }
 
 void close_tty_log(int fd, void *tty)
@@ -83,7 +83,7 @@ void close_tty_log(int fd, void *tty)
 					       .direction = 0,
 					       .sec = tv.tv_sec,
 					       .usec = tv.tv_usec } );
-		os_write_file(tty_log_fd, &data, sizeof(data));
+		write(tty_log_fd, &data, sizeof(data));
 		return;
 	}
 	os_close_file(fd);
@@ -98,21 +98,21 @@ static int log_chunk(int fd, const char 
 		try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
 		missed = copy_from_user_proc(chunk, (char *) buf, try);
 		try -= missed;
-		n = os_write_file(fd, chunk, try);
+		n = write(fd, chunk, try);
 		if(n != try) {
 			if(n < 0)
-				return(n);
-			return(-EIO);
+				return -errno;
+			return -EIO;
 		}
 		if(missed != 0)
-			return(-EFAULT);
+			return -EFAULT;
 
 		len -= try;
 		total += try;
 		buf += try;
 	}
 
-	return(total);
+	return total;
 }
 
 int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
@@ -130,10 +130,10 @@ int write_tty_log(int fd, const char *bu
 					       .direction = direction,
 					       .sec = tv.tv_sec,
 					       .usec = tv.tv_usec } );
-		os_write_file(tty_log_fd, &data, sizeof(data));
+		write(tty_log_fd, &data, sizeof(data));
 	}
 
-	return(log_chunk(fd, buf, len));
+	return log_chunk(fd, buf, len);
 }
 
 void log_exec(char **argv, void *tty)
@@ -161,7 +161,7 @@ void log_exec(char **argv, void *tty)
 				       .direction = 0,
 				       .sec = tv.tv_sec,
 				       .usec = tv.tv_usec } );
-	os_write_file(tty_log_fd, &data, sizeof(data));
+	write(tty_log_fd, &data, sizeof(data));
 
 	for(ptr = argv; ; ptr++){
 		if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
@@ -179,7 +179,7 @@ extern void register_tty_logger(int (*op
 static int register_logger(void)
 {
 	register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
-	return(0);
+	return 0;
 }
 
 __uml_initcall(register_logger);
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 56b8a50..c307a89 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -21,7 +21,6 @@ #include <stdarg.h>
 #include <sched.h>
 #include <termios.h>
 #include <string.h>
-#include "user_util.h"
 #include "kern_util.h"
 #include "user.h"
 #include "mem_user.h"
@@ -30,28 +29,29 @@ #include "ptrace_user.h"
 #include "uml-config.h"
 #include "os.h"
 #include "longjmp.h"
+#include "kern_constants.h"
 
 void stack_protections(unsigned long address)
 {
 	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
 
-	if(mprotect((void *) address, page_size(), prot) < 0)
+	if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
 		panic("protecting stack failed, errno = %d", errno);
 }
 
 void task_protections(unsigned long address)
 {
-	unsigned long guard = address + page_size();
-	unsigned long stack = guard + page_size();
+	unsigned long guard = address + UM_KERN_PAGE_SIZE;
+	unsigned long stack = guard + UM_KERN_PAGE_SIZE;
 	int prot = 0, pages;
 
 #ifdef notdef
-	if(mprotect((void *) stack, page_size(), prot) < 0)
+	if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
 		panic("protecting guard page failed, errno = %d", errno);
 #endif
 	pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
 	prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-	if(mprotect((void *) stack, pages * page_size(), prot) < 0)
+	if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
 		panic("protecting stack failed, errno = %d", errno);
 }
 
@@ -96,15 +96,13 @@ #endif
 	strcpy(machine_out, host.machine);
 }
 
-char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
-
-void setup_hostinfo(void)
+void setup_hostinfo(char *buf, int len)
 {
 	struct utsname host;
 
 	uname(&host);
-	sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
-		host.release, host.version, host.machine);
+	snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename,
+		 host.release, host.version, host.machine);
 }
 
 int setjmp_wrapper(void (*proc)(void *, void *), ...)
@@ -121,3 +119,9 @@ int setjmp_wrapper(void (*proc)(void *, 
 	va_end(args);
 	return n;
 }
+
+void os_dump_core(void)
+{
+	signal(SIGSEGV, SIG_DFL);
+	abort();
+}
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index f1bcd39..0393e44 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -13,7 +13,6 @@ #include "user.h"
 #include "sysdep/ptrace.h"
 #include "task.h"
 #include "os.h"
-#include "user_util.h"
 
 #define MAXTOKEN 64
 
@@ -32,21 +31,21 @@ static char token(int fd, char *buf, int
 		n = os_read_file(fd, ptr, sizeof(*ptr));
 		c = *ptr++;
 		if(n != sizeof(*ptr)){
-			if(n == 0) return(0);
+			if(n == 0)
+				return 0;
 			printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
 			if(n < 0)
-				return(n);
-			else
-				return(-EIO);
+				return n;
+			else return -EIO;
 		}
 	} while((c != '\n') && (c != stop) && (ptr < end));
 
 	if(ptr == end){
 		printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
-		return(-1);
+		return -1;
 	}
 	*(ptr - 1) = '\0';
-	return(c);
+	return c;
 }
 
 static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
@@ -58,48 +57,25 @@ static int find_cpuinfo_line(int fd, cha
 	while(1){
 		c = token(fd, scratch, len - 1, ':');
 		if(c <= 0)
-			return(0);
+			return 0;
 		else if(c != ':'){
 			printk("Failed to find ':' in /proc/cpuinfo\n");
-			return(0);
+			return 0;
 		}
 
 		if(!strncmp(scratch, key, strlen(key)))
-			return(1);
+			return 1;
 
 		do {
 			n = os_read_file(fd, &c, sizeof(c));
 			if(n != sizeof(c)){
 				printk("Failed to find newline in "
 				       "/proc/cpuinfo, err = %d\n", -n);
-				return(0);
+				return 0;
 			}
 		} while(c != '\n');
 	}
-	return(0);
-}
-
-int cpu_feature(char *what, char *buf, int len)
-{
-	int fd, ret = 0;
-
-	fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
-	if(fd < 0){
-		printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
-		return(0);
-	}
-
-	if(!find_cpuinfo_line(fd, what, buf, len)){
-		printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
-		goto out_close;
-	}
-
-	token(fd, buf, len, '\n');
-	ret = 1;
-
- out_close:
-	os_close_file(fd);
-	return(ret);
+	return 0;
 }
 
 static int check_cpu_flag(char *feature, int *have_it)
@@ -119,7 +95,8 @@ static int check_cpu_flag(char *feature,
 		goto out;
 
 	c = token(fd, buf, len - 1, ' ');
-	if(c < 0) goto out;
+	if(c < 0)
+		goto out;
 	else if(c != ' '){
 		printk("Failed to find ' ' in /proc/cpuinfo\n");
 		goto out;
@@ -127,7 +104,8 @@ static int check_cpu_flag(char *feature,
 
 	while(1){
 		c = token(fd, buf, len - 1, ' ');
-		if(c < 0) goto out;
+		if(c < 0)
+			goto out;
 		else if(c == '\n') break;
 
 		if(!strcmp(buf, feature)){
@@ -136,8 +114,10 @@ static int check_cpu_flag(char *feature,
 		}
 	}
  out:
-	if(*have_it == 0) printk("No\n");
-	else if(*have_it == 1) printk("Yes\n");
+	if(*have_it == 0)
+		printk("No\n");
+	else if(*have_it == 1)
+		printk("Yes\n");
 	os_close_file(fd);
 	return 1;
 }
@@ -189,12 +169,13 @@ int arch_handle_signal(int sig, union um
 	/* This is testing for a cmov (0x0f 0x4x) instruction causing a
 	 * SIGILL in init.
 	 */
-	if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
+	if((sig != SIGILL) || (TASK_PID(get_current()) != 1))
+		return 0;
 
 	if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
 		panic("SIGILL in init, could not read instructions!\n");
 	if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
-		return(0);
+		return 0;
 
 	if(host_has_cmov == 0)
 		panic("SIGILL caused by cmov, which this processor doesn't "
@@ -208,16 +189,5 @@ int arch_handle_signal(int sig, union um
 		      "implements it, boot a filesystem compiled for older "
 		      "processors");
 	else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
-	return(0);
+	return 0;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
index d0bbcdf..745b4fd 100644
--- a/arch/um/sys-i386/fault.c
+++ b/arch/um/sys-i386/fault.c
@@ -3,9 +3,7 @@
  * Licensed under the GPL
  */
 
-#include <signal.h>
 #include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
 
 /* These two are from asm-um/uaccess.h and linux/module.h, check them. */
 struct exception_table_entry
@@ -17,26 +15,14 @@ struct exception_table_entry
 const struct exception_table_entry *search_exception_tables(unsigned long add);
 
 /* Compare this to arch/i386/mm/extable.c:fixup_exception() */
-int arch_fixup(unsigned long address, void *sc_ptr)
+int arch_fixup(unsigned long address, union uml_pt_regs *regs)
 {
-	struct sigcontext *sc = sc_ptr;
 	const struct exception_table_entry *fixup;
 
 	fixup = search_exception_tables(address);
 	if(fixup != 0){
-		sc->eip = fixup->fixup;
+		UPT_IP(regs) = fixup->fixup;
 		return(1);
 	}
 	return(0);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 01212c8..40ff0c8 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
@@ -15,7 +15,6 @@ #include "sysdep/thread.h"
 #include "user.h"
 #include "os.h"
 #include "uml-config.h"
-#include "user_util.h"
 
 int ptrace_getregs(long pid, unsigned long *regs_out)
 {
@@ -45,7 +44,8 @@ int ptrace_setfpregs(long pid, unsigned 
 	return 0;
 }
 
-/* All the below stuff is of interest for TT mode only */
+#ifdef UML_CONFIG_MODE_TT
+
 static void write_debugregs(int pid, unsigned long *regs)
 {
 	struct user *dummy;
@@ -128,13 +128,4 @@ void update_debugregs(int seq)
 }
 #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:
- */
+#endif
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 3f6acd6..1cbf95f 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -18,6 +18,28 @@ #ifdef CONFIG_MODE_SKAS
 
 #include "skas.h"
 
+void copy_sc(union uml_pt_regs *regs, void *from)
+{
+	struct sigcontext *sc = from;
+
+	REGS_GS(regs->skas.regs) = sc->gs;
+	REGS_FS(regs->skas.regs) = sc->fs;
+	REGS_ES(regs->skas.regs) = sc->es;
+	REGS_DS(regs->skas.regs) = sc->ds;
+	REGS_EDI(regs->skas.regs) = sc->edi;
+	REGS_ESI(regs->skas.regs) = sc->esi;
+	REGS_EBP(regs->skas.regs) = sc->ebp;
+	REGS_SP(regs->skas.regs) = sc->esp;
+	REGS_EBX(regs->skas.regs) = sc->ebx;
+	REGS_EDX(regs->skas.regs) = sc->edx;
+	REGS_ECX(regs->skas.regs) = sc->ecx;
+	REGS_EAX(regs->skas.regs) = sc->eax;
+	REGS_IP(regs->skas.regs) = sc->eip;
+	REGS_CS(regs->skas.regs) = sc->cs;
+	REGS_EFLAGS(regs->skas.regs) = sc->eflags;
+	REGS_SS(regs->skas.regs) = sc->ss;
+}
+
 static int copy_sc_from_user_skas(struct pt_regs *regs,
 				  struct sigcontext __user *from)
 {
@@ -28,33 +50,18 @@ static int copy_sc_from_user_skas(struct
 	err = copy_from_user(&sc, from, sizeof(sc));
 	err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
 	if(err)
-		return(err);
-
-	REGS_GS(regs->regs.skas.regs) = sc.gs;
-	REGS_FS(regs->regs.skas.regs) = sc.fs;
-	REGS_ES(regs->regs.skas.regs) = sc.es;
-	REGS_DS(regs->regs.skas.regs) = sc.ds;
-	REGS_EDI(regs->regs.skas.regs) = sc.edi;
-	REGS_ESI(regs->regs.skas.regs) = sc.esi;
-	REGS_EBP(regs->regs.skas.regs) = sc.ebp;
-	REGS_SP(regs->regs.skas.regs) = sc.esp;
-	REGS_EBX(regs->regs.skas.regs) = sc.ebx;
-	REGS_EDX(regs->regs.skas.regs) = sc.edx;
-	REGS_ECX(regs->regs.skas.regs) = sc.ecx;
-	REGS_EAX(regs->regs.skas.regs) = sc.eax;
-	REGS_IP(regs->regs.skas.regs) = sc.eip;
-	REGS_CS(regs->regs.skas.regs) = sc.cs;
-	REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
-	REGS_SS(regs->regs.skas.regs) = sc.ss;
+		return err;
+
+	copy_sc(&regs->regs, &sc);
 
 	err = restore_fp_registers(userspace_pid[0], fpregs);
-	if(err < 0){
+	if(err < 0) {
 	  	printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
-		       "errno = %d\n", err);
-		return(1);
+		       "errno = %d\n", -err);
+		return err;
 	}
 
-	return(0);
+	return 0;
 }
 
 int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp,
@@ -90,16 +97,16 @@ int copy_sc_to_user_skas(struct sigconte
 	if(err < 0){
 	  	printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
 		       "errno = %d\n", err);
-		return(1);
+		return 1;
 	}
 	to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
 	sc.fpstate = to_fp;
 
 	if(err)
-	  	return(err);
+	  	return err;
 
-	return(copy_to_user(to, &sc, sizeof(sc)) ||
-	       copy_to_user(to_fp, fpregs, sizeof(fpregs)));
+	return copy_to_user(to, &sc, sizeof(sc)) ||
+	       copy_to_user(to_fp, fpregs, sizeof(fpregs));
 }
 #endif
 
@@ -129,7 +136,7 @@ int copy_sc_from_user_tt(struct sigconte
 	to->fpstate = to_fp;
 	if(to_fp != NULL)
 		err |= copy_from_user(to_fp, from_fp, fpsize);
-	return(err);
+	return err;
 }
 
 int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
@@ -164,15 +171,15 @@ static int copy_sc_from_user(struct pt_r
 	ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
 					       sizeof(struct _fpstate)),
 			  copy_sc_from_user_skas(to, from));
-	return(ret);
+	return ret;
 }
 
 static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp,
 			   struct pt_regs *from, unsigned long sp)
 {
-	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
+	return CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
 					      sizeof(*fp), sp),
-                           copy_sc_to_user_skas(to, fp, from, sp)));
+                           copy_sc_to_user_skas(to, fp, from, sp));
 }
 
 static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp,
@@ -185,7 +192,7 @@ static int copy_ucontext_to_user(struct 
 	err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
 	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
 	err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
-	return(err);
+	return err;
 }
 
 struct sigframe
@@ -359,7 +366,7 @@ long sys_sigreturn(struct pt_regs regs)
 
 	/* Avoid ERESTART handling */
 	PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
-	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+	return PT_REGS_SYSCALL_RET(&current->thread.regs);
 
  segfault:
 	force_sig(SIGSEGV, current);
@@ -389,20 +396,9 @@ long sys_rt_sigreturn(struct pt_regs reg
 
 	/* Avoid ERESTART handling */
 	PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
-	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+	return PT_REGS_SYSCALL_RET(&current->thread.regs);
 
  segfault:
 	force_sig(SIGSEGV, current);
 	return 0;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index 643dab5..fea8e5e 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -23,9 +23,13 @@ #ifdef CONFIG_MODE_SKAS
 #include "skas.h"
 #endif
 
-/* If needed we can detect when it's uninitialized. */
+/*
+ * If needed we can detect when it's uninitialized.
+ *
+ * These are initialized in an initcall and unchanged thereafter.
+ */
 static int host_supports_tls = -1;
-int host_gdt_entry_tls_min = -1;
+int host_gdt_entry_tls_min;
 
 #ifdef CONFIG_MODE_SKAS
 int do_set_thread_area_skas(struct user_desc *info)
@@ -361,7 +365,8 @@ out:
 
 /* XXX: This part is probably common to i386 and x86-64. Don't create a common
  * file for now, do that when implementing x86-64 support.*/
-static int __init __setup_host_supports_tls(void) {
+static int __init __setup_host_supports_tls(void)
+{
 	check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min);
 	if (host_supports_tls) {
 		printk(KERN_INFO "Host TLS support detected\n");
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
index 447306b..29118cf 100644
--- a/arch/um/sys-i386/user-offsets.c
+++ b/arch/um/sys-i386/user-offsets.c
@@ -1,9 +1,10 @@
 #include <stdio.h>
+#include <stddef.h>
 #include <signal.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
-#include <stddef.h>
-#include <sys/poll.h>
 
 #define DEFINE(sym, val) \
 	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -47,7 +48,6 @@ void foo(void)
 	OFFSET(HOST_SC_FP_ST, _fpstate, _st);
 	OFFSET(HOST_SC_FXSR_ENV, _fpstate, _fxsr_env);
 
-	DEFINE(HOST_FRAME_SIZE, FRAME_SIZE);
 	DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_i387_struct));
 	DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fxsr_struct));
 
@@ -73,4 +73,8 @@ void foo(void)
 	DEFINE(UM_POLLIN, POLLIN);
 	DEFINE(UM_POLLPRI, POLLPRI);
 	DEFINE(UM_POLLOUT, POLLOUT);
+
+	DEFINE(UM_PROT_READ, PROT_READ);
+	DEFINE(UM_PROT_WRITE, PROT_WRITE);
+	DEFINE(UM_PROT_EXEC, PROT_EXEC);
 }
diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c
index 5d430fc..4bdc15c 100644
--- a/arch/um/sys-ppc/sigcontext.c
+++ b/arch/um/sys-ppc/sigcontext.c
@@ -1,7 +1,6 @@
 #include "asm/ptrace.h"
 #include "asm/sigcontext.h"
 #include "sysdep/ptrace.h"
-#include "user_util.h"
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c
index fdce7ea..0954788 100644
--- a/arch/um/sys-x86_64/bugs.c
+++ b/arch/um/sys-x86_64/bugs.c
@@ -4,12 +4,7 @@
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/errno.h"
-#include "asm/system.h"
-#include "asm/pda.h"
 #include "sysdep/ptrace.h"
-#include "os.h"
 
 void arch_init_thread(void)
 {
@@ -21,102 +16,5 @@ void arch_check_bugs(void)
 
 int arch_handle_signal(int sig, union uml_pt_regs *regs)
 {
-	return(0);
+	return 0;
 }
-
-#define MAXTOKEN 64
-
-/* Set during early boot */
-int host_has_cmov = 1;
-int host_has_xmm = 0;
-
-static char token(int fd, char *buf, int len, char stop)
-{
-	int n;
-	char *ptr, *end, c;
-
-	ptr = buf;
-	end = &buf[len];
-	do {
-		n = os_read_file(fd, ptr, sizeof(*ptr));
-		c = *ptr++;
-		if(n != sizeof(*ptr)){
-			if(n == 0) return(0);
-			printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
-			if(n < 0)
-				return(n);
-			else
-				return(-EIO);
-		}
-	} while((c != '\n') && (c != stop) && (ptr < end));
-
-	if(ptr == end){
-		printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
-		return(-1);
-	}
-	*(ptr - 1) = '\0';
-	return(c);
-}
-
-static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
-{
-	int n;
-	char c;
-
-	scratch[len - 1] = '\0';
-	while(1){
-		c = token(fd, scratch, len - 1, ':');
-		if(c <= 0)
-			return(0);
-		else if(c != ':'){
-			printk("Failed to find ':' in /proc/cpuinfo\n");
-			return(0);
-		}
-
-		if(!strncmp(scratch, key, strlen(key)))
-			return(1);
-
-		do {
-			n = os_read_file(fd, &c, sizeof(c));
-			if(n != sizeof(c)){
-				printk("Failed to find newline in "
-				       "/proc/cpuinfo, err = %d\n", -n);
-				return(0);
-			}
-		} while(c != '\n');
-	}
-	return(0);
-}
-
-int cpu_feature(char *what, char *buf, int len)
-{
-	int fd, ret = 0;
-
-	fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
-	if(fd < 0){
-		printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
-		return(0);
-	}
-
-	if(!find_cpuinfo_line(fd, what, buf, len)){
-		printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
-		goto out_close;
-	}
-
-	token(fd, buf, len, '\n');
-	ret = 1;
-
- out_close:
-	os_close_file(fd);
-	return(ret);
-}
-
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c
index cee1513..4636b14 100644
--- a/arch/um/sys-x86_64/fault.c
+++ b/arch/um/sys-x86_64/fault.c
@@ -4,20 +4,24 @@
  * Licensed under the GPL
  */
 
-#include "user.h"
+#include "sysdep/ptrace.h"
 
-int arch_fixup(unsigned long address, void *sc_ptr)
+/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
+struct exception_table_entry
 {
-	/* XXX search_exception_tables() */
+	unsigned long insn;
+	unsigned long fixup;
+};
+
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+int arch_fixup(unsigned long address, union uml_pt_regs *regs)
+{
+	const struct exception_table_entry *fixup;
+
+	fixup = search_exception_tables(address);
+	if(fixup != 0){
+		UPT_IP(regs) = fixup->fixup;
+		return(1);
+	}
 	return(0);
 }
-
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index af2f017..fe8ec04 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -20,6 +20,36 @@ #ifdef CONFIG_MODE_SKAS
 
 #include "skas.h"
 
+void copy_sc(union uml_pt_regs *regs, void *from)
+{
+	struct sigcontext *sc = from;
+
+#define GETREG(regs, regno, sc, regname) \
+       (regs)->skas.regs[(regno) / sizeof(unsigned long)] = (sc)->regname
+
+       GETREG(regs, R8, sc, r8);
+       GETREG(regs, R9, sc, r9);
+       GETREG(regs, R10, sc, r10);
+       GETREG(regs, R11, sc, r11);
+       GETREG(regs, R12, sc, r12);
+       GETREG(regs, R13, sc, r13);
+       GETREG(regs, R14, sc, r14);
+       GETREG(regs, R15, sc, r15);
+       GETREG(regs, RDI, sc, rdi);
+       GETREG(regs, RSI, sc, rsi);
+       GETREG(regs, RBP, sc, rbp);
+       GETREG(regs, RBX, sc, rbx);
+       GETREG(regs, RDX, sc, rdx);
+       GETREG(regs, RAX, sc, rax);
+       GETREG(regs, RCX, sc, rcx);
+       GETREG(regs, RSP, sc, rsp);
+       GETREG(regs, RIP, sc, rip);
+       GETREG(regs, EFLAGS, sc, eflags);
+       GETREG(regs, CS, sc, cs);
+
+#undef GETREG
+}
+
 static int copy_sc_from_user_skas(struct pt_regs *regs,
                                  struct sigcontext __user *from)
 {
@@ -51,7 +81,7 @@ #define GETREG(regs, regno, sc, regname)
 
 #undef GETREG
 
-       return(err);
+       return err;
 }
 
 int copy_sc_to_user_skas(struct sigcontext __user *to,
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c
index 899cebb..0d5fd76 100644
--- a/arch/um/sys-x86_64/user-offsets.c
+++ b/arch/um/sys-x86_64/user-offsets.c
@@ -2,6 +2,7 @@ #include <stdio.h>
 #include <stddef.h>
 #include <signal.h>
 #include <sys/poll.h>
+#include <sys/mman.h>
 #define __FRAME_OFFSETS
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -57,7 +58,6 @@ #if 0
 	OFFSET(HOST_SC_SS, sigcontext, ss);
 #endif
 
-	DEFINE_LONGS(HOST_FRAME_SIZE, FRAME_SIZE);
 	DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long));
 	DEFINE(HOST_XFP_SIZE, 0);
 	DEFINE_LONGS(HOST_RBX, RBX);
@@ -94,4 +94,8 @@ #endif
 	DEFINE(UM_POLLIN, POLLIN);
 	DEFINE(UM_POLLPRI, POLLPRI);
 	DEFINE(UM_POLLOUT, POLLOUT);
+
+	DEFINE(UM_PROT_READ, PROT_READ);
+	DEFINE(UM_PROT_WRITE, PROT_WRITE);
+	DEFINE(UM_PROT_EXEC, PROT_EXEC);
 }
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 50ccc7f..5f54c12 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -37,6 +37,10 @@ config GENERIC_IRQ_PROBE
 	bool
 	default y
 
+config GENERIC_TIME
+	bool
+	default y
+
 config TIME_LOW_RES
 	bool
 	default y
diff --git a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c
index c4f844c..e4a4b8e 100644
--- a/arch/v850/kernel/process.c
+++ b/arch/v850/kernel/process.c
@@ -16,7 +16,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
index 67e0575..a9b0934 100644
--- a/arch/v850/kernel/ptrace.c
+++ b/arch/v850/kernel/ptrace.c
@@ -21,7 +21,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
 
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
index 17c2d43..bf166e7 100644
--- a/arch/v850/kernel/signal.c
+++ b/arch/v850/kernel/signal.c
@@ -17,7 +17,6 @@
 
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
index d2b1fb1..f9f00cc 100644
--- a/arch/v850/kernel/syscalls.c
+++ b/arch/v850/kernel/syscalls.c
@@ -18,7 +18,6 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
index 486e3a4..f0905b0 100644
--- a/arch/v850/kernel/time.c
+++ b/arch/v850/kernel/time.c
@@ -90,81 +90,6 @@ #endif /* 0 */
 	return IRQ_HANDLED;
 }
 
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday (struct timeval *tv)
-{
-#if 0 /* DAVIDM later if possible */
-	extern volatile unsigned long lost_ticks;
-	unsigned long lost;
-#endif
-	unsigned long flags;
-	unsigned long usec, sec;
-	unsigned long seq;
-
-	do {
-		seq = read_seqbegin_irqsave(&xtime_lock, flags);
-
-#if 0
-		usec = mach_gettimeoffset ? mach_gettimeoffset () : 0;
-#else
-		usec = 0;
-#endif
-#if 0 /* DAVIDM later if possible */
-		lost = lost_ticks;
-		if (lost)
-			usec += lost * (1000000/HZ);
-#endif
-		sec = xtime.tv_sec;
-		usec += xtime.tv_nsec / 1000;
-	} 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)
-{
-	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!
-	 */
-#if 0
-	tv->tv_nsec -= mach_gettimeoffset() * 1000;
-#endif
-
-	while (tv->tv_nsec < 0) {
-		tv->tv_nsec += NSEC_PER_SEC;
-		tv->tv_sec--;
-	}
-
-	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_nsec = tv->tv_nsec;
-
-	ntp_clear();
-
-	write_sequnlock_irq (&xtime_lock);
-	clock_was_set();
-	return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
 static int timer_dev_id;
 static struct irqaction timer_irqaction = {
 	timer_interrupt,
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 56eb14c..145bb82 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -415,13 +415,13 @@ config OUT_OF_LINE_PFN_TO_PAGE
 	depends on DISCONTIGMEM
 
 config NR_CPUS
-	int "Maximum number of CPUs (2-256)"
+	int "Maximum number of CPUs (2-255)"
 	range 2 255
 	depends on SMP
 	default "8"
 	help
 	  This allows you to specify the maximum number of CPUs which this
-	  kernel will support. Current maximum is 256 CPUs due to
+	  kernel will support. Current maximum is 255 CPUs due to
 	  APIC addressing limits. Less depending on the hardware.
 
 	  This is purely to save memory - each supported CPU requires
@@ -565,23 +565,56 @@ config CRASH_DUMP
 	  PHYSICAL_START.
           For more details see Documentation/kdump/kdump.txt
 
+config RELOCATABLE
+	bool "Build a relocatable kernel(EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  Builds a relocatable kernel. This enables loading and running
+	  a kernel binary from a different physical address than it has
+	  been compiled for.
+
+	  One use is for the kexec on panic case where the recovery kernel
+	  must live at a different physical address than the primary
+	  kernel.
+
+	  Note: If CONFIG_RELOCATABLE=y, then kernel run from the address
+	  it has been loaded at and compile time physical address
+	  (CONFIG_PHYSICAL_START) is ignored.
+
 config PHYSICAL_START
 	hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
-	default "0x1000000" if CRASH_DUMP
 	default "0x200000"
 	help
-	  This gives the physical address where the kernel is loaded. Normally
-	  for regular kernels this value is 0x200000 (2MB). But in the case
-	  of kexec on panic the fail safe kernel needs to run at a different
-	  address than the panic-ed kernel. This option is used to set the load
-	  address for kernels used to capture crash dump on being kexec'ed
-	  after panic. The default value for crash dump kernels is
-	  0x1000000 (16MB). This can also be set based on the "X" value as
+	  This gives the physical address where the kernel is loaded. It
+	  should be aligned to 2MB boundary.
+
+	  If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then
+	  bzImage will decompress itself to above physical address and
+	  run from there. Otherwise, bzImage will run from the address where
+	  it has been loaded by the boot loader and will ignore above physical
+	  address.
+
+	  In normal kdump cases one does not have to set/change this option
+	  as now bzImage can be compiled as a completely relocatable image
+	  (CONFIG_RELOCATABLE=y) and be used to load and run from a different
+	  address. This option is mainly useful for the folks who don't want
+	  to use a bzImage for capturing the crash dump and want to use a
+	  vmlinux instead.
+
+	  So if you are using bzImage for capturing the crash dump, leave
+	  the value here unchanged to 0x200000 and set CONFIG_RELOCATABLE=y.
+	  Otherwise if you plan to use vmlinux for capturing the crash dump
+	  change this value to start of the reserved region (Typically 16MB
+	  0x1000000). In other words, it can be set based on the "X" value as
 	  specified in the "crashkernel=YM@XM" command line boot parameter
 	  passed to the panic-ed kernel. Typically this parameter is set as
 	  crashkernel=64M@16M. Please take a look at
 	  Documentation/kdump/kdump.txt for more details about crash dumps.
 
+	  Usage of bzImage for capturing the crash dump is advantageous as
+	  one does not have to build two kernels. Same kernel can be used
+	  as production kernel and capture kernel.
+
 	  Don't change this unless you know what you are doing.
 
 config SECCOMP
@@ -627,14 +660,6 @@ config CC_STACKPROTECTOR_ALL
 
 source kernel/Kconfig.hz
 
-config REORDER
-	bool "Function reordering"
-	default n
-	help
-         This option enables the toolchain to reorder functions for a more 
-         optimal TLB usage. If you have pretty much any version of binutils, 
-	 this can increase your kernel build time by roughly one minute.
-
 config K8_NB
 	def_bool y
 	depends on AGP_AMD64 || IOMMU || (PCI && NUMA)
@@ -676,6 +701,7 @@ menu "Bus options (PCI etc.)"
 
 config PCI
 	bool "PCI support"
+	select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
 
 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
 config PCI_DIRECT
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 2941a91..29617ae 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -40,10 +40,6 @@ cflags-y += -m64
 cflags-y += -mno-red-zone
 cflags-y += -mcmodel=kernel
 cflags-y += -pipe
-cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections
-# this makes reading assembly source easier, but produces worse code
-# actually it makes the kernel smaller too.
-cflags-y += -fno-reorder-blocks
 cflags-y += -Wno-sign-compare
 cflags-y += -fno-asynchronous-unwind-tables
 ifneq ($(CONFIG_DEBUG_INFO),y)
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index deb063e..ee6f650 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -36,7 +36,7 @@ subdir-		:= compressed/	#Let make clean 
 # ---------------------------------------------------------------------------
 
 $(obj)/bzImage: IMAGE_OFFSET := 0x100000
-$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
 
 quiet_cmd_image = BUILD   $@
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
index e70fa6e..705a3e3 100644
--- a/arch/x86_64/boot/compressed/Makefile
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -8,16 +8,14 @@ #
 
 targets		:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
 EXTRA_AFLAGS	:= -traditional
-AFLAGS		:= $(subst -m64,-m32,$(AFLAGS))
 
 # cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
 # -m32
-CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2  -fno-strict-aliasing
-LDFLAGS := -m elf_i386
+CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2  -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin
+LDFLAGS := -m elf_x86_64
 
-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
-
-$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
+LDFLAGS_vmlinux := -T
+$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
 	$(call if_changed,ld)
 	@:
 
@@ -27,7 +25,7 @@ LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET
 $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,gzip)
 
-LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
+LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
 
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
 	$(call if_changed,ld)
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
index 6f55565..f9d5692 100644
--- a/arch/x86_64/boot/compressed/head.S
+++ b/arch/x86_64/boot/compressed/head.S
@@ -26,116 +26,279 @@
 
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/msr.h>
 
+.section ".text.head"
 	.code32
 	.globl startup_32
-	
+
 startup_32:
 	cld
 	cli
-	movl $(__KERNEL_DS),%eax
-	movl %eax,%ds
-	movl %eax,%es
-	movl %eax,%fs
-	movl %eax,%gs
-
-	lss stack_start,%esp
-	xorl %eax,%eax
-1:	incl %eax		# check that A20 really IS enabled
-	movl %eax,0x000000	# loop forever if it isn't
-	cmpl %eax,0x100000
-	je 1b
+	movl	$(__KERNEL_DS), %eax
+	movl	%eax, %ds
+	movl	%eax, %es
+	movl	%eax, %ss
+
+/* Calculate the delta between where we were compiled to run
+ * at and where we were actually loaded at.  This can only be done
+ * with a short local call on x86.  Nothing  else will tell us what
+ * address we are running at.  The reserved chunk of the real-mode
+ * data at 0x34-0x3f are used as the stack for this calculation.
+ * Only 4 bytes are needed.
+ */
+	leal	0x40(%esi), %esp
+	call	1f
+1:	popl	%ebp
+	subl	$1b, %ebp
+
+/* setup a stack and make sure cpu supports long mode. */
+	movl	$user_stack_end, %eax
+	addl	%ebp, %eax
+	movl	%eax, %esp
+
+	call	verify_cpu
+	testl	%eax, %eax
+	jnz	no_longmode
+
+/* Compute the delta between where we were compiled to run at
+ * and where the code will actually run at.
+ */
+/* %ebp contains the address we are loaded at by the boot loader and %ebx
+ * contains the address where we should move the kernel image temporarily
+ * for safe in-place decompression.
+ */
+
+#ifdef CONFIG_RELOCATABLE
+	movl	%ebp, %ebx
+	addl	$(LARGE_PAGE_SIZE -1), %ebx
+	andl	$LARGE_PAGE_MASK, %ebx
+#else
+	movl	$CONFIG_PHYSICAL_START, %ebx
+#endif
+
+	/* Replace the compressed data size with the uncompressed size */
+	subl	input_len(%ebp), %ebx
+	movl	output_len(%ebp), %eax
+	addl	%eax, %ebx
+	/* Add 8 bytes for every 32K input block */
+	shrl	$12, %eax
+	addl	%eax, %ebx
+	/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+	addl	$(32768 + 18 + 4095), %ebx
+	andl	$~4095, %ebx
 
 /*
- * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
+ * Prepare for entering 64 bit mode
  */
-	pushl $0
-	popfl
+
+	/* Load new GDT with the 64bit segments using 32bit descriptor */
+	leal	gdt(%ebp), %eax
+	movl	%eax, gdt+2(%ebp)
+	lgdt	gdt(%ebp)
+
+	/* Enable PAE mode */
+	xorl	%eax, %eax
+	orl	$(1 << 5), %eax
+	movl	%eax, %cr4
+
+ /*
+  * Build early 4G boot pagetable
+  */
+	/* Initialize Page tables to 0*/
+	leal	pgtable(%ebx), %edi
+	xorl	%eax, %eax
+	movl	$((4096*6)/4), %ecx
+	rep	stosl
+
+	/* Build Level 4 */
+	leal	pgtable + 0(%ebx), %edi
+	leal	0x1007 (%edi), %eax
+	movl	%eax, 0(%edi)
+
+	/* Build Level 3 */
+	leal	pgtable + 0x1000(%ebx), %edi
+	leal	0x1007(%edi), %eax
+	movl	$4, %ecx
+1:	movl	%eax, 0x00(%edi)
+	addl	$0x00001000, %eax
+	addl	$8, %edi
+	decl	%ecx
+	jnz	1b
+
+	/* Build Level 2 */
+	leal	pgtable + 0x2000(%ebx), %edi
+	movl	$0x00000183, %eax
+	movl	$2048, %ecx
+1:	movl	%eax, 0(%edi)
+	addl	$0x00200000, %eax
+	addl	$8, %edi
+	decl	%ecx
+	jnz	1b
+
+	/* Enable the boot page tables */
+	leal	pgtable(%ebx), %eax
+	movl	%eax, %cr3
+
+	/* Enable Long mode in EFER (Extended Feature Enable Register) */
+	movl	$MSR_EFER, %ecx
+	rdmsr
+	btsl	$_EFER_LME, %eax
+	wrmsr
+
+	/* Setup for the jump to 64bit mode
+	 *
+	 * When the jump is performend we will be in long mode but
+	 * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
+	 * (and in turn EFER.LMA = 1).	To jump into 64bit mode we use
+	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+	 * We place all of the values on our mini stack so lret can
+	 * used to perform that far jump.
+	 */
+	pushl	$__KERNEL_CS
+	leal	startup_64(%ebp), %eax
+	pushl	%eax
+
+	/* Enter paged protected Mode, activating Long Mode */
+	movl	$0x80000001, %eax /* Enable Paging and Protected mode */
+	movl	%eax, %cr0
+
+	/* Jump from 32bit compatibility mode into 64bit mode. */
+	lret
+
+no_longmode:
+	/* This isn't an x86-64 CPU so hang */
+1:
+	hlt
+	jmp     1b
+
+#include "../../kernel/verify_cpu.S"
+
+	/* Be careful here startup_64 needs to be at a predictable
+	 * address so I can export it in an ELF header.  Bootloaders
+	 * should look at the ELF header to find this address, as
+	 * it may change in the future.
+	 */
+	.code64
+	.org 0x200
+ENTRY(startup_64)
+	/* We come here either from startup_32 or directly from a
+	 * 64bit bootloader.  If we come here from a bootloader we depend on
+	 * an identity mapped page table being provied that maps our
+	 * entire text+data+bss and hopefully all of memory.
+	 */
+
+	/* Setup data segments. */
+	xorl	%eax, %eax
+	movl	%eax, %ds
+	movl	%eax, %es
+	movl	%eax, %ss
+
+	/* Compute the decompressed kernel start address.  It is where
+	 * we were loaded at aligned to a 2M boundary. %rbp contains the
+	 * decompressed kernel start address.
+	 *
+	 * If it is a relocatable kernel then decompress and run the kernel
+	 * from load address aligned to 2MB addr, otherwise decompress and
+	 * run the kernel from CONFIG_PHYSICAL_START
+	 */
+
+	/* Start with the delta to where the kernel will run at. */
+#ifdef CONFIG_RELOCATABLE
+	leaq	startup_32(%rip) /* - $startup_32 */, %rbp
+	addq	$(LARGE_PAGE_SIZE - 1), %rbp
+	andq	$LARGE_PAGE_MASK, %rbp
+	movq	%rbp, %rbx
+#else
+	movq	$CONFIG_PHYSICAL_START, %rbp
+	movq	%rbp, %rbx
+#endif
+
+	/* Replace the compressed data size with the uncompressed size */
+	movl	input_len(%rip), %eax
+	subq	%rax, %rbx
+	movl	output_len(%rip), %eax
+	addq	%rax, %rbx
+	/* Add 8 bytes for every 32K input block */
+	shrq	$12, %rax
+	addq	%rax, %rbx
+	/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+	addq	$(32768 + 18 + 4095), %rbx
+	andq	$~4095, %rbx
+
+/* Copy the compressed kernel to the end of our buffer
+ * where decompression in place becomes safe.
+ */
+	leaq	_end(%rip), %r8
+	leaq	_end(%rbx), %r9
+	movq	$_end /* - $startup_32 */, %rcx
+1:	subq	$8, %r8
+	subq	$8, %r9
+	movq	0(%r8), %rax
+	movq	%rax, 0(%r9)
+	subq	$8, %rcx
+	jnz	1b
+
+/*
+ * Jump to the relocated address.
+ */
+	leaq	relocated(%rbx), %rax
+	jmp	*%rax
+
+.section ".text"
+relocated:
+
 /*
  * Clear BSS
  */
-	xorl %eax,%eax
-	movl $_edata,%edi
-	movl $_end,%ecx
-	subl %edi,%ecx
+	xorq	%rax, %rax
+	leaq    _edata(%rbx), %rdi
+	leaq    _end(%rbx), %rcx
+	subq	%rdi, %rcx
 	cld
 	rep
 	stosb
+
+	/* Setup the stack */
+	leaq	user_stack_end(%rip), %rsp
+
+	/* zero EFLAGS after setting rsp */
+	pushq	$0
+	popfq
+
 /*
  * Do the decompression, and jump to the new kernel..
  */
-	subl $16,%esp	# place for structure on the stack
-	movl %esp,%eax
-	pushl %esi	# real mode pointer as second arg
-	pushl %eax	# address of structure as first arg
-	call decompress_kernel
-	orl  %eax,%eax 
-	jnz  3f
-	addl $8,%esp
-	xorl %ebx,%ebx
-	ljmp $(__KERNEL_CS), $__PHYSICAL_START
+	pushq	%rsi			# Save the real mode argument
+	movq	%rsi, %rdi		# real mode address
+	leaq	_heap(%rip), %rsi	# _heap
+	leaq	input_data(%rip), %rdx  # input_data
+	movl	input_len(%rip), %eax
+	movq	%rax, %rcx		# input_len
+	movq	%rbp, %r8		# output
+	call	decompress_kernel
+	popq	%rsi
 
-/*
- * We come here, if we were loaded high.
- * We need to move the move-in-place routine down to 0x1000
- * and then start it with the buffer addresses in registers,
- * which we got from the stack.
- */
-3:
-	movl %esi,%ebx	
-	movl $move_routine_start,%esi
-	movl $0x1000,%edi
-	movl $move_routine_end,%ecx
-	subl %esi,%ecx
-	addl $3,%ecx
-	shrl $2,%ecx
-	cld
-	rep
-	movsl
-
-	popl %esi	# discard the address
-	addl $4,%esp	# real mode pointer
-	popl %esi	# low_buffer_start
-	popl %ecx	# lcount
-	popl %edx	# high_buffer_start
-	popl %eax	# hcount
-	movl $__PHYSICAL_START,%edi
-	cli		# make sure we don't get interrupted
-	ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
 
 /*
- * Routine (template) for moving the decompressed kernel in place,
- * if we were high loaded. This _must_ PIC-code !
+ * Jump to the decompressed kernel.
  */
-move_routine_start:
-	movl %ecx,%ebp
-	shrl $2,%ecx
-	rep
-	movsl
-	movl %ebp,%ecx
-	andl $3,%ecx
-	rep
-	movsb
-	movl %edx,%esi
-	movl %eax,%ecx	# NOTE: rep movsb won't move if %ecx == 0
-	addl $3,%ecx
-	shrl $2,%ecx
-	rep
-	movsl
-	movl %ebx,%esi	# Restore setup pointer
-	xorl %ebx,%ebx
-	ljmp $(__KERNEL_CS), $__PHYSICAL_START
-move_routine_end:
+	jmp	*%rbp
 
-
-/* Stack for uncompression */ 	
-	.align 32
-user_stack:	 	
+	.data
+gdt:
+	.word	gdt_end - gdt
+	.long	gdt
+	.word	0
+	.quad	0x0000000000000000	/* NULL descriptor */
+	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
+	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
+gdt_end:
+	.bss
+/* Stack for uncompression */
+	.balign 4
+user_stack:
 	.fill 4096,4,0
-stack_start:	
-	.long user_stack+4096
-	.word __KERNEL_DS
-
+user_stack_end:
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
index 3755b2e..f932b0e 100644
--- a/arch/x86_64/boot/compressed/misc.c
+++ b/arch/x86_64/boot/compressed/misc.c
@@ -9,10 +9,95 @@
  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
  */
 
+#define _LINUX_STRING_H_ 1
+#define __LINUX_BITMAP_H 1
+
+#include <linux/linkage.h>
 #include <linux/screen_info.h>
 #include <asm/io.h>
 #include <asm/page.h>
 
+/* WARNING!!
+ * This code is compiled with -fPIC and it is relocated dynamically
+ * at run time, but no relocation processing is performed.
+ * This means that it is not safe to place pointers in static structures.
+ */
+
+/*
+ * Getting to provable safe in place decompression is hard.
+ * Worst case behaviours need to be analized.
+ * Background information:
+ *
+ * The file layout is:
+ *    magic[2]
+ *    method[1]
+ *    flags[1]
+ *    timestamp[4]
+ *    extraflags[1]
+ *    os[1]
+ *    compressed data blocks[N]
+ *    crc[4] orig_len[4]
+ *
+ * resulting in 18 bytes of non compressed data overhead.
+ *
+ * Files divided into blocks
+ * 1 bit (last block flag)
+ * 2 bits (block type)
+ *
+ * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
+ * The smallest block type encoding is always used.
+ *
+ * stored:
+ *    32 bits length in bytes.
+ *
+ * fixed:
+ *    magic fixed tree.
+ *    symbols.
+ *
+ * dynamic:
+ *    dynamic tree encoding.
+ *    symbols.
+ *
+ *
+ * The buffer for decompression in place is the length of the
+ * uncompressed data, plus a small amount extra to keep the algorithm safe.
+ * The compressed data is placed at the end of the buffer.  The output
+ * pointer is placed at the start of the buffer and the input pointer
+ * is placed where the compressed data starts.  Problems will occur
+ * when the output pointer overruns the input pointer.
+ *
+ * The output pointer can only overrun the input pointer if the input
+ * pointer is moving faster than the output pointer.  A condition only
+ * triggered by data whose compressed form is larger than the uncompressed
+ * form.
+ *
+ * The worst case at the block level is a growth of the compressed data
+ * of 5 bytes per 32767 bytes.
+ *
+ * The worst case internal to a compressed block is very hard to figure.
+ * The worst case can at least be boundined by having one bit that represents
+ * 32764 bytes and then all of the rest of the bytes representing the very
+ * very last byte.
+ *
+ * All of which is enough to compute an amount of extra data that is required
+ * to be safe.  To avoid problems at the block level allocating 5 extra bytes
+ * per 32767 bytes of data is sufficient.  To avoind problems internal to a block
+ * adding an extra 32767 bytes (the worst case uncompressed block size) is
+ * sufficient, to ensure that in the worst case the decompressed data for
+ * block will stop the byte before the compressed data for a block begins.
+ * To avoid problems with the compressed data's meta information an extra 18
+ * bytes are needed.  Leading to the formula:
+ *
+ * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
+ *
+ * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
+ * Adding 32768 instead of 32767 just makes for round numbers.
+ * Adding the decompressor_size is necessary as it musht live after all
+ * of the data as well.  Last I measured the decompressor is about 14K.
+ * 10K of actuall data and 4K of bss.
+ *
+ */
+
 /*
  * gzip declarations
  */
@@ -28,15 +113,20 @@ typedef unsigned char  uch;
 typedef unsigned short ush;
 typedef unsigned long  ulg;
 
-#define WSIZE 0x8000		/* Window size must be at least 32k, */
-				/* and a power of two */
+#define WSIZE 0x80000000	/* Window size must be at least 32k,
+				 * and a power of two
+				 * We don't actually have a window just
+				 * a huge output buffer so I report
+				 * a 2G windows size, as that should
+				 * always be larger than our output buffer.
+				 */
 
-static uch *inbuf;	     /* input buffer */
-static uch window[WSIZE];    /* Sliding window buffer */
+static uch *inbuf;	/* input buffer */
+static uch *window;	/* Sliding window buffer, (and final output buffer) */
 
-static unsigned insize = 0;  /* valid bytes in inbuf */
-static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0;  /* bytes in output buffer */
+static unsigned insize;  /* valid bytes in inbuf */
+static unsigned inptr;   /* index of next byte to be processed in inbuf */
+static unsigned outcnt;  /* bytes in output buffer */
 
 /* gzip flag byte */
 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
@@ -87,8 +177,6 @@ extern unsigned char input_data[];
 extern int input_len;
 
 static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
 
 static void *malloc(int size);
 static void free(void *where);
@@ -98,17 +186,10 @@ static void *memcpy(void *dest, const vo
 
 static void putstr(const char *);
 
-extern int end;
-static long free_mem_ptr = (long)&end;
+static long free_mem_ptr;
 static long free_mem_end_ptr;
 
-#define INPLACE_MOVE_ROUTINE  0x1000
-#define LOW_BUFFER_START      0x2000
-#define LOW_BUFFER_MAX       0x90000
-#define HEAP_SIZE             0x3000
-static unsigned int low_buffer_end, low_buffer_size;
-static int high_loaded =0;
-static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+#define HEAP_SIZE             0x7000
 
 static char *vidmem = (char *)0xb8000;
 static int vidport;
@@ -218,58 +299,31 @@ static void* memcpy(void* dest, const vo
  */
 static int fill_inbuf(void)
 {
-	if (insize != 0) {
-		error("ran out of input data");
-	}
-
-	inbuf = input_data;
-	insize = input_len;
-	inptr = 1;
-	return inbuf[0];
+	error("ran out of input data");
+	return 0;
 }
 
 /* ===========================================================================
  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
  * (Used for the decompressed data only.)
  */
-static void flush_window_low(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in, *out, ch;
-    
-    in = window;
-    out = &output_data[output_ptr]; 
-    for (n = 0; n < outcnt; n++) {
-	    ch = *out++ = *in++;
-	    c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    output_ptr += (ulg)outcnt;
-    outcnt = 0;
-}
-
-static void flush_window_high(void)
-{
-    ulg c = crc;         /* temporary variable */
-    unsigned n;
-    uch *in,  ch;
-    in = window;
-    for (n = 0; n < outcnt; n++) {
-	ch = *output_data++ = *in++;
-	if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
-	c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
-    }
-    crc = c;
-    bytes_out += (ulg)outcnt;
-    outcnt = 0;
-}
-
 static void flush_window(void)
 {
-	if (high_loaded) flush_window_high();
-	else flush_window_low();
+	/* With my window equal to my output buffer
+	 * I only need to compute the crc here.
+	 */
+	ulg c = crc;         /* temporary variable */
+	unsigned n;
+	uch *in, ch;
+
+	in = window;
+	for (n = 0; n < outcnt; n++) {
+		ch = *in++;
+		c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+	}
+	crc = c;
+	bytes_out += (ulg)outcnt;
+	outcnt = 0;
 }
 
 static void error(char *x)
@@ -281,57 +335,8 @@ static void error(char *x)
 	while(1);	/* Halt */
 }
 
-static void setup_normal_output_buffer(void)
-{
-#ifdef STANDARD_MEMORY_BIOS_CALL
-	if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
-#else
-	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
-#endif
-	output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
-	free_mem_end_ptr = (long)real_mode;
-}
-
-struct moveparams {
-	uch *low_buffer_start;  int lcount;
-	uch *high_buffer_start; int hcount;
-};
-
-static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
-{
-	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
-#ifdef STANDARD_MEMORY_BIOS_CALL
-	if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
-#else
-	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
-#endif	
-	mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
-	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
-	  ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
-	low_buffer_size = low_buffer_end - LOW_BUFFER_START;
-	high_loaded = 1;
-	free_mem_end_ptr = (long)high_buffer_start;
-	if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
-		high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
-		mv->hcount = 0; /* say: we need not to move high_buffer */
-	}
-	else mv->hcount = -1;
-	mv->high_buffer_start = high_buffer_start;
-}
-
-static void close_output_buffer_if_we_run_high(struct moveparams *mv)
-{
-	if (bytes_out > low_buffer_size) {
-		mv->lcount = low_buffer_size;
-		if (mv->hcount)
-			mv->hcount = bytes_out - low_buffer_size;
-	} else {
-		mv->lcount = bytes_out;
-		mv->hcount = 0;
-	}
-}
-
-int decompress_kernel(struct moveparams *mv, void *rmode)
+asmlinkage void decompress_kernel(void *rmode, unsigned long heap,
+	uch *input_data, unsigned long input_len, uch *output)
 {
 	real_mode = rmode;
 
@@ -346,13 +351,21 @@ int decompress_kernel(struct moveparams 
 	lines = RM_SCREEN_INFO.orig_video_lines;
 	cols = RM_SCREEN_INFO.orig_video_cols;
 
-	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
-	else setup_output_buffer_if_we_run_high(mv);
+	window = output;  		/* Output buffer (Normally at 1M) */
+	free_mem_ptr     = heap;	/* Heap  */
+	free_mem_end_ptr = heap + HEAP_SIZE;
+	inbuf  = input_data;		/* Input buffer */
+	insize = input_len;
+	inptr  = 0;
+
+	if ((ulg)output & (__KERNEL_ALIGN - 1))
+		error("Destination address not 2M aligned");
+	if ((ulg)output >= 0xffffffffffUL)
+		error("Destination address too large");
 
 	makecrc();
 	putstr(".\nDecompressing Linux...");
 	gunzip();
 	putstr("done.\nBooting the kernel.\n");
-	if (high_loaded) close_output_buffer_if_we_run_high(mv);
-	return high_loaded;
+	return;
 }
diff --git a/arch/x86_64/boot/compressed/vmlinux.lds b/arch/x86_64/boot/compressed/vmlinux.lds
new file mode 100644
index 0000000..94c13e5
--- /dev/null
+++ b/arch/x86_64/boot/compressed/vmlinux.lds
@@ -0,0 +1,44 @@
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(startup_64)
+SECTIONS
+{
+	/* Be careful parts of head.S assume startup_32 is at
+ 	 * address 0.
+	 */
+	. = 0;
+	.text :	{
+		_head = . ;
+		*(.text.head)
+		_ehead = . ;
+		*(.text.compressed)
+		_text = .; 	/* Text */
+		*(.text)
+		*(.text.*)
+		_etext = . ;
+	}
+	.rodata : {
+		_rodata = . ;
+		*(.rodata)	 /* read-only data */
+		*(.rodata.*)
+		_erodata = . ;
+	}
+	.data :	{
+		_data = . ;
+		*(.data)
+		*(.data.*)
+		_edata = . ;
+	}
+	.bss : {
+		_bss = . ;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		. = ALIGN(8);
+		_end = . ;
+		. = ALIGN(4096);
+		pgtable = . ;
+		. = . + 4096 * 6;
+		_heap = .;
+	}
+}
diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr
index 1ed9d79..bd1429c 100644
--- a/arch/x86_64/boot/compressed/vmlinux.scr
+++ b/arch/x86_64/boot/compressed/vmlinux.scr
@@ -1,9 +1,10 @@
 SECTIONS
 {
-  .data : { 
+  .text.compressed : {
 	input_len = .;
-	LONG(input_data_end - input_data) input_data = .; 
-	*(.data) 
-	input_data_end = .; 
+	LONG(input_data_end - input_data) input_data = .;
+	*(.data)
+	output_len = . - 4;
+	input_data_end = .;
 	}
 }
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
index 770940c..e9e33f9 100644
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -51,6 +51,7 @@ #include <linux/compile.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
 #include <asm/page.h>
+#include <asm/setup.h>
 
 /* Signature words to ensure LILO loaded us right */
 #define SIG1	0xAA55
@@ -80,7 +81,7 @@ start:
 # This is the setup header, and it must start at %cs:2 (old 0x9020:2)
 
 		.ascii	"HdrS"		# header signature
-		.word	0x0204		# header version number (>= 0x0105)
+		.word	0x0206		# header version number (>= 0x0105)
 					# or else old loadlin-1.5 will fail)
 realmode_swtch:	.word	0, 0		# default_switch, SETUPSEG
 start_sys_seg:	.word	SYSSEG
@@ -155,7 +156,20 @@ cmd_line_ptr:	.long 0			# (Header versio
 					# low memory 0x10000 or higher.
 
 ramdisk_max:	.long 0xffffffff
-	
+kernel_alignment:  .long 0x200000       # physical addr alignment required for
+					# protected mode relocatable kernel
+#ifdef CONFIG_RELOCATABLE
+relocatable_kernel:    .byte 1
+#else
+relocatable_kernel:    .byte 0
+#endif
+pad2:                  .byte 0
+pad3:                  .word 0
+
+cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
+                                                #added with boot protocol
+                                                #version 2.06
+
 trampoline:	call	start_of_setup
 		.align 16
 					# The offset at this point is 0x240
@@ -290,64 +304,10 @@ loader_ok:
 	movw	%cs,%ax
 	movw	%ax,%ds
 	
-	/* minimum CPUID flags for x86-64 */
-	/* see http://www.x86-64.org/lists/discuss/msg02971.html */		
-#define SSE_MASK ((1<<25)|(1<<26))
-#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\
-					   (1<<13)|(1<<15)|(1<<24))
-#define REQUIRED_MASK2 (1<<29)
-
-	pushfl				/* standard way to check for cpuid */
-	popl	%eax
-	movl	%eax,%ebx
-	xorl	$0x200000,%eax
-	pushl	%eax
-	popfl
-	pushfl
-	popl	%eax
-	cmpl	%eax,%ebx
-	jz	no_longmode		/* cpu has no cpuid */
-	movl	$0x0,%eax
-	cpuid
-	cmpl	$0x1,%eax
-	jb	no_longmode		/* no cpuid 1 */
-	xor	%di,%di
-	cmpl	$0x68747541,%ebx	/* AuthenticAMD */
-	jnz	noamd
-	cmpl	$0x69746e65,%edx
-	jnz	noamd
-	cmpl	$0x444d4163,%ecx
-	jnz	noamd
-	mov	$1,%di			/* cpu is from AMD */
-noamd:		
-	movl    $0x1,%eax
-	cpuid
-	andl	$REQUIRED_MASK1,%edx
-	xorl	$REQUIRED_MASK1,%edx
-	jnz	no_longmode
-	movl    $0x80000000,%eax
-	cpuid
-	cmpl    $0x80000001,%eax
-	jb      no_longmode             /* no extended cpuid */
-	movl    $0x80000001,%eax
-	cpuid
-	andl    $REQUIRED_MASK2,%edx
-	xorl    $REQUIRED_MASK2,%edx
-	jnz     no_longmode
-sse_test:		
-	movl	$1,%eax
-	cpuid
-	andl	$SSE_MASK,%edx
-	cmpl	$SSE_MASK,%edx
-	je	sse_ok
-	test	%di,%di
-	jz	no_longmode	/* only try to force SSE on AMD */ 
-	movl	$0xc0010015,%ecx	/* HWCR */
-	rdmsr
-	btr	$15,%eax	/* enable SSE */
-	wrmsr
-	xor	%di,%di		/* don't loop */
-	jmp	sse_test	/* try again */	
+	call verify_cpu
+	testl %eax,%eax
+	jz sse_ok
+
 no_longmode:
 	call	beep
 	lea	long_mode_panic,%si
@@ -357,7 +317,8 @@ no_longmode_loop:		
 long_mode_panic:
 	.string "Your CPU does not support long mode. Use a 32bit distribution."
 	.byte 0
-	
+
+#include "../kernel/verify_cpu.S"
 sse_ok:
 	popw	%ds
 	
@@ -846,7 +807,7 @@ gdt_48:
 
 # Include video setup & detection code
 
-#include "video.S"
+#include "../../i386/boot/video.S"
 
 # Setup signature -- must be last
 setup_sig1:	.word	SIG1
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
deleted file mode 100644
index 6090516..0000000
--- a/arch/x86_64/boot/video.S
+++ /dev/null
@@ -1,2043 +0,0 @@
-/*	video.S
- *
- *	Display adapter & video mode setup, version 2.13 (14-May-99)
- *
- *	Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
- *	Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
- *
- *	Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
- *
- *	For further information, look at Documentation/svga.txt.
- *
- */
-
-/* Enable autodetection of SVGA adapters and modes. */
-#undef CONFIG_VIDEO_SVGA
-
-/* Enable autodetection of VESA modes */
-#define CONFIG_VIDEO_VESA
-
-/* Enable compacting of mode table */
-#define CONFIG_VIDEO_COMPACT
-
-/* Retain screen contents when switching modes */
-#define CONFIG_VIDEO_RETAIN
-
-/* Enable local mode list */
-#undef CONFIG_VIDEO_LOCAL
-
-/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
-#undef CONFIG_VIDEO_400_HACK
-
-/* Hack that lets you force specific BIOS mode ID and specific dimensions */
-#undef CONFIG_VIDEO_GFX_HACK
-#define VIDEO_GFX_BIOS_AX 0x4f02	/* 800x600 on ThinkPad */
-#define VIDEO_GFX_BIOS_BX 0x0102
-#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425	/* 100x37 */
-
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- *	NORMAL_VGA (-1)
- *	EXTENDED_VGA (-2)
- *	ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-/* Special video modes */
-#define VIDEO_FIRST_SPECIAL 0x0f00
-#define VIDEO_80x25 0x0f00
-#define VIDEO_8POINT 0x0f01
-#define VIDEO_80x43 0x0f02
-#define VIDEO_80x28 0x0f03
-#define VIDEO_CURRENT_MODE 0x0f04
-#define VIDEO_80x30 0x0f05
-#define VIDEO_80x34 0x0f06
-#define VIDEO_80x60 0x0f07
-#define VIDEO_GFX_HACK 0x0f08
-#define VIDEO_LAST_SPECIAL 0x0f09
-
-/* Video modes given by resolution */
-#define VIDEO_FIRST_RESOLUTION 0x1000
-
-/* The "recalculate timings" flag */
-#define VIDEO_RECALC 0x8000
-
-/* Positions of various video parameters passed to the kernel */
-/* (see also include/linux/tty.h) */
-#define PARAM_CURSOR_POS	0x00
-#define PARAM_VIDEO_PAGE	0x04
-#define PARAM_VIDEO_MODE	0x06
-#define PARAM_VIDEO_COLS	0x07
-#define PARAM_VIDEO_EGA_BX	0x0a
-#define PARAM_VIDEO_LINES	0x0e
-#define PARAM_HAVE_VGA		0x0f
-#define PARAM_FONT_POINTS	0x10
-
-#define PARAM_LFB_WIDTH		0x12
-#define PARAM_LFB_HEIGHT	0x14
-#define PARAM_LFB_DEPTH		0x16
-#define PARAM_LFB_BASE		0x18
-#define PARAM_LFB_SIZE		0x1c
-#define PARAM_LFB_LINELENGTH	0x24
-#define PARAM_LFB_COLORS	0x26
-#define PARAM_VESAPM_SEG	0x2e
-#define PARAM_VESAPM_OFF	0x30
-#define PARAM_LFB_PAGES		0x32
-#define PARAM_VESA_ATTRIB	0x34
-#define PARAM_CAPABILITIES	0x36
-
-/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
-#ifdef CONFIG_VIDEO_RETAIN
-#define DO_STORE call store_screen
-#else
-#define DO_STORE
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# This is the main entry point called by setup.S
-# %ds *must* be pointing to the bootsector
-video:	pushw	%ds		# We use different segments
-	pushw	%ds		# FS contains original DS
-	popw	%fs
-	pushw	%cs		# DS is equal to CS
-	popw	%ds
-	pushw	%cs		# ES is equal to CS
-	popw	%es
-	xorw	%ax, %ax
-	movw	%ax, %gs	# GS is zero
-	cld
-	call	basic_detect	# Basic adapter type testing (EGA/VGA/MDA/CGA)
-#ifdef CONFIG_VIDEO_SELECT
-	movw	%fs:(0x01fa), %ax		# User selected video mode
-	cmpw	$ASK_VGA, %ax			# Bring up the menu
-	jz	vid2
-
-	call	mode_set			# Set the mode
-	jc	vid1
-
-	leaw	badmdt, %si			# Invalid mode ID
-	call	prtstr
-vid2:	call	mode_menu
-vid1:
-#ifdef CONFIG_VIDEO_RETAIN
-	call	restore_screen			# Restore screen contents
-#endif /* CONFIG_VIDEO_RETAIN */
-	call	store_edid
-#endif /* CONFIG_VIDEO_SELECT */
-	call	mode_params			# Store mode parameters
-	popw	%ds				# Restore original DS
-	ret
-
-# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
-basic_detect:
-	movb	$0, %fs:(PARAM_HAVE_VGA)
-	movb	$0x12, %ah	# Check EGA/VGA
-	movb	$0x10, %bl
-	int	$0x10
-	movw	%bx, %fs:(PARAM_VIDEO_EGA_BX)	# Identifies EGA to the kernel
-	cmpb	$0x10, %bl			# No, it's a CGA/MDA/HGA card.
-	je	basret
-
-	incb	adapter
-	movw	$0x1a00, %ax			# Check EGA or VGA?
-	int	$0x10
-	cmpb	$0x1a, %al			# 1a means VGA...
-	jne	basret				# anything else is EGA.
-	
-	incb	%fs:(PARAM_HAVE_VGA)		# We've detected a VGA
-	incb	adapter
-basret:	ret
-
-# Store the video mode parameters for later usage by the kernel.
-# This is done by asking the BIOS except for the rows/columns
-# parameters in the default 80x25 mode -- these are set directly,
-# because some very obscure BIOSes supply insane values.
-mode_params:
-#ifdef CONFIG_VIDEO_SELECT
-	cmpb	$0, graphic_mode
-	jnz	mopar_gr
-#endif
-	movb	$0x03, %ah			# Read cursor position
-	xorb	%bh, %bh
-	int	$0x10
-	movw	%dx, %fs:(PARAM_CURSOR_POS)
-	movb	$0x0f, %ah			# Read page/mode/width
-	int	$0x10
-	movw	%bx, %fs:(PARAM_VIDEO_PAGE)
-	movw	%ax, %fs:(PARAM_VIDEO_MODE)	# Video mode and screen width
-	cmpb	$0x7, %al			# MDA/HGA => segment differs
-	jnz	mopar0
-
-	movw	$0xb000, video_segment
-mopar0: movw	%gs:(0x485), %ax		# Font size
-	movw	%ax, %fs:(PARAM_FONT_POINTS)	# (valid only on EGA/VGA)
-	movw	force_size, %ax			# Forced size?
-	orw	%ax, %ax
-	jz	mopar1
-
-	movb	%ah, %fs:(PARAM_VIDEO_COLS)
-	movb	%al, %fs:(PARAM_VIDEO_LINES)
-	ret
-
-mopar1:	movb	$25, %al
-	cmpb	$0, adapter			# If we are on CGA/MDA/HGA, the
-	jz	mopar2				# screen must have 25 lines.
-
-	movb	%gs:(0x484), %al		# On EGA/VGA, use the EGA+ BIOS
-	incb	%al				# location of max lines.
-mopar2: movb	%al, %fs:(PARAM_VIDEO_LINES)
-	ret
-
-#ifdef CONFIG_VIDEO_SELECT
-# Fetching of VESA frame buffer parameters
-mopar_gr:
-	leaw	modelist+1024, %di
-	movb	$0x23, %fs:(PARAM_HAVE_VGA)
-	movw	16(%di), %ax
-	movw	%ax, %fs:(PARAM_LFB_LINELENGTH)
-	movw	18(%di), %ax
-	movw	%ax, %fs:(PARAM_LFB_WIDTH)
-	movw	20(%di), %ax
-	movw	%ax, %fs:(PARAM_LFB_HEIGHT)
-	movb	25(%di), %al
-	movb	$0, %ah
-	movw	%ax, %fs:(PARAM_LFB_DEPTH)
-	movb	29(%di), %al	
-	movb	$0, %ah
-	movw	%ax, %fs:(PARAM_LFB_PAGES)
-	movl	40(%di), %eax
-	movl	%eax, %fs:(PARAM_LFB_BASE)
-	movl	31(%di), %eax
-	movl	%eax, %fs:(PARAM_LFB_COLORS)
-	movl	35(%di), %eax
-	movl	%eax, %fs:(PARAM_LFB_COLORS+4)
-	movw	0(%di), %ax
-	movw	%ax, %fs:(PARAM_VESA_ATTRIB)
-
-# get video mem size
-	leaw	modelist+1024, %di
-	movw	$0x4f00, %ax
-	int	$0x10
-	xorl	%eax, %eax
-	movw	18(%di), %ax
-	movl	%eax, %fs:(PARAM_LFB_SIZE)
-
-# store mode capabilities
-	movl 10(%di), %eax
-	movl %eax, %fs:(PARAM_CAPABILITIES)
-
-# switching the DAC to 8-bit is for <= 8 bpp only
-	movw	%fs:(PARAM_LFB_DEPTH), %ax
-	cmpw	$8, %ax
-	jg	dac_done
-
-# get DAC switching capability
-	xorl	%eax, %eax
-	movb	10(%di), %al
-	testb	$1, %al
-	jz	dac_set
-
-# attempt to switch DAC to 8-bit
-	movw	$0x4f08, %ax
-	movw	$0x0800, %bx
-	int	$0x10
-	cmpw	$0x004f, %ax
-	jne     dac_set
-	movb    %bh, dac_size		# store actual DAC size
-
-dac_set:
-# set color size to DAC size
-	movb	dac_size, %al
-	movb	%al, %fs:(PARAM_LFB_COLORS+0)
-	movb	%al, %fs:(PARAM_LFB_COLORS+2)
-	movb	%al, %fs:(PARAM_LFB_COLORS+4)
-	movb	%al, %fs:(PARAM_LFB_COLORS+6)
-
-# set color offsets to 0
-	movb	$0, %fs:(PARAM_LFB_COLORS+1)
-	movb	$0, %fs:(PARAM_LFB_COLORS+3)
-	movb	$0, %fs:(PARAM_LFB_COLORS+5)
-	movb	$0, %fs:(PARAM_LFB_COLORS+7)
-
-dac_done:
-# get protected mode interface informations
-	movw	$0x4f0a, %ax
-	xorw	%bx, %bx
-	xorw	%di, %di
-	int	$0x10
-	cmp	$0x004f, %ax
-	jnz	no_pm
-
-	movw	%es, %fs:(PARAM_VESAPM_SEG)
-	movw	%di, %fs:(PARAM_VESAPM_OFF)
-no_pm:	ret
-
-# The video mode menu
-mode_menu:
-	leaw	keymsg, %si			# "Return/Space/Timeout" message
-	call	prtstr
-	call	flush
-nokey:	call	getkt
-
-	cmpb	$0x0d, %al			# ENTER ?
-	je	listm				# yes - manual mode selection
-
-	cmpb	$0x20, %al			# SPACE ?
-	je	defmd1				# no - repeat
-
-	call 	beep
-	jmp	nokey
-
-defmd1:	ret					# No mode chosen? Default 80x25
-
-listm:	call	mode_table			# List mode table
-listm0:	leaw	name_bann, %si			# Print adapter name
-	call	prtstr
-	movw	card_name, %si
-	orw	%si, %si
-	jnz	an2
-
-	movb	adapter, %al
-	leaw	old_name, %si
-	orb	%al, %al
-	jz	an1
-
-	leaw	ega_name, %si
-	decb	%al
-	jz	an1
-
-	leaw	vga_name, %si
-	jmp	an1
-
-an2:	call	prtstr
-	leaw	svga_name, %si
-an1:	call	prtstr
-	leaw	listhdr, %si			# Table header
-	call	prtstr
-	movb	$0x30, %dl			# DL holds mode number
-	leaw	modelist, %si
-lm1:	cmpw	$ASK_VGA, (%si)			# End?
-	jz	lm2
-
-	movb	%dl, %al			# Menu selection number
-	call	prtchr
-	call	prtsp2
-	lodsw
-	call	prthw				# Mode ID
-	call	prtsp2
-	movb	0x1(%si), %al
-	call	prtdec				# Rows
-	movb	$0x78, %al			# the letter 'x'
-	call	prtchr
-	lodsw
-	call	prtdec				# Columns
-	movb	$0x0d, %al			# New line
-	call	prtchr
-	movb	$0x0a, %al
-	call	prtchr
-	incb	%dl				# Next character
-	cmpb	$0x3a, %dl
-	jnz	lm1
-
-	movb	$0x61, %dl
-	jmp	lm1
-
-lm2:	leaw	prompt, %si			# Mode prompt
-	call	prtstr
-	leaw	edit_buf, %di			# Editor buffer
-lm3:	call	getkey
-	cmpb	$0x0d, %al			# Enter?
-	jz	lment
-
-	cmpb	$0x08, %al			# Backspace?
-	jz	lmbs
-
-	cmpb	$0x20, %al			# Printable?
-	jc	lm3
-
-	cmpw	$edit_buf+4, %di		# Enough space?
-	jz	lm3
-
-	stosb
-	call	prtchr
-	jmp	lm3
-
-lmbs:	cmpw	$edit_buf, %di			# Backspace
-	jz	lm3
-
-	decw	%di
-	movb	$0x08, %al
-	call	prtchr
-	call	prtspc
-	movb	$0x08, %al
-	call	prtchr
-	jmp	lm3
-	
-lment:	movb	$0, (%di)
-	leaw	crlft, %si
-	call	prtstr
-	leaw	edit_buf, %si
-	cmpb	$0, (%si)			# Empty string = default mode
-	jz	lmdef
-
-	cmpb	$0, 1(%si)			# One character = menu selection
-	jz	mnusel
-
-	cmpw	$0x6373, (%si)			# "scan" => mode scanning
-	jnz	lmhx
-
-	cmpw	$0x6e61, 2(%si)
-	jz	lmscan
-
-lmhx:	xorw	%bx, %bx			# Else => mode ID in hex
-lmhex:	lodsb
-	orb	%al, %al
-	jz	lmuse1
-
-	subb	$0x30, %al
-	jc	lmbad
-
-	cmpb	$10, %al
-	jc	lmhx1
-
-	subb	$7, %al
-	andb	$0xdf, %al
-	cmpb	$10, %al
-	jc	lmbad
-
-	cmpb	$16, %al
-	jnc	lmbad
-
-lmhx1:	shlw	$4, %bx
-	orb	%al, %bl
-	jmp	lmhex
-
-lmuse1:	movw	%bx, %ax
-	jmp	lmuse
-
-mnusel:	lodsb					# Menu selection
-	xorb	%ah, %ah
-	subb	$0x30, %al
-	jc	lmbad
-
-	cmpb	$10, %al
-	jc	lmuse
-	
-	cmpb	$0x61-0x30, %al
-	jc	lmbad
-	
-	subb	$0x61-0x30-10, %al
-	cmpb	$36, %al
-	jnc	lmbad
-
-lmuse:	call	mode_set
-	jc	lmdef
-
-lmbad:	leaw	unknt, %si
-	call	prtstr
-	jmp	lm2
-lmscan:	cmpb	$0, adapter			# Scanning only on EGA/VGA
-	jz	lmbad
-
-	movw	$0, mt_end			# Scanning of modes is
-	movb	$1, scanning			# done as new autodetection.
-	call	mode_table
-	jmp	listm0
-lmdef:	ret
-
-# Additional parts of mode_set... (relative jumps, you know)
-setv7:						# Video7 extended modes
-	DO_STORE
-	subb	$VIDEO_FIRST_V7>>8, %bh
-	movw	$0x6f05, %ax
-	int	$0x10
-	stc
-	ret
-
-_setrec:	jmp	setrec			# Ugly...
-_set_80x25:	jmp	set_80x25
-
-# Aliases for backward compatibility.
-setalias:
-	movw	$VIDEO_80x25, %ax
-	incw	%bx
-	jz	mode_set
-
-	movb	$VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
-	incw	%bx
-	jnz	setbad				# Fall-through!
-
-# Setting of user mode (AX=mode ID) => CF=success
-mode_set:
-	movw	%ax, %fs:(0x01fa)		# Store mode for use in acpi_wakeup.S
-	movw	%ax, %bx
-	cmpb	$0xff, %ah
-	jz	setalias
-
-	testb	$VIDEO_RECALC>>8, %ah
-	jnz	_setrec
-
-	cmpb	$VIDEO_FIRST_RESOLUTION>>8, %ah
-	jnc	setres
-	
-	cmpb	$VIDEO_FIRST_SPECIAL>>8, %ah
-	jz	setspc
-	
-	cmpb	$VIDEO_FIRST_V7>>8, %ah
-	jz	setv7
-	
-	cmpb	$VIDEO_FIRST_VESA>>8, %ah
-	jnc	check_vesa
-	
-	orb	%ah, %ah
-	jz	setmenu
-	
-	decb	%ah
-	jz	setbios
-
-setbad:	clc
-	movb	$0, do_restore			# The screen needn't be restored
-	ret
-
-setvesa:
-	DO_STORE
-	subb	$VIDEO_FIRST_VESA>>8, %bh
-	movw	$0x4f02, %ax			# VESA BIOS mode set call
-	int	$0x10
-	cmpw	$0x004f, %ax			# AL=4f if implemented
-	jnz	setbad				# AH=0 if OK
-
-	stc
-	ret
-
-setbios:
-	DO_STORE
-	int	$0x10				# Standard BIOS mode set call
-	pushw	%bx
-	movb	$0x0f, %ah			# Check if really set
-	int	$0x10
-	popw	%bx
-	cmpb	%bl, %al
-	jnz	setbad
-	
-	stc
-	ret
-
-setspc:	xorb	%bh, %bh			# Set special mode
-	cmpb	$VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
-	jnc	setbad
-	
-	addw	%bx, %bx
-	jmp	*spec_inits(%bx)
-
-setmenu:
-	orb	%al, %al			# 80x25 is an exception
-	jz	_set_80x25
-	
-	pushw	%bx				# Set mode chosen from menu
-	call	mode_table			# Build the mode table
-	popw	%ax
-	shlw	$2, %ax
-	addw	%ax, %si
-	cmpw	%di, %si
-	jnc	setbad
-	
-	movw	(%si), %ax			# Fetch mode ID
-_m_s:	jmp	mode_set
-
-setres:	pushw	%bx				# Set mode chosen by resolution
-	call	mode_table
-	popw	%bx
-	xchgb	%bl, %bh
-setr1:	lodsw
-	cmpw	$ASK_VGA, %ax			# End of the list?
-	jz	setbad
-	
-	lodsw
-	cmpw	%bx, %ax
-	jnz	setr1
-	
-	movw	-4(%si), %ax			# Fetch mode ID
-	jmp	_m_s
-
-check_vesa:
-#ifdef CONFIG_FIRMWARE_EDID
-	leaw	modelist+1024, %di
-	movw	$0x4f00, %ax
-	int	$0x10
-	cmpw	$0x004f, %ax
-	jnz	setbad
-
-	movw	4(%di), %ax
-	movw	%ax, vbe_version
-#endif
-	leaw	modelist+1024, %di
-	subb	$VIDEO_FIRST_VESA>>8, %bh
-	movw	%bx, %cx			# Get mode information structure
-	movw	$0x4f01, %ax
-	int	$0x10
-	addb	$VIDEO_FIRST_VESA>>8, %bh
-	cmpw	$0x004f, %ax
-	jnz	setbad
-
-	movb	(%di), %al			# Check capabilities.
-	andb	$0x19, %al
-	cmpb	$0x09, %al
-	jz	setvesa				# This is a text mode
-
-	movb	(%di), %al			# Check capabilities.
-	andb	$0x99, %al
-	cmpb	$0x99, %al
-	jnz	_setbad				# Doh! No linear frame buffer.
-
-	subb	$VIDEO_FIRST_VESA>>8, %bh
-	orw	$0x4000, %bx			# Use linear frame buffer
-	movw	$0x4f02, %ax			# VESA BIOS mode set call
-	int	$0x10
-	cmpw	$0x004f, %ax			# AL=4f if implemented
-	jnz	_setbad				# AH=0 if OK
-
-	movb	$1, graphic_mode		# flag graphic mode
-	movb	$0, do_restore			# no screen restore
-	stc
-	ret
-
-_setbad:	jmp	setbad          	# Ugly...
-
-# Recalculate vertical display end registers -- this fixes various
-# inconsistencies of extended modes on many adapters. Called when
-# the VIDEO_RECALC flag is set in the mode ID.
-
-setrec:	subb	$VIDEO_RECALC>>8, %ah		# Set the base mode
-	call	mode_set
-	jnc	rct3
-
-	movw	%gs:(0x485), %ax		# Font size in pixels
-	movb	%gs:(0x484), %bl		# Number of rows
-	incb	%bl
-	mulb	%bl				# Number of visible
-	decw	%ax				# scan lines - 1
-	movw	$0x3d4, %dx
-	movw	%ax, %bx
-	movb	$0x12, %al			# Lower 8 bits
-	movb	%bl, %ah
-	outw	%ax, %dx
-	movb	$0x07, %al		# Bits 8 and 9 in the overflow register
-	call	inidx
-	xchgb	%al, %ah
-	andb	$0xbd, %ah
-	shrb	%bh
-	jnc	rct1
-	orb	$0x02, %ah
-rct1:	shrb	%bh
-	jnc	rct2
-	orb	$0x40, %ah
-rct2:	movb	$0x07, %al
-	outw	%ax, %dx
-	stc
-rct3:	ret
-
-# Table of routines for setting of the special modes.
-spec_inits:
-	.word	set_80x25
-	.word	set_8pixel
-	.word	set_80x43
-	.word	set_80x28
-	.word	set_current
-	.word	set_80x30
-	.word	set_80x34
-	.word	set_80x60
-	.word	set_gfx
-
-# Set the 80x25 mode. If already set, do nothing.
-set_80x25:
-	movw	$0x5019, force_size		# Override possibly broken BIOS
-use_80x25:
-#ifdef CONFIG_VIDEO_400_HACK
-	movw	$0x1202, %ax			# Force 400 scan lines
-	movb	$0x30, %bl
-	int	$0x10
-#else
-	movb	$0x0f, %ah			# Get current mode ID
-	int	$0x10
-	cmpw	$0x5007, %ax	# Mode 7 (80x25 mono) is the only one available
-	jz	st80		# on CGA/MDA/HGA and is also available on EGAM
-
-	cmpw	$0x5003, %ax	# Unknown mode, force 80x25 color
-	jnz	force3
-
-st80:	cmpb	$0, adapter	# CGA/MDA/HGA => mode 3/7 is always 80x25
-	jz	set80
-
-	movb	%gs:(0x0484), %al	# This is EGA+ -- beware of 80x50 etc.
-	orb	%al, %al		# Some buggy BIOS'es set 0 rows
-	jz	set80
-	
-	cmpb	$24, %al		# It's hopefully correct
-	jz	set80
-#endif /* CONFIG_VIDEO_400_HACK */
-force3:	DO_STORE
-	movw	$0x0003, %ax			# Forced set
-	int	$0x10
-set80:	stc
-	ret
-
-# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
-set_8pixel:
-	DO_STORE
-	call	use_80x25			# The base is 80x25
-set_8pt:
-	movw	$0x1112, %ax			# Use 8x8 font
-	xorb	%bl, %bl
-	int	$0x10
-	movw	$0x1200, %ax			# Use alternate print screen
-	movb	$0x20, %bl
-	int	$0x10
-	movw	$0x1201, %ax			# Turn off cursor emulation
-	movb	$0x34, %bl
-	int	$0x10
-	movb	$0x01, %ah			# Define cursor scan lines 6-7
-	movw	$0x0607, %cx
-	int	$0x10
-set_current:
-	stc
-	ret
-
-# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
-# 80x25 mode with 14-point fonts instead of 16-point.
-set_80x28:
-	DO_STORE
-	call	use_80x25			# The base is 80x25
-set14:	movw	$0x1111, %ax			# Use 9x14 font
-	xorb	%bl, %bl
-	int	$0x10
-	movb	$0x01, %ah			# Define cursor scan lines 11-12
-	movw	$0x0b0c, %cx
-	int	$0x10
-	stc
-	ret
-
-# Set the 80x43 mode. This mode is works on all VGA's.
-# It's a 350-scanline mode with 8-pixel font.
-set_80x43:
-	DO_STORE
-	movw	$0x1201, %ax			# Set 350 scans
-	movb	$0x30, %bl
-	int	$0x10
-	movw	$0x0003, %ax			# Reset video mode
-	int	$0x10
-	jmp	set_8pt				# Use 8-pixel font
-
-# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
-set_80x30:
-	call	use_80x25			# Start with real 80x25
-	DO_STORE
-	movw	$0x3cc, %dx			# Get CRTC port
-	inb	%dx, %al
-	movb	$0xd4, %dl
-	rorb	%al				# Mono or color?
-	jc	set48a
-
-	movb	$0xb4, %dl
-set48a:	movw	$0x0c11, %ax		# Vertical sync end (also unlocks CR0-7)
- 	call	outidx
-	movw	$0x0b06, %ax			# Vertical total
- 	call	outidx
-	movw	$0x3e07, %ax			# (Vertical) overflow
- 	call	outidx
-	movw	$0xea10, %ax			# Vertical sync start
- 	call	outidx
-	movw	$0xdf12, %ax			# Vertical display end
-	call	outidx
-	movw	$0xe715, %ax			# Vertical blank start
- 	call	outidx
-	movw	$0x0416, %ax			# Vertical blank end
- 	call	outidx
-	pushw	%dx
-	movb	$0xcc, %dl			# Misc output register (read)
- 	inb	%dx, %al
- 	movb	$0xc2, %dl			# (write)
- 	andb	$0x0d, %al	# Preserve clock select bits and color bit
- 	orb	$0xe2, %al			# Set correct sync polarity
- 	outb	%al, %dx
-	popw	%dx
-	movw	$0x501e, force_size
-	stc					# That's all.
-	ret
-
-# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
-set_80x34:
-	call	set_80x30			# Set 480 scans
-	call	set14				# And 14-pt font
-	movw	$0xdb12, %ax			# VGA vertical display end
-	movw	$0x5022, force_size
-setvde:	call	outidx
-	stc
-	ret
-
-# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
-set_80x60:
-	call	set_80x30			# Set 480 scans
-	call	set_8pt				# And 8-pt font
-	movw	$0xdf12, %ax			# VGA vertical display end
-	movw	$0x503c, force_size
-	jmp	setvde
-
-# Special hack for ThinkPad graphics
-set_gfx:
-#ifdef CONFIG_VIDEO_GFX_HACK
-	movw	$VIDEO_GFX_BIOS_AX, %ax
-	movw	$VIDEO_GFX_BIOS_BX, %bx
-	int	$0x10
-	movw	$VIDEO_GFX_DUMMY_RESOLUTION, force_size
-	stc
-#endif
-	ret
-
-#ifdef CONFIG_VIDEO_RETAIN
-
-# Store screen contents to temporary buffer.
-store_screen:
-	cmpb	$0, do_restore			# Already stored?
-	jnz	stsr
-
-	testb	$CAN_USE_HEAP, loadflags	# Have we space for storing?
-	jz	stsr
-	
-	pushw	%ax
-	pushw	%bx
-	pushw	force_size			# Don't force specific size
-	movw	$0, force_size
-	call	mode_params			# Obtain params of current mode
-	popw	force_size
-	movb	%fs:(PARAM_VIDEO_LINES), %ah
-	movb	%fs:(PARAM_VIDEO_COLS), %al
-	movw	%ax, %bx			# BX=dimensions
-	mulb	%ah
-	movw	%ax, %cx			# CX=number of characters
-	addw	%ax, %ax			# Calculate image size
-	addw	$modelist+1024+4, %ax
-	cmpw	heap_end_ptr, %ax
-	jnc	sts1				# Unfortunately, out of memory
-
-	movw	%fs:(PARAM_CURSOR_POS), %ax	# Store mode params
-	leaw	modelist+1024, %di
-	stosw
-	movw	%bx, %ax
-	stosw
-	pushw	%ds				# Store the screen
-	movw	video_segment, %ds
-	xorw	%si, %si
-	rep
-	movsw
-	popw	%ds
-	incb	do_restore			# Screen will be restored later
-sts1:	popw	%bx
-	popw	%ax
-stsr:	ret
-
-# Restore screen contents from temporary buffer.
-restore_screen:
-	cmpb	$0, do_restore			# Has the screen been stored?
-	jz	res1
-
-	call	mode_params			# Get parameters of current mode
-	movb	%fs:(PARAM_VIDEO_LINES), %cl
-	movb	%fs:(PARAM_VIDEO_COLS), %ch
-	leaw	modelist+1024, %si		# Screen buffer
-	lodsw					# Set cursor position
-	movw	%ax, %dx
-	cmpb	%cl, %dh
-	jc	res2
-	
-	movb	%cl, %dh
-	decb	%dh
-res2:	cmpb	%ch, %dl
-	jc	res3
-	
-	movb	%ch, %dl
-	decb	%dl
-res3:	movb	$0x02, %ah
-	movb	$0x00, %bh
-	int	$0x10
-	lodsw					# Display size
-	movb	%ah, %dl			# DL=number of lines
-	movb	$0, %ah				# BX=phys. length of orig. line
-	movw	%ax, %bx
-	cmpb	%cl, %dl			# Too many?
-	jc	res4
-
-	pushw	%ax
-	movb	%dl, %al
-	subb	%cl, %al
-	mulb	%bl
-	addw	%ax, %si
-	addw	%ax, %si
-	popw	%ax
-	movb	%cl, %dl
-res4:	cmpb	%ch, %al			# Too wide?
-	jc	res5
-	
-	movb	%ch, %al			# AX=width of src. line
-res5:	movb	$0, %cl
-	xchgb	%ch, %cl
-	movw	%cx, %bp			# BP=width of dest. line
-	pushw	%es
-	movw	video_segment, %es
-	xorw	%di, %di			# Move the data
-	addw	%bx, %bx			# Convert BX and BP to _bytes_
-	addw	%bp, %bp
-res6:	pushw	%si
-	pushw	%di
-	movw	%ax, %cx
-	rep
-	movsw
-	popw	%di
-	popw	%si
-	addw	%bp, %di
-	addw	%bx, %si
-	decb	%dl
-	jnz	res6
-	
-	popw	%es				# Done
-res1:	ret
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
-outidx:	outb	%al, %dx
-	pushw	%ax
-	movb	%ah, %al
-	incw	%dx
-	outb	%al, %dx
-	decw	%dx
-	popw	%ax
-	ret
-
-# Build the table of video modes (stored after the setup.S code at the
-# `modelist' label. Each video mode record looks like:
-#	.word	MODE-ID		(our special mode ID (see above))
-#	.byte	rows		(number of rows)
-#	.byte	columns		(number of columns)
-# Returns address of the end of the table in DI, the end is marked
-# with a ASK_VGA ID.
-mode_table:
-	movw	mt_end, %di			# Already filled?
-	orw	%di, %di
-	jnz	mtab1x
-	
-	leaw	modelist, %di			# Store standard modes:
-	movl	$VIDEO_80x25 + 0x50190000, %eax	# The 80x25 mode (ALL)
-	stosl
-	movb	adapter, %al			# CGA/MDA/HGA -- no more modes
-	orb	%al, %al
-	jz	mtabe
-	
-	decb	%al
-	jnz	mtabv
-	
-	movl	$VIDEO_8POINT + 0x502b0000, %eax	# The 80x43 EGA mode
-	stosl
-	jmp	mtabe
-
-mtab1x:	jmp	mtab1
-
-mtabv:	leaw	vga_modes, %si			# All modes for std VGA
-	movw	$vga_modes_end-vga_modes, %cx
-	rep	# I'm unable to use movsw as I don't know how to store a half
-	movsb	# of the expression above to cx without using explicit shr.
-
-	cmpb	$0, scanning			# Mode scan requested?
-	jz	mscan1
-	
-	call	mode_scan
-mscan1:
-
-#ifdef CONFIG_VIDEO_LOCAL
-	call	local_modes
-#endif /* CONFIG_VIDEO_LOCAL */
-
-#ifdef CONFIG_VIDEO_VESA
-	call	vesa_modes			# Detect VESA VGA modes
-#endif /* CONFIG_VIDEO_VESA */
-
-#ifdef CONFIG_VIDEO_SVGA
-	cmpb	$0, scanning			# Bypass when scanning
-	jnz	mscan2
-	
-	call	svga_modes			# Detect SVGA cards & modes
-mscan2:
-#endif /* CONFIG_VIDEO_SVGA */
-
-mtabe:
-
-#ifdef CONFIG_VIDEO_COMPACT
-	leaw	modelist, %si
-	movw	%di, %dx
-	movw	%si, %di
-cmt1:	cmpw	%dx, %si			# Scan all modes
-	jz	cmt2
-
-	leaw	modelist, %bx			# Find in previous entries
-	movw	2(%si), %cx
-cmt3:	cmpw	%bx, %si
-	jz	cmt4
-
-	cmpw	2(%bx), %cx			# Found => don't copy this entry
-	jz	cmt5
-
-	addw	$4, %bx
-	jmp	cmt3
-
-cmt4:	movsl					# Copy entry
-	jmp	cmt1
-
-cmt5:	addw	$4, %si				# Skip entry
-	jmp	cmt1
-
-cmt2:
-#endif	/* CONFIG_VIDEO_COMPACT */
-
-	movw	$ASK_VGA, (%di)			# End marker
-	movw	%di, mt_end
-mtab1:	leaw	modelist, %si			# SI=mode list, DI=list end
-ret0:	ret
-
-# Modes usable on all standard VGAs
-vga_modes:
-	.word	VIDEO_8POINT
-	.word	0x5032				# 80x50
-	.word	VIDEO_80x43
-	.word	0x502b				# 80x43
-	.word	VIDEO_80x28
-	.word	0x501c				# 80x28
-	.word	VIDEO_80x30
-	.word	0x501e				# 80x30
-	.word	VIDEO_80x34
-	.word	0x5022				# 80x34
-	.word	VIDEO_80x60
-	.word	0x503c				# 80x60
-#ifdef CONFIG_VIDEO_GFX_HACK
-	.word	VIDEO_GFX_HACK
-	.word	VIDEO_GFX_DUMMY_RESOLUTION
-#endif
-
-vga_modes_end:
-# Detect VESA modes.
-
-#ifdef CONFIG_VIDEO_VESA
-vesa_modes:
-	cmpb	$2, adapter			# VGA only
-	jnz	ret0
-
-	movw	%di, %bp			# BP=original mode table end
-	addw	$0x200, %di			# Buffer space
-	movw	$0x4f00, %ax			# VESA Get card info call
-	int	$0x10
-	movw	%bp, %di
-	cmpw	$0x004f, %ax			# Successful?
-	jnz	ret0
-	
-	cmpw	$0x4556, 0x200(%di)
-	jnz	ret0
-	
-	cmpw	$0x4153, 0x202(%di)
-	jnz	ret0
-	
-	movw	$vesa_name, card_name		# Set name to "VESA VGA"
-	pushw	%gs
-	lgsw	0x20e(%di), %si			# GS:SI=mode list
-	movw	$128, %cx			# Iteration limit
-vesa1:
-# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
-# XXX:	lodsw	%gs:(%si), %ax			# Get next mode in the list
-	gs; lodsw
-	cmpw	$0xffff, %ax			# End of the table?
-	jz	vesar
-	
-	cmpw	$0x0080, %ax			# Check validity of mode ID
-	jc	vesa2
-	
-	orb	%ah, %ah		# Valid IDs: 0x0000-0x007f/0x0100-0x07ff
-	jz	vesan			# Certain BIOSes report 0x80-0xff!
-
-	cmpw	$0x0800, %ax
-	jnc	vesae
-
-vesa2:	pushw	%cx
-	movw	%ax, %cx			# Get mode information structure
-	movw	$0x4f01, %ax
-	int	$0x10
-	movw	%cx, %bx			# BX=mode number
-	addb	$VIDEO_FIRST_VESA>>8, %bh
-	popw	%cx
-	cmpw	$0x004f, %ax
-	jnz	vesan			# Don't report errors (buggy BIOSES)
-
-	movb	(%di), %al			# Check capabilities. We require
-	andb	$0x19, %al			# a color text mode.
-	cmpb	$0x09, %al
-	jnz	vesan
-	
-	cmpw	$0xb800, 8(%di)		# Standard video memory address required
-	jnz	vesan
-
-	testb	$2, (%di)			# Mode characteristics supplied?
-	movw	%bx, (%di)			# Store mode number
-	jz	vesa3
-	
-	xorw	%dx, %dx
-	movw	0x12(%di), %bx			# Width
-	orb	%bh, %bh
-	jnz	vesan
-	
-	movb	%bl, 0x3(%di)
-	movw	0x14(%di), %ax			# Height
-	orb	%ah, %ah
-	jnz	vesan
-	
-	movb	%al, 2(%di)
-	mulb	%bl
-	cmpw	$8193, %ax		# Small enough for Linux console driver?
-	jnc	vesan
-
-	jmp	vesaok
-
-vesa3:	subw	$0x8108, %bx	# This mode has no detailed info specified,
-	jc	vesan		# so it must be a standard VESA mode.
-
-	cmpw	$5, %bx
-	jnc	vesan
-
-	movw	vesa_text_mode_table(%bx), %ax
-	movw	%ax, 2(%di)
-vesaok:	addw	$4, %di				# The mode is valid. Store it.
-vesan:	loop	vesa1			# Next mode. Limit exceeded => error
-vesae:	leaw	vesaer, %si
-	call	prtstr
-	movw	%bp, %di			# Discard already found modes.
-vesar:	popw	%gs
-	ret
-
-# Dimensions of standard VESA text modes
-vesa_text_mode_table:
-	.byte	60, 80				# 0108
-	.byte	25, 132				# 0109
-	.byte	43, 132				# 010A
-	.byte	50, 132				# 010B
-	.byte	60, 132				# 010C
-#endif	/* CONFIG_VIDEO_VESA */
-
-# Scan for video modes. A bit dirty, but should work.
-mode_scan:
-	movw	$0x0100, %cx			# Start with mode 0
-scm1:	movb	$0, %ah				# Test the mode
-	movb	%cl, %al
-	int	$0x10
-	movb	$0x0f, %ah
-	int	$0x10
-	cmpb	%cl, %al
-	jnz	scm2				# Mode not set
-
-	movw	$0x3c0, %dx			# Test if it's a text mode
-	movb	$0x10, %al			# Mode bits
-	call	inidx
-	andb	$0x03, %al
-	jnz	scm2
-	
-	movb	$0xce, %dl			# Another set of mode bits
-	movb	$0x06, %al
-	call	inidx
-	shrb	%al
-	jc	scm2
-	
-	movb	$0xd4, %dl			# Cursor location
-	movb	$0x0f, %al
-	call	inidx
-	orb	%al, %al
-	jnz	scm2
-	
-	movw	%cx, %ax			# Ok, store the mode
-	stosw
-	movb	%gs:(0x484), %al		# Number of rows
-	incb	%al
-	stosb
-	movw	%gs:(0x44a), %ax		# Number of columns
-	stosb
-scm2:	incb	%cl
-	jns	scm1
-	
-	movw	$0x0003, %ax			# Return back to mode 3
-	int	$0x10
-	ret
-
-tstidx:	outw	%ax, %dx			# OUT DX,AX and inidx
-inidx:	outb	%al, %dx			# Read from indexed VGA register
-	incw	%dx			# AL=index, DX=index reg port -> AL=data
-	inb	%dx, %al
-	decw	%dx
-	ret
-
-# Try to detect type of SVGA card and supply (usually approximate) video
-# mode table for it.
-
-#ifdef CONFIG_VIDEO_SVGA
-svga_modes:
-	leaw	svga_table, %si			# Test all known SVGA adapters
-dosvga:	lodsw
-	movw	%ax, %bp			# Default mode table
-	orw	%ax, %ax
-	jz	didsv1
-
-	lodsw					# Pointer to test routine
-	pushw	%si
-	pushw	%di
-	pushw	%es
-	movw	$0xc000, %bx
-	movw	%bx, %es
-	call	*%ax				# Call test routine
-	popw	%es
-	popw	%di
-	popw	%si
-	orw	%bp, %bp
-	jz	dosvga
-	
-	movw	%bp, %si			# Found, copy the modes
-	movb	svga_prefix, %ah
-cpsvga:	lodsb
-	orb	%al, %al
-	jz	didsv
-	
-	stosw
-	movsw
-	jmp	cpsvga
-
-didsv:	movw	%si, card_name			# Store pointer to card name
-didsv1:	ret
-
-# Table of all known SVGA cards. For each card, we store a pointer to
-# a table of video modes supported by the card and a pointer to a routine
-# used for testing of presence of the card. The video mode table is always
-# followed by the name of the card or the chipset.
-svga_table:
-	.word	ati_md, ati_test
-	.word	oak_md, oak_test
-	.word	paradise_md, paradise_test
-	.word	realtek_md, realtek_test
-	.word	s3_md, s3_test
-	.word	chips_md, chips_test
-	.word	video7_md, video7_test
-	.word	cirrus5_md, cirrus5_test
-	.word	cirrus6_md, cirrus6_test
-	.word	cirrus1_md, cirrus1_test
-	.word	ahead_md, ahead_test
-	.word	everex_md, everex_test
-	.word	genoa_md, genoa_test
-	.word	trident_md, trident_test
-	.word	tseng_md, tseng_test
-	.word	0
-
-# Test routines and mode tables:
-
-# S3 - The test algorithm was taken from the SuperProbe package
-# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
-s3_test:
-	movw	$0x0f35, %cx	# we store some constants in cl/ch
-	movw	$0x03d4, %dx
-	movb	$0x38, %al
-	call	inidx
-	movb	%al, %bh	# store current CRT-register 0x38
-	movw	$0x0038, %ax
-	call	outidx		# disable writing to special regs
-	movb	%cl, %al	# check whether we can write special reg 0x35
-	call	inidx
-	movb	%al, %bl	# save the current value of CRT reg 0x35
-	andb	$0xf0, %al	# clear bits 0-3
-	movb	%al, %ah
-	movb	%cl, %al	# and write it to CRT reg 0x35
-	call	outidx
-	call	inidx		# now read it back
-	andb	%ch, %al	# clear the upper 4 bits
-	jz	s3_2		# the first test failed. But we have a
-
-	movb	%bl, %ah	# second chance
-	movb	%cl, %al
-	call	outidx
-	jmp	s3_1		# do the other tests
-
-s3_2:	movw	%cx, %ax	# load ah with 0xf and al with 0x35
-	orb	%bl, %ah	# set the upper 4 bits of ah with the orig value
-	call	outidx		# write ...
-	call	inidx		# ... and reread 
-	andb	%cl, %al	# turn off the upper 4 bits
-	pushw	%ax
-	movb	%bl, %ah	# restore old value in register 0x35
-	movb	%cl, %al
-	call	outidx
-	popw	%ax
-	cmpb	%ch, %al	# setting lower 4 bits was successful => bad
-	je	no_s3		# writing is allowed => this is not an S3
-
-s3_1:	movw	$0x4838, %ax	# allow writing to special regs by putting
-	call	outidx		# magic number into CRT-register 0x38
-	movb	%cl, %al	# check whether we can write special reg 0x35
-	call	inidx
-	movb	%al, %bl
-	andb	$0xf0, %al
-	movb	%al, %ah
-	movb	%cl, %al
-	call	outidx
-	call	inidx
-	andb	%ch, %al
-	jnz	no_s3		# no, we can't write => no S3
-
-	movw	%cx, %ax
-	orb	%bl, %ah
-	call	outidx
-	call	inidx
-	andb	%ch, %al
-	pushw	%ax
-	movb	%bl, %ah	# restore old value in register 0x35
-	movb	%cl, %al
-	call	outidx
-	popw	%ax
-	cmpb	%ch, %al
-	jne	no_s31		# writing not possible => no S3
-	movb	$0x30, %al
-	call	inidx		# now get the S3 id ...
-	leaw	idS3, %di
-	movw	$0x10, %cx
-	repne
-	scasb
-	je	no_s31
-
-	movb	%bh, %ah
-	movb	$0x38, %al
-	jmp	s3rest
-
-no_s3:	movb	$0x35, %al	# restore CRT register 0x35
-	movb	%bl, %ah
-	call	outidx
-no_s31:	xorw	%bp, %bp	# Detection failed
-s3rest:	movb	%bh, %ah
-	movb	$0x38, %al	# restore old value of CRT register 0x38
-	jmp	outidx
-
-idS3:	.byte	0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
-	.byte	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
-
-s3_md:	.byte	0x54, 0x2b, 0x84
-	.byte	0x55, 0x19, 0x84
-	.byte	0
-	.ascii	"S3"
-	.byte	0
-
-# ATI cards.
-ati_test:
-	leaw 	idati, %si
-	movw	$0x31, %di
-	movw	$0x09, %cx
-	repe
-	cmpsb
-	je	atiok
-
-	xorw	%bp, %bp
-atiok:	ret
-
-idati:	.ascii	"761295520"
-
-ati_md:	.byte	0x23, 0x19, 0x84
-	.byte	0x33, 0x2c, 0x84
-	.byte	0x22, 0x1e, 0x64
-	.byte	0x21, 0x19, 0x64
-	.byte	0x58, 0x21, 0x50
-	.byte	0x5b, 0x1e, 0x50
-	.byte	0
-	.ascii	"ATI"
-	.byte	0
-
-# AHEAD
-ahead_test:
-	movw	$0x200f, %ax
-	movw	$0x3ce, %dx
-	outw	%ax, %dx
-	incw	%dx
-	inb	%dx, %al
-	cmpb	$0x20, %al
-	je	isahed
-
-	cmpb	$0x21, %al
-	je	isahed
-	
-	xorw	%bp, %bp
-isahed:	ret
-
-ahead_md:
-	.byte	0x22, 0x2c, 0x84
-	.byte	0x23, 0x19, 0x84
-	.byte	0x24, 0x1c, 0x84
-	.byte	0x2f, 0x32, 0xa0
-	.byte	0x32, 0x22, 0x50
-	.byte	0x34, 0x42, 0x50
-	.byte	0
-	.ascii	"Ahead"
-	.byte	0
-
-# Chips & Tech.
-chips_test:
-	movw	$0x3c3, %dx
-	inb	%dx, %al
-	orb	$0x10, %al
-	outb	%al, %dx
-	movw	$0x104, %dx
-	inb	%dx, %al
-	movb	%al, %bl
-	movw	$0x3c3, %dx
-	inb	%dx, %al
-	andb	$0xef, %al
-	outb	%al, %dx
-	cmpb	$0xa5, %bl
-	je	cantok
-	
-	xorw	%bp, %bp
-cantok:	ret
-
-chips_md:
-	.byte	0x60, 0x19, 0x84
-	.byte	0x61, 0x32, 0x84
-	.byte	0
-	.ascii	"Chips & Technologies"
-	.byte	0
-
-# Cirrus Logic 5X0
-cirrus1_test:
-	movw	$0x3d4, %dx
-	movb	$0x0c, %al
-	outb	%al, %dx
-	incw	%dx
-	inb	%dx, %al
-	movb	%al, %bl
-	xorb	%al, %al
-	outb	%al, %dx
-	decw	%dx
-	movb	$0x1f, %al
-	outb	%al, %dx
-	incw	%dx
-	inb	%dx, %al
-	movb	%al, %bh
-	xorb	%ah, %ah
-	shlb	$4, %al
-	movw	%ax, %cx
-	movb	%bh, %al
-	shrb	$4, %al
-	addw	%ax, %cx
-	shlw	$8, %cx
-	addw	$6, %cx
-	movw	%cx, %ax
-	movw	$0x3c4, %dx
-	outw	%ax, %dx
-	incw	%dx
-	inb	%dx, %al
-	andb	%al, %al
-	jnz	nocirr
-	
-	movb	%bh, %al
-	outb	%al, %dx
-	inb	%dx, %al
-	cmpb	$0x01, %al
-	je	iscirr
-
-nocirr:	xorw	%bp, %bp
-iscirr: movw	$0x3d4, %dx
-	movb	%bl, %al
-	xorb	%ah, %ah
-	shlw	$8, %ax
-	addw	$0x0c, %ax
-	outw	%ax, %dx
-	ret
-
-cirrus1_md:
-	.byte	0x1f, 0x19, 0x84
-	.byte	0x20, 0x2c, 0x84
-	.byte	0x22, 0x1e, 0x84
-	.byte	0x31, 0x25, 0x64
-	.byte	0
-	.ascii	"Cirrus Logic 5X0"
-	.byte	0
-
-# Cirrus Logic 54XX
-cirrus5_test:
-	movw	$0x3c4, %dx
-	movb	$6, %al
-	call	inidx
-	movb	%al, %bl			# BL=backup
-	movw	$6, %ax
-	call	tstidx
-	cmpb	$0x0f, %al
-	jne	c5fail
-	
-	movw	$0x1206, %ax
-	call	tstidx
-	cmpb	$0x12, %al
-	jne	c5fail
-	
-	movb	$0x1e, %al
-	call	inidx
-	movb	%al, %bh
-	movb	%bh, %ah
-	andb	$0xc0, %ah
-	movb	$0x1e, %al
-	call	tstidx
-	andb	$0x3f, %al
-	jne	c5xx
-	
-	movb	$0x1e, %al
-	movb	%bh, %ah
-	orb	$0x3f, %ah
-	call	tstidx
-	xorb	$0x3f, %al
-	andb	$0x3f, %al
-c5xx:	pushf
-	movb	$0x1e, %al
-	movb	%bh, %ah
-	outw	%ax, %dx
-	popf
-	je	c5done
-
-c5fail:	xorw	%bp, %bp
-c5done:	movb	$6, %al
-	movb	%bl, %ah
-	outw	%ax, %dx
-	ret
-
-cirrus5_md:
-	.byte	0x14, 0x19, 0x84
-	.byte	0x54, 0x2b, 0x84
-	.byte	0
-	.ascii	"Cirrus Logic 54XX"
-	.byte	0
-
-# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
-# it's misidentified by the Ahead test.
-cirrus6_test:
-	movw	$0x3ce, %dx
-	movb	$0x0a, %al
-	call	inidx
-	movb	%al, %bl	# BL=backup
-	movw	$0xce0a, %ax
-	call	tstidx
-	orb	%al, %al
-	jne	c2fail
-	
-	movw	$0xec0a, %ax
-	call	tstidx
-	cmpb	$0x01, %al
-	jne	c2fail
-	
-	movb	$0xaa, %al
-	call	inidx		# 4X, 5X, 7X and 8X are valid 64XX chip ID's. 
-	shrb	$4, %al
-	subb	$4, %al
-	jz	c6done
-	
-	decb	%al
-	jz	c6done
-	
-	subb	$2, %al
-	jz	c6done
-	
-	decb	%al
-	jz	c6done
-	
-c2fail:	xorw	%bp, %bp
-c6done:	movb	$0x0a, %al
-	movb	%bl, %ah
-	outw	%ax, %dx
-	ret
-
-cirrus6_md:
-	.byte	0
-	.ascii	"Cirrus Logic 64XX"
-	.byte	0
-
-# Everex / Trident
-everex_test:
-	movw	$0x7000, %ax
-	xorw	%bx, %bx
-	int	$0x10
-	cmpb	$0x70, %al
-	jne	noevrx
-	
-	shrw	$4, %dx
-	cmpw	$0x678, %dx
-	je	evtrid
-	
-	cmpw	$0x236, %dx
-	jne	evrxok
-
-evtrid:	leaw	trident_md, %bp
-evrxok:	ret
-
-noevrx:	xorw	%bp, %bp
-	ret
-
-everex_md:
-	.byte	0x03, 0x22, 0x50
-	.byte	0x04, 0x3c, 0x50
-	.byte	0x07, 0x2b, 0x64
-	.byte	0x08, 0x4b, 0x64
-	.byte	0x0a, 0x19, 0x84
-	.byte	0x0b, 0x2c, 0x84
-	.byte	0x16, 0x1e, 0x50
-	.byte	0x18, 0x1b, 0x64
-	.byte	0x21, 0x40, 0xa0
-	.byte	0x40, 0x1e, 0x84
-	.byte	0
-	.ascii	"Everex/Trident"
-	.byte	0
-
-# Genoa.
-genoa_test:
-	leaw	idgenoa, %si			# Check Genoa 'clues'
-	xorw	%ax, %ax
-	movb	%es:(0x37), %al
-	movw	%ax, %di
-	movw	$0x04, %cx
-	decw	%si
-	decw	%di
-l1:	incw	%si
-	incw	%di
-	movb	(%si), %al
-	testb	%al, %al
-	jz	l2
-
-	cmpb	%es:(%di), %al
-l2:	loope 	l1
-	orw	%cx, %cx
-	je	isgen
-	
-	xorw	%bp, %bp
-isgen:	ret
-
-idgenoa: .byte	0x77, 0x00, 0x99, 0x66
-
-genoa_md:
-	.byte	0x58, 0x20, 0x50
-	.byte	0x5a, 0x2a, 0x64
-	.byte	0x60, 0x19, 0x84
-	.byte	0x61, 0x1d, 0x84
-	.byte	0x62, 0x20, 0x84
-	.byte	0x63, 0x2c, 0x84
-	.byte	0x64, 0x3c, 0x84
-	.byte	0x6b, 0x4f, 0x64
-	.byte	0x72, 0x3c, 0x50
-	.byte	0x74, 0x42, 0x50
-	.byte	0x78, 0x4b, 0x64
-	.byte	0
-	.ascii	"Genoa"
-	.byte	0
-
-# OAK
-oak_test:
-	leaw	idoakvga, %si
-	movw	$0x08, %di
-	movw	$0x08, %cx
-	repe
-	cmpsb
-	je	isoak
-	
-	xorw	%bp, %bp
-isoak:	ret
-
-idoakvga: .ascii  "OAK VGA "
-
-oak_md: .byte	0x4e, 0x3c, 0x50
-	.byte	0x4f, 0x3c, 0x84
-	.byte	0x50, 0x19, 0x84
-	.byte	0x51, 0x2b, 0x84
-	.byte	0
-	.ascii	"OAK"
-	.byte	0
-
-# WD Paradise.
-paradise_test:
-	leaw	idparadise, %si
-	movw	$0x7d, %di
-	movw	$0x04, %cx
-	repe
-	cmpsb
-	je	ispara
-	
-	xorw	%bp, %bp
-ispara:	ret
-
-idparadise:	.ascii	"VGA="
-
-paradise_md:
-	.byte	0x41, 0x22, 0x50
-	.byte	0x47, 0x1c, 0x84
-	.byte	0x55, 0x19, 0x84
-	.byte	0x54, 0x2c, 0x84
-	.byte	0
-	.ascii	"Paradise"
-	.byte	0
-
-# Trident.
-trident_test:
-	movw	$0x3c4, %dx
-	movb	$0x0e, %al
-	outb	%al, %dx
-	incw	%dx
-	inb	%dx, %al
-	xchgb	%al, %ah
-	xorb	%al, %al
-	outb	%al, %dx
-	inb	%dx, %al
-	xchgb	%ah, %al
-	movb	%al, %bl	# Strange thing ... in the book this wasn't
-	andb	$0x02, %bl	# necessary but it worked on my card which
-	jz	setb2		# is a trident. Without it the screen goes
-				# blurred ...
-	andb	$0xfd, %al
-	jmp	clrb2		
-
-setb2:	orb	$0x02, %al	
-clrb2:	outb	%al, %dx
-	andb	$0x0f, %ah
-	cmpb	$0x02, %ah
-	je	istrid
-
-	xorw	%bp, %bp
-istrid:	ret
-
-trident_md:
-	.byte	0x50, 0x1e, 0x50
-	.byte	0x51, 0x2b, 0x50
-	.byte	0x52, 0x3c, 0x50
-	.byte	0x57, 0x19, 0x84
-	.byte	0x58, 0x1e, 0x84
-	.byte	0x59, 0x2b, 0x84
-	.byte	0x5a, 0x3c, 0x84
-	.byte	0
-	.ascii	"Trident"
-	.byte	0
-
-# Tseng.
-tseng_test:
-	movw	$0x3cd, %dx
-	inb	%dx, %al	# Could things be this simple ! :-)
-	movb	%al, %bl
-	movb	$0x55, %al
-	outb	%al, %dx
-	inb	%dx, %al
-	movb	%al, %ah
-	movb	%bl, %al
-	outb	%al, %dx
-	cmpb	$0x55, %ah
- 	je	istsen
-
-isnot:	xorw	%bp, %bp
-istsen:	ret
-
-tseng_md:
-	.byte	0x26, 0x3c, 0x50
-	.byte	0x2a, 0x28, 0x64
-	.byte	0x23, 0x19, 0x84
-	.byte	0x24, 0x1c, 0x84
-	.byte	0x22, 0x2c, 0x84
-	.byte	0x21, 0x3c, 0x84
-	.byte	0
-	.ascii	"Tseng"
-	.byte	0
-
-# Video7.
-video7_test:
-	movw	$0x3cc, %dx
-	inb	%dx, %al
-	movw	$0x3b4, %dx
-	andb	$0x01, %al
-	jz	even7
-
-	movw	$0x3d4, %dx
-even7:	movb	$0x0c, %al
-	outb	%al, %dx
-	incw	%dx
-	inb	%dx, %al
-	movb	%al, %bl
-	movb	$0x55, %al
-	outb	%al, %dx
-	inb	%dx, %al
-	decw	%dx
-	movb	$0x1f, %al
-	outb	%al, %dx
-	incw	%dx
-	inb	%dx, %al
-	movb	%al, %bh
-	decw	%dx
-	movb	$0x0c, %al
-	outb	%al, %dx
-	incw	%dx
-	movb	%bl, %al
-	outb	%al, %dx
-	movb	$0x55, %al
-	xorb	$0xea, %al
-	cmpb	%bh, %al
-	jne	isnot
-	
-	movb	$VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
-	ret
-
-video7_md:
-	.byte	0x40, 0x2b, 0x50
-	.byte	0x43, 0x3c, 0x50
-	.byte	0x44, 0x3c, 0x64
-	.byte	0x41, 0x19, 0x84
-	.byte	0x42, 0x2c, 0x84
-	.byte	0x45, 0x1c, 0x84
-	.byte	0
-	.ascii	"Video 7"
-	.byte	0
-
-# Realtek VGA
-realtek_test:
-	leaw	idrtvga, %si
-	movw	$0x45, %di
-	movw	$0x0b, %cx
-	repe
-	cmpsb
-	je	isrt
-	
-	xorw	%bp, %bp
-isrt:	ret
-
-idrtvga:	.ascii	"REALTEK VGA"
-
-realtek_md:
-	.byte	0x1a, 0x3c, 0x50
-	.byte	0x1b, 0x19, 0x84
-	.byte	0x1c, 0x1e, 0x84
-	.byte	0x1d, 0x2b, 0x84
-	.byte	0x1e, 0x3c, 0x84
-	.byte	0
-	.ascii	"REALTEK"
-	.byte	0
-
-#endif	/* CONFIG_VIDEO_SVGA */
-
-# User-defined local mode table (VGA only)
-#ifdef CONFIG_VIDEO_LOCAL
-local_modes:
-	leaw	local_mode_table, %si
-locm1:	lodsw
-	orw	%ax, %ax
-	jz	locm2
-	
-	stosw
-	movsw
-	jmp	locm1
-
-locm2:	ret
-
-# This is the table of local video modes which can be supplied manually
-# by the user. Each entry consists of mode ID (word) and dimensions
-# (byte for column count and another byte for row count). These modes
-# are placed before all SVGA and VESA modes and override them if table
-# compacting is enabled. The table must end with a zero word followed
-# by NUL-terminated video adapter name.
-local_mode_table:
-	.word	0x0100				# Example: 40x25
-	.byte	25,40
-	.word	0
-	.ascii	"Local"
-	.byte	0
-#endif	/* CONFIG_VIDEO_LOCAL */
-
-# Read a key and return the ASCII code in al, scan code in ah
-getkey:	xorb	%ah, %ah
-	int	$0x16
-	ret
-
-# Read a key with a timeout of 30 seconds.
-# The hardware clock is used to get the time.
-getkt:	call	gettime
-	addb	$30, %al			# Wait 30 seconds
-	cmpb	$60, %al
-	jl	lminute
-
-	subb	$60, %al
-lminute:
-	movb	%al, %cl
-again:	movb	$0x01, %ah
-	int	$0x16
-	jnz	getkey				# key pressed, so get it
-
-	call	gettime
-	cmpb	%cl, %al
-	jne	again
-
-	movb	$0x20, %al			# timeout, return `space'
-	ret
-
-# Flush the keyboard buffer
-flush:	movb	$0x01, %ah
-	int	$0x16
-	jz	empty
-	
-	xorb	%ah, %ah
-	int	$0x16
-	jmp	flush
-
-empty:	ret
-
-# Print hexadecimal number.
-prthw:	pushw	%ax
-	movb	%ah, %al
-	call	prthb
-	popw	%ax
-prthb:	pushw	%ax
-	shrb	$4, %al
-	call	prthn
-	popw	%ax
-	andb	$0x0f, %al
-prthn:	cmpb	$0x0a, %al
-	jc	prth1
-
-	addb	$0x07, %al
-prth1:	addb	$0x30, %al
-	jmp	prtchr
-
-# Print decimal number in al
-prtdec:	pushw	%ax
-	pushw	%cx
-	xorb	%ah, %ah
-	movb	$0x0a, %cl
-	idivb	%cl
-	cmpb	$0x09, %al
-	jbe	lt100
-
-	call	prtdec
-	jmp	skip10
-
-lt100:	addb	$0x30, %al
-	call	prtchr
-skip10:	movb	%ah, %al
-	addb	$0x30, %al
-	call	prtchr	
-	popw	%cx
-	popw	%ax
-	ret
-
-store_edid:
-#ifdef CONFIG_FIRMWARE_EDID
-	pushw	%es				# just save all registers
-	pushw	%ax
-	pushw	%bx
-	pushw   %cx
-	pushw	%dx
-	pushw   %di
-
-	pushw	%fs
-	popw    %es
-
-	movl	$0x13131313, %eax		# memset block with 0x13
-	movw    $32, %cx
-	movw	$0x140, %di
-	cld
-	rep
-	stosl
-
-	cmpw	$0x0200, vbe_version		# only do EDID on >= VBE2.0
-	jl	no_edid
-
-	pushw   %es				# save ES
-	xorw    %di, %di                        # Report Capability
-	pushw   %di
-	popw    %es                             # ES:DI must be 0:0
-	movw	$0x4f15, %ax
-	xorw	%bx, %bx
-	xorw	%cx, %cx
-	int	$0x10
-	popw    %es                             # restore ES
-
-	cmpb    $0x00, %ah                      # call successful
-	jne     no_edid
-
-	cmpb    $0x4f, %al                      # function supported
-	jne     no_edid
-
-	movw	$0x4f15, %ax                    # do VBE/DDC
-	movw	$0x01, %bx
-	movw	$0x00, %cx
-	movw    $0x01, %dx
-	movw	$0x140, %di
-	int	$0x10
-
-no_edid:
-	popw	%di				# restore all registers
-	popw	%dx
-	popw	%cx
-	popw	%bx
-	popw	%ax
-	popw	%es
-#endif
-	ret
-
-# VIDEO_SELECT-only variables
-mt_end:		.word	0	# End of video mode table if built
-edit_buf:	.space	6	# Line editor buffer
-card_name:	.word	0	# Pointer to adapter name
-scanning:	.byte	0	# Performing mode scan
-do_restore:	.byte	0	# Screen contents altered during mode change
-svga_prefix:	.byte	VIDEO_FIRST_BIOS>>8	# Default prefix for BIOS modes
-graphic_mode:	.byte	0	# Graphic mode with a linear frame buffer
-dac_size:	.byte	6	# DAC bit depth
-vbe_version:	.word	0	# VBE bios version
-
-# Status messages
-keymsg:		.ascii	"Press <RETURN> to see video modes available, "
-		.ascii	"<SPACE> to continue or wait 30 secs"
-		.byte	0x0d, 0x0a, 0
-
-listhdr:	.byte	0x0d, 0x0a
-		.ascii	"Mode:    COLSxROWS:"
-
-crlft:		.byte	0x0d, 0x0a, 0
-
-prompt:		.byte	0x0d, 0x0a
-		.asciz	"Enter mode number or `scan': "
-
-unknt:		.asciz	"Unknown mode ID. Try again."
-
-badmdt:		.ascii	"You passed an undefined mode number."
-		.byte	0x0d, 0x0a, 0
-
-vesaer:		.ascii	"Error: Scanning of VESA modes failed. Please "
-		.ascii	"report to <mj@ucw.cz>."
-		.byte	0x0d, 0x0a, 0
-
-old_name:	.asciz	"CGA/MDA/HGA"
-
-ega_name:	.asciz	"EGA"
-
-svga_name:	.ascii	" "
-
-vga_name:	.asciz	"VGA"
-
-vesa_name:	.asciz	"VESA"
-
-name_bann:	.asciz	"Video adapter: "
-#endif /* CONFIG_VIDEO_SELECT */
-
-# Other variables:
-adapter:	.byte	0	# Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-video_segment:	.word	0xb800	# Video memory segment
-force_size:	.word	0	# Use this size instead of the one in BIOS vars
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 7a1e251..941a7e3 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Wed Mar  7 15:29:47 2007
+# Linux kernel version: 2.6.21-git3
+# Tue May  1 07:30:48 2007
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
@@ -118,11 +118,11 @@ CONFIG_X86_PC=y
 # CONFIG_X86_VSMP is not set
 # CONFIG_MK8 is not set
 # CONFIG_MPSC is not set
-# CONFIG_MCORE2 is not set
-CONFIG_GENERIC_CPU=y
-CONFIG_X86_L1_CACHE_BYTES=128
-CONFIG_X86_L1_CACHE_SHIFT=7
-CONFIG_X86_INTERNODE_CACHE_BYTES=128
+CONFIG_MCORE2=y
+# CONFIG_GENERIC_CPU is not set
+CONFIG_X86_L1_CACHE_BYTES=64
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_INTERNODE_CACHE_BYTES=64
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
 # CONFIG_MICROCODE is not set
@@ -174,6 +174,7 @@ CONFIG_X86_MCE_INTEL=y
 CONFIG_X86_MCE_AMD=y
 # CONFIG_KEXEC is not set
 # CONFIG_CRASH_DUMP is not set
+# CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_START=0x200000
 CONFIG_SECCOMP=y
 # CONFIG_CC_STACKPROTECTOR is not set
@@ -182,7 +183,6 @@ CONFIG_HZ_250=y
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
-# CONFIG_REORDER is not set
 CONFIG_K8_NB=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
@@ -218,7 +218,6 @@ CONFIG_ACPI_HOTPLUG_CPU=y
 CONFIG_ACPI_THERMAL=y
 CONFIG_ACPI_NUMA=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
@@ -243,7 +242,7 @@ 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
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 
 #
 # CPUFreq processor drivers
@@ -299,7 +298,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -334,6 +332,7 @@ # CONFIG_TCP_MD5SIG is not set
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
@@ -389,6 +388,13 @@ # CONFIG_NET_TCPPROBE is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
 # CONFIG_IEEE80211 is not set
 
 #
@@ -409,10 +415,6 @@ #
 # Connector - unified userspace <-> kernelspace linker
 #
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
 
 #
@@ -459,6 +461,7 @@ # CONFIG_IBM_ASM is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
+# CONFIG_THINKPAD_ACPI is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -494,7 +497,6 @@ # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_RZ1000 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
@@ -525,7 +527,6 @@ # CONFIG_BLK_DEV_TC86C001 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
 
 #
@@ -584,11 +585,9 @@ 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_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
-CONFIG_MEGARAID_SAS=y
+# CONFIG_MEGARAID_SAS is not set
 # CONFIG_SCSI_HPTIOP is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -608,6 +607,7 @@ # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 
 #
@@ -631,12 +631,12 @@ # CONFIG_SATA_ULI is not set
 CONFIG_SATA_VIA=y
 # CONFIG_SATA_VITESSE is not set
 # CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
 CONFIG_SATA_ACPI=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_CMD640_PCI is not set
 # CONFIG_PATA_CMD64X is not set
 # CONFIG_PATA_CS5520 is not set
 # CONFIG_PATA_CS5530 is not set
@@ -688,7 +688,7 @@ #
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 # CONFIG_FUSION_FC is not set
-CONFIG_FUSION_SAS=y
+# CONFIG_FUSION_SAS is not set
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
@@ -701,19 +701,22 @@ #
 # Subsystem Options
 #
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
 
 #
-# Device Drivers
+# Controllers
+#
+
+#
+# Texas Instruments PCILynx requires I2C
 #
-# CONFIG_IEEE1394_PCILYNX is not set
 CONFIG_IEEE1394_OHCI1394=y
 
 #
-# Protocol Drivers
+# Protocols
 #
 # CONFIG_IEEE1394_VIDEO1394 is not set
 # CONFIG_IEEE1394_SBP2 is not set
+# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
 # CONFIG_IEEE1394_ETH1394 is not set
 # CONFIG_IEEE1394_DV1394 is not set
 CONFIG_IEEE1394_RAWIO=y
@@ -776,7 +779,8 @@ # 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_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 CONFIG_B44=y
 CONFIG_FORCEDETH=y
@@ -838,9 +842,10 @@ #
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Wan interfaces
@@ -854,7 +859,6 @@ # CONFIG_NET_FC is not set
 # CONFIG_SHAPER 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
 
@@ -988,57 +992,7 @@ # 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
-
-#
-# 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_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PASEMI 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
+# CONFIG_I2C is not set
 
 #
 # SPI support
@@ -1054,54 +1008,8 @@ # CONFIG_W1 is not set
 #
 # Hardware Monitoring support
 #
-CONFIG_HWMON=y
+# CONFIG_HWMON is not set
 # 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_ADM1029 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
-# 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_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# 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
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 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
 
 #
 # Multifunction device drivers
@@ -1148,8 +1056,9 @@ #
 # Open Sound System
 #
 CONFIG_SOUND_PRIME=y
-# CONFIG_OBSOLETE_OSS is not set
+CONFIG_OBSOLETE_OSS=y
 # CONFIG_SOUND_BT878 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
@@ -1164,6 +1073,14 @@ CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
 # USB support
 #
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1176,6 +1093,7 @@ #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
 # CONFIG_USB_OTG is not set
@@ -1226,10 +1144,6 @@ # CONFIG_USB_LIBUSUAL is not set
 #
 # USB Input Devices
 #
-CONFIG_USB_HID=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
@@ -1557,7 +1471,7 @@ # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 071100e..185399b 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -5,6 +5,11 @@
  * This tricks binfmt_elf.c into loading 32bit binaries using lots 
  * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
  */ 
+#define __ASM_X86_64_ELF_H 1
+
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/rwsem.h>
@@ -50,9 +55,6 @@ #define ELF_ET_DYN_BASE		(TASK_UNMAPPED_
 #undef ELF_ARCH
 #define ELF_ARCH EM_386
 
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-
 #define ELF_DATA	ELFDATA2LSB
 
 #define USE_ELF_CORE_DUMP 1
@@ -136,7 +138,7 @@ #define ELF_CORE_COPY_REGS(pr_reg, regs)
 
 #define user user32
 
-#define __ASM_X86_64_ELF_H 1
+#undef elf_read_implies_exec
 #define elf_read_implies_exec(ex, executable_stack)     (executable_stack != EXSTACK_DISABLE_X)
 //#include <asm/ia32.h>
 #include <linux/elf.h>
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 359eacc..6ea19c2 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 796df69..f210683 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -481,11 +481,7 @@ ia32_sys_call_table:
 	.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
@@ -714,9 +710,10 @@ #endif
 	.quad compat_sys_get_robust_list
 	.quad sys_splice
 	.quad sys_sync_file_range
-	.quad sys_tee
+	.quad sys_tee			/* 315 */
 	.quad compat_sys_vmsplice
 	.quad compat_sys_move_pages
 	.quad sys_getcpu
 	.quad sys_epoll_pwait
+	.quad compat_sys_utimensat	/* 320 */
 ia32_syscall_end:		
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
index 568ff0d..fc4419f 100644
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -13,6 +13,7 @@ #include <linux/security.h>
 #include <asm/proto.h>
 #include <asm/tlbflush.h>
 #include <asm/ia32_unistd.h>
+#include <asm/vsyscall32.h>
 
 extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
 extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index bb47e86..de1de8a 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -8,7 +8,8 @@ obj-y	:= process.o signal.o entry.o trap
 		ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
 		x8664_ksyms.o i387.o syscall.o vsyscall.o \
 		setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
-		pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o
+		pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \
+		perfctr-watchdog.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_X86_MCE)		+= mce.o therm_throt.o
@@ -21,8 +22,7 @@ obj-$(CONFIG_MICROCODE)		+= microcode.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o trampoline.o tsc_sync.o
 obj-y				+= apic.o  nmi.o
-obj-y				+= io_apic.o mpparse.o \
-		genapic.o genapic_cluster.o genapic_flat.o
+obj-y				+= io_apic.o mpparse.o genapic.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
@@ -32,6 +32,7 @@ obj-$(CONFIG_EARLY_PRINTK)	+= early_prin
 obj-$(CONFIG_IOMMU)		+= pci-gart.o aperture.o
 obj-$(CONFIG_CALGARY_IOMMU)	+= pci-calgary.o tce.o
 obj-$(CONFIG_SWIOTLB)		+= pci-swiotlb.o
+obj-$(CONFIG_SERIAL_8250)	+= legacy_serial.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer.o
 obj-$(CONFIG_X86_VSMP)		+= vsmp.o
@@ -49,6 +50,7 @@ CFLAGS_vsyscall.o		:= $(PROFILING) -g0
 
 therm_throt-y                   += ../../i386/kernel/cpu/mcheck/therm_throt.o
 bootflag-y			+= ../../i386/kernel/bootflag.o
+legacy_serial-y			+= ../../i386/kernel/legacy_serial.o
 cpuid-$(subst m,y,$(CONFIG_X86_CPUID))  += ../../i386/kernel/cpuid.o
 topology-y                     += ../../i386/kernel/topology.o
 microcode-$(subst m,y,$(CONFIG_MICROCODE))  += ../../i386/kernel/microcode.o
@@ -58,3 +60,4 @@ i8237-y				+= ../../i386/kernel/i8237.o
 msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
 alternative-y			+= ../../i386/kernel/alternative.o
 pcspeaker-y			+= ../../i386/kernel/pcspeaker.o
+perfctr-watchdog-y		+= ../../i386/kernel/cpu/perfctr-watchdog.o
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index e1548fb..195b703 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -60,19 +60,6 @@ extern char wakeup_start, wakeup_end;
 
 extern unsigned long acpi_copy_wakeup_routine(unsigned long);
 
-static pgd_t low_ptr;
-
-static void init_low_mapping(void)
-{
-	pgd_t *slot0 = pgd_offset(current->mm, 0UL);
-	low_ptr = *slot0;
-	/* FIXME: We're playing with the current task's page tables here, which
-	 * is potentially dangerous on SMP systems.
-	 */
-	set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET));
-	local_flush_tlb();
-}
-
 /**
  * acpi_save_state_mem - save kernel state
  *
@@ -81,8 +68,6 @@ static void init_low_mapping(void)
  */
 int acpi_save_state_mem(void)
 {
-	init_low_mapping();
-
 	memcpy((void *)acpi_wakeup_address, &wakeup_start,
 	       &wakeup_end - &wakeup_start);
 	acpi_copy_wakeup_routine(acpi_wakeup_address);
@@ -95,8 +80,6 @@ int acpi_save_state_mem(void)
  */
 void acpi_restore_state_mem(void)
 {
-	set_pgd(pgd_offset(current->mm, 0UL), low_ptr);
-	local_flush_tlb();
 }
 
 /**
@@ -109,10 +92,11 @@ void acpi_restore_state_mem(void)
  */
 void __init acpi_reserve_bootmem(void)
 {
-	acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
-	if ((&wakeup_end - &wakeup_start) > PAGE_SIZE)
+	acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2);
+	if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2))
 		printk(KERN_CRIT
-		       "ACPI: Wakeup code way too big, will crash on attempt to suspend\n");
+		       "ACPI: Wakeup code way too big, will crash on attempt"
+		       " to suspend\n");
 }
 
 static int __init acpi_sleep_setup(char *str)
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index 185faa9..8550a6f 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -1,6 +1,7 @@
 .text
 #include <linux/linkage.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/msr.h>
 
@@ -30,22 +31,28 @@ # Running in *copy* of this code, somewh
 	cld
 	# setup data segment
 	movw	%cs, %ax
-	movw	%ax, %ds					# Make ds:0 point to wakeup_start
+	movw	%ax, %ds		# Make ds:0 point to wakeup_start
 	movw	%ax, %ss
-	mov	$(wakeup_stack - wakeup_code), %sp		# Private stack is needed for ASUS board
+					# Private stack is needed for ASUS board
+	mov	$(wakeup_stack - wakeup_code), %sp
 
-	pushl	$0						# Kill any dangerous flags
+	pushl	$0			# Kill any dangerous flags
 	popfl
 
 	movl	real_magic - wakeup_code, %eax
 	cmpl	$0x12345678, %eax
 	jne	bogus_real_magic
 
+  	call	verify_cpu			# Verify the cpu supports long
+						# mode
+	testl	%eax, %eax
+	jnz	no_longmode
+
 	testl	$1, video_flags - wakeup_code
 	jz	1f
 	lcall   $0xc000,$3
 	movw	%cs, %ax
-	movw	%ax, %ds					# Bios might have played with that
+	movw	%ax, %ds		# Bios might have played with that
 	movw	%ax, %ss
 1:
 
@@ -61,12 +68,15 @@ # Running in *copy* of this code, somewh
 
 	movb	$0xa2, %al	;  outb %al, $0x80
 	
-	lidt	%ds:idt_48a - wakeup_code
-	xorl	%eax, %eax
-	movw	%ds, %ax			# (Convert %ds:gdt to a linear ptr)
-	shll	$4, %eax
-	addl	$(gdta - wakeup_code), %eax
-	movl	%eax, gdt_48a +2 - wakeup_code
+	mov	%ds, %ax			# Find 32bit wakeup_code addr
+	movzx   %ax, %esi			# (Convert %ds:gdt to a liner ptr)
+	shll    $4, %esi
+						# Fix up the vectors
+	addl    %esi, wakeup_32_vector - wakeup_code
+	addl    %esi, wakeup_long64_vector - wakeup_code
+	addl    %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
+
+	lidtl	%ds:idt_48a - wakeup_code
 	lgdtl	%ds:gdt_48a - wakeup_code	# load gdt with whatever is
 						# appropriate
 
@@ -75,86 +85,63 @@ # Running in *copy* of this code, somewh
 	jmp	1f
 1:
 
-	.byte 0x66, 0xea			# prefix + jmpi-opcode
-	.long	wakeup_32 - __START_KERNEL_map
-	.word	__KERNEL_CS
+	ljmpl   *(wakeup_32_vector - wakeup_code)
+
+	.balign 4
+wakeup_32_vector:
+	.long   wakeup_32 - wakeup_code
+	.word   __KERNEL32_CS, 0
 
 	.code32
 wakeup_32:
 # Running in this code, but at low address; paging is not yet turned on.
 	movb	$0xa5, %al	;  outb %al, $0x80
 
-	/* Check if extended functions are implemented */		
-	movl	$0x80000000, %eax
-	cpuid
-	cmpl	$0x80000000, %eax
-	jbe	bogus_cpu
-	wbinvd
-	mov	$0x80000001, %eax
-	cpuid
-	btl	$29, %edx
-	jnc	bogus_cpu
-	movl	%edx,%edi
-	
-	movw	$__KERNEL_DS, %ax
-	movw	%ax, %ds
-	movw	%ax, %es
-	movw	%ax, %fs
-	movw	%ax, %gs
-
-	movw	$__KERNEL_DS, %ax	
-	movw	%ax, %ss
+	movl	$__KERNEL_DS, %eax
+	movl	%eax, %ds
 
-	mov	$(wakeup_stack - __START_KERNEL_map), %esp
-	movl	saved_magic - __START_KERNEL_map, %eax
-	cmpl	$0x9abcdef0, %eax
-	jne	bogus_32_magic
+	movw	$0x0e00 + 'i', %ds:(0xb8012)
+	movb	$0xa8, %al	;  outb %al, $0x80;
 
 	/*
 	 * Prepare for entering 64bits mode
 	 */
 
-	/* Enable PAE mode and PGE */
+	/* Enable PAE */
 	xorl	%eax, %eax
 	btsl	$5, %eax
-	btsl	$7, %eax
 	movl	%eax, %cr4
 
 	/* Setup early boot stage 4 level pagetables */
-	movl	$(wakeup_level4_pgt - __START_KERNEL_map), %eax
+	leal    (wakeup_level4_pgt - wakeup_code)(%esi), %eax
 	movl	%eax, %cr3
 
-	/* Setup EFER (Extended Feature Enable Register) */
-	movl	$MSR_EFER, %ecx
-	rdmsr
-	/* Fool rdmsr and reset %eax to avoid dependences */
-	xorl	%eax, %eax
+        /* Check if nx is implemented */
+        movl    $0x80000001, %eax
+        cpuid
+        movl    %edx,%edi
+
 	/* Enable Long Mode */
+	xorl    %eax, %eax
 	btsl	$_EFER_LME, %eax
-	/* Enable System Call */
-	btsl	$_EFER_SCE, %eax
 
-	/* No Execute supported? */	
+	/* No Execute supported? */
 	btl	$20,%edi
 	jnc     1f
 	btsl	$_EFER_NX, %eax
-1:	
 				
 	/* Make changes effective */
+1:	movl    $MSR_EFER, %ecx
+	xorl    %edx, %edx
 	wrmsr
-	wbinvd
 
 	xorl	%eax, %eax
 	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
 	btsl	$0, %eax			/* Enable protected mode */
-	btsl	$1, %eax			/* Enable MP */
-	btsl	$4, %eax			/* Enable ET */
-	btsl	$5, %eax			/* Enable NE */
-	btsl	$16, %eax			/* Enable WP */
-	btsl	$18, %eax			/* Enable AM */
 
 	/* Make changes effective */
 	movl	%eax, %cr0
+
 	/* At this point:
 		CR4.PAE must be 1
 		CS.L must be 0
@@ -162,11 +149,6 @@ # Running in this code, but at low addre
 		Next instruction must be a branch
 		This must be on identity-mapped page
 	*/
-	jmp	reach_compatibility_mode
-reach_compatibility_mode:
-	movw	$0x0e00 + 'i', %ds:(0xb8012)
-	movb	$0xa8, %al	;  outb %al, $0x80; 	
-		
 	/*
 	 * At this point we're in long mode but in 32bit compatibility mode
 	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
@@ -174,24 +156,19 @@ reach_compatibility_mode:
 	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
 	 */
 
-	movw	$0x0e00 + 'n', %ds:(0xb8014)
-	movb	$0xa9, %al	;  outb %al, $0x80
-	
-	/* Load new GDT with the 64bit segment using 32bit descriptor */
-	movl	$(pGDT32 - __START_KERNEL_map), %eax
-	lgdt	(%eax)
-
-	movl    $(wakeup_jumpvector - __START_KERNEL_map), %eax
 	/* Finally jump in 64bit mode */
-	ljmp	*(%eax)
+        ljmp    *(wakeup_long64_vector - wakeup_code)(%esi)
 
-wakeup_jumpvector:
-	.long	wakeup_long64 - __START_KERNEL_map
-	.word	__KERNEL_CS
+	.balign 4
+wakeup_long64_vector:
+	.long   wakeup_long64 - wakeup_code
+	.word   __KERNEL_CS, 0
 
 .code64
 
-	/*	Hooray, we are in Long 64-bit mode (but still running in low memory) */
+	/* Hooray, we are in Long 64-bit mode (but still running in
+	 * low memory)
+	 */
 wakeup_long64:
 	/*
 	 * We must switch to a new descriptor in kernel space for the GDT
@@ -199,7 +176,15 @@ wakeup_long64:
 	 * addresses where we're currently running on. We have to do that here
 	 * because in 32bit we couldn't load a 64bit linear address.
 	 */
-	lgdt	cpu_gdt_descr - __START_KERNEL_map
+	lgdt	cpu_gdt_descr
+
+	movw	$0x0e00 + 'n', %ds:(0xb8014)
+	movb	$0xa9, %al	;  outb %al, $0x80
+
+	movq    saved_magic, %rax
+	movq    $0x123456789abcdef0, %rdx
+	cmpq    %rdx, %rax
+	jne     bogus_64_magic
 
 	movw	$0x0e00 + 'u', %ds:(0xb8016)
 	
@@ -211,75 +196,58 @@ wakeup_long64:
 	movw	%ax, %es
 	movw	%ax, %fs
 	movw	%ax, %gs
-	movq	saved_esp, %rsp
+	movq	saved_rsp, %rsp
 
 	movw	$0x0e00 + 'x', %ds:(0xb8018)
-	movq	saved_ebx, %rbx
-	movq	saved_edi, %rdi
-	movq	saved_esi, %rsi
-	movq	saved_ebp, %rbp
+	movq	saved_rbx, %rbx
+	movq	saved_rdi, %rdi
+	movq	saved_rsi, %rsi
+	movq	saved_rbp, %rbp
 
 	movw	$0x0e00 + '!', %ds:(0xb801a)
-	movq	saved_eip, %rax
+	movq	saved_rip, %rax
 	jmp	*%rax
 
 .code32
 
 	.align	64	
 gdta:
+	/* Its good to keep gdt in sync with one in trampoline.S */
 	.word	0, 0, 0, 0			# dummy
-
-	.word	0, 0, 0, 0			# unused
-
-	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
-	.word	0				# base address = 0
-	.word	0x9B00				# code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?)
-	.word	0x00CF				# granularity = 4096, 386
-						#  (+5th nibble of limit)
-
-	.word	0xFFFF				# 4Gb - (0x100000*0x1000 = 4Gb)
-	.word	0				# base address = 0
-	.word	0x9200				# data read/write
-	.word	0x00CF				# granularity = 4096, 386
-						#  (+5th nibble of limit)
-# this is 64bit descriptor for code
-	.word	0xFFFF
-	.word	0
-	.word	0x9A00				# code read/exec
-	.word	0x00AF				# as above, but it is long mode and with D=0
+	/* ??? Why I need the accessed bit set in order for this to work? */
+	.quad   0x00cf9b000000ffff              # __KERNEL32_CS
+	.quad   0x00af9b000000ffff              # __KERNEL_CS
+	.quad   0x00cf93000000ffff              # __KERNEL_DS
 
 idt_48a:
 	.word	0				# idt limit = 0
 	.word	0, 0				# idt base = 0L
 
 gdt_48a:
-	.word	0x8000				# gdt limit=2048,
+	.word	0x800				# gdt limit=2048,
 						#  256 GDT entries
-	.word	0, 0				# gdt base (filled in later)
-	
+	.long   gdta - wakeup_code              # gdt base (relocated in later)
 	
-real_save_gdt:	.word 0
-		.quad 0
 real_magic:	.quad 0
 video_mode:	.quad 0
 video_flags:	.quad 0
 
+.code16
 bogus_real_magic:
-	movb	$0xba,%al	;  outb %al,$0x80		
+	movb	$0xba,%al	;  outb %al,$0x80
 	jmp bogus_real_magic
 
-bogus_32_magic:
+.code64
+bogus_64_magic:
 	movb	$0xb3,%al	;  outb %al,$0x80
-	jmp bogus_32_magic
+	jmp bogus_64_magic
 
-bogus_31_magic:
-	movb	$0xb1,%al	;  outb %al,$0x80
-	jmp bogus_31_magic
-
-bogus_cpu:
-	movb	$0xbc,%al	;  outb %al,$0x80
-	jmp bogus_cpu
+.code16
+no_longmode:
+	movb    $0xbc,%al       ;  outb %al,$0x80
+	jmp no_longmode
 
+#include "../verify_cpu.S"
 	
 /* This code uses an extended set of video mode numbers. These include:
  * Aliases for standard modes
@@ -301,6 +269,7 @@ #define VIDEO_FIRST_VESA 0x0200
 #define VIDEO_FIRST_V7 0x0900
 
 # Setting of user mode (AX=mode ID) => CF=success
+.code16
 mode_seta:
 	movw	%ax, %bx
 #if 0
@@ -346,21 +315,18 @@ check_vesaa:
 
 _setbada: jmp setbada
 
-	.code64
-bogus_magic:
-	movw	$0x0e00 + 'B', %ds:(0xb8018)
-	jmp bogus_magic
-
-bogus_magic2:
-	movw	$0x0e00 + '2', %ds:(0xb8018)
-	jmp bogus_magic2
-	
-
 wakeup_stack_begin:	# Stack grows down
 
 .org	0xff0
 wakeup_stack:		# Just below end of page
 
+.org   0x1000
+ENTRY(wakeup_level4_pgt)
+	.quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+	.fill   510,8,0
+	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+	.quad   level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
+
 ENTRY(wakeup_end)
 	
 ##
@@ -373,28 +339,11 @@ # %rdi:	place to copy wakeup routine to
 #
 # Returned address is location of code in low memory (past data and stack)
 #
+	.code64
 ENTRY(acpi_copy_wakeup_routine)
 	pushq	%rax
-	pushq	%rcx
 	pushq	%rdx
 
-	sgdt	saved_gdt
-	sidt	saved_idt
-	sldt	saved_ldt
-	str	saved_tss
-
-	movq    %cr3, %rdx
-	movq    %rdx, saved_cr3
-	movq    %cr4, %rdx
-	movq    %rdx, saved_cr4
-	movq	%cr0, %rdx
-	movq	%rdx, saved_cr0
-	sgdt    real_save_gdt - wakeup_start (,%rdi)
-	movl	$MSR_EFER, %ecx
-	rdmsr
-	movl	%eax, saved_efer
-	movl	%edx, saved_efer2
-
 	movl	saved_video_mode, %edx
 	movl	%edx, video_mode - wakeup_start (,%rdi)
 	movl	acpi_video_flags, %edx
@@ -403,21 +352,13 @@ ENTRY(acpi_copy_wakeup_routine)
 	movq	$0x123456789abcdef0, %rdx
 	movq	%rdx, saved_magic
 
-	movl	saved_magic - __START_KERNEL_map, %eax
-	cmpl	$0x9abcdef0, %eax
-	jne	bogus_32_magic
-
-	# make sure %cr4 is set correctly (features, etc)
-	movl	saved_cr4 - __START_KERNEL_map, %eax
-	movq	%rax, %cr4
+	movq    saved_magic, %rax
+	movq    $0x123456789abcdef0, %rdx
+	cmpq    %rdx, %rax
+	jne     bogus_64_magic
 
-	movl	saved_cr0 - __START_KERNEL_map, %eax
-	movq	%rax, %cr0
-	jmp	1f		# Flush pipelines
-1:
 	# restore the regs we used
 	popq	%rdx
-	popq	%rcx
 	popq	%rax
 ENTRY(do_suspend_lowlevel_s4bios)
 	ret
@@ -450,13 +391,13 @@ do_suspend_lowlevel:
 	movq %r15, saved_context_r15(%rip)
 	pushfq ; popq saved_context_eflags(%rip)
 
-	movq	$.L97, saved_eip(%rip)
+	movq	$.L97, saved_rip(%rip)
 
-	movq %rsp,saved_esp
-	movq %rbp,saved_ebp
-	movq %rbx,saved_ebx
-	movq %rdi,saved_edi
-	movq %rsi,saved_esi
+	movq %rsp,saved_rsp
+	movq %rbp,saved_rbp
+	movq %rbx,saved_rbx
+	movq %rdi,saved_rdi
+	movq %rsi,saved_rsi
 
 	addq	$8, %rsp
 	movl	$3, %edi
@@ -503,25 +444,12 @@ do_suspend_lowlevel:
 	
 .data
 ALIGN
-ENTRY(saved_ebp)	.quad	0
-ENTRY(saved_esi)	.quad	0
-ENTRY(saved_edi)	.quad	0
-ENTRY(saved_ebx)	.quad	0
+ENTRY(saved_rbp)	.quad	0
+ENTRY(saved_rsi)	.quad	0
+ENTRY(saved_rdi)	.quad	0
+ENTRY(saved_rbx)	.quad	0
 
-ENTRY(saved_eip)	.quad	0
-ENTRY(saved_esp)	.quad	0
+ENTRY(saved_rip)	.quad	0
+ENTRY(saved_rsp)	.quad	0
 
 ENTRY(saved_magic)	.quad	0
-
-ALIGN
-# saved registers
-saved_gdt:	.quad	0,0
-saved_idt:	.quad	0,0
-saved_ldt:	.quad	0
-saved_tss:	.quad	0
-
-saved_cr0:	.quad 0
-saved_cr3:	.quad 0
-saved_cr4:	.quad 0
-saved_efer:	.quad 0
-saved_efer2:	.quad 0
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index b487396..a52af58 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -51,7 +51,6 @@ static void __init insert_aperture_resou
 
 static u32 __init allocate_aperture(void) 
 {
-	pg_data_t *nd0 = NODE_DATA(0);
 	u32 aper_size;
 	void *p; 
 
@@ -65,12 +64,12 @@ static u32 __init allocate_aperture(void
 	 * Unfortunately we cannot move it up because that would make the
 	 * IOMMU useless.
 	 */
-	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
+	p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
 	if (!p || __pa(p)+aper_size > 0xffffffff) {
 		printk("Cannot allocate aperture memory hole (%p,%uK)\n",
 		       p, aper_size>>10);
 		if (p)
-			free_bootmem_node(nd0, __pa(p), aper_size); 
+			free_bootmem(__pa(p), aper_size);
 		return 0;
 	}
 	printk("Mapping aperture over %d KB of RAM @ %lx\n",
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index bd3e45d..1b0e07b 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -19,7 +19,6 @@ #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>
@@ -68,6 +67,28 @@ int using_apic_timer __read_mostly = 0;
 
 static void apic_pm_activate(void);
 
+void apic_wait_icr_idle(void)
+{
+	while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+		cpu_relax();
+}
+
+unsigned int safe_apic_wait_icr_idle(void)
+{
+	unsigned int send_status;
+	int timeout;
+
+	timeout = 0;
+	do {
+		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+		if (!send_status)
+			break;
+		udelay(100);
+	} while (timeout++ < 1000);
+
+	return send_status;
+}
+
 void enable_NMI_through_LVT0 (void * dummy)
 {
 	unsigned int v;
@@ -817,14 +838,15 @@ #define TICK_COUNT 100000000
 
 static int __init calibrate_APIC_clock(void)
 {
-	int apic, apic_start, tsc, tsc_start;
+	unsigned apic, apic_start;
+	unsigned long tsc, tsc_start;
 	int result;
 	/*
 	 * Put whatever arbitrary (but long enough) timeout
 	 * value into the APIC clock, we just want to get the
 	 * counter running for calibration.
 	 */
-	__setup_APIC_LVTT(1000000000);
+	__setup_APIC_LVTT(4000000000);
 
 	apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -835,15 +857,15 @@ #ifdef CONFIG_X86_PM_TIMER
 	} else
 #endif
 	{
-		rdtscl(tsc_start);
+		rdtscll(tsc_start);
 
 		do {
 			apic = apic_read(APIC_TMCCT);
-			rdtscl(tsc);
+			rdtscll(tsc);
 		} while ((tsc - tsc_start) < TICK_COUNT &&
-				(apic - apic_start) < TICK_COUNT);
+				(apic_start - apic) < TICK_COUNT);
 
-		result = (apic_start - apic) * 1000L * cpu_khz /
+		result = (apic_start - apic) * 1000L * tsc_khz /
 					(tsc - tsc_start);
 	}
 	printk("result %d\n", result);
diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c
index 96687e2..778953b 100644
--- a/arch/x86_64/kernel/asm-offsets.c
+++ b/arch/x86_64/kernel/asm-offsets.c
@@ -21,6 +21,14 @@ #define DEFINE(sym, val) \
 
 #define BLANK() asm volatile("\n->" : : )
 
+#define __NO_STUBS 1
+#undef __SYSCALL
+#undef _ASM_X86_64_UNISTD_H_
+#define __SYSCALL(nr, sym) [nr] = 1,
+static char syscalls[] = {
+#include <asm/unistd.h>
+};
+
 int main(void)
 {
 #define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry))
@@ -71,5 +79,7 @@ #endif
 	DEFINE(TSS_ist, offsetof(struct tss_struct, ist));
 	BLANK();
 	DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+	BLANK();
+	DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
 	return 0;
 }
diff --git a/arch/x86_64/kernel/bugs.c b/arch/x86_64/kernel/bugs.c
new file mode 100644
index 0000000..12b585b
--- /dev/null
+++ b/arch/x86_64/kernel/bugs.c
@@ -0,0 +1,21 @@
+/*
+ *  arch/x86_64/kernel/bugs.c
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 2000  SuSE
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/alternative.h>
+#include <asm/processor.h>
+
+void __init check_bugs(void)
+{
+	identify_cpu(&boot_cpu_data);
+#if !defined(CONFIG_SMP)
+	printk("CPU: ");
+	print_cpu_info(&boot_cpu_data);
+#endif
+	alternative_instructions();
+}
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index 40acb67..c0749d2 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -16,6 +16,9 @@ config X86_POWERNOW_K8
 	help
 	  This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called powernow-k8.
+
 	  For details, take a look at <file:Documentation/cpu-freq/>. 
 
 	  If in doubt, say N.
@@ -38,6 +41,9 @@ config X86_SPEEDSTEP_CENTRINO
 	  mobile CPUs.  This means Intel Pentium M (Centrino) CPUs
 	  or 64bit enabled Intel Xeons.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called speedstep-centrino.
+
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  If in doubt, say N.
@@ -55,6 +61,9 @@ config X86_ACPI_CPUFREQ
 	  Processor Performance States.
 	  This driver also supports Intel Enhanced Speedstep.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called acpi-cpufreq.
+
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  If in doubt, say N.
@@ -62,7 +71,7 @@ config X86_ACPI_CPUFREQ
 comment "shared options"
 
 config X86_ACPI_CPUFREQ_PROC_INTF
-        bool "/proc/acpi/processor/../performance interface (deprecated)"
+	bool "/proc/acpi/processor/../performance interface (deprecated)"
 	depends on PROC_FS
 	depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI
 	help
@@ -86,16 +95,18 @@ config X86_P4_CLOCKMOD
 	  slowdowns and noticeable latencies.  Normally Speedstep should be used
 	  instead.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called p4-clockmod.
+
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  Unless you are absolutely sure say N.
 
 
 config X86_SPEEDSTEP_LIB
-        tristate
-        default X86_P4_CLOCKMOD
+	tristate
+	default X86_P4_CLOCKMOD
 
 endif
 
 endmenu
-
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index 95a7a2c..13432a1 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -17,13 +17,13 @@ #include <linux/kexec.h>
 #include <linux/delay.h>
 #include <linux/elf.h>
 #include <linux/elfcore.h>
+#include <linux/kdebug.h>
 
 #include <asm/processor.h>
 #include <asm/hardirq.h>
 #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;
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index a490fab..13c6c37 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -17,6 +17,8 @@ #include <linux/string.h>
 #include <linux/kexec.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/pfn.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -25,7 +27,7 @@ #include <asm/proto.h>
 #include <asm/bootsetup.h>
 #include <asm/sections.h>
 
-struct e820map e820 __initdata;
+struct e820map e820;
 
 /* 
  * PFN of last memory page.
@@ -98,7 +100,7 @@ #endif
  * This function checks if any part of the range <start,end> is mapped
  * with type.
  */
-int __meminit
+int
 e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
 { 
 	int i;
@@ -112,6 +114,7 @@ e820_any_mapped(unsigned long start, uns
 	} 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(e820_any_mapped);
 
 /*
  * This function checks if the entire range <start,end> is mapped with type.
@@ -255,22 +258,6 @@ #endif
 	}
 }
 
-/* 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
@@ -289,13 +276,13 @@ void __init e820_mark_nosave_regions(voi
 		struct e820entry *ei = &e820.map[i];
 
 		if (paddr < ei->addr)
-			e820_mark_nosave_range(paddr,
-					round_up(ei->addr, PAGE_SIZE));
+			register_nosave_region(PFN_DOWN(paddr),
+						PFN_UP(ei->addr));
 
 		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);
+			register_nosave_region(PFN_UP(ei->addr),
+						PFN_DOWN(paddr));
 
 		if (paddr >= (end_pfn << PAGE_SHIFT))
 			break;
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index fede55a..990d9c2 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -71,18 +71,6 @@ static void __init ati_bugs(void)
 	}
 }
 
-static void intel_bugs(void)
-{
-	u16 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
-
-#ifdef CONFIG_SMP
-	if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
-	    device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
-	    device == PCI_DEVICE_ID_INTEL_E7525_MCH)
-		quirk_intel_irqbalance();
-#endif
-}
-
 struct chipset {
 	u16 vendor;
 	void (*f)(void);
@@ -92,7 +80,6 @@ static struct chipset early_qrk[] __init
 	{ PCI_VENDOR_ID_NVIDIA, nvidia_bugs },
 	{ PCI_VENDOR_ID_VIA, via_bugs },
 	{ PCI_VENDOR_ID_ATI, ati_bugs },
-	{ PCI_VENDOR_ID_INTEL, intel_bugs},
 	{}
 };
 
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 47b6d90..56eaa25 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -11,11 +11,10 @@ #include <asm/fcntl.h>
 
 #ifdef __i386__
 #include <asm/setup.h>
-#define VGABASE		(__ISA_IO_base + 0xb8000)
 #else
 #include <asm/bootsetup.h>
-#define VGABASE		((void __iomem *)0xffffffff800b8000UL)
 #endif
+#define VGABASE		(__ISA_IO_base + 0xb8000)
 
 static int max_ypos = 25, max_xpos = 80;
 static int current_ypos = 25, current_xpos = 0;
@@ -176,7 +175,7 @@ static noinline long simnow(long cmd, lo
 	return ret;
 }
 
-void __init simnow_init(char *str)
+static void __init simnow_init(char *str)
 {
 	char *fn = "klog";
 	if (*str == '=')
@@ -244,22 +243,12 @@ static int __init setup_early_printk(cha
  		early_console = &simnow_console;
  		keep_early = 1;
 	}
+
+	if (keep_early)
+		early_console->flags &= ~CON_BOOT;
+	else
+		early_console->flags |= CON_BOOT;
 	register_console(early_console);
 	return 0;
 }
-
 early_param("earlyprintk", setup_early_printk);
-
-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");
-	}
-}
-
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index ed4350c..fa984b5 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -701,6 +701,7 @@ END(spurious_interrupt)
 	CFI_ADJUST_CFA_OFFSET 8
 	pushq %rax	/* push real oldrax to the rdi slot */ 
 	CFI_ADJUST_CFA_OFFSET 8
+	CFI_REL_OFFSET rax,0
 	leaq  \sym(%rip),%rax
 	jmp error_entry
 	CFI_ENDPROC
@@ -710,6 +711,7 @@ END(spurious_interrupt)
 	XCPT_FRAME
 	pushq %rax
 	CFI_ADJUST_CFA_OFFSET 8
+	CFI_REL_OFFSET rax,0
 	leaq  \sym(%rip),%rax
 	jmp error_entry
 	CFI_ENDPROC
@@ -817,6 +819,7 @@ paranoid_schedule\trace:
  */ 		  				
 KPROBE_ENTRY(error_entry)
 	_frame RDI
+	CFI_REL_OFFSET rax,0
 	/* rdi slot contains rax, oldrax contains error code */
 	cld	
 	subq  $14*8,%rsp
@@ -824,6 +827,7 @@ KPROBE_ENTRY(error_entry)
 	movq %rsi,13*8(%rsp)
 	CFI_REL_OFFSET	rsi,RSI
 	movq 14*8(%rsp),%rsi	/* load rax from rdi slot */
+	CFI_REGISTER	rax,rsi
 	movq %rdx,12*8(%rsp)
 	CFI_REL_OFFSET	rdx,RDX
 	movq %rcx,11*8(%rsp)
@@ -857,6 +861,7 @@ error_swapgs:	
 	swapgs
 error_sti:	
 	movq %rdi,RDI(%rsp) 	
+	CFI_REL_OFFSET	rdi,RDI
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
 	movq $-1,ORIG_RAX(%rsp)
diff --git a/arch/x86_64/kernel/functionlist b/arch/x86_64/kernel/functionlist
deleted file mode 100644
index 7ae18ec..0000000
--- a/arch/x86_64/kernel/functionlist
+++ /dev/null
@@ -1,1284 +0,0 @@
-*(.text.flush_thread)
-*(.text.check_poison_obj)
-*(.text.copy_page)
-*(.text.__set_personality)
-*(.text.gart_map_sg)
-*(.text.kmem_cache_free)
-*(.text.find_get_page)
-*(.text._raw_spin_lock)
-*(.text.ide_outb)
-*(.text.unmap_vmas)
-*(.text.copy_page_range)
-*(.text.kprobe_handler)
-*(.text.__handle_mm_fault)
-*(.text.__d_lookup)
-*(.text.copy_user_generic)
-*(.text.__link_path_walk)
-*(.text.get_page_from_freelist)
-*(.text.kmem_cache_alloc)
-*(.text.drive_cmd_intr)
-*(.text.ia32_setup_sigcontext)
-*(.text.huge_pte_offset)
-*(.text.do_page_fault)
-*(.text.page_remove_rmap)
-*(.text.release_pages)
-*(.text.ide_end_request)
-*(.text.__mutex_lock_slowpath)
-*(.text.__find_get_block)
-*(.text.kfree)
-*(.text.vfs_read)
-*(.text._raw_spin_unlock)
-*(.text.free_hot_cold_page)
-*(.text.fget_light)
-*(.text.schedule)
-*(.text.memcmp)
-*(.text.touch_atime)
-*(.text.__might_sleep)
-*(.text.__down_read_trylock)
-*(.text.arch_pick_mmap_layout)
-*(.text.find_vma)
-*(.text.__make_request)
-*(.text.do_generic_mapping_read)
-*(.text.mutex_lock_interruptible)
-*(.text.__generic_file_aio_read)
-*(.text._atomic_dec_and_lock)
-*(.text.__wake_up_bit)
-*(.text.add_to_page_cache)
-*(.text.cache_alloc_debugcheck_after)
-*(.text.vm_normal_page)
-*(.text.mutex_debug_check_no_locks_freed)
-*(.text.net_rx_action)
-*(.text.__find_first_zero_bit)
-*(.text.put_page)
-*(.text._raw_read_lock)
-*(.text.__delay)
-*(.text.dnotify_parent)
-*(.text.do_path_lookup)
-*(.text.do_sync_read)
-*(.text.do_lookup)
-*(.text.bit_waitqueue)
-*(.text.file_read_actor)
-*(.text.strncpy_from_user)
-*(.text.__pagevec_lru_add_active)
-*(.text.fget)
-*(.text.dput)
-*(.text.__strnlen_user)
-*(.text.inotify_inode_queue_event)
-*(.text.rw_verify_area)
-*(.text.ide_intr)
-*(.text.inotify_dentry_parent_queue_event)
-*(.text.permission)
-*(.text.memscan)
-*(.text.hpet_rtc_interrupt)
-*(.text.do_mmap_pgoff)
-*(.text.current_fs_time)
-*(.text.vfs_getattr)
-*(.text.kmem_flagcheck)
-*(.text.mark_page_accessed)
-*(.text.free_pages_and_swap_cache)
-*(.text.generic_fillattr)
-*(.text.__block_prepare_write)
-*(.text.__set_page_dirty_nobuffers)
-*(.text.link_path_walk)
-*(.text.find_get_pages_tag)
-*(.text.ide_do_request)
-*(.text.__alloc_pages)
-*(.text.generic_permission)
-*(.text.mod_page_state_offset)
-*(.text.free_pgd_range)
-*(.text.generic_file_buffered_write)
-*(.text.number)
-*(.text.ide_do_rw_disk)
-*(.text.__brelse)
-*(.text.__mod_page_state_offset)
-*(.text.rotate_reclaimable_page)
-*(.text.find_vma_prepare)
-*(.text.find_vma_prev)
-*(.text.lru_cache_add_active)
-*(.text.__kmalloc_track_caller)
-*(.text.smp_invalidate_interrupt)
-*(.text.handle_IRQ_event)
-*(.text.__find_get_block_slow)
-*(.text.do_wp_page)
-*(.text.do_select)
-*(.text.set_user_nice)
-*(.text.sys_read)
-*(.text.do_munmap)
-*(.text.csum_partial)
-*(.text.__do_softirq)
-*(.text.may_open)
-*(.text.getname)
-*(.text.get_empty_filp)
-*(.text.__fput)
-*(.text.remove_mapping)
-*(.text.filp_ctor)
-*(.text.poison_obj)
-*(.text.unmap_region)
-*(.text.test_set_page_writeback)
-*(.text.__do_page_cache_readahead)
-*(.text.sock_def_readable)
-*(.text.ide_outl)
-*(.text.shrink_zone)
-*(.text.rb_insert_color)
-*(.text.get_request)
-*(.text.sys_pread64)
-*(.text.spin_bug)
-*(.text.ide_outsl)
-*(.text.mask_and_ack_8259A)
-*(.text.filemap_nopage)
-*(.text.page_add_file_rmap)
-*(.text.find_lock_page)
-*(.text.tcp_poll)
-*(.text.__mark_inode_dirty)
-*(.text.file_ra_state_init)
-*(.text.generic_file_llseek)
-*(.text.__pagevec_lru_add)
-*(.text.page_cache_readahead)
-*(.text.n_tty_receive_buf)
-*(.text.zonelist_policy)
-*(.text.vma_adjust)
-*(.text.test_clear_page_dirty)
-*(.text.sync_buffer)
-*(.text.do_exit)
-*(.text.__bitmap_weight)
-*(.text.alloc_pages_current)
-*(.text.get_unused_fd)
-*(.text.zone_watermark_ok)
-*(.text.cpuset_update_task_memory_state)
-*(.text.__bitmap_empty)
-*(.text.sys_munmap)
-*(.text.__inode_dir_notify)
-*(.text.__generic_file_aio_write_nolock)
-*(.text.__pte_alloc)
-*(.text.sys_select)
-*(.text.vm_acct_memory)
-*(.text.vfs_write)
-*(.text.__lru_add_drain)
-*(.text.prio_tree_insert)
-*(.text.generic_file_aio_read)
-*(.text.vma_merge)
-*(.text.block_write_full_page)
-*(.text.__page_set_anon_rmap)
-*(.text.apic_timer_interrupt)
-*(.text.release_console_sem)
-*(.text.sys_write)
-*(.text.sys_brk)
-*(.text.dup_mm)
-*(.text.read_current_timer)
-*(.text.ll_rw_block)
-*(.text.blk_rq_map_sg)
-*(.text.dbg_userword)
-*(.text.__block_commit_write)
-*(.text.cache_grow)
-*(.text.copy_strings)
-*(.text.release_task)
-*(.text.do_sync_write)
-*(.text.unlock_page)
-*(.text.load_elf_binary)
-*(.text.__follow_mount)
-*(.text.__getblk)
-*(.text.do_sys_open)
-*(.text.current_kernel_time)
-*(.text.call_rcu)
-*(.text.write_chan)
-*(.text.vsnprintf)
-*(.text.dummy_inode_setsecurity)
-*(.text.submit_bh)
-*(.text.poll_freewait)
-*(.text.bio_alloc_bioset)
-*(.text.skb_clone)
-*(.text.page_waitqueue)
-*(.text.__mutex_lock_interruptible_slowpath)
-*(.text.get_index)
-*(.text.csum_partial_copy_generic)
-*(.text.bad_range)
-*(.text.remove_vma)
-*(.text.cp_new_stat)
-*(.text.alloc_arraycache)
-*(.text.test_clear_page_writeback)
-*(.text.strsep)
-*(.text.open_namei)
-*(.text._raw_read_unlock)
-*(.text.get_vma_policy)
-*(.text.__down_write_trylock)
-*(.text.find_get_pages)
-*(.text.tcp_rcv_established)
-*(.text.generic_make_request)
-*(.text.__block_write_full_page)
-*(.text.cfq_set_request)
-*(.text.sys_inotify_init)
-*(.text.split_vma)
-*(.text.__mod_timer)
-*(.text.get_options)
-*(.text.vma_link)
-*(.text.mpage_writepages)
-*(.text.truncate_complete_page)
-*(.text.tcp_recvmsg)
-*(.text.sigprocmask)
-*(.text.filemap_populate)
-*(.text.sys_close)
-*(.text.inotify_dev_queue_event)
-*(.text.do_task_stat)
-*(.text.__dentry_open)
-*(.text.unlink_file_vma)
-*(.text.__pollwait)
-*(.text.packet_rcv_spkt)
-*(.text.drop_buffers)
-*(.text.free_pgtables)
-*(.text.generic_file_direct_write)
-*(.text.copy_process)
-*(.text.netif_receive_skb)
-*(.text.dnotify_flush)
-*(.text.print_bad_pte)
-*(.text.anon_vma_unlink)
-*(.text.sys_mprotect)
-*(.text.sync_sb_inodes)
-*(.text.find_inode_fast)
-*(.text.dummy_inode_readlink)
-*(.text.putname)
-*(.text.init_smp_flush)
-*(.text.dbg_redzone2)
-*(.text.sk_run_filter)
-*(.text.may_expand_vm)
-*(.text.generic_file_aio_write)
-*(.text.find_next_zero_bit)
-*(.text.file_kill)
-*(.text.audit_getname)
-*(.text.arch_unmap_area_topdown)
-*(.text.alloc_page_vma)
-*(.text.tcp_transmit_skb)
-*(.text.rb_next)
-*(.text.dbg_redzone1)
-*(.text.generic_file_mmap)
-*(.text.vfs_fstat)
-*(.text.sys_time)
-*(.text.page_lock_anon_vma)
-*(.text.get_unmapped_area)
-*(.text.remote_llseek)
-*(.text.__up_read)
-*(.text.fd_install)
-*(.text.eventpoll_init_file)
-*(.text.dma_alloc_coherent)
-*(.text.create_empty_buffers)
-*(.text.__mutex_unlock_slowpath)
-*(.text.dup_fd)
-*(.text.d_alloc)
-*(.text.tty_ldisc_try)
-*(.text.sys_stime)
-*(.text.__rb_rotate_right)
-*(.text.d_validate)
-*(.text.rb_erase)
-*(.text.path_release)
-*(.text.memmove)
-*(.text.invalidate_complete_page)
-*(.text.clear_inode)
-*(.text.cache_estimate)
-*(.text.alloc_buffer_head)
-*(.text.smp_call_function_interrupt)
-*(.text.flush_tlb_others)
-*(.text.file_move)
-*(.text.balance_dirty_pages_ratelimited)
-*(.text.vma_prio_tree_add)
-*(.text.timespec_trunc)
-*(.text.mempool_alloc)
-*(.text.iget_locked)
-*(.text.d_alloc_root)
-*(.text.cpuset_populate_dir)
-*(.text.anon_vma_prepare)
-*(.text.sys_newstat)
-*(.text.alloc_page_interleave)
-*(.text.__path_lookup_intent_open)
-*(.text.__pagevec_free)
-*(.text.inode_init_once)
-*(.text.free_vfsmnt)
-*(.text.__user_walk_fd)
-*(.text.cfq_idle_slice_timer)
-*(.text.sys_mmap)
-*(.text.sys_llseek)
-*(.text.prio_tree_remove)
-*(.text.filp_close)
-*(.text.file_permission)
-*(.text.vma_prio_tree_remove)
-*(.text.tcp_ack)
-*(.text.nameidata_to_filp)
-*(.text.sys_lseek)
-*(.text.percpu_counter_mod)
-*(.text.igrab)
-*(.text.__bread)
-*(.text.alloc_inode)
-*(.text.filldir)
-*(.text.__rb_rotate_left)
-*(.text.irq_affinity_write_proc)
-*(.text.init_request_from_bio)
-*(.text.find_or_create_page)
-*(.text.tty_poll)
-*(.text.tcp_sendmsg)
-*(.text.ide_wait_stat)
-*(.text.free_buffer_head)
-*(.text.flush_signal_handlers)
-*(.text.tcp_v4_rcv)
-*(.text.nr_blockdev_pages)
-*(.text.locks_remove_flock)
-*(.text.__iowrite32_copy)
-*(.text.do_filp_open)
-*(.text.try_to_release_page)
-*(.text.page_add_new_anon_rmap)
-*(.text.kmem_cache_size)
-*(.text.eth_type_trans)
-*(.text.try_to_free_buffers)
-*(.text.schedule_tail)
-*(.text.proc_lookup)
-*(.text.no_llseek)
-*(.text.kfree_skbmem)
-*(.text.do_wait)
-*(.text.do_mpage_readpage)
-*(.text.vfs_stat_fd)
-*(.text.tty_write)
-*(.text.705)
-*(.text.sync_page)
-*(.text.__remove_shared_vm_struct)
-*(.text.__kfree_skb)
-*(.text.sock_poll)
-*(.text.get_request_wait)
-*(.text.do_sigaction)
-*(.text.do_brk)
-*(.text.tcp_event_data_recv)
-*(.text.read_chan)
-*(.text.pipe_writev)
-*(.text.__emul_lookup_dentry)
-*(.text.rtc_get_rtc_time)
-*(.text.print_objinfo)
-*(.text.file_update_time)
-*(.text.do_signal)
-*(.text.disable_8259A_irq)
-*(.text.blk_queue_bounce)
-*(.text.__anon_vma_link)
-*(.text.__vma_link)
-*(.text.vfs_rename)
-*(.text.sys_newlstat)
-*(.text.sys_newfstat)
-*(.text.sys_mknod)
-*(.text.__show_regs)
-*(.text.iput)
-*(.text.get_signal_to_deliver)
-*(.text.flush_tlb_page)
-*(.text.debug_mutex_wake_waiter)
-*(.text.copy_thread)
-*(.text.clear_page_dirty_for_io)
-*(.text.buffer_io_error)
-*(.text.vfs_permission)
-*(.text.truncate_inode_pages_range)
-*(.text.sys_recvfrom)
-*(.text.remove_suid)
-*(.text.mark_buffer_dirty)
-*(.text.local_bh_enable)
-*(.text.get_zeroed_page)
-*(.text.get_vmalloc_info)
-*(.text.flush_old_exec)
-*(.text.dummy_inode_permission)
-*(.text.__bio_add_page)
-*(.text.prio_tree_replace)
-*(.text.notify_change)
-*(.text.mntput_no_expire)
-*(.text.fput)
-*(.text.__end_that_request_first)
-*(.text.wake_up_bit)
-*(.text.unuse_mm)
-*(.text.shrink_icache_memory)
-*(.text.sched_balance_self)
-*(.text.__pmd_alloc)
-*(.text.pipe_poll)
-*(.text.normal_poll)
-*(.text.__free_pages)
-*(.text.follow_mount)
-*(.text.cdrom_start_packet_command)
-*(.text.blk_recount_segments)
-*(.text.bio_put)
-*(.text.__alloc_skb)
-*(.text.__wake_up)
-*(.text.vm_stat_account)
-*(.text.sys_fcntl)
-*(.text.sys_fadvise64)
-*(.text._raw_write_unlock)
-*(.text.__pud_alloc)
-*(.text.alloc_page_buffers)
-*(.text.vfs_llseek)
-*(.text.sockfd_lookup)
-*(.text._raw_write_lock)
-*(.text.put_compound_page)
-*(.text.prune_dcache)
-*(.text.pipe_readv)
-*(.text.mempool_free)
-*(.text.make_ahead_window)
-*(.text.lru_add_drain)
-*(.text.constant_test_bit)
-*(.text.__clear_user)
-*(.text.arch_unmap_area)
-*(.text.anon_vma_link)
-*(.text.sys_chroot)
-*(.text.setup_arg_pages)
-*(.text.radix_tree_preload)
-*(.text.init_rwsem)
-*(.text.generic_osync_inode)
-*(.text.generic_delete_inode)
-*(.text.do_sys_poll)
-*(.text.dev_queue_xmit)
-*(.text.default_llseek)
-*(.text.__writeback_single_inode)
-*(.text.vfs_ioctl)
-*(.text.__up_write)
-*(.text.unix_poll)
-*(.text.sys_rt_sigprocmask)
-*(.text.sock_recvmsg)
-*(.text.recalc_bh_state)
-*(.text.__put_unused_fd)
-*(.text.process_backlog)
-*(.text.locks_remove_posix)
-*(.text.lease_modify)
-*(.text.expand_files)
-*(.text.end_buffer_read_nobh)
-*(.text.d_splice_alias)
-*(.text.debug_mutex_init_waiter)
-*(.text.copy_from_user)
-*(.text.cap_vm_enough_memory)
-*(.text.show_vfsmnt)
-*(.text.release_sock)
-*(.text.pfifo_fast_enqueue)
-*(.text.half_md4_transform)
-*(.text.fs_may_remount_ro)
-*(.text.do_fork)
-*(.text.copy_hugetlb_page_range)
-*(.text.cache_free_debugcheck)
-*(.text.__tcp_select_window)
-*(.text.task_handoff_register)
-*(.text.sys_open)
-*(.text.strlcpy)
-*(.text.skb_copy_datagram_iovec)
-*(.text.set_up_list3s)
-*(.text.release_open_intent)
-*(.text.qdisc_restart)
-*(.text.n_tty_chars_in_buffer)
-*(.text.inode_change_ok)
-*(.text.__downgrade_write)
-*(.text.debug_mutex_unlock)
-*(.text.add_timer_randomness)
-*(.text.sock_common_recvmsg)
-*(.text.set_bh_page)
-*(.text.printk_lock)
-*(.text.path_release_on_umount)
-*(.text.ip_output)
-*(.text.ide_build_dmatable)
-*(.text.__get_user_8)
-*(.text.end_buffer_read_sync)
-*(.text.__d_path)
-*(.text.d_move)
-*(.text.del_timer)
-*(.text.constant_test_bit)
-*(.text.blockable_page_cache_readahead)
-*(.text.tty_read)
-*(.text.sys_readlink)
-*(.text.sys_faccessat)
-*(.text.read_swap_cache_async)
-*(.text.pty_write_room)
-*(.text.page_address_in_vma)
-*(.text.kthread)
-*(.text.cfq_exit_io_context)
-*(.text.__tcp_push_pending_frames)
-*(.text.sys_pipe)
-*(.text.submit_bio)
-*(.text.pid_revalidate)
-*(.text.page_referenced_file)
-*(.text.lock_sock)
-*(.text.get_page_state_node)
-*(.text.generic_block_bmap)
-*(.text.do_setitimer)
-*(.text.dev_queue_xmit_nit)
-*(.text.copy_from_read_buf)
-*(.text.__const_udelay)
-*(.text.console_conditional_schedule)
-*(.text.wake_up_new_task)
-*(.text.wait_for_completion_interruptible)
-*(.text.tcp_rcv_rtt_update)
-*(.text.sys_mlockall)
-*(.text.set_fs_altroot)
-*(.text.schedule_timeout)
-*(.text.nr_free_pagecache_pages)
-*(.text.nf_iterate)
-*(.text.mapping_tagged)
-*(.text.ip_queue_xmit)
-*(.text.ip_local_deliver)
-*(.text.follow_page)
-*(.text.elf_map)
-*(.text.dummy_file_permission)
-*(.text.dispose_list)
-*(.text.dentry_open)
-*(.text.dentry_iput)
-*(.text.bio_alloc)
-*(.text.wait_on_page_bit)
-*(.text.vfs_readdir)
-*(.text.vfs_lstat)
-*(.text.seq_escape)
-*(.text.__posix_lock_file)
-*(.text.mm_release)
-*(.text.kref_put)
-*(.text.ip_rcv)
-*(.text.__iget)
-*(.text.free_pages)
-*(.text.find_mergeable_anon_vma)
-*(.text.find_extend_vma)
-*(.text.dummy_inode_listsecurity)
-*(.text.bio_add_page)
-*(.text.__vm_enough_memory)
-*(.text.vfs_stat)
-*(.text.tty_paranoia_check)
-*(.text.tcp_read_sock)
-*(.text.tcp_data_queue)
-*(.text.sys_uname)
-*(.text.sys_renameat)
-*(.text.__strncpy_from_user)
-*(.text.__mutex_init)
-*(.text.__lookup_hash)
-*(.text.kref_get)
-*(.text.ip_route_input)
-*(.text.__insert_inode_hash)
-*(.text.do_sock_write)
-*(.text.blk_done_softirq)
-*(.text.__wake_up_sync)
-*(.text.__vma_link_rb)
-*(.text.tty_ioctl)
-*(.text.tracesys)
-*(.text.sys_getdents)
-*(.text.sys_dup)
-*(.text.stub_execve)
-*(.text.sha_transform)
-*(.text.radix_tree_tag_clear)
-*(.text.put_unused_fd)
-*(.text.put_files_struct)
-*(.text.mpage_readpages)
-*(.text.may_delete)
-*(.text.kmem_cache_create)
-*(.text.ip_mc_output)
-*(.text.interleave_nodes)
-*(.text.groups_search)
-*(.text.generic_drop_inode)
-*(.text.generic_commit_write)
-*(.text.fcntl_setlk)
-*(.text.exit_mmap)
-*(.text.end_page_writeback)
-*(.text.__d_rehash)
-*(.text.debug_mutex_free_waiter)
-*(.text.csum_ipv6_magic)
-*(.text.count)
-*(.text.cleanup_rbuf)
-*(.text.check_spinlock_acquired_node)
-*(.text.can_vma_merge_after)
-*(.text.bio_endio)
-*(.text.alloc_pidmap)
-*(.text.write_ldt)
-*(.text.vmtruncate_range)
-*(.text.vfs_create)
-*(.text.__user_walk)
-*(.text.update_send_head)
-*(.text.unmap_underlying_metadata)
-*(.text.tty_ldisc_deref)
-*(.text.tcp_setsockopt)
-*(.text.tcp_send_ack)
-*(.text.sys_pause)
-*(.text.sys_gettimeofday)
-*(.text.sync_dirty_buffer)
-*(.text.strncmp)
-*(.text.release_posix_timer)
-*(.text.proc_file_read)
-*(.text.prepare_to_wait)
-*(.text.locks_mandatory_locked)
-*(.text.interruptible_sleep_on_timeout)
-*(.text.inode_sub_bytes)
-*(.text.in_group_p)
-*(.text.hrtimer_try_to_cancel)
-*(.text.filldir64)
-*(.text.fasync_helper)
-*(.text.dummy_sb_pivotroot)
-*(.text.d_lookup)
-*(.text.d_instantiate)
-*(.text.__d_find_alias)
-*(.text.cpu_idle_wait)
-*(.text.cond_resched_lock)
-*(.text.chown_common)
-*(.text.blk_congestion_wait)
-*(.text.activate_page)
-*(.text.unlock_buffer)
-*(.text.tty_wakeup)
-*(.text.tcp_v4_do_rcv)
-*(.text.tcp_current_mss)
-*(.text.sys_openat)
-*(.text.sys_fchdir)
-*(.text.strnlen_user)
-*(.text.strnlen)
-*(.text.strchr)
-*(.text.sock_common_getsockopt)
-*(.text.skb_checksum)
-*(.text.remove_wait_queue)
-*(.text.rb_replace_node)
-*(.text.radix_tree_node_ctor)
-*(.text.pty_chars_in_buffer)
-*(.text.profile_hit)
-*(.text.prio_tree_left)
-*(.text.pgd_clear_bad)
-*(.text.pfifo_fast_dequeue)
-*(.text.page_referenced)
-*(.text.open_exec)
-*(.text.mmput)
-*(.text.mm_init)
-*(.text.__ide_dma_off_quietly)
-*(.text.ide_dma_intr)
-*(.text.hrtimer_start)
-*(.text.get_io_context)
-*(.text.__get_free_pages)
-*(.text.find_first_zero_bit)
-*(.text.file_free_rcu)
-*(.text.dummy_socket_sendmsg)
-*(.text.do_unlinkat)
-*(.text.do_arch_prctl)
-*(.text.destroy_inode)
-*(.text.can_vma_merge_before)
-*(.text.block_sync_page)
-*(.text.block_prepare_write)
-*(.text.bio_init)
-*(.text.arch_ptrace)
-*(.text.wake_up_inode)
-*(.text.wait_on_retry_sync_kiocb)
-*(.text.vma_prio_tree_next)
-*(.text.tcp_rcv_space_adjust)
-*(.text.__tcp_ack_snd_check)
-*(.text.sys_utime)
-*(.text.sys_recvmsg)
-*(.text.sys_mremap)
-*(.text.sys_bdflush)
-*(.text.sleep_on)
-*(.text.set_page_dirty_lock)
-*(.text.seq_path)
-*(.text.schedule_timeout_interruptible)
-*(.text.sched_fork)
-*(.text.rt_run_flush)
-*(.text.profile_munmap)
-*(.text.prepare_binprm)
-*(.text.__pagevec_release_nonlru)
-*(.text.m_show)
-*(.text.lookup_mnt)
-*(.text.__lookup_mnt)
-*(.text.lock_timer_base)
-*(.text.is_subdir)
-*(.text.invalidate_bh_lru)
-*(.text.init_buffer_head)
-*(.text.ifind_fast)
-*(.text.ide_dma_start)
-*(.text.__get_page_state)
-*(.text.flock_to_posix_lock)
-*(.text.__find_symbol)
-*(.text.do_futex)
-*(.text.do_execve)
-*(.text.dirty_writeback_centisecs_handler)
-*(.text.dev_watchdog)
-*(.text.can_share_swap_page)
-*(.text.blkdev_put)
-*(.text.bio_get_nr_vecs)
-*(.text.xfrm_compile_policy)
-*(.text.vma_prio_tree_insert)
-*(.text.vfs_lstat_fd)
-*(.text.__user_path_lookup_open)
-*(.text.thread_return)
-*(.text.tcp_send_delayed_ack)
-*(.text.sock_def_error_report)
-*(.text.shrink_slab)
-*(.text.serial_out)
-*(.text.seq_read)
-*(.text.secure_ip_id)
-*(.text.search_binary_handler)
-*(.text.proc_pid_unhash)
-*(.text.pagevec_lookup)
-*(.text.new_inode)
-*(.text.memcpy_toiovec)
-*(.text.locks_free_lock)
-*(.text.__lock_page)
-*(.text.__lock_buffer)
-*(.text.load_module)
-*(.text.is_bad_inode)
-*(.text.invalidate_inode_buffers)
-*(.text.insert_vm_struct)
-*(.text.inode_setattr)
-*(.text.inode_add_bytes)
-*(.text.ide_read_24)
-*(.text.ide_get_error_location)
-*(.text.ide_do_drive_cmd)
-*(.text.get_locked_pte)
-*(.text.get_filesystem_list)
-*(.text.generic_file_open)
-*(.text.follow_down)
-*(.text.find_next_bit)
-*(.text.__find_first_bit)
-*(.text.exit_mm)
-*(.text.exec_keys)
-*(.text.end_buffer_write_sync)
-*(.text.end_bio_bh_io_sync)
-*(.text.dummy_socket_shutdown)
-*(.text.d_rehash)
-*(.text.d_path)
-*(.text.do_ioctl)
-*(.text.dget_locked)
-*(.text.copy_thread_group_keys)
-*(.text.cdrom_end_request)
-*(.text.cap_bprm_apply_creds)
-*(.text.blk_rq_bio_prep)
-*(.text.__bitmap_intersects)
-*(.text.bio_phys_segments)
-*(.text.bio_free)
-*(.text.arch_get_unmapped_area_topdown)
-*(.text.writeback_in_progress)
-*(.text.vfs_follow_link)
-*(.text.tcp_rcv_state_process)
-*(.text.tcp_check_space)
-*(.text.sys_stat)
-*(.text.sys_rt_sigreturn)
-*(.text.sys_rt_sigaction)
-*(.text.sys_remap_file_pages)
-*(.text.sys_pwrite64)
-*(.text.sys_fchownat)
-*(.text.sys_fchmodat)
-*(.text.strncat)
-*(.text.strlcat)
-*(.text.strcmp)
-*(.text.steal_locks)
-*(.text.sock_create)
-*(.text.sk_stream_rfree)
-*(.text.sk_stream_mem_schedule)
-*(.text.skip_atoi)
-*(.text.sk_alloc)
-*(.text.show_stat)
-*(.text.set_fs_pwd)
-*(.text.set_binfmt)
-*(.text.pty_unthrottle)
-*(.text.proc_symlink)
-*(.text.pipe_release)
-*(.text.pageout)
-*(.text.n_tty_write_wakeup)
-*(.text.n_tty_ioctl)
-*(.text.nr_free_zone_pages)
-*(.text.migration_thread)
-*(.text.mempool_free_slab)
-*(.text.meminfo_read_proc)
-*(.text.max_sane_readahead)
-*(.text.lru_cache_add)
-*(.text.kill_fasync)
-*(.text.kernel_read)
-*(.text.invalidate_mapping_pages)
-*(.text.inode_has_buffers)
-*(.text.init_once)
-*(.text.inet_sendmsg)
-*(.text.idedisk_issue_flush)
-*(.text.generic_file_write)
-*(.text.free_more_memory)
-*(.text.__free_fdtable)
-*(.text.filp_dtor)
-*(.text.exit_sem)
-*(.text.exit_itimers)
-*(.text.error_interrupt)
-*(.text.end_buffer_async_write)
-*(.text.eligible_child)
-*(.text.elf_map)
-*(.text.dump_task_regs)
-*(.text.dummy_task_setscheduler)
-*(.text.dummy_socket_accept)
-*(.text.dummy_file_free_security)
-*(.text.__down_read)
-*(.text.do_sock_read)
-*(.text.do_sigaltstack)
-*(.text.do_mremap)
-*(.text.current_io_context)
-*(.text.cpu_swap_callback)
-*(.text.copy_vma)
-*(.text.cap_bprm_set_security)
-*(.text.blk_insert_request)
-*(.text.bio_map_kern_endio)
-*(.text.bio_hw_segments)
-*(.text.bictcp_cong_avoid)
-*(.text.add_interrupt_randomness)
-*(.text.wait_for_completion)
-*(.text.version_read_proc)
-*(.text.unix_write_space)
-*(.text.tty_ldisc_ref_wait)
-*(.text.tty_ldisc_put)
-*(.text.try_to_wake_up)
-*(.text.tcp_v4_tw_remember_stamp)
-*(.text.tcp_try_undo_dsack)
-*(.text.tcp_may_send_now)
-*(.text.sys_waitid)
-*(.text.sys_sched_getparam)
-*(.text.sys_getppid)
-*(.text.sys_getcwd)
-*(.text.sys_dup2)
-*(.text.sys_chmod)
-*(.text.sys_chdir)
-*(.text.sprintf)
-*(.text.sock_wfree)
-*(.text.sock_aio_write)
-*(.text.skb_drop_fraglist)
-*(.text.skb_dequeue)
-*(.text.set_close_on_exec)
-*(.text.set_brk)
-*(.text.seq_puts)
-*(.text.SELECT_DRIVE)
-*(.text.sched_exec)
-*(.text.return_EIO)
-*(.text.remove_from_page_cache)
-*(.text.rcu_start_batch)
-*(.text.__put_task_struct)
-*(.text.proc_pid_readdir)
-*(.text.proc_get_inode)
-*(.text.prepare_to_wait_exclusive)
-*(.text.pipe_wait)
-*(.text.pipe_new)
-*(.text.pdflush_operation)
-*(.text.__pagevec_release)
-*(.text.pagevec_lookup_tag)
-*(.text.packet_rcv)
-*(.text.n_tty_set_room)
-*(.text.nr_free_pages)
-*(.text.__net_timestamp)
-*(.text.mpage_end_io_read)
-*(.text.mod_timer)
-*(.text.__memcpy)
-*(.text.mb_cache_shrink_fn)
-*(.text.lock_rename)
-*(.text.kstrdup)
-*(.text.is_ignored)
-*(.text.int_very_careful)
-*(.text.inotify_inode_is_dead)
-*(.text.inotify_get_cookie)
-*(.text.inode_get_bytes)
-*(.text.init_timer)
-*(.text.init_dev)
-*(.text.inet_getname)
-*(.text.ide_map_sg)
-*(.text.__ide_dma_end)
-*(.text.hrtimer_get_remaining)
-*(.text.get_task_mm)
-*(.text.get_random_int)
-*(.text.free_pipe_info)
-*(.text.filemap_write_and_wait_range)
-*(.text.exit_thread)
-*(.text.enter_idle)
-*(.text.end_that_request_first)
-*(.text.end_8259A_irq)
-*(.text.dummy_file_alloc_security)
-*(.text.do_group_exit)
-*(.text.debug_mutex_init)
-*(.text.cpuset_exit)
-*(.text.cpu_idle)
-*(.text.copy_semundo)
-*(.text.copy_files)
-*(.text.chrdev_open)
-*(.text.cdrom_transfer_packet_command)
-*(.text.cdrom_mode_sense)
-*(.text.blk_phys_contig_segment)
-*(.text.blk_get_queue)
-*(.text.bio_split)
-*(.text.audit_alloc)
-*(.text.anon_pipe_buf_release)
-*(.text.add_wait_queue_exclusive)
-*(.text.add_wait_queue)
-*(.text.acct_process)
-*(.text.account)
-*(.text.zeromap_page_range)
-*(.text.yield)
-*(.text.writeback_acquire)
-*(.text.worker_thread)
-*(.text.wait_on_page_writeback_range)
-*(.text.__wait_on_buffer)
-*(.text.vscnprintf)
-*(.text.vmalloc_to_pfn)
-*(.text.vgacon_save_screen)
-*(.text.vfs_unlink)
-*(.text.vfs_rmdir)
-*(.text.unregister_md_personality)
-*(.text.unlock_new_inode)
-*(.text.unix_stream_sendmsg)
-*(.text.unix_stream_recvmsg)
-*(.text.unhash_process)
-*(.text.udp_v4_lookup_longway)
-*(.text.tty_ldisc_flush)
-*(.text.tty_ldisc_enable)
-*(.text.tty_hung_up_p)
-*(.text.tty_buffer_free_all)
-*(.text.tso_fragment)
-*(.text.try_to_del_timer_sync)
-*(.text.tcp_v4_err)
-*(.text.tcp_unhash)
-*(.text.tcp_seq_next)
-*(.text.tcp_select_initial_window)
-*(.text.tcp_sacktag_write_queue)
-*(.text.tcp_cwnd_validate)
-*(.text.sys_vhangup)
-*(.text.sys_uselib)
-*(.text.sys_symlink)
-*(.text.sys_signal)
-*(.text.sys_poll)
-*(.text.sys_mount)
-*(.text.sys_kill)
-*(.text.sys_ioctl)
-*(.text.sys_inotify_add_watch)
-*(.text.sys_getuid)
-*(.text.sys_getrlimit)
-*(.text.sys_getitimer)
-*(.text.sys_getgroups)
-*(.text.sys_ftruncate)
-*(.text.sysfs_lookup)
-*(.text.sys_exit_group)
-*(.text.stub_fork)
-*(.text.sscanf)
-*(.text.sock_map_fd)
-*(.text.sock_get_timestamp)
-*(.text.__sock_create)
-*(.text.smp_call_function_single)
-*(.text.sk_stop_timer)
-*(.text.skb_copy_and_csum_datagram)
-*(.text.__skb_checksum_complete)
-*(.text.single_next)
-*(.text.sigqueue_alloc)
-*(.text.shrink_dcache_parent)
-*(.text.select_idle_routine)
-*(.text.run_workqueue)
-*(.text.run_local_timers)
-*(.text.remove_inode_hash)
-*(.text.remove_dquot_ref)
-*(.text.register_binfmt)
-*(.text.read_cache_pages)
-*(.text.rb_last)
-*(.text.pty_open)
-*(.text.proc_root_readdir)
-*(.text.proc_pid_flush)
-*(.text.proc_pident_lookup)
-*(.text.proc_fill_super)
-*(.text.proc_exe_link)
-*(.text.posix_locks_deadlock)
-*(.text.pipe_iov_copy_from_user)
-*(.text.opost)
-*(.text.nf_register_hook)
-*(.text.netif_rx_ni)
-*(.text.m_start)
-*(.text.mpage_writepage)
-*(.text.mm_alloc)
-*(.text.memory_open)
-*(.text.mark_buffer_async_write)
-*(.text.lru_add_drain_all)
-*(.text.locks_init_lock)
-*(.text.locks_delete_lock)
-*(.text.lock_hrtimer_base)
-*(.text.load_script)
-*(.text.__kill_fasync)
-*(.text.ip_mc_sf_allow)
-*(.text.__ioremap)
-*(.text.int_with_check)
-*(.text.int_sqrt)
-*(.text.install_thread_keyring)
-*(.text.init_page_buffers)
-*(.text.inet_sock_destruct)
-*(.text.idle_notifier_register)
-*(.text.ide_execute_command)
-*(.text.ide_end_drive_cmd)
-*(.text.__ide_dma_host_on)
-*(.text.hrtimer_run_queues)
-*(.text.hpet_mask_rtc_irq_bit)
-*(.text.__get_zone_counts)
-*(.text.get_zone_counts)
-*(.text.get_write_access)
-*(.text.get_fs_struct)
-*(.text.get_dirty_limits)
-*(.text.generic_readlink)
-*(.text.free_hot_page)
-*(.text.finish_wait)
-*(.text.find_inode)
-*(.text.find_first_bit)
-*(.text.__filemap_fdatawrite_range)
-*(.text.__filemap_copy_from_user_iovec)
-*(.text.exit_aio)
-*(.text.elv_set_request)
-*(.text.elv_former_request)
-*(.text.dup_namespace)
-*(.text.dupfd)
-*(.text.dummy_socket_getsockopt)
-*(.text.dummy_sb_post_mountroot)
-*(.text.dummy_quotactl)
-*(.text.dummy_inode_rename)
-*(.text.__do_SAK)
-*(.text.do_pipe)
-*(.text.do_fsync)
-*(.text.d_instantiate_unique)
-*(.text.d_find_alias)
-*(.text.deny_write_access)
-*(.text.dentry_unhash)
-*(.text.d_delete)
-*(.text.datagram_poll)
-*(.text.cpuset_fork)
-*(.text.cpuid_read)
-*(.text.copy_namespace)
-*(.text.cond_resched)
-*(.text.check_version)
-*(.text.__change_page_attr)
-*(.text.cfq_slab_kill)
-*(.text.cfq_completed_request)
-*(.text.cdrom_pc_intr)
-*(.text.cdrom_decode_status)
-*(.text.cap_capset_check)
-*(.text.blk_put_request)
-*(.text.bio_fs_destructor)
-*(.text.bictcp_min_cwnd)
-*(.text.alloc_chrdev_region)
-*(.text.add_element)
-*(.text.acct_update_integrals)
-*(.text.write_boundary_block)
-*(.text.writeback_release)
-*(.text.writeback_inodes)
-*(.text.wake_up_state)
-*(.text.__wake_up_locked)
-*(.text.wake_futex)
-*(.text.wait_task_inactive)
-*(.text.__wait_on_freeing_inode)
-*(.text.wait_noreap_copyout)
-*(.text.vmstat_start)
-*(.text.vgacon_do_font_op)
-*(.text.vfs_readv)
-*(.text.vfs_quota_sync)
-*(.text.update_queue)
-*(.text.unshare_files)
-*(.text.unmap_vm_area)
-*(.text.unix_socketpair)
-*(.text.unix_release_sock)
-*(.text.unix_detach_fds)
-*(.text.unix_create1)
-*(.text.unix_bind)
-*(.text.udp_sendmsg)
-*(.text.udp_rcv)
-*(.text.udp_queue_rcv_skb)
-*(.text.uart_write)
-*(.text.uart_startup)
-*(.text.uart_open)
-*(.text.tty_vhangup)
-*(.text.tty_termios_baud_rate)
-*(.text.tty_release)
-*(.text.tty_ldisc_ref)
-*(.text.throttle_vm_writeout)
-*(.text.058)
-*(.text.tcp_xmit_probe_skb)
-*(.text.tcp_v4_send_check)
-*(.text.tcp_v4_destroy_sock)
-*(.text.tcp_sync_mss)
-*(.text.tcp_snd_test)
-*(.text.tcp_slow_start)
-*(.text.tcp_send_fin)
-*(.text.tcp_rtt_estimator)
-*(.text.tcp_parse_options)
-*(.text.tcp_ioctl)
-*(.text.tcp_init_tso_segs)
-*(.text.tcp_init_cwnd)
-*(.text.tcp_getsockopt)
-*(.text.tcp_fin)
-*(.text.tcp_connect)
-*(.text.tcp_cong_avoid)
-*(.text.__tcp_checksum_complete_user)
-*(.text.task_dumpable)
-*(.text.sys_wait4)
-*(.text.sys_utimes)
-*(.text.sys_symlinkat)
-*(.text.sys_socketpair)
-*(.text.sys_rmdir)
-*(.text.sys_readahead)
-*(.text.sys_nanosleep)
-*(.text.sys_linkat)
-*(.text.sys_fstat)
-*(.text.sysfs_readdir)
-*(.text.sys_execve)
-*(.text.sysenter_tracesys)
-*(.text.sys_chown)
-*(.text.stub_clone)
-*(.text.strrchr)
-*(.text.strncpy)
-*(.text.stopmachine_set_state)
-*(.text.sock_sendmsg)
-*(.text.sock_release)
-*(.text.sock_fasync)
-*(.text.sock_close)
-*(.text.sk_stream_write_space)
-*(.text.sk_reset_timer)
-*(.text.skb_split)
-*(.text.skb_recv_datagram)
-*(.text.skb_queue_tail)
-*(.text.sk_attach_filter)
-*(.text.si_swapinfo)
-*(.text.simple_strtoll)
-*(.text.set_termios)
-*(.text.set_task_comm)
-*(.text.set_shrinker)
-*(.text.set_normalized_timespec)
-*(.text.set_brk)
-*(.text.serial_in)
-*(.text.seq_printf)
-*(.text.secure_dccp_sequence_number)
-*(.text.rwlock_bug)
-*(.text.rt_hash_code)
-*(.text.__rta_fill)
-*(.text.__request_resource)
-*(.text.relocate_new_kernel)
-*(.text.release_thread)
-*(.text.release_mem)
-*(.text.rb_prev)
-*(.text.rb_first)
-*(.text.random_poll)
-*(.text.__put_super_and_need_restart)
-*(.text.pty_write)
-*(.text.ptrace_stop)
-*(.text.proc_self_readlink)
-*(.text.proc_root_lookup)
-*(.text.proc_root_link)
-*(.text.proc_pid_make_inode)
-*(.text.proc_pid_attr_write)
-*(.text.proc_lookupfd)
-*(.text.proc_delete_inode)
-*(.text.posix_same_owner)
-*(.text.posix_block_lock)
-*(.text.poll_initwait)
-*(.text.pipe_write)
-*(.text.pipe_read_fasync)
-*(.text.pipe_ioctl)
-*(.text.pdflush)
-*(.text.pci_user_read_config_dword)
-*(.text.page_readlink)
-*(.text.null_lseek)
-*(.text.nf_hook_slow)
-*(.text.netlink_sock_destruct)
-*(.text.netlink_broadcast)
-*(.text.neigh_resolve_output)
-*(.text.name_to_int)
-*(.text.mwait_idle)
-*(.text.mutex_trylock)
-*(.text.mutex_debug_check_no_locks_held)
-*(.text.m_stop)
-*(.text.mpage_end_io_write)
-*(.text.mpage_alloc)
-*(.text.move_page_tables)
-*(.text.mounts_open)
-*(.text.__memset)
-*(.text.memcpy_fromiovec)
-*(.text.make_8259A_irq)
-*(.text.lookup_user_key_possessed)
-*(.text.lookup_create)
-*(.text.locks_insert_lock)
-*(.text.locks_alloc_lock)
-*(.text.kthread_should_stop)
-*(.text.kswapd)
-*(.text.kobject_uevent)
-*(.text.kobject_get_path)
-*(.text.kobject_get)
-*(.text.klist_children_put)
-*(.text.__ip_route_output_key)
-*(.text.ip_flush_pending_frames)
-*(.text.ip_compute_csum)
-*(.text.ip_append_data)
-*(.text.ioc_set_batching)
-*(.text.invalidate_inode_pages)
-*(.text.__invalidate_device)
-*(.text.install_arg_page)
-*(.text.in_sched_functions)
-*(.text.inotify_unmount_inodes)
-*(.text.init_once)
-*(.text.init_cdrom_command)
-*(.text.inet_stream_connect)
-*(.text.inet_sk_rebuild_header)
-*(.text.inet_csk_addr2sockaddr)
-*(.text.inet_create)
-*(.text.ifind)
-*(.text.ide_setup_dma)
-*(.text.ide_outsw)
-*(.text.ide_fixstring)
-*(.text.ide_dma_setup)
-*(.text.ide_cdrom_packet)
-*(.text.ide_cd_put)
-*(.text.ide_build_sglist)
-*(.text.i8259A_shutdown)
-*(.text.hung_up_tty_ioctl)
-*(.text.hrtimer_nanosleep)
-*(.text.hrtimer_init)
-*(.text.hrtimer_cancel)
-*(.text.hash_futex)
-*(.text.group_send_sig_info)
-*(.text.grab_cache_page_nowait)
-*(.text.get_wchan)
-*(.text.get_stack)
-*(.text.get_page_state)
-*(.text.getnstimeofday)
-*(.text.get_node)
-*(.text.get_kprobe)
-*(.text.generic_unplug_device)
-*(.text.free_task)
-*(.text.frag_show)
-*(.text.find_next_zero_string)
-*(.text.filp_open)
-*(.text.fillonedir)
-*(.text.exit_io_context)
-*(.text.exit_idle)
-*(.text.exact_lock)
-*(.text.eth_header)
-*(.text.dummy_unregister_security)
-*(.text.dummy_socket_post_create)
-*(.text.dummy_socket_listen)
-*(.text.dummy_quota_on)
-*(.text.dummy_inode_follow_link)
-*(.text.dummy_file_receive)
-*(.text.dummy_file_mprotect)
-*(.text.dummy_file_lock)
-*(.text.dummy_file_ioctl)
-*(.text.dummy_bprm_post_apply_creds)
-*(.text.do_writepages)
-*(.text.__down_interruptible)
-*(.text.do_notify_resume)
-*(.text.do_acct_process)
-*(.text.del_timer_sync)
-*(.text.default_rebuild_header)
-*(.text.d_callback)
-*(.text.dcache_readdir)
-*(.text.ctrl_dumpfamily)
-*(.text.cpuset_rmdir)
-*(.text.copy_strings_kernel)
-*(.text.con_write_room)
-*(.text.complete_all)
-*(.text.collect_sigign_sigcatch)
-*(.text.clear_user)
-*(.text.check_unthrottle)
-*(.text.cdrom_release)
-*(.text.cdrom_newpc_intr)
-*(.text.cdrom_ioctl)
-*(.text.cdrom_check_status)
-*(.text.cdev_put)
-*(.text.cdev_add)
-*(.text.cap_ptrace)
-*(.text.cap_bprm_secureexec)
-*(.text.cache_alloc_refill)
-*(.text.bmap)
-*(.text.blk_run_queue)
-*(.text.blk_queue_dma_alignment)
-*(.text.blk_ordered_req_seq)
-*(.text.blk_backing_dev_unplug)
-*(.text.__bitmap_subset)
-*(.text.__bitmap_and)
-*(.text.bio_unmap_user)
-*(.text.__bforget)
-*(.text.bd_forget)
-*(.text.bad_pipe_w)
-*(.text.bad_get_user)
-*(.text.audit_free)
-*(.text.anon_vma_ctor)
-*(.text.anon_pipe_buf_map)
-*(.text.alloc_sock_iocb)
-*(.text.alloc_fdset)
-*(.text.aio_kick_handler)
-*(.text.__add_entropy_words)
-*(.text.add_disk_randomness)
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index 0b3603a..47496a4 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -11,120 +11,54 @@
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
+#include <linux/module.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>
+#include <asm/genapic.h>
 
-#if defined(CONFIG_ACPI)
+#ifdef 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 };
+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;
+u8 x86_cpu_to_log_apicid[NR_CPUS]	= { [0 ... NR_CPUS-1] = BAD_APICID };
 
-struct genapic *genapic = &apic_flat;
-struct genapic *genapic_force;
+struct genapic __read_mostly *genapic = &apic_flat;
 
 /*
  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
  */
-void __init clustered_apic_check(void)
+void __init setup_apic_routing(void)
 {
-	long i;
-	u8 clusters, max_cluster;
-	u8 id;
-	u8 cluster_cnt[NUM_APIC_CLUSTERS];
-	int max_apic = 0;
-
-	/* genapic selection can be forced because of certain quirks.
-	 */
-	if (genapic_force) {
-		genapic = genapic_force;
-		goto print;
-	}
-
-#if defined(CONFIG_ACPI)
+#ifdef CONFIG_ACPI
 	/*
-	 * Some x86_64 machines use physical APIC mode regardless of how many
-	 * procs/clusters are present (x86_64 ES7000 is an example).
+	 * Quirk: some x86_64 machines can only use physical APIC mode
+	 * regardless of how many processors are present (x86_64 ES7000
+	 * is an example).
 	 */
-	if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
-		if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
-			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) {
+	if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
+			(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
 		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;
+	else
 #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
+	if (cpus_weight(cpu_possible_map) <= 8)
 		genapic = &apic_flat;
-#endif
-	} else
-		genapic = &apic_cluster;
+	else
+		genapic = &apic_physflat;
 
-print:
 	printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
 }
 
-/* Same for both flat and clustered. */
+/* Same for both flat and physical. */
 
 void send_IPI_self(int vector)
 {
diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
deleted file mode 100644
index 73d7630..0000000
--- a/arch/x86_64/kernel/genapic_cluster.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2004 James Cleverdon, IBM.
- * Subject to the GNU Public License, v.2
- *
- * Clustered APIC subarch code.  Up to 255 CPUs, physical delivery.
- * (A more realistic maximum is around 230 CPUs.)
- *
- * 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 <asm/smp.h>
-#include <asm/ipi.h>
-
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116).  So here it goes...
- */
-static void cluster_init_apic_ldr(void)
-{
-	unsigned long val, id;
-	long i, count;
-	u8 lid;
-	u8 my_id = hard_smp_processor_id();
-	u8 my_cluster = APIC_CLUSTER(my_id);
-
-	/* Create logical APIC IDs by counting CPUs already in cluster. */
-	for (count = 0, i = NR_CPUS; --i >= 0; ) {
-		lid = x86_cpu_to_log_apicid[i];
-		if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
-			++count;
-	}
-	/*
-	 * We only have a 4 wide bitmap in cluster mode.  There's no way
-	 * to get above 60 CPUs and still give each one it's own bit.
-	 * But, we're using physical IRQ delivery, so we don't care.
-	 * Use bit 3 for the 4th through Nth CPU in each cluster.
-	 */
-	if (count >= XAPIC_DEST_CPUS_SHIFT)
-		count = 3;
-	id = my_cluster | (1UL << count);
-	x86_cpu_to_log_apicid[smp_processor_id()] = id;
-	apic_write(APIC_DFR, APIC_DFR_CLUSTER);
-	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
-	val |= SET_APIC_LOGICAL_ID(id);
-	apic_write(APIC_LDR, val);
-}
-
-/* Start with all IRQs pointing to boot CPU.  IRQ balancing will shift them. */
-
-static cpumask_t cluster_target_cpus(void)
-{
-	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);
-}
-
-static void cluster_send_IPI_allbutself(int vector)
-{
-	cpumask_t mask = cpu_online_map;
-
-	cpu_clear(smp_processor_id(), mask);
-
-	if (!cpus_empty(mask))
-		cluster_send_IPI_mask(mask, vector);
-}
-
-static void cluster_send_IPI_all(int vector)
-{
-	cluster_send_IPI_mask(cpu_online_map, vector);
-}
-
-static int cluster_apic_id_registered(void)
-{
-	return 1;
-}
-
-static unsigned int cluster_cpu_mask_to_apicid(cpumask_t cpumask)
-{
-	int cpu;
-
-	/*
-	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
-	 * May as well be the first.
-	 */
-	cpu = first_cpu(cpumask);
-	if ((unsigned)cpu < NR_CPUS)
-		return x86_cpu_to_apicid[cpu];
-	else
-		return BAD_APICID;
-}
-
-/* cpuid returns the value latched in the HW at reset, not the APIC ID
- * register's value.  For any box whose BIOS changes APIC IDs, like
- * clustered APIC systems, we must use hard_smp_processor_id.
- *
- * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
- */
-static unsigned int phys_pkg_id(int index_msb)
-{
-	return hard_smp_processor_id() >> index_msb;
-}
-
-struct genapic apic_cluster = {
-	.name = "clustered",
-	.int_delivery_mode = dest_Fixed,
-	.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
-	.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,
-	.send_IPI_allbutself = cluster_send_IPI_allbutself,
-	.send_IPI_mask = cluster_send_IPI_mask,
-	.cpu_mask_to_apicid = cluster_cpu_mask_to_apicid,
-	.phys_pkg_id = phys_pkg_id,
-};
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index 7c01db8..ecb01ee 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -8,6 +8,7 @@
  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
  * James Cleverdon.
  */
+#include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/string.h>
@@ -16,6 +17,7 @@ #include <linux/ctype.h>
 #include <linux/init.h>
 #include <asm/smp.h>
 #include <asm/ipi.h>
+#include <asm/genapic.h>
 
 static cpumask_t flat_target_cpus(void)
 {
@@ -60,31 +62,10 @@ static void flat_init_apic_ldr(void)
 static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
 {
 	unsigned long mask = cpus_addr(cpumask)[0];
-	unsigned long cfg;
 	unsigned long flags;
 
 	local_irq_save(flags);
-
-	/*
-	 * Wait for idle.
-	 */
-	apic_wait_icr_idle();
-
-	/*
-	 * prepare target chip field
-	 */
-	cfg = __prepare_ICR2(mask);
-	apic_write(APIC_ICR2, cfg);
-
-	/*
-	 * program the ICR
-	 */
-	cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL);
-
-	/*
-	 * Send the IPI. The write to APIC_ICR fires this off.
-	 */
-	apic_write(APIC_ICR, cfg);
+	__send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
 	local_irq_restore(flags);
 }
 
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 598a4d0..1fab487 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -5,6 +5,7 @@
  *  Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
  *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
  *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
+ *  Copyright (C) 2005 Eric Biederman <ebiederm@xmission.com>
  */
 
 
@@ -13,97 +14,131 @@ #include <linux/threads.h>
 #include <linux/init.h>
 #include <asm/desc.h>
 #include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/msr.h>
 #include <asm/cache.h>
-	
+
 /* we are not able to switch in one step to the final KERNEL ADRESS SPACE
- * because we need identity-mapped pages on setup so define __START_KERNEL to
- * 0x100000 for this stage
- * 
+ * because we need identity-mapped pages.
+ *
  */
 
 	.text
 	.section .bootstrap.text
-	.code32
-	.globl startup_32
-/* %bx:	 1 if coming from smp trampoline on secondary cpu */ 
-startup_32:
-	
+	.code64
+	.globl startup_64
+startup_64:
+
 	/*
-	 * At this point the CPU runs in 32bit protected mode (CS.D = 1) with
-	 * paging disabled and the point of this file is to switch to 64bit
-	 * long mode with a kernel mapping for kerneland to jump into the
-	 * kernel virtual addresses.
- 	 * There is no stack until we set one up.
+	 * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+	 * and someone has loaded an identity mapped page table
+	 * for us.  These identity mapped page tables map all of the
+	 * kernel pages and possibly all of memory.
+	 *
+	 * %esi holds a physical pointer to real_mode_data.
+	 *
+	 * We come here either directly from a 64bit bootloader, or from
+	 * arch/x86_64/boot/compressed/head.S.
+	 *
+	 * We only come here initially at boot nothing else comes here.
+	 *
+	 * Since we may be loaded at an address different from what we were
+	 * compiled to run at we first fixup the physical addresses in our page
+	 * tables and then reload them.
 	 */
 
-	/* Initialize the %ds segment register */
-	movl $__KERNEL_DS,%eax
-	movl %eax,%ds
-
-	/* Load new GDT with the 64bit segments using 32bit descriptor */
-	lgdt	pGDT32 - __START_KERNEL_map
-
-	/* If the CPU doesn't support CPUID this will double fault.
-	 * Unfortunately it is hard to check for CPUID without a stack. 
+	/* Compute the delta between the address I am compiled to run at and the
+	 * address I am actually running at.
 	 */
-	
-	/* Check if extended functions are implemented */		
-	movl	$0x80000000, %eax
-	cpuid
-	cmpl	$0x80000000, %eax
-	jbe	no_long_mode
-	/* Check if long mode is implemented */
-	mov	$0x80000001, %eax
-	cpuid
-	btl	$29, %edx
-	jnc	no_long_mode
-
-	/*
-	 * Prepare for entering 64bits mode
+	leaq	_text(%rip), %rbp
+	subq	$_text - __START_KERNEL_map, %rbp
+
+	/* Is the address not 2M aligned? */
+	movq	%rbp, %rax
+	andl	$~LARGE_PAGE_MASK, %eax
+	testl	%eax, %eax
+	jnz	bad_address
+
+	/* Is the address too large? */
+	leaq	_text(%rip), %rdx
+	movq	$PGDIR_SIZE, %rax
+	cmpq	%rax, %rdx
+	jae	bad_address
+
+	/* Fixup the physical addresses in the page table
 	 */
+	addq	%rbp, init_level4_pgt + 0(%rip)
+	addq	%rbp, init_level4_pgt + (258*8)(%rip)
+	addq	%rbp, init_level4_pgt + (511*8)(%rip)
+
+	addq	%rbp, level3_ident_pgt + 0(%rip)
+	addq	%rbp, level3_kernel_pgt + (510*8)(%rip)
+
+	/* Add an Identity mapping if I am above 1G */
+	leaq	_text(%rip), %rdi
+	andq	$LARGE_PAGE_MASK, %rdi
+
+	movq	%rdi, %rax
+	shrq	$PUD_SHIFT, %rax
+	andq	$(PTRS_PER_PUD - 1), %rax
+	jz	ident_complete
+
+	leaq	(level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+	leaq	level3_ident_pgt(%rip), %rbx
+	movq	%rdx, 0(%rbx, %rax, 8)
+
+	movq	%rdi, %rax
+	shrq	$PMD_SHIFT, %rax
+	andq	$(PTRS_PER_PMD - 1), %rax
+	leaq	__PAGE_KERNEL_LARGE_EXEC(%rdi), %rdx
+	leaq	level2_spare_pgt(%rip), %rbx
+	movq	%rdx, 0(%rbx, %rax, 8)
+ident_complete:
+
+	/* Fixup the kernel text+data virtual addresses
+	 */
+	leaq	level2_kernel_pgt(%rip), %rdi
+	leaq	4096(%rdi), %r8
+	/* See if it is a valid page table entry */
+1:	testq	$1, 0(%rdi)
+	jz	2f
+	addq	%rbp, 0(%rdi)
+	/* Go to the next page */
+2:	addq	$8, %rdi
+	cmp	%r8, %rdi
+	jne	1b
+
+	/* Fixup phys_base */
+	addq	%rbp, phys_base(%rip)
 
-	/* Enable PAE mode */
-	xorl	%eax, %eax
-	btsl	$5, %eax
-	movl	%eax, %cr4
-
-	/* Setup early boot stage 4 level pagetables */
-	movl	$(boot_level4_pgt - __START_KERNEL_map), %eax
-	movl	%eax, %cr3
-
-	/* Setup EFER (Extended Feature Enable Register) */
-	movl	$MSR_EFER, %ecx
-	rdmsr
-
-	/* Enable Long Mode */
-	btsl	$_EFER_LME, %eax
-				
-	/* Make changes effective */
-	wrmsr
+#ifdef CONFIG_SMP
+	addq	%rbp, trampoline_level4_pgt + 0(%rip)
+	addq	%rbp, trampoline_level4_pgt + (511*8)(%rip)
+#endif
+#ifdef CONFIG_ACPI_SLEEP
+	addq	%rbp, wakeup_level4_pgt + 0(%rip)
+	addq	%rbp, wakeup_level4_pgt + (511*8)(%rip)
+#endif
 
-	xorl	%eax, %eax
-	btsl	$31, %eax			/* Enable paging and in turn activate Long Mode */
-	btsl	$0, %eax			/* Enable protected mode */
-	/* Make changes effective */
-	movl	%eax, %cr0
-	/*
-	 * At this point we're in long mode but in 32bit compatibility mode
-	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
-	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
-	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+	/* Due to ENTRY(), sometimes the empty space gets filled with
+	 * zeros. Better take a jmp than relying on empty space being
+	 * filled with 0x90 (nop)
 	 */
-	ljmp	$__KERNEL_CS, $(startup_64 - __START_KERNEL_map)
-
-	.code64
-	.org 0x100	
-	.globl startup_64
-startup_64:
-	/* We come here either from startup_32
-	 * or directly from a 64bit bootloader.
-	 * Since we may have come directly from a bootloader we
-	 * reload the page tables here.
+	jmp secondary_startup_64
+ENTRY(secondary_startup_64)
+	/*
+	 * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+	 * and someone has loaded a mapped page table.
+	 *
+	 * %esi holds a physical pointer to real_mode_data.
+	 *
+	 * We come here either from startup_64 (using physical addresses)
+	 * or from trampoline.S (using virtual addresses).
+	 *
+	 * Using virtual addresses from trampoline.S removes the need
+	 * to have any identity mapped pages in the kernel page table
+	 * after the boot processor executes this code.
 	 */
 
 	/* Enable PAE mode and PGE */
@@ -113,9 +148,15 @@ startup_64:
 	movq	%rax, %cr4
 
 	/* Setup early boot stage 4 level pagetables. */
-	movq	$(boot_level4_pgt - __START_KERNEL_map), %rax
+	movq	$(init_level4_pgt - __START_KERNEL_map), %rax
+	addq	phys_base(%rip), %rax
 	movq	%rax, %cr3
 
+	/* Ensure I am executing from virtual addresses */
+	movq	$1f, %rax
+	jmp	*%rax
+1:
+
 	/* Check if nx is implemented */
 	movl	$0x80000001, %eax
 	cpuid
@@ -124,17 +165,11 @@ startup_64:
 	/* Setup EFER (Extended Feature Enable Register) */
 	movl	$MSR_EFER, %ecx
 	rdmsr
-
-	/* Enable System Call */
-	btsl	$_EFER_SCE, %eax
-
-	/* No Execute supported? */
-	btl	$20,%edi
+	btsl	$_EFER_SCE, %eax	/* Enable System Call */
+	btl	$20,%edi		/* No Execute supported? */
 	jnc     1f
 	btsl	$_EFER_NX, %eax
-1:
-	/* Make changes effective */
-	wrmsr
+1:	wrmsr				/* Make changes effective */
 
 	/* Setup cr0 */
 #define CR0_PM				1		/* protected mode */
@@ -161,7 +196,7 @@ #define CR0_PAGING 			(1<<31)
 	 * addresses where we're currently running on. We have to do that here
 	 * because in 32bit we couldn't load a 64bit linear address.
 	 */
-	lgdt	cpu_gdt_descr
+	lgdt	cpu_gdt_descr(%rip)
 
 	/* set up data segments. actually 0 would do too */
 	movl $__KERNEL_DS,%eax
@@ -212,6 +247,9 @@ initial_code:
 init_rsp:
 	.quad  init_thread_union+THREAD_SIZE-8
 
+bad_address:
+	jmp bad_address
+
 ENTRY(early_idt_handler)
 	cmpl $2,early_recursion_flag(%rip)
 	jz  1f
@@ -240,110 +278,66 @@ early_idt_msg:
 early_idt_ripmsg:
 	.asciz "RIP %s\n"
 
-.code32
-ENTRY(no_long_mode)
-	/* This isn't an x86-64 CPU so hang */
-1:
-	jmp	1b
-
-.org 0xf00
-	.globl pGDT32
-pGDT32:
-	.word	gdt_end-cpu_gdt_table-1
-	.long	cpu_gdt_table-__START_KERNEL_map
-
-.org 0xf10	
-ljumpvector:
-	.long	startup_64-__START_KERNEL_map
-	.word	__KERNEL_CS
+.balign PAGE_SIZE
 
-ENTRY(stext)
-ENTRY(_stext)
-
-	$page = 0
 #define NEXT_PAGE(name) \
-	$page = $page + 1; \
-	.org $page * 0x1000; \
-	phys_/**/name = $page * 0x1000 + __PHYSICAL_START; \
+	.balign	PAGE_SIZE; \
 ENTRY(name)
 
+/* Automate the creation of 1 to 1 mapping pmd entries */
+#define PMDS(START, PERM, COUNT)		\
+	i = 0 ;					\
+	.rept (COUNT) ;				\
+	.quad	(START) + (i << 21) + (PERM) ;	\
+	i = i + 1 ;				\
+	.endr
+
+	/*
+	 * This default setting generates an ident mapping at address 0x100000
+	 * and a mapping for the kernel that precisely maps virtual address
+	 * 0xffffffff80000000 to physical address 0x000000. (always using
+	 * 2Mbyte large pages provided by PAE mode)
+	 */
 NEXT_PAGE(init_level4_pgt)
-	/* This gets initialized in x86_64_start_kernel */
-	.fill	512,8,0
+	.quad	level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+	.fill	257,8,0
+	.quad	level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+	.fill	252,8,0
+	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+	.quad	level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
 
 NEXT_PAGE(level3_ident_pgt)
-	.quad	phys_level2_ident_pgt | 0x007
+	.quad	level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
 	.fill	511,8,0
 
 NEXT_PAGE(level3_kernel_pgt)
 	.fill	510,8,0
 	/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
-	.quad	phys_level2_kernel_pgt | 0x007
+	.quad	level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
 	.fill	1,8,0
 
 NEXT_PAGE(level2_ident_pgt)
-	/* 40MB for bootup. 	*/
-	i = 0
-	.rept 20
-	.quad	i << 21 | 0x083
-	i = i + 1
-	.endr
-	/* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */
-	.globl temp_boot_pmds
-temp_boot_pmds:
-	.fill	492,8,0
-	
+	/* Since I easily can, map the first 1G.
+	 * Don't set NX because code runs from these pages.
+	 */
+	PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+
 NEXT_PAGE(level2_kernel_pgt)
 	/* 40MB kernel mapping. The kernel code cannot be bigger than that.
 	   When you change this change KERNEL_TEXT_SIZE in page.h too. */
 	/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
-	i = 0
-	.rept 20
-	.quad	i << 21 | 0x183
-	i = i + 1
-	.endr
+	PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL,
+		KERNEL_TEXT_SIZE/PMD_SIZE)
 	/* Module mapping starts here */
-	.fill	492,8,0
+	.fill	(PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0
 
-NEXT_PAGE(level3_physmem_pgt)
-	.quad	phys_level2_kernel_pgt | 0x007	/* so that __va works even before pagetable_init */
-	.fill	511,8,0
+NEXT_PAGE(level2_spare_pgt)
+	.fill   512,8,0
 
+#undef PMDS
 #undef NEXT_PAGE
 
 	.data
-
-#ifdef CONFIG_ACPI_SLEEP
-	.align PAGE_SIZE
-ENTRY(wakeup_level4_pgt)
-	.quad	phys_level3_ident_pgt | 0x007
-	.fill	255,8,0
-	.quad	phys_level3_physmem_pgt | 0x007
-	.fill	254,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad	phys_level3_kernel_pgt | 0x007
-#endif
-
-#ifndef CONFIG_HOTPLUG_CPU
-	__INITDATA
-#endif
-	/*
-	 * This default setting generates an ident mapping at address 0x100000
-	 * and a mapping for the kernel that precisely maps virtual address
-	 * 0xffffffff80000000 to physical address 0x000000. (always using
-	 * 2Mbyte large pages provided by PAE mode)
-	 */
-	.align PAGE_SIZE
-ENTRY(boot_level4_pgt)
-	.quad	phys_level3_ident_pgt | 0x007
-	.fill	255,8,0
-	.quad	phys_level3_physmem_pgt | 0x007
-	.fill	254,8,0
-	/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
-	.quad	phys_level3_kernel_pgt | 0x007
-
-	.data
-
 	.align 16
 	.globl cpu_gdt_descr
 cpu_gdt_descr:
@@ -357,6 +351,10 @@ #ifdef CONFIG_SMP
 	.endr
 #endif
 
+ENTRY(phys_base)
+	/* This must match the first entry in level2_kernel_pgt */
+	.quad   0x0000000000000000
+
 /* 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 
@@ -370,13 +368,13 @@ #endif
 	
 ENTRY(cpu_gdt_table)
 	.quad	0x0000000000000000	/* NULL descriptor */
+	.quad	0x00cf9b000000ffff	/* __KERNEL32_CS */
+	.quad	0x00af9b000000ffff	/* __KERNEL_CS */
+	.quad	0x00cf93000000ffff	/* __KERNEL_DS */
+	.quad	0x00cffb000000ffff	/* __USER32_CS */
+	.quad	0x00cff3000000ffff	/* __USER_DS, __USER32_DS  */
+	.quad	0x00affb000000ffff	/* __USER_CS */
 	.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 */ 
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index 5f197b0..213d90e 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -18,8 +18,16 @@ #include <asm/bootsetup.h>
 #include <asm/setup.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 #include <asm/sections.h>
 
+static void __init zap_identity_mappings(void)
+{
+	pgd_t *pgd = pgd_offset_k(0UL);
+	pgd_clear(pgd);
+	__flush_tlb();
+}
+
 /* Don't add a printk in there. printk relies on the PDA which is not initialized 
    yet. */
 static void __init clear_bss(void)
@@ -29,25 +37,24 @@ static void __init clear_bss(void)
 }
 
 #define NEW_CL_POINTER		0x228	/* Relative to real mode data */
-#define OLD_CL_MAGIC_ADDR	0x90020
+#define OLD_CL_MAGIC_ADDR	0x20
 #define OLD_CL_MAGIC            0xA33F
-#define OLD_CL_BASE_ADDR        0x90000
-#define OLD_CL_OFFSET           0x90022
+#define OLD_CL_OFFSET           0x22
 
 static void __init copy_bootdata(char *real_mode_data)
 {
-	int new_data;
+	unsigned long new_data;
 	char * command_line;
 
 	memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
-	new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
+	new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER);
 	if (!new_data) {
-		if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
+		if (OLD_CL_MAGIC != *(u16 *)(real_mode_data + OLD_CL_MAGIC_ADDR)) {
 			return;
 		}
-		new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
+		new_data = __pa(real_mode_data) + *(u16 *)(real_mode_data + OLD_CL_OFFSET);
 	}
-	command_line = (char *) ((u64)(new_data));
+	command_line = __va(new_data);
 	memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
 }
 
@@ -55,26 +62,30 @@ void __init x86_64_start_kernel(char * r
 {
 	int i;
 
+	/*
+	 * Make sure kernel is aligned to 2MB address. Catching it at compile
+	 * time is better. Change your config file and compile the kernel
+	 * for a 2MB aligned address (CONFIG_PHYSICAL_START)
+	 */
+	BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
+
 	/* clear bss before set_intr_gate with early_idt_handler */
 	clear_bss();
 
+	/* Make NULL pointers segfault */
+	zap_identity_mappings();
+
 	for (i = 0; i < IDT_ENTRIES; i++)
 		set_intr_gate(i, early_idt_handler);
 	asm volatile("lidt %0" :: "m" (idt_descr));
 
 	early_printk("Kernel alive\n");
 
-	/*
-	 * switch to init_level4_pgt from boot_level4_pgt
-	 */
-	memcpy(init_level4_pgt, boot_level4_pgt, PTRS_PER_PGD*sizeof(pgd_t));
-	asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
-
  	for (i = 0; i < NR_CPUS; i++)
  		cpu_pda(i) = &boot_cpu_pda[i];
 
 	pda_init(0);
-	copy_bootdata(real_mode_data);
+	copy_bootdata(__va(real_mode_data));
 #ifdef CONFIG_SMP
 	cpu_set(0, cpu_online_map);
 #endif
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 4894266..4b32665 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -7,7 +7,6 @@ #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index c6a5bc7..4d58258 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -25,7 +25,6 @@ #include <linux/interrupt.h>
 #include <linux/init.h>
 #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>
@@ -907,10 +906,6 @@ static void __init setup_ExtINT_IRQ0_pin
 	enable_8259A_irq(0);
 }
 
-void __init UNEXPECTED_IO_APIC(void)
-{
-}
-
 void __apicdebuginit print_IO_APIC(void)
 {
 	int apic, i;
@@ -946,40 +941,16 @@ void __apicdebuginit print_IO_APIC(void)
 	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 *)&reg_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");
@@ -1407,8 +1378,7 @@ static void irq_complete_move(unsigned i
 
 	vector = ~get_irq_regs()->orig_rax;
 	me = smp_processor_id();
-	if ((vector == cfg->vector) &&
-	    cpu_isset(smp_processor_id(), cfg->domain)) {
+	if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
 		cpumask_t cleanup_mask;
 
 		cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
@@ -1983,18 +1953,18 @@ int arch_setup_msi_irq(struct pci_dev *d
 	if (irq < 0)
 		return irq;
 
-	set_irq_msi(irq, desc);
 	ret = msi_compose_msg(dev, irq, &msg);
 	if (ret < 0) {
 		destroy_irq(irq);
 		return ret;
 	}
 
+	set_irq_msi(irq, desc);
 	write_msi_msg(irq, &msg);
 
 	set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
-	return irq;
+	return 0;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
index 745b1f0..653efa3 100644
--- a/arch/x86_64/kernel/ioport.c
+++ b/arch/x86_64/kernel/ioport.c
@@ -12,10 +12,10 @@ #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 <linux/syscalls.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)
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 209c8c0..d4a0d0a 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -37,10 +37,10 @@ #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
 #include <linux/module.h>
+#include <linux/kdebug.h>
 
 #include <asm/cacheflush.h>
 #include <asm/pgtable.h>
-#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 
 void jprobe_return_end(void);
@@ -266,23 +266,14 @@ static void __kprobes prepare_singlestep
 }
 
 /* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 				      struct pt_regs *regs)
 {
 	unsigned long *sara = (unsigned long *)regs->rsp;
-	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++;
-	}
+	ri->ret_addr = (kprobe_opcode_t *) *sara;
+	/* Replace the return addr with trampoline addr */
+	*sara = (unsigned long) &kretprobe_trampoline;
 }
 
 int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -447,7 +438,7 @@ int __kprobes trampoline_probe_handler(s
 			break;
 	}
 
-	BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
 	regs->rip = orig_ret_address;
 
 	reset_current_kprobe();
@@ -752,3 +743,11 @@ int __init arch_init_kprobes(void)
 {
 	return register_kprobe(&trampoline_p);
 }
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+	if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+		return 1;
+
+	return 0;
+}
diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c
index d7e5d0c..bc9ffd5 100644
--- a/arch/x86_64/kernel/ldt.c
+++ b/arch/x86_64/kernel/ldt.c
@@ -13,7 +13,6 @@ #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>
 
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
index 0497e3b..c3a5547 100644
--- a/arch/x86_64/kernel/machine_kexec.c
+++ b/arch/x86_64/kernel/machine_kexec.c
@@ -189,21 +189,21 @@ NORET_TYPE void machine_kexec(struct kim
 	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[PA_CONTROL_PAGE] = virt_to_phys(control_page);
 	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
-	page_list[PA_PGD] = __pa(kexec_pgd);
+	page_list[PA_PGD] = virt_to_phys(&kexec_pgd);
 	page_list[VA_PGD] = (unsigned long)kexec_pgd;
-	page_list[PA_PUD_0] = __pa(kexec_pud0);
+	page_list[PA_PUD_0] = virt_to_phys(&kexec_pud0);
 	page_list[VA_PUD_0] = (unsigned long)kexec_pud0;
-	page_list[PA_PMD_0] = __pa(kexec_pmd0);
+	page_list[PA_PMD_0] = virt_to_phys(&kexec_pmd0);
 	page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
-	page_list[PA_PTE_0] = __pa(kexec_pte0);
+	page_list[PA_PTE_0] = virt_to_phys(&kexec_pte0);
 	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
-	page_list[PA_PUD_1] = __pa(kexec_pud1);
+	page_list[PA_PUD_1] = virt_to_phys(&kexec_pud1);
 	page_list[VA_PUD_1] = (unsigned long)kexec_pud1;
-	page_list[PA_PMD_1] = __pa(kexec_pmd1);
+	page_list[PA_PMD_1] = virt_to_phys(&kexec_pmd1);
 	page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
-	page_list[PA_PTE_1] = __pa(kexec_pte1);
+	page_list[PA_PTE_1] = virt_to_phys(&kexec_pte1);
 	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
 
 	page_list[PA_TABLE_PAGE] =
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 8011a8e..4421696 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -20,10 +20,10 @@ #include <linux/cpu.h>
 #include <linux/percpu.h>
 #include <linux/ctype.h>
 #include <linux/kmod.h>
+#include <linux/kdebug.h>
 #include <asm/processor.h> 
 #include <asm/msr.h>
 #include <asm/mce.h>
-#include <asm/kdebug.h>
 #include <asm/uaccess.h>
 #include <asm/smp.h>
 
@@ -323,10 +323,13 @@ void mce_log_therm_throt_event(unsigned 
 #endif /* CONFIG_X86_MCE_INTEL */
 
 /*
- * Periodic polling timer for "silent" machine check errors.
+ * Periodic polling timer for "silent" machine check errors.  If the
+ * poller finds an MCE, poll 2x faster.  When the poller finds no more
+ * errors, poll 2x slower (up to check_interval seconds).
  */
 
 static int check_interval = 5 * 60; /* 5 minutes */
+static int next_interval; /* in jiffies */
 static void mcheck_timer(struct work_struct *work);
 static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer);
 
@@ -339,7 +342,6 @@ static void mcheck_check_cpu(void *info)
 static void mcheck_timer(struct work_struct *work)
 {
 	on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
-	schedule_delayed_work(&mcheck_work, check_interval * HZ);
 
 	/*
 	 * It's ok to read stale data here for notify_user and
@@ -349,17 +351,30 @@ static void mcheck_timer(struct work_str
 	 * writes.
 	 */
 	if (notify_user && console_logged) {
+		static unsigned long last_print;
+		unsigned long now = jiffies;
+
+		/* if we logged an MCE, reduce the polling interval */
+		next_interval = max(next_interval/2, HZ/100);
 		notify_user = 0;
 		clear_bit(0, &console_logged);
-		printk(KERN_INFO "Machine check events logged\n");
+		if (time_after_eq(now, last_print + (check_interval*HZ))) {
+			last_print = now;
+			printk(KERN_INFO "Machine check events logged\n");
+		}
+	} else {
+		next_interval = min(next_interval*2, check_interval*HZ);
 	}
+
+	schedule_delayed_work(&mcheck_work, next_interval);
 }
 
 
 static __init int periodic_mcheck_init(void)
 { 
-	if (check_interval)
-		schedule_delayed_work(&mcheck_work, check_interval*HZ);
+	next_interval = check_interval * HZ;
+	if (next_interval)
+		schedule_delayed_work(&mcheck_work, next_interval);
 	return 0;
 } 
 __initcall(periodic_mcheck_init);
@@ -597,12 +612,13 @@ static int mce_resume(struct sys_device 
 /* Reinit MCEs after user configuration changes */
 static void mce_restart(void) 
 { 
-	if (check_interval)
+	if (next_interval)
 		cancel_delayed_work(&mcheck_work);
 	/* Timer race is harmless here */
 	on_each_cpu(mce_init, NULL, 1, 1);       
-	if (check_interval)
-		schedule_delayed_work(&mcheck_work, check_interval*HZ);
+	next_interval = check_interval * HZ;
+	if (next_interval)
+		schedule_delayed_work(&mcheck_work, next_interval);
 }
 
 static struct sysdev_class mce_sysclass = {
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 455aa0b..61ae57e 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -17,7 +17,6 @@ #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>
@@ -300,7 +299,7 @@ static int __init smp_read_mpc(struct mp
 			}
 		}
 	}
-	clustered_apic_check();
+	setup_apic_routing();
 	if (!num_processors)
 		printk(KERN_ERR "MPTABLE: no processors registered!\n");
 	return num_processors;
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index dfab9f1..931c64b 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -21,34 +21,17 @@ #include <linux/sysdev.h>
 #include <linux/sysctl.h>
 #include <linux/kprobes.h>
 #include <linux/cpumask.h>
+#include <linux/kdebug.h>
 
 #include <asm/smp.h>
 #include <asm/nmi.h>
 #include <asm/proto.h>
-#include <asm/kdebug.h>
 #include <asm/mce.h>
-#include <asm/intel_arch_perfmon.h>
 
 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
- */
-
-/* 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
-#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS)
-
-static DEFINE_PER_CPU(unsigned, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-
 static cpumask_t backtrace_mask = CPU_MASK_NONE;
 
 /* nmi_active:
@@ -63,191 +46,11 @@ int panic_on_timeout;
 unsigned int nmi_watchdog = NMI_DEFAULT;
 static unsigned int nmi_hz = HZ;
 
-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);
+static DEFINE_PER_CPU(short, wd_enabled);
 
 /* local prototypes */
 static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
 
-/* 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;
-}
-
-/* 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)
-{
-	int cpu;
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-	for_each_possible_cpu (cpu) {
-		if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
-			return 0;
-	}
-	return 1;
-}
-
-/* checks the an msr for availability */
-int avail_to_resrv_perfctr_nmi(unsigned int msr)
-{
-	unsigned int counter;
-	int cpu;
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	for_each_possible_cpu (cpu) {
-		if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
-			return 0;
-	}
-	return 1;
-}
-
-static int __reserve_perfctr_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
-		return 1;
-	return 0;
-}
-
-static void __release_perfctr_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_perfctr_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu));
-}
-
-int reserve_perfctr_nmi(unsigned int msr)
-{
-	int cpu, i;
-	for_each_possible_cpu (cpu) {
-		if (!__reserve_perfctr_nmi(cpu, msr)) {
-			for_each_possible_cpu (i) {
-				if (i >= cpu)
-					break;
-				__release_perfctr_nmi(i, msr);
-			}
-			return 0;
-		}
-	}
-	return 1;
-}
-
-void release_perfctr_nmi(unsigned int msr)
-{
-	int cpu;
-	for_each_possible_cpu (cpu)
-		__release_perfctr_nmi(cpu, msr);
-}
-
-int __reserve_evntsel_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_evntsel_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]))
-		return 1;
-	return 0;
-}
-
-static void __release_evntsel_nmi(int cpu, unsigned int msr)
-{
-	unsigned int counter;
-	if (cpu < 0)
-		cpu = smp_processor_id();
-
-	counter = nmi_evntsel_msr_to_bit(msr);
-	BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
-	clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]);
-}
-
-int reserve_evntsel_nmi(unsigned int msr)
-{
-	int cpu, i;
-	for_each_possible_cpu (cpu) {
-		if (!__reserve_evntsel_nmi(cpu, msr)) {
-			for_each_possible_cpu (i) {
-				if (i >= cpu)
-					break;
-				__release_evntsel_nmi(i, msr);
-			}
-			return 0;
-		}
-	}
-	return 1;
-}
-
-void release_evntsel_nmi(unsigned int msr)
-{
-	int cpu;
-	for_each_possible_cpu (cpu) {
-		__release_evntsel_nmi(cpu, msr);
-	}
-}
-
-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 == 16;
-	case X86_VENDOR_INTEL:
-		if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
-			return 1;
-		else
-			return (boot_cpu_data.x86 == 15);
-	}
-	return 0;
-}
-
 /* Run after command line and cpu_init init, but before all other checks */
 void nmi_watchdog_default(void)
 {
@@ -277,23 +80,6 @@ static __init void nmi_cpu_busy(void *da
 }
 #endif
 
-static unsigned int adjust_for_32bit_ctr(unsigned int hz)
-{
-	unsigned int retval = hz;
-
-	/*
-	 * 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 ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) {
-		retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
-	}
-	return retval;
-}
-
 int __init check_nmi_watchdog (void)
 {
 	int *counts;
@@ -322,14 +108,14 @@ #endif
 	mdelay((20*1000)/nmi_hz); // wait 20 ticks
 
 	for_each_online_cpu(cpu) {
-		if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
+		if (!per_cpu(wd_enabled, cpu))
 			continue;
 		if (cpu_pda(cpu)->__nmi_count - counts[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
 			       cpu,
 			       counts[cpu],
 			       cpu_pda(cpu)->__nmi_count);
-			per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
+			per_cpu(wd_enabled, cpu) = 0;
 			atomic_dec(&nmi_active);
 		}
 	}
@@ -344,13 +130,8 @@ #endif
 
 	/* 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) {
-		struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
-		nmi_hz = 1;
-	 	if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0)
-			nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-	}
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		nmi_hz = lapic_adjust_nmi_hz(1);
 
 	kfree(counts);
 	return 0;
@@ -379,57 +160,6 @@ int __init setup_nmi_watchdog(char *str)
 
 __setup("nmi_watchdog=", setup_nmi_watchdog);
 
-static void disable_lapic_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
-	if (atomic_read(&nmi_active) <= 0)
-		return;
-
-	on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
-	BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-static void enable_lapic_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
-	/* are we already enabled */
-	if (atomic_read(&nmi_active) != 0)
-		return;
-
-	/* are we lapic aware */
-	if (nmi_known_cpu() <= 0)
-		return;
-
-	on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
-	touch_nmi_watchdog();
-}
-
-void disable_timer_nmi_watchdog(void)
-{
-	BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
-	if (atomic_read(&nmi_active) <= 0)
-		return;
-
-	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)
-{
-	BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
-	if (atomic_read(&nmi_active) == 0) {
-		touch_nmi_watchdog();
-		on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
-		enable_irq(0);
-	}
-}
 
 static void __acpi_nmi_disable(void *__unused)
 {
@@ -515,275 +245,9 @@ late_initcall(init_lapic_nmi_sysfs);
 
 #endif	/* CONFIG_PM */
 
-/*
- * Activate the NMI watchdog via the local APIC.
- * Original code written by Keith Owens.
- */
-
-/* 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(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, 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;
-
-	/* 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(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(-1, evntsel_msr);
-fail1:
-	__release_perfctr_nmi(-1, 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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, 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)
-	 */
-	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(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, 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(-1, 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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, 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;
-	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))
-		goto fail;
-
-	perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
-	evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
-
-	if (!__reserve_perfctr_nmi(-1, perfctr_msr))
-		goto fail;
-
-	if (!__reserve_evntsel_nmi(-1, evntsel_msr))
-		goto fail1;
-
-	wrmsrl(perfctr_msr, 0UL);
-
-	evntsel = ARCH_PERFMON_EVENTSEL_INT
-		| ARCH_PERFMON_EVENTSEL_OS
-		| ARCH_PERFMON_EVENTSEL_USR
-		| ARCH_PERFMON_NMI_EVENT_SEL
-		| ARCH_PERFMON_NMI_EVENT_UMASK;
-
-	/* setup the timer */
-	wrmsr(evntsel_msr, evntsel, 0);
-
-	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-	wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
-
-	apic_write(APIC_LVTPC, APIC_DM_NMI);
-	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
-	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(-1, perfctr_msr);
-fail:
-	return 0;
-}
-
-static void stop_intel_arch_watchdog(void)
-{
-	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(-1, wd->evntsel_msr);
-	__release_perfctr_nmi(-1, 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)
+	if (__get_cpu_var(wd_enabled) == 1)
 		return;
 
 	/* cheap hack to support suspend/resume */
@@ -791,62 +255,31 @@ void setup_apic_nmi_watchdog(void *unuse
 	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;
-			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;
-			break;
-		default:
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		__get_cpu_var(wd_enabled) = 1;
+		if (lapic_watchdog_init(nmi_hz) < 0) {
+			__get_cpu_var(wd_enabled) = 0;
 			return;
 		}
+		/* FALL THROUGH */
+	case NMI_IO_APIC:
+		__get_cpu_var(wd_enabled) = 1;
+		atomic_inc(&nmi_active);
 	}
-	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)
+	if (__get_cpu_var(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;
-		}
-	}
-	wd->enabled = 0;
+	if (nmi_watchdog == NMI_LOCAL_APIC)
+		lapic_watchdog_stop();
+	__get_cpu_var(wd_enabled) = 0;
 	atomic_dec(&nmi_active);
 }
 
@@ -885,9 +318,7 @@ int __kprobes nmi_watchdog_tick(struct p
 	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;
+	int rc = 0;
 
 	/* check for other users first */
 	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
@@ -934,55 +365,20 @@ #endif
 	}
 
 	/* 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);
-				/* start the cycle over again */
-				wrmsrl(wd->perfctr_msr,
-				       -((u64)cpu_khz * 1000 / nmi_hz));
-	 		} 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);
-				/* ARCH_PERFMON has 32 bit counter writes */
-				wrmsr(wd->perfctr_msr,
-				     (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
-			} else {
-				/* 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.
-			 */
-			rc = 1;
-		} else
-			printk(KERN_WARNING "Unknown enabled NMI hardware?!\n");
+	if (!__get_cpu_var(wd_enabled))
+		return rc;
+	switch (nmi_watchdog) {
+	case NMI_LOCAL_APIC:
+		rc |= lapic_wd_event(nmi_hz);
+		break;
+	case 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.
+		 */
+		rc = 1;
+		break;
 	}
-done:
 	return rc;
 }
 
@@ -1067,12 +463,4 @@ void __trigger_all_cpu_backtrace(void)
 
 EXPORT_SYMBOL(nmi_active);
 EXPORT_SYMBOL(nmi_watchdog);
-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 04480c3..5bd20b5 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -507,7 +507,7 @@ error:
 	return ret;
 }
 
-static struct dma_mapping_ops calgary_dma_ops = {
+static const struct dma_mapping_ops calgary_dma_ops = {
 	.alloc_coherent = calgary_alloc_coherent,
 	.map_single = calgary_map_single,
 	.unmap_single = calgary_unmap_single,
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 0bae862..373ef66 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -22,13 +22,13 @@ #include <linux/module.h>
 #include <linux/topology.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/kdebug.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/pgtable.h>
 #include <asm/proto.h>
 #include <asm/cacheflush.h>
-#include <asm/kdebug.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
 #include <asm/k8.h>
@@ -556,7 +556,7 @@ static __init int init_k8_gatt(struct ag
 
 extern int agp_amd64_init(void);
 
-static struct dma_mapping_ops gart_dma_ops = {
+static const struct dma_mapping_ops gart_dma_ops = {
 	.mapping_error = NULL,
 	.map_single = gart_map_single,
 	.map_simple = gart_map_simple,
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index df09ab0..6dade0c 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -79,7 +79,7 @@ void nommu_unmap_sg(struct device *dev, 
 {
 }
 
-struct dma_mapping_ops nommu_dma_ops = {
+const struct dma_mapping_ops nommu_dma_ops = {
 	.map_single = nommu_map_single,
 	.unmap_single = nommu_unmap_single,
 	.map_sg = nommu_map_sg,
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index eb18be5..4b4569a 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -12,7 +12,7 @@ #include <asm/dma.h>
 int swiotlb __read_mostly;
 EXPORT_SYMBOL(swiotlb);
 
-struct dma_mapping_ops swiotlb_dma_ops = {
+const struct dma_mapping_ops swiotlb_dma_ops = {
 	.mapping_error = swiotlb_dma_mapping_error,
 	.alloc_coherent = swiotlb_alloc_coherent,
 	.free_coherent = swiotlb_free_coherent,
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index d8d5ccc..5909039 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -36,6 +36,7 @@ #include <linux/utsname.h>
 #include <linux/random.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
+#include <linux/kdebug.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -46,7 +47,6 @@ #include <asm/i387.h>
 #include <asm/mmu_context.h>
 #include <asm/pda.h>
 #include <asm/prctl.h>
-#include <asm/kdebug.h>
 #include <asm/desc.h>
 #include <asm/proto.h>
 #include <asm/ia32.h>
@@ -288,16 +288,18 @@ void __cpuinit select_idle_routine(const
 
 static int __init idle_setup (char *str)
 {
-	if (!strncmp(str, "poll", 4)) {
+	if (!strcmp(str, "poll")) {
 		printk("using polling idle threads.\n");
 		pm_idle = poll_idle;
-	}
+	} else if (!strcmp(str, "mwait"))
+		force_mwait = 1;
+	else
+		return -1;
 
 	boot_option_idle_override = 1;
-	return 1;
+	return 0;
 }
-
-__setup("idle=", idle_setup);
+early_param("idle", idle_setup);
 
 /* Prints also some state that isn't saved in the pt_regs */ 
 void __show_regs(struct pt_regs * regs)
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 4326a69..9409117 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -11,7 +11,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 2d67698..c116b54 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -7,8 +7,8 @@ #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/pm.h>
+#include <linux/kdebug.h>
 #include <asm/io.h>
-#include <asm/kdebug.h>
 #include <asm/delay.h>
 #include <asm/hw_irq.h>
 #include <asm/system.h>
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 3d98b69..db51577 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -79,6 +79,8 @@ int bootloader_type;
 
 unsigned long saved_video_mode;
 
+int force_mwait __cpuinitdata;
+
 /* 
  * Early DMI memory
  */
@@ -205,10 +207,10 @@ 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 = *(unsigned short *)__va(EBDA_ADDR_POINTER);
 	ebda_addr <<= 4;
 
-	ebda_size = *(unsigned short *)(unsigned long)ebda_addr;
+	ebda_size = *(unsigned short *)__va(ebda_addr);
 
 	/* Round EBDA up to pages */
 	if (ebda_size == 0)
@@ -274,8 +276,6 @@ #endif
 
 	dmi_scan_machine();
 
-	zap_low_mappings(0);
-
 #ifdef CONFIG_ACPI
 	/*
 	 * Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
@@ -329,15 +329,8 @@ #ifdef CONFIG_NUMA
 #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);
+	reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
 #endif
 
 #ifdef CONFIG_ACPI_SLEEP
@@ -612,6 +605,10 @@ #endif
 
 	/* RDTSC can be speculated around */
 	clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+
+	/* Family 10 doesn't support C states in MWAIT so don't use it */
+	if (c->x86 == 0x10 && !force_mwait)
+		clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
@@ -987,9 +984,8 @@ static int show_cpuinfo(struct seq_file 
 		"stc",
 		"100mhzsteps",
 		"hwpstate",
-		NULL,	/* tsc invariant mapped to constant_tsc */
-		NULL,
-		/* nothing */	/* constant_tsc - moved to flags */
+		"",	/* tsc invariant mapped to constant_tsc */
+		/* nothing */
 	};
 
 
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 6a70b55..64379a8 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -103,9 +103,9 @@ #endif
 		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);
+			ptr = alloc_bootmem_pages(size);
 		} else { 
-			ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
+			ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
 		}
 		if (!ptr)
 			panic("Cannot allocate cpu data for CPU %d\n", i);
@@ -201,7 +201,6 @@ void __cpuinit cpu_init (void)
 	/* CPU 0 is initialised in head64.c */
 	if (cpu != 0) {
 		pda_init(cpu);
-		zap_low_mappings(cpu);
 	} else 
 		estacks = boot_exception_stacks; 
 
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 49ec324..290f5d8 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -141,7 +140,7 @@ asmlinkage long sys_rt_sigreturn(struct 
 		goto badframe;
 
 #ifdef DEBUG_SIG
-	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
+	printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs->rip,regs->rsp,frame,eax);
 #endif
 
 	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT)
@@ -301,7 +300,7 @@ #endif
 	if (test_thread_flag(TIF_SINGLESTEP))
 		ptrace_notify(SIGTRAP);
 #ifdef DEBUG_SIG
-	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+	printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%p\n",
 		current->comm, current->pid, frame, regs->rip, frame->pretcode);
 #endif
 
@@ -463,7 +462,7 @@ 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",
+	printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%p pending:%x\n",
 	       thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current)); 
 #endif
 	       
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index af1ec4d..2ff4685 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -14,7 +14,6 @@ #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>
@@ -452,42 +451,34 @@ int smp_call_function (void (*func) (voi
 }
 EXPORT_SYMBOL(smp_call_function);
 
-void smp_stop_cpu(void)
+static void stop_this_cpu(void *dummy)
 {
-	unsigned long flags;
+	local_irq_disable();
 	/*
 	 * Remove this CPU:
 	 */
 	cpu_clear(smp_processor_id(), cpu_online_map);
-	local_irq_save(flags);
 	disable_local_APIC();
-	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;
+	int nolock;
+	unsigned long flags;
+
 	if (reboot_force)
 		return;
+
 	/* 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);
+	nolock = !spin_trylock(&call_lock);
+	local_irq_save(flags);
+	__smp_call_function(stop_this_cpu, NULL, 0, 0);
 	if (!nolock)
 		spin_unlock(&call_lock);
-
-	local_irq_disable();
 	disable_local_APIC();
-	local_irq_enable();
+	local_irq_restore(flags);
 }
 
 /*
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index cd4643a..32f5078 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -42,25 +42,23 @@ #include <linux/init.h>
 
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
 #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 <linux/kdebug.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/desc.h>
-#include <asm/kdebug.h>
 #include <asm/tlbflush.h>
 #include <asm/proto.h>
 #include <asm/nmi.h>
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 #include <asm/numa.h>
-#include <asm/genapic.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -68,7 +66,6 @@ EXPORT_SYMBOL(smp_num_siblings);
 
 /* Last level cache ID of each logical CPU */
 u8 cpu_llc_id[NR_CPUS] __cpuinitdata  = {[0 ... NR_CPUS-1] = BAD_APICID};
-EXPORT_SYMBOL(cpu_llc_id);
 
 /* Bitmask of currently online CPUs */
 cpumask_t cpu_online_map __read_mostly;
@@ -392,7 +389,8 @@ static void inquire_remote_apic(int apic
 {
 	unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
 	char *names[] = { "ID", "VERSION", "SPIV" };
-	int timeout, status;
+	int timeout;
+	unsigned int status;
 
 	printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
 
@@ -402,7 +400,9 @@ static void inquire_remote_apic(int apic
 		/*
 		 * Wait for idle.
 		 */
-		apic_wait_icr_idle();
+		status = safe_apic_wait_icr_idle();
+		if (status)
+			printk("a previous APIC delivery may have failed\n");
 
 		apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
 		apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
@@ -430,8 +430,8 @@ #endif
  */
 static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
 {
-	unsigned long send_status = 0, accept_status = 0;
-	int maxlvt, timeout, num_starts, j;
+	unsigned long send_status, accept_status = 0;
+	int maxlvt, num_starts, j;
 
 	Dprintk("Asserting INIT.\n");
 
@@ -447,12 +447,7 @@ static int __cpuinit wakeup_secondary_vi
 				| APIC_DM_INIT);
 
 	Dprintk("Waiting for send to finish...\n");
-	timeout = 0;
-	do {
-		Dprintk("+");
-		udelay(100);
-		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-	} while (send_status && (timeout++ < 1000));
+	send_status = safe_apic_wait_icr_idle();
 
 	mdelay(10);
 
@@ -465,12 +460,7 @@ static int __cpuinit wakeup_secondary_vi
 	apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
 
 	Dprintk("Waiting for send to finish...\n");
-	timeout = 0;
-	do {
-		Dprintk("+");
-		udelay(100);
-		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-	} while (send_status && (timeout++ < 1000));
+	send_status = safe_apic_wait_icr_idle();
 
 	mb();
 	atomic_set(&init_deasserted, 1);
@@ -509,12 +499,7 @@ static int __cpuinit wakeup_secondary_vi
 		Dprintk("Startup point 1.\n");
 
 		Dprintk("Waiting for send to finish...\n");
-		timeout = 0;
-		do {
-			Dprintk("+");
-			udelay(100);
-			send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
-		} while (send_status && (timeout++ < 1000));
+		send_status = safe_apic_wait_icr_idle();
 
 		/*
 		 * Give the other CPU some time to accept the IPI.
@@ -945,6 +930,12 @@ int __cpuinit __cpu_up(unsigned int cpu)
  		return -ENOSYS;
 	}
 
+	/*
+	 * Save current MTRR state in case it was changed since early boot
+	 * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+	 */
+	mtrr_save_state();
+
 	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
 	/* Boot it! */
 	err = do_boot_cpu(cpu, apicid);
@@ -965,13 +956,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
 	while (!cpu_isset(cpu, cpu_online_map))
 		cpu_relax();
-
-	if (num_online_cpus() > 8 && genapic == &apic_flat) {
-		printk(KERN_WARNING
-		       "flat APIC routing can't be used with > 8 cpus\n");
-		BUG();
-	}
-
 	err = 0;
 
 	return err;
diff --git a/arch/x86_64/kernel/stacktrace.c b/arch/x86_64/kernel/stacktrace.c
index 65ac2c6..cb91091 100644
--- a/arch/x86_64/kernel/stacktrace.c
+++ b/arch/x86_64/kernel/stacktrace.c
@@ -21,8 +21,7 @@ save_stack_warning_symbol(void *data, ch
 
 static int save_stack_stack(void *data, char *name)
 {
-	struct stack_trace *trace = (struct stack_trace *)data;
-	return trace->all_contexts ? 0 : -1;
+	return -1;
 }
 
 static void save_stack_address(void *data, unsigned long addr)
@@ -46,11 +45,10 @@ static struct stacktrace_ops save_stack_
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
  */
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
-	dump_trace(task, NULL, NULL, &save_stack_ops, trace);
+	dump_trace(current, NULL, NULL, &save_stack_ops, trace);
 	if (trace->nr_entries < trace->max_entries)
 		trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
 EXPORT_SYMBOL(save_stack_trace);
-
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 91f7e67..6a5a98f 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -12,6 +12,10 @@ #include <linux/suspend.h>
 #include <asm/proto.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mtrr.h>
+
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
 
 struct saved_context saved_context;
 
@@ -33,7 +37,6 @@ void __save_processor_state(struct saved
 	asm volatile ("str %0"  : "=m" (ctxt->tr));
 
 	/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
-	/* EFER should be constant for kernel version, no need to handle it. */
 	/*
 	 * segment registers
 	 */
@@ -46,10 +49,12 @@ void __save_processor_state(struct saved
 	rdmsrl(MSR_FS_BASE, ctxt->fs_base);
 	rdmsrl(MSR_GS_BASE, ctxt->gs_base);
 	rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+	mtrr_save_fixed_ranges(NULL);
 
 	/*
 	 * control registers 
 	 */
+	rdmsrl(MSR_EFER, ctxt->efer);
 	asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
 	asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
 	asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
@@ -75,6 +80,7 @@ void __restore_processor_state(struct sa
 	/*
 	 * control registers
 	 */
+	wrmsrl(MSR_EFER, ctxt->efer);
 	asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
 	asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
 	asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
@@ -219,4 +225,15 @@ int swsusp_arch_resume(void)
 	restore_image();
 	return 0;
 }
+
+/*
+ *	pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+int pfn_is_nosave(unsigned long pfn)
+{
+	unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+	unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
+	return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
 #endif /* CONFIG_SOFTWARE_SUSPEND */
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
index bfbe007..16d183f 100644
--- a/arch/x86_64/kernel/suspend_asm.S
+++ b/arch/x86_64/kernel/suspend_asm.S
@@ -71,9 +71,10 @@ loop:
 	jmp	loop
 done:
 	/* go back to the original page tables */
-	leaq	init_level4_pgt(%rip), %rax
-	subq	$__START_KERNEL_map, %rax
-	movq	%rax, %cr3
+	movq    $(init_level4_pgt - __START_KERNEL_map), %rax
+	addq    phys_base(%rip), %rax
+	movq    %rax, %cr3
+
 	/* Flush TLB, including "global" things (vmalloc) */
 	movq	mmu_cr4_features(%rip), %rax
 	movq	%rax, %rdx
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index 76bf7c2..d067d9a 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -7,7 +7,6 @@ #include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -93,6 +92,9 @@ arch_get_unmapped_area(struct file *filp
 	unsigned long start_addr;
 	unsigned long begin, end;
 	
+	if (flags & MAP_FIXED)
+		return addr;
+
 	find_start_end(flags, &begin, &end); 
 
 	if (len > end)
diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c
index 213fd6a..63d592c 100644
--- a/arch/x86_64/kernel/syscall.c
+++ b/arch/x86_64/kernel/syscall.c
@@ -3,6 +3,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <asm/asm-offsets.h>
 
 #define __NO_STUBS
 
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 75d73a9..4a0895b 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -39,13 +39,11 @@ #include <asm/timex.h>
 #include <asm/proto.h>
 #include <asm/hpet.h>
 #include <asm/sections.h>
-#include <linux/cpufreq.h>
 #include <linux/hpet.h>
 #include <asm/apic.h>
 #include <asm/hpet.h>
-
-extern void i8254_timer_resume(void);
-extern int using_apic_timer;
+#include <asm/mpspec.h>
+#include <asm/nmi.h>
 
 static char *timename = NULL;
 
@@ -252,6 +250,51 @@ #endif
 	return mktime(year, mon, day, hour, min, sec);
 }
 
+/* calibrate_cpu is used on systems with fixed rate TSCs to determine
+ * processor frequency */
+#define TICK_COUNT 100000000
+static unsigned int __init tsc_calibrate_cpu_khz(void)
+{
+       int tsc_start, tsc_now;
+       int i, no_ctr_free;
+       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+       unsigned long flags;
+
+       for (i = 0; i < 4; i++)
+               if (avail_to_resrv_perfctr_nmi_bit(i))
+                       break;
+       no_ctr_free = (i == 4);
+       if (no_ctr_free) {
+               i = 3;
+               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               rdmsrl(MSR_K7_PERFCTR3, pmc3);
+       } else {
+               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+       local_irq_save(flags);
+       /* start meauring cycles, incrementing from 0 */
+       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+       rdtscl(tsc_start);
+       do {
+               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+               tsc_now = get_cycles_sync();
+       } while ((tsc_now - tsc_start) < TICK_COUNT);
+
+       local_irq_restore(flags);
+       if (no_ctr_free) {
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               wrmsrl(MSR_K7_PERFCTR3, pmc3);
+               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+       } else {
+               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+
+       return pmc_now * tsc_khz / (tsc_now - tsc_start);
+}
 
 /*
  * pit_calibrate_tsc() uses the speaker output (channel 2) of
@@ -285,7 +328,7 @@ static unsigned int __init pit_calibrate
 #define PIT_MODE 0x43
 #define PIT_CH0  0x40
 
-static void __init __pit_init(int val, u8 mode)
+static void __pit_init(int val, u8 mode)
 {
 	unsigned long flags;
 
@@ -301,12 +344,12 @@ void __init pit_init(void)
 	__pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
 }
 
-void __init pit_stop_interrupt(void)
+void pit_stop_interrupt(void)
 {
 	__pit_init(0, 0x30); /* mode 0 */
 }
 
-void __init stop_timer_interrupt(void)
+void stop_timer_interrupt(void)
 {
 	char *name;
 	if (hpet_address) {
@@ -320,7 +363,10 @@ void __init stop_timer_interrupt(void)
 }
 
 static struct irqaction irq0 = {
-	timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
+	.handler	= timer_interrupt,
+	.flags		= IRQF_DISABLED | IRQF_IRQPOLL,
+	.mask		= CPU_MASK_NONE,
+	.name 		= "timer"
 };
 
 void __init time_init(void)
@@ -339,23 +385,29 @@ void __init time_init(void)
 	if (hpet_use_timer) {
 		/* set tick_nsec to use the proper rate for HPET */
 	  	tick_nsec = TICK_NSEC_HPET;
-		cpu_khz = hpet_calibrate_tsc();
+		tsc_khz = hpet_calibrate_tsc();
 		timename = "HPET";
 	} else {
 		pit_init();
-		cpu_khz = pit_calibrate_tsc();
+		tsc_khz = pit_calibrate_tsc();
 		timename = "PIT";
 	}
 
+	cpu_khz = tsc_khz;
+	if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+		boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+		boot_cpu_data.x86 == 16)
+		cpu_khz = tsc_calibrate_cpu_khz();
+
 	if (unsynchronized_tsc())
-		mark_tsc_unstable();
+		mark_tsc_unstable("TSCs unsynchronized");
 
 	if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
 		vgetcpu_mode = VGETCPU_RDTSCP;
 	else
 		vgetcpu_mode = VGETCPU_LSL;
 
-	set_cyc2ns_scale(cpu_khz);
+	set_cyc2ns_scale(tsc_khz);
 	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
 		cpu_khz / 1000, cpu_khz % 1000);
 	init_tsc_clocksource();
diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
index c79b99a..e7e2764 100644
--- a/arch/x86_64/kernel/trampoline.S
+++ b/arch/x86_64/kernel/trampoline.S
@@ -3,6 +3,7 @@
  *	Trampoline.S	Derived from Setup.S by Linus Torvalds
  *
  *	4 Jan 1997 Michael Chastain: changed to gnu as.
+ *	15 Sept 2005 Eric Biederman: 64bit PIC support
  *
  *	Entry: CS:IP point to the start of our code, we are 
  *	in real mode with no stack, but the rest of the 
@@ -17,15 +18,20 @@
  *	and IP is zero.  Thus, data addresses need to be absolute
  *	(no relocation) and are taken with regard to r_base.
  *
+ *	With the addition of trampoline_level4_pgt this code can
+ *	now enter a 64bit kernel that lives at arbitrary 64bit
+ *	physical addresses.
+ *
  *	If you work on this file, check the object module with objdump
  *	--full-contents --reloc to make sure there are no relocation
- *	entries. For the GDT entry we do hand relocation in smpboot.c
- *	because of 64bit linker limitations.
+ *	entries.
  */
 
 #include <linux/linkage.h>
-#include <asm/segment.h>
+#include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/msr.h>
+#include <asm/segment.h>
 
 .data
 
@@ -33,15 +39,33 @@ #include <asm/page.h>
 
 ENTRY(trampoline_data)
 r_base = .
+	cli			# We should be safe anyway
 	wbinvd	
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
+	mov	%ax, %es
+	mov	%ax, %ss
 
-	cli			# We should be safe anyway
 
 	movl	$0xA5A5A5A5, trampoline_data - r_base
 				# write marker for master knows we're running
 
+					# Setup stack
+	movw	$(trampoline_stack_end - r_base), %sp
+
+	call	verify_cpu		# Verify the cpu supports long mode
+	testl   %eax, %eax		# Check for return code
+	jnz	no_longmode
+
+	mov	%cs, %ax
+	movzx	%ax, %esi		# Find the 32bit trampoline location
+	shll	$4, %esi
+
+					# Fixup the vectors
+	addl	%esi, startup_32_vector - r_base
+	addl	%esi, startup_64_vector - r_base
+	addl	%esi, tgdt + 2 - r_base	# Fixup the gdt pointer
+
 	/*
 	 * GDT tables in non default location kernel can be beyond 16MB and
 	 * lgdt will not be able to load the address as in real mode default
@@ -49,23 +73,94 @@ r_base = .
 	 * to 32 bit.
 	 */
 
-	lidtl	idt_48 - r_base	# load idt with 0, 0
-	lgdtl	gdt_48 - r_base	# load gdt with whatever is appropriate
+	lidtl	tidt - r_base	# load idt with 0, 0
+	lgdtl	tgdt - r_base	# load gdt with whatever is appropriate
 
 	xor	%ax, %ax
 	inc	%ax		# protected mode (PE) bit
 	lmsw	%ax		# into protected mode
-	# flaush prefetch and jump to startup_32 in arch/x86_64/kernel/head.S
-	ljmpl	$__KERNEL32_CS, $(startup_32-__START_KERNEL_map)
+
+	# flush prefetch and jump to startup_32
+	ljmpl	*(startup_32_vector - r_base)
+
+	.code32
+	.balign 4
+startup_32:
+	movl	$__KERNEL_DS, %eax	# Initialize the %ds segment register
+	movl	%eax, %ds
+
+	xorl	%eax, %eax
+	btsl	$5, %eax		# Enable PAE mode
+	movl	%eax, %cr4
+
+					# Setup trampoline 4 level pagetables
+	leal	(trampoline_level4_pgt - r_base)(%esi), %eax
+	movl	%eax, %cr3
+
+	movl	$MSR_EFER, %ecx
+	movl	$(1 << _EFER_LME), %eax	# Enable Long Mode
+	xorl	%edx, %edx
+	wrmsr
+
+	xorl	%eax, %eax
+	btsl	$31, %eax		# Enable paging and in turn activate Long Mode
+	btsl	$0, %eax		# Enable protected mode
+	movl	%eax, %cr0
+
+	/*
+	 * At this point we're in long mode but in 32bit compatibility mode
+	 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+	 * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
+	 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+	 */
+	ljmp	*(startup_64_vector - r_base)(%esi)
+
+	.code64
+	.balign 4
+startup_64:
+	# Now jump into the kernel using virtual addresses
+	movq	$secondary_startup_64, %rax
+	jmp	*%rax
+
+	.code16
+no_longmode:
+	hlt
+	jmp no_longmode
+#include "verify_cpu.S"
 
 	# Careful these need to be in the same 64K segment as the above;
-idt_48:
+tidt:
 	.word	0			# idt limit = 0
 	.word	0, 0			# idt base = 0L
 
-gdt_48:
-	.short	GDT_ENTRIES*8 - 1	# gdt limit
-	.long	cpu_gdt_table-__START_KERNEL_map
+	# Duplicate the global descriptor table
+	# so the kernel can live anywhere
+	.balign 4
+tgdt:
+	.short	tgdt_end - tgdt		# gdt limit
+	.long	tgdt - r_base
+	.short 0
+	.quad	0x00cf9b000000ffff	# __KERNEL32_CS
+	.quad	0x00af9b000000ffff	# __KERNEL_CS
+	.quad	0x00cf93000000ffff	# __KERNEL_DS
+tgdt_end:
+
+	.balign 4
+startup_32_vector:
+	.long	startup_32 - r_base
+	.word	__KERNEL32_CS, 0
+
+	.balign 4
+startup_64_vector:
+	.long	startup_64 - r_base
+	.word	__KERNEL_CS, 0
+
+trampoline_stack:
+	.org 0x1000
+trampoline_stack_end:
+ENTRY(trampoline_level4_pgt)
+	.quad	level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+	.fill	510,8,0
+	.quad	level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
 
-.globl trampoline_end
-trampoline_end:	
+ENTRY(trampoline_end)
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 09d2e8a..8c2ac41 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -32,6 +32,7 @@ #include <linux/kexec.h>
 #include <linux/unwind.h>
 #include <linux/uaccess.h>
 #include <linux/bug.h>
+#include <linux/kdebug.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -39,7 +40,6 @@ #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>
@@ -71,22 +71,6 @@ asmlinkage void alignment_check(void);
 asmlinkage void machine_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 
-ATOMIC_NOTIFIER_HEAD(die_chain);
-EXPORT_SYMBOL(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)
@@ -426,8 +410,7 @@ void show_registers(struct pt_regs *regs
 	const int cpu = smp_processor_id();
 	struct task_struct *cur = cpu_pda(cpu)->pcurrent;
 
-		rsp = regs->rsp;
-
+	rsp = regs->rsp;
 	printk("CPU %d ", cpu);
 	__show_regs(regs);
 	printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
@@ -438,7 +421,6 @@ void show_registers(struct pt_regs *regs
 	 * time of the fault..
 	 */
 	if (in_kernel) {
-
 		printk("Stack: ");
 		_show_stack(NULL, regs, (unsigned long*)rsp);
 
@@ -581,10 +563,20 @@ static void __kprobes do_trap(int trapnr
 {
 	struct task_struct *tsk = current;
 
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = trapnr;
-
 	if (user_mode(regs)) {
+		/*
+		 * We want error_code and trap_no set for userspace
+		 * faults and kernelspace faults which result in
+		 * die(), but not kernelspace faults which are fixed
+		 * up.  die() gives the process no chance to handle
+		 * the signal and notice the kernel fault information,
+		 * so that won't result in polluting the information
+		 * about previously queued, but not yet delivered,
+		 * faults.  See also do_general_protection below.
+		 */
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = trapnr;
+
 		if (exception_trace && unhandled_signal(tsk, signr))
 			printk(KERN_INFO
 			       "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
@@ -605,8 +597,11 @@ static void __kprobes do_trap(int trapnr
 		fixup = search_exception_tables(regs->rip);
 		if (fixup)
 			regs->rip = fixup->fixup;
-		else	
+		else {
+			tsk->thread.error_code = error_code;
+			tsk->thread.trap_no = trapnr;
 			die(str, regs, error_code);
+		}
 		return;
 	}
 }
@@ -682,10 +677,10 @@ asmlinkage void __kprobes do_general_pro
 
 	conditional_sti(regs);
 
-	tsk->thread.error_code = error_code;
-	tsk->thread.trap_no = 13;
-
 	if (user_mode(regs)) {
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = 13;
+
 		if (exception_trace && unhandled_signal(tsk, SIGSEGV))
 			printk(KERN_INFO
 		       "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
@@ -704,6 +699,9 @@ asmlinkage void __kprobes do_general_pro
 			regs->rip = fixup->fixup;
 			return;
 		}
+
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = 13;
 		if (notify_die(DIE_GPF, "general protection fault", regs,
 					error_code, 13, SIGSEGV) == NOTIFY_STOP)
 			return;
@@ -778,6 +776,8 @@ asmlinkage __kprobes void default_do_nmi
 		 */
 		if (nmi_watchdog_tick(regs,reason))
 			return;
+		if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
+								== NOTIFY_STOP)
 		if (!do_nmi_callback(regs,cpu))
 			unknown_nmi_error(reason, regs);
 
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index 1a0edbb..48f9a8e 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -13,6 +13,8 @@ static int notsc __initdata = 0;
 
 unsigned int cpu_khz;		/* TSC clocks / usec, not used here */
 EXPORT_SYMBOL(cpu_khz);
+unsigned int tsc_khz;
+EXPORT_SYMBOL(tsc_khz);
 
 static unsigned int cyc2ns_scale __read_mostly;
 
@@ -77,7 +79,7 @@ static void handle_cpufreq_delayed_get(s
 static unsigned int  ref_freq = 0;
 static unsigned long loops_per_jiffy_ref = 0;
 
-static unsigned long cpu_khz_ref = 0;
+static unsigned long tsc_khz_ref = 0;
 
 static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 				 void *data)
@@ -99,7 +101,7 @@ #endif
 	if (!ref_freq) {
 		ref_freq = freq->old;
 		loops_per_jiffy_ref = *lpj;
-		cpu_khz_ref = cpu_khz;
+		tsc_khz_ref = tsc_khz;
 	}
 	if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
 		(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
@@ -107,12 +109,12 @@ #endif
 		*lpj =
 		cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 
-		cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
+		tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
 		if (!(freq->flags & CPUFREQ_CONST_LOOPS))
-			mark_tsc_unstable();
+			mark_tsc_unstable("cpufreq changes");
 	}
 
-	set_cyc2ns_scale(cpu_khz_ref);
+	set_cyc2ns_scale(tsc_khz_ref);
 
 	return 0;
 }
@@ -197,10 +199,11 @@ static struct clocksource clocksource_ts
 	.vread			= vread_tsc,
 };
 
-void mark_tsc_unstable(void)
+void mark_tsc_unstable(char *reason)
 {
 	if (!tsc_unstable) {
 		tsc_unstable = 1;
+		printk("Marking TSC unstable due to %s\n", reason);
 		/* Change only the rating, when not registered */
 		if (clocksource_tsc.mult)
 			clocksource_change_rating(&clocksource_tsc, 0);
@@ -213,7 +216,7 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable);
 void __init init_tsc_clocksource(void)
 {
 	if (!notsc) {
-		clocksource_tsc.mult = clocksource_khz2mult(cpu_khz,
+		clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
 							clocksource_tsc.shift);
 		if (check_tsc_unstable())
 			clocksource_tsc.rating = 0;
diff --git a/arch/x86_64/kernel/tsc_sync.c b/arch/x86_64/kernel/tsc_sync.c
index 014f0db..355f5f5 100644
--- a/arch/x86_64/kernel/tsc_sync.c
+++ b/arch/x86_64/kernel/tsc_sync.c
@@ -50,7 +50,7 @@ static __cpuinit void check_tsc_warp(voi
 	/*
 	 * The measurement runs for 20 msecs:
 	 */
-	end = start + cpu_khz * 20ULL;
+	end = start + tsc_khz * 20ULL;
 	now = start;
 
 	for (i = 0; ; i++) {
@@ -138,7 +138,7 @@ void __cpuinit check_tsc_sync_source(int
 		printk("\n");
 		printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs,"
 				    " turning off TSC clock.\n", max_warp);
-		mark_tsc_unstable();
+		mark_tsc_unstable("check_tsc_sync_source failed");
 		nr_warps = 0;
 		max_warp = 0;
 		last_tsc = 0;
diff --git a/arch/x86_64/kernel/verify_cpu.S b/arch/x86_64/kernel/verify_cpu.S
new file mode 100644
index 0000000..e035f59
--- /dev/null
+++ b/arch/x86_64/kernel/verify_cpu.S
@@ -0,0 +1,119 @@
+/*
+ *
+ *	verify_cpu.S - Code for cpu long mode and SSE verification. This
+ *	code has been borrowed from boot/setup.S and was introduced by
+ * 	Andi Kleen.
+ *
+ *	Copyright (c) 2007  Andi Kleen (ak@suse.de)
+ *	Copyright (c) 2007  Eric Biederman (ebiederm@xmission.com)
+ *	Copyright (c) 2007  Vivek Goyal (vgoyal@in.ibm.com)
+ *
+ * 	This source code is licensed under the GNU General Public License,
+ * 	Version 2.  See the file COPYING for more details.
+ *
+ *	This is a common code for verification whether CPU supports
+ * 	long mode and SSE or not. It is not called directly instead this
+ *	file is included at various places and compiled in that context.
+ * 	Following are the current usage.
+ *
+ * 	This file is included by both 16bit and 32bit code.
+ *
+ *	arch/x86_64/boot/setup.S : Boot cpu verification (16bit)
+ *	arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit)
+ *	arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit)
+ *	arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit)
+ *
+ *	verify_cpu, returns the status of cpu check in register %eax.
+ *		0: Success    1: Failure
+ *
+ * 	The caller needs to check for the error code and take the action
+ * 	appropriately. Either display a message or halt.
+ */
+
+#include <asm/cpufeature.h>
+
+verify_cpu:
+	pushfl				# Save caller passed flags
+	pushl	$0			# Kill any dangerous flags
+	popfl
+
+	/* minimum CPUID flags for x86-64 as defined by AMD */
+#define M(x) (1<<(x))
+#define M2(a,b) M(a)|M(b)
+#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d)
+
+#define SSE_MASK \
+	(M2(X86_FEATURE_XMM,X86_FEATURE_XMM2))
+#define REQUIRED_MASK1 \
+	(M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\
+	 M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\
+	 M(X86_FEATURE_FXSR))
+#define REQUIRED_MASK2 \
+	(M(X86_FEATURE_LM - 32))
+
+	pushfl				# standard way to check for cpuid
+	popl	%eax
+	movl	%eax,%ebx
+	xorl	$0x200000,%eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	cmpl	%eax,%ebx
+	jz	verify_cpu_no_longmode	# cpu has no cpuid
+
+	movl	$0x0,%eax		# See if cpuid 1 is implemented
+	cpuid
+	cmpl	$0x1,%eax
+	jb	verify_cpu_no_longmode	# no cpuid 1
+
+	xor	%di,%di
+	cmpl	$0x68747541,%ebx	# AuthenticAMD
+	jnz	verify_cpu_noamd
+	cmpl	$0x69746e65,%edx
+	jnz	verify_cpu_noamd
+	cmpl	$0x444d4163,%ecx
+	jnz	verify_cpu_noamd
+	mov	$1,%di			# cpu is from AMD
+
+verify_cpu_noamd:
+	movl    $0x1,%eax		# Does the cpu have what it takes
+	cpuid
+	andl	$REQUIRED_MASK1,%edx
+	xorl	$REQUIRED_MASK1,%edx
+	jnz	verify_cpu_no_longmode
+
+	movl    $0x80000000,%eax	# See if extended cpuid is implemented
+	cpuid
+	cmpl    $0x80000001,%eax
+	jb      verify_cpu_no_longmode	# no extended cpuid
+
+	movl    $0x80000001,%eax	# Does the cpu have what it takes
+	cpuid
+	andl    $REQUIRED_MASK2,%edx
+	xorl    $REQUIRED_MASK2,%edx
+	jnz     verify_cpu_no_longmode
+
+verify_cpu_sse_test:
+	movl	$1,%eax
+	cpuid
+	andl	$SSE_MASK,%edx
+	cmpl	$SSE_MASK,%edx
+	je	verify_cpu_sse_ok
+	test	%di,%di
+	jz	verify_cpu_no_longmode	# only try to force SSE on AMD
+	movl	$0xc0010015,%ecx	# HWCR
+	rdmsr
+	btr	$15,%eax		# enable SSE
+	wrmsr
+	xor	%di,%di			# don't loop
+	jmp	verify_cpu_sse_test	# try again
+
+verify_cpu_no_longmode:
+	popfl				# Restore caller passed flags
+	movl $1,%eax
+	ret
+verify_cpu_sse_ok:
+	popfl				# Restore caller passed flags
+	xorl %eax, %eax
+	ret
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 5176ecf..88cfa50 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -29,9 +29,7 @@ SECTIONS
   .text :  AT(ADDR(.text) - LOAD_OFFSET) {
 	/* First the code that has to be first for bootstrapping */
 	*(.bootstrap.text)
-	/* Then all the functions that are "hot" in profiles, to group them
-           onto the same hugetlb entry */
-	#include "functionlist"
+	_stext = .;
 	/* Then the rest */
 	*(.text)
 	SCHED_TEXT
@@ -50,10 +48,10 @@ SECTIONS
   __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
   __stop___ex_table = .;
 
-  RODATA
-
   BUG_TABLE
 
+  RODATA
+
   . = ALIGN(PAGE_SIZE);        /* Align data segment to page size boundary */
 				/* Data */
   .data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -94,6 +92,12 @@ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET
 		{ *(.vsyscall_gtod_data) }
   vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
 
+
+  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
+		{ *(.vsyscall_1) }
+  .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
+		{ *(.vsyscall_2) }
+
   .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
   vgetcpu_mode = VVIRT(.vgetcpu_mode);
 
@@ -101,10 +105,6 @@ #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET
   .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
   jiffies = VVIRT(.jiffies);
 
-  .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
-		{ *(.vsyscall_1) }
-  .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
-		{ *(.vsyscall_2) }
   .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
 		{ *(.vsyscall_3) }
 
@@ -194,7 +194,7 @@ #ifdef CONFIG_BLK_DEV_INITRD
   __initramfs_end = .;
 #endif
 
-    . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index b43c698..dc32cef 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -45,14 +45,34 @@ #include <asm/topology.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","rcx","memory"
+#define __pa_vsymbol(x)			\
+	({unsigned long v;  		\
+	extern char __vsyscall_0; 	\
+	  asm("" : "=r" (v) : "0" (x)); \
+	  ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); })
 
+/*
+ * vsyscall_gtod_data contains data that is :
+ * - readonly from vsyscalls
+ * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
+ * Try to keep this structure as small as possible to avoid cache line ping pongs
+ */
 struct vsyscall_gtod_data_t {
-	seqlock_t lock;
-	int sysctl_enabled;
-	struct timeval wall_time_tv;
+	seqlock_t	lock;
+
+	/* open coded 'struct timespec' */
+	time_t		wall_time_sec;
+	u32		wall_time_nsec;
+
+	int		sysctl_enabled;
 	struct timezone sys_tz;
-	cycle_t offset_base;
-	struct clocksource clock;
+	struct { /* extract of a clocksource struct */
+		cycle_t (*vread)(void);
+		cycle_t	cycle_last;
+		cycle_t	mask;
+		u32	mult;
+		u32	shift;
+	} clock;
 };
 int __vgetcpu_mode __section_vgetcpu_mode;
 
@@ -68,9 +88,13 @@ void update_vsyscall(struct timespec *wa
 
 	write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
 	/* copy vsyscall data */
-	vsyscall_gtod_data.clock = *clock;
-	vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec;
-	vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000;
+	vsyscall_gtod_data.clock.vread = clock->vread;
+	vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
+	vsyscall_gtod_data.clock.mask = clock->mask;
+	vsyscall_gtod_data.clock.mult = clock->mult;
+	vsyscall_gtod_data.clock.shift = clock->shift;
+	vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
+	vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
 	vsyscall_gtod_data.sys_tz = sys_tz;
 	write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
 }
@@ -105,7 +129,8 @@ static __always_inline long time_syscall
 static __always_inline void do_vgettimeofday(struct timeval * tv)
 {
 	cycle_t now, base, mask, cycle_delta;
-	unsigned long seq, mult, shift, nsec_delta;
+	unsigned seq;
+	unsigned long mult, shift, nsec;
 	cycle_t (*vread)(void);
 	do {
 		seq = read_seqbegin(&__vsyscall_gtod_data.lock);
@@ -121,21 +146,20 @@ static __always_inline void do_vgettimeo
 		mult = __vsyscall_gtod_data.clock.mult;
 		shift = __vsyscall_gtod_data.clock.shift;
 
-		*tv = __vsyscall_gtod_data.wall_time_tv;
-
+		tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
+		nsec = __vsyscall_gtod_data.wall_time_nsec;
 	} while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
 
 	/* calculate interval: */
 	cycle_delta = (now - base) & mask;
 	/* convert to nsecs: */
-	nsec_delta = (cycle_delta * mult) >> shift;
+	nsec += (cycle_delta * mult) >> shift;
 
-	/* convert to usecs and add to timespec: */
-	tv->tv_usec += nsec_delta / NSEC_PER_USEC;
-	while (tv->tv_usec > USEC_PER_SEC) {
+	while (nsec >= NSEC_PER_SEC) {
 		tv->tv_sec += 1;
-		tv->tv_usec -= USEC_PER_SEC;
+		nsec -= NSEC_PER_SEC;
 	}
+	tv->tv_usec = nsec / NSEC_PER_USEC;
 }
 
 int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
@@ -151,11 +175,13 @@ int __vsyscall(0) vgettimeofday(struct t
  * unlikely */
 time_t __vsyscall(1) vtime(time_t *t)
 {
+	time_t result;
 	if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
 		return time_syscall(t);
-	else if (t)
-		*t = __vsyscall_gtod_data.wall_time_tv.tv_sec;
-	return __vsyscall_gtod_data.wall_time_tv.tv_sec;
+	result = __vsyscall_gtod_data.wall_time_sec;
+	if (t)
+		*t = result;
+	return result;
 }
 
 /* Fast way to get current CPU and node.
@@ -224,10 +250,10 @@ static int vsyscall_sysctl_change(ctl_ta
 		return ret;
 	/* gcc has some trouble with __va(__pa()), so just do it this
 	   way. */
-	map1 = ioremap(__pa_symbol(&vsysc1), 2);
+	map1 = ioremap(__pa_vsymbol(&vsysc1), 2);
 	if (!map1)
 		return -ENOMEM;
-	map2 = ioremap(__pa_symbol(&vsysc2), 2);
+	map2 = ioremap(__pa_vsymbol(&vsysc2), 2);
 	if (!map2) {
 		ret = -ENOMEM;
 		goto out;
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 6ada723..bfb62a1 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -15,22 +15,22 @@ #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/vmalloc.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
+#include <linux/kdebug.h>
 
 #include <asm/system.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 */
@@ -585,7 +585,7 @@ do_sigbus:
 }
 
 DEFINE_SPINLOCK(pgd_lock);
-struct page *pgd_list;
+LIST_HEAD(pgd_list);
 
 void vmalloc_sync_all(void)
 {
@@ -605,8 +605,7 @@ void vmalloc_sync_all(void)
 			if (pgd_none(*pgd_ref))
 				continue;
 			spin_lock(&pgd_lock);
-			for (page = pgd_list; page;
-			     page = (struct page *)page->index) {
+			list_for_each_entry(page, &pgd_list, lru) {
 				pgd_t *pgd;
 				pgd = (pgd_t *)page_address(page) + pgd_index(address);
 				if (pgd_none(*pgd))
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index ec31534..1336da8 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -22,10 +22,12 @@ #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
+#include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/memory_hotplug.h>
+#include <linux/nmi.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -46,7 +48,7 @@ #ifndef Dprintk
 #define Dprintk(x...)
 #endif
 
-struct dma_mapping_ops* dma_ops;
+const struct dma_mapping_ops* dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
 static unsigned long dma_reserve __initdata;
@@ -72,6 +74,11 @@ void show_mem(void)
 
 	for_each_online_pgdat(pgdat) {
                for (i = 0; i < pgdat->node_spanned_pages; ++i) {
+			/* this loop can take a while with 256 GB and 4k pages
+			   so update the NMI watchdog */
+			if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) {
+				touch_nmi_watchdog();
+			}
 			page = pfn_to_page(pgdat->node_start_pfn + i);
 			total++;
 			if (PageReserved(page))
@@ -165,25 +172,11 @@ __set_fixmap (enum fixed_addresses idx, 
 	set_pte_phys(address, phys, prot);
 }
 
-unsigned long __initdata table_start, table_end; 
+unsigned long __meminitdata table_start, table_end;
 
-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) }, 
-	{}
-}; 
-
-static __meminit void *alloc_low_page(int *index, unsigned long *phys)
+static __meminit void *alloc_low_page(unsigned long *phys)
 { 
-	struct temp_map *ti;
-	int i; 
-	unsigned long pfn = table_end++, paddr; 
+	unsigned long pfn = table_end++;
 	void *adr;
 
 	if (after_bootmem) {
@@ -194,57 +187,63 @@ static __meminit void *alloc_low_page(in
 
 	if (pfn >= end_pfn) 
 		panic("alloc_low_page: ran out of memory"); 
-	for (i = 0; temp_mappings[i].allocated; i++) {
-		if (!temp_mappings[i].pmd) 
-			panic("alloc_low_page: ran out of temp mappings"); 
-	} 
-	ti = &temp_mappings[i];
-	paddr = (pfn << PAGE_SHIFT) & PMD_MASK; 
-	set_pmd(ti->pmd, __pmd(paddr | _KERNPG_TABLE | _PAGE_PSE)); 
-	ti->allocated = 1; 
-	__flush_tlb(); 	       
-	adr = ti->address + ((pfn << PAGE_SHIFT) & ~PMD_MASK); 
+
+	adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
 	memset(adr, 0, PAGE_SIZE);
-	*index = i; 
-	*phys  = pfn * PAGE_SIZE;  
-	return adr; 
-} 
+	*phys  = pfn * PAGE_SIZE;
+	return adr;
+}
 
-static __meminit void unmap_low_page(int i)
+static __meminit void unmap_low_page(void *adr)
 { 
-	struct temp_map *ti;
 
 	if (after_bootmem)
 		return;
 
-	ti = &temp_mappings[i];
-	set_pmd(ti->pmd, __pmd(0));
-	ti->allocated = 0; 
+	early_iounmap(adr, PAGE_SIZE);
 } 
 
 /* Must run before zap_low_mappings */
-__init void *early_ioremap(unsigned long addr, unsigned long size)
+__meminit 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) { 
-		return NULL;
+	unsigned long vaddr;
+	pmd_t *pmd, *last_pmd;
+	int i, pmds;
+
+	pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+	vaddr = __START_KERNEL_map;
+	pmd = level2_kernel_pgt;
+	last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1;
+	for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) {
+		for (i = 0; i < pmds; i++) {
+			if (pmd_present(pmd[i]))
+				goto next;
+		}
+		vaddr += addr & ~PMD_MASK;
+		addr &= PMD_MASK;
+		for (i = 0; i < pmds; i++, addr += PMD_SIZE)
+			set_pmd(pmd + i,__pmd(addr | _KERNPG_TABLE | _PAGE_PSE));
+		__flush_tlb();
+		return (void *)vaddr;
+	next:
+		;
 	}
-	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));
+	printk("early_ioremap(0x%lx, %lu) failed\n", addr, size);
+	return NULL;
 }
 
 /* To avoid virtual aliases later */
-__init void early_iounmap(void *addr, unsigned long size)
+__meminit 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));
+	unsigned long vaddr;
+	pmd_t *pmd;
+	int i, pmds;
+
+	vaddr = (unsigned long)addr;
+	pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+	pmd = level2_kernel_pgt + pmd_index(vaddr);
+	for (i = 0; i < pmds; i++)
+		pmd_clear(pmd + i);
 	__flush_tlb();
 }
 
@@ -289,7 +288,6 @@ static void __meminit phys_pud_init(pud_
 
 
 	for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) {
-		int map; 
 		unsigned long pmd_phys;
 		pud_t *pud = pud_page + pud_index(addr);
 		pmd_t *pmd;
@@ -307,12 +305,12 @@ static void __meminit phys_pud_init(pud_
 			continue;
 		}
 
-		pmd = alloc_low_page(&map, &pmd_phys);
+		pmd = alloc_low_page(&pmd_phys);
 		spin_lock(&init_mm.page_table_lock);
 		set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
 		phys_pmd_init(pmd, addr, end);
 		spin_unlock(&init_mm.page_table_lock);
-		unmap_low_page(map);
+		unmap_low_page(pmd);
 	}
 	__flush_tlb();
 } 
@@ -364,7 +362,6 @@ void __meminit init_memory_mapping(unsig
 	end = (unsigned long)__va(end);
 
 	for (; start < end; start = next) {
-		int map;
 		unsigned long pud_phys; 
 		pgd_t *pgd = pgd_offset_k(start);
 		pud_t *pud;
@@ -372,7 +369,7 @@ void __meminit init_memory_mapping(unsig
 		if (after_bootmem)
 			pud = pud_offset(pgd, start & PGDIR_MASK);
 		else
-			pud = alloc_low_page(&map, &pud_phys);
+			pud = alloc_low_page(&pud_phys);
 
 		next = start + PGDIR_SIZE;
 		if (next > end) 
@@ -380,7 +377,7 @@ void __meminit init_memory_mapping(unsig
 		phys_pud_init(pud, __pa(start), __pa(next));
 		if (!after_bootmem)
 			set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
-		unmap_low_page(map);   
+		unmap_low_page(pud);
 	} 
 
 	if (!after_bootmem)
@@ -388,21 +385,6 @@ void __meminit init_memory_mapping(unsig
 	__flush_tlb_all();
 }
 
-void __cpuinit zap_low_mappings(int cpu)
-{
-	if (cpu == 0) {
-		pgd_t *pgd = pgd_offset_k(0UL);
-		pgd_clear(pgd);
-	} else {
-		/*
-		 * For AP's, zap the low identity mappings by changing the cr3
-		 * to init_level4_pgt and doing local flush tlb all
-		 */
-		asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
-	}
-	__flush_tlb_all();
-}
-
 #ifndef CONFIG_NUMA
 void __init paging_init(void)
 {
@@ -579,15 +561,6 @@ #endif
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
 		initsize >> 10);
-
-#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
 }
 
 void free_init_pages(char *what, unsigned long begin, unsigned long end)
@@ -597,21 +570,23 @@ void free_init_pages(char *what, unsigne
 	if (begin >= end)
 		return;
 
-	printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+	printk(KERN_INFO "Freeing %s: %luk 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);
+		if (addr >= __START_KERNEL_map)
+			change_page_attr_addr(addr, 1, __pgprot(0));
 		free_page(addr);
 		totalram_pages++;
 	}
+	if (addr > __START_KERNEL_map)
+		global_flush_tlb();
 }
 
 void free_initmem(void)
 {
-	memset(__initdata_begin, POISON_FREE_INITDATA,
-		__initdata_end - __initdata_begin);
 	free_init_pages("unused kernel memory",
 			(unsigned long)(&__init_begin),
 			(unsigned long)(&__init_end));
@@ -621,13 +596,23 @@ #ifdef CONFIG_DEBUG_RODATA
 
 void mark_rodata_ro(void)
 {
-	unsigned long addr = (unsigned long)__start_rodata;
+	unsigned long start = (unsigned long)_stext, end;
+
+#ifdef CONFIG_HOTPLUG_CPU
+	/* It must still be possible to apply SMP alternatives. */
+	if (num_possible_cpus() > 1)
+		start = (unsigned long)_etext;
+#endif
+	end = (unsigned long)__end_rodata;
+	start = (start + PAGE_SIZE - 1) & PAGE_MASK;
+	end &= PAGE_MASK;
+	if (end <= start)
+		return;
 
-	for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
-		change_page_attr_addr(addr, 1, PAGE_KERNEL_RO);
+	change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO);
 
-	printk ("Write protecting the kernel read-only data: %luk\n",
-			(__end_rodata - __start_rodata) >> 10);
+	printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
+	       (end - start) >> 10);
 
 	/*
 	 * change_page_attr_addr() requires a global_flush_tlb() call after it.
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index c6e5e8d..6cac90a 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -13,12 +13,21 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/io.h>
+
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
 #include <asm/proto.h>
 
+unsigned long __phys_addr(unsigned long x)
+{
+	if (x >= __START_KERNEL_map)
+		return x - __START_KERNEL_map + phys_base;
+	return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+
 #define ISA_START_ADDRESS      0xa0000
 #define ISA_END_ADDRESS                0x100000
 
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index b5b8dba..f983c75 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -49,11 +49,8 @@ int __init k8_scan_nodes(unsigned long s
 	int found = 0;
 	u32 reg;
 	unsigned numnodes;
-	nodemask_t nodes_parsed;
 	unsigned dualcore = 0;
 
-	nodes_clear(nodes_parsed);
-
 	if (!early_pci_allowed())
 		return -1;
 
@@ -65,6 +62,8 @@ int __init k8_scan_nodes(unsigned long s
 
 	reg = read_pci_config(0, nb, 0, 0x60); 
 	numnodes = ((reg >> 4) & 0xF) + 1;
+	if (numnodes <= 1)
+		return -1;
 
 	printk(KERN_INFO "Number of nodes %d\n", numnodes);
 
@@ -102,7 +101,7 @@ int __init k8_scan_nodes(unsigned long s
 			       nodeid, (base>>8)&3, (limit>>8) & 3); 
 			return -1; 
 		}	
-		if (node_isset(nodeid, nodes_parsed)) { 
+		if (node_isset(nodeid, node_possible_map)) {
 			printk(KERN_INFO "Node %d already present. Skipping\n", 
 			       nodeid);
 			continue;
@@ -155,7 +154,7 @@ int __init k8_scan_nodes(unsigned long s
 
 		prevbase = base;
 
-		node_set(nodeid, nodes_parsed);
+		node_set(nodeid, node_possible_map);
 	} 
 
 	if (!found)
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 41b8fb0..5154894 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -273,125 +273,213 @@ void __init numa_init_array(void)
 
 #ifdef CONFIG_NUMA_EMU
 /* Numa emulation */
-int numa_fake __initdata = 0;
+#define E820_ADDR_HOLE_SIZE(start, end)					\
+	(e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) <<	\
+	PAGE_SHIFT)
+char *cmdline __initdata;
 
 /*
- * This function is used to find out if the start and end correspond to
- * different zones.
+ * Setups up nid to range from addr to addr + size.  If the end boundary is
+ * greater than max_addr, then max_addr is used instead.  The return value is 0
+ * if there is additional memory left for allocation past addr and -1 otherwise.
+ * addr is adjusted to be at the end of the node.
  */
-int zone_cross_over(unsigned long start, unsigned long end)
+static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
+				   u64 size, u64 max_addr)
 {
-	if ((start < (MAX_DMA32_PFN << PAGE_SHIFT)) &&
-			(end >= (MAX_DMA32_PFN << PAGE_SHIFT)))
-		return 1;
-	return 0;
+	int ret = 0;
+	nodes[nid].start = *addr;
+	*addr += size;
+	if (*addr >= max_addr) {
+		*addr = max_addr;
+		ret = -1;
+	}
+	nodes[nid].end = *addr;
+	node_set(nid, node_possible_map);
+	printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid,
+	       nodes[nid].start, nodes[nid].end,
+	       (nodes[nid].end - nodes[nid].start) >> 20);
+	return ret;
 }
 
-static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+/*
+ * Splits num_nodes nodes up equally starting at node_start.  The return value
+ * is the number of nodes split up and addr is adjusted to be at the end of the
+ * last node allocated.
+ */
+static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
+				      u64 max_addr, int node_start,
+				      int num_nodes)
 {
- 	int i, big;
- 	struct bootnode nodes[MAX_NUMNODES];
- 	unsigned long sz, old_sz;
-	unsigned long hole_size;
-	unsigned long start, end;
-	unsigned long max_addr = (end_pfn << PAGE_SHIFT);
-
-	start = (start_pfn << PAGE_SHIFT);
-	hole_size = e820_hole_size(start, max_addr);
-	sz = (max_addr - start - hole_size) / numa_fake;
-
- 	/* Kludge needed for the hash function */
-
-	old_sz = sz;
-	/*
-	 * Round down to the nearest FAKE_NODE_MIN_SIZE.
-	 */
-	sz &= FAKE_NODE_MIN_HASH_MASK;
+	unsigned int big;
+	u64 size;
+	int i;
 
+	if (num_nodes <= 0)
+		return -1;
+	if (num_nodes > MAX_NUMNODES)
+		num_nodes = MAX_NUMNODES;
+	size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) /
+	       num_nodes;
 	/*
-	 * We ensure that each node is at least 64MB big.  Smaller than this
-	 * size can cause VM hiccups.
+	 * Calculate the number of big nodes that can be allocated as a result
+	 * of consolidating the leftovers.
 	 */
-	if (sz == 0) {
-		printk(KERN_INFO "Not enough memory for %d nodes.  Reducing "
-				"the number of nodes\n", numa_fake);
-		numa_fake = (max_addr - start - hole_size) / FAKE_NODE_MIN_SIZE;
-		printk(KERN_INFO "Number of fake nodes will be = %d\n",
-				numa_fake);
-		sz = FAKE_NODE_MIN_SIZE;
+	big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * num_nodes) /
+	      FAKE_NODE_MIN_SIZE;
+
+	/* Round down to nearest FAKE_NODE_MIN_SIZE. */
+	size &= FAKE_NODE_MIN_HASH_MASK;
+	if (!size) {
+		printk(KERN_ERR "Not enough memory for each node.  "
+		       "NUMA emulation disabled.\n");
+		return -1;
 	}
-	/*
-	 * Find out how many nodes can get an extra NODE_MIN_SIZE granule.
-	 * This logic ensures the extra memory gets distributed among as many
-	 * nodes as possible (as compared to one single node getting all that
-	 * extra memory.
-	 */
-	big = ((old_sz - sz) * numa_fake) / FAKE_NODE_MIN_SIZE;
-	printk(KERN_INFO "Fake node Size: %luMB hole_size: %luMB big nodes: "
-			"%d\n",
-			(sz >> 20), (hole_size >> 20), big);
- 	memset(&nodes,0,sizeof(nodes));
-	end = start;
- 	for (i = 0; i < numa_fake; i++) {
-		/*
-		 * In case we are not able to allocate enough memory for all
-		 * the nodes, we reduce the number of fake nodes.
-		 */
-		if (end >= max_addr) {
-			numa_fake = i - 1;
-			break;
-		}
- 		start = nodes[i].start = end;
-		/*
-		 * Final node can have all the remaining memory.
-		 */
- 		if (i == numa_fake-1)
- 			sz = max_addr - start;
- 		end = nodes[i].start + sz;
-		/*
-		 * Fir "big" number of nodes get extra granule.
-		 */
+
+	for (i = node_start; i < num_nodes + node_start; i++) {
+		u64 end = *addr + size;
 		if (i < big)
 			end += FAKE_NODE_MIN_SIZE;
 		/*
-		 * Iterate over the range to ensure that this node gets at
-		 * least sz amount of RAM (excluding holes)
+		 * The final node can have the remaining system RAM.  Other
+		 * nodes receive roughly the same amount of available pages.
 		 */
-		while ((end - start - e820_hole_size(start, end)) < sz) {
-			end += FAKE_NODE_MIN_SIZE;
-			if (end >= max_addr)
-				break;
+		if (i == num_nodes + node_start - 1)
+			end = max_addr;
+		else
+			while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) <
+			       size) {
+				end += FAKE_NODE_MIN_SIZE;
+				if (end > max_addr) {
+					end = max_addr;
+					break;
+				}
+			}
+		if (setup_node_range(i, nodes, addr, end - *addr, max_addr) < 0)
+			break;
+	}
+	return i - node_start + 1;
+}
+
+/*
+ * Splits the remaining system RAM into chunks of size.  The remaining memory is
+ * always assigned to a final node and can be asymmetric.  Returns the number of
+ * nodes split.
+ */
+static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
+				      u64 max_addr, int node_start, u64 size)
+{
+	int i = node_start;
+	size = (size << 20) & FAKE_NODE_MIN_HASH_MASK;
+	while (!setup_node_range(i++, nodes, addr, size, max_addr))
+		;
+	return i - node_start;
+}
+
+/*
+ * Sets up the system RAM area from start_pfn to end_pfn according to the
+ * numa=fake command-line option.
+ */
+static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+{
+	struct bootnode nodes[MAX_NUMNODES];
+	u64 addr = start_pfn << PAGE_SHIFT;
+	u64 max_addr = end_pfn << PAGE_SHIFT;
+	int num_nodes = 0;
+	int coeff_flag;
+	int coeff = -1;
+	int num = 0;
+	u64 size;
+	int i;
+
+	memset(&nodes, 0, sizeof(nodes));
+	/*
+	 * If the numa=fake command-line is just a single number N, split the
+	 * system RAM into N fake nodes.
+	 */
+	if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) {
+		num_nodes = split_nodes_equally(nodes, &addr, max_addr, 0,
+						simple_strtol(cmdline, NULL, 0));
+		if (num_nodes < 0)
+			return num_nodes;
+		goto out;
+	}
+
+	/* Parse the command line. */
+	for (coeff_flag = 0; ; cmdline++) {
+		if (*cmdline && isdigit(*cmdline)) {
+			num = num * 10 + *cmdline - '0';
+			continue;
 		}
-		/*
-		 * Look at the next node to make sure there is some real memory
-		 * to map.  Bad things happen when the only memory present
-		 * in a zone on a fake node is IO hole.
-		 */
-		while (e820_hole_size(end, end + FAKE_NODE_MIN_SIZE) > 0) {
-			if (zone_cross_over(start, end + sz)) {
-				end = (MAX_DMA32_PFN << PAGE_SHIFT);
+		if (*cmdline == '*') {
+			if (num > 0)
+				coeff = num;
+			coeff_flag = 1;
+		}
+		if (!*cmdline || *cmdline == ',') {
+			if (!coeff_flag)
+				coeff = 1;
+			/*
+			 * Round down to the nearest FAKE_NODE_MIN_SIZE.
+			 * Command-line coefficients are in megabytes.
+			 */
+			size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK;
+			if (size)
+				for (i = 0; i < coeff; i++, num_nodes++)
+					if (setup_node_range(num_nodes, nodes,
+						&addr, size, max_addr) < 0)
+						goto done;
+			if (!*cmdline)
 				break;
-			}
-			if (end >= max_addr)
+			coeff_flag = 0;
+			coeff = -1;
+		}
+		num = 0;
+	}
+done:
+	if (!num_nodes)
+		return -1;
+	/* Fill remainder of system RAM, if appropriate. */
+	if (addr < max_addr) {
+		if (coeff_flag && coeff < 0) {
+			/* Split remaining nodes into num-sized chunks */
+			num_nodes += split_nodes_by_size(nodes, &addr, max_addr,
+							 num_nodes, num);
+			goto out;
+		}
+		switch (*(cmdline - 1)) {
+		case '*':
+			/* Split remaining nodes into coeff chunks */
+			if (coeff <= 0)
 				break;
-			end += FAKE_NODE_MIN_SIZE;
+			num_nodes += split_nodes_equally(nodes, &addr, max_addr,
+							 num_nodes, coeff);
+			break;
+		case ',':
+			/* Do not allocate remaining system RAM */
+			break;
+		default:
+			/* Give one final node */
+			setup_node_range(num_nodes, nodes, &addr,
+					 max_addr - addr, max_addr);
+			num_nodes++;
 		}
-		if (end > max_addr)
-			end = max_addr;
-		nodes[i].end = end;
- 		printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n",
- 		       i,
- 		       nodes[i].start, nodes[i].end,
- 		       (nodes[i].end - nodes[i].start) >> 20);
-		node_set_online(i);
- 	}
- 	memnode_shift = compute_hash_shift(nodes, numa_fake);
- 	if (memnode_shift < 0) {
- 		memnode_shift = 0;
- 		printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n");
- 		return -1;
- 	}
- 	for_each_online_node(i) {
+	}
+out:
+	memnode_shift = compute_hash_shift(nodes, num_nodes);
+	if (memnode_shift < 0) {
+		memnode_shift = 0;
+		printk(KERN_ERR "No NUMA hash function found.  NUMA emulation "
+		       "disabled.\n");
+		return -1;
+	}
+
+	/*
+	 * We need to vacate all active ranges that may have been registered by
+	 * SRAT.
+	 */
+	remove_all_active_ranges();
+	for_each_node_mask(i, node_possible_map) {
 		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);
@@ -399,26 +487,32 @@ static int __init numa_emulation(unsigne
  	numa_init_array();
  	return 0;
 }
-#endif
+#undef E820_ADDR_HOLE_SIZE
+#endif /* CONFIG_NUMA_EMU */
 
 void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
 { 
 	int i;
 
+	nodes_clear(node_possible_map);
+
 #ifdef CONFIG_NUMA_EMU
-	if (numa_fake && !numa_emulation(start_pfn, end_pfn))
+	if (cmdline && !numa_emulation(start_pfn, end_pfn))
  		return;
+	nodes_clear(node_possible_map);
 #endif
 
 #ifdef CONFIG_ACPI_NUMA
 	if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
 					  end_pfn << PAGE_SHIFT))
  		return;
+	nodes_clear(node_possible_map);
 #endif
 
 #ifdef CONFIG_K8_NUMA
 	if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT))
 		return;
+	nodes_clear(node_possible_map);
 #endif
 	printk(KERN_INFO "%s\n",
 	       numa_off ? "NUMA turned off" : "No NUMA configuration found");
@@ -432,6 +526,7 @@ #endif
 	memnodemap[0] = 0;
 	nodes_clear(node_online_map);
 	node_set_online(0);
+	node_set(0, node_possible_map);
 	for (i = 0; i < NR_CPUS; i++)
 		numa_set_node(i, 0);
 	node_to_cpumask[0] = cpumask_of_cpu(0);
@@ -486,11 +581,8 @@ static __init int numa_setup(char *opt)
 	if (!strncmp(opt,"off",3))
 		numa_off = 1;
 #ifdef CONFIG_NUMA_EMU
-	if(!strncmp(opt, "fake=", 5)) {
-		numa_fake = simple_strtoul(opt+5,NULL,0); ;
-		if (numa_fake >= MAX_NUMNODES)
-			numa_fake = MAX_NUMNODES;
-	}
+	if (!strncmp(opt, "fake=", 5))
+		cmdline = opt + 5;
 #endif
 #ifdef CONFIG_ACPI_NUMA
  	if (!strncmp(opt,"noacpi",6))
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
index 081409a..d653d0b 100644
--- a/arch/x86_64/mm/pageattr.c
+++ b/arch/x86_64/mm/pageattr.c
@@ -180,16 +180,24 @@ __change_page_attr(unsigned long address
  */
 int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot)
 {
-	int err = 0; 
+	int err = 0, kernel_map = 0;
 	int i; 
 
+	if (address >= __START_KERNEL_map
+	    && address < __START_KERNEL_map + KERNEL_TEXT_SIZE) {
+		address = (unsigned long)__va(__pa(address));
+		kernel_map = 1;
+	}
+
 	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; 
+		if (!kernel_map || pte_present(pfn_pte(0, prot))) {
+			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) {
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 2efe215..1e76bb0 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -419,19 +419,21 @@ int __init acpi_scan_nodes(unsigned long
 		return -1;
 	}
 
+	node_possible_map = nodes_parsed;
+
 	/* Finally register nodes */
-	for_each_node_mask(i, nodes_parsed)
+	for_each_node_mask(i, node_possible_map)
 		setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 	/* Try again in case setup_node_bootmem missed one due
 	   to missing bootmem */
-	for_each_node_mask(i, nodes_parsed)
+	for_each_node_mask(i, node_possible_map)
 		if (!node_online(i))
 			setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 
 	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_to_node[i] == NUMA_NO_NODE)
 			continue;
-		if (!node_isset(cpu_to_node[i], nodes_parsed))
+		if (!node_isset(cpu_to_node[i], node_possible_map))
 			numa_set_node(i, NUMA_NO_NODE);
 	}
 	numa_init_array();
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 795bd5a..ce758ba 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -20,7 +20,6 @@ #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 8b6d3d0..14104ff 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -19,7 +19,6 @@ #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/signal.h>
 
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index c6d9880..5810767 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -17,7 +17,6 @@ #include <asm/coprocessor.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index ab63700..4fbd66a 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -198,7 +198,7 @@ #endif
   __ftr_fixup : { *(__ftr_fixup) }
   __stop___ftr_fixup = .;
 
-  . = ALIGN(32);
+  . = ALIGN(4096);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 0b4cb93..cd7e6a0 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -18,7 +18,6 @@ #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <linux/in6.h>
-#include <linux/pci.h>
 #include <linux/ide.h>
 
 #include <asm/uaccess.h>
diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile
index ed935b5..6c4fdd8 100644
--- a/arch/xtensa/lib/Makefile
+++ b/arch/xtensa/lib/Makefile
@@ -2,6 +2,6 @@ #
 # Makefile for Xtensa-specific library files.
 #
 
-lib-y	+= memcopy.o memset.o checksum.o strcasecmp.o \
+lib-y	+= memcopy.o memset.o checksum.o \
 	   usercopy.o strncpy_user.o strnlen_user.o
 lib-$(CONFIG_PCI) += pci-auto.o
diff --git a/arch/xtensa/lib/strcasecmp.c b/arch/xtensa/lib/strcasecmp.c
deleted file mode 100644
index 165b2d6..0000000
--- a/arch/xtensa/lib/strcasecmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  linux/arch/xtensa/lib/strcasecmp.c
- *
- *  This file is subject to the terms and conditions of the GNU General
- *  Public License.  See the file "COPYING" in the main directory of
- *  this archive for more details.
- *
- *  Copyright (C) 2002 Tensilica Inc.
- */
-
-#include <linux/string.h>
-
-
-/* We handle nothing here except the C locale.  Since this is used in
-   only one place, on strings known to contain only 7 bit ASCII, this
-   is ok.  */
-
-int strcasecmp(const char *a, const char *b)
-{
-	int ca, cb;
-
-	do {
-		ca = *a++ & 0xff;
-		cb = *b++ & 0xff;
-		if (ca >= 'A' && ca <= 'Z')
-			ca += 'a' - 'A';
-		if (cb >= 'A' && cb <= 'Z')
-			cb += 'a' - 'A';
-	} while (ca == cb && ca != '\0');
-
-	return ca - cb;
-}
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
index 8ebfc87..4bfe333 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -251,7 +251,7 @@ static int tuntap_open(struct iss_net_pr
 
 	memset(&ifr, 0, sizeof ifr);
 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-	strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1);
+	strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name);
 
 	if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
 		printk("Failed to set interface, returned %d "
@@ -386,7 +386,7 @@ static int iss_net_rx(struct net_device 
 	/* Setup skb */
 
 	skb->dev = dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	pkt_len = lp->tp.read(lp, &skb);
 	skb_put(skb, pkt_len);
 
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c
index c8a42b6..f60c8cf 100644
--- a/arch/xtensa/platform-iss/setup.c
+++ b/arch/xtensa/platform-iss/setup.c
@@ -20,7 +20,6 @@ #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/reboot.h>
-#include <linux/pci.h>
 #include <linux/kdev_t.h>
 #include <linux/types.h>
 #include <linux/major.h>
diff --git a/block/as-iosched.c b/block/as-iosched.c
index ef12627..640aa83 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -569,7 +569,7 @@ static void as_update_iohist(struct as_d
 static int as_close_req(struct as_data *ad, struct as_io_context *aic,
 			struct request *rq)
 {
-	unsigned long delay;	/* milliseconds */
+	unsigned long delay;	/* jiffies */
 	sector_t last = ad->last_sector[ad->batch_data_dir];
 	sector_t next = rq->sector;
 	sector_t delta; /* acceptable close offset (in sectors) */
@@ -578,11 +578,11 @@ static int as_close_req(struct as_data *
 	if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished)
 		delay = 0;
 	else
-		delay = ((jiffies - ad->antic_start) * 1000) / HZ;
+		delay = jiffies - ad->antic_start;
 
 	if (delay == 0)
 		delta = 8192;
-	else if (delay <= 20 && delay <= ad->antic_expire)
+	else if (delay <= (20 * HZ / 1000) && delay <= ad->antic_expire)
 		delta = 8192 << delay;
 	else
 		return 1;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f92ba2a..baef5fc 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
-#include <linux/hash.h>
 #include <linux/rbtree.h>
 #include <linux/ioprio.h>
 
@@ -26,19 +25,17 @@ static int cfq_slice_async = HZ / 25;
 static const int cfq_slice_async_rq = 2;
 static int cfq_slice_idle = HZ / 125;
 
+/*
+ * grace period before allowing idle class to get disk access
+ */
 #define CFQ_IDLE_GRACE		(HZ / 10)
-#define CFQ_SLICE_SCALE		(5)
-
-#define CFQ_KEY_ASYNC		(0)
 
 /*
- * for the hash of cfqq inside the cfqd
+ * below this threshold, we consider thinktime immediate
  */
-#define CFQ_QHASH_SHIFT		6
-#define CFQ_QHASH_ENTRIES	(1 << CFQ_QHASH_SHIFT)
-#define list_entry_qhash(entry)	hlist_entry((entry), struct cfq_queue, cfq_hash)
+#define CFQ_MIN_TT		(2)
 
-#define list_entry_cfqq(ptr)	list_entry((ptr), struct cfq_queue, cfq_list)
+#define CFQ_SLICE_SCALE		(5)
 
 #define RQ_CIC(rq)		((struct cfq_io_context*)(rq)->elevator_private)
 #define RQ_CFQQ(rq)		((rq)->elevator_private2)
@@ -56,17 +53,21 @@ #define cfq_class_rt(cfqq)	((cfqq)->iopr
 #define ASYNC			(0)
 #define SYNC			(1)
 
-#define cfq_cfqq_dispatched(cfqq)	\
-	((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
-
-#define cfq_cfqq_class_sync(cfqq)	((cfqq)->key != CFQ_KEY_ASYNC)
-
-#define cfq_cfqq_sync(cfqq)		\
-	(cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
-
 #define sample_valid(samples)	((samples) > 80)
 
 /*
+ * Most of our rbtree usage is for sorting with min extraction, so
+ * if we cache the leftmost node we don't have to walk down the tree
+ * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should
+ * move this into the elevator for the rq sorting as well.
+ */
+struct cfq_rb_root {
+	struct rb_root rb;
+	struct rb_node *left;
+};
+#define CFQ_RB_ROOT	(struct cfq_rb_root) { RB_ROOT, NULL, }
+
+/*
  * Per block device queue structure
  */
 struct cfq_data {
@@ -75,18 +76,11 @@ struct cfq_data {
 	/*
 	 * rr list of queues with requests and the count of them
 	 */
-	struct list_head rr_list[CFQ_PRIO_LISTS];
-	struct list_head busy_rr;
-	struct list_head cur_rr;
-	struct list_head idle_rr;
+	struct cfq_rb_root service_tree;
 	unsigned int busy_queues;
 
-	/*
-	 * cfqq lookup hash
-	 */
-	struct hlist_head *cfq_hash;
-
 	int rq_in_driver;
+	int sync_flight;
 	int hw_tag;
 
 	/*
@@ -97,12 +91,10 @@ struct cfq_data {
 
 	struct cfq_queue *active_queue;
 	struct cfq_io_context *active_cic;
-	int cur_prio, cur_end_prio;
-	unsigned int dispatch_slice;
 
 	struct timer_list idle_class_timer;
 
-	sector_t last_sector;
+	sector_t last_position;
 	unsigned long last_end_request;
 
 	/*
@@ -117,6 +109,9 @@ struct cfq_data {
 	unsigned int cfq_slice_idle;
 
 	struct list_head cic_list;
+
+	sector_t new_seek_mean;
+	u64 new_seek_total;
 };
 
 /*
@@ -127,12 +122,10 @@ struct cfq_queue {
 	atomic_t ref;
 	/* parent cfq_data */
 	struct cfq_data *cfqd;
-	/* cfqq lookup hash */
-	struct hlist_node cfq_hash;
-	/* hash key */
-	unsigned int key;
-	/* member of the rr/busy/cur/idle cfqd list */
-	struct list_head cfq_list;
+	/* service_tree member */
+	struct rb_node rb_node;
+	/* service_tree key */
+	unsigned long rb_key;
 	/* sorted list of pending requests */
 	struct rb_root sort_list;
 	/* if fifo isn't expired, next request to serve */
@@ -147,11 +140,10 @@ struct cfq_queue {
 	struct list_head fifo;
 
 	unsigned long slice_end;
-	unsigned long service_last;
 	long slice_resid;
 
-	/* number of requests that are on the dispatch list */
-	int on_dispatch[2];
+	/* number of requests that are on the dispatch list or inside driver */
+	int dispatched;
 
 	/* io prio of this group */
 	unsigned short ioprio, org_ioprio;
@@ -159,6 +151,8 @@ struct cfq_queue {
 
 	/* various state flags, see below */
 	unsigned int flags;
+
+	sector_t last_request_pos;
 };
 
 enum cfqq_state_flags {
@@ -172,6 +166,7 @@ enum cfqq_state_flags {
 	CFQ_CFQQ_FLAG_prio_changed,	/* task priority has changed */
 	CFQ_CFQQ_FLAG_queue_new,	/* queue never been serviced */
 	CFQ_CFQQ_FLAG_slice_new,	/* no requests dispatched in slice */
+	CFQ_CFQQ_FLAG_sync,		/* synchronous queue */
 };
 
 #define CFQ_CFQQ_FNS(name)						\
@@ -198,11 +193,38 @@ CFQ_CFQQ_FNS(idle_window);
 CFQ_CFQQ_FNS(prio_changed);
 CFQ_CFQQ_FNS(queue_new);
 CFQ_CFQQ_FNS(slice_new);
+CFQ_CFQQ_FNS(sync);
 #undef CFQ_CFQQ_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 request *);
-static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
+static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+				       struct task_struct *, gfp_t);
+static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
+						struct io_context *);
+
+static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
+					    int is_sync)
+{
+	return cic->cfqq[!!is_sync];
+}
+
+static inline void cic_set_cfqq(struct cfq_io_context *cic,
+				struct cfq_queue *cfqq, int is_sync)
+{
+	cic->cfqq[!!is_sync] = cfqq;
+}
+
+/*
+ * We regard a request as SYNC, if it's either a read or has the SYNC bit
+ * set (in which case it could also be direct WRITE).
+ */
+static inline int cfq_bio_sync(struct bio *bio)
+{
+	if (bio_data_dir(bio) == READ || bio_sync(bio))
+		return 1;
+
+	return 0;
+}
 
 /*
  * scheduler run of queue, if there are requests pending and no one in the
@@ -221,44 +243,31 @@ static int cfq_queue_empty(request_queue
 	return !cfqd->busy_queues;
 }
 
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
-{
-	/*
-	 * Use the per-process queue, for read requests and syncronous writes
-	 */
-	if (!(rw & REQ_RW) || is_sync)
-		return task->pid;
-
-	return CFQ_KEY_ASYNC;
-}
-
 /*
  * Scale schedule slice based on io priority. Use the sync time slice only
  * if a queue is marked sync and has sync io queued. A sync queue with async
  * io only, should not get full sync slice length.
  */
-static inline int
-cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync,
+				 unsigned short prio)
 {
-	const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+	const int base_slice = cfqd->cfq_slice[sync];
 
-	WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+	WARN_ON(prio >= IOPRIO_BE_NR);
+
+	return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - prio));
+}
 
-	return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
 }
 
 static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
 	cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
-	cfqq->slice_end += cfqq->slice_resid;
-
-	/*
-	 * Don't carry over residual for more than one slice, we only want
-	 * to slightly correct the fairness. Carrying over forever would
-	 * easily introduce oscillations.
-	 */
-	cfqq->slice_resid = 0;
 }
 
 /*
@@ -307,7 +316,7 @@ #define CFQ_RQ2_WRAP	0x02 /* request 2 w
 	s1 = rq1->sector;
 	s2 = rq2->sector;
 
-	last = cfqd->last_sector;
+	last = cfqd->last_position;
 
 	/*
 	 * by definition, 1KiB is 2 sectors
@@ -372,6 +381,26 @@ #define CFQ_RQ2_WRAP	0x02 /* request 2 w
 }
 
 /*
+ * The below is leftmost cache rbtree addon
+ */
+static struct rb_node *cfq_rb_first(struct cfq_rb_root *root)
+{
+	if (!root->left)
+		root->left = rb_first(&root->rb);
+
+	return root->left;
+}
+
+static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
+{
+	if (root->left == n)
+		root->left = NULL;
+
+	rb_erase(n, &root->rb);
+	RB_CLEAR_NODE(n);
+}
+
+/*
  * would be nice to take fifo expire time into account as well
  */
 static struct request *
@@ -398,78 +427,96 @@ cfq_find_next_rq(struct cfq_data *cfqd, 
 	return cfq_choose_req(cfqd, next, prev);
 }
 
-static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
+static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+				      struct cfq_queue *cfqq)
 {
-	struct cfq_data *cfqd = cfqq->cfqd;
-	struct list_head *list, *n;
-	struct cfq_queue *__cfqq;
-
 	/*
-	 * Resorting requires the cfqq to be on the RR list already.
+	 * just an approximation, should be ok.
 	 */
-	if (!cfq_cfqq_on_rr(cfqq))
-		return;
+	return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) -
+		       cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio));
+}
 
-	list_del(&cfqq->cfq_list);
+/*
+ * The cfqd->service_tree holds all pending cfq_queue's that have
+ * requests waiting to be processed. It is sorted in the order that
+ * we will service the queues.
+ */
+static void cfq_service_tree_add(struct cfq_data *cfqd,
+				    struct cfq_queue *cfqq, int add_front)
+{
+	struct rb_node **p = &cfqd->service_tree.rb.rb_node;
+	struct rb_node *parent = NULL;
+	unsigned long rb_key;
+	int left;
+
+	if (!add_front) {
+		rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
+		rb_key += cfqq->slice_resid;
+		cfqq->slice_resid = 0;
+	} else
+		rb_key = 0;
 
-	if (cfq_class_rt(cfqq))
-		list = &cfqd->cur_rr;
-	else if (cfq_class_idle(cfqq))
-		list = &cfqd->idle_rr;
-	else {
+	if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
 		/*
-		 * if cfqq has requests in flight, don't allow it to be
-		 * found in cfq_set_active_queue before it has finished them.
-		 * this is done to increase fairness between a process that
-		 * has lots of io pending vs one that only generates one
-		 * sporadically or synchronously
+		 * same position, nothing more to do
 		 */
-		if (cfq_cfqq_dispatched(cfqq))
-			list = &cfqd->busy_rr;
-		else
-			list = &cfqd->rr_list[cfqq->ioprio];
+		if (rb_key == cfqq->rb_key)
+			return;
+
+		cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
 	}
 
-	if (preempted || cfq_cfqq_queue_new(cfqq)) {
-		/*
-		 * If this queue was preempted or is new (never been serviced),
-		 * let it be added first for fairness but beind other new
-		 * queues.
-		 */
-		n = list;
-		while (n->next != list) {
-			__cfqq = list_entry_cfqq(n->next);
-			if (!cfq_cfqq_queue_new(__cfqq))
-				break;
+	left = 1;
+	while (*p) {
+		struct cfq_queue *__cfqq;
+		struct rb_node **n;
+
+		parent = *p;
+		__cfqq = rb_entry(parent, struct cfq_queue, rb_node);
 
-			n = n->next;
-		}
-		list_add_tail(&cfqq->cfq_list, n);
-	} else if (!cfq_cfqq_class_sync(cfqq)) {
-		/*
-		 * async queue always goes to the end. this wont be overly
-		 * unfair to writes, as the sort of the sync queue wont be
-		 * allowed to pass the async queue again.
-		 */
-		list_add_tail(&cfqq->cfq_list, list);
-	} else {
 		/*
-		 * sort by last service, but don't cross a new or async
-		 * queue. we don't cross a new queue because it hasn't been
-		 * service before, and we don't cross an async queue because
-		 * it gets added to the end on expire.
+		 * sort RT queues first, we always want to give
+		 * preference to them. IDLE queues goes to the back.
+		 * after that, sort on the next service time.
 		 */
-		n = list;
-		while ((n = n->prev) != list) {
-			struct cfq_queue *__cfqq = list_entry_cfqq(n);
+		if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq))
+			n = &(*p)->rb_left;
+		else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq))
+			n = &(*p)->rb_right;
+		else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq))
+			n = &(*p)->rb_left;
+		else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
+			n = &(*p)->rb_right;
+		else if (rb_key < __cfqq->rb_key)
+			n = &(*p)->rb_left;
+		else
+			n = &(*p)->rb_right;
 
-			if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last)
-				break;
-			if (time_before(__cfqq->service_last, cfqq->service_last))
-				break;
-		}
-		list_add(&cfqq->cfq_list, n);
+		if (n == &(*p)->rb_right)
+			left = 0;
+
+		p = n;
 	}
+
+	if (left)
+		cfqd->service_tree.left = &cfqq->rb_node;
+
+	cfqq->rb_key = rb_key;
+	rb_link_node(&cfqq->rb_node, parent, p);
+	rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb);
+}
+
+/*
+ * Update cfqq's position in the service tree.
+ */
+static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+	/*
+	 * Resorting requires the cfqq to be on the RR list already.
+	 */
+	if (cfq_cfqq_on_rr(cfqq))
+		cfq_service_tree_add(cfqd, cfqq, 0);
 }
 
 /*
@@ -483,15 +530,21 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, s
 	cfq_mark_cfqq_on_rr(cfqq);
 	cfqd->busy_queues++;
 
-	cfq_resort_rr_list(cfqq, 0);
+	cfq_resort_rr_list(cfqd, cfqq);
 }
 
+/*
+ * Called when the cfqq no longer has requests pending, remove it from
+ * the service tree.
+ */
 static inline void
 cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
 	BUG_ON(!cfq_cfqq_on_rr(cfqq));
 	cfq_clear_cfqq_on_rr(cfqq);
-	list_del_init(&cfqq->cfq_list);
+
+	if (!RB_EMPTY_NODE(&cfqq->rb_node))
+		cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
 
 	BUG_ON(!cfqd->busy_queues);
 	cfqd->busy_queues--;
@@ -552,10 +605,14 @@ static struct request *
 cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
 {
 	struct task_struct *tsk = current;
-	pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio));
+	struct cfq_io_context *cic;
 	struct cfq_queue *cfqq;
 
-	cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+	if (!cic)
+		return NULL;
+
+	cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
 	if (cfqq) {
 		sector_t sector = bio->bi_sector + bio_sectors(bio);
 
@@ -579,6 +636,8 @@ static void cfq_activate_request(request
 	 */
 	if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
 		cfqd->hw_tag = 1;
+
+	cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
 }
 
 static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
@@ -605,8 +664,7 @@ static void cfq_remove_request(struct re
 	}
 }
 
-static int
-cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct request *__rq;
@@ -648,23 +706,24 @@ static int cfq_allow_merge(request_queue
 			   struct bio *bio)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
-	const int rw = bio_data_dir(bio);
+	struct cfq_io_context *cic;
 	struct cfq_queue *cfqq;
-	pid_t key;
 
 	/*
 	 * Disallow merge of a sync bio into an async request.
 	 */
-	if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq))
+	if (cfq_bio_sync(bio) && !rq_is_sync(rq))
 		return 0;
 
 	/*
 	 * Lookup the cfqq that this bio will be queued with. Allow
 	 * merge only if rq is queued there.
 	 */
-	key = cfq_queue_pid(current, rw, bio_sync(bio));
-	cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
+	cic = cfq_cic_rb_lookup(cfqd, current->io_context);
+	if (!cic)
+		return 0;
 
+	cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
 	if (cfqq == RQ_CFQQ(rq))
 		return 1;
 
@@ -684,6 +743,7 @@ __cfq_set_active_queue(struct cfq_data *
 		cfq_clear_cfqq_must_alloc_slice(cfqq);
 		cfq_clear_cfqq_fifo_expire(cfqq);
 		cfq_mark_cfqq_slice_new(cfqq);
+		cfq_clear_cfqq_queue_new(cfqq);
 	}
 
 	cfqd->active_queue = cfqq;
@@ -694,23 +754,21 @@ __cfq_set_active_queue(struct cfq_data *
  */
 static void
 __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-		    int preempted, int timed_out)
+		    int timed_out)
 {
 	if (cfq_cfqq_wait_request(cfqq))
 		del_timer(&cfqd->idle_slice_timer);
 
 	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
-	 * or was preempted
+	 * store what was left of this slice, if the queue idled/timed out
 	 */
 	if (timed_out && !cfq_cfqq_slice_new(cfqq))
 		cfqq->slice_resid = cfqq->slice_end - jiffies;
 
-	cfq_resort_rr_list(cfqq, preempted);
+	cfq_resort_rr_list(cfqd, cfqq);
 
 	if (cfqq == cfqd->active_queue)
 		cfqd->active_queue = NULL;
@@ -719,163 +777,152 @@ __cfq_slice_expired(struct cfq_data *cfq
 		put_io_context(cfqd->active_cic->ioc);
 		cfqd->active_cic = NULL;
 	}
-
-	cfqd->dispatch_slice = 0;
 }
 
-static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted,
-				     int timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
 {
 	struct cfq_queue *cfqq = cfqd->active_queue;
 
 	if (cfqq)
-		__cfq_slice_expired(cfqd, cfqq, preempted, timed_out);
+		__cfq_slice_expired(cfqd, cfqq, timed_out);
 }
 
 /*
- * 0
- * 0,1
- * 0,1,2
- * 0,1,2,3
- * 0,1,2,3,4
- * 0,1,2,3,4,5
- * 0,1,2,3,4,5,6
- * 0,1,2,3,4,5,6,7
+ * Get next queue for service. Unless we have a queue preemption,
+ * we'll simply select the first cfqq in the service tree.
  */
-static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
 {
-	int prio, wrap;
+	struct cfq_queue *cfqq;
+	struct rb_node *n;
 
-	prio = -1;
-	wrap = 0;
-	do {
-		int p;
+	if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+		return NULL;
 
-		for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
-			if (!list_empty(&cfqd->rr_list[p])) {
-				prio = p;
-				break;
-			}
-		}
+	n = cfq_rb_first(&cfqd->service_tree);
+	cfqq = rb_entry(n, struct cfq_queue, rb_node);
 
-		if (prio != -1)
-			break;
-		cfqd->cur_prio = 0;
-		if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-			cfqd->cur_end_prio = 0;
-			if (wrap)
-				break;
-			wrap = 1;
-		}
-	} while (1);
+	if (cfq_class_idle(cfqq)) {
+		unsigned long end;
 
-	if (unlikely(prio == -1))
-		return -1;
+		/*
+		 * 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
+		 */
+		end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+		if (time_before(jiffies, end)) {
+			mod_timer(&cfqd->idle_class_timer, end);
+			cfqq = NULL;
+		}
+	}
 
-	BUG_ON(prio >= CFQ_PRIO_LISTS);
+	return cfqq;
+}
 
-	list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+/*
+ * Get and set a new active queue for service.
+ */
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+	struct cfq_queue *cfqq;
 
-	cfqd->cur_prio = prio + 1;
-	if (cfqd->cur_prio > cfqd->cur_end_prio) {
-		cfqd->cur_end_prio = cfqd->cur_prio;
-		cfqd->cur_prio = 0;
-	}
-	if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
-		cfqd->cur_prio = 0;
-		cfqd->cur_end_prio = 0;
-	}
+	cfqq = cfq_get_next_queue(cfqd);
+	__cfq_set_active_queue(cfqd, cfqq);
+	return cfqq;
+}
 
-	return prio;
+static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
+					  struct request *rq)
+{
+	if (rq->sector >= cfqd->last_position)
+		return rq->sector - cfqd->last_position;
+	else
+		return cfqd->last_position - rq->sector;
 }
 
-static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
 {
-	struct cfq_queue *cfqq = NULL;
+	struct cfq_io_context *cic = cfqd->active_cic;
 
-	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);
-	} 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);
-	} 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 (!sample_valid(cic->seek_samples))
+		return 0;
 
-		if (time_after_eq(jiffies, end))
-			cfqq = list_entry_cfqq(cfqd->idle_rr.next);
-		else
-			mod_timer(&cfqd->idle_class_timer, end);
-	}
+	return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean;
+}
 
-	__cfq_set_active_queue(cfqd, cfqq);
-	return cfqq;
+static int cfq_close_cooperator(struct cfq_data *cfq_data,
+				struct cfq_queue *cfqq)
+{
+	/*
+	 * We should notice if some of the queues are cooperating, eg
+	 * working closely on the same area of the disk. In that case,
+	 * we can group them together and don't waste time idling.
+	 */
+	return 0;
 }
 
-#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024))
+#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024))
 
-static int cfq_arm_slice_timer(struct cfq_data *cfqd)
+static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 {
 	struct cfq_queue *cfqq = cfqd->active_queue;
 	struct cfq_io_context *cic;
 	unsigned long sl;
 
 	WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
+	WARN_ON(cfq_cfqq_slice_new(cfqq));
 
 	/*
 	 * idle is disabled, either manually or by past process history
 	 */
-	if (!cfqd->cfq_slice_idle)
-		return 0;
-	if (!cfq_cfqq_idle_window(cfqq))
-		return 0;
+	if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
+		return;
+
 	/*
 	 * task has exited, don't wait
 	 */
 	cic = cfqd->active_cic;
 	if (!cic || !cic->ioc->task)
-		return 0;
+		return;
+
+	/*
+	 * See if this prio level has a good candidate
+	 */
+	if (cfq_close_cooperator(cfqd, cfqq) &&
+	    (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2))
+		return;
 
 	cfq_mark_cfqq_must_dispatch(cfqq);
 	cfq_mark_cfqq_wait_request(cfqq);
 
-	sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
-
 	/*
 	 * we don't want to idle for seeks, but we do want to allow
 	 * fair distribution of slice time for a process doing back-to-back
 	 * seeks. so allow a little bit of time for him to submit a new rq
 	 */
+	sl = cfqd->cfq_slice_idle;
 	if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
-		sl = min(sl, msecs_to_jiffies(2));
+		sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
 
 	mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
-	return 1;
 }
 
+/*
+ * Move request from internal lists to the request queue dispatch list.
+ */
 static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct cfq_queue *cfqq = RQ_CFQQ(rq);
 
 	cfq_remove_request(rq);
-	cfqq->on_dispatch[rq_is_sync(rq)]++;
+	cfqq->dispatched++;
 	elv_dispatch_sort(q, rq);
 
-	rq = list_entry(q->queue_head.prev, struct request, queuelist);
-	cfqd->last_sector = rq->sector + rq->nr_sectors;
+	if (cfq_cfqq_sync(cfqq))
+		cfqd->sync_flight++;
 }
 
 /*
@@ -895,13 +942,13 @@ static inline struct request *cfq_check_
 	if (list_empty(&cfqq->fifo))
 		return NULL;
 
-	fifo = cfq_cfqq_class_sync(cfqq);
+	fifo = cfq_cfqq_sync(cfqq);
 	rq = rq_entry_fifo(cfqq->fifo.next);
 
-	if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
-		return rq;
+	if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
+		return NULL;
 
-	return NULL;
+	return rq;
 }
 
 static inline int
@@ -915,7 +962,8 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd,
 }
 
 /*
- * get next queue for service
+ * Select a queue for service. If we have a current active queue,
+ * check whether to continue servicing it, or retrieve and set a new one.
  */
 static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
 {
@@ -926,33 +974,41 @@ static struct cfq_queue *cfq_select_queu
 		goto new_queue;
 
 	/*
-	 * slice has expired
+	 * The active queue has run out of time, expire it and select new.
 	 */
-	if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq))
+	if (cfq_slice_used(cfqq))
 		goto expire;
 
 	/*
-	 * if queue has requests, dispatch one. if not, check if
-	 * enough slice is left to wait for one
+	 * The active queue has requests and isn't expired, allow it to
+	 * dispatch.
 	 */
 	if (!RB_EMPTY_ROOT(&cfqq->sort_list))
 		goto keep_queue;
-	else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) {
+
+	/*
+	 * No requests pending. If the active queue still has requests in
+	 * flight or is idling for a new request, allow either of these
+	 * conditions to happen (or time out) before selecting a new queue.
+	 */
+	if (timer_pending(&cfqd->idle_slice_timer) ||
+	    (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
 		cfqq = NULL;
 		goto keep_queue;
-	} else if (cfq_cfqq_class_sync(cfqq)) {
-		if (cfq_arm_slice_timer(cfqd))
-			return NULL;
 	}
 
 expire:
-	cfq_slice_expired(cfqd, 0, 0);
+	cfq_slice_expired(cfqd, 0);
 new_queue:
 	cfqq = cfq_set_active_queue(cfqd);
 keep_queue:
 	return cfqq;
 }
 
+/*
+ * Dispatch some requests from cfqq, moving them to the request queue
+ * dispatch list.
+ */
 static int
 __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 			int max_dispatch)
@@ -975,7 +1031,6 @@ __cfq_dispatch_requests(struct cfq_data 
 		 */
 		cfq_dispatch_insert(cfqd->queue, rq);
 
-		cfqd->dispatch_slice++;
 		dispatched++;
 
 		if (!cfqd->active_cic) {
@@ -993,57 +1048,54 @@ __cfq_dispatch_requests(struct cfq_data 
 	 * queue always expire after 1 dispatch round.
 	 */
 	if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) &&
-	    cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+	    dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
 	    cfq_class_idle(cfqq))) {
 		cfqq->slice_end = jiffies + 1;
-		cfq_slice_expired(cfqd, 0, 0);
+		cfq_slice_expired(cfqd, 0);
 	}
 
 	return dispatched;
 }
 
-static int
-cfq_forced_dispatch_cfqqs(struct list_head *list)
+static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
 {
-	struct cfq_queue *cfqq, *next;
-	int dispatched;
+	int dispatched = 0;
 
-	dispatched = 0;
-	list_for_each_entry_safe(cfqq, next, list, cfq_list) {
-		while (cfqq->next_rq) {
-			cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
-			dispatched++;
-		}
-		BUG_ON(!list_empty(&cfqq->fifo));
+	while (cfqq->next_rq) {
+		cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
+		dispatched++;
 	}
 
+	BUG_ON(!list_empty(&cfqq->fifo));
 	return dispatched;
 }
 
-static int
-cfq_forced_dispatch(struct cfq_data *cfqd)
+/*
+ * Drain our current requests. Used for barriers and when switching
+ * io schedulers on-the-fly.
+ */
+static int cfq_forced_dispatch(struct cfq_data *cfqd)
 {
-	int i, dispatched = 0;
+	int dispatched = 0;
+	struct rb_node *n;
 
-	for (i = 0; i < CFQ_PRIO_LISTS; i++)
-		dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
+	while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
+		struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
 
-	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
-	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
-	dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
+		dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+	}
 
-	cfq_slice_expired(cfqd, 0, 0);
+	cfq_slice_expired(cfqd, 0);
 
 	BUG_ON(cfqd->busy_queues);
 
 	return dispatched;
 }
 
-static int
-cfq_dispatch_requests(request_queue_t *q, int force)
+static int cfq_dispatch_requests(request_queue_t *q, int force)
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
-	struct cfq_queue *cfqq, *prev_cfqq;
+	struct cfq_queue *cfqq;
 	int dispatched;
 
 	if (!cfqd->busy_queues)
@@ -1053,36 +1105,28 @@ cfq_dispatch_requests(request_queue_t *q
 		return cfq_forced_dispatch(cfqd);
 
 	dispatched = 0;
-	prev_cfqq = NULL;
 	while ((cfqq = cfq_select_queue(cfqd)) != NULL) {
 		int max_dispatch;
 
-		if (cfqd->busy_queues > 1) {
-			/*
-			 * Don't repeat dispatch from the previous queue.
-			 */
-			if (prev_cfqq == cfqq)
-				break;
+		max_dispatch = cfqd->cfq_quantum;
+		if (cfq_class_idle(cfqq))
+			max_dispatch = 1;
 
-			/*
-			 * So we have dispatched before in this round, if the
-			 * next queue has idling enabled (must be sync), don't
-			 * allow it service until the previous have continued.
-			 */
-			if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq))
+		if (cfqq->dispatched >= max_dispatch) {
+			if (cfqd->busy_queues > 1)
+				break;
+			if (cfqq->dispatched >= 4 * max_dispatch)
 				break;
 		}
 
+		if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+			break;
+
 		cfq_clear_cfqq_must_dispatch(cfqq);
 		cfq_clear_cfqq_wait_request(cfqq);
 		del_timer(&cfqd->idle_slice_timer);
 
-		max_dispatch = cfqd->cfq_quantum;
-		if (cfq_class_idle(cfqq))
-			max_dispatch = 1;
-
 		dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
-		prev_cfqq = cfqq;
 	}
 
 	return dispatched;
@@ -1108,48 +1152,21 @@ static void cfq_put_queue(struct cfq_que
 	BUG_ON(cfq_cfqq_on_rr(cfqq));
 
 	if (unlikely(cfqd->active_queue == cfqq)) {
-		__cfq_slice_expired(cfqd, cfqq, 0, 0);
+		__cfq_slice_expired(cfqd, cfqq, 0);
 		cfq_schedule_dispatch(cfqd);
 	}
 
-	/*
-	 * it's on the empty list and still hashed
-	 */
-	list_del(&cfqq->cfq_list);
-	hlist_del(&cfqq->cfq_hash);
 	kmem_cache_free(cfq_pool, cfqq);
 }
 
-static struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
-		    const int hashval)
-{
-	struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
-	struct hlist_node *entry;
-	struct cfq_queue *__cfqq;
-
-	hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
-		const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
-
-		if (__cfqq->key == key && (__p == prio || !prio))
-			return __cfqq;
-	}
-
-	return NULL;
-}
-
-static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
-{
-	return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
-}
-
 static void cfq_free_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
 	struct rb_node *n;
 	int freed = 0;
 
+	ioc->ioc_data = NULL;
+
 	while ((n = rb_first(&ioc->cic_root)) != NULL) {
 		__cic = rb_entry(n, struct cfq_io_context, rb_node);
 		rb_erase(&__cic->rb_node, &ioc->cic_root);
@@ -1166,7 +1183,7 @@ static void cfq_free_io_context(struct i
 static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
 	if (unlikely(cfqq == cfqd->active_queue)) {
-		__cfq_slice_expired(cfqd, cfqq, 0, 0);
+		__cfq_slice_expired(cfqd, cfqq, 0);
 		cfq_schedule_dispatch(cfqd);
 	}
 
@@ -1191,10 +1208,6 @@ static void __cfq_exit_single_io_context
 	}
 }
 
-
-/*
- * Called with interrupts disabled
- */
 static void cfq_exit_single_io_context(struct cfq_io_context *cic)
 {
 	struct cfq_data *cfqd = cic->key;
@@ -1208,15 +1221,20 @@ static void cfq_exit_single_io_context(s
 	}
 }
 
+/*
+ * The process that ioc belongs to has exited, we need to clean up
+ * and put the internal structures we have that belongs to that process.
+ */
 static void cfq_exit_io_context(struct io_context *ioc)
 {
 	struct cfq_io_context *__cic;
 	struct rb_node *n;
 
+	ioc->ioc_data = NULL;
+
 	/*
 	 * put the reference this task is holding to the various queues
 	 */
-
 	n = rb_first(&ioc->cic_root);
 	while (n != NULL) {
 		__cic = rb_entry(n, struct cfq_io_context, rb_node);
@@ -1284,8 +1302,6 @@ static void cfq_init_prio_data(struct cf
 	 */
 	cfqq->org_ioprio = cfqq->ioprio;
 	cfqq->org_ioprio_class = cfqq->ioprio_class;
-
-	cfq_resort_rr_list(cfqq, 0);
 	cfq_clear_cfqq_prio_changed(cfqq);
 }
 
@@ -1303,7 +1319,7 @@ static inline void changed_ioprio(struct
 	cfqq = cic->cfqq[ASYNC];
 	if (cfqq) {
 		struct cfq_queue *new_cfqq;
-		new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task,
+		new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
 					 GFP_ATOMIC);
 		if (new_cfqq) {
 			cic->cfqq[ASYNC] = new_cfqq;
@@ -1335,16 +1351,16 @@ static void cfq_ioc_set_ioprio(struct io
 }
 
 static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk,
+cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
 	      gfp_t gfp_mask)
 {
-	const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
 	struct cfq_queue *cfqq, *new_cfqq = NULL;
-	unsigned short ioprio;
+	struct cfq_io_context *cic;
 
 retry:
-	ioprio = tsk->ioprio;
-	cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+	/* cic always exists here */
+	cfqq = cic_to_cfqq(cic, is_sync);
 
 	if (!cfqq) {
 		if (new_cfqq) {
@@ -1369,20 +1385,20 @@ retry:
 
 		memset(cfqq, 0, sizeof(*cfqq));
 
-		INIT_HLIST_NODE(&cfqq->cfq_hash);
-		INIT_LIST_HEAD(&cfqq->cfq_list);
+		RB_CLEAR_NODE(&cfqq->rb_node);
 		INIT_LIST_HEAD(&cfqq->fifo);
 
-		cfqq->key = key;
-		hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
 		atomic_set(&cfqq->ref, 0);
 		cfqq->cfqd = cfqd;
 
-		if (key != CFQ_KEY_ASYNC)
+		if (is_sync) {
 			cfq_mark_cfqq_idle_window(cfqq);
+			cfq_mark_cfqq_sync(cfqq);
+		}
 
 		cfq_mark_cfqq_prio_changed(cfqq);
 		cfq_mark_cfqq_queue_new(cfqq);
+
 		cfq_init_prio_data(cfqq);
 	}
 
@@ -1395,10 +1411,17 @@ out:
 	return cfqq;
 }
 
+/*
+ * We drop cfq io contexts lazily, so we may find a dead one.
+ */
 static void
 cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
 {
 	WARN_ON(!list_empty(&cic->queue_list));
+
+	if (ioc->ioc_data == cic)
+		ioc->ioc_data = NULL;
+
 	rb_erase(&cic->rb_node, &ioc->cic_root);
 	kmem_cache_free(cfq_ioc_pool, cic);
 	elv_ioc_count_dec(ioc_count);
@@ -1411,6 +1434,16 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd,
 	struct cfq_io_context *cic;
 	void *k, *key = cfqd;
 
+	if (unlikely(!ioc))
+		return NULL;
+
+	/*
+	 * we maintain a last-hit cache, to avoid browsing over the tree
+	 */
+	cic = ioc->ioc_data;
+	if (cic && cic->key == cfqd)
+		return cic;
+
 restart:
 	n = ioc->cic_root.rb_node;
 	while (n) {
@@ -1426,8 +1459,10 @@ restart:
 			n = n->rb_left;
 		else if (key > k)
 			n = n->rb_right;
-		else
+		else {
+			ioc->ioc_data = cic;
 			return cic;
+		}
 	}
 
 	return NULL;
@@ -1524,7 +1559,8 @@ cfq_update_io_thinktime(struct cfq_data 
 }
 
 static void
-cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+		       struct request *rq)
 {
 	sector_t sdist;
 	u64 total;
@@ -1534,6 +1570,11 @@ cfq_update_io_seektime(struct cfq_io_con
 	else
 		sdist = cic->last_request_pos - rq->sector;
 
+	if (!cic->seek_samples) {
+		cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+		cfqd->new_seek_mean = cfqd->new_seek_total / 256;
+	}
+
 	/*
 	 * Don't allow the seek distance to get too large from the
 	 * odd fragment, pagein, etc
@@ -1558,7 +1599,12 @@ static void
 cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
 		       struct cfq_io_context *cic)
 {
-	int enable_idle = cfq_cfqq_idle_window(cfqq);
+	int enable_idle;
+
+	if (!cfq_cfqq_sync(cfqq))
+		return;
+
+	enable_idle = cfq_cfqq_idle_window(cfqq);
 
 	if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
 	    (cfqd->hw_tag && CIC_SEEKY(cic)))
@@ -1584,24 +1630,28 @@ static int
 cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
 		   struct request *rq)
 {
-	struct cfq_queue *cfqq = cfqd->active_queue;
+	struct cfq_queue *cfqq;
 
-	if (cfq_class_idle(new_cfqq))
+	cfqq = cfqd->active_queue;
+	if (!cfqq)
 		return 0;
 
-	if (!cfqq)
+	if (cfq_slice_used(cfqq))
+		return 1;
+
+	if (cfq_class_idle(new_cfqq))
 		return 0;
 
 	if (cfq_class_idle(cfqq))
 		return 1;
-	if (!cfq_cfqq_wait_request(new_cfqq))
-		return 0;
+
 	/*
 	 * 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.
@@ -1609,6 +1659,16 @@ cfq_should_preempt(struct cfq_data *cfqd
 	if (rq_is_meta(rq) && !cfqq->meta_pending)
 		return 1;
 
+	if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
+		return 0;
+
+	/*
+	 * if this request is as-good as one we would expect from the
+	 * current cfqq, let it preempt
+	 */
+	if (cfq_rq_close(cfqd, rq))
+		return 1;
+
 	return 0;
 }
 
@@ -1618,14 +1678,15 @@ cfq_should_preempt(struct cfq_data *cfqd
  */
 static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-	cfq_slice_expired(cfqd, 1, 1);
+	cfq_slice_expired(cfqd, 1);
 
 	/*
 	 * 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);
+
+	cfq_service_tree_add(cfqd, cfqq, 1);
 
 	cfqq->slice_end = 0;
 	cfq_mark_cfqq_slice_new(cfqq);
@@ -1644,28 +1705,12 @@ cfq_rq_enqueued(struct cfq_data *cfqd, s
 	if (rq_is_meta(rq))
 		cfqq->meta_pending++;
 
-	/*
-	 * we never wait for an async request and we don't allow preemption
-	 * of an async request. so just return early
-	 */
-	if (!rq_is_sync(rq)) {
-		/*
-		 * sync process issued an async request, if it's waiting
-		 * then expire it and kick rq handling.
-		 */
-		if (cic == cfqd->active_cic &&
-		    del_timer(&cfqd->idle_slice_timer)) {
-			cfq_slice_expired(cfqd, 0, 0);
-			blk_start_queueing(cfqd->queue);
-		}
-		return;
-	}
-
 	cfq_update_io_thinktime(cfqd, cic);
-	cfq_update_io_seektime(cic, rq);
+	cfq_update_io_seektime(cfqd, cic, rq);
 	cfq_update_idle_window(cfqd, cfqq, cic);
 
 	cic->last_request_pos = rq->sector + rq->nr_sectors;
+	cfqq->last_request_pos = cic->last_request_pos;
 
 	if (cfqq == cfqd->active_queue) {
 		/*
@@ -1714,16 +1759,16 @@ static void cfq_completed_request(reques
 	now = jiffies;
 
 	WARN_ON(!cfqd->rq_in_driver);
-	WARN_ON(!cfqq->on_dispatch[sync]);
+	WARN_ON(!cfqq->dispatched);
 	cfqd->rq_in_driver--;
-	cfqq->on_dispatch[sync]--;
-	cfqq->service_last = now;
+	cfqq->dispatched--;
+
+	if (cfq_cfqq_sync(cfqq))
+		cfqd->sync_flight--;
 
 	if (!cfq_class_idle(cfqq))
 		cfqd->last_end_request = now;
 
-	cfq_resort_rr_list(cfqq, 0);
-
 	if (sync)
 		RQ_CIC(rq)->last_end_request = now;
 
@@ -1737,12 +1782,13 @@ static void cfq_completed_request(reques
 			cfq_clear_cfqq_slice_new(cfqq);
 		}
 		if (cfq_slice_used(cfqq))
-			cfq_slice_expired(cfqd, 0, 1);
-		else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) {
-			if (!cfq_arm_slice_timer(cfqd))
-				cfq_schedule_dispatch(cfqd);
-		}
+			cfq_slice_expired(cfqd, 1);
+		else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
+			cfq_arm_slice_timer(cfqd);
 	}
+
+	if (!cfqd->rq_in_driver)
+		cfq_schedule_dispatch(cfqd);
 }
 
 /*
@@ -1751,9 +1797,6 @@ static void cfq_completed_request(reques
  */
 static void cfq_prio_boost(struct cfq_queue *cfqq)
 {
-	const int ioprio_class = cfqq->ioprio_class;
-	const int ioprio = cfqq->ioprio;
-
 	if (has_fs_excl()) {
 		/*
 		 * boost idle prio on transactions that would lock out other
@@ -1772,12 +1815,6 @@ static void cfq_prio_boost(struct cfq_qu
 		if (cfqq->ioprio != cfqq->org_ioprio)
 			cfqq->ioprio = cfqq->org_ioprio;
 	}
-
-	/*
-	 * refile between round-robin lists if we moved the priority class
-	 */
-	if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio))
-		cfq_resort_rr_list(cfqq, 0);
 }
 
 static inline int __cfq_may_queue(struct cfq_queue *cfqq)
@@ -1795,10 +1832,8 @@ static int cfq_may_queue(request_queue_t
 {
 	struct cfq_data *cfqd = q->elevator->elevator_data;
 	struct task_struct *tsk = current;
+	struct cfq_io_context *cic;
 	struct cfq_queue *cfqq;
-	unsigned int key;
-
-	key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
 
 	/*
 	 * don't force setup of a queue from here, as a call to may_queue
@@ -1806,7 +1841,11 @@ static int cfq_may_queue(request_queue_t
 	 * so just lookup a possibly existing queue, or return 'may queue'
 	 * if that fails
 	 */
-	cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+	cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+	if (!cic)
+		return ELV_MQUEUE_MAY;
+
+	cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
 	if (cfqq) {
 		cfq_init_prio_data(cfqq);
 		cfq_prio_boost(cfqq);
@@ -1850,7 +1889,6 @@ cfq_set_request(request_queue_t *q, stru
 	struct cfq_io_context *cic;
 	const int rw = rq_data_dir(rq);
 	const int is_sync = rq_is_sync(rq);
-	pid_t key = cfq_queue_pid(tsk, rw, is_sync);
 	struct cfq_queue *cfqq;
 	unsigned long flags;
 
@@ -1863,14 +1901,15 @@ cfq_set_request(request_queue_t *q, stru
 	if (!cic)
 		goto queue_fail;
 
-	if (!cic->cfqq[is_sync]) {
-		cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask);
+	cfqq = cic_to_cfqq(cic, is_sync);
+	if (!cfqq) {
+		cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
+
 		if (!cfqq)
 			goto queue_fail;
 
-		cic->cfqq[is_sync] = cfqq;
-	} else
-		cfqq = cic->cfqq[is_sync];
+		cic_set_cfqq(cic, cfqq, is_sync);
+	}
 
 	cfqq->allocated[rw]++;
 	cfq_clear_cfqq_must_alloc(cfqq);
@@ -1940,7 +1979,7 @@ static void cfq_idle_slice_timer(unsigne
 		}
 	}
 expire:
-	cfq_slice_expired(cfqd, 0, timed_out);
+	cfq_slice_expired(cfqd, timed_out);
 out_kick:
 	cfq_schedule_dispatch(cfqd);
 out_cont:
@@ -1986,7 +2025,7 @@ static void cfq_exit_queue(elevator_t *e
 	spin_lock_irq(q->queue_lock);
 
 	if (cfqd->active_queue)
-		__cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0);
+		__cfq_slice_expired(cfqd, cfqd->active_queue, 0);
 
 	while (!list_empty(&cfqd->cic_list)) {
 		struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
@@ -2000,14 +2039,12 @@ static void cfq_exit_queue(elevator_t *e
 
 	cfq_shutdown_timer_wq(cfqd);
 
-	kfree(cfqd->cfq_hash);
 	kfree(cfqd);
 }
 
 static void *cfq_init_queue(request_queue_t *q)
 {
 	struct cfq_data *cfqd;
-	int i;
 
 	cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
 	if (!cfqd)
@@ -2015,21 +2052,9 @@ static void *cfq_init_queue(request_queu
 
 	memset(cfqd, 0, sizeof(*cfqd));
 
-	for (i = 0; i < CFQ_PRIO_LISTS; i++)
-		INIT_LIST_HEAD(&cfqd->rr_list[i]);
-
-	INIT_LIST_HEAD(&cfqd->busy_rr);
-	INIT_LIST_HEAD(&cfqd->cur_rr);
-	INIT_LIST_HEAD(&cfqd->idle_rr);
+	cfqd->service_tree = CFQ_RB_ROOT;
 	INIT_LIST_HEAD(&cfqd->cic_list);
 
-	cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
-	if (!cfqd->cfq_hash)
-		goto out_free;
-
-	for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
-		INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
-
 	cfqd->queue = q;
 
 	init_timer(&cfqd->idle_slice_timer);
@@ -2053,9 +2078,6 @@ static void *cfq_init_queue(request_queu
 	cfqd->cfq_slice_idle = cfq_slice_idle;
 
 	return cfqd;
-out_free:
-	kfree(cfqd);
-	return NULL;
 }
 
 static void cfq_slab_kill(void)
@@ -2068,13 +2090,11 @@ static void cfq_slab_kill(void)
 
 static int __init cfq_slab_setup(void)
 {
-	cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
-					NULL, NULL);
+	cfq_pool = KMEM_CACHE(cfq_queue, 0);
 	if (!cfq_pool)
 		goto fail;
 
-	cfq_ioc_pool = kmem_cache_create("cfq_ioc_pool",
-			sizeof(struct cfq_io_context), 0, 0, NULL, NULL);
+	cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0);
 	if (!cfq_ioc_pool)
 		goto fail;
 
@@ -2087,7 +2107,6 @@ fail:
 /*
  * sysfs parts below -->
  */
-
 static ssize_t
 cfq_var_show(unsigned int var, char *page)
 {
diff --git a/block/elevator.c b/block/elevator.c
index 96a00c8..ce866eb 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -134,13 +134,13 @@ static struct elevator_type *elevator_ge
 {
 	struct elevator_type *e;
 
-	spin_lock_irq(&elv_list_lock);
+	spin_lock(&elv_list_lock);
 
 	e = elevator_find(name);
 	if (e && !try_module_get(e->elevator_owner))
 		e = NULL;
 
-	spin_unlock_irq(&elv_list_lock);
+	spin_unlock(&elv_list_lock);
 
 	return e;
 }
@@ -965,10 +965,11 @@ void elv_unregister_queue(struct request
 int elv_register(struct elevator_type *e)
 {
 	char *def = "";
-	spin_lock_irq(&elv_list_lock);
+
+	spin_lock(&elv_list_lock);
 	BUG_ON(elevator_find(e->elevator_name));
 	list_add_tail(&e->list, &elv_list);
-	spin_unlock_irq(&elv_list_lock);
+	spin_unlock(&elv_list_lock);
 
 	if (!strcmp(e->elevator_name, chosen_elevator) ||
 			(!*chosen_elevator &&
@@ -998,9 +999,9 @@ void elv_unregister(struct elevator_type
 		read_unlock(&tasklist_lock);
 	}
 
-	spin_lock_irq(&elv_list_lock);
+	spin_lock(&elv_list_lock);
 	list_del_init(&e->list);
-	spin_unlock_irq(&elv_list_lock);
+	spin_unlock(&elv_list_lock);
 }
 EXPORT_SYMBOL_GPL(elv_unregister);
 
@@ -1118,7 +1119,7 @@ ssize_t elv_iosched_show(request_queue_t
 	struct list_head *entry;
 	int len = 0;
 
-	spin_lock_irq(&elv_list_lock);
+	spin_lock(&elv_list_lock);
 	list_for_each(entry, &elv_list) {
 		struct elevator_type *__e;
 
@@ -1128,7 +1129,7 @@ ssize_t elv_iosched_show(request_queue_t
 		else
 			len += sprintf(name+len, "%s ", __e->elevator_name);
 	}
-	spin_unlock_irq(&elv_list_lock);
+	spin_unlock(&elv_list_lock);
 
 	len += sprintf(len+name, "\n");
 	return len;
diff --git a/block/genhd.c b/block/genhd.c
index 441432a..b566444 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -17,7 +17,7 @@ #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
 #include <linux/mutex.h>
 
-struct subsystem block_subsys;
+struct kset block_subsys;
 static DEFINE_MUTEX(block_subsys_lock);
 
 /*
@@ -221,7 +221,7 @@ static void *part_start(struct seq_file 
 	loff_t l = *pos;
 
 	mutex_lock(&block_subsys_lock);
-	list_for_each(p, &block_subsys.kset.list)
+	list_for_each(p, &block_subsys.list)
 		if (!l--)
 			return list_entry(p, struct gendisk, kobj.entry);
 	return NULL;
@@ -231,7 +231,7 @@ static void *part_next(struct seq_file *
 {
 	struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
 	++*pos;
-	return p==&block_subsys.kset.list ? NULL : 
+	return p==&block_subsys.list ? NULL :
 		list_entry(p, struct gendisk, kobj.entry);
 }
 
@@ -246,7 +246,7 @@ static int show_partition(struct seq_fil
 	int n;
 	char buf[BDEVNAME_SIZE];
 
-	if (&sgp->kobj.entry == block_subsys.kset.list.next)
+	if (&sgp->kobj.entry == block_subsys.list.next)
 		seq_puts(part, "major minor  #blocks  name\n\n");
 
 	/* Don't show non-partitionable removeable devices or empty devices */
@@ -565,7 +565,7 @@ static void *diskstats_start(struct seq_
 	struct list_head *p;
 
 	mutex_lock(&block_subsys_lock);
-	list_for_each(p, &block_subsys.kset.list)
+	list_for_each(p, &block_subsys.list)
 		if (!k--)
 			return list_entry(p, struct gendisk, kobj.entry);
 	return NULL;
@@ -575,7 +575,7 @@ static void *diskstats_next(struct seq_f
 {
 	struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
 	++*pos;
-	return p==&block_subsys.kset.list ? NULL :
+	return p==&block_subsys.list ? NULL :
 		list_entry(p, struct gendisk, kobj.entry);
 }
 
diff --git a/block/ioctl.c b/block/ioctl.c
index e06dbe9..f7e3e8a 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -80,7 +80,7 @@ static int blkpg_ioctl(struct block_devi
 			}
 			/* all seems OK */
 			fsync_bdev(bdevp);
-			invalidate_bdev(bdevp, 0);
+			invalidate_bdev(bdevp);
 
 			mutex_lock_nested(&bdev->bd_mutex, 1);
 			delete_partition(disk, part);
@@ -236,7 +236,7 @@ int blkdev_ioctl(struct inode *inode, st
 
 		lock_kernel();
 		fsync_bdev(bdev);
-		invalidate_bdev(bdev, 0);
+		invalidate_bdev(bdev);
 		unlock_kernel();
 		return 0;
 
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 3de0695..d99d402 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1925,6 +1925,8 @@ blk_init_queue_node(request_fn_proc *rfn
 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 
+	q->sg_reserved_size = INT_MAX;
+
 	/*
 	 * all done
 	 */
@@ -2556,6 +2558,7 @@ int blk_rq_map_kern(request_queue_t *q, 
 		bio->bi_rw |= (1 << BIO_RW);
 
 	blk_rq_bio_prep(q, rq, bio);
+	blk_queue_bounce(q, &rq->bio);
 	rq->buffer = rq->data = NULL;
 	return 0;
 }
@@ -3741,6 +3744,7 @@ static struct io_context *current_io_con
 		ret->nr_batch_requests = 0; /* because this is 0 */
 		ret->aic = NULL;
 		ret->cic_root.rb_node = NULL;
+		ret->ioc_data = NULL;
 		/* make sure set_task_ioprio() sees the settings above */
 		smp_wmb();
 		tsk->io_context = ret;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 65c6a3c..e83f1db 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -78,7 +78,9 @@ static int sg_set_timeout(request_queue_
 
 static int sg_get_reserved_size(request_queue_t *q, int __user *p)
 {
-	return put_user(q->sg_reserved_size, p);
+	unsigned val = min(q->sg_reserved_size, q->max_sectors << 9);
+
+	return put_user(val, p);
 }
 
 static int sg_set_reserved_size(request_queue_t *q, int __user *p)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 086fcec..620e14c 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -16,6 +16,10 @@ config CRYPTO_ALGAPI
 	help
 	  This option provides the API for cryptographic algorithms.
 
+config CRYPTO_ABLKCIPHER
+	tristate
+	select CRYPTO_BLKCIPHER
+
 config CRYPTO_BLKCIPHER
 	tristate
 	select CRYPTO_ALGAPI
@@ -171,6 +175,15 @@ config CRYPTO_LRW
 	  The first 128, 192 or 256 bits in the key are used for AES and the
 	  rest is used to tie each cipher block to its logical position.
 
+config CRYPTO_CRYPTD
+	tristate "Software async crypto daemon"
+	select CRYPTO_ABLKCIPHER
+	select CRYPTO_MANAGER
+	help
+	  This is a generic software asynchronous crypto daemon that
+	  converts an arbitrary synchronous software crypto algorithm
+	  into an asynchronous algorithm that executes in a kernel thread.
+
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index 12f93f5..cce46a1 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -8,6 +8,7 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.
 crypto_algapi-objs := algapi.o $(crypto_algapi-y)
 obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
 
+obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
 obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
 
 crypto_hash-objs := hash.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o
 obj-$(CONFIG_CRYPTO_CBC) += cbc.o
 obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
+obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
 obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
new file mode 100644
index 0000000..9348ddd
--- /dev/null
+++ b/crypto/ablkcipher.c
@@ -0,0 +1,83 @@
+/*
+ * Asynchronous block chaining cipher operations.
+ * 
+ * This is the asynchronous version of blkcipher.c indicating completion
+ * via a callback.
+ *
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+
+static int setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+		  unsigned int keylen)
+{
+	struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+
+	if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
+		crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -EINVAL;
+	}
+
+	return cipher->setkey(tfm, key, keylen);
+}
+
+static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
+					      u32 mask)
+{
+	return alg->cra_ctxsize;
+}
+
+static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
+				      u32 mask)
+{
+	struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
+	struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+
+	if (alg->ivsize > PAGE_SIZE / 8)
+		return -EINVAL;
+
+	crt->setkey = setkey;
+	crt->encrypt = alg->encrypt;
+	crt->decrypt = alg->decrypt;
+	crt->ivsize = alg->ivsize;
+
+	return 0;
+}
+
+static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
+
+	seq_printf(m, "type         : ablkcipher\n");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
+	seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
+	seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
+	seq_printf(m, "qlen         : %u\n", ablkcipher->queue->qlen);
+	seq_printf(m, "max qlen     : %u\n", ablkcipher->queue->max_qlen);
+}
+
+const struct crypto_type crypto_ablkcipher_type = {
+	.ctxsize = crypto_ablkcipher_ctxsize,
+	.init = crypto_init_ablkcipher_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_ablkcipher_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
diff --git a/crypto/algapi.c b/crypto/algapi.c
index f7d2185..f137a43 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -84,36 +84,47 @@ static void crypto_destroy_instance(stru
 	crypto_tmpl_put(tmpl);
 }
 
-static void crypto_remove_spawns(struct list_head *spawns,
-				 struct list_head *list)
+static void crypto_remove_spawn(struct crypto_spawn *spawn,
+				struct list_head *list,
+				struct list_head *secondary_spawns)
 {
-	struct crypto_spawn *spawn, *n;
+	struct crypto_instance *inst = spawn->inst;
+	struct crypto_template *tmpl = inst->tmpl;
 
-	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;
 
-		list_del_init(&spawn->list);
-		spawn->alg = NULL;
+	if (crypto_is_dead(&inst->alg))
+		return;
 
-		if (crypto_is_dead(&inst->alg))
-			continue;
+	inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
+	if (!tmpl || !crypto_tmpl_get(tmpl))
+		return;
 
-		inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
-		if (!tmpl || !crypto_tmpl_get(tmpl))
+	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;
+
+	list_splice(&inst->alg.cra_users, secondary_spawns);
+}
+
+static void crypto_remove_spawns(struct list_head *spawns,
+				 struct list_head *list, u32 new_type)
+{
+	struct crypto_spawn *spawn, *n;
+	LIST_HEAD(secondary_spawns);
+
+	list_for_each_entry_safe(spawn, n, spawns, list) {
+		if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
 			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;
+		crypto_remove_spawn(spawn, list, &secondary_spawns);
+	}
 
-		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);
-		}
+	while (!list_empty(&secondary_spawns)) {
+		list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
+			crypto_remove_spawn(spawn, list, &secondary_spawns);
 	}
 }
 
@@ -164,7 +175,7 @@ static int __crypto_register_alg(struct 
 		    q->cra_priority > alg->cra_priority)
 			continue;
 
-		crypto_remove_spawns(&q->cra_users, list);
+		crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
 	}
 	
 	list_add(&alg->cra_list, &crypto_alg_list);
@@ -214,7 +225,7 @@ static int crypto_remove_alg(struct cryp
 
 	crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
 	list_del_init(&alg->cra_list);
-	crypto_remove_spawns(&alg->cra_users, list);
+	crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
 
 	return 0;
 }
@@ -351,11 +362,12 @@ err:
 EXPORT_SYMBOL_GPL(crypto_register_instance);
 
 int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
-		      struct crypto_instance *inst)
+		      struct crypto_instance *inst, u32 mask)
 {
 	int err = -EAGAIN;
 
 	spawn->inst = inst;
+	spawn->mask = mask;
 
 	down_write(&crypto_alg_sem);
 	if (!crypto_is_moribund(alg)) {
@@ -425,15 +437,45 @@ int crypto_unregister_notifier(struct no
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
 
-struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
-				       u32 type, u32 mask)
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
+{
+	struct rtattr *rta = tb[CRYPTOA_TYPE - 1];
+	struct crypto_attr_type *algt;
+
+	if (!rta)
+		return ERR_PTR(-ENOENT);
+	if (RTA_PAYLOAD(rta) < sizeof(*algt))
+		return ERR_PTR(-EINVAL);
+
+	algt = RTA_DATA(rta);
+
+	return algt;
+}
+EXPORT_SYMBOL_GPL(crypto_get_attr_type);
+
+int crypto_check_attr_type(struct rtattr **tb, u32 type)
 {
-	struct rtattr *rta = param;
+	struct crypto_attr_type *algt;
+
+	algt = crypto_get_attr_type(tb);
+	if (IS_ERR(algt))
+		return PTR_ERR(algt);
+
+	if ((algt->type ^ type) & algt->mask)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_check_attr_type);
+
+struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask)
+{
+	struct rtattr *rta = tb[CRYPTOA_ALG - 1];
 	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))
+	if (!rta)
+		return ERR_PTR(-ENOENT);
+	if (RTA_PAYLOAD(rta) < sizeof(*alga))
 		return ERR_PTR(-EINVAL);
 
 	alga = RTA_DATA(rta);
@@ -464,7 +506,8 @@ struct crypto_instance *crypto_alloc_ins
 		goto err_free_inst;
 
 	spawn = crypto_instance_ctx(inst);
-	err = crypto_init_spawn(spawn, alg, inst);
+	err = crypto_init_spawn(spawn, alg, inst,
+				CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
 
 	if (err)
 		goto err_free_inst;
@@ -477,6 +520,68 @@ err_free_inst:
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_instance);
 
+void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
+{
+	INIT_LIST_HEAD(&queue->list);
+	queue->backlog = &queue->list;
+	queue->qlen = 0;
+	queue->max_qlen = max_qlen;
+}
+EXPORT_SYMBOL_GPL(crypto_init_queue);
+
+int crypto_enqueue_request(struct crypto_queue *queue,
+			   struct crypto_async_request *request)
+{
+	int err = -EINPROGRESS;
+
+	if (unlikely(queue->qlen >= queue->max_qlen)) {
+		err = -EBUSY;
+		if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+			goto out;
+		if (queue->backlog == &queue->list)
+			queue->backlog = &request->list;
+	}
+
+	queue->qlen++;
+	list_add_tail(&request->list, &queue->list);
+
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(crypto_enqueue_request);
+
+struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
+{
+	struct list_head *request;
+
+	if (unlikely(!queue->qlen))
+		return NULL;
+
+	queue->qlen--;
+
+	if (queue->backlog != &queue->list)
+		queue->backlog = queue->backlog->next;
+
+	request = queue->list.next;
+	list_del(request);
+
+	return list_entry(request, struct crypto_async_request, list);
+}
+EXPORT_SYMBOL_GPL(crypto_dequeue_request);
+
+int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
+{
+	struct crypto_async_request *req;
+
+	list_for_each_entry(req, &queue->list, list) {
+		if (req->tfm == tfm)
+			return 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
+
 static int __init crypto_algapi_init(void)
 {
 	crypto_init_proc();
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index b5befe8..8edf40c 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -349,13 +349,48 @@ static int setkey(struct crypto_tfm *tfm
 	return cipher->setkey(tfm, key, keylen);
 }
 
+static int async_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+			unsigned int keylen)
+{
+	return setkey(crypto_ablkcipher_tfm(tfm), key, keylen);
+}
+
+static int async_encrypt(struct ablkcipher_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+	struct blkcipher_desc desc = {
+		.tfm = __crypto_blkcipher_cast(tfm),
+		.info = req->info,
+		.flags = req->base.flags,
+	};
+
+
+	return alg->encrypt(&desc, req->dst, req->src, req->nbytes);
+}
+
+static int async_decrypt(struct ablkcipher_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+	struct blkcipher_desc desc = {
+		.tfm = __crypto_blkcipher_cast(tfm),
+		.info = req->info,
+		.flags = req->base.flags,
+	};
+
+	return alg->decrypt(&desc, req->dst, req->src, req->nbytes);
+}
+
 static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
 					     u32 mask)
 {
 	struct blkcipher_alg *cipher = &alg->cra_blkcipher;
 	unsigned int len = alg->cra_ctxsize;
 
-	if (cipher->ivsize) {
+	type ^= CRYPTO_ALG_ASYNC;
+	mask &= CRYPTO_ALG_ASYNC;
+	if ((type & mask) && cipher->ivsize) {
 		len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
 		len += cipher->ivsize;
 	}
@@ -363,16 +398,26 @@ static unsigned int crypto_blkcipher_ctx
 	return len;
 }
 
-static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm)
+{
+	struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+	struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+
+	crt->setkey = async_setkey;
+	crt->encrypt = async_encrypt;
+	crt->decrypt = async_decrypt;
+	crt->ivsize = alg->ivsize;
+
+	return 0;
+}
+
+static int crypto_init_blkcipher_ops_sync(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;
@@ -385,8 +430,23 @@ static int crypto_init_blkcipher_ops(str
 	return 0;
 }
 
+static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+	struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+
+	if (alg->ivsize > PAGE_SIZE / 8)
+		return -EINVAL;
+
+	type ^= CRYPTO_ALG_ASYNC;
+	mask &= CRYPTO_ALG_ASYNC;
+	if (type & mask)
+		return crypto_init_blkcipher_ops_sync(tfm);
+	else
+		return crypto_init_blkcipher_ops_async(tfm);
+}
+
 static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
-	__attribute_used__;
+	__attribute__ ((unused));
 static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
 {
 	seq_printf(m, "type         : blkcipher\n");
diff --git a/crypto/cbc.c b/crypto/cbc.c
index 136fea7..1f2649e 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -275,13 +275,18 @@ static void crypto_cbc_exit_tfm(struct c
 	crypto_free_cipher(ctx->child);
 }
 
-static struct crypto_instance *crypto_cbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
 
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
-				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
new file mode 100644
index 0000000..3ff4e1f
--- /dev/null
+++ b/crypto/cryptd.c
@@ -0,0 +1,375 @@
+/*
+ * Software async crypto daemon.
+ *
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * 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/kthread.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define CRYPTD_MAX_QLEN 100
+
+struct cryptd_state {
+	spinlock_t lock;
+	struct mutex mutex;
+	struct crypto_queue queue;
+	struct task_struct *task;
+};
+
+struct cryptd_instance_ctx {
+	struct crypto_spawn spawn;
+	struct cryptd_state *state;
+};
+
+struct cryptd_blkcipher_ctx {
+	struct crypto_blkcipher *child;
+};
+
+struct cryptd_blkcipher_request_ctx {
+	crypto_completion_t complete;
+};
+
+
+static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+	return ictx->state;
+}
+
+static int cryptd_blkcipher_setkey(struct crypto_ablkcipher *parent,
+				   const u8 *key, unsigned int keylen)
+{
+	struct cryptd_blkcipher_ctx *ctx = crypto_ablkcipher_ctx(parent);
+	struct crypto_blkcipher *child = ctx->child;
+	int err;
+
+	crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_blkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) &
+					  CRYPTO_TFM_REQ_MASK);
+	err = crypto_blkcipher_setkey(child, key, keylen);
+	crypto_ablkcipher_set_flags(parent, crypto_blkcipher_get_flags(child) &
+					    CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static void cryptd_blkcipher_crypt(struct ablkcipher_request *req,
+				   struct crypto_blkcipher *child,
+				   int err,
+				   int (*crypt)(struct blkcipher_desc *desc,
+						struct scatterlist *dst,
+						struct scatterlist *src,
+						unsigned int len))
+{
+	struct cryptd_blkcipher_request_ctx *rctx;
+	struct blkcipher_desc desc;
+
+	rctx = ablkcipher_request_ctx(req);
+
+	if (unlikely(err == -EINPROGRESS)) {
+		rctx->complete(&req->base, err);
+		return;
+	}
+
+	desc.tfm = child;
+	desc.info = req->info;
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	err = crypt(&desc, req->dst, req->src, req->nbytes);
+
+	req->base.complete = rctx->complete;
+
+	local_bh_disable();
+	req->base.complete(&req->base, err);
+	local_bh_enable();
+}
+
+static void cryptd_blkcipher_encrypt(struct crypto_async_request *req, int err)
+{
+	struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm);
+	struct crypto_blkcipher *child = ctx->child;
+
+	cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err,
+			       crypto_blkcipher_crt(child)->encrypt);
+}
+
+static void cryptd_blkcipher_decrypt(struct crypto_async_request *req, int err)
+{
+	struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm);
+	struct crypto_blkcipher *child = ctx->child;
+
+	cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err,
+			       crypto_blkcipher_crt(child)->decrypt);
+}
+
+static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req,
+				    crypto_completion_t complete)
+{
+	struct cryptd_blkcipher_request_ctx *rctx = ablkcipher_request_ctx(req);
+	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+	struct cryptd_state *state =
+		cryptd_get_state(crypto_ablkcipher_tfm(tfm));
+	int err;
+
+	rctx->complete = req->base.complete;
+	req->base.complete = complete;
+
+	spin_lock_bh(&state->lock);
+	err = ablkcipher_enqueue_request(crypto_ablkcipher_alg(tfm), req);
+	spin_unlock_bh(&state->lock);
+
+	wake_up_process(state->task);
+	return err;
+}
+
+static int cryptd_blkcipher_encrypt_enqueue(struct ablkcipher_request *req)
+{
+	return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_encrypt);
+}
+
+static int cryptd_blkcipher_decrypt_enqueue(struct ablkcipher_request *req)
+{
+	return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_decrypt);
+}
+
+static int cryptd_blkcipher_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+	struct crypto_spawn *spawn = &ictx->spawn;
+	struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_blkcipher *cipher;
+
+	cipher = crypto_spawn_blkcipher(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+	tfm->crt_ablkcipher.reqsize =
+		sizeof(struct cryptd_blkcipher_request_ctx);
+	return 0;
+}
+
+static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct cryptd_state *state = cryptd_get_state(tfm);
+	int active;
+
+	mutex_lock(&state->mutex);
+	active = ablkcipher_tfm_in_queue(__crypto_ablkcipher_cast(tfm));
+	mutex_unlock(&state->mutex);
+
+	BUG_ON(active);
+
+	crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
+						     struct cryptd_state *state)
+{
+	struct crypto_instance *inst;
+	struct cryptd_instance_ctx *ctx;
+	int err;
+
+	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+	if (IS_ERR(inst))
+		goto out;
+
+	err = -ENAMETOOLONG;
+	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+		     "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+		goto out_free_inst;
+
+	ctx = crypto_instance_ctx(inst);
+	err = crypto_init_spawn(&ctx->spawn, alg, inst,
+				CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	if (err)
+		goto out_free_inst;
+
+	ctx->state = state;
+
+	memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+
+	inst->alg.cra_priority = alg->cra_priority + 50;
+	inst->alg.cra_blocksize = alg->cra_blocksize;
+	inst->alg.cra_alignmask = alg->cra_alignmask;
+
+out:
+	return inst;
+
+out_free_inst:
+	kfree(inst);
+	inst = ERR_PTR(err);
+	goto out;
+}
+
+static struct crypto_instance *cryptd_alloc_blkcipher(
+	struct rtattr **tb, struct cryptd_state *state)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
+				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	inst = cryptd_alloc_instance(alg, state);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC;
+	inst->alg.cra_type = &crypto_ablkcipher_type;
+
+	inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize;
+	inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
+	inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
+
+	inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
+
+	inst->alg.cra_init = cryptd_blkcipher_init_tfm;
+	inst->alg.cra_exit = cryptd_blkcipher_exit_tfm;
+
+	inst->alg.cra_ablkcipher.setkey = cryptd_blkcipher_setkey;
+	inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue;
+	inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue;
+
+	inst->alg.cra_ablkcipher.queue = &state->queue;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return inst;
+}
+
+static struct cryptd_state state;
+
+static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
+{
+	struct crypto_attr_type *algt;
+
+	algt = crypto_get_attr_type(tb);
+	if (IS_ERR(algt))
+		return ERR_PTR(PTR_ERR(algt));
+
+	switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
+	case CRYPTO_ALG_TYPE_BLKCIPHER:
+		return cryptd_alloc_blkcipher(tb, &state);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static void cryptd_free(struct crypto_instance *inst)
+{
+	struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+	crypto_drop_spawn(&ctx->spawn);
+	kfree(inst);
+}
+
+static struct crypto_template cryptd_tmpl = {
+	.name = "cryptd",
+	.alloc = cryptd_alloc,
+	.free = cryptd_free,
+	.module = THIS_MODULE,
+};
+
+static inline int cryptd_create_thread(struct cryptd_state *state,
+				       int (*fn)(void *data), const char *name)
+{
+	spin_lock_init(&state->lock);
+	mutex_init(&state->mutex);
+	crypto_init_queue(&state->queue, CRYPTD_MAX_QLEN);
+
+	state->task = kthread_create(fn, state, name);
+	if (IS_ERR(state->task))
+		return PTR_ERR(state->task);
+
+	return 0;
+}
+
+static inline void cryptd_stop_thread(struct cryptd_state *state)
+{
+	BUG_ON(state->queue.qlen);
+	kthread_stop(state->task);
+}
+
+static int cryptd_thread(void *data)
+{
+	struct cryptd_state *state = data;
+	int stop;
+
+	do {
+		struct crypto_async_request *req, *backlog;
+
+		mutex_lock(&state->mutex);
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_bh(&state->lock);
+		backlog = crypto_get_backlog(&state->queue);
+		req = crypto_dequeue_request(&state->queue);
+		spin_unlock_bh(&state->lock);
+
+		stop = kthread_should_stop();
+
+		if (stop || req) {
+			__set_current_state(TASK_RUNNING);
+			if (req) {
+				if (backlog)
+					backlog->complete(backlog,
+							  -EINPROGRESS);
+				req->complete(req, 0);
+			}
+		}
+
+		mutex_unlock(&state->mutex);
+
+		schedule();
+	} while (!stop);
+
+	return 0;
+}
+
+static int __init cryptd_init(void)
+{
+	int err;
+
+	err = cryptd_create_thread(&state, cryptd_thread, "cryptd");
+	if (err)
+		return err;
+
+	err = crypto_register_template(&cryptd_tmpl);
+	if (err)
+		kthread_stop(state.task);
+
+	return err;
+}
+
+static void __exit cryptd_exit(void)
+{
+	cryptd_stop_thread(&state);
+	crypto_unregister_template(&cryptd_tmpl);
+}
+
+module_init(cryptd_init);
+module_exit(cryptd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Software async crypto daemon");
diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
index 2ebffb8..6958ea8 100644
--- a/crypto/cryptomgr.c
+++ b/crypto/cryptomgr.c
@@ -14,17 +14,24 @@ #include <linux/crypto.h>
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/kthread.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 task_struct *thread;
+
+	struct rtattr *tb[CRYPTOA_MAX];
+
+	struct {
+		struct rtattr attr;
+		struct crypto_attr_type data;
+	} type;
 
 	struct {
 		struct rtattr attr;
@@ -32,18 +39,15 @@ struct cryptomgr_param {
 	} alg;
 
 	struct {
-		u32 type;
-		u32 mask;
 		char name[CRYPTO_MAX_ALG_NAME];
 	} larval;
 
 	char template[CRYPTO_MAX_ALG_NAME];
 };
 
-static void cryptomgr_probe(struct work_struct *work)
+static int cryptomgr_probe(void *data)
 {
-	struct cryptomgr_param *param =
-		container_of(work, struct cryptomgr_param, work);
+	struct cryptomgr_param *param = data;
 	struct crypto_template *tmpl;
 	struct crypto_instance *inst;
 	int err;
@@ -53,7 +57,7 @@ static void cryptomgr_probe(struct work_
 		goto err;
 
 	do {
-		inst = tmpl->alloc(&param->alg, sizeof(param->alg));
+		inst = tmpl->alloc(param->tb);
 		if (IS_ERR(inst))
 			err = PTR_ERR(inst);
 		else if ((err = crypto_register_instance(tmpl, inst)))
@@ -67,11 +71,11 @@ static void cryptomgr_probe(struct work_
 
 out:
 	kfree(param);
-	return;
+	module_put_and_exit(0);
 
 err:
-	crypto_larval_error(param->larval.name, param->larval.type,
-			    param->larval.mask);
+	crypto_larval_error(param->larval.name, param->type.data.type,
+			    param->type.data.mask);
 	goto out;
 }
 
@@ -82,10 +86,13 @@ static int cryptomgr_schedule_probe(stru
 	const char *p;
 	unsigned int len;
 
-	param = kmalloc(sizeof(*param), GFP_KERNEL);
-	if (!param)
+	if (!try_module_get(THIS_MODULE))
 		goto err;
 
+	param = kzalloc(sizeof(*param), GFP_KERNEL);
+	if (!param)
+		goto err_put_module;
+
 	for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
 		;
 
@@ -94,32 +101,45 @@ static int cryptomgr_schedule_probe(stru
 		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 = 0;
+	for (p = name; *p; p++) {
+		for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++)
+			;
 
-	len = p - name;
-	if (!len || *p != ')' || p[1])
+		if (*p != ')')
+			goto err_free_param;
+
+		len = p - name;
+	}
+
+	if (!len || name[len + 1])
 		goto err_free_param;
 
+	param->type.attr.rta_len = sizeof(param->type);
+	param->type.attr.rta_type = CRYPTOA_TYPE;
+	param->type.data.type = larval->alg.cra_flags;
+	param->type.data.mask = larval->mask;
+	param->tb[CRYPTOA_TYPE - 1] = &param->type.attr;
+
 	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;
+	param->tb[CRYPTOA_ALG - 1] = &param->alg.attr;
 
 	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(&param->work, cryptomgr_probe);
-	schedule_work(&param->work);
+	param->thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
+	if (IS_ERR(param->thread))
+		goto err_free_param;
 
 	return NOTIFY_STOP;
 
 err_free_param:
 	kfree(param);
+err_put_module:
+	module_put(THIS_MODULE);
 err:
 	return NOTIFY_OK;
 }
diff --git a/crypto/ecb.c b/crypto/ecb.c
index 839a0ae..6310387 100644
--- a/crypto/ecb.c
+++ b/crypto/ecb.c
@@ -115,13 +115,18 @@ static void crypto_ecb_exit_tfm(struct c
 	crypto_free_cipher(ctx->child);
 }
 
-static struct crypto_instance *crypto_ecb_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
 
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
-				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/crypto/hash.c b/crypto/hash.c
index 12c4514..4ccd22d 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -41,7 +41,7 @@ static int crypto_init_hash_ops(struct c
 }
 
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
-	__attribute_used__;
+	__attribute__ ((unused));
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
 {
 	seq_printf(m, "type         : hash\n");
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 44187c5..8802fb6 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -197,13 +197,18 @@ static void hmac_free(struct crypto_inst
 	kfree(inst);
 }
 
-static struct crypto_instance *hmac_alloc(void *param, unsigned int len)
+static struct crypto_instance *hmac_alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+	if (err)
+		return ERR_PTR(err);
 
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH,
-				  CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
+				  CRYPTO_ALG_TYPE_HASH_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/crypto/lrw.c b/crypto/lrw.c
index b410508..621095d 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -228,13 +228,18 @@ static void exit_tfm(struct crypto_tfm *
 	crypto_free_cipher(ctx->child);
 }
 
-static struct crypto_instance *alloc(void *param, unsigned int len)
+static struct crypto_instance *alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
 
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
-				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 094397b..9e917b8 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -3,7 +3,7 @@
  *
  * Michael MIC (IEEE 802.11i/TKIP) keyed digest
  *
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004 Jouni Malinen <j@w1.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
@@ -173,4 +173,4 @@ module_exit(michael_mic_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
diff --git a/crypto/pcbc.c b/crypto/pcbc.c
index 5174d7f..c3ed8a1 100644
--- a/crypto/pcbc.c
+++ b/crypto/pcbc.c
@@ -279,13 +279,18 @@ static void crypto_pcbc_exit_tfm(struct 
 	crypto_free_cipher(ctx->child);
 }
 
-static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+	if (err)
+		return ERR_PTR(err);
 
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
-				  CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 8eaa5aa..f0aed01 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -57,6 +57,11 @@ #define IDX8		3000
 #define ENCRYPT 1
 #define DECRYPT 0
 
+struct tcrypt_result {
+	struct completion completion;
+	int err;
+};
+
 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
 
 /*
@@ -84,6 +89,17 @@ static void hexdump(unsigned char *buf, 
 	printk("\n");
 }
 
+static void tcrypt_complete(struct crypto_async_request *req, int err)
+{
+	struct tcrypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
 static void test_hash(char *algo, struct hash_testvec *template,
 		      unsigned int tcount)
 {
@@ -203,15 +219,14 @@ static void test_cipher(char *algo, int 
 {
 	unsigned int ret, i, j, k, temp;
 	unsigned int tsize;
-	unsigned int iv_len;
-	unsigned int len;
 	char *q;
-	struct crypto_blkcipher *tfm;
+	struct crypto_ablkcipher *tfm;
 	char *key;
 	struct cipher_testvec *cipher_tv;
-	struct blkcipher_desc desc;
+	struct ablkcipher_request *req;
 	struct scatterlist sg[8];
 	const char *e;
+	struct tcrypt_result result;
 
 	if (enc == ENCRYPT)
 	        e = "encryption";
@@ -232,15 +247,24 @@ static void test_cipher(char *algo, int 
 	memcpy(tvmem, template, tsize);
 	cipher_tv = (void *)tvmem;
 
-	tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
+	init_completion(&result.completion);
+
+	tfm = crypto_alloc_ablkcipher(algo, 0, 0);
 
 	if (IS_ERR(tfm)) {
 		printk("failed to load transform for %s: %ld\n", algo,
 		       PTR_ERR(tfm));
 		return;
 	}
-	desc.tfm = tfm;
-	desc.flags = 0;
+
+	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		printk("failed to allocate request for %s\n", algo);
+		goto out;
+	}
+
+	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+					tcrypt_complete, &result);
 
 	j = 0;
 	for (i = 0; i < tcount; i++) {
@@ -249,17 +273,17 @@ static void test_cipher(char *algo, int 
 			printk("test %u (%d bit key):\n",
 			j, cipher_tv[i].klen * 8);
 
-			crypto_blkcipher_clear_flags(tfm, ~0);
+			crypto_ablkcipher_clear_flags(tfm, ~0);
 			if (cipher_tv[i].wk)
-				crypto_blkcipher_set_flags(
+				crypto_ablkcipher_set_flags(
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 			key = cipher_tv[i].key;
 
-			ret = crypto_blkcipher_setkey(tfm, key,
-						      cipher_tv[i].klen);
+			ret = crypto_ablkcipher_setkey(tfm, key,
+						       cipher_tv[i].klen);
 			if (ret) {
 				printk("setkey() failed flags=%x\n",
-				       crypto_blkcipher_get_flags(tfm));
+				       crypto_ablkcipher_get_flags(tfm));
 
 				if (!cipher_tv[i].fail)
 					goto out;
@@ -268,19 +292,28 @@ static void test_cipher(char *algo, int 
 			sg_set_buf(&sg[0], cipher_tv[i].input,
 				   cipher_tv[i].ilen);
 
-			iv_len = crypto_blkcipher_ivsize(tfm);
-			if (iv_len)
-				crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
-							iv_len);
+			ablkcipher_request_set_crypt(req, sg, sg,
+						     cipher_tv[i].ilen,
+						     cipher_tv[i].iv);
 
-			len = cipher_tv[i].ilen;
 			ret = enc ?
-				crypto_blkcipher_encrypt(&desc, sg, sg, len) :
-				crypto_blkcipher_decrypt(&desc, sg, sg, len);
+				crypto_ablkcipher_encrypt(req) :
+				crypto_ablkcipher_decrypt(req);
 
-			if (ret) {
-				printk("%s () failed flags=%x\n", e,
-				       desc.flags);
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !((ret = result.err))) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk("%s () failed err=%d\n", e, -ret);
 				goto out;
 			}
 
@@ -303,17 +336,17 @@ static void test_cipher(char *algo, int 
 			printk("test %u (%d bit key):\n",
 			j, cipher_tv[i].klen * 8);
 
-			crypto_blkcipher_clear_flags(tfm, ~0);
+			crypto_ablkcipher_clear_flags(tfm, ~0);
 			if (cipher_tv[i].wk)
-				crypto_blkcipher_set_flags(
+				crypto_ablkcipher_set_flags(
 					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
 			key = cipher_tv[i].key;
 
-			ret = crypto_blkcipher_setkey(tfm, key,
-						      cipher_tv[i].klen);
+			ret = crypto_ablkcipher_setkey(tfm, key,
+						       cipher_tv[i].klen);
 			if (ret) {
 				printk("setkey() failed flags=%x\n",
-				       crypto_blkcipher_get_flags(tfm));
+				       crypto_ablkcipher_get_flags(tfm));
 
 				if (!cipher_tv[i].fail)
 					goto out;
@@ -329,19 +362,28 @@ static void test_cipher(char *algo, int 
 					   cipher_tv[i].tap[k]);
 			}
 
-			iv_len = crypto_blkcipher_ivsize(tfm);
-			if (iv_len)
-				crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
-							iv_len);
+			ablkcipher_request_set_crypt(req, sg, sg,
+						     cipher_tv[i].ilen,
+						     cipher_tv[i].iv);
 
-			len = cipher_tv[i].ilen;
 			ret = enc ?
-				crypto_blkcipher_encrypt(&desc, sg, sg, len) :
-				crypto_blkcipher_decrypt(&desc, sg, sg, len);
+				crypto_ablkcipher_encrypt(req) :
+				crypto_ablkcipher_decrypt(req);
 
-			if (ret) {
-				printk("%s () failed flags=%x\n", e,
-				       desc.flags);
+			switch (ret) {
+			case 0:
+				break;
+			case -EINPROGRESS:
+			case -EBUSY:
+				ret = wait_for_completion_interruptible(
+					&result.completion);
+				if (!ret && !((ret = result.err))) {
+					INIT_COMPLETION(result.completion);
+					break;
+				}
+				/* fall through */
+			default:
+				printk("%s () failed err=%d\n", e, -ret);
 				goto out;
 			}
 
@@ -360,7 +402,8 @@ static void test_cipher(char *algo, int 
 	}
 
 out:
-	crypto_free_blkcipher(tfm);
+	crypto_free_ablkcipher(tfm);
+	ablkcipher_request_free(req);
 }
 
 static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p,
@@ -832,7 +875,7 @@ static void test_available(void)
 
 	while (*name) {
 		printk("alg %s ", *name);
-		printk(crypto_has_alg(*name, 0, CRYPTO_ALG_ASYNC) ?
+		printk(crypto_has_alg(*name, 0, 0) ?
 		       "found\n" : "not found\n");
 		name++;
 	}
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 53e8ccb..9f502b8 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -288,12 +288,18 @@ static void xcbc_exit_tfm(struct crypto_
 	crypto_free_cipher(ctx->child);
 }
 
-static struct crypto_instance *xcbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
 {
 	struct crypto_instance *inst;
 	struct crypto_alg *alg;
-	alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
-				  CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
+	int err;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+	if (err)
+		return ERR_PTR(err);
+
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+				  CRYPTO_ALG_TYPE_MASK);
 	if (IS_ERR(alg))
 		return ERR_PTR(PTR_ERR(alg));
 
diff --git a/drivers/Makefile b/drivers/Makefile
index 3a718f5..26ca903 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -58,7 +58,7 @@ obj-$(CONFIG_GAMEPORT)		+= input/gamepor
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_RTC_LIB)		+= rtc/
-obj-$(CONFIG_I2C)		+= i2c/
+obj-y				+= i2c/
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_HWMON)		+= hwmon/
 obj-$(CONFIG_PHONE)		+= telephony/
@@ -72,7 +72,6 @@ obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-$(CONFIG_NEW_LEDS)		+= leds/
 obj-$(CONFIG_INFINIBAND)	+= infiniband/
-obj-$(CONFIG_IPATH_CORE)	+= infiniband/
 obj-$(CONFIG_SGI_SN)		+= sn/
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e2ce4a9..139f41f 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -85,8 +85,8 @@ config ACPI_PROCFS
 	depends on ACPI
 	default y
 	---help---
-	  Procfs interface for ACPI is made optional for back-compatible.
-	  As the same functions are duplicated in sysfs interface
+	  The Procfs interface for ACPI is made optional for backward compatibility.
+	  As the same functions are duplicated in the sysfs interface
 	  and this proc interface will be removed some time later,
 	  it's marked as deprecated.
 	  ( /proc/acpi/debug_layer && debug_level are deprecated by
@@ -218,43 +218,6 @@ config ACPI_ASUS
 	  NOTE: This driver is deprecated and will probably be removed soon,
 	  use asus-laptop instead.
 
-config ACPI_IBM
-	tristate "IBM ThinkPad Laptop Extras"
-	depends on X86
-	select BACKLIGHT_CLASS_DEVICE
-	---help---
-	  This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
-	  support for Fn-Fx key combinations, Bluetooth control, video
-	  output switching, ThinkLight control, UltraBay eject and more.
-	  For more information about this driver see <file:Documentation/ibm-acpi.txt>
-	  and <http://ibm-acpi.sf.net/> .
-
-	  If you have an IBM ThinkPad laptop, say Y or M here.
-
-config ACPI_IBM_DOCK
-	bool "Legacy Docking Station Support"
-	depends on ACPI_IBM
-	depends on ACPI_DOCK=n
-	default n
-	---help---
-	  Allows the ibm_acpi driver to handle docking station events.
-	  This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI.  It will
-	  allow locking and removing the laptop from the docking station,
-	  but will not properly connect PCI devices.
-
-	  If you are not sure, say N here.
-
-config ACPI_IBM_BAY
-	bool "Legacy Removable Bay Support"
-	depends on ACPI_IBM
-	default y
-	---help---
-	  Allows the ibm_acpi driver to handle removable bays.  It will allow
-	  disabling the device in the bay, and also generate notifications when
-	  the bay lever is ejected or inserted.
-
-	  If you are not sure, say Y here.
-
 config ACPI_TOSHIBA
 	tristate "Toshiba Laptop Extras"
 	depends on X86
@@ -388,11 +351,10 @@ config ACPI_HOTPLUG_MEMORY
 
 config ACPI_SBS
 	tristate "Smart Battery System (EXPERIMENTAL)"
-	depends on X86 && I2C
+	depends on X86
 	depends on EXPERIMENTAL
 	help
 	  This driver adds support for the Smart Battery System.
-	  Depends on I2C (Device Drivers ---> I2C support)
 	  A "Smart Battery" is quite old and quite rare compared
 	  to today's ACPI "Control Method" battery.
 
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5956e9f..d4336f1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -1,6 +1,6 @@
 #
 # Makefile for the Linux ACPI interpreter
-# 
+#
 
 export ACPI_CFLAGS
 
@@ -32,16 +32,17 @@ #
 processor-objs	+= processor_core.o processor_throttling.o \
 				processor_idle.o processor_thermal.o
 ifdef CONFIG_CPU_FREQ
-processor-objs	+= processor_perflib.o			
+processor-objs	+= processor_perflib.o
 endif
 
 obj-y				+= sleep/
 obj-y				+= bus.o glue.o
 obj-y				+= scan.o
+# Keep EC driver first. Initialization of others depend on it.
+obj-$(CONFIG_ACPI_EC)		+= ec.o
 obj-$(CONFIG_ACPI_AC) 		+= ac.o
 obj-$(CONFIG_ACPI_BATTERY)	+= battery.o
 obj-$(CONFIG_ACPI_BUTTON)	+= button.o
-obj-$(CONFIG_ACPI_EC)		+= ec.o
 obj-$(CONFIG_ACPI_FAN)		+= fan.o
 obj-$(CONFIG_ACPI_DOCK)		+= dock.o
 obj-$(CONFIG_ACPI_BAY)		+= bay.o
@@ -55,8 +56,7 @@ obj-$(CONFIG_ACPI_SYSTEM)	+= system.o ev
 obj-$(CONFIG_ACPI_DEBUG)	+= debug.o
 obj-$(CONFIG_ACPI_NUMA)		+= numa.o
 obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
-obj-$(CONFIG_ACPI_IBM)		+= ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)	+= acpi_memhotplug.o
 obj-y				+= cm_sbs.o
-obj-$(CONFIG_ACPI_SBS)		+= i2c_ec.o sbs.o
+obj-$(CONFIG_ACPI_SBS)		+= sbs.o
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index c261726..e65628a 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -44,11 +44,6 @@ MODULE_AUTHOR("Naveen B S <naveen.b.s@in
 MODULE_DESCRIPTION("Hotplug Mem Driver");
 MODULE_LICENSE("GPL");
 
-/* ACPI _STA method values */
-#define ACPI_MEMORY_STA_PRESENT		(0x00000001UL)
-#define ACPI_MEMORY_STA_ENABLED		(0x00000002UL)
-#define ACPI_MEMORY_STA_FUNCTIONAL	(0x00000008UL)
-
 /* Memory Device States */
 #define MEMORY_INVALID_STATE	0
 #define MEMORY_POWER_ON_STATE	1
@@ -204,9 +199,9 @@ static int acpi_memory_check_device(stru
 	 * Check for device status. Device should be
 	 * present/enabled/functioning.
 	 */
-	if (!((current_status & ACPI_MEMORY_STA_PRESENT)
-	      && (current_status & ACPI_MEMORY_STA_ENABLED)
-	      && (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+	if (!((current_status & ACPI_STA_DEVICE_PRESENT)
+	      && (current_status & ACPI_STA_DEVICE_ENABLED)
+	      && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
 		return -ENODEV;
 
 	return 0;
@@ -286,7 +281,7 @@ static int acpi_memory_powerdown_device(
 		return -ENODEV;
 
 	/* Check for device status.  Device should be disabled */
-	if (current_status & ACPI_MEMORY_STA_ENABLED)
+	if (current_status & ACPI_STA_DEVICE_ENABLED)
 		return -EINVAL;
 
 	return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index dd49ea0..e5084ec 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -103,7 +103,9 @@ int acpi_bus_get_status(struct acpi_devi
 	else if (device->parent)
 		device->status = device->parent->status;
 	else
-		STRUCT_TO_INT(device->status) = 0x0F;
+		STRUCT_TO_INT(device->status) =
+		    ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+		    ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
 
 	if (device->status.functional && !device->status.present) {
 		printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0930d94..0dd3bf7 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -49,8 +49,6 @@ MODULE_AUTHOR("Anil S Keshavamurthy");
 MODULE_DESCRIPTION("ACPI container driver");
 MODULE_LICENSE("GPL");
 
-#define ACPI_STA_PRESENT		(0x00000001)
-
 static int acpi_container_add(struct acpi_device *device);
 static int acpi_container_remove(struct acpi_device *device, int type);
 
@@ -75,13 +73,13 @@ static int is_device_present(acpi_handle
 
 	status = acpi_get_handle(handle, "_STA", &temp);
 	if (ACPI_FAILURE(status))
-		return 1;	/* _STA not found, assmue device present */
+		return 1;	/* _STA not found, assume device present */
 
 	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
 	if (ACPI_FAILURE(status))
 		return 0;	/* Firmware error */
 
-	return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+	return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
 }
 
 /*******************************************************************/
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 54a697f..4546bf8 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -29,6 +29,7 @@ #include <linux/types.h>
 #include <linux/notifier.h>
 #include <linux/platform_device.h>
 #include <linux/jiffies.h>
+#include <linux/stddef.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -667,6 +668,23 @@ static ssize_t write_undock(struct devic
 }
 DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
 
+/*
+ * show_dock_uid - read method for "uid" file in sysfs
+ */
+static ssize_t show_dock_uid(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	unsigned long lbuf;
+	acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
+	if(ACPI_FAILURE(status)) {
+	    return 0;
+	}
+	return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
+}
+DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+
+
+
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -715,6 +733,13 @@ static int dock_add(acpi_handle handle)
 		kfree(dock_station);
 		return ret;
 	}
+	ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+	if (ret) {
+		printk("Error %d adding sysfs file\n", ret);
+		platform_device_unregister(&dock_device);
+		kfree(dock_station);
+		return ret;
+	}
 
 	/* Find dependent devices */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a802962..e08cf98 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,6 +1,8 @@
 /*
- *  acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ *  ec.c - ACPI Embedded Controller Driver (v2.0)
  *
+ *  Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ *  Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -91,9 +93,9 @@ static struct acpi_driver acpi_ec_driver
 };
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
+/* External interfaces use first EC only, so remember */
 static struct acpi_ec {
 	acpi_handle handle;
-	unsigned long uid;
 	unsigned long gpe;
 	unsigned long command_addr;
 	unsigned long data_addr;
@@ -101,12 +103,8 @@ static struct acpi_ec {
 	struct mutex lock;
 	atomic_t query_pending;
 	atomic_t event_count;
-	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;
+} *boot_ec, *first_ec;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -173,56 +171,6 @@ static int acpi_ec_wait(struct acpi_ec *
 	return -ETIME;
 }
 
-#ifdef ACPI_FUTURE_USAGE
-/*
- * 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(struct acpi_ec *ec)
-{
-	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_IBF_0);
-		if (status)
-			goto end;
-		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->leaving_burst, 0);
-	return 0;
-      end:
-	ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
-	return -1;
-}
-
-int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
-{
-	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_IBF_0);
-		if (status)
-			goto end;
-		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"));
-	return -1;
-}
-#endif				/* ACPI_FUTURE_USAGE */
-
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
 					const u8 * wdata, unsigned wdata_len,
 					u8 * rdata, unsigned rdata_len)
@@ -312,6 +260,21 @@ static int acpi_ec_transaction(struct ac
 	return status;
 }
 
+/*
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+int acpi_ec_burst_enable(struct acpi_ec *ec)
+{
+	u8 d;
+	return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+}
+
+int acpi_ec_burst_disable(struct acpi_ec *ec)
+{
+	return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+}
+
 static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
 {
 	int result;
@@ -333,18 +296,33 @@ static int acpi_ec_write(struct acpi_ec 
 /*
  * Externally callable EC access functions. For now, assume 1 EC only
  */
+int ec_burst_enable(void)
+{
+	if (!first_ec)
+		return -ENODEV;
+	return acpi_ec_burst_enable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_enable);
+
+int ec_burst_disable(void)
+{
+	if (!first_ec)
+		return -ENODEV;
+	return acpi_ec_burst_disable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_disable);
+
 int ec_read(u8 addr, u8 * val)
 {
-	struct acpi_ec *ec;
 	int err;
 	u8 temp_data;
 
 	if (!first_ec)
 		return -ENODEV;
 
-	ec = acpi_driver_data(first_ec);
-
-	err = acpi_ec_read(ec, addr, &temp_data);
+	err = acpi_ec_read(first_ec, addr, &temp_data);
 
 	if (!err) {
 		*val = temp_data;
@@ -357,15 +335,12 @@ EXPORT_SYMBOL(ec_read);
 
 int ec_write(u8 addr, u8 val)
 {
-	struct acpi_ec *ec;
 	int err;
 
 	if (!first_ec)
 		return -ENODEV;
 
-	ec = acpi_driver_data(first_ec);
-
-	err = acpi_ec_write(ec, addr, val);
+	err = acpi_ec_write(first_ec, addr, val);
 
 	return err;
 }
@@ -376,14 +351,10 @@ int ec_transaction(u8 command,
 		   const u8 * wdata, unsigned wdata_len,
 		   u8 * rdata, unsigned rdata_len)
 {
-	struct acpi_ec *ec;
-
 	if (!first_ec)
 		return -ENODEV;
 
-	ec = acpi_driver_data(first_ec);
-
-	return acpi_ec_transaction(ec, command, wdata,
+	return acpi_ec_transaction(first_ec, command, wdata,
 				   wdata_len, rdata, rdata_len);
 }
 
@@ -420,7 +391,7 @@ static int acpi_ec_query(struct acpi_ec 
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
-	struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+	struct acpi_ec *ec = ec_cxt;
 	u8 value = 0;
 	char object_name[8];
 
@@ -438,8 +409,9 @@ static u32 acpi_ec_gpe_handler(void *dat
 {
 	acpi_status status = AE_OK;
 	u8 value;
-	struct acpi_ec *ec = (struct acpi_ec *)data;
+	struct acpi_ec *ec = data;
 	atomic_inc(&ec->event_count);
+
 	if (acpi_ec_mode == EC_INTR) {
 		wake_up(&ec->wait);
 	}
@@ -482,7 +454,7 @@ acpi_ec_space_handler(u32 function,
 		      void *handler_context, void *region_context)
 {
 	int result = 0;
-	struct acpi_ec *ec = NULL;
+	struct acpi_ec *ec = handler_context;
 	u64 temp = *value;
 	acpi_integer f_v = 0;
 	int i = 0;
@@ -494,8 +466,6 @@ acpi_ec_space_handler(u32 function,
 		return AE_BAD_PARAMETER;
 	}
 
-	ec = (struct acpi_ec *)handler_context;
-
       next_byte:
 	switch (function) {
 	case ACPI_READ:
@@ -551,18 +521,16 @@ static struct proc_dir_entry *acpi_ec_di
 
 static int acpi_ec_read_info(struct seq_file *seq, void *offset)
 {
-	struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+	struct acpi_ec *ec = seq->private;
 
 	if (!ec)
 		goto end;
 
-	seq_printf(seq, "gpe:                 0x%02x\n", (u32) ec->gpe);
-	seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-		   (u32) ec->command_addr, (u32) ec->data_addr);
-	seq_printf(seq, "use global lock:         %s\n",
+	seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
+	seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
+		   (unsigned)ec->command_addr, (unsigned)ec->data_addr);
+	seq_printf(seq, "use global lock:\t%s\n",
 		   ec->global_lock ? "yes" : "no");
-	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
       end:
 	return 0;
 }
@@ -619,154 +587,122 @@ static int acpi_ec_remove_fs(struct acpi
 /* --------------------------------------------------------------------------
                                Driver Interface
    -------------------------------------------------------------------------- */
+static acpi_status
+ec_parse_io_ports(struct acpi_resource *resource, void *context);
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
+
+static struct acpi_ec *make_acpi_ec(void)
+{
+	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	if (!ec)
+		return NULL;
+
+	atomic_set(&ec->query_pending, 1);
+	atomic_set(&ec->event_count, 1);
+	mutex_init(&ec->lock);
+	init_waitqueue_head(&ec->wait);
+
+	return ec;
+}
 
 static int acpi_ec_add(struct acpi_device *device)
 {
-	int result = 0;
 	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
 	if (!device)
 		return -EINVAL;
 
-	ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-	if (!ec)
-		return -ENOMEM;
-
-	ec->handle = device->handle;
-	ec->uid = -1;
-	mutex_init(&ec->lock);
-	atomic_set(&ec->query_pending, 0);
-	atomic_set(&ec->event_count, 1);
-	if (acpi_ec_mode == EC_INTR) {
-		atomic_set(&ec->leaving_burst, 1);
-		init_waitqueue_head(&ec->wait);
-	}
 	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
-	acpi_driver_data(device) = ec;
-
-	/* Use the global lock for all EC transactions? */
-	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 */
-	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->gpe,
-					&acpi_ec_gpe_handler);
+	ec = make_acpi_ec();
+	if (!ec)
+		return -ENOMEM;
 
-		kfree(ec_ecdt);
+	status = ec_parse_device(device->handle, 0, ec, NULL);
+	if (status != AE_CTRL_TERMINATE) {
+		kfree(ec);
+		return -EINVAL;
 	}
 
-	/* Get GPE bit assignment (EC events). */
-	/* TODO: Add support for _GPE returning a package */
-	status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Obtaining GPE bit assignment"));
-		result = -ENODEV;
-		goto end;
-	}
+	/* Check if we found the boot EC */
+	if (boot_ec) {
+		if (boot_ec->gpe == ec->gpe) {
+			/* We might have incorrect info for GL at boot time */
+			mutex_lock(&boot_ec->lock);
+			boot_ec->global_lock = ec->global_lock;
+			mutex_unlock(&boot_ec->lock);
+			kfree(ec);
+			ec = boot_ec;
+		}
+	} else
+		first_ec = ec;
+	ec->handle = device->handle;
+	acpi_driver_data(device) = ec;
 
-	result = acpi_ec_add_fs(device);
-	if (result)
-		goto end;
+	acpi_ec_add_fs(device);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
 			  acpi_device_name(device), acpi_device_bid(device),
 			  (u32) ec->gpe));
 
-	if (!first_ec)
-		first_ec = device;
-
-      end:
-	if (result)
-		kfree(ec);
-
-	return result;
+	return 0;
 }
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
-	struct acpi_ec *ec = NULL;
+	struct acpi_ec *ec;
 
 	if (!device)
 		return -EINVAL;
 
 	ec = acpi_driver_data(device);
-
 	acpi_ec_remove_fs(device);
+	acpi_driver_data(device) = NULL;
+	if (ec == first_ec)
+		first_ec = NULL;
 
-	kfree(ec);
-
+	/* Don't touch boot EC */
+	if (boot_ec != ec)
+		kfree(ec);
 	return 0;
 }
 
 static acpi_status
-acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ec_parse_io_ports(struct acpi_resource *resource, void *context)
 {
-	struct acpi_ec *ec = (struct acpi_ec *)context;
+	struct acpi_ec *ec = context;
 
-	if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+	if (resource->type != ACPI_RESOURCE_TYPE_IO)
 		return AE_OK;
-	}
 
 	/*
 	 * The first address region returned is the data port, and
 	 * the second address region returned is the status/command
 	 * port.
 	 */
-	if (ec->data_addr == 0) {
+	if (ec->data_addr == 0)
 		ec->data_addr = resource->data.io.minimum;
-	} else if (ec->command_addr == 0) {
+	else if (ec->command_addr == 0)
 		ec->command_addr = resource->data.io.minimum;
-	} else {
+	else
 		return AE_CTRL_TERMINATE;
-	}
 
 	return AE_OK;
 }
 
-static int acpi_ec_start(struct acpi_device *device)
+static int ec_install_handlers(struct acpi_ec *ec)
 {
-	acpi_status status = AE_OK;
-	struct acpi_ec *ec = NULL;
-
-	if (!device)
-		return -EINVAL;
-
-	ec = acpi_driver_data(device);
-
-	if (!ec)
-		return -EINVAL;
-
-	/*
-	 * Get I/O port addresses. Convert to GAS format.
-	 */
-	status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
-				     acpi_ec_io_ports, ec);
-	if (ACPI_FAILURE(status) || ec->command_addr == 0) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"Error getting I/O port addresses"));
-		return -ENODEV;
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-			  ec->gpe, ec->command_addr, ec->data_addr));
-
-	/*
-	 * Install GPE handler
-	 */
+	acpi_status status;
 	status = acpi_install_gpe_handler(NULL, ec->gpe,
 					  ACPI_GPE_EDGE_TRIGGERED,
 					  &acpi_ec_gpe_handler, ec);
-	if (ACPI_FAILURE(status)) {
+	if (ACPI_FAILURE(status))
 		return -ENODEV;
-	}
+
 	acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
 	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
@@ -779,18 +715,49 @@ static int acpi_ec_start(struct acpi_dev
 		return -ENODEV;
 	}
 
-	return AE_OK;
+	/* EC is fully operational, allow queries */
+	atomic_set(&ec->query_pending, 0);
+
+	return 0;
+}
+
+static int acpi_ec_start(struct acpi_device *device)
+{
+	struct acpi_ec *ec;
+
+	if (!device)
+		return -EINVAL;
+
+	ec = acpi_driver_data(device);
+
+	if (!ec)
+		return -EINVAL;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+			  ec->gpe, ec->command_addr, ec->data_addr));
+
+	/* Boot EC is already working */
+	if (ec == boot_ec)
+		return 0;
+
+	return ec_install_handlers(ec);
 }
 
 static int acpi_ec_stop(struct acpi_device *device, int type)
 {
-	acpi_status status = AE_OK;
-	struct acpi_ec *ec = NULL;
+	acpi_status status;
+	struct acpi_ec *ec;
 
 	if (!device)
 		return -EINVAL;
 
 	ec = acpi_driver_data(device);
+	if (!ec)
+		return -EINVAL;
+
+	/* Don't touch boot EC */
+	if (ec == boot_ec)
+		return 0;
 
 	status = acpi_remove_address_space_handler(ec->handle,
 						   ACPI_ADR_SPACE_EC,
@@ -805,164 +772,67 @@ static int acpi_ec_stop(struct acpi_devi
 	return 0;
 }
 
-static acpi_status __init
-acpi_fake_ecdt_callback(acpi_handle handle,
-			u32 Level, void *context, void **retval)
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
 {
 	acpi_status status;
 
-	mutex_init(&ec_ecdt->lock);
-	atomic_set(&ec_ecdt->event_count, 1);
-	if (acpi_ec_mode == EC_INTR) {
-		init_waitqueue_head(&ec_ecdt->wait);
-	}
+	struct acpi_ec *ec = context;
 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-				     acpi_ec_io_ports, ec_ecdt);
+				     ec_parse_io_ports, ec);
 	if (ACPI_FAILURE(status))
 		return status;
 
-	ec_ecdt->uid = -1;
-	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
-
-	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
+	/* Get GPE bit assignment (EC events). */
+	/* TODO: Add support for _GPE returning a package */
+	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
 	if (ACPI_FAILURE(status))
 		return status;
-	ec_ecdt->global_lock = TRUE;
-	ec_ecdt->handle = handle;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-			  ec_ecdt->gpe, ec_ecdt->command_addr,
-			  ec_ecdt->data_addr));
 
-	return AE_CTRL_TERMINATE;
-}
-
-/*
- * Some BIOS (such as some from Gateway laptops) access EC region very early
- * such as in BAT0._INI or EC._INI before an EC device is found and
- * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
- * required, but if EC regison is accessed early, it is required.
- * The routine tries to workaround the BIOS bug by pre-scan EC device
- * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
- * op region (since _REG isn't invoked yet). The assumption is true for
- * all systems found.
- */
-static int __init acpi_ec_fake_ecdt(void)
-{
-	acpi_status status;
-	int ret = 0;
+	/* Use the global lock for all EC transactions? */
+	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
+	ec->handle = handle;
 
-	ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-	if (!ec_ecdt) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+			  ec->gpe, ec->command_addr, ec->data_addr));
 
-	status = acpi_get_devices(ACPI_EC_HID,
-				  acpi_fake_ecdt_callback, NULL, NULL);
-	if (ACPI_FAILURE(status)) {
-		kfree(ec_ecdt);
-		ec_ecdt = NULL;
-		ret = -ENODEV;
-		ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
-		goto error;
-	}
-	return 0;
-      error:
-	return ret;
+	return AE_CTRL_TERMINATE;
 }
 
-static int __init acpi_ec_get_real_ecdt(void)
+int __init acpi_ec_ecdt_probe(void)
 {
+	int ret;
 	acpi_status status;
 	struct acpi_table_ecdt *ecdt_ptr;
 
-	status = acpi_get_table(ACPI_SIG_ECDT, 1,
-				(struct acpi_table_header **)&ecdt_ptr);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
+	boot_ec = make_acpi_ec();
+	if (!boot_ec)
+		return -ENOMEM;
 	/*
-	 * Generate a temporary ec context to use until the namespace is scanned
+	 * Generate a boot ec context
 	 */
-	ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
-	if (!ec_ecdt)
-		return -ENOMEM;
 
-	mutex_init(&ec_ecdt->lock);
-	atomic_set(&ec_ecdt->event_count, 1);
-	if (acpi_ec_mode == EC_INTR) {
-		init_waitqueue_head(&ec_ecdt->wait);
-	}
-	ec_ecdt->command_addr = ecdt_ptr->control.address;
-	ec_ecdt->data_addr = ecdt_ptr->data.address;
-	ec_ecdt->gpe = ecdt_ptr->gpe;
-	/* use the GL just to be safe */
-	ec_ecdt->global_lock = TRUE;
-	ec_ecdt->uid = ecdt_ptr->uid;
-
-	status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
-	if (ACPI_FAILURE(status)) {
+	status = acpi_get_table(ACPI_SIG_ECDT, 1,
+				(struct acpi_table_header **)&ecdt_ptr);
+	if (ACPI_FAILURE(status))
 		goto error;
-	}
-
-	return 0;
-      error:
-	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
-	kfree(ec_ecdt);
-	ec_ecdt = NULL;
 
-	return -ENODEV;
-}
-
-static int __initdata acpi_fake_ecdt_enabled;
-int __init acpi_ec_ecdt_probe(void)
-{
-	acpi_status status;
-	int ret;
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
 
-	ret = acpi_ec_get_real_ecdt();
-	/* Try to make a fake ECDT */
-	if (ret && acpi_fake_ecdt_enabled) {
-		ret = acpi_ec_fake_ecdt();
-	}
+	boot_ec->command_addr = ecdt_ptr->control.address;
+	boot_ec->data_addr = ecdt_ptr->data.address;
+	boot_ec->gpe = ecdt_ptr->gpe;
+	boot_ec->handle = ACPI_ROOT_OBJECT;
 
-	if (ret)
+	ret = ec_install_handlers(boot_ec);
+	if (!ret) {
+		first_ec = boot_ec;
 		return 0;
-
-	/*
-	 * Install GPE handler
-	 */
-	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
-					  ACPI_GPE_EDGE_TRIGGERED,
-					  &acpi_ec_gpe_handler, ec_ecdt);
-	if (ACPI_FAILURE(status)) {
-		goto error;
 	}
-	acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
-
-	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
-						    ACPI_ADR_SPACE_EC,
-						    &acpi_ec_space_handler,
-						    &acpi_ec_space_setup,
-						    ec_ecdt);
-	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
-					&acpi_ec_gpe_handler);
-		goto error;
-	}
-
-	return 0;
-
       error:
-	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
-	kfree(ec_ecdt);
-	ec_ecdt = NULL;
+	kfree(boot_ec);
+	boot_ec = NULL;
 
 	return -ENODEV;
 }
@@ -1003,13 +873,6 @@ static void __exit acpi_ec_exit(void)
 }
 #endif				/* 0 */
 
-static int __init acpi_fake_ecdt_setup(char *str)
-{
-	acpi_fake_ecdt_enabled = 1;
-	return 1;
-}
-
-__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
 static int __init acpi_ec_set_intr_mode(char *str)
 {
 	int intr;
@@ -1017,12 +880,8 @@ static int __init acpi_ec_set_intr_mode(
 	if (!get_option(&str, &intr))
 		return 0;
 
-	if (intr) {
-		acpi_ec_mode = EC_INTR;
-	} else {
-		acpi_ec_mode = EC_POLL;
-	}
-	acpi_ec_driver.ops.add = acpi_ec_add;
+	acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
+
 	printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
 
 	return 1;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 4334c20..41427a4 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -245,6 +245,35 @@ arch_initcall(init_acpi_device_notify);
 
 #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
 
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+	return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup()	do{}while(0)
+#define rtc_wake_on		NULL
+#define rtc_wake_off		NULL
+#endif
+
 /* Every ACPI platform has a mc146818 compatible "cmos rtc".  Here we find
  * its device node and pass extra config data.  This helps its driver use
  * capabilities that the now-obsolete mc146818 didn't have, and informs it
@@ -283,11 +312,24 @@ static int __init acpi_rtc_init(void)
 	struct device *dev = get_rtc_dev();
 
 	if (dev) {
+		rtc_wake_setup();
+		rtc_info.wake_on = rtc_wake_on;
+		rtc_info.wake_off = rtc_wake_off;
+
+		/* workaround bug in some ACPI tables */
+		if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+			DBG("bogus FADT month_alarm\n");
+			acpi_gbl_FADT.month_alarm = 0;
+		}
+
 		rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
 		rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
 		rtc_info.rtc_century = acpi_gbl_FADT.century;
 
-		/* NOTE:  acpi_gbl_FADT->rtcs4 is NOT currently useful */
+		/* NOTE:  S4_RTC_WAKE is NOT currently useful to Linux */
+		if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+			printk(PREFIX "RTC can wake from S4\n");
+
 
 		dev->platform_data = &rtc_info;
 
@@ -296,7 +338,7 @@ static int __init acpi_rtc_init(void)
 
 		put_device(dev);
 	} else
-		pr_debug("ACPI: RTC unavailable?\n");
+		DBG("RTC unavailable?\n");
 	return 0;
 }
 /* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
deleted file mode 100644
index acab4a4..0000000
--- a/drivers/acpi/i2c_ec.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
- *
- * This program is free software; 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.
- */
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/delay.h>
-
-#include "i2c_ec.h"
-
-#define	xudelay(t)	udelay(t)
-#define	xmsleep(t)	msleep(t)
-
-#define ACPI_EC_HC_COMPONENT	0x00080000
-#define ACPI_EC_HC_CLASS	"ec_hc_smbus"
-#define ACPI_EC_HC_HID		"ACPI0001"
-#define ACPI_EC_HC_DEVICE_NAME	"EC HC smbus"
-
-#define _COMPONENT		ACPI_EC_HC_COMPONENT
-
-ACPI_MODULE_NAME("i2c_ec");
-
-static int acpi_ec_hc_add(struct acpi_device *device);
-static int acpi_ec_hc_remove(struct acpi_device *device, int type);
-
-static struct acpi_driver acpi_ec_hc_driver = {
-	.name = "i2c_ec",
-	.class = ACPI_EC_HC_CLASS,
-	.ids = ACPI_EC_HC_HID,
-	.ops = {
-		.add = acpi_ec_hc_add,
-		.remove = acpi_ec_hc_remove,
-		},
-};
-
-/* Various bit mask for EC_SC (R) */
-#define OBF		0x01
-#define IBF		0x02
-#define CMD		0x08
-#define BURST		0x10
-#define SCI_EVT		0x20
-#define SMI_EVT		0x40
-
-/* Commands for EC_SC (W) */
-#define RD_EC		0x80
-#define WR_EC		0x81
-#define BE_EC		0x82
-#define BD_EC		0x83
-#define QR_EC		0x84
-
-/*
- * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
- */
-
-#define ACPI_EC_SMB_PRTCL	0x00	/* protocol, PEC */
-#define ACPI_EC_SMB_STS		0x01	/* status */
-#define ACPI_EC_SMB_ADDR	0x02	/* address */
-#define ACPI_EC_SMB_CMD		0x03	/* command */
-#define ACPI_EC_SMB_DATA	0x04	/* 32 data registers */
-#define ACPI_EC_SMB_BCNT	0x24	/* number of data bytes */
-#define ACPI_EC_SMB_ALRM_A	0x25	/* alarm address */
-#define ACPI_EC_SMB_ALRM_D	0x26	/* 2 bytes alarm data */
-
-#define ACPI_EC_SMB_STS_DONE	0x80
-#define ACPI_EC_SMB_STS_ALRM	0x40
-#define ACPI_EC_SMB_STS_RES	0x20
-#define ACPI_EC_SMB_STS_STATUS	0x1f
-
-#define ACPI_EC_SMB_STATUS_OK		0x00
-#define ACPI_EC_SMB_STATUS_FAIL		0x07
-#define ACPI_EC_SMB_STATUS_DNAK		0x10
-#define ACPI_EC_SMB_STATUS_DERR		0x11
-#define ACPI_EC_SMB_STATUS_CMD_DENY	0x12
-#define ACPI_EC_SMB_STATUS_UNKNOWN	0x13
-#define ACPI_EC_SMB_STATUS_ACC_DENY	0x17
-#define ACPI_EC_SMB_STATUS_TIMEOUT	0x18
-#define ACPI_EC_SMB_STATUS_NOTSUP	0x19
-#define ACPI_EC_SMB_STATUS_BUSY		0x1A
-#define ACPI_EC_SMB_STATUS_PEC		0x1F
-
-#define ACPI_EC_SMB_PRTCL_WRITE			0x00
-#define ACPI_EC_SMB_PRTCL_READ			0x01
-#define ACPI_EC_SMB_PRTCL_QUICK			0x02
-#define ACPI_EC_SMB_PRTCL_BYTE			0x04
-#define ACPI_EC_SMB_PRTCL_BYTE_DATA		0x06
-#define ACPI_EC_SMB_PRTCL_WORD_DATA		0x08
-#define ACPI_EC_SMB_PRTCL_BLOCK_DATA		0x0a
-#define ACPI_EC_SMB_PRTCL_PROC_CALL		0x0c
-#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
-#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA	0x4a
-#define ACPI_EC_SMB_PRTCL_PEC			0x80
-
-/* Length of pre/post transaction sleep (msec) */
-#define ACPI_EC_SMB_TRANSACTION_SLEEP		1
-#define ACPI_EC_SMB_ACCESS_SLEEP1		1
-#define ACPI_EC_SMB_ACCESS_SLEEP2		10
-
-static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
-{
-	u8 val;
-	int err;
-
-	err = ec_read(smbus->base + address, &val);
-	if (!err) {
-		*data = val;
-	}
-	xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
-	return (err);
-}
-
-static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
-{
-	int err;
-
-	err = ec_write(smbus->base + address, data);
-	return (err);
-}
-
-static int
-acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
-		   char read_write, u8 command, int size,
-		   union i2c_smbus_data *data)
-{
-	struct acpi_ec_smbus *smbus = adap->algo_data;
-	unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
-	int i;
-
-	if (read_write == I2C_SMBUS_READ) {
-		protocol = ACPI_EC_SMB_PRTCL_READ;
-	} else {
-		protocol = ACPI_EC_SMB_PRTCL_WRITE;
-	}
-	pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
-
-	switch (size) {
-
-	case I2C_SMBUS_QUICK:
-		protocol |= ACPI_EC_SMB_PRTCL_QUICK;
-		read_write = I2C_SMBUS_WRITE;
-		break;
-
-	case I2C_SMBUS_BYTE:
-		if (read_write == I2C_SMBUS_WRITE) {
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
-		}
-		protocol |= ACPI_EC_SMB_PRTCL_BYTE;
-		break;
-
-	case I2C_SMBUS_BYTE_DATA:
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		if (read_write == I2C_SMBUS_WRITE) {
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
-		}
-		protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
-		break;
-
-	case I2C_SMBUS_WORD_DATA:
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		if (read_write == I2C_SMBUS_WRITE) {
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
-					  data->word >> 8);
-		}
-		protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
-		break;
-
-	case I2C_SMBUS_BLOCK_DATA:
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		if (read_write == I2C_SMBUS_WRITE) {
-			len = min_t(u8, data->block[0], 32);
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-			for (i = 0; i < len; i++)
-				acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-						  data->block[i + 1]);
-		}
-		protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
-		break;
-
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-		len = min_t(u8, data->block[0], 32);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-		if (read_write == I2C_SMBUS_WRITE) {
-			for (i = 0; i < len; i++) {
-				acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-						  data->block[i + 1]);
-			}
-		}
-		protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
-		break;
-
-	case I2C_SMBUS_PROC_CALL:
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
-		protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
-		read_write = I2C_SMBUS_READ;
-		break;
-
-	case I2C_SMBUS_BLOCK_PROC_CALL:
-		protocol |= pec;
-		len = min_t(u8, data->block[0], 31);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
-		acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
-		for (i = 0; i < len; i++)
-			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
-					  data->block[i + 1]);
-		protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
-		read_write = I2C_SMBUS_READ;
-		break;
-
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
-				  "Unsupported transaction %d\n", size));
-		return (-1);
-	}
-
-	acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
-	acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
-
-	acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-
-	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
-		xudelay(500);
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-	}
-	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
-		xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-	}
-	if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
-	    || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
-		return (-1);
-	}
-
-	if (read_write == I2C_SMBUS_WRITE) {
-		return (0);
-	}
-
-	switch (size) {
-
-	case I2C_SMBUS_BYTE:
-	case I2C_SMBUS_BYTE_DATA:
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
-		break;
-
-	case I2C_SMBUS_WORD_DATA:
-	case I2C_SMBUS_PROC_CALL:
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
-		data->word = (temp[1] << 8) | temp[0];
-		break;
-
-	case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_BLOCK_PROC_CALL:
-		len = 0;
-		acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
-		len = min_t(u8, len, 32);
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-		for (i = 0; i < len; i++)
-			acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
-					 data->block + i + 1);
-		data->block[0] = len;
-		break;
-	}
-
-	return (0);
-}
-
-static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
-{
-
-	return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-		I2C_FUNC_SMBUS_BLOCK_DATA |
-		I2C_FUNC_SMBUS_PROC_CALL |
-		I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
-		I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
-}
-
-static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
-	.smbus_xfer = acpi_ec_smb_access,
-	.functionality = acpi_ec_smb_func,
-};
-
-static int acpi_ec_hc_add(struct acpi_device *device)
-{
-	int status;
-	unsigned long val;
-	struct acpi_ec_hc *ec_hc;
-	struct acpi_ec_smbus *smbus;
-
-	if (!device) {
-		return -EINVAL;
-	}
-
-	ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
-	if (!ec_hc) {
-		return -ENOMEM;
-	}
-
-	smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
-	if (!smbus) {
-		kfree(ec_hc);
-		return -ENOMEM;
-	}
-
-	ec_hc->handle = device->handle;
-	strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
-	strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
-	acpi_driver_data(device) = ec_hc;
-
-	status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
-		kfree(ec_hc);
-		kfree(smbus);
-		return -EIO;
-	}
-
-	smbus->ec = acpi_driver_data(device->parent);
-	smbus->base = (val & 0xff00ull) >> 8;
-	smbus->alert = val & 0xffull;
-
-	smbus->adapter.owner = THIS_MODULE;
-	smbus->adapter.algo = &acpi_ec_smbus_algorithm;
-	smbus->adapter.algo_data = smbus;
-	smbus->adapter.dev.parent = &device->dev;
-
-	if (i2c_add_adapter(&smbus->adapter)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
-				  "EC SMBus adapter: Failed to register adapter\n"));
-		kfree(smbus);
-		kfree(ec_hc);
-		return -EIO;
-	}
-
-	ec_hc->smbus = smbus;
-
-	printk(KERN_INFO PREFIX "%s [%s]\n",
-	       acpi_device_name(device), acpi_device_bid(device));
-
-	return AE_OK;
-}
-
-static int acpi_ec_hc_remove(struct acpi_device *device, int type)
-{
-	struct acpi_ec_hc *ec_hc;
-
-	if (!device) {
-		return -EINVAL;
-	}
-	ec_hc = acpi_driver_data(device);
-
-	i2c_del_adapter(&ec_hc->smbus->adapter);
-	kfree(ec_hc->smbus);
-	kfree(ec_hc);
-
-	return AE_OK;
-}
-
-static int __init acpi_ec_hc_init(void)
-{
-	int result;
-
-	result = acpi_bus_register_driver(&acpi_ec_hc_driver);
-	if (result < 0) {
-		return -ENODEV;
-	}
-	return 0;
-}
-
-static void __exit acpi_ec_hc_exit(void)
-{
-	acpi_bus_unregister_driver(&acpi_ec_hc_driver);
-}
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
-{
-	return acpi_driver_data(device->parent);
-}
-
-EXPORT_SYMBOL(acpi_get_ec_hc);
-
-module_init(acpi_ec_hc_init);
-module_exit(acpi_ec_hc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ducrot Bruno");
-MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
deleted file mode 100644
index 7c53fb7..0000000
--- a/drivers/acpi/i2c_ec.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- *
- * This program is free software; 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.
- */
-
-struct acpi_ec_smbus {
-	struct i2c_adapter adapter;
-	union acpi_ec *ec;
-	int base;
-	int alert;
-};
-
-struct acpi_ec_hc {
-	acpi_handle handle;
-	struct acpi_ec_smbus *smbus;
-};
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
deleted file mode 100644
index dc10966..0000000
--- a/drivers/acpi/ibm_acpi.c
+++ /dev/null
@@ -1,2798 +0,0 @@
-/*
- *  ibm_acpi.c - IBM ThinkPad ACPI Extras
- *
- *
- *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- *  Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU 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 IBM_VERSION "0.13"
-
-/*
- *  Changelog:
- *
- *  2006-11-22	0.13	new maintainer
- *  			changelog now lives in git commit history, and will
- *  			not be updated further in-file.
- *  
- *  2005-08-17  0.12	fix compilation on 2.6.13-rc kernels
- *  2005-03-17	0.11	support for 600e, 770x
- *			    thanks to Jamie Lentin <lentinj@dial.pipex.com>
- *			support for 770e, G41
- *			G40 and G41 don't have a thinklight
- *			temperatures no longer experimental
- *			experimental brightness control
- *			experimental volume control
- *			experimental fan enable/disable
- *  2005-01-16	0.10	fix module loading on R30, R31 
- *  2005-01-16	0.9	support for 570, R30, R31
- *			ultrabay support on A22p, A3x
- *			limit arg for cmos, led, beep, drop experimental status
- *			more capable led control on A21e, A22p, T20-22, X20
- *			experimental temperatures and fan speed
- *			experimental embedded controller register dump
- *			mark more functions as __init, drop incorrect __exit
- *			use MODULE_VERSION
- *			    thanks to Henrik Brix Andersen <brix@gentoo.org>
- *			fix parameter passing on module loading
- *			    thanks to Rusty Russell <rusty@rustcorp.com.au>
- *			    thanks to Jim Radford <radford@blackbean.org>
- *  2004-11-08	0.8	fix init error case, don't return from a macro
- *			    thanks to Chris Wright <chrisw@osdl.org>
- *  2004-10-23	0.7	fix module loading on A21e, A22p, T20, T21, X20
- *			fix led control on A21e
- *  2004-10-19	0.6	use acpi_bus_register_driver() to claim HKEY device
- *  2004-10-18	0.5	thinklight support on A21e, G40, R32, T20, T21, X20
- *			proc file format changed
- *			video_switch command
- *			experimental cmos control
- *			experimental led control
- *			experimental acpi sounds
- *  2004-09-16	0.4	support for module parameters
- *			hotkey mask can be prefixed by 0x
- *			video output switching
- *			video expansion control
- *			ultrabay eject support
- *			removed lcd brightness/on/off control, didn't work
- *  2004-08-17	0.3	support for R40
- *			lcd off, brightness control
- *			thinklight on/off
- *  2004-08-14	0.2	support for T series, X20
- *			bluetooth enable/disable
- *			hotkey events disabled by default
- *			removed fan control, currently useless
- *  2004-08-09	0.1	initial release, support for X series
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#define IBM_NAME "ibm"
-#define IBM_DESC "IBM ThinkPad ACPI Extras"
-#define IBM_FILE "ibm_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
-
-#define IBM_DIR IBM_NAME
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR	   KERN_ERR    IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO   KERN_INFO   IBM_LOG
-#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-#define __unused __attribute__ ((unused))
-
-static int experimental;
-module_param(experimental, int, 0);
-
-static acpi_handle root_handle = NULL;
-
-#define IBM_HANDLE(object, parent, paths...)			\
-	static acpi_handle  object##_handle;			\
-	static acpi_handle *object##_parent = &parent##_handle;	\
-	static char        *object##_path;			\
-	static char        *object##_paths[] = { paths }
-
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",	/* 240, 240x */
-	   "\\_SB.PCI.ISA.EC",	/* 570 */
-	   "\\_SB.PCI0.ISA0.EC0",	/* 600e/x, 770e, 770x */
-	   "\\_SB.PCI0.ISA.EC",	/* A21e, A2xm/p, T20-22, X20-21 */
-	   "\\_SB.PCI0.AD4S.EC0",	/* i1400, R30 */
-	   "\\_SB.PCI0.ICH3.EC0",	/* R31 */
-	   "\\_SB.PCI0.LPC.EC",	/* all others */
-    );
-
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",	/* 570 */
-	   "\\_SB.PCI0.AGP0.VID0",	/* 600e/x, 770x */
-	   "\\_SB.PCI0.VID0",	/* 770e */
-	   "\\_SB.PCI0.VID",	/* A21e, G4x, R50e, X30, X40 */
-	   "\\_SB.PCI0.AGP.VID",	/* all others */
-    );				/* R30, R31 */
-
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");	/* G41 */
-
-IBM_HANDLE(cmos, root, "\\UCMS",	/* R50, R50e, R50p, R51, T4x, X31, X40 */
-	   "\\CMOS",		/* A3x, G4x, R32, T23, T30, X22-24, X30 */
-	   "\\CMS",		/* R40, R40e */
-    );				/* all others */
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_HANDLE(dock, root, "\\_SB.GDCK",	/* X30, X31, X40 */
-	   "\\_SB.PCI0.DOCK",	/* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
-	   "\\_SB.PCI0.PCI1.DOCK",	/* all others */
-	   "\\_SB.PCI.ISA.SLCE",	/* 570 */
-    );				/* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",	/* 570 */
-	   "\\_SB.PCI0.IDE0.IDES.IDSM",	/* 600e/x, 770e, 770x */
-	   "\\_SB.PCI0.SATA.SCND.MSTR",	/* T60, X60, Z60 */ 
-	   "\\_SB.PCI0.IDE0.SCND.MSTR",	/* all others */
-    );				/* A21e, R30, R31 */
-
-IBM_HANDLE(bay_ej, bay, "_EJ3",	/* 600e/x, A2xm/p, A3x */
-	   "_EJ0",		/* all others */
-    );				/* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",	/* A3x, R32 */
-	   "\\_SB.PCI0.IDE0.IDEP.IDPS",	/* 600e/x, 770e, 770x */
-    );				/* all others */
-
-IBM_HANDLE(bay2_ej, bay2, "_EJ3",	/* 600e/x, 770e, A3x */
-	   "_EJ0",		/* 770x */
-    );				/* all others */
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI");	/* 570 */
-
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY",	/* 600e/x, 770e, 770x */
-	   "^HKEY",		/* R30, R31 */
-	   "HKEY",		/* all others */
-    );				/* 570 */
-
-IBM_HANDLE(lght, root, "\\LGHT");	/* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB");	/* G4x */
-
-IBM_HANDLE(led, ec, "SLED",	/* 570 */
-	   "SYSL",		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-	   "LED",		/* all others */
-    );				/* R30, R31 */
-
-IBM_HANDLE(beep, ec, "BEEP");	/* all except R30, R31 */
-IBM_HANDLE(ecrd, ec, "ECRD");	/* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR");	/* 570 */
-IBM_HANDLE(fans, ec, "FANS");	/* X31, X40, X41 */
-
-IBM_HANDLE(gfan, ec, "GFAN",	/* 570 */
-	   "\\FSPD",		/* 600e/x, 770e, 770x */
-    );				/* all others */
-
-IBM_HANDLE(sfan, ec, "SFAN",	/* 570 */
-	   "JFNS",		/* 770x-JL */
-    );				/* all others */
-
-#define IBM_HKEY_HID	"IBM0068"
-#define IBM_PCI_HID	"PNP0A03"
-
-enum thermal_access_mode {
-	IBMACPI_THERMAL_NONE = 0,	/* No thermal support */
-	IBMACPI_THERMAL_ACPI_TMP07,	/* Use ACPI TMP0-7 */
-	IBMACPI_THERMAL_ACPI_UPDT,	/* Use ACPI TMP0-7 with UPDT */
-	IBMACPI_THERMAL_TPEC_8,		/* Use ACPI EC regs, 8 sensors */
-	IBMACPI_THERMAL_TPEC_16,	/* Use ACPI EC regs, 16 sensors */
-};
-
-#define IBMACPI_MAX_THERMAL_SENSORS 16	/* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
-	s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
-};
-
-/*
- * FAN ACCESS MODES
- *
- * IBMACPI_FAN_RD_ACPI_GFAN:
- * 	ACPI GFAN method: returns fan level
- *
- * 	see IBMACPI_FAN_WR_ACPI_SFAN
- * 	EC 0x2f not available if GFAN exists
- *
- * IBMACPI_FAN_WR_ACPI_SFAN:
- * 	ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
- *
- * 	EC 0x2f might be available *for reading*, but never for writing.
- *
- * IBMACPI_FAN_WR_TPEC:
- * 	ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
- * 	on almost all ThinkPads
- *
- * 	Fan speed changes of any sort (including those caused by the
- * 	disengaged mode) are usually done slowly by the firmware as the
- * 	maximum ammount of fan duty cycle change per second seems to be
- * 	limited.
- *
- * 	Reading is not available if GFAN exists.
- * 	Writing is not available if SFAN exists.
- *
- * 	Bits
- *	 7	automatic mode engaged;
- *  		(default operation mode of the ThinkPad)
- * 		fan level is ignored in this mode.
- *	 6	disengage mode (takes precedence over bit 7);
- *		not available on all thinkpads.  May disable
- *		the tachometer, and speeds up fan to 100% duty-cycle,
- *		which speeds it up far above the standard RPM
- *		levels.  It is not impossible that it could cause
- *		hardware damage.
- *	5-3	unused in some models.  Extra bits for fan level
- *		in others, but still useless as all values above
- *		7 map to the same speed as level 7 in these models.
- *	2-0	fan level (0..7 usually)
- *			0x00 = stop
- * 			0x07 = max (set when temperatures critical)
- * 		Some ThinkPads may have other levels, see
- * 		IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
- *
- *	FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
- *	boot. Apparently the EC does not intialize it, so unless ACPI DSDT
- *	does so, its initial value is meaningless (0x07).
- *
- *	For firmware bugs, refer to:
- *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * 	----
- *
- *	ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
- *	Main fan tachometer reading (in RPM)
- *
- *	This register is present on all ThinkPads with a new-style EC, and
- *	it is known not to be present on the A21m/e, and T22, as there is
- *	something else in offset 0x84 according to the ACPI DSDT.  Other
- *	ThinkPads from this same time period (and earlier) probably lack the
- *	tachometer as well.
- *
- *	Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
- *	was never fixed by IBM to report the EC firmware version string
- *	probably support the tachometer (like the early X models), so
- *	detecting it is quite hard.  We need more data to know for sure.
- *
- *	FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
- *	might result.
- *
- *	FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
- *	register is not invalidated in ThinkPads that disable tachometer
- *	readings.  Thus, the tachometer readings go stale.
- *
- *	For firmware bugs, refer to:
- *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * IBMACPI_FAN_WR_ACPI_FANS:
- *	ThinkPad X31, X40, X41.  Not available in the X60.
- *
- *	FANS ACPI handle: takes three arguments: low speed, medium speed,
- *	high speed.  ACPI DSDT seems to map these three speeds to levels
- *	as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
- *	(this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
- *
- * 	The speeds are stored on handles
- * 	(FANA:FAN9), (FANC:FANB), (FANE:FAND).
- *
- * 	There are three default speed sets, acessible as handles:
- * 	FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
- *
- * 	ACPI DSDT switches which set is in use depending on various
- * 	factors.
- *
- * 	IBMACPI_FAN_WR_TPEC is also available and should be used to
- * 	command the fan.  The X31/X40/X41 seems to have 8 fan levels,
- * 	but the ACPI tables just mention level 7.
- */
-
-enum fan_status_access_mode {
-	IBMACPI_FAN_NONE = 0,		/* No fan status or control */
-	IBMACPI_FAN_RD_ACPI_GFAN,	/* Use ACPI GFAN */
-	IBMACPI_FAN_RD_TPEC,		/* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
-	IBMACPI_FAN_WR_NONE = 0,	/* No fan control */
-	IBMACPI_FAN_WR_ACPI_SFAN,	/* Use ACPI SFAN */
-	IBMACPI_FAN_WR_TPEC,		/* Use ACPI EC reg 0x2f */
-	IBMACPI_FAN_WR_ACPI_FANS,	/* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
-	IBMACPI_FAN_CMD_SPEED 	= 0x0001,	/* speed command */
-	IBMACPI_FAN_CMD_LEVEL 	= 0x0002,	/* level command  */
-	IBMACPI_FAN_CMD_ENABLE	= 0x0004,	/* enable/disable cmd,
-						 * and also watchdog cmd */
-};
-
-enum {					/* Fan control constants */
-	fan_status_offset = 0x2f,	/* EC register 0x2f */
-	fan_rpm_offset = 0x84,		/* EC register 0x84: LSB, 0x85 MSB (RPM)
-					 * 0x84 must be read before 0x85 */
-
-	IBMACPI_FAN_EC_DISENGAGED 	= 0x40,	/* EC mode: tachometer
-						 * disengaged */
-	IBMACPI_FAN_EC_AUTO		= 0x80, /* EC mode: auto fan
-						 * control */
-};
-
-static char *ibm_thinkpad_ec_found = NULL;
-
-struct ibm_struct {
-	char *name;
-	char param[32];
-
-	char *hid;
-	struct acpi_driver *driver;
-
-	int (*init) (void);
-	int (*read) (char *);
-	int (*write) (char *);
-	void (*exit) (void);
-
-	void (*notify) (struct ibm_struct *, u32);
-	acpi_handle *handle;
-	int type;
-	struct acpi_device *device;
-
-	int driver_registered;
-	int proc_created;
-	int init_called;
-	int notify_installed;
-
-	int experimental;
-};
-
-static struct proc_dir_entry *proc_dir = NULL;
-
-static struct backlight_device *ibm_backlight_device = NULL;
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-static int acpi_evalf(acpi_handle handle,
-		      void *res, char *method, char *fmt, ...)
-{
-	char *fmt0 = fmt;
-	struct acpi_object_list params;
-	union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
-	struct acpi_buffer result, *resultp;
-	union acpi_object out_obj;
-	acpi_status status;
-	va_list ap;
-	char res_type;
-	int success;
-	int quiet;
-
-	if (!*fmt) {
-		printk(IBM_ERR "acpi_evalf() called with empty format\n");
-		return 0;
-	}
-
-	if (*fmt == 'q') {
-		quiet = 1;
-		fmt++;
-	} else
-		quiet = 0;
-
-	res_type = *(fmt++);
-
-	params.count = 0;
-	params.pointer = &in_objs[0];
-
-	va_start(ap, fmt);
-	while (*fmt) {
-		char c = *(fmt++);
-		switch (c) {
-		case 'd':	/* int */
-			in_objs[params.count].integer.value = va_arg(ap, int);
-			in_objs[params.count++].type = ACPI_TYPE_INTEGER;
-			break;
-			/* add more types as needed */
-		default:
-			printk(IBM_ERR "acpi_evalf() called "
-			       "with invalid format character '%c'\n", c);
-			return 0;
-		}
-	}
-	va_end(ap);
-
-	if (res_type != 'v') {
-		result.length = sizeof(out_obj);
-		result.pointer = &out_obj;
-		resultp = &result;
-	} else
-		resultp = NULL;
-
-	status = acpi_evaluate_object(handle, method, &params, resultp);
-
-	switch (res_type) {
-	case 'd':		/* int */
-		if (res)
-			*(int *)res = out_obj.integer.value;
-		success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
-		break;
-	case 'v':		/* void */
-		success = status == AE_OK;
-		break;
-		/* add more types as needed */
-	default:
-		printk(IBM_ERR "acpi_evalf() called "
-		       "with invalid format character '%c'\n", res_type);
-		return 0;
-	}
-
-	if (!success && !quiet)
-		printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
-		       method, fmt0, status);
-
-	return success;
-}
-
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
-	int i;
-
-	if (acpi_evalf(handle, &i, method, "d"))
-		printk(IBM_INFO "%s = 0x%x\n", method, i);
-	else
-		printk(IBM_ERR "error calling %s\n", method);
-}
-
-static char *next_cmd(char **cmds)
-{
-	char *start = *cmds;
-	char *end;
-
-	while ((end = strchr(start, ',')) && end == start)
-		start = end + 1;
-
-	if (!end)
-		return NULL;
-
-	*end = 0;
-	*cmds = end + 1;
-	return start;
-}
-
-static int ibm_acpi_driver_init(void)
-{
-	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
-	printk(IBM_INFO "%s\n", IBM_URL);
-
-	if (ibm_thinkpad_ec_found)
-		printk(IBM_INFO "ThinkPad EC firmware %s\n",
-		       ibm_thinkpad_ec_found);
-
-	return 0;
-}
-
-static int driver_read(char *p)
-{
-	int len = 0;
-
-	len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
-	len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
-
-	return len;
-}
-
-static int hotkey_supported;
-static int hotkey_mask_supported;
-static int hotkey_orig_status;
-static int hotkey_orig_mask;
-
-static int hotkey_get(int *status, int *mask)
-{
-	if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
-		return 0;
-
-	if (hotkey_mask_supported)
-		if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
-			return 0;
-
-	return 1;
-}
-
-static int hotkey_set(int status, int mask)
-{
-	int i;
-
-	if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
-		return 0;
-
-	if (hotkey_mask_supported)
-		for (i = 0; i < 32; i++) {
-			int bit = ((1 << i) & mask) != 0;
-			if (!acpi_evalf(hkey_handle,
-					NULL, "MHKM", "vdd", i + 1, bit))
-				return 0;
-		}
-
-	return 1;
-}
-
-static int hotkey_init(void)
-{
-	/* hotkey not supported on 570 */
-	hotkey_supported = hkey_handle != NULL;
-
-	if (hotkey_supported) {
-		/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-		   A30, R30, R31, T20-22, X20-21, X22-24 */
-		hotkey_mask_supported =
-		    acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
-
-		if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
-			return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int hotkey_read(char *p)
-{
-	int status, mask;
-	int len = 0;
-
-	if (!hotkey_supported) {
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-		return len;
-	}
-
-	if (!hotkey_get(&status, &mask))
-		return -EIO;
-
-	len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
-	if (hotkey_mask_supported) {
-		len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
-		len += sprintf(p + len,
-			       "commands:\tenable, disable, reset, <mask>\n");
-	} else {
-		len += sprintf(p + len, "mask:\t\tnot supported\n");
-		len += sprintf(p + len, "commands:\tenable, disable, reset\n");
-	}
-
-	return len;
-}
-
-static int hotkey_write(char *buf)
-{
-	int status, mask;
-	char *cmd;
-	int do_cmd = 0;
-
-	if (!hotkey_supported)
-		return -ENODEV;
-
-	if (!hotkey_get(&status, &mask))
-		return -EIO;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "enable") == 0) {
-			status = 1;
-		} else if (strlencmp(cmd, "disable") == 0) {
-			status = 0;
-		} else if (strlencmp(cmd, "reset") == 0) {
-			status = hotkey_orig_status;
-			mask = hotkey_orig_mask;
-		} else if (sscanf(cmd, "0x%x", &mask) == 1) {
-			/* mask set */
-		} else if (sscanf(cmd, "%x", &mask) == 1) {
-			/* mask set */
-		} else
-			return -EINVAL;
-		do_cmd = 1;
-	}
-
-	if (do_cmd && !hotkey_set(status, mask))
-		return -EIO;
-
-	return 0;
-}
-
-static void hotkey_exit(void)
-{
-	if (hotkey_supported)
-		hotkey_set(hotkey_orig_status, hotkey_orig_mask);
-}
-
-static void hotkey_notify(struct ibm_struct *ibm, u32 event)
-{
-	int hkey;
-
-	if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
-		acpi_bus_generate_event(ibm->device, event, hkey);
-	else {
-		printk(IBM_ERR "unknown hotkey event %d\n", event);
-		acpi_bus_generate_event(ibm->device, event, 0);
-	}
-}
-
-static int bluetooth_supported;
-
-static int bluetooth_init(void)
-{
-	/* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-	   G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
-	bluetooth_supported = hkey_handle &&
-	    acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
-
-	return 0;
-}
-
-static int bluetooth_status(void)
-{
-	int status;
-
-	if (!bluetooth_supported ||
-	    !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
-		status = 0;
-
-	return status;
-}
-
-static int bluetooth_read(char *p)
-{
-	int len = 0;
-	int status = bluetooth_status();
-
-	if (!bluetooth_supported)
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	else if (!(status & 1))
-		len += sprintf(p + len, "status:\t\tnot installed\n");
-	else {
-		len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
-		len += sprintf(p + len, "commands:\tenable, disable\n");
-	}
-
-	return len;
-}
-
-static int bluetooth_write(char *buf)
-{
-	int status = bluetooth_status();
-	char *cmd;
-	int do_cmd = 0;
-
-	if (!bluetooth_supported)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "enable") == 0) {
-			status |= 2;
-		} else if (strlencmp(cmd, "disable") == 0) {
-			status &= ~2;
-		} else
-			return -EINVAL;
-		do_cmd = 1;
-	}
-
-	if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
-		return -EIO;
-
-	return 0;
-}
-
-static int wan_supported;
-
-static int wan_init(void)
-{
-	wan_supported = hkey_handle &&
-	    acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
-
-	return 0;
-}
-
-static int wan_status(void)
-{
-	int status;
-
-	if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
-		status = 0;
-
-	return status;
-}
-
-static int wan_read(char *p)
-{
-	int len = 0;
-	int status = wan_status();
-
-	if (!wan_supported)
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	else if (!(status & 1))
-		len += sprintf(p + len, "status:\t\tnot installed\n");
-	else {
-		len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
-		len += sprintf(p + len, "commands:\tenable, disable\n");
-	}
-
-	return len;
-}
-
-static int wan_write(char *buf)
-{
-	int status = wan_status();
-	char *cmd;
-	int do_cmd = 0;
-
-	if (!wan_supported)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "enable") == 0) {
-			status |= 2;
-		} else if (strlencmp(cmd, "disable") == 0) {
-			status &= ~2;
-		} else
-			return -EINVAL;
-		do_cmd = 1;
-	}
-
-	if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
-		return -EIO;
-
-	return 0;
-}
-
-enum video_access_mode {
-	IBMACPI_VIDEO_NONE = 0,
-	IBMACPI_VIDEO_570,	/* 570 */
-	IBMACPI_VIDEO_770,	/* 600e/x, 770e, 770x */
-	IBMACPI_VIDEO_NEW,	/* all others */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-
-static int video_init(void)
-{
-	int ivga;
-
-	if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
-		/* G41, assume IVGA doesn't change */
-		vid_handle = vid2_handle;
-
-	if (!vid_handle)
-		/* video switching not supported on R30, R31 */
-		video_supported = IBMACPI_VIDEO_NONE;
-	else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
-		/* 570 */
-		video_supported = IBMACPI_VIDEO_570;
-	else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
-		/* 600e/x, 770e, 770x */
-		video_supported = IBMACPI_VIDEO_770;
-	else
-		/* all others */
-		video_supported = IBMACPI_VIDEO_NEW;
-
-	return 0;
-}
-
-static int video_status(void)
-{
-	int status = 0;
-	int i;
-
-	if (video_supported == IBMACPI_VIDEO_570) {
-		if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
-			status = i & 3;
-	} else if (video_supported == IBMACPI_VIDEO_770) {
-		if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
-			status |= 0x01 * i;
-		if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
-			status |= 0x02 * i;
-	} else if (video_supported == IBMACPI_VIDEO_NEW) {
-		acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
-		if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
-			status |= 0x02 * i;
-
-		acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
-		if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
-			status |= 0x01 * i;
-		if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
-			status |= 0x08 * i;
-	}
-
-	return status;
-}
-
-static int video_autosw(void)
-{
-	int autosw = 0;
-
-	if (video_supported == IBMACPI_VIDEO_570)
-		acpi_evalf(vid_handle, &autosw, "SWIT", "d");
-	else if (video_supported == IBMACPI_VIDEO_770 ||
-		 video_supported == IBMACPI_VIDEO_NEW)
-		acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
-
-	return autosw & 1;
-}
-
-static int video_read(char *p)
-{
-	int status = video_status();
-	int autosw = video_autosw();
-	int len = 0;
-
-	if (!video_supported) {
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-		return len;
-	}
-
-	len += sprintf(p + len, "status:\t\tsupported\n");
-	len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
-	len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
-	if (video_supported == IBMACPI_VIDEO_NEW)
-		len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
-	len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
-	len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
-	len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
-	if (video_supported == IBMACPI_VIDEO_NEW)
-		len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
-	len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
-	len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
-
-	return len;
-}
-
-static int video_switch(void)
-{
-	int autosw = video_autosw();
-	int ret;
-
-	if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-		return -EIO;
-	ret = video_supported == IBMACPI_VIDEO_570 ?
-	    acpi_evalf(ec_handle, NULL, "_Q16", "v") :
-	    acpi_evalf(vid_handle, NULL, "VSWT", "v");
-	acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-
-	return ret;
-}
-
-static int video_expand(void)
-{
-	if (video_supported == IBMACPI_VIDEO_570)
-		return acpi_evalf(ec_handle, NULL, "_Q17", "v");
-	else if (video_supported == IBMACPI_VIDEO_770)
-		return acpi_evalf(vid_handle, NULL, "VEXP", "v");
-	else
-		return acpi_evalf(NULL, NULL, "\\VEXP", "v");
-}
-
-static int video_switch2(int status)
-{
-	int ret;
-
-	if (video_supported == IBMACPI_VIDEO_570) {
-		ret = acpi_evalf(NULL, NULL,
-				 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
-	} else if (video_supported == IBMACPI_VIDEO_770) {
-		int autosw = video_autosw();
-		if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-			return -EIO;
-
-		ret = acpi_evalf(vid_handle, NULL,
-				 "ASWT", "vdd", status * 0x100, 0);
-
-		acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-	} else {
-		ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
-		    acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
-	}
-
-	return ret;
-}
-
-static int video_write(char *buf)
-{
-	char *cmd;
-	int enable, disable, status;
-
-	if (!video_supported)
-		return -ENODEV;
-
-	enable = disable = 0;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "lcd_enable") == 0) {
-			enable |= 0x01;
-		} else if (strlencmp(cmd, "lcd_disable") == 0) {
-			disable |= 0x01;
-		} else if (strlencmp(cmd, "crt_enable") == 0) {
-			enable |= 0x02;
-		} else if (strlencmp(cmd, "crt_disable") == 0) {
-			disable |= 0x02;
-		} else if (video_supported == IBMACPI_VIDEO_NEW &&
-			   strlencmp(cmd, "dvi_enable") == 0) {
-			enable |= 0x08;
-		} else if (video_supported == IBMACPI_VIDEO_NEW &&
-			   strlencmp(cmd, "dvi_disable") == 0) {
-			disable |= 0x08;
-		} else if (strlencmp(cmd, "auto_enable") == 0) {
-			if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
-				return -EIO;
-		} else if (strlencmp(cmd, "auto_disable") == 0) {
-			if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
-				return -EIO;
-		} else if (strlencmp(cmd, "video_switch") == 0) {
-			if (!video_switch())
-				return -EIO;
-		} else if (strlencmp(cmd, "expand_toggle") == 0) {
-			if (!video_expand())
-				return -EIO;
-		} else
-			return -EINVAL;
-	}
-
-	if (enable || disable) {
-		status = (video_status() & 0x0f & ~disable) | enable;
-		if (!video_switch2(status))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static void video_exit(void)
-{
-	acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
-}
-
-static int light_supported;
-static int light_status_supported;
-
-static int light_init(void)
-{
-	/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
-	light_supported = (cmos_handle || lght_handle) && !ledb_handle;
-
-	if (light_supported)
-		/* light status not supported on
-		   570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
-		light_status_supported = acpi_evalf(ec_handle, NULL,
-						    "KBLT", "qv");
-
-	return 0;
-}
-
-static int light_read(char *p)
-{
-	int len = 0;
-	int status = 0;
-
-	if (!light_supported) {
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	} else if (!light_status_supported) {
-		len += sprintf(p + len, "status:\t\tunknown\n");
-		len += sprintf(p + len, "commands:\ton, off\n");
-	} else {
-		if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
-			return -EIO;
-		len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
-		len += sprintf(p + len, "commands:\ton, off\n");
-	}
-
-	return len;
-}
-
-static int light_write(char *buf)
-{
-	int cmos_cmd, lght_cmd;
-	char *cmd;
-	int success;
-
-	if (!light_supported)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "on") == 0) {
-			cmos_cmd = 0x0c;
-			lght_cmd = 1;
-		} else if (strlencmp(cmd, "off") == 0) {
-			cmos_cmd = 0x0d;
-			lght_cmd = 0;
-		} else
-			return -EINVAL;
-
-		success = cmos_handle ?
-		    acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
-		    acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
-		if (!success)
-			return -EIO;
-	}
-
-	return 0;
-}
-
-#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
-static int _sta(acpi_handle handle)
-{
-	int status;
-
-	if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
-		status = 0;
-
-	return status;
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_DOCK
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int dock_read(char *p)
-{
-	int len = 0;
-	int docked = dock_docked();
-
-	if (!dock_handle)
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	else if (!docked)
-		len += sprintf(p + len, "status:\t\tundocked\n");
-	else {
-		len += sprintf(p + len, "status:\t\tdocked\n");
-		len += sprintf(p + len, "commands:\tdock, undock\n");
-	}
-
-	return len;
-}
-
-static int dock_write(char *buf)
-{
-	char *cmd;
-
-	if (!dock_docked())
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (strlencmp(cmd, "undock") == 0) {
-			if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
-			    !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
-				return -EIO;
-		} else if (strlencmp(cmd, "dock") == 0) {
-			if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
-				return -EIO;
-		} else
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
-	int docked = dock_docked();
-	int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
-
-	if (event == 1 && !pci)	/* 570 */
-		acpi_bus_generate_event(ibm->device, event, 1);	/* button */
-	else if (event == 1 && pci)	/* 570 */
-		acpi_bus_generate_event(ibm->device, event, 3);	/* dock */
-	else if (event == 3 && docked)
-		acpi_bus_generate_event(ibm->device, event, 1);	/* button */
-	else if (event == 3 && !docked)
-		acpi_bus_generate_event(ibm->device, event, 2);	/* undock */
-	else if (event == 0 && docked)
-		acpi_bus_generate_event(ibm->device, event, 3);	/* dock */
-	else {
-		printk(IBM_ERR "unknown dock event %d, status %d\n",
-		       event, _sta(dock_handle));
-		acpi_bus_generate_event(ibm->device, event, 0);	/* unknown */
-	}
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_BAY
-static int bay_status_supported;
-static int bay_status2_supported;
-static int bay_eject_supported;
-static int bay_eject2_supported;
-
-static int bay_init(void)
-{
-	bay_status_supported = bay_handle &&
-	    acpi_evalf(bay_handle, NULL, "_STA", "qv");
-	bay_status2_supported = bay2_handle &&
-	    acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
-	bay_eject_supported = bay_handle && bay_ej_handle &&
-	    (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
-	bay_eject2_supported = bay2_handle && bay2_ej_handle &&
-	    (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
-	return 0;
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
-	int len = 0;
-	int occupied = bay_occupied(bay);
-	int occupied2 = bay_occupied(bay2);
-	int eject, eject2;
-
-	len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
-		       (occupied ? "occupied" : "unoccupied") :
-		       "not supported");
-	if (bay_status2_supported)
-		len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
-			       "occupied" : "unoccupied");
-
-	eject = bay_eject_supported && occupied;
-	eject2 = bay_eject2_supported && occupied2;
-
-	if (eject && eject2)
-		len += sprintf(p + len, "commands:\teject, eject2\n");
-	else if (eject)
-		len += sprintf(p + len, "commands:\teject\n");
-	else if (eject2)
-		len += sprintf(p + len, "commands:\teject2\n");
-
-	return len;
-}
-
-static int bay_write(char *buf)
-{
-	char *cmd;
-
-	if (!bay_eject_supported && !bay_eject2_supported)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
-			if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
-				return -EIO;
-		} else if (bay_eject2_supported &&
-			   strlencmp(cmd, "eject2") == 0) {
-			if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
-				return -EIO;
-		} else
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
-	acpi_bus_generate_event(ibm->device, event, 0);
-}
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-static int cmos_read(char *p)
-{
-	int len = 0;
-
-	/* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-	   R30, R31, T20-22, X20-21 */
-	if (!cmos_handle)
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	else {
-		len += sprintf(p + len, "status:\t\tsupported\n");
-		len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
-	}
-
-	return len;
-}
-
-static int cmos_eval(int cmos_cmd)
-{
-	if (cmos_handle)
-		return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
-	else
-		return 1;
-}
-
-static int cmos_write(char *buf)
-{
-	char *cmd;
-	int cmos_cmd;
-
-	if (!cmos_handle)
-		return -EINVAL;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
-		    cmos_cmd >= 0 && cmos_cmd <= 21) {
-			/* cmos_cmd set */
-		} else
-			return -EINVAL;
-
-		if (!cmos_eval(cmos_cmd))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-enum led_access_mode {
-	IBMACPI_LED_NONE = 0,
-	IBMACPI_LED_570,	/* 570 */
-	IBMACPI_LED_OLD,	/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-	IBMACPI_LED_NEW,	/* all others */
-};
-static enum led_access_mode led_supported;
-
-static int led_init(void)
-{
-	if (!led_handle)
-		/* led not supported on R30, R31 */
-		led_supported = IBMACPI_LED_NONE;
-	else if (strlencmp(led_path, "SLED") == 0)
-		/* 570 */
-		led_supported = IBMACPI_LED_570;
-	else if (strlencmp(led_path, "SYSL") == 0)
-		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-		led_supported = IBMACPI_LED_OLD;
-	else
-		/* all others */
-		led_supported = IBMACPI_LED_NEW;
-
-	return 0;
-}
-
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
-
-static int led_read(char *p)
-{
-	int len = 0;
-
-	if (!led_supported) {
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-		return len;
-	}
-	len += sprintf(p + len, "status:\t\tsupported\n");
-
-	if (led_supported == IBMACPI_LED_570) {
-		/* 570 */
-		int i, status;
-		for (i = 0; i < 8; i++) {
-			if (!acpi_evalf(ec_handle,
-					&status, "GLED", "dd", 1 << i))
-				return -EIO;
-			len += sprintf(p + len, "%d:\t\t%s\n",
-				       i, led_status(status));
-		}
-	}
-
-	len += sprintf(p + len, "commands:\t"
-		       "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
-
-	return len;
-}
-
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 };	/* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 };	/* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
-#define EC_HLCL 0x0c
-#define EC_HLBL 0x0d
-#define EC_HLMS 0x0e
-
-static int led_write(char *buf)
-{
-	char *cmd;
-	int led, ind, ret;
-
-	if (!led_supported)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
-			return -EINVAL;
-
-		if (strstr(cmd, "off")) {
-			ind = 0;
-		} else if (strstr(cmd, "on")) {
-			ind = 1;
-		} else if (strstr(cmd, "blink")) {
-			ind = 2;
-		} else
-			return -EINVAL;
-
-		if (led_supported == IBMACPI_LED_570) {
-			/* 570 */
-			led = 1 << led;
-			if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
-					led, led_sled_arg1[ind]))
-				return -EIO;
-		} else if (led_supported == IBMACPI_LED_OLD) {
-			/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
-			led = 1 << led;
-			ret = ec_write(EC_HLMS, led);
-			if (ret >= 0)
-				ret =
-				    ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
-			if (ret >= 0)
-				ret =
-				    ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
-			if (ret < 0)
-				return ret;
-		} else {
-			/* all others */
-			if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
-					led, led_led_arg1[ind]))
-				return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-static int beep_read(char *p)
-{
-	int len = 0;
-
-	if (!beep_handle)
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	else {
-		len += sprintf(p + len, "status:\t\tsupported\n");
-		len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
-	}
-
-	return len;
-}
-
-static int beep_write(char *buf)
-{
-	char *cmd;
-	int beep_cmd;
-
-	if (!beep_handle)
-		return -ENODEV;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
-		    beep_cmd >= 0 && beep_cmd <= 17) {
-			/* beep_cmd set */
-		} else
-			return -EINVAL;
-		if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static int acpi_ec_read(int i, u8 * p)
-{
-	int v;
-
-	if (ecrd_handle) {
-		if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
-			return 0;
-		*p = v;
-	} else {
-		if (ec_read(i, p) < 0)
-			return 0;
-	}
-
-	return 1;
-}
-
-static int acpi_ec_write(int i, u8 v)
-{
-	if (ecwr_handle) {
-		if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
-			return 0;
-	} else {
-		if (ec_write(i, v) < 0)
-			return 0;
-	}
-
-	return 1;
-}
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(void)
-{
-	u8 t, ta1, ta2;
-	int i;
-	int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
-
-	if (ibm_thinkpad_ec_found && experimental) {
-		/*
-		 * Direct EC access mode: sensors at registers
-		 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
-		 * non-implemented, thermal sensors return 0x80 when
-		 * not available
-		 */
-
-		ta1 = ta2 = 0;
-		for (i = 0; i < 8; i++) {
-			if (likely(acpi_ec_read(0x78 + i, &t))) {
-				ta1 |= t;
-			} else {
-				ta1 = 0;
-				break;
-			}
-			if (likely(acpi_ec_read(0xC0 + i, &t))) {
-				ta2 |= t;
-			} else {
-				ta1 = 0;
-				break;
-			}
-		}
-		if (ta1 == 0) {
-			/* This is sheer paranoia, but we handle it anyway */
-			if (acpi_tmp7) {
-				printk(IBM_ERR
-				       "ThinkPad ACPI EC access misbehaving, "
-				       "falling back to ACPI TMPx access mode\n");
-				thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
-			} else {
-				printk(IBM_ERR
-				       "ThinkPad ACPI EC access misbehaving, "
-				       "disabling thermal sensors access\n");
-				thermal_read_mode = IBMACPI_THERMAL_NONE;
-			}
-		} else {
-			thermal_read_mode =
-			    (ta2 != 0) ?
-			    IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
-		}
-	} else if (acpi_tmp7) {
-		if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
-			/* 600e/x, 770e, 770x */
-			thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
-		} else {
-			/* Standard ACPI TMPx access, max 8 sensors */
-			thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
-		}
-	} else {
-		/* temperatures not supported on 570, G4x, R30, R31, R32 */
-		thermal_read_mode = IBMACPI_THERMAL_NONE;
-	}
-
-	return 0;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
-	int i, t;
-	s8 tmp;
-	char tmpi[] = "TMPi";
-
-	if (!s)
-		return -EINVAL;
-
-	switch (thermal_read_mode) {
-#if IBMACPI_MAX_THERMAL_SENSORS >= 16
-	case IBMACPI_THERMAL_TPEC_16:
-		for (i = 0; i < 8; i++) {
-			if (!acpi_ec_read(0xC0 + i, &tmp))
-				return -EIO;
-			s->temp[i + 8] = tmp * 1000;
-		}
-		/* fallthrough */
-#endif
-	case IBMACPI_THERMAL_TPEC_8:
-		for (i = 0; i < 8; i++) {
-			if (!acpi_ec_read(0x78 + i, &tmp))
-				return -EIO;
-			s->temp[i] = tmp * 1000;
-		}
-		return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
-
-	case IBMACPI_THERMAL_ACPI_UPDT:
-		if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
-			return -EIO;
-		for (i = 0; i < 8; i++) {
-			tmpi[3] = '0' + i;
-			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-				return -EIO;
-			s->temp[i] = (t - 2732) * 100;
-		}
-		return 8;
-
-	case IBMACPI_THERMAL_ACPI_TMP07:
-		for (i = 0; i < 8; i++) {
-			tmpi[3] = '0' + i;
-			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-				return -EIO;
-			s->temp[i] = t * 1000;
-		}
-		return 8;
-
-	case IBMACPI_THERMAL_NONE:
-	default:
-		return 0;
-	}
-}
-
-static int thermal_read(char *p)
-{
-	int len = 0;
-	int n, i;
-	struct ibm_thermal_sensors_struct t;
-
-	n = thermal_get_sensors(&t);
-	if (unlikely(n < 0))
-		return n;
-
-	len += sprintf(p + len, "temperatures:\t");
-
-	if (n > 0) {
-		for (i = 0; i < (n - 1); i++)
-			len += sprintf(p + len, "%d ", t.temp[i] / 1000);
-		len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
-	} else
-		len += sprintf(p + len, "not supported\n");
-
-	return len;
-}
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(char *p)
-{
-	int len = 0;
-	int i, j;
-	u8 v;
-
-	len += sprintf(p + len, "EC      "
-		       " +00 +01 +02 +03 +04 +05 +06 +07"
-		       " +08 +09 +0a +0b +0c +0d +0e +0f\n");
-	for (i = 0; i < 256; i += 16) {
-		len += sprintf(p + len, "EC 0x%02x:", i);
-		for (j = 0; j < 16; j++) {
-			if (!acpi_ec_read(i + j, &v))
-				break;
-			if (v != ecdump_regs[i + j])
-				len += sprintf(p + len, " *%02x", v);
-			else
-				len += sprintf(p + len, "  %02x", v);
-			ecdump_regs[i + j] = v;
-		}
-		len += sprintf(p + len, "\n");
-		if (j != 16)
-			break;
-	}
-
-	/* These are way too dangerous to advertise openly... */
-#if 0
-	len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
-		       " (<offset> is 00-ff, <value> is 00-ff)\n");
-	len += sprintf(p + len, "commands:\t0x<offset> <value>  "
-		       " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
-	return len;
-}
-
-static int ecdump_write(char *buf)
-{
-	char *cmd;
-	int i, v;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
-			/* i and v set */
-		} else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
-			/* i and v set */
-		} else
-			return -EINVAL;
-		if (i >= 0 && i < 256 && v >= 0 && v < 256) {
-			if (!acpi_ec_write(i, v))
-				return -EIO;
-		} else
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int brightness_offset = 0x31;
-
-static int brightness_get(struct backlight_device *bd)
-{
-	u8 level;
-	if (!acpi_ec_read(brightness_offset, &level))
-		return -EIO;
-
-	level &= 0x7;
-
-	return level;
-}
-
-static int brightness_read(char *p)
-{
-	int len = 0;
-	int level;
-
-	if ((level = brightness_get(NULL)) < 0) {
-		len += sprintf(p + len, "level:\t\tunreadable\n");
-	} else {
-		len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
-		len += sprintf(p + len, "commands:\tup, down\n");
-		len += sprintf(p + len, "commands:\tlevel <level>"
-			       " (<level> is 0-7)\n");
-	}
-
-	return len;
-}
-
-#define BRIGHTNESS_UP	4
-#define BRIGHTNESS_DOWN	5
-
-static int brightness_set(int value)
-{
-	int cmos_cmd, inc, i;
-	int current_value = brightness_get(NULL);
-
-	value &= 7;
-
-	cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
-	inc = value > current_value ? 1 : -1;
-	for (i = current_value; i != value; i += inc) {
-		if (!cmos_eval(cmos_cmd))
-			return -EIO;
-		if (!acpi_ec_write(brightness_offset, i + inc))
-			return -EIO;
-	}
-
-	return 0;
-}
-
-static int brightness_write(char *buf)
-{
-	int level;
-	int new_level;
-	char *cmd;
-
-	while ((cmd = next_cmd(&buf))) {
-		if ((level = brightness_get(NULL)) < 0)
-			return level;
-		level &= 7;
-
-		if (strlencmp(cmd, "up") == 0) {
-			new_level = level == 7 ? 7 : level + 1;
-		} else if (strlencmp(cmd, "down") == 0) {
-			new_level = level == 0 ? 0 : level - 1;
-		} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
-			   new_level >= 0 && new_level <= 7) {
-			/* new_level set */
-		} else
-			return -EINVAL;
-
-		brightness_set(new_level);
-	}
-
-	return 0;
-}
-
-static int brightness_update_status(struct backlight_device *bd)
-{
-	return brightness_set(
-		(bd->props.fb_blank == FB_BLANK_UNBLANK &&
-		 bd->props.power == FB_BLANK_UNBLANK) ?
-				bd->props.brightness : 0);
-}
-
-static struct backlight_ops ibm_backlight_data = {
-        .get_brightness = brightness_get,
-        .update_status  = brightness_update_status,
-};
-
-static int brightness_init(void)
-{
-	int b;
-
-	b = brightness_get(NULL);
-	if (b < 0)
-		return b;
-
-	ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
-							 &ibm_backlight_data);
-	if (IS_ERR(ibm_backlight_device)) {
-		printk(IBM_ERR "Could not register backlight device\n");
-		return PTR_ERR(ibm_backlight_device);
-	}
-
-	ibm_backlight_device->props.max_brightness = 7;
-	ibm_backlight_device->props.brightness = b;
-	backlight_update_status(ibm_backlight_device);
-
-	return 0;
-}
-
-static void brightness_exit(void)
-{
-	if (ibm_backlight_device) {
-		backlight_device_unregister(ibm_backlight_device);
-		ibm_backlight_device = NULL;
-	}
-}
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p)
-{
-	int len = 0;
-	u8 level;
-
-	if (!acpi_ec_read(volume_offset, &level)) {
-		len += sprintf(p + len, "level:\t\tunreadable\n");
-	} else {
-		len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
-		len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
-		len += sprintf(p + len, "commands:\tup, down, mute\n");
-		len += sprintf(p + len, "commands:\tlevel <level>"
-			       " (<level> is 0-15)\n");
-	}
-
-	return len;
-}
-
-#define VOLUME_DOWN	0
-#define VOLUME_UP	1
-#define VOLUME_MUTE	2
-
-static int volume_write(char *buf)
-{
-	int cmos_cmd, inc, i;
-	u8 level, mute;
-	int new_level, new_mute;
-	char *cmd;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (!acpi_ec_read(volume_offset, &level))
-			return -EIO;
-		new_mute = mute = level & 0x40;
-		new_level = level = level & 0xf;
-
-		if (strlencmp(cmd, "up") == 0) {
-			if (mute)
-				new_mute = 0;
-			else
-				new_level = level == 15 ? 15 : level + 1;
-		} else if (strlencmp(cmd, "down") == 0) {
-			if (mute)
-				new_mute = 0;
-			else
-				new_level = level == 0 ? 0 : level - 1;
-		} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
-			   new_level >= 0 && new_level <= 15) {
-			/* new_level set */
-		} else if (strlencmp(cmd, "mute") == 0) {
-			new_mute = 0x40;
-		} else
-			return -EINVAL;
-
-		if (new_level != level) {	/* mute doesn't change */
-			cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
-			inc = new_level > level ? 1 : -1;
-
-			if (mute && (!cmos_eval(cmos_cmd) ||
-				     !acpi_ec_write(volume_offset, level)))
-				return -EIO;
-
-			for (i = level; i != new_level; i += inc)
-				if (!cmos_eval(cmos_cmd) ||
-				    !acpi_ec_write(volume_offset, i + inc))
-					return -EIO;
-
-			if (mute && (!cmos_eval(VOLUME_MUTE) ||
-				     !acpi_ec_write(volume_offset,
-						    new_level + mute)))
-				return -EIO;
-		}
-
-		if (new_mute != mute) {	/* level doesn't change */
-			cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
-
-			if (!cmos_eval(cmos_cmd) ||
-			    !acpi_ec_write(volume_offset, level + new_mute))
-				return -EIO;
-		}
-	}
-
-	return 0;
-}
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-
-static int fan_control_status_known;
-static u8 fan_control_initial_status;
-
-static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
-static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
-
-static int fan_init(void)
-{
-	fan_status_access_mode = IBMACPI_FAN_NONE;
-	fan_control_access_mode = IBMACPI_FAN_WR_NONE;
-	fan_control_commands = 0;
-	fan_control_status_known = 1;
-	fan_watchdog_maxinterval = 0;
-
-	if (gfan_handle) {
-		/* 570, 600e/x, 770e, 770x */
-		fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
-	} else {
-		/* all other ThinkPads: note that even old-style
-		 * ThinkPad ECs supports the fan control register */
-		if (likely(acpi_ec_read(fan_status_offset,
-					&fan_control_initial_status))) {
-			fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
-
-			/* In some ThinkPads, neither the EC nor the ACPI
-			 * DSDT initialize the fan status, and it ends up
-			 * being set to 0x07 when it *could* be either
-			 * 0x07 or 0x80.
-			 *
-			 * Enable for TP-1Y (T43), TP-78 (R51e),
-			 * TP-76 (R52), TP-70 (T43, R52), which are known
-			 * to be buggy. */
-			if (fan_control_initial_status == 0x07 &&
-			    ibm_thinkpad_ec_found &&
-			    ((ibm_thinkpad_ec_found[0] == '1' &&
-			      ibm_thinkpad_ec_found[1] == 'Y') ||
-			     (ibm_thinkpad_ec_found[0] == '7' &&
-			      (ibm_thinkpad_ec_found[1] == '6' ||
-			       ibm_thinkpad_ec_found[1] == '8' ||
-			       ibm_thinkpad_ec_found[1] == '0'))
-			    )) {
-				printk(IBM_NOTICE
-				       "fan_init: initial fan status is "
-				       "unknown, assuming it is in auto "
-				       "mode\n");
-				fan_control_status_known = 0;
-			}
-		} else {
-			printk(IBM_ERR
-			       "ThinkPad ACPI EC access misbehaving, "
-			       "fan status and control unavailable\n");
-			return 0;
-		}
-	}
-
-	if (sfan_handle) {
-		/* 570, 770x-JL */
-		fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
-		fan_control_commands |=
-		    IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
-	} else {
-		if (!gfan_handle) {
-			/* gfan without sfan means no fan control */
-			/* all other models implement TP EC 0x2f control */
-
-			if (fans_handle) {
-				/* X31, X40, X41 */
-				fan_control_access_mode =
-				    IBMACPI_FAN_WR_ACPI_FANS;
-				fan_control_commands |=
-				    IBMACPI_FAN_CMD_SPEED |
-				    IBMACPI_FAN_CMD_LEVEL |
-				    IBMACPI_FAN_CMD_ENABLE;
-			} else {
-				fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
-				fan_control_commands |=
-				    IBMACPI_FAN_CMD_LEVEL |
-				    IBMACPI_FAN_CMD_ENABLE;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int fan_get_status(u8 *status)
-{
-	u8 s;
-
-	/* TODO:
-	 * Add IBMACPI_FAN_RD_ACPI_FANS ? */
-
-	switch (fan_status_access_mode) {
-	case IBMACPI_FAN_RD_ACPI_GFAN:
-		/* 570, 600e/x, 770e, 770x */
-
-		if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
-			return -EIO;
-
-		if (likely(status))
-			*status = s & 0x07;
-
-		break;
-
-	case IBMACPI_FAN_RD_TPEC:
-		/* all except 570, 600e/x, 770e, 770x */
-		if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
-			return -EIO;
-
-		if (likely(status))
-			*status = s;
-
-		break;
-
-	default:
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
-static int fan_get_speed(unsigned int *speed)
-{
-	u8 hi, lo;
-
-	switch (fan_status_access_mode) {
-	case IBMACPI_FAN_RD_TPEC:
-		/* all except 570, 600e/x, 770e, 770x */
-		if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
-			     !acpi_ec_read(fan_rpm_offset + 1, &hi)))
-			return -EIO;
-
-		if (likely(speed))
-			*speed = (hi << 8) | lo;
-
-		break;
-
-	default:
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
-static void fan_exit(void)
-{
-	cancel_delayed_work(&fan_watchdog_task);
-	flush_scheduled_work();
-}
-
-static void fan_watchdog_reset(void)
-{
-	static int fan_watchdog_active = 0;
-
-	if (fan_watchdog_active)
-		cancel_delayed_work(&fan_watchdog_task);
-
-	if (fan_watchdog_maxinterval > 0) {
-		fan_watchdog_active = 1;
-		if (!schedule_delayed_work(&fan_watchdog_task,
-				msecs_to_jiffies(fan_watchdog_maxinterval
-						 * 1000))) {
-			printk(IBM_ERR "failed to schedule the fan watchdog, "
-			       "watchdog will not trigger\n");
-		}
-	} else
-		fan_watchdog_active = 0;
-}
-
-static int fan_read(char *p)
-{
-	int len = 0;
-	int rc;
-	u8 status;
-	unsigned int speed = 0;
-
-	switch (fan_status_access_mode) {
-	case IBMACPI_FAN_RD_ACPI_GFAN:
-		/* 570, 600e/x, 770e, 770x */
-		if ((rc = fan_get_status(&status)) < 0)
-			return rc;
-
-		len += sprintf(p + len, "status:\t\t%s\n"
-			       "level:\t\t%d\n",
-			       (status != 0) ? "enabled" : "disabled", status);
-		break;
-
-	case IBMACPI_FAN_RD_TPEC:
-		/* all except 570, 600e/x, 770e, 770x */
-		if ((rc = fan_get_status(&status)) < 0)
-			return rc;
-
-		if (unlikely(!fan_control_status_known)) {
-			if (status != fan_control_initial_status)
-				fan_control_status_known = 1;
-			else
-				/* Return most likely status. In fact, it
-				 * might be the only possible status */
-				status = IBMACPI_FAN_EC_AUTO;
-		}
-
-		len += sprintf(p + len, "status:\t\t%s\n",
-			       (status != 0) ? "enabled" : "disabled");
-
-		/* No ThinkPad boots on disengaged mode, we can safely
-		 * assume the tachometer is online if fan control status
-		 * was unknown */
-		if ((rc = fan_get_speed(&speed)) < 0)
-			return rc;
-
-		len += sprintf(p + len, "speed:\t\t%d\n", speed);
-
-		if (status & IBMACPI_FAN_EC_DISENGAGED)
-			/* Disengaged mode takes precedence */
-			len += sprintf(p + len, "level:\t\tdisengaged\n");
-		else if (status & IBMACPI_FAN_EC_AUTO)
-			len += sprintf(p + len, "level:\t\tauto\n");
-		else
-			len += sprintf(p + len, "level:\t\t%d\n", status);
-		break;
-
-	case IBMACPI_FAN_NONE:
-	default:
-		len += sprintf(p + len, "status:\t\tnot supported\n");
-	}
-
-	if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
-		len += sprintf(p + len, "commands:\tlevel <level>");
-
-		switch (fan_control_access_mode) {
-		case IBMACPI_FAN_WR_ACPI_SFAN:
-			len += sprintf(p + len, " (<level> is 0-7)\n");
-			break;
-
-		default:
-			len += sprintf(p + len, " (<level> is 0-7, "
-				       "auto, disengaged)\n");
-			break;
-		}
-	}
-
-	if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
-		len += sprintf(p + len, "commands:\tenable, disable\n"
-			       "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
-			       "1-120 (seconds))\n");
-
-	if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
-		len += sprintf(p + len, "commands:\tspeed <speed>"
-			       " (<speed> is 0-65535)\n");
-
-	return len;
-}
-
-static int fan_set_level(int level)
-{
-	switch (fan_control_access_mode) {
-	case IBMACPI_FAN_WR_ACPI_SFAN:
-		if (level >= 0 && level <= 7) {
-			if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
-				return -EIO;
-		} else
-			return -EINVAL;
-		break;
-
-	case IBMACPI_FAN_WR_ACPI_FANS:
-	case IBMACPI_FAN_WR_TPEC:
-		if ((level != IBMACPI_FAN_EC_AUTO) &&
-		    (level != IBMACPI_FAN_EC_DISENGAGED) &&
-		    ((level < 0) || (level > 7)))
-			return -EINVAL;
-
-		if (!acpi_ec_write(fan_status_offset, level))
-			return -EIO;
-		else
-			fan_control_status_known = 1;
-		break;
-
-	default:
-		return -ENXIO;
-	}
-	return 0;
-}
-
-static int fan_set_enable(void)
-{
-	u8 s;
-	int rc;
-
-	switch (fan_control_access_mode) {
-	case IBMACPI_FAN_WR_ACPI_FANS:
-	case IBMACPI_FAN_WR_TPEC:
-		if ((rc = fan_get_status(&s)) < 0)
-			return rc;
-
-		/* Don't go out of emergency fan mode */
-		if (s != 7)
-			s = IBMACPI_FAN_EC_AUTO;
-
-		if (!acpi_ec_write(fan_status_offset, s))
-			return -EIO;
-		else
-			fan_control_status_known = 1;
-		break;
-
-	case IBMACPI_FAN_WR_ACPI_SFAN:
-		if ((rc = fan_get_status(&s)) < 0)
-			return rc;
-
-		s &= 0x07;
-
-		/* Set fan to at least level 4 */
-		if (s < 4)
-			s = 4;
-
-		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
-			return -EIO;
-		break;
-
-	default:
-		return -ENXIO;
-	}
-	return 0;
-}
-
-static int fan_set_disable(void)
-{
-	switch (fan_control_access_mode) {
-	case IBMACPI_FAN_WR_ACPI_FANS:
-	case IBMACPI_FAN_WR_TPEC:
-		if (!acpi_ec_write(fan_status_offset, 0x00))
-			return -EIO;
-		else
-			fan_control_status_known = 1;
-		break;
-
-	case IBMACPI_FAN_WR_ACPI_SFAN:
-		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
-			return -EIO;
-		break;
-
-	default:
-		return -ENXIO;
-	}
-	return 0;
-}
-
-static int fan_set_speed(int speed)
-{
-	switch (fan_control_access_mode) {
-	case IBMACPI_FAN_WR_ACPI_FANS:
-		if (speed >= 0 && speed <= 65535) {
-			if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
-					speed, speed, speed))
-				return -EIO;
-		} else
-			return -EINVAL;
-		break;
-
-	default:
-		return -ENXIO;
-	}
-	return 0;
-}
-
-static int fan_write_cmd_level(const char *cmd, int *rc)
-{
-	int level;
-
-	if (strlencmp(cmd, "level auto") == 0)
-		level = IBMACPI_FAN_EC_AUTO;
-	else if (strlencmp(cmd, "level disengaged") == 0)
-		level = IBMACPI_FAN_EC_DISENGAGED;
-	else if (sscanf(cmd, "level %d", &level) != 1)
-		return 0;
-
-	if ((*rc = fan_set_level(level)) == -ENXIO)
-		printk(IBM_ERR "level command accepted for unsupported "
-		       "access mode %d", fan_control_access_mode);
-
-	return 1;
-}
-
-static int fan_write_cmd_enable(const char *cmd, int *rc)
-{
-	if (strlencmp(cmd, "enable") != 0)
-		return 0;
-
-	if ((*rc = fan_set_enable()) == -ENXIO)
-		printk(IBM_ERR "enable command accepted for unsupported "
-		       "access mode %d", fan_control_access_mode);
-
-	return 1;
-}
-
-static int fan_write_cmd_disable(const char *cmd, int *rc)
-{
-	if (strlencmp(cmd, "disable") != 0)
-		return 0;
-
-	if ((*rc = fan_set_disable()) == -ENXIO)
-		printk(IBM_ERR "disable command accepted for unsupported "
-		       "access mode %d", fan_control_access_mode);
-
-	return 1;
-}
-
-static int fan_write_cmd_speed(const char *cmd, int *rc)
-{
-	int speed;
-
-	/* TODO:
-	 * Support speed <low> <medium> <high> ? */
-
-	if (sscanf(cmd, "speed %d", &speed) != 1)
-		return 0;
-
-	if ((*rc = fan_set_speed(speed)) == -ENXIO)
-		printk(IBM_ERR "speed command accepted for unsupported "
-		       "access mode %d", fan_control_access_mode);
-
-	return 1;
-}
-
-static int fan_write_cmd_watchdog(const char *cmd, int *rc)
-{
-	int interval;
-
-	if (sscanf(cmd, "watchdog %d", &interval) != 1)
-		return 0;
-
-	if (interval < 0 || interval > 120)
-		*rc = -EINVAL;
-	else
-		fan_watchdog_maxinterval = interval;
-
-	return 1;
-}
-
-static int fan_write(char *buf)
-{
-	char *cmd;
-	int rc = 0;
-
-	while (!rc && (cmd = next_cmd(&buf))) {
-		if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
-		      fan_write_cmd_level(cmd, &rc)) &&
-		    !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
-		      (fan_write_cmd_enable(cmd, &rc) ||
-		       fan_write_cmd_disable(cmd, &rc) ||
-		       fan_write_cmd_watchdog(cmd, &rc))) &&
-		    !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
-		      fan_write_cmd_speed(cmd, &rc))
-		    )
-			rc = -EINVAL;
-		else if (!rc)
-			fan_watchdog_reset();
-	}
-
-	return rc;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
-	printk(IBM_NOTICE "fan watchdog: enabling fan\n");
-	if (fan_set_enable()) {
-		printk(IBM_ERR "fan watchdog: error while enabling fan\n");
-		/* reschedule for later */
-		fan_watchdog_reset();
-	}
-}
-
-static struct ibm_struct ibms[] = {
-	{
-	 .name = "driver",
-	 .init = ibm_acpi_driver_init,
-	 .read = driver_read,
-	 },
-	{
-	 .name = "hotkey",
-	 .hid = IBM_HKEY_HID,
-	 .init = hotkey_init,
-	 .read = hotkey_read,
-	 .write = hotkey_write,
-	 .exit = hotkey_exit,
-	 .notify = hotkey_notify,
-	 .handle = &hkey_handle,
-	 .type = ACPI_DEVICE_NOTIFY,
-	 },
-	{
-	 .name = "bluetooth",
-	 .init = bluetooth_init,
-	 .read = bluetooth_read,
-	 .write = bluetooth_write,
-	 },
-	{
-	 .name = "wan",
-	 .init = wan_init,
-	 .read = wan_read,
-	 .write = wan_write,
-	 .experimental = 1,
-	 },
-	{
-	 .name = "video",
-	 .init = video_init,
-	 .read = video_read,
-	 .write = video_write,
-	 .exit = video_exit,
-	 },
-	{
-	 .name = "light",
-	 .init = light_init,
-	 .read = light_read,
-	 .write = light_write,
-	 },
-#ifdef CONFIG_ACPI_IBM_DOCK
-	{
-	 .name = "dock",
-	 .read = dock_read,
-	 .write = dock_write,
-	 .notify = dock_notify,
-	 .handle = &dock_handle,
-	 .type = ACPI_SYSTEM_NOTIFY,
-	 },
-	{
-	 .name = "dock",
-	 .hid = IBM_PCI_HID,
-	 .notify = dock_notify,
-	 .handle = &pci_handle,
-	 .type = ACPI_SYSTEM_NOTIFY,
-	 },
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-	{
-	 .name = "bay",
-	 .init = bay_init,
-	 .read = bay_read,
-	 .write = bay_write,
-	 .notify = bay_notify,
-	 .handle = &bay_handle,
-	 .type = ACPI_SYSTEM_NOTIFY,
-	 },
-#endif /* CONFIG_ACPI_IBM_BAY */
-	{
-	 .name = "cmos",
-	 .read = cmos_read,
-	 .write = cmos_write,
-	 },
-	{
-	 .name = "led",
-	 .init = led_init,
-	 .read = led_read,
-	 .write = led_write,
-	 },
-	{
-	 .name = "beep",
-	 .read = beep_read,
-	 .write = beep_write,
-	 },
-	{
-	 .name = "thermal",
-	 .init = thermal_init,
-	 .read = thermal_read,
-	 },
-	{
-	 .name = "ecdump",
-	 .read = ecdump_read,
-	 .write = ecdump_write,
-	 .experimental = 1,
-	 },
-	{
-	 .name = "brightness",
-	 .read = brightness_read,
-	 .write = brightness_write,
-	 .init = brightness_init,
-	 .exit = brightness_exit,
-	 },
-	{
-	 .name = "volume",
-	 .read = volume_read,
-	 .write = volume_write,
-	 },
-	{
-	 .name = "fan",
-	 .read = fan_read,
-	 .write = fan_write,
-	 .init = fan_init,
-	 .exit = fan_exit,
-	 .experimental = 1,
-	 },
-};
-
-static int dispatch_read(char *page, char **start, off_t off, int count,
-			 int *eof, void *data)
-{
-	struct ibm_struct *ibm = data;
-	int len;
-
-	if (!ibm || !ibm->read)
-		return -EINVAL;
-
-	len = ibm->read(page);
-	if (len < 0)
-		return len;
-
-	if (len <= off + count)
-		*eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-
-static int dispatch_write(struct file *file, const char __user * userbuf,
-			  unsigned long count, void *data)
-{
-	struct ibm_struct *ibm = data;
-	char *kernbuf;
-	int ret;
-
-	if (!ibm || !ibm->write)
-		return -EINVAL;
-
-	kernbuf = kmalloc(count + 2, GFP_KERNEL);
-	if (!kernbuf)
-		return -ENOMEM;
-
-	if (copy_from_user(kernbuf, userbuf, count)) {
-		kfree(kernbuf);
-		return -EFAULT;
-	}
-
-	kernbuf[count] = 0;
-	strcat(kernbuf, ",");
-	ret = ibm->write(kernbuf);
-	if (ret == 0)
-		ret = count;
-
-	kfree(kernbuf);
-
-	return ret;
-}
-
-static void dispatch_notify(acpi_handle handle, u32 event, void *data)
-{
-	struct ibm_struct *ibm = data;
-
-	if (!ibm || !ibm->notify)
-		return;
-
-	ibm->notify(ibm, event);
-}
-
-static int __init setup_notify(struct ibm_struct *ibm)
-{
-	acpi_status status;
-	int ret;
-
-	if (!*ibm->handle)
-		return 0;
-
-	ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
-	if (ret < 0) {
-		printk(IBM_ERR "%s device not present\n", ibm->name);
-		return -ENODEV;
-	}
-
-	acpi_driver_data(ibm->device) = ibm;
-	sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
-
-	status = acpi_install_notify_handler(*ibm->handle, ibm->type,
-					     dispatch_notify, ibm);
-	if (ACPI_FAILURE(status)) {
-		if (status == AE_ALREADY_EXISTS) {
-			printk(IBM_NOTICE "another device driver is already handling %s events\n",
-				ibm->name);
-		} else {
-			printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
-				ibm->name, status);
-		}
-		return -ENODEV;
-	}
-	ibm->notify_installed = 1;
-	return 0;
-}
-
-static int __init ibm_device_add(struct acpi_device *device)
-{
-	return 0;
-}
-
-static int __init register_driver(struct ibm_struct *ibm)
-{
-	int ret;
-
-	ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
-	if (!ibm->driver) {
-		printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
-		return -1;
-	}
-
-	sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
-	ibm->driver->ids = ibm->hid;
-	ibm->driver->ops.add = &ibm_device_add;
-
-	ret = acpi_bus_register_driver(ibm->driver);
-	if (ret < 0) {
-		printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
-		       ibm->hid, ret);
-		kfree(ibm->driver);
-	}
-
-	return ret;
-}
-
-static void ibm_exit(struct ibm_struct *ibm);
-
-static int __init ibm_init(struct ibm_struct *ibm)
-{
-	int ret;
-	struct proc_dir_entry *entry;
-
-	if (ibm->experimental && !experimental)
-		return 0;
-
-	if (ibm->hid) {
-		ret = register_driver(ibm);
-		if (ret < 0)
-			return ret;
-		ibm->driver_registered = 1;
-	}
-
-	if (ibm->init) {
-		ret = ibm->init();
-		if (ret != 0)
-			return ret;
-		ibm->init_called = 1;
-	}
-
-	if (ibm->read) {
-		entry = create_proc_entry(ibm->name,
-					  S_IFREG | S_IRUGO | S_IWUSR,
-					  proc_dir);
-		if (!entry) {
-			printk(IBM_ERR "unable to create proc entry %s\n",
-			       ibm->name);
-			return -ENODEV;
-		}
-		entry->owner = THIS_MODULE;
-		entry->data = ibm;
-		entry->read_proc = &dispatch_read;
-		if (ibm->write)
-			entry->write_proc = &dispatch_write;
-		ibm->proc_created = 1;
-	}
-
-	if (ibm->notify) {
-		ret = setup_notify(ibm);
-		if (ret == -ENODEV) {
-			printk(IBM_NOTICE "disabling subdriver %s\n",
-				ibm->name);
-			ibm_exit(ibm);
-			return 0;
-		}
-		if (ret < 0)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void ibm_exit(struct ibm_struct *ibm)
-{
-	if (ibm->notify_installed)
-		acpi_remove_notify_handler(*ibm->handle, ibm->type,
-					   dispatch_notify);
-
-	if (ibm->proc_created)
-		remove_proc_entry(ibm->name, proc_dir);
-
-	if (ibm->init_called && ibm->exit)
-		ibm->exit();
-
-	if (ibm->driver_registered) {
-		acpi_bus_unregister_driver(ibm->driver);
-		kfree(ibm->driver);
-	}
-}
-
-static void __init ibm_handle_init(char *name,
-				   acpi_handle * handle, acpi_handle parent,
-				   char **paths, int num_paths, char **path)
-{
-	int i;
-	acpi_status status;
-
-	for (i = 0; i < num_paths; i++) {
-		status = acpi_get_handle(parent, paths[i], handle);
-		if (ACPI_SUCCESS(status)) {
-			*path = paths[i];
-			return;
-		}
-	}
-
-	*handle = NULL;
-}
-
-#define IBM_HANDLE_INIT(object)						\
-	ibm_handle_init(#object, &object##_handle, *object##_parent,	\
-		object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-static int __init set_ibm_param(const char *val, struct kernel_param *kp)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(ibms); i++)
-		if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
-			if (strlen(val) > sizeof(ibms[i].param) - 2)
-				return -ENOSPC;
-			strcpy(ibms[i].param, val);
-			strcat(ibms[i].param, ",");
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
-#define IBM_PARAM(feature) \
-	module_param_call(feature, set_ibm_param, NULL, NULL, 0)
-
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_PARAM(dock);
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_PARAM(bay);
-#endif /* CONFIG_ACPI_IBM_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
-
-static void acpi_ibm_exit(void)
-{
-	int i;
-
-	for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
-		ibm_exit(&ibms[i]);
-
-	if (proc_dir)
-		remove_proc_entry(IBM_DIR, acpi_root_dir);
-
-	if (ibm_thinkpad_ec_found)
-		kfree(ibm_thinkpad_ec_found);
-}
-
-static char* __init check_dmi_for_ec(void)
-{
-	struct dmi_device *dev = NULL;
-	char ec_fw_string[18];
-
-	/*
-	 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
-	 * X32 or newer, all Z series;  Some models must have an
-	 * up-to-date BIOS or they will not be detected.
-	 *
-	 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
-	 */
-	while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
-		if (sscanf(dev->name,
-			   "IBM ThinkPad Embedded Controller -[%17c",
-			   ec_fw_string) == 1) {
-			ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
-			ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-			return kstrdup(ec_fw_string, GFP_KERNEL);
-		}
-	}
-	return NULL;
-}
-
-static int __init acpi_ibm_init(void)
-{
-	int ret, i;
-
-	if (acpi_disabled)
-		return -ENODEV;
-
-	/* ec is required because many other handles are relative to it */
-	IBM_HANDLE_INIT(ec);
-	if (!ec_handle) {
-		printk(IBM_ERR "ec object not found\n");
-		return -ENODEV;
-	}
-
-	/* Models with newer firmware report the EC in DMI */
-	ibm_thinkpad_ec_found = check_dmi_for_ec();
-
-	/* these handles are not required */
-	IBM_HANDLE_INIT(vid);
-	IBM_HANDLE_INIT(vid2);
-	IBM_HANDLE_INIT(ledb);
-	IBM_HANDLE_INIT(led);
-	IBM_HANDLE_INIT(hkey);
-	IBM_HANDLE_INIT(lght);
-	IBM_HANDLE_INIT(cmos);
-#ifdef CONFIG_ACPI_IBM_DOCK
-	IBM_HANDLE_INIT(dock);
-#endif
-	IBM_HANDLE_INIT(pci);
-#ifdef CONFIG_ACPI_IBM_BAY
-	IBM_HANDLE_INIT(bay);
-	if (bay_handle)
-		IBM_HANDLE_INIT(bay_ej);
-	IBM_HANDLE_INIT(bay2);
-	if (bay2_handle)
-		IBM_HANDLE_INIT(bay2_ej);
-#endif /* CONFIG_ACPI_IBM_BAY */
-	IBM_HANDLE_INIT(beep);
-	IBM_HANDLE_INIT(ecrd);
-	IBM_HANDLE_INIT(ecwr);
-	IBM_HANDLE_INIT(fans);
-	IBM_HANDLE_INIT(gfan);
-	IBM_HANDLE_INIT(sfan);
-
-	proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
-	if (!proc_dir) {
-		printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
-		acpi_ibm_exit();
-		return -ENODEV;
-	}
-	proc_dir->owner = THIS_MODULE;
-
-	for (i = 0; i < ARRAY_SIZE(ibms); i++) {
-		ret = ibm_init(&ibms[i]);
-		if (ret >= 0 && *ibms[i].param)
-			ret = ibms[i].write(ibms[i].param);
-		if (ret < 0) {
-			acpi_ibm_exit();
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-module_init(acpi_ibm_init);
-module_exit(acpi_ibm_exit);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 8fcd6a1..4dd0dab 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -228,7 +228,7 @@ int __init acpi_numa_init(void)
 	return 0;
 }
 
-int acpi_get_pxm(acpi_handle h)
+int __meminit acpi_get_pxm(acpi_handle h)
 {
 	unsigned long pxm;
 	acpi_status status;
@@ -246,7 +246,7 @@ int acpi_get_pxm(acpi_handle h)
 }
 EXPORT_SYMBOL(acpi_get_pxm);
 
-int acpi_get_node(acpi_handle *handle)
+int __meminit acpi_get_node(acpi_handle *handle)
 {
 	int pxm, node = -1;
 
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 971eca4..c2bed56 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -30,7 +30,6 @@ #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kmod.h>
 #include <linux/delay.h>
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 99d1516..f7de02a 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -70,8 +70,6 @@ #define ACPI_PROCESSOR_NOTIFY_POWER	0x81
 #define ACPI_PROCESSOR_LIMIT_USER	0
 #define ACPI_PROCESSOR_LIMIT_THERMAL	1
 
-#define ACPI_STA_PRESENT 0x00000001
-
 #define _COMPONENT		ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_core");
 
@@ -779,7 +777,7 @@ static int is_processor_present(acpi_han
 
 
 	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
 		return 0;
 	}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index cdf7894..ee5759b 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -51,14 +51,6 @@ #ifdef CONFIG_X86
 #include <asm/apic.h>
 #endif
 
-/*
- * Include the apic definitions for x86 to have the APIC timer related defines
- * available also for UP (on SMP it gets magically included via linux/smp.h).
- */
-#ifdef CONFIG_X86
-#include <asm/apic.h>
-#endif
-
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
@@ -483,7 +475,7 @@ #endif
 
 #ifdef CONFIG_GENERIC_TIME
 		/* TSC halts in C2, so notify users */
-		mark_tsc_unstable();
+		mark_tsc_unstable("possible TSC halt in C2");
 #endif
 		/* Re-enable interrupts */
 		local_irq_enable();
@@ -525,7 +517,7 @@ #endif
 
 #ifdef CONFIG_GENERIC_TIME
 		/* TSC halts in C3, so notify users */
-		mark_tsc_unstable();
+		mark_tsc_unstable("TSC halts in C3");
 #endif
 		/* Re-enable interrupts */
 		local_irq_enable();
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 2f2e796..c4efc0c 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -433,49 +433,6 @@ static int acpi_processor_perf_open_fs(s
 			   PDE(inode)->data);
 }
 
-static ssize_t
-acpi_processor_write_performance(struct file *file,
-				 const char __user * buffer,
-				 size_t count, loff_t * data)
-{
-	int result = 0;
-	struct seq_file *m = file->private_data;
-	struct acpi_processor *pr = m->private;
-	struct acpi_processor_performance *perf;
-	char state_string[12] = { '\0' };
-	unsigned int new_state = 0;
-	struct cpufreq_policy policy;
-
-
-	if (!pr || (count > sizeof(state_string) - 1))
-		return -EINVAL;
-
-	perf = pr->performance;
-	if (!perf)
-		return -EINVAL;
-
-	if (copy_from_user(state_string, buffer, count))
-		return -EFAULT;
-
-	state_string[count] = '\0';
-	new_state = simple_strtoul(state_string, NULL, 0);
-
-	if (new_state >= perf->state_count)
-		return -EINVAL;
-
-	cpufreq_get_policy(&policy, pr->id);
-
-	policy.cpu = pr->id;
-	policy.min = perf->states[new_state].core_frequency * 1000;
-	policy.max = perf->states[new_state].core_frequency * 1000;
-
-	result = cpufreq_set_policy(&policy);
-	if (result)
-		return result;
-
-	return count;
-}
-
 static void acpi_cpufreq_add_file(struct acpi_processor *pr)
 {
 	struct proc_dir_entry *entry = NULL;
@@ -487,10 +444,9 @@ static void acpi_cpufreq_add_file(struct
 
 	/* add file 'performance' [R/W] */
 	entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
-				  S_IFREG | S_IRUGO | S_IWUSR,
+				  S_IFREG | S_IRUGO,
 				  acpi_device_dir(device));
 	if (entry){
-		acpi_processor_perf_fops.write = acpi_processor_write_performance;
 		entry->proc_fops = &acpi_processor_perf_fops;
 		entry->data = acpi_driver_data(device);
 		entry->owner = THIS_MODULE;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 59640d9..c1bae10 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -30,30 +30,10 @@ #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include <linux/acpi.h>
-#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
 #include <linux/delay.h>
 
-#include "i2c_ec.h"
-
-#define	DEF_CAPACITY_UNIT	3
-#define	MAH_CAPACITY_UNIT	1
-#define	MWH_CAPACITY_UNIT	2
-#define	CAPACITY_UNIT		DEF_CAPACITY_UNIT
-
-#define	REQUEST_UPDATE_MODE	1
-#define	QUEUE_UPDATE_MODE	2
-
-#define	DATA_TYPE_COMMON	0
-#define	DATA_TYPE_INFO		1
-#define	DATA_TYPE_STATE		2
-#define	DATA_TYPE_ALARM		3
-#define	DATA_TYPE_AC_STATE	4
-
-extern struct proc_dir_entry *acpi_lock_ac_dir(void);
-extern struct proc_dir_entry *acpi_lock_battery_dir(void);
-extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
-extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-
 #define ACPI_SBS_COMPONENT		0x00080000
 #define ACPI_SBS_CLASS			"sbs"
 #define ACPI_AC_CLASS			"ac_adapter"
@@ -74,39 +54,75 @@ #define ACPI_SBS_BATTERY_NOTIFY_INFO	0x8
 
 #define _COMPONENT			ACPI_SBS_COMPONENT
 
-#define	MAX_SBS_BAT			4
-#define	MAX_SMBUS_ERR			1
-
 ACPI_MODULE_NAME("sbs");
 
 MODULE_AUTHOR("Rich Townsend");
 MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
 MODULE_LICENSE("GPL");
 
-static struct semaphore sbs_sem;
+#define	xmsleep(t)	msleep(t)
+
+#define ACPI_EC_SMB_PRTCL	0x00	/* protocol, PEC */
+
+#define ACPI_EC_SMB_STS		0x01	/* status */
+#define ACPI_EC_SMB_ADDR	0x02	/* address */
+#define ACPI_EC_SMB_CMD		0x03	/* command */
+#define ACPI_EC_SMB_DATA	0x04	/* 32 data registers */
+#define ACPI_EC_SMB_BCNT	0x24	/* number of data bytes */
 
-#define	UPDATE_MODE		QUEUE_UPDATE_MODE
-/* REQUEST_UPDATE_MODE  QUEUE_UPDATE_MODE */
-#define	UPDATE_INFO_MODE	0
-#define	UPDATE_TIME		60
-#define	UPDATE_TIME2		0
+#define ACPI_EC_SMB_STS_DONE	0x80
+#define ACPI_EC_SMB_STS_STATUS	0x1f
 
-static int capacity_mode = CAPACITY_UNIT;
-static int update_mode = UPDATE_MODE;
-static int update_info_mode = UPDATE_INFO_MODE;
-static int update_time = UPDATE_TIME;
-static int update_time2 = UPDATE_TIME2;
+#define ACPI_EC_SMB_PRTCL_WRITE		0x00
+#define ACPI_EC_SMB_PRTCL_READ		0x01
+#define ACPI_EC_SMB_PRTCL_WORD_DATA	0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA	0x0a
 
-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);
+#define ACPI_EC_SMB_TRANSACTION_SLEEP	1
+#define ACPI_EC_SMB_ACCESS_SLEEP1	1
+#define ACPI_EC_SMB_ACCESS_SLEEP2	10
+
+#define	DEF_CAPACITY_UNIT	3
+#define	MAH_CAPACITY_UNIT	1
+#define	MWH_CAPACITY_UNIT	2
+#define	CAPACITY_UNIT		DEF_CAPACITY_UNIT
+
+#define	REQUEST_UPDATE_MODE	1
+#define	QUEUE_UPDATE_MODE	2
+
+#define	DATA_TYPE_COMMON	0
+#define	DATA_TYPE_INFO		1
+#define	DATA_TYPE_STATE		2
+#define	DATA_TYPE_ALARM		3
+#define	DATA_TYPE_AC_STATE	4
+
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
+#define	MAX_SBS_BAT			4
+#define ACPI_SBS_BLOCK_MAX		32
+
+#define ACPI_SBS_SMBUS_READ		1
+#define ACPI_SBS_SMBUS_WRITE		2
+
+#define ACPI_SBS_WORD_DATA		1
+#define ACPI_SBS_BLOCK_DATA		2
+
+#define	UPDATE_DELAY	10
+
+/* 0 - every time, > 0 - by update_time */
+static unsigned int update_time = 120;
+
+static unsigned int capacity_mode = CAPACITY_UNIT;
+
+module_param(update_time, uint, 0644);
+module_param(capacity_mode, uint, 0444);
 
 static int acpi_sbs_add(struct acpi_device *device);
 static int acpi_sbs_remove(struct acpi_device *device, int type);
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
-static void acpi_sbs_update_queue(void *data);
+static int acpi_sbs_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_sbs_driver = {
 	.name = "sbs",
@@ -115,9 +131,14 @@ static struct acpi_driver acpi_sbs_drive
 	.ops = {
 		.add = acpi_sbs_add,
 		.remove = acpi_sbs_remove,
+		.resume = acpi_sbs_resume,
 		},
 };
 
+struct acpi_ac {
+	int ac_present;
+};
+
 struct acpi_battery_info {
 	int capacity_mode;
 	s16 full_charge_capacity;
@@ -126,18 +147,16 @@ struct acpi_battery_info {
 	int vscale;
 	int ipscale;
 	s16 serial_number;
-	char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
-	char device_name[I2C_SMBUS_BLOCK_MAX + 3];
-	char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+	char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
+	char device_name[ACPI_SBS_BLOCK_MAX + 3];
+	char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
 };
 
 struct acpi_battery_state {
 	s16 voltage;
 	s16 amperage;
 	s16 remaining_capacity;
-	s16 average_time_to_empty;
-	s16 average_time_to_full;
-	s16 battery_status;
+	s16 battery_state;
 };
 
 struct acpi_battery_alarm {
@@ -146,9 +165,9 @@ struct acpi_battery_alarm {
 
 struct acpi_battery {
 	int alive;
-	int battery_present;
 	int id;
 	int init_state;
+	int battery_present;
 	struct acpi_sbs *sbs;
 	struct acpi_battery_info info;
 	struct acpi_battery_state state;
@@ -158,186 +177,251 @@ struct acpi_battery {
 
 struct acpi_sbs {
 	acpi_handle handle;
+	int base;
 	struct acpi_device *device;
 	struct acpi_ec_smbus *smbus;
+	struct mutex mutex;
 	int sbsm_present;
 	int sbsm_batteries_supported;
-	int ac_present;
 	struct proc_dir_entry *ac_entry;
+	struct acpi_ac ac;
 	struct acpi_battery battery[MAX_SBS_BAT];
-	int update_info_mode;
 	int zombie;
-	int update_time;
-	int update_time2;
 	struct timer_list update_timer;
+	int run_cnt;
+	int update_proc_flg;
 };
 
-static void acpi_update_delay(struct acpi_sbs *sbs);
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type);
+static void acpi_sbs_update_time(void *data);
+
+union sbs_rw_data {
+	u16 word;
+	u8 block[ACPI_SBS_BLOCK_MAX + 2];
+};
+
+static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+			      char read_write, u8 command, int size,
+			      union sbs_rw_data *data);
 
 /* --------------------------------------------------------------------------
                                SMBus Communication
    -------------------------------------------------------------------------- */
 
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
+static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
 {
-	union i2c_smbus_data data;
-	int result = 0;
-	char *err_str;
-	int err_number;
+	u8 val;
+	int err;
 
-	data.word = 0;
+	err = ec_read(sbs->base + address, &val);
+	if (!err) {
+		*data = val;
+	}
+	xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+	return (err);
+}
 
-	result = smbus->adapter.algo->
-	    smbus_xfer(&smbus->adapter,
-		       ACPI_SB_SMBUS_ADDR,
-		       0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
+static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
+{
+	int err;
 
-	err_number = (data.word & 0x000f);
+	err = ec_write(sbs->base + address, data);
+	return (err);
+}
 
-	switch (data.word & 0x000f) {
-	case 0x0000:
-		err_str = "unexpected bus error";
-		break;
-	case 0x0001:
-		err_str = "busy";
-		break;
-	case 0x0002:
-		err_str = "reserved command";
-		break;
-	case 0x0003:
-		err_str = "unsupported command";
-		break;
-	case 0x0004:
-		err_str = "access denied";
+static int
+acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+		   char read_write, u8 command, int size,
+		   union sbs_rw_data *data)
+{
+	unsigned char protocol, len = 0, temp[2] = { 0, 0 };
+	int i;
+
+	if (read_write == ACPI_SBS_SMBUS_READ) {
+		protocol = ACPI_EC_SMB_PRTCL_READ;
+	} else {
+		protocol = ACPI_EC_SMB_PRTCL_WRITE;
+	}
+
+	switch (size) {
+
+	case ACPI_SBS_WORD_DATA:
+		acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+		if (read_write == ACPI_SBS_SMBUS_WRITE) {
+			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
+			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
+					  data->word >> 8);
+		}
+		protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
 		break;
-	case 0x0005:
-		err_str = "overflow/underflow";
+	case ACPI_SBS_BLOCK_DATA:
+		acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+		if (read_write == ACPI_SBS_SMBUS_WRITE) {
+			len = min_t(u8, data->block[0], 32);
+			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
+			for (i = 0; i < len; i++)
+				acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
+						  data->block[i + 1]);
+		}
+		protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
 		break;
-	case 0x0006:
-		err_str = "bad size";
+	default:
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"unsupported transaction %d", size));
+		return (-1);
+	}
+
+	acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
+	acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);
+
+	acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+
+	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+		xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
+		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+	}
+	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+		xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
+		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+	}
+	if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+	    || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"transaction %d error", size));
+		return (-1);
+	}
+
+	if (read_write == ACPI_SBS_SMBUS_WRITE) {
+		return (0);
+	}
+
+	switch (size) {
+
+	case ACPI_SBS_WORD_DATA:
+		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
+		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
+		data->word = (temp[1] << 8) | temp[0];
 		break;
-	case 0x0007:
-		err_str = "unknown error";
+
+	case ACPI_SBS_BLOCK_DATA:
+		len = 0;
+		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
+		len = min_t(u8, len, 32);
+		for (i = 0; i < len; i++)
+			acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
+					 data->block + i + 1);
+		data->block[0] = len;
 		break;
 	default:
-		err_str = "unrecognized error";
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"unsupported transaction %d", size));
+		return (-1);
 	}
-	ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			  "%s: ret %i, err %i\n", err_str, result, err_number));
+
+	return (0);
 }
 
 static int
-acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
-			 u16 * word,
-			 void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
 {
-	union i2c_smbus_data data;
+	union sbs_rw_data data;
 	int result = 0;
-	int i;
 
-	if (err_handler == NULL) {
-		err_handler = acpi_battery_smbus_err_handler;
-	}
-
-	for (i = 0; i < MAX_SMBUS_ERR; i++) {
-		result =
-		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-						    I2C_SMBUS_READ, func,
-						    I2C_SMBUS_WORD_DATA, &data);
-		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
-					  i));
-			if (err_handler) {
-				err_handler(smbus);
-			}
-		} else {
-			*word = data.word;
-			break;
-		}
+	result = acpi_ec_sbs_access(sbs, addr,
+				    ACPI_SBS_SMBUS_READ, func,
+				    ACPI_SBS_WORD_DATA, &data);
+	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_ec_sbs_access() failed"));
+	} else {
+		*word = data.word;
 	}
 
 	return result;
 }
 
 static int
-acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
-			char *str,
-			void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
 {
-	union i2c_smbus_data data;
+	union sbs_rw_data data;
 	int result = 0;
-	int i;
-
-	if (err_handler == NULL) {
-		err_handler = acpi_battery_smbus_err_handler;
-	}
 
-	for (i = 0; i < MAX_SMBUS_ERR; i++) {
-		result =
-		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-						    I2C_SMBUS_READ, func,
-						    I2C_SMBUS_BLOCK_DATA,
-						    &data);
-		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
-					  i));
-			if (err_handler) {
-				err_handler(smbus);
-			}
-		} else {
-			strncpy(str, (const char *)data.block + 1,
-				data.block[0]);
-			str[data.block[0]] = 0;
-			break;
-		}
+	result = acpi_ec_sbs_access(sbs, addr,
+				    ACPI_SBS_SMBUS_READ, func,
+				    ACPI_SBS_BLOCK_DATA, &data);
+	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_ec_sbs_access() failed"));
+	} else {
+		strncpy(str, (const char *)data.block + 1, data.block[0]);
+		str[data.block[0]] = 0;
 	}
 
 	return result;
 }
 
 static int
-acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
-			  int word,
-			  void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
 {
-	union i2c_smbus_data data;
+	union sbs_rw_data data;
 	int result = 0;
-	int i;
-
-	if (err_handler == NULL) {
-		err_handler = acpi_battery_smbus_err_handler;
-	}
 
 	data.word = word;
 
-	for (i = 0; i < MAX_SMBUS_ERR; i++) {
-		result =
-		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
-						    I2C_SMBUS_WRITE, func,
-						    I2C_SMBUS_WORD_DATA, &data);
-		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "try %i: smbus->adapter.algo"
-					  "->smbus_xfer() failed\n", i));
-			if (err_handler) {
-				err_handler(smbus);
-			}
-		} else {
-			break;
-		}
+	result = acpi_ec_sbs_access(sbs, addr,
+				    ACPI_SBS_SMBUS_WRITE, func,
+				    ACPI_SBS_WORD_DATA, &data);
+	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_ec_sbs_access() failed"));
 	}
 
 	return result;
 }
 
+static int sbs_zombie(struct acpi_sbs *sbs)
+{
+	return (sbs->zombie);
+}
+
+static int sbs_mutex_lock(struct acpi_sbs *sbs)
+{
+	if (sbs_zombie(sbs)) {
+		return -ENODEV;
+	}
+	mutex_lock(&sbs->mutex);
+	return 0;
+}
+
+static void sbs_mutex_unlock(struct acpi_sbs *sbs)
+{
+	mutex_unlock(&sbs->mutex);
+}
+
 /* --------------------------------------------------------------------------
                             Smart Battery System Management
    -------------------------------------------------------------------------- */
 
-/* Smart Battery */
+static int acpi_check_update_proc(struct acpi_sbs *sbs)
+{
+	acpi_status status = AE_OK;
+
+	if (update_time == 0) {
+		sbs->update_proc_flg = 0;
+		return 0;
+	}
+	if (sbs->update_proc_flg == 0) {
+		status = acpi_os_execute(OSL_GPE_HANDLER,
+					 acpi_sbs_update_time, sbs);
+		if (status != AE_OK) {
+			ACPI_EXCEPTION((AE_INFO, status,
+					"acpi_os_execute() failed"));
+			return 1;
+		}
+		sbs->update_proc_flg = 1;
+	}
+	return 0;
+}
 
 static int acpi_sbs_generate_event(struct acpi_device *device,
 				   int event, int state, char *bid, char *class)
@@ -366,12 +450,11 @@ static int acpi_battery_get_present(stru
 	int result = 0;
 	int is_present = 0;
 
-	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-					  ACPI_SBSM_SMBUS_ADDR, 0x01,
-					  &state, NULL);
+	result = acpi_sbs_read_word(battery->sbs,
+				    ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 	}
 	if (!result) {
 		is_present = (state & 0x000f) & (1 << battery->id);
@@ -381,45 +464,33 @@ static int acpi_battery_get_present(stru
 	return result;
 }
 
-static int acpi_battery_is_present(struct acpi_battery *battery)
-{
-	return (battery->battery_present);
-}
-
-static int acpi_ac_is_present(struct acpi_sbs *sbs)
-{
-	return (sbs->ac_present);
-}
-
 static int acpi_battery_select(struct acpi_battery *battery)
 {
-	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	s16 state;
 	int foo;
 
-	if (battery->sbs->sbsm_present) {
+	if (sbs->sbsm_present) {
 
 		/* Take special care not to knobble other nibbles of
 		 * state (aka selector_state), since
 		 * it causes charging to halt on SBSELs */
 
 		result =
-		    acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
-					     &state, NULL);
+		    acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_smbus_read_word() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_read_word() failed"));
 			goto end;
 		}
 
 		foo = (state & 0x0fff) | (1 << (battery->id + 12));
 		result =
-		    acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
-					      foo, NULL);
+		    acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_smbus_write_word() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_write_word() failed"));
 			goto end;
 		}
 	}
@@ -430,15 +501,14 @@ static int acpi_battery_select(struct ac
 
 static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
 {
-	struct acpi_ec_smbus *smbus = sbs->smbus;
 	int result = 0;
 	s16 battery_system_info;
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
-					  &battery_system_info, NULL);
+	result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
+				    &battery_system_info);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
@@ -451,53 +521,50 @@ static int acpi_sbsm_get_info(struct acp
 
 static int acpi_battery_get_info(struct acpi_battery *battery)
 {
-	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	s16 battery_mode;
 	s16 specification_info;
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
-					  &battery_mode,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+				    &battery_mode);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 	battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
-					  &battery->info.full_charge_capacity,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
+				    &battery->info.full_charge_capacity);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
-					  &battery->info.design_capacity,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
+				    &battery->info.design_capacity);
 
 	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
-					  &battery->info.design_voltage,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
+				    &battery->info.design_voltage);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
-					  &specification_info,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
+				    &specification_info);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
@@ -529,37 +596,35 @@ static int acpi_battery_get_info(struct 
 		battery->info.ipscale = 1;
 	}
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
-					  &battery->info.serial_number,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
+				    &battery->info.serial_number);
 	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
-					 battery->info.manufacturer_name,
-					 &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
+				   battery->info.manufacturer_name);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_str() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_str() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
-					 battery->info.device_name,
-					 &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
+				   battery->info.device_name);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_str() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_str() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
-					 battery->info.device_chemistry,
-					 &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
+				   battery->info.device_chemistry);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_str() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_str() failed"));
 		goto end;
 	}
 
@@ -567,103 +632,60 @@ static int acpi_battery_get_info(struct 
 	return result;
 }
 
-static void acpi_update_delay(struct acpi_sbs *sbs)
-{
-	if (sbs->zombie) {
-		return;
-	}
-	if (sbs->update_time2 > 0) {
-		msleep(sbs->update_time2 * 1000);
-	}
-}
-
 static int acpi_battery_get_state(struct acpi_battery *battery)
 {
-	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
-					  &battery->state.voltage,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
+				    &battery->state.voltage);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
-					  &battery->state.amperage,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
+				    &battery->state.amperage);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
-					  &battery->state.remaining_capacity,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
+				    &battery->state.remaining_capacity);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
-					  &battery->state.average_time_to_empty,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
+				    &battery->state.battery_state);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
-					  &battery->state.average_time_to_full,
-					  &acpi_battery_smbus_err_handler);
-	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
-		goto end;
-	}
-
-	acpi_update_delay(battery->sbs);
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
-					  &battery->state.battery_status,
-					  &acpi_battery_smbus_err_handler);
-	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
-		goto end;
-	}
-
-	acpi_update_delay(battery->sbs);
-
       end:
 	return result;
 }
 
 static int acpi_battery_get_alarm(struct acpi_battery *battery)
 {
-	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-					  &battery->alarm.remaining_capacity,
-					  &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+				    &battery->alarm.remaining_capacity);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	acpi_update_delay(battery->sbs);
-
       end:
 
 	return result;
@@ -672,15 +694,15 @@ static int acpi_battery_get_alarm(struct
 static int acpi_battery_set_alarm(struct acpi_battery *battery,
 				  unsigned long alarm)
 {
-	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	s16 battery_mode;
 	int foo;
 
 	result = acpi_battery_select(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_select() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_select() failed"));
 		goto end;
 	}
 
@@ -688,33 +710,29 @@ static int acpi_battery_set_alarm(struct
 
 	if (alarm > 0) {
 		result =
-		    acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
-					     &battery_mode,
-					     &acpi_battery_smbus_err_handler);
+		    acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+				       &battery_mode);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_smbus_read_word() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_read_word() failed"));
 			goto end;
 		}
 
 		result =
-		    acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-					      battery_mode & 0xbfff,
-					      &acpi_battery_smbus_err_handler);
+		    acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+					battery_mode & 0xbfff);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_smbus_write_word() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_write_word() failed"));
 			goto end;
 		}
 	}
 
 	foo = alarm / (battery->info.capacity_mode ? 10 : 1);
-	result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
-					   foo,
-					   &acpi_battery_smbus_err_handler);
+	result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_write_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_write_word() failed"));
 		goto end;
 	}
 
@@ -725,6 +743,7 @@ static int acpi_battery_set_alarm(struct
 
 static int acpi_battery_set_mode(struct acpi_battery *battery)
 {
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	s16 battery_mode;
 
@@ -732,12 +751,11 @@ static int acpi_battery_set_mode(struct 
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-					  ACPI_SB_SMBUS_ADDR, 0x03,
-					  &battery_mode, NULL);
+	result = acpi_sbs_read_word(sbs,
+				    ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
@@ -746,21 +764,19 @@ static int acpi_battery_set_mode(struct 
 	} else {
 		battery_mode |= 0x8000;
 	}
-	result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
-					   ACPI_SB_SMBUS_ADDR, 0x03,
-					   battery_mode, NULL);
+	result = acpi_sbs_write_word(sbs,
+				     ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_write_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_write_word() failed"));
 		goto end;
 	}
 
-	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
-					  ACPI_SB_SMBUS_ADDR, 0x03,
-					  &battery_mode, NULL);
+	result = acpi_sbs_read_word(sbs,
+				    ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
@@ -774,36 +790,36 @@ static int acpi_battery_init(struct acpi
 
 	result = acpi_battery_select(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_init() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_select() failed"));
 		goto end;
 	}
 
 	result = acpi_battery_set_mode(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_set_mode() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_set_mode() failed"));
 		goto end;
 	}
 
 	result = acpi_battery_get_info(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_get_info() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_get_info() failed"));
 		goto end;
 	}
 
 	result = acpi_battery_get_state(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_get_state() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_get_state() failed"));
 		goto end;
 	}
 
 	result = acpi_battery_get_alarm(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_get_alarm() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_get_alarm() failed"));
 		goto end;
 	}
 
@@ -813,20 +829,19 @@ static int acpi_battery_init(struct acpi
 
 static int acpi_ac_get_present(struct acpi_sbs *sbs)
 {
-	struct acpi_ec_smbus *smbus = sbs->smbus;
 	int result = 0;
 	s16 charger_status;
 
-	result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
-					  &charger_status, NULL);
+	result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
+				    &charger_status);
 
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_smbus_read_word() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
 
-	sbs->ac_present = (charger_status & 0x8000) >> 15;
+	sbs->ac.ac_present = (charger_status & 0x8000) >> 15;
 
       end:
 
@@ -852,8 +867,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_
 	if (!*dir) {
 		*dir = proc_mkdir(dir_name, parent_dir);
 		if (!*dir) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "proc_mkdir() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"proc_mkdir() failed"));
 			return -ENODEV;
 		}
 		(*dir)->owner = THIS_MODULE;
@@ -863,8 +878,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_
 	if (info_fops) {
 		entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
 		if (!entry) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "create_proc_entry() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"create_proc_entry() failed"));
 		} else {
 			entry->proc_fops = info_fops;
 			entry->data = data;
@@ -876,8 +891,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_
 	if (state_fops) {
 		entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
 		if (!entry) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "create_proc_entry() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"create_proc_entry() failed"));
 		} else {
 			entry->proc_fops = state_fops;
 			entry->data = data;
@@ -889,8 +904,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_
 	if (alarm_fops) {
 		entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
 		if (!entry) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "create_proc_entry() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"create_proc_entry() failed"));
 		} else {
 			entry->proc_fops = alarm_fops;
 			entry->data = data;
@@ -923,24 +938,27 @@ static struct proc_dir_entry *acpi_batte
 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 {
 	struct acpi_battery *battery = seq->private;
+	struct acpi_sbs *sbs = battery->sbs;
 	int cscale;
 	int result = 0;
 
-	if (battery->sbs->zombie) {
+	if (sbs_mutex_lock(sbs)) {
 		return -ENODEV;
 	}
 
-	down(&sbs_sem);
+	result = acpi_check_update_proc(sbs);
+	if (result)
+		goto end;
 
-	if (update_mode == REQUEST_UPDATE_MODE) {
-		result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
+	if (update_time == 0) {
+		result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_update_run() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_update_run() failed"));
 		}
 	}
 
-	if (acpi_battery_is_present(battery)) {
+	if (battery->battery_present) {
 		seq_printf(seq, "present:                 yes\n");
 	} else {
 		seq_printf(seq, "present:                 no\n");
@@ -952,13 +970,13 @@ static int acpi_battery_read_info(struct
 	} else {
 		cscale = battery->info.ipscale;
 	}
-	seq_printf(seq, "design capacity:         %i%s",
+	seq_printf(seq, "design capacity:         %i%s\n",
 		   battery->info.design_capacity * cscale,
-		   battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+		   battery->info.capacity_mode ? "0 mWh" : " mAh");
 
-	seq_printf(seq, "last full capacity:      %i%s",
+	seq_printf(seq, "last full capacity:      %i%s\n",
 		   battery->info.full_charge_capacity * cscale,
-		   battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+		   battery->info.capacity_mode ? "0 mWh" : " mAh");
 
 	seq_printf(seq, "battery technology:      rechargeable\n");
 
@@ -984,7 +1002,7 @@ static int acpi_battery_read_info(struct
 
       end:
 
-	up(&sbs_sem);
+	sbs_mutex_unlock(sbs);
 
 	return result;
 }
@@ -996,26 +1014,29 @@ static int acpi_battery_info_open_fs(str
 
 static int acpi_battery_read_state(struct seq_file *seq, void *offset)
 {
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	int cscale;
 	int foo;
 
-	if (battery->sbs->zombie) {
+	if (sbs_mutex_lock(sbs)) {
 		return -ENODEV;
 	}
 
-	down(&sbs_sem);
+	result = acpi_check_update_proc(sbs);
+	if (result)
+		goto end;
 
-	if (update_mode == REQUEST_UPDATE_MODE) {
-		result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
+	if (update_time == 0) {
+		result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_update_run() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_update_run() failed"));
 		}
 	}
 
-	if (acpi_battery_is_present(battery)) {
+	if (battery->battery_present) {
 		seq_printf(seq, "present:                 yes\n");
 	} else {
 		seq_printf(seq, "present:                 no\n");
@@ -1028,7 +1049,7 @@ static int acpi_battery_read_state(struc
 		cscale = battery->info.ipscale;
 	}
 
-	if (battery->state.battery_status & 0x0010) {
+	if (battery->state.battery_state & 0x0010) {
 		seq_printf(seq, "capacity state:          critical\n");
 	} else {
 		seq_printf(seq, "capacity state:          ok\n");
@@ -1052,16 +1073,16 @@ static int acpi_battery_read_state(struc
 			   battery->info.capacity_mode ? "mW" : "mA");
 	}
 
-	seq_printf(seq, "remaining capacity:      %i%s",
+	seq_printf(seq, "remaining capacity:      %i%s\n",
 		   battery->state.remaining_capacity * cscale,
-		   battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+		   battery->info.capacity_mode ? "0 mWh" : " mAh");
 
 	seq_printf(seq, "present voltage:         %i mV\n",
 		   battery->state.voltage * battery->info.vscale);
 
       end:
 
-	up(&sbs_sem);
+	sbs_mutex_unlock(sbs);
 
 	return result;
 }
@@ -1074,24 +1095,27 @@ static int acpi_battery_state_open_fs(st
 static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
 {
 	struct acpi_battery *battery = seq->private;
+	struct acpi_sbs *sbs = battery->sbs;
 	int result = 0;
 	int cscale;
 
-	if (battery->sbs->zombie) {
+	if (sbs_mutex_lock(sbs)) {
 		return -ENODEV;
 	}
 
-	down(&sbs_sem);
+	result = acpi_check_update_proc(sbs);
+	if (result)
+		goto end;
 
-	if (update_mode == REQUEST_UPDATE_MODE) {
-		result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
+	if (update_time == 0) {
+		result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_update_run() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_update_run() failed"));
 		}
 	}
 
-	if (!acpi_battery_is_present(battery)) {
+	if (!battery->battery_present) {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
@@ -1104,16 +1128,16 @@ static int acpi_battery_read_alarm(struc
 
 	seq_printf(seq, "alarm:                   ");
 	if (battery->alarm.remaining_capacity) {
-		seq_printf(seq, "%i%s",
+		seq_printf(seq, "%i%s\n",
 			   battery->alarm.remaining_capacity * cscale,
-			   battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+			   battery->info.capacity_mode ? "0 mWh" : " mAh");
 	} else {
 		seq_printf(seq, "disabled\n");
 	}
 
       end:
 
-	up(&sbs_sem);
+	sbs_mutex_unlock(sbs);
 
 	return result;
 }
@@ -1124,16 +1148,19 @@ acpi_battery_write_alarm(struct file *fi
 {
 	struct seq_file *seq = file->private_data;
 	struct acpi_battery *battery = seq->private;
+	struct acpi_sbs *sbs = battery->sbs;
 	char alarm_string[12] = { '\0' };
 	int result, old_alarm, new_alarm;
 
-	if (battery->sbs->zombie) {
+	if (sbs_mutex_lock(sbs)) {
 		return -ENODEV;
 	}
 
-	down(&sbs_sem);
+	result = acpi_check_update_proc(sbs);
+	if (result)
+		goto end;
 
-	if (!acpi_battery_is_present(battery)) {
+	if (!battery->battery_present) {
 		result = -ENODEV;
 		goto end;
 	}
@@ -1155,21 +1182,21 @@ acpi_battery_write_alarm(struct file *fi
 
 	result = acpi_battery_set_alarm(battery, new_alarm);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_set_alarm() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_set_alarm() failed"));
 		acpi_battery_set_alarm(battery, old_alarm);
 		goto end;
 	}
 	result = acpi_battery_get_alarm(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_get_alarm() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_get_alarm() failed"));
 		acpi_battery_set_alarm(battery, old_alarm);
 		goto end;
 	}
 
       end:
-	up(&sbs_sem);
+	sbs_mutex_unlock(sbs);
 
 	if (result) {
 		return result;
@@ -1217,24 +1244,22 @@ static int acpi_ac_read_state(struct seq
 	struct acpi_sbs *sbs = seq->private;
 	int result;
 
-	if (sbs->zombie) {
+	if (sbs_mutex_lock(sbs)) {
 		return -ENODEV;
 	}
 
-	down(&sbs_sem);
-
-	if (update_mode == REQUEST_UPDATE_MODE) {
-		result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
+	if (update_time == 0) {
+		result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_update_run() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_update_run() failed"));
 		}
 	}
 
 	seq_printf(seq, "state:                   %s\n",
-		   sbs->ac_present ? "on-line" : "off-line");
+		   sbs->ac.ac_present ? "on-line" : "off-line");
 
-	up(&sbs_sem);
+	sbs_mutex_unlock(sbs);
 
 	return 0;
 }
@@ -1275,25 +1300,25 @@ static int acpi_battery_add(struct acpi_
 
 	result = acpi_battery_select(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_select() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_select() failed"));
 		goto end;
 	}
 
 	result = acpi_battery_get_present(battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_battery_get_present() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_battery_get_present() failed"));
 		goto end;
 	}
 
-	is_present = acpi_battery_is_present(battery);
+	is_present = battery->battery_present;
 
 	if (is_present) {
 		result = acpi_battery_init(battery);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_battery_init() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_battery_init() failed"));
 			goto end;
 		}
 		battery->init_state = 1;
@@ -1308,12 +1333,16 @@ static int acpi_battery_add(struct acpi_
 					 &acpi_battery_state_fops,
 					 &acpi_battery_alarm_fops, battery);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_generic_add_fs() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_generic_add_fs() failed"));
 		goto end;
 	}
 	battery->alive = 1;
 
+	printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name,
+	       sbs->battery->battery_present ? "present" : "absent");
+
       end:
 	return result;
 }
@@ -1333,8 +1362,8 @@ static int acpi_ac_add(struct acpi_sbs *
 
 	result = acpi_ac_get_present(sbs);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_ac_get_present() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_ac_get_present() failed"));
 		goto end;
 	}
 
@@ -1343,11 +1372,15 @@ static int acpi_ac_add(struct acpi_sbs *
 					 ACPI_AC_DIR_NAME,
 					 NULL, &acpi_ac_state_fops, NULL, sbs);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_generic_add_fs() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_generic_add_fs() failed"));
 		goto end;
 	}
 
+	printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
+	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
+	       ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line");
+
       end:
 
 	return result;
@@ -1361,45 +1394,85 @@ static void acpi_ac_remove(struct acpi_s
 	}
 }
 
-static void acpi_sbs_update_queue_run(unsigned long data)
+static void acpi_sbs_update_time_run(unsigned long data)
 {
-	acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
+	acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data);
 }
 
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
 {
 	struct acpi_battery *battery;
-	int result = 0;
-	int old_ac_present;
-	int old_battery_present;
-	int new_ac_present;
-	int new_battery_present;
-	int id;
+	int result = 0, cnt;
+	int old_ac_present = -1;
+	int old_battery_present = -1;
+	int new_ac_present = -1;
+	int new_battery_present = -1;
+	int id_min = 0, id_max = MAX_SBS_BAT - 1;
 	char dir_name[32];
-	int do_battery_init, do_ac_init;
-	s16 old_remaining_capacity;
+	int do_battery_init = 0, do_ac_init = 0;
+	int old_remaining_capacity = 0;
+	int update_ac = 1, update_battery = 1;
+	int up_tm = update_time;
 
-	if (sbs->zombie) {
+	if (sbs_zombie(sbs)) {
 		goto end;
 	}
 
-	old_ac_present = acpi_ac_is_present(sbs);
+	if (id >= 0) {
+		id_min = id_max = id;
+	}
+
+	if (data_type == DATA_TYPE_COMMON && up_tm > 0) {
+		cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+		if (sbs->run_cnt % cnt != 0) {
+			update_battery = 0;
+		}
+	}
+
+	sbs->run_cnt++;
+
+	if (!update_ac && !update_battery) {
+		goto end;
+	}
+
+	old_ac_present = sbs->ac.ac_present;
 
 	result = acpi_ac_get_present(sbs);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_ac_get_present() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_ac_get_present() failed"));
 	}
 
-	new_ac_present = acpi_ac_is_present(sbs);
+	new_ac_present = sbs->ac.ac_present;
 
 	do_ac_init = (old_ac_present != new_ac_present);
+	if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) {
+		do_ac_init = 1;
+	}
 
-	if (data_type == DATA_TYPE_AC_STATE) {
+	if (do_ac_init) {
+		result = acpi_sbs_generate_event(sbs->device,
+						 ACPI_SBS_AC_NOTIFY_STATUS,
+						 new_ac_present,
+						 ACPI_AC_DIR_NAME,
+						 ACPI_AC_CLASS);
+		if (result) {
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_generate_event() failed"));
+		}
+	}
+
+	if (data_type == DATA_TYPE_COMMON) {
+		if (!do_ac_init && !update_battery) {
+			goto end;
+		}
+	}
+
+	if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) {
 		goto end;
 	}
 
-	for (id = 0; id < MAX_SBS_BAT; id++) {
+	for (id = id_min; id <= id_max; id++) {
 		battery = &sbs->battery[id];
 		if (battery->alive == 0) {
 			continue;
@@ -1407,94 +1480,92 @@ static int acpi_sbs_update_run(struct ac
 
 		old_remaining_capacity = battery->state.remaining_capacity;
 
-		old_battery_present = acpi_battery_is_present(battery);
+		old_battery_present = battery->battery_present;
 
 		result = acpi_battery_select(battery);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_battery_select() failed\n"));
-		}
-		if (sbs->zombie) {
-			goto end;
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_battery_select() failed"));
 		}
 
 		result = acpi_battery_get_present(battery);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_battery_get_present() failed\n"));
-		}
-		if (sbs->zombie) {
-			goto end;
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_battery_get_present() failed"));
 		}
 
-		new_battery_present = acpi_battery_is_present(battery);
+		new_battery_present = battery->battery_present;
 
 		do_battery_init = ((old_battery_present != new_battery_present)
 				   && new_battery_present);
-
-		if (sbs->zombie) {
+		if (!new_battery_present)
+			goto event;
+		if (do_ac_init || do_battery_init) {
+			result = acpi_battery_init(battery);
+			if (result) {
+				ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+						"acpi_battery_init() "
+						"failed"));
+			}
+		}
+		if (sbs_zombie(sbs)) {
 			goto end;
 		}
-		if (do_ac_init || do_battery_init ||
-		    update_info_mode || sbs->update_info_mode) {
-			if (sbs->update_info_mode) {
-				sbs->update_info_mode = 0;
-			} else {
-				sbs->update_info_mode = 1;
-			}
-			result = acpi_battery_init(battery);
+
+		if ((data_type == DATA_TYPE_COMMON
+		     || data_type == DATA_TYPE_INFO)
+		    && new_battery_present) {
+			result = acpi_battery_get_info(battery);
 			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "acpi_battery_init() "
-						  "failed\n"));
+				ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+						"acpi_battery_get_info() failed"));
 			}
 		}
 		if (data_type == DATA_TYPE_INFO) {
 			continue;
 		}
-
-		if (sbs->zombie) {
+		if (sbs_zombie(sbs)) {
 			goto end;
 		}
-		if (new_battery_present) {
-			result = acpi_battery_get_alarm(battery);
-			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "acpi_battery_get_alarm() "
-						  "failed\n"));
-			}
-			if (data_type == DATA_TYPE_ALARM) {
-				continue;
-			}
 
+		if ((data_type == DATA_TYPE_COMMON
+		     || data_type == DATA_TYPE_STATE)
+		    && new_battery_present) {
 			result = acpi_battery_get_state(battery);
 			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "acpi_battery_get_state() "
-						  "failed\n"));
+				ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+						"acpi_battery_get_state() failed"));
 			}
 		}
-		if (sbs->zombie) {
-			goto end;
+		if (data_type == DATA_TYPE_STATE) {
+			goto event;
 		}
-		if (data_type != DATA_TYPE_COMMON) {
-			continue;
+		if (sbs_zombie(sbs)) {
+			goto end;
 		}
 
-		if (old_battery_present != new_battery_present) {
-			sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
-			result = acpi_sbs_generate_event(sbs->device,
-							 ACPI_SBS_BATTERY_NOTIFY_STATUS,
-							 new_battery_present,
-							 dir_name,
-							 ACPI_BATTERY_CLASS);
+		if ((data_type == DATA_TYPE_COMMON
+		     || data_type == DATA_TYPE_ALARM)
+		    && new_battery_present) {
+			result = acpi_battery_get_alarm(battery);
 			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "acpi_sbs_generate_event() "
-						  "failed\n"));
+				ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+						"acpi_battery_get_alarm() "
+						"failed"));
 			}
 		}
-		if (old_remaining_capacity != battery->state.remaining_capacity) {
+		if (data_type == DATA_TYPE_ALARM) {
+			continue;
+		}
+		if (sbs_zombie(sbs)) {
+			goto end;
+		}
+
+	      event:
+
+		if (old_battery_present != new_battery_present || do_ac_init ||
+		    old_remaining_capacity !=
+		    battery->state.remaining_capacity) {
 			sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
 			result = acpi_sbs_generate_event(sbs->device,
 							 ACPI_SBS_BATTERY_NOTIFY_STATUS,
@@ -1502,138 +1573,120 @@ static int acpi_sbs_update_run(struct ac
 							 dir_name,
 							 ACPI_BATTERY_CLASS);
 			if (result) {
-				ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-						  "acpi_sbs_generate_event() failed\n"));
+				ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+						"acpi_sbs_generate_event() "
+						"failed"));
 			}
 		}
-
-	}
-	if (sbs->zombie) {
-		goto end;
-	}
-	if (data_type != DATA_TYPE_COMMON) {
-		goto end;
-	}
-
-	if (old_ac_present != new_ac_present) {
-		result = acpi_sbs_generate_event(sbs->device,
-						 ACPI_SBS_AC_NOTIFY_STATUS,
-						 new_ac_present,
-						 ACPI_AC_DIR_NAME,
-						 ACPI_AC_CLASS);
-		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_generate_event() failed\n"));
-		}
 	}
 
       end:
+
 	return result;
 }
 
-static void acpi_sbs_update_queue(void *data)
+static void acpi_sbs_update_time(void *data)
 {
 	struct acpi_sbs *sbs = data;
 	unsigned long delay = -1;
 	int result;
+	unsigned int up_tm = update_time;
 
-	if (sbs->zombie) {
-		goto end;
-	}
+	if (sbs_mutex_lock(sbs))
+		return;
 
-	result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
+	result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_sbs_update_run() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_sbs_update_run() failed"));
 	}
 
-	if (sbs->zombie) {
+	if (sbs_zombie(sbs)) {
 		goto end;
 	}
 
-	if (update_mode == REQUEST_UPDATE_MODE) {
-		goto end;
+	if (!up_tm) {
+		if (timer_pending(&sbs->update_timer))
+			del_timer(&sbs->update_timer);
+	} else {
+		delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+		delay = jiffies + HZ * delay;
+		if (timer_pending(&sbs->update_timer)) {
+			mod_timer(&sbs->update_timer, delay);
+		} else {
+			sbs->update_timer.data = (unsigned long)data;
+			sbs->update_timer.function = acpi_sbs_update_time_run;
+			sbs->update_timer.expires = delay;
+			add_timer(&sbs->update_timer);
+		}
 	}
 
-	delay = jiffies + HZ * update_time;
-	sbs->update_timer.data = (unsigned long)data;
-	sbs->update_timer.function = acpi_sbs_update_queue_run;
-	sbs->update_timer.expires = delay;
-	add_timer(&sbs->update_timer);
       end:
-	;
+
+	sbs_mutex_unlock(sbs);
 }
 
 static int acpi_sbs_add(struct acpi_device *device)
 {
 	struct acpi_sbs *sbs = NULL;
-	struct acpi_ec_hc *ec_hc = NULL;
-	int result, remove_result = 0;
+	int result = 0, remove_result = 0;
 	unsigned long sbs_obj;
-	int id, cnt;
+	int id;
 	acpi_status status = AE_OK;
+	unsigned long val;
+
+	status =
+	    acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
+		return -EIO;
+	}
 
 	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
 	if (!sbs) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
-		return -ENOMEM;
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed"));
+		result = -ENOMEM;
+		goto end;
 	}
 
-	cnt = 0;
-	while (cnt < 10) {
-		cnt++;
-		ec_hc = acpi_get_ec_hc(device);
-		if (ec_hc) {
-			break;
-		}
-		msleep(1000);
-	}
+	mutex_init(&sbs->mutex);
 
-	if (!ec_hc) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_get_ec_hc() failed: "
-				  "NO driver found for EC HC SMBus\n"));
-		result = -ENODEV;
-		goto end;
-	}
+	sbs_mutex_lock(sbs);
 
+	sbs->base = (val & 0xff00ull) >> 8;
 	sbs->device = device;
-	sbs->smbus = ec_hc->smbus;
 
 	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
 	acpi_driver_data(device) = sbs;
 
-	sbs->update_time = 0;
-	sbs->update_time2 = 0;
-
 	result = acpi_ac_add(sbs);
 	if (result) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
 		goto end;
 	}
-	result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
-	if (ACPI_FAILURE(result)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_evaluate_integer() failed\n"));
+	status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+	if (status) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"acpi_evaluate_integer() failed"));
 		result = -EIO;
 		goto end;
 	}
-
 	if (sbs_obj > 0) {
 		result = acpi_sbsm_get_info(sbs);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbsm_get_info() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbsm_get_info() failed"));
 			goto end;
 		}
 		sbs->sbsm_present = 1;
 	}
+
 	if (sbs->sbsm_present == 0) {
 		result = acpi_battery_add(sbs, 0);
 		if (result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_battery_add() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_battery_add() failed"));
 			goto end;
 		}
 	} else {
@@ -1641,9 +1694,8 @@ static int acpi_sbs_add(struct acpi_devi
 			if ((sbs->sbsm_batteries_supported & (1 << id))) {
 				result = acpi_battery_add(sbs, id);
 				if (result) {
-					ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-							  "acpi_battery_add() "
-							  "failed\n"));
+					ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+							"acpi_battery_add() failed"));
 					goto end;
 				}
 			}
@@ -1653,33 +1705,26 @@ static int acpi_sbs_add(struct acpi_devi
 	sbs->handle = device->handle;
 
 	init_timer(&sbs->update_timer);
-	if (update_mode == QUEUE_UPDATE_MODE) {
-		status = acpi_os_execute(OSL_GPE_HANDLER,
-					 acpi_sbs_update_queue, sbs);
-		if (status != AE_OK) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_os_execute() failed\n"));
-		}
-	}
-	sbs->update_time = update_time;
-	sbs->update_time2 = update_time2;
-
-	printk(KERN_INFO PREFIX "%s [%s]\n",
-	       acpi_device_name(device), acpi_device_bid(device));
+	result = acpi_check_update_proc(sbs);
+	if (result)
+		goto end;
 
       end:
+
+	sbs_mutex_unlock(sbs);
+
 	if (result) {
 		remove_result = acpi_sbs_remove(device, 0);
 		if (remove_result) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-					  "acpi_sbs_remove() failed\n"));
+			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+					"acpi_sbs_remove() failed"));
 		}
 	}
 
 	return result;
 }
 
-int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device, int type)
 {
 	struct acpi_sbs *sbs;
 	int id;
@@ -1688,15 +1733,14 @@ int acpi_sbs_remove(struct acpi_device *
 		return -EINVAL;
 	}
 
-	sbs = (struct acpi_sbs *)acpi_driver_data(device);
-
+	sbs = acpi_driver_data(device);
 	if (!sbs) {
 		return -EINVAL;
 	}
 
+	sbs_mutex_lock(sbs);
+
 	sbs->zombie = 1;
-	sbs->update_time = 0;
-	sbs->update_time2 = 0;
 	del_timer_sync(&sbs->update_timer);
 	acpi_os_wait_events_complete(NULL);
 	del_timer_sync(&sbs->update_timer);
@@ -1707,11 +1751,41 @@ int acpi_sbs_remove(struct acpi_device *
 
 	acpi_ac_remove(sbs);
 
+	sbs_mutex_unlock(sbs);
+
+	mutex_destroy(&sbs->mutex);
+
 	kfree(sbs);
 
 	return 0;
 }
 
+static void acpi_sbs_rmdirs(void)
+{
+	if (acpi_ac_dir) {
+		acpi_unlock_ac_dir(acpi_ac_dir);
+		acpi_ac_dir = NULL;
+	}
+	if (acpi_battery_dir) {
+		acpi_unlock_battery_dir(acpi_battery_dir);
+		acpi_battery_dir = NULL;
+	}
+}
+
+static int acpi_sbs_resume(struct acpi_device *device)
+{
+	struct acpi_sbs *sbs;
+
+	if (!device)
+		return -EINVAL;
+
+	sbs = device->driver_data;
+
+	sbs->run_cnt = 0;
+
+	return 0;
+}
+
 static int __init acpi_sbs_init(void)
 {
 	int result = 0;
@@ -1719,35 +1793,34 @@ static int __init acpi_sbs_init(void)
 	if (acpi_disabled)
 		return -ENODEV;
 
-	init_MUTEX(&sbs_sem);
-
 	if (capacity_mode != DEF_CAPACITY_UNIT
 	    && capacity_mode != MAH_CAPACITY_UNIT
 	    && capacity_mode != MWH_CAPACITY_UNIT) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
-				  "invalid capacity_mode = %d\n",
-				  capacity_mode));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"invalid capacity_mode = %d", capacity_mode));
 		return -EINVAL;
 	}
 
 	acpi_ac_dir = acpi_lock_ac_dir();
 	if (!acpi_ac_dir) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_lock_ac_dir() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_lock_ac_dir() failed"));
 		return -ENODEV;
 	}
 
 	acpi_battery_dir = acpi_lock_battery_dir();
 	if (!acpi_battery_dir) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_lock_battery_dir() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_lock_battery_dir() failed"));
+		acpi_sbs_rmdirs();
 		return -ENODEV;
 	}
 
 	result = acpi_bus_register_driver(&acpi_sbs_driver);
 	if (result < 0) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				  "acpi_bus_register_driver() failed\n"));
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+				"acpi_bus_register_driver() failed"));
+		acpi_sbs_rmdirs();
 		return -ENODEV;
 	}
 
@@ -1756,13 +1829,9 @@ static int __init acpi_sbs_init(void)
 
 static void __exit acpi_sbs_exit(void)
 {
-
 	acpi_bus_unregister_driver(&acpi_sbs_driver);
 
-	acpi_unlock_ac_dir(acpi_ac_dir);
-	acpi_ac_dir = NULL;
-	acpi_unlock_battery_dir(acpi_battery_dir);
-	acpi_battery_dir = NULL;
+	acpi_sbs_rmdirs();
 
 	return;
 }
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index bb0e0da..6b3b8a5 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -302,7 +302,7 @@ static void acpi_device_shutdown(struct 
 	return ;
 }
 
-static struct bus_type acpi_bus_type = {
+struct bus_type acpi_bus_type = {
 	.name		= "acpi",
 	.suspend	= acpi_device_suspend,
 	.resume		= acpi_device_resume,
@@ -1068,7 +1068,9 @@ acpi_add_single_object(struct acpi_devic
 		}
 		break;
 	default:
-		STRUCT_TO_INT(device->status) = 0x0F;
+		STRUCT_TO_INT(device->status) =
+		    ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+		    ACPI_STA_DEVICE_UI      | ACPI_STA_DEVICE_FUNCTIONING;
 		break;
 	}
 
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 37a0930..f8c6341 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -168,9 +168,18 @@ int acpi_suspend(u32 acpi_state)
 
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 {
-	u32 acpi_state = acpi_suspend_states[pm_state];
+	u32 acpi_state;
+
+	switch (pm_state) {
+	case PM_SUSPEND_ON:
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		acpi_state = acpi_suspend_states[pm_state];
 
-	return sleep_states[acpi_state];
+		return sleep_states[acpi_state];
+	default:
+		return 0;
+	}
 }
 
 static struct pm_ops acpi_pm_ops = {
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index ccc11b3..5a76e5b 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -60,7 +60,7 @@ acpi_system_write_sleep(struct file *fil
 	state = simple_strtoul(str, NULL, 0);
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	if (state == 4) {
-		error = software_suspend();
+		error = pm_suspend(PM_SUSPEND_DISK);
 		goto Done;
 	}
 #endif
@@ -70,6 +70,14 @@ #endif
 }
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
+#else
+#define	HAVE_ACPI_LEGACY_ALARM
+#endif
+
+#ifdef	HAVE_ACPI_LEGACY_ALARM
+
 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
 {
 	u32 sec, min, hr;
@@ -341,6 +349,8 @@ acpi_system_write_alarm(struct file *fil
       end:
 	return_VALUE(result ? result : count);
 }
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
+
 
 extern struct list_head acpi_wakeup_device_list;
 extern spinlock_t acpi_device_lock;
@@ -350,21 +360,31 @@ acpi_system_wakeup_device_seq_show(struc
 {
 	struct list_head *node, *next;
 
-	seq_printf(seq, "Device	Sleep state	Status\n");
+	seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
 
 	spin_lock(&acpi_device_lock);
 	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
 		struct acpi_device *dev =
 		    container_of(node, struct acpi_device, wakeup_list);
+		struct device *ldev;
 
 		if (!dev->wakeup.flags.valid)
 			continue;
 		spin_unlock(&acpi_device_lock);
-		seq_printf(seq, "%4s	%4d		%s%8s\n",
+
+		ldev = acpi_get_physical_device(dev->handle);
+		seq_printf(seq, "%s\t  S%d\t%c%-8s  ",
 			   dev->pnp.bus_id,
 			   (u32) dev->wakeup.sleep_state,
-			   dev->wakeup.flags.run_wake ? "*" : "",
+			   dev->wakeup.flags.run_wake ? '*' : ' ',
 			   dev->wakeup.state.enabled ? "enabled" : "disabled");
+		if (ldev)
+			seq_printf(seq, "%s:%s",
+				ldev->bus ? ldev->bus->name : "no-bus",
+				ldev->bus_id);
+		seq_printf(seq, "\n");
+		put_device(ldev);
+
 		spin_lock(&acpi_device_lock);
 	}
 	spin_unlock(&acpi_device_lock);
@@ -454,6 +474,7 @@ static const struct file_operations acpi
 };
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#ifdef	HAVE_ACPI_LEGACY_ALARM
 static const struct file_operations acpi_system_alarm_fops = {
 	.open = acpi_system_alarm_open_fs,
 	.read = seq_read,
@@ -469,8 +490,9 @@ static u32 rtc_handler(void *context)
 
 	return ACPI_INTERRUPT_HANDLED;
 }
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
 
-static int acpi_sleep_proc_init(void)
+static int __init acpi_sleep_proc_init(void)
 {
 	struct proc_dir_entry *entry = NULL;
 
@@ -486,6 +508,7 @@ #ifdef	CONFIG_ACPI_SLEEP_PROC_SLEEP
 		entry->proc_fops = &acpi_system_sleep_fops;
 #endif
 
+#ifdef	HAVE_ACPI_LEGACY_ALARM
 	/* 'alarm' [R/W] */
 	entry =
 	    create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
@@ -493,6 +516,9 @@ #endif
 	if (entry)
 		entry->proc_fops = &acpi_system_alarm_fops;
 
+	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
+
 	/* 'wakeup device' [R/W] */
 	entry =
 	    create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
@@ -500,7 +526,6 @@ #endif
 	if (entry)
 		entry->proc_fops = &acpi_system_wakeup_device_fops;
 
-	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
 	return 0;
 }
 
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 807c711..1db833e 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -347,6 +347,18 @@ static void acpi_tb_convert_fadt(void)
 		acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
 
 	}
+
+	/*
+	 * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
+	 * are indeed zero. This will workaround BIOSs that inadvertently placed
+	 * values in these fields.
+	 */
+	if (acpi_gbl_FADT.header.revision < 3) {
+		acpi_gbl_FADT.preferred_profile = 0;
+		acpi_gbl_FADT.pstate_control = 0;
+		acpi_gbl_FADT.cst_control = 0;
+		acpi_gbl_FADT.boot_flags = 0;
+	}
 }
 
 /******************************************************************************
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index fd54750..268e301 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -47,14 +47,13 @@ #ifdef CONFIG_HOTPLUG
 static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
 {
 	struct amba_device *pcdev = to_amba_device(dev);
+	int retval = 0, i = 0, len = 0;
 
-	if (nr_env < 2)
-		return -ENOMEM;
-
-	snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid);
-	*envp++ = buf;
-	*envp++ = NULL;
-	return 0;
+	retval = add_uevent_var(envp, nr_env, &i,
+				buf, bufsz, &len,
+				"AMBA_ID=%08x", pcdev->periphid);
+	envp[i] = NULL;
+	return retval;
 }
 #else
 #define amba_uevent NULL
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 7bdbe5a..45dbdc1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -156,11 +156,6 @@ config SATA_INIC162X
 	help
 	  This option enables support for Initio 162x Serial ATA.
 
-config SATA_INTEL_COMBINED
-	bool
-	depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
-	default y
-
 config SATA_ACPI
 	bool
 	depends on ACPI && PCI
@@ -184,7 +179,7 @@ config PATA_ALI
 	  If unsure, say N.
 
 config PATA_AMD
-	tristate "AMD/NVidia PATA support (Experimental)"
+	tristate "AMD/NVidia PATA support"
 	depends on PCI
 	help
 	  This option enables support for the AMD and NVidia PATA
@@ -209,6 +204,16 @@ config PATA_ATIIXP
 
 	  If unsure, say N.
 
+config PATA_CMD640_PCI
+	tristate "CMD640 PCI PATA support (Very Experimental)"
+	depends on PCI && EXPERIMENTAL
+	help
+	  This option enables support for the CMD640 PCI IDE
+	  interface chip. Only the primary channel is currently
+	  supported.
+
+	  If unsure, say N.
+
 config PATA_CMD64X
 	tristate "CMD64x PATA support (Very Experimental)"
 	depends on PCI&& EXPERIMENTAL
@@ -273,7 +278,7 @@ config ATA_GENERIC
 	  If unsure, say N.
 
 config PATA_HPT366
-	tristate "HPT 366/368 PATA support (Very Experimental)"
+	tristate "HPT 366/368 PATA support (Experimental)"
 	depends on PCI && EXPERIMENTAL
 	help
 	  This option enables support for the HPT 366 and 368
@@ -282,7 +287,7 @@ config PATA_HPT366
 	  If unsure, say N.
 
 config PATA_HPT37X
-	tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+	tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
 	depends on PCI && EXPERIMENTAL
 	help
 	  This option enables support for the majority of the later HPT
@@ -309,7 +314,7 @@ config PATA_HPT3X3
 	  If unsure, say N.
 
 config PATA_ISAPNP
-	tristate "ISA Plug and Play PATA support (Very Experimental)"
+	tristate "ISA Plug and Play PATA support (Experimental)"
 	depends on EXPERIMENTAL && ISAPNP
 	help
 	  This option enables support for ISA plug & play ATA
@@ -318,8 +323,8 @@ config PATA_ISAPNP
 	  If unsure, say N.
 
 config PATA_IT821X
-	tristate "IT8211/2 PATA support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "IT8211/2 PATA support"
+	depends on PCI
 	help
 	  This option enables support for the ITE 8211 and 8212
 	  PATA controllers via the new ATA layer, including RAID
@@ -390,10 +395,10 @@ config PATA_MPIIX
 	  If unsure, say N.
 
 config PATA_OLDPIIX
-	tristate "Intel PATA old PIIX support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "Intel PATA old PIIX support"
+	depends on PCI
 	help
-	  This option enables support for old(?) PIIX PATA support.
+	  This option enables support for early PIIX PATA support.
 
 	  If unsure, say N.
 
@@ -444,7 +449,7 @@ config PATA_PCMCIA
 	  If unsure, say N.
 
 config PATA_PDC_OLD
-	tristate "Older Promise PATA controller support (Very Experimental)"
+	tristate "Older Promise PATA controller support (Experimental)"
 	depends on PCI && EXPERIMENTAL
 	help
 	  This option enables support for the Promise 20246, 20262, 20263,
@@ -459,7 +464,7 @@ config PATA_QDI
 	  Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
 
 config PATA_RADISYS
-	tristate "RADISYS 82600 PATA support (Very experimental)"
+	tristate "RADISYS 82600 PATA support (Very Experimental)"
 	depends on PCI && EXPERIMENTAL
 	help
 	  This option enables support for the RADISYS 82600
@@ -477,7 +482,7 @@ config PATA_RZ1000
 	  If unsure, say N.
 
 config PATA_SC1200
-	tristate "SC1200 PATA support (Raving Lunatic)"
+	tristate "SC1200 PATA support (Very Experimental)"
 	depends on PCI && EXPERIMENTAL
 	help
 	  This option enables support for the NatSemi/AMD SC1200 SoC
@@ -486,8 +491,8 @@ config PATA_SC1200
 	  If unsure, say N.
 
 config PATA_SERVERWORKS
-	tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
+	depends on PCI
 	help
 	  This option enables support for the Serverworks OSB4/CSB5/CSB6 and
 	  HT1000 PATA controllers, via the new ATA layer.
@@ -545,13 +550,21 @@ config PATA_WINBOND_VLB
 
 config PATA_PLATFORM
 	tristate "Generic platform device PATA support"
-	depends on EMBEDDED
+	depends on EMBEDDED || ARCH_RPC
 	help
 	  This option enables support for generic directly connected ATA
 	  devices commonly found on embedded systems.
 
 	  If unsure, say N.
 
+config PATA_ICSIDE
+	tristate "Acorn ICS PATA support"
+	depends on ARM && ARCH_ACORN
+	help
+	  On Acorn systems, say Y here if you wish to use the ICS PATA
+	  interface card.  This is not required for ICS partition support.
+	  If you are unsure, say N to this.
+
 config PATA_IXP4XX_CF
 	tristate "IXP4XX Compact Flash support"
 	depends on ARCH_IXP4XX
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 13d7397..6f42a0e 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -22,6 +22,7 @@ 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_CMD640_PCI)	+= pata_cmd640.o
 obj-$(CONFIG_PATA_CMD64X)	+= pata_cmd64x.o
 obj-$(CONFIG_PATA_CS5520)	+= pata_cs5520.o
 obj-$(CONFIG_PATA_CS5530)	+= pata_cs5530.o
@@ -61,6 +62,7 @@ obj-$(CONFIG_PATA_TRIFLEX)	+= pata_trifl
 obj-$(CONFIG_PATA_IXP4XX_CF)	+= pata_ixp4xx_cf.o
 obj-$(CONFIG_PATA_SCC)		+= pata_scc.o
 obj-$(CONFIG_PATA_PLATFORM)	+= pata_platform.o
+obj-$(CONFIG_PATA_ICSIDE)	+= pata_icside.o
 # Should be last but one libata driver
 obj-$(CONFIG_ATA_GENERIC)	+= ata_generic.o
 # Should be last libata driver
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index fd27227..d961789 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -170,6 +170,10 @@ enum {
 	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
 	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
 	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
+
+	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+					  ATA_FLAG_SKIP_D2H_BSY,
 };
 
 struct ahci_cmd_hdr {
@@ -188,8 +192,10 @@ struct ahci_sg {
 };
 
 struct ahci_host_priv {
-	u32			cap;	/* cache of HOST_CAP register */
-	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
+	u32			cap;		/* cap to use */
+	u32			port_map;	/* port map to use */
+	u32			saved_cap;	/* saved initial cap */
+	u32			saved_port_map;	/* saved initial port_map */
 };
 
 struct ahci_port_priv {
@@ -209,7 +215,6 @@ static u32 ahci_scr_read (struct ata_por
 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);
@@ -263,7 +268,6 @@ static const struct ata_port_operations 
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
-	.irq_handler		= ahci_interrupt,
 	.irq_clear		= ahci_irq_clear,
 	.irq_on			= ata_dummy_irq_on,
 	.irq_ack		= ata_dummy_irq_ack,
@@ -298,7 +302,6 @@ static const struct ata_port_operations 
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
-	.irq_handler		= ahci_interrupt,
 	.irq_clear		= ahci_irq_clear,
 	.irq_on			= ata_dummy_irq_on,
 	.irq_ack		= ata_dummy_irq_ack,
@@ -324,58 +327,41 @@ #endif
 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,
+		.flags		= AHCI_FLAG_COMMON,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
 	},
 	/* board_ahci_pi */
 	{
-		.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_HONOR_PI,
+		.flags		= AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
 		.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 |
-				  ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
+				  AHCI_FLAG_NO_NCQ,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_vt8251_ops,
 	},
 	/* board_ahci_ign_iferr */
 	{
-		.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_IGN_IRQ_IF_ERR,
+		.flags		= AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
 	},
 	/* board_ahci_sb600 */
 	{
-		.sht		= &ahci_sht,
-		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-				  ATA_FLAG_SKIP_D2H_BSY |
+		.flags		= AHCI_FLAG_COMMON |
 				  AHCI_FLAG_IGN_SERR_INTERNAL,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &ahci_ops,
 	},
-
 };
 
 static const struct pci_device_id ahci_pci_tbl[] = {
@@ -413,11 +399,11 @@ static const struct pci_device_id ahci_p
 	  PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
 
 	/* ATI */
-	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 non-raid */
-	{ PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
+	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
 
 	/* VIA */
 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+	{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
 
 	/* NVIDIA */
 	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
@@ -471,10 +457,100 @@ static inline int ahci_nr_ports(u32 cap)
 	return (cap & 0x1f) + 1;
 }
 
-static inline void __iomem *ahci_port_base(void __iomem *base,
-					   unsigned int port)
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+	return mmio + 0x100 + (ap->port_no * 0x80);
+}
+
+/**
+ *	ahci_save_initial_config - Save and fixup initial config values
+ *	@pdev: target PCI device
+ *	@pi: associated ATA port info
+ *	@hpriv: host private area to store config values
+ *
+ *	Some registers containing configuration info might be setup by
+ *	BIOS and might be cleared on reset.  This function saves the
+ *	initial values of those registers into @hpriv such that they
+ *	can be restored after controller reset.
+ *
+ *	If inconsistent, config values are fixed up by this function.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void ahci_save_initial_config(struct pci_dev *pdev,
+				     const struct ata_port_info *pi,
+				     struct ahci_host_priv *hpriv)
 {
-	return base + 0x100 + (port * 0x80);
+	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+	u32 cap, port_map;
+	int i;
+
+	/* Values prefixed with saved_ are written back to host after
+	 * reset.  Values without are used for driver operation.
+	 */
+	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+
+	/* fixup zero port_map */
+	if (!port_map) {
+		port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+
+		/* write the fixed up value to the PI register */
+		hpriv->saved_port_map = port_map;
+	}
+
+	/* cross check port_map and cap.n_ports */
+	if (pi->flags & AHCI_FLAG_HONOR_PI) {
+		u32 tmp_port_map = port_map;
+		int n_ports = ahci_nr_ports(cap);
+
+		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+			if (tmp_port_map & (1 << i)) {
+				n_ports--;
+				tmp_port_map &= ~(1 << i);
+			}
+		}
+
+		/* Whine if inconsistent.  No need to update cap.
+		 * port_map is used to determine number of ports.
+		 */
+		if (n_ports || tmp_port_map)
+			dev_printk(KERN_WARNING, &pdev->dev,
+				   "nr_ports (%u) and implemented port map "
+				   "(0x%x) don't match\n",
+				   ahci_nr_ports(cap), port_map);
+	} else {
+		/* fabricate port_map from cap.nr_ports */
+		port_map = (1 << ahci_nr_ports(cap)) - 1;
+	}
+
+	/* record values to use during operation */
+	hpriv->cap = cap;
+	hpriv->port_map = port_map;
+}
+
+/**
+ *	ahci_restore_initial_config - Restore initial config
+ *	@host: target ATA host
+ *
+ *	Restore initial config stored by ahci_save_initial_config().
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void ahci_restore_initial_config(struct ata_host *host)
+{
+	struct ahci_host_priv *hpriv = host->private_data;
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
+	writel(hpriv->saved_cap, mmio + HOST_CAP);
+	writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
+	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
 }
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -511,8 +587,9 @@ static void ahci_scr_write (struct ata_p
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* start DMA */
@@ -522,8 +599,9 @@ static void ahci_start_engine(void __iom
 	readl(port_mmio + PORT_CMD); /* flush */
 }
 
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	tmp = readl(port_mmio + PORT_CMD);
@@ -545,19 +623,23 @@ static int ahci_stop_engine(void __iomem
 	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)
+static void ahci_start_fis_rx(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	struct ahci_port_priv *pp = ap->private_data;
 	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 (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);
 
-	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);
+	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);
 
 	/* enable FIS reception */
 	tmp = readl(port_mmio + PORT_CMD);
@@ -568,8 +650,9 @@ static void ahci_start_fis_rx(void __iom
 	readl(port_mmio + PORT_CMD);
 }
 
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
 {
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* disable FIS reception */
@@ -586,14 +669,16 @@ static int ahci_stop_fis_rx(void __iomem
 	return 0;
 }
 
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 cmd;
 
 	cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
 
 	/* spin up device */
-	if (cap & HOST_CAP_SSS) {
+	if (hpriv->cap & HOST_CAP_SSS) {
 		cmd |= PORT_CMD_SPIN_UP;
 		writel(cmd, port_mmio + PORT_CMD);
 	}
@@ -603,11 +688,13 @@ static void ahci_power_up(void __iomem *
 }
 
 #ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 cmd, scontrol;
 
-	if (!(cap & HOST_CAP_SSS))
+	if (!(hpriv->cap & HOST_CAP_SSS))
 		return;
 
 	/* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -622,29 +709,28 @@ static void ahci_power_down(void __iomem
 }
 #endif
 
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
-			   dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_init_port(struct ata_port *ap)
 {
 	/* enable FIS reception */
-	ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+	ahci_start_fis_rx(ap);
 
 	/* enable DMA */
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 }
 
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 {
 	int rc;
 
 	/* disable DMA */
-	rc = ahci_stop_engine(port_mmio);
+	rc = ahci_stop_engine(ap);
 	if (rc) {
 		*emsg = "failed to stop engine";
 		return rc;
 	}
 
 	/* disable FIS reception */
-	rc = ahci_stop_fis_rx(port_mmio);
+	rc = ahci_stop_fis_rx(ap);
 	if (rc) {
 		*emsg = "failed stop FIS RX";
 		return rc;
@@ -653,12 +739,11 @@ static int ahci_deinit_port(void __iomem
 	return 0;
 }
 
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+static int ahci_reset_controller(struct ata_host *host)
 {
-	u32 cap_save, impl_save, tmp;
-
-	cap_save = readl(mmio + HOST_CAP);
-	impl_save = readl(mmio + HOST_PORTS_IMPL);
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+	u32 tmp;
 
 	/* global controller reset */
 	tmp = readl(mmio + HOST_CTL);
@@ -674,7 +759,7 @@ static int ahci_reset_controller(void __
 
 	tmp = readl(mmio + HOST_CTL);
 	if (tmp & HOST_RESET) {
-		dev_printk(KERN_ERR, &pdev->dev,
+		dev_printk(KERN_ERR, host->dev,
 			   "controller reset failed (0x%x)\n", tmp);
 		return -EIO;
 	}
@@ -683,18 +768,8 @@ static int ahci_reset_controller(void __
 	writel(HOST_AHCI_EN, mmio + HOST_CTL);
 	(void) readl(mmio + HOST_CTL);	/* flush */
 
-	/* These write-once registers are normally cleared on reset.
-	 * Restore BIOS values... which we HOPE were present before
-	 * reset.
-	 */
-	if (!impl_save) {
-		impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
-		dev_printk(KERN_WARNING, &pdev->dev,
-			   "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
-	}
-	writel(cap_save, mmio + HOST_CAP);
-	writel(impl_save, mmio + HOST_PORTS_IMPL);
-	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
+	/* some registers might be cleared on reset.  restore initial values */
+	ahci_restore_initial_config(host);
 
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		u16 tmp16;
@@ -708,23 +783,23 @@ static int ahci_reset_controller(void __
 	return 0;
 }
 
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
-				 int n_ports, unsigned int port_flags,
-				 struct ahci_host_priv *hpriv)
+static void ahci_init_controller(struct ata_host *host)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	int i, rc;
 	u32 tmp;
 
-	for (i = 0; i < n_ports; i++) {
-		void __iomem *port_mmio = ahci_port_base(mmio, i);
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		void __iomem *port_mmio = ahci_port_base(ap);
 		const char *emsg = NULL;
 
-		if ((port_flags & AHCI_FLAG_HONOR_PI) &&
-		    !(hpriv->port_map & (1 << i)))
+		if (ata_port_is_dummy(ap))
 			continue;
 
 		/* make sure port is not active */
-		rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+		rc = ahci_deinit_port(ap, &emsg);
 		if (rc)
 			dev_printk(KERN_WARNING, &pdev->dev,
 				   "%s (%d)\n", emsg, rc);
@@ -752,7 +827,7 @@ static void ahci_init_controller(void __
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
 {
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	struct ata_taskfile tf;
 	u32 tmp;
 
@@ -799,11 +874,11 @@ static int ahci_clo(struct ata_port *ap)
 	return 0;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+			  unsigned long deadline)
 {
 	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 	const u32 cmd_fis_len = 5; /* five dwords */
 	const char *reason = NULL;
 	struct ata_taskfile tf;
@@ -820,7 +895,7 @@ static int ahci_softreset(struct ata_por
 	}
 
 	/* prepare for SRST (AHCI-1.1 10.4.1) */
-	rc = ahci_stop_engine(port_mmio);
+	rc = ahci_stop_engine(ap);
 	if (rc) {
 		reason = "failed to stop engine";
 		goto fail_restart;
@@ -840,7 +915,7 @@ static int ahci_softreset(struct ata_por
 	}
 
 	/* restart engine */
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	ata_tf_init(ap->device, &tf);
 	fis = pp->cmd_tbl;
@@ -885,47 +960,44 @@ static int ahci_softreset(struct ata_por
 	 */
 	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);
+	rc = ata_wait_ready(ap, deadline);
+	/* link occupied, -ENODEV too is an error */
+	if (rc) {
+		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);
+	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)
+static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+			  unsigned long deadline)
 {
 	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->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	ahci_stop_engine(port_mmio);
+	ahci_stop_engine(ap);
 
 	/* clear D2H reception area to properly wait for D2H FIS */
 	ata_tf_init(ap->device, &tf);
 	tf.command = 0x80;
 	ata_tf_to_fis(&tf, d2h_fis, 0);
 
-	rc = sata_std_hardreset(ap, class);
+	rc = sata_std_hardreset(ap, class, deadline);
 
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	if (rc == 0 && ata_port_online(ap))
 		*class = ahci_dev_classify(ap);
@@ -936,22 +1008,22 @@ static int ahci_hardreset(struct ata_por
 	return rc;
 }
 
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+				 unsigned long deadline)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	ahci_stop_engine(port_mmio);
+	ahci_stop_engine(ap);
 
-	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
+	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+				 deadline);
 
 	/* vt8251 needs SError cleared for the port to operate */
 	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
 
-	ahci_start_engine(port_mmio);
+	ahci_start_engine(ap);
 
 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 
@@ -963,7 +1035,7 @@ static int ahci_vt8251_hardreset(struct 
 
 static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 {
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 new_tmp, tmp;
 
 	ata_std_postreset(ap, class);
@@ -1131,8 +1203,7 @@ static void ahci_error_intr(struct ata_p
 
 static void ahci_host_intr(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
 	struct ata_eh_info *ehi = &ap->eh_info;
 	struct ahci_port_priv *pp = ap->private_data;
 	u32 status, qc_active;
@@ -1283,7 +1354,7 @@ static irqreturn_t ahci_interrupt(int ir
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	void __iomem *port_mmio = ahci_port_base(ap);
 
 	if (qc->tf.protocol == ATA_PROT_NCQ)
 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1295,8 +1366,7 @@ static unsigned int ahci_qc_issue(struct
 
 static void ahci_freeze(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 
 	/* turn IRQ off */
 	writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1305,7 +1375,7 @@ static void ahci_freeze(struct ata_port 
 static void ahci_thaw(struct ata_port *ap)
 {
 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
 
 	/* clear IRQ */
@@ -1319,13 +1389,10 @@ static void ahci_thaw(struct ata_port *a
 
 static void ahci_error_handler(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	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);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 
 	/* perform recovery */
@@ -1335,13 +1402,10 @@ static void ahci_error_handler(struct at
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
 {
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	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);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 
 	/* perform recovery */
@@ -1352,36 +1416,26 @@ static void ahci_vt8251_error_handler(st
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	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) {
+	if (qc->flags & ATA_QCFLAG_FAILED) {
 		/* make DMA engine forget about the failed command */
-		ahci_stop_engine(port_mmio);
-		ahci_start_engine(port_mmio);
+		ahci_stop_engine(ap);
+		ahci_start_engine(ap);
 	}
 }
 
 #ifdef CONFIG_PM
 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->iomap[AHCI_PCI_BAR];
-	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);
+	rc = ahci_deinit_port(ap, &emsg);
 	if (rc == 0)
-		ahci_power_down(port_mmio, hpriv->cap);
+		ahci_power_down(ap);
 	else {
 		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);
+		ahci_init_port(ap);
 	}
 
 	return rc;
@@ -1389,13 +1443,8 @@ static int ahci_port_suspend(struct ata_
 
 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->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
-	ahci_power_up(port_mmio, hpriv->cap);
-	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+	ahci_power_up(ap);
+	ahci_init_port(ap);
 
 	return 0;
 }
@@ -1423,8 +1472,6 @@ static int ahci_pci_device_suspend(struc
 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->iomap[AHCI_PCI_BAR];
 	int rc;
 
 	rc = ata_pci_device_do_resume(pdev);
@@ -1432,12 +1479,11 @@ static int ahci_pci_device_resume(struct
 		return rc;
 
 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
-		rc = ahci_reset_controller(mmio, pdev);
+		rc = ahci_reset_controller(host);
 		if (rc)
 			return rc;
 
-		ahci_init_controller(mmio, pdev, host->n_ports,
-				     host->ports[0]->flags, hpriv);
+		ahci_init_controller(host);
 	}
 
 	ata_host_resume(host);
@@ -1449,10 +1495,7 @@ #endif
 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->iomap[AHCI_PCI_BAR];
-	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 	void *mem;
 	dma_addr_t mem_dma;
 	int rc;
@@ -1500,85 +1543,29 @@ static int ahci_port_start(struct ata_po
 	ap->private_data = pp;
 
 	/* power up port */
-	ahci_power_up(port_mmio, hpriv->cap);
+	ahci_power_up(ap);
 
 	/* initialize port */
-	ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+	ahci_init_port(ap);
 
 	return 0;
 }
 
 static void ahci_port_stop(struct ata_port *ap)
 {
-	struct ahci_host_priv *hpriv = ap->host->private_data;
-	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
-	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);
+	rc = ahci_deinit_port(ap, &emsg);
 	if (rc)
 		ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
 }
 
-static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
-			    unsigned int port_idx)
-{
-	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
-	base = ahci_port_base(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)
+static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
 {
-	struct ahci_host_priv *hpriv = probe_ent->private_data;
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
-	unsigned int i, cap_n_ports, 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);
-	cap_n_ports = ahci_nr_ports(hpriv->cap);
-
-	VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
-		hpriv->cap, hpriv->port_map, cap_n_ports);
-
-	if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
-		unsigned int n_ports = cap_n_ports;
-		u32 port_map = hpriv->port_map;
-		int max_port = 0;
-
-		for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
-			if (port_map & (1 << i)) {
-				n_ports--;
-				port_map &= ~(1 << i);
-				max_port = i;
-			} else
-				probe_ent->dummy_port_mask |= 1 << i;
-		}
-
-		if (n_ports || port_map)
-			dev_printk(KERN_WARNING, &pdev->dev,
-				   "nr_ports (%u) and implemented port map "
-				   "(0x%x) don't match\n",
-				   cap_n_ports, hpriv->port_map);
-
-		probe_ent->n_ports = max_port + 1;
-	} else
-		probe_ent->n_ports = cap_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);
@@ -1604,23 +1591,14 @@ static int ahci_host_init(struct ata_pro
 			return rc;
 		}
 	}
-
-	for (i = 0; i < probe_ent->n_ports; i++)
-		ahci_setup_port(&probe_ent->port[i], mmio, i);
-
-	ahci_init_controller(mmio, pdev, probe_ent->n_ports,
-			     probe_ent->port_flags, hpriv);
-
-	pci_set_master(pdev);
-
 	return 0;
 }
 
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
+static void ahci_print_info(struct ata_host *host)
 {
-	struct ahci_host_priv *hpriv = probe_ent->private_data;
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-	void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+	struct ahci_host_priv *hpriv = host->private_data;
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	u32 vers, cap, impl, speed;
 	const char *speed_s;
 	u16 cc;
@@ -1690,11 +1668,12 @@ static void ahci_print_info(struct ata_p
 static int ahci_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_port_info pi = ahci_port_info[ent->driver_data];
+	const struct ata_port_info *ppi[] = { &pi, NULL };
 	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent;
 	struct ahci_host_priv *hpriv;
-	int rc;
+	struct ata_host *host;
+	int i, rc;
 
 	VPRINTK("ENTER\n");
 
@@ -1703,6 +1682,7 @@ static int ahci_init_one(struct pci_dev 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -1716,44 +1696,49 @@ static int ahci_init_one(struct pci_dev 
 	if (pci_enable_msi(pdev))
 		pci_intx(pdev, 1);
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
 
-	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;
+	/* save initial config */
+	ahci_save_initial_config(pdev, &pi, hpriv);
 
-       	probe_ent->irq = pdev->irq;
-       	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
-	probe_ent->private_data = hpriv;
+	/* prepare host */
+	if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+		pi.flags |= ATA_FLAG_NCQ;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+	if (!host)
+		return -ENOMEM;
+	host->iomap = pcim_iomap_table(pdev);
+	host->private_data = hpriv;
+
+	for (i = 0; i < host->n_ports; i++) {
+		if (hpriv->port_map & (1 << i)) {
+			struct ata_port *ap = host->ports[i];
+			void __iomem *port_mmio = ahci_port_base(ap);
+
+			ap->ioaddr.cmd_addr = port_mmio;
+			ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
+		} else
+			host->ports[i]->ops = &ata_dummy_port_ops;
+	}
 
 	/* initialize adapter */
-	rc = ahci_host_init(probe_ent);
+	rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
 	if (rc)
 		return rc;
 
-	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);
+	rc = ahci_reset_controller(host);
+	if (rc)
+		return rc;
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
+	ahci_init_controller(host);
+	ahci_print_info(host);
 
-	devm_kfree(dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+				 &ahci_sht);
 }
 
 static int __init ahci_init(void)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index d8e7988..92a491d 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -33,35 +33,6 @@ #define DRV_VERSION "0.2.11"
  */
 
 /**
- *	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
  *	@unused: returned device on error
@@ -144,8 +115,9 @@ static struct ata_port_operations generi
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= generic_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_unknown,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b952c58..4a795fd 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -93,7 +93,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"ata_piix"
-#define DRV_VERSION	"2.10ac1"
+#define DRV_VERSION	"2.11"
 
 enum {
 	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
@@ -155,11 +155,11 @@ struct piix_host_priv {
 static int piix_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent);
 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 int ich_pata_cable_detect(struct ata_port *ap);
 
 static unsigned int in_module_init = 1;
 
@@ -305,6 +305,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= piix_pata_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
 
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
@@ -336,8 +337,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= ich_pata_error_handler,
+	.error_handler		= piix_pata_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ich_pata_cable_detect,
 
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
@@ -580,12 +582,13 @@ static const struct ich_laptop ich_lapto
 	/* devid, subvendor, subdev */
 	{ 0x27DF, 0x0005, 0x0280 },	/* ICH7 on Acer 5602WLMi */
 	{ 0x27DF, 0x1025, 0x0110 },	/* ICH7 on Acer 3682WLMi */
+	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
 	/* end marker */
 	{ 0, }
 };
 
 /**
- *	piix_pata_cbl_detect - Probe host controller cable detect info
+ *	ich_pata_cable_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
@@ -595,23 +598,18 @@ static const struct ich_laptop ich_lapto
  *	None (inherited from caller).
  */
 
-static void ich_pata_cbl_detect(struct ata_port *ap)
+static int ich_pata_cable_detect(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	const struct ich_laptop *lap = &ich_laptop[0];
 	u8 tmp, mask;
 
-	/* no 80c support in host controller? */
-	if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
-		goto cbl40;
-
 	/* Check for specials - Acer Aspire 5602WLMi */
 	while (lap->device) {
 		if (lap->device == pdev->device &&
 		    lap->subvendor == pdev->subsystem_vendor &&
 		    lap->subdevice == pdev->subsystem_device) {
-			ap->cbl = ATA_CBL_PATA40_SHORT;
-		    	return;
+			return ATA_CBL_PATA40_SHORT;
 		}
 		lap++;
 	}
@@ -620,32 +618,25 @@ static void ich_pata_cbl_detect(struct a
 	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;
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
 }
 
 /**
  *	piix_pata_prereset - prereset for PATA host controller
  *	@ap: Target port
- *
+ *	@deadline: deadline jiffies for the operation
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
-static int piix_pata_prereset(struct ata_port *ap)
+static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
 {
 	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);
+	return ata_std_prereset(ap, deadline);
 }
 
 static void piix_pata_error_handler(struct ata_port *ap)
@@ -654,31 +645,6 @@ static void piix_pata_error_handler(stru
 			   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]))
-		return -ENOENT;
-	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);
-}
-
 static void piix_sata_error_handler(struct ata_port *ap)
 {
 	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 0abd72d..a795088 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
 
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
 static struct workqueue_struct *ata_wq;
 
 struct workqueue_struct *ata_aux_wq;
@@ -89,6 +89,10 @@ 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_ignore_hpa = 0;
+module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
+MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+
 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)");
@@ -808,6 +812,205 @@ void ata_id_c_string(const u16 *id, unsi
 	*p = '\0';
 }
 
+static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
+{
+	u64 sectors = 0;
+
+	sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+	sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+	sectors |= (tf->hob_lbal & 0xff) << 24;
+	sectors |= (tf->lbah & 0xff) << 16;
+	sectors |= (tf->lbam & 0xff) << 8;
+	sectors |= (tf->lbal & 0xff);
+
+	return ++sectors;
+}
+
+static u64 ata_tf_to_lba(struct ata_taskfile *tf)
+{
+	u64 sectors = 0;
+
+	sectors |= (tf->device & 0x0f) << 24;
+	sectors |= (tf->lbah & 0xff) << 16;
+	sectors |= (tf->lbam & 0xff) << 8;
+	sectors |= (tf->lbal & 0xff);
+
+	return ++sectors;
+}
+
+/**
+ *	ata_read_native_max_address_ext	-	LBA48 native max query
+ *	@dev: Device to query
+ *
+ *	Perform an LBA48 size query upon the device in question. Return the
+ *	actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+{
+	unsigned int err;
+	struct ata_taskfile tf;
+
+	ata_tf_init(dev, &tf);
+
+	tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+	tf.protocol |= ATA_PROT_NODATA;
+	tf.device |= 0x40;
+
+	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	if (err)
+		return 0;
+
+	return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *	ata_read_native_max_address	-	LBA28 native max query
+ *	@dev: Device to query
+ *
+ *	Performa an LBA28 size query upon the device in question. Return the
+ *	actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address(struct ata_device *dev)
+{
+	unsigned int err;
+	struct ata_taskfile tf;
+
+	ata_tf_init(dev, &tf);
+
+	tf.command = ATA_CMD_READ_NATIVE_MAX;
+	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+	tf.protocol |= ATA_PROT_NODATA;
+	tf.device |= 0x40;
+
+	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	if (err)
+		return 0;
+
+	return ata_tf_to_lba(&tf);
+}
+
+/**
+ *	ata_set_native_max_address_ext	-	LBA48 native max set
+ *	@dev: Device to query
+ *
+ *	Perform an LBA48 size set max upon the device in question. Return the
+ *	actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+{
+	unsigned int err;
+	struct ata_taskfile tf;
+
+	new_sectors--;
+
+	ata_tf_init(dev, &tf);
+
+	tf.command = ATA_CMD_SET_MAX_EXT;
+	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+	tf.protocol |= ATA_PROT_NODATA;
+	tf.device |= 0x40;
+
+	tf.lbal = (new_sectors >> 0) & 0xff;
+	tf.lbam = (new_sectors >> 8) & 0xff;
+	tf.lbah = (new_sectors >> 16) & 0xff;
+
+	tf.hob_lbal = (new_sectors >> 24) & 0xff;
+	tf.hob_lbam = (new_sectors >> 32) & 0xff;
+	tf.hob_lbah = (new_sectors >> 40) & 0xff;
+
+	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	if (err)
+		return 0;
+
+	return ata_tf_to_lba48(&tf);
+}
+
+/**
+ *	ata_set_native_max_address	-	LBA28 native max set
+ *	@dev: Device to query
+ *
+ *	Perform an LBA28 size set max upon the device in question. Return the
+ *	actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
+{
+	unsigned int err;
+	struct ata_taskfile tf;
+
+	new_sectors--;
+
+	ata_tf_init(dev, &tf);
+
+	tf.command = ATA_CMD_SET_MAX;
+	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+	tf.protocol |= ATA_PROT_NODATA;
+
+	tf.lbal = (new_sectors >> 0) & 0xff;
+	tf.lbam = (new_sectors >> 8) & 0xff;
+	tf.lbah = (new_sectors >> 16) & 0xff;
+	tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
+
+	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	if (err)
+		return 0;
+
+	return ata_tf_to_lba(&tf);
+}
+
+/**
+ *	ata_hpa_resize		-	Resize a device with an HPA set
+ *	@dev: Device to resize
+ *
+ *	Read the size of an LBA28 or LBA48 disk with HPA features and resize
+ *	it if required to the full size of the media. The caller must check
+ *	the drive has the HPA feature set enabled.
+ */
+
+static u64 ata_hpa_resize(struct ata_device *dev)
+{
+	u64 sectors = dev->n_sectors;
+	u64 hpa_sectors;
+	
+	if (ata_id_has_lba48(dev->id))
+		hpa_sectors = ata_read_native_max_address_ext(dev);
+	else
+		hpa_sectors = ata_read_native_max_address(dev);
+
+	/* if no hpa, both should be equal */
+	ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, "
+				"hpa_sectors = %lld\n",
+		__FUNCTION__, (long long)sectors, (long long)hpa_sectors);
+
+	if (hpa_sectors > sectors) {
+		ata_dev_printk(dev, KERN_INFO,
+			"Host Protected Area detected:\n"
+			"\tcurrent size: %lld sectors\n"
+			"\tnative size: %lld sectors\n",
+			(long long)sectors, (long long)hpa_sectors);
+
+		if (ata_ignore_hpa) {
+			if (ata_id_has_lba48(dev->id))
+				hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
+			else
+				hpa_sectors = ata_set_native_max_address(dev,
+								hpa_sectors);
+
+			if (hpa_sectors) {
+				ata_dev_printk(dev, KERN_INFO, "native size "
+					"increased to %lld sectors\n",
+					(long long)hpa_sectors);
+				return hpa_sectors;
+			}
+		}
+	}
+	return sectors;
+}
+
 static u64 ata_id_n_sectors(const u16 *id)
 {
 	if (ata_id_has_lba(id)) {
@@ -1270,12 +1473,16 @@ unsigned ata_exec_internal_sg(struct ata
 	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;
+	/* perform minimal error analysis */
+	if (qc->flags & ATA_QCFLAG_FAILED) {
+		if (qc->result_tf.command & (ATA_ERR | ATA_DF))
+			qc->err_mask |= AC_ERR_DEV;
+
+		if (!qc->err_mask)
+			qc->err_mask |= AC_ERR_OTHER;
+
+		if (qc->err_mask & ~AC_ERR_OTHER)
+			qc->err_mask &= ~AC_ERR_OTHER;
 	}
 
 	/* finish up */
@@ -1379,30 +1586,44 @@ unsigned int ata_do_simple_cmd(struct at
  *	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)
+	/* Controller doesn't support  IORDY. Probably a pointless check
+	   as the caller should know this */
+	if (adev->ap->flags & ATA_FLAG_NO_IORDY)
 		return 0;
-	if (speed > 2)
+	/* PIO3 and higher it is mandatory */
+	if (adev->pio_mode > XFER_PIO_2)
+		return 1;
+	/* We turn it on when possible */
+	if (ata_id_has_iordy(adev->id))
 		return 1;
+	return 0;
+}
 
+/**
+ *	ata_pio_mask_no_iordy	-	Return the non IORDY mask
+ *	@adev: ATA device
+ *
+ *	Compute the highest mode possible if we are not using iordy. Return
+ *	-1 if no iordy mode is available.
+ */
+ 
+static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
+{
 	/* 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];
+		u16 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 3 << ATA_SHIFT_PIO;
+			return 7 << ATA_SHIFT_PIO;
 		}
 	}
-	return 0;
+	return 3 << ATA_SHIFT_PIO;
 }
 
 /**
@@ -1431,13 +1652,13 @@ int ata_dev_read_id(struct ata_device *d
 	struct ata_taskfile tf;
 	unsigned int err_mask = 0;
 	const char *reason;
+	int tried_spinup = 0;
 	int rc;
 
 	if (ata_msg_ctl(ap))
 		ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
 
 	ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
  retry:
 	ata_tf_init(dev, &tf);
 
@@ -1494,6 +1715,32 @@ int ata_dev_read_id(struct ata_device *d
 			goto err_out;
 	}
 
+	if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+		tried_spinup = 1;
+		/*
+		 * Drive powered-up in standby mode, and requires a specific
+		 * SET_FEATURES spin-up subcommand before it will accept
+		 * anything other than the original IDENTIFY command.
+		 */
+		ata_tf_init(dev, &tf);
+		tf.command = ATA_CMD_SET_FEATURES;
+		tf.feature = SETFEATURES_SPINUP;
+		tf.protocol = ATA_PROT_NODATA;
+		tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+		err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+		if (err_mask) {
+			rc = -EIO;
+			reason = "SPINUP failed";
+			goto err_out;
+		}
+		/*
+		 * If the drive initially returned incomplete IDENTIFY info,
+		 * we now must reissue the IDENTIFY command.
+		 */
+		if (id[2] == 0x37c8)
+			goto retry;
+	}
+
 	if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
 		/*
 		 * The exact sequence expected by certain pre-ATA4 drives is:
@@ -1560,20 +1807,6 @@ static void ata_dev_config_ncq(struct at
 		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
@@ -1658,6 +1891,7 @@ int ata_dev_configure(struct ata_device 
 			snprintf(revbuf, 7, "ATA-%d",  ata_id_major_version(id));
 
 		dev->n_sectors = ata_id_n_sectors(id);
+		dev->n_sectors_boot = dev->n_sectors;
 
 		/* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
 		ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -1684,6 +1918,9 @@ int ata_dev_configure(struct ata_device 
 					dev->flags |= ATA_DFLAG_FLUSH_EXT;
 			}
 
+			if (ata_id_hpa_enabled(dev->id))
+				dev->n_sectors = ata_hpa_resize(dev);
+
 			/* config NCQ */
 			ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
@@ -1773,8 +2010,6 @@ int ata_dev_configure(struct ata_device 
 		}
 	}
 
-	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)
@@ -1785,14 +2020,15 @@ int ata_dev_configure(struct ata_device 
 	}
 
 	if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128)
-		dev->max_sectors = min(ATA_MAX_SECTORS_128, dev->max_sectors);
+		dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
+					 dev->max_sectors);
 
 	/* limit ATAPI DMA to R/W commands only */
 	if (ata_device_blacklisted(dev) & ATA_HORKAGE_DMA_RW_ONLY)
 		dev->horkage |= ATA_HORKAGE_DMA_RW_ONLY;
 
 	if (ap->ops->dev_config)
-		ap->ops->dev_config(ap, dev);
+		ap->ops->dev_config(dev);
 
 	if (ata_msg_probe(ap))
 		ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
@@ -1807,6 +2043,56 @@ err_out_nosup:
 }
 
 /**
+ *	ata_cable_40wire	-	return 40 wire cable type
+ *	@ap: port
+ *
+ *	Helper method for drivers which want to hardwire 40 wire cable
+ *	detection.
+ */
+
+int ata_cable_40wire(struct ata_port *ap)
+{
+	return ATA_CBL_PATA40;
+}
+
+/**
+ *	ata_cable_80wire	-	return 80 wire cable type
+ *	@ap: port
+ *
+ *	Helper method for drivers which want to hardwire 80 wire cable
+ *	detection.
+ */
+
+int ata_cable_80wire(struct ata_port *ap)
+{
+	return ATA_CBL_PATA80;
+}
+
+/**
+ *	ata_cable_unknown	-	return unknown PATA cable.
+ *	@ap: port
+ *
+ *	Helper method for drivers which have no PATA cable detection.
+ */
+
+int ata_cable_unknown(struct ata_port *ap)
+{
+	return ATA_CBL_PATA_UNK;
+}
+
+/**
+ *	ata_cable_sata	-	return SATA cable type
+ *	@ap: port
+ *
+ *	Helper method for drivers which have SATA cables
+ */
+
+int ata_cable_sata(struct ata_port *ap)
+{
+	return ATA_CBL_SATA;
+}
+
+/**
  *	ata_bus_probe - Reset and probe ATA bus
  *	@ap: Bus to probe
  *
@@ -1876,6 +2162,10 @@ int ata_bus_probe(struct ata_port *ap)
 			goto fail;
 	}
 
+	/* Now ask for the cable type as PDIAG- should have been released */
+	if (ap->ops->cable_detect)
+		ap->cbl = ap->ops->cable_detect(ap);
+
 	/* After the identify sequence we can now set up the devices. We do
 	   this in the normal order so that the user doesn't get confused */
 
@@ -1958,7 +2248,7 @@ void ata_port_probe(struct ata_port *ap)
  *	LOCKING:
  *	None.
  */
-static void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_port *ap)
 {
 	u32 sstatus, scontrol, tmp;
 
@@ -2352,6 +2642,12 @@ int ata_timing_compute(struct ata_device
 		t->active += (t->cycle - (t->active + t->recover)) / 2;
 		t->recover = t->cycle - t->active;
 	}
+	
+	/* In a few cases quantisation may produce enough errors to
+	   leave t->cycle too low for the sum of active and recovery
+	   if so we must correct this */
+	if (t->active + t->recover > t->cycle)
+		t->cycle = t->active + t->recover;
 
 	return 0;
 }
@@ -2481,12 +2777,13 @@ static int ata_dev_set_mode(struct ata_d
 }
 
 /**
- *	ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *	ata_do_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
+ *	Standard implementation of the function used to tune and set
+ *	ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
+ *	ata_dev_set_mode() fails, pointer to the failing device is
  *	returned in @r_failed_dev.
  *
  *	LOCKING:
@@ -2495,14 +2792,12 @@ static int ata_dev_set_mode(struct ata_d
  *	RETURNS:
  *	0 on success, negative errno otherwise
  */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+
+int ata_do_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)
-		return ap->ops->set_mode(ap, r_failed_dev);
 
 	/* step 1: calculate xfer_mask */
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2587,6 +2882,29 @@ int ata_set_mode(struct ata_port *ap, st
 }
 
 /**
+ *	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)
+{
+	/* has private set_mode? */
+	if (ap->ops->set_mode)
+		return ap->ops->set_mode(ap, r_failed_dev);
+	return ata_do_set_mode(ap, r_failed_dev);
+}
+
+/**
  *	ata_tf_to_host - issue ATA taskfile to host controller
  *	@ap: port to which command is being issued
  *	@tf: ATA taskfile register set
@@ -2661,23 +2979,71 @@ int ata_busy_sleep(struct ata_port *ap,
 	return 0;
 }
 
-static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+/**
+ *	ata_wait_ready - sleep until BSY clears, or timeout
+ *	@ap: port containing status register to be polled
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	Sleep until ATA Status register bit BSY clears, or timeout
+ *	occurs.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
+{
+	unsigned long start = jiffies;
+	int warned = 0;
+
+	while (1) {
+		u8 status = ata_chk_status(ap);
+		unsigned long now = jiffies;
+
+		if (!(status & ATA_BUSY))
+			return 0;
+		if (status == 0xff)
+			return -ENODEV;
+		if (time_after(now, deadline))
+			return -EBUSY;
+
+		if (!warned && time_after(now, start + 5 * HZ) &&
+		    (deadline - now > 3 * HZ)) {
+			ata_port_printk(ap, KERN_WARNING,
+				"port is slow to respond, please be patient "
+				"(Status 0x%x)\n", status);
+			warned = 1;
+		}
+
+		msleep(50);
+	}
+}
+
+static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
+			      unsigned long deadline)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int dev0 = devmask & (1 << 0);
 	unsigned int dev1 = devmask & (1 << 1);
-	unsigned long timeout;
+	int rc, ret = 0;
 
 	/* 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 (dev0) {
+		rc = ata_wait_ready(ap, deadline);
+		if (rc) {
+			if (rc != -ENODEV)
+				return rc;
+			ret = rc;
+		}
+	}
 
 	/* 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;
 
@@ -2686,14 +3052,18 @@ static void ata_bus_post_reset(struct at
 		lbal = ioread8(ioaddr->lbal_addr);
 		if ((nsect == 1) && (lbal == 1))
 			break;
-		if (time_after(jiffies, timeout)) {
-			dev1 = 0;
-			break;
-		}
+		if (time_after(jiffies, deadline))
+			return -EBUSY;
 		msleep(50);	/* give drive a breather */
 	}
-	if (dev1)
-		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+	if (dev1) {
+		rc = ata_wait_ready(ap, deadline);
+		if (rc) {
+			if (rc != -ENODEV)
+				return rc;
+			ret = rc;
+		}
+	}
 
 	/* is all this really necessary? */
 	ap->ops->dev_select(ap, 0);
@@ -2701,10 +3071,12 @@ static void ata_bus_post_reset(struct at
 		ap->ops->dev_select(ap, 1);
 	if (dev0)
 		ap->ops->dev_select(ap, 0);
+
+	return ret;
 }
 
-static unsigned int ata_bus_softreset(struct ata_port *ap,
-				      unsigned int devmask)
+static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+			     unsigned long deadline)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
@@ -2734,11 +3106,9 @@ static unsigned int ata_bus_softreset(st
 	 * pulldown resistor.
 	 */
 	if (ata_check_status(ap) == 0xFF)
-		return 0;
-
-	ata_bus_post_reset(ap, devmask);
+		return -ENODEV;
 
-	return 0;
+	return ata_bus_post_reset(ap, devmask, deadline);
 }
 
 /**
@@ -2767,6 +3137,7 @@ void ata_bus_reset(struct ata_port *ap)
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	u8 err;
 	unsigned int dev0, dev1 = 0, devmask = 0;
+	int rc;
 
 	DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no);
 
@@ -2788,9 +3159,11 @@ void ata_bus_reset(struct ata_port *ap)
 	ap->ops->dev_select(ap, 0);
 
 	/* issue bus reset */
-	if (ap->flags & ATA_FLAG_SRST)
-		if (ata_bus_softreset(ap, devmask))
+	if (ap->flags & ATA_FLAG_SRST) {
+		rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ);
+		if (rc && rc != -ENODEV)
 			goto err_out;
+	}
 
 	/*
 	 * determine by signature whether we have ATA or ATAPI devices
@@ -2832,29 +3205,37 @@ err_out:
  *	sata_phy_debounce - debounce SATA phy status
  *	@ap: ATA port to debounce SATA phy status for
  *	@params: timing parameters { interval, duratinon, timeout } in msec
+ *	@deadline: deadline jiffies for the operation
  *
  *	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
+ *	beginning of the stable state.  Because DET gets stuck at 1 on
+ *	some controllers after hot unplugging, this functions waits
  *	until timeout then returns 0 if DET is stable at 1.
  *
+ *	@timeout is further limited by @deadline.  The sooner of the
+ *	two is used.
+ *
  *	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)
+int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
+		      unsigned long deadline)
 {
 	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;
+	unsigned long duration = msecs_to_jiffies(params[1]);
+	unsigned long last_jiffies, t;
 	u32 last, cur;
 	int rc;
 
+	t = jiffies + msecs_to_jiffies(params[2]);
+	if (time_before(t, deadline))
+		deadline = t;
+
 	if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
 		return rc;
 	cur &= 0xf;
@@ -2870,7 +3251,7 @@ int sata_phy_debounce(struct ata_port *a
 
 		/* DET stable? */
 		if (cur == last) {
-			if (cur == 1 && time_before(jiffies, timeout))
+			if (cur == 1 && time_before(jiffies, deadline))
 				continue;
 			if (time_after(jiffies, last_jiffies + duration))
 				return 0;
@@ -2881,8 +3262,8 @@ int sata_phy_debounce(struct ata_port *a
 		last = cur;
 		last_jiffies = jiffies;
 
-		/* check timeout */
-		if (time_after(jiffies, timeout))
+		/* check deadline */
+		if (time_after(jiffies, deadline))
 			return -EBUSY;
 	}
 }
@@ -2891,6 +3272,7 @@ int sata_phy_debounce(struct ata_port *a
  *	sata_phy_resume - resume SATA phy
  *	@ap: ATA port to resume SATA phy for
  *	@params: timing parameters { interval, duratinon, timeout } in msec
+ *	@deadline: deadline jiffies for the operation
  *
  *	Resume SATA phy of @ap and debounce it.
  *
@@ -2900,7 +3282,8 @@ int sata_phy_debounce(struct ata_port *a
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
+int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
+		    unsigned long deadline)
 {
 	u32 scontrol;
 	int rc;
@@ -2918,43 +3301,19 @@ int sata_phy_resume(struct ata_port *ap,
 	 */
 	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);
+	return sata_phy_debounce(ap, params, deadline);
 }
 
 /**
  *	ata_std_prereset - prepare for reset
  *	@ap: ATA port to be reset
+ *	@deadline: deadline jiffies for the operation
  *
- *	@ap is about to be reset.  Initialize it.
+ *	@ap is about to be reset.  Initialize it.  Failure from
+ *	prereset makes libata abort whole reset sequence and give up
+ *	that port, so prereset should be best-effort.  It does its
+ *	best to prepare for reset sequence but if things go wrong, it
+ *	should just whine, not fail.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -2962,41 +3321,41 @@ static void ata_wait_spinup(struct ata_p
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_prereset(struct ata_port *ap)
+int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
 
-	/* handle link resume & hotplug spinup */
+	/* handle link resume */
 	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 */
+		rc = sata_phy_resume(ap, timing, deadline);
+		/* whine about phy resume failure but proceed */
+		if (rc && rc != -EOPNOTSUPP)
 			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);
+	if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+		rc = ata_wait_ready(ap, deadline);
+		if (rc) {
+			ata_port_printk(ap, KERN_WARNING, "device not ready "
+					"(errno=%d), forcing hardreset\n", rc);
+			ehc->i.action |= ATA_EH_HARDRESET;
+		}
+	}
 
 	return 0;
 }
@@ -3005,6 +3364,7 @@ int ata_std_prereset(struct ata_port *ap
  *	ata_std_softreset - reset host port via ATA SRST
  *	@ap: port to reset
  *	@classes: resulting classes of attached devices
+ *	@deadline: deadline jiffies for the operation
  *
  *	Reset host port using ATA SRST.
  *
@@ -3014,10 +3374,12 @@ int ata_std_prereset(struct ata_port *ap
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
+int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+		      unsigned long deadline)
 {
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
-	unsigned int devmask = 0, err_mask;
+	unsigned int devmask = 0;
+	int rc;
 	u8 err;
 
 	DPRINTK("ENTER\n");
@@ -3038,11 +3400,11 @@ int ata_std_softreset(struct ata_port *a
 
 	/* 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;
+	rc = ata_bus_softreset(ap, devmask, deadline);
+	/* if link is occupied, -ENODEV too is an error */
+	if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
+		ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+		return rc;
 	}
 
 	/* determine by signature whether we have ATA or ATAPI devices */
@@ -3059,6 +3421,7 @@ int ata_std_softreset(struct ata_port *a
  *	sata_port_hardreset - reset port via SATA phy reset
  *	@ap: port to reset
  *	@timing: timing parameters { interval, duratinon, timeout } in msec
+ *	@deadline: deadline jiffies for the operation
  *
  *	SATA phy-reset host port using DET bits of SControl register.
  *
@@ -3068,7 +3431,8 @@ int ata_std_softreset(struct ata_port *a
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
+int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+			unsigned long deadline)
 {
 	u32 scontrol;
 	int rc;
@@ -3107,7 +3471,7 @@ int sata_port_hardreset(struct ata_port 
 	msleep(1);
 
 	/* bring phy back */
-	rc = sata_phy_resume(ap, timing);
+	rc = sata_phy_resume(ap, timing, deadline);
  out:
 	DPRINTK("EXIT, rc=%d\n", rc);
 	return rc;
@@ -3117,6 +3481,7 @@ int sata_port_hardreset(struct ata_port 
  *	sata_std_hardreset - reset host port via SATA phy reset
  *	@ap: port to reset
  *	@class: resulting class of attached device
+ *	@deadline: deadline jiffies for the operation
  *
  *	SATA phy-reset host port using DET bits of SControl register,
  *	wait for !BSY and classify the attached device.
@@ -3127,7 +3492,8 @@ int sata_port_hardreset(struct ata_port 
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
+int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+		       unsigned long deadline)
 {
 	const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
 	int rc;
@@ -3135,7 +3501,7 @@ int sata_std_hardreset(struct ata_port *
 	DPRINTK("ENTER\n");
 
 	/* do hardreset */
-	rc = sata_port_hardreset(ap, timing);
+	rc = sata_port_hardreset(ap, timing, deadline);
 	if (rc) {
 		ata_port_printk(ap, KERN_ERR,
 				"COMRESET failed (errno=%d)\n", rc);
@@ -3152,10 +3518,12 @@ int sata_std_hardreset(struct ata_port *
 	/* wait a while before checking status, see SRST for more info */
 	msleep(150);
 
-	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+	rc = ata_wait_ready(ap, deadline);
+	/* link occupied, -ENODEV too is an error */
+	if (rc) {
 		ata_port_printk(ap, KERN_ERR,
-				"COMRESET failed (device not ready)\n");
-		return -EIO;
+				"COMRESET failed (errno=%d)\n", rc);
+		return rc;
 	}
 
 	ap->ops->dev_select(ap, 0);	/* probably unnecessary */
@@ -3267,6 +3635,11 @@ static int ata_dev_same_device(struct at
 			       "%llu != %llu\n",
 			       (unsigned long long)dev->n_sectors,
 			       (unsigned long long)new_n_sectors);
+		/* Are we the boot time size - if so we appear to be the
+		   same disk at this point and our HPA got reapplied */
+		if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors 
+		    && ata_id_hpa_enabled(new_id))
+			return 1;
 		return 0;
 	}
 
@@ -3441,19 +3814,7 @@ static void ata_dev_xfermask(struct ata_
 	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);
-	/* Apply drive side cable rule. Unknown or 80 pin cables reported
-	 * host side are checked drive side as well. Cases where we know a
-	 * 40wire cable is used safely for 80 are not checked here.
-	 */
-        if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80))
-		xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
-
-
+	/* drive modes available */
 	xfer_mask &= ata_pack_xfermask(dev->pio_mask,
 				       dev->mwdma_mask, dev->udma_mask);
 	xfer_mask &= ata_id_xfermask(dev->id);
@@ -3482,8 +3843,30 @@ static void ata_dev_xfermask(struct ata_
 			       "other device, disabling DMA\n");
 	}
 
+	if (ap->flags & ATA_FLAG_NO_IORDY)
+		xfer_mask &= ata_pio_mask_no_iordy(dev);
+
 	if (ap->ops->mode_filter)
-		xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+		xfer_mask = ap->ops->mode_filter(dev, xfer_mask);
+
+	/* Apply cable rule here.  Don't apply it early because when
+	 * we handle hot plug the cable type can itself change.
+	 * Check this last so that we know if the transfer rate was
+	 * solely limited by the cable.
+	 * Unknown or 80 wire cables reported host side are checked
+	 * drive side as well. Cases where we know a 40wire cable
+	 * is used safely for 80 are not checked here.
+	 */
+	if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
+		/* UDMA/44 or higher would be available */
+		if((ap->cbl == ATA_CBL_PATA40) ||
+   		    (ata_drive_40wire(dev->id) &&
+		     (ap->cbl == ATA_CBL_PATA_UNK ||
+                     ap->cbl == ATA_CBL_PATA80))) {
+		      	ata_dev_printk(dev, KERN_WARNING,
+				 "limited to UDMA/33 due to 40-wire cable\n");
+			xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
+		}
 
 	ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
 			    &dev->mwdma_mask, &dev->udma_mask);
@@ -4022,10 +4405,10 @@ void ata_data_xfer_noirq(struct ata_devi
 
 
 /**
- *	ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+ *	ata_pio_sector - Transfer a sector of data.
  *	@qc: Command on going
  *
- *	Transfer ATA_SECT_SIZE of data from/to the ATA device.
+ *	Transfer qc->sect_size bytes of data from/to the ATA device.
  *
  *	LOCKING:
  *	Inherited from caller.
@@ -4040,7 +4423,7 @@ static void ata_pio_sector(struct ata_qu
 	unsigned int offset;
 	unsigned char *buf;
 
-	if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE)
+	if (qc->curbytes == qc->nbytes - qc->sect_size)
 		ap->hsm_task_state = HSM_ST_LAST;
 
 	page = sg[qc->cursg].page;
@@ -4060,17 +4443,17 @@ static void ata_pio_sector(struct ata_qu
 		buf = kmap_atomic(page, KM_IRQ0);
 
 		/* do the actual data transfer */
-		ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+		ap->ops->data_xfer(qc->dev, buf + offset, qc->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);
+		ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
 	}
 
-	qc->curbytes += ATA_SECT_SIZE;
-	qc->cursg_ofs += ATA_SECT_SIZE;
+	qc->curbytes += qc->sect_size;
+	qc->cursg_ofs += qc->sect_size;
 
 	if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
 		qc->cursg++;
@@ -4079,10 +4462,10 @@ static void ata_pio_sector(struct ata_qu
 }
 
 /**
- *	ata_pio_sectors - Transfer one or many 512-byte sectors.
+ *	ata_pio_sectors - Transfer one or many sectors.
  *	@qc: Command on going
  *
- *	Transfer one or many ATA_SECT_SIZE of data from/to the
+ *	Transfer one or many sectors of data from/to the
  *	ATA device for the DRQ request.
  *
  *	LOCKING:
@@ -4097,7 +4480,7 @@ static void ata_pio_sectors(struct ata_q
 
 		WARN_ON(qc->dev->multi_count == 0);
 
-		nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE,
+		nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
 			    qc->dev->multi_count);
 		while (nsect--)
 			ata_pio_sector(qc);
@@ -5577,42 +5960,35 @@ void ata_dev_init(struct ata_device *dev
 }
 
 /**
- *	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
+ *	ata_port_alloc - allocate and initialize basic ATA port resources
+ *	@host: ATA host this allocated port belongs to
  *
- *	Initialize a new ata_port structure.
+ *	Allocate and initialize basic ATA port resources.
+ *
+ *	RETURNS:
+ *	Allocate ATA port on success, NULL on failure.
  *
  *	LOCKING:
- *	Inherited from caller.
+ *	Inherited from calling layer (may sleep).
  */
-void ata_port_init(struct ata_port *ap, struct ata_host *host,
-		   const struct ata_probe_ent *ent, unsigned int port_no)
+struct ata_port *ata_port_alloc(struct ata_host *host)
 {
+	struct ata_port *ap;
 	unsigned int i;
 
+	DPRINTK("ENTER\n");
+
+	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+	if (!ap)
+		return NULL;
+
 	ap->lock = &host->lock;
 	ap->flags = ATA_FLAG_DISABLED;
-	ap->print_id = ata_print_id++;
+	ap->print_id = -1;
 	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->dev = host->dev;
+
 	ap->hw_sata_spd_limit = UINT_MAX;
 	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
@@ -5632,10 +6008,7 @@ #endif
 	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];
@@ -5648,100 +6021,209 @@ #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
 	ap->stats.idle_irq = 1;
 #endif
+	return ap;
+}
+
+static void ata_host_release(struct device *gendev, void *res)
+{
+	struct ata_host *host = dev_get_drvdata(gendev);
+	int i;
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
 
-	memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+		if (!ap)
+			continue;
+
+		if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
+			ap->ops->port_stop(ap);
+	}
+
+	if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
+		host->ops->host_stop(host);
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		if (!ap)
+			continue;
+
+		if (ap->scsi_host)
+			scsi_host_put(ap->scsi_host);
+
+		kfree(ap);
+		host->ports[i] = NULL;
+	}
+
+	dev_set_drvdata(gendev, NULL);
 }
 
 /**
- *	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
+ *	ata_host_alloc - allocate and init basic ATA host resources
+ *	@dev: generic device this host is associated with
+ *	@max_ports: maximum number of ATA ports associated with this host
+ *
+ *	Allocate and initialize basic ATA host resources.  LLD calls
+ *	this function to allocate a host, initializes it fully and
+ *	attaches it using ata_host_register().
  *
- *	Initialize SCSI host @shost associated with ATA port @ap.
+ *	@max_ports ports are allocated and host->n_ports is
+ *	initialized to @max_ports.  The caller is allowed to decrease
+ *	host->n_ports before calling ata_host_register().  The unused
+ *	ports will be automatically freed on registration.
+ *
+ *	RETURNS:
+ *	Allocate ATA host on success, NULL on failure.
  *
  *	LOCKING:
- *	Inherited from caller.
+ *	Inherited from calling layer (may sleep).
  */
-static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
 {
-	ap->scsi_host = shost;
+	struct ata_host *host;
+	size_t sz;
+	int i;
+
+	DPRINTK("ENTER\n");
+
+	if (!devres_open_group(dev, NULL, GFP_KERNEL))
+		return NULL;
 
-	shost->unique_id = ap->print_id;
-	shost->max_id = 16;
-	shost->max_lun = 1;
-	shost->max_channel = 1;
-	shost->max_cmd_len = 12;
+	/* alloc a container for our list of ATA ports (buses) */
+	sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
+	/* alloc a container for our list of ATA ports (buses) */
+	host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+	if (!host)
+		goto err_out;
+
+	devres_add(dev, host);
+	dev_set_drvdata(dev, host);
+
+	spin_lock_init(&host->lock);
+	host->dev = dev;
+	host->n_ports = max_ports;
+
+	/* allocate ports bound to this host */
+	for (i = 0; i < max_ports; i++) {
+		struct ata_port *ap;
+
+		ap = ata_port_alloc(host);
+		if (!ap)
+			goto err_out;
+
+		ap->port_no = i;
+		host->ports[i] = ap;
+	}
+
+	devres_remove_group(dev, NULL);
+	return host;
+
+ err_out:
+	devres_release_group(dev, NULL);
+	return NULL;
 }
 
 /**
- *	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.
+ *	ata_host_alloc_pinfo - alloc host and init with port_info array
+ *	@dev: generic device this host is associated with
+ *	@ppi: array of ATA port_info to initialize host with
+ *	@n_ports: number of ATA ports attached to this host
  *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
+ *	Allocate ATA host and initialize with info from @ppi.  If NULL
+ *	terminated, @ppi may contain fewer entries than @n_ports.  The
+ *	last entry will be used for the remaining ports.
  *
  *	RETURNS:
- *	New ata_port on success, for NULL on error.
+ *	Allocate ATA host on success, NULL on failure.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
  */
-static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
-				      struct ata_host *host,
-				      unsigned int port_no)
+struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+				      const struct ata_port_info * const * ppi,
+				      int n_ports)
 {
-	struct Scsi_Host *shost;
-	struct ata_port *ap;
-
-	DPRINTK("ENTER\n");
+	const struct ata_port_info *pi;
+	struct ata_host *host;
+	int i, j;
 
-	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);
+	host = ata_host_alloc(dev, n_ports);
+	if (!host)
 		return NULL;
-	}
 
-	shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
-	if (!shost)
-		return NULL;
+	for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
 
-	shost->transportt = &ata_scsi_transport_template;
+		if (ppi[j])
+			pi = ppi[j++];
 
-	ap = ata_shost_to_port(shost);
+		ap->pio_mask = pi->pio_mask;
+		ap->mwdma_mask = pi->mwdma_mask;
+		ap->udma_mask = pi->udma_mask;
+		ap->flags |= pi->flags;
+		ap->ops = pi->port_ops;
 
-	ata_port_init(ap, host, ent, port_no);
-	ata_port_init_shost(ap, shost);
+		if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
+			host->ops = pi->port_ops;
+		if (!host->private_data && pi->private_data)
+			host->private_data = pi->private_data;
+	}
 
-	return ap;
+	return host;
 }
 
-static void ata_host_release(struct device *gendev, void *res)
+/**
+ *	ata_host_start - start and freeze ports of an ATA host
+ *	@host: ATA host to start ports for
+ *
+ *	Start and then freeze ports of @host.  Started status is
+ *	recorded in host->flags, so this function can be called
+ *	multiple times.  Ports are guaranteed to get started only
+ *	once.  If host->ops isn't initialized yet, its set to the
+ *	first non-dummy port ops.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 if all ports are started successfully, -errno otherwise.
+ */
+int ata_host_start(struct ata_host *host)
 {
-	struct ata_host *host = dev_get_drvdata(gendev);
-	int i;
+	int i, rc;
+
+	if (host->flags & ATA_HOST_STARTED)
+		return 0;
 
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
-		if (ap && ap->ops->port_stop)
-			ap->ops->port_stop(ap);
+		if (!host->ops && !ata_port_is_dummy(ap))
+			host->ops = ap->ops;
+
+		if (ap->ops->port_start) {
+			rc = ap->ops->port_start(ap);
+			if (rc) {
+				ata_port_printk(ap, KERN_ERR, "failed to "
+						"start port (errno=%d)\n", rc);
+				goto err_out;
+			}
+		}
+
+		ata_eh_freeze_port(ap);
 	}
 
-	if (host->ops->host_stop)
-		host->ops->host_stop(host);
+	host->flags |= ATA_HOST_STARTED;
+	return 0;
 
-	for (i = 0; i < host->n_ports; i++) {
+ err_out:
+	while (--i >= 0) {
 		struct ata_port *ap = host->ports[i];
 
-		if (ap)
-			scsi_host_put(ap->scsi_host);
-
-		host->ports[i] = NULL;
+		if (ap->ops->port_stop)
+			ap->ops->port_stop(ap);
 	}
-
-	dev_set_drvdata(gendev, NULL);
+	return rc;
 }
 
 /**
@@ -5755,7 +6237,7 @@ static void ata_host_release(struct devi
  *	PCI/etc. bus probe sem.
  *
  */
-
+/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
 		   unsigned long flags, const struct ata_port_operations *ops)
 {
@@ -5766,155 +6248,95 @@ void ata_host_init(struct ata_host *host
 }
 
 /**
- *	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.
+ *	ata_host_register - register initialized ATA host
+ *	@host: ATA host to register
+ *	@sht: template for SCSI host
  *
- *	This function requests irqs, probes the ATA bus, and probes
- *	the SCSI bus.
+ *	Register initialized ATA host.  @host is allocated using
+ *	ata_host_alloc() and fully initialized by LLD.  This function
+ *	starts ports, registers @host with ATA and SCSI layers and
+ *	probe registered devices.
  *
  *	LOCKING:
- *	PCI/etc. bus probe sem.
+ *	Inherited from calling layer (may sleep).
  *
  *	RETURNS:
- *	Number of ports registered.  Zero on error (no ports registered).
+ *	0 on success, -errno otherwise.
  */
-int ata_device_add(const struct ata_probe_ent *ent)
+int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
 {
-	unsigned int i;
-	struct device *dev = ent->dev;
-	struct ata_host *host;
-	int rc;
-
-	DPRINTK("ENTER\n");
+	int i, rc;
 
-	if (ent->irq == 0) {
-		dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
-		return 0;
+	/* host must have been started */
+	if (!(host->flags & ATA_HOST_STARTED)) {
+		dev_printk(KERN_ERR, host->dev,
+			   "BUG: trying to register unstarted host\n");
+		WARN_ON(1);
+		return -EINVAL;
 	}
 
-	if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
-		return 0;
+	/* Blow away unused ports.  This happens when LLD can't
+	 * determine the exact number of ports to allocate at
+	 * allocation time.
+	 */
+	for (i = host->n_ports; host->ports[i]; i++)
+		kfree(host->ports[i]);
 
-	/* alloc a container for our list of ATA ports (buses) */
-	host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
-			    (ent->n_ports * sizeof(void *)), GFP_KERNEL);
-	if (!host)
-		goto err_out;
-	devres_add(dev, host);
-	dev_set_drvdata(dev, host);
+	/* give ports names and add SCSI hosts */
+	for (i = 0; i < host->n_ports; i++)
+		host->ports[i]->print_id = ata_print_id++;
 
-	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->iomap = ent->iomap;
-	host->private_data = ent->private_data;
+	rc = ata_scsi_add_hosts(host, sht);
+	if (rc)
+		return rc;
 
-	/* register each port bound to this device */
+	/* set cable, sata_spd_limit and report */
 	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;
+		struct ata_port *ap = host->ports[i];
+		int irq_line;
+		u32 scontrol;
+		unsigned long xfer_mask;
 
-		/* dummy? */
-		if (ent->dummy_port_mask & (1 << i)) {
-			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
-			ap->ops = &ata_dummy_port_ops;
-			continue;
-		}
+		/* set SATA cable type if still unset */
+		if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA))
+			ap->cbl = ATA_CBL_SATA;
 
-		/* start port */
-		rc = ap->ops->port_start(ap);
-		if (rc) {
-			host->ports[i] = NULL;
-			scsi_host_put(ap->scsi_host);
-			goto err_out;
+		/* 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;
 
-		/* Report the secondary IRQ for second channel legacy */
-		if (i == 1 && ent->irq2)
-			irq_line = ent->irq2;
+		/* report the secondary IRQ for second channel legacy */
+		irq_line = host->irq;
+		if (i == 1 && host->irq2)
+			irq_line = host->irq2;
 
-		xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
-				(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
-				(ap->pio_mask << ATA_SHIFT_PIO);
+		xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+					      ap->udma_mask);
 
 		/* print per-port info to dmesg */
-		ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-				"ctl 0x%p bmdma 0x%p 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);
-
-		/* freeze port before requesting IRQ */
-		ata_eh_freeze_port(ap);
-	}
-
-	/* obtain irq, that may be shared between channels */
-	rc = devm_request_irq(dev, 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 = devm_request_irq(dev, 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;
-		}
+		if (!ata_port_is_dummy(ap))
+			ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+					"ctl 0x%p bmdma 0x%p irq %d\n",
+					ap->cbl == ATA_CBL_SATA ? 'S' : 'P',
+					ata_mode_string(xfer_mask),
+					ap->ioaddr.cmd_addr,
+					ap->ioaddr.ctl_addr,
+					ap->ioaddr.bmdma_addr,
+					irq_line);
+		else
+			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
 	}
 
-	/* resource acquisition complete */
-	devres_remove_group(dev, ata_device_add);
-
 	/* 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
-			 */
-		}
-
+		/* probe */
 		if (ap->ops->error_handler) {
 			struct ata_eh_info *ehi = &ap->eh_info;
 			unsigned long flags;
@@ -5959,16 +6381,52 @@ int ata_device_add(const struct ata_prob
 		ata_scsi_scan_host(ap);
 	}
 
-	VPRINTK("EXIT, returning %u\n", ent->n_ports);
-	return ent->n_ports; /* success */
-
- err_out:
-	devres_release_group(dev, ata_device_add);
-	VPRINTK("EXIT, returning %d\n", rc);
 	return 0;
 }
 
 /**
+ *	ata_host_activate - start host, request IRQ and register it
+ *	@host: target ATA host
+ *	@irq: IRQ to request
+ *	@irq_handler: irq_handler used when requesting IRQ
+ *	@irq_flags: irq_flags used when requesting IRQ
+ *	@sht: scsi_host_template to use when registering the host
+ *
+ *	After allocating an ATA host and initializing it, most libata
+ *	LLDs perform three steps to activate the host - start host,
+ *	request IRQ and register it.  This helper takes necessasry
+ *	arguments and performs the three steps in one go.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_host_activate(struct ata_host *host, int irq,
+		      irq_handler_t irq_handler, unsigned long irq_flags,
+		      struct scsi_host_template *sht)
+{
+	int rc;
+
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
+			      dev_driver_string(host->dev), host);
+	if (rc)
+		return rc;
+
+	rc = ata_host_register(host, sht);
+	/* if failed, just free the IRQ and leave ports alone */
+	if (rc)
+		devm_free_irq(host->dev, irq, host);
+
+	return rc;
+}
+
+/**
  *	ata_port_detach - Detach ATA port in prepration of device removal
  *	@ap: ATA port to be detached
  *
@@ -6043,32 +6501,6 @@ void ata_host_detach(struct ata_host *ho
 		ata_port_detach(host->ports[i]);
 }
 
-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 = devm_kzalloc(dev, 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
@@ -6334,6 +6766,10 @@ const struct ata_port_operations ata_dum
 	.port_stop		= ata_dummy_noret,
 };
 
+const struct ata_port_info ata_dummy_port_info = {
+	.port_ops		= &ata_dummy_port_ops,
+};
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -6345,10 +6781,15 @@ 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_dummy_port_info);
 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_host_alloc);
+EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_host_start);
+EXPORT_SYMBOL_GPL(ata_host_register);
+EXPORT_SYMBOL_GPL(ata_host_activate);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
 EXPORT_SYMBOL_GPL(ata_sg_init_one);
@@ -6360,6 +6801,7 @@ 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(sata_print_link_status);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
 EXPORT_SYMBOL_GPL(ata_check_status);
@@ -6367,6 +6809,7 @@ EXPORT_SYMBOL_GPL(ata_altstatus);
 EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_do_set_mode);
 EXPORT_SYMBOL_GPL(ata_data_xfer);
 EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
@@ -6400,6 +6843,7 @@ 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_wait_ready);
 EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
@@ -6429,7 +6873,8 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
@@ -6461,3 +6906,8 @@ EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
 EXPORT_SYMBOL_GPL(ata_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dev_try_classify);
+
+EXPORT_SYMBOL_GPL(ata_cable_40wire);
+EXPORT_SYMBOL_GPL(ata_cable_80wire);
+EXPORT_SYMBOL_GPL(ata_cable_unknown);
+EXPORT_SYMBOL_GPL(ata_cable_sata);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 39f556c..8256655 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -50,6 +50,28 @@ enum {
 	ATA_EH_SPDN_FALLBACK_TO_PIO	= (1 << 2),
 };
 
+/* Waiting in ->prereset can never be reliable.  It's sometimes nice
+ * to wait there but it can't be depended upon; otherwise, we wouldn't
+ * be resetting.  Just give it enough time for most drives to spin up.
+ */
+enum {
+	ATA_EH_PRERESET_TIMEOUT		= 10 * HZ,
+};
+
+/* The following table determines how we sequence resets.  Each entry
+ * represents timeout for that try.  The first try can be soft or
+ * hardreset.  All others are hardreset if available.  In most cases
+ * the first reset w/ 10sec timeout should succeed.  Following entries
+ * are mostly for error handling, hotplug and retarded devices.
+ */
+static const unsigned long ata_eh_reset_timeouts[] = {
+	10 * HZ,	/* most drives spin up by 10sec */
+	10 * HZ,	/* > 99% working drives spin up before 20sec */
+	35 * HZ,	/* give > 30 secs of idleness for retarded devices */
+	5 * HZ,		/* and sweet one last chance */
+	/* > 1 min has elapsed, give up */
+};
+
 static void __ata_port_freeze(struct ata_port *ap);
 static void ata_eh_finish(struct ata_port *ap);
 #ifdef CONFIG_PM
@@ -1056,7 +1078,7 @@ static void ata_eh_analyze_serror(struct
 	}
 	if (serror & SERR_INTERNAL) {
 		err_mask |= AC_ERR_SYSTEM;
-		action |= ATA_EH_SOFTRESET;
+		action |= ATA_EH_HARDRESET;
 	}
 	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
 		ata_ehi_hotplugged(&ehc->i);
@@ -1151,7 +1173,9 @@ static unsigned int ata_eh_analyze_tf(st
 		return ATA_EH_SOFTRESET;
 	}
 
-	if (!(qc->err_mask & AC_ERR_DEV))
+	if (stat & (ATA_ERR | ATA_DF))
+		qc->err_mask |= AC_ERR_DEV;
+	else
 		return 0;
 
 	switch (qc->dev->class) {
@@ -1556,14 +1580,14 @@ static void ata_eh_report(struct ata_por
 }
 
 static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
-			unsigned int *classes)
+			unsigned int *classes, unsigned long deadline)
 {
 	int i, rc;
 
 	for (i = 0; i < ATA_MAX_DEVICES; i++)
 		classes[i] = ATA_DEV_UNKNOWN;
 
-	rc = reset(ap, classes);
+	rc = reset(ap, classes, deadline);
 	if (rc)
 		return rc;
 
@@ -1601,8 +1625,9 @@ static int ata_eh_reset(struct ata_port 
 {
 	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);
+	int try = 0;
+	unsigned long deadline;
 	unsigned int action;
 	ata_reset_fn_t reset;
 	int i, did_followup_srst, rc;
@@ -1622,7 +1647,7 @@ static int ata_eh_reset(struct ata_port 
 		ehc->i.action |= ATA_EH_HARDRESET;
 
 	if (prereset) {
-		rc = prereset(ap);
+		rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
 		if (rc) {
 			if (rc == -ENOENT) {
 				ata_port_printk(ap, KERN_DEBUG,
@@ -1663,15 +1688,20 @@ static int ata_eh_reset(struct ata_port 
 	}
 
  retry:
+	deadline = jiffies + ata_eh_reset_timeouts[try++];
+
 	/* 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;
+	if (reset == hardreset)
+		ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+	else
+		ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
 
-	rc = ata_do_reset(ap, reset, classes);
+	rc = ata_do_reset(ap, reset, classes, deadline);
 
 	did_followup_srst = 0;
 	if (reset == hardreset &&
@@ -1688,7 +1718,7 @@ static int ata_eh_reset(struct ata_port 
 		}
 
 		ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
-		rc = ata_do_reset(ap, reset, classes);
+		rc = ata_do_reset(ap, reset, classes, deadline);
 
 		if (rc == 0 && classify &&
 		    classes[0] == ATA_DEV_UNKNOWN) {
@@ -1698,22 +1728,21 @@ static int ata_eh_reset(struct ata_port 
 		}
 	}
 
-	if (rc && --tries) {
-		const char *type;
+	if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+		unsigned long now = jiffies;
 
-		if (reset == softreset) {
-			if (did_followup_srst)
-				type = "follow-up soft";
-			else
-				type = "soft";
-		} else
-			type = "hard";
+		if (time_before(now, deadline)) {
+			unsigned long delta = deadline - jiffies;
 
-		ata_port_printk(ap, KERN_WARNING,
-				"%sreset failed, retrying in 5 secs\n", type);
-		ssleep(5);
+			ata_port_printk(ap, KERN_WARNING, "reset failed "
+				"(errno=%d), retrying in %u secs\n",
+				rc, (jiffies_to_msecs(delta) + 999) / 1000);
+
+			schedule_timeout_uninterruptible(delta);
+		}
 
-		if (reset == hardreset)
+		if (reset == hardreset &&
+		    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
 			sata_down_spd_limit(ap);
 		if (hardreset)
 			reset = hardreset;
@@ -1808,6 +1837,10 @@ static int ata_eh_revalidate_and_attach(
 		}
 	}
 
+	/* PDIAG- should have been released, ask cable type if post-reset */
+	if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+		ap->cbl = ap->ops->cable_detect(ap);
+
 	/* Configure new devices forward such that user doesn't see
 	 * device detection messages backwards.
 	 */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e936443..9afba2b 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTRO
  * 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 = {
+static 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,
@@ -2678,6 +2678,18 @@ static unsigned int ata_scsi_pass_thru(s
 		tf->device = qc->dev->devno ?
 			tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
 
+	/* READ/WRITE LONG use a non-standard sect_size */
+	qc->sect_size = ATA_SECT_SIZE;
+	switch (tf->command) {
+	case ATA_CMD_READ_LONG:
+	case ATA_CMD_READ_LONG_ONCE:
+	case ATA_CMD_WRITE_LONG:
+	case ATA_CMD_WRITE_LONG_ONCE:
+		if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+			goto invalid_fld;
+		qc->sect_size = scmd->request_bufflen;
+	}
+
 	/*
 	 * Filter SET_FEATURES - XFER MODE command -- otherwise,
 	 * SET_FEATURES - XFER MODE must be preceded/succeeded
@@ -2792,8 +2804,9 @@ static inline int __ata_scsi_queuecmd(st
 {
 	int rc = 0;
 
-	if (unlikely(!scmd->cmd_len)) {
-		ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n");
+	if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
+		DPRINTK("bad CDB len=%u, max=%u\n",
+			scmd->cmd_len, dev->cdb_len);
 		scmd->result = DID_ERROR << 16;
 		done(scmd);
 		return 0;
@@ -2948,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device
 	}
 }
 
+int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+{
+	int i, rc;
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		struct Scsi_Host *shost;
+
+		rc = -ENOMEM;
+		shost = scsi_host_alloc(sht, sizeof(struct ata_port *));
+		if (!shost)
+			goto err_alloc;
+
+		*(struct ata_port **)&shost->hostdata[0] = ap;
+		ap->scsi_host = shost;
+
+		shost->transportt = &ata_scsi_transport_template;
+		shost->unique_id = ap->print_id;
+		shost->max_id = 16;
+		shost->max_lun = 1;
+		shost->max_channel = 1;
+		shost->max_cmd_len = 16;
+
+		rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+		if (rc)
+			goto err_add;
+	}
+
+	return 0;
+
+ err_add:
+	scsi_host_put(host->ports[i]->scsi_host);
+ err_alloc:
+	while (--i >= 0) {
+		struct Scsi_Host *shost = host->ports[i]->scsi_host;
+
+		scsi_remove_host(shost);
+		scsi_host_put(shost);
+	}
+	return rc;
+}
+
 void ata_scsi_scan_host(struct ata_port *ap)
 {
 	unsigned int i;
@@ -3224,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(stru
 				    struct ata_port_info *port_info,
 				    struct Scsi_Host *shost)
 {
-	struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
-	struct ata_probe_ent *ent;
+	struct ata_port *ap;
 
+	ap = ata_port_alloc(host);
 	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->port_no = 0;
 	ap->lock = shost->host_lock;
-	devm_kfree(host->dev, ent);
+	ap->pio_mask = port_info->pio_mask;
+	ap->mwdma_mask = port_info->mwdma_mask;
+	ap->udma_mask = port_info->udma_mask;
+	ap->flags |= port_info->flags;
+	ap->ops = port_info->port_ops;
+	ap->cbl = ATA_CBL_SATA;
+
 	return ap;
 }
 EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
@@ -3294,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *a
 {
 	int rc = ap->ops->port_start(ap);
 
-	if (!rc)
+	if (!rc) {
+		ap->print_id = ata_print_id++;
 		rc = ata_bus_probe(ap);
+	}
 
 	return rc;
 }
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ffcca0..d211db6 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -526,168 +526,399 @@ static int ata_resources_present(struct 
 	port = port * 2;
 	for (i = 0; i < 2; i ++) {
 		if (pci_resource_start(pdev, port + i) == 0 ||
-			pci_resource_len(pdev, port + i) == 0)
-		return 0;
+		    pci_resource_len(pdev, port + i) == 0)
+			return 0;
 	}
 	return 1;
 }
 
 /**
- *	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.
+ *	ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ *	@host: target ATA host
+ *
+ *	Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
  */
+static int ata_pci_init_bmdma(struct ata_host *host)
+{
+	struct device *gdev = host->dev;
+	struct pci_dev *pdev = to_pci_dev(gdev);
+	int i, rc;
+
+	/* TODO: If we get no DMA mask we should fall back to PIO */
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+
+	/* request and iomap DMA region */
+	rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+	if (rc) {
+		dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
+		return -ENOMEM;
+	}
+	host->iomap = pcim_iomap_table(pdev);
+
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		void __iomem *bmdma = host->iomap[4] + 8 * i;
+
+		if (ata_port_is_dummy(ap))
+			continue;
+
+		ap->ioaddr.bmdma_addr = bmdma;
+		if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+		    (ioread8(bmdma + 2) & 0x80))
+			host->flags |= ATA_HOST_SIMPLEX;
+	}
+
+	return 0;
+}
 
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+/**
+ *	ata_pci_init_native_host - acquire native ATA resources and init host
+ *	@host: target ATA host
+ *	@port_mask: ports to consider
+ *
+ *	Acquire native PCI ATA resources for @host and initialize
+ *	@host accordoingly.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_pci_init_native_host(struct ata_host *host, unsigned int port_mask)
 {
-	struct ata_probe_ent *probe_ent;
-	int i, p = 0;
-	void __iomem * const *iomap;
-
-	/* iomap BARs */
-	for (i = 0; i < 4; i++) {
-		if (pcim_iomap(pdev, i, 0) == NULL) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "failed to iomap PCI BAR %d\n", i);
-			return NULL;
+	struct device *gdev = host->dev;
+	struct pci_dev *pdev = to_pci_dev(gdev);
+	int i, rc;
+
+	/* Discard disabled ports.  Some controllers show their unused
+	 * channels this way.  Disabled ports are made dummy.
+	 */
+	for (i = 0; i < 2; i++) {
+		if ((port_mask & (1 << i)) && !ata_resources_present(pdev, i)) {
+			host->ports[i]->ops = &ata_dummy_port_ops;
+			port_mask &= ~(1 << i);
 		}
 	}
 
-	pcim_iomap(pdev, 4, 0); /* may fail */
-	iomap = pcim_iomap_table(pdev);
-
-	/* alloc and init probe_ent */
-	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-	if (!probe_ent)
-		return NULL;
-
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = IRQF_SHARED;
-
-	/* Discard disabled ports. Some controllers show their
-	   unused channels this way */
-	if (ata_resources_present(pdev, 0) == 0)
-		ports &= ~ATA_PORT_PRIMARY;
-	if (ata_resources_present(pdev, 1) == 0)
-		ports &= ~ATA_PORT_SECONDARY;
-
-	if (ports & ATA_PORT_PRIMARY) {
-		probe_ent->port[p].cmd_addr = iomap[0];
-		probe_ent->port[p].altstatus_addr =
-		probe_ent->port[p].ctl_addr = (void __iomem *)
-			((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
-		if (iomap[4]) {
-			if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(iomap[4] + 2) & 0x80))
-				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
-			probe_ent->port[p].bmdma_addr = iomap[4];
-		}
-		ata_std_ports(&probe_ent->port[p]);
-		p++;
+	if (!port_mask) {
+		dev_printk(KERN_ERR, gdev, "no available port\n");
+		return -ENODEV;
 	}
 
-	if (ports & ATA_PORT_SECONDARY) {
-		probe_ent->port[p].cmd_addr = iomap[2];
-		probe_ent->port[p].altstatus_addr =
-		probe_ent->port[p].ctl_addr = (void __iomem *)
-			((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
-		if (iomap[4]) {
-			if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(iomap[4] + 10) & 0x80))
-				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
-			probe_ent->port[p].bmdma_addr = iomap[4] + 8;
+	/* request, iomap BARs and init port addresses accordingly */
+	for (i = 0; i < 2; i++) {
+		struct ata_port *ap = host->ports[i];
+		int base = i * 2;
+		void __iomem * const *iomap;
+
+		if (!(port_mask & (1 << i)))
+			continue;
+
+		rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+		if (rc) {
+			dev_printk(KERN_ERR, gdev, "failed to request/iomap "
+				   "BARs for port %d (errno=%d)\n", i, rc);
+			if (rc == -EBUSY)
+				pcim_pin_device(pdev);
+			return rc;
 		}
-		ata_std_ports(&probe_ent->port[p]);
-		probe_ent->pinfo2 = port[1];
-		p++;
+		host->iomap = iomap = pcim_iomap_table(pdev);
+
+		ap->ioaddr.cmd_addr = iomap[base];
+		ap->ioaddr.altstatus_addr =
+		ap->ioaddr.ctl_addr = (void __iomem *)
+			((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
+		ata_std_ports(&ap->ioaddr);
 	}
 
-	probe_ent->n_ports = p;
-	return probe_ent;
+	return 0;
 }
 
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
-				struct ata_port_info **port, int port_mask)
+/**
+ *	ata_pci_prepare_native_host - helper to prepare native PCI ATA host
+ *	@pdev: target PCI device
+ *	@ppi: array of port_info
+ *	@n_ports: number of ports to allocate
+ *	@r_host: out argument for the initialized ATA host
+ *
+ *	Helper to allocate ATA host for @pdev, acquire all native PCI
+ *	resources and initialize it accordingly in one go.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_pci_prepare_native_host(struct pci_dev *pdev,
+				const struct ata_port_info * const * ppi,
+				int n_ports, struct ata_host **r_host)
+{
+	struct ata_host *host;
+	unsigned int port_mask;
+	int rc;
+
+	if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+	if (!host) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "failed to allocate ATA host\n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
+	port_mask = ATA_PORT_PRIMARY;
+	if (n_ports > 1)
+		port_mask |= ATA_PORT_SECONDARY;
+
+	rc = ata_pci_init_native_host(host, port_mask);
+	if (rc)
+		goto err_out;
+
+	/* init DMA related stuff */
+	rc = ata_pci_init_bmdma(host);
+	if (rc)
+		goto err_bmdma;
+
+	devres_remove_group(&pdev->dev, NULL);
+	*r_host = host;
+	return 0;
+
+ err_bmdma:
+	/* This is necessary because PCI and iomap resources are
+	 * merged and releasing the top group won't release the
+	 * acquired resources if some of those have been acquired
+	 * before entering this function.
+	 */
+	pcim_iounmap_regions(pdev, 0xf);
+ err_out:
+	devres_release_group(&pdev->dev, NULL);
+	return rc;
+}
+
+struct ata_legacy_devres {
+	unsigned int	mask;
+	unsigned long	cmd_port[2];
+	void __iomem *	cmd_addr[2];
+	void __iomem *	ctl_addr[2];
+	unsigned int	irq[2];
+	void *		irq_dev_id[2];
+};
+
+static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
 {
-	struct ata_probe_ent *probe_ent;
-	void __iomem *iomap[5] = { }, *bmdma;
-
-	if (port_mask & ATA_PORT_PRIMARY) {
-		iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
-		iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
-		if (!iomap[0] || !iomap[1])
-			return NULL;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		if (!legacy_dr->irq[i])
+			continue;
+
+		free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
+		legacy_dr->irq[i] = 0;
+		legacy_dr->irq_dev_id[i] = NULL;
 	}
+}
+
+static void ata_legacy_release(struct device *gdev, void *res)
+{
+	struct ata_legacy_devres *this = res;
+	int i;
 
-	if (port_mask & ATA_PORT_SECONDARY) {
-		iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
-		iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
-		if (!iomap[2] || !iomap[3])
-			return NULL;
+	ata_legacy_free_irqs(this);
+
+	for (i = 0; i < 2; i++) {
+		if (this->cmd_addr[i])
+			ioport_unmap(this->cmd_addr[i]);
+		if (this->ctl_addr[i])
+			ioport_unmap(this->ctl_addr[i]);
+		if (this->cmd_port[i])
+			release_region(this->cmd_port[i], 8);
 	}
+}
 
-	bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
-
-	/* alloc and init probe_ent */
-	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
-	if (!probe_ent)
-		return NULL;
-
-	probe_ent->n_ports = 2;
-	probe_ent->irq_flags = IRQF_SHARED;
-
-	if (port_mask & ATA_PORT_PRIMARY) {
-		probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
-		probe_ent->port[0].cmd_addr = iomap[0];
-		probe_ent->port[0].altstatus_addr =
-		probe_ent->port[0].ctl_addr = iomap[1];
-		if (bmdma) {
-			probe_ent->port[0].bmdma_addr = bmdma;
-			if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(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;
+static int ata_init_legacy_port(struct ata_port *ap,
+				struct ata_legacy_devres *legacy_dr)
+{
+	struct ata_host *host = ap->host;
+	int port_no = ap->port_no;
+	unsigned long cmd_port, ctl_port;
+
+	if (port_no == 0) {
+		cmd_port = ATA_PRIMARY_CMD;
+		ctl_port = ATA_PRIMARY_CTL;
+	} else {
+		cmd_port = ATA_SECONDARY_CMD;
+		ctl_port = ATA_SECONDARY_CTL;
+	}
+
+	/* request cmd_port */
+	if (request_region(cmd_port, 8, "libata"))
+		legacy_dr->cmd_port[port_no] = cmd_port;
+	else {
+		dev_printk(KERN_WARNING, host->dev,
+			   "0x%0lX IDE port busy\n", cmd_port);
+		return -EBUSY;
+	}
+
+	/* iomap cmd and ctl ports */
+	legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
+	legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
+	if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no])
+		return -ENOMEM;
+
+	/* init IO addresses */
+	ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
+	ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
+	ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
+	ata_std_ports(&ap->ioaddr);
+
+	return 0;
+}
+
+/**
+ *	ata_init_legacy_host - acquire legacy ATA resources and init ATA host
+ *	@host: target ATA host
+ *	@legacy_mask: out parameter, mask indicating ports is in legacy mode
+ *	@was_busy: out parameter, indicates whether any port was busy
+ *
+ *	Acquire legacy ATA resources for ports.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_init_legacy_host(struct ata_host *host,
+				unsigned int *legacy_mask, int *was_busy)
+{
+	struct device *gdev = host->dev;
+	struct ata_legacy_devres *legacy_dr;
+	int i, rc;
+
+	if (!devres_open_group(gdev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	rc = -ENOMEM;
+	legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
+				 GFP_KERNEL);
+	if (!legacy_dr)
+		goto err_out;
+	devres_add(gdev, legacy_dr);
+
+	for (i = 0; i < 2; i++) {
+		*legacy_mask &= ~(1 << i);
+		rc = ata_init_legacy_port(host->ports[i], legacy_dr);
+		if (rc == 0)
+			legacy_dr->mask |= 1 << i;
+		else if (rc == -EBUSY)
+			(*was_busy)++;
+	}
+
+	if (!legacy_dr->mask)
+		return -EBUSY;
+
+	for (i = 0; i < 2; i++)
+		if (!(legacy_dr->mask & (1 << i)))
+			host->ports[i]->ops = &ata_dummy_port_ops;
+
+	*legacy_mask |= legacy_dr->mask;
 
-	if (port_mask & ATA_PORT_SECONDARY) {
-		if (probe_ent->irq)
-			probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
+	devres_remove_group(gdev, NULL);
+	return 0;
+
+ err_out:
+	devres_release_group(gdev, NULL);
+	return rc;
+}
+
+/**
+ *	ata_request_legacy_irqs - request legacy ATA IRQs
+ *	@host: target ATA host
+ *	@handler: array of IRQ handlers
+ *	@irq_flags: array of IRQ flags
+ *	@dev_id: array of IRQ dev_ids
+ *
+ *	Request legacy IRQs for non-dummy legacy ports in @host.  All
+ *	IRQ parameters are passed as array to allow ports to have
+ *	separate IRQ handlers.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int ata_request_legacy_irqs(struct ata_host *host,
+				   irq_handler_t const *handler,
+				   const unsigned int *irq_flags,
+				   void * const *dev_id)
+{
+	struct device *gdev = host->dev;
+	struct ata_legacy_devres *legacy_dr;
+	int i, rc;
+
+	legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
+	BUG_ON(!legacy_dr);
+
+	for (i = 0; i < host->n_ports; i++) {
+		unsigned int irq;
+
+		/* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
+		if (i == 0)
+			irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
 		else
-			probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
-		probe_ent->port[1].cmd_addr = iomap[2];
-		probe_ent->port[1].altstatus_addr =
-		probe_ent->port[1].ctl_addr = iomap[3];
-		if (bmdma) {
-			probe_ent->port[1].bmdma_addr = bmdma + 8;
-			if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
-			    (ioread8(bmdma + 10) & 0x80))
-				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+			irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
+
+		if (!(legacy_dr->mask & (1 << i)))
+			continue;
+
+		if (!handler[i]) {
+			dev_printk(KERN_ERR, gdev,
+				   "NULL handler specified for port %d\n", i);
+			rc = -EINVAL;
+			goto err_out;
 		}
-		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;
+		rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
+				 dev_id[i]);
+		if (rc) {
+			dev_printk(KERN_ERR, gdev,
+				"irq %u request failed (errno=%d)\n", irq, rc);
+			goto err_out;
+		}
 
-	return probe_ent;
-}
+		/* record irq allocation in legacy_dr */
+		legacy_dr->irq[i] = irq;
+		legacy_dr->irq_dev_id[i] = dev_id[i];
+
+		/* only used to print info */
+		if (i == 0)
+			host->irq = irq;
+		else
+			host->irq2 = irq;
+	}
 
+	return 0;
+
+ err_out:
+	ata_legacy_free_irqs(legacy_dr);
+	return rc;
+}
 
 /**
  *	ata_pci_init_one - Initialize/register PCI IDE host controller
@@ -718,8 +949,8 @@ int ata_pci_init_one (struct pci_dev *pd
 		      unsigned int n_ports)
 {
 	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent = NULL;
-	struct ata_port_info *port[2];
+	struct ata_host *host = NULL;
+	const struct ata_port_info *port[2];
 	u8 mask;
 	unsigned int legacy_mode = 0;
 	int rc;
@@ -732,10 +963,7 @@ int ata_pci_init_one (struct pci_dev *pd
 	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];
+	port[1] = (n_ports > 1) ? port_info[1] : NULL;
 
 	/* 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
@@ -743,7 +971,7 @@ int ata_pci_init_one (struct pci_dev *pd
 
 	   Checking dev->is_enabled is insufficient as this is not set at
 	   boot for the primary video which is BIOS enabled
-         */
+	  */
 
 	rc = pcim_enable_device(pdev);
 	if (rc)
@@ -769,96 +997,68 @@ #if defined(CONFIG_NO_ATA_LEGACY)
 #endif
 	}
 
+	/* alloc and init host */
+	host = ata_host_alloc_pinfo(dev, port, n_ports);
+	if (!host) {
+		dev_printk(KERN_ERR, &pdev->dev,
+			   "failed to allocate ATA host\n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+
 	if (!legacy_mode) {
-		rc = pci_request_regions(pdev, DRV_NAME);
-		if (rc) {
-			pcim_pin_device(pdev);
+		unsigned int port_mask;
+
+		port_mask = ATA_PORT_PRIMARY;
+		if (n_ports > 1)
+			port_mask |= ATA_PORT_SECONDARY;
+
+		rc = ata_pci_init_native_host(host, port_mask);
+		if (rc)
 			goto err_out;
-		}
 	} else {
-		/* Deal with combined mode hack. This side of the logic all
-		   goes away once the combined mode hack is killed in 2.6.21 */
-		if (!devm_request_region(dev, 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 {
-				pcim_pin_device(pdev);
-				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 (!devm_request_region(dev, 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 {
-				pcim_pin_device(pdev);
-				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;
-
-		if (legacy_mode & ATA_PORT_PRIMARY)
-			pci_request_region(pdev, 1, DRV_NAME);
-		if (legacy_mode & ATA_PORT_SECONDARY)
-			pci_request_region(pdev, 3, DRV_NAME);
-		/* If there is a DMA resource, allocate it */
-		pci_request_region(pdev, 4, DRV_NAME);
-	}
+		int was_busy = 0;
 
-	/* we have legacy mode, but all ports are unavailable */
-	if (legacy_mode == (1 << 3)) {
-		rc = -EBUSY;
-		goto err_out;
+		rc = ata_init_legacy_host(host, &legacy_mode, &was_busy);
+		if (was_busy)
+			pcim_pin_device(pdev);
+		if (rc)
+			goto err_out;
+
+		/* request respective PCI regions, may fail */
+		rc = pci_request_region(pdev, 1, DRV_NAME);
+		rc = pci_request_region(pdev, 3, DRV_NAME);
 	}
 
-	/* 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;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	/* init BMDMA, may fail */
+	ata_pci_init_bmdma(host);
+	pci_set_master(pdev);
+
+	/* start host and request IRQ */
+	rc = ata_host_start(host);
 	if (rc)
 		goto err_out;
 
-	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 (!legacy_mode)
+		rc = devm_request_irq(dev, pdev->irq,
+				      port_info[0]->port_ops->irq_handler,
+				      IRQF_SHARED, DRV_NAME, host);
+	else {
+		irq_handler_t handler[2] = { host->ops->irq_handler,
+					     host->ops->irq_handler };
+		unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
+		void *dev_id[2] = { host, host };
+
+		rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
 	}
-	if (!probe_ent) {
-		rc = -ENOMEM;
+	if (rc)
 		goto err_out;
-	}
-
-	pci_set_master(pdev);
 
-	if (!ata_device_add(probe_ent)) {
-		rc = -ENODEV;
+	/* register */
+	rc = ata_host_register(host, port_info[0]->sht);
+	if (rc)
 		goto err_out;
-	}
 
-	devm_kfree(dev, probe_ent);
 	devres_remove_group(dev, NULL);
 	return 0;
 
@@ -893,12 +1093,12 @@ int ata_pci_clear_simplex(struct pci_dev
 	return 0;
 }
 
-unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
+unsigned long ata_pci_default_filter(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)
+	if (adev->ap->ioaddr.bmdma_addr == 0)
 		xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
 	return xfer_mask;
 }
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 1f1e3a5..5f4d40c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -52,6 +52,7 @@ enum {
 	ATA_DNXFER_QUIET	= (1 << 31),
 };
 
+extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
@@ -92,10 +93,7 @@ extern int ata_flush_cache(struct ata_de
 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);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_SATA_ACPI
@@ -113,8 +111,8 @@ static inline int ata_acpi_push_id(struc
 #endif
 
 /* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+			      struct scsi_host_template *sht);
 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(struct work_struct *work);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 11ea552..d40edeb 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@ #include <linux/libata.h>
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.4"
 
 /*
  *	Cable special cases
@@ -90,59 +90,6 @@ static int ali_c2_cable_detect(struct at
 }
 
 /**
- *	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
@@ -151,7 +98,7 @@ static void ali_early_error_handler(stru
  *	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)
+static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask)
 {
 	char model_num[ATA_ID_PROD_LEN + 1];
 	/* No DMA on anything but a disk for now */
@@ -160,7 +107,7 @@ static unsigned long ali_20_filter(const
 	ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
 	if (strstr(model_num, "WDC"))
 		return mask &= ~ATA_MASK_UDMA;
-	return ata_pci_default_filter(ap, adev, mask);
+	return ata_pci_default_filter(adev, mask);
 }
 
 /**
@@ -314,7 +261,6 @@ static void ali_set_dmamode(struct ata_p
 
 /**
  *	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
@@ -324,7 +270,7 @@ static void ali_set_dmamode(struct ata_p
  *	slower PIO methods
  */
 
-static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+static void ali_lock_sectors(struct ata_device *adev)
 {
 	adev->max_sectors = 255;
 }
@@ -366,8 +312,9 @@ static struct ata_port_operations ali_ea
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= ali_early_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -402,8 +349,9 @@ static struct ata_port_operations ali_20
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= ali_early_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -440,8 +388,9 @@ static struct ata_port_operations ali_c2
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= ali_c2_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ali_c2_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -477,8 +426,9 @@ static struct ata_port_operations ali_c5
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= ali_c2_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ali_c2_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 1838176..67c7e87 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.3.8"
 
 /**
  *	timing_setup		-	shared timing computation and load
@@ -119,34 +119,27 @@ static void timing_setup(struct ata_port
 }
 
 /**
- *	amd_probe_init		-	cable detection
+ *	amd_probe_init		-	perform reset handling
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
- *	Perform cable detection. The BIOS stores this in PCI config
- *	space for us.
+ *	Reset sequence checking enable bits to see which ports are
+ *	active.
  */
 
-static int amd_pre_reset(struct ata_port *ap)
+static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
-	static const u32 bitmask[2] = {0x03, 0x0C};
 	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);
-
+	return ata_std_prereset(ap, deadline);
 }
 
 static void amd_error_handler(struct ata_port *ap)
@@ -156,28 +149,16 @@ static void amd_error_handler(struct ata
 				      ata_std_postreset);
 }
 
-static int amd_early_pre_reset(struct ata_port *ap)
+static int amd_cable_detect(struct ata_port *ap)
 {
+	static const u32 bitmask[2] = {0x03, 0x0C};
 	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);
-
-}
+	u8 ata66;
 
-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);
+	pci_read_config_byte(pdev, 0x42, &ata66);
+	if (ata66 & bitmask[ap->port_no])
+		return ATA_CBL_PATA80;
+	return ATA_CBL_PATA40;
 }
 
 /**
@@ -246,33 +227,19 @@ static void amd133_set_dmamode(struct at
  *	space for us.
  */
 
-static int nv_pre_reset(struct ata_port *ap) {
-	static const u8 bitmask[2] = {0x03, 0x0C};
+static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+{
 	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);
+	return ata_std_prereset(ap, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -281,6 +248,29 @@ static void nv_error_handler(struct ata_
 			       ata_std_softreset, NULL,
 			       ata_std_postreset);
 }
+
+static int nv_cable_detect(struct ata_port *ap)
+{
+	static const u8 bitmask[2] = {0x03, 0x0C};
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	u8 ata66;
+	u16 udma;
+	int cbl;
+
+	pci_read_config_byte(pdev, 0x52, &ata66);
+	if (ata66 & bitmask[ap->port_no])
+		cbl = ATA_CBL_PATA80;
+	else
+		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)
+		cbl = ATA_CBL_PATA80;
+	return cbl;
+}
+
 /**
  *	nv100_set_piomode	-	set initial PIO mode data
  *	@ap: ATA interface
@@ -353,8 +343,9 @@ static struct ata_port_operations amd33_
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= amd_early_error_handler,
+	.error_handler	= amd_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -387,8 +378,9 @@ static struct ata_port_operations amd66_
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= amd_early_error_handler,
+	.error_handler	= amd_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_unknown,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -423,6 +415,7 @@ static struct ata_port_operations amd100
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= amd_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_unknown,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -457,6 +450,7 @@ static struct ata_port_operations amd133
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= amd_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= amd_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -491,6 +485,7 @@ static struct ata_port_operations nv100_
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= nv_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= nv_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -525,6 +520,7 @@ static struct ata_port_operations nv133_
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= nv_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= nv_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 21c3028..ef51940 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -39,7 +39,7 @@ #define DRV_VERSION	"0.4.2"
 
 static int clock = 0;
 
-static int artop6210_pre_reset(struct ata_port *ap)
+static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	const struct pci_bits artop_enable_bits[] = {
@@ -50,8 +50,7 @@ static int artop6210_pre_reset(struct at
 	if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -72,12 +71,13 @@ static void artop6210_error_handler(stru
 /**
  *	artop6260_pre_reset	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	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 int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits artop_enable_bits[] = {
 		{ 0x4AU, 1U, 0x02UL, 0x02UL },	/* port 0 */
@@ -85,18 +85,29 @@ static int artop6260_pre_reset(struct at
 	};
 
 	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;
 
+	return ata_std_prereset(ap, deadline);
+}
+
+/**
+ *	artop6260_cable_detect	-	identify cable type
+ *	@ap: Port
+ *
+ *	Identify the cable type for the ARTOp interface in question
+ */
+ 
+static int artop6260_cable_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	u8 tmp;
 	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);
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
 }
 
 /**
@@ -225,7 +236,7 @@ static void artop6260_set_piomode(struct
 /**
  *	artop6210_set_dmamode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
- *	@adev: um
+ *	@adev: Device whose timings we are configuring
  *
  *	Set DMA mode for device, in host controller PCI config space.
  *
@@ -333,6 +344,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= artop6210_error_handler,
 	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -366,6 +378,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= artop6260_error_handler,
 	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= artop6260_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 51d9923..2151538 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.5"
 
 enum {
 	ATIIXP_IDE_PIO_TIMING	= 0x40,
@@ -33,26 +33,18 @@ enum {
 	ATIIXP_IDE_UDMA_MODE 	= 0x56
 };
 
-static int atiixp_pre_reset(struct ata_port *ap)
+static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits atiixp_enable_bits[] = {
 		{ 0x48, 1, 0x01, 0x00 },
 		{ 0x48, 1, 0x08, 0x00 }
 	};
-	u8 udma;
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	/* Hack from drivers/ide/pci. Really we want to know how to do the
-	   raw detection not play follow the bios mode guess */
-	pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
-	if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
-		ap->cbl = ATA_CBL_PATA80;
-	else
-		ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 static void atiixp_error_handler(struct ata_port *ap)
@@ -60,6 +52,19 @@ static void atiixp_error_handler(struct 
 	ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL,   ata_std_postreset);
 }
 
+static int atiixp_cable_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	u8 udma;
+
+	/* Hack from drivers/ide/pci. Really we want to know how to do the
+	   raw detection not play follow the bios mode guess */
+	pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
+	if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
+		return  ATA_CBL_PATA80;
+	return ATA_CBL_PATA40;
+}
+
 /**
  *	atiixp_set_pio_timing	-	set initial PIO mode data
  *	@ap: ATA interface
@@ -245,6 +250,7 @@ static struct ata_port_operations atiixp
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= atiixp_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= atiixp_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= atiixp_bmdma_start,
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
new file mode 100644
index 0000000..2105985
--- /dev/null
+++ b/drivers/ata/pata_cmd640.c
@@ -0,0 +1,312 @@
+/*
+ * pata_cmd640.c 	- CMD640 PCI PATA for new ATA layer
+ *			  (C) 2007 Red Hat Inc
+ *			  Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ *  linux/drivers/ide/pci/cmd640.c		Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see driver)
+ *
+ *	This drives only the PCI version of the controller. If you have a
+ *	VLB one then we have enough docs to support it but you can write
+ *	your own code.
+ */
+
+#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_cmd640"
+#define DRV_VERSION "0.0.5"
+
+struct cmd640_reg {
+	int last;
+	u8 reg58[ATA_MAX_DEVICES];
+};
+
+enum {
+	CFR = 0x50,
+	CNTRL = 0x51,
+	CMDTIM = 0x52,
+	ARTIM0 = 0x53,
+	DRWTIM0 = 0x54,
+	ARTIM23 = 0x57,
+	DRWTIM23 = 0x58,
+	BRST = 0x59
+};
+
+/**
+ *	cmd640_set_piomode	-	set initial PIO mode data
+ *	@ap: ATA port
+ *	@adev: ATA device
+ *
+ *	Called to do the PIO mode setup.
+ */
+
+static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct cmd640_reg *timing = ap->private_data;
+	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;
+	int arttim = ARTIM0 + 2 * adev->devno;
+	struct ata_device *pair = ata_dev_pair(adev);
+
+	if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+		printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+		return;
+	}
+
+	/* The second channel has shared timings and the setup timing is
+	   messy to switch to merge it for worst case */
+	if (ap->port_no && pair) {
+		struct ata_timing p;
+		ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+		ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP);
+	}
+
+	/* Make the timings fit */
+	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--;	/* 640B only */
+	else
+		t.recover = 15;
+
+	if (t.setup > 4)
+		t.setup = 0xC0;
+	else
+		t.setup = setup_data[t.setup];
+
+	if (ap->port_no == 0) {
+		t.active &= 0x0F;	/* 0 = 16 */
+
+		/* Load setup timing */
+		pci_read_config_byte(pdev, arttim, &reg);
+		reg &= 0x3F;
+		reg |= t.setup;
+		pci_write_config_byte(pdev, arttim, reg);
+
+		/* Load active/recovery */
+		pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover);
+	} else {
+		/* Save the shared timings for channel, they will be loaded
+		   by qc_issue_prot. Reloading the setup time is expensive 
+		   so we keep a merged one loaded */
+		pci_read_config_byte(pdev, ARTIM23, &reg);
+		reg &= 0x3F;
+		reg |= t.setup;
+		pci_write_config_byte(pdev, ARTIM23, reg);
+		timing->reg58[adev->devno] = (t.active << 4) | t.recover;
+	}
+}
+
+
+/**
+ *	cmd640_qc_issue_prot	-	command preparation hook
+ *	@qc: Command to be issued
+ *
+ *	Channel 1 has shared timings. We must reprogram the
+ *	clock each drive 2/3 switch we do.
+ */
+
+static unsigned int cmd640_qc_issue_prot(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);
+	struct cmd640_reg *timing = ap->private_data;
+
+	if (ap->port_no != 0 && adev->devno != timing->last) {
+		pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]);
+		timing->last = adev->devno;
+	}
+	return ata_qc_issue_prot(qc);
+}
+
+/**
+ *	cmd640_port_start	-	port setup
+ *	@ap: ATA port being set up
+ *
+ *	The CMD640 needs to maintain private data structures so we
+ *	allocate space here.
+ */
+
+static int cmd640_port_start(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	struct cmd640_reg *timing;
+
+	int ret = ata_port_start(ap);
+	if (ret < 0)
+		return ret;
+
+	timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL);
+	if (timing == NULL)
+		return -ENOMEM;
+	timing->last = -1;	/* Force a load */
+	ap->private_data = timing;
+	return ret;
+}
+
+static struct scsi_host_template cmd640_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,
+#ifdef CONFIG_PM
+	.resume			= ata_scsi_device_resume,
+	.suspend		= ata_scsi_device_suspend,
+#endif
+};
+
+static struct ata_port_operations cmd640_port_ops = {
+	.port_disable	= ata_port_disable,
+	.set_piomode	= cmd640_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	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.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	= cmd640_qc_issue_prot,
+
+	/* In theory this is not needed once we kill the prefetcher */
+	.data_xfer	= ata_data_xfer_noirq,
+
+	.irq_handler	= ata_interrupt,
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+	.irq_ack	= ata_irq_ack,
+
+	.port_start	= cmd640_port_start,
+};
+
+static void cmd640_hardware_init(struct pci_dev *pdev)
+{
+	u8 r;
+	u8 ctrl;
+
+	/* CMD640 detected, commiserations */
+	pci_write_config_byte(pdev, 0x5B, 0x00);
+	/* Get version info */
+	pci_read_config_byte(pdev, CFR, &r);
+	/* PIO0 command cycles */
+	pci_write_config_byte(pdev, CMDTIM, 0);
+	/* 512 byte bursts (sector) */
+	pci_write_config_byte(pdev, BRST, 0x40);
+	/* 
+	 * A reporter a long time ago
+	 * Had problems with the data fifo
+	 * So don't run the risk
+	 * Of putting crap on the disk
+	 * For its better just to go slow
+	 */
+	/* Do channel 0 */
+	pci_read_config_byte(pdev, CNTRL, &ctrl);
+	pci_write_config_byte(pdev, CNTRL, ctrl | 0xC0);
+	/* Ditto for channel 1 */
+	pci_read_config_byte(pdev, ARTIM23, &ctrl);
+	ctrl |= 0x0C;
+	pci_write_config_byte(pdev, ARTIM23, ctrl);
+}
+
+static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	static struct ata_port_info info = {
+		.sht = &cmd640_sht,
+		.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+		.pio_mask = 0x1f,
+		.port_ops = &cmd640_port_ops
+	};
+
+	static struct ata_port_info *port_info[2] = { &info, &info };
+
+	cmd640_hardware_init(pdev);
+	return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static int cmd640_reinit_one(struct pci_dev *pdev)
+{
+	cmd640_hardware_init(pdev);
+#ifdef CONFIG_PM
+	return ata_pci_device_resume(pdev);
+#else
+	return 0;
+#endif
+}
+
+static const struct pci_device_id cmd640[] = {
+	{ PCI_VDEVICE(CMD, 0x640), 0 },
+	{ },
+};
+
+static struct pci_driver cmd640_pci_driver = {
+	.name 		= DRV_NAME,
+	.id_table	= cmd640,
+	.probe 		= cmd640_init_one,
+	.remove		= ata_pci_remove_one,
+#ifdef CONFIG_PM
+	.suspend	= ata_pci_device_suspend,
+#endif
+	.resume		= cmd640_reinit_one,
+};
+
+static int __init cmd640_init(void)
+{
+	return pci_register_driver(&cmd640_pci_driver);
+}
+
+static void __exit cmd640_exit(void)
+{
+	pci_unregister_driver(&cmd640_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd640);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd640_init);
+module_exit(cmd640_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 5b13bdd..3989cc5 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -75,13 +75,7 @@ enum {
 	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)
+static int cmd648_cable_detect(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 r;
@@ -89,21 +83,8 @@ static int cmd648_pre_reset(struct ata_p
 	/* 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);
+		return ATA_CBL_PATA80;
+	return ATA_CBL_PATA40;
 }
 
 /**
@@ -304,8 +285,9 @@ static struct ata_port_operations cmd64x
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cmd64x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -338,8 +320,9 @@ static struct ata_port_operations cmd646
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cmd64x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -372,8 +355,9 @@ static struct ata_port_operations cmd648
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cmd648_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= cmd648_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 55cc293..79bef0d 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -139,18 +139,6 @@ static void cs5520_set_piomode(struct at
 	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,
@@ -186,8 +174,9 @@ static struct ata_port_operations cs5520
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= cs5520_error_handler,
+	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -197,7 +186,6 @@ static struct ata_port_operations cs5520
 	.qc_issue		= ata_qc_issue_prot,
 	.data_xfer		= ata_data_xfer,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -205,91 +193,104 @@ static struct ata_port_operations cs5520
 	.port_start		= ata_port_start,
 };
 
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+	struct ata_port_info pi = {
+		.flags		= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,
+		.port_ops	= &cs5520_port_ops,
+	};
+	const struct ata_port_info *ppi[2];
 	u8 pcicfg;
-	void __iomem *iomap[5];
-	static struct ata_probe_ent probe[2];
-	int ports = 0;
+	void *iomap[5];
+	struct ata_host *host;
+	struct ata_ioports *ioaddr;
+	int i, rc;
 
 	/* IDE port enable bits */
-	pci_read_config_byte(dev, 0x60, &pcicfg);
+	pci_read_config_byte(pdev, 0x60, &pcicfg);
 
 	/* Check if the ATA ports are enabled */
 	if ((pcicfg & 3) == 0)
 		return -ENODEV;
 
+	ppi[0] = ppi[1] = &ata_dummy_port_info;
+	if (pcicfg & 1)
+		ppi[0] = &pi;
+	if (pcicfg & 2)
+		ppi[1] = &pi;
+
 	if ((pcicfg & 0x40) == 0) {
-		printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
-		pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "DMA mode disabled. Enabling.\n");
+		pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
 	}
 
+	pi.mwdma_mask = id->driver_data;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+	if (!host)
+		return -ENOMEM;
+
 	/* Perform set up for DMA */
-	if (pci_enable_device_bars(dev, 1<<2)) {
+	if (pci_enable_device_bars(pdev, 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)) {
+
+	if (pci_set_dma_mask(pdev, 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)) {
+	if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
 		return -ENODEV;
 	}
 
-	/* Map IO ports */
-	iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
-	iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
-	iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
-	iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
-	iomap[4] = pcim_iomap(dev, 2, 0);
+	/* Map IO ports and initialize host accordingly */
+	iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
+	iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
+	iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
+	iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+	iomap[4] = pcim_iomap(pdev, 2, 0);
 
 	if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
 		return -ENOMEM;
 
-	/* 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 = iomap[0];
-	probe[0].port[0].ctl_addr = iomap[1];
-	probe[0].port[0].altstatus_addr = iomap[1];
-	probe[0].port[0].bmdma_addr = iomap[4];
-
-	/* 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 = iomap[2];
-	probe[1].port[0].ctl_addr = iomap[3];
-	probe[1].port[0].altstatus_addr = iomap[3];
-	probe[1].port[0].bmdma_addr = iomap[4] + 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;
+	ioaddr = &host->ports[0]->ioaddr;
+	ioaddr->cmd_addr = iomap[0];
+	ioaddr->ctl_addr = iomap[1];
+	ioaddr->altstatus_addr = iomap[1];
+	ioaddr->bmdma_addr = iomap[4];
+	ata_std_ports(ioaddr);
+
+	ioaddr = &host->ports[1]->ioaddr;
+	ioaddr->cmd_addr = iomap[2];
+	ioaddr->ctl_addr = iomap[3];
+	ioaddr->altstatus_addr = iomap[3];
+	ioaddr->bmdma_addr = iomap[4] + 8;
+	ata_std_ports(ioaddr);
+
+	/* activate the host */
+	pci_set_master(pdev);
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < 2; i++) {
+		static const int irq[] = { 14, 15 };
+		struct ata_port *ap = host->ports[0];
+
+		if (ata_port_is_dummy(ap))
+			continue;
+
+		rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
+				      ata_interrupt, 0, DRV_NAME, host);
+		if (rc)
+			return rc;
+	}
+
+	return ata_host_register(host, &cs5520_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index db63e80..29642d5 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -160,18 +160,6 @@ static unsigned int cs5530_qc_issue_prot
 	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,
@@ -213,8 +201,9 @@ static struct ata_port_operations cs5530
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cs5530_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= cs5530_qc_issue_prot,
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 1572e5c..22006ae 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -70,36 +70,24 @@ #define CS5535_CABLE_DETECT    0x48
 #define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
 
 /**
- *	cs5535_pre_reset	-	detect cable type
+ *	cs5535_cable_detect	-	detect cable type
  *	@ap: Port to detect on
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform cable detection for ATA66 capable cable. Return a libata
  *	cable type.
  */
 
-static int cs5535_pre_reset(struct ata_port *ap)
+static int cs5535_cable_detect(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;
+		return 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);
+		return ATA_CBL_PATA40;
 }
 
 /**
@@ -205,8 +193,9 @@ static struct ata_port_operations cs5535
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cs5535_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= cs5535_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index f69dde5..6ec049c 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -41,17 +41,6 @@ enum {
 	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
@@ -156,8 +145,9 @@ static struct ata_port_operations cy82c6
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= cy82c693_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index dac7a65..d0f52e0 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -22,35 +22,29 @@ #include <linux/libata.h>
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_efar"
-#define DRV_VERSION	"0.4.3"
+#define DRV_VERSION	"0.4.4"
 
 /**
- *	efar_pre_reset	-	check for 40/80 pin
+ *	efar_pre_reset	-	Enable bits
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	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 int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	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);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -67,6 +61,25 @@ static void efar_error_handler(struct at
 }
 
 /**
+ *	efar_cable_detect	-	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_cable_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	u8 tmp;
+
+	pci_read_config_byte(pdev, 0x47, &tmp);
+	if (tmp & (2 >> ap->port_no))
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
+}
+
+/**
  *	efar_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
  *	@adev: um
@@ -256,6 +269,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= efar_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= efar_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index baf35f8..e64e05e 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -27,7 +27,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_hpt366"
-#define DRV_VERSION	"0.6.0"
+#define DRV_VERSION	"0.6.1"
 
 struct hpt_clock {
 	u8	xfer_speed;
@@ -169,13 +169,12 @@ static int hpt_dma_blacklisted(const str
 
 /**
  *	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)
+static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
 {
 	if (adev->class == ATA_DEV_ATA) {
 		if (hpt_dma_blacklisted(adev, "UDMA",  bad_ata33))
@@ -185,7 +184,7 @@ static unsigned long hpt366_filter(const
 		if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
 			mask &= ~(0x0F << ATA_SHIFT_UDMA);
 	}
-	return ata_pci_default_filter(ap, adev, mask);
+	return ata_pci_default_filter(adev, mask);
 }
 
 /**
@@ -210,25 +209,29 @@ static u32 hpt36x_find_mode(struct ata_p
 	return 0xffffffffU;	/* silence compiler warning */
 }
 
-static int hpt36x_pre_reset(struct ata_port *ap)
+static int hpt36x_cable_detect(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))
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
+}
+
+static int hpt36x_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits hpt36x_enable_bits[] = {
 		{ 0x50, 1, 0x04, 0x04 },
 		{ 0x54, 1, 0x04, 0x04 }
 	};
-
-	u8 ata66;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	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);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -354,6 +357,7 @@ static struct ata_port_operations hpt366
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= hpt36x_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= hpt36x_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index f331eee..1614e8c 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,6 +8,7 @@
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * Portions Copyright (C) 2003		Red Hat Inc
+ * Portions Copyright (C) 2005-2006	MontaVista Software, Inc.
  *
  * TODO
  *	PLL mode
@@ -25,7 +26,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_hpt37x"
-#define DRV_VERSION	"0.6.0"
+#define DRV_VERSION	"0.6.5"
 
 struct hpt_clock {
 	u8	xfer_speed;
@@ -61,201 +62,75 @@ struct hpt_chip {
  * 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 struct hpt_clock hpt37x_timings_33[] = {
+	{ XFER_UDMA_6,		0x12446231 },	/* 0x12646231 ?? */
+	{ 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 }
 };
 
-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	}
+static struct hpt_clock hpt37x_timings_50[] = {
+	{ XFER_UDMA_6,		0x12848242 },
+	{ 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 }
 };
 
-/* 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	}
+static struct hpt_clock hpt37x_timings_66[] = {
+	{ XFER_UDMA_6,		0x1c869c62 },
+	{ XFER_UDMA_5,		0x1cae9c62 },	/* 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,	0x2c829d2e },
+
+	{ XFER_PIO_4,		0x0c829c62 },
+	{ XFER_PIO_3,		0x0c829c84 },
+	{ XFER_PIO_2,		0x0c829ca6 },
+	{ XFER_PIO_1,		0x0d029d26 },
+	{ XFER_PIO_0,		0x0d029d5e }
 };
 
-/* 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,
+		hpt37x_timings_33,
 		NULL,
 		NULL,
-		hpt370_timings_66
+		NULL
 	}
 };
 
@@ -263,10 +138,10 @@ static const struct hpt_chip hpt370a = {
 	"HPT370A",
 	48,
 	{
-		hpt370a_timings_33,
+		hpt37x_timings_33,
 		NULL,
-		hpt370a_timings_50,
-		hpt370a_timings_66
+		hpt37x_timings_50,
+		NULL
 	}
 };
 
@@ -274,10 +149,10 @@ static const struct hpt_chip hpt372 = {
 	"HPT372",
 	55,
 	{
-		hpt372_timings_33,
+		hpt37x_timings_33,
 		NULL,
-		hpt372_timings_50,
-		hpt372_timings_66
+		hpt37x_timings_50,
+		hpt37x_timings_66
 	}
 };
 
@@ -285,10 +160,10 @@ static const struct hpt_chip hpt302 = {
 	"HPT302",
 	66,
 	{
-		hpt372_timings_33,
+		hpt37x_timings_33,
 		NULL,
-		hpt372_timings_50,
-		hpt372_timings_66
+		hpt37x_timings_50,
+		hpt37x_timings_66
 	}
 };
 
@@ -296,10 +171,10 @@ static const struct hpt_chip hpt371 = {
 	"HPT371",
 	66,
 	{
-		hpt372_timings_33,
+		hpt37x_timings_33,
 		NULL,
-		hpt372_timings_50,
-		hpt372_timings_66
+		hpt37x_timings_50,
+		hpt37x_timings_66
 	}
 };
 
@@ -307,10 +182,10 @@ static const struct hpt_chip hpt372a = {
 	"HPT372A",
 	66,
 	{
-		hpt372_timings_33,
+		hpt37x_timings_33,
 		NULL,
-		hpt372_timings_50,
-		hpt372_timings_66
+		hpt37x_timings_50,
+		hpt37x_timings_66
 	}
 };
 
@@ -318,7 +193,7 @@ static const struct hpt_chip hpt374 = {
 	"HPT374",
 	48,
 	{
-		hpt374_timings_33,
+		hpt37x_timings_33,
 		NULL,
 		NULL,
 		NULL
@@ -397,13 +272,12 @@ static const char *bad_ata100_5[] = {
 
 /**
  *	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)
+static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
 {
 	if (adev->class == ATA_DEV_ATA) {
 		if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -411,34 +285,34 @@ static unsigned long hpt370_filter(const
 		if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
 			mask &= ~(0x1F << ATA_SHIFT_UDMA);
 	}
-	return ata_pci_default_filter(ap, adev, mask);
+	return ata_pci_default_filter(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)
+static unsigned long hpt370a_filter(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);
+	return ata_pci_default_filter(adev, mask);
 }
 
 /**
  *	hpt37x_pre_reset	-	reset the hpt37x bus
  *	@ap: ATA port to reset
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform the initial reset handling for the 370/372 and 374 func 0
  */
 
-static int hpt37x_pre_reset(struct ata_port *ap)
+static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	u8 scr2, ata66;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -462,11 +336,10 @@ static int hpt37x_pre_reset(struct ata_p
 		ap->cbl = ATA_CBL_PATA80;
 
 	/* Reset the state machine */
-	pci_write_config_byte(pdev, 0x50, 0x37);
-	pci_write_config_byte(pdev, 0x54, 0x37);
+	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -481,7 +354,7 @@ static void hpt37x_error_handler(struct 
 	ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
-static int hpt374_pre_reset(struct ata_port *ap)
+static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits hpt37x_enable_bits[] = {
 		{ 0x50, 1, 0x04, 0x04 },
@@ -513,11 +386,10 @@ static int hpt374_pre_reset(struct ata_p
 		ap->cbl = ATA_CBL_PATA80;
 
 	/* Reset the state machine */
-	pci_write_config_byte(pdev, 0x50, 0x37);
-	pci_write_config_byte(pdev, 0x54, 0x37);
+	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -1032,6 +904,24 @@ static int hpt37x_init_one(struct pci_de
 		.udma_mask = 0x3f,
 		.port_ops = &hpt370a_port_ops
 	};
+	/* HPT370 - UDMA100 */
+	static struct ata_port_info info_hpt370_33 = {
+		.sht = &hpt37x_sht,
+		.flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+		.pio_mask = 0x1f,
+		.mwdma_mask = 0x07,
+		.udma_mask = 0x0f,
+		.port_ops = &hpt370_port_ops
+	};
+	/* HPT370A - UDMA100 */
+	static struct ata_port_info info_hpt370a_33 = {
+		.sht = &hpt37x_sht,
+		.flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+		.pio_mask = 0x1f,
+		.mwdma_mask = 0x07,
+		.udma_mask = 0x0f,
+		.port_ops = &hpt370a_port_ops
+	};
 	/* HPT371, 372 and friends - UDMA133 */
 	static struct ata_port_info info_hpt372 = {
 		.sht = &hpt37x_sht,
@@ -1067,7 +957,11 @@ static int hpt37x_init_one(struct pci_de
 
 	u8 irqmask;
 	u32 class_rev;
+	u8 mcr1;
 	u32 freq;
+	int prefer_dpll = 1;
+	
+	unsigned long iobase = pci_resource_start(dev, 4);
 
 	const struct hpt_chip *chip_table;
 	int clock_slot;
@@ -1088,10 +982,12 @@ static int hpt37x_init_one(struct pci_de
 			case 3:
 				port = &info_hpt370;
 				chip_table = &hpt370;
+				prefer_dpll = 0;
 				break;
 			case 4:
 				port = &info_hpt370a;
 				chip_table = &hpt370a;
+				prefer_dpll = 0;
 				break;
 			case 5:
 				port = &info_hpt372;
@@ -1119,8 +1015,16 @@ static int hpt37x_init_one(struct pci_de
 				chip_table = &hpt302;
 				break;
 			case PCI_DEVICE_ID_TTI_HPT371:
+				if (class_rev > 1)
+					return -ENODEV;
 				port = &info_hpt372;
 				chip_table = &hpt371;
+				/* Single channel device, master is not present
+				   but the BIOS (or us for non x86) must mark it
+				   absent */
+				pci_read_config_byte(dev, 0x50, &mcr1);
+				mcr1 &= ~0x04;
+				pci_write_config_byte(dev, 0x50, mcr1);
 				break;
 			case PCI_DEVICE_ID_TTI_HPT374:
 				chip_table = &hpt374;
@@ -1150,8 +1054,18 @@ static int hpt37x_init_one(struct pci_de
 	 */
 
 	pci_write_config_byte(dev, 0x5b, 0x23);
+	
+	/*
+	 * HighPoint does this for HPT372A.
+	 * NOTE: This register is only writeable via I/O space.
+	 */
+	if (chip_table == &hpt372a)
+		outb(0x0e, iobase + 0x9c);
 
-	pci_read_config_dword(dev, 0x70, &freq);
+	/* Some devices do not let this value be accessed via PCI space
+	   according to the old driver */
+
+	freq = inl(iobase + 0x90);
 	if ((freq >> 12) != 0xABCDE) {
 		int i;
 		u8 sr;
@@ -1162,7 +1076,7 @@ static int hpt37x_init_one(struct pci_de
 		/* 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;
+			total += sr & 0x1FF;
 			udelay(15);
 		}
 		freq = total / 128;
@@ -1173,15 +1087,27 @@ static int hpt37x_init_one(struct pci_de
 	 *	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) {
+	if (chip_table->clocks[clock_slot] == NULL || prefer_dpll) {
 		/*
 		 *	We need to try PLL mode instead
+		 *
+		 *	For non UDMA133 capable devices we should
+		 *	use a 50MHz DPLL by choice
 		 */
-		unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
-		unsigned int f_high = f_low + 2;
+		unsigned int f_low, f_high;
 		int adjust;
+		
+		clock_slot = 2;
+		if (port->udma_mask & 0xE0)
+			clock_slot = 3;
+		
+		f_low = (MHz[clock_slot] * chip_table->base) / 192;
+		f_high = f_low + 2;
+
+		/* Select the DPLL clock. */
+		pci_write_config_byte(dev, 0x5b, 0x21);
 
 		for(adjust = 0; adjust < 8; adjust++) {
 			if (hpt37x_calibrate_dpll(dev))
@@ -1197,25 +1123,27 @@ static int hpt37x_init_one(struct pci_de
 			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;
+		if (clock_slot == 3)
+			port->private_data = (void *)hpt37x_timings_66;
+		else
+			port->private_data = (void *)hpt37x_timings_50;
 
 		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();
-		}
+		 *	Perform a final fixup. Note that we will have used the
+		 *	DPLL on the HPT372 which means we don't have to worry
+		 *	about lack of UDMA133 support on lower clocks
+ 		 */
+
+		if (clock_slot < 2 && port == &info_hpt370)
+			port = &info_hpt370_33;
+		if (clock_slot < 2 && port == &info_hpt370a)
+			port = &info_hpt370a_33;
 		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);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 65f2e18..ea1037d 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,10 +8,10 @@
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * Portions Copyright (C) 2003		Red Hat Inc
+ * Portions Copyright (C) 2005-2006	MontaVista Software, Inc.
  *
  *
  * TODO
- *	371N
  *	Work out best PLL policy
  */
 
@@ -25,7 +25,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_hpt3x2n"
-#define DRV_VERSION	"0.3.2"
+#define DRV_VERSION	"0.3.3"
 
 enum {
 	HPT_PCI_FAST	=	(1 << 31),
@@ -115,14 +115,13 @@ static u32 hpt3x2n_find_mode(struct ata_
 }
 
 /**
- *	hpt3x2n_pre_reset	-	reset the hpt3x2n bus
- *	@ap: ATA port to reset
+ *	hpt3x2n_cable_detect	-	Detect the cable type
+ *	@ap: ATA port to detect on
  *
- *	Perform the initial reset handling for the 3x2n series controllers.
- *	Reset the hardware and state machine, obtain the cable type.
+ *	Return the cable type attached to this port
  */
 
-static int hpt3xn_pre_reset(struct ata_port *ap)
+static int hpt3x2n_cable_detect(struct ata_port *ap)
 {
 	u8 scr2, ata66;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -135,16 +134,28 @@ static int hpt3xn_pre_reset(struct ata_p
 	pci_write_config_byte(pdev, 0x5B, scr2);
 
 	if (ata66 & (1 << ap->port_no))
-		ap->cbl = ATA_CBL_PATA40;
+		return ATA_CBL_PATA40;
 	else
-		ap->cbl = ATA_CBL_PATA80;
+		return ATA_CBL_PATA80;
+}
+
+/**
+ *	hpt3x2n_pre_reset	-	reset the hpt3x2n bus
+ *	@ap: ATA port to reset
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	Perform the initial reset handling for the 3x2n series controllers.
+ *	Reset the hardware and state machine,
+ */
 
+static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	/* Reset the state machine */
-	pci_write_config_byte(pdev, 0x50, 0x37);
-	pci_write_config_byte(pdev, 0x54, 0x37);
+	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -364,6 +375,7 @@ static struct ata_port_operations hpt3x2
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= hpt3x2n_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= hpt3x2n_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -422,8 +434,9 @@ static int hpt3x2n_pci_clock(struct pci_
 {
 	unsigned long freq;
 	u32 fcnt;
+	unsigned long iobase = pci_resource_start(pdev, 4);
 
-	pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
+	fcnt = inl(iobase + 0x90);	/* Not PCI readable for some chips */
 	if ((fcnt >> 12) != 0xABCDE) {
 		printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
 		return 33;	/* Not BIOS set */
@@ -492,6 +505,7 @@ static int hpt3x2n_init_one(struct pci_d
 	unsigned int pci_mhz;
 	unsigned int f_low, f_high;
 	int adjust;
+	unsigned long iobase = pci_resource_start(dev, 4);
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xFF;
@@ -501,6 +515,11 @@ static int hpt3x2n_init_one(struct pci_d
 			if (class_rev < 6)
 				return -ENODEV;
 			break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			if (class_rev < 2)
+				return -ENODEV;
+			/* 371N if rev > 1 */
+			break;
 		case PCI_DEVICE_ID_TTI_HPT372:
 			/* 372N if rev >= 1*/
 			if (class_rev == 0)
@@ -528,6 +547,19 @@ static int hpt3x2n_init_one(struct pci_d
 	irqmask &= ~0x10;
 	pci_write_config_byte(dev, 0x5a, irqmask);
 
+	/*
+	 * HPT371 chips physically have only one channel, the secondary one,
+	 * but the primary channel registers do exist!  Go figure...
+	 * So,  we manually disable the non-existing channel here
+	 * (if the BIOS hasn't done this already).
+	 */
+	if (dev->device == PCI_DEVICE_ID_TTI_HPT371) {
+		u8 mcr1;
+		pci_read_config_byte(dev, 0x50, &mcr1);
+		mcr1 &= ~0x04;
+		pci_write_config_byte(dev, 0x50, mcr1);
+	}
+
 	/* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
 	   50 for UDMA100. Right now we always use 66 */
 
@@ -546,14 +578,24 @@ static int hpt3x2n_init_one(struct pci_d
 			break;
 		pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
 	}
-	if (adjust == 8)
-		printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
+	if (adjust == 8) {
+		printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n");
+		return -ENODEV;
+	}
 
 	/* Set our private data up. We only need a few flags so we use
 	   it directly */
 	port->private_data = NULL;
-	if (pci_mhz > 60)
+	if (pci_mhz > 60) {
 		port->private_data = (void *)PCI66;
+		/*
+		 * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+		 * the MISC. register to stretch the UltraDMA Tss timing.
+		 * NOTE: This register is only writeable via I/O space.
+		 */
+		if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+			outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
+	}
 
 	/* Now kick off ATA set up */
 	port_info[0] = port_info[1] = port;
@@ -562,6 +604,7 @@ static int hpt3x2n_init_one(struct pci_d
 
 static const struct pci_device_id hpt3x2n[] = {
 	{ 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_HPT302), },
 	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 813485c..ac28ec8 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -25,25 +25,6 @@ #include <linux/libata.h>
 #define DRV_NAME	"pata_hpt3x3"
 #define DRV_VERSION	"0.4.2"
 
-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
@@ -139,8 +120,9 @@ static struct ata_port_operations hpt3x3
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= hpt3x3_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
new file mode 100644
index 0000000..dbc8ee2
--- /dev/null
+++ b/drivers/ata/pata_icside.c
@@ -0,0 +1,686 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define DRV_NAME	"pata_icside"
+
+#define ICS_IDENT_OFFSET		0x2280
+
+#define ICS_ARCIN_V5_INTRSTAT		0x0000
+#define ICS_ARCIN_V5_INTROFFSET		0x0004
+
+#define ICS_ARCIN_V6_INTROFFSET_1	0x2200
+#define ICS_ARCIN_V6_INTRSTAT_1		0x2290
+#define ICS_ARCIN_V6_INTROFFSET_2	0x3200
+#define ICS_ARCIN_V6_INTRSTAT_2		0x3290
+
+struct portinfo {
+	unsigned int dataoffset;
+	unsigned int ctrloffset;
+	unsigned int stepping;
+};
+
+static const struct portinfo pata_icside_portinfo_v5 = {
+	.dataoffset	= 0x2800,
+	.ctrloffset	= 0x2b80,
+	.stepping	= 6,
+};
+
+static const struct portinfo pata_icside_portinfo_v6_1 = {
+	.dataoffset	= 0x2000,
+	.ctrloffset	= 0x2380,
+	.stepping	= 6,
+};
+
+static const struct portinfo pata_icside_portinfo_v6_2 = {
+	.dataoffset	= 0x3000,
+	.ctrloffset	= 0x3380,
+	.stepping	= 6,
+};
+
+#define PATA_ICSIDE_MAX_SG	128
+
+struct pata_icside_state {
+	void __iomem *irq_port;
+	void __iomem *ioc_base;
+	unsigned int type;
+	unsigned int dma;
+	struct {
+		u8 port_sel;
+		u8 disabled;
+		unsigned int speed[ATA_MAX_DEVICES];
+	} port[2];
+	struct scatterlist sg[PATA_ICSIDE_MAX_SG];
+};
+
+#define ICS_TYPE_A3IN	0
+#define ICS_TYPE_A3USER	1
+#define ICS_TYPE_V6	3
+#define ICS_TYPE_V5	15
+#define ICS_TYPE_NOTYPE	((unsigned int)-1)
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	struct pata_icside_state *state = ec->irq_data;
+
+	writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	struct pata_icside_state *state = ec->irq_data;
+
+	readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t pata_icside_ops_arcin_v5 = {
+	.irqenable	= pata_icside_irqenable_arcin_v5,
+	.irqdisable	= pata_icside_irqdisable_arcin_v5,
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	struct pata_icside_state *state = ec->irq_data;
+	void __iomem *base = state->irq_port;
+
+	if (!state->port[0].disabled)
+		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+	if (!state->port[1].disabled)
+		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	struct pata_icside_state *state = ec->irq_data;
+
+	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: pata_icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+	struct pata_icside_state *state = ec->irq_data;
+
+	return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t pata_icside_ops_arcin_v6 = {
+	.irqenable	= pata_icside_irqenable_arcin_v6,
+	.irqdisable	= pata_icside_irqdisable_arcin_v6,
+	.irqpending	= pata_icside_irqpending_arcin_v6,
+};
+
+
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time.  NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+
+/*
+ * Configure the IOMD to give the appropriate timings for the transfer
+ * mode being requested.  We take the advice of the ATA standards, and
+ * calculate the cycle time based on the transfer mode, and the EIDE
+ * MW DMA specs that the drive provides in the IDENTIFY command.
+ *
+ * We have the following IOMD DMA modes to choose from:
+ *
+ *	Type	Active		Recovery	Cycle
+ *	A	250 (250)	312 (550)	562 (800)
+ *	B	187 (200)	250 (550)	437 (750)
+ *	C	125 (125)	125 (375)	250 (500)
+ *	D	62  (50)	125 (375)	187 (425)
+ *
+ * (figures in brackets are actual measured timings on DIOR/DIOW)
+ *
+ * However, we also need to take care of the read/write active and
+ * recovery timings:
+ *
+ *			Read	Write
+ *  	Mode	Active	-- Recovery --	Cycle	IOMD type
+ *	MW0	215	50	215	480	A
+ *	MW1	80	50	50	150	C
+ *	MW2	70	25	25	120	C
+ */
+static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct pata_icside_state *state = ap->host->private_data;
+	struct ata_timing t;
+	unsigned int cycle;
+	char iomd_type;
+
+	/*
+	 * DMA is based on a 16MHz clock
+	 */
+	if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1))
+		return;
+
+	/*
+	 * Choose the IOMD cycle timing which ensure that the interface
+	 * satisfies the measured active, recovery and cycle times.
+	 */
+	if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425)
+		iomd_type = 'D', cycle = 187;
+	else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500)
+		iomd_type = 'C', cycle = 250;
+	else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750)
+		iomd_type = 'B', cycle = 437;
+	else
+		iomd_type = 'A', cycle = 562;
+
+	ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n",
+		t.active, t.recover, t.cycle, iomd_type);
+
+	state->port[ap->port_no].speed[adev->devno] = cycle;
+}
+
+static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pata_icside_state *state = ap->host->private_data;
+	struct scatterlist *sg, *rsg = state->sg;
+	unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
+
+	/*
+	 * We are simplex; BUG if we try to fiddle with DMA
+	 * while it's active.
+	 */
+	BUG_ON(dma_channel_active(state->dma));
+
+	/*
+	 * Copy ATAs scattered sg list into a contiguous array of sg
+	 */
+	ata_for_each_sg(sg, qc) {
+		memcpy(rsg, sg, sizeof(*sg));
+		rsg++;
+	}
+
+	/*
+	 * Route the DMA signals to the correct interface
+	 */
+	writeb(state->port[ap->port_no].port_sel, state->ioc_base);
+
+	set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);
+	set_dma_sg(state->dma, state->sg, rsg - state->sg);
+	set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);
+
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+}
+
+static void pata_icside_bmdma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pata_icside_state *state = ap->host->private_data;
+
+	BUG_ON(dma_channel_active(state->dma));
+	enable_dma(state->dma);
+}
+
+static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pata_icside_state *state = ap->host->private_data;
+
+	disable_dma(state->dma);
+
+	/* see ata_bmdma_stop */
+	ata_altstatus(ap);
+}
+
+static u8 pata_icside_bmdma_status(struct ata_port *ap)
+{
+	struct pata_icside_state *state = ap->host->private_data;
+	void __iomem *irq_port;
+
+	irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 :
+						    ICS_ARCIN_V6_INTRSTAT_1);
+
+	return readb(irq_port) & 1 ? ATA_DMA_INTR : 0;
+}
+
+static int icside_dma_init(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+	struct pata_icside_state *state = ae->private_data;
+	int i;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		state->port[0].speed[i] = 480;
+		state->port[1].speed[i] = 480;
+	}
+
+	if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
+		state->dma = ec->dma;
+		ae->mwdma_mask = 0x07;	/* MW0..2 */
+	}
+
+	return 0;
+}
+
+
+static int pata_icside_port_start(struct ata_port *ap)
+{
+	/* No PRD to alloc */
+	return ata_pad_alloc(ap, ap->dev);
+}
+
+static struct scsi_host_template pata_icside_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		= PATA_ICSIDE_MAX_SG,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ~0, /* no dma boundaries */
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+};
+
+/* wish this was exported from libata-core */
+static void ata_dummy_noret(struct ata_port *port)
+{
+}
+
+/*
+ * We need to shut down unused ports to prevent spurious interrupts.
+ * FIXME: the libata core doesn't call this function for PATA interfaces.
+ */
+static void pata_icside_port_disable(struct ata_port *ap)
+{
+	struct pata_icside_state *state = ap->host->private_data;
+
+	ata_port_printk(ap, KERN_ERR, "disabling icside port\n");
+
+	ata_port_disable(ap);
+
+	state->port[ap->port_no].disabled = 1;
+
+	if (state->type == ICS_TYPE_V6) {
+		/*
+		 * Disable interrupts from this port, otherwise we
+		 * receive spurious interrupts from the floating
+		 * interrupt line.
+		 */
+		void __iomem *irq_port = state->irq_port +
+				(ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1);
+		readb(irq_port);
+	}
+}
+
+static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+	u8 status;
+
+	status = ata_busy_wait(ap, bits, 1000);
+	if (status & bits)
+		if (ata_msg_err(ap))
+			printk(KERN_ERR "abnormal status 0x%X\n", status);
+
+	if (ata_msg_intr(ap))
+		printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
+			__FUNCTION__, status);
+
+	return status;
+}
+
+static struct ata_port_operations pata_icside_port_ops = {
+	.port_disable		= pata_icside_port_disable,
+
+	.set_dmamode		= pata_icside_set_dmamode,
+
+	.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		= pata_icside_bmdma_setup,
+	.bmdma_start		= pata_icside_bmdma_start,
+
+	.data_xfer		= ata_data_xfer_noirq,
+
+	/* no need to build any PRD tables for DMA */
+	.qc_prep		= ata_noop_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= ata_bmdma_error_handler,
+	.post_internal_cmd	= pata_icside_bmdma_stop,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_dummy_noret,
+	.irq_on			= ata_irq_on,
+	.irq_ack		= pata_icside_irq_ack,
+
+	.port_start		= pata_icside_port_start,
+
+	.bmdma_stop		= pata_icside_bmdma_stop,
+	.bmdma_status		= pata_icside_bmdma_status,
+};
+
+static void
+pata_icside_add_port(struct ata_probe_ent *ae, void __iomem *base,
+		     const struct portinfo *info)
+{
+	struct ata_ioports *ioaddr = &ae->port[ae->n_ports++];
+	void __iomem *cmd = base + info->dataoffset;
+
+	ioaddr->cmd_addr	= cmd;
+	ioaddr->data_addr	= cmd + (ATA_REG_DATA    << info->stepping);
+	ioaddr->error_addr	= cmd + (ATA_REG_ERR     << info->stepping);
+	ioaddr->feature_addr	= cmd + (ATA_REG_FEATURE << info->stepping);
+	ioaddr->nsect_addr	= cmd + (ATA_REG_NSECT   << info->stepping);
+	ioaddr->lbal_addr	= cmd + (ATA_REG_LBAL    << info->stepping);
+	ioaddr->lbam_addr	= cmd + (ATA_REG_LBAM    << info->stepping);
+	ioaddr->lbah_addr	= cmd + (ATA_REG_LBAH    << info->stepping);
+	ioaddr->device_addr	= cmd + (ATA_REG_DEVICE  << info->stepping);
+	ioaddr->status_addr	= cmd + (ATA_REG_STATUS  << info->stepping);
+	ioaddr->command_addr	= cmd + (ATA_REG_CMD     << info->stepping);
+
+	ioaddr->ctl_addr	= base + info->ctrloffset;
+	ioaddr->altstatus_addr	= ioaddr->ctl_addr;
+}
+
+static int __init
+pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+	struct pata_icside_state *state = ae->private_data;
+	void __iomem *base;
+
+	base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+		       ecard_resource_len(ec, ECARD_RES_MEMC));
+	if (!base)
+		return -ENOMEM;
+
+	state->irq_port = base;
+
+	ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
+	ec->irqmask = 1;
+	ec->irq_data = state;
+	ec->ops = &pata_icside_ops_arcin_v5;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	ec->ops->irqdisable(ec, ec->irq);
+
+	pata_icside_add_port(ae, base, &pata_icside_portinfo_v5);
+
+	return 0;
+}
+
+static int __init
+pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+	struct pata_icside_state *state = ae->private_data;
+	void __iomem *ioc_base, *easi_base;
+	unsigned int sel = 0;
+	int ret;
+
+	ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+			   ecard_resource_len(ec, ECARD_RES_IOCFAST));
+	if (!ioc_base) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	easi_base = ioc_base;
+
+	if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+		easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI),
+				    ecard_resource_len(ec, ECARD_RES_EASI));
+		if (!easi_base) {
+			ret = -ENOMEM;
+			goto unmap_slot;
+		}
+
+		/*
+		 * Enable access to the EASI region.
+		 */
+		sel = 1 << 5;
+	}
+
+	writeb(sel, ioc_base);
+
+	ec->irq_data = state;
+	ec->ops = &pata_icside_ops_arcin_v6;
+
+	state->irq_port = easi_base;
+	state->ioc_base = ioc_base;
+	state->port[0].port_sel = sel;
+	state->port[1].port_sel = sel | 1;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	ec->ops->irqdisable(ec, ec->irq);
+
+	/*
+	 * Find and register the interfaces.
+	 */
+	pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_1);
+	pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_2);
+
+	/*
+	 * FIXME: work around libata's aversion to calling port_disable.
+	 * This permanently disables interrupts on port 0 - bad luck if
+	 * you have a drive on that port.
+	 */
+	state->port[0].disabled = 1;
+
+	return icside_dma_init(ae, ec);
+
+ unmap_slot:
+	iounmap(ioc_base);
+ out:
+	return ret;
+}
+
+static int __devinit
+pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct pata_icside_state *state;
+	struct ata_probe_ent ae;
+	void __iomem *idmem;
+	int ret;
+
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
+	state = kzalloc(sizeof(struct pata_icside_state), GFP_KERNEL);
+	if (!state) {
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	state->type = ICS_TYPE_NOTYPE;
+	state->dma = NO_DMA;
+
+	idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+			ecard_resource_len(ec, ECARD_RES_IOCFAST));
+	if (idmem) {
+		unsigned int type;
+
+		type = readb(idmem + ICS_IDENT_OFFSET) & 1;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
+		iounmap(idmem);
+
+		state->type = type;
+	}
+
+	memset(&ae, 0, sizeof(ae));
+	INIT_LIST_HEAD(&ae.node);
+	ae.dev          = &ec->dev;
+	ae.port_ops     = &pata_icside_port_ops;
+	ae.sht          = &pata_icside_sht;
+	ae.pio_mask     = 0x1f;
+	ae.irq          = ec->irq;
+	ae.port_flags   = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+	ae._host_flags  = ATA_HOST_SIMPLEX;
+	ae.private_data = state;
+
+	switch (state->type) {
+	case ICS_TYPE_A3IN:
+		dev_warn(&ec->dev, "A3IN unsupported\n");
+		ret = -ENODEV;
+		break;
+
+	case ICS_TYPE_A3USER:
+		dev_warn(&ec->dev, "A3USER unsupported\n");
+		ret = -ENODEV;
+		break;
+
+	case ICS_TYPE_V5:
+		ret = pata_icside_register_v5(&ae, ec);
+		break;
+
+	case ICS_TYPE_V6:
+		ret = pata_icside_register_v6(&ae, ec);
+		break;
+
+	default:
+		dev_warn(&ec->dev, "unknown interface type\n");
+		ret = -ENODEV;
+		break;
+	}
+
+	if (ret == 0)
+		ret = ata_device_add(&ae) == 0 ? -ENODEV : 0;
+
+	if (ret == 0)
+		goto out;
+
+	kfree(state);
+ release:
+	ecard_release_resources(ec);
+ out:
+	return ret;
+}
+
+static void pata_icside_shutdown(struct expansion_card *ec)
+{
+	struct ata_host *host = ecard_get_drvdata(ec);
+	unsigned long flags;
+
+	/*
+	 * Disable interrupts from this card.  We need to do
+	 * this before disabling EASI since we may be accessing
+	 * this register via that region.
+	 */
+	local_irq_save(flags);
+	if (ec->ops)
+		ec->ops->irqdisable(ec, ec->irq);
+	local_irq_restore(flags);
+
+	/*
+	 * Reset the ROM pointer so that we can read the ROM
+	 * after a soft reboot.  This also disables access to
+	 * the IDE taskfile via the EASI region.
+	 */
+	if (host) {
+		struct pata_icside_state *state = host->private_data;
+		if (state->ioc_base)
+			writeb(0, state->ioc_base);
+	}
+}
+
+static void __devexit pata_icside_remove(struct expansion_card *ec)
+{
+	struct ata_host *host = ecard_get_drvdata(ec);
+	struct pata_icside_state *state = host->private_data;
+
+	ata_host_detach(host);
+
+	pata_icside_shutdown(ec);
+
+	/*
+	 * don't NULL out the drvdata - devres/libata wants it
+	 * to free the ata_host structure.
+	 */
+	ec->ops = NULL;
+	ec->irq_data = NULL;
+
+	if (state->dma != NO_DMA)
+		free_dma(state->dma);
+	if (state->ioc_base)
+		iounmap(state->ioc_base);
+	if (state->ioc_base != state->irq_port)
+		iounmap(state->irq_port);
+
+	kfree(state);
+	ecard_release_resources(ec);
+}
+
+static const struct ecard_id pata_icside_ids[] = {
+	{ MANU_ICS,  PROD_ICS_IDE  },
+	{ MANU_ICS2, PROD_ICS2_IDE },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver pata_icside_driver = {
+	.probe		= pata_icside_probe,
+	.remove 	= __devexit_p(pata_icside_remove),
+	.shutdown	= pata_icside_shutdown,
+	.id_table	= pata_icside_ids,
+	.drv = {
+		.name	= DRV_NAME,
+	},
+};
+
+static int __init pata_icside_init(void)
+{
+	return ecard_register_driver(&pata_icside_driver);
+}
+
+static void __exit pata_icside_exit(void)
+{
+	ecard_remove_driver(&pata_icside_driver);
+}
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ICS PATA driver");
+
+module_init(pata_icside_init);
+module_exit(pata_icside_exit);
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 1a61cc8..d042efd 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -49,13 +49,13 @@ static struct ata_port_operations isapnp
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
 
 	.data_xfer	= ata_data_xfer,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -74,8 +74,10 @@ static struct ata_port_operations isapnp
 
 static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
 {
-	struct ata_probe_ent ae;
+	struct ata_host *host;
+	struct ata_port *ap;
 	void __iomem *cmd_addr, *ctl_addr;
+	int rc;
 
 	if (pnp_port_valid(idev, 0) == 0)
 		return -ENODEV;
@@ -84,34 +86,36 @@ static int isapnp_init_one(struct pnp_de
 	if (pnp_irq_valid(idev, 0) == 0)
 		return -ENODEV;
 
+	/* allocate host */
+	host = ata_host_alloc(&idev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
 	if (!cmd_addr)
 		return -ENOMEM;
 
-	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 = cmd_addr;
+	ap = host->ports[0];
+
+	ap->ops = &isapnp_port_ops;
+	ap->pio_mask = 1;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+	ap->ioaddr.cmd_addr = cmd_addr;
 
 	if (pnp_port_valid(idev, 1) == 0) {
 		ctl_addr = devm_ioport_map(&idev->dev,
 					   pnp_port_start(idev, 1), 1);
-		ae.port[0].altstatus_addr = ctl_addr;
-		ae.port[0].ctl_addr = ctl_addr;
-		ae.port_flags |= ATA_FLAG_SRST;
+		ap->ioaddr.altstatus_addr = ctl_addr;
+		ap->ioaddr.ctl_addr = ctl_addr;
 	}
-	ata_std_ports(&ae.port[0]);
 
-	if (ata_device_add(&ae) == 0)
-		return -ENODEV;
-	return 0;
+	ata_std_ports(&ap->ioaddr);
+
+	/* activate */
+	return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
+				 &isapnp_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index ea73470..17bf9f3 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -24,33 +24,26 @@ #define DRV_VERSION	"0.0.2"
 /**
  *	it8213_pre_reset	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
- *	Perform cable detection for the 8213 ATA interface. This is
- *	different to the PIIX arrangement
+ *	Filter out ports by the enable bits before doing the normal reset
+ *	and probe.
  */
 
-static int it8213_pre_reset(struct ata_port *ap)
+static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits it8213_enable_bits[] = {
 		{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
 	};
-
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u8 tmp;
-
 	if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	pci_read_config_byte(pdev, 0x42, &tmp);
-	if (tmp & 2)	/* The initial docs are incorrect */
-		ap->cbl = ATA_CBL_PATA40;
-	else
-		ap->cbl = ATA_CBL_PATA80;
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
- *	it8213_probe_reset - Probe specified port on PATA host controller
+ *	it8213_error_handler - Probe specified port on PATA host controller
  *	@ap: Port to probe
  *
  *	LOCKING:
@@ -63,9 +56,27 @@ static void it8213_error_handler(struct 
 }
 
 /**
+ *	it8213_cable_detect	-	check for 40/80 pin
+ *	@ap: Port
+ *
+ *	Perform cable detection for the 8213 ATA interface. This is
+ *	different to the PIIX arrangement
+ */
+
+static int it8213_cable_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	u8 tmp;
+	pci_read_config_byte(pdev, 0x42, &tmp);
+	if (tmp & 2)	/* The initial docs are incorrect */
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
+}
+
+/**
  *	it8213_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
- *	@adev: um
+ *	@adev: Device whose timings we are configuring
  *
  *	Set PIO mode for device, in host controller PCI config space.
  *
@@ -268,6 +279,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= it8213_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= it8213_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 35ecb2b..f1f8cec 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@ #include <linux/libata.h>
 
 
 #define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.4"
+#define DRV_VERSION "0.3.6"
 
 struct it821x_dev
 {
@@ -113,31 +113,6 @@ #define MWDMA_OFF	0
 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
@@ -520,7 +495,6 @@ static int it821x_smart_set_mode(struct 
 
 /**
  *	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
@@ -531,7 +505,7 @@ static int it821x_smart_set_mode(struct 
  *	basically we need to filter commands for this chip.
  */
 
-static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void it821x_dev_config(struct ata_device *adev)
 {
 	unsigned char model_num[ATA_ID_PROD_LEN + 1];
 
@@ -667,8 +641,9 @@ static struct ata_port_operations it821x
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= it821x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_unknown,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -703,8 +678,9 @@ static struct ata_port_operations it821x
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= it821x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_unknown,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= it821x_passthru_bmdma_start,
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index c6f0e19..420c343 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -129,8 +129,8 @@ static struct ata_port_operations ixp4xx
 	.qc_issue	= ata_qc_issue_prot,
 	.eng_timeout	= ata_eng_timeout,
 	.data_xfer	= ixp4xx_mmio_data_xfer,
+	.cable_detect	= ata_cable_40wire,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ixp4xx_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -173,12 +173,12 @@ #endif
 
 static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
 {
-	int ret;
 	unsigned int irq;
 	struct resource *cs0, *cs1;
-	struct ata_probe_ent ae;
-
+	struct ata_host *host;
+	struct ata_port *ap;
 	struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+	int rc;
 
 	cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -186,6 +186,12 @@ static __devinit int ixp4xx_pata_probe(s
 	if (!cs0 || !cs1)
 		return -EINVAL;
 
+	/* allocate host */
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
 
 	data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
@@ -199,32 +205,22 @@ static __devinit int ixp4xx_pata_probe(s
 	*data->cs0_cfg = data->cs0_bits;
 	*data->cs1_cfg = data->cs1_bits;
 
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
+	ap = host->ports[0];
 
-	ae.dev		= &pdev->dev;
-	ae.port_ops	= &ixp4xx_port_ops;
-	ae.sht		= &ixp4xx_sht;
-	ae.n_ports	= 1;
-	ae.pio_mask	= 0x1f; /* PIO4 */
-	ae.irq		= irq;
-	ae.irq_flags	= 0;
-	ae.port_flags	= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
-			| ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
+	ap->ops	= &ixp4xx_port_ops;
+	ap->pio_mask = 0x1f; /* PIO4 */
+	ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
 
 	/* run in polling mode if no irq has been assigned */
 	if (!irq)
-		ae.port_flags |= ATA_FLAG_PIO_POLLING;
+		ap->flags |= ATA_FLAG_PIO_POLLING;
 
-	ixp4xx_setup_port(&ae.port[0], data);
+	ixp4xx_setup_port(&ap->ioaddr, data);
 
 	dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
-	ret = ata_device_add(&ae);
-	if (ret == 0)
-		return -ENODEV;
-
-	return 0;
+	/* activate host */
+	return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
 }
 
 static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 43763c9..1daf78a 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -30,16 +30,17 @@ typedef enum {
 /**
  *	jmicron_pre_reset	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	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)
+static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u32 control;
@@ -102,7 +103,7 @@ static int jmicron_pre_reset(struct ata_
 		ap->cbl = ATA_CBL_SATA;
 		break;
 	}
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 86fbcd6..7070992 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -162,6 +162,7 @@ static struct ata_port_operations simple
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -185,6 +186,7 @@ static struct ata_port_operations legacy
 	.check_status 	= ata_check_status,
 	.exec_command	= ata_exec_command,
 	.dev_select 	= ata_std_dev_select,
+	.cable_detect	= ata_cable_40wire,
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
@@ -305,6 +307,7 @@ static struct ata_port_operations pdc202
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -360,6 +363,7 @@ static struct ata_port_operations ht6560
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -426,6 +430,7 @@ static struct ata_port_operations ht6560
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -547,6 +552,7 @@ static struct ata_port_operations opti82
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
@@ -680,6 +686,7 @@ static struct ata_port_operations opti82
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= opti82c46x_qc_issue_prot,
@@ -709,7 +716,8 @@ static struct ata_port_operations opti82
 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 ata_host *host;
+	struct ata_port *ap;
 	struct platform_device *pdev;
 	struct ata_port_operations *ops = &legacy_port_ops;
 	void __iomem *io_addr, *ctrl_addr;
@@ -791,24 +799,23 @@ static __init int legacy_init_one(int po
 	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|iordy;
-	ae.port[0].cmd_addr = io_addr;
-	ae.port[0].altstatus_addr = ctrl_addr;
-	ae.port[0].ctl_addr = ctrl_addr;
-	ata_std_ports(&ae.port[0]);
-	ae.private_data = ld;
-
-	ret = -ENODEV;
-	if (!ata_device_add(&ae))
+	ret = -ENOMEM;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		goto fail;
+	ap = host->ports[0];
+
+	ap->ops = ops;
+	ap->pio_mask = pio_modes;
+	ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+	ap->ioaddr.cmd_addr = io_addr;
+	ap->ioaddr.altstatus_addr = ctrl_addr;
+	ap->ioaddr.ctl_addr = ctrl_addr;
+	ata_std_ports(&ap->ioaddr);
+	ap->private_data = ld;
+
+	ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+	if (ret)
 		goto fail;
 
 	legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 6dd7c4e..837b7fe 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -20,16 +20,17 @@ #include <linux/libata.h>
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_marvell"
-#define DRV_VERSION	"0.1.1"
+#define DRV_VERSION	"0.1.4"
 
 /**
  *	marvell_pre_reset	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform the PATA port setup we need.
  */
 
-static int marvell_pre_reset(struct ata_port *ap)
+static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u32 devices;
@@ -53,21 +54,24 @@ static int marvell_pre_reset(struct ata_
 	    (!(devices & 0x10)))	/* PATA enable ? */
 		return -ENOENT;
 
+	return ata_std_prereset(ap, deadline);
+}
+
+static int marvell_cable_detect(struct ata_port *ap)
+{
 	/* Cable type */
 	switch(ap->port_no)
 	{
 	case 0:
 		if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
-			ap->cbl = ATA_CBL_PATA40;
-		else
-			ap->cbl = ATA_CBL_PATA80;
-		break;
-
+			return ATA_CBL_PATA40;
+		return ATA_CBL_PATA80;
 	case 1: /* Legacy SATA port */
-		ap->cbl = ATA_CBL_SATA;
-		break;
+		return ATA_CBL_SATA;
 	}
-	return ata_std_prereset(ap);
+
+	BUG();
+	return 0;	/* Our BUG macro needs the right markup */
 }
 
 /**
@@ -123,6 +127,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= marvell_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= marvell_cable_detect,
 
 	/* BMDMA handling is PCI ATA format, use helpers */
 	.bmdma_setup		= ata_bmdma_setup,
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 882c36e..9587a89 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -24,7 +24,7 @@ #include <asm/mpc52xx.h>
 
 
 #define DRV_NAME	"mpc52xx_ata"
-#define DRV_VERSION	"0.1.0"
+#define DRV_VERSION	"0.1.0ac2"
 
 
 /* Private structures used by the driver */
@@ -297,38 +297,37 @@ static struct ata_port_operations mpc52x
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= mpc52xx_ata_error_handler,
+	.cable_detect		= ata_cable_40wire,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
 	.port_start		= ata_port_start,
 };
 
-static struct ata_probe_ent mpc52xx_ata_probe_ent = {
-	.port_ops	= &mpc52xx_ata_port_ops,
-	.sht		= &mpc52xx_ata_sht,
-	.n_ports	= 1,
-	.pio_mask	= 0x1f,		/* Up to PIO4 */
-	.mwdma_mask	= 0x00,		/* No MWDMA   */
-	.udma_mask	= 0x00,		/* No UDMA    */
-	.port_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
-	.irq_flags	= 0,
-};
-
 static int __devinit
 mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
 {
-	struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
-	struct ata_ioports *aio = &ae->port[0];
-	int rv;
-
-	INIT_LIST_HEAD(&ae->node);
-	ae->dev = dev;
-	ae->irq = priv->ata_irq;
-
+	struct ata_host *host;
+	struct ata_port *ap;
+	struct ata_ioports *aio;
+	int rc;
+
+	host = ata_host_alloc(dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	ap = host->ports[0];
+	ap->flags		|= ATA_FLAG_SLAVE_POSS;
+	ap->pio_mask		= 0x1f;	/* Up to PIO4 */
+	ap->mwdma_mask		= 0x00;	/* No MWDMA   */
+	ap->udma_mask		= 0x00;	/* No UDMA    */
+	ap->ops			= &mpc52xx_ata_port_ops;
+	host->private_data	= priv;
+
+	aio = &ap->ioaddr;
 	aio->cmd_addr		= NULL;	/* Don't have a classic reg block */
 	aio->altstatus_addr	= &priv->ata_regs->tf_control;
 	aio->ctl_addr		= &priv->ata_regs->tf_control;
@@ -343,11 +342,9 @@ mpc52xx_ata_init_one(struct device *dev,
 	aio->status_addr	= &priv->ata_regs->tf_command;
 	aio->command_addr	= &priv->ata_regs->tf_command;
 
-	ae->private_data = priv;
-
-	rv = ata_device_add(ae);
-
-	return rv ? 0 : -EINVAL;
+	/* activate host */
+	return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
+				 &mpc52xx_ata_sht);
 }
 
 static struct mpc52xx_ata_priv *
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4abe45a..3bfbd49 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.6"
 
 enum {
 	IDETIM = 0x6C,		/* IDE control register */
@@ -46,15 +46,15 @@ enum {
 	SECONDARY = (1 << 14)
 };
 
-static int mpiix_pre_reset(struct ata_port *ap)
+static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
 
 	if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
 		return -ENOENT;
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -185,12 +185,12 @@ static struct ata_port_operations mpiix_
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= mpiix_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= mpiix_qc_issue_prot,
 	.data_xfer	= ata_data_xfer,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -201,8 +201,9 @@ static struct ata_port_operations mpiix_
 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;
 	static int printed_version;
+	struct ata_host *host;
+	struct ata_port *ap;
 	void __iomem *cmd_addr, *ctl_addr;
 	u16 idetim;
 	int irq;
@@ -210,6 +211,10 @@ static int mpiix_init_one(struct pci_dev
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
 
+	host = ata_host_alloc(&dev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+
 	/* 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 */
@@ -238,27 +243,21 @@ static int mpiix_init_one(struct pci_dev
 	   without BARs set fools the setup.  #2 If you pci_disable_device
 	   the MPIIX your box goes castors up */
 
-	INIT_LIST_HEAD(&probe.node);
-	probe.dev = pci_dev_to_dev(dev);
-	probe.port_ops = &mpiix_port_ops;
-	probe.sht = &mpiix_sht;
-	probe.pio_mask = 0x1F;
-	probe.irq_flags = IRQF_SHARED;
-	probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-	probe.n_ports = 1;
+	ap = host->ports[0];
+	ap->ops = &mpiix_port_ops;
+	ap->pio_mask = 0x1F;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
 
-	probe.irq = irq;
-	probe.port[0].cmd_addr = cmd_addr;
-	probe.port[0].ctl_addr = ctl_addr;
-	probe.port[0].altstatus_addr = ctl_addr;
+	ap->ioaddr.cmd_addr = cmd_addr;
+	ap->ioaddr.ctl_addr = ctl_addr;
+	ap->ioaddr.altstatus_addr = ctl_addr;
 
 	/* Let libata fill in the port details */
-	ata_std_ports(&probe.port[0]);
+	ata_std_ports(&ap->ioaddr);
 
-	/* Now add the port that is active */
-	if (ata_device_add(&probe))
-		return 0;
-	return -ENODEV;
+	/* activate host */
+	return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED,
+				 &mpiix_sht);
 }
 
 static const struct pci_device_id mpiix[] = {
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 38f99b3..dbba5b7 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -16,33 +16,7 @@ #include <linux/libata.h>
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_netcell"
-#define DRV_VERSION	"0.1.6"
-
-/**
- *	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);
-}
+#define DRV_VERSION	"0.1.7"
 
 /* No PIO or DMA methods needed for this device */
 
@@ -81,8 +55,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= netcell_error_handler,
+	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_80wire,
 
 	/* BMDMA handling is PCI ATA format, use helpers */
 	.bmdma_setup		= ata_bmdma_setup,
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 9944a28..ebc58a9 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -28,16 +28,17 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_ns87410"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.6"
 
 /**
  *	ns87410_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
- *	Set up cable type and use generic probe init
+ *	Check enabled ports
  */
 
-static int ns87410_pre_reset(struct ata_port *ap)
+static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits ns87410_enable_bits[] = {
@@ -47,8 +48,8 @@ static int ns87410_pre_reset(struct ata_
 
 	if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
 		return -ENOENT;
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -177,6 +178,7 @@ static struct ata_port_operations ns8741
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ns87410_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ns87410_qc_issue_prot,
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index da68cd1..4d75d32 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -25,16 +25,17 @@ #include <linux/libata.h>
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_oldpiix"
-#define DRV_VERSION	"0.5.4"
+#define DRV_VERSION	"0.5.5"
 
 /**
  *	oldpiix_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int oldpiix_pre_reset(struct ata_port *ap)
+static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits oldpiix_enable_bits[] = {
@@ -44,8 +45,8 @@ static int oldpiix_pre_reset(struct ata_
 
 	if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
 		return -ENOENT;
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -65,7 +66,7 @@ static void oldpiix_pata_error_handler(s
 /**
  *	oldpiix_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
- *	@adev: um
+ *	@adev: Device whose timings we are configuring
  *
  *	Set PIO mode for device, in host controller PCI config space.
  *
@@ -255,6 +256,7 @@ static const struct ata_port_operations 
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= oldpiix_pata_error_handler,
 	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 3fd3a35..0af8a2c 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -34,7 +34,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.2.9"
 
 enum {
 	READ_REG	= 0,	/* index of Read cycle timing register */
@@ -47,11 +47,12 @@ enum {
 /**
  *	opti_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int opti_pre_reset(struct ata_port *ap)
+static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits opti_enable_bits[] = {
@@ -62,8 +63,7 @@ static int opti_pre_reset(struct ata_por
 	if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -198,6 +198,7 @@ static struct ata_port_operations opti_p
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= opti_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 9764907..2843e48 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -33,7 +33,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.3.2"
 
 enum {
 	READ_REG	= 0,	/* index of Read cycle timing register */
@@ -48,11 +48,12 @@ static int pci_clock;	/* 0 = 33 1 = 25 *
 /**
  *	optidma_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int optidma_pre_reset(struct ata_port *ap)
+static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits optidma_enable_bits = {
@@ -62,8 +63,7 @@ static int optidma_pre_reset(struct ata_
 	if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
 		return -ENOENT;
 
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -115,7 +115,7 @@ static void optidma_lock(struct ata_port
 }
 
 /**
- *	optidma_set_mode	-	set mode data
+ *	optidma_mode_setup	-	set mode data
  *	@ap: ATA interface
  *	@adev: ATA device
  *	@mode: Mode to set
@@ -128,7 +128,7 @@ static void optidma_lock(struct ata_port
  *	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)
+static void optidma_mode_setup(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;
@@ -202,7 +202,7 @@ static void optidma_set_mode(struct ata_
 }
 
 /**
- *	optiplus_set_mode	-	DMA setup for Firestar Plus
+ *	optiplus_mode_setup	-	DMA setup for Firestar Plus
  *	@ap: ATA port
  *	@adev: device
  *	@mode: desired mode
@@ -213,7 +213,7 @@ static void optidma_set_mode(struct ata_
  *	one
  */
 
-static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 udcfg;
@@ -225,7 +225,7 @@ static void optiplus_set_mode(struct ata
 	pci_read_config_byte(pdev, 0x44, &udcfg);
 	if (mode <= XFER_UDMA_0) {
 		udcfg &= ~(1 << unit);
-		optidma_set_mode(ap, adev, adev->dma_mode);
+		optidma_mode_setup(ap, adev, adev->dma_mode);
 	} else {
 		udcfg |=  (1 << unit);
 		if (ap->port_no) {
@@ -253,7 +253,7 @@ static void optiplus_set_mode(struct ata
 
 static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 {
-	optidma_set_mode(ap, adev, adev->pio_mode);
+	optidma_mode_setup(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -268,7 +268,7 @@ static void optidma_set_pio_mode(struct 
 
 static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 {
-	optidma_set_mode(ap, adev, adev->dma_mode);
+	optidma_mode_setup(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -283,7 +283,7 @@ static void optidma_set_dma_mode(struct 
 
 static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
 {
-	optiplus_set_mode(ap, adev, adev->pio_mode);
+	optiplus_mode_setup(ap, adev, adev->pio_mode);
 }
 
 /**
@@ -298,7 +298,7 @@ static void optiplus_set_pio_mode(struct
 
 static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
 {
-	optiplus_set_mode(ap, adev, adev->dma_mode);
+	optiplus_mode_setup(ap, adev, adev->dma_mode);
 }
 
 /**
@@ -322,26 +322,29 @@ static u8 optidma_make_bits43(struct ata
 }
 
 /**
- *	optidma_post_set_mode	-	finalize PCI setup
+ *	optidma_set_mode	-	mode setup
  *	@ap: port to set up
  *
- *	Finalise the configuration by writing the nibble of extra bits
- *	of data into the chip.
+ *	Use the standard setup to tune the chipset and then 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)
+static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
 {
 	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);
+	int rc  = ata_do_set_mode(ap, r_failed);
+	if (rc == 0) {
+		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);
+	}
+	return rc;
 }
 
 static struct scsi_host_template optidma_sht = {
@@ -381,7 +384,8 @@ static struct ata_port_operations optidm
 	.thaw		= ata_bmdma_thaw,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
 	.error_handler	= optidma_error_handler,
-	.post_set_mode	= optidma_post_set_mode,
+	.set_mode	= optidma_set_mode,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -416,7 +420,8 @@ static struct ata_port_operations optipl
 	.thaw		= ata_bmdma_thaw,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
 	.error_handler	= optidma_error_handler,
-	.post_set_mode	= optidma_post_set_mode,
+	.set_mode	= optidma_set_mode,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 103720f..75dc847 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@ #include <pcmcia/ciscode.h>
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.0"
+#define DRV_VERSION "0.3.1"
 
 /*
  *	Private data structure to glue stuff together
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
 	dev_node_t	node;
 };
 
+/**
+ *	pcmcia_set_mode	-	PCMCIA specific mode setup
+ *	@ap: Port
+ *	@r_failed_dev: Return pointer for failed device
+ *
+ *	Perform the tuning and setup of the devices and timings, which
+ *	for PCMCIA is the same as any other controller. We wrap it however
+ *	as we need to spot hardware with incorrect or missing master/slave
+ *	decode, which alas is embarrassingly common in the PC world
+ */
+
+static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+	struct ata_device *master = &ap->device[0];
+	struct ata_device *slave = &ap->device[1];
+
+	if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
+		return ata_do_set_mode(ap, r_failed_dev);
+
+	if (memcmp(master->id + ATA_ID_FW_REV,  slave->id + ATA_ID_FW_REV,
+			   ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
+	{
+		/* Suspicious match, but could be two cards from
+		   the same vendor - check serial */
+		if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
+			   ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
+			ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+			ata_dev_disable(slave);
+		}
+	}
+	return ata_do_set_mode(ap, r_failed_dev);
+}
+
 static struct scsi_host_template pcmcia_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_
 };
 
 static struct ata_port_operations pcmcia_port_ops = {
+	.set_mode	= pcmcia_set_mode,
 	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
@@ -84,13 +118,13 @@ static struct ata_port_operations pcmcia
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
 
 	.data_xfer	= ata_data_xfer_noirq,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -111,7 +145,8 @@ do { last_fn = (fn); if ((last_ret = (re
 
 static int pcmcia_init_one(struct pcmcia_device *pdev)
 {
-	struct ata_probe_ent ae;
+	struct ata_host *host;
+	struct ata_port *ap;
 	struct ata_pcmcia_info *info;
 	tuple_t tuple;
 	struct {
@@ -255,24 +290,24 @@ next_entry:
  	 *	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 = IRQF_SHARED;
-	ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-	ae.port[0].cmd_addr = io_addr;
-	ae.port[0].altstatus_addr = ctl_addr;
-	ae.port[0].ctl_addr = ctl_addr;
-	ata_std_ports(&ae.port[0]);
-
-	ret = -ENODEV;
-	if (ata_device_add(&ae) == 0)
+	ret = -ENOMEM;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		goto failed;
+	ap = host->ports[0];
+
+	ap->ops = &pcmcia_port_ops;
+	ap->pio_mask = 1;		/* ISA so PIO 0 cycles */
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
+	ap->ioaddr.cmd_addr = io_addr;
+	ap->ioaddr.altstatus_addr = ctl_addr;
+	ap->ioaddr.ctl_addr = ctl_addr;
+	ata_std_ports(&ap->ioaddr);
+
+	/* activate */
+	ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
+				IRQF_SHARED, &pcmcia_sht);
+	if (ret)
 		goto failed;
 
 	info->ndev = 1;
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 93bcdad..0d2cc49 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@ #include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_pdc2027x"
-#define DRV_VERSION	"0.8"
+#define DRV_VERSION	"0.9"
 #undef PDC_DEBUG
 
 #ifdef PDC_DEBUG
@@ -66,8 +66,10 @@ static int pdc2027x_init_one(struct pci_
 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);
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
+static int pdc2027x_cable_detect(struct ata_port *ap);
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
 
 /*
  * ATA Timing Tables based on 133MHz controller clock.
@@ -146,6 +148,7 @@ static struct scsi_host_template pdc2027
 
 static struct ata_port_operations pdc2027x_pata100_ops = {
 	.port_disable		= ata_port_disable,
+	.mode_filter		= ata_pci_default_filter,
 
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -166,8 +169,8 @@ static struct ata_port_operations pdc202
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= pdc2027x_error_handler,
 	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= pdc2027x_cable_detect,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -179,7 +182,8 @@ static struct ata_port_operations pdc202
 	.port_disable		= ata_port_disable,
 	.set_piomode		= pdc2027x_set_piomode,
 	.set_dmamode		= pdc2027x_set_dmamode,
-	.post_set_mode		= pdc2027x_post_set_mode,
+	.set_mode		= pdc2027x_set_mode,
+	.mode_filter		= pdc2027x_mode_filter,
 
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -200,8 +204,8 @@ static struct ata_port_operations pdc202
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= pdc2027x_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= pdc2027x_cable_detect,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -212,7 +216,6 @@ static struct ata_port_operations pdc202
 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 */
@@ -222,7 +225,6 @@ static struct ata_port_info pdc2027x_por
 	},
 	/* PDC_UDMA_133 */
 	{
-		.sht		= &pdc2027x_sht,
 		.flags		= ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
                         	  ATA_FLAG_MMIO,
 		.pio_mask	= 0x1f, /* pio0-4 */
@@ -261,7 +263,7 @@ static inline void __iomem *dev_mmio(str
 }
 
 /**
- *	pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ *	pdc2027x_pata_cable_detect - Probe host controller cable detect info
  *	@ap: Port for which cable detect info is desired
  *
  *	Read 80c cable indicator from Promise extended register.
@@ -270,7 +272,7 @@ static inline void __iomem *dev_mmio(str
  *	LOCKING:
  *	None (inherited from caller).
  */
-static void pdc2027x_cbl_detect(struct ata_port *ap)
+static int pdc2027x_cable_detect(struct ata_port *ap)
 {
 	u32 cgcr;
 
@@ -281,13 +283,10 @@ static void pdc2027x_cbl_detect(struct a
 
 	PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
 
-	ap->cbl = ATA_CBL_PATA80;
-	return;
-
+	return ATA_CBL_PATA80;
 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;
+	return ATA_CBL_PATA40;
 }
 
 /**
@@ -302,6 +301,7 @@ static inline int pdc2027x_port_enabled(
 /**
  *	pdc2027x_prereset - prereset for PATA host controller
  *	@ap: Target port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Probeinit including cable detection.
  *
@@ -309,13 +309,12 @@ static inline int pdc2027x_port_enabled(
  *	None (inherited from caller).
  */
 
-static int pdc2027x_prereset(struct ata_port *ap)
+static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
 {
 	/* Check whether port enabled */
 	if (!pdc2027x_port_enabled(ap))
 		return -ENOENT;
-	pdc2027x_cbl_detect(ap);
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 /**
@@ -334,6 +333,32 @@ static void pdc2027x_error_handler(struc
 }
 
 /**
+ *	pdc2720x_mode_filter	-	mode selection filter
+ *	@adev: ATA device
+ *	@mask: list of modes proposed
+ *
+ *	Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+	unsigned char model_num[ATA_ID_PROD_LEN + 1];
+	struct ata_device *pair = ata_dev_pair(adev);
+
+	if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL)
+		return ata_pci_default_filter(adev, mask);
+
+	/* Check for slave of a Maxtor at UDMA6 */
+	ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
+			  ATA_ID_PROD_LEN + 1);
+	/* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
+	if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+		mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
+
+	return ata_pci_default_filter(adev, mask);
+}
+
+/**
  *	pdc2027x_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port to configure
  *	@adev: um
@@ -444,17 +469,22 @@ static void pdc2027x_set_dmamode(struct 
 }
 
 /**
- *	pdc2027x_post_set_mode - Set the timing registers back to correct values.
+ *	pdc2027x_set_mode - Set the timing registers back to correct values.
  *	@ap: Port to configure
+ *	@r_failed: Returned device for failure
  *
  *	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)
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
 {
 	int i;
 
+	i = ata_do_set_mode(ap, r_failed);
+	if (i < 0)
+		return i;
+
 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
 		struct ata_device *dev = &ap->device[i];
 
@@ -476,6 +506,7 @@ static void pdc2027x_post_set_mode(struc
 			}
 		}
 	}
+	return 0;
 }
 
 /**
@@ -521,12 +552,12 @@ static int pdc2027x_check_atapi_dma(stru
 
 /**
  * pdc_read_counter - Read the ctr counter
- * @probe_ent: for the port address
+ * @host: target ATA host
  */
 
-static long pdc_read_counter(struct ata_probe_ent *probe_ent)
+static long pdc_read_counter(struct ata_host *host)
 {
-	void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
 	long counter;
 	int retry = 1;
 	u32 bccrl, bccrh, bccrlv, bccrhv;
@@ -564,12 +595,12 @@ retry:
  * adjust_pll - Adjust the PLL input clock in Hz.
  *
  * @pdc_controller: controller specific information
- * @probe_ent: For the port address
+ * @host: target ATA host
  * @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)
+static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx)
 {
-	void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
 	u16 pll_ctl;
 	long pll_clock_khz = pll_clock / 1000;
 	long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
@@ -649,19 +680,19 @@ #endif
 
 /**
  * detect_pll_input_clock - Detect the PLL input clock in Hz.
- * @probe_ent: for the port address
+ * @host: target ATA host
  * 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)
+static long pdc_detect_pll_input_clock(struct ata_host *host)
 {
-	void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
 	u32 scr;
 	long start_count, end_count;
 	long pll_clock;
 
 	/* Read current counter value */
-	start_count = pdc_read_counter(probe_ent);
+	start_count = pdc_read_counter(host);
 
 	/* Start the test mode */
 	scr = readl(mmio_base + PDC_SYS_CTL);
@@ -673,7 +704,7 @@ static long pdc_detect_pll_input_clock(s
 	mdelay(100);
 
 	/* Read the counter values again */
-	end_count = pdc_read_counter(probe_ent);
+	end_count = pdc_read_counter(host);
 
 	/* Stop the test mode */
 	scr = readl(mmio_base + PDC_SYS_CTL);
@@ -692,11 +723,10 @@ static long pdc_detect_pll_input_clock(s
 
 /**
  * pdc_hardware_init - Initialize the hardware.
- * @pdev: instance of pci_dev found
- * @pdc_controller: controller specific information
- * @pe:  for the port address
+ * @host: target ATA host
+ * @board_idx: board identifier
  */
-static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
 {
 	long pll_clock;
 
@@ -706,15 +736,15 @@ static int pdc_hardware_init(struct pci_
 	 * 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);
+	pll_clock = pdc_detect_pll_input_clock(host);
 
 	if (pll_clock < 0) /* counter overflow? Try again. */
-		pll_clock = pdc_detect_pll_input_clock(pe);
+		pll_clock = pdc_detect_pll_input_clock(host);
 
-	dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+	dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
 
 	/* Adjust PLL control register */
-	pdc_adjust_pll(pe, pll_clock, board_idx);
+	pdc_adjust_pll(host, pll_clock, board_idx);
 
 	return 0;
 }
@@ -746,8 +776,7 @@ static void pdc_ata_setup_port(struct at
  * 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() )
+ * libata.  (implements struct pci_driver.probe() )
  *
  * @pdev: instance of pci_dev found
  * @ent:  matching entry in the id_tbl[]
@@ -756,14 +785,21 @@ static int __devinit pdc2027x_init_one(s
 {
 	static int printed_version;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
-
-	struct ata_probe_ent *probe_ent;
+	const struct ata_port_info *ppi[] =
+		{ &pdc2027x_port_info[board_idx], NULL };
+	struct ata_host *host;
 	void __iomem *mmio_base;
 	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* alloc host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -771,6 +807,7 @@ static int __devinit pdc2027x_init_one(s
 	rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
 
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
@@ -780,46 +817,22 @@ static int __devinit pdc2027x_init_one(s
 	if (rc)
 		return rc;
 
-	/* Prepare the probe entry */
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	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;
+	mmio_base = host->iomap[PDC_MMIO_BAR];
 
-       	probe_ent->irq = pdev->irq;
-       	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
+	pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
+	host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
+	pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
+	host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
 
-	mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
-
-	pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
-	probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
-	pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
-	probe_ent->port[1].bmdma_addr = mmio_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)
+	if (pdc_hardware_init(host, board_idx) != 0)
 		return -EIO;
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &pdc2027x_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 0a14933..ee636be 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -22,45 +22,17 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.0"
+#define DRV_VERSION "0.4.2"
 
-/**
- *	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)
+static int pdc2026x_cable_detect(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);
+		return ATA_CBL_PATA80;
+	return ATA_CBL_PATA40;
 }
 
 /**
@@ -244,7 +216,6 @@ static void pdc2026x_bmdma_stop(struct a
 
 /**
  *	pdc2026x_dev_config	-	device setup hook
- *	@ap: ATA port
  *	@adev: newly found device
  *
  *	Perform chip specific early setup. We need to lock the transfer
@@ -252,7 +223,7 @@ static void pdc2026x_bmdma_stop(struct a
  *	barf.
  */
 
-static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void pdc2026x_dev_config(struct ata_device *adev)
 {
 	adev->max_sectors = 256;
 }
@@ -292,8 +263,9 @@ static struct ata_port_operations pdc202
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= pdc2024x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -326,8 +298,9 @@ static struct ata_port_operations pdc202
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= pdc2026x_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= pdc2026x_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= pdc2026x_bmdma_start,
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 4b82a54..a0a650c 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -80,13 +80,13 @@ static struct ata_port_operations pata_p
 	.thaw			= ata_bmdma_thaw,
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_unknown,
 
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 
 	.data_xfer		= ata_data_xfer_noirq,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -135,7 +135,8 @@ static void pata_platform_setup_port(str
 static int __devinit pata_platform_probe(struct platform_device *pdev)
 {
 	struct resource *io_res, *ctl_res;
-	struct ata_probe_ent ae;
+	struct ata_host *host;
+	struct ata_port *ap;
 	unsigned int mmio;
 
 	/*
@@ -175,44 +176,41 @@ static int __devinit pata_platform_probe
 	/*
 	 * Now that that's out of the way, wire up the port..
 	 */
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
-	ae.dev = &pdev->dev;
-	ae.port_ops = &pata_platform_port_ops;
-	ae.sht = &pata_platform_sht;
-	ae.n_ports = 1;
-	ae.pio_mask = pio_mask;
-	ae.irq = platform_get_irq(pdev, 0);
-	ae.irq_flags = 0;
-	ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+	ap = host->ports[0];
+
+	ap->ops = &pata_platform_port_ops;
+	ap->pio_mask = pio_mask;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
 
 	/*
 	 * Handle the MMIO case
 	 */
 	if (mmio) {
-		ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
+		ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
 				io_res->end - io_res->start + 1);
-		ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+		ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
 				ctl_res->end - ctl_res->start + 1);
 	} else {
-		ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+		ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
 				io_res->end - io_res->start + 1);
-		ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+		ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
 				ctl_res->end - ctl_res->start + 1);
 	}
-	if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+	if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
 		dev_err(&pdev->dev, "failed to map IO/CTL base\n");
 		return -ENOMEM;
 	}
 
-	ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
+	ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
 
-	pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
+	pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data);
 
-	if (unlikely(ata_device_add(&ae) == 0))
-		return -ENODEV;
-
-	return 0;
+	/* activate */
+	return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
+				 0, &pata_platform_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index c381001..27685ce 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -183,13 +183,13 @@ static struct ata_port_operations qdi650
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.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,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -211,13 +211,13 @@ static struct ata_port_operations qdi658
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.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,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -238,8 +238,9 @@ static struct ata_port_operations qdi658
 
 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;
+	struct ata_host *host;
+	struct ata_port *ap;
 	void __iomem *io_addr, *ctl_addr;
 	int ret;
 
@@ -257,34 +258,31 @@ static __init int qdi_init_one(unsigned 
 	if (!io_addr || !ctl_addr)
 		goto fail;
 
-	memset(&ae, 0, sizeof(struct ata_probe_ent));
-	INIT_LIST_HEAD(&ae.node);
-	ae.dev = &pdev->dev;
+	ret = -ENOMEM;
+	host = ata_host_alloc(&pdev->dev, 1);
+	if (!host)
+		goto fail;
+	ap = host->ports[0];
 
 	if (type == 6580) {
-		ae.port_ops = &qdi6580_port_ops;
-		ae.pio_mask = 0x1F;
-		ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+		ap->ops = &qdi6580_port_ops;
+		ap->pio_mask = 0x1F;
+		ap->flags |= ATA_FLAG_SLAVE_POSS;
 	} else {
-		ae.port_ops = &qdi6500_port_ops;
-		ae.pio_mask = 0x07;	/* Actually PIO3 !IORDY is possible */
-		ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
-				ATA_FLAG_NO_IORDY;
+		ap->ops = &qdi6500_port_ops;
+		ap->pio_mask = 0x07;	/* Actually PIO3 !IORDY is possible */
+		ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
 	}
 
-	ae.sht = &qdi_sht;
-	ae.n_ports = 1;
-	ae.irq = irq;
-	ae.irq_flags = 0;
-	ae.port[0].cmd_addr = io_addr;
-	ae.port[0].altstatus_addr = ctl_addr;
-	ae.port[0].ctl_addr = ctl_addr;
-	ata_std_ports(&ae.port[0]);
+	ap->ioaddr.cmd_addr = io_addr;
+	ap->ioaddr.altstatus_addr = ctl_addr;
+	ap->ioaddr.ctl_addr = ctl_addr;
+	ata_std_ports(&ap->ioaddr);
 
 	/*
 	 *	Hook in a private data structure per channel
 	 */
-	ae.private_data = &qdi_data[nr_qdi_host];
+	ap->private_data = &qdi_data[nr_qdi_host];
 
 	qdi_data[nr_qdi_host].timing = port;
 	qdi_data[nr_qdi_host].fast = fast;
@@ -292,8 +290,9 @@ static __init int qdi_init_one(unsigned 
 
 	printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
 
-	ret = -ENODEV;
-	if (!ata_device_add(&ae))
+	/* activate */
+	ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht);
+	if (ret)
 		goto fail;
 
 	qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 9a9132c..1c54673 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -24,40 +24,12 @@ #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);
-}
+#define DRV_VERSION	"0.4.4"
 
 /**
  *	radisys_set_piomode - Initialize host controller PATA PIO timings
- *	@ap: Port whose timings we are configuring
- *	@adev: um
+ *	@ap: ATA port
+ *	@adev: Device whose timings we are configuring
  *
  *	Set PIO mode for device, in host controller PCI config space.
  *
@@ -248,8 +220,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= radisys_pata_error_handler,
+	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_unknown,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index f522daa..85c4529 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -25,31 +25,6 @@ #define DRV_VERSION	"0.2.3"
 
 
 /**
- *	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
  *	@unused: returned device on set_mode failure
@@ -122,8 +97,9 @@ static struct ata_port_operations rz1000
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= rz1000_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 93b3ed0..66e8ff4 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -216,6 +216,7 @@ static struct ata_port_operations sc1200
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index f3ed141..5df354d 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -1016,7 +1016,6 @@ static const struct ata_port_operations 
 	.error_handler		= scc_error_handler,
 	.post_internal_cmd	= scc_bmdma_stop,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= scc_bmdma_irq_clear,
 	.irq_on			= scc_irq_on,
 	.irq_ack		= scc_irq_ack,
@@ -1027,7 +1026,6 @@ static const struct ata_port_operations 
 
 static struct ata_port_info scc_port_info[] = {
 	{
-		.sht		= &scc_sht,
 		.flags		= ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x00,
@@ -1040,10 +1038,10 @@ static struct ata_port_info scc_port_inf
  *	scc_reset_controller - initialize SCC PATA controller.
  */
 
-static int scc_reset_controller(struct ata_probe_ent *probe_ent)
+static int scc_reset_controller(struct ata_host *host)
 {
-	void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR];
-	void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR];
+	void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
+	void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
 	void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
 	void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
 	void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
@@ -1104,17 +1102,15 @@ static void scc_setup_ports (struct ata_
 	ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
 }
 
-static int scc_host_init(struct ata_probe_ent *probe_ent)
+static int scc_host_init(struct ata_host *host)
 {
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	struct pci_dev *pdev = to_pci_dev(host->dev);
 	int rc;
 
-	rc = scc_reset_controller(probe_ent);
+	rc = scc_reset_controller(host);
 	if (rc)
 		return rc;
 
-	probe_ent->n_ports = 1;
-
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		return rc;
@@ -1122,7 +1118,7 @@ static int scc_host_init(struct ata_prob
 	if (rc)
 		return rc;
 
-	scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]);
+	scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
 
 	pci_set_master(pdev);
 
@@ -1145,14 +1141,18 @@ static int scc_init_one (struct pci_dev 
 {
 	static int printed_version;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
+	const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
 	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent;
 	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev,
 			   "version " DRV_VERSION "\n");
 
+	host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+	if (!host)
+		return -ENOMEM;
+
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -1162,33 +1162,14 @@ static int scc_init_one (struct pci_dev 
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (!probe_ent)
-		return -ENOMEM;
-
-	probe_ent->dev = dev;
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	probe_ent->sht 		= scc_port_info[board_idx].sht;
-	probe_ent->port_flags 	= scc_port_info[board_idx].flags;
-	probe_ent->pio_mask 	= scc_port_info[board_idx].pio_mask;
-	probe_ent->udma_mask 	= scc_port_info[board_idx].udma_mask;
-	probe_ent->port_ops 	= scc_port_info[board_idx].port_ops;
-
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
-
-	rc = scc_host_init(probe_ent);
+	rc = scc_host_init(host);
 	if (rc)
 		return rc;
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &scc_sht);
 }
 
 static struct pci_driver scc_pci_driver = {
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 598eef8..b6e0203 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -1,5 +1,5 @@
 /*
- * ata-serverworks.c 	- Serverworks PATA for new ATA layer
+ * pata_serverworks.c 	- Serverworks PATA for new ATA layer
  *			  (C) 2005 Red Hat Inc
  *			  Alan Cox <alan@redhat.com>
  *
@@ -137,14 +137,16 @@ static struct sv_cable_table cable_detec
 };
 
 /**
- *	serverworks_pre_reset		-	cable detection
+ *	serverworks_cable_detect	-	cable detection
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform cable detection according to the device and subvendor
  *	identifications
  */
 
-static int serverworks_pre_reset(struct ata_port *ap) {
+static int serverworks_cable_detect(struct ata_port *ap)
+{
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	struct sv_cable_table *cb = cable_detect;
 
@@ -152,8 +154,7 @@ static int serverworks_pre_reset(struct 
 		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);
+			return cb->cable_detect(ap);
 		}
 		cb++;
 	}
@@ -162,11 +163,6 @@ static int serverworks_pre_reset(struct 
 	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
@@ -191,31 +187,31 @@ static u8 serverworks_is_csb(struct pci_
 
 /**
  *	serverworks_osb4_filter	-	mode selection filter
- *	@ap: ATA interface
  *	@adev: ATA device
+ *	@mask: Mask of proposed modes
  *
  *	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)
+static unsigned long serverworks_osb4_filter(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);
+	return ata_pci_default_filter(adev, mask);
 }
 
 
 /**
  *	serverworks_csb_filter	-	mode selection filter
- *	@ap: ATA interface
  *	@adev: ATA device
+ *	@mask: Mask of proposed modes
  *
  *	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)
+static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned long mask)
 {
 	const char *p;
 	char model_num[ATA_ID_PROD_LEN + 1];
@@ -223,7 +219,7 @@ static unsigned long serverworks_csb_fil
 
 	/* Disk, UDMA */
 	if (adev->class != ATA_DEV_ATA)
-		return ata_pci_default_filter(ap, adev, mask);
+		return ata_pci_default_filter(adev, mask);
 
 	/* Actually do need to check */
 	ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
@@ -232,7 +228,7 @@ static unsigned long serverworks_csb_fil
 		if (!strcmp(p, model_num))
 			mask &= ~(0x1F << ATA_SHIFT_UDMA);
 	}
-	return ata_pci_default_filter(ap, adev, mask);
+	return ata_pci_default_filter(adev, mask);
 }
 
 
@@ -339,8 +335,9 @@ static struct ata_port_operations server
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= serverworks_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= serverworks_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -374,8 +371,9 @@ static struct ata_port_operations server
 
 	.freeze		= ata_bmdma_freeze,
 	.thaw		= ata_bmdma_thaw,
-	.error_handler	= serverworks_error_handler,
+	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= serverworks_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index dab2889..a5886f0 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
 
 /**
  *	sil680_selreg		-	return register base
@@ -91,20 +91,16 @@ static int sil680_cable_detect(struct at
 		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
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform the SIL680 housekeeping when doing an ATA bus reset
  */
 
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
+static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+			    unsigned long deadline)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	unsigned long addr = sil680_selreg(ap, 0);
@@ -114,12 +110,12 @@ static int sil680_bus_reset(struct ata_p
 	pci_write_config_byte(pdev, addr, reset | 0x03);
 	udelay(25);
 	pci_write_config_byte(pdev, addr, reset);
-	return ata_std_softreset(ap, classes);
+	return ata_std_softreset(ap, classes, deadline);
 }
 
 static void sil680_error_handler(struct ata_port *ap)
 {
-	ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
+	ata_bmdma_drive_eh(ap, ata_std_prereset, sil680_bus_reset, NULL, ata_std_postreset);
 }
 
 /**
@@ -257,6 +253,7 @@ static struct ata_port_operations sil680
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= sil680_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= sil680_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 8dc3bc4..f5838cc 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -35,7 +35,7 @@ #include <linux/ata.h>
 #include "sis.h"
 
 #define DRV_NAME	"pata_sis"
-#define DRV_VERSION	"0.5.0"
+#define DRV_VERSION	"0.5.1"
 
 struct sis_chipset {
 	u16 device;			/* PCI host ID */
@@ -86,106 +86,58 @@ static int sis_port_base(struct ata_devi
 }
 
 /**
- *	sis_133_pre_reset	-	check for 40/80 pin
+ *	sis_133_cable_detect	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform cable detection for the later UDMA133 capable
  *	SiS chipset.
  */
 
-static int sis_133_pre_reset(struct ata_port *ap)
+static int sis_133_cable_detect(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) && !sis_short_ata40(pdev))
-		ap->cbl = ATA_CBL_PATA40;
-	else
-		ap->cbl = ATA_CBL_PATA80;
-
-	return ata_std_prereset(ap);
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
 }
 
 /**
- *	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
+ *	sis_66_cable_detect	-	check for 40/80 pin
  *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Perform cable detection on the UDMA66, UDMA100 and early UDMA133
  *	SiS IDE controllers.
  */
 
-static int sis_66_pre_reset(struct ata_port *ap)
+static int sis_66_cable_detect(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);
-		ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
-		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) && !sis_short_ata40(pdev))
-		ap->cbl = ATA_CBL_PATA40;
-	else
-		ap->cbl = ATA_CBL_PATA80;
-
-	return ata_std_prereset(ap);
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
 }
 
-/**
- *	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
+ *	sis_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int sis_old_pre_reset(struct ata_port *ap)
+static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits sis_enable_bits[] = {
 		{ 0x4aU, 1U, 0x02UL, 0x02UL },	/* port 0 */
@@ -194,27 +146,24 @@ static int sis_old_pre_reset(struct ata_
 
 	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);
-		ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
-		return 0;
-	}
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+	if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+		return -ENOENT;
+
+	return ata_std_prereset(ap, deadline);
 }
 
 
 /**
- *	sis_old_error_handler - Probe specified port on PATA host controller
+ *	sis_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)
+static void sis_error_handler(struct ata_port *ap)
 {
-	ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+	ata_bmdma_drive_eh(ap, sis_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
 /**
@@ -494,7 +443,7 @@ static void sis_133_early_set_dmamode (s
 	int drive_pci = sis_port_base(adev);
 	u16 timing;
 
-	const u16 udma_bits[]  = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+	static const u16 udma_bits[]  = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
 
 	pci_read_config_word(pdev, drive_pci, &timing);
 
@@ -531,8 +480,8 @@ static void sis_133_set_dmamode (struct 
 	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 };
+	static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+	static 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, &reg54);
@@ -595,8 +544,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= sis_133_error_handler,
+	.error_handler		= sis_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= sis_133_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -628,8 +578,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= sis_66_error_handler,
+	.error_handler		= sis_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= sis_66_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -661,9 +612,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= sis_66_error_handler,
+	.error_handler		= sis_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
-
+	.cable_detect		= sis_66_cable_detect,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
@@ -692,10 +643,11 @@ static const struct ata_port_operations 
 	.check_status		= ata_check_status,
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
+	.cable_detect		= sis_66_cable_detect,
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= sis_66_error_handler,
+	.error_handler		= sis_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
 	.bmdma_setup		= ata_bmdma_setup,
@@ -728,8 +680,9 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= sis_old_error_handler,
+	.error_handler		= sis_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
 
 	.bmdma_setup		= ata_bmdma_setup,
 	.bmdma_start		= ata_bmdma_start,
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index b681441..9aeffdb 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -44,11 +44,12 @@ enum {
 /**
  *	sl82c105_pre_reset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int sl82c105_pre_reset(struct ata_port *ap)
+static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits sl82c105_enable_bits[] = {
 		{ 0x40, 1, 0x01, 0x01 },
@@ -58,8 +59,7 @@ static int sl82c105_pre_reset(struct ata
 
 	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);
+	return ata_std_prereset(ap, deadline);
 }
 
 
@@ -238,6 +238,7 @@ static struct ata_port_operations sl82c1
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= sl82c105_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= sl82c105_bmdma_start,
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 71418f2..349887b 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -43,16 +43,17 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_triflex"
-#define DRV_VERSION "0.2.7"
+#define DRV_VERSION "0.2.8"
 
 /**
  *	triflex_prereset		-	probe begin
  *	@ap: ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int triflex_prereset(struct ata_port *ap)
+static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
 {
 	static const struct pci_bits triflex_enable_bits[] = {
 		{ 0x80, 1, 0x01, 0x01 },
@@ -63,8 +64,8 @@ static int triflex_prereset(struct ata_p
 
 	if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
 		return -ENOENT;
-	ap->cbl = ATA_CBL_PATA40;
-	return ata_std_prereset(ap);
+
+	return ata_std_prereset(ap, deadline);
 }
 
 
@@ -214,6 +215,7 @@ static struct ata_port_operations trifle
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= triflex_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= triflex_bmdma_start,
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 946ade0..362beb2 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -62,7 +62,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_via"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.3.1"
 
 /*
  *	The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -135,19 +135,26 @@ static const struct via_isa_bridge {
  */
 
 static int via_cable_detect(struct ata_port *ap) {
+	const struct via_isa_bridge *config = ap->host->private_data;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u32 ata66;
 
+	/* Early chips are 40 wire */
+	if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+		return ATA_CBL_PATA40;
+	/* UDMA 66 chips have only drive side logic */
+	else if((config->flags & VIA_UDMA) < VIA_UDMA_100)
+		return ATA_CBL_PATA_UNK;
+	/* UDMA 100 or later */
 	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;
+	return ATA_CBL_PATA40;
 }
 
-static int via_pre_reset(struct ata_port *ap)
+static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
 {
 	const struct via_isa_bridge *config = ap->host->private_data;
 
@@ -156,23 +163,12 @@ static int via_pre_reset(struct ata_port
 			{ 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_100)
-		ap->cbl = via_cable_detect(ap);
-	/* The UDMA66 series has no cable detect so do drive side detect */
-	else if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
-		ap->cbl = ATA_CBL_PATA40;
-	else
-		ap->cbl = ATA_CBL_PATA_UNK;
-
-
-	return ata_std_prereset(ap);
+	return ata_std_prereset(ap, deadline);
 }
 
 
@@ -327,6 +323,7 @@ static struct ata_port_operations via_po
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= via_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= via_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -362,6 +359,7 @@ static struct ata_port_operations via_po
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= via_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= via_cable_detect,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 6c11103..cc4ad27 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -8,7 +8,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
@@ -36,7 +35,7 @@ #else
 static int probe_winbond;
 #endif
 
-static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(winbond_lock);
 
 static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
 {
@@ -152,13 +151,13 @@ static struct ata_port_operations winbon
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
 
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
 
 	.data_xfer	= winbond_data_xfer,
 
-	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 	.irq_ack	= ata_irq_ack,
@@ -179,11 +178,9 @@ static struct ata_port_operations winbon
 
 static __init int winbond_init_one(unsigned long port)
 {
-	struct ata_probe_ent ae;
 	struct platform_device *pdev;
-	int ret;
 	u8 reg;
-	int i;
+	int i, rc;
 
 	reg = winbond_readcfg(port, 0x81);
 	reg |= 0x80;	/* jumpered mode off */
@@ -202,58 +199,56 @@ static __init int winbond_init_one(unsig
 
 	for (i = 0; i < 2 ; i ++) {
 		unsigned long cmd_port = 0x1F0 - (0x80 * i);
+		struct ata_host *host;
+		struct ata_port *ap;
 		void __iomem *cmd_addr, *ctl_addr;
 
-		if (reg & (1 << i)) {
-			/*
-			 *	Fill in a probe structure first of all
-			 */
-
-			pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
-			if (IS_ERR(pdev))
-				return PTR_ERR(pdev);
-
-			cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
-			ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
-			if (!cmd_addr || !ctl_addr) {
-				platform_device_unregister(pdev);
-				return -ENOMEM;
-			}
-
-			memset(&ae, 0, sizeof(struct ata_probe_ent));
-			INIT_LIST_HEAD(&ae.node);
-			ae.dev = &pdev->dev;
-
-			ae.port_ops = &winbond_port_ops;
-			ae.pio_mask = 0x1F;
-
-			ae.sht = &winbond_sht;
-
-			ae.n_ports = 1;
-			ae.irq = 14 + i;
-			ae.irq_flags = 0;
-			ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
-			ae.port[0].cmd_addr = cmd_addr;
-			ae.port[0].altstatus_addr = ctl_addr;
-			ae.port[0].ctl_addr = ctl_addr;
-			ata_std_ports(&ae.port[0]);
-			/*
-			 *	Hook in a private data structure per channel
-			 */
-			ae.private_data = &winbond_data[nr_winbond_host];
-			winbond_data[nr_winbond_host].config = port;
-			winbond_data[nr_winbond_host].platform_dev = pdev;
-
-			ret = ata_device_add(&ae);
-			if (ret == 0) {
-				platform_device_unregister(pdev);
-				return -ENODEV;
-			}
-			winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
-		}
+		if (!(reg & (1 << i)))
+			continue;
+
+		pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
+		if (IS_ERR(pdev))
+			return PTR_ERR(pdev);
+
+		rc = -ENOMEM;
+		host = ata_host_alloc(&pdev->dev, 1);
+		if (!host)
+			goto err_unregister;
+
+		rc = -ENOMEM;
+		cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+		ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+		if (!cmd_addr || !ctl_addr)
+			goto err_unregister;
+
+		ap = host->ports[0];
+		ap->ops = &winbond_port_ops;
+		ap->pio_mask = 0x1F;
+		ap->flags |= ATA_FLAG_SLAVE_POSS;
+		ap->ioaddr.cmd_addr = cmd_addr;
+		ap->ioaddr.altstatus_addr = ctl_addr;
+		ap->ioaddr.ctl_addr = ctl_addr;
+		ata_std_ports(&ap->ioaddr);
+
+		/* hook in a private data structure per channel */
+		host->private_data = &winbond_data[nr_winbond_host];
+		winbond_data[nr_winbond_host].config = port;
+		winbond_data[nr_winbond_host].platform_dev = pdev;
+
+		/* activate */
+		rc = ata_host_activate(host, 14 + i, ata_interrupt, 0,
+				       &winbond_sht);
+		if (rc)
+			goto err_unregister;
+
+		winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
 	}
 
 	return 0;
+
+ err_unregister:
+	platform_device_unregister(pdev);
+	return rc;
 }
 
 /**
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5dd3ca8..52b6953 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -52,9 +52,9 @@ #define ADMA_ATA_REGS(base,port_no)	((ba
 /* macro to calculate base address for ADMA regs */
 #define ADMA_REGS(base,port_no)		((base) + 0x80 + ((port_no) * 0x20))
 
-/* macro to obtain addresses from ata_host */
-#define ADMA_HOST_REGS(host,port_no) \
-	ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
+/* macro to obtain addresses from ata_port */
+#define ADMA_PORT_REGS(ap) \
+	ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no)
 
 enum {
 	ADMA_MMIO_BAR		= 4,
@@ -128,7 +128,6 @@ struct adma_port_priv {
 
 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);
@@ -172,7 +171,6 @@ static const struct ata_port_operations 
 	.qc_issue		= adma_qc_issue,
 	.eng_timeout		= adma_eng_timeout,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= adma_intr,
 	.irq_clear		= adma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -186,7 +184,6 @@ static const struct ata_port_operations 
 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,
@@ -229,8 +226,10 @@ static void adma_irq_clear(struct ata_po
 	/* nothing */
 }
 
-static void adma_reset_engine(void __iomem *chan)
+static void adma_reset_engine(struct ata_port *ap)
 {
+	void __iomem *chan = ADMA_PORT_REGS(ap);
+
 	/* reset ADMA to idle state */
 	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
 	udelay(2);
@@ -241,14 +240,14 @@ static void adma_reset_engine(void __iom
 static void adma_reinit_engine(struct ata_port *ap)
 {
 	struct adma_port_priv *pp = ap->private_data;
-	void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+	void __iomem *chan = ADMA_PORT_REGS(ap);
 
 	/* mask/clear ATA interrupts */
 	writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
 	ata_check_status(ap);
 
 	/* reset the ADMA engine */
-	adma_reset_engine(chan);
+	adma_reset_engine(ap);
 
 	/* set in-FIFO threshold to 0x100 */
 	writew(0x100, chan + ADMA_FIFO_IN);
@@ -268,7 +267,7 @@ static void adma_reinit_engine(struct at
 
 static inline void adma_enter_reg_mode(struct ata_port *ap)
 {
-	void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+	void __iomem *chan = ADMA_PORT_REGS(ap);
 
 	writew(aPIOMD4, chan + ADMA_CONTROL);
 	readb(chan + ADMA_STATUS);	/* flush */
@@ -415,7 +414,7 @@ #endif
 static inline void adma_packet_start(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+	void __iomem *chan = ADMA_PORT_REGS(ap);
 
 	VPRINTK("ENTER, ap %p\n", ap);
 
@@ -453,7 +452,7 @@ static inline unsigned int adma_intr_pkt
 		struct ata_port *ap = host->ports[port_no];
 		struct adma_port_priv *pp;
 		struct ata_queued_cmd *qc;
-		void __iomem *chan = ADMA_HOST_REGS(host, port_no);
+		void __iomem *chan = ADMA_PORT_REGS(ap);
 		u8 status = readb(chan + ADMA_STATUS);
 
 		if (status == 0)
@@ -575,7 +574,7 @@ static int adma_port_start(struct ata_po
 
 static void adma_port_stop(struct ata_port *ap)
 {
-	adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
+	adma_reset_engine(ap);
 }
 
 static void adma_host_stop(struct ata_host *host)
@@ -583,21 +582,19 @@ static void adma_host_stop(struct ata_ho
 	unsigned int port_no;
 
 	for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
-		adma_reset_engine(ADMA_HOST_REGS(host, port_no));
+		adma_reset_engine(host->ports[port_no]);
 }
 
-static void adma_host_init(unsigned int chip_id,
-				struct ata_probe_ent *probe_ent)
+static void adma_host_init(struct ata_host *host, unsigned int chip_id)
 {
 	unsigned int port_no;
-	void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
 
 	/* enable/lock aGO operation */
-	writeb(7, mmio_base + ADMA_MODE_LOCK);
+	writeb(7, host->iomap[ADMA_MMIO_BAR] + 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));
+		adma_reset_engine(host->ports[port_no]);
 }
 
 static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
@@ -623,14 +620,21 @@ static int adma_ata_init_one(struct pci_
 			     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;
+	const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
+	struct ata_host *host;
+	void __iomem *mmio_base;
 	int rc, port_no;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* alloc host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -641,46 +645,23 @@ static int adma_ata_init_one(struct pci_
 	rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
 	if (rc)
 		return rc;
-	mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
+	host->iomap = pcim_iomap_table(pdev);
+	mmio_base = host->iomap[ADMA_MMIO_BAR];
 
 	rc = adma_set_dma_masks(pdev, mmio_base);
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	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->n_ports	= ADMA_PORTS;
-	probe_ent->iomap	= pcim_iomap_table(pdev);
-
-	for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
-		adma_ata_setup_port(&probe_ent->port[port_no],
+	for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+		adma_ata_setup_port(&host->ports[port_no]->ioaddr,
 				    ADMA_ATA_REGS(mmio_base, port_no));
-	}
-
-	pci_set_master(pdev);
 
 	/* initialize adapter */
-	adma_host_init(board_idx, probe_ent);
+	adma_host_init(host, board_idx);
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED,
+				 &adma_ata_sht);
 }
 
 static int __init adma_ata_init(void)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1e21688..b3b62e9 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -420,7 +420,8 @@ static void inic_thaw(struct ata_port *a
  * SRST and SControl hardreset don't give valid signature on this
  * controller.  Only controller specific hardreset mechanism works.
  */
-static int inic_hardreset(struct ata_port *ap, unsigned int *class)
+static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+			  unsigned long deadline)
 {
 	void __iomem *port_base = inic_port_base(ap);
 	void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
@@ -437,7 +438,7 @@ static int inic_hardreset(struct ata_por
 	msleep(1);
 	writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
 
-	rc = sata_phy_resume(ap, timing);
+	rc = sata_phy_resume(ap, timing, deadline);
 	if (rc) {
 		ata_port_printk(ap, KERN_WARNING, "failed to resume "
 				"link after reset (errno=%d)\n", rc);
@@ -451,10 +452,12 @@ static int inic_hardreset(struct ata_por
 		/* wait a while before checking status */
 		msleep(150);
 
-		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
-			ata_port_printk(ap, KERN_WARNING,
-					"device busy after hardreset\n");
-			return -EIO;
+		rc = ata_wait_ready(ap, deadline);
+		/* link occupied, -ENODEV too is an error */
+		if (rc) {
+			ata_port_printk(ap, KERN_WARNING, "device not ready "
+					"after hardreset (errno=%d)\n", rc);
+			return rc;
 		}
 
 		ata_tf_read(ap, &tf);
@@ -488,11 +491,11 @@ static void inic_error_handler(struct at
 static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
 {
 	/* make DMA engine forget about the failed command */
-	if (qc->err_mask)
+	if (qc->flags & ATA_QCFLAG_FAILED)
 		inic_reset_port(inic_port_base(qc->ap));
 }
 
-static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void inic_dev_config(struct ata_device *dev)
 {
 	/* inic can only handle upto LBA28 max sectors */
 	if (dev->max_sectors > ATA_MAX_SECTORS)
@@ -559,7 +562,6 @@ static struct ata_port_operations inic_p
 	.bmdma_stop		= inic_bmdma_stop,
 	.bmdma_status		= inic_bmdma_status,
 
-	.irq_handler		= inic_interrupt,
 	.irq_clear		= inic_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -580,7 +582,6 @@ static struct ata_port_operations inic_p
 };
 
 static struct ata_port_info inic_port_info = {
-	.sht			= &inic_sht,
 	/* For some reason, ATA_PROT_ATAPI is broken on this
 	 * controller, and no, PIO_POLLING does't fix it.  It somehow
 	 * manages to report the wrong ireason and ignoring ireason
@@ -642,7 +643,9 @@ static int inic_pci_device_resume(struct
 	void __iomem *mmio_base = host->iomap[MMIO_BAR];
 	int rc;
 
-	ata_pci_device_do_resume(pdev);
+	rc = ata_pci_device_do_resume(pdev);
+	if (rc)
+		return rc;
 
 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
 		rc = init_controller(mmio_base, hpriv->cached_hctl);
@@ -659,8 +662,8 @@ #endif
 static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct ata_port_info *pinfo = &inic_port_info;
-	struct ata_probe_ent *probe_ent;
+	const struct ata_port_info *ppi[] = { &inic_port_info, NULL };
+	struct ata_host *host;
 	struct inic_host_priv *hpriv;
 	void __iomem * const *iomap;
 	int i, rc;
@@ -668,6 +671,15 @@ static int inic_init_one(struct pci_dev 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* alloc host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
+	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+	if (!host || !hpriv)
+		return -ENOMEM;
+
+	host->private_data = hpriv;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -675,7 +687,22 @@ static int inic_init_one(struct pci_dev 
 	rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
 	if (rc)
 		return rc;
-	iomap = pcim_iomap_table(pdev);
+	host->iomap = iomap = pcim_iomap_table(pdev);
+
+	for (i = 0; i < NR_PORTS; i++) {
+		struct ata_ioports *port = &host->ports[i]->ioaddr;
+		void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+
+		port->cmd_addr = iomap[2 * i];
+		port->altstatus_addr =
+		port->ctl_addr = (void __iomem *)
+			((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
+		port->scr_addr = port_base + PORT_SCR;
+
+		ata_std_ports(port);
+	}
+
+	hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
 
 	/* Set dma_mask.  This devices doesn't support 64bit addressing. */
 	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -692,43 +719,6 @@ static int inic_init_one(struct pci_dev 
 		return rc;
 	}
 
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!probe_ent || !hpriv)
-		return -ENOMEM;
-
-	probe_ent->dev = &pdev->dev;
-	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		= NR_PORTS;
-
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = IRQF_SHARED;
-
-	probe_ent->iomap = iomap;
-
-	for (i = 0; i < NR_PORTS; i++) {
-		struct ata_ioports *port = &probe_ent->port[i];
-		void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
-
-		port->cmd_addr = iomap[2 * i];
-		port->altstatus_addr =
-		port->ctl_addr = (void __iomem *)
-			((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
-		port->scr_addr = port_base + PORT_SCR;
-
-		ata_std_ports(port);
-	}
-
-	probe_ent->private_data = hpriv;
-	hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
-
 	rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
 	if (rc) {
 		dev_printk(KERN_ERR, &pdev->dev,
@@ -737,13 +727,8 @@ static int inic_init_one(struct pci_dev 
 	}
 
 	pci_set_master(pdev);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-
-	return 0;
+	return ata_host_activate(host, pdev->irq, inic_interrupt, IRQF_SHARED,
+				 &inic_sht);
 }
 
 static const struct pci_device_id inic_pci_tbl[] = {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a65ba63..cb9b9ac 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -253,10 +253,7 @@ #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,
+	MV_DMA_BOUNDARY		= 0xffffffffU,
 
 	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
 
@@ -350,7 +347,6 @@ static void mv_port_stop(struct ata_port
 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);
 
@@ -384,10 +380,10 @@ static struct scsi_host_template mv_sht 
 	.queuecommand		= ata_scsi_queuecmd,
 	.can_queue		= MV_USE_Q_DEPTH,
 	.this_id		= ATA_SHT_THIS_ID,
-	.sg_tablesize		= MV_MAX_SG_CT / 2,
+	.sg_tablesize		= MV_MAX_SG_CT,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
-	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.use_clustering		= 1,
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= MV_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
@@ -405,6 +401,7 @@ static const struct ata_port_operations 
 	.dev_select		= ata_std_dev_select,
 
 	.phy_reset		= mv_phy_reset,
+	.cable_detect		= ata_cable_sata,
 
 	.qc_prep		= mv_qc_prep,
 	.qc_issue		= mv_qc_issue,
@@ -412,7 +409,6 @@ static const struct ata_port_operations 
 
 	.eng_timeout		= mv_eng_timeout,
 
-	.irq_handler		= mv_interrupt,
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -434,6 +430,7 @@ static const struct ata_port_operations 
 	.dev_select		= ata_std_dev_select,
 
 	.phy_reset		= mv_phy_reset,
+	.cable_detect		= ata_cable_sata,
 
 	.qc_prep		= mv_qc_prep,
 	.qc_issue		= mv_qc_issue,
@@ -441,7 +438,6 @@ static const struct ata_port_operations 
 
 	.eng_timeout		= mv_eng_timeout,
 
-	.irq_handler		= mv_interrupt,
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -463,6 +459,7 @@ static const struct ata_port_operations 
 	.dev_select		= ata_std_dev_select,
 
 	.phy_reset		= mv_phy_reset,
+	.cable_detect		= ata_cable_sata,
 
 	.qc_prep		= mv_qc_prep_iie,
 	.qc_issue		= mv_qc_issue,
@@ -470,7 +467,6 @@ static const struct ata_port_operations 
 
 	.eng_timeout		= mv_eng_timeout,
 
-	.irq_handler		= mv_interrupt,
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -484,35 +480,30 @@ static const struct ata_port_operations 
 
 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 */
@@ -520,14 +511,12 @@ static const struct ata_port_info mv_por
 		.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),
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.udma_mask	= 0x7f,	/* udma0-6 */
@@ -551,6 +540,9 @@ static const struct pci_device_id mv_pci
 
 	{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
 
+	/* add Marvell 7042 support */
+	{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
+
 	{ }			/* terminate list */
 };
 
@@ -585,6 +577,39 @@ static const struct mv_hw_ops mv6xxx_ops
 static int msi;	      /* Use PCI msi; either zero (off, default) or non-zero */
 
 
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+	int rc;
+
+	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");
+				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 rc;
+}
+
 /*
  * Functions
  */
@@ -798,20 +823,18 @@ static u32 mv_scr_read(struct ata_port *
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-	if (0xffffffffU != ofs) {
+	if (0xffffffffU != ofs)
 		return readl(mv_ap_base(ap) + ofs);
-	} else {
+	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) {
+	if (0xffffffffU != ofs)
 		writelfl(val, mv_ap_base(ap) + ofs);
-	}
 }
 
 static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
@@ -959,38 +982,30 @@ static void mv_port_stop(struct ata_port
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct mv_port_priv *pp = qc->ap->private_data;
-	unsigned int i = 0;
+	unsigned int n_sg = 0;
 	struct scatterlist *sg;
+	struct mv_sg *mv_sg;
 
+	mv_sg = pp->sg_tbl;
 	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;
+		dma_addr_t addr = sg_dma_address(sg);
+		u32 sg_len = sg_dma_len(sg);
 
-			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);
+		mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+		mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+		mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
 
-			sg_len -= len;
-			addr += len;
+		if (ata_sg_is_last(sg, qc))
+			mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
 
-			if (!sg_len && ata_sg_is_last(sg, qc))
-				pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
-			i++;
-		}
+		mv_sg++;
+		n_sg++;
 	}
+
+	return n_sg;
 }
 
 static inline unsigned mv_inc_q_index(unsigned index)
@@ -1320,17 +1335,15 @@ static void mv_host_intr(struct ata_host
 	int shift, port, port0, hard_port, handled;
 	unsigned int err_mask;
 
-	if (hc == 0) {
+	if (hc == 0)
 		port0 = 0;
-	} else {
+	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) {
+	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);
@@ -1425,9 +1438,8 @@ static irqreturn_t mv_interrupt(int irq,
 	/* 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)) {
+	if (!irq_stat || (0xffffffffU == irq_stat))
 		return IRQ_NONE;
-	}
 
 	n_hcs = mv_get_hc_count(host->ports[0]->flags);
 	spin_lock(&host->lock);
@@ -1952,7 +1964,6 @@ comreset_retry:
 		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
@@ -2077,9 +2088,10 @@ static void mv_port_init(struct ata_iopo
 		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)
+static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	struct mv_host_priv *hpriv = host->private_data;
 	u8 rev_id;
 	u32 hp_flags = hpriv->hp_flags;
 
@@ -2177,8 +2189,8 @@ static int mv_chip_id(struct pci_dev *pd
 
 /**
  *      mv_init_host - Perform some early initialization of the host.
- *	@pdev: host PCI device
- *      @probe_ent: early data struct representing the host
+ *	@host: ATA host to initialize
+ *      @board_idx: controller index
  *
  *      If possible, do an early global reset of the host.  Then do
  *      our port init and clear/unmask all/relevant host interrupts.
@@ -2186,24 +2198,23 @@ static int mv_chip_id(struct pci_dev *pd
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
-			unsigned int board_idx)
+static int mv_init_host(struct ata_host *host, unsigned int board_idx)
 {
 	int rc = 0, n_hc, port, hc;
-	void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
-	struct mv_host_priv *hpriv = probe_ent->private_data;
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+	struct mv_host_priv *hpriv = host->private_data;
 
 	/* global interrupt mask */
 	writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
 
-	rc = mv_chip_id(pdev, hpriv, board_idx);
+	rc = mv_chip_id(host, 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;
+	n_hc = mv_get_hc_count(host->ports[0]->flags);
 
-	for (port = 0; port < probe_ent->n_ports; port++)
+	for (port = 0; port < host->n_ports; port++)
 		hpriv->ops->read_preamp(hpriv, port, mmio);
 
 	rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
@@ -2214,7 +2225,7 @@ static int mv_init_host(struct pci_dev *
 	hpriv->ops->reset_bus(pdev, mmio);
 	hpriv->ops->enable_leds(hpriv, mmio);
 
-	for (port = 0; port < probe_ent->n_ports; port++) {
+	for (port = 0; port < host->n_ports; port++) {
 		if (IS_60XX(hpriv)) {
 			void __iomem *port_mmio = mv_port_base(mmio, port);
 
@@ -2227,9 +2238,9 @@ static int mv_init_host(struct pci_dev *
 		hpriv->ops->phy_errata(hpriv, mmio, port);
 	}
 
-	for (port = 0; port < probe_ent->n_ports; port++) {
+	for (port = 0; port < host->n_ports; port++) {
 		void __iomem *port_mmio = mv_port_base(mmio, port);
-		mv_port_init(&probe_ent->port[port], port_mmio);
+		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
 	}
 
 	for (hc = 0; hc < n_hc; hc++) {
@@ -2268,17 +2279,17 @@ done:
 
 /**
  *      mv_print_info - Dump key info to kernel log for perusal.
- *      @probe_ent: early data struct representing the host
+ *      @host: ATA host to print info about
  *
  *      FIXME: complete this.
  *
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_print_info(struct ata_probe_ent *probe_ent)
+static void mv_print_info(struct ata_host *host)
 {
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
-	struct mv_host_priv *hpriv = probe_ent->private_data;
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	struct mv_host_priv *hpriv = host->private_data;
 	u8 rev_id, scc;
 	const char *scc_s;
 
@@ -2297,7 +2308,7 @@ static void mv_print_info(struct ata_pro
 
 	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,
+	       (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
 	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
 }
 
@@ -2312,50 +2323,42 @@ static void mv_print_info(struct ata_pro
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version = 0;
-	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent;
-	struct mv_host_priv *hpriv;
 	unsigned int board_idx = (unsigned int)ent->driver_data;
-	int rc;
+	const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
+	struct ata_host *host;
+	struct mv_host_priv *hpriv;
+	int n_ports, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* allocate host */
+	n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+	if (!host || !hpriv)
+		return -ENOMEM;
+	host->private_data = hpriv;
+
+	/* acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
-	pci_set_master(pdev);
 
 	rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
 	if (rc == -EBUSY)
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!hpriv)
-		return -ENOMEM;
-
-	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->iomap = pcim_iomap_table(pdev);
-	probe_ent->private_data = hpriv;
+	rc = pci_go_64(pdev);
+	if (rc)
+		return rc;
 
 	/* initialize adapter */
-	rc = mv_init_host(pdev, probe_ent, board_idx);
+	rc = mv_init_host(host, board_idx);
 	if (rc)
 		return rc;
 
@@ -2364,13 +2367,11 @@ static int mv_init_one(struct pci_dev *p
 		pci_intx(pdev, 1);
 
 	mv_dump_pci_cfg(pdev, 0x68);
-	mv_print_info(probe_ent);
+	mv_print_info(host);
 
-	if (ata_device_add(probe_ent) == 0)
-		return -ENODEV;
-
-	devm_kfree(dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
+				 &mv_sht);
 }
 
 static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 9d9670a..e2e795e 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -260,6 +260,7 @@ #endif
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 
 enum nv_host_type
 {
@@ -368,7 +369,6 @@ static const struct ata_port_operations 
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_generic_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -395,7 +395,6 @@ static const struct ata_port_operations 
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_nf2_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -422,7 +421,6 @@ static const struct ata_port_operations 
 	.error_handler		= nv_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_ck804_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -435,7 +433,7 @@ static const struct ata_port_operations 
 static const struct ata_port_operations nv_adma_ops = {
 	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
-	.tf_read		= ata_tf_read,
+	.tf_read		= nv_adma_tf_read,
 	.check_atapi_dma	= nv_adma_check_atapi_dma,
 	.exec_command		= ata_exec_command,
 	.check_status		= ata_check_status,
@@ -451,7 +449,6 @@ static const struct ata_port_operations 
 	.error_handler		= nv_adma_error_handler,
 	.post_internal_cmd	= nv_adma_post_internal_cmd,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= nv_adma_interrupt,
 	.irq_clear		= nv_adma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -476,6 +473,7 @@ static struct ata_port_info nv_port_info
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_generic_ops,
+		.irq_handler	= nv_generic_interrupt,
 	},
 	/* nforce2/3 */
 	{
@@ -486,6 +484,7 @@ static struct ata_port_info nv_port_info
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_nf2_ops,
+		.irq_handler	= nv_nf2_interrupt,
 	},
 	/* ck804 */
 	{
@@ -496,6 +495,7 @@ static struct ata_port_info nv_port_info
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_ck804_ops,
+		.irq_handler	= nv_ck804_interrupt,
 	},
 	/* ADMA */
 	{
@@ -507,6 +507,7 @@ static struct ata_port_info nv_port_info
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
 		.port_ops	= &nv_adma_ops,
+		.irq_handler	= nv_adma_interrupt,
 	},
 };
 
@@ -667,6 +668,18 @@ static int nv_adma_check_atapi_dma(struc
 	return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
 }
 
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	/* Since commands where a result TF is requested are not
+	   executed in ADMA mode, the only time this function will be called
+	   in ADMA mode will be if a command fails. In this case we
+	   don't care about going into register mode with ADMA commands
+	   pending, as the commands will all shortly be aborted anyway. */
+	nv_adma_register_mode(ap);
+
+	ata_tf_read(ap, tf);
+}
+
 static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
 {
 	unsigned int idx = 0;
@@ -738,19 +751,11 @@ static int nv_adma_check_cpb(struct ata_
 		return 1;
 	}
 
-	if (flags & NV_CPB_RESP_DONE) {
+	if (likely(flags & NV_CPB_RESP_DONE)) {
 		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
 		VPRINTK("CPB flags done, flags=0x%x\n", flags);
 		if (likely(qc)) {
-			/* Grab the ATA port status for non-NCQ commands.
-			   For NCQ commands the current status may have nothing to do with
-			   the command just completed. */
-			if (qc->tf.protocol != ATA_PROT_NCQ) {
-				u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
-				qc->err_mask |= ac_err_mask(ata_status);
-			}
-			DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
-				qc->err_mask);
+			DPRINTK("Completing qc from tag %d\n",cpb_num);
 			ata_qc_complete(qc);
 		} else {
 			struct ata_eh_info *ehi = &ap->eh_info;
@@ -1074,14 +1079,14 @@ static int nv_adma_port_resume(struct at
 }
 #endif
 
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
 {
-	void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
-	struct ata_ioports *ioport = &probe_ent->port[port];
+	void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+	struct ata_ioports *ioport = &ap->ioaddr;
 
 	VPRINTK("ENTER\n");
 
-	mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+	mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
 
 	ioport->cmd_addr	= mmio;
 	ioport->data_addr	= mmio + (ATA_REG_DATA * 4);
@@ -1098,9 +1103,9 @@ static void nv_adma_setup_port(struct at
 	ioport->ctl_addr	= mmio + 0x20;
 }
 
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
 {
-	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	struct pci_dev *pdev = to_pci_dev(host->dev);
 	unsigned int i;
 	u32 tmp32;
 
@@ -1115,8 +1120,8 @@ static int nv_adma_host_init(struct ata_
 
 	pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
 
-	for (i = 0; i < probe_ent->n_ports; i++)
-		nv_adma_setup_port(probe_ent, i);
+	for (i = 0; i < host->n_ports; i++)
+		nv_adma_setup_port(host->ports[i]);
 
 	return 0;
 }
@@ -1167,9 +1172,11 @@ static int nv_adma_use_reg_mode(struct a
 	struct nv_adma_port_priv *pp = qc->ap->private_data;
 
 	/* ADMA engine can only be used for non-ATAPI DMA commands,
-	   or interrupt-driven no-data commands. */
+	   or interrupt-driven no-data commands, where a result taskfile
+	   is not required. */
 	if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
-	   (qc->tf.flags & ATA_TFLAG_POLLING))
+	   (qc->tf.flags & ATA_TFLAG_POLLING) ||
+	   (qc->flags & ATA_QCFLAG_RESULT_TF))
 		return 1;
 
 	if((qc->flags & ATA_QCFLAG_DMAMAP) ||
@@ -1398,7 +1405,8 @@ static void nv_ck804_thaw(struct ata_por
 	writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+			unsigned long deadline)
 {
 	unsigned int dummy;
 
@@ -1406,7 +1414,7 @@ static int nv_hardreset(struct ata_port 
 	 * 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);
+	return sata_std_hardreset(ap, &dummy, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -1473,14 +1481,13 @@ static void nv_adma_error_handler(struct
 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;
+	const struct ata_port_info *ppi[2];
+	struct ata_host *host;
 	struct nv_host_priv *hpriv;
 	int rc;
 	u32 bar;
 	void __iomem *base;
 	unsigned long type = ent->driver_data;
-	int mask_set = 0;
 
         // Make sure this is a SATA controller by counting the number of bars
         // (NVIDIA SATA controllers will always have six bars).  Otherwise,
@@ -1496,50 +1503,38 @@ static int nv_init_one (struct pci_dev *
 	if (rc)
 		return rc;
 
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		pcim_pin_device(pdev);
-		return rc;
-	}
-
-	if(type >= CK804 && adma_enabled) {
+	/* determine type and allocate host */
+	if (type >= CK804 && adma_enabled) {
 		dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
 		type = ADMA;
-		if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
-		   !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-			mask_set = 1;
-	}
-
-	if(!mask_set) {
-		rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-		if (rc)
-			return rc;
-		rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-		if (rc)
-			return rc;
 	}
 
-	rc = -ENOMEM;
+	ppi[0] = ppi[1] = &nv_port_info[type];
+	rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+	if (rc)
+		return rc;
 
 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
+	hpriv->type = type;
+	host->private_data = hpriv;
 
-	ppi[0] = ppi[1] = &nv_port_info[type];
-	probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-	if (!probe_ent)
-		return -ENOMEM;
-
-	if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
-		return -EIO;
-	probe_ent->iomap = pcim_iomap_table(pdev);
+	/* set 64bit dma masks, may fail */
+	if (type == ADMA) {
+		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
+			pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+	}
 
-	probe_ent->private_data = hpriv;
-	hpriv->type = type;
+	/* request and iomap NV_MMIO_BAR */
+	rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
+	if (rc)
+		return rc;
 
-	base = probe_ent->iomap[NV_MMIO_BAR];
-	probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
-	probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+	/* configure SCR access */
+	base = host->iomap[NV_MMIO_BAR];
+	host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+	host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
 
 	/* enable SATA space for CK804 */
 	if (type >= CK804) {
@@ -1550,20 +1545,16 @@ static int nv_init_one (struct pci_dev *
 		pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
 	}
 
-	pci_set_master(pdev);
-
+	/* init ADMA */
 	if (type == ADMA) {
-		rc = nv_adma_host_init(probe_ent);
+		rc = nv_adma_host_init(host);
 		if (rc)
 			return rc;
 	}
 
-	rc = ata_device_add(probe_ent);
-	if (rc != NV_PORTS)
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler,
+				 IRQF_SHARED, ppi[0]->sht);
 }
 
 static void nv_remove_one (struct pci_dev *pdev)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 2339813..f56549b 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,10 +45,11 @@ #include <linux/libata.h>
 #include "sata_promise.h"
 
 #define DRV_NAME	"sata_promise"
-#define DRV_VERSION	"2.00"
+#define DRV_VERSION	"2.05"
 
 
 enum {
+	PDC_MAX_PORTS		= 4,
 	PDC_MMIO_BAR		= 3,
 
 	/* register offsets */
@@ -70,14 +71,31 @@ enum {
 	PDC_TBG_MODE		= 0x41C, /* TBG mode (not SATAII) */
 	PDC_SLEW_CTL		= 0x470, /* slew rate control reg (not SATAII) */
 
-	PDC_ERR_MASK		= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
-				  (1<<8) | (1<<9) | (1<<10),
+	/* PDC_GLOBAL_CTL bit definitions */
+	PDC_PH_ERR		= (1 <<  8), /* PCI error while loading packet */
+	PDC_SH_ERR		= (1 <<  9), /* PCI error while loading S/G table */
+	PDC_DH_ERR		= (1 << 10), /* PCI error while loading data */
+	PDC2_HTO_ERR		= (1 << 12), /* host bus timeout */
+	PDC2_ATA_HBA_ERR	= (1 << 13), /* error during SATA DATA FIS transmission */
+	PDC2_ATA_DMA_CNT_ERR	= (1 << 14), /* DMA DATA FIS size differs from S/G count */
+	PDC_OVERRUN_ERR		= (1 << 19), /* S/G byte count larger than HD requires */
+	PDC_UNDERRUN_ERR	= (1 << 20), /* S/G byte count less than HD requires */
+	PDC_DRIVE_ERR		= (1 << 21), /* drive error */
+	PDC_PCI_SYS_ERR		= (1 << 22), /* PCI system error */
+	PDC1_PCI_PARITY_ERR	= (1 << 23), /* PCI parity error (from SATA150 driver) */
+	PDC1_ERR_MASK		= PDC1_PCI_PARITY_ERR,
+	PDC2_ERR_MASK		= PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR,
+	PDC_ERR_MASK		= (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR
+				   | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR
+				   | PDC1_ERR_MASK | PDC2_ERR_MASK),
 
 	board_2037x		= 0,	/* FastTrak S150 TX2plus */
-	board_20319		= 1,	/* FastTrak S150 TX4 */
-	board_20619		= 2,	/* FastTrak TX4000 */
-	board_2057x		= 3,	/* SATAII150 Tx2plus */
-	board_40518		= 4,	/* SATAII150 Tx4 */
+	board_2037x_pata	= 1,	/* FastTrak S150 TX2plus PATA port */
+	board_20319		= 2,	/* FastTrak S150 TX4 */
+	board_20619		= 3,	/* FastTrak TX4000 */
+	board_2057x		= 4,	/* SATAII150 Tx2plus */
+	board_2057x_pata	= 5,	/* SATAII150 Tx2plus */
+	board_40518		= 6,	/* SATAII150 Tx4 */
 
 	PDC_HAS_PATA		= (1 << 1), /* PDC20375/20575 has PATA */
 
@@ -100,8 +118,10 @@ enum {
 				  ATA_FLAG_MMIO |
 				  ATA_FLAG_PIO_POLLING,
 
-	/* hp->flags bits */
-	PDC_FLAG_GEN_II		= (1 << 0),
+	/* ap->flags bits */
+	PDC_FLAG_GEN_II		= (1 << 24),
+	PDC_FLAG_SATA_PATA	= (1 << 25), /* supports SATA + PATA */
+	PDC_FLAG_4_PORTS	= (1 << 26), /* 4 ports */
 };
 
 
@@ -110,28 +130,25 @@ struct pdc_port_priv {
 	dma_addr_t		pkt_dma;
 };
 
-struct pdc_host_priv {
-	unsigned long		flags;
-	unsigned long		port_flags[ATA_MAX_PORTS];
-};
-
 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 int pdc_port_start(struct ata_port *ap);
+static int pdc_common_port_start(struct ata_port *ap);
+static int pdc_sata_port_start(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 int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc);
 static void pdc_irq_clear(struct ata_port *ap);
 static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
 static void pdc_freeze(struct ata_port *ap);
 static void pdc_thaw(struct ata_port *ap);
-static void pdc_error_handler(struct ata_port *ap);
+static void pdc_pata_error_handler(struct ata_port *ap);
+static void pdc_sata_error_handler(struct ata_port *ap);
 static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
-
+static int pdc_pata_cable_detect(struct ata_port *ap);
+static int pdc_sata_cable_detect(struct ata_port *ap);
 
 static struct scsi_host_template pdc_ata_sht = {
 	.module			= THIS_MODULE,
@@ -164,17 +181,17 @@ static const struct ata_port_operations 
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_sata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
+	.cable_detect		= pdc_sata_cable_detect,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= pdc_sata_scr_read,
 	.scr_write		= pdc_sata_scr_write,
-	.port_start		= pdc_port_start,
+	.port_start		= pdc_sata_port_start,
 };
 
 /* First-generation chips need a more restrictive ->check_atapi_dma op */
@@ -185,23 +202,23 @@ static const struct ata_port_operations 
 	.check_status		= ata_check_status,
 	.exec_command		= pdc_exec_command_mmio,
 	.dev_select		= ata_std_dev_select,
-	.check_atapi_dma	= pdc_old_check_atapi_dma,
+	.check_atapi_dma	= pdc_old_sata_check_atapi_dma,
 
 	.qc_prep		= pdc_qc_prep,
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_sata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
+	.cable_detect		= pdc_sata_cable_detect,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= pdc_sata_scr_read,
 	.scr_write		= pdc_sata_scr_write,
-	.port_start		= pdc_port_start,
+	.port_start		= pdc_sata_port_start,
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
@@ -217,32 +234,41 @@ static const struct ata_port_operations 
 	.qc_issue		= pdc_qc_issue_prot,
 	.freeze			= pdc_freeze,
 	.thaw			= pdc_thaw,
-	.error_handler		= pdc_error_handler,
+	.error_handler		= pdc_pata_error_handler,
 	.post_internal_cmd	= pdc_post_internal_cmd,
+	.cable_detect		= pdc_pata_cable_detect,
 	.data_xfer		= ata_data_xfer,
-	.irq_handler		= pdc_interrupt,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
 
-	.port_start		= pdc_port_start,
+	.port_start		= pdc_common_port_start,
 };
 
 static const struct ata_port_info pdc_port_info[] = {
 	/* board_2037x */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_SATA_PATA,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_old_sata_ops,
 	},
 
+	/* board_2037x_pata */
+	{
+		.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_20319 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -251,8 +277,8 @@ static const struct ata_port_info pdc_po
 
 	/* board_20619 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
+				  PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -261,18 +287,28 @@ static const struct ata_port_info pdc_po
 
 	/* board_2057x */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
 		.port_ops	= &pdc_sata_ops,
 	},
 
+	/* board_2057x_pata */
+	{
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+				  PDC_FLAG_GEN_II,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_pata_ops,
+	},
+
 	/* board_40518 */
 	{
-		.sht		= &pdc_ata_sht,
-		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+		.flags		= PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+				  PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
@@ -313,18 +349,12 @@ static struct pci_driver pdc_ata_pci_dri
 };
 
 
-static int pdc_port_start(struct ata_port *ap)
+static int pdc_common_port_start(struct ata_port *ap)
 {
 	struct device *dev = ap->host->dev;
-	struct pdc_host_priv *hp = ap->host->private_data;
 	struct pdc_port_priv *pp;
 	int rc;
 
-	/* fix up port flags and cable type for SATA+PATA chips */
-	ap->flags |= hp->port_flags[ap->port_no];
-	if (ap->flags & ATA_FLAG_SATA)
-		ap->cbl = ATA_CBL_SATA;
-
 	rc = ata_port_start(ap);
 	if (rc)
 		return rc;
@@ -339,8 +369,19 @@ static int pdc_port_start(struct ata_por
 
 	ap->private_data = pp;
 
+	return 0;
+}
+
+static int pdc_sata_port_start(struct ata_port *ap)
+{
+	int rc;
+
+	rc = pdc_common_port_start(ap);
+	if (rc)
+		return rc;
+
 	/* fix up PHYMODE4 align timing */
-	if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
+	if (ap->flags & PDC_FLAG_GEN_II) {
 		void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
 		unsigned int tmp;
 
@@ -374,23 +415,25 @@ static void pdc_reset_port(struct ata_po
 	readl(mmio);	/* flush */
 }
 
-static void pdc_pata_cbl_detect(struct ata_port *ap)
+static int pdc_pata_cable_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)
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
+}
 
-	if (tmp & 0x01) {
-		ap->cbl = ATA_CBL_PATA40;
-		ap->udma_mask &= ATA_UDMA_MASK_40C;
-	} else
-		ap->cbl = ATA_CBL_PATA80;
+static int pdc_sata_cable_detect(struct ata_port *ap)
+{
+	return ATA_CBL_SATA;
 }
 
 static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
-	if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+	if (sc_reg > SCR_CONTROL)
 		return 0xffffffffU;
 	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -399,7 +442,7 @@ static u32 pdc_sata_scr_read (struct ata
 static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
 			       u32 val)
 {
-	if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+	if (sc_reg > SCR_CONTROL)
 		return;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
 }
@@ -555,52 +598,79 @@ static void pdc_thaw(struct ata_port *ap
 	readl(mmio + PDC_CTLSTAT); /* flush */
 }
 
-static int pdc_pre_reset(struct ata_port *ap)
-{
-	if (!sata_scr_valid(ap))
-		pdc_pata_cbl_detect(ap);
-	return ata_std_prereset(ap);
-}
-
-static void pdc_error_handler(struct ata_port *ap)
+static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset)
 {
-	ata_reset_fn_t hardreset;
-
 	if (!(ap->pflags & ATA_PFLAG_FROZEN))
 		pdc_reset_port(ap);
 
-	hardreset = NULL;
-	if (sata_scr_valid(ap))
-		hardreset = sata_std_hardreset;
-
 	/* perform recovery */
-	ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
+	ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
 		  ata_std_postreset);
 }
 
+static void pdc_pata_error_handler(struct ata_port *ap)
+{
+	pdc_common_error_handler(ap, NULL);
+}
+
+static void pdc_sata_error_handler(struct ata_port *ap)
+{
+	pdc_common_error_handler(ap, sata_std_hardreset);
+}
+
 static void pdc_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)
+	if (qc->flags & ATA_QCFLAG_FAILED)
 		pdc_reset_port(ap);
 }
 
+static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
+			   u32 port_status, u32 err_mask)
+{
+	struct ata_eh_info *ehi = &ap->eh_info;
+	unsigned int ac_err_mask = 0;
+
+	ata_ehi_clear_desc(ehi);
+	ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status);
+	port_status &= err_mask;
+
+	if (port_status & PDC_DRIVE_ERR)
+		ac_err_mask |= AC_ERR_DEV;
+	if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))
+		ac_err_mask |= AC_ERR_HSM;
+	if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))
+		ac_err_mask |= AC_ERR_ATA_BUS;
+	if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR
+			   | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
+		ac_err_mask |= AC_ERR_HOST_BUS;
+
+	if (sata_scr_valid(ap))
+		ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+
+	qc->err_mask |= ac_err_mask;
+
+	pdc_reset_port(ap);
+}
+
 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 = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+	u32 port_status, err_mask;
 
-	tmp = readl(mmio);
-	if (tmp & PDC_ERR_MASK) {
-		qc->err_mask |= AC_ERR_DEV;
-		pdc_reset_port(ap);
+	err_mask = PDC_ERR_MASK;
+	if (ap->flags & PDC_FLAG_GEN_II)
+		err_mask &= ~PDC1_ERR_MASK;
+	else
+		err_mask &= ~PDC2_ERR_MASK;
+	port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+	if (unlikely(port_status & err_mask)) {
+		pdc_error_intr(ap, qc, port_status, err_mask);
+		return 1;
 	}
 
 	switch (qc->tf.protocol) {
@@ -767,44 +837,40 @@ static int pdc_check_atapi_dma(struct at
 	return pio;
 }
 
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc)
 {
-	struct ata_port *ap = qc->ap;
-
 	/* First generation chips cannot use ATAPI DMA on SATA ports */
-	if (sata_scr_valid(ap))
-		return 1;
-	return pdc_check_atapi_dma(qc);
+	return 1;
 }
 
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
-			       void __iomem *scr_addr)
+static void pdc_ata_setup_port(struct ata_port *ap,
+			       void __iomem *base, void __iomem *scr_addr)
 {
-	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;
-	port->scr_addr		= scr_addr;
+	ap->ioaddr.cmd_addr		= base;
+	ap->ioaddr.data_addr		= base;
+	ap->ioaddr.feature_addr		=
+	ap->ioaddr.error_addr		= base + 0x4;
+	ap->ioaddr.nsect_addr		= base + 0x8;
+	ap->ioaddr.lbal_addr		= base + 0xc;
+	ap->ioaddr.lbam_addr		= base + 0x10;
+	ap->ioaddr.lbah_addr		= base + 0x14;
+	ap->ioaddr.device_addr		= base + 0x18;
+	ap->ioaddr.command_addr		=
+	ap->ioaddr.status_addr		= base + 0x1c;
+	ap->ioaddr.altstatus_addr	=
+	ap->ioaddr.ctl_addr		= base + 0x38;
+	ap->ioaddr.scr_addr		= scr_addr;
 }
 
 
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void pdc_host_init(struct ata_host *host)
 {
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-	struct pdc_host_priv *hp = pe->private_data;
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+	int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
 	int hotplug_offset;
 	u32 tmp;
 
-	if (hp->flags & PDC_FLAG_GEN_II)
+	if (is_gen2)
 		hotplug_offset = PDC2_SATA_PLUG_CSR;
 	else
 		hotplug_offset = PDC_SATA_PLUG_CSR;
@@ -818,7 +884,7 @@ static void pdc_host_init(unsigned int c
 	/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
 	tmp = readl(mmio + PDC_FLASH_CTL);
 	tmp |= 0x02000;	/* bit 13 (enable bmr burst) */
-	if (!(hp->flags & PDC_FLAG_GEN_II))
+	if (!is_gen2)
 		tmp |= 0x10000;	/* bit 16 (fifo threshold at 8 dw) */
 	writel(tmp, mmio + PDC_FLASH_CTL);
 
@@ -831,7 +897,7 @@ static void pdc_host_init(unsigned int c
 	writel(tmp | 0xff0000, mmio + hotplug_offset);
 
 	/* don't initialise TBG or SLEW on 2nd generation chips */
-	if (hp->flags & PDC_FLAG_GEN_II)
+	if (is_gen2)
 		return;
 
 	/* reduce TBG clock to 133 Mhz. */
@@ -853,16 +919,16 @@ static void pdc_host_init(unsigned int c
 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;
-	struct pdc_host_priv *hp;
+	const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
+	const struct ata_port_info *ppi[PDC_MAX_PORTS];
+	struct ata_host *host;
 	void __iomem *base;
-	unsigned int board_idx = (unsigned int) ent->driver_data;
-	int rc;
-	u8 tmp;
+	int n_ports, i, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* enable and acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -872,89 +938,49 @@ static int pdc_ata_init_one (struct pci_
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
 
-	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
+	/* determine port configuration and setup host */
+	n_ports = 2;
+	if (pi->flags & PDC_FLAG_4_PORTS)
+		n_ports = 4;
+	for (i = 0; i < n_ports; i++)
+		ppi[i] = pi;
 
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
+	if (pi->flags & PDC_FLAG_SATA_PATA) {
+		u8 tmp = readb(base + PDC_FLASH_CTL+1);
+		if (!(tmp & 0x80)) {
+			ppi[n_ports++] = pi + 1;
+			dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n");
+		}
+	}
 
-	hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
-	if (hp == NULL)
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	if (!host) {
+		dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
 		return -ENOMEM;
-
-	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->iomap = pcim_iomap_table(pdev);
-
-	base = probe_ent->iomap[PDC_MMIO_BAR];
-
-	pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
-	pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
-
-	/* notice 4-port boards */
-	switch (board_idx) {
-	case board_40518:
-		hp->flags |= PDC_FLAG_GEN_II;
-		/* Fall through */
-	case board_20319:
-       		probe_ent->n_ports = 4;
-		pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
-		pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
-		break;
-	case board_2057x:
-		hp->flags |= PDC_FLAG_GEN_II;
-		/* Fall through */
-	case board_2037x:
-		/* TX2plus boards also have a PATA port */
-		tmp = readb(base + PDC_FLASH_CTL+1);
-		if (!(tmp & 0x80)) {
-			probe_ent->n_ports = 3;
-			pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-			hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
-			printk(KERN_INFO DRV_NAME " PATA port found\n");
-		} else
-			probe_ent->n_ports = 2;
-		hp->port_flags[0] = ATA_FLAG_SATA;
-		hp->port_flags[1] = ATA_FLAG_SATA;
-		break;
-	case board_20619:
-		probe_ent->n_ports = 4;
-		pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
-		pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
-		break;
-	default:
-		BUG();
-		break;
 	}
+	host->iomap = pcim_iomap_table(pdev);
 
-	pci_set_master(pdev);
+	for (i = 0; i < host->n_ports; i++)
+		pdc_ata_setup_port(host->ports[i],
+				   base + 0x200 + i * 0x80,
+				   base + 0x400 + i * 0x100);
 
 	/* initialize adapter */
-	pdc_host_init(board_idx, probe_ent);
+	pdc_host_init(host);
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
 
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	/* start host, request IRQ and attach */
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,
+				 &pdc_ata_sht);
 }
 
 
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 8786b45..f5a05de 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -114,7 +114,6 @@ struct qs_port_priv {
 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_phy_reset(struct ata_port *ap);
@@ -158,7 +157,6 @@ static const struct ata_port_operations 
 	.qc_issue		= qs_qc_issue,
 	.data_xfer		= ata_data_xfer,
 	.eng_timeout		= qs_eng_timeout,
-	.irq_handler		= qs_intr,
 	.irq_clear		= qs_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -173,7 +171,6 @@ static const struct ata_port_operations 
 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 |
@@ -530,16 +527,16 @@ static void qs_host_stop(struct ata_host
 	writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
 }
 
-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void qs_host_init(struct ata_host *host, unsigned int chip_id)
 {
-	void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
+	void __iomem *mmio_base = host->iomap[QS_MMIO_BAR];
 	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) {
+	for (port_no = 0; port_no < host->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);
@@ -547,7 +544,7 @@ static void qs_host_init(unsigned int ch
 	}
 	writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
 
-	for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+	for (port_no = 0; port_no < host->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);
@@ -607,14 +604,20 @@ static int qs_ata_init_one(struct pci_de
 				const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct ata_probe_ent *probe_ent;
-	void __iomem * const *iomap;
 	unsigned int board_idx = (unsigned int) ent->driver_data;
+	const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL };
+	struct ata_host *host;
 	int rc, port_no;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* alloc host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -625,47 +628,24 @@ static int qs_ata_init_one(struct pci_de
 	rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
 	if (rc)
 		return rc;
-	iomap = pcim_iomap_table(pdev);
+	host->iomap = pcim_iomap_table(pdev);
 
-	rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
+	rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]);
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	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->iomap	= iomap;
-	probe_ent->n_ports	= QS_PORTS;
-
-	for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+	for (port_no = 0; port_no < host->n_ports; ++port_no) {
 		void __iomem *chan =
-			probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
-		qs_ata_setup_port(&probe_ent->port[port_no], chan);
+			host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
+		qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
 	}
 
-	pci_set_master(pdev);
-
 	/* initialize adapter */
-	qs_host_init(board_idx, probe_ent);
+	qs_host_init(host, board_idx);
 
-	if (ata_device_add(probe_ent) != QS_PORTS)
-		return -EIO;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED,
+				 &qs_ata_sht);
 }
 
 static int __init qs_ata_init(void)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 917b7ea..0a1e417 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@ #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil"
-#define DRV_VERSION	"2.1"
+#define DRV_VERSION	"2.2"
 
 enum {
 	SIL_MMIO_BAR		= 5,
@@ -114,11 +114,10 @@ static int sil_init_one (struct pci_dev 
 #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 void sil_dev_config(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 int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -197,7 +196,7 @@ static const struct ata_port_operations 
 	.check_status		= ata_check_status,
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
-	.post_set_mode		= sil_post_set_mode,
+	.set_mode		= sil_set_mode,
 	.bmdma_setup            = ata_bmdma_setup,
 	.bmdma_start            = ata_bmdma_start,
 	.bmdma_stop		= ata_bmdma_stop,
@@ -209,7 +208,6 @@ static const struct ata_port_operations 
 	.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,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -221,7 +219,6 @@ static const struct ata_port_operations 
 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 */
@@ -230,7 +227,6 @@ static const struct ata_port_info sil_po
 	},
 	/* 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 */
@@ -240,7 +236,6 @@ static const struct ata_port_info sil_po
 	},
 	/* 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 */
@@ -249,7 +244,6 @@ static const struct ata_port_info sil_po
 	},
 	/* 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 */
@@ -297,7 +291,16 @@ static unsigned char sil_get_device_cach
 	return cache_line;
 }
 
-static void sil_post_set_mode (struct ata_port *ap)
+/**
+ *	sil_set_mode		-	wrap set_mode functions
+ *	@ap: port to set up
+ *	@r_failed: returned device when we fail
+ *
+ *	Wrap the libata method for device setup as after the setup we need
+ *	to inspect the results and do some configuration work
+ */
+
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
 {
 	struct ata_host *host = ap->host;
 	struct ata_device *dev;
@@ -305,6 +308,11 @@ static void sil_post_set_mode (struct at
 	void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
 	u32 tmp, dev_mode[2];
 	unsigned int i;
+	int rc;
+	
+	rc = ata_do_set_mode(ap, r_failed);
+	if (rc)
+		return rc;
 
 	for (i = 0; i < 2; i++) {
 		dev = &ap->device[i];
@@ -323,6 +331,7 @@ static void sil_post_set_mode (struct at
 	tmp |= (dev_mode[1] << 4);
 	writel(tmp, addr);
 	readl(addr);	/* flush */
+	return 0;
 }
 
 static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
@@ -521,7 +530,6 @@ static void sil_thaw(struct ata_port *ap
 
 /**
  *	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
@@ -548,8 +556,9 @@ static void sil_thaw(struct ata_port *ap
  *	appreciated.
  *	- But then again UDMA5 is hardly anything to complain about
  */
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil_dev_config(struct ata_device *dev)
 {
+	struct ata_port *ap = dev->ap;
 	int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
 	unsigned int n, quirks = 0;
 	unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -583,10 +592,10 @@ static void sil_dev_config(struct ata_po
 	}
 }
 
-static void sil_init_controller(struct pci_dev *pdev,
-				int n_ports, unsigned long port_flags,
-				void __iomem *mmio_base)
+static void sil_init_controller(struct ata_host *host)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
 	u8 cls;
 	u32 tmp;
 	int i;
@@ -596,7 +605,7 @@ static void sil_init_controller(struct p
 	if (cls) {
 		cls >>= 3;
 		cls++;  /* cls = (line_size/8)+1 */
-		for (i = 0; i < n_ports; i++)
+		for (i = 0; i < host->n_ports; i++)
 			writew(cls << 8 | cls,
 			       mmio_base + sil_port[i].fifo_cfg);
 	} else
@@ -604,10 +613,10 @@ static void sil_init_controller(struct p
 			   "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) {
+	if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
 		int cnt;
 
-		for (i = 0, cnt = 0; i < n_ports; i++) {
+		for (i = 0, cnt = 0; i < host->n_ports; i++) {
 			tmp = readl(mmio_base + sil_port[i].sfis_cfg);
 			if ((tmp & 0x3) != 0x01)
 				continue;
@@ -620,7 +629,7 @@ static void sil_init_controller(struct p
 		}
 	}
 
-	if (n_ports == 4) {
+	if (host->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)
@@ -632,15 +641,26 @@ static void sil_init_controller(struct p
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent;
+	int board_id = ent->driver_data;
+	const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+	struct ata_host *host;
 	void __iomem *mmio_base;
-	int rc;
+	int n_ports, rc;
 	unsigned int i;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* allocate host */
+	n_ports = 2;
+	if (board_id == sil_3114)
+		n_ports = 4;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	if (!host)
+		return -ENOMEM;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -650,6 +670,7 @@ static int sil_init_one (struct pci_dev 
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
 
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
@@ -658,45 +679,25 @@ static int sil_init_one (struct pci_dev 
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
+	mmio_base = host->iomap[SIL_MMIO_BAR];
 
-	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;
-
-	probe_ent->iomap = pcim_iomap_table(pdev);
-
-	mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
-
-	for (i = 0; i < probe_ent->n_ports; i++) {
-		probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
-		probe_ent->port[i].altstatus_addr =
-		probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
-		probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
-		probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
-		ata_std_ports(&probe_ent->port[i]);
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+
+		ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
+		ioaddr->altstatus_addr =
+		ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
+		ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
+		ioaddr->scr_addr = mmio_base + sil_port[i].scr;
+		ata_std_ports(ioaddr);
 	}
 
-	sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
-			    mmio_base);
+	/* initialize and activate */
+	sil_init_controller(host);
 
 	pci_set_master(pdev);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,
+				 &sil_sht);
 }
 
 #ifdef CONFIG_PM
@@ -709,8 +710,7 @@ static int sil_pci_device_resume(struct 
 	if (rc)
 		return rc;
 
-	sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
-			    host->iomap[SIL_MMIO_BAR]);
+	sil_init_controller(host);
 	ata_host_resume(host);
 
 	return 0;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5614df8..b97ee9f 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -323,7 +323,7 @@ struct sil24_port_priv {
 	struct ata_taskfile tf;			/* Cached taskfile registers */
 };
 
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil24_dev_config(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);
@@ -331,7 +331,6 @@ static void sil24_tf_read(struct ata_por
 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);
@@ -401,7 +400,6 @@ static const struct ata_port_operations 
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
 
-	.irq_handler		= sil24_interrupt,
 	.irq_clear		= sil24_irq_clear,
 	.irq_on			= ata_dummy_irq_on,
 	.irq_ack		= ata_dummy_irq_ack,
@@ -424,10 +422,9 @@ static const struct ata_port_operations 
 #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[] = {
+static const 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 */
@@ -437,7 +434,6 @@ static struct ata_port_info sil24_port_i
 	},
 	/* sil_3132 */
 	{
-		.sht		= &sil24_sht,
 		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
@@ -446,7 +442,6 @@ static struct ata_port_info sil24_port_i
 	},
 	/* sil_3131/sil_3531 */
 	{
-		.sht		= &sil24_sht,
 		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
@@ -462,9 +457,9 @@ static int sil24_tag(int tag)
 	return tag;
 }
 
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil24_dev_config(struct ata_device *dev)
 {
-	void __iomem *port = ap->ioaddr.cmd_addr;
+	void __iomem *port = dev->ap->ioaddr.cmd_addr;
 
 	if (dev->cdb_len == 16)
 		writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -539,7 +534,8 @@ static int sil24_init_port(struct ata_po
 	return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class)
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+			   unsigned long deadline)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
@@ -571,7 +567,7 @@ static int sil24_softreset(struct ata_po
 
 	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);
+				     100, jiffies_to_msecs(deadline - jiffies));
 
 	writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
 	irq_stat >>= PORT_IRQ_RAW_SHIFT;
@@ -599,7 +595,8 @@ static int sil24_softreset(struct ata_po
 	return -EIO;
 }
 
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
+static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+			   unsigned long deadline)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	const char *reason;
@@ -620,7 +617,7 @@ static int sil24_hardreset(struct ata_po
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 */
-	rc = sata_phy_debounce(ap, sata_deb_timing_long);
+	rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
 	if (rc) {
 		reason = "PHY debouncing failed";
 		goto err;
@@ -924,11 +921,8 @@ static void sil24_post_internal_cmd(stru
 {
 	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)
+	if (qc->flags & ATA_QCFLAG_FAILED)
 		sil24_init_port(ap);
 }
 
@@ -964,11 +958,10 @@ static int sil24_port_start(struct ata_p
 	return 0;
 }
 
-static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
-				  unsigned long port_flags,
-				  void __iomem *host_base,
-				  void __iomem *port_base)
+static void sil24_init_controller(struct ata_host *host)
 {
+	void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
+	void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
 	u32 tmp;
 	int i;
 
@@ -979,7 +972,7 @@ static void sil24_init_controller(struct
 	writel(0, host_base + HOST_CTRL);
 
 	/* init ports */
-	for (i = 0; i < n_ports; i++) {
+	for (i = 0; i < host->n_ports; i++) {
 		void __iomem *port = port_base + i * PORT_REGS_SIZE;
 
 		/* Initial PHY setting */
@@ -993,12 +986,12 @@ static void sil24_init_controller(struct
 						PORT_CS_PORT_RST,
 						PORT_CS_PORT_RST, 10, 100);
 			if (tmp & PORT_CS_PORT_RST)
-				dev_printk(KERN_ERR, &pdev->dev,
+				dev_printk(KERN_ERR, host->dev,
 				           "failed to clear port RST\n");
 		}
 
 		/* Configure IRQ WoC */
-		if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+		if (host->ports[0]->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);
@@ -1026,18 +1019,17 @@ static void sil24_init_controller(struct
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version = 0;
-	struct device *dev = &pdev->dev;
-	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;
-	void __iomem *host_base;
-	void __iomem *port_base;
+	struct ata_port_info pi = sil24_port_info[ent->driver_data];
+	const struct ata_port_info *ppi[] = { &pi, NULL };
+	void __iomem * const *iomap;
+	struct ata_host *host;
 	int i, rc;
 	u32 tmp;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* acquire resources */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -1047,33 +1039,36 @@ static int sil24_init_one(struct pci_dev
 				DRV_NAME);
 	if (rc)
 		return rc;
+	iomap = pcim_iomap_table(pdev);
 
-	/* allocate & init probe_ent */
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (!probe_ent)
-		return -ENOMEM;
+	/* apply workaround for completion IRQ loss on PCI-X errata */
+	if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+		tmp = readl(iomap[SIL24_HOST_BAR] + 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
+			pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+	}
 
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
+	/* allocate and fill host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi,
+				    SIL24_FLAG2NPORTS(ppi[0]->flags));
+	if (!host)
+		return -ENOMEM;
+	host->iomap = iomap;
 
-	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);
+	for (i = 0; i < host->n_ports; i++) {
+		void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
 
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->iomap = pcim_iomap_table(pdev);
+		host->ports[i]->ioaddr.cmd_addr = port;
+		host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
 
-	host_base = probe_ent->iomap[SIL24_HOST_BAR];
-	port_base = probe_ent->iomap[SIL24_PORT_BAR];
+		ata_std_ports(&host->ports[i]->ioaddr);
+	}
 
-	/*
-	 * Configure the device
-	 */
+	/* configure and activate the device */
 	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
 		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 		if (rc) {
@@ -1099,36 +1094,11 @@ static int sil24_init_one(struct pci_dev
 		}
 	}
 
-	/* 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++) {
-		void __iomem *port = port_base + i * PORT_REGS_SIZE;
-
-		probe_ent->port[i].cmd_addr = port;
-		probe_ent->port[i].scr_addr = port + 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);
+	sil24_init_controller(host);
 
 	pci_set_master(pdev);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,
+				 &sil24_sht);
 }
 
 #ifdef CONFIG_PM
@@ -1136,7 +1106,6 @@ static int sil24_pci_device_resume(struc
 {
 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
 	void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
-	void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
 	int rc;
 
 	rc = ata_pci_device_do_resume(pdev);
@@ -1146,8 +1115,7 @@ static int sil24_pci_device_resume(struc
 	if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
 		writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL);
 
-	sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
-			      host_base, port_base);
+	sil24_init_controller(host);
 
 	ata_host_resume(host);
 
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index a787f0d..d8ee062 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -121,7 +121,6 @@ static const struct ata_port_operations 
 	.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,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -131,7 +130,6 @@ static const struct ata_port_operations 
 };
 
 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,
@@ -256,12 +254,13 @@ static void sis_scr_write (struct ata_po
 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;
+	struct ata_port_info pi = sis_port_info;
+	const struct ata_port_info *ppi[2] = { &pi, &pi };
+	struct ata_host *host;
 	u32 genctl, val;
-	struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
 	u8 pmr;
 	u8 port2_start = 0x20;
+	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -270,19 +269,6 @@ static int sis_init_one (struct pci_dev 
 	if (rc)
 		return rc;
 
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		pcim_pin_device(pdev);
-		return rc;
-	}
-
-	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-
 	/* 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)
@@ -349,30 +335,26 @@ static int sis_init_one (struct pci_dev 
 		break;
 	}
 
-	probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
-	if (!probe_ent)
-		return -ENOMEM;
+	rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+	if (rc)
+		return rc;
 
-	if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
+	if (!(pi.flags & SIS_FLAG_CFGSCR)) {
 		void __iomem *mmio;
 
-		mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
-		if (!mmio)
-			return -ENOMEM;
+		rc = pcim_iomap_regions(pdev, 1 << SIS_SCR_PCI_BAR, DRV_NAME);
+		if (rc)
+			return rc;
+		mmio = host->iomap[SIS_SCR_PCI_BAR];
 
-		probe_ent->port[0].scr_addr = mmio;
-		probe_ent->port[1].scr_addr = mmio + port2_start;
+		host->ports[0]->ioaddr.scr_addr = mmio;
+		host->ports[1]->ioaddr.scr_addr = mmio + port2_start;
 	}
 
 	pci_set_master(pdev);
 	pci_intx(pdev, 1);
-
-	if (!ata_device_add(probe_ent))
-		return -EIO;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
-
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &sis_sht);
 }
 
 static int __init sis_init(void)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index b121195..1724673 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -56,7 +56,9 @@ #define DRV_NAME	"sata_svw"
 #define DRV_VERSION	"2.1"
 
 enum {
-	K2_FLAG_NO_ATAPI_DMA		= (1 << 29),
+	/* ap->flags bits */
+	K2_FLAG_SATA_8_PORTS		= (1 << 24),
+	K2_FLAG_NO_ATAPI_DMA		= (1 << 25),
 
 	/* Taskfile registers offsets */
 	K2_SATA_TF_CMD_OFFSET		= 0x00,
@@ -90,17 +92,6 @@ enum {
 	board_svw8			= 1,
 };
 
-static const struct k2_board_info {
-	unsigned int		n_ports;
-	unsigned long		port_flags;
-} k2_board_info[] = {
-	/* board_svw4 */
-	{ 4, K2_FLAG_NO_ATAPI_DMA },
-
-	/* board_svw8 */
-	{ 8, K2_FLAG_NO_ATAPI_DMA },
-};
-
 static u8 k2_stat_check_status(struct ata_port *ap);
 
 
@@ -297,7 +288,7 @@ static int k2_sata_proc_info(struct Scsi
 	/* 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);
+		const u32 *reg = of_get_property(np, "reg", NULL);
 		if (!reg)
 			continue;
 		if (index == *reg)
@@ -354,7 +345,6 @@ static const struct ata_port_operations 
 	.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,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -363,6 +353,28 @@ static const struct ata_port_operations 
 	.port_start		= ata_port_start,
 };
 
+static const struct ata_port_info k2_port_info[] = {
+	/* board_svw4 */
+	{
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
+		.pio_mask	= 0x1f,
+		.mwdma_mask	= 0x07,
+		.udma_mask	= 0x7f,
+		.port_ops	= &k2_sata_ops,
+	},
+	/* board_svw8 */
+	{
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
+				  K2_FLAG_SATA_8_PORTS,
+		.pio_mask	= 0x1f,
+		.mwdma_mask	= 0x07,
+		.udma_mask	= 0x7f,
+		.port_ops	= &k2_sata_ops,
+	},
+};
+
 static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
 {
 	port->cmd_addr		= base + K2_SATA_TF_CMD_OFFSET;
@@ -386,17 +398,24 @@ static void k2_sata_setup_port(struct at
 static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct device *dev = &pdev->dev;
-	struct ata_probe_ent *probe_ent;
+	const struct ata_port_info *ppi[] =
+		{ &k2_port_info[ent->driver_data], NULL };
+	struct ata_host *host;
 	void __iomem *mmio_base;
-	const struct k2_board_info *board_info =
-			&k2_board_info[ent->driver_data];
-	int rc;
-	int i;
+	int n_ports, i, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* allocate host */
+	n_ports = 4;
+	if (ppi[0]->flags & K2_FLAG_SATA_8_PORTS)
+		n_ports = 8;
+
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+	if (!host)
+		return -ENOMEM;
+
 	/*
 	 * 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
@@ -404,6 +423,7 @@ static int k2_sata_init_one (struct pci_
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
+
 	/*
 	 * Check if we have resources mapped at all (second function may
 	 * have been disabled by firmware)
@@ -417,6 +437,15 @@ static int k2_sata_init_one (struct pci_
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
+	mmio_base = host->iomap[5];
+
+	/* 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 < host->n_ports; i++)
+		k2_sata_setup_port(&host->ports[i]->ioaddr,
+				   mmio_base + i * K2_SATA_PORT_OFFSET);
 
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
@@ -425,38 +454,6 @@ static int k2_sata_init_one (struct pci_
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	probe_ent->sht = &k2_sata_sht;
-	probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				ATA_FLAG_MMIO | board_info->port_flags;
-	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->iomap = pcim_iomap_table(pdev);
-
-	/* 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;
-
-	mmio_base = probe_ent->iomap[5];
-
-	/* 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 < board_info->n_ports; i++)
-		k2_sata_setup_port(&probe_ent->port[i],
-				   mmio_base + i * K2_SATA_PORT_OFFSET);
-
 	/* 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)
@@ -469,12 +466,8 @@ static int k2_sata_init_one (struct pci_
 	writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
 
 	pci_set_master(pdev);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &k2_sata_sht);
 }
 
 /* 0x240 is device ID for Apple K2 device
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 1a081c3..3a4f445 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -151,24 +151,23 @@ struct pdc_host_priv {
 
 
 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 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 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,
+static unsigned int pdc20621_dimm_init(struct ata_host *host);
+static int pdc20621_detect_dimm(struct ata_host *host);
+static unsigned int pdc20621_i2c_read(struct ata_host *host,
 				      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);
+static int pdc20621_prog_dimm0(struct ata_host *host);
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+static void pdc20621_get_from_dimm(struct ata_host *host,
 				   void *psource, u32 offset, u32 size);
 #endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+static void pdc20621_put_to_dimm(struct ata_host *host,
 				 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);
@@ -204,7 +203,6 @@ static const struct ata_port_operations 
 	.qc_issue		= pdc20621_qc_issue_prot,
 	.data_xfer		= ata_data_xfer,
 	.eng_timeout		= pdc_eng_timeout,
-	.irq_handler		= pdc20621_interrupt,
 	.irq_clear		= pdc20621_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -214,7 +212,6 @@ static const struct ata_port_operations 
 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,
@@ -882,15 +879,15 @@ static void pdc_sata_setup_port(struct a
 
 
 #ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
 				   u32 offset, u32 size)
 {
 	u32 window_size;
 	u16 idx;
 	u8 page_mask;
 	long dist;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-	void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+	void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
 
 	/* hard-code chip #0 */
 	mmio += PDC_CHIP0_OFS;
@@ -937,15 +934,15 @@ static void pdc20621_get_from_dimm(struc
 #endif
 
 
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
 				 u32 offset, u32 size)
 {
 	u32 window_size;
 	u16 idx;
 	u8 page_mask;
 	long dist;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
-	void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+	void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
 
 	/* hard-code chip #0 */
 	mmio += PDC_CHIP0_OFS;
@@ -987,10 +984,10 @@ static void pdc20621_put_to_dimm(struct 
 }
 
 
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
 				      u32 subaddr, u32 *pdata)
 {
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 	u32 i2creg  = 0;
 	u32 status;
 	u32 count =0;
@@ -1023,17 +1020,17 @@ static unsigned int pdc20621_i2c_read(st
 }
 
 
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+static int pdc20621_detect_dimm(struct ata_host *host)
 {
 	u32 data=0 ;
-  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+	if (pdc20621_i2c_read(host, 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 (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
 		if(data <= 0x75)
 			return 133;
    	} else
@@ -1043,13 +1040,13 @@ static int pdc20621_detect_dimm(struct a
 }
 
 
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+static int pdc20621_prog_dimm0(struct ata_host *host)
 {
 	u32 spd0[50];
 	u32 data = 0;
    	int size, i;
    	u8 bdimmsize;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 	static const struct {
 		unsigned int reg;
 		unsigned int ofs;
@@ -1072,7 +1069,7 @@ static int pdc20621_prog_dimm0(struct at
 	mmio += PDC_CHIP0_OFS;
 
 	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
-		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+		pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
 				  pdc_i2c_read_data[i].reg,
 				  &spd0[pdc_i2c_read_data[i].ofs]);
 
@@ -1108,11 +1105,11 @@ static int pdc20621_prog_dimm0(struct at
 }
 
 
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
 {
 	u32 data, spd0;
 	int error, i;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
 	/* hard-code chip #0 */
    	mmio += PDC_CHIP0_OFS;
@@ -1129,7 +1126,7 @@ static unsigned int pdc20621_prog_dimm_g
 	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
 
 	/* Turn on for ECC */
-	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+	pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
 			  PDC_DIMM_SPD_TYPE, &spd0);
 	if (spd0 == 0x02) {
 		data |= (0x01 << 16);
@@ -1156,7 +1153,7 @@ static unsigned int pdc20621_prog_dimm_g
 }
 
 
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+static unsigned int pdc20621_dimm_init(struct ata_host *host)
 {
 	int speed, size, length;
 	u32 addr,spd0,pci_status;
@@ -1166,7 +1163,7 @@ static unsigned int pdc20621_dimm_init(s
 	u32 ticks=0;
 	u32 clock=0;
 	u32 fparam=0;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
 	/* hard-code chip #0 */
    	mmio += PDC_CHIP0_OFS;
@@ -1225,18 +1222,18 @@ static unsigned int pdc20621_dimm_init(s
 	   Read SPD of DIMM by I2C interface,
 	   and program the DIMM Module Controller.
 	*/
- 	if (!(speed = pdc20621_detect_dimm(pe))) {
+	if (!(speed = pdc20621_detect_dimm(host))) {
 		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);
+	size = pdc20621_prog_dimm0(host);
    	VPRINTK("Local DIMM Size = %dMB\n",size);
 
    	/* Programming DIMM Module Global Control Register (index_CID0:88h) */
-   	if (pdc20621_prog_dimm_global(pe)) {
+	if (pdc20621_prog_dimm_global(host)) {
 		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
 		return 1;
    	}
@@ -1249,20 +1246,20 @@ #ifdef ATA_VERBOSE_DEBUG
   				'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(host, (void *) test_parttern2, 0x10040, 40);
+		pdc20621_put_to_dimm(host, (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);
+		pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40);
+		pdc20621_get_from_dimm(host, (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,
+		pdc20621_get_from_dimm(host, (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);
+		pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40);
+		pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
 		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
 		       test_parttern2[1], &(test_parttern2[2]));
 	}
@@ -1270,14 +1267,14 @@ #endif
 
 	/* ECC initiliazation. */
 
-	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+	pdc20621_i2c_read(host, 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,
+			pdc20621_put_to_dimm(host, (void *) &tmp, addr,
 					     sizeof(u32));
 			addr += sizeof(u32);
 		}
@@ -1287,10 +1284,10 @@ #endif
 }
 
 
-static void pdc_20621_init(struct ata_probe_ent *pe)
+static void pdc_20621_init(struct ata_host *host)
 {
 	u32 tmp;
-	void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+	void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
 
 	/* hard-code chip #0 */
 	mmio += PDC_CHIP0_OFS;
@@ -1321,15 +1318,25 @@ static void pdc_20621_init(struct ata_pr
 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;
+	const struct ata_port_info *ppi[] =
+		{ &pdc_port_info[ent->driver_data], NULL };
+	struct ata_host *host;
 	void __iomem *base;
 	struct pdc_host_priv *hpriv;
-	unsigned int board_idx = (unsigned int) ent->driver_data;
 	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* allocate host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+	if (!host || !hpriv)
+		return -ENOMEM;
+
+	host->private_data = hpriv;
+
+	/* acquire resources and fill host */
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -1340,7 +1347,15 @@ static int pdc_sata_init_one (struct pci
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
+
+	base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+	pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
+	pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
+	pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
+	pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
 
+	/* configure and activate */
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		return rc;
@@ -1348,50 +1363,13 @@ static int pdc_sata_init_one (struct pci
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
+	if (pdc20621_dimm_init(host))
 		return -ENOMEM;
-
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
-	if (!hpriv)
-		return -ENOMEM;
-
-	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->iomap = pcim_iomap_table(pdev);
-
-	probe_ent->private_data = hpriv;
-	base = probe_ent->iomap[PDC_MMIO_BAR] + 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);
+	pdc_20621_init(host);
 
 	pci_set_master(pdev);
-
-	/* initialize adapter */
-	/* initialize local dimm */
-	if (pdc20621_dimm_init(probe_ent))
-		return -ENOMEM;
-	pdc_20621_init(probe_ent);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
+				 IRQF_SHARED, &pdc_sata_sht);
 }
 
 
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index d659ace..f74e383 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -115,7 +115,6 @@ static const struct ata_port_operations 
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -127,7 +126,6 @@ static const struct ata_port_operations 
 };
 
 static struct ata_port_info uli_port_info = {
-	.sht            = &uli_sht,
 	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 			  ATA_FLAG_IGN_SIMPLEX,
 	.pio_mask       = 0x1f,		/* pio0-4 */
@@ -185,12 +183,13 @@ static void uli_scr_write (struct ata_po
 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;
+	const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
 	unsigned int board_idx = (unsigned int) ent->driver_data;
+	struct ata_host *host;
 	struct uli_priv *hpriv;
 	void __iomem * const *iomap;
+	struct ata_ioports *ioaddr;
+	int n_ports, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -199,54 +198,42 @@ static int uli_init_one (struct pci_dev 
 	if (rc)
 		return rc;
 
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		pcim_pin_device(pdev);
-		return rc;
-	}
-
-	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	n_ports = 2;
+	if (board_idx == uli_5287)
+		n_ports = 4;
+	rc = ata_pci_prepare_native_host(pdev, ppi, n_ports, &host);
 	if (rc)
 		return rc;
 
-	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)
-		return -ENOMEM;
-
 	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
+	host->private_data = hpriv;
 
-	probe_ent->private_data = hpriv;
-
-	iomap = pcim_iomap_table(pdev);
+	iomap = host->iomap;
 
 	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 = iomap[0] + 8;
-		probe_ent->port[2].altstatus_addr =
-		probe_ent->port[2].ctl_addr = (void __iomem *)
+		ioaddr = &host->ports[2]->ioaddr;
+		ioaddr->cmd_addr = iomap[0] + 8;
+		ioaddr->altstatus_addr =
+		ioaddr->ctl_addr = (void __iomem *)
 			((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
-		probe_ent->port[2].bmdma_addr = iomap[4] + 16;
+		ioaddr->bmdma_addr = iomap[4] + 16;
 		hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+		ata_std_ports(ioaddr);
 
-		probe_ent->port[3].cmd_addr = iomap[2] + 8;
-		probe_ent->port[3].altstatus_addr =
-		probe_ent->port[3].ctl_addr = (void __iomem *)
+		ioaddr = &host->ports[3]->ioaddr;
+		ioaddr->cmd_addr = iomap[2] + 8;
+		ioaddr->altstatus_addr =
+		ioaddr->ctl_addr = (void __iomem *)
 			((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
-		probe_ent->port[3].bmdma_addr = iomap[4] + 24;
+		ioaddr->bmdma_addr = iomap[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]);
+		ata_std_ports(ioaddr);
 		break;
 
 	case uli_5289:
@@ -266,12 +253,8 @@ static int uli_init_one (struct pci_dev 
 
 	pci_set_master(pdev);
 	pci_intx(pdev, 1);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &uli_sht);
 }
 
 static int __init uli_init(void)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 598e6a2..305ab7c 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -64,8 +64,6 @@ enum {
 	PORT0			= (1 << 1),
 	PORT1			= (1 << 0),
 	ALL_PORTS		= PORT0 | PORT1,
-	PATA_PORT		= 2,	/* PATA is port 2 */
-	N_PORTS			= 3,
 
 	NATIVE_MODE_ALL		= (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
 
@@ -78,11 +76,9 @@ static u32 svia_scr_read (struct ata_por
 static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
-static void vt6421_sata_error_handler(struct ata_port *ap);
-static void vt6421_pata_error_handler(struct ata_port *ap);
+static int vt6421_pata_cable_detect(struct ata_port *ap);
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
 static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
-static int vt6421_port_start(struct ata_port *ap);
 
 static const struct pci_device_id svia_pci_tbl[] = {
 	{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
@@ -141,7 +137,6 @@ static const struct ata_port_operations 
 	.error_handler		= vt6420_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -172,15 +167,15 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= vt6421_pata_error_handler,
+	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= vt6421_pata_cable_detect,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
 
-	.port_start		= vt6421_port_start,
+	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_sata_ops = {
@@ -203,10 +198,10 @@ static const struct ata_port_operations 
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= vt6421_sata_error_handler,
+	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_sata,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -214,11 +209,10 @@ static const struct ata_port_operations 
 	.scr_read		= svia_scr_read,
 	.scr_write		= svia_scr_write,
 
-	.port_start		= vt6421_port_start,
+	.port_start		= ata_port_start,
 };
 
-static struct ata_port_info vt6420_port_info = {
-	.sht		= &svia_sht,
+static const struct ata_port_info vt6420_port_info = {
 	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
 	.pio_mask	= 0x1f,
 	.mwdma_mask	= 0x07,
@@ -226,6 +220,22 @@ static struct ata_port_info vt6420_port_
 	.port_ops	= &vt6420_sata_ops,
 };
 
+static struct ata_port_info vt6421_sport_info = {
+	.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x07,
+	.udma_mask	= 0x7f,
+	.port_ops	= &vt6421_sata_ops,
+};
+
+static struct ata_port_info vt6421_pport_info = {
+	.flags		= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0,
+	.udma_mask	= 0x7f,
+	.port_ops	= &vt6421_pata_ops,
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
 MODULE_LICENSE("GPL");
@@ -258,6 +268,7 @@ static void svia_noop_freeze(struct ata_
 /**
  *	vt6420_prereset - prereset for vt6420
  *	@ap: target ATA port
+ *	@deadline: deadline jiffies for the operation
  *
  *	SCR registers on vt6420 are pieces of shit and may hang the
  *	whole machine completely if accessed with the wrong timing.
@@ -274,7 +285,7 @@ static void svia_noop_freeze(struct ata_
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-static int vt6420_prereset(struct ata_port *ap)
+static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
 {
 	struct ata_eh_context *ehc = &ap->eh_context;
 	unsigned long timeout = jiffies + (HZ * 5);
@@ -319,7 +330,7 @@ static int vt6420_prereset(struct ata_po
 
  skip_scr:
 	/* wait for !BSY */
-	ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+	ata_wait_ready(ap, deadline);
 
 	return 0;
 }
@@ -330,35 +341,15 @@ static void vt6420_error_handler(struct 
 				  NULL, ata_std_postreset);
 }
 
-static int vt6421_pata_prereset(struct ata_port *ap)
+static int vt6421_pata_cable_detect(struct ata_port *ap)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 tmp;
 
 	pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
 	if (tmp & 0x10)
-		ap->cbl = ATA_CBL_PATA40;
-	else
-		ap->cbl = ATA_CBL_PATA80;
-	return 0;
-}
-
-static void vt6421_pata_error_handler(struct ata_port *ap)
-{
-	return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
-				  NULL, ata_std_postreset);
-}
-
-static int vt6421_sata_prereset(struct ata_port *ap)
-{
-	ap->cbl = ATA_CBL_SATA;
-	return 0;
-}
-
-static void vt6421_sata_error_handler(struct ata_port *ap)
-{
-	return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
-				  NULL, ata_std_postreset);
+		return ATA_CBL_PATA40;
+	return ATA_CBL_PATA80;
 }
 
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
@@ -375,16 +366,6 @@ static void vt6421_set_dma_mode(struct a
 	pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
 }
 
-static int vt6421_port_start(struct ata_port *ap)
-{
-	if (ap->port_no == PATA_PORT) {
-		ap->ops = &vt6421_pata_ops;
-		ap->mwdma_mask = 0;
-		ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
-	}
-	return ata_port_start(ap);
-}
-
 static const unsigned int svia_bar_sizes[] = {
 	8, 4, 8, 4, 16, 256
 };
@@ -403,79 +384,78 @@ static void __iomem * vt6421_scr_addr(vo
 	return addr + (port * 64);
 }
 
-static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
-			      void __iomem * const *iomap, unsigned int port)
+static void vt6421_init_addrs(struct ata_port *ap)
 {
-	void __iomem *reg_addr = iomap[port];
-	void __iomem *bmdma_addr = iomap[4] + (port * 8);
-
-	probe_ent->port[port].cmd_addr = reg_addr;
-	probe_ent->port[port].altstatus_addr =
-	probe_ent->port[port].ctl_addr = (void __iomem *)
+	void __iomem * const * iomap = ap->host->iomap;
+	void __iomem *reg_addr = iomap[ap->port_no];
+	void __iomem *bmdma_addr = iomap[4] + (ap->port_no * 8);
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	ioaddr->cmd_addr = reg_addr;
+	ioaddr->altstatus_addr =
+	ioaddr->ctl_addr = (void __iomem *)
 		((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
-	probe_ent->port[port].bmdma_addr = bmdma_addr;
-	probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
+	ioaddr->bmdma_addr = bmdma_addr;
+	ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
 
-	ata_std_ports(&probe_ent->port[port]);
+	ata_std_ports(ioaddr);
 }
 
-static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
 {
-	struct ata_probe_ent *probe_ent;
-	struct ata_port_info *ppi[2];
-	void __iomem *bar5;
+	const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL };
+	struct ata_host *host;
+	int rc;
 
-	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;
+	rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+	if (rc)
+		return rc;
+	*r_host = host;
 
-	bar5 = pcim_iomap(pdev, 5, 0);
-	if (!bar5) {
+	rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+	if (rc) {
 		dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
-		return NULL;
+		return rc;
 	}
 
-	probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0);
-	probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1);
+	host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0);
+	host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1);
 
-	return probe_ent;
+	return 0;
 }
 
-static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
 {
-	struct ata_probe_ent *probe_ent;
-	unsigned int i;
+	const struct ata_port_info *ppi[] =
+		{ &vt6421_sport_info, &vt6421_sport_info, &vt6421_pport_info };
+	struct ata_host *host;
+	int i, rc;
+
+	*r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi));
+	if (!host) {
+		dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
+		return -ENOMEM;
+	}
 
-	probe_ent = devm_kzalloc(&pdev->dev, 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 < 6; i++)
-		if (!pcim_iomap(pdev, i, 0)) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "failed to iomap PCI BAR %d\n", i);
-			return NULL;
-		}
+	rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
+	if (rc) {
+		dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap "
+			   "PCI BARs (errno=%d)\n", rc);
+		return rc;
+	}
+	host->iomap = pcim_iomap_table(pdev);
 
-	for (i = 0; i < N_PORTS; i++)
-		vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
+	for (i = 0; i < host->n_ports; i++)
+		vt6421_init_addrs(host->ports[i]);
 
-	return probe_ent;
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+
+	return 0;
 }
 
 static void svia_configure(struct pci_dev *pdev)
@@ -522,7 +502,7 @@ static int svia_init_one (struct pci_dev
 	static int printed_version;
 	unsigned int i;
 	int rc;
-	struct ata_probe_ent *probe_ent;
+	struct ata_host *host;
 	int board_id = (int) ent->driver_data;
 	const int *bar_sizes;
 	u8 tmp8;
@@ -534,12 +514,6 @@ static int svia_init_one (struct pci_dev
 	if (rc)
 		return rc;
 
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc) {
-		pcim_pin_device(pdev);
-		return rc;
-	}
-
 	if (board_id == vt6420) {
 		pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
 		if (tmp8 & SATA_2DEV) {
@@ -565,32 +539,18 @@ static int svia_init_one (struct pci_dev
 			return -ENODEV;
 		}
 
-	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
-	if (rc)
-		return rc;
-
 	if (board_id == vt6420)
-		probe_ent = vt6420_init_probe_ent(pdev);
+		rc = vt6420_prepare_host(pdev, &host);
 	else
-		probe_ent = vt6421_init_probe_ent(pdev);
-
-	if (!probe_ent) {
-		dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
-		return -ENOMEM;
-	}
+		rc = vt6421_prepare_host(pdev, &host);
+	if (rc)
+		return rc;
 
 	svia_configure(pdev);
 
 	pci_set_master(pdev);
-
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+				 &svia_sht);
 }
 
 static int __init svia_init(void)
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 170bad1..80126f8 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -333,7 +333,6 @@ static const struct ata_port_operations 
 	.thaw			= vsc_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,
 	.irq_on			= ata_irq_on,
 	.irq_ack		= ata_irq_ack,
@@ -367,30 +366,50 @@ static void __devinit vsc_sata_setup_por
 
 static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+	static const struct ata_port_info pi = {
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f,
+		.mwdma_mask	= 0x07,
+		.udma_mask	= 0x7f,
+		.port_ops	= &vsc_sata_ops,
+	};
+	const struct ata_port_info *ppi[] = { &pi, NULL };
 	static int printed_version;
-	struct ata_probe_ent *probe_ent;
+	struct ata_host *host;
 	void __iomem *mmio_base;
-	int rc;
+	int i, rc;
 	u8 cls;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+	/* allocate host */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+	if (!host)
+		return -ENOMEM;
+
 	rc = pcim_enable_device(pdev);
 	if (rc)
 		return rc;
 
-	/*
-	 * Check if we have needed resource mapped.
-	 */
+	/* check if we have needed resource mapped */
 	if (pci_resource_len(pdev, 0) == 0)
 		return -ENODEV;
 
+	/* map IO regions and intialize host accordingly */
 	rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
 	if (rc == -EBUSY)
 		pcim_pin_device(pdev);
 	if (rc)
 		return rc;
+	host->iomap = pcim_iomap_table(pdev);
+
+	mmio_base = host->iomap[VSC_MMIO_BAR];
+
+	for (i = 0; i < host->n_ports; i++)
+		vsc_sata_setup_port(&host->ports[i]->ioaddr,
+				    mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
 
 	/*
 	 * Use 32 bit DMA mask, because 64 bit address support is poor.
@@ -402,12 +421,6 @@ static int __devinit vsc_sata_init_one (
 	if (rc)
 		return rc;
 
-	probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
-	if (probe_ent == NULL)
-		return -ENOMEM;
-	probe_ent->dev = pci_dev_to_dev(pdev);
-	INIT_LIST_HEAD(&probe_ent->node);
-
 	/*
 	 * Due to a bug in the chip, the default cache line size can't be
 	 * used (unless the default is non-zero).
@@ -418,33 +431,6 @@ static int __devinit vsc_sata_init_one (
 
 	if (pci_enable_msi(pdev) == 0)
 		pci_intx(pdev, 0);
-	else
-		probe_ent->irq_flags = IRQF_SHARED;
-
-	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->iomap = pcim_iomap_table(pdev);
-
-	/* 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;
-
-	mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
-
-	/* We have 4 ports per PCI function */
-	vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
-	vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
-	vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
-	vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
-
-	pci_set_master(pdev);
 
 	/*
 	 * Config offset 0x98 is "Extended Control and Status Register 0"
@@ -454,11 +440,9 @@ static int __devinit vsc_sata_init_one (
 	 */
 	pci_write_config_dword(pdev, 0x98, 0);
 
-	if (!ata_device_add(probe_ent))
-		return -ENODEV;
-
-	devm_kfree(&pdev->dev, probe_ent);
-	return 0;
+	pci_set_master(pdev);
+	return ata_host_activate(host, pdev->irq, vsc_sata_interrupt,
+				 IRQF_SHARED, &vsc_sata_sht);
 }
 
 static const struct pci_device_id vsc_sata_pci_tbl[] = {
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 8d60c4e..2ebd07f 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -6,7 +6,6 @@ #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
-#include <linux/pci.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/string.h>
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 3c372e0..59651ab 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -821,7 +821,7 @@ static inline void fill_rx_pool (amb_dev
     }
     // cast needed as there is no %? for pointer differences
     PRINTD (DBG_SKB, "allocated skb at %p, head %p, area %li",
-	    skb, skb->head, (long) (skb->end - skb->head));
+	    skb, skb->head, (long) (skb_end_pointer(skb) - skb->head));
     rx.handle = virt_to_bus (skb);
     rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
     if (rx_give (dev, &rx, pool))
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index fc518d8..02ad83d 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -221,7 +221,7 @@ static int atmtcp_v_send(struct atm_vcc 
 	hdr->vpi = htons(vcc->vpi);
 	hdr->vci = htons(vcc->vci);
 	hdr->length = htonl(skb->len);
-	memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
+	skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len);
 	if (vcc->pop) vcc->pop(vcc,skb);
 	else dev_kfree_skb(skb);
 	out_vcc->push(out_vcc,new_skb);
@@ -310,7 +310,7 @@ static int atmtcp_c_send(struct atm_vcc 
 		goto done;
 	}
 	__net_timestamp(new_skb);
-	memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
+	skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len);
 	out_vcc->push(out_vcc,new_skb);
 	atomic_inc(&vcc->stats->tx);
 	atomic_inc(&out_vcc->stats->rx);
@@ -352,7 +352,7 @@ static struct atm_dev atmtcp_control_dev
 	.ops		= &atmtcp_c_dev_ops,
 	.type		= "atmtcp",
 	.number		= 999,
-	.lock		= SPIN_LOCK_UNLOCKED
+	.lock		= __SPIN_LOCK_UNLOCKED(atmtcp_control_dev.lock)
 };
 
 
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 8fccf01..0d3a38b 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -536,7 +536,7 @@ static int rx_aal0(struct atm_vcc *vcc)
 		return 0;
 	}
 	skb_put(skb,length);
-	skb_set_timestamp(skb, &eni_vcc->timestamp);
+	skb->tstamp = eni_vcc->timestamp;
 	DPRINTK("got len %ld\n",length);
 	if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1;
 	eni_vcc->rxing++;
@@ -701,7 +701,7 @@ static void get_service(struct atm_dev *
 			DPRINTK("Grr, servicing VCC %ld twice\n",vci);
 			continue;
 		}
-		do_gettimeofday(&ENI_VCC(vcc)->timestamp);
+		ENI_VCC(vcc)->timestamp = ktime_get_real();
 		ENI_VCC(vcc)->next = NULL;
 		if (vcc->qos.rxtp.traffic_class == ATM_CBR) {
 			if (eni_dev->fast)
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index 385090c..d04fefb 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -59,7 +59,7 @@ struct eni_vcc {
 	int rxing;			/* number of pending PDUs */
 	int servicing;			/* number of waiting VCs (0 or 1) */
 	int txing;			/* number of pending TX bytes */
-	struct timeval timestamp;	/* for RX timing */
+	ktime_t timestamp;		/* for RX timing */
 	struct atm_vcc *next;		/* next pending RX */
 	struct sk_buff *last;		/* last PDU being DMAed (used to carry
 					   discard information) */
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index a7c0ed3..405ee5e 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1,6 +1,4 @@
 /*
-  $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $
-
   A FORE Systems 200E-series driver for ATM on Linux.
   Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003.
 
@@ -1502,9 +1500,9 @@ fore200e_open(struct atm_vcc *vcc)
     /* pseudo-CBR bandwidth requested? */
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
 	
-	down(&fore200e->rate_sf);
+	mutex_lock(&fore200e->rate_mtx);
 	if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
-	    up(&fore200e->rate_sf);
+	    mutex_unlock(&fore200e->rate_mtx);
 
 	    kfree(fore200e_vcc);
 	    vc_map->vcc = NULL;
@@ -1513,7 +1511,7 @@ fore200e_open(struct atm_vcc *vcc)
 
 	/* reserve bandwidth */
 	fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr;
-	up(&fore200e->rate_sf);
+	mutex_unlock(&fore200e->rate_mtx);
     }
     
     vcc->itf = vcc->dev->number;
@@ -1599,9 +1597,9 @@ fore200e_close(struct atm_vcc* vcc)
     /* release reserved bandwidth, if any */
     if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
 
-	down(&fore200e->rate_sf);
+	mutex_lock(&fore200e->rate_mtx);
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
-	up(&fore200e->rate_sf);
+	mutex_unlock(&fore200e->rate_mtx);
 
 	clear_bit(ATM_VF_HASQOS, &vcc->flags);
     }
@@ -2064,16 +2062,16 @@ fore200e_change_qos(struct atm_vcc* vcc,
 
     if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) {
 
-	down(&fore200e->rate_sf);
+	mutex_lock(&fore200e->rate_mtx);
 	if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) {
-	    up(&fore200e->rate_sf);
+	    mutex_unlock(&fore200e->rate_mtx);
 	    return -EAGAIN;
 	}
 
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 	fore200e->available_cell_rate -= qos->txtp.max_pcr;
 
-	up(&fore200e->rate_sf);
+	mutex_unlock(&fore200e->rate_mtx);
 	
 	memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
 	
@@ -2459,7 +2457,7 @@ fore200e_initialize(struct fore200e* for
 
     DPRINTK(2, "device %s being initialized\n", fore200e->name);
 
-    init_MUTEX(&fore200e->rate_sf);
+    mutex_init(&fore200e->rate_mtx);
     spin_lock_init(&fore200e->q_lock);
 
     cpq = fore200e->cp_queues = fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET;
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index f9abfda..b85a546 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -869,7 +869,7 @@ typedef struct fore200e {
 
     struct stats*              stats;                  /* last snapshot of the stats         */
     
-    struct semaphore           rate_sf;                /* protects rate reservation ops      */
+    struct mutex               rate_mtx;               /* protects rate reservation ops      */
     spinlock_t                 q_lock;                 /* protects queue ops                 */
 #ifdef FORE200E_USE_TASKLET
     struct tasklet_struct      tx_tasklet;             /* performs tx interrupt work         */
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 8510026..d33aba6 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -1901,13 +1901,13 @@ #endif
 			case ATM_AAL0:
 				/* 2.10.1.5 raw cell receive */
 				skb->len = ATM_AAL0_SDU;
-				skb->tail = skb->data + skb->len;
+				skb_set_tail_pointer(skb, skb->len);
 				break;
 			case ATM_AAL5:
 				/* 2.10.1.2 aal5 receive */
 
 				skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len);
-				skb->tail = skb->data + skb->len;
+				skb_set_tail_pointer(skb, skb->len);
 #ifdef USE_CHECKSUM_HW
 				if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) {
 					skb->ip_summed = CHECKSUM_COMPLETE;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index b4b8014..057efbc 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -1065,7 +1065,8 @@ dequeue_rx(struct idt77252_dev *card, st
 	vcc = vc->rx_vcc;
 
 	pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb),
-				    skb->end - skb->data, PCI_DMA_FROMDEVICE);
+				    skb_end_pointer(skb) - skb->data,
+				    PCI_DMA_FROMDEVICE);
 
 	if ((vcc->qos.aal == ATM_AAL0) ||
 	    (vcc->qos.aal == ATM_AAL34)) {
@@ -1194,7 +1195,8 @@ dequeue_rx(struct idt77252_dev *card, st
 		}
 
 		pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
-				 skb->end - skb->data, PCI_DMA_FROMDEVICE);
+				 skb_end_pointer(skb) - skb->data,
+				 PCI_DMA_FROMDEVICE);
 		sb_pool_remove(card, skb);
 
 		skb_trim(skb, len);
@@ -1267,7 +1269,7 @@ idt77252_rx_raw(struct idt77252_dev *car
 	tail = readl(SAR_REG_RAWCT);
 
 	pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue),
-				    queue->end - queue->head - 16,
+				    skb_end_pointer(queue) - queue->head - 16,
 				    PCI_DMA_FROMDEVICE);
 
 	while (head != tail) {
@@ -1363,7 +1365,8 @@ drop:
 				queue = card->raw_cell_head;
 				pci_dma_sync_single_for_cpu(card->pcidev,
 							    IDT77252_PRV_PADDR(queue),
-							    queue->end - queue->data,
+							    (skb_end_pointer(queue) -
+							     queue->data),
 							    PCI_DMA_FROMDEVICE);
 			} else {
 				card->raw_cell_head = NULL;
@@ -1816,7 +1819,8 @@ push_rx_skb(struct idt77252_dev *card, s
 	u32 handle;
 	u32 addr;
 
-	skb->data = skb->tail = skb->head;
+	skb->data = skb->head;
+	skb_reset_tail_pointer(skb);
 	skb->len = 0;
 
 	skb_reserve(skb, 16);
@@ -1835,7 +1839,6 @@ push_rx_skb(struct idt77252_dev *card, s
 		skb_put(skb, SAR_FB_SIZE_3);
 		break;
 	default:
-		dev_kfree_skb(skb);
 		return -1;
 	}
 
@@ -1874,7 +1877,7 @@ add_rx_skb(struct idt77252_dev *card, in
 		}
 
 		paddr = pci_map_single(card->pcidev, skb->data,
-				       skb->end - skb->data,
+				       skb_end_pointer(skb) - skb->data,
 				       PCI_DMA_FROMDEVICE);
 		IDT77252_PRV_PADDR(skb) = paddr;
 
@@ -1888,7 +1891,7 @@ add_rx_skb(struct idt77252_dev *card, in
 
 outunmap:
 	pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
-			 skb->end - skb->data, PCI_DMA_FROMDEVICE);
+			 skb_end_pointer(skb) - skb->data, PCI_DMA_FROMDEVICE);
 
 	handle = IDT77252_PRV_POOL(skb);
 	card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;
@@ -1905,12 +1908,14 @@ recycle_rx_skb(struct idt77252_dev *card
 	int err;
 
 	pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb),
-				       skb->end - skb->data, PCI_DMA_FROMDEVICE);
+				       skb_end_pointer(skb) - skb->data,
+				       PCI_DMA_FROMDEVICE);
 
 	err = push_rx_skb(card, skb, POOL_QUEUE(handle));
 	if (err) {
 		pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
-				 skb->end - skb->data, PCI_DMA_FROMDEVICE);
+				 skb_end_pointer(skb) - skb->data,
+				 PCI_DMA_FROMDEVICE);
 		sb_pool_remove(card, skb);
 		dev_kfree_skb(skb);
 	}
@@ -3122,7 +3127,8 @@ deinit_card(struct idt77252_dev *card)
 			if (skb) {
 				pci_unmap_single(card->pcidev,
 						 IDT77252_PRV_PADDR(skb),
-						 skb->end - skb->data,
+						 (skb_end_pointer(skb) -
+						  skb->data),
 						 PCI_DMA_FROMDEVICE);
 				card->sbpool[i].skb[j] = NULL;
 				dev_kfree_skb(skb);
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index aab9b37..14ced85 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -2208,7 +2208,7 @@ static void dequeue_rx(ns_dev *card, ns_
          if (i == 1 && ns_rsqe_eopdu(rsqe))
             *((u32 *) sb->data) |= 0x00000002;
          skb_put(sb, NS_AAL0_HEADER);
-         memcpy(sb->tail, cell, ATM_CELL_PAYLOAD);
+         memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
          skb_put(sb, ATM_CELL_PAYLOAD);
          ATM_SKB(sb)->vcc = vcc;
 	 __net_timestamp(sb);
@@ -2252,7 +2252,8 @@ static void dequeue_rx(ns_dev *card, ns_
       vc->rx_iov = iovb;
       NS_SKB(iovb)->iovcnt = 0;
       iovb->len = 0;
-      iovb->tail = iovb->data = iovb->head;
+      iovb->data = iovb->head;
+      skb_reset_tail_pointer(iovb);
       NS_SKB(iovb)->vcc = vcc;
       /* IMPORTANT: a pointer to the sk_buff containing the small or large
                     buffer is stored as iovec base, NOT a pointer to the 
@@ -2265,7 +2266,8 @@ static void dequeue_rx(ns_dev *card, ns_
       recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
       NS_SKB(iovb)->iovcnt = 0;
       iovb->len = 0;
-      iovb->tail = iovb->data = iovb->head;
+      iovb->data = iovb->head;
+      skb_reset_tail_pointer(iovb);
       NS_SKB(iovb)->vcc = vcc;
    }
    iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
@@ -2393,7 +2395,7 @@ #ifdef NS_USE_DESTRUCTORS
                skb->destructor = ns_lb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
                skb_push(skb, NS_SMBUFSIZE);
-               memcpy(skb->data, sb->data, NS_SMBUFSIZE);
+               skb_copy_from_linear_data(sb, skb->data, NS_SMBUFSIZE);
                skb_put(skb, len - NS_SMBUFSIZE);
                ATM_SKB(skb)->vcc = vcc;
 	       __net_timestamp(skb);
@@ -2477,7 +2479,7 @@ #endif /* NS_USE_DESTRUCTORS */
 	 {
             /* Copy the small buffer to the huge buffer */
             sb = (struct sk_buff *) iov->iov_base;
-            memcpy(hb->data, sb->data, iov->iov_len);
+            skb_copy_from_linear_data(sb, hb->data, iov->iov_len);
             skb_put(hb, iov->iov_len);
             remaining = len - iov->iov_len;
             iov++;
@@ -2489,7 +2491,7 @@ #endif /* NS_USE_DESTRUCTORS */
             {
                lb = (struct sk_buff *) iov->iov_base;
                tocopy = min_t(int, remaining, iov->iov_len);
-               memcpy(hb->tail, lb->data, tocopy);
+               skb_copy_from_linear_data(lb, skb_tail_pointer(hb), tocopy);
                skb_put(hb, tocopy);
                iov++;
                remaining -= tocopy;
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index e9eb738..b39ea3f 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -2,10 +2,10 @@ # Makefile for the Linux device tree
 
 obj-y			:= core.o sys.o bus.o dd.o \
 			   driver.o class.o platform.o \
-			   cpu.o firmware.o init.o map.o dmapool.o \
-			   dma-mapping.o devres.o \
+			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o
 obj-y			+= power/
+obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o dmapool.o
 obj-$(CONFIG_ISA)	+= isa.o
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 2222073..1ec0654 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -62,7 +62,7 @@ EXPORT_SYMBOL_GPL(attribute_container_cl
 
 static struct list_head attribute_container_list;
 
-static DECLARE_MUTEX(attribute_container_mutex);
+static DEFINE_MUTEX(attribute_container_mutex);
 
 /**
  * attribute_container_register - register an attribute container
@@ -77,9 +77,9 @@ attribute_container_register(struct attr
 	klist_init(&cont->containers,internal_container_klist_get,
 		   internal_container_klist_put);
 		
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_add_tail(&cont->node, &attribute_container_list);
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 
 	return 0;
 }
@@ -94,7 +94,7 @@ int
 attribute_container_unregister(struct attribute_container *cont)
 {
 	int retval = -EBUSY;
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	spin_lock(&cont->containers.k_lock);
 	if (!list_empty(&cont->containers.k_list))
 		goto out;
@@ -102,7 +102,7 @@ attribute_container_unregister(struct at
 	list_del(&cont->node);
  out:
 	spin_unlock(&cont->containers.k_lock);
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 	return retval;
 		
 }
@@ -145,7 +145,7 @@ attribute_container_add_device(struct de
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 
@@ -173,7 +173,7 @@ attribute_container_add_device(struct de
 			attribute_container_add_class_device(&ic->classdev);
 		klist_add_tail(&ic->node, &cont->containers);
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /* FIXME: can't break out of this unless klist_iter_exit is also
@@ -211,7 +211,7 @@ attribute_container_remove_device(struct
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 		struct klist_iter iter;
@@ -234,7 +234,7 @@ attribute_container_remove_device(struct
 			}
 		}
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
@@ -255,7 +255,7 @@ attribute_container_device_trigger(struc
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		struct internal_container *ic;
 		struct klist_iter iter;
@@ -273,7 +273,7 @@ attribute_container_device_trigger(struc
 				fn(cont, dev, &ic->classdev);
 		}
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
@@ -295,12 +295,12 @@ attribute_container_trigger(struct devic
 {
 	struct attribute_container *cont;
 
-	down(&attribute_container_mutex);
+	mutex_lock(&attribute_container_mutex);
 	list_for_each_entry(cont, &attribute_container_list, node) {
 		if (cont->match(cont, dev))
 			fn(cont, dev);
 	}
-	up(&attribute_container_mutex);
+	mutex_unlock(&attribute_container_mutex);
 }
 
 /**
diff --git a/drivers/base/base.h b/drivers/base/base.h
index de7e144..5512d84 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 int bus_attach_device(struct device * dev);
+extern void 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);
@@ -45,3 +45,5 @@ struct class_device_attribute *to_class_
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern void devres_release_all(struct device *dev);
+
+extern struct kset devices_subsys;
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 253868e..dca7348 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -17,7 +17,7 @@ #include "base.h"
 #include "power/power.h"
 
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj)
+#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
 
 /*
  * sysfs bindings for drivers
@@ -27,6 +27,9 @@ #define to_drv_attr(_attr) container_of(
 #define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
+static int __must_check bus_rescan_devices_helper(struct device *dev,
+						void *data);
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops
 
 static void driver_release(struct kobject * kobj)
 {
-	struct device_driver * drv = to_driver(kobj);
-	complete(&drv->unloaded);
+	/*
+	 * Yes this is an empty release function, it is this way because struct
+	 * device is always a static object, not a dynamic one.  Yes, this is
+	 * not nice and bad, but remember, drivers are code, reference counted
+	 * by the module count, not a device, which is really data.  And yes,
+	 * in the future I do want to have all drivers be created dynamically,
+	 * and am working toward that goal, but it will take a bit longer...
+	 *
+	 * But do not let this example give _anyone_ the idea that they can
+	 * create a release function without any code in it at all, to do that
+	 * is almost always wrong.  If you have any questions about this,
+	 * please send an email to <greg@kroah.com>
+	 */
 }
 
 static struct kobj_type ktype_driver = {
@@ -109,7 +123,7 @@ int bus_create_file(struct bus_type * bu
 {
 	int error;
 	if (get_bus(bus)) {
-		error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr);
+		error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
 		put_bus(bus);
 	} else
 		error = -EINVAL;
@@ -119,7 +133,7 @@ int bus_create_file(struct bus_type * bu
 void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
 {
 	if (get_bus(bus)) {
-		sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr);
+		sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
 		put_bus(bus);
 	}
 }
@@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL
 
 
 #ifdef CONFIG_HOTPLUG
-
 /* Manually detach a device from its associated driver. */
 static int driver_helper(struct device *dev, void *data)
 {
@@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
+static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
+{
+	return sprintf(buf, "%d\n", bus->drivers_autoprobe);
+}
+
+static ssize_t store_drivers_autoprobe(struct bus_type *bus,
+				       const char *buf, size_t count)
+{
+	if (buf[0] == '0')
+		bus->drivers_autoprobe = 0;
+	else
+		bus->drivers_autoprobe = 1;
+	return count;
+}
+
+static ssize_t store_drivers_probe(struct bus_type *bus,
+				   const char *buf, size_t count)
+{
+	struct device *dev;
+
+	dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+	if (!dev)
+		return -ENODEV;
+	if (bus_rescan_devices_helper(dev, NULL) != 0)
+		return -EINVAL;
+	return count;
+}
 #endif
 
 static struct device * next_device(struct klist_iter * i)
@@ -357,7 +397,7 @@ #ifdef CONFIG_SYSFS_DEPRECATED
 static int make_deprecated_bus_links(struct device *dev)
 {
 	return sysfs_create_link(&dev->kobj,
-				 &dev->bus->subsys.kset.kobj, "bus");
+				 &dev->bus->subsys.kobj, "bus");
 }
 
 static void remove_deprecated_bus_links(struct device *dev)
@@ -391,7 +431,7 @@ int bus_add_device(struct device * dev)
 		if (error)
 			goto out_id;
 		error = sysfs_create_link(&dev->kobj,
-				&dev->bus->subsys.kset.kobj, "subsystem");
+				&dev->bus->subsys.kobj, "subsystem");
 		if (error)
 			goto out_subsys;
 		error = make_deprecated_bus_links(dev);
@@ -418,21 +458,21 @@ out_put:
  *	- Add device to bus's list of devices.
  *	- Try to attach to driver.
  */
-int bus_attach_device(struct device * dev)
+void bus_attach_device(struct device * dev)
 {
 	struct bus_type *bus = dev->bus;
 	int ret = 0;
 
 	if (bus) {
 		dev->is_registered = 1;
-		ret = device_attach(dev);
-		if (ret >= 0) {
+		if (bus->drivers_autoprobe)
+			ret = device_attach(dev);
+		WARN_ON(ret < 0);
+		if (ret >= 0)
 			klist_add_tail(&dev->knode_bus, &bus->klist_devices);
-			ret = 0;
-		} else
+		else
 			dev->is_registered = 0;
 	}
-	return ret;
 }
 
 /**
@@ -515,9 +555,41 @@ static void remove_bind_files(struct dev
 	driver_remove_file(drv, &driver_attr_bind);
 	driver_remove_file(drv, &driver_attr_unbind);
 }
+
+static int add_probe_files(struct bus_type *bus)
+{
+	int retval;
+
+	bus->drivers_probe_attr.attr.name = "drivers_probe";
+	bus->drivers_probe_attr.attr.mode = S_IWUSR;
+	bus->drivers_probe_attr.attr.owner = bus->owner;
+	bus->drivers_probe_attr.store = store_drivers_probe;
+	retval = bus_create_file(bus, &bus->drivers_probe_attr);
+	if (retval)
+		goto out;
+
+	bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
+	bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
+	bus->drivers_autoprobe_attr.attr.owner = bus->owner;
+	bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
+	bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
+	retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+	if (retval)
+		bus_remove_file(bus, &bus->drivers_probe_attr);
+out:
+	return retval;
+}
+
+static void remove_probe_files(struct bus_type *bus)
+{
+	bus_remove_file(bus, &bus->drivers_autoprobe_attr);
+	bus_remove_file(bus, &bus->drivers_probe_attr);
+}
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
 static inline void remove_bind_files(struct device_driver *drv) {}
+static inline int add_probe_files(struct bus_type *bus) { return 0; }
+static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
 /**
@@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver 
 	int error = 0;
 
 	if (!bus)
-		return 0;
+		return -EINVAL;
 
 	pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
 	error = kobject_set_name(&drv->kobj, "%s", drv->name);
@@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver 
 	if ((error = kobject_register(&drv->kobj)))
 		goto out_put_bus;
 
-	error = driver_attach(drv);
-	if (error)
-		goto out_unregister;
+	if (drv->bus->drivers_autoprobe) {
+		error = driver_attach(drv);
+		if (error)
+			goto out_unregister;
+	}
 	klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
@@ -605,8 +679,6 @@ static int __must_check bus_rescan_devic
 		ret = device_attach(dev);
 		if (dev->parent)
 			up(&dev->parent->sem);
-		if (ret > 0)
-			ret = 0;
 	}
 	return ret < 0 ? ret : 0;
 }
@@ -738,7 +810,7 @@ int bus_register(struct bus_type * bus)
 
 	BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
 
-	retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
+	retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
 	if (retval)
 		goto out;
 
@@ -748,13 +820,13 @@ int bus_register(struct bus_type * bus)
 		goto out;
 
 	kobject_set_name(&bus->devices.kobj, "devices");
-	bus->devices.subsys = &bus->subsys;
+	bus->devices.kobj.parent = &bus->subsys.kobj;
 	retval = kset_register(&bus->devices);
 	if (retval)
 		goto bus_devices_fail;
 
 	kobject_set_name(&bus->drivers.kobj, "drivers");
-	bus->drivers.subsys = &bus->subsys;
+	bus->drivers.kobj.parent = &bus->subsys.kobj;
 	bus->drivers.ktype = &ktype_driver;
 	retval = kset_register(&bus->drivers);
 	if (retval)
@@ -762,6 +834,12 @@ int bus_register(struct bus_type * bus)
 
 	klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
 	klist_init(&bus->klist_drivers, NULL, NULL);
+
+	bus->drivers_autoprobe = 1;
+	retval = add_probe_files(bus);
+	if (retval)
+		goto bus_probe_files_fail;
+
 	retval = bus_add_attrs(bus);
 	if (retval)
 		goto bus_attrs_fail;
@@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus)
 	return 0;
 
 bus_attrs_fail:
+	remove_probe_files(bus);
+bus_probe_files_fail:
 	kset_unregister(&bus->drivers);
 bus_drivers_fail:
 	kset_unregister(&bus->devices);
@@ -779,7 +859,6 @@ out:
 	return retval;
 }
 
-
 /**
  *	bus_unregister - remove a bus from the system
  *	@bus:	bus.
@@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bu
 {
 	pr_debug("bus %s: unregistering\n", bus->name);
 	bus_remove_attrs(bus);
+	remove_probe_files(bus);
 	kset_unregister(&bus->drivers);
 	kset_unregister(&bus->devices);
 	subsystem_unregister(&bus->subsys);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index d596812..20c4ea6 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -19,10 +19,8 @@ #include <linux/err.h>
 #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)
+#define to_class(obj) container_of(obj, struct class, subsys.kobj)
 
 static ssize_t
 class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
@@ -80,7 +78,7 @@ int class_create_file(struct class * cls
 {
 	int error;
 	if (cls) {
-		error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr);
+		error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
 	} else
 		error = -EINVAL;
 	return error;
@@ -89,7 +87,7 @@ int class_create_file(struct class * cls
 void class_remove_file(struct class * cls, const struct class_attribute * attr)
 {
 	if (cls)
-		sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
+		sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
 }
 
 static struct class *class_get(struct class *cls)
@@ -145,8 +143,9 @@ int class_register(struct class * cls)
 	INIT_LIST_HEAD(&cls->children);
 	INIT_LIST_HEAD(&cls->devices);
 	INIT_LIST_HEAD(&cls->interfaces);
+	kset_init(&cls->class_dirs);
 	init_MUTEX(&cls->sem);
-	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
+	error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);
 	if (error)
 		return error;
 
@@ -163,7 +162,6 @@ int class_register(struct class * cls)
 void class_unregister(struct class * cls)
 {
 	pr_debug("device class '%s': unregistering\n", cls->name);
-	kobject_unregister(cls->virtual_dir);
 	remove_class_attrs(cls);
 	subsystem_unregister(&cls->subsys);
 }
@@ -611,7 +609,7 @@ int class_device_add(struct class_device
 	if (parent_class_dev)
 		class_dev->kobj.parent = &parent_class_dev->kobj;
 	else
-		class_dev->kobj.parent = &parent_class->subsys.kset.kobj;
+		class_dev->kobj.parent = &parent_class->subsys.kobj;
 
 	error = kobject_add(&class_dev->kobj);
 	if (error)
@@ -619,7 +617,7 @@ int class_device_add(struct class_device
 
 	/* add the needed attributes to this device */
 	error = sysfs_create_link(&class_dev->kobj,
-				  &parent_class->subsys.kset.kobj, "subsystem");
+				  &parent_class->subsys.kobj, "subsystem");
 	if (error)
 		goto out3;
 	class_dev->uevent_attr.attr.name = "uevent";
@@ -917,8 +915,8 @@ int __init classes_init(void)
 	/* ick, this is ugly, the things we go through to keep from showing up
 	 * in sysfs... */
 	subsystem_init(&class_obj_subsys);
-	if (!class_obj_subsys.kset.subsys)
-			class_obj_subsys.kset.subsys = &class_obj_subsys;
+	if (!class_obj_subsys.kobj.parent)
+		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
 	return 0;
 }
 
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d7fcf82..b78fc1e 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -43,7 +43,8 @@ int (*platform_notify_remove)(struct dev
 const char *dev_driver_string(struct device *dev)
 {
 	return dev->driver ? dev->driver->name :
-			(dev->bus ? dev->bus->name : "");
+			(dev->bus ? dev->bus->name :
+			(dev->class ? dev->class->name : ""));
 }
 EXPORT_SYMBOL(dev_driver_string);
 
@@ -119,6 +120,8 @@ static int dev_uevent_filter(struct kset
 
 	if (ktype == &ktype_device) {
 		struct device *dev = to_dev(kobj);
+		if (dev->uevent_suppress)
+			return 0;
 		if (dev->bus)
 			return 1;
 		if (dev->class)
@@ -156,6 +159,11 @@ static int dev_uevent(struct kset *kset,
 			       "MINOR=%u", MINOR(dev->devt));
 	}
 
+	if (dev->type && dev->type->name)
+		add_uevent_var(envp, num_envp, &i,
+			       buffer, buffer_size, &length,
+			       "DEVTYPE=%s", dev->type->name);
+
 	if (dev->driver)
 		add_uevent_var(envp, num_envp, &i,
 			       buffer, buffer_size, &length,
@@ -238,71 +246,157 @@ static struct kset_uevent_ops device_uev
 	.uevent =	dev_uevent,
 };
 
+static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct kobject *top_kobj;
+	struct kset *kset;
+	char *envp[32];
+	char *data = NULL;
+	char *pos;
+	int i;
+	size_t count = 0;
+	int retval;
+
+	/* search the kset, the device belongs to */
+	top_kobj = &dev->kobj;
+	if (!top_kobj->kset && top_kobj->parent) {
+		do {
+			top_kobj = top_kobj->parent;
+		} while (!top_kobj->kset && top_kobj->parent);
+	}
+	if (!top_kobj->kset)
+		goto out;
+	kset = top_kobj->kset;
+	if (!kset->uevent_ops || !kset->uevent_ops->uevent)
+		goto out;
+
+	/* respect filter */
+	if (kset->uevent_ops && kset->uevent_ops->filter)
+		if (!kset->uevent_ops->filter(kset, &dev->kobj))
+			goto out;
+
+	data = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* let the kset specific function add its keys */
+	pos = data;
+	retval = kset->uevent_ops->uevent(kset, &dev->kobj,
+					  envp, ARRAY_SIZE(envp),
+					  pos, PAGE_SIZE);
+	if (retval)
+		goto out;
+
+	/* copy keys to file */
+	for (i = 0; envp[i]; i++) {
+		pos = &buf[count];
+		count += sprintf(pos, "%s\n", envp[i]);
+	}
+out:
+	free_page((unsigned long)data);
+	return count;
+}
+
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
+	if (memcmp(buf, "add", 3) != 0)
+		dev_err(dev, "uevent: unsupported action-string; this will "
+			"be ignored in a future kernel version");
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	return count;
 }
 
-static int device_add_groups(struct device *dev)
+static int device_add_attributes(struct device *dev,
+				 struct device_attribute *attrs)
 {
+	int error = 0;
 	int i;
+
+	if (attrs) {
+		for (i = 0; attr_name(attrs[i]); i++) {
+			error = device_create_file(dev, &attrs[i]);
+			if (error)
+				break;
+		}
+		if (error)
+			while (--i >= 0)
+				device_remove_file(dev, &attrs[i]);
+	}
+	return error;
+}
+
+static void device_remove_attributes(struct device *dev,
+				     struct device_attribute *attrs)
+{
+	int i;
+
+	if (attrs)
+		for (i = 0; attr_name(attrs[i]); i++)
+			device_remove_file(dev, &attrs[i]);
+}
+
+static int device_add_groups(struct device *dev,
+			     struct attribute_group **groups)
+{
 	int error = 0;
+	int i;
 
-	if (dev->groups) {
-		for (i = 0; dev->groups[i]; i++) {
-			error = sysfs_create_group(&dev->kobj, dev->groups[i]);
+	if (groups) {
+		for (i = 0; groups[i]; i++) {
+			error = sysfs_create_group(&dev->kobj, groups[i]);
 			if (error) {
 				while (--i >= 0)
-					sysfs_remove_group(&dev->kobj, dev->groups[i]);
-				goto out;
+					sysfs_remove_group(&dev->kobj, groups[i]);
+				break;
 			}
 		}
 	}
-out:
 	return error;
 }
 
-static void device_remove_groups(struct device *dev)
+static void device_remove_groups(struct device *dev,
+				 struct attribute_group **groups)
 {
 	int i;
-	if (dev->groups) {
-		for (i = 0; dev->groups[i]; i++) {
-			sysfs_remove_group(&dev->kobj, dev->groups[i]);
-		}
-	}
+
+	if (groups)
+		for (i = 0; groups[i]; i++)
+			sysfs_remove_group(&dev->kobj, groups[i]);
 }
 
 static int device_add_attrs(struct device *dev)
 {
 	struct class *class = dev->class;
 	struct device_type *type = dev->type;
-	int error = 0;
-	int i;
+	int error;
 
-	if (class && 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 (class) {
+		error = device_add_attributes(dev, class->dev_attrs);
 		if (error)
-			while (--i >= 0)
-				device_remove_file(dev, &class->dev_attrs[i]);
+			return error;
 	}
 
-	if (type && type->attrs) {
-		for (i = 0; attr_name(type->attrs[i]); i++) {
-			error = device_create_file(dev, &type->attrs[i]);
-			if (error)
-				break;
-		}
+	if (type) {
+		error = device_add_groups(dev, type->groups);
 		if (error)
-			while (--i >= 0)
-				device_remove_file(dev, &type->attrs[i]);
+			goto err_remove_class_attrs;
 	}
 
+	error = device_add_groups(dev, dev->groups);
+	if (error)
+		goto err_remove_type_groups;
+
+	return 0;
+
+ err_remove_type_groups:
+	if (type)
+		device_remove_groups(dev, type->groups);
+ err_remove_class_attrs:
+	if (class)
+		device_remove_attributes(dev, class->dev_attrs);
+
 	return error;
 }
 
@@ -310,17 +404,14 @@ static void device_remove_attrs(struct d
 {
 	struct class *class = dev->class;
 	struct device_type *type = dev->type;
-	int i;
 
-	if (class && class->dev_attrs) {
-		for (i = 0; attr_name(class->dev_attrs[i]); i++)
-			device_remove_file(dev, &class->dev_attrs[i]);
-	}
+	device_remove_groups(dev, dev->groups);
 
-	if (type && type->attrs) {
-		for (i = 0; attr_name(type->attrs[i]); i++)
-			device_remove_file(dev, &type->attrs[i]);
-	}
+	if (type)
+		device_remove_groups(dev, type->groups);
+
+	if (class)
+		device_remove_attributes(dev, class->dev_attrs);
 }
 
 
@@ -394,9 +485,10 @@ void device_remove_bin_file(struct devic
 EXPORT_SYMBOL_GPL(device_remove_bin_file);
 
 /**
- * device_schedule_callback - helper to schedule a callback for a device
+ * device_schedule_callback_owner - helper to schedule a callback for a device
  * @dev: device.
  * @func: callback function to invoke later.
+ * @owner: module owning the callback routine
  *
  * Attribute methods must not unregister themselves or their parent device
  * (which would amount to the same thing).  Attempts to do so will deadlock,
@@ -407,20 +499,23 @@ EXPORT_SYMBOL_GPL(device_remove_bin_file
  * argument in the workqueue's process context.  @dev will be pinned until
  * @func returns.
  *
+ * This routine is usually called via the inline device_schedule_callback(),
+ * which automatically sets @owner to THIS_MODULE.
+ *
  * Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated.
+ * be allocated, -ENODEV if a reference to @owner isn't available.
  *
  * NOTE: This routine won't work if CONFIG_SYSFS isn't set!  It uses an
  * underlying sysfs routine (since it is intended for use by attribute
  * methods), and if sysfs isn't available you'll get nothing but -ENOSYS.
  */
-int device_schedule_callback(struct device *dev,
-		void (*func)(struct device *))
+int device_schedule_callback_owner(struct device *dev,
+		void (*func)(struct device *), struct module *owner)
 {
 	return sysfs_schedule_callback(&dev->kobj,
-			(void (*)(void *)) func, dev);
+			(void (*)(void *)) func, dev, owner);
 }
-EXPORT_SYMBOL_GPL(device_schedule_callback);
+EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
 
 static void klist_children_get(struct klist_node *n)
 {
@@ -470,41 +565,65 @@ static struct kobject * get_device_paren
 	/* Set the parent to the class, not the parent device */
 	/* this keeps sysfs from having a symlink to make old udevs happy */
 	if (dev->class)
-		return &dev->class->subsys.kset.kobj;
+		return &dev->class->subsys.kobj;
 	else if (parent)
 		return &parent->kobj;
 
 	return NULL;
 }
 #else
-static struct kobject * virtual_device_parent(struct device *dev)
+static struct kobject *virtual_device_parent(struct device *dev)
 {
-	if (!dev->class)
-		return ERR_PTR(-ENODEV);
+	static struct kobject *virtual_dir = NULL;
 
-	if (!dev->class->virtual_dir) {
-		static struct kobject *virtual_dir = NULL;
+	if (!virtual_dir)
+		virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
 
-		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);
-	}
-
-	return dev->class->virtual_dir;
+	return virtual_dir;
 }
 
 static struct kobject * get_device_parent(struct device *dev,
 					  struct device *parent)
 {
-	/* if this is a class device, and has no parent, create one */
-	if ((dev->class) && (parent == NULL)) {
-		return virtual_device_parent(dev);
-	} else if (parent)
+	if (dev->class) {
+		struct kobject *kobj = NULL;
+		struct kobject *parent_kobj;
+		struct kobject *k;
+
+		/*
+		 * If we have no parent, we live in "virtual".
+		 * Class-devices with a bus-device as parent, live
+		 * in a class-directory to prevent namespace collisions.
+		 */
+		if (parent == NULL)
+			parent_kobj = virtual_device_parent(dev);
+		else if (parent->class)
+			return &parent->kobj;
+		else
+			parent_kobj = &parent->kobj;
+
+		/* find our class-directory at the parent and reference it */
+		spin_lock(&dev->class->class_dirs.list_lock);
+		list_for_each_entry(k, &dev->class->class_dirs.list, entry)
+			if (k->parent == parent_kobj) {
+				kobj = kobject_get(k);
+				break;
+			}
+		spin_unlock(&dev->class->class_dirs.list_lock);
+		if (kobj)
+			return kobj;
+
+		/* or create a new class-directory at the parent device */
+		return kobject_kset_add_dir(&dev->class->class_dirs,
+					    parent_kobj, dev->class->name);
+	}
+
+	if (parent)
 		return &parent->kobj;
 	return NULL;
 }
-
 #endif
+
 static int setup_parent(struct device *dev, struct device *parent)
 {
 	struct kobject *kobj;
@@ -541,7 +660,6 @@ int device_add(struct device *dev)
 	pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
 
 	parent = get_device(dev->parent);
-
 	error = setup_parent(dev, parent);
 	if (error)
 		goto Error;
@@ -562,10 +680,11 @@ int device_add(struct device *dev)
 					     BUS_NOTIFY_ADD_DEVICE, dev);
 
 	dev->uevent_attr.attr.name = "uevent";
-	dev->uevent_attr.attr.mode = S_IWUSR;
+	dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR;
 	if (dev->driver)
 		dev->uevent_attr.attr.owner = dev->driver->owner;
 	dev->uevent_attr.store = store_uevent;
+	dev->uevent_attr.show = show_uevent;
 	error = device_create_file(dev, &dev->uevent_attr);
 	if (error)
 		goto attrError;
@@ -592,12 +711,12 @@ int device_add(struct device *dev)
 	}
 
 	if (dev->class) {
-		sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
+		sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
 				  "subsystem");
 		/* If this is not a "fake" compatible device, then create the
 		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
-			sysfs_create_link(&dev->class->subsys.kset.kobj,
+		if (dev->kobj.parent != &dev->class->subsys.kobj)
+			sysfs_create_link(&dev->class->subsys.kobj,
 					  &dev->kobj, dev->bus_id);
 		if (parent) {
 			sysfs_create_link(&dev->kobj, &dev->parent->kobj,
@@ -614,16 +733,12 @@ #endif
 
 	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;
-	if (!dev->uevent_suppress)
-		kobject_uevent(&dev->kobj, KOBJ_ADD);
-	if ((error = bus_attach_device(dev)))
-		goto AttachError;
+	kobject_uevent(&dev->kobj, KOBJ_ADD);
+	bus_attach_device(dev);
 	if (parent)
 		klist_add_tail(&dev->knode_parent, &parent->klist_children);
 
@@ -639,19 +754,15 @@ #endif
 		up(&dev->class->sem);
 	}
  Done:
- 	kfree(class_name);
+	kfree(class_name);
 	put_device(dev);
 	return error;
- AttachError:
-	bus_remove_device(dev);
  BusError:
 	device_pm_remove(dev);
  PMError:
 	if (dev->bus)
 		blocking_notifier_call_chain(&dev->bus->bus_notifier,
 					     BUS_NOTIFY_DEL_DEVICE, dev);
-	device_remove_groups(dev);
- GroupError:
 	device_remove_attrs(dev);
  AttrsError:
 	if (dev->devt_attr) {
@@ -663,8 +774,8 @@ #endif
 		sysfs_remove_link(&dev->kobj, "subsystem");
 		/* If this is not a "fake" compatible device, remove the
 		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
-			sysfs_remove_link(&dev->class->subsys.kset.kobj,
+		if (dev->kobj.parent != &dev->class->subsys.kobj)
+			sysfs_remove_link(&dev->class->subsys.kobj,
 					  dev->bus_id);
 		if (parent) {
 #ifdef CONFIG_SYSFS_DEPRECATED
@@ -677,15 +788,6 @@ #ifdef CONFIG_SYSFS_DEPRECATED
 #endif
 			sysfs_remove_link(&dev->kobj, "device");
 		}
-
-		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);
 	}
  ueventattrError:
 	device_remove_file(dev, &dev->uevent_attr);
@@ -773,8 +875,8 @@ void device_del(struct device * dev)
 		sysfs_remove_link(&dev->kobj, "subsystem");
 		/* If this is not a "fake" compatible device, remove the
 		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
-			sysfs_remove_link(&dev->class->subsys.kset.kobj,
+		if (dev->kobj.parent != &dev->class->subsys.kobj)
+			sysfs_remove_link(&dev->class->subsys.kobj,
 					  dev->bus_id);
 		if (parent) {
 #ifdef CONFIG_SYSFS_DEPRECATED
@@ -796,9 +898,33 @@ #endif
 		/* remove the device from the class list */
 		list_del_init(&dev->node);
 		up(&dev->class->sem);
+
+		/* If we live in a parent class-directory, unreference it */
+		if (dev->kobj.parent->kset == &dev->class->class_dirs) {
+			struct device *d;
+			int other = 0;
+
+			/*
+			 * if we are the last child of our class, delete
+			 * our class-directory at this parent
+			 */
+			down(&dev->class->sem);
+			list_for_each_entry(d, &dev->class->devices, node) {
+				if (d == dev)
+					continue;
+				if (d->kobj.parent == dev->kobj.parent) {
+					other = 1;
+					break;
+				}
+			}
+			if (!other)
+				kobject_del(dev->kobj.parent);
+
+			kobject_put(dev->kobj.parent);
+			up(&dev->class->sem);
+		}
 	}
 	device_remove_file(dev, &dev->uevent_attr);
-	device_remove_groups(dev);
 	device_remove_attrs(dev);
 	bus_remove_device(dev);
 
@@ -1066,9 +1192,9 @@ #ifdef CONFIG_SYSFS_DEPRECATED
 #endif
 
 	if (dev->class) {
-		sysfs_remove_link(&dev->class->subsys.kset.kobj,
+		sysfs_remove_link(&dev->class->subsys.kobj,
 				  old_symlink_name);
-		sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+		sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
 				  dev->bus_id);
 	}
 	put_device(dev);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6a48824..92428e5 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -94,19 +94,11 @@ int device_bind_driver(struct device *de
 	return ret;
 }
 
-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)
+static int really_probe(struct device *dev, struct device_driver *drv)
 {
-	struct stupid_thread_structure *data = void_data;
-	struct device_driver *drv = data->drv;
-	struct device *dev = data->dev;
 	int ret = 0;
 
 	atomic_inc(&probe_count);
@@ -154,7 +146,6 @@ probe_failed:
 	 */
 	ret = 0;
 done:
-	kfree(data);
 	atomic_dec(&probe_count);
 	wake_up(&probe_waitqueue);
 	return ret;
@@ -186,16 +177,14 @@ int driver_probe_done(void)
  * 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 returns 1 if a match is found, -ENODEV if the device is
+ * not registered, 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))
@@ -206,19 +195,7 @@ int driver_probe_device(struct device_dr
 	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);
+	ret = really_probe(dev, drv);
 
 done:
 	return ret;
@@ -230,6 +207,19 @@ static int __device_attach(struct device
 	return driver_probe_device(drv, dev);
 }
 
+static int device_probe_drivers(void *data)
+{
+	struct device *dev = data;
+	int ret = 0;
+
+	if (dev->bus) {
+		down(&dev->sem);
+		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+		up(&dev->sem);
+	}
+	return ret;
+}
+
 /**
  *	device_attach - try to attach device to a driver.
  *	@dev:	device.
@@ -239,7 +229,8 @@ static int __device_attach(struct device
  *	pair is found, break out and return.
  *
  *	Returns 1 if the device was bound to a driver;
- *	0 if no matching device was found; error code otherwise.
+ *	0 if no matching device was found;
+ *	-ENODEV if the device is not registered.
  *
  *	When called for a USB interface, @dev->parent->sem must be held.
  */
@@ -252,8 +243,13 @@ int device_attach(struct device * dev)
 		ret = device_bind_driver(dev);
 		if (ret == 0)
 			ret = 1;
-	} else
+		else {
+			dev->driver = NULL;
+			ret = 0;
+		}
+	} else {
 		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
+	}
 	up(&dev->sem);
 	return ret;
 }
@@ -379,33 +375,6 @@ 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);
 EXPORT_SYMBOL_GPL(device_attach);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index cd467c9..9406259 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -37,7 +37,7 @@ struct dma_page {	/* cacheable header fo
 
 #define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
 
-static DECLARE_MUTEX (pools_lock);
+static DEFINE_MUTEX (pools_lock);
 
 static ssize_t
 show_pools (struct device *dev, struct device_attribute *attr, char *buf)
@@ -55,7 +55,7 @@ show_pools (struct device *dev, struct d
 	size -= temp;
 	next += temp;
 
-	down (&pools_lock);
+	mutex_lock(&pools_lock);
 	list_for_each_entry(pool, &dev->dma_pools, pools) {
 		unsigned pages = 0;
 		unsigned blocks = 0;
@@ -73,7 +73,7 @@ show_pools (struct device *dev, struct d
 		size -= temp;
 		next += temp;
 	}
-	up (&pools_lock);
+	mutex_unlock(&pools_lock);
 
 	return PAGE_SIZE - size;
 }
@@ -143,7 +143,7 @@ dma_pool_create (const char *name, struc
 	if (dev) {
 		int ret;
 
-		down (&pools_lock);
+		mutex_lock(&pools_lock);
 		if (list_empty (&dev->dma_pools))
 			ret = device_create_file (dev, &dev_attr_pools);
 		else
@@ -155,7 +155,7 @@ dma_pool_create (const char *name, struc
 			kfree(retval);
 			retval = NULL;
 		}
-		up (&pools_lock);
+		mutex_unlock(&pools_lock);
 	} else
 		INIT_LIST_HEAD (&retval->pools);
 
@@ -231,11 +231,11 @@ #endif
 void
 dma_pool_destroy (struct dma_pool *pool)
 {
-	down (&pools_lock);
+	mutex_lock(&pools_lock);
 	list_del (&pool->pools);
 	if (pool->dev && list_empty (&pool->dev->dma_pools))
 		device_remove_file (pool->dev, &dev_attr_pools);
-	up (&pools_lock);
+	mutex_unlock(&pools_lock);
 
 	while (!list_empty (&pool->page_list)) {
 		struct dma_page		*page;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 082bfde..eb11475 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -149,10 +149,6 @@ void put_driver(struct device_driver * d
  *	We pass off most of the work to the bus_add_driver() call,
  *	since most of the things we have to do deal with the bus
  *	structures.
- *
- *	The one interesting aspect is that we setup @drv->unloaded
- *	as a completion that gets complete when the driver reference
- *	count reaches 0.
  */
 int driver_register(struct device_driver * drv)
 {
@@ -162,35 +158,19 @@ int driver_register(struct device_driver
 		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
 	}
 	klist_init(&drv->klist_devices, NULL, NULL);
-	init_completion(&drv->unloaded);
 	return bus_add_driver(drv);
 }
 
-
 /**
  *	driver_unregister - remove driver from system.
  *	@drv:	driver.
  *
  *	Again, we pass off most of the work to the bus-level call.
- *
- *	Though, once that is done, we wait until @drv->unloaded is completed.
- *	This will block until the driver refcount reaches 0, and it is
- *	released. Only modular drivers will call this function, and we
- *	have to guarantee that it won't complete, letting the driver
- *	unload until all references are gone.
  */
 
 void driver_unregister(struct device_driver * drv)
 {
 	bus_remove_driver(drv);
-	/*
-	 * If the driver is a module, we are probably in
-	 * the module unload path, and we want to wait
-	 * for everything to unload before we can actually
-	 * finish the unload.
-	 */
-	if (drv->owner)
-		wait_for_completion(&drv->unloaded);
 }
 
 /**
diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c
index cb1b98a..90c8629 100644
--- a/drivers/base/firmware.c
+++ b/drivers/base/firmware.c
@@ -17,13 +17,13 @@ #include "base.h"
 
 static decl_subsys(firmware, NULL, NULL);
 
-int firmware_register(struct subsystem * s)
+int firmware_register(struct kset *s)
 {
-	kset_set_kset_s(s, firmware_subsys);
+	kobj_set_kset_s(s, firmware_subsys);
 	return subsystem_register(s);
 }
 
-void firmware_unregister(struct subsystem * s)
+void firmware_unregister(struct kset *s)
 {
 	subsystem_unregister(s);
 }
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index c0a979a..97ab5bd 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -31,8 +31,6 @@ enum {
 	FW_STATUS_LOADING,
 	FW_STATUS_DONE,
 	FW_STATUS_ABORT,
-	FW_STATUS_READY,
-	FW_STATUS_READY_NOHOTPLUG,
 };
 
 static int loading_timeout = 60;	/* In seconds */
@@ -96,9 +94,6 @@ static int firmware_uevent(struct device
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
 	int i = 0, len = 0;
 
-	if (!test_bit(FW_STATUS_READY, &fw_priv->status))
-		return -ENODEV;
-
 	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
 			   "FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
@@ -333,6 +328,7 @@ static int fw_register_device(struct dev
 	f_dev->parent = device;
 	f_dev->class = &firmware_class;
 	dev_set_drvdata(f_dev, fw_priv);
+	f_dev->uevent_suppress = 1;
 	retval = device_register(f_dev);
 	if (retval) {
 		printk(KERN_ERR "%s: device_register failed\n",
@@ -382,9 +378,7 @@ static int fw_setup_device(struct firmwa
 	}
 
 	if (uevent)
-                set_bit(FW_STATUS_READY, &fw_priv->status);
-        else
-                set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
+		f_dev->uevent_suppress = 0;
 	*dev_p = f_dev;
 	goto out;
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 30480f6..eb84d9d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,6 +160,11 @@ static void platform_device_release(stru
  *
  *	Create a platform device object which can have other objects attached
  *	to it, and which will have attached objects freed when it is released.
+ *
+ *	This device will be marked as not supporting hotpluggable drivers; no
+ *	device add/remove uevents will be generated.  In the unusual case that
+ *	the device isn't being dynamically allocated as a legacy "probe the
+ *	hardware" driver, infrastructure code should reverse this marking.
  */
 struct platform_device *platform_device_alloc(const char *name, unsigned int id)
 {
@@ -172,6 +177,12 @@ struct platform_device *platform_device_
 		pa->pdev.id = id;
 		device_initialize(&pa->pdev.dev);
 		pa->pdev.dev.release = platform_device_release;
+
+		/* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
+		 * legacy probe-the-hardware drivers, which don't properly split
+		 * out device enumeration logic from drivers.
+		 */
+		pa->pdev.dev.uevent_suppress = 1;
 	}
 
 	return pa ? &pa->pdev : NULL;
@@ -292,20 +303,22 @@ EXPORT_SYMBOL_GPL(platform_device_add);
  *	@pdev:	platform device we're removing
  *
  *	Note that this function will also release all memory- and port-based
- *	resources owned by the device (@dev->resource).
+ *	resources owned by the device (@dev->resource).  This function
+ *	must _only_ be externally called in error cases.  All other usage
+ *	is a bug.
  */
 void platform_device_del(struct platform_device *pdev)
 {
 	int i;
 
 	if (pdev) {
+		device_del(&pdev->dev);
+
 		for (i = 0; i < pdev->num_resources; i++) {
 			struct resource *r = &pdev->resource[i];
 			if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
 				release_resource(r);
 		}
-
-		device_del(&pdev->dev);
 	}
 }
 EXPORT_SYMBOL_GPL(platform_device_del);
@@ -349,6 +362,13 @@ EXPORT_SYMBOL_GPL(platform_device_unregi
  *	memory allocated for the device allows drivers using such devices
  *	to be unloaded iwithout waiting for the last reference to the device
  *	to be dropped.
+ *
+ *	This interface is primarily intended for use with legacy drivers
+ *	which probe hardware directly.  Because such drivers create sysfs
+ *	device nodes themselves, rather than letting system infrastructure
+ *	handle such device enumeration tasks, they don't fully conform to
+ *	the Linux driver model.  In particular, when such drivers are built
+ *	as modules, they can't be "hotplugged".
  */
 struct platform_device *platform_device_register_simple(char *name, unsigned int id,
 							struct resource *res, unsigned int num)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index bbbb973..05dc876 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -29,6 +29,9 @@ LIST_HEAD(dpm_off_irq);
 DECLARE_MUTEX(dpm_sem);
 DECLARE_MUTEX(dpm_list_sem);
 
+int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
+
 /**
  *	device_pm_set_parent - Specify power dependency.
  *	@dev:		Device who needs power.
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index 020be36..a2c6418 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -26,7 +26,9 @@ int resume_device(struct device * dev)
 
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
+
 	down(&dev->sem);
+
 	if (dev->power.pm_parent
 			&& dev->power.pm_parent->power.power_state.event) {
 		dev_err(dev, "PM: resume from %d, parent %s still %d\n",
@@ -34,15 +36,24 @@ int resume_device(struct device * dev)
 			dev->power.pm_parent->bus_id,
 			dev->power.pm_parent->power.power_state.event);
 	}
+
 	if (dev->bus && dev->bus->resume) {
 		dev_dbg(dev,"resuming\n");
 		error = dev->bus->resume(dev);
 	}
-	if (dev->class && dev->class->resume) {
+
+	if (!error && dev->type && dev->type->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->type->resume(dev);
+	}
+
+	if (!error && dev->class && dev->class->resume) {
 		dev_dbg(dev,"class resume\n");
 		error = dev->class->resume(dev);
 	}
+
 	up(&dev->sem);
+
 	TRACE_RESUME(error);
 	return error;
 }
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index 3483ae4..a47ee1b 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -16,8 +16,6 @@ #include "power.h"
 
 #define to_dev(node) container_of(node, struct device, kobj.entry)
 
-extern struct subsystem devices_subsys;
-
 
 /**
  * We handle system devices differently - we suspend and shut them
@@ -36,8 +34,7 @@ void device_shutdown(void)
 {
 	struct device * dev, *devn;
 
-	down_write(&devices_subsys.rwsem);
-	list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
+	list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list,
 				kobj.entry) {
 		if (dev->bus && dev->bus->shutdown) {
 			dev_dbg(dev, "shutdown\n");
@@ -47,7 +44,6 @@ void device_shutdown(void)
 			dev->driver->shutdown(dev);
 		}
 	}
-	up_write(&devices_subsys.rwsem);
 
 	sysdev_shutdown();
 }
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index ece136b..42d2b86 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -78,6 +78,18 @@ int suspend_device(struct device * dev, 
 		suspend_report_result(dev->class->suspend, error);
 	}
 
+	if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) {
+		dev_dbg(dev, "%s%s\n",
+			suspend_verb(state.event),
+			((state.event == PM_EVENT_SUSPEND)
+					&& device_may_wakeup(dev))
+				? ", may wakeup"
+				: ""
+			);
+		error = dev->type->suspend(dev, state);
+		suspend_report_result(dev->type->suspend, error);
+	}
+
 	if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
 		dev_dbg(dev, "%s%s\n",
 			suspend_verb(state.event),
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 04e5db4..29f1291 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -25,7 +25,7 @@ #include <asm/semaphore.h>
 
 #include "base.h"
 
-extern struct subsystem devices_subsys;
+extern struct kset devices_subsys;
 
 #define to_sysdev(k) container_of(k, struct sys_device, kobj)
 #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
@@ -138,7 +138,7 @@ int sysdev_class_register(struct sysdev_
 	pr_debug("Registering sysdev class '%s'\n",
 		 kobject_name(&cls->kset.kobj));
 	INIT_LIST_HEAD(&cls->drivers);
-	cls->kset.subsys = &system_subsys;
+	cls->kset.kobj.parent = &system_subsys.kobj;
 	kset_set_kset_s(cls, system_subsys);
 	return kset_register(&cls->kset);
 }
@@ -309,7 +309,7 @@ void sysdev_shutdown(void)
 	pr_debug("Shutting Down System Devices\n");
 
 	down(&sysdev_drivers_lock);
-	list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+	list_for_each_entry_reverse(cls, &system_subsys.list,
 				    kset.kobj.entry) {
 		struct sys_device * sysdev;
 
@@ -384,7 +384,7 @@ int sysdev_suspend(pm_message_t state)
 
 	pr_debug("Suspending System Devices\n");
 
-	list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+	list_for_each_entry_reverse(cls, &system_subsys.list,
 				    kset.kobj.entry) {
 
 		pr_debug("Suspending type '%s':\n",
@@ -457,7 +457,7 @@ gbl_driver:
 	}
 
 	/* resume other classes */
-	list_for_each_entry_continue(cls, &system_subsys.kset.list,
+	list_for_each_entry_continue(cls, &system_subsys.list,
 					kset.kobj.entry) {
 		list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
 			pr_debug(" %s\n", kobject_name(&err_dev->kobj));
@@ -483,7 +483,7 @@ int sysdev_resume(void)
 
 	pr_debug("Resuming System Devices\n");
 
-	list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
+	list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) {
 		struct sys_device * sysdev;
 
 		pr_debug("Resuming type '%s':\n",
@@ -501,7 +501,7 @@ int sysdev_resume(void)
 
 int __init system_bus_init(void)
 {
-	system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
+	system_subsys.kobj.parent = &devices_subsys.kobj;
 	return subsystem_register(&system_subsys);
 }
 
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index e2e0432..1d9d9b4 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -65,7 +65,6 @@ #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 5d65621..27a1390 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1480,7 +1480,7 @@ static int fd_ioctl(struct inode *inode,
 		break;
 	case FDFMTEND:
 		floppy_off(drive);
-		invalidate_bdev(inode->i_bdev, 0);
+		invalidate_bdev(inode->i_bdev);
 		break;
 	case FDGETPRM:
 		memset((void *)&getprm, 0, sizeof (getprm));
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 2308e83..1d84668 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -48,6 +48,15 @@ struct aoe_hdr {
 	__be32 tag;
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct aoe_hdr *aoe_hdr(const struct sk_buff *skb)
+{
+	return (struct aoe_hdr *)skb_mac_header(skb);
+}
+#endif
+
 struct aoe_atahdr {
 	unsigned char aflags;
 	unsigned char errfeat;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 8d17d8d..01fbdd3 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -27,7 +27,8 @@ new_skb(ulong len)
 
 	skb = alloc_skb(len, GFP_ATOMIC);
 	if (skb) {
-		skb->nh.raw = skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
+		skb_reset_network_header(skb);
 		skb->protocol = __constant_htons(ETH_P_AOE);
 		skb->priority = 0;
 		skb->next = skb->prev = NULL;
@@ -118,7 +119,7 @@ aoecmd_ata_rw(struct aoedev *d, struct f
 
 	/* initialize the headers & frame */
 	skb = f->skb;
-	h = (struct aoe_hdr *) skb->mac.raw;
+	h = aoe_hdr(skb);
 	ah = (struct aoe_atahdr *) (h+1);
 	skb_put(skb, sizeof *h + sizeof *ah);
 	memset(h, 0, skb->len);
@@ -193,21 +194,21 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
 	sl = sl_tail = NULL;
 
 	read_lock(&dev_base_lock);
-	for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
+	for_each_netdev(ifp) {
 		dev_hold(ifp);
 		if (!is_aoe_netif(ifp))
-			continue;
+			goto cont;
 
 		skb = new_skb(sizeof *h + sizeof *ch);
 		if (skb == NULL) {
 			printk(KERN_INFO "aoe: skb alloc failure\n");
-			continue;
+			goto cont;
 		}
 		skb_put(skb, sizeof *h + sizeof *ch);
 		skb->dev = ifp;
 		if (sl_tail == NULL)
 			sl_tail = skb;
-		h = (struct aoe_hdr *) skb->mac.raw;
+		h = aoe_hdr(skb);
 		memset(h, 0, sizeof *h + sizeof *ch);
 
 		memset(h->dst, 0xff, sizeof h->dst);
@@ -220,6 +221,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
 
 		skb->next = sl;
 		sl = skb;
+cont:
+		dev_put(ifp);
 	}
 	read_unlock(&dev_base_lock);
 
@@ -300,7 +303,7 @@ rexmit(struct aoedev *d, struct frame *f
 	aoechr_error(buf);
 
 	skb = f->skb;
-	h = (struct aoe_hdr *) skb->mac.raw;
+	h = aoe_hdr(skb);
 	ah = (struct aoe_atahdr *) (h+1);
 	f->tag = n;
 	h->tag = cpu_to_be32(n);
@@ -529,7 +532,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 	char ebuf[128];
 	u16 aoemajor;
 
-	hin = (struct aoe_hdr *) skb->mac.raw;
+	hin = aoe_hdr(skb);
 	aoemajor = be16_to_cpu(get_unaligned(&hin->major));
 	d = aoedev_by_aoeaddr(aoemajor, hin->minor);
 	if (d == NULL) {
@@ -561,7 +564,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
 	calc_rttavg(d, tsince(f->tag));
 
 	ahin = (struct aoe_atahdr *) (hin+1);
-	hout = (struct aoe_hdr *) f->skb->mac.raw;
+	hout = aoe_hdr(f->skb);
 	ahout = (struct aoe_atahdr *) (hout+1);
 	buf = f->buf;
 
@@ -695,7 +698,7 @@ aoecmd_ata_id(struct aoedev *d)
 
 	/* initialize the headers & frame */
 	skb = f->skb;
-	h = (struct aoe_hdr *) skb->mac.raw;
+	h = aoe_hdr(skb);
 	ah = (struct aoe_atahdr *) (h+1);
 	skb_put(skb, sizeof *h + sizeof *ah);
 	memset(h, 0, skb->len);
@@ -726,7 +729,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
 	enum { MAXFRAMES = 16 };
 	u16 n;
 
-	h = (struct aoe_hdr *) skb->mac.raw;
+	h = aoe_hdr(skb);
 	ch = (struct aoe_cfghdr *) (h+1);
 
 	/*
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index aab6d91..f9ddfda 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -123,7 +123,7 @@ aoenet_rcv(struct sk_buff *skb, struct n
 		goto exit;
 	skb_push(skb, ETH_HLEN);	/* (1) */
 
-	h = (struct aoe_hdr *) skb->mac.raw;
+	h = aoe_hdr(skb);
 	n = be32_to_cpu(get_unaligned(&h->tag));
 	if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
 		goto exit;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 65a725c..370dfe1 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -45,6 +45,10 @@ #include <linux/dma-mapping.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
 #include <linux/completion.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <scsi/scsi_ioctl.h>
+#include <linux/cdrom.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 #define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
@@ -1152,6 +1156,30 @@ #endif
 			kfree(ioc);
 			return status;
 		}
+
+	/* scsi_cmd_ioctl handles these, below, though some are not */
+	/* very meaningful for cciss.  SG_IO is the main one people want. */
+
+	case SG_GET_VERSION_NUM:
+	case SG_SET_TIMEOUT:
+	case SG_GET_TIMEOUT:
+	case SG_GET_RESERVED_SIZE:
+	case SG_SET_RESERVED_SIZE:
+	case SG_EMULATED_HOST:
+	case SG_IO:
+	case SCSI_IOCTL_SEND_COMMAND:
+		return scsi_cmd_ioctl(filep, disk, cmd, argp);
+
+	/* scsi_cmd_ioctl would normally handle these, below, but */
+	/* they aren't a good fit for cciss, as CD-ROMs are */
+	/* not supported, and we don't have any bus/target/lun */
+	/* which we present to the kernel. */
+
+	case CDROM_SEND_PACKET:
+	case CDROMCLOSETRAY:
+	case CDROMEJECT:
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
 	default:
 		return -ENOTTY;
 	}
@@ -1234,7 +1262,7 @@ static void cciss_softirq_done(struct re
 		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
 	}
 
-	complete_buffers(rq->bio, rq->errors);
+	complete_buffers(rq->bio, (rq->errors == 0));
 
 	if (blk_fs_request(rq)) {
 		const int rw = rq_data_dir(rq);
@@ -1248,7 +1276,7 @@ #endif				/* CCISS_DEBUG */
 
 	add_disk_randomness(rq->rq_disk);
 	spin_lock_irqsave(&h->lock, flags);
-	end_that_request_last(rq, rq->errors);
+	end_that_request_last(rq, (rq->errors == 0));
 	cmd_free(h, cmd, 1);
 	cciss_check_queues(h);
 	spin_unlock_irqrestore(&h->lock, flags);
@@ -2336,6 +2364,44 @@ static inline void resend_cciss_cmd(ctlr
 	start_io(h);
 }
 
+static inline int evaluate_target_status(CommandList_struct *cmd)
+{
+	unsigned char sense_key;
+	int error_count = 1;
+
+	if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */
+		if (!blk_pc_request(cmd->rq))
+			printk(KERN_WARNING "cciss: cmd %p "
+			       "has SCSI Status 0x%x\n",
+			       cmd, cmd->err_info->ScsiStatus);
+		return error_count;
+	}
+
+	/* check the sense key */
+	sense_key = 0xf & cmd->err_info->SenseInfo[2];
+	/* no status or recovered error */
+	if ((sense_key == 0x0) || (sense_key == 0x1))
+		error_count = 0;
+
+	if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
+		if (error_count != 0)
+			printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
+			       " sense key = 0x%x\n", cmd, sense_key);
+		return error_count;
+	}
+
+	/* SG_IO or similar, copy sense data back */
+	if (cmd->rq->sense) {
+		if (cmd->rq->sense_len > cmd->err_info->SenseLen)
+			cmd->rq->sense_len = cmd->err_info->SenseLen;
+		memcpy(cmd->rq->sense, cmd->err_info->SenseInfo,
+			cmd->rq->sense_len);
+	} else
+		cmd->rq->sense_len = 0;
+
+	return error_count;
+}
+
 /* checks the status of the job and calls complete buffers to mark all
  * buffers for the completed job. Note that this function does not need
  * to hold the hba/queue lock.
@@ -2343,109 +2409,99 @@ static inline void resend_cciss_cmd(ctlr
 static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
 				    int timeout)
 {
-	int status = 1;
 	int retry_cmd = 0;
+	struct request *rq = cmd->rq;
+
+	rq->errors = 0;
 
 	if (timeout)
-		status = 0;
+		rq->errors = 1;
 
-	if (cmd->err_info->CommandStatus != 0) {	/* an error has occurred */
-		switch (cmd->err_info->CommandStatus) {
-			unsigned char sense_key;
-		case CMD_TARGET_STATUS:
-			status = 0;
+	if (cmd->err_info->CommandStatus == 0)	/* no error has occurred */
+		goto after_error_processing;
 
-			if (cmd->err_info->ScsiStatus == 0x02) {
-				printk(KERN_WARNING "cciss: cmd %p "
-				       "has CHECK CONDITION "
-				       " byte 2 = 0x%x\n", cmd,
-				       cmd->err_info->SenseInfo[2]
-				    );
-				/* check the sense key */
-				sense_key = 0xf & cmd->err_info->SenseInfo[2];
-				/* no status or recovered error */
-				if ((sense_key == 0x0) || (sense_key == 0x1)) {
-					status = 1;
-				}
-			} else {
-				printk(KERN_WARNING "cciss: cmd %p "
-				       "has SCSI Status 0x%x\n",
-				       cmd, cmd->err_info->ScsiStatus);
-			}
-			break;
-		case CMD_DATA_UNDERRUN:
+	switch (cmd->err_info->CommandStatus) {
+	case CMD_TARGET_STATUS:
+		rq->errors = evaluate_target_status(cmd);
+		break;
+	case CMD_DATA_UNDERRUN:
+		if (blk_fs_request(cmd->rq)) {
 			printk(KERN_WARNING "cciss: cmd %p has"
 			       " completed with data underrun "
 			       "reported\n", cmd);
-			break;
-		case CMD_DATA_OVERRUN:
+			cmd->rq->data_len = cmd->err_info->ResidualCnt;
+		}
+		break;
+	case CMD_DATA_OVERRUN:
+		if (blk_fs_request(cmd->rq))
 			printk(KERN_WARNING "cciss: cmd %p has"
 			       " completed with data overrun "
 			       "reported\n", cmd);
-			break;
-		case CMD_INVALID:
-			printk(KERN_WARNING "cciss: cmd %p is "
-			       "reported invalid\n", cmd);
-			status = 0;
-			break;
-		case CMD_PROTOCOL_ERR:
-			printk(KERN_WARNING "cciss: cmd %p has "
-			       "protocol error \n", cmd);
-			status = 0;
-			break;
-		case CMD_HARDWARE_ERR:
-			printk(KERN_WARNING "cciss: cmd %p had "
-			       " hardware error\n", cmd);
-			status = 0;
-			break;
-		case CMD_CONNECTION_LOST:
-			printk(KERN_WARNING "cciss: cmd %p had "
-			       "connection lost\n", cmd);
-			status = 0;
-			break;
-		case CMD_ABORTED:
-			printk(KERN_WARNING "cciss: cmd %p was "
-			       "aborted\n", cmd);
-			status = 0;
-			break;
-		case CMD_ABORT_FAILED:
-			printk(KERN_WARNING "cciss: cmd %p reports "
-			       "abort failed\n", cmd);
-			status = 0;
-			break;
-		case CMD_UNSOLICITED_ABORT:
-			printk(KERN_WARNING "cciss%d: unsolicited "
-			       "abort %p\n", h->ctlr, cmd);
-			if (cmd->retry_count < MAX_CMD_RETRIES) {
-				retry_cmd = 1;
-				printk(KERN_WARNING
-				       "cciss%d: retrying %p\n", h->ctlr, cmd);
-				cmd->retry_count++;
-			} else
-				printk(KERN_WARNING
-				       "cciss%d: %p retried too "
-				       "many times\n", h->ctlr, cmd);
-			status = 0;
-			break;
-		case CMD_TIMEOUT:
-			printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
-			status = 0;
-			break;
-		default:
-			printk(KERN_WARNING "cciss: cmd %p returned "
-			       "unknown status %x\n", cmd,
-			       cmd->err_info->CommandStatus);
-			status = 0;
-		}
+		break;
+	case CMD_INVALID:
+		printk(KERN_WARNING "cciss: cmd %p is "
+		       "reported invalid\n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_PROTOCOL_ERR:
+		printk(KERN_WARNING "cciss: cmd %p has "
+		       "protocol error \n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_HARDWARE_ERR:
+		printk(KERN_WARNING "cciss: cmd %p had "
+		       " hardware error\n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_CONNECTION_LOST:
+		printk(KERN_WARNING "cciss: cmd %p had "
+		       "connection lost\n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_ABORTED:
+		printk(KERN_WARNING "cciss: cmd %p was "
+		       "aborted\n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_ABORT_FAILED:
+		printk(KERN_WARNING "cciss: cmd %p reports "
+		       "abort failed\n", cmd);
+		rq->errors = 1;
+		break;
+	case CMD_UNSOLICITED_ABORT:
+		printk(KERN_WARNING "cciss%d: unsolicited "
+		       "abort %p\n", h->ctlr, cmd);
+		if (cmd->retry_count < MAX_CMD_RETRIES) {
+			retry_cmd = 1;
+			printk(KERN_WARNING
+			       "cciss%d: retrying %p\n", h->ctlr, cmd);
+			cmd->retry_count++;
+		} else
+			printk(KERN_WARNING
+			       "cciss%d: %p retried too "
+			       "many times\n", h->ctlr, cmd);
+		rq->errors = 1;
+		break;
+	case CMD_TIMEOUT:
+		printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+		rq->errors = 1;
+		break;
+	default:
+		printk(KERN_WARNING "cciss: cmd %p returned "
+		       "unknown status %x\n", cmd,
+		       cmd->err_info->CommandStatus);
+		rq->errors = 1;
 	}
+
+after_error_processing:
+
 	/* We need to return this command */
 	if (retry_cmd) {
 		resend_cciss_cmd(h, cmd);
 		return;
 	}
-
+	cmd->rq->data_len = 0;
 	cmd->rq->completion_data = cmd;
-	cmd->rq->errors = status;
 	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
 	blk_complete_request(cmd->rq);
 }
@@ -2539,32 +2595,40 @@ #ifdef CCISS_DEBUG
 #endif				/* CCISS_DEBUG */
 
 	c->Header.SGList = c->Header.SGTotal = seg;
-	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;
+	if (likely(blk_fs_request(creq))) {
+		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;
+		}
+	} else if (blk_pc_request(creq)) {
+		c->Request.CDBLen = creq->cmd_len;
+		memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
 	} 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;
+		printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type);
+		BUG();
 	}
 
 	spin_lock_irq(q->queue_lock);
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index bb15051..90961a8 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -35,7 +35,6 @@ #include <linux/string.h>
 
 #include <asm/atomic.h>
 
-#include <scsi/scsi.h> 
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h> 
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 5231ed7..3587cb4 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4334,7 +4334,10 @@ #endif
 		if (err)
 			goto out_flush_work;
 
-		device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+		err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+		if (err)
+			goto out_unreg_platform_dev;
+
 		/* to be cleaned up... */
 		disks[drive]->private_data = (void *)(long)drive;
 		disks[drive]->queue = floppy_queue;
@@ -4345,6 +4348,8 @@ #endif
 
 	return 0;
 
+out_unreg_platform_dev:
+	platform_device_unregister(&floppy_device[drive]);
 out_flush_work:
 	flush_scheduled_work();
 	if (usage_count)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6b5b642..af6d727 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -77,9 +77,8 @@ #include <linux/kthread.h>
 
 #include <asm/uaccess.h>
 
-static int max_loop = 8;
-static struct loop_device *loop_dev;
-static struct gendisk **disks;
+static LIST_HEAD(loop_devices);
+static DEFINE_MUTEX(loop_devices_mutex);
 
 /*
  * Transfer functions
@@ -183,7 +182,7 @@ figure_loop_size(struct loop_device *lo)
 	if (unlikely((loff_t)x != size))
 		return -EFBIG;
 
-	set_capacity(disks[lo->lo_number], x);
+	set_capacity(lo->lo_disk, x);
 	return 0;					
 }
 
@@ -812,7 +811,7 @@ static int loop_set_fd(struct loop_devic
 	lo->lo_queue->queuedata = lo;
 	lo->lo_queue->unplug_fn = loop_unplug;
 
-	set_capacity(disks[lo->lo_number], size);
+	set_capacity(lo->lo_disk, size);
 	bd_set_size(bdev, size << 9);
 
 	set_blocksize(bdev, lo_blocksize);
@@ -832,8 +831,8 @@ out_clr:
 	lo->lo_device = NULL;
 	lo->lo_backing_file = NULL;
 	lo->lo_flags = 0;
-	set_capacity(disks[lo->lo_number], 0);
-	invalidate_bdev(bdev, 0);
+	set_capacity(lo->lo_disk, 0);
+	invalidate_bdev(bdev);
 	bd_set_size(bdev, 0);
 	mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
 	lo->lo_state = Lo_unbound;
@@ -917,8 +916,8 @@ static int loop_clr_fd(struct loop_devic
 	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);
-	invalidate_bdev(bdev, 0);
-	set_capacity(disks[lo->lo_number], 0);
+	invalidate_bdev(bdev);
+	set_capacity(lo->lo_disk, 0);
 	bd_set_size(bdev, 0);
 	mapping_set_gfp_mask(filp->f_mapping, gfp);
 	lo->lo_state = Lo_unbound;
@@ -1322,6 +1321,18 @@ static long lo_compat_ioctl(struct file 
 }
 #endif
 
+static struct loop_device *loop_find_dev(int number)
+{
+	struct loop_device *lo;
+
+	list_for_each_entry(lo, &loop_devices, lo_list) {
+		if (lo->lo_number == number)
+			return lo;
+	}
+	return NULL;
+}
+
+static struct loop_device *loop_init_one(int i);
 static int lo_open(struct inode *inode, struct file *file)
 {
 	struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
@@ -1330,6 +1341,11 @@ static int lo_open(struct inode *inode, 
 	lo->lo_refcnt++;
 	mutex_unlock(&lo->lo_ctl_mutex);
 
+	mutex_lock(&loop_devices_mutex);
+	if (!loop_find_dev(lo->lo_number + 1))
+		loop_init_one(lo->lo_number + 1);
+	mutex_unlock(&loop_devices_mutex);
+
 	return 0;
 }
 
@@ -1357,8 +1373,9 @@ #endif
 /*
  * And now the modules code and kernel interface.
  */
+static int max_loop;
 module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
+MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
 
@@ -1383,7 +1400,7 @@ int loop_unregister_transfer(int number)
 
 	xfer_funcs[n] = NULL;
 
-	for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
+	list_for_each_entry(lo, &loop_devices, lo_list) {
 		mutex_lock(&lo->lo_ctl_mutex);
 
 		if (lo->lo_encryption == xfer)
@@ -1398,91 +1415,110 @@ int loop_unregister_transfer(int number)
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static int __init loop_init(void)
+static struct loop_device *loop_init_one(int i)
+{
+	struct loop_device *lo;
+	struct gendisk *disk;
+
+	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
+	if (!lo)
+		goto out;
+
+	lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
+	if (!lo->lo_queue)
+		goto out_free_dev;
+
+	disk = lo->lo_disk = alloc_disk(1);
+	if (!disk)
+		goto out_free_queue;
+
+	mutex_init(&lo->lo_ctl_mutex);
+	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;
+	disk->fops		= &lo_fops;
+	disk->private_data	= lo;
+	disk->queue		= lo->lo_queue;
+	sprintf(disk->disk_name, "loop%d", i);
+	add_disk(disk);
+	list_add_tail(&lo->lo_list, &loop_devices);
+	return lo;
+
+out_free_queue:
+	blk_cleanup_queue(lo->lo_queue);
+out_free_dev:
+	kfree(lo);
+out:
+	return ERR_PTR(-ENOMEM);
+}
+
+static void loop_del_one(struct loop_device *lo)
 {
-	int	i;
+	del_gendisk(lo->lo_disk);
+	blk_cleanup_queue(lo->lo_queue);
+	put_disk(lo->lo_disk);
+	list_del(&lo->lo_list);
+	kfree(lo);
+}
 
-	if (max_loop < 1 || max_loop > 256) {
-		printk(KERN_WARNING "loop: invalid max_loop (must be between"
-				    " 1 and 256), using default (8)\n");
-		max_loop = 8;
-	}
+static struct kobject *loop_probe(dev_t dev, int *part, void *data)
+{
+	unsigned int number = dev & MINORMASK;
+	struct loop_device *lo;
+
+	mutex_lock(&loop_devices_mutex);
+	lo = loop_find_dev(number);
+	if (lo == NULL)
+		lo = loop_init_one(number);
+	mutex_unlock(&loop_devices_mutex);
+
+	*part = 0;
+	if (IS_ERR(lo))
+		return (void *)lo;
+	else
+		return &lo->lo_disk->kobj;
+}
+
+static int __init loop_init(void)
+{
+	struct loop_device *lo;
 
 	if (register_blkdev(LOOP_MAJOR, "loop"))
 		return -EIO;
+	blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
+				  THIS_MODULE, loop_probe, NULL, NULL);
 
-	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
-	if (!loop_dev)
-		goto out_mem1;
-	memset(loop_dev, 0, max_loop * sizeof(struct loop_device));
+	lo = loop_init_one(0);
+	if (IS_ERR(lo))
+		goto out;
 
-	disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
-	if (!disks)
-		goto out_mem2;
+	if (max_loop) {
+		printk(KERN_INFO "loop: the max_loop option is obsolete "
+				 "and will be removed in March 2008\n");
 
-	for (i = 0; i < max_loop; i++) {
-		disks[i] = alloc_disk(1);
-		if (!disks[i])
-			goto out_mem3;
 	}
-
-	for (i = 0; i < max_loop; i++) {
-		struct loop_device *lo = &loop_dev[i];
-		struct gendisk *disk = disks[i];
-
-		memset(lo, 0, sizeof(*lo));
-		lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
-		if (!lo->lo_queue)
-			goto out_mem4;
-		mutex_init(&lo->lo_ctl_mutex);
-		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;
-		disk->fops = &lo_fops;
-		sprintf(disk->disk_name, "loop%d", i);
-		disk->private_data = lo;
-		disk->queue = lo->lo_queue;
-	}
-
-	/* We cannot fail after we call this, so another loop!*/
-	for (i = 0; i < max_loop; i++)
-		add_disk(disks[i]);
-	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
+	printk(KERN_INFO "loop: module loaded\n");
 	return 0;
 
-out_mem4:
-	while (i--)
-		blk_cleanup_queue(loop_dev[i].lo_queue);
-	i = max_loop;
-out_mem3:
-	while (i--)
-		put_disk(disks[i]);
-	kfree(disks);
-out_mem2:
-	kfree(loop_dev);
-out_mem1:
+out:
 	unregister_blkdev(LOOP_MAJOR, "loop");
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
 }
 
-static void loop_exit(void)
+static void __exit loop_exit(void)
 {
-	int i;
+	struct loop_device *lo, *next;
 
-	for (i = 0; i < max_loop; i++) {
-		del_gendisk(disks[i]);
-		blk_cleanup_queue(loop_dev[i].lo_queue);
-		put_disk(disks[i]);
-	}
+	list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+		loop_del_one(lo);
+
+	blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
 	if (unregister_blkdev(LOOP_MAJOR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
-	kfree(disks);
-	kfree(loop_dev);
 }
 
 module_init(loop_init);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 485aa87..43d4ebc 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -403,7 +403,7 @@ static void __exit rd_cleanup(void)
 		struct block_device *bdev = rd_bdev[i];
 		rd_bdev[i] = NULL;
 		if (bdev) {
-			invalidate_bdev(bdev, 1);
+			invalidate_bdev(bdev);
 			blkdev_put(bdev);
 		}
 		del_gendisk(rd_disks[i]);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 2098eff..746a118 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -2132,10 +2132,13 @@ static int ub_get_pipes(struct ub_dev *s
 		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 				== USB_ENDPOINT_XFER_BULK) {
 			/* BULK in or out? */
-			if (ep->bEndpointAddress & USB_DIR_IN)
-				ep_in = ep;
-			else
-				ep_out = ep;
+			if (ep->bEndpointAddress & USB_DIR_IN) {
+				if (ep_in == NULL)
+					ep_in = ep;
+			} else {
+				if (ep_out == NULL)
+					ep_out = ep;
+			}
 		}
 	}
 
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 5872036..6f5d620 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -44,7 +44,6 @@ #include <linux/ioctl.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 4c766f3..b990805 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -527,7 +527,7 @@ static int bfusb_send_frame(struct sk_bu
 		buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
 
 		memcpy(skb_put(nskb, 3), buf, 3);
-		memcpy(skb_put(nskb, size), skb->data + sent, size);
+		skb_copy_from_linear_data_offset(skb, sent, skb_put(nskb, size), size);
 
 		sent  += size;
 		count -= size;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index acfb6a4..851de4d 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -461,20 +461,20 @@ static void bluecard_receive(bluecard_in
 				switch (info->rx_state) {
 
 				case RECV_WAIT_EVENT_HEADER:
-					eh = (struct hci_event_hdr *)(info->rx_skb->data);
+					eh = hci_event_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = eh->plen;
 					break;
 
 				case RECV_WAIT_ACL_HEADER:
-					ah = (struct hci_acl_hdr *)(info->rx_skb->data);
+					ah = hci_acl_hdr(info->rx_skb);
 					dlen = __le16_to_cpu(ah->dlen);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = dlen;
 					break;
 
 				case RECV_WAIT_SCO_HEADER:
-					sh = (struct hci_sco_hdr *)(info->rx_skb->data);
+					sh = hci_sco_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = sh->dlen;
 					break;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 9fca651..e8ebd5d 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -231,7 +231,7 @@ static void bpa10x_wakeup(struct bpa10x_
 		cr = (struct usb_ctrlrequest *) urb->setup_packet;
 		cr->wLength = __cpu_to_le16(skb->len);
 
-		memcpy(urb->transfer_buffer, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
 		urb->transfer_buffer_length = skb->len;
 
 		err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -250,7 +250,7 @@ static void bpa10x_wakeup(struct bpa10x_
 		skb = skb_dequeue(&data->tx_queue);
 
 	if (skb) {
-		memcpy(urb->transfer_buffer, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
 		urb->transfer_buffer_length = skb->len;
 
 		err = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 18b0f39..3951607 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -303,20 +303,20 @@ static void bt3c_receive(bt3c_info_t *in
 				switch (info->rx_state) {
 
 				case RECV_WAIT_EVENT_HEADER:
-					eh = (struct hci_event_hdr *)(info->rx_skb->data);
+					eh = hci_event_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = eh->plen;
 					break;
 
 				case RECV_WAIT_ACL_HEADER:
-					ah = (struct hci_acl_hdr *)(info->rx_skb->data);
+					ah = hci_acl_hdr(info->rx_skb);
 					dlen = __le16_to_cpu(ah->dlen);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = dlen;
 					break;
 
 				case RECV_WAIT_SCO_HEADER:
-					sh = (struct hci_sco_hdr *)(info->rx_skb->data);
+					sh = hci_sco_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = sh->dlen;
 					break;
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index c1bce75..d7d2ea0 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -250,20 +250,20 @@ static void btuart_receive(btuart_info_t
 				switch (info->rx_state) {
 
 				case RECV_WAIT_EVENT_HEADER:
-					eh = (struct hci_event_hdr *)(info->rx_skb->data);
+					eh = hci_event_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = eh->plen;
 					break;
 
 				case RECV_WAIT_ACL_HEADER:
-					ah = (struct hci_acl_hdr *)(info->rx_skb->data);
+					ah = hci_acl_hdr(info->rx_skb);
 					dlen = __le16_to_cpu(ah->dlen);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = dlen;
 					break;
 
 				case RECV_WAIT_SCO_HEADER:
-					sh = (struct hci_sco_hdr *)(info->rx_skb->data);
+					sh = hci_sco_hdr(info->rx_skb);
 					info->rx_state = RECV_WAIT_DATA;
 					info->rx_count = sh->dlen;
 					break;
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 459aa97..7f9c54b 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -425,7 +425,7 @@ static int dtl1_hci_send_frame(struct sk
 		return -ENOMEM;
 
 	skb_reserve(s, NSHL);
-	memcpy(skb_put(s, skb->len), skb->data, skb->len);
+	skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
 	if (skb->len & 0x0001)
 		*skb_put(s, 1) = 0;	/* PAD */
 
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 34f0afc..bfbae14 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -188,7 +188,7 @@ static int h4_recv(struct hci_uart *hu, 
 				continue;
 
 			case H4_W4_EVENT_HDR:
-				eh = (struct hci_event_hdr *) h4->rx_skb->data;
+				eh = hci_event_hdr(h4->rx_skb);
 
 				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
 
@@ -196,7 +196,7 @@ static int h4_recv(struct hci_uart *hu, 
 				continue;
 
 			case H4_W4_ACL_HDR:
-				ah = (struct hci_acl_hdr *) h4->rx_skb->data;
+				ah = hci_acl_hdr(h4->rx_skb);
 				dlen = __le16_to_cpu(ah->dlen);
 
 				BT_DBG("ACL header: dlen %d", dlen);
@@ -205,7 +205,7 @@ static int h4_recv(struct hci_uart *hu, 
 				continue;
 
 			case H4_W4_SCO_HDR:
-				sh = (struct hci_sco_hdr *) h4->rx_skb->data;
+				sh = hci_sco_hdr(h4->rx_skb);
 
 				BT_DBG("SCO header: dlen %d", sh->dlen);
 
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 406af57..b0238b4 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -114,10 +114,16 @@ static struct usb_device_id blacklist_id
 	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
 
+	/* Broadcom BCM2045 */
+	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_WRONG_SCO_MTU },
+
 	/* IBM/Lenovo ThinkPad with Broadcom chip */
 	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU },
 
+	/* Targus ACB10US */
+	{ USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET },
+
 	/* ANYCOM Bluetooth USB-200 and USB-250 */
 	{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
 
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index b36f44d..3625a05 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2384,7 +2384,7 @@ static int cdrom_ioctl_reset(struct cdro
 		return -EACCES;
 	if (!CDROM_CAN(CDC_RESET))
 		return -ENOSYS;
-	invalidate_bdev(bdev, 0);
+	invalidate_bdev(bdev);
 	return cdi->ops->reset(cdi);
 }
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d0c978f..1e32fb8 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -127,7 +127,7 @@ config ROCKETPORT
 
 config CYCLADES
 	tristate "Cyclades async mux support"
-	depends on SERIAL_NONSTANDARD
+	depends on SERIAL_NONSTANDARD && (PCI || ISA)
 	---help---
 	  This driver supports Cyclades Z and Y multiserial boards.
 	  You would need something like this to connect more than two modems to
@@ -905,8 +905,8 @@ config SONYPI
 	  To compile this driver as a module, choose M here: the
 	  module will be called sonypi.
 
-config TANBAC_TB0219
-	tristate "TANBAC TB0219 base board support"
+config GPIO_TB0219
+	tristate "TANBAC TB0219 GPIO support"
 	depends on TANBAC_TB022X
 	select GPIO_VR41XX
 
@@ -1071,5 +1071,11 @@ config TELCLOCK
 	  /sys/devices/platform/telco_clock, with a number of files for
 	  controlling the behavior of this hardware.
 
+config DEVPORT
+	bool
+	depends on !M68K
+	depends on ISA || PCI
+	default y
+
 endmenu
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ae8567c..2f56ecc 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -91,7 +91,7 @@ obj-$(CONFIG_PC8736x_GPIO)	+= pc8736x_gp
 obj-$(CONFIG_NSC_GPIO)		+= nsc_gpio.o
 obj-$(CONFIG_CS5535_GPIO)	+= cs5535_gpio.o
 obj-$(CONFIG_GPIO_VR41XX)	+= vr41xx_giu.o
-obj-$(CONFIG_TANBAC_TB0219)	+= tb0219.o
+obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o
 obj-$(CONFIG_TELCLOCK)		+= tlclk.o
 
 obj-$(CONFIG_WATCHDOG)		+= watchdog/
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 5b684fd..4941ddb 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -145,6 +145,7 @@ static void *m1541_alloc_page(struct agp
 	void *addr = agp_generic_alloc_page(agp_bridge);
 	u32 temp;
 
+	global_flush_tlb();
 	if (!addr)
 		return NULL;
 
@@ -160,6 +161,7 @@ static void ali_destroy_page(void * addr
 	if (addr) {
 		global_cache_flush();	/* is this really needed?  --hch */
 		agp_generic_destroy_page(addr);
+		global_flush_tlb();
 	}
 }
 
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index b0acf41..aa8f3a3 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -173,7 +173,7 @@ alpha_core_agp_setup(void)
 	/*
 	 * Build a fake pci_dev struct
 	 */
-	pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	pdev = alloc_pci_dev();
 	if (!pdev)
 		return -ENOMEM;
 	pdev->vendor = 0xffff;
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 4857204..c9f0f25 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -14,6 +14,7 @@ #include <linux/init.h>
 #include <linux/agp_backend.h>
 #include <linux/mmzone.h>
 #include <asm/page.h>		/* PAGE_SIZE */
+#include <asm/e820.h>
 #include <asm/k8.h>
 #include "agp.h"
 
@@ -259,7 +260,6 @@ static const struct agp_bridge_driver am
 /* Some basic sanity checks for the aperture. */
 static int __devinit aperture_valid(u64 aper, u32 size)
 {
-	u32 pfn, c;
 	if (aper == 0) {
 		printk(KERN_ERR PFX "No aperture\n");
 		return 0;
@@ -272,14 +272,9 @@ static int __devinit aperture_valid(u64 
 		printk(KERN_ERR PFX "Aperture out of bounds\n");
 		return 0;
 	}
-	pfn = aper >> PAGE_SHIFT;
-	for (c = 0; c < size/PAGE_SIZE; c++) {
-		if (!pfn_valid(pfn + c))
-			break;
-		if (!PageReserved(pfn_to_page(pfn + c))) {
-			printk(KERN_ERR PFX "Aperture pointing to RAM\n");
-			return 0;
-		}
+	if (e820_any_mapped(aper, aper + size, E820_RAM)) {
+		printk(KERN_ERR PFX "Aperture pointing to RAM\n");
+		return 0;
 	}
 
 	/* Request the Aperture. This catches cases when someone else
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f902d71..45aeb91 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -51,28 +51,6 @@ int agp_memory_reserved;
  */
 EXPORT_SYMBOL_GPL(agp_memory_reserved);
 
-#if defined(CONFIG_X86)
-int map_page_into_agp(struct page *page)
-{
-	int i;
-	i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
-	/* Caller's responsibility to call global_flush_tlb() for
-	 * performance reasons */
-	return i;
-}
-EXPORT_SYMBOL_GPL(map_page_into_agp);
-
-int unmap_page_from_agp(struct page *page)
-{
-	int i;
-	i = change_page_attr(page, 1, PAGE_KERNEL);
-	/* Caller's responsibility to call global_flush_tlb() for
-	 * performance reasons */
-	return i;
-}
-EXPORT_SYMBOL_GPL(unmap_page_from_agp);
-#endif
-
 /*
  * Generic routines for handling agp_memory structures -
  * They use the basic page allocation routines to do the brunt of the work.
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 55392a4..9c69f2e 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -186,8 +186,9 @@ static void *i8xx_alloc_pages(void)
 		return NULL;
 
 	if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
+		change_page_attr(page, 4, PAGE_KERNEL);
 		global_flush_tlb();
-		__free_page(page);
+		__free_pages(page, 2);
 		return NULL;
 	}
 	global_flush_tlb();
@@ -209,7 +210,7 @@ static void i8xx_destroy_pages(void *add
 	global_flush_tlb();
 	put_page(page);
 	unlock_page(page);
-	free_pages((unsigned long)addr, 2);
+	__free_pages(page, 2);
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
 
@@ -315,9 +316,6 @@ static struct agp_memory *alloc_agpphysm
 	struct agp_memory *new;
 	void *addr;
 
-	if (pg_count != 1 && pg_count != 4)
-		return NULL;
-
 	switch (pg_count) {
 	case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
 		global_flush_tlb();
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 0c9dab5..6cd7373 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(st
 	u8 cap_ptr;
 
 	nvidia_private.dev_1 =
-		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
+		pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
 	nvidia_private.dev_2 =
-		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
+		pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
 	nvidia_private.dev_3 =
-		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
+		pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
 
 	if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) {
 		printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 "
@@ -443,6 +443,9 @@ static int __init agp_nvidia_init(void)
 static void __exit agp_nvidia_cleanup(void)
 {
 	pci_unregister_driver(&agp_nvidia_pci_driver);
+	pci_dev_put(nvidia_private.dev_1);
+	pci_dev_put(nvidia_private.dev_2);
+	pci_dev_put(nvidia_private.dev_3);
 }
 
 module_init(agp_nvidia_init);
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 3d83b46..f4562cc 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -329,7 +329,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, 
 	struct agp_bridge_data *bridge;
 	int error = 0;
 
-	fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+	fake_bridge_dev = alloc_pci_dev();
 	if (!fake_bridge_dev) {
 		error = -ENOMEM;
 		goto fail;
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index ee8f50e..cda608c 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -47,9 +47,8 @@ static void *sgi_tioca_alloc_page(struct
 
 	nid = info->ca_closest_node;
 	page = alloc_pages_node(nid, GFP_KERNEL, 0);
-	if (page == NULL) {
-		return 0;
-	}
+	if (!page)
+		return NULL;
 
 	get_page(page);
 	SetPageLocked(page);
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 125f428..eb1a1c7 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -143,96 +143,6 @@ static struct agp_bridge_driver sis_driv
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
-{
-	{
-		.device_id	= PCI_DEVICE_ID_SI_5591_AGP,
-		.chipset_name	= "5591",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_530,
-		.chipset_name	= "530",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_540,
-		.chipset_name	= "540",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_550,
-		.chipset_name	= "550",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_620,
-		.chipset_name	= "620",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_630,
-		.chipset_name	= "630",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_635,
-		.chipset_name	= "635",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_645,
-		.chipset_name	= "645",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_646,
-		.chipset_name	= "646",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_648,
-		.chipset_name	= "648",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_650,
-		.chipset_name	= "650",
-	},
-	{
-		.device_id  = PCI_DEVICE_ID_SI_651,
-		.chipset_name   = "651",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_655,
-		.chipset_name	= "655",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_661,
-		.chipset_name	= "661",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_730,
-		.chipset_name	= "730",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_735,
-		.chipset_name	= "735",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_740,
-		.chipset_name	= "740",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_741,
-		.chipset_name	= "741",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_745,
-		.chipset_name	= "745",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_746,
-		.chipset_name	= "746",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_SI_760,
-		.chipset_name	= "760",
-	},
-	{ }, /* dummy final entry, always present */
-};
-
-
 // chipsets that require the 'delay hack'
 static int sis_broken_chipsets[] __devinitdata = {
 	PCI_DEVICE_ID_SI_648,
@@ -269,29 +179,15 @@ static void __devinit sis_get_driver(str
 static int __devinit agp_sis_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *ent)
 {
-	struct agp_device_ids *devs = sis_agp_device_ids;
 	struct agp_bridge_data *bridge;
 	u8 cap_ptr;
-	int j;
 
 	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 	if (!cap_ptr)
 		return -ENODEV;
 
-	/* probe for known chipsets */
-	for (j = 0; devs[j].chipset_name; j++) {
-		if (pdev->device == devs[j].device_id) {
-			printk(KERN_INFO PFX "Detected SiS %s chipset\n",
-					devs[j].chipset_name);
-			goto found;
-		}
-	}
-
-	printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n",
-		    pdev->device);
-	return -ENODEV;
 
-found:
+	printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device);
 	bridge = agp_alloc_bridge();
 	if (!bridge)
 		return -ENOMEM;
@@ -320,12 +216,172 @@ static void __devexit agp_sis_remove(str
 
 static struct pci_device_id agp_sis_pci_table[] = {
 	{
-	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
-	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_SI,
-	.device		= PCI_ANY_ID,
-	.subvendor	= PCI_ANY_ID,
-	.subdevice	= PCI_ANY_ID,
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_5591_AGP,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_530,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_540,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_550,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_620,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_630,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_635,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_645,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_646,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_648,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_650,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_651,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_655,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_661,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_730,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_735,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_740,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_741,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_745,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_746,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{
+		.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+		.class_mask	= ~0,
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_760,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
 	},
 	{ }
 };
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 55212a3..551ef25 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -455,15 +455,6 @@ static int __devinit agp_serverworks_pro
 	u32 temp, temp2;
 	u8 cap_ptr = 0;
 
-	/* Everything is on func 1 here so we are hardcoding function one */
-	bridge_dev = pci_find_slot((unsigned int)pdev->bus->number,
-			PCI_DEVFN(0, 1));
-	if (!bridge_dev) {
-		printk(KERN_INFO PFX "Detected a Serverworks chipset "
-		       "but could not find the secondary device.\n");
-		return -ENODEV;
-	}
-
 	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 
 	switch (pdev->device) {
@@ -483,6 +474,15 @@ static int __devinit agp_serverworks_pro
 		return -ENODEV;
 	}
 
+	/* Everything is on func 1 here so we are hardcoding function one */
+	bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
+			PCI_DEVFN(0, 1));
+	if (!bridge_dev) {
+		printk(KERN_INFO PFX "Detected a Serverworks chipset "
+		       "but could not find the secondary device.\n");
+		return -ENODEV;
+	}
+
 	serverworks_private.svrwrks_dev = bridge_dev;
 	serverworks_private.gart_addr_ofs = 0x10;
 
@@ -515,7 +515,7 @@ static int __devinit agp_serverworks_pro
 
 	bridge->driver = &sworks_driver;
 	bridge->dev_private_data = &serverworks_private,
-	bridge->dev = pdev;
+	bridge->dev = pci_dev_get(pdev);
 
 	pci_set_drvdata(pdev, bridge);
 	return agp_add_bridge(bridge);
@@ -525,8 +525,11 @@ static void __devexit agp_serverworks_re
 {
 	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
+	pci_dev_put(bridge->dev);
 	agp_remove_bridge(bridge);
 	agp_put_bridge(bridge);
+	pci_dev_put(serverworks_private.svrwrks_dev);
+	serverworks_private.svrwrks_dev = NULL;
 }
 
 static struct pci_device_id agp_serverworks_pci_table[] = {
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 91b0621..42c0a60 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -613,7 +613,7 @@ static int __devinit agp_uninorth_probe(
 		uninorth_node = of_find_node_by_name(NULL, "u3");
 	}
 	if (uninorth_node) {
-		const int *revprop = get_property(uninorth_node,
+		const int *revprop = of_get_property(uninorth_node,
 				"device-rev", NULL);
 		if (revprop != NULL)
 			uninorth_rev = *revprop & 0x3f;
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 0e2b72f..4eaceab 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1574,7 +1574,7 @@ #endif
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 #endif
@@ -1700,7 +1700,7 @@ #ifdef SERIAL_DEBUG_OPEN
 #endif
 		schedule();
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	if (extra_count)
 		state->count++;
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index 8dcf9d2..ed53f54 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -202,13 +202,16 @@ static struct miscdevice briq_panel_misc
 
 static int __init briq_panel_init(void)
 {
-	struct device_node *root = find_path_device("/");
+	struct device_node *root = of_find_node_by_path("/");
 	const char *machine;
 	int i;
 
-	machine = get_property(root, "model", NULL);
-	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
+	machine = of_get_property(root, "model", NULL);
+	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
+		of_node_put(root);
 		return -ENODEV;
+	}
+	of_node_put(root);
 
 	printk(KERN_INFO
 		"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index b99b756..fd40b95 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -626,10 +626,10 @@ conv_uni_to_pc(struct vc_data *conp, lon
   
 	/* Only 16-bit codes supported at this time */
 	if (ucs > 0xffff)
-		ucs = 0xfffd;		/* U+FFFD: REPLACEMENT CHARACTER */
-	else if (ucs < 0x20 || ucs >= 0xfffe)
+		return -4;		/* Not found */
+	else if (ucs < 0x20)
 		return -1;		/* Not a printable character */
-	else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+	else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
 		return -2;			/* Zero-width space */
 	/*
 	 * UNI_DIRECT_BASE indicates the start of the region in the User Zone
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index c02d9e9..fe6d240 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -44,6 +44,7 @@ static struct pci_device_id divil_pci[] 
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
 	{ } /* NULL entry */
 };
+MODULE_DEVICE_TABLE(pci, divil_pci);
 
 static struct cdev cs5535_gpio_cdev;
 
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 16dc5d1..c72ee97 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -10,15 +10,14 @@ #undef	Z_EXT_CHARS_IN_BUFFER
  *
  * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
  * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
- * Currently maintained by Cyclades team <async@cyclades.com>.
  *
- * For Technical support and installation problems, please send e-mail
- * to support@cyclades.com.
+ * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
  *
  * Much of the design and some of the code came from serial.c
  * which was copyright (C) 1991, 1992  Linus Torvalds.  It was
  * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
  * and then fixed as suggested by Michael K. Johnson 12/12/92.
+ * Converted to pci probing and cleaned up by Jiri Slaby.
  *
  * This version supports shared IRQ's (only for PCI boards).
  *
@@ -591,7 +590,7 @@ #undef	Z_EXT_CHARS_IN_BUFFER
  *
  */
 
-#define CY_VERSION	"2.4"
+#define CY_VERSION	"2.5"
 
 /* If you need to install more boards than NR_CARDS, change the constant
    in the definition below. No other change is necessary to support up to
@@ -624,12 +623,6 @@ #undef	CY_16Y_HACK
 #undef	CY_ENABLE_MONITORING
 #undef	CY_PCI_DEBUG
 
-#if 0
-#define PAUSE __asm__("nop")
-#else
-#define PAUSE do {} while (0)
-#endif
-
 /*
  * Include section 
  */
@@ -659,17 +652,6 @@ #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#define	CY_LOCK(info,flags)					\
-		do {						\
-		spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
-		} while (0)
-
-#define	CY_UNLOCK(info,flags)					\
-		do {						\
-		spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
-		} while (0)
-
-#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 
@@ -682,13 +664,13 @@ static void cy_send_xchar(struct tty_str
 #define IS_CYC_Z(card) ((card).num_chips == -1)
 
 #define Z_FPGA_CHECK(card) \
-	((cy_readl(&((struct RUNTIME_9060 __iomem *) \
+	((readl(&((struct RUNTIME_9060 __iomem *) \
 		((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
 
-#define ISZLOADED(card)	(((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card)	(((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
 			((card).ctl_addr))->mail_box_0)) || \
 			Z_FPGA_CHECK(card)) && \
-			(ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \
+			(ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
 			((card).base_addr+ID_ADDRESS))->signature)))
 
 #ifndef SERIAL_XMIT_SIZE
@@ -725,8 +707,8 @@ static unsigned int cy_isa_addresses[] =
 #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
 
 #ifdef MODULE
-static long maddr[NR_CARDS] = { 0, };
-static int irq[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS];
+static int irq[NR_CARDS];
 
 module_param_array(maddr, long, NULL, 0);
 module_param_array(irq, int, NULL, 0);
@@ -739,11 +721,6 @@ #endif				/* CONFIG_ISA */
 */
 static struct cyclades_card cy_card[NR_CARDS];
 
-/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
-*/
-static struct cyclades_port cy_port[NR_PORTS];
-
 static int cy_next_channel;	/* next minor available */
 
 /*
@@ -825,9 +802,6 @@ static int cy_chip_offset[] = { 0x0000,
 
 /* PCI related definitions */
 
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
 #ifdef CONFIG_PCI
 static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },	/* PCI < 1Mb */
@@ -845,7 +819,7 @@ #endif
 
 static void cy_start(struct tty_struct *);
 static void set_line_char(struct cyclades_port *);
-static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
+static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
 #ifdef CONFIG_ISA
 static unsigned detect_isa_irq(void __iomem *);
 #endif				/* CONFIG_ISA */
@@ -858,7 +832,6 @@ static void cyz_poll(unsigned long);
 /* The Cyclades-Z polling cycle is defined by this variable */
 static long cyz_polling_cycle = CZ_DEF_POLL;
 
-static int cyz_timeron = 0;
 static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
 
 #else				/* CONFIG_CYZ_INTR */
@@ -871,21 +844,14 @@ static inline int serial_paranoia_check(
 {
 #ifdef SERIAL_PARANOIA_CHECK
 	if (!info) {
-		printk("cyc Warning: null cyclades_port for (%s) in %s\n",
-				name, routine);
-		return 1;
-	}
-
-	if ((long)info < (long)(&cy_port[0]) ||
-			(long)(&cy_port[NR_PORTS]) < (long)info) {
-		printk("cyc Warning: cyclades_port out of range for (%s) in "
-				"%s\n", name, routine);
+		printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
+				"in %s\n", name, routine);
 		return 1;
 	}
 
 	if (info->magic != CYCLADES_MAGIC) {
-		printk("cyc Warning: bad magic number for serial struct (%s) "
-				"in %s\n", name, routine);
+		printk(KERN_WARNING "cyc Warning: bad magic number for serial "
+				"struct (%s) in %s\n", name, routine);
 		return 1;
 	}
 #endif
@@ -943,22 +909,16 @@ do_softint(struct work_struct *work)
 	if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
 		wake_up_interruptible(&info->open_wait);
 #ifdef CONFIG_CYZ_INTR
-	if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
-		if (cyz_rx_full_timer[info->line].function == NULL) {
-			cyz_rx_full_timer[info->line].expires = jiffies + 1;
-			cyz_rx_full_timer[info->line].function = cyz_rx_restart;
-			cyz_rx_full_timer[info->line].data =
-						(unsigned long)info;
-			add_timer(&cyz_rx_full_timer[info->line]);
-		}
-	}
+	if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
+			!timer_pending(&cyz_rx_full_timer[info->line]))
+		mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
 #endif
 	if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
 		wake_up_interruptible(&info->delta_msr_wait);
 	tty_wakeup(tty);
 #ifdef Z_WAKE
 	if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
-		wake_up_interruptible(&info->shutdown_wait);
+		complete(&info->shutdown_wait);
 #endif
 } /* do_softint */
 
@@ -975,11 +935,11 @@ #endif
  */
 static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
 {
-	volatile int i;
+	unsigned int i;
 
 	/* Check to see that the previous command has completed */
 	for (i = 0; i < 100; i++) {
-		if (cy_readb(base_addr + (CyCCR << index)) == 0) {
+		if (readb(base_addr + (CyCCR << index)) == 0) {
 			break;
 		}
 		udelay(10L);
@@ -1022,7 +982,7 @@ static unsigned detect_isa_irq(void __io
 
 	cy_writeb(address + (CyCAR << index), 0);
 	cy_writeb(address + (CySRER << index),
-		  cy_readb(address + (CySRER << index)) | CyTxRdy);
+		  readb(address + (CySRER << index)) | CyTxRdy);
 	local_irq_restore(flags);
 
 	/* Wait ... */
@@ -1032,11 +992,11 @@ static unsigned detect_isa_irq(void __io
 	irq = probe_irq_off(irqs);
 
 	/* Clean up */
-	save_xir = (u_char) cy_readb(address + (CyTIR << index));
-	save_car = cy_readb(address + (CyCAR << index));
+	save_xir = (u_char) readb(address + (CyTIR << index));
+	save_car = readb(address + (CyCAR << index));
 	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
 	cy_writeb(address + (CySRER << index),
-		  cy_readb(address + (CySRER << index)) & ~CyTxRdy);
+		  readb(address + (CySRER << index)) & ~CyTxRdy);
 	cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
 	cy_writeb(address + (CyCAR << index), (save_car));
 	cy_writeb(address + (Cy_ClrIntr << index), 0);
@@ -1051,45 +1011,43 @@ static void cyy_intr_chip(struct cyclade
 {
 	struct cyclades_port *info;
 	struct tty_struct *tty;
-	volatile int char_count;
-	int i, j, len, mdm_change, mdm_status, outch;
+	int char_count;
+	int j, len, mdm_change, mdm_status, outch;
 	int save_xir, channel, save_car;
 	char data;
 
 	if (status & CySRReceive) {	/* reception interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-		printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
+		printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
 #endif
 		/* determine the channel & change to that context */
 		spin_lock(&cinfo->card_lock);
-		save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
+		save_xir = (u_char) readb(base_addr + (CyRIR << index));
 		channel = (u_short) (save_xir & CyIRChannel);
-		i = channel + chip * 4 + cinfo->first_line;
-		info = &cy_port[i];
-		info->last_active = jiffies;
-		save_car = cy_readb(base_addr + (CyCAR << index));
+		info = &cinfo->ports[channel + chip * 4];
+		save_car = readb(base_addr + (CyCAR << index));
 		cy_writeb(base_addr + (CyCAR << index), save_xir);
 
 		/* if there is nowhere to put the data, discard it */
-		if (info->tty == 0) {
-			j = (cy_readb(base_addr + (CyRIVR << index)) &
+		if (info->tty == NULL) {
+			j = (readb(base_addr + (CyRIVR << index)) &
 				CyIVRMask);
 			if (j == CyIVRRxEx) {	/* exception */
-				data = cy_readb(base_addr + (CyRDSR << index));
+				data = readb(base_addr + (CyRDSR << index));
 			} else {	/* normal character reception */
-				char_count = cy_readb(base_addr +
+				char_count = readb(base_addr +
 						(CyRDCR << index));
 				while (char_count--) {
-					data = cy_readb(base_addr +
+					data = readb(base_addr +
 						(CyRDSR << index));
 				}
 			}
 		} else {	/* there is an open port for this data */
 			tty = info->tty;
-			j = (cy_readb(base_addr + (CyRIVR << index)) &
+			j = (readb(base_addr + (CyRIVR << index)) &
 					CyIVRMask);
 			if (j == CyIVRRxEx) {	/* exception */
-				data = cy_readb(base_addr + (CyRDSR << index));
+				data = readb(base_addr + (CyRDSR << index));
 
 				/* For statistics only */
 				if (data & CyBREAK)
@@ -1110,7 +1068,7 @@ #endif
 						if (data & CyBREAK) {
 							tty_insert_flip_char(
 								tty,
-								cy_readb(
+								readb(
 								base_addr +
 								(CyRDSR <<
 									index)),
@@ -1123,7 +1081,7 @@ #endif
 						} else if (data & CyFRAME) {
 							tty_insert_flip_char(
 								tty,
-								cy_readb(
+								readb(
 								base_addr +
 								(CyRDSR <<
 									index)),
@@ -1135,7 +1093,7 @@ #endif
 							/* Pieces of seven... */
 							tty_insert_flip_char(
 								tty,
-								cy_readb(
+								readb(
 								base_addr +
 								(CyRDSR <<
 									index)),
@@ -1154,7 +1112,7 @@ #endif
 						 */
 							tty_insert_flip_char(
 								tty,
-								cy_readb(
+								readb(
 								base_addr +
 								(CyRDSR <<
 									index)),
@@ -1186,7 +1144,7 @@ #endif
 				}
 			} else {	/* normal character reception */
 				/* load # chars available from the chip */
-				char_count = cy_readb(base_addr +
+				char_count = readb(base_addr +
 						(CyRDCR << index));
 
 #ifdef CY_ENABLE_MONITORING
@@ -1198,7 +1156,7 @@ #ifdef CY_ENABLE_MONITORING
 #endif
 				len = tty_buffer_request_room(tty, char_count);
 				while (len--) {
-					data = cy_readb(base_addr +
+					data = readb(base_addr +
 							(CyRDSR << index));
 					tty_insert_flip_char(tty, data,
 							TTY_NORMAL);
@@ -1223,29 +1181,27 @@ #endif
 		   is empty, we know we can always stuff a dozen
 		   characters. */
 #ifdef CY_DEBUG_INTERRUPTS
-		printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
+		printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
 #endif
 
 		/* determine the channel & change to that context */
 		spin_lock(&cinfo->card_lock);
-		save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
+		save_xir = (u_char) readb(base_addr + (CyTIR << index));
 		channel = (u_short) (save_xir & CyIRChannel);
-		i = channel + chip * 4 + cinfo->first_line;
-		save_car = cy_readb(base_addr + (CyCAR << index));
+		save_car = readb(base_addr + (CyCAR << index));
 		cy_writeb(base_addr + (CyCAR << index), save_xir);
 
 		/* validate the port# (as configured and open) */
-		if ((i < 0) || (NR_PORTS <= i)) {
+		if (channel + chip * 4 >= cinfo->nports) {
 			cy_writeb(base_addr + (CySRER << index),
-				  cy_readb(base_addr + (CySRER << index)) &
+				  readb(base_addr + (CySRER << index)) &
 				  ~CyTxRdy);
 			goto txend;
 		}
-		info = &cy_port[i];
-		info->last_active = jiffies;
-		if (info->tty == 0) {
+		info = &cinfo->ports[channel + chip * 4];
+		if (info->tty == NULL) {
 			cy_writeb(base_addr + (CySRER << index),
-				  cy_readb(base_addr + (CySRER << index)) &
+				  readb(base_addr + (CySRER << index)) &
 				  ~CyTxRdy);
 			goto txdone;
 		}
@@ -1278,29 +1234,29 @@ #endif
 
 		while (char_count-- > 0) {
 			if (!info->xmit_cnt) {
-				if (cy_readb(base_addr + (CySRER << index)) &
+				if (readb(base_addr + (CySRER << index)) &
 						CyTxMpty) {
 					cy_writeb(base_addr + (CySRER << index),
-						cy_readb(base_addr +
+						readb(base_addr +
 							(CySRER << index)) &
 						~CyTxMpty);
 				} else {
 					cy_writeb(base_addr + (CySRER << index),
-						(cy_readb(base_addr +
+						(readb(base_addr +
 						  	(CySRER << index)) &
 						~CyTxRdy) | CyTxMpty);
 				}
 				goto txdone;
 			}
-			if (info->xmit_buf == 0) {
+			if (info->xmit_buf == NULL) {
 				cy_writeb(base_addr + (CySRER << index),
-					cy_readb(base_addr + (CySRER << index))&
+					readb(base_addr + (CySRER << index)) &
 					~CyTxRdy);
 				goto txdone;
 			}
 			if (info->tty->stopped || info->tty->hw_stopped) {
 				cy_writeb(base_addr + (CySRER << index),
-					cy_readb(base_addr + (CySRER << index))&
+					readb(base_addr + (CySRER << index)) &
 					~CyTxRdy);
 				goto txdone;
 			}
@@ -1333,7 +1289,6 @@ #endif
 						0);
 					info->icount.tx++;
 					char_count--;
-				} else {
 				}
 			}
 		}
@@ -1353,19 +1308,16 @@ txend:
 
 		/* determine the channel & change to that context */
 		spin_lock(&cinfo->card_lock);
-		save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
+		save_xir = (u_char) readb(base_addr + (CyMIR << index));
 		channel = (u_short) (save_xir & CyIRChannel);
-		info = &cy_port[channel + chip * 4 + cinfo->first_line];
-		info->last_active = jiffies;
-		save_car = cy_readb(base_addr + (CyCAR << index));
+		info = &cinfo->ports[channel + chip * 4];
+		save_car = readb(base_addr + (CyCAR << index));
 		cy_writeb(base_addr + (CyCAR << index), save_xir);
 
-		mdm_change = cy_readb(base_addr + (CyMISR << index));
-		mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
+		mdm_change = readb(base_addr + (CyMISR << index));
+		mdm_status = readb(base_addr + (CyMSVR1 << index));
 
-		if (info->tty == 0) {	/* no place for data, ignore it */
-			;
-		} else {
+		if (info->tty) {
 			if (mdm_change & CyANY_DELTA) {
 				/* For statistics only */
 				if (mdm_change & CyDCD)
@@ -1398,7 +1350,7 @@ txend:
 						info->tty->hw_stopped = 0;
 						cy_writeb(base_addr +
 							(CySRER << index),
-							cy_readb(base_addr +
+							readb(base_addr +
 								(CySRER <<
 									index))|
 							CyTxRdy);
@@ -1412,17 +1364,17 @@ txend:
 						info->tty->hw_stopped = 1;
 						cy_writeb(base_addr +
 							(CySRER << index),
-							cy_readb(base_addr +
+							readb(base_addr +
 								(CySRER <<
 								index)) &
 							~CyTxRdy);
 					}
 				}
 			}
-			if (mdm_change & CyDSR) {
+/*			if (mdm_change & CyDSR) {
 			}
 			if (mdm_change & CyRI) {
-			}
+			}*/
 		}
 		/* end of service */
 		cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
@@ -1438,16 +1390,16 @@ txend:
 static irqreturn_t cyy_interrupt(int irq, void *dev_id)
 {
 	int status;
-	struct cyclades_card *cinfo;
+	struct cyclades_card *cinfo = dev_id;
 	void __iomem *base_addr, *card_base_addr;
 	int chip;
 	int index;
 	int too_many;
 	int had_work;
 
-	if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+	if (unlikely(cinfo == NULL)) {
 #ifdef CY_DEBUG_INTERRUPTS
-		printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
+		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
 #endif
 		return IRQ_NONE;	/* spurious interrupt */
 	}
@@ -1455,6 +1407,10 @@ #endif
 	card_base_addr = cinfo->base_addr;
 	index = cinfo->bus_index;
 
+	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
+	if (unlikely(card_base_addr == NULL))
+		return IRQ_HANDLED;
+
 	/* This loop checks all chips in the card.  Make a note whenever
 	   _any_ chip had some work to do, as this is considered an
 	   indication that there will be more to do.  Only when no chip
@@ -1466,7 +1422,7 @@ #endif
 			base_addr = cinfo->base_addr +
 					(cy_chip_offset[chip] << index);
 			too_many = 0;
-			while ((status = cy_readb(base_addr +
+			while ((status = readb(base_addr +
 						(CySVRR << index))) != 0x00) {
 				had_work++;
 			/* The purpose of the following test is to ensure that
@@ -1498,7 +1454,7 @@ #endif
 
 static int
 cyz_fetch_msg(struct cyclades_card *cinfo,
-		uclong * channel, ucchar * cmd, uclong * param)
+		__u32 * channel, __u8 * cmd, __u32 * param)
 {
 	struct FIRM_ID __iomem *firm_id;
 	struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1509,16 +1465,15 @@ cyz_fetch_msg(struct cyclades_card *cinf
 	if (!ISZLOADED(*cinfo)) {
 		return -1;
 	}
-	zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
-			0xfffff);
+	zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 	board_ctrl = &zfw_ctrl->board_ctrl;
 
-	loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
+	loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
 				  (cinfo->ctl_addr))->loc_doorbell);
 	if (loc_doorbell) {
 		*cmd = (char)(0xff & loc_doorbell);
-		*channel = cy_readl(&board_ctrl->fwcmd_channel);
-		*param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
+		*channel = readl(&board_ctrl->fwcmd_channel);
+		*param = (__u32) readl(&board_ctrl->fwcmd_param);
 		cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
 			  loc_doorbell, 0xffffffff);
 		return 1;
@@ -1528,28 +1483,27 @@ cyz_fetch_msg(struct cyclades_card *cinf
 
 static int
 cyz_issue_cmd(struct cyclades_card *cinfo,
-		uclong channel, ucchar cmd, uclong param)
+		__u32 channel, __u8 cmd, __u32 param)
 {
 	struct FIRM_ID __iomem *firm_id;
 	struct ZFW_CTRL __iomem *zfw_ctrl;
 	struct BOARD_CTRL __iomem *board_ctrl;
-	unsigned long __iomem *pci_doorbell;
+	__u32 __iomem *pci_doorbell;
 	int index;
 
 	firm_id = cinfo->base_addr + ID_ADDRESS;
 	if (!ISZLOADED(*cinfo)) {
 		return -1;
 	}
-	zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
-			0xfffff);
+	zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 	board_ctrl = &zfw_ctrl->board_ctrl;
 
 	index = 0;
 	pci_doorbell =
 	    &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
-	while ((cy_readl(pci_doorbell) & 0xff) != 0) {
+	while ((readl(pci_doorbell) & 0xff) != 0) {
 		if (index++ == 1000) {
-			return (int)(cy_readl(pci_doorbell) & 0xff);
+			return (int)(readl(pci_doorbell) & 0xff);
 		}
 		udelay(50L);
 	}
@@ -1561,34 +1515,30 @@ cyz_issue_cmd(struct cyclades_card *cinf
 }				/* cyz_issue_cmd */
 
 static void
-cyz_handle_rx(struct cyclades_port *info,
-		volatile struct CH_CTRL __iomem * ch_ctrl,
-		volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+		struct BUF_CTRL __iomem *buf_ctrl)
 {
-	struct cyclades_card *cinfo = &cy_card[info->card];
+	struct cyclades_card *cinfo = info->card;
 	struct tty_struct *tty = info->tty;
-	volatile int char_count;
+	int char_count;
 	int len;
 #ifdef BLOCKMOVE
-	int small_count;
+	unsigned char *buf;
 #else
 	char data;
 #endif
-	volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
+	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
 
-	rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
-	rx_put = cy_readl(&buf_ctrl->rx_put);
-	rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
-	rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
+	rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
+	rx_put = readl(&buf_ctrl->rx_put);
+	rx_bufsize = readl(&buf_ctrl->rx_bufsize);
+	rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
 	if (rx_put >= rx_get)
 		char_count = rx_put - rx_get;
 	else
 		char_count = rx_put - rx_get + rx_bufsize;
 
 	if (char_count) {
-		info->last_active = jiffies;
-		info->jiffies[1] = jiffies;
-
 #ifdef CY_ENABLE_MONITORING
 		info->mon.int_count++;
 		info->mon.char_count += char_count;
@@ -1596,7 +1546,7 @@ #ifdef CY_ENABLE_MONITORING
 			info->mon.char_max = char_count;
 		info->mon.char_last = char_count;
 #endif
-		if (tty == 0) {
+		if (tty == NULL) {
 			/* flush received characters */
 			new_rx_get = (new_rx_get + char_count) &
 					(rx_bufsize - 1);
@@ -1606,30 +1556,28 @@ #ifdef BLOCKMOVE
 		/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
 		   for performance, but because of buffer boundaries, there
 		   may be several steps to the operation */
-			while (0 < (small_count = min_t(unsigned int,
-					rx_bufsize - new_rx_get,
-					min_t(unsigned int, TTY_FLIPBUF_SIZE -
-						tty->flip.count, char_count)))){
-				memcpy_fromio(tty->flip.char_buf_ptr,
-					(char *)(cinfo->base_addr + rx_bufaddr +
-						new_rx_get),
-					small_count);
+			while (1) {
+				len = tty_prepare_flip_string(tty, &buf,
+						char_count);
+				if (!len)
+					break;
 
-				tty->flip.char_buf_ptr += small_count;
-				memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
-					small_count);
-				tty->flip.flag_buf_ptr += small_count;
-				new_rx_get = (new_rx_get + small_count) &
+				len = min_t(unsigned int, min(len, char_count),
+						rx_bufsize - new_rx_get);
+
+				memcpy_fromio(buf, cinfo->base_addr +
+						rx_bufaddr + new_rx_get, len);
+
+				new_rx_get = (new_rx_get + len) &
 						(rx_bufsize - 1);
-				char_count -= small_count;
-				info->icount.rx += small_count;
-				info->idle_stats.recv_bytes += small_count;
-				tty->flip.count += small_count;
+				char_count -= len;
+				info->icount.rx += len;
+				info->idle_stats.recv_bytes += len;
 			}
 #else
 			len = tty_buffer_request_room(tty, char_count);
 			while (len--) {
-				data = cy_readb(cinfo->base_addr + rx_bufaddr +
+				data = readb(cinfo->base_addr + rx_bufaddr +
 						new_rx_get);
 				new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
 				tty_insert_flip_char(tty, data, TTY_NORMAL);
@@ -1640,13 +1588,12 @@ #endif
 #ifdef CONFIG_CYZ_INTR
 		/* Recalculate the number of chars in the RX buffer and issue
 		   a cmd in case it's higher than the RX high water mark */
-			rx_put = cy_readl(&buf_ctrl->rx_put);
+			rx_put = readl(&buf_ctrl->rx_put);
 			if (rx_put >= rx_get)
 				char_count = rx_put - rx_get;
 			else
 				char_count = rx_put - rx_get + rx_bufsize;
-			if (char_count >= (int)cy_readl(&buf_ctrl->
-					rx_threshold)) {
+			if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) {
 				cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
 			}
 #endif
@@ -1659,26 +1606,25 @@ #endif
 }
 
 static void
-cyz_handle_tx(struct cyclades_port *info,
-		volatile struct CH_CTRL __iomem * ch_ctrl,
-		volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+		struct BUF_CTRL __iomem *buf_ctrl)
 {
-	struct cyclades_card *cinfo = &cy_card[info->card];
+	struct cyclades_card *cinfo = info->card;
 	struct tty_struct *tty = info->tty;
 	char data;
-	volatile int char_count;
+	int char_count;
 #ifdef BLOCKMOVE
 	int small_count;
 #endif
-	volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
+	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
 
 	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
 		return;
 
-	tx_get = cy_readl(&buf_ctrl->tx_get);
-	tx_put = cy_readl(&buf_ctrl->tx_put);
-	tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
-	tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
+	tx_get = readl(&buf_ctrl->tx_get);
+	tx_put = readl(&buf_ctrl->tx_put);
+	tx_bufsize = readl(&buf_ctrl->tx_bufsize);
+	tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
 	if (tx_put >= tx_get)
 		char_count = tx_get - tx_put - 1 + tx_bufsize;
 	else
@@ -1686,9 +1632,8 @@ #endif
 
 	if (char_count) {
 
-		if (tty == 0) {
+		if (tty == NULL)
 			goto ztxdone;
-		}
 
 		if (info->x_char) {	/* send special char */
 			data = info->x_char;
@@ -1698,8 +1643,6 @@ #endif
 			info->x_char = 0;
 			char_count--;
 			info->icount.tx++;
-			info->last_active = jiffies;
-			info->jiffies[2] = jiffies;
 		}
 #ifdef BLOCKMOVE
 		while (0 < (small_count = min_t(unsigned int,
@@ -1719,8 +1662,6 @@ #ifdef BLOCKMOVE
 			info->xmit_cnt -= small_count;
 			info->xmit_tail = (info->xmit_tail + small_count) &
 					(SERIAL_XMIT_SIZE - 1);
-			info->last_active = jiffies;
-			info->jiffies[2] = jiffies;
 		}
 #else
 		while (info->xmit_cnt && char_count) {
@@ -1733,8 +1674,6 @@ #else
 			tx_put = (tx_put + 1) & (tx_bufsize - 1);
 			char_count--;
 			info->icount.tx++;
-			info->last_active = jiffies;
-			info->jiffies[2] = jiffies;
 		}
 #endif
 ztxdone:
@@ -1750,33 +1689,32 @@ static void cyz_handle_cmd(struct cyclad
 {
 	struct tty_struct *tty;
 	struct cyclades_port *info;
-	static volatile struct FIRM_ID __iomem *firm_id;
-	static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
-	static volatile struct BOARD_CTRL __iomem *board_ctrl;
-	static volatile struct CH_CTRL __iomem *ch_ctrl;
-	static volatile struct BUF_CTRL __iomem *buf_ctrl;
-	uclong channel;
-	ucchar cmd;
-	uclong param;
-	uclong hw_ver, fw_ver;
+	static struct FIRM_ID __iomem *firm_id;
+	static struct ZFW_CTRL __iomem *zfw_ctrl;
+	static struct BOARD_CTRL __iomem *board_ctrl;
+	static struct CH_CTRL __iomem *ch_ctrl;
+	static struct BUF_CTRL __iomem *buf_ctrl;
+	__u32 channel;
+	__u8 cmd;
+	__u32 param;
+	__u32 hw_ver, fw_ver;
 	int special_count;
 	int delta_count;
 
 	firm_id = cinfo->base_addr + ID_ADDRESS;
-	zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
-			0xfffff);
+	zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 	board_ctrl = &zfw_ctrl->board_ctrl;
-	fw_ver = cy_readl(&board_ctrl->fw_version);
-	hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+	fw_ver = readl(&board_ctrl->fw_version);
+	hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
 			mail_box_0);
 
 	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
 		special_count = 0;
 		delta_count = 0;
-		info = &cy_port[channel + cinfo->first_line];
-		if ((tty = info->tty) == 0) {
+		info = &cinfo->ports[channel];
+		if ((tty = info->tty) == NULL)
 			continue;
-		}
+
 		ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
 		buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
 
@@ -1801,7 +1739,7 @@ static void cyz_handle_cmd(struct cyclad
 			delta_count++;
 			if (info->flags & ASYNC_CHECK_CD) {
 				if ((fw_ver > 241 ? ((u_long) param) :
-						cy_readl(&ch_ctrl->rs_status)) &
+						readl(&ch_ctrl->rs_status)) &
 						C_RS_DCD) {
 					cy_sched_event(info,
 						 	Cy_EVENT_OPEN_WAKEUP);
@@ -1833,8 +1771,8 @@ #ifdef CONFIG_CYZ_INTR
 		case C_CM_INTBACK2:
 			/* Reception Interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-			printk("cyz_interrupt: rcvd intr, card %d, "
-					"port %ld\n\r", info->card, channel);
+			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
+					"port %ld\n", info->card, channel);
 #endif
 			cyz_handle_rx(info, ch_ctrl, buf_ctrl);
 			break;
@@ -1843,8 +1781,8 @@ #endif
 		case C_CM_INTBACK:
 			/* Transmission Interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-			printk("cyz_interrupt: xmit intr, card %d, "
-					"port %ld\n\r", info->card, channel);
+			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
+					"port %ld\n", info->card, channel);
 #endif
 			cyz_handle_tx(info, ch_ctrl, buf_ctrl);
 			break;
@@ -1865,18 +1803,19 @@ #endif				/* CONFIG_CYZ_INTR */
 #ifdef CONFIG_CYZ_INTR
 static irqreturn_t cyz_interrupt(int irq, void *dev_id)
 {
-	struct cyclades_card *cinfo;
+	struct cyclades_card *cinfo = dev_id;
 
-	if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+	if (unlikely(cinfo == NULL)) {
 #ifdef CY_DEBUG_INTERRUPTS
-		printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+		printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
 #endif
 		return IRQ_NONE;	/* spurious interrupt */
 	}
 
-	if (!ISZLOADED(*cinfo)) {
+	if (unlikely(!ISZLOADED(*cinfo))) {
 #ifdef CY_DEBUG_INTERRUPTS
-		printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
+				"(IRQ%d).\n", irq);
 #endif
 		return IRQ_NONE;
 	}
@@ -1890,19 +1829,18 @@ #endif
 static void cyz_rx_restart(unsigned long arg)
 {
 	struct cyclades_port *info = (struct cyclades_port *)arg;
+	struct cyclades_card *card = info->card;
 	int retval;
-	int card = info->card;
-	uclong channel = (info->line) - (cy_card[card].first_line);
+	__u32 channel = info->line - card->first_line;
 	unsigned long flags;
 
-	CY_LOCK(info, flags);
-	retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+	spin_lock_irqsave(&card->card_lock, flags);
+	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
 	if (retval != 0) {
-		printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
 			info->line, retval);
 	}
-	cyz_rx_full_timer[info->line].function = NULL;
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 }
 
 #else				/* CONFIG_CYZ_INTR */
@@ -1912,14 +1850,14 @@ static void cyz_poll(unsigned long arg)
 	struct cyclades_card *cinfo;
 	struct cyclades_port *info;
 	struct tty_struct *tty;
-	static volatile struct FIRM_ID *firm_id;
-	static volatile struct ZFW_CTRL *zfw_ctrl;
-	static volatile struct BOARD_CTRL *board_ctrl;
-	static volatile struct CH_CTRL *ch_ctrl;
-	static volatile struct BUF_CTRL *buf_ctrl;
+	static struct FIRM_ID *firm_id;
+	static struct ZFW_CTRL *zfw_ctrl;
+	static struct BOARD_CTRL *board_ctrl;
+	static struct CH_CTRL *ch_ctrl;
+	static struct BUF_CTRL *buf_ctrl;
+	unsigned long expires = jiffies + HZ;
 	int card, port;
 
-	cyz_timerlist.expires = jiffies + (HZ);
 	for (card = 0; card < NR_CARDS; card++) {
 		cinfo = &cy_card[card];
 
@@ -1930,12 +1868,12 @@ static void cyz_poll(unsigned long arg)
 
 		firm_id = cinfo->base_addr + ID_ADDRESS;
 		zfw_ctrl = cinfo->base_addr +
-				(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		board_ctrl = &(zfw_ctrl->board_ctrl);
 
 	/* Skip first polling cycle to avoid racing conditions with the FW */
 		if (!cinfo->intr_enabled) {
-			cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
+			cinfo->nports = (int)readl(&board_ctrl->n_channel);
 			cinfo->intr_enabled = 1;
 			continue;
 		}
@@ -1943,7 +1881,7 @@ static void cyz_poll(unsigned long arg)
 		cyz_handle_cmd(cinfo);
 
 		for (port = 0; port < cinfo->nports; port++) {
-			info = &cy_port[port + cinfo->first_line];
+			info = &cinfo->ports[port];
 			tty = info->tty;
 			ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
 			buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
@@ -1953,9 +1891,9 @@ static void cyz_poll(unsigned long arg)
 			cyz_handle_tx(info, ch_ctrl, buf_ctrl);
 		}
 		/* poll every 'cyz_polling_cycle' period */
-		cyz_timerlist.expires = jiffies + cyz_polling_cycle;
+		expires = jiffies + cyz_polling_cycle;
 	}
-	add_timer(&cyz_timerlist);
+	mod_timer(&cyz_timerlist, expires);
 }				/* cyz_poll */
 
 #endif				/* CONFIG_CYZ_INTR */
@@ -1968,20 +1906,21 @@ #endif				/* CONFIG_CYZ_INTR */
  */
 static int startup(struct cyclades_port *info)
 {
+	struct cyclades_card *card;
 	unsigned long flags;
 	int retval = 0;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 	unsigned long page;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
+	channel = info->line - card->first_line;
 
 	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&card->card_lock, flags);
 
 	if (info->flags & ASYNC_INITIALIZED) {
 		free_page(page);
@@ -2001,24 +1940,22 @@ static int startup(struct cyclades_port 
 	else
 		info->xmit_buf = (unsigned char *)page;
 
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 
 	set_line_char(info);
 
-	if (!IS_CYC_Z(cy_card[card])) {
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr = cy_card[card].base_addr +
-				(cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
 #ifdef CY_DEBUG_OPEN
-		printk("cyc startup card %d, chip %d, channel %d, "
-				"base_addr %lx\n",
-				card, chip, channel, (long)base_addr);
-		/**/
+		printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
+				"base_addr %p\n",
+				card, chip, channel, base_addr);
 #endif
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 
@@ -2034,14 +1971,14 @@ #endif
 		cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
 
 #ifdef CY_DEBUG_DTR
-		printk("cyc:startup raising DTR\n");
-		printk("     status: 0x%x, 0x%x\n",
-			cy_readb(base_addr + (CyMSVR1 << index)),
-			cy_readb(base_addr + (CyMSVR2 << index)));
+		printk(KERN_DEBUG "cyc:startup raising DTR\n");
+		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+			readb(base_addr + (CyMSVR1 << index)),
+			readb(base_addr + (CyMSVR2 << index)));
 #endif
 
 		cy_writeb(base_addr + (CySRER << index),
-			cy_readb(base_addr + (CySRER << index)) | CyRxData);
+			readb(base_addr + (CySRER << index)) | CyRxData);
 		info->flags |= ASYNC_INITIALIZED;
 
 		if (info->tty) {
@@ -2054,7 +1991,7 @@ #endif
 		info->idle_stats.recv_idle =
 		info->idle_stats.xmit_idle = jiffies;
 
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 
 	} else {
 		struct FIRM_ID __iomem *firm_id;
@@ -2063,24 +2000,23 @@ #endif
 		struct CH_CTRL __iomem *ch_ctrl;
 		int retval;
 
-		base_addr = cy_card[card].base_addr;
+		base_addr = card->base_addr;
 
 		firm_id = base_addr + ID_ADDRESS;
-		if (!ISZLOADED(cy_card[card])) {
+		if (!ISZLOADED(*card)) {
 			return -ENODEV;
 		}
 
-		zfw_ctrl = cy_card[card].base_addr +
-				(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		zfw_ctrl = card->base_addr +
+				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		board_ctrl = &zfw_ctrl->board_ctrl;
 		ch_ctrl = zfw_ctrl->ch_ctrl;
 
 #ifdef CY_DEBUG_OPEN
-		printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
-			card, channel, (long)base_addr);
-		/**/
+		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
+			"base_addr %p\n", card, channel, base_addr);
 #endif
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 
 		cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
 #ifdef Z_WAKE
@@ -2102,33 +2038,31 @@ #else
 #endif				/* CONFIG_CYZ_INTR */
 #endif				/* Z_WAKE */
 
-		retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
 		if (retval != 0) {
-			printk("cyc:startup(1) retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
+				"%x\n", info->line, retval);
 		}
 
 		/* Flush RX buffers before raising DTR and RTS */
-		retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
-				0L);
+		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
 		if (retval != 0) {
-			printk("cyc:startup(2) retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
+				"%x\n", info->line, retval);
 		}
 
 		/* set timeout !!! */
 		/* set RTS and DTR !!! */
 		cy_writel(&ch_ctrl[channel].rs_control,
-			cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
+			readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
 			C_RS_DTR);
-		retval = cyz_issue_cmd(&cy_card[info->card], channel,
-				C_CM_IOCTLM, 0L);
+		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
 		if (retval != 0) {
-			printk("cyc:startup(3) retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
+				"%x\n", info->line, retval);
 		}
 #ifdef CY_DEBUG_DTR
-		printk("cyc:startup raising Z DTR\n");
+		printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
 #endif
 
 		/* enable send, recv, modem !!! */
@@ -2144,51 +2078,50 @@ #endif
 		info->idle_stats.recv_idle =
 		info->idle_stats.xmit_idle = jiffies;
 
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 
 #ifdef CY_DEBUG_OPEN
-	printk(" cyc startup done\n");
+	printk(KERN_DEBUG "cyc startup done\n");
 #endif
 	return 0;
 
 errout:
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 	return retval;
 }				/* startup */
 
 static void start_xmit(struct cyclades_port *info)
 {
+	struct cyclades_card *card;
 	unsigned long flags;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr = cy_card[card].base_addr +
-				(cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 		cy_writeb(base_addr + (CyCAR << index), channel);
 		cy_writeb(base_addr + (CySRER << index),
-			cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
-		CY_UNLOCK(info, flags);
+			readb(base_addr + (CySRER << index)) | CyTxRdy);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	} else {
 #ifdef CONFIG_CYZ_INTR
 		int retval;
 
-		CY_LOCK(info, flags);
-		retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
-				0L);
+		spin_lock_irqsave(&card->card_lock, flags);
+		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
 		if (retval != 0) {
-			printk("cyc:start_xmit retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
+				"%x\n", info->line, retval);
 		}
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 #else				/* CONFIG_CYZ_INTR */
 		/* Don't have to do anything at this time */
 #endif				/* CONFIG_CYZ_INTR */
@@ -2201,30 +2134,30 @@ #endif				/* CONFIG_CYZ_INTR */
  */
 static void shutdown(struct cyclades_port *info)
 {
+	struct cyclades_card *card;
 	unsigned long flags;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 
 	if (!(info->flags & ASYNC_INITIALIZED)) {
 		return;
 	}
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr = cy_card[card].base_addr +
-				(cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
 #ifdef CY_DEBUG_OPEN
-		printk("cyc shutdown Y card %d, chip %d, channel %d, "
-				"base_addr %lx\n",
-				card, chip, channel, (long)base_addr);
+		printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
+				"channel %d, base_addr %p\n",
+				card, chip, channel, base_addr);
 #endif
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 
 		/* Clear delta_msr_wait queue to avoid mem leaks. */
 		wake_up_interruptible(&info->delta_msr_wait);
@@ -2240,10 +2173,10 @@ #endif
 			cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
 			cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
 #ifdef CY_DEBUG_DTR
-			printk("cyc shutdown dropping DTR\n");
-			printk("     status: 0x%x, 0x%x\n",
-				cy_readb(base_addr + (CyMSVR1 << index)),
-				cy_readb(base_addr + (CyMSVR2 << index)));
+			printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
+			printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+				readb(base_addr + (CyMSVR1 << index)),
+				readb(base_addr + (CyMSVR2 << index)));
 #endif
 		}
 		cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
@@ -2254,7 +2187,7 @@ #endif
 			set_bit(TTY_IO_ERROR, &info->tty->flags);
 		}
 		info->flags &= ~ASYNC_INITIALIZED;
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	} else {
 		struct FIRM_ID __iomem *firm_id;
 		struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -2262,23 +2195,23 @@ #endif
 		struct CH_CTRL __iomem *ch_ctrl;
 		int retval;
 
-		base_addr = cy_card[card].base_addr;
+		base_addr = card->base_addr;
 #ifdef CY_DEBUG_OPEN
-		printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
-			card, channel, (long)base_addr);
+		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
+			"base_addr %p\n", card, channel, base_addr);
 #endif
 
 		firm_id = base_addr + ID_ADDRESS;
-		if (!ISZLOADED(cy_card[card])) {
+		if (!ISZLOADED(*card)) {
 			return;
 		}
 
-		zfw_ctrl = cy_card[card].base_addr +
-				(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		zfw_ctrl = card->base_addr +
+				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		board_ctrl = &zfw_ctrl->board_ctrl;
 		ch_ctrl = zfw_ctrl->ch_ctrl;
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 
 		if (info->xmit_buf) {
 			unsigned char *temp;
@@ -2289,16 +2222,16 @@ #endif
 
 		if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 			cy_writel(&ch_ctrl[channel].rs_control,
-				(uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
+				(__u32)(readl(&ch_ctrl[channel].rs_control) &
 					~(C_RS_RTS | C_RS_DTR)));
-			retval = cyz_issue_cmd(&cy_card[info->card], channel,
+			retval = cyz_issue_cmd(info->card, channel,
 					C_CM_IOCTLM, 0L);
 			if (retval != 0) {
-				printk("cyc:shutdown retval on ttyC%d was %x\n",
-					info->line, retval);
+				printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
+					"was %x\n", info->line, retval);
 			}
 #ifdef CY_DEBUG_DTR
-			printk("cyc:shutdown dropping Z DTR\n");
+			printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
 #endif
 		}
 
@@ -2307,11 +2240,11 @@ #endif
 		}
 		info->flags &= ~ASYNC_INITIALIZED;
 
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 
 #ifdef CY_DEBUG_OPEN
-	printk(" cyc shutdown done\n");
+	printk(KERN_DEBUG "cyc shutdown done\n");
 #endif
 }				/* shutdown */
 
@@ -2332,7 +2265,7 @@ block_til_ready(struct tty_struct *tty, 
 	int retval;
 	void __iomem *base_addr;
 
-	cinfo = &cy_card[info->card];
+	cinfo = info->card;
 	channel = info->line - cinfo->first_line;
 
 	/*
@@ -2340,9 +2273,8 @@ block_til_ready(struct tty_struct *tty, 
 	 * until it's done, and then try again.
 	 */
 	if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING) {
-			interruptible_sleep_on(&info->close_wait);
-		}
+		wait_event_interruptible(info->close_wait,
+				!(info->flags & ASYNC_CLOSING));
 		return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
 
@@ -2365,17 +2297,16 @@ block_til_ready(struct tty_struct *tty, 
 	retval = 0;
 	add_wait_queue(&info->open_wait, &wait);
 #ifdef CY_DEBUG_OPEN
-	printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
-		info->line, info->count);
-	/**/
+	printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
+		"count = %d\n", info->line, info->count);
 #endif
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&cinfo->card_lock, flags);
 	if (!tty_hung_up_p(filp))
 		info->count--;
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&cinfo->card_lock, flags);
 #ifdef CY_DEBUG_COUNT
-	printk("cyc block_til_ready: (%d): decrementing count to %d\n",
-		current->pid, info->count);
+	printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
+		"%d\n", current->pid, info->count);
 #endif
 	info->blocked_open++;
 
@@ -2386,7 +2317,7 @@ #endif
 		base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
 		while (1) {
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&cinfo->card_lock, flags);
 			if ((tty->termios->c_cflag & CBAUD)) {
 				cy_writeb(base_addr + (CyCAR << index),
 					  (u_char) channel);
@@ -2395,15 +2326,14 @@ #endif
 				cy_writeb(base_addr + (CyMSVR2 << index),
 					  CyDTR);
 #ifdef CY_DEBUG_DTR
-				printk("cyc:block_til_ready raising DTR\n");
-				printk("     status: 0x%x, 0x%x\n",
-					cy_readb(base_addr +
-						(CyMSVR1 << index)),
-					cy_readb(base_addr +
-						(CyMSVR2 << index)));
+				printk(KERN_DEBUG "cyc:block_til_ready raising "
+					"DTR\n");
+				printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+					readb(base_addr + (CyMSVR1 << index)),
+					readb(base_addr + (CyMSVR2 << index)));
 #endif
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&cinfo->card_lock, flags);
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			if (tty_hung_up_p(filp) ||
@@ -2413,26 +2343,25 @@ #endif
 				break;
 			}
 
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&cinfo->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
-					(cy_readb(base_addr +
+					(readb(base_addr +
 						(CyMSVR1 << index)) & CyDCD))) {
-				CY_UNLOCK(info, flags);
+				spin_unlock_irqrestore(&cinfo->card_lock, flags);
 				break;
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&cinfo->card_lock, flags);
 
 			if (signal_pending(current)) {
 				retval = -ERESTARTSYS;
 				break;
 			}
 #ifdef CY_DEBUG_OPEN
-			printk("cyc block_til_ready blocking: ttyC%d, "
-					"count = %d\n",
-					info->line, info->count);
-			/**/
+			printk(KERN_DEBUG "cyc block_til_ready blocking: "
+				"ttyC%d, count = %d\n",
+				info->line, info->count);
 #endif
 			schedule();
 		}
@@ -2446,31 +2375,30 @@ #endif
 		base_addr = cinfo->base_addr;
 		firm_id = base_addr + ID_ADDRESS;
 		if (!ISZLOADED(*cinfo)) {
-			current->state = TASK_RUNNING;
+			__set_current_state(TASK_RUNNING);
 			remove_wait_queue(&info->open_wait, &wait);
 			return -EINVAL;
 		}
 
-		zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
-				0xfffff);
+		zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
 		board_ctrl = &zfw_ctrl->board_ctrl;
 		ch_ctrl = zfw_ctrl->ch_ctrl;
 
 		while (1) {
 			if ((tty->termios->c_cflag & CBAUD)) {
 				cy_writel(&ch_ctrl[channel].rs_control,
-					  cy_readl(&ch_ctrl[channel].
-						   rs_control) | (C_RS_RTS |
-								  C_RS_DTR));
-				retval = cyz_issue_cmd(&cy_card[info->card],
-						channel, C_CM_IOCTLM, 0L);
+					readl(&ch_ctrl[channel].rs_control) |
+					C_RS_RTS | C_RS_DTR);
+				retval = cyz_issue_cmd(cinfo,
+					channel, C_CM_IOCTLM, 0L);
 				if (retval != 0) {
-					printk("cyc:block_til_ready retval on "
-						"ttyC%d was %x\n",
+					printk(KERN_ERR "cyc:block_til_ready "
+						"retval on ttyC%d was %x\n",
 						info->line, retval);
 				}
 #ifdef CY_DEBUG_DTR
-				printk("cyc:block_til_ready raising Z DTR\n");
+				printk(KERN_DEBUG "cyc:block_til_ready raising "
+					"Z DTR\n");
 #endif
 			}
 
@@ -2482,7 +2410,7 @@ #endif
 				break;
 			}
 			if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
-					(cy_readl(&ch_ctrl[channel].rs_status) &
+					(readl(&ch_ctrl[channel].rs_status) &
 						C_RS_DCD))) {
 				break;
 			}
@@ -2491,28 +2419,26 @@ #endif
 				break;
 			}
 #ifdef CY_DEBUG_OPEN
-			printk("cyc block_til_ready blocking: ttyC%d, "
-					"count = %d\n",
-					info->line, info->count);
-			/**/
+			printk(KERN_DEBUG "cyc block_til_ready blocking: "
+				"ttyC%d, count = %d\n",
+				info->line, info->count);
 #endif
 			schedule();
 		}
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	if (!tty_hung_up_p(filp)) {
 		info->count++;
 #ifdef CY_DEBUG_COUNT
-		printk("cyc:block_til_ready (%d): incrementing count to %d\n",
-			current->pid, info->count);
+		printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
+			"count to %d\n", current->pid, info->count);
 #endif
 	}
 	info->blocked_open--;
 #ifdef CY_DEBUG_OPEN
-	printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
-		info->line, info->count);
-	/**/
+	printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
+		"count = %d\n", info->line, info->count);
 #endif
 	if (retval)
 		return retval;
@@ -2527,13 +2453,20 @@ #endif
 static int cy_open(struct tty_struct *tty, struct file *filp)
 {
 	struct cyclades_port *info;
+	unsigned int i;
 	int retval, line;
 
 	line = tty->index;
 	if ((line < 0) || (NR_PORTS <= line)) {
 		return -ENODEV;
 	}
-	info = &cy_port[line];
+	for (i = 0; i < NR_CARDS; i++)
+		if (line < cy_card[i].first_line + cy_card[i].nports &&
+				line >= cy_card[i].first_line)
+			break;
+	if (i >= NR_CARDS)
+		return -ENODEV;
+	info = &cy_card[i].ports[line - cy_card[i].first_line];
 	if (info->line < 0) {
 		return -ENODEV;
 	}
@@ -2542,23 +2475,23 @@ static int cy_open(struct tty_struct *tt
 	   treat it as absent from the system.  This
 	   will make the user pay attention.
 	 */
-	if (IS_CYC_Z(cy_card[info->card])) {
-		struct cyclades_card *cinfo = &cy_card[info->card];
+	if (IS_CYC_Z(*info->card)) {
+		struct cyclades_card *cinfo = info->card;
 		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
 
 		if (!ISZLOADED(*cinfo)) {
-			if (((ZE_V1 == cy_readl(
-					&((struct RUNTIME_9060 __iomem *)
+			if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
 					 (cinfo->ctl_addr))->mail_box_0)) &&
 					Z_FPGA_CHECK(*cinfo)) &&
-					(ZFIRM_HLT == cy_readl(
+					(ZFIRM_HLT == readl(
 						&firm_id->signature))) {
-				printk("cyc:Cyclades-Z Error: you need an "
-					"external power supply for this number "
-					"of ports.\n\rFirmware halted.\r\n");
+				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
+					"need an external power supply for "
+					"this number of ports.\nFirmware "
+					"halted.\n");
 			} else {
-				printk("cyc:Cyclades-Z firmware not yet "
-					"loaded\n");
+				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
+					"yet loaded\n");
 			}
 			return -ENODEV;
 		}
@@ -2572,24 +2505,23 @@ #ifdef CONFIG_CYZ_INTR
 				struct BOARD_CTRL __iomem *board_ctrl;
 
 				zfw_ctrl = cinfo->base_addr +
-					(cy_readl(&firm_id->zfwctrl_addr) &
-						0xfffff);
+					(readl(&firm_id->zfwctrl_addr) &
+					 0xfffff);
 
 				board_ctrl = &zfw_ctrl->board_ctrl;
 
 				/* Enable interrupts on the PLX chip */
 				cy_writew(cinfo->ctl_addr + 0x68,
-					  cy_readw(cinfo->ctl_addr +
-						   0x68) | 0x0900);
+					readw(cinfo->ctl_addr + 0x68) | 0x0900);
 				/* Enable interrupts on the FW */
 				retval = cyz_issue_cmd(cinfo, 0,
 						C_CM_IRQ_ENBL, 0L);
 				if (retval != 0) {
-					printk("cyc:IRQ enable retval was %x\n",
-						retval);
+					printk(KERN_ERR "cyc:IRQ enable retval "
+						"was %x\n", retval);
 				}
 				cinfo->nports =
-					(int)cy_readl(&board_ctrl->n_channel);
+					(int)readl(&board_ctrl->n_channel);
 				cinfo->intr_enabled = 1;
 			}
 		}
@@ -2599,7 +2531,7 @@ #endif				/* CONFIG_CYZ_INTR */
 			return -ENODEV;
 	}
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_open ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
 #endif
 	tty->driver_data = info;
 	info->tty = tty;
@@ -2607,12 +2539,12 @@ #endif
 		return -ENODEV;
 	}
 #ifdef CY_DEBUG_OPEN
-	printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
-	/**/
+	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
+			info->count);
 #endif
 	info->count++;
 #ifdef CY_DEBUG_COUNT
-	printk("cyc:cy_open (%d): incrementing count to %d\n",
+	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
 		current->pid, info->count);
 #endif
 
@@ -2620,8 +2552,8 @@ #endif
 	 * If the port is the middle of closing, bail out now
 	 */
 	if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
-		if (info->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&info->close_wait);
+		wait_event_interruptible(info->close_wait,
+				!(info->flags & ASYNC_CLOSING));
 		return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
 	}
 
@@ -2636,8 +2568,8 @@ #endif
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
 #ifdef CY_DEBUG_OPEN
-		printk("cyc:cy_open returning after block_til_ready with %d\n",
-			retval);
+		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
+			"with %d\n", retval);
 #endif
 		return retval;
 	}
@@ -2645,8 +2577,7 @@ #endif
 	info->throttle = 0;
 
 #ifdef CY_DEBUG_OPEN
-	printk(" cyc:cy_open done\n");
-	/**/
+	printk(KERN_DEBUG "cyc:cy_open done\n");
 #endif
 	return 0;
 }				/* cy_open */
@@ -2656,9 +2587,10 @@ #endif
  */
 static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_card *card;
+	struct cyclades_port *info = tty->driver_data;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 	unsigned long orig_jiffies;
 	int char_time;
 
@@ -2697,20 +2629,19 @@ static void cy_wait_until_sent(struct tt
 	if (!timeout || timeout > 2 * info->timeout)
 		timeout = 2 * info->timeout;
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
-	printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
-	printk("jiff=%lu...", jiffies);
+	printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
+		timeout, char_time, jiffies);
 #endif
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = (info->line) - (card->first_line);
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
-		while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+		while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
-			printk("Not clean (jiff=%lu)...", jiffies);
+			printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
 #endif
 			if (msleep_interruptible(jiffies_to_msecs(char_time)))
 				break;
@@ -2718,13 +2649,11 @@ #endif
 					timeout))
 				break;
 		}
-	} else {
-		/* Nothing to do! */
 	}
 	/* Run one more char cycle */
 	msleep_interruptible(jiffies_to_msecs(char_time * 5));
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
-	printk("Clean (jiff=%lu)...done\n", jiffies);
+	printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
 #endif
 }
 
@@ -2733,25 +2662,29 @@ #endif
  */
 static void cy_close(struct tty_struct *tty, struct file *filp)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
 	unsigned long flags;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_close ttyC%d\n", info->line);
+	printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
 #endif
 
 	if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
 		return;
 	}
 
-	CY_LOCK(info, flags);
+	card = info->card;
+
+	spin_lock_irqsave(&card->card_lock, flags);
 	/* If the TTY is being hung up, nothing to do */
 	if (tty_hung_up_p(filp)) {
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 		return;
 	}
 #ifdef CY_DEBUG_OPEN
-	printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+	printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
+		info->count);
 #endif
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
@@ -2761,22 +2694,22 @@ #endif
 		 * one, we've got real problems, since it means the
 		 * serial port won't be shutdown.
 		 */
-		printk("cyc:cy_close: bad serial port count; tty->count is 1, "
-			"info->count is %d\n", info->count);
+		printk(KERN_ERR "cyc:cy_close: bad serial port count; "
+			"tty->count is 1, info->count is %d\n", info->count);
 		info->count = 1;
 	}
 #ifdef CY_DEBUG_COUNT
-	printk("cyc:cy_close at (%d): decrementing count to %d\n",
+	printk(KERN_DEBUG  "cyc:cy_close at (%d): decrementing count to %d\n",
 		current->pid, info->count - 1);
 #endif
 	if (--info->count < 0) {
 #ifdef CY_DEBUG_COUNT
-		printk("cyc:cyc_close setting count to 0\n");
+		printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
 #endif
 		info->count = 0;
 	}
 	if (info->count) {
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 		return;
 	}
 	info->flags |= ASYNC_CLOSING;
@@ -2786,81 +2719,80 @@ #endif
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 	if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
 		tty_wait_until_sent(tty, info->closing_wait);
 	}
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&card->card_lock, flags);
 
-	if (!IS_CYC_Z(cy_card[info->card])) {
-		int channel = info->line - cy_card[info->card].first_line;
-		int index = cy_card[info->card].bus_index;
-		void __iomem *base_addr = cy_card[info->card].base_addr +
+	if (!IS_CYC_Z(*card)) {
+		int channel = info->line - card->first_line;
+		int index = card->bus_index;
+		void __iomem *base_addr = card->base_addr +
 			(cy_chip_offset[channel >> 2] << index);
 		/* Stop accepting input */
 		channel &= 0x03;
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 		cy_writeb(base_addr + (CySRER << index),
-			  cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
+			  readb(base_addr + (CySRER << index)) & ~CyRxData);
 		if (info->flags & ASYNC_INITIALIZED) {
 			/* Waiting for on-board buffers to be empty before closing
 			   the port */
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 			cy_wait_until_sent(tty, info->timeout);
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 		}
 	} else {
 #ifdef Z_WAKE
 		/* Waiting for on-board buffers to be empty before closing the port */
-		void __iomem *base_addr = cy_card[info->card].base_addr;
+		void __iomem *base_addr = card->base_addr;
 		struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
 		struct ZFW_CTRL __iomem *zfw_ctrl =
-		    base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		    base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
-		int channel = info->line - cy_card[info->card].first_line;
+		int channel = info->line - card->first_line;
 		int retval;
 
-		if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
-			retval = cyz_issue_cmd(&cy_card[info->card], channel,
-						C_CM_IOCTLW, 0L);
+		if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
 			if (retval != 0) {
-				printk("cyc:cy_close retval on ttyC%d was %x\n",
-					info->line, retval);
+				printk(KERN_DEBUG "cyc:cy_close retval on "
+					"ttyC%d was %x\n", info->line, retval);
 			}
-			CY_UNLOCK(info, flags);
-			interruptible_sleep_on(&info->shutdown_wait);
-			CY_LOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
+			wait_for_completion_interruptible(&info->shutdown_wait);
+			spin_lock_irqsave(&card->card_lock, flags);
 		}
 #endif
 	}
 
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 	shutdown(info);
 	if (tty->driver->flush_buffer)
 		tty->driver->flush_buffer(tty);
 	tty_ldisc_flush(tty);
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&card->card_lock, flags);
 
 	tty->closing = 0;
 	info->event = 0;
 	info->tty = NULL;
 	if (info->blocked_open) {
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 		if (info->close_delay) {
 			msleep_interruptible(jiffies_to_msecs
 						(info->close_delay));
 		}
 		wake_up_interruptible(&info->open_wait);
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 	}
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 
 #ifdef CY_DEBUG_OTHER
-	printk(" cyc:cy_close done\n");
+	printk(KERN_DEBUG "cyc:cy_close done\n");
 #endif
 
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 }				/* cy_close */
 
 /* This routine gets called when tty_write has put something into
@@ -2878,12 +2810,12 @@ #endif
  */
 static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	unsigned long flags;
 	int c, ret = 0;
 
 #ifdef CY_DEBUG_IO
-	printk("cyc:cy_write ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_write")) {
@@ -2893,7 +2825,7 @@ #endif
 	if (!info->xmit_buf)
 		return 0;
 
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&info->card->card_lock, flags);
 	while (1) {
 		c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
 				   (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
@@ -2909,7 +2841,7 @@ #endif
 		count -= c;
 		ret += c;
 	}
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&info->card->card_lock, flags);
 
 	info->idle_stats.xmit_bytes += ret;
 	info->idle_stats.xmit_idle = jiffies;
@@ -2929,11 +2861,11 @@ #endif
  */
 static void cy_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	unsigned long flags;
 
 #ifdef CY_DEBUG_IO
-	printk("cyc:cy_put_char ttyC%d\n", info->line);
+	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
@@ -2942,9 +2874,9 @@ #endif
 	if (!info->xmit_buf)
 		return;
 
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&info->card->card_lock, flags);
 	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&info->card->card_lock, flags);
 		return;
 	}
 
@@ -2953,7 +2885,7 @@ #endif
 	info->xmit_cnt++;
 	info->idle_stats.xmit_bytes++;
 	info->idle_stats.xmit_idle = jiffies;
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&info->card->card_lock, flags);
 }				/* cy_put_char */
 
 /*
@@ -2962,10 +2894,10 @@ #endif
  */
 static void cy_flush_chars(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 
 #ifdef CY_DEBUG_IO
-	printk("cyc:cy_flush_chars ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
@@ -2986,11 +2918,11 @@ #endif
  */
 static int cy_write_room(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	int ret;
 
 #ifdef CY_DEBUG_IO
-	printk("cyc:cy_write_room ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
@@ -3003,46 +2935,49 @@ #endif
 
 static int cy_chars_in_buffer(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-	int card, channel;
+	struct cyclades_card *card;
+	struct cyclades_port *info = tty->driver_data;
+	int channel;
 
 	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
 		return 0;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
+	channel = (info->line) - (card->first_line);
 
 #ifdef Z_EXT_CHARS_IN_BUFFER
 	if (!IS_CYC_Z(cy_card[card])) {
 #endif				/* Z_EXT_CHARS_IN_BUFFER */
 #ifdef CY_DEBUG_IO
-		printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt);	/* */
+		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+			info->line, info->xmit_cnt);
 #endif
 		return info->xmit_cnt;
 #ifdef Z_EXT_CHARS_IN_BUFFER
 	} else {
-		static volatile struct FIRM_ID *firm_id;
-		static volatile struct ZFW_CTRL *zfw_ctrl;
-		static volatile struct CH_CTRL *ch_ctrl;
-		static volatile struct BUF_CTRL *buf_ctrl;
+		static struct FIRM_ID *firm_id;
+		static struct ZFW_CTRL *zfw_ctrl;
+		static struct CH_CTRL *ch_ctrl;
+		static struct BUF_CTRL *buf_ctrl;
 		int char_count;
-		volatile uclong tx_put, tx_get, tx_bufsize;
+		__u32 tx_put, tx_get, tx_bufsize;
 
-		firm_id = cy_card[card].base_addr + ID_ADDRESS;
-		zfw_ctrl = cy_card[card].base_addr +
-			(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		firm_id = card->base_addr + ID_ADDRESS;
+		zfw_ctrl = card->base_addr +
+			(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
 		buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
 
-		tx_get = cy_readl(&buf_ctrl->tx_get);
-		tx_put = cy_readl(&buf_ctrl->tx_put);
-		tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+		tx_get = readl(&buf_ctrl->tx_get);
+		tx_put = readl(&buf_ctrl->tx_put);
+		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
 		if (tx_put >= tx_get)
 			char_count = tx_put - tx_get;
 		else
 			char_count = tx_put - tx_get + tx_bufsize;
 #ifdef CY_DEBUG_IO
-		printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count);	/* */
+		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+			info->line, info->xmit_cnt + char_count);
 #endif
 		return info->xmit_cnt + char_count;
 	}
@@ -3055,10 +2990,10 @@ #endif				/* Z_EXT_CHARS_IN_BUFFER */
  * ------------------------------------------------------------
  */
 
-static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
+static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
 {
 	int co, co_val, bpr;
-	uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
+	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
 			25000000);
 
 	if (baud == 0) {
@@ -3086,9 +3021,10 @@ static void cyy_baud_calc(struct cyclade
  */
 static void set_line_char(struct cyclades_port *info)
 {
+	struct cyclades_card *card;
 	unsigned long flags;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 	unsigned cflag, iflag;
 	unsigned short chip_number;
 	int baud, baud_rate = 0;
@@ -3118,12 +3054,12 @@ static void set_line_char(struct cyclade
 	}
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
+	channel = info->line - card->first_line;
 	chip_number = channel / 4;
 
-	if (!IS_CYC_Z(cy_card[card])) {
+	if (!IS_CYC_Z(*card)) {
 
-		index = cy_card[card].bus_index;
+		index = card->bus_index;
 
 		/* baud rate */
 		baud = tty_get_baud_rate(info->tty);
@@ -3241,10 +3177,9 @@ static void set_line_char(struct cyclade
 
 		chip = channel >> 2;
 		channel &= 0x03;
-		base_addr = cy_card[card].base_addr +
-			(cy_chip_offset[chip] << index);
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
 
 		/* tx and rx baud rate */
@@ -3276,8 +3211,7 @@ static void set_line_char(struct cyclade
 		if (C_CLOCAL(info->tty)) {
 			/* without modem intr */
 			cy_writeb(base_addr + (CySRER << index),
-				  cy_readb(base_addr +
-					   (CySRER << index)) | CyMdmCh);
+				readb(base_addr + (CySRER << index)) | CyMdmCh);
 			/* act on 1->0 modem transitions */
 			if ((cflag & CRTSCTS) && info->rflow) {
 				cy_writeb(base_addr + (CyMCOR1 << index),
@@ -3291,7 +3225,7 @@ static void set_line_char(struct cyclade
 		} else {
 			/* without modem intr */
 			cy_writeb(base_addr + (CySRER << index),
-				  cy_readb(base_addr +
+				  readb(base_addr +
 					   (CySRER << index)) | CyMdmCh);
 			/* act on 1->0 modem transitions */
 			if ((cflag & CRTSCTS) && info->rflow) {
@@ -3316,10 +3250,10 @@ static void set_line_char(struct cyclade
 					  ~CyDTR);
 			}
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_line_char dropping DTR\n");
-			printk("     status: 0x%x, 0x%x\n",
-				cy_readb(base_addr + (CyMSVR1 << index)),
-				cy_readb(base_addr + (CyMSVR2 << index)));
+			printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
+			printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+				readb(base_addr + (CyMSVR1 << index)),
+				readb(base_addr + (CyMSVR2 << index)));
 #endif
 		} else {
 			if (info->rtsdtr_inv) {
@@ -3330,17 +3264,17 @@ #endif
 					  CyDTR);
 			}
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_line_char raising DTR\n");
-			printk("     status: 0x%x, 0x%x\n",
-				cy_readb(base_addr + (CyMSVR1 << index)),
-				cy_readb(base_addr + (CyMSVR2 << index)));
+			printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
+			printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+				readb(base_addr + (CyMSVR1 << index)),
+				readb(base_addr + (CyMSVR2 << index)));
 #endif
 		}
 
 		if (info->tty) {
 			clear_bit(TTY_IO_ERROR, &info->tty->flags);
 		}
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 
 	} else {
 		struct FIRM_ID __iomem *firm_id;
@@ -3348,16 +3282,16 @@ #endif
 		struct BOARD_CTRL __iomem *board_ctrl;
 		struct CH_CTRL __iomem *ch_ctrl;
 		struct BUF_CTRL __iomem *buf_ctrl;
-		uclong sw_flow;
+		__u32 sw_flow;
 		int retval;
 
-		firm_id = cy_card[card].base_addr + ID_ADDRESS;
-		if (!ISZLOADED(cy_card[card])) {
+		firm_id = card->base_addr + ID_ADDRESS;
+		if (!ISZLOADED(*card)) {
 			return;
 		}
 
-		zfw_ctrl = cy_card[card].base_addr +
-			(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		zfw_ctrl = card->base_addr +
+			(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 		board_ctrl = &zfw_ctrl->board_ctrl;
 		ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
 		buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
@@ -3408,10 +3342,10 @@ #endif
 		}
 		if (cflag & CSTOPB) {
 			cy_writel(&ch_ctrl->comm_data_l,
-				  cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
 		} else {
 			cy_writel(&ch_ctrl->comm_data_l,
-				  cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
 		}
 		if (cflag & PARENB) {
 			if (cflag & PARODD) {
@@ -3426,12 +3360,10 @@ #endif
 		/* CTS flow control flag */
 		if (cflag & CRTSCTS) {
 			cy_writel(&ch_ctrl->hw_flow,
-				  cy_readl(&ch_ctrl->
-					   hw_flow) | C_RS_CTS | C_RS_RTS);
+				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
 		} else {
-			cy_writel(&ch_ctrl->hw_flow,
-				  cy_readl(&ch_ctrl->
-					   hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
+					~(C_RS_CTS | C_RS_RTS));
 		}
 		/* As the HW flow control is done in firmware, the driver
 		   doesn't need to care about it */
@@ -3446,10 +3378,10 @@ #endif
 		}
 		cy_writel(&ch_ctrl->sw_flow, sw_flow);
 
-		retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
 		if (retval != 0) {
-			printk("cyc:set_line_char retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
+				"was %x\n", info->line, retval);
 		}
 
 		/* CD sensitivity */
@@ -3461,22 +3393,22 @@ #endif
 
 		if (baud == 0) {	/* baud rate is zero, turn off line */
 			cy_writel(&ch_ctrl->rs_control,
-				  cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_line_char dropping Z DTR\n");
+			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
 #endif
 		} else {
 			cy_writel(&ch_ctrl->rs_control,
-				  cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_line_char raising Z DTR\n");
+			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
 #endif
 		}
 
-		retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
+		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
 		if (retval != 0) {
-			printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
+				"was %x\n", info->line, retval);
 		}
 
 		if (info->tty) {
@@ -3490,14 +3422,15 @@ get_serial_info(struct cyclades_port *in
 		struct serial_struct __user * retinfo)
 {
 	struct serial_struct tmp;
-	struct cyclades_card *cinfo = &cy_card[info->card];
+	struct cyclades_card *cinfo = info->card;
 
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = info->type;
 	tmp.line = info->line;
-	tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
+	tmp.port = (info->card - cy_card) * 0x100 + info->line -
+		cinfo->first_line;
 	tmp.irq = cinfo->irq;
 	tmp.flags = info->flags;
 	tmp.close_delay = info->close_delay;
@@ -3566,25 +3499,25 @@ check_and_exit:
  */
 static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
 {
-	int card, chip, channel, index;
+	struct cyclades_card *card;
+	int chip, channel, index;
 	unsigned char status;
 	unsigned int result;
 	unsigned long flags;
 	void __iomem *base_addr;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = (info->line) - (card->first_line);
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
-		status = cy_readb(base_addr + (CySRER << index)) &
+		spin_lock_irqsave(&card->card_lock, flags);
+		status = readb(base_addr + (CySRER << index)) &
 				(CyTxRdy | CyTxMpty);
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 		result = (status ? 0 : TIOCSER_TEMT);
 	} else {
 		/* Not supported yet */
@@ -3595,8 +3528,9 @@ static int get_lsr_info(struct cyclades_
 
 static int cy_tiocmget(struct tty_struct *tty, struct file *file)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-	int card, chip, channel, index;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
+	int chip, channel, index;
 	void __iomem *base_addr;
 	unsigned long flags;
 	unsigned char status;
@@ -3611,19 +3545,18 @@ static int cy_tiocmget(struct tty_struct
 		return -ENODEV;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
-		status = cy_readb(base_addr + (CyMSVR1 << index));
-		status |= cy_readb(base_addr + (CyMSVR2 << index));
-		CY_UNLOCK(info, flags);
+		status = readb(base_addr + (CyMSVR1 << index));
+		status |= readb(base_addr + (CyMSVR2 << index));
+		spin_unlock_irqrestore(&card->card_lock, flags);
 
 		if (info->rtsdtr_inv) {
 			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
@@ -3637,19 +3570,14 @@ static int cy_tiocmget(struct tty_struct
 			((status & CyDSR) ? TIOCM_DSR : 0) |
 			((status & CyCTS) ? TIOCM_CTS : 0);
 	} else {
-		base_addr = cy_card[card].base_addr;
-
-		if (cy_card[card].num_chips != -1) {
-			return -EINVAL;
-		}
-
-		firm_id = cy_card[card].base_addr + ID_ADDRESS;
-		if (ISZLOADED(cy_card[card])) {
-			zfw_ctrl = cy_card[card].base_addr +
-				(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		base_addr = card->base_addr;
+		firm_id = card->base_addr + ID_ADDRESS;
+		if (ISZLOADED(*card)) {
+			zfw_ctrl = card->base_addr +
+				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 			board_ctrl = &zfw_ctrl->board_ctrl;
 			ch_ctrl = zfw_ctrl->ch_ctrl;
-			lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+			lstatus = readl(&ch_ctrl[channel].rs_status);
 			result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
 				((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
 				((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
@@ -3669,8 +3597,9 @@ static int
 cy_tiocmset(struct tty_struct *tty, struct file *file,
 		unsigned int set, unsigned int clear)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-	int card, chip, channel, index;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
+	int chip, channel, index;
 	void __iomem *base_addr;
 	unsigned long flags;
 	struct FIRM_ID __iomem *firm_id;
@@ -3683,16 +3612,15 @@ cy_tiocmset(struct tty_struct *tty, stru
 		return -ENODEV;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = (info->line) - (card->first_line);
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
 		if (set & TIOCM_RTS) {
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -3702,10 +3630,10 @@ cy_tiocmset(struct tty_struct *tty, stru
 				cy_writeb(base_addr + (CyMSVR1 << index),
 					  CyRTS);
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		}
 		if (clear & TIOCM_RTS) {
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -3715,10 +3643,10 @@ cy_tiocmset(struct tty_struct *tty, stru
 				cy_writeb(base_addr + (CyMSVR1 << index),
 					  ~CyRTS);
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		}
 		if (set & TIOCM_DTR) {
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -3729,15 +3657,15 @@ cy_tiocmset(struct tty_struct *tty, stru
 					  CyDTR);
 			}
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_modem_info raising DTR\n");
-			printk("     status: 0x%x, 0x%x\n",
-				cy_readb(base_addr + (CyMSVR1 << index)),
-				cy_readb(base_addr + (CyMSVR2 << index)));
+			printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
+			printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+				readb(base_addr + (CyMSVR1 << index)),
+				readb(base_addr + (CyMSVR2 << index)));
 #endif
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		}
 		if (clear & TIOCM_DTR) {
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -3749,68 +3677,69 @@ #endif
 			}
 
 #ifdef CY_DEBUG_DTR
-			printk("cyc:set_modem_info dropping DTR\n");
-			printk("     status: 0x%x, 0x%x\n",
-				cy_readb(base_addr + (CyMSVR1 << index)),
-				cy_readb(base_addr + (CyMSVR2 << index)));
+			printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
+			printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
+				readb(base_addr + (CyMSVR1 << index)),
+				readb(base_addr + (CyMSVR2 << index)));
 #endif
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		}
 	} else {
-		base_addr = cy_card[card].base_addr;
+		base_addr = card->base_addr;
 
-		firm_id = cy_card[card].base_addr + ID_ADDRESS;
-		if (ISZLOADED(cy_card[card])) {
-			zfw_ctrl = cy_card[card].base_addr +
-				(cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+		firm_id = card->base_addr + ID_ADDRESS;
+		if (ISZLOADED(*card)) {
+			zfw_ctrl = card->base_addr +
+				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
 			board_ctrl = &zfw_ctrl->board_ctrl;
 			ch_ctrl = zfw_ctrl->ch_ctrl;
 
 			if (set & TIOCM_RTS) {
-				CY_LOCK(info, flags);
+				spin_lock_irqsave(&card->card_lock, flags);
 				cy_writel(&ch_ctrl[channel].rs_control,
-					  cy_readl(&ch_ctrl[channel].
-						   rs_control) | C_RS_RTS);
-				CY_UNLOCK(info, flags);
+					readl(&ch_ctrl[channel].rs_control) |
+					C_RS_RTS);
+				spin_unlock_irqrestore(&card->card_lock, flags);
 			}
 			if (clear & TIOCM_RTS) {
-				CY_LOCK(info, flags);
+				spin_lock_irqsave(&card->card_lock, flags);
 				cy_writel(&ch_ctrl[channel].rs_control,
-					  cy_readl(&ch_ctrl[channel].
-						   rs_control) & ~C_RS_RTS);
-				CY_UNLOCK(info, flags);
+					readl(&ch_ctrl[channel].rs_control) &
+					~C_RS_RTS);
+				spin_unlock_irqrestore(&card->card_lock, flags);
 			}
 			if (set & TIOCM_DTR) {
-				CY_LOCK(info, flags);
+				spin_lock_irqsave(&card->card_lock, flags);
 				cy_writel(&ch_ctrl[channel].rs_control,
-					  cy_readl(&ch_ctrl[channel].
-						   rs_control) | C_RS_DTR);
+					readl(&ch_ctrl[channel].rs_control) |
+					C_RS_DTR);
 #ifdef CY_DEBUG_DTR
-				printk("cyc:set_modem_info raising Z DTR\n");
+				printk(KERN_DEBUG "cyc:set_modem_info raising "
+					"Z DTR\n");
 #endif
-				CY_UNLOCK(info, flags);
+				spin_unlock_irqrestore(&card->card_lock, flags);
 			}
 			if (clear & TIOCM_DTR) {
-				CY_LOCK(info, flags);
+				spin_lock_irqsave(&card->card_lock, flags);
 				cy_writel(&ch_ctrl[channel].rs_control,
-					  cy_readl(&ch_ctrl[channel].
-						   rs_control) & ~C_RS_DTR);
+					readl(&ch_ctrl[channel].rs_control) &
+					~C_RS_DTR);
 #ifdef CY_DEBUG_DTR
-				printk("cyc:set_modem_info clearing Z DTR\n");
+				printk(KERN_DEBUG "cyc:set_modem_info clearing "
+					"Z DTR\n");
 #endif
-				CY_UNLOCK(info, flags);
+				spin_unlock_irqrestore(&card->card_lock, flags);
 			}
 		} else {
 			return -ENODEV;
 		}
-		CY_LOCK(info, flags);
-		retval = cyz_issue_cmd(&cy_card[info->card],
-					channel, C_CM_IOCTLM, 0L);
+		spin_lock_irqsave(&card->card_lock, flags);
+		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
 		if (retval != 0) {
-			printk("cyc:set_modem_info retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
+				"was %x\n", info->line, retval);
 		}
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 	return 0;
 }				/* cy_tiocmset */
@@ -3820,14 +3749,17 @@ #endif
  */
 static void cy_break(struct tty_struct *tty, int break_state)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->name, "cy_break"))
 		return;
 
-	CY_LOCK(info, flags);
-	if (!IS_CYC_Z(cy_card[info->card])) {
+	card = info->card;
+
+	spin_lock_irqsave(&card->card_lock, flags);
+	if (!IS_CYC_Z(*card)) {
 		/* Let the transmit ISR take care of this (since it
 		   requires stuffing characters into the output stream).
 		 */
@@ -3835,18 +3767,18 @@ static void cy_break(struct tty_struct *
 			if (!info->breakon) {
 				info->breakon = 1;
 				if (!info->xmit_cnt) {
-					CY_UNLOCK(info, flags);
+					spin_unlock_irqrestore(&card->card_lock, flags);
 					start_xmit(info);
-					CY_LOCK(info, flags);
+					spin_lock_irqsave(&card->card_lock, flags);
 				}
 			}
 		} else {
 			if (!info->breakoff) {
 				info->breakoff = 1;
 				if (!info->xmit_cnt) {
-					CY_UNLOCK(info, flags);
+					spin_unlock_irqrestore(&card->card_lock, flags);
 					start_xmit(info);
-					CY_LOCK(info, flags);
+					spin_lock_irqsave(&card->card_lock, flags);
 				}
 			}
 		}
@@ -3854,24 +3786,25 @@ static void cy_break(struct tty_struct *
 		int retval;
 
 		if (break_state == -1) {
-			retval = cyz_issue_cmd(&cy_card[info->card],
-				info->line - cy_card[info->card].first_line,
+			retval = cyz_issue_cmd(card,
+				info->line - card->first_line,
 				C_CM_SET_BREAK, 0L);
 			if (retval != 0) {
-				printk("cyc:cy_break (set) retval on ttyC%d "
-					"was %x\n", info->line, retval);
+				printk(KERN_ERR "cyc:cy_break (set) retval on "
+					"ttyC%d was %x\n", info->line, retval);
 			}
 		} else {
-			retval = cyz_issue_cmd(&cy_card[info->card],
-				info->line - cy_card[info->card].first_line,
+			retval = cyz_issue_cmd(card,
+				info->line - card->first_line,
 				C_CM_CLR_BREAK, 0L);
 			if (retval != 0) {
-				printk("cyc:cy_break (clr) retval on ttyC%d "
-					"was %x\n", info->line, retval);
+				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
+					"on ttyC%d was %x\n", info->line,
+					retval);
 			}
 		}
 	}
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 }				/* cy_break */
 
 static int
@@ -3889,28 +3822,27 @@ get_mon_info(struct cyclades_port *info,
 
 static int set_threshold(struct cyclades_port *info, unsigned long value)
 {
+	struct cyclades_card *card;
 	void __iomem *base_addr;
-	int card, channel, chip, index;
+	int channel, chip, index;
 	unsigned long flags;
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
+		index = card->bus_index;
 		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		    card->base_addr + (cy_chip_offset[chip] << index);
 
 		info->cor3 &= ~CyREC_FIFO;
 		info->cor3 |= value & CyREC_FIFO;
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 		cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
 		cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
-		CY_UNLOCK(info, flags);
-	} else {
-		/* Nothing to do! */
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 	return 0;
 }				/* set_threshold */
@@ -3918,25 +3850,23 @@ static int set_threshold(struct cyclades
 static int
 get_threshold(struct cyclades_port *info, unsigned long __user * value)
 {
+	struct cyclades_card *card;
 	void __iomem *base_addr;
-	int card, channel, chip, index;
+	int channel, chip, index;
 	unsigned long tmp;
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+		tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
 		return put_user(tmp, value);
-	} else {
-		/* Nothing to do! */
-		return 0;
 	}
+	return 0;
 }				/* get_threshold */
 
 static int
@@ -3954,49 +3884,45 @@ get_default_threshold(struct cyclades_po
 
 static int set_timeout(struct cyclades_port *info, unsigned long value)
 {
+	struct cyclades_card *card;
 	void __iomem *base_addr;
-	int card, channel, chip, index;
+	int channel, chip, index;
 	unsigned long flags;
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&card->card_lock, flags);
 		cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
-		CY_UNLOCK(info, flags);
-	} else {
-		/* Nothing to do! */
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 	return 0;
 }				/* set_timeout */
 
 static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
 {
+	struct cyclades_card *card;
 	void __iomem *base_addr;
-	int card, channel, chip, index;
+	int channel, chip, index;
 	unsigned long tmp;
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
-	if (!IS_CYC_Z(cy_card[card])) {
+	channel = info->line - card->first_line;
+	if (!IS_CYC_Z(*card)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		index = cy_card[card].bus_index;
-		base_addr =
-		    cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+		index = card->bus_index;
+		base_addr = card->base_addr + (cy_chip_offset[chip] << index);
 
-		tmp = cy_readb(base_addr + (CyRTPR << index));
+		tmp = readb(base_addr + (CyRTPR << index));
 		return put_user(tmp, value);
-	} else {
-		/* Nothing to do! */
-		return 0;
 	}
+	return 0;
 }				/* get_timeout */
 
 static int set_default_timeout(struct cyclades_port *info, unsigned long value)
@@ -4020,7 +3946,7 @@ static int
 cy_ioctl(struct tty_struct *tty, struct file *file,
 	 unsigned int cmd, unsigned long arg)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	struct cyclades_icount cprev, cnow;	/* kernel counter temps */
 	struct serial_icounter_struct __user *p_cuser;	/* user space */
 	int ret_val = 0;
@@ -4031,7 +3957,8 @@ cy_ioctl(struct tty_struct *tty, struct 
 		return -ENODEV;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg);	/* */
+	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+		info->line, cmd, arg);
 #endif
 
 	switch (cmd) {
@@ -4076,14 +4003,6 @@ #endif
 	case CYGETRTSDTR_INV:
 		ret_val = info->rtsdtr_inv;
 		break;
-	case CYGETCARDINFO:
-		if (copy_to_user(argp, &cy_card[info->card],
-				 sizeof(struct cyclades_card))) {
-			ret_val = -EFAULT;
-			break;
-		}
-		ret_val = 0;
-		break;
 	case CYGETCD1400VER:
 		ret_val = info->chip_rev;
 		break;
@@ -4119,34 +4038,22 @@ #endif				/* CONFIG_CYZ_INTR */
 		 * Caller should use TIOCGICOUNT to see which one it was
 		 */
 	case TIOCMIWAIT:
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&info->card->card_lock, flags);
 		/* note the counters on entry */
-		cprev = info->icount;
-		CY_UNLOCK(info, flags);
-		while (1) {
-			interruptible_sleep_on(&info->delta_msr_wait);
-			/* see if a signal did it */
-			if (signal_pending(current)) {
-				return -ERESTARTSYS;
-			}
-
-			CY_LOCK(info, flags);
+		cnow = info->icount;
+		spin_unlock_irqrestore(&info->card->card_lock, flags);
+		ret_val = wait_event_interruptible(info->delta_msr_wait, ({
+			cprev = cnow;
+			spin_lock_irqsave(&info->card->card_lock, flags);
 			cnow = info->icount;	/* atomic copy */
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&info->card->card_lock, flags);
 
-			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 */
+			((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));
+		}));
+		break;
 
 		/*
 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -4155,9 +4062,9 @@ #endif				/* CONFIG_CYZ_INTR */
 		 *     RI where only 0->1 is counted.
 		 */
 	case TIOCGICOUNT:
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&info->card->card_lock, flags);
 		cnow = info->icount;
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&info->card->card_lock, flags);
 		p_cuser = argp;
 		ret_val = put_user(cnow.cts, &p_cuser->cts);
 		if (ret_val)
@@ -4199,7 +4106,7 @@ #endif				/* CONFIG_CYZ_INTR */
 	}
 
 #ifdef CY_DEBUG_OTHER
-	printk(" cyc:cy_ioctl done\n");
+	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
 #endif
 
 	return ret_val;
@@ -4213,10 +4120,10 @@ #endif
  */
 static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_set_termios ttyC%d\n", info->line);
+	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
 #endif
 
 	if (tty->termios->c_cflag == old_termios->c_cflag &&
@@ -4248,8 +4155,9 @@ #endif
 */
 static void cy_send_xchar(struct tty_struct *tty, char ch)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-	int card, channel;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
+	int channel;
 
 	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
 		return;
@@ -4260,15 +4168,13 @@ static void cy_send_xchar(struct tty_str
 		cy_start(tty);
 
 	card = info->card;
-	channel = info->line - cy_card[card].first_line;
+	channel = info->line - card->first_line;
 
-	if (IS_CYC_Z(cy_card[card])) {
+	if (IS_CYC_Z(*card)) {
 		if (ch == STOP_CHAR(tty))
-			cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
-					0L);
+			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
 		else if (ch == START_CHAR(tty))
-			cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
-					0L);
+			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
 	}
 }
 
@@ -4278,15 +4184,16 @@ static void cy_send_xchar(struct tty_str
  */
 static void cy_throttle(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
 	unsigned long flags;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 
 #ifdef CY_DEBUG_THROTTLE
 	char buf[64];
 
-	printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+	printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
 			tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
@@ -4297,22 +4204,22 @@ #endif
 	card = info->card;
 
 	if (I_IXOFF(tty)) {
-		if (!IS_CYC_Z(cy_card[card]))
+		if (!IS_CYC_Z(*card))
 			cy_send_xchar(tty, STOP_CHAR(tty));
 		else
 			info->throttle = 1;
 	}
 
 	if (tty->termios->c_cflag & CRTSCTS) {
-		channel = info->line - cy_card[card].first_line;
-		if (!IS_CYC_Z(cy_card[card])) {
+		channel = info->line - card->first_line;
+		if (!IS_CYC_Z(*card)) {
 			chip = channel >> 2;
 			channel &= 0x03;
-			index = cy_card[card].bus_index;
-			base_addr = cy_card[card].base_addr +
+			index = card->bus_index;
+			base_addr = card->base_addr +
 				(cy_chip_offset[chip] << index);
 
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -4322,7 +4229,7 @@ #endif
 				cy_writeb(base_addr + (CyMSVR1 << index),
 					  ~CyRTS);
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		} else {
 			info->throttle = 1;
 		}
@@ -4336,16 +4243,17 @@ #endif
  */
 static void cy_unthrottle(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
 	unsigned long flags;
 	void __iomem *base_addr;
-	int card, chip, channel, index;
+	int chip, channel, index;
 
 #ifdef CY_DEBUG_THROTTLE
 	char buf[64];
 
-	printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
-		tty->ldisc.chars_in_buffer(tty), info->line);
+	printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
+		tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
@@ -4361,15 +4269,15 @@ #endif
 
 	if (tty->termios->c_cflag & CRTSCTS) {
 		card = info->card;
-		channel = info->line - cy_card[card].first_line;
-		if (!IS_CYC_Z(cy_card[card])) {
+		channel = info->line - card->first_line;
+		if (!IS_CYC_Z(*card)) {
 			chip = channel >> 2;
 			channel &= 0x03;
-			index = cy_card[card].bus_index;
-			base_addr = cy_card[card].base_addr +
+			index = card->bus_index;
+			base_addr = card->base_addr +
 				(cy_chip_offset[chip] << index);
 
-			CY_LOCK(info, flags);
+			spin_lock_irqsave(&card->card_lock, flags);
 			cy_writeb(base_addr + (CyCAR << index),
 				  (u_char) channel);
 			if (info->rtsdtr_inv) {
@@ -4379,7 +4287,7 @@ #endif
 				cy_writeb(base_addr + (CyMSVR1 << index),
 					  CyRTS);
 			}
-			CY_UNLOCK(info, flags);
+			spin_unlock_irqrestore(&card->card_lock, flags);
 		} else {
 			info->throttle = 0;
 		}
@@ -4392,102 +4300,96 @@ #endif
 static void cy_stop(struct tty_struct *tty)
 {
 	struct cyclades_card *cinfo;
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	void __iomem *base_addr;
 	int chip, channel, index;
 	unsigned long flags;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_stop ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_stop"))
 		return;
 
-	cinfo = &cy_card[info->card];
+	cinfo = info->card;
 	channel = info->line - cinfo->first_line;
 	if (!IS_CYC_Z(*cinfo)) {
 		index = cinfo->bus_index;
 		chip = channel >> 2;
 		channel &= 0x03;
-		base_addr = cy_card[info->card].base_addr +
-			(cy_chip_offset[chip] << index);
+		base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&cinfo->card_lock, flags);
 		cy_writeb(base_addr + (CyCAR << index),
 			(u_char)(channel & 0x0003)); /* index channel */
 		cy_writeb(base_addr + (CySRER << index),
-			  cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
-		CY_UNLOCK(info, flags);
-	} else {
-		/* Nothing to do! */
+			  readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+		spin_unlock_irqrestore(&cinfo->card_lock, flags);
 	}
 }				/* cy_stop */
 
 static void cy_start(struct tty_struct *tty)
 {
 	struct cyclades_card *cinfo;
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 	void __iomem *base_addr;
 	int chip, channel, index;
 	unsigned long flags;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_start ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_start"))
 		return;
 
-	cinfo = &cy_card[info->card];
+	cinfo = info->card;
 	channel = info->line - cinfo->first_line;
 	index = cinfo->bus_index;
 	if (!IS_CYC_Z(*cinfo)) {
 		chip = channel >> 2;
 		channel &= 0x03;
-		base_addr = cy_card[info->card].base_addr +
-			(cy_chip_offset[chip] << index);
+		base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
 
-		CY_LOCK(info, flags);
+		spin_lock_irqsave(&cinfo->card_lock, flags);
 		cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003));	/* index channel */
 		cy_writeb(base_addr + (CySRER << index),
-			  cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
-		CY_UNLOCK(info, flags);
-	} else {
-		/* Nothing to do! */
+			  readb(base_addr + (CySRER << index)) | CyTxRdy);
+		spin_unlock_irqrestore(&cinfo->card_lock, flags);
 	}
 }				/* cy_start */
 
 static void cy_flush_buffer(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-	int card, channel, retval;
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_card *card;
+	int channel, retval;
 	unsigned long flags;
 
 #ifdef CY_DEBUG_IO
-	printk("cyc:cy_flush_buffer ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
 		return;
 
 	card = info->card;
-	channel = (info->line) - (cy_card[card].first_line);
+	channel = info->line - card->first_line;
 
-	CY_LOCK(info, flags);
+	spin_lock_irqsave(&card->card_lock, flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	CY_UNLOCK(info, flags);
+	spin_unlock_irqrestore(&card->card_lock, flags);
 
-	if (IS_CYC_Z(cy_card[card])) {	/* If it is a Z card, flush the on-board
+	if (IS_CYC_Z(*card)) {	/* If it is a Z card, flush the on-board
 					   buffers as well */
-		CY_LOCK(info, flags);
-		retval =
-		    cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+		spin_lock_irqsave(&card->card_lock, flags);
+		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
 		if (retval != 0) {
-			printk("cyc: flush_buffer retval on ttyC%d was %x\n",
-				info->line, retval);
+			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+				"was %x\n", info->line, retval);
 		}
-		CY_UNLOCK(info, flags);
+		spin_unlock_irqrestore(&card->card_lock, flags);
 	}
 	tty_wakeup(tty);
 }				/* cy_flush_buffer */
@@ -4497,10 +4399,10 @@ #endif
  */
 static void cy_hangup(struct tty_struct *tty)
 {
-	struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+	struct cyclades_port *info = tty->driver_data;
 
 #ifdef CY_DEBUG_OTHER
-	printk("cyc:cy_hangup ttyC%d\n", info->line);	/* */
+	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
@@ -4511,7 +4413,8 @@ #endif
 	info->event = 0;
 	info->count = 0;
 #ifdef CY_DEBUG_COUNT
-	printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+	printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
+		current->pid);
 #endif
 	info->tty = NULL;
 	info->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -4526,10 +4429,107 @@ #endif
  * ---------------------------------------------------------------------
  */
 
+static int __devinit cy_init_card(struct cyclades_card *cinfo)
+{
+	struct cyclades_port *info;
+	u32 mailbox;
+	unsigned int nports;
+	unsigned short chip_number;
+	int index, port;
+
+	spin_lock_init(&cinfo->card_lock);
+
+	if (IS_CYC_Z(*cinfo)) {	/* Cyclades-Z */
+		mailbox = readl(&((struct RUNTIME_9060 __iomem *)
+				     cinfo->ctl_addr)->mail_box_0);
+		nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+		cinfo->intr_enabled = 0;
+		cinfo->nports = 0;	/* Will be correctly set later, after
+					   Z FW is loaded */
+	} else {
+		index = cinfo->bus_index;
+		nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+	}
+
+	cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
+	if (cinfo->ports == NULL) {
+		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
+		cinfo->nports = 0;
+		return -ENOMEM;
+	}
+
+	for (port = cinfo->first_line; port < cinfo->first_line + nports;
+			port++) {
+		info = &cinfo->ports[port - cinfo->first_line];
+		info->magic = CYCLADES_MAGIC;
+		info->card = cinfo;
+		info->line = port;
+		info->flags = STD_COM_FLAGS;
+		info->closing_wait = CLOSING_WAIT_DELAY;
+		info->close_delay = 5 * HZ / 10;
+
+		INIT_WORK(&info->tqueue, do_softint);
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+		init_completion(&info->shutdown_wait);
+		init_waitqueue_head(&info->delta_msr_wait);
+
+		if (IS_CYC_Z(*cinfo)) {
+			info->type = PORT_STARTECH;
+			if (mailbox == ZO_V1)
+				info->xmit_fifo_size = CYZ_FIFO_SIZE;
+			else
+				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
+#ifdef CONFIG_CYZ_INTR
+			setup_timer(&cyz_rx_full_timer[port],
+				cyz_rx_restart, (unsigned long)info);
+#endif
+		} else {
+			info->type = PORT_CIRRUS;
+			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+			info->cor2 = CyETC;
+			info->cor3 = 0x08;	/* _very_ small rcv threshold */
+
+			chip_number = (port - cinfo->first_line) / 4;
+			if ((info->chip_rev = readb(cinfo->base_addr +
+				      (cy_chip_offset[chip_number] <<
+				       index) + (CyGFRCR << index))) >=
+			    CD1400_REV_J) {
+				/* It is a CD1400 rev. J or later */
+				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
+				info->tco = baud_co_60[13];	/* Tx CO */
+				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
+				info->rco = baud_co_60[13];	/* Rx CO */
+				info->rtsdtr_inv = 1;
+			} else {
+				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
+				info->tco = baud_co_25[13];	/* Tx CO */
+				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
+				info->rco = baud_co_25[13];	/* Rx CO */
+				info->rtsdtr_inv = 0;
+			}
+			info->read_status_mask = CyTIMEOUT | CySPECHAR |
+				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
+		}
+
+	}
+
+#ifndef CONFIG_CYZ_INTR
+	if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
+		mod_timer(&cyz_timerlist, jiffies + 1);
+#ifdef CY_PCI_DEBUG
+		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
+#endif
+	}
+#endif
+	return 0;
+}
+
 /* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
-static unsigned short __init
-cyy_init_card(void __iomem * true_base_addr, int index)
+static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
+		int index)
 {
 	unsigned int chip_number;
 	void __iomem *base_addr;
@@ -4544,7 +4544,7 @@ cyy_init_card(void __iomem * true_base_a
 		base_addr =
 		    true_base_addr + (cy_chip_offset[chip_number] << index);
 		mdelay(1);
-		if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
+		if (readb(base_addr + (CyCCR << index)) != 0x00) {
 			/*************
 			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
 			chip_number, (unsigned long)base_addr);
@@ -4561,7 +4561,7 @@ cyy_init_card(void __iomem * true_base_a
 		   chip 4 GFRCR register appears at chip 0, there is no chip 4
 		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
 		 */
-		if (chip_number == 4 && cy_readb(true_base_addr +
+		if (chip_number == 4 && readb(true_base_addr +
 				(cy_chip_offset[0] << index) +
 				(CyGFRCR << index)) == 0) {
 			return chip_number;
@@ -4570,7 +4570,7 @@ cyy_init_card(void __iomem * true_base_a
 		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
 		mdelay(1);
 
-		if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
+		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
 			/*
 			   printk(" chip #%d at %#6lx is not responding ",
 			   chip_number, (unsigned long)base_addr);
@@ -4578,7 +4578,7 @@ cyy_init_card(void __iomem * true_base_a
 			 */
 			return chip_number;
 		}
-		if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
+		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
 				0x40) {
 			/*
 			printk(" chip #%d at %#6lx is not valid (GFRCR == "
@@ -4589,7 +4589,7 @@ cyy_init_card(void __iomem * true_base_a
 			return chip_number;
 		}
 		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
-		if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
+		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
 			/* It is a CD1400 rev. J or later */
 			/* Impossible to reach 5ms with this chip.
 			   Changed to 2ms instead (f = 500 Hz). */
@@ -4602,7 +4602,7 @@ cyy_init_card(void __iomem * true_base_a
 		/*
 		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
 		   chip_number, (unsigned long)base_addr,
-		   cy_readb(base_addr+(CyGFRCR<<index)));
+		   readb(base_addr+(CyGFRCR<<index)));
 		 */
 	}
 	return chip_number;
@@ -4647,9 +4647,15 @@ #endif
 
 		/* probe for CD1400... */
 		cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+		if (cy_isa_address == NULL) {
+			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
+					"address\n");
+			continue;
+		}
 		cy_isa_nchan = CyPORTS_PER_CHIP *
 			cyy_init_card(cy_isa_address, 0);
 		if (cy_isa_nchan == 0) {
+			iounmap(cy_isa_address);
 			continue;
 		}
 #ifdef MODULE
@@ -4660,40 +4666,42 @@ #endif
 			/* find out the board's irq by probing */
 			cy_isa_irq = detect_isa_irq(cy_isa_address);
 		if (cy_isa_irq == 0) {
-			printk("Cyclom-Y/ISA found at 0x%lx ",
+			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
+				"IRQ could not be detected.\n",
 				(unsigned long)cy_isa_address);
-			printk("but the IRQ could not be detected.\n");
+			iounmap(cy_isa_address);
 			continue;
 		}
 
 		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
-			printk("Cyclom-Y/ISA found at 0x%lx ",
+			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+				"more channels are available. Change NR_PORTS "
+				"in cyclades.c and recompile kernel.\n",
 				(unsigned long)cy_isa_address);
-			printk("but no more channels are available.\n");
-			printk("Change NR_PORTS in cyclades.c and recompile "
-					"kernel.\n");
+			iounmap(cy_isa_address);
 			return nboard;
 		}
 		/* fill the next cy_card structure available */
 		for (j = 0; j < NR_CARDS; j++) {
-			if (cy_card[j].base_addr == 0)
+			if (cy_card[j].base_addr == NULL)
 				break;
 		}
 		if (j == NR_CARDS) {	/* no more cy_cards available */
-			printk("Cyclom-Y/ISA found at 0x%lx ",
+			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+				"more cards can be used. Change NR_CARDS in "
+				"cyclades.c and recompile kernel.\n",
 				(unsigned long)cy_isa_address);
-			printk("but no more cards can be used .\n");
-			printk("Change NR_CARDS in cyclades.c and recompile "
-					"kernel.\n");
+			iounmap(cy_isa_address);
 			return nboard;
 		}
 
 		/* allocate IRQ */
 		if (request_irq(cy_isa_irq, cyy_interrupt,
 				IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
-			printk("Cyclom-Y/ISA found at 0x%lx ",
-				(unsigned long)cy_isa_address);
-			printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
+			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
+				"could not allocate IRQ#%d.\n",
+				(unsigned long)cy_isa_address, cy_isa_irq);
+			iounmap(cy_isa_address);
 			return nboard;
 		}
 
@@ -4704,15 +4712,23 @@ #endif
 		cy_card[j].bus_index = 0;
 		cy_card[j].first_line = cy_next_channel;
 		cy_card[j].num_chips = cy_isa_nchan / 4;
+		if (cy_init_card(&cy_card[j])) {
+			cy_card[j].base_addr = NULL;
+			free_irq(cy_isa_irq, &cy_card[j]);
+			iounmap(cy_isa_address);
+			continue;
+		}
 		nboard++;
 
-		/* print message */
-		printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
+			"%d channels starting from port %d\n",
 			j + 1, (unsigned long)cy_isa_address,
 			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
-			cy_isa_irq);
-		printk("%d channels starting from port %d.\n",
-			cy_isa_nchan, cy_next_channel);
+			cy_isa_irq, cy_isa_nchan, cy_next_channel);
+
+		for (j = cy_next_channel;
+				j < cy_next_channel + cy_isa_nchan; j++)
+			tty_register_device(cy_serial_driver, j, NULL);
 		cy_next_channel += cy_isa_nchan;
 	}
 	return nboard;
@@ -4721,510 +4737,310 @@ #else
 #endif				/* CONFIG_ISA */
 }				/* cy_detect_isa */
 
-static void plx_init(void __iomem * addr, uclong initctl)
+#ifdef CONFIG_PCI
+static void __devinit plx_init(void __iomem * addr, __u32 initctl)
 {
 	/* Reset PLX */
-	cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+	cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000);
 	udelay(100L);
-	cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+	cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000);
 
 	/* Reload Config. Registers from EEPROM */
-	cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+	cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000);
 	udelay(100L);
-	cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+	cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000);
 }
 
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-static int __init cy_detect_pci(void)
+static int __devinit cy_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
 {
-#ifdef CONFIG_PCI
-
-	struct pci_dev *pdev = NULL;
-	unsigned char cyy_rev_id;
-	unsigned char cy_pci_irq = 0;
-	uclong cy_pci_phys0, cy_pci_phys2;
-	void __iomem *cy_pci_addr0, *cy_pci_addr2;
-	unsigned short i, j, cy_pci_nchan, plx_ver;
-	unsigned short device_id, dev_index = 0;
-	uclong mailbox;
-	uclong ZeIndex = 0;
-	void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
-	uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
-	unsigned char Ze_irq[NR_CARDS];
-	struct pci_dev *Ze_pdev[NR_CARDS];
-
-	for (i = 0; i < NR_CARDS; i++) {
-		/* look for a Cyclades card by vendor and device id */
-		while ((device_id = cy_pci_dev_id[dev_index].device) != 0) {
-			if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
-						   device_id, pdev)) == NULL) {
-				dev_index++;	/* try next device id */
-			} else {
-				break;	/* found a board */
-			}
-		}
-
-		if (device_id == 0)
-			break;
-
-		if (pci_enable_device(pdev))
-			continue;
-
-		/* read PCI configuration area */
-		cy_pci_irq = pdev->irq;
-		cy_pci_phys0 = pci_resource_start(pdev, 0);
-		cy_pci_phys2 = pci_resource_start(pdev, 2);
-		pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+	void __iomem *addr0 = NULL, *addr2 = NULL;
+	char *card_name = NULL;
+	u32 mailbox;
+	unsigned int device_id, nchan = 0, card_no, i;
+	unsigned char plx_ver;
+	int retval, irq;
+
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		dev_err(&pdev->dev, "cannot enable device\n");
+		goto err;
+	}
 
-		device_id &= ~PCI_DEVICE_ID_MASK;
+	/* read PCI configuration area */
+	irq = pdev->irq;
+	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
 
-		if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
-				device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
-#ifdef CY_PCI_DEBUG
-			printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-				pdev->bus->number, pdev->devfn);
-			printk("rev_id=%d) IRQ%d\n",
-				cyy_rev_id, (int)cy_pci_irq);
-			printk("Cyclom-Y/PCI:found  winaddr=0x%lx "
-				"ctladdr=0x%lx\n",
-				(ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+#if defined(__alpha__)
+	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
+		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
+			"addresses on Alpha systems.\n");
+		retval = -EIO;
+		goto err_dis;
+	}
 #endif
+	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
+		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
+			"addresses\n");
+		retval = -EIO;
+		goto err_dis;
+	}
 
-			if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
-				printk("  Warning: PCI I/O bit incorrectly "
-					"set. Ignoring it...\n");
-				pdev->resource[2].flags &= ~IORESOURCE_IO;
-			}
+	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
+				"it...\n");
+		pdev->resource[2].flags &= ~IORESOURCE_IO;
+	}
 
-			/* Although we don't use this I/O region, we should
-			   request it from the kernel anyway, to avoid problems
-			   with other drivers accessing it. */
-			if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
-				printk(KERN_ERR "cyclades: failed to reserve "
-						"PCI resources\n");
-				continue;
-			}
-#if defined(__alpha__)
-			if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
-				printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-					pdev->bus->number, pdev->devfn);
-				printk("rev_id=%d) IRQ%d\n",
-					cyy_rev_id, (int)cy_pci_irq);
-				printk("Cyclom-Y/PCI:found  winaddr=0x%lx "
-					"ctladdr=0x%lx\n",
-					(ulong)cy_pci_phys2,
-					(ulong)cy_pci_phys0);
-				printk("Cyclom-Y/PCI not supported for low "
-					"addresses in Alpha systems.\n");
-				i--;
-				continue;
-			}
-#endif
-			cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
-			cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
+	retval = pci_request_regions(pdev, "cyclades");
+	if (retval) {
+		dev_err(&pdev->dev, "failed to reserve resources\n");
+		goto err_dis;
+	}
 
-#ifdef CY_PCI_DEBUG
-			printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
-				"ctladdr=0x%lx\n",
-				(u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
-#endif
-			cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
-					cyy_init_card(cy_pci_addr2, 1));
-			if (cy_pci_nchan == 0) {
-				printk("Cyclom-Y PCI host card with ");
-				printk("no Serial-Modules at 0x%lx.\n",
-					(ulong) cy_pci_phys2);
-				i--;
-				continue;
-			}
-			if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
-				printk("Cyclom-Y/PCI found at 0x%lx ",
-					(ulong) cy_pci_phys2);
-				printk("but no channels are available.\n");
-				printk("Change NR_PORTS in cyclades.c and "
-						"recompile kernel.\n");
-				return i;
-			}
-			/* fill the next cy_card structure available */
-			for (j = 0; j < NR_CARDS; j++) {
-				if (cy_card[j].base_addr == 0)
-					break;
-			}
-			if (j == NR_CARDS) {	/* no more cy_cards available */
-				printk("Cyclom-Y/PCI found at 0x%lx ",
-					(ulong) cy_pci_phys2);
-				printk("but no more cards can be used.\n");
-				printk("Change NR_CARDS in cyclades.c and "
-						"recompile kernel.\n");
-				return i;
-			}
+	retval = -EIO;
+	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+		card_name = "Cyclom-Y";
 
-			/* allocate IRQ */
-			if (request_irq(cy_pci_irq, cyy_interrupt,
-					IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
-				printk("Cyclom-Y/PCI found at 0x%lx ",
-					(ulong) cy_pci_phys2);
-				printk("but could not allocate IRQ%d.\n",
-					cy_pci_irq);
-				return i;
-			}
+		addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+		if (addr0 == NULL) {
+			dev_err(&pdev->dev, "can't remap ctl region\n");
+			goto err_reg;
+		}
+		addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+		if (addr2 == NULL) {
+			dev_err(&pdev->dev, "can't remap base region\n");
+			goto err_unmap;
+		}
 
-			/* set cy_card */
-			cy_card[j].base_phys = (ulong) cy_pci_phys2;
-			cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
-			cy_card[j].base_addr = cy_pci_addr2;
-			cy_card[j].ctl_addr = cy_pci_addr0;
-			cy_card[j].irq = (int)cy_pci_irq;
-			cy_card[j].bus_index = 1;
-			cy_card[j].first_line = cy_next_channel;
-			cy_card[j].num_chips = cy_pci_nchan / 4;
-			cy_card[j].pdev = pdev;
-
-			/* enable interrupts in the PCI interface */
-			plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
-			switch (plx_ver) {
-			case PLX_9050:
-
-				cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
-				break;
+		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
+		if (nchan == 0) {
+			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
+					"Serial-Modules\n");
+			return -EIO;
+		}
+	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
+		struct RUNTIME_9060 __iomem *ctl_addr;
 
-			case PLX_9060:
-			case PLX_9080:
-			default:	/* Old boards, use PLX_9060 */
-
-				plx_init(cy_pci_addr0, 0x6c);
-			/* For some yet unknown reason, once the PLX9060 reloads
-			   the EEPROM, the IRQ is lost and, thus, we have to
-			   re-write it to the PCI config. registers.
-			   This will remain here until we find a permanent
-			   fix. */
-				pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
-						cy_pci_irq);
-
-				cy_writew(cy_pci_addr0 + 0x68,
-					  cy_readw(cy_pci_addr0 +
-						   0x68) | 0x0900);
-				break;
-			}
+		ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+		if (addr0 == NULL) {
+			dev_err(&pdev->dev, "can't remap ctl region\n");
+			goto err_reg;
+		}
 
-			/* print message */
-			printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
-				j + 1, (ulong)cy_pci_phys2,
-				(ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
-				(int)cy_pci_irq);
-			printk("%d channels starting from port %d.\n",
-				cy_pci_nchan, cy_next_channel);
-
-			cy_next_channel += cy_pci_nchan;
-		} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
-			/* print message */
-			printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-				pdev->bus->number, pdev->devfn);
-			printk("rev_id=%d) IRQ%d\n",
-				cyy_rev_id, (int)cy_pci_irq);
-			printk("Cyclades-Z/PCI: found winaddr=0x%lx "
-				"ctladdr=0x%lx\n",
-				(ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
-			printk("Cyclades-Z/PCI not supported for low "
-				"addresses\n");
-			break;
-		} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
-#ifdef CY_PCI_DEBUG
-			printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-				pdev->bus->number, pdev->devfn);
-			printk("rev_id=%d) IRQ%d\n",
-				cyy_rev_id, (int)cy_pci_irq);
-			printk("Cyclades-Z/PCI: found winaddr=0x%lx "
-				"ctladdr=0x%lx\n",
-				(ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
-#endif
-			cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
-
-			/* Disable interrupts on the PLX before resetting it */
-			cy_writew(cy_pci_addr0 + 0x68,
-				cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
-
-			plx_init(cy_pci_addr0, 0x6c);
-			/* For some yet unknown reason, once the PLX9060 reloads
-			   the EEPROM, the IRQ is lost and, thus, we have to
-			   re-write it to the PCI config. registers.
-			   This will remain here until we find a permanent
-			   fix. */
-			pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
-						cy_pci_irq);
-
-			mailbox =
-			    (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
-						cy_pci_addr0)->mail_box_0);
-
-			if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
-				printk("  Warning: PCI I/O bit incorrectly "
-					"set. Ignoring it...\n");
-				pdev->resource[2].flags &= ~IORESOURCE_IO;
-			}
+		/* Disable interrupts on the PLX before resetting it */
+		cy_writew(addr0 + 0x68,
+			readw(addr0 + 0x68) & ~0x0900);
+
+		plx_init(addr0, 0x6c);
+		/* For some yet unknown reason, once the PLX9060 reloads
+		   the EEPROM, the IRQ is lost and, thus, we have to
+		   re-write it to the PCI config. registers.
+		   This will remain here until we find a permanent
+		   fix. */
+		pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+		mailbox = (u32)readl(&ctl_addr->mail_box_0);
+
+		addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
+				CyPCI_Ze_win : CyPCI_Zwin);
+		if (addr2 == NULL) {
+			dev_err(&pdev->dev, "can't remap base region\n");
+			goto err_unmap;
+		}
 
-			/* Although we don't use this I/O region, we should
-			   request it from the kernel anyway, to avoid problems
-			   with other drivers accessing it. */
-			if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
-				printk(KERN_ERR "cyclades: failed to reserve "
-					"PCI resources\n");
-				continue;
-			}
+		if (mailbox == ZE_V1) {
+			card_name = "Cyclades-Ze";
 
-			if (mailbox == ZE_V1) {
-				cy_pci_addr2 = ioremap(cy_pci_phys2,
-						CyPCI_Ze_win);
-				if (ZeIndex == NR_CARDS) {
-					printk("Cyclades-Ze/PCI found at "
-						"0x%lx but no more cards can "
-						"be used.\nChange NR_CARDS in "
-						"cyclades.c and recompile "
-						"kernel.\n",
-						(ulong)cy_pci_phys2);
-				} else {
-					Ze_phys0[ZeIndex] = cy_pci_phys0;
-					Ze_phys2[ZeIndex] = cy_pci_phys2;
-					Ze_addr0[ZeIndex] = cy_pci_addr0;
-					Ze_addr2[ZeIndex] = cy_pci_addr2;
-					Ze_irq[ZeIndex] = cy_pci_irq;
-					Ze_pdev[ZeIndex] = pdev;
-					ZeIndex++;
-				}
-				i--;
-				continue;
-			} else {
-				cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
-			}
+			readl(&ctl_addr->mail_box_0);
+			nchan = ZE_V1_NPORTS;
+		} else {
+			card_name = "Cyclades-8Zo";
 
 #ifdef CY_PCI_DEBUG
-			printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
-				"ctladdr=0x%lx\n",
-				(ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
 			if (mailbox == ZO_V1) {
-				cy_writel(&((struct RUNTIME_9060 *)
-					(cy_pci_addr0))->loc_addr_base,
-					WIN_CREG);
-				PAUSE;
-				printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
-					"%lx\n", (ulong) (0xff &
-					cy_readl(&((struct CUSTOM_REG *)
-						(cy_pci_addr2))->fpga_id)),
-					(ulong)(0xff &
-					cy_readl(&((struct CUSTOM_REG *)
-						(cy_pci_addr2))->
-							fpga_version)));
-				cy_writel(&((struct RUNTIME_9060 *)
-					(cy_pci_addr0))->loc_addr_base,
-					WIN_RAM);
+				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
+					"id %lx, ver %lx\n", (ulong)(0xff &
+					readl(&((struct CUSTOM_REG *)addr2)->
+						fpga_id)), (ulong)(0xff &
+					readl(&((struct CUSTOM_REG *)addr2)->
+						fpga_version)));
+				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
 			} else {
-				printk("Cyclades-Z/PCI: New Cyclades-Z board.  "
-						"FPGA not loaded\n");
+				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
+					"Cyclades-Z board.  FPGA not loaded\n");
 			}
 #endif
 			/* The following clears the firmware id word.  This
 			   ensures that the driver will not attempt to talk to
 			   the board until it has been properly initialized.
 			 */
-			PAUSE;
 			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
-				cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
+				cy_writel(addr2 + ID_ADDRESS, 0L);
 
 			/* This must be a Cyclades-8Zo/PCI.  The extendable
 			   version will have a different device_id and will
 			   be allocated its maximum number of ports. */
-			cy_pci_nchan = 8;
-
-			if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
-				printk("Cyclades-8Zo/PCI found at 0x%lx but"
-					"no channels are available.\nChange "
-					"NR_PORTS in cyclades.c and recompile "
-					"kernel.\n", (ulong)cy_pci_phys2);
-				return i;
-			}
-
-			/* fill the next cy_card structure available */
-			for (j = 0; j < NR_CARDS; j++) {
-				if (cy_card[j].base_addr == 0)
-					break;
-			}
-			if (j == NR_CARDS) {	/* no more cy_cards available */
-				printk("Cyclades-8Zo/PCI found at 0x%lx but"
-					"no more cards can be used.\nChange "
-					"NR_CARDS in cyclades.c and recompile "
-					"kernel.\n", (ulong)cy_pci_phys2);
-				return i;
-			}
-#ifdef CONFIG_CYZ_INTR
-			/* allocate IRQ only if board has an IRQ */
-			if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
-				if (request_irq(cy_pci_irq, cyz_interrupt,
-						IRQF_SHARED, "Cyclades-Z",
-						&cy_card[j])) {
-					printk("Cyclom-8Zo/PCI found at 0x%lx "
-						"but could not allocate "
-						"IRQ%d.\n", (ulong)cy_pci_phys2,
-						cy_pci_irq);
-					return i;
-				}
-			}
-#endif				/* CONFIG_CYZ_INTR */
-
-			/* set cy_card */
-			cy_card[j].base_phys = cy_pci_phys2;
-			cy_card[j].ctl_phys = cy_pci_phys0;
-			cy_card[j].base_addr = cy_pci_addr2;
-			cy_card[j].ctl_addr = cy_pci_addr0;
-			cy_card[j].irq = (int)cy_pci_irq;
-			cy_card[j].bus_index = 1;
-			cy_card[j].first_line = cy_next_channel;
-			cy_card[j].num_chips = -1;
-			cy_card[j].pdev = pdev;
-
-			/* print message */
-#ifdef CONFIG_CYZ_INTR
-			/* don't report IRQ if board is no IRQ */
-			if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
-				printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
-					"IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
-					(ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
-					(int)cy_pci_irq);
-			else
-#endif				/* CONFIG_CYZ_INTR */
-				printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
-					j + 1, (ulong)cy_pci_phys2,
-					(ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
-
-			printk("%d channels starting from port %d.\n",
-					cy_pci_nchan, cy_next_channel);
-			cy_next_channel += cy_pci_nchan;
+			nchan = 8;
 		}
 	}
 
-	for (; ZeIndex != 0 && i < NR_CARDS; i++) {
-		cy_pci_phys0 = Ze_phys0[0];
-		cy_pci_phys2 = Ze_phys2[0];
-		cy_pci_addr0 = Ze_addr0[0];
-		cy_pci_addr2 = Ze_addr2[0];
-		cy_pci_irq = Ze_irq[0];
-		pdev = Ze_pdev[0];
-		for (j = 0; j < ZeIndex - 1; j++) {
-			Ze_phys0[j] = Ze_phys0[j + 1];
-			Ze_phys2[j] = Ze_phys2[j + 1];
-			Ze_addr0[j] = Ze_addr0[j + 1];
-			Ze_addr2[j] = Ze_addr2[j + 1];
-			Ze_irq[j] = Ze_irq[j + 1];
-			Ze_pdev[j] = Ze_pdev[j + 1];
-		}
-		ZeIndex--;
-		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
-						cy_pci_addr0)->mail_box_0);
-#ifdef CY_PCI_DEBUG
-		printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
-			(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
-		printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not "
-				"loaded\n");
-#endif
-		PAUSE;
-		/* This must be the new Cyclades-Ze/PCI. */
-		cy_pci_nchan = ZE_V1_NPORTS;
-
-		if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
-			printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
-				"are available.\nChange NR_PORTS in cyclades.c "
-				"and recompile kernel.\n",
-				(ulong) cy_pci_phys2);
-			return i;
-		}
+	if ((cy_next_channel + nchan) > NR_PORTS) {
+		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+			"channels are available. Change NR_PORTS in "
+			"cyclades.c and recompile kernel.\n");
+		goto err_unmap;
+	}
+	/* fill the next cy_card structure available */
+	for (card_no = 0; card_no < NR_CARDS; card_no++) {
+		if (cy_card[card_no].base_addr == NULL)
+			break;
+	}
+	if (card_no == NR_CARDS) {	/* no more cy_cards available */
+		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+			"more cards can be used. Change NR_CARDS in "
+			"cyclades.c and recompile kernel.\n");
+		goto err_unmap;
+	}
 
-		/* fill the next cy_card structure available */
-		for (j = 0; j < NR_CARDS; j++) {
-			if (cy_card[j].base_addr == 0)
-				break;
-		}
-		if (j == NR_CARDS) {	/* no more cy_cards available */
-			printk("Cyclades-Ze/PCI found at 0x%lx but no more "
-				"cards can be used.\nChange NR_CARDS in "
-				"cyclades.c and recompile kernel.\n",
-				(ulong) cy_pci_phys2);
-			return i;
+	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+		/* allocate IRQ */
+		retval = request_irq(irq, cyy_interrupt,
+				IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+		if (retval) {
+			dev_err(&pdev->dev, "could not allocate IRQ\n");
+			goto err_unmap;
 		}
+		cy_card[card_no].num_chips = nchan / 4;
+	} else {
 #ifdef CONFIG_CYZ_INTR
 		/* allocate IRQ only if board has an IRQ */
-		if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
-			if (request_irq(cy_pci_irq, cyz_interrupt,
+		if (irq != 0 && irq != 255) {
+			retval = request_irq(irq, cyz_interrupt,
 					IRQF_SHARED, "Cyclades-Z",
-					&cy_card[j])) {
-				printk("Cyclom-Ze/PCI found at 0x%lx ",
-					(ulong) cy_pci_phys2);
-				printk("but could not allocate IRQ%d.\n",
-					cy_pci_irq);
-				return i;
+					&cy_card[card_no]);
+			if (retval) {
+				dev_err(&pdev->dev, "could not allocate IRQ\n");
+				goto err_unmap;
 			}
 		}
 #endif				/* CONFIG_CYZ_INTR */
+		cy_card[card_no].num_chips = -1;
+	}
 
-		/* set cy_card */
-		cy_card[j].base_phys = cy_pci_phys2;
-		cy_card[j].ctl_phys = cy_pci_phys0;
-		cy_card[j].base_addr = cy_pci_addr2;
-		cy_card[j].ctl_addr = cy_pci_addr0;
-		cy_card[j].irq = (int)cy_pci_irq;
-		cy_card[j].bus_index = 1;
-		cy_card[j].first_line = cy_next_channel;
-		cy_card[j].num_chips = -1;
-		cy_card[j].pdev = pdev;
+	/* set cy_card */
+	cy_card[card_no].base_addr = addr2;
+	cy_card[card_no].ctl_addr = addr0;
+	cy_card[card_no].irq = irq;
+	cy_card[card_no].bus_index = 1;
+	cy_card[card_no].first_line = cy_next_channel;
+	retval = cy_init_card(&cy_card[card_no]);
+	if (retval)
+		goto err_null;
 
-		/* print message */
-#ifdef CONFIG_CYZ_INTR
-		/* don't report IRQ if board is no IRQ */
-		if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
-			printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
-				j + 1, (ulong) cy_pci_phys2,
-				(ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
-				(int)cy_pci_irq);
-		else
-#endif				/* CONFIG_CYZ_INTR */
-			printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
-				j + 1, (ulong) cy_pci_phys2,
-				(ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
+	pci_set_drvdata(pdev, &cy_card[card_no]);
 
-		printk("%d channels starting from port %d.\n",
-			cy_pci_nchan, cy_next_channel);
-		cy_next_channel += cy_pci_nchan;
-	}
-	if (ZeIndex != 0) {
-		printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
-			"used.\nChange NR_CARDS in cyclades.c and recompile "
-			"kernel.\n", (unsigned int)Ze_phys2[0]);
+	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+		/* enable interrupts in the PCI interface */
+		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
+		switch (plx_ver) {
+		case PLX_9050:
+
+			cy_writeb(addr0 + 0x4c, 0x43);
+			break;
+
+		case PLX_9060:
+		case PLX_9080:
+		default:	/* Old boards, use PLX_9060 */
+
+			plx_init(addr0, 0x6c);
+		/* For some yet unknown reason, once the PLX9060 reloads
+		   the EEPROM, the IRQ is lost and, thus, we have to
+		   re-write it to the PCI config. registers.
+		   This will remain here until we find a permanent
+		   fix. */
+			pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+			cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
+			break;
+		}
 	}
-	return i;
-#else
+
+	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
+		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
+	for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
+		tty_register_device(cy_serial_driver, i, &pdev->dev);
+	cy_next_channel += nchan;
+
 	return 0;
-#endif				/* ifdef CONFIG_PCI */
-}				/* cy_detect_pci */
+err_null:
+	cy_card[card_no].base_addr = NULL;
+	free_irq(irq, &cy_card[card_no]);
+err_unmap:
+	pci_iounmap(pdev, addr0);
+	if (addr2)
+		pci_iounmap(pdev, addr2);
+err_reg:
+	pci_release_regions(pdev);
+err_dis:
+	pci_disable_device(pdev);
+err:
+	return retval;
+}
 
-/*
- * This routine prints out the appropriate serial driver version number
- * and identifies which options were configured into this driver.
- */
-static inline void show_version(void)
+static void __devexit cy_pci_remove(struct pci_dev *pdev)
 {
-	printk("Cyclades driver " CY_VERSION "\n");
-	printk("        built %s %s\n", __DATE__, __TIME__);
-}				/* show_version */
+	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
+	unsigned int i;
+
+	/* non-Z with old PLX */
+	if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
+			PLX_9050)
+		cy_writeb(cinfo->ctl_addr + 0x4c, 0);
+	else
+#ifndef CONFIG_CYZ_INTR
+		if (!IS_CYC_Z(*cinfo))
+#endif
+		cy_writew(cinfo->ctl_addr + 0x68,
+				readw(cinfo->ctl_addr + 0x68) & ~0x0900);
+
+	pci_iounmap(pdev, cinfo->base_addr);
+	if (cinfo->ctl_addr)
+		pci_iounmap(pdev, cinfo->ctl_addr);
+	if (cinfo->irq
+#ifndef CONFIG_CYZ_INTR
+		&& !IS_CYC_Z(*cinfo)
+#endif /* CONFIG_CYZ_INTR */
+		)
+		free_irq(cinfo->irq, cinfo);
+	pci_release_regions(pdev);
+
+	cinfo->base_addr = NULL;
+	for (i = cinfo->first_line; i < cinfo->first_line +
+			cinfo->nports; i++)
+		tty_unregister_device(cy_serial_driver, i);
+	cinfo->nports = 0;
+	kfree(cinfo->ports);
+}
+
+static struct pci_driver cy_pci_driver = {
+	.name = "cyclades",
+	.id_table = cy_pci_dev_id,
+	.probe = cy_pci_probe,
+	.remove = __devexit_p(cy_pci_remove)
+};
+#endif
 
 static int
 cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
 		int *eof, void *data)
 {
 	struct cyclades_port *info;
-	int i;
+	unsigned int i, j;
 	int len = 0;
 	off_t begin = 0;
 	off_t pos = 0;
@@ -5238,33 +5054,34 @@ cyclades_get_proc_info(char *buf, char *
 	len += size;
 
 	/* Output one line for each known port */
-	for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
-		info = &cy_port[i];
-
-		if (info->count)
-			size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
-				"%8lu %9lu %6ld\n", info->line,
-				(cur_jifs - info->idle_stats.in_use) / HZ,
-				info->idle_stats.xmit_bytes,
-				(cur_jifs - info->idle_stats.xmit_idle) / HZ,
-				info->idle_stats.recv_bytes,
-				(cur_jifs - info->idle_stats.recv_idle) / HZ,
-				info->idle_stats.overruns,
-				(long)info->tty->ldisc.num);
-		else
-			size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
-				"%8lu %9lu %6ld\n",
-				info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
-		len += size;
-		pos = begin + len;
-
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
+	for (i = 0; i < NR_CARDS; i++)
+		for (j = 0; j < cy_card[i].nports; j++) {
+			info = &cy_card[i].ports[j];
+
+			if (info->count)
+				size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+					"%10lu %8lu %9lu %6ld\n", info->line,
+					(cur_jifs - info->idle_stats.in_use) /
+					HZ, info->idle_stats.xmit_bytes,
+					(cur_jifs - info->idle_stats.xmit_idle)/
+					HZ, info->idle_stats.recv_bytes,
+					(cur_jifs - info->idle_stats.recv_idle)/
+					HZ, info->idle_stats.overruns,
+					(long)info->tty->ldisc.num);
+			else
+				size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+					"%10lu %8lu %9lu %6ld\n",
+					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+			len += size;
+			pos = begin + len;
+
+			if (pos < offset) {
+				len = 0;
+				begin = pos;
+			}
+			if (pos > offset + length)
+				goto done;
 		}
-		if (pos > offset + length)
-			goto done;
-	}
 	*eof = 1;
 done:
 	*start = buf + (offset - begin);	/* Start of wanted data */
@@ -5319,18 +5136,15 @@ static const struct tty_operations cy_op
 
 static int __init cy_init(void)
 {
-	struct cyclades_port *info;
-	struct cyclades_card *cinfo;
-	int number_z_boards = 0;
-	int board, port, i, index;
-	unsigned long mailbox;
-	unsigned short chip_number;
-	int nports;
+	unsigned int nboards;
+	int retval = -ENOMEM;
 
 	cy_serial_driver = alloc_tty_driver(NR_PORTS);
 	if (!cy_serial_driver)
-		return -ENOMEM;
-	show_version();
+		goto err;
+
+	printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
+			__DATE__, __TIME__);
 
 	/* Initialize the tty_driver structure */
 
@@ -5344,15 +5158,13 @@ static int __init cy_init(void)
 	cy_serial_driver->init_termios = tty_std_termios;
 	cy_serial_driver->init_termios.c_cflag =
 	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 	tty_set_operations(cy_serial_driver, &cy_ops);
 
-	if (tty_register_driver(cy_serial_driver))
-		panic("Couldn't register Cyclades serial driver\n");
-
-	for (i = 0; i < NR_CARDS; i++) {
-		/* base_addr=0 indicates board not found */
-		cy_card[i].base_addr = NULL;
+	retval = tty_register_driver(cy_serial_driver);
+	if (retval) {
+		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
+		goto err_frtty;
 	}
 
 	/* the code below is responsible to find the boards. Each different
@@ -5363,223 +5175,68 @@ static int __init cy_init(void)
 	   the cy_next_channel. */
 
 	/* look for isa boards */
-	cy_isa_nboard = cy_detect_isa();
+	nboards = cy_detect_isa();
 
+#ifdef CONFIG_PCI
 	/* look for pci boards */
-	cy_pci_nboard = cy_detect_pci();
-
-	cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
-	/* invalidate remaining cy_card structures */
-	for (i = 0; i < NR_CARDS; i++) {
-		if (cy_card[i].base_addr == 0) {
-			cy_card[i].first_line = -1;
-			cy_card[i].ctl_addr = NULL;
-			cy_card[i].irq = 0;
-			cy_card[i].bus_index = 0;
-			cy_card[i].first_line = 0;
-			cy_card[i].num_chips = 0;
-		}
-	}
-	/* invalidate remaining cy_port structures */
-	for (i = cy_next_channel; i < NR_PORTS; i++) {
-		cy_port[i].line = -1;
-		cy_port[i].magic = -1;
-	}
-
-	/* initialize per-port data structures for each valid board found */
-	for (board = 0; board < cy_nboard; board++) {
-		cinfo = &cy_card[board];
-		if (cinfo->num_chips == -1) {	/* Cyclades-Z */
-			number_z_boards++;
-			mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
-					     cy_card[board].ctl_addr)->
-					   mail_box_0);
-			nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
-			cinfo->intr_enabled = 0;
-			cinfo->nports = 0;	/* Will be correctly set later, after 
-						   Z FW is loaded */
-			spin_lock_init(&cinfo->card_lock);
-			for (port = cinfo->first_line;
-			     port < cinfo->first_line + nports; port++) {
-				info = &cy_port[port];
-				info->magic = CYCLADES_MAGIC;
-				info->type = PORT_STARTECH;
-				info->card = board;
-				info->line = port;
-				info->chip_rev = 0;
-				info->flags = STD_COM_FLAGS;
-				info->tty = NULL;
-				if (mailbox == ZO_V1)
-					info->xmit_fifo_size = CYZ_FIFO_SIZE;
-				else
-					info->xmit_fifo_size =
-					    4 * CYZ_FIFO_SIZE;
-				info->cor1 = 0;
-				info->cor2 = 0;
-				info->cor3 = 0;
-				info->cor4 = 0;
-				info->cor5 = 0;
-				info->tbpr = 0;
-				info->tco = 0;
-				info->rbpr = 0;
-				info->rco = 0;
-				info->custom_divisor = 0;
-				info->close_delay = 5 * HZ / 10;
-				info->closing_wait = CLOSING_WAIT_DELAY;
-				info->icount.cts = info->icount.dsr =
-				    info->icount.rng = info->icount.dcd = 0;
-				info->icount.rx = info->icount.tx = 0;
-				info->icount.frame = info->icount.parity = 0;
-				info->icount.overrun = info->icount.brk = 0;
-				info->x_char = 0;
-				info->event = 0;
-				info->count = 0;
-				info->blocked_open = 0;
-				info->default_threshold = 0;
-				info->default_timeout = 0;
-				INIT_WORK(&info->tqueue, do_softint);
-				init_waitqueue_head(&info->open_wait);
-				init_waitqueue_head(&info->close_wait);
-				init_waitqueue_head(&info->shutdown_wait);
-				init_waitqueue_head(&info->delta_msr_wait);
-				/* info->session */
-				/* info->pgrp */
-				info->read_status_mask = 0;
-				/* info->timeout */
-				/* Bentson's vars */
-				info->jiffies[0] = 0;
-				info->jiffies[1] = 0;
-				info->jiffies[2] = 0;
-				info->rflush_count = 0;
-#ifdef CONFIG_CYZ_INTR
-				init_timer(&cyz_rx_full_timer[port]);
-				cyz_rx_full_timer[port].function = NULL;
+	retval = pci_register_driver(&cy_pci_driver);
+	if (retval && !nboards)
+		goto err_unr;
 #endif
-			}
-			continue;
-		} else {	/* Cyclom-Y of some kind */
-			index = cinfo->bus_index;
-			spin_lock_init(&cinfo->card_lock);
-			cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
-			for (port = cinfo->first_line;
-			     port < cinfo->first_line + cinfo->nports; port++) {
-				info = &cy_port[port];
-				info->magic = CYCLADES_MAGIC;
-				info->type = PORT_CIRRUS;
-				info->card = board;
-				info->line = port;
-				info->flags = STD_COM_FLAGS;
-				info->tty = NULL;
-				info->xmit_fifo_size = CyMAX_CHAR_FIFO;
-				info->cor1 =
-				    CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
-				info->cor2 = CyETC;
-				info->cor3 = 0x08;	/* _very_ small rcv threshold */
-				info->cor4 = 0;
-				info->cor5 = 0;
-				info->custom_divisor = 0;
-				info->close_delay = 5 * HZ / 10;
-				info->closing_wait = CLOSING_WAIT_DELAY;
-				info->icount.cts = info->icount.dsr =
-				    info->icount.rng = info->icount.dcd = 0;
-				info->icount.rx = info->icount.tx = 0;
-				info->icount.frame = info->icount.parity = 0;
-				info->icount.overrun = info->icount.brk = 0;
-				chip_number = (port - cinfo->first_line) / 4;
-				if ((info->chip_rev =
-				     cy_readb(cinfo->base_addr +
-					      (cy_chip_offset[chip_number] <<
-					       index) + (CyGFRCR << index))) >=
-				    CD1400_REV_J) {
-					/* It is a CD1400 rev. J or later */
-					info->tbpr = baud_bpr_60[13];	/* Tx BPR */
-					info->tco = baud_co_60[13];	/* Tx CO */
-					info->rbpr = baud_bpr_60[13];	/* Rx BPR */
-					info->rco = baud_co_60[13];	/* Rx CO */
-					info->rflow = 0;
-					info->rtsdtr_inv = 1;
-				} else {
-					info->tbpr = baud_bpr_25[13];	/* Tx BPR */
-					info->tco = baud_co_25[13];	/* Tx CO */
-					info->rbpr = baud_bpr_25[13];	/* Rx BPR */
-					info->rco = baud_co_25[13];	/* Rx CO */
-					info->rflow = 0;
-					info->rtsdtr_inv = 0;
-				}
-				info->x_char = 0;
-				info->event = 0;
-				info->count = 0;
-				info->blocked_open = 0;
-				info->default_threshold = 0;
-				info->default_timeout = 0;
-				INIT_WORK(&info->tqueue, do_softint);
-				init_waitqueue_head(&info->open_wait);
-				init_waitqueue_head(&info->close_wait);
-				init_waitqueue_head(&info->shutdown_wait);
-				init_waitqueue_head(&info->delta_msr_wait);
-				/* info->session */
-				/* info->pgrp */
-				info->read_status_mask =
-				    CyTIMEOUT | CySPECHAR | CyBREAK
-				    | CyPARITY | CyFRAME | CyOVERRUN;
-				/* info->timeout */
-			}
-		}
-	}
-
-#ifndef CONFIG_CYZ_INTR
-	if (number_z_boards && !cyz_timeron) {
-		cyz_timeron++;
-		cyz_timerlist.expires = jiffies + 1;
-		add_timer(&cyz_timerlist);
-#ifdef CY_PCI_DEBUG
-		printk("Cyclades-Z polling initialized\n");
-#endif
-	}
-#endif				/* CONFIG_CYZ_INTR */
 
 	return 0;
-
+err_unr:
+	tty_unregister_driver(cy_serial_driver);
+err_frtty:
+	put_tty_driver(cy_serial_driver);
+err:
+	return retval;
 }				/* cy_init */
 
 static void __exit cy_cleanup_module(void)
 {
+	struct cyclades_card *card;
 	int i, e1;
 
 #ifndef CONFIG_CYZ_INTR
-	if (cyz_timeron){
-		cyz_timeron = 0;
-		del_timer(&cyz_timerlist);
-	}
+	del_timer_sync(&cyz_timerlist);
 #endif /* CONFIG_CYZ_INTR */
 
 	if ((e1 = tty_unregister_driver(cy_serial_driver)))
-		printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
-			e1);
+		printk(KERN_ERR "failed to unregister Cyclades serial "
+				"driver(%d)\n", e1);
 
-	put_tty_driver(cy_serial_driver);
+#ifdef CONFIG_PCI
+	pci_unregister_driver(&cy_pci_driver);
+#endif
 
 	for (i = 0; i < NR_CARDS; i++) {
-		if (cy_card[i].base_addr) {
-			iounmap(cy_card[i].base_addr);
-			if (cy_card[i].ctl_addr)
-				iounmap(cy_card[i].ctl_addr);
-			if (cy_card[i].irq
+		card = &cy_card[i];
+		if (card->base_addr) {
+			/* clear interrupt */
+			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
+			iounmap(card->base_addr);
+			if (card->ctl_addr)
+				iounmap(card->ctl_addr);
+			if (card->irq
 #ifndef CONFIG_CYZ_INTR
-				&& cy_card[i].num_chips != -1 /* not a Z card */
+				&& !IS_CYC_Z(*card)
 #endif /* CONFIG_CYZ_INTR */
 				)
-				free_irq(cy_card[i].irq, &cy_card[i]);
-#ifdef CONFIG_PCI
-			if (cy_card[i].pdev)
-				pci_release_regions(cy_card[i].pdev);
-#endif
+				free_irq(card->irq, card);
+			for (e1 = card->first_line;
+					e1 < card->first_line +
+					card->nports; e1++)
+				tty_unregister_device(cy_serial_driver, e1);
+			kfree(card->ports);
 		}
 	}
+
+	put_tty_driver(cy_serial_driver);
 } /* cy_cleanup_module */
 
 module_init(cy_init);
 module_exit(cy_cleanup_module);
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CY_VERSION);
diff --git a/drivers/char/digi.h b/drivers/char/digi.h
deleted file mode 100644
index 19df0e8..0000000
--- a/drivers/char/digi.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*          Definitions for DigiBoard ditty(1) command.                 */
-
-#if !defined(TIOCMODG)
-#define	TIOCMODG	(('d'<<8) | 250)		/* get modem ctrl state	*/
-#define	TIOCMODS	(('d'<<8) | 251)		/* set modem ctrl state	*/
-#endif
-
-#if !defined(TIOCMSET)
-#define	TIOCMSET	(('d'<<8) | 252)		/* set modem ctrl state	*/
-#define	TIOCMGET	(('d'<<8) | 253)		/* set modem ctrl state	*/
-#endif
-
-#if !defined(TIOCMBIC)
-#define	TIOCMBIC	(('d'<<8) | 254)		/* set modem ctrl state */
-#define	TIOCMBIS	(('d'<<8) | 255)		/* set modem ctrl state */
-#endif
-
-#if !defined(TIOCSDTR)
-#define	TIOCSDTR	(('e'<<8) | 0)		/* set DTR		*/
-#define	TIOCCDTR	(('e'<<8) | 1)		/* clear DTR		*/
-#endif
-
-/************************************************************************
- * Ioctl command arguments for DIGI parameters.
- ************************************************************************/
-#define DIGI_GETA	(('e'<<8) | 94)		/* Read params		*/
-
-#define DIGI_SETA	(('e'<<8) | 95)		/* Set params		*/
-#define DIGI_SETAW	(('e'<<8) | 96)		/* Drain & set params	*/
-#define DIGI_SETAF	(('e'<<8) | 97)		/* Drain, flush & set params */
-
-#define	DIGI_GETFLOW	(('e'<<8) | 99)		/* Get startc/stopc flow */
-						/* control characters 	 */
-#define	DIGI_SETFLOW	(('e'<<8) | 100)		/* Set startc/stopc flow */
-						/* control characters	 */
-#define	DIGI_GETAFLOW	(('e'<<8) | 101)		/* Get Aux. startc/stopc */
-						/* flow control chars 	 */
-#define	DIGI_SETAFLOW	(('e'<<8) | 102)		/* Set Aux. startc/stopc */
-						/* flow control chars	 */
-
-struct	digiflow_struct {
-	unsigned char	startc;				/* flow cntl start char	*/
-	unsigned char	stopc;				/* flow cntl stop char	*/
-};
-
-typedef struct digiflow_struct digiflow_t;
-
-
-/************************************************************************
- * Values for digi_flags 
- ************************************************************************/
-#define DIGI_IXON	0x0001		/* Handle IXON in the FEP	*/
-#define DIGI_FAST	0x0002		/* Fast baud rates		*/
-#define RTSPACE		0x0004		/* RTS input flow control	*/
-#define CTSPACE		0x0008		/* CTS output flow control	*/
-#define DSRPACE		0x0010		/* DSR output flow control	*/
-#define DCDPACE		0x0020		/* DCD output flow control	*/
-#define DTRPACE		0x0040		/* DTR input flow control	*/
-#define DIGI_FORCEDCD	0x0100		/* Force carrier		*/
-#define	DIGI_ALTPIN	0x0200		/* Alternate RJ-45 pin config	*/
-#define	DIGI_AIXON	0x0400		/* Aux flow control in fep	*/
-
-
-/************************************************************************
- * Structure used with ioctl commands for DIGI parameters.
- ************************************************************************/
-struct digi_struct {
-	unsigned short	digi_flags;		/* Flags (see above)	*/
-};
-
-typedef struct digi_struct digi_t;
diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm
index 6441e01..af74cd7 100644
--- a/drivers/char/drm/README.drm
+++ b/drivers/char/drm/README.drm
@@ -1,6 +1,6 @@
 ************************************************************
 * For the very latest on DRI development, please see:      *
-*     http://dri.sourceforge.net/                          *
+*     http://dri.freedesktop.org/                          *
 ************************************************************
 
 The Direct Rendering Manager (drm) is a device-independent kernel-level
@@ -26,21 +26,19 @@ ways:
 
 
 Documentation on the DRI is available from:
-    http://precisioninsight.com/piinsights.html
+    http://dri.freedesktop.org/wiki/Documentation
+    http://sourceforge.net/project/showfiles.php?group_id=387
+    http://dri.sourceforge.net/doc/
 
 For specific information about kernel-level support, see:
 
     The Direct Rendering Manager, Kernel Support for the Direct Rendering
     Infrastructure
-    http://precisioninsight.com/dr/drm.html
+    http://dri.sourceforge.net/doc/drm_low_level.html
 
     Hardware Locking for the Direct Rendering Infrastructure
-    http://precisioninsight.com/dr/locking.html
+    http://dri.sourceforge.net/doc/hardware_locking_low_level.html
 
     A Security Analysis of the Direct Rendering Infrastructure
-    http://precisioninsight.com/dr/security.html
+    http://dri.sourceforge.net/doc/security_low_level.html
 
-************************************************************
-* For the very latest on DRI development, please see:      *
-*     http://dri.sourceforge.net/                          *
-************************************************************
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index bd7be09..5b91bc0 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -33,59 +33,44 @@
 
 #include "drmP.h"
 
-#if PAGE_SIZE == 65536
-# define ATI_PCIGART_TABLE_ORDER	0
-# define ATI_PCIGART_TABLE_PAGES	(1 << 0)
-#elif PAGE_SIZE == 16384
-# define ATI_PCIGART_TABLE_ORDER	1
-# define ATI_PCIGART_TABLE_PAGES	(1 << 1)
-#elif PAGE_SIZE == 8192
-# define ATI_PCIGART_TABLE_ORDER 	2
-# define ATI_PCIGART_TABLE_PAGES 	(1 << 2)
-#elif PAGE_SIZE == 4096
-# define ATI_PCIGART_TABLE_ORDER 	3
-# define ATI_PCIGART_TABLE_PAGES 	(1 << 3)
-#else
-# error - PAGE_SIZE not 64K, 16K, 8K or 4K
-#endif
-
-# define ATI_MAX_PCIGART_PAGES		8192	/**< 32 MB aperture, 4K pages */
 # define ATI_PCIGART_PAGE_SIZE		4096	/**< PCI GART page size */
 
-static void *drm_ati_alloc_pcigart_table(void)
+static void *drm_ati_alloc_pcigart_table(int order)
 {
 	unsigned long address;
 	struct page *page;
 	int i;
-	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
 
 	address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
-				   ATI_PCIGART_TABLE_ORDER);
+				   order);
 	if (address == 0UL) {
 		return NULL;
 	}
 
 	page = virt_to_page(address);
 
-	for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+	for (i = 0; i < order; i++, page++)
 		SetPageReserved(page);
 
 	DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
 	return (void *)address;
 }
 
-static void drm_ati_free_pcigart_table(void *address)
+static void drm_ati_free_pcigart_table(void *address, int order)
 {
 	struct page *page;
 	int i;
+	int num_pages = 1 << order;
 	DRM_DEBUG("%s\n", __FUNCTION__);
 
 	page = virt_to_page((unsigned long)address);
 
-	for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+	for (i = 0; i < num_pages; i++, page++)
 		ClearPageReserved(page);
 
-	free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
+	free_pages((unsigned long)address, order);
 }
 
 int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t
 	drm_sg_mem_t *entry = dev->sg;
 	unsigned long pages;
 	int i;
+	int order;
+	int num_pages, max_pages;
 
 	/* we need to support large memory configurations */
 	if (!entry) {
@@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t
 		return 0;
 	}
 
+	order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+	num_pages = 1 << order;
+
 	if (gart_info->bus_addr) {
 		if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
 			pci_unmap_single(dev->pdev, gart_info->bus_addr,
-					 ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+					 num_pages * PAGE_SIZE,
 					 PCI_DMA_TODEVICE);
 		}
 
-		pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
-		    ? entry->pages : ATI_MAX_PCIGART_PAGES;
+		max_pages = (gart_info->table_size / sizeof(u32));
+		pages = (entry->pages <= max_pages)
+		  ? entry->pages : max_pages;
 
 		for (i = 0; i < pages; i++) {
 			if (!entry->busaddr[i])
@@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t
 
 	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
 	    && gart_info->addr) {
-		drm_ati_free_pcigart_table(gart_info->addr);
+		drm_ati_free_pcigart_table(gart_info->addr, order);
 		gart_info->addr = NULL;
 	}
 
 	return 1;
 }
-
 EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
 
 int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *d
 	unsigned long pages;
 	u32 *pci_gart, page_base, bus_address = 0;
 	int i, j, ret = 0;
+	int order;
+	int max_pages;
+	int num_pages;
 
 	if (!entry) {
 		DRM_ERROR("no scatter/gather memory!\n");
@@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *d
 	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
 		DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
 
-		address = drm_ati_alloc_pcigart_table();
+		order = drm_order((gart_info->table_size +
+				   (PAGE_SIZE-1)) / PAGE_SIZE);
+		num_pages = 1 << order;
+		address = drm_ati_alloc_pcigart_table(order);
 		if (!address) {
 			DRM_ERROR("cannot allocate PCI GART page!\n");
 			goto done;
@@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *d
 		}
 
 		bus_address = pci_map_single(dev->pdev, address,
-					     ATI_PCIGART_TABLE_PAGES *
-					     PAGE_SIZE, PCI_DMA_TODEVICE);
+					     num_pages * PAGE_SIZE,
+					     PCI_DMA_TODEVICE);
 		if (bus_address == 0) {
 			DRM_ERROR("unable to map PCIGART pages!\n");
-			drm_ati_free_pcigart_table(address);
+			order = drm_order((gart_info->table_size +
+					   (PAGE_SIZE-1)) / PAGE_SIZE);
+			drm_ati_free_pcigart_table(address, order);
 			address = NULL;
 			goto done;
 		}
@@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *d
 
 	pci_gart = (u32 *) address;
 
-	pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
-	    ? entry->pages : ATI_MAX_PCIGART_PAGES;
+	max_pages = (gart_info->table_size / sizeof(u32));
+	pages = (entry->pages <= max_pages)
+	    ? entry->pages : max_pages;
 
-	memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32));
+	memset(pci_gart, 0, max_pages * sizeof(u32));
 
 	for (i = 0; i < pages; i++) {
 		/* we need to support large memory configurations */
@@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *d
 		page_base = (u32) entry->busaddr[i];
 
 		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
-			if (gart_info->is_pcie)
+			switch(gart_info->gart_reg_if) {
+			case DRM_ATI_GART_IGP:
+				*pci_gart = cpu_to_le32((page_base) | 0xc);
+				break;
+			case DRM_ATI_GART_PCIE:
 				*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
-			else
+				break;
+			default:
+			case DRM_ATI_GART_PCI:
 				*pci_gart = cpu_to_le32(page_base);
+				break;
+			}
 			pci_gart++;
 			page_base += ATI_PCIGART_PAGE_SIZE;
 		}
@@ -220,5 +227,4 @@ #endif
 	gart_info->bus_addr = bus_address;
 	return ret;
 }
-
 EXPORT_SYMBOL(drm_ati_pcigart_init);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 8db9041..0891984 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -654,11 +654,13 @@ #define DRM_IOCTL_UPDATE_DRAW		DRM_IOW(0
 
 /**
  * Device specific ioctls should only be in their respective headers
- * The device specific ioctl range is from 0x40 to 0x79.
+ * The device specific ioctl range is from 0x40 to 0x99.
+ * Generic IOCTLS restart at 0xA0.
  *
  * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
  * drmCommandReadWrite().
  */
 #define DRM_COMMAND_BASE                0x40
+#define DRM_COMMAND_END			0xA0
 
 #endif
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 85d99e2..d494315 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -414,6 +414,10 @@ typedef struct drm_lock_data {
 	struct file *filp;		/**< File descr of lock holder (0=kernel) */
 	wait_queue_head_t lock_queue;	/**< Queue of blocked processes */
 	unsigned long lock_time;	/**< Time of last lock in jiffies */
+	spinlock_t spinlock;
+	uint32_t kernel_waiters;
+	uint32_t user_waiters;
+	int idle_has_lock;
 } drm_lock_data_t;
 
 /**
@@ -515,12 +519,17 @@ typedef struct drm_vbl_sig {
 #define DRM_ATI_GART_MAIN 1
 #define DRM_ATI_GART_FB   2
 
+#define DRM_ATI_GART_PCI 1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP 3
+
 typedef struct ati_pcigart_info {
 	int gart_table_location;
-	int is_pcie;
+	int gart_reg_if;
 	void *addr;
 	dma_addr_t bus_addr;
 	drm_local_map_t mapping;
+	int table_size;
 } drm_ati_pcigart_info;
 
 /*
@@ -590,6 +599,8 @@ struct drm_driver {
 	void (*reclaim_buffers) (struct drm_device * dev, struct file * filp);
 	void (*reclaim_buffers_locked) (struct drm_device *dev,
 					struct file *filp);
+	void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
+					struct file * filp);
 	unsigned long (*get_map_ofs) (drm_map_t * map);
 	unsigned long (*get_reg_ofs) (struct drm_device * dev);
 	void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
@@ -764,7 +775,7 @@ static __inline__ int drm_core_check_fea
 }
 
 #ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->bus->number
+#define drm_get_pci_domain(dev) dev->hose->index
 #else
 #define drm_get_pci_domain(dev) 0
 #endif
@@ -915,9 +926,18 @@ extern int drm_lock(struct inode *inode,
 		    unsigned int cmd, unsigned long arg);
 extern int drm_unlock(struct inode *inode, struct file *filp,
 		      unsigned int cmd, unsigned long arg);
-extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context);
-extern int drm_lock_free(drm_device_t * dev,
-			 __volatile__ unsigned int *lock, unsigned int context);
+extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
+extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
+extern void drm_idlelock_take(drm_lock_data_t *lock_data);
+extern void drm_idlelock_release(drm_lock_data_t *lock_data);
+
+/*
+ * These are exported to drivers so that they can implement fencing using
+ * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
+ */
+
+extern int drm_i_have_hw_lock(struct file *filp);
+extern int drm_kernel_take_hw_lock(struct file *filp);
 
 				/* Buffer management support (drm_bufs.h) */
 extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index a6828cc..c113458 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching
 	list_for_each(list, &dev->maplist->head) {
 		drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
 		if (entry->map && map->type == entry->map->type &&
-		    entry->map->offset == map->offset) {
+		    ((entry->map->offset == map->offset) ||
+		     (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
 			return entry;
 		}
 	}
@@ -180,8 +181,20 @@ #endif
 		if (map->type == _DRM_REGISTERS)
 			map->handle = ioremap(map->offset, map->size);
 		break;
-
 	case _DRM_SHM:
+		list = drm_find_matching_map(dev, map);
+		if (list != NULL) {
+			if(list->map->size != map->size) {
+				DRM_DEBUG("Matching maps of type %d with "
+					  "mismatched sizes, (%ld vs %ld)\n",
+					  map->type, map->size, list->map->size);
+				list->map->size = map->size;
+			}
+
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			*maplist = list;
+			return 0;
+		}
 		map->handle = vmalloc_user(map->size);
 		DRM_DEBUG("%lu %d %p\n",
 			  map->size, drm_order(map->size), map->handle);
@@ -200,15 +213,45 @@ #endif
 			dev->sigdata.lock = dev->lock.hw_lock = map->handle;	/* Pointer to lock */
 		}
 		break;
-	case _DRM_AGP:
-		if (drm_core_has_AGP(dev)) {
+	case _DRM_AGP: {
+		drm_agp_mem_t *entry;
+		int valid = 0;
+
+		if (!drm_core_has_AGP(dev)) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EINVAL;
+		}
 #ifdef __alpha__
-			map->offset += dev->hose->mem_space->start;
+		map->offset += dev->hose->mem_space->start;
 #endif
-			map->offset += dev->agp->base;
-			map->mtrr = dev->agp->agp_mtrr;	/* for getmap */
+		/* Note: dev->agp->base may actually be 0 when the DRM
+		 * is not in control of AGP space. But if user space is
+		 * it should already have added the AGP base itself.
+		 */
+		map->offset += dev->agp->base;
+		map->mtrr = dev->agp->agp_mtrr;	/* for getmap */
+
+		/* This assumes the DRM is in total control of AGP space.
+		 * It's not always the case as AGP can be in the control
+		 * of user space (i.e. i810 driver). So this loop will get
+		 * skipped and we double check that dev->agp->memory is
+		 * actually set as well as being invalid before EPERM'ing
+		 */
+		for (entry = dev->agp->memory; entry; entry = entry->next) {
+			if ((map->offset >= entry->bound) &&
+			    (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
+				valid = 1;
+				break;
+			}
 		}
+		if (dev->agp->memory && !valid) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EPERM;
+		}
+		DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+
 		break;
+	}
 	case _DRM_SCATTER_GATHER:
 		if (!dev->sg) {
 			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
@@ -267,7 +310,7 @@ #endif
 
 	*maplist = list;
 	return 0;
-}
+	}
 
 int drm_addmap(drm_device_t * dev, unsigned int offset,
 	       unsigned int size, drm_map_type_t type,
@@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, 
 {
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_entry_t *entry;
+	drm_agp_mem_t *agp_entry;
 	drm_buf_t *buf;
 	unsigned long offset;
 	unsigned long agp_offset;
@@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, 
 	int page_order;
 	int total;
 	int byte_count;
-	int i;
+	int i, valid;
 	drm_buf_t **temp_buflist;
 
 	if (!dma)
@@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, 
 	if (dev->queue_count)
 		return -EBUSY;	/* Not while in use */
 
+	/* Make sure buffers are located in AGP memory that we own */
+	valid = 0;
+	for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
+		if ((agp_offset >= agp_entry->bound) &&
+		    (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+			valid = 1;
+			break;
+		}
+	}
+	if (dev->agp->memory && !valid) {
+		DRM_DEBUG("zone invalid\n");
+		return -EINVAL;
+	}
 	spin_lock(&dev->count_lock);
 	if (dev->buf_use) {
 		spin_unlock(&dev->count_lock);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index f5b9b24..8e77b7e 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -15,8 +15,6 @@
  * #define DRIVER_DESC		"Matrox G200/G400"
  * #define DRIVER_DATE		"20001127"
  *
- * #define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( mga_ioctls )
- *
  * #define drm_x		mga_##x
  * \endcode
  */
@@ -120,7 +118,7 @@ #endif
 	[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
 };
 
-#define DRIVER_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
+#define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
 
 /**
  * Take down the DRM device.
@@ -496,11 +494,14 @@ int drm_ioctl(struct inode *inode, struc
 		  (long)old_encode_dev(priv->head->device),
 		  priv->authenticated);
 
-	if (nr < DRIVER_IOCTL_COUNT)
-		ioctl = &drm_ioctls[nr];
-	else if ((nr >= DRM_COMMAND_BASE)
-		 && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
+	if ((nr >= DRM_CORE_IOCTL_COUNT) &&
+	    ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
+		goto err_i1;
+	if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
+	    (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
 		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
+		ioctl = &drm_ioctls[nr];
 	else
 		goto err_i1;
 
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 898f47d..3b159ca 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev)
 	drm_local_map_t *map;
 	int i;
 	int ret;
+	u32 sareapage;
 
 	if (dev->driver->firstopen) {
 		ret = dev->driver->firstopen(dev);
@@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev)
 	dev->magicfree.next = NULL;
 
 	/* prebuild the SAREA */
-	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+	sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
+	i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
 	if (i != 0)
 		return i;
 
@@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev)
 	INIT_LIST_HEAD(&dev->ctxlist->head);
 
 	dev->vmalist = NULL;
-	dev->sigdata.lock = dev->lock.hw_lock = NULL;
+	dev->sigdata.lock = NULL;
 	init_waitqueue_head(&dev->lock.lock_queue);
 	dev->queue_count = 0;
 	dev->queue_reserved = 0;
@@ -354,58 +356,56 @@ int drm_release(struct inode *inode, str
 		  current->pid, (long)old_encode_dev(priv->head->device),
 		  dev->open_count);
 
-	if (priv->lock_count && dev->lock.hw_lock &&
-	    _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
-	    dev->lock.filp == filp) {
-		DRM_DEBUG("File %p released, freeing lock for context %d\n",
-			  filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
-		if (dev->driver->reclaim_buffers_locked)
+	if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
+		if (drm_i_have_hw_lock(filp)) {
 			dev->driver->reclaim_buffers_locked(dev, filp);
-
-		drm_lock_free(dev, &dev->lock.hw_lock->lock,
-			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
-		/* FIXME: may require heavy-handed reset of
-		   hardware at this point, possibly
-		   processed via a callback to the X
-		   server. */
-	} else if (dev->driver->reclaim_buffers_locked && priv->lock_count
-		   && dev->lock.hw_lock) {
-		/* The lock is required to reclaim buffers */
-		DECLARE_WAITQUEUE(entry, current);
-
-		add_wait_queue(&dev->lock.lock_queue, &entry);
-		for (;;) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			if (!dev->lock.hw_lock) {
-				/* Device has been unregistered */
-				retcode = -EINTR;
-				break;
+		} else {
+			unsigned long _end=jiffies + 3*DRM_HZ;
+			int locked = 0;
+
+			drm_idlelock_take(&dev->lock);
+
+			/*
+			 * Wait for a while.
+			 */
+
+			do{
+				spin_lock(&dev->lock.spinlock);
+				locked = dev->lock.idle_has_lock;
+				spin_unlock(&dev->lock.spinlock);
+				if (locked)
+					break;
+				schedule();
+			} while (!time_after_eq(jiffies, _end));
+
+			if (!locked) {
+				DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
+					  "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
+					  "\tI will go on reclaiming the buffers anyway.\n");
 			}
-			if (drm_lock_take(&dev->lock.hw_lock->lock,
-					  DRM_KERNEL_CONTEXT)) {
-				dev->lock.filp = filp;
-				dev->lock.lock_time = jiffies;
-				atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
-				break;	/* Got lock */
-			}
-			/* Contention */
-			schedule();
-			if (signal_pending(current)) {
-				retcode = -ERESTARTSYS;
-				break;
-			}
-		}
-		__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&dev->lock.lock_queue, &entry);
-		if (!retcode) {
+
 			dev->driver->reclaim_buffers_locked(dev, filp);
-			drm_lock_free(dev, &dev->lock.hw_lock->lock,
-				      DRM_KERNEL_CONTEXT);
+			drm_idlelock_release(&dev->lock);
 		}
 	}
 
+	if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
+
+		drm_idlelock_take(&dev->lock);
+		dev->driver->reclaim_buffers_idlelocked(dev, filp);
+		drm_idlelock_release(&dev->lock);
+
+	}
+
+	if (drm_i_have_hw_lock(filp)) {
+		DRM_DEBUG("File %p released, freeing lock for context %d\n",
+			  filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+		drm_lock_free(&dev->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	}
+
+
 	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
 	    !dev->driver->reclaim_buffers_locked) {
 		dev->driver->reclaim_buffers(dev, filp);
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
index a0b2d68..31acb62 100644
--- a/drivers/char/drm/drm_hashtab.c
+++ b/drivers/char/drm/drm_hashtab.c
@@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, u
 	ht->size = 1 << order;
 	ht->order = order;
 	ht->fill = 0;
-	ht->table = vmalloc(ht->size*sizeof(*ht->table));
+	ht->table = NULL;
+	ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE);
+	if (!ht->use_vmalloc) {
+		ht->table = drm_calloc(ht->size, sizeof(*ht->table),
+				       DRM_MEM_HASHTAB);
+	}
+	if (!ht->table) {
+		ht->use_vmalloc = 1;
+		ht->table = vmalloc(ht->size*sizeof(*ht->table));
+	}
 	if (!ht->table) {
 		DRM_ERROR("Out of memory for hash table\n");
 		return -ENOMEM;
@@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t *
 void drm_ht_remove(drm_open_hash_t *ht)
 {
 	if (ht->table) {
-		vfree(ht->table);
+		if (ht->use_vmalloc)
+			vfree(ht->table);
+		else
+			drm_free(ht->table, ht->size * sizeof(*ht->table),
+				 DRM_MEM_HASHTAB);
 		ht->table = NULL;
 	}
 }
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 40afec0..613091c 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -47,6 +47,7 @@ typedef struct drm_open_hash{
 	unsigned int order;
 	unsigned int fill;
 	struct hlist_head *table;
+	int use_vmalloc;
 } drm_open_hash_t;
 
 
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 9d00c51..2e75331 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -424,7 +424,7 @@ static void drm_locked_tasklet_func(unsi
 	spin_lock_irqsave(&dev->tasklet_lock, irqflags);
 
 	if (!dev->locked_tasklet_func ||
-	    !drm_lock_take(&dev->lock.hw_lock->lock,
+	    !drm_lock_take(&dev->lock,
 			   DRM_KERNEL_CONTEXT)) {
 		spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
 		return;
@@ -435,7 +435,7 @@ static void drm_locked_tasklet_func(unsi
 
 	dev->locked_tasklet_func(dev);
 
-	drm_lock_free(dev, &dev->lock.hw_lock->lock,
+	drm_lock_free(&dev->lock,
 		      DRM_KERNEL_CONTEXT);
 
 	dev->locked_tasklet_func = NULL;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index e9993ba..befd1af 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -35,9 +35,6 @@
 
 #include "drmP.h"
 
-static int drm_lock_transfer(drm_device_t * dev,
-			     __volatile__ unsigned int *lock,
-			     unsigned int context);
 static int drm_notifier(void *priv);
 
 /**
@@ -80,6 +77,9 @@ int drm_lock(struct inode *inode, struct
 			return -EINVAL;
 
 	add_wait_queue(&dev->lock.lock_queue, &entry);
+	spin_lock(&dev->lock.spinlock);
+	dev->lock.user_waiters++;
+	spin_unlock(&dev->lock.spinlock);
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!dev->lock.hw_lock) {
@@ -87,7 +87,7 @@ int drm_lock(struct inode *inode, struct
 			ret = -EINTR;
 			break;
 		}
-		if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
+		if (drm_lock_take(&dev->lock, lock.context)) {
 			dev->lock.filp = filp;
 			dev->lock.lock_time = jiffies;
 			atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
@@ -101,12 +101,14 @@ int drm_lock(struct inode *inode, struct
 			break;
 		}
 	}
+	spin_lock(&dev->lock.spinlock);
+	dev->lock.user_waiters--;
+	spin_unlock(&dev->lock.spinlock);
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->lock.lock_queue, &entry);
 
-	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
-	if (ret)
-		return ret;
+	DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+	if (ret) return ret;
 
 	sigemptyset(&dev->sigmask);
 	sigaddset(&dev->sigmask, SIGSTOP);
@@ -127,14 +129,12 @@ int drm_lock(struct inode *inode, struct
 		}
 	}
 
-	/* dev->driver->kernel_context_switch isn't used by any of the x86
-	 *  drivers but is used by the Sparc driver.
-	 */
 	if (dev->driver->kernel_context_switch &&
 	    dev->last_context != lock.context) {
 		dev->driver->kernel_context_switch(dev, dev->last_context,
 						   lock.context);
 	}
+
 	return 0;
 }
 
@@ -184,12 +184,8 @@ int drm_unlock(struct inode *inode, stru
 	if (dev->driver->kernel_context_switch_unlock)
 		dev->driver->kernel_context_switch_unlock(dev);
 	else {
-		drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
-				  DRM_KERNEL_CONTEXT);
-
-		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
-				  DRM_KERNEL_CONTEXT)) {
-			DRM_ERROR("\n");
+		if (drm_lock_free(&dev->lock,lock.context)) {
+			/* FIXME: Should really bail out here. */
 		}
 	}
 
@@ -206,18 +202,26 @@ int drm_unlock(struct inode *inode, stru
  *
  * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
  */
-int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_take(drm_lock_data_t *lock_data,
+		  unsigned int context)
 {
 	unsigned int old, new, prev;
+	volatile unsigned int *lock = &lock_data->hw_lock->lock;
 
+	spin_lock(&lock_data->spinlock);
 	do {
 		old = *lock;
 		if (old & _DRM_LOCK_HELD)
 			new = old | _DRM_LOCK_CONT;
-		else
-			new = context | _DRM_LOCK_HELD;
+		else {
+			new = context | _DRM_LOCK_HELD |
+				((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
+				 _DRM_LOCK_CONT : 0);
+		}
 		prev = cmpxchg(lock, old, new);
 	} while (prev != old);
+	spin_unlock(&lock_data->spinlock);
+
 	if (_DRM_LOCKING_CONTEXT(old) == context) {
 		if (old & _DRM_LOCK_HELD) {
 			if (context != DRM_KERNEL_CONTEXT) {
@@ -227,7 +231,8 @@ int drm_lock_take(__volatile__ unsigned 
 			return 0;
 		}
 	}
-	if (new == (context | _DRM_LOCK_HELD)) {
+
+	if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
 		/* Have lock */
 		return 1;
 	}
@@ -246,13 +251,13 @@ int drm_lock_take(__volatile__ unsigned 
  * Resets the lock file pointer.
  * Marks the lock as held by the given context, via the \p cmpxchg instruction.
  */
-static int drm_lock_transfer(drm_device_t * dev,
-			     __volatile__ unsigned int *lock,
+static int drm_lock_transfer(drm_lock_data_t *lock_data,
 			     unsigned int context)
 {
 	unsigned int old, new, prev;
+	volatile unsigned int *lock = &lock_data->hw_lock->lock;
 
-	dev->lock.filp = NULL;
+	lock_data->filp = NULL;
 	do {
 		old = *lock;
 		new = context | _DRM_LOCK_HELD;
@@ -272,23 +277,32 @@ static int drm_lock_transfer(drm_device_
  * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
  * waiting on the lock queue.
  */
-int drm_lock_free(drm_device_t * dev,
-		  __volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
 {
 	unsigned int old, new, prev;
+	volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+	spin_lock(&lock_data->spinlock);
+	if (lock_data->kernel_waiters != 0) {
+		drm_lock_transfer(lock_data, 0);
+		lock_data->idle_has_lock = 1;
+		spin_unlock(&lock_data->spinlock);
+		return 1;
+	}
+	spin_unlock(&lock_data->spinlock);
 
-	dev->lock.filp = NULL;
 	do {
 		old = *lock;
-		new = 0;
+		new = _DRM_LOCKING_CONTEXT(old);
 		prev = cmpxchg(lock, old, new);
 	} while (prev != old);
+
 	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
 		DRM_ERROR("%d freed heavyweight lock held by %d\n",
 			  context, _DRM_LOCKING_CONTEXT(old));
 		return 1;
 	}
-	wake_up_interruptible(&dev->lock.lock_queue);
+	wake_up_interruptible(&lock_data->lock_queue);
 	return 0;
 }
 
@@ -322,3 +336,67 @@ static int drm_notifier(void *priv)
 	} while (prev != old);
 	return 0;
 }
+
+/**
+ * This function returns immediately and takes the hw lock
+ * with the kernel context if it is free, otherwise it gets the highest priority when and if
+ * it is eventually released.
+ *
+ * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
+ * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
+ * a deadlock, which is why the "idlelock" was invented).
+ *
+ * This should be sufficient to wait for GPU idle without
+ * having to worry about starvation.
+ */
+
+void drm_idlelock_take(drm_lock_data_t *lock_data)
+{
+	int ret = 0;
+
+	spin_lock(&lock_data->spinlock);
+	lock_data->kernel_waiters++;
+	if (!lock_data->idle_has_lock) {
+
+		spin_unlock(&lock_data->spinlock);
+		ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
+		spin_lock(&lock_data->spinlock);
+
+		if (ret == 1)
+			lock_data->idle_has_lock = 1;
+	}
+	spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_take);
+
+void drm_idlelock_release(drm_lock_data_t *lock_data)
+{
+	unsigned int old, prev;
+	volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+	spin_lock(&lock_data->spinlock);
+	if (--lock_data->kernel_waiters == 0) {
+		if (lock_data->idle_has_lock) {
+			do {
+				old = *lock;
+				prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
+			} while (prev != old);
+			wake_up_interruptible(&lock_data->lock_queue);
+			lock_data->idle_has_lock = 0;
+		}
+	}
+	spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_release);
+
+
+int drm_i_have_hw_lock(struct file *filp)
+{
+	DRM_DEVICE;
+
+	return (priv->lock_count && dev->lock.hw_lock &&
+		_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+		dev->lock.filp == filp);
+}
+
+EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 9b46b85..2ec1d9f 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -274,7 +274,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned 
 	return drm_mm_create_tail_node(mm, start, size);
 }
 
-EXPORT_SYMBOL(drm_mm_init);
 
 void drm_mm_takedown(drm_mm_t * mm)
 {
@@ -295,4 +294,3 @@ void drm_mm_takedown(drm_mm_t * mm)
 	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 2908b72..0fe7b44 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -70,9 +70,6 @@ #define MTRR_TYPE_WRCOMB     1
 
 #endif
 
-/** Task queue handler arguments */
-#define DRM_TASKQUEUE_ARGS	void *arg
-
 /** For data going into the kernel through the ioctl argument */
 #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3)	\
 	if ( copy_from_user(&arg1, arg2, arg3) )	\
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index ad54b84..31cdde8 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -102,6 +102,7 @@ #define radeon_PCI_IDS \
 	{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, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
 	{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}, \
@@ -230,10 +231,10 @@ #define viadrv_PCI_IDS \
 	{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, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
+	{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
 	{0, 0, 0}
 
 #define i810_PCI_IDS \
@@ -296,5 +297,6 @@ #define i915_PCI_IDS \
 	{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}, \
+	{0x8086, 0x2a02, 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 7fd0da7..b204498 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -72,7 +72,7 @@ #if DRM_DEBUG_CODE
 #endif
 };
 
-#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
 
 /**
  * Initialize the DRI proc filesystem for a device.
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 120d102..19408ad 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t 
 	spin_lock_init(&dev->count_lock);
 	spin_lock_init(&dev->drw_lock);
 	spin_lock_init(&dev->tasklet_lock);
+	spin_lock_init(&dev->lock.spinlock);
 	init_timer(&dev->timer);
 	mutex_init(&dev->struct_mutex);
 	mutex_init(&dev->ctxlist_mutex);
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 54a6328..35540cf 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -41,6 +41,30 @@ #endif
 static void drm_vm_open(struct vm_area_struct *vma);
 static void drm_vm_close(struct vm_area_struct *vma);
 
+static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
+{
+	pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
+
+#if defined(__i386__) || defined(__x86_64__)
+	if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) {
+		pgprot_val(tmp) |= _PAGE_PCD;
+		pgprot_val(tmp) &= ~_PAGE_PWT;
+	}
+#elif defined(__powerpc__)
+	pgprot_val(tmp) |= _PAGE_NO_CACHE;
+	if (map_type == _DRM_REGISTERS)
+		pgprot_val(tmp) |= _PAGE_GUARDED;
+#endif
+#if defined(__ia64__)
+	if (efi_range_is_wc(vma->vm_start, vma->vm_end -
+				    vma->vm_start))
+		tmp = pgprot_writecombine(tmp);
+	else
+		tmp = pgprot_noncached(tmp);
+#endif
+	return tmp;
+}
+
 /**
  * \c nopage method for AGP virtual memory.
  *
@@ -151,8 +175,7 @@ static __inline__ struct page *drm_do_vm
 
 	offset = address - vma->vm_start;
 	i = (unsigned long)map->handle + offset;
-	page = (map->type == _DRM_CONSISTENT) ?
-		virt_to_page((void *)i) : vmalloc_to_page((void *)i);
+	page = vmalloc_to_page((void *)i);
 	if (!page)
 		return NOPAGE_SIGBUS;
 	get_page(page);
@@ -389,7 +412,7 @@ static struct vm_operations_struct drm_v
  * Create a new drm_vma_entry structure as the \p vma private data entry and
  * add it to drm_device::vmalist.
  */
-static void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open_locked(struct vm_area_struct *vma)
 {
 	drm_file_t *priv = vma->vm_file->private_data;
 	drm_device_t *dev = priv->head->dev;
@@ -401,15 +424,23 @@ static void drm_vm_open(struct vm_area_s
 
 	vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
 	if (vma_entry) {
-		mutex_lock(&dev->struct_mutex);
 		vma_entry->vma = vma;
 		vma_entry->next = dev->vmalist;
 		vma_entry->pid = current->pid;
 		dev->vmalist = vma_entry;
-		mutex_unlock(&dev->struct_mutex);
 	}
 }
 
+static void drm_vm_open(struct vm_area_struct *vma)
+{
+	drm_file_t *priv = vma->vm_file->private_data;
+	drm_device_t *dev = priv->head->dev;
+
+	mutex_lock(&dev->struct_mutex);
+	drm_vm_open_locked(vma);
+	mutex_unlock(&dev->struct_mutex);
+}
+
 /**
  * \c close method for all virtual memory types.
  *
@@ -460,7 +491,6 @@ static int drm_mmap_dma(struct file *fil
 	drm_device_dma_t *dma;
 	unsigned long length = vma->vm_end - vma->vm_start;
 
-	lock_kernel();
 	dev = priv->head->dev;
 	dma = dev->dma;
 	DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -468,10 +498,8 @@ static int drm_mmap_dma(struct file *fil
 
 	/* Length must match exact page count */
 	if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
-		unlock_kernel();
 		return -EINVAL;
 	}
-	unlock_kernel();
 
 	if (!capable(CAP_SYS_ADMIN) &&
 	    (dma->flags & _DRM_DMA_USE_PCI_RO)) {
@@ -494,7 +522,7 @@ #endif
 	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
 
 	vma->vm_file = filp;	/* Needed for drm_vm_open() */
-	drm_vm_open(vma);
+	drm_vm_open_locked(vma);
 	return 0;
 }
 
@@ -529,7 +557,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
  * according to the mapping type and remaps the pages. Finally sets the file
  * pointer and calls vm_open().
  */
-int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->head->dev;
@@ -565,7 +593,7 @@ #endif
 		return -EPERM;
 
 	/* Check for valid size. */
-	if (map->size != vma->vm_end - vma->vm_start)
+	if (map->size < vma->vm_end - vma->vm_start)
 		return -EINVAL;
 
 	if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
@@ -600,37 +628,16 @@ #endif
 		/* fall through to _DRM_FRAME_BUFFER... */
 	case _DRM_FRAME_BUFFER:
 	case _DRM_REGISTERS:
-#if defined(__i386__) || defined(__x86_64__)
-		if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
-			pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-			pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
-		}
-#elif defined(__powerpc__)
-		pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-		if (map->type == _DRM_REGISTERS)
-			pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
-#endif
-		vma->vm_flags |= VM_IO;	/* not in core dump */
-#if defined(__ia64__)
-		if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
-			vma->vm_page_prot =
-			    pgprot_writecombine(vma->vm_page_prot);
-		else
-			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
 		offset = dev->driver->get_reg_ofs(dev);
+		vma->vm_flags |= VM_IO;	/* not in core dump */
+		vma->vm_page_prot = drm_io_prot(map->type, vma);
 #ifdef __sparc__
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
 		if (io_remap_pfn_range(vma, vma->vm_start,
 				       (map->offset + offset) >> PAGE_SHIFT,
 				       vma->vm_end - vma->vm_start,
 				       vma->vm_page_prot))
-#else
-		if (io_remap_pfn_range(vma, vma->vm_start,
-				       (map->offset + offset) >> PAGE_SHIFT,
-				       vma->vm_end - vma->vm_start,
-				       vma->vm_page_prot))
-#endif
 			return -EAGAIN;
 		DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
 			  " offset = 0x%lx\n",
@@ -638,10 +645,15 @@ #endif
 			  vma->vm_start, vma->vm_end, map->offset + offset);
 		vma->vm_ops = &drm_vm_ops;
 		break;
-	case _DRM_SHM:
 	case _DRM_CONSISTENT:
-		/* Consistent memory is really like shared memory. It's only
-		 * allocate in a different way */
+		/* Consistent memory is really like shared memory. But
+		 * it's allocated in a different way, so avoid nopage */
+		if (remap_pfn_range(vma, vma->vm_start,
+		    page_to_pfn(virt_to_page(map->handle)),
+		    vma->vm_end - vma->vm_start, vma->vm_page_prot))
+			return -EAGAIN;
+	/* fall through to _DRM_SHM */
+	case _DRM_SHM:
 		vma->vm_ops = &drm_vm_shm_ops;
 		vma->vm_private_data = (void *)map;
 		/* Don't let this area swap.  Change when
@@ -659,8 +671,20 @@ #endif
 	vma->vm_flags |= VM_RESERVED;	/* Don't swap */
 
 	vma->vm_file = filp;	/* Needed for drm_vm_open() */
-	drm_vm_open(vma);
+	drm_vm_open_locked(vma);
 	return 0;
 }
 
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->head->dev;
+	int ret;
+
+	mutex_lock(&dev->struct_mutex);
+	ret = drm_mmap_locked(filp, vma);
+	mutex_unlock(&dev->struct_mutex);
+
+	return ret;
+}
 EXPORT_SYMBOL(drm_mmap);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9354ce3..1ba15d9 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -34,7 +34,8 @@ #include "i915_drv.h"
 #define IS_I965G(dev) (dev->pci_device == 0x2972 || \
 		       dev->pci_device == 0x2982 || \
 		       dev->pci_device == 0x2992 || \
-		       dev->pci_device == 0x29A2)
+		       dev->pci_device == 0x29A2 || \
+		       dev->pci_device == 0x2A02)
 
 /* 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
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index db5a604..1014602 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -560,9 +560,10 @@ #if __OS_HAS_AGP
 	if (dev_priv->is_pci) {
 #endif
 		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
+		dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
 		dev_priv->gart_info.addr = NULL;
 		dev_priv->gart_info.bus_addr = 0;
-		dev_priv->gart_info.is_pcie = 0;
+		dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
 		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
 			DRM_ERROR("failed to init PCI GART!\n");
 			dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index f1efb49..9086835 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -383,6 +383,8 @@ #define R128_RING_HIGH_MARK		128
 
 #define R128_PERFORMANCE_BOXES		0
 
+#define R128_PCIGART_TABLE_SIZE         32768
+
 #define R128_READ(reg)		DRM_READ32(  dev_priv->mmio, (reg) )
 #define R128_WRITE(reg,val)	DRM_WRITE32( dev_priv->mmio, (reg), (val) )
 #define R128_READ8(reg)		DRM_READ8(   dev_priv->mmio, (reg) )
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5ed9656..6833838 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_p
 	return RADEON_READ(RADEON_PCIE_DATA);
 }
 
+static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
+{
+	u32 ret;
+	RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f);
+	ret = RADEON_READ(RADEON_IGPGART_DATA);
+	RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f);
+	return ret;
+}
+
 #if RADEON_FIFO_DEBUG
 static void radeon_status(drm_radeon_private_t * dev_priv)
 {
@@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_ra
 	}
 }
 
-/* Enable or disable PCI-E GART on the chip */
+/* Enable or disable IGP GART on the chip */
+static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
+{
+	u32 temp, tmp;
+
+	tmp = RADEON_READ(RADEON_AIC_CNTL);
+	if (on) {
+		DRM_DEBUG("programming igpgart %08X %08lX %08X\n",
+			 dev_priv->gart_vm_start,
+			 (long)dev_priv->gart_info.bus_addr,
+			 dev_priv->gart_size);
+
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR,
+				     dev_priv->gart_info.bus_addr);
+
+		temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp);
+
+		RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
+		dev_priv->gart_size = 32*1024*1024;
+		RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+			     (((dev_priv->gart_vm_start - 1 +
+			       dev_priv->gart_size) & 0xffff0000) |
+			     (dev_priv->gart_vm_start >> 16)));
+
+		temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp);
+
+		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
+		RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+		RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
+       }
+}
+
 static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
 {
 	u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeo
 {
 	u32 tmp;
 
+	if (dev_priv->flags & RADEON_IS_IGPGART) {
+		radeon_set_igpgart(dev_priv, on);
+		return;
+	}
+
 	if (dev_priv->flags & RADEON_IS_PCIE) {
 		radeon_set_pciegart(dev_priv, on);
 		return;
@@ -1560,8 +1611,8 @@ #if __OS_HAS_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 &&
-			    base < (dev_priv->fb_location + dev_priv->fb_size)) {
+			if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
+			    base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
 				DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
 					 dev->agp->base);
 				base = 0;
@@ -1571,8 +1622,8 @@ #endif
 		/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
 		if (base == 0) {
 			base = dev_priv->fb_location + dev_priv->fb_size;
-			if (((base + dev_priv->gart_size) & 0xfffffffful)
-			    < base)
+			if (base < dev_priv->fb_location ||
+			    ((base + dev_priv->gart_size) & 0xfffffffful) < base)
 				base = dev_priv->fb_location
 					- dev_priv->gart_size;
 		}		
@@ -1620,20 +1671,22 @@ #if __OS_HAS_AGP
 #endif
 	{
 		/* if we have an offset set from userspace */
-		if (dev_priv->pcigart_offset) {
+		if (dev_priv->pcigart_offset_set) {
 			dev_priv->gart_info.bus_addr =
 			    dev_priv->pcigart_offset + dev_priv->fb_location;
 			dev_priv->gart_info.mapping.offset =
 			    dev_priv->gart_info.bus_addr;
 			dev_priv->gart_info.mapping.size =
-			    RADEON_PCIGART_TABLE_SIZE;
+			    dev_priv->gart_info.table_size;
 
 			drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
 			dev_priv->gart_info.addr =
 			    dev_priv->gart_info.mapping.handle;
 
-			dev_priv->gart_info.is_pcie =
-			    !!(dev_priv->flags & RADEON_IS_PCIE);
+			if (dev_priv->flags & RADEON_IS_PCIE)
+				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE;
+			else
+				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
 			dev_priv->gart_info.gart_table_location =
 			    DRM_ATI_GART_FB;
 
@@ -1641,6 +1694,10 @@ #endif
 				  dev_priv->gart_info.addr,
 				  dev_priv->pcigart_offset);
 		} else {
+			if (dev_priv->flags & RADEON_IS_IGPGART)
+				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP;
+			else
+				dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
 			dev_priv->gart_info.gart_table_location =
 			    DRM_ATI_GART_MAIN;
 			dev_priv->gart_info.addr = NULL;
@@ -1714,7 +1771,7 @@ #endif
 		if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
 		{
 			drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
-			dev_priv->gart_info.addr = NULL;
+			dev_priv->gart_info.addr = 0;
 		}
 	}
 	/* only clear to the start of flags */
@@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_d
 	drm_local_map_t *map;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 
+	dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+
 	ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
 			 drm_get_resource_len(dev, 2), _DRM_REGISTERS,
 			 _DRM_READ_ONLY, &dev_priv->mmio);
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index 8d6350d..66c4b6f 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -707,6 +707,7 @@ #define RADEON_SETPARAM_FB_LOCATION    1
 #define RADEON_SETPARAM_SWITCH_TILING  2	/* enable/disable color tiling */
 #define RADEON_SETPARAM_PCIGART_LOCATION 3	/* PCI Gart Location */
 #define RADEON_SETPARAM_NEW_MEMMAP 4		/* Use new memory map */
+#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5    /* PCI GART Table Size */
 
 /* 1.14: Clients can allocate/free a surface
  */
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 8b105f1..54f49ef 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -95,9 +95,11 @@ #define DRIVER_DATE		"20060524"
  * 1.24- Add general-purpose packet for manipulating scratch registers (r300)
  * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
  *       new packet type)
+ * 1.26- Add support for variable size PCI(E) gart aperture
+ * 1.27- Add support for IGP GART
  */
 #define DRIVER_MAJOR		1
-#define DRIVER_MINOR		25
+#define DRIVER_MINOR		27
 #define DRIVER_PATCHLEVEL	0
 
 /*
@@ -143,6 +145,7 @@ enum radeon_chip_flags {
 	RADEON_IS_PCIE = 0x00200000UL,
 	RADEON_NEW_MEMMAP = 0x00400000UL,
 	RADEON_IS_PCI = 0x00800000UL,
+	RADEON_IS_IGPGART = 0x01000000UL,
 };
 
 #define GET_RING_HEAD(dev_priv)	(dev_priv->writeback_works ? \
@@ -240,7 +243,6 @@ typedef struct drm_radeon_private {
 
 	int do_boxes;
 	int page_flipping;
-	int current_page;
 
 	u32 color_fmt;
 	unsigned int front_offset;
@@ -280,6 +282,7 @@ typedef struct drm_radeon_private {
 	struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
 
 	unsigned long pcigart_offset;
+	unsigned int pcigart_offset_set;
 	drm_ati_pcigart_info gart_info;
 
 	u32 scratch_ages[5];
@@ -432,6 +435,15 @@ #define RADEON_PCIE_TX_GART_START_HI	0x1
 #define RADEON_PCIE_TX_GART_END_LO	0x16
 #define RADEON_PCIE_TX_GART_END_HI	0x17
 
+#define RADEON_IGPGART_INDEX            0x168
+#define RADEON_IGPGART_DATA             0x16c
+#define RADEON_IGPGART_UNK_18           0x18
+#define RADEON_IGPGART_CTRL             0x2b
+#define RADEON_IGPGART_BASE_ADDR        0x2c
+#define RADEON_IGPGART_FLUSH            0x2e
+#define RADEON_IGPGART_ENABLE           0x38
+#define RADEON_IGPGART_UNK_39           0x39
+
 #define RADEON_MPP_TB_CONFIG		0x01c0
 #define RADEON_MEM_CNTL			0x0140
 #define RADEON_MEM_SDRAM_MODE_REG	0x0158
@@ -964,6 +976,14 @@ do {									\
 	RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) );			\
 } while (0)
 
+#define RADEON_WRITE_IGPGART( addr, val )				\
+do {									\
+	RADEON_WRITE( RADEON_IGPGART_INDEX,				\
+			((addr) & 0x7f) | (1 << 8));			\
+	RADEON_WRITE( RADEON_IGPGART_DATA, (val) );			\
+	RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f );			\
+} while (0)
+
 #define RADEON_WRITE_PCIE( addr, val )					\
 do {									\
 	RADEON_WRITE8( RADEON_PCIE_INDEX,				\
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 938eccb..98c5f1d 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_
 		 RADEON_GMC_SRC_DATATYPE_COLOR |
 		 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
 
-	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+	if (dev_priv->sarea_priv->pfCurrentPage == 1) {
 		OUT_RING(dev_priv->front_pitch_offset);
 	} else {
 		OUT_RING(dev_priv->back_pitch_offset);
@@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm
 
 	dev_priv->stats.clears++;
 
-	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+	if (dev_priv->sarea_priv->pfCurrentPage == 1) {
 		unsigned int tmp = flags;
 
 		flags &= ~(RADEON_FRONT | RADEON_BACK);
@@ -1382,7 +1382,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) {
+		if (dev_priv->sarea_priv->pfCurrentPage == 0) {
 			OUT_RING(dev_priv->back_pitch_offset);
 			OUT_RING(dev_priv->front_pitch_offset);
 		} else {
@@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
-	int offset = (dev_priv->current_page == 1)
+	int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
 	    ? dev_priv->front_offset : dev_priv->back_offset;
 	RING_LOCALS;
-	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
+	DRM_DEBUG("%s: pfCurrentPage=%d\n",
 		  __FUNCTION__,
-		  dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
+		  dev_priv->sarea_priv->pfCurrentPage);
 
 	/* Do some trivial performance monitoring...
 	 */
@@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_
 	 * performing the swapbuffer ioctl.
 	 */
 	dev_priv->sarea_priv->last_frame++;
-	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
-	    1 - dev_priv->current_page;
+	dev_priv->sarea_priv->pfCurrentPage =
+		1 - dev_priv->sarea_priv->pfCurrentPage;
 
 	BEGIN_RING(2);
 
@@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_d
 	ADVANCE_RING();
 
 	dev_priv->page_flipping = 1;
-	dev_priv->current_page = 0;
-	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
 
-	return 0;
-}
-
-/* Called whenever a client dies, from drm_release.
- * NOTE:  Lock isn't necessarily held when this is called!
- */
-static int radeon_do_cleanup_pageflip(drm_device_t * dev)
-{
-	drm_radeon_private_t *dev_priv = dev->dev_private;
-	DRM_DEBUG("\n");
-
-	if (dev_priv->current_page != 0)
-		radeon_cp_dispatch_flip(dev);
+	if (dev_priv->sarea_priv->pfCurrentPage != 1)
+		dev_priv->sarea_priv->pfCurrentPage = 0;
 
-	dev_priv->page_flipping = 0;
 	return 0;
 }
 
@@ -3145,10 +3131,16 @@ static int radeon_cp_setparam(DRM_IOCTL_
 		break;
 	case RADEON_SETPARAM_PCIGART_LOCATION:
 		dev_priv->pcigart_offset = sp.value;
+		dev_priv->pcigart_offset_set = 1;
 		break;
 	case RADEON_SETPARAM_NEW_MEMMAP:
 		dev_priv->new_memmap = sp.value;
 		break;
+	case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
+		dev_priv->gart_info.table_size = sp.value;
+		if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
+			dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+		break;
 	default:
 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
 		return DRM_ERR(EINVAL);
@@ -3168,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t
 {
 	if (dev->dev_private) {
 		drm_radeon_private_t *dev_priv = dev->dev_private;
-		if (dev_priv->page_flipping) {
-			radeon_do_cleanup_pageflip(dev);
-		}
+		dev_priv->page_flipping = 0;
 		radeon_mem_release(filp, dev_priv->gart_heap);
 		radeon_mem_release(filp, dev_priv->fb_heap);
 		radeon_surfaces_release(filp, dev_priv);
@@ -3179,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t
 
 void radeon_driver_lastclose(drm_device_t * dev)
 {
+	if (dev->dev_private) {
+		drm_radeon_private_t *dev_priv = dev->dev_private;
+
+		if (dev_priv->sarea_priv &&
+		    dev_priv->sarea_priv->pfCurrentPage != 0)
+			radeon_cp_dispatch_flip(dev);
+	}
+
 	radeon_do_release(dev);
 }
 
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 3d5b321..690e0af 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -71,7 +71,7 @@ static struct drm_driver driver = {
 	.context_dtor = NULL,
 	.dma_quiescent = sis_idle,
 	.reclaim_buffers = NULL,
-	.reclaim_buffers_locked = sis_reclaim_buffers_locked,
+	.reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
 	.lastclose = sis_lastclose,
 	.get_map_ofs = drm_core_get_map_ofs,
 	.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index c0539c6..13a9c5c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
 		break;
 	case VIA_DMA_INITIALIZED:
 		retcode = (dev_priv->ring.virtual_start != NULL) ?
-		    0 : DRM_ERR(EFAULT);
+			0 : DRM_ERR(EFAULT);
 		break;
 	default:
 		retcode = DRM_ERR(EINVAL);
@@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_priv
 {
 	int paused, count;
 	volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
+	uint32_t reader,ptr;
 
+	paused = 0;
 	via_flush_write_combine();
-	while (!*(via_get_dma(dev_priv) - 1)) ;
-	*dev_priv->last_pause_ptr = pause_addr_lo;
+	(void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
+	*paused_at = pause_addr_lo;
 	via_flush_write_combine();
-
-	/*
-	 * The below statement is inserted to really force the flush.
-	 * Not sure it is needed.
-	 */
-
-	while (!*dev_priv->last_pause_ptr) ;
+	(void) *paused_at;
+	reader = *(dev_priv->hw_addr_ptr);
+	ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
+		dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
 	dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
-	while (!*dev_priv->last_pause_ptr) ;
 
-	paused = 0;
-	count = 20;
-
-	while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
-	if ((count <= 8) && (count >= 0)) {
-		uint32_t rgtr, ptr;
-		rgtr = *(dev_priv->hw_addr_ptr);
-		ptr = ((volatile char *)dev_priv->last_pause_ptr -
-		      dev_priv->dma_ptr) + dev_priv->dma_offset +
-		      (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
-		if (rgtr <= ptr) {
-			DRM_ERROR
-			    ("Command regulator\npaused at count %d, address %x, "
-			     "while current pause address is %x.\n"
-			     "Please mail this message to "
-			     "<unichrome-devel@lists.sourceforge.net>\n", count,
-			     rgtr, ptr);
-		}
+	if ((ptr - reader) <= dev_priv->dma_diff ) {
+		count = 10000000;
+		while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
 	}
 
 	if (paused && !no_pci_fire) {
-		uint32_t rgtr, ptr;
-		uint32_t ptr_low;
+		reader = *(dev_priv->hw_addr_ptr);
+		if ((ptr - reader) == dev_priv->dma_diff) {
 
-		count = 1000000;
-		while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)
-		       && count--) ;
+			/*
+			 * There is a concern that these writes may stall the PCI bus
+			 * if the GPU is not idle. However, idling the GPU first
+			 * doesn't make a difference.
+			 */
 
-		rgtr = *(dev_priv->hw_addr_ptr);
-		ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
-		    dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
-		ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
-		    ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
-		if (rgtr <= ptr && rgtr >= ptr_low) {
 			VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
 			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
 			VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
@@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_priv
 static int via_wait_idle(drm_via_private_t * dev_priv)
 {
 	int count = 10000000;
+
+	while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--);
+
 	while (count-- && (VIA_READ(VIA_REG_STATUS) &
 			   (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
 			    VIA_3D_ENG_BUSY))) ;
@@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_pri
 	uint32_t end_addr, end_addr_lo;
 	uint32_t command;
 	uint32_t agp_base;
+	uint32_t ptr;
+	uint32_t reader;
+	int count;
 
 	dev_priv->dma_low = 0;
 
@@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_pri
 			  &pause_addr_hi, &pause_addr_lo, 1) - 1;
 
 	via_flush_write_combine();
-	while (!*dev_priv->last_pause_ptr) ;
+	(void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
 
 	VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
 	VIA_WRITE(VIA_REG_TRANSPACE, command);
@@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_pri
 	DRM_WRITEMEMORYBARRIER();
 	VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
 	VIA_READ(VIA_REG_TRANSPACE);
+
+	dev_priv->dma_diff = 0;
+
+	count = 10000000;
+	while (!(VIA_READ(0x41c) & 0x80000000) && count--);
+
+	reader = *(dev_priv->hw_addr_ptr);
+	ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
+	    dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
+	/*
+	 * This is the difference between where we tell the
+	 * command reader to pause and where it actually pauses.
+	 * This differs between hw implementation so we need to
+	 * detect it.
+	 */
+
+	dev_priv->dma_diff = ptr - reader;
 }
 
 static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
@@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_priv
 	uint32_t pause_addr_lo, pause_addr_hi;
 	uint32_t jump_addr_lo, jump_addr_hi;
 	volatile uint32_t *last_pause_ptr;
-	uint32_t dma_low_save1, dma_low_save2;
 
 	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
 	via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
@@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_priv
 		      &pause_addr_lo, 0);
 
 	*last_pause_ptr = pause_addr_lo;
-	dma_low_save1 = dev_priv->dma_low;
-
-	/*
-	 * Now, set a trap that will pause the regulator if it tries to rerun the old
-	 * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
-	 * and reissues the jump command over PCI, while the regulator has already taken the jump
-	 * and actually paused at the current buffer end).
-	 * There appears to be no other way to detect this condition, since the hw_addr_pointer
-	 * does not seem to get updated immediately when a jump occurs.
-	 */
 
-	last_pause_ptr =
-	    via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
-			  &pause_addr_lo, 0) - 1;
-	via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
-		      &pause_addr_lo, 0);
-	*last_pause_ptr = pause_addr_lo;
-
-	dma_low_save2 = dev_priv->dma_low;
-	dev_priv->dma_low = dma_low_save1;
-	via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
-	dev_priv->dma_low = dma_low_save2;
-	via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
+	via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
 }
 
+
 static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
 {
 	via_cmdbuf_jump(dev_priv);
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index bb9dde8..2d4957a 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -52,7 +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,
+	.reclaim_buffers_locked = NULL,
+	.reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
 	.lastclose = via_lastclose,
 	.get_map_ofs = drm_core_get_map_ofs,
 	.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 8b8778d..b46ca8e 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,11 +29,11 @@ #define DRIVER_AUTHOR	"Various"
 
 #define DRIVER_NAME		"via"
 #define DRIVER_DESC		"VIA Unichrome / Pro"
-#define DRIVER_DATE		"20061227"
+#define DRIVER_DATE		"20070202"
 
 #define DRIVER_MAJOR		2
 #define DRIVER_MINOR		11
-#define DRIVER_PATCHLEVEL	0
+#define DRIVER_PATCHLEVEL	1
 
 #include "via_verifier.h"
 
@@ -93,6 +93,7 @@ typedef struct drm_via_private {
 	unsigned long vram_offset;
 	unsigned long agp_offset;
 	drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
+	uint32_t dma_diff;
 } drm_via_private_t;
 
 enum via_family {
diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h
deleted file mode 100644
index d57efda..0000000
--- a/drivers/char/drm/via_mm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#ifndef _via_drm_mm_h_
-#define _via_drm_mm_h_
-
-typedef struct {
-	unsigned int context;
-	unsigned int size;
-	unsigned long offset;
-	unsigned long free;
-} drm_via_mm_t;
-
-typedef struct {
-	unsigned int size;
-	unsigned long handle;
-	void *virtual;
-} drm_via_dma_t;
-
-#endif
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 3d7efc2..334ad5b 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -4,7 +4,6 @@
  */
 #include <linux/module.h>
 #include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/capability.h>
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index db984e4..9b8278e 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -32,7 +32,6 @@ #include <linux/delay.h>	/* guess what *
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 
 #include <asm/atarihw.h>
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index d8dbdb9..abde6dd 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -62,7 +62,6 @@ #include <linux/wait.h>		/* for wait_que
 #include <linux/init.h>		/* for __init, module_{init,exit} */
 #include <linux/poll.h>		/* for POLLIN, etc. */
 #include <linux/dtlk.h>		/* local header file for DoubleTalk values */
-#include <linux/smp_lock.h>
 
 #ifdef TRACING
 #define TRACE_TEXT(str) printk(str);
@@ -325,16 +324,22 @@ static int dtlk_release(struct inode *in
 
 static int __init dtlk_init(void)
 {
+	int err;
+
 	dtlk_port_lpc = 0;
 	dtlk_port_tts = 0;
 	dtlk_busy = 0;
 	dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
-	if (dtlk_major == 0) {
+	if (dtlk_major < 0) {
 		printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
-		return 0;
+		return dtlk_major;
+	}
+	err = dtlk_dev_probe();
+	if (err) {
+		unregister_chrdev(dtlk_major, "dtlk");
+		return err;
 	}
-	if (dtlk_dev_probe() == 0)
-		printk(", MAJOR %d\n", dtlk_major);
+	printk(", MAJOR %d\n", dtlk_major);
 
 	init_waitqueue_head(&dtlk_process_list);
 
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
index 77f58ed..0200114 100644
--- a/drivers/char/ec3104_keyb.c
+++ b/drivers/char/ec3104_keyb.c
@@ -41,7 +41,6 @@ #include <linux/poll.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/kbd_kern.h>
-#include <linux/smp_lock.h>
 #include <linux/bitops.h>
 
 #include <asm/keyboard.h>
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index de5be30..c6c56fb 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -949,7 +949,7 @@ static int block_til_ready(struct tty_st
 
 	} /* End forever while  */
 
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&ch->open_wait, &wait);
 	if (!tty_hung_up_p(filp))
 		ch->count++;
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 23b25ad..49f914e 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -207,7 +207,7 @@ static ssize_t gen_rtc_read(struct file 
 			sizeof(unsigned long);
 	}
  out:
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&gen_rtc_wait, &wait);
 
 	return retval;
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index ae76a9f..f0e7263 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -44,7 +44,6 @@ #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/reboot.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index a0a88aa..322bc5f 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -47,8 +47,6 @@ #include "hvc_console.h"
 #define HVC_MAJOR	229
 #define HVC_MINOR	0
 
-#define TIMEOUT		(10)
-
 /*
  * Wait this long per iteration while trying to push buffered data to the
  * hypervisor before allowing the tty to complete a close operation.
@@ -104,16 +102,16 @@ static DEFINE_SPINLOCK(hvc_structs_lock)
 /*
  * This value is used to assign a tty->index value to a hvc_struct based
  * upon order of exposure via hvc_probe(), when we can not match it to
- * a console canidate registered with hvc_instantiate().
+ * a console candidate registered with hvc_instantiate().
  */
 static int last_hvc = -1;
 
 /*
- * Do not call this function with either the hvc_strucst_lock or the hvc_struct
+ * Do not call this function with either the hvc_structs_lock or the hvc_struct
  * lock held.  If successful, this function increments the kobject reference
  * count against the target hvc_struct so it should be released when finished.
  */
-struct hvc_struct *hvc_get_by_index(int index)
+static struct hvc_struct *hvc_get_by_index(int index)
 {
 	struct hvc_struct *hp;
 	unsigned long flags;
@@ -152,7 +150,8 @@ static uint32_t vtermnos[MAX_NR_HVC_CONS
  * hvc_console_setup() finds adapters.
  */
 
-void hvc_console_print(struct console *co, const char *b, unsigned count)
+static void hvc_console_print(struct console *co, const char *b,
+			      unsigned count)
 {
 	char c[N_OUTBUF] __ALIGNED__;
 	unsigned i = 0, n = 0;
@@ -162,7 +161,7 @@ void hvc_console_print(struct console *c
 	if (index >= MAX_NR_HVC_CONSOLES)
 		return;
 
-	/* This console adapter was removed so it is not useable. */
+	/* This console adapter was removed so it is not usable. */
 	if (vtermnos[index] < 0)
 		return;
 
@@ -210,7 +209,7 @@ static int __init hvc_console_setup(stru
 	return 0;
 }
 
-struct console hvc_con_driver = {
+static struct console hvc_con_driver = {
 	.name		= "hvc",
 	.write		= hvc_console_print,
 	.device		= hvc_console_device,
@@ -220,7 +219,7 @@ struct console hvc_con_driver = {
 };
 
 /*
- * Early console initialization.  Preceeds driver initialization.
+ * Early console initialization.  Precedes driver initialization.
  *
  * (1) we are first, and the user specified another driver
  * -- index will remain -1
@@ -257,7 +256,7 @@ int hvc_instantiate(uint32_t vtermno, in
 	if (vtermnos[index] != -1)
 		return -1;
 
-	/* make sure no no tty has been registerd in this index */
+	/* make sure no no tty has been registered in this index */
 	hp = hvc_get_by_index(index);
 	if (hp) {
 		kobject_put(&hp->kobj);
@@ -267,7 +266,7 @@ int hvc_instantiate(uint32_t vtermno, in
 	vtermnos[index] = vtermno;
 	cons_ops[index] = ops;
 
-	/* reserve all indices upto and including this index */
+	/* reserve all indices up to and including this index */
 	if (last_hvc < index)
 		last_hvc = index;
 
@@ -280,7 +279,6 @@ int hvc_instantiate(uint32_t vtermno, in
 
 	return 0;
 }
-EXPORT_SYMBOL(hvc_instantiate);
 
 /* Wake the sleeping khvcd */
 static void hvc_kick(void)
@@ -528,7 +526,7 @@ static int hvc_write(struct tty_struct *
 
 /*
  * This is actually a contract between the driver and the tty layer outlining
- * how much write room the driver can guarentee will be sent OR BUFFERED.  This
+ * how much write room the driver can guarantee will be sent OR BUFFERED.  This
  * driver MUST honor the return value.
  */
 static int hvc_write_room(struct tty_struct *tty)
@@ -550,6 +548,18 @@ static int hvc_chars_in_buffer(struct tt
 	return hp->n_outbuf;
 }
 
+/*
+ * timeout will vary between the MIN and MAX values defined here.  By default
+ * and during console activity we will use a default MIN_TIMEOUT of 10.  When
+ * the console is idle, we increase the timeout value on each pass through
+ * msleep until we reach the max.  This may be noticeable as a brief (average
+ * one second) delay on the console before the console responds to input when
+ * there has been no input for some time.
+ */
+#define MIN_TIMEOUT		(10)
+#define MAX_TIMEOUT		(2000)
+static u32 timeout = MIN_TIMEOUT;
+
 #define HVC_POLL_READ	0x00000001
 #define HVC_POLL_WRITE	0x00000002
 
@@ -642,9 +652,14 @@ #endif /* CONFIG_MAGIC_SYSRQ */
  bail:
 	spin_unlock_irqrestore(&hp->lock, flags);
 
-	if (read_total)
+	if (read_total) {
+		/* Activity is occurring, so reset the polling backoff value to
+		   a minimum for performance. */
+		timeout = MIN_TIMEOUT;
+
 		tty_flip_buffer_push(tty);
-	
+	}
+
 	return poll_mask;
 }
 
@@ -688,8 +703,12 @@ int khvcd(void *unused)
 		if (!hvc_kicked) {
 			if (poll_mask == 0)
 				schedule();
-			else
-				msleep_interruptible(TIMEOUT);
+			else {
+				if (timeout < MAX_TIMEOUT)
+					timeout += (timeout >> 6) + 1;
+
+				msleep_interruptible(timeout);
+			}
 		}
 		__set_current_state(TASK_RUNNING);
 	} while (!kthread_should_stop());
@@ -773,7 +792,6 @@ struct hvc_struct __devinit *hvc_alloc(u
 
 	return hp;
 }
-EXPORT_SYMBOL(hvc_alloc);
 
 int __devexit hvc_remove(struct hvc_struct *hp)
 {
@@ -794,7 +812,7 @@ int __devexit hvc_remove(struct hvc_stru
 
 	/*
 	 * We 'put' the instance that was grabbed when the kobject instance
-	 * was intialized using kobject_init().  Let the last holder of this
+	 * was initialized using kobject_init().  Let the last holder of this
 	 * kobject cause it to be removed, which will probably be the tty_hangup
 	 * below.
 	 */
@@ -809,11 +827,10 @@ int __devexit hvc_remove(struct hvc_stru
 		tty_hangup(tty);
 	return 0;
 }
-EXPORT_SYMBOL(hvc_remove);
 
 /* Driver initialization.  Follow console initialization.  This is where the TTY
  * interfaces start to become available. */
-int __init hvc_init(void)
+static int __init hvc_init(void)
 {
 	struct tty_driver *drv;
 
@@ -850,7 +867,7 @@ int __init hvc_init(void)
 }
 module_init(hvc_init);
 
-/* This isn't particularily necessary due to this being a console driver
+/* This isn't particularly necessary due to this being a console driver
  * but it is nice to be thorough.
  */
 static void __exit hvc_exit(void)
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index f144a94..b37f1d5 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -575,11 +575,11 @@ static int hvc_find_vtys(void)
 				(num_found >= VTTY_PORTS))
 			break;
 
-		vtermno = get_property(vty, "reg", NULL);
+		vtermno = of_get_property(vty, "reg", NULL);
 		if (!vtermno)
 			continue;
 
-		if (!device_is_compatible(vty, "IBM,iSeries-vty"))
+		if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
 			continue;
 
 		if (num_found == 0)
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index f9c0084..79711aa 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -153,11 +153,11 @@ static int hvc_find_vtys(void)
 		if (num_found >= MAX_NR_HVC_CONSOLES)
 			break;
 
-		vtermno = get_property(vty, "reg", NULL);
+		vtermno = of_get_property(vty, "reg", NULL);
 		if (!vtermno)
 			continue;
 
-		if (device_is_compatible(vty, "hvterm1")) {
+		if (of_device_is_compatible(vty, "hvterm1")) {
 			hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
 			++num_found;
 		}
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 50315d6..d5a752d 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1279,8 +1279,8 @@ static int __init hvsi_console_init(void
 		struct hvsi_struct *hp;
 		const uint32_t *vtermno, *irq;
 
-		vtermno = get_property(vty, "reg", NULL);
-		irq = get_property(vty, "interrupts", NULL);
+		vtermno = of_get_property(vty, "reg", NULL);
+		irq = of_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 cc1046e..4ae9811 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -24,10 +24,11 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/hw_random.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hw_random.h>
+#include <linux/stop_machine.h>
 #include <asm/io.h>
 
 
@@ -217,30 +218,117 @@ static struct hwrng intel_rng = {
 	.data_read	= intel_rng_data_read,
 };
 
+struct intel_rng_hw {
+	struct pci_dev *dev;
+	void __iomem *mem;
+	u8 bios_cntl_off;
+	u8 bios_cntl_val;
+	u8 fwh_dec_en1_off;
+	u8 fwh_dec_en1_val;
+};
 
-#ifdef CONFIG_SMP
-static char __initdata waitflag;
+static int __init intel_rng_hw_init(void *_intel_rng_hw)
+{
+	struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
+	u8 mfc, dvc;
+
+	/* interrupts disabled in stop_machine_run call */
+
+	if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+		pci_write_config_byte(intel_rng_hw->dev,
+		                      intel_rng_hw->fwh_dec_en1_off,
+		                      intel_rng_hw->fwh_dec_en1_val |
+				      FWH_F8_EN_MASK);
+	if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
+		pci_write_config_byte(intel_rng_hw->dev,
+		                      intel_rng_hw->bios_cntl_off,
+		                      intel_rng_hw->bios_cntl_val |
+				      BIOS_CNTL_WRITE_ENABLE_MASK);
+
+	writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+	writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);
+	mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+	dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+	writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+
+	if (!(intel_rng_hw->bios_cntl_val &
+	      (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+		pci_write_config_byte(intel_rng_hw->dev,
+				      intel_rng_hw->bios_cntl_off,
+				      intel_rng_hw->bios_cntl_val);
+	if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+		pci_write_config_byte(intel_rng_hw->dev,
+				      intel_rng_hw->fwh_dec_en1_off,
+				      intel_rng_hw->fwh_dec_en1_val);
 
-static void __init intel_init_wait(void *unused)
+	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");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
+					struct pci_dev *dev)
 {
-	while (waitflag)
-		cpu_relax();
+	intel_rng_hw->bios_cntl_val = 0xff;
+	intel_rng_hw->fwh_dec_en1_val = 0xff;
+	intel_rng_hw->dev = dev;
+
+	/* Check for Intel 82802 */
+	if (dev->device < 0x2640) {
+		intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+		intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;
+	} else {
+		intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+		intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;
+	}
+
+	pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,
+			     &intel_rng_hw->fwh_dec_en1_val);
+	pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,
+			     &intel_rng_hw->bios_cntl_val);
+
+	if ((intel_rng_hw->bios_cntl_val &
+	     (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
+	    == BIOS_CNTL_LOCK_ENABLE_MASK) {
+		static __initdata /*const*/ char warning[] =
+			KERN_WARNING PFX "Firmware space is locked read-only. "
+			KERN_WARNING PFX "If you can't or\n don't want to "
+			KERN_WARNING PFX "disable this in firmware setup, and "
+			KERN_WARNING PFX "if\n you are certain that your "
+			KERN_WARNING PFX "system has a functional\n RNG, try"
+			KERN_WARNING PFX "using the 'no_fwh_detect' option.\n";
+
+		if (no_fwh_detect)
+			return -ENODEV;
+		printk(warning);
+		return -EBUSY;
+	}
+
+	intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+	if (intel_rng_hw->mem == NULL)
+		return -EBUSY;
+
+	return 0;
 }
-#endif
+
 
 static int __init mod_init(void)
 {
 	int err = -ENODEV;
-	unsigned i;
+	int i;
 	struct pci_dev *dev = NULL;
-	void __iomem *mem;
-	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;
+	void __iomem *mem = mem;
+	u8 hw_status;
+	struct intel_rng_hw *intel_rng_hw;
 
 	for (i = 0; !dev && pci_tbl[i].vendor; ++i)
-		dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+		dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,
+				     NULL);
 
 	if (!dev)
 		goto out; /* Device not found. */
@@ -250,39 +338,18 @@ static int __init mod_init(void)
 		goto fwh_done;
 	}
 
-	/* 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);
-
-	if ((bios_cntl_val &
-	     (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
-	    == BIOS_CNTL_LOCK_ENABLE_MASK) {
-		static __initdata /*const*/ char warning[] =
-			KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
-			KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
-			KERN_WARNING PFX "you are certain that your system has a functional\n"
-			KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
-
+	intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);
+	if (!intel_rng_hw) {
 		pci_dev_put(dev);
-		if (no_fwh_detect)
-			goto fwh_done;
-		printk(warning);
-		err = -EBUSY;
 		goto out;
 	}
 
-	mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
-	if (mem == NULL) {
+	err = intel_init_hw_struct(intel_rng_hw, dev);
+	if (err) {
 		pci_dev_put(dev);
-		err = -EBUSY;
+		kfree(intel_rng_hw);
+		if (err == -ENODEV)
+			goto fwh_done;
 		goto out;
 	}
 
@@ -290,59 +357,18 @@ static int __init mod_init(void)
 	 * 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.
+	 *
+	 * Use stop_machine_run because IPIs can be blocked by disabling
+	 * interrupts.
 	 */
-#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_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);
+	err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS);
 	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;
+	iounmap(intel_rng_hw->mem);
+	kfree(intel_rng_hw);
+	if (err)
 		goto out;
-	}
 
 fwh_done:
-
 	err = -ENOMEM;
 	mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
 	if (!mem)
@@ -352,22 +378,21 @@ fwh_done:
 	/* Check for Random Number Generator */
 	err = -ENODEV;
 	hw_status = hwstatus_get(mem);
-	if ((hw_status & INTEL_RNG_PRESENT) == 0)
-		goto err_unmap;
+	if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+		iounmap(mem);
+		goto out;
+	}
 
 	printk(KERN_INFO "Intel 82802 RNG detected\n");
 	err = hwrng_register(&intel_rng);
 	if (err) {
 		printk(KERN_ERR PFX "RNG registering failed (%d)\n",
 		       err);
-		goto err_unmap;
+		iounmap(mem);
 	}
 out:
 	return err;
 
-err_unmap:
-	iounmap(mem);
-	goto out;
 }
 
 static void __exit mod_exit(void)
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 9ebf84d..ec435cb 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -26,7 +26,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/pci.h>
 #include <linux/hw_random.h>
 #include <asm/io.h>
 #include <asm/msr.h>
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 353d9f3..0289705 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -22,6 +22,7 @@ #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/dmi.h>
+#include <linux/capability.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index a48da02..932264a 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -35,7 +35,6 @@ #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 
 #include <asm/m48t35.h>
 #include <asm/sn/ioc3.h>
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e221465..6c5d15d 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -9,6 +9,7 @@
  *         source@mvista.com
  *
  * Copyright 2002 MontaVista Software Inc.
+ * Copyright 2006 IBM Corp., Christian Krafft <krafft@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
@@ -64,6 +65,11 @@ #include <linux/dmi.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#ifdef CONFIG_PPC_OF
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#endif
+
 #define PFX "ipmi_si: "
 
 /* Measure times between events in the driver. */
@@ -76,6 +82,12 @@ #define SI_TIMEOUT_JIFFIES	(SI_TIMEOUT_T
 #define SI_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
                                        short timeout */
 
+/* Bit for BMC global enables. */
+#define IPMI_BMC_RCV_MSG_INTR     0x01
+#define IPMI_BMC_EVT_MSG_INTR     0x02
+#define IPMI_BMC_EVT_MSG_BUFF     0x04
+#define IPMI_BMC_SYS_LOG          0x08
+
 enum si_intf_state {
 	SI_NORMAL,
 	SI_GETTING_FLAGS,
@@ -84,7 +96,9 @@ enum si_intf_state {
 	SI_CLEARING_FLAGS_THEN_SET_IRQ,
 	SI_GETTING_MESSAGES,
 	SI_ENABLE_INTERRUPTS1,
-	SI_ENABLE_INTERRUPTS2
+	SI_ENABLE_INTERRUPTS2,
+	SI_DISABLE_INTERRUPTS1,
+	SI_DISABLE_INTERRUPTS2
 	/* FIXME - add watchdog stuff. */
 };
 
@@ -333,6 +347,17 @@ static void start_enable_irq(struct smi_
 	smi_info->si_state = SI_ENABLE_INTERRUPTS1;
 }
 
+static void start_disable_irq(struct smi_info *smi_info)
+{
+	unsigned char msg[2];
+
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+	smi_info->si_state = SI_DISABLE_INTERRUPTS1;
+}
+
 static void start_clear_flags(struct smi_info *smi_info)
 {
 	unsigned char msg[3];
@@ -353,7 +378,7 @@ static void start_clear_flags(struct smi
 static inline void disable_si_irq(struct smi_info *smi_info)
 {
 	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
-		disable_irq_nosync(smi_info->irq);
+		start_disable_irq(smi_info);
 		smi_info->interrupt_disabled = 1;
 	}
 }
@@ -361,7 +386,7 @@ static inline void disable_si_irq(struct
 static inline void enable_si_irq(struct smi_info *smi_info)
 {
 	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
-		enable_irq(smi_info->irq);
+		start_enable_irq(smi_info);
 		smi_info->interrupt_disabled = 0;
 	}
 }
@@ -583,7 +608,9 @@ #endif
 		} else {
 			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
 			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
-			msg[2] = msg[3] | 1; /* enable msg queue int */
+			msg[2] = (msg[3] |
+				  IPMI_BMC_RCV_MSG_INTR |
+				  IPMI_BMC_EVT_MSG_INTR);
 			smi_info->handlers->start_transaction(
 				smi_info->si_sm, msg, 3);
 			smi_info->si_state = SI_ENABLE_INTERRUPTS2;
@@ -605,6 +632,45 @@ #endif
 		smi_info->si_state = SI_NORMAL;
 		break;
 	}
+
+	case SI_DISABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not disable interrupts"
+			       ", failed get.\n");
+			smi_info->si_state = SI_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = (msg[3] &
+				  ~(IPMI_BMC_RCV_MSG_INTR |
+				    IPMI_BMC_EVT_MSG_INTR));
+			smi_info->handlers->start_transaction(
+				smi_info->si_sm, msg, 3);
+			smi_info->si_state = SI_DISABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case SI_DISABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the SMI, now handle them. */
+		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_si: Could not disable interrupts"
+			       ", failed set.\n");
+		}
+		smi_info->si_state = SI_NORMAL;
+		break;
+	}
 	}
 }
 
@@ -858,9 +924,6 @@ #ifdef DEBUG_TIMING
 	struct timeval    t;
 #endif
 
-	if (atomic_read(&smi_info->stop_operation))
-		return;
-
 	spin_lock_irqsave(&(smi_info->si_lock), flags);
 #ifdef DEBUG_TIMING
 	do_gettimeofday(&t);
@@ -916,15 +979,11 @@ #endif
 	smi_info->interrupts++;
 	spin_unlock(&smi_info->count_lock);
 
-	if (atomic_read(&smi_info->stop_operation))
-		goto out;
-
 #ifdef DEBUG_TIMING
 	do_gettimeofday(&t);
 	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 	smi_event_handler(smi_info, 0);
- out:
 	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 	return IRQ_HANDLED;
 }
@@ -1006,6 +1065,7 @@ static DEFINE_MUTEX(smi_infos_lock);
 static int smi_num; /* Used to sequence the SMIs */
 
 #define DEFAULT_REGSPACING	1
+#define DEFAULT_REGSIZE		1
 
 static int           si_trydefaults = 1;
 static char          *si_type[SI_MAX_PARMS];
@@ -1111,7 +1171,7 @@ static int std_irq_setup(struct smi_info
 	if (info->si_type == SI_BT) {
 		rv = request_irq(info->irq,
 				 si_bt_irq_handler,
-				 IRQF_DISABLED,
+				 IRQF_SHARED | IRQF_DISABLED,
 				 DEVICE_NAME,
 				 info);
 		if (!rv)
@@ -1121,7 +1181,7 @@ static int std_irq_setup(struct smi_info
 	} else
 		rv = request_irq(info->irq,
 				 si_irq_handler,
-				 IRQF_DISABLED,
+				 IRQF_SHARED | IRQF_DISABLED,
 				 DEVICE_NAME,
 				 info);
 	if (rv) {
@@ -1701,15 +1761,11 @@ #endif
 	smi_info->interrupts++;
 	spin_unlock(&smi_info->count_lock);
 
-	if (atomic_read(&smi_info->stop_operation))
-		goto out;
-
 #ifdef DEBUG_TIMING
 	do_gettimeofday(&t);
 	printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 	smi_event_handler(smi_info, 0);
- out:
 	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
 
 	return ACPI_INTERRUPT_HANDLED;
@@ -2133,12 +2189,15 @@ static int __devinit ipmi_pci_probe(stru
 		info->irq_setup = std_irq_setup;
 
 	info->dev = &pdev->dev;
+	pci_set_drvdata(pdev, info);
 
 	return try_smi_init(info);
 }
 
 static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
 {
+	struct smi_info *info = pci_get_drvdata(pdev);
+	cleanup_one_si(info);
 }
 
 #ifdef CONFIG_PM
@@ -2172,6 +2231,99 @@ #endif
 #endif /* CONFIG_PCI */
 
 
+#ifdef CONFIG_PPC_OF
+static int __devinit ipmi_of_probe(struct of_device *dev,
+			 const struct of_device_id *match)
+{
+	struct smi_info *info;
+	struct resource resource;
+	const int *regsize, *regspacing, *regshift;
+	struct device_node *np = dev->node;
+	int ret;
+	int proplen;
+
+	dev_info(&dev->dev, PFX "probing via device tree\n");
+
+	ret = of_address_to_resource(np, 0, &resource);
+	if (ret) {
+		dev_warn(&dev->dev, PFX "invalid address from OF\n");
+		return ret;
+	}
+
+	regsize = get_property(np, "reg-size", &proplen);
+	if (regsize && proplen != 4) {
+		dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
+		return -EINVAL;
+	}
+
+	regspacing = get_property(np, "reg-spacing", &proplen);
+	if (regspacing && proplen != 4) {
+		dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
+		return -EINVAL;
+	}
+
+	regshift = get_property(np, "reg-shift", &proplen);
+	if (regshift && proplen != 4) {
+		dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
+		return -EINVAL;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+	if (!info) {
+		dev_err(&dev->dev,
+			PFX "could not allocate memory for OF probe\n");
+		return -ENOMEM;
+	}
+
+	info->si_type		= (enum si_type) match->data;
+	info->addr_source	= "device-tree";
+	info->io_setup		= mem_setup;
+	info->irq_setup		= std_irq_setup;
+
+	info->io.addr_type	= IPMI_MEM_ADDR_SPACE;
+	info->io.addr_data	= resource.start;
+
+	info->io.regsize	= regsize ? *regsize : DEFAULT_REGSIZE;
+	info->io.regspacing	= regspacing ? *regspacing : DEFAULT_REGSPACING;
+	info->io.regshift	= regshift ? *regshift : 0;
+
+	info->irq		= irq_of_parse_and_map(dev->node, 0);
+	info->dev		= &dev->dev;
+
+	dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n",
+		info->io.addr_data, info->io.regsize, info->io.regspacing,
+		info->irq);
+
+	dev->dev.driver_data = (void*) info;
+
+	return try_smi_init(info);
+}
+
+static int __devexit ipmi_of_remove(struct of_device *dev)
+{
+	cleanup_one_si(dev->dev.driver_data);
+	return 0;
+}
+
+static struct of_device_id ipmi_match[] =
+{
+	{ .type = "ipmi", .compatible = "ipmi-kcs",  .data = (void *)(unsigned long) SI_KCS },
+	{ .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC },
+	{ .type = "ipmi", .compatible = "ipmi-bt",   .data = (void *)(unsigned long) SI_BT },
+	{},
+};
+
+static struct of_platform_driver ipmi_of_platform_driver =
+{
+	.name		= "ipmi",
+	.match_table	= ipmi_match,
+	.probe		= ipmi_of_probe,
+	.remove		= __devexit_p(ipmi_of_remove),
+};
+#endif /* CONFIG_PPC_OF */
+
+
 static int try_get_dev_id(struct smi_info *smi_info)
 {
 	unsigned char         msg[2];
@@ -2801,6 +2953,10 @@ #ifdef CONFIG_PCI
 	}
 #endif
 
+#ifdef CONFIG_PPC_OF
+	of_register_platform_driver(&ipmi_of_platform_driver);
+#endif
+
 	if (si_trydefaults) {
 		mutex_lock(&smi_infos_lock);
 		if (list_empty(&smi_infos)) {
@@ -2838,28 +2994,33 @@ static void cleanup_one_si(struct smi_in
 
 	list_del(&to_clean->link);
 
-	/* Tell the timer and interrupt handlers that we are shutting
-	   down. */
-	spin_lock_irqsave(&(to_clean->si_lock), flags);
-	spin_lock(&(to_clean->msg_lock));
-
+	/* Tell the driver that we are shutting down. */
 	atomic_inc(&to_clean->stop_operation);
 
-	if (to_clean->irq_cleanup)
-		to_clean->irq_cleanup(to_clean);
-
-	spin_unlock(&(to_clean->msg_lock));
-	spin_unlock_irqrestore(&(to_clean->si_lock), flags);
-
-	/* Wait until we know that we are out of any interrupt
-	   handlers might have been running before we freed the
-	   interrupt. */
-	synchronize_sched();
-
+	/* Make sure the timer and thread are stopped and will not run
+	   again. */
 	wait_for_timer_and_thread(to_clean);
 
-	/* Interrupts and timeouts are stopped, now make sure the
-	   interface is in a clean state. */
+	/* Timeouts are stopped, now make sure the interrupts are off
+	   for the device.  A little tricky with locks to make sure
+	   there are no races. */
+	spin_lock_irqsave(&to_clean->si_lock, flags);
+	while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+		spin_unlock_irqrestore(&to_clean->si_lock, flags);
+		poll(to_clean);
+		schedule_timeout_uninterruptible(1);
+		spin_lock_irqsave(&to_clean->si_lock, flags);
+	}
+	disable_si_irq(to_clean);
+	spin_unlock_irqrestore(&to_clean->si_lock, flags);
+	while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+		poll(to_clean);
+		schedule_timeout_uninterruptible(1);
+	}
+
+	/* Clean up interrupts and make sure that everything is done. */
+	if (to_clean->irq_cleanup)
+		to_clean->irq_cleanup(to_clean);
 	while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
 		poll(to_clean);
 		schedule_timeout_uninterruptible(1);
@@ -2898,6 +3059,10 @@ #ifdef CONFIG_PCI
 	pci_unregister_driver(&ipmi_pci_driver);
 #endif
 
+#ifdef CONFIG_PPC_OF
+	of_unregister_platform_driver(&ipmi_of_platform_driver);
+#endif
+
 	mutex_lock(&smi_infos_lock);
 	list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
 		cleanup_one_si(e);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 6b634e8..147c120 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -39,6 +39,7 @@ #include <linux/watchdog.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 #include <linux/completion.h>
+#include <linux/kdebug.h>
 #include <linux/rwsem.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
@@ -49,9 +50,18 @@ #include <linux/wait.h>
 #include <linux/poll.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/delay.h>
 #include <asm/atomic.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/apic.h>
+
+#ifdef CONFIG_X86
+/* This is ugly, but I've determined that x86 is the only architecture
+   that can reasonably support the IPMI NMI watchdog timeout at this
+   time.  If another architecture adds this capability somehow, it
+   will have to be a somewhat different mechanism and I have no idea
+   how it will work.  So in the unlikely event that another
+   architecture supports this, we can figure out a good generic
+   mechanism for it at that time. */
+#define HAVE_DIE_NMI_POST
 #endif
 
 #define	PFX "IPMI Watchdog: "
@@ -317,6 +327,11 @@ static unsigned char ipmi_version_minor;
 /* If a pretimeout occurs, this is used to allow only one panic to happen. */
 static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
 
+#ifdef HAVE_DIE_NMI_POST
+static int testing_nmi;
+static int nmi_handler_registered;
+#endif
+
 static int ipmi_heartbeat(void);
 static void panic_halt_ipmi_heartbeat(void);
 
@@ -358,6 +373,10 @@ static int i_ipmi_set_timeout(struct ipm
 	int                               hbnow = 0;
 
 
+	/* These can be cleared as we are setting the timeout. */
+	ipmi_start_timer_on_heartbeat = 0;
+	pretimeout_since_last_heartbeat = 0;
+
 	data[0] = 0;
 	WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
 
@@ -432,13 +451,12 @@ static int ipmi_set_timeout(int do_heart
 
 	wait_for_completion(&set_timeout_wait);
 
+	mutex_unlock(&set_timeout_lock);
+
 	if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
 	    || ((send_heartbeat_now)
 		&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
-	{
 		rv = ipmi_heartbeat();
-	}
-	mutex_unlock(&set_timeout_lock);
 
 out:
 	return rv;
@@ -518,12 +536,10 @@ static int ipmi_heartbeat(void)
 	int                               rv;
 	struct ipmi_system_interface_addr addr;
 
-	if (ipmi_ignore_heartbeat) {
+	if (ipmi_ignore_heartbeat)
 		return 0;
-	}
 
 	if (ipmi_start_timer_on_heartbeat) {
-		ipmi_start_timer_on_heartbeat = 0;
 		ipmi_watchdog_state = action_val;
 		return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
 	} else if (pretimeout_since_last_heartbeat) {
@@ -531,7 +547,6 @@ static int ipmi_heartbeat(void)
 		   We don't want to set the action, though, we want to
 		   leave that alone (thus it can't be combined with the
 		   above operation. */
-		pretimeout_since_last_heartbeat = 0;
 		return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
 	}
 
@@ -919,6 +934,45 @@ static void ipmi_register_watchdog(int i
 		printk(KERN_CRIT PFX "Unable to register misc device\n");
 	}
 
+#ifdef HAVE_DIE_NMI_POST
+	if (nmi_handler_registered) {
+		int old_pretimeout = pretimeout;
+		int old_timeout = timeout;
+		int old_preop_val = preop_val;
+
+		/* Set the pretimeout to go off in a second and give
+		   ourselves plenty of time to stop the timer. */
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+		preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
+		pretimeout = 99;
+		timeout = 100;
+
+		testing_nmi = 1;
+
+		rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
+		if (rv) {
+			printk(KERN_WARNING PFX "Error starting timer to"
+			       " test NMI: 0x%x.  The NMI pretimeout will"
+			       " likely not work\n", rv);
+			rv = 0;
+			goto out_restore;
+		}
+
+		msleep(1500);
+
+		if (testing_nmi != 2) {
+			printk(KERN_WARNING PFX "IPMI NMI didn't seem to"
+			       " occur.  The NMI pretimeout will"
+			       " likely not work\n");
+		}
+	out_restore:
+		testing_nmi = 0;
+		preop_val = old_preop_val;
+		pretimeout = old_pretimeout;
+		timeout = old_timeout;
+	}
+#endif
+
  out:
 	up_write(&register_sem);
 
@@ -928,6 +982,10 @@ static void ipmi_register_watchdog(int i
 		ipmi_watchdog_state = action_val;
 		ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
 		printk(KERN_INFO PFX "Starting now!\n");
+	} else {
+		/* Stop the timer now. */
+		ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+		ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 	}
 }
 
@@ -964,17 +1022,28 @@ static void ipmi_unregister_watchdog(int
 	up_write(&register_sem);
 }
 
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
 static int
-ipmi_nmi(void *dev_id, int cpu, int handled)
+ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
 {
+	if (val != DIE_NMI_POST)
+		return NOTIFY_OK;
+
+	if (testing_nmi) {
+		testing_nmi = 2;
+		return NOTIFY_STOP;
+	}
+
         /* If we are not expecting a timeout, ignore it. */
 	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
-		return NOTIFY_DONE;
+		return NOTIFY_OK;
+
+	if (preaction_val != WDOG_PRETIMEOUT_NMI)
+		return NOTIFY_OK;
 
 	/* If no one else handled the NMI, we assume it was the IPMI
            watchdog. */
-	if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+	if (preop_val == WDOG_PREOP_PANIC) {
 		/* On some machines, the heartbeat will give
 		   an error and not work unless we re-enable
 		   the timer.   So do so. */
@@ -983,18 +1052,12 @@ ipmi_nmi(void *dev_id, int cpu, int hand
 			panic(PFX "pre-timeout");
 	}
 
-	return NOTIFY_DONE;
+	return NOTIFY_STOP;
 }
 
-static struct nmi_handler ipmi_nmi_handler =
-{
-	.link     = LIST_HEAD_INIT(ipmi_nmi_handler.link),
-	.dev_name = "ipmi_watchdog",
-	.dev_id   = NULL,
-	.handler  = ipmi_nmi,
-	.priority = 0, /* Call us last. */
+static struct notifier_block ipmi_nmi_handler = {
+	.notifier_call = ipmi_nmi
 };
-int nmi_handler_registered;
 #endif
 
 static int wdog_reboot_handler(struct notifier_block *this,
@@ -1111,7 +1174,7 @@ static int preaction_op(const char *inva
 		preaction_val = WDOG_PRETIMEOUT_NONE;
 	else if (strcmp(inval, "pre_smi") == 0)
 		preaction_val = WDOG_PRETIMEOUT_SMI;
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
 	else if (strcmp(inval, "pre_nmi") == 0)
 		preaction_val = WDOG_PRETIMEOUT_NMI;
 #endif
@@ -1145,7 +1208,7 @@ static int preop_op(const char *inval, c
 
 static void check_parms(void)
 {
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
 	int do_nmi = 0;
 	int rv;
 
@@ -1158,20 +1221,9 @@ #ifdef HAVE_NMI_HANDLER
 			preop_op("preop_none", NULL);
 			do_nmi = 0;
 		}
-#ifdef CONFIG_X86_LOCAL_APIC
-		if (nmi_watchdog == NMI_IO_APIC) {
-			printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
-			       " mode (value is %d), that is incompatible"
-			       " with using NMI in the IPMI watchdog."
-			       " Disabling IPMI nmi pretimeout.\n",
-			       nmi_watchdog);
-			preaction_val = WDOG_PRETIMEOUT_NONE;
-			do_nmi = 0;
-		}
-#endif
 	}
 	if (do_nmi && !nmi_handler_registered) {
-		rv = request_nmi(&ipmi_nmi_handler);
+		rv = register_die_notifier(&ipmi_nmi_handler);
 		if (rv) {
 			printk(KERN_WARNING PFX
 			       "Can't register nmi handler\n");
@@ -1179,7 +1231,7 @@ #endif
 		} else
 			nmi_handler_registered = 1;
 	} else if (!do_nmi && nmi_handler_registered) {
-		release_nmi(&ipmi_nmi_handler);
+		unregister_die_notifier(&ipmi_nmi_handler);
 		nmi_handler_registered = 0;
 	}
 #endif
@@ -1215,9 +1267,9 @@ static int __init ipmi_wdog_init(void)
 
 	rv = ipmi_smi_watcher_register(&smi_watcher);
 	if (rv) {
-#ifdef HAVE_NMI_HANDLER
-		if (preaction_val == WDOG_PRETIMEOUT_NMI)
-			release_nmi(&ipmi_nmi_handler);
+#ifdef HAVE_DIE_NMI_POST
+		if (nmi_handler_registered)
+			unregister_die_notifier(&ipmi_nmi_handler);
 #endif
 		atomic_notifier_chain_unregister(&panic_notifier_list,
 						 &wdog_panic_notifier);
@@ -1236,9 +1288,9 @@ static void __exit ipmi_wdog_exit(void)
 	ipmi_smi_watcher_unregister(&smi_watcher);
 	ipmi_unregister_watchdog(watchdog_ifnum);
 
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
 	if (nmi_handler_registered)
-		release_nmi(&ipmi_nmi_handler);
+		unregister_die_notifier(&ipmi_nmi_handler);
 #endif
 
 	atomic_notifier_chain_unregister(&panic_notifier_list,
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 43ab9ed..761f777 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -137,11 +137,10 @@ #include <linux/isicom.h>
 #define InterruptTheCard(base) outw(0, (base) + 0xc)
 #define ClearInterrupt(base) inw((base) + 0x0a)
 
+#define pr_dbg(str...) pr_debug("ISICOM: " str)
 #ifdef DEBUG
-#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str)
 #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
 #else
-#define pr_dbg(str...) do { } while (0)
 #define isicom_paranoia_check(a, b, c) 0
 #endif
 
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index cb8d691..1b09450 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,7 +41,6 @@ #include <linux/sysrq.h>
 #include <linux/input.h>
 #include <linux/reboot.h>
 
-static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
 
 /*
@@ -110,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSO
 static struct kbd_struct *kbd = kbd_table;
 
 struct vt_spawn_console vt_spawn_con = {
-	.lock = SPIN_LOCK_UNLOCKED,
+	.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
 	.pid  = NULL,
 	.sig  = 0,
 };
@@ -159,65 +158,41 @@ #endif
 static int sysrq_alt;
 
 /*
- * Translation of scancodes to keycodes. We set them on only the first attached
- * keyboard - for per-keyboard setting, /dev/input/event is more useful.
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ *  USB keyboards for example have two event devices: one for all "normal"
+ *  keys and one for extra function keys (like "volume up", "make coffee",
+ *  etc.). So this means that scancodes for the extra function keys won't
+ *  be valid for the first event device, but will be for the second.
  */
 int getkeycode(unsigned int scancode)
 {
-	struct list_head *node;
-	struct input_dev *dev = NULL;
+	struct input_handle *handle;
+	int keycode;
+	int error = -ENODEV;
 
-	list_for_each(node, &kbd_handler.h_list) {
-		struct input_handle *handle = to_handle_h(node);
-		if (handle->dev->keycodesize) {
-			dev = handle->dev;
-			break;
-		}
+	list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+		error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
+		if (!error)
+			return keycode;
 	}
 
-	if (!dev)
-		return -ENODEV;
-
-	if (scancode >= dev->keycodemax)
-		return -EINVAL;
-
-	return INPUT_KEYCODE(dev, scancode);
+	return error;
 }
 
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	struct list_head *node;
-	struct input_dev *dev = NULL;
-	unsigned int i, oldkey;
+	struct input_handle *handle;
+	int error = -ENODEV;
 
-	list_for_each(node, &kbd_handler.h_list) {
-		struct input_handle *handle = to_handle_h(node);
-		if (handle->dev->keycodesize) {
-			dev = handle->dev;
+	list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+		error = handle->dev->setkeycode(handle->dev, scancode, keycode);
+		if (!error)
 			break;
-		}
 	}
 
-	if (!dev)
-		return -ENODEV;
-
-	if (scancode >= dev->keycodemax)
-		return -EINVAL;
-	if (keycode < 0 || keycode > KEY_MAX)
-		return -EINVAL;
-	if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
-		return -EINVAL;
-
-	oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
-
-	clear_bit(oldkey, dev->keybit);
-	set_bit(keycode, dev->keybit);
-
-	for (i = 0; i < dev->keycodemax; i++)
-		if (INPUT_KEYCODE(dev,i) == oldkey)
-			set_bit(oldkey, dev->keybit);
-
-	return 0;
+	return error;
 }
 
 /*
@@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, un
  */
 static void kd_nosound(unsigned long ignored)
 {
-	struct list_head *node;
+	struct input_handle *handle;
 
-	list_for_each(node, &kbd_handler.h_list) {
-		struct input_handle *handle = to_handle_h(node);
+	list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
 		if (test_bit(EV_SND, handle->dev->evbit)) {
 			if (test_bit(SND_TONE, handle->dev->sndbit))
 				input_inject_event(handle, EV_SND, SND_TONE, 0);
@@ -1161,7 +1135,7 @@ #endif /* CONFIG_MAC_EMUMOUSEBTN */
 
 	if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
 		if (emulate_raw(vc, keycode, !down << 7))
-			if (keycode < BTN_MISC)
+			if (keycode < BTN_MISC && printk_ratelimit())
 				printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
 
 #ifdef CONFIG_MAGIC_SYSRQ	       /* Handle the SysRq Hack */
@@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handl
  * likes it, it can open it and get events from it. In this (kbd_connect)
  * function, we should decide which VT to bind that keyboard to initially.
  */
-static struct input_handle *kbd_connect(struct input_handler *handler,
-					struct input_dev *dev,
-					const struct input_device_id *id)
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+			const struct input_device_id *id)
 {
 	struct input_handle *handle;
+	int error;
 	int i;
 
 	for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(
 			break;
 
 	if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
-		return NULL;
+		return -ENODEV;
 
 	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
 	if (!handle)
-		return NULL;
+		return -ENOMEM;
 
 	handle->dev = dev;
 	handle->handler = handler;
 	handle->name = "kbd";
 
-	input_open_device(handle);
+	error = input_register_handle(handle);
+	if (error)
+		goto err_free_handle;
+
+	error = input_open_device(handle);
+	if (error)
+		goto err_unregister_handle;
+
+	return 0;
 
-	return handle;
+ err_unregister_handle:
+	input_unregister_handle(handle);
+ err_free_handle:
+	kfree(handle);
+	return error;
 }
 
 static void kbd_disconnect(struct input_handle *handle)
 {
 	input_close_device(handle);
+	input_unregister_handle(handle);
 	kfree(handle);
 }
 
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index b51d08b..62051f8 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -118,7 +118,6 @@ #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
@@ -139,9 +138,6 @@ #include <asm/system.h>
 /* if you have more than 8 printers, remember to increase LP_NO */
 #define LP_NO 8
 
-/* ROUND_UP macro from fs/select.c */
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
 static struct lp_struct lp_table[LP_NO];
 
 static unsigned int lp_count = 0;
@@ -652,7 +648,7 @@ #endif
 			    (par_timeout.tv_usec < 0)) {
 				return -EINVAL;
 			}
-			to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
+			to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
 			to_jiffies += par_timeout.tv_sec * (long) HZ;
 			if (to_jiffies <= 0) {
 				return -EINVAL;
@@ -803,7 +799,7 @@ static int lp_register(int nr, struct pa
 	if (reset)
 		lp_reset(nr);
 
-	class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL,
+	class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
 				"lp%d", nr);
 
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 5f06696..cc9a9d0 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,7 +18,6 @@ #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 <linux/highmem.h>
@@ -552,7 +551,7 @@ static ssize_t write_kmem(struct file * 
  	return virtr + wrote;
 }
 
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
 static ssize_t read_port(struct file * file, char __user * buf,
 			 size_t count, loff_t *ppos)
 {
@@ -835,7 +834,7 @@ static const struct file_operations null
 	.splice_write	= splice_write_null,
 };
 
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
 static const struct file_operations port_fops = {
 	.llseek		= memory_lseek,
 	.read		= read_port,
@@ -913,7 +912,7 @@ static int memory_open(struct inode * in
 		case 3:
 			filp->f_op = &null_fops;
 			break;
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
 		case 4:
 			filp->f_op = &port_fops;
 			break;
@@ -960,7 +959,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(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
 	{4, "port",    S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
 #endif
 	{5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 7e975f6..4e6fb96 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -41,6 +41,7 @@ #include <linux/miscdevice.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/stat.h>
@@ -53,7 +54,7 @@ #include <linux/kmod.h>
  * Head entry for the doubly linked miscdevice list
  */
 static LIST_HEAD(misc_list);
-static DECLARE_MUTEX(misc_sem);
+static DEFINE_MUTEX(misc_mtx);
 
 /*
  * Assigned numbers, used for dynamic minors
@@ -69,7 +70,7 @@ static void *misc_seq_start(struct seq_f
 	struct miscdevice *p;
 	loff_t off = 0;
 
-	down(&misc_sem);
+	mutex_lock(&misc_mtx);
 	list_for_each_entry(p, &misc_list, list) {
 		if (*pos == off++) 
 			return p;
@@ -89,7 +90,7 @@ static void *misc_seq_next(struct seq_fi
 
 static void misc_seq_stop(struct seq_file *seq, void *v)
 {
-	up(&misc_sem);
+	mutex_unlock(&misc_mtx);
 }
 
 static int misc_seq_show(struct seq_file *seq, void *v)
@@ -129,7 +130,7 @@ static int misc_open(struct inode * inod
 	int err = -ENODEV;
 	const struct file_operations *old_fops, *new_fops = NULL;
 	
-	down(&misc_sem);
+	mutex_lock(&misc_mtx);
 	
 	list_for_each_entry(c, &misc_list, list) {
 		if (c->minor == minor) {
@@ -139,9 +140,9 @@ static int misc_open(struct inode * inod
 	}
 		
 	if (!new_fops) {
-		up(&misc_sem);
+		mutex_unlock(&misc_mtx);
 		request_module("char-major-%d-%d", MISC_MAJOR, minor);
-		down(&misc_sem);
+		mutex_lock(&misc_mtx);
 
 		list_for_each_entry(c, &misc_list, list) {
 			if (c->minor == minor) {
@@ -165,7 +166,7 @@ static int misc_open(struct inode * inod
 	}
 	fops_put(old_fops);
 fail:
-	up(&misc_sem);
+	mutex_unlock(&misc_mtx);
 	return err;
 }
 
@@ -201,10 +202,10 @@ int misc_register(struct miscdevice * mi
 
 	INIT_LIST_HEAD(&misc->list);
 
-	down(&misc_sem);
+	mutex_lock(&misc_mtx);
 	list_for_each_entry(c, &misc_list, list) {
 		if (c->minor == misc->minor) {
-			up(&misc_sem);
+			mutex_unlock(&misc_mtx);
 			return -EBUSY;
 		}
 	}
@@ -215,7 +216,7 @@ int misc_register(struct miscdevice * mi
 			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
 				break;
 		if (i<0) {
-			up(&misc_sem);
+			mutex_unlock(&misc_mtx);
 			return -EBUSY;
 		}
 		misc->minor = i;
@@ -238,7 +239,7 @@ int misc_register(struct miscdevice * mi
 	 */
 	list_add(&misc->list, &misc_list);
  out:
-	up(&misc_sem);
+	mutex_unlock(&misc_mtx);
 	return err;
 }
 
@@ -259,13 +260,13 @@ int misc_deregister(struct miscdevice * 
 	if (list_empty(&misc->list))
 		return -EINVAL;
 
-	down(&misc_sem);
+	mutex_lock(&misc_mtx);
 	list_del(&misc->list);
 	device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
 	if (i < DYNAMIC_MINORS && i>0) {
 		misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
 	}
-	up(&misc_sem);
+	mutex_unlock(&misc_mtx);
 	return 0;
 }
 
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 7dbaee8..e0d35c2 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -1582,7 +1582,7 @@ copy:
 
 	if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
 		return -EFAULT;
-	if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS)
+	if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
 		return -EINVAL;
 
 	switch(cmd)
@@ -2529,6 +2529,8 @@ static int moxaloadbios(int cardno, unsi
 	void __iomem *baseAddr;
 	int i;
 
+	if(len < 0 || len > sizeof(moxaBuff))
+		return -EINVAL;
 	if(copy_from_user(moxaBuff, tmp, len))
 		return -EFAULT;
 	baseAddr = moxa_boards[cardno].basemem;
@@ -2576,7 +2578,7 @@ static int moxaload320b(int cardno, unsi
 	void __iomem *baseAddr;
 	int i;
 
-	if(len > sizeof(moxaBuff))
+	if(len < 0 || len > sizeof(moxaBuff))
 		return -EINVAL;
 	if(copy_from_user(moxaBuff, tmp, len))
 		return -EFAULT;
@@ -2596,6 +2598,8 @@ static int moxaloadcode(int cardno, unsi
 	void __iomem *baseAddr, *ofsAddr;
 	int retval, port, i;
 
+	if(len < 0 || len > sizeof(moxaBuff))
+		return -EINVAL;
 	if(copy_from_user(moxaBuff, tmp, len))
 		return -EFAULT;
 	baseAddr = moxa_boards[cardno].basemem;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 80a0115..5953a45 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -54,7 +54,6 @@ #include <linux/ptrace.h>
 #include <linux/gfp.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index f7603b6..6cde448 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -37,7 +37,6 @@ #include <linux/ptrace.h>
 #include <linux/gfp.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 65f2d3a..14557a4 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -1088,13 +1088,13 @@ static ssize_t r3964_read(struct tty_str
 			/* block until there is a message: */
 			add_wait_queue(&pInfo->read_wait, &wait);
 repeat:
-			current->state = TASK_INTERRUPTIBLE;
+			__set_current_state(TASK_INTERRUPTIBLE);
 			pMsg = remove_msg(pInfo, pClient);
 			if (!pMsg && !signal_pending(current)) {
 				schedule();
 				goto repeat;
 			}
-			current->state = TASK_RUNNING;
+			__set_current_state(TASK_RUNNING);
 			remove_wait_queue(&pInfo->read_wait, &wait);
 		}
 
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 8d025e9..13808f6 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -42,7 +42,6 @@ #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
@@ -4169,7 +4168,7 @@ static int hdlcdev_xmit(struct sk_buff *
 	netif_stop_queue(dev);
 
 	/* copy data to device buffers */
-	memcpy(info->tx_buf, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, info->tx_buf, skb->len);
 	info->tx_get = 0;
 	info->tx_put = info->tx_count = skb->len;
 
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 4abd1ef..84ac64f 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -66,7 +66,6 @@ #include <linux/ctype.h>
 #include <linux/poll.h>
 #include <linux/major.h>
 #include <linux/ppdev.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <asm/uaccess.h>
 
@@ -752,7 +751,7 @@ static const struct file_operations pp_f
 
 static void pp_attach(struct parport *port)
 {
-	device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number),
+	device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number),
 			"parport%d", port->number);
 }
 
diff --git a/drivers/char/random.c b/drivers/char/random.c
index b9dc7aa..46c1b97 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -881,15 +881,15 @@ EXPORT_SYMBOL(get_random_bytes);
  */
 static void init_std_data(struct entropy_store *r)
 {
-	struct timeval tv;
+	ktime_t now;
 	unsigned long flags;
 
 	spin_lock_irqsave(&r->lock, flags);
 	r->entropy_count = 0;
 	spin_unlock_irqrestore(&r->lock, flags);
 
-	do_gettimeofday(&tv);
-	add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4);
+	now = ktime_get_real();
+	add_entropy_words(r, (__u32 *)&now, sizeof(now)/4);
 	add_entropy_words(r, (__u32 *)utsname(),
 			  sizeof(*(utsname()))/4);
 }
@@ -911,14 +911,12 @@ void rand_initialize_irq(int irq)
 		return;
 
 	/*
-	 * If kmalloc returns null, we just won't use that entropy
+	 * If kzalloc returns null, we just won't use that entropy
 	 * source.
 	 */
-	state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
-	if (state) {
-		memset(state, 0, sizeof(struct timer_rand_state));
+	state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
+	if (state)
 		irq_timer_state[irq] = state;
-	}
 }
 
 #ifdef CONFIG_BLOCK
@@ -927,14 +925,12 @@ void rand_initialize_disk(struct gendisk
 	struct timer_rand_state *state;
 
 	/*
-	 * If kmalloc returns null, we just won't use that entropy
+	 * If kzalloc returns null, we just won't use that entropy
 	 * source.
 	 */
-	state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
-	if (state) {
-		memset(state, 0, sizeof(struct timer_rand_state));
+	state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL);
+	if (state)
 		disk->random = state;
-	}
 }
 #endif
 
@@ -1469,7 +1465,6 @@ #if defined(CONFIG_IPV6) || defined(CONF
 __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
 				   __be16 sport, __be16 dport)
 {
-	struct timeval tv;
 	__u32 seq;
 	__u32 hash[12];
 	struct keydata *keyptr = get_keyptr();
@@ -1485,8 +1480,7 @@ __u32 secure_tcpv6_sequence_number(__be3
 	seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
 	seq += keyptr->count;
 
-	do_gettimeofday(&tv);
-	seq += tv.tv_usec + tv.tv_sec * 1000000;
+	seq += ktime_get_real().tv64;
 
 	return seq;
 }
@@ -1521,7 +1515,6 @@ #ifdef CONFIG_INET
 __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
 				 __be16 sport, __be16 dport)
 {
-	struct timeval tv;
 	__u32 seq;
 	__u32 hash[4];
 	struct keydata *keyptr = get_keyptr();
@@ -1543,12 +1536,11 @@ __u32 secure_tcp_sequence_number(__be32 
 	 *	As close as possible to RFC 793, which
 	 *	suggests using a 250 kHz clock.
 	 *	Further reading shows this assumes 2 Mb/s networks.
-	 *	For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+	 *	For 10 Gb/s Ethernet, a 1 GHz clock is appropriate.
 	 *	That's funny, Linux has one built in!  Use it!
 	 *	(Networks are faster now - should this be increased?)
 	 */
-	do_gettimeofday(&tv);
-	seq += tv.tv_usec + tv.tv_sec * 1000000;
+	seq += ktime_get_real().tv64;
 #if 0
 	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
 	       saddr, daddr, sport, dport, seq);
@@ -1556,8 +1548,6 @@ #endif
 	return seq;
 }
 
-EXPORT_SYMBOL(secure_tcp_sequence_number);
-
 /* Generate secure starting point for ephemeral IPV4 transport port search */
 u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
 {
@@ -1598,7 +1588,6 @@ #if defined(CONFIG_IP_DCCP) || defined(C
 u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
 				__be16 sport, __be16 dport)
 {
-	struct timeval tv;
 	u64 seq;
 	__u32 hash[4];
 	struct keydata *keyptr = get_keyptr();
@@ -1611,8 +1600,7 @@ u64 secure_dccp_sequence_number(__be32 s
 	seq = half_md4_transform(hash, keyptr->secret);
 	seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
 
-	do_gettimeofday(&tv);
-	seq += tv.tv_usec + tv.tv_sec * 1000000;
+	seq += ktime_get_real().tv64;
 	seq &= (1ull << 48) - 1;
 #if 0
 	printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 7014525..3494e3f 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -980,7 +980,7 @@ static int block_til_ready(struct tty_st
 		}
 		schedule();
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->open_wait, &wait);
 	if (!tty_hung_up_p(filp))
 		port->count++;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 76357c8..61a63da 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -65,10 +65,6 @@ #define POLL_PERIOD HZ/100	/*  Polling p
 
 /****** Kernel includes ******/
 
-#ifdef MODVERSIONS
-#include <config/modversions.h>
-#endif				
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/major.h>
@@ -85,6 +81,7 @@ #include <linux/tty_flip.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
+#include <linux/mutex.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
@@ -93,7 +90,6 @@ #include <asm/uaccess.h>
 #include <asm/atomic.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
-#include <asm/semaphore.h>
 #include <linux/init.h>
 
 /****** RocketPort includes ******/
@@ -702,7 +698,7 @@ static void init_r_port(int board, int a
 		}
 	}
 	spin_lock_init(&info->slock);
-	sema_init(&info->write_sem, 1);
+	mutex_init(&info->write_mtx);
 	rp_table[line] = info;
 	if (pci_dev)
 		tty_register_device(rocket_driver, line, &pci_dev->dev);
@@ -947,7 +943,7 @@ #ifdef ROCKET_DEBUG_OPEN
 #endif
 		schedule();	/*  Don't hold spinlock here, will hang PC */
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 
 	spin_lock_irqsave(&info->slock, flags);
@@ -1602,7 +1598,7 @@ #endif
 		if (signal_pending(current))
 			break;
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
 	printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
 #endif
@@ -1661,8 +1657,11 @@ static void rp_put_char(struct tty_struc
 	if (rocket_paranoia_check(info, "rp_put_char"))
 		return;
 
-	/*  Grab the port write semaphore, locking out other processes that try to write to this port */
-	down(&info->write_sem);
+	/*
+	 * Grab the port write mutex, locking out other processes that try to
+	 * write to this port
+	 */
+	mutex_lock(&info->write_mtx);
 
 #ifdef ROCKET_DEBUG_WRITE
 	printk(KERN_INFO "rp_put_char %c...", ch);
@@ -1684,12 +1683,12 @@ #endif
 		info->xmit_fifo_room--;
 	}
 	spin_unlock_irqrestore(&info->slock, flags);
-	up(&info->write_sem);
+	mutex_unlock(&info->write_mtx);
 }
 
 /*
  *  Exception handler - write routine, called when user app writes to the device.
- *  A per port write semaphore is used to protect from another process writing to
+ *  A per port write mutex is used to protect from another process writing to
  *  this port at the same time.  This other process could be running on the other CPU
  *  or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). 
  *  Spinlocks protect the info xmit members.
@@ -1706,7 +1705,7 @@ static int rp_write(struct tty_struct *t
 	if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
 		return 0;
 
-	down_interruptible(&info->write_sem);
+	mutex_lock_interruptible(&info->write_mtx);
 
 #ifdef ROCKET_DEBUG_WRITE
 	printk(KERN_INFO "rp_write %d chars...", count);
@@ -1777,7 +1776,7 @@ #ifdef ROCKETPORT_HAVE_POLL_WAIT
 		wake_up_interruptible(&tty->poll_wait);
 #endif
 	}
-	up(&info->write_sem);
+	mutex_unlock(&info->write_mtx);
 	return retval;
 }
 
@@ -1852,6 +1851,12 @@ #endif
 
 #ifdef CONFIG_PCI
 
+static struct pci_device_id __devinitdata rocket_pci_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
+
 /*
  *  Called when a PCI card is found.  Retrieves and stores model information,
  *  init's aiopic and serial port hardware.
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 3a8bcc8..89b4d7b 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -15,6 +15,8 @@ #define ROCKET_TYPE_MODEMII	2
 #define ROCKET_TYPE_MODEMIII	3
 #define ROCKET_TYPE_PC104       4
 
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -1171,7 +1173,7 @@ #else
 	struct wait_queue *close_wait;
 #endif
 	spinlock_t slock;
-	struct semaphore write_sem;
+	struct mutex write_mtx;
 };
 
 #define RPORT_MAGIC 0x525001
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index c7dac9b..20380a2 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -388,7 +388,7 @@ #else
 	if (!retval)
 		retval = count;
  out:
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&rtc_wait, &wait);
 
 	return retval;
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 74cff83..a69f094 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -299,7 +299,7 @@ int paste_selection(struct tty_struct *t
 		pasted += count;
 	}
 	remove_wait_queue(&vc->paste_wait, &wait);
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 
 	tty_ldisc_deref(ld);
 	return 0;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 5fd314a..c585b47 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1892,7 +1892,7 @@ #ifdef SERIAL_DEBUG_OPEN
 #endif
 		    schedule();
 	}
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	if (!tty_hung_up_p(filp)) {
 		info->count++;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 7823757..3ef593a 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1,6 +1,8 @@
 /*
  * Sony Programmable I/O Control Device driver for VAIO
  *
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
  * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
  *
  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
 MODULE_PARM_DESC(useinput,
 		 "set this if you would like sonypi to feed events to the input subsystem");
 
+static int check_ioport = 1;
+module_param(check_ioport, int, 0444);
+MODULE_PARM_DESC(check_ioport,
+		 "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
+
 #define SONYPI_DEVICE_MODEL_TYPE1	1
 #define SONYPI_DEVICE_MODEL_TYPE2	2
 #define SONYPI_DEVICE_MODEL_TYPE3	3
@@ -477,7 +484,7 @@ static struct sonypi_device {
 	u16 evtype_offset;
 	int camera_power;
 	int bluetooth_power;
-	struct semaphore lock;
+	struct mutex lock;
 	struct kfifo *fifo;
 	spinlock_t fifo_lock;
 	wait_queue_head_t fifo_proc_list;
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u
 	if (!camera)
 		return -EIO;
 
-	down(&sonypi_device.lock);
+	mutex_lock(&sonypi_device.lock);
 
 	switch (command) {
 	case SONYPI_COMMAND_SETCAMERA:
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u
 		       command);
 		break;
 	}
-	up(&sonypi_device.lock);
+	mutex_unlock(&sonypi_device.lock);
 	return 0;
 }
 
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, st
 static int sonypi_misc_release(struct inode *inode, struct file *file)
 {
 	sonypi_misc_fasync(-1, file, 0);
-	down(&sonypi_device.lock);
+	mutex_lock(&sonypi_device.lock);
 	sonypi_device.open_count--;
-	up(&sonypi_device.lock);
+	mutex_unlock(&sonypi_device.lock);
 	return 0;
 }
 
 static int sonypi_misc_open(struct inode *inode, struct file *file)
 {
-	down(&sonypi_device.lock);
+	mutex_lock(&sonypi_device.lock);
 	/* Flush input queue on first open */
 	if (!sonypi_device.open_count)
 		kfifo_reset(sonypi_device.fifo);
 	sonypi_device.open_count++;
-	up(&sonypi_device.lock);
+	mutex_unlock(&sonypi_device.lock);
 	return 0;
 }
 
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inod
 	u8 val8;
 	u16 val16;
 
-	down(&sonypi_device.lock);
+	mutex_lock(&sonypi_device.lock);
 	switch (cmd) {
 	case SONYPI_IOCGBRT:
 		if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inod
 	default:
 		ret = -EINVAL;
 	}
-	up(&sonypi_device.lock);
+	mutex_unlock(&sonypi_device.lock);
 	return ret;
 }
 
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input
 static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
 				const struct sonypi_ioport_list *ioport_list)
 {
+	/* try to detect if sony-laptop is being used and thus
+	 * has already requested one of the known ioports.
+	 * As in the deprecated check_region this is racy has we have
+	 * multiple ioports available and one of them can be requested
+	 * between this check and the subsequent request. Anyway, as an
+	 * attempt to be some more user-friendly as we currently are,
+	 * this is enough.
+	 */
+	const struct sonypi_ioport_list *check = ioport_list;
+	while (check_ioport && check->port1) {
+		if (!request_region(check->port1,
+				   sonypi_device.region_size,
+				   "Sony Programable I/O Device Check")) {
+			printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
+					"if not use check_ioport=0\n",
+					check->port1);
+			return -EBUSY;
+		}
+		release_region(check->port1, sonypi_device.region_size);
+		check++;
+	}
+
 	while (ioport_list->port1) {
 
 		if (request_region(ioport_list->port1,
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct
 	struct pci_dev *pcidev;
 	int error;
 
+	printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
+			"and report failures, see also "
+			"http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
+
 	spin_lock_init(&sonypi_device.fifo_lock);
 	sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
 					 &sonypi_device.fifo_lock);
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct
 	}
 
 	init_waitqueue_head(&sonypi_device.fifo_proc_list);
-	init_MUTEX(&sonypi_device.lock);
+	mutex_init(&sonypi_device.lock);
 	sonypi_device.bluetooth_power = -1;
 
 	if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index ce4db6f..f02a079 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -4010,8 +4010,13 @@ static int mgsl_alloc_intermediate_txbuf
 	for ( i=0; i<info->num_tx_holding_buffers; ++i) {
 		info->tx_holding_buffers[i].buffer =
 			kmalloc(info->max_frame_size, GFP_KERNEL);
-		if ( info->tx_holding_buffers[i].buffer == NULL )
+		if (info->tx_holding_buffers[i].buffer == NULL) {
+			for (--i; i >= 0; i--) {
+				kfree(info->tx_holding_buffers[i].buffer);
+				info->tx_holding_buffers[i].buffer = NULL;
+			}
 			return -ENOMEM;
+		}
 	}
 
 	return 0;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 0a367cd..2a7736b 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -3415,6 +3415,9 @@ static void device_init(int adapter_num,
 			}
 		}
 	}
+
+	for (i=0; i < port_count; ++i)
+		tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
 }
 
 static int __devinit init_one(struct pci_dev *dev,
@@ -3466,6 +3469,8 @@ static void slgt_cleanup(void)
 	printk("unload %s %s\n", driver_name, driver_version);
 
 	if (serial_driver) {
+		for (info=slgt_device_list ; info != NULL ; info=info->next_device)
+			tty_unregister_device(serial_driver, info->line);
 		if ((rc = tty_unregister_driver(serial_driver)))
 			DBGERR(("tty_unregister_driver error=%d\n", rc));
 		put_tty_driver(serial_driver);
@@ -3506,23 +3511,10 @@ static int __init slgt_init(void)
 
  	printk("%s %s\n", driver_name, driver_version);
 
-	slgt_device_count = 0;
-	if ((rc = pci_register_driver(&pci_driver)) < 0) {
-		printk("%s pci_register_driver error=%d\n", driver_name, rc);
-		return rc;
-	}
-	pci_registered = 1;
-
-	if (!slgt_device_list) {
-		printk("%s no devices found\n",driver_name);
-		pci_unregister_driver(&pci_driver);
-		return -ENODEV;
-	}
-
 	serial_driver = alloc_tty_driver(MAX_DEVICES);
 	if (!serial_driver) {
-		rc = -ENOMEM;
-		goto error;
+		printk("%s can't allocate tty driver\n", driver_name);
+		return -ENOMEM;
 	}
 
 	/* Initialize the tty_driver structure */
@@ -3539,7 +3531,7 @@ static int __init slgt_init(void)
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	serial_driver->init_termios.c_ispeed = 9600;
 	serial_driver->init_termios.c_ospeed = 9600;
-	serial_driver->flags = TTY_DRIVER_REAL_RAW;
+	serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
 	tty_set_operations(serial_driver, &ops);
 	if ((rc = tty_register_driver(serial_driver)) < 0) {
 		DBGERR(("%s can't register serial driver\n", driver_name));
@@ -3552,6 +3544,16 @@ static int __init slgt_init(void)
 		driver_name, driver_version,
 		serial_driver->major);
 
+	slgt_device_count = 0;
+	if ((rc = pci_register_driver(&pci_driver)) < 0) {
+		printk("%s pci_register_driver error=%d\n", driver_name, rc);
+		goto error;
+	}
+	pci_registered = 1;
+
+	if (!slgt_device_list)
+		printk("%s no devices found\n",driver_name);
+
 	return 0;
 
 error:
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1d8c4ae..39cc318 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -24,7 +24,6 @@ #include <linux/reboot.h>
 #include <linux/sysrq.h>
 #include <linux/kbd_kern.h>
 #include <linux/quotaops.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 47fb20f..35b40b9 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -442,7 +442,7 @@ tipar_register(int nr, struct parport *p
 	}
 
 	class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
-			TIPAR_MINOR + nr), NULL, "par%d", nr);
+			TIPAR_MINOR + nr), port->dev, "par%d", nr);
 
 	/* Display informations */
 	pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index e5a254a..9bb5429 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -24,7 +24,9 @@
  */
 
 #include <linux/poll.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
+
 #include "tpm.h"
 
 enum tpm_const {
@@ -328,10 +330,10 @@ static void timeout_work(struct work_str
 {
 	struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
 
-	down(&chip->buffer_mutex);
+	mutex_lock(&chip->buffer_mutex);
 	atomic_set(&chip->data_pending, 0);
 	memset(chip->data_buffer, 0, TPM_BUFSIZE);
-	up(&chip->buffer_mutex);
+	mutex_unlock(&chip->buffer_mutex);
 }
 
 /*
@@ -380,7 +382,7 @@ static ssize_t tpm_transmit(struct tpm_c
 		return -E2BIG;
 	}
 
-	down(&chip->tpm_mutex);
+	mutex_lock(&chip->tpm_mutex);
 
 	if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
 		dev_err(chip->dev,
@@ -419,7 +421,7 @@ out_recv:
 		dev_err(chip->dev,
 			"tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
-	up(&chip->tpm_mutex);
+	mutex_unlock(&chip->tpm_mutex);
 	return rc;
 }
 
@@ -942,12 +944,12 @@ int tpm_release(struct inode *inode, str
 {
 	struct tpm_chip *chip = file->private_data;
 
+	flush_scheduled_work();
 	spin_lock(&driver_lock);
 	file->private_data = NULL;
-	chip->num_opens--;
 	del_singleshot_timer_sync(&chip->user_read_timer);
-	flush_scheduled_work();
 	atomic_set(&chip->data_pending, 0);
+	chip->num_opens--;
 	put_device(chip->dev);
 	kfree(chip->data_buffer);
 	spin_unlock(&driver_lock);
@@ -966,14 +968,14 @@ ssize_t tpm_write(struct file *file, con
 	while (atomic_read(&chip->data_pending) != 0)
 		msleep(TPM_TIMEOUT);
 
-	down(&chip->buffer_mutex);
+	mutex_lock(&chip->buffer_mutex);
 
 	if (in_size > TPM_BUFSIZE)
 		in_size = TPM_BUFSIZE;
 
 	if (copy_from_user
 	    (chip->data_buffer, (void __user *) buf, in_size)) {
-		up(&chip->buffer_mutex);
+		mutex_unlock(&chip->buffer_mutex);
 		return -EFAULT;
 	}
 
@@ -981,7 +983,7 @@ ssize_t tpm_write(struct file *file, con
 	out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
 
 	atomic_set(&chip->data_pending, out_size);
-	up(&chip->buffer_mutex);
+	mutex_unlock(&chip->buffer_mutex);
 
 	/* Set a timeout by which the reader must come claim the result */
 	mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
@@ -1004,10 +1006,10 @@ ssize_t tpm_read(struct file *file, char
 		if (size < ret_size)
 			ret_size = size;
 
-		down(&chip->buffer_mutex);
+		mutex_lock(&chip->buffer_mutex);
 		if (copy_to_user(buf, chip->data_buffer, ret_size))
 			ret_size = -EFAULT;
-		up(&chip->buffer_mutex);
+		mutex_unlock(&chip->buffer_mutex);
 	}
 
 	return ret_size;
@@ -1097,11 +1099,16 @@ #define DEVNAME_SIZE 7
 
 	/* Driver specific per-device data */
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
+	devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+
+	if (chip == NULL || devname == NULL) {
+		kfree(chip);
+		kfree(devname);
 		return NULL;
+	}
 
-	init_MUTEX(&chip->buffer_mutex);
-	init_MUTEX(&chip->tpm_mutex);
+	mutex_init(&chip->buffer_mutex);
+	mutex_init(&chip->tpm_mutex);
 	INIT_LIST_HEAD(&chip->list);
 
 	INIT_WORK(&chip->work, timeout_work);
@@ -1124,7 +1131,6 @@ #define DEVNAME_SIZE 7
 
 	set_bit(chip->dev_num, dev_mask);
 
-	devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
 	scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
 	chip->vendor.miscdev.name = devname;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index bb9a43c..b2e2b00 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -19,9 +19,9 @@
  * 
  */
 #include <linux/module.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/miscdevice.h>
 #include <linux/platform_device.h>
@@ -95,11 +95,11 @@ struct tpm_chip {
 	/* Data passed to and from the tpm via the read/write calls */
 	u8 *data_buffer;
 	atomic_t data_pending;
-	struct semaphore buffer_mutex;
+	struct mutex buffer_mutex;
 
 	struct timer_list user_read_timer;	/* user needs to claim result */
 	struct work_struct work;
-	struct semaphore tpm_mutex;	/* tpm is processing */
+	struct mutex tpm_mutex;	/* tpm is processing */
 
 	struct tpm_vendor_specific vendor;
 
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index aefd683..c912d86 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -47,14 +47,14 @@ static void __iomem * atmel_get_base_add
 	if (!dn)
 		return NULL;
 
-	if (!device_is_compatible(dn, "AT97SC3201")) {
+	if (!of_device_is_compatible(dn, "AT97SC3201")) {
 		of_node_put(dn);
 		return NULL;
 	}
 
-	reg = get_property(dn, "reg", &reglen);
-	naddrc = prom_n_addr_cells(dn);
-	nsizec = prom_n_size_cells(dn);
+	reg = of_get_property(dn, "reg", &reglen);
+	naddrc = of_n_addr_cells(dn);
+	nsizec = of_n_size_cells(dn);
 
 	of_node_put(dn);
 
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 1353b5a..967002a 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -30,12 +30,60 @@ #define	TPM_MSLEEP_TIME 	3
 #define	TPM_MAX_TRIES		5000
 #define	TPM_INFINEON_DEV_VEN_VALUE	0x15D1
 
-/* These values will be filled after PnP-call */
-static int TPM_INF_DATA;
-static int TPM_INF_ADDR;
-static int TPM_INF_BASE;
-static int TPM_INF_ADDR_LEN;
-static int TPM_INF_PORT_LEN;
+#define TPM_INF_IO_PORT		0x0
+#define TPM_INF_IO_MEM		0x1
+
+#define TPM_INF_ADDR		0x0
+#define TPM_INF_DATA		0x1
+
+struct tpm_inf_dev {
+	int iotype;
+
+	void __iomem *mem_base;		/* MMIO ioremap'd addr */
+	unsigned long map_base;		/* phys MMIO base */
+	unsigned long map_size;		/* MMIO region size */
+	unsigned int index_off;		/* index register offset */
+
+	unsigned int data_regs;		/* Data registers */
+	unsigned int data_size;
+
+	unsigned int config_port;	/* IO Port config index reg */
+	unsigned int config_size;
+};
+
+static struct tpm_inf_dev tpm_dev;
+
+static inline void tpm_data_out(unsigned char data, unsigned char offset)
+{
+	if (tpm_dev.iotype == TPM_INF_IO_PORT)
+		outb(data, tpm_dev.data_regs + offset);
+	else
+		writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline unsigned char tpm_data_in(unsigned char offset)
+{
+	if (tpm_dev.iotype == TPM_INF_IO_PORT)
+		return inb(tpm_dev.data_regs + offset);
+	else
+		return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline void tpm_config_out(unsigned char data, unsigned char offset)
+{
+	if (tpm_dev.iotype == TPM_INF_IO_PORT)
+		outb(data, tpm_dev.config_port + offset);
+	else
+		writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
+
+static inline unsigned char tpm_config_in(unsigned char offset)
+{
+	if (tpm_dev.iotype == TPM_INF_IO_PORT)
+		return inb(tpm_dev.config_port + offset);
+	else
+		return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
 
 /* TPM header definitions */
 enum infineon_tpm_header {
@@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *c
 
 	if (clear_wrfifo) {
 		for (i = 0; i < 4096; i++) {
-			status = inb(chip->vendor.base + WRFIFO);
+			status = tpm_data_in(WRFIFO);
 			if (status == 0xff) {
 				if (check == 5)
 					break;
@@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *c
 	 */
 	i = 0;
 	do {
-		status = inb(chip->vendor.base + RDFIFO);
-		status = inb(chip->vendor.base + STAT);
+		status = tpm_data_in(RDFIFO);
+		status = tpm_data_in(STAT);
 		i++;
 		if (i == TPM_MAX_TRIES)
 			return -EIO;
@@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, i
 	int status;
 	int i;
 	for (i = 0; i < TPM_MAX_TRIES; i++) {
-		status = inb(chip->vendor.base + STAT);
+		status = tpm_data_in(STAT);
 		/* check the status-register if wait_for_bit is set */
 		if (status & 1 << wait_for_bit)
 			break;
@@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, i
 static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
 {
 	wait(chip, STAT_XFE);
-	outb(sendbyte, chip->vendor.base + WRFIFO);
+	tpm_data_out(sendbyte, WRFIFO);
 }
 
     /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
@@ -205,7 +253,7 @@ recv_begin:
 		ret = wait(chip, STAT_RDA);
 		if (ret)
 			return -EIO;
-		buf[i] = inb(chip->vendor.base + RDFIFO);
+		buf[i] = tpm_data_in(RDFIFO);
 	}
 
 	if (buf[0] != TPM_VL_VER) {
@@ -220,7 +268,7 @@ recv_begin:
 
 		for (i = 0; i < size; i++) {
 			wait(chip, STAT_RDA);
-			buf[i] = inb(chip->vendor.base + RDFIFO);
+			buf[i] = tpm_data_in(RDFIFO);
 		}
 
 		if ((size == 0x6D00) && (buf[1] == 0x80)) {
@@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip 
 	u8 count_high, count_low, count_4, count_3, count_2, count_1;
 
 	/* Disabling Reset, LP and IRQC */
-	outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
+	tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
 
 	ret = empty_fifo(chip, 1);
 	if (ret) {
@@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_ch
 
 static u8 tpm_inf_status(struct tpm_chip *chip)
 {
-	return inb(chip->vendor.base + STAT);
+	return tpm_data_in(STAT);
 }
 
 static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
@@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(s
 	/* read IO-ports through PnP */
 	if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
 	    !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
-		TPM_INF_ADDR = pnp_port_start(dev, 0);
-		TPM_INF_ADDR_LEN = pnp_port_len(dev, 0);
-		TPM_INF_DATA = (TPM_INF_ADDR + 1);
-		TPM_INF_BASE = pnp_port_start(dev, 1);
-		TPM_INF_PORT_LEN = pnp_port_len(dev, 1);
-		if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) {
+
+	    	tpm_dev.iotype = TPM_INF_IO_PORT;
+
+		tpm_dev.config_port = pnp_port_start(dev, 0);
+		tpm_dev.config_size = pnp_port_len(dev, 0);
+		tpm_dev.data_regs = pnp_port_start(dev, 1);
+		tpm_dev.data_size = pnp_port_len(dev, 1);
+		if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
 			rc = -EINVAL;
 			goto err_last;
 		}
 		dev_info(&dev->dev, "Found %s with ID %s\n",
 			 dev->name, dev_id->id);
-		if (!((TPM_INF_BASE >> 8) & 0xff)) {
+		if (!((tpm_dev.data_regs >> 8) & 0xff)) {
 			rc = -EINVAL;
 			goto err_last;
 		}
 		/* publish my base address and request region */
-		if (request_region
-		    (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
+		if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
+				   "tpm_infineon0") == NULL) {
 			rc = -EINVAL;
 			goto err_last;
 		}
-		if (request_region
-		    (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
+		if (request_region(tpm_dev.config_port, tpm_dev.config_size,
+				   "tpm_infineon0") == NULL) {
+			release_region(tpm_dev.data_regs, tpm_dev.data_size);
 			rc = -EINVAL;
 			goto err_last;
 		}
+	} else if (pnp_mem_valid(dev, 0) &&
+	           !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
+
+	    	tpm_dev.iotype = TPM_INF_IO_MEM;
+
+		tpm_dev.map_base = pnp_mem_start(dev, 0);
+		tpm_dev.map_size = pnp_mem_len(dev, 0);
+
+		dev_info(&dev->dev, "Found %s with ID %s\n",
+			 dev->name, dev_id->id);
+
+		/* publish my base address and request region */
+		if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
+				       "tpm_infineon0") == NULL) {
+			rc = -EINVAL;
+			goto err_last;
+		}
+
+		tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
+		if (tpm_dev.mem_base == NULL) {
+			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+			rc = -EINVAL;
+			goto err_last;
+		}
+
+		/*
+		 * The only known MMIO based Infineon TPM system provides
+		 * a single large mem region with the device config
+		 * registers at the default TPM_ADDR.  The data registers
+		 * seem like they could be placed anywhere within the MMIO
+		 * region, but lets just put them at zero offset.
+		 */
+		tpm_dev.index_off = TPM_ADDR;
+		tpm_dev.data_regs = 0x0;
 	} else {
 		rc = -EINVAL;
 		goto err_last;
 	}
 
 	/* query chip for its vendor, its version number a.s.o. */
-	outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
-	outb(IDVENL, TPM_INF_ADDR);
-	vendorid[1] = inb(TPM_INF_DATA);
-	outb(IDVENH, TPM_INF_ADDR);
-	vendorid[0] = inb(TPM_INF_DATA);
-	outb(IDPDL, TPM_INF_ADDR);
-	productid[1] = inb(TPM_INF_DATA);
-	outb(IDPDH, TPM_INF_ADDR);
-	productid[0] = inb(TPM_INF_DATA);
-	outb(CHIP_ID1, TPM_INF_ADDR);
-	version[1] = inb(TPM_INF_DATA);
-	outb(CHIP_ID2, TPM_INF_ADDR);
-	version[0] = inb(TPM_INF_DATA);
+	tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
+	tpm_config_out(IDVENL, TPM_INF_ADDR);
+	vendorid[1] = tpm_config_in(TPM_INF_DATA);
+	tpm_config_out(IDVENH, TPM_INF_ADDR);
+	vendorid[0] = tpm_config_in(TPM_INF_DATA);
+	tpm_config_out(IDPDL, TPM_INF_ADDR);
+	productid[1] = tpm_config_in(TPM_INF_DATA);
+	tpm_config_out(IDPDH, TPM_INF_ADDR);
+	productid[0] = tpm_config_in(TPM_INF_DATA);
+	tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
+	version[1] = tpm_config_in(TPM_INF_DATA);
+	tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
+	version[0] = tpm_config_in(TPM_INF_DATA);
 
 	switch ((productid[0] << 8) | productid[1]) {
 	case 6:
@@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(s
 	if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
 
 		/* configure TPM with IO-ports */
-		outb(IOLIMH, TPM_INF_ADDR);
-		outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
-		outb(IOLIML, TPM_INF_ADDR);
-		outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
+		tpm_config_out(IOLIMH, TPM_INF_ADDR);
+		tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
+		tpm_config_out(IOLIML, TPM_INF_ADDR);
+		tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
 
 		/* control if IO-ports are set correctly */
-		outb(IOLIMH, TPM_INF_ADDR);
-		ioh = inb(TPM_INF_DATA);
-		outb(IOLIML, TPM_INF_ADDR);
-		iol = inb(TPM_INF_DATA);
+		tpm_config_out(IOLIMH, TPM_INF_ADDR);
+		ioh = tpm_config_in(TPM_INF_DATA);
+		tpm_config_out(IOLIML, TPM_INF_ADDR);
+		iol = tpm_config_in(TPM_INF_DATA);
 
-		if ((ioh << 8 | iol) != TPM_INF_BASE) {
+		if ((ioh << 8 | iol) != tpm_dev.data_regs) {
 			dev_err(&dev->dev,
-				"Could not set IO-ports to 0x%x\n",
-				TPM_INF_BASE);
+				"Could not set IO-data registers to 0x%x\n",
+				tpm_dev.data_regs);
 			rc = -EIO;
 			goto err_release_region;
 		}
 
 		/* activate register */
-		outb(TPM_DAR, TPM_INF_ADDR);
-		outb(0x01, TPM_INF_DATA);
-		outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
+		tpm_config_out(TPM_DAR, TPM_INF_ADDR);
+		tpm_config_out(0x01, TPM_INF_DATA);
+		tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
 
 		/* disable RESET, LP and IRQC */
-		outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
+		tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
 
 		/* Finally, we're done, print some infos */
 		dev_info(&dev->dev, "TPM found: "
-			 "config base 0x%x, "
-			 "io base 0x%x, "
+			 "config base 0x%lx, "
+			 "data base 0x%lx, "
 			 "chip version 0x%02x%02x, "
 			 "vendor id 0x%x%x (Infineon), "
 			 "product id 0x%02x%02x"
 			 "%s\n",
-			 TPM_INF_ADDR,
-			 TPM_INF_BASE,
+			 tpm_dev.iotype == TPM_INF_IO_PORT ?
+				tpm_dev.config_port :
+				tpm_dev.map_base + tpm_dev.index_off,
+			 tpm_dev.iotype == TPM_INF_IO_PORT ?
+				tpm_dev.data_regs :
+				tpm_dev.map_base + tpm_dev.data_regs,
 			 version[0], version[1],
 			 vendorid[0], vendorid[1],
 			 productid[0], productid[1], chipname);
 
-		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
+		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
 			goto err_release_region;
-		}
-		chip->vendor.base = TPM_INF_BASE;
+
 		return 0;
 	} else {
 		rc = -ENODEV;
@@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(s
 	}
 
 err_release_region:
-	release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
-	release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+		release_region(tpm_dev.data_regs, tpm_dev.data_size);
+		release_region(tpm_dev.config_port, tpm_dev.config_size);
+	} else {
+		iounmap(tpm_dev.mem_base);
+		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+	}
 
 err_last:
 	return rc;
@@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove
 	struct tpm_chip *chip = pnp_get_drvdata(dev);
 
 	if (chip) {
-		release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
-		release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+		if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+			release_region(tpm_dev.data_regs, tpm_dev.data_size);
+			release_region(tpm_dev.config_port,
+				       tpm_dev.config_size);
+		} else {
+			iounmap(tpm_dev.mem_base);
+			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+		}
 		tpm_remove_hardware(chip->dev);
 	}
 }
@@ -539,5 +638,5 @@ module_exit(cleanup_inf);
 
 MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
-MODULE_VERSION("1.8");
+MODULE_VERSION("1.9");
 MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7a32df5..7710a6a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock
 static int ptmx_open(struct inode *, struct file *);
 #endif
 
-extern void disable_early_printk(void);
-
 static void initialize_tty_struct(struct tty_struct *tty);
 
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
@@ -155,8 +153,8 @@ int tty_ioctl(struct inode * inode, stru
 	      unsigned int cmd, unsigned long arg);
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_tty(struct tty_struct *tty, int idx);
-static struct pid *__proc_set_tty(struct task_struct *tsk,
-				struct tty_struct *tty);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
 
 /**
  *	alloc_tty_struct	-	allocate a tty object
@@ -1534,10 +1532,9 @@ void disassociate_ctty(int on_exit)
 	}
 
 	spin_lock_irq(&current->sighand->siglock);
-	tty_pgrp = current->signal->tty_old_pgrp;
+	put_pid(current->signal->tty_old_pgrp);
 	current->signal->tty_old_pgrp = NULL;
 	spin_unlock_irq(&current->sighand->siglock);
-	put_pid(tty_pgrp);
 
 	mutex_lock(&tty_mutex);
 	/* It is possible that do_tty_hangup has free'd this tty */
@@ -1562,6 +1559,18 @@ #endif
 	unlock_kernel();
 }
 
+/**
+ *
+ *	no_tty	- Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+	struct task_struct *tsk = current;
+	if (tsk->signal->leader)
+		disassociate_ctty(0);
+	proc_clear_tty(tsk);
+}
+
 
 /**
  *	stop_tty	-	propogate flow control
@@ -2508,7 +2517,6 @@ static int tty_open(struct inode * inode
 	int index;
 	dev_t device = inode->i_rdev;
 	unsigned short saved_flags = filp->f_flags;
-	struct pid *old_pgrp;
 
 	nonseekable_open(inode, filp);
 	
@@ -2602,17 +2610,15 @@ #endif
 		goto retry_open;
 	}
 
-	old_pgrp = NULL;
 	mutex_lock(&tty_mutex);
 	spin_lock_irq(&current->sighand->siglock);
 	if (!noctty &&
 	    current->signal->leader &&
 	    !current->signal->tty &&
 	    tty->session == NULL)
-		old_pgrp = __proc_set_tty(current, tty);
+		__proc_set_tty(current, tty);
 	spin_unlock_irq(&current->sighand->siglock);
 	mutex_unlock(&tty_mutex);
-	put_pid(old_pgrp);
 	return 0;
 }
 
@@ -3287,9 +3293,7 @@ int tty_ioctl(struct inode * inode, stru
 		case TIOCNOTTY:
 			if (current->signal->tty != tty)
 				return -ENOTTY;
-			if (current->signal->leader)
-				disassociate_ctty(0);
-			proc_clear_tty(current);
+			no_tty();
 			return 0;
 		case TIOCSCTTY:
 			return tiocsctty(tty, arg);
@@ -3720,11 +3724,10 @@ int tty_register_driver(struct tty_drive
 	if (driver->flags & TTY_DRIVER_INSTALLED)
 		return 0;
 
-	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-		p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+		p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
 		if (!p)
 			return -ENOMEM;
-		memset(p, 0, driver->num * 3 * sizeof(void *));
 	}
 
 	if (!driver->major) {
@@ -3767,7 +3770,9 @@ int tty_register_driver(struct tty_drive
 	if (!driver->put_char)
 		driver->put_char = tty_default_put_char;
 	
+	mutex_lock(&tty_mutex);
 	list_add(&driver->tty_drivers, &tty_drivers);
+	mutex_unlock(&tty_mutex);
 	
 	if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
 		for(i = 0; i < driver->num; i++)
@@ -3793,8 +3798,9 @@ int tty_unregister_driver(struct tty_dri
 
 	unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
 				driver->num);
-
+	mutex_lock(&tty_mutex);
 	list_del(&driver->tty_drivers);
+	mutex_unlock(&tty_mutex);
 
 	/*
 	 * Free the termios and termios_locked structures because
@@ -3837,11 +3843,9 @@ void proc_clear_tty(struct task_struct *
 	p->signal->tty = NULL;
 	spin_unlock_irq(&p->sighand->siglock);
 }
-EXPORT_SYMBOL(proc_clear_tty);
 
-static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
-	struct pid *old_pgrp;
 	if (tty) {
 		/* We should not have a session or pgrp to here but.... */
 		put_pid(tty->session);
@@ -3849,21 +3853,16 @@ static struct pid *__proc_set_tty(struct
 		tty->session = get_pid(task_session(tsk));
 		tty->pgrp = get_pid(task_pgrp(tsk));
 	}
-	old_pgrp = tsk->signal->tty_old_pgrp;
+	put_pid(tsk->signal->tty_old_pgrp);
 	tsk->signal->tty = tty;
 	tsk->signal->tty_old_pgrp = NULL;
-	return old_pgrp;
 }
 
-void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
-	struct pid *old_pgrp;
-
 	spin_lock_irq(&tsk->sighand->siglock);
-	old_pgrp = __proc_set_tty(tsk, tty);
+	__proc_set_tty(tsk, tty);
 	spin_unlock_irq(&tsk->sighand->siglock);
-
-	put_pid(old_pgrp);
 }
 
 struct tty_struct *get_current_tty(void)
@@ -3898,9 +3897,6 @@ void __init console_init(void)
 	 * set up the console device so that later boot sequences can 
 	 * inform about problems etc..
 	 */
-#ifdef CONFIG_EARLY_PRINTK
-	disable_early_printk();
-#endif
 	call = __con_initcall_start;
 	while (call < __con_initcall_end) {
 		(*call)();
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 7919303..83aeedd 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -28,12 +28,13 @@ #include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/kbd_kern.h>
 #include <linux/console.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
+
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
@@ -70,11 +71,11 @@ static loff_t vcs_lseek(struct file *fil
 {
 	int size;
 
-	down(&con_buf_sem);
+	mutex_lock(&con_buf_mtx);
 	size = vcs_size(file->f_path.dentry->d_inode);
 	switch (orig) {
 		default:
-			up(&con_buf_sem);
+			mutex_unlock(&con_buf_mtx);
 			return -EINVAL;
 		case 2:
 			offset += size;
@@ -85,11 +86,11 @@ static loff_t vcs_lseek(struct file *fil
 			break;
 	}
 	if (offset < 0 || offset > size) {
-		up(&con_buf_sem);
+		mutex_unlock(&con_buf_mtx);
 		return -EINVAL;
 	}
 	file->f_pos = offset;
-	up(&con_buf_sem);
+	mutex_unlock(&con_buf_mtx);
 	return file->f_pos;
 }
 
@@ -106,7 +107,7 @@ vcs_read(struct file *file, char __user 
 	unsigned short *org = NULL;
 	ssize_t ret;
 
-	down(&con_buf_sem);
+	mutex_lock(&con_buf_mtx);
 
 	pos = *ppos;
 
@@ -263,7 +264,7 @@ vcs_read(struct file *file, char __user 
 		ret = read;
 unlock_out:
 	release_console_sem();
-	up(&con_buf_sem);
+	mutex_unlock(&con_buf_mtx);
 	return ret;
 }
 
@@ -280,7 +281,7 @@ vcs_write(struct file *file, const char 
 	u16 *org0 = NULL, *org = NULL;
 	size_t ret;
 
-	down(&con_buf_sem);
+	mutex_lock(&con_buf_mtx);
 
 	pos = *ppos;
 
@@ -450,7 +451,7 @@ #endif
 unlock_out:
 	release_console_sem();
 
-	up(&con_buf_sem);
+	mutex_unlock(&con_buf_mtx);
 
 	return ret;
 }
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 1bbb45b..bbd9fc4 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -86,6 +86,7 @@ #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/console.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/tiocl.h>
@@ -157,6 +158,8 @@ static void blank_screen_t(unsigned long
 static void set_palette(struct vc_data *vc);
 
 static int printable;		/* Is console ready for printing? */
+static int default_utf8;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
 
 /*
  * ignore_poke: don't unblank the screen when things are typed.  This is
@@ -348,10 +351,12 @@ void update_region(struct vc_data *vc, u
 
 /* Structure of attributes is hardware-dependent */
 
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+    u8 _underline, u8 _reverse, u8 _italic)
 {
 	if (vc->vc_sw->con_build_attr)
-		return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse);
+		return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+		       _blink, _underline, _reverse, _italic);
 
 #ifndef VT_BUF_VRAM_ONLY
 /*
@@ -368,10 +373,13 @@ #ifndef VT_BUF_VRAM_ONLY
 	u8 a = vc->vc_color;
 	if (!vc->vc_can_do_color)
 		return _intensity |
+		       (_italic ? 2 : 0) |
 		       (_underline ? 4 : 0) |
 		       (_reverse ? 8 : 0) |
 		       (_blink ? 0x80 : 0);
-	if (_underline)
+	if (_italic)
+		a = (a & 0xF0) | vc->vc_itcolor;
+	else if (_underline)
 		a = (a & 0xf0) | vc->vc_ulcolor;
 	else if (_intensity == 0)
 		a = (a & 0xf0) | vc->vc_ulcolor;
@@ -392,8 +400,10 @@ #endif
 
 static void update_attr(struct vc_data *vc)
 {
-	vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm);
-	vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';
+	vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+	              vc->vc_blink, vc->vc_underline,
+	              vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+	vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
 }
 
 /* Note: inverting the screen twice should revert to the original state */
@@ -934,6 +944,10 @@ int default_grn[] = {0x00,0x00,0xaa,0x55
 int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
     0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
 
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
 /*
  * gotoxy() must verify all boundaries, because the arguments
  * might also be negative. If the given position is out of
@@ -1132,6 +1146,7 @@ static void csi_X(struct vc_data *vc, in
 static void default_attr(struct vc_data *vc)
 {
 	vc->vc_intensity = 1;
+	vc->vc_italic = 0;
 	vc->vc_underline = 0;
 	vc->vc_reverse = 0;
 	vc->vc_blink = 0;
@@ -1154,6 +1169,9 @@ static void csi_m(struct vc_data *vc)
 			case 2:
 				vc->vc_intensity = 0;
 				break;
+			case 3:
+				vc->vc_italic = 1;
+				break;
 			case 4:
 				vc->vc_underline = 1;
 				break;
@@ -1194,6 +1212,9 @@ static void csi_m(struct vc_data *vc)
 			case 22:
 				vc->vc_intensity = 1;
 				break;
+			case 23:
+				vc->vc_italic = 0;
+				break;
 			case 24:
 				vc->vc_underline = 0;
 				break;
@@ -1454,6 +1475,7 @@ static void save_cur(struct vc_data *vc)
 	vc->vc_saved_x		= vc->vc_x;
 	vc->vc_saved_y		= vc->vc_y;
 	vc->vc_s_intensity	= vc->vc_intensity;
+	vc->vc_s_italic         = vc->vc_italic;
 	vc->vc_s_underline	= vc->vc_underline;
 	vc->vc_s_blink		= vc->vc_blink;
 	vc->vc_s_reverse	= vc->vc_reverse;
@@ -1468,6 +1490,7 @@ static void restore_cur(struct vc_data *
 {
 	gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
 	vc->vc_intensity	= vc->vc_s_intensity;
+	vc->vc_italic		= vc->vc_s_italic;
 	vc->vc_underline	= vc->vc_s_underline;
 	vc->vc_blink		= vc->vc_s_blink;
 	vc->vc_reverse		= vc->vc_s_reverse;
@@ -1497,7 +1520,7 @@ static void reset_terminal(struct vc_dat
 	vc->vc_charset		= 0;
 	vc->vc_need_wrap	= 0;
 	vc->vc_report_mouse	= 0;
-	vc->vc_utf		= 0;
+	vc->vc_utf              = default_utf8;
 	vc->vc_utf_count	= 0;
 
 	vc->vc_disp_ctrl	= 0;
@@ -1930,7 +1953,47 @@ static void do_con_trol(struct tty_struc
  * kernel memory allocation is available.
  */
 char con_buf[CON_BUF_SIZE];
-DECLARE_MUTEX(con_buf_sem);
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2003-05-20 (Unicode 4.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+	uint32_t first;
+	uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+	int min = 0;
+	int mid;
+
+	if (ucs < table[0].first || ucs > table[max].last)
+		return 0;
+	while (max >= min) {
+		mid = (min + max) / 2;
+		if (ucs > table[mid].last)
+			min = mid + 1;
+		else if (ucs < table[mid].first)
+			max = mid - 1;
+		else
+			return 1;
+	}
+	return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+	static const struct interval double_width[] = {
+		{ 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+		{ 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+		{ 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 },
+		{ 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+	};
+	return bisearch(ucs, double_width,
+		sizeof(double_width) / sizeof(*double_width) - 1);
+}
 
 /* acquires console_sem */
 static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1948,6 +2011,10 @@ #endif
 	unsigned int currcons;
 	unsigned long draw_from = 0, draw_to = 0;
 	struct vc_data *vc;
+	unsigned char vc_attr;
+	uint8_t rescan;
+	uint8_t inverse;
+	uint8_t width;
 	u16 himask, charmask;
 	const unsigned char *orig_buf = NULL;
 	int orig_count;
@@ -1983,7 +2050,7 @@ #endif
 
 	/* At this point 'buf' is guaranteed to be a kernel buffer
 	 * and therefore no access to userspace (and therefore sleeping)
-	 * will be needed.  The con_buf_sem serializes all tty based
+	 * will be needed.  The con_buf_mtx serializes all tty based
 	 * console rendering and vcs write/read operations.  We hold
 	 * the console spinlock during the entire write.
 	 */
@@ -2010,53 +2077,86 @@ #endif
 		buf++;
 		n++;
 		count--;
+		rescan = 0;
+		inverse = 0;
+		width = 1;
 
 		/* Do no translation at all in control states */
 		if (vc->vc_state != ESnormal) {
 			tc = c;
 		} else if (vc->vc_utf && !vc->vc_disp_ctrl) {
-		    /* Combine UTF-8 into Unicode */
-		    /* Malformed sequences as sequences of replacement glyphs */
+		    /* Combine UTF-8 into Unicode in vc_utf_char.
+		     * vc_utf_count is the number of continuation bytes still
+		     * expected to arrive.
+		     * vc_npar is the number of continuation bytes arrived so
+		     * far
+		     */
 rescan_last_byte:
-		    if(c > 0x7f) {
+		    if ((c & 0xc0) == 0x80) {
+			/* Continuation byte received */
+			static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
 			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);
-				} else if ((c & 0xf0) == 0xe0) {
-				    vc->vc_utf_count = 2;
-				    vc->vc_utf_char = (c & 0x0f);
-				} else if ((c & 0xf8) == 0xf0) {
-				    vc->vc_utf_count = 3;
-				    vc->vc_utf_char = (c & 0x07);
-				} else if ((c & 0xfc) == 0xf8) {
-				    vc->vc_utf_count = 4;
-				    vc->vc_utf_char = (c & 0x03);
-				} else if ((c & 0xfe) == 0xfc) {
-				    vc->vc_utf_count = 5;
-				    vc->vc_utf_char = (c & 0x01);
-				} else
-	    			    goto replacement_glyph;
+			    vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+			    vc->vc_npar++;
+			    if (--vc->vc_utf_count) {
+				/* Still need some bytes */
 				continue;
-			      }
+			    }
+			    /* Got a whole character */
+			    c = vc->vc_utf_char;
+			    /* Reject overlong sequences */
+			    if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+					c > utf8_length_changes[vc->vc_npar])
+				c = 0xfffd;
+			} else {
+			    /* Unexpected continuation byte */
+			    vc->vc_utf_count = 0;
+			    c = 0xfffd;
+			}
 		    } else {
-		      if (vc->vc_utf_count)
-	  		      goto replacement_glyph;
-		      tc = c;
+			/* Single ASCII byte or first byte of a sequence received */
+			if (vc->vc_utf_count) {
+			    /* Continuation byte expected */
+			    rescan = 1;
+			    vc->vc_utf_count = 0;
+			    c = 0xfffd;
+			} else if (c > 0x7f) {
+			    /* First byte of a multibyte sequence received */
+			    vc->vc_npar = 0;
+			    if ((c & 0xe0) == 0xc0) {
+				vc->vc_utf_count = 1;
+				vc->vc_utf_char = (c & 0x1f);
+			    } else if ((c & 0xf0) == 0xe0) {
+				vc->vc_utf_count = 2;
+				vc->vc_utf_char = (c & 0x0f);
+			    } else if ((c & 0xf8) == 0xf0) {
+				vc->vc_utf_count = 3;
+				vc->vc_utf_char = (c & 0x07);
+			    } else if ((c & 0xfc) == 0xf8) {
+				vc->vc_utf_count = 4;
+				vc->vc_utf_char = (c & 0x03);
+			    } else if ((c & 0xfe) == 0xfc) {
+				vc->vc_utf_count = 5;
+				vc->vc_utf_char = (c & 0x01);
+			    } else {
+				/* 254 and 255 are invalid */
+				c = 0xfffd;
+			    }
+			    if (vc->vc_utf_count) {
+				/* Still need some bytes */
+				continue;
+			    }
+			}
+			/* Nothing to do if an ASCII byte was received */
 		    }
+		    /* End of UTF-8 decoding. */
+		    /* c is the received character, or U+FFFD for invalid sequences. */
+		    /* Replace invalid Unicode code points with U+FFFD too */
+		    if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+			c = 0xfffd;
+		    tc = c;
 		} else {	/* no utf or alternate charset mode */
-		  tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
+		    tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
 		}
 
                 /* If the original code was a control character we
@@ -2076,56 +2176,80 @@ rescan_last_byte:
 			&& (c != 128+27);
 
 		if (vc->vc_state == ESnormal && ok) {
+			if (vc->vc_utf && !vc->vc_disp_ctrl) {
+				if (is_double_width(c))
+					width = 2;
+			}
 			/* Now try to find out how to display it */
 			tc = conv_uni_to_pc(vc, tc);
 			if (tc & ~charmask) {
-				if ( tc == -4 ) {
-                                /* If we got -4 (not found) then see if we have
-                                   defined a replacement character (U+FFFD) */
-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;
+				if (tc == -1 || tc == -2) {
+				    continue; /* nothing to display */
+				}
+				/* Glyph not found */
+				if (!(vc->vc_utf && !vc->vc_disp_ctrl) && !(c & ~charmask)) {
+				    /* In legacy mode use the glyph we get by a 1:1 mapping.
+				       This would make absolutely no sense with Unicode in mind. */
+				    tc = c;
+				} else {
+				    /* Display U+FFFD. If it's not found, display an inverse question mark. */
+				    tc = conv_uni_to_pc(vc, 0xfffd);
+				    if (tc < 0) {
+					inverse = 1;
+					tc = conv_uni_to_pc(vc, '?');
+					if (tc < 0) tc = '?';
+				    }
+				}
 			}
 
-display_glyph:
-			if (vc->vc_need_wrap || vc->vc_decim)
-				FLUSH
-			if (vc->vc_need_wrap) {
-				cr(vc);
-				lf(vc);
-			}
-			if (vc->vc_decim)
-				insert_char(vc, 1);
-			scr_writew(himask ?
-				     ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-				     (vc->vc_attr << 8) + tc,
-				   (u16 *) vc->vc_pos);
-			if (DO_UPDATE(vc) && draw_x < 0) {
-				draw_x = vc->vc_x;
-				draw_from = vc->vc_pos;
-			}
-			if (vc->vc_x == vc->vc_cols - 1) {
-				vc->vc_need_wrap = vc->vc_decawm;
-				draw_to = vc->vc_pos + 2;
+			if (!inverse) {
+				vc_attr = vc->vc_attr;
 			} else {
-				vc->vc_x++;
-				draw_to = (vc->vc_pos += 2);
+				/* invert vc_attr */
+				if (!vc->vc_can_do_color) {
+					vc_attr = (vc->vc_attr) ^ 0x08;
+				} else if (vc->vc_hi_font_mask == 0x100) {
+					vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+				} else {
+					vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+				}
 			}
-			if (vc->vc_utf_count) {
-				if (vc->vc_npar) {
-					vc->vc_npar--;
-					goto display_glyph;
+
+			while (1) {
+				if (vc->vc_need_wrap || vc->vc_decim)
+					FLUSH
+				if (vc->vc_need_wrap) {
+					cr(vc);
+					lf(vc);
+				}
+				if (vc->vc_decim)
+					insert_char(vc, 1);
+				scr_writew(himask ?
+					     ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+					     (vc_attr << 8) + tc,
+					   (u16 *) vc->vc_pos);
+				if (DO_UPDATE(vc) && draw_x < 0) {
+					draw_x = vc->vc_x;
+					draw_from = vc->vc_pos;
+				}
+				if (vc->vc_x == vc->vc_cols - 1) {
+					vc->vc_need_wrap = vc->vc_decawm;
+					draw_to = vc->vc_pos + 2;
+				} else {
+					vc->vc_x++;
+					draw_to = (vc->vc_pos += 2);
 				}
-				vc->vc_utf_count = 0;
+
+				if (!--width) break;
+
+				tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+				if (tc < 0) tc = ' ';
+			}
+
+			if (rescan) {
+				rescan = 0;
+				inverse = 0;
+				width = 1;
 				c = orig;
 				goto rescan_last_byte;
 			}
@@ -2581,6 +2705,11 @@ static void con_close(struct tty_struct 
 	mutex_unlock(&tty_mutex);
 }
 
+static int default_italic_color    = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
 static void vc_init(struct vc_data *vc, unsigned int rows,
 		    unsigned int cols, int do_clear)
 {
@@ -2600,7 +2729,8 @@ static void vc_init(struct vc_data *vc, 
 		vc->vc_palette[k++] = default_blu[j] ;
 	}
 	vc->vc_def_color       = 0x07;   /* white */
-	vc->vc_ulcolor		= 0x0f;   /* bold white */
+	vc->vc_ulcolor         = default_underline_color;
+	vc->vc_itcolor         = default_italic_color;
 	vc->vc_halfcolor       = 0x08;   /* grey */
 	init_waitqueue_head(&vc->paste_wait);
 	reset_terminal(vc, do_clear);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c9f2dd6..c6f6f42 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -1061,7 +1061,7 @@ int vt_waitactive(int vt)
 		schedule();
 	}
 	remove_wait_queue(&vt_activate_queue, &wait);
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	return retval;
 }
 
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index e812aa1..60198a7 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -548,7 +548,7 @@ config MV64X60_WDT
 	depends on WATCHDOG && MV64X60
 
 config BOOKE_WDT
-	tristate "PowerPC Book-E Watchdog Timer"
+	bool "PowerPC Book-E Watchdog Timer"
 	depends on WATCHDOG && (BOOKE || 4xx)
 	---help---
 	  Please see Documentation/watchdog/watchdog-api.txt for
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 84074a6..b36fa8d 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -34,7 +34,6 @@ #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>
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 1e4a8d7..2f7ba7a 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -38,7 +38,6 @@ #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/pnp.h>
 #include <linux/fs.h>
-#include <linux/pci.h>
 
 #include <asm/semaphore.h>
 #include <asm/io.h>
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index fc0e034..d4fd0fa 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -25,7 +25,7 @@ #include <linux/watchdog.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
-#include <linux/pci.h>
+#include <linux/ioport.h>
 #include <linux/scx200.h>
 
 #include <asm/uaccess.h>
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5ac309e..5cfcff5 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -26,7 +26,7 @@ #include <asm/io.h>
 /*
  * The I/O port the PMTMR resides at.
  * The location is detected during setup_arch(),
- * in arch/i386/acpi/boot.c
+ * in arch/i386/kernel/acpi/boot.c
  */
 u32 pmtmr_ioport __read_mostly;
 
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a905f78..a7b9e9b 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -212,7 +212,7 @@ static void cn_rx_skb(struct sk_buff *__
 	skb = skb_get(__skb);
 
 	if (skb->len >= NLMSG_SPACE(0)) {
-		nlh = (struct nlmsghdr *)skb->data;
+		nlh = nlmsg_hdr(skb);
 
 		if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
 		    skb->len < nlh->nlmsg_len ||
@@ -448,7 +448,7 @@ static int __devinit cn_init(void)
 
 	dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
 					 CN_NETLINK_USERS + 0xf,
-					 dev->input, THIS_MODULE);
+					 dev->input, NULL, THIS_MODULE);
 	if (!dev->nls)
 		return -EIO;
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index d155e81..993fa7b 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -9,6 +9,9 @@ config CPU_FREQ
 	  clock speed, you need to either enable a dynamic cpufreq governor
 	  (see below) after boot, or use a userspace tool.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq.
+
 	  For details, take a look at <file:Documentation/cpu-freq>.
 
 	  If in doubt, say N.
@@ -16,7 +19,7 @@ config CPU_FREQ
 if CPU_FREQ
 
 config CPU_FREQ_TABLE
-       tristate
+	tristate
 
 config CPU_FREQ_DEBUG
 	bool "Enable CPUfreq debugging"
@@ -32,19 +35,26 @@ config CPU_FREQ_DEBUG
 	       4 to activate CPUfreq governor debugging
 
 config CPU_FREQ_STAT
-       tristate "CPU frequency translation statistics"
-       select CPU_FREQ_TABLE
-       default y
-       help
-         This driver exports CPU frequency statistics information through sysfs
-         file system
+	tristate "CPU frequency translation statistics"
+	select CPU_FREQ_TABLE
+	default y
+	help
+	  This driver exports CPU frequency statistics information through sysfs
+	  file system.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_stats.
+
+	  If in doubt, say N.
 
 config CPU_FREQ_STAT_DETAILS
-       bool "CPU frequency translation statistics details"
-       depends on CPU_FREQ_STAT
-       help
-         This will show detail CPU frequency translation table in sysfs file
-         system
+	bool "CPU frequency translation statistics details"
+	depends on CPU_FREQ_STAT
+	help
+	  This will show detail CPU frequency translation table in sysfs file
+	  system.
+
+	  If in doubt, say N.
 
 # Note that it is not currently possible to set the other governors (such as ondemand)
 # as the default, since if they fail to initialise, cpufreq will be
@@ -78,29 +88,38 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
-       tristate "'performance' governor"
-       help
+	tristate "'performance' governor"
+	help
 	  This cpufreq governor sets the frequency statically to the
 	  highest available CPU frequency.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_performance.
+
 	  If in doubt, say Y.
 
 config CPU_FREQ_GOV_POWERSAVE
-       tristate "'powersave' governor"
-       help
+	tristate "'powersave' governor"
+	help
 	  This cpufreq governor sets the frequency statically to the
 	  lowest available CPU frequency.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_powersave.
+
 	  If in doubt, say Y.
 
 config CPU_FREQ_GOV_USERSPACE
-       tristate "'userspace' governor for userspace frequency scaling"
-       help
+	tristate "'userspace' governor for userspace frequency scaling"
+	help
 	  Enable this cpufreq governor when you either want to set the
 	  CPU frequency manually or when an userspace program shall
 	  be able to set the CPU dynamically, like on LART 
 	  <http://www.lartmaker.nl/>.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_userspace.
+
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  If in doubt, say Y.
@@ -116,6 +135,9 @@ config CPU_FREQ_GOV_ONDEMAND
 	  do fast frequency switching (i.e, very low latency frequency
 	  transitions). 
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_ondemand.
+
 	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
@@ -136,6 +158,9 @@ config CPU_FREQ_GOV_CONSERVATIVE
 	  step-by-step latency issues between the minimum and maximum frequency
 	  transitions in the CPU) you will probably want to use this governor.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpufreq_conservative.
+
 	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3162010..893dbaf 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -768,6 +768,9 @@ #endif
 		unlock_policy_rwsem_write(cpu);
 		goto err_out;
 	}
+	policy->user_policy.min = policy->cpuinfo.min_freq;
+	policy->user_policy.max = policy->cpuinfo.max_freq;
+	policy->user_policy.governor = policy->governor;
 
 #ifdef CONFIG_SMP
 	for_each_cpu_mask(j, policy->cpus) {
@@ -858,10 +861,13 @@ #endif
 
 	policy->governor = NULL; /* to assure that the starting sequence is
 				  * run in cpufreq_set_policy */
-	unlock_policy_rwsem_write(cpu);
 
 	/* set default policy */
-	ret = cpufreq_set_policy(&new_policy);
+	ret = __cpufreq_set_policy(policy, &new_policy);
+	policy->user_policy.policy = policy->policy;
+
+	unlock_policy_rwsem_write(cpu);
+
 	if (ret) {
 		dprintk("setting policy failed\n");
 		goto err_out_unregister;
@@ -1620,43 +1626,6 @@ error_out:
 }
 
 /**
- *	cpufreq_set_policy - set a new CPUFreq policy
- *	@policy: policy to be set.
- *
- *	Sets a new CPU frequency and voltage scaling policy.
- */
-int cpufreq_set_policy(struct cpufreq_policy *policy)
-{
-	int ret = 0;
-	struct cpufreq_policy *data;
-
-	if (!policy)
-		return -EINVAL;
-
-	data = cpufreq_cpu_get(policy->cpu);
-	if (!data)
-		return -EINVAL;
-
-	if (unlikely(lock_policy_rwsem_write(policy->cpu)))
-		return -EINVAL;
-
-
-	ret = __cpufreq_set_policy(data, policy);
-	data->user_policy.min = data->min;
-	data->user_policy.max = data->max;
-	data->user_policy.policy = data->policy;
-	data->user_policy.governor = data->governor;
-
-	unlock_policy_rwsem_write(policy->cpu);
-
-	cpufreq_cpu_put(data);
-
-	return ret;
-}
-EXPORT_SYMBOL(cpufreq_set_policy);
-
-
-/**
  *	cpufreq_update_policy - re-evaluate an existing cpufreq policy
  *	@cpu: CPU which shall be re-evaluated
  *
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8d053f5..8532bb7 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -470,7 +470,7 @@ static inline void dbs_timer_init(struct
 	dbs_info->enable = 1;
 	ondemand_powersave_bias_init();
 	dbs_info->sample_type = DBS_NORMAL_SAMPLE;
-	INIT_DELAYED_WORK(&dbs_info->work, do_dbs_timer);
+	INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
 	queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
 	                      delay);
 }
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ff8c4be..f21fe66 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -1,10 +1,10 @@
 menu "Hardware crypto devices"
 
 config CRYPTO_DEV_PADLOCK
-	tristate "Support for VIA PadLock ACE"
+	bool "Support for VIA PadLock ACE"
 	depends on X86_32
 	select CRYPTO_ALGAPI
-	default m
+	default y
 	help
 	  Some VIA processors come with an integrated crypto engine
 	  (so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -14,16 +14,6 @@ config CRYPTO_DEV_PADLOCK
 	  The instructions are used only when the CPU supports them.
 	  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
 	tristate "PadLock driver for AES algorithm"
 	depends on CRYPTO_DEV_PADLOCK
@@ -55,7 +45,7 @@ source "arch/s390/crypto/Kconfig"
 
 config CRYPTO_DEV_GEODE
 	tristate "Support for the Geode LX AES engine"
-	depends on CRYPTO && X86_32 && PCI
+	depends on X86_32 && PCI
 	select CRYPTO_ALGAPI
 	select CRYPTO_BLKCIPHER
 	default m
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 6059cf8..d070030 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,4 +1,3 @@
-obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
diff --git a/drivers/crypto/padlock.c b/drivers/crypto/padlock.c
deleted file mode 100644
index d6d7dd5..0000000
--- a/drivers/crypto/padlock.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for VIA PadLock hardware crypto engine.
- *
- * Copyright (c) 2006  Michal Ludvig <michal@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/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 161fe09..2800b3e 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -261,10 +261,6 @@ static void i82875p_check(struct mem_ctl
 	i82875p_process_error_info(mci, &info, 1);
 }
 
-#ifdef CONFIG_PROC_FS
-extern int pci_proc_attach_device(struct pci_dev *);
-#endif
-
 /* Return 0 on success or 1 on failure. */
 static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
 		struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
@@ -287,17 +283,12 @@ static int i82875p_setup_overfl_dev(stru
 
 		if (dev == NULL)
 			return 1;
+
+        	pci_bus_add_device(dev);
 	}
 
 	*ovrfl_pdev = dev;
 
-#ifdef CONFIG_PROC_FS
-	if ((dev->procent == NULL) && pci_proc_attach_device(dev)) {
-		i82875p_printk(KERN_ERR, "%s(): Failed to attach overflow "
-			       "device\n", __func__);
-		return 1;
-	}
-#endif  /* CONFIG_PROC_FS */
 	if (pci_enable_device(dev)) {
 		i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
 			       "device\n", __func__);
diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c
index 9b4fcac..3074879 100644
--- a/drivers/eisa/virtual_root.c
+++ b/drivers/eisa/virtual_root.c
@@ -47,7 +47,7 @@ static void virtual_eisa_release (struct
 	/* nothing really to do here */
 }
 
-static int virtual_eisa_root_init (void)
+static int __init virtual_eisa_root_init (void)
 {
 	int r;
 	
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index c6281cc..1324984 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -409,7 +409,7 @@ static struct kobj_type ktype_efivar = {
 };
 
 static ssize_t
-dummy(struct subsystem *sub, char *buf)
+dummy(struct kset *kset, char *buf)
 {
 	return -ENODEV;
 }
@@ -422,7 +422,7 @@ efivar_unregister(struct efivar_entry *v
 
 
 static ssize_t
-efivar_create(struct subsystem *sub, const char *buf, size_t count)
+efivar_create(struct kset *kset, const char *buf, size_t count)
 {
 	struct efi_variable *new_var = (struct efi_variable *)buf;
 	struct efivar_entry *search_efivar, *n;
@@ -480,7 +480,7 @@ efivar_create(struct subsystem *sub, con
 }
 
 static ssize_t
-efivar_delete(struct subsystem *sub, const char *buf, size_t count)
+efivar_delete(struct kset *kset, const char *buf, size_t count)
 {
 	struct efi_variable *del_var = (struct efi_variable *)buf;
 	struct efivar_entry *search_efivar, *n;
@@ -551,11 +551,11 @@ static struct subsys_attribute *var_subs
  * the efivars driver
  */
 static ssize_t
-systab_read(struct subsystem *entry, char *buf)
+systab_read(struct kset *kset, char *buf)
 {
 	char *str = buf;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	if (efi.mps != EFI_INVALID_TABLE_ADDR)
@@ -687,7 +687,7 @@ efivars_init(void)
 		goto out_free;
 	}
 
-	kset_set_kset_s(&vars_subsys, efi_subsys);
+	kobj_set_kset_s(&vars_subsys, efi_subsys);
 
 	error = subsystem_register(&vars_subsys);
 
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 850788f..8fbe9fd 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -36,5 +36,7 @@ config HID_DEBUG
 
 	If unsure, say N
 
+source "drivers/hid/usbhid/Kconfig"
+
 endmenu
 
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 52e97d8..68d1376 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -6,3 +6,7 @@ hid-objs			:= hid-core.o hid-input.o
 obj-$(CONFIG_HID)		+= hid.o
 hid-$(CONFIG_HID_DEBUG)		+= hid-debug.o
 
+obj-$(CONFIG_USB_HID)		+= usbhid/
+obj-$(CONFIG_USB_MOUSE)		+= usbhid/
+obj-$(CONFIG_USB_KBD)		+= usbhid/
+
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cca32f..6ec04e7 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -4,7 +4,7 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006 Jiri Kosina
+ *  Copyright (c) 2006-2007 Jiri Kosina
  */
 
 /*
@@ -20,7 +20,6 @@ #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
@@ -37,7 +36,7 @@ #include <linux/hid-debug.h>
  */
 
 #define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
 #define DRIVER_DESC "HID core driver"
 #define DRIVER_LICENSE "GPL"
 
@@ -872,8 +871,13 @@ static void hid_output_field(struct hid_
 	unsigned count = field->report_count;
 	unsigned offset = field->report_offset;
 	unsigned size = field->report_size;
+	unsigned bitsused = offset + count * size;
 	unsigned n;
 
+	/* make sure the unused bits in the last byte are zeros */
+	if (count > 0 && size > 0 && (bitsused % 8) != 0)
+		data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
+
 	for (n = 0; n < count; n++) {
 		if (field->logical_minimum < 0)	/* signed values */
 			implement(data, offset + n * size, size, s32ton(field->value[n], size));
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c843402..a19b65e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -431,6 +431,15 @@ #endif
 				case 0x000: goto ignore;
 				case 0x034: map_key_clear(KEY_SLEEP);		break;
 				case 0x036: map_key_clear(BTN_MISC);		break;
+				/*
+				 * The next three are reported by Belkin wireless
+				 * keyboard (1020:0006). These values are "reserved"
+				 * in HUT 1.12.
+				 */
+				case 0x03a: map_key_clear(KEY_SOUND);           break;
+				case 0x03b: map_key_clear(KEY_CAMERA);          break;
+				case 0x03c: map_key_clear(KEY_DOCUMENTS);       break;
+
 				case 0x040: map_key_clear(KEY_MENU);		break;
 				case 0x045: map_key_clear(KEY_RADIO);		break;
 
@@ -531,10 +540,26 @@ #endif
 				case 0x302: map_key_clear(KEY_PROG2);		break;
 				case 0x303: map_key_clear(KEY_PROG3);		break;
 
-				/* Reported on Logitech S510 wireless keyboard */
+				/* Reported on certain Logitech wireless keyboards */
+				case 0x1001: map_key_clear(KEY_MESSENGER);	break;
+				case 0x1003: map_key_clear(KEY_SOUND);		break;
+				case 0x1004: map_key_clear(KEY_VIDEO);		break;
+				case 0x1005: map_key_clear(KEY_AUDIO);		break;
+				case 0x100a: map_key_clear(KEY_DOCUMENTS);	break;
+				case 0x1011: map_key_clear(KEY_PREVIOUSSONG);	break;
+				case 0x1012: map_key_clear(KEY_NEXTSONG);	break;
+				case 0x1013: map_key_clear(KEY_CAMERA);		break;
+				case 0x1014: map_key_clear(KEY_MESSENGER);	break;
+				case 0x1015: map_key_clear(KEY_RECORD);		break;
+				case 0x1016: map_key_clear(KEY_PLAYER);		break;
+				case 0x1017: map_key_clear(KEY_EJECTCD);	break;
+				case 0x1019: map_key_clear(KEY_PROG1);		break;
+				case 0x101a: map_key_clear(KEY_PROG2);		break;
+				case 0x101b: map_key_clear(KEY_PROG3);		break;
 				case 0x101f: map_key_clear(KEY_ZOOMIN);		break;
 				case 0x1020: map_key_clear(KEY_ZOOMOUT);	break;
 				case 0x1021: map_key_clear(KEY_ZOOMRESET);	break;
+				case 0x1023: map_key_clear(KEY_CLOSE);		break;
 				/* this one is marked as 'Rotate' */
 				case 0x1028: map_key_clear(KEY_ANGLE);		break;
 				case 0x1029: map_key_clear(KEY_SHUFFLE);	break;
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
new file mode 100644
index 0000000..7c87bdc
--- /dev/null
+++ b/drivers/hid/usbhid/Kconfig
@@ -0,0 +1,149 @@
+comment "USB Input Devices"
+	depends on USB
+
+config USB_HID
+	tristate "USB Human Interface Device (full HID) support"
+	default y
+	depends on USB && INPUT
+	select HID
+	---help---
+	  Say Y here if you want full HID support to connect USB keyboards,
+	  mice, joysticks, graphic tablets, or any other HID based devices
+	  to your computer via USB, as well as Uninterruptible Power Supply
+	  (UPS) and monitor control devices.
+
+	  You can't use this driver and the HIDBP (Boot Protocol) keyboard
+	  and mouse drivers at the same time. More information is available:
+	  <file:Documentation/input/input.txt>.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usbhid.
+
+comment "Input core support is needed for USB HID input layer or HIDBP support"
+	depends on USB_HID && INPUT=n
+
+config USB_HIDINPUT_POWERBOOK
+	bool "Enable support for iBook/PowerBook special keys"
+	default n
+	depends on USB_HID
+	help
+	  Say Y here if you want support for the special keys (Fn, Numlock) on
+	  Apple iBooks and PowerBooks.
+
+	  If unsure, say N.
+
+config HID_FF
+	bool "Force feedback support (EXPERIMENTAL)"
+	depends on USB_HID && EXPERIMENTAL
+	help
+	  Say Y here is you want force feedback support for a few HID devices.
+	  See below for a list of supported devices.
+
+	  See <file:Documentation/input/ff.txt> for a description of the force
+	  feedback API.
+
+	  If unsure, say N.
+
+config HID_PID
+	bool "PID device support"
+	depends on HID_FF
+	help
+	  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 devices 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
+	  - Logitech WingMan Cordless RumblePad 2
+	  - Logitech WingMan Force 3D
+	  - Logitech Formula Force EX
+	  - Logitech MOMO Force wheel
+
+	  and if you want to enable force feedback for them.
+	  Note: if you say N here, this device will still be supported, but without
+	  force feedback.
+
+config PANTHERLORD_FF
+	bool "PantherLord USB/PS2 2in1 Adapter support"
+	depends on HID_FF
+	select INPUT_FF_MEMLESS if USB_HID
+	help
+	  Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+	  to enable force feedback support for it.
+
+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
+	help
+	  Say Y here if you want to support HID devices (from the USB
+	  specification standpoint) that aren't strictly user interface
+	  devices, like monitor controls and Uninterruptable Power Supplies.
+
+	  This module supports these devices separately using a separate
+	  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+
+	  If unsure, say Y.
+
+menu "USB HID Boot Protocol drivers"
+	depends on USB!=n && USB_HID!=y
+
+config USB_KBD
+	tristate "USB HIDBP Keyboard (simple Boot) support"
+	depends on USB && INPUT
+	---help---
+	  Say Y here only if you are absolutely sure that you don't want
+	  to use the generic HID driver for your USB keyboard and prefer
+	  to use the keyboard in its limited Boot Protocol mode instead.
+
+	  This is almost certainly not what you want.  This is mostly
+	  useful for embedded applications or simple keyboards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usbkbd.
+
+	  If even remotely unsure, say N.
+
+config USB_MOUSE
+	tristate "USB HIDBP Mouse (simple Boot) support"
+	depends on USB && INPUT
+	---help---
+	  Say Y here only if you are absolutely sure that you don't want
+	  to use the generic HID driver for your USB mouse and prefer
+	  to use the mouse in its limited Boot Protocol mode instead.
+
+	  This is almost certainly not what you want.  This is mostly
+	  useful for embedded applications or simple mice.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usbmouse.
+
+	  If even remotely unsure, say N.
+
+endmenu
+
+
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
new file mode 100644
index 0000000..8e6ab5b
--- /dev/null
+++ b/drivers/hid/usbhid/Makefile
@@ -0,0 +1,35 @@
+#
+# Makefile for the USB input drivers
+#
+
+# Multipart objects.
+usbhid-objs	:= hid-core.o hid-quirks.o
+
+# Optional parts of multipart objects.
+
+ifeq ($(CONFIG_USB_HIDDEV),y)
+	usbhid-objs	+= hiddev.o
+endif
+ifeq ($(CONFIG_HID_PID),y)
+	usbhid-objs	+= hid-pidff.o
+endif
+ifeq ($(CONFIG_LOGITECH_FF),y)
+	usbhid-objs	+= hid-lgff.o
+endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+	usbhid-objs	+= hid-plff.o
+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
+
+obj-$(CONFIG_USB_HID)		+= usbhid.o
+obj-$(CONFIG_USB_KBD)		+= usbkbd.o
+obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
+
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
new file mode 100644
index 0000000..91d6103
--- /dev/null
+++ b/drivers/hid/usbhid/hid-core.c
@@ -0,0 +1,1114 @@
+/*
+ *  USB HID support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
+#include "usbhid.h"
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v2.6"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
+#define DRIVER_DESC "USB HID core driver"
+#define DRIVER_LICENSE "GPL"
+
+static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
+				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+/*
+ * Module parameters.
+ */
+
+static unsigned int hid_mousepoll_interval;
+module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
+MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+
+/* Quirks specified at module load time */
+static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
+MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
+		" quirks=vendorID:productID:quirks"
+		" where vendorID, productID, and quirks are all in"
+		" 0x-prefixed hex");
+/*
+ * Input submission and I/O error handler.
+ */
+
+static void hid_io_error(struct hid_device *hid);
+
+/* Start up the input URB */
+static int hid_start_in(struct hid_device *hid)
+{
+	unsigned long flags;
+	int rc = 0;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	spin_lock_irqsave(&usbhid->inlock, flags);
+	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+			!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
+		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
+		if (rc != 0)
+			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+	}
+	spin_unlock_irqrestore(&usbhid->inlock, flags);
+	return rc;
+}
+
+/* I/O retry timer routine */
+static void hid_retry_timeout(unsigned long _hid)
+{
+	struct hid_device *hid = (struct hid_device *) _hid;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
+	if (hid_start_in(hid))
+		hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device or clear a halt */
+static void hid_reset(struct work_struct *work)
+{
+	struct usbhid_device *usbhid =
+		container_of(work, struct usbhid_device, reset_work);
+	struct hid_device *hid = usbhid->hid;
+	int rc_lock, rc = 0;
+
+	if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
+		dev_dbg(&usbhid->intf->dev, "clear halt\n");
+		rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
+		clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
+		hid_start_in(hid);
+	}
+
+	else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+		dev_dbg(&usbhid->intf->dev, "resetting device\n");
+		rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
+		if (rc_lock >= 0) {
+			rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf);
+			if (rc_lock)
+				usb_unlock_device(hid_to_usb_dev(hid));
+		}
+		clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+	}
+
+	switch (rc) {
+	case 0:
+		if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
+			hid_io_error(hid);
+		break;
+	default:
+		err("can't reset device, %s-%s/input%d, status %d",
+				hid_to_usb_dev(hid)->bus->bus_name,
+				hid_to_usb_dev(hid)->devpath,
+				usbhid->ifnum, rc);
+		/* FALLTHROUGH */
+	case -EHOSTUNREACH:
+	case -ENODEV:
+	case -EINTR:
+		break;
+	}
+}
+
+/* Main I/O error handler */
+static void hid_io_error(struct hid_device *hid)
+{
+	unsigned long flags;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	spin_lock_irqsave(&usbhid->inlock, flags);
+
+	/* Stop when disconnected */
+	if (usb_get_intfdata(usbhid->intf) == NULL)
+		goto done;
+
+	/* If it has been a while since the last error, we'll assume
+	 * this a brand new error and reset the retry timeout. */
+	if (time_after(jiffies, usbhid->stop_retry + HZ/2))
+		usbhid->retry_delay = 0;
+
+	/* When an error occurs, retry at increasing intervals */
+	if (usbhid->retry_delay == 0) {
+		usbhid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
+		usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
+	} else if (usbhid->retry_delay < 100)
+		usbhid->retry_delay *= 2;
+
+	if (time_after(jiffies, usbhid->stop_retry)) {
+
+		/* Retries failed, so do a port reset */
+		if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+			schedule_work(&usbhid->reset_work);
+			goto done;
+		}
+	}
+
+	mod_timer(&usbhid->io_retry,
+			jiffies + msecs_to_jiffies(usbhid->retry_delay));
+done:
+	spin_unlock_irqrestore(&usbhid->inlock, flags);
+}
+
+/*
+ * Input interrupt completion handler.
+ */
+
+static void hid_irq_in(struct urb *urb)
+{
+	struct hid_device	*hid = urb->context;
+	struct usbhid_device 	*usbhid = hid->driver_data;
+	int			status;
+
+	switch (urb->status) {
+		case 0:			/* success */
+			usbhid->retry_delay = 0;
+			hid_input_report(urb->context, HID_INPUT_REPORT,
+					 urb->transfer_buffer,
+					 urb->actual_length, 1);
+			break;
+		case -EPIPE:		/* stall */
+			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+			set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+			schedule_work(&usbhid->reset_work);
+			return;
+		case -ECONNRESET:	/* unlink */
+		case -ENOENT:
+		case -ESHUTDOWN:	/* unplug */
+			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+			return;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
+		case -ETIME:		/* protocol error or unplug */
+		case -ETIMEDOUT:	/* Should never happen, but... */
+			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+			hid_io_error(hid);
+			return;
+		default:		/* error */
+			warn("input irq status %d received", urb->status);
+	}
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status) {
+		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+		if (status != -EPERM) {
+			err("can't resubmit intr, %s-%s/input%d, status %d",
+					hid_to_usb_dev(hid)->bus->bus_name,
+					hid_to_usb_dev(hid)->devpath,
+					usbhid->ifnum, status);
+			hid_io_error(hid);
+		}
+	}
+}
+
+static int hid_submit_out(struct hid_device *hid)
+{
+	struct hid_report *report;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	report = usbhid->out[usbhid->outtail];
+
+	hid_output_report(report, usbhid->outbuf);
+	usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+	usbhid->urbout->dev = hid_to_usb_dev(hid);
+
+	dbg("submitting out urb");
+
+	if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
+		err("usb_submit_urb(out) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hid_submit_ctrl(struct hid_device *hid)
+{
+	struct hid_report *report;
+	unsigned char dir;
+	int len;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	report = usbhid->ctrl[usbhid->ctrltail].report;
+	dir = usbhid->ctrl[usbhid->ctrltail].dir;
+
+	len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+	if (dir == USB_DIR_OUT) {
+		hid_output_report(report, usbhid->ctrlbuf);
+		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
+		usbhid->urbctrl->transfer_buffer_length = len;
+	} else {
+		int maxpacket, padlen;
+
+		usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
+		maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
+		if (maxpacket > 0) {
+			padlen = (len + maxpacket - 1) / maxpacket;
+			padlen *= maxpacket;
+			if (padlen > usbhid->bufsize)
+				padlen = usbhid->bufsize;
+		} else
+			padlen = 0;
+		usbhid->urbctrl->transfer_buffer_length = padlen;
+	}
+	usbhid->urbctrl->dev = hid_to_usb_dev(hid);
+
+	usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
+	usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
+	usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+	usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
+	usbhid->cr->wLength = cpu_to_le16(len);
+
+	dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
+		usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+		usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
+
+	if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
+		err("usb_submit_urb(ctrl) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Output interrupt completion handler.
+ */
+
+static void hid_irq_out(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+	struct usbhid_device *usbhid = hid->driver_data;
+	unsigned long flags;
+	int unplug = 0;
+
+	switch (urb->status) {
+		case 0:			/* success */
+			break;
+		case -ESHUTDOWN:	/* unplug */
+			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
+		case -ECONNRESET:	/* unlink */
+		case -ENOENT:
+			break;
+		default:		/* error */
+			warn("output irq status %d received", urb->status);
+	}
+
+	spin_lock_irqsave(&usbhid->outlock, flags);
+
+	if (unplug)
+		usbhid->outtail = usbhid->outhead;
+	else
+		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
+
+	if (usbhid->outhead != usbhid->outtail) {
+		if (hid_submit_out(hid)) {
+			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+			wake_up(&hid->wait);
+		}
+		spin_unlock_irqrestore(&usbhid->outlock, flags);
+		return;
+	}
+
+	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+	spin_unlock_irqrestore(&usbhid->outlock, flags);
+	wake_up(&hid->wait);
+}
+
+/*
+ * Control pipe completion handler.
+ */
+
+static void hid_ctrl(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+	struct usbhid_device *usbhid = hid->driver_data;
+	unsigned long flags;
+	int unplug = 0;
+
+	spin_lock_irqsave(&usbhid->ctrllock, flags);
+
+	switch (urb->status) {
+		case 0:			/* success */
+			if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+				hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
+						urb->transfer_buffer, urb->actual_length, 0);
+			break;
+		case -ESHUTDOWN:	/* unplug */
+			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
+		case -ECONNRESET:	/* unlink */
+		case -ENOENT:
+		case -EPIPE:		/* report not available */
+			break;
+		default:		/* error */
+			warn("ctrl urb status %d received", urb->status);
+	}
+
+	if (unplug)
+		usbhid->ctrltail = usbhid->ctrlhead;
+	else
+		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+	if (usbhid->ctrlhead != usbhid->ctrltail) {
+		if (hid_submit_ctrl(hid)) {
+			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+			wake_up(&hid->wait);
+		}
+		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+		return;
+	}
+
+	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+	wake_up(&hid->wait);
+}
+
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+	int head;
+	unsigned long flags;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
+		return;
+
+	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
+
+		spin_lock_irqsave(&usbhid->outlock, flags);
+
+		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
+			spin_unlock_irqrestore(&usbhid->outlock, flags);
+			warn("output queue full");
+			return;
+		}
+
+		usbhid->out[usbhid->outhead] = report;
+		usbhid->outhead = head;
+
+		if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
+			if (hid_submit_out(hid))
+				clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+
+		spin_unlock_irqrestore(&usbhid->outlock, flags);
+		return;
+	}
+
+	spin_lock_irqsave(&usbhid->ctrllock, flags);
+
+	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
+		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+		warn("control queue full");
+		return;
+	}
+
+	usbhid->ctrl[usbhid->ctrlhead].report = report;
+	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
+	usbhid->ctrlhead = head;
+
+	if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+		if (hid_submit_ctrl(hid))
+			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+
+	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+}
+
+static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_field *field;
+	int offset;
+
+	if (type == EV_FF)
+		return input_ff_event(dev, type, code, value);
+
+	if (type != EV_LED)
+		return -1;
+
+	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
+		warn("event field not found");
+		return -1;
+	}
+
+	hid_set_field(field, offset, value);
+	usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+int usbhid_wait_io(struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+					!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
+					10*HZ)) {
+		dbg("timeout waiting for ctrl or out queue to clear");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
+		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
+		unsigned char type, void *buf, int size)
+{
+	int result, retries = 4;
+
+	memset(buf, 0, size);
+
+	do {
+		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
+		retries--;
+	} while (result < size && retries);
+	return result;
+}
+
+int usbhid_open(struct hid_device *hid)
+{
+	++hid->open;
+	if (hid_start_in(hid))
+		hid_io_error(hid);
+	return 0;
+}
+
+void usbhid_close(struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (!--hid->open)
+		usb_kill_urb(usbhid->urbin);
+}
+
+/*
+ * Initialize all reports
+ */
+
+void usbhid_init_reports(struct hid_device *hid)
+{
+	struct hid_report *report;
+	struct usbhid_device *usbhid = hid->driver_data;
+	int err, ret;
+
+	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
+		usbhid_submit_report(hid, report, USB_DIR_IN);
+
+	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+		usbhid_submit_report(hid, report, USB_DIR_IN);
+
+	err = 0;
+	ret = usbhid_wait_io(hid);
+	while (ret) {
+		err |= ret;
+		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+			usb_kill_urb(usbhid->urbctrl);
+		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+			usb_kill_urb(usbhid->urbout);
+		ret = usbhid_wait_io(hid);
+	}
+
+	if (err)
+		warn("timeout initializing reports");
+}
+
+/*
+ * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
+ */
+static int hid_find_field_early(struct hid_device *hid, unsigned int page,
+    unsigned int hid_code, struct hid_field **pfield)
+{
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_usage *usage;
+	int i, j;
+
+	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			field = report->field[i];
+			for (j = 0; j < field->maxusage; j++) {
+				usage = &field->usage[j];
+				if ((usage->hid & HID_USAGE_PAGE) == page &&
+				    (usage->hid & 0xFFFF) == hid_code) {
+					*pfield = field;
+					return j;
+				}
+			}
+		}
+	}
+	return -1;
+}
+
+static void usbhid_set_leds(struct hid_device *hid)
+{
+	struct hid_field *field;
+	int offset;
+
+	if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {
+		hid_set_field(field, offset, 0);
+		usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+	}
+}
+
+/*
+ * Traverse the supplied list of reports and find the longest
+ */
+static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
+{
+	struct hid_report *report;
+	int size;
+
+	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
+		size = ((report->size - 1) >> 3) + 1;
+		if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
+			size++;
+		if (*max < size)
+			*max = size;
+	}
+}
+
+static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
+		return -1;
+	if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
+		return -1;
+	if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
+		return -1;
+	if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
+		return -1;
+
+	return 0;
+}
+
+static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
+{
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	if (usbhid->inbuf)
+		usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+	if (usbhid->outbuf)
+		usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+	if (usbhid->cr)
+		usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+	if (usbhid->ctrlbuf)
+		usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+}
+
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+
+static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
+{
+	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+		info("Fixing up Cherry Cymotion report descriptor");
+		rdesc[11] = rdesc[16] = 0xff;
+		rdesc[12] = rdesc[17] = 0x03;
+	}
+}
+
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+	int result;
+	char *buf = kmalloc(18, GFP_KERNEL);
+
+	if (!buf)
+		return;
+
+	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				 HID_REQ_GET_REPORT,
+				 USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE,
+				 (3 << 8) | 0xf2, ifnum, buf, 17,
+				 USB_CTRL_GET_TIMEOUT);
+
+	if (result < 0)
+		err("%s failed: %d\n", __func__, result);
+
+	kfree(buf);
+}
+
+/*
+ * Certain Logitech keyboards send in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
+{
+	if (rsize >= 90 && rdesc[83] == 0x26
+			&& rdesc[84] == 0x8c
+			&& rdesc[85] == 0x02) {
+		info("Fixing up Logitech keyboard report descriptor");
+		rdesc[84] = rdesc[89] = 0x4d;
+		rdesc[85] = rdesc[90] = 0x10;
+	}
+}
+
+static struct hid_device *usb_hid_configure(struct usb_interface *intf)
+{
+	struct usb_host_interface *interface = intf->cur_altsetting;
+	struct usb_device *dev = interface_to_usbdev (intf);
+	struct hid_descriptor *hdesc;
+	struct hid_device *hid;
+	u32 quirks = 0;
+	unsigned rsize = 0;
+	char *rdesc;
+	int n, len, insize = 0;
+	struct usbhid_device *usbhid;
+
+	quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
+			le16_to_cpu(dev->descriptor.idProduct));
+
+	/* Many keyboards and mice don't like to be polled for reports,
+	 * so we will always set the HID_QUIRK_NOGET flag for them. */
+	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
+		if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
+			interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+				quirks |= HID_QUIRK_NOGET;
+	}
+
+	if (quirks & HID_QUIRK_IGNORE)
+		return NULL;
+
+	if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+		(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+			return NULL;
+
+
+	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
+	    (!interface->desc.bNumEndpoints ||
+	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
+		dbg("class descriptor not present\n");
+		return NULL;
+	}
+
+	for (n = 0; n < hdesc->bNumDescriptors; n++)
+		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
+			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
+
+	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+		dbg("weird size of report descriptor (%u)", rsize);
+		return NULL;
+	}
+
+	if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
+		dbg("couldn't allocate rdesc memory");
+		return NULL;
+	}
+
+	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
+
+	if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+		dbg("reading report descriptor failed");
+		kfree(rdesc);
+		return NULL;
+	}
+
+	if ((quirks & HID_QUIRK_CYMOTION))
+		hid_fixup_cymotion_descriptor(rdesc, rsize);
+
+	if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
+		hid_fixup_logitech_descriptor(rdesc, rsize);
+
+#ifdef CONFIG_HID_DEBUG
+	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+	for (n = 0; n < rsize; n++)
+		printk(" %02x", (unsigned char) rdesc[n]);
+	printk("\n");
+#endif
+
+	if (!(hid = hid_parse_report(rdesc, n))) {
+		dbg("parsing report descriptor failed");
+		kfree(rdesc);
+		return NULL;
+	}
+
+	kfree(rdesc);
+	hid->quirks = quirks;
+
+	if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
+		goto fail;
+
+	hid->driver_data = usbhid;
+	usbhid->hid = hid;
+
+	usbhid->bufsize = HID_MIN_BUFFER_SIZE;
+	hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
+	hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
+	hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
+
+	if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
+		usbhid->bufsize = HID_MAX_BUFFER_SIZE;
+
+	hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
+
+	if (insize > HID_MAX_BUFFER_SIZE)
+		insize = HID_MAX_BUFFER_SIZE;
+
+	if (hid_alloc_buffers(dev, hid)) {
+		hid_free_buffers(dev, hid);
+		goto fail;
+	}
+
+	for (n = 0; n < interface->desc.bNumEndpoints; n++) {
+
+		struct usb_endpoint_descriptor *endpoint;
+		int pipe;
+		int interval;
+
+		endpoint = &interface->endpoint[n].desc;
+		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
+			continue;
+
+		interval = endpoint->bInterval;
+
+		/* Change the polling interval of mice. */
+		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
+			interval = hid_mousepoll_interval;
+
+		if (usb_endpoint_dir_in(endpoint)) {
+			if (usbhid->urbin)
+				continue;
+			if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
+				goto fail;
+			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+			usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
+					 hid_irq_in, hid, interval);
+			usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
+			usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		} else {
+			if (usbhid->urbout)
+				continue;
+			if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
+				goto fail;
+			pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
+			usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
+					 hid_irq_out, hid, interval);
+			usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
+			usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		}
+	}
+
+	if (!usbhid->urbin) {
+		err("couldn't find an input interrupt endpoint");
+		goto fail;
+	}
+
+	init_waitqueue_head(&hid->wait);
+
+	INIT_WORK(&usbhid->reset_work, hid_reset);
+	setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+	spin_lock_init(&usbhid->inlock);
+	spin_lock_init(&usbhid->outlock);
+	spin_lock_init(&usbhid->ctrllock);
+
+	hid->version = le16_to_cpu(hdesc->bcdHID);
+	hid->country = hdesc->bCountryCode;
+	hid->dev = &intf->dev;
+	usbhid->intf = intf;
+	usbhid->ifnum = interface->desc.bInterfaceNumber;
+
+	hid->name[0] = 0;
+
+	if (dev->manufacturer)
+		strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(hid->name, " ", sizeof(hid->name));
+		strlcat(hid->name, dev->product, sizeof(hid->name));
+	}
+
+	if (!strlen(hid->name))
+		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+			 le16_to_cpu(dev->descriptor.idVendor),
+			 le16_to_cpu(dev->descriptor.idProduct));
+
+	hid->bus = BUS_USB;
+	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+	hid->product = le16_to_cpu(dev->descriptor.idProduct);
+
+	usb_make_path(dev, hid->phys, sizeof(hid->phys));
+	strlcat(hid->phys, "/input", sizeof(hid->phys));
+	len = strlen(hid->phys);
+	if (len < sizeof(hid->phys) - 1)
+		snprintf(hid->phys + len, sizeof(hid->phys) - len,
+			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
+
+	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+		hid->uniq[0] = 0;
+
+	usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usbhid->urbctrl)
+		goto fail;
+
+	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
+			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
+	usbhid->urbctrl->setup_dma = usbhid->cr_dma;
+	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
+	usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+	hid->hidinput_input_event = usb_hidinput_input_event;
+	hid->hid_open = usbhid_open;
+	hid->hid_close = usbhid_close;
+#ifdef CONFIG_USB_HIDDEV
+	hid->hiddev_hid_event = hiddev_hid_event;
+	hid->hiddev_report_event = hiddev_report_event;
+#endif
+	return hid;
+
+fail:
+	usb_free_urb(usbhid->urbin);
+	usb_free_urb(usbhid->urbout);
+	usb_free_urb(usbhid->urbctrl);
+	hid_free_buffers(dev, hid);
+	hid_free_device(hid);
+
+	return NULL;
+}
+
+static void hid_disconnect(struct usb_interface *intf)
+{
+	struct hid_device *hid = usb_get_intfdata (intf);
+	struct usbhid_device *usbhid;
+
+	if (!hid)
+		return;
+
+	usbhid = hid->driver_data;
+
+	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
+	usb_set_intfdata(intf, NULL);
+	spin_unlock_irq(&usbhid->inlock);
+	usb_kill_urb(usbhid->urbin);
+	usb_kill_urb(usbhid->urbout);
+	usb_kill_urb(usbhid->urbctrl);
+
+	del_timer_sync(&usbhid->io_retry);
+	flush_scheduled_work();
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_disconnect(hid);
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_disconnect(hid);
+
+	usb_free_urb(usbhid->urbin);
+	usb_free_urb(usbhid->urbctrl);
+	usb_free_urb(usbhid->urbout);
+
+	hid_free_buffers(hid_to_usb_dev(hid), hid);
+	hid_free_device(hid);
+}
+
+static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct hid_device *hid;
+	char path[64];
+	int i;
+	char *c;
+
+	dbg("HID probe called for ifnum %d",
+			intf->altsetting->desc.bInterfaceNumber);
+
+	if (!(hid = usb_hid_configure(intf)))
+		return -ENODEV;
+
+	usbhid_init_reports(hid);
+	hid_dump_device(hid);
+	if (hid->quirks & HID_QUIRK_RESET_LEDS)
+		usbhid_set_leds(hid);
+
+	if (!hidinput_connect(hid))
+		hid->claimed |= HID_CLAIMED_INPUT;
+	if (!hiddev_connect(hid))
+		hid->claimed |= HID_CLAIMED_HIDDEV;
+
+	usb_set_intfdata(intf, hid);
+
+	if (!hid->claimed) {
+		printk ("HID device not claimed by input or hiddev\n");
+		hid_disconnect(intf);
+		return -ENODEV;
+	}
+
+	if ((hid->claimed & HID_CLAIMED_INPUT))
+		hid_ff_init(hid);
+
+	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
+	printk(KERN_INFO);
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		printk("input");
+	if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+		printk(",");
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		printk("hiddev%d", hid->minor);
+
+	c = "Device";
+	for (i = 0; i < hid->maxcollection; i++) {
+		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
+		    (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+		    (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
+			c = hid_types[hid->collection[i].usage & 0xffff];
+			break;
+		}
+	}
+
+	usb_make_path(interface_to_usbdev(intf), path, 63);
+
+	printk(": USB HID v%x.%02x %s [%s] on %s\n",
+		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
+
+	return 0;
+}
+
+static int hid_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct hid_device *hid = usb_get_intfdata (intf);
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
+	set_bit(HID_SUSPENDED, &usbhid->iofl);
+	spin_unlock_irq(&usbhid->inlock);
+	del_timer(&usbhid->io_retry);
+	usb_kill_urb(usbhid->urbin);
+	dev_dbg(&intf->dev, "suspend\n");
+	return 0;
+}
+
+static int hid_resume(struct usb_interface *intf)
+{
+	struct hid_device *hid = usb_get_intfdata (intf);
+	struct usbhid_device *usbhid = hid->driver_data;
+	int status;
+
+	clear_bit(HID_SUSPENDED, &usbhid->iofl);
+	usbhid->retry_delay = 0;
+	status = hid_start_in(hid);
+	dev_dbg(&intf->dev, "resume status %d\n", status);
+	return status;
+}
+
+/* Treat USB reset pretty much the same as suspend/resume */
+static void hid_pre_reset(struct usb_interface *intf)
+{
+	/* FIXME: What if the interface is already suspended? */
+	hid_suspend(intf, PMSG_ON);
+}
+
+static void hid_post_reset(struct usb_interface *intf)
+{
+	struct usb_device *dev = interface_to_usbdev (intf);
+
+	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+	/* FIXME: Any more reinitialization needed? */
+
+	hid_resume(intf);
+}
+
+static struct usb_device_id hid_usb_ids [] = {
+	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hid_usb_ids);
+
+static struct usb_driver hid_driver = {
+	.name =		"usbhid",
+	.probe =	hid_probe,
+	.disconnect =	hid_disconnect,
+	.suspend =	hid_suspend,
+	.resume =	hid_resume,
+	.pre_reset =	hid_pre_reset,
+	.post_reset =	hid_post_reset,
+	.id_table =	hid_usb_ids,
+};
+
+static int __init hid_init(void)
+{
+	int retval;
+	retval = usbhid_quirks_init(quirks_param);
+	if (retval)
+		goto usbhid_quirks_init_fail;
+	retval = hiddev_init();
+	if (retval)
+		goto hiddev_init_fail;
+	retval = usb_register(&hid_driver);
+	if (retval)
+		goto usb_register_fail;
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+
+	return 0;
+usb_register_fail:
+	hiddev_exit();
+hiddev_init_fail:
+	usbhid_quirks_exit();
+usbhid_quirks_init_fail:
+	return retval;
+}
+
+static void __exit hid_exit(void)
+{
+	usb_deregister(&hid_driver);
+	hiddev_exit();
+	usbhid_quirks_exit();
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
new file mode 100644
index 0000000..23431fb
--- /dev/null
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -0,0 +1,91 @@
+/*
+ * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
+ *
+ *  Force feedback support for hid devices.
+ *  Not all hid devices use the same protocol. For example, some use PID,
+ *  other use their own proprietary procotol.
+ *
+ *  Copyright (c) 2002-2004 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 <johann.deneux@it.uu.se>
+ */
+
+#include <linux/input.h>
+
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include "usbhid.h"
+
+/*
+ * This table contains pointers to initializers. To add support for new
+ * devices, you need to add the USB vendor and product ids here.
+ */
+struct hid_ff_initializer {
+	u16 idVendor;
+	u16 idProduct;
+	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, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
+	{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+	{ 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */
+	{ 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
+	{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
+	{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
+#endif
+#ifdef CONFIG_PANTHERLORD_FF
+	{ 0x810, 0x0001, hid_plff_init },
+#endif
+#ifdef CONFIG_THRUSTMASTER_FF
+	{ 0x44f, 0xb300, hid_tmff_init },
+	{ 0x44f, 0xb304, hid_tmff_init },
+#endif
+#ifdef CONFIG_ZEROPLUS_FF
+	{ 0xc12, 0x0005, hid_zpff_init },
+	{ 0xc12, 0x0030, hid_zpff_init },
+#endif
+	{ 0,	 0,	 hid_pidff_init}  /* Matches anything */
+};
+
+int hid_ff_init(struct hid_device* hid)
+{
+	struct hid_ff_initializer *init;
+	int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
+	int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
+
+	for (init = inits; init->idVendor; init++)
+		if (init->idVendor == vendor && init->idProduct == product)
+			break;
+
+	return init->init(hid);
+}
+EXPORT_SYMBOL_GPL(hid_ff_init);
+
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
new file mode 100644
index 0000000..92d2553
--- /dev/null
+++ b/drivers/hid/usbhid/hid-lgff.c
@@ -0,0 +1,151 @@
+/*
+ * 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@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
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <johann.deneux@it.uu.se>
+ */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct dev_type {
+	u16 idVendor;
+	u16 idProduct;
+	const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+	FF_RUMBLE,
+	-1
+};
+
+static const signed short ff_joystick[] = {
+	FF_CONSTANT,
+	-1
+};
+
+static const struct dev_type devices[] = {
+	{ 0x046d, 0xc211, ff_rumble },
+	{ 0x046d, 0xc219, ff_rumble },
+	{ 0x046d, 0xc283, ff_joystick },
+	{ 0x046d, 0xc286, ff_joystick },
+	{ 0x046d, 0xc294, ff_joystick },
+	{ 0x046d, 0xc295, ff_joystick },
+	{ 0x046d, 0xca03, 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);
+		usbhid_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);
+		usbhid_submit_report(hid, report, USB_DIR_OUT);
+		break;
+	}
+	return 0;
+}
+
+int hid_lgff_init(struct hid_device* hid)
+{
+	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;
+	const signed short *ff_bits = ff_joystick;
+	int error;
+	int i;
+
+	/* Find the report to use */
+	if (list_empty(report_list)) {
+		err("No output report found");
+		return -1;
+	}
+
+	/* Check that the report looks ok */
+	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;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(devices); i++) {
+		if (dev->id.vendor == devices[i].idVendor &&
+		    dev->id.product == devices[i].idProduct) {
+			ff_bits = devices[i].ff;
+			break;
+		}
+	}
+
+	for (i = 0; ff_bits[i] >= 0; i++)
+		set_bit(ff_bits[i], dev->ffbit);
+
+	error = input_ff_create_memless(dev, NULL, hid_lgff_play);
+	if (error)
+		return error;
+
+	printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+
+	return 0;
+}
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
new file mode 100644
index 0000000..f5a90e9
--- /dev/null
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -0,0 +1,1331 @@
+/*
+ *  Force feedback driver for USB HID PID compliant devices
+ *
+ *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@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/input.h>
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+
+#include "usbhid.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]);
+
+	usbhid_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);
+
+	usbhid_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;
+
+	usbhid_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;
+
+	usbhid_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);
+		usbhid_wait_io(pidff->hid);
+		usbhid_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);
+	usbhid_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;
+	usbhid_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;
+	usbhid_wait_io(pidff->hid);
+
+	for (j = 0; j < 60; j++) {
+		debug("pid_block_load requested");
+		usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+				  USB_DIR_IN);
+		usbhid_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;
+	}
+
+	usbhid_wait_io(pidff->hid);
+	usbhid_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;
+	usbhid_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);
+	usbhid_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;
+
+	usbhid_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 */
+	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+	usbhid_wait_io(hid);
+	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+	usbhid_wait_io(hid);
+
+	pidff->device_control->value[0] =
+		pidff->control_id[PID_ENABLE_ACTUATORS];
+	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+	usbhid_wait_io(hid);
+
+	/* pool report is sometimes messed up, refetch it */
+	usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
+	usbhid_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");
+			usbhid_submit_report(hid, pidff->reports[PID_POOL],
+					  USB_DIR_IN);
+			usbhid_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);
+		usbhid_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@gmail.com>\n");
+
+	return 0;
+
+ fail:
+	kfree(pidff);
+	return error;
+}
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
new file mode 100644
index 0000000..76d2e6e
--- /dev/null
+++ b/drivers/hid/usbhid/hid-plff.c
@@ -0,0 +1,129 @@
+/*
+ *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@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-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+	struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = dev->private;
+	struct plff_device *plff = data;
+	int left, right;
+
+	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;
+
+	plff->report->field[0]->value[2] = left;
+	plff->report->field[0]->value[3] = right;
+	debug("running with 0x%02x 0x%02x", left, right);
+	usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+	struct plff_device *plff;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list =
+			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct list_head *report_ptr = report_list;
+	struct input_dev *dev;
+	int error;
+
+	/* The device contains 2 output reports (one for each
+	   HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+	   contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+	   The 2 input reports also contain a field which contains
+	   8 ff00.0001 usages and 8 boolean values. Their meaning is
+	   currently unknown. */
+
+	if (list_empty(report_list)) {
+		printk(KERN_ERR "hid-plff: no output reports found\n");
+		return -ENODEV;
+	}
+
+	list_for_each_entry(hidinput, &hid->inputs, list) {
+
+		report_ptr = report_ptr->next;
+
+		if (report_ptr == report_list) {
+			printk(KERN_ERR "hid-plff: required output report is missing\n");
+			return -ENODEV;
+		}
+
+		report = list_entry(report_ptr, struct hid_report, list);
+		if (report->maxfield < 1) {
+			printk(KERN_ERR "hid-plff: no fields in the report\n");
+			return -ENODEV;
+		}
+
+		if (report->field[0]->report_count < 4) {
+			printk(KERN_ERR "hid-plff: not enough values in the field\n");
+			return -ENODEV;
+		}
+
+		plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+		if (!plff)
+			return -ENOMEM;
+
+		dev = hidinput->input;
+
+		set_bit(FF_RUMBLE, dev->ffbit);
+
+		error = input_ff_create_memless(dev, plff, hid_plff_play);
+		if (error) {
+			kfree(plff);
+			return error;
+		}
+
+		plff->report = report;
+		plff->report->field[0]->value[0] = 0x00;
+		plff->report->field[0]->value[1] = 0x00;
+		plff->report->field[0]->value[2] = 0x00;
+		plff->report->field[0]->value[3] = 0x00;
+		usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+	}
+
+	printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+	       "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
new file mode 100644
index 0000000..17a8755
--- /dev/null
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -0,0 +1,681 @@
+/*
+ *  USB HID quirks support for Linux
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2007 Paul Walmsley
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/hid.h>
+
+#define USB_VENDOR_ID_A4TECH		0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
+
+#define USB_VENDOR_ID_AASHIMA		0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR	0x0026
+
+#define USB_VENDOR_ID_ACECAD		0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
+#define USB_DEVICE_ID_ACECAD_302	0x0008
+
+#define USB_VENDOR_ID_AIPTEK		0x08ca
+#define USB_DEVICE_ID_AIPTEK_01		0x0001
+#define USB_DEVICE_ID_AIPTEK_10		0x0010
+#define USB_DEVICE_ID_AIPTEK_20		0x0020
+#define USB_DEVICE_ID_AIPTEK_21		0x0021
+#define USB_DEVICE_ID_AIPTEK_22		0x0022
+#define USB_DEVICE_ID_AIPTEK_23		0x0023
+#define USB_DEVICE_ID_AIPTEK_24		0x0024
+
+#define USB_VENDOR_ID_AIRCABLE		0x16CA
+#define USB_DEVICE_ID_AIRCABLE1		0x1502
+
+#define USB_VENDOR_ID_ALCOR		0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232	0x9720
+
+#define USB_VENDOR_ID_ALPS		0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
+
+#define USB_VENDOR_ID_APPLE		0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO	0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI	0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO	0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS	0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI	0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO	0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS	0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI	0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO	0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
+#define USB_DEVICE_ID_APPLE_IR		0x8240
+
+#define USB_VENDOR_ID_ATEN		0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
+#define USB_DEVICE_ID_ATEN_CS124U	0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
+
+#define USB_VENDOR_ID_BELKIN           0x050d
+#define USB_DEVICE_ID_FLIP_KVM         0x3201
+
+#define USB_VENDOR_ID_BERKSHIRE		0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
+
+#define USB_VENDOR_ID_CHERRY		0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
+
+#define USB_VENDOR_ID_CHIC		0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
+
+#define USB_VENDOR_ID_CIDC		0x1677
+
+#define USB_VENDOR_ID_CODEMERCS		0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST	0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST	0x15ff
+
+#define USB_VENDOR_ID_CYPRESS		0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE	0x7417
+
+#define USB_VENDOR_ID_DELL		0x413c
+#define USB_DEVICE_ID_DELL_W7658	0x2005
+
+#define USB_VENDOR_ID_DELORME		0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#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_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_GRIFFIN		0x077d
+#define USB_DEVICE_ID_POWERMATE		0x0410
+#define USB_DEVICE_ID_SOUNDKNOB		0x04AA
+
+#define USB_VENDOR_ID_GTCO		0x078c
+#define USB_DEVICE_ID_GTCO_90		0x0090
+#define USB_DEVICE_ID_GTCO_100		0x0100
+#define USB_DEVICE_ID_GTCO_101		0x0101
+#define USB_DEVICE_ID_GTCO_103		0x0103
+#define USB_DEVICE_ID_GTCO_104		0x0104
+#define USB_DEVICE_ID_GTCO_105		0x0105
+#define USB_DEVICE_ID_GTCO_106		0x0106
+#define USB_DEVICE_ID_GTCO_107		0x0107
+#define USB_DEVICE_ID_GTCO_108		0x0108
+#define USB_DEVICE_ID_GTCO_200		0x0200
+#define USB_DEVICE_ID_GTCO_201		0x0201
+#define USB_DEVICE_ID_GTCO_202		0x0202
+#define USB_DEVICE_ID_GTCO_203		0x0203
+#define USB_DEVICE_ID_GTCO_204		0x0204
+#define USB_DEVICE_ID_GTCO_205		0x0205
+#define USB_DEVICE_ID_GTCO_206		0x0206
+#define USB_DEVICE_ID_GTCO_207		0x0207
+#define USB_DEVICE_ID_GTCO_300		0x0300
+#define USB_DEVICE_ID_GTCO_301		0x0301
+#define USB_DEVICE_ID_GTCO_302		0x0302
+#define USB_DEVICE_ID_GTCO_303		0x0303
+#define USB_DEVICE_ID_GTCO_304		0x0304
+#define USB_DEVICE_ID_GTCO_305		0x0305
+#define USB_DEVICE_ID_GTCO_306		0x0306
+#define USB_DEVICE_ID_GTCO_307		0x0307
+#define USB_DEVICE_ID_GTCO_308		0x0308
+#define USB_DEVICE_ID_GTCO_309		0x0309
+#define USB_DEVICE_ID_GTCO_400		0x0400
+#define USB_DEVICE_ID_GTCO_401		0x0401
+#define USB_DEVICE_ID_GTCO_402		0x0402
+#define USB_DEVICE_ID_GTCO_403		0x0403
+#define USB_DEVICE_ID_GTCO_404		0x0404
+#define USB_DEVICE_ID_GTCO_405		0x0405
+#define USB_DEVICE_ID_GTCO_500		0x0500
+#define USB_DEVICE_ID_GTCO_501		0x0501
+#define USB_DEVICE_ID_GTCO_502		0x0502
+#define USB_DEVICE_ID_GTCO_503		0x0503
+#define USB_DEVICE_ID_GTCO_504		0x0504
+#define USB_DEVICE_ID_GTCO_1000		0x1000
+#define USB_DEVICE_ID_GTCO_1001		0x1001
+#define USB_DEVICE_ID_GTCO_1002		0x1002
+#define USB_DEVICE_ID_GTCO_1003		0x1003
+#define USB_DEVICE_ID_GTCO_1004		0x1004
+#define USB_DEVICE_ID_GTCO_1005		0x1005
+#define USB_DEVICE_ID_GTCO_1006		0x1006
+
+#define USB_VENDOR_ID_HAPP		0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
+#define USB_DEVICE_ID_UGCI_FLYING	0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
+
+#define USB_VENDOR_ID_IMATION		0x0718
+#define USB_DEVICE_ID_DISC_STAKKA	0xd000
+
+#define USB_VENDOR_ID_KBGEAR		0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
+
+#define USB_VENDOR_ID_LD		0x0f11
+#define USB_DEVICE_ID_LD_CASSY		0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY	0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY	0x1020
+#define USB_DEVICE_ID_LD_JWM		0x1080
+#define USB_DEVICE_ID_LD_DMMP		0x1081
+#define USB_DEVICE_ID_LD_UMIP		0x1090
+#define USB_DEVICE_ID_LD_XRAY1		0x1100
+#define USB_DEVICE_ID_LD_XRAY2		0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM	0x1200
+#define USB_DEVICE_ID_LD_COM3LAB	0x2000
+#define USB_DEVICE_ID_LD_TELEPORT	0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL	0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST	0x2040
+
+#define USB_VENDOR_ID_LOGITECH		0x046d
+#define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
+#define USB_DEVICE_ID_S510_RECEIVER	0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
+#define USB_DEVICE_ID_MX3000_RECEIVER	0xc513
+#define USB_DEVICE_ID_DINOVO_EDGE	0xc714
+
+#define USB_VENDOR_ID_MCC		0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
+
+#define USB_VENDOR_ID_MGE		0x0463
+#define USB_DEVICE_ID_MGE_UPS		0xffff
+#define USB_DEVICE_ID_MGE_UPS1		0x0001
+
+#define USB_VENDOR_ID_NEC		0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
+
+#define USB_VENDOR_ID_ONTRAK		0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
+
+#define USB_VENDOR_ID_PANJIT		0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD	0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
+
+#define USB_VENDOR_ID_PLAYDOTCOM	0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII	0x0003
+
+#define USB_VENDOR_ID_SAITEK		0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
+
+#define USB_VENDOR_ID_SONY			0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
+
+#define USB_VENDOR_ID_SUN		0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
+
+#define USB_VENDOR_ID_TOPMAX		0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
+
+#define USB_VENDOR_ID_TURBOX		0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
+
+#define USB_VENDOR_ID_VERNIER		0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP	0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP	0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
+
+#define USB_VENDOR_ID_WACOM		0x056a
+
+#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_QUAD_USB_JOYPAD	0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD	0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD	0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_YEALINK		0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K	0xb001
+
+/*
+ * Alphabetically sorted blacklist by quirk type.
+ */
+
+static const struct hid_blacklist {
+	__u16 idVendor;
+	__u16 idProduct;
+	__u32 quirks;
+} hid_blacklist[] = {
+
+	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
+
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+
+	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+	
+	{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
+
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+
+	{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
+	{ 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_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
+	{ 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_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 },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+	{ 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 },
+	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
+	{ 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 },
+	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR },
+
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
+
+	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+	{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
+
+	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+	{ 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_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_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 },
+
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
+
+	{ 0, 0 }
+};
+
+/* Dynamic HID quirks list - specified at runtime */
+struct quirks_list_struct {
+	struct hid_blacklist hid_bl_item;
+	struct list_head node;
+};
+
+static LIST_HEAD(dquirks_list);
+static DECLARE_RWSEM(dquirks_rwsem);
+
+/* Runtime ("dynamic") quirks manipulation functions */
+
+/**
+ * usbhid_exists_dquirk: find any dynamic quirks for a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ *         Scans dquirks_list for a matching dynamic quirk and returns
+ *         the pointer to the relevant struct hid_blacklist if found.
+ *         Must be called with a read lock held on dquirks_rwsem.
+ *
+ * Returns: NULL if no quirk found, struct hid_blacklist * if found.
+ */
+static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
+		const u16 idProduct)
+{
+	struct quirks_list_struct *q;
+	struct hid_blacklist *bl_entry = NULL;
+
+	list_for_each_entry(q, &dquirks_list, node) {
+		if (q->hid_bl_item.idVendor == idVendor &&
+				q->hid_bl_item.idProduct == idProduct) {
+			bl_entry = &q->hid_bl_item;
+			break;
+		}
+	}
+
+	if (bl_entry != NULL)
+		dbg("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+				bl_entry->quirks, bl_entry->idVendor,
+				bl_entry->idProduct);
+
+	return bl_entry;
+}
+
+
+/**
+ * usbhid_modify_dquirk: add/replace a HID quirk
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ * @quirks: the u32 quirks value to add/replace
+ *
+ * Description:
+ *         If an dynamic quirk exists in memory for this (idVendor,
+ *         idProduct) pair, replace its quirks value with what was
+ *         provided.  Otherwise, add the quirk to the dynamic quirks list.
+ *
+ * Returns: 0 OK, -error on failure.
+ */
+int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
+		const u32 quirks)
+{
+	struct quirks_list_struct *q_new, *q;
+	int list_edited = 0;
+
+	if (!idVendor) {
+		dbg("Cannot add a quirk with idVendor = 0");
+		return -EINVAL;
+	}
+
+	q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
+	if (!q_new) {
+		dbg("Could not allocate quirks_list_struct");
+		return -ENOMEM;
+	}
+
+	q_new->hid_bl_item.idVendor = idVendor;
+	q_new->hid_bl_item.idProduct = idProduct;
+	q_new->hid_bl_item.quirks = quirks;
+
+	down_write(&dquirks_rwsem);
+
+	list_for_each_entry(q, &dquirks_list, node) {
+
+		if (q->hid_bl_item.idVendor == idVendor &&
+				q->hid_bl_item.idProduct == idProduct) {
+
+			list_replace(&q->node, &q_new->node);
+			kfree(q);
+			list_edited = 1;
+			break;
+
+		}
+
+	}
+
+	if (!list_edited)
+		list_add_tail(&q_new->node, &dquirks_list);
+
+	up_write(&dquirks_rwsem);
+
+	return 0;
+}
+
+
+/**
+ * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory
+ *
+ * Description:
+ *         Free all memory associated with dynamic quirks - called before
+ *         module unload.
+ *
+ */
+static void usbhid_remove_all_dquirks(void)
+{
+	struct quirks_list_struct *q, *temp;
+
+	down_write(&dquirks_rwsem);
+	list_for_each_entry_safe(q, temp, &dquirks_list, node) {
+		list_del(&q->node);
+		kfree(q);
+	}
+	up_write(&dquirks_rwsem);
+
+}
+
+/** 
+ * usbhid_quirks_init: apply USB HID quirks specified at module load time
+ */
+int usbhid_quirks_init(char **quirks_param)
+{
+	u16 idVendor, idProduct;
+	u32 quirks;
+	int n = 0, m;
+
+	for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
+
+		m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
+				&idVendor, &idProduct, &quirks);
+
+		if (m != 3 ||
+				usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
+			printk(KERN_WARNING
+					"Could not parse HID quirk module param %s\n",
+					quirks_param[n]);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * usbhid_quirks_exit: release memory associated with dynamic_quirks
+ *
+ * Description:
+ *     Release all memory associated with dynamic quirks.  Called upon
+ *     module unload.
+ *
+ * Returns: nothing
+ */
+void usbhid_quirks_exit(void)
+{
+	usbhid_remove_all_dquirks();
+}
+
+/**
+ * usbhid_exists_squirk: return any static quirks for a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ *     Given a USB vendor ID and product ID, return a pointer to
+ *     the hid_blacklist entry associated with that device.
+ *
+ * Returns: pointer if quirk found, or NULL if no quirks found.
+ */
+static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
+		const u16 idProduct)
+{
+	const struct hid_blacklist *bl_entry = NULL;
+	int n = 0;
+
+	for (; hid_blacklist[n].idVendor; n++)
+		if (hid_blacklist[n].idVendor == idVendor &&
+				hid_blacklist[n].idProduct == idProduct)
+			bl_entry = &hid_blacklist[n];
+
+	if (bl_entry != NULL)
+		dbg("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+				bl_entry->quirks, bl_entry->idVendor, 
+				bl_entry->idProduct);
+	return bl_entry;
+}
+
+/**
+ * usbhid_lookup_quirk: return any quirks associated with a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ *     Given a USB vendor ID and product ID, return any quirks associated
+ *     with that device.
+ *
+ * Returns: a u32 quirks value.
+ */
+u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
+{
+	u32 quirks = 0;
+	const struct hid_blacklist *bl_entry = NULL;
+
+	/* Ignore all Wacom devices */
+	if (idVendor == USB_VENDOR_ID_WACOM)
+		return HID_QUIRK_IGNORE;
+
+	/* ignore all Code Mercenaries IOWarrior devices */
+	if (idVendor == USB_VENDOR_ID_CODEMERCS)
+		if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+				idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+			return HID_QUIRK_IGNORE;
+
+	down_read(&dquirks_rwsem);
+	bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
+	if (!bl_entry)
+		bl_entry = usbhid_exists_squirk(idVendor, idProduct);
+	if (bl_entry)
+		quirks = bl_entry->quirks;
+	up_read(&dquirks_rwsem);
+
+	return quirks;
+}
+
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
new file mode 100644
index 0000000..ab67331
--- /dev/null
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -0,0 +1,147 @@
+/*
+ * Force feedback support for various HID compliant devices by ThrustMaster:
+ *    ThrustMaster FireStorm Dual Power 2
+ * and possibly others whose device ids haven't been added.
+ *
+ *  Modified to support ThrustMaster devices by Zinx Verituse
+ *  on 2003-01-25 from the Logitech force feedback driver,
+ *  which is by Johann Deneux.
+ *
+ *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
+ *  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
+ */
+
+#include <linux/input.h>
+
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <linux/hid.h>
+#include "usbhid.h"
+
+/* Usages for thrustmaster devices I know about */
+#define THRUSTMASTER_USAGE_RUMBLE_LR	(HID_UP_GENDESK | 0xbb)
+
+
+struct tmff_device {
+	struct hid_report *report;
+	struct hid_field *rumble;
+};
+
+/* 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 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 */
+
+	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);
+
+	tmff->rumble->value[0] = left;
+	tmff->rumble->value[1] = right;
+	dbg("(left,right)=(%08x, %08x)", left, right);
+	usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+
+	return 0;
+}
+
+int hid_tmff_init(struct hid_device *hid)
+{
+	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;
+
+	tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+	if (!tmff)
+		return -ENOMEM;
+
+	/* 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;
+		int fieldnum;
+
+		for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
+			struct hid_field *field = report->field[fieldnum];
+
+			if (field->maxusage <= 0)
+				continue;
+
+			switch (field->usage[0].hid) {
+				case THRUSTMASTER_USAGE_RUMBLE_LR:
+					if (field->report_count < 2) {
+						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
+						continue;
+					}
+
+					if (field->logical_maximum == field->logical_minimum) {
+						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
+						continue;
+					}
+
+					if (tmff->report && tmff->report != report) {
+						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
+						continue;
+					}
+
+					if (tmff->rumble && tmff->rumble != field) {
+						warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
+						continue;
+					}
+
+					tmff->report = report;
+					tmff->rumble = field;
+
+					set_bit(FF_RUMBLE, input_dev->ffbit);
+					break;
+
+				default:
+					warn("ignoring unknown output usage %08x", field->usage[0].hid);
+					continue;
+			}
+		}
+	}
+
+	error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+	if (error) {
+		kfree(tmff);
+		return error;
+	}
+
+	info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+
+	return 0;
+}
+
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
new file mode 100644
index 0000000..7bd8238
--- /dev/null
+++ b/drivers/hid/usbhid/hid-zpff.c
@@ -0,0 +1,111 @@
+/*
+ *  Force feedback support for Zeroplus based devices
+ *
+ *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@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 <linux/hid.h>
+#include "usbhid.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);
+	usbhid_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;
+	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+	printk(KERN_INFO "Force feedback for Zeroplus based devices by "
+	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+	return 0;
+}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
new file mode 100644
index 0000000..a8b3d66
--- /dev/null
+++ b/drivers/hid/usbhid/hiddev.c
@@ -0,0 +1,847 @@
+/*
+ *  Copyright (c) 2001 Paul Stewart
+ *  Copyright (c) 2001 Vojtech Pavlik
+ *
+ *  HID char devices, giving access to raw HID device events.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 Paul Stewart <stewart@wetlogic.net>
+ */
+
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include "usbhid.h"
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define HIDDEV_MINOR_BASE	0
+#define HIDDEV_MINORS		256
+#else
+#define HIDDEV_MINOR_BASE	96
+#define HIDDEV_MINORS		16
+#endif
+#define HIDDEV_BUFFER_SIZE	64
+
+struct hiddev {
+	int exist;
+	int open;
+	wait_queue_head_t wait;
+	struct hid_device *hid;
+	struct list_head list;
+};
+
+struct hiddev_list {
+	struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
+	int head;
+	int tail;
+	unsigned flags;
+	struct fasync_struct *fasync;
+	struct hiddev *hiddev;
+	struct list_head node;
+};
+
+static struct hiddev *hiddev_table[HIDDEV_MINORS];
+
+/*
+ * Find a report, given the report's type and ID.  The ID can be specified
+ * indirectly by REPORT_ID_FIRST (which returns the first report of the given
+ * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
+ * given type which follows old_id.
+ */
+static struct hid_report *
+hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
+{
+	unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
+	unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
+	struct hid_report_enum *report_enum;
+	struct hid_report *report;
+	struct list_head *list;
+
+	if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
+	    rinfo->report_type > HID_REPORT_TYPE_MAX)
+		return NULL;
+
+	report_enum = hid->report_enum +
+		(rinfo->report_type - HID_REPORT_TYPE_MIN);
+
+	switch (flags) {
+	case 0: /* Nothing to do -- report_id is already set correctly */
+		break;
+
+	case HID_REPORT_ID_FIRST:
+		if (list_empty(&report_enum->report_list))
+			return NULL;
+
+		list = report_enum->report_list.next;
+		report = list_entry(list, struct hid_report, list);
+		rinfo->report_id = report->id;
+		break;
+
+	case HID_REPORT_ID_NEXT:
+		report = report_enum->report_id_hash[rid];
+		if (!report)
+			return NULL;
+
+		list = report->list.next;
+		if (list == &report_enum->report_list)
+			return NULL;
+
+		report = list_entry(list, struct hid_report, list);
+		rinfo->report_id = report->id;
+		break;
+
+	default:
+		return NULL;
+	}
+
+	return report_enum->report_id_hash[rinfo->report_id];
+}
+
+/*
+ * Perform an exhaustive search of the report table for a usage, given its
+ * type and usage id.
+ */
+static struct hid_field *
+hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
+{
+	int i, j;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct hid_field *field;
+
+	if (uref->report_type < HID_REPORT_TYPE_MIN ||
+	    uref->report_type > HID_REPORT_TYPE_MAX)
+		return NULL;
+
+	report_enum = hid->report_enum +
+		(uref->report_type - HID_REPORT_TYPE_MIN);
+
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			field = report->field[i];
+			for (j = 0; j < field->maxusage; j++) {
+				if (field->usage[j].hid == uref->usage_code) {
+					uref->report_id = report->id;
+					uref->field_index = i;
+					uref->usage_index = j;
+					return field;
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static void hiddev_send_event(struct hid_device *hid,
+			      struct hiddev_usage_ref *uref)
+{
+	struct hiddev *hiddev = hid->hiddev;
+	struct hiddev_list *list;
+
+	list_for_each_entry(list, &hiddev->list, node) {
+		if (uref->field_index != HID_FIELD_INDEX_NONE ||
+		    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
+			list->buffer[list->head] = *uref;
+			list->head = (list->head + 1) &
+				(HIDDEV_BUFFER_SIZE - 1);
+			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		}
+	}
+
+	wake_up_interruptible(&hiddev->wait);
+}
+
+/*
+ * This is where hid.c calls into hiddev to pass an event that occurred over
+ * the interrupt pipe
+ */
+void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
+		      struct hid_usage *usage, __s32 value)
+{
+	unsigned type = field->report_type;
+	struct hiddev_usage_ref uref;
+
+	uref.report_type =
+	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
+	uref.report_id = field->report->id;
+	uref.field_index = field->index;
+	uref.usage_index = (usage - field->usage);
+	uref.usage_code = usage->hid;
+	uref.value = value;
+
+	hiddev_send_event(hid, &uref);
+}
+EXPORT_SYMBOL_GPL(hiddev_hid_event);
+
+void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
+{
+	unsigned type = report->type;
+	struct hiddev_usage_ref uref;
+
+	memset(&uref, 0, sizeof(uref));
+	uref.report_type =
+	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
+	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
+	uref.report_id = report->id;
+	uref.field_index = HID_FIELD_INDEX_NONE;
+
+	hiddev_send_event(hid, &uref);
+}
+
+/*
+ * fasync file op
+ */
+static int hiddev_fasync(int fd, struct file *file, int on)
+{
+	int retval;
+	struct hiddev_list *list = file->private_data;
+
+	retval = fasync_helper(fd, file, on, &list->fasync);
+
+	return retval < 0 ? retval : 0;
+}
+
+
+/*
+ * release file op
+ */
+static int hiddev_release(struct inode * inode, struct file * file)
+{
+	struct hiddev_list *list = file->private_data;
+
+	hiddev_fasync(-1, file, 0);
+	list_del(&list->node);
+
+	if (!--list->hiddev->open) {
+		if (list->hiddev->exist)
+			usbhid_close(list->hiddev->hid);
+		else
+			kfree(list->hiddev);
+	}
+
+	kfree(list);
+
+	return 0;
+}
+
+/*
+ * open file op
+ */
+static int hiddev_open(struct inode *inode, struct file *file)
+{
+	struct hiddev_list *list;
+
+	int i = iminor(inode) - HIDDEV_MINOR_BASE;
+
+	if (i >= HIDDEV_MINORS || !hiddev_table[i])
+		return -ENODEV;
+
+	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+		return -ENOMEM;
+
+	list->hiddev = hiddev_table[i];
+	list_add_tail(&list->node, &hiddev_table[i]->list);
+	file->private_data = list;
+
+	if (!list->hiddev->open++)
+		if (list->hiddev->exist)
+			usbhid_open(hiddev_table[i]->hid);
+
+	return 0;
+}
+
+/*
+ * "write" file op
+ */
+static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+/*
+ * "read" file op
+ */
+static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct hiddev_list *list = file->private_data;
+	int event_size;
+	int retval = 0;
+
+	event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
+		sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
+
+	if (count < event_size)
+		return 0;
+
+	while (retval == 0) {
+		if (list->head == list->tail) {
+			add_wait_queue(&list->hiddev->wait, &wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			while (list->head == list->tail) {
+				if (file->f_flags & O_NONBLOCK) {
+					retval = -EAGAIN;
+					break;
+				}
+				if (signal_pending(current)) {
+					retval = -ERESTARTSYS;
+					break;
+				}
+				if (!list->hiddev->exist) {
+					retval = -EIO;
+					break;
+				}
+
+				schedule();
+				set_current_state(TASK_INTERRUPTIBLE);
+			}
+
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&list->hiddev->wait, &wait);
+		}
+
+		if (retval)
+			return retval;
+
+
+		while (list->head != list->tail &&
+		       retval + event_size <= count) {
+			if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
+				if (list->buffer[list->tail].field_index !=
+				    HID_FIELD_INDEX_NONE) {
+					struct hiddev_event event;
+					event.hid = list->buffer[list->tail].usage_code;
+					event.value = list->buffer[list->tail].value;
+					if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event)))
+						return -EFAULT;
+					retval += sizeof(struct hiddev_event);
+				}
+			} else {
+				if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
+				    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
+					if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref)))
+						return -EFAULT;
+					retval += sizeof(struct hiddev_usage_ref);
+				}
+			}
+			list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
+		}
+
+	}
+
+	return retval;
+}
+
+/*
+ * "poll" file op
+ * No kernel lock - fine
+ */
+static unsigned int hiddev_poll(struct file *file, poll_table *wait)
+{
+	struct hiddev_list *list = file->private_data;
+
+	poll_wait(file, &list->hiddev->wait, wait);
+	if (list->head != list->tail)
+		return POLLIN | POLLRDNORM;
+	if (!list->hiddev->exist)
+		return POLLERR | POLLHUP;
+	return 0;
+}
+
+/*
+ * "ioctl" file op
+ */
+static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hiddev_list *list = file->private_data;
+	struct hiddev *hiddev = list->hiddev;
+	struct hid_device *hid = hiddev->hid;
+	struct usb_device *dev = hid_to_usb_dev(hid);
+	struct hiddev_collection_info cinfo;
+	struct hiddev_report_info rinfo;
+	struct hiddev_field_info finfo;
+	struct hiddev_usage_ref_multi *uref_multi = NULL;
+	struct hiddev_usage_ref *uref;
+	struct hiddev_devinfo dinfo;
+	struct hid_report *report;
+	struct hid_field *field;
+	struct usbhid_device *usbhid = hid->driver_data;
+	void __user *user_arg = (void __user *)arg;
+	int i;
+
+	if (!hiddev->exist)
+		return -EIO;
+
+	switch (cmd) {
+
+	case HIDIOCGVERSION:
+		return put_user(HID_VERSION, (int __user *)arg);
+
+	case HIDIOCAPPLICATION:
+		if (arg < 0 || arg >= hid->maxapplication)
+			return -EINVAL;
+
+		for (i = 0; i < hid->maxcollection; i++)
+			if (hid->collection[i].type ==
+			    HID_COLLECTION_APPLICATION && arg-- == 0)
+				break;
+
+		if (i == hid->maxcollection)
+			return -EINVAL;
+
+		return hid->collection[i].usage;
+
+	case HIDIOCGDEVINFO:
+		dinfo.bustype = BUS_USB;
+		dinfo.busnum = dev->bus->busnum;
+		dinfo.devnum = dev->devnum;
+		dinfo.ifnum = usbhid->ifnum;
+		dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+		dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+		dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+		dinfo.num_applications = hid->maxapplication;
+		if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
+			return -EFAULT;
+
+		return 0;
+
+	case HIDIOCGFLAG:
+		if (put_user(list->flags, (int __user *)arg))
+			return -EFAULT;
+
+		return 0;
+
+	case HIDIOCSFLAG:
+		{
+			int newflags;
+			if (get_user(newflags, (int __user *)arg))
+				return -EFAULT;
+
+			if ((newflags & ~HIDDEV_FLAGS) != 0 ||
+			    ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
+			     (newflags & HIDDEV_FLAG_UREF) == 0))
+				return -EINVAL;
+
+			list->flags = newflags;
+
+			return 0;
+		}
+
+	case HIDIOCGSTRING:
+		{
+			int idx, len;
+			char *buf;
+
+			if (get_user(idx, (int __user *)arg))
+				return -EFAULT;
+
+			if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+
+			if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
+				kfree(buf);
+				return -EINVAL;
+			}
+
+			if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
+				kfree(buf);
+				return -EFAULT;
+			}
+
+			kfree(buf);
+
+			return len;
+		}
+
+	case HIDIOCINITREPORT:
+		usbhid_init_reports(hid);
+
+		return 0;
+
+	case HIDIOCGREPORT:
+		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
+			return -EINVAL;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		usbhid_submit_report(hid, report, USB_DIR_IN);
+		usbhid_wait_io(hid);
+
+		return 0;
+
+	case HIDIOCSREPORT:
+		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
+			return -EINVAL;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		usbhid_submit_report(hid, report, USB_DIR_OUT);
+		usbhid_wait_io(hid);
+
+		return 0;
+
+	case HIDIOCGREPORTINFO:
+		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		rinfo.num_fields = report->maxfield;
+
+		if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
+			return -EFAULT;
+
+		return 0;
+
+	case HIDIOCGFIELDINFO:
+		if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
+			return -EFAULT;
+		rinfo.report_type = finfo.report_type;
+		rinfo.report_id = finfo.report_id;
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		if (finfo.field_index >= report->maxfield)
+			return -EINVAL;
+
+		field = report->field[finfo.field_index];
+		memset(&finfo, 0, sizeof(finfo));
+		finfo.report_type = rinfo.report_type;
+		finfo.report_id = rinfo.report_id;
+		finfo.field_index = field->report_count - 1;
+		finfo.maxusage = field->maxusage;
+		finfo.flags = field->flags;
+		finfo.physical = field->physical;
+		finfo.logical = field->logical;
+		finfo.application = field->application;
+		finfo.logical_minimum = field->logical_minimum;
+		finfo.logical_maximum = field->logical_maximum;
+		finfo.physical_minimum = field->physical_minimum;
+		finfo.physical_maximum = field->physical_maximum;
+		finfo.unit_exponent = field->unit_exponent;
+		finfo.unit = field->unit;
+
+		if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
+			return -EFAULT;
+
+		return 0;
+
+	case HIDIOCGUCODE:
+		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+		if (!uref_multi)
+			return -ENOMEM;
+		uref = &uref_multi->uref;
+		if (copy_from_user(uref, user_arg, sizeof(*uref)))
+			goto fault;
+
+		rinfo.report_type = uref->report_type;
+		rinfo.report_id = uref->report_id;
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			goto inval;
+
+		if (uref->field_index >= report->maxfield)
+			goto inval;
+
+		field = report->field[uref->field_index];
+		if (uref->usage_index >= field->maxusage)
+			goto inval;
+
+		uref->usage_code = field->usage[uref->usage_index].hid;
+
+		if (copy_to_user(user_arg, uref, sizeof(*uref)))
+			goto fault;
+
+		kfree(uref_multi);
+		return 0;
+
+	case HIDIOCGUSAGE:
+	case HIDIOCSUSAGE:
+	case HIDIOCGUSAGES:
+	case HIDIOCSUSAGES:
+	case HIDIOCGCOLLECTIONINDEX:
+		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+		if (!uref_multi)
+			return -ENOMEM;
+		uref = &uref_multi->uref;
+		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+			if (copy_from_user(uref_multi, user_arg,
+					   sizeof(*uref_multi)))
+				goto fault;
+		} else {
+			if (copy_from_user(uref, user_arg, sizeof(*uref)))
+				goto fault;
+		}
+
+		if (cmd != HIDIOCGUSAGE &&
+		    cmd != HIDIOCGUSAGES &&
+		    uref->report_type == HID_REPORT_TYPE_INPUT)
+			goto inval;
+
+		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+			field = hiddev_lookup_usage(hid, uref);
+			if (field == NULL)
+				goto inval;
+		} else {
+			rinfo.report_type = uref->report_type;
+			rinfo.report_id = uref->report_id;
+			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+				goto inval;
+
+			if (uref->field_index >= report->maxfield)
+				goto inval;
+
+			field = report->field[uref->field_index];
+
+			if (cmd == HIDIOCGCOLLECTIONINDEX) {
+				if (uref->usage_index >= field->maxusage)
+					goto inval;
+			} else if (uref->usage_index >= field->report_count)
+				goto inval;
+
+			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
+				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+				  uref->usage_index + uref_multi->num_values > field->report_count))
+				goto inval;
+			}
+
+		switch (cmd) {
+			case HIDIOCGUSAGE:
+				uref->value = field->value[uref->usage_index];
+				if (copy_to_user(user_arg, uref, sizeof(*uref)))
+					goto fault;
+				goto goodreturn;
+
+			case HIDIOCSUSAGE:
+				field->value[uref->usage_index] = uref->value;
+				goto goodreturn;
+
+			case HIDIOCGCOLLECTIONINDEX:
+				kfree(uref_multi);
+				return field->usage[uref->usage_index].collection_index;
+			case HIDIOCGUSAGES:
+				for (i = 0; i < uref_multi->num_values; i++)
+					uref_multi->values[i] =
+					    field->value[uref->usage_index + i];
+				if (copy_to_user(user_arg, uref_multi,
+						 sizeof(*uref_multi)))
+					goto fault;
+				goto goodreturn;
+			case HIDIOCSUSAGES:
+				for (i = 0; i < uref_multi->num_values; i++)
+					field->value[uref->usage_index + i] =
+					    uref_multi->values[i];
+				goto goodreturn;
+		}
+
+goodreturn:
+		kfree(uref_multi);
+		return 0;
+fault:
+		kfree(uref_multi);
+		return -EFAULT;
+inval:
+		kfree(uref_multi);
+		return -EINVAL;
+
+	case HIDIOCGCOLLECTIONINFO:
+		if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
+			return -EFAULT;
+
+		if (cinfo.index >= hid->maxcollection)
+			return -EINVAL;
+
+		cinfo.type = hid->collection[cinfo.index].type;
+		cinfo.usage = hid->collection[cinfo.index].usage;
+		cinfo.level = hid->collection[cinfo.index].level;
+
+		if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
+			return -EFAULT;
+		return 0;
+
+	default:
+
+		if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
+			return -EINVAL;
+
+		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
+			int len;
+			if (!hid->name)
+				return 0;
+			len = strlen(hid->name) + 1;
+			if (len > _IOC_SIZE(cmd))
+				 len = _IOC_SIZE(cmd);
+			return copy_to_user(user_arg, hid->name, len) ?
+				-EFAULT : len;
+		}
+
+		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
+			int len;
+			if (!hid->phys)
+				return 0;
+			len = strlen(hid->phys) + 1;
+			if (len > _IOC_SIZE(cmd))
+				len = _IOC_SIZE(cmd);
+			return copy_to_user(user_arg, hid->phys, len) ?
+				-EFAULT : len;
+		}
+	}
+	return -EINVAL;
+}
+
+static const struct file_operations hiddev_fops = {
+	.owner =	THIS_MODULE,
+	.read =		hiddev_read,
+	.write =	hiddev_write,
+	.poll =		hiddev_poll,
+	.open =		hiddev_open,
+	.release =	hiddev_release,
+	.ioctl =	hiddev_ioctl,
+	.fasync =	hiddev_fasync,
+};
+
+static struct usb_class_driver hiddev_class = {
+	.name =		"hiddev%d",
+	.fops =		&hiddev_fops,
+	.minor_base =	HIDDEV_MINOR_BASE,
+};
+
+/*
+ * This is where hid.c calls us to connect a hid device to the hiddev driver
+ */
+int hiddev_connect(struct hid_device *hid)
+{
+	struct hiddev *hiddev;
+	struct usbhid_device *usbhid = hid->driver_data;
+	int i;
+	int retval;
+
+	for (i = 0; i < hid->maxcollection; i++)
+		if (hid->collection[i].type ==
+		    HID_COLLECTION_APPLICATION &&
+		    !IS_INPUT_APPLICATION(hid->collection[i].usage))
+			break;
+
+	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
+		return -1;
+
+	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
+		return -1;
+
+	retval = usb_register_dev(usbhid->intf, &hiddev_class);
+	if (retval) {
+		err("Not able to get a minor for this device.");
+		kfree(hiddev);
+		return -1;
+	}
+
+	init_waitqueue_head(&hiddev->wait);
+	INIT_LIST_HEAD(&hiddev->list);
+	hiddev->hid = hid;
+	hiddev->exist = 1;
+
+	hid->minor = usbhid->intf->minor;
+	hid->hiddev = hiddev;
+
+	hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+
+	return 0;
+}
+
+/*
+ * This is where hid.c calls us to disconnect a hiddev device from the
+ * corresponding hid device (usually because the usb device has disconnected)
+ */
+static struct usb_class_driver hiddev_class;
+void hiddev_disconnect(struct hid_device *hid)
+{
+	struct hiddev *hiddev = hid->hiddev;
+	struct usbhid_device *usbhid = hid->driver_data;
+
+	hiddev->exist = 0;
+
+	hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
+	usb_deregister_dev(usbhid->intf, &hiddev_class);
+
+	if (hiddev->open) {
+		usbhid_close(hiddev->hid);
+		wake_up_interruptible(&hiddev->wait);
+	} else {
+		kfree(hiddev);
+	}
+}
+
+/* Currently this driver is a USB driver.  It's not a conventional one in
+ * the sense that it doesn't probe at the USB level.  Instead it waits to
+ * be connected by HID through the hiddev_connect / hiddev_disconnect
+ * routines.  The reason to register as a USB device is to gain part of the
+ * minor number space from the USB major.
+ *
+ * In theory, should the HID code be generalized to more than one physical
+ * medium (say, IEEE 1384), this driver will probably need to register its
+ * own major number, and in doing so, no longer need to register with USB.
+ * At that point the probe routine and hiddev_driver struct below will no
+ * longer be useful.
+ */
+
+
+/* We never attach in this manner, and rely on HID to connect us.  This
+ * is why there is no disconnect routine defined in the usb_driver either.
+ */
+static int hiddev_usbd_probe(struct usb_interface *intf,
+			     const struct usb_device_id *hiddev_info)
+{
+	return -ENODEV;
+}
+
+
+static /* const */ struct usb_driver hiddev_driver = {
+	.name =		"hiddev",
+	.probe =	hiddev_usbd_probe,
+};
+
+int __init hiddev_init(void)
+{
+	return usb_register(&hiddev_driver);
+}
+
+void hiddev_exit(void)
+{
+	usb_deregister(&hiddev_driver);
+}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
new file mode 100644
index 0000000..0023f96
--- /dev/null
+++ b/drivers/hid/usbhid/usbhid.h
@@ -0,0 +1,87 @@
+#ifndef __USBHID_H
+#define __USBHID_H
+
+/*
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *  Copyright (c) 2006 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/slab.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+
+/*  API provided by hid-core.c for USB HID drivers */
+int usbhid_wait_io(struct hid_device* hid);
+void usbhid_close(struct hid_device *hid);
+int usbhid_open(struct hid_device *hid);
+void usbhid_init_reports(struct hid_device *hid);
+void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+
+/*
+ * USB-specific HID struct, to be pointed to
+ * from struct hid_device->driver_data
+ */
+
+struct usbhid_device {
+	struct hid_device *hid;						/* pointer to corresponding HID dev */
+
+	struct usb_interface *intf;                                     /* USB interface */
+	int ifnum;                                                      /* USB interface number */
+
+	unsigned int bufsize;                                           /* URB buffer size */
+
+	struct urb *urbin;                                              /* Input URB */
+	char *inbuf;                                                    /* Input buffer */
+	dma_addr_t inbuf_dma;                                           /* Input buffer dma */
+	spinlock_t inlock;                                              /* Input fifo spinlock */
+
+	struct urb *urbctrl;                                            /* Control URB */
+	struct usb_ctrlrequest *cr;                                     /* Control request struct */
+	dma_addr_t cr_dma;                                              /* Control request struct dma */
+	struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];  		/* Control fifo */
+	unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
+	char *ctrlbuf;                                                  /* Control buffer */
+	dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
+	spinlock_t ctrllock;                                            /* Control fifo spinlock */
+
+	struct urb *urbout;                                             /* Output URB */
+	struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
+	unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
+	char *outbuf;                                                   /* Output buffer */
+	dma_addr_t outbuf_dma;                                          /* Output buffer dma */
+	spinlock_t outlock;                                             /* Output fifo spinlock */
+
+	unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	struct timer_list io_retry;                                     /* Retry timer */
+	unsigned long stop_retry;                                       /* Time to give up, in jiffies */
+	unsigned int retry_delay;                                       /* Delay length in ms */
+	struct work_struct reset_work;                                  /* Task context for resets */
+
+};
+
+#define	hid_to_usb_dev(hid_dev) \
+	container_of(hid_dev->dev->parent, struct usb_device, dev)
+
+#endif
+
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
new file mode 100644
index 0000000..65aa12e
--- /dev/null
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -0,0 +1,367 @@
+/*
+ * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  USB HIDBP Keyboard 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION ""
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+static unsigned char usb_kbd_keycode[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
+	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
+	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+struct usb_kbd {
+	struct input_dev *dev;
+	struct usb_device *usbdev;
+	unsigned char old[8];
+	struct urb *irq, *led;
+	unsigned char newleds;
+	char name[128];
+	char phys[64];
+
+	unsigned char *new;
+	struct usb_ctrlrequest *cr;
+	unsigned char *leds;
+	dma_addr_t cr_dma;
+	dma_addr_t new_dma;
+	dma_addr_t leds_dma;
+};
+
+static void usb_kbd_irq(struct urb *urb)
+{
+	struct usb_kbd *kbd = urb->context;
+	int i;
+
+	switch (urb->status) {
+	case 0:			/* success */
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	/* -EPIPE:  should clear the halt */
+	default:		/* error */
+		goto resubmit;
+	}
+
+	for (i = 0; i < 8; i++)
+		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
+
+	for (i = 2; i < 8; i++) {
+
+		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
+			if (usb_kbd_keycode[kbd->old[i]])
+				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
+			else
+				info("Unknown key (scancode %#x) released.", kbd->old[i]);
+		}
+
+		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
+			if (usb_kbd_keycode[kbd->new[i]])
+				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
+			else
+				info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+		}
+	}
+
+	input_sync(kbd->dev);
+
+	memcpy(kbd->old, kbd->new, 8);
+
+resubmit:
+	i = usb_submit_urb (urb, GFP_ATOMIC);
+	if (i)
+		err ("can't resubmit intr, %s-%s/input0, status %d",
+				kbd->usbdev->bus->bus_name,
+				kbd->usbdev->devpath, i);
+}
+
+static int usb_kbd_event(struct input_dev *dev, unsigned int type,
+			 unsigned int code, int value)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	if (type != EV_LED)
+		return -1;
+
+
+	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
+		       (!!test_bit(LED_NUML,    dev->led));
+
+	if (kbd->led->status == -EINPROGRESS)
+		return 0;
+
+	if (*(kbd->leds) == kbd->newleds)
+		return 0;
+
+	*(kbd->leds) = kbd->newleds;
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
+		err("usb_submit_urb(leds) failed");
+
+	return 0;
+}
+
+static void usb_kbd_led(struct urb *urb)
+{
+	struct usb_kbd *kbd = urb->context;
+
+	if (urb->status)
+		warn("led urb status %d received", urb->status);
+
+	if (*(kbd->leds) == kbd->newleds)
+		return;
+
+	*(kbd->leds) = kbd->newleds;
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
+		err("usb_submit_urb(leds) failed");
+}
+
+static int usb_kbd_open(struct input_dev *dev)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	kbd->irq->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_kbd_close(struct input_dev *dev)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	usb_kill_urb(kbd->irq);
+}
+
+static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
+{
+	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
+		return -1;
+	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
+		return -1;
+	if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
+		return -1;
+	if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
+		return -1;
+	if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
+		return -1;
+
+	return 0;
+}
+
+static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
+{
+	usb_free_urb(kbd->irq);
+	usb_free_urb(kbd->led);
+	if (kbd->new)
+		usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
+	if (kbd->cr)
+		usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
+	if (kbd->leds)
+		usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+}
+
+static int usb_kbd_probe(struct usb_interface *iface,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(iface);
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_kbd *kbd;
+	struct input_dev *input_dev;
+	int i, pipe, maxp;
+	int error = -ENOMEM;
+
+	interface = iface->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!kbd || !input_dev)
+		goto fail1;
+
+	if (usb_kbd_alloc_mem(dev, kbd))
+		goto fail2;
+
+	kbd->usbdev = dev;
+	kbd->dev = input_dev;
+
+	if (dev->manufacturer)
+		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(kbd->name, " ", sizeof(kbd->name));
+		strlcat(kbd->name, dev->product, sizeof(kbd->name));
+	}
+
+	if (!strlen(kbd->name))
+		snprintf(kbd->name, sizeof(kbd->name),
+			 "USB HIDBP Keyboard %04x:%04x",
+			 le16_to_cpu(dev->descriptor.idVendor),
+			 le16_to_cpu(dev->descriptor.idProduct));
+
+	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
+	strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
+
+	input_dev->name = kbd->name;
+	input_dev->phys = kbd->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->cdev.dev = &iface->dev;
+	input_dev->private = kbd;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+	input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
+
+	for (i = 0; i < 255; i++)
+		set_bit(usb_kbd_keycode[i], input_dev->keybit);
+	clear_bit(0, input_dev->keybit);
+
+	input_dev->event = usb_kbd_event;
+	input_dev->open = usb_kbd_open;
+	input_dev->close = usb_kbd_close;
+
+	usb_fill_int_urb(kbd->irq, dev, pipe,
+			 kbd->new, (maxp > 8 ? 8 : maxp),
+			 usb_kbd_irq, kbd, endpoint->bInterval);
+	kbd->irq->transfer_dma = kbd->new_dma;
+	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kbd->cr->bRequest = 0x09;
+	kbd->cr->wValue = cpu_to_le16(0x200);
+	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
+	kbd->cr->wLength = cpu_to_le16(1);
+
+	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
+			     (void *) kbd->cr, kbd->leds, 1,
+			     usb_kbd_led, kbd);
+	kbd->led->setup_dma = kbd->cr_dma;
+	kbd->led->transfer_dma = kbd->leds_dma;
+	kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+
+	error = input_register_device(kbd->dev);
+	if (error)
+		goto fail2;
+
+	usb_set_intfdata(iface, kbd);
+	return 0;
+
+fail2:	
+	usb_kbd_free_mem(dev, kbd);
+fail1:	
+	input_free_device(input_dev);
+	kfree(kbd);
+	return error;
+}
+
+static void usb_kbd_disconnect(struct usb_interface *intf)
+{
+	struct usb_kbd *kbd = usb_get_intfdata (intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (kbd) {
+		usb_kill_urb(kbd->irq);
+		input_unregister_device(kbd->dev);
+		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
+		kfree(kbd);
+	}
+}
+
+static struct usb_device_id usb_kbd_id_table [] = {
+	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+		USB_INTERFACE_PROTOCOL_KEYBOARD) },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
+
+static struct usb_driver usb_kbd_driver = {
+	.name =		"usbkbd",
+	.probe =	usb_kbd_probe,
+	.disconnect =	usb_kbd_disconnect,
+	.id_table =	usb_kbd_id_table,
+};
+
+static int __init usb_kbd_init(void)
+{
+	int result = usb_register(&usb_kbd_driver);
+	if (result == 0)
+		info(DRIVER_VERSION ":" DRIVER_DESC);
+	return result;
+}
+
+static void __exit usb_kbd_exit(void)
+{
+	usb_deregister(&usb_kbd_driver);
+}
+
+module_init(usb_kbd_init);
+module_exit(usb_kbd_exit);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
new file mode 100644
index 0000000..573776d
--- /dev/null
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -0,0 +1,252 @@
+/*
+ * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ *  USB HIDBP Mouse 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.6"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+struct usb_mouse {
+	char name[128];
+	char phys[64];
+	struct usb_device *usbdev;
+	struct input_dev *dev;
+	struct urb *irq;
+
+	signed char *data;
+	dma_addr_t data_dma;
+};
+
+static void usb_mouse_irq(struct urb *urb)
+{
+	struct usb_mouse *mouse = urb->context;
+	signed char *data = mouse->data;
+	struct input_dev *dev = mouse->dev;
+	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;
+	}
+
+	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);
+	input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
+	input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
+
+	input_report_rel(dev, REL_X,     data[1]);
+	input_report_rel(dev, REL_Y,     data[2]);
+	input_report_rel(dev, REL_WHEEL, data[3]);
+
+	input_sync(dev);
+resubmit:
+	status = usb_submit_urb (urb, GFP_ATOMIC);
+	if (status)
+		err ("can't resubmit intr, %s-%s/input0, status %d",
+				mouse->usbdev->bus->bus_name,
+				mouse->usbdev->devpath, status);
+}
+
+static int usb_mouse_open(struct input_dev *dev)
+{
+	struct usb_mouse *mouse = dev->private;
+
+	mouse->irq->dev = mouse->usbdev;
+	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_mouse_close(struct input_dev *dev)
+{
+	struct usb_mouse *mouse = dev->private;
+
+	usb_kill_urb(mouse->irq);
+}
+
+static int usb_mouse_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 usb_mouse *mouse;
+	struct input_dev *input_dev;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+
+	if (interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!mouse || !input_dev)
+		goto fail1;
+
+	mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
+	if (!mouse->data)
+		goto fail1;
+
+	mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!mouse->irq)
+		goto fail2;
+
+	mouse->usbdev = dev;
+	mouse->dev = input_dev;
+
+	if (dev->manufacturer)
+		strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(mouse->name, " ", sizeof(mouse->name));
+		strlcat(mouse->name, dev->product, sizeof(mouse->name));
+	}
+
+	if (!strlen(mouse->name))
+		snprintf(mouse->name, sizeof(mouse->name),
+			 "USB HIDBP Mouse %04x:%04x",
+			 le16_to_cpu(dev->descriptor.idVendor),
+			 le16_to_cpu(dev->descriptor.idProduct));
+
+	usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
+	strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
+
+	input_dev->name = mouse->name;
+	input_dev->phys = mouse->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->cdev.dev = &intf->dev;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+	input_dev->relbit[0] |= BIT(REL_WHEEL);
+
+	input_dev->private = mouse;
+	input_dev->open = usb_mouse_open;
+	input_dev->close = usb_mouse_close;
+
+	usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
+			 (maxp > 8 ? 8 : maxp),
+			 usb_mouse_irq, mouse, endpoint->bInterval);
+	mouse->irq->transfer_dma = mouse->data_dma;
+	mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(mouse->dev);
+	if (error)
+		goto fail3;
+
+	usb_set_intfdata(intf, mouse);
+	return 0;
+
+fail3:	
+	usb_free_urb(mouse->irq);
+fail2:	
+	usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
+fail1:	
+	input_free_device(input_dev);
+	kfree(mouse);
+	return error;
+}
+
+static void usb_mouse_disconnect(struct usb_interface *intf)
+{
+	struct usb_mouse *mouse = usb_get_intfdata (intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (mouse) {
+		usb_kill_urb(mouse->irq);
+		input_unregister_device(mouse->dev);
+		usb_free_urb(mouse->irq);
+		usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
+		kfree(mouse);
+	}
+}
+
+static struct usb_device_id usb_mouse_id_table [] = {
+	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+		USB_INTERFACE_PROTOCOL_MOUSE) },
+	{ }	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
+
+static struct usb_driver usb_mouse_driver = {
+	.name		= "usbmouse",
+	.probe		= usb_mouse_probe,
+	.disconnect	= usb_mouse_disconnect,
+	.id_table	= usb_mouse_id_table,
+};
+
+static int __init usb_mouse_init(void)
+{
+	int retval = usb_register(&usb_mouse_driver);
+	if (retval == 0)
+		info(DRIVER_VERSION ":" DRIVER_DESC);
+	return retval;
+}
+
+static void __exit usb_mouse_exit(void)
+{
+	usb_deregister(&usb_mouse_driver);
+}
+
+module_init(usb_mouse_init);
+module_exit(usb_mouse_exit);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6d105a1..3ba3a52 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2,9 +2,7 @@ #
 # Hardware monitoring chip drivers configuration
 #
 
-menu "Hardware Monitoring support"
-
-config HWMON
+menuconfig HWMON
 	tristate "Hardware Monitoring support"
 	default y
 	help
@@ -23,13 +21,15 @@ config HWMON
 	  This support can also be built as a module.  If so, the module
 	  will be called hwmon.
 
+if HWMON
+
 config HWMON_VID
 	tristate
 	default n
 
 config SENSORS_ABITUGURU
 	tristate "Abit uGuru"
-	depends on HWMON && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Abit uGuru chips
 	  sensor part. The voltage and frequency control parts of the Abit
@@ -39,9 +39,19 @@ config SENSORS_ABITUGURU
 	  This driver can also be built as a module.  If so, the module
 	  will be called abituguru.
 
+config SENSORS_AD7418
+	tristate "Analog Devices AD7416, AD7417 and AD7418"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7416, AD7417 and AD7418 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7418.
+
 config SENSORS_ADM1021
 	tristate "Analog Devices ADM1021 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for Analog Devices ADM1021
 	  and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -53,7 +63,7 @@ config SENSORS_ADM1021
 
 config SENSORS_ADM1025
 	tristate "Analog Devices ADM1025 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for Analog Devices ADM1025
@@ -64,7 +74,7 @@ config SENSORS_ADM1025
 
 config SENSORS_ADM1026
 	tristate "Analog Devices ADM1026 and compatibles"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for Analog Devices ADM1026
@@ -75,7 +85,7 @@ config SENSORS_ADM1026
 
 config SENSORS_ADM1029
 	tristate "Analog Devices ADM1029"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for Analog Devices ADM1029
 	  sensor chip.
@@ -86,7 +96,7 @@ config SENSORS_ADM1029
 
 config SENSORS_ADM1031
 	tristate "Analog Devices ADM1031 and compatibles"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for Analog Devices ADM1031
 	  and ADM1030 sensor chips.
@@ -96,7 +106,7 @@ config SENSORS_ADM1031
 
 config SENSORS_ADM9240
 	tristate "Analog Devices ADM9240 and compatibles"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for Analog Devices ADM9240,
@@ -107,7 +117,7 @@ config SENSORS_ADM9240
 
 config SENSORS_K8TEMP
 	tristate "AMD Athlon64/FX or Opteron temperature sensor"
-	depends on HWMON && X86 && PCI && EXPERIMENTAL
+	depends on 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
@@ -119,7 +129,7 @@ config SENSORS_K8TEMP
 
 config SENSORS_AMS
 	tristate "Apple Motion Sensor driver"
-	depends on HWMON && PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+	depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
 	help
 	  Support for the motion sensor included in PowerBooks. Includes
 	  implementations for PMU and I2C.
@@ -144,7 +154,7 @@ config SENSORS_AMS_I2C
 
 config SENSORS_ASB100
 	tristate "Asus ASB100 Bach"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the ASB100 Bach sensor
@@ -155,7 +165,7 @@ config SENSORS_ASB100
 
 config SENSORS_ATXP1
 	tristate "Attansic ATXP1 VID controller"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Attansic ATXP1 VID
@@ -169,7 +179,7 @@ config SENSORS_ATXP1
 
 config SENSORS_DS1621
 	tristate "Dallas Semiconductor DS1621 and DS1625"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for Dallas Semiconductor
 	  DS1621 and DS1625 sensor chips.
@@ -179,7 +189,7 @@ config SENSORS_DS1621
 
 config SENSORS_F71805F
 	tristate "Fintek F71805F/FG and F71872F/FG"
-	depends on HWMON && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for hardware monitoring
 	  features of the Fintek F71805F/FG and F71872F/FG Super-I/O
@@ -190,7 +200,7 @@ config SENSORS_F71805F
 
 config SENSORS_FSCHER
 	tristate "FSC Hermes"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for Fujitsu Siemens
 	  Computers Hermes sensor chips.
@@ -200,7 +210,7 @@ config SENSORS_FSCHER
 
 config SENSORS_FSCPOS
 	tristate "FSC Poseidon"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for Fujitsu Siemens
 	  Computers Poseidon sensor chips.
@@ -210,7 +220,7 @@ config SENSORS_FSCPOS
 
 config SENSORS_GL518SM
 	tristate "Genesys Logic GL518SM"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for Genesys Logic GL518SM
 	  sensor chips.
@@ -220,7 +230,7 @@ config SENSORS_GL518SM
 
 config SENSORS_GL520SM
 	tristate "Genesys Logic GL520SM"
-	depends on HWMON && I2C
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for Genesys Logic GL520SM
@@ -229,9 +239,17 @@ config SENSORS_GL520SM
 	  This driver can also be built as a module.  If so, the module
 	  will be called gl520sm.
 
+config SENSORS_CORETEMP
+	tristate "Intel Core (2) Duo/Solo temperature sensor"
+	depends on X86 && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the temperature
+	  sensor inside your CPU. Supported all are all known variants
+	  of Intel Core family.
+
 config SENSORS_IT87
 	tristate "ITE IT87xx and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	select I2C_ISA
 	select HWMON_VID
 	help
@@ -243,7 +261,7 @@ config SENSORS_IT87
 
 config SENSORS_LM63
 	tristate "National Semiconductor LM63"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for the National Semiconductor
 	  LM63 remote diode digital temperature sensor with integrated fan
@@ -255,7 +273,7 @@ config SENSORS_LM63
 
 config SENSORS_LM70
 	tristate "National Semiconductor LM70"
-	depends on HWMON && SPI_MASTER && EXPERIMENTAL
+	depends on SPI_MASTER && EXPERIMENTAL
 	help
 	  If you say yes here you get support for the National Semiconductor
 	  LM70 digital temperature sensor chip.
@@ -265,7 +283,7 @@ config SENSORS_LM70
 
 config SENSORS_LM75
 	tristate "National Semiconductor LM75 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor LM75
 	  sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
@@ -280,7 +298,7 @@ config SENSORS_LM75
 
 config SENSORS_LM77
 	tristate "National Semiconductor LM77"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor LM77
 	  sensor chips.
@@ -290,8 +308,7 @@ config SENSORS_LM77
 
 config SENSORS_LM78
 	tristate "National Semiconductor LM78 and compatibles"
-	depends on HWMON && I2C
-	select I2C_ISA
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for National Semiconductor LM78,
@@ -302,7 +319,7 @@ config SENSORS_LM78
 
 config SENSORS_LM80
 	tristate "National Semiconductor LM80"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for National Semiconductor
 	  LM80 sensor chips.
@@ -312,7 +329,7 @@ config SENSORS_LM80
 
 config SENSORS_LM83
 	tristate "National Semiconductor LM83 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor
 	  LM82 and LM83 sensor chips.
@@ -322,7 +339,7 @@ config SENSORS_LM83
 
 config SENSORS_LM85
 	tristate "National Semiconductor LM85 and compatibles"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for National Semiconductor LM85
@@ -333,7 +350,7 @@ config SENSORS_LM85
 
 config SENSORS_LM87
 	tristate "National Semiconductor LM87"
-	depends on HWMON && I2C
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for National Semiconductor LM87
@@ -344,7 +361,7 @@ config SENSORS_LM87
 
 config SENSORS_LM90
 	tristate "National Semiconductor LM90 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor LM90,
 	  LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
@@ -358,7 +375,7 @@ config SENSORS_LM90
 
 config SENSORS_LM92
 	tristate "National Semiconductor LM92 and compatibles"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor LM92
 	  and Maxim MAX6635 sensor chips.
@@ -368,16 +385,26 @@ config SENSORS_LM92
 
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
-	depends on HWMON && I2C
+	depends on I2C
 	help
 	  If you say yes here you get support for MAX1619 sensor chip.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called max1619.
 
+config SENSORS_MAX6650
+	tristate "Maxim MAX6650 sensor chip"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the MAX6650 / MAX6651
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max6650.
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select I2C_ISA
 	select HWMON_VID
 	help
@@ -392,7 +419,7 @@ config SENSORS_PC87360
 
 config SENSORS_PC87427
 	tristate "National Semiconductor PC87427"
-	depends on HWMON && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get access to the hardware monitoring
 	  functions of the National Semiconductor PC87427 Super-I/O chip.
@@ -405,7 +432,7 @@ config SENSORS_PC87427
 
 config SENSORS_SIS5595
 	tristate "Silicon Integrated Systems Corp. SiS5595"
-	depends on HWMON && I2C && PCI && EXPERIMENTAL
+	depends on I2C && PCI && EXPERIMENTAL
 	select I2C_ISA
 	help
 	  If you say yes here you get support for the integrated sensors in
@@ -416,28 +443,28 @@ config SENSORS_SIS5595
 
 config SENSORS_SMSC47M1
 	tristate "SMSC LPC47M10x and compatibles"
-	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, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x,
-	  LPC47M192 and LPC47M997 chips.
+	  LPC47M192, LPC47M292 and LPC47M997 chips.
 
-	  The temperature and voltage sensor features of the LPC47M192
-	  and LPC47M997 are supported by another driver, select also
-	  "SMSC LPC47M192 and compatibles" below for those.
+	  The temperature and voltage sensor features of the LPC47M15x,
+	  LPC47M192, LPC47M292 and LPC47M997 are supported by another
+	  driver, select also "SMSC LPC47M192 and compatibles" below for
+	  those.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called smsc47m1.
 
 config SENSORS_SMSC47M192
 	tristate "SMSC LPC47M192 and compatibles"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the temperature and
-	  voltage sensors of the SMSC LPC47M192 and LPC47M997 chips.
+	  voltage sensors of the SMSC LPC47M192, LPC47M15x, LPC47M292
+	  and LPC47M997 chips.
 
 	  The fan monitoring and control capabilities of these chips
 	  are supported by another driver, select
@@ -449,8 +476,7 @@ config SENSORS_SMSC47M192
 
 config SENSORS_SMSC47B397
 	tristate "SMSC LPC47B397-NC"
-	depends on HWMON && I2C && EXPERIMENTAL
-	select I2C_ISA
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for the SMSC LPC47B397-NC
 	  sensor chip.
@@ -460,7 +486,7 @@ config SENSORS_SMSC47B397
 
 config SENSORS_VIA686A
 	tristate "VIA686A"
-	depends on HWMON && I2C && PCI
+	depends on I2C && PCI
 	select I2C_ISA
 	help
 	  If you say yes here you get support for the integrated sensors in
@@ -471,7 +497,7 @@ config SENSORS_VIA686A
 
 config SENSORS_VT1211
 	tristate "VIA VT1211"
-	depends on HWMON && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here then you get support for hardware monitoring
@@ -482,7 +508,7 @@ config SENSORS_VT1211
 
 config SENSORS_VT8231
 	tristate "VIA VT8231"
-	depends on HWMON && I2C && PCI && EXPERIMENTAL
+	depends on I2C && PCI && EXPERIMENTAL
 	select HWMON_VID
 	select I2C_ISA
 	help
@@ -494,8 +520,7 @@ config SENSORS_VT8231
 
 config SENSORS_W83781D
 	tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
-	depends on HWMON && I2C
-	select I2C_ISA
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W8378x series
@@ -507,7 +532,7 @@ config SENSORS_W83781D
 
 config SENSORS_W83791D
 	tristate "Winbond W83791D"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W83791D chip.
@@ -517,7 +542,7 @@ config SENSORS_W83791D
 
 config SENSORS_W83792D
 	tristate "Winbond W83792D"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Winbond W83792D chip.
 
@@ -526,7 +551,7 @@ config SENSORS_W83792D
 
 config SENSORS_W83793
 	tristate "Winbond W83793"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W83793
@@ -537,7 +562,7 @@ config SENSORS_W83793
 
 config SENSORS_W83L785TS
 	tristate "Winbond W83L785TS-S"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Winbond W83L785TS-S
 	  sensor chip, which is used on the Asus A7N8X, among other
@@ -548,8 +573,6 @@ config SENSORS_W83L785TS
 
 config SENSORS_W83627HF
 	tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
-	depends on HWMON && I2C
-	select I2C_ISA
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Winbond W836X7 series
@@ -561,7 +584,7 @@ config SENSORS_W83627HF
 
 config SENSORS_W83627EHF
 	tristate "Winbond W83627EHF"
-	depends on HWMON && I2C && EXPERIMENTAL
+	depends on I2C && EXPERIMENTAL
 	select I2C_ISA
 	help
 	  If you say yes here you get preliminary support for the hardware
@@ -577,7 +600,7 @@ config SENSORS_W83627EHF
 
 config SENSORS_HDAPS
 	tristate "IBM Hard Drive Active Protection System (hdaps)"
-	depends on HWMON && INPUT && X86
+	depends on INPUT && X86
 	default n
 	help
 	  This driver provides support for the IBM Hard Drive Active Protection
@@ -594,9 +617,32 @@ config SENSORS_HDAPS
 	  Say Y here if you have an applicable laptop and want to experience
 	  the awesome power of hdaps.
 
+config SENSORS_APPLESMC
+	tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+	depends on HWMON && INPUT && X86
+	select NEW_LEDS
+	select LEDS_CLASS
+	default n
+	help
+	  This driver provides support for the Apple System Management
+	  Controller, which provides an accelerometer (Apple Sudden Motion
+	  Sensor), light sensors, temperature sensors, keyboard backlight
+	  control and fan control.
+
+	  Only Intel-based Apple's computers are supported (MacBook Pro,
+	  MacBook, MacMini).
+
+	  Data from the different sensors, keyboard backlight control and fan
+	  control are accessible via sysfs.
+
+	  This driver also provides an absolute input class device, allowing
+	  the laptop to act as a pinball machine-esque joystick.
+
+	  Say Y here if you have an applicable laptop and want to experience
+	  the awesome power of applesmc.
+
 config HWMON_DEBUG_CHIP
 	bool "Hardware Monitoring Chip debugging messages"
-	depends on HWMON
 	default n
 	help
 	  Say Y here if you want the I2C chip drivers to produce a bunch of
@@ -604,4 +650,4 @@ config HWMON_DEBUG_CHIP
 	  a problem with I2C support and want to see more of what is going
 	  on.
 
-endmenu
+endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4165c27..cfaf338 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -14,14 +14,17 @@ obj-$(CONFIG_SENSORS_W83781D)	+= w83781d
 obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
+obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
 obj-$(CONFIG_SENSORS_ADM1026)	+= adm1026.o
 obj-$(CONFIG_SENSORS_ADM1029)	+= adm1029.o
 obj-$(CONFIG_SENSORS_ADM1031)	+= adm1031.o
 obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
+obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
 obj-$(CONFIG_SENSORS_AMS)	+= ams/
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
+obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_F71805F)	+= f71805f.o
 obj-$(CONFIG_SENSORS_FSCHER)	+= fscher.o
@@ -43,6 +46,7 @@ obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
+obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 obj-$(CONFIG_SENSORS_SIS5595)	+= sis5595.o
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
new file mode 100644
index 0000000..cc8b624
--- /dev/null
+++ b/drivers/hwmon/ad7418.c
@@ -0,0 +1,373 @@
+/*
+ * An hwmon driver for the Analog Devices AD7416/17/18
+ * Copyright (C) 2006-07 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * Based on lm75.c
+ * Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; 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.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include "lm75.h"
+
+#define DRV_VERSION "0.3"
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418);
+
+/* AD7418 registers */
+#define AD7418_REG_TEMP_IN	0x00
+#define AD7418_REG_CONF		0x01
+#define AD7418_REG_TEMP_HYST	0x02
+#define AD7418_REG_TEMP_OS	0x03
+#define AD7418_REG_ADC		0x04
+#define AD7418_REG_CONF2	0x05
+
+#define AD7418_REG_ADC_CH(x)	((x) << 5)
+#define AD7418_CH_TEMP		AD7418_REG_ADC_CH(0)
+
+static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
+					AD7418_REG_TEMP_HYST,
+					AD7418_REG_TEMP_OS };
+
+struct ad7418_data {
+	struct i2c_client	client;
+	struct class_device	*class_dev;
+	struct attribute_group	attrs;
+	enum chips		type;
+	struct mutex		lock;
+	int			adc_max;	/* number of ADC channels */
+	char			valid;
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[3];	/* Register values */
+	u16			in[4];
+};
+
+static int ad7418_attach_adapter(struct i2c_adapter *adapter);
+static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ad7418_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7418_driver = {
+	.driver = {
+		.name	= "ad7418",
+	},
+	.attach_adapter	= ad7418_attach_adapter,
+	.detach_client	= ad7418_detach_client,
+};
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7418 uses a high-byte first convention. Do NOT use those functions to
+ * access the configuration registers CONF and CONF2, as they are byte-sized.
+ */
+static inline int ad7418_read(struct i2c_client *client, u8 reg)
+{
+	return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	return i2c_smbus_write_word_data(client, reg, swab16(value));
+}
+
+static void ad7418_init_client(struct i2c_client *client)
+{
+	struct ad7418_data *data = i2c_get_clientdata(client);
+
+	int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+	if (reg < 0) {
+		dev_err(&client->dev, "cannot read configuration register\n");
+	} else {
+		dev_info(&client->dev, "configuring for mode 1\n");
+		i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
+
+		if (data->type == ad7417 || data->type == ad7418)
+			i2c_smbus_write_byte_data(client,
+						AD7418_REG_CONF2, 0x00);
+	}
+}
+
+static struct ad7418_data *ad7418_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ad7418_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+		u8 cfg;
+		int i, ch;
+
+		/* read config register and clear channel bits */
+		cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+		cfg &= 0x1F;
+
+		i2c_smbus_write_byte_data(client, AD7418_REG_CONF,
+						cfg | AD7418_CH_TEMP);
+		udelay(30);
+
+		for (i = 0; i < 3; i++) {
+			data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]);
+		}
+
+		for (i = 0, ch = 4; i < data->adc_max; i++, ch--) {
+			i2c_smbus_write_byte_data(client,
+					AD7418_REG_CONF,
+					cfg | AD7418_REG_ADC_CH(ch));
+
+			udelay(15);
+			data->in[data->adc_max - 1 - i] =
+				ad7418_read(client, AD7418_REG_ADC);
+		}
+
+		/* restore old configuration value */
+		ad7418_write(client, AD7418_REG_CONF, cfg);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct ad7418_data *data = ad7418_update_device(dev);
+	return sprintf(buf, "%d\n",
+		LM75_TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
+			char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct ad7418_data *data = ad7418_update_device(dev);
+
+	return sprintf(buf, "%d\n",
+		((data->in[attr->index] >> 6) * 2500 + 512) / 1024);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ad7418_data *data = i2c_get_clientdata(client);
+	int temp = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->lock);
+	data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
+	ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]);
+	mutex_unlock(&data->lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+				show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+				show_temp, set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
+
+static int ad7418_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_probe(adapter, &addr_data, ad7418_detect);
+}
+
+static struct attribute *ad7416_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	NULL
+};
+
+static struct attribute *ad7417_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_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,
+	NULL
+};
+
+static struct attribute *ad7418_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	NULL
+};
+
+static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct ad7418_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ad7418_driver;
+
+	i2c_set_clientdata(client, data);
+
+	mutex_init(&data->lock);
+
+	/* AD7418 has a curious behaviour on registers 6 and 7. They
+	 * both always read 0xC071 and are not documented on the datasheet.
+	 * We use them to detect the chip.
+	 */
+	if (kind <= 0) {
+		int reg, reg6, reg7;
+
+		/* the AD7416 lies within this address range, but I have
+		 * no means to check.
+		 */
+		if (address >= 0x48 && address <= 0x4f) {
+			/* XXX add tests for AD7416 here */
+			/* data->type = ad7416; */
+		}
+		/* here we might have AD7417 or AD7418 */
+		else if (address >= 0x28 && address <= 0x2f) {
+			reg6 = i2c_smbus_read_word_data(client, 0x06);
+			reg7 = i2c_smbus_read_word_data(client, 0x07);
+
+			if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071)
+				data->type = ad7418;
+
+			/* XXX add tests for AD7417 here */
+
+
+			/* both AD7417 and AD7418 have bits 0-5 of
+			 * the CONF2 register at 0
+			 */
+			reg = i2c_smbus_read_byte_data(client,
+							AD7418_REG_CONF2);
+			if (reg & 0x3F)
+				data->type = any_chip; /* detection failed */
+		}
+	} else {
+		dev_dbg(&adapter->dev, "detection forced\n");
+	}
+
+	if (kind > 0)
+		data->type = kind;
+	else if (kind < 0 && data->type == any_chip) {
+		err = -ENODEV;
+		goto exit_free;
+	}
+
+	switch (data->type) {
+	case any_chip:
+	case ad7416:
+		data->adc_max = 0;
+		data->attrs.attrs = ad7416_attributes;
+		strlcpy(client->name, "ad7416", I2C_NAME_SIZE);
+		break;
+
+	case ad7417:
+		data->adc_max = 4;
+		data->attrs.attrs = ad7417_attributes;
+		strlcpy(client->name, "ad7417", I2C_NAME_SIZE);
+		break;
+
+	case ad7418:
+		data->adc_max = 1;
+		data->attrs.attrs = ad7418_attributes;
+		strlcpy(client->name, "ad7418", I2C_NAME_SIZE);
+		break;
+	}
+
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	dev_info(&client->dev, "%s chip found\n", client->name);
+
+	/* Initialize the AD7418 chip */
+	ad7418_init_client(client);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
+		goto exit_detach;
+
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ad7418_detach_client(struct i2c_client *client)
+{
+	struct ad7418_data *data = i2c_get_clientdata(client);
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&client->dev.kobj, &data->attrs);
+	i2c_detach_client(client);
+	kfree(data);
+	return 0;
+}
+
+static int __init ad7418_init(void)
+{
+	return i2c_add_driver(&ad7418_driver);
+}
+
+static void __exit ad7418_exit(void)
+{
+	i2c_del_driver(&ad7418_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("AD7416/17/18 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7418_init);
+module_exit(ad7418_exit);
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index f1f0f5d..6db9737 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -141,10 +141,10 @@ static void ams_worker(struct work_struc
 int ams_sensor_attach(void)
 {
 	int result;
-	u32 *prop;
+	const u32 *prop;
 
 	/* Get orientation */
-	prop = (u32*)get_property(ams_info.of_node, "orientation", NULL);
+	prop = of_get_property(ams_info.of_node, "orientation", NULL);
 	if (!prop)
 		return -ENODEV;
 	ams_info.orient1 = *prop;
@@ -208,20 +208,17 @@ int __init ams_init(void)
 
 #ifdef CONFIG_SENSORS_AMS_I2C
 	np = of_find_node_by_name(NULL, "accelerometer");
-	if (np && device_is_compatible(np, "AAPL,accelerometer_1"))
+	if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
 		/* Found I2C motion sensor */
 		return ams_i2c_init(np);
 #endif
 
 #ifdef CONFIG_SENSORS_AMS_PMU
 	np = of_find_node_by_name(NULL, "sms");
-	if (np && device_is_compatible(np, "sms"))
+	if (np && of_device_is_compatible(np, "sms"))
 		/* Found PMU motion sensor */
 		return ams_pmu_init(np);
 #endif
-
-	printk(KERN_ERR "ams: No motion sensor found.\n");
-
 	return -ENODEV;
 }
 
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
index 0d24bdf..9577605 100644
--- a/drivers/hwmon/ams/ams-i2c.c
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -85,17 +85,17 @@ static int ams_i2c_write(u8 reg, u8 valu
 static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
 {
 	s32 result;
-	int remaining = HZ / 20;
+	int count = 3;
 
 	ams_i2c_write(AMS_COMMAND, cmd);
-	mdelay(5);
+	msleep(5);
 
-	while (remaining) {
+	while (count--) {
 		result = ams_i2c_read(AMS_COMMAND);
 		if (result == 0 || result & 0x80)
 			return 0;
 
-		remaining = schedule_timeout(remaining);
+		schedule_timeout_uninterruptible(HZ / 20);
 	}
 
 	return -1;
@@ -263,7 +263,7 @@ int __init ams_i2c_init(struct device_no
 {
 	char *tmp_bus;
 	int result;
-	u32 *prop;
+	const u32 *prop;
 
 	mutex_lock(&ams_info.lock);
 
@@ -276,7 +276,7 @@ int __init ams_i2c_init(struct device_no
 	ams_info.bustype = BUS_I2C;
 
 	/* look for bus either using "reg" or by path */
-	prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+	prop = of_get_property(ams_info.of_node, "reg", NULL);
 	if (!prop) {
 		result = -ENODEV;
 
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
index 4636ae0..9463e97 100644
--- a/drivers/hwmon/ams/ams-pmu.c
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -146,7 +146,7 @@ static void ams_pmu_exit(void)
 
 int __init ams_pmu_init(struct device_node *np)
 {
-	u32 *prop;
+	const u32 *prop;
 	int result;
 
 	mutex_lock(&ams_info.lock);
@@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_no
 	ams_info.bustype = BUS_HOST;
 
 	/* Get PMU command, should be 0x4e, but we can never know */
-	prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+	prop = of_get_property(ams_info.of_node, "reg", NULL);
 	if (!prop) {
 		result = -ENODEV;
 		goto exit;
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
new file mode 100644
index 0000000..3215f9c
--- /dev/null
+++ b/drivers/hwmon/applesmc.c
@@ -0,0 +1,1339 @@
+/*
+ * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
+ * sensors, fan control, keyboard backlight control) used in Intel-based Apple
+ * computers.
+ *
+ * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ *
+ * Based on hdaps.c driver:
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ *
+ * Fan control based on smcFanControl:
+ * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+#include <linux/leds.h>
+#include <linux/hwmon.h>
+#include <linux/workqueue.h>
+
+/* data port used by Apple SMC */
+#define APPLESMC_DATA_PORT	0x300
+/* command/status port used by Apple SMC */
+#define APPLESMC_CMD_PORT	0x304
+
+#define APPLESMC_NR_PORTS	32 /* 0x300-0x31f */
+
+#define APPLESMC_MAX_DATA_LENGTH 32
+
+#define APPLESMC_STATUS_MASK	0x0f
+#define APPLESMC_READ_CMD	0x10
+#define APPLESMC_WRITE_CMD	0x11
+#define APPLESMC_GET_KEY_BY_INDEX_CMD	0x12
+#define APPLESMC_GET_KEY_TYPE_CMD	0x13
+
+#define KEY_COUNT_KEY		"#KEY" /* r-o ui32 */
+
+#define LIGHT_SENSOR_LEFT_KEY	"ALV0" /* r-o {alv (6 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY	"ALV1" /* r-o {alv (6 bytes) */
+#define BACKLIGHT_KEY 		"LKSB" /* w-o {lkb (2 bytes) */
+
+#define CLAMSHELL_KEY 		"MSLD" /* r-o ui8 (unused) */
+
+#define MOTION_SENSOR_X_KEY	"MO_X" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Y_KEY	"MO_Y" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Z_KEY	"MO_Z" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_KEY	"MOCN" /* r/w ui16 */
+
+#define FANS_COUNT		"FNum" /* r-o ui8 */
+#define FANS_MANUAL		"FS! " /* r-w ui16 */
+#define FAN_ACTUAL_SPEED	"F0Ac" /* r-o fpe2 (2 bytes) */
+#define FAN_MIN_SPEED		"F0Mn" /* r-o fpe2 (2 bytes) */
+#define FAN_MAX_SPEED		"F0Mx" /* r-o fpe2 (2 bytes) */
+#define FAN_SAFE_SPEED		"F0Sf" /* r-o fpe2 (2 bytes) */
+#define FAN_TARGET_SPEED	"F0Tg" /* r-w fpe2 (2 bytes) */
+#define FAN_POSITION		"F0ID" /* r-o char[16] */
+
+/*
+ * Temperature sensors keys (sp78 - 2 bytes).
+ * First set for Macbook(Pro), second for Macmini.
+ */
+static const char* temperature_sensors_sets[][13] = {
+	{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
+	  "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
+	{ "TC0D", "TC0P", NULL }
+};
+
+/* List of keys used to read/write fan speeds */
+static const char* fan_speed_keys[] = {
+	FAN_ACTUAL_SPEED,
+	FAN_MIN_SPEED,
+	FAN_MAX_SPEED,
+	FAN_SAFE_SPEED,
+	FAN_TARGET_SPEED
+};
+
+#define INIT_TIMEOUT_MSECS	5000	/* wait up to 5s for device init ... */
+#define INIT_WAIT_MSECS		50	/* ... in 50ms increments */
+
+#define APPLESMC_POLL_PERIOD	(HZ/20)	/* poll for input every 1/20s */
+#define APPLESMC_INPUT_FUZZ	4	/* input event threshold */
+#define APPLESMC_INPUT_FLAT	4
+
+#define SENSOR_X 0
+#define SENSOR_Y 1
+#define SENSOR_Z 2
+
+/* Structure to be passed to DMI_MATCH function */
+struct dmi_match_data {
+/* Indicates whether this computer has an accelerometer. */
+	int accelerometer;
+/* Indicates whether this computer has light sensors and keyboard backlight. */
+	int light;
+/* Indicates which temperature sensors set to use. */
+	int temperature_set;
+};
+
+static const int debug;
+static struct platform_device *pdev;
+static s16 rest_x;
+static s16 rest_y;
+static struct timer_list applesmc_timer;
+static struct input_dev *applesmc_idev;
+static struct class_device *hwmon_class_dev;
+
+/* Indicates whether this computer has an accelerometer. */
+static unsigned int applesmc_accelerometer;
+
+/* Indicates whether this computer has light sensors and keyboard backlight. */
+static unsigned int applesmc_light;
+
+/* Indicates which temperature sensors set to use. */
+static unsigned int applesmc_temperature_set;
+
+static struct mutex applesmc_lock;
+
+/*
+ * Last index written to key_at_index sysfs file, and value to use for all other
+ * key_at_index_* sysfs files.
+ */
+static unsigned int key_at_index;
+
+static struct workqueue_struct *applesmc_led_wq;
+
+/*
+ * __wait_status - Wait up to 2ms for the status port to get a certain value
+ * (masked with 0x0f), returning zero if the value is obtained.  Callers must
+ * hold applesmc_lock.
+ */
+static int __wait_status(u8 val)
+{
+	unsigned int i;
+
+	val = val & APPLESMC_STATUS_MASK;
+
+	for (i = 0; i < 200; i++) {
+		if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
+			if (debug)
+				printk(KERN_DEBUG
+						"Waited %d us for status %x\n",
+						i*10, val);
+			return 0;
+		}
+		udelay(10);
+	}
+
+	printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
+						val, inb(APPLESMC_CMD_PORT));
+
+	return -EIO;
+}
+
+/*
+ * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_read_key(const char* key, u8* buffer, u8 len)
+{
+	int i;
+
+	if (len > APPLESMC_MAX_DATA_LENGTH) {
+		printk(KERN_ERR	"applesmc_read_key: cannot read more than "
+					"%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+		return -EINVAL;
+	}
+
+	outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
+	if (__wait_status(0x0c))
+		return -EIO;
+
+	for (i = 0; i < 4; i++) {
+		outb(key[i], APPLESMC_DATA_PORT);
+		if (__wait_status(0x04))
+			return -EIO;
+	}
+	if (debug)
+		printk(KERN_DEBUG "<%s", key);
+
+	outb(len, APPLESMC_DATA_PORT);
+	if (debug)
+		printk(KERN_DEBUG ">%x", len);
+
+	for (i = 0; i < len; i++) {
+		if (__wait_status(0x05))
+			return -EIO;
+		buffer[i] = inb(APPLESMC_DATA_PORT);
+		if (debug)
+			printk(KERN_DEBUG "<%x", buffer[i]);
+	}
+	if (debug)
+		printk(KERN_DEBUG "\n");
+
+	return 0;
+}
+
+/*
+ * applesmc_write_key - writes len bytes from buffer to a given key.
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_write_key(const char* key, u8* buffer, u8 len)
+{
+	int i;
+
+	if (len > APPLESMC_MAX_DATA_LENGTH) {
+		printk(KERN_ERR	"applesmc_write_key: cannot write more than "
+					"%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+		return -EINVAL;
+	}
+
+	outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
+	if (__wait_status(0x0c))
+		return -EIO;
+
+	for (i = 0; i < 4; i++) {
+		outb(key[i], APPLESMC_DATA_PORT);
+		if (__wait_status(0x04))
+			return -EIO;
+	}
+
+	outb(len, APPLESMC_DATA_PORT);
+
+	for (i = 0; i < len; i++) {
+		if (__wait_status(0x04))
+			return -EIO;
+		outb(buffer[i], APPLESMC_DATA_PORT);
+	}
+
+	return 0;
+}
+
+/*
+ * applesmc_get_key_at_index - get key at index, and put the result in key
+ * (char[6]). Returns zero on success or a negative error on failure. Callers
+ * must hold applesmc_lock.
+ */
+static int applesmc_get_key_at_index(int index, char* key)
+{
+	int i;
+	u8 readkey[4];
+	readkey[0] = index >> 24;
+	readkey[1] = index >> 16;
+	readkey[2] = index >> 8;
+	readkey[3] = index;
+
+	outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT);
+	if (__wait_status(0x0c))
+		return -EIO;
+
+	for (i = 0; i < 4; i++) {
+		outb(readkey[i], APPLESMC_DATA_PORT);
+		if (__wait_status(0x04))
+			return -EIO;
+	}
+
+	outb(4, APPLESMC_DATA_PORT);
+
+	for (i = 0; i < 4; i++) {
+		if (__wait_status(0x05))
+			return -EIO;
+		key[i] = inb(APPLESMC_DATA_PORT);
+	}
+	key[4] = 0;
+
+	return 0;
+}
+
+/*
+ * applesmc_get_key_type - get key type, and put the result in type (char[6]).
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_get_key_type(char* key, char* type)
+{
+	int i;
+
+	outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT);
+	if (__wait_status(0x0c))
+		return -EIO;
+
+	for (i = 0; i < 4; i++) {
+		outb(key[i], APPLESMC_DATA_PORT);
+		if (__wait_status(0x04))
+			return -EIO;
+	}
+
+	outb(5, APPLESMC_DATA_PORT);
+
+	for (i = 0; i < 6; i++) {
+		if (__wait_status(0x05))
+			return -EIO;
+		type[i] = inb(APPLESMC_DATA_PORT);
+	}
+	type[5] = 0;
+
+	return 0;
+}
+
+/*
+ * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_read_motion_sensor(int index, s16* value)
+{
+	u8 buffer[2];
+	int ret;
+
+	switch (index) {
+	case SENSOR_X:
+		ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
+		break;
+	case SENSOR_Y:
+		ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
+		break;
+	case SENSOR_Z:
+		ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	*value = ((s16)buffer[0] << 8) | buffer[1];
+
+	return ret;
+}
+
+/*
+ * applesmc_device_init - initialize the accelerometer.  Returns zero on success
+ * and negative error code on failure.  Can sleep.
+ */
+static int applesmc_device_init(void)
+{
+	int total, ret = -ENXIO;
+	u8 buffer[2];
+
+	if (!applesmc_accelerometer)
+		return 0;
+
+	mutex_lock(&applesmc_lock);
+
+	for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+		if (debug)
+			printk(KERN_DEBUG "applesmc try %d\n", total);
+		if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
+				(buffer[0] != 0x00 || buffer[1] != 0x00)) {
+			if (total == INIT_TIMEOUT_MSECS) {
+				printk(KERN_DEBUG "applesmc: device has"
+						" already been initialized"
+						" (0x%02x, 0x%02x).\n",
+						buffer[0], buffer[1]);
+			} else {
+				printk(KERN_DEBUG "applesmc: device"
+						" successfully initialized"
+						" (0x%02x, 0x%02x).\n",
+						buffer[0], buffer[1]);
+			}
+			ret = 0;
+			goto out;
+		}
+		buffer[0] = 0xe0;
+		buffer[1] = 0x00;
+		applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
+		msleep(INIT_WAIT_MSECS);
+	}
+
+	printk(KERN_WARNING "applesmc: failed to init the device\n");
+
+out:
+	mutex_unlock(&applesmc_lock);
+	return ret;
+}
+
+/*
+ * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
+ * applesmc_lock.
+ */
+static int applesmc_get_fan_count(void)
+{
+	int ret;
+	u8 buffer[1];
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(FANS_COUNT, buffer, 1);
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return buffer[0];
+}
+
+/* Device model stuff */
+static int applesmc_probe(struct platform_device *dev)
+{
+	int ret;
+
+	ret = applesmc_device_init();
+	if (ret)
+		return ret;
+
+	printk(KERN_INFO "applesmc: device successfully initialized.\n");
+	return 0;
+}
+
+static int applesmc_resume(struct platform_device *dev)
+{
+	return applesmc_device_init();
+}
+
+static struct platform_driver applesmc_driver = {
+	.probe = applesmc_probe,
+	.resume = applesmc_resume,
+	.driver	= {
+		.name = "applesmc",
+		.owner = THIS_MODULE,
+	},
+};
+
+/*
+ * applesmc_calibrate - Set our "resting" values.  Callers must
+ * hold applesmc_lock.
+ */
+static void applesmc_calibrate(void)
+{
+	applesmc_read_motion_sensor(SENSOR_X, &rest_x);
+	applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
+	rest_x = -rest_x;
+}
+
+static int applesmc_idev_open(struct input_dev *dev)
+{
+	add_timer(&applesmc_timer);
+
+	return 0;
+}
+
+static void applesmc_idev_close(struct input_dev *dev)
+{
+	del_timer_sync(&applesmc_timer);
+}
+
+static void applesmc_idev_poll(unsigned long unused)
+{
+	s16 x, y;
+
+	/* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
+	if (!mutex_trylock(&applesmc_lock)) {
+		mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
+		return;
+	}
+
+	if (applesmc_read_motion_sensor(SENSOR_X, &x))
+		goto out;
+	if (applesmc_read_motion_sensor(SENSOR_Y, &y))
+		goto out;
+
+	x = -x;
+	input_report_abs(applesmc_idev, ABS_X, x - rest_x);
+	input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
+	input_sync(applesmc_idev);
+
+out:
+	mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
+
+	mutex_unlock(&applesmc_lock);
+}
+
+/* Sysfs Files */
+
+static ssize_t applesmc_position_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	int ret;
+	s16 x, y, z;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_motion_sensor(SENSOR_X, &x);
+	if (ret)
+		goto out;
+	ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
+	if (ret)
+		goto out;
+	ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
+	if (ret)
+		goto out;
+
+out:
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t applesmc_light_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	u8 left = 0, right = 0;
+	u8 buffer[6];
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6);
+	left = buffer[2];
+	if (ret)
+		goto out;
+	ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6);
+	right = buffer[2];
+
+out:
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
+}
+
+/* Displays degree Celsius * 1000 */
+static ssize_t applesmc_show_temperature(struct device *dev,
+			struct device_attribute *devattr, char *sysfsbuf)
+{
+	int ret;
+	u8 buffer[2];
+	unsigned int temp;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	const char* key =
+		temperature_sensors_sets[applesmc_temperature_set][attr->index];
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(key, buffer, 2);
+	temp = buffer[0]*1000;
+	temp += (buffer[1] >> 6) * 250;
+
+	mutex_unlock(&applesmc_lock);
+
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
+}
+
+static ssize_t applesmc_show_fan_speed(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	unsigned int speed = 0;
+	char newkey[5];
+	u8 buffer[2];
+	struct sensor_device_attribute_2 *sensor_attr =
+						to_sensor_dev_attr_2(attr);
+
+	newkey[0] = fan_speed_keys[sensor_attr->nr][0];
+	newkey[1] = '0' + sensor_attr->index;
+	newkey[2] = fan_speed_keys[sensor_attr->nr][2];
+	newkey[3] = fan_speed_keys[sensor_attr->nr][3];
+	newkey[4] = 0;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(newkey, buffer, 2);
+	speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+}
+
+static ssize_t applesmc_store_fan_speed(struct device *dev,
+					struct device_attribute *attr,
+					const char *sysfsbuf, size_t count)
+{
+	int ret;
+	u32 speed;
+	char newkey[5];
+	u8 buffer[2];
+	struct sensor_device_attribute_2 *sensor_attr =
+						to_sensor_dev_attr_2(attr);
+
+	speed = simple_strtoul(sysfsbuf, NULL, 10);
+
+	if (speed > 0x4000) /* Bigger than a 14-bit value */
+		return -EINVAL;
+
+	newkey[0] = fan_speed_keys[sensor_attr->nr][0];
+	newkey[1] = '0' + sensor_attr->index;
+	newkey[2] = fan_speed_keys[sensor_attr->nr][2];
+	newkey[3] = fan_speed_keys[sensor_attr->nr][3];
+	newkey[4] = 0;
+
+	mutex_lock(&applesmc_lock);
+
+	buffer[0] = (speed >> 6) & 0xff;
+	buffer[1] = (speed << 2) & 0xff;
+	ret = applesmc_write_key(newkey, buffer, 2);
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static ssize_t applesmc_show_fan_manual(struct device *dev,
+			struct device_attribute *devattr, char *sysfsbuf)
+{
+	int ret;
+	u16 manual = 0;
+	u8 buffer[2];
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+	manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+}
+
+static ssize_t applesmc_store_fan_manual(struct device *dev,
+					 struct device_attribute *devattr,
+					 const char *sysfsbuf, size_t count)
+{
+	int ret;
+	u8 buffer[2];
+	u32 input;
+	u16 val;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+	input = simple_strtoul(sysfsbuf, NULL, 10);
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+	val = (buffer[0] << 8 | buffer[1]);
+	if (ret)
+		goto out;
+
+	if (input)
+		val = val | (0x01 << attr->index);
+	else
+		val = val & ~(0x01 << attr->index);
+
+	buffer[0] = (val >> 8) & 0xFF;
+	buffer[1] = val & 0xFF;
+
+	ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
+
+out:
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static ssize_t applesmc_show_fan_position(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	char newkey[5];
+	u8 buffer[17];
+	struct sensor_device_attribute_2 *sensor_attr =
+						to_sensor_dev_attr_2(attr);
+
+	newkey[0] = FAN_POSITION[0];
+	newkey[1] = '0' + sensor_attr->index;
+	newkey[2] = FAN_POSITION[2];
+	newkey[3] = FAN_POSITION[3];
+	newkey[4] = 0;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(newkey, buffer, 16);
+	buffer[16] = 0;
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
+}
+
+static ssize_t applesmc_calibrate_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t applesmc_calibrate_store(struct device *dev,
+	struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+	mutex_lock(&applesmc_lock);
+	applesmc_calibrate();
+	mutex_unlock(&applesmc_lock);
+
+	return count;
+}
+
+/* Store the next backlight value to be written by the work */
+static unsigned int backlight_value;
+
+static void applesmc_backlight_set(struct work_struct *work)
+{
+	u8 buffer[2];
+
+	mutex_lock(&applesmc_lock);
+	buffer[0] = backlight_value;
+	buffer[1] = 0x00;
+	applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
+	mutex_unlock(&applesmc_lock);
+}
+static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
+
+static void applesmc_brightness_set(struct led_classdev *led_cdev,
+						enum led_brightness value)
+{
+	int ret;
+
+	backlight_value = value;
+	ret = queue_work(applesmc_led_wq, &backlight_work);
+
+	if (debug && (!ret))
+		printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
+}
+
+static ssize_t applesmc_key_count_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	u8 buffer[4];
+	u32 count;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
+	count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
+						((u32)buffer[2]<<8) + buffer[3];
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+}
+
+static ssize_t applesmc_key_at_index_read_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	char key[5];
+	char info[6];
+	int ret;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_get_key_at_index(key_at_index, key);
+
+	if (ret || !key[0]) {
+		mutex_unlock(&applesmc_lock);
+
+		return -EINVAL;
+	}
+
+	ret = applesmc_get_key_type(key, info);
+
+	if (ret) {
+		mutex_unlock(&applesmc_lock);
+
+		return ret;
+	}
+
+	/*
+	 * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
+	 * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
+	 */
+	ret = applesmc_read_key(key, sysfsbuf, info[0]);
+
+	mutex_unlock(&applesmc_lock);
+
+	if (!ret) {
+		return info[0];
+	}
+	else {
+		return ret;
+	}
+}
+
+static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	char key[5];
+	char info[6];
+	int ret;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_get_key_at_index(key_at_index, key);
+
+	if (ret || !key[0]) {
+		mutex_unlock(&applesmc_lock);
+
+		return -EINVAL;
+	}
+
+	ret = applesmc_get_key_type(key, info);
+
+	mutex_unlock(&applesmc_lock);
+
+	if (!ret)
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
+	else
+		return ret;
+}
+
+static ssize_t applesmc_key_at_index_type_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	char key[5];
+	char info[6];
+	int ret;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_get_key_at_index(key_at_index, key);
+
+	if (ret || !key[0]) {
+		mutex_unlock(&applesmc_lock);
+
+		return -EINVAL;
+	}
+
+	ret = applesmc_get_key_type(key, info);
+
+	mutex_unlock(&applesmc_lock);
+
+	if (!ret)
+		return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
+	else
+		return ret;
+}
+
+static ssize_t applesmc_key_at_index_name_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	char key[5];
+	int ret;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_get_key_at_index(key_at_index, key);
+
+	mutex_unlock(&applesmc_lock);
+
+	if (!ret && key[0])
+		return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+	else
+		return -EINVAL;
+}
+
+static ssize_t applesmc_key_at_index_show(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
+}
+
+static ssize_t applesmc_key_at_index_store(struct device *dev,
+	struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+	mutex_lock(&applesmc_lock);
+
+	key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
+
+	mutex_unlock(&applesmc_lock);
+
+	return count;
+}
+
+static struct led_classdev applesmc_backlight = {
+	.name			= "smc:kbd_backlight",
+	.default_trigger	= "nand-disk",
+	.brightness_set		= applesmc_brightness_set,
+};
+
+static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
+static DEVICE_ATTR(calibrate, 0644,
+			applesmc_calibrate_show, applesmc_calibrate_store);
+
+static struct attribute *accelerometer_attributes[] = {
+	&dev_attr_position.attr,
+	&dev_attr_calibrate.attr,
+	NULL
+};
+
+static const struct attribute_group accelerometer_attributes_group =
+	{ .attrs = accelerometer_attributes };
+
+static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
+
+static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
+static DEVICE_ATTR(key_at_index, 0644,
+		applesmc_key_at_index_show, applesmc_key_at_index_store);
+static DEVICE_ATTR(key_at_index_name, 0444,
+					applesmc_key_at_index_name_show, NULL);
+static DEVICE_ATTR(key_at_index_type, 0444,
+					applesmc_key_at_index_type_show, NULL);
+static DEVICE_ATTR(key_at_index_data_length, 0444,
+				applesmc_key_at_index_data_length_show, NULL);
+static DEVICE_ATTR(key_at_index_data, 0444,
+				applesmc_key_at_index_read_show, NULL);
+
+static struct attribute *key_enumeration_attributes[] = {
+	&dev_attr_key_count.attr,
+	&dev_attr_key_at_index.attr,
+	&dev_attr_key_at_index_name.attr,
+	&dev_attr_key_at_index_type.attr,
+	&dev_attr_key_at_index_data_length.attr,
+	&dev_attr_key_at_index_data.attr,
+	NULL
+};
+
+static const struct attribute_group key_enumeration_group =
+	{ .attrs = key_enumeration_attributes };
+
+/*
+ * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
+ *  - show actual speed
+ *  - show/store minimum speed
+ *  - show maximum speed
+ *  - show safe speed
+ *  - show/store target speed
+ *  - show/store manual mode
+ */
+#define sysfs_fan_speeds_offset(offset) \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 0, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
+	applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 2, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 3, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
+	applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
+\
+static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
+	applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
+\
+static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \
+	applesmc_show_fan_position, NULL, offset-1); \
+\
+static struct attribute *fan##offset##_attributes[] = { \
+	&sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_position.dev_attr.attr, \
+	NULL \
+};
+
+/*
+ * Create the needed functions for each fan using the macro defined above
+ * (2 fans are supported)
+ */
+sysfs_fan_speeds_offset(1);
+sysfs_fan_speeds_offset(2);
+
+static const struct attribute_group fan_attribute_groups[] = {
+	{ .attrs = fan1_attributes },
+	{ .attrs = fan2_attributes }
+};
+
+/*
+ * Temperature sensors sysfs entries.
+ */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 11);
+
+static struct attribute *temperature_attributes[] = {
+	&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_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_temp5_input.dev_attr.attr,
+	&sensor_dev_attr_temp6_input.dev_attr.attr,
+	&sensor_dev_attr_temp7_input.dev_attr.attr,
+	&sensor_dev_attr_temp8_input.dev_attr.attr,
+	&sensor_dev_attr_temp9_input.dev_attr.attr,
+	&sensor_dev_attr_temp10_input.dev_attr.attr,
+	&sensor_dev_attr_temp11_input.dev_attr.attr,
+	&sensor_dev_attr_temp12_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group temperature_attributes_group =
+	{ .attrs = temperature_attributes };
+
+/* Module stuff */
+
+/*
+ * applesmc_dmi_match - found a match.  return one, short-circuiting the hunt.
+ */
+static int applesmc_dmi_match(struct dmi_system_id *id)
+{
+	int i = 0;
+	struct dmi_match_data* dmi_data = id->driver_data;
+	printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
+	applesmc_accelerometer = dmi_data->accelerometer;
+	printk(KERN_INFO "applesmc:  - Model %s accelerometer\n",
+				applesmc_accelerometer ? "with" : "without");
+	applesmc_light = dmi_data->light;
+	printk(KERN_INFO "applesmc:  - Model %s light sensors and backlight\n",
+					applesmc_light ? "with" : "without");
+
+	applesmc_temperature_set =  dmi_data->temperature_set;
+	while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
+		i++;
+	printk(KERN_INFO "applesmc:  - Model with %d temperature sensors\n", i);
+	return 1;
+}
+
+/* Create accelerometer ressources */
+static int applesmc_create_accelerometer(void)
+{
+	int ret;
+
+	ret = sysfs_create_group(&pdev->dev.kobj,
+					&accelerometer_attributes_group);
+	if (ret)
+		goto out;
+
+	applesmc_idev = input_allocate_device();
+	if (!applesmc_idev) {
+		ret = -ENOMEM;
+		goto out_sysfs;
+	}
+
+	/* initial calibrate for the input device */
+	applesmc_calibrate();
+
+	/* initialize the input class */
+	applesmc_idev->name = "applesmc";
+	applesmc_idev->id.bustype = BUS_HOST;
+	applesmc_idev->cdev.dev = &pdev->dev;
+	applesmc_idev->evbit[0] = BIT(EV_ABS);
+	applesmc_idev->open = applesmc_idev_open;
+	applesmc_idev->close = applesmc_idev_close;
+	input_set_abs_params(applesmc_idev, ABS_X,
+			-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+	input_set_abs_params(applesmc_idev, ABS_Y,
+			-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+
+	ret = input_register_device(applesmc_idev);
+	if (ret)
+		goto out_idev;
+
+	/* start up our timer for the input device */
+	init_timer(&applesmc_timer);
+	applesmc_timer.function = applesmc_idev_poll;
+	applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
+
+	return 0;
+
+out_idev:
+	input_free_device(applesmc_idev);
+
+out_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+
+out:
+	printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+	return ret;
+}
+
+/* Release all ressources used by the accelerometer */
+static void applesmc_release_accelerometer(void)
+{
+	del_timer_sync(&applesmc_timer);
+	input_unregister_device(applesmc_idev);
+	sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+}
+
+static __initdata struct dmi_match_data applesmc_dmi_data[] = {
+/* MacBook Pro: accelerometer, backlight and temperature set 0 */
+	{ .accelerometer = 1, .light = 1, .temperature_set = 0 },
+/* MacBook: accelerometer and temperature set 0 */
+	{ .accelerometer = 1, .light = 0, .temperature_set = 0 },
+/* MacBook: temperature set 1 */
+	{ .accelerometer = 0, .light = 0, .temperature_set = 1 }
+};
+
+/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
+ * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
+static __initdata struct dmi_system_id applesmc_whitelist[] = {
+	{ applesmc_dmi_match, "Apple MacBook Pro", {
+	  DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
+		(void*)&applesmc_dmi_data[0]},
+	{ applesmc_dmi_match, "Apple MacBook", {
+	  DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
+		(void*)&applesmc_dmi_data[1]},
+	{ applesmc_dmi_match, "Apple Macmini", {
+	  DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+	  DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
+		(void*)&applesmc_dmi_data[2]},
+	{ .ident = NULL }
+};
+
+static int __init applesmc_init(void)
+{
+	int ret;
+	int count;
+	int i;
+
+	mutex_init(&applesmc_lock);
+
+	if (!dmi_check_system(applesmc_whitelist)) {
+		printk(KERN_WARNING "applesmc: supported laptop not found!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
+								"applesmc")) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = platform_driver_register(&applesmc_driver);
+	if (ret)
+		goto out_region;
+
+	pdev = platform_device_register_simple("applesmc", -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		ret = PTR_ERR(pdev);
+		goto out_driver;
+	}
+
+	/* Create key enumeration sysfs files */
+	ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
+	if (ret)
+		goto out_device;
+
+	/* create fan files */
+	count = applesmc_get_fan_count();
+	if (count < 0) {
+		printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
+	} else {
+		printk(KERN_INFO "applesmc: %d fans found.\n", count);
+
+		switch (count) {
+		default:
+			printk(KERN_WARNING "applesmc: More than 2 fans found,"
+					" but at most 2 fans are supported"
+						" by the driver.\n");
+		case 2:
+			ret = sysfs_create_group(&pdev->dev.kobj,
+						 &fan_attribute_groups[1]);
+			if (ret)
+				goto out_key_enumeration;
+		case 1:
+			ret = sysfs_create_group(&pdev->dev.kobj,
+						 &fan_attribute_groups[0]);
+			if (ret)
+				goto out_fan_1;
+		case 0:
+			;
+		}
+	}
+
+	for (i = 0;
+	     temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
+	     i++) {
+		if (temperature_attributes[i] == NULL) {
+			printk(KERN_ERR "applesmc: More temperature sensors "
+				"in temperature_sensors_sets (at least %i)"
+				"than available sysfs files in "
+				"temperature_attributes (%i), please report "
+				"this bug.\n", i, i-1);
+			goto out_temperature;
+		}
+		ret = sysfs_create_file(&pdev->dev.kobj,
+						temperature_attributes[i]);
+		if (ret)
+			goto out_temperature;
+	}
+
+	if (applesmc_accelerometer) {
+		ret = applesmc_create_accelerometer();
+		if (ret)
+			goto out_temperature;
+	}
+
+	if (applesmc_light) {
+		/* Add light sensor file */
+		ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
+		if (ret)
+			goto out_accelerometer;
+
+		/* Create the workqueue */
+		applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+		if (!applesmc_led_wq) {
+			ret = -ENOMEM;
+			goto out_light_sysfs;
+		}
+
+		/* register as a led device */
+		ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
+		if (ret < 0)
+			goto out_light_wq;
+	}
+
+	hwmon_class_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(hwmon_class_dev)) {
+		ret = PTR_ERR(hwmon_class_dev);
+		goto out_light_ledclass;
+	}
+
+	printk(KERN_INFO "applesmc: driver successfully loaded.\n");
+
+	return 0;
+
+out_light_ledclass:
+	if (applesmc_light)
+		led_classdev_unregister(&applesmc_backlight);
+out_light_wq:
+	if (applesmc_light)
+		destroy_workqueue(applesmc_led_wq);
+out_light_sysfs:
+	if (applesmc_light)
+		sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+out_accelerometer:
+	if (applesmc_accelerometer)
+		applesmc_release_accelerometer();
+out_temperature:
+	sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+out_fan_1:
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
+out_key_enumeration:
+	sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+out_device:
+	platform_device_unregister(pdev);
+out_driver:
+	platform_driver_unregister(&applesmc_driver);
+out_region:
+	release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+out:
+	printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+	return ret;
+}
+
+static void __exit applesmc_exit(void)
+{
+	hwmon_device_unregister(hwmon_class_dev);
+	if (applesmc_light) {
+		led_classdev_unregister(&applesmc_backlight);
+		destroy_workqueue(applesmc_led_wq);
+		sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+	}
+	if (applesmc_accelerometer)
+		applesmc_release_accelerometer();
+	sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
+	sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&applesmc_driver);
+	release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+
+	printk(KERN_INFO "applesmc: driver unloaded.\n");
+}
+
+module_init(applesmc_init);
+module_exit(applesmc_exit);
+
+MODULE_AUTHOR("Nicolas Boichat");
+MODULE_DESCRIPTION("Apple SMC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
new file mode 100644
index 0000000..03b1f65
--- /dev/null
+++ b/drivers/hwmon/coretemp.c
@@ -0,0 +1,406 @@
+/*
+ * coretemp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Inspired from many hwmon 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; 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., 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/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define DRVNAME	"coretemp"
+
+typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
+
+/*
+ * Functions declaration
+ */
+
+static struct coretemp_data *coretemp_update_device(struct device *dev);
+
+struct coretemp_data {
+	struct class_device *class_dev;
+	struct mutex update_lock;
+	const char *name;
+	u32 id;
+	char valid;		/* zero until following fields are valid */
+	unsigned long last_updated;	/* in jiffies */
+	int temp;
+	int tjmax;
+	u8 alarm;
+};
+
+static struct coretemp_data *coretemp_update_device(struct device *dev);
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	int ret;
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct coretemp_data *data = dev_get_drvdata(dev);
+
+	if (attr->index == SHOW_NAME)
+		ret = sprintf(buf, "%s\n", data->name);
+	else	/* show label */
+		ret = sprintf(buf, "Core %d\n", data->id);
+	return ret;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
+{
+	struct coretemp_data *data = coretemp_update_device(dev);
+	/* read the Out-of-spec log, never clear */
+	return sprintf(buf, "%d\n", data->alarm);
+}
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct coretemp_data *data = coretemp_update_device(dev);
+	int err;
+
+	if (attr->index == SHOW_TEMP)
+		err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
+	else
+		err = sprintf(buf, "%d\n", data->tjmax);
+
+	return err;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
+			  SHOW_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
+			  SHOW_TJMAX);
+static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
+
+static struct attribute *coretemp_attributes[] = {
+	&sensor_dev_attr_name.dev_attr.attr,
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&dev_attr_temp1_crit_alarm.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group coretemp_group = {
+	.attrs = coretemp_attributes,
+};
+
+static struct coretemp_data *coretemp_update_device(struct device *dev)
+{
+	struct coretemp_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+		u32 eax, edx;
+
+		data->valid = 0;
+		rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+		data->alarm = (eax >> 5) & 1;
+		/* update only if data has been valid */
+		if (eax & 0x80000000) {
+			data->temp = data->tjmax - (((eax >> 16)
+							& 0x7f) * 1000);
+			data->valid = 1;
+		} else {
+			dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+		}
+		data->last_updated = jiffies;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static int __devinit coretemp_probe(struct platform_device *pdev)
+{
+	struct coretemp_data *data;
+	struct cpuinfo_x86 *c = &(cpu_data)[pdev->id];
+	int err;
+	u32 eax, edx;
+
+	if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		dev_err(&pdev->dev, "Out of memory\n");
+		goto exit;
+	}
+
+	data->id = pdev->id;
+	data->name = "coretemp";
+	mutex_init(&data->update_lock);
+	/* Tjmax default is 100 degrees C */
+	data->tjmax = 100000;
+
+	/* test if we can access the THERM_STATUS MSR */
+	err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+	if (err) {
+		dev_err(&pdev->dev,
+			"Unable to access THERM_STATUS MSR, giving up\n");
+		goto exit_free;
+	}
+
+	/* Some processors have Tjmax 85 following magic should detect it
+	   Intel won't disclose the information without signed NDA, but
+	   individuals cannot sign it. Catch(ed) 22.
+	*/
+
+	if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
+		(c->x86_model == 0xe))  {
+		err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
+		if (err) {
+			dev_warn(&pdev->dev,
+				 "Unable to access MSR 0xEE, Tjmax left at %d "
+				 "degrees C\n", data->tjmax/1000);
+		} else if (eax & 0x40000000) {
+			data->tjmax = 85000;
+		}
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
+		goto exit_free;
+
+	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_class;
+	}
+
+	return 0;
+
+exit_class:
+	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int __devexit coretemp_remove(struct platform_device *pdev)
+{
+	struct coretemp_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+	platform_set_drvdata(pdev, NULL);
+	kfree(data);
+	return 0;
+}
+
+static struct platform_driver coretemp_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRVNAME,
+	},
+	.probe = coretemp_probe,
+	.remove = __devexit_p(coretemp_remove),
+};
+
+struct pdev_entry {
+	struct list_head list;
+	struct platform_device *pdev;
+	unsigned int cpu;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static int __cpuinit coretemp_device_add(unsigned int cpu)
+{
+	int err;
+	struct platform_device *pdev;
+	struct pdev_entry *pdev_entry;
+
+	pdev = platform_device_alloc(DRVNAME, cpu);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+	if (!pdev_entry) {
+		err = -ENOMEM;
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_free;
+	}
+
+	pdev_entry->pdev = pdev;
+	pdev_entry->cpu = cpu;
+	mutex_lock(&pdev_list_mutex);
+	list_add_tail(&pdev_entry->list, &pdev_list);
+	mutex_unlock(&pdev_list_mutex);
+
+	return 0;
+
+exit_device_free:
+	kfree(pdev_entry);
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void coretemp_device_remove(unsigned int cpu)
+{
+	struct pdev_entry *p, *n;
+	mutex_lock(&pdev_list_mutex);
+	list_for_each_entry_safe(p, n, &pdev_list, list) {
+		if (p->cpu == cpu) {
+			platform_device_unregister(p->pdev);
+			list_del(&p->list);
+			kfree(p);
+		}
+	}
+	mutex_unlock(&pdev_list_mutex);
+}
+
+static int coretemp_cpu_callback(struct notifier_block *nfb,
+				 unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long) hcpu;
+
+	switch (action) {
+	case CPU_ONLINE:
+		coretemp_device_add(cpu);
+		break;
+	case CPU_DEAD:
+		coretemp_device_remove(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
+	.notifier_call = coretemp_cpu_callback,
+};
+#endif				/* !CONFIG_HOTPLUG_CPU */
+
+static int __init coretemp_init(void)
+{
+	int i, err = -ENODEV;
+	struct pdev_entry *p, *n;
+
+	printk(KERN_NOTICE DRVNAME ": This driver uses undocumented features "
+		"of Core CPU. Temperature might be wrong!\n");
+
+	/* quick check if we run Intel */
+	if (cpu_data[0].x86_vendor != X86_VENDOR_INTEL)
+		goto exit;
+
+	err = platform_driver_register(&coretemp_driver);
+	if (err)
+		goto exit;
+
+	for_each_online_cpu(i) {
+		struct cpuinfo_x86 *c = &(cpu_data)[i];
+
+		/* check if family 6, models e, f */
+		if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
+		    !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
+
+			/* supported CPU not found, but report the unknown
+			   family 6 CPU */
+			if ((c->x86 == 0x6) && (c->x86_model > 0xf))
+				printk(KERN_WARNING DRVNAME ": Unknown CPU "
+					"model %x\n", c->x86_model);
+			continue;
+		}
+
+		err = coretemp_device_add(i);
+		if (err)
+			goto exit_devices_unreg;
+	}
+	if (list_empty(&pdev_list)) {
+		err = -ENODEV;
+		goto exit_driver_unreg;
+	}
+
+#ifdef CONFIG_HOTPLUG_CPU
+	register_hotcpu_notifier(&coretemp_cpu_notifier);
+#endif
+	return 0;
+
+exit_devices_unreg:
+	mutex_lock(&pdev_list_mutex);
+	list_for_each_entry_safe(p, n, &pdev_list, list) {
+		platform_device_unregister(p->pdev);
+		list_del(&p->list);
+		kfree(p);
+	}
+	mutex_unlock(&pdev_list_mutex);
+exit_driver_unreg:
+	platform_driver_unregister(&coretemp_driver);
+exit:
+	return err;
+}
+
+static void __exit coretemp_exit(void)
+{
+	struct pdev_entry *p, *n;
+#ifdef CONFIG_HOTPLUG_CPU
+	unregister_hotcpu_notifier(&coretemp_cpu_notifier);
+#endif
+	mutex_lock(&pdev_list_mutex);
+	list_for_each_entry_safe(p, n, &pdev_list, list) {
+		platform_device_unregister(p->pdev);
+		list_del(&p->list);
+		kfree(p);
+	}
+	mutex_unlock(&pdev_list_mutex);
+	platform_driver_unregister(&coretemp_driver);
+}
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
+MODULE_DESCRIPTION("Intel Core temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(coretemp_init)
+module_exit(coretemp_exit)
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 7c29734..cdbe309 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -35,6 +35,7 @@ #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/ioport.h>
 #include <asm/io.h>
 
 static struct platform_device *pdev;
@@ -1140,6 +1141,13 @@ static int __devinit f71805f_probe(struc
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start + ADDR_REG_OFFSET, 2, DRVNAME)) {
+		err = -EBUSY;
+		dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)(res->start + ADDR_REG_OFFSET),
+			(unsigned long)(res->start + ADDR_REG_OFFSET + 1));
+		goto exit_free;
+	}
 	data->addr = res->start;
 	data->name = names[sio_data->kind];
 	mutex_init(&data->update_lock);
@@ -1165,7 +1173,7 @@ static int __devinit f71805f_probe(struc
 
 	/* Register sysfs interface files */
 	if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
-		goto exit_free;
+		goto exit_release_region;
 	if (data->has_in & (1 << 4)) { /* in4 */
 		if ((err = sysfs_create_group(&pdev->dev.kobj,
 					      &f71805f_group_optin[0])))
@@ -1219,6 +1227,8 @@ exit_remove_files:
 	for (i = 0; i < 4; i++)
 		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+exit_release_region:
+	release_region(res->start + ADDR_REG_OFFSET, 2);
 exit_free:
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
@@ -1229,6 +1239,7 @@ exit:
 static int __devexit f71805f_remove(struct platform_device *pdev)
 {
 	struct f71805f_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 	int i;
 
 	platform_set_drvdata(pdev, NULL);
@@ -1239,6 +1250,9 @@ static int __devexit f71805f_remove(stru
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
 	kfree(data);
 
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start + ADDR_REG_OFFSET, 2);
+
 	return 0;
 }
 
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index bf759ea..f82fa2d 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -30,10 +30,12 @@ #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/kernel.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/timer.h>
 #include <linux/dmi.h>
 #include <linux/jiffies.h>
+
 #include <asm/io.h>
 
 #define HDAPS_LOW_PORT		0x1600	/* first port used by hdaps */
@@ -71,10 +73,10 @@ static u8 km_activity;
 static int rest_x;
 static int rest_y;
 
-static DECLARE_MUTEX(hdaps_sem);
+static DEFINE_MUTEX(hdaps_mtx);
 
 /*
- * __get_latch - Get the value from a given port.  Callers must hold hdaps_sem.
+ * __get_latch - Get the value from a given port.  Callers must hold hdaps_mtx.
  */
 static inline u8 __get_latch(u16 port)
 {
@@ -83,7 +85,7 @@ static inline u8 __get_latch(u16 port)
 
 /*
  * __check_latch - Check a port latch for a given value.  Returns zero if the
- * port contains the given value.  Callers must hold hdaps_sem.
+ * port contains the given value.  Callers must hold hdaps_mtx.
  */
 static inline int __check_latch(u16 port, u8 val)
 {
@@ -94,7 +96,7 @@ static inline int __check_latch(u16 port
 
 /*
  * __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained.  Callers must hold hdaps_sem.
+ * returning zero if the value is obtained.  Callers must hold hdaps_mtx.
  */
 static int __wait_latch(u16 port, u8 val)
 {
@@ -111,7 +113,7 @@ static int __wait_latch(u16 port, u8 val
 
 /*
  * __device_refresh - request a refresh from the accelerometer.  Does not wait
- * for refresh to complete.  Callers must hold hdaps_sem.
+ * for refresh to complete.  Callers must hold hdaps_mtx.
  */
 static void __device_refresh(void)
 {
@@ -125,7 +127,7 @@ static void __device_refresh(void)
 /*
  * __device_refresh_sync - request a synchronous refresh from the
  * accelerometer.  We wait for the refresh to complete.  Returns zero if
- * successful and nonzero on error.  Callers must hold hdaps_sem.
+ * successful and nonzero on error.  Callers must hold hdaps_mtx.
  */
 static int __device_refresh_sync(void)
 {
@@ -135,7 +137,7 @@ static int __device_refresh_sync(void)
 
 /*
  * __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh.  Callers must hold hdaps_sem.
+ * data, and then initiate an async refresh.  Callers must hold hdaps_mtx.
  */
 static inline void __device_complete(void)
 {
@@ -153,7 +155,7 @@ static int hdaps_readb_one(unsigned int 
 {
 	int ret;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mtx);
 
 	/* do a sync refresh -- we need to be sure that we read fresh data */
 	ret = __device_refresh_sync();
@@ -164,7 +166,7 @@ static int hdaps_readb_one(unsigned int 
 	__device_complete();
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mtx);
 	return ret;
 }
 
@@ -199,9 +201,9 @@ static int hdaps_read_pair(unsigned int 
 {
 	int ret;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mtx);
 	ret = __hdaps_read_pair(port1, port2, val1, val2);
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mtx);
 
 	return ret;
 }
@@ -214,7 +216,7 @@ static int hdaps_device_init(void)
 {
 	int total, ret = -ENXIO;
 
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mtx);
 
 	outb(0x13, 0x1610);
 	outb(0x01, 0x161f);
@@ -280,7 +282,7 @@ static int hdaps_device_init(void)
 	}
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mtx);
 	return ret;
 }
 
@@ -314,7 +316,7 @@ static struct platform_driver hdaps_driv
 };
 
 /*
- * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_sem.
+ * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_mtx.
  */
 static void hdaps_calibrate(void)
 {
@@ -326,7 +328,7 @@ static void hdaps_mousedev_poll(unsigned
 	int x, y;
 
 	/* Cannot sleep.  Try nonblockingly.  If we fail, try again later. */
-	if (down_trylock(&hdaps_sem)) {
+	if (mutex_trylock(&hdaps_mtx)) {
 		mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
 		return;
 	}
@@ -341,7 +343,7 @@ static void hdaps_mousedev_poll(unsigned
 	mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
 
 out:
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mtx);
 }
 
 
@@ -421,9 +423,9 @@ static ssize_t hdaps_calibrate_store(str
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
-	down(&hdaps_sem);
+	mutex_lock(&hdaps_mtx);
 	hdaps_calibrate();
-	up(&hdaps_sem);
+	mutex_unlock(&hdaps_mtx);
 
 	return count;
 }
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index b80f6ed..5aab23b 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -166,16 +166,16 @@ static struct vrm_model vrm_models[] = {
 	{X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14},		/* Intel Core (65 nm) */
 	{X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110},		/* Intel Conroe */
 	{X86_VENDOR_INTEL, 0x6, ANY, ANY, 82},		/* any P6 */
-	{X86_VENDOR_INTEL, 0x7, ANY, ANY, 0},		/* Itanium */
 	{X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90},		/* P4 */
 	{X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90},		/* P4 Willamette */
 	{X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90},		/* P4 Northwood */
 	{X86_VENDOR_INTEL, 0xF, ANY, ANY, 100},		/* Prescott and above assume VRD 10 */
-	{X86_VENDOR_INTEL, 0x10, ANY, ANY, 0},		/* Itanium 2 */
 	{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85},	/* Eden ESP/Ezra */
 	{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85},	/* Ezra T */
 	{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85},	/* Nemiah */
-	{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17},	/* C3-M */
+	{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17},	/* C3-M, Eden-N */
+	{X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0},		/* No information */
+	{X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13},	/* C7, Esther */
 	{X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0}		/* stop here */
 };
 
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 7c65b8b..a40166f 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -24,6 +24,7 @@ #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include "lm75.h"
@@ -39,10 +40,12 @@ I2C_CLIENT_INSMOD_1(lm75);
 /* Many LM75 constants specified below */
 
 /* The LM75 registers */
-#define LM75_REG_TEMP		0x00
 #define LM75_REG_CONF		0x01
-#define LM75_REG_TEMP_HYST	0x02
-#define LM75_REG_TEMP_OS	0x03
+static const u8 LM75_REG_TEMP[3] = {
+	0x00,		/* input */
+	0x03,		/* max */
+	0x02,		/* hyst */
+};
 
 /* Each client has this additional data */
 struct lm75_data {
@@ -51,9 +54,10 @@ struct lm75_data {
 	struct mutex		update_lock;
 	char			valid;		/* !=0 if following fields are valid */
 	unsigned long		last_updated;	/* In jiffies */
-	u16			temp_input;	/* Register values */
-	u16			temp_max;
-	u16			temp_hyst;
+	u16			temp[3];	/* Register values,
+						   0 = input
+						   1 = max
+						   2 = hyst */
 };
 
 static int lm75_attach_adapter(struct i2c_adapter *adapter);
@@ -75,35 +79,36 @@ static struct i2c_driver lm75_driver = {
 	.detach_client	= lm75_detach_client,
 };
 
-#define show(value)	\
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	struct lm75_data *data = lm75_update_device(dev);		\
-	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value));	\
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm75_data *data = lm75_update_device(dev);
+	return sprintf(buf, "%d\n",
+		       LM75_TEMP_FROM_REG(data->temp[attr->index]));
 }
-show(temp_max);
-show(temp_hyst);
-show(temp_input);
-
-#define set(value, reg)	\
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)	\
-{								\
-	struct i2c_client *client = to_i2c_client(dev);		\
-	struct lm75_data *data = i2c_get_clientdata(client);	\
-	int temp = simple_strtoul(buf, NULL, 10);		\
-								\
-	mutex_lock(&data->update_lock);				\
-	data->value = LM75_TEMP_TO_REG(temp);			\
-	lm75_write_value(client, reg, data->value);		\
-	mutex_unlock(&data->update_lock);					\
-	return count;						\
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm75_data *data = i2c_get_clientdata(client);
+	int nr = attr->index;
+	unsigned long temp = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = LM75_TEMP_TO_REG(temp);
+	lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
 }
-set(temp_max, LM75_REG_TEMP_OS);
-set(temp_hyst, LM75_REG_TEMP_HYST);
 
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
 
 static int lm75_attach_adapter(struct i2c_adapter *adapter)
 {
@@ -113,9 +118,9 @@ static int lm75_attach_adapter(struct i2
 }
 
 static struct attribute *lm75_attributes[] = {
-	&dev_attr_temp1_input.attr,
-	&dev_attr_temp1_max.attr,
-	&dev_attr_temp1_max_hyst.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,
 
 	NULL
 };
@@ -283,11 +288,12 @@ static struct lm75_data *lm75_update_dev
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
+		int i;
 		dev_dbg(&client->dev, "Starting lm75 update\n");
 
-		data->temp_input = lm75_read_value(client, LM75_REG_TEMP);
-		data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS);
-		data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST);
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+			data->temp[i] = lm75_read_value(client,
+							LM75_REG_TEMP[i]);
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 886786c..9fb572f 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -2,6 +2,7 @@
     lm78.c - Part of lm_sensors, Linux kernel modules for hardware
              monitoring
     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
+    Copyright (c) 2007        Jean Delvare <khali@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
@@ -23,13 +24,18 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 
+/* ISA device, if found */
+static struct platform_device *pdev;
+
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24,
 					0x25, 0x26, 0x27, 0x28, 0x29,
@@ -121,12 +127,8 @@ #define DIV_FROM_REG(val) (1 << (val))
    a bit - except if there could be more than one SMBus. Groan. No solution
    for this yet. */
 
-/* This module may seem overly long and complicated. In fact, it is not so
-   bad. Quite a lot of bookkeeping is done. A real driver can often cut
-   some corners. */
-
-/* For each registered chip, we need to keep some data in memory.
-   The structure is dynamically allocated. */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+   the driver field to differentiate between I2C and ISA chips. */
 struct lm78_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
@@ -152,14 +154,16 @@ struct lm78_data {
 
 
 static int lm78_attach_adapter(struct i2c_adapter *adapter);
-static int lm78_isa_attach_adapter(struct i2c_adapter *adapter);
 static int lm78_detect(struct i2c_adapter *adapter, int address, int kind);
 static int lm78_detach_client(struct i2c_client *client);
 
-static int lm78_read_value(struct i2c_client *client, u8 reg);
-static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int __devinit lm78_isa_probe(struct platform_device *pdev);
+static int __devexit lm78_isa_remove(struct platform_device *pdev);
+
+static int lm78_read_value(struct lm78_data *data, u8 reg);
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value);
 static struct lm78_data *lm78_update_device(struct device *dev);
-static void lm78_init_client(struct i2c_client *client);
+static void lm78_init_device(struct lm78_data *data);
 
 
 static struct i2c_driver lm78_driver = {
@@ -171,95 +175,78 @@ static struct i2c_driver lm78_driver = {
 	.detach_client	= lm78_detach_client,
 };
 
-static struct i2c_driver lm78_isa_driver = {
+static struct platform_driver lm78_isa_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "lm78-isa",
+		.name	= "lm78",
 	},
-	.attach_adapter	= lm78_isa_attach_adapter,
-	.detach_client	= lm78_detach_client,
+	.probe		= lm78_isa_probe,
+	.remove		= lm78_isa_remove,
 };
 
 
 /* 7 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		       char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index]));
 }
 
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index]));
 }
 
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index]));
 }
 
-static ssize_t set_in_min(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+	int nr = attr->index;
 
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
-	lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]);
+	lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t set_in_max(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
+	int nr = attr->index;
 
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
-	lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]);
+	lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 	
 #define show_in_offset(offset)					\
-static ssize_t							\
-	show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
-{								\
-	return show_in(dev, buf, offset);			\
-}								\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, 		\
-		show_in##offset, NULL);				\
-static ssize_t							\
-	show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)   \
-{								\
-	return show_in_min(dev, buf, offset);			\
-}								\
-static ssize_t							\
-	show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)   \
-{								\
-	return show_in_max(dev, buf, offset);			\
-}								\
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t count)			\
-{								\
-	return set_in_min(dev, buf, count, offset);		\
-}								\
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t count)			\
-{								\
-	return set_in_max(dev, buf, count, offset);		\
-}								\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_min, set_in##offset##_min);	\
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -270,46 +257,49 @@ show_in_offset(5);
 show_in_offset(6);
 
 /* Temperature */
-static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
 }
 
-static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+			      char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
 }
 
-static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+			     const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct lm78_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_over = TEMP_TO_REG(val);
-	lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over);
+	lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+			      char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
 }
 
-static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+			     const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct lm78_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_hyst = TEMP_TO_REG(val);
-	lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst);
+	lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -321,49 +311,59 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRU
 		show_temp_hyst, set_temp_hyst);
 
 /* 3 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+			char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+			    char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
+	int nr = attr->index;
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+			    char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct lm78_data *data = lm78_update_device(dev);
-	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
 }
 
 /* Note: we save and restore the fan minimum here, because its value is
    determined in part by the fan divisor.  This follows the principle of
    least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-	size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct lm78_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	unsigned long min;
 	u8 reg;
@@ -378,13 +378,13 @@ static ssize_t set_fan_div(struct device
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
 	default:
-		dev_err(&client->dev, "fan_div value %ld not "
+		dev_err(dev, "fan_div value %ld not "
 			"supported. Choose one of 1, 2, 4 or 8!\n", val);
 		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
 
-	reg = lm78_read_value(client, LM78_REG_VID_FANDIV);
+	reg = lm78_read_value(data, LM78_REG_VID_FANDIV);
 	switch (nr) {
 	case 0:
 		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
@@ -393,63 +393,36 @@ static ssize_t set_fan_div(struct device
 		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
 		break;
 	}
-	lm78_write_value(client, LM78_REG_VID_FANDIV, reg);
+	lm78_write_value(data, LM78_REG_VID_FANDIV, reg);
 
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+	lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-#define show_fan_offset(offset)						\
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan(dev, buf, offset - 1);				\
-}									\
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)  \
-{									\
-	return show_fan_min(dev, buf, offset - 1);			\
-}									\
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)  \
-{									\
-	return show_fan_div(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr,		\
-		const char *buf, size_t count)				\
-{									\
-	return set_fan_min(dev, buf, count, offset - 1);		\
-}									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_fan_##offset##_min, set_fan_##offset##_min);
-
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
-		size_t count)
-{
-	return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
-		size_t count)
-{
-	return set_fan_div(dev, buf, count, 1) ;
-}
+#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##_min, S_IRUGO | S_IWUSR,	\
+		show_fan_min, set_fan_min, offset - 1);
 
 show_fan_offset(1);
 show_fan_offset(2);
 show_fan_offset(3);
 
 /* Fan 3 divisor is locked in H/W */
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
-		show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
-		show_fan_2_div, set_fan_2_div);
-static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		show_fan_div, set_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2);
 
 /* VID */
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_vid(struct device *dev, struct device_attribute *da,
+			char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82));
@@ -457,7 +430,8 @@ static ssize_t show_vid(struct device *d
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
 
 /* Alarms */
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
 	struct lm78_data *data = lm78_update_device(dev);
 	return sprintf(buf, "%u\n", data->alarms);
@@ -475,45 +449,40 @@ static int lm78_attach_adapter(struct i2
 	return i2c_probe(adapter, &addr_data, lm78_detect);
 }
 
-static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
-{
-	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,
+	&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,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.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,
+	&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,
 	&dev_attr_alarms.attr,
 	&dev_attr_cpu0_vid.attr,
 
@@ -524,6 +493,17 @@ static const struct attribute_group lm78
 	.attrs = lm78_attributes,
 };
 
+/* I2C devices get this name attribute automatically, but for ISA devices
+   we must create it by ourselves. */
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct lm78_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->client.name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 /* This function is called by i2c_probe */
 static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
 {
@@ -531,54 +511,10 @@ static int lm78_detect(struct i2c_adapte
 	struct i2c_client *new_client;
 	struct lm78_data *data;
 	const char *client_name = "";
-	int is_isa = i2c_is_isa_adapter(adapter);
 
-	if (!is_isa &&
-	    !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 		err = -ENODEV;
-		goto ERROR0;
-	}
-
-	/* Reserve the ISA region */
-	if (is_isa)
-		if (!request_region(address, LM78_EXTENT,
-				    lm78_isa_driver.driver.name)) {
-			err = -EBUSY;
-			goto ERROR0;
-		}
-
-	/* Probe whether there is anything available on this address. Already
-	   done for SMBus clients */
-	if (kind < 0) {
-		if (is_isa) {
-
-#define REALLY_SLOW_IO
-			/* We need the timeouts for at least some LM78-like
-			   chips. But only if we read 'undefined' registers. */
-			i = inb_p(address + 1);
-			if (inb_p(address + 2) != i) {
-				err = -ENODEV;
-				goto ERROR1;
-			}
-			if (inb_p(address + 3) != i) {
-				err = -ENODEV;
-				goto ERROR1;
-			}
-			if (inb_p(address + 7) != i) {
-				err = -ENODEV;
-				goto ERROR1;
-			}
-#undef REALLY_SLOW_IO
-
-			/* Let's just hope nothing breaks here */
-			i = inb_p(address + 5) & 0x7f;
-			outb_p(~i & 0x7f, address + 5);
-			if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
-				outb_p(i, address + 5);
-				err = -ENODEV;
-				goto ERROR1;
-			}
-		}
+		goto ERROR1;
 	}
 
 	/* OK. For now, we presume we have a valid client. We now create the
@@ -591,22 +527,19 @@ #undef REALLY_SLOW_IO
 	}
 
 	new_client = &data->client;
-	if (is_isa)
-		mutex_init(&data->lock);
 	i2c_set_clientdata(new_client, data);
 	new_client->addr = address;
 	new_client->adapter = adapter;
-	new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver;
-	new_client->flags = 0;
+	new_client->driver = &lm78_driver;
 
 	/* Now, we do the remaining detection. */
 	if (kind < 0) {
-		if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) {
+		if (lm78_read_value(data, LM78_REG_CONFIG) & 0x80) {
 			err = -ENODEV;
 			goto ERROR2;
 		}
-		if (!is_isa && (lm78_read_value(
-				new_client, LM78_REG_I2C_ADDR) != address)) {
+		if (lm78_read_value(data, LM78_REG_I2C_ADDR) !=
+		    address) {
 			err = -ENODEV;
 			goto ERROR2;
 		}
@@ -614,7 +547,7 @@ #undef REALLY_SLOW_IO
 
 	/* Determine the chip type. */
 	if (kind <= 0) {
-		i = lm78_read_value(new_client, LM78_REG_CHIPID);
+		i = lm78_read_value(data, LM78_REG_CHIPID);
 		if (i == 0x00 || i == 0x20	/* LM78 */
 		 || i == 0x40)			/* LM78-J */
 			kind = lm78;
@@ -641,21 +574,12 @@ #undef REALLY_SLOW_IO
 	strlcpy(new_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)))
 		goto ERROR2;
 
 	/* Initialize the LM78 chip */
-	lm78_init_client(new_client);
-
-	/* A few vars need to be filled upon startup */
-	for (i = 0; i < 3; i++) {
-		data->fan_min[i] = lm78_read_value(new_client,
-					LM78_REG_FAN_MIN(i));
-	}
+	lm78_init_device(data);
 
 	/* Register sysfs hooks */
 	if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
@@ -676,9 +600,6 @@ ERROR3:
 ERROR2:
 	kfree(data);
 ERROR1:
-	if (is_isa)
-		release_region(address, LM78_EXTENT);
-ERROR0:
 	return err;
 }
 
@@ -693,9 +614,77 @@ static int lm78_detach_client(struct i2c
 	if ((err = i2c_detach_client(client)))
 		return err;
 
-	if(i2c_is_isa_client(client))
-		release_region(client->addr, LM78_EXTENT);
+	kfree(data);
+
+	return 0;
+}
+
+static int __devinit lm78_isa_probe(struct platform_device *pdev)
+{
+	int err;
+	struct lm78_data *data;
+	struct resource *res;
+	const char *name;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, LM78_EXTENT, "lm78")) {
+		err = -EBUSY;
+		goto exit;
+	}
+
+	if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit_release_region;
+	}
+	mutex_init(&data->lock);
+	data->client.addr = res->start;
+	i2c_set_clientdata(&data->client, data);
+	platform_set_drvdata(pdev, data);
+
+	if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) {
+		data->type = lm79;
+		name = "lm79";
+	} else {
+		data->type = lm78;
+		name = "lm78";
+	}
+	strlcpy(data->client.name, name, I2C_NAME_SIZE);
+
+	/* Initialize the LM78 chip */
+	lm78_init_device(data);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group))
+	 || (err = device_create_file(&pdev->dev, &dev_attr_name)))
+		goto exit_remove_files;
+
+	data->class_dev = hwmon_device_register(&pdev->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(&pdev->dev.kobj, &lm78_group);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	kfree(data);
+ exit_release_region:
+	release_region(res->start, LM78_EXTENT);
+ exit:
+	return err;
+}
+
+static int __devexit lm78_isa_remove(struct platform_device *pdev)
+{
+	struct lm78_data *data = platform_get_drvdata(pdev);
 
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	release_region(data->client.addr, LM78_EXTENT);
 	kfree(data);
 
 	return 0;
@@ -706,11 +695,12 @@ static int lm78_detach_client(struct i2c
    separately.
    We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the LM78 access and should not be necessary.  */
-static int lm78_read_value(struct i2c_client *client, u8 reg)
+static int lm78_read_value(struct lm78_data *data, u8 reg)
 {
-	int res;
-	if (i2c_is_isa_client(client)) {
-		struct lm78_data *data = i2c_get_clientdata(client);
+	struct i2c_client *client = &data->client;
+
+	if (!client->driver) { /* ISA device */
+		int res;
 		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
 		res = inb_p(client->addr + LM78_DATA_REG_OFFSET);
@@ -727,10 +717,11 @@ static int lm78_read_value(struct i2c_cl
    would slow down the LM78 access and should not be necessary. 
    There are some ugly typecasts here, but the good new is - they should
    nowhere else be necessary! */
-static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value)
 {
-	if (i2c_is_isa_client(client)) {
-		struct lm78_data *data = i2c_get_clientdata(client);
+	struct i2c_client *client = &data->client;
+
+	if (!client->driver) { /* ISA device */
 		mutex_lock(&data->lock);
 		outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
 		outb_p(value, client->addr + LM78_DATA_REG_OFFSET);
@@ -740,20 +731,29 @@ static int lm78_write_value(struct i2c_c
 		return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static void lm78_init_client(struct i2c_client *client)
+static void lm78_init_device(struct lm78_data *data)
 {
-	u8 config = lm78_read_value(client, LM78_REG_CONFIG);
+	u8 config;
+	int i;
 
 	/* Start monitoring */
-	if (!(config & 0x01))
-		lm78_write_value(client, LM78_REG_CONFIG,
+	config = lm78_read_value(data, LM78_REG_CONFIG);
+	if ((config & 0x09) != 0x01)
+		lm78_write_value(data, LM78_REG_CONFIG,
 				 (config & 0xf7) | 0x01);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 3; i++) {
+		data->fan_min[i] = lm78_read_value(data,
+					LM78_REG_FAN_MIN(i));
+	}
+
+	mutex_init(&data->update_lock);
 }
 
 static struct lm78_data *lm78_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm78_data *data = i2c_get_clientdata(client);
+	struct lm78_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -761,39 +761,39 @@ static struct lm78_data *lm78_update_dev
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
 
-		dev_dbg(&client->dev, "Starting lm78 update\n");
+		dev_dbg(dev, "Starting lm78 update\n");
 
 		for (i = 0; i <= 6; i++) {
 			data->in[i] =
-			    lm78_read_value(client, LM78_REG_IN(i));
+			    lm78_read_value(data, LM78_REG_IN(i));
 			data->in_min[i] =
-			    lm78_read_value(client, LM78_REG_IN_MIN(i));
+			    lm78_read_value(data, LM78_REG_IN_MIN(i));
 			data->in_max[i] =
-			    lm78_read_value(client, LM78_REG_IN_MAX(i));
+			    lm78_read_value(data, LM78_REG_IN_MAX(i));
 		}
 		for (i = 0; i < 3; i++) {
 			data->fan[i] =
-			    lm78_read_value(client, LM78_REG_FAN(i));
+			    lm78_read_value(data, LM78_REG_FAN(i));
 			data->fan_min[i] =
-			    lm78_read_value(client, LM78_REG_FAN_MIN(i));
+			    lm78_read_value(data, LM78_REG_FAN_MIN(i));
 		}
-		data->temp = lm78_read_value(client, LM78_REG_TEMP);
+		data->temp = lm78_read_value(data, LM78_REG_TEMP);
 		data->temp_over =
-		    lm78_read_value(client, LM78_REG_TEMP_OVER);
+		    lm78_read_value(data, LM78_REG_TEMP_OVER);
 		data->temp_hyst =
-		    lm78_read_value(client, LM78_REG_TEMP_HYST);
-		i = lm78_read_value(client, LM78_REG_VID_FANDIV);
+		    lm78_read_value(data, LM78_REG_TEMP_HYST);
+		i = lm78_read_value(data, LM78_REG_VID_FANDIV);
 		data->vid = i & 0x0f;
 		if (data->type == lm79)
 			data->vid |=
-			    (lm78_read_value(client, LM78_REG_CHIPID) &
+			    (lm78_read_value(data, LM78_REG_CHIPID) &
 			     0x01) << 4;
 		else
 			data->vid |= 0x10;
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = i >> 6;
-		data->alarms = lm78_read_value(client, LM78_REG_ALARM1) +
-		    (lm78_read_value(client, LM78_REG_ALARM2) << 8);
+		data->alarms = lm78_read_value(data, LM78_REG_ALARM1) +
+		    (lm78_read_value(data, LM78_REG_ALARM2) << 8);
 		data->last_updated = jiffies;
 		data->valid = 1;
 
@@ -805,26 +805,154 @@ static struct lm78_data *lm78_update_dev
 	return data;
 }
 
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init lm78_isa_found(unsigned short address)
+{
+	int val, save, found = 0;
+
+	if (!request_region(address, LM78_EXTENT, "lm78"))
+		return 0;
+
+#define REALLY_SLOW_IO
+	/* We need the timeouts for at least some LM78-like
+	   chips. But only if we read 'undefined' registers. */
+	val = inb_p(address + 1);
+	if (inb_p(address + 2) != val
+	 || inb_p(address + 3) != val
+	 || inb_p(address + 7) != val)
+		goto release;
+#undef REALLY_SLOW_IO
+
+	/* We should be able to change the 7 LSB of the address port. The
+	   MSB (busy flag) should be clear initially, set after the write. */
+	save = inb_p(address + LM78_ADDR_REG_OFFSET);
+	if (save & 0x80)
+		goto release;
+	val = ~save & 0x7f;
+	outb_p(val, address + LM78_ADDR_REG_OFFSET);
+	if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) {
+		outb_p(save, address + LM78_ADDR_REG_OFFSET);
+		goto release;
+	}
+
+	/* We found a device, now see if it could be an LM78 */
+	outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val & 0x80)
+		goto release;
+	outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val < 0x03 || val > 0x77)	/* Not a valid I2C address */
+		goto release;
+
+	/* The busy flag should be clear again */
+	if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80)
+		goto release;
+
+	/* Explicitly prevent the misdetection of Winbond chips */
+	outb_p(0x4f, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0xa3 || val == 0x5c)
+		goto release;
+
+	/* Explicitly prevent the misdetection of ITE chips */
+	outb_p(0x58, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0x90)
+		goto release;
+
+	/* Determine the chip type */
+	outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET);
+	val = inb_p(address + LM78_DATA_REG_OFFSET);
+	if (val == 0x00			/* LM78 */
+	 || val == 0x40			/* LM78-J */
+	 || (val & 0xfe) == 0xc0)	/* LM79 */
+		found = 1;
+
+	if (found)
+		pr_info("lm78: Found an %s chip at %#x\n",
+			val & 0x80 ? "LM79" : "LM78", (int)address);
+
+ release:
+	release_region(address, LM78_EXTENT);
+	return found;
+}
+
+static int __init lm78_isa_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + LM78_EXTENT,
+		.name	= "lm78",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("lm78", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "lm78: Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR "lm78: Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "lm78: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+ exit_device_put:
+	platform_device_put(pdev);
+ exit:
+	pdev = NULL;
+	return err;
+}
+
 static int __init sm_lm78_init(void)
 {
 	int res;
 
 	res = i2c_add_driver(&lm78_driver);
 	if (res)
-		return res;
+		goto exit;
 
-	/* 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;
+	if (lm78_isa_found(isa_address)) {
+		res = platform_driver_register(&lm78_isa_driver);
+		if (res)
+			goto exit_unreg_i2c_driver;
+
+		/* Sets global pdev as a side effect */
+		res = lm78_isa_device_add(isa_address);
+		if (res)
+			goto exit_unreg_isa_driver;
+	}
 
 	return 0;
+
+ exit_unreg_isa_driver:
+	platform_driver_unregister(&lm78_isa_driver);
+ exit_unreg_i2c_driver:
+	i2c_del_driver(&lm78_driver);
+ exit:
+	return res;
 }
 
 static void __exit sm_lm78_exit(void)
 {
-	if (isa_address)
-		i2c_isa_del_driver(&lm78_isa_driver);
+	if (pdev) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&lm78_isa_driver);
+	}
 	i2c_del_driver(&lm78_driver);
 }
 
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 3ce8254..988ae1c 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -747,6 +747,7 @@ static int lm87_detect(struct i2c_adapte
 	}
 
 	if (!(data->channel & CHAN_NO_VID)) {
+		data->vrm = vid_which_vrm();
 		if ((err = device_create_file(&new_client->dev,
 					&dev_attr_cpu0_vid))
 		 || (err = device_create_file(&new_client->dev,
@@ -779,7 +780,6 @@ static void lm87_init_client(struct i2c_
 	u8 config;
 
 	data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
-	data->vrm = vid_which_vrm();
 
 	config = lm87_read_value(client, LM87_REG_CONFIG);
 	if (!(config & 0x01)) {
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
new file mode 100644
index 0000000..8415664
--- /dev/null
+++ b/drivers/hwmon/max6650.c
@@ -0,0 +1,693 @@
+/*
+ * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
+ *             monitoring.
+ *
+ * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ *
+ * based on code written by John Morris <john.morris@spirentcom.com>
+ * Copyright (c) 2003 Spirent Communications
+ * and Claus Gindhart <claus.gindhart@kontron.com>
+ *
+ * This module has only been tested with the MAX6650 chip. It should
+ * also work with the MAX6651. It does not distinguish max6650 and max6651
+ * chips.
+ *
+ * Tha datasheet was last seen at:
+ *
+ *        http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/*
+ * Addresses to scan. There are four disjoint possibilities, by pin config.
+ */
+
+static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, I2C_CLIENT_END};
+
+/*
+ * Insmod parameters
+ */
+
+/* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */
+static int fan_voltage;
+/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */
+static int prescaler;
+/* clock: The clock frequency of the chip the driver should assume */
+static int clock = 254000;
+
+module_param(fan_voltage, int, S_IRUGO);
+module_param(prescaler, int, S_IRUGO);
+module_param(clock, int, S_IRUGO);
+
+I2C_CLIENT_INSMOD_1(max6650);
+
+/*
+ * MAX 6650/6651 registers
+ */
+
+#define MAX6650_REG_SPEED	0x00
+#define MAX6650_REG_CONFIG	0x02
+#define MAX6650_REG_GPIO_DEF	0x04
+#define MAX6650_REG_DAC		0x06
+#define MAX6650_REG_ALARM_EN	0x08
+#define MAX6650_REG_ALARM	0x0A
+#define MAX6650_REG_TACH0	0x0C
+#define MAX6650_REG_TACH1	0x0E
+#define MAX6650_REG_TACH2	0x10
+#define MAX6650_REG_TACH3	0x12
+#define MAX6650_REG_GPIO_STAT	0x14
+#define MAX6650_REG_COUNT	0x16
+
+/*
+ * Config register bits
+ */
+
+#define MAX6650_CFG_V12			0x08
+#define MAX6650_CFG_PRESCALER_MASK	0x07
+#define MAX6650_CFG_PRESCALER_2		0x01
+#define MAX6650_CFG_PRESCALER_4		0x02
+#define MAX6650_CFG_PRESCALER_8		0x03
+#define MAX6650_CFG_PRESCALER_16	0x04
+#define MAX6650_CFG_MODE_MASK		0x30
+#define MAX6650_CFG_MODE_ON		0x00
+#define MAX6650_CFG_MODE_OFF		0x10
+#define MAX6650_CFG_MODE_CLOSED_LOOP	0x20
+#define MAX6650_CFG_MODE_OPEN_LOOP	0x30
+#define MAX6650_COUNT_MASK		0x03
+
+/* Minimum and maximum values of the FAN-RPM */
+#define FAN_RPM_MIN 240
+#define FAN_RPM_MAX 30000
+
+#define DIV_FROM_REG(reg) (1 << (reg & 7))
+
+static int max6650_attach_adapter(struct i2c_adapter *adapter);
+static int max6650_detect(struct i2c_adapter *adapter, int address, int kind);
+static int max6650_init_client(struct i2c_client *client);
+static int max6650_detach_client(struct i2c_client *client);
+static struct max6650_data *max6650_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver max6650_driver = {
+	.driver = {
+		.name	= "max6650",
+	},
+	.attach_adapter	= max6650_attach_adapter,
+	.detach_client	= max6650_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max6650_data
+{
+	struct i2c_client client;
+	struct class_device *class_dev;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	u8 speed;
+	u8 config;
+	u8 tach[4];
+	u8 count;
+	u8 dac;
+};
+
+static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct max6650_data *data = max6650_update_device(dev);
+	int rpm;
+
+	/*
+	* Calculation details:
+	*
+	* Each tachometer counts over an interval given by the "count"
+	* register (0.25, 0.5, 1 or 2 seconds). This module assumes
+	* that the fans produce two pulses per revolution (this seems
+	* to be the most common).
+	*/
+
+	rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
+	return sprintf(buf, "%d\n", rpm);
+}
+
+/*
+ * Set the fan speed to the specified RPM (or read back the RPM setting).
+ * This works in closed loop mode only. Use pwm1 for open loop speed setting.
+ *
+ * The MAX6650/1 will automatically control fan speed when in closed loop
+ * mode.
+ *
+ * Assumptions:
+ *
+ * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use
+ *    the clock module parameter if you need to fine tune this.
+ *
+ * 2) The prescaler (low three bits of the config register) has already
+ *    been set to an appropriate value. Use the prescaler module parameter
+ *    if your BIOS doesn't initialize the chip properly.
+ *
+ * The relevant equations are given on pages 21 and 22 of the datasheet.
+ *
+ * From the datasheet, the relevant equation when in regulation is:
+ *
+ *    [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE
+ *
+ * where:
+ *
+ *    fCLK is the oscillator frequency (either the 254kHz internal
+ *         oscillator or the externally applied clock)
+ *
+ *    KTACH is the value in the speed register
+ *
+ *    FanSpeed is the speed of the fan in rps
+ *
+ *    KSCALE is the prescaler value (1, 2, 4, 8, or 16)
+ *
+ * When reading, we need to solve for FanSpeed. When writing, we need to
+ * solve for KTACH.
+ *
+ * Note: this tachometer is completely separate from the tachometers
+ * used to measure the fan speeds. Only one fan's speed (fan1) is
+ * controlled.
+ */
+
+static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
+			 char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+	int kscale, ktach, rpm;
+
+	/*
+	* Use the datasheet equation:
+	*
+	*    FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
+	*
+	* then multiply by 60 to give rpm.
+	*/
+
+	kscale = DIV_FROM_REG(data->config);
+	ktach = data->speed;
+	rpm = 60 * kscale * clock / (256 * (ktach + 1));
+	return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
+			 const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int rpm = simple_strtoul(buf, NULL, 10);
+	int kscale, ktach;
+
+	rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+
+	/*
+	* Divide the required speed by 60 to get from rpm to rps, then
+	* use the datasheet equation:
+	*
+	*     KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
+	*/
+
+	mutex_lock(&data->update_lock);
+
+	kscale = DIV_FROM_REG(data->config);
+	ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;
+	if (ktach < 0)
+		ktach = 0;
+	if (ktach > 255)
+		ktach = 255;
+	data->speed = ktach;
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_SPEED, data->speed);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Get/set the fan speed in open loop mode using pwm1 sysfs file.
+ * Speed is given as a relative value from 0 to 255, where 255 is maximum
+ * speed. Note that this is done by writing directly to the chip's DAC,
+ * it won't change the closed loop speed set by fan1_target.
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+
+static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	int pwm;
+	struct max6650_data *data = max6650_update_device(dev);
+
+	/* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
+	   Lower DAC values mean higher speeds. */
+	if (data->config & MAX6650_CFG_V12)
+		pwm = 255 - (255 * (int)data->dac)/180;
+	else
+		pwm = 255 - (255 * (int)data->dac)/76;
+
+	if (pwm < 0)
+		pwm = 0;
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+			const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int pwm = simple_strtoul(buf, NULL, 10);
+
+	pwm = SENSORS_LIMIT(pwm, 0, 255);
+
+	mutex_lock(&data->update_lock);
+
+	if (data->config & MAX6650_CFG_V12)
+		data->dac = 180 - (180 * pwm)/255;
+	else
+		data->dac = 76 - (76 * pwm)/255;
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Get/Set controller mode:
+ * Possible values:
+ * 0 = Fan always on
+ * 1 = Open loop, Voltage is set according to speed, not regulated.
+ * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
+ */
+
+static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
+			  char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+	int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
+	int sysfs_modes[4] = {0, 1, 2, 1};
+
+	return sprintf(buf, "%d\n", sysfs_modes[mode]);
+}
+
+static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
+			  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int mode = simple_strtoul(buf, NULL, 10);
+	int max6650_modes[3] = {0, 3, 2};
+
+	if ((mode < 0)||(mode > 2)) {
+		dev_err(&client->dev,
+			"illegal value for pwm1_enable (%d)\n", mode);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->update_lock);
+
+	data->config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+	data->config = (data->config & ~MAX6650_CFG_MODE_MASK)
+		       | (max6650_modes[mode] << 4);
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config);
+
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/*
+ * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
+ * divider. We handle this by converting between divider and counttime:
+ *
+ * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
+ *
+ * Lower values of k allow to connect a faster fan without the risk of
+ * counter overflow. The price is lower resolution. You can also set counttime
+ * using the module parameter. Note that the module parameter "prescaler" also
+ * influences the behaviour. Unfortunately, there's no sysfs attribute
+ * defined for that. See the data sheet for details.
+ */
+
+static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
+		       char *buf)
+{
+	struct max6650_data *data = max6650_update_device(dev);
+
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
+}
+
+static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
+		       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int div = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (div) {
+	case 1:
+		data->count = 0;
+		break;
+	case 2:
+		data->count = 1;
+		break;
+	case 4:
+		data->count = 2;
+		break;
+	case 8:
+		data->count = 3;
+		break;
+	default:
+		dev_err(&client->dev,
+			"illegal value for fan divider (%d)\n", div);
+		return -EINVAL;
+	}
+
+	i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+
+
+static struct attribute *max6650_attrs[] = {
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_div.attr,
+	&dev_attr_pwm1_enable.attr,
+	&dev_attr_pwm1.attr,
+	NULL
+};
+
+static struct attribute_group max6650_attr_grp = {
+	.attrs = max6650_attrs,
+};
+
+/*
+ * Real code
+ */
+
+static int max6650_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON)) {
+		dev_dbg(&adapter->dev,
+			"FATAL: max6650_attach_adapter class HWMON not set\n");
+		return 0;
+	}
+
+	return i2c_probe(adapter, &addr_data, max6650_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+
+static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct max6650_data *data;
+	int err = -ENODEV;
+
+	dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
+					"byte read mode, skipping.\n");
+		return 0;
+	}
+
+	if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
+		dev_err(&adapter->dev, "max6650: out of memory.\n");
+		return -ENOMEM;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &max6650_driver;
+
+	/*
+	 * Now we do the remaining detection. A negative kind means that
+	 * the driver was loaded with no force parameter (default), so we
+	 * must both detect and identify the chip (actually there is only
+	 * one possible kind of chip for now, max6650). A zero kind means that
+	 * the driver was loaded with the force parameter, the detection
+	 * step shall be skipped. A positive kind means that the driver
+	 * was loaded with the force parameter and a given kind of chip is
+	 * requested, so both the detection and the identification steps
+	 * are skipped.
+	 *
+	 * Currently I can find no way to distinguish between a MAX6650 and
+	 * a MAX6651. This driver has only been tried on the former.
+	 */
+
+	if ((kind < 0) &&
+	   (  (i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
+	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
+	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
+	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
+	    ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
+		dev_dbg(&adapter->dev,
+			"max6650: detection failed at 0x%02x.\n", address);
+		goto err_free;
+	}
+
+	dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
+
+	strlcpy(client->name, "max6650", I2C_NAME_SIZE);
+	mutex_init(&data->update_lock);
+
+	if ((err = i2c_attach_client(client))) {
+		dev_err(&adapter->dev, "max6650: failed to attach client.\n");
+		goto err_free;
+	}
+
+	/*
+	 * Initialize the max6650 chip
+	 */
+	if (max6650_init_client(client))
+		goto err_detach;
+
+	err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
+	if (err)
+		goto err_detach;
+
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (!IS_ERR(data->class_dev))
+		return 0;
+
+	err = PTR_ERR(data->class_dev);
+	dev_err(&client->dev, "error registering hwmon device.\n");
+	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
+err_detach:
+	i2c_detach_client(client);
+err_free:
+	kfree(data);
+	return err;
+}
+
+static int max6650_detach_client(struct i2c_client *client)
+{
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int err;
+
+	sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
+	hwmon_device_unregister(data->class_dev);
+	err = i2c_detach_client(client);
+	if (!err)
+		kfree(data);
+	return err;
+}
+
+static int max6650_init_client(struct i2c_client *client)
+{
+	struct max6650_data *data = i2c_get_clientdata(client);
+	int config;
+	int err = -EIO;
+
+	config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+
+	if (config < 0) {
+		dev_err(&client->dev, "Error reading config, aborting.\n");
+		return err;
+	}
+
+	switch (fan_voltage) {
+		case 0:
+			break;
+		case 5:
+			config &= ~MAX6650_CFG_V12;
+			break;
+		case 12:
+			config |= MAX6650_CFG_V12;
+			break;
+		default:
+			dev_err(&client->dev,
+				"illegal value for fan_voltage (%d)\n",
+				fan_voltage);
+	}
+
+	dev_info(&client->dev, "Fan voltage is set to %dV.\n",
+		 (config & MAX6650_CFG_V12) ? 12 : 5);
+
+	switch (prescaler) {
+		case 0:
+			break;
+		case 1:
+			config &= ~MAX6650_CFG_PRESCALER_MASK;
+			break;
+		case 2:
+			config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+				 | MAX6650_CFG_PRESCALER_2;
+			break;
+		case  4:
+			config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+				 | MAX6650_CFG_PRESCALER_4;
+			break;
+		case  8:
+			config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+				 | MAX6650_CFG_PRESCALER_8;
+			break;
+		case 16:
+			config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+				 | MAX6650_CFG_PRESCALER_16;
+			break;
+		default:
+			dev_err(&client->dev,
+				"illegal value for prescaler (%d)\n",
+				prescaler);
+	}
+
+	dev_info(&client->dev, "Prescaler is set to %d.\n",
+		 1 << (config & MAX6650_CFG_PRESCALER_MASK));
+
+	/* If mode is set to "full off", we change it to "open loop" and
+	 * set DAC to 255, which has the same effect. We do this because
+	 * there's no "full off" mode defined in hwmon specifcations.
+	 */
+
+	if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
+		dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
+		config = (config & ~MAX6650_CFG_MODE_MASK)
+			 | MAX6650_CFG_MODE_OPEN_LOOP;
+		if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
+			dev_err(&client->dev, "DAC write error, aborting.\n");
+			return err;
+		}
+	}
+
+	if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
+		dev_err(&client->dev, "Config write error, aborting.\n");
+		return err;
+	}
+
+	data->config = config;
+	data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+
+	return 0;
+}
+
+static const u8 tach_reg[] = {
+	MAX6650_REG_TACH0,
+	MAX6650_REG_TACH1,
+	MAX6650_REG_TACH2,
+	MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+	int i;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct max6650_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+		data->speed = i2c_smbus_read_byte_data(client,
+						       MAX6650_REG_SPEED);
+		data->config = i2c_smbus_read_byte_data(client,
+							MAX6650_REG_CONFIG);
+		for (i = 0; i < 4; i++) {
+			data->tach[i] = i2c_smbus_read_byte_data(client,
+								 tach_reg[i]);
+		}
+		data->count = i2c_smbus_read_byte_data(client,
+							MAX6650_REG_COUNT);
+		data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int __init sensors_max6650_init(void)
+{
+	return i2c_add_driver(&max6650_driver);
+}
+
+static void __exit sensors_max6650_exit(void)
+{
+	i2c_del_driver(&max6650_driver);
+}
+
+MODULE_AUTHOR("Hans J. Koch");
+MODULE_DESCRIPTION("MAX6650 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_max6650_init);
+module_exit(sensors_max6650_exit);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index affa21a..29354fa 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -31,6 +31,7 @@ #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/ioport.h>
 #include <asm/io.h>
 
 static struct platform_device *pdev;
@@ -429,6 +430,12 @@ static int __devinit pc87427_probe(struc
 	/* This will need to be revisited when we add support for
 	   temperature and voltage monitoring. */
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+		err = -EBUSY;
+		dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start, (unsigned long)res->end);
+		goto exit_kfree;
+	}
 	data->address[0] = res->start;
 
 	mutex_init(&data->lock);
@@ -438,7 +445,7 @@ static int __devinit pc87427_probe(struc
 
 	/* Register sysfs hooks */
 	if ((err = device_create_file(&pdev->dev, &dev_attr_name)))
-		goto exit_kfree;
+		goto exit_release_region;
 	for (i = 0; i < 8; i++) {
 		if (!(data->fan_enabled & (1 << i)))
 			continue;
@@ -462,6 +469,8 @@ exit_remove_files:
 			continue;
 		sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
 	}
+exit_release_region:
+	release_region(res->start, res->end - res->start + 1);
 exit_kfree:
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
@@ -472,6 +481,7 @@ exit:
 static int __devexit pc87427_remove(struct platform_device *pdev)
 {
 	struct pc87427_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 	int i;
 
 	platform_set_drvdata(pdev, NULL);
@@ -484,6 +494,9 @@ static int __devexit pc87427_remove(stru
 	}
 	kfree(data);
 
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, res->end - res->start + 1);
+
 	return 0;
 }
 
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 72b0e2d..943abbd 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -30,16 +30,17 @@ #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 
-/* Address is autodetected, there is no default value */
-static unsigned short address;
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47b397"
 
 /* Super-I/0 registers and commands */
 
@@ -91,7 +92,8 @@ #define SMSC47B397_REG_FAN_LSB(nr) (0x28
 #define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr))
 
 struct smsc47b397_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
 	struct class_device *class_dev;
 	struct mutex lock;
 
@@ -104,45 +106,43 @@ struct smsc47b397_data {
 	u8 temp[4];
 };
 
-static int smsc47b397_read_value(struct i2c_client *client, u8 reg)
+static int smsc47b397_read_value(struct smsc47b397_data* data, u8 reg)
 {
-	struct smsc47b397_data *data = i2c_get_clientdata(client);
 	int res;
 
 	mutex_lock(&data->lock);
-	outb(reg, client->addr);
-	res = inb_p(client->addr + 1);
+	outb(reg, data->addr);
+	res = inb_p(data->addr + 1);
 	mutex_unlock(&data->lock);
 	return res;
 }
 
 static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
 {
- 	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47b397_data *data = i2c_get_clientdata(client);
+	struct smsc47b397_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-		dev_dbg(&client->dev, "starting device update...\n");
+		dev_dbg(dev, "starting device update...\n");
 
 		/* 4 temperature inputs, 4 fan inputs */
 		for (i = 0; i < 4; i++) {
-			data->temp[i] = smsc47b397_read_value(client,
+			data->temp[i] = smsc47b397_read_value(data,
 					SMSC47B397_REG_TEMP(i));
 
 			/* must read LSB first */
-			data->fan[i]  = smsc47b397_read_value(client,
+			data->fan[i]  = smsc47b397_read_value(data,
 					SMSC47B397_REG_FAN_LSB(i));
-			data->fan[i] |= smsc47b397_read_value(client,
+			data->fan[i] |= smsc47b397_read_value(data,
 					SMSC47B397_REG_FAN_MSB(i)) << 8;
 		}
 
 		data->last_updated = jiffies;
 		data->valid = 1;
 
-		dev_dbg(&client->dev, "... device update complete\n");
+		dev_dbg(dev, "... device update complete\n");
 	}
 
 	mutex_unlock(&data->update_lock);
@@ -157,24 +157,18 @@ static int temp_from_reg(u8 reg)
 	return (s8)reg * 1000;
 }
 
-/* 0 <= nr <= 3 */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47b397_data *data = smsc47b397_update_device(dev);
-	return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr]));
+	return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
 }
 
-#define sysfs_temp(num) \
-static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_temp(dev, buf, num-1); \
-} \
-static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL)
-
-sysfs_temp(1);
-sysfs_temp(2);
-sysfs_temp(3);
-sysfs_temp(4);
+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);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
 
 /* FAN: 1 RPM/bit
    REG: count of 90kHz pulses / revolution */
@@ -183,35 +177,37 @@ static int fan_from_reg(u16 reg)
 	return 90000 * 60 / reg;
 }
 
-/* 0 <= nr <= 3 */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute
+			*devattr, char *buf)
 {
-        struct smsc47b397_data *data = smsc47b397_update_device(dev);
-        return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr]));
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47b397_data *data = smsc47b397_update_device(dev);
+	return sprintf(buf, "%d\n", fan_from_reg(data->fan[attr->index]));
 }
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
 
-#define sysfs_fan(num) \
-static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_fan(dev, buf, num-1); \
-} \
-static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL)
-
-sysfs_fan(1);
-sysfs_fan(2);
-sysfs_fan(3);
-sysfs_fan(4);
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct smsc47b397_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 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,
-
+	&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_temp4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -219,44 +215,44 @@ static const struct attribute_group smsc
 	.attrs = smsc47b397_attributes,
 };
 
-static int smsc47b397_detach_client(struct i2c_client *client)
+static int __devexit smsc47b397_remove(struct platform_device *pdev)
 {
-	struct smsc47b397_data *data = i2c_get_clientdata(client);
-	int err;
+	struct smsc47b397_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 
 	hwmon_device_unregister(data->class_dev);
-	sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	release_region(client->addr, SMSC_EXTENT);
+	sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, SMSC_EXTENT);
 	kfree(data);
 
 	return 0;
 }
 
-static int smsc47b397_detect(struct i2c_adapter *adapter);
+static int smsc47b397_probe(struct platform_device *pdev);
 
-static struct i2c_driver smsc47b397_driver = {
+static struct platform_driver smsc47b397_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "smsc47b397",
+		.name	= DRVNAME,
 	},
-	.attach_adapter	= smsc47b397_detect,
-	.detach_client	= smsc47b397_detach_client,
+	.probe		= smsc47b397_probe,
+	.remove		= __devexit_p(smsc47b397_remove),
 };
 
-static int smsc47b397_detect(struct i2c_adapter *adapter)
+static int __devinit smsc47b397_probe(struct platform_device *pdev)
 {
-	struct i2c_client *new_client;
+	struct device *dev = &pdev->dev;
 	struct smsc47b397_data *data;
+	struct resource *res;
 	int err = 0;
 
-	if (!request_region(address, SMSC_EXTENT,
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, SMSC_EXTENT,
 			    smsc47b397_driver.driver.name)) {
-		dev_err(&adapter->dev, "Region 0x%x already in use!\n",
-			address);
+		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start,
+			(unsigned long)res->start + SMSC_EXTENT - 1);
 		return -EBUSY;
 	}
 
@@ -265,25 +261,16 @@ static int smsc47b397_detect(struct i2c_
 		goto error_release;
 	}
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
+	data->addr = res->start;
+	data->name = "smsc47b397";
 	mutex_init(&data->lock);
-	new_client->adapter = adapter;
-	new_client->driver = &smsc47b397_driver;
-	new_client->flags = 0;
-
-	strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE);
-
 	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
 
-	if ((err = i2c_attach_client(new_client)))
+	if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
 		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);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto error_remove;
@@ -292,13 +279,50 @@ static int smsc47b397_detect(struct i2c_
 	return 0;
 
 error_remove:
-	sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
-error_detach:
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&dev->kobj, &smsc47b397_group);
 error_free:
 	kfree(data);
 error_release:
-	release_region(address, SMSC_EXTENT);
+	release_region(res->start, SMSC_EXTENT);
+	return err;
+}
+
+static int __init smsc47b397_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SMSC_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
 	return err;
 }
 
@@ -320,7 +344,7 @@ static int __init smsc47b397_find(unsign
 	*addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
 		 |  superio_inb(SUPERIO_REG_BASE_LSB);
 
-	printk(KERN_INFO "smsc47b397: found SMSC %s "
+	printk(KERN_INFO DRVNAME ": found SMSC %s "
 		"(base address 0x%04x, revision %u)\n",
 		id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
 
@@ -330,17 +354,33 @@ static int __init smsc47b397_find(unsign
 
 static int __init smsc47b397_init(void)
 {
+	unsigned short address;
 	int ret;
 
 	if ((ret = smsc47b397_find(&address)))
 		return ret;
 
-	return i2c_isa_add_driver(&smsc47b397_driver);
+	ret = platform_driver_register(&smsc47b397_driver);
+	if (ret)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	ret = smsc47b397_device_add(address);
+	if (ret)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&smsc47b397_driver);
+exit:
+	return ret;
 }
 
 static void __exit smsc47b397_exit(void)
 {
-	i2c_isa_del_driver(&smsc47b397_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&smsc47b397_driver);
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index beb881c..1e21c8c 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -3,10 +3,11 @@
                  for hardware monitoring
 
     Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
-    LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
+    LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
+    Super-I/O chips.
 
     Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
-    Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
     Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
                         and Jean Delvare
 
@@ -29,17 +30,19 @@ #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #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 */
-static unsigned short address;
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47m1"
+enum chips { smsc47m1, smsc47m2 };
 
 /* Super-I/0 registers and commands */
 
@@ -87,10 +90,18 @@ #define SMSC_EXTENT		0x80
 #define SMSC47M1_REG_ALARM		0x04
 #define SMSC47M1_REG_TPIN(nr)		(0x34 - (nr))
 #define SMSC47M1_REG_PPIN(nr)		(0x36 - (nr))
-#define SMSC47M1_REG_PWM(nr)		(0x56 + (nr))
 #define SMSC47M1_REG_FANDIV		0x58
-#define SMSC47M1_REG_FAN(nr)		(0x59 + (nr))
-#define SMSC47M1_REG_FAN_PRELOAD(nr)	(0x5B + (nr))
+
+static const u8 SMSC47M1_REG_FAN[3]		= { 0x59, 0x5a, 0x6b };
+static const u8 SMSC47M1_REG_FAN_PRELOAD[3]	= { 0x5b, 0x5c, 0x6c };
+static const u8 SMSC47M1_REG_PWM[3]		= { 0x56, 0x57, 0x69 };
+
+#define SMSC47M2_REG_ALARM6		0x09
+#define SMSC47M2_REG_TPIN1		0x38
+#define SMSC47M2_REG_TPIN2		0x37
+#define SMSC47M2_REG_TPIN3		0x2d
+#define SMSC47M2_REG_PPIN3		0x2c
+#define SMSC47M2_REG_FANDIV3		0x6a
 
 #define MIN_FROM_REG(reg,div)		((reg)>=192 ? 0 : \
 					 983040/((192-(reg))*(div)))
@@ -102,45 +113,57 @@ #define PWM_EN_FROM_REG(reg)		((~(reg)) 
 #define PWM_TO_REG(reg)			(((reg) >> 1) & 0x7E)
 
 struct smsc47m1_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
+	enum chips type;
 	struct class_device *class_dev;
-	struct mutex lock;
 
 	struct mutex update_lock;
 	unsigned long last_updated;	/* In jiffies */
 
-	u8 fan[2];		/* Register value */
-	u8 fan_preload[2];	/* Register value */
-	u8 fan_div[2];		/* Register encoding, shifted right */
+	u8 fan[3];		/* Register value */
+	u8 fan_preload[3];	/* Register value */
+	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 alarms;		/* Register encoding */
-	u8 pwm[2];		/* Register value (bit 7 is enable) */
+	u8 pwm[3];		/* Register value (bit 0 is disable) */
 };
 
+struct smsc47m1_sio_data {
+	enum chips type;
+};
 
-static int smsc47m1_detect(struct i2c_adapter *adapter);
-static int smsc47m1_detach_client(struct i2c_client *client);
-
-static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
-static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value);
 
+static int smsc47m1_probe(struct platform_device *pdev);
+static int smsc47m1_remove(struct platform_device *pdev);
 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 		int init);
 
+static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
+{
+	return inb_p(data->addr + reg);
+}
 
-static struct i2c_driver smsc47m1_driver = {
+static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
+		u8 value)
+{
+	outb_p(value, data->addr + reg);
+}
+
+static struct platform_driver smsc47m1_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "smsc47m1",
+		.name	= DRVNAME,
 	},
-	.attach_adapter	= smsc47m1_detect,
-	.detach_client	= smsc47m1_detach_client,
+	.probe		= smsc47m1_probe,
+	.remove		= __devexit_p(smsc47m1_remove),
 };
 
-/* nr is 0 or 1 in the callback functions below */
-
-static ssize_t get_fan(struct device *dev, char *buf, int nr)
+static ssize_t get_fan(struct device *dev, struct device_attribute
+		       *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	int nr = attr->index;
 	/* This chip (stupidly) stops monitoring fan speed if PWM is
 	   enabled and duty cycle is 0%. This is fine if the monitoring
 	   and control concern the same fan, but troublesome if they are
@@ -152,43 +175,54 @@ static ssize_t get_fan(struct device *de
 	return sprintf(buf, "%d\n", rpm);
 }
 
-static ssize_t get_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t get_fan_min(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+	int nr = attr->index;
 	int rpm = MIN_FROM_REG(data->fan_preload[nr],
 			       DIV_FROM_REG(data->fan_div[nr]));
 	return sprintf(buf, "%d\n", rpm);
 }
 
-static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t get_fan_div(struct device *dev, struct device_attribute
+			   *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
-	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
 }
 
-static ssize_t get_pwm(struct device *dev, char *buf, int nr)
+static ssize_t get_pwm(struct device *dev, struct device_attribute
+		       *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
-	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
+	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
 }
 
-static ssize_t get_pwm_en(struct device *dev, char *buf, int nr)
+static ssize_t get_pwm_en(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
-	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
+	return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
 }
 
-static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t get_alarms(struct device *dev, struct device_attribute
+			  *devattr, char *buf)
 {
 	struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
 	return sprintf(buf, "%d\n", data->alarms);
 }
 
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	long rpmdiv, val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -200,7 +234,7 @@ static ssize_t set_fan_min(struct device
 	}
 
 	data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
-	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
 			     data->fan_preload[nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -211,12 +245,12 @@ static ssize_t set_fan_min(struct device
    determined in part by the fan clock divider.  This follows the principle
    of least surprise; the user doesn't expect the fan minimum to change just
    because the divider changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute
+			   *devattr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	long new_div = simple_strtol(buf, NULL, 10), tmp;
 	u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
 
@@ -234,27 +268,38 @@ static ssize_t set_fan_div(struct device
 		return -EINVAL;
 	}
 
-	tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F;
-	tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6);
-	smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
+	switch (nr) {
+	case 0:
+	case 1:
+		tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
+		      & ~(0x03 << (4 + 2 * nr));
+		tmp |= data->fan_div[nr] << (4 + 2 * nr);
+		smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
+		break;
+	case 2:
+		tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
+		tmp |= data->fan_div[2] << 4;
+		smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
+		break;
+	}
 
 	/* Preserve fan min */
 	tmp = 192 - (old_div * (192 - data->fan_preload[nr])
 		     + new_div / 2) / new_div;
 	data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
-	smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+	smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
 			     data->fan_preload[nr]);
 	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-static ssize_t set_pwm(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_pwm(struct device *dev, struct device_attribute
+		       *devattr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 
 	if (val < 0 || val > 255)
@@ -263,19 +308,19 @@ static ssize_t set_pwm(struct device *de
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] &= 0x81; /* Preserve additional bits */
 	data->pwm[nr] |= PWM_TO_REG(val);
-	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
 			     data->pwm[nr]);
 	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-static ssize_t set_pwm_en(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_pwm_en(struct device *dev, struct device_attribute
+			  *devattr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	long val = simple_strtol(buf, NULL, 10);
 	
 	if (val != 0 && val != 1)
@@ -284,7 +329,7 @@ static ssize_t set_pwm_en(struct device 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] &= 0xFE; /* preserve the other bits */
 	data->pwm[nr] |= !val;
-	smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+	smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
 			     data->pwm[nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -292,79 +337,55 @@ static ssize_t set_pwm_en(struct device 
 }
 
 #define fan_present(offset)						\
-static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	return get_fan(dev, buf, offset - 1);				\
-}									\
-static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return get_fan_min(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr,		\
-		const char *buf, size_t count)				\
-{									\
-	return set_fan_min(dev, buf, count, offset - 1);		\
-}									\
-static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return get_fan_div(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr,		\
-		const char *buf, size_t count)				\
-{									\
-	return set_fan_div(dev, buf, count, offset - 1);		\
-}									\
-static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	return get_pwm(dev, buf, offset - 1);				\
-}									\
-static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr,			\
-		const char *buf, size_t count)				\
-{									\
-	return set_pwm(dev, buf, count, offset - 1);			\
-}									\
-static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return get_pwm_en(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr,		\
-		const char *buf, size_t count)				\
-{									\
-	return set_pwm_en(dev, buf, count, offset - 1);			\
-}									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset,	\
-		NULL);							\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
-		get_fan##offset##_min, set_fan##offset##_min);		\
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
-		get_fan##offset##_div, set_fan##offset##_div);		\
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,			\
-		get_pwm##offset, set_pwm##offset);			\
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,		\
-		get_pwm##offset##_en, set_pwm##offset##_en);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan,	\
+		NULL, offset - 1);					\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		get_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		get_fan_div, set_fan_div, offset - 1);			\
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,		\
+		get_pwm, set_pwm, offset - 1);				\
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,	\
+		get_pwm_en, set_pwm_en, offset - 1)
 
 fan_present(1);
 fan_present(2);
+fan_present(3);
 
 static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, 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,
+	&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.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
 
 	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -372,7 +393,8 @@ static const struct attribute_group smsc
 	.attrs = smsc47m1_attributes,
 };
 
-static int __init smsc47m1_find(unsigned short *addr)
+static int __init smsc47m1_find(unsigned short *addr,
+				struct smsc47m1_sio_data *sio_data)
 {
 	u8 val;
 
@@ -386,18 +408,32 @@ static int __init smsc47m1_find(unsigned
 	 * can do much more besides (device id 0x60).
 	 * The LPC47M997 is undocumented, but seems to be compatible with
 	 * the LPC47M192, and has the same device id.
+	 * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
+	 * supports a 3rd fan, and the pin configuration registers are
+	 * unfortunately different.
 	 */
-	if (val == 0x51)
-		printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
-	else if (val == 0x59)
-		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)
-		printk(KERN_INFO "smsc47m1: Found SMSC "
-		       "LPC47M15x/LPC47M192/LPC47M997\n");
-	else {
+	switch (val) {
+	case 0x51:
+		pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x59:
+		pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x5F:
+		pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x60:
+		pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
+		sio_data->type = smsc47m1;
+		break;
+	case 0x6B:
+		pr_info(DRVNAME ": Found SMSC LPC47M292\n");
+		sio_data->type = smsc47m2;
+		break;
+	default:
 		superio_exit();
 		return -ENODEV;
 	}
@@ -407,7 +443,7 @@ static int __init smsc47m1_find(unsigned
 	      |  superio_inb(SUPERIO_REG_BASE + 1);
 	val = superio_inb(SUPERIO_REG_ACT);
 	if (*addr == 0 || (val & 0x01) == 0) {
-		printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
+		pr_info(DRVNAME ": Device is disabled, will not use\n");
 		superio_exit();
 		return -ENODEV;
 	}
@@ -416,15 +452,25 @@ static int __init smsc47m1_find(unsigned
 	return 0;
 }
 
-static int smsc47m1_detect(struct i2c_adapter *adapter)
+static int __devinit smsc47m1_probe(struct platform_device *pdev)
 {
-	struct i2c_client *new_client;
+	struct device *dev = &pdev->dev;
+	struct smsc47m1_sio_data *sio_data = dev->platform_data;
 	struct smsc47m1_data *data;
+	struct resource *res;
 	int err = 0;
-	int fan1, fan2, pwm1, pwm2;
-
-	if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) {
-		dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
+	int fan1, fan2, fan3, pwm1, pwm2, pwm3;
+
+	static const char *names[] = {
+		"smsc47m1",
+		"smsc47m2",
+	};
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
+		dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start,
+			(unsigned long)res->end);
 		return -EBUSY;
 	}
 
@@ -433,93 +479,114 @@ static int smsc47m1_detect(struct i2c_ad
 		goto error_release;
 	}
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	mutex_init(&data->lock);
-	new_client->adapter = adapter;
-	new_client->driver = &smsc47m1_driver;
-	new_client->flags = 0;
-
-	strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->name = names[sio_data->type];
 	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
 
 	/* If no function is properly configured, there's no point in
 	   actually registering the chip. */
-	fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
-	       == 0x05;
-	fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
-	       == 0x05;
-	pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
+	pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
 	       == 0x04;
-	pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
+	pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
 	       == 0x04;
-	if (!(fan1 || fan2 || pwm1 || pwm2)) {
-		dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
-			 "will not use\n", new_client->addr);
+	if (data->type == smsc47m2) {
+		fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
+			& 0x0d) == 0x09;
+		fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
+			& 0x0d) == 0x09;
+		fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
+			& 0x0d) == 0x0d;
+		pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
+			& 0x0d) == 0x08;
+	} else {
+		fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
+			& 0x05) == 0x05;
+		fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
+			& 0x05) == 0x05;
+		fan3 = 0;
+		pwm3 = 0;
+	}
+	if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
+		dev_warn(dev, "Device not configured, will not use\n");
 		err = -ENODEV;
 		goto error_free;
 	}
 
-	if ((err = i2c_attach_client(new_client)))
-		goto error_free;
-
 	/* Some values (fan min, clock dividers, pwm registers) may be
 	   needed before any update is triggered, so we better read them
 	   at least once here. We don't usually do it that way, but in
 	   this particular case, manually reading 5 registers out of 8
 	   doesn't make much sense and we're better using the existing
 	   function. */
-	smsc47m1_update_device(&new_client->dev, 1);
+	smsc47m1_update_device(dev, 1);
 
 	/* Register sysfs hooks */
 	if (fan1) {
-		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)))
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_fan1_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan1_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan1_div.dev_attr)))
 			goto error_remove_files;
 	} else
-		dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
-			"skipping\n");
+		dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
 
 	if (fan2) {
-		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)))
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_fan2_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan2_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan2_div.dev_attr)))
 			goto error_remove_files;
 	} else
-		dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
-			"skipping\n");
+		dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
+
+	if (fan3) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_fan3_input.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_min.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_fan3_div.dev_attr)))
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
 
 	if (pwm1) {
-		if ((err = device_create_file(&new_client->dev,
-					      &dev_attr_pwm1))
-		 || (err = device_create_file(&new_client->dev,
-					      &dev_attr_pwm1_enable)))
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm1.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm1_enable.dev_attr)))
 			goto error_remove_files;
 	} else
-		dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
-			"skipping\n");
+		dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
+
 	if (pwm2) {
-		if ((err = device_create_file(&new_client->dev,
-					      &dev_attr_pwm2))
-		 || (err = device_create_file(&new_client->dev,
-					      &dev_attr_pwm2_enable)))
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm2.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm2_enable.dev_attr)))
+			goto error_remove_files;
+	} else
+		dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
+
+	if (pwm3) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm3.dev_attr))
+		 || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm3_enable.dev_attr)))
 			goto error_remove_files;
 	} else
-		dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
-			"skipping\n");
+		dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
 
-	if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
+	if ((err = device_create_file(dev, &dev_attr_alarms)))
 		goto error_remove_files;
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto error_remove_files;
@@ -528,78 +595,71 @@ static int smsc47m1_detect(struct i2c_ad
 	return 0;
 
 error_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
 error_free:
 	kfree(data);
 error_release:
-	release_region(address, SMSC_EXTENT);
+	release_region(res->start, SMSC_EXTENT);
 	return err;
 }
 
-static int smsc47m1_detach_client(struct i2c_client *client)
+static int __devexit smsc47m1_remove(struct platform_device *pdev)
 {
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
-	int err;
+	struct smsc47m1_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 
+	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
-	sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
+	sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
 
-	release_region(client->addr, SMSC_EXTENT);
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, SMSC_EXTENT);
 	kfree(data);
 
 	return 0;
 }
 
-static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
-{
-	int res;
-
-	mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
-	res = inb_p(client->addr + reg);
-	mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
-	return res;
-}
-
-static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
-{
-	mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
-	outb_p(value, client->addr + reg);
-	mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
-}
-
 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 		int init)
 {
- 	struct i2c_client *client = to_i2c_client(dev);
-	struct smsc47m1_data *data = i2c_get_clientdata(client);
+	struct smsc47m1_data *data = dev_get_drvdata(dev);
 
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			data->fan[i] = smsc47m1_read_value(client,
-				       SMSC47M1_REG_FAN(i));
-			data->fan_preload[i] = smsc47m1_read_value(client,
-					       SMSC47M1_REG_FAN_PRELOAD(i));
-			data->pwm[i] = smsc47m1_read_value(client,
-				       SMSC47M1_REG_PWM(i));
+		int i, fan_nr;
+		fan_nr = data->type == smsc47m2 ? 3 : 2;
+
+		for (i = 0; i < fan_nr; i++) {
+			data->fan[i] = smsc47m1_read_value(data,
+				       SMSC47M1_REG_FAN[i]);
+			data->fan_preload[i] = smsc47m1_read_value(data,
+					       SMSC47M1_REG_FAN_PRELOAD[i]);
+			data->pwm[i] = smsc47m1_read_value(data,
+				       SMSC47M1_REG_PWM[i]);
 		}
 
-		i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
+		i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = i >> 6;
 
-		data->alarms = smsc47m1_read_value(client,
+		data->alarms = smsc47m1_read_value(data,
 			       SMSC47M1_REG_ALARM) >> 6;
 		/* Clear alarms if needed */
 		if (data->alarms)
-			smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);
+			smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
+
+		if (fan_nr >= 3) {
+			data->fan_div[2] = (smsc47m1_read_value(data,
+					    SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
+			data->alarms |= (smsc47m1_read_value(data,
+					 SMSC47M2_REG_ALARM6) & 0x40) >> 4;
+			/* Clear alarm if needed */
+			if (data->alarms & 0x04)
+				smsc47m1_write_value(data,
+						     SMSC47M2_REG_ALARM6,
+						     0x40);
+		}
 
 		data->last_updated = jiffies;
 	}
@@ -608,18 +668,86 @@ static struct smsc47m1_data *smsc47m1_up
 	return data;
 }
 
+static int __init smsc47m1_device_add(unsigned short address,
+				      const struct smsc47m1_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SMSC_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
+					  GFP_KERNEL);
+	if (!pdev->dev.platform_data) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+	memcpy(pdev->dev.platform_data, sio_data,
+	       sizeof(struct smsc47m1_sio_data));
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __init sm_smsc47m1_init(void)
 {
-	if (smsc47m1_find(&address)) {
+	int err;
+	unsigned short address;
+	struct smsc47m1_sio_data sio_data;
+
+	if (smsc47m1_find(&address, &sio_data))
 		return -ENODEV;
-	}
 
-	return i2c_isa_add_driver(&smsc47m1_driver);
+	err = platform_driver_register(&smsc47m1_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = smsc47m1_device_add(address, &sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&smsc47m1_driver);
+exit:
+	return err;
 }
 
 static void __exit sm_smsc47m1_exit(void)
 {
-	i2c_isa_del_driver(&smsc47m1_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&smsc47m1_driver);
 }
 
 MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index a6833f4..a012f39 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -1,6 +1,6 @@
 /*
     smsc47m192.c - Support for hardware monitoring block of
-                   SMSC LPC47M192 and LPC47M997 Super I/O chips
+                   SMSC LPC47M192 and compatible Super I/O chips
 
     Copyright (C) 2006  Hartmut Rick <linux@rick.claranet.de>
 
@@ -518,7 +518,7 @@ static int smsc47m192_detect(struct i2c_
 		 && (i2c_smbus_read_byte_data(client,
 				SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
 			dev_info(&adapter->dev,
-				 "found SMSC47M192 or SMSC47M997, "
+				 "found SMSC47M192 or compatible, "
 				 "version 2, stepping A%d\n", version & 0x0f);
 		} else {
 			dev_dbg(&adapter->dev,
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 89c23d6..9f3e332 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -31,6 +31,7 @@ #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/ioport.h>
 #include <asm/io.h>
 
 static int uch_config = -1;
@@ -1130,6 +1131,12 @@ static int __devinit vt1211_probe(struct
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+		err = -EBUSY;
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start, (unsigned long)res->end);
+		goto EXIT_KFREE;
+	}
 	data->addr = res->start;
 	data->name = DRVNAME;
 	mutex_init(&data->update_lock);
@@ -1197,6 +1204,8 @@ EXIT_DEV_REMOVE:
 	dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
 EXIT_DEV_REMOVE_SILENT:
 	vt1211_remove_sysfs(pdev);
+	release_region(res->start, res->end - res->start + 1);
+EXIT_KFREE:
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 EXIT:
@@ -1206,12 +1215,16 @@ EXIT:
 static int __devexit vt1211_remove(struct platform_device *pdev)
 {
 	struct vt1211_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 
 	hwmon_device_unregister(data->class_dev);
 	vt1211_remove_sysfs(pdev);
 	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, res->end - res->start + 1);
+
 	return 0;
 }
 
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index d7e2406..a5b774b 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -5,6 +5,7 @@
     Philip Edelbrock <phil@netroedge.com>,
     and Mark Studebaker <mdsxyz123@yahoo.com>
     Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+    Copyright (c) 2007  Jean Delvare <khali@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
@@ -42,15 +43,20 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/ioport.h>
 #include <asm/io.h>
 #include "lm75.h"
 
+static struct platform_device *pdev;
+
+#define DRVNAME "w83627hf"
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+
 static u16 force_addr;
 module_param(force_addr, ushort, 0);
 MODULE_PARM_DESC(force_addr,
@@ -60,12 +66,6 @@ module_param(force_i2c, byte, 0);
 MODULE_PARM_DESC(force_i2c,
 		 "Initialize the i2c address of the sensors");
 
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
-
-/* Insmod parameters */
-enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
 static int reset;
 module_param(reset, bool, 0);
 MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
@@ -156,9 +156,9 @@ #define WINB_ALIGNMENT		~7
 #define WINB_REGION_OFFSET	5
 #define WINB_REGION_SIZE	2
 
-/* Where are the sensors address/data registers relative to the base address */
-#define W83781D_ADDR_REG_OFFSET 5
-#define W83781D_DATA_REG_OFFSET 6
+/* Where are the sensors address/data registers relative to the region offset */
+#define W83781D_ADDR_REG_OFFSET 0
+#define W83781D_DATA_REG_OFFSET 1
 
 /* The W83781D registers */
 /* The W83782D registers for nr=7,8 are in bank 5 */
@@ -289,7 +289,8 @@ static inline u8 DIV_TO_REG(long val)
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct w83627hf_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
 	struct class_device *class_dev;
 	struct mutex lock;
 	enum chips type;
@@ -298,9 +299,6 @@ struct w83627hf_data {
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
-	struct i2c_client *lm75;	/* for secondary I2C addresses */
-	/* pointer to array of 2 subclients */
-
 	u8 in[9];		/* Register value */
 	u8 in_max[9];		/* Register value */
 	u8 in_min[9];		/* Register value */
@@ -327,22 +325,26 @@ struct w83627hf_data {
 	u8 vrm_ovt;		/* Register value, 627THF/637HF/687THF only */
 };
 
+struct w83627hf_sio_data {
+	enum chips type;
+};
+
 
-static int w83627hf_detect(struct i2c_adapter *adapter);
-static int w83627hf_detach_client(struct i2c_client *client);
+static int w83627hf_probe(struct platform_device *pdev);
+static int w83627hf_remove(struct platform_device *pdev);
 
-static int w83627hf_read_value(struct i2c_client *client, u16 reg);
-static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value);
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
 static struct w83627hf_data *w83627hf_update_device(struct device *dev);
-static void w83627hf_init_client(struct i2c_client *client);
+static void w83627hf_init_device(struct platform_device *pdev);
 
-static struct i2c_driver w83627hf_driver = {
+static struct platform_driver w83627hf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "w83627hf",
+		.name	= DRVNAME,
 	},
-	.attach_adapter	= w83627hf_detect,
-	.detach_client	= w83627hf_detach_client,
+	.probe		= w83627hf_probe,
+	.remove		= __devexit_p(w83627hf_remove),
 };
 
 /* following are the sysfs callback functions */
@@ -360,15 +362,14 @@ #define store_in_reg(REG, reg) \
 static ssize_t \
 store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627hf_data *data = i2c_get_clientdata(client); \
+	struct w83627hf_data *data = dev_get_drvdata(dev); \
 	u32 val; \
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
 	 \
 	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
-	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
+	w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
 			    data->in_##reg[nr]); \
 	 \
 	mutex_unlock(&data->update_lock); \
@@ -452,8 +453,7 @@ static ssize_t show_regs_in_max0(struct 
 static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
 	const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -472,7 +472,7 @@ static ssize_t store_regs_in_min0(struct
 		/* use VRM8 (standard) calculation */
 		data->in_min[0] = IN_TO_REG(val);
 
-	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
+	w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -480,8 +480,7 @@ static ssize_t store_regs_in_min0(struct
 static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
 	const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -500,7 +499,7 @@ static ssize_t store_regs_in_max0(struct
 		/* use VRM8 (standard) calculation */
 		data->in_max[0] = IN_TO_REG(val);
 
-	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
+	w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -525,8 +524,7 @@ show_fan_reg(fan_min);
 static ssize_t
 store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -534,7 +532,7 @@ store_fan_min(struct device *dev, const 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr - 1] =
 	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
-	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
+	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
 			    data->fan_min[nr - 1]);
 
 	mutex_unlock(&data->update_lock);
@@ -587,8 +585,7 @@ #define store_temp_reg(REG, reg) \
 static ssize_t \
 store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627hf_data *data = i2c_get_clientdata(client); \
+	struct w83627hf_data *data = dev_get_drvdata(dev); \
 	u32 val; \
 	 \
 	val = simple_strtoul(buf, NULL, 10); \
@@ -597,11 +594,11 @@ store_temp_##reg (struct device *dev, co
 	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
-		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+		w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
 				data->temp_##reg##_add[nr-2]); \
 	} else {	/* TEMP1 */ \
 		data->temp_##reg = TEMP_TO_REG(val); \
-		w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+		w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
 			data->temp_##reg); \
 	} \
 	 \
@@ -659,8 +656,7 @@ show_vrm_reg(struct device *dev, struct 
 static ssize_t
 store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -695,8 +691,7 @@ static ssize_t
 store_beep_reg(struct device *dev, const char *buf, size_t count,
 	       int update_mask)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val, val2;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -705,18 +700,18 @@ store_beep_reg(struct device *dev, const
 
 	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
 		data->beep_mask = BEEP_MASK_TO_REG(val);
-		w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
 				    data->beep_mask & 0xff);
-		w83627hf_write_value(client, W83781D_REG_BEEP_INTS3,
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
 				    ((data->beep_mask) >> 16) & 0xff);
 		val2 = (data->beep_mask >> 8) & 0x7f;
 	} else {		/* We are storing beep_enable */
 		val2 =
-		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
+		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
 		data->beep_enable = BEEP_ENABLE_TO_REG(val);
 	}
 
-	w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
+	w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
 			    val2 | data->beep_enable << 7);
 
 	mutex_unlock(&data->update_lock);
@@ -754,8 +749,7 @@ show_fan_div_reg(struct device *dev, cha
 static ssize_t
 store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	unsigned long min;
 	u8 reg;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
@@ -768,19 +762,19 @@ store_fan_div_reg(struct device *dev, co
 
 	data->fan_div[nr] = DIV_TO_REG(val);
 
-	reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+	reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
 	       & (nr==0 ? 0xcf : 0x3f))
 	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
-	w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+	w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
 
-	reg = (w83627hf_read_value(client, W83781D_REG_VBAT)
+	reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
 	       & ~(1 << (5 + nr)))
 	    | ((data->fan_div[nr] & 0x04) << (3 + nr));
-	w83627hf_write_value(client, W83781D_REG_VBAT, reg);
+	w83627hf_write_value(data, W83781D_REG_VBAT, reg);
 
 	/* Restore fan_min */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -814,8 +808,7 @@ show_pwm_reg(struct device *dev, char *b
 static ssize_t
 store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -825,14 +818,14 @@ store_pwm_reg(struct device *dev, const 
 	if (data->type == w83627thf) {
 		/* bits 0-3 are reserved  in 627THF */
 		data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
-		w83627hf_write_value(client,
+		w83627hf_write_value(data,
 				     W836X7HF_REG_PWM(data->type, nr),
 				     data->pwm[nr - 1] |
-				     (w83627hf_read_value(client,
+				     (w83627hf_read_value(data,
 				     W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
 	} else {
 		data->pwm[nr - 1] = PWM_TO_REG(val);
-		w83627hf_write_value(client,
+		w83627hf_write_value(data,
 				     W836X7HF_REG_PWM(data->type, nr),
 				     data->pwm[nr - 1]);
 	}
@@ -868,8 +861,7 @@ show_sensor_reg(struct device *dev, char
 static ssize_t
 store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	u32 val, tmp;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -878,31 +870,31 @@ store_sensor_reg(struct device *dev, con
 
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
-		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
-		w83627hf_write_value(client, W83781D_REG_SCFG1,
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
 				    tmp | BIT_SCFG1[nr - 1]);
-		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
-		w83627hf_write_value(client, W83781D_REG_SCFG2,
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+		w83627hf_write_value(data, W83781D_REG_SCFG2,
 				    tmp | BIT_SCFG2[nr - 1]);
 		data->sens[nr - 1] = val;
 		break;
 	case 2:		/* 3904 */
-		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
-		w83627hf_write_value(client, W83781D_REG_SCFG1,
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
 				    tmp | BIT_SCFG1[nr - 1]);
-		tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
-		w83627hf_write_value(client, W83781D_REG_SCFG2,
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+		w83627hf_write_value(data, W83781D_REG_SCFG2,
 				    tmp & ~BIT_SCFG2[nr - 1]);
 		data->sens[nr - 1] = val;
 		break;
 	case W83781D_DEFAULT_BETA:	/* thermistor */
-		tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
-		w83627hf_write_value(client, W83781D_REG_SCFG1,
+		tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+		w83627hf_write_value(data, W83781D_REG_SCFG1,
 				    tmp & ~BIT_SCFG1[nr - 1]);
 		data->sens[nr - 1] = val;
 		break;
 	default:
-		dev_err(&client->dev,
+		dev_err(dev,
 		       "Invalid sensor type %ld; must be 1, 2, or %d\n",
 		       (long) val, W83781D_DEFAULT_BETA);
 		break;
@@ -929,35 +921,85 @@ sysfs_sensor(1);
 sysfs_sensor(2);
 sysfs_sensor(3);
 
-static int __init w83627hf_find(int sioaddr, unsigned short *addr)
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+				struct w83627hf_sio_data *sio_data)
 {
+	int err = -ENODEV;
 	u16 val;
 
+	static const __initdata char *names[] = {
+		"W83627HF",
+		"W83627THF",
+		"W83697HF",
+		"W83637HF",
+		"W83687THF",
+	};
+
 	REG = sioaddr;
 	VAL = sioaddr + 1;
 
 	superio_enter();
 	val= superio_inb(DEVID);
-	if(val != W627_DEVID &&
-	   val != W627THF_DEVID &&
-	   val != W697_DEVID &&
-	   val != W637_DEVID &&
-	   val != W687THF_DEVID) {
-		superio_exit();
-		return -ENODEV;
+	switch (val) {
+	case W627_DEVID:
+		sio_data->type = w83627hf;
+		break;
+	case W627THF_DEVID:
+		sio_data->type = w83627thf;
+		break;
+	case W697_DEVID:
+		sio_data->type = w83697hf;
+		break;
+	case W637_DEVID:
+		sio_data->type = w83637hf;
+		break;
+	case W687THF_DEVID:
+		sio_data->type = w83687thf;
+		break;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n", val);
+		goto exit;
 	}
 
 	superio_select(W83627HF_LD_HWM);
+	force_addr &= WINB_ALIGNMENT;
+	if (force_addr) {
+		printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+		       force_addr);
+		superio_outb(WINB_BASE_REG, force_addr >> 8);
+		superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
+	}
 	val = (superio_inb(WINB_BASE_REG) << 8) |
 	       superio_inb(WINB_BASE_REG + 1);
 	*addr = val & WINB_ALIGNMENT;
-	if (*addr == 0 && force_addr == 0) {
-		superio_exit();
-		return -ENODEV;
+	if (*addr == 0) {
+		printk(KERN_WARNING DRVNAME ": Base address not set, "
+		       "skipping\n");
+		goto exit;
 	}
 
+	val = superio_inb(WINB_ACT_REG);
+	if (!(val & 0x01)) {
+		printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+		superio_outb(WINB_ACT_REG, val | 0x01);
+	}
+
+	err = 0;
+	pr_info(DRVNAME ": Found %s chip at %#x\n",
+		names[sio_data->type], *addr);
+
+ exit:
 	superio_exit();
-	return 0;
+	return err;
 }
 
 static struct attribute *w83627hf_attributes[] = {
@@ -1003,6 +1045,7 @@ static struct attribute *w83627hf_attrib
 	&dev_attr_pwm1.attr,
 	&dev_attr_pwm2.attr,
 
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -1039,161 +1082,92 @@ static const struct attribute_group w836
 	.attrs = w83627hf_attributes_opt,
 };
 
-static int w83627hf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627hf_probe(struct platform_device *pdev)
 {
-	int val, kind;
-	struct i2c_client *new_client;
+	struct device *dev = &pdev->dev;
+	struct w83627hf_sio_data *sio_data = dev->platform_data;
 	struct w83627hf_data *data;
-	int err = 0;
-	const char *client_name = "";
-
-	if(force_addr)
-		address = force_addr & WINB_ALIGNMENT;
+	struct resource *res;
+	int err;
 
-	if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE,
-	                    w83627hf_driver.driver.name)) {
+	static const char *names[] = {
+		"w83627hf",
+		"w83627thf",
+		"w83697hf",
+		"w83637hf",
+		"w83687thf",
+	};
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)(res->start + WINB_REGION_SIZE - 1));
 		err = -EBUSY;
 		goto ERROR0;
 	}
 
-	if(force_addr) {
-		printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
-		superio_enter();
-		superio_select(W83627HF_LD_HWM);
-		superio_outb(WINB_BASE_REG, address >> 8);
-		superio_outb(WINB_BASE_REG+1, address & 0xff);
-		superio_exit();
-	}
-
-	superio_enter();
-	val= superio_inb(DEVID);
-	if(val == W627_DEVID)
-		kind = w83627hf;
-	else if(val == W697_DEVID)
-		kind = w83697hf;
-	else if(val == W627THF_DEVID)
-		kind = w83627thf;
-	else if(val == W637_DEVID)
-		kind = w83637hf;
-	else if (val == W687THF_DEVID)
-		kind = w83687thf;
-	else {
-		dev_info(&adapter->dev,
-			 "Unsupported chip (dev_id=0x%02X).\n", val);
-		goto ERROR1;
-	}
-
-	superio_select(W83627HF_LD_HWM);
-	if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
-		superio_outb(WINB_ACT_REG, 1);
-	superio_exit();
-
-	/* OK. For now, we presume we have a valid client. We now create the
-	   client structure, even though we cannot fill it completely yet.
-	   But it allows us to access w83627hf_{read,write}_value. */
-
 	if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto ERROR1;
 	}
-
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->name = names[sio_data->type];
 	mutex_init(&data->lock);
-	new_client->adapter = adapter;
-	new_client->driver = &w83627hf_driver;
-	new_client->flags = 0;
-
-
-	if (kind == w83627hf) {
-		client_name = "w83627hf";
-	} else if (kind == w83627thf) {
-		client_name = "w83627thf";
-	} else if (kind == w83697hf) {
-		client_name = "w83697hf";
-	} else if (kind == w83637hf) {
-		client_name = "w83637hf";
-	} else if (kind == w83687thf) {
-		client_name = "w83687thf";
-	}
-
-	/* Fill in the remaining client fields and put into the global list */
-	strlcpy(new_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)))
-		goto ERROR2;
-
-	data->lm75 = NULL;
+	platform_set_drvdata(pdev, data);
 
 	/* Initialize the chip */
-	w83627hf_init_client(new_client);
+	w83627hf_init_device(pdev);
 
 	/* A few vars need to be filled upon startup */
-	data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1));
-	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));
+	data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
+	data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
+	data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
 
 	/* Register common device attributes */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
+	if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
 		goto ERROR3;
 
 	/* 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)))
+	if (data->type == w83627hf || data->type == w83697hf)
+		if ((err = device_create_file(dev, &dev_attr_in5_input))
+		 || (err = device_create_file(dev, &dev_attr_in5_min))
+		 || (err = device_create_file(dev, &dev_attr_in5_max))
+		 || (err = device_create_file(dev, &dev_attr_in6_input))
+		 || (err = device_create_file(dev, &dev_attr_in6_min))
+		 || (err = device_create_file(dev, &dev_attr_in6_max)))
 			goto ERROR4;
 
-	if (kind != w83697hf)
-		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)))
+	if (data->type != w83697hf)
+		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))
+		 || (err = device_create_file(dev, &dev_attr_fan3_input))
+		 || (err = device_create_file(dev, &dev_attr_fan3_min))
+		 || (err = device_create_file(dev, &dev_attr_fan3_div))
+		 || (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))
+		 || (err = device_create_file(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)))
+	if (data->type != w83697hf && data->vid != 0xff) {
+		/* Convert VID to voltage based on VRM */
+		data->vrm = vid_which_vrm();
+
+		if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
+		 || (err = device_create_file(dev, &dev_attr_vrm)))
 			goto ERROR4;
+	}
 
-	if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
-		if ((err = device_create_file(&new_client->dev,
-					&dev_attr_pwm3)))
+	if (data->type == w83627thf || data->type == w83637hf
+	 || data->type == w83687thf)
+		if ((err = device_create_file(dev, &dev_attr_pwm3)))
 			goto ERROR4;
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto ERROR4;
@@ -1202,47 +1176,37 @@ static int w83627hf_detect(struct i2c_ad
 	return 0;
 
       ERROR4:
-	sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
-	sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
+	sysfs_remove_group(&dev->kobj, &w83627hf_group);
+	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
       ERROR3:
-	i2c_detach_client(new_client);
-      ERROR2:
 	kfree(data);
       ERROR1:
-	release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE);
+	release_region(res->start, WINB_REGION_SIZE);
       ERROR0:
 	return err;
 }
 
-static int w83627hf_detach_client(struct i2c_client *client)
+static int __devexit w83627hf_remove(struct platform_device *pdev)
 {
-	struct w83627hf_data *data = i2c_get_clientdata(client);
-	int err;
+	struct w83627hf_data *data = platform_get_drvdata(pdev);
+	struct resource *res;
 
+	platform_set_drvdata(pdev, NULL);
 	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;
-
-	release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE);
+	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
+	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
 	kfree(data);
 
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, WINB_REGION_SIZE);
+
 	return 0;
 }
 
 
-/*
-   ISA access must always be locked explicitly!
-   We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
-   would slow down the W83781D access and should not be necessary.
-   There are some ugly typecasts here, but the good news is - they should
-   nowhere else be necessary! */
-static int w83627hf_read_value(struct i2c_client *client, u16 reg)
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
 {
-	struct w83627hf_data *data = i2c_get_clientdata(client);
 	int res, word_sized;
 
 	mutex_lock(&data->lock);
@@ -1253,29 +1217,29 @@ static int w83627hf_read_value(struct i2
 		   || ((reg & 0x00ff) == 0x55));
 	if (reg & 0xff00) {
 		outb_p(W83781D_REG_BANK,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
 		outb_p(reg >> 8,
-		       client->addr + W83781D_DATA_REG_OFFSET);
+		       data->addr + W83781D_DATA_REG_OFFSET);
 	}
-	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
-	res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
+	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
+	res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
 	if (word_sized) {
 		outb_p((reg & 0xff) + 1,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
 		res =
-		    (res << 8) + inb_p(client->addr +
+		    (res << 8) + inb_p(data->addr +
 				       W83781D_DATA_REG_OFFSET);
 	}
 	if (reg & 0xff00) {
 		outb_p(W83781D_REG_BANK,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
-		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
 	}
 	mutex_unlock(&data->lock);
 	return res;
 }
 
-static int w83627thf_read_gpio5(struct i2c_client *client)
+static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
 {
 	int res = 0xff, sel;
 
@@ -1284,7 +1248,7 @@ static int w83627thf_read_gpio5(struct i
 
 	/* Make sure these GPIO pins are enabled */
 	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
-		dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n");
+		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
 		goto exit;
 	}
 
@@ -1292,12 +1256,12 @@ static int w83627thf_read_gpio5(struct i
 	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */
 	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
 	if ((sel & 0x1f) != 0x1f) {
-		dev_dbg(&client->dev, "GPIO5 not configured for VID "
+		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
 			"function\n");
 		goto exit;
 	}
 
-	dev_info(&client->dev, "Reading VID from GPIO5\n");
+	dev_info(&pdev->dev, "Reading VID from GPIO5\n");
 	res = superio_inb(W83627THF_GPIO5_DR) & sel;
 
 exit:
@@ -1305,7 +1269,7 @@ exit:
 	return res;
 }
 
-static int w83687thf_read_vid(struct i2c_client *client)
+static int __devinit w83687thf_read_vid(struct platform_device *pdev)
 {
 	int res = 0xff;
 
@@ -1314,13 +1278,13 @@ static int w83687thf_read_vid(struct i2c
 
 	/* Make sure these GPIO pins are enabled */
 	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
-		dev_dbg(&client->dev, "VID disabled, no VID function\n");
+		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
 		goto exit;
 	}
 
 	/* Make sure the pins are configured for input */
 	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
-		dev_dbg(&client->dev, "VID configured as output, "
+		dev_dbg(&pdev->dev, "VID configured as output, "
 			"no VID function\n");
 		goto exit;
 	}
@@ -1332,9 +1296,8 @@ exit:
 	return res;
 }
 
-static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
 {
-	struct w83627hf_data *data = i2c_get_clientdata(client);
 	int word_sized;
 
 	mutex_lock(&data->lock);
@@ -1344,33 +1307,33 @@ static int w83627hf_write_value(struct i
 		   || ((reg & 0x00ff) == 0x55));
 	if (reg & 0xff00) {
 		outb_p(W83781D_REG_BANK,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
 		outb_p(reg >> 8,
-		       client->addr + W83781D_DATA_REG_OFFSET);
+		       data->addr + W83781D_DATA_REG_OFFSET);
 	}
-	outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
 	if (word_sized) {
 		outb_p(value >> 8,
-		       client->addr + W83781D_DATA_REG_OFFSET);
+		       data->addr + W83781D_DATA_REG_OFFSET);
 		outb_p((reg & 0xff) + 1,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
 	}
 	outb_p(value & 0xff,
-	       client->addr + W83781D_DATA_REG_OFFSET);
+	       data->addr + W83781D_DATA_REG_OFFSET);
 	if (reg & 0xff00) {
 		outb_p(W83781D_REG_BANK,
-		       client->addr + W83781D_ADDR_REG_OFFSET);
-		outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+		       data->addr + W83781D_ADDR_REG_OFFSET);
+		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
 	}
 	mutex_unlock(&data->lock);
 	return 0;
 }
 
-static void w83627hf_init_client(struct i2c_client *client)
+static void __devinit w83627hf_init_device(struct platform_device *pdev)
 {
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = platform_get_drvdata(pdev);
 	int i;
-	int type = data->type;
+	enum chips type = data->type;
 	u8 tmp;
 
 	if (reset) {
@@ -1379,57 +1342,53 @@ static void w83627hf_init_client(struct 
 		   speed...) so it is now optional. It might even go away if
 		   nobody reports it as being useful, as I see very little
 		   reason why this would be needed at all. */
-		dev_info(&client->dev, "If reset=1 solved a problem you were "
+		dev_info(&pdev->dev, "If reset=1 solved a problem you were "
 			 "having, please report!\n");
 
 		/* save this register */
-		i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
+		i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
 		/* Reset all except Watchdog values and last conversion values
 		   This sets fan-divs to 2, among others */
-		w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);
+		w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
 		/* Restore the register and disable power-on abnormal beep.
 		   This saves FAN 1/2/3 input/output values set by BIOS. */
-		w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+		w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
 		/* Disable master beep-enable (reset turns it on).
 		   Individual beeps should be reset to off but for some reason
 		   disabling this bit helps some people not get beeped */
-		w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);
+		w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
 	}
 
 	/* Minimize conflicts with other winbond i2c-only clients...  */
 	/* disable i2c subclients... how to disable main i2c client?? */
 	/* force i2c address to relatively uncommon address */
-	w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
-	w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
+	w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
+	w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
 
 	/* Read VID only once */
-	if (w83627hf == data->type || w83637hf == data->type) {
-		int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
-		int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
+	if (type == w83627hf || type == w83637hf) {
+		int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+		int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
 		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
-	} else if (w83627thf == data->type) {
-		data->vid = w83627thf_read_gpio5(client);
-	} else if (w83687thf == data->type) {
-		data->vid = w83687thf_read_vid(client);
+	} else if (type == w83627thf) {
+		data->vid = w83627thf_read_gpio5(pdev);
+	} else if (type == w83687thf) {
+		data->vid = w83687thf_read_vid(pdev);
 	}
 
 	/* Read VRM & OVT Config only once */
-	if (w83627thf == data->type || w83637hf == data->type
-	 || w83687thf == data->type) {
+	if (type == w83627thf || type == w83637hf || type == w83687thf) {
 		data->vrm_ovt = 
-			w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
+			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
 	}
 
-	/* Convert VID to voltage based on VRM */
-	data->vrm = vid_which_vrm();
-
-	tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+	tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
 	for (i = 1; i <= 3; i++) {
 		if (!(tmp & BIT_SCFG1[i - 1])) {
 			data->sens[i - 1] = W83781D_DEFAULT_BETA;
 		} else {
 			if (w83627hf_read_value
-			    (client,
+			    (data,
 			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
 				data->sens[i - 1] = 1;
 			else
@@ -1441,38 +1400,37 @@ static void w83627hf_init_client(struct 
 
 	if(init) {
 		/* Enable temp2 */
-		tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG);
+		tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
 		if (tmp & 0x01) {
-			dev_warn(&client->dev, "Enabling temp2, readings "
+			dev_warn(&pdev->dev, "Enabling temp2, readings "
 				 "might not make sense\n");
-			w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG,
+			w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
 				tmp & 0xfe);
 		}
 
 		/* Enable temp3 */
 		if (type != w83697hf) {
-			tmp = w83627hf_read_value(client,
+			tmp = w83627hf_read_value(data,
 				W83781D_REG_TEMP3_CONFIG);
 			if (tmp & 0x01) {
-				dev_warn(&client->dev, "Enabling temp3, "
+				dev_warn(&pdev->dev, "Enabling temp3, "
 					 "readings might not make sense\n");
-				w83627hf_write_value(client,
+				w83627hf_write_value(data,
 					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
 			}
 		}
 	}
 
 	/* Start monitoring */
-	w83627hf_write_value(client, W83781D_REG_CONFIG,
-			    (w83627hf_read_value(client,
+	w83627hf_write_value(data, W83781D_REG_CONFIG,
+			    (w83627hf_read_value(data,
 						W83781D_REG_CONFIG) & 0xf7)
 			    | 0x01);
 }
 
 static struct w83627hf_data *w83627hf_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627hf_data *data = i2c_get_clientdata(client);
+	struct w83627hf_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -1486,23 +1444,23 @@ static struct w83627hf_data *w83627hf_up
 			    && (i == 5 || i == 6)))
 				continue;
 			data->in[i] =
-			    w83627hf_read_value(client, W83781D_REG_IN(i));
+			    w83627hf_read_value(data, W83781D_REG_IN(i));
 			data->in_min[i] =
-			    w83627hf_read_value(client,
+			    w83627hf_read_value(data,
 					       W83781D_REG_IN_MIN(i));
 			data->in_max[i] =
-			    w83627hf_read_value(client,
+			    w83627hf_read_value(data,
 					       W83781D_REG_IN_MAX(i));
 		}
 		for (i = 1; i <= 3; i++) {
 			data->fan[i - 1] =
-			    w83627hf_read_value(client, W83781D_REG_FAN(i));
+			    w83627hf_read_value(data, W83781D_REG_FAN(i));
 			data->fan_min[i - 1] =
-			    w83627hf_read_value(client,
+			    w83627hf_read_value(data,
 					       W83781D_REG_FAN_MIN(i));
 		}
 		for (i = 1; i <= 3; i++) {
-			u8 tmp = w83627hf_read_value(client,
+			u8 tmp = w83627hf_read_value(data,
 				W836X7HF_REG_PWM(data->type, i));
  			/* bits 0-3 are reserved  in 627THF */
  			if (data->type == w83627thf)
@@ -1513,47 +1471,47 @@ static struct w83627hf_data *w83627hf_up
 				break;
 		}
 
-		data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));
+		data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
 		data->temp_max =
-		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));
+		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
 		data->temp_max_hyst =
-		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));
+		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
 		data->temp_add[0] =
-		    w83627hf_read_value(client, W83781D_REG_TEMP(2));
+		    w83627hf_read_value(data, W83781D_REG_TEMP(2));
 		data->temp_max_add[0] =
-		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));
+		    w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
 		data->temp_max_hyst_add[0] =
-		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));
+		    w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
 		if (data->type != w83697hf) {
 			data->temp_add[1] =
-			  w83627hf_read_value(client, W83781D_REG_TEMP(3));
+			  w83627hf_read_value(data, W83781D_REG_TEMP(3));
 			data->temp_max_add[1] =
-			  w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));
+			  w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
 			data->temp_max_hyst_add[1] =
-			  w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));
+			  w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
 		}
 
-		i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
+		i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = (i >> 6) & 0x03;
 		if (data->type != w83697hf) {
-			data->fan_div[2] = (w83627hf_read_value(client,
+			data->fan_div[2] = (w83627hf_read_value(data,
 					       W83781D_REG_PIN) >> 6) & 0x03;
 		}
-		i = w83627hf_read_value(client, W83781D_REG_VBAT);
+		i = w83627hf_read_value(data, W83781D_REG_VBAT);
 		data->fan_div[0] |= (i >> 3) & 0x04;
 		data->fan_div[1] |= (i >> 4) & 0x04;
 		if (data->type != w83697hf)
 			data->fan_div[2] |= (i >> 5) & 0x04;
 		data->alarms =
-		    w83627hf_read_value(client, W83781D_REG_ALARM1) |
-		    (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
-		    (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
-		i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
+		    w83627hf_read_value(data, W83781D_REG_ALARM1) |
+		    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
+		    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
+		i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
 		data->beep_enable = i >> 7;
 		data->beep_mask = ((i & 0x7f) << 8) |
-		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
-		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
+		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
+		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
@@ -1563,19 +1521,87 @@ static struct w83627hf_data *w83627hf_up
 	return data;
 }
 
+static int __init w83627hf_device_add(unsigned short address,
+				      const struct w83627hf_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address + WINB_REGION_OFFSET,
+		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
+					  GFP_KERNEL);
+	if (!pdev->dev.platform_data) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+	memcpy(pdev->dev.platform_data, sio_data,
+	       sizeof(struct w83627hf_sio_data));
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __init sensors_w83627hf_init(void)
 {
-	if (w83627hf_find(0x2e, &address)
-	 && w83627hf_find(0x4e, &address)) {
+	int err;
+	unsigned short address;
+	struct w83627hf_sio_data sio_data;
+
+	if (w83627hf_find(0x2e, &address, &sio_data)
+	 && w83627hf_find(0x4e, &address, &sio_data))
 		return -ENODEV;
-	}
 
-	return i2c_isa_add_driver(&w83627hf_driver);
+	err = platform_driver_register(&w83627hf_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = w83627hf_device_add(address, &sio_data);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+exit_driver:
+	platform_driver_unregister(&w83627hf_driver);
+exit:
+	return err;
 }
 
 static void __exit sensors_w83627hf_exit(void)
 {
-	i2c_isa_del_driver(&w83627hf_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&w83627hf_driver);
 }
 
 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index a47da3e..f85b48f 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -2,8 +2,9 @@
     w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
                 monitoring
     Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>,
-    Philip Edelbrock <phil@netroedge.com>,
-    and Mark Studebaker <mdsxyz123@yahoo.com>
+                               Philip Edelbrock <phil@netroedge.com>,
+                               and Mark Studebaker <mdsxyz123@yahoo.com>
+    Copyright (c) 2007         Jean Delvare <khali@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
@@ -38,15 +39,20 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
+/* ISA device, if found */
+static struct platform_device *pdev;
+
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
 					0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
@@ -75,8 +81,8 @@ #define W83781D_EXTENT			8
 #define W83781D_ADDR_REG_OFFSET		5
 #define W83781D_DATA_REG_OFFSET		6
 
-/* The W83781D registers */
-/* The W83782D registers for nr=7,8 are in bank 5 */
+/* The device registers */
+/* in nr from 0 to 8 */
 #define W83781D_REG_IN_MAX(nr)		((nr < 7) ? (0x2b + (nr) * 2) : \
 						    (0x554 + (((nr) - 7) * 2)))
 #define W83781D_REG_IN_MIN(nr)		((nr < 7) ? (0x2c + (nr) * 2) : \
@@ -84,12 +90,14 @@ #define W83781D_REG_IN_MIN(nr)		((nr < 7
 #define W83781D_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
 						    (0x550 + (nr) - 7))
 
-#define W83781D_REG_FAN_MIN(nr)		(0x3a + (nr))
-#define W83781D_REG_FAN(nr)		(0x27 + (nr))
+/* fan nr from 0 to 2 */
+#define W83781D_REG_FAN_MIN(nr)		(0x3b + (nr))
+#define W83781D_REG_FAN(nr)		(0x28 + (nr))
 
 #define W83781D_REG_BANK		0x4E
 #define W83781D_REG_TEMP2_CONFIG	0x152
 #define W83781D_REG_TEMP3_CONFIG	0x252
+/* temp nr from 1 to 3 */
 #define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \
 					((nr == 2) ? (0x0150) : \
 						     (0x27)))
@@ -127,19 +135,9 @@ #define W83781D_REG_PIN			0x4B
 #define W83781D_REG_VBAT		0x5D
 
 /* PWM 782D (1-4) and 783S (1-2) only */
-#define W83781D_REG_PWM1		0x5B	/* 782d and 783s/627hf datasheets disagree */
-						/* on which is which; */
-#define W83781D_REG_PWM2		0x5A	/* We follow the 782d convention here, */
-						/* However 782d is probably wrong. */
-#define W83781D_REG_PWM3		0x5E
-#define W83781D_REG_PWM4		0x5F
+static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
 #define W83781D_REG_PWMCLK12		0x5C
 #define W83781D_REG_PWMCLK34		0x45C
-static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2,
-	W83781D_REG_PWM3, W83781D_REG_PWM4
-};
-
-#define W83781D_REG_PWM(nr)		(regpwm[(nr) - 1])
 
 #define W83781D_REG_I2C_ADDR		0x48
 #define W83781D_REG_I2C_SUBADDR		0x4A
@@ -159,12 +157,9 @@ #define W83781D_DEFAULT_BETA		3435
 #define W83781D_REG_RT_IDX		0x50
 #define W83781D_REG_RT_VAL		0x51
 
-/* Conversions. Rounding and limit checking is only done on the TO_REG
-   variants. Note that you should be a bit careful with which arguments
-   these macros are called: arguments may be evaluated more than once.
-   Fixing this is just not worth it. */
-#define IN_TO_REG(val)			(SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-#define IN_FROM_REG(val)		(((val) * 16) / 10)
+/* Conversions */
+#define IN_TO_REG(val)			SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
+#define IN_FROM_REG(val)		((val) * 16)
 
 static inline u8
 FAN_TO_REG(long rpm, int div)
@@ -175,24 +170,24 @@ FAN_TO_REG(long rpm, int div)
 	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
 }
 
-#define FAN_FROM_REG(val,div)		((val) == 0   ? -1 : \
-					((val) == 255 ? 0 : \
-							1350000 / ((val) * (div))))
+static inline long
+FAN_FROM_REG(u8 val, int div)
+{
+	if (val == 0)
+		return -1;
+	if (val == 255)
+		return 0;
+	return 1350000 / (val * div);
+}
 
-#define TEMP_TO_REG(val)		(SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
-						: (val)) / 1000, 0, 0xff))
-#define TEMP_FROM_REG(val)		(((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+#define TEMP_TO_REG(val)		SENSORS_LIMIT((val) / 1000, -127, 128)
+#define TEMP_FROM_REG(val)		((val) * 1000)
 
-#define PWM_FROM_REG(val)		(val)
-#define PWM_TO_REG(val)			(SENSORS_LIMIT((val),0,255))
 #define BEEP_MASK_FROM_REG(val,type)	((type) == as99127f ? \
 					 (val) ^ 0x7fff : (val))
 #define BEEP_MASK_TO_REG(val,type)	((type) == as99127f ? \
 					 (~(val)) & 0x7fff : (val) & 0xffffff)
 
-#define BEEP_ENABLE_TO_REG(val)		((val) ? 1 : 0)
-#define BEEP_ENABLE_FROM_REG(val)	((val) ? 1 : 0)
-
 #define DIV_FROM_REG(val)		(1 << (val))
 
 static inline u8
@@ -207,7 +202,7 @@ DIV_TO_REG(long val, enum chips type)
 			break;
 		val >>= 1;
 	}
-	return ((u8) i);
+	return i;
 }
 
 /* There are some complications in a module like this. First off, W83781D chips
@@ -221,8 +216,8 @@ DIV_TO_REG(long val, enum chips type)
    a bit - except if there could be more than one SMBus. Groan. No solution
    for this yet. */
 
-/* For each registered chip, we need to keep some data in memory.
-   The structure is dynamically allocated. */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+   the driver field to differentiate between I2C and ISA chips. */
 struct w83781d_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
@@ -241,9 +236,9 @@ struct w83781d_data {
 	u8 in_min[9];		/* Register value - 8 & 9 for 782D only */
 	u8 fan[3];		/* Register value */
 	u8 fan_min[3];		/* Register value */
-	u8 temp;
-	u8 temp_max;		/* Register value */
-	u8 temp_max_hyst;	/* Register value */
+	s8 temp;		/* Register value */
+	s8 temp_max;		/* Register value */
+	s8 temp_max_hyst;	/* Register value */
 	u16 temp_add[2];	/* Register value */
 	u16 temp_max_add[2];	/* Register value */
 	u16 temp_max_hyst_add[2];	/* Register value */
@@ -253,7 +248,7 @@ struct w83781d_data {
 	u32 beep_mask;		/* Register encoding, combined */
 	u8 beep_enable;		/* Boolean */
 	u8 pwm[4];		/* Register value */
-	u8 pwmenable[4];	/* Boolean */
+	u8 pwm2_enable;		/* Boolean */
 	u16 sens[3];		/* 782D/783S only.
 				   1 = pentium diode; 2 = 3904 diode;
 				   3000-5000 = thermistor beta.
@@ -263,14 +258,16 @@ struct w83781d_data {
 };
 
 static int w83781d_attach_adapter(struct i2c_adapter *adapter);
-static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
 static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
 static int w83781d_detach_client(struct i2c_client *client);
 
-static int w83781d_read_value(struct i2c_client *client, u16 reg);
-static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value);
+static int __devinit w83781d_isa_probe(struct platform_device *pdev);
+static int __devexit w83781d_isa_remove(struct platform_device *pdev);
+
+static int w83781d_read_value(struct w83781d_data *data, u16 reg);
+static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
 static struct w83781d_data *w83781d_update_device(struct device *dev);
-static void w83781d_init_client(struct i2c_client *client);
+static void w83781d_init_device(struct device *dev);
 
 static struct i2c_driver w83781d_driver = {
 	.driver = {
@@ -281,39 +278,44 @@ static struct i2c_driver w83781d_driver 
 	.detach_client = w83781d_detach_client,
 };
 
-static struct i2c_driver w83781d_isa_driver = {
+static struct platform_driver w83781d_isa_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
-		.name = "w83781d-isa",
+		.name = "w83781d",
 	},
-	.attach_adapter = w83781d_isa_attach_adapter,
-	.detach_client = w83781d_detach_client,
+	.probe = w83781d_isa_probe,
+	.remove = w83781d_isa_remove,
 };
 
 
 /* following are the sysfs callback functions */
 #define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+		char *buf) \
 { \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
 	struct w83781d_data *data = w83781d_update_device(dev); \
-	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \
+	return sprintf(buf, "%ld\n", \
+		       (long)IN_FROM_REG(data->reg[attr->index])); \
 }
 show_in_reg(in);
 show_in_reg(in_min);
 show_in_reg(in_max);
 
 #define store_in_reg(REG, reg) \
-static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
+		*da, const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = dev_get_drvdata(dev); \
+	int nr = attr->index; \
 	u32 val; \
 	 \
-	val = simple_strtoul(buf, NULL, 10) / 10; \
+	val = simple_strtoul(buf, NULL, 10); \
 	 \
 	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = IN_TO_REG(val); \
-	w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
+	w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
 	 \
 	mutex_unlock(&data->update_lock); \
 	return count; \
@@ -321,29 +323,13 @@ static ssize_t store_in_##reg (struct de
 store_in_reg(MIN, min);
 store_in_reg(MAX, max);
 
-#define sysfs_in_offset(offset) \
-static ssize_t \
-show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-        return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
-
-#define sysfs_in_reg_offset(reg, offset) \
-static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_in_##reg (dev, buf, offset); \
-} \
-static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-	return store_in_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
-
 #define sysfs_in_offsets(offset) \
-sysfs_in_offset(offset); \
-sysfs_in_reg_offset(min, offset); \
-sysfs_in_reg_offset(max, offset);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+		show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+		show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+		show_in_max, store_in_max, offset)
 
 sysfs_in_offsets(0);
 sysfs_in_offsets(1);
@@ -356,63 +342,56 @@ sysfs_in_offsets(7);
 sysfs_in_offsets(8);
 
 #define show_fan_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+		char *buf) \
 { \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
 	struct w83781d_data *data = w83781d_update_device(dev); \
 	return sprintf(buf,"%ld\n", \
-		FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+		FAN_FROM_REG(data->reg[attr->index], \
+			DIV_FROM_REG(data->fan_div[attr->index]))); \
 }
 show_fan_reg(fan);
 show_fan_reg(fan_min);
 
 static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
-	data->fan_min[nr - 1] =
-	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
-	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
-			    data->fan_min[nr - 1]);
+	data->fan_min[nr] =
+	    FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
+			    data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define sysfs_fan_offset(offset) \
-static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_fan(dev, buf, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
-
-#define sysfs_fan_min_offset(offset) \
-static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_fan_min(dev, buf, offset); \
-} \
-static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-	return store_fan_min(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
+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, store_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, store_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, store_fan_min, 2);
 
 #define show_temp_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+		char *buf) \
 { \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
 	struct w83781d_data *data = w83781d_update_device(dev); \
+	int nr = attr->index; \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		return sprintf(buf,"%d\n", \
 			LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
@@ -425,10 +404,12 @@ show_temp_reg(temp_max);
 show_temp_reg(temp_max_hyst);
 
 #define store_temp_reg(REG, reg) \
-static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+static ssize_t store_temp_##reg (struct device *dev, \
+		struct device_attribute *da, const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83781d_data *data = i2c_get_clientdata(client); \
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+	struct w83781d_data *data = dev_get_drvdata(dev); \
+	int nr = attr->index; \
 	s32 val; \
 	 \
 	val = simple_strtol(buf, NULL, 10); \
@@ -437,11 +418,11 @@ static ssize_t store_temp_##reg (struct 
 	 \
 	if (nr >= 2) {	/* TEMP2 and TEMP3 */ \
 		data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
-		w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
 				data->temp_##reg##_add[nr-2]); \
 	} else {	/* TEMP1 */ \
 		data->temp_##reg = TEMP_TO_REG(val); \
-		w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+		w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
 			data->temp_##reg); \
 	} \
 	 \
@@ -451,29 +432,13 @@ static ssize_t store_temp_##reg (struct 
 store_temp_reg(OVER, max);
 store_temp_reg(HYST, max_hyst);
 
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_temp(dev, buf, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
-
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_temp_##reg (dev, buf, offset); \
-} \
-static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-	return store_temp_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
-
 #define sysfs_temp_offsets(offset) \
-sysfs_temp_offset(offset); \
-sysfs_temp_reg_offset(max, offset); \
-sysfs_temp_reg_offset(max_hyst, offset);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+		show_temp, NULL, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+		show_temp_max, store_temp_max, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
+		show_temp_max_hyst, store_temp_max_hyst, offset);
 
 sysfs_temp_offsets(1);
 sysfs_temp_offsets(2);
@@ -498,8 +463,7 @@ show_vrm_reg(struct device *dev, struct 
 static ssize_t
 store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct w83781d_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -528,68 +492,67 @@ static ssize_t show_beep_mask (struct de
 static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct w83781d_data *data = w83781d_update_device(dev);
-	return sprintf(buf, "%ld\n",
-		       (long)BEEP_ENABLE_FROM_REG(data->beep_enable));
+	return sprintf(buf, "%ld\n", (long)data->beep_enable);
 }
 
-#define BEEP_ENABLE			0	/* Store beep_enable */
-#define BEEP_MASK			1	/* Store beep_mask */
-
 static ssize_t
-store_beep_reg(struct device *dev, const char *buf, size_t count,
-	       int update_mask)
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
-	u32 val, val2;
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
+	data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
+	w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
+			    data->beep_mask & 0xff);
+	w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
+			    ((data->beep_mask >> 8) & 0x7f)
+			    | data->beep_enable << 7);
+	if (data->type != w83781d && data->type != as99127f) {
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
+				    ((data->beep_mask) >> 16) & 0xff);
+	}
+	mutex_unlock(&data->update_lock);
 
-	if (update_mask == BEEP_MASK) {	/* We are storing beep_mask */
-		data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
-		w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
-				    data->beep_mask & 0xff);
-
-		if ((data->type != w83781d) && (data->type != as99127f)) {
-			w83781d_write_value(client, W83781D_REG_BEEP_INTS3,
-					    ((data->beep_mask) >> 16) & 0xff);
-		}
+	return count;
+}
 
-		val2 = (data->beep_mask >> 8) & 0x7f;
-	} else {		/* We are storing beep_enable */
-		val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
-		data->beep_enable = BEEP_ENABLE_TO_REG(val);
-	}
+static ssize_t
+store_beep_enable(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	u32 val;
 
-	w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
-			    val2 | data->beep_enable << 7);
+	val = simple_strtoul(buf, NULL, 10);
+	if (val != 0 && val != 1)
+		return -EINVAL;
 
+	mutex_lock(&data->update_lock);
+	data->beep_enable = val;
+	val = w83781d_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
+	val |= data->beep_enable << 7;
+	w83781d_write_value(data, W83781D_REG_BEEP_INTS2, val);
 	mutex_unlock(&data->update_lock);
+
 	return count;
 }
 
-#define sysfs_beep(REG, reg) \
-static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_beep_##reg(dev, attr, buf); \
-} \
-static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-	return store_beep_reg(dev, buf, count, BEEP_##REG); \
-} \
-static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
-
-sysfs_beep(ENABLE, enable);
-sysfs_beep(MASK, mask);
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+		show_beep_mask, store_beep_mask);
+static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+		show_beep_enable, store_beep_enable);
 
 static ssize_t
-show_fan_div_reg(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct w83781d_data *data = w83781d_update_device(dev);
 	return sprintf(buf, "%ld\n",
-		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+		       (long) DIV_FROM_REG(data->fan_div[attr->index]));
 }
 
 /* Note: we save and restore the fan minimum here, because its value is
@@ -597,11 +560,13 @@ show_fan_div_reg(struct device *dev, cha
    least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
 static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_div(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
 	unsigned long min;
+	int nr = attr->index;
 	u8 reg;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
@@ -613,77 +578,72 @@ store_fan_div_reg(struct device *dev, co
 
 	data->fan_div[nr] = DIV_TO_REG(val, data->type);
 
-	reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+	reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
 	       & (nr==0 ? 0xcf : 0x3f))
 	    | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
-	w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+	w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
 
 	/* w83781d and as99127f don't have extended divisor bits */
 	if (data->type != w83781d && data->type != as99127f) {
-		reg = (w83781d_read_value(client, W83781D_REG_VBAT)
+		reg = (w83781d_read_value(data, W83781D_REG_VBAT)
 		       & ~(1 << (5 + nr)))
 		    | ((data->fan_div[nr] & 0x04) << (3 + nr));
-		w83781d_write_value(client, W83781D_REG_VBAT, reg);
+		w83781d_write_value(data, W83781D_REG_VBAT, reg);
 	}
 
 	/* Restore fan_min */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-#define sysfs_fan_div(offset) \
-static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_fan_div_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-	return store_fan_div_reg(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
-
-sysfs_fan_div(1);
-sysfs_fan_div(2);
-sysfs_fan_div(3);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
+		show_fan_div, store_fan_div, 2);
 
 static ssize_t
-show_pwm_reg(struct device *dev, char *buf, int nr)
+show_pwm(struct device *dev, struct device_attribute *da, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct w83781d_data *data = w83781d_update_device(dev);
-	return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1]));
+	return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
 }
 
 static ssize_t
-show_pwmenable_reg(struct device *dev, char *buf, int nr)
+show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
 {
 	struct w83781d_data *data = w83781d_update_device(dev);
-	return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]);
+	return sprintf(buf, "%d\n", (int)data->pwm2_enable);
 }
 
 static ssize_t
-store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
+		size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
-	data->pwm[nr - 1] = PWM_TO_REG(val);
-	w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
+	data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+	w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 static ssize_t
-store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm2_enable(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct w83781d_data *data = dev_get_drvdata(dev);
 	u32 val, reg;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -693,15 +653,15 @@ store_pwmenable_reg(struct device *dev, 
 	switch (val) {
 	case 0:
 	case 1:
-		reg = w83781d_read_value(client, W83781D_REG_PWMCLK12);
-		w83781d_write_value(client, W83781D_REG_PWMCLK12,
+		reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
+		w83781d_write_value(data, W83781D_REG_PWMCLK12,
 				    (reg & 0xf7) | (val << 3));
 
-		reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
-		w83781d_write_value(client, W83781D_REG_BEEP_CONFIG,
+		reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
 				    (reg & 0xef) | (!val << 4));
 
-		data->pwmenable[nr - 1] = val;
+		data->pwm2_enable = val;
 		break;
 
 	default:
@@ -713,50 +673,29 @@ store_pwmenable_reg(struct device *dev, 
 	return count;
 }
 
-#define sysfs_pwm(offset) \
-static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_pwm_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \
-		const char *buf, size_t count) \
-{ \
-	return store_pwm_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
-		show_regs_pwm_##offset, store_regs_pwm_##offset);
-
-#define sysfs_pwmenable(offset) \
-static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-	return show_pwmenable_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \
-		const char *buf, size_t count) \
-{ \
-	return store_pwmenable_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
-		show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwmenable(2);		/* only PWM2 can be enabled/disabled */
-sysfs_pwm(3);
-sysfs_pwm(4);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
+/* only PWM2 can be enabled/disabled */
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+		show_pwm2_enable, store_pwm2_enable);
 
 static ssize_t
-show_sensor_reg(struct device *dev, char *buf, int nr)
+show_sensor(struct device *dev, struct device_attribute *da, char *buf)
 {
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct w83781d_data *data = w83781d_update_device(dev);
-	return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+	return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
 }
 
 static ssize_t
-store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_sensor(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
 	u32 val, tmp;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -765,28 +704,28 @@ store_sensor_reg(struct device *dev, con
 
 	switch (val) {
 	case 1:		/* PII/Celeron diode */
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
-		w83781d_write_value(client, W83781D_REG_SCFG1,
-				    tmp | BIT_SCFG1[nr - 1]);
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
-		w83781d_write_value(client, W83781D_REG_SCFG2,
-				    tmp | BIT_SCFG2[nr - 1]);
-		data->sens[nr - 1] = val;
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+		w83781d_write_value(data, W83781D_REG_SCFG2,
+				    tmp | BIT_SCFG2[nr]);
+		data->sens[nr] = val;
 		break;
 	case 2:		/* 3904 */
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
-		w83781d_write_value(client, W83781D_REG_SCFG1,
-				    tmp | BIT_SCFG1[nr - 1]);
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
-		w83781d_write_value(client, W83781D_REG_SCFG2,
-				    tmp & ~BIT_SCFG2[nr - 1]);
-		data->sens[nr - 1] = val;
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp | BIT_SCFG1[nr]);
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+		w83781d_write_value(data, W83781D_REG_SCFG2,
+				    tmp & ~BIT_SCFG2[nr]);
+		data->sens[nr] = val;
 		break;
 	case W83781D_DEFAULT_BETA:	/* thermistor */
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
-		w83781d_write_value(client, W83781D_REG_SCFG1,
-				    tmp & ~BIT_SCFG1[nr - 1]);
-		data->sens[nr - 1] = val;
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+		w83781d_write_value(data, W83781D_REG_SCFG1,
+				    tmp & ~BIT_SCFG1[nr]);
+		data->sens[nr] = val;
 		break;
 	default:
 		dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
@@ -798,20 +737,22 @@ store_sensor_reg(struct device *dev, con
 	return count;
 }
 
-#define sysfs_sensor(offset) \
-static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
-    return show_sensor_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
-    return store_sensor_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 0);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
+	show_sensor, store_sensor, 0);
 
-sysfs_sensor(1);
-sysfs_sensor(2);
-sysfs_sensor(3);
+/* I2C devices get this name attribute automatically, but for ISA devices
+   we must create it by ourselves. */
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->client.name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 /* This function is called when:
      * w83781d_driver is inserted (when this module is loaded), for each
@@ -825,12 +766,6 @@ w83781d_attach_adapter(struct i2c_adapte
 	return i2c_probe(adapter, &addr_data, w83781d_detect);
 }
 
-static int
-w83781d_isa_attach_adapter(struct i2c_adapter *adapter)
-{
-	return w83781d_detect(adapter, isa_address, -1);
-}
-
 /* Assumes that adapter is of I2C, not ISA variety.
  * OTHERWISE DON'T CALL THIS
  */
@@ -862,12 +797,12 @@ w83781d_detect_subclients(struct i2c_ada
 				goto ERROR_SC_1;
 			}
 		}
-		w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR,
+		w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
 				(force_subclients[2] & 0x07) |
 				((force_subclients[3] & 0x07) << 4));
 		data->lm75[0]->addr = force_subclients[2];
 	} else {
-		val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR);
+		val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
 		data->lm75[0]->addr = 0x48 + (val1 & 0x07);
 	}
 
@@ -937,20 +872,20 @@ 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 IN_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_in##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_min.dev_attr.attr,		\
+	&sensor_dev_attr_in##X##_max.dev_attr.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 FAN_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_fan##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_min.dev_attr.attr,		\
+	&sensor_dev_attr_fan##X##_div.dev_attr.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
+#define TEMP_UNIT_ATTRS(X)					\
+	&sensor_dev_attr_temp##X##_input.dev_attr.attr,		\
+	&sensor_dev_attr_temp##X##_max.dev_attr.attr,		\
+	&sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
 
 static struct attribute* w83781d_attributes[] = {
 	IN_UNIT_ATTRS(0),
@@ -980,91 +915,115 @@ static struct attribute *w83781d_attribu
 	IN_UNIT_ATTRS(7),
 	IN_UNIT_ATTRS(8),
 	TEMP_UNIT_ATTRS(3),
-	&dev_attr_pwm1.attr,
-	&dev_attr_pwm2.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm4.dev_attr.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,
+	&sensor_dev_attr_temp1_type.dev_attr.attr,
+	&sensor_dev_attr_temp2_type.dev_attr.attr,
+	&sensor_dev_attr_temp3_type.dev_attr.attr,
 	NULL
 };
 static const struct attribute_group w83781d_group_opt = {
 	.attrs = w83781d_attributes_opt,
 };
 
+/* No clean up is done on error, it's up to the caller */
 static int
-w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
+w83781d_create_files(struct device *dev, int kind, int is_isa)
 {
-	int i = 0, val1 = 0, val2;
-	struct i2c_client *client;
-	struct device *dev;
-	struct w83781d_data *data;
 	int err;
-	const char *client_name = "";
-	int is_isa = i2c_is_isa_adapter(adapter);
-	enum vendor { winbond, asus } vendid;
 
-	if (!is_isa
-	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-		err = -EINVAL;
-		goto ERROR0;
+	if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
+		return err;
+
+	if (kind != w83783s) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_in1_input.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_min.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in1_max.dev_attr)))
+			return err;
+	}
+	if (kind != as99127f && kind != w83781d && kind != w83783s) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_in7_input.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in7_min.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in7_max.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in8_input.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in8_min.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_in8_max.dev_attr)))
+			return err;
+	}
+	if (kind != w83783s) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_temp3_input.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_max.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_temp3_max_hyst.dev_attr)))
+			return err;
 	}
 
-	/* Prevent users from forcing a kind for a bus it isn't supposed
-	   to possibly be on */
-	if (is_isa && (kind == as99127f || kind == w83783s)) {
-		dev_err(&adapter->dev,
-			"Cannot force I2C-only chip for ISA address 0x%02x.\n",
-			address);
-		err = -EINVAL;
-		goto ERROR0;
+	if (kind != w83781d && kind != as99127f) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm1.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm2.dev_attr))
+		    || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
+			return err;
 	}
-	
-	if (is_isa)
-		if (!request_region(address, W83781D_EXTENT,
-				    w83781d_isa_driver.driver.name)) {
-			dev_dbg(&adapter->dev, "Request of region "
-				"0x%x-0x%x for w83781d failed\n", address,
-				address + W83781D_EXTENT - 1);
-			err = -EBUSY;
-			goto ERROR0;
+	if (kind == w83782d && !is_isa) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_pwm3.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_pwm4.dev_attr)))
+			return err;
+	}
+
+	if (kind != as99127f && kind != w83781d) {
+		if ((err = device_create_file(dev,
+				&sensor_dev_attr_temp1_type.dev_attr))
+		    || (err = device_create_file(dev,
+				&sensor_dev_attr_temp2_type.dev_attr)))
+			return err;
+		if (kind != w83783s) {
+			if ((err = device_create_file(dev,
+					&sensor_dev_attr_temp3_type.dev_attr)))
+				return err;
 		}
+	}
 
-	/* Probe whether there is anything available on this address. Already
-	   done for SMBus clients */
-	if (kind < 0) {
-		if (is_isa) {
+	if (is_isa) {
+		err = device_create_file(&pdev->dev, &dev_attr_name);
+		if (err)
+			return err;
+	}
 
-#define REALLY_SLOW_IO
-			/* We need the timeouts for at least some LM78-like
-			   chips. But only if we read 'undefined' registers. */
-			i = inb_p(address + 1);
-			if (inb_p(address + 2) != i
-			 || inb_p(address + 3) != i
-			 || inb_p(address + 7) != i) {
-				dev_dbg(&adapter->dev, "Detection of w83781d "
-					"chip failed at step 1\n");
-				err = -ENODEV;
-				goto ERROR1;
-			}
-#undef REALLY_SLOW_IO
+	return 0;
+}
 
-			/* Let's just hope nothing breaks here */
-			i = inb_p(address + 5) & 0x7f;
-			outb_p(~i & 0x7f, address + 5);
-			val2 = inb_p(address + 5) & 0x7f;
-			if (val2 != (~i & 0x7f)) {
-				outb_p(i, address + 5);
-				dev_dbg(&adapter->dev, "Detection of w83781d "
-					"chip failed at step 2 (0x%x != "
-					"0x%x at 0x%x)\n", val2, ~i & 0x7f,
-					address + 5);
-				err = -ENODEV;
-				goto ERROR1;
-			}
-		}
+static int
+w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	int val1 = 0, val2;
+	struct i2c_client *client;
+	struct device *dev;
+	struct w83781d_data *data;
+	int err;
+	const char *client_name = "";
+	enum vendor { winbond, asus } vendid;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		err = -EINVAL;
+		goto ERROR1;
 	}
 
 	/* OK. For now, we presume we have a valid client. We now create the
@@ -1081,8 +1040,7 @@ #undef REALLY_SLOW_IO
 	client->addr = address;
 	mutex_init(&data->lock);
 	client->adapter = adapter;
-	client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
-	client->flags = 0;
+	client->driver = &w83781d_driver;
 	dev = &client->dev;
 
 	/* Now, we do the remaining detection. */
@@ -1092,14 +1050,14 @@ #undef REALLY_SLOW_IO
 	   force_*=... parameter, and the Winbond will be reset to the right
 	   bank. */
 	if (kind < 0) {
-		if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
+		if (w83781d_read_value(data, 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(client, W83781D_REG_BANK);
-		val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+		val1 = w83781d_read_value(data, W83781D_REG_BANK);
+		val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
 		/* Check for Winbond or Asus ID if in bank 0 */
 		if ((!(val1 & 0x07)) &&
 		    (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
@@ -1111,10 +1069,10 @@ #undef REALLY_SLOW_IO
 		}
 		/* If Winbond SMBus, check address at 0x48.
 		   Asus doesn't support, except for as99127f rev.2 */
-		if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
-				  ((val1 & 0x80) && (val2 == 0x5c)))) {
+		if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
+		    ((val1 & 0x80) && (val2 == 0x5c))) {
 			if (w83781d_read_value
-			    (client, W83781D_REG_I2C_ADDR) != address) {
+			    (data, W83781D_REG_I2C_ADDR) != address) {
 				dev_dbg(&adapter->dev, "Detection of w83781d "
 					"chip failed at step 5\n");
 				err = -ENODEV;
@@ -1125,14 +1083,14 @@ #undef REALLY_SLOW_IO
 
 	/* 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(client, W83781D_REG_BANK,
-			    (w83781d_read_value(client, W83781D_REG_BANK)
+	w83781d_write_value(data, W83781D_REG_BANK,
+			    (w83781d_read_value(data, W83781D_REG_BANK)
 			     & 0x78) | 0x80);
 
 	/* Determine the chip type. */
 	if (kind <= 0) {
 		/* get vendor ID */
-		val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+		val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
 		if (val2 == 0x5c)
 			vendid = winbond;
 		else if (val2 == 0x12)
@@ -1144,17 +1102,16 @@ #undef REALLY_SLOW_IO
 			goto ERROR2;
 		}
 
-		val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
+		val1 = w83781d_read_value(data, W83781D_REG_WCHIPID);
 		if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
 			kind = w83781d;
 		else if (val1 == 0x30 && vendid == winbond)
 			kind = w83782d;
-		else if (val1 == 0x40 && vendid == winbond && !is_isa
-				&& address == 0x2d)
+		else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
 			kind = w83783s;
 		else if (val1 == 0x21 && vendid == winbond)
 			kind = w83627hf;
-		else if (val1 == 0x31 && !is_isa && address >= 0x28)
+		else if (val1 == 0x31 && address >= 0x28)
 			kind = as99127f;
 		else {
 			if (kind == 0)
@@ -1182,86 +1139,23 @@ #undef REALLY_SLOW_IO
 	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(client)))
 		goto ERROR2;
 
 	/* attach secondary i2c lm75-like clients */
-	if (!is_isa) {
-		if ((err = w83781d_detect_subclients(adapter, address,
-				kind, client)))
-			goto ERROR3;
-	} else {
-		data->lm75[0] = NULL;
-		data->lm75[1] = NULL;
-	}
+	if ((err = w83781d_detect_subclients(adapter, address,
+			kind, client)))
+		goto ERROR3;
 
 	/* Initialize the chip */
-	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(client,
-					W83781D_REG_FAN_MIN(i));
-	}
-	if (kind != w83781d && kind != as99127f)
-		for (i = 0; i < 4; i++)
-			data->pwmenable[i] = 1;
+	w83781d_init_device(dev);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
+	err = w83781d_create_files(dev, kind, 0);
+	if (err)
 		goto ERROR4;
 
-	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) {
-		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;
-	}
-
-	if (kind != w83781d && kind != as99127f) {
-		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) {
-		if ((err = device_create_file(dev, &dev_attr_pwm3))
-		    || (err = device_create_file(dev, &dev_attr_pwm4)))
-			goto ERROR4;
-	}
-
-	if (kind != as99127f && kind != w83781d) {
-		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);
@@ -1287,9 +1181,6 @@ ERROR3:
 ERROR2:
 	kfree(data);
 ERROR1:
-	if (is_isa)
-		release_region(address, W83781D_EXTENT);
-ERROR0:
 	return err;
 }
 
@@ -1305,8 +1196,6 @@ w83781d_detach_client(struct i2c_client 
 		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);
 
 	if ((err = i2c_detach_client(client)))
 		return err;
@@ -1322,6 +1211,88 @@ w83781d_detach_client(struct i2c_client 
 	return 0;
 }
 
+static int __devinit
+w83781d_isa_probe(struct platform_device *pdev)
+{
+	int err, reg;
+	struct w83781d_data *data;
+	struct resource *res;
+	const char *name;
+
+	/* Reserve the ISA region */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, W83781D_EXTENT, "w83781d")) {
+		err = -EBUSY;
+		goto exit;
+	}
+
+	if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit_release_region;
+	}
+	mutex_init(&data->lock);
+	data->client.addr = res->start;
+	i2c_set_clientdata(&data->client, data);
+	platform_set_drvdata(pdev, data);
+
+	reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
+	switch (reg) {
+	case 0x21:
+		data->type = w83627hf;
+		name = "w83627hf";
+		break;
+	case 0x30:
+		data->type = w83782d;
+		name = "w83782d";
+		break;
+	default:
+		data->type = w83781d;
+		name = "w83781d";
+	}
+	strlcpy(data->client.name, name, I2C_NAME_SIZE);
+
+	/* Initialize the W83781D chip */
+	w83781d_init_device(&pdev->dev);
+
+	/* Register sysfs hooks */
+	err = w83781d_create_files(&pdev->dev, data->type, 1);
+	if (err)
+		goto exit_remove_files;
+
+	data->class_dev = hwmon_device_register(&pdev->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(&pdev->dev.kobj, &w83781d_group);
+	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	kfree(data);
+ exit_release_region:
+	release_region(res->start, W83781D_EXTENT);
+ exit:
+	return err;
+}
+
+static int __devexit
+w83781d_isa_remove(struct platform_device *pdev)
+{
+	struct w83781d_data *data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
+	sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	release_region(data->client.addr, W83781D_EXTENT);
+	kfree(data);
+
+	return 0;
+}
+
 /* The SMBus locks itself, usually, but nothing may access the Winbond between
    bank switches. ISA access must always be locked explicitly! 
    We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
@@ -1329,14 +1300,14 @@ w83781d_detach_client(struct i2c_client 
    There are some ugly typecasts here, but the good news is - they should
    nowhere else be necessary! */
 static int
-w83781d_read_value(struct i2c_client *client, u16 reg)
+w83781d_read_value(struct w83781d_data *data, u16 reg)
 {
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct i2c_client *client = &data->client;
 	int res, word_sized, bank;
 	struct i2c_client *cl;
 
 	mutex_lock(&data->lock);
-	if (i2c_is_isa_client(client)) {
+	if (!client->driver) { /* ISA device */
 		word_sized = (((reg & 0xff00) == 0x100)
 			      || ((reg & 0xff00) == 0x200))
 		    && (((reg & 0x00ff) == 0x50)
@@ -1398,14 +1369,14 @@ w83781d_read_value(struct i2c_client *cl
 }
 
 static int
-w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
 {
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct i2c_client *client = &data->client;
 	int word_sized, bank;
 	struct i2c_client *cl;
 
 	mutex_lock(&data->lock);
-	if (i2c_is_isa_client(client)) {
+	if (!client->driver) { /* ISA device */
 		word_sized = (((reg & 0xff00) == 0x100)
 			      || ((reg & 0xff00) == 0x200))
 		    && (((reg & 0x00ff) == 0x53)
@@ -1462,13 +1433,18 @@ w83781d_write_value(struct i2c_client *c
 }
 
 static void
-w83781d_init_client(struct i2c_client *client)
+w83781d_init_device(struct device *dev)
 {
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct w83781d_data *data = dev_get_drvdata(dev);
 	int i, p;
 	int type = data->type;
 	u8 tmp;
 
+	if (type == w83627hf)
+		dev_info(dev, "The W83627HF chip is better supported by the "
+			 "w83627hf driver, support will be dropped from the "
+			 "w83781d driver soon\n");
+
 	if (reset && type != as99127f) { /* this resets registers we don't have
 					   documentation for on the as99127f */
 		/* Resetting the chip has been the default for a long time,
@@ -1477,42 +1453,42 @@ w83781d_init_client(struct i2c_client *c
 		   It might even go away if nobody reports it as being useful,
 		   as I see very little reason why this would be needed at
 		   all. */
-		dev_info(&client->dev, "If reset=1 solved a problem you were "
+		dev_info(dev, "If reset=1 solved a problem you were "
 			 "having, please report!\n");
 
 		/* save these registers */
-		i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
-		p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
+		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
 		/* Reset all except Watchdog values and last conversion values
 		   This sets fan-divs to 2, among others */
-		w83781d_write_value(client, W83781D_REG_CONFIG, 0x80);
+		w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
 		/* Restore the registers and disable power-on abnormal beep.
 		   This saves FAN 1/2/3 input/output values set by BIOS. */
-		w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
-		w83781d_write_value(client, W83781D_REG_PWMCLK12, p);
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
+		w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
 		/* Disable master beep-enable (reset turns it on).
 		   Individual beep_mask should be reset to off but for some reason
 		   disabling this bit helps some people not get beeped */
-		w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
+		w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
 	}
 
 	/* Disable power-on abnormal beep, as advised by the datasheet.
 	   Already done if reset=1. */
 	if (init && !reset && type != as99127f) {
-		i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
-		w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+		i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+		w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
 	}
 
 	data->vrm = vid_which_vrm();
 
 	if ((type != w83781d) && (type != as99127f)) {
-		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
+		tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
 		for (i = 1; i <= 3; i++) {
 			if (!(tmp & BIT_SCFG1[i - 1])) {
 				data->sens[i - 1] = W83781D_DEFAULT_BETA;
 			} else {
 				if (w83781d_read_value
-				    (client,
+				    (data,
 				     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
 					data->sens[i - 1] = 1;
 				else
@@ -1525,38 +1501,46 @@ w83781d_init_client(struct i2c_client *c
 
 	if (init && type != as99127f) {
 		/* Enable temp2 */
-		tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG);
+		tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
 		if (tmp & 0x01) {
-			dev_warn(&client->dev, "Enabling temp2, readings "
+			dev_warn(dev, "Enabling temp2, readings "
 				 "might not make sense\n");
-			w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG,
+			w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
 				tmp & 0xfe);
 		}
 
 		/* Enable temp3 */
 		if (type != w83783s) {
-			tmp = w83781d_read_value(client,
+			tmp = w83781d_read_value(data,
 				W83781D_REG_TEMP3_CONFIG);
 			if (tmp & 0x01) {
-				dev_warn(&client->dev, "Enabling temp3, "
+				dev_warn(dev, "Enabling temp3, "
 					 "readings might not make sense\n");
-				w83781d_write_value(client,
+				w83781d_write_value(data,
 					W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
 			}
 		}
 	}
 
 	/* Start monitoring */
-	w83781d_write_value(client, W83781D_REG_CONFIG,
-			    (w83781d_read_value(client,
+	w83781d_write_value(data, W83781D_REG_CONFIG,
+			    (w83781d_read_value(data,
 						W83781D_REG_CONFIG) & 0xf7)
 			    | 0x01);
+
+	/* A few vars need to be filled upon startup */
+	for (i = 0; i < 3; i++) {
+		data->fan_min[i] = w83781d_read_value(data,
+					W83781D_REG_FAN_MIN(i));
+	}
+
+	mutex_init(&data->update_lock);
 }
 
 static struct w83781d_data *w83781d_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83781d_data *data = i2c_get_clientdata(client);
+	struct w83781d_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = &data->client;
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -1569,98 +1553,97 @@ static struct w83781d_data *w83781d_upda
 			if (data->type == w83783s && i == 1)
 				continue;	/* 783S has no in1 */
 			data->in[i] =
-			    w83781d_read_value(client, W83781D_REG_IN(i));
+			    w83781d_read_value(data, W83781D_REG_IN(i));
 			data->in_min[i] =
-			    w83781d_read_value(client, W83781D_REG_IN_MIN(i));
+			    w83781d_read_value(data, W83781D_REG_IN_MIN(i));
 			data->in_max[i] =
-			    w83781d_read_value(client, W83781D_REG_IN_MAX(i));
+			    w83781d_read_value(data, W83781D_REG_IN_MAX(i));
 			if ((data->type != w83782d)
 			    && (data->type != w83627hf) && (i == 6))
 				break;
 		}
-		for (i = 1; i <= 3; i++) {
-			data->fan[i - 1] =
-			    w83781d_read_value(client, W83781D_REG_FAN(i));
-			data->fan_min[i - 1] =
-			    w83781d_read_value(client, W83781D_REG_FAN_MIN(i));
+		for (i = 0; i < 3; i++) {
+			data->fan[i] =
+			    w83781d_read_value(data, W83781D_REG_FAN(i));
+			data->fan_min[i] =
+			    w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
 		}
 		if (data->type != w83781d && data->type != as99127f) {
-			for (i = 1; i <= 4; i++) {
-				data->pwm[i - 1] =
-				    w83781d_read_value(client,
-						       W83781D_REG_PWM(i));
-				if ((data->type != w83782d
-				     || i2c_is_isa_client(client))
-				    && i == 2)
+			for (i = 0; i < 4; i++) {
+				data->pwm[i] =
+				    w83781d_read_value(data,
+						       W83781D_REG_PWM[i]);
+				if ((data->type != w83782d || !client->driver)
+				    && i == 1)
 					break;
 			}
 			/* Only PWM2 can be disabled */
-			data->pwmenable[1] = (w83781d_read_value(client,
+			data->pwm2_enable = (w83781d_read_value(data,
 					      W83781D_REG_PWMCLK12) & 0x08) >> 3;
 		}
 
-		data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));
+		data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
 		data->temp_max =
-		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
+		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
 		data->temp_max_hyst =
-		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));
+		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
 		data->temp_add[0] =
-		    w83781d_read_value(client, W83781D_REG_TEMP(2));
+		    w83781d_read_value(data, W83781D_REG_TEMP(2));
 		data->temp_max_add[0] =
-		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
+		    w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
 		data->temp_max_hyst_add[0] =
-		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
+		    w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
 		if (data->type != w83783s) {
 			data->temp_add[1] =
-			    w83781d_read_value(client, W83781D_REG_TEMP(3));
+			    w83781d_read_value(data, W83781D_REG_TEMP(3));
 			data->temp_max_add[1] =
-			    w83781d_read_value(client,
+			    w83781d_read_value(data,
 					       W83781D_REG_TEMP_OVER(3));
 			data->temp_max_hyst_add[1] =
-			    w83781d_read_value(client,
+			    w83781d_read_value(data,
 					       W83781D_REG_TEMP_HYST(3));
 		}
-		i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
+		i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
 		data->vid = i & 0x0f;
-		data->vid |= (w83781d_read_value(client,
+		data->vid |= (w83781d_read_value(data,
 					W83781D_REG_CHIPID) & 0x01) << 4;
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = (i >> 6) & 0x03;
-		data->fan_div[2] = (w83781d_read_value(client,
+		data->fan_div[2] = (w83781d_read_value(data,
 					W83781D_REG_PIN) >> 6) & 0x03;
 		if ((data->type != w83781d) && (data->type != as99127f)) {
-			i = w83781d_read_value(client, W83781D_REG_VBAT);
+			i = w83781d_read_value(data, W83781D_REG_VBAT);
 			data->fan_div[0] |= (i >> 3) & 0x04;
 			data->fan_div[1] |= (i >> 4) & 0x04;
 			data->fan_div[2] |= (i >> 5) & 0x04;
 		}
 		if ((data->type == w83782d) || (data->type == w83627hf)) {
-			data->alarms = w83781d_read_value(client,
+			data->alarms = w83781d_read_value(data,
 						W83782D_REG_ALARM1)
-				     | (w83781d_read_value(client,
+				     | (w83781d_read_value(data,
 						W83782D_REG_ALARM2) << 8)
-				     | (w83781d_read_value(client,
+				     | (w83781d_read_value(data,
 						W83782D_REG_ALARM3) << 16);
 		} else if (data->type == w83783s) {
-			data->alarms = w83781d_read_value(client,
+			data->alarms = w83781d_read_value(data,
 						W83782D_REG_ALARM1)
-				     | (w83781d_read_value(client,
+				     | (w83781d_read_value(data,
 						W83782D_REG_ALARM2) << 8);
 		} else {
 			/* No real-time status registers, fall back to
 			   interrupt status registers */
-			data->alarms = w83781d_read_value(client,
+			data->alarms = w83781d_read_value(data,
 						W83781D_REG_ALARM1)
-				     | (w83781d_read_value(client,
+				     | (w83781d_read_value(data,
 						W83781D_REG_ALARM2) << 8);
 		}
-		i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
+		i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
 		data->beep_enable = i >> 7;
 		data->beep_mask = ((i & 0x7f) << 8) +
-		    w83781d_read_value(client, W83781D_REG_BEEP_INTS1);
+		    w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
 		if ((data->type != w83781d) && (data->type != as99127f)) {
 			data->beep_mask |=
-			    w83781d_read_value(client,
+			    w83781d_read_value(data,
 					       W83781D_REG_BEEP_INTS3) << 16;
 		}
 		data->last_updated = jiffies;
@@ -1672,6 +1655,133 @@ static struct w83781d_data *w83781d_upda
 	return data;
 }
 
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init
+w83781d_isa_found(unsigned short address)
+{
+	int val, save, found = 0;
+
+	if (!request_region(address, W83781D_EXTENT, "w83781d"))
+		return 0;
+
+#define REALLY_SLOW_IO
+	/* We need the timeouts for at least some W83781D-like
+	   chips. But only if we read 'undefined' registers. */
+	val = inb_p(address + 1);
+	if (inb_p(address + 2) != val
+	 || inb_p(address + 3) != val
+	 || inb_p(address + 7) != val) {
+		pr_debug("w83781d: Detection failed at step 1\n");
+		goto release;
+	}
+#undef REALLY_SLOW_IO
+
+	/* We should be able to change the 7 LSB of the address port. The
+	   MSB (busy flag) should be clear initially, set after the write. */
+	save = inb_p(address + W83781D_ADDR_REG_OFFSET);
+	if (save & 0x80) {
+		pr_debug("w83781d: Detection failed at step 2\n");
+		goto release;
+	}
+	val = ~save & 0x7f;
+	outb_p(val, address + W83781D_ADDR_REG_OFFSET);
+	if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
+		outb_p(save, address + W83781D_ADDR_REG_OFFSET);
+		pr_debug("w83781d: Detection failed at step 3\n");
+		goto release;
+	}
+
+	/* We found a device, now see if it could be a W83781D */
+	outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if (val & 0x80) {
+		pr_debug("w83781d: Detection failed at step 4\n");
+		goto release;
+	}
+	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+	save = inb_p(address + W83781D_DATA_REG_OFFSET);
+	outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if ((!(save & 0x80) && (val != 0xa3))
+	 || ((save & 0x80) && (val != 0x5c))) {
+		pr_debug("w83781d: Detection failed at step 5\n");
+		goto release;
+	}
+	outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if (val < 0x03 || val > 0x77) {	/* Not a valid I2C address */
+		pr_debug("w83781d: Detection failed at step 6\n");
+		goto release;
+	}
+
+	/* The busy flag should be clear again */
+	if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
+		pr_debug("w83781d: Detection failed at step 7\n");
+		goto release;
+	}
+
+	/* Determine the chip type */
+	outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+	save = inb_p(address + W83781D_DATA_REG_OFFSET);
+	outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
+	outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
+	val = inb_p(address + W83781D_DATA_REG_OFFSET);
+	if ((val & 0xfe) == 0x10	/* W83781D */
+	 || val == 0x30			/* W83782D */
+	 || val == 0x21)		/* W83627HF */
+		found = 1;
+
+	if (found)
+		pr_info("w83781d: Found a %s chip at %#x\n",
+			val == 0x21 ? "W83627HF" :
+			val == 0x30 ? "W83782D" : "W83781D", (int)address);
+
+ release:
+	release_region(address, W83781D_EXTENT);
+	return found;
+}
+
+static int __init
+w83781d_isa_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + W83781D_EXTENT,
+		.name	= "w83781d",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("w83781d", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "w83781d: Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR "w83781d: Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+ exit_device_put:
+	platform_device_put(pdev);
+ exit:
+	pdev = NULL;
+	return err;
+}
+
 static int __init
 sensors_w83781d_init(void)
 {
@@ -1679,21 +1789,36 @@ sensors_w83781d_init(void)
 
 	res = i2c_add_driver(&w83781d_driver);
 	if (res)
-		return res;
+		goto exit;
+
+	if (w83781d_isa_found(isa_address)) {
+		res = platform_driver_register(&w83781d_isa_driver);
+		if (res)
+			goto exit_unreg_i2c_driver;
 
-	/* 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;
+		/* Sets global pdev as a side effect */
+		res = w83781d_isa_device_add(isa_address);
+		if (res)
+			goto exit_unreg_isa_driver;
+	}
 
 	return 0;
+
+ exit_unreg_isa_driver:
+	platform_driver_unregister(&w83781d_isa_driver);
+ exit_unreg_i2c_driver:
+	i2c_del_driver(&w83781d_driver);
+ exit:
+	return res;
 }
 
 static void __exit
 sensors_w83781d_exit(void)
 {
-	if (isa_address)
-		i2c_isa_del_driver(&w83781d_isa_driver);
+	if (pdev) {
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&w83781d_isa_driver);
+	}
 	i2c_del_driver(&w83781d_driver);
 }
 
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 11935f6..434a61b 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,9 +2,7 @@ #
 # I2C subsystem configuration
 #
 
-menu "I2C support"
-
-config I2C
+menuconfig I2C
 	tristate "I2C support"
 	---help---
 	  I2C (pronounce: I-square-C) is a slow serial bus protocol used in
@@ -22,9 +20,14 @@ config I2C
 	  This I2C support can also be built as a module.  If so, the module
 	  will be called i2c-core.
 
+if I2C
+
+config I2C_BOARDINFO
+	boolean
+	default y
+
 config I2C_CHARDEV
 	tristate "I2C device interface"
-	depends on I2C
 	help
 	  Say Y here to use i2c-* device files, usually found in the /dev
 	  directory on your system.  They make it possible to have user-space
@@ -40,7 +43,6 @@ source drivers/i2c/chips/Kconfig
 
 config I2C_DEBUG_CORE
 	bool "I2C Core debugging messages"
-	depends on I2C
 	help
 	  Say Y here if you want the I2C core to produce a bunch of debug
 	  messages to the system log.  Select this if you are having a
@@ -48,7 +50,6 @@ config I2C_DEBUG_CORE
 
 config I2C_DEBUG_ALGO
 	bool "I2C Algorithm debugging messages"
-	depends on I2C
 	help
 	  Say Y here if you want the I2C algorithm drivers to produce a bunch
 	  of debug messages to the system log.  Select this if you are having
@@ -57,7 +58,6 @@ config I2C_DEBUG_ALGO
 
 config I2C_DEBUG_BUS
 	bool "I2C Bus debugging messages"
-	depends on I2C
 	help
 	  Say Y here if you want the I2C bus drivers to produce a bunch of
 	  debug messages to the system log.  Select this if you are having
@@ -66,12 +66,10 @@ config I2C_DEBUG_BUS
 
 config I2C_DEBUG_CHIP
 	bool "I2C Chip debugging messages"
-	depends on I2C
 	help
 	  Say Y here if you want the I2C chip drivers to produce a bunch of
 	  debug messages to the system log.  Select this if you are having
 	  a problem with I2C support and want to see more of what is going
 	  on.
 
-endmenu
-
+endif # I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 71c5a85..ba26e6c 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -2,6 +2,7 @@ #
 # Makefile for the i2c core.
 #
 
+obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
 obj-$(CONFIG_I2C)		+= i2c-core.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 obj-y				+= busses/ chips/ algos/
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index af02034..5889907 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -3,11 +3,9 @@ # Character device configuration
 #
 
 menu "I2C Algorithms"
-	depends on I2C
 
 config I2C_ALGOBIT
 	tristate "I2C bit-banging interfaces"
-	depends on I2C
 	help
 	  This allows you to use a range of I2C adapters called bit-banging
 	  adapters.  Say Y if you own an I2C adapter belonging to this class
@@ -18,7 +16,6 @@ config I2C_ALGOBIT
 
 config I2C_ALGOPCF
 	tristate "I2C PCF 8584 interfaces"
-	depends on I2C
 	help
 	  This allows you to use a range of I2C adapters called PCF adapters.
 	  Say Y if you own an I2C adapter belonging to this class and then say
@@ -29,7 +26,6 @@ config I2C_ALGOPCF
 
 config I2C_ALGOPCA
 	tristate "I2C PCA 9564 interfaces"
-	depends on I2C
 	help
 	  This allows you to use a range of I2C adapters called PCA adapters.
 	  Say Y if you own an I2C adapter belonging to this class and then say
@@ -40,11 +36,11 @@ config I2C_ALGOPCA
 
 config I2C_ALGO8XX
 	tristate "MPC8xx CPM I2C interface"
-	depends on 8xx && I2C
+	depends on 8xx
 
 config I2C_ALGO_SGI
 	tristate "I2C SGI interfaces"
-	depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
+	depends on SGI_IP22 || SGI_IP32 || X86_VISWS
 	help
 	  Supports the SGI interfaces like the ones found on SGI Indy VINO
 	  or SGI O2 MACE.
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 95aa539..8a5f582 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -33,19 +33,30 @@ #include <linux/i2c-algo-bit.h>
 
 
 /* ----- global defines ----------------------------------------------- */
-#define DEB(x) if (i2c_debug>=1) x;
-#define DEB2(x) if (i2c_debug>=2) x;
-#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
-#define DEBPROTO(x) if (i2c_debug>=9) { x; }
- 	/* debug the protocol by showing transferred bits */
 
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+	do { \
+		if (i2c_debug >= level) \
+			dev_dbg(dev, format, ##args); \
+	} while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+	do {} while (0)
+#endif /* DEBUG */
 
 /* ----- global variables ---------------------------------------------	*/
 
-/* module parameters:
- */
-static int i2c_debug;
 static int bit_test;	/* see if the line-setting functions work	*/
+module_param(bit_test, bool, 0);
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+		 "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
+#endif
 
 /* --- setting states on the bus with the right timing: ---------------	*/
 
@@ -57,19 +68,19 @@ #define getscl(adap) adap->getscl(adap->
 static inline void sdalo(struct i2c_algo_bit_data *adap)
 {
 	setsda(adap,0);
-	udelay(adap->udelay);
+	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void sdahi(struct i2c_algo_bit_data *adap)
 {
 	setsda(adap,1);
-	udelay(adap->udelay);
+	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void scllo(struct i2c_algo_bit_data *adap)
 {
 	setscl(adap,0);
-	udelay(adap->udelay);
+	udelay(adap->udelay / 2);
 }
 
 /*
@@ -98,7 +109,11 @@ static int sclhi(struct i2c_algo_bit_dat
 		}
 		cond_resched();
 	}
-	DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
+#ifdef DEBUG
+	if (jiffies != start && i2c_debug >= 3)
+		pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+			 "high\n", jiffies - start);
+#endif
 
 done:
 	udelay(adap->udelay);
@@ -110,30 +125,29 @@ done:
 static void i2c_start(struct i2c_algo_bit_data *adap) 
 {
 	/* assert: scl, sda are high */
-	DEBPROTO(printk("S "));
-	sdalo(adap);
+	setsda(adap, 0);
+	udelay(adap->udelay);
 	scllo(adap);
 }
 
 static void i2c_repstart(struct i2c_algo_bit_data *adap) 
 {
-	/* scl, sda may not be high */
-	DEBPROTO(printk(" Sr "));
-	setsda(adap,1);
+	/* assert: scl is low */
+	sdahi(adap);
 	sclhi(adap);
-	
-	sdalo(adap);
+	setsda(adap, 0);
+	udelay(adap->udelay);
 	scllo(adap);
 }
 
 
 static void i2c_stop(struct i2c_algo_bit_data *adap) 
 {
-	DEBPROTO(printk("P\n"));
 	/* assert: scl is low */
 	sdalo(adap);
 	sclhi(adap); 
-	sdahi(adap);
+	setsda(adap, 1);
+	udelay(adap->udelay);
 }
 
 
@@ -145,7 +159,7 @@ static void i2c_stop(struct i2c_algo_bit
  * 0 if the device did not ack
  * -ETIMEDOUT if an error occurred (while raising the scl line)
  */
-static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
 {
 	int i;
 	int sb;
@@ -154,34 +168,32 @@ static int i2c_outb(struct i2c_adapter *
 
 	/* assert: scl is low */
 	for ( i=7 ; i>=0 ; i-- ) {
-		sb = c & ( 1 << i );
+		sb = (c >> i) & 1;
 		setsda(adap,sb);
-		udelay(adap->udelay);
-		DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
+		udelay((adap->udelay + 1) / 2);
 		if (sclhi(adap)<0) { /* timed out */
-			sdahi(adap); /* we don't want to block the net */
-			DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
+			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+				"timeout at bit #%d\n", (int)c, i);
 			return -ETIMEDOUT;
 		};
 		/* do arbitration here: 
 		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
 		 */
-		setscl(adap, 0 );
-		udelay(adap->udelay);
+		scllo(adap);
 	}
 	sdahi(adap);
 	if (sclhi(adap)<0){ /* timeout */
-	    DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
-	    return -ETIMEDOUT;
+		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+			"timeout at ack\n", (int)c);
+		return -ETIMEDOUT;
 	};
 	/* read ack: SDA should be pulled down by slave */
-	ack=getsda(adap);	/* ack: sda is pulled low ->success.	 */
-	DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
+	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
+	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+		ack ? "A" : "NA");
 
-	DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
-	DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
 	scllo(adap);
-	return 0==ack;		/* return 1 if device acked	 */
+	return ack;
 	/* assert: scl is low (sda undef) */
 }
 
@@ -198,19 +210,18 @@ static int i2c_inb(struct i2c_adapter *i
 	sdahi(adap);
 	for (i=0;i<8;i++) {
 		if (sclhi(adap)<0) { /* timeout */
-			DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
+			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+				"#%d\n", 7 - i);
 			return -ETIMEDOUT;
 		};
 		indata *= 2;
 		if ( getsda(adap) ) 
 			indata |= 0x01;
-		scllo(adap);
+		setscl(adap, 0);
+		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
 	}
 	/* assert: scl is low */
-	DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
-
-	DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
-	return (int) (indata & 0xff);
+	return indata;
 }
 
 /*
@@ -221,73 +232,67 @@ static int test_bus(struct i2c_algo_bit_
 	int scl,sda;
 
 	if (adap->getscl==NULL)
-		printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
-			"SCL is not readable.\n");
+		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
 
 	sda=getsda(adap);
 	scl=(adap->getscl==NULL?1:getscl(adap));
-	printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
 	if (!scl || !sda ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
+		printk(KERN_WARNING "%s: bus seems to be busy\n", name);
 		goto bailout;
 	}
 
 	sdalo(adap);
 	sda=getsda(adap);
 	scl=(adap->getscl==NULL?1:getscl(adap));
-	printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
 	if ( 0 != sda ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
+		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
 		goto bailout;
 	}
 	if ( 0 == scl ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
-			"while pulling SDA low!\n");
+		printk(KERN_WARNING "%s: SCL unexpected low "
+		       "while pulling SDA low!\n", name);
 		goto bailout;
 	}		
 
 	sdahi(adap);
 	sda=getsda(adap);
 	scl=(adap->getscl==NULL?1:getscl(adap));
-	printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
 	if ( 0 == sda ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
+		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
 		goto bailout;
 	}
 	if ( 0 == scl ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
-			"while pulling SDA high!\n");
+		printk(KERN_WARNING "%s: SCL unexpected low "
+		       "while pulling SDA high!\n", name);
 		goto bailout;
 	}
 
 	scllo(adap);
 	sda=getsda(adap);
 	scl=(adap->getscl==NULL?0:getscl(adap));
-	printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
 	if ( 0 != scl ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
+		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
 		goto bailout;
 	}
 	if ( 0 == sda ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
-			"while pulling SCL low!\n");
+		printk(KERN_WARNING "%s: SDA unexpected low "
+		       "while pulling SCL low!\n", name);
 		goto bailout;
 	}
 	
 	sclhi(adap);
 	sda=getsda(adap);
 	scl=(adap->getscl==NULL?1:getscl(adap));
-	printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
 	if ( 0 == scl ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
+		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
 		goto bailout;
 	}
 	if ( 0 == sda ) {
-		printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
-			"while pulling SCL high!\n");
+		printk(KERN_WARNING "%s: SDA unexpected low "
+		       "while pulling SCL high!\n", name);
 		goto bailout;
 	}
-	printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
+	pr_info("%s: Test OK\n", name);
 	return 0;
 bailout:
 	sdahi(adap);
@@ -312,44 +317,39 @@ static int try_address(struct i2c_adapte
 	int i,ret = -1;
 	for (i=0;i<=retries;i++) {
 		ret = i2c_outb(i2c_adap,addr);
-		if (ret==1)
-			break;	/* success! */
-		i2c_stop(adap);
-		udelay(5/*adap->udelay*/);
-		if (i==retries)  /* no success */
+		if (ret == 1 || i == retries)
 			break;
-		i2c_start(adap);
+		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+		i2c_stop(adap);
 		udelay(adap->udelay);
+		yield();
+		bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+		i2c_start(adap);
 	}
-	DEB2(if (i)
-	     printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
-		    i+1, addr & 1 ? "read" : "write", addr>>1,
-		    ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
-	    );
+	if (i && ret)
+		bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+			"0x%02x: %s\n", i + 1,
+			addr & 1 ? "read from" : "write to", addr >> 1,
+			ret == 1 ? "success" : "failed, timeout?");
 	return ret;
 }
 
 static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
-	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	char c;
-	const char *temp = msg->buf;
+	const unsigned char *temp = msg->buf;
 	int count = msg->len;
 	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
 	int retval;
 	int wrcount=0;
 
 	while (count > 0) {
-		c = *temp;
-		DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff));
-		retval = i2c_outb(i2c_adap,c);
+		retval = i2c_outb(i2c_adap, *temp);
 		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
 			count--; 
 			temp++;
 			wrcount++;
 		} else { /* arbitration or no acknowledge */
 			dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
-			i2c_stop(adap);
 			return (retval<0)? retval : -EFAULT;
 			        /* got a better one ?? */
 		}
@@ -362,7 +362,7 @@ static int readbytes(struct i2c_adapter 
 	int inval;
 	int rdcount=0;   	/* counts bytes read */
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	char *temp = msg->buf;
+	unsigned char *temp = msg->buf;
 	int count = msg->len;
 
 	while (count > 0) {
@@ -371,30 +371,44 @@ static int readbytes(struct i2c_adapter 
 			*temp = inval;
 			rdcount++;
 		} else {   /* read timed out */
-			printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n");
 			break;
 		}
 
 		temp++;
 		count--;
 
-		if (msg->flags & I2C_M_NO_RD_ACK)
+		if (msg->flags & I2C_M_NO_RD_ACK) {
+			bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n",
+				inval);
 			continue;
-
-		if ( count > 0 ) {		/* send ack */
-			sdalo(adap);
-			DEBPROTO(printk(" Am "));
-		} else {
-			sdahi(adap);	/* neg. ack on last byte */
-			DEBPROTO(printk(" NAm "));
 		}
+
+		/* assert: sda is high */
+		if (count)		/* send ack */
+			setsda(adap, 0);
+		udelay((adap->udelay + 1) / 2);
+		bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval,
+			count ? "A" : "NA");
 		if (sclhi(adap)<0) {	/* timeout */
-			sdahi(adap);
-			printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
+			dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n");
 			return -ETIMEDOUT;
 		};
 		scllo(adap);
-		sdahi(adap);
+
+		/* Some SMBus transactions require that we receive the
+		   transaction length as the first read byte. */
+		if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) {
+			if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+				dev_err(&i2c_adap->dev, "readbytes: invalid "
+					"block length (%d)\n", inval);
+				return -EREMOTEIO;
+			}
+			/* The original count value accounts for the extra
+			   bytes, that is, either 1 for a regular transaction,
+			   or 2 for a PEC transaction. */
+			count += inval;
+			msg->len += inval;
+		}
 	}
 	return rdcount;
 }
@@ -421,27 +435,31 @@ static int bit_doAddress(struct i2c_adap
 	if ( (flags & I2C_M_TEN)  ) { 
 		/* a ten bit address */
 		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
-		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
 		/* try extended address code...*/
 		ret = try_address(i2c_adap, addr, retries);
 		if ((ret != 1) && !nak_ok)  {
-			printk(KERN_ERR "died at extended address code.\n");
+			dev_err(&i2c_adap->dev,
+				"died at extended address code\n");
 			return -EREMOTEIO;
 		}
 		/* the remaining 8 bit address */
 		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
 		if ((ret != 1) && !nak_ok) {
 			/* the chip did not ack / xmission error occurred */
-			printk(KERN_ERR "died at 2nd address code.\n");
+			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
 			return -EREMOTEIO;
 		}
 		if ( flags & I2C_M_RD ) {
+			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+				"start condition\n");
 			i2c_repstart(adap);
 			/* okay, now switch into reading mode */
 			addr |= 0x01;
 			ret = try_address(i2c_adap, addr, retries);
 			if ((ret!=1) && !nak_ok) {
-				printk(KERN_ERR "died at extended address code.\n");
+				dev_err(&i2c_adap->dev,
+					"died at repeated address code\n");
 				return -EREMOTEIO;
 			}
 		}
@@ -468,44 +486,62 @@ static int bit_xfer(struct i2c_adapter *
 	int i,ret;
 	unsigned short nak_ok;
 
+	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
 	i2c_start(adap);
 	for (i=0;i<num;i++) {
 		pmsg = &msgs[i];
 		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
 			if (i) {
+				bit_dbg(3, &i2c_adap->dev, "emitting "
+					"repeated start condition\n");
 				i2c_repstart(adap);
 			}
 			ret = bit_doAddress(i2c_adap, pmsg);
 			if ((ret != 0) && !nak_ok) {
-			    DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n"
-					,msgs[i].addr,i));
-			    return (ret<0) ? ret : -EREMOTEIO;
+				bit_dbg(1, &i2c_adap->dev, "NAK from "
+					"device addr 0x%02x msg #%d\n",
+					msgs[i].addr, i);
+				goto bailout;
 			}
 		}
 		if (pmsg->flags & I2C_M_RD ) {
 			/* read bytes into buffer*/
 			ret = readbytes(i2c_adap, pmsg);
-			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
-			if (ret < pmsg->len ) {
-				return (ret<0)? ret : -EREMOTEIO;
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EREMOTEIO;
+				goto bailout;
 			}
 		} else {
 			/* write bytes from buffer */
 			ret = sendbytes(i2c_adap, pmsg);
-			DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
-			if (ret < pmsg->len ) {
-				return (ret<0) ? ret : -EREMOTEIO;
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EREMOTEIO;
+				goto bailout;
 			}
 		}
 	}
+	ret = i;
+
+bailout:
+	bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
 	i2c_stop(adap);
-	return num;
+	return ret;
 }
 
 static u32 bit_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
 }
 
@@ -520,7 +556,7 @@ static const struct i2c_algorithm i2c_bi
 /* 
  * registering functions to load algorithms at runtime 
  */
-int i2c_bit_add_bus(struct i2c_adapter *adap)
+static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
 {
 	struct i2c_algo_bit_data *bit_adap = adap->algo_data;
 
@@ -530,25 +566,39 @@ int i2c_bit_add_bus(struct i2c_adapter *
 			return -ENODEV;
 	}
 
-	DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
-
 	/* register new adapter to i2c module... */
 	adap->algo = &i2c_bit_algo;
 
 	adap->timeout = 100;	/* default values, should	*/
 	adap->retries = 3;	/* be replaced by defines	*/
 
+	return 0;
+}
+
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+	int err;
+
+	err = i2c_bit_prepare_bus(adap);
+	if (err)
+		return err;
+
 	return i2c_add_adapter(adap);
 }
 EXPORT_SYMBOL(i2c_bit_add_bus);
 
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+	int err;
+
+	err = i2c_bit_prepare_bus(adap);
+	if (err)
+		return err;
+
+	return i2c_add_numbered_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
+
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
 MODULE_LICENSE("GPL");
-
-module_param(bit_test, bool, 0);
-module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
-
-MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
-MODULE_PARM_DESC(i2c_debug,
-		 "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index ac2d505..6eaf145 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -1,6 +1,7 @@
 /*
- * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
- * 
+ * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and
+ * MACE (SGI O2) chips.
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License version 2 as published by the Free Software Foundation.
  *
@@ -162,8 +163,8 @@ static const struct i2c_algorithm sgi_al
 	.functionality	= sgi_func,
 };
 
-/* 
- * registering functions to load algorithms at runtime 
+/*
+ * registering functions to load algorithms at runtime
  */
 int i2c_sgi_add_bus(struct i2c_adapter *adap)
 {
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ece31d2..838dc1c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -3,11 +3,10 @@ # Sensor device configuration
 #
 
 menu "I2C Hardware Bus support"
-	depends on I2C
 
 config I2C_ALI1535
 	tristate "ALI 1535"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the SMB
 	  Host controller on Acer Labs Inc. (ALI) M1535 South Bridges.  The SMB
@@ -19,7 +18,7 @@ config I2C_ALI1535
 
 config I2C_ALI1563
 	tristate "ALI 1563"
-	depends on I2C && PCI && EXPERIMENTAL
+	depends on PCI && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the SMB
 	  Host controller on Acer Labs Inc. (ALI) M1563 South Bridges.  The SMB
@@ -31,7 +30,7 @@ config I2C_ALI1563
 
 config I2C_ALI15X3
 	tristate "ALI 15x3"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the
 	  Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
@@ -41,7 +40,7 @@ config I2C_ALI15X3
 
 config I2C_AMD756
 	tristate "AMD 756/766/768/8111 and nVidia nForce"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the AMD
 	  756/766/768 mainboard I2C interfaces.  The driver also includes
@@ -66,7 +65,7 @@ config I2C_AMD756_S4882
 
 config I2C_AMD8111
 	tristate "AMD 8111"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the
 	  second (SMBus 2.0) AMD 8111 mainboard I2C interface.
@@ -76,14 +75,14 @@ config I2C_AMD8111
 
 config I2C_AT91
 	tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-	depends on I2C && ARCH_AT91 && EXPERIMENTAL
+	depends on ARCH_AT91 && EXPERIMENTAL
 	help
 	  This supports the use of the I2C interface on Atmel AT91
 	  processors.
 
 config I2C_AU1550
 	tristate "Au1550/Au1200 SMBus interface"
-	depends on I2C && (SOC_AU1550 || SOC_AU1200)
+	depends on SOC_AU1550 || SOC_AU1200
 	help
 	  If you say yes to this option, support will be included for the
 	  Au1550 and Au1200 SMBus interface.
@@ -91,9 +90,25 @@ config I2C_AU1550
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-au1550.
 
+config I2C_BLACKFIN_TWI
+	tristate "Blackfin TWI I2C support"
+	depends on BF534 || BF536 || BF537
+	help
+	  This is the TWI I2C device driver for Blackfin 534/536/537.
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+	int "Blackfin TWI I2C clock (kHz)"
+	depends on I2C_BLACKFIN_TWI
+	range 10 400
+	default 50
+	help
+	  The unit of the TWI clock is kHz.
+
 config I2C_ELEKTOR
 	tristate "Elektor ISA card"
-	depends on I2C && ISA && BROKEN_ON_SMP
+	depends on ISA && BROKEN_ON_SMP
 	select I2C_ALGOPCF
 	help
 	  This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
@@ -102,9 +117,17 @@ config I2C_ELEKTOR
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-elektor.
 
+config I2C_GPIO
+	tristate "GPIO-based bitbanging I2C"
+	depends on GENERIC_GPIO
+	select I2C_ALGOBIT
+	help
+	  This is a very simple bitbanging I2C driver utilizing the
+	  arch-neutral GPIO API to control the SCL and SDA lines.
+
 config I2C_HYDRA
 	tristate "CHRP Apple Hydra Mac I/O I2C interface"
-	depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL
+	depends on PCI && PPC_CHRP && EXPERIMENTAL
 	select I2C_ALGOBIT
 	help
 	  This supports the use of the I2C interface in the Apple Hydra Mac
@@ -116,7 +139,7 @@ config I2C_HYDRA
 
 config I2C_I801
 	tristate "Intel 82801 (ICH)"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the Intel
 	  801 family of mainboard I2C interfaces.  Specifically, the following
@@ -139,7 +162,7 @@ config I2C_I801
 
 config I2C_I810
 	tristate "Intel 810/815"
-	depends on I2C && PCI
+	depends on PCI
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the Intel
@@ -156,7 +179,7 @@ config I2C_I810
 
 config I2C_PXA
 	tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
-	depends on I2C && EXPERIMENTAL && ARCH_PXA
+	depends on EXPERIMENTAL && ARCH_PXA
 	help
 	  If you have devices in the PXA I2C bus, say yes to this option.
 	  This driver can also be built as a module.  If so, the module
@@ -172,7 +195,7 @@ config I2C_PXA_SLAVE
 
 config I2C_PIIX4
 	tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the Intel
 	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
@@ -195,7 +218,7 @@ config I2C_PIIX4
 
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
-	depends on IBM_OCP && I2C
+	depends on IBM_OCP
 	help
 	  Say Y here if you want to use IIC peripheral found on 
 	  embedded IBM PPC 4xx based systems. 
@@ -205,7 +228,7 @@ config I2C_IBM_IIC
 
 config I2C_IOP3XX
 	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
-	depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C
+	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
 	help
 	  Say Y here if you want to use the IIC bus controller on
 	  the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
@@ -215,11 +238,10 @@ config I2C_IOP3XX
 
 config I2C_ISA
 	tristate
-	depends on I2C
 
 config I2C_IXP4XX
-	tristate "IXP4xx GPIO-Based I2C Interface"
-	depends on I2C && ARCH_IXP4XX
+	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
+	depends on ARCH_IXP4XX
 	select I2C_ALGOBIT
 	help
 	  Say Y here if you have an Intel IXP4xx(420,421,422,425) based 
@@ -228,9 +250,12 @@ config I2C_IXP4XX
 	  This support is also available as a module. If so, the module
 	  will be called i2c-ixp4xx.
 
+	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+	  instead.
+
 config I2C_IXP2000
-	tristate "IXP2000 GPIO-Based I2C Interface"
-	depends on I2C && ARCH_IXP2000
+	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+	depends on ARCH_IXP2000
 	select I2C_ALGOBIT
 	help
 	  Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based 
@@ -239,9 +264,12 @@ config I2C_IXP2000
 	  This support is also available as a module. If so, the module
 	  will be called i2c-ixp2000.
 
+	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+	  instead.
+
 config I2C_POWERMAC
 	tristate "Powermac I2C interface"
-	depends on I2C && PPC_PMAC
+	depends on PPC_PMAC
 	default y
 	help
 	  This exposes the various PowerMac i2c interfaces to the linux i2c
@@ -253,7 +281,7 @@ config I2C_POWERMAC
 
 config I2C_MPC
 	tristate "MPC107/824x/85xx/52xx/86xx"
-	depends on I2C && PPC32
+	depends on PPC32
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -265,7 +293,7 @@ config I2C_MPC
 
 config I2C_NFORCE2
 	tristate "Nvidia nForce2, nForce3 and nForce4"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the Nvidia
 	  nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
@@ -275,7 +303,7 @@ config I2C_NFORCE2
 
 config I2C_OCORES
 	tristate "OpenCores I2C Controller"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the
 	  OpenCores I2C controller. For details see
@@ -286,7 +314,7 @@ config I2C_OCORES
 
 config I2C_OMAP
 	tristate "OMAP I2C adapter"
-	depends on I2C && ARCH_OMAP
+	depends on 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
@@ -296,7 +324,7 @@ config I2C_OMAP
 
 config I2C_PARPORT
 	tristate "Parallel port adapter"
-	depends on I2C && PARPORT
+	depends on PARPORT
 	select I2C_ALGOBIT
 	help
 	  This supports parallel port I2C adapters such as the ones made by
@@ -320,7 +348,6 @@ config I2C_PARPORT
 
 config I2C_PARPORT_LIGHT
 	tristate "Parallel port adapter (light)"
-	depends on I2C
 	select I2C_ALGOBIT
 	help
 	  This supports parallel port I2C adapters such as the ones made by
@@ -344,13 +371,13 @@ config I2C_PARPORT_LIGHT
 
 config I2C_PASEMI
 	tristate "PA Semi SMBus interface"
-	depends on PPC_PASEMI && I2C && PCI
+	depends on PPC_PASEMI && PCI
 	help
 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
 
 config I2C_PROSAVAGE
 	tristate "S3/VIA (Pro)Savage"
-	depends on I2C && PCI
+	depends on PCI
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the
@@ -365,19 +392,19 @@ config I2C_PROSAVAGE
 
 config I2C_RPXLITE
 	tristate "Embedded Planet RPX Lite/Classic support"
-	depends on (RPXLITE || RPXCLASSIC) && I2C
+	depends on RPXLITE || RPXCLASSIC
 	select I2C_ALGO8XX
 
 config I2C_S3C2410
 	tristate "S3C2410 I2C Driver"
-	depends on I2C && ARCH_S3C2410
+	depends on ARCH_S3C2410
 	help
 	  Say Y here to include support for I2C controller in the
 	  Samsung S3C2410 based System-on-Chip devices.
 
 config I2C_SAVAGE4
 	tristate "S3 Savage 4"
-	depends on I2C && PCI && EXPERIMENTAL
+	depends on PCI && EXPERIMENTAL
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the 
@@ -388,13 +415,25 @@ config I2C_SAVAGE4
 
 config I2C_SIBYTE
 	tristate "SiByte SMBus interface"
-	depends on SIBYTE_SB1xxx_SOC && I2C
+	depends on SIBYTE_SB1xxx_SOC
 	help
 	  Supports the SiByte SOC on-chip I2C interfaces (2 channels).
 
+config I2C_SIMTEC
+	tristate "Simtec Generic I2C interface"
+	select I2C_ALGOBIT
+	help
+	  If you say yes to this option, support will be inclyded for
+	  the Simtec Generic I2C interface. This driver is for the
+	  simple I2C bus used on newer Simtec products for general
+	  I2C, such as DDC on the Simtec BBD2016A.
+
+	  This driver can also be build as a module. If so, the module
+	  will be called i2c-simtec.
+
 config SCx200_I2C
-	tristate "NatSemi SCx200 I2C using GPIO pins"
-	depends on SCx200_GPIO && I2C
+	tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+	depends on SCx200_GPIO
 	select I2C_ALGOBIT
 	help
 	  Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
@@ -404,6 +443,9 @@ config SCx200_I2C
 	  This support is also available as a module.  If so, the module 
 	  will be called scx200_i2c.
 
+	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+	  (or scx200_acb) instead.
+
 config SCx200_I2C_SCL
 	int "GPIO pin used for SCL"
 	depends on SCx200_I2C
@@ -422,7 +464,7 @@ config SCx200_I2C_SDA
 
 config SCx200_ACB
 	tristate "Geode ACCESS.bus support"
-	depends on X86_32 && I2C && PCI
+	depends on X86_32 && PCI
 	help
 	  Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
 	  SC1100 processors and the CS5535 and CS5536 Geode companion devices.
@@ -434,7 +476,7 @@ config SCx200_ACB
 
 config I2C_SIS5595
 	tristate "SiS 5595"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the 
 	  SiS5595 SMBus (a subset of I2C) interface.
@@ -444,7 +486,7 @@ config I2C_SIS5595
 
 config I2C_SIS630
 	tristate "SiS 630/730"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the 
 	  SiS630 and SiS730 SMBus (a subset of I2C) interface.
@@ -454,7 +496,7 @@ config I2C_SIS630
 
 config I2C_SIS96X
 	tristate "SiS 96x"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the SiS
 	  96x SMBus (a subset of I2C) interfaces.  Specifically, the following
@@ -472,7 +514,7 @@ config I2C_SIS96X
 
 config I2C_STUB
 	tristate "I2C/SMBus Test Stub"
-	depends on I2C && EXPERIMENTAL && 'm'
+	depends on EXPERIMENTAL && m
 	default 'n'
 	help
 	  This module may be useful to developers of SMBus client drivers,
@@ -483,9 +525,20 @@ config I2C_STUB
 
 	  If you don't know what to do here, definitely say N.
 
+config I2C_TINY_USB
+	tristate "I2C-Tiny-USB"
+	depends on USB
+	help
+	  If you say yes to this option, support will be included for the
+	  i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+	  http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-tiny-usb.
+
 config I2C_VERSATILE
 	tristate "ARM Versatile/Realview I2C bus support"
-	depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
+	depends on ARCH_VERSATILE || ARCH_REALVIEW
 	select I2C_ALGOBIT
 	help
 	  Say yes if you want to support the I2C serial bus on ARMs Versatile
@@ -496,7 +549,7 @@ config I2C_VERSATILE
 
 config I2C_ACORN
 	bool "Acorn IOC/IOMD I2C bus support"
-	depends on I2C && ARCH_ACORN
+	depends on ARCH_ACORN
 	default y
 	select I2C_ALGOBIT
 	help
@@ -506,7 +559,7 @@ config I2C_ACORN
 
 config I2C_VIA
 	tristate "VIA 82C586B"
-	depends on I2C && PCI && EXPERIMENTAL
+	depends on PCI && EXPERIMENTAL
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the VIA
@@ -517,7 +570,7 @@ config I2C_VIA
 
 config I2C_VIAPRO
 	tristate "VIA VT82C596/82C686/82xx and CX700"
-	depends on I2C && PCI
+	depends on PCI
 	help
 	  If you say yes to this option, support will be included for the VIA
 	  VT82C596 and later SMBus interface.  Specifically, the following
@@ -536,7 +589,7 @@ config I2C_VIAPRO
 
 config I2C_VOODOO3
 	tristate "Voodoo 3"
-	depends on I2C && PCI
+	depends on PCI
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the
@@ -547,7 +600,7 @@ config I2C_VOODOO3
 
 config I2C_PCA_ISA
 	tristate "PCA9564 on an ISA bus"
-	depends on I2C
+	depends on ISA
 	select I2C_ALGOPCA
 	default n
 	help
@@ -564,7 +617,7 @@ config I2C_PCA_ISA
 
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
-	depends on I2C && MV64X60 && EXPERIMENTAL
+	depends on MV64X60 && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -574,7 +627,7 @@ config I2C_MV64XXX
 
 config I2C_PNX
 	tristate "I2C bus support for Philips PNX targets"
-	depends on ARCH_PNX4008 && I2C
+	depends on ARCH_PNX4008
 	help
 	  This driver supports the Philips IP3204 I2C IP block master and/or
 	  slave controller
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 290b540..14d1432 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_I2C_AMD756_S4882)	+= i2c-am
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
+obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
 obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
@@ -37,10 +39,12 @@ obj-$(CONFIG_I2C_RPXLITE)	+= i2c-rpx.o
 obj-$(CONFIG_I2C_S3C2410)	+= i2c-s3c2410.o
 obj-$(CONFIG_I2C_SAVAGE4)	+= i2c-savage4.o
 obj-$(CONFIG_I2C_SIBYTE)	+= i2c-sibyte.o
+obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
 obj-$(CONFIG_I2C_SIS5595)	+= i2c-sis5595.o
 obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_STUB)		+= i2c-stub.o
+obj-$(CONFIG_I2C_TINY_USB)	+= i2c-tiny-usb.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_ACORN)		+= i2c-acorn.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 1e277ba..f14372a 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struc
 	/* set up the sysfs linkage to our parent device */
 	ali1535_adapter.dev.parent = &dev->dev;
 
-	snprintf(ali1535_adapter.name, I2C_NAME_SIZE, 
+	snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
 		"SMBus ALI1535 adapter at %04x", ali1535_smba);
 	return i2c_add_adapter(&ali1535_adapter);
 }
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index e47fe01..93bf87d 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struc
 	/* set up the sysfs linkage to our parent device */
 	ali15x3_adapter.dev.parent = &dev->dev;
 
-	snprintf(ali15x3_adapter.name, I2C_NAME_SIZE,
+	snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
 		"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
 	return i2c_add_adapter(&ali15x3_adapter);
 }
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 0c70f82..c9fca7b 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struc
 	}
 
 	smbus->adapter.owner = THIS_MODULE;
-	snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
 		"SMBus2 AMD8111 adapter at %04x", smbus->base);
 	smbus->adapter.id = I2C_HW_SMBUS_AMD8111;
 	smbus->adapter.class = I2C_CLASS_HWMON;
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 67f91bd..f35156c 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -17,7 +17,6 @@ #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 0000000..6311039
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,644 @@
+/*
+ * drivers/i2c/busses/i2c-bfin-twi.c
+ *
+ * Description: Driver for Blackfin Two Wire Interface
+ *
+ * Author:      sonicz  <sonic.zhang@analog.com>
+ *
+ * Copyright (c) 2005-2007 Analog Devices, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+#define POLL_TIMEOUT       (2 * HZ)
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD		0x01
+#define TWI_I2C_MODE_STANDARDSUB	0x02
+#define TWI_I2C_MODE_COMBINED		0x04
+
+struct bfin_twi_iface {
+	struct mutex		twi_lock;
+	int			irq;
+	spinlock_t		lock;
+	char			read_write;
+	u8			command;
+	u8			*transPtr;
+	int			readNum;
+	int			writeNum;
+	int			cur_mode;
+	int			manual_stop;
+	int			result;
+	int			timeout_count;
+	struct timer_list	timeout_timer;
+	struct i2c_adapter	adap;
+	struct completion	complete;
+};
+
+static struct bfin_twi_iface twi_iface;
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
+{
+	unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
+	unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
+
+	if (twi_int_status & XMTSERV) {
+		/* Transmit next data */
+		if (iface->writeNum > 0) {
+			bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+			iface->writeNum--;
+		}
+		/* start receive immediately after complete sending in
+		 * combine mode.
+		 */
+		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+				| MDIR | RSTART);
+		} else if (iface->manual_stop)
+			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+				| STOP);
+		SSYNC();
+		/* Clear status */
+		bfin_write_TWI_INT_STAT(XMTSERV);
+		SSYNC();
+	}
+	if (twi_int_status & RCVSERV) {
+		if (iface->readNum > 0) {
+			/* Receive next data */
+			*(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
+			if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+				/* Change combine mode into sub mode after
+				 * read first data.
+				 */
+				iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+				/* Get read number from first byte in block
+				 * combine mode.
+				 */
+				if (iface->readNum == 1 && iface->manual_stop)
+					iface->readNum = *iface->transPtr + 1;
+			}
+			iface->transPtr++;
+			iface->readNum--;
+		} else if (iface->manual_stop) {
+			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+				| STOP);
+			SSYNC();
+		}
+		/* Clear interrupt source */
+		bfin_write_TWI_INT_STAT(RCVSERV);
+		SSYNC();
+	}
+	if (twi_int_status & MERR) {
+		bfin_write_TWI_INT_STAT(MERR);
+		bfin_write_TWI_INT_MASK(0);
+		bfin_write_TWI_MASTER_STAT(0x3e);
+		bfin_write_TWI_MASTER_CTL(0);
+		SSYNC();
+		iface->result = -1;
+		/* if both err and complete int stats are set, return proper
+		 * results.
+		 */
+		if (twi_int_status & MCOMP) {
+			bfin_write_TWI_INT_STAT(MCOMP);
+			bfin_write_TWI_INT_MASK(0);
+			bfin_write_TWI_MASTER_CTL(0);
+			SSYNC();
+			/* If it is a quick transfer, only address bug no data,
+			 * not an err, return 1.
+			 */
+			if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
+				iface->result = 1;
+			/* If address not acknowledged return -1,
+			 * else return 0.
+			 */
+			else if (!(mast_stat & ANAK))
+				iface->result = 0;
+		}
+		complete(&iface->complete);
+		return;
+	}
+	if (twi_int_status & MCOMP) {
+		bfin_write_TWI_INT_STAT(MCOMP);
+		SSYNC();
+		if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+			if (iface->readNum == 0) {
+				/* set the read number to 1 and ask for manual
+				 * stop in block combine mode
+				 */
+				iface->readNum = 1;
+				iface->manual_stop = 1;
+				bfin_write_TWI_MASTER_CTL(
+					bfin_read_TWI_MASTER_CTL()
+					| (0xff << 6));
+			} else {
+				/* set the readd number in other
+				 * combine mode.
+				 */
+				bfin_write_TWI_MASTER_CTL(
+					(bfin_read_TWI_MASTER_CTL() &
+					(~(0xff << 6))) |
+					( iface->readNum << 6));
+			}
+			/* remove restart bit and enable master receive */
+			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
+				~RSTART);
+			bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
+				MEN | MDIR);
+			SSYNC();
+		} else {
+			iface->result = 1;
+			bfin_write_TWI_INT_MASK(0);
+			bfin_write_TWI_MASTER_CTL(0);
+			SSYNC();
+			complete(&iface->complete);
+		}
+	}
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+	struct bfin_twi_iface *iface = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iface->lock, flags);
+	del_timer(&iface->timeout_timer);
+	bfin_twi_handle_interrupt(iface);
+	spin_unlock_irqrestore(&iface->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void bfin_twi_timeout(unsigned long data)
+{
+	struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iface->lock, flags);
+	bfin_twi_handle_interrupt(iface);
+	if (iface->result == 0) {
+		iface->timeout_count--;
+		if (iface->timeout_count > 0) {
+			iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+			add_timer(&iface->timeout_timer);
+		} else {
+			iface->result = -1;
+			complete(&iface->complete);
+		}
+	}
+	spin_unlock_irqrestore(&iface->lock, flags);
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msgs, int num)
+{
+	struct bfin_twi_iface *iface = adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i, ret;
+	int rc = 0;
+
+	if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+		return -ENXIO;
+
+	mutex_lock(&iface->twi_lock);
+
+	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+		mutex_unlock(&iface->twi_lock);
+		yield();
+		mutex_lock(&iface->twi_lock);
+	}
+
+	ret = 0;
+	for (i = 0; rc >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (pmsg->flags & I2C_M_TEN) {
+			dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
+				"not supported !\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		iface->cur_mode = TWI_I2C_MODE_STANDARD;
+		iface->manual_stop = 0;
+		iface->transPtr = pmsg->buf;
+		iface->writeNum = iface->readNum = pmsg->len;
+		iface->result = 0;
+		iface->timeout_count = 10;
+		/* Set Transmit device address */
+		bfin_write_TWI_MASTER_ADDR(pmsg->addr);
+
+		/* FIFO Initiation. Data in FIFO should be
+		 *  discarded before start a new operation.
+		 */
+		bfin_write_TWI_FIFO_CTL(0x3);
+		SSYNC();
+		bfin_write_TWI_FIFO_CTL(0);
+		SSYNC();
+
+		if (pmsg->flags & I2C_M_RD)
+			iface->read_write = I2C_SMBUS_READ;
+		else {
+			iface->read_write = I2C_SMBUS_WRITE;
+			/* Transmit first data */
+			if (iface->writeNum > 0) {
+				bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+				iface->writeNum--;
+				SSYNC();
+			}
+		}
+
+		/* clear int stat */
+		bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+		/* Interrupt mask . Enable XMT, RCV interrupt */
+		bfin_write_TWI_INT_MASK(MCOMP | MERR |
+			((iface->read_write == I2C_SMBUS_READ)?
+			RCVSERV : XMTSERV));
+		SSYNC();
+
+		if (pmsg->len > 0 && pmsg->len <= 255)
+			bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
+		else if (pmsg->len > 255) {
+			bfin_write_TWI_MASTER_CTL(0xff << 6);
+			iface->manual_stop = 1;
+		} else
+			break;
+
+		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+		add_timer(&iface->timeout_timer);
+
+		/* Master enable */
+		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+			((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+		SSYNC();
+
+		wait_for_completion(&iface->complete);
+
+		rc = iface->result;
+		if (rc == 1)
+			ret++;
+		else if (rc == -1)
+			break;
+	}
+
+	/* Release mutex */
+	mutex_unlock(&iface->twi_lock);
+
+	return ret;
+}
+
+/*
+ * SMBus type transfer entrypoint
+ */
+
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+			unsigned short flags, char read_write,
+			u8 command, int size, union i2c_smbus_data *data)
+{
+	struct bfin_twi_iface *iface = adap->algo_data;
+	int rc = 0;
+
+	if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+		return -ENXIO;
+
+	mutex_lock(&iface->twi_lock);
+
+	while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+		mutex_unlock(&iface->twi_lock);
+		yield();
+		mutex_lock(&iface->twi_lock);
+	}
+
+	iface->writeNum = 0;
+	iface->readNum = 0;
+
+	/* Prepare datas & select mode */
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		iface->transPtr = NULL;
+		iface->cur_mode = TWI_I2C_MODE_STANDARD;
+		break;
+	case I2C_SMBUS_BYTE:
+		if (data == NULL)
+			iface->transPtr = NULL;
+		else {
+			if (read_write == I2C_SMBUS_READ)
+				iface->readNum = 1;
+			else
+				iface->writeNum = 1;
+			iface->transPtr = &data->byte;
+		}
+		iface->cur_mode = TWI_I2C_MODE_STANDARD;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 1;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = 1;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = &data->byte;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 2;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = 2;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = (u8 *)&data->word;
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		iface->writeNum = 2;
+		iface->readNum = 2;
+		iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		iface->transPtr = (u8 *)&data->word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 0;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = data->block[0] + 1;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = data->block;
+		break;
+	default:
+		return -1;
+	}
+
+	iface->result = 0;
+	iface->manual_stop = 0;
+	iface->read_write = read_write;
+	iface->command = command;
+	iface->timeout_count = 10;
+
+	/* FIFO Initiation. Data in FIFO should be discarded before
+	 * start a new operation.
+	 */
+	bfin_write_TWI_FIFO_CTL(0x3);
+	SSYNC();
+	bfin_write_TWI_FIFO_CTL(0);
+
+	/* clear int stat */
+	bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+	/* Set Transmit device address */
+	bfin_write_TWI_MASTER_ADDR(addr);
+	SSYNC();
+
+	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+	add_timer(&iface->timeout_timer);
+
+	switch (iface->cur_mode) {
+	case TWI_I2C_MODE_STANDARDSUB:
+		bfin_write_TWI_XMT_DATA8(iface->command);
+		bfin_write_TWI_INT_MASK(MCOMP | MERR |
+			((iface->read_write == I2C_SMBUS_READ) ?
+			RCVSERV : XMTSERV));
+		SSYNC();
+
+		if (iface->writeNum + 1 <= 255)
+			bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+		else {
+			bfin_write_TWI_MASTER_CTL(0xff << 6);
+			iface->manual_stop = 1;
+		}
+		/* Master enable */
+		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+		break;
+	case TWI_I2C_MODE_COMBINED:
+		bfin_write_TWI_XMT_DATA8(iface->command);
+		bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
+		SSYNC();
+
+		if (iface->writeNum > 0)
+			bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+		else
+			bfin_write_TWI_MASTER_CTL(0x1 << 6);
+		/* Master enable */
+		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+		break;
+	default:
+		bfin_write_TWI_MASTER_CTL(0);
+		if (size != I2C_SMBUS_QUICK) {
+			/* Don't access xmit data register when this is a
+			 * read operation.
+			 */
+			if (iface->read_write != I2C_SMBUS_READ) {
+				if (iface->writeNum > 0) {
+					bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+					if (iface->writeNum <= 255)
+						bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
+					else {
+						bfin_write_TWI_MASTER_CTL(0xff << 6);
+						iface->manual_stop = 1;
+					}
+					iface->writeNum--;
+				} else {
+					bfin_write_TWI_XMT_DATA8(iface->command);
+					bfin_write_TWI_MASTER_CTL(1 << 6);
+				}
+			} else {
+				if (iface->readNum > 0 && iface->readNum <= 255)
+					bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
+				else if (iface->readNum > 255) {
+					bfin_write_TWI_MASTER_CTL(0xff << 6);
+					iface->manual_stop = 1;
+				} else {
+					del_timer(&iface->timeout_timer);
+					break;
+				}
+			}
+		}
+		bfin_write_TWI_INT_MASK(MCOMP | MERR |
+			((iface->read_write == I2C_SMBUS_READ) ?
+			RCVSERV : XMTSERV));
+		SSYNC();
+
+		/* Master enable */
+		bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+			((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+		break;
+	}
+	SSYNC();
+
+	wait_for_completion(&iface->complete);
+
+	rc = (iface->result >= 0) ? 0 : -1;
+
+	/* Release mutex */
+	mutex_unlock(&iface->twi_lock);
+
+	return rc;
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+	       I2C_FUNC_I2C;
+}
+
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+	.master_xfer   = bfin_twi_master_xfer,
+	.smbus_xfer    = bfin_twi_smbus_xfer,
+	.functionality = bfin_twi_functionality,
+};
+
+
+static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
+{
+/*	struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+	/* Disable TWI */
+	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+	SSYNC();
+
+	return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *dev)
+{
+/*	struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+	/* Enable TWI */
+	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+	SSYNC();
+
+	return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *dev)
+{
+	struct bfin_twi_iface *iface = &twi_iface;
+	struct i2c_adapter *p_adap;
+	int rc;
+
+	mutex_init(&(iface->twi_lock));
+	spin_lock_init(&(iface->lock));
+	init_completion(&(iface->complete));
+	iface->irq = IRQ_TWI;
+
+	init_timer(&(iface->timeout_timer));
+	iface->timeout_timer.function = bfin_twi_timeout;
+	iface->timeout_timer.data = (unsigned long)iface;
+
+	p_adap = &iface->adap;
+	p_adap->id = I2C_HW_BLACKFIN;
+	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+	p_adap->algo = &bfin_twi_algorithm;
+	p_adap->algo_data = iface;
+	p_adap->class = I2C_CLASS_ALL;
+	p_adap->dev.parent = &dev->dev;
+
+	rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+		IRQF_DISABLED, dev->name, iface);
+	if (rc) {
+		dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
+			iface->irq);
+		return -ENODEV;
+	}
+
+	/* Set TWI internal clock as 10MHz */
+	bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+
+	/* Set Twi interface clock as specified */
+	bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+			<< 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+			& 0xFF));
+
+	/* Enable TWI */
+	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+	SSYNC();
+
+	rc = i2c_add_adapter(p_adap);
+	if (rc < 0)
+		free_irq(iface->irq, iface);
+	else
+		platform_set_drvdata(dev, iface);
+
+	return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	i2c_del_adapter(&(iface->adap));
+	free_irq(iface->irq, iface);
+
+	return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+	.probe		= i2c_bfin_twi_probe,
+	.remove		= i2c_bfin_twi_remove,
+	.suspend	= i2c_bfin_twi_suspend,
+	.resume		= i2c_bfin_twi_resume,
+	.driver		= {
+		.name	= "i2c-bfin-twi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+	pr_info("I2C: Blackfin I2C TWI driver\n");
+
+	return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+	platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 8349674..804f0a5 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -35,6 +35,7 @@ #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/wait.h>
 
+#include <linux/isa.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
 
@@ -207,7 +208,7 @@ static struct i2c_adapter pcf_isa_ops = 
 	.name		= "i2c-elektor",
 };
 
-static int __init i2c_pcfisa_init(void)
+static int __devinit elektor_match(struct device *dev, unsigned int id)
 {
 #ifdef __alpha__
 	/* check to see we have memory mapped PCF8584 connected to the
@@ -222,9 +223,8 @@ #ifdef __alpha__
 			/* yeap, we've found cypress, let's check config */
 			if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
 
-				pr_debug("%s: found cy82c693, config "
-					 "register 0x47 = 0x%02x\n",
-					 pcf_isa_ops.name, config);
+				dev_dbg(dev, "found cy82c693, config "
+					"register 0x47 = 0x%02x\n", config);
 
 				/* UP2000 board has this register set to 0xe1,
 				   but the most significant bit as seems can be
@@ -244,9 +244,9 @@ #ifdef __alpha__
 					   8.25 MHz (PCI/4) clock
 					   (this can be read from cypress) */
 					clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
-					pr_info("%s: found API UP2000 like "
-						"board, will probe PCF8584 "
-						"later\n", pcf_isa_ops.name);
+					dev_info(dev, "found API UP2000 like "
+						 "board, will probe PCF8584 "
+						 "later\n");
 				}
 			}
 			pci_dev_put(cy693_dev);
@@ -256,22 +256,27 @@ #endif
 
 	/* sanity checks for mmapped I/O */
 	if (mmapped && base < 0xc8000) {
-		printk(KERN_ERR "%s: incorrect base address (%#x) specified "
-		       "for mmapped I/O\n", pcf_isa_ops.name, base);
-		return -ENODEV;
+		dev_err(dev, "incorrect base address (%#x) specified "
+		       "for mmapped I/O\n", base);
+		return 0;
 	}
 
 	if (base == 0) {
 		base = DEFAULT_BASE;
 	}
+	return 1;
+}
 
+static int __devinit elektor_probe(struct device *dev, unsigned int id)
+{
 	init_waitqueue_head(&pcf_wait);
 	if (pcf_isa_init())
 		return -ENODEV;
+	pcf_isa_ops.dev.parent = dev;
 	if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
 		goto fail;
 
-	dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base);
+	dev_info(dev, "found device at %#x\n", base);
 
 	return 0;
 
@@ -291,7 +296,7 @@ #endif
 	return -ENODEV;
 }
 
-static void i2c_pcfisa_exit(void)
+static int __devexit elektor_remove(struct device *dev, unsigned int id)
 {
 	i2c_del_adapter(&pcf_isa_ops);
 
@@ -307,6 +312,28 @@ static void i2c_pcfisa_exit(void)
 		iounmap(base_iomem);
 		release_mem_region(base, 2);
 	}
+
+	return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+	.match		= elektor_match,
+	.probe		= elektor_probe,
+	.remove		= __devexit_p(elektor_remove),
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "i2c-elektor",
+	},
+};
+
+static int __init i2c_pcfisa_init(void)
+{
+	return isa_register_driver(&i2c_elektor_driver, 1);
+}
+
+static void __exit i2c_pcfisa_exit(void)
+{
+	isa_unregister_driver(&i2c_elektor_driver);
 }
 
 MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 0000000..a7dd546
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,215 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 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/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->sda_pin);
+	else
+		gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->scl_pin);
+	else
+		gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->scl_pin, state);
+}
+
+int i2c_gpio_getsda(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->sda_pin);
+}
+
+int i2c_gpio_getscl(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->scl_pin);
+}
+
+static int __init i2c_gpio_probe(struct platform_device *pdev)
+{
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_algo_bit_data *bit_data;
+	struct i2c_adapter *adap;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -ENXIO;
+
+	ret = -ENOMEM;
+	adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (!adap)
+		goto err_alloc_adap;
+	bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
+	if (!bit_data)
+		goto err_alloc_bit_data;
+
+	ret = gpio_request(pdata->sda_pin, "sda");
+	if (ret)
+		goto err_request_sda;
+	ret = gpio_request(pdata->scl_pin, "scl");
+	if (ret)
+		goto err_request_scl;
+
+	if (pdata->sda_is_open_drain) {
+		gpio_direction_output(pdata->sda_pin, 1);
+		bit_data->setsda = i2c_gpio_setsda_val;
+	} else {
+		gpio_direction_input(pdata->sda_pin);
+		bit_data->setsda = i2c_gpio_setsda_dir;
+	}
+
+	if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+		gpio_direction_output(pdata->scl_pin, 1);
+		bit_data->setscl = i2c_gpio_setscl_val;
+	} else {
+		gpio_direction_input(pdata->scl_pin);
+		bit_data->setscl = i2c_gpio_setscl_dir;
+	}
+
+	if (!pdata->scl_is_output_only)
+		bit_data->getscl = i2c_gpio_getscl;
+	bit_data->getsda = i2c_gpio_getsda;
+
+	if (pdata->udelay)
+		bit_data->udelay = pdata->udelay;
+	else if (pdata->scl_is_output_only)
+		bit_data->udelay = 50;			/* 10 kHz */
+	else
+		bit_data->udelay = 5;			/* 100 kHz */
+
+	if (pdata->timeout)
+		bit_data->timeout = pdata->timeout;
+	else
+		bit_data->timeout = HZ / 10;		/* 100 ms */
+
+	bit_data->data = pdata;
+
+	adap->owner = THIS_MODULE;
+	snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+	adap->algo_data = bit_data;
+	adap->dev.parent = &pdev->dev;
+
+	ret = i2c_bit_add_bus(adap);
+	if (ret)
+		goto err_add_bus;
+
+	platform_set_drvdata(pdev, adap);
+
+	dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+		 pdata->sda_pin, pdata->scl_pin,
+		 pdata->scl_is_output_only
+		 ? ", no clock stretching" : "");
+
+	return 0;
+
+err_add_bus:
+	gpio_free(pdata->scl_pin);
+err_request_scl:
+	gpio_free(pdata->sda_pin);
+err_request_sda:
+	kfree(bit_data);
+err_alloc_bit_data:
+	kfree(adap);
+err_alloc_adap:
+	return ret;
+}
+
+static int __exit i2c_gpio_remove(struct platform_device *pdev)
+{
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_adapter *adap;
+
+	adap = platform_get_drvdata(pdev);
+	pdata = pdev->dev.platform_data;
+
+	i2c_del_adapter(adap);
+	gpio_free(pdata->scl_pin);
+	gpio_free(pdata->sda_pin);
+	kfree(adap->algo_data);
+	kfree(adap);
+
+	return 0;
+}
+
+static struct platform_driver i2c_gpio_driver = {
+	.driver		= {
+		.name	= "i2c-gpio",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+	int ret;
+
+	ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe);
+	if (ret)
+		printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+	return ret;
+}
+module_init(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+	platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index a320e7d..611b571 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -527,7 +527,7 @@ static int __devinit i801_probe(struct p
 	/* set up the sysfs linkage to our parent device */
 	i801_adapter.dev.parent = &dev->dev;
 
-	snprintf(i801_adapter.name, I2C_NAME_SIZE,
+	snprintf(i801_adapter.name, sizeof(i801_adapter.name),
 		"SMBus I801 adapter at %04lx", i801_smba);
 	err = i2c_add_adapter(&i801_adapter);
 	if (err) {
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 5f33bc9..b0e1370 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -41,6 +41,10 @@ #include <linux/i2c-isa.h>
 #include <linux/platform_device.h>
 #include <linux/completion.h>
 
+/* Exported by i2c-core for i2c-isa only */
+extern void i2c_adapter_dev_release(struct device *dev);
+extern struct class i2c_adapter_class;
+
 static u32 isa_func(struct i2c_adapter *adapter);
 
 /* This is the actual algorithm we define */
@@ -64,16 +68,6 @@ static u32 isa_func(struct i2c_adapter *
 }
 
 
-/* Copied from i2c-core */
-static ssize_t show_adapter_name(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
-	return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
-
-
 /* We implement an interface which resembles i2c_{add,del}_driver,
    but for i2c-isa drivers. We don't have to remember and handle lists
    of drivers and adapters so this is much more simple, of course. */
@@ -139,41 +133,18 @@ static int __init i2c_isa_init(void)
 	isa_adapter.nr = ANY_I2C_ISA_BUS;
 	isa_adapter.dev.parent = &platform_bus;
 	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;
+	isa_adapter.dev.class = &i2c_adapter_class;
 	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));
-	isa_adapter.class_dev.dev = &isa_adapter.dev;
-	isa_adapter.class_dev.class = &i2c_adapter_class;
-	strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
-		BUS_ID_SIZE);
-	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;
 }
@@ -201,15 +172,11 @@ #endif
 	/* Clean up the sysfs representation */
 	dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
 	init_completion(&isa_adapter.dev_released);
-	init_completion(&isa_adapter.class_dev_released);
-	class_device_unregister(&isa_adapter.class_dev);
-	device_remove_file(&isa_adapter.dev, &dev_attr_name);
 	device_unregister(&isa_adapter.dev);
 
 	/* Wait for sysfs to drop all references */
 	dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
 	wait_for_completion(&isa_adapter.dev_released);
-	wait_for_completion(&isa_adapter.class_dev_released);
 
 	dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
 }
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index efa3ecc..6352121 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct plat
 
 	drv_data->adapter.id = I2C_HW_B_IXP2000,
 	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
-		I2C_NAME_SIZE);
+		sizeof(drv_data->adapter.name));
 	drv_data->adapter.algo_data = &drv_data->algo_data,
 
 	drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 08e89b8..069ed7f 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platf
 	drv_data->adapter.id = I2C_HW_B_IXP4XX;
 	drv_data->adapter.class = I2C_CLASS_HWMON;
 	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
-		I2C_NAME_SIZE);
+		sizeof(drv_data->adapter.name));
 	drv_data->adapter.algo_data = &drv_data->algo_data;
 
 	drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index ee65aa1..c6b6898 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -17,7 +17,6 @@ #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a3283b9..a55b333 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device
 	}
 
 	strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
-		I2C_NAME_SIZE);
+		sizeof(drv_data->adapter.name));
 
 	init_waitqueue_head(&drv_data->waitq);
 	spin_lock_init(&drv_data->lock);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 1514ec5..3cd0d63 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -33,6 +33,8 @@
     nForce4 MCP-04		0034
     nForce4 MCP51		0264
     nForce4 MCP55		0368
+    nForce MCP61		03EB
+    nForce MCP65		0446
 
     This driver supports the 2 SMBuses that are included in the MCP of the
     nForce2/3/4/5xx chipsets.
@@ -200,6 +202,8 @@ static struct pci_device_id nforce2_ids[
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
 	{ 0 }
 };
 
@@ -240,7 +244,7 @@ static int __devinit nforce2_probe_smb (
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
 	smbus->adapter.dev.parent = &dev->dev;
-	snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
 		"SMBus nForce2 adapter at %04x", smbus->base);
 
 	error = i2c_add_adapter(&smbus->adapter);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index bcd8367..e471e3b 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -605,7 +605,8 @@ omap_i2c_probe(struct platform_device *p
 	adap->dev.parent = &pdev->dev;
 
 	/* i2c device drivers may be active on return from add_adapter() */
-	r = i2c_add_adapter(adap);
+	adap->nr = pdev->id;
+	r = i2c_add_numbered_adapter(adap);
 	if (r) {
 		dev_err(dev->dev, "failure adding adapter\n");
 		goto err_free_irq;
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 4bc4281..49a95e2 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
- * i2c-parport.c I2C bus over parallel port                                 *
+ * i2c-parport-light.c I2C bus over parallel port                           *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
    
    Based on older i2c-velleman.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <linux/ioport.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -34,6 +35,9 @@ #include <asm/io.h>
 #include "i2c-parport.h"
 
 #define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
 
 static u16 base;
 module_param(base, ushort, 0);
@@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_
 	.timeout	= HZ,
 }; 
 
-/* ----- I2c structure ---------------------------------------------------- */
+/* ----- Driver registration ---------------------------------------------- */
 
 static struct i2c_adapter parport_adapter = {
 	.owner		= THIS_MODULE,
@@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapte
 	.name		= "Parallel port adapter (light)",
 };
 
-/* ----- Module loading, unloading and information ------------------------ */
+static int __devinit i2c_parport_probe(struct platform_device *pdev)
+{
+	int err;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
+		return -EBUSY;
+
+	/* Reset hardware to a sane state (SCL and SDA high) */
+	parport_setsda(NULL, 1);
+	parport_setscl(NULL, 1);
+	/* Other init if needed (power on...) */
+	if (adapter_parm[type].init.val)
+		line_set(1, &adapter_parm[type].init);
+
+	parport_adapter.dev.parent = &pdev->dev;
+	err = i2c_bit_add_bus(&parport_adapter);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register with I2C\n");
+		goto exit_region;
+	}
+	return 0;
+
+exit_region:
+	release_region(res->start, res->end - res->start + 1);
+	return err;
+}
+
+static int __devexit i2c_parport_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	i2c_del_adapter(&parport_adapter);
+
+	/* Un-init if needed (power off...) */
+	if (adapter_parm[type].init.val)
+		line_set(0, &adapter_parm[type].init);
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	release_region(res->start, res->end - res->start + 1);
+	return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= DRVNAME,
+	},
+	.probe		= i2c_parport_probe,
+	.remove		= __devexit_p(i2c_parport_remove),
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + 2,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, -1);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
 
 static int __init i2c_parport_init(void)
 {
+	int err;
+
 	if (type < 0) {
-		printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
+		printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
 		return -ENODEV;
 	}
 
 	if (type >= ARRAY_SIZE(adapter_parm)) {
-		printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+		printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
 		return -ENODEV;
 	}
 
 	if (base == 0) {
-		printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE);
+		pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
 		base = DEFAULT_BASE;
 	}
 
-	if (!request_region(base, 3, "i2c-parport"))
-		return -ENODEV;
-
         if (!adapter_parm[type].getscl.val)
 		parport_algo_data.getscl = NULL;
 
-	/* Reset hardware to a sane state (SCL and SDA high) */
-	parport_setsda(NULL, 1);
-	parport_setscl(NULL, 1);
-	/* Other init if needed (power on...) */
-	if (adapter_parm[type].init.val)
-		line_set(1, &adapter_parm[type].init);
+	/* Sets global pdev as a side effect */
+	err = i2c_parport_device_add(base);
+	if (err)
+		goto exit;
 
-	if (i2c_bit_add_bus(&parport_adapter) < 0) {
-		printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
-		release_region(base, 3);
-		return -ENODEV;
-	}
+	err = platform_driver_register(&i2c_parport_driver);
+	if (err)
+		goto exit_device;
 
 	return 0;
+
+exit_device:
+	platform_device_unregister(pdev);
+exit:
+	return err;
 }
 
 static void __exit i2c_parport_exit(void)
 {
-	/* Un-init if needed (power off...) */
-	if (adapter_parm[type].init.val)
-		line_set(0, &adapter_parm[type].init);
-
-	i2c_del_adapter(&parport_adapter);
-	release_region(base, 3);
+	platform_driver_unregister(&i2c_parport_driver);
+	platform_device_unregister(pdev);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 66696a4..039a07f 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
  * i2c-parport.c I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
    
    Based on older i2c-philips-par.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
@@ -137,19 +137,12 @@ static struct i2c_algo_bit_data parport_
 	.setscl		= parport_setscl,
 	.getsda		= parport_getsda,
 	.getscl		= parport_getscl,
-	.udelay		= 60,
+	.udelay		= 10, /* ~50 kbps */
 	.timeout	= HZ,
 }; 
 
 /* ----- I2c and parallel port call-back functions and structures --------- */
 
-static struct i2c_adapter parport_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON,
-	.id		= I2C_HW_B_LP,
-	.name		= "Parallel port adapter",
-};
-
 static void i2c_parport_attach (struct parport *port)
 {
 	struct i2c_par *adapter;
@@ -169,12 +162,20 @@ static void i2c_parport_attach (struct p
 	}
 
 	/* Fill the rest of the structure */
-	adapter->adapter = parport_adapter;
+	adapter->adapter.owner = THIS_MODULE;
+	adapter->adapter.class = I2C_CLASS_HWMON;
+	adapter->adapter.id = I2C_HW_B_LP;
+	strlcpy(adapter->adapter.name, "Parallel port adapter",
+		sizeof(adapter->adapter.name));
 	adapter->algo_data = parport_algo_data;
-	if (!adapter_parm[type].getscl.val)
+	/* Slow down if we can't sense SCL */
+	if (!adapter_parm[type].getscl.val) {
 		adapter->algo_data.getscl = NULL;
+		adapter->algo_data.udelay = 50; /* ~10 kbps */
+	}
 	adapter->algo_data.data = port;
 	adapter->adapter.algo_data = &adapter->algo_data;
+	adapter->adapter.dev.parent = port->physport->dev;
 
 	if (parport_claim_or_block(adapter->pdev) < 0) {
 		printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
@@ -214,11 +215,12 @@ static void i2c_parport_detach (struct p
 	for (prev = NULL, adapter = adapter_list; adapter;
 	     prev = adapter, adapter = adapter->next) {
 		if (adapter->pdev->port == port) {
+			i2c_del_adapter(&adapter->adapter);
+
 			/* Un-init if needed (power off...) */
 			if (adapter_parm[type].init.val)
 				line_set(port, 0, &adapter_parm[type].init);
 				
-			i2c_del_adapter(&adapter->adapter);
 			parport_unregister_device(adapter->pdev);
 			if (prev)
 				prev->next = adapter->next;
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index bf89eee..58e3271 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(st
 	}
 
 	smbus->adapter.owner = THIS_MODULE;
-	snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
 		 "PA Semi SMBus adapter at 0x%lx", smbus->base);
 	smbus->adapter.class = I2C_CLASS_HWMON;
 	smbus->adapter.algo = &smbus_algorithm;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index cc6536a..5161aaf 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -25,9 +25,9 @@ #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/wait.h>
 
+#include <linux/isa.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pca.h>
 
@@ -119,27 +119,26 @@ static struct i2c_adapter pca_isa_ops = 
 	.name		= "PCA9564 ISA Adapter",
 };
 
-static int __init pca_isa_init(void)
+static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
 {
-
 	init_waitqueue_head(&pca_wait);
 
-	printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq);
+	dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
 
 	if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
-		printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base);
+		dev_err(dev, "I/O address %#08lx is in use\n", base);
 		goto out;
 	}
 
 	if (irq > -1) {
 		if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
-			printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq);
+			dev_err(dev, "Request irq%d failed\n", irq);
 			goto out_region;
 		}
 	}
 
 	if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
-		printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n");
+		dev_err(dev, "Failed to add i2c bus\n");
 		goto out_irq;
 	}
 
@@ -154,7 +153,7 @@ static int __init pca_isa_init(void)
 	return -ENODEV;
 }
 
-static void pca_isa_exit(void)
+static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
 {
 	i2c_del_adapter(&pca_isa_ops);
 
@@ -163,6 +162,27 @@ static void pca_isa_exit(void)
 		free_irq(irq, &pca_isa_ops);
 	}
 	release_region(base, IO_SIZE);
+
+	return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+	.probe		= pca_isa_probe,
+	.remove		= __devexit_p(pca_isa_remove),
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "i2c-pca-isa",
+	}
+};
+
+static int __init pca_isa_init(void)
+{
+	return isa_register_driver(&pca_isa_driver, 1);
+}
+
+static void __exit pca_isa_exit(void)
+{
+	isa_unregister_driver(&pca_isa_driver);
 }
 
 MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 21b1809..5a52bf5 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct 
 	/* set up the sysfs linkage to our parent device */
 	piix4_adapter.dev.parent = &dev->dev;
 
-	snprintf(piix4_adapter.name, I2C_NAME_SIZE,
+	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
 		"SMBus PIIX4 adapter at %04x", piix4_smba);
 
 	if ((retval = i2c_add_adapter(&piix4_adapter))) {
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 14e83d0..873544a 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -539,6 +539,18 @@ static inline void i2c_pxa_start_message
 	writel(icr | ICR_START | ICR_TB, _ICR(i2c));
 }
 
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+	u32 icr;
+
+	/*
+	 * Clear the STOP and ACK flags
+	 */
+	icr = readl(_ICR(i2c));
+	icr &= ~(ICR_STOP | ICR_ACKNAK);
+	writel(icr, _IRC(i2c));
+}
+
 /*
  * We are protected by the adapter bus mutex.
  */
@@ -581,6 +593,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2
 	 * The rest of the processing occurs in the interrupt handler.
 	 */
 	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+	i2c_pxa_stop_message(i2c);
 
 	/*
 	 * We place the return code in i2c->msg_idx.
@@ -825,7 +838,7 @@ static const struct i2c_algorithm i2c_px
 };
 
 static struct pxa_i2c i2c_pxa = {
-	.lock	= SPIN_LOCK_UNLOCKED,
+	.lock	= __SPIN_LOCK_UNLOCKED(i2c_pxa.lock),
 	.adap	= {
 		.owner		= THIS_MODULE,
 		.algo		= &i2c_pxa_algorithm,
@@ -839,9 +852,7 @@ static int i2c_pxa_probe(struct platform
 {
 	struct pxa_i2c *i2c = &i2c_pxa;
 	struct resource *res;
-#ifdef CONFIG_I2C_PXA_SLAVE
 	struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
-#endif
 	int ret;
 	int irq;
 
@@ -889,14 +900,14 @@ #ifdef CONFIG_PXA27x
 		pxa_gpio_mode(GPIO117_I2CSCL_MD);
 		pxa_gpio_mode(GPIO118_I2CSDA_MD);
 #endif
-		pxa_set_cken(CKEN14_I2C, 1);
+		pxa_set_cken(CKEN_I2C, 1);
 		break;
 #ifdef CONFIG_PXA27x
 	case 1:
 		local_irq_disable();
 		PCFR |= PCFR_PI2CEN;
 		local_irq_enable();
-		pxa_set_cken(CKEN15_PWRI2C, 1);
+		pxa_set_cken(CKEN_PWRI2C, 1);
 #endif
 	}
 
@@ -911,6 +922,10 @@ #endif
 	i2c->adap.algo_data = i2c;
 	i2c->adap.dev.parent = &dev->dev;
 
+	if (plat) {
+		i2c->adap.class = plat->class;
+	}
+
 	ret = i2c_add_adapter(&i2c->adap);
 	if (ret < 0) {
 		printk(KERN_INFO "I2C: Failed to add bus\n");
@@ -933,11 +948,11 @@ eadapt:
 ereqirq:
 	switch (dev->id) {
 	case 0:
-		pxa_set_cken(CKEN14_I2C, 0);
+		pxa_set_cken(CKEN_I2C, 0);
 		break;
 #ifdef CONFIG_PXA27x
 	case 1:
-		pxa_set_cken(CKEN15_PWRI2C, 0);
+		pxa_set_cken(CKEN_PWRI2C, 0);
 		local_irq_disable();
 		PCFR &= ~PCFR_PI2CEN;
 		local_irq_enable();
@@ -960,11 +975,11 @@ static int i2c_pxa_remove(struct platfor
 	free_irq(i2c->irq, i2c);
 	switch (dev->id) {
 	case 0:
-		pxa_set_cken(CKEN14_I2C, 0);
+		pxa_set_cken(CKEN_I2C, 0);
 		break;
 #ifdef CONFIG_PXA27x
 	case 1:
-		pxa_set_cken(CKEN15_PWRI2C, 0);
+		pxa_set_cken(CKEN_PWRI2C, 0);
 		local_irq_disable();
 		PCFR &= ~PCFR_PI2CEN;
 		local_irq_enable();
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 556f244..e68a96f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -61,6 +61,8 @@ struct s3c24xx_i2c {
 	unsigned int		msg_idx;
 	unsigned int		msg_ptr;
 
+	unsigned int		tx_setup;
+
 	enum s3c24xx_i2c_state	state;
 
 	void __iomem		*regs;
@@ -199,8 +201,11 @@ static void s3c24xx_i2c_message_start(st
 	dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
 	writeb(addr, i2c->regs + S3C2410_IICDS);
 	
-	// delay a bit and reset iiccon before setting start (per samsung)
-	udelay(1);
+	/* delay here to ensure the data byte has gotten onto the bus
+	 * before the transaction is started */
+
+	ndelay(i2c->tx_setup);
+
 	dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
 	writel(iiccon, i2c->regs + S3C2410_IICCON);
 	
@@ -322,7 +327,15 @@ static int i2s_s3c_irq_nextbyte(struct s
 		if (!is_msgend(i2c)) {
 			byte = i2c->msg->buf[i2c->msg_ptr++];
 			writeb(byte, i2c->regs + S3C2410_IICDS);
-			
+
+			/* delay after writing the byte to allow the
+			 * data setup time on the bus, as writing the
+			 * data to the register causes the first bit
+			 * to appear on SDA, and SCL will change as
+			 * soon as the interrupt is acknowledged */
+
+			ndelay(i2c->tx_setup);
+
 		} else if (!is_lastmsg(i2c)) {
 			/* we need to go to the next i2c message */
 
@@ -570,9 +583,10 @@ static const struct i2c_algorithm s3c24x
 };
 
 static struct s3c24xx_i2c s3c24xx_i2c = {
-	.lock	= SPIN_LOCK_UNLOCKED,
-	.wait	= __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
-	.adap	= {
+	.lock		= __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
+	.wait		= __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
+	.tx_setup	= 50,
+	.adap		= {
 		.name			= "s3c2410-i2c",
 		.owner			= THIS_MODULE,
 		.algo			= &s3c24xx_i2c_algorithm,
@@ -731,26 +745,6 @@ static int s3c24xx_i2c_init(struct s3c24
 	return 0;
 }
 
-static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
-{
-	if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
-		clk_disable(i2c->clk);
-		clk_put(i2c->clk);
-		i2c->clk = NULL;
-	}
-
-	if (i2c->regs != NULL) {
-		iounmap(i2c->regs);
-		i2c->regs = NULL;
-	}
-
-	if (i2c->ioarea != NULL) {
-		release_resource(i2c->ioarea);
-		kfree(i2c->ioarea);
-		i2c->ioarea = NULL;
-	}
-}
-
 /* s3c24xx_i2c_probe
  *
  * called by the bus driver when a suitable device is found
@@ -769,7 +763,7 @@ static int s3c24xx_i2c_probe(struct plat
 	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "cannot get clock\n");
 		ret = -ENOENT;
-		goto out;
+		goto err_noclk;
 	}
 
 	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
@@ -782,7 +776,7 @@ static int s3c24xx_i2c_probe(struct plat
 	if (res == NULL) {
 		dev_err(&pdev->dev, "cannot find IO resource\n");
 		ret = -ENOENT;
-		goto out;
+		goto err_clk;
 	}
 
 	i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
@@ -791,7 +785,7 @@ static int s3c24xx_i2c_probe(struct plat
 	if (i2c->ioarea == NULL) {
 		dev_err(&pdev->dev, "cannot request IO\n");
 		ret = -ENXIO;
-		goto out;
+		goto err_clk;
 	}
 
 	i2c->regs = ioremap(res->start, (res->end-res->start)+1);
@@ -799,7 +793,7 @@ static int s3c24xx_i2c_probe(struct plat
 	if (i2c->regs == NULL) {
 		dev_err(&pdev->dev, "cannot map IO\n");
 		ret = -ENXIO;
-		goto out;
+		goto err_ioarea;
 	}
 
 	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
@@ -813,7 +807,7 @@ static int s3c24xx_i2c_probe(struct plat
 
 	ret = s3c24xx_i2c_init(i2c);
 	if (ret != 0)
-		goto out;
+		goto err_iomap;
 
 	/* find the IRQ for this unit (note, this relies on the init call to
 	 * ensure no current IRQs pending 
@@ -823,7 +817,7 @@ static int s3c24xx_i2c_probe(struct plat
 	if (res == NULL) {
 		dev_err(&pdev->dev, "cannot find IRQ\n");
 		ret = -ENOENT;
-		goto out;
+		goto err_iomap;
 	}
 
 	ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
@@ -831,7 +825,7 @@ static int s3c24xx_i2c_probe(struct plat
 
 	if (ret != 0) {
 		dev_err(&pdev->dev, "cannot claim IRQ\n");
-		goto out;
+		goto err_iomap;
 	}
 
 	i2c->irq = res;
@@ -841,17 +835,29 @@ static int s3c24xx_i2c_probe(struct plat
 	ret = i2c_add_adapter(&i2c->adap);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
-		goto out;
+		goto err_irq;
 	}
 
 	platform_set_drvdata(pdev, i2c);
 
 	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+	return 0;
 
- out:
-	if (ret < 0)
-		s3c24xx_i2c_free(i2c);
+ err_irq:
+	free_irq(i2c->irq->start, i2c);
+
+ err_iomap:
+	iounmap(i2c->regs);
 
+ err_ioarea:
+	release_resource(i2c->ioarea);
+	kfree(i2c->ioarea);
+
+ err_clk:
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+ err_noclk:
 	return ret;
 }
 
@@ -863,11 +869,17 @@ static int s3c24xx_i2c_probe(struct plat
 static int s3c24xx_i2c_remove(struct platform_device *pdev)
 {
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
-	
-	if (i2c != NULL) {
-		s3c24xx_i2c_free(i2c);
-		platform_set_drvdata(pdev, NULL);
-	}
+
+	i2c_del_adapter(&i2c->adap);
+	free_irq(i2c->irq->start, i2c);
+
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+	iounmap(i2c->regs);
+
+	release_resource(i2c->ioarea);
+	kfree(i2c->ioarea);
 
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 0000000..10af8d3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+struct simtec_i2c_data {
+	struct resource		*ioarea;
+	void __iomem		*reg;
+	struct i2c_adapter	 adap;
+	struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA	(1<<2)
+#define CMD_SET_SCL	(1<<3)
+
+#define STATE_SDA	(1<<0)
+#define STATE_SCL	(1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+	struct simtec_i2c_data *pd = pw;
+	writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+	struct simtec_i2c_data *pd = pw;
+	writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+	struct simtec_i2c_data *pd = pw;
+	return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+	struct simtec_i2c_data *pd = pw;
+	return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+	struct simtec_i2c_data *pd;
+	struct resource *res;
+	int size;
+	int ret;
+
+	pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+	if (pd == NULL) {
+		dev_err(&dev->dev, "cannot allocate private data\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(dev, pd);
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&dev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	size = (res->end-res->start)+1;
+
+	pd->ioarea = request_mem_region(res->start, size, dev->name);
+	if (pd->ioarea == NULL) {
+		dev_err(&dev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err;
+	}
+
+	pd->reg = ioremap(res->start, size);
+	if (pd->reg == NULL) {
+		dev_err(&dev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_res;
+	}
+
+	/* setup the private data */
+
+	pd->adap.owner = THIS_MODULE;
+	pd->adap.algo_data = &pd->bit;
+	pd->adap.dev.parent = &dev->dev;
+
+	strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+	pd->bit.data = pd;
+	pd->bit.setsda = simtec_i2c_setsda;
+	pd->bit.setscl = simtec_i2c_setscl;
+	pd->bit.getsda = simtec_i2c_getsda;
+	pd->bit.getscl = simtec_i2c_getscl;
+	pd->bit.timeout = HZ;
+	pd->bit.udelay = 20;
+
+	ret = i2c_bit_add_bus(&pd->adap);
+	if (ret)
+		goto err_all;
+
+	return 0;
+
+ err_all:
+	iounmap(pd->reg);
+
+ err_res:
+	release_resource(pd->ioarea);
+	kfree(pd->ioarea);
+
+ err:
+	kfree(pd);
+	return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+	struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+	i2c_del_adapter(&pd->adap);
+
+	iounmap(pd->reg);
+	release_resource(pd->ioarea);
+	kfree(pd->ioarea);
+	kfree(pd);
+
+	return 0;
+}
+
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+	.driver		= {
+		.name		= "simtec-i2c",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= simtec_i2c_probe,
+	.remove		= simtec_i2c_remove,
+};
+
+static int __init i2c_adap_simtec_init(void)
+{
+	return platform_driver_register(&simtec_i2c_driver);
+}
+
+static void __exit i2c_adap_simtec_exit(void)
+{
+	platform_driver_unregister(&simtec_i2c_driver);
+}
+
+module_init(i2c_adap_simtec_init);
+module_exit(i2c_adap_simtec_exit);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 4157b0c..dc235bb 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct
 	/* set up the sysfs linkage to our parent device */
 	sis96x_adapter.dev.parent = &dev->dev;
 
-	snprintf(sis96x_adapter.name, I2C_NAME_SIZE,
+	snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
 		"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
 
 	if ((retval = i2c_add_adapter(&sis96x_adapter))) {
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 0000000..9079990
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,277 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+/* include interfaces to usb layer */
+#include <linux/usb.h>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO		0
+#define CMD_GET_FUNC		1
+#define CMD_SET_DELAY		2
+#define CMD_GET_STATUS		3
+
+#define CMD_I2C_IO		4
+#define CMD_I2C_IO_BEGIN	(1<<0)
+#define CMD_I2C_IO_END		(1<<1)
+
+/* i2c bit delay, default is 10us -> 100kHz */
+static int delay = 10;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds, "
+		 "e.g. 10 for 100kHz (default is 100kHz)");
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+		    int value, int index, void *data, int len);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+		     int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE		0
+#define STATUS_ADDRESS_ACK	1
+#define STATUS_ADDRESS_NAK	2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+	unsigned char status;
+	struct i2c_msg *pmsg;
+	int i;
+
+	dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+	for (i = 0 ; i < num ; i++) {
+		int cmd = CMD_I2C_IO;
+
+		if (i == 0)
+			cmd |= CMD_I2C_IO_BEGIN;
+
+		if (i == num-1)
+			cmd |= CMD_I2C_IO_END;
+
+		pmsg = &msgs[i];
+
+		dev_dbg(&adapter->dev,
+			"  %d: %s (flags %d) %d bytes to 0x%02x\n",
+			i, pmsg->flags & I2C_M_RD ? "read" : "write",
+			pmsg->flags, pmsg->len, pmsg->addr);
+
+		/* and directly send the message */
+		if (pmsg->flags & I2C_M_RD) {
+			/* read data */
+			if (usb_read(adapter, cmd,
+				     pmsg->flags, pmsg->addr,
+				     pmsg->buf, pmsg->len) != pmsg->len) {
+				dev_err(&adapter->dev,
+					"failure reading data\n");
+				return -EREMOTEIO;
+			}
+		} else {
+			/* write data */
+			if (usb_write(adapter, cmd,
+				      pmsg->flags, pmsg->addr,
+				      pmsg->buf, pmsg->len) != pmsg->len) {
+				dev_err(&adapter->dev,
+					"failure writing data\n");
+				return -EREMOTEIO;
+			}
+		}
+
+		/* read status */
+		if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+			dev_err(&adapter->dev, "failure reading status\n");
+			return -EREMOTEIO;
+		}
+
+		dev_dbg(&adapter->dev, "  status = %d\n", status);
+		if (status == STATUS_ADDRESS_NAK)
+			return -EREMOTEIO;
+	}
+
+	return i;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+	u32 func;
+
+	/* get functionality from adapter */
+	if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
+	    sizeof(func)) {
+		dev_err(&adapter->dev, "failure reading functionality\n");
+		return 0;
+	}
+
+	return func;
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+	.master_xfer	= usb_xfer,
+	.functionality	= usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/* The usb i2c interface uses a vid/pid pair donated by */
+/* Future Technology Devices International Ltd. */
+static struct usb_device_id i2c_tiny_usb_table [] = {
+	{ USB_DEVICE(0x0403, 0xc631) },
+	{ }			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+	struct usb_device *usb_dev; /* the usb device for this device */
+	struct usb_interface *interface; /* the interface for this device */
+	struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+		    int value, int index, void *data, int len)
+{
+	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+	/* do control transfer */
+	return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+			       USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+		     int value, int index, void *data, int len)
+{
+	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+	/* do control transfer */
+	return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			       value, index, data, len, 2000);
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+	usb_put_dev(dev->usb_dev);
+	kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+			      const struct usb_device_id *id)
+{
+	struct i2c_tiny_usb *dev;
+	int retval = -ENOMEM;
+	u16 version;
+
+	dev_dbg(&interface->dev, "probing usb device\n");
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&interface->dev, "Out of memory\n");
+		goto error;
+	}
+
+	dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+	dev_info(&interface->dev,
+		 "version %x.%02x found at bus %03d address %03d\n",
+		 version >> 8, version & 0xff,
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+	/* setup i2c adapter description */
+	dev->adapter.owner = THIS_MODULE;
+	dev->adapter.class = I2C_CLASS_HWMON;
+	dev->adapter.algo = &usb_algorithm;
+	dev->adapter.algo_data = dev;
+	snprintf(dev->adapter.name, I2C_NAME_SIZE,
+		 "i2c-tiny-usb at bus %03d device %03d",
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+	if (usb_write(&dev->adapter, CMD_SET_DELAY,
+		      cpu_to_le16(delay), 0, NULL, 0) != 0) {
+		dev_err(&dev->adapter.dev,
+			"failure setting delay to %dus\n", delay);
+		retval = -EIO;
+		goto error;
+	}
+
+	dev->adapter.dev.parent = &dev->interface->dev;
+
+	/* and finally attach to i2c layer */
+	i2c_add_adapter(&dev->adapter);
+
+	/* inform user about successful attachment to i2c layer */
+	dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+	return 0;
+
+ error:
+	if (dev)
+		i2c_tiny_usb_free(dev);
+
+	return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+	struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+	i2c_del_adapter(&dev->adapter);
+	usb_set_intfdata(interface, NULL);
+	i2c_tiny_usb_free(dev);
+
+	dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+	.name		= "i2c-tiny-usb",
+	.probe		= i2c_tiny_usb_probe,
+	.disconnect	= i2c_tiny_usb_disconnect,
+	.id_table	= i2c_tiny_usb_table,
+};
+
+static int __init usb_i2c_tiny_usb_init(void)
+{
+	/* register this driver with the USB subsystem */
+	return usb_register(&i2c_tiny_usb_driver);
+}
+
+static void __exit usb_i2c_tiny_usb_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&i2c_tiny_usb_driver);
+}
+
+module_init(usb_i2c_tiny_usb_init);
+module_exit(usb_i2c_tiny_usb_exit);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 03c5fc8..7a2bc06 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -404,7 +404,7 @@ found:
 	}
 
 	vt596_adapter.dev.parent = &pdev->dev;
-	snprintf(vt596_adapter.name, I2C_NAME_SIZE,
+	snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
 		 "SMBus Via Pro adapter at %04x", vt596_smba);
 
 	vt596_pdev = pci_dev_get(pdev);
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 0b082c5..0d6bd4f 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -28,7 +28,6 @@ #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -441,7 +440,7 @@ static __init struct scx200_acb_iface *s
 
 	adapter = &iface->adapter;
 	i2c_set_adapdata(adapter, iface);
-	snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index);
+	snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
 	adapter->owner = THIS_MODULE;
 	adapter->id = I2C_HW_SMBUS_SCX200;
 	adapter->algo = &scx200_acb_algorithm;
@@ -599,6 +598,7 @@ static __init int scx200_scan_pci(void)
 		else {
 			int i;
 
+			pci_dev_put(pdev);
 			for (i = 0; i < MAX_DEVICES; ++i) {
 				if (base[i] == 0)
 					continue;
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 87ee3ce..ea085a0 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -3,11 +3,10 @@ # Miscellaneous I2C chip drivers configu
 #
 
 menu "Miscellaneous I2C Chip support"
-	depends on I2C
 
 config SENSORS_DS1337
 	tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for Dallas Semiconductor
 	  DS1337 and DS1339 real-time clock chips.
@@ -17,7 +16,7 @@ config SENSORS_DS1337
 
 config SENSORS_DS1374
 	tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for Dallas Semiconductor
 	  DS1374 real-time clock chips.
@@ -27,7 +26,7 @@ config SENSORS_DS1374
 
 config SENSORS_EEPROM
 	tristate "EEPROM reader"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get read-only access to the EEPROM data
 	  available on modern memory DIMMs and Sony Vaio laptops.  Such
@@ -38,7 +37,7 @@ config SENSORS_EEPROM
 
 config SENSORS_PCF8574
 	tristate "Philips PCF8574 and PCF8574A"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	default n
 	help
 	  If you say yes here you get support for Philips PCF8574 and 
@@ -52,7 +51,7 @@ config SENSORS_PCF8574
 
 config SENSORS_PCA9539
 	tristate "Philips PCA9539 16-bit I/O port"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Philips PCA9539
 	  16-bit I/O port.
@@ -62,7 +61,7 @@ config SENSORS_PCA9539
 
 config SENSORS_PCF8591
 	tristate "Philips PCF8591"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	default n
 	help
 	  If you say yes here you get support for Philips PCF8591 chips.
@@ -75,7 +74,7 @@ config SENSORS_PCF8591
 
 config ISP1301_OMAP
 	tristate "Philips ISP1301 with OMAP OTG"
-	depends on I2C && ARCH_OMAP_OTG
+	depends on ARCH_OMAP_OTG
 	help
 	  If you say yes here you get support for the Philips ISP1301
 	  USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -90,7 +89,7 @@ # interface location in  <include/asm-ar
 # and having mostly OMAP-specific board support
 config TPS65010
 	tristate "TPS6501x Power Management chips"
-	depends on I2C && ARCH_OMAP
+	depends on ARCH_OMAP
 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
 	help
 	  If you say yes here you get support for the TPS6501x series of
@@ -103,7 +102,7 @@ config TPS65010
 
 config SENSORS_M41T00
 	tristate "ST M41T00 RTC chip"
-	depends on I2C && PPC32
+	depends on PPC32
 	help
 	  If you say yes here you get support for the ST M41T00 RTC chip.
 
@@ -112,7 +111,7 @@ config SENSORS_M41T00
 
 config SENSORS_MAX6875
 	tristate "Maxim MAX6875 Power supply supervisor"
-	depends on I2C && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for the Maxim MAX6875
 	  EEPROM-programmable, quad power-supply sequencer/supervisor.
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 214fbb1..7ed92dc 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -351,8 +351,10 @@ static void tps65010_interrupt(struct tp
 #if 0
 			/* REVISIT:  this might need its own workqueue
 			 * plus tweaks including deadlock avoidance ...
+			 * also needs to get error handling and probably
+			 * an #ifdef CONFIG_SOFTWARE_SUSPEND
 			 */
-			software_suspend();
+			pm_suspend(PM_SUSPEND_DISK);
 #endif
 			poll = 1;
 		}
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
new file mode 100644
index 0000000..ffb35f0
--- /dev/null
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -0,0 +1,90 @@
+/*
+ * i2c-boardinfo.h - collect pre-declarations of I2C 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/i2c.h>
+
+#include "i2c-core.h"
+
+
+/* These symbols are exported ONLY FOR the i2c core.
+ * No other users will be supported.
+ */
+DEFINE_MUTEX(__i2c_board_lock);
+EXPORT_SYMBOL_GPL(__i2c_board_lock);
+
+LIST_HEAD(__i2c_board_list);
+EXPORT_SYMBOL_GPL(__i2c_board_list);
+
+int __i2c_first_dynamic_bus_num;
+EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
+
+
+/**
+ * i2c_register_board_info - statically declare I2C devices
+ * @busnum: identifies the bus to which these devices belong
+ * @info: vector of i2c device descriptors
+ * @len: how many descriptors in the vector; may be zero to reserve
+ *	the specified bus number.
+ *
+ * Systems using the Linux I2C driver stack can declare tables of board info
+ * while they initialize.  This should be done in board-specific init code
+ * near arch_initcall() time, or equivalent, before any I2C adapter driver is
+ * registered.  For example, mainboard init code could define several devices,
+ * as could the init code for each daughtercard in a board stack.
+ *
+ * The I2C devices will be created later, after the adapter for the relevant
+ * bus has been registered.  After that moment, standard driver model tools
+ * are used to bind "new style" I2C drivers to the devices.  The bus number
+ * for any device declared using this routine is not available for dynamic
+ * allocation.
+ *
+ * The board info passed can safely be __initdata, but be careful of embedded
+ * pointers (for platform_data, functions, etc) since that won't be copied.
+ */
+int __init
+i2c_register_board_info(int busnum,
+	struct i2c_board_info const *info, unsigned len)
+{
+	int status;
+
+	mutex_lock(&__i2c_board_lock);
+
+	/* dynamic bus numbers will be assigned after the last static one */
+	if (busnum >= __i2c_first_dynamic_bus_num)
+		__i2c_first_dynamic_bus_num = busnum + 1;
+
+	for (status = 0; len; len--, info++) {
+		struct i2c_devinfo	*devinfo;
+
+		devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
+		if (!devinfo) {
+			pr_debug("i2c-core: can't register boardinfo!\n");
+			status = -ENOMEM;
+			break;
+		}
+
+		devinfo->busnum = busnum;
+		devinfo->board_info = *info;
+		list_add_tail(&devinfo->list, &__i2c_board_list);
+	}
+
+	mutex_unlock(&__i2c_board_lock);
+
+	return status;
+}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 21fe140..64f8e56 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -35,29 +35,92 @@ #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <asm/uaccess.h>
 
+#include "i2c-core.h"
+
 
 static LIST_HEAD(adapters);
 static LIST_HEAD(drivers);
 static DEFINE_MUTEX(core_lists);
 static DEFINE_IDR(i2c_adapter_idr);
 
+#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
 
 /* ------------------------------------------------------------------------- */
 
-/* match always succeeds, as we want the probe() to tell if we really accept this match */
 static int i2c_device_match(struct device *dev, struct device_driver *drv)
 {
-	return 1;
+	struct i2c_client	*client = to_i2c_client(dev);
+	struct i2c_driver	*driver = to_i2c_driver(drv);
+
+	/* make legacy i2c drivers bypass driver model probing entirely;
+	 * such drivers scan each i2c adapter/bus themselves.
+	 */
+	if (!is_newstyle_driver(driver))
+		return 0;
+
+	/* new style drivers use the same kind of driver matching policy
+	 * as platform devices or SPI:  compare device and driver IDs.
+	 */
+	return strcmp(client->driver_name, drv->name) == 0;
+}
+
+#ifdef	CONFIG_HOTPLUG
+
+/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
+static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
+		      char *buffer, int buffer_size)
+{
+	struct i2c_client	*client = to_i2c_client(dev);
+	int			i = 0, length = 0;
+
+	/* by definition, legacy drivers can't hotplug */
+	if (dev->driver || !client->driver_name)
+		return 0;
+
+	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+			"MODALIAS=%s", client->driver_name))
+		return -ENOMEM;
+	envp[i] = NULL;
+	dev_dbg(dev, "uevent\n");
+	return 0;
 }
 
+#else
+#define i2c_device_uevent	NULL
+#endif	/* CONFIG_HOTPLUG */
+
 static int i2c_device_probe(struct device *dev)
 {
-	return -ENODEV;
+	struct i2c_client	*client = to_i2c_client(dev);
+	struct i2c_driver	*driver = to_i2c_driver(dev->driver);
+
+	if (!driver->probe)
+		return -ENODEV;
+	client->driver = driver;
+	dev_dbg(dev, "probe\n");
+	return driver->probe(client);
 }
 
 static int i2c_device_remove(struct device *dev)
 {
-	return 0;
+	struct i2c_client	*client = to_i2c_client(dev);
+	struct i2c_driver	*driver;
+	int			status;
+
+	if (!dev->driver)
+		return 0;
+
+	driver = to_i2c_driver(dev->driver);
+	if (driver->remove) {
+		dev_dbg(dev, "remove\n");
+		status = driver->remove(client);
+	} else {
+		dev->driver = NULL;
+		status = 0;
+	}
+	if (status == 0)
+		client->driver = NULL;
+	return status;
 }
 
 static void i2c_device_shutdown(struct device *dev)
@@ -95,122 +158,184 @@ static int i2c_device_resume(struct devi
 	return driver->resume(to_i2c_client(dev));
 }
 
+static void i2c_client_release(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	complete(&client->released);
+}
+
+static void i2c_client_dev_release(struct device *dev)
+{
+	kfree(to_i2c_client(dev));
+}
+
+static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	return sprintf(buf, "%s\n", client->name);
+}
+
+static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	return client->driver_name
+		? sprintf(buf, "%s\n", client->driver_name)
+		: 0;
+}
+
+static struct device_attribute i2c_dev_attrs[] = {
+	__ATTR(name, S_IRUGO, show_client_name, NULL),
+	/* modalias helps coldplug:  modprobe $(cat .../modalias) */
+	__ATTR(modalias, S_IRUGO, show_modalias, NULL),
+	{ },
+};
+
 struct bus_type i2c_bus_type = {
 	.name		= "i2c",
+	.dev_attrs	= i2c_dev_attrs,
 	.match		= i2c_device_match,
+	.uevent		= i2c_device_uevent,
 	.probe		= i2c_device_probe,
 	.remove		= i2c_device_remove,
 	.shutdown	= i2c_device_shutdown,
 	.suspend	= i2c_device_suspend,
 	.resume		= i2c_device_resume,
 };
+EXPORT_SYMBOL_GPL(i2c_bus_type);
 
-/* ------------------------------------------------------------------------- */
+/**
+ * i2c_new_device - instantiate an i2c device for use with a new style driver
+ * @adap: the adapter managing the device
+ * @info: describes one I2C device; bus_num is ignored
+ *
+ * Create a device to work with a new style i2c driver, where binding is
+ * handled through driver model probe()/remove() methods.  This call is not
+ * appropriate for use by mainboad initialization logic, which usually runs
+ * during an arch_initcall() long before any i2c_adapter could exist.
+ *
+ * This returns the new i2c client, which may be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+{
+	struct i2c_client	*client;
+	int			status;
 
-void i2c_adapter_dev_release(struct device *dev)
+	client = kzalloc(sizeof *client, GFP_KERNEL);
+	if (!client)
+		return NULL;
+
+	client->adapter = adap;
+
+	client->dev.platform_data = info->platform_data;
+	client->flags = info->flags;
+	client->addr = info->addr;
+	client->irq = info->irq;
+
+	strlcpy(client->driver_name, info->driver_name,
+		sizeof(client->driver_name));
+	strlcpy(client->name, info->type, sizeof(client->name));
+
+	/* a new style driver may be bound to this device when we
+	 * return from this function, or any later moment (e.g. maybe
+	 * hotplugging will load the driver module).  and the device
+	 * refcount model is the standard driver model one.
+	 */
+	status = i2c_attach_client(client);
+	if (status < 0) {
+		kfree(client);
+		client = NULL;
+	}
+	return client;
+}
+EXPORT_SYMBOL_GPL(i2c_new_device);
+
+
+/**
+ * i2c_unregister_device - reverse effect of i2c_new_device()
+ * @client: value returned from i2c_new_device()
+ */
+void i2c_unregister_device(struct i2c_client *client)
 {
-	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
-	complete(&adap->dev_released);
+	struct i2c_adapter	*adapter = client->adapter;
+	struct i2c_driver	*driver = client->driver;
+
+	if (driver && !is_newstyle_driver(driver)) {
+		dev_err(&client->dev, "can't unregister devices "
+			"with legacy drivers\n");
+		WARN_ON(1);
+		return;
+	}
+
+	mutex_lock(&adapter->clist_lock);
+	list_del(&client->list);
+	mutex_unlock(&adapter->clist_lock);
+
+	device_unregister(&client->dev);
 }
+EXPORT_SYMBOL_GPL(i2c_unregister_device);
 
-struct device_driver i2c_adapter_driver = {
-	.owner = THIS_MODULE,
-	.name =	"i2c_adapter",
-	.bus = &i2c_bus_type,
-};
 
 /* ------------------------------------------------------------------------- */
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
 
-static void i2c_adapter_class_dev_release(struct class_device *dev)
+void i2c_adapter_dev_release(struct device *dev)
 {
-	struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
-	complete(&adap->class_dev_released);
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	complete(&adap->dev_released);
 }
+EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);	/* exported to i2c-isa */
 
-static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf)
+static ssize_t
+show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
 	return sprintf(buf, "%s\n", adap->name);
 }
 
-static struct class_device_attribute i2c_adapter_attrs[] = {
-	__ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL),
+static struct device_attribute i2c_adapter_attrs[] = {
+	__ATTR(name, S_IRUGO, show_adapter_name, NULL),
 	{ },
 };
 
 struct class i2c_adapter_class = {
 	.owner			= THIS_MODULE,
 	.name			= "i2c-adapter",
-	.class_dev_attrs	= i2c_adapter_attrs,
-	.release		= &i2c_adapter_class_dev_release,
+	.dev_attrs		= i2c_adapter_attrs,
 };
+EXPORT_SYMBOL_GPL(i2c_adapter_class);		/* exported to i2c-isa */
 
-static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
-	return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
-
-
-static void i2c_client_release(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	complete(&client->released);
-}
-
-static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
+static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	return sprintf(buf, "%s\n", client->name);
+	struct i2c_devinfo	*devinfo;
+
+	mutex_lock(&__i2c_board_lock);
+	list_for_each_entry(devinfo, &__i2c_board_list, list) {
+		if (devinfo->busnum == adapter->nr
+				&& !i2c_new_device(adapter,
+						&devinfo->board_info))
+			printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",
+				i2c_adapter_id(adapter),
+				devinfo->board_info.addr);
+	}
+	mutex_unlock(&__i2c_board_lock);
 }
 
-/*
- * We can't use the DEVICE_ATTR() macro here, as we used the same name for
- * an i2c adapter attribute (above).
- */
-static struct device_attribute dev_attr_client_name =
-	__ATTR(name, S_IRUGO, &show_client_name, NULL);
-
-
-/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
- */
-
-/* -----
- * i2c_add_adapter is called from within the algorithm layer,
- * when a new hw adapter registers. A new device is register to be
- * available for clients.
- */
-int i2c_add_adapter(struct i2c_adapter *adap)
+static int i2c_register_adapter(struct i2c_adapter *adap)
 {
-	int id, res = 0;
+	int res = 0;
 	struct list_head   *item;
 	struct i2c_driver  *driver;
 
-	mutex_lock(&core_lists);
-
-	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
-		res = -ENOMEM;
-		goto out_unlock;
-	}
-
-	res = idr_get_new(&i2c_adapter_idr, adap, &id);
-	if (res < 0) {
-		if (res == -EAGAIN)
-			res = -ENOMEM;
-		goto out_unlock;
-	}
-
-	adap->nr =  id & MAX_ID_MASK;
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
-	list_add_tail(&adap->list,&adapters);
 	INIT_LIST_HEAD(&adap->clients);
 
+	mutex_lock(&core_lists);
+	list_add_tail(&adap->list, &adapters);
+
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
 	 * we add this adapter to the host bus.
@@ -221,27 +346,19 @@ int i2c_add_adapter(struct i2c_adapter *
 			 "physical device\n", adap->name);
 	}
 	sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
-	adap->dev.driver = &i2c_adapter_driver;
 	adap->dev.release = &i2c_adapter_dev_release;
+	adap->dev.class = &i2c_adapter_class;
 	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);
-	res = class_device_register(&adap->class_dev);
-	if (res)
-		goto out_remove_name;
 
 	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
 
-	/* inform drivers of new adapters */
+	/* create pre-declared device nodes for new-style drivers */
+	if (adap->nr < __i2c_first_dynamic_bus_num)
+		i2c_scan_static_board_info(adap);
+
+	/* let legacy drivers scan this bus for matching devices */
 	list_for_each(item,&drivers) {
 		driver = list_entry(item, struct i2c_driver, list);
 		if (driver->attach_adapter)
@@ -253,18 +370,98 @@ 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;
 }
 
+/**
+ * i2c_add_adapter - declare i2c adapter, use dynamic bus number
+ * @adapter: the adapter to add
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter.  Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adapter)
+{
+	int	id, res = 0;
+
+retry:
+	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+		return -ENOMEM;
+
+	mutex_lock(&core_lists);
+	/* "above" here means "above or equal to", sigh */
+	res = idr_get_new_above(&i2c_adapter_idr, adapter,
+				__i2c_first_dynamic_bus_num, &id);
+	mutex_unlock(&core_lists);
+
+	if (res < 0) {
+		if (res == -EAGAIN)
+			goto retry;
+		return res;
+	}
+
+	adapter->nr = id;
+	return i2c_register_adapter(adapter);
+}
+EXPORT_SYMBOL(i2c_add_adapter);
+
+/**
+ * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
+ * @adap: the adapter to register (with adap->nr initialized)
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters.  Example: for I2C adapters from system-on-chip CPUs, or
+ * otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices.
+ *
+ * If no devices have pre-been declared for this bus, then be sure to
+ * register the adapter before any dynamically allocated ones.  Otherwise
+ * the required bus ID may not be available.
+ *
+ * When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr.  Also, the table
+ * of I2C devices pre-declared using i2c_register_board_info() is scanned,
+ * and the appropriate driver model device nodes are created.  Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adap)
+{
+	int	id;
+	int	status;
+
+	if (adap->nr & ~MAX_ID_MASK)
+		return -EINVAL;
+
+retry:
+	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+		return -ENOMEM;
+
+	mutex_lock(&core_lists);
+	/* "above" here means "above or equal to", sigh;
+	 * we need the "equal to" result to force the result
+	 */
+	status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+	if (status == 0 && id != adap->nr) {
+		status = -EBUSY;
+		idr_remove(&i2c_adapter_idr, id);
+	}
+	mutex_unlock(&core_lists);
+	if (status == -EAGAIN)
+		goto retry;
+
+	if (status == 0)
+		status = i2c_register_adapter(adap);
+	return status;
+}
+EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
@@ -302,9 +499,19 @@ int i2c_del_adapter(struct i2c_adapter *
 	/* detach any active clients. This must be done first, because
 	 * it can fail; in which case we give up. */
 	list_for_each_safe(item, _n, &adap->clients) {
+		struct i2c_driver	*driver;
+
 		client = list_entry(item, struct i2c_client, list);
+		driver = client->driver;
+
+		/* new style, follow standard driver model */
+		if (!driver || is_newstyle_driver(driver)) {
+			i2c_unregister_device(client);
+			continue;
+		}
 
-		if ((res=client->driver->detach_client(client))) {
+		/* legacy drivers create and remove clients themselves */
+		if ((res = driver->detach_client(client))) {
 			dev_err(&adap->dev, "detach_client failed for client "
 				"[%s] at address 0x%02x\n", client->name,
 				client->addr);
@@ -314,17 +521,13 @@ int i2c_del_adapter(struct i2c_adapter *
 
 	/* clean up the sysfs representation */
 	init_completion(&adap->dev_released);
-	init_completion(&adap->class_dev_released);
-	class_device_unregister(&adap->class_dev);
-	device_remove_file(&adap->dev, &dev_attr_name);
 	device_unregister(&adap->dev);
 	list_del(&adap->list);
 
 	/* wait for sysfs to drop all references */
 	wait_for_completion(&adap->dev_released);
-	wait_for_completion(&adap->class_dev_released);
 
-	/* free dynamically allocated bus id */
+	/* free bus id */
 	idr_remove(&i2c_adapter_idr, adap->nr);
 
 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
@@ -333,24 +536,42 @@ int i2c_del_adapter(struct i2c_adapter *
 	mutex_unlock(&core_lists);
 	return res;
 }
+EXPORT_SYMBOL(i2c_del_adapter);
+
 
+/* ------------------------------------------------------------------------- */
 
-/* -----
- * What follows is the "upwards" interface: commands for talking to clients,
- * which implement the functions to access the physical information of the
- * chips.
+/*
+ * An i2c_driver is used with one or more i2c_client (device) nodes to access
+ * i2c slave chips, on a bus instance associated with some i2c_adapter.  There
+ * are two models for binding the driver to its device:  "new style" drivers
+ * follow the standard Linux driver model and just respond to probe() calls
+ * issued if the driver core sees they match(); "legacy" drivers create device
+ * nodes themselves.
  */
 
 int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 {
-	struct list_head   *item;
-	struct i2c_adapter *adapter;
 	int res;
 
+	/* new style driver methods can't mix with legacy ones */
+	if (is_newstyle_driver(driver)) {
+		if (driver->attach_adapter || driver->detach_adapter
+				|| driver->detach_client) {
+			printk(KERN_WARNING
+					"i2c-core: driver [%s] is confused\n",
+					driver->driver.name);
+			return -EINVAL;
+		}
+	}
+
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.owner = owner;
 	driver->driver.bus = &i2c_bus_type;
 
+	/* for new style drivers, when registration returns the driver core
+	 * will have called probe() for all matching-but-unbound devices.
+	 */
 	res = driver_register(&driver->driver);
 	if (res)
 		return res;
@@ -360,10 +581,11 @@ int i2c_register_driver(struct module *o
 	list_add_tail(&driver->list,&drivers);
 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
-	/* now look for instances of driver on our adapters */
+	/* legacy drivers scan i2c busses directly */
 	if (driver->attach_adapter) {
-		list_for_each(item,&adapters) {
-			adapter = list_entry(item, struct i2c_adapter, list);
+		struct i2c_adapter *adapter;
+
+		list_for_each_entry(adapter, &adapters, list) {
 			driver->attach_adapter(adapter);
 		}
 	}
@@ -373,16 +595,22 @@ int i2c_register_driver(struct module *o
 }
 EXPORT_SYMBOL(i2c_register_driver);
 
-int i2c_del_driver(struct i2c_driver *driver)
+/**
+ * i2c_del_driver - unregister I2C driver
+ * @driver: the driver being unregistered
+ */
+void i2c_del_driver(struct i2c_driver *driver)
 {
 	struct list_head   *item1, *item2, *_n;
 	struct i2c_client  *client;
 	struct i2c_adapter *adap;
 
-	int res = 0;
-
 	mutex_lock(&core_lists);
 
+	/* new-style driver? */
+	if (is_newstyle_driver(driver))
+		goto unregister;
+
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver
 	 * afterwards.
@@ -390,11 +618,10 @@ int i2c_del_driver(struct i2c_driver *dr
 	list_for_each(item1,&adapters) {
 		adap = list_entry(item1, struct i2c_adapter, list);
 		if (driver->detach_adapter) {
-			if ((res = driver->detach_adapter(adap))) {
+			if (driver->detach_adapter(adap)) {
 				dev_err(&adap->dev, "detach_adapter failed "
 					"for driver [%s]\n",
 					driver->driver.name);
-				goto out_unlock;
 			}
 		} else {
 			list_for_each_safe(item2, _n, &adap->clients) {
@@ -404,25 +631,26 @@ int i2c_del_driver(struct i2c_driver *dr
 				dev_dbg(&adap->dev, "detaching client [%s] "
 					"at 0x%02x\n", client->name,
 					client->addr);
-				if ((res = driver->detach_client(client))) {
+				if (driver->detach_client(client)) {
 					dev_err(&adap->dev, "detach_client "
 						"failed for client [%s] at "
 						"0x%02x\n", client->name,
 						client->addr);
-					goto out_unlock;
 				}
 			}
 		}
 	}
 
+ unregister:
 	driver_unregister(&driver->driver);
 	list_del(&driver->list);
 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
- out_unlock:
 	mutex_unlock(&core_lists);
-	return 0;
 }
+EXPORT_SYMBOL(i2c_del_driver);
+
+/* ------------------------------------------------------------------------- */
 
 static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
@@ -447,6 +675,7 @@ int i2c_check_addr(struct i2c_adapter *a
 
 	return rval;
 }
+EXPORT_SYMBOL(i2c_check_addr);
 
 int i2c_attach_client(struct i2c_client *client)
 {
@@ -463,9 +692,15 @@ int i2c_attach_client(struct i2c_client 
 	client->usage_count = 0;
 
 	client->dev.parent = &client->adapter->dev;
-	client->dev.driver = &client->driver->driver;
 	client->dev.bus = &i2c_bus_type;
-	client->dev.release = &i2c_client_release;
+
+	if (client->driver)
+		client->dev.driver = &client->driver->driver;
+
+	if (client->driver && !is_newstyle_driver(client->driver))
+		client->dev.release = i2c_client_release;
+	else
+		client->dev.release = i2c_client_dev_release;
 
 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
@@ -474,9 +709,6 @@ int i2c_attach_client(struct i2c_client 
 	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)  {
@@ -489,10 +721,6 @@ int i2c_attach_client(struct i2c_client 
 
 	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 "
@@ -501,7 +729,7 @@ out_unlock:
 	mutex_unlock(&adapter->clist_lock);
 	return res;
 }
-
+EXPORT_SYMBOL(i2c_attach_client);
 
 int i2c_detach_client(struct i2c_client *client)
 {
@@ -527,7 +755,6 @@ int i2c_detach_client(struct i2c_client 
 	mutex_lock(&adapter->clist_lock);
 	list_del(&client->list);
 	init_completion(&client->released);
-	device_remove_file(&client->dev, &dev_attr_client_name);
 	device_unregister(&client->dev);
 	mutex_unlock(&adapter->clist_lock);
 	wait_for_completion(&client->released);
@@ -535,6 +762,7 @@ int i2c_detach_client(struct i2c_client 
  out:
 	return res;
 }
+EXPORT_SYMBOL(i2c_detach_client);
 
 static int i2c_inc_use_client(struct i2c_client *client)
 {
@@ -567,6 +795,7 @@ int i2c_use_client(struct i2c_client *cl
 
 	return 0;
 }
+EXPORT_SYMBOL(i2c_use_client);
 
 int i2c_release_client(struct i2c_client *client)
 {
@@ -581,6 +810,7 @@ int i2c_release_client(struct i2c_client
 
 	return 0;
 }
+EXPORT_SYMBOL(i2c_release_client);
 
 void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
 {
@@ -601,6 +831,7 @@ void i2c_clients_command(struct i2c_adap
        }
        mutex_unlock(&adap->clist_lock);
 }
+EXPORT_SYMBOL(i2c_clients_command);
 
 static int __init i2c_init(void)
 {
@@ -609,16 +840,12 @@ static int __init i2c_init(void)
 	retval = bus_register(&i2c_bus_type);
 	if (retval)
 		return retval;
-	retval = driver_register(&i2c_adapter_driver);
-	if (retval)
-		return retval;
 	return class_register(&i2c_adapter_class);
 }
 
 static void __exit i2c_exit(void)
 {
 	class_unregister(&i2c_adapter_class);
-	driver_unregister(&i2c_adapter_driver);
 	bus_unregister(&i2c_bus_type);
 }
 
@@ -638,8 +865,9 @@ int i2c_transfer(struct i2c_adapter * ad
 #ifdef DEBUG
 		for (ret = 0; ret < num; ret++) {
 			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
-				"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
-				'R' : 'W', msgs[ret].addr, msgs[ret].len);
+				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
 		}
 #endif
 
@@ -653,6 +881,7 @@ #endif
 		return -ENOSYS;
 	}
 }
+EXPORT_SYMBOL(i2c_transfer);
 
 int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
 {
@@ -671,6 +900,7 @@ int i2c_master_send(struct i2c_client *c
 	   transmitted, else error code. */
 	return (ret == 1) ? count : ret;
 }
+EXPORT_SYMBOL(i2c_master_send);
 
 int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
 {
@@ -690,7 +920,7 @@ int i2c_master_recv(struct i2c_client *c
 	   transmitted, else error code. */
 	return (ret == 1) ? count : ret;
 }
-
+EXPORT_SYMBOL(i2c_master_recv);
 
 int i2c_control(struct i2c_client *client,
 	unsigned int cmd, unsigned long arg)
@@ -712,6 +942,7 @@ int i2c_control(struct i2c_client *clien
 	}
 	return ret;
 }
+EXPORT_SYMBOL(i2c_control);
 
 /* ----------------------------------------------------
  * the i2c address scanning function
@@ -853,6 +1084,70 @@ int i2c_probe(struct i2c_adapter *adapte
 
 	return 0;
 }
+EXPORT_SYMBOL(i2c_probe);
+
+struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+		      struct i2c_board_info *info,
+		      unsigned short const *addr_list)
+{
+	int i;
+
+	/* Stop here if the bus doesn't support probing */
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
+		dev_err(&adap->dev, "Probing not supported\n");
+		return NULL;
+	}
+
+	mutex_lock(&adap->clist_lock);
+	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+		/* Check address validity */
+		if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
+			dev_warn(&adap->dev, "Invalid 7-bit address "
+				 "0x%02x\n", addr_list[i]);
+			continue;
+		}
+
+		/* Check address availability */
+		if (__i2c_check_addr(adap, addr_list[i])) {
+			dev_dbg(&adap->dev, "Address 0x%02x already in "
+				"use, not probing\n", addr_list[i]);
+			continue;
+		}
+
+		/* Test address responsiveness
+		   The default probe method is a quick write, but it is known
+		   to corrupt the 24RF08 EEPROMs due to a state machine bug,
+		   and could also irreversibly write-protect some EEPROMs, so
+		   for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte
+		   read instead. Also, some bus drivers don't implement
+		   quick write, so we fallback to a byte read it that case
+		   too. */
+		if ((addr_list[i] & ~0x07) == 0x30
+		 || (addr_list[i] & ~0x0f) == 0x50
+		 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) {
+			if (i2c_smbus_xfer(adap, addr_list[i], 0,
+					   I2C_SMBUS_READ, 0,
+					   I2C_SMBUS_BYTE, NULL) >= 0)
+				break;
+		} else {
+			if (i2c_smbus_xfer(adap, addr_list[i], 0,
+					   I2C_SMBUS_WRITE, 0,
+					   I2C_SMBUS_QUICK, NULL) >= 0)
+				break;
+		}
+	}
+	mutex_unlock(&adap->clist_lock);
+
+	if (addr_list[i] == I2C_CLIENT_END) {
+		dev_dbg(&adap->dev, "Probing failed, no device found\n");
+		return NULL;
+	}
+
+	info->addr = addr_list[i];
+	return i2c_new_device(adap, info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_probed_device);
 
 struct i2c_adapter* i2c_get_adapter(int id)
 {
@@ -866,11 +1161,13 @@ struct i2c_adapter* i2c_get_adapter(int 
 	mutex_unlock(&core_lists);
 	return adapter;
 }
+EXPORT_SYMBOL(i2c_get_adapter);
 
 void i2c_put_adapter(struct i2c_adapter *adap)
 {
 	module_put(adap->owner);
 }
+EXPORT_SYMBOL(i2c_put_adapter);
 
 /* The SMBus parts */
 
@@ -939,6 +1236,7 @@ s32 i2c_smbus_write_quick(struct i2c_cli
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
 	                      value,0,I2C_SMBUS_QUICK,NULL);
 }
+EXPORT_SYMBOL(i2c_smbus_write_quick);
 
 s32 i2c_smbus_read_byte(struct i2c_client *client)
 {
@@ -949,12 +1247,14 @@ s32 i2c_smbus_read_byte(struct i2c_clien
 	else
 		return data.byte;
 }
+EXPORT_SYMBOL(i2c_smbus_read_byte);
 
 s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
 	                      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
 }
+EXPORT_SYMBOL(i2c_smbus_write_byte);
 
 s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
 {
@@ -965,6 +1265,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_
 	else
 		return data.byte;
 }
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
 
 s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
 {
@@ -974,6 +1275,7 @@ s32 i2c_smbus_write_byte_data(struct i2c
 	                      I2C_SMBUS_WRITE,command,
 	                      I2C_SMBUS_BYTE_DATA,&data);
 }
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
 
 s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
 {
@@ -984,6 +1286,7 @@ s32 i2c_smbus_read_word_data(struct i2c_
 	else
 		return data.word;
 }
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
 
 s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
 {
@@ -993,6 +1296,23 @@ s32 i2c_smbus_write_word_data(struct i2c
 	                      I2C_SMBUS_WRITE,command,
 	                      I2C_SMBUS_WORD_DATA,&data);
 }
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+
+/* Returns the number of read bytes */
+s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
+			      u8 *values)
+{
+	union i2c_smbus_data data;
+
+	if (i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+	                   I2C_SMBUS_READ, command,
+	                   I2C_SMBUS_BLOCK_DATA, &data))
+		return -1;
+
+	memcpy(values, &data.block[1], data.block[0]);
+	return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
 
 s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
 			       u8 length, const u8 *values)
@@ -1007,6 +1327,7 @@ s32 i2c_smbus_write_block_data(struct i2
 			      I2C_SMBUS_WRITE,command,
 			      I2C_SMBUS_BLOCK_DATA,&data);
 }
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
 
 /* Returns the number of read bytes */
 s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
@@ -1021,6 +1342,7 @@ s32 i2c_smbus_read_i2c_block_data(struct
 	memcpy(values, &data.block[1], data.block[0]);
 	return data.block[0];
 }
+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
 
 s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
 				   u8 length, const u8 *values)
@@ -1035,6 +1357,7 @@ s32 i2c_smbus_write_i2c_block_data(struc
 			      I2C_SMBUS_WRITE, command,
 			      I2C_SMBUS_I2C_BLOCK_DATA, &data);
 }
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
 
 /* Simulate a SMBus command using the i2c protocol
    No checking of parameters is done!  */
@@ -1098,9 +1421,9 @@ static s32 i2c_smbus_xfer_emulated(struc
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
 		if (read_write == I2C_SMBUS_READ) {
-			dev_err(&adapter->dev, "Block read not supported "
-			       "under I2C emulation!\n");
-			return -1;
+			msg[1].flags |= I2C_M_RECV_LEN;
+			msg[1].len = 1; /* block length will be added by
+					   the underlying bus driver */
 		} else {
 			msg[0].len = data->block[0] + 2;
 			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
@@ -1114,9 +1437,21 @@ static s32 i2c_smbus_xfer_emulated(struc
 		}
 		break;
 	case I2C_SMBUS_BLOCK_PROC_CALL:
-		dev_dbg(&adapter->dev, "Block process call not supported "
-		       "under I2C emulation!\n");
-		return -1;
+		num = 2; /* Another special case */
+		read_write = I2C_SMBUS_READ;
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+			dev_err(&adapter->dev, "%s called with invalid "
+				"block proc call size (%d)\n", __FUNCTION__,
+				data->block[0]);
+			return -1;
+		}
+		msg[0].len = data->block[0] + 2;
+		for (i = 1; i < msg[0].len; i++)
+			msgbuf0[i] = data->block[i-1];
+		msg[1].flags |= I2C_M_RECV_LEN;
+		msg[1].len = 1; /* block length will be added by
+				   the underlying bus driver */
+		break;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
 		if (read_write == I2C_SMBUS_READ) {
 			msg[1].len = I2C_SMBUS_BLOCK_MAX;
@@ -1180,6 +1515,11 @@ static s32 i2c_smbus_xfer_emulated(struc
 				for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
 					data->block[i+1] = msgbuf1[i];
 				break;
+			case I2C_SMBUS_BLOCK_DATA:
+			case I2C_SMBUS_BLOCK_PROC_CALL:
+				for (i = 0; i < msgbuf1[0] + 1; i++)
+					data->block[i] = msgbuf1[i];
+				break;
 		}
 	return 0;
 }
@@ -1204,43 +1544,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * 
 
 	return res;
 }
-
-
-/* Next four are needed by i2c-isa */
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
-EXPORT_SYMBOL_GPL(i2c_adapter_driver);
-EXPORT_SYMBOL_GPL(i2c_adapter_class);
-EXPORT_SYMBOL_GPL(i2c_bus_type);
-
-EXPORT_SYMBOL(i2c_add_adapter);
-EXPORT_SYMBOL(i2c_del_adapter);
-EXPORT_SYMBOL(i2c_del_driver);
-EXPORT_SYMBOL(i2c_attach_client);
-EXPORT_SYMBOL(i2c_detach_client);
-EXPORT_SYMBOL(i2c_use_client);
-EXPORT_SYMBOL(i2c_release_client);
-EXPORT_SYMBOL(i2c_clients_command);
-EXPORT_SYMBOL(i2c_check_addr);
-
-EXPORT_SYMBOL(i2c_master_send);
-EXPORT_SYMBOL(i2c_master_recv);
-EXPORT_SYMBOL(i2c_control);
-EXPORT_SYMBOL(i2c_transfer);
-EXPORT_SYMBOL(i2c_get_adapter);
-EXPORT_SYMBOL(i2c_put_adapter);
-EXPORT_SYMBOL(i2c_probe);
-
 EXPORT_SYMBOL(i2c_smbus_xfer);
-EXPORT_SYMBOL(i2c_smbus_write_quick);
-EXPORT_SYMBOL(i2c_smbus_read_byte);
-EXPORT_SYMBOL(i2c_smbus_write_byte);
-EXPORT_SYMBOL(i2c_smbus_read_byte_data);
-EXPORT_SYMBOL(i2c_smbus_write_byte_data);
-EXPORT_SYMBOL(i2c_smbus_read_word_data);
-EXPORT_SYMBOL(i2c_smbus_write_word_data);
-EXPORT_SYMBOL(i2c_smbus_write_block_data);
-EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
-EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
 
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
new file mode 100644
index 0000000..cd5bff8
--- /dev/null
+++ b/drivers/i2c/i2c-core.h
@@ -0,0 +1,31 @@
+/*
+ * i2c-core.h - interfaces internal to the I2C framework
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ */
+
+struct i2c_devinfo {
+	struct list_head	list;
+	int			busnum;
+	struct i2c_board_info	board_info;
+};
+
+/* board_lock protects board_list and first_dynamic_bus_num.
+ * only i2c core components are allowed to use these symbols.
+ */
+extern struct mutex	__i2c_board_lock;
+extern struct list_head	__i2c_board_list;
+extern int		__i2c_first_dynamic_bus_num;
+
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index cb4fa9b..e7a7097 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -30,7 +30,6 @@ #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/i2c.h>
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 556455f..5e8efc8 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -730,7 +730,7 @@ static int speed_cris_ide(ide_drive_t *d
 
 	if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
 		tune_cris_ide(drive, speed - XFER_PIO_0);
-		return 0;
+		return ide_config_drive_speed(drive, speed);
 	}
 
 	switch(speed)
@@ -760,7 +760,8 @@ static int speed_cris_ide(ide_drive_t *d
 			hold = ATA_DMA2_HOLD;
 			break;
 		default:
-			return 0;
+			BUG();
+			break;
 	}
 
 	if (speed >= XFER_UDMA_0)
@@ -768,7 +769,7 @@ static int speed_cris_ide(ide_drive_t *d
 	else
 		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
 
-	return 0;
+	return ide_config_drive_speed(drive, speed);
 }
 
 void __init
@@ -821,7 +822,6 @@ init_e100_ide (void)
 		hwif->udma_four = 0;
 		hwif->ultra_mask = cris_ultra_mask;
 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
-		hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */
 		hwif->autodma = 1;
 		hwif->drives[0].autodma = 1;
 		hwif->drives[1].autodma = 1;
@@ -1010,7 +1010,6 @@ static int cris_config_drive_for_dma (id
 		return 0;
 
 	speed_cris_ide(drive, speed);
-	ide_config_drive_speed(drive, speed);
 
 	return ide_dma_enable(drive);
 }
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index afb71c6..a9e0b30 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -310,14 +310,12 @@ static int proc_ide_read_driver
 	ide_driver_t	*ide_drv;
 	int		len;
 
-	down_read(&dev->bus->subsys.rwsem);
 	if (dev->driver) {
 		ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
 		len = sprintf(page, "%s version %s\n",
 				dev->driver->name, ide_drv->version);
 	} else
 		len = sprintf(page, "ide-default version 0.9.newide\n");
-	up_read(&dev->bus->subsys.rwsem);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -327,7 +325,6 @@ static int ide_replace_subdriver(ide_dri
 	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));
@@ -345,7 +342,6 @@ static int ide_replace_subdriver(ide_dri
 	}
 	if (dev->driver && !strcmp(dev->driver->name, driver))
 		ret = 0;
-	up_write(&dev->bus->subsys.rwsem);
 
 	return ret;
 }
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index b08c37c..c6522a6 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -401,6 +401,7 @@ static struct pcmcia_device_id ide_ids[]
 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 	PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
+	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
 	PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
 	PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 990eafe..73bdf64 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/ide/pci/aec62xx.c		Version 0.11	March 27, 2002
+ * linux/drivers/ide/pci/aec62xx.c		Version 0.21	Apr 21, 2007
  *
  * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007		MontaVista Software, Inc. <source@mvista.com>
  *
  */
 
@@ -193,18 +194,8 @@ static int config_chipset_for_dma (ide_d
 
 static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 {
-	u8 speed = 0;
-	u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	switch(pio) {
-		case 5:		speed = new_pio; break;
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-	(void) aec62xx_tune_chipset(drive, speed);
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) aec62xx_tune_chipset(drive, pio + XFER_PIO_0);
 }
 
 static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
@@ -213,7 +204,7 @@ static int aec62xx_config_drive_xfer_rat
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		aec62xx_tune_drive(drive, 5);
+		aec62xx_tune_drive(drive, 255);
 
 	return -1;
 }
@@ -288,11 +279,10 @@ static void __devinit init_hwif_aec62xx(
 
 	hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
 
 	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
 	hwif->ide_dma_lostirq	= &aec62xx_irq_timeout;
-	hwif->ide_dma_timeout	= &aec62xx_irq_timeout;
+
 	if (!noautodma)
 		hwif->autodma = 1;
 	hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 83e0aa6..946a127 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -534,7 +534,7 @@ static int ali15x3_config_drive_for_dma(
 	struct hd_driveid *id	= drive->id;
 
 	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		goto no_dma_set;
+		goto ata_pio;
 
 	drive->init_speed = 0;
 
@@ -555,20 +555,19 @@ try_dma_modes:
 			    (id->dma_1word & hwif->swdma_mask)) {
 				/* Force if Capable regular DMA modes */
 				if (!config_chipset_for_dma(drive))
-					goto no_dma_set;
+					goto ata_pio;
 			}
 		} else if (__ide_dma_good_drive(drive) &&
 			   (id->eide_dma_time < 150)) {
 			/* Consult the list of known "good" drives */
 			if (!config_chipset_for_dma(drive))
-				goto no_dma_set;
+				goto ata_pio;
 		} else {
 			goto ata_pio;
 		}
 	} else {
 ata_pio:
 		hwif->tuneproc(drive, 255);
-no_dma_set:
 		return -1;
 	}
 
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 561197f..77f51ab 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,10 +1,7 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/pci/cmd64x.c		Version 1.42	Feb 8, 2007
+/*
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.47	Mar 19, 2007
  *
  * 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.
  *
@@ -39,11 +36,12 @@ #endif
  * CMD64x specific registers definition.
  */
 #define CFR		0x50
-#define   CFR_INTR_CH0		0x02
+#define   CFR_INTR_CH0		0x04
 #define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
+#define   CNTRL_ENA_1ST 	0x04
+#define   CNTRL_ENA_2ND 	0x08
+#define   CNTRL_DIS_RA0 	0x40
+#define   CNTRL_DIS_RA1 	0x80
 
 #define	CMDTIM		0x52
 #define	ARTTIM0		0x53
@@ -90,86 +88,67 @@ static int n_cmd_devs;
 static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
 {
 	char *p = buf;
-
-	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
-	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
 	u8 reg72 = 0, reg73 = 0;			/* primary */
 	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 0, reg71 = 0;			/* extra */
+	u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;	/* extra */
+	u8 rev = 0;
 
 	p += sprintf(p, "\nController: %d\n", index);
-	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
+
 	(void) pci_read_config_byte(dev, CFR,       &reg50);
-	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, CNTRL,     &reg51);
+	(void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
 	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
 	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
 	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
 	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
 	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
 
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled           "
-			"              %sabled\n",
-		(reg72&0x80)?"dis":" en",
-		(reg7a&0x80)?"dis":" en");
-	p += sprintf(p, "--------------- drive0 "
-		"--------- drive1 -------- drive0 "
-		"---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s"
-			"             %s               %s\n",
-		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
-		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
-
-	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
-		(reg72&0x20)?(
-			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
-			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
-			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
-			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
-			"X"):"?",
-		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
-		(reg72&0x40)?(
-			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
-			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
-			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
-			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
-			"X"):"?");
-	p += sprintf(p, "         %s(%s)           %s(%s)\n",
-		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x20)?(
-			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
-			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
-			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
-			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
-			"X"):"?",
-		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x40)?(
-			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
-			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
-			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
-			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
-			"X"):"?" );
-	p += sprintf(p, "PIO Mode:       %s                %s"
-			"               %s                 %s\n",
-			"?", "?", "?", "?");
-	p += sprintf(p, "                %s                     %s\n",
-		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
-		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
-		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+	/* PCI0643/6 originally didn't have the primary channel enable bit */
+	(void) pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+	if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
+	    (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 3))
+		reg51 |= CNTRL_ENA_1ST;
+
+	p += sprintf(p, "---------------- Primary Channel "
+			"---------------- Secondary Channel ------------\n");
+	p += sprintf(p, "                 %s                         %s\n",
+		 (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
+		 (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
+	p += sprintf(p, "---------------- drive0 --------- drive1 "
+			"-------- drive0 --------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:     %s              %s"
+			"             %s              %s\n",
+		(reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
+		(reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
+	p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
+		( reg73 & 0x01) ? " on" : "off",
+		((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
+		((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
+		((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
+		((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
+		( reg73 & 0x02) ? " on" : "off",
+		((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
+		((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
+		((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
+		((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
+	p += sprintf(p, "         %s (%c)          %s (%c)\n",
+		( reg7b & 0x01) ? " on" : "off",
+		((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
+		((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
+		((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
+		((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
+		( reg7b & 0x02) ? " on" : "off",
+		((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
+		((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
+		((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
+		((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
+	p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
+		(reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
+		(reg50 & CFR_INTR_CH0	  ) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
+		(reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
 
 	return (char *)p;
 }
@@ -179,7 +158,6 @@ static int cmd64x_get_info (char *buffer
 	char *p = buffer;
 	int i;
 
-	p += sprintf(p, "\n");
 	for (i = 0; i < n_cmd_devs; i++) {
 		struct pci_dev *dev	= cmd_devs[i];
 		p = print_cmd64x_get_info(p, dev, i);
@@ -195,116 +173,103 @@ static u8 quantize_timing(int timing, in
 }
 
 /*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
+ * This routine calculates active/recovery counts and then writes them into
+ * the chipset registers.
  */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
 {
-	unsigned long flags;
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	u8 temp_b;
-	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const u8 recovery_counts[] =
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	int clock_time		= 1000 / system_bus_clock();
+	u8  cycle_count, active_count, recovery_count, drwtim;
+	static const u8 recovery_values[] =
 		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const u8 arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const u8 drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
-
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
-		setup_count, active_count, recovery_count, drive->present);
+	static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
+
+	cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
+		  cycle_time, active_time);
+
+	cycle_count	= quantize_timing( cycle_time, clock_time);
+	active_count	= quantize_timing(active_time, clock_time);
+	recovery_count	= cycle_count - active_count;
+
 	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
+	 * In case we've got too long recovery phase, try to lengthen
+	 * the active phase
 	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = max(drives[0].drive_data,
-					drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n",
-					setup_count);
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
 	}
+	if (active_count > 16)		/* shouldn't actually happen... */
+	 	active_count = 16;
+
+	cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
+		  cycle_count, active_count, recovery_count);
 
 	/*
 	 * Convert values to internal chipset representation
 	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
+	recovery_count = recovery_values[recovery_count];
+ 	active_count  &= 0x0f;
 
-	cmdprintk("Final values = %d,%d,%d\n",
-		setup_count, active_count, recovery_count);
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	local_irq_save(flags);
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
-		((u8) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
-		(u8) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n",
-		((u8) setup_count) | (temp_b & 0x3f),
-		arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n",
-		(u8) ((active_count << 4) | recovery_count),
-		drwtim_regs[channel][slave]);
-	local_irq_restore(flags);
+	/* Program the active/recovery counts into the DRWTIM register */
+	drwtim = (active_count << 4) | recovery_count;
+	(void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
+	cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
 }
 
 /*
- * This routine selects drive's best PIO mode, calculates setup/active/recovery
- * counts, and then writes them into the chipset registers.
+ * This routine selects drive's best PIO mode and writes into the chipset
+ * registers setup/active/recovery timings.
  */
 static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
 {
-	int setup_time, active_time, cycle_time;
-	u8  cycle_count, setup_count, active_count, recovery_count;
-	u8  pio_mode;
-	int clock_time = 1000 / system_bus_clock();
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 	ide_pio_data_t pio;
-
+	u8 pio_mode, setup_count, arttim = 0;
+	static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
 	pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
-	cycle_time = pio.cycle_time;
 
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
+	cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
+		  drive->name, mode_wanted, pio_mode, pio.cycle_time,
+		  pio.overridden ? " (overriding vendor mode)" : "");
 
-	setup_count  = quantize_timing( setup_time, clock_time);
-	cycle_count  = quantize_timing( cycle_time, clock_time);
-	active_count = quantize_timing(active_time, clock_time);
+	program_cycle_times(drive, pio.cycle_time,
+			    ide_pio_timings[pio_mode].active_time);
 
-	recovery_count = cycle_count - active_count;
-	/* program_drive_counts() takes care of zero recovery cycles */
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
+	setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+				      1000 / system_bus_clock());
+
+	/*
+	 * The primary channel has individual address setup timing registers
+	 * for each drive and the hardware selects the slowest timing itself.
+	 * The secondary channel has one common register and we have to select
+	 * the slowest address setup timing ourselves.
+	 */
+	if (hwif->channel) {
+		ide_drive_t *drives = hwif->drives;
+
+		drive->drive_data = setup_count;
+		setup_count = max(drives[0].drive_data, drives[1].drive_data);
 	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd64x */
 
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
+	if (setup_count > 5)		/* shouldn't actually happen... */
+		setup_count = 5;
+	cmdprintk("Final address setup count: %d\n", setup_count);
 
-	cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, "
-		"clocks=%d/%d/%d\n",
-		drive->name, mode_wanted, pio_mode, cycle_time,
-		pio.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
+	/*
+	 * Program the address setup clocks into the ARTTIM registers.
+	 * Avoid clearing the secondary channel's interrupt bit.
+	 */
+	(void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
+	if (hwif->channel)
+		arttim &= ~ARTTIM23_INTR_CH1;
+	arttim &= ~0xc0;
+	arttim |= setup_values[setup_count];
+	(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
+	cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
 
 	return pio_mode;
 }
@@ -376,61 +341,64 @@ static u8 cmd64x_ratemask (ide_drive_t *
 	return mode;
 }
 
-static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
+	u8 unit			= drive->dn & 0x01;
+	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
 
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 regU = 0, pciU	= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 regD = 0, pciD	= (hwif->channel) ? BMIDESR1 : BMIDESR0;
-
-	u8 speed	= ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+	speed = ide_rate_filter(cmd64x_ratemask(drive), speed);
 
 	if (speed >= XFER_SW_DMA_0) {
-		(void) pci_read_config_byte(dev, pciD, &regD);
 		(void) pci_read_config_byte(dev, pciU, &regU);
-		regD &= ~(unit ? 0x40 : 0x20);
 		regU &= ~(unit ? 0xCA : 0x35);
-		(void) pci_write_config_byte(dev, pciD, regD);
-		(void) pci_write_config_byte(dev, pciU, regU);
-		(void) pci_read_config_byte(dev, pciD, &regD);
-		(void) pci_read_config_byte(dev, pciU, &regU);
 	}
 
 	switch(speed) {
-		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
-		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
-		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
-		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
-		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
-		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
-		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_PIO_5:
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			(void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
-			break;
-
-		default:
-			return 1;
+	case XFER_UDMA_5:
+		regU |= unit ? 0x0A : 0x05;
+		break;
+	case XFER_UDMA_4:
+		regU |= unit ? 0x4A : 0x15;
+		break;
+	case XFER_UDMA_3:
+		regU |= unit ? 0x8A : 0x25;
+		break;
+	case XFER_UDMA_2:
+		regU |= unit ? 0x42 : 0x11;
+		break;
+	case XFER_UDMA_1:
+		regU |= unit ? 0x82 : 0x21;
+		break;
+	case XFER_UDMA_0:
+		regU |= unit ? 0xC2 : 0x31;
+		break;
+	case XFER_MW_DMA_2:
+		program_cycle_times(drive, 120, 70);
+		break;
+	case XFER_MW_DMA_1:
+		program_cycle_times(drive, 150, 80);
+		break;
+	case XFER_MW_DMA_0:
+		program_cycle_times(drive, 480, 215);
+		break;
+	case XFER_PIO_5:
+	case XFER_PIO_4:
+	case XFER_PIO_3:
+	case XFER_PIO_2:
+	case XFER_PIO_1:
+	case XFER_PIO_0:
+		(void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
+		break;
+	default:
+		return 1;
 	}
 
-	if (speed >= XFER_SW_DMA_0) {
+	if (speed >= XFER_SW_DMA_0)
 		(void) pci_write_config_byte(dev, pciU, regU);
-		regD |= (unit ? 0x40 : 0x20);
-		(void) pci_write_config_byte(dev, pciD, regD);
-	}
 
-	return (ide_config_drive_speed(drive, speed));
+	return ide_config_drive_speed(drive, speed);
 }
 
 static int config_chipset_for_dma (ide_drive_t *drive)
@@ -457,67 +425,80 @@ static int cmd64x_config_drive_for_dma (
 	return -1;
 }
 
-static int cmd64x_alt_dma_status (struct pci_dev *dev)
+static int cmd648_ide_dma_end (ide_drive_t *drive)
 {
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			return 1;
-		default:
-			break;
-	}
-	return 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	int err			= __ide_dma_end(drive);
+	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
+						  MRDMODE_INTR_CH0;
+	u8  mrdmode		= inb(hwif->dma_master + 0x01);
+
+	/* clear the interrupt bit */
+	outb(mrdmode | irq_mask, hwif->dma_master + 0x01);
+
+	return err;
 }
 
 static int cmd64x_ide_dma_end (ide_drive_t *drive)
 {
-	u8 dma_stat = 0, dma_cmd = 0;
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
+	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
+	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
+						  CFR_INTR_CH0;
+	u8  irq_stat		= 0;
+	int err			= __ide_dma_end(drive);
 
-	drive->waiting_for_dma = 0;
-	/* read DMA command state */
-	dma_cmd = inb(hwif->dma_command);
-	/* stop DMA */
-	outb(dma_cmd & ~1, hwif->dma_command);
-	/* get DMA status */
-	dma_stat = inb(hwif->dma_status);
-	/* clear the INTR & ERROR bits */
-	outb(dma_stat | 6, hwif->dma_status);
-	if (cmd64x_alt_dma_status(dev)) {
-		u8 dma_intr	= 0;
-		u8 dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 :
-						    CFR_INTR_CH0;
-		u8 dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
-		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-		/* clear the INTR bit */
-		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
-	}
-	/* purge DMA mappings */
-	ide_destroy_dmatable(drive);
-	/* verify good DMA status */
-	return (dma_stat & 7) != 4;
+	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
+	/* clear the interrupt bit */
+	(void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
+
+	return err;
+}
+
+static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
+						  MRDMODE_INTR_CH0;
+	u8 dma_stat		= inb(hwif->dma_status);
+	u8 mrdmode		= inb(hwif->dma_master + 0x01);
+
+#ifdef DEBUG
+	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
+	       drive->name, dma_stat, mrdmode, irq_mask);
+#endif
+	if (!(mrdmode & irq_mask))
+		return 0;
+
+	/* return 1 if INTR asserted */
+	if (dma_stat & 4)
+		return 1;
+
+	return 0;
 }
 
 static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
 {
-	ide_hwif_t *hwif		= HWIF(drive);
-	struct pci_dev *dev		= hwif->pci_dev;
-        u8 dma_alt_stat = 0, mask	= (hwif->channel) ? MRDMODE_INTR_CH1 :
-							    MRDMODE_INTR_CH0;
-	u8 dma_stat = inb(hwif->dma_status);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int irq_reg		= hwif->channel ? ARTTIM23 : CFR;
+	u8  irq_mask		= hwif->channel ? ARTTIM23_INTR_CH1 :
+						  CFR_INTR_CH0;
+	u8  dma_stat		= inb(hwif->dma_status);
+	u8  irq_stat		= 0;
+
+	(void) pci_read_config_byte(dev, irq_reg, &irq_stat);
 
-	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
 #ifdef DEBUG
-	printk("%s: dma_stat: 0x%02x dma_alt_stat: "
-		"0x%02x mask: 0x%02x\n", drive->name,
-		dma_stat, dma_alt_stat, mask);
+	printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n",
+	       drive->name, dma_stat, irq_stat, irq_mask);
 #endif
-	if (!(dma_alt_stat & mask))
+	if (!(irq_stat & irq_mask))
 		return 0;
 
 	/* return 1 if INTR asserted */
-	if ((dma_stat & 4) == 4)
+	if (dma_stat & 4)
 		return 1;
 
 	return 0;
@@ -665,7 +646,6 @@ static void __devinit init_hwif_cmd64x(i
 
 	hwif->ultra_mask = 0x3f;
 	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
 
 	if (dev->device == PCI_DEVICE_ID_CMD_643)
 		hwif->ultra_mask = 0x80;
@@ -678,17 +658,25 @@ static void __devinit init_hwif_cmd64x(i
 	if (!(hwif->udma_four))
 		hwif->udma_four = ata66_cmd64x(hwif);
 
-	if (dev->device == PCI_DEVICE_ID_CMD_646) {
+	switch(dev->device) {
+	case PCI_DEVICE_ID_CMD_648:
+	case PCI_DEVICE_ID_CMD_649:
+	alt_irq_bits:
+		hwif->ide_dma_end	= &cmd648_ide_dma_end;
+		hwif->ide_dma_test_irq	= &cmd648_ide_dma_test_irq;
+		break;
+	case PCI_DEVICE_ID_CMD_646:
 		hwif->chipset = ide_cmd646;
 		if (class_rev == 0x01) {
 			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
-		} else {
-			hwif->ide_dma_end = &cmd64x_ide_dma_end;
-			hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
-		}
-	} else {
-		hwif->ide_dma_end = &cmd64x_ide_dma_end;
-		hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+			break;
+		} else if (class_rev >= 0x03)
+			goto alt_irq_bits;
+		/* fall thru */
+	default:
+		hwif->ide_dma_end	= &cmd64x_ide_dma_end;
+		hwif->ide_dma_test_irq	= &cmd64x_ide_dma_test_irq;
+		break;
 	}
 
 
@@ -698,42 +686,75 @@ static void __devinit init_hwif_cmd64x(i
 	hwif->drives[1].autodma = hwif->autodma;
 }
 
+static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_cmd646(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u8 rev = 0;
+
+	/*
+	 * The original PCI0646 didn't have the primary channel enable bit,
+	 * it appeared starting with PCI0646U (i.e. revision ID 3).
+	 */
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+	if (rev < 3)
+		d->enablebits[0].reg = 0;
+
+	return ide_setup_pci_device(dev, d);
+}
+
 static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
 	{	/* 0 */
 		.name		= "CMD643",
+		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
 	},{	/* 1 */
 		.name		= "CMD646",
+		.init_setup	= init_setup_cmd646,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
 		.channels	= 2,
 		.autodma	= AUTODMA,
-		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
 	},{	/* 2 */
 		.name		= "CMD648",
+		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
 	},{	/* 3 */
 		.name		= "CMD649",
+		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
 		.channels	= 2,
 		.autodma	= AUTODMA,
+		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
 	}
 };
 
+/*
+ * We may have to modify enablebits for PCI0646, so we'd better pass
+ * a local copy of the ide_pci_device_t structure down the call chain...
+ */
 static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	return ide_setup_pci_device(dev, &cmd64x_chipsets[id->driver_data]);
+	ide_pci_device_t d = cmd64x_chipsets[id->driver_data];
+
+	return d.init_setup(dev, &d);
 }
 
 static struct pci_device_id cmd64x_pci_tbl[] = {
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index ab6fa27..cf9d344 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c		Version 1.02	Apr 18, 2007
+ * linux/drivers/ide/pci/hpt366.c		Version 1.03	May 4, 2007
  *
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
@@ -1527,7 +1527,12 @@ static int __devinit init_setup_hpt366(s
 	if (rev > 2)
 		goto init_single;
 
+	/*
+	 * HPT36x chips are single channel and
+	 * do not seem to have the channel enable bit...
+	 */
 	d->channels = 1;
+	d->enablebits[0].reg = 0;
 
 	if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
 	  	u8  pin1 = 0, pin2 = 0;
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index a132767..4e12548 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -1,8 +1,9 @@
 
 /*
- * linux/drivers/ide/pci/it821x.c		Version 0.09	December 2004
+ * linux/drivers/ide/pci/it821x.c		Version 0.10	Mar 10 2007
  *
  * Copyright (C) 2004		Red Hat <alan@redhat.com>
+ * Copyright (C) 2007		Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *  Based in part on the ITE vendor provided SCSI driver.
@@ -104,6 +105,7 @@ static int it8212_noraid;
 /**
  *	it821x_program	-	program the PIO/MWDMA registers
  *	@drive: drive to tune
+ *	@timing: timing info
  *
  *	Program the PIO/MWDMA timing for this channel according to the
  *	current clock.
@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *
 /**
  *	it821x_program_udma	-	program the UDMA registers
  *	@drive: drive to tune
+ *	@timing: timing info
  *
  *	Program the UDMA timing for this drive according to the
  *	current clock.
@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_driv
 	}
 }
 
-
 /**
  *	it821x_clock_strategy
- *	@hwif: hardware interface
+ *	@drive: drive to set up
  *
  *	Select between the 50 and 66Mhz base clocks to get the best
  *	results for this interface.
@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_dr
 		altclock = itdev->want[0][1];
 	}
 
-	/* Master doesn't care does the slave ? */
-	if(clock == ATA_ANY)
+	/*
+	 * if both clocks can be used for the mode with the higher priority
+	 * use the clock needed by the mode with the lower priority
+	 */
+	if (clock == ATA_ANY)
 		clock = altclock;
 
 	/* Nobody cares - keep the same clock */
@@ -240,37 +245,56 @@ static u8 it821x_ratemask (ide_drive_t *
 }
 
 /**
- *	it821x_tuneproc	-	tune a drive
+ *	it821x_tunepio	-	tune a drive
  *	@drive: drive to tune
- *	@mode_wanted: the target operating mode
- *
- *	Load the timing settings for this device mode into the
- *	controller. By the time we are called the mode has been
- *	modified as neccessary to handle the absence of seperate
- *	master/slave timers for MWDMA/PIO.
+ *	@pio: the desired PIO mode
  *
- *	This code is only used in pass through mode.
+ *	Try to tune the drive/host to the desired PIO mode taking into
+ *	the consideration the maximum PIO mode supported by the other
+ *	device on the cable.
  */
 
-static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
 {
 	ide_hwif_t *hwif	= drive->hwif;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
 	int unit = drive->select.b.unit;
+	ide_drive_t *pair = &hwif->drives[1 - unit];
 
 	/* Spec says 89 ref driver uses 88 */
 	static u16 pio[]	= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
 	static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
 
-	if(itdev->smart)
-		return;
+	/*
+	 * Compute the best PIO mode we can for a given device. We must
+	 * pick a speed that does not cause problems with the other device
+	 * on the cable.
+	 */
+	if (pair) {
+		u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+		/* trim PIO to the slowest of the master/slave */
+		if (pair_pio < set_pio)
+			set_pio = pair_pio;
+	}
+
+	if (itdev->smart)
+		goto set_drive_speed;
 
 	/* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
-	itdev->want[unit][1] = pio_want[mode_wanted];
+	itdev->want[unit][1] = pio_want[set_pio];
 	itdev->want[unit][0] = 1;	/* PIO is lowest priority */
-	itdev->pio[unit] = pio[mode_wanted];
+	itdev->pio[unit] = pio[set_pio];
 	it821x_clock_strategy(drive);
 	it821x_program(drive, itdev->pio[unit]);
+
+set_drive_speed:
+	return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
+}
+
+static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void)it821x_tunepio(drive, pio);
 }
 
 /**
@@ -354,40 +378,6 @@ static void it821x_tune_udma (ide_drive_
 }
 
 /**
- *	config_it821x_chipset_for_pio	-	set drive timings
- *	@drive: drive to tune
- *	@speed we want
- *
- *	Compute the best pio mode we can for a given device. We must
- *	pick a speed that does not cause problems with the other device
- *	on the cable.
- */
-
-static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	u8 unit = drive->select.b.unit;
-	ide_hwif_t *hwif = drive->hwif;
-	ide_drive_t *pair = &hwif->drives[1-unit];
-	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
-	u8 pair_pio;
-
-	/* We have to deal with this mess in pairs */
-	if(pair != NULL) {
-		pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
-		/* Trim PIO to the slowest of the master/slave */
-		if(pair_pio < set_pio)
-			set_pio = pair_pio;
-	}
-	it821x_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	/* XXX - We trim to the lowest of the pair so the other drive
-	   will always be fine at this point until we do hotplug passthru */
-
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
-}
-
-/**
  *	it821x_dma_read	-	DMA hook
  *	@drive: drive for DMA
  *
@@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_driv
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
 	u8 speed		= ide_rate_filter(it821x_ratemask(drive), xferspeed);
 
-	if(!itdev->smart) {
-		switch(speed) {
-			case XFER_PIO_4:
-			case XFER_PIO_3:
-			case XFER_PIO_2:
-			case XFER_PIO_1:
-			case XFER_PIO_0:
-				it821x_tuneproc(drive, (speed - XFER_PIO_0));
-				break;
+	switch (speed) {
+	case XFER_PIO_4:
+	case XFER_PIO_3:
+	case XFER_PIO_2:
+	case XFER_PIO_1:
+	case XFER_PIO_0:
+		return it821x_tunepio(drive, speed - XFER_PIO_0);
+	}
+
+	if (itdev->smart == 0) {
+		switch (speed) {
 			/* MWDMA tuning is really hard because our MWDMA and PIO
 			   timings are kept in the same place. We can switch in the
 			   host dma on/off callbacks */
@@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_d
 {
 	u8 speed	= ide_dma_speed(drive, it821x_ratemask(drive));
 
-	if (speed) {
-		config_it821x_chipset_for_pio(drive, 0);
-		it821x_tune_chipset(drive, speed);
+	if (speed == 0)
+		return 0;
 
-		return ide_dma_enable(drive);
-	}
+	it821x_tune_chipset(drive, speed);
 
-	return 0;
+	return ide_dma_enable(drive);
 }
 
 /**
@@ -523,7 +513,7 @@ static int it821x_config_drive_for_dma (
 	if (ide_use_dma(drive) && config_chipset_for_dma(drive))
 		return 0;
 
-	config_it821x_chipset_for_pio(drive, 1);
+	it821x_tuneproc(drive, 255);
 
 	return -1;
 }
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ace9892..2cdd629 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -255,9 +255,6 @@ static int config_chipset_for_dma(ide_dr
 		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
 	}
 
-	if (drive->media != ide_disk && drive->media != ide_cdrom)
-		return 0;
-
 	if (id->capability & 4) {
 		/*
 		 * Set IORDY_EN & PREFETCH_EN (this seems to have
@@ -398,7 +395,7 @@ static void __devinit apple_kiwi_init(st
 	unsigned int class_rev = 0;
 	u8 conf;
 
-	if (np == NULL || !device_is_compatible(np, "kiwi-root"))
+	if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
 		return;
 
 	pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 71eccdf..c0188de 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/siimage.c		Version 1.11	Jan 27, 2007
+ * linux/drivers/ide/pci/siimage.c		Version 1.12	Mar 10 2007
  *
  * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003		Red Hat <alan@redhat.com>
@@ -287,11 +287,6 @@ static void config_siimage_chipset_for_p
 		(void) ide_config_drive_speed(drive, speed);
 }
 
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	config_siimage_chipset_for_pio(drive, set_speed);
-}
-
 /**
  *	siimage_tune_chipset	-	set controller timings
  *	@drive: Drive to set up
@@ -396,8 +391,6 @@ static int config_chipset_for_dma (ide_d
 {
 	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
 
-	config_chipset_for_pio(drive, !speed);
-
 	if (!speed)
 		return 0;
 
@@ -423,7 +416,7 @@ static int siimage_config_drive_for_dma 
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		config_chipset_for_pio(drive, 1);
+		config_siimage_chipset_for_pio(drive, 1);
 
 	return -1;
 }
@@ -1015,7 +1008,6 @@ static void __devinit init_hwif_siimage(
 
 	hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
-	hwif->swdma_mask = 0x07;
 
 	if (!is_sata(hwif))
 		hwif->atapi_dma = 1;
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 3a8a76f..fe3b4b9 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -11,6 +11,8 @@
  * Merge in Russell's HW workarounds, fix various problems
  * with the timing registers setup.
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
+ *
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
  */
 
 #include <linux/types.h>
@@ -47,25 +49,19 @@ #define CTRL_P0F16      (1 << 1)
 #define CTRL_P0EN       (1 << 0)
 
 /*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface.  This has protection against run-away
- * timings.
+ * Convert a PIO mode and cycle time to the required on/off times
+ * for the interface.  This has protection against runaway timings.
  */
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_pio_data_t *p)
 {
-	unsigned int cmd_on;
-	unsigned int cmd_off;
+	unsigned int cmd_on, cmd_off;
 
-	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_on  = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
 	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
 
-	if (cmd_on > 32)
-		cmd_on = 32;
 	if (cmd_on == 0)
 		cmd_on = 1;
 
-	if (cmd_off > 32)
-		cmd_off = 32;
 	if (cmd_off == 0)
 		cmd_off = 1;
 
@@ -73,100 +69,59 @@ static unsigned int get_timing_sl82c105(
 }
 
 /*
- * Configure the drive and chipset for PIO
+ * Configure the chipset for PIO mode.
  */
-static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only)
+static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	int reg			= 0x44 + drive->dn * 4;
 	ide_pio_data_t p;
-	u16 drv_ctrl = 0x909;
-	unsigned int xfer_mode, reg;
+	u16 drv_ctrl;
 
-	DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n",
-		drive->name, pio, report, chipset_only));
-		
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+	DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
 
 	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
 
-	xfer_mode = XFER_PIO_0 + pio;
-
-	if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) {
-		drv_ctrl = get_timing_sl82c105(&p);
-		drive->pio_speed = xfer_mode;
-	} else
-		drive->pio_speed = XFER_PIO_0;
+	drive->drive_data = drv_ctrl = get_pio_timings(&p);
 
-	if (drive->using_dma == 0) {
+	if (!drive->using_dma) {
 		/*
 		 * If we are actually using MW DMA, then we can not
 		 * reprogram the interface drive control register.
 		 */
-		pci_write_config_word(dev, reg, drv_ctrl);
-		pci_read_config_word(dev, reg, &drv_ctrl);
-
-		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
-		}
+		pci_write_config_word(dev, reg,  drv_ctrl);
+		pci_read_config_word (dev, reg, &drv_ctrl);
 	}
+
+	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
+	       ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
+
+	return pio;
 }
 
 /*
- * Configure the drive and the chipset for DMA
+ * Configure the drive for DMA.
+ * We'll program the chipset only when DMA is actually turned on.
  */
-static int config_for_dma (ide_drive_t *drive)
+static int config_for_dma(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned int reg;
-
 	DBG(("config_for_dma(drive:%s)\n", drive->name));
 
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
 	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0)
-		return 1;
+		return 0;
 
-	pci_write_config_word(dev, reg, 0x0240);
-
-	return 0;
+	return ide_dma_enable(drive);
 }
 
 /*
- * Check to see if the drive and
- * chipset is capable of DMA mode
+ * Check to see if the drive and chipset are capable of DMA mode.
  */
-
-static int sl82c105_check_drive (ide_drive_t *drive)
+static int sl82c105_ide_dma_check(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	DBG(("sl82c105_check_drive(drive:%s)\n", drive->name));
-
-	do {
-		struct hd_driveid *id = drive->id;
-
-		if (!drive->autodma)
-			break;
-
-		if (!id || !(id->capability & 1))
-			break;
+	DBG(("sl82c105_ide_dma_check(drive:%s)\n", drive->name));
 
-		/* Consult the list of known "bad" drives */
-		if (__ide_dma_bad_drive(drive))
-			break;
-
-		if (id->field_valid & 2) {
-			if ((id->dma_mword & hwif->mwdma_mask) ||
-			    (id->dma_1word & hwif->swdma_mask))
-				return 0;
-		}
-
-		if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)
-			return 0;
-	} while (0);
+	if (ide_use_dma(drive) && config_for_dma(drive))
+		return 0;
 
 	return -1;
 }
@@ -195,14 +150,14 @@ static inline void sl82c105_reset_host(s
  * This function is called when the IDE timer expires, the drive
  * indicates that it is READY, and we were waiting for DMA to complete.
  */
-static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
+static int sl82c105_ide_dma_lostirq(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
-	unsigned long dma_base = hwif->dma_base;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 val, mask		= hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+	u8 dma_cmd;
 
-	printk("sl82c105: lost IRQ: resetting host\n");
+	printk("sl82c105: lost IRQ, resetting host\n");
 
 	/*
 	 * Check the raw interrupt from the drive.
@@ -215,15 +170,15 @@ static int sl82c105_ide_dma_lost_irq(ide
 	 * Was DMA enabled?  If so, disable it - we're resetting the
 	 * host.  The IDE layer will be handling the drive for us.
 	 */
-	val = inb(dma_base);
-	if (val & 1) {
-		outb(val & ~1, dma_base);
+	dma_cmd = inb(hwif->dma_command);
+	if (dma_cmd & 1) {
+		outb(dma_cmd & ~1, hwif->dma_command);
 		printk("sl82c105: DMA was enabled\n");
 	}
 
 	sl82c105_reset_host(dev);
 
-	/* ide_dmaproc would return 1, so we do as well */
+	/* __ide_dma_lostirq would return 1, so we do as well */
 	return 1;
 }
 
@@ -235,10 +190,10 @@ static int sl82c105_ide_dma_lost_irq(ide
  * The generic IDE core will have disabled the BMEN bit before this
  * function is called.
  */
-static void sl82c105_ide_dma_start(ide_drive_t *drive)
+static void sl82c105_dma_start(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 
 	sl82c105_reset_host(dev);
 	ide_dma_start(drive);
@@ -246,8 +201,8 @@ static void sl82c105_ide_dma_start(ide_d
 
 static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 
 	DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
 
@@ -255,26 +210,32 @@ static int sl82c105_ide_dma_timeout(ide_
 	return __ide_dma_timeout(drive);
 }
 
-static int sl82c105_ide_dma_on (ide_drive_t *drive)
+static int sl82c105_ide_dma_on(ide_drive_t *drive)
 {
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	int rc, reg 		= 0x44 + drive->dn * 4;
+
 	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
 
-	if (config_for_dma(drive))
-		return 1;
-	printk(KERN_INFO "%s: DMA enabled\n", drive->name);
-	return __ide_dma_on(drive);
+	rc = __ide_dma_on(drive);
+	if (rc == 0) {
+		pci_write_config_word(dev, reg, 0x0200);
+
+		printk(KERN_INFO "%s: DMA enabled\n", drive->name);
+	}
+	return rc;
 }
 
 static void sl82c105_dma_off_quietly(ide_drive_t *drive)
 {
-	u8 speed = XFER_PIO_0;
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	int reg 		= 0x44 + drive->dn * 4;
 
 	DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
 
+	pci_write_config_word(dev, reg, drive->drive_data);
+
 	ide_dma_off_quietly(drive);
-	if (drive->pio_speed)
-		speed = drive->pio_speed - XFER_PIO_0;
-	config_for_pio(drive, speed, 0, 1);
 }
 
 /*
@@ -286,8 +247,8 @@ static void sl82c105_dma_off_quietly(ide
  */
 static void sl82c105_selectproc(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
 	u32 val, old, mask;
 
 	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
@@ -323,18 +284,12 @@ static void sl82c105_resetproc(ide_drive
  * We only deal with PIO mode here - DMA mode 'using_dma' is not
  * initialised at the point that this function is called.
  */
-static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
 {
-	DBG(("tune_sl82c105(drive:%s)\n", drive->name));
-
-	config_for_pio(drive, pio, 1, 0);
+	DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio));
 
-	/*
-	 * We support 32-bit I/O on this interface, and it
-	 * doesn't have problems with interrupts.
-	 */
-	drive->io_32bit = 1;
-	drive->unmask = 1;
+	pio = sl82c105_tune_pio(drive, pio);
+	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /*
@@ -393,7 +348,7 @@ static unsigned int __devinit init_chips
 }
 
 /*
- * Initialise the chip
+ * Initialise IDE channel
  */
 static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 {
@@ -401,24 +356,22 @@ static void __devinit init_hwif_sl82c105
 
 	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
 
-	hwif->tuneproc = tune_sl82c105;
-	hwif->selectproc = sl82c105_selectproc;
-	hwif->resetproc = sl82c105_resetproc;
+	hwif->tuneproc		= &sl82c105_tune_drive;
+	hwif->selectproc	= &sl82c105_selectproc;
+	hwif->resetproc 	= &sl82c105_resetproc;
+
+	/*
+	 * We support 32-bit I/O on this interface, and
+	 * it doesn't have problems with interrupts.
+	 */
+	hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1;
+	hwif->drives[0].unmask   = hwif->drives[1].unmask   = 1;
 
 	/*
-	 * Default to PIO 0 for fallback unless tuned otherwise.
 	 * We always autotune PIO,  this is done before DMA is checked,
 	 * so there's no risk of accidentally disabling DMA
 	 */
-	hwif->drives[0].pio_speed = XFER_PIO_0;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].pio_speed = XFER_PIO_0;
-	hwif->drives[1].autotune = 1;
-
-	hwif->atapi_dma = 0;
-	hwif->mwdma_mask = 0;
-	hwif->swdma_mask = 0;
-	hwif->autodma = 0;
+	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
 	if (!hwif->dma_base)
 		return;
@@ -429,27 +382,27 @@ static void __devinit init_hwif_sl82c105
 		 * Never ever EVER under any circumstances enable
 		 * DMA when the bridge is this old.
 		 */
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-	} else {
-		hwif->atapi_dma = 1;
-		hwif->mwdma_mask = 0x04;
-
-		hwif->ide_dma_check = &sl82c105_check_drive;
-		hwif->ide_dma_on = &sl82c105_ide_dma_on;
-		hwif->dma_off_quietly = &sl82c105_dma_off_quietly;
-		hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
-		hwif->dma_start = &sl82c105_ide_dma_start;
-		hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
-
-		if (!noautodma)
-			hwif->autodma = 1;
-		hwif->drives[0].autodma = hwif->autodma;
-		hwif->drives[1].autodma = hwif->autodma;
-
-		if (hwif->mate)
-			hwif->serialized = hwif->mate->serialized = 1;
+		printk("    %s: Winbond W83C553 bridge revision %d, "
+		       "BM-DMA disabled\n", hwif->name, rev);
+		return;
 	}
+
+	hwif->atapi_dma  = 1;
+	hwif->mwdma_mask = 0x04;
+
+	hwif->ide_dma_check		= &sl82c105_ide_dma_check;
+	hwif->ide_dma_on		= &sl82c105_ide_dma_on;
+	hwif->dma_off_quietly		= &sl82c105_dma_off_quietly;
+	hwif->ide_dma_lostirq		= &sl82c105_ide_dma_lostirq;
+	hwif->dma_start			= &sl82c105_dma_start;
+	hwif->ide_dma_timeout		= &sl82c105_ide_dma_timeout;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
 }
 
 static ide_pci_device_t sl82c105_chipset __devinitdata = {
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 071a030..a49ebe4 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1157,32 +1157,32 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 
 	pmif->cable_80 = 0;
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
-	if (device_is_compatible(np, "shasta-ata"))
+	if (of_device_is_compatible(np, "shasta-ata"))
 		pmif->kind = controller_sh_ata6;
-	else if (device_is_compatible(np, "kauai-ata"))
+	else if (of_device_is_compatible(np, "kauai-ata"))
 		pmif->kind = controller_un_ata6;
-	else if (device_is_compatible(np, "K2-UATA"))
+	else if (of_device_is_compatible(np, "K2-UATA"))
 		pmif->kind = controller_k2_ata6;
-	else if (device_is_compatible(np, "keylargo-ata")) {
+	else if (of_device_is_compatible(np, "keylargo-ata")) {
 		if (strcmp(np->name, "ata-4") == 0)
 			pmif->kind = controller_kl_ata4;
 		else
 			pmif->kind = controller_kl_ata3;
-	} else if (device_is_compatible(np, "heathrow-ata"))
+	} else if (of_device_is_compatible(np, "heathrow-ata"))
 		pmif->kind = controller_heathrow;
 	else {
 		pmif->kind = controller_ohare;
 		pmif->broken_dma = 1;
 	}
 
-	bidp = get_property(np, "AAPL,bus-id", NULL);
+	bidp = of_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) {
-		const char* cable = get_property(np, "cable-type", NULL);
+		const char* cable = of_get_property(np, "cable-type", NULL);
 		if (cable && !strncmp(cable, "80-", 3))
 			pmif->cable_80 = 1;
 	}
@@ -1190,8 +1190,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	 * they have a 80 conductor cable, this seem to be always the case unless
 	 * the user mucked around
 	 */
-	if (device_is_compatible(np, "K2-UATA") ||
-	    device_is_compatible(np, "shasta-ata"))
+	if (of_device_is_compatible(np, "K2-UATA") ||
+	    of_device_is_compatible(np, "shasta-ata"))
 		pmif->cable_80 = 1;
 
 	/* On Kauai-type controllers, we make sure the FCR is correct */
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index cd84a55..61d7809 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -1,11 +1,8 @@
-# -*- shell-script -*-
-
 menu "IEEE 1394 (FireWire) support"
 
 config IEEE1394
 	tristate "IEEE 1394 (FireWire) support"
 	depends on PCI || BROKEN
-	select NET
 	help
 	  IEEE 1394 describes a high performance serial bus, which is also
 	  known as FireWire(tm) or i.Link(tm) and is used for connecting all
@@ -35,24 +32,7 @@ config IEEE1394_VERBOSEDEBUG
 	  Say Y if you really want or need the debugging output, everyone
 	  else says N.
 
-config IEEE1394_EXTRA_CONFIG_ROMS
-	bool "Build in extra config rom entries for certain functionality"
-	depends on IEEE1394
-	help
-	  Some IEEE1394 functionality depends on extra config rom entries
-	  being available in the host adapters CSR. These options will
-	  allow you to choose which ones.
-
-config IEEE1394_CONFIG_ROM_IP1394
-	bool "IP-1394 Entry"
-	depends on IEEE1394_EXTRA_CONFIG_ROMS && IEEE1394
-	help
-	  Adds an entry for using IP-over-1394. If you want to use your
-	  IEEE1394 bus as a network for IP systems (including interacting
-	  with MacOSX and WinXP IP-over-1394), enable this option and the
-	  eth1394 option below.
-
-comment "Device Drivers"
+comment "Controllers"
 	depends on IEEE1394
 
 comment "Texas Instruments PCILynx requires I2C"
@@ -70,6 +50,10 @@ config IEEE1394_PCILYNX
 	  To compile this driver as a module, say M here: the
 	  module will be called pcilynx.
 
+	  Only some old and now very rare PCI and CardBus cards and
+	  PowerMacs G3 B&W contain the PCILynx controller.  Therefore
+	  almost everybody can say N here.
+
 config IEEE1394_OHCI1394
 	tristate "OHCI-1394 support"
 	depends on PCI && IEEE1394
@@ -83,7 +67,7 @@ config IEEE1394_OHCI1394
 	  To compile this driver as a module, say M here: the
 	  module will be called ohci1394.
 
-comment "Protocol Drivers"
+comment "Protocols"
 	depends on IEEE1394
 
 config IEEE1394_VIDEO1394
@@ -121,11 +105,15 @@ config IEEE1394_SBP2_PHYS_DMA
 	  This option is buggy and currently broken on some architectures.
 	  If unsure, say N.
 
+config IEEE1394_ETH1394_ROM_ENTRY
+	depends on IEEE1394
+	bool
+	default n
+
 config IEEE1394_ETH1394
-	tristate "Ethernet over 1394"
+	tristate "IP over 1394"
 	depends on IEEE1394 && EXPERIMENTAL && INET
-	select IEEE1394_CONFIG_ROM_IP1394
-	select IEEE1394_EXTRA_CONFIG_ROMS
+	select IEEE1394_ETH1394_ROM_ENTRY
 	help
 	  This driver implements a functional majority of RFC 2734: IPv4 over
 	  1394.  It will provide IP connectivity with implementations of RFC
@@ -134,6 +122,8 @@ config IEEE1394_ETH1394
 	  This driver is still considered experimental.  It does not yet support
 	  MCAP, therefore multicast support is significantly limited.
 
+	  The module is called eth1394 although it does not emulate Ethernet.
+
 config IEEE1394_DV1394
 	tristate "OHCI-DV I/O support (deprecated)"
 	depends on IEEE1394 && IEEE1394_OHCI1394
@@ -146,12 +136,12 @@ config IEEE1394_RAWIO
 	tristate "Raw IEEE1394 I/O support"
 	depends on IEEE1394
 	help
-	  Say Y here if you want support for the raw device. This is generally
-	  a good idea, so you should say Y here. The raw device enables
-	  direct communication of user programs with the IEEE 1394 bus and
-	  thus with the attached peripherals.
+	  This option adds support for the raw1394 device file which enables
+	  direct communication of user programs with the IEEE 1394 bus and thus
+	  with the attached peripherals.  Almost all application programs which
+	  access FireWire require this option.
 
-	  To compile this driver as a module, say M here: the
-	  module will be called raw1394.
+	  To compile this driver as a module, say M here: the module will be
+	  called raw1394.
 
 endmenu
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
index e2de6fa..1b98120 100644
--- a/drivers/ieee1394/config_roms.c
+++ b/drivers/ieee1394/config_roms.c
@@ -26,12 +26,6 @@ struct hpsb_config_rom_entry {
 	/* Base initialization, called at module load */
 	int (*init)(void);
 
-	/* Add entry to specified host */
-	int (*add)(struct hpsb_host *host);
-
-	/* Remove entry from specified host */
-	void (*remove)(struct hpsb_host *host);
-
 	/* Cleanup called at module exit */
 	void (*cleanup)(void);
 
@@ -39,7 +33,7 @@ struct hpsb_config_rom_entry {
 	unsigned int flag;
 };
 
-
+/* The default host entry. This must succeed. */
 int hpsb_default_host_entry(struct hpsb_host *host)
 {
 	struct csr1212_keyval *root;
@@ -63,9 +57,9 @@ int hpsb_default_host_entry(struct hpsb_
 		return -ENOMEM;
 	}
 
-	ret = csr1212_associate_keyval(vend_id, text);
+	csr1212_associate_keyval(vend_id, text);
 	csr1212_release_keyval(text);
-	ret |= csr1212_attach_keyval_to_directory(root, vend_id);
+	ret = csr1212_attach_keyval_to_directory(root, vend_id);
 	csr1212_release_keyval(vend_id);
 	if (ret != CSR1212_SUCCESS) {
 		csr1212_destroy_csr(host->csr.rom);
@@ -78,7 +72,7 @@ int hpsb_default_host_entry(struct hpsb_
 }
 
 
-#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
 #include "eth1394.h"
 
 static struct csr1212_keyval *ip1394_ud;
@@ -103,10 +97,12 @@ static int config_rom_ip1394_init(void)
 	if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
 		goto ip1394_fail;
 
-	if (csr1212_associate_keyval(spec_id, spec_desc) == CSR1212_SUCCESS &&
-	    csr1212_associate_keyval(ver, ver_desc) == CSR1212_SUCCESS &&
-	    csr1212_attach_keyval_to_directory(ip1394_ud, spec_id) == CSR1212_SUCCESS &&
-	    csr1212_attach_keyval_to_directory(ip1394_ud, ver) == CSR1212_SUCCESS)
+	csr1212_associate_keyval(spec_id, spec_desc);
+	csr1212_associate_keyval(ver, ver_desc);
+	if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
+			== CSR1212_SUCCESS &&
+	    csr1212_attach_keyval_to_directory(ip1394_ud, ver)
+			== CSR1212_SUCCESS)
 		ret = 0;
 
 ip1394_fail:
@@ -135,7 +131,7 @@ static void config_rom_ip1394_cleanup(vo
 	}
 }
 
-static int config_rom_ip1394_add(struct hpsb_host *host)
+int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
 {
 	if (!ip1394_ud)
 		return -ENODEV;
@@ -144,92 +140,55 @@ static int config_rom_ip1394_add(struct 
 					       ip1394_ud) != CSR1212_SUCCESS)
 		return -ENOMEM;
 
+	host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
+	host->update_config_rom = 1;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
 
-static void config_rom_ip1394_remove(struct hpsb_host *host)
+void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
 {
 	csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
+	host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
+	host->update_config_rom = 1;
 }
+EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
 
 static struct hpsb_config_rom_entry ip1394_entry = {
 	.name		= "ip1394",
 	.init		= config_rom_ip1394_init,
-	.add		= config_rom_ip1394_add,
-	.remove		= config_rom_ip1394_remove,
 	.cleanup	= config_rom_ip1394_cleanup,
 	.flag		= HPSB_CONFIG_ROM_ENTRY_IP1394,
 };
-#endif /* CONFIG_IEEE1394_CONFIG_ROM_IP1394 */
 
+#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
 
 static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
 	&ip1394_entry,
 #endif
-	NULL,
 };
 
-
+/* Initialize all config roms */
 int hpsb_init_config_roms(void)
 {
 	int i, error = 0;
 
-	for (i = 0; config_rom_entries[i]; i++) {
-		if (!config_rom_entries[i]->init)
-			continue;
-
+	for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
 		if (config_rom_entries[i]->init()) {
 			HPSB_ERR("Failed to initialize config rom entry `%s'",
 				 config_rom_entries[i]->name);
 			error = -1;
-		} else
-			HPSB_DEBUG("Initialized config rom entry `%s'",
-				   config_rom_entries[i]->name);
-	}
-
-	return error;
-}
-
-void hpsb_cleanup_config_roms(void)
-{
-	int i;
-
-	for (i = 0; config_rom_entries[i]; i++) {
-		if (config_rom_entries[i]->cleanup)
-			config_rom_entries[i]->cleanup();
-	}
-}
-
-int hpsb_add_extra_config_roms(struct hpsb_host *host)
-{
-	int i, error = 0;
-
-	for (i = 0; config_rom_entries[i]; i++) {
-		if (config_rom_entries[i]->add(host)) {
-			HPSB_ERR("fw-host%d: Failed to attach config rom entry `%s'",
-				 host->id, config_rom_entries[i]->name);
-			error = -1;
-		} else {
-			host->config_roms |= config_rom_entries[i]->flag;
-			host->update_config_rom = 1;
 		}
-	}
 
 	return error;
 }
 
-void hpsb_remove_extra_config_roms(struct hpsb_host *host)
+/* Cleanup all config roms */
+void hpsb_cleanup_config_roms(void)
 {
 	int i;
 
-	for (i = 0; config_rom_entries[i]; i++) {
-		if (!(host->config_roms & config_rom_entries[i]->flag))
-			continue;
-
-		config_rom_entries[i]->remove(host);
-
-		host->config_roms &= ~config_rom_entries[i]->flag;
-		host->update_config_rom = 1;
-	}
+	for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
+		config_rom_entries[i]->cleanup();
 }
diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h
index 0a70544..1f5cd1f 100644
--- a/drivers/ieee1394/config_roms.h
+++ b/drivers/ieee1394/config_roms.h
@@ -1,27 +1,19 @@
 #ifndef _IEEE1394_CONFIG_ROMS_H
 #define _IEEE1394_CONFIG_ROMS_H
 
-#include "ieee1394_types.h"
-#include "hosts.h"
+struct hpsb_host;
 
-/* The default host entry. This must succeed. */
 int hpsb_default_host_entry(struct hpsb_host *host);
-
-/* Initialize all config roms */
 int hpsb_init_config_roms(void);
-
-/* Cleanup all config roms */
 void hpsb_cleanup_config_roms(void);
 
-/* Add extra config roms to specified host */
-int hpsb_add_extra_config_roms(struct hpsb_host *host);
-
-/* Remove extra config roms from specified host */
-void hpsb_remove_extra_config_roms(struct hpsb_host *host);
-
-
 /* List of flags to check if a host contains a certain extra config rom
  * entry. Available in the host->config_roms member. */
 #define HPSB_CONFIG_ROM_ENTRY_IP1394		0x00000001
 
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
+int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
+void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
+#endif
+
 #endif /* _IEEE1394_CONFIG_ROMS_H */
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index c28f639..d08166b 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -31,12 +31,13 @@
 /* TODO List:
  * - Verify interface consistency: i.e., public functions that take a size
  *   parameter expect size to be in bytes.
- * - Convenience functions for reading a block of data from a given offset.
  */
 
-#ifndef __KERNEL__
-#include <string.h>
-#endif
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/bug.h>
+#include <asm/byteorder.h>
 
 #include "csr1212.h"
 
@@ -46,7 +47,7 @@ #define __I (1 << CSR1212_KV_TYPE_IMMEDI
 #define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
 #define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
 #define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u_int8_t csr1212_key_id_type_map[0x30] = {
+static const u8 csr1212_key_id_type_map[0x30] = {
 	__C,			/* used by Apple iSight */
 	__D | __L,		/* Descriptor */
 	__I | __D | __L,	/* Bus_Dependent_Info */
@@ -82,10 +83,10 @@ #undef __D
 #undef __L
 
 
-#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t))
-#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t))
+#define quads_to_bytes(_q) ((_q) * sizeof(u32))
+#define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32))
 
-static inline void free_keyval(struct csr1212_keyval *kv)
+static void free_keyval(struct csr1212_keyval *kv)
 {
 	if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
 	    (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
@@ -94,14 +95,14 @@ static inline void free_keyval(struct cs
 	CSR1212_FREE(kv);
 }
 
-static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
+static u16 csr1212_crc16(const u32 *buffer, size_t length)
 {
 	int shift;
-	u_int32_t data;
-	u_int16_t sum, crc = 0;
+	u32 data;
+	u16 sum, crc = 0;
 
 	for (; length; length--) {
-		data = CSR1212_BE32_TO_CPU(*buffer);
+		data = be32_to_cpu(*buffer);
 		buffer++;
 		for (shift = 28; shift >= 0; shift -= 4 ) {
 			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
@@ -110,21 +111,18 @@ static u_int16_t csr1212_crc16(const u_i
 		crc &= 0xffff;
 	}
 
-	return CSR1212_CPU_TO_BE16(crc);
+	return cpu_to_be16(crc);
 }
 
-#if 0
-/* Microsoft computes the CRC with the bytes in reverse order.  Therefore we
- * have a special version of the CRC algorithm to account for their buggy
- * software. */
-static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
+/* Microsoft computes the CRC with the bytes in reverse order. */
+static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
 {
 	int shift;
-	u_int32_t data;
-	u_int16_t sum, crc = 0;
+	u32 data;
+	u16 sum, crc = 0;
 
 	for (; length; length--) {
-		data = CSR1212_LE32_TO_CPU(*buffer);
+		data = le32_to_cpu(*buffer);
 		buffer++;
 		for (shift = 28; shift >= 0; shift -= 4 ) {
 			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
@@ -133,38 +131,35 @@ static u_int16_t csr1212_msft_crc16(cons
 		crc &= 0xffff;
 	}
 
-	return CSR1212_CPU_TO_BE16(crc);
+	return cpu_to_be16(crc);
 }
-#endif
 
-static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir,
-							 struct csr1212_keyval *kv)
+static struct csr1212_dentry *
+csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
 {
 	struct csr1212_dentry *pos;
 
 	for (pos = dir->value.directory.dentries_head;
-	     pos != NULL; pos = pos->next) {
+	     pos != NULL; pos = pos->next)
 		if (pos->kv == kv)
 			return pos;
-	}
 	return NULL;
 }
 
-
-static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list,
-								u_int32_t offset)
+static struct csr1212_keyval *
+csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
 {
 	struct csr1212_keyval *kv;
 
-	for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) {
+	for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
 		if (kv->offset == offset)
 			return kv;
-	}
 	return NULL;
 }
 
 
 /* Creation Routines */
+
 struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
 				       size_t bus_info_size, void *private)
 {
@@ -202,27 +197,17 @@ struct csr1212_csr *csr1212_create_csr(s
 	return csr;
 }
 
-
-
 void csr1212_init_local_csr(struct csr1212_csr *csr,
-			    const u_int32_t *bus_info_data, int max_rom)
+			    const u32 *bus_info_data, int max_rom)
 {
 	static const int mr_map[] = { 4, 64, 1024, 0 };
 
-#ifdef __KERNEL__
 	BUG_ON(max_rom & ~0x3);
 	csr->max_rom = mr_map[max_rom];
-#else
-	if (max_rom & ~0x3) /* caller supplied invalid argument */
-		csr->max_rom = 0;
-	else
-		csr->max_rom = mr_map[max_rom];
-#endif
 	memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
 }
 
-
-static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
+static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
 {
 	struct csr1212_keyval *kv;
 
@@ -246,10 +231,11 @@ static struct csr1212_keyval *csr1212_ne
 	return kv;
 }
 
-struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
+struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
 {
-	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
+	struct csr1212_keyval *kv;
 
+	kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
 	if (!kv)
 		return NULL;
 
@@ -258,10 +244,12 @@ struct csr1212_keyval *csr1212_new_immed
 	return kv;
 }
 
-struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len)
+static struct csr1212_keyval *
+csr1212_new_leaf(u8 key, const void *data, size_t data_len)
 {
-	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
+	struct csr1212_keyval *kv;
 
+	kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
 	if (!kv)
 		return NULL;
 
@@ -285,10 +273,12 @@ struct csr1212_keyval *csr1212_new_leaf(
 	return kv;
 }
 
-struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset)
+static struct csr1212_keyval *
+csr1212_new_csr_offset(u8 key, u32 csr_offset)
 {
-	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
+	struct csr1212_keyval *kv;
 
+	kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
 	if (!kv)
 		return NULL;
 
@@ -299,10 +289,11 @@ struct csr1212_keyval *csr1212_new_csr_o
 	return kv;
 }
 
-struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
+struct csr1212_keyval *csr1212_new_directory(u8 key)
 {
-	struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
+	struct csr1212_keyval *kv;
 
+	kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
 	if (!kv)
 		return NULL;
 
@@ -314,43 +305,29 @@ struct csr1212_keyval *csr1212_new_direc
 	return kv;
 }
 
-int csr1212_associate_keyval(struct csr1212_keyval *kv,
-			     struct csr1212_keyval *associate)
+void csr1212_associate_keyval(struct csr1212_keyval *kv,
+			      struct csr1212_keyval *associate)
 {
-	if (!kv || !associate)
-		return CSR1212_EINVAL;
-
-	if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
-	   (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
-	    associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
-	    associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
-	    associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
-	    associate->key.id < 0x30))
-		return CSR1212_EINVAL;
-
-	if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
-	   associate->key.id != CSR1212_KV_ID_EXTENDED_KEY)
-		return CSR1212_EINVAL;
-
-	if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-	   associate->key.id != CSR1212_KV_ID_EXTENDED_DATA)
-		return CSR1212_EINVAL;
-
-	if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-	   kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID)
-		return CSR1212_EINVAL;
-
-	if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
-	   kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)
-		return CSR1212_EINVAL;
+	BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
+	       (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
+		associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
+		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
+		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
+		associate->key.id < 0x30) ||
+	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
+		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
+	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
+	       (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
+	       (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
+		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
 
 	if (kv->associate)
 		csr1212_release_keyval(kv->associate);
 
 	associate->refcnt++;
 	kv->associate = associate;
-
-	return CSR1212_SUCCESS;
 }
 
 int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
@@ -358,12 +335,11 @@ int csr1212_attach_keyval_to_directory(s
 {
 	struct csr1212_dentry *dentry;
 
-	if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
-		return CSR1212_EINVAL;
+	BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
 
 	dentry = CSR1212_MALLOC(sizeof(*dentry));
 	if (!dentry)
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 
 	dentry->kv = kv;
 
@@ -382,66 +358,22 @@ int csr1212_attach_keyval_to_directory(s
 	return CSR1212_SUCCESS;
 }
 
-struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key,
-						      u_int32_t value)
-{
-	struct csr1212_keyval *kvs, *kvk, *kvv;
-
-	kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
-	kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
-	kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value);
-
-	if (!kvs || !kvk || !kvv) {
-		if (kvs)
-			free_keyval(kvs);
-		if (kvk)
-			free_keyval(kvk);
-		if (kvv)
-			free_keyval(kvv);
-		return NULL;
-	}
-
-	/* Don't keep a local reference to the extended key or value. */
-	kvk->refcnt = 0;
-	kvv->refcnt = 0;
-
-	csr1212_associate_keyval(kvk, kvv);
-	csr1212_associate_keyval(kvs, kvk);
-
-	return kvs;
-}
-
-struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, u_int32_t key,
-						 const void *data, size_t data_len)
-{
-	struct csr1212_keyval *kvs, *kvk, *kvv;
-
-	kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
-	kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
-	kvv = csr1212_new_leaf(CSR1212_KV_ID_EXTENDED_DATA, data, data_len);
-
-	if (!kvs || !kvk || !kvv) {
-		if (kvs)
-			free_keyval(kvs);
-		if (kvk)
-			free_keyval(kvk);
-		if (kvv)
-			free_keyval(kvv);
-		return NULL;
-	}
-
-	/* Don't keep a local reference to the extended key or value. */
-	kvk->refcnt = 0;
-	kvv->refcnt = 0;
-
-	csr1212_associate_keyval(kvk, kvv);
-	csr1212_associate_keyval(kvs, kvk);
-
-	return kvs;
-}
-
-struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id,
-						   const void *data, size_t data_len)
+#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
+	(&((kv)->value.leaf.data[1]))
+
+#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
+	((kv)->value.leaf.data[0] = \
+	 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
+		     ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
+#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
+	((kv)->value.leaf.data[0] = \
+	 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
+		      CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
+		     ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
+
+static struct csr1212_keyval *
+csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
+			    const void *data, size_t data_len)
 {
 	struct csr1212_keyval *kv;
 
@@ -453,197 +385,72 @@ struct csr1212_keyval *csr1212_new_descr
 	CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
 	CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
 
-	if (data) {
+	if (data)
 		memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
-	}
-
-	return kv;
-}
-
-
-struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
-							   u_int16_t cset,
-							   u_int16_t language,
-							   const void *data,
-							   size_t data_len)
-{
-	struct csr1212_keyval *kv;
-	char *lstr;
-
-	kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
-					 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
-	if (!kv)
-		return NULL;
-
-	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
-	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
-	CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
-
-	lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
-
-	/* make sure last quadlet is zeroed out */
-	*((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0;
-
-	/* don't copy the NUL terminator */
-	memcpy(lstr, data, data_len);
 
 	return kv;
 }
 
+/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
 static int csr1212_check_minimal_ascii(const char *s)
 {
 	static const char minimal_ascii_table[] = {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-		0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x20, 0x21, 0x22, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x5f,
-		0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
+					/*  1   2   4   8  16  32  64  128 */
+		128,			/* --, --, --, --, --, --, --, 07, */
+		4 + 16 + 32,		/* --, --, 0a, --, 0C, 0D, --, --, */
+		0,			/* --, --, --, --, --, --, --, --, */
+		0,			/* --, --, --, --, --, --, --, --, */
+		255 - 8 - 16,		/* 20, 21, 22, --, --, 25, 26, 27, */
+		255,			/* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
+		255,			/* 30, 31, 32, 33, 34, 35, 36, 37, */
+		255,			/* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
+		255,			/* 40, 41, 42, 43, 44, 45, 46, 47, */
+		255,			/* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
+		255,			/* 50, 51, 52, 53, 54, 55, 56, 57, */
+		1 + 2 + 4 + 128,	/* 58, 59, 5a, --, --, --, --, 5f, */
+		255 - 1,		/* --, 61, 62, 63, 64, 65, 66, 67, */
+		255,			/* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
+		255,			/* 70, 71, 72, 73, 74, 75, 76, 77, */
+		1 + 2 + 4,		/* 78, 79, 7a, --, --, --, --, --, */
 	};
+	int i, j;
+
 	for (; *s; s++) {
-		if (minimal_ascii_table[*s & 0x7F] != *s)
-			return -1; /* failed */
+		i = *s >> 3;		/*  i = *s / 8;		*/
+		j = 1 << (*s & 3);	/*  j = 1 << (*s % 8);	*/
+
+		if (i >= ARRAY_SIZE(minimal_ascii_table) ||
+		    !(minimal_ascii_table[i] & j))
+			return -EINVAL;
 	}
-	/* String conforms to minimal-ascii, as specified by IEEE 1212,
-	 * par. 7.4 */
 	return 0;
 }
 
+/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
 struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
 {
-	/* Check if string conform to minimal_ascii format */
-	if (csr1212_check_minimal_ascii(s))
-		return NULL;
-
-	/* IEEE 1212, par. 7.5.4.1  Textual descriptors (minimal ASCII) */
-	return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
-}
-
-struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
-							u_int8_t palette_depth,
-							u_int8_t color_space,
-							u_int16_t language,
-							u_int16_t hscan,
-							u_int16_t vscan,
-							u_int32_t *palette,
-							u_int32_t *pixels)
-{
-	static const int pd[4] = { 0, 4, 16, 256 };
-	static const int cs[16] = { 4, 2 };
 	struct csr1212_keyval *kv;
-	int palette_size;
-	int pixel_size = (hscan * vscan + 3) & ~0x3;
+	u32 *text;
+	size_t str_len, quads;
 
-	if (!pixels || (!palette && palette_depth) ||
-	    (palette_depth & ~0x3) || (color_space & ~0xf))
+	if (!s || !*s || csr1212_check_minimal_ascii(s))
 		return NULL;
 
-	palette_size = pd[palette_depth] * cs[color_space];
-
-	kv = csr1212_new_descriptor_leaf(1, 0, NULL,
-					 palette_size + pixel_size +
-					 CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
+	str_len = strlen(s);
+	quads = bytes_to_quads(str_len);
+	kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
+				      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
 	if (!kv)
 		return NULL;
 
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version);
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth);
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space);
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan);
-	CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan);
-
-	if (palette_size)
-		memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette,
-		       palette_size);
-
-	memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size);
-
-	return kv;
-}
-
-struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
-							      u_int64_t address)
-{
-	struct csr1212_keyval *kv;
-
-	/* IEEE 1212, par. 7.5.4.3  Modifiable descriptors */
-	kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t));
-	if(!kv)
-		return NULL;
-
-	CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size);
-	CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address);
-	CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address);
+	kv->value.leaf.data[1] = 0;	/* width, character_set, language */
+	text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
+	text[quads - 1] = 0;		/* padding */
+	memcpy(text, s, str_len);
 
 	return kv;
 }
 
-static int csr1212_check_keyword(const char *s)
-{
-	for (; *s; s++) {
-
-		if (('A' <= *s) && (*s <= 'Z'))
-			continue;
-		if (('0' <= *s) && (*s <= '9'))
-			continue;
-		if (*s == '-')
-			continue;
-
-		return -1; /* failed */
-	}
-	/* String conforms to keyword, as specified by IEEE 1212,
-	 * par. 7.6.5 */
-	return CSR1212_SUCCESS;
-}
-
-struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[])
-{
-	struct csr1212_keyval *kv;
-	char *buffer;
-	int i, data_len = 0;
-
-	/* Check all keywords to see if they conform to restrictions:
-	 * Only the following characters is allowed ['A'..'Z','0'..'9','-']
-	 * Each word is zero-terminated.
-	 * Also calculate the total length of the keywords.
-	 */
-	for (i = 0; i < strc; i++) {
-		if (!strv[i] || csr1212_check_keyword(strv[i])) {
-			return NULL;
-		}
-		data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */
-	}
-
-	/* IEEE 1212, par. 7.6.5 Keyword leaves */
-	kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len);
-	if (!kv)
-		return NULL;
-
-	buffer = (char *)kv->value.leaf.data;
-
-	/* make sure last quadlet is zeroed out */
-	*((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0;
-
-	/* Copy keyword(s) into leaf data buffer */
-	for (i = 0; i < strc; i++) {
-		int len = strlen(strv[i]) + 1;
-		memcpy(buffer, strv[i], len);
-		buffer += len;
-	}
-	return kv;
-}
-
 
 /* Destruction Routines */
 
@@ -674,23 +481,12 @@ void csr1212_detach_keyval_from_director
 	csr1212_release_keyval(kv);
 }
 
-
-void csr1212_disassociate_keyval(struct csr1212_keyval *kv)
-{
-	if (kv->associate) {
-		csr1212_release_keyval(kv->associate);
-	}
-
-	kv->associate = NULL;
-}
-
-
 /* This function is used to free the memory taken by a keyval.  If the given
  * keyval is a directory type, then any keyvals contained in that directory
  * will be destroyed as well if their respective refcnts are 0.  By means of
  * list manipulation, this routine will descend a directory structure in a
  * non-recursive manner. */
-void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
+static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
 {
 	struct csr1212_keyval *k, *a;
 	struct csr1212_dentry dentry;
@@ -715,11 +511,13 @@ void _csr1212_destroy_keyval(struct csr1
 			a = k->associate;
 
 			if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
-				/* If the current entry is a directory, then move all
+				/* If the current entry is a directory, move all
 				 * the entries to the destruction list. */
 				if (k->value.directory.dentries_head) {
-					tail->next = k->value.directory.dentries_head;
-					k->value.directory.dentries_head->prev = tail;
+					tail->next =
+					    k->value.directory.dentries_head;
+					k->value.directory.dentries_head->prev =
+					    tail;
 					tail = k->value.directory.dentries_tail;
 				}
 			}
@@ -729,15 +527,22 @@ void _csr1212_destroy_keyval(struct csr1
 
 		head = head->next;
 		if (head) {
-			if (head->prev && head->prev != &dentry) {
+			if (head->prev && head->prev != &dentry)
 				CSR1212_FREE(head->prev);
-			}
 			head->prev = NULL;
-		} else if (tail != &dentry)
+		} else if (tail != &dentry) {
 			CSR1212_FREE(tail);
+		}
 	}
 }
 
+void csr1212_release_keyval(struct csr1212_keyval *kv)
+{
+	if (kv->refcnt > 1)
+		kv->refcnt--;
+	else
+		csr1212_destroy_keyval(kv);
+}
 
 void csr1212_destroy_csr(struct csr1212_csr *csr)
 {
@@ -763,49 +568,51 @@ void csr1212_destroy_csr(struct csr1212_
 }
 
 
-
 /* CSR Image Creation */
 
 static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
 {
 	struct csr1212_csr_rom_cache *cache;
-	u_int64_t csr_addr;
+	u64 csr_addr;
 
-	if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
-	    !csr->ops->release_addr || csr->max_rom < 1)
-		return CSR1212_EINVAL;
+	BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
+	       !csr->ops->release_addr || csr->max_rom < 1);
 
 	/* ROM size must be a multiple of csr->max_rom */
 	romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
 
-	csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
-	if (csr_addr == CSR1212_INVALID_ADDR_SPACE) {
-		return CSR1212_ENOMEM;
-	}
+	csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
+						 csr->private);
+	if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
+		return -ENOMEM;
+
 	if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
 		/* Invalid address returned from allocate_addr_range(). */
 		csr->ops->release_addr(csr_addr, csr->private);
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 	}
 
-	cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
+	cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
+					 romsize);
 	if (!cache) {
 		csr->ops->release_addr(csr_addr, csr->private);
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 	}
 
-	cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
+	cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
+					    CSR1212_KV_ID_EXTENDED_ROM);
 	if (!cache->ext_rom) {
 		csr->ops->release_addr(csr_addr, csr->private);
 		CSR1212_FREE(cache);
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 	}
 
-	if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) {
+	if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
+	    CSR1212_SUCCESS) {
 		csr1212_release_keyval(cache->ext_rom);
 		csr->ops->release_addr(csr_addr, csr->private);
 		CSR1212_FREE(cache);
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 	}
 	cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
 	cache->ext_rom->value.leaf.len = -1;
@@ -818,8 +625,8 @@ static int csr1212_append_new_cache(stru
 	return CSR1212_SUCCESS;
 }
 
-static inline void csr1212_remove_cache(struct csr1212_csr *csr,
-					struct csr1212_csr_rom_cache *cache)
+static void csr1212_remove_cache(struct csr1212_csr *csr,
+				 struct csr1212_csr_rom_cache *cache)
 {
 	if (csr->cache_head == cache)
 		csr->cache_head = cache->next;
@@ -832,7 +639,8 @@ static inline void csr1212_remove_cache(
 		cache->next->prev = cache->prev;
 
 	if (cache->ext_rom) {
-		csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
+		csr1212_detach_keyval_from_directory(csr->root_kv,
+						     cache->ext_rom);
 		csr1212_release_keyval(cache->ext_rom);
 	}
 
@@ -852,28 +660,29 @@ static int csr1212_generate_layout_subdi
 	     dentry = dentry->next) {
 		for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
 			/* Special Case: Extended Key Specifier_ID */
-			if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-				if (last_extkey_spec == NULL) {
+			if (dkv->key.id ==
+			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+				if (last_extkey_spec == NULL)
 					last_extkey_spec = dkv;
-				} else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
+				else if (dkv->value.immediate !=
+					 last_extkey_spec->value.immediate)
 					last_extkey_spec = dkv;
-				} else {
+				else
 					continue;
-				}
 			/* Special Case: Extended Key */
 			} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-				if (last_extkey == NULL) {
+				if (last_extkey == NULL)
 					last_extkey = dkv;
-				} else if (dkv->value.immediate != last_extkey->value.immediate) {
+				else if (dkv->value.immediate !=
+					 last_extkey->value.immediate)
 					last_extkey = dkv;
-				} else {
+				else
 					continue;
-				}
 			}
 
 			num_entries += 1;
 
-			switch(dkv->key.type) {
+			switch (dkv->key.type) {
 			default:
 			case CSR1212_KV_TYPE_IMMEDIATE:
 			case CSR1212_KV_TYPE_CSR_OFFSET:
@@ -891,8 +700,9 @@ static int csr1212_generate_layout_subdi
 				/* Special case: Extended ROM leafs */
 				if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
 					dkv->value.leaf.len = -1;
-					/* Don't add Extended ROM leafs in the layout list,
-					 * they are handled differently. */
+					/* Don't add Extended ROM leafs in the
+					 * layout list, they are handled
+					 * differently. */
 					break;
 				}
 
@@ -908,20 +718,21 @@ static int csr1212_generate_layout_subdi
 	return num_entries;
 }
 
-size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
+static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
 {
 	struct csr1212_keyval *ltail = kv;
 	size_t agg_size = 0;
 
-	while(kv) {
-		switch(kv->key.type) {
+	while (kv) {
+		switch (kv->key.type) {
 		case CSR1212_KV_TYPE_LEAF:
 			/* Add 1 quadlet for crc/len field */
 			agg_size += kv->value.leaf.len + 1;
 			break;
 
 		case CSR1212_KV_TYPE_DIRECTORY:
-			kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
+			kv->value.directory.len =
+				csr1212_generate_layout_subdir(kv, &ltail);
 			/* Add 1 quadlet for crc/len field */
 			agg_size += kv->value.directory.len + 1;
 			break;
@@ -931,9 +742,9 @@ size_t csr1212_generate_layout_order(str
 	return quads_to_bytes(agg_size);
 }
 
-struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
-						  struct csr1212_keyval *start_kv,
-						  int start_pos)
+static struct csr1212_keyval *
+csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
+			   struct csr1212_keyval *start_kv, int start_pos)
 {
 	struct csr1212_keyval *kv = start_kv;
 	struct csr1212_keyval *okv = start_kv;
@@ -942,13 +753,12 @@ struct csr1212_keyval *csr1212_generate_
 
 	cache->layout_head = kv;
 
-	while(kv && pos < cache->size) {
+	while (kv && pos < cache->size) {
 		/* Special case: Extended ROM leafs */
-		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
+		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
 			kv->offset = cache->offset + pos;
-		}
 
-		switch(kv->key.type) {
+		switch (kv->key.type) {
 		case CSR1212_KV_TYPE_LEAF:
 			kv_len = kv->value.leaf.len;
 			break;
@@ -959,6 +769,7 @@ struct csr1212_keyval *csr1212_generate_
 
 		default:
 			/* Should never get here */
+			WARN_ON(1);
 			break;
 		}
 
@@ -972,46 +783,55 @@ struct csr1212_keyval *csr1212_generate_
 	}
 
 	cache->layout_tail = okv;
-	cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
+	cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
 
 	return kv;
 }
 
-static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir,
-					 u_int32_t *data_buffer)
+#define CSR1212_KV_KEY_SHIFT		24
+#define CSR1212_KV_KEY_TYPE_SHIFT	6
+#define CSR1212_KV_KEY_ID_MASK		0x3f
+#define CSR1212_KV_KEY_TYPE_MASK	0x3	/* after shift */
+
+static void
+csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
 {
 	struct csr1212_dentry *dentry;
 	struct csr1212_keyval *last_extkey_spec = NULL;
 	struct csr1212_keyval *last_extkey = NULL;
 	int index = 0;
 
-	for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
+	for (dentry = dir->value.directory.dentries_head;
+	     dentry;
+	     dentry = dentry->next) {
 		struct csr1212_keyval *a;
 
 		for (a = dentry->kv; a; a = a->associate) {
-			u_int32_t value = 0;
+			u32 value = 0;
 
 			/* Special Case: Extended Key Specifier_ID */
-			if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-				if (last_extkey_spec == NULL) {
+			if (a->key.id ==
+			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+				if (last_extkey_spec == NULL)
 					last_extkey_spec = a;
-				} else if (a->value.immediate != last_extkey_spec->value.immediate) {
+				else if (a->value.immediate !=
+					 last_extkey_spec->value.immediate)
 					last_extkey_spec = a;
-				} else {
+				else
 					continue;
-				}
+
 			/* Special Case: Extended Key */
 			} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-				if (last_extkey == NULL) {
+				if (last_extkey == NULL)
 					last_extkey = a;
-				} else if (a->value.immediate != last_extkey->value.immediate) {
+				else if (a->value.immediate !=
+					 last_extkey->value.immediate)
 					last_extkey = a;
-				} else {
+				else
 					continue;
-				}
 			}
 
-			switch(a->key.type) {
+			switch (a->key.type) {
 			case CSR1212_KV_TYPE_IMMEDIATE:
 				value = a->value.immediate;
 				break;
@@ -1030,32 +850,46 @@ static void csr1212_generate_tree_subdir
 				break;
 			default:
 				/* Should never get here */
-				break; /* GDB breakpoint */
+				WARN_ON(1);
+				break;
 			}
 
-			value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
+			value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
+				 CSR1212_KV_KEY_SHIFT;
 			value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
-				(CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
-			data_buffer[index] = CSR1212_CPU_TO_BE32(value);
+				 (CSR1212_KV_KEY_SHIFT +
+				  CSR1212_KV_KEY_TYPE_SHIFT);
+			data_buffer[index] = cpu_to_be32(value);
 			index++;
 		}
 	}
 }
 
-void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
+struct csr1212_keyval_img {
+	u16 length;
+	u16 crc;
+
+	/* Must be last */
+	u32 data[0];	/* older gcc can't handle [] which is standard */
+};
+
+static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
 {
 	struct csr1212_keyval *kv, *nkv;
 	struct csr1212_keyval_img *kvi;
 
-	for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
-		kvi = (struct csr1212_keyval_img *)
-			(cache->data + bytes_to_quads(kv->offset - cache->offset));
-		switch(kv->key.type) {
+	for (kv = cache->layout_head;
+	     kv != cache->layout_tail->next;
+	     kv = nkv) {
+		kvi = (struct csr1212_keyval_img *)(cache->data +
+				bytes_to_quads(kv->offset - cache->offset));
+		switch (kv->key.type) {
 		default:
 		case CSR1212_KV_TYPE_IMMEDIATE:
 		case CSR1212_KV_TYPE_CSR_OFFSET:
 			/* Should never get here */
-			break; /* GDB breakpoint */
+			WARN_ON(1);
+			break;
 
 		case CSR1212_KV_TYPE_LEAF:
 			/* Don't copy over Extended ROM areas, they are
@@ -1064,15 +898,16 @@ void csr1212_fill_cache(struct csr1212_c
 				memcpy(kvi->data, kv->value.leaf.data,
 				       quads_to_bytes(kv->value.leaf.len));
 
-			kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len);
+			kvi->length = cpu_to_be16(kv->value.leaf.len);
 			kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
 			break;
 
 		case CSR1212_KV_TYPE_DIRECTORY:
 			csr1212_generate_tree_subdir(kv, kvi->data);
 
-			kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len);
-			kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
+			kvi->length = cpu_to_be16(kv->value.directory.len);
+			kvi->crc = csr1212_crc16(kvi->data,
+						 kv->value.directory.len);
 			break;
 		}
 
@@ -1086,6 +921,10 @@ void csr1212_fill_cache(struct csr1212_c
 	}
 }
 
+/* This size is arbitrarily chosen.
+ * The struct overhead is subtracted for more economic allocations. */
+#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
+
 int csr1212_generate_csr_image(struct csr1212_csr *csr)
 {
 	struct csr1212_bus_info_block_img *bi;
@@ -1095,8 +934,7 @@ int csr1212_generate_csr_image(struct cs
 	int ret;
 	int init_offset;
 
-	if (!csr)
-		return CSR1212_EINVAL;
+	BUG_ON(!csr);
 
 	cache = csr->cache_head;
 
@@ -1113,18 +951,21 @@ int csr1212_generate_csr_image(struct cs
 
 	init_offset = csr->bus_info_len;
 
-	for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
+	for (kv = csr->root_kv, cache = csr->cache_head;
+	     kv;
+	     cache = cache->next) {
 		if (!cache) {
 			/* Estimate approximate number of additional cache
 			 * regions needed (it assumes that the cache holding
 			 * the first 1K Config ROM space always exists). */
 			int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
-						(2 * sizeof(u_int32_t))) + 1;
+						(2 * sizeof(u32))) + 1;
 
 			/* Add additional cache regions, extras will be
 			 * removed later */
 			for (; est_c; est_c--) {
-				ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
+				ret = csr1212_append_new_cache(csr,
+						CSR1212_EXTENDED_ROM_SIZE);
 				if (ret != CSR1212_SUCCESS)
 					return ret;
 			}
@@ -1136,7 +977,7 @@ int csr1212_generate_csr_image(struct cs
 		}
 		kv = csr1212_generate_positions(cache, kv, init_offset);
 		agg_size -= cache->len;
-		init_offset = sizeof(u_int32_t);
+		init_offset = sizeof(u32);
 	}
 
 	/* Remove unused, excess cache regions */
@@ -1149,15 +990,14 @@ int csr1212_generate_csr_image(struct cs
 
 	/* Go through the list backward so that when done, the correct CRC
 	 * will be calculated for the Extended ROM areas. */
-	for(cache = csr->cache_tail; cache; cache = cache->prev) {
+	for (cache = csr->cache_tail; cache; cache = cache->prev) {
 		/* Only Extended ROM caches should have this set. */
 		if (cache->ext_rom) {
 			int leaf_size;
 
 			/* Make sure the Extended ROM leaf is a multiple of
 			 * max_rom in size. */
-			if (csr->max_rom < 1)
-				return CSR1212_EINVAL;
+			BUG_ON(csr->max_rom < 1);
 			leaf_size = (cache->len + (csr->max_rom - 1)) &
 				~(csr->max_rom - 1);
 
@@ -1166,7 +1006,7 @@ int csr1212_generate_csr_image(struct cs
 			       leaf_size - cache->len);
 
 			/* Subtract leaf header */
-			leaf_size -= sizeof(u_int32_t);
+			leaf_size -= sizeof(u32);
 
 			/* Update the Extended ROM leaf length */
 			cache->ext_rom->value.leaf.len =
@@ -1184,33 +1024,31 @@ int csr1212_generate_csr_image(struct cs
 			/* Set the length and CRC of the extended ROM. */
 			struct csr1212_keyval_img *kvi =
 				(struct csr1212_keyval_img*)cache->data;
+			u16 len = bytes_to_quads(cache->len) - 1;
 
-			kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1);
-			kvi->crc = csr1212_crc16(kvi->data,
-						 bytes_to_quads(cache->len) - 1);
-
+			kvi->length = cpu_to_be16(len);
+			kvi->crc = csr1212_crc16(kvi->data, len);
 		}
 	}
 
 	return CSR1212_SUCCESS;
 }
 
-int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len)
+int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
 {
 	struct csr1212_csr_rom_cache *cache;
 
-	for (cache = csr->cache_head; cache; cache = cache->next) {
+	for (cache = csr->cache_head; cache; cache = cache->next)
 		if (offset >= cache->offset &&
 		    (offset + len) <= (cache->offset + cache->size)) {
-			memcpy(buffer,
-			       &cache->data[bytes_to_quads(offset - cache->offset)],
+			memcpy(buffer, &cache->data[
+					bytes_to_quads(offset - cache->offset)],
 			       len);
 			return CSR1212_SUCCESS;
 		}
-	}
-	return CSR1212_ENOENT;
-}
 
+	return -ENOENT;
+}
 
 
 /* Parse a chunk of data as a Config ROM */
@@ -1227,46 +1065,43 @@ static int csr1212_parse_bus_info_block(
 	 * Unfortunately, many IEEE 1394 devices do not abide by that, so the
 	 * bus info block will be read 1 quadlet at a time.  The rest of the
 	 * ConfigROM will be read according to the max_rom field. */
-	for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) {
+	for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
 		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-					 sizeof(csr1212_quad_t),
-					 &csr->cache_head->data[bytes_to_quads(i)],
-					 csr->private);
+			sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
+			csr->private);
 		if (ret != CSR1212_SUCCESS)
 			return ret;
 
 		/* check ROM header's info_length */
 		if (i == 0 &&
-		    CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+		    be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
 		    bytes_to_quads(csr->bus_info_len) - 1)
-			return CSR1212_EINVAL;
+			return -EINVAL;
 	}
 
 	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
 	csr->crc_len = quads_to_bytes(bi->crc_length);
 
-	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
-	 * always the case, so read the rest of the crc area 1 quadlet at a time. */
-	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) {
+	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
+	 * is not always the case, so read the rest of the crc area 1 quadlet at
+	 * a time. */
+	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
 		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-					 sizeof(csr1212_quad_t),
-					 &csr->cache_head->data[bytes_to_quads(i)],
-					 csr->private);
+			sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
+			csr->private);
 		if (ret != CSR1212_SUCCESS)
 			return ret;
 	}
 
-#if 0
-	/* Apparently there are too many differnt wrong implementations of the
-	 * CRC algorithm that verifying them is moot. */
+	/* Apparently there are many different wrong implementations of the CRC
+	 * algorithm.  We don't fail, we just warn. */
 	if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
 	    (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
-		return CSR1212_EINVAL;
-#endif
+		printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
 
 	cr = CSR1212_MALLOC(sizeof(*cr));
 	if (!cr)
-		return CSR1212_ENOMEM;
+		return -ENOMEM;
 
 	cr->next = NULL;
 	cr->prev = NULL;
@@ -1279,21 +1114,26 @@ #endif
 	return CSR1212_SUCCESS;
 }
 
-static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
-				   csr1212_quad_t ki,
-				   u_int32_t kv_pos)
+#define CSR1212_KV_KEY(q)	(be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
+#define CSR1212_KV_KEY_TYPE(q)	(CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
+#define CSR1212_KV_KEY_ID(q)	(CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
+#define CSR1212_KV_VAL_MASK	0xffffff
+#define CSR1212_KV_VAL(q)	(be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
+
+static int
+csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
 {
 	int ret = CSR1212_SUCCESS;
 	struct csr1212_keyval *k = NULL;
-	u_int32_t offset;
+	u32 offset;
 
-	switch(CSR1212_KV_KEY_TYPE(ki)) {
+	switch (CSR1212_KV_KEY_TYPE(ki)) {
 	case CSR1212_KV_TYPE_IMMEDIATE:
 		k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
 					  CSR1212_KV_VAL(ki));
 		if (!k) {
-			ret = CSR1212_ENOMEM;
-			goto fail;
+			ret = -ENOMEM;
+			goto out;
 		}
 
 		k->refcnt = 0;	/* Don't keep local reference when parsing. */
@@ -1303,8 +1143,8 @@ static int csr1212_parse_dir_entry(struc
 		k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
 					   CSR1212_KV_VAL(ki));
 		if (!k) {
-			ret = CSR1212_ENOMEM;
-			goto fail;
+			ret = -ENOMEM;
+			goto out;
 		}
 		k->refcnt = 0;	/* Don't keep local reference when parsing. */
 		break;
@@ -1316,8 +1156,8 @@ static int csr1212_parse_dir_entry(struc
 			/* Uh-oh.  Can't have a relative offset of 0 for Leaves
 			 * or Directories.  The Config ROM image is most likely
 			 * messed up, so we'll just abort here. */
-			ret = CSR1212_EIO;
-			goto fail;
+			ret = -EIO;
+			goto out;
 		}
 
 		k = csr1212_find_keyval_offset(dir, offset);
@@ -1325,14 +1165,14 @@ static int csr1212_parse_dir_entry(struc
 		if (k)
 			break;		/* Found it. */
 
-		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
+		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
 			k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
-		} else {
+		else
 			k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
-		}
+
 		if (!k) {
-			ret = CSR1212_ENOMEM;
-			goto fail;
+			ret = -ENOMEM;
+			goto out;
 		}
 		k->refcnt = 0;	/* Don't keep local reference when parsing. */
 		k->valid = 0;	/* Contents not read yet so it's not valid. */
@@ -1344,16 +1184,12 @@ static int csr1212_parse_dir_entry(struc
 		dir->next = k;
 	}
 	ret = csr1212_attach_keyval_to_directory(dir, k);
-
-fail:
-	if (ret != CSR1212_SUCCESS) {
-		if (k)
-			free_keyval(k);
-	}
+out:
+	if (ret != CSR1212_SUCCESS && k != NULL)
+		free_keyval(k);
 	return ret;
 }
 
-
 int csr1212_parse_keyval(struct csr1212_keyval *kv,
 			 struct csr1212_csr_rom_cache *cache)
 {
@@ -1362,24 +1198,20 @@ int csr1212_parse_keyval(struct csr1212_
 	int ret = CSR1212_SUCCESS;
 	int kvi_len;
 
-	kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
-								      cache->offset)];
-	kvi_len = CSR1212_BE16_TO_CPU(kvi->length);
+	kvi = (struct csr1212_keyval_img*)
+		&cache->data[bytes_to_quads(kv->offset - cache->offset)];
+	kvi_len = be16_to_cpu(kvi->length);
 
-#if 0
-	/* Apparently there are too many differnt wrong implementations of the
-	 * CRC algorithm that verifying them is moot. */
+	/* Apparently there are many different wrong implementations of the CRC
+	 * algorithm.  We don't fail, we just warn. */
 	if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
-	    (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
-		ret = CSR1212_EINVAL;
-		goto fail;
-	}
-#endif
+	    (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc))
+		printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
 
-	switch(kv->key.type) {
+	switch (kv->key.type) {
 	case CSR1212_KV_TYPE_DIRECTORY:
 		for (i = 0; i < kvi_len; i++) {
-			csr1212_quad_t ki = kvi->data[i];
+			u32 ki = kvi->data[i];
 
 			/* Some devices put null entries in their unit
 			 * directories.  If we come across such an entry,
@@ -1387,76 +1219,72 @@ #endif
 			if (ki == 0x0)
 				continue;
 			ret = csr1212_parse_dir_entry(kv, ki,
-						      (kv->offset +
-						       quads_to_bytes(i + 1)));
+					kv->offset + quads_to_bytes(i + 1));
 		}
 		kv->value.directory.len = kvi_len;
 		break;
 
 	case CSR1212_KV_TYPE_LEAF:
 		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
-			kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
+			size_t size = quads_to_bytes(kvi_len);
+
+			kv->value.leaf.data = CSR1212_MALLOC(size);
 			if (!kv->value.leaf.data) {
-				ret = CSR1212_ENOMEM;
-				goto fail;
+				ret = -ENOMEM;
+				goto out;
 			}
 
 			kv->value.leaf.len = kvi_len;
-			memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
+			memcpy(kv->value.leaf.data, kvi->data, size);
 		}
 		break;
 	}
 
 	kv->valid = 1;
-
-fail:
+out:
 	return ret;
 }
 
-
-int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
+static int
+csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
 {
 	struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
 	struct csr1212_keyval_img *kvi = NULL;
 	struct csr1212_csr_rom_cache *cache;
 	int cache_index;
-	u_int64_t addr;
-	u_int32_t *cache_ptr;
-	u_int16_t kv_len = 0;
+	u64 addr;
+	u32 *cache_ptr;
+	u16 kv_len = 0;
 
-	if (!csr || !kv || csr->max_rom < 1)
-		return CSR1212_EINVAL;
+	BUG_ON(!csr || !kv || csr->max_rom < 1);
 
 	/* First find which cache the data should be in (or go in if not read
 	 * yet). */
-	for (cache = csr->cache_head; cache; cache = cache->next) {
+	for (cache = csr->cache_head; cache; cache = cache->next)
 		if (kv->offset >= cache->offset &&
 		    kv->offset < (cache->offset + cache->size))
 			break;
-	}
 
 	if (!cache) {
-		csr1212_quad_t q;
-		u_int32_t cache_size;
+		u32 q, cache_size;
 
 		/* Only create a new cache for Extended ROM leaves. */
 		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-			return CSR1212_EINVAL;
+			return -EINVAL;
 
 		if (csr->ops->bus_read(csr,
 				       CSR1212_REGISTER_SPACE_BASE + kv->offset,
-				       sizeof(csr1212_quad_t), &q, csr->private)) {
-			return CSR1212_EIO;
-		}
+				       sizeof(u32), &q, csr->private))
+			return -EIO;
 
-		kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16;
+		kv->value.leaf.len = be32_to_cpu(q) >> 16;
 
 		cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
 			      (csr->max_rom - 1)) & ~(csr->max_rom - 1);
 
 		cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
 		if (!cache)
-			return CSR1212_ENOMEM;
+			return -ENOMEM;
 
 		kv->value.leaf.data = &cache->data[1];
 		csr->cache_tail->next = cache;
@@ -1465,12 +1293,11 @@ int _csr1212_read_keyval(struct csr1212_
 		csr->cache_tail = cache;
 		cache->filled_head =
 			CSR1212_MALLOC(sizeof(*cache->filled_head));
-		if (!cache->filled_head) {
-			return CSR1212_ENOMEM;
-		}
+		if (!cache->filled_head)
+			return -ENOMEM;
 
 		cache->filled_head->offset_start = 0;
-		cache->filled_head->offset_end = sizeof(csr1212_quad_t);
+		cache->filled_head->offset_end = sizeof(u32);
 		cache->filled_tail = cache->filled_head;
 		cache->filled_head->next = NULL;
 		cache->filled_head->prev = NULL;
@@ -1488,7 +1315,7 @@ int _csr1212_read_keyval(struct csr1212_
 		if (cache_index < cr->offset_start) {
 			newcr = CSR1212_MALLOC(sizeof(*newcr));
 			if (!newcr)
-				return CSR1212_ENOMEM;
+				return -ENOMEM;
 
 			newcr->offset_start = cache_index & ~(csr->max_rom - 1);
 			newcr->offset_end = newcr->offset_start;
@@ -1501,18 +1328,18 @@ int _csr1212_read_keyval(struct csr1212_
 			   (cache_index < cr->offset_end)) {
 			kvi = (struct csr1212_keyval_img*)
 				(&cache->data[bytes_to_quads(cache_index)]);
-			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
-						1);
+			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
 			break;
-		} else if (cache_index == cr->offset_end)
+		} else if (cache_index == cr->offset_end) {
 			break;
+		}
 	}
 
 	if (!cr) {
 		cr = cache->filled_tail;
 		newcr = CSR1212_MALLOC(sizeof(*newcr));
 		if (!newcr)
-			return CSR1212_ENOMEM;
+			return -ENOMEM;
 
 		newcr->offset_start = cache_index & ~(csr->max_rom - 1);
 		newcr->offset_end = newcr->offset_start;
@@ -1534,7 +1361,7 @@ int _csr1212_read_keyval(struct csr1212_
 				       csr->private)) {
 			if (csr->max_rom == 4)
 				/* We've got problems! */
-				return CSR1212_EIO;
+				return -EIO;
 
 			/* Apperently the max_rom value was a lie, set it to
 			 * do quadlet reads and try again. */
@@ -1548,8 +1375,7 @@ int _csr1212_read_keyval(struct csr1212_
 		if (!kvi && (cr->offset_end > cache_index)) {
 			kvi = (struct csr1212_keyval_img*)
 				(&cache->data[bytes_to_quads(cache_index)]);
-			kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
-						1);
+			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
 		}
 
 		if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
@@ -1557,7 +1383,7 @@ int _csr1212_read_keyval(struct csr1212_
 			 * beyond the ConfigROM image region and thus beyond the
 			 * end of our cache region.  Therefore, we abort now
 			 * rather than seg faulting later. */
-			return CSR1212_EIO;
+			return -EIO;
 		}
 
 		ncr = cr->next;
@@ -1579,7 +1405,16 @@ int _csr1212_read_keyval(struct csr1212_
 	return csr1212_parse_keyval(kv, cache);
 }
 
-
+struct csr1212_keyval *
+csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
+{
+	if (!kv)
+		return NULL;
+	if (!kv->valid)
+		if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
+			return NULL;
+	return kv;
+}
 
 int csr1212_parse_csr(struct csr1212_csr *csr)
 {
@@ -1587,20 +1422,19 @@ int csr1212_parse_csr(struct csr1212_csr
 	struct csr1212_dentry *dentry;
 	int ret;
 
-	if (!csr || !csr->ops || !csr->ops->bus_read)
-		return CSR1212_EINVAL;
+	BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
 
 	ret = csr1212_parse_bus_info_block(csr);
 	if (ret != CSR1212_SUCCESS)
 		return ret;
 
-	if (!csr->ops->get_max_rom)
+	if (!csr->ops->get_max_rom) {
 		csr->max_rom = mr_map[0];	/* default value */
-	else {
+	} else {
 		int i = csr->ops->get_max_rom(csr->bus_info_data,
 					      csr->private);
 		if (i & ~0x3)
-			return CSR1212_EINVAL;
+			return -EINVAL;
 		csr->max_rom = mr_map[i];
 	}
 
@@ -1613,7 +1447,7 @@ int csr1212_parse_csr(struct csr1212_csr
 	csr->root_kv->valid = 0;
 	csr->root_kv->next = csr->root_kv;
 	csr->root_kv->prev = csr->root_kv;
-	ret = _csr1212_read_keyval(csr, csr->root_kv);
+	ret = csr1212_read_keyval(csr, csr->root_kv);
 	if (ret != CSR1212_SUCCESS)
 		return ret;
 
@@ -1623,7 +1457,7 @@ int csr1212_parse_csr(struct csr1212_csr
 	     dentry; dentry = dentry->next) {
 		if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
 			!dentry->kv->valid) {
-			ret = _csr1212_read_keyval(csr, dentry->kv);
+			ret = csr1212_read_keyval(csr, dentry->kv);
 			if (ret != CSR1212_SUCCESS)
 				return ret;
 		}
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
index 17ddd72..df909ce 100644
--- a/drivers/ieee1394/csr1212.h
+++ b/drivers/ieee1394/csr1212.h
@@ -30,94 +30,13 @@
 #ifndef __CSR1212_H__
 #define __CSR1212_H__
 
-
-/* Compatibility layer */
-#ifdef __KERNEL__
-
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-
-#define CSR1212_MALLOC(size)		vmalloc((size))
-#define CSR1212_FREE(ptr)		vfree(ptr)
-#define CSR1212_BE16_TO_CPU(quad)	be16_to_cpu(quad)
-#define CSR1212_CPU_TO_BE16(quad)	cpu_to_be16(quad)
-#define CSR1212_BE32_TO_CPU(quad)	be32_to_cpu(quad)
-#define CSR1212_CPU_TO_BE32(quad)	cpu_to_be32(quad)
-#define CSR1212_BE64_TO_CPU(quad)	be64_to_cpu(quad)
-#define CSR1212_CPU_TO_BE64(quad)	cpu_to_be64(quad)
-
-#define CSR1212_LE16_TO_CPU(quad)	le16_to_cpu(quad)
-#define CSR1212_CPU_TO_LE16(quad)	cpu_to_le16(quad)
-#define CSR1212_LE32_TO_CPU(quad)	le32_to_cpu(quad)
-#define CSR1212_CPU_TO_LE32(quad)	cpu_to_le32(quad)
-#define CSR1212_LE64_TO_CPU(quad)	le64_to_cpu(quad)
-#define CSR1212_CPU_TO_LE64(quad)	cpu_to_le64(quad)
-
-#include <linux/errno.h>
-#define CSR1212_SUCCESS (0)
-#define CSR1212_EINVAL	(-EINVAL)
-#define CSR1212_ENOMEM	(-ENOMEM)
-#define CSR1212_ENOENT	(-ENOENT)
-#define CSR1212_EIO	(-EIO)
-#define CSR1212_EBUSY	(-EBUSY)
-
-#else	/* Userspace */
-
-#include <sys/types.h>
-#include <malloc.h>
-#define CSR1212_MALLOC(size)		malloc(size)
-#define CSR1212_FREE(ptr)		free(ptr)
-#include <endian.h>
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#include <byteswap.h>
-#define CSR1212_BE16_TO_CPU(quad)	bswap_16(quad)
-#define CSR1212_CPU_TO_BE16(quad)	bswap_16(quad)
-#define CSR1212_BE32_TO_CPU(quad)	bswap_32(quad)
-#define CSR1212_CPU_TO_BE32(quad)	bswap_32(quad)
-#define CSR1212_BE64_TO_CPU(quad)	bswap_64(quad)
-#define CSR1212_CPU_TO_BE64(quad)	bswap_64(quad)
-
-#define CSR1212_LE16_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_LE16(quad)	(quad)
-#define CSR1212_LE32_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_LE32(quad)	(quad)
-#define CSR1212_LE64_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_LE64(quad)	(quad)
-#else
-#define CSR1212_BE16_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_BE16(quad)	(quad)
-#define CSR1212_BE32_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_BE32(quad)	(quad)
-#define CSR1212_BE64_TO_CPU(quad)	(quad)
-#define CSR1212_CPU_TO_BE64(quad)	(quad)
-
-#define CSR1212_LE16_TO_CPU(quad)	bswap_16(quad)
-#define CSR1212_CPU_TO_LE16(quad)	bswap_16(quad)
-#define CSR1212_LE32_TO_CPU(quad)	bswap_32(quad)
-#define CSR1212_CPU_TO_LE32(quad)	bswap_32(quad)
-#define CSR1212_LE64_TO_CPU(quad)	bswap_64(quad)
-#define CSR1212_CPU_TO_LE64(quad)	bswap_64(quad)
-#endif
-
-#include <errno.h>
-#define CSR1212_SUCCESS (0)
-#define CSR1212_EINVAL	(EINVAL)
-#define CSR1212_ENOMEM	(ENOMEM)
-#define CSR1212_ENOENT	(ENOENT)
-#define CSR1212_EIO	(EIO)
-#define CSR1212_EBUSY	(EBUSY)
-
-#endif
 
+#define CSR1212_MALLOC(size)	kmalloc((size), GFP_KERNEL)
+#define CSR1212_FREE(ptr)	kfree(ptr)
 
-#define CSR1212_KV_VAL_MASK			0xffffff
-#define CSR1212_KV_KEY_SHIFT			24
-#define CSR1212_KV_KEY_TYPE_SHIFT		6
-#define CSR1212_KV_KEY_ID_MASK			0x3f
-#define CSR1212_KV_KEY_TYPE_MASK		0x3		/* After shift */
+#define CSR1212_SUCCESS (0)
 
 
 /* CSR 1212 key types */
@@ -190,48 +109,22 @@ #define  CSR1212_UNITS_SPACE_SIZE		((256
 #define  CSR1212_UNITS_SPACE_END		(CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
 #define  CSR1212_UNITS_SPACE_OFFSET		(CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
 
-#define  CSR1212_EXTENDED_ROM_SIZE		(0x10000 * sizeof(u_int32_t))
-
 #define  CSR1212_INVALID_ADDR_SPACE		-1
 
+
 /* Config ROM image structures */
 struct csr1212_bus_info_block_img {
-	u_int8_t length;
-	u_int8_t crc_length;
-	u_int16_t crc;
+	u8 length;
+	u8 crc_length;
+	u16 crc;
 
 	/* Must be last */
-	u_int32_t data[0];	/* older gcc can't handle [] which is standard */
-};
-
-#define CSR1212_KV_KEY(quad)		(CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(quad)	(CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(quad)		(CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL(quad)		(CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK)
-
-#define CSR1212_SET_KV_KEY(quad, key)	((quad) = \
-	CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT)))
-#define CSR1212_SET_KV_VAL(quad, val)	((quad) = \
-	CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val)))
-#define CSR1212_SET_KV_TYPEID(quad, type, id)	((quad) = \
-	CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \
-	(((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \
-	  ((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT)))
-
-typedef u_int32_t csr1212_quad_t;
-
-
-struct csr1212_keyval_img {
-	u_int16_t length;
-	u_int16_t crc;
-
-	/* Must be last */
-	csr1212_quad_t data[0];	/* older gcc can't handle [] which is standard */
+	u32 data[0];	/* older gcc can't handle [] which is standard */
 };
 
 struct csr1212_leaf {
 	int len;
-	u_int32_t *data;
+	u32 *data;
 };
 
 struct csr1212_dentry {
@@ -246,12 +139,12 @@ struct csr1212_directory {
 
 struct csr1212_keyval {
 	struct {
-		u_int8_t type;
-		u_int8_t id;
+		u8 type;
+		u8 id;
 	} key;
 	union {
-		u_int32_t immediate;
-		u_int32_t csr_offset;
+		u32 immediate;
+		u32 csr_offset;
 		struct csr1212_leaf leaf;
 		struct csr1212_directory directory;
 	} value;
@@ -260,15 +153,15 @@ struct csr1212_keyval {
 
 	/* used in generating and/or parsing CSR image */
 	struct csr1212_keyval *next, *prev;	/* flat list of CSR elements */
-	u_int32_t offset;	/* position in CSR from 0xffff f000 0000 */
-	u_int8_t valid;		/* flag indicating keyval has valid data*/
+	u32 offset;	/* position in CSR from 0xffff f000 0000 */
+	u8 valid;	/* flag indicating keyval has valid data*/
 };
 
 
 struct csr1212_cache_region {
 	struct csr1212_cache_region *next, *prev;
-	u_int32_t offset_start;		/* inclusive */
-	u_int32_t offset_end;		/* exclusive */
+	u32 offset_start;	/* inclusive */
+	u32 offset_end;		/* exclusive */
 };
 
 struct csr1212_csr_rom_cache {
@@ -276,18 +169,18 @@ struct csr1212_csr_rom_cache {
 	struct csr1212_cache_region *filled_head, *filled_tail;
 	struct csr1212_keyval *layout_head, *layout_tail;
 	size_t size;
-	u_int32_t offset;
+	u32 offset;
 	struct csr1212_keyval *ext_rom;
 	size_t len;
 
 	/* Must be last */
-	u_int32_t data[0];	/* older gcc can't handle [] which is standard */
+	u32 data[0];	/* older gcc can't handle [] which is standard */
 };
 
 struct csr1212_csr {
 	size_t bus_info_len;	/* bus info block length in bytes */
 	size_t crc_len;		/* crc length in bytes */
-	u_int32_t *bus_info_data;	/* bus info data incl bus name and EUI */
+	u32 *bus_info_data;	/* bus info data incl bus name and EUI */
 
 	void *private;		/* private, bus specific data */
 	struct csr1212_bus_ops *ops;
@@ -305,52 +198,38 @@ struct csr1212_bus_ops {
 	 * from remote nodes when parsing a Config ROM (i.e., read Config ROM
 	 * entries located in the Units Space.  Must return 0 on success
 	 * anything else indicates an error. */
-	int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr,
-			 u_int16_t length, void *buffer, void *private);
+	int (*bus_read) (struct csr1212_csr *csr, u64 addr,
+			 u16 length, void *buffer, void *private);
 
 	/* This function is used by csr1212 to allocate a region in units space
 	 * in the event that Config ROM entries don't all fit in the predefined
 	 * 1K region.  The void *private parameter is private member of struct
 	 * csr1212_csr. */
-	u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment,
-					  void *private);
-
+	u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
 
 	/* This function is used by csr1212 to release a region in units space
 	 * that is no longer needed. */
-	void (*release_addr) (u_int64_t addr, void *private);
+	void (*release_addr) (u64 addr, void *private);
 
 	/* This function is used by csr1212 to determine the max read request
 	 * supported by a remote node when reading the ConfigROM space.  Must
 	 * return 0, 1, or 2 per IEEE 1212.  */
-	int (*get_max_rom) (u_int32_t *bus_info, void *private);
+	int (*get_max_rom) (u32 *bus_info, void *private);
 };
 
 
-
-
 /* Descriptor Leaf manipulation macros */
 #define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
 #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
 
 #define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
+	(be32_to_cpu((kv)->value.leaf.data[0]) >> \
+	 CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
 #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \
+	(be32_to_cpu((kv)->value.leaf.data[0]) & \
 	 CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
-	(&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
-	((kv)->value.leaf.data[0] = \
-	 CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
-			     ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
-	((kv)->value.leaf.data[0] = \
-	 CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
-			      CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
-			     ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
+
 
 /* Text Descriptor Leaf manipulation macros */
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
@@ -358,182 +237,21 @@ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff  /* after shift */
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
 
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
+	(be32_to_cpu((kv)->value.leaf.data[1]) >> \
 	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
-	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
-			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
-			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
+	((be32_to_cpu((kv)->value.leaf.data[1]) >> \
+	  CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
+	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \
+	(be32_to_cpu((kv)->value.leaf.data[1]) & \
 	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
 	(&((kv)->value.leaf.data[2]))
 
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
-	((kv)->value.leaf.data[1] = \
-	 ((kv)->value.leaf.data[1] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
-				CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((width) & \
-			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
-			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
-	((kv)->value.leaf.data[1] = \
-	 ((kv)->value.leaf.data[1] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
-				CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((char_set) & \
-			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
-			     CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
-	((kv)->value.leaf.data[1] = \
-	 ((kv)->value.leaf.data[1] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
-	 CSR1212_CPU_TO_BE32(((language) & \
-			      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
-
-
-/* Icon Descriptor Leaf manipulation macros */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3 /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \
-	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
-	  CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \
-	((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \
-	  CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \
-	(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \
-	 CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \
-	(&((kv)->value.leaf.data[5]))
-
-static inline u_int32_t *CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(struct csr1212_keyval *kv)
-{
-	static const int pd[4] = { 0, 4, 16, 256 };
-	static const int cs[16] = { 4, 2 };
-	int ps = pd[CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv)];
-
-	return &kv->value.leaf.data[5 +
-				    (ps * cs[CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv)]) /
-			   sizeof(u_int32_t)];
-}
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \
-	((kv)->value.leaf.data[2] = \
-	 ((kv)->value.leaf.data[2] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \
-	 CSR1212_CPU_TO_BE32(((version) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \
-	((kv)->value.leaf.data[3] = \
-	 ((kv)->value.leaf.data[3] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \
-				CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((palette_depth) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \
-			     CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \
-	((kv)->value.leaf.data[3] = \
-	 ((kv)->value.leaf.data[3] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \
-				CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((color_space) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \
-			     CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
-	((kv)->value.leaf.data[3] = \
-	 ((kv)->value.leaf.data[3] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
-	 CSR1212_CPU_TO_BE32(((language) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \
-	((kv)->value.leaf.data[4] = \
-	 ((kv)->value.leaf.data[4] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \
-				CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((hscan) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \
-			     CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \
-	((kv)->value.leaf.data[4] = \
-	 (((kv)->value.leaf.data[4] & \
-	  CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \
-	 CSR1212_CPU_TO_BE32(((vscan) & \
-			      CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)))
-
-
-/* Modifiable Descriptor Leaf manipulation macros */
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \
-	CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT)
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \
-	(CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \
-			     CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \
-	 CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \
-	((kv)->value.leaf.data[0] = \
-	 ((kv)->value.leaf.data[0] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \
-				CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \
-	 CSR1212_CPU_TO_BE32(((size) & \
-			      CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \
-			     CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \
-	((kv)->value.leaf.data[0] = \
-	 ((kv)->value.leaf.data[0] & \
-	  CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \
-	  CSR1212_CPU_TO_BE32(((addr) & \
-			       CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK)))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \
-	((kv)->value.leaf.data[1] = \
-	 CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK))
-
-
 
 /* The following 2 function are for creating new Configuration ROM trees.  The
  * first function is used for both creating local trees and parsing remote
@@ -543,11 +261,10 @@ extern struct csr1212_csr *csr1212_creat
 					      size_t bus_info_size,
 					      void *private);
 extern void csr1212_init_local_csr(struct csr1212_csr *csr,
-				   const u_int32_t *bus_info_data, int max_rom);
+				   const u32 *bus_info_data, int max_rom);
 
 
-/* The following function destroys a Configuration ROM tree and release all
- * memory taken by the tree. */
+/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
 extern void csr1212_destroy_csr(struct csr1212_csr *csr);
 
 
@@ -555,50 +272,20 @@ extern void csr1212_destroy_csr(struct c
  * a Configuration ROM tree.  Code that creates new keyvals with these functions
  * must release those keyvals with csr1212_release_keyval() when they are no
  * longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value);
-extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data,
-					       size_t data_len);
-extern struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key,
-						     u_int32_t csr_offset);
-extern struct csr1212_keyval *csr1212_new_directory(u_int8_t key);
-extern struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec,
-							     u_int32_t key,
-							     u_int32_t value);
-extern struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec,
-							u_int32_t key,
-							const void *data,
-							size_t data_len);
-extern struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype,
-							  u_int32_t specifier_id,
-							  const void *data,
-							  size_t data_len);
-extern struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
-								  u_int16_t cset,
-								  u_int16_t language,
-								  const void *data,
-								  size_t data_len);
+extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
+extern struct csr1212_keyval *csr1212_new_directory(u8 key);
 extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-extern struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
-							       u_int8_t palette_depth,
-							       u_int8_t color_space,
-							       u_int16_t language,
-							       u_int16_t hscan,
-							       u_int16_t vscan,
-							       u_int32_t *palette,
-							       u_int32_t *pixels);
-extern struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
-								     u_int64_t address);
-extern struct csr1212_keyval *csr1212_new_keyword_leaf(int strc,
-						       const char *strv[]);
-
-
-/* The following functions manage association between keyvals.  Typically,
+
+
+/* The following function manages association between keyvals.  Typically,
  * Descriptor Leaves and Directories will be associated with another keyval and
  * it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.*/
-extern int csr1212_associate_keyval(struct csr1212_keyval *kv,
-				    struct csr1212_keyval *associate);
-extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv);
+ * keyval that it is associated with.
+ * Take care with subsequent ROM modifications:  There is no function to remove
+ * previously specified associations.
+ */
+extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
+				     struct csr1212_keyval *associate);
 
 
 /* The following functions manage the association of a keyval and directories.
@@ -609,23 +296,15 @@ extern void csr1212_detach_keyval_from_d
 						 struct csr1212_keyval *kv);
 
 
-/* The following functions create a Configuration ROM image from the tree of
- * keyvals provided.  csr1212_generate_csr_image() creates a complete image in
- * the list of caches available via csr->cache_head.  The other functions are
- * provided should there be a need to create a flat image without restrictions
- * placed by IEEE 1212. */
-extern struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
-							 struct csr1212_keyval *start_kv,
-							 int start_pos);
-extern size_t csr1212_generate_layout_order(struct csr1212_keyval *kv);
-extern void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache);
+/* Creates a complete Configuration ROM image in the list of caches available
+ * via csr->cache_head. */
 extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
 
 
 /* This is a convience function for reading a block of data out of one of the
  * caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer,
-			u_int32_t len);
+extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
+			u32 len);
 
 
 /* The following functions are in place for parsing Configuration ROM images.
@@ -635,15 +314,11 @@ extern int csr1212_parse_keyval(struct c
 				struct csr1212_csr_rom_cache *cache);
 extern int csr1212_parse_csr(struct csr1212_csr *csr);
 
-/* These are internal functions referenced by inline functions below. */
-extern int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-extern void _csr1212_destroy_keyval(struct csr1212_keyval *kv);
-
 
 /* This function allocates a new cache which may be used for either parsing or
  * generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset,
-								     size_t size)
+static inline struct csr1212_csr_rom_cache *
+csr1212_rom_cache_malloc(u32 offset, size_t size)
 {
 	struct csr1212_csr_rom_cache *cache;
 
@@ -667,16 +342,8 @@ static inline struct csr1212_csr_rom_cac
 
 /* This function ensures that a keyval contains data when referencing a keyval
  * created by parsing a Configuration ROM. */
-static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr,
-							struct csr1212_keyval *kv)
-{
-	if (!kv)
-		return NULL;
-	if (!kv->valid)
-		if (_csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
-			return NULL;
-	return kv;
-}
+extern struct csr1212_keyval *
+csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
 
 
 /* This function increments the reference count for a keyval should there be a
@@ -691,37 +358,29 @@ static inline void csr1212_keep_keyval(s
  * keyval when there are no more users of the keyval.  This should be called by
  * any code that calls csr1212_keep_keyval() or any of the keyval creation
  * routines csr1212_new_*(). */
-static inline void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
-	if (kv->refcnt > 1)
-		kv->refcnt--;
-	else
-		_csr1212_destroy_keyval(kv);
-}
+extern void csr1212_release_keyval(struct csr1212_keyval *kv);
 
 
 /*
  * This macro allows for looping over the keyval entries in a directory and it
  * ensures that keyvals from remote ConfigROMs are parsed properly.
  *
- * _csr is a struct csr1212_csr * that points to CSR associated with dir.
- * _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index).
- * _dir is a struct csr1212_keyval * that points to the directory to be looped.
- * _pos is a struct csr1212_dentry * that is used internally for indexing.
+ * struct csr1212_csr *_csr points to the CSR associated with dir.
+ * struct csr1212_keyval *_kv points to the current keyval (loop index).
+ * struct csr1212_keyval *_dir points to the directory to be looped.
+ * struct csr1212_dentry *_pos is used internally for indexing.
  *
  * kv will be NULL upon exit of the loop.
  */
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos)			\
-	for (csr1212_get_keyval((_csr), (_dir)),				\
-	     _pos = (_dir)->value.directory.dentries_head,			\
-	     _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;	\
-	     (_kv) && (_pos);							\
-	     (_kv->associate == NULL) ?						\
-		     ((_pos = _pos->next), 					\
-		      (_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) :	\
-                          NULL)) :						\
+#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos)		\
+	for (csr1212_get_keyval((_csr), (_dir)),			\
+	     _pos = (_dir)->value.directory.dentries_head,		\
+	     _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
+	     (_kv) && (_pos);						\
+	     (_kv->associate == NULL) ?					\
+		     ((_pos = _pos->next), (_kv = (_pos) ?		\
+				csr1212_get_keyval((_csr), _pos->kv) :	\
+				NULL)) :				\
 		     (_kv = csr1212_get_keyval((_csr), _kv->associate)))
 
-
-
 #endif /* __CSR1212_H__ */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index c68f328..45d6055 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -62,6 +62,9 @@ void dma_prog_region_free(struct dma_pro
 
 /* dma_region */
 
+/**
+ * dma_region_init - clear out all fields but do not allocate anything
+ */
 void dma_region_init(struct dma_region *dma)
 {
 	dma->kvirt = NULL;
@@ -71,6 +74,9 @@ void dma_region_init(struct dma_region *
 	dma->sglist = NULL;
 }
 
+/**
+ * dma_region_alloc - 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)
 {
@@ -128,6 +134,9 @@ int dma_region_alloc(struct dma_region *
 	return -ENOMEM;
 }
 
+/**
+ * dma_region_free - unmap and free the buffer
+ */
 void dma_region_free(struct dma_region *dma)
 {
 	if (dma->n_dma_pages) {
@@ -167,6 +176,12 @@ static inline int dma_region_find(struct
 	return i;
 }
 
+/**
+ * dma_region_offset_to_bus - get bus address of an offset within a DMA region
+ *
+ * Returns the DMA bus address of the byte with the given @offset relative to
+ * the beginning of the @dma.
+ */
 dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
 				    unsigned long offset)
 {
@@ -177,6 +192,9 @@ dma_addr_t dma_region_offset_to_bus(stru
 	return sg_dma_address(sg) + rem;
 }
 
+/**
+ * dma_region_sync_for_cpu - sync the CPU's view of the buffer
+ */
 void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
 			     unsigned long len)
 {
@@ -193,6 +211,9 @@ void dma_region_sync_for_cpu(struct dma_
 				dma->direction);
 }
 
+/**
+ * dma_region_sync_for_device - sync the IO bus' view of the buffer
+ */
 void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
 				unsigned long len)
 {
@@ -244,6 +265,9 @@ static struct vm_operations_struct dma_r
 	.nopage = dma_region_pagefault,
 };
 
+/**
+ * dma_region_mmap - map the buffer into a user space process
+ */
 int dma_region_mmap(struct dma_region *dma, struct file *file,
 		    struct vm_area_struct *vma)
 {
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
index a1682ab..2727bcd 100644
--- a/drivers/ieee1394/dma.h
+++ b/drivers/ieee1394/dma.h
@@ -66,35 +66,23 @@ struct dma_region {
 	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);
-
-/* 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);
-
-/* sync the IO bus' view of the buffer */
 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);
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
+				    unsigned long offset);
 
-/* macro to index into a DMA region (or dma_prog_region) */
+/**
+ * dma_region_i - macro to index into a DMA region (or dma_prog_region)
+ */
 #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);
-
 #endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 026e38f..2081413 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -94,7 +94,6 @@ #include <linux/init.h>
 #include <linux/pci.h>
 #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>
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 03e44b3..2296d43 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1,5 +1,5 @@
 /*
- * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem
+ * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
  *
  * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
  *               2000 Bonin Franck <boninf@free.fr>
@@ -22,10 +22,9 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/* This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver
- * will ultimately support that method, but currently falls short in
- * several areas.
+/*
+ * This driver intends to support RFC 2734, which describes a method for
+ * transporting IPv4 datagrams over IEEE-1394 serial busses.
  *
  * TODO:
  * RFC 2734 related:
@@ -40,7 +39,6 @@
  * - Consider garbage collecting old partial datagrams after X amount of time
  */
 
-
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -52,7 +50,6 @@ #include <linux/init.h>
 
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/ip.h>
@@ -84,10 +81,6 @@ #define ETH1394_PRINT_G(level, fmt, args
 #define ETH1394_PRINT(level, dev_name, fmt, args...) \
 	printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
 
-#define DEBUG(fmt, args...) \
-	printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args)
-#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
-
 struct fragment_info {
 	struct list_head list;
 	int offset;
@@ -105,9 +98,9 @@ struct partial_datagram {
 };
 
 struct pdg_list {
-	struct list_head list;		/* partial datagram list per node	*/
-	unsigned int sz;		/* partial datagram list size per node	*/
-	spinlock_t lock;		/* partial datagram lock		*/
+	struct list_head list;	/* partial datagram list per node	*/
+	unsigned int sz;	/* partial datagram list size per node	*/
+	spinlock_t lock;	/* partial datagram lock		*/
 };
 
 struct eth1394_host_info {
@@ -121,16 +114,14 @@ struct eth1394_node_ref {
 };
 
 struct eth1394_node_info {
-	u16 maxpayload;			/* Max payload			*/
-	u8 sspd;			/* Max speed			*/
-	u64 fifo;			/* FIFO address			*/
-	struct pdg_list pdg;		/* partial RX datagram lists	*/
-	int dgl;			/* Outgoing datagram label	*/
+	u16 maxpayload;		/* max payload			*/
+	u8 sspd;		/* max speed			*/
+	u64 fifo;		/* FIFO address			*/
+	struct pdg_list pdg;	/* partial RX datagram lists	*/
+	int dgl;		/* outgoing datagram label	*/
 };
 
-/* Our ieee1394 highlevel driver */
-#define ETH1394_DRIVER_NAME "eth1394"
-static const char driver_name[] = ETH1394_DRIVER_NAME;
+static const char driver_name[] = "eth1394";
 
 static struct kmem_cache *packet_task_cache;
 
@@ -138,18 +129,12 @@ static struct hpsb_highlevel eth1394_hig
 
 /* Use common.lf to determine header len */
 static const int hdr_type_len[] = {
-	sizeof (struct eth1394_uf_hdr),
-	sizeof (struct eth1394_ff_hdr),
-	sizeof (struct eth1394_sf_hdr),
-	sizeof (struct eth1394_sf_hdr)
+	sizeof(struct eth1394_uf_hdr),
+	sizeof(struct eth1394_ff_hdr),
+	sizeof(struct eth1394_sf_hdr),
+	sizeof(struct eth1394_sf_hdr)
 };
 
-/* Change this to IEEE1394_SPEED_S100 to make testing easier */
-#define ETH1394_SPEED_DEF	IEEE1394_SPEED_MAX
-
-/* For now, this needs to be 1500, so that XP works with us */
-#define ETH1394_DATA_LEN	ETH_DATA_LEN
-
 static const u16 eth1394_speedto_maxpayload[] = {
 /*     S100, S200, S400, S800, S1600, S3200 */
 	512, 1024, 2048, 4096,  4096,  4096
@@ -159,7 +144,8 @@ MODULE_AUTHOR("Ben Collins (bcollins@deb
 MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
 MODULE_LICENSE("GPL");
 
-/* The max_partial_datagrams parameter is the maximum number of fragmented
+/*
+ * The max_partial_datagrams parameter is the maximum number of fragmented
  * datagrams per node that eth1394 will keep in memory.  Providing an upper
  * bound allows us to limit the amount of memory that partial datagrams
  * consume in the event that some partial datagrams are never completed.
@@ -179,10 +165,7 @@ static int ether1394_header_parse(struct
 static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
 static void ether1394_header_cache_update(struct hh_cache *hh,
 					  struct net_device *dev,
-					  unsigned char * haddr);
-static int ether1394_mac_addr(struct net_device *dev, void *p);
-
-static void purge_partial_datagram(struct list_head *old);
+					  unsigned char *haddr);
 static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
@@ -190,9 +173,9 @@ static struct ethtool_ops ethtool_ops;
 
 static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
 			   quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host (struct hpsb_host *host);
-static void ether1394_remove_host (struct hpsb_host *host);
-static void ether1394_host_reset (struct hpsb_host *host);
+static void ether1394_add_host(struct hpsb_host *host);
+static void ether1394_remove_host(struct hpsb_host *host);
+static void ether1394_host_reset(struct hpsb_host *host);
 
 /* Function for incoming 1394 packets */
 static struct hpsb_address_ops addr_ops = {
@@ -207,89 +190,107 @@ static struct hpsb_highlevel eth1394_hig
 	.host_reset =	ether1394_host_reset,
 };
 
+static int ether1394_recv_init(struct eth1394_priv *priv)
+{
+	unsigned int iso_buf_size;
+
+	/* FIXME: rawiso limits us to PAGE_SIZE */
+	iso_buf_size = min((unsigned int)PAGE_SIZE,
+			   2 * (1U << (priv->host->csr.max_rec + 1)));
+
+	priv->iso = hpsb_iso_recv_init(priv->host,
+				       ETHER1394_GASP_BUFFERS * iso_buf_size,
+				       ETHER1394_GASP_BUFFERS,
+				       priv->broadcast_channel,
+				       HPSB_ISO_DMA_PACKET_PER_BUFFER,
+				       1, ether1394_iso);
+	if (priv->iso == NULL) {
+		ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
+		priv->bc_state = ETHER1394_BC_ERROR;
+		return -EAGAIN;
+	}
+
+	if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
+		priv->bc_state = ETHER1394_BC_STOPPED;
+	else
+		priv->bc_state = ETHER1394_BC_RUNNING;
+	return 0;
+}
 
 /* This is called after an "ifup" */
-static int ether1394_open (struct net_device *dev)
+static int ether1394_open(struct net_device *dev)
 {
 	struct eth1394_priv *priv = netdev_priv(dev);
-	int ret = 0;
+	int ret;
 
-	/* Something bad happened, don't even try */
 	if (priv->bc_state == ETHER1394_BC_ERROR) {
-		/* we'll try again */
-		priv->iso = hpsb_iso_recv_init(priv->host,
-					       ETHER1394_ISO_BUF_SIZE,
-					       ETHER1394_GASP_BUFFERS,
-					       priv->broadcast_channel,
-					       HPSB_ISO_DMA_PACKET_PER_BUFFER,
-					       1, ether1394_iso);
-		if (priv->iso == NULL) {
-			ETH1394_PRINT(KERN_ERR, dev->name,
-				      "Could not allocate isochronous receive "
-				      "context for the broadcast channel\n");
-			priv->bc_state = ETHER1394_BC_ERROR;
-			ret = -EAGAIN;
-		} else {
-			if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
-				priv->bc_state = ETHER1394_BC_STOPPED;
-			else
-				priv->bc_state = ETHER1394_BC_RUNNING;
-		}
+		ret = ether1394_recv_init(priv);
+		if (ret)
+			return ret;
 	}
-
-	if (ret)
-		return ret;
-
-	netif_start_queue (dev);
+	netif_start_queue(dev);
 	return 0;
 }
 
 /* This is called after an "ifdown" */
-static int ether1394_stop (struct net_device *dev)
+static int ether1394_stop(struct net_device *dev)
 {
-	netif_stop_queue (dev);
+	netif_stop_queue(dev);
 	return 0;
 }
 
 /* Return statistics to the caller */
-static struct net_device_stats *ether1394_stats (struct net_device *dev)
+static struct net_device_stats *ether1394_stats(struct net_device *dev)
 {
 	return &(((struct eth1394_priv *)netdev_priv(dev))->stats);
 }
 
-/* What to do if we timeout. I think a host reset is probably in order, so
- * that's what we do. Should we increment the stat counters too?  */
-static void ether1394_tx_timeout (struct net_device *dev)
+/* FIXME: What to do if we timeout? I think a host reset is probably in order,
+ * so that's what we do. Should we increment the stat counters too?  */
+static void ether1394_tx_timeout(struct net_device *dev)
 {
-	ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n",
-		       ((struct eth1394_priv *)netdev_priv(dev))->host->driver->name);
+	struct hpsb_host *host =
+			((struct eth1394_priv *)netdev_priv(dev))->host;
 
-	highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host);
+	ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
+	ether1394_host_reset(host);
+}
 
-	netif_wake_queue (dev);
+static inline int ether1394_max_mtu(struct hpsb_host* host)
+{
+	return (1 << (host->csr.max_rec + 1))
+			- sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
 }
 
 static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct eth1394_priv *priv = netdev_priv(dev);
+	int max_mtu;
 
-	if ((new_mtu < 68) ||
-	    (new_mtu > min(ETH1394_DATA_LEN,
-			   (int)((1 << (priv->host->csr.max_rec + 1)) -
-				 (sizeof(union eth1394_hdr) +
-				  ETHER1394_GASP_OVERHEAD)))))
+	if (new_mtu < 68)
 		return -EINVAL;
+
+	max_mtu = ether1394_max_mtu(
+			((struct eth1394_priv *)netdev_priv(dev))->host);
+	if (new_mtu > max_mtu) {
+		ETH1394_PRINT(KERN_INFO, dev->name,
+			      "Local node constrains MTU to %d\n", max_mtu);
+		return -ERANGE;
+	}
+
 	dev->mtu = new_mtu;
 	return 0;
 }
 
 static void purge_partial_datagram(struct list_head *old)
 {
-	struct partial_datagram *pd = list_entry(old, struct partial_datagram, list);
+	struct partial_datagram *pd;
 	struct list_head *lh, *n;
+	struct fragment_info *fi;
+
+	pd = list_entry(old, struct partial_datagram, list);
 
 	list_for_each_safe(lh, n, &pd->frag_info) {
-		struct fragment_info *fi = list_entry(lh, struct fragment_info, list);
+		fi = list_entry(lh, struct fragment_info, list);
 		list_del(lh);
 		kfree(fi);
 	}
@@ -330,35 +331,26 @@ static struct eth1394_node_ref *eth1394_
 							 nodeid_t nodeid)
 {
 	struct eth1394_node_ref *node;
-	list_for_each_entry(node, inl, list) {
+
+	list_for_each_entry(node, inl, list)
 		if (node->ud->ne->nodeid == nodeid)
 			return node;
-	}
 
 	return NULL;
 }
 
-static int eth1394_probe(struct device *dev)
+static int eth1394_new_node(struct eth1394_host_info *hi,
+			    struct unit_directory *ud)
 {
-	struct unit_directory *ud;
-	struct eth1394_host_info *hi;
 	struct eth1394_priv *priv;
 	struct eth1394_node_ref *new_node;
 	struct eth1394_node_info *node_info;
 
-	ud = container_of(dev, struct unit_directory, device);
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-	if (!hi)
-		return -ENOENT;
-
-	new_node = kmalloc(sizeof(*new_node),
-			   in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
 	if (!new_node)
 		return -ENOMEM;
 
-	node_info = kmalloc(sizeof(*node_info),
-			    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
 	if (!node_info) {
 		kfree(new_node);
 		return -ENOMEM;
@@ -374,10 +366,22 @@ static int eth1394_probe(struct device *
 
 	priv = netdev_priv(hi->dev);
 	list_add_tail(&new_node->list, &priv->ip_node_list);
-
 	return 0;
 }
 
+static int eth1394_probe(struct device *dev)
+{
+	struct unit_directory *ud;
+	struct eth1394_host_info *hi;
+
+	ud = container_of(dev, struct unit_directory, device);
+	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
+	if (!hi)
+		return -ENOENT;
+
+	return eth1394_new_node(hi, ud);
+}
+
 static int eth1394_remove(struct device *dev)
 {
 	struct unit_directory *ud;
@@ -396,24 +400,23 @@ static int eth1394_remove(struct device 
 	priv = netdev_priv(hi->dev);
 
 	old_node = eth1394_find_node(&priv->ip_node_list, ud);
+	if (!old_node)
+		return 0;
 
-	if (old_node) {
-		list_del(&old_node->list);
-		kfree(old_node);
+	list_del(&old_node->list);
+	kfree(old_node);
 
-		node_info = (struct eth1394_node_info*)ud->device.driver_data;
+	node_info = (struct eth1394_node_info*)ud->device.driver_data;
 
-		spin_lock_irqsave(&node_info->pdg.lock, flags);
-		/* The partial datagram list should be empty, but we'll just
-		 * make sure anyway... */
-		list_for_each_safe(lh, n, &node_info->pdg.list) {
-			purge_partial_datagram(lh);
-		}
-		spin_unlock_irqrestore(&node_info->pdg.lock, flags);
+	spin_lock_irqsave(&node_info->pdg.lock, flags);
+	/* The partial datagram list should be empty, but we'll just
+	 * make sure anyway... */
+	list_for_each_safe(lh, n, &node_info->pdg.list)
+		purge_partial_datagram(lh);
+	spin_unlock_irqrestore(&node_info->pdg.lock, flags);
 
-		kfree(node_info);
-		ud->device.driver_data = NULL;
-	}
+	kfree(node_info);
+	ud->device.driver_data = NULL;
 	return 0;
 }
 
@@ -422,44 +425,19 @@ static int eth1394_update(struct unit_di
 	struct eth1394_host_info *hi;
 	struct eth1394_priv *priv;
 	struct eth1394_node_ref *node;
-	struct eth1394_node_info *node_info;
 
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
 	if (!hi)
 		return -ENOENT;
 
 	priv = netdev_priv(hi->dev);
-
 	node = eth1394_find_node(&priv->ip_node_list, ud);
+	if (node)
+		return 0;
 
-	if (!node) {
-		node = kmalloc(sizeof(*node),
-			       in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-		if (!node)
-			return -ENOMEM;
-
-		node_info = kmalloc(sizeof(*node_info),
-				    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-		if (!node_info) {
-			kfree(node);
-			return -ENOMEM;
-		}
-
-		spin_lock_init(&node_info->pdg.lock);
-		INIT_LIST_HEAD(&node_info->pdg.list);
-		node_info->pdg.sz = 0;
-
-		ud->device.driver_data = node_info;
-		node->ud = ud;
-
-		priv = netdev_priv(hi->dev);
-		list_add_tail(&node->list, &priv->ip_node_list);
-	}
-
-	return 0;
+	return eth1394_new_node(hi, ud);
 }
 
-
 static struct ieee1394_device_id eth1394_id_table[] = {
 	{
 		.match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
@@ -473,7 +451,7 @@ static struct ieee1394_device_id eth1394
 MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
 
 static struct hpsb_protocol_driver eth1394_proto_driver = {
-	.name		= ETH1394_DRIVER_NAME,
+	.name		= driver_name,
 	.id_table	= eth1394_id_table,
 	.update		= eth1394_update,
 	.driver		= {
@@ -482,47 +460,50 @@ static struct hpsb_protocol_driver eth13
 	},
 };
 
-
-static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
+static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
 {
 	unsigned long flags;
 	int i;
 	struct eth1394_priv *priv = netdev_priv(dev);
 	struct hpsb_host *host = priv->host;
-	u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3]));
-	u16 maxpayload = 1 << (host->csr.max_rec + 1);
+	u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
 	int max_speed = IEEE1394_SPEED_MAX;
 
-	spin_lock_irqsave (&priv->lock, flags);
+	spin_lock_irqsave(&priv->lock, flags);
 
-	memset(priv->ud_list, 0, sizeof(struct node_entry*) * ALL_NODES);
+	memset(priv->ud_list, 0, sizeof(priv->ud_list));
 	priv->bc_maxpayload = 512;
 
 	/* Determine speed limit */
-	for (i = 0; i < host->node_count; i++)
+	/* FIXME: This is broken for nodes with link speed < PHY speed,
+	 * and it is suboptimal for S200B...S800B hardware.
+	 * The result of nodemgr's speed probe should be used somehow. */
+	for (i = 0; i < host->node_count; i++) {
+		/* take care of S100B...S400B PHY ports */
+		if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
+			max_speed = IEEE1394_SPEED_100;
+			break;
+		}
 		if (max_speed > host->speed[i])
 			max_speed = host->speed[i];
+	}
 	priv->bc_sspd = max_speed;
 
-	/* We'll use our maxpayload as the default mtu */
 	if (set_mtu) {
-		dev->mtu = min(ETH1394_DATA_LEN,
-			       (int)(maxpayload -
-				     (sizeof(union eth1394_hdr) +
-				      ETHER1394_GASP_OVERHEAD)));
+		/* Use the RFC 2734 default 1500 octets or the maximum payload
+		 * as initial MTU */
+		dev->mtu = min(1500, ether1394_max_mtu(host));
 
 		/* Set our hardware address while we're at it */
 		memcpy(dev->dev_addr, &guid, sizeof(u64));
 		memset(dev->broadcast, 0xff, sizeof(u64));
 	}
 
-	spin_unlock_irqrestore (&priv->lock, flags);
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-/* This function is called right before register_netdev */
-static void ether1394_init_dev (struct net_device *dev)
+static void ether1394_init_dev(struct net_device *dev)
 {
-	/* Our functions */
 	dev->open		= ether1394_open;
 	dev->stop		= ether1394_stop;
 	dev->hard_start_xmit	= ether1394_tx;
@@ -535,10 +516,9 @@ static void ether1394_init_dev (struct n
 	dev->hard_header_cache	= ether1394_header_cache;
 	dev->header_cache_update= ether1394_header_cache_update;
 	dev->hard_header_parse	= ether1394_header_parse;
-	dev->set_mac_address	= ether1394_mac_addr;
+
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
-	/* Some constants */
 	dev->watchdog_timeo	= ETHER1394_TIMEOUT;
 	dev->flags		= IFF_BROADCAST | IFF_MULTICAST;
 	dev->features		= NETIF_F_HIGHDMA;
@@ -546,7 +526,8 @@ static void ether1394_init_dev (struct n
 	dev->hard_header_len 	= ETH1394_HLEN;
 	dev->type		= ARPHRD_IEEE1394;
 
-	ether1394_reset_priv (dev, 1);
+	/* FIXME: This value was copied from ether_setup(). Is it too much? */
+	dev->tx_queue_len	= 1000;
 }
 
 /*
@@ -554,34 +535,33 @@ static void ether1394_init_dev (struct n
  * when the module is installed. This is where we add all of our ethernet
  * devices. One for each host.
  */
-static void ether1394_add_host (struct hpsb_host *host)
+static void ether1394_add_host(struct hpsb_host *host)
 {
 	struct eth1394_host_info *hi = NULL;
 	struct net_device *dev = NULL;
 	struct eth1394_priv *priv;
 	u64 fifo_addr;
 
-	if (!(host->config_roms & HPSB_CONFIG_ROM_ENTRY_IP1394))
+	if (hpsb_config_rom_ip1394_add(host) != 0) {
+		ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
 		return;
+	}
 
 	fifo_addr = hpsb_allocate_and_register_addrspace(
 			&eth1394_highlevel, host, &addr_ops,
 			ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
 			CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
-	if (fifo_addr == CSR1212_INVALID_ADDR_SPACE)
-		goto out;
-
-	/* We should really have our own alloc_hpsbdev() function in
-	 * net_init.c instead of calling the one for ethernet then hijacking
-	 * it for ourselves.  That way we'd be a real networking device. */
-	dev = alloc_etherdev(sizeof (struct eth1394_priv));
+	if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
+		ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
+		hpsb_config_rom_ip1394_remove(host);
+		return;
+	}
 
+	dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
 	if (dev == NULL) {
-		ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate "
-				 "etherdevice for IEEE 1394 device %s-%d\n",
-				 host->driver->name, host->id);
+		ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
 		goto out;
-        }
+	}
 
 	SET_MODULE_OWNER(dev);
 #if 0
@@ -590,31 +570,26 @@ #if 0
 #endif
 
 	priv = netdev_priv(dev);
-
 	INIT_LIST_HEAD(&priv->ip_node_list);
-
 	spin_lock_init(&priv->lock);
 	priv->host = host;
 	priv->local_fifo = fifo_addr;
 
 	hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
-
 	if (hi == NULL) {
-		ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create "
-				 "hostinfo for IEEE 1394 device %s-%d\n",
-				 host->driver->name, host->id);
+		ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
 		goto out;
-        }
+	}
 
-	ether1394_init_dev(dev);
+	ether1394_reset_priv(dev, 1);
 
-	if (register_netdev (dev)) {
-		ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
+	if (register_netdev(dev)) {
+		ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
 		goto out;
 	}
 
-	ETH1394_PRINT (KERN_INFO, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n",
-		       host->id);
+	ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
+		      host->id);
 
 	hi->host = host;
 	hi->dev = dev;
@@ -623,61 +598,37 @@ #endif
 	 * be checked when the eth device is opened. */
 	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
 
-	priv->iso = hpsb_iso_recv_init(host,
-				       ETHER1394_ISO_BUF_SIZE,
-				       ETHER1394_GASP_BUFFERS,
-				       priv->broadcast_channel,
-				       HPSB_ISO_DMA_PACKET_PER_BUFFER,
-				       1, ether1394_iso);
-	if (priv->iso == NULL) {
-		ETH1394_PRINT(KERN_ERR, dev->name,
-			      "Could not allocate isochronous receive context "
-			      "for the broadcast channel\n");
-		priv->bc_state = ETHER1394_BC_ERROR;
-	} else {
-		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
-			priv->bc_state = ETHER1394_BC_STOPPED;
-		else
-			priv->bc_state = ETHER1394_BC_RUNNING;
-	}
-
+	ether1394_recv_init(priv);
 	return;
-
 out:
-	if (dev != NULL)
+	if (dev)
 		free_netdev(dev);
 	if (hi)
 		hpsb_destroy_hostinfo(&eth1394_highlevel, host);
-
-	return;
+	hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
+	hpsb_config_rom_ip1394_remove(host);
 }
 
 /* Remove a card from our list */
-static void ether1394_remove_host (struct hpsb_host *host)
+static void ether1394_remove_host(struct hpsb_host *host)
 {
 	struct eth1394_host_info *hi;
+	struct eth1394_priv *priv;
 
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-	if (hi != NULL) {
-		struct eth1394_priv *priv = netdev_priv(hi->dev);
-
-		hpsb_unregister_addrspace(&eth1394_highlevel, host,
-					  priv->local_fifo);
-
-		if (priv->iso != NULL)
-			hpsb_iso_shutdown(priv->iso);
-
-		if (hi->dev) {
-			unregister_netdev (hi->dev);
-			free_netdev(hi->dev);
-		}
-	}
-
-	return;
+	if (!hi)
+		return;
+	priv = netdev_priv(hi->dev);
+	hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
+	hpsb_config_rom_ip1394_remove(host);
+	if (priv->iso)
+		hpsb_iso_shutdown(priv->iso);
+	unregister_netdev(hi->dev);
+	free_netdev(hi->dev);
 }
 
-/* A reset has just arisen */
-static void ether1394_host_reset (struct hpsb_host *host)
+/* A bus reset happened */
+static void ether1394_host_reset(struct hpsb_host *host)
 {
 	struct eth1394_host_info *hi;
 	struct eth1394_priv *priv;
@@ -690,24 +641,23 @@ static void ether1394_host_reset (struct
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 
 	/* This can happen for hosts that we don't use */
-	if (hi == NULL)
+	if (!hi)
 		return;
 
 	dev = hi->dev;
-	priv = (struct eth1394_priv *)netdev_priv(dev);
+	priv = netdev_priv(dev);
 
-	/* Reset our private host data, but not our mtu */
-	netif_stop_queue (dev);
-	ether1394_reset_priv (dev, 0);
+	/* Reset our private host data, but not our MTU */
+	netif_stop_queue(dev);
+	ether1394_reset_priv(dev, 0);
 
 	list_for_each_entry(node, &priv->ip_node_list, list) {
-		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+		node_info = node->ud->device.driver_data;
 
 		spin_lock_irqsave(&node_info->pdg.lock, flags);
 
-		list_for_each_safe(lh, n, &node_info->pdg.list) {
+		list_for_each_safe(lh, n, &node_info->pdg.list)
 			purge_partial_datagram(lh);
-		}
 
 		INIT_LIST_HEAD(&(node_info->pdg.list));
 		node_info->pdg.sz = 0;
@@ -715,7 +665,7 @@ static void ether1394_host_reset (struct
 		spin_unlock_irqrestore(&node_info->pdg.lock, flags);
 	}
 
-	netif_wake_queue (dev);
+	netif_wake_queue(dev);
 }
 
 /******************************************
@@ -723,7 +673,6 @@ static void ether1394_host_reset (struct
  ******************************************/
 /* These functions have been adapted from net/ethernet/eth.c */
 
-
 /* Create a fake MAC header for an arbitrary protocol layer.
  * saddr=NULL means use device source address
  * daddr=NULL means leave destination address (eg unresolved arp). */
@@ -731,25 +680,24 @@ static int ether1394_header(struct sk_bu
 			    unsigned short type, void *daddr, void *saddr,
 			    unsigned len)
 {
-	struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
+	struct eth1394hdr *eth =
+			(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
 
 	eth->h_proto = htons(type);
 
-	if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) {
+	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
 		memset(eth->h_dest, 0, dev->addr_len);
-		return(dev->hard_header_len);
+		return dev->hard_header_len;
 	}
 
 	if (daddr) {
-		memcpy(eth->h_dest,daddr,dev->addr_len);
+		memcpy(eth->h_dest, daddr, dev->addr_len);
 		return dev->hard_header_len;
 	}
 
 	return -dev->hard_header_len;
-
 }
 
-
 /* Rebuild the faked 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.
@@ -760,38 +708,30 @@ static int ether1394_header(struct sk_bu
 static int ether1394_rebuild_header(struct sk_buff *skb)
 {
 	struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
-	struct net_device *dev = skb->dev;
 
-	switch (eth->h_proto) {
-
-#ifdef CONFIG_INET
-	case __constant_htons(ETH_P_IP):
- 		return arp_find((unsigned char*)&eth->h_dest, skb);
-#endif
-	default:
-		ETH1394_PRINT(KERN_DEBUG, dev->name,
-			      "unable to resolve type %04x addresses.\n",
-			      ntohs(eth->h_proto));
-		break;
-	}
+	if (eth->h_proto == htons(ETH_P_IP))
+		return arp_find((unsigned char *)&eth->h_dest, skb);
 
+	ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
+		      "unable to resolve type %04x addresses\n",
+		      ntohs(eth->h_proto));
 	return 0;
 }
 
 static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
 	struct net_device *dev = skb->dev;
+
 	memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
 	return ETH1394_ALEN;
 }
 
-
 static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
-	struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) +
-						      (16 - ETH1394_HLEN));
 	struct net_device *dev = neigh->dev;
+	struct eth1394hdr *eth =
+		(struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
 
 	if (type == htons(ETH_P_802_3))
 		return -1;
@@ -808,38 +748,25 @@ static void ether1394_header_cache_updat
 					  struct net_device *dev,
 					  unsigned char * haddr)
 {
-	memcpy(((u8*)hh->hh_data) + (16 - ETH1394_HLEN), haddr, dev->addr_len);
+	memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
 }
 
-static int ether1394_mac_addr(struct net_device *dev, void *p)
-{
-	if (netif_running(dev))
-		return -EBUSY;
-
-	/* Not going to allow setting the MAC address, we really need to use
-	 * the real one supplied by the hardware */
-	 return -EINVAL;
- }
-
-
-
 /******************************************
  * Datagram reception code
  ******************************************/
 
 /* Copied from net/ethernet/eth.c */
-static inline u16 ether1394_type_trans(struct sk_buff *skb,
-				       struct net_device *dev)
+static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct eth1394hdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw = skb->data;
-	skb_pull (skb, ETH1394_HLEN);
+	skb_reset_mac_header(skb);
+	skb_pull(skb, ETH1394_HLEN);
 	eth = eth1394_hdr(skb);
 
 	if (*eth->h_dest & 1) {
-		if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0)
+		if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
 			skb->pkt_type = PACKET_BROADCAST;
 #if 0
 		else
@@ -848,47 +775,45 @@ #endif
 	} else {
 		if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
 			skb->pkt_type = PACKET_OTHERHOST;
-        }
+	}
 
-	if (ntohs (eth->h_proto) >= 1536)
+	if (ntohs(eth->h_proto) >= 1536)
 		return eth->h_proto;
 
 	rawp = skb->data;
 
-        if (*(unsigned short *)rawp == 0xFFFF)
-		return htons (ETH_P_802_3);
+	if (*(unsigned short *)rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
 
-        return htons (ETH_P_802_2);
+	return htons(ETH_P_802_2);
 }
 
 /* Parse an encapsulated IP1394 header into an ethernet frame packet.
  * We also perform ARP translation here, if need be.  */
-static inline u16 ether1394_parse_encap(struct sk_buff *skb,
-					struct net_device *dev,
-					nodeid_t srcid, nodeid_t destid,
-					u16 ether_type)
+static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
+				 nodeid_t srcid, nodeid_t destid,
+				 u16 ether_type)
 {
 	struct eth1394_priv *priv = netdev_priv(dev);
 	u64 dest_hw;
 	unsigned short ret = 0;
 
-	/* Setup our hw addresses. We use these to build the
-	 * ethernet header.  */
+	/* Setup our hw addresses. We use these to build the ethernet header. */
 	if (destid == (LOCAL_BUS | ALL_NODES))
 		dest_hw = ~0ULL;  /* broadcast */
 	else
-		dest_hw = cpu_to_be64((((u64)priv->host->csr.guid_hi) << 32) |
+		dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
 				      priv->host->csr.guid_lo);
 
 	/* If this is an ARP packet, convert it. First, we want to make
 	 * use of some of the fields, since they tell us a little bit
 	 * about the sending machine.  */
 	if (ether_type == htons(ETH_P_ARP)) {
-		struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data;
+		struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
 		struct arphdr *arp = (struct arphdr *)skb->data;
 		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
 		u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
-			ntohl(arp1394->fifo_lo);
+					   ntohl(arp1394->fifo_lo);
 		u8 max_rec = min(priv->host->csr.max_rec,
 				 (u8)(arp1394->max_rec));
 		int sspd = arp1394->sspd;
@@ -902,16 +827,17 @@ static inline u16 ether1394_parse_encap(
 		if (sspd > 5 || sspd < 0)
 			sspd = 0;
 
-		maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1)));
+		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(guid));
-		if (!node) {
+		if (!node)
 			return 0;
-		}
 
-		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+		node_info =
+		    (struct eth1394_node_info *)node->ud->device.driver_data;
 
 		/* Update our speed/payload/fifo_offset table */
 		node_info->maxpayload =	maxpayload;
@@ -930,7 +856,7 @@ static inline u16 ether1394_parse_encap(
 
 		arp->ar_hln = 8;
 		arp_ptr += arp->ar_hln;		/* skip over sender unique id */
-		*(u32*)arp_ptr = arp1394->sip;	/* move sender IP addr */
+		*(u32 *)arp_ptr = arp1394->sip;	/* move sender IP addr */
 		arp_ptr += arp->ar_pln;		/* skip over sender IP addr */
 
 		if (arp->ar_op == htons(ARPOP_REQUEST))
@@ -947,65 +873,65 @@ static inline u16 ether1394_parse_encap(
 	return ret;
 }
 
-static inline int fragment_overlap(struct list_head *frag_list, int offset, int len)
+static int fragment_overlap(struct list_head *frag_list, int offset, int len)
 {
 	struct fragment_info *fi;
+	int end = offset + len;
 
-	list_for_each_entry(fi, frag_list, list) {
-		if ( ! ((offset > (fi->offset + fi->len - 1)) ||
-		       ((offset + len - 1) < fi->offset)))
+	list_for_each_entry(fi, frag_list, list)
+		if (offset < fi->offset + fi->len && end > fi->offset)
 			return 1;
-	}
+
 	return 0;
 }
 
-static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
+static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
 {
 	struct partial_datagram *pd;
 
-	list_for_each_entry(pd, pdgl, list) {
+	list_for_each_entry(pd, pdgl, list)
 		if (pd->dgl == dgl)
 			return &pd->list;
-	}
+
 	return NULL;
 }
 
 /* Assumes that new fragment does not overlap any existing fragments */
-static inline int new_fragment(struct list_head *frag_info, int offset, int len)
+static int new_fragment(struct list_head *frag_info, int offset, int len)
 {
 	struct list_head *lh;
 	struct fragment_info *fi, *fi2, *new;
 
 	list_for_each(lh, frag_info) {
 		fi = list_entry(lh, struct fragment_info, list);
-		if ((fi->offset + fi->len) == offset) {
+		if (fi->offset + fi->len == offset) {
 			/* The new fragment can be tacked on to the end */
 			fi->len += len;
 			/* Did the new fragment plug a hole? */
 			fi2 = list_entry(lh->next, struct fragment_info, list);
-			if ((fi->offset + fi->len) == fi2->offset) {
+			if (fi->offset + fi->len == fi2->offset) {
 				/* glue fragments together */
 				fi->len += fi2->len;
 				list_del(lh->next);
 				kfree(fi2);
 			}
 			return 0;
-		} else if ((offset + len) == fi->offset) {
+		} else if (offset + len == fi->offset) {
 			/* The new fragment can be tacked on to the beginning */
 			fi->offset = offset;
 			fi->len += len;
 			/* Did the new fragment plug a hole? */
 			fi2 = list_entry(lh->prev, struct fragment_info, list);
-			if ((fi2->offset + fi2->len) == fi->offset) {
+			if (fi2->offset + fi2->len == fi->offset) {
 				/* glue fragments together */
 				fi2->len += fi->len;
 				list_del(lh);
 				kfree(fi);
 			}
 			return 0;
-		} else if (offset > (fi->offset + fi->len)) {
+		} else if (offset > fi->offset + fi->len) {
 			break;
-		} else if ((offset + len) < fi->offset) {
+		} else if (offset + len < fi->offset) {
 			lh = lh->prev;
 			break;
 		}
@@ -1019,14 +945,12 @@ static inline int new_fragment(struct li
 	new->len = len;
 
 	list_add(&new->list, lh);
-
 	return 0;
 }
 
-static inline int new_partial_datagram(struct net_device *dev,
-				       struct list_head *pdgl, int dgl,
-				       int dg_size, char *frag_buf,
-				       int frag_off, int frag_len)
+static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
+				int dgl, int dg_size, char *frag_buf,
+				int frag_off, int frag_len)
 {
 	struct partial_datagram *new;
 
@@ -1059,33 +983,33 @@ static inline int new_partial_datagram(s
 	memcpy(new->pbuf + frag_off, frag_buf, frag_len);
 
 	list_add(&new->list, pdgl);
-
 	return 0;
 }
 
-static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
-					  char *frag_buf, int frag_off, int frag_len)
+static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
+				   char *frag_buf, int frag_off, int frag_len)
 {
-	struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
+	struct partial_datagram *pd =
+			list_entry(lh, struct partial_datagram, list);
 
-	if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) {
+	if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
 		return -ENOMEM;
-	}
 
 	memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
 
 	/* Move list entry to beginnig of list so that oldest partial
 	 * datagrams percolate to the end of the list */
 	list_move(lh, pdgl);
-
 	return 0;
 }
 
-static inline int is_datagram_complete(struct list_head *lh, int dg_size)
+static int is_datagram_complete(struct list_head *lh, int dg_size)
 {
-	struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
-	struct fragment_info *fi = list_entry(pd->frag_info.next,
-					      struct fragment_info, list);
+	struct partial_datagram *pd;
+	struct fragment_info *fi;
+
+	pd = list_entry(lh, struct partial_datagram, list);
+	fi = list_entry(pd->frag_info.next, struct fragment_info, list);
 
 	return (fi->len == dg_size);
 }
@@ -1108,7 +1032,7 @@ static int ether1394_data_handler(struct
 	if (!ud) {
 		struct eth1394_node_ref *node;
 		node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
-		if (!node) {
+		if (unlikely(!node)) {
 			HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
 				   "lookup failure: " NODE_BUS_FMT,
 				   NODE_BUS_ARGS(priv->host, srcid));
@@ -1120,7 +1044,7 @@ static int ether1394_data_handler(struct
 		priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
 	}
 
-	node_info = (struct eth1394_node_info*)ud->device.driver_data;
+	node_info = (struct eth1394_node_info *)ud->device.driver_data;
 
 	/* First, did we receive a fragmented or unfragmented datagram? */
 	hdr->words.word1 = ntohs(hdr->words.word1);
@@ -1133,13 +1057,14 @@ static int ether1394_data_handler(struct
 		 * high level network layer. */
 
 		skb = dev_alloc_skb(len + dev->hard_header_len + 15);
-		if (!skb) {
-			HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+		if (unlikely(!skb)) {
+			ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
 			priv->stats.rx_dropped++;
 			return -1;
 		}
 		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-		memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len);
+		memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
+		       len - hdr_len);
 		ether_type = hdr->uf.ether_type;
 	} else {
 		/* A datagram fragment has been received, now the fun begins. */
@@ -1224,9 +1149,8 @@ static int ether1394_data_handler(struct
 
 		pd = list_entry(lh, struct partial_datagram, list);
 
-		if (hdr->common.lf == ETH1394_HDR_LF_FF) {
+		if (hdr->common.lf == ETH1394_HDR_LF_FF)
 			pd->ether_type = ether_type;
-		}
 
 		if (is_datagram_complete(lh, dg_size)) {
 			ether_type = pd->ether_type;
@@ -1253,8 +1177,8 @@ static int ether1394_data_handler(struct
 	skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
 					      ether_type);
 
-
 	spin_lock_irqsave(&priv->lock, flags);
+
 	if (!skb->protocol) {
 		priv->stats.rx_errors++;
 		priv->stats.rx_dropped++;
@@ -1288,9 +1212,9 @@ static int ether1394_write(struct hpsb_h
 	struct eth1394_host_info *hi;
 
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-	if (hi == NULL) {
-		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
-				host->driver->name);
+	if (unlikely(!hi)) {
+		ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
+				host->id);
 		return RCODE_ADDRESS_ERROR;
 	}
 
@@ -1314,9 +1238,9 @@ static void ether1394_iso(struct hpsb_is
 	int nready;
 
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
-	if (hi == NULL) {
-		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
-				iso->host->driver->name);
+	if (unlikely(!hi)) {
+		ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
+				iso->host->id);
 		return;
 	}
 
@@ -1326,20 +1250,20 @@ static void ether1394_iso(struct hpsb_is
 	for (i = 0; i < nready; i++) {
 		struct hpsb_iso_packet_info *info =
 			&iso->infos[(iso->first_packet + i) % iso->buf_packets];
-		data = (quadlet_t*) (iso->data_buf.kvirt + info->offset);
+		data = (quadlet_t *)(iso->data_buf.kvirt + info->offset);
 
 		/* skip over GASP header */
 		buf = (char *)data + 8;
 		len = info->len - 8;
 
-		specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) |
-				((be32_to_cpu(data[1]) & 0xff000000) >> 24));
+		specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
+			       (be32_to_cpu(data[1]) & 0xff000000) >> 24;
 		source_id = be32_to_cpu(data[0]) >> 16;
 
 		priv = netdev_priv(dev);
 
-		if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) ||
-		   specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+		if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
+		    || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
 			/* This packet is not for us */
 			continue;
 		}
@@ -1367,35 +1291,31 @@ static void ether1394_iso(struct hpsb_is
  * speed, and unicast FIFO address information between the sender_unique_id
  * and the IP addresses.
  */
-static inline void ether1394_arp_to_1394arp(struct sk_buff *skb,
-					    struct net_device *dev)
+static void ether1394_arp_to_1394arp(struct sk_buff *skb,
+				     struct net_device *dev)
 {
 	struct eth1394_priv *priv = netdev_priv(dev);
-
 	struct arphdr *arp = (struct arphdr *)skb->data;
 	unsigned char *arp_ptr = (unsigned char *)(arp + 1);
 	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
 
-	/* Believe it or not, all that need to happen is sender IP get moved
-	 * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo.  */
 	arp1394->hw_addr_len	= 16;
 	arp1394->sip		= *(u32*)(arp_ptr + ETH1394_ALEN);
 	arp1394->max_rec	= priv->host->csr.max_rec;
 	arp1394->sspd		= priv->host->csr.lnk_spd;
-	arp1394->fifo_hi	= htons (priv->local_fifo >> 32);
-	arp1394->fifo_lo	= htonl (priv->local_fifo & ~0x0);
-
-	return;
+	arp1394->fifo_hi	= htons(priv->local_fifo >> 32);
+	arp1394->fifo_lo	= htonl(priv->local_fifo & ~0x0);
 }
 
 /* We need to encapsulate the standard header with our own. We use the
  * ethernet header's proto for our own. */
-static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
-						      __be16 proto,
-						      union eth1394_hdr *hdr,
-						      u16 dg_size, u16 dgl)
+static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
+					       __be16 proto,
+					       union eth1394_hdr *hdr,
+					       u16 dg_size, u16 dgl)
 {
-	unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
+	unsigned int adj_max_payload =
+				max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
 
 	/* Does it all fit in one packet? */
 	if (dg_size <= adj_max_payload) {
@@ -1408,19 +1328,19 @@ static inline unsigned int ether1394_enc
 		hdr->ff.dgl = dgl;
 		adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
 	}
-	return((dg_size + (adj_max_payload - 1)) / adj_max_payload);
+	return (dg_size + adj_max_payload - 1) / adj_max_payload;
 }
 
-static inline unsigned int ether1394_encapsulate(struct sk_buff *skb,
-						 unsigned int max_payload,
-						 union eth1394_hdr *hdr)
+static unsigned int ether1394_encapsulate(struct sk_buff *skb,
+					  unsigned int max_payload,
+					  union eth1394_hdr *hdr)
 {
 	union eth1394_hdr *bufhdr;
 	int ftype = hdr->common.lf;
 	int hdrsz = hdr_type_len[ftype];
 	unsigned int adj_max_payload = max_payload - hdrsz;
 
-	switch(ftype) {
+	switch (ftype) {
 	case ETH1394_HDR_LF_UF:
 		bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
 		bufhdr->words.word1 = htons(hdr->words.word1);
@@ -1449,11 +1369,10 @@ static inline unsigned int ether1394_enc
 		bufhdr->words.word3 = htons(hdr->words.word3);
 		bufhdr->words.word4 = 0;
 	}
-
 	return min(max_payload, skb->len);
 }
 
-static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
+static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
 {
 	struct hpsb_packet *p;
 
@@ -1466,61 +1385,57 @@ static inline struct hpsb_packet *ether1
 	return p;
 }
 
-static inline int ether1394_prep_write_packet(struct hpsb_packet *p,
-					      struct hpsb_host *host,
-					      nodeid_t node, u64 addr,
-					      void * data, int tx_len)
+static int ether1394_prep_write_packet(struct hpsb_packet *p,
+				       struct hpsb_host *host, nodeid_t node,
+				       u64 addr, void *data, int tx_len)
 {
 	p->node_id = node;
 	p->data = NULL;
 
 	p->tcode = TCODE_WRITEB;
-	p->header[1] = (host->node_id << 16) | (addr >> 32);
+	p->header[1] = host->node_id << 16 | addr >> 32;
 	p->header[2] = addr & 0xffffffff;
 
 	p->header_size = 16;
 	p->expect_response = 1;
 
 	if (hpsb_get_tlabel(p)) {
-		ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending "
-				"to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node));
+		ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
 		return -1;
 	}
-	p->header[0] = (p->node_id << 16) | (p->tlabel << 10)
-		| (1 << 8) | (TCODE_WRITEB << 4);
+	p->header[0] =
+		p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
 
 	p->header[3] = tx_len << 16;
 	p->data_size = (tx_len + 3) & ~3;
-	p->data = (quadlet_t*)data;
+	p->data = data;
 
 	return 0;
 }
 
-static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p,
-					      struct eth1394_priv *priv,
-					      struct sk_buff *skb, int length)
+static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
+				       struct eth1394_priv *priv,
+				       struct sk_buff *skb, int length)
 {
 	p->header_size = 4;
 	p->tcode = TCODE_STREAM_DATA;
 
-	p->header[0] = (length << 16) | (3 << 14)
-		| ((priv->broadcast_channel) << 8)
-		| (TCODE_STREAM_DATA << 4);
+	p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
+		       TCODE_STREAM_DATA << 4;
 	p->data_size = length;
-	p->data = ((quadlet_t*)skb->data) - 2;
-	p->data[0] = cpu_to_be32((priv->host->node_id << 16) |
+	p->data = (quadlet_t *)skb->data - 2;
+	p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
 				 ETHER1394_GASP_SPECIFIER_ID_HI);
-	p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) |
+	p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
 				 ETHER1394_GASP_VERSION);
 
-	/* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES)
-	 * prevents hpsb_send_packet() from setting the speed to an arbitrary
-	 * value based on packet->node_id if packet->node_id is not set. */
-	p->node_id = ALL_NODES;
 	p->speed_code = priv->bc_sspd;
+
+	/* prevent hpsb_send_packet() from overriding our speed code */
+	p->node_id = LOCAL_BUS | ALL_NODES;
 }
 
-static inline void ether1394_free_packet(struct hpsb_packet *packet)
+static void ether1394_free_packet(struct hpsb_packet *packet)
 {
 	if (packet->tcode != TCODE_STREAM_DATA)
 		hpsb_free_tlabel(packet);
@@ -1539,7 +1454,7 @@ static int ether1394_send_packet(struct 
 		return -1;
 
 	if (ptask->tx_type == ETH1394_GASP) {
-		int length = tx_len + (2 * sizeof(quadlet_t));
+		int length = tx_len + 2 * sizeof(quadlet_t);
 
 		ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
 	} else if (ether1394_prep_write_packet(packet, priv->host,
@@ -1562,13 +1477,11 @@ static int ether1394_send_packet(struct 
 	return 0;
 }
 
-
 /* Task function to be run when a datagram transmission is completed */
-static inline void ether1394_dg_complete(struct packet_task *ptask, int fail)
+static void ether1394_dg_complete(struct packet_task *ptask, int fail)
 {
 	struct sk_buff *skb = ptask->skb;
-	struct net_device *dev = skb->dev;
-	struct eth1394_priv *priv = netdev_priv(dev);
+	struct eth1394_priv *priv = netdev_priv(skb->dev);
 	unsigned long flags;
 
 	/* Statistics */
@@ -1586,7 +1499,6 @@ static inline void ether1394_dg_complete
 	kmem_cache_free(packet_task_cache, ptask);
 }
 
-
 /* Callback for when a packet has been sent and the status of that packet is
  * known */
 static void ether1394_complete_cb(void *__ptask)
@@ -1614,19 +1526,15 @@ static void ether1394_complete_cb(void *
 	}
 }
 
-
-
 /* Transmit a packet (called by kernel) */
-static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
+static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 	struct eth1394hdr *eth;
 	struct eth1394_priv *priv = netdev_priv(dev);
 	__be16 proto;
 	unsigned long flags;
 	nodeid_t dest_node;
 	eth1394_tx_type tx_type;
-	int ret = 0;
 	unsigned int tx_len;
 	unsigned int max_payload;
 	u16 dg_size;
@@ -1635,29 +1543,24 @@ static int ether1394_tx (struct sk_buff 
 	struct eth1394_node_ref *node;
 	struct eth1394_node_info *node_info = NULL;
 
-	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
-	if (ptask == NULL) {
-		ret = -ENOMEM;
+	ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
+	if (ptask == NULL)
 		goto fail;
-	}
 
 	/* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
 	 * it does not set our validity bit. We need to compensate for
 	 * that somewhere else, but not in eth1394. */
 #if 0
-	if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) {
-		ret = -EAGAIN;
+	if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
 		goto fail;
-	}
 #endif
 
-	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
-		ret = -ENOMEM;
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
 		goto fail;
-	}
 
 	/* Get rid of the fake eth1394 header, but save a pointer */
-	eth = (struct eth1394hdr*)skb->data;
+	eth = (struct eth1394hdr *)skb->data;
 	skb_pull(skb, ETH1394_HLEN);
 
 	proto = eth->h_proto;
@@ -1668,11 +1571,11 @@ #endif
 	if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
 	    proto == htons(ETH_P_ARP) ||
 	    (proto == htons(ETH_P_IP) &&
-	     IN_MULTICAST(ntohl(skb->nh.iph->daddr)))) {
+	     IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
 		tx_type = ETH1394_GASP;
 		dest_node = LOCAL_BUS | ALL_NODES;
 		max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
-		BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+		BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
 		dgl = priv->bc_dgl;
 		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
 			priv->bc_dgl++;
@@ -1681,19 +1584,17 @@ #endif
 
 		node = eth1394_find_node_guid(&priv->ip_node_list,
 					      be64_to_cpu(guid));
-		if (!node) {
-			ret = -EAGAIN;
+		if (!node)
 			goto fail;
-		}
-		node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
-		if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) {
-			ret = -EAGAIN;
+
+		node_info =
+		    (struct eth1394_node_info *)node->ud->device.driver_data;
+		if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
 			goto fail;
-		}
 
 		dest_node = node->ud->ne->nodeid;
 		max_payload = node_info->maxpayload;
-		BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+		BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
 
 		dgl = node_info->dgl;
 		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
@@ -1703,7 +1604,7 @@ #endif
 
 	/* If this is an ARP packet, convert it */
 	if (proto == htons(ETH_P_ARP))
-		ether1394_arp_to_1394arp (skb, dev);
+		ether1394_arp_to_1394arp(skb, dev);
 
 	ptask->hdr.words.word1 = 0;
 	ptask->hdr.words.word2 = 0;
@@ -1726,9 +1627,8 @@ #endif
 
 	ptask->tx_type = tx_type;
 	ptask->max_payload = max_payload;
-        ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto,
-							     &ptask->hdr, dg_size,
-							     dgl);
+	ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
+					proto, &ptask->hdr, dg_size, dgl);
 
 	/* Add the encapsulation header to the fragment */
 	tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
@@ -1737,7 +1637,7 @@ #endif
 		goto fail;
 
 	netif_wake_queue(dev);
-	return 0;
+	return NETDEV_TX_OK;
 fail:
 	if (ptask)
 		kmem_cache_free(packet_task_cache, ptask);
@@ -1745,40 +1645,56 @@ fail:
 	if (skb != NULL)
 		dev_kfree_skb(skb);
 
-	spin_lock_irqsave (&priv->lock, flags);
+	spin_lock_irqsave(&priv->lock, flags);
 	priv->stats.tx_dropped++;
 	priv->stats.tx_errors++;
-	spin_unlock_irqrestore (&priv->lock, flags);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (netif_queue_stopped(dev))
 		netif_wake_queue(dev);
 
-	return 0;  /* returning non-zero causes serious problems */
+	/*
+	 * FIXME: According to a patch from 2003-02-26, "returning non-zero
+	 * causes serious problems" here, allegedly.  Before that patch,
+	 * -ERRNO was returned which is not appropriate under Linux 2.6.
+	 * Perhaps more needs to be done?  Stop the queue in serious
+	 * conditions and restart it elsewhere?
+	 */
+	/* return NETDEV_TX_BUSY; */
+	return NETDEV_TX_OK;
 }
 
-static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static void ether1394_get_drvinfo(struct net_device *dev,
+				  struct ethtool_drvinfo *info)
 {
-	strcpy (info->driver, driver_name);
-	/* FIXME XXX provide sane businfo */
-	strcpy (info->bus_info, "ieee1394");
+	strcpy(info->driver, driver_name);
+	strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
 }
 
 static struct ethtool_ops ethtool_ops = {
 	.get_drvinfo = ether1394_get_drvinfo
 };
 
-static int __init ether1394_init_module (void)
+static int __init ether1394_init_module(void)
 {
-	packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task),
+	int err;
+
+	packet_task_cache = kmem_cache_create("packet_task",
+					      sizeof(struct packet_task),
 					      0, 0, NULL, NULL);
+	if (!packet_task_cache)
+		return -ENOMEM;
 
-	/* Register ourselves as a highlevel driver */
 	hpsb_register_highlevel(&eth1394_highlevel);
-
-	return hpsb_register_protocol(&eth1394_proto_driver);
+	err = hpsb_register_protocol(&eth1394_proto_driver);
+	if (err) {
+		hpsb_unregister_highlevel(&eth1394_highlevel);
+		kmem_cache_destroy(packet_task_cache);
+	}
+	return err;
 }
 
-static void __exit ether1394_exit_module (void)
+static void __exit ether1394_exit_module(void)
 {
 	hpsb_unregister_protocol(&eth1394_proto_driver);
 	hpsb_unregister_highlevel(&eth1394_highlevel);
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
index c45cbff..a3439ee 100644
--- a/drivers/ieee1394/eth1394.h
+++ b/drivers/ieee1394/eth1394.h
@@ -25,8 +25,11 @@ #ifndef __ETH1394_H
 #define __ETH1394_H
 
 #include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <asm/byteorder.h>
 
 #include "ieee1394.h"
+#include "ieee1394_types.h"
 
 /* Register for incoming packets. This is 4096 bytes, which supports up to
  * S3200 (per Table 16-3 of IEEE 1394b-2002). */
@@ -34,22 +37,15 @@ #define ETHER1394_REGION_ADDR_LEN	4096
 
 /* GASP identifier numbers for IPv4 over IEEE 1394 */
 #define ETHER1394_GASP_SPECIFIER_ID	0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI	((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO	(ETHER1394_GASP_SPECIFIER_ID & 0xff)
+#define ETHER1394_GASP_SPECIFIER_ID_HI	((0x00005E >> 8) & 0xffff)
+#define ETHER1394_GASP_SPECIFIER_ID_LO	(0x00005E & 0xff)
 #define ETHER1394_GASP_VERSION		1
 
-#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t))  /* GASP header overhead */
+#define ETHER1394_GASP_OVERHEAD	(2 * sizeof(quadlet_t))	/* for GASP header */
 
-#define ETHER1394_GASP_BUFFERS 16
+#define ETHER1394_GASP_BUFFERS	16
 
-/* rawiso buffer size - due to a limitation in rawiso, we must limit each
- * GASP buffer to be less than PAGE_SIZE. */
-#define ETHER1394_ISO_BUF_SIZE	ETHER1394_GASP_BUFFERS *                        \
-				   min((unsigned int)PAGE_SIZE,                 \
-				       2 * (1U << (priv->host->csr.max_rec + 1)))
-
-/* Node set == 64 */
-#define NODE_SET			(ALL_NODES + 1)
+#define NODE_SET		(ALL_NODES + 1)		/* Node set == 64 */
 
 enum eth1394_bc_states { ETHER1394_BC_ERROR,
 			 ETHER1394_BC_RUNNING,
@@ -85,19 +81,14 @@ struct eth1394hdr {
 	unsigned short	h_proto;		/* packet type ID field	*/
 }  __attribute__((packed));
 
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
 static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
 {
-	return (struct eth1394hdr *)skb->mac.raw;
+	return (struct eth1394hdr *)skb_mac_header(skb);
 }
-#endif
 
 typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
 
 /* IP1394 headers */
-#include <asm/byteorder.h>
 
 /* Unfragmented */
 #if defined __BIG_ENDIAN_BITFIELD
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 694da82..83a4933 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -70,8 +70,12 @@ static struct hl_host_info *hl_get_hosti
 	return NULL;
 }
 
-/* Returns a per host/driver data structure that was previously stored by
- * hpsb_create_hostinfo. */
+/**
+ * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
+ *
+ * Returns a per @host and @hl driver data structure that was previously stored
+ * by hpsb_create_hostinfo.
+ */
 void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
 {
 	struct hl_host_info *hi = hl_get_hostinfo(hl, host);
@@ -79,7 +83,13 @@ void *hpsb_get_hostinfo(struct hpsb_high
 	return hi ? hi->data : NULL;
 }
 
-/* If size is zero, then the return here is only valid for error checking */
+/**
+ * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
+ *
+ * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
+ * to this @hl driver and @host.  If @data_size is zero, then the return here is
+ * only valid for error checking.
+ */
 void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			   size_t data_size)
 {
@@ -113,6 +123,11 @@ void *hpsb_create_hostinfo(struct hpsb_h
 	return data;
 }
 
+/**
+ * hpsb_set_hostinfo - 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)
 {
@@ -132,6 +147,11 @@ int hpsb_set_hostinfo(struct hpsb_highle
 	return -EINVAL;
 }
 
+/**
+ * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
+ *
+ * Free and remove the hostinfo pointer bound to this @hl driver and @host.
+ */
 void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
 {
 	struct hl_host_info *hi;
@@ -147,6 +167,12 @@ void hpsb_destroy_hostinfo(struct hpsb_h
 	return;
 }
 
+/**
+ * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
+ *
+ * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
+ * @host.
+ */
 void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			   unsigned long key)
 {
@@ -158,6 +184,9 @@ void hpsb_set_hostinfo_key(struct hpsb_h
 	return;
 }
 
+/**
+ * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
+ */
 void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
 {
 	struct hl_host_info *hi;
@@ -189,6 +218,12 @@ static int highlevel_for_each_host_reg(s
 	return 0;
 }
 
+/**
+ * hpsb_register_highlevel - register highlevel driver
+ *
+ * The name pointer in @hl has to stay valid at all times because the string is
+ * not copied.
+ */
 void hpsb_register_highlevel(struct hpsb_highlevel *hl)
 {
 	unsigned long flags;
@@ -258,6 +293,9 @@ static int highlevel_for_each_host_unreg
 	return 0;
 }
 
+/**
+ * hpsb_unregister_highlevel - unregister highlevel driver
+ */
 void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
 {
 	unsigned long flags;
@@ -273,6 +311,19 @@ void hpsb_unregister_highlevel(struct hp
 	nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
 }
 
+/**
+ * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
+ *
+ * @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 @hl 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.  Address spaces can be
+ * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
+ * are automatically deallocated together with the hpsb_highlevel @hl.
+ */
 u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
 					 struct hpsb_host *host,
 					 struct hpsb_address_ops *ops,
@@ -348,6 +399,19 @@ u64 hpsb_allocate_and_register_addrspace
 	return retval;
 }
 
+/**
+ * hpsb_register_addrspace - register a host address space
+ *
+ * @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 @hl 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.  Address spaces can be
+ * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
+ * are automatically deallocated together with the hpsb_highlevel @hl.
+ */
 int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			    struct hpsb_address_ops *ops, u64 start, u64 end)
 {
@@ -419,6 +483,11 @@ int hpsb_unregister_addrspace(struct hps
 	return retval;
 }
 
+/**
+ * hpsb_listen_channel - enable receving a certain isochronous channel
+ *
+ * Reception is handled through the @hl's iso_receive op.
+ */
 int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			unsigned int channel)
 {
@@ -431,6 +500,9 @@ int hpsb_listen_channel(struct hpsb_high
 	return 0;
 }
 
+/**
+ * hpsb_unlisten_channel - disable receving a certain isochronous channel
+ */
 void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			   unsigned int channel)
 {
@@ -528,6 +600,17 @@ void highlevel_fcp_request(struct hpsb_h
 	read_unlock_irqrestore(&hl_irqs_lock, flags);
 }
 
+/*
+ * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
+ *
+ * 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)
 {
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index 4b33011..63474f7 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -99,16 +99,6 @@ struct hpsb_address_ops {
 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 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,
@@ -119,30 +109,13 @@ int highlevel_lock(struct hpsb_host *hos
 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);
-
 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);
 
-/*
- * Register highlevel driver.  The name pointer has to stay valid at all times
- * because the string is not copied.
- */
 void hpsb_register_highlevel(struct hpsb_highlevel *hl);
 void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
 
-/*
- * Register handlers for host address spaces.  Start and end are 48 bit pointers
- * 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.  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,
 					 struct hpsb_address_ops *ops,
@@ -152,45 +125,19 @@ int hpsb_register_addrspace(struct hpsb_
 			    struct hpsb_address_ops *ops, u64 start, u64 end);
 int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			      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);
 
-/* Retrieve a hostinfo pointer bound to this driver/host */
 void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-
-/* Allocate a hostinfo pointer of data_size bound to this driver/host */
 void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
 			   size_t data_size);
-
-/* Free and remove the hostinfo pointer bound to this driver/host */
 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);
-
-/* 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);
 
-/* Retrieve hpsb_host using a highlevel handle and a 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 32a1309..bd0755c 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -15,7 +15,6 @@ #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/timer.h>
 #include <linux/jiffies.h>
 #include <linux/mutex.h>
@@ -94,14 +93,6 @@ 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);
 
 /**
@@ -137,9 +128,7 @@ struct hpsb_host *hpsb_alloc_host(struct
 	h->hostdata = h + 1;
 	h->driver = drv;
 
-	skb_queue_head_init(&h->pending_packet_queue);
-	lockdep_set_class(&h->pending_packet_queue.lock,
-			   &pending_packet_queue_key);
+	INIT_LIST_HEAD(&h->pending_packets);
 	INIT_LIST_HEAD(&h->addr_space);
 
 	for (i = 2; i < 16; i++)
@@ -190,7 +179,7 @@ int hpsb_add_host(struct hpsb_host *host
 {
 	if (hpsb_default_host_entry(host))
 		return -ENOMEM;
-	hpsb_add_extra_config_roms(host);
+
 	highlevel_add_host(host);
 	return 0;
 }
@@ -212,12 +201,19 @@ void hpsb_remove_host(struct hpsb_host *
 
 	host->driver = &dummy_driver;
 	highlevel_remove_host(host);
-	hpsb_remove_extra_config_roms(host);
 
 	class_device_unregister(&host->class_dev);
 	device_unregister(&host->device);
 }
 
+/**
+ * hpsb_update_config_rom_image - updates configuration ROM image of a host
+ *
+ * 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.
+ * Return value 0 indicates success.
+ */
 int hpsb_update_config_rom_image(struct hpsb_host *host)
 {
 	unsigned long reset_delay;
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index 4bf4fb7..feb55d0 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -3,7 +3,6 @@ #define _IEEE1394_HOSTS_H
 
 #include <linux/device.h>
 #include <linux/list.h>
-#include <linux/skbuff.h>
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
@@ -25,8 +24,7 @@ struct hpsb_host {
 
 	atomic_t generation;
 
-	struct sk_buff_head pending_packet_queue;
-
+	struct list_head pending_packets;
 	struct timer_list timeout;
 	unsigned long timeout_interval;
 
@@ -202,12 +200,6 @@ struct hpsb_host *hpsb_alloc_host(struct
 int hpsb_add_host(struct hpsb_host *host);
 void hpsb_resume_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *host);
-
-/* 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.
- * Return value 0 indicates success.
- */
 int hpsb_update_config_rom_image(struct hpsb_host *host);
 
 #endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index d791d08..8f71b6a 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -30,7 +30,6 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/bitops.h>
 #include <linux/kdev_t.h>
-#include <linux/skbuff.h>
 #include <linux/suspend.h>
 #include <linux/kthread.h>
 #include <linux/preempt.h>
@@ -96,13 +95,15 @@ static void queue_packet_complete(struct
 
 
 /**
- * hpsb_set_packet_complete_task - set the task that runs when a packet
- * completes. You cannot call this more than once on a single packet
- * before it is sent.
- *
+ * hpsb_set_packet_complete_task - set task that runs when a packet completes
  * @packet: the packet whose completion we want the task added to
  * @routine: function to call
  * @data: data (if any) to pass to the above function
+ *
+ * Set the task that runs when a packet completes. You cannot call this more
+ * than once on a single packet before it is sent.
+ *
+ * Typically, the complete @routine is responsible to call hpsb_free_packet().
  */
 void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
 				   void (*routine)(void *), void *data)
@@ -115,12 +116,12 @@ void hpsb_set_packet_complete_task(struc
 
 /**
  * hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated
+ * @data_size: size of the data block to be allocated, in bytes
  *
  * This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context.  A header block is always included, its
- * size is big enough to contain all possible 1394 headers.  The data block is
- * only allocated when @data_size is not zero.
+ * It can be used in interrupt context.  A header block is always included and
+ * initialized with zeros.  Its size is big enough to contain all possible 1394
+ * headers.  The data block is only allocated if @data_size is not zero.
  *
  * For packets for which responses will be received the @data_size has to be big
  * enough to contain the response's data block since no further allocation
@@ -135,50 +136,49 @@ void hpsb_set_packet_complete_task(struc
  */
 struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
 {
-	struct hpsb_packet *packet = NULL;
-	struct sk_buff *skb;
+	struct hpsb_packet *packet;
 
 	data_size = ((data_size + 3) & ~3);
 
-	skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC);
-	if (skb == NULL)
+	packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
+	if (!packet)
 		return NULL;
 
-	memset(skb->data, 0, data_size + sizeof(*packet));
-
-	packet = (struct hpsb_packet *)skb->data;
-	packet->skb = skb;
-
-	packet->header = packet->embedded_header;
 	packet->state = hpsb_unused;
 	packet->generation = -1;
 	INIT_LIST_HEAD(&packet->driver_list);
+	INIT_LIST_HEAD(&packet->queue);
 	atomic_set(&packet->refcnt, 1);
 
 	if (data_size) {
-		packet->data = (quadlet_t *)(skb->data + sizeof(*packet));
-		packet->data_size = data_size;
+		packet->data = packet->embedded_data;
+		packet->allocated_data_size = data_size;
 	}
-
 	return packet;
 }
 
-
 /**
  * hpsb_free_packet - free packet and data associated with it
  * @packet: packet to free (is NULL safe)
  *
- * This function will free packet->data and finally the packet itself.
+ * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
  */
 void hpsb_free_packet(struct hpsb_packet *packet)
 {
 	if (packet && atomic_dec_and_test(&packet->refcnt)) {
-		BUG_ON(!list_empty(&packet->driver_list));
-		kfree_skb(packet->skb);
+		BUG_ON(!list_empty(&packet->driver_list) ||
+		       !list_empty(&packet->queue));
+		kfree(packet);
 	}
 }
 
-
+/**
+ * hpsb_reset_bus - initiate bus reset on the given host
+ * @host: host controller whose bus to reset
+ * @type: one of enum reset_types
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
 int hpsb_reset_bus(struct hpsb_host *host, int type)
 {
 	if (!host->in_bus_reset) {
@@ -229,6 +229,14 @@ int hpsb_read_cycle_timer(struct hpsb_ho
 	return 0;
 }
 
+/**
+ * hpsb_bus_reset - notify a bus reset to the core
+ *
+ * For host driver module usage.  Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
 int hpsb_bus_reset(struct hpsb_host *host)
 {
 	if (host->in_bus_reset) {
@@ -405,6 +413,14 @@ #endif
 }
 
 
+/**
+ * hpsb_selfid_received - hand over received selfid packet to the core
+ *
+ * For host driver module usage.  Safe to use in interrupt context.
+ *
+ * The host driver should have done a successful complement check (second
+ * quadlet is complement of first) beforehand.
+ */
 void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
 {
 	if (host->in_bus_reset) {
@@ -416,6 +432,15 @@ void hpsb_selfid_received(struct hpsb_ho
 	}
 }
 
+/**
+ * hpsb_selfid_complete - notify completion of SelfID stage to the core
+ *
+ * For host driver module usage.  Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Notify completion of SelfID stage to the core and report new physical ID
+ * and whether host is root now.
+ */
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
 {
 	if (!host->in_bus_reset)
@@ -462,30 +487,41 @@ void hpsb_selfid_complete(struct hpsb_ho
 	highlevel_host_reset(host);
 }
 
+static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED;
 
+/**
+ * hpsb_packet_sent - notify core of sending a packet
+ *
+ * For host driver module usage.  Safe to call from within a transmit packet
+ * routine.
+ *
+ * Notify core of sending a packet.  Ackcode is the ack code returned for async
+ * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
+ * for other cases (internal errors that don't justify a panic).
+ */
 void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
 		      int ackcode)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+	spin_lock_irqsave(&pending_packets_lock, flags);
 
 	packet->ack_code = ackcode;
 
 	if (packet->no_waiter || packet->state == hpsb_complete) {
 		/* if packet->no_waiter, must not have a tlabel allocated */
-		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+		spin_unlock_irqrestore(&pending_packets_lock, flags);
 		hpsb_free_packet(packet);
 		return;
 	}
 
 	atomic_dec(&packet->refcnt);	/* drop HC's reference */
-	/* here the packet must be on the host->pending_packet_queue */
+	/* here the packet must be on the host->pending_packets queue */
 
 	if (ackcode != ACK_PENDING || !packet->expect_response) {
 		packet->state = hpsb_complete;
-		__skb_unlink(packet->skb, &host->pending_packet_queue);
-		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+		list_del_init(&packet->queue);
+		spin_unlock_irqrestore(&pending_packets_lock, flags);
 		queue_packet_complete(packet);
 		return;
 	}
@@ -493,7 +529,7 @@ void hpsb_packet_sent(struct hpsb_host *
 	packet->state = hpsb_pending;
 	packet->sendtime = jiffies;
 
-	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
 
 	mod_timer(&host->timeout, jiffies + host->timeout_interval);
 }
@@ -504,9 +540,10 @@ void hpsb_packet_sent(struct hpsb_host *
  * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
  * @gapcnt: gap count value to set (-1 = don't set gap count)
  *
- * This function sends a PHY config packet on the bus through the specified host.
+ * This function sends a PHY config packet on the bus through the specified
+ * host.
  *
- * Return value: 0 for success or error number otherwise.
+ * Return value: 0 for success or negative error number otherwise.
  */
 int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
 {
@@ -567,12 +604,16 @@ int hpsb_send_packet(struct hpsb_packet 
 	WARN_ON(packet->no_waiter && packet->expect_response);
 
 	if (!packet->no_waiter || packet->expect_response) {
+		unsigned long flags;
+
 		atomic_inc(&packet->refcnt);
 		/* Set the initial "sendtime" to 10 seconds from now, to
 		   prevent premature expiry.  If a packet takes more than
 		   10 seconds to hit the wire, we have bigger problems :) */
 		packet->sendtime = jiffies + 10 * HZ;
-		skb_queue_tail(&host->pending_packet_queue, packet->skb);
+		spin_lock_irqsave(&pending_packets_lock, flags);
+		list_add_tail(&packet->queue, &host->pending_packets);
+		spin_unlock_irqrestore(&pending_packets_lock, flags);
 	}
 
 	if (packet->node_id == host->node_id) {
@@ -621,6 +662,12 @@ static void complete_packet(void *data)
 	complete((struct completion *) data);
 }
 
+/**
+ * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
+ * @packet: packet to send
+ *
+ * Return value: 0 on success, negative errno on failure.
+ */
 int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
 {
 	struct completion done;
@@ -642,86 +689,97 @@ static void send_packet_nocare(struct hp
 	}
 }
 
+static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
+				       size_t buffer_size, int tcode)
+{
+	size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
+
+	if (unlikely(ret > buffer_size))
+		ret = buffer_size;
+
+	if (unlikely(ret + header_size != packet_size))
+		HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
+			 packet_size, tcode);
+	return ret;
+}
 
 static void handle_packet_response(struct hpsb_host *host, int tcode,
 				   quadlet_t *data, size_t size)
 {
-	struct hpsb_packet *packet = NULL;
-	struct sk_buff *skb;
-	int tcode_match = 0;
-	int tlabel;
+	struct hpsb_packet *packet;
+	int tlabel = (data[0] >> 10) & 0x3f;
+	size_t header_size;
 	unsigned long flags;
 
-	tlabel = (data[0] >> 10) & 0x3f;
-
-	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+	spin_lock_irqsave(&pending_packets_lock, flags);
 
-	skb_queue_walk(&host->pending_packet_queue, skb) {
-		packet = (struct hpsb_packet *)skb->data;
-		if ((packet->tlabel == tlabel)
-		    && (packet->node_id == (data[1] >> 16))){
-			break;
-		}
-
-		packet = NULL;
-	}
+	list_for_each_entry(packet, &host->pending_packets, queue)
+		if (packet->tlabel == tlabel &&
+		    packet->node_id == (data[1] >> 16))
+			goto found;
 
-	if (packet == NULL) {
-		HPSB_DEBUG("unsolicited response packet received - no tlabel match");
-		dump_packet("contents", data, 16, -1);
-		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
-		return;
-	}
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
+	HPSB_DEBUG("unsolicited response packet received - %s",
+		   "no tlabel match");
+	dump_packet("contents", data, 16, -1);
+	return;
 
+found:
 	switch (packet->tcode) {
 	case TCODE_WRITEQ:
 	case TCODE_WRITEB:
-		if (tcode != TCODE_WRITE_RESPONSE)
+		if (unlikely(tcode != TCODE_WRITE_RESPONSE))
 			break;
-		tcode_match = 1;
-		memcpy(packet->header, data, 12);
-		break;
+		header_size = 12;
+		size = 0;
+		goto dequeue;
+
 	case TCODE_READQ:
-		if (tcode != TCODE_READQ_RESPONSE)
+		if (unlikely(tcode != TCODE_READQ_RESPONSE))
 			break;
-		tcode_match = 1;
-		memcpy(packet->header, data, 16);
-		break;
+		header_size = 16;
+		size = 0;
+		goto dequeue;
+
 	case TCODE_READB:
-		if (tcode != TCODE_READB_RESPONSE)
+		if (unlikely(tcode != TCODE_READB_RESPONSE))
 			break;
-		tcode_match = 1;
-		BUG_ON(packet->skb->len - sizeof(*packet) < size - 16);
-		memcpy(packet->header, data, 16);
-		memcpy(packet->data, data + 4, size - 16);
-		break;
+		header_size = 16;
+		size = packet_size_to_data_size(size, header_size,
+						packet->allocated_data_size,
+						tcode);
+		goto dequeue;
+
 	case TCODE_LOCK_REQUEST:
-		if (tcode != TCODE_LOCK_RESPONSE)
+		if (unlikely(tcode != TCODE_LOCK_RESPONSE))
 			break;
-		tcode_match = 1;
-		size = min((size - 16), (size_t)8);
-		BUG_ON(packet->skb->len - sizeof(*packet) < size);
-		memcpy(packet->header, data, 16);
-		memcpy(packet->data, data + 4, size);
-		break;
+		header_size = 16;
+		size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
+						header_size,
+						packet->allocated_data_size,
+						tcode);
+		goto dequeue;
 	}
 
-	if (!tcode_match) {
-		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
-		HPSB_INFO("unsolicited response packet received - tcode mismatch");
-		dump_packet("contents", data, 16, -1);
-		return;
-	}
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
+	HPSB_DEBUG("unsolicited response packet received - %s",
+		   "tcode mismatch");
+	dump_packet("contents", data, 16, -1);
+	return;
 
-	__skb_unlink(skb, &host->pending_packet_queue);
+dequeue:
+	list_del_init(&packet->queue);
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
 
 	if (packet->state == hpsb_queued) {
 		packet->sendtime = jiffies;
 		packet->ack_code = ACK_PENDING;
 	}
-
 	packet->state = hpsb_complete;
-	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+
+	memcpy(packet->header, data, header_size);
+	if (size)
+		memcpy(packet->data, data + 4, size);
 
 	queue_packet_complete(packet);
 }
@@ -735,6 +793,7 @@ static struct hpsb_packet *create_reply_
 	p = hpsb_alloc_packet(dsize);
 	if (unlikely(p == NULL)) {
 		/* FIXME - send data_error response */
+		HPSB_ERR("out of memory, cannot send response packet");
 		return NULL;
 	}
 
@@ -784,7 +843,6 @@ static void fill_async_readblock_resp(st
 static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
 {
 	PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
-	packet->header[2] = 0;
 	packet->header_size = 12;
 	packet->data_size = 0;
 }
@@ -801,12 +859,9 @@ static void fill_async_lock_resp(struct 
 	packet->data_size = length;
 }
 
-#define PREP_REPLY_PACKET(length) \
-		packet = create_reply_packet(host, data, length); \
-		if (packet == NULL) break
-
 static void handle_incoming_packet(struct hpsb_host *host, int tcode,
-				   quadlet_t *data, size_t size, int write_acked)
+				   quadlet_t *data, size_t size,
+				   int write_acked)
 {
 	struct hpsb_packet *packet;
 	int length, rcode, extcode;
@@ -816,74 +871,72 @@ static void handle_incoming_packet(struc
 	u16 flags = (u16) data[0];
 	u64 addr;
 
-	/* big FIXME - no error checking is done for an out of bounds length */
+	/* FIXME?
+	 * Out-of-bounds lengths are left for highlevel_read|write to cap. */
 
 	switch (tcode) {
 	case TCODE_WRITEQ:
 		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_write(host, source, dest, data+3,
+		rcode = highlevel_write(host, source, dest, data + 3,
 					addr, 4, flags);
-
-		if (!write_acked
-		    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
-		    && (rcode >= 0)) {
-			/* not a broadcast write, reply */
-			PREP_REPLY_PACKET(0);
-			fill_async_write_resp(packet, rcode);
-			send_packet_nocare(packet);
-		}
-		break;
+		goto handle_write_request;
 
 	case TCODE_WRITEB:
 		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_write(host, source, dest, data+4,
-					addr, data[3]>>16, flags);
-
-		if (!write_acked
-		    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
-		    && (rcode >= 0)) {
-			/* not a broadcast write, reply */
-			PREP_REPLY_PACKET(0);
+		rcode = highlevel_write(host, source, dest, data + 4,
+					addr, data[3] >> 16, flags);
+handle_write_request:
+		if (rcode < 0 || write_acked ||
+		    NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
+			return;
+		/* not a broadcast write, reply */
+		packet = create_reply_packet(host, data, 0);
+		if (packet) {
 			fill_async_write_resp(packet, rcode);
 			send_packet_nocare(packet);
 		}
-		break;
+		return;
 
 	case TCODE_READQ:
 		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
 		rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+		if (rcode < 0)
+			return;
 
-		if (rcode >= 0) {
-			PREP_REPLY_PACKET(0);
+		packet = create_reply_packet(host, data, 0);
+		if (packet) {
 			fill_async_readquad_resp(packet, rcode, buffer);
 			send_packet_nocare(packet);
 		}
-		break;
+		return;
 
 	case TCODE_READB:
 		length = data[3] >> 16;
-		PREP_REPLY_PACKET(length);
+		packet = create_reply_packet(host, data, length);
+		if (!packet)
+			return;
 
 		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
 		rcode = highlevel_read(host, source, packet->data, addr,
 				       length, flags);
-
-		if (rcode >= 0) {
-			fill_async_readblock_resp(packet, rcode, length);
-			send_packet_nocare(packet);
-		} else {
+		if (rcode < 0) {
 			hpsb_free_packet(packet);
+			return;
 		}
-		break;
+		fill_async_readblock_resp(packet, rcode, length);
+		send_packet_nocare(packet);
+		return;
 
 	case TCODE_LOCK_REQUEST:
 		length = data[3] >> 16;
 		extcode = data[3] & 0xffff;
 		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
 
-		PREP_REPLY_PACKET(8);
+		packet = create_reply_packet(host, data, 8);
+		if (!packet)
+			return;
 
-		if ((extcode == 0) || (extcode >= 7)) {
+		if (extcode == 0 || extcode >= 7) {
 			/* let switch default handle error */
 			length = 0;
 		}
@@ -891,12 +944,12 @@ static void handle_incoming_packet(struc
 		switch (length) {
 		case 4:
 			rcode = highlevel_lock(host, source, packet->data, addr,
-					       data[4], 0, extcode,flags);
+					       data[4], 0, extcode, flags);
 			fill_async_lock_resp(packet, rcode, extcode, 4);
 			break;
 		case 8:
-			if ((extcode != EXTCODE_FETCH_ADD)
-			    && (extcode != EXTCODE_LITTLE_ADD)) {
+			if (extcode != EXTCODE_FETCH_ADD &&
+			    extcode != EXTCODE_LITTLE_ADD) {
 				rcode = highlevel_lock(host, source,
 						       packet->data, addr,
 						       data[5], data[4],
@@ -920,29 +973,38 @@ static void handle_incoming_packet(struc
 			break;
 		default:
 			rcode = RCODE_TYPE_ERROR;
-			fill_async_lock_resp(packet, rcode,
-					     extcode, 0);
+			fill_async_lock_resp(packet, rcode, extcode, 0);
 		}
 
-		if (rcode >= 0) {
-			send_packet_nocare(packet);
-		} else {
+		if (rcode < 0)
 			hpsb_free_packet(packet);
-		}
-		break;
+		else
+			send_packet_nocare(packet);
+		return;
 	}
-
 }
-#undef PREP_REPLY_PACKET
-
 
+/**
+ * hpsb_packet_received - hand over received packet to the core
+ *
+ * For host driver module usage.
+ *
+ * The contents of data are expected to be the full packet but with the CRCs
+ * left out (data block follows header immediately), with the header (i.e. the
+ * first four quadlets) in machine byte order and the data block in big endian.
+ * *@data can be safely overwritten after this call.
+ *
+ * If the packet is a write request, @write_acked is to be set to true if it was
+ * ack_complete'd already, false otherwise.  This argument is ignored for any
+ * other packet type.
+ */
 void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
 			  int write_acked)
 {
 	int tcode;
 
-	if (host->in_bus_reset) {
-		HPSB_INFO("received packet during reset; ignoring");
+	if (unlikely(host->in_bus_reset)) {
+		HPSB_DEBUG("received packet during reset; ignoring");
 		return;
 	}
 
@@ -976,23 +1038,27 @@ void hpsb_packet_received(struct hpsb_ho
 		break;
 
 	default:
-		HPSB_NOTICE("received packet with bogus transaction code %d",
-			    tcode);
+		HPSB_DEBUG("received packet with bogus transaction code %d",
+			   tcode);
 		break;
 	}
 }
 
-
 static void abort_requests(struct hpsb_host *host)
 {
-	struct hpsb_packet *packet;
-	struct sk_buff *skb;
+	struct hpsb_packet *packet, *p;
+	struct list_head tmp;
+	unsigned long flags;
 
 	host->driver->devctl(host, CANCEL_REQUESTS, 0);
 
-	while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) {
-		packet = (struct hpsb_packet *)skb->data;
+	INIT_LIST_HEAD(&tmp);
+	spin_lock_irqsave(&pending_packets_lock, flags);
+	list_splice_init(&host->pending_packets, &tmp);
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
 
+	list_for_each_entry_safe(packet, p, &tmp, queue) {
+		list_del_init(&packet->queue);
 		packet->state = hpsb_complete;
 		packet->ack_code = ACKX_ABORTED;
 		queue_packet_complete(packet);
@@ -1002,87 +1068,90 @@ static void abort_requests(struct hpsb_h
 void abort_timedouts(unsigned long __opaque)
 {
 	struct hpsb_host *host = (struct hpsb_host *)__opaque;
-	unsigned long flags;
-	struct hpsb_packet *packet;
-	struct sk_buff *skb;
-	unsigned long expire;
+	struct hpsb_packet *packet, *p;
+	struct list_head tmp;
+	unsigned long flags, expire, j;
 
 	spin_lock_irqsave(&host->csr.lock, flags);
 	expire = host->csr.expire;
 	spin_unlock_irqrestore(&host->csr.lock, flags);
 
-	/* Hold the lock around this, since we aren't dequeuing all
-	 * packets, just ones we need. */
-	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
-
-	while (!skb_queue_empty(&host->pending_packet_queue)) {
-		skb = skb_peek(&host->pending_packet_queue);
-
-		packet = (struct hpsb_packet *)skb->data;
+	j = jiffies;
+	INIT_LIST_HEAD(&tmp);
+	spin_lock_irqsave(&pending_packets_lock, flags);
 
-		if (time_before(packet->sendtime + expire, jiffies)) {
-			__skb_unlink(skb, &host->pending_packet_queue);
-			packet->state = hpsb_complete;
-			packet->ack_code = ACKX_TIMEOUT;
-			queue_packet_complete(packet);
-		} else {
+	list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
+		if (time_before(packet->sendtime + expire, j))
+			list_move_tail(&packet->queue, &tmp);
+		else
 			/* Since packets are added to the tail, the oldest
 			 * ones are first, always. When we get to one that
 			 * isn't timed out, the rest aren't either. */
 			break;
-		}
 	}
+	if (!list_empty(&host->pending_packets))
+		mod_timer(&host->timeout, j + host->timeout_interval);
 
-	if (!skb_queue_empty(&host->pending_packet_queue))
-		mod_timer(&host->timeout, jiffies + host->timeout_interval);
+	spin_unlock_irqrestore(&pending_packets_lock, flags);
 
-	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+	list_for_each_entry_safe(packet, p, &tmp, queue) {
+		list_del_init(&packet->queue);
+		packet->state = hpsb_complete;
+		packet->ack_code = ACKX_TIMEOUT;
+		queue_packet_complete(packet);
+	}
 }
 
-
-/* Kernel thread and vars, which handles packets that are completed. Only
- * packets that have a "complete" function are sent here. This way, the
- * completion is run out of kernel context, and doesn't block the rest of
- * the stack. */
 static struct task_struct *khpsbpkt_thread;
-static struct sk_buff_head hpsbpkt_queue;
+static LIST_HEAD(hpsbpkt_queue);
 
 static void queue_packet_complete(struct hpsb_packet *packet)
 {
+	unsigned long flags;
+
 	if (packet->no_waiter) {
 		hpsb_free_packet(packet);
 		return;
 	}
 	if (packet->complete_routine != NULL) {
-		skb_queue_tail(&hpsbpkt_queue, packet->skb);
+		spin_lock_irqsave(&pending_packets_lock, flags);
+		list_add_tail(&packet->queue, &hpsbpkt_queue);
+		spin_unlock_irqrestore(&pending_packets_lock, flags);
 		wake_up_process(khpsbpkt_thread);
 	}
 	return;
 }
 
+/*
+ * Kernel thread which handles packets that are completed.  This way the
+ * packet's "complete" function is asynchronously run in process context.
+ * Only packets which have a "complete" function may be sent here.
+ */
 static int hpsbpkt_thread(void *__hi)
 {
-	struct sk_buff *skb;
-	struct hpsb_packet *packet;
-	void (*complete_routine)(void*);
-	void *complete_data;
+	struct hpsb_packet *packet, *p;
+	struct list_head tmp;
+	int may_schedule;
 
 	current->flags |= PF_NOFREEZE;
 
 	while (!kthread_should_stop()) {
-		while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
-			packet = (struct hpsb_packet *)skb->data;
-
-			complete_routine = packet->complete_routine;
-			complete_data = packet->complete_data;
 
-			packet->complete_routine = packet->complete_data = NULL;
+		INIT_LIST_HEAD(&tmp);
+		spin_lock_irq(&pending_packets_lock);
+		list_splice_init(&hpsbpkt_queue, &tmp);
+		spin_unlock_irq(&pending_packets_lock);
 
-			complete_routine(complete_data);
+		list_for_each_entry_safe(packet, p, &tmp, queue) {
+			list_del_init(&packet->queue);
+			packet->complete_routine(packet->complete_data);
 		}
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (!skb_peek(&hpsbpkt_queue))
+		spin_lock_irq(&pending_packets_lock);
+		may_schedule = list_empty(&hpsbpkt_queue);
+		spin_unlock_irq(&pending_packets_lock);
+		if (may_schedule)
 			schedule();
 		__set_current_state(TASK_RUNNING);
 	}
@@ -1093,8 +1162,6 @@ static int __init ieee1394_init(void)
 {
 	int i, ret;
 
-	skb_queue_head_init(&hpsbpkt_queue);
-
 	/* non-fatal error */
 	if (hpsb_init_config_roms()) {
 		HPSB_ERR("Failed to initialize some config rom entries.\n");
@@ -1268,7 +1335,6 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo);
 EXPORT_SYMBOL(hpsb_set_hostinfo_key);
 EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
 EXPORT_SYMBOL(hpsb_set_hostinfo);
-EXPORT_SYMBOL(highlevel_host_reset);
 
 /** nodemgr.c **/
 EXPORT_SYMBOL(hpsb_node_fill_packet);
@@ -1311,11 +1377,10 @@ EXPORT_SYMBOL(hpsb_iso_wake);
 EXPORT_SYMBOL(hpsb_iso_recv_flush);
 
 /** csr1212.c **/
-EXPORT_SYMBOL(csr1212_new_directory);
 EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
 EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_release_keyval);
-EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_get_keyval);
+EXPORT_SYMBOL(csr1212_new_directory);
 EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(_csr1212_read_keyval);
-EXPORT_SYMBOL(_csr1212_destroy_keyval);
+EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_release_keyval);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index bd29d8e..ad52652 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -4,7 +4,6 @@ #define _IEEE1394_CORE_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>
 
@@ -13,7 +12,7 @@ #include "ieee1394_types.h"
 
 struct hpsb_packet {
 	/* This struct is basically read-only for hosts with the exception of
-	 * the data buffer contents and xnext - see below. */
+	 * the data buffer contents and driver_list. */
 
 	/* This can be used for host driver internal linking.
 	 *
@@ -49,134 +48,65 @@ struct hpsb_packet {
 	/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
 	unsigned speed_code:2;
 
-	/*
-	 * *header and *data are guaranteed to be 32-bit DMAable and may be
-	 * overwritten to allow in-place byte swapping.  Neither of these is
-	 * CRCed (the sizes also don't include CRC), but contain space for at
-	 * least one additional quadlet to allow in-place CRCing.  The memory is
-	 * also guaranteed to be DMA mappable.
-	 */
-	quadlet_t *header;
-	quadlet_t *data;
-	size_t header_size;
-	size_t data_size;
-
 	struct hpsb_host *host;
 	unsigned int generation;
 
 	atomic_t refcnt;
+	struct list_head queue;
 
 	/* Function (and possible data to pass to it) to call when this
 	 * packet is completed.  */
 	void (*complete_routine)(void *);
 	void *complete_data;
 
-	/* XXX This is just a hack at the moment */
-	struct sk_buff *skb;
-
 	/* Store jiffies for implementing bus timeouts. */
 	unsigned long sendtime;
 
-	quadlet_t embedded_header[5];
+	/* Sizes are in bytes. *data can be DMA-mapped. */
+	size_t allocated_data_size;	/* as allocated */
+	size_t data_size;		/* as filled in */
+	size_t header_size;		/* as filled in, not counting the CRC */
+	quadlet_t *data;
+	quadlet_t header[5];
+	quadlet_t embedded_data[0];	/* keep as last member */
 };
 
-/* Set a task for when a packet completes */
 void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
 				   void (*routine)(void *), void *data);
-
 static inline struct hpsb_packet *driver_packet(struct list_head *l)
 {
 	return list_entry(l, struct hpsb_packet, driver_list);
 }
-
 void abort_timedouts(unsigned long __opaque);
-
 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).
+/**
+ * get_hpsb_generation - generation counter for the complete 1394 subsystem
  *
- * Use the functions, not the variable.
+ * Generation gets incremented on every change in the subsystem (notably on bus
+ * resets). Use the functions, not the variable.
  */
 static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
 {
 	return atomic_read(&host->generation);
 }
 
-/*
- * Send a PHY configuration packet, return 0 on success, negative
- * errno on failure.
- */
 int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-
-/*
- * Queue packet for transmitting, return 0 on success, negative errno
- * on failure.
- */
 int hpsb_send_packet(struct hpsb_packet *packet);
-
-/*
- * Queue packet for transmitting, and block until the transaction
- * completes. Return 0 on success, negative errno on failure.
- */
 int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-
-/* Initiate bus reset on the given host.  Returns 1 if bus reset already in
- * progress, 0 otherwise. */
 int hpsb_reset_bus(struct hpsb_host *host, int type);
-
 int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
 			  u64 *local_time);
 
-/*
- * The following functions are exported for host driver module usage.  All of
- * them are safe to use in interrupt contexts, although some are quite
- * complicated so you may want to run them in bottom halves instead of calling
- * them directly.
- */
-
-/* Notify a bus reset to the core.  Returns 1 if bus reset already in progress,
- * 0 otherwise. */
 int hpsb_bus_reset(struct hpsb_host *host);
-
-/*
- * Hand over received selfid packet to the core.  Complement check (second
- * quadlet is complement of first) is expected to be done and successful.
- */
 void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-
-/*
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
 void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-
-/*
- * Notify core of sending a packet.  Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic).  Safe to call
- * from within a transmit packet routine.
- */
 void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
 		      int ackcode);
-
-/*
- * Hand over received packet to the core.  The contents of data are expected to
- * be the full packet but with the CRCs left out (data block follows header
- * immediately), with the header (i.e. the first four quadlets) in machine byte
- * order and the data block in big endian.  *data can be safely overwritten
- * after this call.
- *
- * If the packet is a write request, write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise.  This arg is ignored for any other
- * packet type.
- */
 void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
 			  int write_acked);
 
-
 /*
  * CHARACTER DEVICE DISPATCHING
  *
@@ -217,7 +147,9 @@ #define IEEE1394_DV1394_DEV	  MKDEV(IEEE
 #define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
 					IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
 
-/* return the index (within a minor number block) of a file */
+/**
+ * ieee1394_file_to_instance - get the index within a minor number block
+ */
 static inline unsigned char ieee1394_file_to_instance(struct file *file)
 {
 	return file->f_path.dentry->d_inode->i_cindex;
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index 0833fc9..40078ce 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -10,11 +10,16 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/hardirq.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sched.h>  /* because linux/wait.h is broken if CONFIG_SMP=n */
 #include <linux/wait.h>
 
 #include <asm/bug.h>
 #include <asm/errno.h>
+#include <asm/system.h>
 
 #include "ieee1394.h"
 #include "ieee1394_types.h"
@@ -32,7 +37,7 @@ #define PREP_ASYNC_HEAD_ADDRESS(tc) \
 #ifndef HPSB_DEBUG_TLABELS
 static
 #endif
-spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(hpsb_tlabel_lock);
 
 static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
 
@@ -212,6 +217,15 @@ void hpsb_free_tlabel(struct hpsb_packet
 	wake_up_interruptible(&tlabel_wq);
 }
 
+/**
+ * hpsb_packet_success - Make sense of the ack and reply codes
+ *
+ * Make sense of the ack and reply codes and return more convenient error codes:
+ * 0 = success.  -%EBUSY = node is busy, try again.  -%EAGAIN = error which can
+ * probably resolved by retry.  -%EREMOTEIO = node suffers from an internal
+ * error.  -%EACCES = this transaction is not allowed on requested address.
+ * -%EINVAL = invalid address at node.
+ */
 int hpsb_packet_success(struct hpsb_packet *packet)
 {
 	switch (packet->ack_code) {
@@ -364,6 +378,13 @@ struct hpsb_packet *hpsb_make_streampack
 	}
 	packet->host = host;
 
+	/* Because it is too difficult to determine all PHY speeds and link
+	 * speeds here, we use S100... */
+	packet->speed_code = IEEE1394_SPEED_100;
+
+	/* ...and prevent hpsb_send_packet() from overriding it. */
+	packet->node_id = LOCAL_BUS | ALL_NODES;
+
 	if (hpsb_get_tlabel(packet)) {
 		hpsb_free_packet(packet);
 		return NULL;
@@ -493,6 +514,16 @@ struct hpsb_packet *hpsb_make_isopacket(
  * avoid in kernel buffers for user space callers
  */
 
+/**
+ * hpsb_read - generic read function
+ *
+ * Recognizes the local node ID and act accordingly.  Automatically uses a
+ * quadlet read request if @length == 4 and and a block read request otherwise.
+ * It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
 int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	      u64 addr, quadlet_t * buffer, size_t length)
 {
@@ -532,6 +563,16 @@ int hpsb_read(struct hpsb_host *host, no
 	return retval;
 }
 
+/**
+ * hpsb_write - generic write function
+ *
+ * Recognizes the local node ID and act accordingly.  Automatically uses a
+ * quadlet write request if @length == 4 and and a block write request
+ * otherwise.  It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	       u64 addr, quadlet_t * buffer, size_t length)
 {
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
index c1369c4..86b8ee6 100644
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -27,27 +27,7 @@ struct hpsb_packet *hpsb_make_writepacke
 struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
                                            int length, int channel, int tag,
 					   int sync);
-
-/*
- * hpsb_packet_success - Make sense of the ack and reply codes and
- * return more convenient error codes:
- * 0           success
- * -EBUSY      node is busy, try again
- * -EAGAIN     error which can probably resolved by retry
- * -EREMOTEIO  node suffers from an internal error
- * -EACCES     this transaction is not allowed on requested address
- * -EINVAL     invalid address at node
- */
 int hpsb_packet_success(struct hpsb_packet *packet);
-
-/*
- * 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
- * the generation for which the node ID is valid, to avoid sending packets to
- * the wrong nodes when we race with a bus reset.
- */
 int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 	      u64 addr, quadlet_t *buffer, size_t length);
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index c6227e5..07ca35c 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -10,11 +10,15 @@
  */
 
 #include <linux/pci.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 
 #include "hosts.h"
 #include "iso.h"
 
+/**
+ * hpsb_iso_stop - stop DMA
+ */
 void hpsb_iso_stop(struct hpsb_iso *iso)
 {
 	if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
@@ -25,6 +29,9 @@ void hpsb_iso_stop(struct hpsb_iso *iso)
 	iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
 }
 
+/**
+ * hpsb_iso_shutdown - deallocate buffer and DMA context
+ */
 void hpsb_iso_shutdown(struct hpsb_iso *iso)
 {
 	if (iso->flags & HPSB_ISO_DRIVER_INIT) {
@@ -130,6 +137,9 @@ static struct hpsb_iso *hpsb_iso_common_
 	return NULL;
 }
 
+/**
+ * hpsb_iso_n_ready - returns number of packets ready to send or receive
+ */
 int hpsb_iso_n_ready(struct hpsb_iso *iso)
 {
 	unsigned long flags;
@@ -142,6 +152,9 @@ int hpsb_iso_n_ready(struct hpsb_iso *is
 	return val;
 }
 
+/**
+ * hpsb_iso_xmit_init - allocate the buffer and DMA context
+ */
 struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
 				    unsigned int data_buf_size,
 				    unsigned int buf_packets,
@@ -172,6 +185,11 @@ struct hpsb_iso *hpsb_iso_xmit_init(stru
 	return NULL;
 }
 
+/**
+ * hpsb_iso_recv_init - allocate the buffer and DMA context
+ *
+ * Note, if channel = -1, multi-channel receive is enabled.
+ */
 struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
 				    unsigned int data_buf_size,
 				    unsigned int buf_packets,
@@ -199,6 +217,11 @@ struct hpsb_iso *hpsb_iso_recv_init(stru
 	return NULL;
 }
 
+/**
+ * hpsb_iso_recv_listen_channel
+ *
+ * multi-channel only
+ */
 int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
 {
 	if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
@@ -206,6 +229,11 @@ int hpsb_iso_recv_listen_channel(struct 
 	return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
 }
 
+/**
+ * hpsb_iso_recv_unlisten_channel
+ *
+ * multi-channel only
+ */
 int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
 {
 	if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
@@ -213,6 +241,11 @@ int hpsb_iso_recv_unlisten_channel(struc
 	return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
 }
 
+/**
+ * hpsb_iso_recv_set_channel_mask
+ *
+ * multi-channel only
+ */
 int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
 {
 	if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
@@ -221,6 +254,12 @@ int hpsb_iso_recv_set_channel_mask(struc
 					 (unsigned long)&mask);
 }
 
+/**
+ * hpsb_iso_recv_flush - check for arrival of new packets
+ *
+ * check for arrival of new packets immediately (even if irq_interval
+ * has not yet been reached)
+ */
 int hpsb_iso_recv_flush(struct hpsb_iso *iso)
 {
 	if (iso->type != HPSB_ISO_RECV)
@@ -238,6 +277,9 @@ static int do_iso_xmit_start(struct hpsb
 	return retval;
 }
 
+/**
+ * hpsb_iso_xmit_start - start DMA
+ */
 int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
 {
 	if (iso->type != HPSB_ISO_XMIT)
@@ -270,6 +312,9 @@ int hpsb_iso_xmit_start(struct hpsb_iso 
 	return 0;
 }
 
+/**
+ * hpsb_iso_recv_start - start DMA
+ */
 int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
 {
 	int retval = 0;
@@ -306,8 +351,7 @@ int hpsb_iso_recv_start(struct hpsb_iso 
 }
 
 /* check to make sure the user has not supplied bogus values of offset/len
-   that would cause the kernel to access memory outside the buffer */
-
+ * that would cause the kernel to access memory outside the buffer */
 static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
 				     unsigned int offset, unsigned short len,
 				     unsigned int *out_offset,
@@ -331,6 +375,12 @@ static int hpsb_iso_check_offset_len(str
 	return 0;
 }
 
+/**
+ * hpsb_iso_xmit_queue_packet - 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)
 {
@@ -380,6 +430,9 @@ int hpsb_iso_xmit_queue_packet(struct hp
 	return rv;
 }
 
+/**
+ * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
+ */
 int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
 {
 	if (iso->type != HPSB_ISO_XMIT)
@@ -390,6 +443,15 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *
 					iso->buf_packets);
 }
 
+/**
+ * hpsb_iso_packet_sent
+ *
+ * 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.
+ */
 void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
 {
 	unsigned long flags;
@@ -413,6 +475,13 @@ void hpsb_iso_packet_sent(struct hpsb_is
 	spin_unlock_irqrestore(&iso->lock, flags);
 }
 
+/**
+ * hpsb_iso_packet_received
+ *
+ * Available to low-level drivers.
+ *
+ * Call after a packet has been received (interrupt context is 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)
@@ -442,6 +511,11 @@ void hpsb_iso_packet_received(struct hps
 	spin_unlock_irqrestore(&iso->lock, flags);
 }
 
+/**
+ * hpsb_iso_recv_release_packets - release packets, reuse buffer
+ *
+ * @n_packets have been read out of the buffer, re-use the buffer space
+ */
 int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
 {
 	unsigned long flags;
@@ -477,6 +551,13 @@ int hpsb_iso_recv_release_packets(struct
 	return rv;
 }
 
+/**
+ * hpsb_iso_wake
+ *
+ * Available to low-level drivers.
+ *
+ * Call to wake waiting processes after buffer space has opened up.
+ */
 void hpsb_iso_wake(struct hpsb_iso *iso)
 {
 	wake_up_interruptible(&iso->waitq);
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index 1210a97..b94e55e 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -150,8 +150,6 @@ #define HPSB_ISO_DRIVER_STARTED  (1<<1)
 
 /* functions available to high-level drivers (e.g. raw1394) */
 
-/* allocate the buffer and DMA context */
-
 struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
 				    unsigned int data_buf_size,
 				    unsigned int buf_packets,
@@ -159,8 +157,6 @@ struct hpsb_iso* hpsb_iso_xmit_init(stru
 				    int speed,
 				    int irq_interval,
 				    void (*callback)(struct hpsb_iso*));
-
-/* note: if channel = -1, multi-channel receive is enabled */
 struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
 				    unsigned int data_buf_size,
 				    unsigned int buf_packets,
@@ -168,56 +164,29 @@ struct hpsb_iso* hpsb_iso_recv_init(stru
 				    int dma_mode,
 				    int irq_interval,
 				    void (*callback)(struct hpsb_iso*));
-
-/* multi-channel only */
 int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
 int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
 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);
 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);
-
-/* 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);
-
-/* check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached) */
+int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
+				  unsigned int n_packets);
 int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-
-/* returns # of packets ready to send or receive */
 int hpsb_iso_n_ready(struct hpsb_iso *iso);
 
 /* 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 */
 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);
-
-/* call to wake waiting processes after buffer space has opened up. */
 void hpsb_iso_wake(struct hpsb_iso *iso);
 
 #endif /* IEEE1394_ISO_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index c5ace19..6a1a057 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -16,6 +16,7 @@ #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <asm/atomic.h>
 
@@ -115,7 +116,7 @@ static int nodemgr_bus_read(struct csr12
 
 static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
 {
-	return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3;
+	return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3;
 }
 
 static struct csr1212_bus_ops nodemgr_csr_ops = {
@@ -370,9 +371,7 @@ static ssize_t fw_set_ignore_driver(stru
 
 	if (state == 1) {
 		ud->ignore_driver = 1;
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		device_release_driver(dev);
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	} else if (state == 0)
 		ud->ignore_driver = 0;
 
@@ -582,7 +581,7 @@ static void nodemgr_create_drv_files(str
 			goto fail;
 	return;
 fail:
-	HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name);
+	HPSB_ERR("Failed to add sysfs attribute");
 }
 
 
@@ -606,8 +605,7 @@ static void nodemgr_create_ne_dev_files(
 			goto fail;
 	return;
 fail:
-	HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
-		 (unsigned long long)ne->guid);
+	HPSB_ERR("Failed to add sysfs attribute");
 }
 
 
@@ -621,7 +619,7 @@ static void nodemgr_create_host_dev_file
 			goto fail;
 	return;
 fail:
-	HPSB_ERR("Failed to add sysfs attribute for host %d", host->id);
+	HPSB_ERR("Failed to add sysfs attribute");
 }
 
 
@@ -681,8 +679,7 @@ static void nodemgr_create_ud_dev_files(
 	}
 	return;
 fail:
-	HPSB_ERR("Failed to add sysfs attributes for unit %s",
-		 ud->device.bus_id);
+	HPSB_ERR("Failed to add sysfs attribute");
 }
 
 
@@ -1146,13 +1143,13 @@ static void nodemgr_process_root_directo
 		last_key_id = kv->key.id;
 	}
 
-	if (ne->vendor_name_kv &&
-	    device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
-		goto fail;
-	return;
-fail:
-	HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
-		 (unsigned long long)ne->guid);
+	if (ne->vendor_name_kv) {
+		int error = device_create_file(&ne->device,
+					       &dev_attr_ne_vendor_name_kv);
+
+		if (error && error != -EEXIST)
+			HPSB_ERR("Failed to add sysfs attribute");
+	}
 }
 
 #ifdef CONFIG_HOTPLUG
@@ -1163,6 +1160,7 @@ static int nodemgr_uevent(struct class_d
 	struct unit_directory *ud;
 	int i = 0;
 	int length = 0;
+	int retval = 0;
 	/* ieee1394:venNmoNspNverN */
 	char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
 
@@ -1176,14 +1174,11 @@ static int nodemgr_uevent(struct class_d
 
 #define PUT_ENVP(fmt,val) 					\
 do {								\
-    	int printed;						\
-	envp[i++] = buffer;					\
-	printed = snprintf(buffer, buffer_size - length,	\
-			   fmt, val);				\
-	if ((buffer_size - (length+printed) <= 0) || (i >= num_envp))	\
-		return -ENOMEM;					\
-	length += printed+1;					\
-	buffer += printed+1;					\
+	retval = add_uevent_var(envp, num_envp, &i,		\
+				buffer, buffer_size, &length,	\
+				fmt, val);			\
+	if (retval)						\
+		return retval;					\
 } while (0)
 
 	PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
@@ -1393,12 +1388,10 @@ static void nodemgr_suspend_ne(struct no
 		if (ud->ne != ne)
 			continue;
 
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver &&
 		    (!ud->device.driver->suspend ||
 		      ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
 			device_release_driver(&ud->device);
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 }
@@ -1418,10 +1411,8 @@ static void nodemgr_resume_ne(struct nod
 		if (ud->ne != ne)
 			continue;
 
-		down_read(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver && ud->device.driver->resume)
 			ud->device.driver->resume(&ud->device);
-		up_read(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 
@@ -1442,7 +1433,6 @@ static void nodemgr_update_pdrv(struct n
 		if (ud->ne != ne)
 			continue;
 
-		down_write(&ieee1394_bus_type.subsys.rwsem);
 		if (ud->device.driver) {
 			pdrv = container_of(ud->device.driver,
 					    struct hpsb_protocol_driver,
@@ -1450,7 +1440,6 @@ static void nodemgr_update_pdrv(struct n
 			if (pdrv->update && pdrv->update(ud))
 				device_release_driver(&ud->device);
 		}
-		up_write(&ieee1394_bus_type.subsys.rwsem);
 	}
 	up(&nodemgr_ud_class.sem);
 }
@@ -1748,7 +1737,19 @@ exit:
 	return 0;
 }
 
-int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
+/**
+ * nodemgr_for_each_host - call a function for each IEEE 1394 host
+ * @data: an address to supply to the callback
+ * @cb: function to call for each host
+ *
+ * Iterate the hosts, calling a given function with supplied data for each host.
+ * If the callback fails on a host, i.e. if it returns a non-zero value, the
+ * iteration is stopped.
+ *
+ * Return value: 0 on success, non-zero on failure (same as returned by last run
+ * of the callback).
+ */
+int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
 {
 	struct class_device *cdev;
 	struct hpsb_host *host;
@@ -1758,7 +1759,7 @@ int nodemgr_for_each_host(void *__data, 
 	list_for_each_entry(cdev, &hpsb_host_class.children, node) {
 		host = container_of(cdev, struct hpsb_host, class_dev);
 
-		if ((error = cb(host, __data)))
+		if ((error = cb(host, data)))
 			break;
 	}
 	up(&hpsb_host_class.sem);
@@ -1766,7 +1767,7 @@ int nodemgr_for_each_host(void *__data, 
 	return error;
 }
 
-/* The following four convenience functions use a struct node_entry
+/* The following two convenience functions use a struct node_entry
  * for addressing a node on the bus.  They are intended for use by any
  * process context, not just the nodemgr thread, so we need to be a
  * little careful when reading out the node ID and generation.  The
@@ -1781,12 +1782,20 @@ int nodemgr_for_each_host(void *__data, 
  * ID's.
  */
 
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
+/**
+ * hpsb_node_fill_packet - fill some destination information into a packet
+ * @ne: destination node
+ * @packet: packet to fill in
+ *
+ * This will fill in the given, pre-initialised hpsb_packet with the current
+ * information from the node entry (host, node ID, bus generation number).
+ */
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
 {
-	pkt->host = ne->host;
-	pkt->generation = ne->generation;
+	packet->host = ne->host;
+	packet->generation = ne->generation;
 	barrier();
-	pkt->node_id = ne->nodeid;
+	packet->node_id = ne->nodeid;
 }
 
 int hpsb_node_write(struct node_entry *ne, u64 addr,
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index 4147303..e7ac683 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -153,30 +153,10 @@ static inline int hpsb_node_entry_valid(
 {
 	return ne->generation == get_hpsb_generation(ne->host);
 }
-
-/*
- * 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.
- *
- * 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
- * number).  It will at least reliably fail so that you don't accidentally and
- * unknowingly send your packet to the wrong node.
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
-
-int hpsb_node_read(struct node_entry *ne, u64 addr,
-		   quadlet_t *buffer, size_t length);
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
 int hpsb_node_write(struct node_entry *ne, u64 addr,
 		    quadlet_t *buffer, size_t length);
-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 nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
 
 int init_ieee1394_nodemgr(void);
 void cleanup_ieee1394_nodemgr(void);
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 06fac0d..5dadfd2 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -507,9 +507,8 @@ static void ohci_initialize(struct ti_oh
 	/* Set up self-id dma buffer */
 	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
 
-	/* enable self-id and phys */
-	reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID |
-		  OHCI1394_LinkControl_RcvPhyPkt);
+	/* enable self-id */
+	reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
 
 	/* Set the Config ROM mapping register */
 	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
@@ -518,9 +517,6 @@ static void ohci_initialize(struct ti_oh
 	ohci->max_packet_size =
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
 		
-	/* Don't accept phy packets into AR request context */
-	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
-
 	/* Clear the interrupt mask */
 	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
@@ -617,7 +613,7 @@ #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
 #endif
 
 		PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
-                      "attempting to setting max_packet_size to 512 bytes");
+                      "attempting to set max_packet_size to 512 bytes");
 		reg_write(ohci, OHCI1394_BusOptions,
 			  (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
 		ohci->max_packet_size = 512;
@@ -2377,6 +2373,7 @@ static irqreturn_t ohci_irq_handler(int 
 	if (event & OHCI1394_postedWriteErr) {
 		PRINT(KERN_ERR, "physical posted write error");
 		/* no recovery strategy yet, had to involve protocol drivers */
+		event &= ~OHCI1394_postedWriteErr;
 	}
 	if (event & OHCI1394_cycleTooLong) {
 		if(printk_ratelimit())
@@ -3658,6 +3655,7 @@ #endif
 /* essentially the only purpose of this code is to allow another
    module to hook into ohci's interrupt handler */
 
+/* returns zero if successful, one if DMA context is locked up */
 int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
 {
 	int i=0;
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index fa05f11..f1ad539 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -461,9 +461,7 @@ int ohci1394_register_iso_tasklet(struct
 				  struct ohci1394_iso_tasklet *tasklet);
 void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
 				     struct ohci1394_iso_tasklet *tasklet);
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context      (struct ti_ohci *ohci, int reg, char *msg);
+int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
 struct ti_ohci *ohci1394_get_struct(int card_num);
 
 #endif
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index bb897a3..d382500 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -35,7 +35,6 @@ #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/cdev.h>
@@ -938,7 +937,8 @@ static int handle_async_send(struct file
 	int header_length = req->req.misc & 0xffff;
 	int expect_response = req->req.misc >> 16;
 
-	if ((header_length > req->req.length) || (header_length < 12)) {
+	if (header_length > req->req.length || header_length < 12 ||
+	    header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
 		req->req.error = RAW1394_ERROR_INVALID_ARG;
 		req->req.length = 0;
 		queue_complete_req(req);
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4edfff4..4cb6fa2 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -59,8 +59,10 @@ #include <linux/gfp.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/stat.h>
@@ -469,19 +471,13 @@ static void sbp2util_write_doorbell(stru
 static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
 {
 	struct sbp2_fwhost_info *hi = lu->hi;
-	int i;
-	unsigned long flags, orbs;
 	struct sbp2_command_info *cmd;
+	int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
 
-	orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
 	for (i = 0; i < orbs; i++) {
-		cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
-		if (!cmd) {
-			spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
+		cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+		if (!cmd)
 			return -ENOMEM;
-		}
 		cmd->command_orb_dma = dma_map_single(hi->host->device.parent,
 						&cmd->command_orb,
 						sizeof(struct sbp2_command_orb),
@@ -489,11 +485,10 @@ static int sbp2util_create_command_orb_p
 		cmd->sge_dma = dma_map_single(hi->host->device.parent,
 					&cmd->scatter_gather_element,
 					sizeof(cmd->scatter_gather_element),
-					DMA_BIDIRECTIONAL);
+					DMA_TO_DEVICE);
 		INIT_LIST_HEAD(&cmd->list);
 		list_add_tail(&cmd->list, &lu->cmd_orb_completed);
 	}
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
 	return 0;
 }
 
@@ -514,7 +509,7 @@ static void sbp2util_remove_command_orb_
 					 DMA_TO_DEVICE);
 			dma_unmap_single(host->device.parent, cmd->sge_dma,
 					 sizeof(cmd->scatter_gather_element),
-					 DMA_BIDIRECTIONAL);
+					 DMA_TO_DEVICE);
 			kfree(cmd);
 		}
 	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
@@ -757,6 +752,11 @@ #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 			SBP2_ERR("failed to register lower 4GB address range");
 			goto failed_alloc;
 		}
+#else
+		if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) {
+			SBP2_ERR("failed to set 4GB DMA mask");
+			goto failed_alloc;
+		}
 #endif
 	}
 
@@ -865,11 +865,8 @@ static int sbp2_start_device(struct sbp2
 	if (!lu->login_orb)
 		goto alloc_fail;
 
-	if (sbp2util_create_command_orb_pool(lu)) {
-		SBP2_ERR("sbp2util_create_command_orb_pool failed!");
-		sbp2_remove_device(lu);
-		return -ENOMEM;
-	}
+	if (sbp2util_create_command_orb_pool(lu))
+		goto alloc_fail;
 
 	/* Wait a second before trying to log in. Previously logged in
 	 * initiators need a chance to reconnect. */
@@ -1628,7 +1625,7 @@ static void sbp2_link_orb_command(struct
 				   DMA_TO_DEVICE);
 	dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma,
 				   sizeof(cmd->scatter_gather_element),
-				   DMA_BIDIRECTIONAL);
+				   DMA_TO_DEVICE);
 
 	/* check to see if there are any previous orbs to use */
 	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
@@ -1794,7 +1791,7 @@ static int sbp2_handle_status_write(stru
 					DMA_TO_DEVICE);
 		dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
 					sizeof(cmd->scatter_gather_element),
-					DMA_BIDIRECTIONAL);
+					DMA_TO_DEVICE);
 		/* Grab SCSI command pointers and check status. */
 		/*
 		 * FIXME: If the src field in the status is 1, the ORB DMA must
@@ -1926,7 +1923,7 @@ static void sbp2scsi_complete_all_comman
 					DMA_TO_DEVICE);
 		dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
 					sizeof(cmd->scatter_gather_element),
-					DMA_BIDIRECTIONAL);
+					DMA_TO_DEVICE);
 		sbp2util_mark_command_completed(lu, cmd);
 		if (cmd->Current_SCpnt) {
 			cmd->Current_SCpnt->result = status << 16;
@@ -2057,7 +2054,7 @@ static int sbp2scsi_abort(struct scsi_cm
 			dma_sync_single_for_cpu(hi->host->device.parent,
 					cmd->sge_dma,
 					sizeof(cmd->scatter_gather_element),
-					DMA_BIDIRECTIONAL);
+					DMA_TO_DEVICE);
 			sbp2util_mark_command_completed(lu, cmd);
 			if (cmd->Current_SCpnt) {
 				cmd->Current_SCpnt->result = DID_ABORT << 16;
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index 9ae8423..44402b9 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -250,15 +250,15 @@ enum sbp2_dma_types {
 /* Per SCSI command */
 struct sbp2_command_info {
 	struct list_head list;
-	struct sbp2_command_orb command_orb ____cacheline_aligned;
-	dma_addr_t command_orb_dma ____cacheline_aligned;
+	struct sbp2_command_orb command_orb;
+	dma_addr_t command_orb_dma;
 	struct scsi_cmnd *Current_SCpnt;
 	void (*Current_done)(struct scsi_cmnd *);
 
 	/* Also need s/g structure for each sbp2 command */
 	struct sbp2_unrestricted_page_table
-			scatter_gather_element[SG_ALL] ____cacheline_aligned;
-	dma_addr_t sge_dma ____cacheline_aligned;
+		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
+	dma_addr_t sge_dma;
 	void *sge_buffer;
 	dma_addr_t cmd_dma;
 	enum sbp2_dma_types dma_type;
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 95ca26d..87ebd08 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -39,7 +39,6 @@ #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 842cd0b..eff591d 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -40,7 +40,6 @@ #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/random.h>
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 1d796e7..a06bcc6 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -43,6 +43,8 @@ #include <rdma/ib_fmr_pool.h>
 
 #include "core_priv.h"
 
+#define PFX "fmr_pool: "
+
 enum {
 	IB_FMR_MAX_REMAPS = 32,
 
@@ -150,7 +152,7 @@ static void ib_fmr_batch_release(struct 
 
 #ifdef DEBUG
 		if (fmr->ref_count !=0) {
-			printk(KERN_WARNING "Unmapping FMR 0x%08x with ref count %d",
+			printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
 			       fmr, fmr->ref_count);
 		}
 #endif
@@ -168,7 +170,7 @@ #endif
 
 	ret = ib_unmap_fmr(&fmr_list);
 	if (ret)
-		printk(KERN_WARNING "ib_unmap_fmr returned %d", ret);
+		printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
 
 	spin_lock_irq(&pool->pool_lock);
 	list_splice(&unmap_list, &pool->free_list);
@@ -226,20 +228,20 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 	device = pd->device;
 	if (!device->alloc_fmr    || !device->dealloc_fmr  ||
 	    !device->map_phys_fmr || !device->unmap_fmr) {
-		printk(KERN_WARNING "Device %s does not support fast memory regions",
+		printk(KERN_INFO PFX "Device %s does not support FMRs\n",
 		       device->name);
 		return ERR_PTR(-ENOSYS);
 	}
 
 	attr = kmalloc(sizeof *attr, GFP_KERNEL);
 	if (!attr) {
-		printk(KERN_WARNING "couldn't allocate device attr struct");
+		printk(KERN_WARNING PFX "couldn't allocate device attr struct");
 		return ERR_PTR(-ENOMEM);
 	}
 
 	ret = ib_query_device(device, attr);
 	if (ret) {
-		printk(KERN_WARNING "couldn't query device");
+		printk(KERN_WARNING PFX "couldn't query device: %d", ret);
 		kfree(attr);
 		return ERR_PTR(ret);
 	}
@@ -253,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 
 	pool = kmalloc(sizeof *pool, GFP_KERNEL);
 	if (!pool) {
-		printk(KERN_WARNING "couldn't allocate pool struct");
+		printk(KERN_WARNING PFX "couldn't allocate pool struct");
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -270,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 			kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
 				GFP_KERNEL);
 		if (!pool->cache_bucket) {
-			printk(KERN_WARNING "Failed to allocate cache in pool");
+			printk(KERN_WARNING PFX "Failed to allocate cache in pool");
 			ret = -ENOMEM;
 			goto out_free_pool;
 		}
@@ -294,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 				      "ib_fmr(%s)",
 				      device->name);
 	if (IS_ERR(pool->thread)) {
-		printk(KERN_WARNING "couldn't start cleanup thread");
+		printk(KERN_WARNING PFX "couldn't start cleanup thread");
 		ret = PTR_ERR(pool->thread);
 		goto out_free_pool;
 	}
@@ -311,8 +313,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 			fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
 				      GFP_KERNEL);
 			if (!fmr) {
-				printk(KERN_WARNING "failed to allocate fmr struct "
-				       "for FMR %d", i);
+				printk(KERN_WARNING PFX "failed to allocate fmr "
+				       "struct for FMR %d", i);
 				goto out_fail;
 			}
 
@@ -323,7 +325,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 
 			fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
 			if (IS_ERR(fmr->fmr)) {
-				printk(KERN_WARNING "fmr_create failed for FMR %d", i);
+				printk(KERN_WARNING PFX "fmr_create failed "
+				       "for FMR %d", i);
 				kfree(fmr);
 				goto out_fail;
 			}
@@ -378,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_p
 	}
 
 	if (i < pool->pool_size)
-		printk(KERN_WARNING "pool still has %d regions registered",
+		printk(KERN_WARNING PFX "pool still has %d regions registered",
 		       pool->pool_size - i);
 
 	kfree(pool->cache_bucket);
@@ -463,8 +466,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys
 		list_add(&fmr->list, &pool->free_list);
 		spin_unlock_irqrestore(&pool->pool_lock, flags);
 
-		printk(KERN_WARNING "fmr_map returns %d\n",
-		       result);
+		printk(KERN_WARNING PFX "fmr_map returns %d\n", result);
 
 		return ERR_PTR(result);
 	}
@@ -516,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr
 
 #ifdef DEBUG
 	if (fmr->ref_count < 0)
-		printk(KERN_WARNING "FMR %p has ref count %d < 0",
+		printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
 		       fmr, fmr->ref_count);
 #endif
 
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 891d1fa..223b1aa 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -39,7 +39,6 @@ #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>
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 13efd41..85ccf13 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 Intel Corporation.  All rights reserved.
  * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
  *
@@ -31,7 +31,6 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $
  */
 #include <linux/dma-mapping.h>
 #include <rdma/ib_cache.h>
@@ -668,7 +667,7 @@ static void build_smp_wc(struct ib_qp *q
 static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
 				  struct ib_mad_send_wr_private *mad_send_wr)
 {
-	int ret;
+	int ret = 0;
 	struct ib_smp *smp = mad_send_wr->send_buf.mad;
 	unsigned long flags;
 	struct ib_mad_local_private *local;
@@ -688,14 +687,15 @@ static int handle_outgoing_dr_smp(struct
 	 */
 	if ((ib_get_smp_direction(smp) ? smp->dr_dlid : smp->dr_slid) ==
 	     IB_LID_PERMISSIVE &&
-	    !smi_handle_dr_smp_send(smp, device->node_type, port_num)) {
+	     smi_handle_dr_smp_send(smp, device->node_type, port_num) ==
+	     IB_SMI_DISCARD) {
 		ret = -EINVAL;
 		printk(KERN_ERR PFX "Invalid directed route\n");
 		goto out;
 	}
+
 	/* Check to post send on QP or process locally */
-	ret = smi_check_local_smp(smp, device);
-	if (!ret)
+	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
 		goto out;
 
 	local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -1874,18 +1874,22 @@ static void ib_mad_recv_done_handler(str
 
 	if (recv->mad.mad.mad_hdr.mgmt_class ==
 	    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
-		if (!smi_handle_dr_smp_recv(&recv->mad.smp,
-					    port_priv->device->node_type,
-					    port_priv->port_num,
-					    port_priv->device->phys_port_cnt))
+		if (smi_handle_dr_smp_recv(&recv->mad.smp,
+					   port_priv->device->node_type,
+					   port_priv->port_num,
+					   port_priv->device->phys_port_cnt) ==
+					   IB_SMI_DISCARD)
 			goto out;
-		if (!smi_check_forward_dr_smp(&recv->mad.smp))
+
+		if (smi_check_forward_dr_smp(&recv->mad.smp) == IB_SMI_LOCAL)
 			goto local;
-		if (!smi_handle_dr_smp_send(&recv->mad.smp,
-					    port_priv->device->node_type,
-					    port_priv->port_num))
+
+		if (smi_handle_dr_smp_send(&recv->mad.smp,
+					   port_priv->device->node_type,
+					   port_priv->port_num) == IB_SMI_DISCARD)
 			goto out;
-		if (!smi_check_local_smp(&recv->mad.smp, port_priv->device))
+
+		if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD)
 			goto out;
 	}
 
@@ -2767,7 +2771,7 @@ static int ib_mad_port_open(struct ib_de
 	cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2;
 	port_priv->cq = ib_create_cq(port_priv->device,
 				     ib_mad_thread_completion_handler,
-				     NULL, port_priv, cq_size);
+				     NULL, port_priv, cq_size, 0);
 	if (IS_ERR(port_priv->cq)) {
 		printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n");
 		ret = PTR_ERR(port_priv->cq);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index de89717..9be5cc0 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -39,7 +39,6 @@ #define __IB_MAD_PRIV_H__
 
 #include <linux/completion.h>
 #include <linux/err.h>
-#include <linux/pci.h>
 #include <linux/workqueue.h>
 #include <rdma/ib_mad.h>
 #include <rdma/ib_smi.h>
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 4a579b3..1e13ab4 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -34,7 +34,6 @@ #include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/bitops.h>
 #include <linux/random.h>
 
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 68db633..6469406 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -40,7 +40,6 @@ #include <linux/err.h>
 #include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/kref.h>
 #include <linux/idr.h>
@@ -57,6 +56,7 @@ MODULE_LICENSE("Dual BSD/GPL");
 struct ib_sa_sm_ah {
 	struct ib_ah        *ah;
 	struct kref          ref;
+	u8		     src_path_mask;
 };
 
 struct ib_sa_port {
@@ -380,6 +380,7 @@ static void update_sm_ah(struct work_str
 	}
 
 	kref_init(&new_ah->ref);
+	new_ah->src_path_mask = (1 << port_attr.lmc) - 1;
 
 	memset(&ah_attr, 0, sizeof ah_attr);
 	ah_attr.dlid     = port_attr.sm_lid;
@@ -460,6 +461,25 @@ void ib_sa_cancel_query(int id, struct i
 }
 EXPORT_SYMBOL(ib_sa_cancel_query);
 
+static u8 get_src_path_mask(struct ib_device *device, u8 port_num)
+{
+	struct ib_sa_device *sa_dev;
+	struct ib_sa_port   *port;
+	unsigned long flags;
+	u8 src_path_mask;
+
+	sa_dev = ib_get_client_data(device, &sa_client);
+	if (!sa_dev)
+		return 0x7f;
+
+	port  = &sa_dev->port[port_num - sa_dev->start_port];
+	spin_lock_irqsave(&port->ah_lock, flags);
+	src_path_mask = port->sm_ah ? port->sm_ah->src_path_mask : 0x7f;
+	spin_unlock_irqrestore(&port->ah_lock, flags);
+
+	return src_path_mask;
+}
+
 int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
 			 struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr)
 {
@@ -469,7 +489,8 @@ int ib_init_ah_from_path(struct ib_devic
 	memset(ah_attr, 0, sizeof *ah_attr);
 	ah_attr->dlid = be16_to_cpu(rec->dlid);
 	ah_attr->sl = rec->sl;
-	ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f;
+	ah_attr->src_path_bits = be16_to_cpu(rec->slid) &
+				 get_src_path_mask(device, port_num);
 	ah_attr->port_num = port_num;
 	ah_attr->static_rate = rec->rate;
 
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
index 54b81e1..2bca753 100644
--- a/drivers/infiniband/core/smi.c
+++ b/drivers/infiniband/core/smi.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
  * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004-2007 Voltaire Corporation.  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
@@ -34,7 +34,6 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $
  */
 
 #include <rdma/ib_smi.h>
@@ -44,9 +43,8 @@ #include "smi.h"
  * Fixup a directed route SMP for sending
  * Return 0 if the SMP should be discarded
  */
-int smi_handle_dr_smp_send(struct ib_smp *smp,
-			   u8 node_type,
-			   int port_num)
+enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
+				       u8 node_type, int port_num)
 {
 	u8 hop_ptr, hop_cnt;
 
@@ -59,18 +57,18 @@ int smi_handle_dr_smp_send(struct ib_smp
 		if (hop_cnt && hop_ptr == 0) {
 			smp->hop_ptr++;
 			return (smp->initial_path[smp->hop_ptr] ==
-				port_num);
+				port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-9:2 */
 		if (hop_ptr && hop_ptr < hop_cnt) {
 			if (node_type != RDMA_NODE_IB_SWITCH)
-				return 0;
+				return IB_SMI_DISCARD;
 
 			/* smp->return_path set when received */
 			smp->hop_ptr++;
 			return (smp->initial_path[smp->hop_ptr] ==
-				port_num);
+				port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-9:3 -- We're at the end of the DR segment of path */
@@ -78,29 +76,30 @@ int smi_handle_dr_smp_send(struct ib_smp
 			/* smp->return_path set when received */
 			smp->hop_ptr++;
 			return (node_type == RDMA_NODE_IB_SWITCH ||
-				smp->dr_dlid == IB_LID_PERMISSIVE);
+				smp->dr_dlid == IB_LID_PERMISSIVE ?
+				IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
 		/* C14-9:5 -- Fail unreasonable hop pointer */
-		return (hop_ptr == hop_cnt + 1);
+		return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 
 	} else {
 		/* C14-13:1 */
 		if (hop_cnt && hop_ptr == hop_cnt + 1) {
 			smp->hop_ptr--;
 			return (smp->return_path[smp->hop_ptr] ==
-				port_num);
+				port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-13:2 */
 		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
 			if (node_type != RDMA_NODE_IB_SWITCH)
-				return 0;
+				return IB_SMI_DISCARD;
 
 			smp->hop_ptr--;
 			return (smp->return_path[smp->hop_ptr] ==
-				port_num);
+				port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-13:3 -- at the end of the DR segment of path */
@@ -108,15 +107,16 @@ int smi_handle_dr_smp_send(struct ib_smp
 			smp->hop_ptr--;
 			/* C14-13:3 -- SMPs destined for SM shouldn't be here */
 			return (node_type == RDMA_NODE_IB_SWITCH ||
-				smp->dr_slid == IB_LID_PERMISSIVE);
+				smp->dr_slid == IB_LID_PERMISSIVE ?
+				IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */
 		if (hop_ptr == 0)
-			return 1;
+			return IB_SMI_HANDLE;
 
 		/* C14-13:5 -- Check for unreasonable hop pointer */
-		return 0;
+		return IB_SMI_DISCARD;
 	}
 }
 
@@ -124,10 +124,8 @@ int smi_handle_dr_smp_send(struct ib_smp
  * Adjust information for a received SMP
  * Return 0 if the SMP should be dropped
  */
-int smi_handle_dr_smp_recv(struct ib_smp *smp,
-			   u8 node_type,
-			   int port_num,
-			   int phys_port_cnt)
+enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
+				       int port_num, int phys_port_cnt)
 {
 	u8 hop_ptr, hop_cnt;
 
@@ -138,16 +136,17 @@ int smi_handle_dr_smp_recv(struct ib_smp
 	if (!ib_get_smp_direction(smp)) {
 		/* C14-9:1 -- sender should have incremented hop_ptr */
 		if (hop_cnt && hop_ptr == 0)
-			return 0;
+			return IB_SMI_DISCARD;
 
 		/* C14-9:2 -- intermediate hop */
 		if (hop_ptr && hop_ptr < hop_cnt) {
 			if (node_type != RDMA_NODE_IB_SWITCH)
-				return 0;
+				return IB_SMI_DISCARD;
 
 			smp->return_path[hop_ptr] = port_num;
 			/* smp->hop_ptr updated when sending */
-			return (smp->initial_path[hop_ptr+1] <= phys_port_cnt);
+			return (smp->initial_path[hop_ptr+1] <= phys_port_cnt ?
+				IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-9:3 -- We're at the end of the DR segment of path */
@@ -157,12 +156,13 @@ int smi_handle_dr_smp_recv(struct ib_smp
 			/* smp->hop_ptr updated when sending */
 
 			return (node_type == RDMA_NODE_IB_SWITCH ||
-				smp->dr_dlid == IB_LID_PERMISSIVE);
+				smp->dr_dlid == IB_LID_PERMISSIVE ?
+				IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
 		/* C14-9:5 -- fail unreasonable hop pointer */
-		return (hop_ptr == hop_cnt + 1);
+		return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 
 	} else {
 
@@ -170,16 +170,17 @@ int smi_handle_dr_smp_recv(struct ib_smp
 		if (hop_cnt && hop_ptr == hop_cnt + 1) {
 			smp->hop_ptr--;
 			return (smp->return_path[smp->hop_ptr] ==
-				port_num);
+				port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-13:2 */
 		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
 			if (node_type != RDMA_NODE_IB_SWITCH)
-				return 0;
+				return IB_SMI_DISCARD;
 
 			/* smp->hop_ptr updated when sending */
-			return (smp->return_path[hop_ptr-1] <= phys_port_cnt);
+			return (smp->return_path[hop_ptr-1] <= phys_port_cnt ?
+				IB_SMI_HANDLE : IB_SMI_DISCARD);
 		}
 
 		/* C14-13:3 -- We're at the end of the DR segment of path */
@@ -187,23 +188,20 @@ int smi_handle_dr_smp_recv(struct ib_smp
 			if (smp->dr_slid == IB_LID_PERMISSIVE) {
 				/* giving SMP to SM - update hop_ptr */
 				smp->hop_ptr--;
-				return 1;
+				return IB_SMI_HANDLE;
 			}
 			/* smp->hop_ptr updated when sending */
-			return (node_type == RDMA_NODE_IB_SWITCH);
+			return (node_type == RDMA_NODE_IB_SWITCH ?
+				IB_SMI_HANDLE: IB_SMI_DISCARD);
 		}
 
 		/* C14-13:4 -- hop_ptr = 0 -> give to SM */
 		/* C14-13:5 -- Check for unreasonable hop pointer */
-		return (hop_ptr == 0);
+		return (hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
 	}
 }
 
-/*
- * Return 1 if the received DR SMP should be forwarded to the send queue
- * Return 0 if the SMP should be completed up the stack
- */
-int smi_check_forward_dr_smp(struct ib_smp *smp)
+enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
 {
 	u8 hop_ptr, hop_cnt;
 
@@ -213,23 +211,25 @@ int smi_check_forward_dr_smp(struct ib_s
 	if (!ib_get_smp_direction(smp)) {
 		/* C14-9:2 -- intermediate hop */
 		if (hop_ptr && hop_ptr < hop_cnt)
-			return 1;
+			return IB_SMI_SEND;
 
 		/* C14-9:3 -- at the end of the DR segment of path */
 		if (hop_ptr == hop_cnt)
-			return (smp->dr_dlid == IB_LID_PERMISSIVE);
+			return (smp->dr_dlid == IB_LID_PERMISSIVE ?
+				IB_SMI_SEND : IB_SMI_LOCAL);
 
 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
 		if (hop_ptr == hop_cnt + 1)
-			return 1;
+			return IB_SMI_SEND;
 	} else {
-		/* C14-13:2 */
+		/* C14-13:2  -- intermediate hop */
 		if (2 <= hop_ptr && hop_ptr <= hop_cnt)
-			return 1;
+			return IB_SMI_SEND;
 
 		/* C14-13:3 -- at the end of the DR segment of path */
 		if (hop_ptr == 1)
-			return (smp->dr_slid != IB_LID_PERMISSIVE);
+			return (smp->dr_slid != IB_LID_PERMISSIVE ?
+				IB_SMI_SEND : IB_SMI_LOCAL);
 	}
-	return 0;
+	return IB_SMI_LOCAL;
 }
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 3011bfd..9a4b349 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -3,7 +3,7 @@
  * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
- * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
+ * Copyright (c) 2004-2007 Voltaire 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
@@ -33,7 +33,6 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: smi.h 1389 2004-12-27 22:56:47Z roland $
  */
 
 #ifndef __SMI_H_
@@ -41,26 +40,33 @@ #define __SMI_H_
 
 #include <rdma/ib_smi.h>
 
-int smi_handle_dr_smp_recv(struct ib_smp *smp,
-			   u8 node_type,
-			   int port_num,
-			   int phys_port_cnt);
-extern int smi_check_forward_dr_smp(struct ib_smp *smp);
-extern int smi_handle_dr_smp_send(struct ib_smp *smp,
-				  u8 node_type,
-				  int port_num);
+enum smi_action {
+	IB_SMI_DISCARD,
+	IB_SMI_HANDLE
+};
+
+enum smi_forward_action {
+	IB_SMI_LOCAL,	/* SMP should be completed up the stack */
+	IB_SMI_SEND,	/* received DR SMP should be forwarded to the send queue */
+};
+
+enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
+				       int port_num, int phys_port_cnt);
+extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp);
+extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
+					      u8 node_type, int port_num);
 
 /*
  * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
  */
-static inline int smi_check_local_smp(struct ib_smp *smp,
-				      struct ib_device *device)
+static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
+						  struct ib_device *device)
 {
 	/* C14-9:3 -- We're at the end of the DR segment of path */
 	/* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */
 	return ((device->process_mad &&
 		!ib_get_smp_direction(smp) &&
-		(smp->hop_ptr == smp->hop_cnt + 1)));
+		(smp->hop_ptr == smp->hop_cnt + 1)) ?
+		IB_SMI_HANDLE : IB_SMI_DISCARD);
 }
-
 #endif	/* __SMI_H_ */
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 000c086..08c299e 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -683,6 +683,7 @@ int ib_device_register_sysfs(struct ib_d
 
 	class_dev->class      = &ib_class;
 	class_dev->class_data = device;
+	class_dev->dev	      = device->dma_device;
 	strlcpy(class_dev->class_id, device->name, BUS_ID_SIZE);
 
 	INIT_LIST_HEAD(&device->port_list);
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index ee51d79..2586a3e 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -407,29 +407,18 @@ static ssize_t ib_ucm_event(struct ib_uc
 
 	mutex_lock(&file->file_mutex);
 	while (list_empty(&file->events)) {
+		mutex_unlock(&file->file_mutex);
 
-		if (file->filp->f_flags & O_NONBLOCK) {
-			result = -EAGAIN;
-			break;
-		}
+		if (file->filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
 
-		if (signal_pending(current)) {
-			result = -ERESTARTSYS;
-			break;
-		}
+		if (wait_event_interruptible(file->poll_wait,
+					     !list_empty(&file->events)))
+			return -ERESTARTSYS;
 
-		prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE);
-
-		mutex_unlock(&file->file_mutex);
-		schedule();
 		mutex_lock(&file->file_mutex);
-
-		finish_wait(&file->poll_wait, &wait);
 	}
 
-	if (result)
-		goto done;
-
 	uevent = list_entry(file->events.next, struct ib_ucm_event, file_list);
 
 	if (ib_ucm_new_cm_id(uevent->resp.event)) {
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index c859134..53b4c94 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -306,26 +306,18 @@ static ssize_t ucma_get_event(struct ucm
 
 	mutex_lock(&file->mut);
 	while (list_empty(&file->event_list)) {
-		if (file->filp->f_flags & O_NONBLOCK) {
-			ret = -EAGAIN;
-			break;
-		}
+		mutex_unlock(&file->mut);
 
-		if (signal_pending(current)) {
-			ret = -ERESTARTSYS;
-			break;
-		}
+		if (file->filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		if (wait_event_interruptible(file->poll_wait,
+					     !list_empty(&file->event_list)))
+			return -ERESTARTSYS;
 
-		prepare_to_wait(&file->poll_wait, &wait, TASK_INTERRUPTIBLE);
-		mutex_unlock(&file->mut);
-		schedule();
 		mutex_lock(&file->mut);
-		finish_wait(&file->poll_wait, &wait);
 	}
 
-	if (ret)
-		goto done;
-
 	uevent = list_entry(file->event_list.next, struct ucma_event, list);
 
 	if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) {
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index c069ebe..d97ded2 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -40,7 +40,6 @@ #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/cdev.h>
-#include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/poll.h>
 #include <linux/rwsem.h>
@@ -135,7 +134,7 @@ static const dev_t base_dev = MKDEV(IB_U
 
 static DEFINE_SPINLOCK(port_lock);
 static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS];
-static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2);
+static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS);
 
 static void ib_umad_add_one(struct ib_device *device);
 static void ib_umad_remove_one(struct ib_device *device);
@@ -231,12 +230,17 @@ static void recv_handler(struct ib_mad_a
 	packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
 	packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
 	if (packet->mad.hdr.grh_present) {
-		/* XXX parse GRH */
-		packet->mad.hdr.gid_index 	= 0;
-		packet->mad.hdr.hop_limit 	= 0;
-		packet->mad.hdr.traffic_class	= 0;
-		memset(packet->mad.hdr.gid, 0, 16);
-		packet->mad.hdr.flow_label	= 0;
+		struct ib_ah_attr ah_attr;
+
+		ib_init_ah_from_wc(agent->device, agent->port_num,
+				   mad_recv_wc->wc, mad_recv_wc->recv_buf.grh,
+				   &ah_attr);
+
+		packet->mad.hdr.gid_index = ah_attr.grh.sgid_index;
+		packet->mad.hdr.hop_limit = ah_attr.grh.hop_limit;
+		packet->mad.hdr.traffic_class = ah_attr.grh.traffic_class;
+		memcpy(packet->mad.hdr.gid, &ah_attr.grh.dgid, 16);
+		packet->mad.hdr.flow_label = cpu_to_be32(ah_attr.grh.flow_label);
 	}
 
 	if (queue_packet(file, agent, packet))
@@ -473,6 +477,7 @@ static ssize_t ib_umad_write(struct file
 	if (packet->mad.hdr.grh_present) {
 		ah_attr.ah_flags = IB_AH_GRH;
 		memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16);
+		ah_attr.grh.sgid_index	   = packet->mad.hdr.gid_index;
 		ah_attr.grh.flow_label 	   = be32_to_cpu(packet->mad.hdr.flow_label);
 		ah_attr.grh.hop_limit  	   = packet->mad.hdr.hop_limit;
 		ah_attr.grh.traffic_class  = packet->mad.hdr.traffic_class;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 4fd75af..bab6676 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -802,6 +802,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uv
 	INIT_LIST_HEAD(&obj->async_list);
 
 	cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+					     cmd.comp_vector,
 					     file->ucontext, &udata);
 	if (IS_ERR(cq)) {
 		ret = PTR_ERR(cq);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index f8bc822..d44e547 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -752,7 +752,7 @@ static void ib_uverbs_add_one(struct ib_
 	spin_unlock(&map_lock);
 
 	uverbs_dev->ib_dev           = device;
-	uverbs_dev->num_comp_vectors = 1;
+	uverbs_dev->num_comp_vectors = device->num_comp_vectors;
 
 	uverbs_dev->dev = cdev_alloc();
 	if (!uverbs_dev->dev)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index ccdf93d..86ed8af 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -609,11 +609,11 @@ EXPORT_SYMBOL(ib_destroy_qp);
 struct ib_cq *ib_create_cq(struct ib_device *device,
 			   ib_comp_handler comp_handler,
 			   void (*event_handler)(struct ib_event *, void *),
-			   void *cq_context, int cqe)
+			   void *cq_context, int cqe, int comp_vector)
 {
 	struct ib_cq *cq;
 
-	cq = device->create_cq(device, cqe, NULL, NULL);
+	cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
 
 	if (!IS_ERR(cq)) {
 		cq->device        = device;
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 59243d9..58bc272 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -439,7 +439,8 @@ static void c2_rx_error(struct c2_port *
 	}
 
 	/* Setup the skb for reuse since we're dropping this pkt */
-	elem->skb->tail = elem->skb->data = elem->skb->head;
+	elem->skb->data = elem->skb->head;
+	skb_reset_tail_pointer(elem->skb);
 
 	/* Zero out the rxp hdr in the sk_buff */
 	memset(elem->skb->data, 0, sizeof(*rxp_hdr));
@@ -521,9 +522,8 @@ static void c2_rx_interrupt(struct net_d
 		 * "sizeof(struct c2_rxp_hdr)".
 		 */
 		skb->data += sizeof(*rxp_hdr);
-		skb->tail = skb->data + buflen;
+		skb_set_tail_pointer(skb, buflen);
 		skb->len = buflen;
-		skb->dev = netdev;
 		skb->protocol = eth_type_trans(skb, netdev);
 
 		netif_rx(skb);
diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h
index 04a9db5..fa58200 100644
--- a/drivers/infiniband/hw/amso1100/c2.h
+++ b/drivers/infiniband/hw/amso1100/c2.h
@@ -519,7 +519,7 @@ extern void c2_free_cq(struct c2_dev *c2
 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);
+extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
 
 /* CM */
 extern int c2_llp_connect(struct iw_cm_id *cm_id,
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 5175c99..d2b3366 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -217,17 +217,19 @@ int c2_poll_cq(struct ib_cq *ibcq, int n
 	return npolled;
 }
 
-int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
 {
 	struct c2_mq_shared __iomem *shared;
 	struct c2_cq *cq;
+	unsigned long flags;
+	int ret = 0;
 
 	cq = to_c2cq(ibcq);
 	shared = cq->mq.peer;
 
-	if (notify == IB_CQ_NEXT_COMP)
+	if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
-	else if (notify == IB_CQ_SOLICITED)
+	else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
 		writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
 	else
 		return -EINVAL;
@@ -241,7 +243,13 @@ int c2_arm_cq(struct ib_cq *ibcq, enum i
 	 */
 	readb(&shared->armed);
 
-	return 0;
+	if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+		spin_lock_irqsave(&cq->lock, flags);
+		ret = !c2_mq_empty(&cq->mq);
+		spin_unlock_irqrestore(&cq->lock, flags);
+	}
+
+	return ret;
 }
 
 static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index fef9727..1091662 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -290,7 +290,7 @@ static int c2_destroy_qp(struct ib_qp *i
 	return 0;
 }
 
-static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, int vector,
 				  struct ib_ucontext *context,
 				  struct ib_udata *udata)
 {
@@ -795,8 +795,8 @@ int c2_register_device(struct c2_dev *de
 	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.num_comp_vectors = 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;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index f5e9aee..76049af 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -114,7 +114,10 @@ int cxio_hal_cq_op(struct cxio_rdev *rde
 				return -EIO;
 			}
 		}
+
+		return 1;
 	}
+
 	return 0;
 }
 
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index 90d7b89..ff7290e 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -38,6 +38,7 @@ #include <linux/timer.h>
 #include "firmware_exports.h"
 
 #define T3_MAX_SGE      4
+#define T3_MAX_INLINE	64
 
 #define Q_EMPTY(rptr,wptr) ((rptr)==(wptr))
 #define Q_FULL(rptr,wptr,size_log2)  ( (((wptr)-(rptr))>>(size_log2)) && \
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 2d2de9b..b2faff5 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -477,7 +477,7 @@ static void send_mpa_req(struct iwch_ep 
 	BUG_ON(skb_cloned(skb));
 
 	mpalen = sizeof(*mpa) + ep->plen;
-	if (skb->data + mpalen + sizeof(*req) > skb->end) {
+	if (skb->data + mpalen + sizeof(*req) > skb_end_pointer(skb)) {
 		kfree_skb(skb);
 		skb=alloc_skb(mpalen + sizeof(*req), GFP_KERNEL);
 		if (!skb) {
@@ -507,7 +507,7 @@ static void send_mpa_req(struct iwch_ep 
 	 */
 	skb_get(skb);
 	set_arp_failure_handler(skb, arp_failure_discard);
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	len = skb->len;
 	req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
 	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
@@ -559,7 +559,7 @@ static int send_mpa_reject(struct iwch_e
 	skb_get(skb);
 	skb->priority = CPL_PRIORITY_DATA;
 	set_arp_failure_handler(skb, arp_failure_discard);
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
 	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
 	req->wr_lo = htonl(V_WR_TID(ep->hwtid));
@@ -610,7 +610,7 @@ static int send_mpa_reply(struct iwch_ep
 	 */
 	skb_get(skb);
 	set_arp_failure_handler(skb, arp_failure_discard);
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	len = skb->len;
 	req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
 	req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
@@ -821,7 +821,8 @@ static void process_mpa_reply(struct iwc
 	/*
 	 * copy the new data into our accumulation buffer.
 	 */
-	memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len);
+	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),
+				  skb->len);
 	ep->mpa_pkt_len += skb->len;
 
 	/*
@@ -940,7 +941,8 @@ static void process_mpa_request(struct i
 	/*
 	 * Copy the new data into our accumulation buffer.
 	 */
-	memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len);
+	skb_copy_from_linear_data(skb, &(ep->mpa_pkt[ep->mpa_pkt_len]),
+				  skb->len);
 	ep->mpa_pkt_len += skb->len;
 
 	/*
@@ -1107,6 +1109,15 @@ static int abort_rpl(struct t3cdev *tdev
 
 	PDBG("%s ep %p\n", __FUNCTION__, ep);
 
+	/*
+	 * We get 2 abort replies from the HW.  The first one must
+	 * be ignored except for scribbling that we need one more.
+	 */
+	if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) {
+		ep->flags |= ABORT_REQ_IN_PROGRESS;
+		return CPL_RET_BUF_DONE;
+	}
+
 	close_complete_upcall(ep);
 	state_set(&ep->com, DEAD);
 	release_ep_resources(ep);
@@ -1187,6 +1198,7 @@ static int listen_stop(struct iwch_liste
 	}
 	req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	req->cpu_idx = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
 	skb->priority = 1;
 	ep->com.tdev->send(ep->com.tdev, skb);
@@ -1473,6 +1485,15 @@ static int peer_abort(struct t3cdev *tde
 	int ret;
 	int state;
 
+	/*
+	 * We get 2 peer aborts from the HW.  The first one must
+	 * be ignored except for scribbling that we need one more.
+	 */
+	if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) {
+		ep->flags |= PEER_ABORT_IN_PROGRESS;
+		return CPL_RET_BUF_DONE;
+	}
+
 	if (is_neg_adv_abort(req->status)) {
 		PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
 		     ep->hwtid);
@@ -1619,7 +1640,8 @@ static int terminate(struct t3cdev *tdev
 	PDBG("%s ep %p\n", __FUNCTION__, ep);
 	skb_pull(skb, sizeof(struct cpl_rdma_terminate));
 	PDBG("%s saving %d bytes of term msg\n", __FUNCTION__, skb->len);
-	memcpy(ep->com.qp->attr.terminate_buffer, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, ep->com.qp->attr.terminate_buffer,
+				  skb->len);
 	ep->com.qp->attr.terminate_msg_len = skb->len;
 	ep->com.qp->attr.is_terminate_local = 0;
 	return CPL_RET_BUF_DONE;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 0c6f281..21a388c 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -143,6 +143,11 @@ enum iwch_ep_state {
 	DEAD,
 };
 
+enum iwch_ep_flags {
+	PEER_ABORT_IN_PROGRESS	= (1 << 0),
+	ABORT_REQ_IN_PROGRESS	= (1 << 1),
+};
+
 struct iwch_ep_common {
 	struct iw_cm_id *cm_id;
 	struct iwch_qp *qp;
@@ -181,6 +186,7 @@ struct iwch_ep {
 	u16 plen;
 	u32 ird;
 	u32 ord;
+	u32 flags;
 };
 
 static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 24e0df0..a891493 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -139,7 +139,7 @@ static int iwch_destroy_cq(struct ib_cq 
 	return 0;
 }
 
-static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int vector,
 			     struct ib_ucontext *ib_context,
 			     struct ib_udata *udata)
 {
@@ -292,7 +292,7 @@ #else
 #endif
 }
 
-static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
 {
 	struct iwch_dev *rhp;
 	struct iwch_cq *chp;
@@ -303,7 +303,7 @@ static int iwch_arm_cq(struct ib_cq *ibc
 
 	chp = to_iwch_cq(ibcq);
 	rhp = chp->rhp;
-	if (notify == IB_CQ_SOLICITED)
+	if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
 		cq_op = CQ_ARM_SE;
 	else
 		cq_op = CQ_ARM_AN;
@@ -317,9 +317,11 @@ static int iwch_arm_cq(struct ib_cq *ibc
 	PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr);
 	err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0);
 	spin_unlock_irqrestore(&chp->lock, flag);
-	if (err)
+	if (err < 0)
 		printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err,
 		       chp->cq.cqid);
+	if (err > 0 && !(flags & IB_CQ_REPORT_MISSED_EVENTS))
+		err = 0;
 	return err;
 }
 
@@ -780,6 +782,9 @@ static struct ib_qp *iwch_create_qp(stru
 	if (rqsize > T3_MAX_RQ_SIZE)
 		return ERR_PTR(-EINVAL);
 
+	if (attrs->cap.max_inline_data > T3_MAX_INLINE)
+		return ERR_PTR(-EINVAL);
+
 	/*
 	 * NOTE: The SQ and total WQ sizes don't need to be
 	 * a power of two.  However, all the code assumes
@@ -1107,8 +1112,8 @@ int iwch_register_device(struct iwch_dev
 	dev->ibdev.node_type = RDMA_NODE_RNIC;
 	memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
 	dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
+	dev->ibdev.num_comp_vectors = 1;
 	dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev);
-	dev->ibdev.class_dev.dev = &(dev->rdev.rnic_info.pdev->dev);
 	dev->ibdev.query_device = iwch_query_device;
 	dev->ibdev.query_port = iwch_query_port;
 	dev->ibdev.modify_port = iwch_modify_port;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 0a472c9..714dddb 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -471,43 +471,62 @@ int iwch_bind_mw(struct ib_qp *qp,
 	return err;
 }
 
-static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged)
+static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
+				    u8 *layer_type, u8 *ecode)
 {
-	switch (t3err) {
+	int status = TPT_ERR_INTERNAL_ERR;
+	int tagged = 0;
+	int opcode = -1;
+	int rqtype = 0;
+	int send_inv = 0;
+
+	if (rsp_msg) {
+		status = CQE_STATUS(rsp_msg->cqe);
+		opcode = CQE_OPCODE(rsp_msg->cqe);
+		rqtype = RQ_TYPE(rsp_msg->cqe);
+		send_inv = (opcode == T3_SEND_WITH_INV) ||
+		           (opcode == T3_SEND_WITH_SE_INV);
+		tagged = (opcode == T3_RDMA_WRITE) ||
+			 (rqtype && (opcode == T3_READ_RESP));
+	}
+
+	switch (status) {
 	case TPT_ERR_STAG:
-		if (tagged == 1) {
-			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
-			*ecode = DDPT_INV_STAG;
-		} else if (tagged == 2) {
+		if (send_inv) {
+			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+			*ecode = RDMAP_CANT_INV_STAG;
+		} else {
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*ecode = RDMAP_INV_STAG;
 		}
 		break;
 	case TPT_ERR_PDID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		if ((opcode == T3_SEND_WITH_INV) ||
+		    (opcode == T3_SEND_WITH_SE_INV))
+			*ecode = RDMAP_CANT_INV_STAG;
+		else
+			*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
 	case TPT_ERR_QPID:
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_STAG_NOT_ASSOC;
+		break;
 	case TPT_ERR_ACCESS:
-		if (tagged == 1) {
-			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
-			*ecode = DDPT_STAG_NOT_ASSOC;
-		} else if (tagged == 2) {
-			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
-			*ecode = RDMAP_STAG_NOT_ASSOC;
-		}
+		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+		*ecode = RDMAP_ACC_VIOL;
 		break;
 	case TPT_ERR_WRAP:
 		*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 		*ecode = RDMAP_TO_WRAP;
 		break;
 	case TPT_ERR_BOUND:
-		if (tagged == 1) {
+		if (tagged) {
 			*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
 			*ecode = DDPT_BASE_BOUNDS;
-		} else if (tagged == 2) {
+		} else {
 			*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
 			*ecode = RDMAP_BASE_BOUNDS;
-		} else {
-			*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
-			*ecode = DDPU_MSG_TOOBIG;
 		}
 		break;
 	case TPT_ERR_INVALIDATE_SHARED_MR:
@@ -591,8 +610,6 @@ int iwch_post_terminate(struct iwch_qp *
 {
 	union t3_wr *wqe;
 	struct terminate_message *term;
-	int status;
-	int tagged = 0;
 	struct sk_buff *skb;
 
 	PDBG("%s %d\n", __FUNCTION__, __LINE__);
@@ -610,17 +627,7 @@ int iwch_post_terminate(struct iwch_qp *
 
 	/* immediate data starts here. */
 	term = (struct terminate_message *)wqe->send.sgl;
-	if (rsp_msg) {
-		status = CQE_STATUS(rsp_msg->cqe);
-		if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)
-			tagged = 1;
-		if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) ||
-		    (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP))
-			tagged = 2;
-	} else {
-		status = TPT_ERR_INTERNAL_ERR;
-	}
-	build_term_codes(status, &term->layer_etype, &term->ecode, tagged);
+	build_term_codes(rsp_msg, &term->layer_etype, &term->ecode);
 	build_fw_riwrh((void *)wqe, T3_WR_SEND,
 		       T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
 		       qhp->ep->hwtid, 5);
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 82ded44..10fb8fb 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -106,6 +106,7 @@ struct ehca_shca {
 	struct ehca_mr *maxmr;
 	struct ehca_pd *pd;
 	struct h_galpas galpas;
+	struct mutex modify_mutex;
 };
 
 struct ehca_pd {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index e2cdc1a..67f0670 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -113,7 +113,7 @@ struct ehca_qp* ehca_cq_get_qp(struct eh
 	return ret;
 }
 
-struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
 			     struct ib_ucontext *context,
 			     struct ib_udata *udata)
 {
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index 30eb45d..32b55a4 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -147,6 +147,7 @@ int ehca_query_port(struct ib_device *ib
 		break;
 	}
 
+	props->port_cap_flags  = rblock->capability_mask;
 	props->gid_tbl_len     = rblock->gid_tbl_len;
 	props->max_msg_sz      = rblock->max_msg_sz;
 	props->bad_pkey_cntr   = rblock->bad_pkey_cntr;
@@ -236,10 +237,60 @@ query_gid1:
 	return ret;
 }
 
+const u32 allowed_port_caps = (
+	IB_PORT_SM | IB_PORT_LED_INFO_SUP | IB_PORT_CM_SUP |
+	IB_PORT_SNMP_TUNNEL_SUP | IB_PORT_DEVICE_MGMT_SUP |
+	IB_PORT_VENDOR_CLASS_SUP);
+
 int ehca_modify_port(struct ib_device *ibdev,
 		     u8 port, int port_modify_mask,
 		     struct ib_port_modify *props)
 {
-	/* Not implemented yet */
-	return -EFAULT;
+	int ret = 0;
+	struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+	struct hipz_query_port *rblock;
+	u32 cap;
+	u64 hret;
+
+	if ((props->set_port_cap_mask | props->clr_port_cap_mask)
+	    & ~allowed_port_caps) {
+		ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
+			 "set=%x  clr=%x  allowed=%x", props->set_port_cap_mask,
+			 props->clr_port_cap_mask, allowed_port_caps);
+		return -EINVAL;
+	}
+
+	if (mutex_lock_interruptible(&shca->modify_mutex))
+                return -ERESTARTSYS;
+
+	rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+	if (!rblock) {
+		ehca_err(&shca->ib_device,  "Can't allocate rblock memory.");
+		ret = -ENOMEM;
+		goto modify_port1;
+	}
+
+	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 modify_port2;
+	}
+
+	cap = (rblock->capability_mask | props->set_port_cap_mask)
+		& ~props->clr_port_cap_mask;
+
+	hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
+				  cap, props->init_type, port_modify_mask);
+	if (hret != H_SUCCESS) {
+		ehca_err(&shca->ib_device, "Modify port failed  hret=%lx", hret);
+		ret = -EINVAL;
+	}
+
+modify_port2:
+	ehca_free_fw_ctrlblock(rblock);
+
+modify_port1:
+        mutex_unlock(&shca->modify_mutex);
+
+	return ret;
 }
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 95fd59f..e14b029 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -123,7 +123,7 @@ int ehca_destroy_eq(struct ehca_shca *sh
 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_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
 			     struct ib_ucontext *context,
 			     struct ib_udata *udata);
 
@@ -135,7 +135,7 @@ int ehca_poll_cq(struct ib_cq *cq, int n
 
 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);
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags);
 
 struct ib_qp *ehca_create_qp(struct ib_pd *pd,
 			     struct ib_qp_init_attr *init_attr,
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 059da96..fe90e74 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -313,6 +313,7 @@ int ehca_init_device(struct ehca_shca *s
 
 	shca->ib_device.node_type           = RDMA_NODE_IB_CA;
 	shca->ib_device.phys_port_cnt       = shca->num_ports;
+	shca->ib_device.num_comp_vectors    = 1;
 	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;
@@ -375,7 +376,7 @@ static int ehca_create_aqp1(struct ehca_
 		return -EPERM;
 	}
 
-	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
 	if (IS_ERR(ibcq)) {
 		ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
 		return PTR_ERR(ibcq);
@@ -565,11 +566,11 @@ static int __devinit ehca_probe(struct i
 				const struct of_device_id *id)
 {
 	struct ehca_shca *shca;
-	u64 *handle;
+	const u64 *handle;
 	struct ib_pd *ibpd;
 	int ret;
 
-	handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+	handle = of_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);
@@ -587,6 +588,7 @@ static int __devinit ehca_probe(struct i
 		ehca_gen_err("Cannot allocate shca memory.");
 		return -ENOMEM;
 	}
+	mutex_init(&shca->modify_mutex);
 
 	shca->ibmebus_dev = dev;
 	shca->ipz_hca_handle.handle = *handle;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 08d3f89..caec9de 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -634,11 +634,13 @@ poll_cq_exit0:
 	return ret;
 }
 
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
 {
 	struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+	unsigned long spl_flags;
+	int ret = 0;
 
-	switch (cq_notify) {
+	switch (notify_flags & IB_CQ_SOLICITED_MASK) {
 	case IB_CQ_SOLICITED:
 		hipz_set_cqx_n0(my_cq, 1);
 		break;
@@ -649,5 +651,11 @@ int ehca_req_notify_cq(struct ib_cq *cq,
 		return -EINVAL;
 	}
 
-	return 0;
+	if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+		spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+		ret = ipz_qeit_is_valid(&my_cq->ipz_queue);
+		spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+	}
+
+	return ret;
 }
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 3fb46e6..b564fcd 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -70,6 +70,10 @@ #define H_ALL_RES_QP_ACT_RECV_SGE       
 #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)
 
+#define H_MP_INIT_TYPE                  EHCA_BMASK_IBM(44, 47)
+#define H_MP_SHUTDOWN                   EHCA_BMASK_IBM(48, 48)
+#define H_MP_RESET_QKEY_CTR             EHCA_BMASK_IBM(49, 49)
+
 /* direct access qp controls */
 #define DAQP_CTRL_ENABLE    0x01
 #define DAQP_CTRL_SEND_COMP 0x20
@@ -364,6 +368,26 @@ u64 hipz_h_query_port(const struct ipz_a
 	return ret;
 }
 
+u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle,
+		       const u8 port_id, const u32 port_cap,
+		       const u8 init_type, const int modify_mask)
+{
+	u64 port_attributes = port_cap;
+
+	if (modify_mask & IB_PORT_SHUTDOWN)
+		port_attributes |= EHCA_BMASK_SET(H_MP_SHUTDOWN, 1);
+	if (modify_mask & IB_PORT_INIT_TYPE)
+		port_attributes |= EHCA_BMASK_SET(H_MP_INIT_TYPE, init_type);
+	if (modify_mask & IB_PORT_RESET_QKEY_CNTR)
+		port_attributes |= EHCA_BMASK_SET(H_MP_RESET_QKEY_CTR, 1);
+
+	return ehca_plpar_hcall_norets(H_MODIFY_PORT,
+				       adapter_handle.handle, /* r4 */
+				       port_id,               /* r5 */
+				       port_attributes,       /* r6 */
+				       0, 0, 0, 0);
+}
+
 u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
 		     struct hipz_query_hca *query_hca_rblock)
 {
diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h
index 587ebd4..2869f7d 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.h
+++ b/drivers/infiniband/hw/ehca/hcp_if.h
@@ -85,6 +85,10 @@ u64 hipz_h_query_port(const struct ipz_a
 		      const u8 port_id,
 		      struct hipz_query_port *query_port_response_block);
 
+u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle,
+		       const u8 port_id, const u32 port_cap,
+		       const u8 init_type, const int modify_mask);
+
 u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
 		     struct hipz_query_hca *query_hca_rblock);
 
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 8199c45..57f141a 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -140,6 +140,14 @@ static inline void *ipz_qeit_get_inc_val
 	return cqe;
 }
 
+static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
+{
+	struct ehca_cqe *cqe = ipz_qeit_get(queue);
+	u32 cqe_flags = cqe->cqe_flags;
+
+	return cqe_flags >> 7 == (queue->toggle_state & 1);
+}
+
 /*
  * returns and resets Queue Entry iterator
  * returns address (kv) of first Queue Entry
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 54139d3..10c008f 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. 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
@@ -78,6 +78,8 @@ #define IPATH_IB_LINKACTIVE		2
 #define IPATH_IB_LINKINIT		3
 #define IPATH_IB_LINKDOWN_SLEEP		4
 #define IPATH_IB_LINKDOWN_DISABLE	5
+#define IPATH_IB_LINK_LOOPBACK	6 /* enable local loopback */
+#define IPATH_IB_LINK_EXTERNAL	7 /* normal, disable local loopback */
 
 /*
  * stats maintained by the driver.  For now, at least, this is global
@@ -316,11 +318,17 @@ struct ipath_base_info {
 	/* 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 */
+	/* shared memory pages for subports if port is shared */
 	__u64 spi_subport_uregbase;
 	__u64 spi_subport_rcvegrbuf;
 	__u64 spi_subport_rcvhdr_base;
 
+	/* shared memory page for hardware port if it is shared */
+	__u64 spi_port_uregbase;
+	__u64 spi_port_rcvegrbuf;
+	__u64 spi_port_rcvhdr_base;
+	__u64 spi_port_rcvhdr_tailaddr;
+
 } __attribute__ ((aligned(8)));
 
 
@@ -344,7 +352,7 @@ #define IPATH_USER_SWMAJOR 1
  * may not be implemented; the user code must deal with this if it
  * cares, or it must abort after initialization reports the difference.
  */
-#define IPATH_USER_SWMINOR 3
+#define IPATH_USER_SWMINOR 5
 
 #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
 
@@ -418,11 +426,14 @@ #define IPATH_CMD_RECV_CTRL	18	/* contro
 #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_SLAVE_INFO	22	/* return info on slave processes (for old user code) */
 #define IPATH_CMD_ASSIGN_PORT	23	/* allocate HCA and port */
 #define IPATH_CMD_USER_INIT 	24	/* set up userspace */
+#define IPATH_CMD_UNUSED_1	25
+#define IPATH_CMD_UNUSED_2	26
+#define IPATH_CMD_PIOAVAILUPD	27	/* force an update of PIOAvail reg */
 
-#define IPATH_CMD_MAX		24
+#define IPATH_CMD_MAX		27
 
 struct ipath_port_info {
 	__u32 num_active;	/* number of active units */
@@ -430,7 +441,7 @@ struct ipath_port_info {
 	__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 */
+	__u16 num_subports;	/* number of subports opened on port */
 };
 
 struct ipath_tid_info {
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index 87462e0..3e9241b 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -76,7 +76,20 @@ void ipath_cq_enter(struct ipath_cq *cq,
 		}
 		return;
 	}
-	wc->queue[head] = *entry;
+	wc->queue[head].wr_id = entry->wr_id;
+	wc->queue[head].status = entry->status;
+	wc->queue[head].opcode = entry->opcode;
+	wc->queue[head].vendor_err = entry->vendor_err;
+	wc->queue[head].byte_len = entry->byte_len;
+	wc->queue[head].imm_data = (__u32 __force)entry->imm_data;
+	wc->queue[head].qp_num = entry->qp->qp_num;
+	wc->queue[head].src_qp = entry->src_qp;
+	wc->queue[head].wc_flags = entry->wc_flags;
+	wc->queue[head].pkey_index = entry->pkey_index;
+	wc->queue[head].slid = entry->slid;
+	wc->queue[head].sl = entry->sl;
+	wc->queue[head].dlid_path_bits = entry->dlid_path_bits;
+	wc->queue[head].port_num = entry->port_num;
 	wc->head = next;
 
 	if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -122,9 +135,30 @@ int ipath_poll_cq(struct ib_cq *ibcq, in
 	if (tail > (u32) cq->ibcq.cqe)
 		tail = (u32) cq->ibcq.cqe;
 	for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
+		struct ipath_qp *qp;
+
 		if (tail == wc->head)
 			break;
-		*entry = wc->queue[tail];
+
+		qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
+				      wc->queue[tail].qp_num);
+		entry->qp = &qp->ibqp;
+		if (atomic_dec_and_test(&qp->refcount))
+			wake_up(&qp->wait);
+
+		entry->wr_id = wc->queue[tail].wr_id;
+		entry->status = wc->queue[tail].status;
+		entry->opcode = wc->queue[tail].opcode;
+		entry->vendor_err = wc->queue[tail].vendor_err;
+		entry->byte_len = wc->queue[tail].byte_len;
+		entry->imm_data = wc->queue[tail].imm_data;
+		entry->src_qp = wc->queue[tail].src_qp;
+		entry->wc_flags = wc->queue[tail].wc_flags;
+		entry->pkey_index = wc->queue[tail].pkey_index;
+		entry->slid = wc->queue[tail].slid;
+		entry->sl = wc->queue[tail].sl;
+		entry->dlid_path_bits = wc->queue[tail].dlid_path_bits;
+		entry->port_num = wc->queue[tail].port_num;
 		if (tail >= cq->ibcq.cqe)
 			tail = 0;
 		else
@@ -170,7 +204,7 @@ static void send_complete(unsigned long 
  *
  * Called by ib_create_cq() in the generic verbs code.
  */
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
 			      struct ib_ucontext *context,
 			      struct ib_udata *udata)
 {
@@ -209,33 +243,21 @@ struct ib_cq *ipath_create_cq(struct ib_
 	 * See ipath_mmap() for details.
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		struct ipath_mmap_info *ip;
-		__u64 offset = (__u64) wc;
 		int err;
+		u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
 
-		err = ib_copy_to_udata(udata, &offset, sizeof(offset));
-		if (err) {
-			ret = ERR_PTR(err);
+		cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+		if (!cq->ip) {
+			ret = ERR_PTR(-ENOMEM);
 			goto bail_wc;
 		}
 
-		/* Allocate info for ipath_mmap(). */
-		ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-		if (!ip) {
-			ret = ERR_PTR(-ENOMEM);
-			goto bail_wc;
+		err = ib_copy_to_udata(udata, &cq->ip->offset,
+				       sizeof(cq->ip->offset));
+		if (err) {
+			ret = ERR_PTR(err);
+			goto bail_ip;
 		}
-		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;
 
@@ -243,12 +265,18 @@ struct ib_cq *ipath_create_cq(struct ib_
 	if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
 		spin_unlock(&dev->n_cqs_lock);
 		ret = ERR_PTR(-ENOMEM);
-		goto bail_wc;
+		goto bail_ip;
 	}
 
 	dev->n_cqs_allocated++;
 	spin_unlock(&dev->n_cqs_lock);
 
+	if (cq->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	/*
 	 * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
 	 * The number of entries should be >= the number requested or return
@@ -267,12 +295,12 @@ struct ib_cq *ipath_create_cq(struct ib_
 
 	goto done;
 
+bail_ip:
+	kfree(cq->ip);
 bail_wc:
 	vfree(wc);
-
 bail_cq:
 	kfree(cq);
-
 done:
 	return ret;
 }
@@ -306,17 +334,18 @@ int ipath_destroy_cq(struct ib_cq *ibcq)
 /**
  * ipath_req_notify_cq - change the notification type for a completion queue
  * @ibcq: the completion queue
- * @notify: the type of notification to request
+ * @notify_flags: the type of notification to request
  *
  * Returns 0 for success.
  *
  * This may be called from interrupt context.  Also called by
  * ib_req_notify_cq() in the generic verbs code.
  */
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
 {
 	struct ipath_cq *cq = to_icq(ibcq);
 	unsigned long flags;
+	int ret = 0;
 
 	spin_lock_irqsave(&cq->lock, flags);
 	/*
@@ -324,9 +353,15 @@ int ipath_req_notify_cq(struct ib_cq *ib
 	 * 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;
+		cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
+
+	if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+	    cq->queue->head != cq->queue->tail)
+		ret = 1;
+
 	spin_unlock_irqrestore(&cq->lock, flags);
-	return 0;
+
+	return ret;
 }
 
 /**
@@ -409,13 +444,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, 
 	if (cq->ip) {
 		struct ipath_ibdev *dev = to_idev(ibcq->device);
 		struct ipath_mmap_info *ip = cq->ip;
+		u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
 
-		ip->obj = wc;
-		ip->size = PAGE_ALIGN(sizeof(*wc) +
-				      sizeof(struct ib_wc) * cqe);
+		ipath_update_mmap_info(dev, ip, s, wc);
 		spin_lock_irq(&dev->pending_lock);
-		ip->next = dev->pending_mmaps;
-		dev->pending_mmaps = ip;
+		if (list_empty(&ip->pending_mmaps))
+			list_add(&ip->pending_mmaps, &dev->pending_mmaps);
 		spin_unlock_irq(&dev->pending_lock);
 	}
 
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
index df69f0d..42bfbdb 100644
--- a/drivers/infiniband/hw/ipath/ipath_debug.h
+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
@@ -57,6 +57,7 @@ #define __IPATH_PKTDBG      0x80	/* prin
 #define __IPATH_PROCDBG     0x100
 /* print mmap/nopage stuff, not using VDBG any more */
 #define __IPATH_MMDBG       0x200
+#define __IPATH_ERRPKTDBG   0x400
 #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 */
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 0f13a21..63e8368 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -296,7 +296,7 @@ static int ipath_diag_open(struct inode 
 	}
 
 	fp->private_data = dd;
-	ipath_diag_inuse = 1;
+	ipath_diag_inuse = -2;
 	diag_set_link = 0;
 	ret = 0;
 
@@ -461,6 +461,8 @@ static ssize_t ipath_diag_read(struct fi
 	else if ((count % 4) || (*off % 4))
 		/* address or length is not 32-bit aligned, hence invalid */
 		ret = -EINVAL;
+	else if (ipath_diag_inuse < 1 && (*off || count != 8))
+		ret = -EINVAL;  /* prevent cat /dev/ipath_diag* */
 	else if ((count % 8) || (*off % 8))
 		/* address or length not 64-bit aligned; do 32-bit reads */
 		ret = ipath_read_umem32(dd, data, kreg_base + *off, count);
@@ -470,6 +472,8 @@ static ssize_t ipath_diag_read(struct fi
 	if (ret >= 0) {
 		*off += count;
 		ret = count;
+		if (ipath_diag_inuse == -2)
+			ipath_diag_inuse++;
 	}
 
 	return ret;
@@ -489,6 +493,9 @@ static ssize_t ipath_diag_write(struct f
 	else if ((count % 4) || (*off % 4))
 		/* address or length is not 32-bit aligned, hence invalid */
 		ret = -EINVAL;
+	else if ((ipath_diag_inuse == -1 && (*off || count != 8)) ||
+		 ipath_diag_inuse == -2)  /* read qw off 0, write qw off 0 */
+		ret = -EINVAL;  /* before any other write allowed */
 	else if ((count % 8) || (*off % 8))
 		/* address or length not 64-bit aligned; do 32-bit writes */
 		ret = ipath_write_umem32(dd, kreg_base + *off, data, count);
@@ -498,6 +505,8 @@ static ssize_t ipath_diag_write(struct f
 	if (ret >= 0) {
 		*off += count;
 		ret = count;
+		if (ipath_diag_inuse == -1)
+			ipath_diag_inuse = 1; /* all read/write OK now */
 	}
 
 	return ret;
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index ae7f21a..e3a2232 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -390,15 +390,23 @@ static int __devinit ipath_init_one(stru
 
 	/* setup the chip-specific functions, as early as possible. */
 	switch (ent->device) {
-#ifdef CONFIG_HT_IRQ
 	case PCI_DEVICE_ID_INFINIPATH_HT:
+#ifdef CONFIG_HT_IRQ
 		ipath_init_iba6110_funcs(dd);
 		break;
+#else
+		ipath_dev_err(dd, "QLogic HT device 0x%x cannot work if "
+			      "CONFIG_HT_IRQ is not enabled\n", ent->device);
+		return -ENODEV;
 #endif
-#ifdef CONFIG_PCI_MSI
 	case PCI_DEVICE_ID_INFINIPATH_PE800:
+#ifdef CONFIG_PCI_MSI
 		ipath_init_iba6120_funcs(dd);
 		break;
+#else
+		ipath_dev_err(dd, "QLogic PCIE device 0x%x cannot work if "
+			      "CONFIG_PCI_MSI is not enabled\n", ent->device);
+		return -ENODEV;
 #endif
 	default:
 		ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
@@ -486,7 +494,7 @@ #endif
 
 	ret = ipath_init_chip(dd, 0);	/* do the chip-specific init */
 	if (ret)
-		goto bail_iounmap;
+		goto bail_irqsetup;
 
 	ret = ipath_enable_wc(dd);
 
@@ -505,6 +513,9 @@ #endif
 
 	goto bail;
 
+bail_irqsetup:
+	if (pdev->irq) free_irq(pdev->irq, dd);
+
 bail_iounmap:
 	iounmap((volatile void __iomem *) dd->ipath_kregbase);
 
@@ -525,8 +536,6 @@ static void __devexit cleanup_device(str
 {
 	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;
@@ -594,8 +603,9 @@ static void __devexit cleanup_device(str
 
 		ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
 			   dd->ipath_pageshadow);
-		vfree(dd->ipath_pageshadow);
+		tmpp = dd->ipath_pageshadow;
 		dd->ipath_pageshadow = NULL;
+		vfree(tmpp);
 	}
 
 	/*
@@ -622,6 +632,12 @@ static void __devexit ipath_remove_one(s
 
 	ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
 
+	/*
+	 * disable the IB link early, to be sure no new packets arrive, which
+	 * complicates the shutdown process
+	 */
+	ipath_shutdown_device(dd);
+
 	if (dd->verbs_dev)
 		ipath_unregister_ib_device(dd->verbs_dev);
 
@@ -754,9 +770,42 @@ static int ipath_wait_linkstate(struct i
 	return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT;
 }
 
-void ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
+/*
+ * Decode the error status into strings, deciding whether to always
+ * print * it or not depending on "normal packet errors" vs everything
+ * else.   Return 1 if "real" errors, otherwise 0 if only packet
+ * errors, so caller can decide what to print with the string.
+ */
+int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
 {
+	int iserr = 1;
 	*buf = '\0';
+	if (err & INFINIPATH_E_PKTERRS) {
+		if (!(err & ~INFINIPATH_E_PKTERRS))
+			iserr = 0; // if only packet errors.
+		if (ipath_debug & __IPATH_ERRPKTDBG) {
+			if (err & INFINIPATH_E_REBP)
+				strlcat(buf, "EBP ", blen);
+			if (err & INFINIPATH_E_RVCRC)
+				strlcat(buf, "VCRC ", blen);
+			if (err & INFINIPATH_E_RICRC) {
+				strlcat(buf, "CRC ", blen);
+				// clear for check below, so only once
+				err &= INFINIPATH_E_RICRC;
+			}
+			if (err & INFINIPATH_E_RSHORTPKTLEN)
+				strlcat(buf, "rshortpktlen ", blen);
+			if (err & INFINIPATH_E_SDROPPEDDATAPKT)
+				strlcat(buf, "sdroppeddatapkt ", blen);
+			if (err & INFINIPATH_E_SPKTLEN)
+				strlcat(buf, "spktlen ", blen);
+		}
+		if ((err & INFINIPATH_E_RICRC) &&
+			!(err&(INFINIPATH_E_RVCRC|INFINIPATH_E_REBP)))
+			strlcat(buf, "CRC ", blen);
+		if (!iserr)
+			goto done;
+	}
 	if (err & INFINIPATH_E_RHDRLEN)
 		strlcat(buf, "rhdrlen ", blen);
 	if (err & INFINIPATH_E_RBADTID)
@@ -767,12 +816,12 @@ void ipath_decode_err(char *buf, size_t 
 		strlcat(buf, "rhdr ", blen);
 	if (err & INFINIPATH_E_RLONGPKTLEN)
 		strlcat(buf, "rlongpktlen ", blen);
-	if (err & INFINIPATH_E_RSHORTPKTLEN)
-		strlcat(buf, "rshortpktlen ", blen);
 	if (err & INFINIPATH_E_RMAXPKTLEN)
 		strlcat(buf, "rmaxpktlen ", blen);
 	if (err & INFINIPATH_E_RMINPKTLEN)
 		strlcat(buf, "rminpktlen ", blen);
+	if (err & INFINIPATH_E_SMINPKTLEN)
+		strlcat(buf, "sminpktlen ", blen);
 	if (err & INFINIPATH_E_RFORMATERR)
 		strlcat(buf, "rformaterr ", blen);
 	if (err & INFINIPATH_E_RUNSUPVL)
@@ -781,32 +830,20 @@ void ipath_decode_err(char *buf, size_t 
 		strlcat(buf, "runexpchar ", blen);
 	if (err & INFINIPATH_E_RIBFLOW)
 		strlcat(buf, "ribflow ", blen);
-	if (err & INFINIPATH_E_REBP)
-		strlcat(buf, "EBP ", blen);
 	if (err & INFINIPATH_E_SUNDERRUN)
 		strlcat(buf, "sunderrun ", blen);
 	if (err & INFINIPATH_E_SPIOARMLAUNCH)
 		strlcat(buf, "spioarmlaunch ", blen);
 	if (err & INFINIPATH_E_SUNEXPERRPKTNUM)
 		strlcat(buf, "sunexperrpktnum ", blen);
-	if (err & INFINIPATH_E_SDROPPEDDATAPKT)
-		strlcat(buf, "sdroppeddatapkt ", blen);
 	if (err & INFINIPATH_E_SDROPPEDSMPPKT)
 		strlcat(buf, "sdroppedsmppkt ", blen);
 	if (err & INFINIPATH_E_SMAXPKTLEN)
 		strlcat(buf, "smaxpktlen ", blen);
-	if (err & INFINIPATH_E_SMINPKTLEN)
-		strlcat(buf, "sminpktlen ", blen);
 	if (err & INFINIPATH_E_SUNSUPVL)
 		strlcat(buf, "sunsupVL ", blen);
-	if (err & INFINIPATH_E_SPKTLEN)
-		strlcat(buf, "spktlen ", blen);
 	if (err & INFINIPATH_E_INVALIDADDR)
 		strlcat(buf, "invalidaddr ", blen);
-	if (err & INFINIPATH_E_RICRC)
-		strlcat(buf, "CRC ", blen);
-	if (err & INFINIPATH_E_RVCRC)
-		strlcat(buf, "VCRC ", blen);
 	if (err & INFINIPATH_E_RRCVEGRFULL)
 		strlcat(buf, "rcvegrfull ", blen);
 	if (err & INFINIPATH_E_RRCVHDRFULL)
@@ -819,6 +856,8 @@ void ipath_decode_err(char *buf, size_t 
 		strlcat(buf, "hardware ", blen);
 	if (err & INFINIPATH_E_RESET)
 		strlcat(buf, "reset ", blen);
+done:
+	return iserr;
 }
 
 /**
@@ -1662,6 +1701,22 @@ int ipath_set_linkstate(struct ipath_dev
 		lstate = IPATH_LINKACTIVE;
 		break;
 
+	case IPATH_IB_LINK_LOOPBACK:
+		dev_info(&dd->pcidev->dev, "Enabling IB local loopback\n");
+		dd->ipath_ibcctrl |= INFINIPATH_IBCC_LOOPBACK;
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+				 dd->ipath_ibcctrl);
+		ret = 0;
+		goto bail; // no state change to wait for
+
+	case IPATH_IB_LINK_EXTERNAL:
+		dev_info(&dd->pcidev->dev, "Disabling IB local loopback (normal)\n");
+		dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LOOPBACK;
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+				 dd->ipath_ibcctrl);
+		ret = 0;
+		goto bail; // no state change to wait for
+
 	default:
 		ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
 		ret = -EINVAL;
@@ -1765,29 +1820,6 @@ int ipath_set_lid(struct ipath_devdata *
 	return 0;
 }
 
-/**
- * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register
- * @dd: the infinipath device
- * @regno: the register number to read
- * @port: the port containing the register
- *
- * Registers that vary with the chip implementation constants (port)
- * use this routine.
- */
-u64 ipath_read_kreg64_port(const struct ipath_devdata *dd, ipath_kreg regno,
-			   unsigned port)
-{
-	u16 where;
-
-	if (port < dd->ipath_portcnt &&
-	    (regno == dd->ipath_kregs->kr_rcvhdraddr ||
-	     regno == dd->ipath_kregs->kr_rcvhdrtailaddr))
-		where = regno + port;
-	else
-		where = -1;
-
-	return ipath_read_kreg64(dd, where);
-}
 
 /**
  * ipath_write_kreg_port - write a device's per-port 64-bit kernel register
@@ -1973,7 +2005,8 @@ static int __init infinipath_init(void)
 {
 	int ret;
 
-	ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version);
+	if (ipath_debug & __IPATH_DBG)
+		printk(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version);
 
 	/*
 	 * These must be called before the driver is registered with
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index a4019a6..030185f 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -626,6 +626,10 @@ void ipath_get_eeprom_info(struct ipath_
 	} else
 		memcpy(dd->ipath_serial, ifp->if_serial,
 		       sizeof ifp->if_serial);
+	if (!strstr(ifp->if_comment, "Tested successfully"))
+		ipath_dev_err(dd, "Board SN %s did not pass functional "
+			"test: %s\n", dd->ipath_serial,
+			ifp->if_comment);
 
 	ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n",
 		   (unsigned long long) be64_to_cpu(dd->ipath_guid));
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 5d64ff8..1272aaf 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. 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
@@ -41,12 +41,6 @@ #include <asm/pgtable.h>
 #include "ipath_kernel.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,
@@ -63,6 +57,24 @@ static const struct file_operations ipat
 	.mmap = ipath_mmap
 };
 
+/*
+ * Convert kernel virtual addresses to physical addresses so they don't
+ * potentially conflict with the chip addresses used as mmap offsets.
+ * It doesn't really matter what mmap offset we use as long as we can
+ * interpret it correctly.
+ */
+static u64 cvt_kvaddr(void *p)
+{
+	struct page *page;
+	u64 paddr = 0;
+
+	page = vmalloc_to_page(p);
+	if (page)
+		paddr = page_to_pfn(page) << PAGE_SHIFT;
+
+	return paddr;
+}
+
 static int ipath_get_base_info(struct file *fp,
 			       void __user *ubase, size_t ubase_size)
 {
@@ -87,7 +99,7 @@ static int ipath_get_base_info(struct fi
 	sz = sizeof(*kinfo);
 	/* If port sharing is not requested, allow the old size structure */
 	if (!shared)
-		sz -= 3 * sizeof(u64);
+		sz -= 7 * sizeof(u64);
 	if (ubase_size < sz) {
 		ipath_cdbg(PROC,
 			   "Base size %zu, need %zu (version mismatch?)\n",
@@ -165,24 +177,41 @@ static int ipath_get_base_info(struct fi
 		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;
+	}
+	if (shared) {
+		kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
+			dd->ipath_palign * pd->port_port;
+		kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
+		kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
+		kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
 
-		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_uregbase = cvt_kvaddr(pd->subport_uregbase +
+			PAGE_SIZE * subport_fp(fp));
+
+		kinfo->spi_rcvhdr_base = cvt_kvaddr(pd->subport_rcvhdr_base +
+			pd->port_rcvhdrq_size * subport_fp(fp));
+		kinfo->spi_rcvhdr_tailaddr = 0;
+		kinfo->spi_rcv_egrbufs = cvt_kvaddr(pd->subport_rcvegrbuf +
+			pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size *
+			subport_fp(fp));
+
+		kinfo->spi_subport_uregbase =
+			cvt_kvaddr(pd->subport_uregbase);
+		kinfo->spi_subport_rcvegrbuf =
+			cvt_kvaddr(pd->subport_rcvegrbuf);
+		kinfo->spi_subport_rcvhdr_base =
+			cvt_kvaddr(pd->subport_rcvhdr_base);
+		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);
 	}
 
 	kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
@@ -199,20 +228,10 @@ static int ipath_get_base_info(struct fi
 
 	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)))
+	sz = (ubase_size < sizeof(*kinfo)) ? ubase_size : sizeof(*kinfo);
+	if (copy_to_user(ubase, kinfo, sz))
 		ret = -EFAULT;
 
 bail:
@@ -1132,67 +1151,55 @@ static int mmap_kvaddr(struct vm_area_st
 	struct ipath_devdata *dd;
 	void *addr;
 	size_t size;
-	int ret;
+	int ret = 0;
 
 	/* If the port is not shared, all addresses should be physical */
-	if (!pd->port_subport_cnt) {
-		ret = -EINVAL;
+	if (!pd->port_subport_cnt)
 		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.
+	 * Each process has all the subport uregbase, rcvhdrq, and
+	 * rcvegrbufs mmapped - as an array for all the processes,
+	 * and also separately for this process.
 	 */
-	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;
+	if (pgaddr == cvt_kvaddr(pd->subport_uregbase)) {
+		addr = pd->subport_uregbase;
+		size = PAGE_SIZE * pd->port_subport_cnt;
+	} else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base)) {
+		addr = pd->subport_rcvhdr_base;
+		size = pd->port_rcvhdrq_size * pd->port_subport_cnt;
+	} else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf)) {
+		addr = pd->subport_rcvegrbuf;
+		size *= pd->port_subport_cnt;
+        } else if (pgaddr == cvt_kvaddr(pd->subport_uregbase +
+                                        PAGE_SIZE * subport)) {
+                addr = pd->subport_uregbase + PAGE_SIZE * subport;
+                size = PAGE_SIZE;
+        } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base +
+                                pd->port_rcvhdrq_size * subport)) {
+                addr = pd->subport_rcvhdr_base +
+                        pd->port_rcvhdrq_size * subport;
+                size = pd->port_rcvhdrq_size;
+        } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf +
+                               size * subport)) {
+                addr = pd->subport_rcvegrbuf + size * subport;
+                /* 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;
@@ -1205,7 +1212,7 @@ static int mmap_kvaddr(struct vm_area_st
 	vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
 	vma->vm_ops = &ipath_file_vm_ops;
 	vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
-	ret = 0;
+	ret = 1;
 
 bail:
 	return ret;
@@ -1265,19 +1272,20 @@ static int ipath_mmap(struct file *fp, s
 	 * 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));
+	ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
+	if (ret) {
+		if (ret > 0)
+			ret = 0;
 		goto bail;
 	}
 
+	ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
 	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 +
@@ -1286,7 +1294,6 @@ static int ipath_mmap(struct file *fp, s
 		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;
 	}
@@ -1300,9 +1307,6 @@ static int ipath_mmap(struct file *fp, s
 		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)
@@ -1400,32 +1404,41 @@ static int init_subports(struct ipath_de
 			 const struct ipath_user_info *uinfo)
 {
 	int ret = 0;
-	unsigned num_slaves;
+	unsigned num_subports;
 	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) {
+
+	/* Old user binaries don't know about new subport implementation */
+	if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR) {
+		dev_info(&dd->pcidev->dev,
+			 "Mismatched user minor version (%d) and driver "
+                         "minor version (%d) while port sharing. Ensure "
+                         "that driver and library are from the same "
+                         "release.\n",
+                         (int) (uinfo->spu_userversion & 0xffff),
+	                 IPATH_USER_SWMINOR);
+		goto bail;
+	}
+	if (uinfo->spu_subport_cnt > INFINIPATH_MAX_SUBPORT) {
 		ret = -EINVAL;
 		goto bail;
 	}
 
-	num_slaves = uinfo->spu_subport_cnt - 1;
-	pd->subport_uregbase = vmalloc(PAGE_SIZE * num_slaves);
+	num_subports = uinfo->spu_subport_cnt;
+	pd->subport_uregbase = vmalloc(PAGE_SIZE * num_subports);
 	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;
+		     sizeof(u32), PAGE_SIZE) * num_subports;
 	pd->subport_rcvhdr_base = vmalloc(size);
 	if (!pd->subport_rcvhdr_base) {
 		ret = -ENOMEM;
@@ -1434,7 +1447,7 @@ static int init_subports(struct ipath_de
 
 	pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks *
 					pd->port_rcvegrbuf_size *
-					num_slaves);
+					num_subports);
 	if (!pd->subport_rcvegrbuf) {
 		ret = -ENOMEM;
 		goto bail_rhdr;
@@ -1443,6 +1456,12 @@ static int init_subports(struct ipath_de
 	pd->port_subport_cnt = uinfo->spu_subport_cnt;
 	pd->port_subport_id = uinfo->spu_subport_id;
 	pd->active_slaves = 1;
+	set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag);
+	memset(pd->subport_uregbase, 0, PAGE_SIZE * num_subports);
+	memset(pd->subport_rcvhdr_base, 0, size);
+	memset(pd->subport_rcvegrbuf, 0, pd->port_rcvegrbuf_chunks *
+				         pd->port_rcvegrbuf_size *
+				         num_subports);
 	goto bail;
 
 bail_rhdr:
@@ -1573,18 +1592,19 @@ static int find_best_unit(struct file *f
 	 */
 	if (!cpus_empty(current->cpus_allowed) &&
 	    !cpus_full(current->cpus_allowed)) {
-		int ncpus = num_online_cpus(), curcpu = -1;
+		int ncpus = num_online_cpus(), curcpu = -1, nset = 0;
 		for (i = 0; i < ncpus; i++)
 			if (cpu_isset(i, current->cpus_allowed)) {
 				ipath_cdbg(PROC, "%s[%u] affinity set for "
-					   "cpu %d\n", current->comm,
-					   current->pid, i);
+					   "cpu %d/%d\n", current->comm,
+					   current->pid, i, ncpus);
 				curcpu = i;
+				nset++;
 			}
-		if (curcpu != -1) {
+		if (curcpu != -1 && nset != ncpus) {
 			if (npresent) {
 				prefunit = curcpu / (ncpus / npresent);
-				ipath_dbg("%s[%u] %d chips, %d cpus, "
+				ipath_cdbg(PROC,"%s[%u] %d chips, %d cpus, "
 					  "%d cpus/chip, select unit %d\n",
 					  current->comm, current->pid,
 					  npresent, ncpus, ncpus / npresent,
@@ -1764,11 +1784,17 @@ static int ipath_do_user_init(struct fil
 			      const struct ipath_user_info *uinfo)
 {
 	int ret;
-	struct ipath_portdata *pd;
+	struct ipath_portdata *pd = port_fp(fp);
 	struct ipath_devdata *dd;
 	u32 head32;
 
-	pd = port_fp(fp);
+	/* Subports don't need to initialize anything since master did it. */
+	if (subport_fp(fp)) {
+		ret = wait_event_interruptible(pd->port_wait,
+			!test_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag));
+		goto done;
+	}
+
 	dd = pd->port_dd;
 
 	if (uinfo->spu_rcvhdrsize) {
@@ -1826,6 +1852,11 @@ static int ipath_do_user_init(struct fil
 			 dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
 			 dd->ipath_rcvctrl);
+	/* Notify any waiting slaves */
+	if (pd->port_subport_cnt) {
+		clear_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag);
+		wake_up(&pd->port_wait);
+	}
 done:
 	return ret;
 }
@@ -2017,6 +2048,17 @@ static int ipath_get_slave_info(struct i
 	return ret;
 }
 
+static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
+{
+	u64 reg = dd->ipath_sendctrl;
+
+	clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+
+	return 0;
+}
+
 static ssize_t ipath_write(struct file *fp, const char __user *data,
 			   size_t count, loff_t *off)
 {
@@ -2071,27 +2113,35 @@ static ssize_t ipath_write(struct file *
 		dest = &cmd.cmd.part_key;
 		src = &ucmd->cmd.part_key;
 		break;
-	case IPATH_CMD_SLAVE_INFO:
+	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;
+	case IPATH_CMD_PIOAVAILUPD:	// force an update of PIOAvail reg
+		copy = 0;
+		src = NULL;
+		dest = NULL;
+		break;
 	default:
 		ret = -EINVAL;
 		goto bail;
 	}
 
-	if ((count - consumed) < copy) {
-		ret = -EINVAL;
-		goto bail;
-	}
+	if (copy) {
+		if ((count - consumed) < copy) {
+			ret = -EINVAL;
+			goto bail;
+		}
 
-	if (copy_from_user(dest, src, copy)) {
-		ret = -EFAULT;
-		goto bail;
+		if (copy_from_user(dest, src, copy)) {
+			ret = -EFAULT;
+			goto bail;
+		}
+
+		consumed += copy;
 	}
 
-	consumed += copy;
 	pd = port_fp(fp);
 	if (!pd && cmd.type != __IPATH_CMD_USER_INIT &&
 		cmd.type != IPATH_CMD_ASSIGN_PORT) {
@@ -2137,11 +2187,14 @@ static ssize_t ipath_write(struct file *
 	case IPATH_CMD_SET_PART_KEY:
 		ret = ipath_set_part_key(pd, cmd.cmd.part_key);
 		break;
-	case IPATH_CMD_SLAVE_INFO:
+	case __IPATH_CMD_SLAVE_INFO:
 		ret = ipath_get_slave_info(pd,
 					   (void __user *) (unsigned long)
 					   cmd.cmd.slave_mask_addr);
 		break;
+	case IPATH_CMD_PIOAVAILUPD:
+		ret = ipath_force_pio_avail_update(pd->port_dd);
+		break;
 	}
 
 	if (ret >= 0)
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index ed55979..ebd5c7b 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -38,7 +38,6 @@ #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/namei.h>
-#include <linux/pci.h>
 
 #include "ipath_kernel.h"
 
@@ -524,7 +523,7 @@ static int ipathfs_fill_super(struct sup
 	int ret;
 
 	static struct tree_descr files[] = {
-		[1] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
+		[2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
 		{""},
 	};
 
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 9934825..4171198 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -43,6 +43,9 @@ #include <linux/htirq.h>
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
 
+static void ipath_setup_ht_setextled(struct ipath_devdata *, u64, u64);
+
+
 /*
  * This lists the InfiniPath registers, in the actual chip layout.
  * This structure should never be directly accessed.
@@ -208,8 +211,8 @@ static const struct ipath_kregs ipath_ht
 	.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(),
+	 * These should not be used directly via ipath_write_kreg64(),
+	 * use them with ipath_write_kreg64_port(),
 	 */
 	.kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
 	.kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0)
@@ -284,6 +287,14 @@ #define INFINIPATH_EXTS_SERDESSEL 0x4
 #define INFINIPATH_EXTS_MEMBIST_ENDTEST     0x0000000000004000
 #define INFINIPATH_EXTS_MEMBIST_CORRECT     0x0000000000008000
 
+
+/* TID entries (memory), HT-only */
+#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL	/* 40 bits valid */
+#define INFINIPATH_RT_VALID 0x8000000000000000ULL
+#define INFINIPATH_RT_ADDR_SHIFT 0
+#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
+#define INFINIPATH_RT_BUFSIZE_SHIFT 48
+
 /*
  * masks and bits that are different in different chips, or present only
  * in one
@@ -402,6 +413,14 @@ static const struct ipath_hwerror_msgs i
 	INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
 };
 
+#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
+		        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
+		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
+#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \
+			  << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)
+
+static int ipath_ht_txe_recover(struct ipath_devdata *);
+
 /**
  * ipath_ht_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
@@ -450,13 +469,12 @@ static void ipath_ht_handle_hwerrors(str
 
 	/*
 	 * make sure we get this much out, unless told to be quiet,
+	 * it's a parity error we may recover from,
 	 * 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))
+	if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY |
+		RXE_EAGER_PARITY)) ||
+		(ipath_debug & __IPATH_VERBDBG))
 		dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
 			 "(cleared)\n", (unsigned long long) hwerrs);
 	dd->ipath_lasthwerror |= hwerrs;
@@ -467,7 +485,7 @@ static void ipath_ht_handle_hwerrors(str
 			      (hwerrs & ~dd->ipath_hwe_bitsextant));
 
 	ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-	if (ctrl & INFINIPATH_C_FREEZEMODE) {
+	if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
 		/*
 		 * parity errors in send memory are recoverable,
 		 * just cancel the send (if indicated in * sendbuffererror),
@@ -476,50 +494,14 @@ static void ipath_ht_handle_hwerrors(str
 		 * 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");
+		if ((hwerrs & TXE_PIO_PARITY) && ipath_ht_txe_recover(dd))
+			hwerrs &= ~TXE_PIO_PARITY;
+		if (hwerrs & RXE_EAGER_PARITY)
+			ipath_dev_err(dd, "RXE parity, Eager TID error is not "
+				"recoverable\n");
+		if (!hwerrs) {
+			ipath_dbg("Clearing freezemode on ignored or "
+				  "recovered hardware error\n");
 			ctrl &= ~INFINIPATH_C_FREEZEMODE;
 			ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
 					 ctrl);
@@ -587,7 +569,39 @@ #define _IPATH_PLL_FAIL (INFINIPATH_HWE_
 				 dd->ipath_hwerrmask);
 	}
 
-	ipath_dev_err(dd, "%s hardware error\n", msg);
+	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.
+		 * force link down, so switch knows, and
+		 * LEDs are turned off
+		 */
+		if (dd->ipath_flags & IPATH_INITTED) {
+			ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
+			ipath_setup_ht_setextled(dd,
+				INFINIPATH_IBCS_L_STATE_DOWN,
+				INFINIPATH_IBCS_LT_STATE_DISABLED);
+			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
+		*msg = 0; /* recovered from all of them */
+	if (*msg)
+		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,
@@ -658,7 +672,8 @@ static int ipath_ht_boardname(struct ipa
 	if (n)
 		snprintf(name, namelen, "%s", n);
 
-	if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
+	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
 		 */
@@ -1163,6 +1178,8 @@ static void ipath_ht_init_hwerrors(struc
 
 	if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
 		ipath_dev_err(dd, "MemBIST did not complete!\n");
+	if (extsval & INFINIPATH_EXTS_MEMBIST_CORRECT)
+		ipath_dbg("MemBIST corrected\n");
 
 	ipath_check_htlink(dd);
 
@@ -1366,6 +1383,9 @@ static void ipath_ht_put_tid(struct ipat
 			     u64 __iomem *tidptr, u32 type,
 			     unsigned long pa)
 {
+	if (!dd->ipath_kregbase)
+		return;
+
 	if (pa != dd->ipath_tidinvalid) {
 		if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {
 			dev_info(&dd->pcidev->dev,
@@ -1382,10 +1402,10 @@ static void ipath_ht_put_tid(struct ipat
 			pa |= lenvalid | INFINIPATH_RT_VALID;
 		}
 	}
-	if (dd->ipath_kregbase)
-		writeq(pa, tidptr);
+	writeq(pa, tidptr);
 }
 
+
 /**
  * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager
  * @dd: the infinipath device
@@ -1515,7 +1535,7 @@ static int ipath_ht_early_init(struct ip
 			 INFINIPATH_S_ABORT);
 
 	ipath_get_eeprom_info(dd);
-	if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
+	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
@@ -1528,6 +1548,24 @@ static int ipath_ht_early_init(struct ip
 	return 0;
 }
 
+
+static int ipath_ht_txe_recover(struct ipath_devdata *dd)
+{
+	int cnt = ++ipath_stats.sps_txeparity;
+	if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
+		if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
+			ipath_dev_err(dd,
+				"Too many attempts to recover from "
+				"TXE parity, giving up\n");
+		return 0;
+	}
+	dev_info(&dd->pcidev->dev,
+		"Recovering from TXE PIO parity error\n");
+	ipath_disarm_senderrbufs(dd, 1);
+	return 1;
+}
+
+
 /**
  * ipath_init_ht_get_base_info - set chip-specific flags for user code
  * @dd: the infinipath device
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 05918e1..1b9c308 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -43,6 +43,8 @@ #include <linux/delay.h>
 #include "ipath_kernel.h"
 #include "ipath_registers.h"
 
+static void ipath_setup_pe_setextled(struct ipath_devdata *, u64, u64);
+
 /*
  * This file contains all the chip-specific register information and
  * access functions for the QLogic InfiniPath PCI-Express chip.
@@ -207,8 +209,8 @@ static const struct ipath_kregs ipath_pe
 	.kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg),
 
 	/*
-	 * These should not be used directly via ipath_read_kreg64(),
-	 * use them with ipath_read_kreg64_port()
+	 * These should not be used directly via ipath_write_kreg64(),
+	 * use them with ipath_write_kreg64_port(),
 	 */
 	.kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
 	.kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
@@ -321,6 +323,12 @@ static const struct ipath_hwerror_msgs i
 	INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
 };
 
+#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
+		        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
+		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
+
+static int ipath_pe_txe_recover(struct ipath_devdata *);
+
 /**
  * ipath_pe_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
@@ -394,32 +402,21 @@ static void ipath_pe_handle_hwerrors(str
 		 * 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 & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
+			hwerrs &= ~TXE_PIO_PARITY;
 		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
+			 * Force link down, so switch knows, and
+			 * LEDs are turned off
 			 */
 			if (dd->ipath_flags & IPATH_INITTED) {
+				ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
+				ipath_setup_pe_setextled(dd,
+					INFINIPATH_IBCS_L_STATE_DOWN,
+					INFINIPATH_IBCS_LT_STATE_DISABLED);
 				ipath_dev_err(dd, "Fatal Hardware Error (freeze "
 					      "mode), no longer usable, SN %.16s\n",
 						  dd->ipath_serial);
@@ -493,7 +490,8 @@ #define _IPATH_PLL_FAIL (INFINIPATH_HWE_
 				 dd->ipath_hwerrmask);
 	}
 
-	ipath_dev_err(dd, "%s hardware error\n", msg);
+	if (*msg)
+		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
@@ -581,6 +579,8 @@ static void ipath_pe_init_hwerrors(struc
 
 	if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
 		ipath_dev_err(dd, "MemBIST did not complete!\n");
+	if (extsval & INFINIPATH_EXTS_MEMBIST_FOUND)
+		ipath_dbg("MemBIST corrected\n");
 
 	val = ~0ULL;	/* barring bugs, all hwerrors become interrupts, */
 
@@ -1330,6 +1330,35 @@ static void ipath_pe_free_irq(struct ipa
 	dd->ipath_irq = 0;
 }
 
+/*
+ * On platforms using this chip, and not having ordered WC stores, we
+ * can get TXE parity errors due to speculative reads to the PIO buffers,
+ * and this, due to a chip bug can result in (many) false parity error
+ * reports.  So it's a debug print on those, and an info print on systems
+ * where the speculative reads don't occur.
+ * Because we can get lots of false errors, we have no upper limit
+ * on recovery attempts on those platforms.
+ */
+static int ipath_pe_txe_recover(struct ipath_devdata *dd)
+{
+	if (ipath_unordered_wc())
+		ipath_dbg("Recovering from TXE PIO parity error\n");
+	else {
+		int cnt = ++ipath_stats.sps_txeparity;
+		if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
+			if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
+				ipath_dev_err(dd,
+					"Too many attempts to recover from "
+					"TXE parity, giving up\n");
+			return 0;
+		}
+		dev_info(&dd->pcidev->dev,
+			"Recovering from TXE PIO parity error\n");
+	}
+	ipath_disarm_senderrbufs(dd, 1);
+	return 1;
+}
+
 /**
  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index d4f6b52..7045ba6 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -216,6 +216,20 @@ static int bringup_link(struct ipath_dev
 	return ret;
 }
 
+static struct ipath_portdata *create_portdata0(struct ipath_devdata *dd)
+{
+	struct ipath_portdata *pd = NULL;
+
+	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+	if (pd) {
+		pd->port_dd = dd;
+		pd->port_cnt = 1;
+		/* The port 0 pkey table is used by the layer interface. */
+		pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
+	}
+	return pd;
+}
+
 static int init_chip_first(struct ipath_devdata *dd,
 			   struct ipath_portdata **pdp)
 {
@@ -271,20 +285,16 @@ static int init_chip_first(struct ipath_
 		goto done;
 	}
 
-	dd->ipath_pd[0] = kzalloc(sizeof(*pd), GFP_KERNEL);
+	pd = create_portdata0(dd);
 
-	if (!dd->ipath_pd[0]) {
+	if (!pd) {
 		ipath_dev_err(dd, "Unable to allocate portdata for port "
 			      "0, failing\n");
 		ret = -ENOMEM;
 		goto done;
 	}
-	pd = dd->ipath_pd[0];
-	pd->port_dd = dd;
-	pd->port_port = 0;
-	pd->port_cnt = 1;
-	/* The port 0 pkey table is used by the layer interface. */
-	pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
+	dd->ipath_pd[0] = pd;
+
 	dd->ipath_rcvtidcnt =
 		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
 	dd->ipath_rcvtidbase =
@@ -590,6 +600,10 @@ static int init_housekeeping(struct ipat
 		goto done;
 	}
 
+
+	/* clear diagctrl register, in case diags were running and crashed */
+	ipath_write_kreg (dd, dd->ipath_kregs->kr_hwdiagctrl, 0);
+
 	/* clear the initial reset flag, in case first driver load */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
 			 INFINIPATH_E_RESET);
@@ -668,6 +682,7 @@ int ipath_init_chip(struct ipath_devdata
 {
 	int ret = 0, i;
 	u32 val32, kpiobufs;
+	u32 piobufs, uports;
 	u64 val;
 	struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
 	gfp_t gfp_flags = GFP_USER | __GFP_COMP;
@@ -702,16 +717,17 @@ int ipath_init_chip(struct ipath_devdata
 	 * the in memory DMA'ed copies of the registers.  This has to
 	 * be done early, before we calculate lastport, etc.
 	 */
-	val = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+	piobufs = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
 	/*
 	 * calc number of pioavail registers, and save it; we have 2
 	 * bits per buffer.
 	 */
-	dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2)
+	dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2)
 		/ (sizeof(u64) * BITS_PER_BYTE / 2);
+	uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
 	if (ipath_kpiobufs == 0) {
 		/* not set by user (this is default) */
-		if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128)
+		if (piobufs >= (uports * IPATH_MIN_USER_PORT_BUFCNT) + 32)
 			kpiobufs = 32;
 		else
 			kpiobufs = 16;
@@ -719,31 +735,25 @@ int ipath_init_chip(struct ipath_devdata
 	else
 		kpiobufs = ipath_kpiobufs;
 
-	if (kpiobufs >
-	    (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k -
-	     (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT))) {
-		i = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k -
-			(dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT);
+	if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
+		i = (int) piobufs -
+			(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
 		if (i < 0)
 			i = 0;
-		dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs for "
-			 "kernel leaves too few for %d user ports "
+		dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of "
+			 "%d for kernel leaves too few for %d user ports "
 			 "(%d each); using %u\n", kpiobufs,
-			 dd->ipath_cfgports - 1,
-			 IPATH_MIN_USER_PORT_BUFCNT, i);
+			 piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i);
 		/*
 		 * shouldn't change ipath_kpiobufs, because could be
 		 * different for different devices...
 		 */
 		kpiobufs = i;
 	}
-	dd->ipath_lastport_piobuf =
-		dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - kpiobufs;
-	dd->ipath_pbufsport = dd->ipath_cfgports > 1
-		? dd->ipath_lastport_piobuf / (dd->ipath_cfgports - 1)
-		: 0;
-	val32 = dd->ipath_lastport_piobuf -
-		(dd->ipath_pbufsport * (dd->ipath_cfgports - 1));
+	dd->ipath_lastport_piobuf = piobufs - kpiobufs;
+	dd->ipath_pbufsport =
+		uports ? dd->ipath_lastport_piobuf / uports : 0;
+	val32 = dd->ipath_lastport_piobuf - (dd->ipath_pbufsport * uports);
 	if (val32 > 0) {
 		ipath_dbg("allocating %u pbufs/port leaves %u unused, "
 			  "add to kernel\n", dd->ipath_pbufsport, val32);
@@ -754,8 +764,7 @@ int ipath_init_chip(struct ipath_devdata
 	dd->ipath_lastpioindex = dd->ipath_lastport_piobuf;
 	ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
 		   "each for %u user ports\n", kpiobufs,
-		   dd->ipath_piobcnt2k + dd->ipath_piobcnt4k,
-		   dd->ipath_pbufsport, dd->ipath_cfgports - 1);
+		   piobufs, dd->ipath_pbufsport, uports);
 
 	dd->ipath_f_early_init(dd);
 
@@ -839,11 +848,24 @@ int ipath_init_chip(struct ipath_devdata
 	 * Set up the port 0 (kernel) rcvhdr q and egr TIDs.  If doing
 	 * re-init, the simplest way to handle this is to free
 	 * existing, and re-allocate.
+	 * Need to re-create rest of port 0 portdata as well.
 	 */
 	if (reinit) {
-		struct ipath_portdata *pd = dd->ipath_pd[0];
-		dd->ipath_pd[0] = NULL;
-		ipath_free_pddata(dd, pd);
+		/* Alloc and init new ipath_portdata for port0,
+		 * Then free old pd. Could lead to fragmentation, but also
+		 * makes later support for hot-swap easier.
+		 */
+		struct ipath_portdata *npd;
+		npd = create_portdata0(dd);
+		if (npd) {
+			ipath_free_pddata(dd, pd);
+			dd->ipath_pd[0] = pd = npd;
+		} else {
+			ipath_dev_err(dd, "Unable to allocate portdata for"
+				      "  port 0, failing\n");
+			ret = -ENOMEM;
+			goto done;
+		}
 	}
 	dd->ipath_f_tidtemplate(dd);
 	ret = ipath_create_rcvhdrq(dd, pd);
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 72b9e27..45d0331 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -38,10 +38,39 @@ #include "ipath_verbs.h"
 #include "ipath_common.h"
 
 /*
+ * clear (write) a pio buffer, to clear a parity error.   This routine
+ * should only be called when in freeze mode, and the buffer should be
+ * canceled afterwards.
+ */
+static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
+{
+	u32 __iomem *pbuf;
+	u32 dwcnt; /* dword count to write */
+	if (pnum < dd->ipath_piobcnt2k) {
+		pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum *
+			dd->ipath_palign);
+		dwcnt = dd->ipath_piosize2k >> 2;
+	}
+	else {
+		pbuf = (u32 __iomem *) (dd->ipath_pio4kbase +
+			(pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign);
+		dwcnt = dd->ipath_piosize4k >> 2;
+	}
+	dev_info(&dd->pcidev->dev,
+		"Rewrite PIO buffer %u, to recover from parity error\n",
+		pnum);
+	*pbuf = dwcnt+1; /* no flush required, since already in freeze */
+	while(--dwcnt)
+		*pbuf++ = 0;
+}
+
+/*
  * 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.
+ * If rewrite is true, and bits are set in the sendbufferror registers,
+ * we'll write to the buffer, for error recovery on parity errors.
  */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
 	u32 piobcnt;
 	unsigned long sbuf[4];
@@ -74,8 +103,11 @@ void ipath_disarm_senderrbufs(struct ipa
 		}
 
 		for (i = 0; i < piobcnt; i++)
-			if (test_bit(i, sbuf))
+			if (test_bit(i, sbuf)) {
+				if (rewrite)
+					ipath_clrpiobuf(dd, i);
 				ipath_disarm_piobufs(dd, i, 1);
+			}
 		dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
 	}
 }
@@ -114,7 +146,7 @@ static u64 handle_e_sum_errs(struct ipat
 {
 	u64 ignore_this_time = 0;
 
-	ipath_disarm_senderrbufs(dd);
+	ipath_disarm_senderrbufs(dd, 0);
 	if ((errs & E_SUM_LINK_PKTERRS) &&
 	    !(dd->ipath_flags & IPATH_LINKACTIVE)) {
 		/*
@@ -403,10 +435,13 @@ static void handle_supp_msgs(struct ipat
 	 * happens so often we never want to count it.
 	 */
 	if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
-		ipath_decode_err(msg, sizeof msg, dd->ipath_lasterror &
-				 ~INFINIPATH_E_IBSTATUSCHANGED);
+		int iserr;
+		iserr = ipath_decode_err(msg, sizeof msg,
+				dd->ipath_lasterror &
+				~INFINIPATH_E_IBSTATUSCHANGED);
 		if (dd->ipath_lasterror &
-		    ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
+			~(INFINIPATH_E_RRCVEGRFULL |
+			INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
 			ipath_dev_err(dd, "Suppressed %u messages for "
 				      "fast-repeating errors (%s) (%llx)\n",
 				      supp_msgs, msg,
@@ -420,8 +455,13 @@ static void handle_supp_msgs(struct ipat
 			 * them. So only complain about these at debug
 			 * level.
 			 */
-			ipath_dbg("Suppressed %u messages for %s\n",
-				  supp_msgs, msg);
+			if (iserr)
+				ipath_dbg("Suppressed %u messages for %s\n",
+					  supp_msgs, msg);
+			else
+				ipath_cdbg(ERRPKT,
+					"Suppressed %u messages for %s\n",
+					  supp_msgs, msg);
 		}
 	}
 }
@@ -462,7 +502,7 @@ static int handle_errors(struct ipath_de
 {
 	char msg[512];
 	u64 ignore_this_time = 0;
-	int i;
+	int i, iserr = 0;
 	int chkerrpkts = 0, noprint = 0;
 	unsigned supp_msgs;
 
@@ -502,6 +542,7 @@ static int handle_errors(struct ipath_de
 	}
 
 	if (supp_msgs == 250000) {
+		int s_iserr;
 		/*
 		 * It's not entirely reasonable assuming that the errors set
 		 * in the last clear period are all responsible for the
@@ -511,17 +552,17 @@ static int handle_errors(struct ipath_de
 		dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
 				 ~dd->ipath_maskederrs);
-		ipath_decode_err(msg, sizeof msg,
+		s_iserr = ipath_decode_err(msg, sizeof msg,
 				 (dd->ipath_maskederrs & ~dd->
 				  ipath_ignorederrs));
 
 		if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
-		    ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
-			ipath_dev_err(dd, "Disabling error(s) %llx because "
-				      "occurring too frequently (%s)\n",
-				      (unsigned long long)
-				      (dd->ipath_maskederrs &
-				       ~dd->ipath_ignorederrs), msg);
+			~(INFINIPATH_E_RRCVEGRFULL |
+			INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
+			ipath_dev_err(dd, "Temporarily disabling "
+			    "error(s) %llx reporting; too frequent (%s)\n",
+				(unsigned long long) (dd->ipath_maskederrs &
+				~dd->ipath_ignorederrs), msg);
 		else {
 			/*
 			 * rcvegrfull and rcvhdrqfull are "normal",
@@ -530,8 +571,15 @@ static int handle_errors(struct ipath_de
 			 * processing them.  So only complain about
 			 * these at debug level.
 			 */
-			ipath_dbg("Disabling frequent queue full errors "
-				  "(%s)\n", msg);
+			if (s_iserr)
+				ipath_dbg("Temporarily disabling reporting "
+				    "too frequent queue full errors (%s)\n",
+				    msg);
+			else
+				ipath_cdbg(ERRPKT,
+				    "Temporarily disabling reporting too"
+				    " frequent packet errors (%s)\n",
+				    msg);
 		}
 
 		/*
@@ -589,6 +637,8 @@ static int handle_errors(struct ipath_de
 		ipath_stats.sps_crcerrs++;
 		chkerrpkts = 1;
 	}
+	iserr = errs & ~(E_SUM_PKTERRS | INFINIPATH_E_PKTERRS);
+
 
 	/*
 	 * We don't want to print these two as they happen, or we can make
@@ -677,8 +727,13 @@ static int handle_errors(struct ipath_de
 		*dd->ipath_statusp &= ~IPATH_STATUS_IB_CONF;
 	}
 
-	if (!noprint && *msg)
-		ipath_dev_err(dd, "%s error\n", msg);
+	if (!noprint && *msg) {
+		if (iserr)
+			ipath_dev_err(dd, "%s error\n", msg);
+		else
+			dev_info(&dd->pcidev->dev, "%s packet problems\n",
+				msg);
+	}
 	if (dd->ipath_state_wanted & dd->ipath_flags) {
 		ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, "
 			   "waking\n", dd->ipath_state_wanted,
@@ -819,11 +874,10 @@ static void handle_urcv(struct ipath_dev
 		struct ipath_portdata *pd = dd->ipath_pd[i];
 		if (portr & (1 << i) && pd && pd->port_cnt &&
 			test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
-			int rcbit;
 			clear_bit(IPATH_PORT_WAITING_RCV,
 				  &pd->port_flag);
-			rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
-			clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
+			clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+				  &dd->ipath_rcvctrl);
 			wake_up_interruptible(&pd->port_wait);
 			rcvdint = 1;
 		}
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 6d8d05f..e900c25 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -590,7 +590,6 @@ int ipath_enable_wc(struct ipath_devdata
 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, const struct file_operations *fops,
@@ -611,7 +610,7 @@ struct sk_buff *ipath_alloc_skb(struct i
 extern int ipath_diag_inuse;
 
 irqreturn_t ipath_intr(int irq, void *devid);
-void ipath_decode_err(char *buf, size_t blen, ipath_err_t err);
+int ipath_decode_err(char *buf, size_t blen, ipath_err_t err);
 #if __IPATH_INFO || __IPATH_DBG
 extern const char *ipath_ibcstatus_str[];
 #endif
@@ -701,6 +700,8 @@ #define IPATH_GPIO_ERRINTR_MASK 0x38
 #define IPATH_PORT_WAITING_RCV   2
 		/* waiting for a PIO buffer to be available */
 #define IPATH_PORT_WAITING_PIO   3
+		/* master has not finished initializing */
+#define IPATH_PORT_MASTER_UNINIT 4
 
 /* free up any allocated data at closes */
 void ipath_free_data(struct ipath_portdata *dd);
@@ -711,6 +712,7 @@ void ipath_init_iba6120_funcs(struct ipa
 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);
+void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
 
 /*
  * number of words used for protocol header if not set by ipath_userinit();
@@ -754,8 +756,6 @@ int ipath_eeprom_write(struct ipath_devd
 /* these are used for the registers that vary with port */
 void ipath_write_kreg_port(const struct ipath_devdata *, ipath_kreg,
 			   unsigned, u64);
-u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg,
-			   unsigned);
 
 /*
  * We could have a single register get/put routine, that takes a group type,
@@ -897,6 +897,8 @@ #endif
 
 extern unsigned ipath_debug; /* debugging bit mask */
 
+#define IPATH_MAX_PARITY_ATTEMPTS 10000 /* max times to try recovery */
+
 const char *ipath_get_unit_name(int unit);
 
 extern struct mutex ipath_mutex;
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 851763d..dd487c1 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -61,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);
-			ipath_dbg(KERN_INFO "LKEY table full\n");
+			ipath_dbg("LKEY table full\n");
 			ret = 0;
 			goto bail;
 		}
@@ -133,6 +133,12 @@ int ipath_lkey_ok(struct ipath_qp *qp, s
 	 * being reversible by calling bus_to_virt().
 	 */
 	if (sge->lkey == 0) {
+		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
+
+		if (pd->user) {
+			ret = 0;
+			goto bail;
+		}
 		isge->mr = NULL;
 		isge->vaddr = (void *) sge->addr;
 		isge->length = sge->length;
@@ -206,6 +212,12 @@ int ipath_rkey_ok(struct ipath_qp *qp, s
 	 * (see ipath_get_dma_mr and ipath_dma.c).
 	 */
 	if (rkey == 0) {
+		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
+
+		if (pd->user) {
+			ret = 0;
+			goto bail;
+		}
 		sge->mr = NULL;
 		sge->vaddr = (void *) vaddr;
 		sge->length = len;
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
index e46aa4e..05a1d2b 100644
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ b/drivers/infiniband/hw/ipath/ipath_layer.c
@@ -37,7 +37,6 @@
  */
 
 #include <linux/io.h>
-#include <linux/pci.h>
 #include <asm/byteorder.h>
 
 #include "ipath_kernel.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
index a82157d..937bc33 100644
--- a/drivers/infiniband/hw/ipath/ipath_mmap.c
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref
 {
 	struct ipath_mmap_info *ip =
 		container_of(ref, struct ipath_mmap_info, ref);
+	struct ipath_ibdev *dev = to_idev(ip->context->device);
+
+	spin_lock_irq(&dev->pending_lock);
+	list_del(&ip->pending_mmaps);
+	spin_unlock_irq(&dev->pending_lock);
 
 	vfree(ip->obj);
 	kfree(ip);
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_are
 	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);
 }
 
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *conte
 	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;
+	struct ipath_mmap_info *ip, *pp;
 	int ret = -EINVAL;
 
 	/*
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *conte
 	 * 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) {
+	list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
+				 pending_mmaps) {
 		/* Only the creator is allowed to mmap the object */
-		if (context != ip->context || (void *) offset != ip->obj)
+		if (context != ip->context || (__u64) offset != ip->offset)
 			continue;
 		/* Don't allow a mmap larger than the object. */
 		if (size > ip->size)
 			break;
 
-		*pp = ip->next;
+		list_del_init(&ip->pending_mmaps);
 		spin_unlock_irq(&dev->pending_lock);
 
 		ret = remap_vmalloc_range(vma, ip->obj, 0);
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *conte
 done:
 	return ret;
 }
+
+/*
+ * Allocate information for ipath_mmap
+ */
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+					       u32 size,
+					       struct ib_ucontext *context,
+					       void *obj) {
+	struct ipath_mmap_info *ip;
+
+	ip = kmalloc(sizeof *ip, GFP_KERNEL);
+	if (!ip)
+		goto bail;
+
+	size = PAGE_ALIGN(size);
+
+	spin_lock_irq(&dev->mmap_offset_lock);
+	if (dev->mmap_offset == 0)
+		dev->mmap_offset = PAGE_SIZE;
+	ip->offset = dev->mmap_offset;
+	dev->mmap_offset += size;
+	spin_unlock_irq(&dev->mmap_offset_lock);
+
+	INIT_LIST_HEAD(&ip->pending_mmaps);
+	ip->size = size;
+	ip->context = context;
+	ip->obj = obj;
+	kref_init(&ip->ref);
+
+bail:
+	return ip;
+}
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+			    struct ipath_mmap_info *ip,
+			    u32 size, void *obj) {
+	size = PAGE_ALIGN(size);
+
+	spin_lock_irq(&dev->mmap_offset_lock);
+	if (dev->mmap_offset == 0)
+		dev->mmap_offset = PAGE_SIZE;
+	ip->offset = dev->mmap_offset;
+	dev->mmap_offset += size;
+	spin_unlock_irq(&dev->mmap_offset_lock);
+
+	ip->size = size;
+	ip->obj = obj;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index 8cc8598..31e7073 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -210,9 +210,15 @@ struct ib_mr *ipath_reg_user_mr(struct i
 	m = 0;
 	n = 0;
 	list_for_each_entry(chunk, &region->chunk_list, list) {
-		for (i = 0; i < chunk->nmap; i++) {
-			mr->mr.map[m]->segs[n].vaddr =
-				page_address(chunk->page_list[i].page);
+		for (i = 0; i < chunk->nents; i++) {
+			void *vaddr;
+
+			vaddr = page_address(chunk->page_list[i].page);
+			if (!vaddr) {
+				ret = ERR_PTR(-EINVAL);
+				goto bail;
+			}
+			mr->mr.map[m]->segs[n].vaddr = vaddr;
 			mr->mr.map[m]->segs[n].length = region->page_size;
 			n++;
 			if (n == IPATH_SEGSZ) {
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 64f07b1..bfef08e 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -81,11 +81,51 @@ static u32 credit_table[31] = {
 	32768			/* 1E */
 };
 
-static u32 alloc_qpn(struct ipath_qp_table *qpt)
+
+static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map)
+{
+	unsigned long page = get_zeroed_page(GFP_KERNEL);
+	unsigned long flags;
+
+	/*
+	 * Free the page if someone raced with us installing it.
+	 */
+
+	spin_lock_irqsave(&qpt->lock, flags);
+	if (map->page)
+		free_page(page);
+	else
+		map->page = (void *)page;
+	spin_unlock_irqrestore(&qpt->lock, flags);
+}
+
+
+static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type)
 {
 	u32 i, offset, max_scan, qpn;
 	struct qpn_map *map;
-	u32 ret;
+	u32 ret = -1;
+
+	if (type == IB_QPT_SMI)
+		ret = 0;
+	else if (type == IB_QPT_GSI)
+		ret = 1;
+
+	if (ret != -1) {
+		map = &qpt->map[0];
+		if (unlikely(!map->page)) {
+			get_map_page(qpt, map);
+			if (unlikely(!map->page)) {
+				ret = -ENOMEM;
+				goto bail;
+			}
+		}
+		if (!test_and_set_bit(ret, map->page))
+			atomic_dec(&map->n_free);
+		else
+			ret = -EBUSY;
+		goto bail;
+	}
 
 	qpn = qpt->last + 1;
 	if (qpn >= QPN_MAX)
@@ -95,19 +135,7 @@ static u32 alloc_qpn(struct ipath_qp_tab
 	max_scan = qpt->nmaps - !offset;
 	for (i = 0;;) {
 		if (unlikely(!map->page)) {
-			unsigned long page = get_zeroed_page(GFP_KERNEL);
-			unsigned long flags;
-
-			/*
-			 * Free the page if someone raced with us
-			 * installing it:
-			 */
-			spin_lock_irqsave(&qpt->lock, flags);
-			if (map->page)
-				free_page(page);
-			else
-				map->page = (void *)page;
-			spin_unlock_irqrestore(&qpt->lock, flags);
+			get_map_page(qpt, map);
 			if (unlikely(!map->page))
 				break;
 		}
@@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_tab
 		qpn = mk_qpn(qpt, map, offset);
 	}
 
-	ret = 0;
+	ret = -ENOMEM;
 
 bail:
 	return ret;
@@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_
 			   enum ib_qp_type type)
 {
 	unsigned long flags;
-	u32 qpn;
 	int ret;
 
-	if (type == IB_QPT_SMI)
-		qpn = 0;
-	else if (type == IB_QPT_GSI)
-		qpn = 1;
-	else {
-		/* Allocate the next available QPN */
-		qpn = alloc_qpn(qpt);
-		if (qpn == 0) {
-			ret = -ENOMEM;
-			goto bail;
-		}
-	}
-	qp->ibqp.qp_num = qpn;
+	ret = alloc_qpn(qpt, type);
+	if (ret < 0)
+		goto bail;
+	qp->ibqp.qp_num = ret;
 
 	/* Add the QP to the hash table. */
 	spin_lock_irqsave(&qpt->lock, flags);
 
-	qpn %= qpt->max;
-	qp->next = qpt->table[qpn];
-	qpt->table[qpn] = qp;
+	ret %= qpt->max;
+	qp->next = qpt->table[ret];
+	qpt->table[ret] = qp;
 	atomic_inc(&qp->refcount);
 
 	spin_unlock_irqrestore(&qpt->lock, flags);
@@ -245,9 +263,7 @@ static void ipath_free_qp(struct ipath_q
 	if (!fnd)
 		return;
 
-	/* If QPN is not reserved, mark QPN free in the bitmap. */
-	if (qp->ibqp.qp_num > 1)
-		free_qpn(qpt, qp->ibqp.qp_num);
+	free_qpn(qpt, qp->ibqp.qp_num);
 
 	wait_event(qp->wait, !atomic_read(&qp->refcount));
 }
@@ -270,11 +286,10 @@ void ipath_free_all_qps(struct ipath_qp_
 
 		while (qp) {
 			nqp = qp->next;
-			if (qp->ibqp.qp_num > 1)
-				free_qpn(qpt, qp->ibqp.qp_num);
+			free_qpn(qpt, qp->ibqp.qp_num);
 			if (!atomic_dec_and_test(&qp->refcount) ||
 			    !ipath_destroy_qp(&qp->ibqp))
-				ipath_dbg(KERN_INFO "QP memory leak!\n");
+				ipath_dbg("QP memory leak!\n");
 			qp = nqp;
 		}
 	}
@@ -320,7 +335,8 @@ static void ipath_reset_qp(struct ipath_
 	qp->remote_qpn = 0;
 	qp->qkey = 0;
 	qp->qp_access_flags = 0;
-	clear_bit(IPATH_S_BUSY, &qp->s_flags);
+	qp->s_busy = 0;
+	qp->s_flags &= ~IPATH_S_SIGNAL_REQ_WR;
 	qp->s_hdrwords = 0;
 	qp->s_psn = 0;
 	qp->r_psn = 0;
@@ -333,7 +349,6 @@ static void ipath_reset_qp(struct ipath_
 		qp->r_state = IB_OPCODE_UC_SEND_LAST;
 	}
 	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;
@@ -344,6 +359,10 @@ static void ipath_reset_qp(struct ipath_
 	qp->s_ssn = 1;
 	qp->s_lsn = 0;
 	qp->s_wait_credit = 0;
+	memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue));
+	qp->r_head_ack_queue = 0;
+	qp->s_tail_ack_queue = 0;
+	qp->s_num_rd_atomic = 0;
 	if (qp->r_rq.wq) {
 		qp->r_rq.wq->head = 0;
 		qp->r_rq.wq->tail = 0;
@@ -357,7 +376,7 @@ static void ipath_reset_qp(struct ipath_
  * @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.
+ * The QP s_lock should be held and interrupts disabled.
  */
 
 void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
@@ -365,7 +384,7 @@ void ipath_error_qp(struct ipath_qp *qp,
 	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
 	struct ib_wc wc;
 
-	ipath_dbg(KERN_INFO "QP%d/%d in error state\n",
+	ipath_dbg("QP%d/%d in error state\n",
 		  qp->ibqp.qp_num, qp->remote_qpn);
 
 	spin_lock(&dev->pending_lock);
@@ -389,6 +408,8 @@ void ipath_error_qp(struct ipath_qp *qp,
 	wc.port_num = 0;
 	if (qp->r_wrid_valid) {
 		qp->r_wrid_valid = 0;
+		wc.wr_id = qp->r_wr_id;
+		wc.opcode = IB_WC_RECV;
 		wc.status = err;
 		ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
 	}
@@ -503,13 +524,17 @@ int ipath_modify_qp(struct ib_qp *ibqp, 
 		    attr->path_mig_state != IB_MIG_REARM)
 			goto inval;
 
+	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+		if (attr->max_dest_rd_atomic > IPATH_MAX_RDMA_ATOMIC)
+			goto inval;
+
 	switch (new_state) {
 	case IB_QPS_RESET:
 		ipath_reset_qp(qp);
 		break;
 
 	case IB_QPS_ERR:
-		ipath_error_qp(qp, IB_WC_GENERAL_ERR);
+		ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
 		break;
 
 	default:
@@ -559,6 +584,12 @@ int ipath_modify_qp(struct ib_qp *ibqp, 
 	if (attr_mask & IB_QP_QKEY)
 		qp->qkey = attr->qkey;
 
+	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+		qp->r_max_rd_atomic = attr->max_dest_rd_atomic;
+
+	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
+		qp->s_max_rd_atomic = attr->max_rd_atomic;
+
 	qp->state = new_state;
 	spin_unlock_irqrestore(&qp->s_lock, flags);
 
@@ -598,8 +629,8 @@ int ipath_query_qp(struct ib_qp *ibqp, s
 	attr->alt_pkey_index = 0;
 	attr->en_sqd_async_notify = 0;
 	attr->sq_draining = 0;
-	attr->max_rd_atomic = 1;
-	attr->max_dest_rd_atomic = 1;
+	attr->max_rd_atomic = qp->s_max_rd_atomic;
+	attr->max_dest_rd_atomic = qp->r_max_rd_atomic;
 	attr->min_rnr_timer = qp->r_min_rnr_timer;
 	attr->port_num = 1;
 	attr->timeout = qp->timeout;
@@ -614,7 +645,7 @@ 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;
-	if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
+	if (qp->s_flags & IPATH_S_SIGNAL_REQ_WR)
 		init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
 	else
 		init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
@@ -786,7 +817,7 @@ struct ib_qp *ipath_create_qp(struct ib_
 		qp->s_size = init_attr->cap.max_send_wr + 1;
 		qp->s_max_sge = init_attr->cap.max_send_sge;
 		if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
-			qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR;
+			qp->s_flags = IPATH_S_SIGNAL_REQ_WR;
 		else
 			qp->s_flags = 0;
 		dev = to_idev(ibpd->device);
@@ -813,34 +844,36 @@ struct ib_qp *ipath_create_qp(struct ib_
 	 * 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) {
+			__u64 offset = 0;
 
-		if (qp->r_rq.wq) {
-			/* Allocate info for ipath_mmap(). */
-			ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-			if (!ip) {
+			err = ib_copy_to_udata(udata, &offset,
+					       sizeof(offset));
+			if (err) {
+				ret = ERR_PTR(err);
+				goto bail_rwq;
+			}
+		} else {
+			u32 s = sizeof(struct ipath_rwq) +
+				qp->r_rq.size * sz;
+
+			qp->ip =
+			    ipath_create_mmap_info(dev, s,
+						   ibpd->uobject->context,
+						   qp->r_rq.wq);
+			if (!qp->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);
+
+			err = ib_copy_to_udata(udata, &(qp->ip->offset),
+					       sizeof(qp->ip->offset));
+			if (err) {
+				ret = ERR_PTR(err);
+				goto bail_ip;
+			}
 		}
 	}
 
@@ -854,6 +887,12 @@ struct ib_qp *ipath_create_qp(struct ib_
 	dev->n_qps_allocated++;
 	spin_unlock(&dev->n_qps_lock);
 
+	if (qp->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	ret = &qp->ibqp;
 	goto bail;
 
@@ -958,7 +997,7 @@ bail:
  * @wc: the WC responsible for putting the QP in this state
  *
  * Flushes the send work queue.
- * The QP s_lock should be held.
+ * The QP s_lock should be held and interrupts disabled.
  */
 
 void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
@@ -966,7 +1005,7 @@ 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);
 
-	ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n",
+	ipath_dbg("Send queue error on QP%d/%d: err: %d\n",
 		  qp->ibqp.qp_num, qp->remote_qpn, wc->status);
 
 	spin_lock(&dev->pending_lock);
@@ -984,12 +1023,12 @@ void ipath_sqerror_qp(struct ipath_qp *q
 	wc->status = IB_WC_WR_FLUSH_ERR;
 
 	while (qp->s_last != qp->s_head) {
+		wqe = get_swqe_ptr(qp, qp->s_last);
 		wc->wr_id = wqe->wr.wr_id;
 		wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 		ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1);
 		if (++qp->s_last >= qp->s_size)
 			qp->s_last = 0;
-		wqe = get_swqe_ptr(qp, qp->s_last);
 	}
 	qp->s_cur = qp->s_tail = qp->s_head;
 	qp->state = IB_QPS_SQE;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 5ff20cb..1915771 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -37,6 +37,19 @@ #include "ipath_kernel.h"
 /* cut down ridiculously long IB macro names */
 #define OP(x) IB_OPCODE_RC_##x
 
+static u32 restart_sge(struct ipath_sge_state *ss, struct ipath_swqe *wqe,
+		       u32 psn, u32 pmtu)
+{
+	u32 len;
+
+	len = ((psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
+	ss->sge = wqe->sg_list[0];
+	ss->sg_list = wqe->sg_list + 1;
+	ss->num_sge = wqe->wr.num_sge;
+	ipath_skip_sge(ss, len);
+	return wqe->length - len;
+}
+
 /**
  * ipath_init_restart- initialize the qp->s_sge after a restart
  * @qp: the QP who's SGE we're restarting
@@ -47,15 +60,9 @@ #define OP(x) IB_OPCODE_RC_##x
 static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
 {
 	struct ipath_ibdev *dev;
-	u32 len;
 
-	len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) *
-		ib_mtu_enum_to_int(qp->path_mtu);
-	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;
-	ipath_skip_sge(&qp->s_sge, len);
-	qp->s_len = wqe->length - len;
+	qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn,
+				ib_mtu_enum_to_int(qp->path_mtu));
 	dev = to_idev(qp->ibqp.device);
 	spin_lock(&dev->pending_lock);
 	if (list_empty(&qp->timerwait))
@@ -70,45 +77,81 @@ static void ipath_init_restart(struct ip
  * @ohdr: a pointer to the IB header being constructed
  * @pmtu: the path MTU
  *
- * Return bth0 if constructed; otherwise, return 0.
+ * Return 1 if constructed; otherwise, return 0.
+ * Note that we are in the responder's side of the QP context.
  * Note the QP s_lock must be held.
  */
-u32 ipath_make_rc_ack(struct ipath_qp *qp,
-		      struct ipath_other_headers *ohdr,
-		      u32 pmtu)
+static int ipath_make_rc_ack(struct ipath_qp *qp,
+			     struct ipath_other_headers *ohdr,
+			     u32 pmtu, u32 *bth0p, u32 *bth2p)
 {
+	struct ipath_ack_entry *e;
 	u32 hwords;
 	u32 len;
 	u32 bth0;
+	u32 bth2;
 
 	/* header size in 32-bit words LRH+BTH = (8+12)/4. */
 	hwords = 5;
 
-	/*
-	 * Send a response.  Note that we are in the responder's
-	 * side of the QP context.
-	 */
 	switch (qp->s_ack_state) {
-	case OP(RDMA_READ_REQUEST):
-		qp->s_cur_sge = &qp->s_rdma_sge;
-		len = qp->s_rdma_len;
-		if (len > pmtu) {
-			len = pmtu;
-			qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
-		} else
-			qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
-		qp->s_rdma_len -= len;
+	case OP(RDMA_READ_RESPONSE_LAST):
+	case OP(RDMA_READ_RESPONSE_ONLY):
+	case OP(ATOMIC_ACKNOWLEDGE):
+		/*
+		 * We can increment the tail pointer now that the last
+		 * response has been sent instead of only being
+		 * constructed.
+		 */
+		if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
+			qp->s_tail_ack_queue = 0;
+		/* FALLTHROUGH */
+	case OP(SEND_ONLY):
+	case OP(ACKNOWLEDGE):
+		/* Check for no next entry in the queue. */
+		if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
+			if (qp->s_flags & IPATH_S_ACK_PENDING)
+				goto normal;
+			qp->s_ack_state = OP(ACKNOWLEDGE);
+			goto bail;
+		}
+
+		e = &qp->s_ack_queue[qp->s_tail_ack_queue];
+		if (e->opcode == OP(RDMA_READ_REQUEST)) {
+			/* Copy SGE state in case we need to resend */
+			qp->s_ack_rdma_sge = e->rdma_sge;
+			qp->s_cur_sge = &qp->s_ack_rdma_sge;
+			len = e->rdma_sge.sge.sge_length;
+			if (len > pmtu) {
+				len = pmtu;
+				qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
+			} else
+				qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
+			ohdr->u.aeth = ipath_compute_aeth(qp);
+			hwords++;
+			qp->s_ack_rdma_psn = e->psn;
+			bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
+		} else {
+			/* COMPARE_SWAP or FETCH_ADD */
+			qp->s_cur_sge = NULL;
+			len = 0;
+			qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+			ohdr->u.at.aeth = ipath_compute_aeth(qp);
+			ohdr->u.at.atomic_ack_eth[0] =
+				cpu_to_be32(e->atomic_data >> 32);
+			ohdr->u.at.atomic_ack_eth[1] =
+				cpu_to_be32(e->atomic_data);
+			hwords += sizeof(ohdr->u.at) / sizeof(u32);
+			bth2 = e->psn;
+		}
 		bth0 = qp->s_ack_state << 24;
-		ohdr->u.aeth = ipath_compute_aeth(qp);
-		hwords++;
 		break;
 
 	case OP(RDMA_READ_RESPONSE_FIRST):
 		qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
 		/* FALLTHROUGH */
 	case OP(RDMA_READ_RESPONSE_MIDDLE):
-		qp->s_cur_sge = &qp->s_rdma_sge;
-		len = qp->s_rdma_len;
+		len = qp->s_ack_rdma_sge.sge.sge_length;
 		if (len > pmtu)
 			len = pmtu;
 		else {
@@ -116,61 +159,41 @@ u32 ipath_make_rc_ack(struct ipath_qp *q
 			hwords++;
 			qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
 		}
-		qp->s_rdma_len -= len;
 		bth0 = qp->s_ack_state << 24;
-		break;
-
-	case OP(RDMA_READ_RESPONSE_LAST):
-	case OP(RDMA_READ_RESPONSE_ONLY):
-		/*
-		 * We have to prevent new requests from changing
-		 * the r_sge state while a ipath_verbs_send()
-		 * is in progress.
-		 */
-		qp->s_ack_state = OP(ACKNOWLEDGE);
-		bth0 = 0;
-		goto bail;
-
-	case OP(COMPARE_SWAP):
-	case OP(FETCH_ADD):
-		qp->s_cur_sge = NULL;
-		len = 0;
-		/*
-		 * Set the s_ack_state so the receive interrupt handler
-		 * won't try to send an ACK (out of order) until this one
-		 * is actually sent.
-		 */
-		qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
-		bth0 = OP(ATOMIC_ACKNOWLEDGE) << 24;
-		ohdr->u.at.aeth = ipath_compute_aeth(qp);
-		ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
-		hwords += sizeof(ohdr->u.at) / 4;
+		bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
 		break;
 
 	default:
-		/* Send a regular ACK. */
-		qp->s_cur_sge = NULL;
-		len = 0;
+	normal:
 		/*
-		 * Set the s_ack_state so the receive interrupt handler
-		 * won't try to send an ACK (out of order) until this one
-		 * is actually sent.
+		 * Send a regular ACK.
+		 * Set the s_ack_state so we wait until after sending
+		 * the ACK before setting s_ack_state to ACKNOWLEDGE
+		 * (see above).
 		 */
-		qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
-		bth0 = OP(ACKNOWLEDGE) << 24;
+		qp->s_ack_state = OP(SEND_ONLY);
+		qp->s_flags &= ~IPATH_S_ACK_PENDING;
+		qp->s_cur_sge = NULL;
 		if (qp->s_nak_state)
-			ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
-						    (qp->s_nak_state <<
-						     IPATH_AETH_CREDIT_SHIFT));
+			ohdr->u.aeth =
+				cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
+					    (qp->s_nak_state <<
+					     IPATH_AETH_CREDIT_SHIFT));
 		else
 			ohdr->u.aeth = ipath_compute_aeth(qp);
 		hwords++;
+		len = 0;
+		bth0 = OP(ACKNOWLEDGE) << 24;
+		bth2 = qp->s_ack_psn & IPATH_PSN_MASK;
 	}
 	qp->s_hdrwords = hwords;
 	qp->s_cur_size = len;
+	*bth0p = bth0;
+	*bth2p = bth2;
+	return 1;
 
 bail:
-	return bth0;
+	return 0;
 }
 
 /**
@@ -197,20 +220,22 @@ int ipath_make_rc_req(struct ipath_qp *q
 	u32 bth2;
 	char newreq;
 
-	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
-	    qp->s_rnr_timeout)
+	/* Sending responses has higher priority over sending requests. */
+	if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
+	     (qp->s_flags & IPATH_S_ACK_PENDING) ||
+	     qp->s_ack_state != OP(ACKNOWLEDGE)) &&
+	    ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
 		goto done;
 
+	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
+	    qp->s_rnr_timeout || qp->s_wait_credit)
+		goto bail;
+
 	/* 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;
+		goto bail;
 	}
 
 	/* header size in 32-bit words LRH+BTH = (8+12)/4. */
@@ -232,7 +257,16 @@ int ipath_make_rc_req(struct ipath_qp *q
 		if (qp->s_cur == qp->s_tail) {
 			/* Check if send work queue is empty. */
 			if (qp->s_tail == qp->s_head)
-				goto done;
+				goto bail;
+			/*
+			 * If a fence is requested, wait for previous
+			 * RDMA read and atomic operations to finish.
+			 */
+			if ((wqe->wr.send_flags & IB_SEND_FENCE) &&
+			    qp->s_num_rd_atomic) {
+				qp->s_flags |= IPATH_S_FENCE_PENDING;
+				goto bail;
+			}
 			wqe->psn = qp->s_next_psn;
 			newreq = 1;
 		}
@@ -250,7 +284,7 @@ int ipath_make_rc_req(struct ipath_qp *q
 			/* If no credit, return. */
 			if (qp->s_lsn != (u32) -1 &&
 			    ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
-				goto done;
+				goto bail;
 			wqe->lpsn = wqe->psn;
 			if (len > pmtu) {
 				wqe->lpsn += (len - 1) / pmtu;
@@ -281,13 +315,13 @@ int ipath_make_rc_req(struct ipath_qp *q
 			/* If no credit, return. */
 			if (qp->s_lsn != (u32) -1 &&
 			    ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0)
-				goto done;
+				goto bail;
 			ohdr->u.rc.reth.vaddr =
 				cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
 			ohdr->u.rc.reth.rkey =
 				cpu_to_be32(wqe->wr.wr.rdma.rkey);
 			ohdr->u.rc.reth.length = cpu_to_be32(len);
-			hwords += sizeof(struct ib_reth) / 4;
+			hwords += sizeof(struct ib_reth) / sizeof(u32);
 			wqe->lpsn = wqe->psn;
 			if (len > pmtu) {
 				wqe->lpsn += (len - 1) / pmtu;
@@ -312,14 +346,17 @@ int ipath_make_rc_req(struct ipath_qp *q
 			break;
 
 		case IB_WR_RDMA_READ:
-			ohdr->u.rc.reth.vaddr =
-				cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
-			ohdr->u.rc.reth.rkey =
-				cpu_to_be32(wqe->wr.wr.rdma.rkey);
-			ohdr->u.rc.reth.length = cpu_to_be32(len);
-			qp->s_state = OP(RDMA_READ_REQUEST);
-			hwords += sizeof(ohdr->u.rc.reth) / 4;
+			/*
+			 * Don't allow more operations to be started
+			 * than the QP limits allow.
+			 */
 			if (newreq) {
+				if (qp->s_num_rd_atomic >=
+				    qp->s_max_rd_atomic) {
+					qp->s_flags |= IPATH_S_RDMAR_PENDING;
+					goto bail;
+				}
+				qp->s_num_rd_atomic++;
 				if (qp->s_lsn != (u32) -1)
 					qp->s_lsn++;
 				/*
@@ -330,6 +367,13 @@ int ipath_make_rc_req(struct ipath_qp *q
 					qp->s_next_psn += (len - 1) / pmtu;
 				wqe->lpsn = qp->s_next_psn++;
 			}
+			ohdr->u.rc.reth.vaddr =
+				cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
+			ohdr->u.rc.reth.rkey =
+				cpu_to_be32(wqe->wr.wr.rdma.rkey);
+			ohdr->u.rc.reth.length = cpu_to_be32(len);
+			qp->s_state = OP(RDMA_READ_REQUEST);
+			hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
 			ss = NULL;
 			len = 0;
 			if (++qp->s_cur == qp->s_size)
@@ -338,32 +382,48 @@ int ipath_make_rc_req(struct ipath_qp *q
 
 		case IB_WR_ATOMIC_CMP_AND_SWP:
 		case IB_WR_ATOMIC_FETCH_AND_ADD:
-			if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP)
-				qp->s_state = OP(COMPARE_SWAP);
-			else
-				qp->s_state = OP(FETCH_ADD);
-			ohdr->u.atomic_eth.vaddr = cpu_to_be64(
-				wqe->wr.wr.atomic.remote_addr);
-			ohdr->u.atomic_eth.rkey = cpu_to_be32(
-				wqe->wr.wr.atomic.rkey);
-			ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-				wqe->wr.wr.atomic.swap);
-			ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-				wqe->wr.wr.atomic.compare_add);
-			hwords += sizeof(struct ib_atomic_eth) / 4;
+			/*
+			 * Don't allow more operations to be started
+			 * than the QP limits allow.
+			 */
 			if (newreq) {
+				if (qp->s_num_rd_atomic >=
+				    qp->s_max_rd_atomic) {
+					qp->s_flags |= IPATH_S_RDMAR_PENDING;
+					goto bail;
+				}
+				qp->s_num_rd_atomic++;
 				if (qp->s_lsn != (u32) -1)
 					qp->s_lsn++;
 				wqe->lpsn = wqe->psn;
 			}
-			if (++qp->s_cur == qp->s_size)
-				qp->s_cur = 0;
+			if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+				qp->s_state = OP(COMPARE_SWAP);
+				ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+					wqe->wr.wr.atomic.swap);
+				ohdr->u.atomic_eth.compare_data = cpu_to_be64(
+					wqe->wr.wr.atomic.compare_add);
+			} else {
+				qp->s_state = OP(FETCH_ADD);
+				ohdr->u.atomic_eth.swap_data = cpu_to_be64(
+					wqe->wr.wr.atomic.compare_add);
+				ohdr->u.atomic_eth.compare_data = 0;
+			}
+			ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
+				wqe->wr.wr.atomic.remote_addr >> 32);
+			ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
+				wqe->wr.wr.atomic.remote_addr);
+			ohdr->u.atomic_eth.rkey = cpu_to_be32(
+				wqe->wr.wr.atomic.rkey);
+			hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
 			ss = NULL;
 			len = 0;
+			if (++qp->s_cur == qp->s_size)
+				qp->s_cur = 0;
 			break;
 
 		default:
-			goto done;
+			goto bail;
 		}
 		qp->s_sge.sge = wqe->sg_list[0];
 		qp->s_sge.sg_list = wqe->sg_list + 1;
@@ -379,7 +439,7 @@ int ipath_make_rc_req(struct ipath_qp *q
 			qp->s_psn = wqe->lpsn + 1;
 		else {
 			qp->s_psn++;
-			if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+			if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
 				qp->s_next_psn = qp->s_psn;
 		}
 		/*
@@ -406,7 +466,7 @@ int ipath_make_rc_req(struct ipath_qp *q
 		/* FALLTHROUGH */
 	case OP(SEND_MIDDLE):
 		bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-		if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+		if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
 			qp->s_next_psn = qp->s_psn;
 		ss = &qp->s_sge;
 		len = qp->s_len;
@@ -442,7 +502,7 @@ int ipath_make_rc_req(struct ipath_qp *q
 		/* FALLTHROUGH */
 	case OP(RDMA_WRITE_MIDDLE):
 		bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-		if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+		if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
 			qp->s_next_psn = qp->s_psn;
 		ss = &qp->s_sge;
 		len = qp->s_len;
@@ -479,9 +539,9 @@ int ipath_make_rc_req(struct ipath_qp *q
 			cpu_to_be32(wqe->wr.wr.rdma.rkey);
 		ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
 		qp->s_state = OP(RDMA_READ_REQUEST);
-		hwords += sizeof(ohdr->u.rc.reth) / 4;
+		hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
 		bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-		if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+		if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
 			qp->s_next_psn = qp->s_psn;
 		ss = NULL;
 		len = 0;
@@ -489,20 +549,6 @@ int ipath_make_rc_req(struct ipath_qp *q
 		if (qp->s_cur == qp->s_size)
 			qp->s_cur = 0;
 		break;
-
-	case OP(RDMA_READ_REQUEST):
-	case OP(COMPARE_SWAP):
-	case OP(FETCH_ADD):
-		/*
-		 * We shouldn't start anything new until this request is
-		 * finished.  The ACK will handle rescheduling us.  XXX The
-		 * number of outstanding ones is negotiated at connection
-		 * setup time (see pg. 258,289)?  XXX Also, if we support
-		 * multiple outstanding requests, we need to check the WQE
-		 * IB_SEND_FENCE flag and not send a new request if a RDMA
-		 * read or atomic is pending.
-		 */
-		goto done;
 	}
 	if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
 		bth2 |= 1 << 31;	/* Request ACK. */
@@ -512,9 +558,10 @@ int ipath_make_rc_req(struct ipath_qp *q
 	qp->s_cur_size = len;
 	*bth0p = bth0 | (qp->s_state << 24);
 	*bth2p = bth2;
+done:
 	return 1;
 
-done:
+bail:
 	return 0;
 }
 
@@ -524,7 +571,8 @@ done:
  *
  * This is called from ipath_rc_rcv() and only uses the receive
  * side QP state.
- * Note that RDMA reads are handled in the send side QP state and tasklet.
+ * Note that RDMA reads and atomics are handled in the
+ * send side QP state and tasklet.
  */
 static void send_rc_ack(struct ipath_qp *qp)
 {
@@ -534,6 +582,13 @@ static void send_rc_ack(struct ipath_qp 
 	u32 hwords;
 	struct ipath_ib_header hdr;
 	struct ipath_other_headers *ohdr;
+	unsigned long flags;
+
+	/* Don't send ACK or NAK if a RDMA read or atomic is pending. */
+	if (qp->r_head_ack_queue != qp->s_tail_ack_queue ||
+	    (qp->s_flags & IPATH_S_ACK_PENDING) ||
+	    qp->s_ack_state != OP(ACKNOWLEDGE))
+		goto queue_ack;
 
 	/* Construct the header. */
 	ohdr = &hdr.u.oth;
@@ -548,19 +603,14 @@ static void send_rc_ack(struct ipath_qp 
 		lrh0 = IPATH_LRH_GRH;
 	}
 	/* read pkey_index w/o lock (its atomic) */
-	bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index);
+	bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index) |
+		OP(ACKNOWLEDGE) << 24;
 	if (qp->r_nak_state)
 		ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
 					    (qp->r_nak_state <<
 					     IPATH_AETH_CREDIT_SHIFT));
 	else
 		ohdr->u.aeth = ipath_compute_aeth(qp);
-	if (qp->r_ack_state >= OP(COMPARE_SWAP)) {
-		bth0 |= OP(ATOMIC_ACKNOWLEDGE) << 24;
-		ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
-		hwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4;
-	} else
-		bth0 |= OP(ACKNOWLEDGE) << 24;
 	lrh0 |= qp->remote_ah_attr.sl << 4;
 	hdr.lrh[0] = cpu_to_be16(lrh0);
 	hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
@@ -574,31 +624,31 @@ static void send_rc_ack(struct ipath_qp 
 	 * If we can send the ACK, clear the ACK state.
 	 */
 	if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
-		qp->r_ack_state = OP(ACKNOWLEDGE);
 		dev->n_unicast_xmit++;
-	} else {
-		/*
-		 * We are out of PIO buffers at the moment.
-		 * Pass responsibility for sending the ACK to the
-		 * send tasklet so that when a PIO buffer becomes
-		 * available, the ACK is sent ahead of other outgoing
-		 * packets.
-		 */
-		dev->n_rc_qacks++;
-		spin_lock_irq(&qp->s_lock);
-		/* Don't coalesce if a RDMA read or atomic is pending. */
-		if (qp->s_ack_state == OP(ACKNOWLEDGE) ||
-		    qp->s_ack_state < OP(RDMA_READ_REQUEST)) {
-			qp->s_ack_state = qp->r_ack_state;
-			qp->s_nak_state = qp->r_nak_state;
-			qp->s_ack_psn = qp->r_ack_psn;
-			qp->r_ack_state = OP(ACKNOWLEDGE);
-		}
-		spin_unlock_irq(&qp->s_lock);
-
-		/* Call ipath_do_rc_send() in another thread. */
-		tasklet_hi_schedule(&qp->s_task);
+		goto done;
 	}
+
+	/*
+	 * We are out of PIO buffers at the moment.
+	 * Pass responsibility for sending the ACK to the
+	 * send tasklet so that when a PIO buffer becomes
+	 * available, the ACK is sent ahead of other outgoing
+	 * packets.
+	 */
+	dev->n_rc_qacks++;
+
+queue_ack:
+	spin_lock_irqsave(&qp->s_lock, flags);
+	qp->s_flags |= IPATH_S_ACK_PENDING;
+	qp->s_nak_state = qp->r_nak_state;
+	qp->s_ack_psn = qp->r_ack_psn;
+	spin_unlock_irqrestore(&qp->s_lock, flags);
+
+	/* Call ipath_do_rc_send() in another thread. */
+	tasklet_hi_schedule(&qp->s_task);
+
+done:
+	return;
 }
 
 /**
@@ -727,7 +777,7 @@ void ipath_restart_rc(struct ipath_qp *q
 	if (wqe->wr.opcode == IB_WR_RDMA_READ)
 		dev->n_rc_resends++;
 	else
-		dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+		dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK;
 
 	reset_psn(qp, psn);
 	tasklet_hi_schedule(&qp->s_task);
@@ -775,10 +825,6 @@ 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
@@ -806,7 +852,7 @@ static int do_rc_ack(struct ipath_qp *qp
 		 */
 		if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
 		     (opcode != OP(RDMA_READ_RESPONSE_LAST) ||
-		       ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
+		      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) ||
@@ -824,20 +870,33 @@ 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);
+		if (qp->s_num_rd_atomic &&
+		    (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)) {
+			qp->s_num_rd_atomic--;
+			/* Restart sending task if fence is complete */
+			if ((qp->s_flags & IPATH_S_FENCE_PENDING) &&
+			    !qp->s_num_rd_atomic) {
+				qp->s_flags &= ~IPATH_S_FENCE_PENDING;
+				tasklet_hi_schedule(&qp->s_task);
+			} else if (qp->s_flags & IPATH_S_RDMAR_PENDING) {
+				qp->s_flags &= ~IPATH_S_RDMAR_PENDING;
+				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) ||
+		if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
 		    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
 			wc.wr_id = wqe->wr.wr_id;
 			wc.status = IB_WC_SUCCESS;
 			wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
 			wc.vendor_err = 0;
 			wc.byte_len = wqe->length;
+			wc.imm_data = 0;
 			wc.qp = &qp->ibqp;
 			wc.src_qp = qp->remote_qpn;
+			wc.wc_flags = 0;
 			wc.pkey_index = 0;
 			wc.slid = qp->remote_ah_attr.dlid;
 			wc.sl = qp->remote_ah_attr.sl;
@@ -854,15 +913,19 @@ static int do_rc_ack(struct ipath_qp *qp
 		if (qp->s_last == qp->s_cur) {
 			if (++qp->s_cur >= qp->s_size)
 				qp->s_cur = 0;
+			qp->s_last = qp->s_cur;
+			if (qp->s_last == qp->s_tail)
+				break;
 			wqe = get_swqe_ptr(qp, qp->s_cur);
 			qp->s_state = OP(SEND_LAST);
 			qp->s_psn = wqe->psn;
+		} else {
+			if (++qp->s_last >= qp->s_size)
+				qp->s_last = 0;
+			if (qp->s_last == qp->s_tail)
+				break;
+			wqe = get_swqe_ptr(qp, qp->s_last);
 		}
-		if (++qp->s_last >= qp->s_size)
-			qp->s_last = 0;
-		wqe = get_swqe_ptr(qp, qp->s_last);
-		if (qp->s_last == qp->s_tail)
-			break;
 	}
 
 	switch (aeth >> 29) {
@@ -874,6 +937,18 @@ static int do_rc_ack(struct ipath_qp *qp
 			list_add_tail(&qp->timerwait,
 				      &dev->pending[dev->pending_index]);
 			spin_unlock(&dev->pending_lock);
+			/*
+			 * If we get a partial ACK for a resent operation,
+			 * we can stop resending the earlier packets and
+			 * continue with the next packet the receiver wants.
+			 */
+			if (ipath_cmp24(qp->s_psn, psn) <= 0) {
+				reset_psn(qp, psn + 1);
+				tasklet_hi_schedule(&qp->s_task);
+			}
+		} else if (ipath_cmp24(qp->s_psn, psn) <= 0) {
+			qp->s_state = OP(SEND_LAST);
+			qp->s_psn = psn + 1;
 		}
 		ipath_get_credit(qp, aeth);
 		qp->s_rnr_retry = qp->s_rnr_retry_cnt;
@@ -884,22 +959,23 @@ static int do_rc_ack(struct ipath_qp *qp
 
 	case 1:		/* RNR NAK */
 		dev->n_rnr_naks++;
+		if (qp->s_last == qp->s_tail)
+			goto bail;
 		if (qp->s_rnr_retry == 0) {
-			if (qp->s_last == qp->s_tail)
-				goto bail;
-
 			wc.status = IB_WC_RNR_RETRY_EXC_ERR;
 			goto class_b;
 		}
 		if (qp->s_rnr_retry_cnt < 7)
 			qp->s_rnr_retry--;
-		if (qp->s_last == qp->s_tail)
-			goto bail;
 
 		/* The last valid PSN is the previous PSN. */
 		update_last_psn(qp, psn - 1);
 
-		dev->n_rc_resends += (int)qp->s_psn - (int)psn;
+		if (wqe->wr.opcode == IB_WR_RDMA_READ)
+			dev->n_rc_resends++;
+		else
+			dev->n_rc_resends +=
+				(qp->s_psn - psn) & IPATH_PSN_MASK;
 
 		reset_psn(qp, psn);
 
@@ -910,26 +986,20 @@ static int do_rc_ack(struct ipath_qp *qp
 		goto bail;
 
 	case 3:		/* NAK */
-		/* The last valid PSN seen is the previous request's. */
-		if (qp->s_last != qp->s_tail)
-			update_last_psn(qp, wqe->psn - 1);
+		if (qp->s_last == qp->s_tail)
+			goto bail;
+		/* The last valid PSN is the previous PSN. */
+		update_last_psn(qp, psn - 1);
 		switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
 			IPATH_AETH_CREDIT_MASK) {
 		case 0:	/* PSN sequence error */
 			dev->n_seq_naks++;
 			/*
-			 * Back up to the responder's expected PSN.  XXX
+			 * Back up to the responder's expected PSN.
 			 * Note that we might get a NAK in the middle of an
 			 * RDMA READ response which terminates the RDMA
 			 * READ.
 			 */
-			if (qp->s_last == qp->s_tail)
-				break;
-
-			if (ipath_cmp24(psn, wqe->psn) < 0)
-				break;
-
-			/* Retry the request. */
 			ipath_restart_rc(qp, psn, &wc);
 			break;
 
@@ -1003,6 +1073,7 @@ static inline void ipath_rc_rcv_resp(str
 				     u32 psn, u32 hdrsize, u32 pmtu,
 				     int header_in_data)
 {
+	struct ipath_swqe *wqe;
 	unsigned long flags;
 	struct ib_wc wc;
 	int diff;
@@ -1032,6 +1103,10 @@ static inline void ipath_rc_rcv_resp(str
 		goto ack_done;
 	}
 
+	if (unlikely(qp->s_last == qp->s_tail))
+		goto ack_done;
+	wqe = get_swqe_ptr(qp, qp->s_last);
+
 	switch (opcode) {
 	case OP(ACKNOWLEDGE):
 	case OP(ATOMIC_ACKNOWLEDGE):
@@ -1042,38 +1117,49 @@ static inline void ipath_rc_rcv_resp(str
 			aeth = be32_to_cpu(((__be32 *) data)[0]);
 			data += sizeof(__be32);
 		}
-		if (opcode == OP(ATOMIC_ACKNOWLEDGE))
-			*(u64 *) qp->s_sge.sge.vaddr = *(u64 *) data;
+		if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
+			u64 val;
+
+			if (!header_in_data) {
+				__be32 *p = ohdr->u.at.atomic_ack_eth;
+
+				val = ((u64) be32_to_cpu(p[0]) << 32) |
+					be32_to_cpu(p[1]);
+			} else
+				val = be64_to_cpu(((__be64 *) data)[0]);
+			*(u64 *) wqe->sg_list[0].vaddr = val;
+		}
 		if (!do_rc_ack(qp, aeth, psn, opcode) ||
 		    opcode != OP(RDMA_READ_RESPONSE_FIRST))
 			goto ack_done;
 		hdrsize += 4;
+		if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+			goto ack_op_err;
 		/*
-		 * do_rc_ack() has already checked the PSN so skip
-		 * the sequence check.
+		 * If this is a response to a resent RDMA read, we
+		 * have to be careful to copy the data to the right
+		 * location.
 		 */
-		goto rdma_read;
+		qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+						  wqe, psn, pmtu);
+		goto read_middle;
 
 	case OP(RDMA_READ_RESPONSE_MIDDLE):
 		/* no AETH, no ACK */
 		if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
 			dev->n_rdma_seq++;
-			if (qp->s_last != qp->s_tail)
-				ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+			ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
 			goto ack_done;
 		}
-	rdma_read:
-		if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
-			goto ack_done;
+		if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+			goto ack_op_err;
+	read_middle:
 		if (unlikely(tlen != (hdrsize + pmtu + 4)))
-			goto ack_done;
-		if (unlikely(pmtu >= qp->s_len))
-			goto ack_done;
+			goto ack_len_err;
+		if (unlikely(pmtu >= qp->s_rdma_read_len))
+			goto ack_len_err;
+
 		/* We got a response so update the timeout. */
-		if (unlikely(qp->s_last == qp->s_tail ||
-			     get_swqe_ptr(qp, qp->s_last)->wr.opcode !=
-			     IB_WR_RDMA_READ))
-			goto ack_done;
 		spin_lock(&dev->pending_lock);
 		if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
 			list_move_tail(&qp->timerwait,
@@ -1082,67 +1168,98 @@ static inline void ipath_rc_rcv_resp(str
 		/*
 		 * Update the RDMA receive state but do the copy w/o
 		 * holding the locks and blocking interrupts.
-		 * XXX Yet another place that affects relaxed RDMA order
-		 * since we don't want s_sge modified.
 		 */
-		qp->s_len -= pmtu;
+		qp->s_rdma_read_len -= pmtu;
 		update_last_psn(qp, psn);
 		spin_unlock_irqrestore(&qp->s_lock, flags);
-		ipath_copy_sge(&qp->s_sge, data, pmtu);
+		ipath_copy_sge(&qp->s_rdma_read_sge, data, pmtu);
 		goto bail;
 
-	case OP(RDMA_READ_RESPONSE_LAST):
-		/* ACKs READ req. */
+	case OP(RDMA_READ_RESPONSE_ONLY):
 		if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
 			dev->n_rdma_seq++;
-			if (qp->s_last != qp->s_tail)
-				ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+			ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
 			goto ack_done;
 		}
-		/* FALLTHROUGH */
-	case OP(RDMA_READ_RESPONSE_ONLY):
-		if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
-			goto ack_done;
+		if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+			goto ack_op_err;
+		/* Get the number of bytes the message was padded by. */
+		pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
 		/*
-		 * Get the number of bytes the message was padded by.
+		 * Check that the data size is >= 0 && <= pmtu.
+		 * Remember to account for the AETH header (4) and
+		 * ICRC (4).
+		 */
+		if (unlikely(tlen < (hdrsize + pad + 8)))
+			goto ack_len_err;
+		/*
+		 * If this is a response to a resent RDMA read, we
+		 * have to be careful to copy the data to the right
+		 * location.
 		 */
+		qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
+						  wqe, psn, pmtu);
+		goto read_last;
+
+	case OP(RDMA_READ_RESPONSE_LAST):
+		/* 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);
+			goto ack_done;
+		}
+		if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
+			goto ack_op_err;
+		/* Get the number of bytes the message was padded by. */
 		pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
 		/*
 		 * Check that the data size is >= 1 && <= pmtu.
 		 * Remember to account for the AETH header (4) and
 		 * ICRC (4).
 		 */
-		if (unlikely(tlen <= (hdrsize + pad + 8))) {
-			/* XXX Need to generate an error CQ entry. */
-			goto ack_done;
-		}
+		if (unlikely(tlen <= (hdrsize + pad + 8)))
+			goto ack_len_err;
+	read_last:
 		tlen -= hdrsize + pad + 8;
-		if (unlikely(tlen != qp->s_len)) {
-			/* XXX Need to generate an error CQ entry. */
-			goto ack_done;
-		}
+		if (unlikely(tlen != qp->s_rdma_read_len))
+			goto ack_len_err;
 		if (!header_in_data)
 			aeth = be32_to_cpu(ohdr->u.aeth);
 		else {
 			aeth = be32_to_cpu(((__be32 *) data)[0]);
 			data += sizeof(__be32);
 		}
-		ipath_copy_sge(&qp->s_sge, data, tlen);
-		if (do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST))) {
-			/*
-			 * Change the state so we contimue
-			 * processing new requests and wake up the
-			 * tasklet if there are posted sends.
-			 */
-			qp->s_state = OP(SEND_LAST);
-			if (qp->s_tail != qp->s_head)
-				tasklet_hi_schedule(&qp->s_task);
-		}
+		ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen);
+		(void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST));
 		goto ack_done;
 	}
 
 ack_done:
 	spin_unlock_irqrestore(&qp->s_lock, flags);
+	goto bail;
+
+ack_op_err:
+	wc.status = IB_WC_LOC_QP_OP_ERR;
+	goto ack_err;
+
+ack_len_err:
+	wc.status = IB_WC_LOC_LEN_ERR;
+ack_err:
+	wc.wr_id = wqe->wr.wr_id;
+	wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+	wc.vendor_err = 0;
+	wc.byte_len = 0;
+	wc.imm_data = 0;
+	wc.qp = &qp->ibqp;
+	wc.src_qp = qp->remote_qpn;
+	wc.wc_flags = 0;
+	wc.pkey_index = 0;
+	wc.slid = qp->remote_ah_attr.dlid;
+	wc.sl = qp->remote_ah_attr.sl;
+	wc.dlid_path_bits = 0;
+	wc.port_num = 0;
+	ipath_sqerror_qp(qp, &wc);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 bail:
 	return;
 }
@@ -1162,7 +1279,7 @@ bail:
  * incoming RC packet for the given QP.
  * Called at interrupt level.
  * Return 1 if no more processing is needed; otherwise return 0 to
- * schedule a response to be sent and the s_lock unlocked.
+ * schedule a response to be sent.
  */
 static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
 				     struct ipath_other_headers *ohdr,
@@ -1173,25 +1290,24 @@ static inline int ipath_rc_rcv_error(str
 				     int diff,
 				     int header_in_data)
 {
-	struct ib_reth *reth;
+	struct ipath_ack_entry *e;
+	u8 i, prev;
+	int old_req;
+	unsigned long flags;
 
 	if (diff > 0) {
 		/*
 		 * Packet sequence error.
 		 * A NAK will ACK earlier sends and RDMA writes.
-		 * Don't queue the NAK if a RDMA read, atomic, or
-		 * NAK is pending though.
+		 * Don't queue the NAK if we already sent one.
 		 */
-		if (qp->s_ack_state != OP(ACKNOWLEDGE) ||
-		    qp->r_nak_state != 0)
-			goto done;
-		if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-			qp->r_ack_state = OP(SEND_ONLY);
+		if (!qp->r_nak_state) {
 			qp->r_nak_state = IB_NAK_PSN_ERROR;
 			/* Use the expected PSN. */
 			qp->r_ack_psn = qp->r_psn;
+			goto send_ack;
 		}
-		goto send_ack;
+		goto done;
 	}
 
 	/*
@@ -1204,8 +1320,46 @@ static inline int ipath_rc_rcv_error(str
 	 * can coalesce an outstanding duplicate ACK.  We have to
 	 * send the earliest so that RDMA reads can be restarted at
 	 * the requester's expected PSN.
+	 *
+	 * First, find where this duplicate PSN falls within the
+	 * ACKs previously sent.
 	 */
-	if (opcode == OP(RDMA_READ_REQUEST)) {
+	psn &= IPATH_PSN_MASK;
+	e = NULL;
+	old_req = 1;
+	spin_lock_irqsave(&qp->s_lock, flags);
+	for (i = qp->r_head_ack_queue; ; i = prev) {
+		if (i == qp->s_tail_ack_queue)
+			old_req = 0;
+		if (i)
+			prev = i - 1;
+		else
+			prev = IPATH_MAX_RDMA_ATOMIC;
+		if (prev == qp->r_head_ack_queue) {
+			e = NULL;
+			break;
+		}
+		e = &qp->s_ack_queue[prev];
+		if (!e->opcode) {
+			e = NULL;
+			break;
+		}
+		if (ipath_cmp24(psn, e->psn) >= 0)
+			break;
+	}
+	switch (opcode) {
+	case OP(RDMA_READ_REQUEST): {
+		struct ib_reth *reth;
+		u32 offset;
+		u32 len;
+
+		/*
+		 * If we didn't find the RDMA read request in the ack queue,
+		 * or the send tasklet is already backed up to send an
+		 * earlier entry, we can ignore this request.
+		 */
+		if (!e || e->opcode != OP(RDMA_READ_REQUEST) || old_req)
+			goto unlock_done;
 		/* RETH comes after BTH */
 		if (!header_in_data)
 			reth = &ohdr->u.rc.reth;
@@ -1214,96 +1368,96 @@ static inline int ipath_rc_rcv_error(str
 			data += sizeof(*reth);
 		}
 		/*
-		 * If we receive a duplicate RDMA request, it means the
-		 * requester saw a sequence error and needs to restart
-		 * from an earlier point.  We can abort the current
-		 * RDMA read send in that case.
+		 * Address range must be a subset of the original
+		 * request and start on pmtu boundaries.
+		 * We reuse the old ack_queue slot since the requester
+		 * should not back up and request an earlier PSN for the
+		 * same request.
 		 */
-		spin_lock_irq(&qp->s_lock);
-		if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
-		    (qp->s_hdrwords || ipath_cmp24(psn, qp->s_ack_psn) >= 0)) {
-			/*
-			 * We are already sending earlier requested data.
-			 * Don't abort it to send later out of sequence data.
-			 */
-			spin_unlock_irq(&qp->s_lock);
-			goto done;
-		}
-		qp->s_rdma_len = be32_to_cpu(reth->length);
-		if (qp->s_rdma_len != 0) {
+		offset = ((psn - e->psn) & IPATH_PSN_MASK) *
+			ib_mtu_enum_to_int(qp->path_mtu);
+		len = be32_to_cpu(reth->length);
+		if (unlikely(offset + len > e->rdma_sge.sge.sge_length))
+			goto unlock_done;
+		if (len != 0) {
 			u32 rkey = be32_to_cpu(reth->rkey);
 			u64 vaddr = be64_to_cpu(reth->vaddr);
 			int ok;
 
-			/*
-			 * Address range must be a subset of the original
-			 * request and start on pmtu boundaries.
-			 */
-			ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
-					   qp->s_rdma_len, vaddr, rkey,
+			ok = ipath_rkey_ok(qp, &e->rdma_sge,
+					   len, vaddr, rkey,
 					   IB_ACCESS_REMOTE_READ);
-			if (unlikely(!ok)) {
-				spin_unlock_irq(&qp->s_lock);
-				goto done;
-			}
+			if (unlikely(!ok))
+				goto unlock_done;
 		} else {
-			qp->s_rdma_sge.sg_list = NULL;
-			qp->s_rdma_sge.num_sge = 0;
-			qp->s_rdma_sge.sge.mr = NULL;
-			qp->s_rdma_sge.sge.vaddr = NULL;
-			qp->s_rdma_sge.sge.length = 0;
-			qp->s_rdma_sge.sge.sge_length = 0;
+			e->rdma_sge.sg_list = NULL;
+			e->rdma_sge.num_sge = 0;
+			e->rdma_sge.sge.mr = NULL;
+			e->rdma_sge.sge.vaddr = NULL;
+			e->rdma_sge.sge.length = 0;
+			e->rdma_sge.sge.sge_length = 0;
 		}
-		qp->s_ack_state = opcode;
-		qp->s_ack_psn = psn;
-		spin_unlock_irq(&qp->s_lock);
-		tasklet_hi_schedule(&qp->s_task);
-		goto send_ack;
+		e->psn = psn;
+		qp->s_ack_state = OP(ACKNOWLEDGE);
+		qp->s_tail_ack_queue = prev;
+		break;
 	}
 
-	/*
-	 * A pending RDMA read will ACK anything before it so
-	 * ignore earlier duplicate requests.
-	 */
-	if (qp->s_ack_state != OP(ACKNOWLEDGE))
-		goto done;
-
-	/*
-	 * If an ACK is pending, don't replace the pending ACK
-	 * with an earlier one since the later one will ACK the earlier.
-	 * Also, if we already have a pending atomic, send it.
-	 */
-	if (qp->r_ack_state != OP(ACKNOWLEDGE) &&
-	    (ipath_cmp24(psn, qp->r_ack_psn) <= 0 ||
-	     qp->r_ack_state >= OP(COMPARE_SWAP)))
-		goto send_ack;
-	switch (opcode) {
 	case OP(COMPARE_SWAP):
-	case OP(FETCH_ADD):
+	case OP(FETCH_ADD): {
 		/*
-		 * Check for the PSN of the last atomic operation
-		 * performed and resend the result if found.
+		 * If we didn't find the atomic request in the ack queue
+		 * or the send tasklet is already backed up to send an
+		 * earlier entry, we can ignore this request.
 		 */
-		if ((psn & IPATH_PSN_MASK) != qp->r_atomic_psn)
-			goto done;
+		if (!e || e->opcode != (u8) opcode || old_req)
+			goto unlock_done;
+		qp->s_ack_state = OP(ACKNOWLEDGE);
+		qp->s_tail_ack_queue = prev;
+		break;
+	}
+
+	default:
+		if (old_req)
+			goto unlock_done;
+		/*
+		 * Resend the most recent ACK if this request is
+		 * after all the previous RDMA reads and atomics.
+		 */
+		if (i == qp->r_head_ack_queue) {
+			spin_unlock_irqrestore(&qp->s_lock, flags);
+			qp->r_nak_state = 0;
+			qp->r_ack_psn = qp->r_psn - 1;
+			goto send_ack;
+		}
+		/*
+		 * Resend the RDMA read or atomic op which
+		 * ACKs this duplicate request.
+		 */
+		qp->s_ack_state = OP(ACKNOWLEDGE);
+		qp->s_tail_ack_queue = i;
 		break;
 	}
-	qp->r_ack_state = opcode;
 	qp->r_nak_state = 0;
-	qp->r_ack_psn = psn;
-send_ack:
-	return 0;
+	tasklet_hi_schedule(&qp->s_task);
 
+unlock_done:
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 done:
 	return 1;
+
+send_ack:
+	return 0;
 }
 
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
 {
-	spin_lock_irq(&qp->s_lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&qp->s_lock, flags);
 	qp->state = IB_QPS_ERR;
 	ipath_error_qp(qp, err);
-	spin_unlock_irq(&qp->s_lock);
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 }
 
 /**
@@ -1391,15 +1545,7 @@ void ipath_rc_rcv(struct ipath_ibdev *de
 		    opcode == OP(SEND_LAST_WITH_IMMEDIATE))
 			break;
 	nack_inv:
-		/*
-		 * A NAK will ACK earlier sends and RDMA writes.
-		 * Don't queue the NAK if a RDMA read, atomic, or NAK
-		 * is pending though.
-		 */
-		if (qp->r_ack_state >= OP(COMPARE_SWAP))
-			goto send_ack;
 		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;
 		goto send_ack;
@@ -1441,9 +1587,8 @@ void ipath_rc_rcv(struct ipath_ibdev *de
 			 * Don't queue the NAK if a RDMA read or atomic
 			 * is pending though.
 			 */
-			if (qp->r_ack_state >= OP(COMPARE_SWAP))
-				goto send_ack;
-			qp->r_ack_state = OP(SEND_ONLY);
+			if (qp->r_nak_state)
+				goto done;
 			qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
 			qp->r_ack_psn = qp->r_psn;
 			goto send_ack;
@@ -1567,7 +1712,19 @@ void ipath_rc_rcv(struct ipath_ibdev *de
 			goto rnr_nak;
 		goto send_last_imm;
 
-	case OP(RDMA_READ_REQUEST):
+	case OP(RDMA_READ_REQUEST): {
+		struct ipath_ack_entry *e;
+		u32 len;
+		u8 next;
+
+		if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
+			goto nack_acc;
+		next = qp->r_head_ack_queue + 1;
+		if (next > IPATH_MAX_RDMA_ATOMIC)
+			next = 0;
+		if (unlikely(next == qp->s_tail_ack_queue))
+			goto nack_inv;
+		e = &qp->s_ack_queue[qp->r_head_ack_queue];
 		/* RETH comes after BTH */
 		if (!header_in_data)
 			reth = &ohdr->u.rc.reth;
@@ -1575,72 +1732,75 @@ void ipath_rc_rcv(struct ipath_ibdev *de
 			reth = (struct ib_reth *)data;
 			data += sizeof(*reth);
 		}
-		if (unlikely(!(qp->qp_access_flags &
-			       IB_ACCESS_REMOTE_READ)))
-			goto nack_acc;
-		spin_lock_irq(&qp->s_lock);
-		qp->s_rdma_len = be32_to_cpu(reth->length);
-		if (qp->s_rdma_len != 0) {
+		len = be32_to_cpu(reth->length);
+		if (len) {
 			u32 rkey = be32_to_cpu(reth->rkey);
 			u64 vaddr = be64_to_cpu(reth->vaddr);
 			int ok;
 
 			/* Check rkey & NAK */
-			ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
-					   qp->s_rdma_len, vaddr, rkey,
-					   IB_ACCESS_REMOTE_READ);
-			if (unlikely(!ok)) {
-				spin_unlock_irq(&qp->s_lock);
+			ok = ipath_rkey_ok(qp, &e->rdma_sge, len, vaddr,
+					   rkey, IB_ACCESS_REMOTE_READ);
+			if (unlikely(!ok))
 				goto nack_acc;
-			}
 			/*
 			 * Update the next expected PSN.  We add 1 later
 			 * below, so only add the remainder here.
 			 */
-			if (qp->s_rdma_len > pmtu)
-				qp->r_psn += (qp->s_rdma_len - 1) / pmtu;
+			if (len > pmtu)
+				qp->r_psn += (len - 1) / pmtu;
 		} else {
-			qp->s_rdma_sge.sg_list = NULL;
-			qp->s_rdma_sge.num_sge = 0;
-			qp->s_rdma_sge.sge.mr = NULL;
-			qp->s_rdma_sge.sge.vaddr = NULL;
-			qp->s_rdma_sge.sge.length = 0;
-			qp->s_rdma_sge.sge.sge_length = 0;
+			e->rdma_sge.sg_list = NULL;
+			e->rdma_sge.num_sge = 0;
+			e->rdma_sge.sge.mr = NULL;
+			e->rdma_sge.sge.vaddr = NULL;
+			e->rdma_sge.sge.length = 0;
+			e->rdma_sge.sge.sge_length = 0;
 		}
+		e->opcode = opcode;
+		e->psn = psn;
 		/*
 		 * We need to increment the MSN here instead of when we
 		 * finish sending the result since a duplicate request would
 		 * increment it more than once.
 		 */
 		qp->r_msn++;
-
-		qp->s_ack_state = opcode;
-		qp->s_ack_psn = psn;
-		spin_unlock_irq(&qp->s_lock);
-
 		qp->r_psn++;
 		qp->r_state = opcode;
 		qp->r_nak_state = 0;
+		barrier();
+		qp->r_head_ack_queue = next;
 
 		/* Call ipath_do_rc_send() in another thread. */
 		tasklet_hi_schedule(&qp->s_task);
 
 		goto done;
+	}
 
 	case OP(COMPARE_SWAP):
 	case OP(FETCH_ADD): {
 		struct ib_atomic_eth *ateth;
+		struct ipath_ack_entry *e;
 		u64 vaddr;
+		atomic64_t *maddr;
 		u64 sdata;
 		u32 rkey;
+		u8 next;
 
+		if (unlikely(!(qp->qp_access_flags &
+			       IB_ACCESS_REMOTE_ATOMIC)))
+			goto nack_acc;
+		next = qp->r_head_ack_queue + 1;
+		if (next > IPATH_MAX_RDMA_ATOMIC)
+			next = 0;
+		if (unlikely(next == qp->s_tail_ack_queue))
+			goto nack_inv;
 		if (!header_in_data)
 			ateth = &ohdr->u.atomic_eth;
-		else {
+		else
 			ateth = (struct ib_atomic_eth *)data;
-			data += sizeof(*ateth);
-		}
-		vaddr = be64_to_cpu(ateth->vaddr);
+		vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) |
+			be32_to_cpu(ateth->vaddr[1]);
 		if (unlikely(vaddr & (sizeof(u64) - 1)))
 			goto nack_inv;
 		rkey = be32_to_cpu(ateth->rkey);
@@ -1649,63 +1809,50 @@ void ipath_rc_rcv(struct ipath_ibdev *de
 					    sizeof(u64), vaddr, rkey,
 					    IB_ACCESS_REMOTE_ATOMIC)))
 			goto nack_acc;
-		if (unlikely(!(qp->qp_access_flags &
-			       IB_ACCESS_REMOTE_ATOMIC)))
-			goto nack_acc;
 		/* Perform atomic OP and save result. */
+		maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
 		sdata = be64_to_cpu(ateth->swap_data);
-		spin_lock_irq(&dev->pending_lock);
-		qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr;
-		if (opcode == OP(FETCH_ADD))
-			*(u64 *) qp->r_sge.sge.vaddr =
-				qp->r_atomic_data + sdata;
-		else if (qp->r_atomic_data ==
-			 be64_to_cpu(ateth->compare_data))
-			*(u64 *) qp->r_sge.sge.vaddr = sdata;
-		spin_unlock_irq(&dev->pending_lock);
+		e = &qp->s_ack_queue[qp->r_head_ack_queue];
+		e->atomic_data = (opcode == OP(FETCH_ADD)) ?
+			(u64) atomic64_add_return(sdata, maddr) - sdata :
+			(u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+				      be64_to_cpu(ateth->compare_data),
+				      sdata);
+		e->opcode = opcode;
+		e->psn = psn & IPATH_PSN_MASK;
 		qp->r_msn++;
-		qp->r_atomic_psn = psn & IPATH_PSN_MASK;
-		psn |= 1 << 31;
-		break;
+		qp->r_psn++;
+		qp->r_state = opcode;
+		qp->r_nak_state = 0;
+		barrier();
+		qp->r_head_ack_queue = next;
+
+		/* Call ipath_do_rc_send() in another thread. */
+		tasklet_hi_schedule(&qp->s_task);
+
+		goto done;
 	}
 
 	default:
-		/* Drop packet for unknown opcodes. */
-		goto done;
+		/* NAK unknown opcodes. */
+		goto nack_inv;
 	}
 	qp->r_psn++;
 	qp->r_state = opcode;
+	qp->r_ack_psn = psn;
 	qp->r_nak_state = 0;
 	/* Send an ACK if requested or required. */
-	if (psn & (1 << 31)) {
-		/*
-		 * Coalesce ACKs unless there is a RDMA READ or
-		 * ATOMIC pending.
-		 */
-		if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-			qp->r_ack_state = opcode;
-			qp->r_ack_psn = psn;
-		}
+	if (psn & (1 << 31))
 		goto send_ack;
-	}
 	goto done;
 
 nack_acc:
-	/*
-	 * A NAK will ACK earlier sends and RDMA writes.
-	 * Don't queue the NAK if a RDMA read, atomic, or NAK
-	 * is pending though.
-	 */
-	if (qp->r_ack_state < OP(COMPARE_SWAP)) {
-		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;
-	}
+	ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
+	qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
+	qp->r_ack_psn = qp->r_psn;
+
 send_ack:
-	/* Send ACK right away unless the send tasklet has a pending ACK. */
-	if (qp->s_ack_state == OP(ACKNOWLEDGE))
-		send_rc_ack(qp);
+	send_rc_ack(qp);
 
 done:
 	return;
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index dffc760..c182bcd 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -126,9 +126,18 @@ #define INFINIPATH_E_INVALIDADDR     0x0
 #define INFINIPATH_E_RESET           0x0004000000000000ULL
 #define INFINIPATH_E_HARDWARE        0x0008000000000000ULL
 
+/*
+ * this is used to print "common" packet errors only when the
+ * __IPATH_ERRPKTDBG bit is set in ipath_debug.
+ */
+#define INFINIPATH_E_PKTERRS ( INFINIPATH_E_SPKTLEN \
+		| INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_RVCRC \
+		| INFINIPATH_E_RICRC | INFINIPATH_E_RSHORTPKTLEN \
+		| INFINIPATH_E_REBP )
+
 /* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
 /* TXEMEMPARITYERR bit 0: PIObuf, 1: PIOpbc, 2: launchfifo
- * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2: eagerTID, 3: expTID
+ * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2:  expTID, 3: eagerTID
  * 		bit 4: flag buffer, 5: datainfo, 6: header info */
 #define INFINIPATH_HWE_TXEMEMPARITYERR_MASK 0xFULL
 #define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40
@@ -143,8 +152,8 @@ #define INFINIPATH_HWE_TXEMEMPARITYERR_P
 /* 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_EXPTID   0x04ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x08ULL
 #define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF  0x10ULL
 #define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL
 #define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO  0x40ULL
@@ -299,13 +308,6 @@ #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), HT-only */
-#define INFINIPATH_RT_VALID 0x8000000000000000ULL
-#define INFINIPATH_RT_ADDR_SHIFT 0
-#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF
-#define INFINIPATH_RT_BUFSIZE_SHIFT 48
 
 /*
  * IPATH_PIO_MAXIBHDR is the max IB header size allowed for in our
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index e86cb17..d9c2a9b 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -202,6 +202,7 @@ int ipath_get_rwqe(struct ipath_qp *qp, 
 	wq->tail = tail;
 
 	ret = 1;
+	qp->r_wrid_valid = 1;
 	if (handler) {
 		u32 n;
 
@@ -229,7 +230,6 @@ int ipath_get_rwqe(struct ipath_qp *qp, 
 		}
 	}
 	spin_unlock_irqrestore(&rq->lock, flags);
-	qp->r_wrid_valid = 1;
 
 bail:
 	return ret;
@@ -255,6 +255,7 @@ static void ipath_ruc_loopback(struct ip
 	unsigned long flags;
 	struct ib_wc wc;
 	u64 sdata;
+	atomic64_t *maddr;
 
 	qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn);
 	if (!qp) {
@@ -265,7 +266,8 @@ static void ipath_ruc_loopback(struct ip
 again:
 	spin_lock_irqsave(&sqp->s_lock, flags);
 
-	if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK)) {
+	if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK) ||
+	    qp->s_rnr_timeout) {
 		spin_unlock_irqrestore(&sqp->s_lock, flags);
 		goto done;
 	}
@@ -310,7 +312,7 @@ again:
 				sqp->s_rnr_retry--;
 			dev->n_rnr_naks++;
 			sqp->s_rnr_timeout =
-				ib_ipath_rnr_table[sqp->r_min_rnr_timer];
+				ib_ipath_rnr_table[qp->r_min_rnr_timer];
 			ipath_insert_rnr_queue(sqp);
 			goto done;
 		}
@@ -343,20 +345,22 @@ again:
 			wc.sl = sqp->remote_ah_attr.sl;
 			wc.dlid_path_bits = 0;
 			wc.port_num = 0;
+			spin_lock_irqsave(&sqp->s_lock, flags);
 			ipath_sqerror_qp(sqp, &wc);
+			spin_unlock_irqrestore(&sqp->s_lock, flags);
 			goto done;
 		}
 		break;
 
 	case IB_WR_RDMA_READ:
+		if (unlikely(!(qp->qp_access_flags &
+			       IB_ACCESS_REMOTE_READ)))
+			goto acc_err;
 		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)))
 			goto acc_err;
-		if (unlikely(!(qp->qp_access_flags &
-			       IB_ACCESS_REMOTE_READ)))
-			goto acc_err;
 		qp->r_sge.sge = wqe->sg_list[0];
 		qp->r_sge.sg_list = wqe->sg_list + 1;
 		qp->r_sge.num_sge = wqe->wr.num_sge;
@@ -364,22 +368,22 @@ again:
 
 	case IB_WR_ATOMIC_CMP_AND_SWP:
 	case IB_WR_ATOMIC_FETCH_AND_ADD:
+		if (unlikely(!(qp->qp_access_flags &
+			       IB_ACCESS_REMOTE_ATOMIC)))
+			goto acc_err;
 		if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
-					    wqe->wr.wr.rdma.remote_addr,
-					    wqe->wr.wr.rdma.rkey,
+					    wqe->wr.wr.atomic.remote_addr,
+					    wqe->wr.wr.atomic.rkey,
 					    IB_ACCESS_REMOTE_ATOMIC)))
 			goto acc_err;
 		/* Perform atomic OP and save result. */
-		sdata = wqe->wr.wr.atomic.swap;
-		spin_lock_irqsave(&dev->pending_lock, flags);
-		qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr;
-		if (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-			*(u64 *) qp->r_sge.sge.vaddr =
-				qp->r_atomic_data + sdata;
-		else if (qp->r_atomic_data == wqe->wr.wr.atomic.compare_add)
-			*(u64 *) qp->r_sge.sge.vaddr = sdata;
-		spin_unlock_irqrestore(&dev->pending_lock, flags);
-		*(u64 *) sqp->s_sge.sge.vaddr = qp->r_atomic_data;
+		maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
+		sdata = wqe->wr.wr.atomic.compare_add;
+		*(u64 *) sqp->s_sge.sge.vaddr =
+			(wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
+			(u64) atomic64_add_return(sdata, maddr) - sdata :
+			(u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
+				      sdata, wqe->wr.wr.atomic.swap);
 		goto send_comp;
 
 	default:
@@ -440,7 +444,7 @@ again:
 send_comp:
 	sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
 
-	if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &sqp->s_flags) ||
+	if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
 	    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
 		wc.wr_id = wqe->wr.wr_id;
 		wc.status = IB_WC_SUCCESS;
@@ -502,7 +506,7 @@ void ipath_no_bufs_available(struct ipat
 	 * We clear the tasklet flag now since we are committing to return
 	 * from the tasklet function.
 	 */
-	clear_bit(IPATH_S_BUSY, &qp->s_flags);
+	clear_bit(IPATH_S_BUSY, &qp->s_busy);
 	tasklet_unlock(&qp->s_task);
 	want_buffer(dev->dd);
 	dev->n_piowait++;
@@ -541,6 +545,9 @@ int ipath_post_ruc_send(struct ipath_qp 
 		    wr->sg_list[0].addr & (sizeof(u64) - 1))) {
 		ret = -EINVAL;
 		goto bail;
+	} else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
+		ret = -EINVAL;
+		goto bail;
 	}
 	/* IB spec says that num_sge == 0 is OK. */
 	if (wr->num_sge > qp->s_max_sge) {
@@ -647,7 +654,7 @@ void ipath_do_ruc_send(unsigned long dat
 	u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
 	struct ipath_other_headers *ohdr;
 
-	if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
+	if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
 		goto bail;
 
 	if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
@@ -683,19 +690,15 @@ again:
 	 */
 	spin_lock_irqsave(&qp->s_lock, flags);
 
-	/* Sending responses has higher priority over sending requests. */
-	if (qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE &&
-	    (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0)
-		bth2 = qp->s_ack_psn++ & IPATH_PSN_MASK;
-	else if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
-		   ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
-		   ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
+	if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
+	       ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
+	       ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
 		/*
 		 * Clear the busy bit before unlocking to avoid races with
 		 * adding new work queue items and then failing to process
 		 * them.
 		 */
-		clear_bit(IPATH_S_BUSY, &qp->s_flags);
+		clear_bit(IPATH_S_BUSY, &qp->s_busy);
 		spin_unlock_irqrestore(&qp->s_lock, flags);
 		goto bail;
 	}
@@ -728,7 +731,7 @@ again:
 	goto again;
 
 clear:
-	clear_bit(IPATH_S_BUSY, &qp->s_flags);
+	clear_bit(IPATH_S_BUSY, &qp->s_busy);
 bail:
 	return;
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 9403350..03acae6 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -139,33 +139,24 @@ struct ib_srq *ipath_create_srq(struct i
 	 * See ipath_mmap() for details.
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		struct ipath_mmap_info *ip;
-		__u64 offset = (__u64) srq->rq.wq;
 		int err;
+		u32 s = sizeof(struct ipath_rwq) + srq->rq.size * sz;
 
-		err = ib_copy_to_udata(udata, &offset, sizeof(offset));
-		if (err) {
-			ret = ERR_PTR(err);
+		srq->ip =
+		    ipath_create_mmap_info(dev, s,
+					   ibpd->uobject->context,
+					   srq->rq.wq);
+		if (!srq->ip) {
+			ret = ERR_PTR(-ENOMEM);
 			goto bail_wq;
 		}
 
-		/* Allocate info for ipath_mmap(). */
-		ip = kmalloc(sizeof(*ip), GFP_KERNEL);
-		if (!ip) {
-			ret = ERR_PTR(-ENOMEM);
-			goto bail_wq;
+		err = ib_copy_to_udata(udata, &srq->ip->offset,
+				       sizeof(srq->ip->offset));
+		if (err) {
+			ret = ERR_PTR(err);
+			goto bail_ip;
 		}
-		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;
 
@@ -181,21 +172,27 @@ struct ib_srq *ipath_create_srq(struct i
 	if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
 		spin_unlock(&dev->n_srqs_lock);
 		ret = ERR_PTR(-ENOMEM);
-		goto bail_wq;
+		goto bail_ip;
 	}
 
  	dev->n_srqs_allocated++;
 	spin_unlock(&dev->n_srqs_lock);
 
+	if (srq->ip) {
+		spin_lock_irq(&dev->pending_lock);
+		list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps);
+		spin_unlock_irq(&dev->pending_lock);
+	}
+
 	ret = &srq->ibsrq;
 	goto done;
 
+bail_ip:
+	kfree(srq->ip);
 bail_wq:
 	vfree(srq->rq.wq);
-
 bail_srq:
 	kfree(srq);
-
 done:
 	return ret;
 }
@@ -312,13 +309,13 @@ int ipath_modify_srq(struct ib_srq *ibsr
 		if (srq->ip) {
 			struct ipath_mmap_info *ip = srq->ip;
 			struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
+			u32 s = sizeof(struct ipath_rwq) + size * sz;
 
-			ip->obj = wq;
-			ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
-					      size * sz);
+			ipath_update_mmap_info(dev, ip, s, wq);
 			spin_lock_irq(&dev->pending_lock);
-			ip->next = dev->pending_mmaps;
-			dev->pending_mmaps = ip;
+			if (list_empty(&ip->pending_mmaps))
+				list_add(&ip->pending_mmaps,
+					 &dev->pending_mmaps);
 			spin_unlock_irq(&dev->pending_lock);
 		}
 	} else if (attr_mask & IB_SRQ_LIMIT) {
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index 30a8259..d8b5e4c 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -31,8 +31,6 @@
  * SOFTWARE.
  */
 
-#include <linux/pci.h>
-
 #include "ipath_kernel.h"
 
 struct infinipath_stats ipath_stats;
@@ -207,7 +205,7 @@ void ipath_get_faststats(unsigned long o
 	 * don't access the chip while running diags, or memory diags can
 	 * fail
 	 */
-	if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT) ||
+	if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_INITTED) ||
 	    ipath_diag_inuse)
 		/* but re-arm the timer, for diags case; won't hurt other */
 		goto done;
@@ -237,11 +235,13 @@ void ipath_get_faststats(unsigned long o
 	if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs)
 	    && time_after(jiffies, dd->ipath_unmasktime)) {
 		char ebuf[256];
-		ipath_decode_err(ebuf, sizeof ebuf,
+		int iserr;
+		iserr = ipath_decode_err(ebuf, sizeof ebuf,
 				 (dd->ipath_maskederrs & ~dd->
 				  ipath_ignorederrs));
 		if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
-		    ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
+				~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
+				INFINIPATH_E_PKTERRS ))
 			ipath_dev_err(dd, "Re-enabling masked errors "
 				      "(%s)\n", ebuf);
 		else {
@@ -252,8 +252,12 @@ void ipath_get_faststats(unsigned long o
 			 * them.  So only complain about these at debug
 			 * level.
 			 */
-			ipath_dbg("Disabling frequent queue full errors "
-				  "(%s)\n", ebuf);
+			if (iserr)
+					ipath_dbg("Re-enabling queue full errors (%s)\n",
+							ebuf);
+			else
+				ipath_cdbg(ERRPKT, "Re-enabling packet"
+						" problem interrupt (%s)\n", ebuf);
 		}
 		dd->ipath_maskederrs = dd->ipath_ignorederrs;
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index ffa6318..4dc398d 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -32,7 +32,6 @@
  */
 
 #include <linux/ctype.h>
-#include <linux/pci.h>
 
 #include "ipath_kernel.h"
 #include "ipath_common.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 325d663..1c2b03c 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -42,7 +42,7 @@ static void complete_last_send(struct ip
 {
 	if (++qp->s_last == qp->s_size)
 		qp->s_last = 0;
-	if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) ||
+	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
 	    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
 		wc->wr_id = wqe->wr.wr_id;
 		wc->status = IB_WC_SUCCESS;
@@ -344,13 +344,13 @@ void ipath_uc_rcv(struct ipath_ibdev *de
 	send_first:
 		if (qp->r_reuse_sge) {
 			qp->r_reuse_sge = 0;
-			qp->r_sge = qp->s_rdma_sge;
+			qp->r_sge = qp->s_rdma_read_sge;
 		} else if (!ipath_get_rwqe(qp, 0)) {
 			dev->n_pkt_drops++;
 			goto done;
 		}
 		/* Save the WQE so we can reuse it in case of an error. */
-		qp->s_rdma_sge = qp->r_sge;
+		qp->s_rdma_read_sge = qp->r_sge;
 		qp->r_rcv_len = 0;
 		if (opcode == OP(SEND_ONLY))
 			goto send_last;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 9a3e546..a518f7c 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -308,6 +308,11 @@ int ipath_post_ud_send(struct ipath_qp *
 		goto bail;
 	}
 
+	if (wr->wr.ud.ah->pd != qp->ibqp.pd) {
+		ret = -EPERM;
+		goto bail;
+	}
+
 	/* IB spec says that num_sge == 0 is OK. */
 	if (wr->num_sge > qp->s_max_sge) {
 		ret = -EINVAL;
@@ -467,7 +472,7 @@ int ipath_post_ud_send(struct ipath_qp *
 
 done:
 	/* Queue the completion status entry. */
-	if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) ||
+	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
 	    (wr->send_flags & IB_SEND_SIGNALED)) {
 		wc.wr_id = wr->wr_id;
 		wc.status = IB_WC_SUCCESS;
@@ -647,6 +652,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));
+	qp->r_wrid_valid = 0;
 	wc.wr_id = qp->r_wr_id;
 	wc.status = IB_WC_SUCCESS;
 	wc.opcode = IB_WC_RECV;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 2aaacdb..12933e7 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -438,6 +438,10 @@ void ipath_ib_rcv(struct ipath_ibdev *de
 		struct ipath_mcast *mcast;
 		struct ipath_mcast_qp *p;
 
+		if (lnh != IPATH_LRH_GRH) {
+			dev->n_pkt_drops++;
+			goto bail;
+		}
 		mcast = ipath_mcast_find(&hdr->u.l.grh.dgid);
 		if (mcast == NULL) {
 			dev->n_pkt_drops++;
@@ -445,8 +449,7 @@ void ipath_ib_rcv(struct ipath_ibdev *de
 		}
 		dev->n_multicast_rcv++;
 		list_for_each_entry_rcu(p, &mcast->qp_list, list)
-			ipath_qp_rcv(dev, hdr, lnh == IPATH_LRH_GRH, data,
-				     tlen, p->qp);
+			ipath_qp_rcv(dev, hdr, 1, data, tlen, p->qp);
 		/*
 		 * Notify ipath_multicast_detach() if it is waiting for us
 		 * to finish.
@@ -773,7 +776,6 @@ int ipath_verbs_send(struct ipath_devdat
 	/* +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;
 	}
@@ -980,14 +982,14 @@ static int ipath_query_device(struct ib_
 	props->max_cqe = ib_ipath_max_cqes;
 	props->max_mr = dev->lk_table.max;
 	props->max_pd = ib_ipath_max_pds;
-	props->max_qp_rd_atom = 1;
-	props->max_qp_init_rd_atom = 1;
+	props->max_qp_rd_atom = IPATH_MAX_RDMA_ATOMIC;
+	props->max_qp_init_rd_atom = 255;
 	/* props->max_res_rd_atom */
 	props->max_srq = ib_ipath_max_srqs;
 	props->max_srq_wr = ib_ipath_max_srq_wrs;
 	props->max_srq_sge = ib_ipath_max_srq_sges;
 	/* props->local_ca_ack_delay */
-	props->atomic_cap = IB_ATOMIC_HCA;
+	props->atomic_cap = IB_ATOMIC_GLOB;
 	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;
@@ -1474,7 +1476,10 @@ int ipath_register_ib_device(struct ipat
 		ret = -ENOMEM;
 		goto err_lk;
 	}
+	INIT_LIST_HEAD(&idev->pending_mmaps);
 	spin_lock_init(&idev->pending_lock);
+	idev->mmap_offset = PAGE_SIZE;
+	spin_lock_init(&idev->mmap_offset_lock);
 	INIT_LIST_HEAD(&idev->pending[0]);
 	INIT_LIST_HEAD(&idev->pending[1]);
 	INIT_LIST_HEAD(&idev->pending[2]);
@@ -1556,8 +1561,8 @@ int ipath_register_ib_device(struct ipat
 		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
 	dev->node_type = RDMA_NODE_IB_CA;
 	dev->phys_port_cnt = 1;
+	dev->num_comp_vectors = 1;
 	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;
 	dev->query_port = ipath_query_port;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index c0c8d5b..7064fc2 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -40,9 +40,12 @@ #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/kref.h>
 #include <rdma/ib_pack.h>
+#include <rdma/ib_user_verbs.h>
 
 #include "ipath_layer.h"
 
+#define IPATH_MAX_RDMA_ATOMIC	4
+
 #define QPN_MAX                 (1 << 24)
 #define QPNMAP_ENTRIES          (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE)
 
@@ -89,7 +92,7 @@ struct ib_reth {
 } __attribute__ ((packed));
 
 struct ib_atomic_eth {
-	__be64 vaddr;
+	__be32 vaddr[2];	/* unaligned so access as 2 32-bit words */
 	__be32 rkey;
 	__be64 swap_data;
 	__be64 compare_data;
@@ -108,7 +111,7 @@ struct ipath_other_headers {
 		} rc;
 		struct {
 			__be32 aeth;
-			__be64 atomic_ack_eth;
+			__be32 atomic_ack_eth[2];
 		} at;
 		__be32 imm_data;
 		__be32 aeth;
@@ -170,12 +173,12 @@ struct ipath_ah {
  * this as its vm_private_data.
  */
 struct ipath_mmap_info {
-	struct ipath_mmap_info *next;
+	struct list_head pending_mmaps;
 	struct ib_ucontext *context;
 	void *obj;
+	__u64 offset;
 	struct kref ref;
 	unsigned size;
-	unsigned mmap_cnt;
 };
 
 /*
@@ -186,7 +189,7 @@ struct ipath_mmap_info {
 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 */
+	struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
 };
 
 /*
@@ -312,6 +315,19 @@ struct ipath_sge_state {
 };
 
 /*
+ * This structure holds the information that the send tasklet needs
+ * to send a RDMA read response or atomic operation.
+ */
+struct ipath_ack_entry {
+	u8 opcode;
+	u32 psn;
+	union {
+		struct ipath_sge_state rdma_sge;
+		u64 atomic_data;
+	};
+};
+
+/*
  * Variables prefixed with s_ are for the requester (sender).
  * Variables prefixed with r_ are for the responder (receiver).
  * Variables prefixed with ack_ are for responder replies.
@@ -333,24 +349,24 @@ struct ipath_qp {
 	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 */
-	struct ipath_sge_state s_rdma_sge;
+	struct ipath_ack_entry s_ack_queue[IPATH_MAX_RDMA_ATOMIC + 1];
+	struct ipath_sge_state s_ack_rdma_sge;
+	struct ipath_sge_state s_rdma_read_sge;
 	struct ipath_sge_state r_sge;	/* current receive data */
 	spinlock_t s_lock;
-	unsigned long s_flags;
+	unsigned long s_busy;
 	u32 s_hdrwords;		/* size of s_hdr in 32 bit words */
 	u32 s_cur_size;		/* size of send packet in bytes */
 	u32 s_len;		/* total length of s_sge */
-	u32 s_rdma_len;		/* total length of s_rdma_sge */
+	u32 s_rdma_read_len;	/* total length of s_rdma_read_sge */
 	u32 s_next_psn;		/* PSN for next request */
 	u32 s_last_psn;		/* last response PSN processed */
 	u32 s_psn;		/* current packet sequence number */
-	u32 s_ack_psn;		/* PSN for RDMA_READ */
+	u32 s_ack_rdma_psn;	/* PSN for sending RDMA read responses */
+	u32 s_ack_psn;		/* PSN for acking sends and RDMA writes */
 	u32 s_rnr_timeout;	/* number of milliseconds for RNR timeout */
 	u32 r_ack_psn;		/* PSN for next ACK or atomic ACK */
 	u64 r_wr_id;		/* ID for current receive WQE */
-	u64 r_atomic_data;	/* data for last atomic op */
-	u32 r_atomic_psn;	/* PSN of last atomic op */
 	u32 r_len;		/* total length of r_sge */
 	u32 r_rcv_len;		/* receive data len processed */
 	u32 r_psn;		/* expected rcv packet sequence number */
@@ -360,12 +376,13 @@ struct ipath_qp {
 	u8 s_ack_state;		/* opcode of packet to ACK */
 	u8 s_nak_state;		/* non-zero if NAK is pending */
 	u8 r_state;		/* opcode of last packet received */
-	u8 r_ack_state;		/* opcode of packet to ACK */
 	u8 r_nak_state;		/* non-zero if NAK is pending */
 	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 r_max_rd_atomic;	/* max number of RDMA read/atomic to receive */
+	u8 r_head_ack_queue;	/* index into s_ack_queue[] */
 	u8 qp_access_flags;
 	u8 s_max_sge;		/* size of s_wq->sg_list */
 	u8 s_retry_cnt;		/* number of times to retry */
@@ -374,6 +391,10 @@ struct ipath_qp {
 	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 s_max_rd_atomic;	/* max number of RDMA read/atomic to send */
+	u8 s_num_rd_atomic;	/* number of RDMA read/atomic pending */
+	u8 s_tail_ack_queue;	/* index into s_ack_queue[] */
+	u8 s_flags;
 	u8 timeout;		/* Timeout for this QP */
 	enum ib_mtu path_mtu;
 	u32 remote_qpn;
@@ -390,13 +411,18 @@ struct ipath_qp {
 	struct ipath_sge r_sg_list[0];	/* verified SGEs */
 };
 
+/* Bit definition for s_busy. */
+#define IPATH_S_BUSY		0
+
 /*
  * Bit definitions for s_flags.
  */
-#define IPATH_S_BUSY		0
-#define IPATH_S_SIGNAL_REQ_WR	1
+#define IPATH_S_SIGNAL_REQ_WR	0x01
+#define IPATH_S_FENCE_PENDING	0x02
+#define IPATH_S_RDMAR_PENDING	0x04
+#define IPATH_S_ACK_PENDING	0x08
 
-#define IPATH_PSN_CREDIT	2048
+#define IPATH_PSN_CREDIT	512
 
 /*
  * Since struct ipath_swqe is not a fixed size, we can't simply index into
@@ -459,9 +485,10 @@ struct ipath_opcode_stats {
 
 struct ipath_ibdev {
 	struct ib_device ibdev;
-	struct list_head dev_list;
 	struct ipath_devdata *dd;
-	struct ipath_mmap_info *pending_mmaps;
+	struct list_head pending_mmaps;
+	spinlock_t mmap_offset_lock;
+	u32 mmap_offset;
 	int ib_unit;		/* This is the device number */
 	u16 sm_lid;		/* in host order */
 	u8 sm_sl;
@@ -706,17 +733,15 @@ int ipath_query_srq(struct ib_srq *ibsrq
 
 int ipath_destroy_srq(struct ib_srq *ibsrq);
 
-void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
-
 int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
 
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
 			      struct ib_ucontext *context,
 			      struct ib_udata *udata);
 
 int ipath_destroy_cq(struct ib_cq *ibcq);
 
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
 
 int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
 
@@ -744,6 +769,15 @@ int ipath_dealloc_fmr(struct ib_fmr *ibf
 
 void ipath_release_mmap_info(struct kref *ref);
 
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+					       u32 size,
+					       struct ib_ucontext *context,
+					       void *obj);
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+			    struct ipath_mmap_info *ip,
+			    u32 size, void *obj);
+
 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);
@@ -757,9 +791,6 @@ u32 ipath_make_grh(struct ipath_ibdev *d
 
 void ipath_do_ruc_send(unsigned long data);
 
-u32 ipath_make_rc_ack(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
-		      u32 pmtu);
-
 int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
 		      u32 pmtu, u32 *bth0p, u32 *bth2p);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index efd79ef..cf0868f 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -726,11 +726,12 @@ repoll:
 	return err == 0 || err == -EAGAIN ? npolled : err;
 }
 
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
 {
 	__be32 doorbell[2];
 
-	doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ?
+	doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) ==
+				   IB_CQ_SOLICITED ?
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_TAVOR_CQ_DB_REQ_NOT)      |
 				  to_mcq(cq)->cqn);
@@ -743,7 +744,7 @@ int mthca_tavor_arm_cq(struct ib_cq *cq,
 	return 0;
 }
 
-int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
 {
 	struct mthca_cq *cq = to_mcq(ibcq);
 	__be32 doorbell[2];
@@ -755,7 +756,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibc
 
 	doorbell[0] = ci;
 	doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
-				  (notify == IB_CQ_SOLICITED ? 1 : 2));
+				  ((flags & IB_CQ_SOLICITED_MASK) ==
+				   IB_CQ_SOLICITED ? 1 : 2));
 
 	mthca_write_db_rec(doorbell, cq->arm_db);
 
@@ -766,7 +768,7 @@ int mthca_arbel_arm_cq(struct ib_cq *ibc
 	wmb();
 
 	doorbell[0] = cpu_to_be32((sn << 28)                       |
-				  (notify == IB_CQ_SOLICITED ?
+				  ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
 				   MTHCA_ARBEL_CQ_DB_REQ_NOT)      |
 				  cq->cqn);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index b7e42ef..9bae3cc 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -495,8 +495,8 @@ void mthca_unmap_eq_icm(struct mthca_dev
 
 int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
 		  struct ib_wc *entry);
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
-int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
+int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
 int mthca_init_cq(struct mthca_dev *dev, int nent,
 		  struct mthca_ucontext *ctx, u32 pdn,
 		  struct mthca_cq *cq);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 0d9b7d0..773145e 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -1013,14 +1013,14 @@ static struct {
 	u64 latest_fw;
 	u32 flags;
 } mthca_hca_table[] = {
-	[TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 4, 0),
+	[TAVOR]        = { .latest_fw = MTHCA_FW_VER(3, 5, 0),
 			   .flags     = 0 },
-	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 600),
+	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),
 			   .flags     = MTHCA_FLAG_PCIE },
-	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 400),
+	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0),
 			   .flags     = MTHCA_FLAG_MEMFREE |
 					MTHCA_FLAG_PCIE },
-	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 1, 0),
+	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 2, 0),
 			   .flags     = MTHCA_FLAG_MEMFREE |
 					MTHCA_FLAG_PCIE    |
 					MTHCA_FLAG_SINAI_OPT }
@@ -1135,7 +1135,7 @@ static int __mthca_init_one(struct pci_d
 		goto err_cmd;
 
 	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",
+		mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
 			   (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
 			   (int) (mdev->fw_ver & 0xffff),
 			   (int) (mthca_hca_table[hca_type].latest_fw >> 32),
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index 5941441..a1ab068 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -38,7 +38,6 @@ #ifndef MTHCA_MEMFREE_H
 #define MTHCA_MEMFREE_H
 
 #include <linux/list.h>
-#include <linux/pci.h>
 #include <linux/mutex.h>
 
 #define MTHCA_ICM_CHUNK_LEN \
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index ee561c5..aa6c70a 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -297,7 +297,8 @@ out:
 
 int mthca_write_mtt_size(struct mthca_dev *dev)
 {
-	if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy)
+	if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy ||
+	    !(dev->mthca_flags & MTHCA_FLAG_FMR))
 		/*
 		 * Be friendly to WRITE_MTT command
 		 * and leave two empty slots for the
@@ -355,7 +356,8 @@ int mthca_write_mtt(struct mthca_dev *de
 	int size = mthca_write_mtt_size(dev);
 	int chunk;
 
-	if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy)
+	if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy ||
+	    !(dev->mthca_flags & MTHCA_FLAG_FMR))
 		return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len);
 
 	while (list_len > 0) {
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 0725ad7..1c05486 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -663,6 +663,7 @@ static int mthca_destroy_qp(struct ib_qp
 }
 
 static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+				     int comp_vector,
 				     struct ib_ucontext *context,
 				     struct ib_udata *udata)
 {
@@ -1292,8 +1293,8 @@ int mthca_register_device(struct mthca_d
 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
 	dev->ib_dev.node_type            = RDMA_NODE_IB_CA;
 	dev->ib_dev.phys_port_cnt        = dev->limits.num_ports;
+	dev->ib_dev.num_comp_vectors     = 1;
 	dev->ib_dev.dma_device           = &dev->pdev->dev;
-	dev->ib_dev.class_dev.dev        = &dev->pdev->dev;
 	dev->ib_dev.query_device         = mthca_query_device;
 	dev->ib_dev.query_port           = mthca_query_port;
 	dev->ib_dev.modify_device        = mthca_modify_device;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 1c6b63a..fee60c8 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -701,6 +701,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, 
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
 	}
 
+	if (ibqp->qp_type == IB_QPT_RC &&
+	    cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
+		u8 sched_queue = ibqp->uobject ? 0x2 : 0x1;
+
+		if (mthca_is_memfree(dev))
+			qp_context->rlkey_arbel_sched_queue |= sched_queue;
+		else
+			qp_context->tavor_sched_queue |= cpu_to_be32(sched_queue);
+
+		qp_param->opt_param_mask |=
+			cpu_to_be32(MTHCA_QP_OPTPAR_SCHED_QUEUE);
+	}
+
 	if (attr_mask & IB_QP_TIMEOUT) {
 		qp_context->pri_path.ackto = attr->timeout << 3;
 		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT);
@@ -1419,11 +1432,10 @@ void mthca_free_qp(struct mthca_dev *dev
 	 * unref the mem-free tables and free the QPN in our table.
 	 */
 	if (!qp->ibqp.uobject) {
-		mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
+		mthca_cq_clean(dev, 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);
+		if (send_cq != recv_cq)
+			mthca_cq_clean(dev, send_cq, qp->qpn, NULL);
 
 		mthca_free_memfree(dev, qp);
 		mthca_free_wqe_buf(dev, qp);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index fd55826..87310ee 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -41,7 +41,6 @@ #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/workqueue.h>
-#include <linux/pci.h>
 #include <linux/kref.h>
 #include <linux/if_infiniband.h>
 #include <linux/mutex.h>
@@ -311,6 +310,7 @@ extern struct workqueue_struct *ipoib_wo
 
 /* functions */
 
+int ipoib_poll(struct net_device *dev, int *budget);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
 
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 2b242a4..785bc85 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -228,7 +228,6 @@ static int ipoib_cm_req_handler(struct i
 	struct net_device *dev = cm_id->context;
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_cm_rx *p;
-	unsigned long flags;
 	unsigned psn;
 	int ret;
 
@@ -257,9 +256,9 @@ static int ipoib_cm_req_handler(struct i
 
 	cm_id->context = p;
 	p->jiffies = jiffies;
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irq(&priv->lock);
 	list_add(&p->list, &priv->cm.passive_ids);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irq(&priv->lock);
 	queue_delayed_work(ipoib_workqueue,
 			   &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
 	return 0;
@@ -277,7 +276,6 @@ static int ipoib_cm_rx_handler(struct ib
 {
 	struct ipoib_cm_rx *p;
 	struct ipoib_dev_priv *priv;
-	unsigned long flags;
 	int ret;
 
 	switch (event->event) {
@@ -290,14 +288,14 @@ static int ipoib_cm_rx_handler(struct ib
 	case IB_CM_REJ_RECEIVED:
 		p = cm_id->context;
 		priv = netdev_priv(p->dev);
-		spin_lock_irqsave(&priv->lock, flags);
+		spin_lock_irq(&priv->lock);
 		if (list_empty(&p->list))
 			ret = 0; /* Connection is going away already. */
 		else {
 			list_del_init(&p->list);
 			ret = -ECONNRESET;
 		}
-		spin_unlock_irqrestore(&priv->lock, flags);
+		spin_unlock_irq(&priv->lock);
 		if (ret) {
 			ib_destroy_qp(p->qp);
 			kfree(p);
@@ -351,8 +349,8 @@ void ipoib_cm_handle_rx_wc(struct net_de
 	u64 mapping[IPOIB_CM_RX_SG];
 	int frags;
 
-	ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n",
-		       wr_id, wc->opcode, wc->status);
+	ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
+		       wr_id, wc->status);
 
 	if (unlikely(wr_id >= ipoib_recvq_size)) {
 		ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n",
@@ -372,7 +370,7 @@ void ipoib_cm_handle_rx_wc(struct net_de
 
 	if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
 		p = wc->qp->qp_context;
-		if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
+		if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
 			spin_lock_irqsave(&priv->lock, flags);
 			p->jiffies = jiffies;
 			/* Move this entry to list head, but do
@@ -408,7 +406,7 @@ void ipoib_cm_handle_rx_wc(struct net_de
 	skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb);
 
 	skb->protocol = ((struct ipoib_header *) skb->data)->proto;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, IPOIB_ENCAP_LEN);
 
 	dev->last_rx = jiffies;
@@ -418,7 +416,7 @@ void ipoib_cm_handle_rx_wc(struct net_de
 	skb->dev = dev;
 	/* XXX get correct PACKET_ type here */
 	skb->pkt_type = PACKET_HOST;
-	netif_rx_ni(skb);
+	netif_receive_skb(skb);
 
 repost:
 	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
@@ -504,8 +502,8 @@ static void ipoib_cm_handle_tx_wc(struct
 	struct ipoib_tx_buf *tx_req;
 	unsigned long flags;
 
-	ipoib_dbg_data(priv, "cm send completion: id %d, op %d, status: %d\n",
-		       wr_id, wc->opcode, wc->status);
+	ipoib_dbg_data(priv, "cm send completion: id %d, status: %d\n",
+		       wr_id, wc->status);
 
 	if (unlikely(wr_id >= ipoib_sendq_size)) {
 		ipoib_warn(priv, "cm send completion event with wrid %d (> %d)\n",
@@ -594,7 +592,9 @@ int ipoib_cm_dev_open(struct net_device 
 	priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
 	if (IS_ERR(priv->cm.id)) {
 		printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
-		return IS_ERR(priv->cm.id);
+		ret = PTR_ERR(priv->cm.id);
+		priv->cm.id = NULL;
+		return ret;
 	}
 
 	ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
@@ -603,6 +603,7 @@ int ipoib_cm_dev_open(struct net_device 
 		printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
 		       IPOIB_CM_IETF_ID | priv->qp->qp_num);
 		ib_destroy_cm_id(priv->cm.id);
+		priv->cm.id = NULL;
 		return ret;
 	}
 	return 0;
@@ -612,23 +613,23 @@ void ipoib_cm_dev_stop(struct net_device
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ipoib_cm_rx *p;
-	unsigned long flags;
 
-	if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
+	if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id)
 		return;
 
 	ib_destroy_cm_id(priv->cm.id);
-	spin_lock_irqsave(&priv->lock, flags);
+	priv->cm.id = NULL;
+	spin_lock_irq(&priv->lock);
 	while (!list_empty(&priv->cm.passive_ids)) {
 		p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
 		list_del_init(&p->list);
-		spin_unlock_irqrestore(&priv->lock, flags);
+		spin_unlock_irq(&priv->lock);
 		ib_destroy_cm_id(p->id);
 		ib_destroy_qp(p->qp);
 		kfree(p);
-		spin_lock_irqsave(&priv->lock, flags);
+		spin_lock_irq(&priv->lock);
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irq(&priv->lock);
 
 	cancel_delayed_work(&priv->cm.stale_task);
 }
@@ -642,7 +643,6 @@ static int ipoib_cm_rep_handler(struct i
 	struct ib_qp_attr qp_attr;
 	int qp_attr_mask, ret;
 	struct sk_buff *skb;
-	unsigned long flags;
 
 	p->mtu = be32_to_cpu(data->mtu);
 
@@ -680,12 +680,12 @@ static int ipoib_cm_rep_handler(struct i
 
 	skb_queue_head_init(&skqueue);
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irq(&priv->lock);
 	set_bit(IPOIB_FLAG_OPER_UP, &p->flags);
 	if (p->neigh)
 		while ((skb = __skb_dequeue(&p->neigh->queue)))
 			__skb_queue_tail(&skqueue, skb);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irq(&priv->lock);
 
 	while ((skb = __skb_dequeue(&skqueue))) {
 		skb->dev = p->dev;
@@ -793,7 +793,7 @@ static int ipoib_cm_tx_init(struct ipoib
 	}
 
 	p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
-			     ipoib_sendq_size + 1);
+			     ipoib_sendq_size + 1, 0);
 	if (IS_ERR(p->cq)) {
 		ret = PTR_ERR(p->cq);
 		ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
@@ -895,7 +895,6 @@ static int ipoib_cm_tx_handler(struct ib
 	struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
 	struct net_device *dev = priv->dev;
 	struct ipoib_neigh *neigh;
-	unsigned long flags;
 	int ret;
 
 	switch (event->event) {
@@ -914,7 +913,7 @@ static int ipoib_cm_tx_handler(struct ib
 	case IB_CM_REJ_RECEIVED:
 	case IB_CM_TIMEWAIT_EXIT:
 		ipoib_dbg(priv, "CM error %d.\n", event->event);
-		spin_lock_irqsave(&priv->tx_lock, flags);
+		spin_lock_irq(&priv->tx_lock);
 		spin_lock(&priv->lock);
 		neigh = tx->neigh;
 
@@ -934,7 +933,7 @@ static int ipoib_cm_tx_handler(struct ib
 		}
 
 		spin_unlock(&priv->lock);
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+		spin_unlock_irq(&priv->tx_lock);
 		break;
 	default:
 		break;
@@ -1023,21 +1022,20 @@ static void ipoib_cm_tx_reap(struct work
 	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
 						   cm.reap_task);
 	struct ipoib_cm_tx *p;
-	unsigned long flags;
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
+	spin_lock_irq(&priv->tx_lock);
 	spin_lock(&priv->lock);
 	while (!list_empty(&priv->cm.reap_list)) {
 		p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
 		list_del(&p->list);
 		spin_unlock(&priv->lock);
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+		spin_unlock_irq(&priv->tx_lock);
 		ipoib_cm_tx_destroy(p);
-		spin_lock_irqsave(&priv->tx_lock, flags);
+		spin_lock_irq(&priv->tx_lock);
 		spin_lock(&priv->lock);
 	}
 	spin_unlock(&priv->lock);
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	spin_unlock_irq(&priv->tx_lock);
 }
 
 static void ipoib_cm_skb_reap(struct work_struct *work)
@@ -1046,15 +1044,14 @@ static void ipoib_cm_skb_reap(struct wor
 						   cm.skb_task);
 	struct net_device *dev = priv->dev;
 	struct sk_buff *skb;
-	unsigned long flags;
 
 	unsigned mtu = priv->mcast_mtu;
 
-	spin_lock_irqsave(&priv->tx_lock, flags);
+	spin_lock_irq(&priv->tx_lock);
 	spin_lock(&priv->lock);
 	while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
 		spin_unlock(&priv->lock);
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
+		spin_unlock_irq(&priv->tx_lock);
 		if (skb->protocol == htons(ETH_P_IP))
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -1062,11 +1059,11 @@ #if defined(CONFIG_IPV6) || defined(CONF
 			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
 #endif
 		dev_kfree_skb_any(skb);
-		spin_lock_irqsave(&priv->tx_lock, flags);
+		spin_lock_irq(&priv->tx_lock);
 		spin_lock(&priv->lock);
 	}
 	spin_unlock(&priv->lock);
-	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	spin_unlock_irq(&priv->tx_lock);
 }
 
 void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
@@ -1088,9 +1085,8 @@ static void ipoib_cm_stale_task(struct w
 	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
 						   cm.stale_task.work);
 	struct ipoib_cm_rx *p;
-	unsigned long flags;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irq(&priv->lock);
 	while (!list_empty(&priv->cm.passive_ids)) {
 		/* List if sorted by LRU, start from tail,
 		 * stop when we see a recently used entry */
@@ -1098,13 +1094,13 @@ static void ipoib_cm_stale_task(struct w
 		if (time_before_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT))
 			break;
 		list_del_init(&p->list);
-		spin_unlock_irqrestore(&priv->lock, flags);
+		spin_unlock_irq(&priv->lock);
 		ib_destroy_cm_id(p->id);
 		ib_destroy_qp(p->qp);
 		kfree(p);
-		spin_lock_irqsave(&priv->lock, flags);
+		spin_lock_irq(&priv->lock);
 	}
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock_irq(&priv->lock);
 }
 
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index ba0ee5c..68d72c6 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -172,8 +172,8 @@ static void ipoib_ib_handle_rx_wc(struct
 	struct sk_buff *skb;
 	u64 addr;
 
-	ipoib_dbg_data(priv, "recv completion: id %d, op %d, status: %d\n",
-		       wr_id, wc->opcode, wc->status);
+	ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
+		       wr_id, wc->status);
 
 	if (unlikely(wr_id >= ipoib_recvq_size)) {
 		ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n",
@@ -216,7 +216,7 @@ static void ipoib_ib_handle_rx_wc(struct
 	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_reset_mac_header(skb);
 		skb_pull(skb, IPOIB_ENCAP_LEN);
 
 		dev->last_rx = jiffies;
@@ -226,7 +226,7 @@ static void ipoib_ib_handle_rx_wc(struct
 		skb->dev = dev;
 		/* XXX get correct PACKET_ type here */
 		skb->pkt_type = PACKET_HOST;
-		netif_rx_ni(skb);
+		netif_receive_skb(skb);
 	} else {
 		ipoib_dbg_data(priv, "dropping loopback packet\n");
 		dev_kfree_skb_any(skb);
@@ -245,8 +245,8 @@ static void ipoib_ib_handle_tx_wc(struct
 	struct ipoib_tx_buf *tx_req;
 	unsigned long flags;
 
-	ipoib_dbg_data(priv, "send completion: id %d, op %d, status: %d\n",
-		       wr_id, wc->opcode, wc->status);
+	ipoib_dbg_data(priv, "send completion: id %d, status: %d\n",
+		       wr_id, wc->status);
 
 	if (unlikely(wr_id >= ipoib_sendq_size)) {
 		ipoib_warn(priv, "send completion event with wrid %d (> %d)\n",
@@ -280,28 +280,63 @@ static void ipoib_ib_handle_tx_wc(struct
 			   wc->status, wr_id, wc->vendor_err);
 }
 
-static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
+int ipoib_poll(struct net_device *dev, int *budget)
 {
-	if (wc->wr_id & IPOIB_CM_OP_SRQ)
-		ipoib_cm_handle_rx_wc(dev, wc);
-	else if (wc->wr_id & IPOIB_OP_RECV)
-		ipoib_ib_handle_rx_wc(dev, wc);
-	else
-		ipoib_ib_handle_tx_wc(dev, wc);
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int max = min(*budget, dev->quota);
+	int done;
+	int t;
+	int empty;
+	int n, i;
+
+	done  = 0;
+	empty = 0;
+
+	while (max) {
+		t = min(IPOIB_NUM_WC, max);
+		n = ib_poll_cq(priv->cq, t, priv->ibwc);
+
+		for (i = 0; i < n; ++i) {
+			struct ib_wc *wc = priv->ibwc + i;
+
+			if (wc->wr_id & IPOIB_CM_OP_SRQ) {
+				++done;
+				--max;
+				ipoib_cm_handle_rx_wc(dev, wc);
+			} else if (wc->wr_id & IPOIB_OP_RECV) {
+				++done;
+				--max;
+				ipoib_ib_handle_rx_wc(dev, wc);
+			} else
+				ipoib_ib_handle_tx_wc(dev, wc);
+		}
+
+		if (n != t) {
+			empty = 1;
+			break;
+		}
+	}
+
+	dev->quota -= done;
+	*budget    -= done;
+
+	if (empty) {
+		netif_rx_complete(dev);
+		if (unlikely(ib_req_notify_cq(priv->cq,
+					      IB_CQ_NEXT_COMP |
+					      IB_CQ_REPORT_MISSED_EVENTS)) &&
+		    netif_rx_reschedule(dev, 0))
+			return 1;
+
+		return 0;
+	}
+
+	return 1;
 }
 
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
 {
-	struct net_device *dev = (struct net_device *) dev_ptr;
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	int n, i;
-
-	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
-	do {
-		n = ib_poll_cq(cq, IPOIB_NUM_WC, priv->ibwc);
-		for (i = 0; i < n; ++i)
-			ipoib_ib_handle_wc(dev, priv->ibwc + i);
-	} while (n == IPOIB_NUM_WC);
+	netif_rx_schedule(dev_ptr);
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -514,9 +549,10 @@ int ipoib_ib_dev_stop(struct net_device 
 	struct ib_qp_attr qp_attr;
 	unsigned long begin;
 	struct ipoib_tx_buf *tx_req;
-	int i;
+	int i, n;
 
 	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+	netif_poll_disable(dev);
 
 	ipoib_cm_dev_stop(dev);
 
@@ -568,6 +604,18 @@ int ipoib_ib_dev_stop(struct net_device 
 			goto timeout;
 		}
 
+		do {
+			n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
+			for (i = 0; i < n; ++i) {
+				if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
+					ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
+				else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
+					ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
+				else
+					ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+			}
+		} while (n == IPOIB_NUM_WC);
+
 		msleep(1);
 	}
 
@@ -596,6 +644,9 @@ timeout:
 		msleep(1);
 	}
 
+	netif_poll_enable(dev);
+	ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
+
 	return 0;
 }
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index f2a40ae..0a428f2 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -395,14 +395,10 @@ static void path_rec_completion(int stat
 	skb_queue_head_init(&skqueue);
 
 	if (!status) {
-		struct ib_ah_attr av = {
-			.dlid 	       = be16_to_cpu(pathrec->dlid),
-			.sl 	       = pathrec->sl,
-			.port_num      = priv->port,
-			.static_rate   = pathrec->rate
-		};
-
-		ah = ipoib_create_ah(dev, priv->pd, &av);
+		struct ib_ah_attr av;
+
+		if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av))
+			ah = ipoib_create_ah(dev, priv->pd, &av);
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -952,6 +948,8 @@ static void ipoib_setup(struct net_devic
 	dev->hard_header 	 = ipoib_hard_header;
 	dev->set_multicast_list  = ipoib_set_mcast_list;
 	dev->neigh_setup         = ipoib_neigh_setup_dev;
+	dev->poll                = ipoib_poll;
+	dev->weight              = 100;
 
 	dev->watchdog_timeo 	 = HZ;
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 7f3ec20..5c3c6a4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -187,7 +187,7 @@ int ipoib_transport_dev_init(struct net_
 	if (!ret)
 		size += ipoib_recvq_size;
 
-	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size);
+	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
 	if (IS_ERR(priv->cq)) {
 		printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
 		goto out_free_mr;
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 278fcbc..3651072 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -201,7 +201,7 @@ static int iser_post_receive_control(str
 	 * what's common for both schemes is that the connection is not started
 	 */
 	if (conn->c_stage != ISCSI_CONN_STARTED)
-		rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+		rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
 	else /* FIXME till user space sets conn->max_recv_dlength correctly */
 		rx_data_size = 128;
 
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 1fc9674..3702e23 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -35,7 +35,6 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/version.h>
 
@@ -76,7 +75,7 @@ static int iser_create_device_ib_res(str
 				  iser_cq_callback,
 				  iser_cq_event_callback,
 				  (void *)device,
-				  ISER_MAX_CQ_LEN);
+				  ISER_MAX_CQ_LEN, 0);
 	if (IS_ERR(device->cq))
 		goto cq_err;
 
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5e8ac57..39bf057 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -197,7 +197,7 @@ static int srp_create_target_ib(struct s
 		return -ENOMEM;
 
 	target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
-				  NULL, target, SRP_CQ_SIZE);
+				  NULL, target, SRP_CQ_SIZE, 0);
 	if (IS_ERR(target->cq)) {
 		ret = PTR_ERR(target->cq);
 		goto out;
@@ -1468,6 +1468,25 @@ static ssize_t show_dgid(struct class_de
 		       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
 }
 
+static ssize_t show_orig_dgid(struct class_device *cdev, char *buf)
+{
+	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+	if (target->state == SRP_TARGET_DEAD ||
+	    target->state == SRP_TARGET_REMOVED)
+		return -ENODEV;
+
+	return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+		       be16_to_cpu(target->orig_dgid[0]),
+		       be16_to_cpu(target->orig_dgid[1]),
+		       be16_to_cpu(target->orig_dgid[2]),
+		       be16_to_cpu(target->orig_dgid[3]),
+		       be16_to_cpu(target->orig_dgid[4]),
+		       be16_to_cpu(target->orig_dgid[5]),
+		       be16_to_cpu(target->orig_dgid[6]),
+		       be16_to_cpu(target->orig_dgid[7]));
+}
+
 static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
 {
 	struct srp_target_port *target = host_to_target(class_to_shost(cdev));
@@ -1498,6 +1517,7 @@ static CLASS_DEVICE_ATTR(ioc_guid,	  S_I
 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(orig_dgid,	  S_IRUGO, show_orig_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);
@@ -1508,6 +1528,7 @@ static struct class_device_attribute *sr
 	&class_device_attr_service_id,
 	&class_device_attr_pkey,
 	&class_device_attr_dgid,
+	&class_device_attr_orig_dgid,
 	&class_device_attr_zero_req_lim,
 	&class_device_attr_local_ib_port,
 	&class_device_attr_local_ib_device,
@@ -1516,7 +1537,8 @@ static struct class_device_attribute *sr
 
 static struct scsi_host_template srp_template = {
 	.module				= THIS_MODULE,
-	.name				= DRV_NAME,
+	.name				= "InfiniBand SRP initiator",
+	.proc_name			= DRV_NAME,
 	.info				= srp_target_info,
 	.queuecommand			= srp_queuecommand,
 	.eh_abort_handler		= srp_abort,
@@ -1662,6 +1684,7 @@ static int srp_parse_options(const char 
 				target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
 			}
 			kfree(p);
+			memcpy(target->orig_dgid, target->path.dgid.raw, 16);
 			break;
 
 		case SRP_OPT_PKEY:
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 2f3319c..1d53c7b 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -129,6 +129,7 @@ struct srp_target_port {
 	unsigned int		scsi_id;
 
 	struct ib_sa_path_rec	path;
+	__be16			orig_dgid[8];
 	struct ib_sa_query     *path_query;
 	int			path_query_id;
 
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 9623231..0e9b695 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -153,6 +153,8 @@ source "drivers/input/mouse/Kconfig"
 
 source "drivers/input/joystick/Kconfig"
 
+source "drivers/input/tablet/Kconfig"
+
 source "drivers/input/touchscreen/Kconfig"
 
 source "drivers/input/misc/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index da575de..8a2dd98 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,12 +13,12 @@ obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev
 obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
 obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
 obj-$(CONFIG_INPUT_TSDEV)	+= tsdev.o
-obj-$(CONFIG_INPUT_POWER)	+= power.o
 obj-$(CONFIG_INPUT_EVBUG)	+= evbug.o
 
 obj-$(CONFIG_INPUT_KEYBOARD)	+= keyboard/
 obj-$(CONFIG_INPUT_MOUSE)	+= mouse/
 obj-$(CONFIG_INPUT_JOYSTICK)	+= joystick/
+obj-$(CONFIG_INPUT_TABLET)	+= tablet/
 obj-$(CONFIG_INPUT_TOUCHSCREEN)	+= touchscreen/
 obj-$(CONFIG_INPUT_MISC)	+= misc/
 
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index 5a9653c..c21f2f1 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@u
 MODULE_DESCRIPTION("Input driver event debug module");
 MODULE_LICENSE("GPL");
 
-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);
 }
 
-static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
-					  const struct input_device_id *id)
+static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
+			 const struct input_device_id *id)
 {
 	struct input_handle *handle;
+	int error;
 
-	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
-		return NULL;
+	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
 
 	handle->dev = dev;
 	handle->handler = handler;
-	handle->name = evbug_name;
+	handle->name = "evbug";
+
+	error = input_register_handle(handle);
+	if (error)
+		goto err_free_handle;
 
-	input_open_device(handle);
+	error = input_open_device(handle);
+	if (error)
+		goto err_unregister_handle;
 
 	printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
 
-	return handle;
+	return 0;
+
+ err_unregister_handle:
+	input_unregister_handle(handle);
+ err_free_handle:
+	kfree(handle);
+	return error;
 }
 
 static void evbug_disconnect(struct input_handle *handle)
@@ -70,7 +82,7 @@ static void evbug_disconnect(struct inpu
 	printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
 
 	input_close_device(handle);
-
+	input_unregister_handle(handle);
 	kfree(handle);
 }
 
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 6439f37..55a7259 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -18,7 +18,6 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/compat.h>
 
@@ -29,11 +28,11 @@ struct evdev {
 	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
-	struct evdev_list *grab;
-	struct list_head list;
+	struct evdev_client *grab;
+	struct list_head client_list;
 };
 
-struct evdev_list {
+struct evdev_client {
 	struct input_event buffer[EVDEV_BUFFER_SIZE];
 	int head;
 	int tail;
@@ -47,28 +46,28 @@ static struct evdev *evdev_table[EVDEV_M
 static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct evdev *evdev = handle->private;
-	struct evdev_list *list;
+	struct evdev_client *client;
 
 	if (evdev->grab) {
-		list = evdev->grab;
+		client = evdev->grab;
 
-		do_gettimeofday(&list->buffer[list->head].time);
-		list->buffer[list->head].type = type;
-		list->buffer[list->head].code = code;
-		list->buffer[list->head].value = value;
-		list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+		do_gettimeofday(&client->buffer[client->head].time);
+		client->buffer[client->head].type = type;
+		client->buffer[client->head].code = code;
+		client->buffer[client->head].value = value;
+		client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
 
-		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		kill_fasync(&client->fasync, SIGIO, POLL_IN);
 	} else
-		list_for_each_entry(list, &evdev->list, node) {
+		list_for_each_entry(client, &evdev->client_list, node) {
 
-			do_gettimeofday(&list->buffer[list->head].time);
-			list->buffer[list->head].type = type;
-			list->buffer[list->head].code = code;
-			list->buffer[list->head].value = value;
-			list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+			do_gettimeofday(&client->buffer[client->head].time);
+			client->buffer[client->head].type = type;
+			client->buffer[client->head].code = code;
+			client->buffer[client->head].value = value;
+			client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
 
-			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+			kill_fasync(&client->fasync, SIGIO, POLL_IN);
 		}
 
 	wake_up_interruptible(&evdev->wait);
@@ -76,22 +75,23 @@ static void evdev_event(struct input_han
 
 static int evdev_fasync(int fd, struct file *file, int on)
 {
+	struct evdev_client *client = file->private_data;
 	int retval;
-	struct evdev_list *list = file->private_data;
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
+	retval = fasync_helper(fd, file, on, &client->fasync);
 
 	return retval < 0 ? retval : 0;
 }
 
 static int evdev_flush(struct file *file, fl_owner_t id)
 {
-	struct evdev_list *list = file->private_data;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 
-	if (!list->evdev->exist)
+	if (!evdev->exist)
 		return -ENODEV;
 
-	return input_flush_device(&list->evdev->handle, file);
+	return input_flush_device(&evdev->handle, file);
 }
 
 static void evdev_free(struct evdev *evdev)
@@ -100,48 +100,62 @@ static void evdev_free(struct evdev *evd
 	kfree(evdev);
 }
 
-static int evdev_release(struct inode * inode, struct file * file)
+static int evdev_release(struct inode *inode, struct file *file)
 {
-	struct evdev_list *list = file->private_data;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 
-	if (list->evdev->grab == list) {
-		input_release_device(&list->evdev->handle);
-		list->evdev->grab = NULL;
+	if (evdev->grab == client) {
+		input_release_device(&evdev->handle);
+		evdev->grab = NULL;
 	}
 
 	evdev_fasync(-1, file, 0);
-	list_del(&list->node);
+	list_del(&client->node);
+	kfree(client);
 
-	if (!--list->evdev->open) {
-		if (list->evdev->exist)
-			input_close_device(&list->evdev->handle);
+	if (!--evdev->open) {
+		if (evdev->exist)
+			input_close_device(&evdev->handle);
 		else
-			evdev_free(list->evdev);
+			evdev_free(evdev);
 	}
 
-	kfree(list);
 	return 0;
 }
 
-static int evdev_open(struct inode * inode, struct file * file)
+static int evdev_open(struct inode *inode, struct file *file)
 {
-	struct evdev_list *list;
+	struct evdev_client *client;
+	struct evdev *evdev;
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
+	int error;
 
-	if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
+	if (i >= EVDEV_MINORS)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
+	evdev = evdev_table[i];
+
+	if (!evdev || !evdev->exist)
+		return -ENODEV;
+
+	client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+	if (!client)
 		return -ENOMEM;
 
-	list->evdev = evdev_table[i];
-	list_add_tail(&list->node, &evdev_table[i]->list);
-	file->private_data = list;
+	client->evdev = evdev;
+	list_add_tail(&client->node, &evdev->client_list);
 
-	if (!list->evdev->open++)
-		if (list->evdev->exist)
-			input_open_device(&list->evdev->handle);
+	if (!evdev->open++ && evdev->exist) {
+		error = input_open_device(&evdev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
+	file->private_data = client;
 	return 0;
 }
 
@@ -243,54 +257,55 @@ static int evdev_event_to_user(char __us
 
 #endif /* CONFIG_COMPAT */
 
-static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct evdev_list *list = file->private_data;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 	struct input_event event;
 	int retval = 0;
 
-	if (!list->evdev->exist)
+	if (!evdev->exist)
 		return -ENODEV;
 
 	while (retval < count) {
 
 		if (evdev_event_from_user(buffer + retval, &event))
 			return -EFAULT;
-		input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
+		input_inject_event(&evdev->handle, event.type, event.code, event.value);
 		retval += evdev_event_size();
 	}
 
 	return retval;
 }
 
-static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct evdev_list *list = file->private_data;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 	int retval;
 
 	if (count < evdev_event_size())
 		return -EINVAL;
 
-	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+	if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(list->evdev->wait,
-		list->head != list->tail || (!list->evdev->exist));
-
+	retval = wait_event_interruptible(evdev->wait,
+		client->head != client->tail || !evdev->exist);
 	if (retval)
 		return retval;
 
-	if (!list->evdev->exist)
+	if (!evdev->exist)
 		return -ENODEV;
 
-	while (list->head != list->tail && retval + evdev_event_size() <= count) {
+	while (client->head != client->tail && retval + evdev_event_size() <= count) {
 
-		struct input_event *event = (struct input_event *) list->buffer + list->tail;
+		struct input_event *event = (struct input_event *) client->buffer + client->tail;
 
 		if (evdev_event_to_user(buffer + retval, event))
 			return -EFAULT;
 
-		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+		client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 		retval += evdev_event_size();
 	}
 
@@ -300,11 +315,12 @@ static ssize_t evdev_read(struct file * 
 /* No kernel lock - fine */
 static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
-	struct evdev_list *list = file->private_data;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 
-	poll_wait(file, &list->evdev->wait, wait);
-	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
+	poll_wait(file, &evdev->wait, wait);
+	return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(evdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 #ifdef CONFIG_COMPAT
@@ -387,8 +403,8 @@ static int str_to_user(const char *str, 
 static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
 				void __user *p, int compat_mode)
 {
-	struct evdev_list *list = file->private_data;
-	struct evdev *evdev = list->evdev;
+	struct evdev_client *client = file->private_data;
+	struct evdev *evdev = client->evdev;
 	struct input_dev *dev = evdev->handle.dev;
 	struct input_absinfo abs;
 	struct ff_effect effect;
@@ -434,32 +450,21 @@ static long evdev_ioctl_handler(struct f
 		case EVIOCGKEYCODE:
 			if (get_user(t, ip))
 				return -EFAULT;
-			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
-				return -EINVAL;
-			if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
+
+			error = dev->getkeycode(dev, t, &v);
+			if (error)
+				return error;
+
+			if (put_user(v, ip + 1))
 				return -EFAULT;
+
 			return 0;
 
 		case EVIOCSKEYCODE:
-			if (get_user(t, ip))
+			if (get_user(t, ip) || get_user(v, ip + 1))
 				return -EFAULT;
-			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
-				return -EINVAL;
-			if (get_user(v, ip + 1))
-				return -EFAULT;
-			if (v < 0 || v > KEY_MAX)
-				return -EINVAL;
-			if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
-				return -EINVAL;
-
-			u = SET_INPUT_KEYCODE(dev, t, v);
-			clear_bit(u, dev->keybit);
-			set_bit(v, dev->keybit);
-			for (i = 0; i < dev->keycodemax; i++)
-				if (INPUT_KEYCODE(dev, i) == u)
-					set_bit(u, dev->keybit);
 
-			return 0;
+			return dev->setkeycode(dev, t, v);
 
 		case EVIOCSFF:
 			if (copy_from_user(&effect, p, sizeof(effect)))
@@ -487,10 +492,10 @@ static long evdev_ioctl_handler(struct f
 					return -EBUSY;
 				if (input_grab_device(&evdev->handle))
 					return -EBUSY;
-				evdev->grab = list;
+				evdev->grab = client;
 				return 0;
 			} else {
-				if (evdev->grab != list)
+				if (evdev->grab != client)
 					return -EINVAL;
 				input_release_device(&evdev->handle);
 				evdev->grab = NULL;
@@ -506,7 +511,7 @@ static long evdev_ioctl_handler(struct f
 
 				if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 
-					long *bits;
+					unsigned long *bits;
 					int len;
 
 					switch (_IOC_NR(cmd) & EV_MAX) {
@@ -551,7 +556,7 @@ static long evdev_ioctl_handler(struct f
 
 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 
-					int t = _IOC_NR(cmd) & ABS_MAX;
+					t = _IOC_NR(cmd) & ABS_MAX;
 
 					abs.value = dev->abs[t];
 					abs.minimum = dev->absmin[t];
@@ -571,7 +576,7 @@ static long evdev_ioctl_handler(struct f
 
 				if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 
-					int t = _IOC_NR(cmd) & ABS_MAX;
+					t = _IOC_NR(cmd) & ABS_MAX;
 
 					if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 						return -EFAULT;
@@ -616,23 +621,26 @@ #endif
 	.flush =	evdev_flush
 };
 
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
-					  const struct input_device_id *id)
+static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
+			 const struct input_device_id *id)
 {
 	struct evdev *evdev;
 	struct class_device *cdev;
+	dev_t devt;
 	int minor;
+	int error;
 
 	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
 	if (minor == EVDEV_MINORS) {
 		printk(KERN_ERR "evdev: no more free evdev devices\n");
-		return NULL;
+		return -ENFILE;
 	}
 
-	if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
-		return NULL;
+	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
+	if (!evdev)
+		return -ENOMEM;
 
-	INIT_LIST_HEAD(&evdev->list);
+	INIT_LIST_HEAD(&evdev->client_list);
 	init_waitqueue_head(&evdev->wait);
 
 	evdev->exist = 1;
@@ -645,23 +653,45 @@ static struct input_handle *evdev_connec
 
 	evdev_table[minor] = evdev;
 
-	cdev = class_device_create(&input_class, &dev->cdev,
-			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
-			dev->cdev.dev, evdev->name);
+	devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+
+	cdev = class_device_create(&input_class, &dev->cdev, devt,
+				   dev->cdev.dev, evdev->name);
+	if (IS_ERR(cdev)) {
+		error = PTR_ERR(cdev);
+		goto err_free_evdev;
+	}
 
 	/* temporary symlink to keep userspace happy */
-	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-			  evdev->name);
+	error = sysfs_create_link(&input_class.subsys.kobj,
+				  &cdev->kobj, evdev->name);
+	if (error)
+		goto err_cdev_destroy;
+
+	error = input_register_handle(&evdev->handle);
+	if (error)
+		goto err_remove_link;
 
-	return &evdev->handle;
+	return 0;
+
+ err_remove_link:
+	sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
+ err_cdev_destroy:
+	class_device_destroy(&input_class, devt);
+ err_free_evdev:
+	kfree(evdev);
+	evdev_table[minor] = NULL;
+	return error;
 }
 
 static void evdev_disconnect(struct input_handle *handle)
 {
 	struct evdev *evdev = handle->private;
-	struct evdev_list *list;
+	struct evdev_client *client;
+
+	input_unregister_handle(handle);
 
-	sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
+	sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
 	class_device_destroy(&input_class,
 			MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
 	evdev->exist = 0;
@@ -670,8 +700,8 @@ static void evdev_disconnect(struct inpu
 		input_flush_device(handle, NULL);
 		input_close_device(handle);
 		wake_up_interruptible(&evdev->wait);
-		list_for_each_entry(list, &evdev->list, node)
-			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+		list_for_each_entry(client, &evdev->client_list, node)
+			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
 	} else
 		evdev_free(evdev);
 }
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 783b341..eebc724 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -281,7 +281,8 @@ int input_ff_event(struct input_dev *dev
 		break;
 
 	default:
-		ff->playback(dev, code, value);
+		if (check_effect_access(ff, code, NULL) == 0)
+			ff->playback(dev, code, value);
 		break;
 	}
 
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index a00fe47..bd686a2 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -190,16 +190,14 @@ static void gameport_run_poll_handler(un
  * Basic gameport -> driver core mappings
  */
 
-static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
+static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
 {
 	int error;
 
-	down_write(&gameport_bus.subsys.rwsem);
-
 	gameport->dev.driver = &drv->driver;
 	if (drv->connect(gameport, drv)) {
 		gameport->dev.driver = NULL;
-		goto out;
+		return -ENODEV;
 	}
 
 	error = device_bind_driver(&gameport->dev);
@@ -211,31 +209,21 @@ static void gameport_bind_driver(struct 
 			drv->description, error);
 		drv->disconnect(gameport);
 		gameport->dev.driver = NULL;
-		goto out;
+		return error;
 	}
 
- out:
-	up_write(&gameport_bus.subsys.rwsem);
-}
-
-static void gameport_release_driver(struct gameport *gameport)
-{
-	down_write(&gameport_bus.subsys.rwsem);
-	device_release_driver(&gameport->dev);
-	up_write(&gameport_bus.subsys.rwsem);
+	return 0;
 }
 
 static void gameport_find_driver(struct gameport *gameport)
 {
 	int error;
 
-	down_write(&gameport_bus.subsys.rwsem);
 	error = device_attach(&gameport->dev);
 	if (error < 0)
 		printk(KERN_WARNING
 			"gameport: device_attach() failed for %s (%s), error: %d\n",
 			gameport->phys, gameport->name, error);
-	up_write(&gameport_bus.subsys.rwsem);
 }
 
 
@@ -483,13 +471,12 @@ static ssize_t gameport_rebind_driver(st
 {
 	struct gameport *gameport = to_gameport_port(dev);
 	struct device_driver *drv;
-	int retval;
+	int error;
 
-	retval = mutex_lock_interruptible(&gameport_mutex);
-	if (retval)
-		return retval;
+	error = mutex_lock_interruptible(&gameport_mutex);
+	if (error)
+		return error;
 
-	retval = count;
 	if (!strncmp(buf, "none", count)) {
 		gameport_disconnect_port(gameport);
 	} else if (!strncmp(buf, "reconnect", count)) {
@@ -499,15 +486,15 @@ static ssize_t gameport_rebind_driver(st
 		gameport_find_driver(gameport);
 	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
 		gameport_disconnect_port(gameport);
-		gameport_bind_driver(gameport, to_gameport_driver(drv));
+		error = gameport_bind_driver(gameport, to_gameport_driver(drv));
 		put_driver(drv);
 	} else {
-		retval = -EINVAL;
+		error = -EINVAL;
 	}
 
 	mutex_unlock(&gameport_mutex);
 
-	return retval;
+	return error ? error : count;
 }
 
 static struct device_attribute gameport_device_attrs[] = {
@@ -655,7 +642,7 @@ static void gameport_disconnect_port(str
 		do {
 			parent = s->parent;
 
-			gameport_release_driver(s);
+			device_release_driver(&s->dev);
 			gameport_destroy_port(s);
 		} while ((s = parent) != gameport);
 	}
@@ -663,7 +650,7 @@ static void gameport_disconnect_port(str
 	/*
 	 * Ok, no children left, now disconnect this port
 	 */
-	gameport_release_driver(gameport);
+	device_release_driver(&gameport->dev);
 }
 
 void gameport_rescan(struct gameport *gameport)
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a9a706f..ccd8aba 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -11,7 +11,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/random.h>
@@ -299,12 +298,87 @@ void input_close_device(struct input_han
 }
 EXPORT_SYMBOL(input_close_device);
 
-static void input_link_handle(struct input_handle *handle)
+static int input_fetch_keycode(struct input_dev *dev, int scancode)
 {
-	list_add_tail(&handle->d_node, &handle->dev->h_list);
-	list_add_tail(&handle->h_node, &handle->handler->h_list);
+	switch (dev->keycodesize) {
+		case 1:
+			return ((u8 *)dev->keycode)[scancode];
+
+		case 2:
+			return ((u16 *)dev->keycode)[scancode];
+
+		default:
+			return ((u32 *)dev->keycode)[scancode];
+	}
+}
+
+static int input_default_getkeycode(struct input_dev *dev,
+				    int scancode, int *keycode)
+{
+	if (!dev->keycodesize)
+		return -EINVAL;
+
+	if (scancode < 0 || scancode >= dev->keycodemax)
+		return -EINVAL;
+
+	*keycode = input_fetch_keycode(dev, scancode);
+
+	return 0;
+}
+
+static int input_default_setkeycode(struct input_dev *dev,
+				    int scancode, int keycode)
+{
+	int old_keycode;
+	int i;
+
+	if (scancode < 0 || scancode >= dev->keycodemax)
+		return -EINVAL;
+
+	if (keycode < 0 || keycode > KEY_MAX)
+		return -EINVAL;
+
+	if (!dev->keycodesize)
+		return -EINVAL;
+
+	if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+		return -EINVAL;
+
+	switch (dev->keycodesize) {
+		case 1: {
+			u8 *k = (u8 *)dev->keycode;
+			old_keycode = k[scancode];
+			k[scancode] = keycode;
+			break;
+		}
+		case 2: {
+			u16 *k = (u16 *)dev->keycode;
+			old_keycode = k[scancode];
+			k[scancode] = keycode;
+			break;
+		}
+		default: {
+			u32 *k = (u32 *)dev->keycode;
+			old_keycode = k[scancode];
+			k[scancode] = keycode;
+			break;
+		}
+	}
+
+	clear_bit(old_keycode, dev->keybit);
+	set_bit(keycode, dev->keybit);
+
+	for (i = 0; i < dev->keycodemax; i++) {
+		if (input_fetch_keycode(dev, i) == old_keycode) {
+			set_bit(old_keycode, dev->keybit);
+			break; /* Setting the bit twice is useless, so break */
+		}
+	}
+
+	return 0;
 }
 
+
 #define MATCH_BIT(bit, max) \
 		for (i = 0; i < NBITS(max); i++) \
 			if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
@@ -351,6 +425,29 @@ static const struct input_device_id *inp
 	return NULL;
 }
 
+static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
+{
+	const struct input_device_id *id;
+	int error;
+
+	if (handler->blacklist && input_match_device(handler->blacklist, dev))
+		return -ENODEV;
+
+	id = input_match_device(handler->id_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	error = handler->connect(handler, dev, id);
+	if (error && error != -ENODEV)
+		printk(KERN_ERR
+			"input: failed to attach handler %s to device %s, "
+			"error: %d\n",
+			handler->name, kobject_name(&dev->cdev.kobj), error);
+
+	return error;
+}
+
+
 #ifdef CONFIG_PROC_FS
 
 static struct proc_dir_entry *proc_bus_input_dir;
@@ -439,6 +536,7 @@ static int input_devices_seq_show(struct
 	seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
 	seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
 	seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
+	seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");
 	seq_printf(seq, "H: Handlers=");
 
 	list_for_each_entry(handle, &dev->h_list, d_node)
@@ -753,6 +851,13 @@ static struct attribute_group input_dev_
 	.attrs	= input_dev_caps_attrs,
 };
 
+static struct attribute_group *input_dev_attr_groups[] = {
+	&input_dev_attr_group,
+	&input_dev_id_attr_group,
+	&input_dev_caps_attr_group,
+	NULL
+};
+
 static void input_dev_release(struct class_device *class_dev)
 {
 	struct input_dev *dev = to_input_dev(class_dev);
@@ -906,6 +1011,7 @@ struct input_dev *input_allocate_device(
 	dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
 	if (dev) {
 		dev->cdev.class = &input_class;
+		dev->cdev.groups = input_dev_attr_groups;
 		class_device_initialize(&dev->cdev);
 		mutex_init(&dev->mutex);
 		INIT_LIST_HEAD(&dev->h_list);
@@ -934,23 +1040,71 @@ EXPORT_SYMBOL(input_allocate_device);
  */
 void input_free_device(struct input_dev *dev)
 {
-	if (dev) {
-
-		mutex_lock(&dev->mutex);
-		dev->name = dev->phys = dev->uniq = NULL;
-		mutex_unlock(&dev->mutex);
-
+	if (dev)
 		input_put_device(dev);
-	}
 }
 EXPORT_SYMBOL(input_free_device);
 
+/**
+ * input_set_capability - mark device as capable of a certain event
+ * @dev: device that is capable of emitting or accepting event
+ * @type: type of the event (EV_KEY, EV_REL, etc...)
+ * @code: event code
+ *
+ * In addition to setting up corresponding bit in appropriate capability
+ * bitmap the function also adjusts dev->evbit.
+ */
+void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
+{
+	switch (type) {
+	case EV_KEY:
+		__set_bit(code, dev->keybit);
+		break;
+
+	case EV_REL:
+		__set_bit(code, dev->relbit);
+		break;
+
+	case EV_ABS:
+		__set_bit(code, dev->absbit);
+		break;
+
+	case EV_MSC:
+		__set_bit(code, dev->mscbit);
+		break;
+
+	case EV_SW:
+		__set_bit(code, dev->swbit);
+		break;
+
+	case EV_LED:
+		__set_bit(code, dev->ledbit);
+		break;
+
+	case EV_SND:
+		__set_bit(code, dev->sndbit);
+		break;
+
+	case EV_FF:
+		__set_bit(code, dev->ffbit);
+		break;
+
+	default:
+		printk(KERN_ERR
+			"input_set_capability: unknown type %u (code %u)\n",
+			type, code);
+		dump_stack();
+		return;
+	}
+
+	__set_bit(type, dev->evbit);
+}
+EXPORT_SYMBOL(input_set_capability);
+
 int input_register_device(struct input_dev *dev)
 {
 	static atomic_t input_no = ATOMIC_INIT(0);
-	struct input_handle *handle;
 	struct input_handler *handler;
-	const struct input_device_id *id;
 	const char *path;
 	int error;
 
@@ -969,55 +1123,41 @@ int input_register_device(struct input_d
 		dev->rep[REP_PERIOD] = 33;
 	}
 
+	if (!dev->getkeycode)
+		dev->getkeycode = input_default_getkeycode;
+
+	if (!dev->setkeycode)
+		dev->setkeycode = input_default_setkeycode;
+
 	list_add_tail(&dev->node, &input_dev_list);
 
 	snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
 		 "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
 
+	if (!dev->cdev.dev)
+		dev->cdev.dev = dev->dev.parent;
+
 	error = class_device_add(&dev->cdev);
 	if (error)
 		return error;
 
-	error = sysfs_create_group(&dev->cdev.kobj, &input_dev_attr_group);
-	if (error)
-		goto fail1;
-
-	error = sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group);
-	if (error)
-		goto fail2;
-
-	error = sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
-	if (error)
-		goto fail3;
-
 	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");
 	kfree(path);
 
 	list_for_each_entry(handler, &input_handler_list, node)
-		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-			if ((id = input_match_device(handler->id_table, dev)))
-				if ((handle = handler->connect(handler, dev, id))) {
-					input_link_handle(handle);
-					if (handler->start)
-						handler->start(handle);
-				}
+		input_attach_handler(dev, handler);
 
 	input_wakeup_procfs_readers();
 
 	return 0;
-
- fail3:	sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
- fail2:	sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
- fail1:	class_device_del(&dev->cdev);
-	return error;
 }
 EXPORT_SYMBOL(input_register_device);
 
 void input_unregister_device(struct input_dev *dev)
 {
-	struct list_head *node, *next;
+	struct input_handle *handle, *next;
 	int code;
 
 	for (code = 0; code <= KEY_MAX; code++)
@@ -1027,19 +1167,12 @@ void input_unregister_device(struct inpu
 
 	del_timer_sync(&dev->timer);
 
-	list_for_each_safe(node, next, &dev->h_list) {
-		struct input_handle * handle = to_handle(node);
-		list_del_init(&handle->d_node);
-		list_del_init(&handle->h_node);
+	list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
 		handle->handler->disconnect(handle);
-	}
+	WARN_ON(!list_empty(&dev->h_list));
 
 	list_del_init(&dev->node);
 
-	sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
-	sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
-	sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
-
 	class_device_unregister(&dev->cdev);
 
 	input_wakeup_procfs_readers();
@@ -1049,8 +1182,6 @@ EXPORT_SYMBOL(input_unregister_device);
 int input_register_handler(struct input_handler *handler)
 {
 	struct input_dev *dev;
-	struct input_handle *handle;
-	const struct input_device_id *id;
 
 	INIT_LIST_HEAD(&handler->h_list);
 
@@ -1064,13 +1195,7 @@ int input_register_handler(struct input_
 	list_add_tail(&handler->node, &input_handler_list);
 
 	list_for_each_entry(dev, &input_dev_list, node)
-		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-			if ((id = input_match_device(handler->id_table, dev)))
-				if ((handle = handler->connect(handler, dev, id))) {
-					input_link_handle(handle);
-					if (handler->start)
-						handler->start(handle);
-				}
+		input_attach_handler(dev, handler);
 
 	input_wakeup_procfs_readers();
 	return 0;
@@ -1079,14 +1204,11 @@ EXPORT_SYMBOL(input_register_handler);
 
 void input_unregister_handler(struct input_handler *handler)
 {
-	struct list_head *node, *next;
+	struct input_handle *handle, *next;
 
-	list_for_each_safe(node, next, &handler->h_list) {
-		struct input_handle * handle = to_handle_h(node);
-		list_del_init(&handle->h_node);
-		list_del_init(&handle->d_node);
+	list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
 		handler->disconnect(handle);
-	}
+	WARN_ON(!list_empty(&handler->h_list));
 
 	list_del_init(&handler->node);
 
@@ -1097,6 +1219,27 @@ void input_unregister_handler(struct inp
 }
 EXPORT_SYMBOL(input_unregister_handler);
 
+int input_register_handle(struct input_handle *handle)
+{
+	struct input_handler *handler = handle->handler;
+
+	list_add_tail(&handle->d_node, &handle->dev->h_list);
+	list_add_tail(&handle->h_node, &handler->h_list);
+
+	if (handler->start)
+		handler->start(handle);
+
+	return 0;
+}
+EXPORT_SYMBOL(input_register_handle);
+
+void input_unregister_handle(struct input_handle *handle)
+{
+	list_del_init(&handle->h_node);
+	list_del_init(&handle->d_node);
+}
+EXPORT_SYMBOL(input_unregister_handle);
+
 static int input_open_file(struct inode *inode, struct file *file)
 {
 	struct input_handler *handler = input_table[iminor(inode) >> 5];
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 9f3529a..06f0541 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -24,7 +24,6 @@ #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -43,7 +42,7 @@ struct joydev {
 	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
-	struct list_head list;
+	struct list_head client_list;
 	struct js_corr corr[ABS_MAX + 1];
 	struct JS_DATA_SAVE_TYPE glue;
 	int nabs;
@@ -55,7 +54,7 @@ struct joydev {
 	__s16 abs[ABS_MAX + 1];
 };
 
-struct joydev_list {
+struct joydev_client {
 	struct js_event buffer[JOYDEV_BUFFER_SIZE];
 	int head;
 	int tail;
@@ -87,7 +86,7 @@ static int joydev_correct(int value, str
 static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct joydev *joydev = handle->private;
-	struct joydev_list *list;
+	struct joydev_client *client;
 	struct js_event event;
 
 	switch (type) {
@@ -115,15 +114,15 @@ static void joydev_event(struct input_ha
 
 	event.time = jiffies_to_msecs(jiffies);
 
-	list_for_each_entry(list, &joydev->list, node) {
+	list_for_each_entry(client, &joydev->client_list, node) {
 
-		memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
+		memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
 
-		if (list->startup == joydev->nabs + joydev->nkey)
-			if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
-				list->startup = 0;
+		if (client->startup == joydev->nabs + joydev->nkey)
+			if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
+				client->startup = 0;
 
-		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		kill_fasync(&client->fasync, SIGIO, POLL_IN);
 	}
 
 	wake_up_interruptible(&joydev->wait);
@@ -132,9 +131,9 @@ static void joydev_event(struct input_ha
 static int joydev_fasync(int fd, struct file *file, int on)
 {
 	int retval;
-	struct joydev_list *list = file->private_data;
+	struct joydev_client *client = file->private_data;
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
+	retval = fasync_helper(fd, file, on, &client->fasync);
 
 	return retval < 0 ? retval : 0;
 }
@@ -145,60 +144,73 @@ static void joydev_free(struct joydev *j
 	kfree(joydev);
 }
 
-static int joydev_release(struct inode * inode, struct file * file)
+static int joydev_release(struct inode *inode, struct file *file)
 {
-	struct joydev_list *list = file->private_data;
+	struct joydev_client *client = file->private_data;
+	struct joydev *joydev = client->joydev;
 
 	joydev_fasync(-1, file, 0);
 
-	list_del(&list->node);
+	list_del(&client->node);
+	kfree(client);
 
-	if (!--list->joydev->open) {
-		if (list->joydev->exist)
-			input_close_device(&list->joydev->handle);
+	if (!--joydev->open) {
+		if (joydev->exist)
+			input_close_device(&joydev->handle);
 		else
-			joydev_free(list->joydev);
+			joydev_free(joydev);
 	}
 
-	kfree(list);
 	return 0;
 }
 
 static int joydev_open(struct inode *inode, struct file *file)
 {
-	struct joydev_list *list;
+	struct joydev_client *client;
+	struct joydev *joydev;
 	int i = iminor(inode) - JOYDEV_MINOR_BASE;
+	int error;
+
+	if (i >= JOYDEV_MINORS)
+		return -ENODEV;
 
-	if (i >= JOYDEV_MINORS || !joydev_table[i])
+	joydev = joydev_table[i];
+	if (!joydev || !joydev->exist)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL)))
+	client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
+	if (!client)
 		return -ENOMEM;
 
-	list->joydev = joydev_table[i];
-	list_add_tail(&list->node, &joydev_table[i]->list);
-	file->private_data = list;
+	client->joydev = joydev;
+	list_add_tail(&client->node, &joydev->client_list);
 
-	if (!list->joydev->open++)
-		if (list->joydev->exist)
-			input_open_device(&list->joydev->handle);
+	if (!joydev->open++ && joydev->exist) {
+		error = input_open_device(&joydev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
+	file->private_data = client;
 	return 0;
 }
 
-static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 	return -EINVAL;
 }
 
 static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-	struct joydev_list *list = file->private_data;
-	struct joydev *joydev = list->joydev;
+	struct joydev_client *client = file->private_data;
+	struct joydev *joydev = client->joydev;
 	struct input_dev *input = joydev->handle.dev;
 	int retval = 0;
 
-	if (!list->joydev->exist)
+	if (!joydev->exist)
 		return -ENODEV;
 
 	if (count < sizeof(struct js_event))
@@ -217,56 +229,55 @@ static ssize_t joydev_read(struct file *
 		if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
 			return -EFAULT;
 
-		list->startup = 0;
-		list->tail = list->head;
+		client->startup = 0;
+		client->tail = client->head;
 
 		return sizeof(struct JS_DATA_TYPE);
 	}
 
-	if (list->startup == joydev->nabs + joydev->nkey &&
-	    list->head == list->tail && (file->f_flags & O_NONBLOCK))
+	if (client->startup == joydev->nabs + joydev->nkey &&
+	    client->head == client->tail && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(list->joydev->wait,
-					  !list->joydev->exist ||
-					  list->startup < joydev->nabs + joydev->nkey ||
-					  list->head != list->tail);
-
+	retval = wait_event_interruptible(joydev->wait,
+					  !joydev->exist ||
+					  client->startup < joydev->nabs + joydev->nkey ||
+					  client->head != client->tail);
 	if (retval)
 		return retval;
 
-	if (!list->joydev->exist)
+	if (!joydev->exist)
 		return -ENODEV;
 
-	while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
+	while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
 
 		struct js_event event;
 
 		event.time = jiffies_to_msecs(jiffies);
 
-		if (list->startup < joydev->nkey) {
+		if (client->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
-			event.number = list->startup;
+			event.number = client->startup;
 			event.value = !!test_bit(joydev->keypam[event.number], input->key);
 		} else {
 			event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
-			event.number = list->startup - joydev->nkey;
+			event.number = client->startup - joydev->nkey;
 			event.value = joydev->abs[event.number];
 		}
 
 		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
 			return -EFAULT;
 
-		list->startup++;
+		client->startup++;
 		retval += sizeof(struct js_event);
 	}
 
-	while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
+	while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
 
-		if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
+		if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
 			return -EFAULT;
 
-		list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
+		client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
 		retval += sizeof(struct js_event);
 	}
 
@@ -276,11 +287,12 @@ static ssize_t joydev_read(struct file *
 /* No kernel lock - fine */
 static unsigned int joydev_poll(struct file *file, poll_table *wait)
 {
-	struct joydev_list *list = file->private_data;
+	struct joydev_client *client = file->private_data;
+	struct joydev *joydev = client->joydev;
 
-	poll_wait(file, &list->joydev->wait, wait);
-	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
-		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
+	poll_wait(file, &joydev->wait, wait);
+	return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
+		(POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
@@ -374,8 +386,8 @@ static int joydev_ioctl_common(struct jo
 #ifdef CONFIG_COMPAT
 static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct joydev_list *list = file->private_data;
-	struct joydev *joydev = list->joydev;
+	struct joydev_client *client = file->private_data;
+	struct joydev *joydev = client->joydev;
 	void __user *argp = (void __user *)arg;
 	s32 tmp32;
 	struct JS_DATA_SAVE_TYPE_32 ds32;
@@ -428,8 +440,8 @@ #endif /* CONFIG_COMPAT */
 
 static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct joydev_list *list = file->private_data;
-	struct joydev *joydev = list->joydev;
+	struct joydev_client *client = file->private_data;
+	struct joydev *joydev = client->joydev;
 	void __user *argp = (void __user *)arg;
 
 	if (!joydev->exist)
@@ -465,23 +477,26 @@ #endif
 	.fasync =	joydev_fasync,
 };
 
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
-					   const struct input_device_id *id)
+static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
+			  const struct input_device_id *id)
 {
 	struct joydev *joydev;
 	struct class_device *cdev;
+	dev_t devt;
 	int i, j, t, minor;
+	int error;
 
 	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
 	if (minor == JOYDEV_MINORS) {
 		printk(KERN_ERR "joydev: no more free joydev devices\n");
-		return NULL;
+		return -ENFILE;
 	}
 
-	if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
-		return NULL;
+	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
+	if (!joydev)
+		return -ENOMEM;
 
-	INIT_LIST_HEAD(&joydev->list);
+	INIT_LIST_HEAD(&joydev->client_list);
 	init_waitqueue_head(&joydev->wait);
 
 	joydev->minor = minor;
@@ -534,31 +549,54 @@ static struct input_handle *joydev_conne
 
 	joydev_table[minor] = joydev;
 
-	cdev = class_device_create(&input_class, &dev->cdev,
-			MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
-			dev->cdev.dev, joydev->name);
+	devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+
+	cdev = class_device_create(&input_class, &dev->cdev, devt,
+				   dev->cdev.dev, joydev->name);
+	if (IS_ERR(cdev)) {
+		error = PTR_ERR(cdev);
+		goto err_free_joydev;
+	}
 
 	/* temporary symlink to keep userspace happy */
-	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-			  joydev->name);
+	error = sysfs_create_link(&input_class.subsys.kobj,
+				  &cdev->kobj, joydev->name);
+	if (error)
+		goto err_cdev_destroy;
+
+	error = input_register_handle(&joydev->handle);
+	if (error)
+		goto err_remove_link;
+
+	return 0;
 
-	return &joydev->handle;
+ err_remove_link:
+	sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
+ err_cdev_destroy:
+	class_device_destroy(&input_class, devt);
+ err_free_joydev:
+	joydev_table[minor] = NULL;
+	kfree(joydev);
+	return error;
 }
 
+
 static void joydev_disconnect(struct input_handle *handle)
 {
 	struct joydev *joydev = handle->private;
-	struct joydev_list *list;
+	struct joydev_client *client;
+
+	input_unregister_handle(handle);
 
-	sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
+	sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
 	class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
 	joydev->exist = 0;
 
 	if (joydev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&joydev->wait);
-		list_for_each_entry(list, &joydev->list, node)
-			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+		list_for_each_entry(client, &joydev->client_list, node)
+			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
 	} else
 		joydev_free(joydev);
 }
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 2712634..82f563e 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -2,7 +2,7 @@ #
 # Joystick driver configuration
 #
 menuconfig INPUT_JOYSTICK
-	bool "Joysticks"
+	bool "Joysticks/Gamepads"
 	help
 	  If you have a joystick, 6dof controller, gamepad, steering wheel,
 	  weapon control system or something like that you can say Y here
@@ -196,7 +196,7 @@ config JOYSTICK_TWIDJOY
 config JOYSTICK_DB9
 	tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
 	depends on PARPORT
-	---help---
+	help
 	  Say Y here if you have a Sega Master System gamepad, Sega Genesis
 	  gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
 	  Commodore, Amstrad CPC joystick connected to your parallel port.
@@ -253,4 +253,18 @@ config JOYSTICK_JOYDUMP
 	  To compile this driver as a module, choose M here: the
 	  module will be called joydump.
 
+config JOYSTICK_XPAD
+	tristate "X-Box gamepad support"
+	select USB
+	help
+	  Say Y here if you want to use the X-Box pad with your computer.
+	  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
+	  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
+
+	  For information about how to connect the X-Box pad to USB, see
+	  <file:Documentation/input/xpad.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called xpad.
+
 endif
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index 5231f6f..e855abb 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_JOYSTICK_TMDC)		+= tmdc.o
 obj-$(CONFIG_JOYSTICK_TURBOGRAFX)	+= turbografx.o
 obj-$(CONFIG_JOYSTICK_TWIDJOY)		+= twidjoy.o
 obj-$(CONFIG_JOYSTICK_WARRIOR)		+= warrior.o
+obj-$(CONFIG_JOYSTICK_XPAD)		+= xpad.o
 
 obj-$(CONFIG_JOYSTICK_IFORCE)		+= iforce/
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index b11a4bb..ff701ab 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -241,7 +241,7 @@ static void a3d_adc_close(struct gamepor
 
 static int a3d_open(struct input_dev *dev)
 {
-	struct a3d *a3d = dev->private;
+	struct a3d *a3d = input_get_drvdata(dev);
 
 	gameport_start_polling(a3d->gameport);
 	return 0;
@@ -253,7 +253,7 @@ static int a3d_open(struct input_dev *de
 
 static void a3d_close(struct input_dev *dev)
 {
-	struct a3d *a3d = dev->private;
+	struct a3d *a3d = input_get_drvdata(dev);
 
 	gameport_stop_polling(a3d->gameport);
 }
@@ -314,11 +314,12 @@ static int a3d_connect(struct gameport *
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
 	input_dev->id.product = a3d->mode;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &gameport->dev;
-	input_dev->private = a3d;
+	input_dev->dev.parent = &gameport->dev;
 	input_dev->open = a3d_open;
 	input_dev->close = a3d_close;
 
+	input_set_drvdata(input_dev, a3d);
+
 	if (a3d->mode == A3D_MODE_PXL) {
 
 		int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 6279ced..28140c4 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -290,7 +290,7 @@ static void adi_poll(struct gameport *ga
 
 static int adi_open(struct input_dev *dev)
 {
-	struct adi_port *port = dev->private;
+	struct adi_port *port = input_get_drvdata(dev);
 
 	gameport_start_polling(port->gameport);
 	return 0;
@@ -302,7 +302,7 @@ static int adi_open(struct input_dev *de
 
 static void adi_close(struct input_dev *dev)
 {
-	struct adi_port *port = dev->private;
+	struct adi_port *port = input_get_drvdata(dev);
 
 	gameport_stop_polling(port->gameport);
 }
@@ -424,8 +424,9 @@ static int adi_init_input(struct adi *ad
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
 	input_dev->id.product = adi->id;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &port->gameport->dev;
-	input_dev->private = port;
+	input_dev->dev.parent = &port->gameport->dev;
+
+	input_set_drvdata(input_dev, port);
 
 	input_dev->open = adi_open;
 	input_dev->close = adi_close;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 51f1e4b..bdd157c 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -53,7 +53,7 @@ MODULE_LICENSE("GPL");
 #define ANALOG_PORTS		16
 
 static char *js[ANALOG_PORTS];
-static int js_nargs;
+static unsigned int js_nargs;
 static int analog_options[ANALOG_PORTS];
 module_param_array_named(map, js, charp, &js_nargs, 0);
 MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
@@ -343,7 +343,7 @@ static void analog_poll(struct gameport 
 
 static int analog_open(struct input_dev *dev)
 {
-	struct analog_port *port = dev->private;
+	struct analog_port *port = input_get_drvdata(dev);
 
 	gameport_start_polling(port->gameport);
 	return 0;
@@ -355,7 +355,7 @@ static int analog_open(struct input_dev 
 
 static void analog_close(struct input_dev *dev)
 {
-	struct analog_port *port = dev->private;
+	struct analog_port *port = input_get_drvdata(dev);
 
 	gameport_stop_polling(port->gameport);
 }
@@ -449,10 +449,13 @@ static int analog_init_device(struct ana
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
 	input_dev->id.product = analog->mask >> 4;
 	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &port->gameport->dev;
+
+	input_set_drvdata(input_dev, port);
 
 	input_dev->open = analog_open;
 	input_dev->close = analog_close;
-	input_dev->private = port;
+
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (i = j = 0; i < 4; i++)
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 034ec39..d3352a8 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -142,7 +142,7 @@ static void cobra_poll(struct gameport *
 
 static int cobra_open(struct input_dev *dev)
 {
-	struct cobra *cobra = dev->private;
+	struct cobra *cobra = input_get_drvdata(dev);
 
 	gameport_start_polling(cobra->gameport);
 	return 0;
@@ -150,7 +150,7 @@ static int cobra_open(struct input_dev *
 
 static void cobra_close(struct input_dev *dev)
 {
-	struct cobra *cobra = dev->private;
+	struct cobra *cobra = input_get_drvdata(dev);
 
 	gameport_stop_polling(cobra->gameport);
 }
@@ -211,8 +211,9 @@ static int cobra_connect(struct gameport
 		input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
 		input_dev->id.product = 0x0008;
 		input_dev->id.version = 0x0100;
-		input_dev->cdev.dev = &gameport->dev;
-		input_dev->private = cobra;
+		input_dev->dev.parent = &gameport->dev;
+
+		input_set_drvdata(input_dev, cobra);
 
 		input_dev->open = cobra_open;
 		input_dev->close = cobra_close;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index b41bd2e..86ad102 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -46,17 +46,17 @@ MODULE_LICENSE("GPL");
 
 struct db9_config {
 	int args[2];
-	int nargs;
+	unsigned int nargs;
 };
 
 #define DB9_MAX_PORTS		3
-static struct db9_config db9[DB9_MAX_PORTS] __initdata;
+static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata;
 
-module_param_array_named(dev, db9[0].args, int, &db9[0].nargs, 0);
+module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0);
 MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
-module_param_array_named(dev2, db9[1].args, int, &db9[0].nargs, 0);
+module_param_array_named(dev2, db9_cfg[1].args, int, &db9_cfg[0].nargs, 0);
 MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
-module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0);
+module_param_array_named(dev3, db9_cfg[2].args, int, &db9_cfg[2].nargs, 0);
 MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
 
 #define DB9_ARG_PARPORT		0
@@ -518,7 +518,7 @@ static void db9_timer(unsigned long priv
 
 static int db9_open(struct input_dev *dev)
 {
-	struct db9 *db9 = dev->private;
+	struct db9 *db9 = input_get_drvdata(dev);
 	struct parport *port = db9->pd->port;
 	int err;
 
@@ -542,7 +542,7 @@ static int db9_open(struct input_dev *de
 
 static void db9_close(struct input_dev *dev)
 {
-	struct db9 *db9 = dev->private;
+	struct db9 *db9 = input_get_drvdata(dev);
 	struct parport *port = db9->pd->port;
 
 	mutex_lock(&db9->mutex);
@@ -625,7 +625,8 @@ static struct db9 __init *db9_probe(int 
 		input_dev->id.vendor = 0x0002;
 		input_dev->id.product = mode;
 		input_dev->id.version = 0x0100;
-		input_dev->private = db9;
+
+		input_set_drvdata(input_dev, db9);
 
 		input_dev->open = db9_open;
 		input_dev->close = db9_close;
@@ -679,17 +680,17 @@ static int __init db9_init(void)
 	int err = 0;
 
 	for (i = 0; i < DB9_MAX_PORTS; i++) {
-		if (db9[i].nargs == 0 || db9[i].args[DB9_ARG_PARPORT] < 0)
+		if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0)
 			continue;
 
-		if (db9[i].nargs < 2) {
+		if (db9_cfg[i].nargs < 2) {
 			printk(KERN_ERR "db9.c: Device type must be specified.\n");
 			err = -EINVAL;
 			break;
 		}
 
-		db9_base[i] = db9_probe(db9[i].args[DB9_ARG_PARPORT],
-					db9[i].args[DB9_ARG_MODE]);
+		db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT],
+					db9_cfg[i].args[DB9_ARG_MODE]);
 		if (IS_ERR(db9_base[i])) {
 			err = PTR_ERR(db9_base[i]);
 			break;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 711e4b3..1a452e0 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -48,16 +48,16 @@ #define GC_MAX_DEVICES		5
 
 struct gc_config {
 	int args[GC_MAX_DEVICES + 1];
-	int nargs;
+	unsigned int nargs;
 };
 
-static struct gc_config gc[GC_MAX_PORTS] __initdata;
+static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata;
 
-module_param_array_named(map, gc[0].args, int, &gc[0].nargs, 0);
+module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0);
 MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
-module_param_array_named(map2, gc[1].args, int, &gc[1].nargs, 0);
+module_param_array_named(map2, gc_cfg[1].args, int, &gc_cfg[1].nargs, 0);
 MODULE_PARM_DESC(map2, "Describes second set of devices");
-module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0);
+module_param_array_named(map3, gc_cfg[2].args, int, &gc_cfg[2].nargs, 0);
 MODULE_PARM_DESC(map3, "Describes third set of devices");
 
 /* see also gs_psx_delay parameter in PSX support section */
@@ -591,7 +591,7 @@ static void gc_timer(unsigned long priva
 
 static int gc_open(struct input_dev *dev)
 {
-	struct gc *gc = dev->private;
+	struct gc *gc = input_get_drvdata(dev);
 	int err;
 
 	err = mutex_lock_interruptible(&gc->mutex);
@@ -610,7 +610,7 @@ static int gc_open(struct input_dev *dev
 
 static void gc_close(struct input_dev *dev)
 {
-	struct gc *gc = dev->private;
+	struct gc *gc = input_get_drvdata(dev);
 
 	mutex_lock(&gc->mutex);
 	if (!--gc->used) {
@@ -646,7 +646,8 @@ static int __init gc_setup_pad(struct gc
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = pad_type;
 	input_dev->id.version = 0x0100;
-	input_dev->private = gc;
+
+	input_set_drvdata(input_dev, gc);
 
 	input_dev->open = gc_open;
 	input_dev->close = gc_close;
@@ -809,16 +810,17 @@ static int __init gc_init(void)
 	int err = 0;
 
 	for (i = 0; i < GC_MAX_PORTS; i++) {
-		if (gc[i].nargs == 0 || gc[i].args[0] < 0)
+		if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0)
 			continue;
 
-		if (gc[i].nargs < 2) {
+		if (gc_cfg[i].nargs < 2) {
 			printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
 			err = -EINVAL;
 			break;
 		}
 
-		gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1);
+		gc_base[i] = gc_probe(gc_cfg[i].args[0],
+				      gc_cfg[i].args + 1, gc_cfg[i].nargs - 1);
 		if (IS_ERR(gc_base[i])) {
 			err = PTR_ERR(gc_base[i]);
 			break;
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index bacbab5..d514aeb 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -220,7 +220,7 @@ static void gf2k_poll(struct gameport *g
 
 static int gf2k_open(struct input_dev *dev)
 {
-	struct gf2k *gf2k = dev->private;
+	struct gf2k *gf2k = input_get_drvdata(dev);
 
 	gameport_start_polling(gf2k->gameport);
 	return 0;
@@ -228,7 +228,7 @@ static int gf2k_open(struct input_dev *d
 
 static void gf2k_close(struct input_dev *dev)
 {
-	struct gf2k *gf2k = dev->private;
+	struct gf2k *gf2k = input_get_drvdata(dev);
 
 	gameport_stop_polling(gf2k->gameport);
 }
@@ -308,11 +308,13 @@ #endif
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS;
 	input_dev->id.product = gf2k->id;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &gameport->dev;
-	input_dev->private = gf2k;
+	input_dev->dev.parent = &gameport->dev;
+
+	input_set_drvdata(input_dev, gf2k);
 
 	input_dev->open = gf2k_open;
 	input_dev->close = gf2k_close;
+
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	for (i = 0; i < gf2k_axes[gf2k->id]; i++)
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 17a90c4..73eb5ab 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -285,7 +285,7 @@ static void grip_poll(struct gameport *g
 
 static int grip_open(struct input_dev *dev)
 {
-	struct grip *grip = dev->private;
+	struct grip *grip = input_get_drvdata(dev);
 
 	gameport_start_polling(grip->gameport);
 	return 0;
@@ -293,7 +293,7 @@ static int grip_open(struct input_dev *d
 
 static void grip_close(struct input_dev *dev)
 {
-	struct grip *grip = dev->private;
+	struct grip *grip = input_get_drvdata(dev);
 
 	gameport_stop_polling(grip->gameport);
 }
@@ -363,8 +363,9 @@ static int grip_connect(struct gameport 
 		input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
 		input_dev->id.product = grip->mode[i];
 		input_dev->id.version = 0x0100;
-		input_dev->cdev.dev = &gameport->dev;
-		input_dev->private = grip;
+		input_dev->dev.parent = &gameport->dev;
+
+		input_set_drvdata(input_dev, grip);
 
 		input_dev->open = grip_open;
 		input_dev->close = grip_close;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 8120a9c..555319e 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -562,7 +562,7 @@ static void grip_poll(struct gameport *g
 
 static int grip_open(struct input_dev *dev)
 {
-	struct grip_mp *grip = dev->private;
+	struct grip_mp *grip = input_get_drvdata(dev);
 
 	gameport_start_polling(grip->gameport);
 	return 0;
@@ -574,9 +574,9 @@ static int grip_open(struct input_dev *d
 
 static void grip_close(struct input_dev *dev)
 {
-	struct grip_mp *grip = dev->private;
+	struct grip_mp *grip = input_get_drvdata(dev);
 
-	gameport_start_polling(grip->gameport);
+	gameport_stop_polling(grip->gameport);
 }
 
 /*
@@ -599,8 +599,9 @@ static int register_slot(int slot, struc
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
 	input_dev->id.product = 0x0100 + port->mode;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &grip->gameport->dev;
-	input_dev->private = grip;
+	input_dev->dev.parent = &grip->gameport->dev;
+
+	input_set_drvdata(input_dev, grip);
 
 	input_dev->open = grip_open;
 	input_dev->close = grip_close;
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index dbc5d92..d4e8073 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -156,7 +156,7 @@ static void guillemot_poll(struct gamepo
 
 static int guillemot_open(struct input_dev *dev)
 {
-	struct guillemot *guillemot = dev->private;
+	struct guillemot *guillemot = input_get_drvdata(dev);
 
 	gameport_start_polling(guillemot->gameport);
 	return 0;
@@ -168,7 +168,7 @@ static int guillemot_open(struct input_d
 
 static void guillemot_close(struct input_dev *dev)
 {
-	struct guillemot *guillemot = dev->private;
+	struct guillemot *guillemot = input_get_drvdata(dev);
 
 	gameport_stop_polling(guillemot->gameport);
 }
@@ -231,8 +231,9 @@ static int guillemot_connect(struct game
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
 	input_dev->id.product = guillemot_type[i].id;
 	input_dev->id.version = (int)data[14] << 8 | data[15];
-	input_dev->cdev.dev = &gameport->dev;
-	input_dev->private = guillemot;
+	input_dev->dev.parent = &gameport->dev;
+
+	input_set_drvdata(input_dev, guillemot);
 
 	input_dev->open = guillemot_open;
 	input_dev->close = guillemot_close;
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 8fb0c19..f2a4381 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -2,7 +2,7 @@
  * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
@@ -205,7 +205,7 @@ static int need_condition_modifier(struc
 	int i;
 
 	if (new->type != FF_SPRING && new->type != FF_FRICTION) {
-		printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
+		warn("bad effect type in need_condition_modifier");
 		return 0;
 	}
 
@@ -227,7 +227,7 @@ static int need_condition_modifier(struc
 static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
 {
 	if (effect->type != FF_CONSTANT) {
-		printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+		warn("bad effect type in need_envelope_modifier");
 		return 0;
 	}
 
@@ -258,7 +258,7 @@ static int need_envelope_modifier(struct
 		break;
 
 	default:
-		printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+		warn("bad effect type in need_envelope_modifier");
 	}
 
 	return 0;
@@ -271,7 +271,7 @@ static int need_envelope_modifier(struct
 static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
 {
 	if (new->type != FF_PERIODIC) {
-		printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n");
+		warn("bad effect type in need_period_modifier");
 		return 0;
 	}
 	return (old->u.periodic.period != new->u.periodic.period
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 3393a37..fb129c4 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -2,7 +2,7 @@
  * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
@@ -29,7 +29,7 @@
 
 #include "iforce.h"
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
 MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
 MODULE_LICENSE("GPL");
 
@@ -220,7 +220,7 @@ static void iforce_release(struct input_
 		/* 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");
+				warn("iforce_release: Device still owns effects");
 				break;
 			}
 		}
@@ -232,7 +232,7 @@ static void iforce_release(struct input_
 	switch (iforce->bus) {
 #ifdef CONFIG_JOYSTICK_IFORCE_USB
 		case IFORCE_USB:
-			usb_unlink_urb(iforce->irq);
+			usb_kill_urb(iforce->irq);
 
 			/* The device was unplugged before the file
 			 * was released */
@@ -287,13 +287,13 @@ int iforce_init_device(struct iforce *if
 #ifdef CONFIG_JOYSTICK_IFORCE_USB
 	case IFORCE_USB:
 		input_dev->id.bustype = BUS_USB;
-		input_dev->cdev.dev = &iforce->usbdev->dev;
+		input_dev->dev.parent = &iforce->usbdev->dev;
 		break;
 #endif
 #ifdef CONFIG_JOYSTICK_IFORCE_232
 	case IFORCE_232:
 		input_dev->id.bustype = BUS_RS232;
-		input_dev->cdev.dev = &iforce->serio->dev;
+		input_dev->dev.parent = &iforce->serio->dev;
 		break;
 #endif
 	}
@@ -324,7 +324,7 @@ #endif
 			break;
 
 	if (i == 20) { /* 5 seconds */
-		printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
+		err("Timeout waiting for response from device.");
 		error = -ENODEV;
 		goto fail;
 	}
@@ -336,26 +336,26 @@ #endif
 	if (!iforce_get_id_packet(iforce, "M"))
 		input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
 	else
-		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n");
+		warn("Device does not respond to id packet M");
 
 	if (!iforce_get_id_packet(iforce, "P"))
 		input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
 	else
-		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n");
+		warn("Device does not respond to id packet P");
 
 	if (!iforce_get_id_packet(iforce, "B"))
 		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
 	else
-		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
+		warn("Device does not respond to id packet B");
 
 	if (!iforce_get_id_packet(iforce, "N"))
 		ff_effects = iforce->edata[1];
 	else
-		printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
+		warn("Device does not respond to id packet N");
 
 	/* Check if the device can store more effects than the driver can really handle */
 	if (ff_effects > IFORCE_EFFECTS_MAX) {
-		printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
+		warn("Limiting number of effects to %d (device reports %d)",
 		       IFORCE_EFFECTS_MAX, ff_effects);
 		ff_effects = IFORCE_EFFECTS_MAX;
 	}
@@ -457,8 +457,6 @@ #endif
 	if (error)
 		goto fail;
 
-	printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open);
-
 	return 0;
 
  fail:	input_free_device(input_dev);
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 808f059..21c4e13 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -2,7 +2,7 @@
  * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
@@ -39,10 +39,10 @@ void iforce_dump_packet(char *msg, u16 c
 {
 	int i;
 
-	printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
+	printk(KERN_DEBUG __FILE__ ": %s cmd = %04x, data = ", msg, cmd);
 	for (i = 0; i < LO(cmd); i++)
 		printk("%02x ", data[i]);
-	printk(")\n");
+	printk("\n");
 }
 
 /*
@@ -65,8 +65,9 @@ int iforce_send_packet(struct iforce *if
 	head = iforce->xmit.head;
 	tail = iforce->xmit.tail;
 
+
 	if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
-		printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
+		warn("not enough space in xmit buffer to send new packet");
 		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
 		return -1;
 	}
@@ -126,8 +127,6 @@ int iforce_control_playback(struct iforc
 {
 	unsigned char data[3];
 
-printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
-
 	data[0] = LO(id);
 	data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
 	data[2] = LO(value);
@@ -151,7 +150,7 @@ static int mark_core_as_ready(struct ifo
 			return 0;
 		}
 	}
-	printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
+	warn("unused effect %04x updated !!!", addr);
 	return -1;
 }
 
@@ -162,7 +161,7 @@ void iforce_process_packet(struct iforce
 	static int being_used = 0;
 
 	if (being_used)
-		printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
+		warn("re-entrant call to iforce_process %d", being_used);
 	being_used++;
 
 #ifdef CONFIG_JOYSTICK_IFORCE_232
@@ -266,7 +265,7 @@ #ifdef CONFIG_JOYSTICK_IFORCE_USB
 			return -1;
 		}
 #else
-		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
+		err("iforce_get_id_packet: iforce->bus = USB!");
 #endif
 		break;
 
@@ -284,13 +283,12 @@ #ifdef CONFIG_JOYSTICK_IFORCE_232
 			return -1;
 		}
 #else
-		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
+		err("iforce_get_id_packet: iforce->bus = SERIO!");
 #endif
 		break;
 
 	default:
-		printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
-		       iforce->bus);
+		err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
 		break;
 	}
 
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index ec4be53..7b4bc19 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -2,7 +2,7 @@
  * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 80cdebc..750099d 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -2,7 +2,7 @@
  * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
@@ -65,7 +65,7 @@ void iforce_usb_xmit(struct iforce *ifor
 	XMIT_INC(iforce->xmit.tail, n);
 
 	if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
-		printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
+		warn("usb_submit_urb failed %d\n", n);
 	}
 
 	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -110,7 +110,7 @@ static void iforce_usb_out(struct urb *u
 	struct iforce *iforce = urb->context;
 
 	if (urb->status) {
-		printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
+		dbg("urb->status %d, exiting", urb->status);
 		return;
 	}
 
@@ -190,10 +190,9 @@ fail:
 /* Called by iforce_delete() */
 void iforce_usb_delete(struct iforce* iforce)
 {
-	usb_unlink_urb(iforce->irq);
-/* Is it ok to unlink those ? */
-	usb_unlink_urb(iforce->out);
-	usb_unlink_urb(iforce->ctrl);
+	usb_kill_urb(iforce->irq);
+	usb_kill_urb(iforce->out);
+	usb_kill_urb(iforce->ctrl);
 
 	usb_free_urb(iforce->irq);
 	usb_free_urb(iforce->out);
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index ffaeaef..40a853a 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -2,7 +2,7 @@
  * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- *  Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ *  Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  */
@@ -124,7 +124,7 @@ #endif
 	/* Buffer used for asynchronous sending of bytes to the device */
 	struct circ_buf xmit;
 	unsigned char xmit_data[XMIT_SIZE];
-	long xmit_flags[1];
+	unsigned long xmit_flags[1];
 
 					/* Force Feedback */
 	wait_queue_head_t wait;
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index fec8b3d..1aec1e9 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -185,7 +185,7 @@ static void interact_poll(struct gamepor
 
 static int interact_open(struct input_dev *dev)
 {
-	struct interact *interact = dev->private;
+	struct interact *interact = input_get_drvdata(dev);
 
 	gameport_start_polling(interact->gameport);
 	return 0;
@@ -197,7 +197,7 @@ static int interact_open(struct input_de
 
 static void interact_close(struct input_dev *dev)
 {
-	struct interact *interact = dev->private;
+	struct interact *interact = input_get_drvdata(dev);
 
 	gameport_stop_polling(interact->gameport);
 }
@@ -262,7 +262,9 @@ static int interact_connect(struct gamep
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
 	input_dev->id.product = interact_type[i].id;
 	input_dev->id.version = 0x0100;
-	input_dev->private = interact;
+	input_dev->dev.parent = &gameport->dev;
+
+	input_set_drvdata(input_dev, interact);
 
 	input_dev->open = interact_open;
 	input_dev->close = interact_close;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 4112789..b35604e 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -168,8 +168,7 @@ static int magellan_connect(struct serio
 	input_dev->id.vendor = SERIO_MAGELLAN;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = magellan;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index e58b22c..2adf73f 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -509,7 +509,7 @@ static void sw_poll(struct gameport *gam
 
 static int sw_open(struct input_dev *dev)
 {
-	struct sw *sw = dev->private;
+	struct sw *sw = input_get_drvdata(dev);
 
 	gameport_start_polling(sw->gameport);
 	return 0;
@@ -517,7 +517,7 @@ static int sw_open(struct input_dev *dev
 
 static void sw_close(struct input_dev *dev)
 {
-	struct sw *sw = dev->private;
+	struct sw *sw = input_get_drvdata(dev);
 
 	gameport_stop_polling(sw->gameport);
 }
@@ -751,8 +751,9 @@ #endif
 		input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
 		input_dev->id.product = sw->type;
 		input_dev->id.version = 0x0100;
-		input_dev->cdev.dev = &gameport->dev;
-		input_dev->private = sw;
+		input_dev->dev.parent = &gameport->dev;
+
+		input_set_drvdata(input_dev, sw);
 
 		input_dev->open = sw_open;
 		input_dev->close = sw_close;
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 08bf113..abb7c4c 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -226,8 +226,7 @@ static int spaceball_connect(struct seri
 	input_dev->id.vendor = SERIO_SPACEBALL;
 	input_dev->id.product = id;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = spaceball;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index c9c7921..c4937f1 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -183,8 +183,7 @@ static int spaceorb_connect(struct serio
 	input_dev->id.vendor = SERIO_SPACEORB;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = spaceorb;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index ecb0916..8581ee9 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -154,8 +154,7 @@ static int stinger_connect(struct serio 
 	input_dev->id.vendor = SERIO_STINGER;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = stinger;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) |
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index bb23ed2..3b36ee0 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -265,7 +265,7 @@ static void tmdc_poll(struct gameport *g
 
 static int tmdc_open(struct input_dev *dev)
 {
-	struct tmdc *tmdc = dev->private;
+	struct tmdc *tmdc = input_get_drvdata(dev);
 
 	gameport_start_polling(tmdc->gameport);
 	return 0;
@@ -273,7 +273,7 @@ static int tmdc_open(struct input_dev *d
 
 static void tmdc_close(struct input_dev *dev)
 {
-	struct tmdc *tmdc = dev->private;
+	struct tmdc *tmdc = input_get_drvdata(dev);
 
 	gameport_stop_polling(tmdc->gameport);
 }
@@ -326,8 +326,9 @@ static int tmdc_setup_port(struct tmdc *
 	input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
 	input_dev->id.product = model->id;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &tmdc->gameport->dev;
-	input_dev->private = tmdc;
+	input_dev->dev.parent = &tmdc->gameport->dev;
+
+	input_set_drvdata(input_dev, tmdc);
 
 	input_dev->open = tmdc_open;
 	input_dev->close = tmdc_close;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 037d348..8381c6f 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -48,16 +48,16 @@ #define TGFX_MAX_DEVICES	7
 
 struct tgfx_config {
 	int args[TGFX_MAX_DEVICES + 1];
-	int nargs;
+	unsigned int nargs;
 };
 
-static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata;
+static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata;
 
-module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0);
+module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0);
 MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
-module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0);
+module_param_array_named(map2, tgfx_cfg[1].args, int, &tgfx_cfg[1].nargs, 0);
 MODULE_PARM_DESC(map2, "Describes second set of devices");
-module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0);
+module_param_array_named(map3, tgfx_cfg[2].args, int, &tgfx_cfg[2].nargs, 0);
 MODULE_PARM_DESC(map3, "Describes third set of devices");
 
 #define TGFX_REFRESH_TIME	HZ/100	/* 10 ms */
@@ -122,7 +122,7 @@ static void tgfx_timer(unsigned long pri
 
 static int tgfx_open(struct input_dev *dev)
 {
-	struct tgfx *tgfx = dev->private;
+	struct tgfx *tgfx = input_get_drvdata(dev);
 	int err;
 
 	err = mutex_lock_interruptible(&tgfx->sem);
@@ -141,7 +141,7 @@ static int tgfx_open(struct input_dev *d
 
 static void tgfx_close(struct input_dev *dev)
 {
-	struct tgfx *tgfx = dev->private;
+	struct tgfx *tgfx = input_get_drvdata(dev);
 
 	mutex_lock(&tgfx->sem);
 	if (!--tgfx->used) {
@@ -224,7 +224,8 @@ static struct tgfx __init *tgfx_probe(in
 		input_dev->id.product = n_buttons[i];
 		input_dev->id.version = 0x0100;
 
-		input_dev->private = tgfx;
+		input_set_drvdata(input_dev, tgfx);
+
 		input_dev->open = tgfx_open;
 		input_dev->close = tgfx_close;
 
@@ -282,16 +283,18 @@ static int __init tgfx_init(void)
 	int err = 0;
 
 	for (i = 0; i < TGFX_MAX_PORTS; i++) {
-		if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0)
+		if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0)
 			continue;
 
-		if (tgfx[i].nargs < 2) {
+		if (tgfx_cfg[i].nargs < 2) {
 			printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
 			err = -EINVAL;
 			break;
 		}
 
-		tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1);
+		tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0],
+					  tgfx_cfg[i].args + 1,
+					  tgfx_cfg[i].nargs - 1);
 		if (IS_ERR(tgfx_base[i])) {
 			err = PTR_ERR(tgfx_base[i]);
 			break;
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 9cf17d6..c91504e 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -205,11 +205,9 @@ static int twidjoy_connect(struct serio 
 	input_dev->id.vendor = SERIO_TWIDJOY;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = twidjoy;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 	input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4);
 	input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4);
 
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index 29d339a..4e85f72 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -160,8 +160,7 @@ static int warrior_connect(struct serio 
 	input_dev->id.vendor = SERIO_WARRIOR;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = warrior;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
new file mode 100644
index 0000000..8c8cd95
--- /dev/null
+++ b/drivers/input/joystick/xpad.c
@@ -0,0 +1,433 @@
+/*
+ * X-Box gamepad - v0.0.6
+ *
+ * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
+ *               2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
+ *                    Steven Toth <steve@toth.demon.co.uk>,
+ *                    Franz Lehner <franz@caos.at>,
+ *                    Ivan Hawkes <blackhawk@ivanhawkes.com>
+ *               2005 Dominic Cerquetti <binary1230@yahoo.com>
+ *               2006 Adam Buchbinder <adam.buchbinder@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
+ *
+ *
+ * This driver is based on:
+ *  - information from     http://euc.jp/periphs/xbox-controller.ja.html
+ *  - the iForce driver    drivers/char/joystick/iforce.c
+ *  - the skeleton-driver  drivers/usb/usb-skeleton.c
+ *
+ * Thanks to:
+ *  - 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 (especially trigger axes)
+ *  - fix "analog" buttons (reported as digital now)
+ *  - get rumble working
+ *  - need USB IDs for other dance pads
+ *
+ * History:
+ *
+ * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
+ *
+ * 2002-07-02 - 0.0.2 : basic working version
+ *  - all axes and 9 of the 10 buttons work (german InterAct device)
+ *  - the black button does not work
+ *
+ * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik
+ *  - indentation fixes
+ *  - usb + input init sequence fixes
+ *
+ * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
+ *  - verified the lack of HID and report descriptors
+ *  - verified that ALL buttons WORK
+ *  - 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/usb/input.h>
+
+#define DRIVER_VERSION "v0.0.6"
+#define DRIVER_AUTHOR "Marko Friedemann <mfr@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 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[] = {
+	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,	/* "analog" buttons */
+	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
+	-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 */
+	-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 */
+};
+
+static struct usb_device_id xpad_table [] = {
+	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
+	{ }
+};
+
+MODULE_DEVICE_TABLE (usb, xpad_table);
+
+struct usb_xpad {
+	struct input_dev *dev;		/* input device interface */
+	struct usb_device *udev;	/* usb device */
+
+	struct urb *irq_in;		/* urb for interrupt in report */
+	unsigned char *idata;		/* input data */
+	dma_addr_t idata_dma;
+
+	char phys[65];			/* physical device path */
+
+	int dpad_mapping;		/* map d-pad to buttons or to axes */
+};
+
+/*
+ *	xpad_process_packet
+ *
+ *	Completes a request by converting the data into events for the
+ *	input subsystem.
+ *
+ *	The used report descriptor was taken from ITO Takayukis website:
+ *	 http://euc.jp/periphs/xbox-controller.ja.html
+ */
+
+static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+{
+	struct input_dev *dev = xpad->dev;
+
+	/* left stick */
+	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
+	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+
+	/* right stick */
+	input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
+	input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+
+	/* triggers left/right */
+	input_report_abs(dev, ABS_Z, data[10]);
+	input_report_abs(dev, ABS_RZ, data[11]);
+
+	/* digital pad */
+	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);
+	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]);
+	input_report_key(dev, BTN_B, data[5]);
+	input_report_key(dev, BTN_X, data[6]);
+	input_report_key(dev, BTN_Y, data[7]);
+
+	/* "analog" buttons black, white */
+	input_report_key(dev, BTN_C, data[8]);
+	input_report_key(dev, BTN_Z, data[9]);
+
+	input_sync(dev);
+}
+
+static void xpad_irq_in(struct urb *urb)
+{
+	struct usb_xpad *xpad = urb->context;
+	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;
+	}
+
+	xpad_process_packet(xpad, 0, xpad->idata);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, retval);
+}
+
+static int xpad_open (struct input_dev *dev)
+{
+	struct usb_xpad *xpad = input_get_drvdata(dev);
+
+	xpad->irq_in->dev = xpad->udev;
+	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void xpad_close (struct input_dev *dev)
+{
+	struct usb_xpad *xpad = input_get_drvdata(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);
+	struct usb_xpad *xpad;
+	struct input_dev *input_dev;
+	struct usb_endpoint_descriptor *ep_irq_in;
+	int i;
+	int error = -ENOMEM;
+
+	for (i = 0; xpad_device[i].idVendor; i++) {
+		if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
+		    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
+			break;
+	}
+
+	xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!xpad || !input_dev)
+		goto fail1;
+
+	xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
+				       GFP_ATOMIC, &xpad->idata_dma);
+	if (!xpad->idata)
+		goto fail1;
+
+	xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
+	if (!xpad->irq_in)
+		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));
+
+	input_dev->name = xpad_device[i].name;
+	input_dev->phys = xpad->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, xpad);
+
+	input_dev->open = xpad_open;
+	input_dev->close = xpad_close;
+
+	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);
+
+	/* 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,
+			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
+			 xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
+			 xpad, ep_irq_in->bInterval);
+	xpad->irq_in->transfer_dma = xpad->idata_dma;
+	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(xpad->dev);
+	if (error)
+		goto fail3;
+
+	usb_set_intfdata(intf, xpad);
+	return 0;
+
+ fail3:	usb_free_urb(xpad->irq_in);
+ fail2:	usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+ fail1:	input_free_device(input_dev);
+	kfree(xpad);
+	return error;
+
+}
+
+static void xpad_disconnect(struct usb_interface *intf)
+{
+	struct usb_xpad *xpad = usb_get_intfdata (intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (xpad) {
+		usb_kill_urb(xpad->irq_in);
+		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);
+		kfree(xpad);
+	}
+}
+
+static struct usb_driver xpad_driver = {
+	.name		= "xpad",
+	.probe		= xpad_probe,
+	.disconnect	= xpad_disconnect,
+	.id_table	= xpad_table,
+};
+
+static int __init usb_xpad_init(void)
+{
+	int result = usb_register(&xpad_driver);
+	if (result == 0)
+		info(DRIVER_DESC ":" DRIVER_VERSION);
+	return result;
+}
+
+static void __exit usb_xpad_exit(void)
+{
+	usb_deregister(&xpad_driver);
+}
+
+module_init(usb_xpad_init);
+module_exit(usb_xpad_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f17e9c7..bd707b8 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -164,6 +164,17 @@ config KEYBOARD_AMIGA
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
 
+config KEYBOARD_ATARI
+	tristate "Atari keyboard"
+	depends on ATARI
+	select ATARI_KBD_CORE
+	help
+	  Say Y here if you are running Linux on any Atari and have a keyboard
+	  attached.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atakbd.
+
 config KEYBOARD_HIL_OLD
 	tristate "HP HIL keyboard support (simple driver)"
 	depends on GSC || HP300
@@ -203,9 +214,19 @@ config KEYBOARD_OMAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called omap-keypad.
 
+config KEYBOARD_PXA27x
+	tristate "PXA27x keyboard support"
+	depends on PXA27x
+	help
+	  Enable support for PXA27x matrix keyboard controller
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pxa27x_keyboard.
+
 config KEYBOARD_AAED2000
 	tristate "AAED-2000 keyboard"
 	depends on MACH_AAED2000
+	select INPUT_POLLDEV
 	default y
 	help
 	  Say Y here to enable the keyboard on the Agilent AAED-2000
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 586a0fe..28d211b 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd
 obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
+obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkb
 obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
+obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
index 65fcb6a..63d6ead 100644
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ b/drivers/input/keyboard/aaed2000_kbd.c
@@ -14,12 +14,11 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/init.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 
 #include <asm/arch/hardware.h>
 #include <asm/arch/aaed2000.h>
@@ -46,8 +45,7 @@ static unsigned char aaedkbd_keycode[NR_
 
 struct aaedkbd {
 	unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
-	struct input_dev *input;
-	struct work_struct workq;
+	struct input_polled_dev *poll_dev;
 	int kbdscan_state[KB_COLS];
 	int kbdscan_count[KB_COLS];
 };
@@ -64,14 +62,15 @@ static void aaedkbd_report_col(struct aa
 		scancode = SCANCODE(row, col);
 		pressed = rowd & KB_ROWMASK(row);
 
-		input_report_key(aaedkbd->input, aaedkbd->keycode[scancode], pressed);
+		input_report_key(aaedkbd->poll_dev->input,
+				 aaedkbd->keycode[scancode], pressed);
 	}
 }
 
 /* Scan the hardware keyboard and push any changes up through the input layer */
-static void aaedkbd_work(void *data)
+static void aaedkbd_poll(struct input_polled_dev *dev)
 {
-	struct aaedkbd *aaedkbd = data;
+	struct aaedkbd *aaedkbd = dev->private;
 	unsigned int col, rowd;
 
 	col = 0;
@@ -90,59 +89,41 @@ static void aaedkbd_work(void *data)
 	} while (col < KB_COLS);
 
 	AAEC_GPIO_KSCAN = 0x07;
-	input_sync(aaedkbd->input);
-
-	schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
-}
-
-static int aaedkbd_open(struct input_dev *indev)
-{
-	struct aaedkbd *aaedkbd = indev->private;
-
-	schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
-
-	return 0;
-}
-
-static void aaedkbd_close(struct input_dev *indev)
-{
-	struct aaedkbd *aaedkbd = indev->private;
-
-	cancel_delayed_work(&aaedkbd->workq);
-	flush_scheduled_work();
+	input_sync(dev->input);
 }
 
 static int __devinit aaedkbd_probe(struct platform_device *pdev)
 {
 	struct aaedkbd *aaedkbd;
+	struct input_polled_dev *poll_dev;
 	struct input_dev *input_dev;
 	int i;
 	int error;
 
 	aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!aaedkbd || !input_dev) {
+	poll_dev = input_allocate_polled_device();
+	if (!aaedkbd || !poll_dev) {
 		error = -ENOMEM;
 		goto fail;
 	}
 
 	platform_set_drvdata(pdev, aaedkbd);
 
-	aaedkbd->input = input_dev;
-
-	/* Init keyboard rescan workqueue */
-	INIT_WORK(&aaedkbd->workq, aaedkbd_work, aaedkbd);
-
+	aaedkbd->poll_dev = poll_dev;
 	memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
 
+	poll_dev->private = aaedkbd;
+	poll_dev->poll = aaedkbd_poll;
+	poll_dev->poll_interval = SCAN_INTERVAL;
+
+	input_dev = poll_dev->input;
 	input_dev->name = "AAED-2000 Keyboard";
 	input_dev->phys = "aaedkbd/input0";
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &pdev->dev;
-	input_dev->private = aaedkbd;
+	input_dev->dev.parent = &pdev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	input_dev->keycode = aaedkbd->keycode;
@@ -153,17 +134,14 @@ static int __devinit aaedkbd_probe(struc
 		set_bit(aaedkbd->keycode[i], input_dev->keybit);
 	clear_bit(0, input_dev->keybit);
 
-	input_dev->open = aaedkbd_open;
-	input_dev->close = aaedkbd_close;
-
-	error = input_register_device(aaedkbd->input);
+	error = input_register_polled_device(aaedkbd->poll_dev);
 	if (error)
 		goto fail;
 
 	return 0;
 
  fail:	kfree(aaedkbd);
-	input_free_device(input_dev);
+	input_free_polled_device(poll_dev);
 	return error;
 }
 
@@ -171,7 +149,8 @@ static int __devexit aaedkbd_remove(stru
 {
 	struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
 
-	input_unregister_device(aaedkbd->input);
+	input_unregister_polled_device(aaedkbd->poll_dev);
+	input_free_polled_device(aaedkbd->poll_dev);
 	kfree(aaedkbd);
 
 	return 0;
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
new file mode 100644
index 0000000..ded1d6a
--- /dev/null
+++ b/drivers/input/keyboard/atakbd.c
@@ -0,0 +1,134 @@
+/*
+ *  atakbd.c
+ *
+ *  Copyright (c) 2005 Michael Schmitz
+ *
+ * Based on amikbd.c, which is
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Hamish Macdonald
+ */
+
+/*
+ * Atari keyboard driver for Linux/m68k
+ *
+ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
+ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
+ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
+ * This driver only deals with handing key events off to the input layer.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
+MODULE_DESCRIPTION("Atari keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char atakbd_keycode[0x72];
+
+static struct input_dev *atakbd_dev;
+
+static void atakbd_interrupt(unsigned char scancode, char down)
+{
+
+	if (scancode < 0x72) {		/* scancodes < 0xf2 are keys */
+
+		// report raw events here?
+
+		scancode = atakbd_keycode[scancode];
+
+		if (scancode == KEY_CAPSLOCK) {	/* CapsLock is a toggle switch key on Amiga */
+			input_report_key(atakbd_dev, scancode, 1);
+			input_report_key(atakbd_dev, scancode, 0);
+			input_sync(atakbd_dev);
+		} else {
+			input_report_key(atakbd_dev, scancode, down);
+			input_sync(atakbd_dev);
+		}
+	} else				/* scancodes >= 0xf2 are mouse data, most likely */
+		printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
+
+	return;
+}
+
+static int __init atakbd_init(void)
+{
+	int i;
+
+	if (!ATARIHW_PRESENT(ST_MFP))
+		return -EIO;
+
+	// TODO: request_mem_region if not done in arch code
+
+	if (!(atakbd_dev = input_allocate_device()))
+		return -ENOMEM;
+
+	// need to init core driver if not already done so
+	if (atari_keyb_init())
+		return -ENODEV;
+
+	atakbd_dev->name = "Atari Keyboard";
+	atakbd_dev->phys = "atakbd/input0";
+	atakbd_dev->id.bustype = BUS_ATARI;
+	atakbd_dev->id.vendor = 0x0001;
+	atakbd_dev->id.product = 0x0001;
+	atakbd_dev->id.version = 0x0100;
+
+	atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	atakbd_dev->keycode = atakbd_keycode;
+	atakbd_dev->keycodesize = sizeof(unsigned char);
+	atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
+
+	for (i = 1; i < 0x72; i++) {
+		atakbd_keycode[i] = i;
+		set_bit(atakbd_keycode[i], atakbd_dev->keybit);
+	}
+
+	input_register_device(atakbd_dev);
+
+	atari_input_keyboard_interrupt_hook = atakbd_interrupt;
+
+	printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
+
+	return 0;
+}
+
+static void __exit atakbd_exit(void)
+{
+	atari_input_keyboard_interrupt_hook = NULL;
+	input_unregister_device(atakbd_dev);
+}
+
+module_init(atakbd_init);
+module_exit(atakbd_exit);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 6638770..be1fe46 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -586,7 +586,7 @@ static void atkbd_event_work(struct work
 
 static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct atkbd *atkbd = dev->private;
+	struct atkbd *atkbd = input_get_drvdata(dev);
 
 	if (!atkbd->write)
 		return -1;
@@ -883,8 +883,9 @@ static void atkbd_set_device_attrs(struc
 	input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
 	input_dev->id.version = atkbd->id;
 	input_dev->event = atkbd_event;
-	input_dev->private = atkbd;
-	input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
+	input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
+
+	input_set_drvdata(input_dev, atkbd);
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
 
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 1016c94..6578bff 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -323,8 +323,7 @@ static int __init corgikbd_probe(struct 
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &pdev->dev;
-	input_dev->private = corgikbd;
+	input_dev->dev.parent = &pdev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
 	input_dev->keycode = corgikbd->keycode;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ccf6df3..7392122 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -35,11 +35,14 @@ static irqreturn_t gpio_keys_isr(int irq
 	struct input_dev *input = platform_get_drvdata(pdev);
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		int gpio = pdata->buttons[i].gpio;
+		struct gpio_keys_button *button = &pdata->buttons[i];
+		int gpio = button->gpio;
+
 		if (irq == gpio_to_irq(gpio)) {
-			int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+			unsigned int type = button->type ?: EV_KEY;
+			int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
 
-			input_report_key(input, pdata->buttons[i].keycode, state);
+			input_event(input, type, button->code, !!state);
 			input_sync(input);
 		}
 	}
@@ -63,8 +66,7 @@ static int __devinit gpio_keys_probe(str
 
 	input->name = pdev->name;
 	input->phys = "gpio-keys/input0";
-	input->cdev.dev = &pdev->dev;
-	input->private = pdata;
+	input->dev.parent = &pdev->dev;
 
 	input->id.bustype = BUS_HOST;
 	input->id.vendor = 0x0001;
@@ -72,19 +74,21 @@ static int __devinit gpio_keys_probe(str
 	input->id.version = 0x0100;
 
 	for (i = 0; i < pdata->nbuttons; i++) {
-		int code = pdata->buttons[i].keycode;
-		int irq = gpio_to_irq(pdata->buttons[i].gpio);
+		struct gpio_keys_button *button = &pdata->buttons[i];
+		int irq = gpio_to_irq(button->gpio);
+		unsigned int type = button->type ?: EV_KEY;
 
 		set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
 		error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
-				     pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
+				     button->desc ? button->desc : "gpio_keys",
 				     pdev);
 		if (error) {
 			printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
 				irq, error);
 			goto fail;
 		}
-		set_bit(code, input->keybit);
+
+		input_set_capability(input, type, button->code);
 	}
 
 	error = input_register_device(input);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 7cc9728..cdd254f 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -51,7 +51,7 @@ #define HIL_KBD_MAX_LENGTH 16
 
 #define HIL_KBD_SET1_UPBIT 0x01
 #define HIL_KBD_SET1_SHIFT 1
-static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] = 
+static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
 	{ HIL_KEYCODES_SET1 };
 
 #define HIL_KBD_SET2_UPBIT 0x01
@@ -60,10 +60,10 @@ #define HIL_KBD_SET2_SHIFT 1
 
 #define HIL_KBD_SET3_UPBIT 0x80
 #define HIL_KBD_SET3_SHIFT 0
-static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
+static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
 	{ HIL_KEYCODES_SET3 };
 
-static char hil_language[][16] = { HIL_LOCALE_MAP };
+static const char hil_language[][16] = { HIL_LOCALE_MAP };
 
 struct hil_kbd {
 	struct input_dev *dev;
@@ -94,10 +94,12 @@ static void hil_kbd_process_record(struc
 	idx = kbd->idx4/4;
 	p = data[idx - 1];
 
-	if ((p & ~HIL_CMDCT_POL) == 
-	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
-	if ((p & ~HIL_CMDCT_RPL) == 
-	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+	if ((p & ~HIL_CMDCT_POL) ==
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+		goto report;
+	if ((p & ~HIL_CMDCT_RPL) ==
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+		goto report;
 
 	/* Not a poll response.  See if we are loading config records. */
 	switch (p & HIL_PKT_DATA_MASK) {
@@ -107,27 +109,32 @@ static void hil_kbd_process_record(struc
 		for (; i < HIL_KBD_MAX_LENGTH; i++)
 			kbd->idd[i] = 0;
 		break;
+
 	case HIL_CMD_RSC:
 		for (i = 0; i < idx; i++)
 			kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_KBD_MAX_LENGTH; i++)
 			kbd->rsc[i] = 0;
 		break;
+
 	case HIL_CMD_EXD:
 		for (i = 0; i < idx; i++)
 			kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_KBD_MAX_LENGTH; i++)
 			kbd->exd[i] = 0;
 		break;
+
 	case HIL_CMD_RNM:
 		for (i = 0; i < idx; i++)
 			kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
 			kbd->rnm[i] = '\0';
 		break;
+
 	default:
 		/* These occur when device isn't present */
-		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD))
+			break;
 		/* Anything else we'd like to know about. */
 		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
 		break;
@@ -139,16 +146,19 @@ static void hil_kbd_process_record(struc
 	switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
 	case HIL_POL_CHARTYPE_NONE:
 		break;
+
 	case HIL_POL_CHARTYPE_ASCII:
 		while (cnt < idx - 1)
 			input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
 		break;
+
 	case HIL_POL_CHARTYPE_RSVD1:
 	case HIL_POL_CHARTYPE_RSVD2:
 	case HIL_POL_CHARTYPE_BINARY:
 		while (cnt < idx - 1)
 			input_report_key(dev, kbd->data[cnt++], 1);
 		break;
+
 	case HIL_POL_CHARTYPE_SET1:
 		while (cnt < idx - 1) {
 			unsigned int key;
@@ -161,6 +171,7 @@ static void hil_kbd_process_record(struc
 				input_report_key(dev, key, !up);
 		}
 		break;
+
 	case HIL_POL_CHARTYPE_SET2:
 		while (cnt < idx - 1) {
 			unsigned int key;
@@ -173,6 +184,7 @@ static void hil_kbd_process_record(struc
 				input_report_key(dev, key, !up);
 		}
 		break;
+
 	case HIL_POL_CHARTYPE_SET3:
 		while (cnt < idx - 1) {
 			unsigned int key;
@@ -191,42 +203,43 @@ static void hil_kbd_process_record(struc
 	up(&kbd->sem);
 }
 
-static void hil_kbd_process_err(struct hil_kbd *kbd) {
+static void hil_kbd_process_err(struct hil_kbd *kbd)
+{
 	printk(KERN_WARNING PREFIX "errored HIL packet\n");
 	kbd->idx4 = 0;
 	up(&kbd->sem);
 }
 
-static irqreturn_t hil_kbd_interrupt(struct serio *serio, 
-	      unsigned char data, unsigned int flags)
+static irqreturn_t hil_kbd_interrupt(struct serio *serio,
+				unsigned char data, unsigned int flags)
 {
 	struct hil_kbd *kbd;
 	hil_packet packet;
 	int idx;
 
 	kbd = serio_get_drvdata(serio);
-	if (kbd == NULL) {
-		BUG();
-		return IRQ_HANDLED;
-	}
+	BUG_ON(kbd == NULL);
 
 	if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
 		hil_kbd_process_err(kbd);
 		return IRQ_HANDLED;
 	}
 	idx = kbd->idx4/4;
-	if (!(kbd->idx4 % 4)) kbd->data[idx] = 0;
+	if (!(kbd->idx4 % 4))
+		kbd->data[idx] = 0;
 	packet = kbd->data[idx];
 	packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
 	kbd->data[idx] = packet;
 
 	/* Records of N 4-byte hil_packets must terminate with a command. */
-	if ((++(kbd->idx4)) % 4) return IRQ_HANDLED;
+	if ((++(kbd->idx4)) % 4)
+		return IRQ_HANDLED;
 	if ((packet & 0xffff0000) != HIL_ERR_INT) {
 		hil_kbd_process_err(kbd);
 		return IRQ_HANDLED;
 	}
-	if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
+	if (packet & HIL_PKT_CMD)
+		hil_kbd_process_record(kbd);
 	return IRQ_HANDLED;
 }
 
@@ -235,10 +248,7 @@ static void hil_kbd_disconnect(struct se
 	struct hil_kbd *kbd;
 
 	kbd = serio_get_drvdata(serio);
-	if (kbd == NULL) {
-		BUG();
-		return;
-	}
+	BUG_ON(kbd == NULL);
 
 	serio_close(serio);
 	input_unregister_device(kbd->dev);
@@ -259,42 +269,40 @@ static int hil_kbd_connect(struct serio 
 	if (!kbd->dev)
 		goto bail0;
 
-	kbd->dev->private = kbd;
-
 	if (serio_open(serio, drv))
 		goto bail1;
 
 	serio_set_drvdata(serio, kbd);
 	kbd->serio = serio;
 
-	init_MUTEX_LOCKED(&(kbd->sem));
+	init_MUTEX_LOCKED(&kbd->sem);
 
 	/* Get device info.  MLC driver supplies devid/status/etc. */
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_IDD);
-	down(&(kbd->sem));
+	down(&kbd->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_RSC);
-	down(&(kbd->sem));
+	down(&kbd->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_RNM);
-	down(&(kbd->sem));
+	down(&kbd->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_EXD);
-	down(&(kbd->sem));
+	down(&kbd->sem);
 
-	up(&(kbd->sem));
+	up(&kbd->sem);
 
 	did = kbd->idd[0];
 	idd = kbd->idd + 1;
@@ -310,12 +318,11 @@ static int hil_kbd_connect(struct serio 
 		goto bail2;
 	}
 
-	if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+	if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
 		printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
 		goto bail2;
 	}
 
-
 	kbd->dev->evbit[0]	= BIT(EV_KEY) | BIT(EV_REP);
 	kbd->dev->ledbit[0]	= BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
 	kbd->dev->keycodemax	= HIL_KEYCODES_SET1_TBLSIZE;
@@ -328,7 +335,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->cdev.dev	= &serio->dev;
+	kbd->dev->dev.parent	= &serio->dev;
 
 	for (i = 0; i < 128; i++) {
 		set_bit(hil_kbd_set1[i], kbd->dev->keybit);
@@ -344,8 +351,8 @@ static int hil_kbd_connect(struct serio 
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
-	down(&(kbd->sem));
-	up(&(kbd->sem));
+	down(&kbd->sem);
+	up(&kbd->sem);
 
 	return 0;
  bail2:
@@ -368,26 +375,26 @@ static struct serio_device_id hil_kbd_id
 	{ 0 }
 };
 
-struct serio_driver hil_kbd_serio_drv = {
+static struct serio_driver hil_kbd_serio_drv = {
 	.driver		= {
 		.name	= "hil_kbd",
 	},
 	.description	= "HP HIL keyboard driver",
 	.id_table	= hil_kbd_ids,
-	.connect 	= hil_kbd_connect,
-	.disconnect 	= hil_kbd_disconnect,
-	.interrupt 	= hil_kbd_interrupt
+	.connect	= hil_kbd_connect,
+	.disconnect	= hil_kbd_disconnect,
+	.interrupt	= hil_kbd_interrupt
 };
 
 static int __init hil_kbd_init(void)
 {
 	return serio_register_driver(&hil_kbd_serio_drv);
 }
-                
+
 static void __exit hil_kbd_exit(void)
 {
 	serio_unregister_driver(&hil_kbd_serio_drv);
 }
-                        
+
 module_init(hil_kbd_init);
 module_exit(hil_kbd_exit);
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 4de4dc2..499b697 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
  *  Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
- *  Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
+ *  Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
  *
  *  Very basic HP Human Interface Loop (HIL) driver.
  *  This driver handles the keyboard on HP300 (m68k) and on some
@@ -52,7 +52,7 @@ #if defined(CONFIG_PARISC)
 
 #elif defined(CONFIG_HP300)
 
- #define HILBASE		0xf0428000 /* HP300 (m86k) port address */
+ #define HILBASE		0xf0428000UL /* HP300 (m68k) port address */
  #define HIL_DATA		0x1
  #define HIL_CMD		0x3
  #define HIL_IRQ		2
@@ -89,7 +89,7 @@ #define	HIL_INTOFF		0x5D		/* Turn off in
 #define	HIL_READKBDSADR		0xF9
 #define	HIL_WRITEKBDSADR	0xE9
 
-static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
 	{ HIL_KEYCODES_SET1 };
 
 /* HIL structure */
@@ -211,10 +211,10 @@ hil_keyb_init(void)
 		return -ENODEV; /* already initialized */
 	}
 
+	spin_lock_init(&hil_dev.lock);
 	hil_dev.dev = input_allocate_device();
 	if (!hil_dev.dev)
 		return -ENOMEM;
-	hil_dev.dev->private = &hil_dev;
 
 #if defined(CONFIG_HP300)
 	if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 3d4d0a0..1b08f4e 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -515,7 +515,7 @@ static int
 lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
 		int value)
 {
-	struct lkkbd *lk = dev->private;
+	struct lkkbd *lk = input_get_drvdata (dev);
 	unsigned char leds_on = 0;
 	unsigned char leds_off = 0;
 
@@ -666,9 +666,10 @@ lkkbd_connect (struct serio *serio, stru
 	input_dev->id.vendor = SERIO_LKKBD;
 	input_dev->id.product = 0;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
+	input_dev->dev.parent = &serio->dev;
 	input_dev->event = lkkbd_event;
-	input_dev->private = lk;
+
+	input_set_drvdata (input_dev, lk);
 
 	set_bit (EV_KEY, input_dev->evbit);
 	set_bit (EV_LED, input_dev->evbit);
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 2ade518..7a41b27 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -231,7 +231,7 @@ static int locomokbd_probe(struct locomo
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->private = locomokbd;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	input_dev->keycode = locomokbd->keycode;
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index aa29b50..b97a41e 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -104,8 +104,7 @@ static int nkbd_connect(struct serio *se
 	input_dev->id.vendor = SERIO_NEWTON;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = nkbd;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	input_dev->keycode = nkbd->keycode;
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 5680a6d..3a22863 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -370,8 +370,7 @@ static int __init omap_kp_probe(struct p
 		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->dev.parent = &pdev->dev;
 
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor = 0x0001;
diff --git a/drivers/input/keyboard/pxa27x_keyboard.c b/drivers/input/keyboard/pxa27x_keyboard.c
new file mode 100644
index 0000000..06eaf76
--- /dev/null
+++ b/drivers/input/keyboard/pxa27x_keyboard.c
@@ -0,0 +1,258 @@
+/*
+ * linux/drivers/input/keyboard/pxa27x_keyboard.c
+ *
+ * Driver for the pxa27x matrix keyboard controller.
+ *
+ * Created:	Feb 22, 2007
+ * Author:	Rodolfo Giometti <giometti@linux.it>
+ *
+ * Based on a previous implementations by Kevin O'Connor
+ * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
+ * on some suggestions by Nicolas Pitre <nico@cam.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/pxa27x_keyboard.h>
+
+#define DRIVER_NAME		"pxa27x-keyboard"
+
+#define KPASMKP(col)		(col/2 == 0 ? KPASMKP0 : \
+				 col/2 == 1 ? KPASMKP1 : \
+				 col/2 == 2 ? KPASMKP2 : KPASMKP3)
+#define KPASMKPx_MKC(row, col)	(1 << (row + 16 * (col % 2)))
+
+static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+	unsigned long kpc = KPC;
+	int p, row, col, rel;
+
+	if (kpc & KPC_DI) {
+		unsigned long kpdk = KPDK;
+
+		if (!(kpdk & KPDK_DKP)) {
+			/* better luck next time */
+		} else if (kpc & KPC_REE0) {
+			unsigned long kprec = KPREC;
+			KPREC = 0x7f;
+
+			if (kprec & KPREC_OF0)
+				rel = (kprec & 0xff) + 0x7f;
+			else if (kprec & KPREC_UF0)
+				rel = (kprec & 0xff) - 0x7f - 0xff;
+			else
+				rel = (kprec & 0xff) - 0x7f;
+
+			if (rel) {
+				input_report_rel(input_dev, REL_WHEEL, rel);
+				input_sync(input_dev);
+			}
+		}
+	}
+
+	if (kpc & KPC_MI) {
+		/* report the status of every button */
+		for (row = 0; row < pdata->nr_rows; row++) {
+			for (col = 0; col < pdata->nr_cols; col++) {
+				p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
+					1 : 0;
+				pr_debug("keycode %x - pressed %x\n",
+						pdata->keycodes[row][col], p);
+				input_report_key(input_dev,
+						pdata->keycodes[row][col], p);
+			}
+		}
+		input_sync(input_dev);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int pxakbd_open(struct input_dev *dev)
+{
+	/* Set keypad control register */
+	KPC |= (KPC_ASACT |
+		KPC_MS_ALL |
+		(2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
+		KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
+
+	KPC &= ~KPC_AS;         /* disable automatic scan */
+	KPC &= ~KPC_IMKP;       /* do not ignore multiple keypresses */
+
+	/* Set rotary count to mid-point value */
+	KPREC = 0x7F;
+
+	/* Enable unit clock */
+	pxa_set_cken(CKEN19_KEYPAD, 1);
+
+	return 0;
+}
+
+static void pxakbd_close(struct input_dev *dev)
+{
+	/* Disable clock unit */
+	pxa_set_cken(CKEN19_KEYPAD, 0);
+}
+
+#ifdef CONFIG_PM
+static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+
+	/* Save controller status */
+	pdata->reg_kpc = KPC;
+	pdata->reg_kprec = KPREC;
+
+	return 0;
+}
+
+static int pxakbd_resume(struct platform_device *pdev)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users) {
+		/* Restore controller status */
+		KPC = pdata->reg_kpc;
+		KPREC = pdata->reg_kprec;
+
+		/* Enable unit clock */
+		pxa_set_cken(CKEN19_KEYPAD, 1);
+	}
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+#else
+#define pxakbd_suspend	NULL
+#define pxakbd_resume	NULL
+#endif
+
+static int __devinit pxakbd_probe(struct platform_device *pdev)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+	struct input_dev *input_dev;
+	int i, row, col, error;
+
+	/* Create and register the input driver. */
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		printk(KERN_ERR "Cannot request keypad device\n");
+		return -ENOMEM;
+	}
+
+	input_dev->name = DRIVER_NAME;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->open = pxakbd_open;
+	input_dev->close = pxakbd_close;
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+	input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
+	for (row = 0; row < pdata->nr_rows; row++) {
+		for (col = 0; col < pdata->nr_cols; col++) {
+			int code = pdata->keycodes[row][col];
+			if (code > 0)
+				set_bit(code, input_dev->keybit);
+		}
+	}
+
+	error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
+			    DRIVER_NAME, pdev);
+	if (error) {
+		printk(KERN_ERR "Cannot request keypad IRQ\n");
+		pxa_set_cken(CKEN19_KEYPAD, 0);
+		goto err_free_dev;
+	}
+
+	platform_set_drvdata(pdev, input_dev);
+
+	/* Register the input device */
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	/* Setup GPIOs. */
+	for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
+		pxa_gpio_mode(pdata->gpio_modes[i]);
+
+	/*
+	 * Store rows/cols info into keyboard registers.
+	 */
+
+	KPC |= (pdata->nr_rows - 1) << 26;
+	KPC |= (pdata->nr_cols - 1) << 23;
+
+	for (col = 0; col < pdata->nr_cols; col++)
+		KPC |= KPC_MS0 << col;
+
+	return 0;
+
+ err_free_irq:
+	platform_set_drvdata(pdev, NULL);
+	free_irq(IRQ_KEYPAD, pdev);
+ err_free_dev:
+	input_free_device(input_dev);
+	return error;
+}
+
+static int __devexit pxakbd_remove(struct platform_device *pdev)
+{
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+	input_unregister_device(input_dev);
+	free_irq(IRQ_KEYPAD, pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver pxakbd_driver = {
+	.probe		= pxakbd_probe,
+	.remove		= __devexit_p(pxakbd_remove),
+	.suspend	= pxakbd_suspend,
+	.resume		= pxakbd_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init pxakbd_init(void)
+{
+	return platform_driver_register(&pxakbd_driver);
+}
+
+static void __exit pxakbd_exit(void)
+{
+	platform_driver_unregister(&pxakbd_driver);
+}
+
+module_init(pxakbd_init);
+module_exit(pxakbd_exit);
+
+MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 8a2166c..41b8038 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -372,10 +372,9 @@ static int __init spitzkbd_probe(struct 
 
 	spitzkbd->input = input_dev;
 
-	input_dev->private = spitzkbd;
 	input_dev->name = "Spitz Keyboard";
 	input_dev->phys = spitzkbd->phys;
-	input_dev->cdev.dev = &dev->dev;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor = 0x0001;
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index f7b5c5b..b44b068 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -108,8 +108,7 @@ static int skbd_connect(struct serio *se
 	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->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	input_dev->keycode = skbd->keycode;
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index cc02383..1d4e396 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -146,7 +146,7 @@ out:
 
 static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct sunkbd *sunkbd = dev->private;
+	struct sunkbd *sunkbd = input_get_drvdata(dev);
 
 	switch (type) {
 
@@ -271,8 +271,10 @@ static int sunkbd_connect(struct serio *
 	input_dev->id.vendor  = SERIO_SUNKBD;
 	input_dev->id.product = sunkbd->type;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = sunkbd;
+	input_dev->dev.parent = &serio->dev;
+
+	input_set_drvdata(input_dev, sunkbd);
+
 	input_dev->event = sunkbd_event;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index a820934..f3a56eb 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -108,8 +108,7 @@ static int xtkbd_connect(struct serio *s
 	input_dev->id.vendor  = 0x0001;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = xtkbd;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	input_dev->keycode = xtkbd->keycode;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 41b4258..6013ace 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -40,6 +40,28 @@ config INPUT_M68K_BEEP
 	tristate "M68k Beeper support"
 	depends on M68K
 
+config INPUT_IXP4XX_BEEPER
+	tristate "IXP4XX Beeper support"
+	depends on ARCH_IXP4XX
+	help
+	  If you say yes here, you can connect a beeper to the
+	  ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ixp4xx-beeper.
+
+config INPUT_COBALT_BTNS
+	tristate "Cobalt button interface"
+	depends on MIPS_COBALT
+	select INPUT_POLLDEV
+	help
+	  Say Y here if you want to support MIPS Cobalt button interface.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cobalt_btns.
+
 config INPUT_WISTRON_BTNS
 	tristate "x86 Wistron laptop button interface"
 	depends on X86 && !X86_64
@@ -60,17 +82,79 @@ config INPUT_ATLAS_BTNS
 	  To compile this driver as a module, choose M here: the module will
 	  be called atlas_btns.
 
-config INPUT_IXP4XX_BEEPER
-	tristate "IXP4XX Beeper support"
-	depends on ARCH_IXP4XX
+config INPUT_ATI_REMOTE
+	tristate "ATI / X10 USB RF remote control"
+	select USB
 	help
-	  If you say yes here, you can connect a beeper to the
-	  ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+	  Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
+	  These are RF remotes with USB receivers.
+	  The ATI remote comes with many of ATI's All-In-Wonder video cards.
+	  The X10 "Lola" remote is available at:
+	     <http://www.x10.com/products/lola_sg1.htm>
+	  This driver provides mouse pointer, left and right mouse buttons,
+	  and maps all the other remote buttons to keypress events.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ati_remote.
+
+config INPUT_ATI_REMOTE2
+	tristate "ATI / Philips USB RF remote control"
+	select USB
+	help
+	  Say Y here if you want to use an ATI or Philips USB RF remote control.
+	  These are RF remotes with USB receivers.
+	  ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
+	  and is also available as a separate product.
+	  This driver provides mouse pointer, left and right mouse buttons,
+	  and maps all the other remote buttons to keypress events.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ati_remote2.
+
+config INPUT_KEYSPAN_REMOTE
+	tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	select USB
+	help
+	  Say Y here if you want to use a Keyspan DMR USB remote control.
+	  Currently only the UIA-11 type of receiver has been tested.  The tag
+	  on the receiver that connects to the USB port should have a P/N that
+	  will tell you what type of DMR you have.  The UIA-10 type is not
+	  supported at this time.  This driver maps all buttons to keypress
+	  events.
 
-	  If unsure, say Y.
+	  To compile this driver as a module, choose M here: the module will
+	  be called keyspan_remote.
+
+config INPUT_POWERMATE
+	tristate "Griffin PowerMate and Contour Jog support"
+	select USB
+	help
+	  Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
+	  These are aluminum dials which can measure clockwise and anticlockwise
+	  rotation.  The dial also acts as a pushbutton.  The base contains an LED
+	  which can be instructed to pulse or to switch to a particular intensity.
+
+	  You can download userspace tools from
+	  <http://sowerbutts.com/powermate/>.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called ixp4xx-beeper.
+	  module will be called powermate.
+
+config INPUT_YEALINK
+	tristate "Yealink usb-p1k voip phone"
+	depends EXPERIMENTAL
+	select USB
+	help
+	  Say Y here if you want to enable keyboard and LCD functions of the
+	  Yealink usb-p1k usb phones. The audio part is enabled by the generic
+	  usb sound driver, so you might want to enable that as well.
+
+	  For information about how to use these additional functions, see
+	  <file:Documentation/input/yealink.txt>.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called yealink.
 
 config INPUT_UINPUT
 	tristate "User level driver support"
@@ -81,8 +165,19 @@ config INPUT_UINPUT
 	  To compile this driver as a module, choose M here: the
 	  module will be called uinput.
 
+config INPUT_POLLDEV
+	tristate "Polled input device skeleton"
+	help
+	  Say Y here if you are using a driver for an input
+	  device that periodically polls hardware state. This
+	  option is only useful for out-of-tree drivers since
+	  in-tree drivers select it automatically.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called input-polldev.
+
 config HP_SDC_RTC
-	tristate "HP SDC Real Time Clock"       
+	tristate "HP SDC Real Time Clock"
 	depends on GSC || HP300
 	select HP_SDC
 	help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e0a8d58..8b2f779 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -4,11 +4,18 @@ #
 
 # Each configuration option enables a list of files.
 
+obj-$(CONFIG_INPUT_POLLDEV)		+= input-polldev.o
 obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
-obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
+obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
+obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
+obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
+obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
+obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
-obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
new file mode 100644
index 0000000..471aab2
--- /dev/null
+++ b/drivers/input/misc/ati_remote.c
@@ -0,0 +1,862 @@
+/*
+ *  USB ATI Remote support
+ *
+ *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
+ *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
+ *
+ *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
+ *  porting to the 2.6 kernel interfaces, along with other modification
+ *  to better match the style of the existing usb/input drivers.  However, the
+ *  protocol and hardware handling is essentially unchanged from 2.1.1.
+ *
+ *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
+ *  Vojtech Pavlik.
+ *
+ *  Changes:
+ *
+ *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.0
+ *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
+ *            Version 2.2.1
+ *            Added key repeat support contributed by:
+ *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
+ *            Added support for the "Lola" remote contributed by:
+ *                Seth Cohn <sethcohn@yahoo.com>
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Hardware & software notes
+ *
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages.  The receiver self-identifies as a
+ * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
+ *
+ * The "Lola" remote is available from X10.  See:
+ *    http://www.x10.com/products/lola_sg1.htm
+ * The Lola is similar to the ATI remote but has no mouse support, and slightly
+ * different keys.
+ *
+ * It is possible to use multiple receivers and remotes on multiple computers
+ * simultaneously by configuring them to use specific channels.
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
+ * hardware.
+ *
+ * Each remote can be configured to transmit on one channel as follows:
+ *   - Press and hold the "hand icon" button.
+ *   - When the red LED starts to blink, let go of the "hand icon" button.
+ *   - When it stops blinking, input the channel code as two digits, from 01
+ *     to 16, and press the hand icon again.
+ *
+ * The timing can be a little tricky.  Try loading the module with debug=1
+ * to have the kernel print out messages about the remote control number
+ * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
+ *
+ * The driver has a "channel_mask" parameter. This bitmask specifies which
+ * channels will be ignored by the module.  To mask out channels, just add
+ * all the 2^channel_number values together.
+ *
+ * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
+ * ignore signals coming from remote controls transmitting on channel 4, but
+ * accept all other channels.
+ *
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
+ * ignored.
+ *
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
+ * parameter are unused.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb/input.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+
+/*
+ * Module and Version Information, Module Parameters
+ */
+
+#define ATI_REMOTE_VENDOR_ID	0x0bc7
+#define ATI_REMOTE_PRODUCT_ID	0x004
+#define LOLA_REMOTE_PRODUCT_ID	0x002
+#define MEDION_REMOTE_PRODUCT_ID 0x006
+
+#define DRIVER_VERSION	        "2.2.1"
+#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
+#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
+
+#define NAME_BUFSIZE      80    /* size of product name, path buffers */
+#define DATA_BUFSIZE      63    /* size of URB data buffers */
+
+/*
+ * Duplicate event filtering time.
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME milliseconds between them are considered as repeat
+ * events. The hardware generates 5 events for the first keypress
+ * and we have to take this into account for an accurate repeat
+ * behaviour.
+ */
+#define FILTER_TIME	60 /* msec */
+#define REPEAT_DELAY	500 /* msec */
+
+static unsigned long channel_mask;
+module_param(channel_mask, ulong, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+static int repeat_filter = FILTER_TIME;
+module_param(repeat_filter, int, 0644);
+MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+
+static int repeat_delay = REPEAT_DELAY;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
+
+#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+#undef err
+#define err(format, arg...) printk(KERN_ERR format , ## arg)
+
+static struct usb_device_id ati_remote_table[] = {
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
+	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ati_remote_table);
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+#define SEND_FLAG_IN_PROGRESS	1
+#define SEND_FLAG_COMPLETE	2
+
+/* Device initialization strings */
+static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
+static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+
+struct ati_remote {
+	struct input_dev *idev;
+	struct usb_device *udev;
+	struct usb_interface *interface;
+
+	struct urb *irq_urb;
+	struct urb *out_urb;
+	struct usb_endpoint_descriptor *endpoint_in;
+	struct usb_endpoint_descriptor *endpoint_out;
+	unsigned char *inbuf;
+	unsigned char *outbuf;
+	dma_addr_t inbuf_dma;
+	dma_addr_t outbuf_dma;
+
+	unsigned char old_data[2];  /* Detect duplicate events */
+	unsigned long old_jiffies;
+	unsigned long acc_jiffies;  /* handle acceleration */
+	unsigned long first_jiffies;
+
+	unsigned int repeat_count;
+
+	char name[NAME_BUFSIZE];
+	char phys[NAME_BUFSIZE];
+
+	wait_queue_head_t wait;
+	int send_flags;
+};
+
+/* "Kinds" of messages sent from the hardware to the driver. */
+#define KIND_END        0
+#define KIND_LITERAL    1   /* Simply pass to input system */
+#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
+#define KIND_LU         3   /* Directional keypad diagonals - left up, */
+#define KIND_RU         4   /*   right up,  */
+#define KIND_LD         5   /*   left down, */
+#define KIND_RD         6   /*   right down */
+#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
+
+/* Translation table from hardware messages to input events. */
+static const struct {
+	short kind;
+	unsigned char data1, data2;
+	int type;
+	unsigned int code;
+	int value;
+}  ati_remote_tbl[] = {
+	/* Directional control pad axes */
+	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
+	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
+	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
+	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
+	/* Directional control pad diagonals */
+	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
+	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
+	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
+	{KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
+
+	/* "Mouse button" buttons */
+	{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
+	{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
+	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
+	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+
+	/* Artificial "doubleclick" events are generated by the hardware.
+	 * They are mapped to the "side" and "extra" mouse buttons here. */
+	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
+	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+
+	/* keyboard. */
+	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
+	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
+	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
+	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
+	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
+	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
+	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
+	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
+	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
+	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
+	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
+	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
+	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
+	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
+	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
+	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
+
+	/* "special" keys */
+	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
+	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
+	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
+	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
+	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
+	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
+	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
+	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
+	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
+	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
+	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
+	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
+	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
+	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
+	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
+	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
+	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
+	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
+	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
+	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
+	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
+	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
+	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
+	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
+	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
+	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
+	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
+	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
+	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
+	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
+	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
+	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
+
+	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
+};
+
+/* Local function prototypes */
+static void ati_remote_dump		(unsigned char *data, unsigned int actual_length);
+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);
+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);
+
+/* usb specific object to register with the usb subsystem */
+static struct usb_driver ati_remote_driver = {
+	.name         = "ati_remote",
+	.probe        = ati_remote_probe,
+	.disconnect   = ati_remote_disconnect,
+	.id_table     = ati_remote_table,
+};
+
+/*
+ *	ati_remote_dump_input
+ */
+static void ati_remote_dump(unsigned char *data, unsigned int len)
+{
+	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
+		warn("Weird byte 0x%02x", data[0]);
+	else if (len == 4)
+		warn("Weird key %02x %02x %02x %02x",
+		     data[0], data[1], data[2], data[3]);
+	else
+		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
+		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+/*
+ *	ati_remote_open
+ */
+static int ati_remote_open(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+	/* On first open, submit the read urb which was set up previously. */
+	ati_remote->irq_urb->dev = ati_remote->udev;
+	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
+		dev_err(&ati_remote->interface->dev,
+			"%s: usb_submit_urb failed!\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *	ati_remote_close
+ */
+static void ati_remote_close(struct input_dev *inputdev)
+{
+	struct ati_remote *ati_remote = input_get_drvdata(inputdev);
+
+	usb_kill_urb(ati_remote->irq_urb);
+}
+
+/*
+ *		ati_remote_irq_out
+ */
+static void ati_remote_irq_out(struct urb *urb)
+{
+	struct ati_remote *ati_remote = urb->context;
+
+	if (urb->status) {
+		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
+			__FUNCTION__, urb->status);
+		return;
+	}
+
+	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
+	wmb();
+	wake_up(&ati_remote->wait);
+}
+
+/*
+ *	ati_remote_sendpacket
+ *
+ *	Used to send device initialization strings
+ */
+static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
+{
+	int retval = 0;
+
+	/* Set up out_urb */
+	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
+	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
+
+	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
+	ati_remote->out_urb->dev = ati_remote->udev;
+	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
+
+	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
+	if (retval) {
+		dev_dbg(&ati_remote->interface->dev,
+			 "sendpacket: usb_submit_urb failed: %d\n", retval);
+		return retval;
+	}
+
+	wait_event_timeout(ati_remote->wait,
+		((ati_remote->out_urb->status != -EINPROGRESS) ||
+			(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+		HZ);
+	usb_kill_urb(ati_remote->out_urb);
+
+	return retval;
+}
+
+/*
+ *	ati_remote_event_lookup
+ */
+static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
+{
+	int i;
+
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+		/*
+		 * Decide if the table entry matches the remote input.
+		 */
+		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
+		    ((((ati_remote_tbl[i].data1 >> 4) -
+		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
+		    (ati_remote_tbl[i].data2 == d2))
+			return i;
+
+	}
+	return -1;
+}
+
+/*
+ *	ati_remote_compute_accel
+ *
+ * Implements acceleration curve for directional control pad
+ * If elapsed time since last event is > 1/4 second, user "stopped",
+ * so reset acceleration. Otherwise, user is probably holding the control
+ * pad down, so we increase acceleration, ramping up over two seconds to
+ * a maximum speed.
+ */
+static int ati_remote_compute_accel(struct ati_remote *ati_remote)
+{
+	static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+	unsigned long now = jiffies;
+	int acc;
+
+	if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
+		acc = 1;
+		ati_remote->acc_jiffies = now;
+	}
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
+		acc = accel[0];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
+		acc = accel[1];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
+		acc = accel[2];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
+		acc = accel[3];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
+		acc = accel[4];
+	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
+		acc = accel[5];
+	else
+		acc = accel[6];
+
+	return acc;
+}
+
+/*
+ *	ati_remote_report_input
+ */
+static void ati_remote_input_report(struct urb *urb)
+{
+	struct ati_remote *ati_remote = urb->context;
+	unsigned char *data= ati_remote->inbuf;
+	struct input_dev *dev = ati_remote->idev;
+	int index, acc;
+	int remote_num;
+
+	/* Deal with strange looking inputs */
+	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+		((data[3] & 0x0f) != 0x00) ) {
+		ati_remote_dump(data, urb->actual_length);
+		return;
+	}
+
+	/* Mask unwanted remote channels.  */
+	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
+	remote_num = (data[3] >> 4) & 0x0f;
+        if (channel_mask & (1 << (remote_num + 1))) {
+		dbginfo(&ati_remote->interface->dev,
+			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
+			remote_num, data[1], data[2], channel_mask);
+		return;
+	}
+
+	/* Look up event code index in translation table */
+	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
+	if (index < 0) {
+		dev_warn(&ati_remote->interface->dev,
+			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
+			 remote_num, data[1], data[2]);
+		return;
+	}
+	dbginfo(&ati_remote->interface->dev,
+		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
+		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
+
+	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code,
+			ati_remote_tbl[index].value);
+		input_sync(dev);
+
+		ati_remote->old_jiffies = jiffies;
+		return;
+	}
+
+	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+		unsigned long now = jiffies;
+
+		/* Filter duplicate events which happen "too close" together. */
+		if (ati_remote->old_data[0] == data[1] &&
+		    ati_remote->old_data[1] == data[2] &&
+		    time_before(now, ati_remote->old_jiffies +
+				     msecs_to_jiffies(repeat_filter))) {
+			ati_remote->repeat_count++;
+		} else {
+			ati_remote->repeat_count = 0;
+			ati_remote->first_jiffies = now;
+		}
+
+		ati_remote->old_data[0] = data[1];
+		ati_remote->old_data[1] = data[2];
+		ati_remote->old_jiffies = now;
+
+		/* Ensure we skip at least the 4 first duplicate events (generated
+		 * by a single keypress), and continue skipping until repeat_delay
+		 * msecs have passed
+		 */
+		if (ati_remote->repeat_count > 0 &&
+		    (ati_remote->repeat_count < 5 ||
+		     time_before(now, ati_remote->first_jiffies +
+				      msecs_to_jiffies(repeat_delay))))
+			return;
+
+
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 1);
+		input_sync(dev);
+		input_event(dev, ati_remote_tbl[index].type,
+			ati_remote_tbl[index].code, 0);
+		input_sync(dev);
+
+	} else {
+
+		/*
+		 * Other event kinds are from the directional control pad, and have an
+		 * acceleration factor applied to them.  Without this acceleration, the
+		 * control pad is mostly unusable.
+		 */
+		acc = ati_remote_compute_accel(ati_remote);
+
+		switch (ati_remote_tbl[index].kind) {
+		case KIND_ACCEL:
+			input_event(dev, ati_remote_tbl[index].type,
+				ati_remote_tbl[index].code,
+				ati_remote_tbl[index].value * acc);
+			break;
+		case KIND_LU:
+			input_report_rel(dev, REL_X, -acc);
+			input_report_rel(dev, REL_Y, -acc);
+			break;
+		case KIND_RU:
+			input_report_rel(dev, REL_X, acc);
+			input_report_rel(dev, REL_Y, -acc);
+			break;
+		case KIND_LD:
+			input_report_rel(dev, REL_X, -acc);
+			input_report_rel(dev, REL_Y, acc);
+			break;
+		case KIND_RD:
+			input_report_rel(dev, REL_X, acc);
+			input_report_rel(dev, REL_Y, acc);
+			break;
+		default:
+			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+				ati_remote_tbl[index].kind);
+		}
+		input_sync(dev);
+
+		ati_remote->old_jiffies = jiffies;
+		ati_remote->old_data[0] = data[1];
+		ati_remote->old_data[1] = data[2];
+	}
+}
+
+/*
+ *	ati_remote_irq_in
+ */
+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);
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
+			__FUNCTION__);
+		return;
+	default:		/* error */
+		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
+			__FUNCTION__, urb->status);
+	}
+
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
+			__FUNCTION__, retval);
+}
+
+/*
+ *	ati_remote_alloc_buffers
+ */
+static int ati_remote_alloc_buffers(struct usb_device *udev,
+				    struct ati_remote *ati_remote)
+{
+	ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					     &ati_remote->inbuf_dma);
+	if (!ati_remote->inbuf)
+		return -1;
+
+	ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
+					      &ati_remote->outbuf_dma);
+	if (!ati_remote->outbuf)
+		return -1;
+
+	ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->irq_urb)
+		return -1;
+
+	ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ati_remote->out_urb)
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	ati_remote_free_buffers
+ */
+static void ati_remote_free_buffers(struct ati_remote *ati_remote)
+{
+	usb_free_urb(ati_remote->irq_urb);
+	usb_free_urb(ati_remote->out_urb);
+
+	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+		ati_remote->inbuf, ati_remote->inbuf_dma);
+
+	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+		ati_remote->outbuf, ati_remote->outbuf_dma);
+}
+
+static void ati_remote_input_init(struct ati_remote *ati_remote)
+{
+	struct input_dev *idev = ati_remote->idev;
+	int i;
+
+	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+					  BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
+	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
+		if (ati_remote_tbl[i].type == EV_KEY)
+			set_bit(ati_remote_tbl[i].code, idev->keybit);
+
+	input_set_drvdata(idev, ati_remote);
+
+	idev->open = ati_remote_open;
+	idev->close = ati_remote_close;
+
+	idev->name = ati_remote->name;
+	idev->phys = ati_remote->phys;
+
+	usb_to_input_id(ati_remote->udev, &idev->id);
+	idev->dev.parent = &ati_remote->udev->dev;
+}
+
+static int ati_remote_initialize(struct ati_remote *ati_remote)
+{
+	struct usb_device *udev = ati_remote->udev;
+	int pipe, maxp;
+
+	init_waitqueue_head(&ati_remote->wait);
+
+	/* Set up irq_urb */
+	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+			 maxp, ati_remote_irq_in, ati_remote,
+			 ati_remote->endpoint_in->bInterval);
+	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
+	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* Set up out_urb */
+	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
+
+	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+			 maxp, ati_remote_irq_out, ati_remote,
+			 ati_remote->endpoint_out->bInterval);
+	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
+	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* send initialization strings */
+	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
+	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+		dev_err(&ati_remote->interface->dev,
+			 "Initializing ati_remote hardware failed.\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ *	ati_remote_probe
+ */
+static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_host = interface->cur_altsetting;
+	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+	struct ati_remote *ati_remote;
+	struct input_dev *input_dev;
+	int err = -ENOMEM;
+
+	if (iface_host->desc.bNumEndpoints != 2) {
+		err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	endpoint_in = &iface_host->endpoint[0].desc;
+	endpoint_out = &iface_host->endpoint[1].desc;
+
+	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) {
+		err("%s: endpoint_in message size==0? \n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ati_remote || !input_dev)
+		goto fail1;
+
+	/* Allocate URB buffers, URBs */
+	if (ati_remote_alloc_buffers(udev, ati_remote))
+		goto fail2;
+
+	ati_remote->endpoint_in = endpoint_in;
+	ati_remote->endpoint_out = endpoint_out;
+	ati_remote->udev = udev;
+	ati_remote->idev = input_dev;
+	ati_remote->interface = interface;
+
+	usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
+	strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
+
+	if (udev->manufacturer)
+		strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
+
+	if (udev->product)
+		snprintf(ati_remote->name, sizeof(ati_remote->name),
+			 "%s %s", ati_remote->name, udev->product);
+
+	if (!strlen(ati_remote->name))
+		snprintf(ati_remote->name, sizeof(ati_remote->name),
+			DRIVER_DESC "(%04x,%04x)",
+			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
+			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
+
+	ati_remote_input_init(ati_remote);
+
+	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
+	err = ati_remote_initialize(ati_remote);
+	if (err)
+		goto fail3;
+
+	/* Set up and register input device */
+	err = input_register_device(ati_remote->idev);
+	if (err)
+		goto fail3;
+
+	usb_set_intfdata(interface, ati_remote);
+	return 0;
+
+ fail3:	usb_kill_urb(ati_remote->irq_urb);
+	usb_kill_urb(ati_remote->out_urb);
+ fail2:	ati_remote_free_buffers(ati_remote);
+ fail1:	input_free_device(input_dev);
+	kfree(ati_remote);
+	return err;
+}
+
+/*
+ *	ati_remote_disconnect
+ */
+static void ati_remote_disconnect(struct usb_interface *interface)
+{
+	struct ati_remote *ati_remote;
+
+	ati_remote = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+	if (!ati_remote) {
+		warn("%s - null device?\n", __FUNCTION__);
+		return;
+	}
+
+	usb_kill_urb(ati_remote->irq_urb);
+	usb_kill_urb(ati_remote->out_urb);
+	input_unregister_device(ati_remote->idev);
+	ati_remote_free_buffers(ati_remote);
+	kfree(ati_remote);
+}
+
+/*
+ *	ati_remote_init
+ */
+static int __init ati_remote_init(void)
+{
+	int result;
+
+	result = usb_register(&ati_remote_driver);
+	if (result)
+		err("usb_register error #%d\n", result);
+	else
+		info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
+
+	return result;
+}
+
+/*
+ *	ati_remote_exit
+ */
+static void __exit ati_remote_exit(void)
+{
+	usb_deregister(&ati_remote_driver);
+}
+
+/*
+ *	module specification
+ */
+
+module_init(ati_remote_init);
+module_exit(ati_remote_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
new file mode 100644
index 0000000..1031543
--- /dev/null
+++ b/drivers/input/misc/ati_remote2.c
@@ -0,0 +1,543 @@
+/*
+ * ati_remote2 - ATI/Philips USB RF remote driver
+ *
+ * Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
+ * Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.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/usb/input.h>
+
+#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
+#define DRIVER_VERSION "0.2"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
+MODULE_LICENSE("GPL");
+
+/*
+ * ATI Remote Wonder II Channel Configuration
+ *
+ * The remote control can by assigned one of sixteen "channels" in order to facilitate
+ * the use of multiple remote controls within range of each other.
+ * A remote's "channel" may be altered by pressing and holding the "PC" button for
+ * approximately 3 seconds, after which the button will slowly flash the count of the
+ * currently configured "channel", using the numeric keypad enter a number between 1 and
+ * 16 and then the "PC" button again, the button will slowly flash the count of the
+ * newly configured "channel".
+ */
+
+static unsigned int channel_mask = 0xFFFF;
+module_param(channel_mask, uint, 0644);
+MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
+
+static unsigned int mode_mask = 0x1F;
+module_param(mode_mask, uint, 0644);
+MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
+
+static struct usb_device_id ati_remote2_id_table[] = {
+	{ USB_DEVICE(0x0471, 0x0602) },	/* ATI Remote Wonder II */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
+
+static struct {
+	int hw_code;
+	int key_code;
+} ati_remote2_key_table[] = {
+	{ 0x00, KEY_0 },
+	{ 0x01, KEY_1 },
+	{ 0x02, KEY_2 },
+	{ 0x03, KEY_3 },
+	{ 0x04, KEY_4 },
+	{ 0x05, KEY_5 },
+	{ 0x06, KEY_6 },
+	{ 0x07, KEY_7 },
+	{ 0x08, KEY_8 },
+	{ 0x09, KEY_9 },
+	{ 0x0c, KEY_POWER },
+	{ 0x0d, KEY_MUTE },
+	{ 0x10, KEY_VOLUMEUP },
+	{ 0x11, KEY_VOLUMEDOWN },
+	{ 0x20, KEY_CHANNELUP },
+	{ 0x21, KEY_CHANNELDOWN },
+	{ 0x28, KEY_FORWARD },
+	{ 0x29, KEY_REWIND },
+	{ 0x2c, KEY_PLAY },
+	{ 0x30, KEY_PAUSE },
+	{ 0x31, KEY_STOP },
+	{ 0x37, KEY_RECORD },
+	{ 0x38, KEY_DVD },
+	{ 0x39, KEY_TV },
+	{ 0x54, KEY_MENU },
+	{ 0x58, KEY_UP },
+	{ 0x59, KEY_DOWN },
+	{ 0x5a, KEY_LEFT },
+	{ 0x5b, KEY_RIGHT },
+	{ 0x5c, KEY_OK },
+	{ 0x78, KEY_A },
+	{ 0x79, KEY_B },
+	{ 0x7a, KEY_C },
+	{ 0x7b, KEY_D },
+	{ 0x7c, KEY_E },
+	{ 0x7d, KEY_F },
+	{ 0x82, KEY_ENTER },
+	{ 0x8e, KEY_VENDOR },
+	{ 0x96, KEY_COFFEE },
+	{ 0xa9, BTN_LEFT },
+	{ 0xaa, BTN_RIGHT },
+	{ 0xbe, KEY_QUESTION },
+	{ 0xd5, KEY_FRONT },
+	{ 0xd0, KEY_EDIT },
+	{ 0xf9, KEY_INFO },
+	{ (0x00 << 8) | 0x3f, KEY_PROG1 },
+	{ (0x01 << 8) | 0x3f, KEY_PROG2 },
+	{ (0x02 << 8) | 0x3f, KEY_PROG3 },
+	{ (0x03 << 8) | 0x3f, KEY_PROG4 },
+	{ (0x04 << 8) | 0x3f, KEY_PC },
+	{ 0, KEY_RESERVED }
+};
+
+struct ati_remote2 {
+	struct input_dev *idev;
+	struct usb_device *udev;
+
+	struct usb_interface *intf[2];
+	struct usb_endpoint_descriptor *ep[2];
+	struct urb *urb[2];
+	void *buf[2];
+	dma_addr_t buf_dma[2];
+
+	unsigned long jiffies;
+	int mode;
+
+	char name[64];
+	char phys[64];
+};
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
+static void ati_remote2_disconnect(struct usb_interface *interface);
+
+static struct usb_driver ati_remote2_driver = {
+	.name       = "ati_remote2",
+	.probe      = ati_remote2_probe,
+	.disconnect = ati_remote2_disconnect,
+	.id_table   = ati_remote2_id_table,
+};
+
+static int ati_remote2_open(struct input_dev *idev)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+	int r;
+
+	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
+	if (r) {
+		dev_err(&ar2->intf[0]->dev,
+			"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
+		return r;
+	}
+	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
+	if (r) {
+		usb_kill_urb(ar2->urb[0]);
+		dev_err(&ar2->intf[1]->dev,
+			"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
+		return r;
+	}
+
+	return 0;
+}
+
+static void ati_remote2_close(struct input_dev *idev)
+{
+	struct ati_remote2 *ar2 = input_get_drvdata(idev);
+
+	usb_kill_urb(ar2->urb[0]);
+	usb_kill_urb(ar2->urb[1]);
+}
+
+static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev = ar2->idev;
+	u8 *data = ar2->buf[0];
+	int channel, mode;
+
+	channel = data[0] >> 4;
+
+	if (!((1 << channel) & channel_mask))
+		return;
+
+	mode = data[0] & 0x0F;
+
+	if (mode > 4) {
+		dev_err(&ar2->intf[0]->dev,
+			"Unknown mode byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	if (!((1 << mode) & mode_mask))
+		return;
+
+	input_event(idev, EV_REL, REL_X, (s8) data[1]);
+	input_event(idev, EV_REL, REL_Y, (s8) data[2]);
+	input_sync(idev);
+}
+
+static int ati_remote2_lookup(unsigned int hw_code)
+{
+	int i;
+
+	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
+		if (ati_remote2_key_table[i].hw_code == hw_code)
+			return i;
+
+	return -1;
+}
+
+static void ati_remote2_input_key(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev = ar2->idev;
+	u8 *data = ar2->buf[1];
+	int channel, mode, hw_code, index;
+
+	channel = data[0] >> 4;
+
+	if (!((1 << channel) & channel_mask))
+		return;
+
+	mode = data[0] & 0x0F;
+
+	if (mode > 4) {
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown mode byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	hw_code = data[2];
+	/*
+	 * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
+	 * Use the mode byte to figure out which one was pressed.
+	 */
+	if (hw_code == 0x3f) {
+		/*
+		 * For some incomprehensible reason the mouse pad generates
+		 * events which look identical to the events from the last
+		 * pressed mode key. Naturally we don't want to generate key
+		 * events for the mouse pad so we filter out any subsequent
+		 * events from the same mode key.
+		 */
+		if (ar2->mode == mode)
+			return;
+
+		if (data[1] == 0)
+			ar2->mode = mode;
+
+		hw_code |= mode << 8;
+	}
+
+	if (!((1 << mode) & mode_mask))
+		return;
+
+	index = ati_remote2_lookup(hw_code);
+	if (index < 0) {
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown code byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	switch (data[1]) {
+	case 0:	/* release */
+		break;
+	case 1:	/* press */
+		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
+		break;
+	case 2:	/* repeat */
+
+		/* No repeat for mouse buttons. */
+		if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
+		    ati_remote2_key_table[index].key_code == BTN_RIGHT)
+			return;
+
+		if (!time_after_eq(jiffies, ar2->jiffies))
+			return;
+
+		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
+		break;
+	default:
+		dev_err(&ar2->intf[1]->dev,
+			"Unknown state byte (%02x %02x %02x %02x)\n",
+			data[3], data[2], data[1], data[0]);
+		return;
+	}
+
+	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 ati_remote2 *ar2 = urb->context;
+	int r;
+
+	switch (urb->status) {
+	case 0:
+		ati_remote2_input_mouse(ar2);
+		break;
+	case -ENOENT:
+	case -EILSEQ:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev_dbg(&ar2->intf[0]->dev,
+			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
+		return;
+	default:
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
+	}
+
+	r = usb_submit_urb(urb, GFP_ATOMIC);
+	if (r)
+		dev_err(&ar2->intf[0]->dev,
+			"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
+}
+
+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);
+		break;
+	case -ENOENT:
+	case -EILSEQ:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		dev_dbg(&ar2->intf[1]->dev,
+			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
+		return;
+	default:
+		dev_err(&ar2->intf[1]->dev,
+			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
+	}
+
+	r = usb_submit_urb(urb, GFP_ATOMIC);
+	if (r)
+		dev_err(&ar2->intf[1]->dev,
+			"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
+}
+
+static int ati_remote2_input_init(struct ati_remote2 *ar2)
+{
+	struct input_dev *idev;
+	int i, retval;
+
+	idev = input_allocate_device();
+	if (!idev)
+		return -ENOMEM;
+
+	ar2->idev = idev;
+	input_set_drvdata(idev, ar2);
+
+	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+	idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
+		set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
+
+	idev->rep[REP_DELAY]  = 250;
+	idev->rep[REP_PERIOD] = 33;
+
+	idev->open = ati_remote2_open;
+	idev->close = ati_remote2_close;
+
+	idev->name = ar2->name;
+	idev->phys = ar2->phys;
+
+	usb_to_input_id(ar2->udev, &idev->id);
+	idev->dev.parent = &ar2->udev->dev;
+
+	retval = input_register_device(idev);
+	if (retval)
+		input_free_device(idev);
+
+	return retval;
+}
+
+static int ati_remote2_urb_init(struct ati_remote2 *ar2)
+{
+	struct usb_device *udev = ar2->udev;
+	int i, pipe, maxp;
+
+	for (i = 0; i < 2; i++) {
+		ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
+		if (!ar2->buf[i])
+			return -ENOMEM;
+
+		ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ar2->urb[i])
+			return -ENOMEM;
+
+		pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
+		maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+		maxp = maxp > 4 ? 4 : maxp;
+
+		usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
+				 i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
+				 ar2, ar2->ep[i]->bInterval);
+		ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
+		ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	}
+
+	return 0;
+}
+
+static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		usb_free_urb(ar2->urb[i]);
+		usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
+	}
+}
+
+static int ati_remote2_setup(struct ati_remote2 *ar2)
+{
+	int r, i, channel;
+
+	/*
+	 * Configure receiver to only accept input from remote "channel"
+	 *  channel == 0  -> Accept input from any remote channel
+	 *  channel == 1  -> Only accept input from remote channel 1
+	 *  channel == 2  -> Only accept input from remote channel 2
+	 *  ...
+	 *  channel == 16 -> Only accept input from remote channel 16
+	 */
+
+	channel = 0;
+	for (i = 0; i < 16; i++) {
+		if ((1 << i) & channel_mask) {
+			if (!(~(1 << i) & 0xFFFF & channel_mask))
+				channel = i + 1;
+			break;
+		}
+	}
+
+	r = usb_control_msg(ar2->udev, usb_sndctrlpipe(ar2->udev, 0),
+			    0x20,
+			    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			    channel, 0x0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	if (r) {
+		dev_err(&ar2->udev->dev, "%s - failed to set channel due to error: %d\n",
+			__FUNCTION__, r);
+		return r;
+	}
+
+	return 0;
+}
+
+static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *alt = interface->cur_altsetting;
+	struct ati_remote2 *ar2;
+	int r;
+
+	if (alt->desc.bInterfaceNumber)
+		return -ENODEV;
+
+	ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
+	if (!ar2)
+		return -ENOMEM;
+
+	ar2->udev = udev;
+
+	ar2->intf[0] = interface;
+	ar2->ep[0] = &alt->endpoint[0].desc;
+
+	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
+	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
+	if (r)
+		goto fail1;
+	alt = ar2->intf[1]->cur_altsetting;
+	ar2->ep[1] = &alt->endpoint[0].desc;
+
+	r = ati_remote2_urb_init(ar2);
+	if (r)
+		goto fail2;
+
+	r = ati_remote2_setup(ar2);
+	if (r)
+		goto fail2;
+
+	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
+	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
+
+	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
+
+	r = ati_remote2_input_init(ar2);
+	if (r)
+		goto fail2;
+
+	usb_set_intfdata(interface, ar2);
+
+	return 0;
+
+ fail2:
+	ati_remote2_urb_cleanup(ar2);
+
+	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+ fail1:
+	kfree(ar2);
+
+	return r;
+}
+
+static void ati_remote2_disconnect(struct usb_interface *interface)
+{
+	struct ati_remote2 *ar2;
+	struct usb_host_interface *alt = interface->cur_altsetting;
+
+	if (alt->desc.bInterfaceNumber)
+		return;
+
+	ar2 = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	input_unregister_device(ar2->idev);
+
+	ati_remote2_urb_cleanup(ar2);
+
+	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
+
+	kfree(ar2);
+}
+
+static int __init ati_remote2_init(void)
+{
+	int r;
+
+	r = usb_register(&ati_remote2_driver);
+	if (r)
+		printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
+	else
+		printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
+
+	return r;
+}
+
+static void __exit ati_remote2_exit(void)
+{
+	usb_deregister(&ati_remote2_driver);
+}
+
+module_init(ati_remote2_init);
+module_exit(ati_remote2_exit);
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
new file mode 100644
index 0000000..064b079
--- /dev/null
+++ b/drivers/input/misc/cobalt_btns.c
@@ -0,0 +1,172 @@
+/*
+ *  Cobalt button interface driver.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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/init.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define BUTTONS_POLL_INTERVAL	30	/* msec */
+#define BUTTONS_COUNT_THRESHOLD	3
+#define BUTTONS_STATUS_MASK	0xfe000000
+
+struct buttons_dev {
+	struct input_polled_dev *poll_dev;
+	void __iomem *reg;
+};
+
+struct buttons_map {
+	uint32_t mask;
+	int keycode;
+	int count;
+};
+
+static struct buttons_map buttons_map[] = {
+	{ 0x02000000, KEY_RESTART, },
+	{ 0x04000000, KEY_LEFT, },
+	{ 0x08000000, KEY_UP, },
+	{ 0x10000000, KEY_DOWN, },
+	{ 0x20000000, KEY_RIGHT, },
+	{ 0x40000000, KEY_ENTER, },
+	{ 0x80000000, KEY_SELECT, },
+};
+
+static void handle_buttons(struct input_polled_dev *dev)
+{
+	struct buttons_map *button = buttons_map;
+	struct buttons_dev *bdev = dev->private;
+	struct input_dev *input = dev->input;
+	uint32_t status;
+	int i;
+
+	status = readl(bdev->reg);
+	status = ~status & BUTTONS_STATUS_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
+		if (status & button->mask) {
+			button->count++;
+		} else {
+			if (button->count >= BUTTONS_COUNT_THRESHOLD) {
+				input_report_key(input, button->keycode, 0);
+				input_sync(input);
+			}
+			button->count = 0;
+		}
+
+		if (button->count == BUTTONS_COUNT_THRESHOLD) {
+			input_report_key(input, button->keycode, 1);
+			input_sync(input);
+		}
+
+		button++;
+	}
+}
+
+static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
+{
+	struct buttons_dev *bdev;
+	struct input_polled_dev *poll_dev;
+	struct input_dev *input;
+	struct resource *res;
+	int error, i;
+
+	bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
+	poll_dev = input_allocate_polled_device();
+	if (!bdev || !poll_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	poll_dev->private = bdev;
+	poll_dev->poll = handle_buttons;
+	poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
+
+	input = poll_dev->input;
+	input->name = "Cobalt buttons";
+	input->phys = "cobalt/input0";
+	input->id.bustype = BUS_HOST;
+	input->cdev.dev = &pdev->dev;
+
+	input->evbit[0] = BIT(EV_KEY);
+	for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
+		set_bit(buttons_map[i].keycode, input->keybit);
+		buttons_map[i].count = 0;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	bdev->poll_dev = poll_dev;
+	bdev->reg = ioremap(res->start, res->end - res->start + 1);
+	dev_set_drvdata(&pdev->dev, bdev);
+
+	error = input_register_polled_device(poll_dev);
+	if (error)
+		goto err_iounmap;
+
+	return 0;
+
+ err_iounmap:
+	iounmap(bdev->reg);
+ err_free_mem:
+	input_free_polled_device(poll_dev);
+	kfree(bdev);
+	dev_set_drvdata(&pdev->dev, NULL);
+	return error;
+}
+
+static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct buttons_dev *bdev = dev_get_drvdata(dev);
+
+	input_unregister_polled_device(bdev->poll_dev);
+	input_free_polled_device(bdev->poll_dev);
+	iounmap(bdev->reg);
+	kfree(bdev);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver cobalt_buttons_driver = {
+	.probe	= cobalt_buttons_probe,
+	.remove	= __devexit_p(cobalt_buttons_remove),
+	.driver	= {
+		.name	= "Cobalt buttons",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init cobalt_buttons_init(void)
+{
+	return platform_driver_register(&cobalt_buttons_driver);
+}
+
+static void __exit cobalt_buttons_exit(void)
+{
+	platform_driver_unregister(&cobalt_buttons_driver);
+}
+
+module_init(cobalt_buttons_init);
+module_exit(cobalt_buttons_exit);
diff --git a/drivers/input/misc/input-polldev.c b/drivers/input/misc/input-polldev.c
new file mode 100644
index 0000000..1b2b9c9
--- /dev/null
+++ b/drivers/input/misc/input-polldev.c
@@ -0,0 +1,171 @@
+/*
+ * Generic implementation of a polled input device
+
+ * Copyright (c) 2007 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/input-polldev.h>
+
+static DEFINE_MUTEX(polldev_mutex);
+static int polldev_users;
+static struct workqueue_struct *polldev_wq;
+
+static int input_polldev_start_workqueue(void)
+{
+	int retval;
+
+	retval = mutex_lock_interruptible(&polldev_mutex);
+	if (retval)
+		return retval;
+
+	if (!polldev_users) {
+		polldev_wq = create_singlethread_workqueue("ipolldevd");
+		if (!polldev_wq) {
+			printk(KERN_ERR "input-polldev: failed to create "
+				"ipolldevd workqueue\n");
+			retval = -ENOMEM;
+			goto out;
+		}
+	}
+
+	polldev_users++;
+
+ out:
+	mutex_unlock(&polldev_mutex);
+	return retval;
+}
+
+static void input_polldev_stop_workqueue(void)
+{
+	mutex_lock(&polldev_mutex);
+
+	if (!--polldev_users)
+		destroy_workqueue(polldev_wq);
+
+	mutex_unlock(&polldev_mutex);
+}
+
+static void input_polled_device_work(struct work_struct *work)
+{
+	struct input_polled_dev *dev =
+		container_of(work, struct input_polled_dev, work.work);
+
+	dev->poll(dev);
+	queue_delayed_work(polldev_wq, &dev->work,
+			   msecs_to_jiffies(dev->poll_interval));
+}
+
+static int input_open_polled_device(struct input_dev *input)
+{
+	struct input_polled_dev *dev = input->private;
+	int error;
+
+	error = input_polldev_start_workqueue();
+	if (error)
+		return error;
+
+	if (dev->flush)
+		dev->flush(dev);
+
+	queue_delayed_work(polldev_wq, &dev->work,
+			   msecs_to_jiffies(dev->poll_interval));
+
+	return 0;
+}
+
+static void input_close_polled_device(struct input_dev *input)
+{
+	struct input_polled_dev *dev = input->private;
+
+	cancel_rearming_delayed_workqueue(polldev_wq, &dev->work);
+	input_polldev_stop_workqueue();
+}
+
+/**
+ * input_allocate_polled_device - allocated memory polled device
+ *
+ * The function allocates memory for a polled device and also
+ * for an input device associated with this polled device.
+ */
+struct input_polled_dev *input_allocate_polled_device(void)
+{
+	struct input_polled_dev *dev;
+
+	dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->input = input_allocate_device();
+	if (!dev->input) {
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL(input_allocate_polled_device);
+
+/**
+ * input_free_polled_device - free memory allocated for polled device
+ * @dev: device to free
+ *
+ * The function frees memory allocated for polling device and drops
+ * reference to the associated input device (if present).
+ */
+void input_free_polled_device(struct input_polled_dev *dev)
+{
+	if (dev) {
+		input_free_device(dev->input);
+		kfree(dev);
+	}
+}
+EXPORT_SYMBOL(input_free_polled_device);
+
+/**
+ * input_register_polled_device - register polled device
+ * @dev: device to register
+ *
+ * The function registers previously initialized polled input device
+ * with input layer. The device should be allocated with call to
+ * input_allocate_polled_device(). Callers should also set up poll()
+ * method and set up capabilities (id, name, phys, bits) of the
+ * corresponing input_dev structure.
+ */
+int input_register_polled_device(struct input_polled_dev *dev)
+{
+	struct input_dev *input = dev->input;
+
+	INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
+	if (!dev->poll_interval)
+		dev->poll_interval = 500;
+	input->private = dev;
+	input->open = input_open_polled_device;
+	input->close = input_close_polled_device;
+
+	return input_register_device(input);
+}
+EXPORT_SYMBOL(input_register_polled_device);
+
+/**
+ * input_unregister_polled_device - unregister polled device
+ * @dev: device to unregister
+ *
+ * The function unregisters previously registered polled input
+ * device from input layer. Polling is stopped and device is
+ * ready to be freed with call to input_free_polled_device().
+ * Callers should not attempt to access dev->input pointer
+ * after calling this function.
+ */
+void input_unregister_polled_device(struct input_polled_dev *dev)
+{
+	input_unregister_device(dev->input);
+	dev->input = NULL;
+}
+EXPORT_SYMBOL(input_unregister_polled_device);
+
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 105c6fc..3d4b619 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -51,7 +51,7 @@ static void ixp4xx_spkr_control(unsigned
 
 static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	unsigned int pin = (unsigned int) dev->private;
+	unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 	unsigned int count = 0;
 
 	if (type != EV_SND)
@@ -99,14 +99,15 @@ static int __devinit ixp4xx_spkr_probe(s
 	if (!input_dev)
 		return -ENOMEM;
 
-	input_dev->private = (void *) dev->id;
+	input_set_drvdata(input_dev, (void *) dev->id);
+
 	input_dev->name = "ixp4xx beeper",
 	input_dev->phys = "ixp4xx/gpio";
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor  = 0x001f;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &dev->dev;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->evbit[0] = BIT(EV_SND);
 	input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
@@ -136,7 +137,7 @@ static int __devinit ixp4xx_spkr_probe(s
 static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
 {
 	struct input_dev *input_dev = platform_get_drvdata(dev);
-	unsigned int pin = (unsigned int) input_dev->private;
+	unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 
 	input_unregister_device(input_dev);
 	platform_set_drvdata(dev, NULL);
@@ -153,7 +154,7 @@ static int __devexit ixp4xx_spkr_remove(
 static void ixp4xx_spkr_shutdown(struct platform_device *dev)
 {
 	struct input_dev *input_dev = platform_get_drvdata(dev);
-	unsigned int pin = (unsigned int) input_dev->private;
+	unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 
 	/* turn off the speaker */
 	disable_irq(IRQ_IXP4XX_TIMER2);
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
new file mode 100644
index 0000000..1bffc9f
--- /dev/null
+++ b/drivers/input/misc/keyspan_remote.c
@@ -0,0 +1,592 @@
+/*
+ * keyspan_remote: USB driver for the Keyspan DMR
+ *
+ * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2.
+ *
+ * This driver has been put together with the support of Innosys, Inc.
+ * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb/input.h>
+
+#define DRIVER_VERSION	"v0.1"
+#define DRIVER_AUTHOR	"Michael Downey <downey@zymeta.com>"
+#define DRIVER_DESC	"Driver for the USB Keyspan remote control."
+#define DRIVER_LICENSE	"GPL"
+
+/* Parameters that can be passed to the driver. */
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* Vendor and product ids */
+#define USB_KEYSPAN_VENDOR_ID		0x06CD
+#define USB_KEYSPAN_PRODUCT_UIA11	0x0202
+
+/* Defines for converting the data from the remote. */
+#define ZERO		0x18
+#define ZERO_MASK	0x1F	/* 5 bits for a 0 */
+#define ONE		0x3C
+#define ONE_MASK	0x3F	/* 6 bits for a 1 */
+#define SYNC		0x3F80
+#define SYNC_MASK	0x3FFF	/* 14 bits for a SYNC sequence */
+#define STOP		0x00
+#define STOP_MASK	0x1F	/* 5 bits for the STOP sequence */
+#define GAP		0xFF
+
+#define RECV_SIZE	8	/* The UIA-11 type have a 8 byte limit. */
+
+/* table of devices that work with this driver */
+static struct usb_device_id keyspan_table[] = {
+	{ USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
+	{ }					/* Terminating entry */
+};
+
+/* Structure to store all the real stuff that a remote sends to us. */
+struct keyspan_message {
+	u16	system;
+	u8	button;
+	u8	toggle;
+};
+
+/* Structure used for all the bit testing magic needed to be done. */
+struct bit_tester {
+	u32	tester;
+	int	len;
+	int	pos;
+	int	bits_left;
+	u8	buffer[32];
+};
+
+/* Structure to hold all of our driver specific stuff */
+struct usb_keyspan {
+	char				name[128];
+	char				phys[64];
+	struct usb_device*		udev;
+	struct input_dev		*input;
+	struct usb_interface*		interface;
+	struct usb_endpoint_descriptor* in_endpoint;
+	struct urb*			irq_urb;
+	int				open;
+	dma_addr_t			in_dma;
+	unsigned char*			in_buffer;
+
+	/* variables used to parse messages from remote. */
+	struct bit_tester		data;
+	int				stage;
+	int				toggle;
+};
+
+/*
+ * Table that maps the 31 possible keycodes to input keys.
+ * Currently there are 15 and 17 button models so RESERVED codes
+ * are blank areas in the mapping.
+ */
+static const int keyspan_key_table[] = {
+	KEY_RESERVED,		/* 0 is just a place holder. */
+	KEY_RESERVED,
+	KEY_STOP,
+	KEY_PLAYCD,
+	KEY_RESERVED,
+	KEY_PREVIOUSSONG,
+	KEY_REWIND,
+	KEY_FORWARD,
+	KEY_NEXTSONG,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_PAUSE,
+	KEY_VOLUMEUP,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_VOLUMEDOWN,
+	KEY_RESERVED,
+	KEY_UP,
+	KEY_RESERVED,
+	KEY_MUTE,
+	KEY_LEFT,
+	KEY_ENTER,
+	KEY_RIGHT,
+	KEY_RESERVED,
+	KEY_RESERVED,
+	KEY_DOWN,
+	KEY_RESERVED,
+	KEY_KPASTERISK,
+	KEY_RESERVED,
+	KEY_MENU
+};
+
+static struct usb_driver keyspan_driver;
+
+/*
+ * Debug routine that prints out what we've received from the remote.
+ */
+static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
+{
+	char codes[4 * RECV_SIZE];
+	int i;
+
+	for (i = 0; i < RECV_SIZE; i++)
+		snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]);
+
+	dev_info(&dev->udev->dev, "%s\n", codes);
+}
+
+/*
+ * Routine that manages the bit_tester structure.  It makes sure that there are
+ * at least bits_needed bits loaded into the tester.
+ */
+static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
+{
+	if (dev->data.bits_left >= bits_needed)
+		return 0;
+
+	/*
+	 * Somehow we've missed the last message. The message will be repeated
+	 * though so it's not too big a deal
+	 */
+	if (dev->data.pos >= dev->data.len) {
+		dev_dbg(&dev->udev->dev,
+			"%s - Error ran out of data. pos: %d, len: %d\n",
+			__FUNCTION__, dev->data.pos, dev->data.len);
+		return -1;
+	}
+
+	/* Load as much as we can into the tester. */
+	while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
+	       (dev->data.pos < dev->data.len)) {
+		dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
+		dev->data.bits_left += 8;
+	}
+
+	return 0;
+}
+
+/*
+ * Routine that handles all the logic needed to parse out the message from the remote.
+ */
+static void keyspan_check_data(struct usb_keyspan *remote)
+{
+	int i;
+	int found = 0;
+	struct keyspan_message message;
+
+	switch(remote->stage) {
+	case 0:
+		/*
+		 * In stage 0 we want to find the start of a message.  The remote sends a 0xFF as filler.
+		 * So the first byte that isn't a FF should be the start of a new message.
+		 */
+		for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
+
+		if (i < RECV_SIZE) {
+			memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
+			remote->data.len = RECV_SIZE;
+			remote->data.pos = 0;
+			remote->data.tester = 0;
+			remote->data.bits_left = 0;
+			remote->stage = 1;
+		}
+		break;
+
+	case 1:
+		/*
+		 * Stage 1 we should have 16 bytes and should be able to detect a
+		 * SYNC.  The SYNC is 14 bits, 7 0's and then 7 1's.
+		 */
+		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+		remote->data.len += RECV_SIZE;
+
+		found = 0;
+		while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
+			for (i = 0; i < 8; ++i) {
+				if (keyspan_load_tester(remote, 14) != 0) {
+					remote->stage = 0;
+					return;
+				}
+
+				if ((remote->data.tester & SYNC_MASK) == SYNC) {
+					remote->data.tester = remote->data.tester >> 14;
+					remote->data.bits_left -= 14;
+					found = 1;
+					break;
+				} else {
+					remote->data.tester = remote->data.tester >> 1;
+					--remote->data.bits_left;
+				}
+			}
+		}
+
+		if (!found) {
+			remote->stage = 0;
+			remote->data.len = 0;
+		} else {
+			remote->stage = 2;
+		}
+		break;
+
+	case 2:
+		/*
+		 * Stage 2 we should have 24 bytes which will be enough for a full
+		 * message.  We need to parse out the system code, button code,
+		 * toggle code, and stop.
+		 */
+		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+		remote->data.len += RECV_SIZE;
+
+		message.system = 0;
+		for (i = 0; i < 9; i++) {
+			keyspan_load_tester(remote, 6);
+
+			if ((remote->data.tester & ZERO_MASK) == ZERO) {
+				message.system = message.system << 1;
+				remote->data.tester = remote->data.tester >> 5;
+				remote->data.bits_left -= 5;
+			} else if ((remote->data.tester & ONE_MASK) == ONE) {
+				message.system = (message.system << 1) + 1;
+				remote->data.tester = remote->data.tester >> 6;
+				remote->data.bits_left -= 6;
+			} else {
+				err("%s - Unknown sequence found in system data.\n", __FUNCTION__);
+				remote->stage = 0;
+				return;
+			}
+		}
+
+		message.button = 0;
+		for (i = 0; i < 5; i++) {
+			keyspan_load_tester(remote, 6);
+
+			if ((remote->data.tester & ZERO_MASK) == ZERO) {
+				message.button = message.button << 1;
+				remote->data.tester = remote->data.tester >> 5;
+				remote->data.bits_left -= 5;
+			} else if ((remote->data.tester & ONE_MASK) == ONE) {
+				message.button = (message.button << 1) + 1;
+				remote->data.tester = remote->data.tester >> 6;
+				remote->data.bits_left -= 6;
+			} else {
+				err("%s - Unknown sequence found in button data.\n", __FUNCTION__);
+				remote->stage = 0;
+				return;
+			}
+		}
+
+		keyspan_load_tester(remote, 6);
+		if ((remote->data.tester & ZERO_MASK) == ZERO) {
+			message.toggle = 0;
+			remote->data.tester = remote->data.tester >> 5;
+			remote->data.bits_left -= 5;
+		} else if ((remote->data.tester & ONE_MASK) == ONE) {
+			message.toggle = 1;
+			remote->data.tester = remote->data.tester >> 6;
+			remote->data.bits_left -= 6;
+		} else {
+			err("%s - Error in message, invalid toggle.\n", __FUNCTION__);
+			remote->stage = 0;
+			return;
+		}
+
+		keyspan_load_tester(remote, 5);
+		if ((remote->data.tester & STOP_MASK) == STOP) {
+			remote->data.tester = remote->data.tester >> 5;
+			remote->data.bits_left -= 5;
+		} else {
+			err("Bad message recieved, no stop bit found.\n");
+		}
+
+		dev_dbg(&remote->udev->dev,
+			"%s found valid message: system: %d, button: %d, toggle: %d\n",
+			__FUNCTION__, message.system, message.button, message.toggle);
+
+		if (message.toggle != remote->toggle) {
+			input_report_key(remote->input, keyspan_key_table[message.button], 1);
+			input_report_key(remote->input, keyspan_key_table[message.button], 0);
+			input_sync(remote->input);
+			remote->toggle = message.toggle;
+		}
+
+		remote->stage = 0;
+		break;
+	}
+}
+
+/*
+ * Routine for sending all the initialization messages to the remote.
+ */
+static int keyspan_setup(struct usb_device* dev)
+{
+	int retval = 0;
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
+			__FUNCTION__, retval);
+		return(retval);
+	}
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
+			__FUNCTION__, retval);
+		return(retval);
+	}
+
+	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+				 0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
+	if (retval) {
+		dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
+			__FUNCTION__, retval);
+		return(retval);
+	}
+
+	dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__);
+	return(retval);
+}
+
+/*
+ * Routine used to handle a new message that has come in.
+ */
+static void keyspan_irq_recv(struct urb *urb)
+{
+	struct usb_keyspan *dev = urb->context;
+	int retval;
+
+	/* Check our status in case we need to bail out early. */
+	switch (urb->status) {
+	case 0:
+		break;
+
+	/* Device went away so don't keep trying to read from it. */
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+
+	default:
+		goto resubmit;
+		break;
+	}
+
+	if (debug)
+		keyspan_print(dev);
+
+	keyspan_check_data(dev);
+
+resubmit:
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval);
+}
+
+static int keyspan_open(struct input_dev *dev)
+{
+	struct usb_keyspan *remote = input_get_drvdata(dev);
+
+	remote->irq_urb->dev = remote->udev;
+	if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void keyspan_close(struct input_dev *dev)
+{
+	struct usb_keyspan *remote = input_get_drvdata(dev);
+
+	usb_kill_urb(remote->irq_urb);
+}
+
+static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
+{
+
+	struct usb_endpoint_descriptor *endpoint;
+	int i;
+
+	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+		endpoint = &iface->endpoint[i].desc;
+
+		if (usb_endpoint_is_int_in(endpoint)) {
+			/* we found our interrupt in endpoint */
+			return endpoint;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * Routine that sets up the driver to handle a specific USB device detected on the bus.
+ */
+static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_keyspan *remote;
+	struct input_dev *input_dev;
+	int i, error;
+
+	endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
+	if (!endpoint)
+		return -ENODEV;
+
+	remote = kzalloc(sizeof(*remote), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!remote || !input_dev) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	remote->udev = udev;
+	remote->input = input_dev;
+	remote->interface = interface;
+	remote->in_endpoint = endpoint;
+	remote->toggle = -1;	/* Set to -1 so we will always not match the toggle from the first remote message. */
+
+	remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
+	if (!remote->in_buffer) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!remote->irq_urb) {
+		error = -ENOMEM;
+		goto fail2;
+	}
+
+	error = keyspan_setup(udev);
+	if (error) {
+		error = -ENODEV;
+		goto fail3;
+	}
+
+	if (udev->manufacturer)
+		strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
+
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(remote->name, " ", sizeof(remote->name));
+		strlcat(remote->name, udev->product, sizeof(remote->name));
+	}
+
+	if (!strlen(remote->name))
+		snprintf(remote->name, sizeof(remote->name),
+			 "USB Keyspan Remote %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	usb_make_path(udev, remote->phys, sizeof(remote->phys));
+	strlcat(remote->phys, "/input0", sizeof(remote->phys));
+
+	input_dev->name = remote->name;
+	input_dev->phys = remote->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &interface->dev;
+
+	input_dev->evbit[0] = BIT(EV_KEY);		/* We will only report KEY events. */
+	for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
+		if (keyspan_key_table[i] != KEY_RESERVED)
+			set_bit(keyspan_key_table[i], input_dev->keybit);
+
+	input_set_drvdata(input_dev, remote);
+
+	input_dev->open = keyspan_open;
+	input_dev->close = keyspan_close;
+
+	/*
+	 * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
+	 */
+	usb_fill_int_urb(remote->irq_urb,
+			 remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
+			 remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
+			 remote->in_endpoint->bInterval);
+	remote->irq_urb->transfer_dma = remote->in_dma;
+	remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* we can register the device now, as it is ready */
+	error = input_register_device(remote->input);
+	if (error)
+		goto fail3;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, remote);
+
+	return 0;
+
+ fail3:	usb_free_urb(remote->irq_urb);
+ fail2:	usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+ fail1:	kfree(remote);
+	input_free_device(input_dev);
+
+	return error;
+}
+
+/*
+ * Routine called when a device is disconnected from the USB.
+ */
+static void keyspan_disconnect(struct usb_interface *interface)
+{
+	struct usb_keyspan *remote;
+
+	remote = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (remote) {	/* We have a valid driver structure so clean up everything we allocated. */
+		input_unregister_device(remote->input);
+		usb_kill_urb(remote->irq_urb);
+		usb_free_urb(remote->irq_urb);
+		usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+		kfree(remote);
+	}
+}
+
+/*
+ * Standard driver set up sections
+ */
+static struct usb_driver keyspan_driver =
+{
+	.name =		"keyspan_remote",
+	.probe =	keyspan_probe,
+	.disconnect =	keyspan_disconnect,
+	.id_table =	keyspan_table
+};
+
+static int __init usb_keyspan_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&keyspan_driver);
+	if (result)
+		err("usb_register failed. Error number %d\n", result);
+
+	return result;
+}
+
+static void __exit usb_keyspan_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&keyspan_driver);
+}
+
+module_init(usb_keyspan_init);
+module_exit(usb_keyspan_exit);
+
+MODULE_DEVICE_TABLE(usb, keyspan_table);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 8d6c383..e9f26e7 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -63,7 +63,7 @@ static int __devinit m68kspkr_probe(stru
 	input_dev->id.vendor  = 0x001f;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &dev->dev;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->evbit[0] = BIT(EV_SND);
 	input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/input/misc/map_to_7segment.h b/drivers/input/misc/map_to_7segment.h
new file mode 100644
index 0000000..a424094
--- /dev/null
+++ b/drivers/input/misc/map_to_7segment.h
@@ -0,0 +1,189 @@
+/*
+ * drivers/usb/input/map_to_7segment.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
+ */
+
+#ifndef MAP_TO_7SEGMENT_H
+#define MAP_TO_7SEGMENT_H
+
+/* This file provides translation primitives and tables for the conversion
+ * of (ASCII) characters to a 7-segments notation.
+ *
+ * The 7 segment's wikipedia notation below is used as standard.
+ * See: http://en.wikipedia.org/wiki/Seven_segment_display
+ *
+ * Notation:	+-a-+
+ *		f   b
+ *		+-g-+
+ *		e   c
+ *		+-d-+
+ *
+ * Usage:
+ *
+ *   Register a map variable, and fill it with a character set:
+ * 	static SEG7_DEFAULT_MAP(map_seg7);
+ *
+ *
+ *   Then use for conversion:
+ *	seg7 = map_to_seg7(&map_seg7, some_char);
+ *	...
+ *
+ * In device drivers it is recommended, if required, to make the char map
+ * accessible via the sysfs interface using the following scheme:
+ *
+ * static ssize_t show_map(struct device *dev, char *buf) {
+ *	memcpy(buf, &map_seg7, sizeof(map_seg7));
+ *	return sizeof(map_seg7);
+ * }
+ * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
+ *	if(cnt != sizeof(map_seg7))
+ *		return -EINVAL;
+ *	memcpy(&map_seg7, buf, cnt);
+ *	return cnt;
+ * }
+ * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
+ *
+ * History:
+ * 2005-05-31	RFC linux-kernel@vger.kernel.org
+ */
+#include <linux/errno.h>
+
+
+#define BIT_SEG7_A		0
+#define BIT_SEG7_B		1
+#define BIT_SEG7_C		2
+#define BIT_SEG7_D		3
+#define BIT_SEG7_E		4
+#define BIT_SEG7_F		5
+#define BIT_SEG7_G		6
+#define BIT_SEG7_RESERVED	7
+
+struct seg7_conversion_map {
+	unsigned char	table[128];
+};
+
+static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
+{
+	return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
+}
+
+#define SEG7_CONVERSION_MAP(_name, _map)	\
+	struct seg7_conversion_map _name = { .table = { _map } }
+
+/*
+ * It is recommended to use a facility that allows user space to redefine
+ * custom character sets for LCD devices. Please use a sysfs interface
+ * as described above.
+ */
+#define MAP_TO_SEG7_SYSFS_FILE	"map_seg7"
+
+/*******************************************************************************
+ * ASCII conversion table
+ ******************************************************************************/
+
+#define _SEG7(l,a,b,c,d,e,f,g)	\
+      (	a<<BIT_SEG7_A |	b<<BIT_SEG7_B |	c<<BIT_SEG7_C |	d<<BIT_SEG7_D |	\
+	e<<BIT_SEG7_E |	f<<BIT_SEG7_F |	g<<BIT_SEG7_G )
+
+#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+#define _MAP_33_47_ASCII_SEG7_SYMBOL		\
+ _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
+ _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
+ _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
+ _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
+ _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
+
+#define _MAP_48_57_ASCII_SEG7_NUMERIC		\
+ _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
+ _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
+ _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
+ _SEG7('9',1,1,1,1,0,1,1),
+
+#define _MAP_58_64_ASCII_SEG7_SYMBOL		\
+ _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
+ _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
+ _SEG7('@',1,1,0,1,1,1,1),
+
+#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
+ _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
+ _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
+ _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_91_96_ASCII_SEG7_SYMBOL		\
+ _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
+ _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
+
+#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+ _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
+ _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
+ _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
+ _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
+ _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
+ _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
+ _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
+ _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
+ _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
+
+#define _MAP_123_126_ASCII_SEG7_SYMBOL		\
+ _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
+ _SEG7('~',1,0,0,0,0,0,0),
+
+/* Maps */
+
+/* This set tries to map as close as possible to the visible characteristics
+ * of the ASCII symbol, lowercase and uppercase letters may differ in
+ * presentation on the display.
+ */
+#define MAP_ASCII7SEG_ALPHANUM			\
+	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	_MAP_33_47_ASCII_SEG7_SYMBOL		\
+	_MAP_48_57_ASCII_SEG7_NUMERIC		\
+	_MAP_58_64_ASCII_SEG7_SYMBOL		\
+	_MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
+	_MAP_91_96_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_123_126_ASCII_SEG7_SYMBOL
+
+/* This set tries to map as close as possible to the symbolic characteristics
+ * of the ASCII character for maximum discrimination.
+ * For now this means all alpha chars are in lower case representations.
+ * (This for example facilitates the use of hex numbers with uppercase input.)
+ */
+#define MAP_ASCII7SEG_ALPHANUM_LC			\
+	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
+	_MAP_33_47_ASCII_SEG7_SYMBOL		\
+	_MAP_48_57_ASCII_SEG7_NUMERIC		\
+	_MAP_58_64_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_91_96_ASCII_SEG7_SYMBOL		\
+	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
+	_MAP_123_126_ASCII_SEG7_SYMBOL
+
+#define SEG7_DEFAULT_MAP(_name)		\
+	SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
+
+#endif	/* MAP_TO_7SEGMENT_H */
+
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index afd3221..31989dc 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -78,7 +78,7 @@ static int __devinit pcspkr_probe(struct
 	pcspkr_dev->id.vendor = 0x001f;
 	pcspkr_dev->id.product = 0x0001;
 	pcspkr_dev->id.version = 0x0100;
-	pcspkr_dev->cdev.dev = &dev->dev;
+	pcspkr_dev->dev.parent = &dev->dev;
 
 	pcspkr_dev->evbit[0] = BIT(EV_SND);
 	pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
new file mode 100644
index 0000000..448a470
--- /dev/null
+++ b/drivers/input/misc/powermate.c
@@ -0,0 +1,463 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a anodised aluminium knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 94 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it. Griffin say that it loses a
+ * pulse or two on a direction change; the granularity is so fine that I never
+ * noticed this in practice.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ * Some userspace tools are available on the web: http://sowerbutts.com/powermate/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/usb/input.h>
+
+#define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW	0x0410	/* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD	0x04AA	/* Griffin soundKnob */
+
+#define CONTOUR_VENDOR		0x05f3	/* Contour Design, Inc. */
+#define CONTOUR_JOG		0x0240	/* Jog and Shuttle */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+/* at least two versions of the hardware exist, with differing payload
+   sizes. the first three bytes always contain the "interesting" data in
+   the relevant format. */
+#define POWERMATE_PAYLOAD_SIZE_MAX 6
+#define POWERMATE_PAYLOAD_SIZE_MIN 3
+struct powermate_device {
+	signed char *data;
+	dma_addr_t data_dma;
+	struct urb *irq, *config;
+	struct usb_ctrlrequest *configcr;
+	dma_addr_t configcr_dma;
+	struct usb_device *udev;
+	struct input_dev *input;
+	spinlock_t lock;
+	int static_brightness;
+	int pulse_speed;
+	int pulse_table;
+	int pulse_asleep;
+	int pulse_awake;
+	int requires_update; // physical settings which are out of sync
+	char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+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 powermate_device *pm = urb->context;
+	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;
+	}
+
+	/* handle updates to device state */
+	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);
+
+exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, retval);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+	if (pm->requires_update == 0)
+		return; /* no updates are required */
+	if (pm->config->status == -EINPROGRESS)
+		return; /* an update is already in progress; it'll issue this update when it completes */
+
+	if (pm->requires_update & UPDATE_PULSE_ASLEEP){
+		pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+		pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+	}else if (pm->requires_update & UPDATE_PULSE_AWAKE){
+		pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE );
+		pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+	}else if (pm->requires_update & UPDATE_PULSE_MODE){
+		int op, arg;
+		/* the powermate takes an operation and an argument for its pulse algorithm.
+		   the operation can be:
+		   0: divide the speed
+		   1: pulse at normal speed
+		   2: multiply the speed
+		   the argument only has an effect for operations 0 and 2, and ranges between
+		   1 (least effect) to 255 (maximum effect).
+
+		   thus, several states are equivalent and are coalesced into one state.
+
+		   we map this onto a range from 0 to 510, with:
+		   0 -- 254    -- use divide (0 = slowest)
+		   255         -- use normal speed
+		   256 -- 510  -- use multiple (510 = fastest).
+
+		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+		*/
+		if (pm->pulse_speed < 255) {
+			op = 0;                   // divide
+			arg = 255 - pm->pulse_speed;
+		} else if (pm->pulse_speed > 255) {
+			op = 2;                   // multiply
+			arg = pm->pulse_speed - 255;
+		} else {
+			op = 1;                   // normal speed
+			arg = 0;                  // can be any value
+		}
+		pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+		pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op );
+		pm->requires_update &= ~UPDATE_PULSE_MODE;
+	} else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) {
+		pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+		pm->configcr->wIndex = cpu_to_le16( pm->static_brightness );
+		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+	} else {
+		printk(KERN_ERR "powermate: unknown update required");
+		pm->requires_update = 0; /* fudge the bug */
+		return;
+	}
+
+/*	printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */
+
+	pm->configcr->bRequestType = 0x41; /* vendor request */
+	pm->configcr->bRequest = 0x01;
+	pm->configcr->wLength = 0;
+
+	usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
+			     (void *) pm->configcr, NULL, 0,
+			     powermate_config_complete, pm);
+	pm->config->setup_dma = pm->configcr_dma;
+	pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
+
+	if (usb_submit_urb(pm->config, GFP_ATOMIC))
+		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+	unsigned long flags;
+
+	if (urb->status)
+		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+
+	spin_lock_irqsave(&pm->lock, flags);
+	powermate_sync_state(pm);
+	spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
+				int pulse_table, int pulse_asleep, int pulse_awake)
+{
+	unsigned long flags;
+
+	if (pulse_speed < 0)
+		pulse_speed = 0;
+	if (pulse_table < 0)
+		pulse_table = 0;
+	if (pulse_speed > 510)
+		pulse_speed = 510;
+	if (pulse_table > 2)
+		pulse_table = 2;
+
+	pulse_asleep = !!pulse_asleep;
+	pulse_awake = !!pulse_awake;
+
+
+	spin_lock_irqsave(&pm->lock, flags);
+
+	/* mark state updates which are required */
+	if (static_brightness != pm->static_brightness) {
+		pm->static_brightness = static_brightness;
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
+	}
+	if (pulse_asleep != pm->pulse_asleep) {
+		pm->pulse_asleep = pulse_asleep;
+		pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if (pulse_awake != pm->pulse_awake) {
+		pm->pulse_awake = pulse_awake;
+		pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) {
+		pm->pulse_speed = pulse_speed;
+		pm->pulse_table = pulse_table;
+		pm->requires_update |= UPDATE_PULSE_MODE;
+	}
+
+	powermate_sync_state(pm);
+
+	spin_unlock_irqrestore(&pm->lock, flags);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+	unsigned int command = (unsigned int)_value;
+	struct powermate_device *pm = input_get_drvdata(dev);
+
+	if (type == EV_MSC && code == MSC_PULSELED){
+		/*
+		    bits  0- 7: 8 bits: LED brightness
+		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+		    bit     19: 1 bit : pulse whilst asleep?
+		    bit     20: 1 bit : pulse constantly?
+		*/
+		int static_brightness = command & 0xFF;   // bits 0-7
+		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+		int pulse_asleep = (command >> 19) & 0x1; // bit 19
+		int pulse_awake  = (command >> 20) & 0x1; // bit 20
+
+		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+	}
+
+	return 0;
+}
+
+static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+	pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+				    GFP_ATOMIC, &pm->data_dma);
+	if (!pm->data)
+		return -1;
+
+	pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
+					GFP_ATOMIC, &pm->configcr_dma);
+	if (!pm->configcr)
+		return -1;
+
+	return 0;
+}
+
+static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
+{
+	usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+			pm->data, pm->data_dma);
+	usb_buffer_free(udev, sizeof(*(pm->configcr)),
+			pm->configcr, pm->configcr_dma);
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev (intf);
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct powermate_device *pm;
+	struct input_dev *input_dev;
+	int pipe, maxp;
+	int error = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -EIO;
+
+	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+		0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		0, interface->desc.bInterfaceNumber, NULL, 0,
+		USB_CTRL_SET_TIMEOUT);
+
+	pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!pm || !input_dev)
+		goto fail1;
+
+	if (powermate_alloc_buffers(udev, pm))
+		goto fail2;
+
+	pm->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pm->irq)
+		goto fail2;
+
+	pm->config = usb_alloc_urb(0, GFP_KERNEL);
+	if (!pm->config)
+		goto fail3;
+
+	pm->udev = udev;
+	pm->input = input_dev;
+
+	usb_make_path(udev, pm->phys, sizeof(pm->phys));
+	strlcpy(pm->phys, "/input0", sizeof(pm->phys));
+
+	spin_lock_init(&pm->lock);
+
+	switch (le16_to_cpu(udev->descriptor.idProduct)) {
+	case POWERMATE_PRODUCT_NEW:
+		input_dev->name = pm_name_powermate;
+		break;
+	case POWERMATE_PRODUCT_OLD:
+		input_dev->name = pm_name_soundknob;
+		break;
+	default:
+		input_dev->name = pm_name_soundknob;
+		printk(KERN_WARNING "powermate: unknown product id %04x\n",
+		       le16_to_cpu(udev->descriptor.idProduct));
+	}
+
+	input_dev->phys = pm->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, pm);
+
+	input_dev->event = powermate_input_event;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
+	input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+	input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
+	input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
+		printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
+			POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
+		maxp = POWERMATE_PAYLOAD_SIZE_MAX;
+	}
+
+	usb_fill_int_urb(pm->irq, udev, pipe, pm->data,
+			 maxp, powermate_irq,
+			 pm, endpoint->bInterval);
+	pm->irq->transfer_dma = pm->data_dma;
+	pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* register our interrupt URB with the USB system */
+	if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
+		error = -EIO;
+		goto fail4;
+	}
+
+	error = input_register_device(pm->input);
+	if (error)
+		goto fail5;
+
+
+	/* force an update of everything */
+	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+
+	usb_set_intfdata(intf, pm);
+	return 0;
+
+ fail5:	usb_kill_urb(pm->irq);
+ fail4:	usb_free_urb(pm->config);
+ fail3:	usb_free_urb(pm->irq);
+ fail2:	powermate_free_buffers(udev, pm);
+ fail1:	input_free_device(input_dev);
+	kfree(pm);
+	return error;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_interface *intf)
+{
+	struct powermate_device *pm = usb_get_intfdata (intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (pm) {
+		pm->requires_update = 0;
+		usb_kill_urb(pm->irq);
+		input_unregister_device(pm->input);
+		usb_free_urb(pm->irq);
+		usb_free_urb(pm->config);
+		powermate_free_buffers(interface_to_usbdev(intf), pm);
+
+		kfree(pm);
+	}
+}
+
+static struct usb_device_id powermate_devices [] = {
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+	{ USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        .name =         "powermate",
+        .probe =        powermate_probe,
+        .disconnect =   powermate_disconnect,
+        .id_table =     powermate_devices,
+};
+
+static int __init powermate_init(void)
+{
+	return usb_register(&powermate_driver);
+}
+
+static void __exit powermate_cleanup(void)
+{
+	usb_deregister(&powermate_driver);
+}
+
+module_init(powermate_init);
+module_exit(powermate_cleanup);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 106c94f..e36ec1d 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -28,7 +28,7 @@ struct sparcspkr_state {
 
 static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
+	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
 	unsigned int count = 0;
 	unsigned long flags;
 
@@ -61,7 +61,7 @@ static int ebus_spkr_event(struct input_
 
 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
+	struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
 	unsigned int count = 0;
 	unsigned long flags;
 
@@ -113,7 +113,7 @@ static int __devinit sparcspkr_probe(str
 	input_dev->id.vendor = 0x001f;
 	input_dev->id.product = 0x0001;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = dev;
+	input_dev->dev.parent = dev;
 
 	input_dev->evbit[0] = BIT(EV_SND);
 	input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 4255623..a56ad4b 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -33,7 +33,6 @@ #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/input.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
@@ -41,9 +40,7 @@ #include <linux/uinput.h>
 
 static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct uinput_device	*udev;
-
-	udev = dev->private;
+	struct uinput_device	*udev = input_get_drvdata(dev);
 
 	udev->buff[udev->head].type = type;
 	udev->buff[udev->head].code = code;
@@ -136,7 +133,7 @@ static int uinput_dev_upload_effect(stru
 	request.u.upload.effect = effect;
 	request.u.upload.old = old;
 
-	retval = uinput_request_reserve_slot(dev->private, &request);
+	retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
 	if (!retval)
 		retval = uinput_request_submit(dev, &request);
 
@@ -156,7 +153,7 @@ static int uinput_dev_erase_effect(struc
 	request.code = UI_FF_ERASE;
 	request.u.effect_id = effect_id;
 
-	retval = uinput_request_reserve_slot(dev->private, &request);
+	retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
 	if (!retval)
 		retval = uinput_request_submit(dev, &request);
 
@@ -274,7 +271,7 @@ static int uinput_allocate_device(struct
 		return -ENOMEM;
 
 	udev->dev->event = uinput_dev_event;
-	udev->dev->private = udev;
+	input_set_drvdata(udev->dev, udev);
 
 	return 0;
 }
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index e1183ae..961aad7 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -50,7 +50,7 @@ #define BLUETOOTH	0x34
 MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
 MODULE_DESCRIPTION("Wistron laptop button driver");
 MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
 
 static int force; /* = 0; */
 module_param(force, bool, 0);
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(force, "Load even if co
 
 static char *keymap_name; /* = NULL; */
 module_param_named(keymap, keymap_name, charp, 0);
-MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected");
+MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
 
 static struct platform_device *wistron_device;
 
@@ -233,10 +233,20 @@ static void bios_set_state(u8 subsys, in
 struct key_entry {
 	char type;		/* See KE_* below */
 	u8 code;
-	unsigned keycode;	/* For KE_KEY */
+	union {
+		u16 keycode;		/* For KE_KEY */
+		struct {		/* For KE_SW */
+			u8 code;
+			u8 value;
+		} sw;
+	};
 };
 
-enum { KE_END, KE_KEY, KE_WIFI, KE_BLUETOOTH };
+enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
+
+#define FE_MAIL_LED 0x01
+#define FE_WIFI_LED 0x02
+#define FE_UNTESTED 0x80
 
 static const struct key_entry *keymap; /* = NULL; Current key map */
 static int have_wifi;
@@ -256,93 +266,341 @@ static int __init dmi_matched(struct dmi
 	return 1;
 }
 
-static struct key_entry keymap_empty[] = {
+static struct key_entry keymap_empty[] __initdata = {
 	{ KE_END, 0 }
 };
 
-static struct key_entry keymap_fs_amilo_pro_v2000[] = {
-	{ KE_KEY,  0x01, KEY_HELP },
-	{ KE_KEY,  0x11, KEY_PROG1 },
-	{ KE_KEY,  0x12, KEY_PROG2 },
-	{ KE_WIFI, 0x30, 0 },
-	{ KE_KEY,  0x31, KEY_MAIL },
-	{ KE_KEY,  0x36, KEY_WWW },
+static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
+	{ KE_KEY,  0x01, {KEY_HELP} },
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
 	{ KE_END,  0 }
 };
 
-static struct key_entry keymap_fujitsu_n3510[] = {
-	{ KE_KEY, 0x11, KEY_PROG1 },
-	{ KE_KEY, 0x12, KEY_PROG2 },
-	{ KE_KEY, 0x36, KEY_WWW },
-	{ KE_KEY, 0x31, KEY_MAIL },
-	{ KE_KEY, 0x71, KEY_STOPCD },
-	{ KE_KEY, 0x72, KEY_PLAYPAUSE },
-	{ KE_KEY, 0x74, KEY_REWIND },
-	{ KE_KEY, 0x78, KEY_FORWARD },
+static struct key_entry keymap_fujitsu_n3510[] __initdata = {
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x71, {KEY_STOPCD} },
+	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x74, {KEY_REWIND} },
+	{ KE_KEY, 0x78, {KEY_FORWARD} },
 	{ KE_END, 0 }
 };
 
-static struct key_entry keymap_wistron_ms2111[] = {
-	{ KE_KEY,  0x11, KEY_PROG1 },
-	{ KE_KEY,  0x12, KEY_PROG2 },
-	{ KE_KEY,  0x13, KEY_PROG3 },
-	{ KE_KEY,  0x31, KEY_MAIL },
-	{ KE_KEY,  0x36, KEY_WWW },
-	{ KE_END,  0 }
+static struct key_entry keymap_wistron_ms2111[] __initdata = {
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_KEY,  0x13, {KEY_PROG3} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
+	{ KE_END, FE_MAIL_LED }
+};
+
+static struct key_entry keymap_wistron_md40100[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
 };
 
-static struct key_entry keymap_wistron_ms2141[] = {
-	{ KE_KEY,  0x11, KEY_PROG1 },
-	{ KE_KEY,  0x12, KEY_PROG2 },
-	{ KE_WIFI, 0x30, 0 },
-	{ KE_KEY,  0x22, KEY_REWIND },
-	{ KE_KEY,  0x23, KEY_FORWARD },
-	{ KE_KEY,  0x24, KEY_PLAYPAUSE },
-	{ KE_KEY,  0x25, KEY_STOPCD },
-	{ KE_KEY,  0x31, KEY_MAIL },
-	{ KE_KEY,  0x36, KEY_WWW },
+static struct key_entry keymap_wistron_ms2141[] __initdata = {
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x22, {KEY_REWIND} },
+	{ KE_KEY,  0x23, {KEY_FORWARD} },
+	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY,  0x25, {KEY_STOPCD} },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
 	{ KE_END,  0 }
 };
 
-static struct key_entry keymap_acer_aspire_1500[] = {
-	{ KE_KEY, 0x11, KEY_PROG1 },
-	{ KE_KEY, 0x12, KEY_PROG2 },
-	{ KE_WIFI, 0x30, 0 },
-	{ KE_KEY, 0x31, KEY_MAIL },
-	{ KE_KEY, 0x36, KEY_WWW },
-	{ KE_BLUETOOTH, 0x44, 0 },
-	{ KE_END, 0 }
+static struct key_entry keymap_acer_aspire_1500[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_UNTESTED }
 };
 
-static struct key_entry keymap_acer_travelmate_240[] = {
-	{ KE_KEY, 0x31, KEY_MAIL },
-	{ KE_KEY, 0x36, KEY_WWW },
-	{ KE_KEY, 0x11, KEY_PROG1 },
-	{ KE_KEY, 0x12, KEY_PROG2 },
-	{ KE_BLUETOOTH, 0x44, 0 },
-	{ KE_WIFI, 0x30, 0 },
-	{ KE_END, 0 }
+static struct key_entry keymap_acer_aspire_1600[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* 3020 has been tested */
+static struct key_entry keymap_acer_aspire_5020[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x6d, {KEY_POWER} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_110[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_300[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
 };
 
-static struct key_entry keymap_aopen_1559as[] = {
-	{ KE_KEY,  0x01, KEY_HELP },
-	{ KE_KEY,  0x06, KEY_PROG3 },
-	{ KE_KEY,  0x11, KEY_PROG1 },
-	{ KE_KEY,  0x12, KEY_PROG2 },
-	{ KE_WIFI, 0x30, 0 },
-	{ KE_KEY,  0x31, KEY_MAIL },
-	{ KE_KEY,  0x36, KEY_WWW },
+static struct key_entry keymap_acer_travelmate_380[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* unusual map */
+static struct key_entry keymap_acer_travelmate_220[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_MAIL} },
+	{ KE_KEY, 0x12, {KEY_WWW} },
+	{ KE_KEY, 0x13, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_PROG1} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_230[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_240[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_350[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_MAIL} },
+	{ KE_KEY, 0x14, {KEY_PROG3} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_360[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_MAIL} },
+	{ KE_KEY, 0x14, {KEY_PROG3} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
+};
+
+/* Wifi subsystem only activates the led. Therefore we need to pass
+ * wifi event as a normal key, then userspace can really change the wifi state.
+ * TODO we need to export led state to userspace (wifi and mail) */
+static struct key_entry keymap_acer_travelmate_610[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x14, {KEY_MAIL} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED }
+};
+
+static struct key_entry keymap_acer_travelmate_630[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_aopen_1559as[] __initdata = {
+	{ KE_KEY,  0x01, {KEY_HELP} },
+	{ KE_KEY,  0x06, {KEY_PROG3} },
+	{ KE_KEY,  0x11, {KEY_PROG1} },
+	{ KE_KEY,  0x12, {KEY_PROG2} },
+	{ KE_WIFI, 0x30 },
+	{ KE_KEY,  0x31, {KEY_MAIL} },
+	{ KE_KEY,  0x36, {KEY_WWW} },
 	{ KE_END,  0 },
 };
 
-static struct key_entry keymap_fs_amilo_d88x0[] = {
-	{ KE_KEY, 0x01, KEY_HELP },
-	{ KE_KEY, 0x08, KEY_MUTE },
-	{ KE_KEY, 0x31, KEY_MAIL },
-	{ KE_KEY, 0x36, KEY_WWW },
-	{ KE_KEY, 0x11, KEY_PROG1 },
-	{ KE_KEY, 0x12, KEY_PROG2 },
-	{ KE_KEY, 0x13, KEY_PROG3 },
+static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md2900[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md96500[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x22, {KEY_REWIND} },
+	{ KE_KEY, 0x23, {KEY_FORWARD} },
+	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x25, {KEY_STOPCD} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
+	{ KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_generic[] __initdata = {
+	{ KE_KEY, 0x01, {KEY_HELP} },
+	{ KE_KEY, 0x02, {KEY_CONFIG} },
+	{ KE_KEY, 0x03, {KEY_POWER} },
+	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x08, {KEY_MUTE} },
+	{ KE_KEY, 0x11, {KEY_PROG1} },
+	{ KE_KEY, 0x12, {KEY_PROG2} },
+	{ KE_KEY, 0x13, {KEY_PROG3} },
+	{ KE_KEY, 0x14, {KEY_MAIL} },
+	{ KE_KEY, 0x15, {KEY_WWW} },
+	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
+	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+	{ KE_KEY, 0x22, {KEY_REWIND} },
+	{ KE_KEY, 0x23, {KEY_FORWARD} },
+	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x25, {KEY_STOPCD} },
+	{ KE_KEY, 0x31, {KEY_MAIL} },
+	{ KE_KEY, 0x36, {KEY_WWW} },
+	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+	{ KE_KEY, 0x40, {KEY_WLAN} },
+	{ KE_KEY, 0x49, {KEY_CONFIG} },
+	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+	{ KE_KEY, 0x6a, {KEY_CONFIG} },
+	{ KE_KEY, 0x6d, {KEY_POWER} },
+	{ KE_KEY, 0x71, {KEY_STOPCD} },
+	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+	{ KE_KEY, 0x74, {KEY_REWIND} },
+	{ KE_KEY, 0x78, {KEY_FORWARD} },
+	{ KE_WIFI, 0x30 },
+	{ KE_BLUETOOTH, 0x44 },
 	{ KE_END, 0 }
 };
 
@@ -390,6 +648,133 @@ static struct dmi_system_id dmi_ids[] __
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Acer Aspire 1600",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
+		},
+		.driver_data = keymap_acer_aspire_1600
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer Aspire 3020",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer Aspire 5020",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 2100",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
+		},
+		.driver_data = keymap_acer_aspire_5020
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 2410",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
+		},
+		.driver_data = keymap_acer_travelmate_2410
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate C300",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
+		},
+		.driver_data = keymap_acer_travelmate_300
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate C100",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
+		},
+		.driver_data = keymap_acer_travelmate_300
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate C110",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
+		},
+		.driver_data = keymap_acer_travelmate_110
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 380",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
+		},
+		.driver_data = keymap_acer_travelmate_380
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 370",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
+		},
+		.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 220",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
+		},
+		.driver_data = keymap_acer_travelmate_220
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 260",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
+		},
+		.driver_data = keymap_acer_travelmate_220
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 230",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
+			/* acerhk looks for "TravelMate F4..." ?! */
+		},
+		.driver_data = keymap_acer_travelmate_230
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 280",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
+		},
+		.driver_data = keymap_acer_travelmate_230
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "Acer TravelMate 240",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -399,6 +784,15 @@ static struct dmi_system_id dmi_ids[] __
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Acer TravelMate 250",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
+		},
+		.driver_data = keymap_acer_travelmate_240
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "Acer TravelMate 2424NWXCi",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -408,6 +802,51 @@ static struct dmi_system_id dmi_ids[] __
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Acer TravelMate 350",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
+		},
+		.driver_data = keymap_acer_travelmate_350
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 360",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+		},
+		.driver_data = keymap_acer_travelmate_360
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 610",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
+		},
+		.driver_data = keymap_acer_travelmate_610
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 620",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
+		},
+		.driver_data = keymap_acer_travelmate_630
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Acer TravelMate 630",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
+		},
+		.driver_data = keymap_acer_travelmate_630
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "AOpen 1559AS",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
@@ -426,6 +865,51 @@ static struct dmi_system_id dmi_ids[] __
 	},
 	{
 		.callback = dmi_matched,
+		.ident = "Medion MD 40100",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
+		},
+		.driver_data = keymap_wistron_md40100
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Medion MD 2900",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
+		},
+		.driver_data = keymap_wistron_md2900
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Medion MD 96500",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
+		},
+		.driver_data = keymap_wistron_md96500
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Medion MD 95400",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
+		},
+		.driver_data = keymap_wistron_md96500
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Fujitsu Siemens Amilo D7820",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
+			DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
+		},
+		.driver_data = keymap_fs_amilo_d88x0
+	},
+	{
+		.callback = dmi_matched,
 		.ident = "Fujitsu Siemens Amilo D88x0",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
@@ -436,17 +920,39 @@ static struct dmi_system_id dmi_ids[] __
 	{ NULL, }
 };
 
+/* Copy the good keymap, as the original ones are free'd */
+static int __init copy_keymap(void)
+{
+	const struct key_entry *key;
+	struct key_entry *new_keymap;
+	unsigned int length = 1;
+
+	for (key = keymap; key->type != KE_END; key++)
+		length++;
+
+	new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL);
+	if (!new_keymap)
+		return -ENOMEM;
+
+	memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
+	keymap = new_keymap;
+
+	return 0;
+}
+
 static int __init select_keymap(void)
 {
+	dmi_check_system(dmi_ids);
 	if (keymap_name != NULL) {
 		if (strcmp (keymap_name, "1557/MS2141") == 0)
 			keymap = keymap_wistron_ms2141;
+		else if (strcmp (keymap_name, "generic") == 0)
+			keymap = keymap_wistron_generic;
 		else {
 			printk(KERN_ERR "wistron_btns: Keymap unknown\n");
 			return -EINVAL;
 		}
 	}
-	dmi_check_system(dmi_ids);
 	if (keymap == NULL) {
 		if (!force) {
 			printk(KERN_ERR "wistron_btns: System unknown\n");
@@ -454,7 +960,8 @@ static int __init select_keymap(void)
 		}
 		keymap = keymap_empty;
 	}
-	return 0;
+
+	return copy_keymap();
 }
 
  /* Input layer interface */
@@ -476,12 +983,28 @@ static int __devinit setup_input_dev(voi
 	input_dev->cdev.dev = &wistron_device->dev;
 
 	for (key = keymap; key->type != KE_END; key++) {
-		if (key->type == KE_KEY) {
-			input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
-			set_bit(key->keycode, input_dev->keybit);
+		switch (key->type) {
+			case KE_KEY:
+				set_bit(EV_KEY, input_dev->evbit);
+				set_bit(key->keycode, input_dev->keybit);
+				break;
+
+			case KE_SW:
+				set_bit(EV_SW, input_dev->evbit);
+				set_bit(key->sw.code, input_dev->swbit);
+				break;
+
+			default:
+				;
 		}
 	}
 
+	/* reads information flags on KE_END */
+	if (key->code & FE_UNTESTED)
+		printk(KERN_WARNING "Untested laptop multimedia keys, "
+			"please report success or failure to eric.piel"
+			"@tremplin-utc.net\n");
+
 	error = input_register_device(input_dev);
 	if (error) {
 		input_free_device(input_dev);
@@ -499,6 +1022,12 @@ static void report_key(unsigned keycode)
 	input_sync(input_dev);
 }
 
+static void report_switch(unsigned code, int value)
+{
+	input_report_switch(input_dev, code, value);
+	input_sync(input_dev);
+}
+
  /* Driver core */
 
 static int wifi_enabled;
@@ -519,6 +1048,10 @@ static void handle_key(u8 code)
 				report_key(key->keycode);
 				break;
 
+			case KE_SW:
+				report_switch(key->sw.code, key->sw.value);
+				break;
+
 			case KE_WIFI:
 				if (have_wifi) {
 					wifi_enabled = !wifi_enabled;
@@ -534,6 +1067,7 @@ static void handle_key(u8 code)
 				break;
 
 			case KE_END:
+				break;
 			default:
 				BUG();
 			}
@@ -690,6 +1224,7 @@ static void __exit wb_module_exit(void)
 	platform_device_unregister(wistron_device);
 	platform_driver_unregister(&wistron_driver);
 	unmap_bios();
+	kfree(keymap);
 }
 
 module_init(wb_module_init);
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
new file mode 100644
index 0000000..ab15880
--- /dev/null
+++ b/drivers/input/misc/yealink.c
@@ -0,0 +1,1004 @@
+/*
+ * drivers/usb/input/yealink.c
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
+ */
+/*
+ * Description:
+ *   Driver for the USB-P1K voip usb phone.
+ *   This device is produced by Yealink Network Technology Co Ltd
+ *   but may be branded under several names:
+ *	- Yealink usb-p1k
+ *	- Tiptel 115
+ *	- ...
+ *
+ * This driver is based on:
+ *   - the usbb2k-api	http://savannah.nongnu.org/projects/usbb2k-api/
+ *   - information from	http://memeteau.free.fr/usbb2k
+ *   - the xpad-driver	drivers/input/joystick/xpad.c
+ *
+ * Thanks to:
+ *   - Olivier Vandorpe, for providing the usbb2k-api.
+ *   - Martin Diehl, for spotting my memory allocation bug.
+ *
+ * History:
+ *   20050527 henk	First version, functional keyboard. Keyboard events
+ *			will pop-up on the ../input/eventX bus.
+ *   20050531 henk	Added led, LCD, dialtone and sysfs interface.
+ *   20050610 henk	Cleanups, make it ready for public consumption.
+ *   20050630 henk	Cleanups, fixes in response to comments.
+ *   20050701 henk	sysfs write serialisation, fix potential unload races
+ *   20050801 henk	Added ringtone, restructure USB
+ *   20050816 henk	Merge 2.6.13-rc6
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/usb/input.h>
+
+#include "map_to_7segment.h"
+#include "yealink.h"
+
+#define DRIVER_VERSION "yld-20051230"
+#define DRIVER_AUTHOR "Henk Vergonet"
+#define DRIVER_DESC "Yealink phone driver"
+
+#define YEALINK_POLLING_FREQUENCY	10	/* in [Hz] */
+
+struct yld_status {
+	u8	lcd[24];
+	u8	led;
+	u8	dialtone;
+	u8	ringtone;
+	u8	keynum;
+} __attribute__ ((packed));
+
+/*
+ * Register the LCD segment and icon map
+ */
+#define _LOC(k,l)	{ .a = (k), .m = (l) }
+#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)	\
+	{ .type	= (t),							\
+	  .u = { .s = {	_LOC(a, am), _LOC(b, bm), _LOC(c, cm),		\
+		        _LOC(d, dm), _LOC(e, em), _LOC(g, gm),		\
+			_LOC(f, fm) } } }
+#define _PIC(t, h, hm, n)						\
+	{ .type	= (t),							\
+ 	  .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
+
+static const struct lcd_segment_map {
+	char	type;
+	union {
+		struct pictogram_map {
+			u8	a,m;
+			char	name[10];
+		}	p;
+		struct segment_map {
+			u8	a,m;
+		} s[7];
+	} u;
+} lcdMap[] = {
+#include "yealink.h"
+};
+
+struct yealink_dev {
+	struct input_dev *idev;		/* input device */
+	struct usb_device *udev;	/* usb device */
+
+	/* irq input channel */
+	struct yld_ctl_packet	*irq_data;
+	dma_addr_t		irq_dma;
+	struct urb		*urb_irq;
+
+	/* control output channel */
+	struct yld_ctl_packet	*ctl_data;
+	dma_addr_t		ctl_dma;
+	struct usb_ctrlrequest	*ctl_req;
+	dma_addr_t		ctl_req_dma;
+	struct urb		*urb_ctl;
+
+	char phys[64];			/* physical device path */
+
+	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
+	int key_code;			/* last reported key	 */
+
+	int	stat_ix;
+	union {
+		struct yld_status s;
+		u8		  b[sizeof(struct yld_status)];
+	} master, copy;
+};
+
+
+/*******************************************************************************
+ * Yealink lcd interface
+ ******************************************************************************/
+
+/*
+ * Register a default 7 segment character set
+ */
+static SEG7_DEFAULT_MAP(map_seg7);
+
+ /* Display a char,
+  * char '\9' and '\n' are placeholders and do not overwrite the original text.
+  * A space will always hide an icon.
+  */
+static int setChar(struct yealink_dev *yld, int el, int chr)
+{
+	int i, a, m, val;
+
+	if (el >= ARRAY_SIZE(lcdMap))
+		return -EINVAL;
+
+	if (chr == '\t' || chr == '\n')
+	    return 0;
+
+	yld->lcdMap[el] = chr;
+
+	if (lcdMap[el].type == '.') {
+		a = lcdMap[el].u.p.a;
+		m = lcdMap[el].u.p.m;
+		if (chr != ' ')
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		return 0;
+	}
+
+	val = map_to_seg7(&map_seg7, chr);
+	for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
+		m = lcdMap[el].u.s[i].m;
+
+		if (m == 0)
+			continue;
+
+		a = lcdMap[el].u.s[i].a;
+		if (val & 1)
+			yld->master.b[a] |= m;
+		else
+			yld->master.b[a] &= ~m;
+		val = val >> 1;
+	}
+	return 0;
+};
+
+/*******************************************************************************
+ * Yealink key interface
+ ******************************************************************************/
+
+/* Map device buttons to internal key events.
+ *
+ * USB-P1K button layout:
+ *
+ *             up
+ *       IN           OUT
+ *            down
+ *
+ *     pickup   C    hangup
+ *       1      2      3
+ *       4      5      6
+ *       7      8      9
+ *       *      0      #
+ *
+ * The "up" and "down" keys, are symbolised by arrows on the button.
+ * The "pickup" and "hangup" keys are symbolised by a green and red phone
+ * on the button.
+ */
+static int map_p1k_to_key(int scancode)
+{
+	switch(scancode) {		/* phone key:	*/
+	case 0x23: return KEY_LEFT;	/*   IN		*/
+	case 0x33: return KEY_UP;	/*   up		*/
+	case 0x04: return KEY_RIGHT;	/*   OUT	*/
+	case 0x24: return KEY_DOWN;	/*   down	*/
+	case 0x03: return KEY_ENTER;	/*   pickup	*/
+	case 0x14: return KEY_BACKSPACE; /*  C		*/
+	case 0x13: return KEY_ESC;	/*   hangup	*/
+	case 0x00: return KEY_1;	/*   1		*/
+	case 0x01: return KEY_2;	/*   2 		*/
+	case 0x02: return KEY_3;	/*   3		*/
+	case 0x10: return KEY_4;	/*   4		*/
+	case 0x11: return KEY_5;	/*   5		*/
+	case 0x12: return KEY_6;	/*   6		*/
+	case 0x20: return KEY_7;	/*   7		*/
+	case 0x21: return KEY_8;	/*   8		*/
+	case 0x22: return KEY_9;	/*   9		*/
+	case 0x30: return KEY_KPASTERISK; /* *		*/
+	case 0x31: return KEY_0;	/*   0		*/
+	case 0x32: return KEY_LEFTSHIFT |
+			  KEY_3 << 8;	/*   #		*/
+	}
+	return -EINVAL;
+}
+
+/* Completes a request by converting the data into events for the
+ * input subsystem.
+ *
+ * The key parameter can be cascaded: key2 << 8 | key1
+ */
+static void report_key(struct yealink_dev *yld, int key)
+{
+	struct input_dev *idev = yld->idev;
+
+	if (yld->key_code >= 0) {
+		/* old key up */
+		input_report_key(idev, yld->key_code & 0xff, 0);
+		if (yld->key_code >> 8)
+			input_report_key(idev, yld->key_code >> 8, 0);
+	}
+
+	yld->key_code = key;
+	if (key >= 0) {
+		/* new valid key */
+		input_report_key(idev, key & 0xff, 1);
+		if (key >> 8)
+			input_report_key(idev, key >> 8, 1);
+	}
+	input_sync(idev);
+}
+
+/*******************************************************************************
+ * Yealink usb communication interface
+ ******************************************************************************/
+
+static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
+{
+	u8	*buf = (u8 *)p;
+	int	i;
+	u8	sum = 0;
+
+	for(i=0; i<USB_PKT_LEN-1; i++)
+		sum -= buf[i];
+	p->sum = sum;
+	return usb_control_msg(yld->udev,
+			usb_sndctrlpipe(yld->udev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			0x200, 3,
+			p, sizeof(*p),
+			USB_CTRL_SET_TIMEOUT);
+}
+
+static u8 default_ringtone[] = {
+	0xEF,			/* volume [0-255] */
+	0xFB, 0x1E, 0x00, 0x0C,	/* 1250 [hz], 12/100 [s] */
+	0xFC, 0x18, 0x00, 0x0C,	/* 1000 [hz], 12/100 [s] */
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFB, 0x1E, 0x00, 0x0C,
+	0xFC, 0x18, 0x00, 0x0C,
+	0xFF, 0xFF, 0x01, 0x90,	/* silent, 400/100 [s] */
+	0x00, 0x00		/* end of sequence */
+};
+
+static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
+{
+	struct yld_ctl_packet *p = yld->ctl_data;
+	int	ix, len;
+
+	if (size <= 0)
+		return -EINVAL;
+
+	/* Set the ringtone volume */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_RING_VOLUME;
+	yld->ctl_data->size	= 1;
+	yld->ctl_data->data[0]	= buf[0];
+	yealink_cmd(yld, p);
+
+	buf++;
+	size--;
+
+	p->cmd = CMD_RING_NOTE;
+	ix = 0;
+	while (size != ix) {
+		len = size - ix;
+		if (len > sizeof(p->data))
+			len = sizeof(p->data);
+		p->size	  = len;
+		p->offset = cpu_to_be16(ix);
+		memcpy(p->data, &buf[ix], len);
+		yealink_cmd(yld, p);
+		ix += len;
+	}
+	return 0;
+}
+
+/* keep stat_master & stat_copy in sync.
+ */
+static int yealink_do_idle_tasks(struct yealink_dev *yld)
+{
+	u8 val;
+	int i, ix, len;
+
+	ix = yld->stat_ix;
+
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd  = CMD_KEYPRESS;
+	yld->ctl_data->size = 1;
+	yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
+
+	/* If state update pointer wraps do a KEYPRESS first. */
+	if (ix >= sizeof(yld->master)) {
+		yld->stat_ix = 0;
+		return 0;
+	}
+
+	/* find update candidates: copy != master */
+	do {
+		val = yld->master.b[ix];
+		if (val != yld->copy.b[ix])
+			goto send_update;
+	} while (++ix < sizeof(yld->master));
+
+	/* nothing todo, wait a bit and poll for a KEYPRESS */
+	yld->stat_ix = 0;
+	/* TODO how can we wait abit. ??
+	 * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
+	 */
+	return 0;
+
+send_update:
+
+	/* Setup an appropriate update request */
+	yld->copy.b[ix] = val;
+	yld->ctl_data->data[0] = val;
+
+	switch(ix) {
+	case offsetof(struct yld_status, led):
+		yld->ctl_data->cmd	= CMD_LED;
+		yld->ctl_data->sum	= -1 - CMD_LED - val;
+		break;
+	case offsetof(struct yld_status, dialtone):
+		yld->ctl_data->cmd	= CMD_DIALTONE;
+		yld->ctl_data->sum	= -1 - CMD_DIALTONE - val;
+		break;
+	case offsetof(struct yld_status, ringtone):
+		yld->ctl_data->cmd	= CMD_RINGTONE;
+		yld->ctl_data->sum	= -1 - CMD_RINGTONE - val;
+		break;
+	case offsetof(struct yld_status, keynum):
+		val--;
+		val &= 0x1f;
+		yld->ctl_data->cmd	= CMD_SCANCODE;
+		yld->ctl_data->offset	= cpu_to_be16(val);
+		yld->ctl_data->data[0]	= 0;
+		yld->ctl_data->sum	= -1 - CMD_SCANCODE - val;
+		break;
+	default:
+		len = sizeof(yld->master.s.lcd) - ix;
+		if (len > sizeof(yld->ctl_data->data))
+			len = sizeof(yld->ctl_data->data);
+
+		/* Combine up to <len> consecutive LCD bytes in a singe request
+		 */
+		yld->ctl_data->cmd	= CMD_LCD;
+		yld->ctl_data->offset	= cpu_to_be16(ix);
+		yld->ctl_data->size	= len;
+		yld->ctl_data->sum	= -CMD_LCD - ix - val - len;
+		for(i=1; i<len; i++) {
+			ix++;
+			val = yld->master.b[ix];
+			yld->copy.b[ix]		= val;
+			yld->ctl_data->data[i]	= val;
+			yld->ctl_data->sum     -= val;
+		}
+	}
+	yld->stat_ix = ix + 1;
+	return 1;
+}
+
+/* Decide on how to handle responses
+ *
+ * The state transition diagram is somethhing like:
+ *
+ *          syncState<--+
+ *               |      |
+ *               |    idle
+ *              \|/     |
+ * init --ok--> waitForKey --ok--> getKey
+ *  ^               ^                |
+ *  |               +-------ok-------+
+ * error,start
+ *
+ */
+static void urb_irq_callback(struct urb *urb)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret;
+
+	if (urb->status)
+		err("%s - urb status %d", __FUNCTION__, urb->status);
+
+	switch (yld->irq_data->cmd) {
+	case CMD_KEYPRESS:
+
+		yld->master.s.keynum = yld->irq_data->data[0];
+		break;
+
+	case CMD_SCANCODE:
+		dbg("get scancode %x", yld->irq_data->data[0]);
+
+		report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
+		break;
+
+	default:
+		err("unexpected response %x", yld->irq_data->cmd);
+	}
+
+	yealink_do_idle_tasks(yld);
+
+	ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+	if (ret)
+		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+static void urb_ctl_callback(struct urb *urb)
+{
+	struct yealink_dev *yld = urb->context;
+	int ret;
+
+	if (urb->status)
+		err("%s - urb status %d", __FUNCTION__, urb->status);
+
+	switch (yld->ctl_data->cmd) {
+	case CMD_KEYPRESS:
+	case CMD_SCANCODE:
+		/* ask for a response */
+		ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
+		break;
+	default:
+		/* send new command */
+		yealink_do_idle_tasks(yld);
+		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+	}
+
+	if (ret)
+		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+}
+
+/*******************************************************************************
+ * input event interface
+ ******************************************************************************/
+
+/* TODO should we issue a ringtone on a SND_BELL event?
+static int input_ev(struct input_dev *dev, unsigned int type,
+		unsigned int code, int value)
+{
+
+	if (type != EV_SND)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+*/
+
+static int input_open(struct input_dev *dev)
+{
+	struct yealink_dev *yld = input_get_drvdata(dev);
+	int i, ret;
+
+	dbg("%s", __FUNCTION__);
+
+	/* force updates to device */
+	for (i = 0; i<sizeof(yld->master); i++)
+		yld->copy.b[i] = ~yld->master.b[i];
+	yld->key_code = -1;	/* no keys pressed */
+
+        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
+
+	/* issue INIT */
+	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
+	yld->ctl_data->cmd	= CMD_INIT;
+	yld->ctl_data->size	= 10;
+	yld->ctl_data->sum	= 0x100-CMD_INIT-10;
+	if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
+		dbg("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void input_close(struct input_dev *dev)
+{
+	struct yealink_dev *yld = input_get_drvdata(dev);
+
+	usb_kill_urb(yld->urb_ctl);
+	usb_kill_urb(yld->urb_irq);
+}
+
+/*******************************************************************************
+ * sysfs interface
+ ******************************************************************************/
+
+static DECLARE_RWSEM(sysfs_rwsema);
+
+/* Interface to the 7-segments translation table aka. char set.
+ */
+static ssize_t show_map(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	memcpy(buf, &map_seg7, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+static ssize_t store_map(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t cnt)
+{
+	if (cnt != sizeof(map_seg7))
+		return -EINVAL;
+	memcpy(&map_seg7, buf, sizeof(map_seg7));
+	return sizeof(map_seg7);
+}
+
+/* Interface to the LCD.
+ */
+
+/* Reading /sys/../lineX will return the format string with its settings:
+ *
+ * Example:
+ * cat ./line3
+ * 888888888888
+ * Linux Rocks!
+ */
+static ssize_t show_line(struct device *dev, char *buf, int a, int b)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = a; i < b; i++)
+		*buf++ = lcdMap[i].type;
+	*buf++ = '\n';
+	for (i = a; i < b; i++)
+		*buf++ = yld->lcdMap[i];
+	*buf++ = '\n';
+	*buf = 0;
+
+	up_read(&sysfs_rwsema);
+	return 3 + ((b - a) << 1);
+}
+
+static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
+}
+
+static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
+}
+
+static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
+}
+
+/* Writing to /sys/../lineX will set the coresponding LCD line.
+ * - Excess characters are ignored.
+ * - If less characters are written than allowed, the remaining digits are
+ *   unchanged.
+ * - The '\n' or '\t' char is a placeholder, it does not overwrite the
+ *   original content.
+ */
+static ssize_t store_line(struct device *dev, const char *buf, size_t count,
+		int el, size_t len)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	if (len > count)
+		len = count;
+	for (i = 0; i < len; i++)
+		setChar(yld, el++, buf[i]);
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
+}
+
+static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
+}
+
+static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
+}
+
+/* Interface to visible and audible "icons", these include:
+ * pictures on the LCD, the LED, and the dialtone signal.
+ */
+
+/* Get a list of "switchable elements" with their current state. */
+static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct yealink_dev *yld;
+	int i, ret = 1;
+
+	down_read(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_read(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		ret += sprintf(&buf[ret], "%s %s\n",
+				yld->lcdMap[i] == ' ' ? "  " : "on",
+				lcdMap[i].u.p.name);
+	}
+	up_read(&sysfs_rwsema);
+	return ret;
+}
+
+/* Change the visibility of a particular element. */
+static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
+			int chr)
+{
+	struct yealink_dev *yld;
+	int i;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
+		if (lcdMap[i].type != '.')
+			continue;
+		if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
+			setChar(yld, i, chr);
+			break;
+		}
+	}
+
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, buf[0]);
+}
+
+static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	return set_icon(dev, buf, count, ' ');
+}
+
+/* Upload a ringtone to the device.
+ */
+
+/* Stores raw ringtone data in the phone */
+static ssize_t store_ringtone(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = dev_get_drvdata(dev);
+	if (yld == NULL) {
+		up_write(&sysfs_rwsema);
+		return -ENODEV;
+	}
+
+	/* TODO locking with async usb control interface??? */
+	yealink_set_ringtone(yld, (char *)buf, count);
+	up_write(&sysfs_rwsema);
+	return count;
+}
+
+#define _M444	S_IRUGO
+#define _M664	S_IRUGO|S_IWUSR|S_IWGRP
+#define _M220	S_IWUSR|S_IWGRP
+
+static DEVICE_ATTR(map_seg7	, _M664, show_map	, store_map	);
+static DEVICE_ATTR(line1	, _M664, show_line1	, store_line1	);
+static DEVICE_ATTR(line2	, _M664, show_line2	, store_line2	);
+static DEVICE_ATTR(line3	, _M664, show_line3	, store_line3	);
+static DEVICE_ATTR(get_icons	, _M444, get_icons	, NULL		);
+static DEVICE_ATTR(show_icon	, _M220, NULL		, show_icon	);
+static DEVICE_ATTR(hide_icon	, _M220, NULL		, hide_icon	);
+static DEVICE_ATTR(ringtone	, _M220, NULL		, store_ringtone);
+
+static struct attribute *yld_attributes[] = {
+	&dev_attr_line1.attr,
+	&dev_attr_line2.attr,
+	&dev_attr_line3.attr,
+	&dev_attr_get_icons.attr,
+	&dev_attr_show_icon.attr,
+	&dev_attr_hide_icon.attr,
+	&dev_attr_map_seg7.attr,
+	&dev_attr_ringtone.attr,
+	NULL
+};
+
+static struct attribute_group yld_attr_group = {
+	.attrs = yld_attributes
+};
+
+/*******************************************************************************
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+struct driver_info {
+	char *name;
+};
+
+static const struct driver_info info_P1K = {
+	.name	= "Yealink usb-p1k",
+};
+
+static const struct usb_device_id usb_table [] = {
+	{
+		.match_flags		= USB_DEVICE_ID_MATCH_DEVICE |
+						USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor		= 0x6993,
+		.idProduct		= 0xb001,
+		.bInterfaceClass	= USB_CLASS_HID,
+		.bInterfaceSubClass	= 0,
+		.bInterfaceProtocol	= 0,
+		.driver_info		= (kernel_ulong_t)&info_P1K
+	},
+	{ }
+};
+
+static int usb_cleanup(struct yealink_dev *yld, int err)
+{
+	if (yld == NULL)
+		return err;
+
+	usb_kill_urb(yld->urb_irq);	/* parameter validation in core/urb */
+	usb_kill_urb(yld->urb_ctl);	/* parameter validation in core/urb */
+
+        if (yld->idev) {
+		if (err)
+			input_free_device(yld->idev);
+		else
+			input_unregister_device(yld->idev);
+	}
+
+	usb_free_urb(yld->urb_irq);
+	usb_free_urb(yld->urb_ctl);
+
+	usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
+			yld->ctl_req, yld->ctl_req_dma);
+	usb_buffer_free(yld->udev, USB_PKT_LEN,
+			yld->ctl_data, yld->ctl_dma);
+	usb_buffer_free(yld->udev, USB_PKT_LEN,
+			yld->irq_data, yld->irq_dma);
+
+	kfree(yld);
+	return err;
+}
+
+static void usb_disconnect(struct usb_interface *intf)
+{
+	struct yealink_dev *yld;
+
+	down_write(&sysfs_rwsema);
+	yld = usb_get_intfdata(intf);
+	sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
+	usb_set_intfdata(intf, NULL);
+	up_write(&sysfs_rwsema);
+
+	usb_cleanup(yld, 0);
+}
+
+static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev (intf);
+	struct driver_info *nfo = (struct driver_info *)id->driver_info;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct yealink_dev *yld;
+	struct input_dev *input_dev;
+	int ret, pipe, i;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
+	if (!yld)
+		return -ENOMEM;
+
+	yld->udev = udev;
+
+	yld->idev = input_dev = input_allocate_device();
+	if (!input_dev)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* allocate usb buffers */
+	yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					GFP_ATOMIC, &yld->irq_dma);
+	if (yld->irq_data == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
+					GFP_ATOMIC, &yld->ctl_dma);
+	if (!yld->ctl_data)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
+					GFP_ATOMIC, &yld->ctl_req_dma);
+	if (yld->ctl_req == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* allocate urb structures */
+	yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_irq == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
+        if (yld->urb_ctl == NULL)
+		return usb_cleanup(yld, -ENOMEM);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+	if (ret != USB_PKT_LEN)
+		err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+
+	/* initialise irq urb */
+	usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
+			USB_PKT_LEN,
+			urb_irq_callback,
+			yld, endpoint->bInterval);
+	yld->urb_irq->transfer_dma = yld->irq_dma;
+	yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_irq->dev = udev;
+
+	/* initialise ctl urb */
+	yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+				      USB_DIR_OUT;
+	yld->ctl_req->bRequest	= USB_REQ_SET_CONFIGURATION;
+	yld->ctl_req->wValue	= cpu_to_le16(0x200);
+	yld->ctl_req->wIndex	= cpu_to_le16(interface->desc.bInterfaceNumber);
+	yld->ctl_req->wLength	= cpu_to_le16(USB_PKT_LEN);
+
+	usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
+			(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
+			urb_ctl_callback, yld);
+	yld->urb_ctl->setup_dma	= yld->ctl_req_dma;
+	yld->urb_ctl->transfer_dma	= yld->ctl_dma;
+	yld->urb_ctl->transfer_flags	|= URB_NO_SETUP_DMA_MAP |
+					URB_NO_TRANSFER_DMA_MAP;
+	yld->urb_ctl->dev = udev;
+
+	/* find out the physical bus location */
+	usb_make_path(udev, yld->phys, sizeof(yld->phys));
+	strlcat(yld->phys,  "/input0", sizeof(yld->phys));
+
+	/* register settings for the input device */
+	input_dev->name = nfo->name;
+	input_dev->phys = yld->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, yld);
+
+	input_dev->open = input_open;
+	input_dev->close = input_close;
+	/* input_dev->event = input_ev;	TODO */
+
+	/* register available key events */
+	input_dev->evbit[0] = BIT(EV_KEY);
+	for (i = 0; i < 256; i++) {
+		int k = map_p1k_to_key(i);
+		if (k >= 0) {
+			set_bit(k & 0xff, input_dev->keybit);
+			if (k >> 8)
+				set_bit(k >> 8, input_dev->keybit);
+		}
+	}
+
+	ret = input_register_device(yld->idev);
+	if (ret)
+		return usb_cleanup(yld, ret);
+
+	usb_set_intfdata(intf, yld);
+
+	/* clear visible elements */
+	for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
+		setChar(yld, i, ' ');
+
+	/* display driver version on LCD line 3 */
+	store_line3(&intf->dev, NULL,
+			DRIVER_VERSION, sizeof(DRIVER_VERSION));
+
+	/* Register sysfs hooks (don't care about failure) */
+	ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+	return 0;
+}
+
+static struct usb_driver yealink_driver = {
+	.name		= "yealink",
+	.probe		= usb_probe,
+	.disconnect	= usb_disconnect,
+	.id_table	= usb_table,
+};
+
+static int __init yealink_dev_init(void)
+{
+	int ret = usb_register(&yealink_driver);
+	if (ret == 0)
+		info(DRIVER_DESC ":" DRIVER_VERSION);
+	return ret;
+}
+
+static void __exit yealink_dev_exit(void)
+{
+	usb_deregister(&yealink_driver);
+}
+
+module_init(yealink_dev_init);
+module_exit(yealink_dev_exit);
+
+MODULE_DEVICE_TABLE (usb, usb_table);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h
new file mode 100644
index 0000000..48af0be
--- /dev/null
+++ b/drivers/input/misc/yealink.h
@@ -0,0 +1,220 @@
+/*
+ * drivers/usb/input/yealink.h
+ *
+ * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
+ */
+#ifndef INPUT_YEALINK_H
+#define INPUT_YEALINK_H
+
+/* Using the control channel on interface 3 various aspects of the phone
+ * can be controlled like LCD, LED, dialtone and the ringtone.
+ */
+
+struct yld_ctl_packet {
+	u8	cmd;		/* command code, see below */
+	u8	size;		/* 1-11, size of used data bytes. */
+	u16	offset;		/* internal packet offset */
+	u8	data[11];
+	s8	sum;		/* negative sum of 15 preceding bytes */
+} __attribute__ ((packed));
+
+#define USB_PKT_LEN	sizeof(struct yld_ctl_packet)
+
+/* The following yld_ctl_packet's are available: */
+
+/* Init registers
+ *
+ * cmd		0x8e
+ * size		10
+ * offset	0
+ * data		0,0,0,0....
+ */
+#define CMD_INIT		0x8e
+
+/* Request key scan
+ *
+ * cmd		0x80
+ * size		1
+ * offset	0
+ * data[0]	on return returns the key number, if it changes there's a new
+ * 		key pressed.
+ */
+#define CMD_KEYPRESS		0x80
+
+/* Request scancode
+ *
+ * cmd		0x81
+ * size		1
+ * offset	key number [0-1f]
+ * data[0]	on return returns the scancode
+ */
+#define CMD_SCANCODE		0x81
+
+/* Set LCD
+ *
+ * cmd		0x04
+ * size		1-11
+ * offset	0-23
+ * data		segment bits
+ */
+#define CMD_LCD			0x04
+
+/* Set led
+ *
+ * cmd		0x05
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_LED			0x05
+
+/* Set ringtone volume
+ *
+ * cmd		0x11
+ * size		1
+ * offset	0
+ * data[0]	0-0xff  volume
+ */
+#define CMD_RING_VOLUME		0x11
+
+/* Set ringtone notes
+ *
+ * cmd		0x02
+ * size		1-11
+ * offset	0->
+ * data		binary representation LE16(-freq), LE16(duration) ....
+ */
+#define CMD_RING_NOTE		0x02
+
+/* Sound ringtone via the speaker on the back
+ *
+ * cmd		0x03
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 0x24 ON
+ */
+#define CMD_RINGTONE		0x03
+
+/* Sound dial tone via the ear speaker
+ *
+ * cmd		0x09
+ * size		1
+ * offset	0
+ * data[0]	0 OFF / 1 ON
+ */
+#define CMD_DIALTONE		0x09
+
+#endif /* INPUT_YEALINK_H */
+
+
+#if defined(_SEG) && defined(_PIC)
+/* This table maps the LCD segments onto individual bit positions in the
+ * yld_status struct.
+ */
+
+/* LCD, each segment must be driven seperately.
+ *
+ * Layout:
+ *
+ *   |[]   [][]   [][]   [][]   in   |[][]
+ *   |[] M [][] D [][] : [][]   out  |[][]
+ *                             store
+ *
+ *    NEW REP         SU MO TU WE TH FR SA
+ *
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ *    [] [] [] [] [] [] [] [] [] [] [] []
+ */
+
+/* Line 1
+ *	Format		: 18.e8.M8.88...188
+ *	Icon names	: M D : IN OUT STORE
+ */
+#define LCD_LINE1_OFFSET	0
+#define LCD_LINE1_SIZE		17
+
+/* Note: first g then f =>			       !      !      */
+/* _SEG(    type    a      b      c      d      e      g      f   )  */
+	_SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1	),
+	_PIC('.', 22,1 , "M"						),
+	_SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1	),
+	_SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1	),
+	_PIC('.', 15,8 , "D"						),
+	_SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1	),
+	_SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1	),
+	_PIC('.', 11,8 , ":"						),
+	_SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1	),
+	_SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1	),
+	_PIC('.',  7,1 , "IN"						),
+	_PIC('.',  7,2 , "OUT"						),
+	_PIC('.',  7,4 , "STORE"					),
+	_SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
+	_SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2	),
+	_SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1	),
+
+/* Line 2
+ *	Format		: .........
+ *	Pict. name	: NEW REP SU MO TU WE TH FR SA
+ */
+#define LCD_LINE2_OFFSET	LCD_LINE1_OFFSET + LCD_LINE1_SIZE
+#define LCD_LINE2_SIZE		9
+
+	_PIC('.', 23,2 , "NEW"	),
+	_PIC('.', 23,4 , "REP"	),
+	_PIC('.',  1,8 , "SU"	),
+	_PIC('.',  1,4 , "MO"	),
+	_PIC('.',  1,2 , "TU"	),
+	_PIC('.',  1,1 , "WE"	),
+	_PIC('.',  0,1 , "TH"	),
+	_PIC('.',  0,2 , "FR"	),
+	_PIC('.',  0,4 , "SA"	),
+
+/* Line 3
+ *	Format		: 888888888888
+ */
+#define LCD_LINE3_OFFSET	LCD_LINE2_OFFSET + LCD_LINE2_SIZE
+#define LCD_LINE3_SIZE		12
+
+	_SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
+	_SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
+	_SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
+	_SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
+	_SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
+	_SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
+	_SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
+	_SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
+	_SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
+	_SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
+	_SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
+	_SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
+
+/* Line 4
+ *
+ * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
+ * sysfs interface.
+ */
+#define LCD_LINE4_OFFSET	LCD_LINE3_OFFSET + LCD_LINE3_SIZE
+
+	_PIC('.', offsetof(struct yld_status, led)	, 0x01, "LED" ),
+	_PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
+	_PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
+
+#undef _SEG
+#undef _PIC
+#endif /* _SEG && _PIC */
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 35d998c..2ccc114 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -2,7 +2,7 @@ #
 # Mouse driver configuration
 #
 menuconfig INPUT_MOUSE
-	bool "Mouse"
+	bool "Mice"
 	default y
 	help
 	  Say Y here, and a list of supported mice will be displayed.
@@ -19,7 +19,7 @@ config MOUSE_PS2
 	select SERIO_LIBPS2
 	select SERIO_I8042 if X86_PC
 	select SERIO_GSCPS2 if GSC
-	---help---
+	help
 	  Say Y here if you have a PS/2 mouse connected to your system. This
 	  includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
 	  mice with wheels and extra buttons, Microsoft, Logitech or Genius
@@ -37,10 +37,69 @@ config MOUSE_PS2
 	  To compile this driver as a module, choose M here: the
 	  module will be called psmouse.
 
+config MOUSE_PS2_ALPS
+	bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
+	default y
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have an ALPS PS/2 touchpad connected to
+	  your system.
+
+	  If unsure, say Y.
+
+config MOUSE_PS2_LOGIPS2PP
+	bool "Logictech PS/2++ mouse protocol extension" if EMBEDDED
+	default y
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have a Logictech PS/2++ mouse connected to
+	  your system.
+
+	  If unsure, say Y.
+
+config MOUSE_PS2_SYNAPTICS
+	bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
+	default y
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have a Synaptics PS/2 TouchPad connected to
+	  your system.
+
+	  If unsure, say Y.
+
+config MOUSE_PS2_LIFEBOOK
+	bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
+	default y
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have a Fujitsu B-series Lifebook PS/2
+	  TouchScreen connected to your system.
+
+	  If unsure, say Y.
+
+config MOUSE_PS2_TRACKPOINT
+	bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
+	default y
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have an IBM Trackpoint PS/2 mouse connected
+	  to your system.
+
+	  If unsure, say Y.
+
+config MOUSE_PS2_TOUCHKIT
+	bool "eGalax TouchKit PS/2 protocol extension"
+	depends on MOUSE_PS2
+	help
+	  Say Y here if you have an eGalax TouchKit PS/2 touchscreen
+	  connected to your system.
+
+	  If unsure, say N.
+
 config MOUSE_SERIAL
 	tristate "Serial mouse"
 	select SERIO
-	---help---
+	help
 	  Say Y here if you have a serial (RS-232, COM port) mouse connected
 	  to your system. This includes Sun, MouseSystems, Microsoft,
 	  Logitech and all other compatible serial mice.
@@ -50,6 +109,26 @@ config MOUSE_SERIAL
 	  To compile this driver as a module, choose M here: the
 	  module will be called sermouse.
 
+config MOUSE_APPLETOUCH
+	tristate "Apple USB Touchpad support"
+	select USB
+	help
+	  Say Y here if you want to use an Apple USB Touchpad.
+
+	  These are the touchpads that can be found on post-February 2005
+	  Apple Powerbooks (prior models have a Synaptics touchpad connected
+	  to the ADB bus).
+
+	  This driver provides a basic mouse driver but can be interfaced
+	  with the synaptics X11 driver to provide acceleration and
+	  scrolling in X11.
+
+	  For further information, see
+	  <file:Documentation/input/appletouch.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called appletouch.
+
 config MOUSE_INPORT
 	tristate "InPort/MS/ATIXL busmouse"
 	depends on ISA
@@ -96,6 +175,17 @@ config MOUSE_AMIGA
 	  To compile this driver as a module, choose M here: the
 	  module will be called amimouse.
 
+config MOUSE_ATARI
+	tristate "Atari mouse"
+	depends on ATARI
+	select ATARI_KBD_CORE
+	help
+	  Say Y here if you have an Atari and want its native mouse
+	  supported by the kernel.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atarimouse.
+
 config MOUSE_RISCPC
 	tristate "Acorn RiscPC mouse"
 	depends on ARCH_ACORN
@@ -118,7 +208,7 @@ config MOUSE_VSXXXAA
 	  digitizer (VSXXX-AB) DEC produced.
 
 config MOUSE_HIL
-	tristate "HIL pointers (mice etc)."     
+	tristate "HIL pointers (mice etc)."
 	depends on GSC || HP300
 	select HP_SDC
 	select HIL_MLC
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 21a1de6..aa4ba87 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -5,6 +5,8 @@ #
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_MOUSE_AMIGA)	+= amimouse.o
+obj-$(CONFIG_MOUSE_APPLETOUCH)	+= appletouch.o
+obj-$(CONFIG_MOUSE_ATARI)	+= atarimouse.o
 obj-$(CONFIG_MOUSE_RISCPC)	+= rpcmouse.o
 obj-$(CONFIG_MOUSE_INPORT)	+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
@@ -14,4 +16,10 @@ obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 
-psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
+psmouse-objs := psmouse-base.o synaptics.o
+
+psmouse-$(CONFIG_MOUSE_PS2_ALPS)	+= alps.o
+psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP)	+= logips2pp.o
+psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK)	+= lifebook.o
+psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)	+= trackpoint.o
+psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT)	+= touchkit_ps2.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4e71a66..cf3e466 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -424,14 +424,15 @@ int alps_init(struct psmouse *psmouse)
 	struct input_dev *dev1 = psmouse->dev, *dev2;
 	int version;
 
-	psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+	priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
 	dev2 = input_allocate_device();
 	if (!priv || !dev2)
 		goto init_fail;
 
 	priv->dev2 = dev2;
 
-	if (!(priv->i = alps_get_model(psmouse, &version)))
+	priv->i = alps_get_model(psmouse, &version);
+	if (!priv->i)
 		goto init_fail;
 
 	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
@@ -480,7 +481,8 @@ int alps_init(struct psmouse *psmouse)
 	dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
 	dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 
-	input_register_device(priv->dev2);
+	if (input_register_device(priv->dev2))
+		goto init_fail;
 
 	psmouse->protocol_handler = alps_process_byte;
 	psmouse->poll = alps_poll;
@@ -491,9 +493,11 @@ int alps_init(struct psmouse *psmouse)
 	/* We are having trouble resyncing ALPS touchpads so disable it for now */
 	psmouse->resync_time = 0;
 
+	psmouse->private = priv;
 	return 0;
 
 init_fail:
+	psmouse_reset(psmouse);
 	input_free_device(dev2);
 	kfree(priv);
 	return -1;
@@ -504,7 +508,8 @@ int alps_detect(struct psmouse *psmouse,
 	int version;
 	const struct alps_model_info *model;
 
-	if (!(model = alps_get_model(psmouse, &version)))
+	model = alps_get_model(psmouse, &version);
+	if (!model)
 		return -1;
 
 	if (set_properties) {
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 69db732..4bbddc9 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,9 +12,6 @@
 #ifndef _ALPS_H
 #define _ALPS_H
 
-int alps_detect(struct psmouse *psmouse, int set_properties);
-int alps_init(struct psmouse *psmouse);
-
 struct alps_model_info {
         unsigned char signature[3];
         unsigned char byte0, mask0;
@@ -23,10 +20,23 @@ struct alps_model_info {
 
 struct alps_data {
 	struct input_dev *dev2;		/* Relative device */
-	char name[32];			/* Name */
 	char phys[32];			/* Phys */
 	const struct alps_model_info *i;/* Info */
 	int prev_fin;			/* Finger bit from previous packet */
 };
 
+#ifdef CONFIG_MOUSE_PS2_ALPS
+int alps_detect(struct psmouse *psmouse, int set_properties);
+int alps_init(struct psmouse *psmouse);
+#else
+inline int alps_detect(struct psmouse *psmouse, int set_properties)
+{
+	return -ENOSYS;
+}
+inline int alps_init(struct psmouse *psmouse)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_ALPS */
+
 #endif
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
new file mode 100644
index 0000000..e321526
--- /dev/null
+++ b/drivers/input/mouse/appletouch.c
@@ -0,0 +1,706 @@
+/*
+ * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
+ * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
+ * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
+ * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
+ * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
+ * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
+ *
+ * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/input.h>
+
+/* Apple has powerbooks which have the keyboard with different Product IDs */
+#define APPLE_VENDOR_ID		0x05AC
+
+/* These names come from Info.plist in AppleUSBTrackpad.kext */
+#define FOUNTAIN_ANSI_PRODUCT_ID	0x020E
+#define FOUNTAIN_ISO_PRODUCT_ID		0x020F
+
+#define FOUNTAIN_TP_ONLY_PRODUCT_ID	0x030A
+
+#define GEYSER1_TP_ONLY_PRODUCT_ID	0x030B
+
+#define GEYSER_ANSI_PRODUCT_ID		0x0214
+#define GEYSER_ISO_PRODUCT_ID		0x0215
+#define GEYSER_JIS_PRODUCT_ID		0x0216
+
+/* MacBook devices */
+#define GEYSER3_ANSI_PRODUCT_ID		0x0217
+#define GEYSER3_ISO_PRODUCT_ID		0x0218
+#define GEYSER3_JIS_PRODUCT_ID		0x0219
+
+/*
+ * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext
+ * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables
+ */
+#define GEYSER4_ANSI_PRODUCT_ID	0x021A
+#define GEYSER4_ISO_PRODUCT_ID	0x021B
+#define GEYSER4_JIS_PRODUCT_ID	0x021C
+
+#define ATP_DEVICE(prod)					\
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |		\
+		       USB_DEVICE_ID_MATCH_INT_CLASS |		\
+		       USB_DEVICE_ID_MATCH_INT_PROTOCOL,	\
+	.idVendor = APPLE_VENDOR_ID,				\
+	.idProduct = (prod),					\
+	.bInterfaceClass = 0x03,				\
+	.bInterfaceProtocol = 0x02
+
+/* table of devices that work with this driver */
+static struct usb_device_id atp_table [] = {
+	{ ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) },
+	{ ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) },
+	{ ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) },
+
+	/* PowerBooks Oct 2005 */
+	{ ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
+
+	/* Core Duo MacBook & MacBook Pro */
+	{ ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) },
+
+	/* Core2 Duo MacBook & MacBook Pro */
+	{ ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) },
+	{ ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) },
+
+	/* Terminating entry */
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, atp_table);
+
+/*
+ * number of sensors. Note that only 16 instead of 26 X (horizontal)
+ * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
+ * (vertical) sensors.
+ */
+#define ATP_XSENSORS	26
+#define ATP_YSENSORS	16
+
+/* amount of fuzz this touchpad generates */
+#define ATP_FUZZ	16
+
+/* maximum pressure this driver will report */
+#define ATP_PRESSURE	300
+/*
+ * multiplication factor for the X and Y coordinates.
+ * We try to keep the touchpad aspect ratio while still doing only simple
+ * arithmetics.
+ * The factors below give coordinates like:
+ *	0 <= x <  960 on 12" and 15" Powerbooks
+ *	0 <= x < 1600 on 17" Powerbooks
+ *	0 <= y <  646
+ */
+#define ATP_XFACT	64
+#define ATP_YFACT	43
+
+/*
+ * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
+ * ignored.
+ */
+#define ATP_THRESHOLD	 5
+
+/* MacBook Pro (Geyser 3 & 4) initialization constants */
+#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
+#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
+#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
+#define ATP_GEYSER3_MODE_REQUEST_INDEX 0
+#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04
+
+/* Structure to hold all of our device specific stuff */
+struct atp {
+	char			phys[64];
+	struct usb_device *	udev;		/* usb device */
+	struct urb *		urb;		/* usb request block */
+	signed char *		data;		/* transferred data */
+	int			open;		/* non-zero if opened */
+	struct input_dev	*input;		/* input dev */
+	int			valid;		/* are the sensors valid ? */
+	int			x_old;		/* last reported x/y, */
+	int			y_old;		/* used for smoothing */
+						/* current value of the sensors */
+	signed char		xy_cur[ATP_XSENSORS + ATP_YSENSORS];
+						/* last value of the sensors */
+	signed char		xy_old[ATP_XSENSORS + ATP_YSENSORS];
+						/* accumulated sensors */
+	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS];
+	int			overflowwarn;	/* overflow warning printed? */
+	int			datalen;	/* size of an USB urb transfer */
+};
+
+#define dbg_dump(msg, tab) \
+	if (debug > 1) {						\
+		int i;							\
+		printk("appletouch: %s %lld", msg, (long long)jiffies); \
+		for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++)	\
+			printk(" %02x", tab[i]);			\
+		printk("\n");						\
+	}
+
+#define dprintk(format, a...)						\
+	do {								\
+		if (debug) printk(format, ##a);				\
+	} while (0)
+
+MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann");
+MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Make the threshold a module parameter
+ */
+static int threshold = ATP_THRESHOLD;
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value");
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activate debugging output");
+
+/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
+static inline int atp_is_geyser_2(struct atp *dev)
+{
+	u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+	return (productId == GEYSER_ANSI_PRODUCT_ID) ||
+		(productId == GEYSER_ISO_PRODUCT_ID) ||
+		(productId == GEYSER_JIS_PRODUCT_ID);
+}
+
+static inline int atp_is_geyser_3(struct atp *dev)
+{
+	u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+	return (productId == GEYSER3_ANSI_PRODUCT_ID) ||
+		(productId == GEYSER3_ISO_PRODUCT_ID) ||
+		(productId == GEYSER3_JIS_PRODUCT_ID) ||
+		(productId == GEYSER4_ANSI_PRODUCT_ID) ||
+		(productId == GEYSER4_ISO_PRODUCT_ID) ||
+		(productId == GEYSER4_JIS_PRODUCT_ID);
+}
+
+static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
+			     int *z, int *fingers)
+{
+	int i;
+	/* values to calculate mean */
+	int pcum = 0, psum = 0;
+	int is_increasing = 0;
+
+	*fingers = 0;
+
+	for (i = 0; i < nb_sensors; i++) {
+		if (xy_sensors[i] < threshold) {
+			if (is_increasing)
+				is_increasing = 0;
+
+			continue;
+		}
+
+		/*
+		 * Makes the finger detection more versatile.  For example,
+		 * two fingers with no gap will be detected.  Also, my
+		 * tests show it less likely to have intermittent loss
+		 * of multiple finger readings while moving around (scrolling).
+		 *
+		 * Changes the multiple finger detection to counting humps on
+		 * sensors (transitions from nonincreasing to increasing)
+		 * instead of counting transitions from low sensors (no
+		 * finger reading) to high sensors (finger above
+		 * sensor)
+		 *
+		 * - Jason Parekh <jasonparekh@gmail.com>
+		 */
+		if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
+			(*fingers)++;
+			is_increasing = 1;
+		} else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) {
+			is_increasing = 0;
+		}
+
+		/*
+		 * Subtracts threshold so a high sensor that just passes the threshold
+		 * won't skew the calculated absolute coordinate.  Fixes an issue
+		 * where slowly moving the mouse would occassionaly jump a number of
+		 * pixels (let me restate--slowly moving the mouse makes this issue
+		 * most apparent).
+		 */
+		pcum += (xy_sensors[i] - threshold) * i;
+		psum += (xy_sensors[i] - threshold);
+	}
+
+	if (psum > 0) {
+		*z = psum;
+		return pcum * fact / psum;
+	}
+
+	return 0;
+}
+
+static inline void atp_report_fingers(struct input_dev *input, int fingers)
+{
+	input_report_key(input, BTN_TOOL_FINGER, fingers == 1);
+	input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2);
+	input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
+}
+
+static void atp_complete(struct urb* urb)
+{
+	int x, y, x_z, y_z, x_f, y_f;
+	int retval, i, j;
+	struct atp *dev = urb->context;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -EOVERFLOW:
+		if(!dev->overflowwarn) {
+			printk("appletouch: OVERFLOW with data "
+				"length %d, actual length is %d\n",
+				dev->datalen, dev->urb->actual_length);
+			dev->overflowwarn = 1;
+		}
+	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;
+	}
+
+	/* drop incomplete datasets */
+	if (dev->urb->actual_length != dev->datalen) {
+		dprintk("appletouch: incomplete data package"
+			" (first byte: %d, length: %d).\n",
+			dev->data[0], dev->urb->actual_length);
+		goto exit;
+	}
+
+	/* reorder the sensors values */
+	if (atp_is_geyser_3(dev)) {
+		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+
+		/*
+		 * The values are laid out like this:
+		 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
+		 * '-' is an unused value.
+		 */
+
+		/* read X values */
+		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+			dev->xy_cur[i] = dev->data[j + 1];
+			dev->xy_cur[i + 1] = dev->data[j + 2];
+		}
+		/* read Y values */
+		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
+			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
+		}
+	} else if (atp_is_geyser_2(dev)) {
+		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
+
+		/*
+		 * The values are laid out like this:
+		 * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ...
+		 * '-' is an unused value.
+		 */
+
+		/* read X values */
+		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
+			dev->xy_cur[i] = dev->data[j];
+			dev->xy_cur[i + 1] = dev->data[j + 1];
+		}
+
+		/* read Y values */
+		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
+			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j];
+			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1];
+		}
+	} else {
+		for (i = 0; i < 8; i++) {
+			/* X values */
+			dev->xy_cur[i     ] = dev->data[5 * i +  2];
+			dev->xy_cur[i +  8] = dev->data[5 * i +  4];
+			dev->xy_cur[i + 16] = dev->data[5 * i + 42];
+			if (i < 2)
+				dev->xy_cur[i + 24] = dev->data[5 * i + 44];
+
+			/* Y values */
+			dev->xy_cur[i + 26] = dev->data[5 * i +  1];
+			dev->xy_cur[i + 34] = dev->data[5 * i +  3];
+		}
+	}
+
+	dbg_dump("sample", dev->xy_cur);
+
+	if (!dev->valid) {
+		/* first sample */
+		dev->valid = 1;
+		dev->x_old = dev->y_old = -1;
+		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+
+		if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
+			goto exit;
+
+		/* 17" Powerbooks have extra X sensors */
+		for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
+			if (!dev->xy_cur[i]) continue;
+
+			printk("appletouch: 17\" model detected.\n");
+			if(atp_is_geyser_2(dev))
+				input_set_abs_params(dev->input, ABS_X, 0,
+						     (20 - 1) *
+						     ATP_XFACT - 1,
+						     ATP_FUZZ, 0);
+			else
+				input_set_abs_params(dev->input, ABS_X, 0,
+						     (ATP_XSENSORS - 1) *
+						     ATP_XFACT - 1,
+						     ATP_FUZZ, 0);
+
+			break;
+		}
+
+		goto exit;
+	}
+
+	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
+		/* accumulate the change */
+		signed char change = dev->xy_old[i] - dev->xy_cur[i];
+		dev->xy_acc[i] -= change;
+
+		/* prevent down drifting */
+		if (dev->xy_acc[i] < 0)
+			dev->xy_acc[i] = 0;
+	}
+
+	memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
+
+	dbg_dump("accumulator", dev->xy_acc);
+
+	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
+			      ATP_XFACT, &x_z, &x_f);
+	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
+			      ATP_YFACT, &y_z, &y_f);
+
+	if (x && y) {
+		if (dev->x_old != -1) {
+			x = (dev->x_old * 3 + x) >> 2;
+			y = (dev->y_old * 3 + y) >> 2;
+			dev->x_old = x;
+			dev->y_old = y;
+
+			if (debug > 1)
+				printk("appletouch: X: %3d Y: %3d "
+				       "Xz: %3d Yz: %3d\n",
+				       x, y, x_z, y_z);
+
+			input_report_key(dev->input, BTN_TOUCH, 1);
+			input_report_abs(dev->input, ABS_X, x);
+			input_report_abs(dev->input, ABS_Y, y);
+			input_report_abs(dev->input, ABS_PRESSURE,
+					 min(ATP_PRESSURE, x_z + y_z));
+			atp_report_fingers(dev->input, max(x_f, y_f));
+		}
+		dev->x_old = x;
+		dev->y_old = y;
+	}
+	else if (!x && !y) {
+
+		dev->x_old = dev->y_old = -1;
+		input_report_key(dev->input, BTN_TOUCH, 0);
+		input_report_abs(dev->input, ABS_PRESSURE, 0);
+		atp_report_fingers(dev->input, 0);
+
+		/* reset the accumulator on release */
+		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+	}
+
+	input_report_key(dev->input, BTN_LEFT,
+			 !!dev->data[dev->datalen - 1]);
+
+	input_sync(dev->input);
+
+exit:
+	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+	if (retval) {
+		err("%s - usb_submit_urb failed with result %d",
+		    __FUNCTION__, retval);
+	}
+}
+
+static int atp_open(struct input_dev *input)
+{
+	struct atp *dev = input_get_drvdata(input);
+
+	if (usb_submit_urb(dev->urb, GFP_ATOMIC))
+		return -EIO;
+
+	dev->open = 1;
+	return 0;
+}
+
+static void atp_close(struct input_dev *input)
+{
+	struct atp *dev = input_get_drvdata(input);
+
+	usb_kill_urb(dev->urb);
+	dev->open = 0;
+}
+
+static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+	struct atp *dev;
+	struct input_dev *input_dev;
+	struct usb_device *udev = interface_to_usbdev(iface);
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	int int_in_endpointAddr = 0;
+	int i, error = -ENOMEM;
+
+	/* set up the endpoint information */
+	/* use only the first interrupt-in endpoint */
+	iface_desc = iface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
+			/* we found an interrupt in endpoint */
+			int_in_endpointAddr = endpoint->bEndpointAddress;
+			break;
+		}
+	}
+	if (!int_in_endpointAddr) {
+		err("Could not find int-in endpoint");
+		return -EIO;
+	}
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!dev || !input_dev) {
+		err("Out of memory");
+		goto err_free_devs;
+	}
+
+	dev->udev = udev;
+	dev->input = input_dev;
+	dev->overflowwarn = 0;
+	if (atp_is_geyser_3(dev))
+		dev->datalen = 64;
+	else if (atp_is_geyser_2(dev))
+		dev->datalen = 64;
+	else
+		dev->datalen = 81;
+
+	if (atp_is_geyser_3(dev)) {
+		/*
+		 * By default Geyser 3 device sends standard USB HID mouse
+		 * packets (Report ID 2). This code changes device mode, so it
+		 * sends raw sensor reports (Report ID 5).
+		 */
+		char data[8];
+		int size;
+
+		size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_READ_REQUEST_ID,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+		if (size != 8) {
+			err("Could not do mode read request from device"
+							" (Geyser 3 mode)");
+			goto err_free_devs;
+		}
+
+		/* Apply the mode switch */
+		data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+		size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+		if (size != 8) {
+			err("Could not do mode write request to device"
+							" (Geyser 3 mode)");
+			goto err_free_devs;
+		}
+		printk("appletouch Geyser 3 inited.\n");
+	}
+
+	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->urb)
+		goto err_free_devs;
+
+	dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
+				     &dev->urb->transfer_dma);
+	if (!dev->data)
+		goto err_free_urb;
+
+	usb_fill_int_urb(dev->urb, udev,
+			 usb_rcvintpipe(udev, int_in_endpointAddr),
+			 dev->data, dev->datalen, atp_complete, dev, 1);
+
+	usb_make_path(udev, dev->phys, sizeof(dev->phys));
+	strlcat(dev->phys, "/input0", sizeof(dev->phys));
+
+	input_dev->name = "appletouch";
+	input_dev->phys = dev->phys;
+	usb_to_input_id(dev->udev, &input_dev->id);
+	input_dev->dev.parent = &iface->dev;
+
+	input_set_drvdata(input_dev, dev);
+
+	input_dev->open = atp_open;
+	input_dev->close = atp_close;
+
+	set_bit(EV_ABS, input_dev->evbit);
+
+	if (atp_is_geyser_3(dev)) {
+		/*
+		 * MacBook have 20 X sensors, 10 Y sensors
+		 */
+		input_set_abs_params(input_dev, ABS_X, 0,
+				     ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0,
+				     ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
+	} else if (atp_is_geyser_2(dev)) {
+		/*
+		 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
+		 * later.
+		 */
+		input_set_abs_params(input_dev, ABS_X, 0,
+				     ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0,
+				     ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
+	} else {
+		/*
+		 * 12" and 15" Powerbooks only have 16 x sensors,
+		 * 17" models are detected later.
+		 */
+		input_set_abs_params(input_dev, ABS_X, 0,
+				     (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0,
+				     (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
+	}
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
+
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(BTN_TOUCH, input_dev->keybit);
+	set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+	set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+	set_bit(BTN_LEFT, input_dev->keybit);
+
+	error = input_register_device(dev->input);
+	if (error)
+		goto err_free_buffer;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(iface, dev);
+
+	return 0;
+
+ err_free_buffer:
+	usb_buffer_free(dev->udev, dev->datalen,
+			dev->data, dev->urb->transfer_dma);
+ err_free_urb:
+	usb_free_urb(dev->urb);
+ err_free_devs:
+	usb_set_intfdata(iface, NULL);
+	kfree(dev);
+	input_free_device(input_dev);
+	return error;
+}
+
+static void atp_disconnect(struct usb_interface *iface)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+
+	usb_set_intfdata(iface, NULL);
+	if (dev) {
+		usb_kill_urb(dev->urb);
+		input_unregister_device(dev->input);
+		usb_buffer_free(dev->udev, dev->datalen,
+				dev->data, dev->urb->transfer_dma);
+		usb_free_urb(dev->urb);
+		kfree(dev);
+	}
+	printk(KERN_INFO "input: appletouch disconnected\n");
+}
+
+static int atp_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+	usb_kill_urb(dev->urb);
+	dev->valid = 0;
+	return 0;
+}
+
+static int atp_resume(struct usb_interface *iface)
+{
+	struct atp *dev = usb_get_intfdata(iface);
+	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
+		return -EIO;
+
+	return 0;
+}
+
+static struct usb_driver atp_driver = {
+	.name		= "appletouch",
+	.probe		= atp_probe,
+	.disconnect	= atp_disconnect,
+	.suspend	= atp_suspend,
+	.resume		= atp_resume,
+	.id_table	= atp_table,
+};
+
+static int __init atp_init(void)
+{
+	return usb_register(&atp_driver);
+}
+
+static void __exit atp_exit(void)
+{
+	usb_deregister(&atp_driver);
+}
+
+module_init(atp_init);
+module_exit(atp_exit);
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
new file mode 100644
index 0000000..43ab656
--- /dev/null
+++ b/drivers/input/mouse/atarimouse.c
@@ -0,0 +1,160 @@
+/*
+ *  Atari mouse driver for Linux/m68k
+ *
+ *  Copyright (c) 2005 Michael Schmitz
+ *
+ *  Based on:
+ *  Amiga mouse driver for Linux/m68k
+ *
+ *  Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ */
+/*
+ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
+ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
+ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
+ * This driver only deals with handing key events off to the input layer.
+ *
+ * Largely based on the old:
+ *
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ *
+ * Converted to use new generic busmouse code.  5 Apr 1998
+ *   Russell King <rmk@arm.uk.linux.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/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atariints.h>
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
+MODULE_DESCRIPTION("Atari mouse driver");
+MODULE_LICENSE("GPL");
+
+static int mouse_threshold[2] = {2,2};
+
+#ifdef __MODULE__
+MODULE_PARM(mouse_threshold, "2i");
+#endif
+#ifdef FIXED_ATARI_JOYSTICK
+extern int atari_mouse_buttons;
+#endif
+static int atamouse_used = 0;
+
+static struct input_dev *atamouse_dev;
+
+static void atamouse_interrupt(char *buf)
+{
+	int buttons, dx, dy;
+
+/*	ikbd_mouse_disable(); */
+
+	buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
+#ifdef FIXED_ATARI_JOYSTICK
+	buttons |= atari_mouse_buttons & 2;
+	atari_mouse_buttons = buttons;
+#endif
+/*	ikbd_mouse_rel_pos(); */
+
+	/* only relative events get here */
+	dx =  buf[1];
+	dy = -buf[2];
+
+	input_report_rel(atamouse_dev, REL_X, dx);
+	input_report_rel(atamouse_dev, REL_Y, dy);
+
+	input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x1);
+	input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
+	input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x4);
+
+	input_sync(atamouse_dev);
+
+	return;
+}
+
+static int atamouse_open(struct input_dev *dev)
+{
+	if (atamouse_used++)
+		return 0;
+
+#ifdef FIXED_ATARI_JOYSTICK
+	atari_mouse_buttons = 0;
+#endif
+	ikbd_mouse_y0_top();
+	ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]);
+	ikbd_mouse_rel_pos();
+	atari_input_mouse_interrupt_hook = atamouse_interrupt;
+	return 0;
+}
+
+static void atamouse_close(struct input_dev *dev)
+{
+	if (!--atamouse_used) {
+		ikbd_mouse_disable();
+		atari_mouse_interrupt_hook = NULL;
+	}
+}
+
+static int __init atamouse_init(void)
+{
+	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
+		return -ENODEV;
+
+	if (!(atamouse_dev = input_allocate_device()))
+		return -ENOMEM;
+
+	if (!(atari_keyb_init()))
+		return -ENODEV;
+
+	atamouse_dev->name = "Atari mouse";
+	atamouse_dev->phys = "atamouse/input0";
+	atamouse_dev->id.bustype = BUS_ATARI;
+	atamouse_dev->id.vendor = 0x0001;
+	atamouse_dev->id.product = 0x0002;
+	atamouse_dev->id.version = 0x0100;
+
+	atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+	atamouse_dev->open = atamouse_open;
+	atamouse_dev->close = atamouse_close;
+
+	input_register_device(atamouse_dev);
+
+	printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
+	return 0;
+}
+
+static void __exit atamouse_exit(void)
+{
+	input_unregister_device(atamouse_dev);
+}
+
+module_init(atamouse_init);
+module_exit(atamouse_exit);
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
index bfb174f..449bf4d 100644
--- a/drivers/input/mouse/hil_ptr.c
+++ b/drivers/input/mouse/hil_ptr.c
@@ -88,10 +88,12 @@ static void hil_ptr_process_record(struc
 	idx = ptr->idx4/4;
 	p = data[idx - 1];
 
-	if ((p & ~HIL_CMDCT_POL) == 
-	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
-	if ((p & ~HIL_CMDCT_RPL) == 
-	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+	if ((p & ~HIL_CMDCT_POL) ==
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+		goto report;
+	if ((p & ~HIL_CMDCT_RPL) ==
+	    (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+		goto report;
 
 	/* Not a poll response.  See if we are loading config records. */
 	switch (p & HIL_PKT_DATA_MASK) {
@@ -101,27 +103,32 @@ static void hil_ptr_process_record(struc
 		for (; i < HIL_PTR_MAX_LENGTH; i++)
 			ptr->idd[i] = 0;
 		break;
+
 	case HIL_CMD_RSC:
 		for (i = 0; i < idx; i++)
 			ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_PTR_MAX_LENGTH; i++)
 			ptr->rsc[i] = 0;
 		break;
+
 	case HIL_CMD_EXD:
 		for (i = 0; i < idx; i++)
 			ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_PTR_MAX_LENGTH; i++)
 			ptr->exd[i] = 0;
 		break;
+
 	case HIL_CMD_RNM:
 		for (i = 0; i < idx; i++)
 			ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
 		for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
-			ptr->rnm[i] = '\0';
+			ptr->rnm[i] = 0;
 		break;
+
 	default:
 		/* These occur when device isn't present */
-		if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break; 
+		if (p == (HIL_ERR_INT | HIL_PKT_CMD))
+			break;
 		/* Anything else we'd like to know about. */
 		printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
 		break;
@@ -130,7 +137,8 @@ static void hil_ptr_process_record(struc
 
  report:
 	if ((p & HIL_CMDCT_POL) != idx - 1) {
-		printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
+		printk(KERN_WARNING PREFIX
+			"Malformed poll packet %x (idx = %i)\n", p, idx);
 		goto out;
 	}
 
@@ -139,7 +147,7 @@ static void hil_ptr_process_record(struc
 	laxis += i;
 
 	ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
-	absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; 
+	absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
 
 	for (cnt = 1; i < laxis; i++) {
 		unsigned int lo,hi,val;
@@ -157,7 +165,8 @@ #endif
 			input_report_abs(dev, ABS_X + i, val);
 		} else {
 			val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
-			if (i%3) val *= -1;
+			if (i%3)
+				val *= -1;
 			input_report_rel(dev, REL_X + i, val);
 		}
 	}
@@ -168,10 +177,11 @@ #endif
 		btn = ptr->data[cnt++];
 		up = btn & 1;
 		btn &= 0xfe;
-		if (btn == 0x8e) {
+		if (btn == 0x8e)
 			continue; /* TODO: proximity == touch? */
-		}
-		else if ((btn > 0x8c) || (btn < 0x80)) continue;
+		else
+			if ((btn > 0x8c) || (btn < 0x80))
+				continue;
 		btn = (btn - 0x80) >> 1;
 		btn = ptr->btnmap[btn];
 		input_report_key(dev, btn, !up);
@@ -182,14 +192,14 @@ #endif
 	up(&ptr->sem);
 }
 
-static void hil_ptr_process_err(struct hil_ptr *ptr) {
+static void hil_ptr_process_err(struct hil_ptr *ptr)
+{
 	printk(KERN_WARNING PREFIX "errored HIL packet\n");
 	ptr->idx4 = 0;
 	up(&ptr->sem);
-	return;
 }
 
-static irqreturn_t hil_ptr_interrupt(struct serio *serio, 
+static irqreturn_t hil_ptr_interrupt(struct serio *serio,
         unsigned char data, unsigned int flags)
 {
 	struct hil_ptr *ptr;
@@ -197,29 +207,29 @@ static irqreturn_t hil_ptr_interrupt(str
 	int idx;
 
 	ptr = serio_get_drvdata(serio);
-	if (ptr == NULL) {
-		BUG();
-		return IRQ_HANDLED;
-	}
+	BUG_ON(ptr == NULL);
 
 	if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
 		hil_ptr_process_err(ptr);
 		return IRQ_HANDLED;
 	}
 	idx = ptr->idx4/4;
-	if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
+	if (!(ptr->idx4 % 4))
+		ptr->data[idx] = 0;
 	packet = ptr->data[idx];
 	packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
 	ptr->data[idx] = packet;
 
 	/* Records of N 4-byte hil_packets must terminate with a command. */
-	if ((++(ptr->idx4)) % 4) return IRQ_HANDLED;
+	if ((++(ptr->idx4)) % 4)
+		return IRQ_HANDLED;
 	if ((packet & 0xffff0000) != HIL_ERR_INT) {
 		hil_ptr_process_err(ptr);
 		return IRQ_HANDLED;
 	}
-	if (packet & HIL_PKT_CMD) 
+	if (packet & HIL_PKT_CMD)
 		hil_ptr_process_record(ptr);
+
 	return IRQ_HANDLED;
 }
 
@@ -228,10 +238,7 @@ static void hil_ptr_disconnect(struct se
 	struct hil_ptr *ptr;
 
 	ptr = serio_get_drvdata(serio);
-	if (ptr == NULL) {
-		BUG();
-		return;
-	}
+	BUG_ON(ptr == NULL);
 
 	serio_close(serio);
 	input_unregister_device(ptr->dev);
@@ -241,7 +248,7 @@ static void hil_ptr_disconnect(struct se
 static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
 {
 	struct hil_ptr	 *ptr;
-	char		 *txt;
+	const char	 *txt;
 	unsigned int	 i, naxsets, btntype;
 	uint8_t		 did, *idd;
 
@@ -252,42 +259,40 @@ static int hil_ptr_connect(struct serio 
 	if (!ptr->dev)
 		goto bail0;
 
-	ptr->dev->private = ptr;
-
 	if (serio_open(serio, driver))
 		goto bail1;
 
 	serio_set_drvdata(serio, ptr);
 	ptr->serio = serio;
 
-	init_MUTEX_LOCKED(&(ptr->sem));
+	init_MUTEX_LOCKED(&ptr->sem);
 
 	/* Get device info.  MLC driver supplies devid/status/etc. */
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_IDD);
-	down(&(ptr->sem));
+	down(&ptr->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_RSC);
-	down(&(ptr->sem));
+	down(&ptr->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_RNM);
-	down(&(ptr->sem));
+	down(&ptr->sem);
 
 	serio->write(serio, 0);
 	serio->write(serio, 0);
 	serio->write(serio, HIL_PKT_CMD >> 8);
 	serio->write(serio, HIL_CMD_EXD);
-	down(&(ptr->sem));
+	down(&ptr->sem);
 
-	up(&(ptr->sem));
+	up(&ptr->sem);
 
 	did = ptr->idd[0];
 	idd = ptr->idd + 1;
@@ -301,12 +306,12 @@ static int hil_ptr_connect(struct serio 
 		ptr->dev->evbit[0] = BIT(EV_ABS);
 		txt = "absolute";
 	}
-	if (!ptr->dev->evbit[0]) {
+	if (!ptr->dev->evbit[0])
 		goto bail2;
-	}
 
 	ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
-	if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY);
+	if (ptr->nbtn)
+		ptr->dev->evbit[0] |= BIT(EV_KEY);
 
 	naxsets = HIL_IDD_NUM_AXSETS(*idd);
 	ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
@@ -315,7 +320,7 @@ static int hil_ptr_connect(struct serio 
 			did, txt);
 	printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
 			ptr->nbtn, naxsets, ptr->naxes);
-	
+
 	btntype = BTN_MISC;
 	if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
 #ifdef TABLET_SIMULATES_MOUSE
@@ -325,7 +330,7 @@ #else
 #endif
 	if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
 		btntype = BTN_TOUCH;
-		
+
 	if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
 		btntype = BTN_MOUSE;
 
@@ -341,12 +346,10 @@ #endif
 	}
 
 	if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
-		for (i = 0; i < ptr->naxes; i++) {
+		for (i = 0; i < ptr->naxes; i++)
 			set_bit(REL_X + i, ptr->dev->relbit);
-		}
-		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+		for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++)
 			set_bit(REL_X + i, ptr->dev->relbit);
-		}
 	} else {
 		for (i = 0; i < ptr->naxes; i++) {
 			set_bit(ABS_X + i, ptr->dev->absbit);
@@ -375,7 +378,7 @@ #endif
 	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->cdev.dev	= &serio->dev;
+	ptr->dev->dev.parent	= &serio->dev;
 
 	input_register_device(ptr->dev);
 	printk(KERN_INFO "input: %s (%s), ID: %d\n",
@@ -419,11 +422,11 @@ static int __init hil_ptr_init(void)
 {
 	return serio_register_driver(&hil_ptr_serio_driver);
 }
-                
+
 static void __exit hil_ptr_exit(void)
 {
 	serio_unregister_driver(&hil_ptr_serio_driver);
 }
-                        
+
 module_init(hil_ptr_init);
 module_exit(hil_ptr_exit);
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 29542f0..1740cad 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -20,6 +20,27 @@ #include <linux/dmi.h>
 #include "psmouse.h"
 #include "lifebook.h"
 
+struct lifebook_data {
+	struct input_dev *dev2;		/* Relative device */
+	char phys[32];
+};
+
+static const char *desired_serio_phys;
+
+static int lifebook_set_serio_phys(struct dmi_system_id *d)
+{
+	desired_serio_phys = d->driver_data;
+	return 0;
+}
+
+static unsigned char lifebook_use_6byte_proto;
+
+static int lifebook_set_6byte_proto(struct dmi_system_id *d)
+{
+	lifebook_use_6byte_proto = 1;
+	return 0;
+}
+
 static struct dmi_system_id lifebook_dmi_table[] = {
 	{
 		.ident = "FLORA-ie 55mi",
@@ -56,6 +77,24 @@ static struct dmi_system_id lifebook_dmi
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
 		},
+		.callback = lifebook_set_serio_phys,
+		.driver_data = "isa0060/serio3",
+	},
+	{
+		.ident = "Panasonic CF-28",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
+		},
+		.callback = lifebook_set_6byte_proto,
+	},
+	{
+		.ident = "Panasonic CF-29",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+		},
+		.callback = lifebook_set_6byte_proto,
 	},
 	{
 		.ident = "Lifebook B142",
@@ -68,30 +107,70 @@ static struct dmi_system_id lifebook_dmi
 
 static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 {
+	struct lifebook_data *priv = psmouse->private;
+	struct input_dev *dev1 = psmouse->dev;
+	struct input_dev *dev2 = priv->dev2;
 	unsigned char *packet = psmouse->packet;
-	struct input_dev *dev = psmouse->dev;
+	int relative_packet = packet[0] & 0x08;
 
-	if (psmouse->pktcnt != 3)
-		return PSMOUSE_GOOD_DATA;
+	if (relative_packet || !lifebook_use_6byte_proto) {
+		if (psmouse->pktcnt != 3)
+			return PSMOUSE_GOOD_DATA;
+	} else {
+		switch (psmouse->pktcnt) {
+		case 1:
+			return (packet[0] & 0xf8) == 0x00 ?
+				PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+		case 2:
+			return PSMOUSE_GOOD_DATA;
+		case 3:
+			return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
+				PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+		case 4:
+			return (packet[3] & 0xf8) == 0xc0 ?
+				PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+		case 5:
+			return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
+				PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+		case 6:
+			if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
+				return PSMOUSE_BAD_DATA;
+			if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
+				return PSMOUSE_BAD_DATA;
+			break; /* report data */
+		}
+	}
 
-	/* calculate X and Y */
-	if ((packet[0] & 0x08) == 0x00) {
-		input_report_abs(dev, ABS_X,
+	if (relative_packet) {
+		if (!dev2)
+			printk(KERN_WARNING "lifebook.c: got relative packet "
+				"but no relative device set up\n");
+	} else if (lifebook_use_6byte_proto) {
+		input_report_abs(dev1, ABS_X,
+				 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
+		input_report_abs(dev1, ABS_Y,
+				 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
+	} else {
+		input_report_abs(dev1, ABS_X,
 				 (packet[1] | ((packet[0] & 0x30) << 4)));
-		input_report_abs(dev, ABS_Y,
+		input_report_abs(dev1, ABS_Y,
 				 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
-	} else {
-		input_report_rel(dev, REL_X,
-				((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
-		input_report_rel(dev, REL_Y,
-				 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
 	}
 
-	input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
-	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
-	input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+	input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
+	input_sync(dev1);
 
-	input_sync(dev);
+	if (dev2) {
+		if (relative_packet) {
+			input_report_rel(dev2, REL_X,
+				((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+			input_report_rel(dev2, REL_Y,
+				 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+		}
+		input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
+		input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
+		input_sync(dev2);
+	}
 
 	return PSMOUSE_FULL_PACKET;
 }
@@ -109,12 +188,20 @@ static int lifebook_absolute_mode(struct
 	   you leave this call out the touchsreen will never send
 	   absolute coordinates
 	*/
-	param = 0x07;
+	param = lifebook_use_6byte_proto ? 0x08 : 0x07;
 	ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
 
 	return 0;
 }
 
+static void lifebook_relative_mode(struct psmouse *psmouse)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char param = 0x06;
+
+	ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+}
+
 static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 {
 	static const unsigned char params[] = { 0, 1, 2, 2, 3 };
@@ -131,6 +218,8 @@ static void lifebook_set_resolution(stru
 static void lifebook_disconnect(struct psmouse *psmouse)
 {
 	psmouse_reset(psmouse);
+	kfree(psmouse->private);
+	psmouse->private = NULL;
 }
 
 int lifebook_detect(struct psmouse *psmouse, int set_properties)
@@ -138,6 +227,10 @@ int lifebook_detect(struct psmouse *psmo
         if (!dmi_check_system(lifebook_dmi_table))
                 return -1;
 
+	if (desired_serio_phys &&
+	    strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
+		return -1;
+
 	if (set_properties) {
 		psmouse->vendor = "Fujitsu";
 		psmouse->name = "Lifebook TouchScreen";
@@ -146,24 +239,78 @@ int lifebook_detect(struct psmouse *psmo
         return 0;
 }
 
+static int lifebook_create_relative_device(struct psmouse *psmouse)
+{
+	struct input_dev *dev2;
+	struct lifebook_data *priv;
+	int error = -ENOMEM;
+
+	priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
+	dev2 = input_allocate_device();
+	if (!priv || !dev2)
+		goto err_out;
+
+	priv->dev2 = dev2;
+	snprintf(priv->phys, sizeof(priv->phys),
+		 "%s/input1", psmouse->ps2dev.serio->phys);
+
+	dev2->phys = priv->phys;
+	dev2->name = "PS/2 Touchpad";
+	dev2->id.bustype = BUS_I8042;
+	dev2->id.vendor  = 0x0002;
+	dev2->id.product = PSMOUSE_LIFEBOOK;
+	dev2->id.version = 0x0000;
+	dev2->dev.parent = &psmouse->ps2dev.serio->dev;
+
+	dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y);
+	dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+
+	error = input_register_device(priv->dev2);
+	if (error)
+		goto err_out;
+
+	psmouse->private = priv;
+	return 0;
+
+ err_out:
+	input_free_device(dev2);
+	kfree(priv);
+	return error;
+}
+
 int lifebook_init(struct psmouse *psmouse)
 {
-	struct input_dev *input_dev = psmouse->dev;
+	struct input_dev *dev1 = psmouse->dev;
+	int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
 
 	if (lifebook_absolute_mode(psmouse))
 		return -1;
 
-	input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
-	input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0);
+	dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+	dev1->relbit[0] = 0;
+	dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
+	input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
+
+	if (!desired_serio_phys) {
+		if (lifebook_create_relative_device(psmouse)) {
+			lifebook_relative_mode(psmouse);
+			return -1;
+		}
+	}
 
 	psmouse->protocol_handler = lifebook_process_byte;
 	psmouse->set_resolution = lifebook_set_resolution;
 	psmouse->disconnect = lifebook_disconnect;
 	psmouse->reconnect  = lifebook_absolute_mode;
+
+	psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
+
+	/*
+	 * Use packet size = 3 even when using 6-byte protocol because
+	 * that's what POLL will return on Lifebooks (according to spec).
+	 */
 	psmouse->pktsize = 3;
 
 	return 0;
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
index be1c094..c1647cf 100644
--- a/drivers/input/mouse/lifebook.h
+++ b/drivers/input/mouse/lifebook.h
@@ -11,7 +11,18 @@
 #ifndef _LIFEBOOK_H
 #define _LIFEBOOK_H
 
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
 int lifebook_detect(struct psmouse *psmouse, int set_properties);
 int lifebook_init(struct psmouse *psmouse);
+#else
+inline int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+	return -ENOSYS;
+}
+inline int lifebook_init(struct psmouse *psmouse)
+{
+	return -ENOSYS;
+}
+#endif
 
 #endif
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index d3ddea2..9df74b7 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -200,6 +200,7 @@ static void ps2pp_disconnect(struct psmo
 static const struct ps2pp_info *get_model_info(unsigned char model)
 {
 	static const struct ps2pp_info ps2pp_list[] = {
+		{  1,	0,			0 },	/* Simple 2-button mouse */
 		{ 12,	0,			PS2PP_SIDE_BTN},
 		{ 13,	0,			0 },
 		{ 15,	PS2PP_KIND_MX,					/* MX1000 */
@@ -338,12 +339,12 @@ int ps2pp_init(struct psmouse *psmouse, 
 	param[1] = 0;
 	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 
-	if (!param[1])
-		return -1;
-
 	model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
 	buttons = param[1];
 
+	if (!model || !buttons)
+		return -1;
+
 	if ((model_info = get_model_info(model)) != NULL) {
 
 /*
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
index 64a8ec5..6e57125 100644
--- a/drivers/input/mouse/logips2pp.h
+++ b/drivers/input/mouse/logips2pp.h
@@ -11,6 +11,13 @@
 #ifndef _LOGIPS2PP_H
 #define _LOGIPS2PP_H
 
+#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
 int ps2pp_init(struct psmouse *psmouse, int set_properties);
+#else
+inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */
 
 #endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0fe5869..f15f695 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -28,6 +28,7 @@ #include "logips2pp.h"
 #include "alps.h"
 #include "lifebook.h"
 #include "trackpoint.h"
+#include "touchkit_ps2.h"
 
 #define DRIVER_DESC	"PS/2 mouse driver"
 
@@ -569,7 +570,9 @@ static int psmouse_extensions(struct psm
 		return PSMOUSE_THINKPS;
 
 /*
- * Try Synaptics TouchPad
+ * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
+ * support is disabled in config - we need to know if it is synaptics so we
+ * can reset it properly after probing for intellimouse.
  */
 	if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
 		synaptics_hardware = 1;
@@ -605,14 +608,20 @@ static int psmouse_extensions(struct psm
 		}
 	}
 
-	if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
-		return PSMOUSE_GENPS;
+	if (max_proto > PSMOUSE_IMEX) {
+
+		if (genius_detect(psmouse, set_properties) == 0)
+			return PSMOUSE_GENPS;
 
-	if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
-		return PSMOUSE_PS2PP;
+		if (ps2pp_init(psmouse, set_properties) == 0)
+			return PSMOUSE_PS2PP;
 
-	if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
-		return PSMOUSE_TRACKPOINT;
+		if (trackpoint_detect(psmouse, set_properties) == 0)
+			return PSMOUSE_TRACKPOINT;
+
+		if (touchkit_ps2_detect(psmouse, set_properties) == 0)
+			return PSMOUSE_TOUCHKIT_PS2;
+	}
 
 /*
  * Reset to defaults in case the device got confused by extended
@@ -654,12 +663,14 @@ static const struct psmouse_protocol psm
 		.maxproto	= 1,
 		.detect		= ps2bare_detect,
 	},
+#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
 	{
 		.type		= PSMOUSE_PS2PP,
 		.name		= "PS2++",
 		.alias		= "logitech",
 		.detect		= ps2pp_init,
 	},
+#endif
 	{
 		.type		= PSMOUSE_THINKPS,
 		.name		= "ThinkPS/2",
@@ -686,6 +697,7 @@ static const struct psmouse_protocol psm
 		.maxproto	= 1,
 		.detect		= im_explorer_detect,
 	},
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
 	{
 		.type		= PSMOUSE_SYNAPTICS,
 		.name		= "SynPS/2",
@@ -693,6 +705,8 @@ static const struct psmouse_protocol psm
 		.detect		= synaptics_detect,
 		.init		= synaptics_init,
 	},
+#endif
+#ifdef CONFIG_MOUSE_PS2_ALPS
 	{
 		.type		= PSMOUSE_ALPS,
 		.name		= "AlpsPS/2",
@@ -700,18 +714,31 @@ static const struct psmouse_protocol psm
 		.detect		= alps_detect,
 		.init		= alps_init,
 	},
+#endif
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
 	{
 		.type		= PSMOUSE_LIFEBOOK,
 		.name		= "LBPS/2",
 		.alias		= "lifebook",
 		.init		= lifebook_init,
 	},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
 	{
 		.type		= PSMOUSE_TRACKPOINT,
 		.name		= "TPPS/2",
 		.alias		= "trackpoint",
 		.detect		= trackpoint_detect,
 	},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
+	{
+		.type		= PSMOUSE_TOUCHKIT_PS2,
+		.name		= "touchkitPS/2",
+		.alias		= "touchkit",
+		.detect		= touchkit_ps2_detect,
+	},
+#endif
 	{
 		.type		= PSMOUSE_AUTO,
 		.name		= "auto",
@@ -823,12 +850,6 @@ static void psmouse_set_rate(struct psmo
 static void psmouse_initialize(struct psmouse *psmouse)
 {
 /*
- * We set the mouse into streaming mode.
- */
-
-	ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
-
-/*
  * We set the mouse report rate, resolution and scaling.
  */
 
@@ -1062,8 +1083,7 @@ static int psmouse_switch_protocol(struc
 {
 	struct input_dev *input_dev = psmouse->dev;
 
-	input_dev->private = psmouse;
-	input_dev->cdev.dev = &psmouse->ps2dev.serio->dev;
+	input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index cf1de95..3964e8a 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -87,6 +87,7 @@ enum psmouse_type {
 	PSMOUSE_ALPS,
 	PSMOUSE_LIFEBOOK,
 	PSMOUSE_TRACKPOINT,
+	PSMOUSE_TOUCHKIT_PS2,
 	PSMOUSE_AUTO		/* This one should always be last */
 };
 
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index a85d747..77b8ee2 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -69,7 +69,8 @@ static void sermouse_process_msc(struct 
 	switch (sermouse->count) {
 
 		case 0:
-			if ((data & 0xf8) != 0x80) return;
+			if ((data & 0xf8) != 0x80)
+				return;
 			input_report_key(dev, BTN_LEFT,   !(data & 4));
 			input_report_key(dev, BTN_RIGHT,  !(data & 1));
 			input_report_key(dev, BTN_MIDDLE, !(data & 2));
@@ -107,7 +108,10 @@ static void sermouse_process_ms(struct s
 	struct input_dev *dev = sermouse->dev;
 	signed char *buf = sermouse->buf;
 
-	if (data & 0x40) sermouse->count = 0;
+	if (data & 0x40)
+		sermouse->count = 0;
+	else if (sermouse->count == 0)
+		return;
 
 	switch (sermouse->count) {
 
@@ -169,7 +173,8 @@ static void sermouse_process_ms(struct s
 
 		case 5:
 		case 7: /* Ignore anything besides MZ++ */
-			if (sermouse->type != SERIO_MZPP) break;
+			if (sermouse->type != SERIO_MZPP)
+				break;
 
 			switch (buf[1]) {
 
@@ -206,13 +211,16 @@ static irqreturn_t sermouse_interrupt(st
 {
 	struct sermouse *sermouse = serio_get_drvdata(serio);
 
-	if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
+	if (time_after(jiffies, sermouse->last + HZ/10))
+		sermouse->count = 0;
+
 	sermouse->last = jiffies;
 
 	if (sermouse->type > SERIO_SUN)
 		sermouse_process_ms(sermouse, data);
 	else
 		sermouse_process_msc(sermouse, data);
+
 	return IRQ_HANDLED;
 }
 
@@ -258,12 +266,11 @@ static int sermouse_connect(struct serio
 	input_dev->id.vendor  = sermouse->type;
 	input_dev->id.product = c;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
 	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	input_dev->private = sermouse;
 
 	if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
 	if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f0f9413..666ad3a 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -40,33 +40,70 @@ #define XMAX_NOMINAL 5472
 #define YMIN_NOMINAL 1408
 #define YMAX_NOMINAL 4448
 
+
 /*****************************************************************************
- *	Synaptics communications functions
+ *	Stuff we need even when we do not want native Synaptics support
  ****************************************************************************/
 
 /*
- * Send a command to the synpatics touchpad by special commands
+ * Set the synaptics touchpad mode byte by special commands
  */
-static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
 {
-	if (psmouse_sliced_command(psmouse, c))
+	unsigned char param[1];
+
+	if (psmouse_sliced_command(psmouse, mode))
 		return -1;
-	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
+	param[0] = SYN_PS_SET_MODE2;
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
 		return -1;
 	return 0;
 }
 
+int synaptics_detect(struct psmouse *psmouse, int set_properties)
+{
+	struct ps2dev *ps2dev = &psmouse->ps2dev;
+	unsigned char param[4];
+
+	param[0] = 0;
+
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
+
+	if (param[1] != 0x47)
+		return -ENODEV;
+
+	if (set_properties) {
+		psmouse->vendor = "Synaptics";
+		psmouse->name = "TouchPad";
+	}
+
+	return 0;
+}
+
+void synaptics_reset(struct psmouse *psmouse)
+{
+	/* reset touchpad back to relative mode, gestures enabled */
+	synaptics_mode_cmd(psmouse, 0);
+}
+
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+/*****************************************************************************
+ *	Synaptics communications functions
+ ****************************************************************************/
+
 /*
- * Set the synaptics touchpad mode byte by special commands
+ * Send a command to the synpatics touchpad by special commands
  */
-static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
 {
-	unsigned char param[1];
-
-	if (psmouse_sliced_command(psmouse, mode))
+	if (psmouse_sliced_command(psmouse, c))
 		return -1;
-	param[0] = SYN_PS_SET_MODE2;
-	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
+	if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
 		return -1;
 	return 0;
 }
@@ -148,7 +185,7 @@ static int synaptics_query_hardware(stru
 	int retries = 0;
 
 	while ((retries++ < 3) && psmouse_reset(psmouse))
-		printk(KERN_ERR "synaptics reset failed\n");
+		/* empty */;
 
 	if (synaptics_identify(psmouse))
 		return -1;
@@ -529,12 +566,6 @@ static void set_input_params(struct inpu
 	clear_bit(REL_Y, dev->relbit);
 }
 
-void synaptics_reset(struct psmouse *psmouse)
-{
-	/* reset touchpad back to relative mode, gestures enabled */
-	synaptics_mode_cmd(psmouse, 0);
-}
-
 static void synaptics_disconnect(struct psmouse *psmouse)
 {
 	synaptics_reset(psmouse);
@@ -569,30 +600,6 @@ static int synaptics_reconnect(struct ps
 	return 0;
 }
 
-int synaptics_detect(struct psmouse *psmouse, int set_properties)
-{
-	struct ps2dev *ps2dev = &psmouse->ps2dev;
-	unsigned char param[4];
-
-	param[0] = 0;
-
-	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
-	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
-	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
-	ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
-	ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
-
-	if (param[1] != 0x47)
-		return -1;
-
-	if (set_properties) {
-		psmouse->vendor = "Synaptics";
-		psmouse->name = "TouchPad";
-	}
-
-	return 0;
-}
-
 #if defined(__i386__)
 #include <linux/dmi.h>
 static struct dmi_system_id toshiba_dmi_table[] = {
@@ -648,6 +655,16 @@ int synaptics_init(struct psmouse *psmou
 
 	set_input_params(psmouse->dev, priv);
 
+	/*
+	 * Encode touchpad model so that it can be used to set
+	 * input device->id.version and be visible to userspace.
+	 * Because version is __u16 we have to drop something.
+	 * Hardware info bits seem to be good candidates as they
+	 * are documented to be for Synaptics corp. internal use.
+	 */
+	psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
+			  (priv->model_id & 0x000000ff);
+
 	psmouse->protocol_handler = synaptics_process_byte;
 	psmouse->set_rate = synaptics_set_rate;
 	psmouse->disconnect = synaptics_disconnect;
@@ -680,4 +697,12 @@ #endif
 	return -1;
 }
 
+#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
+
+int synaptics_init(struct psmouse *psmouse)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
 
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 68fff1d..02aa4cf 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -9,10 +9,6 @@
 #ifndef _SYNAPTICS_H
 #define _SYNAPTICS_H
 
-extern int synaptics_detect(struct psmouse *psmouse, int set_properties);
-extern int synaptics_init(struct psmouse *psmouse);
-extern void synaptics_reset(struct psmouse *psmouse);
-
 /* synaptics queries */
 #define SYN_QUE_IDENTIFY		0x00
 #define SYN_QUE_MODES			0x01
@@ -62,9 +58,9 @@ #define SYN_MODE_PACKSIZE(m)		((m) & (1 
 #define SYN_MODE_WMODE(m)		((m) & (1 << 0))
 
 /* synaptics identify query bits */
-#define SYN_ID_MODEL(i) 		(((i) >> 4) & 0x0f)
-#define SYN_ID_MAJOR(i) 		((i) & 0x0f)
-#define SYN_ID_MINOR(i) 		(((i) >> 16) & 0xff)
+#define SYN_ID_MODEL(i)			(((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i)			((i) & 0x0f)
+#define SYN_ID_MINOR(i)			(((i) >> 16) & 0xff)
 #define SYN_ID_IS_SYNAPTICS(i)		((((i) >> 8) & 0xff) == 0x47)
 
 /* synaptics special commands */
@@ -98,8 +94,8 @@ struct synaptics_hw_state {
 struct synaptics_data {
 	/* Data read from the touchpad */
 	unsigned long int model_id;		/* Model-ID */
-	unsigned long int capabilities; 	/* Capabilities */
-	unsigned long int ext_cap; 		/* Extended Capabilities */
+	unsigned long int capabilities;		/* Capabilities */
+	unsigned long int ext_cap;		/* Extended Capabilities */
 	unsigned long int identity;		/* Identification */
 
 	unsigned char pkt_type;			/* packet type - old, new, etc */
@@ -107,4 +103,8 @@ struct synaptics_data {
 	int scroll;
 };
 
+int synaptics_detect(struct psmouse *psmouse, int set_properties);
+int synaptics_init(struct psmouse *psmouse);
+void synaptics_reset(struct psmouse *psmouse);
+
 #endif /* _SYNAPTICS_H */
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
new file mode 100644
index 0000000..7b977fd
--- /dev/null
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -0,0 +1,100 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.c  --  Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (C) 2004 by Daniel Ritz
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon touchkitusb.c
+ *
+ * Vendor documentation is available in support section of:
+ * http://www.egalax.com.tw/
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+
+#include "psmouse.h"
+#include "touchkit_ps2.h"
+
+#define TOUCHKIT_MAX_XC			0x07ff
+#define TOUCHKIT_MAX_YC			0x07ff
+
+#define TOUCHKIT_CMD			0x0a
+#define TOUCHKIT_CMD_LENGTH		1
+
+#define TOUCHKIT_CMD_ACTIVE		'A'
+#define TOUCHKIT_CMD_FIRMWARE_VERSION	'D'
+#define TOUCHKIT_CMD_CONTROLLER_TYPE	'E'
+
+#define TOUCHKIT_SEND_PARMS(s, r, c)	((s) << 12 | (r) << 8 | (c))
+
+#define TOUCHKIT_GET_TOUCHED(packet)	(((packet)[0]) & 0x01)
+#define TOUCHKIT_GET_X(packet)		(((packet)[1] << 7) | (packet)[2])
+#define TOUCHKIT_GET_Y(packet)		(((packet)[3] << 7) | (packet)[4])
+
+static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
+{
+	unsigned char *packet = psmouse->packet;
+	struct input_dev *dev = psmouse->dev;
+
+	if (psmouse->pktcnt != 5)
+		return PSMOUSE_GOOD_DATA;
+
+	input_report_abs(dev, ABS_X, TOUCHKIT_GET_X(packet));
+	input_report_abs(dev, ABS_Y, TOUCHKIT_GET_Y(packet));
+	input_report_key(dev, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(packet));
+	input_sync(dev);
+
+	return PSMOUSE_FULL_PACKET;
+}
+
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+{
+	struct input_dev *dev = psmouse->dev;
+	unsigned char param[3];
+	int command;
+
+	param[0] = TOUCHKIT_CMD_LENGTH;
+	param[1] = TOUCHKIT_CMD_ACTIVE;
+	command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD);
+
+	if (ps2_command(&psmouse->ps2dev, param, command))
+		return -ENODEV;
+
+	if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 ||
+	    param[2] != TOUCHKIT_CMD_ACTIVE)
+		return -ENODEV;
+
+	if (set_properties) {
+		dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+		set_bit(BTN_TOUCH, dev->keybit);
+		input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
+		input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
+
+		psmouse->vendor = "eGalax";
+		psmouse->name = "Touchscreen";
+		psmouse->protocol_handler = touchkit_ps2_process_byte;
+		psmouse->pktsize = 5;
+	}
+
+	return 0;
+}
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
new file mode 100644
index 0000000..61e9dfd
--- /dev/null
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -0,0 +1,24 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.h  --  Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _TOUCHKIT_PS2_H
+#define _TOUCHKIT_PS2_H
+
+#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
+#else
+inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */
+
+#endif
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 050298b..c10a6e7 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -142,6 +142,13 @@ struct trackpoint_data
 	unsigned char ext_dev;
 };
 
-extern int trackpoint_detect(struct psmouse *psmouse, int set_properties);
+#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
+int trackpoint_detect(struct psmouse *psmouse, int set_properties);
+#else
+inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */
 
 #endif /* _TRACKPOINT_H */
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index c3d64fc..4a32157 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -508,8 +508,7 @@ vsxxxaa_connect (struct serio *serio, st
 	input_dev->name = mouse->name;
 	input_dev->phys = mouse->phys;
 	input_dev->id.bustype = BUS_RS232;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = mouse;
+	input_dev->dev.parent = &serio->dev;
 
 	set_bit (EV_KEY, input_dev->evbit);		/* We have buttons */
 	set_bit (EV_REL, input_dev->evbit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 664bcc8..8675f95 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -19,7 +19,6 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/input.h>
-#include <linux/smp_lock.h>
 #include <linux/random.h>
 #include <linux/major.h>
 #include <linux/device.h>
@@ -63,9 +62,12 @@ struct mousedev {
 	int minor;
 	char name[16];
 	wait_queue_head_t wait;
-	struct list_head list;
+	struct list_head client_list;
 	struct input_handle handle;
 
+	struct list_head mixdev_node;
+	int mixdev_open;
+
 	struct mousedev_hw_data packet;
 	unsigned int pkt_count;
 	int old_x[4], old_y[4];
@@ -85,7 +87,7 @@ struct mousedev_motion {
 };
 
 #define PACKET_QUEUE_LEN	16
-struct mousedev_list {
+struct mousedev_client {
 	struct fasync_struct *fasync;
 	struct mousedev *mousedev;
 	struct list_head node;
@@ -111,6 +113,7 @@ static struct input_handler mousedev_han
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
+static LIST_HEAD(mousedev_mix_list);
 
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -120,32 +123,33 @@ static void mousedev_touchpad_event(stru
 	int size, tmp;
 	enum { FRACTION_DENOM = 128 };
 
-	if (mousedev->touch) {
-		size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
-		if (size == 0)
-			size = 256 * 2;
-
-		switch (code) {
-			case ABS_X:
-				fx(0) = value;
-				if (mousedev->pkt_count >= 2) {
-					tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
-					tmp += mousedev->frac_dx;
-					mousedev->packet.dx = tmp / FRACTION_DENOM;
-					mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
-				}
-				break;
+	switch (code) {
+		case ABS_X:
+			fx(0) = value;
+			if (mousedev->touch && mousedev->pkt_count >= 2) {
+				size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+				if (size == 0)
+					size = 256 * 2;
+				tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+				tmp += mousedev->frac_dx;
+				mousedev->packet.dx = tmp / FRACTION_DENOM;
+				mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+			}
+			break;
 
-			case ABS_Y:
-				fy(0) = value;
-				if (mousedev->pkt_count >= 2) {
-					tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
-					tmp += mousedev->frac_dy;
-					mousedev->packet.dy = tmp / FRACTION_DENOM;
-					mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
-				}
-				break;
-		}
+		case ABS_Y:
+			fy(0) = value;
+			if (mousedev->touch && mousedev->pkt_count >= 2) {
+				/* use X size to keep the same scale */
+				size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+				if (size == 0)
+					size = 256 * 2;
+				tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+				tmp += mousedev->frac_dy;
+				mousedev->packet.dy = tmp / FRACTION_DENOM;
+				mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+			}
+			break;
 	}
 }
 
@@ -223,47 +227,47 @@ static void mousedev_key_event(struct mo
 
 static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
 {
-	struct mousedev_list *list;
+	struct mousedev_client *client;
 	struct mousedev_motion *p;
 	unsigned long flags;
 	int wake_readers = 0;
 
-	list_for_each_entry(list, &mousedev->list, node) {
-		spin_lock_irqsave(&list->packet_lock, flags);
+	list_for_each_entry(client, &mousedev->client_list, node) {
+		spin_lock_irqsave(&client->packet_lock, flags);
 
-		p = &list->packets[list->head];
-		if (list->ready && p->buttons != mousedev->packet.buttons) {
-			unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
-			if (new_head != list->tail) {
-				p = &list->packets[list->head = new_head];
+		p = &client->packets[client->head];
+		if (client->ready && p->buttons != mousedev->packet.buttons) {
+			unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+			if (new_head != client->tail) {
+				p = &client->packets[client->head = new_head];
 				memset(p, 0, sizeof(struct mousedev_motion));
 			}
 		}
 
 		if (packet->abs_event) {
-			p->dx += packet->x - list->pos_x;
-			p->dy += packet->y - list->pos_y;
-			list->pos_x = packet->x;
-			list->pos_y = packet->y;
+			p->dx += packet->x - client->pos_x;
+			p->dy += packet->y - client->pos_y;
+			client->pos_x = packet->x;
+			client->pos_y = packet->y;
 		}
 
-		list->pos_x += packet->dx;
-		list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
-		list->pos_y += packet->dy;
-		list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
+		client->pos_x += packet->dx;
+		client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
+		client->pos_y += packet->dy;
+		client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
 
 		p->dx += packet->dx;
 		p->dy += packet->dy;
 		p->dz += packet->dz;
 		p->buttons = mousedev->packet.buttons;
 
-		if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
-			list->ready = 1;
+		if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
+			client->ready = 1;
 
-		spin_unlock_irqrestore(&list->packet_lock, flags);
+		spin_unlock_irqrestore(&client->packet_lock, flags);
 
-		if (list->ready) {
-			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		if (client->ready) {
+			kill_fasync(&client->fasync, SIGIO, POLL_IN);
 			wake_readers = 1;
 		}
 	}
@@ -351,9 +355,9 @@ static void mousedev_event(struct input_
 static int mousedev_fasync(int fd, struct file *file, int on)
 {
 	int retval;
-	struct mousedev_list *list = file->private_data;
+	struct mousedev_client *client = file->private_data;
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
+	retval = fasync_helper(fd, file, on, &client->fasync);
 
 	return retval < 0 ? retval : 0;
 }
@@ -364,50 +368,95 @@ static void mousedev_free(struct mousede
 	kfree(mousedev);
 }
 
-static void mixdev_release(void)
+static int mixdev_add_device(struct mousedev *mousedev)
 {
-	struct input_handle *handle;
+	int error;
 
-	list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-		struct mousedev *mousedev = handle->private;
+	if (mousedev_mix.open) {
+		error = input_open_device(&mousedev->handle);
+		if (error)
+			return error;
 
-		if (!mousedev->open) {
-			if (mousedev->exist)
-				input_close_device(&mousedev->handle);
-			else
-				mousedev_free(mousedev);
+		mousedev->open++;
+		mousedev->mixdev_open++;
+	}
+
+	list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+	return 0;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
+{
+	if (mousedev->mixdev_open) {
+		mousedev->mixdev_open = 0;
+		if (!--mousedev->open && mousedev->exist)
+			input_close_device(&mousedev->handle);
+	}
+
+	list_del_init(&mousedev->mixdev_node);
+}
+
+static void mixdev_open_devices(void)
+{
+	struct mousedev *mousedev;
+
+	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+		if (mousedev->exist && !mousedev->open) {
+			if (input_open_device(&mousedev->handle))
+				continue;
+
+			mousedev->open++;
+			mousedev->mixdev_open++;
+		}
+	}
+}
+
+static void mixdev_close_devices(void)
+{
+	struct mousedev *mousedev, *next;
+
+	list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
+		if (mousedev->mixdev_open) {
+			mousedev->mixdev_open = 0;
+			if (!--mousedev->open) {
+				if (mousedev->exist)
+					input_close_device(&mousedev->handle);
+				else
+					mousedev_free(mousedev);
+			}
 		}
 	}
 }
 
-static int mousedev_release(struct inode * inode, struct file * file)
+static int mousedev_release(struct inode *inode, struct file *file)
 {
-	struct mousedev_list *list = file->private_data;
+	struct mousedev_client *client = file->private_data;
+	struct mousedev *mousedev = client->mousedev;
 
 	mousedev_fasync(-1, file, 0);
 
-	list_del(&list->node);
+	list_del(&client->node);
+	kfree(client);
 
-	if (!--list->mousedev->open) {
-		if (list->mousedev->minor == MOUSEDEV_MIX)
-			mixdev_release();
-		else if (!mousedev_mix.open) {
-			if (list->mousedev->exist)
-				input_close_device(&list->mousedev->handle);
-			else
-				mousedev_free(list->mousedev);
-		}
+	if (!--mousedev->open) {
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_close_devices();
+		else if (mousedev->exist)
+			input_close_device(&mousedev->handle);
+		else
+			mousedev_free(mousedev);
 	}
 
-	kfree(list);
 	return 0;
 }
 
-static int mousedev_open(struct inode * inode, struct file * file)
+
+static int mousedev_open(struct inode *inode, struct file *file)
 {
-	struct mousedev_list *list;
-	struct input_handle *handle;
+	struct mousedev_client *client;
 	struct mousedev *mousedev;
+	int error;
 	int i;
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -417,31 +466,37 @@ #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
 #endif
 		i = iminor(inode) - MOUSEDEV_MINOR_BASE;
 
-	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
+	if (i >= MOUSEDEV_MINORS)
+		return -ENODEV;
+
+	mousedev = mousedev_table[i];
+	if (!mousedev)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
+	client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
+	if (!client)
 		return -ENOMEM;
 
-	spin_lock_init(&list->packet_lock);
-	list->pos_x = xres / 2;
-	list->pos_y = yres / 2;
-	list->mousedev = mousedev_table[i];
-	list_add_tail(&list->node, &mousedev_table[i]->list);
-	file->private_data = list;
-
-	if (!list->mousedev->open++) {
-		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-				mousedev = handle->private;
-				if (!mousedev->open && mousedev->exist)
-					input_open_device(handle);
+	spin_lock_init(&client->packet_lock);
+	client->pos_x = xres / 2;
+	client->pos_y = yres / 2;
+	client->mousedev = mousedev;
+	list_add_tail(&client->node, &mousedev->client_list);
+
+	if (!mousedev->open++) {
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_open_devices();
+		else if (mousedev->exist) {
+			error = input_open_device(&mousedev->handle);
+			if (error) {
+				list_del(&client->node);
+				kfree(client);
+				return error;
 			}
-		} else
-			if (!mousedev_mix.open && list->mousedev->exist)
-				input_open_device(&list->mousedev->handle);
+		}
 	}
 
+	file->private_data = client;
 	return 0;
 }
 
@@ -450,13 +505,13 @@ static inline int mousedev_limit_delta(i
 	return delta > limit ? limit : (delta < -limit ? -limit : delta);
 }
 
-static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
 {
 	struct mousedev_motion *p;
 	unsigned long flags;
 
-	spin_lock_irqsave(&list->packet_lock, flags);
-	p = &list->packets[list->tail];
+	spin_lock_irqsave(&client->packet_lock, flags);
+	p = &client->packets[client->tail];
 
 	ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
 	ps2_data[1] = mousedev_limit_delta(p->dx, 127);
@@ -464,44 +519,44 @@ static void mousedev_packet(struct mouse
 	p->dx -= ps2_data[1];
 	p->dy -= ps2_data[2];
 
-	switch (list->mode) {
+	switch (client->mode) {
 		case MOUSEDEV_EMUL_EXPS:
 			ps2_data[3] = mousedev_limit_delta(p->dz, 7);
 			p->dz -= ps2_data[3];
 			ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
-			list->bufsiz = 4;
+			client->bufsiz = 4;
 			break;
 
 		case MOUSEDEV_EMUL_IMPS:
 			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
 			ps2_data[3] = mousedev_limit_delta(p->dz, 127);
 			p->dz -= ps2_data[3];
-			list->bufsiz = 4;
+			client->bufsiz = 4;
 			break;
 
 		case MOUSEDEV_EMUL_PS2:
 		default:
 			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
 			p->dz = 0;
-			list->bufsiz = 3;
+			client->bufsiz = 3;
 			break;
 	}
 
 	if (!p->dx && !p->dy && !p->dz) {
-		if (list->tail == list->head) {
-			list->ready = 0;
-			list->last_buttons = p->buttons;
+		if (client->tail == client->head) {
+			client->ready = 0;
+			client->last_buttons = p->buttons;
 		} else
-			list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
+			client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
 	}
 
-	spin_unlock_irqrestore(&list->packet_lock, flags);
+	spin_unlock_irqrestore(&client->packet_lock, flags);
 }
 
 
-static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct mousedev_list *list = file->private_data;
+	struct mousedev_client *client = file->private_data;
 	unsigned char c;
 	unsigned int i;
 
@@ -510,95 +565,95 @@ static ssize_t mousedev_write(struct fil
 		if (get_user(c, buffer + i))
 			return -EFAULT;
 
-		if (c == mousedev_imex_seq[list->imexseq]) {
-			if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
-				list->imexseq = 0;
-				list->mode = MOUSEDEV_EMUL_EXPS;
+		if (c == mousedev_imex_seq[client->imexseq]) {
+			if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
+				client->imexseq = 0;
+				client->mode = MOUSEDEV_EMUL_EXPS;
 			}
 		} else
-			list->imexseq = 0;
+			client->imexseq = 0;
 
-		if (c == mousedev_imps_seq[list->impsseq]) {
-			if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
-				list->impsseq = 0;
-				list->mode = MOUSEDEV_EMUL_IMPS;
+		if (c == mousedev_imps_seq[client->impsseq]) {
+			if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
+				client->impsseq = 0;
+				client->mode = MOUSEDEV_EMUL_IMPS;
 			}
 		} else
-			list->impsseq = 0;
+			client->impsseq = 0;
 
-		list->ps2[0] = 0xfa;
+		client->ps2[0] = 0xfa;
 
 		switch (c) {
 
 			case 0xeb: /* Poll */
-				mousedev_packet(list, &list->ps2[1]);
-				list->bufsiz++; /* account for leading ACK */
+				mousedev_packet(client, &client->ps2[1]);
+				client->bufsiz++; /* account for leading ACK */
 				break;
 
 			case 0xf2: /* Get ID */
-				switch (list->mode) {
-					case MOUSEDEV_EMUL_PS2:  list->ps2[1] = 0; break;
-					case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
-					case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
+				switch (client->mode) {
+					case MOUSEDEV_EMUL_PS2:  client->ps2[1] = 0; break;
+					case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
+					case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
 				}
-				list->bufsiz = 2;
+				client->bufsiz = 2;
 				break;
 
 			case 0xe9: /* Get info */
-				list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
-				list->bufsiz = 4;
+				client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+				client->bufsiz = 4;
 				break;
 
 			case 0xff: /* Reset */
-				list->impsseq = list->imexseq = 0;
-				list->mode = MOUSEDEV_EMUL_PS2;
-				list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
-				list->bufsiz = 3;
+				client->impsseq = client->imexseq = 0;
+				client->mode = MOUSEDEV_EMUL_PS2;
+				client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+				client->bufsiz = 3;
 				break;
 
 			default:
-				list->bufsiz = 1;
+				client->bufsiz = 1;
 				break;
 		}
 
-		list->buffer = list->bufsiz;
+		client->buffer = client->bufsiz;
 	}
 
-	kill_fasync(&list->fasync, SIGIO, POLL_IN);
+	kill_fasync(&client->fasync, SIGIO, POLL_IN);
 
-	wake_up_interruptible(&list->mousedev->wait);
+	wake_up_interruptible(&client->mousedev->wait);
 
 	return count;
 }
 
-static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
-	struct mousedev_list *list = file->private_data;
+	struct mousedev_client *client = file->private_data;
 	int retval = 0;
 
-	if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
+	if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(list->mousedev->wait,
-					  !list->mousedev->exist || list->ready || list->buffer);
+	retval = wait_event_interruptible(client->mousedev->wait,
+					  !client->mousedev->exist || client->ready || client->buffer);
 
 	if (retval)
 		return retval;
 
-	if (!list->mousedev->exist)
+	if (!client->mousedev->exist)
 		return -ENODEV;
 
-	if (!list->buffer && list->ready) {
-		mousedev_packet(list, list->ps2);
-		list->buffer = list->bufsiz;
+	if (!client->buffer && client->ready) {
+		mousedev_packet(client, client->ps2);
+		client->buffer = client->bufsiz;
 	}
 
-	if (count > list->buffer)
-		count = list->buffer;
+	if (count > client->buffer)
+		count = client->buffer;
 
-	list->buffer -= count;
+	client->buffer -= count;
 
-	if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
+	if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
 		return -EFAULT;
 
 	return count;
@@ -607,11 +662,12 @@ static ssize_t mousedev_read(struct file
 /* No kernel lock - fine */
 static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
-	struct mousedev_list *list = file->private_data;
+	struct mousedev_client *client = file->private_data;
+	struct mousedev *mousedev = client->mousedev;
 
-	poll_wait(file, &list->mousedev->wait, wait);
-	return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
-		(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
+	poll_wait(file, &mousedev->wait, wait);
+	return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
+		(mousedev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static const struct file_operations mousedev_fops = {
@@ -624,23 +680,27 @@ static const struct file_operations mous
 	.fasync =	mousedev_fasync,
 };
 
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
-					     const struct input_device_id *id)
+static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+			    const struct input_device_id *id)
 {
 	struct mousedev *mousedev;
 	struct class_device *cdev;
-	int minor = 0;
+	dev_t devt;
+	int minor;
+	int error;
 
 	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
 	if (minor == MOUSEDEV_MINORS) {
 		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
-		return NULL;
+		return -ENFILE;
 	}
 
-	if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
-		return NULL;
+	mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
+	if (!mousedev)
+		return -ENOMEM;
 
-	INIT_LIST_HEAD(&mousedev->list);
+	INIT_LIST_HEAD(&mousedev->client_list);
+	INIT_LIST_HEAD(&mousedev->mixdev_node);
 	init_waitqueue_head(&mousedev->wait);
 
 	mousedev->minor = minor;
@@ -651,42 +711,66 @@ static struct input_handle *mousedev_con
 	mousedev->handle.private = mousedev;
 	sprintf(mousedev->name, "mouse%d", minor);
 
-	if (mousedev_mix.open)
-		input_open_device(&mousedev->handle);
-
 	mousedev_table[minor] = mousedev;
 
-	cdev = class_device_create(&input_class, &dev->cdev,
-			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
-			dev->cdev.dev, mousedev->name);
+	devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+
+	cdev = class_device_create(&input_class, &dev->cdev, devt,
+				   dev->cdev.dev, mousedev->name);
+	if (IS_ERR(cdev)) {
+		error = PTR_ERR(cdev);
+		goto err_free_mousedev;
+	}
 
 	/* temporary symlink to keep userspace happy */
-	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-			  mousedev->name);
+	error = sysfs_create_link(&input_class.subsys.kobj,
+				  &cdev->kobj, mousedev->name);
+	if (error)
+		goto err_cdev_destroy;
+
+	error = input_register_handle(&mousedev->handle);
+	if (error)
+		goto err_remove_link;
+
+	error = mixdev_add_device(mousedev);
+	if (error)
+		goto err_unregister_handle;
+
+	return 0;
 
-	return &mousedev->handle;
+ err_unregister_handle:
+	input_unregister_handle(&mousedev->handle);
+ err_remove_link:
+	sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
+ err_cdev_destroy:
+	class_device_destroy(&input_class, devt);
+ err_free_mousedev:
+	mousedev_table[minor] = NULL;
+	kfree(mousedev);
+	return error;
 }
 
 static void mousedev_disconnect(struct input_handle *handle)
 {
 	struct mousedev *mousedev = handle->private;
-	struct mousedev_list *list;
+	struct mousedev_client *client;
 
-	sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
+	input_unregister_handle(handle);
+
+	sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
 	class_device_destroy(&input_class,
 			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
 	mousedev->exist = 0;
 
+	mixdev_remove_device(mousedev);
+
 	if (mousedev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&mousedev->wait);
-		list_for_each_entry(list, &mousedev->list, node)
-			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-	} else {
-		if (mousedev_mix.open)
-			input_close_device(handle);
+		list_for_each_entry(client, &mousedev->client_list, node)
+			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+	} else
 		mousedev_free(mousedev);
-	}
 }
 
 static const struct input_device_id mousedev_ids[] = {
@@ -714,7 +798,7 @@ static const struct input_device_id mous
 		.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
 	},	/* A touchpad */
 
-	{ }, 	/* Terminating entry */
+	{ },	/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, mousedev_ids);
@@ -746,7 +830,7 @@ static int __init mousedev_init(void)
 		return error;
 
 	memset(&mousedev_mix, 0, sizeof(struct mousedev));
-	INIT_LIST_HEAD(&mousedev_mix.list);
+	INIT_LIST_HEAD(&mousedev_mix.client_list);
 	init_waitqueue_head(&mousedev_mix.wait);
 	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
 	mousedev_mix.exist = 1;
diff --git a/drivers/input/power.c b/drivers/input/power.c
deleted file mode 100644
index ee82464..0000000
--- a/drivers/input/power.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
- *
- *  Copyright (c) 2001 "Crazy" James Simmons
- *
- *  Input driver Power Management.
- *
- *  Sponsored by Transvirtual Technology.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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 <jsimmons@transvirtual.com>.
- */
-
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-
-static struct input_handler power_handler;
-
-/*
- * Power management can't be done in a interrupt context. So we have to
- * use keventd.
- */
-static int suspend_button_pushed = 0;
-static void suspend_button_task_handler(void *data)
-{
-        udelay(200); /* debounce */
-        suspend_button_pushed = 0;
-}
-
-static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL);
-
-static void power_event(struct input_handle *handle, unsigned int type,
-		        unsigned int code, int down)
-{
-	struct input_dev *dev = handle->dev;
-
-	printk("Entering power_event\n");
-
-	if (type == EV_PWR) {
-		switch (code) {
-			case KEY_SUSPEND:
-				printk("Powering down entire device\n");
-
-				if (!suspend_button_pushed) {
-                			suspend_button_pushed = 1;
-                        		schedule_work(&suspend_button_task);
-                		}
-				break;
-			case KEY_POWER:
-				/* Hum power down the machine. */
-				break;
-			default:
-				return;
-		}
-	}
-
-	if (type == EV_KEY) {
-		switch (code) {
-			case KEY_SUSPEND:
-				printk("Powering down input device\n");
-				/* This is risky. See pm.h for details. */
-				if (dev->state != PM_RESUME)
-					dev->state = PM_RESUME;
-				else
-					dev->state = PM_SUSPEND;
-				pm_send(dev->pm_dev, dev->state, dev);
-				break;
-			case KEY_POWER:
-				/* Turn the input device off completely ? */
-				break;
-			default:
-				return;
-		}
-	}
-	return;
-}
-
-static struct input_handle *power_connect(struct input_handler *handler,
-					  struct input_dev *dev,
-					  const struct input_device_id *id)
-{
-	struct input_handle *handle;
-
-	if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
-		return NULL;
-
-	handle->dev = dev;
-	handle->handler = handler;
-
-	input_open_device(handle);
-
-	printk(KERN_INFO "power.c: Adding power management to input layer\n");
-	return handle;
-}
-
-static void power_disconnect(struct input_handle *handle)
-{
-	input_close_device(handle);
-	kfree(handle);
-}
-
-static const struct input_device_id power_ids[] = {
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-		.evbit = { BIT(EV_KEY) },
-		.keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
-	},
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-		.evbit = { BIT(EV_KEY) },
-		.keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
-	},
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-		.evbit = { BIT(EV_PWR) },
-	},
-	{ }, 	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, power_ids);
-
-static struct input_handler power_handler = {
-	.event =	power_event,
-	.connect =	power_connect,
-	.disconnect =	power_disconnect,
-	.name =		"power",
-	.id_table =	power_ids,
-};
-
-static int __init power_init(void)
-{
-	return input_register_handler(&power_handler);
-}
-
-static void __exit power_exit(void)
-{
-	input_unregister_handler(&power_handler);
-}
-
-module_init(power_init);
-module_exit(power_exit);
-
-MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
-MODULE_DESCRIPTION("Input Power Management driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 4fa93ff..93a1a6b 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -32,11 +32,11 @@
  *
  *	Driver theory of operation:
  *
- *	Some access methods and an ISR is defined by the sub-driver 
- *	(e.g. hp_sdc_mlc.c).  These methods are expected to provide a 
- *	few bits of logic in addition to raw access to the HIL MLC, 
- *	specifically, the ISR, which is entirely registered by the 
- *	sub-driver and invoked directly, must check for record 
+ *	Some access methods and an ISR is defined by the sub-driver
+ *	(e.g. hp_sdc_mlc.c).  These methods are expected to provide a
+ *	few bits of logic in addition to raw access to the HIL MLC,
+ *	specifically, the ISR, which is entirely registered by the
+ *	sub-driver and invoked directly, must check for record
  *	termination or packet match, at which point a semaphore must
  *	be cleared and then the hil_mlcs_tasklet must be scheduled.
  *
@@ -47,7 +47,7 @@
  *	itself if output is pending.  (This rescheduling should be replaced
  *	at some point with a sub-driver-specific mechanism.)
  *
- *	A timer task prods the tasklet once per second to prevent 
+ *	A timer task prods the tasklet once per second to prevent
  *	hangups when attached devices do not return expected data
  *	and to initiate probes of the loop for new devices.
  */
@@ -83,69 +83,85 @@ DECLARE_TASKLET_DISABLED(hil_mlcs_taskle
 
 /********************** Device info/instance management **********************/
 
-static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) {
+static void hil_mlc_clear_di_map(hil_mlc *mlc, int val)
+{
 	int j;
-	for (j = val; j < 7 ; j++) {
+
+	for (j = val; j < 7 ; j++)
 		mlc->di_map[j] = -1;
-	}
 }
 
-static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
-	memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
+static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
+{
+	memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
 }
 
-static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
-	memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
+static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
+{
+	memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch));
 }
 
-static int hil_mlc_match_di_scratch (hil_mlc *mlc) {
+static int hil_mlc_match_di_scratch(hil_mlc *mlc)
+{
 	int idx;
 
 	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
-		int j, found;
+		int j, found = 0;
 
 		/* In-use slots are not eligible. */
-		found = 0;
-		for (j = 0; j < 7 ; j++) {
-			if (mlc->di_map[j] == idx) found++;
-		}
-		if (found) continue;
-		if (!memcmp(mlc->di + idx, 
-			    &(mlc->di_scratch), 
-			    sizeof(mlc->di_scratch))) break;
+		for (j = 0; j < 7 ; j++)
+			if (mlc->di_map[j] == idx)
+				found++;
+
+		if (found)
+			continue;
+
+		if (!memcmp(mlc->di + idx, &mlc->di_scratch,
+				sizeof(mlc->di_scratch)))
+			break;
 	}
-	return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
+	return idx >= HIL_MLC_DEVMEM ? -1 : idx;
 }
 
-static int hil_mlc_find_free_di(hil_mlc *mlc) {
+static int hil_mlc_find_free_di(hil_mlc *mlc)
+{
 	int idx;
-	/* TODO: Pick all-zero slots first, failing that, 
-	 * randomize the slot picked among those eligible. 
+
+	/* TODO: Pick all-zero slots first, failing that,
+	 * randomize the slot picked among those eligible.
 	 */
 	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
-		int j, found;
-		found = 0;
-		for (j = 0; j < 7 ; j++) {
-			if (mlc->di_map[j] == idx) found++;
-		}
-		if (!found) break;
+		int j, found = 0;
+
+		for (j = 0; j < 7 ; j++)
+			if (mlc->di_map[j] == idx)
+				found++;
+
+		if (!found)
+			break;
 	}
-	return(idx); /* Note: It is guaranteed at least one above will match */
+
+	return idx; /* Note: It is guaranteed at least one above will match */
 }
 
-static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) {
+static inline void hil_mlc_clean_serio_map(hil_mlc *mlc)
+{
 	int idx;
+
 	for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
-		int j, found;
-		found = 0;
-		for (j = 0; j < 7 ; j++) {
-			if (mlc->di_map[j] == idx) found++;
-		}
-		if (!found) mlc->serio_map[idx].di_revmap = -1;
+		int j, found = 0;
+
+		for (j = 0; j < 7 ; j++)
+			if (mlc->di_map[j] == idx)
+				found++;
+
+		if (!found)
+			mlc->serio_map[idx].di_revmap = -1;
 	}
 }
 
-static void hil_mlc_send_polls(hil_mlc *mlc) {
+static void hil_mlc_send_polls(hil_mlc *mlc)
+{
 	int did, i, cnt;
 	struct serio *serio;
 	struct serio_driver *drv;
@@ -157,26 +173,31 @@ static void hil_mlc_send_polls(hil_mlc *
 
 	while (mlc->icount < 15 - i) {
 		hil_packet p;
+
 		p = mlc->ipacket[i];
 		if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
-			if (drv == NULL || drv->interrupt == NULL) goto skip;
+			if (drv && drv->interrupt) {
+				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);
+			}
 
-			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;
 			drv = (serio != NULL) ? serio->drv : NULL;
 			cnt = 0;
 		}
-		cnt++; i++;
-		if (drv == NULL || drv->interrupt == NULL) continue;
-		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);
+
+		cnt++;
+		i++;
+
+		if (drv && drv->interrupt) {
+			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);
+		}
 	}
 }
 
@@ -215,12 +236,16 @@ #define HILSEN_LAST	(HILSEN_UP | 1)
 #define HILSEN_DOZE	(HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
 #define HILSEN_SLEEP	(HILSEN_SAME | HILSEN_BREAK)
 
-static int hilse_match(hil_mlc *mlc, int unused) {
+static int hilse_match(hil_mlc *mlc, int unused)
+{
 	int rc;
+
 	rc = hil_mlc_match_di_scratch(mlc);
 	if (rc == -1) {
 		rc = hil_mlc_find_free_di(mlc);
-		if (rc == -1) goto err;
+		if (rc == -1)
+			goto err;
+
 #ifdef HIL_MLC_DEBUG
 		printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
 #endif
@@ -231,6 +256,7 @@ #endif
 		serio_rescan(mlc->serio[rc]);
 		return -1;
 	}
+
 	mlc->di_map[mlc->ddi] = rc;
 #ifdef HIL_MLC_DEBUG
 	printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
@@ -238,152 +264,177 @@ #endif
 	mlc->serio_map[rc].di_revmap = mlc->ddi;
 	hil_mlc_clean_serio_map(mlc);
 	return 0;
+
  err:
 	printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
 	return 1;
 }
 
 /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
-static int hilse_init_lcv(hil_mlc *mlc, int unused) {
+static int hilse_init_lcv(hil_mlc *mlc, int unused)
+{
 	struct timeval tv;
 
 	do_gettimeofday(&tv);
 
-	if(mlc->lcv == 0) goto restart;  /* First init, no need to dally */
-	if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
- restart:
+	if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
+		return -1;
+
 	mlc->lcv_tv = tv;
 	mlc->lcv = 0;
+
 	return 0;
 }
 
-static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
-	if (mlc->lcv++ >= lim) return -1;
-	return 0;
+static int hilse_inc_lcv(hil_mlc *mlc, int lim)
+{
+	return mlc->lcv++ >= lim ? -1 : 0;
 }
 
 #if 0
-static int hilse_set_lcv(hil_mlc *mlc, int val) {
+static int hilse_set_lcv(hil_mlc *mlc, int val)
+{
 	mlc->lcv = val;
+
 	return 0;
 }
 #endif
 
 /* Management of the discovered device index (zero based, -1 means no devs) */
-static int hilse_set_ddi(hil_mlc *mlc, int val) {
+static int hilse_set_ddi(hil_mlc *mlc, int val)
+{
 	mlc->ddi = val;
 	hil_mlc_clear_di_map(mlc, val + 1);
+
 	return 0;
 }
 
-static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
+static int hilse_dec_ddi(hil_mlc *mlc, int unused)
+{
 	mlc->ddi--;
-	if (mlc->ddi <= -1) { 
+	if (mlc->ddi <= -1) {
 		mlc->ddi = -1;
 		hil_mlc_clear_di_map(mlc, 0);
 		return -1;
 	}
 	hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
+
 	return 0;
 }
 
-static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
-	if (mlc->ddi >= 6) {
-		BUG();
-		return -1;
-	}
+static int hilse_inc_ddi(hil_mlc *mlc, int unused)
+{
+	BUG_ON(mlc->ddi >= 6);
 	mlc->ddi++;
+
 	return 0;
 }
 
-static int hilse_take_idd(hil_mlc *mlc, int unused) {
+static int hilse_take_idd(hil_mlc *mlc, int unused)
+{
 	int i;
 
-	/* Help the state engine: 
-	 * Is this a real IDD response or just an echo? 
+	/* Help the state engine:
+	 * Is this a real IDD response or just an echo?
 	 *
-	 * Real IDD response does not start with a command. 
+	 * Real IDD response does not start with a command.
 	 */
-	if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail;
+	if (mlc->ipacket[0] & HIL_PKT_CMD)
+		goto bail;
+
 	/* Should have the command echoed further down. */
 	for (i = 1; i < 16; i++) {
-		if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) == 
+		if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
 		     (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
-		    (mlc->ipacket[i] & HIL_PKT_CMD) && 
+		    (mlc->ipacket[i] & HIL_PKT_CMD) &&
 		    ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
 			break;
 	}
-	if (i > 15) goto bail;
+	if (i > 15)
+		goto bail;
+
 	/* And the rest of the packets should still be clear. */
-	while (++i < 16) {
-		if (mlc->ipacket[i]) break;
-	}
-	if (i < 16) goto bail;
-	for (i = 0; i < 16; i++) {
-		mlc->di_scratch.idd[i] = 
+	while (++i < 16)
+		if (mlc->ipacket[i])
+			break;
+
+	if (i < 16)
+		goto bail;
+
+	for (i = 0; i < 16; i++)
+		mlc->di_scratch.idd[i] =
 			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
-	}
+
 	/* Next step is to see if RSC supported */
-	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC) 
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
 		return HILSEN_NEXT;
-	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
 		return HILSEN_DOWN | 4;
+
 	return 0;
+
  bail:
 	mlc->ddi--;
+
 	return -1; /* This should send us off to ACF */
 }
 
-static int hilse_take_rsc(hil_mlc *mlc, int unused) {
+static int hilse_take_rsc(hil_mlc *mlc, int unused)
+{
 	int i;
 
-	for (i = 0; i < 16; i++) {
-		mlc->di_scratch.rsc[i] = 
+	for (i = 0; i < 16; i++)
+		mlc->di_scratch.rsc[i] =
 			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
-	}
+
 	/* Next step is to see if EXD supported (IDD has already been read) */
-	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD) 
+	if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
 		return HILSEN_NEXT;
+
 	return 0;
 }
 
-static int hilse_take_exd(hil_mlc *mlc, int unused) {
+static int hilse_take_exd(hil_mlc *mlc, int unused)
+{
 	int i;
 
-	for (i = 0; i < 16; i++) {
-		mlc->di_scratch.exd[i] = 
+	for (i = 0; i < 16; i++)
+		mlc->di_scratch.exd[i] =
 			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
-	}
+
 	/* Next step is to see if RNM supported. */
-	if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM) 
+	if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
 		return HILSEN_NEXT;
+
 	return 0;
 }
 
-static int hilse_take_rnm(hil_mlc *mlc, int unused) {
+static int hilse_take_rnm(hil_mlc *mlc, int unused)
+{
 	int i;
 
-	for (i = 0; i < 16; i++) {
-		mlc->di_scratch.rnm[i] = 
+	for (i = 0; i < 16; i++)
+		mlc->di_scratch.rnm[i] =
 			mlc->ipacket[i] & HIL_PKT_DATA_MASK;
-	}
-	do {
-	  char nam[17];
-	  snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
-	  nam[16] = '\0';
-	  printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
-	} while (0);
+
+	printk(KERN_INFO PREFIX "Device name gotten: %16s\n",
+			mlc->di_scratch.rnm);
+
 	return 0;
 }
 
-static int hilse_operate(hil_mlc *mlc, int repoll) { 
+static int hilse_operate(hil_mlc *mlc, int repoll)
+{
 
-	if (mlc->opercnt == 0) hil_mlcs_probe = 0;
+	if (mlc->opercnt == 0)
+		hil_mlcs_probe = 0;
 	mlc->opercnt = 1;
 
 	hil_mlc_send_polls(mlc);
 
-	if (!hil_mlcs_probe) return 0;
+	if (!hil_mlcs_probe)
+		return 0;
 	hil_mlcs_probe = 0;
 	mlc->opercnt = 0;
 	return 1;
@@ -408,7 +459,7 @@ #define OUT_DISC(pack) \
 #define OUT_LAST(pack) \
 { HILSE_OUT_LAST,	{ .packet = pack }, 0, 0, 0, 0 },
 
-struct hilse_node hil_mlc_se[HILSEN_END] = {
+const struct hilse_node hil_mlc_se[HILSEN_END] = {
 
 	/* 0  HILSEN_START */
 	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
@@ -428,7 +479,7 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 	EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
 	       2000,		HILSEN_NEXT,	HILSEN_RESTART,	HILSEN_RESTART)
 	OUT(HIL_CTRL_ONLY | 0)			/* Disable test mode */
-	
+
 	/* 9  HILSEN_DHR */
 	FUNC(hilse_init_lcv, 0,	HILSEN_NEXT,	HILSEN_SLEEP,	0)
 
@@ -439,7 +490,7 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 	IN(300000,		HILSEN_DHR2,	HILSEN_DHR2,	HILSEN_NEXT)
 
 	/* 14 HILSEN_IFC */
-  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
 	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
 	       20000,		HILSEN_DISC,	HILSEN_DHR2,	HILSEN_NEXT )
 
@@ -455,7 +506,7 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 
 	/* 18 HILSEN_HEAL */
 	OUT_LAST(HIL_CMD_ELB)
-	EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT, 
+	EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
 		    20000,	HILSEN_REPOLL,	HILSEN_DSR,	HILSEN_NEXT)
 	FUNC(hilse_dec_ddi, 0,	HILSEN_HEAL,	HILSEN_NEXT,	0)
 
@@ -503,7 +554,7 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 
 	/* 44 HILSEN_PROBE */
 	OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
-	IN(10000, 		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
+	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
 	OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
 	IN(10000,		HILSEN_DISC,	HILSEN_DSR,	HILSEN_NEXT)
 	OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
@@ -514,7 +565,7 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 	/* 52 HILSEN_DSR */
 	FUNC(hilse_set_ddi, -1,	HILSEN_NEXT,	0,		0)
 	OUT(HIL_PKT_CMD | HIL_CMD_DSR)
-	IN(20000, 		HILSEN_DHR,	HILSEN_DHR,	HILSEN_IFC)
+	IN(20000,		HILSEN_DHR,	HILSEN_DHR,	HILSEN_IFC)
 
 	/* 55 HILSEN_REPOLL */
 	OUT(HIL_PKT_CMD | HIL_CMD_RPL)
@@ -523,14 +574,15 @@ (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT)
 	FUNC(hilse_operate, 1,	HILSEN_OPERATE,	HILSEN_IFC,	HILSEN_PROBE)
 
 	/* 58 HILSEN_IFCACF */
-  	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+	OUT(HIL_PKT_CMD | HIL_CMD_IFC)
 	EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
 	       20000,		HILSEN_ACF2,	HILSEN_DHR2,	HILSEN_HEAL)
 
 	/* 60 HILSEN_END */
 };
 
-static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
+static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node)
+{
 
 	switch (node->act) {
 	case HILSE_EXPECT_DISC:
@@ -555,29 +607,27 @@ static inline void hilse_setup_input(hil
 	do_gettimeofday(&(mlc->instart));
 	mlc->icount = 15;
 	memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
-	BUG_ON(down_trylock(&(mlc->isem)));
-
-	return;
+	BUG_ON(down_trylock(&mlc->isem));
 }
 
 #ifdef HIL_MLC_DEBUG
-static int doze = 0;
+static int doze;
 static int seidx; /* For debug */
-static int kick = 1;
 #endif
 
-static int hilse_donode (hil_mlc *mlc) {
-	struct hilse_node *node;
+static int hilse_donode(hil_mlc *mlc)
+{
+	const struct hilse_node *node;
 	int nextidx = 0;
 	int sched_long = 0;
 	unsigned long flags;
 
 #ifdef HIL_MLC_DEBUG
-	if (mlc->seidx && (mlc->seidx != seidx)  && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
-	  printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
+	if (mlc->seidx && mlc->seidx != seidx &&
+	    mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
+		printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
 		doze = 0;
 	}
-	kick = 0;
 
 	seidx = mlc->seidx;
 #endif
@@ -588,52 +638,61 @@ #endif
 		hil_packet pack;
 
 	case HILSE_FUNC:
-		if (node->object.func == NULL) break;
+		BUG_ON(node->object.func == NULL);
 		rc = node->object.func(mlc, node->arg);
-		nextidx = (rc > 0) ? node->ugly : 
+		nextidx = (rc > 0) ? node->ugly :
 			((rc < 0) ? node->bad : node->good);
-		if (nextidx == HILSEN_FOLLOW) nextidx = rc;
+		if (nextidx == HILSEN_FOLLOW)
+			nextidx = rc;
 		break;
+
 	case HILSE_EXPECT_LAST:
 	case HILSE_EXPECT_DISC:
 	case HILSE_EXPECT:
 	case HILSE_IN:
 		/* Already set up from previous HILSE_OUT_* */
-		write_lock_irqsave(&(mlc->lock), flags);
+		write_lock_irqsave(&mlc->lock, flags);
 		rc = mlc->in(mlc, node->arg);
 		if (rc == 2)  {
 			nextidx = HILSEN_DOZE;
 			sched_long = 1;
-			write_unlock_irqrestore(&(mlc->lock), flags);
+			write_unlock_irqrestore(&mlc->lock, flags);
 			break;
 		}
-		if (rc == 1)		nextidx = node->ugly;
-		else if (rc == 0)	nextidx = node->good;
-		else			nextidx = node->bad;
+		if (rc == 1)
+			nextidx = node->ugly;
+		else if (rc == 0)
+			nextidx = node->good;
+		else
+			nextidx = node->bad;
 		mlc->istarted = 0;
-		write_unlock_irqrestore(&(mlc->lock), flags);
+		write_unlock_irqrestore(&mlc->lock, flags);
 		break;
+
 	case HILSE_OUT_LAST:
-		write_lock_irqsave(&(mlc->lock), flags);
+		write_lock_irqsave(&mlc->lock, flags);
 		pack = node->object.packet;
 		pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
 		goto out;
+
 	case HILSE_OUT_DISC:
-		write_lock_irqsave(&(mlc->lock), flags);
+		write_lock_irqsave(&mlc->lock, flags);
 		pack = node->object.packet;
 		pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
 		goto out;
+
 	case HILSE_OUT:
-		write_lock_irqsave(&(mlc->lock), flags);
+		write_lock_irqsave(&mlc->lock, flags);
 		pack = node->object.packet;
 	out:
-		if (mlc->istarted) goto out2;
+		if (mlc->istarted)
+			goto out2;
 		/* Prepare to receive input */
 		if ((node + 1)->act & HILSE_IN)
 			hilse_setup_input(mlc, node + 1);
 
 	out2:
-		write_unlock_irqrestore(&(mlc->lock), flags);
+		write_unlock_irqrestore(&mlc->lock, flags);
 
 		if (down_trylock(&mlc->osem)) {
 			nextidx = HILSEN_DOZE;
@@ -641,60 +700,71 @@ #endif
 		}
 		up(&mlc->osem);
 
-		write_lock_irqsave(&(mlc->lock), flags);
-		if (!(mlc->ostarted)) {
+		write_lock_irqsave(&mlc->lock, flags);
+		if (!mlc->ostarted) {
 			mlc->ostarted = 1;
 			mlc->opacket = pack;
 			mlc->out(mlc);
 			nextidx = HILSEN_DOZE;
-			write_unlock_irqrestore(&(mlc->lock), flags);
+			write_unlock_irqrestore(&mlc->lock, flags);
 			break;
 		}
 		mlc->ostarted = 0;
 		do_gettimeofday(&(mlc->instart));
-		write_unlock_irqrestore(&(mlc->lock), flags);
+		write_unlock_irqrestore(&mlc->lock, flags);
 		nextidx = HILSEN_NEXT;
 		break;
+
 	case HILSE_CTS:
+		write_lock_irqsave(&mlc->lock, flags);
 		nextidx = mlc->cts(mlc) ? node->bad : node->good;
+		write_unlock_irqrestore(&mlc->lock, flags);
 		break;
+
 	default:
 		BUG();
-		nextidx = 0;
-		break;
 	}
 
 #ifdef HIL_MLC_DEBUG
-	if (nextidx == HILSEN_DOZE) doze++;
+	if (nextidx == HILSEN_DOZE)
+		doze++;
 #endif
 
 	while (nextidx & HILSEN_SCHED) {
 		struct timeval tv;
 
-		if (!sched_long) goto sched;
+		if (!sched_long)
+			goto sched;
 
 		do_gettimeofday(&tv);
-		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
 		tv.tv_usec -= mlc->instart.tv_usec;
 		if (tv.tv_usec >= mlc->intimeout) goto sched;
-		tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000;
+		tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;
 		if (!tv.tv_usec) goto sched;
 		mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
 		break;
 	sched:
 		tasklet_schedule(&hil_mlcs_tasklet);
 		break;
-	} 
-	if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK;
-	else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK;
-	else mlc->seidx = nextidx & HILSEN_MASK;
+	}
+
+	if (nextidx & HILSEN_DOWN)
+		mlc->seidx += nextidx & HILSEN_MASK;
+	else if (nextidx & HILSEN_UP)
+		mlc->seidx -= nextidx & HILSEN_MASK;
+	else
+		mlc->seidx = nextidx & HILSEN_MASK;
+
+	if (nextidx & HILSEN_BREAK)
+		return 1;
 
-	if (nextidx & HILSEN_BREAK)	return 1;
 	return 0;
 }
 
 /******************** tasklet context functions **************************/
-static void hil_mlcs_process(unsigned long unused) {
+static void hil_mlcs_process(unsigned long unused)
+{
 	struct list_head *tmp;
 
 	read_lock(&hil_mlcs_lock);
@@ -702,19 +772,20 @@ static void hil_mlcs_process(unsigned lo
 		struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
 		while (hilse_donode(mlc) == 0) {
 #ifdef HIL_MLC_DEBUG
-		  if (mlc->seidx != 41 && 
-		      mlc->seidx != 42 && 
-		      mlc->seidx != 43) 
-		    printk(KERN_DEBUG PREFIX " + ");
+			if (mlc->seidx != 41 &&
+			    mlc->seidx != 42 &&
+			    mlc->seidx != 43)
+				printk(KERN_DEBUG PREFIX " + ");
 #endif
-		};
+		}
 	}
 	read_unlock(&hil_mlcs_lock);
 }
 
 /************************* Keepalive timer task *********************/
 
-void hil_mlcs_timer (unsigned long data) {
+void hil_mlcs_timer(unsigned long data)
+{
 	hil_mlcs_probe = 1;
 	tasklet_schedule(&hil_mlcs_tasklet);
 	/* Re-insert the periodic task. */
@@ -724,28 +795,25 @@ void hil_mlcs_timer (unsigned long data)
 
 /******************** user/kernel context functions **********************/
 
-static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
+static int hil_mlc_serio_write(struct serio *serio, unsigned char c)
+{
 	struct hil_mlc_serio_map *map;
 	struct hil_mlc *mlc;
 	struct serio_driver *drv;
 	uint8_t *idx, *last;
 
 	map = serio->port_data;
-	if (map == NULL) {
-		BUG();
-		return -EIO;
-	}
+	BUG_ON(map == NULL);
+
 	mlc = map->mlc;
-	if (mlc == NULL) {
-		BUG();
-		return -EIO;
-	}
-	mlc->serio_opacket[map->didx] |= 
+	BUG_ON(mlc == NULL);
+
+	mlc->serio_opacket[map->didx] |=
 		((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
 
 	if (mlc->serio_oidx[map->didx] >= 3) {
 		/* for now only commands */
-		if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD)) 
+		if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
 			return -EIO;
 		switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
 		case HIL_CMD_IDD:
@@ -771,12 +839,11 @@ static int hil_mlc_serio_write(struct se
 	return -EIO;
  emu:
 	drv = serio->drv;
-	if (drv == NULL) {
-		BUG();
-		return -EIO;
-	}
+	BUG_ON(drv == NULL);
+
 	last = idx + 15;
-	while ((last != idx) && (*last == 0)) last--;
+	while ((last != idx) && (*last == 0))
+		last--;
 
 	while (idx != last) {
 		drv->interrupt(serio, 0, 0);
@@ -789,14 +856,15 @@ static int hil_mlc_serio_write(struct se
 	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;
 
 	return 0;
 }
 
-static int hil_mlc_serio_open(struct serio *serio) {
+static int hil_mlc_serio_open(struct serio *serio)
+{
 	struct hil_mlc_serio_map *map;
 	struct hil_mlc *mlc;
 
@@ -804,67 +872,57 @@ static int hil_mlc_serio_open(struct ser
 		return -EBUSY;
 
 	map = serio->port_data;
-	if (map == NULL) {
-		BUG();
-		return -ENODEV;
-	}
+	BUG_ON(map == NULL);
+
 	mlc = map->mlc;
-	if (mlc == NULL) {
-		BUG();
-		return -ENODEV;
-	}
+	BUG_ON(mlc == NULL);
 
 	return 0;
 }
 
-static void hil_mlc_serio_close(struct serio *serio) {
+static void hil_mlc_serio_close(struct serio *serio)
+{
 	struct hil_mlc_serio_map *map;
 	struct hil_mlc *mlc;
 
 	map = serio->port_data;
-	if (map == NULL) {
-		BUG();
-		return;
-	}
+	BUG_ON(map == NULL);
+
 	mlc = map->mlc;
-	if (mlc == NULL) {
-		BUG();
-		return;
-	}
+	BUG_ON(mlc == NULL);
 
 	serio_set_drvdata(serio, NULL);
 	serio->drv = NULL;
 	/* TODO wake up interruptable */
 }
 
-static struct serio_device_id hil_mlc_serio_id = {
+static const struct serio_device_id hil_mlc_serio_id = {
 	.type = SERIO_HIL_MLC,
 	.proto = SERIO_HIL,
 	.extra = SERIO_ANY,
 	.id = SERIO_ANY,
 };
 
-int hil_mlc_register(hil_mlc *mlc) {
+int hil_mlc_register(hil_mlc *mlc)
+{
 	int i;
-        unsigned long flags;
+	unsigned long flags;
 
-	if (mlc == NULL) {
-		return -EINVAL;
-	}
+	BUG_ON(mlc == NULL);
 
 	mlc->istarted = 0;
-        mlc->ostarted = 0;
+	mlc->ostarted = 0;
 
-        rwlock_init(&mlc->lock);
-        init_MUTEX(&(mlc->osem));
+	rwlock_init(&mlc->lock);
+	init_MUTEX(&mlc->osem);
 
-        init_MUTEX(&(mlc->isem));
-        mlc->icount = -1;
-        mlc->imatch = 0;
+	init_MUTEX(&mlc->isem);
+	mlc->icount = -1;
+	mlc->imatch = 0;
 
 	mlc->opercnt = 0;
 
-        init_MUTEX_LOCKED(&(mlc->csem));
+	init_MUTEX_LOCKED(&(mlc->csem));
 
 	hil_mlc_clear_di_scratch(mlc);
 	hil_mlc_clear_di_map(mlc, 0);
@@ -873,6 +931,8 @@ int hil_mlc_register(hil_mlc *mlc) {
 		hil_mlc_copy_di_scratch(mlc, i);
 		mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
 		mlc->serio[i] = mlc_serio;
+		snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
+		snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
 		mlc_serio->id			= hil_mlc_serio_id;
 		mlc_serio->write		= hil_mlc_serio_write;
 		mlc_serio->open			= hil_mlc_serio_open;
@@ -897,19 +957,18 @@ int hil_mlc_register(hil_mlc *mlc) {
 	return 0;
 }
 
-int hil_mlc_unregister(hil_mlc *mlc) {
+int hil_mlc_unregister(hil_mlc *mlc)
+{
 	struct list_head *tmp;
-        unsigned long flags;
+	unsigned long flags;
 	int i;
 
-	if (mlc == NULL)
-		return -EINVAL;
+	BUG_ON(mlc == NULL);
 
 	write_lock_irqsave(&hil_mlcs_lock, flags);
-	list_for_each(tmp, &hil_mlcs) {
+	list_for_each(tmp, &hil_mlcs)
 		if (list_entry(tmp, hil_mlc, list) == mlc)
 			goto found;
-	}
 
 	/* not found in list */
 	write_unlock_irqrestore(&hil_mlcs_lock, flags);
@@ -918,7 +977,7 @@ int hil_mlc_unregister(hil_mlc *mlc) {
 
  found:
 	list_del(tmp);
-        write_unlock_irqrestore(&hil_mlcs_lock, flags);
+	write_unlock_irqrestore(&hil_mlcs_lock, flags);
 
 	for (i = 0; i < HIL_MLC_DEVMEM; i++) {
 		serio_unregister_port(mlc->serio[i]);
@@ -942,7 +1001,7 @@ static int __init hil_mlc_init(void)
 
 	return 0;
 }
-                
+
 static void __exit hil_mlc_exit(void)
 {
 	del_timer(&hil_mlcs_kicker);
@@ -950,6 +1009,6 @@ static void __exit hil_mlc_exit(void)
 	tasklet_disable(&hil_mlcs_tasklet);
 	tasklet_kill(&hil_mlcs_tasklet);
 }
-                        
+
 module_init(hil_mlc_init);
 module_exit(hil_mlc_exit);
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index b57370d..6af1998 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -34,27 +34,27 @@
  *
  * Driver theory of operation:
  *
- * hp_sdc_put does all writing to the SDC.  ISR can run on a different 
- * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time 
+ * hp_sdc_put does all writing to the SDC.  ISR can run on a different
+ * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
  * (it cannot really benefit from SMP anyway.)  A tasket fit this perfectly.
  *
- * All data coming back from the SDC is sent via interrupt and can be read 
- * fully in the ISR, so there are no latency/throughput problems there.  
- * The problem is with output, due to the slow clock speed of the SDC 
- * compared to the CPU.  This should not be too horrible most of the time, 
- * but if used with HIL devices that support the multibyte transfer command, 
- * keeping outbound throughput flowing at the 6500KBps that the HIL is 
+ * All data coming back from the SDC is sent via interrupt and can be read
+ * fully in the ISR, so there are no latency/throughput problems there.
+ * The problem is with output, due to the slow clock speed of the SDC
+ * compared to the CPU.  This should not be too horrible most of the time,
+ * but if used with HIL devices that support the multibyte transfer command,
+ * keeping outbound throughput flowing at the 6500KBps that the HIL is
  * capable of is more than can be done at HZ=100.
  *
- * Busy polling for IBF clear wastes CPU cycles and bus cycles.  hp_sdc.ibf 
- * is set to 0 when the IBF flag in the status register has cleared.  ISR 
- * may do this, and may also access the parts of queued transactions related 
- * to reading data back from the SDC, but otherwise will not touch the 
+ * Busy polling for IBF clear wastes CPU cycles and bus cycles.  hp_sdc.ibf
+ * is set to 0 when the IBF flag in the status register has cleared.  ISR
+ * may do this, and may also access the parts of queued transactions related
+ * to reading data back from the SDC, but otherwise will not touch the
  * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
  *
  * The i8042 write index and the values in the 4-byte input buffer
  * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
- * to minimize the amount of IO needed to the SDC.  However these values 
+ * to minimize the amount of IO needed to the SDC.  However these values
  * do not need to be locked since they are only ever accessed by hp_sdc_put.
  *
  * A timer task schedules the tasklet once per second just to make
@@ -100,39 +100,46 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq);
 EXPORT_SYMBOL(hp_sdc_release_hil_irq);
 EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
 
+EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
 EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
 EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
 
 static hp_i8042_sdc	hp_sdc;	/* All driver state is kept in here. */
 
 /*************** primitives for use in any context *********************/
-static inline uint8_t hp_sdc_status_in8 (void) {
+static inline uint8_t hp_sdc_status_in8(void)
+{
 	uint8_t status;
 	unsigned long flags;
 
 	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
 	status = sdc_readb(hp_sdc.status_io);
-	if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
+	if (!(status & HP_SDC_STATUS_IBF))
+		hp_sdc.ibf = 0;
 	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
 
 	return status;
 }
 
-static inline uint8_t hp_sdc_data_in8 (void) {
-	return sdc_readb(hp_sdc.data_io); 
+static inline uint8_t hp_sdc_data_in8(void)
+{
+	return sdc_readb(hp_sdc.data_io);
 }
 
-static inline void hp_sdc_status_out8 (uint8_t val) {
+static inline void hp_sdc_status_out8(uint8_t val)
+{
 	unsigned long flags;
 
 	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
 	hp_sdc.ibf = 1;
-	if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff;
+	if ((val & 0xf0) == 0xe0)
+		hp_sdc.wi = 0xff;
 	sdc_writeb(val, hp_sdc.status_io);
 	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
 }
 
-static inline void hp_sdc_data_out8 (uint8_t val) {
+static inline void hp_sdc_data_out8(uint8_t val)
+{
 	unsigned long flags;
 
 	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
@@ -141,11 +148,12 @@ static inline void hp_sdc_data_out8 (uin
 	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
 }
 
-/*	Care must be taken to only invoke hp_sdc_spin_ibf when 
- *	absolutely needed, or in rarely invoked subroutines.  
- *	Not only does it waste CPU cycles, it also wastes bus cycles. 
+/*	Care must be taken to only invoke hp_sdc_spin_ibf when
+ *	absolutely needed, or in rarely invoked subroutines.
+ *	Not only does it waste CPU cycles, it also wastes bus cycles.
  */
-static inline void hp_sdc_spin_ibf(void) {
+static inline void hp_sdc_spin_ibf(void)
+{
 	unsigned long flags;
 	rwlock_t *lock;
 
@@ -158,19 +166,21 @@ static inline void hp_sdc_spin_ibf(void)
 	}
 	read_unlock(lock);
 	write_lock(lock);
-	while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
+	while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF)
+		{ }
 	hp_sdc.ibf = 0;
 	write_unlock_irqrestore(lock, flags);
 }
 
 
 /************************ Interrupt context functions ************************/
-static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
+static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
+{
 	hp_sdc_transaction *curr;
 
 	read_lock(&hp_sdc.rtq_lock);
 	if (hp_sdc.rcurr < 0) {
-	  	read_unlock(&hp_sdc.rtq_lock);
+		read_unlock(&hp_sdc.rtq_lock);
 		return;
 	}
 	curr = hp_sdc.tq[hp_sdc.rcurr];
@@ -183,25 +193,27 @@ static void hp_sdc_take (int irq, void *
 
 	if (hp_sdc.rqty <= 0) {
 		/* All data has been gathered. */
-		if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) {
-			if (curr->act.semaphore) up(curr->act.semaphore);
-		}
-		if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) {
+		if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE)
+			if (curr->act.semaphore)
+				up(curr->act.semaphore);
+
+		if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
 			if (curr->act.irqhook)
 				curr->act.irqhook(irq, dev_id, status, data);
-		}
+
 		curr->actidx = curr->idx;
 		curr->idx++;
 		/* Return control of this transaction */
 		write_lock(&hp_sdc.rtq_lock);
-		hp_sdc.rcurr = -1; 
+		hp_sdc.rcurr = -1;
 		hp_sdc.rqty = 0;
 		write_unlock(&hp_sdc.rtq_lock);
 		tasklet_schedule(&hp_sdc.task);
 	}
 }
 
-static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
+static irqreturn_t hp_sdc_isr(int irq, void *dev_id)
+{
 	uint8_t status, data;
 
 	status = hp_sdc_status_in8();
@@ -209,67 +221,74 @@ static irqreturn_t hp_sdc_isr(int irq, v
 	data =   hp_sdc_data_in8();
 
 	/* For now we are ignoring these until we get the SDC to behave. */
-	if (((status & 0xf1) == 0x51) && data == 0x82) {
-	  return IRQ_HANDLED;
-	}
+	if (((status & 0xf1) == 0x51) && data == 0x82)
+		return IRQ_HANDLED;
 
-	switch(status & HP_SDC_STATUS_IRQMASK) {
-	      case 0: /* This case is not documented. */
+	switch (status & HP_SDC_STATUS_IRQMASK) {
+	case 0: /* This case is not documented. */
 		break;
-	      case HP_SDC_STATUS_USERTIMER:
-	      case HP_SDC_STATUS_PERIODIC:
-	      case HP_SDC_STATUS_TIMER:
+
+	case HP_SDC_STATUS_USERTIMER:
+	case HP_SDC_STATUS_PERIODIC:
+	case HP_SDC_STATUS_TIMER:
 		read_lock(&hp_sdc.hook_lock);
-	      	if (hp_sdc.timer != NULL)
+		if (hp_sdc.timer != NULL)
 			hp_sdc.timer(irq, dev_id, status, data);
 		read_unlock(&hp_sdc.hook_lock);
 		break;
-	      case HP_SDC_STATUS_REG:
+
+	case HP_SDC_STATUS_REG:
 		hp_sdc_take(irq, dev_id, status, data);
 		break;
-	      case HP_SDC_STATUS_HILCMD:
-	      case HP_SDC_STATUS_HILDATA:
+
+	case HP_SDC_STATUS_HILCMD:
+	case HP_SDC_STATUS_HILDATA:
 		read_lock(&hp_sdc.hook_lock);
 		if (hp_sdc.hil != NULL)
 			hp_sdc.hil(irq, dev_id, status, data);
 		read_unlock(&hp_sdc.hook_lock);
 		break;
-	      case HP_SDC_STATUS_PUP:
+
+	case HP_SDC_STATUS_PUP:
 		read_lock(&hp_sdc.hook_lock);
 		if (hp_sdc.pup != NULL)
 			hp_sdc.pup(irq, dev_id, status, data);
-		else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
+		else
+			printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
 		read_unlock(&hp_sdc.hook_lock);
 		break;
-	      default:
+
+	default:
 		read_lock(&hp_sdc.hook_lock);
 		if (hp_sdc.cooked != NULL)
 			hp_sdc.cooked(irq, dev_id, status, data);
 		read_unlock(&hp_sdc.hook_lock);
 		break;
 	}
+
 	return IRQ_HANDLED;
 }
 
 
-static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
+static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id)
+{
 	int status;
-	
+
 	status = hp_sdc_status_in8();
 	printk(KERN_WARNING PREFIX "NMI !\n");
 
-#if 0	
+#if 0
 	if (status & HP_SDC_NMISTATUS_FHS) {
 		read_lock(&hp_sdc.hook_lock);
-	      	if (hp_sdc.timer != NULL)
+		if (hp_sdc.timer != NULL)
 			hp_sdc.timer(irq, dev_id, status, 0);
 		read_unlock(&hp_sdc.hook_lock);
-	}
-	else {
+	} else {
 		/* TODO: pass this on to the HIL handler, or do SAK here? */
 		printk(KERN_WARNING PREFIX "HIL NMI\n");
 	}
 #endif
+
 	return IRQ_HANDLED;
 }
 
@@ -278,13 +297,17 @@ #endif
 
 unsigned long hp_sdc_put(void);
 
-static void hp_sdc_tasklet(unsigned long foo) {
-
+static void hp_sdc_tasklet(unsigned long foo)
+{
 	write_lock_irq(&hp_sdc.rtq_lock);
+
 	if (hp_sdc.rcurr >= 0) {
 		struct timeval tv;
+
 		do_gettimeofday(&tv);
-		if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000;
+		if (tv.tv_sec > hp_sdc.rtv.tv_sec)
+			tv.tv_usec += USEC_PER_SEC;
+
 		if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
 			hp_sdc_transaction *curr;
 			uint8_t tmp;
@@ -300,27 +323,29 @@ static void hp_sdc_tasklet(unsigned long
 			hp_sdc.rqty = 0;
 			tmp = curr->seq[curr->actidx];
 			curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
-			if(tmp & HP_SDC_ACT_SEMAPHORE) {
-				if (curr->act.semaphore) 
+			if (tmp & HP_SDC_ACT_SEMAPHORE)
+				if (curr->act.semaphore)
 					up(curr->act.semaphore);
-			}
-			if(tmp & HP_SDC_ACT_CALLBACK) {
+
+			if (tmp & HP_SDC_ACT_CALLBACK) {
 				/* Note this means that irqhooks may be called
 				 * in tasklet/bh context.
 				 */
-				if (curr->act.irqhook) 
+				if (curr->act.irqhook)
 					curr->act.irqhook(0, NULL, 0, 0);
 			}
+
 			curr->actidx = curr->idx;
 			curr->idx++;
-			hp_sdc.rcurr = -1; 
+			hp_sdc.rcurr = -1;
 		}
 	}
 	write_unlock_irq(&hp_sdc.rtq_lock);
 	hp_sdc_put();
 }
 
-unsigned long hp_sdc_put(void) {
+unsigned long hp_sdc_put(void)
+{
 	hp_sdc_transaction *curr;
 	uint8_t act;
 	int idx, curridx;
@@ -333,19 +358,24 @@ unsigned long hp_sdc_put(void) {
 	   requires output, so we skip to the administrativa. */
 	if (hp_sdc.ibf) {
 		hp_sdc_status_in8();
-		if (hp_sdc.ibf) goto finish;
+		if (hp_sdc.ibf)
+			goto finish;
 	}
 
  anew:
 	/* See if we are in the middle of a sequence. */
-	if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0;
+	if (hp_sdc.wcurr < 0)
+		hp_sdc.wcurr = 0;
 	read_lock_irq(&hp_sdc.rtq_lock);
-	if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++;
+	if (hp_sdc.rcurr == hp_sdc.wcurr)
+		hp_sdc.wcurr++;
 	read_unlock_irq(&hp_sdc.rtq_lock);
-	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+		hp_sdc.wcurr = 0;
 	curridx = hp_sdc.wcurr;
 
-	if (hp_sdc.tq[curridx] != NULL) goto start;
+	if (hp_sdc.tq[curridx] != NULL)
+		goto start;
 
 	while (++curridx != hp_sdc.wcurr) {
 		if (curridx >= HP_SDC_QUEUE_LEN) {
@@ -358,7 +388,8 @@ unsigned long hp_sdc_put(void) {
 			continue;
 		}
 		read_unlock_irq(&hp_sdc.rtq_lock);
-		if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */
+		if (hp_sdc.tq[curridx] != NULL)
+			break; /* Found one. */
 	}
 	if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
 		curridx = -1;
@@ -374,7 +405,8 @@ unsigned long hp_sdc_put(void) {
 		goto finish;
 	}
 
-	if (hp_sdc.wcurr == -1) goto done;
+	if (hp_sdc.wcurr == -1)
+		goto done;
 
 	curr = hp_sdc.tq[curridx];
 	idx = curr->actidx;
@@ -383,20 +415,23 @@ unsigned long hp_sdc_put(void) {
 		hp_sdc.tq[curridx] = NULL;
 		/* Interleave outbound data between the transactions. */
 		hp_sdc.wcurr++;
-		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
-		goto finish;	
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+			hp_sdc.wcurr = 0;
+		goto finish;
 	}
 
 	act = curr->seq[idx];
 	idx++;
 
 	if (curr->idx >= curr->endidx) {
-		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		if (act & HP_SDC_ACT_DEALLOC)
+			kfree(curr);
 		hp_sdc.tq[curridx] = NULL;
 		/* Interleave outbound data between the transactions. */
 		hp_sdc.wcurr++;
-		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
-		goto finish;	
+		if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+			hp_sdc.wcurr = 0;
+		goto finish;
 	}
 
 	while (act & HP_SDC_ACT_PRECMD) {
@@ -409,9 +444,10 @@ unsigned long hp_sdc_put(void) {
 		curr->idx++;
 		/* act finished? */
 		if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
-		  goto actdone;
+			goto actdone;
 		/* skip quantity field if data-out sequence follows. */
-		if (act & HP_SDC_ACT_DATAOUT) curr->idx++;
+		if (act & HP_SDC_ACT_DATAOUT)
+			curr->idx++;
 		goto finish;
 	}
 	if (act & HP_SDC_ACT_DATAOUT) {
@@ -423,15 +459,15 @@ unsigned long hp_sdc_put(void) {
 			hp_sdc_data_out8(curr->seq[curr->idx]);
 			curr->idx++;
 			/* act finished? */
-			if ((curr->idx - idx >= qty) && 
-			    ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
+			if (curr->idx - idx >= qty &&
+			    (act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
 				goto actdone;
 			goto finish;
 		}
 		idx += qty;
 		act &= ~HP_SDC_ACT_DATAOUT;
-	}
-	else while (act & HP_SDC_ACT_DATAREG) {
+	} else
+	    while (act & HP_SDC_ACT_DATAREG) {
 		int mask;
 		uint8_t w7[4];
 
@@ -445,26 +481,30 @@ unsigned long hp_sdc_put(void) {
 			act &= ~HP_SDC_ACT_DATAREG;
 			break;
 		}
-		
+
 		w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
 		w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
 		w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
 		w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
-		
+
 		if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
-		        w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) {
+		    w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) {
 			int i = 0;
 
-			/* Need to point the write index register */	
-			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			/* Need to point the write index register */
+			while (i < 4 && w7[i] == hp_sdc.r7[i])
+				i++;
+
 			if (i < 4) {
 				hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
 				hp_sdc.wi = 0x70 + i;
 				goto finish;
 			}
+
 			idx++;
 			if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
 				goto actdone;
+
 			curr->idx = idx;
 			act &= ~HP_SDC_ACT_DATAREG;
 			break;
@@ -476,12 +516,13 @@ unsigned long hp_sdc_put(void) {
 		{
 			int i = 0;
 
-			while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+			while ((i < 4) && w7[i] == hp_sdc.r7[i])
+				i++;
 			if (i >= 4) {
 				curr->idx = idx + 1;
-				if ((act & HP_SDC_ACT_DURING) == 
+				if ((act & HP_SDC_ACT_DURING) ==
 				    HP_SDC_ACT_DATAREG)
-				        goto actdone;
+					goto actdone;
 			}
 		}
 		goto finish;
@@ -497,7 +538,7 @@ unsigned long hp_sdc_put(void) {
 
 
 	if (act & HP_SDC_ACT_POSTCMD) {
-	  	uint8_t postcmd;
+		uint8_t postcmd;
 
 		/* curr->idx should == idx at this point. */
 		postcmd = curr->seq[idx];
@@ -505,12 +546,12 @@ unsigned long hp_sdc_put(void) {
 		if (act & HP_SDC_ACT_DATAIN) {
 
 			/* Start a new read */
-	  		hp_sdc.rqty = curr->seq[curr->idx];
+			hp_sdc.rqty = curr->seq[curr->idx];
 			do_gettimeofday(&hp_sdc.rtv);
 			curr->idx++;
 			/* Still need to lock here in case of spurious irq. */
 			write_lock_irq(&hp_sdc.rtq_lock);
-			hp_sdc.rcurr = curridx; 
+			hp_sdc.rcurr = curridx;
 			write_unlock_irq(&hp_sdc.rtq_lock);
 			hp_sdc_status_out8(postcmd);
 			goto finish;
@@ -519,75 +560,86 @@ unsigned long hp_sdc_put(void) {
 		goto actdone;
 	}
 
-actdone:
-	if (act & HP_SDC_ACT_SEMAPHORE) {
+ actdone:
+	if (act & HP_SDC_ACT_SEMAPHORE)
 		up(curr->act.semaphore);
-	}
-	else if (act & HP_SDC_ACT_CALLBACK) {
+	else if (act & HP_SDC_ACT_CALLBACK)
 		curr->act.irqhook(0,NULL,0,0);
-	}
+
 	if (curr->idx >= curr->endidx) { /* This transaction is over. */
-		if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+		if (act & HP_SDC_ACT_DEALLOC)
+			kfree(curr);
 		hp_sdc.tq[curridx] = NULL;
-	}
-	else {
+	} else {
 		curr->actidx = idx + 1;
 		curr->idx = idx + 2;
 	}
 	/* Interleave outbound data between the transactions. */
 	hp_sdc.wcurr++;
-	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+	if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+		hp_sdc.wcurr = 0;
 
  finish:
-	/* If by some quirk IBF has cleared and our ISR has run to 
+	/* If by some quirk IBF has cleared and our ISR has run to
 	   see that that has happened, do it all again. */
-	if (!hp_sdc.ibf && limit++ < 20) goto anew;
+	if (!hp_sdc.ibf && limit++ < 20)
+		goto anew;
 
  done:
-	if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);
+	if (hp_sdc.wcurr >= 0)
+		tasklet_schedule(&hp_sdc.task);
 	write_unlock(&hp_sdc.lock);
+
 	return 0;
 }
 
 /******* Functions called in either user or kernel context ****/
-int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
-	unsigned long flags;
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
+{
 	int i;
 
 	if (this == NULL) {
-		tasklet_schedule(&hp_sdc.task);
+		BUG();
 		return -EINVAL;
-	};
-
-	write_lock_irqsave(&hp_sdc.lock, flags);
+	}
 
 	/* Can't have same transaction on queue twice */
-	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
-		if (hp_sdc.tq[i] == this) goto fail;
+	for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this)
+			goto fail;
 
 	this->actidx = 0;
 	this->idx = 1;
 
 	/* Search for empty slot */
-	for (i=0; i < HP_SDC_QUEUE_LEN; i++) {
+	for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
 		if (hp_sdc.tq[i] == NULL) {
 			hp_sdc.tq[i] = this;
-			write_unlock_irqrestore(&hp_sdc.lock, flags);
 			tasklet_schedule(&hp_sdc.task);
 			return 0;
 		}
-	}
-	write_unlock_irqrestore(&hp_sdc.lock, flags);
+
 	printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
 	return -EBUSY;
 
  fail:
-	write_unlock_irqrestore(&hp_sdc.lock,flags);
 	printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
 	return -EINVAL;
 }
 
-int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+	unsigned long flags;
+	int ret;
+
+	write_lock_irqsave(&hp_sdc.lock, flags);
+	ret = __hp_sdc_enqueue_transaction(this);
+	write_unlock_irqrestore(&hp_sdc.lock,flags);
+
+	return ret;
+}
+
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
+{
 	unsigned long flags;
 	int i;
 
@@ -595,8 +647,9 @@ int hp_sdc_dequeue_transaction(hp_sdc_tr
 
 	/* TODO: don't remove it if it's not done. */
 
-	for (i=0; i < HP_SDC_QUEUE_LEN; i++)
-		if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
+	for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
+		if (hp_sdc.tq[i] == this)
+			hp_sdc.tq[i] = NULL;
 
 	write_unlock_irqrestore(&hp_sdc.lock, flags);
 	return 0;
@@ -605,11 +658,11 @@ int hp_sdc_dequeue_transaction(hp_sdc_tr
 
 
 /********************** User context functions **************************/
-int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
-
-	if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
+{
+	if (callback == NULL || hp_sdc.dev == NULL)
 		return -EINVAL;
-	}
+
 	write_lock_irq(&hp_sdc.hook_lock);
 	if (hp_sdc.timer != NULL) {
 		write_unlock_irq(&hp_sdc.hook_lock);
@@ -629,11 +682,11 @@ int hp_sdc_request_timer_irq(hp_sdc_irqh
 	return 0;
 }
 
-int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
-
-	if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
+{
+	if (callback == NULL || hp_sdc.dev == NULL)
 		return -EINVAL;
-	}
+
 	write_lock_irq(&hp_sdc.hook_lock);
 	if (hp_sdc.hil != NULL) {
 		write_unlock_irq(&hp_sdc.hook_lock);
@@ -650,11 +703,11 @@ int hp_sdc_request_hil_irq(hp_sdc_irqhoo
 	return 0;
 }
 
-int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
-
-	if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
+{
+	if (callback == NULL || hp_sdc.dev == NULL)
 		return -EINVAL;
-	}
+
 	write_lock_irq(&hp_sdc.hook_lock);
 	if (hp_sdc.cooked != NULL) {
 		write_unlock_irq(&hp_sdc.hook_lock);
@@ -672,9 +725,8 @@ int hp_sdc_request_cooked_irq(hp_sdc_irq
 	return 0;
 }
 
-int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
-
-
+int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback)
+{
 	write_lock_irq(&hp_sdc.hook_lock);
 	if ((callback != hp_sdc.timer) ||
 	    (hp_sdc.timer == NULL)) {
@@ -694,8 +746,8 @@ int hp_sdc_release_timer_irq(hp_sdc_irqh
 	return 0;
 }
 
-int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
-
+int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback)
+{
 	write_lock_irq(&hp_sdc.hook_lock);
 	if ((callback != hp_sdc.hil) ||
 	    (hp_sdc.hil == NULL)) {
@@ -715,8 +767,8 @@ int hp_sdc_release_hil_irq(hp_sdc_irqhoo
 	return 0;
 }
 
-int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
-
+int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
+{
 	write_lock_irq(&hp_sdc.hook_lock);
 	if ((callback != hp_sdc.cooked) ||
 	    (hp_sdc.cooked == NULL)) {
@@ -738,7 +790,8 @@ int hp_sdc_release_cooked_irq(hp_sdc_irq
 
 /************************* Keepalive timer task *********************/
 
-void hp_sdc_kicker (unsigned long data) {
+void hp_sdc_kicker (unsigned long data)
+{
 	tasklet_schedule(&hp_sdc.task);
 	/* Re-insert the periodic task. */
 	mod_timer(&hp_sdc.kicker, jiffies + HZ);
@@ -748,12 +801,12 @@ void hp_sdc_kicker (unsigned long data) 
 
 #if defined(__hppa__)
 
-static struct parisc_device_id hp_sdc_tbl[] = {
+static const struct parisc_device_id hp_sdc_tbl[] = {
 	{
-		.hw_type =	HPHW_FIO, 
+		.hw_type =	HPHW_FIO,
 		.hversion_rev =	HVERSION_REV_ANY_ID,
 		.hversion =	HVERSION_ANY_ID,
-		.sversion =	0x73, 
+		.sversion =	0x73,
 	 },
 	{ 0, }
 };
@@ -772,16 +825,15 @@ #endif /* __hppa__ */
 
 static int __init hp_sdc_init(void)
 {
-	int i;
 	char *errstr;
 	hp_sdc_transaction t_sync;
 	uint8_t ts_sync[6];
 	struct semaphore s_sync;
 
-  	rwlock_init(&hp_sdc.lock);
-  	rwlock_init(&hp_sdc.ibf_lock);
-  	rwlock_init(&hp_sdc.rtq_lock);
-  	rwlock_init(&hp_sdc.hook_lock);
+	rwlock_init(&hp_sdc.lock);
+	rwlock_init(&hp_sdc.ibf_lock);
+	rwlock_init(&hp_sdc.rtq_lock);
+	rwlock_init(&hp_sdc.hook_lock);
 
 	hp_sdc.timer		= NULL;
 	hp_sdc.hil		= NULL;
@@ -796,7 +848,8 @@ static int __init hp_sdc_init(void)
 	hp_sdc.r7[3]		= 0xff;
 	hp_sdc.ibf		= 1;
 
-	for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;
+	memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq));
+
 	hp_sdc.wcurr		= -1;
         hp_sdc.rcurr		= -1;
 	hp_sdc.rqty		= 0;
@@ -804,27 +857,32 @@ static int __init hp_sdc_init(void)
 	hp_sdc.dev_err = -ENODEV;
 
 	errstr = "IO not found for";
-	if (!hp_sdc.base_io) goto err0;
+	if (!hp_sdc.base_io)
+		goto err0;
 
 	errstr = "IRQ not found for";
-	if (!hp_sdc.irq) goto err0;
+	if (!hp_sdc.irq)
+		goto err0;
 
 	hp_sdc.dev_err = -EBUSY;
 
 #if defined(__hppa__)
 	errstr = "IO not available for";
-        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
-#endif	
+        if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
+		goto err0;
+#endif
 
 	errstr = "IRQ not available for";
-        if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
-		       (void *) hp_sdc.base_io)) goto err1;
+	if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
+			"HP SDC", &hp_sdc))
+		goto err1;
 
 	errstr = "NMI not available for";
-	if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI", 
-			(void *) hp_sdc.base_io)) goto err2;
+	if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
+			"HP SDC NMI", &hp_sdc))
+		goto err2;
 
-	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n", 
+	printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
 	       (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
 
 	hp_sdc_status_in8();
@@ -854,13 +912,14 @@ #endif	
 	hp_sdc.dev_err = 0;
 	return 0;
  err2:
-	free_irq(hp_sdc.irq, NULL);
+	free_irq(hp_sdc.irq, &hp_sdc);
  err1:
 	release_region(hp_sdc.data_io, 2);
  err0:
-	printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n", 
+	printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
 		errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
 	hp_sdc.dev = NULL;
+
 	return hp_sdc.dev_err;
 }
 
@@ -868,8 +927,10 @@ #if defined(__hppa__)
 
 static int __init hp_sdc_init_hppa(struct parisc_device *d)
 {
-	if (!d) return 1;
-	if (hp_sdc.dev != NULL) return 1;	/* We only expect one SDC */
+	if (!d)
+		return 1;
+	if (hp_sdc.dev != NULL)
+		return 1;	/* We only expect one SDC */
 
 	hp_sdc.dev		= d;
 	hp_sdc.irq		= d->irq;
@@ -898,18 +959,16 @@ #endif
 	/* Wait until we know this has been processed by the i8042 */
 	hp_sdc_spin_ibf();
 
-	free_irq(hp_sdc.nmi, NULL);
-	free_irq(hp_sdc.irq, NULL);
+	free_irq(hp_sdc.nmi, &hp_sdc);
+	free_irq(hp_sdc.irq, &hp_sdc);
 	write_unlock_irq(&hp_sdc.lock);
 
 	del_timer(&hp_sdc.kicker);
 
 	tasklet_kill(&hp_sdc.task);
 
-/*        release_region(hp_sdc.data_io, 2); */
-
 #if defined(__hppa__)
-	if (unregister_parisc_driver(&hp_sdc_driver)) 
+	if (unregister_parisc_driver(&hp_sdc_driver))
 		printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
 #endif
 }
@@ -923,7 +982,7 @@ #if defined(__mc68000__)
 	mm_segment_t fs;
 	unsigned char i;
 #endif
-	
+
 	hp_sdc.dev = NULL;
 	hp_sdc.dev_err = 0;
 #if defined(__hppa__)
@@ -960,8 +1019,8 @@ #endif
 	tq_init.seq		= tq_init_seq;
 	tq_init.act.semaphore	= &tq_init_sem;
 
-	tq_init_seq[0] = 
-	  HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+	tq_init_seq[0] =
+		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
 	tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
 	tq_init_seq[2] = 1;
 	tq_init_seq[3] = 0;
@@ -979,13 +1038,13 @@ #endif
 	}
 	hp_sdc.r11 = tq_init_seq[4];
 	if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
-		char *str;
+		const char *str;
 		printk(KERN_INFO PREFIX "New style SDC\n");
 		tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
 		tq_init.actidx		= 0;
 		tq_init.idx		= 1;
 		down(&tq_init_sem);
-		hp_sdc_enqueue_transaction(&tq_init);		
+		hp_sdc_enqueue_transaction(&tq_init);
 		down(&tq_init_sem);
 		up(&tq_init_sem);
 		if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
@@ -995,15 +1054,13 @@ #endif
 		hp_sdc.r7e = tq_init_seq[4];
 		HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
 		printk(KERN_INFO PREFIX "Revision: %s\n", str);
-		if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {
+		if (hp_sdc.r7e & HP_SDC_XTD_BEEPER)
 			printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
-		}
-		if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {
+		if (hp_sdc.r7e & HP_SDC_XTD_BBRTC)
 			printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
-		}
 		printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
 		       "on next firmware reset.\n");
-		tq_init_seq[0] = HP_SDC_ACT_PRECMD | 
+		tq_init_seq[0] = HP_SDC_ACT_PRECMD |
 			HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
 		tq_init_seq[1] = HP_SDC_CMD_SET_STR;
 		tq_init_seq[2] = 1;
@@ -1012,14 +1069,12 @@ #endif
 		tq_init.idx		= 1;
 		tq_init.endidx		= 4;
 		down(&tq_init_sem);
-		hp_sdc_enqueue_transaction(&tq_init);		
+		hp_sdc_enqueue_transaction(&tq_init);
 		down(&tq_init_sem);
 		up(&tq_init_sem);
-	}
-	else {
-		printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n", 
+	} else
+		printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
 		       (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
-	}
 
         return 0;
 }
@@ -1027,13 +1082,13 @@ #endif
 module_init(hp_sdc_register);
 module_exit(hp_sdc_exit);
 
-/* Timing notes:  These measurements taken on my 64MHz 7100-LC (715/64) 
+/* Timing notes:  These measurements taken on my 64MHz 7100-LC (715/64)
  *                                              cycles cycles-adj    time
  * between two consecutive mfctl(16)'s:              4        n/a    63ns
  * hp_sdc_spin_ibf when idle:                      119        115   1.7us
  * gsc_writeb status register:                      83         79   1.2us
  * IBF to clear after sending SET_IM:             6204       6006    93us
- * IBF to clear after sending LOAD_RT:            4467       4352    68us  
+ * IBF to clear after sending LOAD_RT:            4467       4352    68us
  * IBF to clear after sending two LOAD_RTs:      18974      18859   295us
  * READ_T1, read status/data, IRQ, call handler: 35564        n/a   556us
  * cmd to ~IBF READ_T1 2nd time right after:   5158403        n/a    81ms
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index aa4a8a4..c45ea74 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -58,12 +58,13 @@ struct hp_sdc_mlc_priv_s {
 } hp_sdc_mlc_priv;
 
 /************************* Interrupt context ******************************/
-static void hp_sdc_mlc_isr (int irq, void *dev_id, 
-			    uint8_t status, uint8_t data) {
-  	int idx;
+static void hp_sdc_mlc_isr (int irq, void *dev_id,
+			    uint8_t status, uint8_t data)
+{
+	int idx;
 	hil_mlc *mlc = &hp_sdc_mlc;
 
-	write_lock(&(mlc->lock));
+	write_lock(&mlc->lock);
 	if (mlc->icount < 0) {
 		printk(KERN_WARNING PREFIX "HIL Overflow!\n");
 		up(&mlc->isem);
@@ -73,239 +74,232 @@ static void hp_sdc_mlc_isr (int irq, voi
 	if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
 		mlc->ipacket[idx] |= data | HIL_ERR_INT;
 		mlc->icount--;
-		if (hp_sdc_mlc_priv.got5x) goto check;
-		if (!idx) goto check;
-		if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
+		if (hp_sdc_mlc_priv.got5x || !idx)
+			goto check;
+		if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
 		    (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
 			mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
-			mlc->ipacket[idx] |= (mlc->ipacket[idx-1] 
-						    & HIL_PKT_ADDR_MASK);
+			mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
+						& HIL_PKT_ADDR_MASK);
 		}
 		goto check;
 	}
 	/* We know status is 5X */
-	if (data & HP_SDC_HIL_ISERR) goto err;
-	mlc->ipacket[idx] = 
+	if (data & HP_SDC_HIL_ISERR)
+		goto err;
+	mlc->ipacket[idx] =
 		(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
 	hp_sdc_mlc_priv.got5x = 1;
 	goto out;
 
  check:
 	hp_sdc_mlc_priv.got5x = 0;
-	if (mlc->imatch == 0) goto done;
-	if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) 
-	    && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
-	if (mlc->ipacket[idx] == mlc->imatch) goto done;
+	if (mlc->imatch == 0)
+		goto done;
+	if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+	    && (mlc->ipacket[idx] == (mlc->imatch | idx)))
+		goto done;
+	if (mlc->ipacket[idx] == mlc->imatch)
+		goto done;
 	goto out;
 
- err:				
+ err:
 	printk(KERN_DEBUG PREFIX "err code %x\n", data);
+
 	switch (data) {
 	case HP_SDC_HIL_RC_DONE:
 		printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
 		break;
+
 	case HP_SDC_HIL_ERR:
-		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR | 
-		  HIL_ERR_FERR | HIL_ERR_FOF;
+		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
+					HIL_ERR_FERR | HIL_ERR_FOF;
 		break;
+
 	case HP_SDC_HIL_TO:
 		mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
 		break;
+
 	case HP_SDC_HIL_RC:
 		printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
 		break;
+
 	default:
 		printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
 		break;
 	}
+
 	/* No more data will be coming due to an error. */
  done:
 	tasklet_schedule(mlc->tasklet);
-	up(&(mlc->isem));
+	up(&mlc->isem);
  out:
-	write_unlock(&(mlc->lock));
+	write_unlock(&mlc->lock);
 }
 
 
 /******************** Tasklet or userspace context functions ****************/
 
-static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
-	unsigned long flags;
+static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
+{
 	struct hp_sdc_mlc_priv_s *priv;
 	int rc = 2;
 
 	priv = mlc->priv;
 
-	write_lock_irqsave(&(mlc->lock), flags);
-
 	/* Try to down the semaphore */
-	if (down_trylock(&(mlc->isem))) {
+	if (down_trylock(&mlc->isem)) {
 		struct timeval tv;
 		if (priv->emtestmode) {
-			mlc->ipacket[0] = 
-				HIL_ERR_INT | (mlc->opacket & 
-					       (HIL_PKT_CMD | 
-						HIL_PKT_ADDR_MASK | 
+			mlc->ipacket[0] =
+				HIL_ERR_INT | (mlc->opacket &
+					       (HIL_PKT_CMD |
+						HIL_PKT_ADDR_MASK |
 						HIL_PKT_DATA_MASK));
 			mlc->icount = 14;
 			/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
 			goto wasup;
 		}
 		do_gettimeofday(&tv);
-		tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+		tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
 		if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
-		  /*		  printk("!%i %i", 
-				  tv.tv_usec - mlc->instart.tv_usec, 
-				  mlc->intimeout);
-		  */
+			/*	printk("!%i %i",
+				tv.tv_usec - mlc->instart.tv_usec,
+				mlc->intimeout);
+			 */
 			rc = 1;
-			up(&(mlc->isem));
+			up(&mlc->isem);
 		}
 		goto done;
 	}
  wasup:
-	up(&(mlc->isem));
+	up(&mlc->isem);
 	rc = 0;
-	goto done;
  done:
-	write_unlock_irqrestore(&(mlc->lock), flags);
 	return rc;
 }
 
-static int hp_sdc_mlc_cts (hil_mlc *mlc) {
+static int hp_sdc_mlc_cts(hil_mlc *mlc)
+{
 	struct hp_sdc_mlc_priv_s *priv;
-	unsigned long flags;
 
-	priv = mlc->priv;	
-
-	write_lock_irqsave(&(mlc->lock), flags);
+	priv = mlc->priv;
 
 	/* Try to down the semaphores -- they should be up. */
-	if (down_trylock(&(mlc->isem))) {
-		BUG();
-		goto busy;
-	}
-	if (down_trylock(&(mlc->osem))) {
-	 	BUG();
-		up(&(mlc->isem));
-		goto busy;
-	}
-	up(&(mlc->isem));
-	up(&(mlc->osem));
+	BUG_ON(down_trylock(&mlc->isem));
+	BUG_ON(down_trylock(&mlc->osem));
+
+	up(&mlc->isem);
+	up(&mlc->osem);
 
-	if (down_trylock(&(mlc->csem))) {
-		if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
-		goto busy;
+	if (down_trylock(&mlc->csem)) {
+		if (priv->trans.act.semaphore != &mlc->csem)
+			goto poll;
+		else
+			goto busy;
 	}
-	if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
+
+	if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
+		goto done;
 
  poll:
-	priv->trans.act.semaphore = &(mlc->csem);
+	priv->trans.act.semaphore = &mlc->csem;
 	priv->trans.actidx = 0;
 	priv->trans.idx = 1;
 	priv->trans.endidx = 5;
-	priv->tseq[0] = 
+	priv->tseq[0] =
 		HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
 	priv->tseq[1] = HP_SDC_CMD_READ_USE;
 	priv->tseq[2] = 1;
 	priv->tseq[3] = 0;
 	priv->tseq[4] = 0;
-	hp_sdc_enqueue_transaction(&(priv->trans));
+	__hp_sdc_enqueue_transaction(&priv->trans);
  busy:
-	write_unlock_irqrestore(&(mlc->lock), flags);
 	return 1;
  done:
-	priv->trans.act.semaphore = &(mlc->osem);
-	up(&(mlc->csem));
-	write_unlock_irqrestore(&(mlc->lock), flags);
+	priv->trans.act.semaphore = &mlc->osem;
+	up(&mlc->csem);
 	return 0;
 }
 
-static void hp_sdc_mlc_out (hil_mlc *mlc) {
+static void hp_sdc_mlc_out(hil_mlc *mlc)
+{
 	struct hp_sdc_mlc_priv_s *priv;
-	unsigned long flags;
 
 	priv = mlc->priv;
 
-	write_lock_irqsave(&(mlc->lock), flags);
-	
 	/* Try to down the semaphore -- it should be up. */
-	if (down_trylock(&(mlc->osem))) {
-	 	BUG();
-		goto done;
-	}
+	BUG_ON(down_trylock(&mlc->osem));
 
-	if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
+	if (mlc->opacket & HIL_DO_ALTER_CTRL)
+		goto do_control;
 
  do_data:
 	if (priv->emtestmode) {
-		up(&(mlc->osem));
-		goto done;
+		up(&mlc->osem);
+		return;
 	}
 	/* Shouldn't be sending commands when loop may be busy */
-	if (down_trylock(&(mlc->csem))) {
-	 	BUG();
-		goto done;
-	}
-	up(&(mlc->csem));
+	BUG_ON(down_trylock(&mlc->csem));
+	up(&mlc->csem);
 
 	priv->trans.actidx = 0;
 	priv->trans.idx = 1;
-	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.act.semaphore = &mlc->osem;
 	priv->trans.endidx = 6;
-	priv->tseq[0] = 
+	priv->tseq[0] =
 		HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
 	priv->tseq[1] = 0x7;
-	priv->tseq[2] = 
-		(mlc->opacket & 
+	priv->tseq[2] =
+		(mlc->opacket &
 		 (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
 		   >> HIL_PKT_ADDR_SHIFT;
-	priv->tseq[3] = 
-		(mlc->opacket & HIL_PKT_DATA_MASK) 
+	priv->tseq[3] =
+		(mlc->opacket & HIL_PKT_DATA_MASK)
 		  >> HIL_PKT_DATA_SHIFT;
 	priv->tseq[4] = 0;  /* No timeout */
-	if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1;
+	if (priv->tseq[3] == HIL_CMD_DHR)
+		priv->tseq[4] = 1;
 	priv->tseq[5] = HP_SDC_CMD_DO_HIL;
 	goto enqueue;
 
  do_control:
 	priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
-	
+
 	/* we cannot emulate this, it should not be used. */
 	BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
-	
-	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
-	if (mlc->opacket & HIL_CTRL_APE) { 
-		BUG(); /* Should not send command/data after engaging APE */
-		goto done;
-	}
-	/* Disengaging APE this way would not be valid either since 
+
+	if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
+		goto control_only;
+
+	/* Should not send command/data after engaging APE */
+	BUG_ON(mlc->opacket & HIL_CTRL_APE);
+
+	/* Disengaging APE this way would not be valid either since
 	 * the loop must be allowed to idle.
 	 *
-	 * So, it works out that we really never actually send control 
-	 * and data when using SDC, we just send the data. 
+	 * So, it works out that we really never actually send control
+	 * and data when using SDC, we just send the data.
 	 */
 	goto do_data;
 
  control_only:
 	priv->trans.actidx = 0;
 	priv->trans.idx = 1;
-	priv->trans.act.semaphore = &(mlc->osem);
+	priv->trans.act.semaphore = &mlc->osem;
 	priv->trans.endidx = 4;
-	priv->tseq[0] = 
+	priv->tseq[0] =
 	  HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
 	priv->tseq[1] = HP_SDC_CMD_SET_LPC;
 	priv->tseq[2] = 1;
-	//	priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC;
+	/* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
 	priv->tseq[3] = 0;
 	if (mlc->opacket & HIL_CTRL_APE) {
 		priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
-		down_trylock(&(mlc->csem));
-	} 
+		down_trylock(&mlc->csem);
+	}
  enqueue:
-	hp_sdc_enqueue_transaction(&(priv->trans));
- done:
-	write_unlock_irqrestore(&(mlc->lock), flags);
+	hp_sdc_enqueue_transaction(&priv->trans);
 }
 
 static int __init hp_sdc_mlc_init(void)
@@ -316,18 +310,18 @@ static int __init hp_sdc_mlc_init(void)
 
 	hp_sdc_mlc_priv.emtestmode = 0;
 	hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
-	hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem);
+	hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
 	hp_sdc_mlc_priv.got5x = 0;
 
-	mlc->cts		= &hp_sdc_mlc_cts;
-	mlc->in			= &hp_sdc_mlc_in;
-	mlc->out		= &hp_sdc_mlc_out;
+	mlc->cts = &hp_sdc_mlc_cts;
+	mlc->in	= &hp_sdc_mlc_in;
+	mlc->out = &hp_sdc_mlc_out;
+	mlc->priv = &hp_sdc_mlc_priv;
 
 	if (hil_mlc_register(mlc)) {
 		printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
 		goto err0;
 	}
-	mlc->priv		= &hp_sdc_mlc_priv;
 
 	if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
 		printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
@@ -335,10 +329,9 @@ static int __init hp_sdc_mlc_init(void)
 	}
 	return 0;
  err1:
-	if (hil_mlc_unregister(mlc)) {
+	if (hil_mlc_unregister(mlc))
 		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
 			"This is bad.  Could cause an oops.\n");
-	}
  err0:
 	return -EBUSY;
 }
@@ -346,14 +339,14 @@ static int __init hp_sdc_mlc_init(void)
 static void __exit hp_sdc_mlc_exit(void)
 {
 	hil_mlc *mlc = &hp_sdc_mlc;
-	if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) {
+
+	if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
 		printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
 			"This is bad.  Could cause an oops.\n");
-	}
-	if (hil_mlc_unregister(mlc)) {
+
+	if (hil_mlc_unregister(mlc))
 		printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
 			"This is bad.  Could cause an oops.\n");
-	}
 }
 
 module_init(hp_sdc_mlc_init);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index d36bd54..6858bc5 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -160,6 +160,28 @@ static struct dmi_system_id __initdata i
 		},
 	},
 	{
+		/*
+		 * No data is coming from the touchscreen unless KBC
+		 * is in legacy mode.
+		 */
+		.ident = "Panasonic CF-29",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+		},
+	},
+	{
+		/*
+		 * Errors on MUX ports are reported without raising AUXDATA
+		 * causing "spurious NAK" messages.
+		 */
+		.ident = "HP Pavilion DV4017EA",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
+		},
+	},
+	{
 		.ident = "Toshiba P10",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -280,6 +302,8 @@ static struct pnp_driver i8042_pnp_kbd_d
 };
 
 static struct pnp_device_id pnp_aux_devids[] = {
+	{ .id = "FJC6000", .driver_data = 0 },
+	{ .id = "FJC6001", .driver_data = 0 },
 	{ .id = "PNP0f03", .driver_data = 0 },
 	{ .id = "PNP0f0b", .driver_data = 0 },
 	{ .id = "PNP0f0e", .driver_data = 0 },
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index db9cca3..3888dc3 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -526,6 +526,33 @@ static irqreturn_t __devinit i8042_aux_t
 	return IRQ_HANDLED;
 }
 
+/*
+ * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
+ * verifies success by readinng CTR. Used when testing for presence of AUX
+ * port.
+ */
+static int __devinit i8042_toggle_aux(int on)
+{
+	unsigned char param;
+	int i;
+
+	if (i8042_command(&param,
+			on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
+		return -1;
+
+	/* some chips need some time to set the I8042_CTR_AUXDIS bit */
+	for (i = 0; i < 100; i++) {
+		udelay(50);
+
+		if (i8042_command(&param, I8042_CMD_CTL_RCTR))
+			return -1;
+
+		if (!(param & I8042_CTR_AUXDIS) == on)
+			return 0;
+	}
+
+	return -1;
+}
 
 /*
  * i8042_check_aux() applies as much paranoia as it can at detecting
@@ -580,16 +607,12 @@ static int __devinit i8042_check_aux(voi
  * Bit assignment test - filters out PS/2 i8042's in AT mode
  */
 
-	if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
-		return -1;
-	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) {
+	if (i8042_toggle_aux(0)) {
 		printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
 		printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
 	}
 
-	if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
-		return -1;
-	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
+	if (i8042_toggle_aux(1))
 		return -1;
 
 /*
@@ -768,6 +791,13 @@ static void i8042_controller_reset(void)
 	i8042_flush();
 
 /*
+ * Disable both KBD and AUX interfaces so they don't get in the way
+ */
+
+	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
+	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
+
+/*
  * Disable MUX mode if present.
  */
 
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index a15e531..5895202 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -115,18 +115,18 @@ static int serio_match_port(const struct
  * Basic serio -> driver core mappings
  */
 
-static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
+static int 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)) {
+
 		serio->dev.driver = &drv->driver;
 		if (serio_connect_driver(serio, drv)) {
 			serio->dev.driver = NULL;
-			goto out;
+			return -ENODEV;
 		}
+
 		error = device_bind_driver(&serio->dev);
 		if (error) {
 			printk(KERN_WARNING
@@ -136,31 +136,21 @@ static void serio_bind_driver(struct ser
 				drv->description, error);
 			serio_disconnect_driver(serio);
 			serio->dev.driver = NULL;
-			goto out;
+			return error;
 		}
 	}
- out:
-	up_write(&serio_bus.subsys.rwsem);
-}
-
-static void serio_release_driver(struct serio *serio)
-{
-	down_write(&serio_bus.subsys.rwsem);
-	device_release_driver(&serio->dev);
-	up_write(&serio_bus.subsys.rwsem);
+	return 0;
 }
 
 static void serio_find_driver(struct serio *serio)
 {
 	int error;
 
-	down_write(&serio_bus.subsys.rwsem);
 	error = device_attach(&serio->dev);
 	if (error < 0)
 		printk(KERN_WARNING
 			"serio: device_attach() failed for %s (%s), error: %d\n",
 			serio->phys, serio->name, error);
-	up_write(&serio_bus.subsys.rwsem);
 }
 
 
@@ -470,13 +460,12 @@ static ssize_t serio_rebind_driver(struc
 {
 	struct serio *serio = to_serio_port(dev);
 	struct device_driver *drv;
-	int retval;
+	int error;
 
-	retval = mutex_lock_interruptible(&serio_mutex);
-	if (retval)
-		return retval;
+	error = mutex_lock_interruptible(&serio_mutex);
+	if (error)
+		return error;
 
-	retval = count;
 	if (!strncmp(buf, "none", count)) {
 		serio_disconnect_port(serio);
 	} else if (!strncmp(buf, "reconnect", count)) {
@@ -486,15 +475,15 @@ static ssize_t serio_rebind_driver(struc
 		serio_find_driver(serio);
 	} else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
 		serio_disconnect_port(serio);
-		serio_bind_driver(serio, to_serio_driver(drv));
+		error = serio_bind_driver(serio, to_serio_driver(drv));
 		put_driver(drv);
 	} else {
-		retval = -EINVAL;
+		error = -EINVAL;
 	}
 
 	mutex_unlock(&serio_mutex);
 
-	return retval;
+	return error ? error : count;
 }
 
 static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
@@ -665,7 +654,7 @@ static void serio_disconnect_port(struct
 		do {
 			parent = s->parent;
 
-			serio_release_driver(s);
+			device_release_driver(&s->dev);
 			serio_destroy_port(s);
 		} while ((s = parent) != serio);
 	}
@@ -673,7 +662,7 @@ static void serio_disconnect_port(struct
 	/*
 	 * Ok, no children left, now disconnect this port
 	 */
-	serio_release_driver(serio);
+	device_release_driver(&serio->dev);
 }
 
 void serio_rescan(struct serio *serio)
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
new file mode 100644
index 0000000..12dfb0e
--- /dev/null
+++ b/drivers/input/tablet/Kconfig
@@ -0,0 +1,74 @@
+#
+# Tablet driver configuration
+#
+menuconfig INPUT_TABLET
+	bool "Tablets"
+	help
+	  Say Y here, and a list of supported tablets will be displayed.
+	  This option doesn't affect the kernel.
+
+	  If unsure, say Y.
+
+if INPUT_TABLET
+
+config TABLET_USB_ACECAD
+	tristate "Acecad Flair tablet support (USB)"
+	select USB
+	help
+	  Say Y here if you want to use the USB version of the Acecad Flair
+	  tablet.  Make sure to say Y to "Mouse support"
+	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+	  (CONFIG_INPUT_EVDEV) as well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acecad.
+
+config TABLET_USB_AIPTEK
+	tristate "Aiptek 6000U/8000U tablet support (USB)"
+	select USB
+	help
+	  Say Y here if you want to use the USB version of the Aiptek 6000U
+	  or Aiptek 8000U tablet.  Make sure to say Y to "Mouse support"
+	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+	  (CONFIG_INPUT_EVDEV) as well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aiptek.
+
+config TABLET_USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        help
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
+
+config TABLET_USB_KBTAB
+	tristate "KB Gear JamStudio tablet support (USB)"
+	select USB
+	help
+	  Say Y here if you want to use the USB version of the KB Gear
+	  JamStudio tablet.  Make sure to say Y to "Mouse support"
+	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+	  (CONFIG_INPUT_EVDEV) as well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called kbtab.
+
+config TABLET_USB_WACOM
+	tristate "Wacom Intuos/Graphire tablet support (USB)"
+	select USB
+	help
+	  Say Y here if you want to use the USB version of the Wacom Intuos
+	  or Graphire tablet.  Make sure to say Y to "Mouse support"
+	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+	  (CONFIG_INPUT_EVDEV) as well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wacom.
+
+endif
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
new file mode 100644
index 0000000..ce8b9a9
--- /dev/null
+++ b/drivers/input/tablet/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the tablet drivers
+#
+
+# Multipart objects.
+wacom-objs	:= wacom_wac.o wacom_sys.o
+
+obj-$(CONFIG_TABLET_USB_ACECAD)	+= acecad.o
+obj-$(CONFIG_TABLET_USB_AIPTEK)	+= aiptek.o
+obj-$(CONFIG_TABLET_USB_GTCO)	+= gtco.o
+obj-$(CONFIG_TABLET_USB_KBTAB)	+= kbtab.o
+obj-$(CONFIG_TABLET_USB_WACOM)	+= wacom.o
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
new file mode 100644
index 0000000..dd23104
--- /dev/null
+++ b/drivers/input/tablet/acecad.c
@@ -0,0 +1,289 @@
+/*
+ *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
+ *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
+ *
+ *  USB Acecad "Acecad Flair" tablet support
+ *
+ *  Changelog:
+ *      v3.2 - Added sysfs support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v3.2"
+#define DRIVER_DESC    "USB Acecad Flair tablet driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_ACECAD	0x0460
+#define USB_DEVICE_ID_FLAIR	0x0004
+#define USB_DEVICE_ID_302	0x0008
+
+struct usb_acecad {
+	char name[128];
+	char phys[64];
+	struct usb_device *usbdev;
+	struct input_dev *input;
+	struct urb *irq;
+
+	unsigned char *data;
+	dma_addr_t data_dma;
+};
+
+static void usb_acecad_irq(struct urb *urb)
+{
+	struct usb_acecad *acecad = urb->context;
+	unsigned char *data = acecad->data;
+	struct input_dev *dev = acecad->input;
+	int prox, status;
+
+	switch (urb->status) {
+		case 0:
+			/* success */
+			break;
+		case -ECONNRESET:
+		case -ENOENT:
+		case -ESHUTDOWN:
+			/* this urb is terminated, clean up */
+			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+			return;
+		default:
+			dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+			goto resubmit;
+	}
+
+	prox = (data[0] & 0x04) >> 2;
+	input_report_key(dev, BTN_TOOL_PEN, prox);
+
+	if (prox) {
+		int x = data[1] | (data[2] << 8);
+		int y = data[3] | (data[4] << 8);
+		/* Pressure should compute the same way for flair and 302 */
+		int pressure = data[5] | (data[6] << 8);
+		int touch = data[0] & 0x01;
+		int stylus = (data[0] & 0x10) >> 4;
+		int stylus2 = (data[0] & 0x20) >> 5;
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
+		input_report_abs(dev, ABS_PRESSURE, pressure);
+		input_report_key(dev, BTN_TOUCH, touch);
+		input_report_key(dev, BTN_STYLUS, stylus);
+		input_report_key(dev, BTN_STYLUS2, stylus2);
+	}
+
+	/* event termination */
+	input_sync(dev);
+
+resubmit:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		err("can't resubmit intr, %s-%s/input0, status %d",
+			acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+}
+
+static int usb_acecad_open(struct input_dev *dev)
+{
+	struct usb_acecad *acecad = input_get_drvdata(dev);
+
+	acecad->irq->dev = acecad->usbdev;
+	if (usb_submit_urb(acecad->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_acecad_close(struct input_dev *dev)
+{
+	struct usb_acecad *acecad = input_get_drvdata(dev);
+
+	usb_kill_urb(acecad->irq);
+}
+
+static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_host_interface *interface = intf->cur_altsetting;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_acecad *acecad;
+	struct input_dev *input_dev;
+	int pipe, maxp;
+	int err = -ENOMEM;
+
+	if (interface->desc.bNumEndpoints != 1)
+		return -ENODEV;
+
+	endpoint = &interface->endpoint[0].desc;
+
+	if (!usb_endpoint_is_int_in(endpoint))
+		return -ENODEV;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!acecad || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
+	if (!acecad->data) {
+		err= -ENOMEM;
+		goto fail1;
+	}
+
+	acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!acecad->irq) {
+		err = -ENOMEM;
+		goto fail2;
+	}
+
+	acecad->usbdev = dev;
+	acecad->input = input_dev;
+
+	if (dev->manufacturer)
+		strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
+
+	if (dev->product) {
+		if (dev->manufacturer)
+			strlcat(acecad->name, " ", sizeof(acecad->name));
+		strlcat(acecad->name, dev->product, sizeof(acecad->name));
+	}
+
+	usb_make_path(dev, acecad->phys, sizeof(acecad->phys));
+	strlcat(acecad->phys, "/input0", sizeof(acecad->phys));
+
+	input_dev->name = acecad->name;
+	input_dev->phys = acecad->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, acecad);
+
+	input_dev->open = usb_acecad_open;
+	input_dev->close = usb_acecad_close;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+	input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+
+	switch (id->driver_info) {
+		case 0:
+			input_dev->absmax[ABS_X] = 5000;
+			input_dev->absmax[ABS_Y] = 3750;
+			input_dev->absmax[ABS_PRESSURE] = 512;
+			if (!strlen(acecad->name))
+				snprintf(acecad->name, sizeof(acecad->name),
+					"USB Acecad Flair Tablet %04x:%04x",
+					le16_to_cpu(dev->descriptor.idVendor),
+					le16_to_cpu(dev->descriptor.idProduct));
+			break;
+		case 1:
+			input_dev->absmax[ABS_X] = 3000;
+			input_dev->absmax[ABS_Y] = 2250;
+			input_dev->absmax[ABS_PRESSURE] = 1024;
+			if (!strlen(acecad->name))
+				snprintf(acecad->name, sizeof(acecad->name),
+					"USB Acecad 302 Tablet %04x:%04x",
+					le16_to_cpu(dev->descriptor.idVendor),
+					le16_to_cpu(dev->descriptor.idProduct));
+			break;
+	}
+
+	input_dev->absfuzz[ABS_X] = 4;
+	input_dev->absfuzz[ABS_Y] = 4;
+
+	usb_fill_int_urb(acecad->irq, dev, pipe,
+			acecad->data, maxp > 8 ? 8 : maxp,
+			usb_acecad_irq, acecad, endpoint->bInterval);
+	acecad->irq->transfer_dma = acecad->data_dma;
+	acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	err = input_register_device(acecad->input);
+	if (err)
+		goto fail2;
+
+	usb_set_intfdata(intf, acecad);
+
+	return 0;
+
+ fail2:	usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail1: input_free_device(input_dev);
+	kfree(acecad);
+	return err;
+}
+
+static void usb_acecad_disconnect(struct usb_interface *intf)
+{
+	struct usb_acecad *acecad = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (acecad) {
+		usb_kill_urb(acecad->irq);
+		input_unregister_device(acecad->input);
+		usb_free_urb(acecad->irq);
+		usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
+		kfree(acecad);
+	}
+}
+
+static struct usb_device_id usb_acecad_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
+	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),	 .driver_info = 1 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
+
+static struct usb_driver usb_acecad_driver = {
+	.name =		"usb_acecad",
+	.probe =	usb_acecad_probe,
+	.disconnect =	usb_acecad_disconnect,
+	.id_table =	usb_acecad_id_table,
+};
+
+static int __init usb_acecad_init(void)
+{
+	int result = usb_register(&usb_acecad_driver);
+	if (result == 0)
+		info(DRIVER_VERSION ":" DRIVER_DESC);
+	return result;
+}
+
+static void __exit usb_acecad_exit(void)
+{
+	usb_deregister(&usb_acecad_driver);
+}
+
+module_init(usb_acecad_init);
+module_exit(usb_acecad_exit);
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
new file mode 100644
index 0000000..cc0a498
--- /dev/null
+++ b/drivers/input/tablet/aiptek.c
@@ -0,0 +1,2236 @@
+/*
+ *  Native support for the Aiptek HyperPen USB Tablets
+ *  (4000U/5000U/6000U/8000U/12000U)
+ *
+ *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
+ *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
+ *
+ *  based on wacom.c by
+ *     Vojtech Pavlik      <vojtech@suse.cz>
+ *     Andreas Bach Aaen   <abach@stofanet.dk>
+ *     Clifford Wolf       <clifford@clifford.at>
+ *     Sam Mosel           <sam.mosel@computer.org>
+ *     James E. Blair      <corvus@gnu.org>
+ *     Daniel Egger        <egger@suse.de>
+ *
+ *  Many thanks to Oliver Kuechemann for his support.
+ *
+ *  ChangeLog:
+ *      v0.1 - Initial release
+ *      v0.2 - Hack to get around fake event 28's. (Bryan W. Headley)
+ *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
+ *             Released to Linux 2.4.19 and 2.5.x
+ *      v0.4 - Rewrote substantial portions of the code to deal with
+ *             corrected control sequences, timing, dynamic configuration,
+ *             support of 6000U - 12000U, procfs, and macro key support
+ *             (Jan-1-2003 - Feb-5-2003, Bryan W. Headley)
+ *      v1.0 - Added support for diagnostic messages, count of messages
+ *             received from URB - Mar-8-2003, Bryan W. Headley
+ *      v1.1 - added support for tablet resolution, changed DV and proximity
+ *             some corrections - Jun-22-2003, martin schneebacher
+ *           - Added support for the sysfs interface, deprecating the
+ *             procfs interface for 2.5.x kernel. Also added support for
+ *             Wheel command. Bryan W. Headley July-15-2003.
+ *      v1.2 - Reworked jitter timer as a kernel thread.
+ *             Bryan W. Headley November-28-2003/Jan-10-2004.
+ *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
+ *             machines, introduced programmableDelay as a command line
+ *             parameter. Feb 7 2004, Bryan W. Headley.
+ *      v1.4 - Re-wire jitter so it does not require a thread. Courtesy of
+ *             Rene van Paassen. Added reporting of physical pointer device
+ *             (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know
+ *             for reports 1, 6.)
+ *             what physical device reports for reports 1, 6.) Also enabled
+ *             MOUSE and LENS tool button modes. Renamed "rubber" to "eraser".
+ *             Feb 20, 2004, Bryan W. Headley.
+ *      v1.5 - Added previousJitterable, so we don't do jitter delay when the
+ *             user is holding a button down for periods of time.
+ *
+ * NOTE:
+ *      This kernel driver is augmented by the "Aiptek" XFree86 input
+ *      driver for your X server, as well as the Gaiptek GUI Front-end
+ *      "Tablet Manager".
+ *      These three products are highly interactive with one another,
+ *      so therefore it's easier to document them all as one subsystem.
+ *      Please visit the project's "home page", located at,
+ *      http://aiptektablet.sourceforge.net.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.5 (May-15-2004)"
+#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio"
+#define DRIVER_DESC    "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
+
+/*
+ * Aiptek status packet:
+ *
+ * (returned as Report 1 - relative coordinates from mouse and stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     0     1
+ * byte1   0     0     0     0     0    BS2   BS    Tip
+ * byte2  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ *
+ * (returned as Report 2 - absolute coordinates from the stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   IR    DV
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 3 - absolute coordinates from the mouse)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   IR    DV
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 4 - macrokeys from the stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     1     0     0
+ * byte1   0     0     0    BS2   BS    Tip   IR    DV
+ * byte2   0     0     0     0     0     0     1     0
+ * byte3   0     0     0    K4    K3    K2    K1    K0
+ * byte4  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte5  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 5 - macrokeys from the mouse)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     1     0     0
+ * byte1   0     0     0    BS2   BS    Tip   IR    DV
+ * byte2   0     0     0     0     0     0     1     0
+ * byte3   0     0     0    K4    K3    K2    K1    K0
+ * byte4  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte5  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * IR: In Range = Proximity on
+ * DV = Data Valid
+ * BS = Barrel Switch (as in, macro keys)
+ * BS2 also referred to as Tablet Pick
+ *
+ * Command Summary:
+ *
+ * Use report_type CONTROL (3)
+ * Use report_id   2
+ *
+ * Command/Data    Description     Return Bytes    Return Value
+ * 0x10/0x00       SwitchToMouse       0
+ * 0x10/0x01       SwitchToTablet      0
+ * 0x18/0x04       SetResolution       0
+ * 0x12/0xFF       AutoGainOn          0
+ * 0x17/0x00       FilterOn            0
+ * 0x01/0x00       GetXExtension       2           MaxX
+ * 0x01/0x01       GetYExtension       2           MaxY
+ * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
+ * 0x03/0x00       GetODMCode          2           ODMCode
+ * 0x08/0x00       GetPressureLevels   2           =512
+ * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
+ * 0x11/0x02       EnableMacroKeys     0
+ *
+ * To initialize the tablet:
+ *
+ * (1) Send Resolution500LPI (Command)
+ * (2) Query for Model code (Option Report)
+ * (3) Query for ODM code (Option Report)
+ * (4) Query for firmware (Option Report)
+ * (5) Query for GetXExtension (Option Report)
+ * (6) Query for GetYExtension (Option Report)
+ * (7) Query for GetPressureLevels (Option Report)
+ * (8) SwitchToTablet for Absolute coordinates, or
+ *     SwitchToMouse for Relative coordinates (Command)
+ * (9) EnableMacroKeys (Command)
+ * (10) FilterOn (Command)
+ * (11) AutoGainOn (Command)
+ *
+ * (Step 9 can be omitted, but you'll then have no function keys.)
+ */
+
+#define USB_VENDOR_ID_AIPTEK				0x08ca
+#define USB_REQ_GET_REPORT				0x01
+#define USB_REQ_SET_REPORT				0x09
+
+	/* PointerMode codes
+	 */
+#define AIPTEK_POINTER_ONLY_MOUSE_MODE			0
+#define AIPTEK_POINTER_ONLY_STYLUS_MODE			1
+#define AIPTEK_POINTER_EITHER_MODE			2
+
+#define AIPTEK_POINTER_ALLOW_MOUSE_MODE(a)		\
+	(a == AIPTEK_POINTER_ONLY_MOUSE_MODE ||		\
+	 a == AIPTEK_POINTER_EITHER_MODE)
+#define AIPTEK_POINTER_ALLOW_STYLUS_MODE(a)		\
+	(a == AIPTEK_POINTER_ONLY_STYLUS_MODE ||	\
+	 a == AIPTEK_POINTER_EITHER_MODE)
+
+	/* CoordinateMode code
+	 */
+#define AIPTEK_COORDINATE_RELATIVE_MODE			0
+#define AIPTEK_COORDINATE_ABSOLUTE_MODE			1
+
+       /* XTilt and YTilt values
+        */
+#define AIPTEK_TILT_MIN					(-128)
+#define AIPTEK_TILT_MAX					127
+#define AIPTEK_TILT_DISABLE				(-10101)
+
+	/* Wheel values
+	 */
+#define AIPTEK_WHEEL_MIN				0
+#define AIPTEK_WHEEL_MAX				1024
+#define AIPTEK_WHEEL_DISABLE				(-10101)
+
+	/* ToolCode values, which BTW are 0x140 .. 0x14f
+	 * We have things set up such that if TOOL_BUTTON_FIRED_BIT is
+	 * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx.
+	 *
+	 * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will
+	 * get reset.
+	 */
+#define TOOL_BUTTON(x)					((x) & 0x14f)
+#define TOOL_BUTTON_FIRED(x)				((x) & 0x200)
+#define TOOL_BUTTON_FIRED_BIT				0x200
+	/* toolMode codes
+	 */
+#define AIPTEK_TOOL_BUTTON_PEN_MODE			BTN_TOOL_PEN
+#define AIPTEK_TOOL_BUTTON_PEN_MODE			BTN_TOOL_PEN
+#define AIPTEK_TOOL_BUTTON_PENCIL_MODE			BTN_TOOL_PENCIL
+#define AIPTEK_TOOL_BUTTON_BRUSH_MODE			BTN_TOOL_BRUSH
+#define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE		BTN_TOOL_AIRBRUSH
+#define AIPTEK_TOOL_BUTTON_ERASER_MODE			BTN_TOOL_RUBBER
+#define AIPTEK_TOOL_BUTTON_MOUSE_MODE			BTN_TOOL_MOUSE
+#define AIPTEK_TOOL_BUTTON_LENS_MODE			BTN_TOOL_LENS
+
+	/* Diagnostic message codes
+	 */
+#define AIPTEK_DIAGNOSTIC_NA				0
+#define AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE	1
+#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE	2
+#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED		3
+
+	/* Time to wait (in ms) to help mask hand jittering
+	 * when pressing the stylus buttons.
+	 */
+#define AIPTEK_JITTER_DELAY_DEFAULT			50
+
+	/* Time to wait (in ms) in-between sending the tablet
+	 * a command and beginning the process of reading the return
+	 * sequence from the tablet.
+	 */
+#define AIPTEK_PROGRAMMABLE_DELAY_25		25
+#define AIPTEK_PROGRAMMABLE_DELAY_50		50
+#define AIPTEK_PROGRAMMABLE_DELAY_100		100
+#define AIPTEK_PROGRAMMABLE_DELAY_200		200
+#define AIPTEK_PROGRAMMABLE_DELAY_300		300
+#define AIPTEK_PROGRAMMABLE_DELAY_400		400
+#define AIPTEK_PROGRAMMABLE_DELAY_DEFAULT	AIPTEK_PROGRAMMABLE_DELAY_400
+
+	/* Mouse button programming
+	 */
+#define AIPTEK_MOUSE_LEFT_BUTTON		0x01
+#define AIPTEK_MOUSE_RIGHT_BUTTON		0x02
+#define AIPTEK_MOUSE_MIDDLE_BUTTON		0x04
+
+	/* Stylus button programming
+	 */
+#define AIPTEK_STYLUS_LOWER_BUTTON		0x08
+#define AIPTEK_STYLUS_UPPER_BUTTON		0x10
+
+	/* Length of incoming packet from the tablet
+	 */
+#define AIPTEK_PACKET_LENGTH			8
+
+	/* We report in EV_MISC both the proximity and
+	 * whether the report came from the stylus, tablet mouse
+	 * or "unknown" -- Unknown when the tablet is in relative
+	 * mode, because we only get report 1's.
+	 */
+#define AIPTEK_REPORT_TOOL_UNKNOWN		0x10
+#define AIPTEK_REPORT_TOOL_STYLUS		0x20
+#define AIPTEK_REPORT_TOOL_MOUSE		0x40
+
+static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT;
+static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT;
+
+struct aiptek_features {
+	int odmCode;		/* Tablet manufacturer code       */
+	int modelCode;		/* Tablet model code (not unique) */
+	int firmwareCode;	/* prom/eeprom version            */
+	char usbPath[64 + 1];	/* device's physical usb path     */
+	char inputPath[64 + 1];	/* input device path              */
+};
+
+struct aiptek_settings {
+	int pointerMode;	/* stylus-, mouse-only or either */
+	int coordinateMode;	/* absolute/relative coords      */
+	int toolMode;		/* pen, pencil, brush, etc. tool */
+	int xTilt;		/* synthetic xTilt amount        */
+	int yTilt;		/* synthetic yTilt amount        */
+	int wheel;		/* synthetic wheel amount        */
+	int stylusButtonUpper;	/* stylus upper btn delivers...  */
+	int stylusButtonLower;	/* stylus lower btn delivers...  */
+	int mouseButtonLeft;	/* mouse left btn delivers...    */
+	int mouseButtonMiddle;	/* mouse middle btn delivers...  */
+	int mouseButtonRight;	/* mouse right btn delivers...   */
+	int programmableDelay;	/* delay for tablet programming  */
+	int jitterDelay;	/* delay for hand jittering      */
+};
+
+struct aiptek {
+	struct input_dev *inputdev;		/* input device struct           */
+	struct usb_device *usbdev;		/* usb device struct             */
+	struct urb *urb;			/* urb for incoming reports      */
+	dma_addr_t data_dma;			/* our dma stuffage              */
+	struct aiptek_features features;	/* tablet's array of features    */
+	struct aiptek_settings curSetting;	/* tablet's current programmable */
+	struct aiptek_settings newSetting;	/* ... and new param settings    */
+	unsigned int ifnum;			/* interface number for IO       */
+	int diagnostic;				/* tablet diagnostic codes       */
+	unsigned long eventCount;		/* event count                   */
+	int inDelay;				/* jitter: in jitter delay?      */
+	unsigned long endDelay;			/* jitter: time when delay ends  */
+	int previousJitterable;			/* jitterable prev value     */
+	unsigned char *data;			/* incoming packet data          */
+};
+
+/*
+ * Permit easy lookup of keyboard events to send, versus
+ * the bitmap which comes from the tablet. This hides the
+ * issue that the F_keys are not sequentially numbered.
+ */
+static const int macroKeyEvents[] = {
+	KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+	KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
+	KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17,
+	KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23,
+	KEY_F24, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO,
+	KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, 0
+};
+
+/***********************************************************************
+ * Relative reports deliver values in 2's complement format to
+ * deal with negative offsets.
+ */
+static int aiptek_convert_from_2s_complement(unsigned char c)
+{
+	int ret;
+	unsigned char b = c;
+	int negate = 0;
+
+	if ((b & 0x80) != 0) {
+		b = ~b;
+		b--;
+		negate = 1;
+	}
+	ret = b;
+	ret = (negate == 1) ? -ret : ret;
+	return ret;
+}
+
+/***********************************************************************
+ * aiptek_irq can receive one of six potential reports.
+ * The documentation for each is in the body of the function.
+ *
+ * The tablet reports on several attributes per invocation of
+ * aiptek_irq. Because the Linux Input Event system allows the
+ * transmission of ONE attribute per input_report_xxx() call,
+ * collation has to be done on the other end to reconstitute
+ * a complete tablet report. Further, the number of Input Event reports
+ * submitted varies, depending on what USB report type, and circumstance.
+ * To deal with this, EV_MSC is used to indicate an 'end-of-report'
+ * message. This has been an undocumented convention understood by the kernel
+ * tablet driver and clients such as gpm and XFree86's tablet drivers.
+ *
+ * Of the information received from the tablet, the one piece I
+ * cannot transmit is the proximity bit (without resorting to an EV_MSC
+ * convention above.) I therefore have taken over REL_MISC and ABS_MISC
+ * (for relative and absolute reports, respectively) for communicating
+ * Proximity. Why two events? I thought it interesting to know if the
+ * Proximity event occurred while the tablet was in absolute or relative
+ * mode.
+ *
+ * Other tablets use the notion of a certain minimum stylus pressure
+ * to infer proximity. While that could have been done, that is yet
+ * another 'by convention' behavior, the documentation for which
+ * would be spread between two (or more) pieces of software.
+ *
+ * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
+ * replaced with the input_sync() method (which emits EV_SYN.)
+ */
+
+static void aiptek_irq(struct urb *urb)
+{
+	struct aiptek *aiptek = urb->context;
+	unsigned char *data = aiptek->data;
+	struct input_dev *inputdev = aiptek->inputdev;
+	int jitterable = 0;
+	int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
+
+	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;
+	}
+
+	/* See if we are in a delay loop -- throw out report if true.
+	 */
+	if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
+		goto exit;
+	}
+
+	aiptek->inDelay = 0;
+	aiptek->eventCount++;
+
+	/* Report 1 delivers relative coordinates with either a stylus
+	 * or the mouse. You do not know, however, which input
+	 * tool generated the event.
+	 */
+	if (data[0] == 1) {
+		if (aiptek->curSetting.coordinateMode ==
+		    AIPTEK_COORDINATE_ABSOLUTE_MODE) {
+			aiptek->diagnostic =
+			    AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
+		} else {
+			x = aiptek_convert_from_2s_complement(data[2]);
+			y = aiptek_convert_from_2s_complement(data[3]);
+
+			/* jitterable keeps track of whether any button has been pressed.
+			 * We're also using it to remap the physical mouse button mask
+			 * to pseudo-settings. (We don't specifically care about it's
+			 * value after moving/transposing mouse button bitmasks, except
+			 * that a non-zero value indicates that one or more
+			 * mouse button was pressed.)
+			 */
+			jitterable = data[5] & 0x07;
+
+			left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+			right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+			middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+
+			input_report_key(inputdev, BTN_LEFT, left);
+			input_report_key(inputdev, BTN_MIDDLE, middle);
+			input_report_key(inputdev, BTN_RIGHT, right);
+			input_report_rel(inputdev, REL_X, x);
+			input_report_rel(inputdev, REL_Y, y);
+			input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
+
+			/* Wheel support is in the form of a single-event
+			 * firing.
+			 */
+			if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
+				input_report_rel(inputdev, REL_WHEEL,
+						 aiptek->curSetting.wheel);
+				aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+			}
+			input_sync(inputdev);
+		}
+	}
+	/* Report 2 is delivered only by the stylus, and delivers
+	 * absolute coordinates.
+	 */
+	else if (data[0] == 2) {
+		if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
+			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
+		} else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
+			    (aiptek->curSetting.pointerMode)) {
+				aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+		} else {
+			x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+			y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+			z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
+
+			p = (data[5] & 0x01) != 0 ? 1 : 0;
+			dv = (data[5] & 0x02) != 0 ? 1 : 0;
+			tip = (data[5] & 0x04) != 0 ? 1 : 0;
+
+			/* Use jitterable to re-arrange button masks
+			 */
+			jitterable = data[5] & 0x18;
+
+			bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
+			pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
+
+			/* dv indicates 'data valid' (e.g., the tablet is in sync
+			 * and has delivered a "correct" report) We will ignore
+			 * all 'bad' reports...
+			 */
+			if (dv != 0) {
+				/* 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.
+				 */
+				if (TOOL_BUTTON_FIRED
+				    (aiptek->curSetting.toolMode) == 0) {
+					input_report_key(inputdev,
+							 TOOL_BUTTON(aiptek->curSetting.toolMode),
+							 1);
+					aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+				}
+
+				if (p != 0) {
+					input_report_abs(inputdev, ABS_X, x);
+					input_report_abs(inputdev, ABS_Y, y);
+					input_report_abs(inputdev, ABS_PRESSURE, z);
+
+					input_report_key(inputdev, BTN_TOUCH, tip);
+					input_report_key(inputdev, BTN_STYLUS, bs);
+					input_report_key(inputdev, BTN_STYLUS2, pck);
+
+					if (aiptek->curSetting.xTilt !=
+					    AIPTEK_TILT_DISABLE) {
+						input_report_abs(inputdev,
+								 ABS_TILT_X,
+								 aiptek->curSetting.xTilt);
+					}
+					if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
+						input_report_abs(inputdev,
+								 ABS_TILT_Y,
+								 aiptek->curSetting.yTilt);
+					}
+
+					/* Wheel support is in the form of a single-event
+					 * firing.
+					 */
+					if (aiptek->curSetting.wheel !=
+					    AIPTEK_WHEEL_DISABLE) {
+						input_report_abs(inputdev,
+								 ABS_WHEEL,
+								 aiptek->curSetting.wheel);
+						aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+					}
+				}
+				input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
+				input_sync(inputdev);
+			}
+		}
+	}
+	/* Report 3's come from the mouse in absolute mode.
+	 */
+	else if (data[0] == 3) {
+		if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
+			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
+		} else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
+			(aiptek->curSetting.pointerMode)) {
+			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+		} else {
+			x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+			y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+
+			jitterable = data[5] & 0x1c;
+
+			p = (data[5] & 0x01) != 0 ? 1 : 0;
+			dv = (data[5] & 0x02) != 0 ? 1 : 0;
+			left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+			right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+			middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+
+			if (dv != 0) {
+				/* 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.
+				 */
+				if (TOOL_BUTTON_FIRED
+				    (aiptek->curSetting.toolMode) == 0) {
+					input_report_key(inputdev,
+							 TOOL_BUTTON(aiptek->curSetting.toolMode),
+							 1);
+					aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+				}
+
+				if (p != 0) {
+					input_report_abs(inputdev, ABS_X, x);
+					input_report_abs(inputdev, ABS_Y, y);
+
+					input_report_key(inputdev, BTN_LEFT, left);
+					input_report_key(inputdev, BTN_MIDDLE, middle);
+					input_report_key(inputdev, BTN_RIGHT, right);
+
+					/* Wheel support is in the form of a single-event
+					 * firing.
+					 */
+					if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
+						input_report_abs(inputdev,
+								 ABS_WHEEL,
+								 aiptek->curSetting.wheel);
+						aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+					}
+				}
+				input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
+				input_sync(inputdev);
+			}
+		}
+	}
+	/* Report 4s come from the macro keys when pressed by stylus
+	 */
+	else if (data[0] == 4) {
+		jitterable = data[1] & 0x18;
+
+		p = (data[1] & 0x01) != 0 ? 1 : 0;
+		dv = (data[1] & 0x02) != 0 ? 1 : 0;
+		tip = (data[1] & 0x04) != 0 ? 1 : 0;
+		bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
+		pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
+
+		macro = data[3];
+		z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
+
+		if (dv != 0) {
+			/* 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.
+			 */
+			if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+				input_report_key(inputdev,
+						 TOOL_BUTTON(aiptek->curSetting.toolMode),
+						 1);
+				aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+			}
+
+			if (p != 0) {
+				input_report_key(inputdev, BTN_TOUCH, tip);
+				input_report_key(inputdev, BTN_STYLUS, bs);
+				input_report_key(inputdev, BTN_STYLUS2, pck);
+				input_report_abs(inputdev, ABS_PRESSURE, z);
+			}
+
+			/* For safety, we're sending key 'break' codes for the
+			 * neighboring macro keys.
+			 */
+			if (macro > 0) {
+				input_report_key(inputdev,
+						 macroKeyEvents[macro - 1], 0);
+			}
+			if (macro < 25) {
+				input_report_key(inputdev,
+						 macroKeyEvents[macro + 1], 0);
+			}
+			input_report_key(inputdev, macroKeyEvents[macro], p);
+			input_report_abs(inputdev, ABS_MISC,
+					 p | AIPTEK_REPORT_TOOL_STYLUS);
+			input_sync(inputdev);
+		}
+	}
+	/* Report 5s come from the macro keys when pressed by mouse
+	 */
+	else if (data[0] == 5) {
+		jitterable = data[1] & 0x1c;
+
+		p = (data[1] & 0x01) != 0 ? 1 : 0;
+		dv = (data[1] & 0x02) != 0 ? 1 : 0;
+		left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+		right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+		middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+		macro = data[3];
+
+		if (dv != 0) {
+			/* 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.
+			 */
+			if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+				input_report_key(inputdev,
+						 TOOL_BUTTON(aiptek->curSetting.toolMode),
+						 1);
+				aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+			}
+
+			if (p != 0) {
+				input_report_key(inputdev, BTN_LEFT, left);
+				input_report_key(inputdev, BTN_MIDDLE, middle);
+				input_report_key(inputdev, BTN_RIGHT, right);
+			}
+
+			/* For safety, we're sending key 'break' codes for the
+			 * neighboring macro keys.
+			 */
+			if (macro > 0) {
+				input_report_key(inputdev,
+						 macroKeyEvents[macro - 1], 0);
+			}
+			if (macro < 25) {
+				input_report_key(inputdev,
+						 macroKeyEvents[macro + 1], 0);
+			}
+
+			input_report_key(inputdev, macroKeyEvents[macro], 1);
+			input_report_rel(inputdev, ABS_MISC,
+					 p | AIPTEK_REPORT_TOOL_MOUSE);
+			input_sync(inputdev);
+		}
+	}
+	/* We have no idea which tool can generate a report 6. Theoretically,
+	 * neither need to, having been given reports 4 & 5 for such use.
+	 * However, report 6 is the 'official-looking' report for macroKeys;
+	 * reports 4 & 5 supposively are used to support unnamed, unknown
+	 * hat switches (which just so happen to be the macroKeys.)
+	 */
+	else if (data[0] == 6) {
+		macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+		if (macro > 0) {
+			input_report_key(inputdev, macroKeyEvents[macro - 1],
+					 0);
+		}
+		if (macro < 25) {
+			input_report_key(inputdev, macroKeyEvents[macro + 1],
+					 0);
+		}
+
+		/* 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.
+		 */
+		if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+			input_report_key(inputdev,
+					 TOOL_BUTTON(aiptek->curSetting.
+						     toolMode), 1);
+			aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+		}
+
+		input_report_key(inputdev, macroKeyEvents[macro], 1);
+		input_report_abs(inputdev, ABS_MISC,
+				 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
+		input_sync(inputdev);
+	} else {
+		dbg("Unknown report %d", data[0]);
+	}
+
+	/* Jitter may occur when the user presses a button on the stlyus
+	 * or the mouse. What we do to prevent that is wait 'x' milliseconds
+	 * following a 'jitterable' event, which should give the hand some time
+	 * stabilize itself.
+	 *
+	 * We just introduced aiptek->previousJitterable to carry forth the
+	 * notion that jitter occurs when the button state changes from on to off:
+	 * a person drawing, holding a button down is not subject to jittering.
+	 * With that in mind, changing from upper button depressed to lower button
+	 * WILL transition through a jitter delay.
+	 */
+
+	if (aiptek->previousJitterable != jitterable &&
+	    aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
+		aiptek->endDelay = jiffies +
+		    ((aiptek->curSetting.jitterDelay * HZ) / 1000);
+		aiptek->inDelay = 1;
+	}
+	aiptek->previousJitterable = jitterable;
+
+exit:
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval != 0) {
+		err("%s - usb_submit_urb failed with result %d",
+		    __FUNCTION__, retval);
+	}
+}
+
+/***********************************************************************
+ * These are the USB id's known so far. We do not identify them to
+ * specific Aiptek model numbers, because there has been overlaps,
+ * use, and reuse of id's in existing models. Certain models have
+ * been known to use more than one ID, indicative perhaps of
+ * manufacturing revisions. In any event, we consider these
+ * IDs to not be model-specific nor unique.
+ */
+static const struct usb_device_id aiptek_ids[] = {
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)},
+	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, aiptek_ids);
+
+/***********************************************************************
+ * Open an instance of the tablet driver.
+ */
+static int aiptek_open(struct input_dev *inputdev)
+{
+	struct aiptek *aiptek = input_get_drvdata(inputdev);
+
+	aiptek->urb->dev = aiptek->usbdev;
+	if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
+		return -EIO;
+
+	return 0;
+}
+
+/***********************************************************************
+ * Close an instance of the tablet driver.
+ */
+static void aiptek_close(struct input_dev *inputdev)
+{
+	struct aiptek *aiptek = input_get_drvdata(inputdev);
+
+	usb_kill_urb(aiptek->urb);
+}
+
+/***********************************************************************
+ * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
+ * where they were known as usb_set_report and usb_get_report.
+ */
+static int
+aiptek_set_report(struct aiptek *aiptek,
+		  unsigned char report_type,
+		  unsigned char report_id, void *buffer, int size)
+{
+	return usb_control_msg(aiptek->usbdev,
+			       usb_sndctrlpipe(aiptek->usbdev, 0),
+			       USB_REQ_SET_REPORT,
+			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+			       USB_DIR_OUT, (report_type << 8) + report_id,
+			       aiptek->ifnum, buffer, size, 5000);
+}
+
+static int
+aiptek_get_report(struct aiptek *aiptek,
+		  unsigned char report_type,
+		  unsigned char report_id, void *buffer, int size)
+{
+	return usb_control_msg(aiptek->usbdev,
+			       usb_rcvctrlpipe(aiptek->usbdev, 0),
+			       USB_REQ_GET_REPORT,
+			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+			       USB_DIR_IN, (report_type << 8) + report_id,
+			       aiptek->ifnum, buffer, size, 5000);
+}
+
+/***********************************************************************
+ * Send a command to the tablet.
+ */
+static int
+aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
+{
+	const int sizeof_buf = 3 * sizeof(u8);
+	int ret;
+	u8 *buf;
+
+	buf = kmalloc(sizeof_buf, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = 2;
+	buf[1] = command;
+	buf[2] = data;
+
+	if ((ret =
+	     aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
+		dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
+		    command, data);
+	}
+	kfree(buf);
+	return ret < 0 ? ret : 0;
+}
+
+/***********************************************************************
+ * Retrieve information from the tablet. Querying info is defined as first
+ * sending the {command,data} sequence as a command, followed by a wait
+ * (aka, "programmaticDelay") and then a "read" request.
+ */
+static int
+aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
+{
+	const int sizeof_buf = 3 * sizeof(u8);
+	int ret;
+	u8 *buf;
+
+	buf = kmalloc(sizeof_buf, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = 2;
+	buf[1] = command;
+	buf[2] = data;
+
+	if (aiptek_command(aiptek, command, data) != 0) {
+		kfree(buf);
+		return -EIO;
+	}
+	msleep(aiptek->curSetting.programmableDelay);
+
+	if ((ret =
+	     aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
+		dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
+		    buf[0], buf[1], buf[2]);
+		ret = -EIO;
+	} else {
+		ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
+	}
+	kfree(buf);
+	return ret;
+}
+
+/***********************************************************************
+ * Program the tablet into either absolute or relative mode.
+ * We also get information about the tablet's size.
+ */
+static int aiptek_program_tablet(struct aiptek *aiptek)
+{
+	int ret;
+	/* Execute Resolution500LPI */
+	if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0)
+		return ret;
+
+	/* Query getModelCode */
+	if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0)
+		return ret;
+	aiptek->features.modelCode = ret & 0xff;
+
+	/* Query getODMCode */
+	if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0)
+		return ret;
+	aiptek->features.odmCode = ret;
+
+	/* Query getFirmwareCode */
+	if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0)
+		return ret;
+	aiptek->features.firmwareCode = ret;
+
+	/* Query getXextension */
+	if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0)
+		return ret;
+	aiptek->inputdev->absmin[ABS_X] = 0;
+	aiptek->inputdev->absmax[ABS_X] = ret - 1;
+
+	/* Query getYextension */
+	if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0)
+		return ret;
+	aiptek->inputdev->absmin[ABS_Y] = 0;
+	aiptek->inputdev->absmax[ABS_Y] = ret - 1;
+
+	/* Query getPressureLevels */
+	if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0)
+		return ret;
+	aiptek->inputdev->absmin[ABS_PRESSURE] = 0;
+	aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1;
+
+	/* Depending on whether we are in absolute or relative mode, we will
+	 * do a switchToTablet(absolute) or switchToMouse(relative) command.
+	 */
+	if (aiptek->curSetting.coordinateMode ==
+	    AIPTEK_COORDINATE_ABSOLUTE_MODE) {
+		/* Execute switchToTablet */
+		if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) {
+			return ret;
+		}
+	} else {
+		/* Execute switchToMouse */
+		if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) {
+			return ret;
+		}
+	}
+
+	/* Enable the macro keys */
+	if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0)
+		return ret;
+#if 0
+	/* Execute FilterOn */
+	if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0)
+		return ret;
+#endif
+
+	/* Execute AutoGainOn */
+	if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0)
+		return ret;
+
+	/* Reset the eventCount, so we track events from last (re)programming
+	 */
+	aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA;
+	aiptek->eventCount = 0;
+
+	return 0;
+}
+
+/***********************************************************************
+ * Sysfs functions. Sysfs prefers that individually-tunable parameters
+ * exist in their separate pseudo-files. Summary data that is immutable
+ * may exist in a singular file so long as you don't define a writeable
+ * interface.
+ */
+
+/***********************************************************************
+ * support the 'size' file -- display support
+ */
+static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%dx%d\n",
+			aiptek->inputdev->absmax[ABS_X] + 1,
+			aiptek->inputdev->absmax[ABS_Y] + 1);
+}
+
+/* These structs define the sysfs files, param #1 is the name of the
+ * file, param 2 is the file permissions, param 3 & 4 are to the
+ * output generator and input parser routines. Absence of a routine is
+ * permitted -- it only means can't either 'cat' the file, or send data
+ * to it.
+ */
+static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);
+
+/***********************************************************************
+ * support routines for the 'product_id' file
+ */
+static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n",
+			aiptek->inputdev->id.product);
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL);
+
+/***********************************************************************
+ * support routines for the 'vendor_id' file
+ */
+static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor);
+}
+
+static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL);
+
+/***********************************************************************
+ * support routines for the 'vendor' file
+ */
+static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	int retval;
+
+	if (aiptek == NULL)
+		return 0;
+
+	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
+	return retval;
+}
+
+static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL);
+
+/***********************************************************************
+ * support routines for the 'product' file
+ */
+static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	int retval;
+
+	if (aiptek == NULL)
+		return 0;
+
+	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
+	return retval;
+}
+
+static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL);
+
+/***********************************************************************
+ * support routines for the 'pointer_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.pointerMode) {
+	case AIPTEK_POINTER_ONLY_STYLUS_MODE:
+		s = "stylus";
+		break;
+
+	case AIPTEK_POINTER_ONLY_MOUSE_MODE:
+		s = "mouse";
+		break;
+
+	case AIPTEK_POINTER_EITHER_MODE:
+		s = "either";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "stylus") == 0) {
+		aiptek->newSetting.pointerMode =
+		    AIPTEK_POINTER_ONLY_STYLUS_MODE;
+	} else if (strcmp(buf, "mouse") == 0) {
+		aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE;
+	} else if (strcmp(buf, "either") == 0) {
+		aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(pointer_mode,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletPointerMode, store_tabletPointerMode);
+
+/***********************************************************************
+ * support routines for the 'coordinate_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.coordinateMode) {
+	case AIPTEK_COORDINATE_ABSOLUTE_MODE:
+		s = "absolute";
+		break;
+
+	case AIPTEK_COORDINATE_RELATIVE_MODE:
+		s = "relative";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "absolute") == 0) {
+		aiptek->newSetting.pointerMode =
+		    AIPTEK_COORDINATE_ABSOLUTE_MODE;
+	} else if (strcmp(buf, "relative") == 0) {
+		aiptek->newSetting.pointerMode =
+		    AIPTEK_COORDINATE_RELATIVE_MODE;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(coordinate_mode,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletCoordinateMode, store_tabletCoordinateMode);
+
+/***********************************************************************
+ * support routines for the 'tool_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) {
+	case AIPTEK_TOOL_BUTTON_MOUSE_MODE:
+		s = "mouse";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_ERASER_MODE:
+		s = "eraser";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_PENCIL_MODE:
+		s = "pencil";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_PEN_MODE:
+		s = "pen";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_BRUSH_MODE:
+		s = "brush";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE:
+		s = "airbrush";
+		break;
+
+	case AIPTEK_TOOL_BUTTON_LENS_MODE:
+		s = "lens";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "mouse") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE;
+	} else if (strcmp(buf, "eraser") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE;
+	} else if (strcmp(buf, "pencil") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE;
+	} else if (strcmp(buf, "pen") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
+	} else if (strcmp(buf, "brush") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE;
+	} else if (strcmp(buf, "airbrush") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE;
+	} else if (strcmp(buf, "lens") == 0) {
+		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(tool_mode,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletToolMode, store_tabletToolMode);
+
+/***********************************************************************
+ * support routines for the 'xtilt' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
+		return snprintf(buf, PAGE_SIZE, "disable\n");
+	} else {
+		return snprintf(buf, PAGE_SIZE, "%d\n",
+				aiptek->curSetting.xTilt);
+	}
+}
+
+static ssize_t
+store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	int x;
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "disable") == 0) {
+		aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
+	} else {
+		x = (int)simple_strtol(buf, NULL, 10);
+		if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
+			aiptek->newSetting.xTilt = x;
+		}
+	}
+	return count;
+}
+
+static DEVICE_ATTR(xtilt,
+		   S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
+
+/***********************************************************************
+ * support routines for the 'ytilt' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
+		return snprintf(buf, PAGE_SIZE, "disable\n");
+	} else {
+		return snprintf(buf, PAGE_SIZE, "%d\n",
+				aiptek->curSetting.yTilt);
+	}
+}
+
+static ssize_t
+store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	int y;
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "disable") == 0) {
+		aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
+	} else {
+		y = (int)simple_strtol(buf, NULL, 10);
+		if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
+			aiptek->newSetting.yTilt = y;
+		}
+	}
+	return count;
+}
+
+static DEVICE_ATTR(ytilt,
+		   S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
+
+/***********************************************************************
+ * support routines for the 'jitter' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
+}
+
+static ssize_t
+store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
+	return count;
+}
+
+static DEVICE_ATTR(jitter,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletJitterDelay, store_tabletJitterDelay);
+
+/***********************************************************************
+ * support routines for the 'delay' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			aiptek->curSetting.programmableDelay);
+}
+
+static ssize_t
+store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
+	return count;
+}
+
+static DEVICE_ATTR(delay,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletProgrammableDelay, store_tabletProgrammableDelay);
+
+/***********************************************************************
+ * support routines for the 'input_path' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n",
+			aiptek->features.inputPath);
+}
+
+static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL);
+
+/***********************************************************************
+ * support routines for the 'event_count' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
+}
+
+static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
+
+/***********************************************************************
+ * support routines for the 'diagnostic' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *retMsg;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->diagnostic) {
+	case AIPTEK_DIAGNOSTIC_NA:
+		retMsg = "no errors\n";
+		break;
+
+	case AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE:
+		retMsg = "Error: receiving relative reports\n";
+		break;
+
+	case AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE:
+		retMsg = "Error: receiving absolute reports\n";
+		break;
+
+	case AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED:
+		if (aiptek->curSetting.pointerMode ==
+		    AIPTEK_POINTER_ONLY_MOUSE_MODE) {
+			retMsg = "Error: receiving stylus reports\n";
+		} else {
+			retMsg = "Error: receiving mouse reports\n";
+		}
+		break;
+
+	default:
+		return 0;
+	}
+	return snprintf(buf, PAGE_SIZE, retMsg);
+}
+
+static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
+
+/***********************************************************************
+ * support routines for the 'stylus_upper' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.stylusButtonUpper) {
+	case AIPTEK_STYLUS_UPPER_BUTTON:
+		s = "upper";
+		break;
+
+	case AIPTEK_STYLUS_LOWER_BUTTON:
+		s = "lower";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "upper") == 0) {
+		aiptek->newSetting.stylusButtonUpper =
+		    AIPTEK_STYLUS_UPPER_BUTTON;
+	} else if (strcmp(buf, "lower") == 0) {
+		aiptek->newSetting.stylusButtonUpper =
+		    AIPTEK_STYLUS_LOWER_BUTTON;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(stylus_upper,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletStylusUpper, store_tabletStylusUpper);
+
+/***********************************************************************
+ * support routines for the 'stylus_lower' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.stylusButtonLower) {
+	case AIPTEK_STYLUS_UPPER_BUTTON:
+		s = "upper";
+		break;
+
+	case AIPTEK_STYLUS_LOWER_BUTTON:
+		s = "lower";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "upper") == 0) {
+		aiptek->newSetting.stylusButtonLower =
+		    AIPTEK_STYLUS_UPPER_BUTTON;
+	} else if (strcmp(buf, "lower") == 0) {
+		aiptek->newSetting.stylusButtonLower =
+		    AIPTEK_STYLUS_LOWER_BUTTON;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(stylus_lower,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletStylusLower, store_tabletStylusLower);
+
+/***********************************************************************
+ * support routines for the 'mouse_left' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.mouseButtonLeft) {
+	case AIPTEK_MOUSE_LEFT_BUTTON:
+		s = "left";
+		break;
+
+	case AIPTEK_MOUSE_MIDDLE_BUTTON:
+		s = "middle";
+		break;
+
+	case AIPTEK_MOUSE_RIGHT_BUTTON:
+		s = "right";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "left") == 0) {
+		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
+	} else if (strcmp(buf, "middle") == 0) {
+		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON;
+	} else if (strcmp(buf, "right") == 0) {
+		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(mouse_left,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletMouseLeft, store_tabletMouseLeft);
+
+/***********************************************************************
+ * support routines for the 'mouse_middle' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.mouseButtonMiddle) {
+	case AIPTEK_MOUSE_LEFT_BUTTON:
+		s = "left";
+		break;
+
+	case AIPTEK_MOUSE_MIDDLE_BUTTON:
+		s = "middle";
+		break;
+
+	case AIPTEK_MOUSE_RIGHT_BUTTON:
+		s = "right";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "left") == 0) {
+		aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON;
+	} else if (strcmp(buf, "middle") == 0) {
+		aiptek->newSetting.mouseButtonMiddle =
+		    AIPTEK_MOUSE_MIDDLE_BUTTON;
+	} else if (strcmp(buf, "right") == 0) {
+		aiptek->newSetting.mouseButtonMiddle =
+		    AIPTEK_MOUSE_RIGHT_BUTTON;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(mouse_middle,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletMouseMiddle, store_tabletMouseMiddle);
+
+/***********************************************************************
+ * support routines for the 'mouse_right' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+	char *s;
+
+	if (aiptek == NULL)
+		return 0;
+
+	switch (aiptek->curSetting.mouseButtonRight) {
+	case AIPTEK_MOUSE_LEFT_BUTTON:
+		s = "left";
+		break;
+
+	case AIPTEK_MOUSE_MIDDLE_BUTTON:
+		s = "middle";
+		break;
+
+	case AIPTEK_MOUSE_RIGHT_BUTTON:
+		s = "right";
+		break;
+
+	default:
+		s = "unknown";
+		break;
+	}
+	return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (strcmp(buf, "left") == 0) {
+		aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON;
+	} else if (strcmp(buf, "middle") == 0) {
+		aiptek->newSetting.mouseButtonRight =
+		    AIPTEK_MOUSE_MIDDLE_BUTTON;
+	} else if (strcmp(buf, "right") == 0) {
+		aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
+	}
+	return count;
+}
+
+static DEVICE_ATTR(mouse_right,
+		   S_IRUGO | S_IWUGO,
+		   show_tabletMouseRight, store_tabletMouseRight);
+
+/***********************************************************************
+ * support routines for the 'wheel' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
+		return snprintf(buf, PAGE_SIZE, "disable\n");
+	} else {
+		return snprintf(buf, PAGE_SIZE, "%d\n",
+				aiptek->curSetting.wheel);
+	}
+}
+
+static ssize_t
+store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
+	return count;
+}
+
+static DEVICE_ATTR(wheel,
+		   S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
+
+/***********************************************************************
+ * support routines for the 'execute' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	/* There is nothing useful to display, so a one-line manual
+	 * is in order...
+	 */
+	return snprintf(buf, PAGE_SIZE,
+			"Write anything to this file to program your tablet.\n");
+}
+
+static ssize_t
+store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	/* We do not care what you write to this file. Merely the action
+	 * of writing to this file triggers a tablet reprogramming.
+	 */
+	memcpy(&aiptek->curSetting, &aiptek->newSetting,
+	       sizeof(struct aiptek_settings));
+
+	if (aiptek_program_tablet(aiptek) < 0)
+		return -EIO;
+
+	return count;
+}
+
+static DEVICE_ATTR(execute,
+		   S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
+
+/***********************************************************************
+ * support routines for the 'odm_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
+}
+
+static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
+
+/***********************************************************************
+ * support routines for the 'model_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
+}
+
+static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
+
+/***********************************************************************
+ * support routines for the 'firmware_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct aiptek *aiptek = dev_get_drvdata(dev);
+
+	if (aiptek == NULL)
+		return 0;
+
+	return snprintf(buf, PAGE_SIZE, "%04x\n",
+			aiptek->features.firmwareCode);
+}
+
+static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
+
+/***********************************************************************
+ * This routine removes all existing sysfs files managed by this device
+ * driver.
+ */
+static void aiptek_delete_files(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_size);
+	device_remove_file(dev, &dev_attr_product_id);
+	device_remove_file(dev, &dev_attr_vendor_id);
+	device_remove_file(dev, &dev_attr_vendor);
+	device_remove_file(dev, &dev_attr_product);
+	device_remove_file(dev, &dev_attr_pointer_mode);
+	device_remove_file(dev, &dev_attr_coordinate_mode);
+	device_remove_file(dev, &dev_attr_tool_mode);
+	device_remove_file(dev, &dev_attr_xtilt);
+	device_remove_file(dev, &dev_attr_ytilt);
+	device_remove_file(dev, &dev_attr_jitter);
+	device_remove_file(dev, &dev_attr_delay);
+	device_remove_file(dev, &dev_attr_input_path);
+	device_remove_file(dev, &dev_attr_event_count);
+	device_remove_file(dev, &dev_attr_diagnostic);
+	device_remove_file(dev, &dev_attr_odm_code);
+	device_remove_file(dev, &dev_attr_model_code);
+	device_remove_file(dev, &dev_attr_firmware_code);
+	device_remove_file(dev, &dev_attr_stylus_lower);
+	device_remove_file(dev, &dev_attr_stylus_upper);
+	device_remove_file(dev, &dev_attr_mouse_left);
+	device_remove_file(dev, &dev_attr_mouse_middle);
+	device_remove_file(dev, &dev_attr_mouse_right);
+	device_remove_file(dev, &dev_attr_wheel);
+	device_remove_file(dev, &dev_attr_execute);
+}
+
+/***********************************************************************
+ * This routine creates the sysfs files managed by this device
+ * driver.
+ */
+static int aiptek_add_files(struct device *dev)
+{
+	int ret;
+
+	if ((ret = device_create_file(dev, &dev_attr_size)) ||
+	    (ret = device_create_file(dev, &dev_attr_product_id)) ||
+	    (ret = device_create_file(dev, &dev_attr_vendor_id)) ||
+	    (ret = device_create_file(dev, &dev_attr_vendor)) ||
+	    (ret = device_create_file(dev, &dev_attr_product)) ||
+	    (ret = device_create_file(dev, &dev_attr_pointer_mode)) ||
+	    (ret = device_create_file(dev, &dev_attr_coordinate_mode)) ||
+	    (ret = device_create_file(dev, &dev_attr_tool_mode)) ||
+	    (ret = device_create_file(dev, &dev_attr_xtilt)) ||
+	    (ret = device_create_file(dev, &dev_attr_ytilt)) ||
+	    (ret = device_create_file(dev, &dev_attr_jitter)) ||
+	    (ret = device_create_file(dev, &dev_attr_delay)) ||
+	    (ret = device_create_file(dev, &dev_attr_input_path)) ||
+	    (ret = device_create_file(dev, &dev_attr_event_count)) ||
+	    (ret = device_create_file(dev, &dev_attr_diagnostic)) ||
+	    (ret = device_create_file(dev, &dev_attr_odm_code)) ||
+	    (ret = device_create_file(dev, &dev_attr_model_code)) ||
+	    (ret = device_create_file(dev, &dev_attr_firmware_code)) ||
+	    (ret = device_create_file(dev, &dev_attr_stylus_lower)) ||
+	    (ret = device_create_file(dev, &dev_attr_stylus_upper)) ||
+	    (ret = device_create_file(dev, &dev_attr_mouse_left)) ||
+	    (ret = device_create_file(dev, &dev_attr_mouse_middle)) ||
+	    (ret = device_create_file(dev, &dev_attr_mouse_right)) ||
+	    (ret = device_create_file(dev, &dev_attr_wheel)) ||
+	    (ret = device_create_file(dev, &dev_attr_execute))) {
+		err("aiptek: killing own sysfs device files\n");
+		aiptek_delete_files(dev);
+	}
+	return ret;
+}
+
+/***********************************************************************
+ * This routine is called when a tablet has been identified. It basically
+ * sets up the tablet and the driver's internal structures.
+ */
+static int
+aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+	struct usb_endpoint_descriptor *endpoint;
+	struct aiptek *aiptek;
+	struct input_dev *inputdev;
+	struct input_handle *inputhandle;
+	struct list_head *node, *next;
+	int i;
+	int speeds[] = { 0,
+		AIPTEK_PROGRAMMABLE_DELAY_50,
+		AIPTEK_PROGRAMMABLE_DELAY_400,
+		AIPTEK_PROGRAMMABLE_DELAY_25,
+		AIPTEK_PROGRAMMABLE_DELAY_100,
+		AIPTEK_PROGRAMMABLE_DELAY_200,
+		AIPTEK_PROGRAMMABLE_DELAY_300
+	};
+	int err = -ENOMEM;
+
+	/* programmableDelay is where the command-line specified
+	 * delay is kept. We make it the first element of speeds[],
+	 * so therefore, your override speed is tried first, then the
+	 * remainder. Note that the default value of 400ms will be tried
+	 * if you do not specify any command line parameter.
+	 */
+	speeds[0] = programmableDelay;
+
+	aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
+	inputdev = input_allocate_device();
+	if (!aiptek || !inputdev)
+		goto fail1;
+
+	aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
+					GFP_ATOMIC, &aiptek->data_dma);
+	if (!aiptek->data)
+		goto fail1;
+
+	aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!aiptek->urb)
+		goto fail2;
+
+	aiptek->inputdev = inputdev;
+	aiptek->usbdev = usbdev;
+	aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
+	aiptek->inDelay = 0;
+	aiptek->endDelay = 0;
+	aiptek->previousJitterable = 0;
+
+	/* Set up the curSettings struct. Said struct contains the current
+	 * programmable parameters. The newSetting struct contains changes
+	 * the user makes to the settings via the sysfs interface. Those
+	 * changes are not "committed" to curSettings until the user
+	 * writes to the sysfs/.../execute file.
+	 */
+	aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
+	aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE;
+	aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
+	aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE;
+	aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE;
+	aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
+	aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON;
+	aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
+	aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON;
+	aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON;
+	aiptek->curSetting.jitterDelay = jitterDelay;
+	aiptek->curSetting.programmableDelay = programmableDelay;
+
+	/* Both structs should have equivalent settings
+	 */
+	aiptek->newSetting = aiptek->curSetting;
+
+	/* Determine the usb devices' physical path.
+	 * Asketh not why we always pretend we're using "../input0",
+	 * but I suspect this will have to be refactored one
+	 * day if a single USB device can be a keyboard & a mouse
+	 * & a tablet, and the inputX number actually will tell
+	 * us something...
+	 */
+	usb_make_path(usbdev, aiptek->features.usbPath,
+			sizeof(aiptek->features.usbPath));
+	strlcat(aiptek->features.usbPath, "/input0",
+		sizeof(aiptek->features.usbPath));
+
+	/* Set up client data, pointers to open and close routines
+	 * for the input device.
+	 */
+	inputdev->name = "Aiptek";
+	inputdev->phys = aiptek->features.usbPath;
+	usb_to_input_id(usbdev, &inputdev->id);
+	inputdev->dev.parent = &intf->dev;
+
+	input_set_drvdata(inputdev, aiptek);
+
+	inputdev->open = aiptek_open;
+	inputdev->close = aiptek_close;
+
+	/* Now program the capacities of the tablet, in terms of being
+	 * an input device.
+	 */
+	inputdev->evbit[0] |= BIT(EV_KEY)
+	    | BIT(EV_ABS)
+	    | BIT(EV_REL)
+	    | BIT(EV_MSC);
+
+	inputdev->absbit[0] |= BIT(ABS_MISC);
+
+	inputdev->relbit[0] |=
+	    (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC));
+
+	inputdev->keybit[LONG(BTN_LEFT)] |=
+	    (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE));
+
+	inputdev->keybit[LONG(BTN_DIGI)] |=
+	    (BIT(BTN_TOOL_PEN) |
+	     BIT(BTN_TOOL_RUBBER) |
+	     BIT(BTN_TOOL_PENCIL) |
+	     BIT(BTN_TOOL_AIRBRUSH) |
+	     BIT(BTN_TOOL_BRUSH) |
+	     BIT(BTN_TOOL_MOUSE) |
+	     BIT(BTN_TOOL_LENS) |
+	     BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2));
+
+	inputdev->mscbit[0] = BIT(MSC_SERIAL);
+
+	/* Programming the tablet macro keys needs to be done with a for loop
+	 * as the keycodes are discontiguous.
+	 */
+	for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
+		set_bit(macroKeyEvents[i], inputdev->keybit);
+
+	/*
+	 * Program the input device coordinate capacities. We do not yet
+	 * know what maximum X, Y, and Z values are, so we're putting fake
+	 * values in. Later, we'll ask the tablet to put in the correct
+	 * values.
+	 */
+	input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0);
+	input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0);
+	input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
+	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
+
+	endpoint = &intf->altsetting[0].endpoint[0].desc;
+
+	/* Go set up our URB, which is called when the tablet receives
+	 * input.
+	 */
+	usb_fill_int_urb(aiptek->urb,
+			 aiptek->usbdev,
+			 usb_rcvintpipe(aiptek->usbdev,
+					endpoint->bEndpointAddress),
+			 aiptek->data, 8, aiptek_irq, aiptek,
+			 endpoint->bInterval);
+
+	aiptek->urb->transfer_dma = aiptek->data_dma;
+	aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* Program the tablet. This sets the tablet up in the mode
+	 * specified in newSetting, and also queries the tablet's
+	 * physical capacities.
+	 *
+	 * Sanity check: if a tablet doesn't like the slow programmatic
+	 * delay, we often get sizes of 0x0. Let's use that as an indicator
+	 * to try faster delays, up to 25 ms. If that logic fails, well, you'll
+	 * have to explain to us how your tablet thinks it's 0x0, and yet that's
+	 * not an error :-)
+	 */
+
+	for (i = 0; i < ARRAY_SIZE(speeds); ++i) {
+		aiptek->curSetting.programmableDelay = speeds[i];
+		(void)aiptek_program_tablet(aiptek);
+		if (aiptek->inputdev->absmax[ABS_X] > 0) {
+			info("input: Aiptek using %d ms programming speed\n",
+			     aiptek->curSetting.programmableDelay);
+			break;
+		}
+	}
+
+	/* Register the tablet as an Input Device
+	 */
+	err = input_register_device(aiptek->inputdev);
+	if (err)
+		goto fail2;
+
+	/* We now will look for the evdev device which is mapped to
+	 * the tablet. The partial name is kept in the link list of
+	 * input_handles associated with this input device.
+	 * What identifies an evdev input_handler is that it begins
+	 * with 'event', continues with a digit, and that in turn
+	 * is mapped to input/eventN.
+	 */
+	list_for_each_safe(node, next, &inputdev->h_list) {
+		inputhandle = to_handle(node);
+		if (strncmp(inputhandle->name, "event", 5) == 0) {
+			strcpy(aiptek->features.inputPath, inputhandle->name);
+			break;
+		}
+	}
+
+	/* Associate this driver's struct with the usb interface.
+	 */
+	usb_set_intfdata(intf, aiptek);
+
+	/* Set up the sysfs files
+	 */
+	aiptek_add_files(&intf->dev);
+
+	/* Make sure the evdev module is loaded. Assuming evdev IS a module :-)
+	 */
+	if (request_module("evdev") != 0)
+		info("aiptek: error loading 'evdev' module");
+
+	return 0;
+
+ fail2:	usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
+			aiptek->data_dma);
+ fail1:	input_free_device(inputdev);
+	kfree(aiptek);
+	return err;
+}
+
+/***********************************************************************
+ * Deal with tablet disconnecting from the system.
+ */
+static void aiptek_disconnect(struct usb_interface *intf)
+{
+	struct aiptek *aiptek = usb_get_intfdata(intf);
+
+	/* Disassociate driver's struct with usb interface
+	 */
+	usb_set_intfdata(intf, NULL);
+	if (aiptek != NULL) {
+		/* Free & unhook everything from the system.
+		 */
+		usb_kill_urb(aiptek->urb);
+		input_unregister_device(aiptek->inputdev);
+		aiptek_delete_files(&intf->dev);
+		usb_free_urb(aiptek->urb);
+		usb_buffer_free(interface_to_usbdev(intf),
+				AIPTEK_PACKET_LENGTH,
+				aiptek->data, aiptek->data_dma);
+		kfree(aiptek);
+	}
+}
+
+static struct usb_driver aiptek_driver = {
+	.name = "aiptek",
+	.probe = aiptek_probe,
+	.disconnect = aiptek_disconnect,
+	.id_table = aiptek_ids,
+};
+
+static int __init aiptek_init(void)
+{
+	int result = usb_register(&aiptek_driver);
+	if (result == 0) {
+		info(DRIVER_VERSION ": " DRIVER_AUTHOR);
+		info(DRIVER_DESC);
+	}
+	return result;
+}
+
+static void __exit aiptek_exit(void)
+{
+	usb_deregister(&aiptek_driver);
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(programmableDelay, int, 0);
+MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");
+module_param(jitterDelay, int, 0);
+MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");
+
+module_init(aiptek_init);
+module_exit(aiptek_exit);
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
new file mode 100644
index 0000000..b2ca10f
--- /dev/null
+++ b/drivers/input/tablet/gtco.c
@@ -0,0 +1,1055 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+This program is free software; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO	      0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+	struct input_dev  *inputdevice; /* input device struct pointer  */
+	struct usb_device *usbdev; /* the usb device for this device */
+	struct urb        *urbinfo;	 /* urb for incoming reports      */
+	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+	unsigned char *   buffer;   /* databuffer for reports */
+
+	char  usbpath[PATHLENGTH];
+	int   openCount;
+
+	/* Information pulled from Report Descriptor */
+	u32  usage;
+	u32  min_X;
+	u32  max_X;
+	u32  min_Y;
+	u32  max_Y;
+	s8   mintilt_X;
+	s8   maxtilt_X;
+	s8   mintilt_Y;
+	s8   maxtilt_Y;
+	u32  maxpressure;
+	u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+	struct usb_descriptor_header header;
+	__le16   bcdHID;
+	u8       bCountryCode;
+	u8       bNumDescriptors;
+	u8       bDescriptorType;
+	__le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+					int length)
+{
+	int   x, i = 0;
+
+	/* Tag primitive vars */
+	__u8   prefix;
+	__u8   size;
+	__u8   tag;
+	__u8   type;
+	__u8   data   = 0;
+	__u16  data16 = 0;
+	__u32  data32 = 0;
+
+	/* For parsing logic */
+	int   inputnum = 0;
+	__u32 usage = 0;
+
+	/* Global Values, indexed by TAG */
+	__u32 globalval[TAG_GLOB_MAX];
+	__u32 oldval[TAG_GLOB_MAX];
+
+	/* Debug stuff */
+	char  maintype = 'x';
+	char  globtype[12];
+	int   indent = 0;
+	char  indentstr[10] = "";
+
+
+	dbg("======>>>>>>PARSE<<<<<<======");
+
+	/* Walk  this report and pull out the info we need */
+	while (i < length) {
+		prefix = report[i];
+
+		/* Skip over prefix */
+		i++;
+
+		/* Determine data size and save the data in the proper variable */
+		size = PREF_SIZE(prefix);
+		switch (size) {
+		case 1:
+			data = report[i];
+			break;
+		case 2:
+			data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
+			break;
+		case 3:
+			size = 4;
+			data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
+			break;
+		}
+
+		/* Skip size of data */
+		i += size;
+
+		/* What we do depends on the tag type */
+		tag  = PREF_TAG(prefix);
+		type = PREF_TYPE(prefix);
+		switch (type) {
+		case TYPE_MAIN:
+			strcpy(globtype, "");
+			switch (tag) {
+
+			case TAG_MAIN_INPUT:
+				/*
+				 * The INPUT MAIN tag signifies this is
+				 * information from a report.  We need to
+				 * figure out what it is and store the
+				 * min/max values
+				 */
+
+				maintype = 'I';
+				if (data == 2)
+					strcpy(globtype, "Variable");
+				else if (data == 3)
+					strcpy(globtype, "Var|Const");
+
+				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+				    globalval[TAG_GLOB_REPORT_ID], inputnum,
+				    globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+				    globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+				    globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
+
+
+				/*
+				  We can assume that the first two input items
+				  are always the X and Y coordinates.  After
+				  that, we look for everything else by
+				  local usage value
+				 */
+				switch (inputnum) {
+				case 0:  /* X coord */
+					dbg("GER: X Usage: 0x%x", usage);
+					if (device->max_X == 0) {
+						device->max_X = globalval[TAG_GLOB_LOG_MAX];
+						device->min_X = globalval[TAG_GLOB_LOG_MIN];
+					}
+					break;
+
+				case 1:  /* Y coord */
+					dbg("GER: Y Usage: 0x%x", usage);
+					if (device->max_Y == 0) {
+						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+					}
+					break;
+
+				default:
+					/* Tilt X */
+					if (usage == DIGITIZER_USAGE_TILT_X) {
+						if (device->maxtilt_X == 0) {
+							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					/* Tilt Y */
+					if (usage == DIGITIZER_USAGE_TILT_Y) {
+						if (device->maxtilt_Y == 0) {
+							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					/* Pressure */
+					if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {
+						if (device->maxpressure == 0) {
+							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+							device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					break;
+				}
+
+				inputnum++;
+				break;
+
+			case TAG_MAIN_OUTPUT:
+				maintype = 'O';
+				break;
+
+			case TAG_MAIN_FEATURE:
+				maintype = 'F';
+				break;
+
+			case TAG_MAIN_COL_START:
+				maintype = 'S';
+
+				if (data == 0) {
+					dbg("======>>>>>> Physical");
+					strcpy(globtype, "Physical");
+				} else
+					dbg("======>>>>>>");
+
+				/* Indent the debug output */
+				indent++;
+				for (x = 0; x < indent; x++)
+					indentstr[x] = '-';
+				indentstr[x] = 0;
+
+				/* Save global tags */
+				for (x = 0; x < TAG_GLOB_MAX; x++)
+					oldval[x] = globalval[x];
+
+				break;
+
+			case TAG_MAIN_COL_END:
+				dbg("<<<<<<======");
+				maintype = 'E';
+				indent--;
+				for (x = 0; x < indent; x++)
+					indentstr[x] = '-';
+				indentstr[x] = 0;
+
+				/* Copy global tags back */
+				for (x = 0; x < TAG_GLOB_MAX; x++)
+					globalval[x] = oldval[x];
+
+				break;
+			}
+
+			switch (size) {
+			case 1:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr, tag, maintype, size, globtype, data);
+				break;
+
+			case 2:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr, tag, maintype, size, globtype, data16);
+				break;
+
+			case 4:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr, tag, maintype, size, globtype, data32);
+				break;
+			}
+			break;
+
+		case TYPE_GLOBAL:
+			switch (tag) {
+			case TAG_GLOB_USAGE:
+				/*
+				 * First time we hit the global usage tag,
+				 * it should tell us the type of device
+				 */
+				if (device->usage == 0)
+					device->usage = data;
+
+				strcpy(globtype, "USAGE");
+				break;
+
+			case TAG_GLOB_LOG_MIN:
+				strcpy(globtype, "LOG_MIN");
+				break;
+
+			case TAG_GLOB_LOG_MAX:
+				strcpy(globtype, "LOG_MAX");
+				break;
+
+			case TAG_GLOB_PHYS_MIN:
+				strcpy(globtype, "PHYS_MIN");
+				break;
+
+			case TAG_GLOB_PHYS_MAX:
+				strcpy(globtype, "PHYS_MAX");
+				break;
+
+			case TAG_GLOB_UNIT_EXP:
+				strcpy(globtype, "EXP");
+				break;
+
+			case TAG_GLOB_UNIT:
+				strcpy(globtype, "UNIT");
+				break;
+
+			case TAG_GLOB_REPORT_SZ:
+				strcpy(globtype, "REPORT_SZ");
+				break;
+
+			case TAG_GLOB_REPORT_ID:
+				strcpy(globtype, "REPORT_ID");
+				/* New report, restart numbering */
+				inputnum = 0;
+				break;
+
+			case TAG_GLOB_REPORT_CNT:
+				strcpy(globtype, "REPORT_CNT");
+				break;
+
+			case TAG_GLOB_PUSH:
+				strcpy(globtype, "PUSH");
+				break;
+
+			case TAG_GLOB_POP:
+				strcpy(globtype, "POP");
+				break;
+			}
+
+			/* Check to make sure we have a good tag number
+			   so we don't overflow array */
+			if (tag < TAG_GLOB_MAX) {
+				switch (size) {
+				case 1:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+					    indentstr, globtype, tag, size, data);
+					globalval[tag] = data;
+					break;
+
+				case 2:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+					    indentstr, globtype, tag, size, data16);
+					globalval[tag] = data16;
+					break;
+
+				case 4:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+					    indentstr, globtype, tag, size, data32);
+					globalval[tag] = data32;
+					break;
+				}
+			} else {
+				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+				    indentstr, tag, size);
+			}
+			break;
+
+		case TYPE_LOCAL:
+			switch (tag) {
+			case TAG_GLOB_USAGE:
+				strcpy(globtype, "USAGE");
+				/* Always 1 byte */
+				usage = data;
+				break;
+
+			case TAG_GLOB_LOG_MIN:
+				strcpy(globtype, "MIN");
+				break;
+
+			case TAG_GLOB_LOG_MAX:
+				strcpy(globtype, "MAX");
+				break;
+
+			default:
+				strcpy(globtype, "UNKNOWN");
+				break;
+			}
+
+			switch (size) {
+			case 1:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr, tag, globtype, size, data);
+				break;
+
+			case 2:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr, tag, globtype, size, data16);
+				break;
+
+			case 4:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr, tag, globtype, size, data32);
+				break;
+			}
+
+			break;
+		}
+	}
+}
+
+/*   INPUT DRIVER Routines                               */
+
+/*
+ * Called when opening the input device.  This will submit the URB to
+ * the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+	struct gtco *device = input_get_drvdata(inputdev);
+
+	device->urbinfo->dev = device->usbdev;
+	if (usb_submit_urb(device->urbinfo, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * Called when closing the input device.  This will unlink the URB
+ */
+static void gtco_input_close(struct input_dev *inputdev)
+{
+	struct gtco *device = input_get_drvdata(inputdev);
+
+	usb_kill_urb(device->urbinfo);
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void gtco_setup_caps(struct input_dev *inputdev)
+{
+	struct gtco *device = input_get_drvdata(inputdev);
+
+	/* Which events */
+	inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+	/* Misc event menu block */
+	inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+	/* Absolute values based on HID report info */
+	input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+			     0, 0);
+	input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+			     0, 0);
+
+	/* Proximity */
+	input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+	/* Tilt & pressure */
+	input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+			     device->maxtilt_X, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+			     device->maxtilt_Y, 0, 0);
+	input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+			     device->maxpressure, 0, 0);
+
+	/* Transducer */
+	input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);
+}
+
+/*   USB Routines  */
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+	struct gtco *device = urbinfo->context;
+	struct input_dev  *inputdev;
+	int               rc;
+	u32               val = 0;
+	s8                valsigned = 0;
+	char              le_buffer[2];
+
+	inputdev = device->inputdevice;
+
+	/* Was callback OK? */
+	if (urbinfo->status == -ECONNRESET ||
+	    urbinfo->status == -ENOENT ||
+	    urbinfo->status == -ESHUTDOWN) {
+
+		/* Shutdown is occurring. Return and don't queue up any more */
+		return;
+	}
+
+	if (urbinfo->status != 0) {
+		/*
+		 * Some unknown error.  Hopefully temporary. Just go and
+		 * requeue an URB
+		 */
+		goto resubmit;
+	}
+
+	/*
+	 * Good URB, now process
+	 */
+
+	/* PID dependent when we interpret the report */
+	if (inputdev->id.product == PID_1000 ||
+	    inputdev->id.product == PID_1001 ||
+	    inputdev->id.product == PID_1002) {
+
+		/*
+		 * Switch on the report ID
+		 * Conveniently, the reports have more information, the higher
+		 * the report number.  We can just fall through the case
+		 * statements if we start with the highest number report
+		 */
+		switch (device->buffer[0]) {
+		case 5:
+			/* Pressure is 9 bits */
+			val = ((u16)(device->buffer[8]) << 1);
+			val |= (u16)(device->buffer[7] >> 7);
+			input_report_abs(inputdev, ABS_PRESSURE,
+					 device->buffer[8]);
+
+			/* Mask out the Y tilt value used for pressure */
+			device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+			/* Fall thru */
+		case 4:
+			/* Tilt */
+
+			/* Sign extend these 7 bit numbers.  */
+			if (device->buffer[6] & 0x40)
+				device->buffer[6] |= 0x80;
+
+			if (device->buffer[7] & 0x40)
+				device->buffer[7] |= 0x80;
+
+
+			valsigned = (device->buffer[6]);
+			input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+			valsigned = (device->buffer[7]);
+			input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+			/* Fall thru */
+		case 2:
+		case 3:
+			/* Convert buttons, only 5 bits possible */
+			val = (device->buffer[5]) & MASK_BUTTON;
+
+			/* We don't apply any meaning to the bitmask,
+			   just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+			/*  Fall thru */
+		case 1:
+			/* All reports have X and Y coords in the same place */
+			val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+			input_report_abs(inputdev, ABS_X, val);
+
+			val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+			input_report_abs(inputdev, ABS_Y, val);
+
+			/* Ditto for proximity bit */
+			val = device->buffer[5] & MASK_INRANGE ? 1 : 0;
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+			/* Report 1 is an exception to how we handle buttons */
+			/* Buttons are an index, not a bitmask */
+			if (device->buffer[0] == 1) {
+
+				/*
+				 * Convert buttons, 5 bit index
+				 * Report value of index set as one,
+				 * the rest as 0
+				 */
+				val = device->buffer[5] & MASK_BUTTON;
+				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+				    val, val);
+
+				/*
+				 * We don't apply any meaning to the button
+				 * index, just report it
+				 */
+				input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+			}
+			break;
+
+		case 7:
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+			break;
+		}
+	}
+
+	/* Other pid class */
+	if (inputdev->id.product == PID_400 ||
+	    inputdev->id.product == PID_401) {
+
+		/* Report 2 */
+		if (device->buffer[0] == 2) {
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]);
+		}
+
+		/*  Report 1 */
+		if (device->buffer[0] == 1) {
+			char buttonbyte;
+
+			/*  IF X max > 64K, we still a bit from the y report */
+			if (device->max_X > 0x10000) {
+
+				val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]);
+				val |= (u32)(((u8)device->buffer[3] & 0x1) << 16);
+
+				input_report_abs(inputdev, ABS_X, val);
+
+				le_buffer[0]  = (u8)((u8)(device->buffer[3]) >> 1);
+				le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7);
+
+				le_buffer[1]  = (u8)(device->buffer[4] >> 1);
+				le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
+
+				val = le16_to_cpu(get_unaligned((__le16 *)le_buffer));
+				input_report_abs(inputdev, ABS_Y, val);
+
+				/*
+				 * Shift the button byte right by one to
+				 * make it look like the standard report
+				 */
+				buttonbyte = device->buffer[5] >> 1;
+			} else {
+
+				val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+				input_report_abs(inputdev, ABS_X, val);
+
+				val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+				input_report_abs(inputdev, ABS_Y, val);
+
+				buttonbyte = device->buffer[5];
+			}
+
+			/* BUTTONS and PROXIMITY */
+			val = buttonbyte & MASK_INRANGE ? 1 : 0;
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+			/* Convert buttons, only 4 bits possible */
+			val = buttonbyte & 0x0F;
+#ifdef USE_BUTTONS
+			for (i = 0; i < 5; i++)
+				input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));
+#else
+			/* We don't apply any meaning to the bitmask, just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+
+			/* TRANSDUCER */
+			input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+		}
+	}
+
+	/* Everybody gets report ID's */
+	input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+	/* Sync it up */
+	input_sync(inputdev);
+
+ resubmit:
+	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+	if (rc != 0)
+		err("usb_submit_urb failed rc=0x%x", rc);
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+		      const struct usb_device_id *id)
+{
+
+	struct gtco             *gtco;
+	struct input_dev        *input_dev;
+	struct hid_descriptor   *hid_desc;
+	char                    *report = NULL;
+	int                     result = 0, retry;
+	int			error;
+	struct usb_endpoint_descriptor *endpoint;
+
+	/* Allocate memory for device structure */
+	gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!gtco || !input_dev) {
+		err("No more memory");
+		error = -ENOMEM;
+		goto err_free_devs;
+	}
+
+	/* Set pointer to the input device */
+	gtco->inputdevice = input_dev;
+
+	/* Save interface information */
+	gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+
+	/* Allocate some data for incoming reports */
+	gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
+					GFP_KERNEL, &gtco->buf_dma);
+	if (!gtco->buffer) {
+		err("No more memory for us buffers");
+		error = -ENOMEM;
+		goto err_free_devs;
+	}
+
+	/* Allocate URB for reports */
+	gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+	if (!gtco->urbinfo) {
+		err("Failed to allocate URB");
+		return -ENOMEM;
+		goto err_free_buf;
+	}
+
+	/*
+	 * The endpoint is always altsetting 0, we know this since we know
+	 * this device only has one interrupt endpoint
+	 */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	/* Some debug */
+	dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
+	dbg("num endpoints:     %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
+	dbg("interface class:   %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
+	dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+		dbg("endpoint: we have interrupt endpoint\n");
+
+	dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
+
+	/*
+	 * Find the HID descriptor so we can find out the size of the
+	 * HID report descriptor
+	 */
+	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+				     HID_DEVICE_TYPE, &hid_desc) != 0){
+		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+		error = -EIO;
+		goto err_free_urb;
+	}
+
+	dbg("Extra descriptor success: type:%d  len:%d",
+	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+	report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+	if (!report) {
+		err("No more memory for report");
+		error = -ENOMEM;
+		goto err_free_urb;
+	}
+
+	/* Couple of tries to get reply */
+	for (retry = 0; retry < 3; retry++) {
+		result = usb_control_msg(gtco->usbdev,
+					 usb_rcvctrlpipe(gtco->usbdev, 0),
+					 USB_REQ_GET_DESCRIPTOR,
+					 USB_RECIP_INTERFACE | USB_DIR_IN,
+					 REPORT_DEVICE_TYPE << 8,
+					 0, /* interface */
+					 report,
+					 hid_desc->wDescriptorLength,
+					 5000); /* 5 secs */
+
+		if (result == hid_desc->wDescriptorLength)
+			break;
+	}
+
+	/* If we didn't get the report, fail */
+	dbg("usb_control_msg result: :%d", result);
+	if (result != hid_desc->wDescriptorLength) {
+		err("Failed to get HID Report Descriptor of size: %d",
+		    hid_desc->wDescriptorLength);
+		error = -EIO;
+		goto err_free_urb;
+	}
+
+	/* Now we parse the report */
+	parse_hid_report_descriptor(gtco, report, result);
+
+	/* Now we delete it */
+	kfree(report);
+
+	/* Create a device file node */
+	usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath));
+	strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
+
+	/* Set Input device functions */
+	input_dev->open = gtco_input_open;
+	input_dev->close = gtco_input_close;
+
+	/* Set input device information */
+	input_dev->name = "GTCO_CalComp";
+	input_dev->phys = gtco->usbpath;
+
+	input_set_drvdata(input_dev, gtco);
+
+	/* Now set up all the input device capabilities */
+	gtco_setup_caps(input_dev);
+
+	/* Set input device required ID information */
+	usb_to_input_id(gtco->usbdev, &input_dev->id);
+	input_dev->dev.parent = &usbinterface->dev;
+
+	/* Setup the URB, it will be posted later on open of input device */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	usb_fill_int_urb(gtco->urbinfo,
+			 gtco->usbdev,
+			 usb_rcvintpipe(gtco->usbdev,
+					endpoint->bEndpointAddress),
+			 gtco->buffer,
+			 REPORT_MAX_SIZE,
+			 gtco_urb_callback,
+			 gtco,
+			 endpoint->bInterval);
+
+	gtco->urbinfo->transfer_dma = gtco->buf_dma;
+	gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* Save gtco pointer in USB interface gtco */
+	usb_set_intfdata(usbinterface, gtco);
+
+	/* All done, now register the input device */
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_urb;
+
+	return 0;
+
+ err_free_urb:
+	usb_free_urb(gtco->urbinfo);
+ err_free_buf:
+	usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+			gtco->buffer, gtco->buf_dma);
+ err_free_devs:
+	kfree(report);
+	input_free_device(input_dev);
+	kfree(gtco);
+	return error;
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+	/* Grab private device ptr */
+	struct gtco *gtco = usb_get_intfdata(interface);
+
+	/* Now reverse all the registration stuff */
+	if (gtco) {
+		input_unregister_device(gtco->inputdevice);
+		usb_kill_urb(gtco->urbinfo);
+		usb_free_urb(gtco->urbinfo);
+		usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+				gtco->buffer, gtco->buf_dma);
+		kfree(gtco);
+	}
+
+	info("gtco driver disconnected");
+}
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+	.name		= "gtco",
+	.id_table	= gtco_usbid_table,
+	.probe		= gtco_probe,
+	.disconnect	= gtco_disconnect,
+};
+
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+	int error;
+
+	error = usb_register(&gtco_driverinfo_table);
+	if (error) {
+		err("usb_register() failed rc=0x%x", error);
+		return error;
+	}
+
+	printk("GTCO usb driver version: %s", GTCO_VERSION);
+	return 0;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+	usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init(gtco_init);
+module_exit(gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
new file mode 100644
index 0000000..91e6d00
--- /dev/null
+++ b/drivers/input/tablet/kbtab.c
@@ -0,0 +1,226 @@
+#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
+ * v0.0.1 - Original, extremely basic version, 2.4.xx only
+ * v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
+ *           - added pressure-threshold modules param code from
+ *              Alex Perry <alex.perry@ieee.org>
+ */
+
+#define DRIVER_VERSION "v0.0.2"
+#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
+#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_KBGEAR	0x084e
+
+static int kb_pressure_click = 0x10;
+module_param(kb_pressure_click, int, 0);
+MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks");
+
+struct kbtab {
+	unsigned char *data;
+	dma_addr_t data_dma;
+	struct input_dev *dev;
+	struct usb_device *usbdev;
+	struct urb *irq;
+	int x, y;
+	int button;
+	int pressure;
+	__u32 serial[2];
+	char phys[32];
+};
+
+static void kbtab_irq(struct urb *urb)
+{
+	struct kbtab *kbtab = urb->context;
+	unsigned char *data = kbtab->data;
+	struct input_dev *dev = kbtab->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;
+	}
+
+	kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
+	kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
+
+	kbtab->pressure = (data[5]);
+
+	input_report_key(dev, BTN_TOOL_PEN, 1);
+
+	input_report_abs(dev, ABS_X, kbtab->x);
+	input_report_abs(dev, ABS_Y, kbtab->y);
+
+	/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
+	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+	if (-1 == kb_pressure_click) {
+		input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
+	} else {
+		input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
+	};
+
+	input_sync(dev);
+
+ exit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, retval);
+}
+
+static struct usb_device_id kbtab_ids[] = {
+	{ USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, kbtab_ids);
+
+static int kbtab_open(struct input_dev *dev)
+{
+	struct kbtab *kbtab = input_get_drvdata(dev);
+
+	kbtab->irq->dev = kbtab->usbdev;
+	if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void kbtab_close(struct input_dev *dev)
+{
+	struct kbtab *kbtab = input_get_drvdata(dev);
+
+	usb_kill_urb(kbtab->irq);
+}
+
+static int kbtab_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 kbtab *kbtab;
+	struct input_dev *input_dev;
+	int error = -ENOMEM;
+
+	kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!kbtab || !input_dev)
+		goto fail1;
+
+	kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
+	if (!kbtab->data)
+		goto fail1;
+
+	kbtab->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kbtab->irq)
+		goto fail2;
+
+	kbtab->usbdev = dev;
+	kbtab->dev = input_dev;
+
+	usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
+	strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys));
+
+	input_dev->name = "KB Gear Tablet";
+	input_dev->phys = kbtab->phys;
+	usb_to_input_id(dev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, kbtab);
+
+	input_dev->open = kbtab_open;
+	input_dev->close = kbtab_close;
+
+	input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+	input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
+	input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+	input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
+
+	endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+	usb_fill_int_urb(kbtab->irq, dev,
+			 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+			 kbtab->data, 8,
+			 kbtab_irq, kbtab, endpoint->bInterval);
+	kbtab->irq->transfer_dma = kbtab->data_dma;
+	kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	error = input_register_device(kbtab->dev);
+	if (error)
+		goto fail3;
+
+	usb_set_intfdata(intf, kbtab);
+
+	return 0;
+
+ fail3:	usb_free_urb(kbtab->irq);
+ fail2:	usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
+ fail1:	input_free_device(input_dev);
+	kfree(kbtab);
+	return error;
+}
+
+static void kbtab_disconnect(struct usb_interface *intf)
+{
+	struct kbtab *kbtab = usb_get_intfdata(intf);
+
+	usb_set_intfdata(intf, NULL);
+	if (kbtab) {
+		usb_kill_urb(kbtab->irq);
+		input_unregister_device(kbtab->dev);
+		usb_free_urb(kbtab->irq);
+		usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
+		kfree(kbtab);
+	}
+}
+
+static struct usb_driver kbtab_driver = {
+	.name =		"kbtab",
+	.probe =	kbtab_probe,
+	.disconnect =	kbtab_disconnect,
+	.id_table =	kbtab_ids,
+};
+
+static int __init kbtab_init(void)
+{
+	int retval;
+	retval = usb_register(&kbtab_driver);
+	if (retval)
+		goto out;
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+out:
+	return retval;
+}
+
+static void __exit kbtab_exit(void)
+{
+	usb_deregister(&kbtab_driver);
+}
+
+module_init(kbtab_init);
+module_exit(kbtab_exit);
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
new file mode 100644
index 0000000..ef01a80
--- /dev/null
+++ b/drivers/input/tablet/wacom.h
@@ -0,0 +1,131 @@
+/*
+ * drivers/input/tablet/wacom.h
+ *
+ *  USB Wacom Graphire and Wacom Intuos tablet support
+ *
+ *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@ucw.cz>
+ *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
+ *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
+ *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
+ *  Copyright (c) 2000 James E. Blair		<corvus@gnu.org>
+ *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
+ *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
+ *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
+ *  Copyright (c) 2002-2006 Ping Cheng		<pingc@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@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_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/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
new file mode 100644
index 0000000..83bddef
--- /dev/null
+++ b/drivers/input/tablet/wacom_sys.c
@@ -0,0 +1,318 @@
+/*
+ * drivers/input/tablet/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;
+}
+
+static 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 = input_get_drvdata(dev);
+
+	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 = input_get_drvdata(dev);
+
+	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, 4096, 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, 4096, 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;
+	int error = -ENOMEM;
+	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->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, 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;
+
+	error = input_register_device(wacom->dev);
+	if (error)
+		goto fail3;
+
+	/* 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;
+
+ fail3:	usb_free_urb(wacom->irq);
+ fail2:	usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+ fail1:	input_free_device(input_dev);
+	kfree(wacom);
+	kfree(wacom_wac);
+	return error;
+}
+
+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/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
new file mode 100644
index 0000000..7661f03
--- /dev/null
+++ b/drivers/input/tablet/wacom_wac.c
@@ -0,0 +1,675 @@
+/*
+ * drivers/input/tablet/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] & 0x80) { /* 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;
+		}
+		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);
+		}
+		wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+		wacom_report_key(wcombo, wacom->tool[0], 1);
+	} else if (!(data[1] & 0x90)) {
+		wacom_report_abs(wcombo, ABS_X, 0);
+		wacom_report_abs(wcombo, ABS_Y, 0);
+		if (wacom->tool[0] == BTN_TOOL_MOUSE) {
+			wacom_report_key(wcombo, BTN_LEFT, 0);
+			wacom_report_key(wcombo, BTN_RIGHT, 0);
+			wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+		} else {
+			wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+			wacom_report_key(wcombo, BTN_TOUCH, 0);
+			wacom_report_key(wcombo, BTN_STYLUS, 0);
+			wacom_report_key(wcombo, BTN_STYLUS2, 0);
+		}
+		wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+		wacom_report_key(wcombo, wacom->tool[0], 0);
+	}
+
+	/* send pad data */
+	if (wacom->features->type == WACOM_G4) {
+		if (data[7] & 0xf8) {
+			wacom_input_sync(wcombo); /* sync last event */
+			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_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+			wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+		} else if (wacom->id[1]) {
+			wacom_input_sync(wcombo); /* sync last event */
+			wacom->id[1] = 0;
+			wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+			wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+			wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+			wacom_report_abs(wcombo, ABS_MISC, 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;
+		}
+		return 1;
+	}
+
+	/* Exit report */
+	if ((data[1] & 0xfe) == 0x80) {
+		wacom_report_abs(wcombo, ABS_X, 0);
+		wacom_report_abs(wcombo, ABS_Y, 0);
+		wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+			wacom_report_key(wcombo, BTN_LEFT, 0);
+			wacom_report_key(wcombo, BTN_MIDDLE, 0);
+			wacom_report_key(wcombo, BTN_RIGHT, 0);
+			wacom_report_key(wcombo, BTN_SIDE, 0);
+			wacom_report_key(wcombo, BTN_EXTRA, 0);
+			wacom_report_abs(wcombo, ABS_THROTTLE, 0);
+			wacom_report_abs(wcombo, ABS_RZ, 0);
+ 		} else {
+			wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+			wacom_report_abs(wcombo, ABS_TILT_X, 0);
+			wacom_report_abs(wcombo, ABS_TILT_Y, 0);
+			wacom_report_key(wcombo, BTN_STYLUS, 0);
+			wacom_report_key(wcombo, BTN_STYLUS2, 0);
+			wacom_report_key(wcombo, BTN_TOUCH, 0);
+			wacom_report_abs(wcombo, ABS_WHEEL, 0);
+		}
+		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_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+		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;
+
+	/* Only large I3 and I1 & I2 support Lense Cursor */
+ 	if((wacom->tool[idx] == BTN_TOOL_LENS)
+			&& ((wacom->features->type == INTUOS3)
+		 	|| (wacom->features->type == INTUOS3S)))
+		return 0;
+
+	/* 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 >= INTUOS3S) {
+		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 >= INTUOS3S) {
+				/* 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, 63, GRAPHIRE },
+	{ "Wacom PenStation2",   8,   3250,  2320,  255, 63, GRAPHIRE },
+	{ "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
+	{ "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
+	{ "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
+	{ "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
+	{ "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
+	{ "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
+	{ "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 31, INTUOS },
+	{ "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 31, 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, 31, INTUOS },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
+	{ "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 31, INTUOS },
+	{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, 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, 63, INTUOS3S },
+	{ "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
+	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, 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/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
new file mode 100644
index 0000000..a5e12e8
--- /dev/null
+++ b/drivers/input/tablet/wacom_wac.h
@@ -0,0 +1,49 @@
+/*
+ * drivers/input/tablet/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
+#define PAD_DEVICE_ID		0x0F
+
+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 {
+	unsigned char *data;
+        int tool[2];
+        int id[2];
+        __u32 serial[2];
+	struct wacom_features *features;
+};
+
+#endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 9716180..5e640ae 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1,5 +1,5 @@
 #
-# Mouse driver configuration
+# Touchscreen driver configuration
 #
 menuconfig INPUT_TOUCHSCREEN
 	bool "Touchscreens"
@@ -44,9 +44,9 @@ config TOUCHSCREEN_BITSY
 config TOUCHSCREEN_CORGI
 	tristate "SharpSL (Corgi and Spitz series) touchscreen driver"
 	depends on PXA_SHARPSL
-	default y	
+	default y
 	help
-	  Say Y here to enable the driver for the touchscreen on the 
+	  Say Y here to enable the driver for the touchscreen on the
 	  Sharp SL-C7xx and SL-Cxx00 series of PDAs.
 
 	  If unsure, say N.
@@ -164,4 +164,58 @@ config TOUCHSCREEN_UCB1400
 	  To compile this driver as a module, choose M here: the
 	  module will be called ucb1400_ts.
 
+config TOUCHSCREEN_USB_COMPOSITE
+	tristate "USB Touchscreen Driver"
+	select USB
+	help
+	  USB Touchscreen driver for:
+	  - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
+	  - PanJit TouchSet USB
+	  - 3M MicroTouch USB (EX II series)
+	  - ITM
+	  - some other eTurboTouch
+	  - Gunze AHL61
+	  - DMC TSC-10/25
+
+	  Have a look at <http://linux.chapter7.ch/touchkit/> for
+	  a usage description and the required user-space stuff.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usbtouchscreen.
+
+config TOUCHSCREEN_USB_EGALAX
+	default y
+	bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_PANJIT
+	default y
+	bool "PanJit device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_3M
+	default y
+	bool "3M/Microtouch EX II series device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ITM
+	default y
+	bool "ITM device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETURBO
+	default y
+	bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GUNZE
+	default y
+	bool "Gunze AHL61 device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_DMC_TSC10
+	default y
+	bool "DMC TSC-10/25 device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 30e6e22..2f86d6a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -1,17 +1,18 @@
 #
-# Makefile for the mouse drivers.
+# Makefile for the touchscreen drivers.
 #
 
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
-obj-$(CONFIG_TOUCHSCREEN_BITSY)	+= h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_CORGI)	+= corgi_ts.o
-obj-$(CONFIG_TOUCHSCREEN_GUNZE)	+= gunze.o
-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_BITSY)		+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CORGI)		+= corgi_ts.o
+obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
+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_USB_COMPOSITE)	+= usbtouchscreen.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 0a26e06..693e3b2 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -39,7 +39,8 @@ #endif
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
  * tested on other ads7846 devices (OSK/Mistral, Lubbock).
- * Support for ads7843 and ads7845 has only been stubbed in.
+ * Support for ads7843 tested on Atmel at91sam926x-EK.
+ * Support for ads7845 has only been stubbed in.
  *
  * IRQ handling needs a workaround because of a shortcoming in handling
  * edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -246,18 +247,16 @@ static int ads7846_read12_ser(struct dev
 
 	/* REVISIT:  take a few more samples, and compare ... */
 
-	/* maybe off internal vREF */
-	if (use_internal) {
-		req->ref_off = REF_OFF;
-		req->xfer[4].tx_buf = &req->ref_off;
-		req->xfer[4].len = 1;
-		spi_message_add_tail(&req->xfer[4], &req->msg);
-
-		req->xfer[5].rx_buf = &req->scratch;
-		req->xfer[5].len = 2;
-		CS_CHANGE(req->xfer[5]);
-		spi_message_add_tail(&req->xfer[5], &req->msg);
-	}
+	/* converter in low power mode & enable PENIRQ */
+	req->ref_off = PWRDOWN;
+	req->xfer[4].tx_buf = &req->ref_off;
+	req->xfer[4].len = 1;
+	spi_message_add_tail(&req->xfer[4], &req->msg);
+
+	req->xfer[5].rx_buf = &req->scratch;
+	req->xfer[5].len = 2;
+	CS_CHANGE(req->xfer[5]);
+	spi_message_add_tail(&req->xfer[5], &req->msg);
 
 	ts->irq_disabled = 1;
 	disable_irq(spi->irq);
@@ -536,6 +535,9 @@ static void ads7846_rx(void *ads)
 	} else
 		Rt = 0;
 
+	if (ts->model == 7843)
+		Rt = ts->pressure_max / 2;
+
 	/* Sample found inconsistent by debouncing or pressure is beyond
 	 * the maximum. Don't report it to user space, repeat at least
 	 * once more the measurement
@@ -897,7 +899,7 @@ static int __devinit ads7846_probe(struc
 
 	input_dev->name = "ADS784x Touchscreen";
 	input_dev->phys = ts->phys;
-	input_dev->cdev.dev = &spi->dev;
+	input_dev->dev.parent = &spi->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index e294558..e6a31d1 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -300,8 +300,7 @@ static int __init corgits_probe(struct p
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0002;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &pdev->dev;
-	input_dev->private = corgi_ts;
+	input_dev->dev.parent = &pdev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 9d61cd1..557d781 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -312,14 +312,13 @@ static int elo_connect(struct serio *ser
 	init_completion(&elo->cmd_done);
 	snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
 
-	input_dev->private = elo;
 	input_dev->name = "Elo Serial TouchScreen";
 	input_dev->phys = elo->phys;
 	input_dev->id.bustype = BUS_RS232;
 	input_dev->id.vendor = SERIO_ELO;
 	input_dev->id.product = elo->id;
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
+	input_dev->dev.parent = &serio->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 9157eb1..39d6026 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -130,13 +130,13 @@ static int gunze_connect(struct serio *s
 	gunze->dev = input_dev;
 	snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
 
-	input_dev->private = gunze;
 	input_dev->name = "Gunze AHL-51S TouchScreen";
 	input_dev->phys = gunze->phys;
 	input_dev->id.bustype = BUS_RS232;
 	input_dev->id.vendor = SERIO_GUNZE;
 	input_dev->id.product = 0x0051;
 	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &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(input_dev, ABS_X, 24, 1000, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index c4116d4..09ed780 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -147,7 +147,7 @@ enum flite_pwr {
 unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
 {
 	unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
-	struct h3600_dev *ts = dev->private;
+	struct h3600_dev *ts = input_get_drvdata(dev);
 
 	/* Must be in this order */
 	ts->serio->write(ts->serio, 1);
@@ -260,7 +260,7 @@ static int h3600ts_event(struct input_de
 			 unsigned int code, int value)
 {
 #if 0
-	struct h3600_dev *ts = dev->private;
+	struct h3600_dev *ts = input_get_drvdata(dev);
 
 	switch (type) {
 		case EV_LED: {
@@ -367,8 +367,9 @@ static int h3600ts_connect(struct serio 
 	input_dev->id.vendor = SERIO_H3600;
 	input_dev->id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
 	input_dev->id.version = 0x0100;
-	input_dev->cdev.dev = &serio->dev;
-	input_dev->private = ts;
+	input_dev->dev.parent = &serio->dev;
+
+	input_set_drvdata(input_dev, ts);
 
 	input_dev->event = h3600ts_event;
 
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 2490874..61c1502 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -21,7 +21,7 @@ #define SCPDR	0xa4000136
 static void do_softint(void *data);
 
 static struct input_dev *hp680_ts_dev;
-static DECLARE_WORK(work, do_softint, 0);
+static DECLARE_WORK(work, do_softint);
 
 static void do_softint(void *data)
 {
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index c3c2d73..4ec3b1f 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -144,13 +144,13 @@ static int mtouch_connect(struct serio *
 	mtouch->dev = input_dev;
 	snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
 
-	input_dev->private = mtouch;
 	input_dev->name = "MicroTouch Serial TouchScreen";
 	input_dev->phys = mtouch->phys;
 	input_dev->id.bustype = BUS_RS232;
 	input_dev->id.vendor = SERIO_MICROTOUCH;
 	input_dev->id.product = 0;
 	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &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(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index bd27679..f2c0d3c 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -105,14 +105,13 @@ static int pm_connect(struct serio *seri
 	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->dev.parent = &serio->dev;
 
         input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
         input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 35ba46c..3def7bb 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -118,13 +118,13 @@ static int tr_connect(struct serio *seri
 	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->dev.parent = &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(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 4dc073d..ac4bdcf 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -125,13 +125,13 @@ static int tw_connect(struct serio *seri
 	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->dev.parent = &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(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index e8606c4..6582816 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -97,6 +97,8 @@ struct ucb1400 {
 };
 
 static int adcsync;
+static int ts_delay = 55; /* us */
+static int ts_delay_pressure;	/* us */
 
 static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
 {
@@ -159,6 +161,7 @@ static inline unsigned int ucb1400_ts_re
 			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
 			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	udelay(ts_delay_pressure);
 	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
 }
 
@@ -180,7 +183,7 @@ static inline unsigned int ucb1400_ts_re
 			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
 			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
 
-	udelay(55);
+	udelay(ts_delay);
 
 	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
 }
@@ -203,7 +206,7 @@ static inline unsigned int ucb1400_ts_re
 			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
 			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
 
-	udelay(55);
+	udelay(ts_delay);
 
 	return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
 }
@@ -369,7 +372,7 @@ static irqreturn_t ucb1400_hard_irq(int 
 
 static int ucb1400_ts_open(struct input_dev *idev)
 {
-	struct ucb1400 *ucb = idev->private;
+	struct ucb1400 *ucb = input_get_drvdata(idev);
 	int ret = 0;
 
 	BUG_ON(ucb->ts_task);
@@ -385,7 +388,7 @@ static int ucb1400_ts_open(struct input_
 
 static void ucb1400_ts_close(struct input_dev *idev)
 {
-	struct ucb1400 *ucb = idev->private;
+	struct ucb1400 *ucb = input_get_drvdata(idev);
 
 	if (ucb->ts_task)
 		kthread_stop(ucb->ts_task);
@@ -507,8 +510,9 @@ static int ucb1400_ts_probe(struct devic
 	}
 	printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
 
-	idev->private		= ucb;
-	idev->cdev.dev		= dev;
+	input_set_drvdata(idev, ucb);
+
+	idev->dev.parent	= dev;
 	idev->name		= "UCB1400 touchscreen interface";
 	idev->id.vendor		= ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
 	idev->id.product	= id;
@@ -571,7 +575,15 @@ static void __exit ucb1400_ts_exit(void)
 	driver_unregister(&ucb1400_ts_driver);
 }
 
-module_param(adcsync, int, 0444);
+module_param(adcsync, bool, 0444);
+MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
+
+module_param(ts_delay, int, 0444);
+MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us.");
+
+module_param(ts_delay_pressure, int, 0444);
+MODULE_PARM_DESC(ts_delay_pressure,
+		  "delay between panel setup and pressure read.  Default = 0us.");
 
 module_init(ucb1400_ts_init);
 module_exit(ucb1400_ts_exit);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
new file mode 100644
index 0000000..8e18e6c
--- /dev/null
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -0,0 +1,839 @@
+/******************************************************************************
+ * usbtouchscreen.c
+ * Driver for USB Touchscreens, supporting those devices:
+ *  - eGalax Touchkit
+ *    includes eTurboTouch CT-410/510/700
+ *  - 3M/Microtouch  EX II series
+ *  - ITM
+ *  - PanJit TouchSet
+ *  - eTurboTouch
+ *  - Gunze AHL61
+ *  - DMC TSC-10/25
+ *
+ * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Driver is based on touchkitusb.c
+ * - ITM parts are from itmtouch.c
+ * - 3M parts are from mtouchusb.c
+ * - PanJit parts are from an unmerged driver by Lanslott Gish
+ * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
+ *   driver from Marius Vollmer
+ *
+ *****************************************************************************/
+
+//#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+
+#define DRIVER_VERSION		"v0.5"
+#define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
+#define DRIVER_DESC		"USB Touchscreen Driver"
+
+static int swap_xy;
+module_param(swap_xy, bool, 0644);
+MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
+
+/* device specifc data/functions */
+struct usbtouch_usb;
+struct usbtouch_device_info {
+	int min_xc, max_xc;
+	int min_yc, max_yc;
+	int min_press, max_press;
+	int rept_size;
+	int flags;
+
+	void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
+	int  (*get_pkt_len) (unsigned char *pkt, int len);
+	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+	int  (*init)        (struct usbtouch_usb *usbtouch);
+};
+
+#define USBTOUCH_FLG_BUFFER	0x01
+
+
+/* a usbtouch device */
+struct usbtouch_usb {
+	unsigned char *data;
+	dma_addr_t data_dma;
+	unsigned char *buffer;
+	int buf_len;
+	struct urb *irq;
+	struct usb_device *udev;
+	struct input_dev *input;
+	struct usbtouch_device_info *type;
+	char name[128];
+	char phys[64];
+
+	int x, y;
+	int touch, press;
+};
+
+
+#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 {
+	DEVTPYE_DUMMY = -1,
+	DEVTYPE_EGALAX,
+	DEVTYPE_PANJIT,
+	DEVTYPE_3M,
+	DEVTYPE_ITM,
+	DEVTYPE_ETURBO,
+	DEVTYPE_GUNZE,
+	DEVTYPE_DMC_TSC10,
+};
+
+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
+	{USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_3M
+	{USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_ITM
+	{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
+
+#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
+	{USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
+#endif
+
+	{}
+};
+
+
+/*****************************************************************************
+ * eGalax part
+ */
+
+#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
+
+#define EGALAX_PKT_TYPE_MASK		0xFE
+#define EGALAX_PKT_TYPE_REPT		0x80
+#define EGALAX_PKT_TYPE_DIAG		0x0A
+
+static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
+		return 0;
+
+	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
+	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+
+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;
+}
+#endif
+
+
+/*****************************************************************************
+ * PanJit Part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
+static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
+	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * 3M/Microtouch Part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_3M
+
+#define MTOUCHUSB_ASYNC_REPORT          1
+#define MTOUCHUSB_RESET                 7
+#define MTOUCHUSB_REQ_CTRLLR_ID         10
+
+static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = (pkt[8] << 8) | pkt[7];
+	dev->y = (pkt[10] << 8) | pkt[9];
+	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
+
+	return 1;
+}
+
+static int mtouch_init(struct usbtouch_usb *usbtouch)
+{
+	int ret, i;
+
+	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+	                      MTOUCHUSB_RESET,
+	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
+	    __FUNCTION__, 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;
+}
+#endif
+
+
+/*****************************************************************************
+ * ITM Part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_ITM
+static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	int touch;
+	/*
+	 * ITM devices report invalid x/y data if not touched.
+	 * if the screen was touched before but is not touched any more
+	 * report touch as 0 with the last valid x/y data once. then stop
+	 * reporting data until touched again.
+	 */
+	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
+
+	touch = ~pkt[7] & 0x20;
+	if (!touch) {
+		if (dev->touch) {
+			dev->touch = 0;
+			return 1;
+		}
+
+		return 0;
+	}
+
+	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
+	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
+	dev->touch = touch;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * eTurboTouch part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	unsigned int shift;
+
+	/* packets should start with sync */
+	if (!(pkt[0] & 0x80))
+		return 0;
+
+	shift = (6 - (pkt[0] & 0x03));
+	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
+	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
+	dev->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(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
+		return 0;
+
+	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
+	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
+	dev->touch = pkt[0] & 0x20;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * DMC TSC-10/25 Part
+ *
+ * Documentation about the controller and it's protocol can be found at
+ *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
+ *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
+
+/* supported data rates. currently using 130 */
+#define TSC10_RATE_POINT	0x50
+#define TSC10_RATE_30		0x40
+#define TSC10_RATE_50		0x41
+#define TSC10_RATE_80		0x42
+#define TSC10_RATE_100		0x43
+#define TSC10_RATE_130		0x44
+#define TSC10_RATE_150		0x45
+
+/* commands */
+#define TSC10_CMD_RESET		0x55
+#define TSC10_CMD_RATE		0x05
+#define TSC10_CMD_DATA1		0x01
+
+static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
+{
+	struct usb_device *dev = usbtouch->udev;
+	int ret;
+	unsigned char buf[2];
+
+	/* reset */
+	buf[0] = buf[1] = 0xFF;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_RESET,
+	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0)
+		return ret;
+	if (buf[0] != 0x06 || buf[1] != 0x00)
+		return -ENODEV;
+
+	/* set coordinate output rate */
+	buf[0] = buf[1] = 0xFF;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_RATE,
+	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0)
+		return ret;
+	if (buf[0] != 0x06 || buf[1] != 0x00)
+		return -ENODEV;
+
+	/* start sending data */
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_DATA1,
+	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+
+static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
+	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * the different device descriptors
+ */
+static struct usbtouch_device_info usbtouch_dev_info[] = {
+#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
+	[DEVTYPE_EGALAX] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x07ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x07ff,
+		.rept_size	= 16,
+		.flags		= USBTOUCH_FLG_BUFFER,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= egalax_get_pkt_len,
+		.read_data	= egalax_read_data,
+	},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
+	[DEVTYPE_PANJIT] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 8,
+		.read_data	= panjit_read_data,
+	},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_3M
+	[DEVTYPE_3M] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x4000,
+		.min_yc		= 0x0,
+		.max_yc		= 0x4000,
+		.rept_size	= 11,
+		.read_data	= mtouch_read_data,
+		.init		= mtouch_init,
+	},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_ITM
+	[DEVTYPE_ITM] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.max_press	= 0xff,
+		.rept_size	= 8,
+		.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
+
+#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
+	[DEVTYPE_DMC_TSC10] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x03ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x03ff,
+		.rept_size	= 5,
+		.init		= dmc_tsc10_init,
+		.read_data	= dmc_tsc10_read_data,
+	},
+#endif
+};
+
+
+/*****************************************************************************
+ * Generic Part
+ */
+static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
+                                 unsigned char *pkt, int len)
+{
+	struct usbtouch_device_info *type = usbtouch->type;
+
+	if (!type->read_data(usbtouch, pkt))
+			return;
+
+	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
+
+	if (swap_xy) {
+		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
+		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
+	} else {
+		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
+		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
+	}
+	if (type->max_press)
+		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
+	input_sync(usbtouch->input);
+}
+
+
+#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;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ETIME:
+		/* this urb is timing out */
+		dbg("%s - urb timed out - was the device unplugged?",
+		    __FUNCTION__);
+		return;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, urb->status);
+		goto exit;
+	}
+
+	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
+
+exit:
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result: %d",
+		    __FUNCTION__, retval);
+}
+
+static int usbtouch_open(struct input_dev *input)
+{
+	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+
+	usbtouch->irq->dev = usbtouch->udev;
+
+	if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
+		return -EIO;
+
+	return 0;
+}
+
+static void usbtouch_close(struct input_dev *input)
+{
+	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+
+	usb_kill_urb(usbtouch->irq);
+}
+
+
+static void usbtouch_free_buffers(struct usb_device *udev,
+				  struct usbtouch_usb *usbtouch)
+{
+	usb_buffer_free(udev, usbtouch->type->rept_size,
+	                usbtouch->data, usbtouch->data_dma);
+	kfree(usbtouch->buffer);
+}
+
+
+static int usbtouch_probe(struct usb_interface *intf,
+			  const struct usb_device_id *id)
+{
+	struct usbtouch_usb *usbtouch;
+	struct input_dev *input_dev;
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usbtouch_device_info *type;
+	int err = -ENOMEM;
+
+	interface = intf->cur_altsetting;
+	endpoint = &interface->endpoint[0].desc;
+
+	usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!usbtouch || !input_dev)
+		goto out_free;
+
+	type = &usbtouch_dev_info[id->driver_info];
+	usbtouch->type = type;
+	if (!type->process_pkt)
+		type->process_pkt = usbtouch_process_pkt;
+
+	usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
+	                                  GFP_KERNEL, &usbtouch->data_dma);
+	if (!usbtouch->data)
+		goto out_free;
+
+	if (type->flags & USBTOUCH_FLG_BUFFER) {
+		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
+		if (!usbtouch->buffer)
+			goto out_free_buffers;
+	}
+
+	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usbtouch->irq) {
+		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__);
+		goto out_free_buffers;
+	}
+
+	usbtouch->udev = udev;
+	usbtouch->input = input_dev;
+
+	if (udev->manufacturer)
+		strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
+
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
+		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
+	}
+
+	if (!strlen(usbtouch->name))
+		snprintf(usbtouch->name, sizeof(usbtouch->name),
+			"USB Touchscreen %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
+	strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
+
+	input_dev->name = usbtouch->name;
+	input_dev->phys = usbtouch->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, usbtouch);
+
+	input_dev->open = usbtouch_open;
+	input_dev->close = usbtouch_close;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
+	if (type->max_press)
+		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
+		                     type->max_press, 0, 0);
+
+	usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
+			 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;
+
+	/* device specific init */
+	if (type->init) {
+		err = type->init(usbtouch);
+		if (err) {
+			dbg("%s - type->init() failed, err: %d", __FUNCTION__, err);
+			goto out_free_buffers;
+		}
+	}
+
+	err = input_register_device(usbtouch->input);
+	if (err) {
+		dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err);
+		goto out_free_buffers;
+	}
+
+	usb_set_intfdata(intf, usbtouch);
+
+	return 0;
+
+out_free_buffers:
+	usbtouch_free_buffers(udev, usbtouch);
+out_free:
+	input_free_device(input_dev);
+	kfree(usbtouch);
+	return err;
+}
+
+static void usbtouch_disconnect(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+	dbg("%s - called", __FUNCTION__);
+
+	if (!usbtouch)
+		return;
+
+	dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__);
+	usb_set_intfdata(intf, NULL);
+	usb_kill_urb(usbtouch->irq);
+	input_unregister_device(usbtouch->input);
+	usb_free_urb(usbtouch->irq);
+	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
+	kfree(usbtouch);
+}
+
+MODULE_DEVICE_TABLE(usb, usbtouch_devices);
+
+static struct usb_driver usbtouch_driver = {
+	.name		= "usbtouchscreen",
+	.probe		= usbtouch_probe,
+	.disconnect	= usbtouch_disconnect,
+	.id_table	= usbtouch_devices,
+};
+
+static int __init usbtouch_init(void)
+{
+	return usb_register(&usbtouch_driver);
+}
+
+static void __exit usbtouch_cleanup(void)
+{
+	usb_deregister(&usbtouch_driver);
+}
+
+module_init(usbtouch_init);
+module_exit(usbtouch_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("touchkitusb");
+MODULE_ALIAS("itmtouch");
+MODULE_ALIAS("mtouchusb");
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index 0300dca..8238b13 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -48,7 +48,6 @@ #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/major.h>
-#include <linux/smp_lock.h>
 #include <linux/random.h>
 #include <linux/time.h>
 #include <linux/device.h>
@@ -111,13 +110,13 @@ struct tsdev {
 	int minor;
 	char name[8];
 	wait_queue_head_t wait;
-	struct list_head list;
+	struct list_head client_list;
 	struct input_handle handle;
 	int x, y, pressure;
 	struct ts_calibration cal;
 };
 
-struct tsdev_list {
+struct tsdev_client {
 	struct fasync_struct *fasync;
 	struct list_head node;
 	struct tsdev *tsdev;
@@ -139,38 +138,49 @@ static struct tsdev *tsdev_table[TSDEV_M
 
 static int tsdev_fasync(int fd, struct file *file, int on)
 {
-	struct tsdev_list *list = file->private_data;
+	struct tsdev_client *client = file->private_data;
 	int retval;
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
+	retval = fasync_helper(fd, file, on, &client->fasync);
 	return retval < 0 ? retval : 0;
 }
 
 static int tsdev_open(struct inode *inode, struct file *file)
 {
 	int i = iminor(inode) - TSDEV_MINOR_BASE;
-	struct tsdev_list *list;
+	struct tsdev_client *client;
+	struct tsdev *tsdev;
+	int error;
 
 	printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
 		"for removal.\nSee Documentation/feature-removal-schedule.txt "
 		"for details.\n");
 
-	if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
+	if (i >= TSDEV_MINORS)
+		return -ENODEV;
+
+	tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
+	if (!tsdev || !tsdev->exist)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+	client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
+	if (!client)
 		return -ENOMEM;
 
-	list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+	client->tsdev = tsdev;
+	client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
+	list_add_tail(&client->node, &tsdev->client_list);
 
-	i &= TSDEV_MINOR_MASK;
-	list->tsdev = tsdev_table[i];
-	list_add_tail(&list->node, &tsdev_table[i]->list);
-	file->private_data = list;
+	if (!tsdev->open++ && tsdev->exist) {
+		error = input_open_device(&tsdev->handle);
+		if (error) {
+			list_del(&client->node);
+			kfree(client);
+			return error;
+		}
+	}
 
-	if (!list->tsdev->open++)
-		if (list->tsdev->exist)
-			input_open_device(&list->tsdev->handle);
+	file->private_data = client;
 	return 0;
 }
 
@@ -182,45 +192,48 @@ static void tsdev_free(struct tsdev *tsd
 
 static int tsdev_release(struct inode *inode, struct file *file)
 {
-	struct tsdev_list *list = file->private_data;
+	struct tsdev_client *client = file->private_data;
+	struct tsdev *tsdev = client->tsdev;
 
 	tsdev_fasync(-1, file, 0);
-	list_del(&list->node);
 
-	if (!--list->tsdev->open) {
-		if (list->tsdev->exist)
-			input_close_device(&list->tsdev->handle);
+	list_del(&client->node);
+	kfree(client);
+
+	if (!--tsdev->open) {
+		if (tsdev->exist)
+			input_close_device(&tsdev->handle);
 		else
-			tsdev_free(list->tsdev);
+			tsdev_free(tsdev);
 	}
-	kfree(list);
+
 	return 0;
 }
 
 static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
-			  loff_t * ppos)
+			  loff_t *ppos)
 {
-	struct tsdev_list *list = file->private_data;
+	struct tsdev_client *client = file->private_data;
+	struct tsdev *tsdev = client->tsdev;
 	int retval = 0;
 
-	if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
+	if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(list->tsdev->wait,
-			list->head != list->tail || !list->tsdev->exist);
-
+	retval = wait_event_interruptible(tsdev->wait,
+			client->head != client->tail || !tsdev->exist);
 	if (retval)
 		return retval;
 
-	if (!list->tsdev->exist)
+	if (!tsdev->exist)
 		return -ENODEV;
 
-	while (list->head != list->tail &&
+	while (client->head != client->tail &&
 	       retval + sizeof (struct ts_event) <= count) {
-		if (copy_to_user (buffer + retval, list->event + list->tail,
+		if (copy_to_user (buffer + retval, client->event + client->tail,
 				  sizeof (struct ts_event)))
 			return -EFAULT;
-		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+		client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
 		retval += sizeof (struct ts_event);
 	}
 
@@ -228,32 +241,33 @@ static ssize_t tsdev_read(struct file *f
 }
 
 /* No kernel lock - fine */
-static unsigned int tsdev_poll(struct file *file, poll_table * wait)
+static unsigned int tsdev_poll(struct file *file, poll_table *wait)
 {
-	struct tsdev_list *list = file->private_data;
+	struct tsdev_client *client = file->private_data;
+	struct tsdev *tsdev = client->tsdev;
 
-	poll_wait(file, &list->tsdev->wait, wait);
-	return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-		(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
+	poll_wait(file, &tsdev->wait, wait);
+	return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+		(tsdev->exist ? 0 : (POLLHUP | POLLERR));
 }
 
 static int tsdev_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-	struct tsdev_list *list = file->private_data;
-	struct tsdev *tsdev = list->tsdev;
+	struct tsdev_client *client = file->private_data;
+	struct tsdev *tsdev = client->tsdev;
 	int retval = 0;
 
 	switch (cmd) {
 	case TS_GET_CAL:
-		if (copy_to_user ((void __user *)arg, &tsdev->cal,
-				  sizeof (struct ts_calibration)))
+		if (copy_to_user((void __user *)arg, &tsdev->cal,
+				 sizeof (struct ts_calibration)))
 			retval = -EFAULT;
 		break;
 
 	case TS_SET_CAL:
-		if (copy_from_user (&tsdev->cal, (void __user *)arg,
-				    sizeof (struct ts_calibration)))
+		if (copy_from_user(&tsdev->cal, (void __user *)arg,
+				   sizeof (struct ts_calibration)))
 			retval = -EFAULT;
 		break;
 
@@ -279,7 +293,7 @@ static void tsdev_event(struct input_han
 			unsigned int code, int value)
 {
 	struct tsdev *tsdev = handle->private;
-	struct tsdev_list *list;
+	struct tsdev_client *client;
 	struct timeval time;
 
 	switch (type) {
@@ -343,18 +357,18 @@ static void tsdev_event(struct input_han
 	if (type != EV_SYN || code != SYN_REPORT)
 		return;
 
-	list_for_each_entry(list, &tsdev->list, node) {
+	list_for_each_entry(client, &tsdev->client_list, node) {
 		int x, y, tmp;
 
 		do_gettimeofday(&time);
-		list->event[list->head].millisecs = time.tv_usec / 100;
-		list->event[list->head].pressure = tsdev->pressure;
+		client->event[client->head].millisecs = time.tv_usec / 100;
+		client->event[client->head].pressure = tsdev->pressure;
 
 		x = tsdev->x;
 		y = tsdev->y;
 
 		/* Calibration */
-		if (!list->raw) {
+		if (!client->raw) {
 			x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
 			y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
 			if (tsdev->cal.xyswap) {
@@ -362,33 +376,35 @@ static void tsdev_event(struct input_han
 			}
 		}
 
-		list->event[list->head].x = x;
-		list->event[list->head].y = y;
-		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
-		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		client->event[client->head].x = x;
+		client->event[client->head].y = y;
+		client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+		kill_fasync(&client->fasync, SIGIO, POLL_IN);
 	}
 	wake_up_interruptible(&tsdev->wait);
 }
 
-static struct input_handle *tsdev_connect(struct input_handler *handler,
-					  struct input_dev *dev,
-					  const struct input_device_id *id)
+static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
+			 const struct input_device_id *id)
 {
 	struct tsdev *tsdev;
 	struct class_device *cdev;
+	dev_t devt;
 	int minor, delta;
+	int error;
 
 	for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
 	if (minor >= TSDEV_MINORS / 2) {
 		printk(KERN_ERR
 		       "tsdev: You have way too many touchscreens\n");
-		return NULL;
+		return -ENFILE;
 	}
 
-	if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
-		return NULL;
+	tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
+	if (!tsdev)
+		return -ENOMEM;
 
-	INIT_LIST_HEAD(&tsdev->list);
+	INIT_LIST_HEAD(&tsdev->client_list);
 	init_waitqueue_head(&tsdev->wait);
 
 	sprintf(tsdev->name, "ts%d", minor);
@@ -415,23 +431,45 @@ static struct input_handle *tsdev_connec
 
 	tsdev_table[minor] = tsdev;
 
-	cdev = class_device_create(&input_class, &dev->cdev,
-			MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
-			dev->cdev.dev, tsdev->name);
+	devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+
+	cdev = class_device_create(&input_class, &dev->cdev, devt,
+				   dev->cdev.dev, tsdev->name);
+	if (IS_ERR(cdev)) {
+		error = PTR_ERR(cdev);
+		goto err_free_tsdev;
+	}
 
 	/* temporary symlink to keep userspace happy */
-	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
-			  tsdev->name);
+	error = sysfs_create_link(&input_class.subsys.kobj,
+				  &cdev->kobj, tsdev->name);
+	if (error)
+		goto err_cdev_destroy;
+
+	error = input_register_handle(&tsdev->handle);
+	if (error)
+		goto err_remove_link;
 
-	return &tsdev->handle;
+	return 0;
+
+ err_remove_link:
+	sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
+ err_cdev_destroy:
+	class_device_destroy(&input_class, devt);
+ err_free_tsdev:
+	tsdev_table[minor] = NULL;
+	kfree(tsdev);
+	return error;
 }
 
 static void tsdev_disconnect(struct input_handle *handle)
 {
 	struct tsdev *tsdev = handle->private;
-	struct tsdev_list *list;
+	struct tsdev_client *client;
+
+	input_unregister_handle(handle);
 
-	sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
+	sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
 	class_device_destroy(&input_class,
 			MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
 	tsdev->exist = 0;
@@ -439,8 +477,8 @@ static void tsdev_disconnect(struct inpu
 	if (tsdev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&tsdev->wait);
-		list_for_each_entry(list, &tsdev->list, node)
-			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+		list_for_each_entry(client, &tsdev->client_list, node)
+			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
 	} else
 		tsdev_free(tsdev);
 }
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index e3e5c13..ee2b0b9 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -442,7 +442,7 @@ act2000_sendbuf(act2000_card *card, int 
 			return 0;
 		}
 		skb_reserve(xmit_skb, 19);
-		memcpy(skb_put(xmit_skb, len), skb->data, len);
+		skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len);
 	} else {
 		xmit_skb = skb_clone(skb, GFP_ATOMIC);
 		if (!xmit_skb) {
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index db1260f..81661b8 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -18,8 +18,8 @@ #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
 #include <linux/signal.h>
+#include <linux/mutex.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -147,7 +147,7 @@ struct capidev {
 
 	struct capincci *nccis;
 
-	struct semaphore ncci_list_sem;
+	struct mutex ncci_list_mtx;
 };
 
 /* -------- global variables ---------------------------------------- */
@@ -395,7 +395,7 @@ static struct capidev *capidev_alloc(voi
 	if (!cdev)
 		return NULL;
 
-	init_MUTEX(&cdev->ncci_list_sem);
+	mutex_init(&cdev->ncci_list_mtx);
 	skb_queue_head_init(&cdev->recvqueue);
 	init_waitqueue_head(&cdev->recvwait);
 	write_lock_irqsave(&capidev_list_lock, flags);
@@ -414,9 +414,9 @@ static void capidev_free(struct capidev 
 	}
 	skb_queue_purge(&cdev->recvqueue);
 
-	down(&cdev->ncci_list_sem);
+	mutex_lock(&cdev->ncci_list_mtx);
 	capincci_free(cdev, 0xffffffff);
-	up(&cdev->ncci_list_sem);
+	mutex_unlock(&cdev->ncci_list_mtx);
 
 	write_lock_irqsave(&capidev_list_lock, flags);
 	list_del(&cdev->list);
@@ -603,15 +603,15 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 	if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
 		u16 info = CAPIMSG_U16(skb->data, 12); // Info field
 		if (info == 0) {
-			down(&cdev->ncci_list_sem);
+			mutex_lock(&cdev->ncci_list_mtx);
 			capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
-			up(&cdev->ncci_list_sem);
+			mutex_unlock(&cdev->ncci_list_mtx);
 		}
 	}
 	if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
-		down(&cdev->ncci_list_sem);
+		mutex_lock(&cdev->ncci_list_mtx);
 		capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
-		up(&cdev->ncci_list_sem);
+		mutex_unlock(&cdev->ncci_list_mtx);
 	}
 	spin_lock_irqsave(&workaround_lock, flags);
 	if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
@@ -752,9 +752,9 @@ capi_write(struct file *file, const char
 	CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
 
 	if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
-		down(&cdev->ncci_list_sem);
+		mutex_lock(&cdev->ncci_list_mtx);
 		capincci_free(cdev, CAPIMSG_NCCI(skb->data));
-		up(&cdev->ncci_list_sem);
+		mutex_unlock(&cdev->ncci_list_mtx);
 	}
 
 	cdev->errcode = capi20_put_message(&cdev->ap, skb);
@@ -939,9 +939,9 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 			if (copy_from_user(&ncci, argp, sizeof(ncci)))
 				return -EFAULT;
 
-			down(&cdev->ncci_list_sem);
+			mutex_lock(&cdev->ncci_list_mtx);
 			if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
-				up(&cdev->ncci_list_sem);
+				mutex_unlock(&cdev->ncci_list_mtx);
 				return 0;
 			}
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -949,7 +949,7 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 				count += atomic_read(&mp->ttyopencount);
 			}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-			up(&cdev->ncci_list_sem);
+			mutex_unlock(&cdev->ncci_list_mtx);
 			return count;
 		}
 		return 0;
@@ -964,14 +964,14 @@ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 			if (copy_from_user(&ncci, argp,
 					   sizeof(ncci)))
 				return -EFAULT;
-			down(&cdev->ncci_list_sem);
+			mutex_lock(&cdev->ncci_list_mtx);
 			nccip = capincci_find(cdev, (u32) ncci);
 			if (!nccip || (mp = nccip->minorp) == 0) {
-				up(&cdev->ncci_list_sem);
+				mutex_unlock(&cdev->ncci_list_mtx);
 				return -ESRCH;
 			}
 			unit = mp->minor;
-			up(&cdev->ncci_list_sem);
+			mutex_unlock(&cdev->ncci_list_mtx);
 			return unit;
 		}
 		return 0;
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index ad1e270..22379b9 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -855,7 +855,7 @@ static _cdebbuf *g_debbuf;
 static u_long g_debbuf_lock;
 static _cmsg *g_cmsg;
 
-_cdebbuf *cdebbuf_alloc(void)
+static _cdebbuf *cdebbuf_alloc(void)
 {
 	_cdebbuf *cdb;
 
@@ -989,11 +989,6 @@ _cdebbuf *capi_cmsg2str(_cmsg * cmsg)
 	return &g_debbuf;
 }
 
-_cdebbuf *cdebbuf_alloc(void)
-{
-	return &g_debbuf;
-}
-
 void cdebbuf_free(_cdebbuf *cdb)
 {
 }
@@ -1009,7 +1004,6 @@ void __exit cdebug_exit(void)
 
 #endif
 
-EXPORT_SYMBOL(cdebbuf_alloc);
 EXPORT_SYMBOL(cdebbuf_free);
 EXPORT_SYMBOL(capi_cmsg2message);
 EXPORT_SYMBOL(capi_message2cmsg);
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 53a1890..be77ee6 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 #else
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 2baef34..c8e1c35 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -652,7 +652,7 @@ static int write_modem(struct cardstate 
 	 * transmit data
 	 */
 	count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size);
-	memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count);
+	skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count);
 	skb_pull(bcs->tx_skb, count);
 	atomic_set(&ucs->busy, 1);
 	gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count);
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 1e2d38e..428872b 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -404,7 +404,8 @@ #ifdef AVM_B1DMA_DEBUG
 		printk(KERN_DEBUG "tx: put 0x%x len=%d\n", 
 		       skb->data[2], txlen);
 #endif
-		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
+		skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf,
+						 skb->len - 2);
 	}
 	txlen = (txlen + 3) & ~3;
 
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index 6f5efa8..d58f927 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -457,7 +457,8 @@ #ifdef AVM_C4_DEBUG
 		printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
 				card->name, skb->data[2], txlen);
 #endif
-		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
+		skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf,
+						 skb->len - 2);
 	}
 	txlen = (txlen + 3) & ~3;
 
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
index 7a74ed3..98fcdfc 100644
--- a/drivers/isdn/hardware/eicon/capimain.c
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <linux/smp_lock.h>
 #include <linux/skbuff.h>
 
 #include "os_capi.h"
diff --git a/drivers/isdn/hardware/eicon/dbgioctl.h b/drivers/isdn/hardware/eicon/dbgioctl.h
deleted file mode 100644
index 0fb6f5e..0000000
--- a/drivers/isdn/hardware/eicon/dbgioctl.h
+++ /dev/null
@@ -1,198 +0,0 @@
-
-/*
- *
-  Copyright (c) Eicon Technology Corporation, 2000.
- *
-  This source file is supplied for the use with Eicon
-  Technology Corporation's range of DIVA Server Adapters.
- *
-  This program is free software; you can redistribute 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 OF ANY KIND WHATSOEVER INCLUDING ANY
-  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
- *
-  You 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.
- *
- */
-/*------------------------------------------------------------------*/
-/* file: dbgioctl.h                                                 */
-/*------------------------------------------------------------------*/
-
-#if !defined(__DBGIOCTL_H__)
-
-#define __DBGIOCTL_H__
-
-#ifdef NOT_YET_NEEDED
-/*
- * The requested operation is passed in arg0 of DbgIoctlArgs,
- * additional arguments (if any) in arg1, arg2 and arg3.
- */
-
-typedef struct
-{	ULONG	arg0 ;
-	ULONG	arg1 ;
-	ULONG	arg2 ;
-	ULONG	arg3 ;
-} DbgIoctlArgs ;
-
-#define	DBG_COPY_LOGS	0	/* copy debugs to user until buffer full	*/
-							/* arg1: size threshold						*/
-							/* arg2: timeout in milliseconds			*/
-
-#define DBG_FLUSH_LOGS	1	/* flush pending debugs to user buffer		*/
-							/* arg1: internal driver id					*/
-
-#define DBG_LIST_DRVS	2	/* return the list of registered drivers	*/
-
-#define	DBG_GET_MASK	3	/* get current debug mask of driver			*/
-							/* arg1: internal driver id					*/
-
-#define	DBG_SET_MASK	4	/* set/change debug mask of driver			*/
-							/* arg1: internal driver id					*/
-							/* arg2: new debug mask						*/
-
-#define	DBG_GET_BUFSIZE	5	/* get current buffer size of driver		*/
-							/* arg1: internal driver id					*/
-							/* arg2: new debug mask						*/
-
-#define	DBG_SET_BUFSIZE	6	/* set new buffer size of driver			*/
-							/* arg1: new buffer size					*/
-
-/*
- *	common internal debug message structure
- */
-
-typedef struct
-{	unsigned short id ;		/* virtual driver id                  */
-	unsigned short type ;	/* special message type               */
-	unsigned long  seq ;	/* sequence number of message         */
-	unsigned long  size ;	/* size of message in bytes           */
-	unsigned long  next ;	/* offset to next buffered message    */
-	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
-	unsigned char  data[4] ;/* message data                       */
-} OldDbgMessage ;
-
-typedef struct
-{	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
-	unsigned short size ;	/* size of message in bytes           */
-	unsigned short ffff ;	/* always 0xffff to indicate new msg  */
-	unsigned short id ;		/* virtual driver id                  */
-	unsigned short type ;	/* special message type               */
-	unsigned long  seq ;	/* sequence number of message         */
-	unsigned char  data[4] ;/* message data                       */
-} DbgMessage ;
-
-#endif
-
-#define DRV_ID_UNKNOWN		0x0C	/* for messages via prtComp() */
-
-#define	MSG_PROC_FLAG		0x80
-#define	MSG_PROC_NO_GET(x)	(((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1)
-#define	MSG_PROC_NO_SET(x)	(MSG_PROC_FLAG | (((x) & 7) << 4))
-
-#define MSG_TYPE_DRV_ID		0x0001
-#define MSG_TYPE_FLAGS		0x0002
-#define MSG_TYPE_STRING		0x0003
-#define MSG_TYPE_BINARY		0x0004
-
-#define MSG_HEAD_SIZE	((unsigned long)&(((DbgMessage *)0)->data[0]))
-#define MSG_ALIGN(len)	(((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3)
-#define MSG_SIZE(pMsg)	MSG_ALIGN((pMsg)->size)
-#define MSG_NEXT(pMsg)	((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) ))
-
-#define OLD_MSG_HEAD_SIZE	((unsigned long)&(((OldDbgMessage *)0)->data[0]))
-#define OLD_MSG_ALIGN(len)	(((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3)
-
-/*
- * manifest constants
- */
-
-#define MSG_FRAME_MAX_SIZE	2150		/* maximum size of B1 frame	 */
-#define MSG_TEXT_MAX_SIZE	1024		/* maximum size of msg text	 */
-#define MSG_MAX_SIZE		MSG_ALIGN(MSG_FRAME_MAX_SIZE)
-#define DBG_MIN_BUFFER_SIZE	0x00008000	/* minimal total buffer size  32 KB */
-#define DBG_DEF_BUFFER_SIZE	0x00020000	/* default total buffer size 128 KB */
-#define DBG_MAX_BUFFER_SIZE	0x00400000	/* maximal total buffer size   4 MB */
-
-#define DBGDRV_NAME		"Diehl_DIMAINT"
-#define UNIDBG_DRIVER	L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */
-#define DEBUG_DRIVER	"\\\\.\\" DBGDRV_NAME  /* traditional string for apps */
-#define DBGVXD_NAME		"DIMAINT"
-#define DEBUG_VXD		"\\\\.\\" DBGVXD_NAME  /* traditional string for apps */
-
-/*
- *	Special IDI interface debug construction
- */
-
-#define	DBG_IDI_SIG_REQ		(unsigned long)0xF479C402
-#define	DBG_IDI_SIG_IND		(unsigned long)0xF479C403
-#define	DBG_IDI_NL_REQ		(unsigned long)0xF479C404
-#define	DBG_IDI_NL_IND		(unsigned long)0xF479C405
-
-typedef struct
-{	unsigned long  magic_type ;
-	unsigned short data_len ;
-	unsigned char  layer_ID ;
-	unsigned char  entity_ID ;
-	unsigned char  request ;
-	unsigned char  ret_code ;
-	unsigned char  indication ;
-	unsigned char  complete ;
-	unsigned char  data[4] ;
-} DbgIdiAct, *DbgIdiAction ;
-
-/*
- * We want to use the same IOCTL codes in Win95 and WinNT.
- * The official constructor for IOCTL codes is the CTL_CODE macro
- * from <winoctl.h> (<devioctl.h> in WinNT DDK environment).
- * The problem here is that we don't know how to get <winioctl.h>
- * working in a Win95 DDK environment!
- */
-
-# ifdef CTL_CODE	/*{*/
-
-/* Assert that we have the same idea of the CTL_CODE macro.	*/
-
-#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
-    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
-)
-
-# else	/* !CTL_CODE */ /*}{*/
-
-/* Use the definitions stolen from <winioctl.h>.  */
-
-#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
-    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
-)
-
-#define METHOD_BUFFERED                 0
-#define METHOD_IN_DIRECT                1
-#define METHOD_OUT_DIRECT               2
-#define METHOD_NEITHER                  3
-
-#define FILE_ANY_ACCESS                 0
-#define FILE_READ_ACCESS          ( 0x0001 )    // file & pipe
-#define FILE_WRITE_ACCESS         ( 0x0002 )    // file & pipe
-
-# endif	/* CTL_CODE */ /*}*/
-
-/*
- * Now we can define WinNT/Win95 DeviceIoControl codes.
- *
- * These codes are defined in di_defs.h too, a possible mismatch will be
- * detected when the dbgtool is compiled.
- */
-
-#define IOCTL_DRIVER_LNK \
-	CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
-#define IOCTL_DRIVER_DBG \
-	CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
-
-#endif /* __DBGIOCTL_H__ */
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 4aba5c5..c909289 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <asm/uaccess.h>
 
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index 556b196..78f141e 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -14,7 +14,6 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 5e862e2..6d39f93 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -17,7 +17,6 @@ #include <asm/io.h>
 #include <linux/ioport.h>
 #include <linux/workqueue.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/poll.h>
diff --git a/drivers/isdn/hardware/eicon/main_if.h b/drivers/isdn/hardware/eicon/main_if.h
deleted file mode 100644
index 0ea339a..0000000
--- a/drivers/isdn/hardware/eicon/main_if.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
-  Copyright (c) Eicon Technology Corporation, 2000.
- *
-  This source file is supplied for the use with Eicon
-  Technology Corporation's range of DIVA Server Adapters.
- *
-  This program is free software; you can redistribute 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 OF ANY KIND WHATSOEVER INCLUDING ANY
-  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-  See the GNU General Public License for more details.
- *
-  You 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.
- *
- */
-/*------------------------------------------------------------------*/
-/* file: main_if.h                                                  */
-/*------------------------------------------------------------------*/
-# ifndef MAIN_IF___H
-# define MAIN_IF___H
-
-# include "debug_if.h"
-
-void  DI_lock (void) ;
-void  DI_unlock (void) ;
-
-#ifdef NOT_YET_NEEDED
-void  DI_nttime (LARGE_INTEGER *NTtime) ;
-void  DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ;
-void  DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields);
-unsigned long  DI_wintime(LARGE_INTEGER *NTtime) ;
-
-unsigned short  DiInsertProcessorNumber (int type) ;
-void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap);
-
-void  StartIoctlTimer (void (*Handler)(void), unsigned long msec) ;
-void  StopIoctlTimer (void) ;
-void  UnpendIoctl (DbgRequest *pDbgReq) ;
-#endif
-
-void add_to_q(int, char* , unsigned int);
-# endif /* MAIN_IF___H */
-
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
index ff09f07..15d4942 100644
--- a/drivers/isdn/hardware/eicon/platform.h
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -26,7 +26,6 @@ #include <linux/skbuff.h>
 #include <linux/vmalloc.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/list.h>
 #include <asm/types.h>
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index ae377e8..1642dca 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -254,14 +254,16 @@ write_modem(struct BCState *bcs) {
 	count = len;
 	if (count > MAX_MODEM_BUF - fp) {
 		count = MAX_MODEM_BUF - fp;
-		memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count);
+		skb_copy_from_linear_data(bcs->tx_skb,
+					  cs->hw.elsa.transbuf + fp, count);
 		skb_pull(bcs->tx_skb, count);
 		cs->hw.elsa.transcnt += count;
 		ret = count;
 		count = len - count;
 		fp = 0;
 	}
-	memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count);
+	skb_copy_from_linear_data(bcs->tx_skb,
+				  cs->hw.elsa.transbuf + fp, count);
 	skb_pull(bcs->tx_skb, count);
 	cs->hw.elsa.transcnt += count;
 	ret += count;
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 9f44d3e..99e70d4 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -37,7 +37,6 @@ #include <linux/module.h>
 #include <linux/kernel_stat.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include "hisax.h"
 #include "hisax_if.h"
 #include "hfc_usb.h"
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index cd3b5ad..3446f24 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1293,7 +1293,8 @@ l2_pull_iqueue(struct FsmInst *fi, int e
 		oskb = skb;
 		skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
 		memcpy(skb_put(skb, i), header, i);
-		memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
+		skb_copy_from_linear_data(oskb,
+					  skb_put(skb, oskb->len), oskb->len);
 		dev_kfree_skb(oskb);
 	}
 	st->l2.l2l1(st, PH_PULL | INDICATION, skb);
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 38f648f..02c6fba 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -19,7 +19,6 @@ #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
-#include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/ppp_defs.h>
 #include <asm/io.h>
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 84dccd5..6cdbad3 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -443,7 +443,7 @@ ergo_inithardware(hysdn_card * card)
 	card->waitpofready = ergo_waitpofready;
 	card->set_errlog_state = ergo_set_errlog_state;
 	INIT_WORK(&card->irq_queue, ergo_irq_bh);
-	card->hysdn_lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&card->hysdn_lock);
 
 	return (0);
 }				/* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index b2ae4ec..f854501 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -398,8 +398,9 @@ static u16 hycapi_send_message(struct ca
 			_len = CAPIMSG_LEN(skb->data);
 			if (_len > 22) {
 				_len2 = _len - 22;
-				memcpy(msghead, skb->data, 22);
-				memcpy(skb->data + _len2, msghead, 22);
+				skb_copy_from_linear_data(skb, msghead, 22);
+				skb_copy_to_linear_data_offset(skb, _len2,
+							       msghead, 22);
 				skb_pull(skb, _len2);
 				CAPIMSG_SETLEN(skb->data, 22);
 				retval = capilib_data_b3_req(&cinfo->ncci_head,
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 557d96c..cfa8fa5 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -214,8 +214,6 @@ hysdn_rx_netpkt(hysdn_card * card, unsig
 		lp->stats.rx_dropped++;
 		return;
 	}
-	skb->dev = &lp->netdev;
-
 	/* copy the data */
 	memcpy(skb_put(skb, len), buf, len);
 
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index f7e83a8..27b3991 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
-#include <linux/pci.h>
 #include <linux/smp_lock.h>
 
 #include "hysdn_defs.h"
@@ -298,8 +297,6 @@ hysdn_log_close(struct inode *ino, struc
 	struct procdata *pd;
 	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) {
@@ -309,7 +306,6 @@ hysdn_log_close(struct inode *ino, struc
 		/* read access -> log/debug read, mark one further file as closed */
 
 		pd = NULL;
-		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 */
@@ -332,7 +328,6 @@ hysdn_log_close(struct inode *ino, struc
 			inf->usage_cnt--;	/* decrement usage count for buffers */
 			inf = inf->next;
 		}
-		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 b7b5aa4..81db4a1 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -113,7 +113,8 @@ hysdn_sched_tx(hysdn_card *card, unsigne
 	    (skb = hysdn_tx_netget(card)) != NULL) 
 	{
 		if (skb->len <= maxlen) {
-			memcpy(buf, skb->data, skb->len);	/* copy the packet to the buffer */
+			/* copy the packet to the buffer */
+			skb_copy_from_linear_data(skb, buf, skb->len);
 			*len = skb->len;
 			*chan = CHAN_NDIS_DATA;
 			card->net_tx_busy = 1;	/* we are busy sending network data */
@@ -126,7 +127,7 @@ #ifdef CONFIG_HYSDN_CAPI
 	    ((skb = hycapi_tx_capiget(card)) != NULL) )
 	{
 		if (skb->len <= maxlen) {
-			memcpy(buf, skb->data, skb->len);
+			skb_copy_from_linear_data(skb, buf, skb->len);
 			*len = skb->len;
 			*chan = CHAN_CAPI;
 			hycapi_tx_capiack(card);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 9c926e4..c97330b 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -829,7 +829,7 @@ #endif
 				dflag = 0;
 			}
 			count_put = count_pull;
-			memcpy(cp, skb->data, count_put);
+			skb_copy_from_linear_data(skb, cp, count_put);
 			cp += count_put;
 			len -= count_put;
 #ifdef CONFIG_ISDN_AUDIO
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 838b373..aa83277 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -872,7 +872,8 @@ typedef struct {
 static void
 isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
 {
-	u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+	/* hopefully, this was set correctly */
+	const u_char *p = skb_network_header(skb);
 	unsigned short proto = ntohs(skb->protocol);
 	int data_ofs;
 	ip_ports *ipp;
@@ -880,7 +881,7 @@ isdn_net_log_skb(struct sk_buff * skb, i
 
 	addinfo[0] = '\0';
 	/* This check stolen from 2.1.72 dev_queue_xmit_nit() */
-	if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
+	if (p < skb->data || skb->network_header >= skb->tail) {
 		/* fall back to old isdn_net_log_packet method() */
 		char * buf = skb->data;
 
@@ -1121,7 +1122,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb,
 	if (!skb)
 		return;
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
-		int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
+		const int pullsize = skb_network_offset(skb) - ETH_HLEN;
 		if (pullsize > 0) {
 			printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
 			skb_pull(skb, pullsize);
@@ -1366,7 +1367,7 @@ isdn_net_type_trans(struct sk_buff *skb,
 	struct ethhdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
 	eth = eth_hdr(skb);
 
@@ -1786,7 +1787,7 @@ #endif
 	}
 	skb->dev = ndev;
 	skb->pkt_type = PACKET_HOST;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 #ifdef ISDN_DEBUG_NET_DUMP
 	isdn_dumppkt("R:", skb->data, skb->len, 40);
 #endif
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 1b2df80..387392c 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1100,7 +1100,8 @@ #ifdef CONFIG_ISDN_PPP_VJ
 					goto drop_packet;
 				}
 				skb_put(skb, skb_old->len + 128);
-				memcpy(skb->data, skb_old->data, skb_old->len);
+				skb_copy_from_linear_data(skb_old, skb->data,
+							  skb_old->len);
 				if (net_dev->local->ppp_slot < 0) {
 					printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
 						__FUNCTION__, net_dev->local->ppp_slot);
@@ -1167,7 +1168,7 @@ #else /* CONFIG_IPPP_FILTER */
 		mlp->huptimer = 0;
 #endif /* CONFIG_IPPP_FILTER */
 	skb->dev = dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	netif_rx(skb);
 	/* net_dev->local->stats.rx_packets++; done in isdn_net.c */
 	return;
@@ -1902,7 +1903,9 @@ void isdn_ppp_mp_reassembly( isdn_net_de
 		while( from != to ) {
 			unsigned int len = from->len - MP_HEADER_LEN;
 
-			memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
+			skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
+							 skb_put(skb,len),
+							 len);
 			frag = from->next;
 			isdn_ppp_mp_free_skb(mp, from);
 			from = frag; 
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index e3add27..bb92e3c 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -415,7 +415,8 @@ isdnloop_sendbuf(int channel, struct sk_
 		spin_lock_irqsave(&card->isdnloop_lock, flags);
 		nskb = dev_alloc_skb(skb->len);
 		if (nskb) {
-			memcpy(skb_put(nskb, len), skb->data, len);
+			skb_copy_from_linear_data(skb,
+						  skb_put(nskb, len), len);
 			skb_queue_tail(&card->bqueue[channel], nskb);
 			dev_kfree_skb(skb);
 		} else
@@ -1461,7 +1462,7 @@ #endif
 		skb_queue_head_init(&card->bqueue[i]);
 	}
 	skb_queue_head_init(&card->dqueue);
-	card->isdnloop_lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_init(&card->isdnloop_lock);
 	card->next = cards;
 	cards = card;
 	if (!register_isdn(&card->interface)) {
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index 47c59e9..7b55e15 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -429,8 +429,9 @@ #endif
 		if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
 			return -1;
        
-		memcpy(info->data.setup.CallingPN, skb->data + count + 1, 
-		       len - count);
+		skb_copy_from_linear_data_offset(skb, count + 1,
+						 info->data.setup.CallingPN,
+						 len - count);
 		info->data.setup.CallingPN[len - count] = 0;
 
 	}
@@ -457,8 +458,9 @@ #endif
 		if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
 			return -1;
         
-		memcpy(info->data.setup.CalledPN, skb->data + count + 1, 
-		       len - count); 
+		skb_copy_from_linear_data_offset(skb, count + 1,
+						 info->data.setup.CalledPN,
+						 len - count);
 		info->data.setup.CalledPN[len - count] = 0;
 
 	}
@@ -539,7 +541,7 @@ #endif
 
 #ifdef DEBUG
 	if (len > 1 && len < 31) {
-		memcpy(str, skb->data + 2, len - 1);
+		skb_copy_from_linear_data_offset(skb, 2, str, len - 1);
 		str[len] = 0;
 		printk(KERN_DEBUG "Connected Party Number: %s\n", str);
 	}
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 0d122bf..41634fd 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -51,16 +51,19 @@ #define INVALID_PAGE (~(hpa_t)0)
 #define UNMAPPED_GVA (~(gpa_t)0)
 
 #define KVM_MAX_VCPUS 1
+#define KVM_ALIAS_SLOTS 4
 #define KVM_MEMORY_SLOTS 4
 #define KVM_NUM_MMU_PAGES 256
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
+#define KVM_MAX_CPUID_ENTRIES 40
 
 #define FX_IMAGE_SIZE 512
 #define FX_IMAGE_ALIGN 16
 #define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
 
 #define DE_VECTOR 0
+#define NM_VECTOR 7
 #define DF_VECTOR 8
 #define TS_VECTOR 10
 #define NP_VECTOR 11
@@ -73,6 +76,8 @@ #define SELECTOR_RPL_MASK 0x03
 
 #define IOPL_SHIFT 12
 
+#define KVM_PIO_PAGE_OFFSET 1
+
 /*
  * Address types:
  *
@@ -106,6 +111,7 @@ struct kvm_pte_chain {
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
+ *   bits 17:18 - "access" - the user and writable bits of a huge page pde
  */
 union kvm_mmu_page_role {
 	unsigned word;
@@ -115,6 +121,7 @@ union kvm_mmu_page_role {
 		unsigned quadrant : 2;
 		unsigned pad_for_nice_hex_output : 6;
 		unsigned metaphysical : 1;
+		unsigned hugepage_access : 2;
 	};
 };
 
@@ -133,7 +140,6 @@ struct kvm_mmu_page {
 	unsigned long slot_bitmap; /* One bit set per slot which has memory
 				    * in this shadow page.
 				    */
-	int global;              /* Set if all ptes in this page are global */
 	int multimapped;         /* More than one parent_pte? */
 	int root_count;          /* Currently serving as active root */
 	union {
@@ -219,6 +225,34 @@ enum {
 	VCPU_SREG_LDTR,
 };
 
+struct kvm_pio_request {
+	unsigned long count;
+	int cur_count;
+	struct page *guest_pages[2];
+	unsigned guest_page_offset;
+	int in;
+	int size;
+	int string;
+	int down;
+	int rep;
+};
+
+struct kvm_stat {
+	u32 pf_fixed;
+	u32 pf_guest;
+	u32 tlb_flush;
+	u32 invlpg;
+
+	u32 exits;
+	u32 io_exits;
+	u32 mmio_exits;
+	u32 signal_exits;
+	u32 irq_window_exits;
+	u32 halt_exits;
+	u32 request_irq_exits;
+	u32 irq_exits;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -228,6 +262,8 @@ struct kvm_vcpu {
 	struct mutex mutex;
 	int   cpu;
 	int   launched;
+	u64 host_tsc;
+	struct kvm_run *run;
 	int interrupt_window_open;
 	unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
@@ -266,6 +302,7 @@ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE
 	char fx_buf[FX_BUF_SIZE];
 	char *host_fx_image;
 	char *guest_fx_image;
+	int fpu_active;
 
 	int mmio_needed;
 	int mmio_read_completed;
@@ -273,6 +310,14 @@ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE
 	int mmio_size;
 	unsigned char mmio_data[8];
 	gpa_t mmio_phys_addr;
+	gva_t mmio_fault_cr2;
+	struct kvm_pio_request pio;
+	void *pio_data;
+
+	int sigset_active;
+	sigset_t sigset;
+
+	struct kvm_stat stat;
 
 	struct {
 		int active;
@@ -284,6 +329,15 @@ #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE
 			u32 ar;
 		} tr, es, ds, fs, gs;
 	} rmode;
+
+	int cpuid_nent;
+	struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
+};
+
+struct kvm_mem_alias {
+	gfn_t base_gfn;
+	unsigned long npages;
+	gfn_t target_gfn;
 };
 
 struct kvm_memory_slot {
@@ -296,6 +350,8 @@ struct kvm_memory_slot {
 
 struct kvm {
 	spinlock_t lock; /* protects everything except vcpus */
+	int naliases;
+	struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
 	int nmemslots;
 	struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS];
 	/*
@@ -312,22 +368,6 @@ struct kvm {
 	struct file *filp;
 };
 
-struct kvm_stat {
-	u32 pf_fixed;
-	u32 pf_guest;
-	u32 tlb_flush;
-	u32 invlpg;
-
-	u32 exits;
-	u32 io_exits;
-	u32 mmio_exits;
-	u32 signal_exits;
-	u32 irq_window_exits;
-	u32 halt_exits;
-	u32 request_irq_exits;
-	u32 irq_exits;
-};
-
 struct descriptor_table {
 	u16 limit;
 	unsigned long base;
@@ -358,10 +398,8 @@ struct kvm_arch_ops {
 	void (*set_segment)(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
 	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
-	void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu);
+	void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu);
 	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
-	void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
-				      unsigned long cr0);
 	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
 	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
@@ -391,7 +429,6 @@ struct kvm_arch_ops {
 				unsigned char *hypercall_addr);
 };
 
-extern struct kvm_stat kvm_stat;
 extern struct kvm_arch_ops *kvm_arch_ops;
 
 #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
@@ -400,28 +437,29 @@ #define vcpu_printf(vcpu, fmt...) kvm_pr
 int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
 void kvm_exit_arch(void);
 
+int kvm_mmu_module_init(void);
+void kvm_mmu_module_exit(void);
+
 void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
 int kvm_mmu_create(struct kvm_vcpu *vcpu);
 int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
 void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
+void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
 #define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
 static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
 hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
+struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
 
 void kvm_emulator_want_group7_invlpg(void);
 
 extern hpa_t bad_page_address;
 
-static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn)
-{
-	return slot->phys_mem[gfn - slot->base_gfn];
-}
-
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
 
@@ -444,6 +482,10 @@ void realmode_set_cr(struct kvm_vcpu *vc
 
 struct x86_emulate_ctxt;
 
+int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+		  int size, unsigned long count, int string, int down,
+		  gva_t address, int rep, unsigned port);
+void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
 int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
 int emulate_clts(struct kvm_vcpu *vcpu);
 int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
@@ -493,12 +535,6 @@ static inline int kvm_mmu_page_fault(str
 	return vcpu->mmu.page_fault(vcpu, gva, error_code);
 }
 
-static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
-{
-	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
-	return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL;
-}
-
 static inline int is_long_mode(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index dc7a8c7..c8b8cfa 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -51,27 +51,27 @@ static DEFINE_SPINLOCK(kvm_lock);
 static LIST_HEAD(vm_list);
 
 struct kvm_arch_ops *kvm_arch_ops;
-struct kvm_stat kvm_stat;
-EXPORT_SYMBOL_GPL(kvm_stat);
+
+#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
 
 static struct kvm_stats_debugfs_item {
 	const char *name;
-	u32 *data;
+	int offset;
 	struct dentry *dentry;
 } debugfs_entries[] = {
-	{ "pf_fixed", &kvm_stat.pf_fixed },
-	{ "pf_guest", &kvm_stat.pf_guest },
-	{ "tlb_flush", &kvm_stat.tlb_flush },
-	{ "invlpg", &kvm_stat.invlpg },
-	{ "exits", &kvm_stat.exits },
-	{ "io_exits", &kvm_stat.io_exits },
-	{ "mmio_exits", &kvm_stat.mmio_exits },
-	{ "signal_exits", &kvm_stat.signal_exits },
-	{ "irq_window", &kvm_stat.irq_window_exits },
-	{ "halt_exits", &kvm_stat.halt_exits },
-	{ "request_irq", &kvm_stat.request_irq_exits },
-	{ "irq_exits", &kvm_stat.irq_exits },
-	{ NULL, NULL }
+	{ "pf_fixed", STAT_OFFSET(pf_fixed) },
+	{ "pf_guest", STAT_OFFSET(pf_guest) },
+	{ "tlb_flush", STAT_OFFSET(tlb_flush) },
+	{ "invlpg", STAT_OFFSET(invlpg) },
+	{ "exits", STAT_OFFSET(exits) },
+	{ "io_exits", STAT_OFFSET(io_exits) },
+	{ "mmio_exits", STAT_OFFSET(mmio_exits) },
+	{ "signal_exits", STAT_OFFSET(signal_exits) },
+	{ "irq_window", STAT_OFFSET(irq_window_exits) },
+	{ "halt_exits", STAT_OFFSET(halt_exits) },
+	{ "request_irq", STAT_OFFSET(request_irq_exits) },
+	{ "irq_exits", STAT_OFFSET(irq_exits) },
+	{ NULL }
 };
 
 static struct dentry *debugfs_dir;
@@ -346,6 +346,17 @@ static void kvm_free_physmem(struct kvm 
 		kvm_free_physmem_slot(&kvm->memslots[i], NULL);
 }
 
+static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
+{
+	int i;
+
+	for (i = 0; i < 2; ++i)
+		if (vcpu->pio.guest_pages[i]) {
+			__free_page(vcpu->pio.guest_pages[i]);
+			vcpu->pio.guest_pages[i] = NULL;
+		}
+}
+
 static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
 {
 	if (!vcpu->vmcs)
@@ -355,6 +366,11 @@ static void kvm_free_vcpu(struct kvm_vcp
 	kvm_mmu_destroy(vcpu);
 	vcpu_put(vcpu);
 	kvm_arch_ops->vcpu_free(vcpu);
+	free_page((unsigned long)vcpu->run);
+	vcpu->run = NULL;
+	free_page((unsigned long)vcpu->pio_data);
+	vcpu->pio_data = NULL;
+	free_pio_guest_pages(vcpu);
 }
 
 static void kvm_free_vcpus(struct kvm *kvm)
@@ -404,12 +420,12 @@ static int load_pdptrs(struct kvm_vcpu *
 	u64 pdpte;
 	u64 *pdpt;
 	int ret;
-	struct kvm_memory_slot *memslot;
+	struct page *page;
 
 	spin_lock(&vcpu->kvm->lock);
-	memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn);
-	/* FIXME: !memslot - emulate? 0xff? */
-	pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0);
+	page = gfn_to_page(vcpu->kvm, pdpt_gfn);
+	/* FIXME: !page - emulate? 0xff? */
+	pdpt = kmap_atomic(page, KM_USER0);
 
 	ret = 1;
 	for (i = 0; i < 4; ++i) {
@@ -494,7 +510,6 @@ EXPORT_SYMBOL_GPL(set_cr0);
 
 void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
 {
-	kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
 	set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
 }
 EXPORT_SYMBOL_GPL(lmsw);
@@ -830,7 +845,73 @@ out:
 	return r;
 }
 
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+/*
+ * Set a new alias region.  Aliases map a portion of physical memory into
+ * another portion.  This is useful for memory windows, for example the PC
+ * VGA region.
+ */
+static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
+					 struct kvm_memory_alias *alias)
+{
+	int r, n;
+	struct kvm_mem_alias *p;
+
+	r = -EINVAL;
+	/* General sanity checks */
+	if (alias->memory_size & (PAGE_SIZE - 1))
+		goto out;
+	if (alias->guest_phys_addr & (PAGE_SIZE - 1))
+		goto out;
+	if (alias->slot >= KVM_ALIAS_SLOTS)
+		goto out;
+	if (alias->guest_phys_addr + alias->memory_size
+	    < alias->guest_phys_addr)
+		goto out;
+	if (alias->target_phys_addr + alias->memory_size
+	    < alias->target_phys_addr)
+		goto out;
+
+	spin_lock(&kvm->lock);
+
+	p = &kvm->aliases[alias->slot];
+	p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
+	p->npages = alias->memory_size >> PAGE_SHIFT;
+	p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
+
+	for (n = KVM_ALIAS_SLOTS; n > 0; --n)
+		if (kvm->aliases[n - 1].npages)
+			break;
+	kvm->naliases = n;
+
+	spin_unlock(&kvm->lock);
+
+	vcpu_load(&kvm->vcpus[0]);
+	spin_lock(&kvm->lock);
+	kvm_mmu_zap_all(&kvm->vcpus[0]);
+	spin_unlock(&kvm->lock);
+	vcpu_put(&kvm->vcpus[0]);
+
+	return 0;
+
+out:
+	return r;
+}
+
+static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+	int i;
+	struct kvm_mem_alias *alias;
+
+	for (i = 0; i < kvm->naliases; ++i) {
+		alias = &kvm->aliases[i];
+		if (gfn >= alias->base_gfn
+		    && gfn < alias->base_gfn + alias->npages)
+			return alias->target_gfn + gfn - alias->base_gfn;
+	}
+	return gfn;
+}
+
+static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
 {
 	int i;
 
@@ -843,7 +924,24 @@ struct kvm_memory_slot *gfn_to_memslot(s
 	}
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(gfn_to_memslot);
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+{
+	gfn = unalias_gfn(kvm, gfn);
+	return __gfn_to_memslot(kvm, gfn);
+}
+
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+	struct kvm_memory_slot *slot;
+
+	gfn = unalias_gfn(kvm, gfn);
+	slot = __gfn_to_memslot(kvm, gfn);
+	if (!slot)
+		return NULL;
+	return slot->phys_mem[gfn - slot->base_gfn];
+}
+EXPORT_SYMBOL_GPL(gfn_to_page);
 
 void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
 {
@@ -871,7 +969,7 @@ void mark_page_dirty(struct kvm *kvm, gf
 }
 
 static int emulator_read_std(unsigned long addr,
-			     unsigned long *val,
+			     void *val,
 			     unsigned int bytes,
 			     struct x86_emulate_ctxt *ctxt)
 {
@@ -883,20 +981,20 @@ static int emulator_read_std(unsigned lo
 		unsigned offset = addr & (PAGE_SIZE-1);
 		unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
 		unsigned long pfn;
-		struct kvm_memory_slot *memslot;
-		void *page;
+		struct page *page;
+		void *page_virt;
 
 		if (gpa == UNMAPPED_GVA)
 			return X86EMUL_PROPAGATE_FAULT;
 		pfn = gpa >> PAGE_SHIFT;
-		memslot = gfn_to_memslot(vcpu->kvm, pfn);
-		if (!memslot)
+		page = gfn_to_page(vcpu->kvm, pfn);
+		if (!page)
 			return X86EMUL_UNHANDLEABLE;
-		page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0);
+		page_virt = kmap_atomic(page, KM_USER0);
 
-		memcpy(data, page + offset, tocopy);
+		memcpy(data, page_virt + offset, tocopy);
 
-		kunmap_atomic(page, KM_USER0);
+		kunmap_atomic(page_virt, KM_USER0);
 
 		bytes -= tocopy;
 		data += tocopy;
@@ -907,7 +1005,7 @@ static int emulator_read_std(unsigned lo
 }
 
 static int emulator_write_std(unsigned long addr,
-			      unsigned long val,
+			      const void *val,
 			      unsigned int bytes,
 			      struct x86_emulate_ctxt *ctxt)
 {
@@ -917,7 +1015,7 @@ static int emulator_write_std(unsigned l
 }
 
 static int emulator_read_emulated(unsigned long addr,
-				  unsigned long *val,
+				  void *val,
 				  unsigned int bytes,
 				  struct x86_emulate_ctxt *ctxt)
 {
@@ -945,37 +1043,37 @@ static int emulator_read_emulated(unsign
 }
 
 static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
-			       unsigned long val, int bytes)
+			       const void *val, int bytes)
 {
-	struct kvm_memory_slot *m;
 	struct page *page;
 	void *virt;
 
 	if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
 		return 0;
-	m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
-	if (!m)
+	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+	if (!page)
 		return 0;
-	page = gfn_to_page(m, gpa >> PAGE_SHIFT);
 	kvm_mmu_pre_write(vcpu, gpa, bytes);
 	mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
 	virt = kmap_atomic(page, KM_USER0);
-	memcpy(virt + offset_in_page(gpa), &val, bytes);
+	memcpy(virt + offset_in_page(gpa), val, bytes);
 	kunmap_atomic(virt, KM_USER0);
 	kvm_mmu_post_write(vcpu, gpa, bytes);
 	return 1;
 }
 
 static int emulator_write_emulated(unsigned long addr,
-				   unsigned long val,
+				   const void *val,
 				   unsigned int bytes,
 				   struct x86_emulate_ctxt *ctxt)
 {
 	struct kvm_vcpu *vcpu = ctxt->vcpu;
 	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
 
-	if (gpa == UNMAPPED_GVA)
+	if (gpa == UNMAPPED_GVA) {
+		kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
 		return X86EMUL_PROPAGATE_FAULT;
+	}
 
 	if (emulator_write_phys(vcpu, gpa, val, bytes))
 		return X86EMUL_CONTINUE;
@@ -984,14 +1082,14 @@ static int emulator_write_emulated(unsig
 	vcpu->mmio_phys_addr = gpa;
 	vcpu->mmio_size = bytes;
 	vcpu->mmio_is_write = 1;
-	memcpy(vcpu->mmio_data, &val, bytes);
+	memcpy(vcpu->mmio_data, val, bytes);
 
 	return X86EMUL_CONTINUE;
 }
 
 static int emulator_cmpxchg_emulated(unsigned long addr,
-				     unsigned long old,
-				     unsigned long new,
+				     const void *old,
+				     const void *new,
 				     unsigned int bytes,
 				     struct x86_emulate_ctxt *ctxt)
 {
@@ -1004,30 +1102,6 @@ static int emulator_cmpxchg_emulated(uns
 	return emulator_write_emulated(addr, new, bytes, ctxt);
 }
 
-#ifdef CONFIG_X86_32
-
-static int emulator_cmpxchg8b_emulated(unsigned long addr,
-				       unsigned long old_lo,
-				       unsigned long old_hi,
-				       unsigned long new_lo,
-				       unsigned long new_hi,
-				       struct x86_emulate_ctxt *ctxt)
-{
-	static int reported;
-	int r;
-
-	if (!reported) {
-		reported = 1;
-		printk(KERN_WARNING "kvm: emulating exchange8b as write\n");
-	}
-	r = emulator_write_emulated(addr, new_lo, 4, ctxt);
-	if (r != X86EMUL_CONTINUE)
-		return r;
-	return emulator_write_emulated(addr+4, new_hi, 4, ctxt);
-}
-
-#endif
-
 static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
 {
 	return kvm_arch_ops->get_segment_base(vcpu, seg);
@@ -1042,7 +1116,6 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 {
 	unsigned long cr0;
 
-	kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
 	cr0 = vcpu->cr0 & ~CR0_TS_MASK;
 	kvm_arch_ops->set_cr0(vcpu, cr0);
 	return X86EMUL_CONTINUE;
@@ -1102,9 +1175,6 @@ struct x86_emulate_ops emulate_ops = {
 	.read_emulated       = emulator_read_emulated,
 	.write_emulated      = emulator_write_emulated,
 	.cmpxchg_emulated    = emulator_cmpxchg_emulated,
-#ifdef CONFIG_X86_32
-	.cmpxchg8b_emulated  = emulator_cmpxchg8b_emulated,
-#endif
 };
 
 int emulate_instruction(struct kvm_vcpu *vcpu,
@@ -1116,6 +1186,7 @@ int emulate_instruction(struct kvm_vcpu 
 	int r;
 	int cs_db, cs_l;
 
+	vcpu->mmio_fault_cr2 = cr2;
 	kvm_arch_ops->cache_regs(vcpu);
 
 	kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
@@ -1166,8 +1237,10 @@ int emulate_instruction(struct kvm_vcpu 
 	kvm_arch_ops->decache_regs(vcpu);
 	kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
 
-	if (vcpu->mmio_is_write)
+	if (vcpu->mmio_is_write) {
+		vcpu->mmio_needed = 0;
 		return EMULATE_DO_MMIO;
+	}
 
 	return EMULATE_DONE;
 }
@@ -1177,7 +1250,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu,
 {
 	unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
 
-	kvm_arch_ops->decache_regs(vcpu);
+	kvm_arch_ops->cache_regs(vcpu);
 	ret = -KVM_EINVAL;
 #ifdef CONFIG_X86_64
 	if (is_long_mode(vcpu)) {
@@ -1201,10 +1274,19 @@ #endif
 	}
 	switch (nr) {
 	default:
-		;
+		run->hypercall.args[0] = a0;
+		run->hypercall.args[1] = a1;
+		run->hypercall.args[2] = a2;
+		run->hypercall.args[3] = a3;
+		run->hypercall.args[4] = a4;
+		run->hypercall.args[5] = a5;
+		run->hypercall.ret = ret;
+		run->hypercall.longmode = is_long_mode(vcpu);
+		kvm_arch_ops->decache_regs(vcpu);
+		return 0;
 	}
 	vcpu->regs[VCPU_REGS_RAX] = ret;
-	kvm_arch_ops->cache_regs(vcpu);
+	kvm_arch_ops->decache_regs(vcpu);
 	return 1;
 }
 EXPORT_SYMBOL_GPL(kvm_hypercall);
@@ -1237,7 +1319,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu
 
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
 {
-	kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+	kvm_arch_ops->decache_cr4_guest_bits(vcpu);
 	switch (cr) {
 	case 0:
 		return vcpu->cr0;
@@ -1442,6 +1524,10 @@ #endif
 		printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
 		       __FUNCTION__, data);
 		break;
+	case MSR_IA32_MCG_STATUS:
+		printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
+			__FUNCTION__, data);
+		break;
 	case MSR_IA32_UCODE_REV:
 	case MSR_IA32_UCODE_WRITE:
 	case 0x200 ... 0x2ff: /* MTRRs */
@@ -1478,6 +1564,8 @@ static int set_msr(struct kvm_vcpu *vcpu
 
 void kvm_resched(struct kvm_vcpu *vcpu)
 {
+	if (!need_resched())
+		return;
 	vcpu_put(vcpu);
 	cond_resched();
 	vcpu_load(vcpu);
@@ -1502,29 +1590,250 @@ void save_msrs(struct vmx_msr_entry *e, 
 }
 EXPORT_SYMBOL_GPL(save_msrs);
 
+void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
+{
+	int i;
+	u32 function;
+	struct kvm_cpuid_entry *e, *best;
+
+	kvm_arch_ops->cache_regs(vcpu);
+	function = vcpu->regs[VCPU_REGS_RAX];
+	vcpu->regs[VCPU_REGS_RAX] = 0;
+	vcpu->regs[VCPU_REGS_RBX] = 0;
+	vcpu->regs[VCPU_REGS_RCX] = 0;
+	vcpu->regs[VCPU_REGS_RDX] = 0;
+	best = NULL;
+	for (i = 0; i < vcpu->cpuid_nent; ++i) {
+		e = &vcpu->cpuid_entries[i];
+		if (e->function == function) {
+			best = e;
+			break;
+		}
+		/*
+		 * Both basic or both extended?
+		 */
+		if (((e->function ^ function) & 0x80000000) == 0)
+			if (!best || e->function > best->function)
+				best = e;
+	}
+	if (best) {
+		vcpu->regs[VCPU_REGS_RAX] = best->eax;
+		vcpu->regs[VCPU_REGS_RBX] = best->ebx;
+		vcpu->regs[VCPU_REGS_RCX] = best->ecx;
+		vcpu->regs[VCPU_REGS_RDX] = best->edx;
+	}
+	kvm_arch_ops->decache_regs(vcpu);
+	kvm_arch_ops->skip_emulated_instruction(vcpu);
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
+
+static int pio_copy_data(struct kvm_vcpu *vcpu)
+{
+	void *p = vcpu->pio_data;
+	void *q;
+	unsigned bytes;
+	int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
+
+	kvm_arch_ops->vcpu_put(vcpu);
+	q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
+		 PAGE_KERNEL);
+	if (!q) {
+		kvm_arch_ops->vcpu_load(vcpu);
+		free_pio_guest_pages(vcpu);
+		return -ENOMEM;
+	}
+	q += vcpu->pio.guest_page_offset;
+	bytes = vcpu->pio.size * vcpu->pio.cur_count;
+	if (vcpu->pio.in)
+		memcpy(q, p, bytes);
+	else
+		memcpy(p, q, bytes);
+	q -= vcpu->pio.guest_page_offset;
+	vunmap(q);
+	kvm_arch_ops->vcpu_load(vcpu);
+	free_pio_guest_pages(vcpu);
+	return 0;
+}
+
+static int complete_pio(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pio_request *io = &vcpu->pio;
+	long delta;
+	int r;
+
+	kvm_arch_ops->cache_regs(vcpu);
+
+	if (!io->string) {
+		if (io->in)
+			memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data,
+			       io->size);
+	} else {
+		if (io->in) {
+			r = pio_copy_data(vcpu);
+			if (r) {
+				kvm_arch_ops->cache_regs(vcpu);
+				return r;
+			}
+		}
+
+		delta = 1;
+		if (io->rep) {
+			delta *= io->cur_count;
+			/*
+			 * The size of the register should really depend on
+			 * current address size.
+			 */
+			vcpu->regs[VCPU_REGS_RCX] -= delta;
+		}
+		if (io->down)
+			delta = -delta;
+		delta *= io->size;
+		if (io->in)
+			vcpu->regs[VCPU_REGS_RDI] += delta;
+		else
+			vcpu->regs[VCPU_REGS_RSI] += delta;
+	}
+
+	kvm_arch_ops->decache_regs(vcpu);
+
+	io->count -= io->cur_count;
+	io->cur_count = 0;
+
+	if (!io->count)
+		kvm_arch_ops->skip_emulated_instruction(vcpu);
+	return 0;
+}
+
+int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+		  int size, unsigned long count, int string, int down,
+		  gva_t address, int rep, unsigned port)
+{
+	unsigned now, in_page;
+	int i;
+	int nr_pages = 1;
+	struct page *page;
+
+	vcpu->run->exit_reason = KVM_EXIT_IO;
+	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+	vcpu->run->io.size = size;
+	vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+	vcpu->run->io.count = count;
+	vcpu->run->io.port = port;
+	vcpu->pio.count = count;
+	vcpu->pio.cur_count = count;
+	vcpu->pio.size = size;
+	vcpu->pio.in = in;
+	vcpu->pio.string = string;
+	vcpu->pio.down = down;
+	vcpu->pio.guest_page_offset = offset_in_page(address);
+	vcpu->pio.rep = rep;
+
+	if (!string) {
+		kvm_arch_ops->cache_regs(vcpu);
+		memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
+		kvm_arch_ops->decache_regs(vcpu);
+		return 0;
+	}
+
+	if (!count) {
+		kvm_arch_ops->skip_emulated_instruction(vcpu);
+		return 1;
+	}
+
+	now = min(count, PAGE_SIZE / size);
+
+	if (!down)
+		in_page = PAGE_SIZE - offset_in_page(address);
+	else
+		in_page = offset_in_page(address) + size;
+	now = min(count, (unsigned long)in_page / size);
+	if (!now) {
+		/*
+		 * String I/O straddles page boundary.  Pin two guest pages
+		 * so that we satisfy atomicity constraints.  Do just one
+		 * transaction to avoid complexity.
+		 */
+		nr_pages = 2;
+		now = 1;
+	}
+	if (down) {
+		/*
+		 * String I/O in reverse.  Yuck.  Kill the guest, fix later.
+		 */
+		printk(KERN_ERR "kvm: guest string pio down\n");
+		inject_gp(vcpu);
+		return 1;
+	}
+	vcpu->run->io.count = now;
+	vcpu->pio.cur_count = now;
+
+	for (i = 0; i < nr_pages; ++i) {
+		spin_lock(&vcpu->kvm->lock);
+		page = gva_to_page(vcpu, address + i * PAGE_SIZE);
+		if (page)
+			get_page(page);
+		vcpu->pio.guest_pages[i] = page;
+		spin_unlock(&vcpu->kvm->lock);
+		if (!page) {
+			inject_gp(vcpu);
+			free_pio_guest_pages(vcpu);
+			return 1;
+		}
+	}
+
+	if (!vcpu->pio.in)
+		return pio_copy_data(vcpu);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_setup_pio);
+
 static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	int r;
+	sigset_t sigsaved;
 
 	vcpu_load(vcpu);
 
+	if (vcpu->sigset_active)
+		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
 	/* re-sync apic's tpr */
 	vcpu->cr8 = kvm_run->cr8;
 
-	if (kvm_run->emulated) {
-		kvm_arch_ops->skip_emulated_instruction(vcpu);
-		kvm_run->emulated = 0;
+	if (vcpu->pio.cur_count) {
+		r = complete_pio(vcpu);
+		if (r)
+			goto out;
 	}
 
-	if (kvm_run->mmio_completed) {
+	if (vcpu->mmio_needed) {
 		memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
 		vcpu->mmio_read_completed = 1;
+		vcpu->mmio_needed = 0;
+		r = emulate_instruction(vcpu, kvm_run,
+					vcpu->mmio_fault_cr2, 0);
+		if (r == EMULATE_DO_MMIO) {
+			/*
+			 * Read-modify-write.  Back to userspace.
+			 */
+			kvm_run->exit_reason = KVM_EXIT_MMIO;
+			r = 0;
+			goto out;
+		}
 	}
 
-	vcpu->mmio_needed = 0;
+	if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
+		kvm_arch_ops->cache_regs(vcpu);
+		vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
+		kvm_arch_ops->decache_regs(vcpu);
+	}
 
 	r = kvm_arch_ops->run(vcpu, kvm_run);
 
+out:
+	if (vcpu->sigset_active)
+		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
 	vcpu_put(vcpu);
 	return r;
 }
@@ -1633,7 +1942,7 @@ static int kvm_vcpu_ioctl_get_sregs(stru
 	sregs->gdt.limit = dt.limit;
 	sregs->gdt.base = dt.base;
 
-	kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+	kvm_arch_ops->decache_cr4_guest_bits(vcpu);
 	sregs->cr0 = vcpu->cr0;
 	sregs->cr2 = vcpu->cr2;
 	sregs->cr3 = vcpu->cr3;
@@ -1665,16 +1974,6 @@ static int kvm_vcpu_ioctl_set_sregs(stru
 
 	vcpu_load(vcpu);
 
-	set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
-	set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
-	set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
-	set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
-	set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
-	set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
-
-	set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
-	set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
-
 	dt.limit = sregs->idt.limit;
 	dt.base = sregs->idt.base;
 	kvm_arch_ops->set_idt(vcpu, &dt);
@@ -1694,10 +1993,10 @@ #ifdef CONFIG_X86_64
 #endif
 	vcpu->apic_base = sregs->apic_base;
 
-	kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+	kvm_arch_ops->decache_cr4_guest_bits(vcpu);
 
 	mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
-	kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
+	kvm_arch_ops->set_cr0(vcpu, sregs->cr0);
 
 	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
 	kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
@@ -1714,6 +2013,16 @@ #endif
 		if (vcpu->irq_pending[i])
 			__set_bit(i, &vcpu->irq_summary);
 
+	set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+	set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+	set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+	set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+	set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+	set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+	set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+	set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
 	vcpu_put(vcpu);
 
 	return 0;
@@ -1887,6 +2196,36 @@ static int kvm_vcpu_ioctl_debug_guest(st
 	return r;
 }
 
+static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
+				    unsigned long address,
+				    int *type)
+{
+	struct kvm_vcpu *vcpu = vma->vm_file->private_data;
+	unsigned long pgoff;
+	struct page *page;
+
+	*type = VM_FAULT_MINOR;
+	pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+	if (pgoff == 0)
+		page = virt_to_page(vcpu->run);
+	else if (pgoff == KVM_PIO_PAGE_OFFSET)
+		page = virt_to_page(vcpu->pio_data);
+	else
+		return NOPAGE_SIGBUS;
+	get_page(page);
+	return page;
+}
+
+static struct vm_operations_struct kvm_vcpu_vm_ops = {
+	.nopage = kvm_vcpu_nopage,
+};
+
+static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	vma->vm_ops = &kvm_vcpu_vm_ops;
+	return 0;
+}
+
 static int kvm_vcpu_release(struct inode *inode, struct file *filp)
 {
 	struct kvm_vcpu *vcpu = filp->private_data;
@@ -1899,6 +2238,7 @@ static struct file_operations kvm_vcpu_f
 	.release        = kvm_vcpu_release,
 	.unlocked_ioctl = kvm_vcpu_ioctl,
 	.compat_ioctl   = kvm_vcpu_ioctl,
+	.mmap           = kvm_vcpu_mmap,
 };
 
 /*
@@ -1947,6 +2287,7 @@ static int kvm_vm_ioctl_create_vcpu(stru
 {
 	int r;
 	struct kvm_vcpu *vcpu;
+	struct page *page;
 
 	r = -EINVAL;
 	if (!valid_vcpu(n))
@@ -1961,9 +2302,22 @@ static int kvm_vm_ioctl_create_vcpu(stru
 		return -EEXIST;
 	}
 
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	r = -ENOMEM;
+	if (!page)
+		goto out_unlock;
+	vcpu->run = page_address(page);
+
+	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+	r = -ENOMEM;
+	if (!page)
+		goto out_free_run;
+	vcpu->pio_data = page_address(page);
+
 	vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
 					   FX_IMAGE_ALIGN);
 	vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+	vcpu->cr0 = 0x10;
 
 	r = kvm_arch_ops->vcpu_create(vcpu);
 	if (r < 0)
@@ -1990,11 +2344,107 @@ static int kvm_vm_ioctl_create_vcpu(stru
 
 out_free_vcpus:
 	kvm_free_vcpu(vcpu);
+out_free_run:
+	free_page((unsigned long)vcpu->run);
+	vcpu->run = NULL;
+out_unlock:
 	mutex_unlock(&vcpu->mutex);
 out:
 	return r;
 }
 
+static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
+				    struct kvm_cpuid *cpuid,
+				    struct kvm_cpuid_entry __user *entries)
+{
+	int r;
+
+	r = -E2BIG;
+	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
+		goto out;
+	r = -EFAULT;
+	if (copy_from_user(&vcpu->cpuid_entries, entries,
+			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
+		goto out;
+	vcpu->cpuid_nent = cpuid->nent;
+	return 0;
+
+out:
+	return r;
+}
+
+static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
+{
+	if (sigset) {
+		sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+		vcpu->sigset_active = 1;
+		vcpu->sigset = *sigset;
+	} else
+		vcpu->sigset_active = 0;
+	return 0;
+}
+
+/*
+ * fxsave fpu state.  Taken from x86_64/processor.h.  To be killed when
+ * we have asm/x86/processor.h
+ */
+struct fxsave {
+	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 */
+#ifdef CONFIG_X86_64
+	u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 256 bytes */
+#else
+	u32	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+#endif
+};
+
+static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+	struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+
+	vcpu_load(vcpu);
+
+	memcpy(fpu->fpr, fxsave->st_space, 128);
+	fpu->fcw = fxsave->cwd;
+	fpu->fsw = fxsave->swd;
+	fpu->ftwx = fxsave->twd;
+	fpu->last_opcode = fxsave->fop;
+	fpu->last_ip = fxsave->rip;
+	fpu->last_dp = fxsave->rdp;
+	memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
+
+	vcpu_put(vcpu);
+
+	return 0;
+}
+
+static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+	struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+
+	vcpu_load(vcpu);
+
+	memcpy(fxsave->st_space, fpu->fpr, 128);
+	fxsave->cwd = fpu->fcw;
+	fxsave->swd = fpu->fsw;
+	fxsave->twd = fpu->ftwx;
+	fxsave->fop = fpu->last_opcode;
+	fxsave->rip = fpu->last_ip;
+	fxsave->rdp = fpu->last_dp;
+	memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
+
+	vcpu_put(vcpu);
+
+	return 0;
+}
+
 static long kvm_vcpu_ioctl(struct file *filp,
 			   unsigned int ioctl, unsigned long arg)
 {
@@ -2003,21 +2453,12 @@ static long kvm_vcpu_ioctl(struct file *
 	int r = -EINVAL;
 
 	switch (ioctl) {
-	case KVM_RUN: {
-		struct kvm_run kvm_run;
-
-		r = -EFAULT;
-		if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
+	case KVM_RUN:
+		r = -EINVAL;
+		if (arg)
 			goto out;
-		r = kvm_vcpu_ioctl_run(vcpu, &kvm_run);
-		if (r < 0 &&  r != -EINTR)
-			goto out;
-		if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
-			r = -EFAULT;
-			goto out;
-		}
+		r = kvm_vcpu_ioctl_run(vcpu, vcpu->run);
 		break;
-	}
 	case KVM_GET_REGS: {
 		struct kvm_regs kvm_regs;
 
@@ -2113,6 +2554,66 @@ static long kvm_vcpu_ioctl(struct file *
 	case KVM_SET_MSRS:
 		r = msr_io(vcpu, argp, do_set_msr, 0);
 		break;
+	case KVM_SET_CPUID: {
+		struct kvm_cpuid __user *cpuid_arg = argp;
+		struct kvm_cpuid cpuid;
+
+		r = -EFAULT;
+		if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
+			goto out;
+		r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries);
+		if (r)
+			goto out;
+		break;
+	}
+	case KVM_SET_SIGNAL_MASK: {
+		struct kvm_signal_mask __user *sigmask_arg = argp;
+		struct kvm_signal_mask kvm_sigmask;
+		sigset_t sigset, *p;
+
+		p = NULL;
+		if (argp) {
+			r = -EFAULT;
+			if (copy_from_user(&kvm_sigmask, argp,
+					   sizeof kvm_sigmask))
+				goto out;
+			r = -EINVAL;
+			if (kvm_sigmask.len != sizeof sigset)
+				goto out;
+			r = -EFAULT;
+			if (copy_from_user(&sigset, sigmask_arg->sigset,
+					   sizeof sigset))
+				goto out;
+			p = &sigset;
+		}
+		r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
+		break;
+	}
+	case KVM_GET_FPU: {
+		struct kvm_fpu fpu;
+
+		memset(&fpu, 0, sizeof fpu);
+		r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu);
+		if (r)
+			goto out;
+		r = -EFAULT;
+		if (copy_to_user(argp, &fpu, sizeof fpu))
+			goto out;
+		r = 0;
+		break;
+	}
+	case KVM_SET_FPU: {
+		struct kvm_fpu fpu;
+
+		r = -EFAULT;
+		if (copy_from_user(&fpu, argp, sizeof fpu))
+			goto out;
+		r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu);
+		if (r)
+			goto out;
+		r = 0;
+		break;
+	}
 	default:
 		;
 	}
@@ -2155,6 +2656,17 @@ static long kvm_vm_ioctl(struct file *fi
 			goto out;
 		break;
 	}
+	case KVM_SET_MEMORY_ALIAS: {
+		struct kvm_memory_alias alias;
+
+		r = -EFAULT;
+		if (copy_from_user(&alias, argp, sizeof alias))
+			goto out;
+		r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
+		if (r)
+			goto out;
+		break;
+	}
 	default:
 		;
 	}
@@ -2168,15 +2680,11 @@ static struct page *kvm_vm_nopage(struct
 {
 	struct kvm *kvm = vma->vm_file->private_data;
 	unsigned long pgoff;
-	struct kvm_memory_slot *slot;
 	struct page *page;
 
 	*type = VM_FAULT_MINOR;
 	pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-	slot = gfn_to_memslot(kvm, pgoff);
-	if (!slot)
-		return NOPAGE_SIGBUS;
-	page = gfn_to_page(slot, pgoff);
+	page = gfn_to_page(kvm, pgoff);
 	if (!page)
 		return NOPAGE_SIGBUS;
 	get_page(page);
@@ -2248,13 +2756,19 @@ static long kvm_dev_ioctl(struct file *f
 			  unsigned int ioctl, unsigned long arg)
 {
 	void __user *argp = (void __user *)arg;
-	int r = -EINVAL;
+	long r = -EINVAL;
 
 	switch (ioctl) {
 	case KVM_GET_API_VERSION:
+		r = -EINVAL;
+		if (arg)
+			goto out;
 		r = KVM_API_VERSION;
 		break;
 	case KVM_CREATE_VM:
+		r = -EINVAL;
+		if (arg)
+			goto out;
 		r = kvm_dev_ioctl_create_vm();
 		break;
 	case KVM_GET_MSR_INDEX_LIST: {
@@ -2284,6 +2798,18 @@ static long kvm_dev_ioctl(struct file *f
 		r = 0;
 		break;
 	}
+	case KVM_CHECK_EXTENSION:
+		/*
+		 * No extensions defined at present.
+		 */
+		r = 0;
+		break;
+	case KVM_GET_VCPU_MMAP_SIZE:
+		r = -EINVAL;
+		if (arg)
+			goto out;
+		r = 2 * PAGE_SIZE;
+		break;
 	default:
 		;
 	}
@@ -2299,7 +2825,7 @@ static struct file_operations kvm_charde
 };
 
 static struct miscdevice kvm_dev = {
-	MISC_DYNAMIC_MINOR,
+	KVM_MINOR,
 	"kvm",
 	&kvm_chardev_ops,
 };
@@ -2385,14 +2911,39 @@ static struct notifier_block kvm_cpu_not
 	.priority = 20, /* must be > scheduler priority */
 };
 
+static u64 stat_get(void *_offset)
+{
+	unsigned offset = (long)_offset;
+	u64 total = 0;
+	struct kvm *kvm;
+	struct kvm_vcpu *vcpu;
+	int i;
+
+	spin_lock(&kvm_lock);
+	list_for_each_entry(kvm, &vm_list, vm_list)
+		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+			vcpu = &kvm->vcpus[i];
+			total += *(u32 *)((void *)vcpu + offset);
+		}
+	spin_unlock(&kvm_lock);
+	return total;
+}
+
+static void stat_set(void *offset, u64 val)
+{
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
+
 static __init void kvm_init_debug(void)
 {
 	struct kvm_stats_debugfs_item *p;
 
 	debugfs_dir = debugfs_create_dir("kvm", NULL);
 	for (p = debugfs_entries; p->name; ++p)
-		p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
-					       p->data);
+		p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir,
+						(void *)(long)p->offset,
+						&stat_fops);
 }
 
 static void kvm_exit_debug(void)
@@ -2522,6 +3073,10 @@ static __init int kvm_init(void)
 	static struct page *bad_page;
 	int r;
 
+	r = kvm_mmu_module_init();
+	if (r)
+		goto out4;
+
 	r = register_filesystem(&kvm_fs_type);
 	if (r)
 		goto out3;
@@ -2550,6 +3105,8 @@ out:
 out2:
 	unregister_filesystem(&kvm_fs_type);
 out3:
+	kvm_mmu_module_exit();
+out4:
 	return r;
 }
 
@@ -2559,6 +3116,7 @@ static __exit void kvm_exit(void)
 	__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
 	mntput(kvmfs_mnt);
 	unregister_filesystem(&kvm_fs_type);
+	kvm_mmu_module_exit();
 }
 
 module_init(kvm_init)
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
index 624f1ca..a869983 100644
--- a/drivers/kvm/kvm_svm.h
+++ b/drivers/kvm/kvm_svm.h
@@ -9,17 +9,15 @@ #include <asm/msr.h>
 #include "svm.h"
 #include "kvm.h"
 
-static const u32 host_save_msrs[] = {
+static const u32 host_save_user_msrs[] = {
 #ifdef CONFIG_X86_64
 	MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
-	MSR_FS_BASE, MSR_GS_BASE,
+	MSR_FS_BASE,
 #endif
 	MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-	MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP,
-	MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
 };
 
-#define NR_HOST_SAVE_MSRS ARRAY_SIZE(host_save_msrs)
+#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
 #define NUM_DB_REGS 4
 
 struct vcpu_svm {
@@ -28,13 +26,12 @@ struct vcpu_svm {
 	struct svm_cpu_data *svm_data;
 	uint64_t asid_generation;
 
-	unsigned long cr0;
-	unsigned long cr4;
 	unsigned long db_regs[NUM_DB_REGS];
 
 	u64 next_rip;
 
-	u64 host_msrs[NR_HOST_SAVE_MSRS];
+	u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
+	u64 host_gs_base;
 	unsigned long host_cr2;
 	unsigned long host_db_regs[NUM_DB_REGS];
 	unsigned long host_dr6;
diff --git a/drivers/kvm/kvm_vmx.h b/drivers/kvm/kvm_vmx.h
deleted file mode 100644
index d139f73..0000000
--- a/drivers/kvm/kvm_vmx.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __KVM_VMX_H
-#define __KVM_VMX_H
-
-#ifdef CONFIG_X86_64
-/*
- * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
- * mechanism (cpu bug AA24)
- */
-#define NR_BAD_MSRS 2
-#else
-#define NR_BAD_MSRS 0
-#endif
-
-#endif
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index cab26f3..e8e2281 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -52,11 +52,15 @@ #if defined(MMU_DEBUG) || defined(AUDIT)
 static int dbg = 1;
 #endif
 
+#ifndef MMU_DEBUG
+#define ASSERT(x) do { } while (0)
+#else
 #define ASSERT(x)							\
 	if (!(x)) {							\
 		printk(KERN_WARNING "assertion failed %s:%d: %s\n",	\
 		       __FILE__, __LINE__, #x);				\
 	}
+#endif
 
 #define PT64_PT_BITS 9
 #define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS)
@@ -159,6 +163,9 @@ struct kvm_rmap_desc {
 	struct kvm_rmap_desc *more;
 };
 
+static struct kmem_cache *pte_chain_cache;
+static struct kmem_cache *rmap_desc_cache;
+
 static int is_write_protection(struct kvm_vcpu *vcpu)
 {
 	return vcpu->cr0 & CR0_WP_MASK;
@@ -196,14 +203,15 @@ static int is_rmap_pte(u64 pte)
 }
 
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
-				  size_t objsize, int min)
+				  struct kmem_cache *base_cache, int min,
+				  gfp_t gfp_flags)
 {
 	void *obj;
 
 	if (cache->nobjs >= min)
 		return 0;
 	while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
-		obj = kzalloc(objsize, GFP_NOWAIT);
+		obj = kmem_cache_zalloc(base_cache, gfp_flags);
 		if (!obj)
 			return -ENOMEM;
 		cache->objects[cache->nobjs++] = obj;
@@ -217,20 +225,35 @@ static void mmu_free_memory_cache(struct
 		kfree(mc->objects[--mc->nobjs]);
 }
 
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
+static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
 {
 	int r;
 
 	r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
-				   sizeof(struct kvm_pte_chain), 4);
+				   pte_chain_cache, 4, gfp_flags);
 	if (r)
 		goto out;
 	r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
-				   sizeof(struct kvm_rmap_desc), 1);
+				   rmap_desc_cache, 1, gfp_flags);
 out:
 	return r;
 }
 
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
+{
+	int r;
+
+	r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
+	if (r < 0) {
+		spin_unlock(&vcpu->kvm->lock);
+		kvm_arch_ops->vcpu_put(vcpu);
+		r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
+		kvm_arch_ops->vcpu_load(vcpu);
+		spin_lock(&vcpu->kvm->lock);
+	}
+	return r;
+}
+
 static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
 	mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
@@ -390,13 +413,11 @@ static void rmap_write_protect(struct kv
 {
 	struct kvm *kvm = vcpu->kvm;
 	struct page *page;
-	struct kvm_memory_slot *slot;
 	struct kvm_rmap_desc *desc;
 	u64 *spte;
 
-	slot = gfn_to_memslot(kvm, gfn);
-	BUG_ON(!slot);
-	page = gfn_to_page(slot, gfn);
+	page = gfn_to_page(kvm, gfn);
+	BUG_ON(!page);
 
 	while (page_private(page)) {
 		if (!(page_private(page) & 1))
@@ -417,6 +438,7 @@ static void rmap_write_protect(struct kv
 	}
 }
 
+#ifdef MMU_DEBUG
 static int is_empty_shadow_page(hpa_t page_hpa)
 {
 	u64 *pos;
@@ -431,15 +453,15 @@ static int is_empty_shadow_page(hpa_t pa
 		}
 	return 1;
 }
+#endif
 
 static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
 {
 	struct kvm_mmu_page *page_head = page_header(page_hpa);
 
 	ASSERT(is_empty_shadow_page(page_hpa));
-	list_del(&page_head->link);
 	page_head->page_hpa = page_hpa;
-	list_add(&page_head->link, &vcpu->free_pages);
+	list_move(&page_head->link, &vcpu->free_pages);
 	++vcpu->kvm->n_free_mmu_pages;
 }
 
@@ -457,11 +479,9 @@ static struct kvm_mmu_page *kvm_mmu_allo
 		return NULL;
 
 	page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
-	list_del(&page->link);
-	list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+	list_move(&page->link, &vcpu->kvm->active_mmu_pages);
 	ASSERT(is_empty_shadow_page(page->page_hpa));
 	page->slot_bitmap = 0;
-	page->global = 1;
 	page->multimapped = 0;
 	page->parent_pte = parent_pte;
 	--vcpu->kvm->n_free_mmu_pages;
@@ -569,6 +589,7 @@ static struct kvm_mmu_page *kvm_mmu_get_
 					     gva_t gaddr,
 					     unsigned level,
 					     int metaphysical,
+					     unsigned hugepage_access,
 					     u64 *parent_pte)
 {
 	union kvm_mmu_page_role role;
@@ -582,6 +603,7 @@ static struct kvm_mmu_page *kvm_mmu_get_
 	role.glevels = vcpu->mmu.root_level;
 	role.level = level;
 	role.metaphysical = metaphysical;
+	role.hugepage_access = hugepage_access;
 	if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
 		quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
 		quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
@@ -669,10 +691,8 @@ static void kvm_mmu_zap_page(struct kvm_
 	if (!page->root_count) {
 		hlist_del(&page->hash_link);
 		kvm_mmu_free_page(vcpu, page->page_hpa);
-	} else {
-		list_del(&page->link);
-		list_add(&page->link, &vcpu->kvm->active_mmu_pages);
-	}
+	} else
+		list_move(&page->link, &vcpu->kvm->active_mmu_pages);
 }
 
 static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -714,14 +734,12 @@ hpa_t safe_gpa_to_hpa(struct kvm_vcpu *v
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
 {
-	struct kvm_memory_slot *slot;
 	struct page *page;
 
 	ASSERT((gpa & HPA_ERR_MASK) == 0);
-	slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
-	if (!slot)
+	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+	if (!page)
 		return gpa | HPA_ERR_MASK;
-	page = gfn_to_page(slot, gpa >> PAGE_SHIFT);
 	return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT)
 		| (gpa & (PAGE_SIZE-1));
 }
@@ -735,6 +753,15 @@ hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, 
 	return gpa_to_hpa(vcpu, gpa);
 }
 
+struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva)
+{
+	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
+
+	if (gpa == UNMAPPED_GVA)
+		return NULL;
+	return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT);
+}
+
 static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
 {
 }
@@ -772,7 +799,7 @@ static int nonpaging_map(struct kvm_vcpu
 				>> PAGE_SHIFT;
 			new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
 						     v, level - 1,
-						     1, &table[index]);
+						     1, 0, &table[index]);
 			if (!new_table) {
 				pgprintk("nonpaging_map: ENOMEM\n");
 				return -ENOMEM;
@@ -804,10 +831,12 @@ #endif
 	for (i = 0; i < 4; ++i) {
 		hpa_t root = vcpu->mmu.pae_root[i];
 
-		ASSERT(VALID_PAGE(root));
-		root &= PT64_BASE_ADDR_MASK;
-		page = page_header(root);
-		--page->root_count;
+		if (root) {
+			ASSERT(VALID_PAGE(root));
+			root &= PT64_BASE_ADDR_MASK;
+			page = page_header(root);
+			--page->root_count;
+		}
 		vcpu->mmu.pae_root[i] = INVALID_PAGE;
 	}
 	vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -827,7 +856,7 @@ #ifdef CONFIG_X86_64
 
 		ASSERT(!VALID_PAGE(root));
 		page = kvm_mmu_get_page(vcpu, root_gfn, 0,
-					PT64_ROOT_LEVEL, 0, NULL);
+					PT64_ROOT_LEVEL, 0, 0, NULL);
 		root = page->page_hpa;
 		++page->root_count;
 		vcpu->mmu.root_hpa = root;
@@ -838,13 +867,17 @@ #endif
 		hpa_t root = vcpu->mmu.pae_root[i];
 
 		ASSERT(!VALID_PAGE(root));
-		if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL)
+		if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) {
+			if (!is_present_pte(vcpu->pdptrs[i])) {
+				vcpu->mmu.pae_root[i] = 0;
+				continue;
+			}
 			root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT;
-		else if (vcpu->mmu.root_level == 0)
+		} else if (vcpu->mmu.root_level == 0)
 			root_gfn = 0;
 		page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
 					PT32_ROOT_LEVEL, !is_paging(vcpu),
-					NULL);
+					0, NULL);
 		root = page->page_hpa;
 		++page->root_count;
 		vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
@@ -903,7 +936,7 @@ static int nonpaging_init_context(struct
 
 static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
 {
-	++kvm_stat.tlb_flush;
+	++vcpu->stat.tlb_flush;
 	kvm_arch_ops->tlb_flush(vcpu);
 }
 
@@ -918,11 +951,6 @@ static void paging_new_cr3(struct kvm_vc
 	kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
 }
 
-static void mark_pagetable_nonglobal(void *shadow_pte)
-{
-	page_header(__pa(shadow_pte))->global = 0;
-}
-
 static inline void set_pte_common(struct kvm_vcpu *vcpu,
 			     u64 *shadow_pte,
 			     gpa_t gaddr,
@@ -940,9 +968,6 @@ static inline void set_pte_common(struct
 
 	*shadow_pte |= access_bits;
 
-	if (!(*shadow_pte & PT_GLOBAL_MASK))
-		mark_pagetable_nonglobal(shadow_pte);
-
 	if (is_error_hpa(paddr)) {
 		*shadow_pte |= gaddr;
 		*shadow_pte |= PT_SHADOW_IO_MARK;
@@ -1316,6 +1341,51 @@ void kvm_mmu_slot_remove_write_access(st
 	}
 }
 
+void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+{
+	destroy_kvm_mmu(vcpu);
+
+	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
+		struct kvm_mmu_page *page;
+
+		page = container_of(vcpu->kvm->active_mmu_pages.next,
+				    struct kvm_mmu_page, link);
+		kvm_mmu_zap_page(vcpu, page);
+	}
+
+	mmu_free_memory_caches(vcpu);
+	kvm_arch_ops->tlb_flush(vcpu);
+	init_kvm_mmu(vcpu);
+}
+
+void kvm_mmu_module_exit(void)
+{
+	if (pte_chain_cache)
+		kmem_cache_destroy(pte_chain_cache);
+	if (rmap_desc_cache)
+		kmem_cache_destroy(rmap_desc_cache);
+}
+
+int kvm_mmu_module_init(void)
+{
+	pte_chain_cache = kmem_cache_create("kvm_pte_chain",
+					    sizeof(struct kvm_pte_chain),
+					    0, 0, NULL, NULL);
+	if (!pte_chain_cache)
+		goto nomem;
+	rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
+					    sizeof(struct kvm_rmap_desc),
+					    0, 0, NULL, NULL);
+	if (!rmap_desc_cache)
+		goto nomem;
+
+	return 0;
+
+nomem:
+	kvm_mmu_module_exit();
+	return -ENOMEM;
+}
+
 #ifdef AUDIT
 
 static const char *audit_msg;
@@ -1338,7 +1408,7 @@ static void audit_mappings_page(struct k
 	for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
 		u64 ent = pt[i];
 
-		if (!ent & PT_PRESENT_MASK)
+		if (!(ent & PT_PRESENT_MASK))
 			continue;
 
 		va = canonicalize(va);
@@ -1360,7 +1430,7 @@ static void audit_mappings_page(struct k
 
 static void audit_mappings(struct kvm_vcpu *vcpu)
 {
-	int i;
+	unsigned i;
 
 	if (vcpu->mmu.root_level == 4)
 		audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4);
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index f3bcee9..73ffbff 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -148,8 +148,7 @@ #endif
 			break;
 		}
 
-		if (walker->level != 3 || is_long_mode(vcpu))
-			walker->inherited_ar &= walker->table[index];
+		walker->inherited_ar &= walker->table[index];
 		table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
 		paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
 		kunmap_atomic(walker->table, KM_USER0);
@@ -248,6 +247,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu
 		u64 shadow_pte;
 		int metaphysical;
 		gfn_t table_gfn;
+		unsigned hugepage_access = 0;
 
 		if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
 			if (level == PT_PAGE_TABLE_LEVEL)
@@ -277,6 +277,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu
 		if (level - 1 == PT_PAGE_TABLE_LEVEL
 		    && walker->level == PT_DIRECTORY_LEVEL) {
 			metaphysical = 1;
+			hugepage_access = *guest_ent;
+			hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+			hugepage_access >>= PT_WRITABLE_SHIFT;
 			table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
 				>> PAGE_SHIFT;
 		} else {
@@ -284,7 +287,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu
 			table_gfn = walker->table_gfn[level - 2];
 		}
 		shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
-					       metaphysical, shadow_ent);
+					       metaphysical, hugepage_access,
+					       shadow_ent);
 		shadow_addr = shadow_page->page_hpa;
 		shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
 			| PT_WRITABLE_MASK | PT_USER_MASK;
@@ -444,7 +448,7 @@ static int FNAME(page_fault)(struct kvm_
 	if (is_io_pte(*shadow_pte))
 		return 1;
 
-	++kvm_stat.pf_fixed;
+	++vcpu->stat.pf_fixed;
 	kvm_mmu_audit(vcpu, "post page fault (fixed)");
 
 	return write_pt;
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 3d8ea7a..9c15f32 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -44,6 +44,10 @@ #define SEG_TYPE_BUSY_TSS16 3
 #define KVM_EFER_LMA (1 << 10)
 #define KVM_EFER_LME (1 << 8)
 
+#define SVM_FEATURE_NPT  (1 << 0)
+#define SVM_FEATURE_LBRV (1 << 1)
+#define SVM_DEATURE_SVML (1 << 2)
+
 unsigned long iopm_base;
 unsigned long msrpm_base;
 
@@ -59,15 +63,16 @@ struct kvm_ldttss_desc {
 struct svm_cpu_data {
 	int cpu;
 
-	uint64_t asid_generation;
-	uint32_t max_asid;
-	uint32_t next_asid;
+	u64 asid_generation;
+	u32 max_asid;
+	u32 next_asid;
 	struct kvm_ldttss_desc *tss_desc;
 
 	struct page *save_area;
 };
 
 static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+static uint32_t svm_features;
 
 struct svm_init_data {
 	int cpu;
@@ -82,6 +87,11 @@ #define MSRS_IN_RANGE (MSRS_RANGE_SIZE *
 
 #define MAX_INST_SIZE 15
 
+static inline u32 svm_has(u32 feat)
+{
+	return svm_features & feat;
+}
+
 static unsigned get_addr_size(struct kvm_vcpu *vcpu)
 {
 	struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
@@ -203,13 +213,6 @@ static void inject_ud(struct kvm_vcpu *v
 						UD_VECTOR;
 }
 
-static void inject_db(struct kvm_vcpu *vcpu)
-{
-	vcpu->svm->vmcb->control.event_inj = 	SVM_EVTINJ_VALID |
-						SVM_EVTINJ_TYPE_EXEPT |
-						DB_VECTOR;
-}
-
 static int is_page_fault(uint32_t info)
 {
 	info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
@@ -309,6 +312,7 @@ #endif
 	svm_data->asid_generation = 1;
 	svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
 	svm_data->next_asid = svm_data->max_asid + 1;
+	svm_features = cpuid_edx(SVM_CPUID_FUNC);
 
 	asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
 	gdt = (struct desc_struct *)gdt_descr.address;
@@ -459,7 +463,6 @@ static void init_vmcb(struct vmcb *vmcb)
 {
 	struct vmcb_control_area *control = &vmcb->control;
 	struct vmcb_save_area *save = &vmcb->save;
-	u64 tsc;
 
 	control->intercept_cr_read = 	INTERCEPT_CR0_MASK |
 					INTERCEPT_CR3_MASK |
@@ -511,12 +514,13 @@ static void init_vmcb(struct vmcb *vmcb)
 				(1ULL << INTERCEPT_VMSAVE) |
 				(1ULL << INTERCEPT_STGI) |
 				(1ULL << INTERCEPT_CLGI) |
-				(1ULL << INTERCEPT_SKINIT);
+				(1ULL << INTERCEPT_SKINIT) |
+				(1ULL << INTERCEPT_MONITOR) |
+				(1ULL << INTERCEPT_MWAIT);
 
 	control->iopm_base_pa = iopm_base;
 	control->msrpm_base_pa = msrpm_base;
-	rdtscll(tsc);
-	control->tsc_offset = -tsc;
+	control->tsc_offset = 0;
 	control->int_ctl = V_INTR_MASKING_MASK;
 
 	init_seg(&save->es);
@@ -576,12 +580,15 @@ static int svm_create_vcpu(struct kvm_vc
 	vcpu->svm->vmcb = page_address(page);
 	memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
 	vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
-	vcpu->svm->cr0 = 0x00000010;
 	vcpu->svm->asid_generation = 0;
 	memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
 	init_vmcb(vcpu->svm->vmcb);
 
 	fx_init(vcpu);
+	vcpu->fpu_active = 1;
+	vcpu->apic_base = 0xfee00000 |
+			/*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
+			MSR_IA32_APICBASE_ENABLE;
 
 	return 0;
 
@@ -602,11 +609,34 @@ static void svm_free_vcpu(struct kvm_vcp
 
 static void svm_vcpu_load(struct kvm_vcpu *vcpu)
 {
-	get_cpu();
+	int cpu, i;
+
+	cpu = get_cpu();
+	if (unlikely(cpu != vcpu->cpu)) {
+		u64 tsc_this, delta;
+
+		/*
+		 * Make sure that the guest sees a monotonically
+		 * increasing TSC.
+		 */
+		rdtscll(tsc_this);
+		delta = vcpu->host_tsc - tsc_this;
+		vcpu->svm->vmcb->control.tsc_offset += delta;
+		vcpu->cpu = cpu;
+	}
+
+	for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
+		rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
 {
+	int i;
+
+	for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
+		wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+
+	rdtscll(vcpu->host_tsc);
 	put_cpu();
 }
 
@@ -714,7 +744,7 @@ static void svm_set_gdt(struct kvm_vcpu 
 	vcpu->svm->vmcb->save.gdtr.base = dt->base ;
 }
 
-static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 {
 }
 
@@ -733,9 +763,15 @@ #ifdef CONFIG_X86_64
 		}
 	}
 #endif
-	vcpu->svm->cr0 = cr0;
-	vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK | CR0_WP_MASK;
+	if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
+		vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+		vcpu->fpu_active = 1;
+	}
+
 	vcpu->cr0 = cr0;
+	cr0 |= CR0_PG_MASK | CR0_WP_MASK;
+	cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
+	vcpu->svm->vmcb->save.cr0 = cr0;
 }
 
 static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -785,18 +821,16 @@ static int svm_guest_debug(struct kvm_vc
 
 static void load_host_msrs(struct kvm_vcpu *vcpu)
 {
-	int i;
-
-	for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
-		wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+#ifdef CONFIG_X86_64
+	wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+#endif
 }
 
 static void save_host_msrs(struct kvm_vcpu *vcpu)
 {
-	int i;
-
-	for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
-		rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+#ifdef CONFIG_X86_64
+	rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+#endif
 }
 
 static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
@@ -890,7 +924,7 @@ static int pf_interception(struct kvm_vc
 	case EMULATE_DONE:
 		return 1;
 	case EMULATE_DO_MMIO:
-		++kvm_stat.mmio_exits;
+		++vcpu->stat.mmio_exits;
 		kvm_run->exit_reason = KVM_EXIT_MMIO;
 		return 0;
 	case EMULATE_FAIL:
@@ -904,6 +938,16 @@ static int pf_interception(struct kvm_vc
 	return 0;
 }
 
+static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+       if (!(vcpu->cr0 & CR0_TS_MASK))
+               vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
+       vcpu->fpu_active = 1;
+
+       return 1;
+}
+
 static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	/*
@@ -981,7 +1025,7 @@ static int io_get_override(struct kvm_vc
 	return 0;
 }
 
-static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address)
+static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address)
 {
 	unsigned long addr_mask;
 	unsigned long *reg;
@@ -1025,38 +1069,38 @@ static unsigned long io_adress(struct kv
 static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
-	int _in = io_info & SVM_IOIO_TYPE_MASK;
+	int size, down, in, string, rep;
+	unsigned port;
+	unsigned long count;
+	gva_t address = 0;
 
-	++kvm_stat.io_exits;
+	++vcpu->stat.io_exits;
 
 	vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
 
-	kvm_run->exit_reason = KVM_EXIT_IO;
-	kvm_run->io.port = io_info >> 16;
-	kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-	kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT);
-	kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0;
-	kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+	in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
+	port = io_info >> 16;
+	size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
+	string = (io_info & SVM_IOIO_STR_MASK) != 0;
+	rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+	count = 1;
+	down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
 
-	if (kvm_run->io.string) {
+	if (string) {
 		unsigned addr_mask;
 
-		addr_mask = io_adress(vcpu, _in, &kvm_run->io.address);
+		addr_mask = io_adress(vcpu, in, &address);
 		if (!addr_mask) {
 			printk(KERN_DEBUG "%s: get io address failed\n",
 			       __FUNCTION__);
 			return 1;
 		}
 
-		if (kvm_run->io.rep) {
-			kvm_run->io.count
-				= vcpu->regs[VCPU_REGS_RCX] & addr_mask;
-			kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags
-						   & X86_EFLAGS_DF) != 0;
-		}
-	} else
-		kvm_run->io.value = vcpu->svm->vmcb->save.rax;
-	return 0;
+		if (rep)
+			count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
+	}
+	return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
+			     address, rep, port);
 }
 
 static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1072,13 +1116,14 @@ static int halt_interception(struct kvm_
 		return 1;
 
 	kvm_run->exit_reason = KVM_EXIT_HLT;
-	++kvm_stat.halt_exits;
+	++vcpu->stat.halt_exits;
 	return 0;
 }
 
 static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-	vcpu->svm->vmcb->save.rip += 3;
+	vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3;
+	skip_emulated_instruction(vcpu);
 	return kvm_hypercall(vcpu, kvm_run);
 }
 
@@ -1098,8 +1143,8 @@ static int task_switch_interception(stru
 static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
-	kvm_run->exit_reason = KVM_EXIT_CPUID;
-	return 0;
+	kvm_emulate_cpuid(vcpu);
+	return 1;
 }
 
 static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1239,7 +1284,7 @@ static int interrupt_window_interception
 	 */
 	if (kvm_run->request_interrupt_window &&
 	    !vcpu->irq_summary) {
-		++kvm_stat.irq_window_exits;
+		++vcpu->stat.irq_window_exits;
 		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
 		return 0;
 	}
@@ -1267,6 +1312,7 @@ static int (*svm_exit_handlers[])(struct
 	[SVM_EXIT_WRITE_DR5]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_DR7]			= emulate_on_interception,
 	[SVM_EXIT_EXCP_BASE + PF_VECTOR] 	= pf_interception,
+	[SVM_EXIT_EXCP_BASE + NM_VECTOR] 	= nm_interception,
 	[SVM_EXIT_INTR] 			= nop_on_interception,
 	[SVM_EXIT_NMI]				= nop_on_interception,
 	[SVM_EXIT_SMI]				= nop_on_interception,
@@ -1288,6 +1334,8 @@ static int (*svm_exit_handlers[])(struct
 	[SVM_EXIT_STGI]				= invalid_op_interception,
 	[SVM_EXIT_CLGI]				= invalid_op_interception,
 	[SVM_EXIT_SKINIT]			= invalid_op_interception,
+	[SVM_EXIT_MONITOR]			= invalid_op_interception,
+	[SVM_EXIT_MWAIT]			= invalid_op_interception,
 };
 
 
@@ -1295,8 +1343,6 @@ static int handle_exit(struct kvm_vcpu *
 {
 	u32 exit_code = vcpu->svm->vmcb->control.exit_code;
 
-	kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
-
 	if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
 	    exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
 		printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
@@ -1307,12 +1353,7 @@ static int handle_exit(struct kvm_vcpu *
 	if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
 	    || svm_exit_handlers[exit_code] == 0) {
 		kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-		printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n",
-		       __FUNCTION__,
-		       exit_code,
-		       vcpu->svm->vmcb->save.rip,
-		       vcpu->cr0,
-		       vcpu->svm->vmcb->save.rflags);
+		kvm_run->hw.hardware_exit_reason = exit_code;
 		return 0;
 	}
 
@@ -1461,8 +1502,10 @@ again:
 		load_db_regs(vcpu->svm->db_regs);
 	}
 
-	fx_save(vcpu->host_fx_image);
-	fx_restore(vcpu->guest_fx_image);
+	if (vcpu->fpu_active) {
+		fx_save(vcpu->host_fx_image);
+		fx_restore(vcpu->guest_fx_image);
+	}
 
 	asm volatile (
 #ifdef CONFIG_X86_64
@@ -1573,8 +1616,10 @@ #ifdef CONFIG_X86_64
 #endif
 		: "cc", "memory" );
 
-	fx_save(vcpu->guest_fx_image);
-	fx_restore(vcpu->host_fx_image);
+	if (vcpu->fpu_active) {
+		fx_save(vcpu->guest_fx_image);
+		fx_restore(vcpu->host_fx_image);
+	}
 
 	if ((vcpu->svm->vmcb->save.dr7 & 0xff))
 		load_db_regs(vcpu->svm->host_db_regs);
@@ -1606,8 +1651,9 @@ #endif
 	vcpu->svm->next_rip = 0;
 
 	if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
-		kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
-		kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code;
+		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+		kvm_run->fail_entry.hardware_entry_failure_reason
+			= vcpu->svm->vmcb->control.exit_code;
 		post_kvm_run_save(vcpu, kvm_run);
 		return 0;
 	}
@@ -1615,14 +1661,16 @@ #endif
 	r = handle_exit(vcpu, kvm_run);
 	if (r > 0) {
 		if (signal_pending(current)) {
-			++kvm_stat.signal_exits;
+			++vcpu->stat.signal_exits;
 			post_kvm_run_save(vcpu, kvm_run);
+			kvm_run->exit_reason = KVM_EXIT_INTR;
 			return -EINTR;
 		}
 
 		if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-			++kvm_stat.request_irq_exits;
+			++vcpu->stat.request_irq_exits;
 			post_kvm_run_save(vcpu, kvm_run);
+			kvm_run->exit_reason = KVM_EXIT_INTR;
 			return -EINTR;
 		}
 		kvm_resched(vcpu);
@@ -1641,6 +1689,12 @@ static void svm_set_cr3(struct kvm_vcpu 
 {
 	vcpu->svm->vmcb->save.cr3 = root;
 	force_new_asid(vcpu);
+
+	if (vcpu->fpu_active) {
+		vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
+		vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
+		vcpu->fpu_active = 0;
+	}
 }
 
 static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
@@ -1649,7 +1703,7 @@ static void svm_inject_page_fault(struct
 {
 	uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
 
-	++kvm_stat.pf_guest;
+	++vcpu->stat.pf_guest;
 
 	if (is_page_fault(exit_int_info)) {
 
@@ -1709,9 +1763,8 @@ static struct kvm_arch_ops svm_arch_ops 
 	.get_segment = svm_get_segment,
 	.set_segment = svm_set_segment,
 	.get_cs_db_l_bits = svm_get_cs_db_l_bits,
-	.decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
+	.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
 	.set_cr0 = svm_set_cr0,
-	.set_cr0_no_modeswitch = svm_set_cr0,
 	.set_cr3 = svm_set_cr3,
 	.set_cr4 = svm_set_cr4,
 	.set_efer = svm_set_efer,
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
index df731c3..5e93814 100644
--- a/drivers/kvm/svm.h
+++ b/drivers/kvm/svm.h
@@ -44,6 +44,9 @@ enum {
 	INTERCEPT_RDTSCP,
 	INTERCEPT_ICEBP,
 	INTERCEPT_WBINVD,
+	INTERCEPT_MONITOR,
+	INTERCEPT_MWAIT,
+	INTERCEPT_MWAIT_COND,
 };
 
 
@@ -298,6 +301,9 @@ #define SVM_EXIT_SKINIT		0x086
 #define SVM_EXIT_RDTSCP		0x087
 #define SVM_EXIT_ICEBP		0x088
 #define SVM_EXIT_WBINVD		0x089
+#define SVM_EXIT_MONITOR	0x08a
+#define SVM_EXIT_MWAIT		0x08b
+#define SVM_EXIT_MWAIT_COND	0x08c
 #define SVM_EXIT_NPF  		0x400
 
 #define SVM_EXIT_ERR		-1
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index fbbf9d6..724db00 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -17,7 +17,6 @@
 
 #include "kvm.h"
 #include "vmx.h"
-#include "kvm_vmx.h"
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -70,6 +69,10 @@ static struct kvm_vmx_segment_field {
 	VMX_SEGMENT_FIELD(LDTR),
 };
 
+/*
+ * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
+ * away by decrementing the array size.
+ */
 static const u32 vmx_msr_index[] = {
 #ifdef CONFIG_X86_64
 	MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
@@ -78,6 +81,19 @@ #endif
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
+#ifdef CONFIG_X86_64
+static unsigned msr_offset_kernel_gs_base;
+#define NR_64BIT_MSRS 4
+/*
+ * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
+ * mechanism (cpu bug AA24)
+ */
+#define NR_BAD_MSRS 2
+#else
+#define NR_64BIT_MSRS 0
+#define NR_BAD_MSRS 0
+#endif
+
 static inline int is_page_fault(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -85,6 +101,13 @@ static inline int is_page_fault(u32 intr
 		(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
 }
 
+static inline int is_no_device(u32 intr_info)
+{
+	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+			     INTR_INFO_VALID_MASK)) ==
+		(INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
+}
+
 static inline int is_external_interrupt(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -200,6 +223,16 @@ #else
 #endif
 }
 
+static void vmcs_clear_bits(unsigned long field, u32 mask)
+{
+	vmcs_writel(field, vmcs_readl(field) & ~mask);
+}
+
+static void vmcs_set_bits(unsigned long field, u32 mask)
+{
+	vmcs_writel(field, vmcs_readl(field) | mask);
+}
+
 /*
  * Switches to specified vcpu, until a matching vcpu_put(), but assumes
  * vcpu mutex is already taken.
@@ -297,6 +330,44 @@ static void vmx_inject_gp(struct kvm_vcp
 }
 
 /*
+ * Set up the vmcs to automatically save and restore system
+ * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
+ * mode, as fiddling with msrs is very expensive.
+ */
+static void setup_msrs(struct kvm_vcpu *vcpu)
+{
+	int nr_skip, nr_good_msrs;
+
+	if (is_long_mode(vcpu))
+		nr_skip = NR_BAD_MSRS;
+	else
+		nr_skip = NR_64BIT_MSRS;
+	nr_good_msrs = vcpu->nmsrs - nr_skip;
+
+	/*
+	 * MSR_K6_STAR is only needed on long mode guests, and only
+	 * if efer.sce is enabled.
+	 */
+	if (find_msr_entry(vcpu, MSR_K6_STAR)) {
+		--nr_good_msrs;
+#ifdef CONFIG_X86_64
+		if (is_long_mode(vcpu) && (vcpu->shadow_efer & EFER_SCE))
+			++nr_good_msrs;
+#endif
+	}
+
+	vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
+		    virt_to_phys(vcpu->guest_msrs + nr_skip));
+	vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
+		    virt_to_phys(vcpu->guest_msrs + nr_skip));
+	vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
+		    virt_to_phys(vcpu->host_msrs + nr_skip));
+	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
+	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs);  /* 22.2.2 */
+	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+}
+
+/*
  * reads and returns guest's timestamp counter "register"
  * guest_tsc = host_tsc + tsc_offset    -- 21.3
  */
@@ -712,6 +783,8 @@ static void enter_rmode(struct kvm_vcpu 
 
 	vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
 	vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+	if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
+		vmcs_writel(GUEST_CS_BASE, 0xf0000);
 	vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
 
 	fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
@@ -754,11 +827,8 @@ static void exit_lmode(struct kvm_vcpu *
 
 #endif
 
-static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 {
-	vcpu->cr0 &= KVM_GUEST_CR0_MASK;
-	vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK;
-
 	vcpu->cr4 &= KVM_GUEST_CR4_MASK;
 	vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
 }
@@ -780,22 +850,11 @@ #ifdef CONFIG_X86_64
 	}
 #endif
 
-	vmcs_writel(CR0_READ_SHADOW, cr0);
-	vmcs_writel(GUEST_CR0,
-		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
-	vcpu->cr0 = cr0;
-}
-
-/*
- * Used when restoring the VM to avoid corrupting segment registers
- */
-static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
-{
-	if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
-		enter_rmode(vcpu);
+	if (!(cr0 & CR0_TS_MASK)) {
+		vcpu->fpu_active = 1;
+		vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK);
+	}
 
-	vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
-	update_exception_bitmap(vcpu);
 	vmcs_writel(CR0_READ_SHADOW, cr0);
 	vmcs_writel(GUEST_CR0,
 		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
@@ -805,6 +864,12 @@ static void vmx_set_cr0_no_modeswitch(st
 static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
 	vmcs_writel(GUEST_CR3, cr3);
+
+	if (!(vcpu->cr0 & CR0_TS_MASK)) {
+		vcpu->fpu_active = 0;
+		vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+		vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+	}
 }
 
 static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -835,6 +900,7 @@ static void vmx_set_efer(struct kvm_vcpu
 
 		msr->data = efer & ~EFER_LME;
 	}
+	setup_msrs(vcpu);
 }
 
 #endif
@@ -878,7 +944,14 @@ static void vmx_set_segment(struct kvm_v
 	vmcs_writel(sf->base, var->base);
 	vmcs_write32(sf->limit, var->limit);
 	vmcs_write16(sf->selector, var->selector);
-	if (var->unusable)
+	if (vcpu->rmode.active && var->s) {
+		/*
+		 * Hack real-mode segments into vm86 compatibility.
+		 */
+		if (var->base == 0xffff0000 && var->selector == 0xf000)
+			vmcs_writel(sf->base, 0xf0000);
+		ar = 0xf3;
+	} else if (var->unusable)
 		ar = 1 << 16;
 	else {
 		ar = var->type & 15;
@@ -933,9 +1006,9 @@ static int init_rmode_tss(struct kvm* kv
 	gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
 	char *page;
 
-	p1 = _gfn_to_page(kvm, fn++);
-	p2 = _gfn_to_page(kvm, fn++);
-	p3 = _gfn_to_page(kvm, fn);
+	p1 = gfn_to_page(kvm, fn++);
+	p2 = gfn_to_page(kvm, fn++);
+	p3 = gfn_to_page(kvm, fn);
 
 	if (!p1 || !p2 || !p3) {
 		kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
@@ -991,7 +1064,6 @@ static int vmx_vcpu_setup(struct kvm_vcp
 	struct descriptor_table dt;
 	int i;
 	int ret = 0;
-	int nr_good_msrs;
 	extern asmlinkage void kvm_vmx_return(void);
 
 	if (!init_rmode_tss(vcpu->kvm)) {
@@ -1136,23 +1208,17 @@ #endif
 		vcpu->host_msrs[j].reserved = 0;
 		vcpu->host_msrs[j].data = data;
 		vcpu->guest_msrs[j] = vcpu->host_msrs[j];
+#ifdef CONFIG_X86_64
+		if (index == MSR_KERNEL_GS_BASE)
+			msr_offset_kernel_gs_base = j;
+#endif
 		++vcpu->nmsrs;
 	}
-	printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs);
 
-	nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS;
-	vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
-		    virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
-	vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
-		    virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
-	vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
-		    virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS));
+	setup_msrs(vcpu);
+
 	vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
 		     	       (HOST_IS_64 << 9));  /* 22.2,1, 20.7.1 */
-	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
-	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs);  /* 22.2.2 */
-	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
-
 
 	/* 22.2.1, 20.8.1 */
 	vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
@@ -1164,7 +1230,7 @@ #ifdef CONFIG_X86_64
 	vmcs_writel(TPR_THRESHOLD, 0);
 #endif
 
-	vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK);
+	vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
 	vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
 
 	vcpu->cr0 = 0x60000010;
@@ -1190,7 +1256,7 @@ static void inject_rmode_irq(struct kvm_
 	u16 sp =  vmcs_readl(GUEST_RSP);
 	u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
 
-	if (sp > ss_limit || sp - 6 > sp) {
+	if (sp > ss_limit || sp < 6 ) {
 		vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
 			    __FUNCTION__,
 			    vmcs_readl(GUEST_RSP),
@@ -1330,6 +1396,15 @@ static int handle_exception(struct kvm_v
 		asm ("int $2");
 		return 1;
 	}
+
+	if (is_no_device(intr_info)) {
+		vcpu->fpu_active = 1;
+		vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+		if (!(vcpu->cr0 & CR0_TS_MASK))
+			vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+		return 1;
+	}
+
 	error_code = 0;
 	rip = vmcs_readl(GUEST_RIP);
 	if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
@@ -1355,7 +1430,7 @@ static int handle_exception(struct kvm_v
 		case EMULATE_DONE:
 			return 1;
 		case EMULATE_DO_MMIO:
-			++kvm_stat.mmio_exits;
+			++vcpu->stat.mmio_exits;
 			kvm_run->exit_reason = KVM_EXIT_MMIO;
 			return 0;
 		 case EMULATE_FAIL:
@@ -1384,7 +1459,7 @@ static int handle_exception(struct kvm_v
 static int handle_external_interrupt(struct kvm_vcpu *vcpu,
 				     struct kvm_run *kvm_run)
 {
-	++kvm_stat.irq_exits;
+	++vcpu->stat.irq_exits;
 	return 1;
 }
 
@@ -1394,7 +1469,7 @@ static int handle_triple_fault(struct kv
 	return 0;
 }
 
-static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
+static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count)
 {
 	u64 inst;
 	gva_t rip;
@@ -1439,33 +1514,35 @@ static int get_io_count(struct kvm_vcpu 
 done:
 	countr_size *= 8;
 	*count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
+	//printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]);
 	return 1;
 }
 
 static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	u64 exit_qualification;
+	int size, down, in, string, rep;
+	unsigned port;
+	unsigned long count;
+	gva_t address;
 
-	++kvm_stat.io_exits;
+	++vcpu->stat.io_exits;
 	exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
-	kvm_run->exit_reason = KVM_EXIT_IO;
-	if (exit_qualification & 8)
-		kvm_run->io.direction = KVM_EXIT_IO_IN;
-	else
-		kvm_run->io.direction = KVM_EXIT_IO_OUT;
-	kvm_run->io.size = (exit_qualification & 7) + 1;
-	kvm_run->io.string = (exit_qualification & 16) != 0;
-	kvm_run->io.string_down
-		= (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
-	kvm_run->io.rep = (exit_qualification & 32) != 0;
-	kvm_run->io.port = exit_qualification >> 16;
-	if (kvm_run->io.string) {
-		if (!get_io_count(vcpu, &kvm_run->io.count))
+	in = (exit_qualification & 8) != 0;
+	size = (exit_qualification & 7) + 1;
+	string = (exit_qualification & 16) != 0;
+	down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
+	count = 1;
+	rep = (exit_qualification & 32) != 0;
+	port = exit_qualification >> 16;
+	address = 0;
+	if (string) {
+		if (rep && !get_io_count(vcpu, &count))
 			return 1;
-		kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS);
-	} else
-		kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */
-	return 0;
+		address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+	}
+	return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
+			     address, rep, port);
 }
 
 static void
@@ -1514,6 +1591,15 @@ static int handle_cr(struct kvm_vcpu *vc
 			return 1;
 		};
 		break;
+	case 2: /* clts */
+		vcpu_load_rsp_rip(vcpu);
+		vcpu->fpu_active = 1;
+		vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+		vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+		vcpu->cr0 &= ~CR0_TS_MASK;
+		vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
+		skip_emulated_instruction(vcpu);
+		return 1;
 	case 1: /*mov from cr*/
 		switch (cr) {
 		case 3:
@@ -1523,8 +1609,6 @@ static int handle_cr(struct kvm_vcpu *vc
 			skip_emulated_instruction(vcpu);
 			return 1;
 		case 8:
-			printk(KERN_DEBUG "handle_cr: read CR8 "
-			       "cpu erratum AA15\n");
 			vcpu_load_rsp_rip(vcpu);
 			vcpu->regs[reg] = vcpu->cr8;
 			vcpu_put_rsp_rip(vcpu);
@@ -1583,8 +1667,8 @@ static int handle_dr(struct kvm_vcpu *vc
 
 static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-	kvm_run->exit_reason = KVM_EXIT_CPUID;
-	return 0;
+	kvm_emulate_cpuid(vcpu);
+	return 1;
 }
 
 static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1639,7 +1723,7 @@ static int handle_interrupt_window(struc
 	if (kvm_run->request_interrupt_window &&
 	    !vcpu->irq_summary) {
 		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
-		++kvm_stat.irq_window_exits;
+		++vcpu->stat.irq_window_exits;
 		return 0;
 	}
 	return 1;
@@ -1652,13 +1736,13 @@ static int handle_halt(struct kvm_vcpu *
 		return 1;
 
 	kvm_run->exit_reason = KVM_EXIT_HLT;
-	++kvm_stat.halt_exits;
+	++vcpu->stat.halt_exits;
 	return 0;
 }
 
 static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-	vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3);
+	skip_emulated_instruction(vcpu);
 	return kvm_hypercall(vcpu, kvm_run);
 }
 
@@ -1699,7 +1783,6 @@ static int kvm_handle_exit(struct kvm_ru
 				exit_reason != EXIT_REASON_EXCEPTION_NMI )
 		printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
 		       "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
-	kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
 	if (exit_reason < kvm_vmx_max_exit_handlers
 	    && kvm_vmx_exit_handlers[exit_reason])
 		return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
@@ -1763,11 +1846,21 @@ #endif
 	if (vcpu->guest_debug.enabled)
 		kvm_guest_debug_pre(vcpu);
 
-	fx_save(vcpu->host_fx_image);
-	fx_restore(vcpu->guest_fx_image);
+	if (vcpu->fpu_active) {
+		fx_save(vcpu->host_fx_image);
+		fx_restore(vcpu->guest_fx_image);
+	}
+	/*
+	 * Loading guest fpu may have cleared host cr0.ts
+	 */
+	vmcs_writel(HOST_CR0, read_cr0());
 
-	save_msrs(vcpu->host_msrs, vcpu->nmsrs);
-	load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+#ifdef CONFIG_X86_64
+	if (is_long_mode(vcpu)) {
+		save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1);
+		load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+	}
+#endif
 
 	asm (
 		/* Store host registers */
@@ -1909,21 +2002,28 @@ #endif
 
 		reload_tss();
 	}
-	++kvm_stat.exits;
+	++vcpu->stat.exits;
 
-	save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
-	load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+#ifdef CONFIG_X86_64
+	if (is_long_mode(vcpu)) {
+		save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+		load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+	}
+#endif
+
+	if (vcpu->fpu_active) {
+		fx_save(vcpu->guest_fx_image);
+		fx_restore(vcpu->host_fx_image);
+	}
 
-	fx_save(vcpu->guest_fx_image);
-	fx_restore(vcpu->host_fx_image);
 	vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
 
 	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
-	kvm_run->exit_type = 0;
 	if (fail) {
-		kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
-		kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR);
+		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+		kvm_run->fail_entry.hardware_entry_failure_reason
+			= vmcs_read32(VM_INSTRUCTION_ERROR);
 		r = 0;
 	} else {
 		/*
@@ -1933,19 +2033,20 @@ #endif
 			profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
 
 		vcpu->launched = 1;
-		kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
 		r = kvm_handle_exit(kvm_run, vcpu);
 		if (r > 0) {
 			/* Give scheduler a change to reschedule. */
 			if (signal_pending(current)) {
-				++kvm_stat.signal_exits;
+				++vcpu->stat.signal_exits;
 				post_kvm_run_save(vcpu, kvm_run);
+				kvm_run->exit_reason = KVM_EXIT_INTR;
 				return -EINTR;
 			}
 
 			if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-				++kvm_stat.request_irq_exits;
+				++vcpu->stat.request_irq_exits;
 				post_kvm_run_save(vcpu, kvm_run);
+				kvm_run->exit_reason = KVM_EXIT_INTR;
 				return -EINTR;
 			}
 
@@ -1969,7 +2070,7 @@ static void vmx_inject_page_fault(struct
 {
 	u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
 
-	++kvm_stat.pf_guest;
+	++vcpu->stat.pf_guest;
 
 	if (is_page_fault(vect_info)) {
 		printk(KERN_DEBUG "inject_page_fault: "
@@ -2026,6 +2127,7 @@ static int vmx_create_vcpu(struct kvm_vc
 	vmcs_clear(vmcs);
 	vcpu->vmcs = vmcs;
 	vcpu->launched = 0;
+	vcpu->fpu_active = 1;
 
 	return 0;
 
@@ -2062,9 +2164,8 @@ static struct kvm_arch_ops vmx_arch_ops 
 	.get_segment = vmx_get_segment,
 	.set_segment = vmx_set_segment,
 	.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
-	.decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits,
+	.decache_cr4_guest_bits = vmx_decache_cr4_guest_bits,
 	.set_cr0 = vmx_set_cr0,
-	.set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
 	.set_cr3 = vmx_set_cr3,
 	.set_cr4 = vmx_set_cr4,
 #ifdef CONFIG_X86_64
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 7513cdd..7ade090 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -833,8 +833,9 @@ done_prefixes:
 		dst.ptr = (unsigned long *)cr2;
 		dst.bytes = (d & ByteOp) ? 1 : op_bytes;
 		if (d & BitOp) {
-			dst.ptr += src.val / BITS_PER_LONG;
-			dst.bytes = sizeof(long);
+			unsigned long mask = ~(dst.bytes * 8 - 1);
+
+			dst.ptr = (void *)dst.ptr + (src.val & mask) / 8;
 		}
 		if (!(d & Mov) && /* optimisation - avoid slow emulated read */
 		    ((rc = ops->read_emulated((unsigned long)dst.ptr,
@@ -1044,7 +1045,7 @@ done_prefixes:
 			if ((rc = ops->write_std(
 				     register_address(ctxt->ss_base,
 						      _regs[VCPU_REGS_RSP]),
-				     dst.val, dst.bytes, ctxt)) != 0)
+				     &dst.val, dst.bytes, ctxt)) != 0)
 				goto done;
 			dst.val = dst.orig_val;	/* skanky: disable writeback */
 			break;
@@ -1077,12 +1078,12 @@ writeback:
 		case OP_MEM:
 			if (lock_prefix)
 				rc = ops->cmpxchg_emulated((unsigned long)dst.
-							   ptr, dst.orig_val,
-							   dst.val, dst.bytes,
+							   ptr, &dst.orig_val,
+							   &dst.val, dst.bytes,
 							   ctxt);
 			else
 				rc = ops->write_emulated((unsigned long)dst.ptr,
-							 dst.val, dst.bytes,
+							 &dst.val, dst.bytes,
 							 ctxt);
 			if (rc != 0)
 				goto done;
@@ -1320,36 +1321,8 @@ twobyte_special_insn:
 		realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
 		break;
 	case 0xc7:		/* Grp9 (cmpxchg8b) */
-#if defined(__i386__)
-		{
-			unsigned long old_lo, old_hi;
-			if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4,
-						      ctxt)) != 0)
-			    || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4,
-							 ctxt)) != 0))
-				goto done;
-			if ((old_lo != _regs[VCPU_REGS_RAX])
-			    || (old_hi != _regs[VCPU_REGS_RDX])) {
-				_regs[VCPU_REGS_RAX] = old_lo;
-				_regs[VCPU_REGS_RDX] = old_hi;
-				_eflags &= ~EFLG_ZF;
-			} else if (ops->cmpxchg8b_emulated == NULL) {
-				rc = X86EMUL_UNHANDLEABLE;
-				goto done;
-			} else {
-				if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo,
-							  old_hi,
-							  _regs[VCPU_REGS_RBX],
-							  _regs[VCPU_REGS_RCX],
-							  ctxt)) != 0)
-					goto done;
-				_eflags |= EFLG_ZF;
-			}
-			break;
-		}
-#elif defined(CONFIG_X86_64)
 		{
-			unsigned long old, new;
+			u64 old, new;
 			if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
 				goto done;
 			if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
@@ -1358,15 +1331,15 @@ #elif defined(CONFIG_X86_64)
 				_regs[VCPU_REGS_RDX] = (u32) (old >> 32);
 				_eflags &= ~EFLG_ZF;
 			} else {
-				new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX];
-				if ((rc = ops->cmpxchg_emulated(cr2, old,
-							  new, 8, ctxt)) != 0)
+				new = ((u64)_regs[VCPU_REGS_RCX] << 32)
+					| (u32) _regs[VCPU_REGS_RBX];
+				if ((rc = ops->cmpxchg_emulated(cr2, &old,
+							  &new, 8, ctxt)) != 0)
 					goto done;
 				_eflags |= EFLG_ZF;
 			}
 			break;
 		}
-#endif
 	}
 	goto writeback;
 
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
index 5d41bd5..ea3407d 100644
--- a/drivers/kvm/x86_emulate.h
+++ b/drivers/kvm/x86_emulate.h
@@ -59,8 +59,7 @@ struct x86_emulate_ops {
 	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
 	 *  @bytes: [IN ] Number of bytes to read from memory.
 	 */
-	int (*read_std)(unsigned long addr,
-			unsigned long *val,
+	int (*read_std)(unsigned long addr, void *val,
 			unsigned int bytes, struct x86_emulate_ctxt * ctxt);
 
 	/*
@@ -71,8 +70,7 @@ struct x86_emulate_ops {
 	 *                required).
 	 *  @bytes: [IN ] Number of bytes to write to memory.
 	 */
-	int (*write_std)(unsigned long addr,
-			 unsigned long val,
+	int (*write_std)(unsigned long addr, const void *val,
 			 unsigned int bytes, struct x86_emulate_ctxt * ctxt);
 
 	/*
@@ -82,7 +80,7 @@ struct x86_emulate_ops {
 	 *  @bytes: [IN ] Number of bytes to read from memory.
 	 */
 	int (*read_emulated) (unsigned long addr,
-			      unsigned long *val,
+			      void *val,
 			      unsigned int bytes,
 			      struct x86_emulate_ctxt * ctxt);
 
@@ -94,7 +92,7 @@ struct x86_emulate_ops {
 	 *  @bytes: [IN ] Number of bytes to write to memory.
 	 */
 	int (*write_emulated) (unsigned long addr,
-			       unsigned long val,
+			       const void *val,
 			       unsigned int bytes,
 			       struct x86_emulate_ctxt * ctxt);
 
@@ -107,29 +105,11 @@ struct x86_emulate_ops {
 	 *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
 	 */
 	int (*cmpxchg_emulated) (unsigned long addr,
-				 unsigned long old,
-				 unsigned long new,
+				 const void *old,
+				 const void *new,
 				 unsigned int bytes,
 				 struct x86_emulate_ctxt * ctxt);
 
-	/*
-	 * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
-	 *                     emulated/special memory area.
-	 *  @addr:  [IN ] Linear address to access.
-	 *  @old:   [IN ] Value expected to be current at @addr.
-	 *  @new:   [IN ] Value to write to @addr.
-	 * NOTES:
-	 *  1. This function is only ever called when emulating a real CMPXCHG8B.
-	 *  2. This function is *never* called on x86/64 systems.
-	 *  2. Not defining this function (i.e., specifying NULL) is equivalent
-	 *     to defining a function that always returns X86EMUL_UNHANDLEABLE.
-	 */
-	int (*cmpxchg8b_emulated) (unsigned long addr,
-				   unsigned long old_lo,
-				   unsigned long old_hi,
-				   unsigned long new_lo,
-				   unsigned long new_hi,
-				   struct x86_emulate_ctxt * ctxt);
 };
 
 struct cpu_user_regs;
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 1a86387..a32c91e 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,10 @@
 
-menu "Macintosh device drivers"
+menuconfig MACINTOSH_DRIVERS
+	bool "Macintosh device drivers"
 	depends on PPC || MAC || X86
+	default y
+
+if MACINTOSH_DRIVERS
 
 config ADB
 	bool "Apple Desktop Bus (ADB) support"
@@ -109,7 +113,9 @@ config PMAC_SMU
 
 config PMAC_APM_EMU
 	tristate "APM emulation"
-	depends on PPC_PMAC && PPC32 && PM && ADB_PMU
+	select SYS_SUPPORTS_APM_EMULATION
+	select APM_EMULATION
+	depends on ADB_PMU && PM
 
 config PMAC_MEDIABAY
 	bool "Support PowerBook hotswap media bay"
@@ -234,4 +240,4 @@ config PMAC_RACKMETER
 	  This driver procides some support to control the front panel
           blue LEDs "vu-meter" of the XServer macs.
 
-endmenu
+endif # MACINTOSH_DRIVERS
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index f729eeb..adfea3c 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@ static int autopoll_devs;
 int __adb_probe_sync;
 
 #ifdef CONFIG_PM
-static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier adb_sleep_notifier = {
 	adb_notify_sleep,
 	SLEEP_LEVEL_ADB,
@@ -340,11 +340,9 @@ #ifdef CONFIG_PM
 /*
  * notify clients before sleep and reset bus afterwards
  */
-int
+void
 adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
 {
-	int ret;
-	
 	switch (when) {
 	case PBOOK_SLEEP_REQUEST:
 		adb_got_sleep = 1;
@@ -353,22 +351,8 @@ adb_notify_sleep(struct pmu_sleep_notifi
 		/* Stop autopoll */
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(0);
-		ret = blocking_notifier_call_chain(&adb_client_list,
-				ADB_MSG_POWERDOWN, NULL);
-		if (ret & NOTIFY_STOP_MASK) {
-			up(&adb_probe_mutex);
-			return PBOOK_SLEEP_REFUSE;
-		}
-		break;
-	case PBOOK_SLEEP_REJECT:
-		if (adb_got_sleep) {
-			adb_got_sleep = 0;
-			up(&adb_probe_mutex);
-			adb_reset_bus();
-		}
-		break;
-		
-	case PBOOK_SLEEP_NOW:
+		blocking_notifier_call_chain(&adb_client_list,
+			ADB_MSG_POWERDOWN, NULL);
 		break;
 	case PBOOK_WAKE:
 		adb_got_sleep = 0;
@@ -376,14 +360,13 @@ adb_notify_sleep(struct pmu_sleep_notifi
 		adb_reset_bus();
 		break;
 	}
-	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PM */
 
 static int
 do_adb_reset_bus(void)
 {
-	int ret, nret;
+	int ret;
 	
 	if (adb_controller == NULL)
 		return -ENXIO;
@@ -391,13 +374,8 @@ do_adb_reset_bus(void)
 	if (adb_controller->autopoll)
 		adb_controller->autopoll(0);
 
-	nret = blocking_notifier_call_chain(&adb_client_list,
-			ADB_MSG_PRE_RESET, NULL);
-	if (nret & NOTIFY_STOP_MASK) {
-		if (adb_controller->autopoll)
-			adb_controller->autopoll(autopoll_devs);
-		return -EBUSY;
-	}
+	blocking_notifier_call_chain(&adb_client_list,
+		ADB_MSG_PRE_RESET, NULL);
 
 	if (sleepy_trackpad) {
 		/* Let the trackpad settle down */
@@ -427,10 +405,8 @@ do_adb_reset_bus(void)
 	}
 	up(&adb_handler_sem);
 
-	nret = blocking_notifier_call_chain(&adb_client_list,
-			ADB_MSG_POST_RESET, NULL);
-	if (nret & NOTIFY_STOP_MASK)
-		return -EBUSY;
+	blocking_notifier_call_chain(&adb_client_list,
+		ADB_MSG_POST_RESET, NULL);
 	
 	return ret;
 }
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index cdd5a0f..e54c4d9 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -145,11 +145,12 @@ anslcd_init(void)
 	int retval;
 	struct device_node* node;
 
-	node = find_devices("lcd");
-	if (!node || !node->parent)
-		return -ENODEV;
-	if (strcmp(node->parent->name, "gc"))
+	node = of_find_node_by_name(NULL, "lcd");
+	if (!node || !node->parent || strcmp(node->parent->name, "gc")) {
+		of_node_put(node);
 		return -ENODEV;
+	}
+	of_node_put(node);
 
 	anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
 	
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index c5e4d43..9821e63 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -1,9 +1,7 @@
-/* APM emulation layer for PowerMac
- * 
- * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+/*
+ * APM emulation for PMU-based machines
  *
- * Lots of code inherited from apm.c, see appropriate notice in
- *  arch/i386/kernel/apm.c
+ * Copyright 2001 Benjamin Herrenschmidt (benh@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
@@ -18,434 +16,39 @@
  *
  */
 
-#include <linux/module.h>
-
-#include <linux/poll.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
-#include <linux/apm_bios.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/pm.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
-
+#include <linux/module.h>
+#include <linux/apm-emulation.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(args...) printk(KERN_DEBUG args)
-//#define DBG(args...) xmon_printf(args)
-#else
-#define DBG(args...) do { } while (0)
-#endif
-
-/*
- * 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		20
-
-#define FAKE_APM_BIOS_VERSION	0x0101
-
-#define APM_USER_NOTIFY_TIMEOUT	(5*HZ)
-
-/*
- * The per-file APM data
- */
-struct apm_user {
-	int		magic;
-	struct apm_user *	next;
-	int		suser: 1;
-	int		suspend_waiting: 1;
-	int		suspends_pending;
-	int		suspends_read;
-	int		event_head;
-	int		event_tail;
-	apm_event_t	events[APM_MAX_EVENTS];
-};
-
-/*
- * The magic number in apm_user
- */
-#define APM_BIOS_MAGIC		0x4101
-
-/*
- * Local variables
- */
-static int			suspends_pending;
-
-static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user *	user_list;
-
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier apm_sleep_notifier = {
-	apm_notify_sleep,
-	SLEEP_LEVEL_USERLAND,
-};
-
-static const char driver_version[] = "0.5";	/* no spaces */
-
-#ifdef DEBUG
-static char *	apm_event_name[] = {
-	"system standby",
-	"system suspend",
-	"normal resume",
-	"critical resume",
-	"low battery",
-	"power status change",
-	"update time",
-	"critical suspend",
-	"user standby",
-	"user suspend",
-	"system standby resume",
-	"capabilities change"
-};
-#define NR_APM_EVENT_NAME	\
-		(sizeof(apm_event_name) / sizeof(apm_event_name[0]))
-
-#endif
-
-static int queue_empty(struct apm_user *as)
-{
-	return as->event_head == as->event_tail;
-}
-
-static apm_event_t get_queued_event(struct apm_user *as)
-{
-	as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
-	return as->events[as->event_tail];
-}
-
-static void queue_event(apm_event_t event, struct apm_user *sender)
-{
-	struct apm_user *	as;
-
-	DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]);
-	if (user_list == NULL)
-		return;
-	for (as = user_list; as != NULL; as = as->next) {
-		if (as == sender)
-			continue;
-		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
-		if (as->event_head == as->event_tail) {
-			static int notified;
-
-			if (notified++ == 0)
-			    printk(KERN_ERR "apm_emu: an event queue overflowed\n");
-			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
-		}
-		as->events[as->event_head] = event;
-		if (!as->suser)
-			continue;
-		switch (event) {
-		case APM_SYS_SUSPEND:
-		case APM_USER_SUSPEND:
-			as->suspends_pending++;
-			suspends_pending++;
-			break;
-		case APM_NORMAL_RESUME:
-			as->suspend_waiting = 0;
-			break;
-		}
-	}
-	wake_up_interruptible(&apm_waitqueue);
-}
-
-static int check_apm_user(struct apm_user *as, const char *func)
-{
-	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
-		printk(KERN_ERR "apm_emu: %s passed bad filp\n", func);
-		return 1;
-	}
-	return 0;
-}
-
-static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
-{
-	struct apm_user *	as;
-	size_t			i;
-	apm_event_t		event;
-	DECLARE_WAITQUEUE(wait, current);
-
-	as = fp->private_data;
-	if (check_apm_user(as, "read"))
-		return -EIO;
-	if (count < sizeof(apm_event_t))
-		return -EINVAL;
-	if (queue_empty(as)) {
-		if (fp->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		add_wait_queue(&apm_waitqueue, &wait);
-repeat:
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (queue_empty(as) && !signal_pending(current)) {
-			schedule();
-			goto repeat;
-		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&apm_waitqueue, &wait);
-	}
-	i = count;
-	while ((i >= sizeof(event)) && !queue_empty(as)) {
-		event = get_queued_event(as);
-		DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]);
-		if (copy_to_user(buf, &event, sizeof(event))) {
-			if (i < count)
-				break;
-			return -EFAULT;
-		}
-		switch (event) {
-		case APM_SYS_SUSPEND:
-		case APM_USER_SUSPEND:
-			as->suspends_read++;
-			break;
-		}
-		buf += sizeof(event);
-		i -= sizeof(event);
-	}
-	if (i < count)
-		return count - i;
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-static unsigned int do_poll(struct file *fp, poll_table * wait)
-{
-	struct apm_user * as;
-
-	as = fp->private_data;
-	if (check_apm_user(as, "poll"))
-		return 0;
-	poll_wait(fp, &apm_waitqueue, wait);
-	if (!queue_empty(as))
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static int do_ioctl(struct inode * inode, struct file *filp,
-		    u_int cmd, u_long arg)
-{
-	struct apm_user *	as;
-	DECLARE_WAITQUEUE(wait, current);
-
-	as = filp->private_data;
-	if (check_apm_user(as, "ioctl"))
-		return -EIO;
-	if (!as->suser)
-		return -EPERM;
-	switch (cmd) {
-	case APM_IOC_SUSPEND:
-		/* If a suspend message was sent to userland, we
-		 * consider this as a confirmation message
-		 */
-		if (as->suspends_read > 0) {
-			as->suspends_read--;
-			as->suspends_pending--;
-			suspends_pending--;
-		} else {
-			// Route to PMU suspend ?
-			break;
-		}
-		as->suspend_waiting = 1;
-		add_wait_queue(&apm_waitqueue, &wait);
-		DBG("apm_emu: ioctl waking up sleep waiter !\n");
-		wake_up(&apm_suspend_waitqueue);
-		mb();
-		while(as->suspend_waiting && !signal_pending(current)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
-		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&apm_waitqueue, &wait);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int do_release(struct inode * inode, struct file * filp)
-{
-	struct apm_user *	as;
-
-	as = filp->private_data;
-	if (check_apm_user(as, "release"))
-		return 0;
-	filp->private_data = NULL;
-	lock_kernel();
-	if (as->suspends_pending > 0) {
-		suspends_pending -= as->suspends_pending;
-		if (suspends_pending <= 0)
-			wake_up(&apm_suspend_waitqueue);
-	}
-	if (user_list == as)
-		user_list = as->next;
-	else {
-		struct apm_user *	as1;
-
-		for (as1 = user_list;
-		     (as1 != NULL) && (as1->next != as);
-		     as1 = as1->next)
-			;
-		if (as1 == NULL)
-			printk(KERN_ERR "apm: filp not in user list\n");
-		else
-			as1->next = as->next;
-	}
-	unlock_kernel();
-	kfree(as);
-	return 0;
-}
-
-static int do_open(struct inode * inode, struct file * filp)
-{
-	struct apm_user *	as;
-
-	as = kmalloc(sizeof(*as), GFP_KERNEL);
-	if (as == NULL) {
-		printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
-		       sizeof(*as));
-		return -ENOMEM;
-	}
-	as->magic = APM_BIOS_MAGIC;
-	as->event_tail = as->event_head = 0;
-	as->suspends_pending = 0;
-	as->suspends_read = 0;
-	/*
-	 * 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->next = user_list;
-	user_list = as;
-	filp->private_data = as;
-
-	DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser);
-
-	return 0;
-}
-
-/* Wait for all clients to ack the suspend request. APM API
- * doesn't provide a way to NAK, but this could be added
- * here.
- */
-static int wait_all_suspend(void)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&apm_suspend_waitqueue, &wait);
-	DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending);
-	while(suspends_pending > 0) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule();
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&apm_suspend_waitqueue, &wait);
-
-	DBG("apm_emu: wait_all_suspend() - complete !\n");
-	
-	return 1;
-}
-
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	switch(when) {
-		case PBOOK_SLEEP_REQUEST:
-			queue_event(APM_SYS_SUSPEND, NULL);
-			if (!wait_all_suspend())
-				return PBOOK_SLEEP_REFUSE;
-			break;
-		case PBOOK_SLEEP_REJECT:
-		case PBOOK_WAKE:
-			queue_event(APM_NORMAL_RESUME, NULL);
-			break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-
 #define APM_CRITICAL		10
 #define APM_LOW			30
 
-static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length)
+static void pmu_apm_get_power_status(struct apm_power_info *info)
 {
-	/* Arguments, with symbols from linux/apm_bios.h.  Information is
-	   from the Get Power Status (0x0a) call unless otherwise noted.
+	int percentage = -1;
+	int batteries = 0;
+	int time_units = -1;
+	int real_count = 0;
+	int i;
+	char charging = 0;
+	long charge = -1;
+	long amperage = 0;
+	unsigned long btype = 0;
+
+	info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
+	info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
+	info->units = APM_UNITS_MINS;
+
+	if (pmu_power_flags & PMU_PWR_AC_PRESENT)
+		info->ac_line_status = APM_AC_ONLINE;
+	else
+		info->ac_line_status = APM_AC_OFFLINE;
 
-	   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 */
-
-	unsigned short  ac_line_status;
-	unsigned short  battery_status = 0;
-	unsigned short  battery_flag   = 0xff;
-	int		percentage     = -1;
-	int             time_units     = -1;
-	int		real_count     = 0;
-	int		i;
-	char *		p = buf;
-	char		charging       = 0;
-	long		charge	       = -1;
-	long		amperage       = 0;
-	unsigned long	btype          = 0;
-
-	ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0);
 	for (i=0; i<pmu_battery_count; i++) {
 		if (pmu_batteries[i].flags & PMU_BATT_PRESENT) {
-			battery_status++;
+			batteries++;
 			if (percentage < 0)
 				percentage = 0;
 			if (charge < 0)
@@ -461,9 +64,9 @@ static int apm_emu_get_info(char *buf, c
 				charging++;
 		}
 	}
-	if (0 == battery_status)
-		ac_line_status = 1;
-	battery_status = 0xff;
+	if (batteries == 0)
+		info->ac_line_status = APM_AC_ONLINE;
+
 	if (real_count) {
 		if (amperage < 0) {
 			if (btype == PMU_BATT_TYPE_SMART)
@@ -473,85 +76,44 @@ static int apm_emu_get_info(char *buf, c
 		}
 		percentage /= real_count;
 		if (charging > 0) {
-			battery_status = 0x03;
-			battery_flag = 0x08;
+			info->battery_status = APM_BATTERY_STATUS_CHARGING;
+			info->battery_flag = APM_BATTERY_FLAG_CHARGING;
 		} else if (percentage <= APM_CRITICAL) {
-			battery_status = 0x02;
-			battery_flag = 0x04;
+			info->battery_status = APM_BATTERY_STATUS_CRITICAL;
+			info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
 		} else if (percentage <= APM_LOW) {
-			battery_status = 0x01;
-			battery_flag = 0x02;
+			info->battery_status = APM_BATTERY_STATUS_LOW;
+			info->battery_flag = APM_BATTERY_FLAG_LOW;
 		} else {
-			battery_status = 0x00;
-			battery_flag = 0x01;
+			info->battery_status = APM_BATTERY_STATUS_HIGH;
+			info->battery_flag = APM_BATTERY_FLAG_HIGH;
 		}
 	}
-	p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-		     driver_version,
-		     (FAKE_APM_BIOS_VERSION >> 8) & 0xff,
-		     FAKE_APM_BIOS_VERSION & 0xff,
-		     0,
-		     ac_line_status,
-		     battery_status,
-		     battery_flag,
-		     percentage,
-		     time_units,
-		     "min");
 
-	return p - buf;
+	info->battery_life = percentage;
+	info->time = time_units;
 }
 
-static const struct file_operations apm_bios_fops = {
-	.owner		= THIS_MODULE,
-	.read		= do_read,
-	.poll		= do_poll,
-	.ioctl		= do_ioctl,
-	.open		= do_open,
-	.release	= do_release,
-};
-
-static struct miscdevice apm_device = {
-	APM_MINOR_DEV,
-	"apm_bios",
-	&apm_bios_fops
-};
-
 static int __init apm_emu_init(void)
 {
-	struct proc_dir_entry *apm_proc;
-
-	if (sys_ctrler != SYS_CTRLER_PMU) {
-		printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n");
-		return -ENODEV;
-	}
-		
-	apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info);
-	if (apm_proc)
-		apm_proc->owner = THIS_MODULE;
+	apm_get_power_status = pmu_apm_get_power_status;
 
-	if (misc_register(&apm_device) != 0)
-		printk(KERN_INFO "Could not create misc. device for apm\n");
-
-	pmu_register_sleep_notifier(&apm_sleep_notifier);
-
-	printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version);
+	printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n");
 
 	return 0;
 }
 
 static void __exit apm_emu_exit(void)
 {
-	pmu_unregister_sleep_notifier(&apm_sleep_notifier);
-	misc_deregister(&apm_device);
-	remove_proc_entry("apm", NULL);
+	if (apm_get_power_status == pmu_apm_get_power_status)
+		apm_get_power_status = NULL;
 
-	printk(KERN_INFO "apm_emu: APM Emulation removed.\n");
+	printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n");
 }
 
 module_init(apm_emu_init);
 module_exit(apm_emu_exit);
 
 MODULE_AUTHOR("Benjamin Herrenschmidt");
-MODULE_DESCRIPTION("APM emulation layer for PowerMac");
+MODULE_DESCRIPTION("APM emulation for PowerMac");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index c1fd816..76c1e8e 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -24,7 +24,7 @@ static int mouse_last_keycode;
 
 #if defined(CONFIG_SYSCTL)
 /* file(s) in /proc/sys/dev/mac_hid */
-ctl_table mac_hid_files[] = {
+static ctl_table mac_hid_files[] = {
 	{
 		.ctl_name	= DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
 		.procname	= "mouse_button_emulation",
@@ -53,7 +53,7 @@ ctl_table mac_hid_files[] = {
 };
 
 /* dir in /proc/sys/dev */
-ctl_table mac_hid_dir[] = {
+static ctl_table mac_hid_dir[] = {
 	{
 		.ctl_name	= DEV_MAC_HID,
 		.procname	= "mac_hid",
@@ -65,7 +65,7 @@ ctl_table mac_hid_dir[] = {
 };
 
 /* /proc/sys/dev itself, in case that is not there yet */
-ctl_table mac_hid_root_dir[] = {
+static ctl_table mac_hid_root_dir[] = {
 	{
 		.ctl_name	= CTL_DEV,
 		.procname	= "dev",
@@ -102,8 +102,6 @@ int mac_hid_mouse_emulate_buttons(int ca
 	return 0;
 }
 
-EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
-
 static int emumousebtn_input_register(void)
 {
 	int ret;
@@ -129,7 +127,7 @@ static int emumousebtn_input_register(vo
 	return ret;
 }
 
-int __init mac_hid_init(void)
+static int __init mac_hid_init(void)
 {
 	int err;
 
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 026b67f..79119f5 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -82,7 +82,14 @@ struct adb_driver macio_adb_driver = {
 
 int macio_probe(void)
 {
-	return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
+	if (np) {
+		of_node_put(np);
+		return 0;
+	}
+	return -ENODEV;
 }
 
 int macio_init(void)
@@ -91,12 +98,14 @@ int macio_init(void)
 	struct resource r;
 	unsigned int irq;
 
-	adbs = find_compatible_devices("adb", "chrp,adb0");
+	adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
 	if (adbs == 0)
 		return -ENXIO;
 
-	if (of_address_to_resource(adbs, 0, &r))
+	if (of_address_to_resource(adbs, 0, &r)) {
+		of_node_put(adbs);
 		return -ENXIO;
+	}
 	adb = ioremap(r.start, sizeof(struct adb_regs));
 
 	out_8(&adb->ctrl.r, 0);
@@ -107,6 +116,7 @@ int macio_init(void)
 	out_8(&adb->autopoll.r, APE);
 
 	irq = irq_of_parse_and_map(adbs, 0);
+	of_node_put(adbs);
 	if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
 		printk(KERN_ERR "ADB: can't get irq %d\n", irq);
 		return -EAGAIN;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index d562160..c96b7fe 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -134,108 +134,12 @@ static int macio_device_resume(struct de
 	return 0;
 }
 
-static int macio_uevent(struct device *dev, char **envp, int num_envp,
-                          char *buffer, int buffer_size)
-{
-	struct macio_dev * macio_dev;
-	struct of_device * of;
-	char *scratch;
-	const char *compat, *compat2;
-
-	int i = 0;
-	int length, cplen, cplen2, seen = 0;
-
-	if (!dev)
-		return -ENODEV;
-
-	macio_dev = to_macio_device(dev);
-	if (!macio_dev)
-		return -ENODEV;
-
-	of = &macio_dev->ofdev;
-
-	/* stuff we want to pass to /sbin/hotplug */
-	envp[i++] = scratch = buffer;
-	length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-        /* Since the compatible field can contain pretty much anything
-         * it's not really legal to split it out with commas. We split it
-         * up using a number of environment variables instead. */
-
-	compat = get_property(of->node, "compatible", &cplen);
-	compat2 = compat;
-	cplen2= cplen;
-	while (compat && cplen > 0) {
-                envp[i++] = scratch;
-		length = scnprintf (scratch, buffer_size,
-		                     "OF_COMPATIBLE_%d=%s", seen, compat);
-		++length;
-		buffer_size -= length;
-		if ((buffer_size <= 0) || (i >= num_envp))
-			return -ENOMEM;
-		scratch += length;
-		length = strlen (compat) + 1;
-		compat += length;
-		cplen -= length;
-		seen++;
-	}
-
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
-			of->node->name, of->node->type);
-	/* overwrite '\0' */
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-	if (!compat2) {
-		compat2 = "";
-		cplen2 = 1;
-	}
-	while (cplen2 > 0) {
-		length = snprintf (scratch, buffer_size, "C%s", compat2);
-		buffer_size -= length;
-		if (buffer_size <= 0)
-			return -ENOMEM;
-		scratch += length;
-		length = strlen (compat2) + 1;
-		compat2 += length;
-		cplen2 -= length;
-	}
-
-	envp[i] = NULL;
-
-	return 0;
-}
-
 extern struct device_attribute macio_dev_attrs[];
 
 struct bus_type macio_bus_type = {
        .name	= "macio",
        .match	= macio_bus_match,
-       .uevent = macio_uevent,
+       .uevent = of_device_uevent,
        .probe	= macio_device_probe,
        .remove	= macio_device_remove,
        .shutdown = macio_device_shutdown,
@@ -491,7 +395,7 @@ #else
 #endif
 			MAX_NODE_NAME_SIZE, np->name);
 	} else {
-		reg = get_property(np, "reg", NULL);
+		reg = of_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 8566bdf..112e5ef 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -21,7 +21,7 @@ compatible_show (struct device *dev, str
 	int length = 0;
 
 	of = &to_macio_device (dev)->ofdev;
-	compat = get_property(of->node, "compatible", &cplen);
+	compat = of_get_property(of->node, "compatible", &cplen);
 	if (!compat) {
 		*buf = '\0';
 		return 0;
@@ -41,26 +41,15 @@ compatible_show (struct device *dev, str
 static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
 			      char *buf)
 {
-	struct of_device *of;
-	const char *compat;
-	int cplen;
-	int length;
+	struct of_device *ofdev = to_of_device(dev);
+	int len;
 
-	of = &to_macio_device (dev)->ofdev;
-	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;
-	while (cplen > 0) {
-		int l;
-		length += sprintf (buf, "C%s", compat);
-		buf += length;
-		l = strlen (compat) + 1;
-		compat += l;
-		cplen -= l;
-	}
+	len = of_device_get_modalias(ofdev, buf, PAGE_SIZE);
 
-	return length;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+
+	return len+1;
 }
 
 macio_config_of_attr (name, "%s\n");
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index f83fad2..4177ff0 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -387,7 +387,7 @@ static int __devinit rackmeter_probe(str
 	       if (strcmp(np->name, "lightshow") == 0)
 		       break;
 	       if ((strcmp(np->name, "sound") == 0) &&
-		   get_property(np, "virtual", NULL) != NULL)
+		   of_get_property(np, "virtual", NULL) != NULL)
 		       break;
 	}
 	if (np == NULL) {
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index c9f3dc4..f8e1a13 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -491,7 +491,7 @@ int __init smu_init (void)
 		printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
 		goto fail;
 	}
-	data = get_property(smu->db_node, "reg", NULL);
+	data = of_get_property(smu->db_node, "reg", NULL);
 	if (data == NULL) {
 		of_node_put(smu->db_node);
 		smu->db_node = NULL;
@@ -512,7 +512,7 @@ int __init smu_init (void)
 		smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
 		if (smu->msg_node == NULL)
 			break;
-		data = get_property(smu->msg_node, "reg", NULL);
+		data = of_get_property(smu->msg_node, "reg", NULL);
 		if (data == NULL) {
 			of_node_put(smu->msg_node);
 			smu->msg_node = NULL;
@@ -606,7 +606,7 @@ static void smu_expose_childs(struct wor
 	struct device_node *np;
 
 	for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
-		if (device_is_compatible(np, "smu-sensors"))
+		if (of_device_is_compatible(np, "smu-sensors"))
 			of_platform_device_create(np, "smu-sensors",
 						  &smu->of_dev->dev);
 }
@@ -952,7 +952,7 @@ static struct smu_sdbp_header *smu_creat
 	prop->name = ((char *)prop) + tlen - 18;
 	sprintf(prop->name, "sdb-partition-%02x", id);
 	prop->length = len;
-	prop->value = (unsigned char *)hdr;
+	prop->value = hdr;
 	prop->next = NULL;
 
 	/* Read the datablock */
@@ -1004,7 +1004,7 @@ const struct smu_sdbp_header *__smu_get_
 	} else
 		mutex_lock(&smu_part_access);
 
-	part = get_property(smu->of_node, pname, size);
+	part = of_get_property(smu->of_node, pname, size);
 	if (part == NULL) {
 		DPRINTK("trying to extract from SMU ...\n");
 		part = smu_create_sdb_partition(id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index a7ce559..bd55e6a 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -19,7 +19,6 @@ #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/suspend.h>
 #include <linux/kthread.h>
@@ -560,20 +559,20 @@ thermostat_init(void)
 	np = of_find_node_by_name(NULL, "fan");
 	if (!np)
 		return -ENODEV;
-	if (device_is_compatible(np, "adt7460"))
+	if (of_device_is_compatible(np, "adt7460"))
 		therm_type = ADT7460;
-	else if (device_is_compatible(np, "adt7467"))
+	else if (of_device_is_compatible(np, "adt7467"))
 		therm_type = ADT7467;
 	else
 		return -ENODEV;
 
-	prop = get_property(np, "hwsensor-params-version", NULL);
+	prop = of_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 = get_property(np, "reg", NULL);
+	prop = of_get_property(np, "reg", NULL);
 	if (!prop)
 		return -ENODEV;
 
@@ -591,9 +590,9 @@ thermostat_init(void)
 			 "limit_adjust: %d, fan_speed: %d\n",
 			 therm_bus, therm_address, limit_adjust, fan_speed);
 
-	if (get_property(np, "hwsensor-location", NULL)) {
+	if (of_get_property(np, "hwsensor-location", NULL)) {
 		for (i = 0; i < 3; i++) {
-			sensor_location[i] = get_property(np,
+			sensor_location[i] = of_get_property(np,
 					"hwsensor-location", NULL) + offset;
 
 			if (sensor_location[i] == NULL)
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 2e4ad44..dbb2240 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -117,7 +117,6 @@ #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/reboot.h>
 #include <linux/kmod.h>
@@ -674,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 = get_property(np, "cpuid", &len);
+	data = of_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);
@@ -1337,7 +1336,7 @@ static int init_backside_state(struct ba
 	 */
 	u3 = of_find_node_by_path("/u3@0,f8000000");
 	if (u3 != NULL) {
-		const u32 *vers = get_property(u3, "device-rev", NULL);
+		const u32 *vers = of_get_property(u3, "device-rev", NULL);
 		if (vers)
 			if (((*vers) & 0x3f) < 0x34)
 				u3h = 0;
@@ -2129,8 +2128,8 @@ static void fcu_lookup_fans(struct devic
 			continue;
 
 		/* Lookup for a matching location */
-		loc = get_property(np, "location", NULL);
-		reg = get_property(np, "reg", NULL);
+		loc = of_get_property(np, "location", NULL);
+		reg = of_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 a1d3a98..3d0354e 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -459,7 +459,8 @@ therm_of_probe( struct of_device *dev, c
 static int
 therm_of_remove( struct of_device *dev )
 {
-	return i2c_del_driver( &g4fan_driver );
+	i2c_del_driver( &g4fan_driver );
+	return 0;
 }
 
 static struct of_device_id therm_of_match[] = {{
@@ -492,7 +493,7 @@ g4fan_init( void )
 
 	if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
 		return -ENODEV;
-	info = get_property(np, "thermal-info", NULL);
+	info = of_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 d58fcf6..741a93a 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16];
 static unsigned char *reply_ptr;
 static int reading_reply;
 static int data_index;
+static int cuda_irq;
 #ifdef CONFIG_PPC
 static struct device_node *vias;
 #endif
@@ -131,7 +132,7 @@ int __init find_via_cuda(void)
     if (vias == 0)
 	return 0;
 
-    reg = get_property(vias, "reg", NULL);
+    reg = of_get_property(vias, "reg", NULL);
     if (reg == NULL) {
 	    printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
 	    goto fail;
@@ -160,10 +161,8 @@ int __init find_via_cuda(void)
     /* Clear and enable interrupts, but only on PPC. On 68K it's done  */
     /* for us by the main VIA driver in arch/m68k/mac/via.c        */
 
-#ifndef CONFIG_MAC
     out_8(&via[IFR], 0x7f);	/* clear interrupts by writing 1s */
     out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
-#endif
 
     /* enable autopoll */
     cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
@@ -181,24 +180,22 @@ #endif /* CONFIG_PPC */
 
 static int __init via_cuda_start(void)
 {
-    unsigned int irq;
-
     if (via == NULL)
 	return -ENODEV;
 
 #ifdef CONFIG_MAC
-    irq = IRQ_MAC_ADB;
+    cuda_irq = IRQ_MAC_ADB;
 #else /* CONFIG_MAC */
-    irq = irq_of_parse_and_map(vias, 0);
-    if (irq == NO_IRQ) {
+    cuda_irq = irq_of_parse_and_map(vias, 0);
+    if (cuda_irq == NO_IRQ) {
 	printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
 	       vias->full_name);
 	return -ENODEV;
     }
-#endif /* CONFIG_MAP */
+#endif /* CONFIG_MAC */
 
-    if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
-	printk(KERN_ERR "via-cuda: can't request irq %d\n", irq);
+    if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+	printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
 	return -EAGAIN;
     }
 
@@ -238,6 +235,7 @@ #else 
 	printk(KERN_ERR "cuda_init_via() failed\n");
 	return -ENODEV;
     }
+    out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
 
     return via_cuda_start();
 #endif
@@ -263,15 +261,17 @@ cuda_init_via(void)
     out_8(&via[B], in_8(&via[B]) | TACK | TIP);			/* negate them */
     out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT);	/* SR data in */
     (void)in_8(&via[SR]);						/* clear any left-over data */
-#ifndef CONFIG_MAC
+#ifdef CONFIG_PPC
     out_8(&via[IER], 0x7f);					/* disable interrupts from VIA */
     (void)in_8(&via[IER]);
+#else
+    out_8(&via[IER], SR_INT);					/* disable SR interrupt from VIA */
 #endif
 
     /* delay 4ms and then clear any pending interrupt */
     mdelay(4);
     (void)in_8(&via[SR]);
-    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+    out_8(&via[IFR], SR_INT);
 
     /* sync with the CUDA - assert TACK without TIP */
     out_8(&via[B], in_8(&via[B]) & ~TACK);
@@ -282,7 +282,7 @@ #endif
     /* wait for the interrupt and then clear it */
     WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
     (void)in_8(&via[SR]);
-    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+    out_8(&via[IFR], SR_INT);
 
     /* finish the sync by negating TACK */
     out_8(&via[B], in_8(&via[B]) | TACK);
@@ -291,7 +291,7 @@ #endif
     WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
     WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
     (void)in_8(&via[SR]);
-    out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+    out_8(&via[IFR], SR_INT);
     out_8(&via[B], in_8(&via[B]) | TIP);	/* should be unnecessary */
 
     return 0;
@@ -428,16 +428,12 @@ cuda_start(void)
 void
 cuda_poll(void)
 {
-    unsigned long flags;
-
     /* cuda_interrupt only takes a normal lock, we disable
      * interrupts here to avoid re-entering and thus deadlocking.
-     * An option would be to disable only the IRQ source with
-     * disable_irq(), would that work on m68k ? --BenH
      */
-    local_irq_save(flags);
+    disable_irq(cuda_irq);
     cuda_interrupt(0, NULL);
-    local_irq_restore(flags);
+    enable_irq(cuda_irq);
 }
 
 static irqreturn_t
@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg)
     unsigned char ibuf[16];
     int ibuf_len = 0;
     int complete = 0;
-    unsigned char virq;
     
     spin_lock(&cuda_lock);
 
-    virq = in_8(&via[IFR]) & 0x7f;
-    out_8(&via[IFR], virq);   
-    if ((virq & SR_INT) == 0) {
-        spin_unlock(&cuda_lock);
-	return IRQ_NONE;
+    /* On powermacs, this handler is registered for the VIA IRQ. But it uses
+     * just the shift register IRQ -- other VIA interrupt sources are disabled.
+     * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
+     * we are polling, the shift register IRQ flag has already been cleared.
+     */
+
+#ifdef CONFIG_MAC
+    if (!arg)
+#endif
+    {
+        if ((in_8(&via[IFR]) & SR_INT) == 0) {
+            spin_unlock(&cuda_lock);
+            return IRQ_NONE;
+        } else {
+            out_8(&via[IFR], SR_INT);
+        }
     }
     
     status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 1b3bad6..01b8eca 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -12,6 +12,15 @@
  * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
  * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
  * 				- Big overhaul, should actually work now.
+ * 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul.
+ *
+ * Suggested reading:
+ *   Inside Macintosh, ch. 5 ADB Manager
+ *   Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
+ *   Rockwell R6522 VIA datasheet
+ *
+ * Apple's "ADB Analyzer" bus sniffer is invaluable:
+ *   ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
  */
  
 #include <stdarg.h>
@@ -26,7 +35,6 @@ #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/machw.h>
 #include <asm/mac_via.h>
-#include <asm/io.h>
 #include <asm/system.h>
 
 static volatile unsigned char *via;
@@ -51,9 +59,7 @@ #define IER		(14*RS)		/* Interrupt enabl
 #define ANH		(15*RS)		/* A-side data, no handshake */
 
 /* Bits in B data register: all active low */
-#define TREQ		0x08		/* Transfer request (input) */
-#define TACK		0x10		/* Transfer acknowledge (output) */
-#define TIP		0x20		/* Transfer in progress (output) */
+#define CTLR_IRQ	0x08		/* Controller rcv status (input) */
 #define ST_MASK		0x30		/* mask for selecting ADB state bits */
 
 /* Bits in ACR */
@@ -65,8 +71,6 @@ #define SR_OUT		0x10		/* Shift out if 1 
 #define IER_SET		0x80		/* set bits in IER */
 #define IER_CLR		0		/* clear bits in IER */
 #define SR_INT		0x04		/* Shift register full/empty */
-#define SR_DATA		0x08		/* Shift register data */
-#define SR_CLOCK	0x10		/* Shift register clock */
 
 /* ADB transaction states according to GMHW */
 #define ST_CMD		0x00		/* ADB state: command byte */
@@ -77,7 +81,6 @@ #define ST_IDLE		0x30		/* ADB state: idl
 static int  macii_init_via(void);
 static void macii_start(void);
 static irqreturn_t macii_interrupt(int irq, void *arg);
-static void macii_retransmit(int);
 static void macii_queue_poll(void);
 
 static int macii_probe(void);
@@ -103,29 +106,37 @@ static enum macii_state {
 	sending,
 	reading,
 	read_done,
-	awaiting_reply
 } macii_state;
 
-static int need_poll;
-static int command_byte;
-static int last_reply;
-static int last_active;
-
-static struct adb_request *current_req;
-static struct adb_request *last_req;
-static struct adb_request *retry_req;
-static unsigned char reply_buf[16];
-static unsigned char *reply_ptr;
-static int reply_len;
-static int reading_reply;
-static int data_index;
-static int first_byte;
-static int prefix_len;
-static int status = ST_IDLE|TREQ;
-static int last_status;
-static int driver_running;
-
-/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
+static struct adb_request *current_req; /* first request struct in the queue */
+static struct adb_request *last_req;     /* last request struct in the queue */
+static unsigned char reply_buf[16];        /* storage for autopolled replies */
+static unsigned char *reply_ptr;      /* next byte in req->data or reply_buf */
+static int reading_reply;        /* store reply in reply_buf else req->reply */
+static int data_index;      /* index of the next byte to send from req->data */
+static int reply_len; /* number of bytes received in reply_buf or req->reply */
+static int status;          /* VIA's ADB status bits captured upon interrupt */
+static int last_status;              /* status bits as at previous interrupt */
+static int srq_asserted;     /* have to poll for the device that asserted it */
+static int command_byte;         /* the most recent command byte transmitted */
+static int autopoll_devs;      /* bits set are device addresses to be polled */
+
+/* Sanity check for request queue. Doesn't check for cycles. */
+static int request_is_queued(struct adb_request *req) {
+	struct adb_request *cur;
+	unsigned long flags;
+	local_irq_save(flags);
+	cur = current_req;
+	while (cur) {
+		if (cur == req) {
+			local_irq_restore(flags);
+			return 1;
+		}
+		cur = cur->next;
+	}
+	local_irq_restore(flags);
+	return 0;
+}
 
 /* Check for MacII style ADB */
 static int macii_probe(void)
@@ -147,15 +158,16 @@ int macii_init(void)
 	local_irq_save(flags);
 	
 	err = macii_init_via();
-	if (err) return err;
+	if (err) goto out;
 
 	err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
 			  macii_interrupt);
-	if (err) return err;
+	if (err) goto out;
 
 	macii_state = idle;
+out:
 	local_irq_restore(flags);
-	return 0;
+	return err;
 }
 
 /* initialize the hardware */	
@@ -163,12 +175,12 @@ static int macii_init_via(void)
 {
 	unsigned char x;
 
-	/* Set the lines up. We want TREQ as input TACK|TIP as output */
-	via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+	/* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
+	via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
 
 	/* Set up state: idle */
 	via[B] |= ST_IDLE;
-	last_status = via[B] & (ST_MASK|TREQ);
+	last_status = via[B] & (ST_MASK|CTLR_IRQ);
 
 	/* Shift register on input */
 	via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
@@ -179,81 +191,72 @@ static int macii_init_via(void)
 	return 0;
 }
 
-/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */
+/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
 static void macii_queue_poll(void)
 {
-	static int device = 0;
-	static int in_poll=0;
+	/* No point polling the active device as it will never assert SRQ, so
+	 * poll the next device in the autopoll list. This could leave us
+	 * stuck in a polling loop if an unprobed device is asserting SRQ.
+	 * In theory, that could only happen if a device was plugged in after
+	 * probing started. Unplugging it again will break the cycle.
+	 * (Simply polling the next higher device often ends up polling almost
+	 * every device (after wrapping around), which takes too long.)
+	 */
+	int device_mask;
+	int next_device;
 	static struct adb_request req;
-	unsigned long flags;
-	
-	if (in_poll) printk("macii_queue_poll: double poll!\n");
-
-	in_poll++;
-	if (++device > 15) device = 1;
-
-	adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
-		    ADB_READREG(device, 0));
-
-	local_irq_save(flags);
-
-	req.next = current_req;
-	current_req = &req;
 
-	local_irq_restore(flags);
-	macii_start();
-	in_poll--;
-}
+	if (!autopoll_devs) return;
 
-/* Send an ADB retransmit (Talk, appended to the request queue) */
-static void macii_retransmit(int device)
-{
-	static int in_retransmit = 0;
-	static struct adb_request rt;
-	unsigned long flags;
-	
-	if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
+	device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
+	if (autopoll_devs & ~device_mask)
+		next_device = ffs(autopoll_devs & ~device_mask) - 1;
+	else
+		next_device = ffs(autopoll_devs) - 1;
 
-	in_retransmit++;
+	BUG_ON(request_is_queued(&req));
 
-	adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
-		    ADB_READREG(device, 0));
+	adb_request(&req, NULL, ADBREQ_NOSEND, 1,
+	            ADB_READREG(next_device, 0));
 
-	local_irq_save(flags);
+	req.sent = 0;
+	req.complete = 0;
+	req.reply_len = 0;
+	req.next = current_req;
 
 	if (current_req != NULL) {
-		last_req->next = &rt;
-		last_req = &rt;
+		current_req = &req;
 	} else {
-		current_req = &rt;
-		last_req = &rt;
+		current_req = &req;
+		last_req = &req;
 	}
-
-	if (macii_state == idle) macii_start();
-
-	local_irq_restore(flags);
-	in_retransmit--;
 }
 
 /* Send an ADB request; if sync, poll out the reply 'till it's done */
 static int macii_send_request(struct adb_request *req, int sync)
 {
-	int i;
+	int err;
+	unsigned long flags;
 
-	i = macii_write(req);
-	if (i) return i;
+	BUG_ON(request_is_queued(req));
 
-	if (sync) {
-		while (!req->complete) macii_poll();
+	local_irq_save(flags);
+	err = macii_write(req);
+	local_irq_restore(flags);
+
+	if (!err && sync) {
+		while (!req->complete) {
+			macii_poll();
+		}
+		BUG_ON(request_is_queued(req));
 	}
-	return 0;
+
+	return err;
 }
 
-/* Send an ADB request */
+/* Send an ADB request (append to request queue) */
 static int macii_write(struct adb_request *req)
 {
-	unsigned long flags;
-
 	if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
 		req->complete = 1;
 		return -EINVAL;
@@ -264,8 +267,6 @@ static int macii_write(struct adb_reques
 	req->complete = 0;
 	req->reply_len = 0;
 
-	local_irq_save(flags);
-
 	if (current_req != NULL) {
 		last_req->next = req;
 		last_req = req;
@@ -274,28 +275,52 @@ static int macii_write(struct adb_reques
 		last_req = req;
 		if (macii_state == idle) macii_start();
 	}
-
-	local_irq_restore(flags);
 	return 0;
 }
 
 /* Start auto-polling */
 static int macii_autopoll(int devs)
 {
-	/* Just ping a random default address */
-	if (!(current_req || retry_req))
-		macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3);
-	return 0;
+	static struct adb_request req;
+	unsigned long flags;
+	int err = 0;
+
+	/* bit 1 == device 1, and so on. */
+	autopoll_devs = devs & 0xFFFE;
+
+	if (!autopoll_devs) return 0;
+
+	local_irq_save(flags);
+
+	if (current_req == NULL) {
+		/* Send a Talk Reg 0. The controller will repeatedly transmit
+		 * this as long as it is idle.
+		 */
+		adb_request(&req, NULL, ADBREQ_NOSEND, 1,
+		            ADB_READREG(ffs(autopoll_devs) - 1, 0));
+		err = macii_write(&req);
+	}
+
+	local_irq_restore(flags);
+	return err;
+}
+
+static inline int need_autopoll(void) {
+	/* Was the last command Talk Reg 0
+	 * and is the target on the autopoll list?
+	 */
+	if ((command_byte & 0x0F) == 0x0C &&
+	    ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs))
+		return 0;
+	return 1;
 }
 
 /* Prod the chip without interrupts */
 static void macii_poll(void)
 {
-	unsigned long flags;
-
-	local_irq_save(flags);
-	if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
-	local_irq_restore(flags);
+	disable_irq(IRQ_MAC_ADB);
+	macii_interrupt(0, NULL);
+	enable_irq(IRQ_MAC_ADB);
 }
 
 /* Reset the bus */
@@ -303,73 +328,34 @@ static int macii_reset_bus(void)
 {
 	static struct adb_request req;
 	
+	if (request_is_queued(&req))
+		return 0;
+
 	/* Command = 0, Address = ignored */
 	adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
 
+	/* Don't want any more requests during the Global Reset low time. */
+	udelay(3000);
+
 	return 0;
 }
 
 /* Start sending ADB packet */
 static void macii_start(void)
 {
-	unsigned long flags;
 	struct adb_request *req;
 
 	req = current_req;
-	if (!req) return;
-	
-	/* assert macii_state == idle */
-	if (macii_state != idle) {
-		printk("macii_start: called while driver busy (%p %x %x)!\n",
-			req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
-		return;
-	}
 
-	local_irq_save(flags);
-	
-	/* 
-	 * IRQ signaled ?? (means ADB controller wants to send, or might 
-	 * be end of packet if we were reading)
-	 */
-#if 0 /* FIXME: This is broke broke broke, for some reason */
-	if ((via[B] & TREQ) == 0) {
-		printk("macii_start: weird poll stuff. huh?\n");
-		/*
-		 *	FIXME - we need to restart this on a timer
-		 *	or a collision at boot hangs us.
-		 *	Never set macii_state to idle here, or macii_start 
-		 *	won't be called again from send_request!
-		 *	(need to re-check other cases ...)
-		 */
-		/*
-		 * if the interrupt handler set the need_poll
-		 * flag, it's hopefully a SRQ poll or re-Talk
-		 * so we try to send here anyway
-		 */
-		if (!need_poll) {
-			if (console_loglevel == 10)
-				printk("macii_start: device busy - retry %p state %d status %x!\n", 
-					req, macii_state,
-					(uint) via[B] & (ST_MASK|TREQ));
-			retry_req = req;
-			/* set ADB status here ? */
-			local_irq_restore(flags);
-			return;
-		} else {
-			need_poll = 0;
-		}
-	}
-#endif
-	/*
-	 * Another retry pending? (sanity check)
+	BUG_ON(req == NULL);
+
+	BUG_ON(macii_state != idle);
+
+	/* Now send it. Be careful though, that first byte of the request
+	 * is actually ADB_PACKET; the real data begins at index 1!
+	 * And req->nbytes is the number of bytes of real data plus one.
 	 */
-	if (retry_req) {
-		retry_req = NULL;
-	}
 
-	/* Now send it. Be careful though, that first byte of the request */
-	/* is actually ADB_PACKET; the real data begins at index 1!	  */
-	
 	/* store command byte */
 	command_byte = req->data[1];
 	/* Output mode */
@@ -381,115 +367,97 @@ #endif
 
 	macii_state = sending;
 	data_index = 2;
-
-	local_irq_restore(flags);
 }
 
 /*
- * The notorious ADB interrupt handler - does all of the protocol handling, 
- * except for starting new send operations. Relies heavily on the ADB 
- * controller sending and receiving data, thereby generating SR interrupts
- * for us. This means there has to be always activity on the ADB bus, otherwise
- * the whole process dies and has to be re-kicked by sending TALK requests ...
- * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
- * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
- * a good choice; either on timeout or on a timer interrupt).
+ * The notorious ADB interrupt handler - does all of the protocol handling.
+ * Relies on the ADB controller sending and receiving data, thereby
+ * generating shift register interrupts (SR_INT) for us. This means there has
+ * to be activity on the ADB bus. The chip will poll to achieve this.
  *
  * The basic ADB state machine was left unchanged from the original MacII code
  * by Alan Cox, which was based on the CUDA driver for PowerMac. 
- * The syntax of the ADB status lines seems to be totally different on MacII, 
- * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
- * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start 
- * and end of a receive packet are signaled by asserting /IRQ on the interrupt
- * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on 
- * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the 
- * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB 
- * protocol with a logic analyzer!!)
- *
- * Note: As of 21/10/97, the MacII ADB part works including timeout detection
- * and retransmit (Talk to the last active device).
+ * The syntax of the ADB status lines is totally different on MacII,
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
+ * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
+ * Start and end of a receive packet are signalled by asserting /IRQ on the
+ * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused
+ * with the VIA shift register interrupt. /IRQ never actually interrupts the
+ * processor, it's just an ordinary input.)
  */
 static irqreturn_t macii_interrupt(int irq, void *arg)
 {
-	int x, adbdir;
-	unsigned long flags;
+	int x;
+	static int entered;
 	struct adb_request *req;
 
-	last_status = status;
-
-	/* prevent races due to SCSI enabling ints */
-	local_irq_save(flags);
-
-	if (driver_running) {
-		local_irq_restore(flags);
-		return IRQ_NONE;
+	if (!arg) {
+		/* Clear the SR IRQ flag when polling. */
+		if (via[IFR] & SR_INT)
+			via[IFR] = SR_INT;
+		else
+			return IRQ_NONE;
 	}
 
-	driver_running = 1;
-	
-	status = via[B] & (ST_MASK|TREQ);
-	adbdir = via[ACR] & SR_OUT;
+	BUG_ON(entered++);
+
+	last_status = status;
+	status = via[B] & (ST_MASK|CTLR_IRQ);
 
 	switch (macii_state) {
 		case idle:
+			if (reading_reply) {
+				reply_ptr = current_req->reply;
+			} else {
+				BUG_ON(current_req != NULL);
+				reply_ptr = reply_buf;
+			}
+
 			x = via[SR];
-			first_byte = x;
-			/* set ADB state = even for first data byte */
-			via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
 
-			reply_buf[0] = first_byte; /* was command_byte?? */
-			reply_ptr = reply_buf + 1;
-			reply_len = 1;
-			prefix_len = 1;
-			reading_reply = 0;
-			
-			macii_state = reading;
-			break;
+			if ((status & CTLR_IRQ) && (x == 0xFF)) {
+				/* Bus timeout without SRQ sequence:
+				 *     data is "FF" while CTLR_IRQ is "H"
+				 */
+				reply_len = 0;
+				srq_asserted = 0;
+				macii_state = read_done;
+			} else {
+				macii_state = reading;
+				*reply_ptr = x;
+				reply_len = 1;
+			}
 
-		case awaiting_reply:
-			/* handshake etc. for II ?? */
-			x = via[SR];
-			first_byte = x;
 			/* set ADB state = even for first data byte */
 			via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
-
-			current_req->reply[0] = first_byte;
-			reply_ptr = current_req->reply + 1;
-			reply_len = 1;
-			prefix_len = 1;
-			reading_reply = 1;
-
-			macii_state = reading;			
 			break;
 
 		case sending:
 			req = current_req;
 			if (data_index >= req->nbytes) {
-				/* print an error message if a listen command has no data */
-				if (((command_byte & 0x0C) == 0x08)
-				 /* && (console_loglevel == 10) */
-				    && (data_index == 2))
-					printk("MacII ADB: listen command with no data: %x!\n", 
-						command_byte);
-				/* reset to shift in */
-				via[ACR] &= ~SR_OUT;
-				x = via[SR];
-				/* set ADB state idle - might get SRQ */
-				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
-
 				req->sent = 1;
+				macii_state = idle;
 
 				if (req->reply_expected) {
-					macii_state = awaiting_reply;
+					reading_reply = 1;
 				} else {
 					req->complete = 1;
 					current_req = req->next;
 					if (req->done) (*req->done)(req);
-					macii_state = idle;
-					if (current_req || retry_req)
+
+					if (current_req)
 						macii_start();
 					else
-						macii_retransmit((command_byte & 0xF0) >> 4);
+						if (need_autopoll())
+							macii_autopoll(autopoll_devs);
+				}
+
+				if (macii_state == idle) {
+					/* reset to shift in */
+					via[ACR] &= ~SR_OUT;
+					x = via[SR];
+					/* set ADB state idle - might get SRQ */
+					via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
 				}
 			} else {
 				via[SR] = req->data[data_index++];
@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int i
 			break;
 
 		case reading:
+			x = via[SR];
+			BUG_ON((status & ST_MASK) == ST_CMD ||
+			       (status & ST_MASK) == ST_IDLE);
+
+			/* Bus timeout with SRQ sequence:
+			 *     data is "XX FF"      while CTLR_IRQ is "L L"
+			 * End of packet without SRQ sequence:
+			 *     data is "XX...YY 00" while CTLR_IRQ is "L...H L"
+			 * End of packet SRQ sequence:
+			 *     data is "XX...YY 00" while CTLR_IRQ is "L...L L"
+			 * (where XX is the first response byte and
+			 * YY is the last byte of valid response data.)
+			 */
 
-			/* timeout / SRQ handling for II hw */
-			if( (first_byte == 0xFF && (reply_len-prefix_len)==2 
-			     && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || 
-			    ((reply_len-prefix_len)==3 
-			     && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
-			{
-				/*
-				 * possible timeout (in fact, most probably a 
-				 * timeout, since SRQ can't be signaled without
-				 * transfer on the bus).
-				 * The last three bytes seen were FF, together 
-				 * with the starting byte (in case we started
-				 * on 'idle' or 'awaiting_reply') this probably
-				 * makes four. So this is mostl likely #5!
-				 * The timeout signal is a pattern 1 0 1 0 0..
-				 * on /INT, meaning we missed it :-(
-				 */
-				x = via[SR];
-				if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n");
-
-				if ((status & TREQ) == (last_status & TREQ)) {
-					/* Not a timeout. Unsolicited SRQ? weird. */
-					/* Terminate the SRQ packet and poll */
-					need_poll = 1;
+			srq_asserted = 0;
+			if (!(status & CTLR_IRQ)) {
+				if (x == 0xFF) {
+					if (!(last_status & CTLR_IRQ)) {
+						macii_state = read_done;
+						reply_len = 0;
+						srq_asserted = 1;
+					}
+				} else if (x == 0x00) {
+					macii_state = read_done;
+					if (!(last_status & CTLR_IRQ))
+						srq_asserted = 1;
 				}
-				/* There's no packet to get, so reply is blank */
-				via[B] ^= ST_MASK;
-				reply_ptr -= (reply_len-prefix_len);
-				reply_len = prefix_len;
-				macii_state = read_done;
-				break;
-			} /* end timeout / SRQ handling for II hw. */
-
-			if((reply_len-prefix_len)>3
-				&& memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
-			{
-				/* SRQ tacked on data packet */
-				/* Terminate the packet (SRQ never ends) */
-				x = via[SR];
-				macii_state = read_done;
-				reply_len -= 3;
-				reply_ptr -= 3;
-				need_poll = 1;
-				/* need to continue; next byte not seen else */
-			} else {
-				/* Sanity check */
-				if (reply_len > 15) reply_len = 0;
-				/* read byte */
-				x = via[SR];
-				*reply_ptr = x;
+			}
+
+			if (macii_state == reading) {
+				BUG_ON(reply_len > 15);
 				reply_ptr++;
+				*reply_ptr = x;
 				reply_len++;
 			}
-			/* The usual handshake ... */
-
-			/*
-			 * NetBSD hints that the next to last byte 
-			 * is sent with IRQ !! 
-			 * Guido found out it's the last one (0x0),
-			 * but IRQ should be asserted already.
-			 * Problem with timeout detection: First
-			 * transition to /IRQ might be second 
-			 * byte of timeout packet! 
-			 * Timeouts are signaled by 4x FF.
-			 */
-			if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */
-				/* invert state bits, toggle ODD/EVEN */
-				via[B] ^= ST_MASK;
 
-				/* adjust packet length */
-				reply_len--;
-				reply_ptr--;
-				macii_state = read_done;
-			} else {
-				/* not caught: ST_CMD */
-				/* required for re-entry 'reading'! */
-				if ((status & ST_MASK) == ST_IDLE) {
-					/* (in)sanity check - set even */
-					via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
-				} else {
-					/* invert state bits */
-					via[B] ^= ST_MASK;
-				}
-			}
+			/* invert state bits, toggle ODD/EVEN */
+			via[B] ^= ST_MASK;
 			break;
 
 		case read_done:
 			x = via[SR];
+
 			if (reading_reply) {
+				reading_reply = 0;
 				req = current_req;
-				req->reply_len = reply_ptr - req->reply;
+				req->reply_len = reply_len;
 				req->complete = 1;
 				current_req = req->next;
 				if (req->done) (*req->done)(req);
-			} else {
-				adb_input(reply_buf, reply_ptr - reply_buf, 0);
-			}
+			} else if (reply_len && autopoll_devs)
+				adb_input(reply_buf, reply_len, 0);
 
-			/*
-			 * remember this device ID; it's the latest we got a 
-			 * reply from!
-			 */
-			last_reply = command_byte;
-			last_active = (command_byte & 0xF0) >> 4;
+			macii_state = idle;
 
 			/* SRQ seen before, initiate poll now */
-			if (need_poll) {
-				macii_state = idle;
+			if (srq_asserted)
 				macii_queue_poll();
-				need_poll = 0;
-				break;
-			}
-			
-			/* set ADB state to idle */
-			via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
-			
-			/* /IRQ seen, so the ADB controller has data for us */
-			if ((via[B] & TREQ) != 0) {
-				macii_state = reading;
 
-				reply_buf[0] = command_byte;
-				reply_ptr = reply_buf + 1;
-				reply_len = 1;
-				prefix_len = 1;
-				reading_reply = 0;
-			} else {
-				/* no IRQ, send next packet or wait */
-				macii_state = idle;
-				if (current_req)
-					macii_start();
-				else
-					macii_retransmit(last_active);
-			}
+			if (current_req)
+				macii_start();
+			else
+				if (need_autopoll())
+					macii_autopoll(autopoll_devs);
+
+			if (macii_state == idle)
+				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
 			break;
 
 		default:
 		break;
 	}
-	/* reset mutex and interrupts */
-	driver_running = 0;
-	local_irq_restore(flags);
+
+	entered--;
 	return IRQ_HANDLED;
 }
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
index 179af10..55ad956 100644
--- a/drivers/macintosh/via-pmu-led.c
+++ b/drivers/macintosh/via-pmu-led.c
@@ -31,7 +31,6 @@ static spinlock_t pmu_blink_lock;
 static struct adb_request pmu_blink_req;
 /* -1: no change, 0: request off, 1: request on */
 static int requested_change;
-static int sleeping;
 
 static void pmu_req_done(struct adb_request * req)
 {
@@ -41,7 +40,7 @@ static void pmu_req_done(struct adb_requ
 	/* if someone requested a change in the meantime
 	 * (we only see the last one which is fine)
 	 * then apply it now */
-	if (requested_change != -1 && !sleeping)
+	if (requested_change != -1 && !pmu_sys_suspended)
 		pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
 	/* reset requested change */
 	requested_change = -1;
@@ -66,7 +65,7 @@ static void pmu_led_set(struct led_class
 		break;
 	}
 	/* if request isn't done, then don't do anything */
-	if (pmu_blink_req.complete && !sleeping)
+	if (pmu_blink_req.complete && !pmu_sys_suspended)
 		pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
  out:
  	spin_unlock_irqrestore(&pmu_blink_lock, flags);
@@ -80,34 +79,6 @@ #endif
 	.brightness_set = pmu_led_set,
 };
 
-#ifdef CONFIG_PM
-static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pmu_blink_lock, flags);
-
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		sleeping = 1;
-		break;
-	case PBOOK_WAKE:
-		sleeping = 0;
-		break;
-	default:
-		/* do nothing */
-		break;
-	}
-	spin_unlock_irqrestore(&pmu_blink_lock, flags);
-
-	return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
-	.notifier_call = pmu_led_sleep_call,
-};
-#endif
-
 static int __init via_pmu_led_init(void)
 {
 	struct device_node *dt;
@@ -120,11 +91,13 @@ static int __init via_pmu_led_init(void)
 	dt = of_find_node_by_path("/");
 	if (dt == NULL)
 		return -ENODEV;
-	model = get_property(dt, "model", NULL);
+	model = of_get_property(dt, "model", NULL);
 	if (model == NULL)
 		return -ENODEV;
 	if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
-	    strncmp(model, "iBook", strlen("iBook")) != 0) {
+	    strncmp(model, "iBook", strlen("iBook")) != 0 &&
+	    strcmp(model, "PowerMac7,2") != 0 &&
+	    strcmp(model, "PowerMac7,3") != 0) {
 		of_node_put(dt);
 		/* ignore */
 		return -ENODEV;
@@ -135,9 +108,7 @@ static int __init via_pmu_led_init(void)
 	/* no outstanding req */
 	pmu_blink_req.complete = 1;
 	pmu_blink_req.done = pmu_req_done;
-#ifdef CONFIG_PM
-	pmu_register_sleep_notifier(&via_pmu_led_sleep_notif);
-#endif
+
 	return led_classdev_register(NULL, &pmu_led);
 }
 
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b6073bd..157080b 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -289,7 +289,7 @@ int __init find_via_pmu(void)
 	if (vias == NULL)
 		return 0;
 
-	reg = get_property(vias, "reg", NULL);
+	reg = of_get_property(vias, "reg", NULL);
 	if (reg == NULL) {
 		printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
 		goto fail;
@@ -310,19 +310,22 @@ int __init find_via_pmu(void)
 			PMU_INT_TICK;
 	
 	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
-	    || device_is_compatible(vias->parent, "ohare")))
+	    || of_device_is_compatible(vias->parent, "ohare")))
 		pmu_kind = PMU_OHARE_BASED;
-	else if (device_is_compatible(vias->parent, "paddington"))
+	else if (of_device_is_compatible(vias->parent, "paddington"))
 		pmu_kind = PMU_PADDINGTON_BASED;
-	else if (device_is_compatible(vias->parent, "heathrow"))
+	else if (of_device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
-	else if (device_is_compatible(vias->parent, "Keylargo")
-		 || device_is_compatible(vias->parent, "K2-Keylargo")) {
+	else if (of_device_is_compatible(vias->parent, "Keylargo")
+		 || of_device_is_compatible(vias->parent, "K2-Keylargo")) {
 		struct device_node *gpiop;
+		struct device_node *adbp;
 		u64 gaddr = OF_BAD_ADDR;
 
 		pmu_kind = PMU_KEYLARGO_BASED;
-		pmu_has_adb = (find_type_devices("adb") != NULL);
+		adbp = of_find_node_by_type(NULL, "adb");
+		pmu_has_adb = (adbp != NULL);
+		of_node_put(adbp);
 		pmu_intr_mask =	PMU_INT_PCEJECT |
 				PMU_INT_SNDBRT |
 				PMU_INT_ADB |
@@ -331,7 +334,7 @@ int __init find_via_pmu(void)
 		
 		gpiop = of_find_node_by_name(NULL, "gpio");
 		if (gpiop) {
-			reg = get_property(gpiop, "reg", NULL);
+			reg = of_get_property(gpiop, "reg", NULL);
 			if (reg)
 				gaddr = of_translate_address(gpiop, reg);
 			if (gaddr != OF_BAD_ADDR)
@@ -484,10 +487,11 @@ #ifdef CONFIG_PPC32
 		pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
 		pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
 	} else {
-		struct device_node* prim = find_devices("power-mgt");
+		struct device_node* prim =
+			of_find_node_by_name(NULL, "power-mgt");
 		const u32 *prim_info = NULL;
 		if (prim)
-			prim_info = get_property(prim, "prim-info", NULL);
+			prim_info = of_get_property(prim, "prim-info", NULL);
 		if (prim_info) {
 			/* Other stuffs here yet unknown */
 			pmu_battery_count = (prim_info[6] >> 16) & 0xff;
@@ -495,6 +499,7 @@ #ifdef CONFIG_PPC32
 			if (pmu_battery_count > 1)
 				pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
 		}
+		of_node_put(prim);
 	}
 #endif /* CONFIG_PPC32 */
 
@@ -1769,35 +1774,21 @@ #endif /* CONFIG_PM */
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 
 /* Sleep is broadcast last-to-first */
-static int
-broadcast_sleep(int when, int fallback)
+static void broadcast_sleep(int when)
 {
-	int ret = PBOOK_SLEEP_OK;
 	struct list_head *list;
 	struct pmu_sleep_notifier *notifier;
 
 	for (list = sleep_notifiers.prev; list != &sleep_notifiers;
 	     list = list->prev) {
 		notifier = list_entry(list, struct pmu_sleep_notifier, list);
-		ret = notifier->notifier_call(notifier, when);
-		if (ret != PBOOK_SLEEP_OK) {
-			printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
-			       when, notifier, notifier->notifier_call);
-			for (; list != &sleep_notifiers; list = list->next) {
-				notifier = list_entry(list, struct pmu_sleep_notifier, list);
-				notifier->notifier_call(notifier, fallback);
-			}
-			return ret;
-		}
+		notifier->notifier_call(notifier, when);
 	}
-	return ret;
 }
 
 /* Wake is broadcast first-to-last */
-static int
-broadcast_wake(void)
+static void broadcast_wake(void)
 {
-	int ret = PBOOK_SLEEP_OK;
 	struct list_head *list;
 	struct pmu_sleep_notifier *notifier;
 
@@ -1806,7 +1797,6 @@ broadcast_wake(void)
 		notifier = list_entry(list, struct pmu_sleep_notifier, list);
 		notifier->notifier_call(notifier, PBOOK_WAKE);
 	}
-	return ret;
 }
 
 /*
@@ -2013,12 +2003,8 @@ pmac_suspend_devices(void)
 
 	pm_prepare_console();
 	
-	/* Notify old-style device drivers & userland */
-	ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
-	if (ret != PBOOK_SLEEP_OK) {
-		printk(KERN_ERR "Sleep rejected by drivers\n");
-		return -EBUSY;
-	}
+	/* Notify old-style device drivers */
+	broadcast_sleep(PBOOK_SLEEP_REQUEST);
 
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
@@ -2028,12 +2014,7 @@ pmac_suspend_devices(void)
 	 */
 	sys_sync();
 
-	/* Sleep can fail now. May not be very robust but useful for debugging */
-	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
-	if (ret != PBOOK_SLEEP_OK) {
-		printk(KERN_ERR "Driver sleep failed\n");
-		return -EBUSY;
-	}
+	broadcast_sleep(PBOOK_SLEEP_NOW);
 
 	/* Send suspend call to devices, hold the device core's dpm_sem */
 	ret = device_suspend(PMSG_SUSPEND);
@@ -2154,7 +2135,7 @@ static int powerbook_sleep_grackle(void)
 	int ret;
 	struct pci_dev *grackle;
 
-	grackle = pci_find_slot(0, 0);
+	grackle = pci_get_bus_and_slot(0, 0);
 	if (!grackle)
 		return -ENODEV;
 
@@ -2202,6 +2183,8 @@ static int powerbook_sleep_grackle(void)
 	pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); 
 	pci_write_config_word(grackle, 0x70, pmcr1);
 
+	pci_dev_put(grackle);
+
 	/* Make sure the PMU is idle */
 	pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
 	restore_via_state();
@@ -2776,7 +2759,7 @@ #endif /* DEBUG_SLEEP */
 
 #if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 
-static int pmu_sys_suspended;
+int pmu_sys_suspended;
 
 static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
 {
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index 356c721..dfdf11c 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -111,7 +111,6 @@ static int pmu_send_request(struct adb_r
 static int pmu_autopoll(int devs);
 void pmu_poll(void);
 static int pmu_reset_bus(void);
-static int pmu_queue_request(struct adb_request *req);
 
 static void pmu_start(void);
 static void send_byte(int x);
@@ -475,7 +474,7 @@ pmu_request(struct adb_request *req, voi
 	return pmu_queue_request(req);
 }
 
-static int 
+int
 pmu_queue_request(struct adb_request *req)
 {
 	unsigned long flags;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 94c117e..192b26e 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -27,7 +27,6 @@ #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>
 #include <linux/reboot.h>
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 3f7967f..a0fabf3 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -176,7 +176,7 @@ static int wf_lm75_attach(struct i2c_ada
 	for (dev = NULL;
 	     (dev = of_get_next_child(busnode, dev)) != NULL;) {
 		const char *loc =
-			get_property(dev, "hwsensor-location", NULL);
+			of_get_property(dev, "hwsensor-location", NULL);
 		u8 addr;
 
 		/* We must re-match the adapter in order to properly check
@@ -188,10 +188,10 @@ static int wf_lm75_attach(struct i2c_ada
 		if (loc == NULL || addr == 0)
 			continue;
 		/* real lm75 */
-		if (device_is_compatible(dev, "lm75"))
+		if (of_device_is_compatible(dev, "lm75"))
 			wf_lm75_create(adapter, addr, 0, loc);
 		/* ds1775 (compatible, better resolution */
-		else if (device_is_compatible(dev, "ds1775"))
+		else if (of_device_is_compatible(dev, "ds1775"))
 			wf_lm75_create(adapter, addr, 1, loc);
 	}
 	return 0;
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index eae1189..5f03aab 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -131,10 +131,10 @@ static int wf_max6690_attach(struct i2c_
 		 */
 		if (!pmac_i2c_match_adapter(dev, adapter))
 			continue;
-		if (!device_is_compatible(dev, "max6690"))
+		if (!of_device_is_compatible(dev, "max6690"))
 			continue;
 		addr = pmac_i2c_get_dev_addr(dev);
-		loc = get_property(dev, "hwsensor-location", NULL);
+		loc = of_get_property(dev, "hwsensor-location", NULL);
 		if (loc == NULL || addr == 0)
 			continue;
 		printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 31b750d..58c2590 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -167,7 +167,7 @@ static struct smu_fan_control *smu_fan_c
 	if (fct == NULL)
 		return NULL;
 	fct->ctrl.ops = &smu_fan_ops;
-	l = get_property(node, "location", NULL);
+	l = of_get_property(node, "location", NULL);
 	if (l == NULL)
 		goto fail;
 
@@ -224,17 +224,17 @@ static struct smu_fan_control *smu_fan_c
 		goto fail;
 
 	/* Get min & max values*/
-	v = get_property(node, "min-value", NULL);
+	v = of_get_property(node, "min-value", NULL);
 	if (v == NULL)
 		goto fail;
 	fct->min = *v;
-	v = get_property(node, "max-value", NULL);
+	v = of_get_property(node, "max-value", NULL);
 	if (v == NULL)
 		goto fail;
 	fct->max = *v;
 
 	/* Get "reg" value */
-	reg = get_property(node, "reg", NULL);
+	reg = of_get_property(node, "reg", NULL);
 	if (reg == NULL)
 		goto fail;
 	fct->reg = *reg;
@@ -263,7 +263,7 @@ static int __init smu_controls_init(void
 	/* Look for RPM fans */
 	for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
 		if (!strcmp(fans->name, "rpm-fans") ||
-		    device_is_compatible(fans, "smu-rpm-fans"))
+		    of_device_is_compatible(fans, "smu-rpm-fans"))
 			break;
 	for (fan = NULL;
 	     fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 83f79de..1043b39 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -241,7 +241,7 @@ static void wf_sat_create(struct i2c_ada
 	char *name;
 	int vsens[2], isens[2];
 
-	reg = get_property(dev, "reg", NULL);
+	reg = of_get_property(dev, "reg", NULL);
 	if (reg == NULL)
 		return;
 	addr = *reg;
@@ -268,9 +268,9 @@ 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 = get_property(child, "reg", NULL);
-		type = get_property(child, "device_type", NULL);
-		loc = get_property(child, "location", NULL);
+		reg = of_get_property(child, "reg", NULL);
+		type = of_get_property(child, "device_type", NULL);
+		loc = of_get_property(child, "location", NULL);
 		if (reg == NULL || loc == NULL)
 			continue;
 
@@ -380,7 +380,7 @@ static int wf_sat_attach(struct i2c_adap
 	busnode = pmac_i2c_get_bus_node(bus);
 
 	while ((dev = of_get_next_child(busnode, dev)) != NULL)
-		if (device_is_compatible(dev, "smu-sat"))
+		if (of_device_is_compatible(dev, "smu-sat"))
 			wf_sat_create(adapter, dev);
 	return 0;
 }
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 01b4c50..9c567b9 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -204,8 +204,8 @@ static struct smu_ad_sensor *smu_ads_cre
 	ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
 	if (ads == NULL)
 		return NULL;
-	c = get_property(node, "device_type", NULL);
-	l = get_property(node, "location", NULL);
+	c = of_get_property(node, "device_type", NULL);
+	l = of_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 = get_property(node, "reg", NULL);
+	v = of_get_property(node, "reg", NULL);
 	if (v == NULL)
 		goto fail;
 	ads->reg = *v;
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index e61e0ef..5a4a74c 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1456,10 +1456,10 @@ int bitmap_create(mddev_t *mddev)
 	bitmap->offset = mddev->bitmap_offset;
 	if (file) {
 		get_file(file);
-		do_sync_file_range(file, 0, LLONG_MAX,
-				   SYNC_FILE_RANGE_WAIT_BEFORE |
-				   SYNC_FILE_RANGE_WRITE |
-				   SYNC_FILE_RANGE_WAIT_AFTER);
+		do_sync_mapping_range(file->f_mapping, 0, LLONG_MAX,
+				      SYNC_FILE_RANGE_WAIT_BEFORE |
+				      SYNC_FILE_RANGE_WRITE |
+				      SYNC_FILE_RANGE_WAIT_AFTER);
 	}
 	/* read superblock from bitmap file (this sets bitmap->chunksize) */
 	err = bitmap_read_sb(bitmap);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 4c2471e..d812123 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -867,7 +867,7 @@ static int crypt_ctr(struct dm_target *t
 		goto bad4;
 	}
 
-	cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4);
+	cc->bs = bioset_create(MIN_IOS, MIN_IOS);
 	if (!cc->bs) {
 		ti->error = "Cannot allocate crypt bioset";
 		goto bad_bs;
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 4eb73d3..8bdc8a8 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -60,7 +60,7 @@ static int resize_pool(unsigned int new_
 		if (!_io_pool)
 			return -ENOMEM;
 
-		_bios = bioset_create(16, 16, 4);
+		_bios = bioset_create(16, 16);
 		if (!_bios) {
 			mempool_destroy(_io_pool);
 			_io_pool = NULL;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 3668b17..11a98df 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1012,7 +1012,7 @@ static struct mapped_device *alloc_dev(i
 	if (!md->tio_pool)
 		goto bad3;
 
-	md->bs = bioset_create(16, 16, 4);
+	md->bs = bioset_create(16, 16);
 	if (!md->bs)
 		goto bad_no_bioset;
 
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 509171c..2b4315d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3080,7 +3080,7 @@ #endif
 		if (test_bit(Faulty, &rdev->flags))
 			continue;
 		sync_blockdev(rdev->bdev);
-		invalidate_bdev(rdev->bdev, 0);
+		invalidate_bdev(rdev->bdev);
 	}
 
 	md_probe(mddev->unit, NULL, NULL);
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 03b47a2..cbd1184 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -667,7 +667,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR
 	[ 0x1f ] = KEY_L,
 	[ 0x2b ] = KEY_I,
 
-	[ 0x2d ] = KEY_ZOOM,
+	[ 0x2d ] = KEY_SCREEN,
 	[ 0x1e ] = KEY_ZOOM,
 	[ 0x1b ] = KEY_VOLUMEUP,
 	[ 0x0f ] = KEY_VOLUMEDOWN,
@@ -682,12 +682,12 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR
 
 	[ 0x3f ] = KEY_UP,
 	[ 0x3e ] = KEY_DOWN,
-	[ 0x1a ] = KEY_PAUSE,
+	[ 0x1a ] = KEY_ENTER,
 
 	[ 0x1d ] = KEY_MENU,
-	[ 0x19 ] = KEY_PLAY,
-	[ 0x16 ] = KEY_REWIND,
-	[ 0x13 ] = KEY_FORWARD,
+	[ 0x19 ] = KEY_AGAIN,
+	[ 0x16 ] = KEY_PREVIOUSSONG,
+	[ 0x13 ] = KEY_NEXTSONG,
 	[ 0x15 ] = KEY_PAUSE,
 	[ 0x0e ] = KEY_REWIND,
 	[ 0x0d ] = KEY_PLAY,
@@ -1739,7 +1739,7 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_
 
 EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
 
-/* for the Technotrend 1500 bundled remote: */
+/* for the Technotrend 1500 bundled remotes (grey and black): */
 IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
 	[ 0x01 ] = KEY_POWER,
 	[ 0x02 ] = KEY_SHUFFLE,	/* ? double-arrow key */
@@ -1774,6 +1774,12 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTA
 	[ 0x25 ] = KEY_VOLUMEUP,
 	[ 0x26 ] = KEY_VOLUMEDOWN,
 	[ 0x27 ] = KEY_SETUP,
+	[ 0x3a ] = KEY_RECORD, /* these keys are only in the black remote */
+	[ 0x3b ] = KEY_PLAY,
+	[ 0x3c ] = KEY_STOP,
+	[ 0x3d ] = KEY_REWIND,
+	[ 0x3e ] = KEY_PAUSE,
+	[ 0x3f ] = KEY_FORWARD,
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 7e0cedc..e3d04a4 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1428,6 +1428,7 @@ static void video_close(struct saa7146_d
 {
 	struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
 	struct saa7146_vv *vv = dev->vv_data;
+	struct videobuf_queue *q = &fh->video_q;
 	int err;
 
 	if (IS_CAPTURE_ACTIVE(fh) != 0) {
@@ -1436,6 +1437,11 @@ static void video_close(struct saa7146_d
 		err = saa7146_stop_preview(fh);
 	}
 
+	// release all capture buffers
+	mutex_lock(&q->lock);
+	videobuf_read_stop(q);
+	mutex_unlock(&q->lock);
+
 	/* hmm, why is this function declared void? */
 	/* return err */
 }
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 7987595..a0dcd59 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,7 +9,6 @@ config DVB_B2C2_FLEXCOP
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_BCM3510 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_LGH06XF 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 752cf79..b02c2fd 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -14,7 +14,6 @@ #include "bcm3510.h"
 #include "stv0297.h"
 #include "mt312.h"
 #include "lgdt330x.h"
-#include "lgh06xf.h"
 #include "dvb-pll.h"
 
 /* lnb control */
@@ -507,7 +506,7 @@ int flexcop_frontend_init(struct flexcop
 	/* try the air atsc 3nd generation (lgdt3303) */
 	if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC3;
-		dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap);
+		dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
 		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 */
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 5347a40..02a0ea6 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -183,7 +183,8 @@ int flexcop_i2c_init(struct flexcop_devi
 	mutex_init(&fc->i2c_mutex);
 
 	memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
-	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
+	strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",
+		sizeof(fc->i2c_adap.name));
 
 	i2c_set_adapdata(&fc->i2c_adap,fc);
 
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 6e16680..01af4d2 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -127,10 +127,11 @@ static irqreturn_t flexcop_pci_isr(int i
 {
 	struct flexcop_pci *fc_pci = dev_id;
 	struct flexcop_device *fc = fc_pci->fc_dev;
+	unsigned long flags;
 	flexcop_ibi_value v;
 	irqreturn_t ret = IRQ_HANDLED;
 
-	spin_lock_irq(&fc_pci->irq_lock);
+	spin_lock_irqsave(&fc_pci->irq_lock,flags);
 
 	v = fc->read_ibi_reg(fc,irq_20c);
 
@@ -194,7 +195,7 @@ static irqreturn_t flexcop_pci_isr(int i
 		ret = IRQ_NONE;
 	}
 
-	spin_unlock_irq(&fc_pci->irq_lock);
+	spin_unlock_irqrestore(&fc_pci->irq_lock,flags);
 
 	return ret;
 }
@@ -293,12 +294,12 @@ static int flexcop_pci_init(struct flexc
 	}
 
 	pci_set_drvdata(fc_pci->pdev, fc_pci);
-
+	spin_lock_init(&fc_pci->irq_lock);
 	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
 					IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
 		goto err_pci_iounmap;
 
-	spin_lock_init(&fc_pci->irq_lock);
+
 
 	fc_pci->init_state |= FC_PCI_INIT;
 	return ret;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index dd66b60..cfd6fb7 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,7 +7,7 @@ config DVB_BT8XX
 	select DVB_CX24110 if !DVB_FE_CUSTOMISE
 	select DVB_OR51211 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
+	select DVB_PLL
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 83b090e..df72b4b 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -393,9 +393,7 @@ static struct cards card_list[] __devini
 	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,		"Ultraview DVB-T Lite" },
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
 	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
-	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" },
-
-	{ 0, -1, NULL }
+	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" }
 };
 
 
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 3bf084f..87623d2 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -22,7 +22,6 @@
 #ifndef DST_COMMON_H
 #define DST_COMMON_H
 
-#include <linux/smp_lock.h>
 #include <linux/dvb/frontend.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 58f69f6..4f1c09b 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -610,7 +610,8 @@ static void frontend_init(struct dvb_bt8
 		lgdt330x_reset(card);
 		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
 		if (card->fe != NULL) {
-			dvb_attach(lgh06xf_attach, card->fe, card->i2c_adapter);
+			dvb_attach(dvb_pll_attach, card->fe, 0x61,
+				   card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
 		}
 		break;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index e75f417..436880e 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -37,8 +37,8 @@ #include "nxt6000.h"
 #include "cx24110.h"
 #include "or51211.h"
 #include "lgdt330x.h"
-#include "lgh06xf.h"
 #include "zl10353.h"
+#include "dvb-pll.h"
 
 struct dvb_bt8xx_card {
 	struct mutex lock;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index a6cbbdd..34d7abc 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -26,11 +26,11 @@ #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
-#include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/dvb/frontend.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
+#include <asm/io.h>
 
 #include "dmxdev.h"
 #include "dvb_demux.h"
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index a5c0e1a..275df65 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -132,6 +132,11 @@ static int dvb_dvr_open(struct inode *in
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
 
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
+
 	if ((file->f_flags & O_ACCMODE) == O_RDWR) {
 		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
 			mutex_unlock(&dmxdev->mutex);
@@ -171,6 +176,7 @@ static int dvb_dvr_open(struct inode *in
 		dmxdev->demux->disconnect_frontend(dmxdev->demux);
 		dmxdev->demux->connect_frontend(dmxdev->demux, front);
 	}
+	dvbdev->users++;
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
@@ -198,7 +204,16 @@ static int dvb_dvr_release(struct inode 
 			vfree(mem);
 		}
 	}
-	mutex_unlock(&dmxdev->mutex);
+	/* TODO */
+	dvbdev->users--;
+	if(dvbdev->users==-1 && dmxdev->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		mutex_unlock(&dmxdev->mutex);
+		wake_up(&dvbdev->wait_queue);
+	} else
+		mutex_unlock(&dmxdev->mutex);
+
 	return 0;
 }
 
@@ -215,6 +230,11 @@ static ssize_t dvb_dvr_write(struct file
 		return -EINVAL;
 	if (mutex_lock_interruptible(&dmxdev->mutex))
 		return -ERESTARTSYS;
+
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
 	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
 	mutex_unlock(&dmxdev->mutex);
 	return ret;
@@ -227,6 +247,11 @@ static ssize_t dvb_dvr_read(struct file 
 	struct dmxdev *dmxdev = dvbdev->priv;
 	int ret;
 
+	if (dmxdev->exit) {
+		mutex_unlock(&dmxdev->mutex);
+		return -ENODEV;
+	}
+
 	//mutex_lock(&dmxdev->mutex);
 	ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
 				     file->f_flags & O_NONBLOCK,
@@ -665,6 +690,8 @@ static int dvb_demux_open(struct inode *
 	dmxdevfilter->feed.ts = NULL;
 	init_timer(&dmxdevfilter->timer);
 
+	dvbdev->users++;
+
 	mutex_unlock(&dmxdev->mutex);
 	return 0;
 }
@@ -943,7 +970,21 @@ static int dvb_demux_release(struct inod
 	struct dmxdev_filter *dmxdevfilter = file->private_data;
 	struct dmxdev *dmxdev = dmxdevfilter->dev;
 
-	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+	int ret;
+
+	ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+	mutex_lock(&dmxdev->mutex);
+	dmxdev->dvbdev->users--;
+	if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		mutex_unlock(&dmxdev->mutex);
+		wake_up(&dmxdev->dvbdev->wait_queue);
+	} else
+		mutex_unlock(&dmxdev->mutex);
+
+	return ret;
 }
 
 static struct file_operations dvb_demux_fops = {
@@ -1027,6 +1068,7 @@ static struct file_operations dvb_dvr_fo
 static struct dvb_device dvbdev_dvr = {
 	.priv = NULL,
 	.readers = 1,
+	.users = 1,
 	.fops = &dvb_dvr_fops
 };
 
@@ -1064,6 +1106,16 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
 
 void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
+	dmxdev->exit=1;
+	if (dmxdev->dvbdev->users > 1) {
+		wait_event(dmxdev->dvbdev->wait_queue,
+				dmxdev->dvbdev->users==1);
+	}
+	if (dmxdev->dvr_dvbdev->users > 1) {
+		wait_event(dmxdev->dvr_dvbdev->wait_queue,
+				dmxdev->dvr_dvbdev->users==1);
+	}
+
 	dvb_unregister_device(dmxdev->dvbdev);
 	dvb_unregister_device(dmxdev->dvr_dvbdev);
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index d2bee9f..29746e7 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -91,6 +91,8 @@ struct dmxdev {
 
 	int filternum;
 	int capabilities;
+
+	unsigned int exit:1;
 #define DMXDEV_CAP_DUPLEX 1
 	struct dmx_frontend *dvr_orig_fe;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a21a894..f4e4ca2 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -606,6 +606,7 @@ static void dvb_frontend_stop(struct dvb
 		return;
 
 	kthread_stop(fepriv->thread);
+
 	init_MUTEX (&fepriv->sem);
 	fepriv->state = FESTATE_IDLE;
 
@@ -1023,6 +1024,7 @@ static int dvb_frontend_release(struct i
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int ret;
 
 	dprintk ("%s\n", __FUNCTION__);
 
@@ -1032,7 +1034,14 @@ static int dvb_frontend_release(struct i
 	if (fe->ops.ts_bus_ctrl)
 		fe->ops.ts_bus_ctrl (fe, 0);
 
-	return dvb_generic_release (inode, file);
+	ret = dvb_generic_release (inode, file);
+
+	if (dvbdev->users==-1 && fepriv->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		wake_up(&dvbdev->wait_queue);
+	}
+	return ret;
 }
 
 static struct file_operations dvb_frontend_fops = {
@@ -1092,8 +1101,15 @@ int dvb_unregister_frontend(struct dvb_f
 	dprintk ("%s\n", __FUNCTION__);
 
 	mutex_lock(&frontend_mutex);
-	dvb_unregister_device (fepriv->dvbdev);
 	dvb_frontend_stop (fe);
+	mutex_unlock(&frontend_mutex);
+
+	if (fepriv->dvbdev->users < -1)
+		wait_event(fepriv->dvbdev->wait_queue,
+				fepriv->dvbdev->users==-1);
+
+	mutex_lock(&frontend_mutex);
+	dvb_unregister_device (fepriv->dvbdev);
 
 	/* fe is invalid now */
 	kfree(fepriv);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 76e9c36..4ebf33a 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -174,7 +174,7 @@ static unsigned short dvb_net_eth_type_t
 	struct ethhdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb,dev->hard_header_len);
 	eth = eth_hdr(skb);
 
@@ -600,6 +600,7 @@ #endif
 			/* Check CRC32, we've got it in our skb already. */
 			unsigned short ulen = htons(priv->ule_sndu_len);
 			unsigned short utype = htons(priv->ule_sndu_type);
+			const u8 *tail;
 			struct kvec iov[3] = {
 				{ &ulen, sizeof ulen },
 				{ &utype, sizeof utype },
@@ -613,10 +614,11 @@ #endif
 			}
 
 			ule_crc = iov_crc32(ule_crc, iov, 3);
-			expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 |
-				       *((u8 *)priv->ule_skb->tail - 3) << 16 |
-				       *((u8 *)priv->ule_skb->tail - 2) << 8 |
-				       *((u8 *)priv->ule_skb->tail - 1);
+			tail = skb_tail_pointer(priv->ule_skb);
+			expected_crc = *(tail - 4) << 24 |
+				       *(tail - 3) << 16 |
+				       *(tail - 2) << 8 |
+				       *(tail - 1);
 			if (ule_crc != expected_crc) {
 				printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
 				       priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
@@ -695,7 +697,9 @@ #endif
 					}
 					else
 					{
-						memcpy(dest_addr,  priv->ule_skb->data, ETH_ALEN);
+						skb_copy_from_linear_data(priv->ule_skb,
+							      dest_addr,
+							      ETH_ALEN);
 						skb_pull(priv->ule_skb, ETH_ALEN);
 					}
 				}
@@ -1435,11 +1439,36 @@ static int dvb_net_ioctl(struct inode *i
 	return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
 }
 
+static int dvb_net_close(struct inode *inode, struct file *file)
+{
+	struct dvb_device *dvbdev = file->private_data;
+	struct dvb_net *dvbnet = dvbdev->priv;
+
+	if (!dvbdev)
+		return -ENODEV;
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+		dvbdev->readers++;
+	} else {
+		dvbdev->writers++;
+	}
+
+	dvbdev->users++;
+
+	if(dvbdev->users == 1 && dvbnet->exit==1) {
+		fops_put(file->f_op);
+		file->f_op = NULL;
+		wake_up(&dvbdev->wait_queue);
+	}
+	return 0;
+}
+
+
 static struct file_operations dvb_net_fops = {
 	.owner = THIS_MODULE,
 	.ioctl = dvb_net_ioctl,
 	.open =	dvb_generic_open,
-	.release = dvb_generic_release,
+	.release = dvb_net_close,
 };
 
 static struct dvb_device dvbdev_net = {
@@ -1454,6 +1483,11 @@ void dvb_net_release (struct dvb_net *dv
 {
 	int i;
 
+	dvbnet->exit = 1;
+	if (dvbnet->dvbdev->users < 1)
+		wait_event(dvbnet->dvbdev->wait_queue,
+				dvbnet->dvbdev->users==1);
+
 	dvb_unregister_device(dvbnet->dvbdev);
 
 	for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
index f14e4ca..3a3126c 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/drivers/media/dvb/dvb-core/dvb_net.h
@@ -36,6 +36,7 @@ struct dvb_net {
 	struct dvb_device *dvbdev;
 	struct net_device *device[DVB_NET_DEVICES_MAX];
 	int state[DVB_NET_DEVICES_MAX];
+	unsigned int exit:1;
 	struct dmx_demux *demux;
 };
 
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 14a372a..e23d8a0 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -233,6 +233,7 @@ int dvb_register_device(struct dvb_adapt
 	dvbdev->adapter = adap;
 	dvbdev->priv = priv;
 	dvbdev->fops = dvbdevfops;
+	init_waitqueue_head (&dvbdev->wait_queue);
 
 	memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
 	dvbdev->fops->owner = adap->module;
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 620e788..6dff10e 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -69,6 +69,7 @@ struct dvb_device {
 	int writers;
 	int users;
 
+	wait_queue_head_t	  wait_queue;
 	/* don't really need those !? -- FIXME: use video_usercopy  */
 	int (*kernel_ioctl)(struct inode *inode, struct file *file,
 			    unsigned int cmd, void *arg);
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 80f67a5..5448873 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -33,6 +33,7 @@ config DVB_USB_A800
 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_PLL
 	select DVB_DIB3000MB
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	help
@@ -88,6 +89,7 @@ config DVB_USB_DIB0700
 config DVB_USB_UMT_010
 	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
 	depends on DVB_USB
+	select DVB_PLL
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	help
@@ -96,9 +98,9 @@ config DVB_USB_UMT_010
 config DVB_USB_CXUSB
 	tristate "Conexant USB2.0 hybrid reference design support"
 	depends on DVB_USB
+	select DVB_PLL
 	select DVB_CX22702 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	help
@@ -140,6 +142,7 @@ config DVB_USB_AU6610
 config DVB_USB_DIGITV
 	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
 	depends on DVB_USB
+	select DVB_PLL
 	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	help
@@ -208,3 +211,10 @@ config DVB_USB_DTT200U
 	  The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
 
 	  The WT-220U and its clones are pen-sized.
+
+config DVB_USB_OPERA1
+	tristate "Opera1 DVB-S USB2.0 receiver"
+	depends on DVB_USB
+	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Opera DVB-S USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 40f28f5..976f840 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -51,4 +51,8 @@ obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-
 dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
 obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
 
+dvb-usb-opera-objs = opera1.o
+obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
+
+
 EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index 0dc66a8..18e0b16 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -40,7 +40,7 @@ static int au6610_usb_msg(struct dvb_usb
 	}
 
 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
-			      USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
+			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
 			      sizeof(usb_buf), AU6610_USB_TIMEOUT);
 
 	if (ret < 0)
@@ -124,7 +124,7 @@ static int au6610_identify_state(struct 
 }
 
 static struct zl10353_config au6610_zl10353_config = {
-	.demod_address = 0x1e,
+	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
 };
@@ -140,7 +140,7 @@ static int au6610_zl10353_frontend_attac
 }
 
 static struct qt1010_config au6610_qt1010_config = {
-	.i2c_address = 0xc4
+	.i2c_address = 0x62
 };
 
 static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 127a94b..bac2ae3 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -27,7 +27,6 @@ #include "cxusb.h"
 
 #include "cx22702.h"
 #include "lgdt330x.h"
-#include "lgh06xf.h"
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
@@ -388,7 +387,8 @@ static int cxusb_dtt7579_tuner_attach(st
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	dvb_attach(lgh06xf_attach, adap->fe, &adap->dev->i2c_adap);
+	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+		   &dvb_pll_lg_tdvs_h06xf);
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 6a4d150..dddf164 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -56,10 +56,6 @@ static int dib0700_ctrl_rd(struct dvb_us
 	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);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 70df31b..088b6de 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_devi
 		return -EINVAL;
 	}
 
-	strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
+	strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
 #ifdef I2C_ADAP_CLASS_TV_DIGITAL
 	d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
 #else
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 148386a..97715f7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -13,6 +13,7 @@ #define _DVB_USB_IDS_H_
 #define USB_VID_ADSTECH				0x06e1
 #define USB_VID_ALCOR_MICRO		0x058f
 #define USB_VID_ANCHOR				0x0547
+#define USB_VID_ANUBIS_ELECTRONIC		0x10fd
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
@@ -31,6 +32,7 @@ #define USB_VID_LEADTEK				0x0413
 #define USB_VID_LITEON				0x04ca
 #define USB_VID_MEDION				0x1660
 #define USB_VID_MSI				0x0db0
+#define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
 #define USB_VID_VISIONPLUS			0x13d3
 #define USB_VID_TWINHAN				0x1822
@@ -127,6 +129,7 @@ #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_PCTV_450E				0x0222
 #define USB_PID_LITEON_DVB_T_COLD			0xf000
 #define USB_PID_LITEON_DVB_T_WARM			0xf001
 #define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
@@ -139,6 +142,9 @@ #define USB_PID_WINFAST_DTV_DONGLE_STK77
 #define USB_PID_GENPIX_8PSK_COLD			0x0200
 #define USB_PID_GENPIX_8PSK_WARM			0x0201
 #define USB_PID_SIGMATEK_DVB_110			0x6610
+#define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
+#define USB_PID_OPERA1_COLD				0x2830
+#define USB_PID_OPERA1_WARM				0x3829
 
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index c9f38a5..e0587e6 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -12,7 +12,7 @@ #include "zl10353.h"
 #include "qt1010.h"
 
 /* debug */
-int dvb_usb_gl861_debug;
+static int dvb_usb_gl861_debug;
 module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
@@ -20,7 +20,7 @@ static int gl861_i2c_msg(struct dvb_usb_
 			 u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
 {
 	u16 index;
-	u16 value = addr << 8;
+	u16 value = addr << (8 + 1);
 	int wo = (rbuf == NULL || rlen == 0); /* write-only */
 	u8 req, type;
 
@@ -101,7 +101,7 @@ static int gl861_identify_state(struct u
 }
 
 static struct zl10353_config gl861_zl10353_config = {
-	.demod_address = 0x1e,
+	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.parallel_ts = 1,
 };
@@ -117,7 +117,7 @@ static int gl861_frontend_attach(struct 
 }
 
 static struct qt1010_config gl861_qt1010_config = {
-	.i2c_address = 0xc4
+	.i2c_address = 0x62
 };
 
 static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index d48b24d..45d7bc2 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -14,6 +14,8 @@ #include "m920x.h"
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "qt1010.h"
+#include "tda1004x.h"
+#include "tda827x.h"
 
 /* debug */
 static int dvb_usb_m920x_debug;
@@ -47,11 +49,15 @@ static inline int m9206_read(struct usb_
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 			      request, USB_TYPE_VENDOR | USB_DIR_IN,
 			      value, index, data, size, 2000);
-	if (ret < 0)
+	if (ret < 0) {
+		printk(KERN_INFO "m920x_read = error: %d\n", ret);
 		return ret;
+	}
 
-	if (ret != size)
+	if (ret != size) {
+		deb_rc("m920x_read = no data\n");
 		return -EIO;
+	}
 
 	return 0;
 }
@@ -64,19 +70,22 @@ static inline int m9206_write(struct usb
 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 			      request, USB_TYPE_VENDOR | USB_DIR_OUT,
 			      value, index, NULL, 0, 2000);
+
 	return ret;
 }
 
-static int m9206_rc_init(struct usb_device *udev)
+static int m9206_init(struct dvb_usb_device *d)
 {
 	int ret = 0;
 
 	/* Remote controller init. */
-	if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
-		return ret;
+	if (d->props.rc_query) {
+		if ((ret = m9206_write(d->udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
+			return ret;
 
-	if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
-		return ret;
+		if ((ret = m9206_write(d->udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
+			return ret;
+	}
 
 	return ret;
 }
@@ -87,16 +96,15 @@ static int m9206_rc_query(struct dvb_usb
 	int i, ret = 0;
 	u8 rc_state[2];
 
-
 	if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
 		goto unlock;
 
 	if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
 		goto unlock;
 
-	for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
-		if (megasky_rc_keys[i].data == rc_state[1]) {
-			*event = megasky_rc_keys[i].event;
+	for (i = 0; i < d->props.rc_key_map_size; i++)
+		if (d->props.rc_key_map[i].data == rc_state[1]) {
+			*event = d->props.rc_key_map[i].event;
 
 			switch(rc_state[0]) {
 			case 0x80:
@@ -137,53 +145,51 @@ static int m9206_i2c_xfer(struct i2c_ada
 			  int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	struct m9206_state *m = d->priv;
-	int i;
+	int i, j;
 	int ret = 0;
 
+	if (!num)
+		return -EINVAL;
+
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	if (num > 2)
-		return -EINVAL;
-
 	for (i = 0; i < num; i++) {
-		if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
-			goto unlock;
-
-		if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
+		if (msg[i].flags & (I2C_M_NO_RD_ACK|I2C_M_IGNORE_NAK|I2C_M_TEN) ||
+		    msg[i].len == 0) {
+			/* For a 0 byte message, I think sending the address to index 0x80|0x40
+			 * would be the correct thing to do.  However, zero byte messages are
+			 * only used for probing, and since we don't know how to get the slave's
+			 * ack, we can't probe. */
+			ret = -ENOTSUPP;
 			goto unlock;
-
-		if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
-			int i2c_i;
-
-			for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
-				if (msg[i].addr == m->i2c_r[i2c_i].addr)
-					break;
-
-			if (i2c_i >= M9206_I2C_MAX) {
-				deb_rc("No magic for i2c addr!\n");
-				ret = -EINVAL;
+		}
+		/* Send START & address/RW bit */
+		if (!(msg[i].flags & I2C_M_NOSTART)) {
+			if ((ret = m9206_write(d->udev, M9206_I2C, (msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0), 0x80)) != 0)
 				goto unlock;
+			/* Should check for ack here, if we knew how. */
+		}
+		if (msg[i].flags & I2C_M_RD) {
+			for (j = 0; j < msg[i].len; j++) {
+				/* Last byte of transaction? Send STOP, otherwise send ACK. */
+				int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x01;
+				if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x20|stop, &msg[i].buf[j], 1)) != 0)
+					goto unlock;
 			}
-
-			if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
-				goto unlock;
-
-			if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
-				goto unlock;
-
-			i++;
 		} else {
-			if (msg[i].len != 2)
-				return -EINVAL;
-
-			if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
-				goto unlock;
+			for (j = 0; j < msg[i].len; j++) {
+				/* Last byte of transaction? Then send STOP. */
+				int stop = (i+1 == num && j+1 == msg[i].len)?0x40:0x00;
+				if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], stop)) != 0)
+					goto unlock;
+				/* Should check for ack here too. */
+			}
 		}
 	}
-	ret = i;
-	unlock:
+	ret = num;
+
+unlock:
 	mutex_unlock(&d->i2c_mutex);
 
 	return ret;
@@ -324,6 +330,7 @@ static int m9206_firmware_download(struc
 			i += size;
 		}
 		if (i != fw->size) {
+			deb_rc("bad firmware file!\n");
 			ret = -EINVAL;
 			goto done;
 		}
@@ -342,10 +349,10 @@ static int m9206_firmware_download(struc
 }
 
 /* Callbacks for DVB USB */
-static int megasky_identify_state(struct usb_device *udev,
-				  struct dvb_usb_device_properties *props,
-				  struct dvb_usb_device_description **desc,
-				  int *cold)
+static int m920x_identify_state(struct usb_device *udev,
+				struct dvb_usb_device_properties *props,
+				struct dvb_usb_device_description **desc,
+				int *cold)
 {
 	struct usb_host_interface *alt;
 
@@ -381,20 +388,15 @@ static int megasky_mt352_demod_init(stru
 }
 
 static struct mt352_config megasky_mt352_config = {
-	.demod_address = 0x1e,
+	.demod_address = 0x0f,
 	.no_tuner = 1,
 	.demod_init = megasky_mt352_demod_init,
 };
 
 static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	struct m9206_state *m = adap->dev->priv;
-
 	deb_rc("megasky_frontend_attach!\n");
 
-	m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
-	m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
-
 	if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
 		return -EIO;
 
@@ -402,16 +404,11 @@ static int megasky_mt352_frontend_attach
 }
 
 static struct qt1010_config megasky_qt1010_config = {
-	.i2c_address = 0xc4
+	.i2c_address = 0x62
 };
 
 static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	struct m9206_state *m = adap->dev->priv;
-
-	m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
-	m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
-
 	if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
 		       &megasky_qt1010_config) == NULL)
 		return -ENODEV;
@@ -419,8 +416,40 @@ static int megasky_qt1010_tuner_attach(s
 	return 0;
 }
 
+static struct tda1004x_config digivox_tda10046_config = {
+	.demod_address = 0x08,
+	.invert = 0,
+	.invert_oclk = 0,
+	.ts_mode = TDA10046_TS_SERIAL,
+	.xtal_freq = TDA10046_XTAL_16M,
+	.if_freq = TDA10046_FREQ_045,
+	.agc_config = TDA10046_AGC_TDA827X,
+	.gpio_config = TDA10046_GPTRI,
+	.request_firmware = NULL,
+};
+
+static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	deb_rc("digivox_tda10046_frontend_attach!\n");
+
+	if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config,
+				   &adap->dev->i2c_adap)) == NULL)
+		return -EIO;
+
+	return 0;
+}
+
+static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+		       NULL) == NULL)
+		return -ENODEV;
+	return 0;
+}
+
 /* DVB USB Driver stuff */
 static struct dvb_usb_device_properties megasky_properties;
+static struct dvb_usb_device_properties digivox_mini_ii_properties;
 
 static int m920x_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -429,30 +458,36 @@ static int m920x_probe(struct usb_interf
 	struct usb_host_interface *alt;
 	int ret;
 
-	if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
-		deb_rc("probed!\n");
+	deb_rc("Probed!\n");
 
-		alt = usb_altnum_to_altsetting(intf, 1);
-		if (alt == NULL) {
-			deb_rc("not alt found!\n");
-			return -ENODEV;
-		}
+	if (((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) ||
+	    ((ret = dvb_usb_device_init(intf, &digivox_mini_ii_properties, THIS_MODULE, &d)) == 0))
+		goto found;
 
-		ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-					alt->desc.bAlternateSetting);
-		if (ret < 0)
-			return ret;
-
-		deb_rc("Changed to alternate setting!\n");
+	return ret;
 
-		if ((ret = m9206_rc_init(d->udev)) != 0)
-			return ret;
+found:
+	alt = usb_altnum_to_altsetting(intf, 1);
+	if (alt == NULL) {
+		deb_rc("No alt found!\n");
+		return -ENODEV;
 	}
+
+	ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+				alt->desc.bAlternateSetting);
+	if (ret < 0)
+		return ret;
+
+	if ((ret = m9206_init(d)) != 0)
+		return ret;
+
 	return ret;
 }
 
 static struct usb_device_id m920x_table [] = {
 		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
+		{ USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC,
+			     USB_PID_MSI_DIGI_VOX_MINI_II) },
 		{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, m920x_table);
@@ -471,7 +506,7 @@ static struct dvb_usb_device_properties 
 
 	.size_of_priv     = sizeof(struct m9206_state),
 
-	.identify_state   = megasky_identify_state,
+	.identify_state   = m920x_identify_state,
 	.num_adapters = 1,
 	.adapter = {{
 		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
@@ -502,6 +537,50 @@ static struct dvb_usb_device_properties 
 		{   "MSI Mega Sky 580 DVB-T USB2.0",
 			{ &m920x_table[0], NULL },
 			{ NULL },
+		}
+	}
+};
+
+static struct dvb_usb_device_properties digivox_mini_ii_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "dvb-usb-digivox-02.fw",
+	.download_firmware = m9206_firmware_download,
+
+	.size_of_priv     = sizeof(struct m9206_state),
+
+	.identify_state   = m920x_identify_state,
+	.num_adapters = 1,
+	.adapter = {{
+		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
+		DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+		.pid_filter_count = 8,
+		.pid_filter       = m9206_pid_filter,
+		.pid_filter_ctrl  = m9206_pid_filter_ctrl,
+
+		.frontend_attach  = digivox_tda10046_frontend_attach,
+		.tuner_attach     = digivox_tda8275_tuner_attach,
+
+		.stream = {
+			.type = USB_BULK,
+			.count = 8,
+			.endpoint = 0x81,
+			.u = {
+				.bulk = {
+					.buffersize = 0x4000,
+				}
+			}
+		},
+	}},
+	.i2c_algo         = &m9206_i2c_algo,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "MSI DIGI VOX mini II DVB-T USB2.0",
+			{ &m920x_table[1], NULL },
+			{ NULL },
 		},
 	}
 };
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index c354196..7dd3db6 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -19,17 +19,49 @@ #define M9206_FW	0x30
 
 #define M9206_MAX_FILTERS 8
 
-#define M9206_I2C_TUNER	0
-#define M9206_I2C_DEMOD	1
-#define M9206_I2C_MAX	2
+/*
+sequences found in logs:
+[index value]
+0x80 write addr
+(0x00 out byte)*
+0x40 out byte
+
+0x80 write addr
+(0x00 out byte)*
+0x80 read addr
+(0x21 in byte)*
+0x60 in byte
+
+this sequence works:
+0x80 read addr
+(0x21 in byte)*
+0x60 in byte
+
+Guess at API of the I2C function:
+I2C operation is done one byte at a time with USB control messages.  The
+index the messages is sent to is made up of a set of flags that control
+the I2C bus state:
+0x80:  Send START condition.  After a START condition, one would normally
+       always send the 7-bit slave I2C address as the 7 MSB, followed by
+       the read/write bit as the LSB.
+0x40:  Send STOP condition.  This should be set on the last byte of an
+       I2C transaction.
+0x20:  Read a byte from the slave.  As opposed to writing a byte to the
+       slave.  The slave will normally not produce any data unless you
+       set the R/W bit to 1 when sending the slave's address after the
+       START condition.
+0x01:  Respond with ACK, as opposed to a NACK.  For a multi-byte read,
+       the master should send an ACK, that is pull SDA low during the 9th
+       clock cycle, after every byte but the last.  This flags only makes
+       sense when bit 0x20 is set, indicating a read.
+
+What any other bits might mean, or how to get the slave's ACK/NACK
+response to a write, is unknown.
+*/
 
 struct m9206_state {
 	u16 filters[M9206_MAX_FILTERS];
 	int filtering_enabled;
 	int rep_count;
-	struct {
-		unsigned char addr;
-		unsigned char magic;
-	}i2c_r[M9206_I2C_MAX];
 };
 #endif
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
new file mode 100644
index 0000000..518d7ad
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -0,0 +1,581 @@
+/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
+*
+* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
+* Copyright (C) 2006 Marco Gittler (g.marco@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, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#include "opera1.h"
+#include "stv0299.h"
+
+#define OPERA_READ_MSG 0
+#define OPERA_WRITE_MSG 1
+#define OPERA_I2C_TUNER 0xd1
+
+#define READ_FX2_REG_REQ  0xba
+#define READ_MAC_ADDR 0x08
+#define OPERA_WRITE_FX2 0xbb
+#define OPERA_TUNER_REQ 0xb1
+#define REG_1F_SYMBOLRATE_BYTE0 0x1f
+#define REG_20_SYMBOLRATE_BYTE1 0x20
+#define REG_21_SYMBOLRATE_BYTE2 0x21
+
+#define ADDR_B600_VOLTAGE_13V (0x02)
+#define ADDR_B601_VOLTAGE_18V (0x03)
+#define ADDR_B1A6_STREAM_CTRL (0x04)
+#define ADDR_B880_READ_REMOTE (0x05)
+
+struct opera1_state {
+	u32 last_key_pressed;
+};
+struct opera_rc_keys {
+	u32 keycode;
+	u32 event;
+};
+
+int dvb_usb_opera1_debug;
+module_param_named(debug, dvb_usb_opera1_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);
+
+static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
+			    u8 * data, u16 len, int flags)
+{
+	int ret;
+	u8 r;
+	u8 u8buf[len];
+
+	unsigned int pipe = (flags == OPERA_READ_MSG) ?
+		usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
+	u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+
+	if (flags == OPERA_WRITE_MSG)
+		memcpy(u8buf, data, len);
+	ret =
+		usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+			value, 0x0, u8buf, len, 2000);
+
+	if (request == OPERA_TUNER_REQ) {
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+				0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
+					return 0;
+	}
+	if (flags == OPERA_READ_MSG)
+		memcpy(data, u8buf, len);
+	return ret;
+}
+
+/* I2C */
+
+static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
+				  u8 * buf, u16 len)
+{
+	int ret = 0;
+	u8 request;
+	u16 value;
+
+	if (!dev) {
+		info("no usb_device");
+		return -EINVAL;
+	}
+	if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
+		return -EAGAIN;
+
+	switch (addr>>1){
+		case ADDR_B600_VOLTAGE_13V:
+			request=0xb6;
+			value=0x00;
+			break;
+		case ADDR_B601_VOLTAGE_18V:
+			request=0xb6;
+			value=0x01;
+			break;
+		case ADDR_B1A6_STREAM_CTRL:
+			request=0xb1;
+			value=0xa6;
+			break;
+		case ADDR_B880_READ_REMOTE:
+			request=0xb8;
+			value=0x80;
+			break;
+		default:
+			request=0xb1;
+			value=addr;
+	}
+	ret = opera1_xilinx_rw(dev->udev, request,
+		value, buf, len,
+		addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
+
+	mutex_unlock(&dev->usb_mutex);
+	return ret;
+}
+
+static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			   int num)
+{
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int i = 0, tmp = 0;
+
+	if (!d)
+		return -ENODEV;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	for (i = 0; i < num; i++) {
+		if ((tmp = opera1_usb_i2c_msgxfer(d,
+					(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
+					msg[i].buf,
+					msg[i].len
+					)!= msg[i].len)) {
+			break;
+		}
+		if (dvb_usb_opera1_debug & 0x10)
+			info("sending i2c mesage %d %d", tmp, msg[i].len);
+	}
+	mutex_unlock(&d->i2c_mutex);
+	return num;
+}
+
+static u32 opera1_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm opera1_i2c_algo = {
+	.master_xfer = opera1_i2c_xfer,
+	.functionality = opera1_i2c_func,
+};
+
+static int opera1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+	static u8 command_13v[1]={0x00};
+	static u8 command_18v[1]={0x01};
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
+	};
+	struct dvb_usb_adapter *udev_adap =
+	    (struct dvb_usb_adapter *)(fe->dvb->priv);
+	if (voltage == SEC_VOLTAGE_18) {
+		msg[0].addr = ADDR_B601_VOLTAGE_18V;
+		msg[0].buf = command_18v;
+	}
+	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
+					  u32 ratio)
+{
+	stv0299_writereg(fe, 0x13, 0x98);
+	stv0299_writereg(fe, 0x14, 0x95);
+	stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
+	stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
+	stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
+	return 0;
+
+}
+static u8 opera1_inittab[] = {
+	0x00, 0xa1,
+	0x01, 0x15,
+	0x02, 0x00,
+	0x03, 0x00,
+	0x04, 0x7d,
+	0x05, 0x05,
+	0x06, 0x02,
+	0x07, 0x00,
+	0x0b, 0x00,
+	0x0c, 0x01,
+	0x0d, 0x81,
+	0x0e, 0x44,
+	0x0f, 0x19,
+	0x10, 0x3f,
+	0x11, 0x84,
+	0x12, 0xda,
+	0x13, 0x98,
+	0x14, 0x95,
+	0x15, 0xc9,
+	0x16, 0xeb,
+	0x17, 0x00,
+	0x18, 0x19,
+	0x19, 0x8b,
+	0x1a, 0x00,
+	0x1b, 0x82,
+	0x1c, 0x7f,
+	0x1d, 0x00,
+	0x1e, 0x00,
+	REG_1F_SYMBOLRATE_BYTE0, 0x06,
+	REG_20_SYMBOLRATE_BYTE1, 0x50,
+	REG_21_SYMBOLRATE_BYTE2, 0x10,
+	0x22, 0x00,
+	0x23, 0x00,
+	0x24, 0x37,
+	0x25, 0xbc,
+	0x26, 0x00,
+	0x27, 0x00,
+	0x28, 0x00,
+	0x29, 0x1e,
+	0x2a, 0x14,
+	0x2b, 0x1f,
+	0x2c, 0x09,
+	0x2d, 0x0a,
+	0x2e, 0x00,
+	0x2f, 0x00,
+	0x30, 0x00,
+	0x31, 0x1f,
+	0x32, 0x19,
+	0x33, 0xfc,
+	0x34, 0x13,
+	0xff, 0xff,
+};
+
+static struct stv0299_config opera1_stv0299_config = {
+	.demod_address = 0xd0>>1,
+	.min_delay_ms = 100,
+	.mclk = 88000000UL,
+	.invert = 1,
+	.skip_reinit = 0,
+	.lock_output = STV0229_LOCKOUTPUT_0,
+	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+	.inittab = opera1_inittab,
+	.set_symbol_rate = opera1_stv0299_set_symbol_rate,
+};
+
+static int opera1_frontend_attach(struct dvb_usb_adapter *d)
+{
+	if ((d->fe =
+	     dvb_attach(stv0299_attach, &opera1_stv0299_config,
+			&d->dev->i2c_adap)) != NULL) {
+		d->fe->ops.set_voltage = opera1_set_voltage;
+		return 0;
+	}
+	info("not attached stv0299");
+	return -EIO;
+}
+
+static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	dvb_attach(
+		dvb_pll_attach, adap->fe, 0xc0>>1,
+		&adap->dev->i2c_adap, &dvb_pll_opera1
+	);
+	return 0;
+}
+
+static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	u8 val = onoff ? 0x01 : 0x00;
+
+	if (dvb_usb_opera1_debug)
+		info("power %s", onoff ? "on" : "off");
+	return opera1_xilinx_rw(d->udev, 0xb7, val,
+				&val, 1, OPERA_WRITE_MSG);
+}
+
+static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+	static u8 buf_start[2] = { 0xff, 0x03 };
+	static u8 buf_stop[2] = { 0xff, 0x00 };
+	struct i2c_msg start_tuner[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
+	};
+	if (dvb_usb_opera1_debug)
+		info("streaming %s", onoff ? "on" : "off");
+	i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
+	return 0;
+}
+
+static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+			     int onoff)
+{
+	u8 b_pid[3];
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("pidfilter index: %d pid: %d %s", index, pid,
+			onoff ? "on" : "off");
+	b_pid[0] = (2 * index) + 4;
+	b_pid[1] = onoff ? (pid & 0xff) : (0x00);
+	b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
+	i2c_transfer(&adap->dev->i2c_adap, msg, 1);
+	return 0;
+}
+
+static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+	int u = 0x04;
+	u8 b_pid[3];
+	struct i2c_msg msg[] = {
+		{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
+	};
+	if (dvb_usb_opera1_debug)
+		info("%s hw-pidfilter", onoff ? "enable" : "disable");
+	for (; u < 0x7e; u += 2) {
+		b_pid[0] = u;
+		b_pid[1] = 0;
+		b_pid[2] = 0x80;
+		i2c_transfer(&adap->dev->i2c_adap, msg, 1);
+	}
+	return 0;
+}
+
+static struct dvb_usb_rc_key opera1_rc_keys[] = {
+	{0x5f, 0xa0, KEY_1},
+	{0x51, 0xaf, KEY_2},
+	{0x5d, 0xa2, KEY_3},
+	{0x41, 0xbe, KEY_4},
+	{0x0b, 0xf5, KEY_5},
+	{0x43, 0xbd, KEY_6},
+	{0x47, 0xb8, KEY_7},
+	{0x49, 0xb6, KEY_8},
+	{0x05, 0xfa, KEY_9},
+	{0x45, 0xba, KEY_0},
+	{0x09, 0xf6, KEY_UP},	/*chanup */
+	{0x1b, 0xe5, KEY_DOWN},	/*chandown */
+	{0x5d, 0xa3, KEY_LEFT},	/*voldown */
+	{0x5f, 0xa1, KEY_RIGHT},	/*volup */
+	{0x07, 0xf8, KEY_SPACE},	/*tab */
+	{0x1f, 0xe1, KEY_ENTER},	/*play ok */
+	{0x1b, 0xe4, KEY_Z},	/*zoom */
+	{0x59, 0xa6, KEY_M},	/*mute */
+	{0x5b, 0xa5, KEY_F},	/*tv/f */
+	{0x19, 0xe7, KEY_R},	/*rec */
+	{0x01, 0xfe, KEY_S},	/*Stop */
+	{0x03, 0xfd, KEY_P},	/*pause */
+	{0x03, 0xfc, KEY_W},	/*<- -> */
+	{0x07, 0xf9, KEY_C},	/*capture */
+	{0x47, 0xb9, KEY_Q},	/*exit */
+	{0x43, 0xbc, KEY_O},	/*power */
+
+};
+
+static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
+{
+	struct opera1_state *opst = dev->priv;
+	u8 rcbuffer[32];
+	const u16 startmarker1 = 0x10ed;
+	const u16 startmarker2 = 0x11ec;
+	struct i2c_msg read_remote[] = {
+		{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
+	};
+	int i = 0;
+	u32 send_key = 0;
+
+	if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
+		for (i = 0; i < 32; i++) {
+			if (rcbuffer[i])
+				send_key |= 1;
+			if (i < 31)
+				send_key = send_key << 1;
+		}
+		if (send_key & 0x8000)
+			send_key = (send_key << 1) | (send_key >> 15 & 0x01);
+
+		if (send_key == 0xffff && opst->last_key_pressed != 0) {
+			*state = REMOTE_KEY_REPEAT;
+			*event = opst->last_key_pressed;
+			return 0;
+		}
+		for (; send_key != 0;) {
+			if (send_key >> 16 == startmarker2) {
+				break;
+			} else if (send_key >> 16 == startmarker1) {
+				send_key =
+					(send_key & 0xfffeffff) | (startmarker1 << 16);
+				break;
+			} else
+				send_key >>= 1;
+		}
+
+		if (send_key == 0)
+			return 0;
+
+		send_key = (send_key & 0xffff) | 0x0100;
+
+		for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) {
+			if ((opera1_rc_keys[i].custom * 256 +
+					opera1_rc_keys[i].data) == (send_key & 0xffff)) {
+				*state = REMOTE_KEY_PRESSED;
+				*event = opera1_rc_keys[i].event;
+				opst->last_key_pressed =
+					opera1_rc_keys[i].event;
+				break;
+			}
+			opst->last_key_pressed = 0;
+		}
+	} else
+		*state = REMOTE_NO_KEY_PRESSED;
+	return 0;
+}
+
+static struct usb_device_id opera1_table[] = {
+	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
+	{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, opera1_table);
+
+static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+	u8 command[] = { READ_MAC_ADDR };
+	opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
+	opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
+	return 0;
+}
+static int opera1_xilinx_load_firmware(struct usb_device *dev,
+				       const char *filename)
+{
+	const struct firmware *fw = NULL;
+	u8 *b, *p;
+	int ret = 0, i;
+	u8 testval;
+	info("start downloading fpga firmware");
+
+	if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
+		err("did not find the firmware file. (%s) "
+			"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+			filename);
+		return ret;
+	} else {
+		p = kmalloc(fw->size, GFP_KERNEL);
+		opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
+		if (p != NULL && testval != 0x67) {
+
+			u8 reset = 0, fpga_command = 0;
+			memcpy(p, fw->data, fw->size);
+			/* clear fpga ? */
+			opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
+					 OPERA_WRITE_MSG);
+			for (i = 0; p[i] != 0 && i < fw->size;) {
+				b = (u8 *) p + i;
+				if (opera1_xilinx_rw
+					(dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
+						OPERA_WRITE_MSG) != b[0]
+					) {
+					err("error while transferring firmware");
+					ret = -EINVAL;
+					break;
+				}
+				i = i + 1 + b[0];
+			}
+			/* restart the CPU */
+			if (ret || opera1_xilinx_rw
+					(dev, 0xa0, 0xe600, &reset, 1,
+					OPERA_WRITE_MSG) != 1) {
+				err("could not restart the USB controller CPU.");
+				ret = -EINVAL;
+			}
+			kfree(p);
+		}
+	}
+	if (fw) {
+		release_firmware(fw);
+	}
+	return ret;
+}
+
+static struct dvb_usb_device_properties opera1_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-opera-01.fw",
+	.size_of_priv = sizeof(struct opera1_state),
+
+	.power_ctrl = opera1_power_ctrl,
+	.i2c_algo = &opera1_i2c_algo,
+
+	.rc_key_map = opera1_rc_keys,
+	.rc_key_map_size = ARRAY_SIZE(opera1_rc_keys),
+	.rc_interval = 200,
+	.rc_query = opera1_rc_query,
+	.read_mac_address = opera1_read_mac_address,
+	.generic_bulk_ctrl_endpoint = 0x00,
+	/* parameter for the MPEG2-data transfer */
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.frontend_attach = opera1_frontend_attach,
+			.streaming_ctrl = opera1_streaming_ctrl,
+			.tuner_attach = opera1_tuner_attach,
+			.caps =
+				DVB_USB_ADAP_HAS_PID_FILTER |
+				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+			.pid_filter = opera1_pid_filter,
+			.pid_filter_ctrl = opera1_pid_filter_control,
+			.pid_filter_count = 252,
+			.stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x82,
+				.u = {
+					.bulk = {
+						.buffersize = 4096,
+					}
+				}
+			},
+		}
+	},
+	.num_device_descs = 1,
+	.devices = {
+		{"Opera1 DVB-S USB2.0",
+			{&opera1_table[0], NULL},
+			{&opera1_table[1], NULL},
+		},
+	}
+};
+
+static int opera1_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct dvb_usb_device *d;
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
+		udev->descriptor.idVendor == USB_VID_OPERA1 &&
+		(d == NULL
+			|| opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
+		) {
+		return -EINVAL;
+	}
+
+	if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static struct usb_driver opera1_driver = {
+	.name = "opera1",
+	.probe = opera1_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = opera1_table,
+};
+
+static int __init opera1_module_init(void)
+{
+	int result = 0;
+	if ((result = usb_register(&opera1_driver))) {
+		err("usb_register failed. Error number %d", result);
+	}
+	return result;
+}
+
+static void __exit opera1_module_exit(void)
+{
+	usb_deregister(&opera1_driver);
+}
+
+module_init(opera1_module_init);
+module_exit(opera1_module_exit);
+
+MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
+MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
+MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h
new file mode 100644
index 0000000..5317442
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/opera1.h
@@ -0,0 +1,9 @@
+#ifndef _OPERA1_H_
+#define _OPERA1_H_
+
+#define DVB_USB_LOG_PREFIX "opera"
+#include "dvb-usb.h"
+
+extern int dvb_usb_opera1_debug;
+#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
+#endif
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 95d2997..88dc436 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -184,6 +184,7 @@ static int ttusb2_probe(struct usb_inter
 
 static struct usb_device_id ttusb2_table [] = {
 		{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+		{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
 		{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -227,12 +228,16 @@ static struct dvb_usb_device_properties 
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.num_device_descs = 1,
+	.num_device_descs = 2,
 	.devices = {
 		{   "Pinnacle 400e DVB-S USB2.0",
 			{ &ttusb2_table[0], NULL },
 			{ NULL },
 		},
+		{   "Pinnacle 450e DVB-S USB2.0",
+			{ &ttusb2_table[1], NULL },
+			{ NULL },
+		},
 	}
 };
 
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 22c2cf2..ff44876 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -205,6 +205,13 @@ config DVB_TDA10021
 	help
 	  A DVB-C tuner module. Say Y when you want to support this frontend.
 
+config DVB_TDA10023
+	tristate "Philips TDA10023 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
@@ -280,8 +287,12 @@ comment "Tuners/PLL support"
 	depends on DVB_CORE
 
 config DVB_PLL
-	tristate
+	tristate "Generic I2C PLL based tuners"
 	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  This module driver a number of tuners based on PLL chips with a
+	  common I2C interface. Say Y when you want to support these tuners.
 
 config DVB_TDA826X
 	tristate "Philips TDA826X silicon tuner"
@@ -290,6 +301,13 @@ config DVB_TDA826X
 	help
 	  A DVB-S silicon tuner module. Say Y when you want to support this tuner.
 
+config DVB_TDA827X
+	tristate "Philips TDA827X silicon tuner"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_TUNER_QT1010
 	tristate "Quantek QT1010 silicon tuner"
 	depends on DVB_CORE && I2C
@@ -304,14 +322,6 @@ config DVB_TUNER_MT2060
 	help
 	  A driver for the silicon IF tuner MT2060 from Microtune.
 
-config DVB_TUNER_LGH06XF
-	tristate "LG TDVS-H06xF ATSC tuner"
-	depends on DVB_CORE && I2C
-	select DVB_PLL
-	default m if DVB_FE_CUSTOMISE
-	help
-	  A driver for the LG TDVS-H06xF ATSC tuner family.
-
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index a646d99..27f3865 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_MT352) += mt352.o
 obj-$(CONFIG_DVB_ZL10353) += zl10353.o
 obj-$(CONFIG_DVB_CX22702) += cx22702.o
 obj-$(CONFIG_DVB_TDA10021) += tda10021.o
+obj-$(CONFIG_DVB_TDA10023) += tda10023.o
 obj-$(CONFIG_DVB_STV0297) += stv0297.o
 obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
 obj-$(CONFIG_DVB_OR51211) += or51211.o
@@ -37,7 +38,7 @@ 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_TDA827X) += tda827x.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
-obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index a18c8f4..315e09e 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -105,9 +105,9 @@ struct i2c_adapter * dibx000_get_i2c_ada
 }
 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)
+static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst)
 {
-	strncpy(i2c_adap->name, name, I2C_NAME_SIZE);
+	strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
 	i2c_adap->class     = I2C_CLASS_TV_DIGITAL,
 	i2c_adap->algo      = algo;
 	i2c_adap->algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 62de760..5f96ffd 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -27,17 +27,29 @@ #include "dvb-pll.h"
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
+/* Set AGC TOP value to 103 dBuV:
+	0x80 = Control Byte
+	0x40 = 250 uA charge pump (irrelevant)
+	0x18 = Aux Byte to follow
+	0x06 = 64.5 kHz divider (irrelevant)
+	0x01 = Disable Vt (aka sleep)
+
+	0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
+	0x50 = AGC Take over point = 103 dBuV */
+static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
+
 struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
 	.name  = "Thomson dtt7579",
 	.min   = 177000000,
 	.max   = 858000000,
-	.count = 5,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0xb4, 0x03 },
+	.count = 4,
 	.entries = {
-		{          0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */
-		{  443250000, 36166667, 166666, 0xb4, 0x02 },
-		{  542000000, 36166667, 166666, 0xb4, 0x08 },
-		{  771000000, 36166667, 166666, 0xbc, 0x08 },
-		{  999999999, 36166667, 166666, 0xf4, 0x08 },
+		{  443250000, 166667, 0xb4, 0x02 },
+		{  542000000, 166667, 0xb4, 0x08 },
+		{  771000000, 166667, 0xbc, 0x08 },
+		{  999999999, 166667, 0xf4, 0x08 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
@@ -46,11 +58,12 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7
 	.name  = "Thomson dtt7610",
 	.min   =  44000000,
 	.max   = 958000000,
+	.iffreq= 44000000,
 	.count = 3,
 	.entries = {
-		{ 157250000, 44000000, 62500, 0x8e, 0x39 },
-		{ 454000000, 44000000, 62500, 0x8e, 0x3a },
-		{ 999999999, 44000000, 62500, 0x8e, 0x3c },
+		{ 157250000, 62500, 0x8e, 0x39 },
+		{ 454000000, 62500, 0x8e, 0x3a },
+		{ 999999999, 62500, 0x8e, 0x3c },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
@@ -66,14 +79,15 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7
 	.min   = 177000000,
 	.max   = 896000000,
 	.setbw = thomson_dtt759x_bw,
-	.count = 6,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0x84, 0x03 },
+	.count = 5,
 	.entries = {
-		{          0, 36166667, 166666, 0x84, 0x03 },
-		{  264000000, 36166667, 166666, 0xb4, 0x02 },
-		{  470000000, 36166667, 166666, 0xbc, 0x02 },
-		{  735000000, 36166667, 166666, 0xbc, 0x08 },
-		{  835000000, 36166667, 166666, 0xf4, 0x08 },
-		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+		{  264000000, 166667, 0xb4, 0x02 },
+		{  470000000, 166667, 0xbc, 0x02 },
+		{  735000000, 166667, 0xbc, 0x08 },
+		{  835000000, 166667, 0xf4, 0x08 },
+		{  999999999, 166667, 0xfc, 0x08 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
@@ -82,14 +96,15 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
 	.name  = "LG z201",
 	.min   = 174000000,
 	.max   = 862000000,
-	.count = 6,
+	.iffreq= 36166667,
+	.sleepdata = (u8[]){ 2, 0xbc, 0x03 },
+	.count = 5,
 	.entries = {
-		{          0, 36166667, 166666, 0xbc, 0x03 },
-		{  157500000, 36166667, 166666, 0xbc, 0x01 },
-		{  443250000, 36166667, 166666, 0xbc, 0x02 },
-		{  542000000, 36166667, 166666, 0xbc, 0x04 },
-		{  830000000, 36166667, 166666, 0xf4, 0x04 },
-		{  999999999, 36166667, 166666, 0xfc, 0x04 },
+		{  157500000, 166667, 0xbc, 0x01 },
+		{  443250000, 166667, 0xbc, 0x02 },
+		{  542000000, 166667, 0xbc, 0x04 },
+		{  830000000, 166667, 0xf4, 0x04 },
+		{  999999999, 166667, 0xfc, 0x04 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_lg_z201);
@@ -98,11 +113,12 @@ struct dvb_pll_desc dvb_pll_microtune_40
 	.name  = "Microtune 4042 FI5",
 	.min   =  57000000,
 	.max   = 858000000,
+	.iffreq= 44000000,
 	.count = 3,
 	.entries = {
-		{ 162000000, 44000000, 62500, 0x8e, 0xa1 },
-		{ 457000000, 44000000, 62500, 0x8e, 0x91 },
-		{ 999999999, 44000000, 62500, 0x8e, 0x31 },
+		{ 162000000, 62500, 0x8e, 0xa1 },
+		{ 457000000, 62500, 0x8e, 0x91 },
+		{ 999999999, 62500, 0x8e, 0x31 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_microtune_4042);
@@ -112,11 +128,13 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7
 	.name  = "Thomson dtt761x",
 	.min   =  57000000,
 	.max   = 863000000,
+	.iffreq= 44000000,
 	.count = 3,
+	.initdata = tua603x_agc103,
 	.entries = {
-		{ 147000000, 44000000, 62500, 0x8e, 0x39 },
-		{ 417000000, 44000000, 62500, 0x8e, 0x3a },
-		{ 999999999, 44000000, 62500, 0x8e, 0x3c },
+		{ 147000000, 62500, 0x8e, 0x39 },
+		{ 417000000, 62500, 0x8e, 0x3a },
+		{ 999999999, 62500, 0x8e, 0x3c },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
@@ -125,17 +143,18 @@ struct dvb_pll_desc dvb_pll_unknown_1 = 
 	.name  = "unknown 1", /* used by dntv live dvb-t */
 	.min   = 174000000,
 	.max   = 862000000,
+	.iffreq= 36166667,
 	.count = 9,
 	.entries = {
-		{  150000000, 36166667, 166666, 0xb4, 0x01 },
-		{  173000000, 36166667, 166666, 0xbc, 0x01 },
-		{  250000000, 36166667, 166666, 0xb4, 0x02 },
-		{  400000000, 36166667, 166666, 0xbc, 0x02 },
-		{  420000000, 36166667, 166666, 0xf4, 0x02 },
-		{  470000000, 36166667, 166666, 0xfc, 0x02 },
-		{  600000000, 36166667, 166666, 0xbc, 0x08 },
-		{  730000000, 36166667, 166666, 0xf4, 0x08 },
-		{  999999999, 36166667, 166666, 0xfc, 0x08 },
+		{  150000000, 166667, 0xb4, 0x01 },
+		{  173000000, 166667, 0xbc, 0x01 },
+		{  250000000, 166667, 0xb4, 0x02 },
+		{  400000000, 166667, 0xbc, 0x02 },
+		{  420000000, 166667, 0xf4, 0x02 },
+		{  470000000, 166667, 0xfc, 0x02 },
+		{  600000000, 166667, 0xbc, 0x08 },
+		{  730000000, 166667, 0xf4, 0x08 },
+		{  999999999, 166667, 0xfc, 0x08 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_unknown_1);
@@ -147,11 +166,12 @@ struct dvb_pll_desc dvb_pll_tua6010xs = 
 	.name  = "Infineon TUA6010XS",
 	.min   =  44250000,
 	.max   = 858000000,
+	.iffreq= 36125000,
 	.count = 3,
 	.entries = {
-		{  115750000, 36125000, 62500, 0x8e, 0x03 },
-		{  403250000, 36125000, 62500, 0x8e, 0x06 },
-		{  999999999, 36125000, 62500, 0x8e, 0x85 },
+		{  115750000, 62500, 0x8e, 0x03 },
+		{  403250000, 62500, 0x8e, 0x06 },
+		{  999999999, 62500, 0x8e, 0x85 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_tua6010xs);
@@ -161,12 +181,13 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 =
 	.name  = "Panasonic ENV57H1XD5",
 	.min   =  44250000,
 	.max   = 858000000,
+	.iffreq= 36125000,
 	.count = 4,
 	.entries = {
-		{  153000000, 36291666, 166666, 0xc2, 0x41 },
-		{  470000000, 36291666, 166666, 0xc2, 0x42 },
-		{  526000000, 36291666, 166666, 0xc2, 0x84 },
-		{  999999999, 36291666, 166666, 0xc2, 0xa4 },
+		{  153000000, 166667, 0xc2, 0x41 },
+		{  470000000, 166667, 0xc2, 0x42 },
+		{  526000000, 166667, 0xc2, 0x84 },
+		{  999999999, 166667, 0xc2, 0xa4 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_env57h1xd5);
@@ -185,20 +206,21 @@ struct dvb_pll_desc dvb_pll_tda665x = {
 	.min   =  44250000,
 	.max   = 858000000,
 	.setbw = tda665x_bw,
+	.iffreq= 36166667,
 	.count = 12,
 	.entries = {
-		{   93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
-		{  123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
-		{  161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
-		{  163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
-		{  253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0  10 */ },
-		{  383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0  10 */ },
-		{  443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
-		{  444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
-		{  583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1  00 */ },
-		{  793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1  00 */ },
-		{  444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
-		{  861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
+		{   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
+		{  123834000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+		{  161000000, 166667, 0xca, 0xa1 /* 101 0 0 0  01 */ },
+		{  163834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+		{  253834000, 166667, 0xca, 0x62 /* 011 0 0 0  10 */ },
+		{  383834000, 166667, 0xca, 0xa2 /* 101 0 0 0  10 */ },
+		{  443834000, 166667, 0xca, 0xc2 /* 110 0 0 0  10 */ },
+		{  444000000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
+		{  583834000, 166667, 0xca, 0x64 /* 011 0 0 1  00 */ },
+		{  793834000, 166667, 0xca, 0xa4 /* 101 0 0 1  00 */ },
+		{  444834000, 166667, 0xca, 0xc4 /* 110 0 0 1  00 */ },
+		{  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_tda665x);
@@ -216,12 +238,13 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
 	.name  = "Infineon TUA6034",
 	.min   =  44250000,
 	.max   = 858000000,
+	.iffreq= 36166667,
 	.count = 3,
 	.setbw = tua6034_bw,
 	.entries = {
-		{  174500000, 36166667, 62500, 0xce, 0x01 },
-		{  230000000, 36166667, 62500, 0xce, 0x02 },
-		{  999999999, 36166667, 62500, 0xce, 0x04 },
+		{  174500000, 62500, 0xce, 0x01 },
+		{  230000000, 62500, 0xce, 0x02 },
+		{  999999999, 62500, 0xce, 0x04 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_tua6034);
@@ -233,11 +256,13 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06x
 	.name  = "LG TDVS-H06xF",
 	.min   =  54000000,
 	.max   = 863000000,
+	.iffreq= 44000000,
+	.initdata = tua603x_agc103,
 	.count = 3,
 	.entries = {
-		{  165000000, 44000000, 62500, 0xce, 0x01 },
-		{  450000000, 44000000, 62500, 0xce, 0x02 },
-		{  999999999, 44000000, 62500, 0xce, 0x04 },
+		{  165000000, 62500, 0xce, 0x01 },
+		{  450000000, 62500, 0xce, 0x02 },
+		{  999999999, 62500, 0xce, 0x04 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
@@ -255,16 +280,17 @@ struct dvb_pll_desc dvb_pll_fmd1216me = 
 	.name = "Philips FMD1216ME",
 	.min = 50870000,
 	.max = 858000000,
+	.iffreq= 36125000,
 	.setbw = fmd1216me_bw,
 	.count = 7,
 	.entries = {
-		{ 143870000, 36213333, 166667, 0xbc, 0x41 },
-		{ 158870000, 36213333, 166667, 0xf4, 0x41 },
-		{ 329870000, 36213333, 166667, 0xbc, 0x42 },
-		{ 441870000, 36213333, 166667, 0xf4, 0x42 },
-		{ 625870000, 36213333, 166667, 0xbc, 0x44 },
-		{ 803870000, 36213333, 166667, 0xf4, 0x44 },
-		{ 999999999, 36213333, 166667, 0xfc, 0x44 },
+		{ 143870000, 166667, 0xbc, 0x41 },
+		{ 158870000, 166667, 0xf4, 0x41 },
+		{ 329870000, 166667, 0xbc, 0x42 },
+		{ 441870000, 166667, 0xf4, 0x42 },
+		{ 625870000, 166667, 0xbc, 0x44 },
+		{ 803870000, 166667, 0xf4, 0x44 },
+		{ 999999999, 166667, 0xfc, 0x44 },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_fmd1216me);
@@ -282,13 +308,14 @@ struct dvb_pll_desc dvb_pll_tded4 = {
 	.name = "ALPS TDED4",
 	.min = 47000000,
 	.max = 863000000,
+	.iffreq= 36166667,
 	.setbw = tded4_bw,
 	.count = 4,
 	.entries = {
-		{ 153000000, 36166667, 166667, 0x85, 0x01 },
-		{ 470000000, 36166667, 166667, 0x85, 0x02 },
-		{ 823000000, 36166667, 166667, 0x85, 0x08 },
-		{ 999999999, 36166667, 166667, 0x85, 0x88 },
+		{ 153000000, 166667, 0x85, 0x01 },
+		{ 470000000, 166667, 0x85, 0x02 },
+		{ 823000000, 166667, 0x85, 0x08 },
+		{ 999999999, 166667, 0x85, 0x88 },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_tded4);
@@ -300,12 +327,13 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
 	.name = "ALPS TDHU2",
 	.min = 54000000,
 	.max = 864000000,
+	.iffreq= 44000000,
 	.count = 4,
 	.entries = {
-		{ 162000000, 44000000, 62500, 0x85, 0x01 },
-		{ 426000000, 44000000, 62500, 0x85, 0x02 },
-		{ 782000000, 44000000, 62500, 0x85, 0x08 },
-		{ 999999999, 44000000, 62500, 0x85, 0x88 },
+		{ 162000000, 62500, 0x85, 0x01 },
+		{ 426000000, 62500, 0x85, 0x02 },
+		{ 782000000, 62500, 0x85, 0x08 },
+		{ 999999999, 62500, 0x85, 0x88 },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_tdhu2);
@@ -317,11 +345,12 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
 	.name  = "Philips TUV1236D",
 	.min   =  54000000,
 	.max   = 864000000,
+	.iffreq= 44000000,
 	.count = 3,
 	.entries = {
-		{ 157250000, 44000000, 62500, 0xc6, 0x41 },
-		{ 454000000, 44000000, 62500, 0xc6, 0x42 },
-		{ 999999999, 44000000, 62500, 0xc6, 0x44 },
+		{ 157250000, 62500, 0xc6, 0x41 },
+		{ 454000000, 62500, 0xc6, 0x42 },
+		{ 999999999, 62500, 0xc6, 0x44 },
 	},
 };
 EXPORT_SYMBOL(dvb_pll_tuv1236d);
@@ -333,14 +362,15 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv
 	.name = "Samsung TBMV30111IN / TBMV30712IN1",
 	.min = 54000000,
 	.max = 860000000,
+	.iffreq= 44000000,
 	.count = 6,
 	.entries = {
-		{ 172000000, 44000000, 166666, 0xb4, 0x01 },
-		{ 214000000, 44000000, 166666, 0xb4, 0x02 },
-		{ 467000000, 44000000, 166666, 0xbc, 0x02 },
-		{ 721000000, 44000000, 166666, 0xbc, 0x08 },
-		{ 841000000, 44000000, 166666, 0xf4, 0x08 },
-		{ 999999999, 44000000, 166666, 0xfc, 0x02 },
+		{ 172000000, 166667, 0xb4, 0x01 },
+		{ 214000000, 166667, 0xb4, 0x02 },
+		{ 467000000, 166667, 0xbc, 0x02 },
+		{ 721000000, 166667, 0xbc, 0x08 },
+		{ 841000000, 166667, 0xf4, 0x08 },
+		{ 999999999, 166667, 0xfc, 0x02 },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
@@ -352,12 +382,13 @@ struct dvb_pll_desc dvb_pll_philips_sd18
 	.name  = "Philips SD1878",
 	.min   =  950000,
 	.max   = 2150000,
+	.iffreq= 249, /* zero-IF, offset 249 is to round up */
 	.count = 4,
 	.entries = {
-		{ 1250000, 499, 500, 0xc4, 0x00},
-		{ 1550000, 499, 500, 0xc4, 0x40},
-		{ 2050000, 499, 500, 0xc4, 0x80},
-		{ 2150000, 499, 500, 0xc4, 0xc0},
+		{ 1250000, 500, 0xc4, 0x00},
+		{ 1550000, 500, 0xc4, 0x40},
+		{ 2050000, 500, 0xc4, 0x80},
+		{ 2150000, 500, 0xc4, 0xc0},
 	},
 };
 EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
@@ -388,18 +419,19 @@ struct dvb_pll_desc dvb_pll_philips_td13
 	.name  = "Philips TD1316",
 	.min   =  87000000,
 	.max   = 895000000,
+	.iffreq= 36166667,
 	.setbw = td1316_bw,
 	.count = 9,
 	.entries = {
-		{  93834000, 36166000, 166666, 0xca, 0x60},
-		{ 123834000, 36166000, 166666, 0xca, 0xa0},
-		{ 163834000, 36166000, 166666, 0xca, 0xc0},
-		{ 253834000, 36166000, 166666, 0xca, 0x60},
-		{ 383834000, 36166000, 166666, 0xca, 0xa0},
-		{ 443834000, 36166000, 166666, 0xca, 0xc0},
-		{ 583834000, 36166000, 166666, 0xca, 0x60},
-		{ 793834000, 36166000, 166666, 0xca, 0xa0},
-		{ 858834000, 36166000, 166666, 0xca, 0xe0},
+		{  93834000, 166667, 0xca, 0x60},
+		{ 123834000, 166667, 0xca, 0xa0},
+		{ 163834000, 166667, 0xca, 0xc0},
+		{ 253834000, 166667, 0xca, 0x60},
+		{ 383834000, 166667, 0xca, 0xa0},
+		{ 443834000, 166667, 0xca, 0xc0},
+		{ 583834000, 166667, 0xca, 0x60},
+		{ 793834000, 166667, 0xca, 0xa0},
+		{ 858834000, 166667, 0xca, 0xe0},
 	},
 };
 EXPORT_SYMBOL(dvb_pll_philips_td1316);
@@ -409,15 +441,41 @@ struct dvb_pll_desc dvb_pll_thomson_fe66
 	.name = "Thomson FE6600",
 	.min =  44250000,
 	.max = 858000000,
+	.iffreq= 36125000,
 	.count = 4,
 	.entries = {
-		{ 250000000, 36213333, 166667, 0xb4, 0x12 },
-		{ 455000000, 36213333, 166667, 0xfe, 0x11 },
-		{ 775500000, 36213333, 166667, 0xbc, 0x18 },
-		{ 999999999, 36213333, 166667, 0xf4, 0x18 },
+		{ 250000000, 166667, 0xb4, 0x12 },
+		{ 455000000, 166667, 0xfe, 0x11 },
+		{ 775500000, 166667, 0xbc, 0x18 },
+		{ 999999999, 166667, 0xf4, 0x18 },
 	}
 };
 EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+{
+	if (bandwidth == BANDWIDTH_8_MHZ)
+		buf[2] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_opera1 = {
+	.name  = "Opera Tuner",
+	.min   =  900000,
+	.max   = 2250000,
+	.iffreq= 0,
+	.setbw = opera1_bw,
+	.count = 8,
+	.entries = {
+		{ 1064000, 500, 0xe5, 0xc6 },
+		{ 1169000, 500, 0xe5, 0xe6 },
+		{ 1299000, 500, 0xe5, 0x24 },
+		{ 1444000, 500, 0xe5, 0x44 },
+		{ 1606000, 500, 0xe5, 0x64 },
+		{ 1777000, 500, 0xe5, 0x84 },
+		{ 1941000, 500, 0xe5, 0xa4 },
+		{ 2250000, 500, 0xe5, 0xc4 },
+	}
+};
+EXPORT_SYMBOL(dvb_pll_opera1);
 
 struct dvb_pll_priv {
 	/* i2c details */
@@ -459,7 +517,8 @@ int dvb_pll_configure(struct dvb_pll_des
 	if (i == desc->count)
 		return -EINVAL;
 
-	div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
+	div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
+	      desc->entries[i].stepsize;
 	buf[0] = div >> 8;
 	buf[1] = div & 0xff;
 	buf[2] = desc->entries[i].config;
@@ -473,7 +532,7 @@ int dvb_pll_configure(struct dvb_pll_des
 		       desc->name, div, buf[0], buf[1], buf[2], buf[3]);
 
 	// calculate the frequency we set it to
-	return (div * desc->entries[i].stepsize) - desc->entries[i].offset;
+	return (div * desc->entries[i].stepsize) - desc->iffreq;
 }
 EXPORT_SYMBOL(dvb_pll_configure);
 
@@ -487,35 +546,27 @@ static int dvb_pll_release(struct dvb_fr
 static int dvb_pll_sleep(struct dvb_frontend *fe)
 {
 	struct dvb_pll_priv *priv = fe->tuner_priv;
-	u8 buf[4];
-	struct i2c_msg msg =
-		{ .addr = priv->pll_i2c_address, .flags = 0,
-		  .buf = buf, .len = sizeof(buf) };
-	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;
-	}
-	if (i == priv->pll_desc->count)
-		return 0;
+	if (priv->pll_desc->sleepdata) {
+		struct i2c_msg msg = { .flags = 0,
+			.addr = priv->pll_i2c_address,
+			.buf = priv->pll_desc->sleepdata + 1,
+			.len = priv->pll_desc->sleepdata[0] };
 
-	buf[0] = 0;
-	buf[1] = 0;
-	buf[2] = priv->pll_desc->entries[i].config;
-	buf[3] = priv->pll_desc->entries[i].cb;
+		int result;
 
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
-		return result;
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+			return result;
+		}
+		return 0;
 	}
-
-	return 0;
+	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
+	return -EINVAL;
 }
 
 static int dvb_pll_set_params(struct dvb_frontend *fe,
@@ -599,9 +650,35 @@ static int dvb_pll_get_bandwidth(struct 
 	return 0;
 }
 
+static int dvb_pll_init(struct dvb_frontend *fe)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+
+	if (priv->i2c == NULL)
+		return -EINVAL;
+
+	if (priv->pll_desc->initdata) {
+		struct i2c_msg msg = { .flags = 0,
+			.addr = priv->pll_i2c_address,
+			.buf = priv->pll_desc->initdata + 1,
+			.len = priv->pll_desc->initdata[0] };
+
+		int result;
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+			return result;
+		}
+		return 0;
+	}
+	/* Shouldn't be called when initdata is NULL, maybe BUG()? */
+	return -EINVAL;
+}
+
 static struct dvb_tuner_ops dvb_pll_tuner_ops = {
 	.release = dvb_pll_release,
 	.sleep = dvb_pll_sleep,
+	.init = dvb_pll_init,
 	.set_params = dvb_pll_set_params,
 	.calc_regs = dvb_pll_calc_regs,
 	.get_frequency = dvb_pll_get_frequency,
@@ -640,9 +717,14 @@ struct dvb_frontend *dvb_pll_attach(stru
 	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
 
-	strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+	strncpy(fe->ops.tuner_ops.info.name, desc->name,
+		sizeof(fe->ops.tuner_ops.info.name));
 	fe->ops.tuner_ops.info.frequency_min = desc->min;
 	fe->ops.tuner_ops.info.frequency_min = desc->max;
+	if (!desc->initdata)
+		fe->ops.tuner_ops.init = NULL;
+	if (!desc->sleepdata)
+		fe->ops.tuner_ops.sleep = NULL;
 
 	fe->tuner_priv = priv;
 	return fe;
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 681186a..5209f46 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -12,11 +12,13 @@ struct dvb_pll_desc {
 	char *name;
 	u32  min;
 	u32  max;
+	u32  iffreq;
 	void (*setbw)(u8 *buf, u32 freq, int bandwidth);
+	u8   *initdata;
+	u8   *sleepdata;
 	int  count;
 	struct {
 		u32 limit;
-		u32 offset;
 		u32 stepsize;
 		u8  config;
 		u8  cb;
@@ -46,6 +48,7 @@ extern struct dvb_pll_desc dvb_pll_phili
 extern struct dvb_pll_desc dvb_pll_philips_td1316;
 
 extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
+extern struct dvb_pll_desc dvb_pll_opera1;
 
 extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
 			     u32 freq, int bandwidth);
@@ -59,9 +62,20 @@ extern int dvb_pll_configure(struct dvb_
  * @param desc dvb_pll_desc to use.
  * @return Frontend pointer on success, NULL on failure
  */
+#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
 extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
 					   int pll_addr,
 					   struct i2c_adapter *i2c,
 					   struct dvb_pll_desc *desc);
+#else
+static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
+					   int pll_addr,
+					   struct i2c_adapter *i2c,
+					   struct dvb_pll_desc *desc)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
 
 #endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 68aad0f..e25286e 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -475,7 +475,7 @@ static int lgdt3302_read_status(struct d
 			*status |= FE_HAS_CARRIER;
 		break;
 	default:
-		printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
 	}
 
 	return 0;
@@ -534,7 +534,7 @@ static int lgdt3303_read_status(struct d
 		}
 		break;
 	default:
-		printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		printk(KERN_WARNING "lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
 	}
 	return 0;
 }
diff --git a/drivers/media/dvb/frontends/lgh06xf.c b/drivers/media/dvb/frontends/lgh06xf.c
deleted file mode 100644
index 2202d0c..0000000
--- a/drivers/media/dvb/frontends/lgh06xf.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *  lgh06xf.c - ATSC Tuner support for LG TDVS-H06xF
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU 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 "dvb-pll.h"
-#include "lgh06xf.h"
-
-#define LG_H06XF_PLL_I2C_ADDR 0x61
-
-struct lgh06xf_priv {
-	struct i2c_adapter *i2c;
-	u32 frequency;
-};
-
-static int lgh06xf_release(struct dvb_frontend *fe)
-{
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
-	return 0;
-}
-
-static int lgh06xf_set_params(struct dvb_frontend* fe,
-			      struct dvb_frontend_parameters* params)
-{
-	struct lgh06xf_priv *priv = fe->tuner_priv;
-	u8 buf[4];
-	struct i2c_msg msg = { .addr = LG_H06XF_PLL_I2C_ADDR, .flags = 0,
-			       .buf = buf, .len = sizeof(buf) };
-	u32 frequency;
-	int result;
-
-	if ((result = dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf,
-					params->frequency, 0)) < 0)
-		return result;
-	else
-		frequency = result;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "lgh06xf: %s error "
-		       "(addr %02x <- %02x, result = %i)\n",
-		       __FUNCTION__, buf[0], buf[1], result);
-		if (result < 0)
-			return result;
-		else
-			return -EREMOTEIO;
-	}
-
-	/* Set the Auxiliary Byte. */
-	buf[0] = buf[2];
-	buf[0] &= ~0x20;
-	buf[0] |= 0x18;
-	buf[1] = 0x50;
-	msg.len = 2;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "lgh06xf: %s error "
-		       "(addr %02x <- %02x, result = %i)\n",
-		       __FUNCTION__, buf[0], buf[1], result);
-		if (result < 0)
-			return result;
-		else
-			return -EREMOTEIO;
-	}
-
-	priv->frequency = frequency;
-
-	return 0;
-}
-
-static int lgh06xf_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct lgh06xf_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
-}
-
-static struct dvb_tuner_ops lgh06xf_tuner_ops = {
-	.release       = lgh06xf_release,
-	.set_params    = lgh06xf_set_params,
-	.get_frequency = lgh06xf_get_frequency,
-};
-
-struct dvb_frontend* lgh06xf_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter *i2c)
-{
-	struct lgh06xf_priv *priv = NULL;
-
-	priv = kzalloc(sizeof(struct lgh06xf_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-
-	priv->i2c = i2c;
-
-	memcpy(&fe->ops.tuner_ops, &lgh06xf_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	strlcpy(fe->ops.tuner_ops.info.name, dvb_pll_lg_tdvs_h06xf.name,
-		sizeof(fe->ops.tuner_ops.info.name));
-
-	fe->ops.tuner_ops.info.frequency_min = dvb_pll_lg_tdvs_h06xf.min;
-	fe->ops.tuner_ops.info.frequency_max = dvb_pll_lg_tdvs_h06xf.max;
-
-	fe->tuner_priv = priv;
-	return fe;
-}
-
-EXPORT_SYMBOL(lgh06xf_attach);
-
-MODULE_DESCRIPTION("LG TDVS-H06xF ATSC Tuner support");
-MODULE_AUTHOR("Michael Krufky");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/lgh06xf.h b/drivers/media/dvb/frontends/lgh06xf.h
deleted file mode 100644
index 510b4be..0000000
--- a/drivers/media/dvb/frontends/lgh06xf.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  lgh06xf.h - ATSC Tuner support for LG TDVS-H06xF
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU 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 _LGH06XF_H_
-#define _LGH06XF_H_
-#include "dvb_frontend.h"
-
-#if defined(CONFIG_DVB_TUNER_LGH06XF) || (defined(CONFIG_DVB_TUNER_LGH06XF_MODULE) && defined(MODULE))
-extern struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
-					    struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* lgh06xf_attach(struct dvb_frontend* fe,
-						  struct i2c_adapter *i2c)
-{
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
-	return NULL;
-}
-#endif /* CONFIG_DVB_TUNER_LGH06XF */
-
-#endif /* _LGH06XF_H_ */
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 5a3a6e5..4e0aca7 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -1,6 +1,9 @@
 /*
  *    Support for OR51132 (pcHDTV HD-3000) - VSB/QAM
  *
+ *
+ *    Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
+ *
  *    Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com>
  *
  *    Based on code from Jack Kelliher (kelliher@xmission.com)
@@ -69,46 +72,70 @@ struct or51132_state
 	u32 current_frequency;
 };
 
-static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len)
+
+/* Write buffer to demod */
+static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len)
 {
 	int err;
-	struct i2c_msg msg;
-	msg.addr  = reg;
-	msg.flags = 0;
-	msg.len   = len;
-	msg.buf   = buf;
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = (u8*)buf, .len = len };
 
+	/* msleep(20); */ /* doesn't appear to be necessary */
 	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err);
+		printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n",
+		       msg.addr, msg.len, err);
 		return -EREMOTEIO;
 	}
-
 	return 0;
 }
 
-static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len)
+/* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00);
+   Less code and more efficient that loading a buffer on the stack with
+   the bytes to send and then calling or51132_writebuf() on that. */
+#define or51132_writebytes(state, data...)  \
+	({ const static u8 _data[] = {data}; \
+	or51132_writebuf(state, _data, sizeof(_data)); })
+
+/* Read data from demod into buffer.  Returns 0 on success. */
+static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len)
 {
 	int err;
-	struct i2c_msg msg;
-	msg.addr   = reg;
-	msg.flags = I2C_M_RD;
-	msg.len = len;
-	msg.buf = buf;
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = I2C_M_RD, .buf = buf, .len = len };
 
+	/* msleep(20); */ /* doesn't appear to be necessary */
 	if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
-		printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err);
+		printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n",
+		       msg.addr, msg.len, err);
 		return -EREMOTEIO;
 	}
-
 	return 0;
 }
 
+/* Reads a 16-bit demod register.  Returns <0 on error. */
+static int or51132_readreg(struct or51132_state *state, u8 reg)
+{
+	u8 buf[2] = { 0x04, reg };
+	struct i2c_msg msg[2] = {
+		{.addr = state->config->demod_address, .flags = 0,
+		 .buf = buf, .len = 2 },
+		{.addr = state->config->demod_address, .flags = I2C_M_RD,
+		 .buf = buf, .len = 2 }};
+	int err;
+
+	if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) {
+		printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n",
+		       reg, err);
+		return -EREMOTEIO;
+	}
+	return le16_to_cpup((u16*)buf);
+}
+
 static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	static u8 run_buf[] = {0x7F,0x01};
+	const static u8 run_buf[] = {0x7F,0x01};
 	u8 rec_buf[8];
-	u8 cmd_buf[3];
 	u32 firmwareAsize, firmwareBsize;
 	int i,ret;
 
@@ -121,30 +148,21 @@ static int or51132_load_firmware (struct
 	dprintk("FirmwareB is %i bytes\n",firmwareBsize);
 
 	/* Upload firmware */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 &fw->data[8],firmwareAsize))) {
+	if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) {
 		printk(KERN_WARNING "or51132: load_firmware error 1\n");
 		return ret;
 	}
-	msleep(1); /* 1ms */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 &fw->data[8+firmwareAsize],firmwareBsize))) {
+	if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize],
+				    firmwareBsize))) {
 		printk(KERN_WARNING "or51132: load_firmware error 2\n");
 		return ret;
 	}
-	msleep(1); /* 1ms */
 
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 run_buf,2))) {
+	if ((ret = or51132_writebuf(state, run_buf, 2))) {
 		printk(KERN_WARNING "or51132: load_firmware error 3\n");
 		return ret;
 	}
-
-	/* Wait at least 5 msec */
-	msleep(20); /* 10ms */
-
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 run_buf,2))) {
+	if ((ret = or51132_writebuf(state, run_buf, 2))) {
 		printk(KERN_WARNING "or51132: load_firmware error 4\n");
 		return ret;
 	}
@@ -154,43 +172,25 @@ static int or51132_load_firmware (struct
 
 	/* Read back ucode version to besure we loaded correctly and are really up and running */
 	/* Get uCode version */
-	cmd_buf[0] = 0x10;
-	cmd_buf[1] = 0x10;
-	cmd_buf[2] = 0x00;
-	msleep(20); /* 20ms */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 cmd_buf,3))) {
+	if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) {
 		printk(KERN_WARNING "or51132: load_firmware error a\n");
 		return ret;
 	}
-
-	cmd_buf[0] = 0x04;
-	cmd_buf[1] = 0x17;
-	msleep(20); /* 20ms */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 cmd_buf,2))) {
+	if ((ret = or51132_writebytes(state, 0x04, 0x17))) {
 		printk(KERN_WARNING "or51132: load_firmware error b\n");
 		return ret;
 	}
-
-	cmd_buf[0] = 0x00;
-	cmd_buf[1] = 0x00;
-	msleep(20); /* 20ms */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 cmd_buf,2))) {
+	if ((ret = or51132_writebytes(state, 0x00, 0x00))) {
 		printk(KERN_WARNING "or51132: load_firmware error c\n");
 		return ret;
 	}
-
-	for(i=0;i<4;i++) {
-		msleep(20); /* 20ms */
+	for (i=0;i<4;i++) {
 		/* Once upon a time, this command might have had something
 		   to do with getting the firmware version, but it's
 		   not used anymore:
 		   {0x04,0x00,0x30,0x00,i+1} */
 		/* Read 8 bytes, two bytes at a time */
-		if ((ret = i2c_readbytes(state,state->config->demod_address,
-					&rec_buf[i*2],2))) {
+		if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) {
 			printk(KERN_WARNING
 			       "or51132: load_firmware error d - %d\n",i);
 			return ret;
@@ -204,12 +204,7 @@ static int or51132_load_firmware (struct
 	       rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f,
 	       rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f);
 
-	cmd_buf[0] = 0x10;
-	cmd_buf[1] = 0x00;
-	cmd_buf[2] = 0x00;
-	msleep(20); /* 20ms */
-	if ((ret = i2c_writebytes(state,state->config->demod_address,
-				 cmd_buf,3))) {
+	if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) {
 		printk(KERN_WARNING "or51132: load_firmware error e\n");
 		return ret;
 	}
@@ -241,70 +236,55 @@ static int or51132_sleep(struct dvb_fron
 static int or51132_setmode(struct dvb_frontend* fe)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	unsigned char cmd_buf[3];
+	u8 cmd_buf1[3] = {0x04, 0x01, 0x5f};
+	u8 cmd_buf2[3] = {0x1c, 0x00, 0 };
 
 	dprintk("setmode %d\n",(int)state->current_modulation);
-	/* set operation mode in Receiver 1 register; */
-	cmd_buf[0] = 0x04;
-	cmd_buf[1] = 0x01;
+
 	switch (state->current_modulation) {
-	case QAM_256:
-	case QAM_64:
-	case QAM_AUTO:
-		/* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/
-		cmd_buf[2] = 0x5F;
-		break;
 	case VSB_8:
-		/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/
-		cmd_buf[2] = 0x50;
+		/* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */
+		cmd_buf1[2] = 0x50;
+		/* REC MODE inv IF spectrum, Normal */
+		cmd_buf2[1] = 0x03;
+		/* Channel MODE ATSC/VSB8 */
+		cmd_buf2[2] = 0x06;
 		break;
-	default:
-		printk("setmode:Modulation set to unsupported value\n");
-	};
-	if (i2c_writebytes(state,state->config->demod_address,
-			   cmd_buf,3)) {
-		printk(KERN_WARNING "or51132: set_mode error 1\n");
-		return -1;
-	}
-	dprintk("or51132: set #1 to %02x\n", cmd_buf[2]);
-
-	/* Set operation mode in Receiver 6 register */
-	cmd_buf[0] = 0x1C;
-	switch (state->current_modulation) {
+	/* All QAM modes are:
+	   Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high
+	   REC MODE Normal Carrier Lock */
 	case QAM_AUTO:
-		/* REC MODE Normal Carrier Lock */
-		cmd_buf[1] = 0x00;
 		/* Channel MODE Auto QAM64/256 */
-		cmd_buf[2] = 0x4f;
+		cmd_buf2[2] = 0x4f;
 		break;
 	case QAM_256:
-		/* REC MODE Normal Carrier Lock */
-		cmd_buf[1] = 0x00;
 		/* Channel MODE QAM256 */
-		cmd_buf[2] = 0x45;
+		cmd_buf2[2] = 0x45;
 		break;
 	case QAM_64:
-		/* REC MODE Normal Carrier Lock */
-		cmd_buf[1] = 0x00;
 		/* Channel MODE QAM64 */
-		cmd_buf[2] = 0x43;
-		break;
-	case VSB_8:
-		 /* REC MODE inv IF spectrum, Normal */
-		cmd_buf[1] = 0x03;
-		/* Channel MODE ATSC/VSB8 */
-		cmd_buf[2] = 0x06;
+		cmd_buf2[2] = 0x43;
 		break;
 	default:
-		printk("setmode: Modulation set to unsupported value\n");
-	};
-	msleep(20); /* 20ms */
-	if (i2c_writebytes(state,state->config->demod_address,
-			   cmd_buf,3)) {
+		printk(KERN_WARNING
+		       "or51132: setmode: Modulation set to unsupported value (%d)\n",
+		       state->current_modulation);
+		return -EINVAL;
+	}
+
+	/* Set Receiver 1 register */
+	if (or51132_writebuf(state, cmd_buf1, 3)) {
+		printk(KERN_WARNING "or51132: set_mode error 1\n");
+		return -EREMOTEIO;
+	}
+	dprintk("set #1 to %02x\n", cmd_buf1[2]);
+
+	/* Set operation mode in Receiver 6 register */
+	if (or51132_writebuf(state, cmd_buf2, 3)) {
 		printk(KERN_WARNING "or51132: set_mode error 2\n");
-		return -1;
+		return -EREMOTEIO;
 	}
-	dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]);
+	dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]);
 
 	return 0;
 }
@@ -401,28 +381,23 @@ static int or51132_get_parameters(struct
 				  struct dvb_frontend_parameters *param)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	u8 buf[2];
+	int status;
+	int retry = 1;
 
+start:
 	/* Receiver Status */
-	buf[0]=0x04;
-	buf[1]=0x00;
-	msleep(30); /* 30ms */
-	if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
-		printk(KERN_WARNING "or51132: get_parameters write error\n");
-		return -EREMOTEIO;
-	}
-	msleep(30); /* 30ms */
-	if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
-		printk(KERN_WARNING "or51132: get_parameters read error\n");
+	if ((status = or51132_readreg(state, 0x00)) < 0) {
+		printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n");
 		return -EREMOTEIO;
 	}
-	switch(buf[0]) {
+	switch(status&0xff) {
 		case 0x06: param->u.vsb.modulation = VSB_8; break;
 		case 0x43: param->u.vsb.modulation = QAM_64; break;
 		case 0x45: param->u.vsb.modulation = QAM_256; break;
 		default:
+			if (retry--) goto start;
 			printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
-			       buf[0]);
+			       status&0xff);
 			return -EREMOTEIO;
 	}
 
@@ -438,32 +413,21 @@ static int or51132_get_parameters(struct
 static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	unsigned char rec_buf[2];
-	unsigned char snd_buf[2];
-	*status = 0;
+	int reg;
 
 	/* Receiver Status */
-	snd_buf[0]=0x04;
-	snd_buf[1]=0x00;
-	msleep(30); /* 30ms */
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-		printk(KERN_WARNING "or51132: read_status write error\n");
-		return -1;
-	}
-	msleep(30); /* 30ms */
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51132: read_status read error\n");
-		return -1;
-	}
-	dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]);
-
-	if (rec_buf[1] & 0x01) { /* Receiver Lock */
-		*status |= FE_HAS_SIGNAL;
-		*status |= FE_HAS_CARRIER;
-		*status |= FE_HAS_VITERBI;
-		*status |= FE_HAS_SYNC;
-		*status |= FE_HAS_LOCK;
+	if ((reg = or51132_readreg(state, 0x00)) < 0) {
+		printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg);
+		*status = 0;
+		return -EREMOTEIO;
 	}
+	dprintk("%s: read_status %04x\n", __FUNCTION__, reg);
+
+	if (reg & 0x0100) /* Receiver Lock */
+		*status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|
+			  FE_HAS_SYNC|FE_HAS_LOCK;
+	else
+		*status = 0;
 	return 0;
 }
 
@@ -506,47 +470,30 @@ static u32 calculate_snr(u32 mse, u32 c)
 static int or51132_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 	struct or51132_state* state = fe->demodulator_priv;
-	u8 rec_buf[2];
-	u8 snd_buf[2];
-	u32 noise;
-	u32 c;
-	u32 usK;
-
-	/* Register is same for VSB or QAM firmware */
-	snd_buf[0]=0x04;
-	snd_buf[1]=0x02; /* SNR after Equalizer */
-	msleep(30); /* 30ms */
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-		printk(KERN_WARNING "or51132: snr write error\n");
-		return -EREMOTEIO;
-	}
-	msleep(30); /* 30ms */
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51132: snr read error\n");
+	int noise, reg;
+	u32 c, usK = 0;
+	int retry = 1;
+
+start:
+	/* SNR after Equalizer */
+	noise = or51132_readreg(state, 0x02);
+	if (noise < 0) {
+		printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n");
 		return -EREMOTEIO;
 	}
-	noise = rec_buf[0] | (rec_buf[1] << 8);
-	dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise);
+	dprintk("read_snr noise (%d)\n", noise);
 
 	/* Read status, contains modulation type for QAM_AUTO and
 	   NTSC filter for VSB */
-	snd_buf[0]=0x04;
-	snd_buf[1]=0x00; /* Status register */
-	msleep(30); /* 30ms */
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) {
-		printk(KERN_WARNING "or51132: status write error\n");
-		return -EREMOTEIO;
-	}
-	msleep(30); /* 30ms */
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51132: status read error\n");
+	reg = or51132_readreg(state, 0x00);
+	if (reg < 0) {
+		printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n");
 		return -EREMOTEIO;
 	}
 
-	usK = 0;
-	switch (rec_buf[0]) {
+	switch (reg&0xff) {
 	case 0x06:
-		usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0;
+		if (reg & 0x1000) usK = 3 << 24;
 		/* Fall through to QAM64 case */
 	case 0x43:
 		c = 150204167;
@@ -555,11 +502,12 @@ static int or51132_read_snr(struct dvb_f
 		c = 150290396;
 		break;
 	default:
-		printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]);
+		printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff);
+		if (retry--) goto start;
 		return -EREMOTEIO;
 	}
 	dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__,
-		rec_buf[0], rec_buf[1]&0x10?"n":"ff");
+		reg&0xff, reg&0x1000?"n":"ff");
 
 	/* Calculate SNR using noise, c, and NTSC rejection correction */
 	state->snr = calculate_snr(noise, c) - usK;
@@ -671,6 +619,7 @@ MODULE_PARM_DESC(debug, "Turn on/off fro
 
 MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver");
 MODULE_AUTHOR("Kirk Lapray");
+MODULE_AUTHOR("Trent Piepho");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(or51132_attach);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 5b9c5bb..1105368 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -30,13 +30,13 @@ #include <linux/string.h>
 #include <linux/slab.h>
 
 #include "dvb_frontend.h"
-#include "tda10021.h"
+#include "tda1002x.h"
 
 
 struct tda10021_state {
 	struct i2c_adapter* i2c;
 	/* configuration settings */
-	const struct tda10021_config* config;
+	const struct tda1002x_config* config;
 	struct dvb_frontend frontend;
 
 	u8 pwm;
@@ -53,9 +53,6 @@ #endif
 static int verbose;
 
 #define XIN 57840000UL
-#define DISABLE_INVERSION(reg0)		do { reg0 |= 0x20; } while (0)
-#define ENABLE_INVERSION(reg0)		do { reg0 &= ~0x20; } while (0)
-#define HAS_INVERSION(reg0)		(!(reg0 & 0x20))
 
 #define FIN (XIN >> 4)
 
@@ -64,7 +61,7 @@ static u8 tda10021_inittab[0x40]=
 {
 	0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
 	0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
-	0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff,
+	0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
 	0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
 	0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
 	0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
@@ -97,7 +94,8 @@ static u8 tda10021_readreg (struct tda10
 	int ret;
 
 	ret = i2c_transfer (state->i2c, msg, 2);
-	if (ret != 2)
+	// Don't print an error message if the id is read.
+	if (ret != 2 && reg != 0x1a)
 		printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
 				__FUNCTION__, ret);
 	return b1[0];
@@ -136,10 +134,10 @@ static int tda10021_setup_reg0 (struct t
 {
 	reg0 |= state->reg0 & 0x63;
 
-	if (INVERSION_ON == inversion)
-		ENABLE_INVERSION(reg0);
-	else if (INVERSION_OFF == inversion)
-		DISABLE_INVERSION(reg0);
+	if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
+		reg0 &= ~0x20;
+	else
+		reg0 |= 0x20;
 
 	_tda10021_writereg (state, 0x00, reg0 & 0xfe);
 	_tda10021_writereg (state, 0x00, reg0 | 0x01);
@@ -201,16 +199,6 @@ static int tda10021_set_symbolrate (stru
 	return 0;
 }
 
-static 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;
@@ -258,6 +246,9 @@ static int tda10021_set_parameters (stru
 	if (qam < 0 || qam > 5)
 		return -EINVAL;
 
+	if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF)
+		return -EINVAL;
+
 	//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
 
 	if (fe->ops.tuner_ops.set_params) {
@@ -366,7 +357,7 @@ static int tda10021_get_frontend(struct 
 		       -((s32)p->u.qam.symbol_rate * afc) >> 10);
 	}
 
-	p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF;
+	p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
 	p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
 
 	p->u.qam.fec_inner = FEC_NONE;
@@ -408,11 +399,12 @@ static void tda10021_release(struct dvb_
 
 static struct dvb_frontend_ops tda10021_ops;
 
-struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
 				     struct i2c_adapter* i2c,
 				     u8 pwm)
 {
 	struct tda10021_state* state = NULL;
+	u8 id;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL);
@@ -425,7 +417,11 @@ struct dvb_frontend* tda10021_attach(con
 	state->reg0 = tda10021_inittab[0];
 
 	/* check if the demod is there */
-	if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+	id = tda10021_readreg(state, 0x1a);
+	if ((id & 0xf0) != 0x70) goto error;
+
+	printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
+	       state->config->demod_address, id);
 
 	/* create dvb_frontend */
 	memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
@@ -447,7 +443,7 @@ static struct dvb_frontend_ops tda10021_
 		.frequency_max = 858000000,
 		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
 		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
-#if 0
+	#if 0
 		.frequency_tolerance = ???,
 		.symbol_rate_tolerance = ???,  /* ppm */  /* == 8% (spec p. 5) */
 	#endif
@@ -461,7 +457,6 @@ #if 0
 
 	.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
deleted file mode 100644
index e3da780..0000000
--- a/drivers/media/dvb/frontends/tda10021.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-    TDA10021  - Single Chip Cable Channel Receiver driver module
-	       used on the the Siemens DVB-C cards
-
-    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
-    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
-		   Support for TDA10021
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU 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 TDA10021_H
-#define TDA10021_H
-
-#include <linux/dvb/frontend.h>
-
-struct tda10021_config
-{
-	/* the demodulator's i2c address */
-	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);
-#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/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
new file mode 100644
index 0000000..da796e7
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -0,0 +1,540 @@
+/*
+    TDA10023  - DVB-C decoder
+    (as used in Philips CU1216-3 NIM and the Reelbox DVB-C tuner card)
+
+    Copyright (C) 2005 Georg Acher, BayCom GmbH (acher at baycom dot de)
+    Copyright (c) 2006 Hartmut Birr (e9hack at gmail dot com)
+
+    Remotely based on tda10021.c
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+		   Support for TDA10021
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "tda1002x.h"
+
+
+struct tda10023_state {
+	struct i2c_adapter* i2c;
+	/* configuration settings */
+	const struct tda1002x_config* config;
+	struct dvb_frontend frontend;
+
+	u8 pwm;
+	u8 reg0;
+};
+
+
+#define dprintk(x...)
+
+static int verbose;
+
+#define XTAL   28920000UL
+#define PLL_M  8UL
+#define PLL_P  4UL
+#define PLL_N  1UL
+#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P))  // -> 57840000
+
+static u8 tda10023_inittab[]={
+	// reg mask val
+	0x2a,0xff,0x02,  // PLL3, Bypass, Power Down
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x2a,0xff,0x03,  // PLL3, Bypass, Power Down
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x28,0xff,PLL_M-1,  // PLL1 M=8
+	0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1),  // PLL2
+	0x00,0xff,0x23,  // GPR FSAMPLING=1
+	0x2a,0xff,0x08,  // PLL3 PSACLK=1
+	0xff,0x64,0x00,  // Sleep 100ms
+	0x1f,0xff,0x00,  // RESET
+	0xff,0x64,0x00,  // Sleep 100ms
+	0xe6,0x0c,0x04,  // RSCFG_IND
+	0x10,0xc0,0x80,  // DECDVBCFG1 PBER=1
+
+	0x0e,0xff,0x82,  // GAIN1
+	0x03,0x08,0x08,  // CLKCONF DYN=1
+	0x2e,0xbf,0x30,  // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
+	0x01,0xff,0x30,  // AGCREF
+	0x1e,0x84,0x84,  // CONTROL SACLK_ON=1
+	0x1b,0xff,0xc8,  // ADC TWOS=1
+	0x3b,0xff,0xff,  // IFMAX
+	0x3c,0xff,0x00,  // IFMIN
+	0x34,0xff,0x00,  // PWMREF
+	0x35,0xff,0xff,  // TUNMAX
+	0x36,0xff,0x00,  // TUNMIN
+	0x06,0xff,0x7f,  // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1    // 0x77
+	0x1c,0x30,0x30,  // EQCONF2 STEPALGO=SGNALGO=1
+	0x37,0xff,0xf6,  // DELTAF_LSB
+	0x38,0xff,0xff,  // DELTAF_MSB
+	0x02,0xff,0x93,  // AGCCONF1  IFS=1 KAGCIF=2 KAGCTUN=3
+	0x2d,0xff,0xf6,  // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
+	0x04,0x10,0x00,   // SWRAMP=1
+	0x12,0xff,0xa1,  // INTP1 POCLKP=1 FEL=1 MFS=0
+	0x2b,0x01,0xa1,  // INTS1
+	0x20,0xff,0x04,  // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
+	0x2c,0xff,0x0d,  // INTP/S TRIP=0 TRIS=0
+	0xc4,0xff,0x00,
+	0xc3,0x30,0x00,
+	0xb5,0xff,0x19,  // ERAGC_THD
+	0x00,0x03,0x01,  // GPR, CLBS soft reset
+	0x00,0x03,0x03,  // GPR, CLBS soft reset
+	0xff,0x64,0x00,  // Sleep 100ms
+	0xff,0xff,0xff
+};
+
+static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
+{
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0 };
+	struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
+				  { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, msg, 2);
+	if (ret != 2)
+		printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
+				 __FUNCTION__, ret);
+	return b1[0];
+}
+
+static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
+{
+	u8 buf[] = { reg, data };
+	struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+	int ret;
+
+	ret = i2c_transfer (state->i2c, &msg, 1);
+	if (ret != 1)
+		printk("DVB: TDA10023(%d): %s, writereg error "
+			"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+			state->frontend.dvb->num, __FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+
+static int tda10023_writebit (struct tda10023_state* state, u8 reg, u8 mask,u8 data)
+{
+	if (mask==0xff)
+		return tda10023_writereg(state, reg, data);
+	else {
+		u8 val;
+		val=tda10023_readreg(state,reg);
+		val&=~mask;
+		val|=(data&mask);
+		return tda10023_writereg(state, reg, val);
+	}
+}
+
+static void tda10023_writetab(struct tda10023_state* state, u8* tab)
+{
+	u8 r,m,v;
+	while (1) {
+		r=*tab++;
+		m=*tab++;
+		v=*tab++;
+		if (r==0xff) {
+			if (m==0xff)
+				break;
+			else
+				msleep(m);
+		}
+		else
+			tda10023_writebit(state,r,m,v);
+	}
+}
+
+//get access to tuner
+static int lock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0xc0 };
+	struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg, 1) != 1)
+	{
+		printk("tda10023: lock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+//release access from tuner
+static int unlock_tuner(struct tda10023_state* state)
+{
+	u8 buf[2] = { 0x0f, 0x40 };
+	struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
+
+	if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
+	{
+		printk("tda10023: unlock tuner fails\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int tda10023_setup_reg0 (struct tda10023_state* state, u8 reg0)
+{
+	reg0 |= state->reg0 & 0x63;
+
+	tda10023_writereg (state, 0x00, reg0 & 0xfe);
+	tda10023_writereg (state, 0x00, reg0 | 0x01);
+
+	state->reg0 = reg0;
+	return 0;
+}
+
+static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
+{
+	s32 BDR;
+	s32 BDRI;
+	s16 SFIL=0;
+	u16 NDEC = 0;
+
+	if (sr > (SYSCLK/(2*4)))
+		sr=SYSCLK/(2*4);
+
+	if (sr<870000)
+		sr=870000;
+
+	if (sr < (u32)(SYSCLK/98.40)) {
+		NDEC=3;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/64.0)) {
+		NDEC=3;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/49.2)) {
+		NDEC=2;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/32.0)) {
+		NDEC=2;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/24.6)) {
+		NDEC=1;
+		SFIL=1;
+	} else if (sr<(u32)(SYSCLK/16.0)) {
+		NDEC=1;
+		SFIL=0;
+	} else if (sr<(u32)(SYSCLK/12.3)) {
+		NDEC=0;
+		SFIL=1;
+	}
+
+	BDRI=SYSCLK*16;
+	BDRI>>=NDEC;
+	BDRI +=sr/2;
+	BDRI /=sr;
+
+	if (BDRI>255)
+		BDRI=255;
+
+	{
+		u64 BDRX;
+
+		BDRX=1<<(24+NDEC);
+		BDRX*=sr;
+		do_div(BDRX,SYSCLK); 	// BDRX/=SYSCLK;
+
+		BDR=(s32)BDRX;
+	}
+//	printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+	tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
+	tda10023_writereg (state, 0x0a, BDR&255);
+	tda10023_writereg (state, 0x0b, (BDR>>8)&255);
+	tda10023_writereg (state, 0x0c, (BDR>>16)&31);
+	tda10023_writereg (state, 0x0d, BDRI);
+	tda10023_writereg (state, 0x3d, (SFIL<<7));
+	return 0;
+}
+
+static int tda10023_init (struct dvb_frontend *fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+
+	tda10023_writetab(state, tda10023_inittab);
+
+	return 0;
+}
+
+static int tda10023_set_parameters (struct dvb_frontend *fe,
+			    struct dvb_frontend_parameters *p)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	static int qamvals[6][6] = {
+		//  QAM   LOCKTHR  MSETH   AREF AGCREFNYQ  ERAGCNYQ_THD
+		{ (5<<2),  0x78,    0x8c,   0x96,   0x78,   0x4c  },  // 4 QAM
+		{ (0<<2),  0x87,    0xa2,   0x91,   0x8c,   0x57  },  // 16 QAM
+		{ (1<<2),  0x64,    0x74,   0x96,   0x8c,   0x57  },  // 32 QAM
+		{ (2<<2),  0x46,    0x43,   0x6a,   0x6a,   0x44  },  // 64 QAM
+		{ (3<<2),  0x36,    0x34,   0x7e,   0x78,   0x4c  },  // 128 QAM
+		{ (4<<2),  0x26,    0x23,   0x6c,   0x5c,   0x3c  },  // 256 QAM
+	};
+
+	int qam = p->u.qam.modulation;
+
+	if (qam < 0 || qam > 5)
+		return -EINVAL;
+
+	if (fe->ops.tuner_ops.set_params) {
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	tda10023_set_symbolrate (state, p->u.qam.symbol_rate);
+	tda10023_writereg (state, 0x05, qamvals[qam][1]);
+	tda10023_writereg (state, 0x08, qamvals[qam][2]);
+	tda10023_writereg (state, 0x09, qamvals[qam][3]);
+	tda10023_writereg (state, 0xb4, qamvals[qam][4]);
+	tda10023_writereg (state, 0xb6, qamvals[qam][5]);
+
+//	tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32));
+//	tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20));
+	tda10023_writebit (state, 0x04, 0x40, 0x40);
+	tda10023_setup_reg0 (state, qamvals[qam][0]);
+
+	return 0;
+}
+
+static int tda10023_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync;
+
+	*status = 0;
+
+	//0x11[1] == CARLOCK -> Carrier locked
+	//0x11[2] == FSYNC -> Frame synchronisation
+	//0x11[3] == FEL -> Front End locked
+	//0x11[6] == NODVB -> DVB Mode Information
+	sync = tda10023_readreg (state, 0x11);
+
+	if (sync & 2)
+		*status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
+
+	if (sync & 4)
+		*status |= FE_HAS_SYNC|FE_HAS_VITERBI;
+
+	if (sync & 8)
+		*status |= FE_HAS_LOCK;
+
+	return 0;
+}
+
+static int tda10023_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c;
+	a=tda10023_readreg(state, 0x14);
+	b=tda10023_readreg(state, 0x15);
+	c=tda10023_readreg(state, 0x16)&0xf;
+	tda10023_writebit (state, 0x10, 0xc0, 0x00);
+
+	*ber = a | (b<<8)| (c<<16);
+	return 0;
+}
+
+static int tda10023_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 ifgain=tda10023_readreg(state, 0x2f);
+
+	u16 gain = ((255-tda10023_readreg(state, 0x17))) + (255-ifgain)/16;
+	// Max raw value is about 0xb0 -> Normalize to >0xf0 after 0x90
+	if (gain>0x90)
+		gain=gain+2*(gain-0x90);
+	if (gain>255)
+		gain=255;
+
+	*strength = (gain<<8)|gain;
+	return 0;
+}
+
+static int tda10023_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	u8 quality = ~tda10023_readreg(state, 0x18);
+	*snr = (quality << 8) | quality;
+	return 0;
+}
+
+static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	u8 a,b,c,d;
+	a= tda10023_readreg (state, 0x74);
+	b= tda10023_readreg (state, 0x75);
+	c= tda10023_readreg (state, 0x76);
+	d= tda10023_readreg (state, 0x77);
+	*ucblocks = a | (b<<8)|(c<<16)|(d<<24);
+
+	tda10023_writebit (state, 0x10, 0x20,0x00);
+	tda10023_writebit (state, 0x10, 0x20,0x20);
+	tda10023_writebit (state, 0x13, 0x01, 0x00);
+
+	return 0;
+}
+
+static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	int sync,inv;
+	s8 afc = 0;
+
+	sync = tda10023_readreg(state, 0x11);
+	afc = tda10023_readreg(state, 0x19);
+	inv = tda10023_readreg(state, 0x04);
+
+	if (verbose) {
+		/* AFC only valid when carrier has been recovered */
+		printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" :
+				  "DVB: TDA10023(%d): [AFC (%d) %dHz]\n",
+			state->frontend.dvb->num, afc,
+		       -((s32)p->u.qam.symbol_rate * afc) >> 10);
+	}
+
+	p->inversion = (inv&0x20?0:1);
+	p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16;
+
+	p->u.qam.fec_inner = FEC_NONE;
+	p->frequency = ((p->frequency + 31250) / 62500) * 62500;
+
+	if (sync & 2)
+		p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10;
+
+	return 0;
+}
+
+static int tda10023_sleep(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	tda10023_writereg (state, 0x1b, 0x02);  /* pdown ADC */
+	tda10023_writereg (state, 0x00, 0x80);  /* standby */
+
+	return 0;
+}
+
+static int tda10023_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+
+	if (enable) {
+		lock_tuner(state);
+	} else {
+		unlock_tuner(state);
+	}
+	return 0;
+}
+
+static void tda10023_release(struct dvb_frontend* fe)
+{
+	struct tda10023_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops tda10023_ops;
+
+struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
+				     struct i2c_adapter* i2c,
+				     u8 pwm)
+{
+	struct tda10023_state* state = NULL;
+	int i;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL);
+	if (state == NULL) goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->pwm = pwm;
+	for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+		if (tda10023_inittab[i] == 0x00) {
+			state->reg0 = tda10023_inittab[i+2];
+			break;
+		}
+	}
+
+	// Wakeup if in standby
+	tda10023_writereg (state, 0x00, 0x33);
+	/* check if the demod is there */
+	if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops tda10023_ops = {
+
+	.info = {
+		.name = "Philips TDA10023 DVB-C",
+		.type = FE_QAM,
+		.frequency_stepsize = 62500,
+		.frequency_min = 51000000,
+		.frequency_max = 858000000,
+		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
+		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
+		.caps = 0x400 | //FE_CAN_QAM_4
+			FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+			FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+			FE_CAN_FEC_AUTO
+	},
+
+	.release = tda10023_release,
+
+	.init = tda10023_init,
+	.sleep = tda10023_sleep,
+	.i2c_gate_ctrl = tda10023_i2c_gate_ctrl,
+
+	.set_frontend = tda10023_set_parameters,
+	.get_frontend = tda10023_get_frontend,
+
+	.read_status = tda10023_read_status,
+	.read_ber = tda10023_read_ber,
+	.read_signal_strength = tda10023_read_signal_strength,
+	.read_snr = tda10023_read_snr,
+	.read_ucblocks = tda10023_read_ucblocks,
+};
+
+
+MODULE_DESCRIPTION("Philips TDA10023 DVB-C demodulator driver");
+MODULE_AUTHOR("Georg Acher, Hartmut Birr");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10023_attach);
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
new file mode 100644
index 0000000..e9094d8
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda1002x.h
@@ -0,0 +1,60 @@
+/*
+    TDA10021/TDA10023  - Single Chip Cable Channel Receiver driver module
+			 used on the the Siemens DVB-C cards
+
+    Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
+    Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
+		   Support for TDA10021
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 TDA1002x_H
+#define TDA1002x_H
+
+#include <linux/dvb/frontend.h>
+
+struct tda1002x_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+	u8 invert;
+};
+
+#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10021
+
+#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
+					    struct i2c_adapter* i2c, u8 pwm)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA10023
+
+#endif // TDA1002x_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index f4a9cf9..33a8437 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -40,20 +40,6 @@ #include <linux/slab.h>
 #include "dvb_frontend.h"
 #include "tda1004x.h"
 
-enum tda1004x_demod {
-	TDA1004X_DEMOD_TDA10045,
-	TDA1004X_DEMOD_TDA10046,
-};
-
-struct tda1004x_state {
-	struct i2c_adapter* i2c;
-	const struct tda1004x_config* config;
-	struct dvb_frontend frontend;
-
-	/* private demod data */
-	enum tda1004x_demod demod_type;
-};
-
 static int debug;
 #define dprintk(args...) \
 	do { \
@@ -507,35 +493,51 @@ static int tda10046_fwupload(struct dvb_
 		tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x80);
 	}
 	tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
+	/* set GPIO 1 and 3 */
+	if (state->config->gpio_config != TDA10046_GPTRI) {
+		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x33);
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f, state->config->gpio_config &0x0f);
+	}
 	/* let the clocks recover from sleep */
-	msleep(5);
+	msleep(10);
 
 	/* The PLLs need to be reprogrammed after sleep */
 	tda10046_init_plls(fe);
+	tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0);
 
 	/* don't re-upload unless necessary */
 	if (tda1004x_check_upload_ok(state) == 0)
 		return 0;
 
+	printk(KERN_INFO "tda1004x: trying to boot from eeprom\n");
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
+	msleep(300);
+	/* don't re-upload unless necessary */
+	if (tda1004x_check_upload_ok(state) == 0)
+		return 0;
+
 	if (state->config->request_firmware != NULL) {
 		/* request the firmware, this will block until someone uploads it */
 		printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
 		ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
 		if (ret) {
-			printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
-			return ret;
+			/* remain compatible to old bug: try to load with tda10045 image name */
+			ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
+			if (ret) {
+				printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+				return ret;
+			} else {
+				printk(KERN_INFO "tda1004x: please rename the firmware file to %s\n",
+						  TDA10046_DEFAULT_FIRMWARE);
+			}
 		}
-		tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-		ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
-		release_firmware(fw);
-		if (ret)
-			return ret;
 	} else {
-		/* boot from firmware eeprom */
-		printk(KERN_INFO "tda1004x: booting from eeprom\n");
-		tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
-		msleep(300);
+		printk(KERN_ERR "tda1004x: no request function defined, can't upload from file\n");
+		return -EIO;
 	}
+	tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+	ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
+	release_firmware(fw);
 	return tda1004x_check_upload_ok(state);
 }
 
@@ -638,37 +640,33 @@ static int tda10046_init(struct dvb_fron
 	switch (state->config->agc_config) {
 	case TDA10046_AGC_DEFAULT:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
 		break;
 	case TDA10046_AGC_IFO_AUTO_NEG:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
 		break;
 	case TDA10046_AGC_IFO_AUTO_POS:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
-		break;
-	case TDA10046_AGC_TDA827X_GP11:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x6a); // set AGC polarities
-		break;
-	case TDA10046_AGC_TDA827X_GP00:
-		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
-		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
-		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x00);  // set AGC polarities
 		break;
-	case TDA10046_AGC_TDA827X_GP01:
+	case TDA10046_AGC_TDA827X:
 		tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02);   // AGC setup
 		tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70);    // AGC Threshold
 		tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize
-		tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x62); // set AGC polarities
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60);  // set AGC polarities
 		break;
 	}
+	if (state->config->ts_mode == 0) {
+		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x40);
+		tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+	} else {
+		tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0xc0, 0x80);
+		tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x10,
+							state->config->invert_oclk << 4);
+	}
 	tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38);
-	tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
+	tda1004x_write_mask (state, TDA10046H_CONF_TRISTATE1, 0x3e, 0x38); // Turn IF AGC output on
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0);	  // }
 	tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
 	tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0);	  // }
@@ -678,7 +676,6 @@ static int tda10046_init(struct dvb_fron
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
 	tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
 	// tda1004x_write_mask(state, 0x50, 0x80, 0x80);         // handle out of guard echoes
-	tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
 
 	return 0;
 }
@@ -705,7 +702,8 @@ static int tda1004x_set_fe(struct dvb_fr
 	// set frequency
 	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.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
 	// Hardcoded to use auto as much as possible on the TDA10045 as it
@@ -1165,6 +1163,7 @@ static int tda1004x_read_ber(struct dvb_
 static int tda1004x_sleep(struct dvb_frontend* fe)
 {
 	struct tda1004x_state* state = fe->demodulator_priv;
+	int gpio_conf;
 
 	switch (state->demod_type) {
 	case TDA1004X_DEMOD_TDA10045:
@@ -1174,6 +1173,13 @@ static int tda1004x_sleep(struct dvb_fro
 	case TDA1004X_DEMOD_TDA10046:
 		/* set outputs to tristate */
 		tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
+		/* invert GPIO 1 and 3 if desired*/
+		gpio_conf = state->config->gpio_config;
+		if (gpio_conf >= TDA10046_GP00_I)
+			tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x0f,
+							(gpio_conf & 0x0f) ^ 0x0a);
+
+		tda1004x_write_mask(state, TDA1004X_CONFADC2, 0xc0, 0xc0);
 		tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
 		break;
 	}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index ec502d7..abae843 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -35,9 +35,23 @@ enum tda10046_agc {
 	TDA10046_AGC_DEFAULT,		/* original configuration */
 	TDA10046_AGC_IFO_AUTO_NEG,	/* IF AGC only, automatic, negtive */
 	TDA10046_AGC_IFO_AUTO_POS,	/* IF AGC only, automatic, positive */
-	TDA10046_AGC_TDA827X_GP11,	/* IF AGC only, special setup for tda827x */
-	TDA10046_AGC_TDA827X_GP00,	/* same as above, but GPIOs 0 */
-	TDA10046_AGC_TDA827X_GP01,	/* same as above, but GPIO3=0 GPIO1=1*/
+	TDA10046_AGC_TDA827X,		/* IF AGC only, special setup for tda827x */
+};
+
+/* Many (hybrid) boards use GPIO 1 and 3
+	GPIO1	analog - dvb switch
+	GPIO3	firmware eeprom address switch
+*/
+enum tda10046_gpio {
+	TDA10046_GPTRI  = 0x00,		/* All GPIOs tristate */
+	TDA10046_GP00   = 0x40,		/* GPIO3=0, GPIO1=0 */
+	TDA10046_GP01   = 0x42,		/* GPIO3=0, GPIO1=1 */
+	TDA10046_GP10   = 0x48,		/* GPIO3=1, GPIO1=0 */
+	TDA10046_GP11   = 0x4a,		/* GPIO3=1, GPIO1=1 */
+	TDA10046_GP00_I = 0x80,		/* GPIO3=0, GPIO1=0, invert in sleep mode*/
+	TDA10046_GP01_I = 0x82,		/* GPIO3=0, GPIO1=1, invert in sleep mode */
+	TDA10046_GP10_I = 0x88,		/* GPIO3=1, GPIO1=0, invert in sleep mode */
+	TDA10046_GP11_I = 0x8a,		/* GPIO3=1, GPIO1=1, invert in sleep mode */
 };
 
 enum tda10046_if {
@@ -47,6 +61,11 @@ enum tda10046_if {
 	TDA10046_FREQ_052,		/* low IF, 5.1667 MHZ for tda9889 */
 };
 
+enum tda10046_tsout {
+	TDA10046_TS_PARALLEL  = 0x00,	/* parallel transport stream, default */
+	TDA10046_TS_SERIAL    = 0x01,	/* serial transport stream */
+};
+
 struct tda1004x_config
 {
 	/* the demodulator's i2c address */
@@ -58,6 +77,9 @@ struct tda1004x_config
 	/* Does the OCLK signal need inverted? */
 	u8 invert_oclk;
 
+	/* parallel or serial transport stream */
+	enum tda10046_tsout ts_mode;
+
 	/* Xtal frequency, 4 or 16MHz*/
 	enum tda10046_xtal xtal_freq;
 
@@ -67,11 +89,35 @@ struct tda1004x_config
 	/* AGC configuration */
 	enum tda10046_agc agc_config;
 
+	/* setting of GPIO1 and 3 */
+	enum tda10046_gpio gpio_config;
+
+	/* slave address and configuration of the tuner */
+	u8 tuner_address;
+	u8 tuner_config;
+	u8 antenna_switch;
+
+	/* if the board uses another I2c Bridge (tda8290), its address */
+	u8 i2c_gate;
+
 	/* request firmware for device */
-	/* set this to NULL if the card has a firmware EEPROM */
 	int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
 };
 
+enum tda1004x_demod {
+	TDA1004X_DEMOD_TDA10045,
+	TDA1004X_DEMOD_TDA10046,
+};
+
+struct tda1004x_state {
+	struct i2c_adapter* i2c;
+	const struct tda1004x_config* config;
+	struct dvb_frontend frontend;
+
+	/* private demod data */
+	enum tda1004x_demod demod_type;
+};
+
 #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);
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
new file mode 100644
index 0000000..256fc4b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda827x.c
@@ -0,0 +1,512 @@
+/*
+ *
+ * (c) 2005 Hartmut Hackmann
+ * (c) 2007 Michael Krufky
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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 "tda827x.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+	do {					    \
+		if (debug) printk(KERN_DEBUG "tda827x: " args); \
+	} while (0)
+
+struct tda827x_priv {
+	int i2c_addr;
+	struct i2c_adapter *i2c_adap;
+	struct tda827x_config *cfg;
+	u32 frequency;
+	u32 bandwidth;
+};
+
+struct tda827x_data {
+	u32 lomax;
+	u8  spd;
+	u8  bs;
+	u8  bp;
+	u8  cp;
+	u8  gc3;
+	u8 div1p5;
+};
+
+static const struct tda827x_data tda827x_dvbt[] = {
+	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+	{ .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+	{ .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+	{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+	{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+	{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
+};
+
+static int tda827xo_set_params(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	u8 buf[14];
+
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+	int i, tuner_freq, if_freq;
+	u32 N;
+
+	dprintk("%s:\n", __FUNCTION__);
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		if_freq = 4000000;
+		break;
+	case BANDWIDTH_7_MHZ:
+		if_freq = 4500000;
+		break;
+	default:		   /* 8 MHz or Auto */
+		if_freq = 5000000;
+		break;
+	}
+	tuner_freq = params->frequency + if_freq;
+
+	i = 0;
+	while (tda827x_dvbt[i].lomax < tuner_freq) {
+		if(tda827x_dvbt[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
+	buf[0] = 0;
+	buf[1] = (N>>8) | 0x40;
+	buf[2] = N & 0xff;
+	buf[3] = 0;
+	buf[4] = 0x52;
+	buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
+				(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
+	buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
+	buf[7] = 0xbf;
+	buf[8] = 0x2a;
+	buf[9] = 0x05;
+	buf[10] = 0xff;
+	buf[11] = 0x00;
+	buf[12] = 0x00;
+	buf[13] = 0x40;
+
+	msg.len = 14;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+		printk("%s: could not write to tuner at addr: 0x%02x\n",
+		       __FUNCTION__, priv->i2c_addr << 1);
+		return -EIO;
+	}
+	msleep(500);
+	/* correct CP value */
+	buf[0] = 0x30;
+	buf[1] = 0x50 + tda827x_dvbt[i].cp;
+	msg.len = 2;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = tuner_freq - if_freq; // FIXME
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+	return 0;
+}
+
+static int tda827xo_sleep(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	static u8 buf[] = { 0x30, 0xd0 };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	dprintk("%s:\n", __FUNCTION__);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	if (priv->cfg && priv->cfg->sleep)
+		priv->cfg->sleep(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+	u32 lomax;
+	u8  svco;
+	u8  spd;
+	u8  scr;
+	u8  sbs;
+	u8  gc3;
+};
+
+static const struct tda827xa_data tda827xa_dvbt[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
+static int tda827xa_set_params(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	u8 buf[11];
+
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	int i, tuner_freq, if_freq;
+	u32 N;
+
+	dprintk("%s:\n", __FUNCTION__);
+	if (priv->cfg && priv->cfg->lna_gain)
+		priv->cfg->lna_gain(fe, 1);
+	msleep(20);
+
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		if_freq = 4000000;
+		break;
+	case BANDWIDTH_7_MHZ:
+		if_freq = 4500000;
+		break;
+	default:		   /* 8 MHz or Auto */
+		if_freq = 5000000;
+		break;
+	}
+	tuner_freq = params->frequency + if_freq;
+
+	i = 0;
+	while (tda827xa_dvbt[i].lomax < tuner_freq) {
+		if(tda827xa_dvbt[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+	buf[0] = 0;            // subaddress
+	buf[1] = N >> 8;
+	buf[2] = N & 0xff;
+	buf[3] = 0;
+	buf[4] = 0x16;
+	buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+			tda827xa_dvbt[i].sbs;
+	buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+	buf[7] = 0x1c;
+	buf[8] = 0x06;
+	buf[9] = 0x24;
+	buf[10] = 0x00;
+	msg.len = 11;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+		printk("%s: could not write to tuner at addr: 0x%02x\n",
+		       __FUNCTION__, priv->i2c_addr << 1);
+		return -EIO;
+	}
+	buf[0] = 0x90;
+	buf[1] = 0xff;
+	buf[2] = 0x60;
+	buf[3] = 0x00;
+	buf[4] = 0x59;  // lpsel, for 6MHz + 2
+	msg.len = 5;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	buf[0] = 0xa0;
+	buf[1] = 0x40;
+	msg.len = 2;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(11);
+	msg.flags = I2C_M_RD;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+	msg.flags = 0;
+
+	buf[1] >>= 4;
+	dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
+	if ((buf[1]) < 2) {
+		if (priv->cfg && priv->cfg->lna_gain)
+			priv->cfg->lna_gain(fe, 0);
+		buf[0] = 0x60;
+		buf[1] = 0x0c;
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		i2c_transfer(priv->i2c_adap, &msg, 1);
+	}
+
+	buf[0] = 0xc0;
+	buf[1] = 0x99;    // lpsel, for 6MHz + 2
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	buf[0] = 0x60;
+	buf[1] = 0x3c;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	/* correct CP value */
+	buf[0] = 0x30;
+	buf[1] = 0x10 + tda827xa_dvbt[i].scr;
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(163);
+	buf[0] = 0xc0;
+	buf[1] = 0x39;  // lpsel, for 6MHz + 2
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(3);
+	/* freeze AGC1 */
+	buf[0] = 0x50;
+	buf[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = tuner_freq - if_freq; // FIXME
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+	return 0;
+}
+
+static int tda827xa_sleep(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	static u8 buf[] = { 0x30, 0x90 };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	dprintk("%s:\n", __FUNCTION__);
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0);
+
+	if (priv->cfg && priv->cfg->sleep)
+		priv->cfg->sleep(fe);
+
+	return 0;
+}
+
+static int tda827x_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int tda827x_init(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	dprintk("%s:\n", __FUNCTION__);
+	if (priv->cfg && priv->cfg->init)
+		priv->cfg->init(fe);
+
+	return 0;
+}
+
+static int tda827x_probe_version(struct dvb_frontend *fe);
+
+static int tda827x_initial_init(struct dvb_frontend *fe)
+{
+	int ret;
+	ret = tda827x_probe_version(fe);
+	if (ret)
+		return ret;
+	return fe->ops.tuner_ops.init(fe);
+}
+
+static int tda827x_initial_sleep(struct dvb_frontend *fe)
+{
+	int ret;
+	ret = tda827x_probe_version(fe);
+	if (ret)
+		return ret;
+	return fe->ops.tuner_ops.sleep(fe);
+}
+
+static struct dvb_tuner_ops tda827xo_tuner_ops = {
+	.info = {
+		.name = "Philips TDA827X",
+		.frequency_min  =  55000000,
+		.frequency_max  = 860000000,
+		.frequency_step =    250000
+	},
+	.release = tda827x_release,
+	.init = tda827x_initial_init,
+	.sleep = tda827x_initial_sleep,
+	.set_params = tda827xo_set_params,
+	.get_frequency = tda827x_get_frequency,
+	.get_bandwidth = tda827x_get_bandwidth,
+};
+
+static struct dvb_tuner_ops tda827xa_tuner_ops = {
+	.info = {
+		.name = "Philips TDA827XA",
+		.frequency_min  =  44000000,
+		.frequency_max  = 906000000,
+		.frequency_step =     62500
+	},
+	.release = tda827x_release,
+	.init = tda827x_init,
+	.sleep = tda827xa_sleep,
+	.set_params = tda827xa_set_params,
+	.get_frequency = tda827x_get_frequency,
+	.get_bandwidth = tda827x_get_bandwidth,
+};
+
+static int tda827x_probe_version(struct dvb_frontend *fe)
+{	u8 data;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+			       .buf = &data, .len = 1 };
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
+		printk("%s: could not read from tuner at addr: 0x%02x\n",
+		       __FUNCTION__, msg.addr << 1);
+		return -EIO;
+	}
+	if ((data & 0x3c) == 0) {
+		dprintk("tda827x tuner found\n");
+		fe->ops.tuner_ops.init  = tda827x_init;
+		fe->ops.tuner_ops.sleep = tda827xo_sleep;
+	} else {
+		dprintk("tda827xa tuner found\n");
+		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
+	}
+	return 0;
+}
+
+struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
+				    struct i2c_adapter *i2c,
+				    struct tda827x_config *cfg)
+{
+	struct tda827x_priv *priv = NULL;
+
+	dprintk("%s:\n", __FUNCTION__);
+	priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->i2c_addr = addr;
+	priv->i2c_adap = i2c;
+	priv->cfg = cfg;
+	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+
+EXPORT_SYMBOL(tda827x_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB TDA827x driver");
+MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
new file mode 100644
index 0000000..69e8263
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda827x.h
@@ -0,0 +1,62 @@
+  /*
+     DVB Driver for Philips tda827x / tda827xa Silicon tuners
+
+     (c) 2005 Hartmut Hackmann
+     (c) 2007 Michael Krufky
+
+     This program is free software; you can redistribute it and/or modify
+     it under the terms of the GNU 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_TDA827X_H__
+#define __DVB_TDA827X_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda827x_config
+{
+	void (*lna_gain) (struct dvb_frontend *fe, int high);
+	int (*init) (struct dvb_frontend *fe);
+	int (*sleep) (struct dvb_frontend *fe);
+};
+
+
+/**
+ * Attach a tda827x 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 cfg optional callback function pointers.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE))
+extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
+					   struct i2c_adapter *i2c,
+					   struct tda827x_config *cfg);
+#else
+static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe,
+						  int addr,
+						  struct i2c_adapter *i2c,
+						  struct tda827x_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TDA827X
+
+#endif // __DVB_TDA827X_H__
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
index 9b84b1b..7d8e6e8 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -2,7 +2,6 @@ config DVB_PLUTO2
 	tristate "Pluto2 cards"
 	depends on DVB_CORE && PCI && I2C
 	select I2C_ALGOBIT
-	select DVB_PLL
 	select DVB_TDA1004X
 	help
 	  Support for PCI cards based on the Pluto2 FPGA like the Satelco
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index eec7ccf..7751628 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -3,7 +3,6 @@ config DVB_AV7110
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select FW_LOADER if !DVB_AV7110_FIRMWARE
 	select VIDEO_SAA7146_VV
-	select DVB_PLL
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
@@ -62,13 +61,13 @@ config DVB_BUDGET
 	tristate "Budget cards"
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146
-	select DVB_PLL
 	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_TDA10023 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
@@ -87,7 +86,6 @@ config DVB_BUDGET_CI
 	tristate "Budget cards with onboard CI connector"
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146
-	select DVB_PLL
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -114,6 +112,7 @@ config DVB_BUDGET_AV
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+	select DVB_TDA10023 if !DVB_FE_CUSTOMISE
 	select DVB_TUA6100 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
@@ -130,7 +129,6 @@ config DVB_BUDGET_PATCH
 	tristate "AV7110 cards with Budget Patch"
 	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
 	select DVB_AV7110
-	select DVB_PLL
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 29ed532..67becdd 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -219,7 +219,10 @@ static void recover_arm(struct av7110 *a
 		av7110->recover(av7110);
 
 	restart_feeds(av7110);
-	av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+	av7110_check_ir_config(av7110, true);
+#endif
 }
 
 static void av7110_arm_sync(struct av7110 *av7110)
@@ -250,6 +253,10 @@ static int arm_thread(void *data)
 		if (!av7110->arm_ready)
 			continue;
 
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+		av7110_check_ir_config(av7110, false);
+#endif
+
 		if (mutex_lock_interruptible(&av7110->dcomlock))
 			break;
 		newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
@@ -667,8 +674,8 @@ static void gpioirq(unsigned long data)
 		return;
 
 	case DATA_IRCOMMAND:
-		if (av7110->ir_handler)
-			av7110->ir_handler(av7110,
+		if (av7110->ir.ir_handler)
+			av7110->ir.ir_handler(av7110,
 				swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4)));
 		iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
 		break;
@@ -1907,8 +1914,10 @@ static int av7110_fe_lock_fix(struct av7
 	if (av7110->fe_synced == synced)
 		return 0;
 
-	if (av7110->playing)
+	if (av7110->playing) {
+		av7110->fe_synced = synced;
 		return 0;
+	}
 
 	if (mutex_lock_interruptible(&av7110->pid_mutex))
 		return -ERESTARTSYS;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index b98bd45..115002b 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -5,6 +5,7 @@ #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/netdevice.h>
 #include <linux/i2c.h>
+#include <linux/input.h>
 
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
@@ -66,6 +67,27 @@ struct dvb_video_events {
 };
 
 
+struct av7110;
+
+/* infrared remote control */
+struct infrared {
+	u16	key_map[256];
+	struct input_dev	*input_dev;
+	char			input_phys[32];
+	struct timer_list	keyup_timer;
+	struct tasklet_struct	ir_tasklet;
+	void			(*ir_handler)(struct av7110 *av7110, u32 ircom);
+	u32			ir_command;
+	u32			ir_config;
+	u32			device_mask;
+	u8			protocol;
+	u8			inversion;
+	u16			last_key;
+	u16			last_toggle;
+	u8			delay_timer_finished;
+};
+
+
 /* place to store all the necessary device information */
 struct av7110 {
 
@@ -227,10 +249,7 @@ #define TRICK_FREEZE 3
 	u16			wssMode;
 	u16			wssData;
 
-	u32			ir_config;
-	u32			ir_command;
-	void			(*ir_handler)(struct av7110 *av7110, u32 ircom);
-	struct tasklet_struct	ir_tasklet;
+	struct infrared		ir;
 
 	/* firmware stuff */
 	unsigned char *bin_fw;
@@ -268,6 +287,7 @@ #define TRICK_FREEZE 3
 extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
 		       u16 subpid, u16 pcrpid);
 
+extern int av7110_check_ir_config(struct av7110 *av7110, int force);
 extern int av7110_ir_init(struct av7110 *av7110);
 extern void av7110_ir_exit(struct av7110 *av7110);
 
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index e719af8..58678c0 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -32,7 +32,6 @@ #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 
 #include "av7110.h"
@@ -1009,7 +1008,7 @@ static int dvb_video_ioctl(struct inode 
 		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
 			ret = av7110_av_stop(av7110, RP_VIDEO);
 		else
-			ret = vidcom(av7110, VIDEO_CMD_STOP,
+			ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
 			       av7110->videostate.video_blank ? 0 : 1);
 		if (!ret)
 			av7110->trickmode = TRICK_NONE;
@@ -1019,7 +1018,7 @@ static int dvb_video_ioctl(struct inode 
 		av7110->trickmode = TRICK_NONE;
 		if (av7110->videostate.play_state == VIDEO_FREEZED) {
 			av7110->videostate.play_state = VIDEO_PLAYING;
-			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
 			if (ret)
 				break;
 		}
@@ -1034,7 +1033,7 @@ static int dvb_video_ioctl(struct inode 
 			ret = av7110_av_start_play(av7110, RP_VIDEO);
 		}
 		if (!ret)
-			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
 		if (!ret)
 			av7110->videostate.play_state = VIDEO_PLAYING;
 		break;
@@ -1044,7 +1043,7 @@ static int dvb_video_ioctl(struct inode 
 		if (av7110->playing & RP_VIDEO)
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
 		else
-			ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1);
+			ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
 		if (!ret)
 			av7110->trickmode = TRICK_FREEZE;
 		break;
@@ -1053,7 +1052,7 @@ static int dvb_video_ioctl(struct inode 
 		if (av7110->playing & RP_VIDEO)
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
 		if (!ret)
-			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
 		if (!ret) {
 			av7110->videostate.play_state = VIDEO_PLAYING;
 			av7110->trickmode = TRICK_NONE;
@@ -1136,7 +1135,7 @@ static int dvb_video_ioctl(struct inode 
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 					    __Scan_I, 2, AV_PES, 0);
 		else
-			ret = vidcom(av7110, VIDEO_CMD_FFWD, arg);
+			ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);
 		if (!ret) {
 			av7110->trickmode = TRICK_FAST;
 			av7110->videostate.play_state = VIDEO_PLAYING;
@@ -1147,13 +1146,13 @@ static int dvb_video_ioctl(struct inode 
 		if (av7110->playing&RP_VIDEO) {
 			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
 			if (!ret)
-				ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
+				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
 		} else {
-			ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
 			if (!ret)
-				ret = vidcom(av7110, VIDEO_CMD_STOP, 0);
+				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);
 			if (!ret)
-				ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
+				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
 		}
 		if (!ret) {
 			av7110->trickmode = TRICK_SLOW;
@@ -1182,10 +1181,10 @@ static int dvb_video_ioctl(struct inode 
 				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
 						    __Slow, 2, 0, 0);
 				if (!ret)
-					ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
+					ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
 			}
 			if (av7110->trickmode == TRICK_FREEZE)
-				ret = vidcom(av7110, VIDEO_CMD_STOP, 1);
+				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);
 		}
 		break;
 
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e9b4e88..e1c1294 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -34,7 +34,6 @@ #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 
 #include "av7110.h"
 #include "av7110_hw.h"
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 4d7150e..70aee4e 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -33,7 +33,6 @@ #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 
 #include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 4e173c6..673d9b3 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -216,11 +216,11 @@ #define VID_VC_AND_PS_PREF	0x03	/* PanSc
 #define VID_CENTRE_CUT_PREF	0x05	/* PanScan with zero vector */
 
 /* MPEG video decoder commands */
-#define VIDEO_CMD_STOP		0x000e
-#define VIDEO_CMD_PLAY		0x000d
-#define VIDEO_CMD_FREEZE	0x0102
-#define VIDEO_CMD_FFWD		0x0016
-#define VIDEO_CMD_SLOW		0x0022
+#define AV_VIDEO_CMD_STOP	0x000e
+#define AV_VIDEO_CMD_PLAY	0x000d
+#define AV_VIDEO_CMD_FREEZE	0x0102
+#define AV_VIDEO_CMD_FFWD	0x0016
+#define AV_VIDEO_CMD_SLOW	0x0022
 
 /* MPEG audio decoder commands */
 #define AUDIO_CMD_MUTE		0x0001
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index f59465b..a97f166 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -1,8 +1,31 @@
+/*
+ * Driver for the remote control of SAA7146 based AV7110 cards
+ *
+ * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de>
+ * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/input.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
 #include <asm/bitops.h>
@@ -10,18 +33,37 @@ #include <asm/bitops.h>
 #include "av7110.h"
 #include "av7110_hw.h"
 
-#define UP_TIMEOUT (HZ*7/25)
 
-/* enable ir debugging by or'ing debug with 16 */
+#define AV_CNT		4
+
+#define IR_RC5		0
+#define IR_RCMM		1
+#define IR_RC5_EXT	2 /* internal only */
+
+#define IR_ALL		0xffffffff
+
+#define UP_TIMEOUT	(HZ*7/25)
 
-static int av_cnt;
-static struct av7110 *av_list[4];
-static struct input_dev *input_dev;
-static char input_phys[32];
 
-static u8 delay_timer_finished;
+/* Note: enable ir debugging by or'ing debug with 16 */
+
+static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
+module_param_array(ir_protocol, int, NULL, 0644);
+MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
+
+static int ir_inversion[AV_CNT];
+module_param_array(ir_inversion, int, NULL, 0644);
+MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted");
+
+static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
+module_param_array(ir_device_mask, uint, NULL, 0644);
+MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)");
+
+
+static int av_cnt;
+static struct av7110 *av_list[AV_CNT];
 
-static u16 key_map [256] = {
+static u16 default_key_map [256] = {
 	KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
 	KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
 	KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -45,141 +87,194 @@ static u16 key_map [256] = {
 };
 
 
-static void av7110_emit_keyup(unsigned long data)
+/* key-up timer */
+static void av7110_emit_keyup(unsigned long parm)
 {
-	if (!data || !test_bit(data, input_dev->key))
+	struct infrared *ir = (struct infrared *) parm;
+
+	if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
 		return;
 
-	input_report_key(input_dev, data, 0);
-	input_sync(input_dev);
+	input_report_key(ir->input_dev, ir->last_key, 0);
+	input_sync(ir->input_dev);
 }
 
 
-static struct timer_list keyup_timer = { .function = av7110_emit_keyup };
-
-
+/* tasklet */
 static void av7110_emit_key(unsigned long parm)
 {
-	struct av7110 *av7110 = (struct av7110 *) parm;
-	u32 ir_config = av7110->ir_config;
-	u32 ircom = av7110->ir_command;
+	struct infrared *ir = (struct infrared *) parm;
+	u32 ircom = ir->ir_command;
 	u8 data;
 	u8 addr;
-	static u16 old_toggle = 0;
-	u16 new_toggle;
+	u16 toggle;
 	u16 keycode;
 
 	/* extract device address and data */
-	switch (ir_config & 0x0003) {
-	case 0:	/* RC5: 5 bits device address, 6 bits data */
+	switch (ir->protocol) {
+	case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
 		data = ircom & 0x3f;
 		addr = (ircom >> 6) & 0x1f;
+		toggle = ircom & 0x0800;
 		break;
 
-	case 1:	/* RCMM: 8(?) bits device address, 8(?) bits data */
+	case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
 		data = ircom & 0xff;
-		addr = (ircom >> 8) & 0xff;
+		addr = (ircom >> 8) & 0x1f;
+		toggle = ircom & 0x8000;
 		break;
 
-	case 2:	/* extended RC5: 5 bits device address, 7 bits data */
+	case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
 		data = ircom & 0x3f;
 		addr = (ircom >> 6) & 0x1f;
 		/* invert 7th data bit for backward compatibility with RC5 keymaps */
 		if (!(ircom & 0x1000))
 			data |= 0x40;
+		toggle = ircom & 0x0800;
 		break;
 
 	default:
-		printk("invalid ir_config %x\n", ir_config);
+		printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol);
 		return;
 	}
 
-	keycode = key_map[data];
+	input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data);
+	input_event(ir->input_dev, EV_MSC, MSC_SCAN, data);
 
-	dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n",
-		ircom, addr, data, keycode);
+	keycode = ir->key_map[data];
 
-	/* check device address (if selected) */
-	if (ir_config & 0x4000)
-		if (addr != ((ir_config >> 16) & 0xff))
-			return;
+	dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
+		__FUNCTION__, ircom, addr, data, keycode);
+
+	/* check device address */
+	if (!(ir->device_mask & (1 << addr)))
+		return;
 
 	if (!keycode) {
-		printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data);
+		printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n",
+			__FUNCTION__, ircom, addr, data);
 		return;
 	}
 
-	if ((ir_config & 0x0003) == 1)
-		new_toggle = 0; /* RCMM */
-	else
-		new_toggle = (ircom & 0x800); /* RC5, extended RC5 */
-
-	if (timer_pending(&keyup_timer)) {
-		del_timer(&keyup_timer);
-		if (keyup_timer.data != keycode || new_toggle != old_toggle) {
-			delay_timer_finished = 0;
-			input_event(input_dev, EV_KEY, keyup_timer.data, 0);
-			input_event(input_dev, EV_KEY, keycode, 1);
-			input_sync(input_dev);
-		} else if (delay_timer_finished) {
-			input_event(input_dev, EV_KEY, keycode, 2);
-			input_sync(input_dev);
+	if (timer_pending(&ir->keyup_timer)) {
+		del_timer(&ir->keyup_timer);
+		if (ir->last_key != keycode || toggle != ir->last_toggle) {
+			ir->delay_timer_finished = 0;
+			input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
+			input_event(ir->input_dev, EV_KEY, keycode, 1);
+			input_sync(ir->input_dev);
+		} else if (ir->delay_timer_finished) {
+			input_event(ir->input_dev, EV_KEY, keycode, 2);
+			input_sync(ir->input_dev);
 		}
 	} else {
-		delay_timer_finished = 0;
-		input_event(input_dev, EV_KEY, keycode, 1);
-		input_sync(input_dev);
+		ir->delay_timer_finished = 0;
+		input_event(ir->input_dev, EV_KEY, keycode, 1);
+		input_sync(ir->input_dev);
 	}
 
-	keyup_timer.expires = jiffies + UP_TIMEOUT;
-	keyup_timer.data = keycode;
+	ir->last_key = keycode;
+	ir->last_toggle = toggle;
 
-	add_timer(&keyup_timer);
+	ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
+	add_timer(&ir->keyup_timer);
 
-	old_toggle = new_toggle;
 }
 
-static void input_register_keys(void)
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
 {
 	int i;
 
-	memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
+	set_bit(EV_KEY, ir->input_dev->evbit);
+	set_bit(EV_REP, ir->input_dev->evbit);
+	set_bit(EV_MSC, ir->input_dev->evbit);
 
-	for (i = 0; i < ARRAY_SIZE(key_map); i++) {
-		if (key_map[i] > KEY_MAX)
-			key_map[i] = 0;
-		else if (key_map[i] > KEY_RESERVED)
-			set_bit(key_map[i], input_dev->keybit);
+	set_bit(MSC_RAW, ir->input_dev->mscbit);
+	set_bit(MSC_SCAN, ir->input_dev->mscbit);
+
+	memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+	for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
+		if (ir->key_map[i] > KEY_MAX)
+			ir->key_map[i] = 0;
+		else if (ir->key_map[i] > KEY_RESERVED)
+			set_bit(ir->key_map[i], ir->input_dev->keybit);
 	}
+
+	ir->input_dev->keycode = ir->key_map;
+	ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
 }
 
 
-static void input_repeat_key(unsigned long data)
+/* called by the input driver after rep[REP_DELAY] ms */
+static void input_repeat_key(unsigned long parm)
 {
-	/* called by the input driver after rep[REP_DELAY] ms */
-	delay_timer_finished = 1;
+	struct infrared *ir = (struct infrared *) parm;
+
+	ir->delay_timer_finished = 1;
 }
 
 
-static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
+/* check for configuration changes */
+int av7110_check_ir_config(struct av7110 *av7110, int force)
 {
-	int ret = 0;
+	int i;
+	int modified = force;
+	int ret = -ENODEV;
 
-	dprintk(4, "%p\n", av7110);
-	if (av7110) {
-		ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
-		av7110->ir_config = ir_config;
+	for (i = 0; i < av_cnt; i++)
+		if (av7110 == av_list[i])
+			break;
+
+	if (i < av_cnt && av7110) {
+		if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
+		    av7110->ir.inversion != ir_inversion[i])
+			modified = true;
+
+		if (modified) {
+			/* protocol */
+			if (ir_protocol[i]) {
+				ir_protocol[i] = 1;
+				av7110->ir.protocol = IR_RCMM;
+				av7110->ir.ir_config = 0x0001;
+			} else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
+				av7110->ir.protocol = IR_RC5_EXT;
+				av7110->ir.ir_config = 0x0002;
+			} else {
+				av7110->ir.protocol = IR_RC5;
+				av7110->ir.ir_config = 0x0000;
+			}
+			/* inversion */
+			if (ir_inversion[i]) {
+				ir_inversion[i] = 1;
+				av7110->ir.ir_config |= 0x8000;
+			}
+			av7110->ir.inversion = ir_inversion[i];
+			/* update ARM */
+			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
+						av7110->ir.ir_config);
+		} else
+			ret = 0;
+
+		/* address */
+		if (av7110->ir.device_mask != ir_device_mask[i])
+			av7110->ir.device_mask = ir_device_mask[i];
 	}
+
 	return ret;
 }
 
 
+/* /proc/av7110_ir interface */
 static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
 				unsigned long count, void *data)
 {
 	char *page;
-	int size = 4 + 256 * sizeof(u16);
 	u32 ir_config;
+	int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
 	int i;
 
 	if (count < size)
@@ -194,71 +289,86 @@ static int av7110_ir_write_proc(struct f
 		return -EFAULT;
 	}
 
-	memcpy(&ir_config, page, 4);
-	memcpy(&key_map, page + 4, 256 * sizeof(u16));
+	memcpy(&ir_config, page, sizeof ir_config);
+
+	for (i = 0; i < av_cnt; i++) {
+		/* keymap */
+		memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
+			sizeof(av_list[i]->ir.key_map));
+		/* protocol, inversion, address */
+		ir_protocol[i] = ir_config & 0x0001;
+		ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
+		if (ir_config & 0x4000)
+			ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
+		else
+			ir_device_mask[i] = IR_ALL;
+		/* update configuration */
+		av7110_check_ir_config(av_list[i], false);
+		input_register_keys(&av_list[i]->ir);
+	}
 	vfree(page);
-	if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001))
-		ir_config |= 0x0002; /* enable extended RC5 */
-	for (i = 0; i < av_cnt; i++)
-		av7110_setup_irc_config(av_list[i], ir_config);
-	input_register_keys();
 	return count;
 }
 
 
+/* interrupt handler */
 static void ir_handler(struct av7110 *av7110, u32 ircom)
 {
-	dprintk(4, "ircommand = %08x\n", ircom);
-	av7110->ir_command = ircom;
-	tasklet_schedule(&av7110->ir_tasklet);
+	dprintk(4, "ir command = %08x\n", ircom);
+	av7110->ir.ir_command = ircom;
+	tasklet_schedule(&av7110->ir.ir_tasklet);
 }
 
 
 int __devinit av7110_ir_init(struct av7110 *av7110)
 {
+	struct input_dev *input_dev;
 	static struct proc_dir_entry *e;
 	int err;
 
 	if (av_cnt >= ARRAY_SIZE(av_list))
 		return -ENOSPC;
 
-	av7110_setup_irc_config(av7110, 0x0001);
 	av_list[av_cnt++] = av7110;
+	av7110_check_ir_config(av7110, true);
 
-	if (av_cnt == 1) {
-		init_timer(&keyup_timer);
-		keyup_timer.data = 0;
-
-		input_dev = input_allocate_device();
-		if (!input_dev)
-			return -ENOMEM;
-
-		snprintf(input_phys, sizeof(input_phys),
-			"pci-%s/ir0", pci_name(av7110->dev->pci));
-
-		input_dev->name = "DVB on-card IR receiver";
-
-		input_dev->phys = input_phys;
-		input_dev->id.bustype = BUS_PCI;
-		input_dev->id.version = 1;
-		if (av7110->dev->pci->subsystem_vendor) {
-			input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
-			input_dev->id.product = av7110->dev->pci->subsystem_device;
-		} else {
-			input_dev->id.vendor = av7110->dev->pci->vendor;
-			input_dev->id.product = av7110->dev->pci->device;
-		}
-		input_dev->cdev.dev = &av7110->dev->pci->dev;
-		set_bit(EV_KEY, input_dev->evbit);
-		set_bit(EV_REP, input_dev->evbit);
-		input_register_keys();
-		err = input_register_device(input_dev);
-		if (err) {
-			input_free_device(input_dev);
-			return err;
-		}
-		input_dev->timer.function = input_repeat_key;
+	init_timer(&av7110->ir.keyup_timer);
+	av7110->ir.keyup_timer.function = av7110_emit_keyup;
+	av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
 
+	av7110->ir.input_dev = input_dev;
+	snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
+		"pci-%s/ir0", pci_name(av7110->dev->pci));
+
+	input_dev->name = "DVB on-card IR receiver";
+
+	input_dev->phys = av7110->ir.input_phys;
+	input_dev->id.bustype = BUS_PCI;
+	input_dev->id.version = 2;
+	if (av7110->dev->pci->subsystem_vendor) {
+		input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+		input_dev->id.product = av7110->dev->pci->subsystem_device;
+	} else {
+		input_dev->id.vendor = av7110->dev->pci->vendor;
+		input_dev->id.product = av7110->dev->pci->device;
+	}
+	input_dev->cdev.dev = &av7110->dev->pci->dev;
+	/* initial keymap */
+	memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
+	input_register_keys(&av7110->ir);
+	err = input_register_device(input_dev);
+	if (err) {
+		input_free_device(input_dev);
+		return err;
+	}
+	input_dev->timer.function = input_repeat_key;
+	input_dev->timer.data = (unsigned long) &av7110->ir;
+
+	if (av_cnt == 1) {
 		e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);
 		if (e) {
 			e->write_proc = av7110_ir_write_proc;
@@ -266,8 +376,8 @@ int __devinit av7110_ir_init(struct av71
 		}
 	}
 
-	tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) av7110);
-	av7110->ir_handler = ir_handler;
+	tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir);
+	av7110->ir.ir_handler = ir_handler;
 
 	return 0;
 }
@@ -280,8 +390,10 @@ void __devexit av7110_ir_exit(struct av7
 	if (av_cnt == 0)
 		return;
 
-	av7110->ir_handler = NULL;
-	tasklet_kill(&av7110->ir_tasklet);
+	del_timer_sync(&av7110->ir.keyup_timer);
+	av7110->ir.ir_handler = NULL;
+	tasklet_kill(&av7110->ir.ir_tasklet);
+
 	for (i = 0; i < av_cnt; i++)
 		if (av_list[i] == av7110) {
 			av_list[i] = av_list[av_cnt-1];
@@ -289,14 +401,13 @@ void __devexit av7110_ir_exit(struct av7
 			break;
 		}
 
-	if (av_cnt == 1) {
-		del_timer_sync(&keyup_timer);
+	if (av_cnt == 1)
 		remove_proc_entry("av7110_ir", NULL);
-		input_unregister_device(input_dev);
-	}
+
+	input_unregister_device(av7110->ir.input_dev);
 
 	av_cnt--;
 }
 
-//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>");
+//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>");
 //MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index cde5d3a..fcd9994 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -31,7 +31,6 @@ #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/timer.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 
 #include "av7110.h"
 #include "av7110_hw.h"
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 3035b22..0e817d6 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -35,7 +35,7 @@
 
 #include "budget.h"
 #include "stv0299.h"
-#include "tda10021.h"
+#include "tda1002x.h"
 #include "tda1004x.h"
 #include "tua6100.h"
 #include "dvb-pll.h"
@@ -66,9 +66,6 @@ struct budget_av {
 	int slot_status;
 	struct dvb_ca_en50221 ca;
 	u8 reinitialise_demod:1;
-	u8 tda10021_poclkp:1;
-	u8 tda10021_ts_enabled;
-	int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
 };
 
 static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
@@ -234,12 +231,6 @@ static int ciintf_slot_reset(struct dvb_
 	if (budget_av->reinitialise_demod)
 		dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
 
-	/* set tda10021 back to original clock configuration on reset */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-		budget_av->tda10021_ts_enabled = 0;
-	}
-
 	return 0;
 }
 
@@ -256,11 +247,6 @@ static int ciintf_slot_shutdown(struct d
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
 	budget_av->slot_status = SLOTSTATUS_NONE;
 
-	/* set tda10021 back to original clock configuration when cam removed */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-		budget_av->tda10021_ts_enabled = 0;
-	}
 	return 0;
 }
 
@@ -276,12 +262,6 @@ static int ciintf_slot_ts_enable(struct 
 
 	ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
 
-	/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
-	if (budget_av->tda10021_poclkp) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
-		budget_av->tda10021_ts_enabled = 1;
-	}
-
 	return 0;
 }
 
@@ -631,37 +611,62 @@ static struct stv0299_config cinergy_120
 static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
-	u8 buf[4];
+	u8 buf[6];
 	struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
+	int i;
 
+#define CU1216_IF 36125000
 #define TUNER_MUL 62500
 
-	u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
+	u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
 
 	buf[0] = (div >> 8) & 0x7f;
 	buf[1] = div & 0xff;
-	buf[2] = 0x86;
+	buf[2] = 0xce;
 	buf[3] = (params->frequency < 150000000 ? 0x01 :
 		  params->frequency < 445000000 ? 0x02 : 0x04);
+	buf[4] = 0xde;
+	buf[5] = 0x20;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
+		return -EIO;
 
+	/* wait for the pll lock */
+	msg.flags = I2C_M_RD;
+	msg.len = 1;
+	for (i = 0; i < 20; i++) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40))
+			break;
+		msleep(10);
+	}
+
+	/* switch the charge pump to the lower current */
+	msg.flags = 0;
+	msg.len = 2;
+	msg.buf = &buf[2];
+	buf[2] &= ~0x40;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
 		return -EIO;
+
 	return 0;
 }
 
-static struct tda10021_config philips_cu1216_config = {
+static struct tda1002x_config philips_cu1216_config = {
 	.demod_address = 0x0c,
+	.invert = 1,
 };
 
-static struct tda10021_config philips_cu1216_config_altaddress = {
+static struct tda1002x_config philips_cu1216_config_altaddress = {
 	.demod_address = 0x0d,
+	.invert = 0,
 };
 
-
-
-
 static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct budget *budget = (struct budget *) fe->dvb->priv;
@@ -908,41 +913,28 @@ static u8 read_pwm(struct budget_av *bud
 	return pwm;
 }
 
-#define SUBID_DVBS_KNC1		0x0010
-#define SUBID_DVBS_KNC1_PLUS	0x0011
-#define SUBID_DVBS_TYPHOON	0x4f56
-#define SUBID_DVBS_CINERGY1200	0x1154
-#define SUBID_DVBS_CYNERGY1200N 0x1155
-
-#define SUBID_DVBS_TV_STAR	0x0014
-#define SUBID_DVBS_TV_STAR_CI	0x0016
-#define SUBID_DVBS_EASYWATCH_1  0x001a
-#define SUBID_DVBS_EASYWATCH	0x001e
-#define SUBID_DVBC_EASYWATCH	0x002a
-#define SUBID_DVBC_KNC1		0x0020
-#define SUBID_DVBC_KNC1_PLUS	0x0021
-#define SUBID_DVBC_CINERGY1200	0x1156
-
-#define SUBID_DVBT_KNC1_PLUS	0x0031
-#define SUBID_DVBT_KNC1		0x0030
-#define SUBID_DVBT_CINERGY1200	0x1157
-
-
-static int tda10021_set_frontend(struct dvb_frontend *fe,
-				 struct dvb_frontend_parameters *p)
-{
-	struct budget_av* budget_av = fe->dvb->priv;
-	int result;
-
-	result = budget_av->tda10021_set_frontend(fe, p);
-	if (budget_av->tda10021_ts_enabled) {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
-	} else {
-		tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
-	}
-
-	return result;
-}
+#define SUBID_DVBS_KNC1			0x0010
+#define SUBID_DVBS_KNC1_PLUS		0x0011
+#define SUBID_DVBS_TYPHOON		0x4f56
+#define SUBID_DVBS_CINERGY1200		0x1154
+#define SUBID_DVBS_CYNERGY1200N 	0x1155
+#define SUBID_DVBS_TV_STAR		0x0014
+#define SUBID_DVBS_TV_STAR_CI		0x0016
+#define SUBID_DVBS_EASYWATCH_1  	0x001a
+#define SUBID_DVBS_EASYWATCH		0x001e
+
+#define SUBID_DVBC_EASYWATCH		0x002a
+#define SUBID_DVBC_EASYWATCH_MK3	0x002c
+#define SUBID_DVBC_KNC1			0x0020
+#define SUBID_DVBC_KNC1_PLUS		0x0021
+#define SUBID_DVBC_KNC1_MK3		0x0022
+#define SUBID_DVBC_KNC1_PLUS_MK3	0x0023
+#define SUBID_DVBC_CINERGY1200		0x1156
+#define SUBID_DVBC_CINERGY1200_MK3	0x1176
+
+#define SUBID_DVBT_KNC1_PLUS		0x0031
+#define SUBID_DVBT_KNC1			0x0030
+#define SUBID_DVBT_CINERGY1200		0x1157
 
 static void frontend_init(struct budget_av *budget_av)
 {
@@ -961,6 +953,7 @@ static void frontend_init(struct budget_
 		case SUBID_DVBC_KNC1_PLUS:
 		case SUBID_DVBT_KNC1_PLUS:
 		case SUBID_DVBC_EASYWATCH:
+		case SUBID_DVBC_KNC1_PLUS_MK3:
 			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
 			break;
 	}
@@ -1017,6 +1010,7 @@ static void frontend_init(struct budget_
 	case SUBID_DVBC_CINERGY1200:
 	case SUBID_DVBC_EASYWATCH:
 		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
 		fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
 				     &budget_av->budget.i2c_adap,
 				     read_pwm(budget_av));
@@ -1025,9 +1019,20 @@ static void frontend_init(struct budget_
 					     &budget_av->budget.i2c_adap,
 					     read_pwm(budget_av));
 		if (fe) {
-			budget_av->tda10021_poclkp = 1;
-			budget_av->tda10021_set_frontend = fe->ops.set_frontend;
-			fe->ops.set_frontend = tda10021_set_frontend;
+			fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+		}
+		break;
+
+	case SUBID_DVBC_EASYWATCH_MK3:
+	case SUBID_DVBC_CINERGY1200_MK3:
+	case SUBID_DVBC_KNC1_MK3:
+	case SUBID_DVBC_KNC1_PLUS_MK3:
+		budget_av->reinitialise_demod = 1;
+		budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
+		fe = dvb_attach(tda10023_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;
@@ -1260,12 +1265,16 @@ MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
 MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
+MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);
+MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);
 MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
 MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
 MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
 MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);
 MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
 
 static struct pci_device_id pci_tbl[] = {
@@ -1279,13 +1288,17 @@ static struct pci_device_id pci_tbl[] = 
 	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
 	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
 	MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
+	MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
 	MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
+	MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),
+	MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),
 	MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
 	MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
 	MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
 	MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
 	MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+	MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),
 	MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
 	{
 	 .vendor = 0,
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 464feaf..4ed4599 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -73,21 +73,15 @@ #define SLOTSTATUS_RESET	4
 #define SLOTSTATUS_READY	8
 #define SLOTSTATUS_OCCUPIED	(SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
 
-/* Milliseconds during which key presses are regarded as key repeat and during
- * which the debounce logic is active
+/*
+ * Milliseconds during which a key is regarded as pressed.
+ * If an identical command arrives within this time, the timer will start over.
  */
-#define IR_REPEAT_TIMEOUT	350
+#define IR_KEYPRESS_TIMEOUT	250
 
 /* RC5 device wildcard */
 #define IR_DEVICE_ANY		255
 
-/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
- * this setting allows the superflous sequences to be ignored
- */
-static int debounce = 0;
-module_param(debounce, int, 0644);
-MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
-
 static int rc5_device = -1;
 module_param(rc5_device, int, 0644);
 MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
@@ -99,10 +93,14 @@ MODULE_PARM_DESC(ir_debug, "enable debug
 struct budget_ci_ir {
 	struct input_dev *dev;
 	struct tasklet_struct msp430_irq_tasklet;
+	struct timer_list timer_keyup;
 	char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
 	char phys[32];
 	struct ir_input_state state;
 	int rc5_device;
+	u32 last_raw;
+	u32 ir_key;
+	bool have_command;
 };
 
 struct budget_ci {
@@ -125,13 +123,8 @@ static void msp430_ir_interrupt(unsigned
 {
 	struct budget_ci *budget_ci = (struct budget_ci *) data;
 	struct input_dev *dev = budget_ci->ir.dev;
-	static int bounces = 0;
-	int device;
-	int toggle;
-	static int prev_toggle = -1;
-	static u32 ir_key;
-	static int state = 0;
 	u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
+	u32 raw;
 
 	/*
 	 * The msp430 chip can generate two different bytes, command and device
@@ -143,7 +136,7 @@ static void msp430_ir_interrupt(unsigned
 	 * bytes and one or more device bytes. For the repeated bytes, the
 	 * highest bit (X) is set. The first command byte is always generated
 	 * before the first device byte. Other than that, no specific order
-	 * seems to apply.
+	 * seems to apply. To make life interesting, bytes can also be lost.
 	 *
 	 * Only when we have a command and device byte, a keypress is
 	 * generated.
@@ -152,53 +145,35 @@ static void msp430_ir_interrupt(unsigned
 	if (ir_debug)
 		printk("budget_ci: received byte 0x%02x\n", command);
 
-	/* Is this a repeated byte? */
-	if (command & 0x80)
-		return;
+	/* Remove repeat bit, we use every command */
+	command = command & 0x7f;
 
 	/* Is this a RC5 command byte? */
 	if (command & 0x40) {
-		state = 1;
-		ir_key = command & 0x3f;
+		budget_ci->ir.have_command = true;
+		budget_ci->ir.ir_key = command & 0x3f;
 		return;
 	}
 
 	/* It's a RC5 device byte */
-	if (!state)
+	if (!budget_ci->ir.have_command)
 		return;
-	state = 0;
-	device = command & 0x1f;
-	toggle = command & 0x20;
+	budget_ci->ir.have_command = false;
 
-	if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
+	if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
+	    budget_ci->ir.rc5_device != (command & 0x1f))
 		return;
 
-	/* Ignore repeated key sequences if requested */
-	if (toggle == prev_toggle && ir_key == dev->repeat_key &&
-	    bounces > 0 && timer_pending(&dev->timer)) {
-		if (ir_debug)
-			printk("budget_ci: debounce logic ignored IR command\n");
-		bounces--;
-		return;
-	}
-	prev_toggle = toggle;
-
-	/* Are we still waiting for a keyup event? */
-	if (del_timer(&dev->timer))
-		ir_input_nokey(dev, &budget_ci->ir.state);
-
-	/* Generate keypress */
-	if (ir_debug)
-		printk("budget_ci: generating keypress 0x%02x\n", ir_key);
-	ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
-
-	/* Do we want to delay the keyup event? */
-	if (debounce) {
-		bounces = debounce;
-		mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
-	} else {
+	/* Is this a repeated key sequence? (same device, command, toggle) */
+	raw = budget_ci->ir.ir_key | (command << 8);
+	if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
 		ir_input_nokey(dev, &budget_ci->ir.state);
+		ir_input_keydown(dev, &budget_ci->ir.state,
+				 budget_ci->ir.ir_key, raw);
+		budget_ci->ir.last_raw = raw;
 	}
+
+	mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
 }
 
 static int msp430_ir_init(struct budget_ci *budget_ci)
@@ -271,16 +246,21 @@ static int msp430_ir_init(struct budget_
 		break;
 	}
 
-	/* initialise the key-up debounce timeout handler */
-	input_dev->timer.function = msp430_ir_keyup;
-	input_dev->timer.data = (unsigned long) &budget_ci->ir;
-
+	/* initialise the key-up timeout handler */
+	init_timer(&budget_ci->ir.timer_keyup);
+	budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
+	budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
+	budget_ci->ir.last_raw = 0xffff; /* An impossible value */
 	error = input_register_device(input_dev);
 	if (error) {
 		printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
 		goto out2;
 	}
 
+	/* note: these must be after input_register_device */
+	input_dev->rep[REP_DELAY] = 400;
+	input_dev->rep[REP_PERIOD] = 250;
+
 	tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
 		     (unsigned long) budget_ci);
 
@@ -304,10 +284,8 @@ static void msp430_ir_deinit(struct budg
 	saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
 	tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
 
-	if (del_timer(&dev->timer)) {
-		ir_input_nokey(dev, &budget_ci->ir.state);
-		input_sync(dev);
-	}
+	del_timer_sync(&dev->timer);
+	ir_input_nokey(dev, &budget_ci->ir.state);
 
 	input_unregister_device(dev);
 }
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index e15562f..6b97dc1 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -41,11 +41,14 @@ #include "ttpci-eeprom.h"
 
 #define TS_WIDTH		(2 * TS_SIZE)
 #define TS_WIDTH_ACTIVY		TS_SIZE
+#define TS_WIDTH_DVBC		TS_SIZE
 #define TS_HEIGHT_MASK		0xf00
 #define TS_HEIGHT_MASK_ACTIVY	0xc00
+#define TS_HEIGHT_MASK_DVBC	0xe00
 #define TS_MIN_BUFSIZE_K	188
 #define TS_MAX_BUFSIZE_K	1410
 #define TS_MAX_BUFSIZE_K_ACTIVY	564
+#define TS_MAX_BUFSIZE_K_DVBC	1316
 #define BUFFER_WARNING_WAIT	(30*HZ)
 
 int budget_debug;
@@ -106,6 +109,19 @@ static int start_ts_capture(struct budge
 		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
 		saa7146_write(dev, BRS_CTRL, 0x60000000);
 		break;
+	case BUDGET_CIN1200C_MK3:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1CP_MK3:
+		if (budget->video_port == BUDGET_VIDEO_PORTA) {
+			saa7146_write(dev, DD1_INIT, 0x06000200);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x00000000);
+		} else {
+			saa7146_write(dev, DD1_INIT, 0x00000600);
+			saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+			saa7146_write(dev, BRS_CTRL, 0x60000000);
+		}
+		break;
 	default:
 		if (budget->video_port == BUDGET_VIDEO_PORTA) {
 			saa7146_write(dev, DD1_INIT, 0x06000200);
@@ -122,7 +138,13 @@ static int start_ts_capture(struct budge
 	mdelay(10);
 
 	saa7146_write(dev, BASE_ODD3, 0);
-	saa7146_write(dev, BASE_EVEN3, 0);
+	if (budget->buffer_size > budget->buffer_height * budget->buffer_width) {
+		// using odd/even buffers
+		saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width);
+	} else {
+		// using a single buffer
+		saa7146_write(dev, BASE_EVEN3, 0);
+	}
 	saa7146_write(dev, PROT_ADDR3, budget->buffer_size);
 	saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
 
@@ -399,11 +421,25 @@ int ttpci_budget_init(struct budget *bud
 	budget->card = bi;
 	budget->dev = (struct saa7146_dev *) dev;
 
-	if (budget->card->type == BUDGET_FS_ACTIVY) {
+	switch(budget->card->type) {
+	case BUDGET_FS_ACTIVY:
 		budget->buffer_width = TS_WIDTH_ACTIVY;
 		max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY;
 		height_mask = TS_HEIGHT_MASK_ACTIVY;
-	} else {
+		break;
+
+	case BUDGET_KNC1C:
+	case BUDGET_KNC1CP:
+	case BUDGET_CIN1200C:
+	case BUDGET_KNC1C_MK3:
+	case BUDGET_KNC1CP_MK3:
+	case BUDGET_CIN1200C_MK3:
+		budget->buffer_width = TS_WIDTH_DVBC;
+		max_bufsize = TS_MAX_BUFSIZE_K_DVBC;
+		height_mask = TS_HEIGHT_MASK_DVBC;
+		break;
+
+	default:
 		budget->buffer_width = TS_WIDTH;
 		max_bufsize = TS_MAX_BUFSIZE_K;
 		height_mask = TS_HEIGHT_MASK;
@@ -415,14 +451,22 @@ int ttpci_budget_init(struct budget *bud
 		dma_buffer_size = max_bufsize;
 
 	budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width;
-	budget->buffer_height &= height_mask;
-	budget->buffer_size = budget->buffer_height * budget->buffer_width;
+	if (budget->buffer_height > 0xfff) {
+		budget->buffer_height /= 2;
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width;
+	} else {
+		budget->buffer_height &= height_mask;
+		budget->buffer_size = budget->buffer_height * budget->buffer_width;
+	}
 	budget->buffer_warning_threshold = budget->buffer_size * 80/100;
 	budget->buffer_warnings = 0;
 	budget->buffer_warning_time = jiffies;
 
-	dprintk(2, "%s: width = %d, height = %d\n",
-		budget->dev->name, budget->buffer_width, budget->buffer_height);
+	dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n",
+		budget->dev->name,
+		budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single",
+		budget->buffer_width, budget->buffer_height);
 	printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
 
 	if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index e8a5c79..d764ffa 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -99,6 +99,9 @@ #define BUDGET_KNC1SP		   11
 #define BUDGET_KNC1CP		   12
 #define BUDGET_KNC1TP		   13
 #define BUDGET_TVSTAR		   14
+#define BUDGET_CIN1200C_MK3	   15
+#define BUDGET_KNC1C_MK3	   16
+#define BUDGET_KNC1CP_MK3	   17
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index e78ea92..f546bcc 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -1,7 +1,6 @@
 config DVB_TTUSB_BUDGET
 	tristate "Technotrend/Hauppauge Nova-USB devices"
 	depends on DVB_CORE && USB && I2C
-	select DVB_PLL
 	select DVB_CX22700 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index df8d052..449df1b 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -79,7 +79,6 @@ #include <linux/input.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 
 /*
  * Version Information
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index b2e88ad..5adc27c 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -231,129 +231,149 @@ static struct v4l2_queryctrl radio_qctrl
 	}
 };
 
-static int rt_do_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
+{
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt=dev->priv;
+	struct rt_device *rt = dev->priv;
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	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*rt_getsigstr(rt);
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+	rt->curfreq = f->frequency;
+	rt_setfreq(rt, rt->curfreq);
+	return 0;
+}
 
-			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*rt_getsigstr(rt);
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = rt->curfreq;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			rt->curfreq = f->frequency;
-			rt_setfreq(rt, rt->curfreq);
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = rt->curfreq;
+	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;
+}
 
-			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:
-					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;
-		}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  rt_do_ioctl);
+	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;
+}
+
+static int vidioc_g_audio (struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
 }
 
-static int rt_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, rt_do_ioctl);
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct rt_device rtrack_unit;
@@ -362,7 +382,7 @@ static const struct file_operations rtra
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= rt_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -374,6 +394,18 @@ static struct video_device rtrack_radio=
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &rtrack_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static int __init rtrack_init(void)
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 74976cb..fdf5d6e 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -192,131 +192,158 @@ static inline unsigned int gemtek_pci_ge
 	return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
 }
 
-static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
-			       unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void *priv,
+					struct v4l2_capability *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;
+	return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_pci_card *card = dev->priv;
 
-	switch ( cmd ) {
-		case VIDIOC_QUERYCAP:
-		{
-			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;
-
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	if (v->index > 0)
+		return -EINVAL;
+
+	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;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_pci_card *card = dev->priv;
 
-			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 );
+	if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
+			(f->frequency > GEMTEK_PCI_RANGE_HIGH) )
+		return -EINVAL;
+	gemtek_pci_setfrequency(card, f->frequency);
+	card->current_frequency = f->frequency;
+	card->mute = false;
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_pci_card *card = dev->priv;
 
-			if (v->index > 0)
-				return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = card->current_frequency;
+	return 0;
+}
 
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
-			     (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
-				return -EINVAL;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_pci_card *card = dev->priv;
 
+	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;
+}
 
-			gemtek_pci_setfrequency( card, f->frequency );
-			card->current_frequency = f->frequency;
-			card->mute = false;
-			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->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 v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  gemtek_pci_do_ioctl);
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_pci_card *card = dev->priv;
+
+	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;
 }
 
-static int gemtek_pci_ioctl(struct inode *inode, struct file *file,
-			    unsigned int cmd, unsigned long arg)
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, gemtek_pci_do_ioctl);
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 enum {
@@ -342,7 +369,7 @@ static const struct file_operations gemt
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= gemtek_pci_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -353,6 +380,18 @@ static struct video_device vdev_template
 	.type          = VID_TYPE_TUNER,
 	.hardware      = 0,
 	.fops          = &gemtek_pci_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 36c4be6..b04b6a7 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -161,137 +161,157 @@ static int gemtek_getsigstr(struct gemte
 	return 1;		/* signal present */
 }
 
-static int gemtek_do_ioctl(struct inode *inode, struct file *file,
-			   unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
+{
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt=dev->priv;
+	struct gemtek_device *rt = dev->priv;
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	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;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_device *rt = dev->priv;
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+	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;
+}
 
-			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);
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_device *rt = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = rt->curfreq;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			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 VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = rt->curfreq;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_device *rt = dev->priv;
 
-			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 v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  gemtek_do_ioctl);
+	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;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct gemtek_device *rt = dev->priv;
+
+	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;
 }
 
-static int gemtek_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static int vidioc_g_audio (struct file *file, void *priv,
+					struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, gemtek_do_ioctl);
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct gemtek_device gemtek_unit;
@@ -300,7 +320,7 @@ static const struct file_operations gemt
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= gemtek_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -312,6 +332,18 @@ static struct video_device gemtek_radio=
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &gemtek_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static int __init gemtek_init(void)
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index e67b7f2..11f80ca 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -75,8 +75,6 @@ #define BITS2FREQ(x)	((x) * FREQ_STEP - 
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg);
 static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static void maestro_remove(struct pci_dev *pdev);
 
@@ -102,18 +100,11 @@ static const struct file_operations maes
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= radio_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
 
-static struct video_device maestro_radio = {
-	.name		= "Maestro radio",
-	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
-	.fops		= &maestro_fops,
-};
-
 struct radio_device {
 	u16	io,	/* base of Maestro card radio io (GPIO_DATA)*/
 		muted,	/* VIDEO_AUDIO_MUTE */
@@ -190,142 +181,153 @@ static void radio_bits_set(struct radio_
 	msleep(125);
 }
 
-static inline int radio_function(struct inode *inode, struct file *file,
-	unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
 	struct radio_device *card = video_get_drvdata(dev);
 
-	switch (cmd) {
-		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);
+	if (v->index > 0)
+		return -EINVAL;
+
+	(void)radio_bits_get(card);
+
+	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;
+}
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			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;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct radio_device *card = video_get_drvdata(dev);
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+		return -EINVAL;
+	radio_bits_set(card, FREQ2BITS(f->frequency));
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct radio_device *card = video_get_drvdata(dev);
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = BITS2FREQ(radio_bits_get(card));
+	return 0;
+}
 
-			if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
-				return -EINVAL;
-			radio_bits_set(card, FREQ2BITS(f->frequency));
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = BITS2FREQ(radio_bits_get(card));
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct radio_device *card = video_get_drvdata(dev);
 
-			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;
-		}
-		case VIDIOC_S_CTRL:
-		{
-			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;
-		}
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  radio_function);
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = card->muted;
+		return 0;
 	}
+	return -EINVAL;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
 {
 	struct video_device *dev = video_devdata(file);
 	struct radio_device *card = video_get_drvdata(dev);
-	int ret;
+	register u16 io = card->io;
+	register u16 omask = inw(io + IO_MASK);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		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;
+}
 
-	mutex_lock(&card->lock);
-	ret = video_usercopy(inode, file, cmd, arg, radio_function);
-	mutex_unlock(&card->lock);
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
 
-	return ret;
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static u16 __devinit radio_power_on(struct radio_device *dev)
@@ -352,6 +354,24 @@ static u16 __devinit radio_power_on(stru
 	return (ofreq == radio_bits_get(dev));
 }
 
+static struct video_device maestro_radio = {
+	.name           = "Maestro radio",
+	.type           = VID_TYPE_TUNER,
+	.fops           = &maestro_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+};
+
 static int __devinit maestro_probe(struct pci_dev *pdev,
 	const struct pci_device_id *ent)
 {
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index f668387..9b493b3 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -122,6 +122,26 @@ static int rt_setfreq(struct rt_device *
 	return 0;
 }
 
+static int vidioc_querycap(struct file *file, void *priv,
+				struct v4l2_capability *v)
+{
+	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;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int rt_getsigstr(struct rt_device *dev)
 {
 	if (inb(io) & 2)	/* bit set = no signal present	*/
@@ -129,135 +149,136 @@ static int rt_getsigstr(struct rt_device
 	return 1;		/* signal present		*/
 }
 
-static int rt_do_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
-	struct rt_device *rt=dev->priv;
+	struct rt_device *rt = dev->priv;
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	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;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+	rt->curfreq = f->frequency;
+	rt_setfreq(rt, rt->curfreq);
+	return 0;
+}
 
-			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);
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = rt->curfreq;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			rt->curfreq = f->frequency;
-			rt_setfreq(rt, rt->curfreq);
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = rt->curfreq;
+	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;
+}
 
-			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) {
-						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 v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  rt_do_ioctl);
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct rt_device *rt = dev->priv;
+
+	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;
 }
 
-static int rt_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+static int vidioc_g_audio(struct file *file, void *priv,
+				struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, rt_do_ioctl);
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+				struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct rt_device rtrack2_unit;
@@ -266,7 +287,7 @@ static const struct file_operations rtra
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= rt_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -278,6 +299,18 @@ static struct video_device rtrack2_radio
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &rtrack2_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
 };
 
 static int __init rtrack2_init(void)
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index f4619e4..dc33f19 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -130,137 +130,155 @@ static inline int fmi_getsigstr(struct f
 	return (res & 2) ? 0 : 0xFFFF;
 }
 
-static int fmi_do_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
 {
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	int mult;
 	struct video_device *dev = video_devdata(file);
-	struct fmi_device *fmi=dev->priv;
+	struct fmi_device *fmi = dev->priv;
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
-			int mult;
-
-			if (v->index > 0)
-				return -EINVAL;
-
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			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->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);
+	strcpy(v->name, "FM");
+	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->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;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmi_device *fmi = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			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 = (f->frequency/800)*800;
-			fmi_setfreq(fmi);
+	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 = (f->frequency/800)*800;
+	fmi_setfreq(fmi);
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmi_device *fmi = dev->priv;
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = fmi->curfreq;
-			if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-				f->frequency /= 1000;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = fmi->curfreq;
+	if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+		f->frequency /= 1000;
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		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=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 v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  fmi_do_ioctl);
 	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmi_device *fmi = dev->priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = fmi->curvol;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmi_device *fmi = dev->priv;
+
+	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;
 }
 
-static int fmi_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, fmi_do_ioctl);
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct fmi_device fmi_unit;
@@ -269,7 +287,7 @@ static const struct file_operations fmi_
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= fmi_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -281,6 +299,18 @@ static struct video_device fmi_radio=
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &fmi_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 /* ladis: this is my card. does any other types exist? */
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index b96fafe..e6c125d 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -226,186 +226,204 @@ static int fmr2_setvolume(struct fmr2_de
 	return 0;
 }
 
-static int fmr2_do_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
 {
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	int mult;
 	struct video_device *dev = video_devdata(file);
 	struct fmr2_device *fmr2 = dev->priv;
-	debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
-		"stereo %d type %d\n",
-		fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute,
-		fmr2->stereo, fmr2->card_type));
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
-			int mult;
-
-			if (v->index > 0)
-				return -EINVAL;
-
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			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->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);
+	strcpy(v->name, "FM");
+	v->type = V4L2_TUNER_RADIO;
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
+	v->rangelow = RSF16_MINFREQ/mult;
+	v->rangehigh = RSF16_MAXFREQ/mult;
+	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;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			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 = (f->frequency/200)*200;
-
-			/* set card freq (if not muted) */
-			if (fmr2->curvol && !fmr2->mute)
-			{
-				mutex_lock(&lock);
-				fmr2_setfreq(fmr2);
-				mutex_unlock(&lock);
-			}
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			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 = (f->frequency/200)*200;
+
+	/* set card freq (if not muted) */
+	if (fmr2->curvol && !fmr2->mute) {
+		mutex_lock(&lock);
+		fmr2_setfreq(fmr2);
+		mutex_unlock(&lock);
+	}
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = fmr2->curfreq;
-			if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-				f->frequency /= 1000;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = fmr2->curfreq;
+	if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+		f->frequency /= 1000;
+	return 0;
+}
 
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	int i;
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
+
+	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;
 		}
-		case VIDIOC_QUERYCTRL:
-		{
-			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;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
+
+	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;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct fmr2_device *fmr2 = dev->priv;
+
+	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;
 		}
-		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);
+		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;
 			}
-			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;
-			}
+		break;
+	default:
+		return -EINVAL;
+	}
+
 #ifdef DEBUG
-			if (fmr2->curvol && !fmr2->mute)
-				printk(KERN_DEBUG "unmute\n");
-			else
-				printk(KERN_DEBUG "mute\n");
+	if (fmr2->curvol && !fmr2->mute)
+		printk(KERN_DEBUG "unmute\n");
+	else
+		printk(KERN_DEBUG "mute\n");
 #endif
-			mutex_lock(&lock);
-			if (fmr2->curvol && !fmr2->mute) {
-				fmr2_setvolume(fmr2);
-				fmr2_setfreq(fmr2);
-			} else
-				fmr2_mute(fmr2->port);
-			mutex_unlock(&lock);
-			return (0);
-		}
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  fmr2_do_ioctl);
 
-	}
+	mutex_lock(&lock);
+	if (fmr2->curvol && !fmr2->mute) {
+		fmr2_setvolume(fmr2);
+		fmr2_setfreq(fmr2);
+	} else
+		fmr2_mute(fmr2->port);
+	mutex_unlock(&lock);
+	return 0;
 }
 
-static int fmr2_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg)
- {
-	return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct fmr2_device fmr2_unit;
@@ -414,7 +432,7 @@ static const struct file_operations fmr2
 	.owner          = THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl          = fmr2_ioctl,
+	.ioctl          = video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -426,6 +444,18 @@ static struct video_device fmr2_radio=
 	. type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops		= &fmr2_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static int __init fmr2_init(void)
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index d59a27a..e43acfd 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -205,135 +205,152 @@ static int tt_getsigstr(struct tt_device
 	return 1;		/* signal present		*/
 }
 
+static int vidioc_querycap(struct file *file, void *priv,
+					struct v4l2_capability *v)
+{
+	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;
+}
 
-/* implement the video4linux api */
-
-static int tt_do_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
-	struct tt_device *tt=dev->priv;
+	struct tt_device *tt = dev->priv;
 
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	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*tt_getsigstr(tt);
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct tt_device *tt = dev->priv;
 
-			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*tt_getsigstr(tt);
+	tt->curfreq = f->frequency;
+	tt_setfreq(tt, tt->curfreq);
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct tt_device *tt = dev->priv;
 
-			if (v->index > 0)
-				return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = tt->curfreq;
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	int i;
 
-			tt->curfreq = f->frequency;
-			tt_setfreq(tt, tt->curfreq);
+	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;
 		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	}
+	return -EINVAL;
+}
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = tt->curfreq;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct tt_device *tt = dev->priv;
 
-			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:
-					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;
-		}
+	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;
+}
 
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  tt_do_ioctl);
+static int vidioc_s_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct tt_device *tt = dev->priv;
+
+	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;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
 }
 
-static int tt_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-	return video_usercopy(inode, file, cmd, arg, tt_do_ioctl);
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct tt_device terratec_unit;
@@ -342,7 +359,7 @@ static const struct file_operations terr
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= tt_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -354,6 +371,18 @@ static struct video_device terratec_radi
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &terratec_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
 };
 
 static int __init terratec_init(void)
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 6d7f1e7..c27c629 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -192,144 +192,154 @@ static void tr_setfreq(unsigned long f)
 	write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
 }
 
-static int tr_do_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void *priv,
+				struct v4l2_capability *v)
 {
-	switch(cmd)
-	{
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	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;
+}
 
-			return 0;
-		}
-		case VIDIOC_G_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.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->audmode = V4L2_TUNER_MODE_STEREO;
-			else
-				v->audmode = V4L2_TUNER_MODE_MONO;
-			v->signal=tr_getsigstr();
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	strcpy(v->name, "FM");
+	v->type = V4L2_TUNER_RADIO;
+	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->audmode = V4L2_TUNER_MODE_STEREO;
+	else
+		v->audmode = V4L2_TUNER_MODE_MONO;
+	v->signal = tr_getsigstr();
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
 
-			if (v->index > 0)
-				return -EINVAL;
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	curfreq = f->frequency;
+	tr_setfreq(curfreq);
+	return 0;
+}
 
-			curfreq = f->frequency;
-			tr_setfreq(curfreq);
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = curfreq;
+	return 0;
+}
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = curfreq;
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		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=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;
-		}
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	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;
+}
 
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  tr_do_ioctl);
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	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;
 }
 
-static int tr_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+static int vidioc_g_audio(struct file *file, void *priv,
+				struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, tr_do_ioctl);
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+				struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static const struct file_operations trust_fops = {
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= tr_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -341,6 +351,18 @@ static struct video_device trust_radio=
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &trust_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
 };
 
 static int __init trust_init(void)
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 3031fef..8ff5a23 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -93,8 +93,6 @@ static int typhoon_setfreq(struct typhoo
 static void typhoon_mute(struct typhoon_device *dev);
 static void typhoon_unmute(struct typhoon_device *dev);
 static int typhoon_setvol(struct typhoon_device *dev, int vol);
-static int typhoon_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg);
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
 static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
 #endif
@@ -186,129 +184,148 @@ static int typhoon_setvol(struct typhoon
 	return 0;
 }
 
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
+{
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+
+	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;
+}
 
-static int typhoon_do_ioctl(struct inode *inode, struct file *file,
-			    unsigned int cmd, void *arg)
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
 {
 	struct video_device *dev = video_devdata(file);
 	struct typhoon_device *typhoon = dev->priv;
 
-	switch (cmd) {
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	typhoon->curfreq = f->frequency;
+	typhoon_setfreq(typhoon, typhoon->curfreq);
+	return 0;
+}
 
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct typhoon_device *typhoon = dev->priv;
 
-			if (v->index > 0)
-				return -EINVAL;
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = typhoon->curfreq;
 
-			memset(v,0,sizeof(*v));
-			strcpy(v->name, "FM");
-			v->type = V4L2_TUNER_RADIO;
+	return 0;
+}
 
-			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 */
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+	}
+	return -EINVAL;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct typhoon_device *typhoon = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = 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;
+}
 
-			typhoon->curfreq = f->frequency;
-			typhoon_setfreq(typhoon, typhoon->curfreq);
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_s_ctrl (struct file *file, void *priv,
+					struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct typhoon_device *typhoon = dev->priv;
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = typhoon->curfreq;
+	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;
+}
 
-			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=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;
-		}
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
 
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  typhoon_do_ioctl);
-	}
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
 }
 
-static int typhoon_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, unsigned long arg)
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
 {
-	return video_usercopy(inode, file, cmd, arg, typhoon_do_ioctl);
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct typhoon_device typhoon_unit =
@@ -322,7 +339,7 @@ static const struct file_operations typh
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= typhoon_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -334,6 +351,18 @@ static struct video_device typhoon_radio
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &typhoon_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index ec08491..a471590 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -230,121 +230,123 @@ static int zol_is_stereo (struct zol_dev
 	return 0;
 }
 
-static int zol_do_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, void *arg)
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *v)
+{
+	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;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
 {
 	struct video_device *dev = video_devdata(file);
 	struct zol_device *zol = dev->priv;
 
-	switch (cmd) {
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *v = arg;
-			memset(v,0,sizeof(*v));
-			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;
+	if (v->index > 0)
+		return -EINVAL;
 
-			return 0;
-		}
-		case VIDIOC_G_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=(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);
+	strcpy(v->name, "FM");
+	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;
+}
 
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *v = arg;
+static int vidioc_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *v)
+{
+	if (v->index > 0)
+		return -EINVAL;
+	return 0;
+}
 
-			if (v->index > 0)
-				return -EINVAL;
+static int vidioc_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct zol_device *zol = dev->priv;
 
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+	zol->curfreq = f->frequency;
+	zol_setfreq(zol, zol->curfreq);
+	return 0;
+}
 
-			zol->curfreq = f->frequency;
-			zol_setfreq(zol, zol->curfreq);
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
+static int vidioc_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct video_device *dev = video_devdata(file);
+	struct zol_device *zol = dev->priv;
+
+	f->type = V4L2_TUNER_RADIO;
+	f->frequency = zol->curfreq;
+	return 0;
+}
 
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = zol->curfreq;
+static int vidioc_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *qc)
+{
+	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;
 		}
-		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;
+	}
+	return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct zol_device *zol = dev->priv;
+
+	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;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct zol_device *zol = dev->priv;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value)
+			zol_mute(zol);
+		else {
+			zol_unmute(zol);
+			zol_setvol(zol,zol->curvol);
 		}
-		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);
+		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) {
@@ -356,19 +358,39 @@ #if 0
 				zol_setfreq(zol, zol->curfreq);
 			}
 #endif
-			return -EINVAL;
-		}
+	return -EINVAL;
+}
 
-		default:
-			return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-							  zol_do_ioctl);
-	}
+static int vidioc_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index > 1)
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	a->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
 }
 
-static int zol_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
 {
-	return video_usercopy(inode, file, cmd, arg, zol_do_ioctl);
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	if (a->index != 0)
+		return -EINVAL;
+	return 0;
 }
 
 static struct zol_device zoltrix_unit;
@@ -378,7 +400,7 @@ static const struct file_operations zolt
 	.owner		= THIS_MODULE,
 	.open           = video_exclusive_open,
 	.release        = video_exclusive_release,
-	.ioctl		= zol_ioctl,
+	.ioctl		= video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek         = no_llseek,
 };
@@ -390,6 +412,18 @@ static struct video_device zoltrix_radio
 	.type		= VID_TYPE_TUNER,
 	.hardware	= 0,
 	.fops           = &zoltrix_fops,
+	.vidioc_querycap    = vidioc_querycap,
+	.vidioc_g_tuner     = vidioc_g_tuner,
+	.vidioc_s_tuner     = vidioc_s_tuner,
+	.vidioc_g_audio     = vidioc_g_audio,
+	.vidioc_s_audio     = vidioc_s_audio,
+	.vidioc_g_input     = vidioc_g_input,
+	.vidioc_s_input     = vidioc_s_input,
+	.vidioc_g_frequency = vidioc_g_frequency,
+	.vidioc_s_frequency = vidioc_s_frequency,
+	.vidioc_queryctrl   = vidioc_queryctrl,
+	.vidioc_g_ctrl      = vidioc_g_ctrl,
+	.vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static int __init zoltrix_init(void)
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 7a61051..bc77378 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
 
 config VIDEO_MEYE
 	tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
-	depends on PCI && SONYPI && VIDEO_V4L1
+	depends on PCI && SONY_LAPTOP && VIDEO_V4L1
 	---help---
 	  This is the video4linux driver for the Motion Eye camera found
 	  in the Vaio Picturebook laptops. Please read the material in
 	  <file:Documentation/video4linux/meye.txt> for more information.
 
-	  If you say Y or M here, you need to say Y or M to "Sony Programmable
-	  I/O Control Device" in the character device section.
+	  If you say Y or M here, you need to say Y or M to "Sony Laptop
+	  Extras" in the misc device section.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called meye.
@@ -647,6 +647,8 @@ config VIDEO_HEXIUM_GEMINI
 
 source "drivers/media/video/cx88/Kconfig"
 
+source "drivers/media/video/ivtv/Kconfig"
+
 config VIDEO_M32R_AR
 	tristate "AR devices"
 	depends on M32R && VIDEO_V4L1
@@ -761,6 +763,18 @@ source "drivers/media/video/zc0301/Kconf
 
 source "drivers/media/video/pwc/Kconfig"
 
+config USB_ZR364XX
+	tristate "USB ZR364XX Camera support"
+	depends on USB && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to connect this type of camera to your
+	  computer's USB port.
+	  See <file:Documentation/video4linux/zr364xx.txt> for more info
+	  and list of supported cameras.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zr364xx.
+
 endmenu # V4L USB devices
 
 endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 44ccaed..9c2de50 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
 obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
@@ -99,6 +100,7 @@ obj-$(CONFIG_USB_OV511)         += ov511
 obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_STV680)        += stv680.o
 obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
+obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 2aa9ce9..823cd6c 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -37,7 +37,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index a3246a2..05c7820 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -33,7 +33,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 6867386..59a4360 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -37,7 +37,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 42e2299..853b1a3 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -37,7 +37,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 772fd52..2e4cf1e 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -37,7 +37,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6addc42..6b31e50 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -291,6 +291,9 @@ static struct CARD {
 
 	{ 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
 
+	{ 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" },
+	{ 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" },
+
 	/* likely broken, vendor id doesn't match the other magic views ...
 	 * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
 
@@ -2907,6 +2910,28 @@ struct tvcard bttv_tvcards[] = {
 		.has_radio      = 1,
 		.has_remote     = 1,
 	},
+	[BTTV_BOARD_SSAI_SECURITY] = {
+		.name		= "SSAI Security Video Interface",
+		.video_inputs	= 4,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.svhs		= -1,
+		.muxsel		= { 0, 1, 2, 3 },
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
+	[BTTV_BOARD_SSAI_ULTRASOUND] = {
+		.name		= "SSAI Ultrasound Video Interface",
+		.video_inputs	= 2,
+		.audio_inputs	= 0,
+		.tuner		= -1,
+		.svhs		= 1,
+		.muxsel		= { 2, 0, 1, 3 },
+		.tuner_type	= -1,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2970,20 +2995,20 @@ void __devinit bttv_idcard(struct bttv *
 
 	if (UNSET != audiomux[0]) {
 		gpiobits = 0;
-		for (i = 0; i < 4; i++) {
+		for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
 			bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i];
 			gpiobits |= audiomux[i];
 		}
 	} else {
 		gpiobits = audioall;
-		for (i = 0; i < 4; i++) {
+		for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
 			bttv_tvcards[btv->c.type].gpiomux[i] = audioall;
 		}
 	}
 	bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
 	printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
 	       btv->c.nr,bttv_tvcards[btv->c.type].gpiomask);
-	for (i = 0; i < 5; i++) {
+	for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) {
 		printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]);
 	}
 	printk("\n");
@@ -3638,7 +3663,7 @@ static int __devinit pvr_altera_load(str
 
 	for (n = 0; n < microlen; n++) {
 		bits = micro[n];
-		for ( i = 0 ; i < 8 ; i++ ) {
+		for (i = 0 ; i < 8 ; i++) {
 			gpio_bits(BTTV_ALT_DCLK,0);
 			if (bits & 0x01)
 				gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA);
@@ -3691,7 +3716,7 @@ static void __devinit osprey_eeprom(stru
 	       /* this might be an antique... check for MMAC label in eeprom */
 	       if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
 		       unsigned char checksum = 0;
-		       for (i =0; i<21; i++)
+		       for (i = 0; i < 21; i++)
 			       checksum += ee[i];
 		       if (checksum != ee[21])
 			       return;
@@ -3703,12 +3728,13 @@ static void __devinit osprey_eeprom(stru
 	       unsigned short type;
 	       int offset = 4*16;
 
-	       for(; offset < 8*16; offset += 16) {
+	       for (; offset < 8*16; offset += 16) {
 		       unsigned short checksum = 0;
 		       /* verify the checksum */
-		       for(i = 0; i<14; i++) checksum += ee[i+offset];
-			       checksum = ~checksum;  /* no idea why */
-			       if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+		       for (i = 0; i < 14; i++)
+				checksum += ee[i+offset];
+			checksum = ~checksum;  /* no idea why */
+			if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
 				   ((checksum & 0x0FF) == ee[offset+15])) {
 			       break;
 		       }
@@ -3721,7 +3747,6 @@ static void __devinit osprey_eeprom(stru
 	       type = (ee[offset+4]<<8) | (ee[offset+5]);
 
 	       switch(type) {
-
 	       /* 848 based */
 	       case 0x0004:
 		       btv->c.type = BTTV_BOARD_OSPREY1x0_848;
@@ -4149,8 +4174,7 @@ static int tea5757_read(struct bttv *btv
 	}
 
 	dprintk("bttv%d: tea5757:",btv->c.nr);
-	for(i = 0; i < 24; i++)
-	{
+	for (i = 0; i < 24; i++) {
 		udelay(5);
 		bus_high(btv,btv->mbox_clk);
 		udelay(5);
@@ -4182,8 +4206,7 @@ static int tea5757_write(struct bttv *bt
 	dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value);
 	bus_low(btv,btv->mbox_clk);
 	bus_high(btv,btv->mbox_we);
-	for(i = 0; i < 25; i++)
-	{
+	for (i = 0; i < 25; i++) {
 		if (reg & 0x1000000)
 			bus_high(btv,btv->mbox_data);
 		else
@@ -4755,7 +4778,7 @@ static void kodicom4400r_init(struct btt
 	gpio_write(1 << 9);	/* reset MUX */
 	gpio_write(0);
 	/* Preset camera 0 to the 4 controllers */
-	for (ix=0; ix<4; ix++) {
+	for (ix = 0; ix < 4; ix++) {
 		sw_status[ix] = ix;
 		kodicom4400r_write(btv, ix, ix, 1);
 	}
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 5720b77..1c38723 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -164,6 +164,24 @@ static ssize_t show_card(struct class_de
 static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
 
 /* ----------------------------------------------------------------------- */
+/* dvb auto-load setup                                                     */
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	request_module("dvb-bt8xx");
+}
+
+static void request_modules(struct bttv *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+
+/* ----------------------------------------------------------------------- */
 /* static data                                                             */
 
 /* special timing tables from conexant... */
@@ -4769,9 +4787,11 @@ static int __devinit bttv_probe(struct p
 		disclaim_video_lines(btv);
 	}
 
-	/* add subdevices */
-	if (bttv_tvcards[btv->c.type].has_dvb)
+	/* add subdevices and autoload dvb-bt8xx if needed */
+	if (bttv_tvcards[btv->c.type].has_dvb) {
 		bttv_sub_add_device(&btv->c, "dvb");
+		request_modules(btv);
+	}
 
 	bttv_input_init(btv);
 
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index ba081f6..84154c2 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -71,7 +71,6 @@ struct bus_type bttv_sub_bus_type = {
 	.probe  = bttv_sub_probe,
 	.remove = bttv_sub_remove,
 };
-EXPORT_SYMBOL(bttv_sub_bus_type);
 
 static void release_sub_device(struct device *dev)
 {
@@ -152,7 +151,6 @@ void bttv_gpio_inout(struct bttv_core *c
 	btwrite(data,BT848_GPIO_OUT_EN);
 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
 }
-EXPORT_SYMBOL(bttv_gpio_inout);
 
 u32 bttv_gpio_read(struct bttv_core *core)
 {
@@ -162,7 +160,6 @@ u32 bttv_gpio_read(struct bttv_core *cor
 	value = btread(BT848_GPIO_DATA);
 	return value;
 }
-EXPORT_SYMBOL(bttv_gpio_read);
 
 void bttv_gpio_write(struct bttv_core *core, u32 value)
 {
@@ -170,7 +167,6 @@ void bttv_gpio_write(struct bttv_core *c
 
 	btwrite(value,BT848_GPIO_DATA);
 }
-EXPORT_SYMBOL(bttv_gpio_write);
 
 void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
 {
@@ -185,7 +181,6 @@ void bttv_gpio_bits(struct bttv_core *co
 	btwrite(data,BT848_GPIO_DATA);
 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
 }
-EXPORT_SYMBOL(bttv_gpio_bits);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 62b8730..0dfa49b 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -412,7 +412,7 @@ static void do_i2c_scan(char *name, stru
 	unsigned char buf;
 	int i,rc;
 
-	for (i = 0; i < 128; i++) {
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
 		c->addr = i;
 		rc = i2c_master_recv(c,&buf,0);
 		if (rc < 0)
diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c
index 19b564a..ecf0798 100644
--- a/drivers/media/video/bt8xx/bttv-if.c
+++ b/drivers/media/video/bt8xx/bttv-if.c
@@ -33,32 +33,16 @@ #include <asm/io.h>
 
 #include "bttvp.h"
 
-EXPORT_SYMBOL(bttv_get_cardinfo);
 EXPORT_SYMBOL(bttv_get_pcidev);
-EXPORT_SYMBOL(bttv_get_id);
 EXPORT_SYMBOL(bttv_gpio_enable);
 EXPORT_SYMBOL(bttv_read_gpio);
 EXPORT_SYMBOL(bttv_write_gpio);
-EXPORT_SYMBOL(bttv_get_gpio_queue);
-EXPORT_SYMBOL(bttv_i2c_call);
 
 /* ----------------------------------------------------------------------- */
 /* Exported functions - for other modules which want to access the         */
 /*                      gpio ports (IR for example)                        */
 /*                      see bttv.h for comments                            */
 
-int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
-{
-	printk("The bttv_* interface is obsolete and will go away,\n"
-	       "please use the new, sysfs based interface instead.\n");
-	if (card >= bttv_num) {
-		return -1;
-	}
-	*type   = bttvs[card].c.type;
-	*cardid = bttvs[card].cardid;
-	return 0;
-}
-
 struct pci_dev* bttv_get_pcidev(unsigned int card)
 {
 	if (card >= bttv_num)
@@ -66,16 +50,6 @@ struct pci_dev* bttv_get_pcidev(unsigned
 	return bttvs[card].c.pci;
 }
 
-int bttv_get_id(unsigned int card)
-{
-	printk("The bttv_* interface is obsolete and will go away,\n"
-	       "please use the new, sysfs based interface instead.\n");
-	if (card >= bttv_num) {
-		return -1;
-	}
-	return bttvs[card].c.type;
-}
-
 
 int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
 {
@@ -130,28 +104,6 @@ int bttv_write_gpio(unsigned int card, u
 	return 0;
 }
 
-wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
-{
-	struct bttv *btv;
-
-	if (card >= bttv_num) {
-		return NULL;
-	}
-
-	btv = &bttvs[card];
-	if (bttvs[card].shutdown) {
-		return NULL;
-	}
-	return &btv->gpioq;
-}
-
-void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
-{
-	if (card >= bttv_num)
-		return;
-	bttv_call_i2c_clients(&bttvs[card], cmd, arg);
-}
-
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 5491acb..f821ba6 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -168,6 +168,8 @@ #define BTTV_BOARD_ASOUND_SKYEYE	   0x8d
 #define BTTV_BOARD_SABRENT_TVFM   	   0x8e
 #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB     0x8f
 #define BTTV_BOARD_MACHTV_MAGICTV          0x90
+#define BTTV_BOARD_SSAI_SECURITY	   0x91
+#define BTTV_BOARD_SSAI_ULTRASOUND	   0x92
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
@@ -260,17 +262,8 @@ extern int bttv_handle_chipset(struct bt
 /* this obsolete -- please use the sysfs-based
    interface below for new code */
 
-/* returns card type + card ID (for bt878-based ones)
-   for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
-   returns negative value if error occurred
-*/
-extern int bttv_get_cardinfo(unsigned int card, int *type,
-			     unsigned int *cardid);
 extern struct pci_dev* bttv_get_pcidev(unsigned int card);
 
-/* obsolete, use bttv_get_cardinfo instead */
-extern int bttv_get_id(unsigned int card);
-
 /* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
    data | (current_GPOE_value & ~mask)
    returns negative value if error occurred
@@ -290,20 +283,6 @@ extern int bttv_read_gpio(unsigned int c
 extern int bttv_write_gpio(unsigned int card,
 			   unsigned long mask, unsigned long data);
 
-/* returns pointer to task queue which can be used as parameter to
-   interruptible_sleep_on
-   in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
-   (wake_up_interruptible) and following call to the function bttv_read_gpio
-   should return new value of GPDATA,
-   returns NULL value if error occurred or queue is not available
-   WARNING: because there is no buffer for GPIO data, one MUST
-   process data ASAP
-*/
-extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
-
-/* call i2c clients
-*/
-extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg);
 
 
 
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index ad79b8d..8f44f02 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -434,6 +434,9 @@ #endif
 	unsigned int users;
 	struct bttv_fh init;
 
+	/* used to make dvb-bt8xx autoloadable */
+	struct work_struct request_module_wk;
+
 	/* Default (0) and current (1) video capturing and overlay
 	   cropping parameters in bttv_tvnorm.cropcap units. Protected
 	   by bttv.lock. */
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 710c11a..96254db 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -4,6 +4,7 @@
  * sensor.
  *
  * Copyright 2006 One Laptop Per Child Association, Inc.
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
  *
  * Written by Jonathan Corbet, corbet@lwn.net.
  *
@@ -22,6 +23,7 @@ #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/list.h>
@@ -36,7 +38,7 @@ #include <asm/io.h>
 
 #include "cafe_ccic-regs.h"
 
-#define CAFE_VERSION 0x000001
+#define CAFE_VERSION 0x000002
 
 
 /*
@@ -164,7 +166,7 @@ struct cafe_camera
 	struct tasklet_struct s_tasklet;
 
 	/* Current operating parameters */
-	enum v4l2_chip_ident sensor_type;		/* Currently ov7670 only */
+	u32 sensor_type;		/* Currently ov7670 only */
 	struct v4l2_pix_format pix_format;
 
 	/* Locks */
@@ -704,7 +706,13 @@ static void cafe_ctlr_init(struct cafe_c
 	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
 	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
 	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+	/*
+	 * Here we must wait a bit for the controller to come around.
+	 */
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
 	mdelay(5);	/* FIXME revisit this */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+
 	cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
 	cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
 	/*
@@ -772,9 +780,9 @@ static void cafe_ctlr_power_up(struct ca
 	 * Control 1 is power down, set to 0 to operate.
 	 */
 	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-	mdelay(1); /* Marvell says 1ms will do it */
+//	mdelay(1); /* Marvell says 1ms will do it */
 	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-	mdelay(1); /* Enough? */
+//	mdelay(1); /* Enough? */
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
 }
 
@@ -818,6 +826,7 @@ static int __cafe_cam_reset(struct cafe_
  */
 static int cafe_cam_init(struct cafe_camera *cam)
 {
+	struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 };
 	int ret;
 
 	mutex_lock(&cam->s_mutex);
@@ -827,9 +836,11 @@ static int cafe_cam_init(struct cafe_cam
 	ret = __cafe_cam_reset(cam);
 	if (ret)
 		goto out;
-	ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
+	chip.match_chip = cam->sensor->addr;
+	ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip);
 	if (ret)
 		goto out;
+	cam->sensor_type = chip.ident;
 //	if (cam->sensor->addr != OV7xx0_SID) {
 	if (cam->sensor_type != V4L2_IDENT_OV7670) {
 		cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
@@ -1792,18 +1803,19 @@ static void cafe_frame_tasklet(unsigned 
 		if (list_empty(&cam->sb_avail))
 			break;  /* Leave it valid, hope for better later */
 		clear_bit(bufno, &cam->flags);
-		/*
-		 * We could perhaps drop the spinlock during this
-		 * big copy.  Something to consider.
-		 */
 		sbuf = list_entry(cam->sb_avail.next,
 				struct cafe_sio_buffer, list);
+		/*
+		 * Drop the lock during the big copy.  This *should* be safe...
+		 */
+		spin_unlock_irqrestore(&cam->dev_lock, flags);
 		memcpy(sbuf->buffer, cam->dma_bufs[bufno],
 				cam->pix_format.sizeimage);
 		sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
 		sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
 		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
 		sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+		spin_lock_irqsave(&cam->dev_lock, flags);
 		list_move_tail(&sbuf->list, &cam->sb_full);
 	}
 	if (! list_empty(&cam->sb_full))
@@ -2107,6 +2119,7 @@ static int cafe_pci_probe(struct pci_dev
 	cam->v4ldev = cafe_v4l_template;
 	cam->v4ldev.debug = 0;
 //	cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
+	cam->v4ldev.dev = &pdev->dev;
 	ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
 	if (ret)
 		goto out_smbus;
@@ -2176,10 +2189,52 @@ static void cafe_pci_remove(struct pci_d
 }
 
 
+#ifdef CONFIG_PM
+/*
+ * Basic power management.
+ */
+static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+	int ret;
+
+	ret = pci_save_state(pdev);
+	if (ret)
+		return ret;
+	cafe_ctlr_stop_dma(cam);
+	cafe_ctlr_power_down(cam);
+	pci_disable_device(pdev);
+	return 0;
+}
+
+
+static int cafe_pci_resume(struct pci_dev *pdev)
+{
+	struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+	int ret = 0;
+
+	ret = pci_restore_state(pdev);
+	if (ret)
+		return ret;
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		cam_warn(cam, "Unable to re-enable device on resume!\n");
+		return ret;
+	}
+	cafe_ctlr_init(cam);
+	cafe_ctlr_power_up(cam);
+	set_bit(CF_CONFIG_NEEDED, &cam->flags);
+	if (cam->state == S_SPECREAD)
+		cam->state = S_IDLE;  /* Don't bother restarting */
+	else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)
+		ret = cafe_read_setup(cam, cam->state);
+	return ret;
+}
+
+#endif  /* CONFIG_PM */
 
 
 static struct pci_device_id cafe_ids[] = {
-	{ PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
 	{ PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
 	{ PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
 	{ 0, }
@@ -2192,6 +2247,10 @@ static struct pci_driver cafe_pci_driver
 	.id_table = cafe_ids,
 	.probe = cafe_pci_probe,
 	.remove = cafe_pci_remove,
+#ifdef CONFIG_PM
+	.suspend = cafe_pci_suspend,
+	.resume = cafe_pci_resume,
+#endif
 };
 
 
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index 6eaa692..78392fb 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -47,7 +47,6 @@ #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 
 struct cpia_camera_ops
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index b12cec9..c431df8 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -34,7 +34,6 @@ #include <linux/parport.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 
 #include <linux/kmod.h>
@@ -62,7 +61,6 @@ #define PPCPIA_PARPORT_AUTO -3
 #define PPCPIA_PARPORT_OFF -2
 #define PPCPIA_PARPORT_NONE -1
 
-#ifdef MODULE
 static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
 static char *parport[PARPORT_MAX] = {NULL,};
 
@@ -72,11 +70,6 @@ MODULE_LICENSE("GPL");
 
 module_param_array(parport, charp, NULL, 0);
 MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
-#else
-static int parport_nr[PARPORT_MAX] __initdata =
-	{[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
-static int parport_ptr = 0;
-#endif
 
 struct pp_cam_entry {
 	struct pardevice *pdev;
@@ -141,7 +134,6 @@ static void cpia_pp_run_callback(struct 
 	cam = container_of(work, struct pp_cam_entry, cb_task);
 	cb_func = cam->cb_func;
 	cb_data = cam->cb_data;
-	work_release(work);
 
 	cb_func(cb_data);
 }
@@ -682,7 +674,7 @@ static int cpia_pp_registerCallback(void
 	if(cam->port->irq != PARPORT_IRQ_NONE) {
 		cam->cb_func = cb;
 		cam->cb_data = cbdata;
-		INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback);
+		INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
 	} else {
 		retval = -1;
 	}
@@ -820,7 +812,7 @@ static struct parport_driver cpia_pp_dri
 	.detach = cpia_pp_detach,
 };
 
-static int cpia_pp_init(void)
+static int __init cpia_pp_init(void)
 {
 	printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
 	       CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
@@ -839,8 +831,7 @@ static int cpia_pp_init(void)
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
+static int __init cpia_init(void)
 {
 	if (parport[0]) {
 		/* The user gave some parameters.  Let's see what they were. */
@@ -867,38 +858,11 @@ int init_module(void)
 	return cpia_pp_init();
 }
 
-void cleanup_module(void)
+static void __exit cpia_cleanup(void)
 {
-	parport_unregister_driver (&cpia_pp_driver);
+	parport_unregister_driver(&cpia_pp_driver);
 	return;
 }
 
-#else /* !MODULE */
-
-static int __init cpia_pp_setup(char *str)
-{
-	int err;
-
-	if (!strncmp(str, "parport", 7)) {
-		int n = simple_strtoul(str + 7, NULL, 10);
-		if (parport_ptr < PARPORT_MAX) {
-			parport_nr[parport_ptr++] = n;
-		} else {
-			LOG("too many ports, %s ignored.\n", str);
-		}
-	} else if (!strcmp(str, "auto")) {
-		parport_nr[0] = PPCPIA_PARPORT_AUTO;
-	} else if (!strcmp(str, "none")) {
-		parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
-	}
-
-	err=cpia_pp_init();
-	if (err)
-		return err;
-
-	return 1;
-}
-
-__setup("cpia_pp=", cpia_pp_setup);
-
-#endif /* !MODULE */
+module_init(cpia_init);
+module_exit(cpia_cleanup);
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index de87247..a73e285 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -28,6 +28,7 @@ #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
@@ -103,6 +104,9 @@ static int cs53l32a_command(struct i2c_c
 		cs53l32a_write(client, 0x05, (u8) ctrl->value);
 		break;
 
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
+
 	case VIDIOC_LOG_STATUS:
 		{
 			u8 v = cs53l32a_read(client, 0x01);
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index d60cd5e..d73c86a 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -26,7 +26,6 @@ #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
-#include <linux/i2c.h>
 
 #include <media/tuner.h>
 #include <media/cx2341x.h>
@@ -51,6 +50,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
 	V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
 	V4L2_CID_MPEG_AUDIO_EMPHASIS,
 	V4L2_CID_MPEG_AUDIO_CRC,
+	V4L2_CID_MPEG_AUDIO_MUTE,
 	V4L2_CID_MPEG_VIDEO_ENCODING,
 	V4L2_CID_MPEG_VIDEO_ASPECT,
 	V4L2_CID_MPEG_VIDEO_B_FRAMES,
@@ -60,6 +60,8 @@ const u32 cx2341x_mpeg_ctrls[] = {
 	V4L2_CID_MPEG_VIDEO_BITRATE,
 	V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
 	V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+	V4L2_CID_MPEG_VIDEO_MUTE,
+	V4L2_CID_MPEG_VIDEO_MUTE_YUV,
 	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
 	V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
 	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
@@ -71,6 +73,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
 	V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
 	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
 	V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+	V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
 	0
 };
 
@@ -102,6 +105,9 @@ static int cx2341x_get_ctrl(struct cx234
 	case V4L2_CID_MPEG_AUDIO_CRC:
 		ctrl->value = params->audio_crc;
 		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		ctrl->value = params->audio_mute;
+		break;
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
 		ctrl->value = params->video_encoding;
 		break;
@@ -129,6 +135,12 @@ static int cx2341x_get_ctrl(struct cx234
 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
 		ctrl->value = params->video_temporal_decimation;
 		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		ctrl->value = params->video_mute;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+		ctrl->value = params->video_mute_yuv;
+		break;
 	case V4L2_CID_MPEG_STREAM_TYPE:
 		ctrl->value = params->stream_type;
 		break;
@@ -168,6 +180,9 @@ static int cx2341x_get_ctrl(struct cx234
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
 		ctrl->value = params->video_chroma_median_filter_bottom;
 		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		ctrl->value = params->stream_insert_nav_packets;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -201,6 +216,9 @@ static int cx2341x_set_ctrl(struct cx234
 	case V4L2_CID_MPEG_AUDIO_CRC:
 		params->audio_crc = ctrl->value;
 		break;
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		params->audio_mute = ctrl->value;
+		break;
 	case V4L2_CID_MPEG_VIDEO_ASPECT:
 		params->video_aspect = ctrl->value;
 		break;
@@ -243,6 +261,12 @@ static int cx2341x_set_ctrl(struct cx234
 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
 		params->video_temporal_decimation = ctrl->value;
 		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		params->video_mute = (ctrl->value != 0);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
+		params->video_mute_yuv = ctrl->value;
+		break;
 	case V4L2_CID_MPEG_STREAM_TYPE:
 		params->stream_type = ctrl->value;
 		params->video_encoding =
@@ -290,6 +314,9 @@ static int cx2341x_set_ctrl(struct cx234
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
 		params->video_chroma_median_filter_bottom = ctrl->value;
 		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		params->stream_insert_nav_packets = ctrl->value;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -336,6 +363,9 @@ static int cx2341x_ctrl_query_fill(struc
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
 		name = "Median Chroma Filter Minimum";
 		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		name = "Insert Navigation Packets";
+		break;
 
 	default:
 		return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
@@ -350,6 +380,12 @@ static int cx2341x_ctrl_query_fill(struc
 		min = 0;
 		step = 1;
 		break;
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+		min = 0;
+		max = 1;
+		step = 1;
+		break;
 	default:
 		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
 		break;
@@ -505,6 +541,9 @@ int cx2341x_ctrl_query(struct cx2341x_mp
 		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
+	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
 	default:
 		return v4l2_ctrl_query_fill_std(qctrl);
 
@@ -656,6 +695,7 @@ void cx2341x_fill_defaults(struct cx2341
 	/* stream */
 	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
 	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+	.stream_insert_nav_packets = 0,
 
 	/* audio */
 	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
@@ -665,6 +705,7 @@ void cx2341x_fill_defaults(struct cx2341
 	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
 	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
 	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+	.audio_mute = 0,
 
 	/* video */
 	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
@@ -676,6 +717,8 @@ void cx2341x_fill_defaults(struct cx2341
 	.video_bitrate = 6000000,
 	.video_bitrate_peak = 8000000,
 	.video_temporal_decimation = 0,
+	.video_mute = 0,
+	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
 
 	/* encoding filters */
 	.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
@@ -779,6 +822,10 @@ int cx2341x_update(void *priv, cx2341x_m
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
 		if (err) return err;
 	}
+	if (old == NULL || old->audio_mute != new->audio_mute) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
+		if (err) return err;
+	}
 	if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
 		old->video_bitrate != new->video_bitrate ||
 		old->video_bitrate_peak != new->video_bitrate_peak) {
@@ -826,6 +873,15 @@ int cx2341x_update(void *priv, cx2341x_m
 			new->video_temporal_decimation);
 		if (err) return err;
 	}
+	if (old == NULL || old->video_mute != new->video_mute ||
+			(new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
+		if (err) return err;
+	}
+	if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
+		if (err) return err;
+	}
 	return 0;
 }
 
@@ -854,18 +910,22 @@ void cx2341x_log_status(struct cx2341x_m
 	int temporal = p->video_temporal_filter;
 
 	/* Stream */
-	printk(KERN_INFO "%s: Stream: %s\n",
+	printk(KERN_INFO "%s: Stream: %s",
 		prefix,
 		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+	if (p->stream_insert_nav_packets)
+		printk(" (with navigation packets)");
+	printk("\n");
 	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",
+	printk(KERN_INFO "%s: Video:  %dx%d, %d fps%s\n",
 		prefix,
 		p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
-		p->is_50hz ? 25 : 30);
+		p->is_50hz ? 25 : 30,
+		(p->video_mute) ? " (muted)" : "");
 	printk(KERN_INFO "%s: Video:  %s, %s, %s, %d",
 		prefix,
 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
@@ -886,12 +946,13 @@ void cx2341x_log_status(struct cx2341x_m
 	}
 
 	/* Audio */
-	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s",
+	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
 		prefix,
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
-		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
+		p->audio_mute ? " (muted)" : "");
 	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
 		printk(", %s",
 			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 774d253..1757a58 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -35,6 +35,7 @@ #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -827,9 +828,8 @@ #endif
 			cx25840_initialize(client, 0);
 		break;
 
-	case VIDIOC_INT_G_CHIP_IDENT:
-		*(enum v4l2_chip_ident *)arg = state->id;
-		break;
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
 
 	default:
 		return -EINVAL;
@@ -847,7 +847,7 @@ static int cx25840_detect_client(struct 
 {
 	struct i2c_client *client;
 	struct cx25840_state *state;
-	enum v4l2_chip_ident id;
+	u32 id;
 	u16 device_id;
 
 	/* Check if the adapter supports the needed features
@@ -902,6 +902,7 @@ static int cx25840_detect_client(struct 
 	state->audmode = V4L2_TUNER_MODE_LANG1;
 	state->vbi_line_offset = 8;
 	state->id = id;
+	state->rev = device_id;
 
 	i2c_attach_client(client);
 
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 2804906..f4b56d2 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -43,7 +43,8 @@ struct cx25840_state {
 	u32 audclk_freq;
 	int audmode;
 	int vbi_line_offset;
-	enum v4l2_chip_ident id;
+	u32 id;
+	u32 rev;
 	int is_cx25836;
 };
 
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 0e86b9d..e852024 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -17,7 +17,6 @@
 
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include <linux/firmware.h>
 #include <media/v4l2-common.h>
 #include <media/cx25840.h>
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index b2a66ba..0f9d969 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -53,7 +53,6 @@ config VIDEO_CX88_DVB
 	select DVB_OR51132 if !DVB_FE_CUSTOMISE
 	select DVB_CX22702 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_TUNER_LGH06XF 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
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index e4355fd..2d666b5 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -27,6 +27,8 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
 #include <asm/delay.h>
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -232,7 +234,8 @@ static void cx8801_aud_irq(snd_cx88_card
 	cx_write(MO_AUD_INTSTAT, status);
 	if (debug > 1  ||  (status & mask & ~0xff))
 		cx88_print_irqbits(core->name, "irq aud",
-				   cx88_aud_irqs, status, mask);
+				   cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
+				   status, mask);
 	/* risc op code error */
 	if (status & (1 << 16)) {
 		printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
@@ -413,11 +416,9 @@ static int snd_cx88_hw_params(struct snd
 
 	dprintk(1,"Setting buffer\n");
 
-	buf = kmalloc(sizeof(*buf),GFP_KERNEL);
+	buf = kzalloc(sizeof(*buf),GFP_KERNEL);
 	if (NULL == buf)
 		return -ENOMEM;
-	memset(buf,0,sizeof(*buf));
-
 
 	buf->vb.memory = V4L2_MEMORY_MMAP;
 	buf->vb.width  = chip->period_size;
@@ -682,7 +683,7 @@ static int __devinit snd_cx88_create(str
 		return err;
 	}
 
-	if (!pci_dma_supported(pci,0xffffffff)) {
+	if (!pci_dma_supported(pci,DMA_32BIT_MASK)) {
 		dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
 		err = -EIO;
 		cx88_core_put(core,pci);
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 65e9d80..e61102d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -885,6 +885,12 @@ struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_DVB,
 			.vmux   = 0,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
 		}},
 		.mpeg           = CX88_MPEG_DVB,
 	},
@@ -1537,10 +1543,10 @@ struct cx88_subid cx88_subids[] = {
 	},{
 		.subvendor = 0x17de,
 		.subdevice = 0x0840,
-	       .card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
-       },{
-	       .subvendor = 0x1421,
-	       .subdevice = 0x0305,
+		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0305,
 		.card      = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
 	},{
 		.subvendor = 0x18ac,
@@ -1631,6 +1637,10 @@ struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x0070,
 		.subdevice = 0x1402,
 		.card      = CX88_BOARD_HAUPPAUGE_HVR3000,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
+		.card      = CX88_BOARD_KWORLD_DVBS_100,
 	},
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1786,7 +1796,7 @@ static void dvico_fusionhdtv_hybrid_init
 		{ 0x03, 0x0C },
 	};
 
-	for (i = 0; i < 13; i++) {
+	for (i = 0; i < ARRAY_SIZE(init_bufs); i++) {
 		msg.buf = init_bufs[i];
 		msg.len = (i != 12 ? 5 : 2);
 		err = i2c_transfer(&core->i2c_adap, &msg, 1);
@@ -1913,12 +1923,21 @@ void cx88_card_setup(struct cx88_core *c
 		if (0 == core->i2c_rc) {
 			/* enable tuner */
 			int i;
-			static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+			static const u8 buffer [][2] = {
+				{0x10,0x12},
+				{0x13,0x04},
+				{0x16,0x00},
+				{0x14,0x04},
+				{0x17,0x00}
+			};
 			core->i2c_client.addr = 0x0a;
 
-			for (i = 0; i < 5; i++)
-				if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
-					printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+			for (i = 0; i < ARRAY_SIZE(buffer); i++)
+				if (2 != i2c_master_send(&core->i2c_client,
+							buffer[i],2))
+					printk(KERN_WARNING
+						"%s: Unable to enable "
+						"tuner(%i).\n",
 						core->name, i);
 		}
 		break;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index d86813b..f31ec96 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -489,12 +489,12 @@ static char *cx88_pci_irqs[32] = {
 };
 
 void cx88_print_irqbits(char *name, char *tag, char **strings,
-			u32 bits, u32 mask)
+			int len, u32 bits, u32 mask)
 {
 	unsigned int i;
 
 	printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits);
-	for (i = 0; i < 32; i++) {
+	for (i = 0; i < len; i++) {
 		if (!(bits & (1 << i)))
 			continue;
 		if (strings[i])
@@ -520,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core
 	}
 	if (!handled)
 		cx88_print_irqbits(core->name, "irq pci",
-				   cx88_pci_irqs, status,
-				   core->pci_irqmask);
+				   cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs),
+				   status, core->pci_irqmask);
 	return handled;
 }
 
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 4f55602..dbfe4dc 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -42,7 +42,6 @@ #include "zl10353.h"
 #include "cx22702.h"
 #include "or51132.h"
 #include "lgdt330x.h"
-#include "lgh06xf.h"
 #include "nxt200x.h"
 #include "cx24123.h"
 #include "isl6421.h"
@@ -476,6 +475,8 @@ static int dvb_register(struct cx8802_de
 	case CX88_BOARD_WINFAST_DTV2000H:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+	case CX88_BOARD_HAUPPAUGE_HVR1300:
+	case CX88_BOARD_HAUPPAUGE_HVR3000:
 		dev->dvb.frontend = dvb_attach(cx22702_attach,
 					       &hauppauge_hvr_config,
 					       &dev->core->i2c_adap);
@@ -631,8 +632,9 @@ #endif
 					       &fusionhdtv_5_gold,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(lgh06xf_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_lg_tdvs_h06xf);
 		}
 		}
 		break;
@@ -650,8 +652,9 @@ #endif
 					       &pchdtv_hd5500,
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
-			dvb_attach(lgh06xf_attach, dev->dvb.frontend,
-				   &dev->core->i2c_adap);
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap,
+				   &dvb_pll_lg_tdvs_h06xf);
 		}
 		}
 		break;
@@ -692,24 +695,6 @@ #endif
 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
 		}
 		break;
-	case CX88_BOARD_HAUPPAUGE_HVR1300:
-		dev->dvb.frontend = dvb_attach(cx22702_attach,
-					       &hauppauge_hvr_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_hvr_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;
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 9830d5c..7919a1f 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -1,3 +1,4 @@
+
 /*
 
     cx88-i2c.c  --  all the i2c code is here
@@ -195,7 +196,7 @@ static void do_i2c_scan(char *name, stru
 	unsigned char buf;
 	int i,rc;
 
-	for (i = 0; i < 128; i++) {
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
 		c->addr = i;
 		rc = i2c_master_recv(c,&buf,0);
 		if (rc < 0)
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 1fe1a83..2ebde2f 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -26,6 +26,7 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <asm/delay.h>
 
@@ -49,6 +50,27 @@ #define dprintk(level,fmt, arg...)	if (d
 #define mpeg_dbg(level,fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg)
 
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
+
+	if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB)
+		request_module("cx88-dvb");
+	if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD)
+		request_module("cx88-blackbird");
+}
+
+static void request_modules(struct cx8802_dev *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+
 static LIST_HEAD(cx8802_devlist);
 /* ------------------------------------------------------------------ */
 
@@ -345,7 +367,8 @@ static void cx8802_mpeg_irq(struct cx880
 
 	if (debug || (status & mask & ~0xff))
 		cx88_print_irqbits(core->name, "irq mpeg ",
-				   cx88_mpeg_irqs, status, mask);
+				   cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs),
+				   status, mask);
 
 	/* risc op code error */
 	if (status & (1 << 16)) {
@@ -427,7 +450,7 @@ int cx8802_init_common(struct cx8802_dev
 	if (pci_enable_device(dev->pci))
 		return -EIO;
 	pci_set_master(dev->pci);
-	if (!pci_dma_supported(dev->pci,0xffffffff)) {
+	if (!pci_dma_supported(dev->pci,DMA_32BIT_MASK)) {
 		printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
 		return -EIO;
 	}
@@ -778,6 +801,9 @@ static int __devinit cx8802_probe(struct
 
 	/* Maintain a reference so cx88-video can query the 8802 device. */
 	core->dvbdev = dev;
+
+	/* now autoload cx88-dvb or cx88-blackbird */
+	request_modules(dev);
 	return 0;
 
  fail_free:
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 97ef421..259ea08 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -43,14 +43,12 @@ #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/poll.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <linux/ioport.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
 
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index bdfe2af..b94ef8a 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,4 +1,3 @@
-
 /*
  *
  * device driver for Conexant 2388x based TV cards
@@ -34,6 +33,7 @@ #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <asm/div64.h>
@@ -1555,7 +1555,8 @@ static void cx8800_vid_irq(struct cx8800
 	cx_write(MO_VID_INTSTAT, status);
 	if (irq_debug  ||  (status & mask & ~0xff))
 		cx88_print_irqbits(core->name, "irq vid",
-				   cx88_vid_irqs, status, mask);
+				   cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs),
+				   status, mask);
 
 	/* risc op code error */
 	if (status & (1 << 16)) {
@@ -1778,7 +1779,7 @@ static int __devinit cx8800_initdev(stru
 	       dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
 
 	pci_set_master(pci_dev);
-	if (!pci_dma_supported(pci_dev,0xffffffff)) {
+	if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) {
 		printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
 		err = -EIO;
 		goto fail_core;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index a4f7bef..738d4f2 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -481,6 +481,8 @@ #endif
 
 	/* List of attached drivers */
 	struct cx8802_driver       drvlist;
+	struct work_struct request_module_wk;
+
 };
 
 /* ----------------------------------------------------------- */
@@ -510,7 +512,7 @@ #define cx_sandor(sreg,reg,mask,value) \
 /* cx88-core.c                                                 */
 
 extern void cx88_print_irqbits(char *name, char *tag, char **strings,
-			       u32 bits, u32 mask);
+			       int len, u32 bits, u32 mask);
 
 extern int cx88_core_irq(struct cx88_core *core, u32 status);
 extern void cx88_wakeup(struct cx88_core *core,
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index ff4b238..a5731f9 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -37,7 +37,6 @@ #include <asm/uaccess.h>
 #include <asm/atomic.h>
 #include <linux/delay.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 
 #include "dabusb.h"
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index ed882eb..418ea8b 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -23,7 +23,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/usb.h>
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index d829d8f..563a831 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -523,7 +523,7 @@ static void do_i2c_scan(char *name, stru
 	unsigned char buf;
 	int i, rc;
 
-	for (i = 0; i < 128; i++) {
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
 		c->addr = i;
 		rc = i2c_master_recv(c, &buf, 0);
 		if (rc < 0)
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 210582d..ed92b6f 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -173,7 +173,7 @@ static int get_key_pinnacle(struct IR_i2
 		return -EIO;
 	}
 
-	for (start = 0; start<4; start++) {
+	for (start = 0; start < ARRAY_SIZE(b); start++) {
 		if (b[start] == marker) {
 			code=b[(start+parity_offset+1)%4];
 			parity=b[(start+parity_offset)%4];
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
new file mode 100644
index 0000000..e854f3f
--- /dev/null
+++ b/drivers/media/video/ivtv/Kconfig
@@ -0,0 +1,26 @@
+config VIDEO_IVTV
+	tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
+	depends on VIDEO_V4L1 && VIDEO_V4L2 && USB && I2C && EXPERIMENTAL
+	select FW_LOADER
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_CX2341X
+	select VIDEO_CX25840
+	select VIDEO_MSP3400
+	select VIDEO_SAA711X
+	select VIDEO_SAA7127
+	select VIDEO_TVAUDIO
+	select VIDEO_CS53L32A
+	select VIDEO_WM8775
+	select VIDEO_WM8739
+	select VIDEO_UPD64031A
+	select VIDEO_UPD64083
+	---help---
+	  This is a video4linux driver for Conexant cx23416 or cx23416 based
+	  PCI personal video recorder devices.
+
+	  This is used in devices such as the Hauppauge PVR-150/250/350/500
+	  cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ivtv.
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
new file mode 100644
index 0000000..7e95148
--- /dev/null
+++ b/drivers/media/video/ivtv/Makefile
@@ -0,0 +1,7 @@
+ivtv-objs	:= ivtv-audio.o ivtv-cards.o ivtv-controls.o \
+		   ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
+		   ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
+		   ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
+		   ivtv-vbi.o ivtv-video.o ivtv-yuv.o
+
+obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c
new file mode 100644
index 0000000..d702b8b
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-audio.c
@@ -0,0 +1,74 @@
+/*
+    Audio-related ivtv functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-i2c.h"
+#include "ivtv-gpio.h"
+#include "ivtv-cards.h"
+#include "ivtv-audio.h"
+#include <media/msp3400.h>
+#include <linux/videodev.h>
+
+/* Selects the audio input and output according to the current
+   settings. */
+int ivtv_audio_set_io(struct ivtv *itv)
+{
+	struct v4l2_routing route;
+	u32 audio_input;
+	int mux_input;
+
+	/* Determine which input to use */
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+		audio_input = itv->card->radio_input.audio_input;
+		mux_input = itv->card->radio_input.muxer_input;
+	} else {
+		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
+		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
+	}
+
+	/* handle muxer chips */
+	route.input = mux_input;
+	route.output = 0;
+	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+	route.input = audio_input;
+	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+	}
+	return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+}
+
+void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route)
+{
+	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+}
+
+void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq)
+{
+	static u32 freqs[3] = { 44100, 48000, 32000 };
+
+	/* The audio clock of the digitizer must match the codec sample
+	   rate otherwise you get some very strange effects. */
+	if (freq > 2)
+		return;
+	ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
+}
+
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h
new file mode 100644
index 0000000..9c42846
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-audio.h
@@ -0,0 +1,23 @@
+/*
+    Audio-related ivtv functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+int ivtv_audio_set_io(struct ivtv *itv);
+void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route);
+void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq);
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
new file mode 100644
index 0000000..8eab020
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -0,0 +1,964 @@
+/*
+    Functions to query card hardware
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-i2c.h"
+
+#include <media/msp3400.h>
+#include <media/wm8775.h>
+#include <media/cs53l32a.h>
+#include <media/cx25840.h>
+#include <media/upd64031a.h>
+
+#define MSP_TUNER  MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
+				MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
+#define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
+				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+
+/********************** card configuration *******************************/
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+   This keeps the PCI ID database up to date. Note that the entries
+   must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+   New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge PVR-250 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */
+static const struct ivtv_card ivtv_card_pvr250 = {
+	.type = IVTV_CARD_PVR_250,
+	.name = "Hauppauge WinTV PVR-250",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_TUNER  },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Hauppauge PVR-350 cards */
+
+/* Outputs for Hauppauge PVR350 cards */
+static struct ivtv_card_output ivtv_pvr350_outputs[] = {
+	{
+		.name = "S-Video + Composite",
+		.video_output = 0,
+	}, {
+		.name = "Composite",
+		.video_output = 1,
+	}, {
+		.name = "S-Video",
+		.video_output = 2,
+	}, {
+		.name = "RGB",
+		.video_output = 3,
+	}, {
+		.name = "YUV C",
+		.video_output = 4,
+	}, {
+		.name = "YUV V",
+		.video_output = 5,
+	}
+};
+
+static const struct ivtv_card ivtv_card_pvr350 = {
+	.type = IVTV_CARD_PVR_350,
+	.name = "Hauppauge WinTV PVR-350",
+	.v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER,
+	.video_outputs = ivtv_pvr350_outputs,
+	.nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs),
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_TUNER  },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+};
+
+/* PVR-350 V1 boards have a different audio tuner input and use a
+   saa7114 instead of a saa7115.
+   Note that the info below comes from a pre-production model so it may
+   not be correct. Especially the audio behaves strangely (mono only it seems) */
+static const struct ivtv_card ivtv_card_pvr350_v1 = {
+	.type = IVTV_CARD_PVR_350_V1,
+	.name = "Hauppauge WinTV PVR-350 (V1)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER,
+	.video_outputs = ivtv_pvr350_outputs,
+	.nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs),
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 |
+		  IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 },
+		{ IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  MSP_MONO   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   MSP_SCART1 },
+		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Hauppauge PVR-150/PVR-500 cards */
+
+static const struct ivtv_card ivtv_card_pvr150 = {
+	.type = IVTV_CARD_PVR_150,
+	.name = "Hauppauge WinTV PVR-150",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_WM8775,
+	.hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 |
+		  IVTV_HW_TVEEPROM | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE7 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
+		{ IVTV_CARD_INPUT_SVIDEO2,    2, CX25840_SVIDEO2    },
+		{ IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,
+		  CX25840_AUDIO8, WM8775_AIN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,
+		  CX25840_AUDIO_SERIAL, WM8775_AIN2 },
+		{ IVTV_CARD_INPUT_LINE_IN2,
+		  CX25840_AUDIO_SERIAL, WM8775_AIN3 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER,
+			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
+	/* apparently needed for the IR blaster */
+	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M179 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_m179[] = {
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf },
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_m179 = {
+	.type = IVTV_CARD_M179,
+	.name = "AVerMedia M179",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xe380, .initial_value = 0x8290 },
+	.gpio_audio_input  = { .mask = 0x8040, .tuner  = 0x8000, .linein = 0x0000 },
+	.gpio_audio_mute   = { .mask = 0x2000, .mute   = 0x2000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0200, .lang2  = 0x0100, .both   = 0x0000 },
+	.gpio_audio_freq   = { .mask = 0x0018, .f32000 = 0x0000,
+			     .f44100 = 0x0008, .f48000 = 0x0010 },
+	.gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 },
+	.tuners = {
+		/* As far as we know all M179 cards use this tuner */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
+	},
+	.pci_list = ivtv_pci_m179,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_mpg600 = {
+	.type = IVTV_CARD_MPG600,
+	.name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0x3080, .initial_value = 0x0004 },
+	.gpio_audio_input  = { .mask = 0x3000, .tuner  = 0x0000, .linein = 0x2000 },
+	.gpio_audio_mute   = { .mask = 0x0001, .mute   = 0x0001 },
+	.gpio_audio_mode   = { .mask = 0x000e, .mono   = 0x0006, .stereo = 0x0004,
+			      .lang1 = 0x0004, .lang2  = 0x0000, .both   = 0x0008 },
+	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
+	.tuners = {
+		/* The PAL tuner is confirmed */
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_mpg600,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = {
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 },
+	{ PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_mpg160 = {
+	.type = IVTV_CARD_MPG160,
+	.name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0x7080, .initial_value = 0x400c },
+	.gpio_audio_input  = { .mask = 0x3000, .tuner  = 0x0000, .linein = 0x2000 },
+	.gpio_audio_mute   = { .mask = 0x0001, .mute   = 0x0001 },
+	.gpio_audio_mode   = { .mask = 0x000e, .mono   = 0x0006, .stereo = 0x0004,
+			      .lang1 = 0x0004, .lang2  = 0x0000, .both   = 0x0008 },
+	.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
+	.tuners = {
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_mpg160,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan PG600/Diamond PVR-550 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_pg600[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_pg600 = {
+	.type = IVTV_CARD_PG600,
+	.name = "Yuan PG600, Diamond PVR-550",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_pg600,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Adaptec VideOh! AVC-2410 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avc2410 = {
+	.type = IVTV_CARD_AVC2410,
+	.name = "Adaptec VideOh! AVC-2410",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_muxer = IVTV_HW_CS53L32A,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A |
+		  IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,
+		  MSP_TUNER, CS53L32A_IN0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,
+		  MSP_SCART1, CS53L32A_IN2 },
+	},
+	/* This card has no eeprom and in fact the Windows driver relies
+	   on the country/region setting of the user to decide which tuner
+	   is available. */
+	.tuners = {
+		/* This tuner has been verified for the AVC2410 */
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		/* This is a good guess, but I'm not totally sure this is
+		   the correct tuner for NTSC. */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.pci_list = ivtv_pci_avc2410,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Adaptec VideOh! AVC-2010 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avc2010 = {
+	.type = IVTV_CARD_AVC2010,
+	.name = "Adaptec VideOh! AVC-2010",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_CS53L32A,
+	.hw_audio_ctrl = IVTV_HW_CS53L32A,
+	.hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CS53L32A_IN2 },
+	},
+	/* Does not have a tuner */
+	.pci_list = ivtv_pci_avc2010,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Nagase Transgear 5000TV card */
+
+static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_tg5000tv = {
+	.type = IVTV_CARD_TG5000TV,
+	.name = "Nagase Transgear 5000TV",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X |
+	IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO2 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gr_config = UPD64031A_VERTICAL_EXTERNAL,
+	.gpio_init = { .direction = 0xe080, .initial_value = 0x8000 },
+	.gpio_audio_input  = { .mask = 0x8080, .tuner  = 0x8000, .linein = 0x0080 },
+	.gpio_audio_mute   = { .mask = 0x6000, .mute   = 0x6000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0300, .lang2  = 0x0000, .both   = 0x0200 },
+	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
+			  .composite = 0x0010, .svideo = 0x0020 },
+	.tuners = {
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_tg5000tv,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AOpen VA2000MAX-SNT6 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_va2000[] = {
+	{ PCI_DEVICE_ID_IVTV16, 0, 0xff5f },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_va2000 = {
+	.type = IVTV_CARD_VA2000MAX_SNT6,
+	.name = "AOpen VA2000MAX-SNT6",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_MSP34XX,
+	.hw_audio_ctrl = IVTV_HW_MSP34XX,
+	.hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 |
+		  IVTV_HW_UPD6408X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_va2000,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc = {
+	.type = IVTV_CARD_CX23416GYC,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO |
+		IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO3 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gr_config = UPD64031A_VERTICAL_EXTERNAL,
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.pci_list = ivtv_pci_cx23416gyc,
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
+	.type = IVTV_CARD_CX23416GYC_NOGR,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER |
+		  IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+};
+
+static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
+	.type = IVTV_CARD_CX23416GYC_NOGRYCS,
+	.name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 |
+						 IVTV_SAA717X_TUNER_FLAG },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN2 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN0 },
+	},
+	.gpio_init = { .direction = 0xf880, .initial_value = 0x8800 },
+	.gpio_video_input  = { .mask = 0x0020, .tuner  = 0x0000,
+			       .composite = 0x0020, .svideo = 0x0020 },
+	.gpio_audio_freq   = { .mask = 0xc000, .f32000 = 0x0000,
+			     .f44100 = 0x4000, .f48000 = 0x8000 },
+	.tuners = {
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gv_mvprx = {
+	.type = IVTV_CARD_GV_MVPRX,
+	.name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO |
+		  IVTV_HW_TUNER | IVTV_HW_WM8739 |
+		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO1    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2    },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xc301, .initial_value = 0x0200 },
+	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
+	.tuners = {
+		/* This card has the Panasonic VP27 tuner */
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+	},
+	.pci_list = ivtv_pci_gv_mvprx,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* I/O Data GV-MVP/RX2E card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 },
+	{0, 0, 0}
+};
+
+static const struct ivtv_card ivtv_card_gv_mvprx2e = {
+	.type = IVTV_CARD_GV_MVPRX2E,
+	.name = "I/O Data GV-MVP/RX2E",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+		  IVTV_HW_TVAUDIO | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xc301, .initial_value = 0x0200 },
+	.gpio_audio_input  = { .mask = 0xffff, .tuner  = 0x0200, .linein = 0x0300 },
+	.tuners = {
+		/* This card has the Panasonic VP27 tuner */
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+	},
+	.pci_list = ivtv_pci_gv_mvprx2e,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* GotVIEW PCI DVD card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
+	.type = IVTV_CARD_GOTVIEW_PCI_DVD,
+	.name = "GotView PCI DVD",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA717X,
+	.hw_audio = IVTV_HW_SAA717X,
+	.hw_audio_ctrl = IVTV_HW_SAA717X,
+	.hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE1 },  /* pin 116 */
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0 },     /* pin 114/109 */
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 },  /* pin 118 */
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_SAA717X_IN0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_SAA717X_IN2 },
+	},
+	.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
+	.tuners = {
+		/* This card has a Philips FQ1216ME MK3 tuner */
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.pci_list = ivtv_pci_gotview_pci_dvd,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* GotVIEW PCI DVD2 Deluxe card */
+
+static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
+	.type = IVTV_CARD_GOTVIEW_PCI_DVD2,
+	.name = "GotView PCI DVD2 Deluxe",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	.gpio_init = { .direction = 0x0800, .initial_value = 0 },
+	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
+	.tuners = {
+		/* This card has a Philips FQ1216ME MK5 tuner */
+		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+	},
+	.pci_list = ivtv_pci_gotview_pci_dvd2,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC622 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_yuan_mpc622 = {
+	.type = IVTV_CARD_YUAN_MPC622,
+	.name = "Yuan MPC622",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 },
+	.tuners = {
+		/* This card has the TDA8290/TDA8275 tuner chips */
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
+	},
+	.pci_list = ivtv_pci_yuan_mpc622,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* DIGITAL COWBOY DCT-MTVP1 card */
+
+static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_dctmvtvp1 = {
+	.type = IVTV_CARD_DCTMTVP1,
+	.name = "Digital Cowboy DCT-MTVP1",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X |
+		IVTV_HW_GPIO,
+	.hw_audio = IVTV_HW_GPIO,
+	.hw_audio_ctrl = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+		IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_SVIDEO0    },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO2    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  IVTV_GPIO_TUNER   },
+		{ IVTV_CARD_INPUT_LINE_IN1,   IVTV_GPIO_LINE_IN },
+	},
+	.gpio_init = { .direction = 0xe080, .initial_value = 0x8000 },
+	.gpio_audio_input  = { .mask = 0x8080, .tuner  = 0x8000, .linein = 0x0080 },
+	.gpio_audio_mute   = { .mask = 0x6000, .mute   = 0x6000 },
+	.gpio_audio_mode   = { .mask = 0x4300, .mono   = 0x4000, .stereo = 0x0200,
+			      .lang1 = 0x0300, .lang2  = 0x0000, .both   = 0x0200 },
+	.gpio_video_input  = { .mask = 0x0030, .tuner  = 0x0000,
+			       .composite = 0x0010, .svideo = 0x0020},
+	.tuners = {
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+	},
+	.pci_list = ivtv_pci_dctmvtvp1,
+};
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef HAVE_XC3028
+
+/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2,  0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_pg600v2 = {
+	.type = IVTV_CARD_PG600V2,
+	.name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+	},
+	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+	.pci_list = ivtv_pci_pg600v2,
+};
+#endif
+
+static const struct ivtv_card *ivtv_card_list[] = {
+	&ivtv_card_pvr250,
+	&ivtv_card_pvr350,
+	&ivtv_card_pvr150,
+	&ivtv_card_m179,
+	&ivtv_card_mpg600,
+	&ivtv_card_mpg160,
+	&ivtv_card_pg600,
+	&ivtv_card_avc2410,
+	&ivtv_card_avc2010,
+	&ivtv_card_tg5000tv,
+	&ivtv_card_va2000,
+	&ivtv_card_cx23416gyc,
+	&ivtv_card_gv_mvprx,
+	&ivtv_card_gv_mvprx2e,
+	&ivtv_card_gotview_pci_dvd,
+	&ivtv_card_gotview_pci_dvd2,
+	&ivtv_card_yuan_mpc622,
+	&ivtv_card_dctmvtvp1,
+#ifdef HAVE_XC3028
+	&ivtv_card_pg600v2,
+#endif
+
+	/* Variations of standard cards but with the same PCI IDs.
+	   These cards must come last in this list. */
+	&ivtv_card_pvr350_v1,
+	&ivtv_card_cx23416gyc_nogr,
+	&ivtv_card_cx23416gyc_nogrycs,
+};
+
+const struct ivtv_card *ivtv_get_card(u16 index)
+{
+	if (index >= ARRAY_SIZE(ivtv_card_list))
+		return NULL;
+	return ivtv_card_list[index];
+}
+
+int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
+{
+	const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"S-Video 1",
+		"S-Video 2",
+		"Composite 1",
+		"Composite 2",
+		"Composite 3"
+	};
+
+	memset(input, 0, sizeof(*input));
+	if (index >= itv->nof_inputs)
+		return -EINVAL;
+	input->index = index;
+	strcpy(input->name, input_strs[card_input->video_type - 1]);
+	input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
+			V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+	input->audioset = (1 << itv->nof_audio_inputs) - 1;
+	input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+				itv->tuner_std : V4L2_STD_ALL;
+	return 0;
+}
+
+int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
+{
+	const struct ivtv_card_output *card_output = itv->card->video_outputs + index;
+
+	memset(output, 0, sizeof(*output));
+	if (index >= itv->card->nof_outputs)
+		return -EINVAL;
+	output->index = index;
+	strcpy(output->name, card_output->name);
+	output->type = V4L2_OUTPUT_TYPE_ANALOG;
+	output->audioset = 1;
+	output->std = V4L2_STD_ALL;
+	return 0;
+}
+
+int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio)
+{
+	const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index;
+	static const char * const input_strs[] = {
+		"Tuner 1",
+		"Line In 1",
+		"Line In 2"
+	};
+
+	memset(audio, 0, sizeof(*audio));
+	if (index >= itv->nof_audio_inputs)
+		return -EINVAL;
+	strcpy(audio->name, input_strs[aud_input->audio_type - 1]);
+	audio->index = index;
+	audio->capability = V4L2_AUDCAP_STEREO;
+	return 0;
+}
+
+int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output)
+{
+	memset(aud_output, 0, sizeof(*aud_output));
+	if (itv->card->video_outputs == NULL || index != 0)
+		return -EINVAL;
+	strcpy(aud_output->name, "A/V Audio Out");
+	return 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
new file mode 100644
index 0000000..15012f8
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -0,0 +1,207 @@
+/*
+    Functions to query card hardware
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* hardware flags */
+#define IVTV_HW_CX25840   (1 << 0)
+#define IVTV_HW_SAA7115   (1 << 1)
+#define IVTV_HW_SAA7127   (1 << 2)
+#define IVTV_HW_MSP34XX   (1 << 3)
+#define IVTV_HW_TUNER     (1 << 4)
+#define IVTV_HW_WM8775    (1 << 5)
+#define IVTV_HW_CS53L32A  (1 << 6)
+#define IVTV_HW_TVEEPROM  (1 << 7)
+#define IVTV_HW_SAA7114   (1 << 8)
+#define IVTV_HW_TVAUDIO   (1 << 9)
+#define IVTV_HW_UPD64031A (1 << 10)
+#define IVTV_HW_UPD6408X  (1 << 11)
+#define IVTV_HW_SAA717X   (1 << 12)
+#define IVTV_HW_WM8739    (1 << 13)
+#define IVTV_HW_GPIO      (1 << 14)
+
+#define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
+
+/* video inputs */
+#define	IVTV_CARD_INPUT_VID_TUNER	1
+#define	IVTV_CARD_INPUT_SVIDEO1 	2
+#define	IVTV_CARD_INPUT_SVIDEO2 	3
+#define	IVTV_CARD_INPUT_COMPOSITE1 	4
+#define	IVTV_CARD_INPUT_COMPOSITE2 	5
+#define	IVTV_CARD_INPUT_COMPOSITE3 	6
+
+/* audio inputs */
+#define	IVTV_CARD_INPUT_AUD_TUNER	1
+#define	IVTV_CARD_INPUT_LINE_IN1 	2
+#define	IVTV_CARD_INPUT_LINE_IN2 	3
+
+#define IVTV_CARD_MAX_VIDEO_INPUTS 6
+#define IVTV_CARD_MAX_AUDIO_INPUTS 3
+#define IVTV_CARD_MAX_TUNERS  	   2
+
+/* SAA71XX HW inputs */
+#define IVTV_SAA71XX_COMPOSITE0 0
+#define IVTV_SAA71XX_COMPOSITE1 1
+#define IVTV_SAA71XX_COMPOSITE2 2
+#define IVTV_SAA71XX_COMPOSITE3 3
+#define IVTV_SAA71XX_COMPOSITE4 4
+#define IVTV_SAA71XX_COMPOSITE5 5
+#define IVTV_SAA71XX_SVIDEO0    6
+#define IVTV_SAA71XX_SVIDEO1    7
+#define IVTV_SAA71XX_SVIDEO2    8
+#define IVTV_SAA71XX_SVIDEO3    9
+
+/* SAA717X needs to mark the tuner input by ORing with this flag */
+#define IVTV_SAA717X_TUNER_FLAG 0x80
+
+/* Dummy HW input */
+#define IVTV_DUMMY_AUDIO        0
+
+/* GPIO HW inputs */
+#define IVTV_GPIO_TUNER   0
+#define IVTV_GPIO_LINE_IN 1
+
+/* SAA717X HW inputs */
+#define IVTV_SAA717X_IN0 0
+#define IVTV_SAA717X_IN1 1
+#define IVTV_SAA717X_IN2 2
+
+/* V4L2 capability aliases */
+#define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+			  V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \
+			  V4L2_CAP_SLICED_VBI_CAPTURE)
+#define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \
+			  V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_POS)
+
+struct ivtv_card_video_input {
+	u8  video_type; 	/* video input type */
+	u8  audio_index;	/* index in ivtv_card_audio_input array */
+	u16 video_input;	/* hardware video input */
+};
+
+struct ivtv_card_audio_input {
+	u8  audio_type;		/* audio input type */
+	u32 audio_input;	/* hardware audio input */
+	u16 muxer_input;	/* hardware muxer input for boards with a
+				   multiplexer chip */
+};
+
+struct ivtv_card_output {
+	u8  name[32];
+	u16 video_output;  /* hardware video output */
+};
+
+struct ivtv_card_pci_info {
+	u16 device;
+	u16 subsystem_vendor;
+	u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct ivtv_gpio_init { 	/* set initial GPIO DIR and OUT values */
+	u16 direction; 		/* DIR setting. Leave to 0 if no init is needed */
+	u16 initial_value;
+};
+
+struct ivtv_gpio_video_input { 	/* select tuner/line in input */
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 tuner;
+	u16 composite;
+	u16 svideo;
+};
+
+struct ivtv_gpio_audio_input { 	/* select tuner/line in input */
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 tuner;
+	u16 linein;
+	u16 radio;
+};
+
+struct ivtv_gpio_audio_mute {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 mute;		/* set this value to mute, 0 to unmute */
+};
+
+struct ivtv_gpio_audio_mode {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 mono; 		/* set audio to mono */
+	u16 stereo; 		/* set audio to stereo */
+	u16 lang1;		/* set audio to the first language */
+	u16 lang2;		/* set audio to the second language */
+	u16 both; 		/* both languages are output */
+};
+
+struct ivtv_gpio_audio_freq {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 f32000;
+	u16 f44100;
+	u16 f48000;
+};
+
+struct ivtv_gpio_audio_detect {
+	u16 mask; 		/* leave to 0 if not supported */
+	u16 stereo; 		/* if the input matches this value then
+				   stereo is detected */
+};
+
+struct ivtv_card_tuner {
+	v4l2_std_id std; 	/* standard for which the tuner is suitable */
+	int 	    tuner; 	/* tuner ID (from tuner.h) */
+};
+
+/* for card information/parameters */
+struct ivtv_card {
+	int type;
+	char *name;
+	u32 v4l2_capabilities;
+	u32 hw_video;		/* hardware used to process video */
+	u32 hw_audio;		/* hardware used to process audio */
+	u32 hw_audio_ctrl;	/* hardware used for the V4L2 controls (only 1 dev allowed) */
+	u32 hw_muxer;		/* hardware used to multiplex audio input */
+	u32 hw_all;		/* all hardware used by the board */
+	struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS];
+	struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS];
+	struct ivtv_card_audio_input radio_input;
+	int nof_outputs;
+	const struct ivtv_card_output *video_outputs;
+	u8 gr_config; 		/* config byte for the ghost reduction device */
+
+	/* GPIO card-specific settings */
+	struct ivtv_gpio_init 		gpio_init;
+	struct ivtv_gpio_video_input	gpio_video_input;
+	struct ivtv_gpio_audio_input 	gpio_audio_input;
+	struct ivtv_gpio_audio_mute 	gpio_audio_mute;
+	struct ivtv_gpio_audio_mode 	gpio_audio_mode;
+	struct ivtv_gpio_audio_freq 	gpio_audio_freq;
+	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
+
+	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
+
+	/* list of device and subsystem vendor/devices that
+	   correspond to this card type. */
+	const struct ivtv_card_pci_info *pci_list;
+};
+
+int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input);
+int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output);
+int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input);
+int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output);
+const struct ivtv_card *ivtv_get_card(u16 index);
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
new file mode 100644
index 0000000..7a876c3
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -0,0 +1,303 @@
+/*
+    ioctl control functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-audio.h"
+#include "ivtv-i2c.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-controls.h"
+
+static const u32 user_ctrls[] = {
+	V4L2_CID_USER_CLASS,
+	V4L2_CID_BRIGHTNESS,
+	V4L2_CID_CONTRAST,
+	V4L2_CID_SATURATION,
+	V4L2_CID_HUE,
+	V4L2_CID_AUDIO_VOLUME,
+	V4L2_CID_AUDIO_BALANCE,
+	V4L2_CID_AUDIO_BASS,
+	V4L2_CID_AUDIO_TREBLE,
+	V4L2_CID_AUDIO_MUTE,
+	V4L2_CID_AUDIO_LOUDNESS,
+	0
+};
+
+static const u32 *ctrl_classes[] = {
+	user_ctrls,
+	cx2341x_mpeg_ctrls,
+	NULL
+};
+
+static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
+{
+	const char *name;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
+
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (qctrl->id == 0)
+		return -EINVAL;
+
+	switch (qctrl->id) {
+	/* Standard V4L2 controls */
+	case V4L2_CID_BRIGHTNESS:
+	case V4L2_CID_HUE:
+	case V4L2_CID_SATURATION:
+	case V4L2_CID_CONTRAST:
+		if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl))
+			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_LOUDNESS:
+		if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+
+	default:
+		if (cx2341x_ctrl_query(&itv->params, qctrl))
+			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+		return 0;
+	}
+	strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
+	qctrl->name[sizeof(qctrl->name) - 1] = 0;
+	return 0;
+}
+
+static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu)
+{
+	struct v4l2_queryctrl qctrl;
+
+	qctrl.id = qmenu->id;
+	ivtv_queryctrl(itv, &qctrl);
+	return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
+{
+	s32 v = vctrl->value;
+
+	IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+
+	switch (vctrl->id) {
+		/* Standard V4L2 controls */
+	case V4L2_CID_BRIGHTNESS:
+	case V4L2_CID_HUE:
+	case V4L2_CID_SATURATION:
+	case V4L2_CID_CONTRAST:
+		return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl);
+
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_LOUDNESS:
+		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+
+	default:
+		IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
+{
+	IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
+
+	switch (vctrl->id) {
+		/* Standard V4L2 controls */
+	case V4L2_CID_BRIGHTNESS:
+	case V4L2_CID_HUE:
+	case V4L2_CID_SATURATION:
+	case V4L2_CID_CONTRAST:
+		return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl);
+
+	case V4L2_CID_AUDIO_VOLUME:
+	case V4L2_CID_AUDIO_MUTE:
+	case V4L2_CID_AUDIO_BALANCE:
+	case V4L2_CID_AUDIO_BASS:
+	case V4L2_CID_AUDIO_TREBLE:
+	case V4L2_CID_AUDIO_LOUDNESS:
+		return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+	default:
+		IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt)
+{
+	if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
+		return -EINVAL;
+	if (atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
+
+	/* First try to allocate sliced VBI buffers if needed. */
+	if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) {
+		int i;
+
+		for (i = 0; i < IVTV_VBI_FRAMES; i++) {
+			/* Yuck, hardcoded. Needs to be a define */
+			itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+			if (itv->vbi.sliced_mpeg_data[i] == NULL) {
+				while (--i >= 0) {
+					kfree(itv->vbi.sliced_mpeg_data[i]);
+					itv->vbi.sliced_mpeg_data[i] = NULL;
+				}
+				return -ENOMEM;
+			}
+		}
+	}
+
+	itv->vbi.insert_mpeg = fmt;
+
+	if (itv->vbi.insert_mpeg == 0) {
+		return 0;
+	}
+	/* Need sliced data for mpeg insertion */
+	if (get_service_set(itv->vbi.sliced_in) == 0) {
+		if (itv->is_60hz)
+			itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+		else
+			itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+		expand_service_set(itv->vbi.sliced_in, itv->is_50hz);
+	}
+	return 0;
+}
+
+int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	struct v4l2_control ctrl;
+
+	switch (cmd) {
+	case VIDIOC_QUERYMENU:
+		IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
+		return ivtv_querymenu(itv, arg);
+
+	case VIDIOC_QUERYCTRL:
+		return ivtv_queryctrl(itv, arg);
+
+	case VIDIOC_S_CTRL:
+		return ivtv_s_ctrl(itv, arg);
+
+	case VIDIOC_G_CTRL:
+		return ivtv_g_ctrl(itv, arg);
+
+	case VIDIOC_S_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *c = arg;
+
+		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+			int i;
+			int err = 0;
+
+			for (i = 0; i < c->count; i++) {
+				ctrl.id = c->controls[i].id;
+				ctrl.value = c->controls[i].value;
+				err = ivtv_s_ctrl(itv, &ctrl);
+				c->controls[i].value = ctrl.value;
+				if (err) {
+					c->error_idx = i;
+					break;
+				}
+			}
+			return err;
+		}
+		IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
+		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+			struct cx2341x_mpeg_params p = itv->params;
+			int err = cx2341x_ext_ctrls(&p, arg, cmd);
+
+			if (err)
+				return err;
+
+			if (p.video_encoding != itv->params.video_encoding) {
+				int is_mpeg1 = p.video_encoding ==
+						V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+				struct v4l2_format fmt;
+
+				/* fix videodecoder resolution */
+				fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+				fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
+				fmt.fmt.pix.height = itv->params.height;
+				itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
+			}
+			err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
+			if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) {
+				err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
+			}
+			itv->params = p;
+			itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+			ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03);
+			return err;
+		}
+		return -EINVAL;
+	}
+
+	case VIDIOC_G_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *c = arg;
+
+		if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+			int i;
+			int err = 0;
+
+			for (i = 0; i < c->count; i++) {
+				ctrl.id = c->controls[i].id;
+				ctrl.value = c->controls[i].value;
+				err = ivtv_g_ctrl(itv, &ctrl);
+				c->controls[i].value = ctrl.value;
+				if (err) {
+					c->error_idx = i;
+					break;
+				}
+			}
+			return err;
+		}
+		IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
+		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+			return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+		return -EINVAL;
+	}
+
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *c = arg;
+
+		IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
+		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+			return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+		return -EINVAL;
+	}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
new file mode 100644
index 0000000..5a11149
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -0,0 +1,21 @@
+/*
+    ioctl control functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
new file mode 100644
index 0000000..45b9328
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -0,0 +1,1374 @@
+/*
+    ivtv driver initialization and card probing
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* Main Driver file for the ivtv project:
+ * Driver for the Conexant CX23415/CX23416 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.ivtvdriver.org
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ *
+ * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta <alpha292@bremen.or.jp>
+ *                using information from T.Adachi,Takeru KOMORIYA and others :-)
+ *
+ * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX
+ *                version by T.Adachi. Special thanks  Mr.Suzuki
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-version.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-firmware.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-streams.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
+#include "ivtv-vbi.h"
+#include "ivtv-audio.h"
+#include "ivtv-gpio.h"
+#include "ivtv-yuv.h"
+
+#include <linux/vermagic.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+
+/* var to keep track of the number of array elements in use */
+int ivtv_cards_active = 0;
+
+/* If you have already X v4l cards, then set this to X. This way
+   the device numbers stay matched. Example: you have a WinTV card
+   without radio and a PVR-350 with. Normally this would give a
+   video1 device together with a radio0 device for the PVR. By
+   setting this to 1 you ensure that radio0 is now also radio1. */
+int ivtv_first_minor = 0;
+
+/* Master variable for all ivtv info */
+struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
+
+/* Protects ivtv_cards_active */
+spinlock_t ivtv_cards_lock = SPIN_LOCK_UNLOCKED;
+
+/* add your revision and whatnot here */
+static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
+
+const u32 yuv_offset[4] = {
+	IVTV_YUV_BUFFER_OFFSET,
+	IVTV_YUV_BUFFER_OFFSET_1,
+	IVTV_YUV_BUFFER_OFFSET_2,
+	IVTV_YUV_BUFFER_OFFSET_3
+};
+
+/* Parameter declarations */
+static int cardtype[IVTV_MAX_CARDS];
+static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static int cardtype_c = 1;
+static int tuner_c = 1;
+static int radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS;
+static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS;
+static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS;
+static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS;
+
+static int ivtv_yuv_mode = 0;
+static int ivtv_yuv_threshold=-1;
+static int ivtv_pci_latency = 1;
+
+int ivtv_debug = 0;
+
+static int newi2c = -1;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug,ivtv_debug, int, 0644);
+module_param(ivtv_pci_latency, int, 0644);
+module_param(ivtv_yuv_mode, int, 0644);
+module_param(ivtv_yuv_threshold, int, 0644);
+module_param(ivtv_first_minor, int, 0644);
+
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+module_param(dec_mpg_buffers, int, 0644);
+module_param(dec_yuv_buffers, int, 0644);
+module_param(dec_vbi_buffers, int, 0644);
+
+module_param(newi2c, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+			"\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+		 "Enable or disable the radio. Use only if autodetection\n"
+		 "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+		 "Only use this option if your card is not detected properly.\n"
+		 "\t\tSpecify card type:\n"
+		 "\t\t\t 1 = WinTV PVR 250\n"
+		 "\t\t\t 2 = WinTV PVR 350\n"
+		 "\t\t\t 3 = WinTV PVR-150 or PVR-500\n"
+		 "\t\t\t 4 = AVerMedia M179\n"
+		 "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n"
+		 "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n"
+		 "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n"
+		 "\t\t\t 8 = Adaptec AVC-2410\n"
+		 "\t\t\t 9 = Adaptec AVC-2010\n"
+		 "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n"
+		 "\t\t\t11 = AOpen VA2000MAX-STN6\n"
+		 "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n"
+		 "\t\t\t13 = I/O Data GV-MVP/RX\n"
+		 "\t\t\t14 = I/O Data GV-MVP/RX2E\n"
+		 "\t\t\t15 = GOTVIEW PCI DVD\n"
+		 "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n"
+		 "\t\t\t17 = Yuan MPC622\n"
+		 "\t\t\t18 = Digital Cowboy DCT-MTVP1\n"
+#ifdef HAVE_XC3028
+		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n"
+#endif
+		 "\t\t\t 0 = Autodetect (default)\n"
+		 "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: errors only\n"
+		 "\t\t\t(debug = 511 gives full debugging)");
+MODULE_PARM_DESC(ivtv_pci_latency,
+		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+		 "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(ivtv_yuv_mode,
+		 "Specify the yuv playback mode:\n"
+		 "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n"
+		 "\t\t\tDefault: 0 (interlaced)");
+MODULE_PARM_DESC(ivtv_yuv_threshold,
+		 "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n"
+		 "\t\t\tDefault: 480");;
+MODULE_PARM_DESC(enc_mpg_buffers,
+		 "Encoder MPG Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_buffers,
+		 "Encoder YUV Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_buffers,
+		 "Encoder VBI Buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_buffers,
+		 "Encoder PCM buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(dec_mpg_buffers,
+		 "Decoder MPG buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS));
+MODULE_PARM_DESC(dec_yuv_buffers,
+		 "Decoder YUV buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS));
+MODULE_PARM_DESC(dec_vbi_buffers,
+		 "Decoder VBI buffers (in MB)\n"
+		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS));
+MODULE_PARM_DESC(newi2c,
+		 "Use new I2C implementation\n"
+		 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
+		 "\t\t\tDefault is autodetect");
+
+MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_DESCRIPTION("CX23415/CX23416 driver");
+MODULE_SUPPORTED_DEVICE
+    ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n"
+		"\t\t\tYuan MPG series and similar)");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(IVTV_VERSION);
+
+void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask)
+{
+	itv->irqmask &= ~mask;
+	write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK);
+}
+
+void ivtv_set_irq_mask(struct ivtv *itv, u32 mask)
+{
+	itv->irqmask |= mask;
+	write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK);
+}
+
+int ivtv_set_output_mode(struct ivtv *itv, int mode)
+{
+    int old_mode;
+
+    spin_lock(&itv->lock);
+    old_mode = itv->output_mode;
+    if (old_mode == 0)
+	itv->output_mode = old_mode = mode;
+    spin_unlock(&itv->lock);
+    return old_mode;
+}
+
+struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv)
+{
+	switch (itv->output_mode) {
+	case OUT_MPG:
+		return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+	case OUT_YUV:
+		return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+	default:
+		return NULL;
+	}
+}
+
+int ivtv_waitq(wait_queue_head_t *waitq)
+{
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE);
+	schedule();
+	finish_wait(waitq, &wait);
+	return signal_pending(current) ? -EINTR : 0;
+}
+
+/* Generic utility functions */
+int ivtv_sleep_timeout(int timeout, int intr)
+{
+	int ret;
+
+	do {
+		set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+		if (intr && (ret = signal_pending(current)))
+			return ret;
+	} while (timeout);
+	return 0;
+}
+
+/* Release ioremapped memory */
+static void ivtv_iounmap(struct ivtv *itv)
+{
+	if (itv == NULL)
+		return;
+
+	/* Release registers memory */
+	if (itv->reg_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing reg_mem\n");
+		iounmap(itv->reg_mem);
+		itv->reg_mem = NULL;
+	}
+	/* Release io memory */
+	if (itv->has_cx23415 && itv->dec_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing dec_mem\n");
+		iounmap(itv->dec_mem);
+	}
+	itv->dec_mem = NULL;
+
+	/* Release io memory */
+	if (itv->enc_mem != NULL) {
+		IVTV_DEBUG_INFO("releasing enc_mem\n");
+		iounmap(itv->enc_mem);
+		itv->enc_mem = NULL;
+	}
+}
+
+/* Hauppauge card? get values from tveeprom */
+void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
+{
+	u8 eedata[256];
+
+	itv->i2c_client.addr = 0xA0 >> 1;
+	tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata));
+	tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata);
+}
+
+static void ivtv_process_eeprom(struct ivtv *itv)
+{
+	struct tveeprom tv;
+	int pci_slot = PCI_SLOT(itv->dev->devfn);
+
+	ivtv_read_eeprom(itv, &tv);
+
+	/* Many thanks to Steven Toth from Hauppauge for providing the
+	   model numbers */
+	switch (tv.model) {
+		/* In a few cases the PCI subsystem IDs do not correctly
+		   identify the card. A better method is to check the
+		   model number from the eeprom instead. */
+		case 32000 ... 32999:
+		case 48000 ... 48099:  /* 48??? range are PVR250s with a cx23415 */
+		case 48400 ... 48599:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_250);
+			break;
+		case 48100 ... 48399:
+		case 48600 ... 48999:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_350);
+			break;
+		case 23000 ... 23999:  /* PVR500 */
+		case 25000 ... 25999:  /* Low profile PVR150 */
+		case 26000 ... 26999:  /* Regular PVR150 */
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+			break;
+		case 0:
+			IVTV_ERR("Invalid EEPROM\n");
+			return;
+		default:
+			IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model);
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+			break;
+	}
+
+	switch (tv.model) {
+		/* Old style PVR350 (with an saa7114) uses this input for
+		   the tuner. */
+		case 48254:
+			itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1);
+			break;
+		default:
+			break;
+	}
+
+	itv->v4l2_cap = itv->card->v4l2_capabilities;
+	itv->card_name = itv->card->name;
+
+	/* If this is a PVR500 then it should be possible to detect whether it is the
+	   first or second unit by looking at the subsystem device ID: is bit 4 is
+	   set, then it is the second unit (according to info from Hauppauge).
+
+	   However, while this works for most cards, I have seen a few PVR500 cards
+	   where both units have the same subsystem ID.
+
+	   So instead I look at the reported 'PCI slot' (which is the slot on the PVR500
+	   PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise
+	   it is the second unit. It is possible that it is a different slot when ivtv is
+	   used in Xen, in that case I ignore this card here. The worst that can happen
+	   is that the card presents itself with a non-working radio device.
+
+	   This detection is needed since the eeprom reports incorrectly that a radio is
+	   present on the second unit. */
+	if (tv.model / 1000 == 23) {
+		itv->card_name = "WinTV PVR 500";
+		if (pci_slot == 8 || pci_slot == 9) {
+			int is_first = (pci_slot & 1) == 0;
+
+			itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" :
+						    "WinTV PVR 500 (unit #2)";
+			if (!is_first) {
+				IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n");
+				tv.has_radio = 0;
+			}
+		}
+	}
+	IVTV_INFO("Autodetected %s\n", itv->card_name);
+
+	switch (tv.tuner_hauppauge_model) {
+		case 85:
+		case 99:
+		case 112:
+			itv->pvr150_workaround = 1;
+			break;
+		default:
+			break;
+	}
+	if (tv.tuner_type == TUNER_ABSENT)
+		IVTV_ERR("tveeprom cannot autodetect tuner!");
+
+	if (itv->options.tuner == -1)
+		itv->options.tuner = tv.tuner_type;
+	if (itv->options.radio == -1)
+		itv->options.radio = (tv.has_radio != 0);
+	/* only enable newi2c if an IR blaster is present */
+	/* FIXME: for 2.6.20 the test against 2 should be removed */
+	if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
+		itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
+		if (itv->options.newi2c) {
+		    IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+		    exit_ivtv_i2c(itv);
+		    init_ivtv_i2c(itv);
+		}
+	}
+
+	if (itv->std != 0)
+		/* user specified tuner standard */
+		return;
+
+	/* autodetect tuner standard */
+	if (tv.tuner_formats & V4L2_STD_PAL) {
+		IVTV_DEBUG_INFO("PAL tuner detected\n");
+		itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+	} else if (tv.tuner_formats & V4L2_STD_NTSC) {
+		IVTV_DEBUG_INFO("NTSC tuner detected\n");
+		itv->std |= V4L2_STD_NTSC_M;
+	} else if (tv.tuner_formats & V4L2_STD_SECAM) {
+		IVTV_DEBUG_INFO("SECAM tuner detected\n");
+		itv->std |= V4L2_STD_SECAM_L;
+	} else {
+		IVTV_INFO("No tuner detected, default to NTSC-M\n");
+		itv->std |= V4L2_STD_NTSC_M;
+	}
+}
+
+static v4l2_std_id ivtv_parse_std(struct ivtv *itv)
+{
+	switch (pal[0]) {
+		case '6':
+			return V4L2_STD_PAL_60;
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+			return V4L2_STD_PAL_BG;
+		case 'h':
+		case 'H':
+			return V4L2_STD_PAL_H;
+		case 'n':
+		case 'N':
+			if (pal[1] == 'c' || pal[1] == 'C')
+				return V4L2_STD_PAL_Nc;
+			return V4L2_STD_PAL_N;
+		case 'i':
+		case 'I':
+			return V4L2_STD_PAL_I;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			return V4L2_STD_PAL_DK;
+		case 'M':
+		case 'm':
+			return V4L2_STD_PAL_M;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("pal= argument not recognised\n");
+			return 0;
+	}
+
+	switch (secam[0]) {
+		case 'b':
+		case 'B':
+		case 'g':
+		case 'G':
+		case 'h':
+		case 'H':
+			return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+		case 'd':
+		case 'D':
+		case 'k':
+		case 'K':
+			return V4L2_STD_SECAM_DK;
+		case 'l':
+		case 'L':
+			if (secam[1] == 'C' || secam[1] == 'c')
+				return V4L2_STD_SECAM_LC;
+			return V4L2_STD_SECAM_L;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("secam= argument not recognised\n");
+			return 0;
+	}
+
+	switch (ntsc[0]) {
+		case 'm':
+		case 'M':
+			return V4L2_STD_NTSC_M;
+		case 'j':
+		case 'J':
+			return V4L2_STD_NTSC_M_JP;
+		case 'k':
+		case 'K':
+			return V4L2_STD_NTSC_M_KR;
+		case '-':
+			break;
+		default:
+			IVTV_WARN("ntsc= argument not recognised\n");
+			return 0;
+	}
+
+	/* no match found */
+	return 0;
+}
+
+static void ivtv_process_options(struct ivtv *itv)
+{
+	const char *chipname;
+	int i, j;
+
+	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers;
+	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers;
+	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
+	itv->options.cardtype = cardtype[itv->num];
+	itv->options.tuner = tuner[itv->num];
+	itv->options.radio = radio[itv->num];
+	itv->options.newi2c = newi2c;
+
+	itv->std = ivtv_parse_std(itv);
+	itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
+	chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
+	if (itv->options.cardtype == -1) {
+		IVTV_INFO("Ignore card (detected %s based chip)\n", chipname);
+		return;
+	}
+	if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) {
+		IVTV_INFO("User specified %s card (detected %s based chip)\n",
+				itv->card->name, chipname);
+	} else if (itv->options.cardtype != 0) {
+		IVTV_ERR("Unknown user specified type, trying to autodetect card\n");
+	}
+	if (itv->card == NULL) {
+		if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE ||
+		    itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 ||
+		    itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) {
+			itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150);
+			IVTV_INFO("Autodetected Hauppauge card (%s based)\n",
+					chipname);
+		}
+	}
+	if (itv->card == NULL) {
+		for (i = 0; (itv->card = ivtv_get_card(i)); i++) {
+			if (itv->card->pci_list == NULL)
+				continue;
+			for (j = 0; itv->card->pci_list[j].device; j++) {
+				if (itv->dev->device !=
+				    itv->card->pci_list[j].device)
+					continue;
+				if (itv->dev->subsystem_vendor !=
+				    itv->card->pci_list[j].subsystem_vendor)
+					continue;
+				if (itv->dev->subsystem_device !=
+				    itv->card->pci_list[j].subsystem_device)
+					continue;
+				IVTV_INFO("Autodetected %s card (%s based)\n",
+						itv->card->name, chipname);
+				goto done;
+			}
+		}
+	}
+done:
+
+	if (itv->card == NULL) {
+		itv->card = ivtv_get_card(IVTV_CARD_PVR_150);
+		IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n",
+		     itv->dev->vendor, itv->dev->device);
+		IVTV_ERR("              subsystem vendor/device: %04x/%04x\n",
+		     itv->dev->subsystem_vendor, itv->dev->subsystem_device);
+		IVTV_ERR("              %s based\n", chipname);
+		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
+		IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+		IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+		IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n");
+	}
+	itv->v4l2_cap = itv->card->v4l2_capabilities;
+	itv->card_name = itv->card->name;
+}
+
+/* Precondition: the ivtv structure has been memset to 0. Only
+   the dev and num fields have been filled in.
+   No assumptions on the card type may be made here (see ivtv_init_struct2
+   for that).
+ */
+static int __devinit ivtv_init_struct1(struct ivtv *itv)
+{
+	itv->base_addr = pci_resource_start(itv->dev, 0);
+	itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
+	itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+
+	mutex_init(&itv->i2c_bus_lock);
+	mutex_init(&itv->udma.lock);
+
+	spin_lock_init(&itv->lock);
+	spin_lock_init(&itv->dma_reg_lock);
+
+	itv->irq_work_queues = create_workqueue(itv->name);
+	if (itv->irq_work_queues == NULL) {
+		IVTV_ERR("Could not create ivtv workqueue\n");
+		return -1;
+	}
+
+	INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler);
+
+	/* start counting open_id at 1 */
+	itv->open_id = 1;
+
+	/* Initial settings */
+	cx2341x_fill_defaults(&itv->params);
+	itv->params.port = CX2341X_PORT_MEMORY;
+	itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+	init_waitqueue_head(&itv->cap_w);
+	init_waitqueue_head(&itv->event_waitq);
+	init_waitqueue_head(&itv->vsync_waitq);
+	init_waitqueue_head(&itv->dma_waitq);
+	init_timer(&itv->dma_timer);
+	itv->dma_timer.function = ivtv_unfinished_dma;
+	itv->dma_timer.data = (unsigned long)itv;
+
+	itv->cur_dma_stream = -1;
+	itv->audio_stereo_mode = AUDIO_STEREO;
+	itv->audio_bilingual_mode = AUDIO_MONO_LEFT;
+
+	/* Ctrls */
+	itv->speed = 1000;
+
+	/* VBI */
+	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced;
+
+	/* OSD */
+	itv->osd_global_alpha_state = 1;
+	itv->osd_global_alpha = 255;
+
+	/* YUV */
+	atomic_set(&itv->yuv_info.next_dma_frame, -1);
+	itv->yuv_info.lace_mode = ivtv_yuv_mode;
+	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
+	return 0;
+}
+
+/* Second initialization part. Here the card type has been
+   autodetected. */
+static void __devinit ivtv_init_struct2(struct ivtv *itv)
+{
+	int i;
+
+	for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++)
+		if (itv->card->video_inputs[i].video_type == 0)
+			break;
+	itv->nof_inputs = i;
+	for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++)
+		if (itv->card->audio_inputs[i].audio_type == 0)
+			break;
+	itv->nof_audio_inputs = i;
+
+	/* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */
+	if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+		itv->digitizer = 0xF1;
+	else if (itv->card->hw_all & IVTV_HW_SAA7114)
+		itv->digitizer = 0xEF;
+	else /* cx25840 */
+		itv->digitizer = 0x140;
+
+	if (itv->card->hw_all & IVTV_HW_CX25840) {
+		itv->vbi.sliced_size = 288;  /* multiple of 16, real size = 284 */
+	} else {
+		itv->vbi.sliced_size = 64;   /* multiple of 16, real size = 52 */
+	}
+
+	/* Find tuner input */
+	for (i = 0; i < itv->nof_inputs; i++) {
+		if (itv->card->video_inputs[i].video_type ==
+				IVTV_CARD_INPUT_VID_TUNER)
+			break;
+	}
+	if (i == itv->nof_inputs)
+		i = 0;
+	itv->active_input = i;
+	itv->audio_input = itv->card->video_inputs[i].audio_index;
+	if (itv->card->hw_all & IVTV_HW_CX25840)
+		itv->video_dec_func = ivtv_cx25840;
+	else if (itv->card->hw_all & IVTV_HW_SAA717X)
+		itv->video_dec_func = ivtv_saa717x;
+	else
+		itv->video_dec_func = ivtv_saa7115;
+}
+
+static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
+			  const struct pci_device_id *pci_id)
+{
+	u16 cmd;
+	unsigned char pci_latency;
+
+	IVTV_DEBUG_INFO("Enabling pci device\n");
+
+	if (pci_enable_device(dev)) {
+		IVTV_ERR("Can't enable device %d!\n", itv->num);
+		return -EIO;
+	}
+	if (pci_set_dma_mask(dev, 0xffffffff)) {
+		IVTV_ERR("No suitable DMA available on card %d.\n", itv->num);
+		return -EIO;
+	}
+	if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
+		IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num);
+		return -EIO;
+	}
+
+	if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
+				IVTV_REG_SIZE, "ivtv registers")) {
+		IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num);
+		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+		return -EIO;
+	}
+
+	if (itv->has_cx23415 &&
+	    !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
+				IVTV_DECODER_SIZE, "ivtv decoder")) {
+		IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num);
+		release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+		release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+		return -EIO;
+	}
+
+	/* Check for bus mastering */
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (!(cmd & PCI_COMMAND_MASTER)) {
+		IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n");
+		pci_set_master(dev);
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		if (!(cmd & PCI_COMMAND_MASTER)) {
+			IVTV_ERR("Bus Mastering is not enabled\n");
+			return -ENXIO;
+		}
+	}
+	IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
+
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+
+	if (pci_latency < 64 && ivtv_pci_latency) {
+		IVTV_INFO("Unreasonably low latency timer, "
+			       "setting to 64 (was %d)\n", pci_latency);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+	}
+	/* This config space value relates to DMA latencies. The
+	   default value 0x8080 is too low however and will lead
+	   to DMA errors. 0xffff is the max value which solves
+	   these problems. */
+	pci_write_config_dword(dev, 0x40, 0xffff);
+
+	IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
+		   "irq: %d, latency: %d, memory: 0x%lx\n",
+		   itv->dev->device, itv->card_rev, dev->bus->number,
+		   PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+		   itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
+
+	return 0;
+}
+
+static void ivtv_request_module(struct ivtv *itv, const char *name)
+{
+	if (request_module(name) != 0) {
+		IVTV_ERR("Failed to load module %s\n", name);
+	} else {
+		IVTV_DEBUG_INFO("Loaded module %s\n", name);
+	}
+}
+
+static void ivtv_load_and_init_modules(struct ivtv *itv)
+{
+	struct v4l2_control ctrl;
+	u32 hw = itv->card->hw_all;
+	int i;
+
+	/* load modules */
+#ifndef CONFIG_VIDEO_TUNER
+	if (hw & IVTV_HW_TUNER) {
+		ivtv_request_module(itv, "tuner");
+#ifdef HAVE_XC3028
+		if (itv->options.tuner == TUNER_XCEIVE_XC3028)
+			ivtv_request_module(itv, "xc3028-tuner");
+#endif
+	}
+#endif
+#ifndef CONFIG_VIDEO_CX25840
+	if (hw & IVTV_HW_CX25840)
+		ivtv_request_module(itv, "cx25840");
+#endif
+#ifndef CONFIG_VIDEO_SAA711X
+	if (hw & IVTV_HW_SAA711X)
+		ivtv_request_module(itv, "saa7115");
+#endif
+#ifndef CONFIG_VIDEO_SAA7127
+	if (hw & IVTV_HW_SAA7127)
+		ivtv_request_module(itv, "saa7127");
+#endif
+	if (hw & IVTV_HW_SAA717X)
+		ivtv_request_module(itv, "saa717x");
+#ifndef CONFIG_VIDEO_UPD64031A
+	if (hw & IVTV_HW_UPD64031A)
+		ivtv_request_module(itv, "upd64031a");
+#endif
+#ifndef CONFIG_VIDEO_UPD64083
+	if (hw & IVTV_HW_UPD6408X)
+		ivtv_request_module(itv, "upd64083");
+#endif
+#ifndef CONFIG_VIDEO_MSP3400
+	if (hw & IVTV_HW_MSP34XX)
+		ivtv_request_module(itv, "msp3400");
+#endif
+	if (hw & IVTV_HW_TVAUDIO)
+		ivtv_request_module(itv, "tvaudio");
+#ifndef CONFIG_VIDEO_WM8775
+	if (hw & IVTV_HW_WM8775)
+		ivtv_request_module(itv, "wm8775");
+#endif
+#ifndef CONFIG_VIDEO_WM8739
+	if (hw & IVTV_HW_WM8739)
+		ivtv_request_module(itv, "wm8739");
+#endif
+#ifndef CONFIG_VIDEO_CS53L32A
+	if (hw & IVTV_HW_CS53L32A)
+		ivtv_request_module(itv, "cs53l32a");
+#endif
+
+	/* check which i2c devices are actually found */
+	for (i = 0; i < 32; i++) {
+		u32 device = 1 << i;
+
+		if (!(device & hw))
+			continue;
+		if (device == IVTV_HW_GPIO) {
+			/* GPIO is always available */
+			itv->hw_flags |= IVTV_HW_GPIO;
+			continue;
+		}
+		if (ivtv_i2c_hw_addr(itv, device) > 0)
+			itv->hw_flags |= device;
+	}
+
+	hw = itv->hw_flags;
+
+	if (itv->card->type == IVTV_CARD_CX23416GYC) {
+		/* Several variations of this card exist, detect which card
+		   type should be used. */
+		if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0)
+			itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS);
+		else if ((hw & IVTV_HW_UPD64031A) == 0)
+			itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR);
+	}
+
+	if (hw & IVTV_HW_CX25840) {
+		/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
+		ctrl.id = V4L2_CID_PRIVATE_BASE;
+		ctrl.value = itv->pvr150_workaround;
+		itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+
+		itv->vbi.raw_decoder_line_size = 1444;
+		itv->vbi.raw_decoder_sav_odd_field = 0x20;
+		itv->vbi.raw_decoder_sav_even_field = 0x60;
+		itv->vbi.sliced_decoder_line_size = 272;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xB0;
+		itv->vbi.sliced_decoder_sav_even_field = 0xF0;
+	}
+
+	if (hw & IVTV_HW_SAA711X) {
+		struct v4l2_chip_ident v = { V4L2_CHIP_MATCH_I2C_DRIVER, I2C_DRIVERID_SAA711X };
+
+		/* determine the exact saa711x model */
+		itv->hw_flags &= ~IVTV_HW_SAA711X;
+
+		ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v);
+		if (v.ident == V4L2_IDENT_SAA7114) {
+			itv->hw_flags |= IVTV_HW_SAA7114;
+			/* VBI is not yet supported by the saa7114 driver. */
+			itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE);
+		}
+		else {
+			itv->hw_flags |= IVTV_HW_SAA7115;
+		}
+		itv->vbi.raw_decoder_line_size = 1443;
+		itv->vbi.raw_decoder_sav_odd_field = 0x25;
+		itv->vbi.raw_decoder_sav_even_field = 0x62;
+		itv->vbi.sliced_decoder_line_size = 51;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xAB;
+		itv->vbi.sliced_decoder_sav_even_field = 0xEC;
+	}
+
+	if (hw & IVTV_HW_SAA717X) {
+		itv->vbi.raw_decoder_line_size = 1443;
+		itv->vbi.raw_decoder_sav_odd_field = 0x25;
+		itv->vbi.raw_decoder_sav_even_field = 0x62;
+		itv->vbi.sliced_decoder_line_size = 51;
+		itv->vbi.sliced_decoder_sav_odd_field = 0xAB;
+		itv->vbi.sliced_decoder_sav_even_field = 0xEC;
+	}
+}
+
+static int __devinit ivtv_probe(struct pci_dev *dev,
+				const struct pci_device_id *pci_id)
+{
+	int retval = 0;
+	int video_input;
+	int yuv_buf_size;
+	int vbi_buf_size;
+	int fw_retry_count = 3;
+	struct ivtv *itv;
+	struct v4l2_frequency vf;
+
+	spin_lock(&ivtv_cards_lock);
+
+	/* Make sure we've got a place for this card */
+	if (ivtv_cards_active == IVTV_MAX_CARDS) {
+		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d).\n",
+			      ivtv_cards_active);
+		spin_unlock(&ivtv_cards_lock);
+		return -ENOMEM;
+	}
+
+	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
+	if (itv == 0) {
+		spin_unlock(&ivtv_cards_lock);
+		return -ENOMEM;
+	}
+	ivtv_cards[ivtv_cards_active] = itv;
+	itv->dev = dev;
+	itv->num = ivtv_cards_active++;
+	snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
+	if (itv->num) {
+		printk(KERN_INFO "ivtv:  ======================  NEXT CARD  ======================\n");
+	}
+
+	spin_unlock(&ivtv_cards_lock);
+
+	ivtv_process_options(itv);
+	if (itv->options.cardtype == -1) {
+		retval = -ENODEV;
+		goto err;
+	}
+	if (ivtv_init_struct1(itv)) {
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
+
+	/* PCI Device Setup */
+	if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
+		if (retval == -EIO)
+			goto free_workqueue;
+		else if (retval == -ENXIO)
+			goto free_mem;
+	}
+	/* save itv in the pci struct for later use */
+	pci_set_drvdata(dev, itv);
+
+	/* map io memory */
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+		   itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
+	itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET,
+				       IVTV_ENCODER_SIZE);
+	if (!itv->enc_mem) {
+		IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+		IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+		retval = -ENOMEM;
+		goto free_mem;
+	}
+
+	if (itv->has_cx23415) {
+		IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+				itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+		itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET,
+				IVTV_DECODER_SIZE);
+		if (!itv->dec_mem) {
+			IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+			IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+			retval = -ENOMEM;
+			goto free_mem;
+		}
+	}
+	else {
+		itv->dec_mem = itv->enc_mem;
+	}
+
+	/* map registers memory */
+	IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+		   itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	itv->reg_mem =
+	    ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (!itv->reg_mem) {
+		IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+		IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+		retval = -ENOMEM;
+		goto free_io;
+	}
+
+	while (--fw_retry_count > 0) {
+		/* load firmware */
+		if (ivtv_firmware_init(itv) == 0)
+			break;
+		if (fw_retry_count > 1)
+			IVTV_WARN("Retry loading firmware\n");
+	}
+	if (fw_retry_count == 0) {
+		IVTV_ERR("Error initializing firmware\n");
+		goto free_i2c;
+	}
+
+	/* Try and get firmware versions */
+	IVTV_DEBUG_INFO("Getting firmware version..\n");
+	ivtv_firmware_versions(itv);
+
+	/* Check yuv output filter table */
+	if (itv->has_cx23415) ivtv_yuv_filter_check(itv);
+
+	ivtv_gpio_init(itv);
+
+	/* active i2c  */
+	IVTV_DEBUG_INFO("activating i2c...\n");
+	if (init_ivtv_i2c(itv)) {
+		IVTV_ERR("Could not initialize i2c\n");
+		goto free_irq;
+	}
+
+	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
+
+	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
+#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
+		ivtv_request_module(itv, "tveeprom");
+#endif
+		/* Based on the model number the cardtype may be changed.
+		   The PCI IDs are not always reliable. */
+		ivtv_process_eeprom(itv);
+	}
+
+	if (itv->std == 0) {
+		itv->std = V4L2_STD_NTSC_M;
+	}
+
+	if (itv->options.tuner == -1) {
+		int i;
+
+		for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) {
+			if ((itv->std & itv->card->tuners[i].std) == 0)
+				continue;
+			itv->options.tuner = itv->card->tuners[i].tuner;
+			break;
+		}
+	}
+	/* if no tuner was found, then pick the first tuner in the card list */
+	if (itv->options.tuner == -1 && itv->card->tuners[0].std) {
+		itv->std = itv->card->tuners[0].std;
+		itv->options.tuner = itv->card->tuners[0].tuner;
+	}
+	if (itv->options.radio == -1)
+		itv->options.radio = (itv->card->radio_input.audio_type != 0);
+
+	/* The card is now fully identified, continue with card-specific
+	   initialization. */
+	ivtv_init_struct2(itv);
+
+	ivtv_load_and_init_modules(itv);
+
+	if (itv->std & V4L2_STD_525_60) {
+		itv->is_60hz = 1;
+		itv->is_out_60hz = 1;
+	} else {
+		itv->is_50hz = 1;
+		itv->is_out_50hz = 1;
+	}
+	itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
+
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
+
+	/* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */
+	yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8;
+
+	/* Setup VBI Raw Size. Should be big enough to hold PAL.
+	   It is possible to switch between PAL and NTSC, so we need to
+	   take the largest size here. */
+	/* 1456 is multiple of 16, real size = 1444 */
+	itv->vbi.raw_size = 1456;
+	/* We use a buffer size of 1/2 of the total size needed for a
+	   frame. This is actually very useful, since we now receive
+	   a field at a time and that makes 'compressing' the raw data
+	   down to size by stripping off the SAV codes a lot easier.
+	   Note: having two different buffer sizes prevents standard
+	   switching on the fly. We need to find a better solution... */
+	vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36;
+
+	if (itv->options.radio > 0)
+		itv->v4l2_cap |= V4L2_CAP_RADIO;
+
+	if (itv->options.tuner > -1) {
+		struct tuner_setup setup;
+
+		setup.addr = ADDR_UNSET;
+		setup.type = itv->options.tuner;
+		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
+#ifdef HAVE_XC3028
+		setup.initmode = V4L2_TUNER_ANALOG_TV;
+		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
+			setup.gpio_write = ivtv_reset_tuner_gpio;
+			setup.gpio_priv = itv;
+		}
+#endif
+		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+	}
+
+	vf.tuner = 0;
+	vf.type = V4L2_TUNER_ANALOG_TV;
+	vf.frequency = 6400; /* the tuner 'baseline' frequency */
+	if (itv->std & V4L2_STD_NTSC_M) {
+		/* Why on earth? */
+		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
+	}
+
+	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+	   are not. */
+	itv->tuner_std = itv->std;
+
+	video_input = itv->active_input;
+	itv->active_input++;	/* Force update of input */
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+
+	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+	   in one place. */
+	itv->std++;		/* Force full standard initialization */
+	itv->std_out = itv->std;
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+
+	retval = ivtv_streams_setup(itv);
+	if (retval) {
+		IVTV_ERR("Error %d setting up streams\n", retval);
+		goto free_i2c;
+	}
+
+	if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_init_mpeg_decoder(itv);
+	}
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+
+	IVTV_DEBUG_IRQ("Masking interrupts\n");
+	/* clear interrupt mask, effectively disabling interrupts */
+	ivtv_set_irq_mask(itv, 0xffffffff);
+
+	/* Register IRQ */
+	retval = request_irq(itv->dev->irq, ivtv_irq_handler,
+			     IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
+	if (retval) {
+		IVTV_ERR("Failed to register irq %d\n", retval);
+		goto free_streams;
+	}
+
+	/* On a cx23416 this seems to be able to enable DMA to the chip? */
+	if (!itv->has_cx23415)
+		write_reg_sync(0x03, IVTV_REG_DMACONTROL);
+
+	/* Default interrupts enabled. For the PVR350 this includes the
+	   decoder VSYNC interrupt, which is always on. It is not only used
+	   during decoding but also by the OSD.
+	   Some old PVR250 cards had a cx23415, so testing for that is too
+	   general. Instead test if the card has video output capability. */
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
+	else
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+
+	if (itv->has_cx23415)
+		ivtv_set_osd_alpha(itv);
+
+	IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+
+	return 0;
+
+      free_irq:
+	free_irq(itv->dev->irq, (void *)itv);
+      free_streams:
+	ivtv_streams_cleanup(itv);
+      free_i2c:
+	exit_ivtv_i2c(itv);
+      free_io:
+	ivtv_iounmap(itv);
+      free_mem:
+	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (itv->has_cx23415)
+		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+      free_workqueue:
+	destroy_workqueue(itv->irq_work_queues);
+      err:
+	if (retval == 0)
+		retval = -ENODEV;
+	IVTV_ERR("Error %d on initialization\n", retval);
+
+	kfree(ivtv_cards[ivtv_cards_active]);
+	ivtv_cards[ivtv_cards_active] = NULL;
+	return retval;
+}
+
+static void ivtv_remove(struct pci_dev *pci_dev)
+{
+	struct ivtv *itv = pci_get_drvdata(pci_dev);
+
+	IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+
+	/* Stop all captures */
+	IVTV_DEBUG_INFO(" Stopping all streams.\n");
+	if (atomic_read(&itv->capturing) > 0)
+		ivtv_stop_all_captures(itv);
+
+	/* Stop all decoding */
+	IVTV_DEBUG_INFO(" Stopping decoding.\n");
+	if (atomic_read(&itv->decoding) > 0) {
+		int type;
+
+		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+			type = IVTV_DEC_STREAM_TYPE_YUV;
+		else
+			type = IVTV_DEC_STREAM_TYPE_MPG;
+		ivtv_stop_v4l2_decode_stream(&itv->streams[type],
+			VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+	}
+
+	/* Interrupts */
+	IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+	ivtv_set_irq_mask(itv, 0xffffffff);
+	del_timer_sync(&itv->dma_timer);
+
+	/* Stop all Work Queues */
+	IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+	flush_workqueue(itv->irq_work_queues);
+	destroy_workqueue(itv->irq_work_queues);
+
+	IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+	ivtv_halt_firmware(itv);
+
+	IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+	ivtv_streams_cleanup(itv);
+	IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+	ivtv_udma_free(itv);
+
+	exit_ivtv_i2c(itv);
+
+	IVTV_DEBUG_INFO(" Releasing irq.\n");
+	free_irq(itv->dev->irq, (void *)itv);
+
+	if (itv->dev) {
+		ivtv_iounmap(itv);
+	}
+
+	IVTV_DEBUG_INFO(" Releasing mem.\n");
+	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
+	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+	if (itv->has_cx23415)
+		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
+
+	pci_disable_device(itv->dev);
+
+	IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num);
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver ivtv_pci_driver = {
+      .name =     "ivtv",
+      .id_table = ivtv_pci_tbl,
+      .probe =    ivtv_probe,
+      .remove =   ivtv_remove,
+};
+
+static int module_start(void)
+{
+	printk(KERN_INFO "ivtv:  ==================== START INIT IVTV ====================\n");
+	printk(KERN_INFO "ivtv:  version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+
+	memset(ivtv_cards, 0, sizeof(ivtv_cards));
+
+	/* Validate parameters */
+	if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
+		printk(KERN_ERR "ivtv:  ivtv_first_minor must be between 0 and %d. Exiting...\n",
+		     IVTV_MAX_CARDS - 1);
+		return -1;
+	}
+
+	if (ivtv_debug < 0 || ivtv_debug > 511) {
+		ivtv_debug = 0;
+		printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 511!\n");
+	}
+
+	if (pci_register_driver(&ivtv_pci_driver)) {
+		printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "ivtv:  ====================  END INIT IVTV  ====================\n");
+	return 0;
+}
+
+static void module_cleanup(void)
+{
+	int i, j;
+
+	pci_unregister_driver(&ivtv_pci_driver);
+
+	for (i = 0; i < ivtv_cards_active; i++) {
+		if (ivtv_cards[i] == NULL)
+			continue;
+		for (j = 0; j < IVTV_VBI_FRAMES; j++) {
+			kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]);
+		}
+		kfree(ivtv_cards[i]);
+	}
+}
+
+/* Note: These symbols are exported because they are used by the ivtv-fb
+   framebuffer module and an infrared module for the IR-blaster. */
+EXPORT_SYMBOL(ivtv_set_irq_mask);
+EXPORT_SYMBOL(ivtv_cards_active);
+EXPORT_SYMBOL(ivtv_cards);
+EXPORT_SYMBOL(ivtv_api);
+EXPORT_SYMBOL(ivtv_vapi);
+EXPORT_SYMBOL(ivtv_vapi_result);
+EXPORT_SYMBOL(ivtv_clear_irq_mask);
+EXPORT_SYMBOL(ivtv_debug);
+EXPORT_SYMBOL(ivtv_reset_ir_gpio);
+EXPORT_SYMBOL(ivtv_udma_setup);
+EXPORT_SYMBOL(ivtv_udma_unmap);
+EXPORT_SYMBOL(ivtv_udma_alloc);
+EXPORT_SYMBOL(ivtv_udma_prepare);
+
+module_init(module_start);
+module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
new file mode 100644
index 0000000..9a412d6
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -0,0 +1,868 @@
+/*
+    ivtv driver internal defines and structures
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 IVTV_DRIVER_H
+#define IVTV_DRIVER_H
+
+/* Internal header for ivtv project:
+ * Driver for the cx23415/6 chip.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ * License: GPL
+ * http://www.ivtvdriver.org
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/byteorder/swab.h>
+#include <linux/pagemap.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+
+/* #define HAVE_XC3028 1 */
+
+#include <media/ivtv.h>
+
+#ifdef CONFIG_LIRC_I2C
+#  error "This driver is not compatible with the LIRC I2C kernel configuration option."
+#endif /* CONFIG_LIRC_I2C */
+
+#ifndef CONFIG_PCI
+#  error "This driver requires kernel PCI support."
+#endif /* CONFIG_PCI */
+
+#define IVTV_ENCODER_OFFSET	0x00000000
+#define IVTV_ENCODER_SIZE	0x00800000	/* Last half isn't needed 0x01000000 */
+
+#define IVTV_DECODER_OFFSET	0x01000000
+#define IVTV_DECODER_SIZE	0x00800000	/* Last half isn't needed 0x01000000 */
+
+#define IVTV_REG_OFFSET 	0x02000000
+#define IVTV_REG_SIZE		0x00010000
+
+/* Buffers on hardware offsets */
+#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
+#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
+
+/* Offset to filter table in firmware */
+#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
+#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
+
+extern const u32 yuv_offset[4];
+
+/* Maximum ivtv driver instances.
+   Based on 6 PVR500s each with two PVR15s...
+   TODO: make this dynamic. I believe it is only a global in order to support
+    ivtv-fb. There must be a better way to do that. */
+#define IVTV_MAX_CARDS 12
+
+/* Supported cards */
+#define IVTV_CARD_PVR_250 	      0	/* WinTV PVR 250 */
+#define IVTV_CARD_PVR_350 	      1	/* encoder, decoder, tv-out */
+#define IVTV_CARD_PVR_150 	      2	/* WinTV PVR 150 and PVR 500 (really just two
+					   PVR150s on one PCI board) */
+#define IVTV_CARD_M179    	      3	/* AVerMedia M179 (encoder only) */
+#define IVTV_CARD_MPG600  	      4	/* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
+#define IVTV_CARD_MPG160  	      5	/* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
+					   cx23415 based, but does not have tv-out */
+#define IVTV_CARD_PG600 	      6	/* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
+#define IVTV_CARD_AVC2410 	      7	/* Adaptec AVC-2410 */
+#define IVTV_CARD_AVC2010 	      8	/* Adaptec AVD-2010 (No Tuner) */
+#define IVTV_CARD_TG5000TV   	      9 /* NAGASE TRANSGEAR 5000TV, encoder only */
+#define IVTV_CARD_VA2000MAX_SNT6     10 /* VA2000MAX-STN6 */
+#define IVTV_CARD_CX23416GYC 	     11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_GV_MVPRX   	     12 /* I/O Data GV-MVP/RX, RX2, RX2W */
+#define IVTV_CARD_GV_MVPRX2E 	     13 /* I/O Data GV-MVP/RX2E */
+#define IVTV_CARD_GOTVIEW_PCI_DVD    14	/* GotView PCI DVD */
+#define IVTV_CARD_GOTVIEW_PCI_DVD2   15	/* GotView PCI DVD2 */
+#define IVTV_CARD_YUAN_MPC622        16	/* Yuan MPC622 miniPCI */
+#define IVTV_CARD_DCTMTVP1 	     17 /* DIGITAL COWBOY DCT-MTVP1 */
+#ifdef HAVE_XC3028
+#define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */
+#define IVTV_CARD_LAST 		     18
+#else
+#define IVTV_CARD_LAST 		     17
+#endif
+
+/* Variants of existing cards but with the same PCI IDs. The driver
+   detects these based on other device information.
+   These cards must always come last.
+   New cards must be inserted above, and the indices of the cards below
+   must be adjusted accordingly. */
+
+/* PVR-350 V1 (uses saa7114) */
+#define IVTV_CARD_PVR_350_V1 	     (IVTV_CARD_LAST+1)
+/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_CX23416GYC_NOGR    (IVTV_CARD_LAST+2)
+#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+
+#define IVTV_ENC_STREAM_TYPE_MPG  0
+#define IVTV_ENC_STREAM_TYPE_YUV  1
+#define IVTV_ENC_STREAM_TYPE_VBI  2
+#define IVTV_ENC_STREAM_TYPE_PCM  3
+#define IVTV_ENC_STREAM_TYPE_RAD  4
+#define IVTV_DEC_STREAM_TYPE_MPG  5
+#define IVTV_DEC_STREAM_TYPE_VBI  6
+#define IVTV_DEC_STREAM_TYPE_VOUT 7
+#define IVTV_DEC_STREAM_TYPE_YUV  8
+#define IVTV_MAX_STREAMS	  9
+
+#define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */
+
+#define IVTV_ENC_MEM_START 0x00000000
+#define IVTV_DEC_MEM_START 0x01000000
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_ICOMP  0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+
+/* subsystem vendor ID */
+#define IVTV_PCI_ID_HAUPPAUGE 		0x0070
+#define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
+#define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
+#define IVTV_PCI_ID_ADAPTEC 		0x9005
+#define IVTV_PCI_ID_AVERMEDIA 		0x1461
+#define IVTV_PCI_ID_YUAN1		0x12ab
+#define IVTV_PCI_ID_YUAN2 		0xff01
+#define IVTV_PCI_ID_YUAN3 		0xffab
+#define IVTV_PCI_ID_YUAN4 		0xfbab
+#define IVTV_PCI_ID_DIAMONDMM 		0xff92
+#define IVTV_PCI_ID_IODATA 		0x10fc
+#define IVTV_PCI_ID_MELCO 		0x1154
+#define IVTV_PCI_ID_GOTVIEW1		0xffac
+#define IVTV_PCI_ID_GOTVIEW2 		0xffad
+
+/* Decoder Buffer hardware size on Chip */
+#define IVTV_DEC_MAX_BUF        0x00100000	/* max bytes in decoder buffer */
+#define IVTV_DEC_MIN_BUF        0x00010000	/* min bytes in dec buffer */
+
+/* ======================================================================== */
+/* ========================== START USER SETTABLE DMA VARIABLES =========== */
+/* ======================================================================== */
+
+#define IVTV_DMA_SG_OSD_ENT	(2883584/PAGE_SIZE)	/* sg entities */
+
+/* DMA Buffers, Default size in MB allocated */
+#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
+#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
+#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
+#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
+#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1
+
+/* ======================================================================== */
+/* ========================== END USER SETTABLE DMA VARIABLES ============= */
+/* ======================================================================== */
+
+/* Decoder Status Register */
+#define IVTV_DMA_ERR_LIST 	0x00000010
+#define IVTV_DMA_ERR_WRITE 	0x00000008
+#define IVTV_DMA_ERR_READ 	0x00000004
+#define IVTV_DMA_SUCCESS_WRITE 	0x00000002
+#define IVTV_DMA_SUCCESS_READ 	0x00000001
+#define IVTV_DMA_READ_ERR 	(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
+#define IVTV_DMA_WRITE_ERR 	(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
+#define IVTV_DMA_ERR 		(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)
+
+/* DMA Registers */
+#define IVTV_REG_DMAXFER 	(0x0000)
+#define IVTV_REG_DMASTATUS 	(0x0004)
+#define IVTV_REG_DECDMAADDR 	(0x0008)
+#define IVTV_REG_ENCDMAADDR 	(0x000c)
+#define IVTV_REG_DMACONTROL 	(0x0010)
+#define IVTV_REG_IRQSTATUS 	(0x0040)
+#define IVTV_REG_IRQMASK 	(0x0048)
+
+/* Setup Registers */
+#define IVTV_REG_ENC_SDRAM_REFRESH 	(0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE 	(0x07FC)
+#define IVTV_REG_DEC_SDRAM_REFRESH 	(0x08F8)
+#define IVTV_REG_DEC_SDRAM_PRECHARGE 	(0x08FC)
+#define IVTV_REG_VDM 			(0x2800)
+#define IVTV_REG_AO 			(0x2D00)
+#define IVTV_REG_BYTEFLUSH 		(0x2D24)
+#define IVTV_REG_SPU 			(0x9050)
+#define IVTV_REG_HW_BLOCKS 		(0x9054)
+#define IVTV_REG_VPU 			(0x9058)
+#define IVTV_REG_APU 			(0xA064)
+
+#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
+#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
+#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
+#define IVTV_IRQ_DMA_ERR		(0x1 << 18)
+#define IVTV_IRQ_DMA_WRITE		(0x1 << 17)
+#define IVTV_IRQ_DMA_READ		(0x1 << 16)
+#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|IVTV_IRQ_DMA_READ)
+
+#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
+#define IVTV_IRQ_MASK_DECODE  (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+
+/* debugging */
+
+#define IVTV_DBGFLG_WARN  (1 << 0)
+#define IVTV_DBGFLG_INFO  (1 << 1)
+#define IVTV_DBGFLG_API   (1 << 2)
+#define IVTV_DBGFLG_DMA   (1 << 3)
+#define IVTV_DBGFLG_IOCTL (1 << 4)
+#define IVTV_DBGFLG_I2C   (1 << 5)
+#define IVTV_DBGFLG_IRQ   (1 << 6)
+#define IVTV_DBGFLG_DEC   (1 << 7)
+#define IVTV_DBGFLG_YUV   (1 << 8)
+
+/* NOTE: extra space before comma in 'itv->num , ## args' is required for
+   gcc-2.95, otherwise it won't compile. */
+#define IVTV_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & ivtv_debug) \
+			printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+	} while (0)
+#define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args)
+#define IVTV_DEBUG_API(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_DEBUG_DMA(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_I2C(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_IRQ(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
+#define IVTV_FB_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & ivtv_debug) \
+			printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \
+	} while (0)
+#define IVTV_FB_DEBUG_WARN(fmt, args...)  IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_FB_DEBUG_INFO(fmt, args...)  IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+#define IVTV_FB_DEBUG_API(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_FB_DEBUG_DMA(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_FB_DEBUG_I2C(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_FB_DEBUG_IRQ(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_FB_DEBUG_DEC(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_FB_DEBUG_YUV(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTV_ERR(fmt, args...)      printk(KERN_ERR  "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_WARN(fmt, args...)     printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_INFO(fmt, args...)     printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_FB_ERR(fmt, args...)   printk(KERN_ERR  "ivtv%d-fb: " fmt, itv->num , ## args)
+#define IVTV_FB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtv%d-fb: " fmt, itv->num , ## args)
+#define IVTV_FB_INFO(fmt, args...)  printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args)
+
+/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+#define MPEG_FRAME_TYPE_IFRAME 1
+#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
+#define MPEG_FRAME_TYPE_ALL 7
+
+/* output modes (cx23415 only) */
+#define OUT_NONE        0
+#define OUT_MPG         1
+#define OUT_YUV         2
+#define OUT_UDMA_YUV    3
+#define OUT_PASSTHROUGH 4
+
+#define IVTV_MAX_PGM_INDEX (400)
+
+extern int ivtv_debug;
+
+
+struct ivtv_options {
+	int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */
+	int cardtype;		/* force card type on load */
+	int tuner;		/* set tuner on load */
+	int radio;		/* enable/disable radio */
+	int newi2c;		/* New I2C algorithm */
+};
+
+#define IVTV_MBOX_DMA_START 6
+#define IVTV_MBOX_DMA_END 8
+#define IVTV_MBOX_DMA 9
+#define IVTV_MBOX_FIELD_DISPLAYED 8
+
+/* ivtv-specific mailbox template */
+struct ivtv_mailbox {
+	u32 flags;
+	u32 cmd;
+	u32 retval;
+	u32 timeout;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+};
+
+struct ivtv_api_cache {
+	unsigned long last_jiffies;		/* when last command was issued */
+	u32 data[CX2341X_MBOX_MAX_DATA];	/* last sent api data */
+};
+
+struct ivtv_mailbox_data {
+	volatile struct ivtv_mailbox __iomem *mbox;
+	/* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes.
+	   If the bit is set, then the corresponding mailbox is in use by the driver. */
+	unsigned long busy;
+	u8 max_mbox;
+};
+
+/* per-buffer bit flags */
+#define IVTV_F_B_NEED_BUF_SWAP  0	/* this buffer should be byte swapped */
+
+/* per-stream, s_flags */
+#define IVTV_F_S_DMA_PENDING	0	/* this stream has pending DMA */
+#define IVTV_F_S_DMA_HAS_VBI	1       /* the current DMA request also requests VBI data */
+#define IVTV_F_S_NEEDS_DATA	2 	/* this decoding stream needs more data */
+
+#define IVTV_F_S_CLAIMED 	3	/* this stream is claimed */
+#define IVTV_F_S_STREAMING      4	/* the fw is decoding/encoding this stream */
+#define IVTV_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
+#define IVTV_F_S_PASSTHROUGH	6	/* this stream is in passthrough mode */
+#define IVTV_F_S_STREAMOFF	7	/* signal end of stream EOS */
+#define IVTV_F_S_APPL_IO        8	/* this stream is used read/written by an application */
+
+/* per-ivtv, i_flags */
+#define IVTV_F_I_DMA		   0 	/* DMA in progress */
+#define IVTV_F_I_UDMA		   1 	/* UDMA in progress */
+#define IVTV_F_I_UDMA_PENDING	   2 	/* UDMA pending */
+#define IVTV_F_I_SPEED_CHANGE	   3 	/* A speed change is in progress */
+#define IVTV_F_I_EOS		   4 	/* End of encoder stream reached */
+#define IVTV_F_I_RADIO_USER	   5 	/* The radio tuner is selected */
+#define IVTV_F_I_DIG_RST	   6 	/* Reset digitizer */
+#define IVTV_F_I_DEC_YUV	   7 	/* YUV instead of MPG is being decoded */
+#define IVTV_F_I_ENC_VBI	   8 	/* VBI DMA */
+#define IVTV_F_I_UPDATE_CC	   9  	/* CC should be updated */
+#define IVTV_F_I_UPDATE_WSS	   10 	/* WSS should be updated */
+#define IVTV_F_I_UPDATE_VPS	   11 	/* VPS should be updated */
+#define IVTV_F_I_DECODING_YUV	   12 	/* this stream is YUV frame decoding */
+#define IVTV_F_I_ENC_PAUSED	   13 	/* the encoder is paused */
+#define IVTV_F_I_VALID_DEC_TIMINGS 14 	/* last_dec_timing is valid */
+#define IVTV_F_I_WORK_HANDLER_VBI  15	/* there is work to be done for VBI */
+#define IVTV_F_I_WORK_HANDLER_YUV  16	/* there is work to be done for YUV */
+
+/* Event notifications */
+#define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
+#define IVTV_F_I_EV_VSYNC	   29 	/* VSYNC event */
+#define IVTV_F_I_EV_VSYNC_FIELD    30 	/* VSYNC event field (0 = first, 1 = second field) */
+#define IVTV_F_I_EV_VSYNC_ENABLED  31 	/* VSYNC event enabled */
+
+/* Scatter-Gather array element, used in DMA transfers */
+struct ivtv_SG_element {
+	u32 src;
+	u32 dst;
+	u32 size;
+};
+
+struct ivtv_user_dma {
+	struct mutex lock;
+	int page_count;
+	struct page *map[IVTV_DMA_SG_OSD_ENT];
+
+	/* Base Dev SG Array for cx23415/6 */
+	struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT];
+	dma_addr_t SG_handle;
+	int SG_length;
+
+	/* SG List of Buffers */
+	struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT];
+};
+
+struct ivtv_dma_page_info {
+	unsigned long uaddr;
+	unsigned long first;
+	unsigned long last;
+	unsigned int offset;
+	unsigned int tail;
+	int page_count;
+};
+
+struct ivtv_buffer {
+	struct list_head list;
+	dma_addr_t dma_handle;
+	unsigned long b_flags;
+	char *buf;
+
+	u32 bytesused;
+	u32 readpos;
+};
+
+struct ivtv_queue {
+	struct list_head list;
+	u32 buffers;
+	u32 length;
+	u32 bytesused;
+};
+
+struct ivtv;	/* forward reference */
+
+struct ivtv_stream {
+	/* These first four fields are always set, even if the stream
+	   is not actually created. */
+	struct video_device *v4l2dev;	/* NULL when stream not created */
+	struct ivtv *itv; 		/* for ease of use */
+	const char *name;		/* name of the stream */
+	int type;			/* stream type */
+
+	u32 id;
+	spinlock_t qlock; 	/* locks access to the queues */
+	unsigned long s_flags;	/* status flags, see above */
+	int dma;		/* can be PCI_DMA_TODEVICE,
+				   PCI_DMA_FROMDEVICE or
+				   PCI_DMA_NONE */
+	u32 dma_offset;
+	u32 dma_backup;
+	u64 dma_pts;
+
+	int subtype;
+	wait_queue_head_t waitq;
+	u32 dma_last_offset;
+
+	/* Buffer Stats */
+	u32 buffers;
+	u32 buf_size;
+	u32 buffers_stolen;
+
+	/* Buffer Queues */
+	struct ivtv_queue q_free;	/* free buffers */
+	struct ivtv_queue q_full;	/* full buffers */
+	struct ivtv_queue q_io;		/* waiting for I/O */
+	struct ivtv_queue q_dma;	/* waiting for DMA */
+	struct ivtv_queue q_predma;	/* waiting for DMA */
+
+	/* Base Dev SG Array for cx23415/6 */
+	struct ivtv_SG_element *SGarray;
+	dma_addr_t SG_handle;
+	int SG_length;
+
+	/* SG List of Buffers */
+	struct scatterlist *SGlist;
+};
+
+struct ivtv_open_id {
+	u32 open_id;
+	int type;
+	enum v4l2_priority prio;
+	struct ivtv *itv;
+};
+
+#define IVTV_YUV_UPDATE_HORIZONTAL  0x01
+#define IVTV_YUV_UPDATE_VERTICAL    0x02
+
+struct yuv_frame_info
+{
+	u32 update;
+	int src_x;
+	int src_y;
+	unsigned int src_w;
+	unsigned int src_h;
+	int dst_x;
+	int dst_y;
+	unsigned int dst_w;
+	unsigned int dst_h;
+	int pan_x;
+	int pan_y;
+	u32 vis_w;
+	u32 vis_h;
+	u32 interlaced_y;
+	u32 interlaced_uv;
+	int tru_x;
+	u32 tru_w;
+	u32 tru_h;
+	u32 offset_y;
+};
+
+#define IVTV_YUV_MODE_INTERLACED	0x00
+#define IVTV_YUV_MODE_PROGRESSIVE	0x01
+#define IVTV_YUV_MODE_AUTO		0x02
+#define IVTV_YUV_MODE_MASK		0x03
+
+#define IVTV_YUV_SYNC_EVEN		0x00
+#define IVTV_YUV_SYNC_ODD		0x04
+#define IVTV_YUV_SYNC_MASK		0x04
+
+struct yuv_playback_info
+{
+	u32 reg_2834;
+	u32 reg_2838;
+	u32 reg_283c;
+	u32 reg_2840;
+	u32 reg_2844;
+	u32 reg_2848;
+	u32 reg_2854;
+	u32 reg_285c;
+	u32 reg_2864;
+
+	u32 reg_2870;
+	u32 reg_2874;
+	u32 reg_2890;
+	u32 reg_2898;
+	u32 reg_289c;
+
+	u32 reg_2918;
+	u32 reg_291c;
+	u32 reg_2920;
+	u32 reg_2924;
+	u32 reg_2928;
+	u32 reg_292c;
+	u32 reg_2930;
+
+	u32 reg_2934;
+
+	u32 reg_2938;
+	u32 reg_293c;
+	u32 reg_2940;
+	u32 reg_2944;
+	u32 reg_2948;
+	u32 reg_294c;
+	u32 reg_2950;
+	u32 reg_2954;
+	u32 reg_2958;
+	u32 reg_295c;
+	u32 reg_2960;
+	u32 reg_2964;
+	u32 reg_2968;
+	u32 reg_296c;
+
+	u32 reg_2970;
+
+	int v_filter_1;
+	int v_filter_2;
+	int h_filter;
+
+	u32 osd_x_offset;
+	u32 osd_y_offset;
+
+	u32 osd_x_pan;
+	u32 osd_y_pan;
+
+	u32 osd_vis_w;
+	u32 osd_vis_h;
+
+	int decode_height;
+
+	int frame_interlaced;
+	int frame_interlaced_last;
+
+	int lace_mode;
+	int lace_threshold;
+	int lace_sync_field;
+
+	atomic_t next_dma_frame;
+	atomic_t next_fill_frame;
+
+	u32 yuv_forced_update;
+	int update_frame;
+	struct yuv_frame_info new_frame_info[4];
+	struct yuv_frame_info old_frame_info;
+	struct yuv_frame_info old_frame_info_args;
+
+	void *blanking_ptr;
+	dma_addr_t blanking_dmaptr;
+};
+
+#define IVTV_VBI_FRAMES 32
+
+/* VBI data */
+struct vbi_info {
+	u32 dec_start;
+	u32 enc_start, enc_size;
+	int fpi;
+	u32 frame;
+	u32 dma_offset;
+	u8 cc_data_odd[256];
+	u8 cc_data_even[256];
+	int cc_pos;
+	u8 cc_no_update;
+	u8 vps[5];
+	u8 vps_found;
+	int wss;
+	u8 wss_found;
+	u8 wss_no_update;
+	u32 raw_decoder_line_size;
+	u8 raw_decoder_sav_odd_field;
+	u8 raw_decoder_sav_even_field;
+	u32 sliced_decoder_line_size;
+	u8 sliced_decoder_sav_odd_field;
+	u8 sliced_decoder_sav_even_field;
+	struct v4l2_format in;
+	/* convenience pointer to sliced struct in vbi_in union */
+	struct v4l2_sliced_vbi_format *sliced_in;
+	u32 service_set_in;
+	u32 service_set_out;
+	int insert_mpeg;
+
+	/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+	   One for /dev/vbi0 and one for /dev/vbi8 */
+	struct v4l2_sliced_vbi_data sliced_data[36];
+	struct v4l2_sliced_vbi_data sliced_dec_data[36];
+
+	/* Buffer for VBI data inserted into MPEG stream.
+	   The first byte is a dummy byte that's never used.
+	   The next 16 bytes contain the MPEG header for the VBI data,
+	   the remainder is the actual VBI data.
+	   The max size accepted by the MPEG VBI reinsertion turns out
+	   to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+	   where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+	   a single line header byte and 2 * 18 is the number of VBI lines per frame.
+
+	   However, it seems that the data must be 1K aligned, so we have to
+	   pad the data until the 1 or 2 K boundary.
+
+	   This pointer array will allocate 2049 bytes to store each VBI frame. */
+	u8 *sliced_mpeg_data[IVTV_VBI_FRAMES];
+	u32 sliced_mpeg_size[IVTV_VBI_FRAMES];
+	struct ivtv_buffer sliced_mpeg_buf;
+	u32 inserted_frame;
+
+	u32 start[2], count;
+	u32 raw_size;
+	u32 sliced_size;
+};
+
+/* forward declaration of struct defined in ivtv-cards.h */
+struct ivtv_card;
+
+/* Struct to hold info about ivtv cards */
+struct ivtv {
+	int num;		/* board number, -1 during init! */
+	char name[8];		/* board name for printk and interrupts (e.g. 'ivtv0') */
+	struct pci_dev *dev;	/* PCI device */
+	const struct ivtv_card *card;	/* card information */
+	const char *card_name;  /* full name of the card */
+	u8 has_cx23415;		/* 1 if it is a cx23415 based card, 0 for cx23416 */
+	u8 is_50hz;
+	u8 is_60hz;
+	u8 is_out_50hz;
+	u8 is_out_60hz;
+	u8 pvr150_workaround;   /* 1 if the cx25840 needs to workaround a PVR150 bug */
+	u8 nof_inputs;		/* number of video inputs */
+	u8 nof_audio_inputs;	/* number of audio inputs */
+	u32 v4l2_cap;		/* V4L2 capabilities of card */
+	u32 hw_flags; 		/* Hardware description of the board */
+
+	/* controlling Video decoder function */
+	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+
+	struct ivtv_options options; 	/* User options */
+	int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */
+	struct ivtv_stream streams[IVTV_MAX_STREAMS]; 	/* Stream data */
+	int speed;
+	u8 speed_mute_audio;
+	unsigned long i_flags;  /* global ivtv flags */
+	atomic_t capturing;	/* count number of active capture streams */
+	atomic_t decoding;	/* count number of active decoding streams */
+	u32 irq_rr_idx; /* Round-robin stream index */
+	int cur_dma_stream;	/* index of stream doing DMA */
+	u32 dma_data_req_offset;
+	u32 dma_data_req_size;
+	int output_mode;        /* NONE, MPG, YUV, UDMA YUV, passthrough */
+	spinlock_t lock;        /* lock access to this struct */
+	int search_pack_header;
+
+	spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+
+	/* User based DMA for OSD */
+	struct ivtv_user_dma udma;
+
+	int open_id;		/* incremented each time an open occurs, used as unique ID.
+				   starts at 1, so 0 can be used as uninitialized value
+				   in the stream->id. */
+
+	u32 base_addr;
+	u32 irqmask;
+
+	struct v4l2_prio_state prio;
+	struct workqueue_struct *irq_work_queues;
+	struct work_struct irq_work_queue;
+	struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */
+
+	struct vbi_info vbi;
+
+	struct ivtv_mailbox_data enc_mbox;
+	struct ivtv_mailbox_data dec_mbox;
+	struct ivtv_api_cache api_cache[256]; 	/* Cached API Commands */
+
+	u8 card_rev;
+	volatile void __iomem *enc_mem, *dec_mem, *reg_mem;
+
+	u32 pgm_info_offset;
+	u32 pgm_info_num;
+	u32 pgm_info_write_idx;
+	u32 pgm_info_read_idx;
+	struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX];
+
+	u64 mpg_data_received;
+	u64 vbi_data_inserted;
+
+	wait_queue_head_t cap_w;
+	/* when the next decoder event arrives this queue is woken up */
+	wait_queue_head_t event_waitq;
+	/* when the next decoder vsync arrives this queue is woken up */
+	wait_queue_head_t vsync_waitq;
+	/* when the current DMA is finished this queue is woken up */
+	wait_queue_head_t dma_waitq;
+
+	/* OSD support */
+	unsigned long osd_video_pbase;
+	int osd_global_alpha_state; /* 0=off : 1=on */
+	int osd_local_alpha_state;  /* 0=off : 1=on */
+	int osd_color_key_state;    /* 0=off : 1=on */
+	u8  osd_global_alpha;       /* Current global alpha */
+	u32 osd_color_key;          /* Current color key */
+	u32 osd_pixelformat; 	    /* Current pixel format */
+	struct v4l2_rect osd_rect;  /* Current OSD position and size */
+	struct v4l2_rect main_rect; /* Current Main window position and size */
+
+	u32 last_dec_timing[3];     /* Store last retrieved pts/scr/frame values */
+
+	/* i2c */
+	struct i2c_adapter i2c_adap;
+	struct i2c_algo_bit_data i2c_algo;
+	struct i2c_client i2c_client;
+	struct mutex i2c_bus_lock;
+	int i2c_state;
+	struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+	/* v4l2 and User settings */
+
+	/* codec settings */
+	struct cx2341x_mpeg_params params;
+	u32 audio_input;
+	u32 active_input;
+	u32 active_output;
+	v4l2_std_id std;
+	v4l2_std_id std_out;
+	v4l2_std_id tuner_std;	/* The norm of the tuner (fixed) */
+	u8 audio_stereo_mode;
+	u8 audio_bilingual_mode;
+
+	/* dualwatch */
+	unsigned long dualwatch_jiffies;
+	u16 dualwatch_stereo_mode;
+
+	/* Digitizer type */
+	int digitizer;		/* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+
+	u32 lastVsyncFrame;
+
+	struct yuv_playback_info yuv_info;
+	struct osd_info *osd_info;
+};
+
+/* Globals */
+extern struct ivtv *ivtv_cards[];
+extern int ivtv_cards_active;
+extern int ivtv_first_minor;
+extern spinlock_t ivtv_cards_lock;
+
+/*==============Prototypes==================*/
+
+/* Hardware/IRQ */
+void ivtv_set_irq_mask(struct ivtv *itv, u32 mask);
+void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask);
+
+/* try to set output mode, return current mode. */
+int ivtv_set_output_mode(struct ivtv *itv, int mode);
+
+/* return current output stream based on current mode */
+struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
+
+/* Return non-zero if a signal is pending */
+int ivtv_sleep_timeout(int timeout, int intr);
+
+/* Wait on queue, returns -EINTR if interrupted */
+int ivtv_waitq(wait_queue_head_t *waitq);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
+
+/* This is a PCI post thing, where if the pci register is not read, then
+   the write doesn't always take effect right away. By reading back the
+   register any pending PCI writes will be performed (in order), and so
+   you can be sure that the writes are guaranteed to be done.
+
+   Rarely needed, only in some timing sensitive cases.
+   Apparently if this is not done some motherboards seem
+   to kill the firmware and get into the broken state until computer is
+   rebooted. */
+#define write_sync(val, reg) \
+	do { writel(val, reg); readl(reg); } while (0)
+
+#define read_reg(reg) readl(itv->reg_mem + (reg))
+#define write_reg(val, reg) writel(val, itv->reg_mem + (reg))
+#define write_reg_sync(val, reg) \
+	do { write_reg(val, reg); read_reg(reg); } while (0)
+
+#define read_enc(addr) readl(itv->enc_mem + (u32)(addr))
+#define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr))
+#define write_enc_sync(val, addr) \
+	do { write_enc(val, addr); read_enc(addr); } while (0)
+
+#define read_dec(addr) readl(itv->dec_mem + (u32)(addr))
+#define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr))
+#define write_dec_sync(val, addr) \
+	do { write_dec(val, addr); read_dec(addr); } while (0)
+
+#endif /* IVTV_DRIVER_H */
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
new file mode 100644
index 0000000..1637097
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -0,0 +1,921 @@
+/*
+    file operation functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-vbi.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-audio.h"
+#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
+#include "ivtv-controls.h"
+#include "ivtv-ioctl.h"
+
+/* This function tries to claim the stream for a specific file descriptor.
+   If no one else is using this stream then the stream is claimed and
+   associated VBI streams are also automatically claimed.
+   Possible error returns: -EBUSY if someone else has claimed
+   the stream or 0 on success. */
+int ivtv_claim_stream(struct ivtv_open_id *id, int type)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[type];
+	struct ivtv_stream *s_vbi;
+	int vbi_type;
+
+	if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		/* someone already claimed this stream */
+		if (s->id == id->open_id) {
+			/* yes, this file descriptor did. So that's OK. */
+			return 0;
+		}
+		if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI ||
+					 type == IVTV_ENC_STREAM_TYPE_VBI)) {
+			/* VBI is handled already internally, now also assign
+			   the file descriptor to this stream for external
+			   reading of the stream. */
+			s->id = id->open_id;
+			IVTV_DEBUG_INFO("Start Read VBI\n");
+			return 0;
+		}
+		/* someone else is using this stream already */
+		IVTV_DEBUG_INFO("Stream %d is busy\n", type);
+		return -EBUSY;
+	}
+	s->id = id->open_id;
+	if (type == IVTV_DEC_STREAM_TYPE_VBI) {
+		/* Enable reinsertion interrupt */
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	}
+
+	/* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI,
+	   IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI
+	   (provided VBI insertion is on and sliced VBI is selected), for all
+	   other streams we're done */
+	if (type == IVTV_DEC_STREAM_TYPE_MPG) {
+		vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
+	} else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
+		   itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) {
+		vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
+	} else {
+		return 0;
+	}
+	s_vbi = &itv->streams[vbi_type];
+
+	if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) {
+		/* Enable reinsertion interrupt */
+		if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI)
+			ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	}
+	/* mark that it is used internally */
+	set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags);
+	return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+   account associated VBI streams. */
+void ivtv_release_stream(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi;
+
+	s->id = -1;
+	if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
+		test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
+		/* this stream is still in use internally */
+		return;
+	}
+	if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+		return;
+	}
+
+	ivtv_flush_queues(s);
+
+	/* disable reinsertion interrupt */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+
+	/* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI,
+	   IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI,
+	   for all other streams we're done */
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+		s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
+	else if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+		s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	else
+		return;
+
+	/* clear internal use flag */
+	if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+		/* was already cleared */
+		return;
+	}
+	if (s_vbi->id != -1) {
+		/* VBI stream still claimed by a file descriptor */
+		return;
+	}
+	/* disable reinsertion interrupt */
+	if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
+	clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags);
+	ivtv_flush_queues(s_vbi);
+}
+
+static void ivtv_dualwatch(struct ivtv *itv)
+{
+	struct v4l2_tuner vt;
+	u16 new_bitmap;
+	u16 new_stereo_mode;
+	const u16 stereo_mask = 0x0300;
+	const u16 dual = 0x0200;
+
+	new_stereo_mode = itv->params.audio_properties & stereo_mask;
+	memset(&vt, 0, sizeof(vt));
+	ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt);
+	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+		new_stereo_mode = dual;
+
+	if (new_stereo_mode == itv->dualwatch_stereo_mode)
+		return;
+
+	new_bitmap = new_stereo_mode | (itv->params.audio_properties & ~stereo_mask);
+
+	IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
+			   itv->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+
+	if (ivtv_vapi(itv, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new_bitmap) == 0) {
+		itv->dualwatch_stereo_mode = new_stereo_mode;
+		return;
+	}
+	IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+static void ivtv_update_pgm_info(struct ivtv *itv)
+{
+	u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24;
+	int cnt;
+	int i = 0;
+
+	if (wr_idx >= itv->pgm_info_num) {
+		IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num);
+		return;
+	}
+	cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num;
+	while (i < cnt) {
+		int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+		struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
+		u32 addr = itv->pgm_info_offset + 4 + idx * 24;
+		const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 };
+
+		e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
+		if (e->offset > itv->mpg_data_received) {
+			break;
+		}
+		e->offset += itv->vbi_data_inserted;
+		e->length = read_enc(addr);
+		e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
+		e->flags = mapping[read_enc(addr + 12) & 3];
+		i++;
+	}
+	itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
+}
+
+static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	struct ivtv_buffer *buf;
+	DEFINE_WAIT(wait);
+
+	*err = 0;
+	while (1) {
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG) {
+			/* Process pending program info updates and pending VBI data */
+			ivtv_update_pgm_info(itv);
+
+			if (jiffies - itv->dualwatch_jiffies > HZ) {
+				itv->dualwatch_jiffies = jiffies;
+				ivtv_dualwatch(itv);
+			}
+
+			if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+			    !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+				while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) {
+					/* byteswap and process VBI data */
+					ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type);
+					ivtv_enqueue(s_vbi, buf, &s_vbi->q_free);
+				}
+			}
+			buf = &itv->vbi.sliced_mpeg_buf;
+			if (buf->readpos != buf->bytesused) {
+				return buf;
+			}
+		}
+
+		/* do we have leftover data? */
+		buf = ivtv_dequeue(s, &s->q_io);
+		if (buf)
+			return buf;
+
+		/* do we have new data? */
+		buf = ivtv_dequeue(s, &s->q_full);
+		if (buf) {
+			if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags))
+				return buf;
+			if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
+				/* byteswap MPG data */
+				ivtv_buf_swap(buf);
+			else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) {
+				/* byteswap and process VBI data */
+				ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type);
+			}
+			return buf;
+		}
+		/* return if file was opened with O_NONBLOCK */
+		if (non_block) {
+			*err = -EAGAIN;
+			return NULL;
+		}
+
+		/* return if end of stream */
+		if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+			clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+			IVTV_DEBUG_INFO("EOS %s\n", s->name);
+			return NULL;
+		}
+
+		/* wait for more data to arrive */
+		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+		/* New buffers might have become available before we were added to the waitqueue */
+		if (!s->q_full.buffers)
+			schedule();
+		finish_wait(&s->waitq, &wait);
+		if (signal_pending(current)) {
+			/* return if a signal was received */
+			IVTV_DEBUG_INFO("User stopped %s\n", s->name);
+			*err = -EINTR;
+			return NULL;
+		}
+	}
+}
+
+static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv)
+{
+	int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+
+	itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx];
+	itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx];
+	itv->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf,
+		char __user *ubuf, size_t ucount)
+{
+	struct ivtv *itv = s->itv;
+	size_t len = buf->bytesused - buf->readpos;
+
+	if (len > ucount) len = ucount;
+	if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) {
+		const char *start = buf->buf + buf->readpos;
+		const char *p = start + 1;
+		const u8 *q;
+		u8 ch = itv->search_pack_header ? 0xba : 0xe0;
+		int stuffing, i;
+
+		while (start + len > p && (q = memchr(p, 0, start + len - p))) {
+			p = q + 1;
+			if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+			    q[1] != 0 || q[2] != 1 || q[3] != ch) {
+				continue;
+			}
+			if (!itv->search_pack_header) {
+				if ((q[6] & 0xc0) != 0x80)
+					continue;
+				if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) ||
+				    ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) {
+					ch = 0xba;
+					itv->search_pack_header = 1;
+					p = q + 9;
+				}
+				continue;
+			}
+			stuffing = q[13] & 7;
+			/* all stuffing bytes must be 0xff */
+			for (i = 0; i < stuffing; i++)
+				if (q[14 + i] != 0xff)
+					break;
+			if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 &&
+					q[14 + stuffing] == 0 && q[15 + stuffing] == 0 &&
+					q[16 + stuffing] == 1) {
+				itv->search_pack_header = 0;
+				len = (char *)q - start;
+				ivtv_setup_sliced_vbi_buf(itv);
+				break;
+			}
+		}
+	}
+	if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+		IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name);
+		return -EFAULT;
+	}
+	/*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount,
+			buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len,
+			buf == &itv->vbi.sliced_mpeg_buf); */
+	buf->readpos += len;
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf)
+		itv->mpg_data_received += len;
+	return len;
+}
+
+static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block)
+{
+	struct ivtv *itv = s->itv;
+	size_t tot_written = 0;
+	int single_frame = 0;
+
+	if (atomic_read(&itv->capturing) == 0 && s->id == -1) {
+		/* shouldn't happen */
+		IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name);
+		return -EIO;
+	}
+
+	/* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
+	   arrive one-by-one, so make sure we never output more than one VBI frame at a time */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
+			(s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set))
+		single_frame = 1;
+
+	for (;;) {
+		struct ivtv_buffer *buf;
+		int rc;
+
+		buf = ivtv_get_buffer(s, non_block, &rc);
+		if (buf == NULL && rc == -EAGAIN && tot_written)
+			break;
+		if (buf == NULL)
+			return rc;
+		rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
+		if (buf != &itv->vbi.sliced_mpeg_buf) {
+			ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
+		}
+		else if (buf->readpos == buf->bytesused) {
+			int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES;
+			itv->vbi.sliced_mpeg_size[idx] = 0;
+			itv->vbi.inserted_frame++;
+			itv->vbi_data_inserted += buf->bytesused;
+		}
+		if (rc < 0)
+			return rc;
+		tot_written += rc;
+
+		if (tot_written == tot_count || single_frame)
+			break;
+	}
+	return tot_written;
+}
+
+static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count,
+			loff_t *pos, int non_block)
+{
+	ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
+	struct ivtv *itv = s->itv;
+
+	IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+	if (rc > 0)
+		pos += rc;
+	return rc;
+}
+
+int ivtv_start_capture(struct ivtv_open_id *id)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	struct ivtv_stream *s_vbi;
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_RAD ||
+	    s->type == IVTV_DEC_STREAM_TYPE_MPG ||
+	    s->type == IVTV_DEC_STREAM_TYPE_YUV ||
+	    s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+		/* you cannot read from these stream types. */
+		return -EPERM;
+	}
+
+	/* Try to claim this stream. */
+	if (ivtv_claim_stream(id, s->type))
+		return -EBUSY;
+
+	/* This stream does not need to start capturing */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return 0;
+	}
+
+	/* If capture is already in progress, then we also have to
+	   do nothing extra. */
+	if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return 0;
+	}
+
+	/* Start VBI capture if required */
+	s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+	    !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+		/* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed
+		   automatically when the MPG stream is claimed.
+		   We only need to start the VBI capturing. */
+		if (ivtv_start_v4l2_encode_stream(s_vbi)) {
+			IVTV_DEBUG_WARN("VBI capture start failed\n");
+
+			/* Failure, clean up and return an error */
+			clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+			clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+			/* also releases the associated VBI stream */
+			ivtv_release_stream(s);
+			return -EIO;
+		}
+		IVTV_DEBUG_INFO("VBI insertion started\n");
+	}
+
+	/* Tell the card to start capturing */
+	if (!ivtv_start_v4l2_encode_stream(s)) {
+		/* We're done */
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		/* Resume a possibly paused encoder */
+		if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+		return 0;
+	}
+
+	/* failure, clean up */
+	IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+	/* Note: the IVTV_ENC_STREAM_TYPE_VBI is released
+	   automatically when the MPG stream is released.
+	   We only need to stop the VBI capturing. */
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG &&
+	    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) {
+		ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+		clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags);
+	}
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+	ivtv_release_stream(s);
+	return -EIO;
+}
+
+ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int rc;
+
+	IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+
+	rc = ivtv_start_capture(id);
+	if (rc)
+		return rc;
+	return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+}
+
+int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	if (atomic_read(&itv->decoding) == 0) {
+		if (ivtv_claim_stream(id, s->type)) {
+			/* someone else is using this stream already */
+			IVTV_DEBUG_WARN("start decode, stream already claimed\n");
+			return -EBUSY;
+		}
+		ivtv_start_v4l2_decode_stream(s, 0);
+	}
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+		return ivtv_set_speed(itv, speed);
+	return 0;
+}
+
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	struct ivtv_buffer *buf;
+	struct ivtv_queue q;
+	int bytes_written = 0;
+	int mode;
+	int rc;
+	DEFINE_WAIT(wait);
+
+	IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+
+	if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
+	    s->type != IVTV_DEC_STREAM_TYPE_YUV &&
+	    s->type != IVTV_DEC_STREAM_TYPE_VOUT)
+		/* not decoder streams */
+		return -EPERM;
+
+	/* Try to claim this stream */
+	if (ivtv_claim_stream(id, s->type))
+		return -EBUSY;
+
+	/* This stream does not need to start any decoding */
+	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return ivtv_write_vbi(itv, user_buf, count);
+	}
+
+	mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
+
+	if (ivtv_set_output_mode(itv, mode) != mode) {
+	    ivtv_release_stream(s);
+	    return -EBUSY;
+	}
+	ivtv_queue_init(&q);
+	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+
+retry:
+	for (;;) {
+		/* Gather buffers */
+		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
+			ivtv_enqueue(s, buf, &q);
+		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) {
+			ivtv_enqueue(s, buf, &q);
+		}
+		if (q.buffers)
+			break;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+		/* New buffers might have become free before we were added to the waitqueue */
+		if (!s->q_free.buffers)
+			schedule();
+		finish_wait(&s->waitq, &wait);
+		if (signal_pending(current)) {
+			IVTV_DEBUG_INFO("User stopped %s\n", s->name);
+			return -EINTR;
+		}
+	}
+
+	/* copy user data into buffers */
+	while ((buf = ivtv_dequeue(s, &q))) {
+		/* Make sure we really got all the user data */
+		rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+
+		if (rc < 0) {
+			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
+			return rc;
+		}
+		user_buf += rc;
+		count -= rc;
+		bytes_written += rc;
+
+		if (buf->bytesused != s->buf_size) {
+			/* incomplete, leave in q_io for next time */
+			ivtv_enqueue(s, buf, &s->q_io);
+			break;
+		}
+		/* Byteswap MPEG buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+			ivtv_buf_swap(buf);
+		ivtv_enqueue(s, buf, &s->q_full);
+	}
+
+	/* Start decoder (returns 0 if already started) */
+	rc = ivtv_start_decoding(id, itv->speed);
+	if (rc) {
+		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
+
+		/* failure, clean up */
+		clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		return rc;
+	}
+	if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
+		if (s->q_full.length >= itv->dma_data_req_size) {
+			int got_sig;
+
+			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+			while (!(got_sig = signal_pending(current)) &&
+					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
+				schedule();
+			}
+			finish_wait(&itv->dma_waitq, &wait);
+			if (got_sig) {
+				IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
+				return -EINTR;
+			}
+
+			clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+			ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+			ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1);
+		}
+	}
+	/* more user data is available, wait until buffers become free
+	   to transfer the rest. */
+	if (count && !(filp->f_flags & O_NONBLOCK))
+		goto retry;
+	IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+	return bytes_written;
+}
+
+unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int res = 0;
+
+	/* add stream's waitq to the poll list */
+	poll_wait(filp, &s->waitq, wait);
+
+	set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+	if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) ||
+	    test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+		res = POLLPRI;
+
+	/* Allow write if buffers are available for writing */
+	if (s->q_free.buffers)
+		res |= POLLOUT | POLLWRNORM;
+	return res;
+}
+
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+	int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	/* Start a capture if there is none */
+	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		int rc = ivtv_start_capture(id);
+
+		if (rc) {
+			IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
+					s->name, rc);
+			return POLLERR;
+		}
+	}
+
+	/* add stream's waitq to the poll list */
+	poll_wait(filp, &s->waitq, wait);
+
+	if (eof || s->q_full.length)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+
+	/* 'Unclaim' this stream */
+
+	/* Stop capturing */
+	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+
+		IVTV_DEBUG_INFO("close stopping capture\n");
+		/* Special case: a running VBI capture for VBI insertion
+		   in the mpeg stream. Need to stop that too. */
+		if (id->type == IVTV_ENC_STREAM_TYPE_MPG &&
+		    test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) &&
+		    !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) {
+			IVTV_DEBUG_INFO("close stopping embedded VBI capture\n");
+			ivtv_stop_v4l2_encode_stream(s_vbi, 0);
+		}
+		if ((id->type == IVTV_DEC_STREAM_TYPE_VBI ||
+		     id->type == IVTV_ENC_STREAM_TYPE_VBI) &&
+		    test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
+			/* Also used internally, don't stop capturing */
+			s->id = -1;
+		}
+		else {
+			ivtv_stop_v4l2_encode_stream(s, gop_end);
+		}
+	}
+	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	ivtv_release_stream(s);
+}
+
+static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
+{
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+
+	/* Stop decoding */
+	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+		IVTV_DEBUG_INFO("close stopping decode\n");
+
+		ivtv_stop_v4l2_decode_stream(s, flags, pts);
+	}
+	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+	if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
+		/* Restore registers we've changed & clean up any mess we've made */
+		ivtv_yuv_close(itv);
+	}
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV)
+	    itv->output_mode = OUT_NONE;
+	else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG)
+	    itv->output_mode = OUT_NONE;
+
+	itv->speed = 0;
+	ivtv_release_stream(s);
+}
+
+int ivtv_v4l2_close(struct inode *inode, struct file *filp)
+{
+	struct ivtv_open_id *id = filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+
+	v4l2_prio_close(&itv->prio, &id->prio);
+
+	/* Easy case first: this stream was never claimed by us */
+	if (s->id != id->open_id) {
+		kfree(id);
+		return 0;
+	}
+
+	/* 'Unclaim' this stream */
+
+	/* Stop radio */
+	if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
+		/* Closing radio device, return to TV mode */
+		ivtv_mute(itv);
+		/* Mark that the radio is no longer in use */
+		clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+		/* Switch tuner to TV */
+		ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+		/* Select correct audio input (i.e. TV tuner or Line in) */
+		ivtv_audio_set_io(itv);
+		/* Done! Unmute and continue. */
+		ivtv_unmute(itv);
+		ivtv_release_stream(s);
+	} else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+		ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+	} else {
+		ivtv_stop_capture(id, 0);
+	}
+	kfree(id);
+	return 0;
+}
+
+int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+{
+	int x, y = 0;
+	struct ivtv_open_id *item;
+	struct ivtv *itv = NULL;
+	struct ivtv_stream *s = NULL;
+	int minor = MINOR(inode->i_rdev);
+
+	/* Find which card this open was on */
+	spin_lock(&ivtv_cards_lock);
+	for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+		/* find out which stream this open was on */
+		for (y = 0; y < IVTV_MAX_STREAMS; y++) {
+			s = &ivtv_cards[x]->streams[y];
+			if (s->v4l2dev && s->v4l2dev->minor == minor) {
+				itv = ivtv_cards[x];
+				break;
+			}
+		}
+	}
+	spin_unlock(&ivtv_cards_lock);
+
+	if (itv == NULL) {
+		/* Couldn't find a device registered
+		   on that minor, shouldn't happen! */
+		printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+		return -ENXIO;
+	}
+
+	if (y == IVTV_DEC_STREAM_TYPE_MPG &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
+		return -EBUSY;
+
+	if (y == IVTV_DEC_STREAM_TYPE_YUV &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
+		return -EBUSY;
+
+	if (y == IVTV_DEC_STREAM_TYPE_YUV) {
+		if (read_reg(0x82c) == 0) {
+			IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
+			/* return -ENODEV; */
+		}
+		ivtv_udma_alloc(itv);
+	}
+
+	/* Allocate memory */
+	item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+	if (NULL == item) {
+		IVTV_DEBUG_WARN("nomem on v4l2 open\n");
+		return -ENOMEM;
+	}
+	item->itv = itv;
+	item->type = y;
+	v4l2_prio_open(&itv->prio, &item->prio);
+
+	item->open_id = itv->open_id++;
+	filp->private_data = item;
+
+	if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
+		/* Try to claim this stream */
+		if (ivtv_claim_stream(item, item->type)) {
+			/* No, it's already in use */
+			kfree(item);
+			return -EBUSY;
+		}
+
+		/* We have the radio */
+		ivtv_mute(itv);
+		/* Switch tuner to radio */
+		ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
+		/* Mark that the radio is being used. */
+		set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+		/* Select the correct audio input (i.e. radio tuner) */
+		ivtv_audio_set_io(itv);
+		/* Done! Unmute and continue. */
+		ivtv_unmute(itv);
+	}
+
+	/* YUV or MPG Decoding Mode? */
+	if (y == IVTV_DEC_STREAM_TYPE_MPG)
+		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+	else if (y == IVTV_DEC_STREAM_TYPE_YUV)
+	{
+		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+	}
+
+	return 0;
+}
+
+void ivtv_mute(struct ivtv *itv)
+{
+	struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 };
+
+	/* Mute sound to avoid pop */
+	ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
+
+	if (atomic_read(&itv->capturing))
+		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
+
+	IVTV_DEBUG_INFO("Mute\n");
+}
+
+void ivtv_unmute(struct ivtv *itv)
+{
+	struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
+
+	/* initialize or refresh input */
+	if (atomic_read(&itv->capturing) == 0)
+		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+	ivtv_sleep_timeout(HZ / 10, 0);
+
+	if (atomic_read(&itv->capturing)) {
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
+	}
+
+	/* Unmute */
+	ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
+	IVTV_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h
new file mode 100644
index 0000000..74a1745
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-fileops.h
@@ -0,0 +1,44 @@
+/*
+    file operation functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* Testing/Debugging */
+int ivtv_v4l2_open(struct inode *inode, struct file *filp);
+ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
+		      loff_t * pos);
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+		       loff_t * pos);
+int ivtv_v4l2_close(struct inode *inode, struct file *filp);
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait);
+unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait);
+int ivtv_start_capture(struct ivtv_open_id *id);
+void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end);
+int ivtv_start_decoding(struct ivtv_open_id *id, int speed);
+void ivtv_mute(struct ivtv *itv);
+void ivtv_unmute(struct ivtv *itv);
+
+/* Utilities */
+
+/* Try to claim a stream for the filehandle. Return 0 on success,
+   -EBUSY if stream already claimed. Once a stream is claimed, it
+   remains claimed until the associated filehandle is closed. */
+int ivtv_claim_stream(struct ivtv_open_id *id, int type);
+
+/* Release a previously claimed stream. */
+void ivtv_release_stream(struct ivtv_stream *s);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
new file mode 100644
index 0000000..d4c910b
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -0,0 +1,272 @@
+/*
+    ivtv firmware functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
+#include <linux/firmware.h>
+
+#define IVTV_MASK_SPU_ENABLE 		0xFFFFFFFE
+#define IVTV_MASK_VPU_ENABLE15 		0xFFFFFFF6
+#define IVTV_MASK_VPU_ENABLE16 		0xFFFFFFFB
+#define IVTV_CMD_VDM_STOP 		0x00000000
+#define IVTV_CMD_AO_STOP 		0x00000005
+#define IVTV_CMD_APU_PING 		0x00000000
+#define IVTV_CMD_VPU_STOP15 		0xFFFFFFFE
+#define IVTV_CMD_VPU_STOP16 		0xFFFFFFEE
+#define IVTV_CMD_HW_BLOCKS_RST 		0xFFFFFFFF
+#define IVTV_CMD_SPU_STOP 		0x00000001
+#define IVTV_CMD_SDRAM_PRECHARGE_INIT 	0x0000001A
+#define IVTV_CMD_SDRAM_REFRESH_INIT 	0x80000640
+#define IVTV_SDRAM_SLEEPTIME 		(60 * HZ / 100)	/* 600 ms */
+
+#define IVTV_DECODE_INIT_MPEG_FILENAME 	"v4l-cx2341x-init.mpg"
+#define IVTV_DECODE_INIT_MPEG_SIZE 	(152*1024)
+
+/* Encoder/decoder firmware sizes */
+#define IVTV_FW_ENC_SIZE 		(376836)
+#define IVTV_FW_DEC_SIZE 		(256*1024)
+
+static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size)
+{
+	const struct firmware *fw = NULL;
+	int retries = 3;
+
+retry:
+	if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) {
+		int i;
+		volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
+		const u32 *src = (const u32 *)fw->data;
+
+		/* temporarily allow 256 KB encoding firmwares as well for
+		   compatibility with blackbird cards */
+		if (fw->size != size && fw->size != 256 * 1024) {
+			/* Due to race conditions in firmware loading (esp. with udev <0.95)
+			   the wrong file was sometimes loaded. So we check filesizes to
+			   see if at least the right-sized file was loaded. If not, then we
+			   retry. */
+			IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+			release_firmware(fw);
+			retries--;
+			goto retry;
+		}
+		for (i = 0; i < fw->size; i += 4) {
+			/* no need for endianness conversion on the ppc */
+			__raw_writel(*src, dst);
+			dst++;
+			src++;
+		}
+		release_firmware(fw);
+		IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+		return size;
+	}
+	IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
+	IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+	return -ENOMEM;
+}
+
+void ivtv_halt_firmware(struct ivtv *itv)
+{
+	IVTV_DEBUG_INFO("Preparing for firmware halt.\n");
+	if (itv->has_cx23415 && itv->dec_mbox.mbox)
+		ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0);
+	if (itv->enc_mbox.mbox)
+		ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
+
+	ivtv_sleep_timeout(HZ / 100, 0);
+	itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
+
+	IVTV_DEBUG_INFO("Stopping VDM\n");
+	write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM);
+
+	IVTV_DEBUG_INFO("Stopping AO\n");
+	write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO);
+
+	IVTV_DEBUG_INFO("pinging (?) APU\n");
+	write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU);
+
+	IVTV_DEBUG_INFO("Stopping VPU\n");
+	if (!itv->has_cx23415)
+		write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU);
+	else
+		write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU);
+
+	IVTV_DEBUG_INFO("Resetting Hw Blocks\n");
+	write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS);
+
+	IVTV_DEBUG_INFO("Stopping SPU\n");
+	write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
+
+	ivtv_sleep_timeout(HZ / 100, 0);
+
+	IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
+	write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
+
+	IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n");
+	write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH);
+
+	if (itv->has_cx23415) {
+		IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n");
+		write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE);
+
+		IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n");
+		write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
+	}
+
+	IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
+		   (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
+	ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+}
+
+void ivtv_firmware_versions(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	/* Encoder */
+	ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0);
+	IVTV_INFO("Encoder revision: 0x%08x\n", data[0]);
+
+	if (data[0] != 0x02060039)
+		IVTV_WARN("Recommended firmware version is 0x02060039.\n");
+
+	if (itv->has_cx23415) {
+		/* Decoder */
+		ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0);
+		IVTV_INFO("Decoder revision: 0x%08x\n", data[0]);
+	}
+}
+
+static int ivtv_firmware_copy(struct ivtv *itv)
+{
+	IVTV_DEBUG_INFO("Loading encoder image\n");
+	if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME,
+		   itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) {
+		IVTV_DEBUG_WARN("failed loading encoder firmware\n");
+		return -3;
+	}
+	if (!itv->has_cx23415)
+		return 0;
+
+	IVTV_DEBUG_INFO("Loading decoder image\n");
+	if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME,
+		   itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) {
+		IVTV_DEBUG_WARN("failed loading decoder firmware\n");
+		return -1;
+	}
+	return 0;
+}
+
+static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size)
+{
+	int i;
+
+	/* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte
+	   address boundary */
+	for (i = 0; i < size; i += 0x100) {
+		if (readl(mem + i)      == 0x12345678 &&
+		    readl(mem + i + 4)  == 0x34567812 &&
+		    readl(mem + i + 8)  == 0x56781234 &&
+		    readl(mem + i + 12) == 0x78123456) {
+			return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16);
+		}
+	}
+	return NULL;
+}
+
+int ivtv_firmware_init(struct ivtv *itv)
+{
+	int err;
+
+	ivtv_halt_firmware(itv);
+
+	/* load firmware */
+	err = ivtv_firmware_copy(itv);
+	if (err) {
+		IVTV_DEBUG_WARN("Error %d loading firmware\n", err);
+		return err;
+	}
+
+	/* start firmware */
+	write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
+	ivtv_sleep_timeout(HZ / 10, 0);
+	if (itv->has_cx23415)
+		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
+	else
+		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
+	ivtv_sleep_timeout(HZ / 10, 0);
+
+	/* find mailboxes and ping firmware */
+	itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
+	if (itv->enc_mbox.mbox == NULL)
+		IVTV_ERR("Encoder mailbox not found\n");
+	else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) {
+		IVTV_ERR("Encoder firmware dead!\n");
+		itv->enc_mbox.mbox = NULL;
+	}
+	if (itv->enc_mbox.mbox == NULL)
+		return -ENODEV;
+
+	if (!itv->has_cx23415)
+		return 0;
+
+	itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE);
+	if (itv->dec_mbox.mbox == NULL)
+		IVTV_ERR("Decoder mailbox not found\n");
+	else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) {
+		IVTV_ERR("Decoder firmware dead!\n");
+		itv->dec_mbox.mbox = NULL;
+	}
+	return itv->dec_mbox.mbox ? 0 : -ENODEV;
+}
+
+void ivtv_init_mpeg_decoder(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	long readbytes;
+	volatile u8 __iomem *mem_offset;
+
+	data[0] = 0;
+	data[1] = itv->params.width;	/* YUV source width */
+	data[2] = itv->params.height;
+	data[3] = itv->params.audio_properties;	/* Audio settings to use,
+							   bitmap. see docs. */
+	if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) {
+		IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n");
+		return;
+	}
+
+	if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) {
+		IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n");
+		return;
+	}
+	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
+	mem_offset = itv->dec_mem + data[1];
+
+	if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME,
+		mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) {
+		IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n",
+				IVTV_DECODE_INIT_MPEG_FILENAME);
+	} else {
+		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
+		ivtv_sleep_timeout(HZ / 10, 0);
+	}
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
+}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
new file mode 100644
index 0000000..8b2ffe6
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -0,0 +1,25 @@
+/*
+    ivtv firmware functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+int ivtv_firmware_init(struct ivtv *itv);
+void ivtv_firmware_versions(struct ivtv *itv);
+void ivtv_halt_firmware(struct ivtv *itv);
+void ivtv_init_mpeg_decoder(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
new file mode 100644
index 0000000..bc8f8ca
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -0,0 +1,307 @@
+/*
+    gpio functions.
+    Merging GPIO support into driver:
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include <media/tuner.h>
+
+/*
+ * GPIO assignment of Yuan MPG600/MPG160
+ *
+ *    bit 15  14  13  12 |  11  10   9   8 |   7   6   5   4 |   3   2   1   0
+ * OUTPUT         IN1 IN0                                       AM3 AM2 AM1 AM0
+ *  INPUT                   DM1         DM0
+ *
+ *   IN* : Input selection
+ *          IN1 IN0
+ *           1   1  N/A
+ *           1   0  Line
+ *           0   1  N/A
+ *           0   0  Tuner
+ *
+ *   AM* : Audio Mode
+ *          AM3  0: Normal        1: Mixed(Sub+Main channel)
+ *          AM2  0: Subchannel    1: Main channel
+ *          AM1  0: Stereo        1: Mono
+ *          AM0  0: Normal        1: Mute
+ *
+ *   DM* : Detected tuner audio Mode
+ *          DM1  0: Stereo        1: Mono
+ *          DM0  0: Multiplex     1: Normal
+ *
+ * GPIO Initial Settings
+ *           MPG600   MPG160
+ *     DIR   0x3080   0x7080
+ *  OUTPUT   0x000C   0x400C
+ *
+ *  Special thanks to Makoto Iguchi <iguchi@tahoo.org> and Mr. Anonymous
+ *  for analyzing GPIO of MPG160.
+ *
+ *****************************************************************************
+ *
+ * GPIO assignment of Avermedia M179 (per information direct from AVerMedia)
+ *
+ *    bit 15  14  13  12 |  11  10   9   8 |   7   6   5   4 |   3   2   1   0
+ * OUTPUT IN0 AM0 IN1               AM1 AM2       IN2     BR0   BR1
+ *  INPUT
+ *
+ *   IN* : Input selection
+ *          IN0 IN1 IN2
+ *           *   1   *  Mute
+ *           0   0   0  Line-In
+ *           1   0   0  TV Tuner Audio
+ *           0   0   1  FM Audio
+ *           1   0   1  Mute
+ *
+ *   AM* : Audio Mode
+ *          AM0 AM1 AM2
+ *           0   0   0  TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP
+ *           0   0   1  TV Tuner Audio: L_OUT=R_OUT=SAP   (SAP)
+ *           0   1   0  TV Tuner Audio: L_OUT=L, R_OUT=R   (stereo)
+ *           0   1   1  TV Tuner Audio: mute
+ *           1   *   *  TV Tuner Audio: L_OUT=R_OUT=(L+R)/2   (mono)
+ *
+ *   BR* : Audio Sample Rate (BR stands for bitrate for some reason)
+ *          BR0 BR1
+ *           0   0   32 kHz
+ *           0   1   44.1 kHz
+ *           1   0   48 kHz
+ *
+ *   DM* : Detected tuner audio Mode
+ *         Unknown currently
+ *
+ * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at
+ * AVerMedia for providing the GPIO information used to add support
+ * for the M179 cards.
+ */
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define IVTV_REG_GPIO_IN    0x9008
+#define IVTV_REG_GPIO_OUT   0x900c
+#define IVTV_REG_GPIO_DIR   0x9020
+
+void ivtv_reset_ir_gpio(struct ivtv *itv)
+{
+	int curdir, curout;
+
+	if (itv->card->type != IVTV_CARD_PVR_150)
+		return;
+	IVTV_DEBUG_INFO("Resetting PVR150 IR\n");
+	curout = read_reg(IVTV_REG_GPIO_OUT);
+	curdir = read_reg(IVTV_REG_GPIO_DIR);
+	curdir |= 0x80;
+	write_reg(curdir, IVTV_REG_GPIO_DIR);
+	curout = (curout & ~0xF) | 1;
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	/* We could use something else for smaller time */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(1);
+	curout |= 2;
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	curdir &= ~0x80;
+	write_reg(curdir, IVTV_REG_GPIO_DIR);
+}
+
+#ifdef HAVE_XC3028
+int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
+{
+	int curdir, curout;
+	struct ivtv *itv = (struct ivtv *) priv;
+
+	if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
+		return -EINVAL;
+	IVTV_INFO("Resetting tuner.\n");
+	curout = read_reg(IVTV_REG_GPIO_OUT);
+	curdir = read_reg(IVTV_REG_GPIO_DIR);
+	curdir |= (1 << 12);  /* GPIO bit 12 */
+
+	curout &= ~(1 << 12);
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(1);
+
+	curout |= (1 << 12);
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(1);
+
+	return 0;
+}
+#endif
+
+void ivtv_gpio_init(struct ivtv *itv)
+{
+	if (itv->card->gpio_init.direction == 0)
+		return;
+
+	IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+		   read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
+
+	/* init output data then direction */
+	write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT);
+	write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR);
+}
+
+static struct v4l2_queryctrl gpio_ctrl_mute = {
+	.id            = V4L2_CID_AUDIO_MUTE,
+	.type          = V4L2_CTRL_TYPE_BOOLEAN,
+	.name          = "Mute",
+	.minimum       = 0,
+	.maximum       = 1,
+	.step          = 1,
+	.default_value = 1,
+	.flags         = 0,
+};
+
+int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg)
+{
+	struct v4l2_tuner *tuner = arg;
+	struct v4l2_control *ctrl = arg;
+	struct v4l2_routing *route = arg;
+	u16 mask, data;
+
+	switch (command) {
+	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		mask = itv->card->gpio_audio_freq.mask;
+		switch (*(u32 *)arg) {
+		case 32000:
+			data = itv->card->gpio_audio_freq.f32000;
+			break;
+		case 44100:
+			data = itv->card->gpio_audio_freq.f44100;
+			break;
+		case 48000:
+		default:
+			data = itv->card->gpio_audio_freq.f48000;
+			break;
+		}
+		break;
+
+	case VIDIOC_G_TUNER:
+		mask = itv->card->gpio_audio_detect.mask;
+		if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
+			tuner->rxsubchans = V4L2_TUNER_MODE_STEREO |
+			       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		else
+			tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+		return 0;
+
+	case VIDIOC_S_TUNER:
+		mask = itv->card->gpio_audio_mode.mask;
+		switch (tuner->audmode) {
+		case V4L2_TUNER_MODE_LANG1:
+			data = itv->card->gpio_audio_mode.lang1;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			data = itv->card->gpio_audio_mode.lang2;
+			break;
+		case V4L2_TUNER_MODE_MONO:
+			data = itv->card->gpio_audio_mode.mono;
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+		default:
+			data = itv->card->gpio_audio_mode.stereo;
+			break;
+		}
+		break;
+
+	case AUDC_SET_RADIO:
+		mask = itv->card->gpio_audio_input.mask;
+		data = itv->card->gpio_audio_input.radio;
+		break;
+
+	case VIDIOC_S_STD:
+		mask = itv->card->gpio_audio_input.mask;
+		data = itv->card->gpio_audio_input.tuner;
+		break;
+
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+		if (route->input > 2)
+			return -EINVAL;
+		mask = itv->card->gpio_audio_input.mask;
+		switch (route->input) {
+			case 0:
+				data = itv->card->gpio_audio_input.tuner;
+				break;
+			case 1:
+				data = itv->card->gpio_audio_input.linein;
+				break;
+			case 2:
+			default:
+				data = itv->card->gpio_audio_input.radio;
+				break;
+		}
+		break;
+
+	case VIDIOC_G_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		mask = itv->card->gpio_audio_mute.mask;
+		data = itv->card->gpio_audio_mute.mute;
+		ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
+		return 0;
+
+	case VIDIOC_S_CTRL:
+		if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		mask = itv->card->gpio_audio_mute.mask;
+		data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
+		break;
+
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+
+		if (qc->id != V4L2_CID_AUDIO_MUTE)
+			return -EINVAL;
+		*qc = gpio_ctrl_mute;
+		return 0;
+	}
+
+	case VIDIOC_LOG_STATUS:
+		IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
+			read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT),
+			read_reg(IVTV_REG_GPIO_IN));
+		return 0;
+
+	case VIDIOC_INT_S_VIDEO_ROUTING:
+		if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
+			return -EINVAL;
+		mask = itv->card->gpio_video_input.mask;
+		if  (route->input == 0)
+			data = itv->card->gpio_video_input.tuner;
+		else if  (route->input == 1)
+			data = itv->card->gpio_video_input.composite;
+		else
+			data = itv->card->gpio_video_input.svideo;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	if (mask)
+		write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+	return 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
new file mode 100644
index 0000000..c301d2a
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -0,0 +1,25 @@
+/*
+    gpio functions.
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* GPIO stuff */
+void ivtv_gpio_init(struct ivtv *itv);
+void ivtv_reset_ir_gpio(struct ivtv *itv);
+int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr);
+int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
new file mode 100644
index 0000000..50624c6
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -0,0 +1,748 @@
+/*
+    I2C functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+    This file includes an i2c implementation that was reverse engineered
+    from the Hauppauge windows driver.  Older ivtv versions used i2c-algo-bit,
+    which whilst fine under most circumstances, had trouble with the Zilog
+    CPU on the PVR-150 which handles IR functions (occasional inability to
+    communicate with the chip until it was reset) and also with the i2c
+    bus being completely unreachable when multiple PVR cards were present.
+
+    The implementation is very similar to i2c-algo-bit, but there are enough
+    subtle differences that the two are hard to merge.  The general strategy
+    employed by i2c-algo-bit is to use udelay() to implement the timing
+    when putting out bits on the scl/sda lines.  The general strategy taken
+    here is to poll the lines for state changes (see ivtv_waitscl and
+    ivtv_waitsda).  In addition there are small delays at various locations
+    which poll the SCL line 5 times (ivtv_scldelay).  I would guess that
+    since this is memory mapped I/O that the length of those delays is tied
+    to the PCI bus clock.  There is some extra code to do with recovery
+    and retries.  Since it is not known what causes the actual i2c problems
+    in the first place, the only goal if one was to attempt to use
+    i2c-algo-bit would be to try to make it follow the same code path.
+    This would be a lot of work, and I'm also not convinced that it would
+    provide a generic benefit to i2c-algo-bit.  Therefore consider this
+    an engineering solution -- not pretty, but it works.
+
+    Some more general comments about what we are doing:
+
+    The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA)
+    lines.  To communicate on the bus (as a master, we don't act as a slave),
+    we first initiate a start condition (ivtv_start).  We then write the
+    address of the device that we want to communicate with, along with a flag
+    that indicates whether this is a read or a write.  The slave then issues
+    an ACK signal (ivtv_ack), which tells us that it is ready for reading /
+    writing.  We then proceed with reading or writing (ivtv_read/ivtv_write),
+    and finally issue a stop condition (ivtv_stop) to make the bus available
+    to other masters.
+
+    There is an additional form of transaction where a write may be
+    immediately followed by a read.  In this case, there is no intervening
+    stop condition.  (Only the msp3400 chip uses this method of data transfer).
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-i2c.h"
+
+#include <media/ir-kbd-i2c.h>
+
+/* i2c implementation for cx23415/6 chip, ivtv project.
+ * Author: Kevin Thayer (nufan_wfk at yahoo.com)
+ */
+/* i2c stuff */
+#define IVTV_REG_I2C_SETSCL_OFFSET 0x7000
+#define IVTV_REG_I2C_SETSDA_OFFSET 0x7004
+#define IVTV_REG_I2C_GETSCL_OFFSET 0x7008
+#define IVTV_REG_I2C_GETSDA_OFFSET 0x700c
+
+#ifndef I2C_ADAP_CLASS_TV_ANALOG
+#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
+#endif /* I2C_ADAP_CLASS_TV_ANALOG */
+
+#define IVTV_CS53L32A_I2C_ADDR		0x11
+#define IVTV_CX25840_I2C_ADDR 		0x44
+#define IVTV_SAA7115_I2C_ADDR 		0x21
+#define IVTV_SAA7127_I2C_ADDR 		0x44
+#define IVTV_SAA717x_I2C_ADDR 		0x21
+#define IVTV_MSP3400_I2C_ADDR 		0x40
+#define IVTV_HAUPPAUGE_I2C_ADDR 	0x50
+#define IVTV_WM8739_I2C_ADDR 		0x1a
+#define IVTV_WM8775_I2C_ADDR		0x1b
+#define IVTV_TEA5767_I2C_ADDR		0x60
+#define IVTV_UPD64031A_I2C_ADDR 	0x12
+#define IVTV_UPD64083_I2C_ADDR 		0x5c
+#define IVTV_TDA985X_I2C_ADDR      	0x5b
+
+/* This array should match the IVTV_HW_ defines */
+static const u8 hw_driverids[] = {
+	I2C_DRIVERID_CX25840,
+	I2C_DRIVERID_SAA711X,
+	I2C_DRIVERID_SAA7127,
+	I2C_DRIVERID_MSP3400,
+	I2C_DRIVERID_TUNER,
+	I2C_DRIVERID_WM8775,
+	I2C_DRIVERID_CS53L32A,
+	I2C_DRIVERID_TVEEPROM,
+	I2C_DRIVERID_SAA711X,
+	I2C_DRIVERID_TVAUDIO,
+	I2C_DRIVERID_UPD64031A,
+	I2C_DRIVERID_UPD64083,
+	I2C_DRIVERID_SAA717X,
+	I2C_DRIVERID_WM8739,
+	0 		/* IVTV_HW_GPIO dummy driver ID */
+};
+
+/* This array should match the IVTV_HW_ defines */
+static const char * const hw_drivernames[] = {
+	"cx2584x",
+	"saa7115",
+	"saa7127",
+	"msp3400",
+	"tuner",
+	"wm8775",
+	"cs53l32a",
+	"tveeprom",
+	"saa7114",
+	"tvaudio",
+	"upd64031a",
+	"upd64083",
+	"saa717x",
+	"wm8739",
+	"gpio",
+};
+
+static int attach_inform(struct i2c_client *client)
+{
+	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+	int i;
+
+	IVTV_DEBUG_I2C("i2c client attach\n");
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (itv->i2c_clients[i] == NULL) {
+			itv->i2c_clients[i] = client;
+			break;
+		}
+	}
+	if (i == I2C_CLIENTS_MAX) {
+		IVTV_ERR("insufficient room for new I2C client!\n");
+	}
+	return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+	int i;
+	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+
+	IVTV_DEBUG_I2C("i2c client detach\n");
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		if (itv->i2c_clients[i] == client) {
+			itv->i2c_clients[i] = NULL;
+			break;
+		}
+	}
+	IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n",
+		   client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
+
+	return 0;
+}
+
+/* Set the serial clock line to the desired state */
+static void ivtv_setscl(struct ivtv *itv, int state)
+{
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET);
+}
+
+/* Set the serial data line to the desired state */
+static void ivtv_setsda(struct ivtv *itv, int state)
+{
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET);
+}
+
+/* Read the serial clock line */
+static int ivtv_getscl(struct ivtv *itv)
+{
+	return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1;
+}
+
+/* Read the serial data line */
+static int ivtv_getsda(struct ivtv *itv)
+{
+	return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1;
+}
+
+/* Implement a short delay by polling the serial clock line */
+static void ivtv_scldelay(struct ivtv *itv)
+{
+	int i;
+
+	for (i = 0; i < 5; ++i)
+		ivtv_getscl(itv);
+}
+
+/* Wait for the serial clock line to become set to a specific value */
+static int ivtv_waitscl(struct ivtv *itv, int val)
+{
+	int i;
+
+	ivtv_scldelay(itv);
+	for (i = 0; i < 1000; ++i) {
+		if (ivtv_getscl(itv) == val)
+			return 1;
+	}
+	return 0;
+}
+
+/* Wait for the serial data line to become set to a specific value */
+static int ivtv_waitsda(struct ivtv *itv, int val)
+{
+	int i;
+
+	ivtv_scldelay(itv);
+	for (i = 0; i < 1000; ++i) {
+		if (ivtv_getsda(itv) == val)
+			return 1;
+	}
+	return 0;
+}
+
+/* Wait for the slave to issue an ACK */
+static int ivtv_ack(struct ivtv *itv)
+{
+	int ret = 0;
+
+	if (ivtv_getscl(itv) == 1) {
+		IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setsda(itv, 1);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	if (!ivtv_waitsda(itv, 0)) {
+		IVTV_DEBUG_I2C("Slave did not ack\n");
+		ret = -EREMOTEIO;
+	}
+	ivtv_setscl(itv, 0);
+	if (!ivtv_waitscl(itv, 0)) {
+		IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n");
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* Write a single byte to the i2c bus and wait for the slave to ACK */
+static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
+{
+	int i, bit;
+
+	IVTV_DEBUG_I2C("write %x\n",byte);
+	for (i = 0; i < 8; ++i, byte<<=1) {
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("Error setting SCL low\n");
+			return -EREMOTEIO;
+		}
+		bit = (byte>>7)&1;
+		ivtv_setsda(itv, bit);
+		if (!ivtv_waitsda(itv, bit)) {
+			IVTV_DEBUG_I2C("Error setting SDA\n");
+			return -EREMOTEIO;
+		}
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("Slave not ready for bit\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setscl(itv, 0);
+	if (!ivtv_waitscl(itv, 0)) {
+		IVTV_DEBUG_I2C("Error setting SCL low\n");
+		return -EREMOTEIO;
+	}
+	return ivtv_ack(itv);
+}
+
+/* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the
+   final byte) */
+static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
+{
+	int i;
+
+	*byte = 0;
+
+	ivtv_setsda(itv, 1);
+	ivtv_scldelay(itv);
+	for (i = 0; i < 8; ++i) {
+		ivtv_setscl(itv, 0);
+		ivtv_scldelay(itv);
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("Error setting SCL high\n");
+			return -EREMOTEIO;
+		}
+		*byte = ((*byte)<<1)|ivtv_getsda(itv);
+	}
+	ivtv_setscl(itv, 0);
+	ivtv_scldelay(itv);
+	ivtv_setsda(itv, nack);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 0);
+	ivtv_scldelay(itv);
+	IVTV_DEBUG_I2C("read %x\n",*byte);
+	return 0;
+}
+
+/* Issue a start condition on the i2c bus to alert slaves to prepare for
+   an address write */
+static int ivtv_start(struct ivtv *itv)
+{
+	int sda;
+
+	sda = ivtv_getsda(itv);
+	if (sda != 1) {
+		IVTV_DEBUG_I2C("SDA was low at start\n");
+		ivtv_setsda(itv, 1);
+		if (!ivtv_waitsda(itv, 1)) {
+			IVTV_DEBUG_I2C("SDA stuck low\n");
+			return -EREMOTEIO;
+		}
+	}
+	if (ivtv_getscl(itv) != 1) {
+		ivtv_setscl(itv, 1);
+		if (!ivtv_waitscl(itv, 1)) {
+			IVTV_DEBUG_I2C("SCL stuck low at start\n");
+			return -EREMOTEIO;
+		}
+	}
+	ivtv_setsda(itv, 0);
+	ivtv_scldelay(itv);
+	return 0;
+}
+
+/* Issue a stop condition on the i2c bus to release it */
+static int ivtv_stop(struct ivtv *itv)
+{
+	int i;
+
+	if (ivtv_getscl(itv) != 0) {
+		IVTV_DEBUG_I2C("SCL not low when stopping\n");
+		ivtv_setscl(itv, 0);
+		if (!ivtv_waitscl(itv, 0)) {
+			IVTV_DEBUG_I2C("SCL could not be set low\n");
+		}
+	}
+	ivtv_setsda(itv, 0);
+	ivtv_scldelay(itv);
+	ivtv_setscl(itv, 1);
+	if (!ivtv_waitscl(itv, 1)) {
+		IVTV_DEBUG_I2C("SCL could not be set high\n");
+		return -EREMOTEIO;
+	}
+	ivtv_scldelay(itv);
+	ivtv_setsda(itv, 1);
+	if (!ivtv_waitsda(itv, 1)) {
+		IVTV_DEBUG_I2C("resetting I2C\n");
+		for (i = 0; i < 16; ++i) {
+			ivtv_setscl(itv, 0);
+			ivtv_scldelay(itv);
+			ivtv_setscl(itv, 1);
+			ivtv_scldelay(itv);
+			ivtv_setsda(itv, 1);
+		}
+		ivtv_waitsda(itv, 1);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+/* Write a message to the given i2c slave.  do_stop may be 0 to prevent
+   issuing the i2c stop condition (when following with a read) */
+static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop)
+{
+	int retry, ret = -EREMOTEIO;
+	u32 i;
+
+	for (retry = 0; ret != 0 && retry < 8; ++retry) {
+		ret = ivtv_start(itv);
+
+		if (ret == 0) {
+			ret = ivtv_sendbyte(itv, addr<<1);
+			for (i = 0; ret == 0 && i < len; ++i)
+				ret = ivtv_sendbyte(itv, data[i]);
+		}
+		if (ret != 0 || do_stop) {
+			ivtv_stop(itv);
+		}
+	}
+	if (ret)
+		IVTV_DEBUG_I2C("i2c write to %x failed\n", addr);
+	return ret;
+}
+
+/* Read data from the given i2c slave.  A stop condition is always issued. */
+static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len)
+{
+	int retry, ret = -EREMOTEIO;
+	u32 i;
+
+	for (retry = 0; ret != 0 && retry < 8; ++retry) {
+		ret = ivtv_start(itv);
+		if (ret == 0)
+			ret = ivtv_sendbyte(itv, (addr << 1) | 1);
+		for (i = 0; ret == 0 && i < len; ++i) {
+			ret = ivtv_readbyte(itv, &data[i], i == len - 1);
+		}
+		ivtv_stop(itv);
+	}
+	if (ret)
+		IVTV_DEBUG_I2C("i2c read from %x failed\n", addr);
+	return ret;
+}
+
+/* Kernel i2c transfer implementation.  Takes a number of messages to be read
+   or written.  If a read follows a write, this will occur without an
+   intervening stop condition */
+static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct ivtv *itv = i2c_get_adapdata(i2c_adap);
+	int retval;
+	int i;
+
+	mutex_lock(&itv->i2c_bus_lock);
+	for (i = retval = 0; retval == 0 && i < num; i++) {
+		if (msgs[i].flags & I2C_M_RD)
+			retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len);
+		else {
+			/* if followed by a read, don't stop */
+			int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD);
+
+			retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop);
+		}
+	}
+	mutex_unlock(&itv->i2c_bus_lock);
+	return retval ? retval : num;
+}
+
+/* Kernel i2c capabilities */
+static u32 ivtv_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm ivtv_algo = {
+	.master_xfer   = ivtv_xfer,
+	.functionality = ivtv_functionality,
+};
+
+/* template for our-bit banger */
+static struct i2c_adapter ivtv_i2c_adap_hw_template = {
+	.name = "ivtv i2c driver",
+	.id = I2C_HW_B_CX2341X,
+	.algo = &ivtv_algo,
+	.algo_data = NULL,			/* filled from template */
+	.client_register = attach_inform,
+	.client_unregister = detach_inform,
+	.owner = THIS_MODULE,
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+	.class = I2C_ADAP_CLASS_TV_ANALOG,
+#endif
+};
+
+static void ivtv_setscl_old(void *data, int state)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state)
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET);
+}
+
+static void ivtv_setsda_old(void *data, int state)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	if (state)
+		itv->i2c_state |= 0x01;
+	else
+		itv->i2c_state &= ~0x01;
+
+	/* write them out */
+	/* write bits are inverted */
+	write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET);
+}
+
+static int ivtv_getscl_old(void *data)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1;
+}
+
+static int ivtv_getsda_old(void *data)
+{
+	struct ivtv *itv = (struct ivtv *)data;
+
+	return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter ivtv_i2c_adap_template = {
+	.name = "ivtv i2c driver",
+	.id = I2C_HW_B_CX2341X,  	/* algo-bit is OR'd with this */
+	.algo = NULL,                   /* set by i2c-algo-bit */
+	.algo_data = NULL,              /* filled from template */
+	.client_register = attach_inform,
+	.client_unregister = detach_inform,
+	.owner = THIS_MODULE,
+#ifdef I2C_ADAP_CLASS_TV_ANALOG
+	.class = I2C_ADAP_CLASS_TV_ANALOG,
+#endif
+};
+
+static struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+	NULL,                   /* ?? */
+	ivtv_setsda_old,        /* setsda function */
+	ivtv_setscl_old,        /* " */
+	ivtv_getsda_old,        /* " */
+	ivtv_getscl_old,        /* " */
+	10,                     /* udelay */
+	200                     /* timeout */
+};
+
+static struct i2c_client ivtv_i2c_client_template = {
+	.name = "ivtv internal",
+};
+
+int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg)
+{
+	struct i2c_client *client;
+	int retval;
+	int i;
+
+	IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		client = itv->i2c_clients[i];
+		if (client == NULL) {
+			continue;
+		}
+		if (client->driver->command == NULL) {
+			continue;
+		}
+		if (addr == client->addr) {
+			retval = client->driver->command(client, cmd, arg);
+			return retval;
+		}
+	}
+	if (cmd != VIDIOC_G_CHIP_IDENT)
+		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+	return -ENODEV;
+}
+
+/* Find the i2c device based on the driver ID and return
+   its i2c address or -ENODEV if no matching device was found. */
+static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
+{
+	struct i2c_client *client;
+	int retval = -ENODEV;
+	int i;
+
+	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+		client = itv->i2c_clients[i];
+		if (client == NULL)
+			continue;
+		if (id == client->driver->id) {
+			retval = client->addr;
+			break;
+		}
+	}
+	return retval;
+}
+
+/* Find the i2c device name matching the DRIVERID */
+static const char *ivtv_i2c_id_name(u32 id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+		if (hw_driverids[i] == id)
+			return hw_drivernames[i];
+	return "unknown device";
+}
+
+/* Find the i2c device name matching the IVTV_HW_ flag */
+static const char *ivtv_i2c_hw_name(u32 hw)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+		if (1 << i == hw)
+			return hw_drivernames[i];
+	return "unknown device";
+}
+
+/* Find the i2c device matching the IVTV_HW_ flag and return
+   its i2c address or -ENODEV if no matching device was found. */
+int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+		if (1 << i == hw)
+			return ivtv_i2c_id_addr(itv, hw_driverids[i]);
+	return -ENODEV;
+}
+
+/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing.
+   If hw == IVTV_HW_GPIO then call the gpio handler. */
+int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
+{
+	int addr;
+
+	if (hw == IVTV_HW_GPIO)
+		return ivtv_gpio(itv, cmd, arg);
+	if (hw == 0)
+		return 0;
+
+	addr = ivtv_i2c_hw_addr(itv, hw);
+	if (addr < 0) {
+		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+			       hw, ivtv_i2c_hw_name(hw), cmd);
+		return addr;
+	}
+	return ivtv_call_i2c_client(itv, addr, cmd, arg);
+}
+
+/* Calls i2c device based on I2C driver ID. */
+int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
+{
+	int addr;
+
+	addr = ivtv_i2c_id_addr(itv, id);
+	if (addr < 0) {
+		if (cmd != VIDIOC_G_CHIP_IDENT)
+			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+				id, ivtv_i2c_id_name(id), cmd);
+		return addr;
+	}
+	return ivtv_call_i2c_client(itv, addr, cmd, arg);
+}
+
+int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg);
+}
+
+int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg);
+}
+
+int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);
+}
+
+int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg);
+}
+
+int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg);
+}
+
+int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg);
+}
+
+/* broadcast cmd for all I2C clients and for the gpio subsystem */
+void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	if (itv->i2c_adap.algo == NULL) {
+		IVTV_ERR("adapter is not set");
+		return;
+	}
+	i2c_clients_command(&itv->i2c_adap, cmd, arg);
+	if (itv->hw_flags & IVTV_HW_GPIO)
+		ivtv_gpio(itv, cmd, arg);
+}
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_ivtv_i2c(struct ivtv *itv)
+{
+	IVTV_DEBUG_I2C("i2c init\n");
+
+	if (itv->options.newi2c > 0) {
+		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
+		       sizeof(struct i2c_adapter));
+	} else {
+		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template,
+		       sizeof(struct i2c_adapter));
+		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
+		       sizeof(struct i2c_algo_bit_data));
+		itv->i2c_algo.data = itv;
+		itv->i2c_adap.algo_data = &itv->i2c_algo;
+	}
+
+	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
+		itv->num);
+	i2c_set_adapdata(&itv->i2c_adap, itv);
+
+	memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
+	       sizeof(struct i2c_client));
+	itv->i2c_client.adapter = &itv->i2c_adap;
+	itv->i2c_adap.dev.parent = &itv->dev->dev;
+
+	IVTV_DEBUG_I2C("setting scl and sda to 1\n");
+	ivtv_setscl(itv, 1);
+	ivtv_setsda(itv, 1);
+
+	if (itv->options.newi2c > 0)
+		return i2c_add_adapter(&itv->i2c_adap);
+	else
+		return i2c_bit_add_bus(&itv->i2c_adap);
+}
+
+void __devexit exit_ivtv_i2c(struct ivtv *itv)
+{
+	IVTV_DEBUG_I2C("i2c exit\n");
+
+	i2c_del_adapter(&itv->i2c_adap);
+}
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
new file mode 100644
index 0000000..5d210ad
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -0,0 +1,36 @@
+/*
+    I2C functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg);
+
+int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw);
+int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
+int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
+int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
+void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
+
+/* init + register i2c algo-bit adapter */
+int __devinit init_ivtv_i2c(struct ivtv *itv);
+void __devexit exit_ivtv_i2c(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
new file mode 100644
index 0000000..794a6a0
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -0,0 +1,1567 @@
+/*
+    ioctl system call
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-version.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-fileops.h"
+#include "ivtv-vbi.h"
+#include "ivtv-audio.h"
+#include "ivtv-video.h"
+#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-gpio.h"
+#include "ivtv-controls.h"
+#include "ivtv-cards.h"
+#include <media/saa7127.h>
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/dvb/audio.h>
+#include <linux/i2c-id.h>
+
+u16 service2vbi(int type)
+{
+	switch (type) {
+		case V4L2_SLICED_TELETEXT_B:
+			return IVTV_SLICED_TYPE_TELETEXT_B;
+		case V4L2_SLICED_CAPTION_525:
+			return IVTV_SLICED_TYPE_CAPTION_525;
+		case V4L2_SLICED_WSS_625:
+			return IVTV_SLICED_TYPE_WSS_625;
+		case V4L2_SLICED_VPS:
+			return IVTV_SLICED_TYPE_VPS;
+		default:
+			return 0;
+	}
+}
+
+static int valid_service_line(int field, int line, int is_pal)
+{
+	return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+	       (!is_pal && line >= 10 && line < 22);
+}
+
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+	int i;
+
+	set = set & valid_set;
+	if (set == 0 || !valid_service_line(field, line, is_pal)) {
+		return 0;
+	}
+	if (!is_pal) {
+		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+			return V4L2_SLICED_CAPTION_525;
+	}
+	else {
+		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+			return V4L2_SLICED_VPS;
+		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+			return V4L2_SLICED_WSS_625;
+		if (line == 23)
+			return 0;
+	}
+	for (i = 0; i < 32; i++) {
+		if ((1 << i) & set)
+			return 1 << i;
+	}
+	return 0;
+}
+
+void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	u16 set = fmt->service_set;
+	int f, l;
+
+	fmt->service_set = 0;
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+		}
+	}
+}
+
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+	int f, l;
+	u16 set = 0;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+			set |= fmt->service_lines[f][l];
+		}
+	}
+	return set != 0;
+}
+
+u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+	int f, l;
+	u16 set = 0;
+
+	for (f = 0; f < 2; f++) {
+		for (l = 0; l < 24; l++) {
+			set |= fmt->service_lines[f][l];
+		}
+	}
+	return set;
+}
+
+static const struct {
+	v4l2_std_id  std;
+	char        *name;
+} enum_stds[] = {
+	{ V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
+	{ V4L2_STD_PAL_DK,    "PAL-DK"    },
+	{ V4L2_STD_PAL_I,     "PAL-I"     },
+	{ V4L2_STD_PAL_M,     "PAL-M"     },
+	{ V4L2_STD_PAL_N,     "PAL-N"     },
+	{ V4L2_STD_PAL_Nc,    "PAL-Nc"    },
+	{ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
+	{ V4L2_STD_SECAM_DK,  "SECAM-DK"  },
+	{ V4L2_STD_SECAM_L,   "SECAM-L"   },
+	{ V4L2_STD_SECAM_LC,  "SECAM-L'"  },
+	{ V4L2_STD_NTSC_M,    "NTSC-M"    },
+	{ V4L2_STD_NTSC_M_JP, "NTSC-J"    },
+	{ V4L2_STD_NTSC_M_KR, "NTSC-K"    },
+};
+
+static const struct v4l2_standard ivtv_std_60hz =
+{
+	.frameperiod = {.numerator = 1001, .denominator = 30000},
+	.framelines = 525,
+};
+
+static const struct v4l2_standard ivtv_std_50hz =
+{
+	.frameperiod = {.numerator = 1, .denominator = 25},
+	.framelines = 625,
+};
+
+void ivtv_set_osd_alpha(struct ivtv *itv)
+{
+	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
+		itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
+	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key);
+}
+
+int ivtv_set_speed(struct ivtv *itv, int speed)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+	int single_step = (speed == 1 || speed == -1);
+	DEFINE_WAIT(wait);
+
+	if (speed == 0) speed = 1000;
+
+	/* No change? */
+	if (speed == itv->speed && !single_step)
+		return 0;
+
+	s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+
+	if (single_step && (speed < 0) == (itv->speed < 0)) {
+		/* Single step video and no need to change direction */
+		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
+		itv->speed = speed;
+		return 0;
+	}
+	if (single_step)
+		/* Need to change direction */
+		speed = speed < 0 ? -1000 : 1000;
+
+	data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0;
+	data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0;
+	data[1] = (speed < 0);
+	data[2] = speed < 0 ? 3 : 7;
+	data[3] = itv->params.video_b_frames;
+	data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0;
+	data[5] = 0;
+	data[6] = 0;
+
+	if (speed == 1500 || speed == -1500) data[0] |= 1;
+	else if (speed == 2000 || speed == -2000) data[0] |= 2;
+	else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed);
+	else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed);
+
+	/* If not decoding, just change speed setting */
+	if (atomic_read(&itv->decoding) > 0) {
+		int got_sig = 0;
+
+		/* Stop all DMA and decoding activity */
+		ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);
+
+		/* Wait for any DMA to finish */
+		prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+		while (itv->i_flags & IVTV_F_I_DMA) {
+			got_sig = signal_pending(current);
+			if (got_sig)
+				break;
+			got_sig = 0;
+			schedule();
+		}
+		finish_wait(&itv->dma_waitq, &wait);
+		if (got_sig)
+			return -EINTR;
+
+		/* Change Speed safely */
+		ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data);
+		IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
+	}
+	if (single_step) {
+		speed = (speed < 0) ? -1 : 1;
+		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
+	}
+	itv->speed = speed;
+	return 0;
+}
+
+static int ivtv_validate_speed(int cur_speed, int new_speed)
+{
+	int fact = new_speed < 0 ? -1 : 1;
+	int s;
+
+	if (new_speed < 0) new_speed = -new_speed;
+	if (cur_speed < 0) cur_speed = -cur_speed;
+
+	if (cur_speed <= new_speed) {
+		if (new_speed > 1500) return fact * 2000;
+		if (new_speed > 1000) return fact * 1500;
+	}
+	else {
+		if (new_speed >= 2000) return fact * 2000;
+		if (new_speed >= 1500) return fact * 1500;
+		if (new_speed >= 1000) return fact * 1000;
+	}
+	if (new_speed == 0) return 1000;
+	if (new_speed == 1 || new_speed == 1000) return fact * new_speed;
+
+	s = new_speed;
+	new_speed = 1000 / new_speed;
+	if (1000 / cur_speed == new_speed)
+		new_speed += (cur_speed < s) ? -1 : 1;
+	if (new_speed > 60) return 1000 / (fact * 60);
+	return 1000 / (fact * new_speed);
+}
+
+static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,
+		struct video_command *vc, int try)
+{
+	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return -EINVAL;
+
+	switch (vc->cmd) {
+	case VIDEO_CMD_PLAY: {
+		vc->flags = 0;
+		vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);
+		if (vc->play.speed < 0)
+			vc->play.format = VIDEO_PLAY_FMT_GOP;
+		if (try) break;
+
+		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
+			return -EBUSY;
+		return ivtv_start_decoding(id, vc->play.speed);
+	}
+
+	case VIDEO_CMD_STOP:
+		vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;
+		if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)
+			vc->stop.pts = 0;
+		if (try) break;
+		if (atomic_read(&itv->decoding) == 0)
+			return 0;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+
+		itv->output_mode = OUT_NONE;
+		return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);
+
+	case VIDEO_CMD_FREEZE:
+		vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;
+		if (try) break;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+		if (atomic_read(&itv->decoding) > 0) {
+			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
+				(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+		}
+		break;
+
+	case VIDEO_CMD_CONTINUE:
+		vc->flags = 0;
+		if (try) break;
+		if (itv->output_mode != OUT_MPG)
+			return -EBUSY;
+		if (atomic_read(&itv->decoding) > 0) {
+			ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
+{
+	struct v4l2_register *regs = arg;
+	unsigned long flags;
+	volatile u8 __iomem *reg_start;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
+		reg_start = itv->reg_mem - IVTV_REG_OFFSET;
+	else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
+			regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
+		reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
+	else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)
+		reg_start = itv->enc_mem;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&ivtv_cards_lock, flags);
+	if (cmd == VIDIOC_DBG_G_REGISTER) {
+		regs->val = readl(regs->reg + reg_start);
+	} else {
+		writel(regs->val, regs->reg + reg_start);
+	}
+	spin_unlock_irqrestore(&ivtv_cards_lock, flags);
+	return 0;
+}
+
+static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt)
+{
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		fmt->fmt.pix.left = itv->main_rect.left;
+		fmt->fmt.pix.top = itv->main_rect.top;
+		fmt->fmt.pix.width = itv->main_rect.width;
+		fmt->fmt.pix.height = itv->main_rect.height;
+		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+		if (itv->output_mode == OUT_UDMA_YUV) {
+			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
+			case IVTV_YUV_MODE_INTERLACED:
+				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
+					V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
+				break;
+			case IVTV_YUV_MODE_PROGRESSIVE:
+				fmt->fmt.pix.field = V4L2_FIELD_NONE;
+				break;
+			default:
+				fmt->fmt.pix.field = V4L2_FIELD_ANY;
+				break;
+			}
+			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+			fmt->fmt.pix.sizeimage =
+				fmt->fmt.pix.height * fmt->fmt.pix.width +
+				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+		}
+		else if (itv->output_mode == OUT_YUV ||
+				streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
+				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+			fmt->fmt.pix.sizeimage =
+				fmt->fmt.pix.height * fmt->fmt.pix.width +
+				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+		} else {
+			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+			fmt->fmt.pix.sizeimage = 128 * 1024;
+		}
+		break;
+
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		fmt->fmt.pix.left = 0;
+		fmt->fmt.pix.top = 0;
+		fmt->fmt.pix.width = itv->params.width;
+		fmt->fmt.pix.height = itv->params.height;
+		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+		if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
+				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+			fmt->fmt.pix.sizeimage =
+				fmt->fmt.pix.height * fmt->fmt.pix.width +
+				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+		} else {
+			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+			fmt->fmt.pix.sizeimage = 128 * 1024;
+		}
+		break;
+
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		fmt->fmt.win.chromakey = itv->osd_color_key;
+		fmt->fmt.win.global_alpha = itv->osd_global_alpha;
+		break;
+
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		fmt->fmt.vbi.sampling_rate = 27000000;
+		fmt->fmt.vbi.offset = 248;
+		fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
+		fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+		fmt->fmt.vbi.start[0] = itv->vbi.start[0];
+		fmt->fmt.vbi.start[1] = itv->vbi.start[1];
+		fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
+		break;
+
+	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+	{
+		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+		if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+			return -EINVAL;
+		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+		if (itv->is_60hz) {
+			vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+			vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+		} else {
+			vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
+			vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
+		}
+		vbifmt->service_set = get_service_set(vbifmt);
+		break;
+	}
+
+	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+	{
+		struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+		vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+		memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+		memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+
+		if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
+			vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
+						 V4L2_SLICED_VBI_525;
+			expand_service_set(vbifmt, itv->is_50hz);
+			break;
+		}
+
+		itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+		vbifmt->service_set = get_service_set(vbifmt);
+		break;
+	}
+	case V4L2_BUF_TYPE_VBI_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
+		struct v4l2_format *fmt, int set_fmt)
+{
+	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+	u16 set;
+
+	if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		struct v4l2_rect r;
+		int field;
+
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		field = fmt->fmt.pix.field;
+		r.top = fmt->fmt.pix.top;
+		r.left = fmt->fmt.pix.left;
+		r.width = fmt->fmt.pix.width;
+		r.height = fmt->fmt.pix.height;
+		ivtv_get_fmt(itv, streamtype, fmt);
+		if (itv->output_mode != OUT_UDMA_YUV) {
+			/* TODO: would setting the rect also be valid for this mode? */
+			fmt->fmt.pix.top = r.top;
+			fmt->fmt.pix.left = r.left;
+			fmt->fmt.pix.width = r.width;
+			fmt->fmt.pix.height = r.height;
+		}
+		if (itv->output_mode == OUT_UDMA_YUV) {
+			/* TODO: add checks for validity */
+			fmt->fmt.pix.field = field;
+		}
+		if (set_fmt) {
+			if (itv->output_mode == OUT_UDMA_YUV) {
+				switch (field) {
+				case V4L2_FIELD_NONE:
+					itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+					break;
+				case V4L2_FIELD_ANY:
+					itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
+					break;
+				case V4L2_FIELD_INTERLACED_BT:
+					itv->yuv_info.lace_mode =
+						IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+					break;
+				case V4L2_FIELD_INTERLACED_TB:
+				default:
+					itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
+					break;
+				}
+				itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+				/* Force update of yuv registers */
+				itv->yuv_info.yuv_forced_update = 1;
+				return 0;
+			}
+			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+				 r.width, r.height, r.left, r.top))
+				itv->main_rect = r;
+			else
+				return -EINVAL;
+		}
+		return 0;
+	}
+
+	if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		if (set_fmt) {
+			itv->osd_color_key = fmt->fmt.win.chromakey;
+			itv->osd_global_alpha = fmt->fmt.win.global_alpha;
+			ivtv_set_osd_alpha(itv);
+		}
+		return 0;
+	}
+
+	/* set window size */
+	if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		int w = fmt->fmt.pix.width;
+		int h = fmt->fmt.pix.height;
+
+		if (w > 720) w = 720;
+		else if (w < 1) w = 1;
+		if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480);
+		else if (h < 2) h = 2;
+		ivtv_get_fmt(itv, streamtype, fmt);
+		fmt->fmt.pix.width = w;
+		fmt->fmt.pix.height = h;
+
+		if (!set_fmt || (itv->params.width == w && itv->params.height == h))
+			return 0;
+		if (atomic_read(&itv->capturing) > 0)
+			return -EBUSY;
+
+		itv->params.width = w;
+		itv->params.height = h;
+		if (w != 720 || h != (itv->is_50hz ? 576 : 480))
+			itv->params.video_temporal_filter = 0;
+		else
+			itv->params.video_temporal_filter = 8;
+		itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+		return ivtv_get_fmt(itv, streamtype, fmt);
+	}
+
+	/* set raw VBI format */
+	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI &&
+		    itv->vbi.sliced_in->service_set &&
+		    atomic_read(&itv->capturing) > 0) {
+			return -EBUSY;
+		}
+		if (set_fmt) {
+			itv->vbi.sliced_in->service_set = 0;
+			itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+		}
+		return ivtv_get_fmt(itv, streamtype, fmt);
+	}
+
+	/* set sliced VBI output
+	   In principle the user could request that only certain
+	   VBI types are output and that the others are ignored.
+	   I.e., suppress CC in the even fields or only output
+	   WSS and no VPS. Currently though there is no choice. */
+	if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+		return ivtv_get_fmt(itv, streamtype, fmt);
+
+	/* any else but sliced VBI capture is an error */
+	if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		return -EINVAL;
+
+	if (streamtype == IVTV_DEC_STREAM_TYPE_VBI)
+		return ivtv_get_fmt(itv, streamtype, fmt);
+
+	/* set sliced VBI capture format */
+	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+	memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+
+	if (vbifmt->service_set)
+		expand_service_set(vbifmt, itv->is_50hz);
+	set = check_service_set(vbifmt, itv->is_50hz);
+	vbifmt->service_set = get_service_set(vbifmt);
+
+	if (!set_fmt)
+		return 0;
+	if (set == 0)
+		return -EINVAL;
+	if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) {
+		return -EBUSY;
+	}
+	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
+	return 0;
+}
+
+static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv *itv = id->itv;
+	struct v4l2_register *reg = arg;
+
+	switch (cmd) {
+	/* ioctls to allow direct access to the encoder registers for testing */
+	case VIDIOC_DBG_G_REGISTER:
+		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+			return ivtv_itvc(itv, cmd, arg);
+		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
+		return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
+
+	case VIDIOC_DBG_S_REGISTER:
+		if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+			return ivtv_itvc(itv, cmd, arg);
+		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
+		return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
+
+	case VIDIOC_G_CHIP_IDENT: {
+		struct v4l2_chip_ident *chip = arg;
+
+		chip->ident = V4L2_IDENT_NONE;
+		chip->revision = 0;
+		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
+			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
+				struct v4l2_chip_ident *chip = arg;
+
+				chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
+			}
+			return 0;
+		}
+		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+			return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
+		if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+			return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
+		return -EINVAL;
+	}
+
+	case VIDIOC_INT_S_AUDIO_ROUTING: {
+		struct v4l2_routing *route = arg;
+
+		ivtv_audio_set_route(itv, route);
+		break;
+	}
+
+	case VIDIOC_INT_RESET:
+		ivtv_reset_ir_gpio(itv);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
+{
+	struct ivtv_open_id *id = NULL;
+
+	if (filp) id = (struct ivtv_open_id *)filp->private_data;
+
+	switch (cmd) {
+	case VIDIOC_G_PRIORITY:
+	{
+		enum v4l2_priority *p = arg;
+
+		*p = v4l2_prio_max(&itv->prio);
+		break;
+	}
+
+	case VIDIOC_S_PRIORITY:
+	{
+		enum v4l2_priority *prio = arg;
+
+		return v4l2_prio_change(&itv->prio, &id->prio, *prio);
+	}
+
+	case VIDIOC_QUERYCAP:{
+		struct v4l2_capability *vcap = arg;
+
+		memset(vcap, 0, sizeof(*vcap));
+		strcpy(vcap->driver, IVTV_DRIVER_NAME);     /* driver name */
+		strcpy(vcap->card, itv->card_name); 	    /* card type */
+		strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
+		vcap->version = IVTV_DRIVER_VERSION; 	    /* version */
+		vcap->capabilities = itv->v4l2_cap; 	    /* capabilities */
+
+		/* reserved.. must set to 0! */
+		vcap->reserved[0] = vcap->reserved[1] =
+			vcap->reserved[2] = vcap->reserved[3] = 0;
+		break;
+	}
+
+	case VIDIOC_ENUMAUDIO:{
+		struct v4l2_audio *vin = arg;
+
+		return ivtv_get_audio_input(itv, vin->index, vin);
+	}
+
+	case VIDIOC_G_AUDIO:{
+		struct v4l2_audio *vin = arg;
+
+		vin->index = itv->audio_input;
+		return ivtv_get_audio_input(itv, vin->index, vin);
+	}
+
+	case VIDIOC_S_AUDIO:{
+		struct v4l2_audio *vout = arg;
+
+		if (vout->index >= itv->nof_audio_inputs)
+			return -EINVAL;
+		itv->audio_input = vout->index;
+		ivtv_audio_set_io(itv);
+		break;
+	}
+
+	case VIDIOC_ENUMAUDOUT:{
+		struct v4l2_audioout *vin = arg;
+
+		/* set it to defaults from our table */
+		return ivtv_get_audio_output(itv, vin->index, vin);
+	}
+
+	case VIDIOC_G_AUDOUT:{
+		struct v4l2_audioout *vin = arg;
+
+		vin->index = 0;
+		return ivtv_get_audio_output(itv, vin->index, vin);
+	}
+
+	case VIDIOC_S_AUDOUT:{
+		struct v4l2_audioout *vout = arg;
+
+		return ivtv_get_audio_output(itv, vout->index, vout);
+	}
+
+	case VIDIOC_ENUMINPUT:{
+		struct v4l2_input *vin = arg;
+
+		/* set it to defaults from our table */
+		return ivtv_get_input(itv, vin->index, vin);
+	}
+
+	case VIDIOC_ENUMOUTPUT:{
+		struct v4l2_output *vout = arg;
+
+		return ivtv_get_output(itv, vout->index, vout);
+	}
+
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_S_FMT: {
+		struct v4l2_format *fmt = arg;
+
+		return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT);
+	}
+
+	case VIDIOC_G_FMT: {
+		struct v4l2_format *fmt = arg;
+		int type = fmt->type;
+
+		memset(fmt, 0, sizeof(*fmt));
+		fmt->type = type;
+		return ivtv_get_fmt(itv, id->type, fmt);
+	}
+
+	case VIDIOC_S_CROP: {
+		struct v4l2_crop *crop = arg;
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		return itv->video_dec_func(itv, VIDIOC_S_CROP, arg);
+	}
+
+	case VIDIOC_G_CROP: {
+		struct v4l2_crop *crop = arg;
+
+		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+		return itv->video_dec_func(itv, VIDIOC_G_CROP, arg);
+	}
+
+	case VIDIOC_ENUM_FMT: {
+		static struct v4l2_fmtdesc formats[] = {
+			{ 0, 0, 0,
+			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+			  { 0, 0, 0, 0 }
+			},
+			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+			  "MPEG", V4L2_PIX_FMT_MPEG,
+			  { 0, 0, 0, 0 }
+			}
+		};
+		struct v4l2_fmtdesc *fmt = arg;
+		enum v4l2_buf_type type = fmt->type;
+
+		switch (type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+			if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (fmt->index > 1)
+			return -EINVAL;
+		*fmt = formats[fmt->index];
+		fmt->type = type;
+		return 0;
+	}
+
+	case VIDIOC_G_INPUT:{
+		*(int *)arg = itv->active_input;
+		break;
+	}
+
+	case VIDIOC_S_INPUT:{
+		int inp = *(int *)arg;
+
+		if (inp < 0 || inp >= itv->nof_inputs)
+			return -EINVAL;
+
+		if (inp == itv->active_input) {
+			IVTV_DEBUG_INFO("Input unchanged\n");
+			break;
+		}
+		IVTV_DEBUG_INFO("Changing input from %d to %d\n",
+				itv->active_input, inp);
+
+		itv->active_input = inp;
+		/* Set the audio input to whatever is appropriate for the
+		   input type. */
+		itv->audio_input = itv->card->video_inputs[inp].audio_index;
+
+		/* prevent others from messing with the streams until
+		   we're finished changing inputs. */
+		ivtv_mute(itv);
+		ivtv_video_set_io(itv);
+		ivtv_audio_set_io(itv);
+		ivtv_unmute(itv);
+		break;
+	}
+
+	case VIDIOC_G_OUTPUT:{
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		*(int *)arg = itv->active_output;
+		break;
+	}
+
+	case VIDIOC_S_OUTPUT:{
+		int outp = *(int *)arg;
+		struct v4l2_routing route;
+
+		if (outp >= itv->card->nof_outputs)
+			return -EINVAL;
+
+		if (outp == itv->active_output) {
+			IVTV_DEBUG_INFO("Output unchanged\n");
+			break;
+		}
+		IVTV_DEBUG_INFO("Changing output from %d to %d\n",
+			   itv->active_output, outp);
+
+		itv->active_output = outp;
+		route.input = SAA7127_INPUT_TYPE_NORMAL;
+		route.output = itv->card->video_outputs[outp].video_output;
+		ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+		break;
+	}
+
+	case VIDIOC_G_FREQUENCY:{
+		struct v4l2_frequency *vf = arg;
+
+		if (vf->tuner != 0)
+			return -EINVAL;
+		ivtv_call_i2c_clients(itv, cmd, arg);
+		break;
+	}
+
+	case VIDIOC_S_FREQUENCY:{
+		struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+
+		if (vf.tuner != 0)
+			return -EINVAL;
+
+		ivtv_mute(itv);
+		IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
+		ivtv_call_i2c_clients(itv, cmd, &vf);
+		ivtv_unmute(itv);
+		break;
+	}
+
+	case VIDIOC_ENUMSTD:{
+		struct v4l2_standard *vs = arg;
+		int idx = vs->index;
+
+		if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
+			return -EINVAL;
+
+		*vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
+				ivtv_std_60hz : ivtv_std_50hz;
+		vs->index = idx;
+		vs->id = enum_stds[idx].std;
+		strcpy(vs->name, enum_stds[idx].name);
+		break;
+	}
+
+	case VIDIOC_G_STD:{
+		*(v4l2_std_id *) arg = itv->std;
+		break;
+	}
+
+	case VIDIOC_S_STD: {
+		v4l2_std_id std = *(v4l2_std_id *) arg;
+
+		if ((std & V4L2_STD_ALL) == 0)
+			return -EINVAL;
+
+		if (std == itv->std)
+			break;
+
+		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
+		    atomic_read(&itv->capturing) > 0 ||
+		    atomic_read(&itv->decoding) > 0) {
+			/* Switching standard would turn off the radio or mess
+			   with already running streams, prevent that by
+			   returning EBUSY. */
+			return -EBUSY;
+		}
+
+		itv->std = std;
+		itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
+		itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
+		itv->params.width = 720;
+		itv->params.height = itv->is_50hz ? 576 : 480;
+		itv->vbi.count = itv->is_50hz ? 18 : 12;
+		itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
+		itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
+		if (itv->hw_flags & IVTV_HW_CX25840) {
+			itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
+		}
+		IVTV_DEBUG_INFO("Switching standard to %llx.\n", itv->std);
+
+		/* Tuner */
+		ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+
+		if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+			/* set display standard */
+			itv->std_out = std;
+			itv->is_out_60hz = itv->is_60hz;
+			itv->is_out_50hz = itv->is_50hz;
+			ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+			ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
+			itv->main_rect.left = itv->main_rect.top = 0;
+			itv->main_rect.width = 720;
+			itv->main_rect.height = itv->params.height;
+			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+				720, itv->main_rect.height, 0, 0);
+		}
+		break;
+	}
+
+	case VIDIOC_S_TUNER: {	/* Setting tuner can only set audio mode */
+		struct v4l2_tuner *vt = arg;
+
+		if (vt->index != 0)
+			return -EINVAL;
+
+		ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+		break;
+	}
+
+	case VIDIOC_G_TUNER: {
+		struct v4l2_tuner *vt = arg;
+
+		if (vt->index != 0)
+			return -EINVAL;
+
+		memset(vt, 0, sizeof(*vt));
+		ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+
+		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+			strcpy(vt->name, "ivtv Radio Tuner");
+			vt->type = V4L2_TUNER_RADIO;
+		} else {
+			strcpy(vt->name, "ivtv TV Tuner");
+			vt->type = V4L2_TUNER_ANALOG_TV;
+		}
+		break;
+	}
+
+	case VIDIOC_G_SLICED_VBI_CAP: {
+		struct v4l2_sliced_vbi_cap *cap = arg;
+		int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+		int f, l;
+		enum v4l2_buf_type type = cap->type;
+
+		memset(cap, 0, sizeof(*cap));
+		cap->type = type;
+		if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+			for (f = 0; f < 2; f++) {
+				for (l = 0; l < 24; l++) {
+					if (valid_service_line(f, l, itv->is_50hz)) {
+						cap->service_lines[f][l] = set;
+					}
+				}
+			}
+			return 0;
+		}
+		if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+			if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
+				return -EINVAL;
+			if (itv->is_60hz) {
+				cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+				cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+			} else {
+				cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
+				cap->service_lines[0][16] = V4L2_SLICED_VPS;
+			}
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	case VIDIOC_G_ENC_INDEX: {
+		struct v4l2_enc_idx *idx = arg;
+		int i;
+
+		idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+					IVTV_MAX_PGM_INDEX;
+		if (idx->entries > V4L2_ENC_IDX_ENTRIES)
+			idx->entries = V4L2_ENC_IDX_ENTRIES;
+		for (i = 0; i < idx->entries; i++) {
+			idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+		}
+		itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
+		break;
+	}
+
+	case VIDIOC_ENCODER_CMD:
+	case VIDIOC_TRY_ENCODER_CMD: {
+		struct v4l2_encoder_cmd *enc = arg;
+		int try = cmd == VIDIOC_TRY_ENCODER_CMD;
+
+		memset(&enc->raw, 0, sizeof(enc->raw));
+		switch (enc->cmd) {
+		case V4L2_ENC_CMD_START:
+			enc->flags = 0;
+			if (try)
+				return 0;
+			return ivtv_start_capture(id);
+
+		case V4L2_ENC_CMD_STOP:
+			enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+			if (try)
+				return 0;
+			ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+			return 0;
+
+		case V4L2_ENC_CMD_PAUSE:
+			enc->flags = 0;
+			if (try)
+				return 0;
+			if (!atomic_read(&itv->capturing))
+				return -EPERM;
+			if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+				return 0;
+			ivtv_mute(itv);
+			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
+			break;
+
+		case V4L2_ENC_CMD_RESUME:
+			enc->flags = 0;
+			if (try)
+				return 0;
+			if (!atomic_read(&itv->capturing))
+				return -EPERM;
+			if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
+				return 0;
+			ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
+			ivtv_unmute(itv);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	}
+
+	case VIDIOC_G_FBUF: {
+		struct v4l2_framebuffer *fb = arg;
+
+		memset(fb, 0, sizeof(*fb));
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+			break;
+		fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
+			V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
+		fb->fmt.pixelformat = itv->osd_pixelformat;
+		fb->fmt.width = itv->osd_rect.width;
+		fb->fmt.height = itv->osd_rect.height;
+		fb->fmt.left = itv->osd_rect.left;
+		fb->fmt.top = itv->osd_rect.top;
+		fb->base = (void *)itv->osd_video_pbase;
+		if (itv->osd_global_alpha_state)
+			fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+		if (itv->osd_local_alpha_state)
+			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		if (itv->osd_color_key_state)
+			fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+		break;
+	}
+
+	case VIDIOC_S_FBUF: {
+		struct v4l2_framebuffer *fb = arg;
+
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+			break;
+		itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+		itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
+		itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+		break;
+	}
+
+	case VIDIOC_LOG_STATUS:
+	{
+		int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
+		struct v4l2_input vidin;
+		struct v4l2_audio audin;
+		int i;
+
+		IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
+		if (itv->hw_flags & IVTV_HW_TVEEPROM) {
+			struct tveeprom tv;
+
+			ivtv_read_eeprom(itv, &tv);
+		}
+		ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+		ivtv_get_input(itv, itv->active_input, &vidin);
+		ivtv_get_audio_input(itv, itv->audio_input, &audin);
+		IVTV_INFO("Video Input: %s\n", vidin.name);
+		IVTV_INFO("Audio Input: %s\n", audin.name);
+		if (has_output) {
+			struct v4l2_output vidout;
+			struct v4l2_audioout audout;
+			int mode = itv->output_mode;
+			static const char * const output_modes[] = {
+				"None",
+				"MPEG Streaming",
+				"YUV Streaming",
+				"YUV Frames",
+				"Passthrough",
+			};
+
+			ivtv_get_output(itv, itv->active_output, &vidout);
+			ivtv_get_audio_output(itv, 0, &audout);
+			IVTV_INFO("Video Output: %s\n", vidout.name);
+			IVTV_INFO("Audio Output: %s\n", audout.name);
+			if (mode < 0 || mode > OUT_PASSTHROUGH)
+				mode = OUT_NONE;
+			IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+		}
+		IVTV_INFO("Tuner: %s\n",
+			test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
+		cx2341x_log_status(&itv->params, itv->name);
+		IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+			struct ivtv_stream *s = &itv->streams[i];
+
+			if (s->v4l2dev == NULL || s->buffers == 0)
+				continue;
+			IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
+					(s->buffers - s->q_free.buffers) * 100 / s->buffers,
+					(s->buffers * s->buf_size) / 1024, s->buffers);
+		}
+		IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", itv->mpg_data_received, itv->vbi_data_inserted);
+		IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv *itv = id->itv;
+	int nonblocking = filp->f_flags & O_NONBLOCK;
+	struct ivtv_stream *s = &itv->streams[id->type];
+
+	switch (cmd) {
+	case IVTV_IOC_DMA_FRAME: {
+		struct ivtv_dma_frame *args = arg;
+
+		IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+			return -EINVAL;
+		if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL)
+			return 0;
+		if (ivtv_claim_stream(id, id->type)) {
+			return -EBUSY;
+		}
+		if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) {
+			ivtv_release_stream(s);
+			return -EBUSY;
+		}
+		if (args->y_source == NULL)
+			return 0;
+		return ivtv_yuv_prep_frame(itv, args);
+	}
+
+	case VIDEO_GET_PTS: {
+		u32 data[CX2341X_MBOX_MAX_DATA];
+		u64 *pts = arg;
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
+		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
+			*pts = s->dma_pts;
+			break;
+		}
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+
+		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+			*pts = (u64) ((u64)itv->last_dec_timing[2] << 32) |
+					(u64)itv->last_dec_timing[1];
+			break;
+		}
+		*pts = 0;
+		if (atomic_read(&itv->decoding)) {
+			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+				return -EIO;
+			}
+			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+			*pts = (u64) ((u64) data[2] << 32) | (u64) data[1];
+			/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
+		}
+		break;
+	}
+
+	case VIDEO_GET_FRAME_COUNT: {
+		u32 data[CX2341X_MBOX_MAX_DATA];
+		u64 *frame = arg;
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
+		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
+			*frame = 0;
+			break;
+		}
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+
+		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
+			*frame = itv->last_dec_timing[0];
+			break;
+		}
+		*frame = 0;
+		if (atomic_read(&itv->decoding)) {
+			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
+				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
+				return -EIO;
+			}
+			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
+			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+			*frame = data[0];
+		}
+		break;
+	}
+
+	case VIDEO_PLAY: {
+		struct video_command vc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
+		memset(&vc, 0, sizeof(vc));
+		vc.cmd = VIDEO_CMD_PLAY;
+		return ivtv_video_command(itv, id, &vc, 0);
+	}
+
+	case VIDEO_STOP: {
+		struct video_command vc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
+		memset(&vc, 0, sizeof(vc));
+		vc.cmd = VIDEO_CMD_STOP;
+		vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY;
+		return ivtv_video_command(itv, id, &vc, 0);
+	}
+
+	case VIDEO_FREEZE: {
+		struct video_command vc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
+		memset(&vc, 0, sizeof(vc));
+		vc.cmd = VIDEO_CMD_FREEZE;
+		return ivtv_video_command(itv, id, &vc, 0);
+	}
+
+	case VIDEO_CONTINUE: {
+		struct video_command vc;
+
+		IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
+		memset(&vc, 0, sizeof(vc));
+		vc.cmd = VIDEO_CMD_CONTINUE;
+		return ivtv_video_command(itv, id, &vc, 0);
+	}
+
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND: {
+		struct video_command *vc = arg;
+		int try = (cmd == VIDEO_TRY_COMMAND);
+
+		if (try)
+			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n");
+		else
+			IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n");
+		return ivtv_video_command(itv, id, vc, try);
+	}
+
+	case VIDEO_GET_EVENT: {
+		struct video_event *ev = arg;
+		DEFINE_WAIT(wait);
+
+		IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		memset(ev, 0, sizeof(*ev));
+		set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
+
+		while (1) {
+			if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags))
+				ev->type = VIDEO_EVENT_DECODER_STOPPED;
+			else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) {
+				ev->type = VIDEO_EVENT_VSYNC;
+				ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ?
+					VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN;
+				if (itv->output_mode == OUT_UDMA_YUV &&
+					(itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) ==
+								IVTV_YUV_MODE_PROGRESSIVE) {
+					ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE;
+				}
+			}
+			if (ev->type)
+				return 0;
+			if (nonblocking)
+				return -EAGAIN;
+			/* wait for event */
+			prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
+			if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
+				schedule();
+			finish_wait(&itv->event_waitq, &wait);
+			if (signal_pending(current)) {
+				/* return if a signal was received */
+				IVTV_DEBUG_INFO("User stopped wait for event\n");
+				return -EINTR;
+			}
+		}
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
+			      unsigned int cmd, void *arg)
+{
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv *itv = id->itv;
+	int ret;
+
+	/* check priority */
+	switch (cmd) {
+	case VIDIOC_S_CTRL:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_S_OUTPUT:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_S_FREQUENCY:
+	case VIDIOC_S_FMT:
+	case VIDIOC_S_CROP:
+	case VIDIOC_S_AUDIO:
+	case VIDIOC_S_AUDOUT:
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_S_FBUF:
+		ret = v4l2_prio_check(&itv->prio, &id->prio);
+		if (ret)
+			return ret;
+	}
+
+	switch (cmd) {
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
+	case VIDIOC_G_CHIP_IDENT:
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+	case VIDIOC_INT_RESET:
+		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
+			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
+			v4l_printk_ioctl(cmd);
+		}
+		return ivtv_debug_ioctls(filp, cmd, arg);
+
+	case VIDIOC_G_PRIORITY:
+	case VIDIOC_S_PRIORITY:
+	case VIDIOC_QUERYCAP:
+	case VIDIOC_ENUMINPUT:
+	case VIDIOC_G_INPUT:
+	case VIDIOC_S_INPUT:
+	case VIDIOC_ENUMOUTPUT:
+	case VIDIOC_G_OUTPUT:
+	case VIDIOC_S_OUTPUT:
+	case VIDIOC_G_FMT:
+	case VIDIOC_S_FMT:
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_ENUM_FMT:
+	case VIDIOC_G_CROP:
+	case VIDIOC_S_CROP:
+	case VIDIOC_G_FREQUENCY:
+	case VIDIOC_S_FREQUENCY:
+	case VIDIOC_ENUMSTD:
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+	case VIDIOC_S_TUNER:
+	case VIDIOC_G_TUNER:
+	case VIDIOC_ENUMAUDIO:
+	case VIDIOC_S_AUDIO:
+	case VIDIOC_G_AUDIO:
+	case VIDIOC_ENUMAUDOUT:
+	case VIDIOC_S_AUDOUT:
+	case VIDIOC_G_AUDOUT:
+	case VIDIOC_G_SLICED_VBI_CAP:
+	case VIDIOC_LOG_STATUS:
+	case VIDIOC_G_ENC_INDEX:
+	case VIDIOC_ENCODER_CMD:
+	case VIDIOC_TRY_ENCODER_CMD:
+	case VIDIOC_G_FBUF:
+	case VIDIOC_S_FBUF:
+		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
+			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
+			v4l_printk_ioctl(cmd);
+		}
+		return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
+
+	case VIDIOC_QUERYMENU:
+	case VIDIOC_QUERYCTRL:
+	case VIDIOC_S_CTRL:
+	case VIDIOC_G_CTRL:
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_G_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
+			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
+			v4l_printk_ioctl(cmd);
+		}
+		return ivtv_control_ioctls(itv, cmd, arg);
+
+	case IVTV_IOC_DMA_FRAME:
+	case VIDEO_GET_PTS:
+	case VIDEO_GET_FRAME_COUNT:
+	case VIDEO_GET_EVENT:
+	case VIDEO_PLAY:
+	case VIDEO_STOP:
+	case VIDEO_FREEZE:
+	case VIDEO_CONTINUE:
+	case VIDEO_COMMAND:
+	case VIDEO_TRY_COMMAND:
+		return ivtv_decoder_ioctls(filp, cmd, arg);
+
+	case 0x00005401:	/* Handle isatty() calls */
+		return -EINVAL;
+	default:
+		return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+						   ivtv_v4l2_do_ioctl);
+	}
+	return 0;
+}
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv *itv = id->itv;
+
+	/* Filter dvb ioctls that cannot be handled by video_usercopy */
+	switch (cmd) {
+	case VIDEO_SELECT_SOURCE:
+		IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+			return -EINVAL;
+		return ivtv_passthrough_mode(itv, arg == VIDEO_SOURCE_DEMUX);
+
+	case AUDIO_SET_MUTE:
+		IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n");
+		itv->speed_mute_audio = arg;
+		return 0;
+
+	case AUDIO_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
+		if (arg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		itv->audio_stereo_mode = arg;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		return 0;
+
+	case AUDIO_BILINGUAL_CHANNEL_SELECT:
+		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
+		if (arg > AUDIO_STEREO_SWAPPED)
+			return -EINVAL;
+		itv->audio_bilingual_mode = arg;
+		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+		return 0;
+
+	default:
+		break;
+	}
+	return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
+}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
new file mode 100644
index 0000000..cbccf7a
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -0,0 +1,28 @@
+/*
+    ioctl system call
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+u16 service2vbi(int type);
+void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg);
+int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
+void ivtv_set_osd_alpha(struct ivtv *itv);
+int ivtv_set_speed(struct ivtv *itv, int speed);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
new file mode 100644
index 0000000..c3a047b
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -0,0 +1,838 @@
+/* interrupt handling
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-firmware.h"
+#include "ivtv-fileops.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-vbi.h"
+#include "ivtv-yuv.h"
+
+#define DMA_MAGIC_COOKIE 0x000001fe
+
+#define SLICED_VBI_PIO 1
+
+static void ivtv_dma_dec_start(struct ivtv_stream *s);
+
+static const int ivtv_stream_map[] = {
+	IVTV_ENC_STREAM_TYPE_MPG,
+	IVTV_ENC_STREAM_TYPE_YUV,
+	IVTV_ENC_STREAM_TYPE_PCM,
+	IVTV_ENC_STREAM_TYPE_VBI,
+};
+
+static inline int ivtv_use_pio(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	return s->dma == PCI_DMA_NONE ||
+	    (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set);
+}
+
+void ivtv_irq_work_handler(struct work_struct *work)
+{
+	struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue);
+
+	DEFINE_WAIT(wait);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
+		vbi_work_handler(itv);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
+		ivtv_yuv_work_handler(itv);
+}
+
+/* Determine the required DMA size, setup enough buffers in the predma queue and
+   actually copy the data from the card to the buffers in case a PIO transfer is
+   required for this stream.
+ */
+static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_buffer *buf;
+	struct list_head *p;
+	u32 bytes_needed = 0;
+	u32 offset, size;
+	u32 UVoffset = 0, UVsize = 0;
+	int skip_bufs = s->q_predma.buffers;
+	int idx = s->SG_length;
+	int rc;
+
+	/* sanity checks */
+	if (s->v4l2dev == NULL) {
+		IVTV_DEBUG_WARN("Stream %s not started\n", s->name);
+		return -1;
+	}
+	if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
+		IVTV_DEBUG_WARN("Stream %s not open\n", s->name);
+		return -1;
+	}
+
+	/* determine offset, size and PTS for the various streams */
+	switch (s->type) {
+		case IVTV_ENC_STREAM_TYPE_MPG:
+			offset = data[1];
+			size = data[2];
+			s->dma_pts = 0;
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_YUV:
+			offset = data[1];
+			size = data[2];
+			UVoffset = data[3];
+			UVsize = data[4];
+			s->dma_pts = ((u64) data[5] << 32) | data[6];
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_PCM:
+			offset = data[1] + 12;
+			size = data[2] - 12;
+			s->dma_pts = read_dec(offset - 8) |
+				((u64)(read_dec(offset - 12)) << 32);
+			if (itv->has_cx23415)
+				offset += IVTV_DECODER_OFFSET;
+			break;
+
+		case IVTV_ENC_STREAM_TYPE_VBI:
+			size = itv->vbi.enc_size * itv->vbi.fpi;
+			offset = read_enc(itv->vbi.enc_start - 4) + 12;
+			if (offset == 12) {
+				IVTV_DEBUG_INFO("VBI offset == 0\n");
+				return -1;
+			}
+			s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
+			break;
+
+		case IVTV_DEC_STREAM_TYPE_VBI:
+			size = read_dec(itv->vbi.dec_start + 4) + 8;
+			offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
+			s->dma_pts = 0;
+			offset += IVTV_DECODER_OFFSET;
+			break;
+		default:
+			/* shouldn't happen */
+			return -1;
+	}
+
+	/* if this is the start of the DMA then fill in the magic cookie */
+	if (s->SG_length == 0) {
+		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
+		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
+			s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET);
+			write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+		}
+		else {
+			s->dma_backup = read_enc(offset);
+			write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+		}
+		s->dma_offset = offset;
+	}
+
+	bytes_needed = size;
+	if (s->type == IVTV_ENC_STREAM_TYPE_YUV) {
+		/* The size for the Y samples needs to be rounded upwards to a
+		   multiple of the buf_size. The UV samples then start in the
+		   next buffer. */
+		bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size);
+		bytes_needed += UVsize;
+	}
+
+	IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+		ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
+
+	rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
+	if (rc < 0) { /* Insufficient buffers */
+		IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n",
+				bytes_needed, s->name);
+		return -1;
+	}
+	if (rc && !s->buffers_stolen && (s->s_flags & IVTV_F_S_APPL_IO)) {
+		IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name);
+		IVTV_WARN("Cause: the application is not reading fast enough.\n");
+	}
+	s->buffers_stolen = rc;
+
+	/* got the buffers, now fill in SGarray (DMA) or copy the data from the card
+	   to the buffers (PIO). */
+	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
+	memset(buf->buf, 0, 128);
+	list_for_each(p, &s->q_predma.list) {
+		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+
+		if (skip_bufs-- > 0)
+			continue;
+		if (!ivtv_use_pio(s)) {
+			s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle);
+			s->SGarray[idx].src = cpu_to_le32(offset);
+			s->SGarray[idx].size = cpu_to_le32(s->buf_size);
+		}
+		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+
+		/* If PIO, then copy the data from the card to the buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+			memcpy_fromio(buf->buf, itv->dec_mem + offset - IVTV_DECODER_OFFSET, buf->bytesused);
+		}
+		else if (ivtv_use_pio(s)) {
+			memcpy_fromio(buf->buf, itv->enc_mem + offset, buf->bytesused);
+		}
+
+		s->q_predma.bytesused += buf->bytesused;
+		size -= buf->bytesused;
+		offset += s->buf_size;
+
+		/* Sync SG buffers */
+		ivtv_buf_sync_for_device(s, buf);
+
+		if (size == 0) {	/* YUV */
+			/* process the UV section */
+			offset = UVoffset;
+			size = UVsize;
+		}
+		idx++;
+	}
+	s->SG_length = idx;
+	return 0;
+}
+
+static void dma_post(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_buffer *buf = NULL;
+	struct list_head *p;
+	u32 offset;
+	u32 *u32buf;
+	int x = 0;
+
+	if (ivtv_use_pio(s)) {
+		if (s->q_predma.bytesused)
+			ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+		s->SG_length = 0;
+	}
+	IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+			s->name, s->dma_offset);
+	list_for_each(p, &s->q_dma.list) {
+		buf = list_entry(p, struct ivtv_buffer, list);
+		u32buf = (u32 *)buf->buf;
+
+		/* Sync Buffer */
+		ivtv_buf_sync_for_cpu(s, buf);
+
+		if (x == 0) {
+			offset = s->dma_last_offset;
+			if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+			{
+				for (offset = 0; offset < 64; offset++) {
+					if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+						break;
+					}
+				}
+				offset *= 4;
+				if (offset == 256) {
+					IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
+					offset = s->dma_last_offset;
+				}
+				if (s->dma_last_offset != offset)
+					IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset);
+				s->dma_last_offset = offset;
+			}
+			if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
+						s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
+				write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET);
+			}
+			else {
+				write_enc_sync(0, s->dma_offset);
+			}
+			if (offset) {
+				buf->bytesused -= offset;
+				memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset);
+			}
+			*u32buf = cpu_to_le32(s->dma_backup);
+		}
+		x++;
+		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
+		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
+			set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags);
+	}
+	if (buf)
+		buf->bytesused += s->dma_last_offset;
+	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
+		/* Parse and Groom VBI Data */
+		s->q_dma.bytesused -= buf->bytesused;
+		ivtv_process_vbi_data(itv, buf, 0, s->type);
+		s->q_dma.bytesused += buf->bytesused;
+		if (s->id == -1) {
+			ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
+			return;
+		}
+	}
+	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused);
+	if (s->id != -1)
+		wake_up(&s->waitq);
+}
+
+void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_buffer *buf;
+	struct list_head *p;
+	u32 y_size = itv->params.height * itv->params.width;
+	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
+	int y_done = 0;
+	int bytes_written = 0;
+	unsigned long flags = 0;
+	int idx = 0;
+
+	IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
+	list_for_each(p, &s->q_predma.list) {
+		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+
+		/* YUV UV Offset from Y Buffer */
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
+			offset = uv_offset;
+			y_done = 1;
+		}
+		s->SGarray[idx].src = cpu_to_le32(buf->dma_handle);
+		s->SGarray[idx].dst = cpu_to_le32(offset);
+		s->SGarray[idx].size = cpu_to_le32(buf->bytesused);
+
+		offset += buf->bytesused;
+		bytes_written += buf->bytesused;
+
+		/* Sync SG buffers */
+		ivtv_buf_sync_for_device(s, buf);
+		idx++;
+	}
+	s->SG_length = idx;
+
+	/* Mark last buffer size for Interrupt flag */
+	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	if (lock)
+		spin_lock_irqsave(&itv->dma_reg_lock, flags);
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+		ivtv_dma_dec_start(s);
+	}
+	else {
+		set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
+	}
+	if (lock)
+		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
+}
+
+/* start the encoder DMA */
+static void ivtv_dma_enc_start(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+	int i;
+
+	if (s->q_predma.bytesused)
+		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+	IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+	s->SGarray[s->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);
+
+	/* If this is an MPEG stream, and VBI data is also pending, then append the
+	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
+
+	   VBI DMA is a second class citizen compared to MPEG and mixing them together
+	   will confuse the firmware (the end of a VBI DMA is seen as the end of a
+	   MPEG DMA, thus effectively dropping an MPEG frame). So instead we make
+	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
+	   use. This way no conflicts occur. */
+	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length &&
+			s->SG_length + s_vbi->SG_length <= s->buffers) {
+		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
+		s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256);
+		for (i = 0; i < s_vbi->SG_length; i++) {
+			s->SGarray[s->SG_length++] = s_vbi->SGarray[i];
+		}
+		itv->vbi.dma_offset = s_vbi->dma_offset;
+		s_vbi->SG_length = 0;
+		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
+		IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+	}
+
+	/* Mark last buffer size for Interrupt flag */
+	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+	set_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = s->type;
+	itv->dma_timer.expires = jiffies + HZ / 10;
+	add_timer(&itv->dma_timer);
+}
+
+static void ivtv_dma_dec_start(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	if (s->q_predma.bytesused)
+		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+	IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+	/* put SG Handle into register 0x0c */
+	write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	set_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = s->type;
+	itv->dma_timer.expires = jiffies + HZ / 10;
+	add_timer(&itv->dma_timer);
+}
+
+static void ivtv_irq_dma_read(struct ivtv *itv)
+{
+	struct ivtv_stream *s = NULL;
+	struct ivtv_buffer *buf;
+	int hw_stream_type;
+
+	IVTV_DEBUG_IRQ("DEC DMA READ\n");
+	del_timer(&itv->dma_timer);
+	if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
+		IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
+		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+	}
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
+			s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+			hw_stream_type = 2;
+		}
+		else {
+			s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+			hw_stream_type = 0;
+		}
+		IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+
+		ivtv_stream_sync_for_cpu(s);
+
+		/* For some reason must kick the firmware, like PIO mode,
+		   I think this tells the firmware we are done and the size
+		   of the xfer so it can calculate what we need next.
+		   I think we can do this part ourselves but would have to
+		   fully calculate xfer info ourselves and not use interrupts
+		 */
+		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused,
+				hw_stream_type);
+
+		/* Free last DMA call */
+		while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) {
+			ivtv_buf_sync_for_cpu(s, buf);
+			ivtv_enqueue(s, buf, &s->q_free);
+		}
+		wake_up(&s->waitq);
+	}
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	del_timer(&itv->dma_timer);
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
+	IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
+	if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
+		data[1] = 3;
+	else if (data[1] > 2)
+		return;
+	s = &itv->streams[ivtv_stream_map[data[1]]];
+	if (data[0] & 0x18) {
+		IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]);
+		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]);
+	}
+	s->SG_length = 0;
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	dma_post(s);
+	ivtv_stream_sync_for_cpu(s);
+	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
+		u32 tmp;
+
+		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+		tmp = s->dma_offset;
+		s->dma_offset = itv->vbi.dma_offset;
+		dma_post(s);
+		s->dma_offset = tmp;
+	}
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_dma_err(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	del_timer(&itv->dma_timer);
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
+	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
+					read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
+	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
+		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
+
+		/* retry */
+		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
+			ivtv_dma_dec_start(s);
+		else
+			ivtv_dma_enc_start(s);
+		return;
+	}
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
+
+static void ivtv_irq_enc_start_cap(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	/* Get DMA destination and size arguments from card */
+	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
+	IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+
+	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
+		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
+				data[0], data[1], data[2]);
+		return;
+	}
+	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+	s = &itv->streams[ivtv_stream_map[data[0]]];
+	if (!stream_enc_dma_append(s, data)) {
+		if (ivtv_use_pio(s)) {
+			dma_post(s);
+			ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[0]);
+		}
+		else {
+			set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
+		}
+	}
+}
+
+static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
+{
+	struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
+
+	if (ivtv_use_pio(s)) {
+		if (stream_enc_dma_append(s, data))
+			return;
+		if (s->q_predma.bytesused)
+			ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+		s->SG_length = 0;
+		dma_post(s);
+		return;
+	}
+	/* If more than two VBI buffers are pending, then
+	   clear the old ones and start with this new one.
+	   This can happen during transition stages when MPEG capturing is
+	   started, but the first interrupts haven't arrived yet. During
+	   that period VBI requests can accumulate without being able to
+	   DMA the data. Since at most four VBI DMA buffers are available,
+	   we just drop the old requests when there are already three
+	   requests queued. */
+	if (s->SG_length > 2) {
+		struct list_head *p;
+		list_for_each(p, &s->q_predma.list) {
+			struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+			ivtv_buf_sync_for_cpu(s, buf);
+		}
+		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
+		s->SG_length = 0;
+	}
+	/* if we can append the data, and the MPEG stream isn't capturing,
+	   then start a DMA request for just the VBI data. */
+	if (!stream_enc_dma_append(s, data) &&
+			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
+		set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+		set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
+	}
+}
+
+static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
+
+	IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
+			!stream_enc_dma_append(s, data)) {
+		dma_post(s);
+	}
+}
+
+static void ivtv_irq_dec_data_req(struct ivtv *itv)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv_stream *s;
+
+	/* YUV or MPG */
+	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
+
+	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
+		itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;
+		itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];
+		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+	}
+	else {
+		itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];
+		itv->dma_data_req_offset = data[1];
+		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
+	}
+	IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+		       itv->dma_data_req_offset, itv->dma_data_req_size);
+	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
+		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+	}
+	else {
+		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
+		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
+	}
+}
+
+static void ivtv_irq_vsync(struct ivtv *itv)
+{
+	/* The vsync interrupt is unusual in that it won't clear until
+	 * the end of the first line for the current field, at which
+	 * point it clears itself. This can result in repeated vsync
+	 * interrupts, or a missed vsync. Read some of the registers
+	 * to determine the line being displayed and ensure we handle
+	 * one vsync per frame.
+	 */
+	unsigned int frame = read_reg(0x28c0) & 1;
+	int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+
+	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
+
+	if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) ||
+			(frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) {
+		int next_dma_frame = last_dma_frame;
+
+		if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+			write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+			write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+			write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+			write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+			next_dma_frame = (next_dma_frame + 1) & 0x3;
+			atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+		}
+	}
+	if (frame != (itv->lastVsyncFrame & 1)) {
+		struct ivtv_stream *s = ivtv_get_output_stream(itv);
+		int work = 0;
+
+		itv->lastVsyncFrame += 1;
+		if (frame == 0) {
+			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
+			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
+		}
+		else {
+			set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
+		}
+		if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) {
+			set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags);
+			wake_up(&itv->event_waitq);
+		}
+		wake_up(&itv->vsync_waitq);
+		if (s)
+			wake_up(&s->waitq);
+
+		/* Send VBI to saa7127 */
+		if (frame) {
+			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
+			work = 1;
+		}
+
+		/* Check if we need to update the yuv registers */
+		if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
+			if (!itv->yuv_info.new_frame_info[last_dma_frame].update)
+				last_dma_frame = (last_dma_frame - 1) & 3;
+
+			if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
+				itv->yuv_info.update_frame = last_dma_frame;
+				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
+				itv->yuv_info.yuv_forced_update = 0;
+				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
+				work = 1;
+			}
+		}
+		if (work)
+			queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+	}
+}
+
+#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ)
+
+irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
+{
+	struct ivtv *itv = (struct ivtv *)dev_id;
+	u32 combo;
+	u32 stat;
+	int i;
+	u8 vsync_force = 0;
+
+	spin_lock(&itv->dma_reg_lock);
+	/* get contents of irq status register */
+	stat = read_reg(IVTV_REG_IRQSTATUS);
+
+	combo = ~itv->irqmask & stat;
+
+	/* Clear out IRQ */
+	if (combo) write_reg(combo, IVTV_REG_IRQSTATUS);
+
+	if (0 == combo) {
+		/* The vsync interrupt is unusual and clears itself. If we
+		 * took too long, we may have missed it. Do some checks
+		 */
+		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
+			/* vsync is enabled, see if we're in a new field */
+			if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) {
+				/* New field, looks like we missed it */
+				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16);
+				vsync_force = 1;
+			}
+		}
+
+		if (!vsync_force) {
+			/* No Vsync expected, wasn't for us */
+			spin_unlock(&itv->dma_reg_lock);
+			return IRQ_NONE;
+		}
+	}
+
+	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
+	   these messages */
+	if (combo & ~0xff6d0400)
+		IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+
+	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
+		IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+	}
+
+	if (combo & IVTV_IRQ_DMA_READ) {
+		ivtv_irq_dma_read(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) {
+		ivtv_irq_enc_dma_complete(itv);
+	}
+
+	if (combo & IVTV_IRQ_DMA_ERR) {
+		ivtv_irq_dma_err(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_START_CAP) {
+		ivtv_irq_enc_start_cap(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_VBI_CAP) {
+		ivtv_irq_enc_vbi_cap(itv);
+	}
+
+	if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) {
+		ivtv_irq_dev_vbi_reinsert(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_EOS) {
+		IVTV_DEBUG_IRQ("ENC EOS\n");
+		set_bit(IVTV_F_I_EOS, &itv->i_flags);
+		wake_up(&itv->cap_w);
+	}
+
+	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
+		ivtv_irq_dec_data_req(itv);
+	}
+
+	/* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */
+	if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
+		ivtv_irq_vsync(itv);
+	}
+
+	if (combo & IVTV_IRQ_ENC_VIM_RST) {
+		IVTV_DEBUG_IRQ("VIM RST\n");
+		/*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */
+	}
+
+	if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) {
+		IVTV_DEBUG_INFO("Stereo mode changed\n");
+	}
+
+	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
+			int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+			struct ivtv_stream *s = &itv->streams[idx];
+
+			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
+				continue;
+			if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
+				ivtv_dma_dec_start(s);
+			else
+				ivtv_dma_enc_start(s);
+			break;
+		}
+		if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) {
+			ivtv_udma_start(itv);
+		}
+	}
+
+	spin_unlock(&itv->dma_reg_lock);
+
+	/* If we've just handled a 'forced' vsync, it's safest to say it
+	 * wasn't ours. Another device may have triggered it at just
+	 * the right time.
+	 */
+	return vsync_force ? IRQ_NONE : IRQ_HANDLED;
+}
+
+void ivtv_unfinished_dma(unsigned long arg)
+{
+	struct ivtv *itv = (struct ivtv *)arg;
+
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+		return;
+	IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+
+	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
+	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
+	itv->cur_dma_stream = -1;
+	wake_up(&itv->dma_waitq);
+}
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
new file mode 100644
index 0000000..a43348a
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -0,0 +1,26 @@
+/*
+    interrupt handling
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
+
+void ivtv_irq_work_handler(struct work_struct *work);
+void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
+void ivtv_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
new file mode 100644
index 0000000..6ae42a3
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -0,0 +1,360 @@
+/*
+    mailbox functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-mailbox.h"
+
+/* Firmware mailbox flags*/
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE   0x00000002
+#define IVTV_MBOX_DRIVER_BUSY   0x00000001
+#define IVTV_MBOX_FREE 		0x00000000
+
+/* Firmware mailbox standard timeout */
+#define IVTV_API_STD_TIMEOUT 	0x02000000
+
+#define API_CACHE 	 (1 << 0) 	/* Allow the command to be stored in the cache */
+#define API_RESULT	 (1 << 1) 	/* Allow 1 second for this cmd to end */
+#define API_FAST_RESULT	 (3 << 1)	/* Allow 0.1 second for this cmd to end */
+#define API_DMA 	 (1 << 3)	/* DMA mailbox, has special handling */
+#define API_NO_WAIT_MB 	 (1 << 4)	/* Command may not wait for a free mailbox */
+#define API_NO_WAIT_RES	 (1 << 5)	/* Command may not wait for the result */
+
+struct ivtv_api_info {
+	int flags;		/* Flags, see above */
+	const char *name; 	/* The name of the command */
+};
+
+#define API_ENTRY(x, f) [x] = { (f), #x }
+
+static const struct ivtv_api_info api_info[256] = {
+	/* MPEG encoder API */
+	API_ENTRY(CX2341X_ENC_PING_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_START_CAPTURE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_STOP_CAPTURE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_PCR_ID, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_BIT_RATE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_VBI_LINE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_HALT_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_GET_VERSION, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_GET_SEQ_END, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, 	API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB),
+	API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, 	API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, 	API_CACHE),
+	API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, 		API_CACHE),
+	API_ENTRY(CX2341X_ENC_MUTE_VIDEO, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_MUTE_AUDIO, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE,	API_FAST_RESULT),
+	API_ENTRY(CX2341X_ENC_MISC, 			API_FAST_RESULT),
+	/* Obsolete PULLDOWN API command */
+	API_ENTRY(0xb1, 				API_CACHE),
+
+	/* MPEG decoder API */
+	API_ENTRY(CX2341X_DEC_PING_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_START_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, 	API_RESULT),
+	API_ENTRY(CX2341X_DEC_STEP_VIDEO, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_XFER_INFO, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_HALT_FW, 			API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_STANDARD, 		API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_VERSION, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, 		API_RESULT /*| API_NO_WAIT_RES*/),
+	API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, 		API_CACHE),
+	API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, 	API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, 	API_CACHE),
+	API_ENTRY(CX2341X_DEC_EXTRACT_VBI, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, 	API_CACHE),
+
+	/* OSD API */
+	API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_STATE, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_STATE, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, 		API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_BLT_COPY, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_BLT_FILL, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_BLT_TEXT, 		API_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 	API_CACHE),
+	API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, 		API_CACHE),
+	API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, 	API_FAST_RESULT),
+	API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, 	API_CACHE)
+};
+
+static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb)
+{
+	u32 flags = readl(&mbdata->mbox[mb].flags);
+	int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE);
+
+	/* if the mailbox is free, then try to claim it */
+	if (is_free && !test_and_set_bit(mb, &mbdata->busy)) {
+		write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags);
+		return 1;
+	}
+	return 0;
+}
+
+/* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not
+   attempted here. */
+static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags)
+{
+	unsigned long then = jiffies;
+	int i, mb;
+	int max_mbox = mbdata->max_mbox;
+	int retries = 100;
+
+	/* All slow commands use the same mailbox, serializing them and also
+	   leaving the other mailbox free for simple fast commands. */
+	if ((flags & API_FAST_RESULT) == API_RESULT)
+		max_mbox = 1;
+
+	/* find free non-DMA mailbox */
+	for (i = 0; i < retries; i++) {
+		for (mb = 1; mb <= max_mbox; mb++)
+			if (try_mailbox(itv, mbdata, mb))
+				return mb;
+
+		/* Sleep before a retry, if not atomic */
+		if (!(flags & API_NO_WAIT_MB)) {
+			if (jiffies - then > retries * HZ / 100)
+			       break;
+			ivtv_sleep_timeout(HZ / 100, 0);
+		}
+	}
+	return -ENODEV;
+}
+
+static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[])
+{
+	int i;
+
+	write_sync(cmd, &mbox->cmd);
+	write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout);
+
+	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
+		write_sync(data[i], &mbox->data[i]);
+
+	write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags);
+}
+
+static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata)
+{
+	int i;
+
+	for (i = 0; i <= mbdata->max_mbox; i++) {
+		IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n",
+			i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags));
+		write_sync(0, &mbdata->mbox[i].flags);
+		clear_bit(i, &mbdata->busy);
+	}
+}
+
+static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
+{
+	struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
+	volatile struct ivtv_mailbox __iomem *mbox;
+	int api_timeout = HZ;
+	int flags, mb, i;
+	unsigned long then;
+
+	/* sanity checks */
+	if (NULL == mbdata) {
+		IVTV_ERR("No mailbox allocated\n");
+		return -ENODEV;
+	}
+	if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
+	    cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
+		IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args);
+		return -EINVAL;
+	}
+
+	IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+
+	/* clear possibly uninitialized part of data array */
+	for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
+		data[i] = 0;
+
+	/* If this command was issued within the last 30 minutes and with identical
+	   data, then just return 0 as there is no need to issue this command again.
+	   Just an optimization to prevent unnecessary use of mailboxes. */
+	if (itv->api_cache[cmd].last_jiffies &&
+	    jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+	    !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
+		itv->api_cache[cmd].last_jiffies = jiffies;
+		return 0;
+	}
+
+	flags = api_info[cmd].flags;
+
+	if (flags & API_DMA) {
+		for (i = 0; i < 100; i++) {
+			mb = i % (mbdata->max_mbox + 1);
+			if (try_mailbox(itv, mbdata, mb)) {
+				write_mailbox(&mbdata->mbox[mb], cmd, args, data);
+				clear_bit(mb, &mbdata->busy);
+				return 0;
+			}
+			IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n",
+					api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags));
+		}
+		IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name);
+		clear_all_mailboxes(itv, mbdata);
+		return -EBUSY;
+	}
+
+	if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
+		api_timeout = HZ / 10;
+
+	mb = get_mailbox(itv, mbdata, flags);
+	if (mb < 0) {
+		IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name);
+		clear_all_mailboxes(itv, mbdata);
+		return -EBUSY;
+	}
+	mbox = &mbdata->mbox[mb];
+	write_mailbox(mbox, cmd, args, data);
+	if (flags & API_CACHE) {
+		memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data));
+		itv->api_cache[cmd].last_jiffies = jiffies;
+	}
+	if ((flags & API_RESULT) == 0) {
+		clear_bit(mb, &mbdata->busy);
+		return 0;
+	}
+
+	/* Get results */
+	then = jiffies;
+
+	while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
+		if (jiffies - then > api_timeout) {
+			IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
+			/* reset the mailbox, but it is likely too late already */
+			write_sync(0, &mbox->flags);
+			clear_bit(mb, &mbdata->busy);
+			return -EIO;
+		}
+		if (flags & API_NO_WAIT_RES)
+			mdelay(1);
+		else
+			ivtv_sleep_timeout(HZ / 100, 0);
+	}
+	if (jiffies - then > HZ / 10)
+		IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
+				api_info[cmd].name, jiffies - then, HZ);
+
+	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
+		data[i] = readl(&mbox->data[i]);
+	write_sync(0, &mbox->flags);
+	clear_bit(mb, &mbdata->busy);
+	return 0;
+}
+
+int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
+{
+	int res = ivtv_api_call(itv, cmd, args, data);
+
+	/* Allow a single retry, probably already too late though.
+	   If there is no free mailbox then that is usually an indication
+	   of a more serious problem. */
+	return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
+}
+
+int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+	return ivtv_api(priv, cmd, in, data);
+}
+
+int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...)
+{
+	va_list ap;
+	int i;
+
+	va_start(ap, args);
+	for (i = 0; i < args; i++) {
+		data[i] = va_arg(ap, u32);
+	}
+	va_end(ap);
+	return ivtv_api(itv, cmd, args, data);
+}
+
+int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	va_list ap;
+	int i;
+
+	va_start(ap, args);
+	for (i = 0; i < args; i++) {
+		data[i] = va_arg(ap, u32);
+	}
+	va_end(ap);
+	return ivtv_api(itv, cmd, args, data);
+}
+
+/* This one is for stuff that can't sleep.. irq handlers, etc.. */
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, u32 data[])
+{
+	int i;
+
+	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
+		data[i] = readl(&mbdata->mbox[mb].data[i]);
+}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
new file mode 100644
index 0000000..79b8aec
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -0,0 +1,25 @@
+/*
+    mailbox functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
+int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
+int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
+int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
+int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
new file mode 100644
index 0000000..ccfcef1
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -0,0 +1,262 @@
+/*
+    buffer queues.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-streams.h"
+#include "ivtv-queue.h"
+#include "ivtv-mailbox.h"
+
+int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
+{
+	if (s->buf_size - buf->bytesused < copybytes)
+		copybytes = s->buf_size - buf->bytesused;
+	if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) {
+		return -EFAULT;
+	}
+	buf->bytesused += copybytes;
+	return copybytes;
+}
+
+void ivtv_buf_swap(struct ivtv_buffer *buf)
+{
+	int i;
+
+	for (i = 0; i < buf->bytesused; i += 4)
+		swab32s((u32 *)(buf->buf + i));
+}
+
+void ivtv_queue_init(struct ivtv_queue *q)
+{
+	INIT_LIST_HEAD(&q->list);
+	q->buffers = 0;
+	q->length = 0;
+	q->bytesused = 0;
+}
+
+void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
+{
+	unsigned long flags = 0;
+
+	/* clear the buffer if it is going to be enqueued to the free queue */
+	if (q == &s->q_free) {
+		buf->bytesused = 0;
+		buf->readpos = 0;
+		buf->b_flags = 0;
+	}
+	spin_lock_irqsave(&s->qlock, flags);
+	list_add_tail(&buf->list, &q->list);
+	q->buffers++;
+	q->length += s->buf_size;
+	q->bytesused += buf->bytesused - buf->readpos;
+	spin_unlock_irqrestore(&s->qlock, flags);
+}
+
+struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
+{
+	struct ivtv_buffer *buf = NULL;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&s->qlock, flags);
+	if (!list_empty(&q->list)) {
+		buf = list_entry(q->list.next, struct ivtv_buffer, list);
+		list_del_init(q->list.next);
+		q->buffers--;
+		q->length -= s->buf_size;
+		q->bytesused -= buf->bytesused - buf->readpos;
+	}
+	spin_unlock_irqrestore(&s->qlock, flags);
+	return buf;
+}
+
+static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
+		struct ivtv_queue *to, int clear, int full)
+{
+	struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
+
+	list_move_tail(from->list.next, &to->list);
+	from->buffers--;
+	from->length -= s->buf_size;
+	from->bytesused -= buf->bytesused - buf->readpos;
+	/* special handling for q_free */
+	if (clear)
+		buf->bytesused = buf->readpos = buf->b_flags = 0;
+	else if (full) {
+		/* special handling for stolen buffers, assume
+		   all bytes are used. */
+		buf->bytesused = s->buf_size;
+		buf->readpos = buf->b_flags = 0;
+	}
+	to->buffers++;
+	to->length += s->buf_size;
+	to->bytesused += buf->bytesused - buf->readpos;
+}
+
+/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
+   If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
+   If 'steal' != NULL, then buffers may also taken from that queue if
+   needed.
+
+   The buffer is automatically cleared if it goes to the free queue. It is
+   also cleared if buffers need to be taken from the 'steal' queue and
+   the 'from' queue is the free queue.
+
+   When 'from' is q_free, then needed_bytes is compared to the total
+   available buffer length, otherwise needed_bytes is compared to the
+   bytesused value. For the 'steal' queue the total available buffer
+   length is always used.
+
+   -ENOMEM is returned if the buffers could not be obtained, 0 if all
+   buffers where obtained from the 'from' list and if non-zero then
+   the number of stolen buffers is returned. */
+int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
+		    struct ivtv_queue *to, int needed_bytes)
+{
+	unsigned long flags;
+	int rc = 0;
+	int from_free = from == &s->q_free;
+	int to_free = to == &s->q_free;
+	int bytes_available;
+
+	spin_lock_irqsave(&s->qlock, flags);
+	if (needed_bytes == 0) {
+		from_free = 1;
+		needed_bytes = from->length;
+	}
+
+	bytes_available = from_free ? from->length : from->bytesused;
+	bytes_available += steal ? steal->length : 0;
+
+	if (bytes_available < needed_bytes) {
+		spin_unlock_irqrestore(&s->qlock, flags);
+		return -ENOMEM;
+	}
+	if (from_free) {
+		u32 old_length = to->length;
+
+		while (to->length - old_length < needed_bytes) {
+			if (list_empty(&from->list))
+				from = steal;
+			if (from == steal)
+				rc++; 		/* keep track of 'stolen' buffers */
+			ivtv_queue_move_buf(s, from, to, 1, 0);
+		}
+	}
+	else {
+		u32 old_bytesused = to->bytesused;
+
+		while (to->bytesused - old_bytesused < needed_bytes) {
+			if (list_empty(&from->list))
+				from = steal;
+			if (from == steal)
+				rc++; 		/* keep track of 'stolen' buffers */
+			ivtv_queue_move_buf(s, from, to, to_free, rc);
+		}
+	}
+	spin_unlock_irqrestore(&s->qlock, flags);
+	return rc;
+}
+
+void ivtv_flush_queues(struct ivtv_stream *s)
+{
+	ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
+	ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
+}
+
+int ivtv_stream_alloc(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+	int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
+	int i;
+
+	if (s->buffers == 0)
+		return 0;
+
+	IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n",
+		s->dma != PCI_DMA_NONE ? "DMA " : "",
+		s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
+
+	/* Allocate DMA SG Arrays */
+	if (s->dma != PCI_DMA_NONE) {
+		s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
+		if (s->SGarray == NULL) {
+			IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
+			return -ENOMEM;
+		}
+		s->SG_length = 0;
+		s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
+		ivtv_stream_sync_for_cpu(s);
+	}
+
+	/* allocate stream buffers. Initially all buffers are in q_free. */
+	for (i = 0; i < s->buffers; i++) {
+		struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL);
+
+		if (buf == NULL)
+			break;
+		buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL);
+		if (buf->buf == NULL) {
+			kfree(buf);
+			break;
+		}
+		INIT_LIST_HEAD(&buf->list);
+		if (s->dma != PCI_DMA_NONE) {
+			buf->dma_handle = pci_map_single(s->itv->dev,
+				buf->buf, s->buf_size + 256, s->dma);
+			ivtv_buf_sync_for_cpu(s, buf);
+		}
+		ivtv_enqueue(s, buf, &s->q_free);
+	}
+	if (i == s->buffers)
+		return 0;
+	IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+	ivtv_stream_free(s);
+	return -ENOMEM;
+}
+
+void ivtv_stream_free(struct ivtv_stream *s)
+{
+	struct ivtv_buffer *buf;
+
+	/* move all buffers to q_free */
+	ivtv_flush_queues(s);
+
+	/* empty q_free */
+	while ((buf = ivtv_dequeue(s, &s->q_free))) {
+		if (s->dma != PCI_DMA_NONE)
+			pci_unmap_single(s->itv->dev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+		kfree(buf->buf);
+		kfree(buf);
+	}
+
+	/* Free SG Array/Lists */
+	if (s->SGarray != NULL) {
+		if (s->SG_handle != IVTV_DMA_UNMAPPED) {
+			pci_unmap_single(s->itv->dev, s->SG_handle,
+				 sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+			s->SG_handle = IVTV_DMA_UNMAPPED;
+		}
+		s->SGarray = NULL;
+		s->SG_length = 0;
+	}
+}
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
new file mode 100644
index 0000000..903edd4
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -0,0 +1,64 @@
+/*
+    buffer queues.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 IVTV_DMA_UNMAPPED	((u32) -1)
+
+/* ivtv_buffer utility functions */
+static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf)
+{
+	if (s->dma != PCI_DMA_NONE)
+		pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+}
+
+static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf)
+{
+	if (s->dma != PCI_DMA_NONE)
+		pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle,
+				s->buf_size + 256, s->dma);
+}
+
+int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes);
+void ivtv_buf_swap(struct ivtv_buffer *buf);
+
+/* ivtv_queue utility functions */
+void ivtv_queue_init(struct ivtv_queue *q);
+void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q);
+struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q);
+int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal,
+		    struct ivtv_queue *to, int needed_bytes);
+void ivtv_flush_queues(struct ivtv_stream *s);
+
+/* ivtv_stream utility functions */
+int ivtv_stream_alloc(struct ivtv_stream *s);
+void ivtv_stream_free(struct ivtv_stream *s);
+
+static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
+{
+	pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle,
+		sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+}
+
+static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
+{
+	pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle,
+		sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
new file mode 100644
index 0000000..01a41a8
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -0,0 +1,977 @@
+/*
+    init/start/stop/exit stream functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* License: GPL
+ * Author: Kevin Thayer <nufan_wfk at yahoo dot com>
+ *
+ * This file will hold API related functions, both internal (firmware api)
+ * and external (v4l2, etc)
+ *
+ * -----
+ * MPG600/MPG160 support by  T.Adachi <tadachi@tadachi-net.com>
+ *                      and Takeru KOMORIYA<komoriya@paken.org>
+ *
+ * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org>
+ *                using information provided by Jiun-Kuei Jung @ AVerMedia.
+ */
+
+#include "ivtv-driver.h"
+#include "ivtv-fileops.h"
+#include "ivtv-i2c.h"
+#include "ivtv-queue.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-audio.h"
+#include "ivtv-video.h"
+#include "ivtv-vbi.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-irq.h"
+#include "ivtv-streams.h"
+#include "ivtv-cards.h"
+
+static struct file_operations ivtv_v4l2_enc_fops = {
+      .owner = THIS_MODULE,
+      .read = ivtv_v4l2_read,
+      .write = ivtv_v4l2_write,
+      .open = ivtv_v4l2_open,
+      .ioctl = ivtv_v4l2_ioctl,
+      .release = ivtv_v4l2_close,
+      .poll = ivtv_v4l2_enc_poll,
+};
+
+static struct file_operations ivtv_v4l2_dec_fops = {
+      .owner = THIS_MODULE,
+      .read = ivtv_v4l2_read,
+      .write = ivtv_v4l2_write,
+      .open = ivtv_v4l2_open,
+      .ioctl = ivtv_v4l2_ioctl,
+      .release = ivtv_v4l2_close,
+      .poll = ivtv_v4l2_dec_poll,
+};
+
+static struct {
+	const char *name;
+	int vfl_type;
+	int minor_offset;
+	int dma, pio;
+	enum v4l2_buf_type buf_type;
+	struct file_operations *fops;
+} ivtv_stream_info[] = {
+	{	/* IVTV_ENC_STREAM_TYPE_MPG */
+		"encoder MPEG",
+		VFL_TYPE_GRABBER, 0,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_YUV */
+		"encoder YUV",
+		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_VBI */
+		"encoder VBI",
+		VFL_TYPE_VBI, 0,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_PCM */
+		"encoder PCM audio",
+		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
+		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_ENC_STREAM_TYPE_RAD */
+		"encoder radio",
+		VFL_TYPE_RADIO, 0,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_MPG */
+		"decoder MPEG",
+		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
+		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		&ivtv_v4l2_dec_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_VBI */
+		"decoder VBI",
+		VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE,
+		&ivtv_v4l2_enc_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_VOUT */
+		"decoder VOUT",
+		VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET,
+		PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT,
+		&ivtv_v4l2_dec_fops
+	},
+	{	/* IVTV_DEC_STREAM_TYPE_YUV */
+		"decoder YUV",
+		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
+		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+		&ivtv_v4l2_dec_fops
+	}
+};
+
+static void ivtv_stream_init(struct ivtv *itv, int type)
+{
+	struct ivtv_stream *s = &itv->streams[type];
+	struct video_device *dev = s->v4l2dev;
+
+	/* we need to keep v4l2dev, so restore it afterwards */
+	memset(s, 0, sizeof(*s));
+	s->v4l2dev = dev;
+
+	/* initialize ivtv_stream fields */
+	s->itv = itv;
+	s->type = type;
+	s->name = ivtv_stream_info[type].name;
+
+	if (ivtv_stream_info[type].pio)
+		s->dma = PCI_DMA_NONE;
+	else
+		s->dma = ivtv_stream_info[type].dma;
+	s->buf_size = itv->stream_buf_size[type];
+	if (s->buf_size)
+		s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size;
+	spin_lock_init(&s->qlock);
+	init_waitqueue_head(&s->waitq);
+	s->id = -1;
+	s->SG_handle = IVTV_DMA_UNMAPPED;
+	ivtv_queue_init(&s->q_free);
+	ivtv_queue_init(&s->q_full);
+	ivtv_queue_init(&s->q_dma);
+	ivtv_queue_init(&s->q_predma);
+	ivtv_queue_init(&s->q_io);
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+	struct ivtv_stream *s = &itv->streams[type];
+	int vfl_type = ivtv_stream_info[type].vfl_type;
+	int minor_offset = ivtv_stream_info[type].minor_offset;
+	int minor;
+
+	/* These four fields are always initialized. If v4l2dev == NULL, then
+	   this stream is not in use. In that case no other fields but these
+	   four can be used. */
+	s->v4l2dev = NULL;
+	s->itv = itv;
+	s->type = type;
+	s->name = ivtv_stream_info[type].name;
+
+	/* Check whether the radio is supported */
+	if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO))
+		return 0;
+	if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return 0;
+
+	if (minor_offset >= 0)
+		/* card number + user defined offset + device offset */
+		minor = itv->num + ivtv_first_minor + minor_offset;
+	else
+		minor = -1;
+
+	/* User explicitly selected 0 buffers for these streams, so don't
+	   create them. */
+	if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+	    itv->options.megabytes[type] == 0) {
+		IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
+		return 0;
+	}
+
+	ivtv_stream_init(itv, type);
+
+	/* allocate and initialize the v4l2 video device structure */
+	s->v4l2dev = video_device_alloc();
+	if (s->v4l2dev == NULL) {
+		IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name);
+		return -ENOMEM;
+	}
+
+	s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
+		    VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		s->v4l2dev->type |= VID_TYPE_MPEG_DECODER;
+	}
+	snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
+			itv->num, s->name);
+
+	s->v4l2dev->minor = minor;
+	s->v4l2dev->dev = &itv->dev->dev;
+	s->v4l2dev->fops = ivtv_stream_info[type].fops;
+	s->v4l2dev->release = video_device_release;
+
+	if (minor >= 0) {
+		/* Register device. First try the desired minor, then any free one. */
+		if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+		    video_register_device(s->v4l2dev, vfl_type, -1)) {
+			IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
+					s->name, minor);
+			video_device_release(s->v4l2dev);
+			s->v4l2dev = NULL;
+			return -ENOMEM;
+		}
+	}
+	else {
+		/* Don't register a 'hidden' stream (OSD) */
+		IVTV_INFO("Created framebuffer stream for %s\n", s->name);
+		return 0;
+	}
+
+	switch (vfl_type) {
+	case VFL_TYPE_GRABBER:
+		IVTV_INFO("Registered device video%d for %s (%d MB)\n",
+			s->v4l2dev->minor, s->name, itv->options.megabytes[type]);
+		break;
+	case VFL_TYPE_RADIO:
+		IVTV_INFO("Registered device radio%d for %s\n",
+			s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+		break;
+	case VFL_TYPE_VBI:
+		if (itv->options.megabytes[type])
+			IVTV_INFO("Registered device vbi%d for %s (%d MB)\n",
+				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
+				s->name, itv->options.megabytes[type]);
+		else
+			IVTV_INFO("Registered device vbi%d for %s\n",
+				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+		break;
+	}
+	return 0;
+}
+
+/* Initialize v4l2 variables and register v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+	int type;
+
+	/* Setup V4L2 Devices */
+	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+		/* Register Device */
+		if (ivtv_reg_dev(itv, type))
+			break;
+
+		if (itv->streams[type].v4l2dev == NULL)
+			continue;
+
+		/* Allocate Stream */
+		if (ivtv_stream_alloc(&itv->streams[type]))
+			break;
+	}
+	if (type == IVTV_MAX_STREAMS) {
+		return 0;
+	}
+
+	/* One or more streams could not be initialized. Clean 'em all up. */
+	ivtv_streams_cleanup(itv);
+	return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void ivtv_streams_cleanup(struct ivtv *itv)
+{
+	int type;
+
+	/* Teardown all streams */
+	for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+		struct video_device *vdev = itv->streams[type].v4l2dev;
+
+		itv->streams[type].v4l2dev = NULL;
+		if (vdev == NULL)
+			continue;
+
+		ivtv_stream_free(&itv->streams[type]);
+		/* Free Device */
+		if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */
+			video_device_release(vdev);
+		else    /* All others, just unregister. */
+			video_unregister_device(vdev);
+	}
+}
+
+static void ivtv_vbi_setup(struct ivtv *itv)
+{
+	int raw = itv->vbi.sliced_in->service_set == 0;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int lines;
+	int i;
+
+	/* If Embed then streamtype must be Program */
+	/* TODO: should we really do this? */
+	if (0 && !raw && itv->vbi.insert_mpeg) {
+		itv->params.stream_type = 0;
+
+		/* assign stream type */
+		ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type);
+	}
+
+	/* Reset VBI */
+	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
+
+	if (itv->is_60hz) {
+		itv->vbi.count = 12;
+		itv->vbi.start[0] = 10;
+		itv->vbi.start[1] = 273;
+	} else {        /* PAL/SECAM */
+		itv->vbi.count = 18;
+		itv->vbi.start[0] = 6;
+		itv->vbi.start[1] = 318;
+	}
+
+	/* setup VBI registers */
+	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+
+	/* determine number of lines and total number of VBI bytes.
+	   A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+	   The '- 1' byte is probably an unused U or V byte. Or something...
+	   A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+	   header, 42 data bytes + checksum (to be confirmed) */
+	if (raw) {
+		lines = itv->vbi.count * 2;
+	} else {
+		lines = itv->is_60hz ? 24 : 38;
+		if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840))
+			lines += 2;
+	}
+
+	itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+
+	/* Note: sliced vs raw flag doesn't seem to have any effect
+	   TODO: check mode (0x02) value with older ivtv versions. */
+	data[0] = raw | 0x02 | (0xbd << 8);
+
+	/* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */
+	data[1] = 1;
+	/* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */
+	data[2] = raw ? 4 : 8;
+	/* The start/stop codes determine which VBI lines end up in the raw VBI data area.
+	   The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line
+	   is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video)
+	   code. These values for raw VBI are obtained from a driver disassembly. The sliced
+	   start/stop codes was deduced from this, but they do not appear in the driver.
+	   Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54.
+	   However, I have no idea what these values are for. */
+	if (itv->hw_flags & IVTV_HW_CX25840) {
+		/* Setup VBI for the cx25840 digitizer */
+		if (raw) {
+			data[3] = 0x20602060;
+			data[4] = 0x30703070;
+		} else {
+			data[3] = 0xB0F0B0F0;
+			data[4] = 0xA0E0A0E0;
+		}
+		/* Lines per frame */
+		data[5] = lines;
+		/* bytes per line */
+		data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size);
+	} else {
+		/* Setup VBI for the saa7115 digitizer */
+		if (raw) {
+			data[3] = 0x25256262;
+			data[4] = 0x387F7F7F;
+		} else {
+			data[3] = 0xABABECEC;
+			data[4] = 0xB6F1F1F1;
+		}
+		/* Lines per frame */
+		data[5] = lines;
+		/* bytes per line */
+		data[6] = itv->vbi.enc_size / lines;
+	}
+
+	IVTV_DEBUG_INFO(
+		"Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n",
+			data[0], data[1], data[2], data[5], data[6]);
+
+	ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data);
+
+	/* returns the VBI encoder memory area. */
+	itv->vbi.enc_start = data[2];
+	itv->vbi.fpi = data[0];
+	if (!itv->vbi.fpi)
+		itv->vbi.fpi = 1;
+
+	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n",
+		itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer);
+
+	/* select VBI lines.
+	   Note that the sliced argument seems to have no effect. */
+	for (i = 2; i <= 24; i++) {
+		int valid;
+
+		if (itv->is_60hz) {
+			valid = i >= 10 && i < 22;
+		} else {
+			valid = i >= 6 && i < 24;
+		}
+		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1,
+				valid, 0 , 0, 0);
+		ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000,
+				valid, 0, 0, 0);
+	}
+
+	/* Remaining VBI questions:
+	   - Is it possible to select particular VBI lines only for inclusion in the MPEG
+	   stream? Currently you can only get the first X lines.
+	   - Is mixed raw and sliced VBI possible?
+	   - What's the meaning of the raw/sliced flag?
+	   - What's the meaning of params 2, 3 & 4 of the Select VBI command? */
+}
+
+int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv *itv = s->itv;
+	int captype = 0, subtype = 0;
+	int enable_passthrough = 0;
+
+	if (s->v4l2dev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+	switch (s->type) {
+	case IVTV_ENC_STREAM_TYPE_MPG:
+		captype = 0;
+		subtype = 3;
+
+		/* Stop Passthrough */
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			ivtv_passthrough_mode(itv, 0);
+			enable_passthrough = 1;
+		}
+		itv->mpg_data_received = itv->vbi_data_inserted = 0;
+		itv->dualwatch_jiffies = jiffies;
+		itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300;
+		itv->search_pack_header = 0;
+		break;
+
+	case IVTV_ENC_STREAM_TYPE_YUV:
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			captype = 2;
+			subtype = 11;	/* video+audio+decoder */
+			break;
+		}
+		captype = 1;
+		subtype = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_PCM:
+		captype = 1;
+		subtype = 2;
+		break;
+	case IVTV_ENC_STREAM_TYPE_VBI:
+		captype = 1;
+		subtype = 4;
+
+		itv->vbi.frame = 0;
+		itv->vbi.inserted_frame = 0;
+		memset(itv->vbi.sliced_mpeg_size,
+			0, sizeof(itv->vbi.sliced_mpeg_size));
+		break;
+	default:
+		return -EINVAL;
+	}
+	s->subtype = subtype;
+	s->buffers_stolen = 0;
+
+	/* mute/unmute video */
+	ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0);
+
+	/* Clear Streamoff flags in case left from last capture */
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	if (atomic_read(&itv->capturing) == 0) {
+		/* Always use frame based mode. Experiments have demonstrated that byte
+		   stream based mode results in dropped frames and corruption. Not often,
+		   but occasionally. Many thanks go to Leonard Orb who spent a lot of
+		   effort and time trying to trace the cause of the drop outs. */
+		/* 1 frame per DMA */
+		/*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
+		ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
+
+		/* Stuff from Windows, we don't know what it is */
+		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0);
+		/* According to the docs, this should be correct. However, this is
+		   untested. I don't dare enable this without having tested it.
+		   Only very few old cards actually have this hardware combination.
+		ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1,
+			((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0);
+		*/
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
+		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
+
+		/* assign placeholder */
+		ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+		ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer);
+
+		/* Setup VBI */
+		if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
+			ivtv_vbi_setup(itv);
+		}
+
+		/* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */
+		ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400);
+		itv->pgm_info_offset = data[0];
+		itv->pgm_info_num = data[1];
+		itv->pgm_info_write_idx = 0;
+		itv->pgm_info_read_idx = 0;
+
+		IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n",
+				itv->pgm_info_offset, itv->pgm_info_num);
+
+		/* Setup API for Stream */
+		cx2341x_update(itv, ivtv_api_func, NULL, &itv->params);
+	}
+
+	/* Vsync Setup */
+	if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+		/* event notification (on) */
+		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1);
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+	}
+
+	if (atomic_read(&itv->capturing) == 0) {
+		/* Clear all Pending Interrupts */
+		ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+
+		/* Initialize Digitizer for Capture */
+		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+		ivtv_sleep_timeout(HZ / 10, 0);
+	}
+
+	/* begin_capture */
+	if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
+	{
+		IVTV_DEBUG_WARN( "Error starting capture!\n");
+		return -EINVAL;
+	}
+
+	/* Start Passthrough */
+	if (enable_passthrough) {
+		ivtv_passthrough_mode(itv, 1);
+	}
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+	else
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+	/* you're live! sit back and await interrupts :) */
+	atomic_inc(&itv->capturing);
+	return 0;
+}
+
+static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	struct ivtv *itv = s->itv;
+	int datatype;
+
+	if (s->v4l2dev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+
+	/* disable VBI signals, if the MPEG stream contains VBI data,
+	   then that data will be processed automatically for you. */
+	ivtv_disable_vbi(itv);
+
+	/* set audio mode to left/stereo  for dual/stereo mode. */
+	ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
+
+	/* set number of internal decoder buffers */
+	ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
+
+	/* prebuffering */
+	ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1);
+
+	/* extract from user packets */
+	ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1);
+	itv->vbi.dec_start = data[0];
+
+	IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n",
+		itv->vbi.dec_start, data[1]);
+
+	/* set decoder source settings */
+	/* Data type: 0 = mpeg from host,
+	   1 = yuv from encoder,
+	   2 = yuv_from_host */
+	switch (s->type) {
+	case IVTV_DEC_STREAM_TYPE_YUV:
+		datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2;
+		IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
+		break;
+	case IVTV_DEC_STREAM_TYPE_MPG:
+	default:
+		datatype = 0;
+		break;
+	}
+	if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
+			itv->params.width, itv->params.height, itv->params.audio_properties)) {
+		IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n");
+	}
+	return 0;
+}
+
+int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
+{
+	struct ivtv *itv = s->itv;
+
+	if (s->v4l2dev == NULL)
+		return -EINVAL;
+
+	if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags))
+		return 0;	/* already started */
+
+	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
+
+	/* Clear Streamoff */
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		/* Initialize Decoder */
+		/* Reprogram Decoder YUV Buffers for YUV */
+		write_reg(yuv_offset[0] >> 4, 0x82c);
+		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+		write_reg(yuv_offset[0] >> 4, 0x834);
+		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+
+		write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
+
+		write_reg_sync(0x00108080, 0x2898);
+		/* Enable YUV decoder output */
+		write_reg_sync(0x01, IVTV_REG_VDM);
+	}
+
+	ivtv_setup_v4l2_decode_stream(s);
+
+	/* set dma size to 65536 bytes */
+	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
+
+	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+
+	/* Zero out decoder counters */
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]);
+
+	/* turn on notification of dual/stereo mode change */
+	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
+
+	/* start playback */
+	ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
+
+	/* Clear the following Interrupt mask bits for decoding */
+	ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+	IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
+
+	/* you're live! sit back and await interrupts :) */
+	atomic_inc(&itv->decoding);
+	return 0;
+}
+
+void ivtv_stop_all_captures(struct ivtv *itv)
+{
+	int i;
+
+	for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) {
+		struct ivtv_stream *s = &itv->streams[i];
+
+		if (s->v4l2dev == NULL)
+			continue;
+		if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+			ivtv_stop_v4l2_encode_stream(s, 0);
+		}
+	}
+}
+
+int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
+{
+	struct ivtv *itv = s->itv;
+	DECLARE_WAITQUEUE(wait, current);
+	int cap_type;
+	unsigned long then;
+	int stopmode;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	if (s->v4l2dev == NULL)
+		return -EINVAL;
+
+	/* This function assumes that you are allowed to stop the capture
+	   and that we are actually capturing */
+
+	IVTV_DEBUG_INFO("Stop Capture\n");
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT)
+		return 0;
+	if (atomic_read(&itv->capturing) == 0)
+		return 0;
+
+	switch (s->type) {
+	case IVTV_ENC_STREAM_TYPE_YUV:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_PCM:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_VBI:
+		cap_type = 1;
+		break;
+	case IVTV_ENC_STREAM_TYPE_MPG:
+	default:
+		cap_type = 0;
+		break;
+	}
+
+	/* Stop Capture Mode */
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+		stopmode = 0;
+	} else {
+		stopmode = 1;
+	}
+
+	/* end_capture */
+	/* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
+
+	/* only run these if we're shutting down the last cap */
+	if (atomic_read(&itv->capturing) - 1 == 0) {
+		/* event notification (off) */
+		if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+			/* type: 0 = refresh */
+			/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+			ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+			ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+		}
+	}
+
+	then = jiffies;
+
+	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
+		if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
+			/* only run these if we're shutting down the last cap */
+			unsigned long duration;
+
+			then = jiffies;
+			add_wait_queue(&itv->cap_w, &wait);
+
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			/* wait 2s for EOS interrupt */
+			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
+				schedule_timeout(HZ / 100);
+			}
+
+			/* To convert jiffies to ms, we must multiply by 1000
+			 * and divide by HZ.  To avoid runtime division, we
+			 * convert this to multiplication by 1000/HZ.
+			 * Since integer division truncates, we get the best
+			 * accuracy if we do a rounding calculation of the constant.
+			 * Think of the case where HZ is 1024.
+			 */
+			duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
+
+			if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
+				IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
+				IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
+			} else {
+				IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
+			}
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&itv->cap_w, &wait);
+		}
+
+		then = jiffies;
+		/* Make sure DMA is complete */
+		add_wait_queue(&s->waitq, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		do {
+			/* check if DMA is pending */
+			if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) &&	/* MPG Only */
+			    (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
+				/* Check for last DMA */
+				ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
+
+				if (data[0] == 1) {
+					IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
+					break;
+				}
+			} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
+				break;
+			}
+
+			ivtv_sleep_timeout(HZ / 100, 1);
+		} while (then + HZ * 2 > jiffies);
+
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&s->waitq, &wait);
+	}
+
+	atomic_dec(&itv->capturing);
+
+	/* Clear capture and no-read bits */
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+
+	if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
+
+	if (atomic_read(&itv->capturing) > 0) {
+		return 0;
+	}
+
+	/* Set the following Interrupt mask bits for capture */
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+
+	wake_up(&s->waitq);
+
+	return 0;
+}
+
+int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
+{
+	struct ivtv *itv = s->itv;
+
+	if (s->v4l2dev == NULL)
+		return -EINVAL;
+
+	if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG)
+		return -EINVAL;
+
+	if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags))
+		return 0;
+
+	IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", pts, flags);
+
+	/* Stop Decoder */
+	if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) {
+		u32 tmp = 0;
+
+		/* Wait until the decoder is no longer running */
+		if (pts) {
+			ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3,
+				0, (u32)(pts & 0xffffffff), (u32)(pts >> 32));
+		}
+		while (1) {
+			u32 data[CX2341X_MBOX_MAX_DATA];
+			ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0);
+			if (s->q_full.buffers + s->q_dma.buffers == 0) {
+				if (tmp == data[3])
+					break;
+				tmp = data[3];
+			}
+			if (ivtv_sleep_timeout(HZ/10, 1))
+				break;
+		}
+	}
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0);
+
+	/* turn off notification of dual/stereo mode change */
+	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
+
+	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+
+	clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
+	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+	ivtv_flush_queues(s);
+
+	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
+		/* disable VBI on TV-out */
+		ivtv_disable_vbi(itv);
+	}
+
+	/* decrement decoding */
+	atomic_dec(&itv->decoding);
+
+	set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags);
+	wake_up(&itv->event_waitq);
+
+	/* wake up wait queues */
+	wake_up(&s->waitq);
+
+	return 0;
+}
+
+int ivtv_passthrough_mode(struct ivtv *itv, int enable)
+{
+	struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV];
+	struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
+
+	if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL)
+		return -EINVAL;
+
+	IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n");
+
+	/* Prevent others from starting/stopping streams while we
+	   initiate/terminate passthrough mode */
+	if (enable) {
+		if (itv->output_mode == OUT_PASSTHROUGH) {
+			return 0;
+		}
+		if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH)
+			return -EBUSY;
+
+		/* Fully initialize stream, and then unflag init */
+		set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+		set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+
+		/* Setup YUV Decoder */
+		ivtv_setup_v4l2_decode_stream(dec_stream);
+
+		/* Start Decoder */
+		ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1);
+		atomic_inc(&itv->decoding);
+
+		/* Setup capture if not already done */
+		if (atomic_read(&itv->capturing) == 0) {
+			cx2341x_update(itv, ivtv_api_func, NULL, &itv->params);
+		}
+
+		/* Start Passthrough Mode */
+		ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11);
+		atomic_inc(&itv->capturing);
+		return 0;
+	}
+
+	if (itv->output_mode != OUT_PASSTHROUGH)
+		return 0;
+
+	/* Stop Passthrough Mode */
+	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11);
+	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0);
+
+	atomic_dec(&itv->capturing);
+	atomic_dec(&itv->decoding);
+	clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
+	clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
+	itv->output_mode = OUT_NONE;
+
+	return 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
new file mode 100644
index 0000000..8597b75
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -0,0 +1,31 @@
+/*
+    init/start/stop/exit stream functions
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+int ivtv_streams_setup(struct ivtv *itv);
+void ivtv_streams_cleanup(struct ivtv *itv);
+
+/* Capture related */
+int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s);
+int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end);
+int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset);
+int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts);
+
+void ivtv_stop_all_captures(struct ivtv *itv);
+int ivtv_passthrough_mode(struct ivtv *itv, int enable);
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
new file mode 100644
index 0000000..bd642e1
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -0,0 +1,200 @@
+/*
+    User DMA
+
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-streams.h"
+#include "ivtv-udma.h"
+
+void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size)
+{
+	dma_page->uaddr = first & PAGE_MASK;
+	dma_page->offset = first & ~PAGE_MASK;
+	dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK);
+	dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT;
+	dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+	dma_page->page_count = dma_page->last - dma_page->first + 1;
+	if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset;
+}
+
+int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
+{
+	int i, offset;
+
+	offset = dma_page->offset;
+
+	/* Fill SG Array with new values */
+	for (i = 0; i < dma_page->page_count; i++) {
+		if (i == dma_page->page_count - 1) {
+			dma->SGlist[map_offset].length = dma_page->tail;
+		}
+		else {
+			dma->SGlist[map_offset].length = PAGE_SIZE - offset;
+		}
+		dma->SGlist[map_offset].offset = offset;
+		dma->SGlist[map_offset].page = dma->map[map_offset];
+		offset = 0;
+		map_offset++;
+	}
+	return map_offset;
+}
+
+void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) {
+	int i;
+	struct scatterlist *sg;
+
+	for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) {
+		dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg));
+		dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg));
+		dma->SGarray[i].dst = cpu_to_le32(buffer_offset);
+		buffer_offset += sg_dma_len(sg);
+
+		split -= sg_dma_len(sg);
+		if (split == 0)
+			buffer_offset = buffer_offset_2;
+	}
+}
+
+/* User DMA Buffers */
+void ivtv_udma_alloc(struct ivtv *itv)
+{
+	if (itv->udma.SG_handle == 0) {
+		/* Map DMA Page Array Buffer */
+		itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray,
+			   sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+		ivtv_udma_sync_for_cpu(itv);
+	}
+}
+
+int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
+		       void __user *userbuf, int size_in_bytes)
+{
+	struct ivtv_dma_page_info user_dma;
+	struct ivtv_user_dma *dma = &itv->udma;
+	int err;
+
+	IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
+
+	/* Still in USE */
+	if (dma->SG_length || dma->page_count) {
+		IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n",
+			   dma->SG_length, dma->page_count);
+		return -EBUSY;
+	}
+
+	ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes);
+
+	if (user_dma.page_count <= 0) {
+		IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n",
+			   user_dma.page_count, size_in_bytes, user_dma.offset);
+		return -EINVAL;
+	}
+
+	/* Get user pages for DMA Xfer */
+	down_read(&current->mm->mmap_sem);
+	err = get_user_pages(current, current->mm,
+			user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL);
+	up_read(&current->mm->mmap_sem);
+
+	if (user_dma.page_count != err) {
+		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
+			   err, user_dma.page_count);
+		return -EINVAL;
+	}
+
+	dma->page_count = user_dma.page_count;
+
+	/* Fill SG List with new values */
+	ivtv_udma_fill_sg_list(dma, &user_dma, 0);
+
+	/* Map SG List */
+	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+	/* Fill SG Array with new values */
+	ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
+
+	/* Tag SG Array with Interrupt Bit */
+	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	ivtv_udma_sync_for_device(itv);
+	return dma->page_count;
+}
+
+void ivtv_udma_unmap(struct ivtv *itv)
+{
+	struct ivtv_user_dma *dma = &itv->udma;
+	int i;
+
+	IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n");
+
+	/* Nothing to free */
+	if (dma->page_count == 0)
+		return;
+
+	/* Unmap Scatterlist */
+	if (dma->SG_length) {
+		pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+		dma->SG_length = 0;
+	}
+	/* sync DMA */
+	ivtv_udma_sync_for_cpu(itv);
+
+	/* Release User Pages */
+	for (i = 0; i < dma->page_count; i++) {
+		put_page(dma->map[i]);
+	}
+	dma->page_count = 0;
+}
+
+void ivtv_udma_free(struct ivtv *itv)
+{
+	/* Unmap SG Array */
+	if (itv->udma.SG_handle) {
+		pci_unmap_single(itv->dev, itv->udma.SG_handle,
+			 sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+	}
+
+	/* Unmap Scatterlist */
+	if (itv->udma.SG_length) {
+		pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
+	}
+}
+
+void ivtv_udma_start(struct ivtv *itv)
+{
+	IVTV_DEBUG_DMA("start UDMA\n");
+	write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	set_bit(IVTV_F_I_DMA, &itv->i_flags);
+	set_bit(IVTV_F_I_UDMA, &itv->i_flags);
+}
+
+void ivtv_udma_prepare(struct ivtv *itv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&itv->dma_reg_lock, flags);
+	if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+		ivtv_udma_start(itv);
+	else
+		set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags);
+	spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
+}
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h
new file mode 100644
index 0000000..e131bcc
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-udma.h
@@ -0,0 +1,43 @@
+/*
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+    Copyright (C) 2006-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+/* User DMA functions */
+void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size);
+int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset);
+void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split);
+int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
+		       void __user *userbuf, int size_in_bytes);
+void ivtv_udma_unmap(struct ivtv *itv);
+void ivtv_udma_free(struct ivtv *itv);
+void ivtv_udma_alloc(struct ivtv *itv);
+void ivtv_udma_prepare(struct ivtv *itv);
+void ivtv_udma_start(struct ivtv *itv);
+
+static inline void ivtv_udma_sync_for_device(struct ivtv *itv)
+{
+	pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+		sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+}
+
+static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
+{
+	pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
+		sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
+}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
new file mode 100644
index 0000000..5efa5a8
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -0,0 +1,538 @@
+/*
+    Vertical Blank Interval support functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-video.h"
+#include "ivtv-vbi.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-queue.h"
+
+static int odd_parity(u8 c)
+{
+	c ^= (c >> 4);
+	c ^= (c >> 2);
+	c ^= (c >> 1);
+
+	return c & 1;
+}
+
+static void passthrough_vbi_data(struct ivtv *itv, int cnt)
+{
+	int wss = 0;
+	u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
+	u8 vps[13];
+	int found_cc = 0;
+	int found_wss = 0;
+	int found_vps = 0;
+	int cc_pos = itv->vbi.cc_pos;
+	int i;
+
+	for (i = 0; i < cnt; i++) {
+		struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
+
+		if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
+			found_cc = 1;
+			if (d->field) {
+				cc[2] = d->data[0];
+				cc[3] = d->data[1];
+			} else {
+				cc[0] = d->data[0];
+				cc[1] = d->data[1];
+			}
+		}
+		else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
+			memcpy(vps, d->data, sizeof(vps));
+			found_vps = 1;
+		}
+		else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
+			wss = d->data[0] | d->data[1] << 8;
+			found_wss = 1;
+		}
+	}
+
+	if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
+		itv->vbi.wss = wss;
+		itv->vbi.wss_found = found_wss;
+		set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+	}
+
+	if (found_vps || itv->vbi.vps_found) {
+		itv->vbi.vps[0] = vps[2];
+		itv->vbi.vps[1] = vps[8];
+		itv->vbi.vps[2] = vps[9];
+		itv->vbi.vps[3] = vps[10];
+		itv->vbi.vps[4] = vps[11];
+		itv->vbi.vps_found = found_vps;
+		set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+	}
+
+	if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
+		itv->vbi.cc_data_odd[cc_pos] = cc[0];
+		itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
+		itv->vbi.cc_data_even[cc_pos] = cc[2];
+		itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
+		itv->vbi.cc_pos = cc_pos + 2;
+		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+	}
+}
+
+static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
+{
+	int line = 0;
+	int i;
+	u32 linemask[2] = { 0, 0 };
+	unsigned short size;
+	static const u8 mpeg_hdr_data[] = {
+		0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+		0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+		0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+		0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+	};
+	const int sd = sizeof(mpeg_hdr_data);	/* start of vbi data */
+	int idx = itv->vbi.frame % IVTV_VBI_FRAMES;
+	u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0];
+
+	for (i = 0; i < lines; i++) {
+		int f, l;
+
+		if (itv->vbi.sliced_data[i].id == 0)
+			continue;
+
+		l = itv->vbi.sliced_data[i].line - 6;
+		f = itv->vbi.sliced_data[i].field;
+		if (f)
+			l += 18;
+		if (l < 32)
+			linemask[0] |= (1 << l);
+		else
+			linemask[1] |= (1 << (l - 32));
+		dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id);
+		memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
+		line++;
+	}
+	memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+	if (line == 36) {
+		/* All lines are used, so there is no space for the linemask
+		   (the max size of the VBI data is 36 * 43 + 4 bytes).
+		   So in this case we use the magic number 'ITV0'. */
+		memcpy(dst + sd, "ITV0", 4);
+		memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+		size = 4 + ((43 * line + 3) & ~3);
+	} else {
+		memcpy(dst + sd, "itv0", 4);
+		memcpy(dst + sd + 4, &linemask[0], 8);
+		size = 12 + ((43 * line + 3) & ~3);
+	}
+	dst[4+16] = (size + 10) >> 8;
+	dst[5+16] = (size + 10) & 0xff;
+	dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+	dst[10+16] = (pts_stamp >> 22) & 0xff;
+	dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+	dst[12+16] = (pts_stamp >> 7) & 0xff;
+	dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+	itv->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
+{
+	u32 linemask[2];
+	int i, l, id2;
+	int line = 0;
+
+	if (!memcmp(p, "itv0", 4)) {
+		memcpy(linemask, p + 4, 8);
+		p += 12;
+	} else if (!memcmp(p, "ITV0", 4)) {
+		linemask[0] = 0xffffffff;
+		linemask[1] = 0xf;
+		p += 4;
+	} else {
+		/* unknown VBI data stream */
+		return 0;
+	}
+	for (i = 0; i < 36; i++) {
+		int err = 0;
+
+		if (i < 32 && !(linemask[0] & (1 << i)))
+			continue;
+		if (i >= 32 && !(linemask[1] & (1 << (i - 32))))
+			continue;
+		id2 = *p & 0xf;
+		switch (id2) {
+		case IVTV_SLICED_TYPE_TELETEXT_B:
+			id2 = V4L2_SLICED_TELETEXT_B;
+			break;
+		case IVTV_SLICED_TYPE_CAPTION_525:
+			id2 = V4L2_SLICED_CAPTION_525;
+			err = !odd_parity(p[1]) || !odd_parity(p[2]);
+			break;
+		case IVTV_SLICED_TYPE_VPS:
+			id2 = V4L2_SLICED_VPS;
+			break;
+		case IVTV_SLICED_TYPE_WSS_625:
+			id2 = V4L2_SLICED_WSS_625;
+			break;
+		default:
+			id2 = 0;
+			break;
+		}
+		if (err == 0) {
+			l = (i < 18) ? i + 6 : i - 18 + 6;
+			itv->vbi.sliced_dec_data[line].line = l;
+			itv->vbi.sliced_dec_data[line].field = i >= 18;
+			itv->vbi.sliced_dec_data[line].id = id2;
+			memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42);
+			line++;
+		}
+		p += 43;
+	}
+	while (line < 36) {
+		itv->vbi.sliced_dec_data[line].id = 0;
+		itv->vbi.sliced_dec_data[line].line = 0;
+		itv->vbi.sliced_dec_data[line].field = 0;
+		line++;
+	}
+	return line * sizeof(itv->vbi.sliced_dec_data[0]);
+}
+
+ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
+{
+	/* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
+	const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
+	u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
+	int found_cc = 0;
+	int cc_pos = itv->vbi.cc_pos;
+
+	if (itv->vbi.service_set_out == 0)
+		return -EPERM;
+
+	while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
+		switch (p->id) {
+		case V4L2_SLICED_CAPTION_525:
+			if (p->id == V4L2_SLICED_CAPTION_525 &&
+			    p->line == 21 &&
+			    (itv->vbi.service_set_out &
+				V4L2_SLICED_CAPTION_525) == 0) {
+				break;
+			}
+			found_cc = 1;
+			if (p->field) {
+				cc[2] = p->data[0];
+				cc[3] = p->data[1];
+			} else {
+				cc[0] = p->data[0];
+				cc[1] = p->data[1];
+			}
+			break;
+
+		case V4L2_SLICED_VPS:
+			if (p->line == 16 && p->field == 0 &&
+			    (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
+				itv->vbi.vps[0] = p->data[2];
+				itv->vbi.vps[1] = p->data[8];
+				itv->vbi.vps[2] = p->data[9];
+				itv->vbi.vps[3] = p->data[10];
+				itv->vbi.vps[4] = p->data[11];
+				itv->vbi.vps_found = 1;
+				set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+			}
+			break;
+
+		case V4L2_SLICED_WSS_625:
+			if (p->line == 23 && p->field == 0 &&
+			    (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
+				/* No lock needed for WSS */
+				itv->vbi.wss = p->data[0] | (p->data[1] << 8);
+				itv->vbi.wss_found = 1;
+				set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+			}
+			break;
+
+		default:
+			break;
+		}
+		count -= sizeof(*p);
+		p++;
+	}
+
+	if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
+		itv->vbi.cc_data_odd[cc_pos] = cc[0];
+		itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
+		itv->vbi.cc_data_even[cc_pos] = cc[2];
+		itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
+		itv->vbi.cc_pos = cc_pos + 2;
+		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+	}
+
+	return (const char __user *)p - ubuf;
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space after the
+   field.
+   Returns new compressed size. */
+static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size)
+{
+	u32 line_size = itv->vbi.raw_decoder_line_size;
+	u32 lines = itv->vbi.count;
+	u8 sav1 = itv->vbi.raw_decoder_sav_odd_field;
+	u8 sav2 = itv->vbi.raw_decoder_sav_even_field;
+	u8 *q = buf;
+	u8 *p;
+	int i;
+
+	for (i = 0; i < lines; i++) {
+		p = buf + i * line_size;
+
+		/* Look for SAV code */
+		if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) {
+			break;
+		}
+		memcpy(q, p + 4, line_size - 4);
+		q += line_size - 4;
+	}
+	return lines * (line_size - 4);
+}
+
+
+/* Compressed VBI format, all found sliced blocks put next to one another
+   Returns new compressed size */
+static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav)
+{
+	u32 line_size = itv->vbi.sliced_decoder_line_size;
+	struct v4l2_decode_vbi_line vbi;
+	int i;
+
+	/* find the first valid line */
+	for (i = 0; i < size; i++, buf++) {
+		if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+			break;
+	}
+
+	size -= i;
+	if (size < line_size) {
+		return line;
+	}
+	for (i = 0; i < size / line_size; i++) {
+		u8 *p = buf + i * line_size;
+
+		/* Look for SAV code  */
+		if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) {
+			continue;
+		}
+		vbi.p = p + 4;
+		itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+		if (vbi.type) {
+			itv->vbi.sliced_data[line].id = vbi.type;
+			itv->vbi.sliced_data[line].field = vbi.is_second_field;
+			itv->vbi.sliced_data[line].line = vbi.line;
+			memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42);
+			line++;
+		}
+	}
+	return line;
+}
+
+void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
+			   u64 pts_stamp, int streamtype)
+{
+	u8 *p = (u8 *) buf->buf;
+	u32 size = buf->bytesused;
+	int y;
+
+	/* Raw VBI data */
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
+		u8 type;
+
+		ivtv_buf_swap(buf);
+
+		type = p[3];
+
+		size = buf->bytesused = compress_raw_buf(itv, p, size);
+
+		/* second field of the frame? */
+		if (type == itv->vbi.raw_decoder_sav_even_field) {
+			/* Dirty hack needed for backwards
+			   compatibility of old VBI software. */
+			p += size - 4;
+			memcpy(p, &itv->vbi.frame, 4);
+			itv->vbi.frame++;
+		}
+		return;
+	}
+
+	/* Sliced VBI data with data insertion */
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) {
+		int lines;
+
+		ivtv_buf_swap(buf);
+
+		/* first field */
+		lines = compress_sliced_buf(itv, 0, p, size / 2,
+			itv->vbi.sliced_decoder_sav_odd_field);
+		/* second field */
+		/* experimentation shows that the second half does not always begin
+		   at the exact address. So start a bit earlier (hence 32). */
+		lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32,
+			itv->vbi.sliced_decoder_sav_even_field);
+		/* always return at least one empty line */
+		if (lines == 0) {
+			itv->vbi.sliced_data[0].id = 0;
+			itv->vbi.sliced_data[0].line = 0;
+			itv->vbi.sliced_data[0].field = 0;
+			lines = 1;
+		}
+		buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]);
+		memcpy(p, &itv->vbi.sliced_data[0], size);
+
+		if (itv->vbi.insert_mpeg) {
+			copy_vbi_data(itv, lines, pts_stamp);
+		}
+		itv->vbi.frame++;
+		return;
+	}
+
+	/* Sliced VBI re-inserted from an MPEG stream */
+	if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
+		/* If the size is not 4-byte aligned, then the starting address
+		   for the swapping is also shifted. After swapping the data the
+		   real start address of the VBI data is exactly 4 bytes after the
+		   original start. It's a bit fiddly but it works like a charm.
+		   Non-4-byte alignment happens when an lseek is done on the input
+		   mpeg file to a non-4-byte aligned position. So on arrival here
+		   the VBI data is also non-4-byte aligned. */
+		int offset = size & 3;
+		int cnt;
+
+		if (offset) {
+			p += 4 - offset;
+		}
+		/* Swap Buffer */
+		for (y = 0; y < size; y += 4) {
+		       swab32s((u32 *)(p + y));
+		}
+
+		cnt = ivtv_convert_ivtv_vbi(itv, p + offset);
+		memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
+		buf->bytesused = cnt;
+
+		passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+		return;
+	}
+}
+
+void ivtv_disable_vbi(struct ivtv *itv)
+{
+	clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+	clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+	clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+	ivtv_set_wss(itv, 0, 0);
+	ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+	ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
+	itv->vbi.vps_found = itv->vbi.wss_found = 0;
+	itv->vbi.wss = 0;
+	itv->vbi.cc_pos = 0;
+}
+
+
+void vbi_work_handler(struct ivtv *itv)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	/* Lock */
+	if (itv->output_mode == OUT_PASSTHROUGH) {
+		/* Note: currently only the saa7115 is used in a PVR350,
+		   so these commands are for now saa7115 specific. */
+		if (itv->is_50hz) {
+			data.id = V4L2_SLICED_WSS_625;
+			data.field = 0;
+
+			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+				ivtv_set_wss(itv, 1, data.data[0] & 0xf);
+				itv->vbi.wss_no_update = 0;
+			} else if (itv->vbi.wss_no_update == 4) {
+				ivtv_set_wss(itv, 1, 0x8);  /* 4x3 full format */
+			} else {
+				itv->vbi.wss_no_update++;
+			}
+		}
+		else {
+			u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+			int mode = 0;
+
+			data.id = V4L2_SLICED_CAPTION_525;
+			data.field = 0;
+			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+				mode |= 1;
+				c1 = data.data[0];
+				c2 = data.data[1];
+			}
+			data.field = 1;
+			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+				mode |= 2;
+				c3 = data.data[0];
+				c4 = data.data[1];
+			}
+			if (mode) {
+				itv->vbi.cc_no_update = 0;
+				ivtv_set_cc(itv, mode, c1, c2, c3, c4);
+			} else if (itv->vbi.cc_no_update == 4) {
+				ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+			} else {
+				itv->vbi.cc_no_update++;
+			}
+		}
+		return;
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
+		/* Lock */
+		ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+		if (itv->vbi.cc_pos == 0) {
+			ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
+		}
+		while (itv->vbi.cc_pos) {
+			u8 cc_odd0 = itv->vbi.cc_data_odd[0];
+			u8 cc_odd1 = itv->vbi.cc_data_odd[1];
+			u8 cc_even0 = itv->vbi.cc_data_even[0];
+			u8 cc_even1 = itv->vbi.cc_data_even[1];
+
+			memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
+			memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
+			itv->vbi.cc_pos -= 2;
+			if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
+				continue;
+
+			/* Send to Saa7127 */
+			ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
+			if (itv->vbi.cc_pos == 0)
+				set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+			break;
+		}
+	}
+
+	if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
+		/* Lock */
+		ivtv_set_vps(itv, itv->vbi.vps_found,
+			itv->vbi.vps[0], itv->vbi.vps[1],
+			itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
+	}
+}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
new file mode 100644
index 0000000..cdaea69
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -0,0 +1,26 @@
+/*
+    Vertical Blank Interval support functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count);
+void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
+			   u64 pts_stamp, int streamtype);
+int ivtv_used_line(struct ivtv *itv, int line, int field);
+void ivtv_disable_vbi(struct ivtv *itv);
+void ivtv_set_vbi(unsigned long arg);
+void vbi_work_handler(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
new file mode 100644
index 0000000..85530a3
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -0,0 +1,26 @@
+/*
+    ivtv driver version information
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 IVTV_DRIVER_NAME "ivtv"
+#define IVTV_DRIVER_VERSION_MAJOR 1
+#define IVTV_DRIVER_VERSION_MINOR 0
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+
+#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
+#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-video.c
new file mode 100644
index 0000000..5858b19
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-video.c
@@ -0,0 +1,142 @@
+/*
+    saa7127 interface functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 "ivtv-driver.h"
+#include "ivtv-video.h"
+#include "ivtv-i2c.h"
+#include "ivtv-gpio.h"
+#include "ivtv-cards.h"
+#include <media/upd64031a.h>
+#include <media/upd64083.h>
+
+void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
+		  u8 vps4, u8 vps5)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_VPS;
+	data.field = 0;
+	data.line = enabled ? 16 : 0;
+	data.data[4] = vps1;
+	data.data[10] = vps2;
+	data.data[11] = vps3;
+	data.data[12] = vps4;
+	data.data[13] = vps5;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_CAPTION_525;
+	data.field = 0;
+	data.line = (mode & 1) ? 21 : 0;
+	data.data[0] = cc1;
+	data.data[1] = cc2;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	data.field = 1;
+	data.line = (mode & 2) ? 21 : 0;
+	data.data[0] = cc3;
+	data.data[1] = cc4;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	/* When using a 50 Hz system, always turn on the
+	   wide screen signal with 4x3 ratio as the default.
+	   Turning this signal on and off can confuse certain
+	   TVs. As far as I can tell there is no reason not to
+	   transmit this signal. */
+	if ((itv->std & V4L2_STD_625_50) && !enabled) {
+		enabled = 1;
+		mode = 0x08;  /* 4x3 full format */
+	}
+	data.id = V4L2_SLICED_WSS_625;
+	data.field = 0;
+	data.line = enabled ? 23 : 0;
+	data.data[0] = mode & 0xff;
+	data.data[1] = (mode >> 8) & 0xff;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+void ivtv_video_set_io(struct ivtv *itv)
+{
+	struct v4l2_routing route;
+	int inp = itv->active_input;
+	u32 type;
+
+	route.input = itv->card->video_inputs[inp].video_input;
+	route.output = 0;
+	itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	type = itv->card->video_inputs[inp].video_type;
+
+	if (type == IVTV_CARD_INPUT_VID_TUNER) {
+		route.input = 0;  /* Tuner */
+	} else if (type < IVTV_CARD_INPUT_COMPOSITE1) {
+		route.input = 2;  /* S-Video */
+	} else {
+		route.input = 1;  /* Composite */
+	}
+
+	if (itv->card->hw_video & IVTV_HW_GPIO)
+		ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+		if (type == IVTV_CARD_INPUT_VID_TUNER ||
+		    type >= IVTV_CARD_INPUT_COMPOSITE1) {
+			/* Composite: GR on, connect to 3DYCS */
+			route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE;
+		} else {
+			/* S-Video: GR bypassed, turn it off */
+			route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE;
+		}
+		route.input |= itv->card->gr_config;
+
+		ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	}
+
+	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
+		route.input = UPD64083_YCS_MODE;
+		if (type > IVTV_CARD_INPUT_VID_TUNER &&
+		    type < IVTV_CARD_INPUT_COMPOSITE1) {
+			/* S-Video uses YCNR mode and internal Y-ADC, the upd64031a
+			   is not used. */
+			route.input |= UPD64083_YCNR_MODE;
+		}
+		else if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+		  /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */
+		  if ((type == IVTV_CARD_INPUT_VID_TUNER)||
+		      (itv->card->type == IVTV_CARD_CX23416GYC)) {
+		    route.input |= UPD64083_EXT_Y_ADC;
+		  }
+		}
+		ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	}
+}
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h
new file mode 100644
index 0000000..c8ade5d
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-video.h
@@ -0,0 +1,24 @@
+/*
+    saa7127 interface functions
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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
+ */
+
+void ivtv_set_wss(struct ivtv *itv, int enabled, int mode);
+void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4);
+void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
+		  u8 vps4, u8 vps5);
+void ivtv_video_set_io(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
new file mode 100644
index 0000000..bcea095
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -0,0 +1,1129 @@
+/*
+    yuv support
+
+    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.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 "ivtv-driver.h"
+#include "ivtv-queue.h"
+#include "ivtv-udma.h"
+#include "ivtv-irq.h"
+#include "ivtv-yuv.h"
+
+static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
+				 struct ivtv_dma_frame *args)
+{
+	struct ivtv_dma_page_info y_dma;
+	struct ivtv_dma_page_info uv_dma;
+
+	int i;
+	int y_pages, uv_pages;
+
+	unsigned long y_buffer_offset, uv_buffer_offset;
+	int y_decode_height, uv_decode_height, y_size;
+	int frame = atomic_read(&itv->yuv_info.next_fill_frame);
+
+	y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame];
+	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
+
+	y_decode_height = uv_decode_height = args->src.height + args->src.top;
+
+	if (y_decode_height < 512-16)
+		y_buffer_offset += 720 * 16;
+
+	if (y_decode_height & 15)
+		y_decode_height = (y_decode_height + 16) & ~15;
+
+	if (uv_decode_height & 31)
+		uv_decode_height = (uv_decode_height + 32) & ~31;
+
+	y_size = 720 * y_decode_height;
+
+	/* Still in USE */
+	if (dma->SG_length || dma->page_count) {
+		IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
+				dma->SG_length, dma->page_count);
+		return -EBUSY;
+	}
+
+	ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
+	ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
+
+	/* Get user pages for DMA Xfer */
+	down_read(&current->mm->mmap_sem);
+	y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
+	uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
+	up_read(&current->mm->mmap_sem);
+
+	dma->page_count = y_dma.page_count + uv_dma.page_count;
+
+	if (y_pages + uv_pages != dma->page_count) {
+		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
+				y_pages + uv_pages, dma->page_count);
+
+		for (i = 0; i < dma->page_count; i++) {
+			put_page(dma->map[i]);
+		}
+		dma->page_count = 0;
+		return -EINVAL;
+	}
+
+	/* Fill & map SG List */
+	ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0));
+	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
+
+	/* Fill SG Array with new values */
+	ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
+
+	/* If we've offset the y plane, ensure top area is blanked */
+	if (args->src.height + args->src.top < 512-16) {
+		if (itv->yuv_info.blanking_dmaptr) {
+			dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
+			dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
+			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]);
+			dma->SG_length++;
+		}
+	}
+
+	/* Tag SG Array with Interrupt Bit */
+	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
+
+	ivtv_udma_sync_for_device(itv);
+	return 0;
+}
+
+/* We rely on a table held in the firmware - Quick check. */
+int ivtv_yuv_filter_check(struct ivtv *itv)
+{
+	int i, offset_y, offset_uv;
+
+	for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
+		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
+		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
+			IVTV_WARN ("YUV filter table not found in firmware.\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
+{
+	int filter_index, filter_line;
+
+	/* If any filter is -1, then don't update it */
+	if (h_filter > -1) {
+		if (h_filter > 4) h_filter = 4;
+		filter_index = h_filter * 384;
+		filter_line = 0;
+		while (filter_line < 16) {
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
+			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
+			filter_index += 8;
+			write_reg(0, 0x02818);
+			write_reg(0, 0x02830);
+			filter_line ++;
+		}
+		IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
+	}
+
+	if (v_filter_1 > -1) {
+		if (v_filter_1 > 4) v_filter_1 = 4;
+		filter_index = v_filter_1 * 192;
+		filter_line = 0;
+		while (filter_line < 16) {
+			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
+			filter_index += 8;
+			write_reg(0, 0x02908);
+			filter_line ++;
+		}
+		IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
+	}
+
+	if (v_filter_2 > -1) {
+		if (v_filter_2 > 4) v_filter_2 = 4;
+		filter_index = v_filter_2 * 192;
+		filter_line = 0;
+		while (filter_line < 16) {
+			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
+			filter_index += 4;
+			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
+			filter_index += 8;
+			write_reg(0, 0x02914);
+			filter_line ++;
+		}
+		IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
+	}
+}
+
+static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
+{
+	u32 reg_2834, reg_2838, reg_283c;
+	u32 reg_2844, reg_2854, reg_285c;
+	u32 reg_2864, reg_2874, reg_2890;
+	u32 reg_2870, reg_2870_base, reg_2870_offset;
+	int x_cutoff;
+	int h_filter;
+	u32 master_width;
+
+	IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
+			 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
+
+	/* How wide is the src image */
+	x_cutoff  = window->src_w + window->src_x;
+
+	/* Set the display width */
+	reg_2834 = window->dst_w;
+	reg_2838 = reg_2834;
+
+	/* Set the display position */
+	reg_2890 = window->dst_x;
+
+	/* Index into the image horizontally */
+	reg_2870 = 0;
+
+	/* 2870 is normally fudged to align video coords with osd coords.
+	   If running full screen, it causes an unwanted left shift
+	   Remove the fudge if we almost fill the screen.
+	   Gradually adjust the offset to avoid the video 'snapping'
+	   left/right if it gets dragged through this region.
+	   Only do this if osd is full width. */
+	if (window->vis_w == 720) {
+		if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
+			reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
+		}
+		else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
+			reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
+		}
+
+		if (window->dst_w >= window->src_w)
+			reg_2870 = reg_2870 << 16 | reg_2870;
+		else
+			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
+	}
+
+	if (window->dst_w < window->src_w)
+		reg_2870 = 0x000d000e - reg_2870;
+	else
+		reg_2870 = 0x0012000e - reg_2870;
+
+	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
+	reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
+
+	if (window->dst_w >= window->src_w) {
+		x_cutoff &= ~1;
+		master_width = (window->src_w * 0x00200000) / (window->dst_w);
+		if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 2;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+
+		/* We also need to factor in the scaling
+		   (src_w - dst_w) / (src_w / 4) */
+		if (window->dst_w > window->src_w)
+			reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
+		else
+			reg_2870_base = 0;
+
+		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
+		reg_2874 = 0;
+	}
+	else if (window->dst_w < window->src_w / 2) {
+		master_width = (window->src_w * 0x00080000) / window->dst_w;
+		if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 1;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+		reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
+		reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
+		reg_2874 = 0x00000012;
+	}
+	else {
+		master_width = (window->src_w * 0x00100000) / window->dst_w;
+		if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
+		reg_2834 = (reg_2834 << 16) | x_cutoff;
+		reg_2838 = (reg_2838 << 16) | x_cutoff;
+		reg_283c = master_width >> 2;
+		reg_2844 = master_width >> 1;
+		reg_2854 = master_width;
+		reg_285c = master_width >> 1;
+		reg_2864 = master_width >> 1;
+		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
+		reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
+		reg_2874 = 0x00000001;
+	}
+
+	/* Select the horizontal filter */
+	if (window->src_w == window->dst_w) {
+		/* An exact size match uses filter 0 */
+		h_filter = 0;
+	}
+	else {
+		/* Figure out which filter to use */
+		h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
+		h_filter = (h_filter >> 1) + (h_filter & 1);
+		/* Only an exact size match can use filter 0 */
+		if (h_filter == 0) h_filter = 1;
+	}
+
+	write_reg(reg_2834, 0x02834);
+	write_reg(reg_2838, 0x02838);
+	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
+
+	write_reg(reg_283c, 0x0283c);
+	write_reg(reg_2844, 0x02844);
+
+	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
+
+	write_reg(0x00080514, 0x02840);
+	write_reg(0x00100514, 0x02848);
+	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
+
+	write_reg(reg_2854, 0x02854);
+	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
+
+	write_reg(reg_285c, 0x0285c);
+	write_reg(reg_2864, 0x02864);
+	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
+
+	write_reg(reg_2874, 0x02874);
+	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
+
+	write_reg(reg_2870, 0x02870);
+	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
+
+	write_reg( reg_2890,0x02890);
+	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
+
+	/* Only update the filter if we really need to */
+	if (h_filter != itv->yuv_info.h_filter) {
+		ivtv_yuv_filter (itv,h_filter,-1,-1);
+		itv->yuv_info.h_filter = h_filter;
+	}
+}
+
+static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
+{
+	u32 master_height;
+	u32 reg_2918, reg_291c, reg_2920, reg_2928;
+	u32 reg_2930, reg_2934, reg_293c;
+	u32 reg_2940, reg_2944, reg_294c;
+	u32 reg_2950, reg_2954, reg_2958, reg_295c;
+	u32 reg_2960, reg_2964, reg_2968, reg_296c;
+	u32 reg_289c;
+	u32 src_y_major_y, src_y_minor_y;
+	u32 src_y_major_uv, src_y_minor_uv;
+	u32 reg_2964_base, reg_2968_base;
+	int v_filter_1, v_filter_2;
+
+	IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
+		window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
+
+	/* What scaling mode is being used... */
+	if (window->interlaced_y) {
+		IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
+	}
+	else {
+		IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
+	}
+
+	if (window->interlaced_uv) {
+		IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
+	}
+	else {
+		IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
+	}
+
+	/* What is the source video being treated as... */
+	if (itv->yuv_info.frame_interlaced) {
+		IVTV_DEBUG_WARN("Source video: Interlaced\n");
+	}
+	else {
+		IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
+	}
+
+	/* We offset into the image using two different index methods, so split
+	   the y source coord into two parts. */
+	if (window->src_y < 8) {
+		src_y_minor_uv = window->src_y;
+		src_y_major_uv = 0;
+	}
+	else {
+		src_y_minor_uv = 8;
+		src_y_major_uv = window->src_y - 8;
+	}
+
+	src_y_minor_y = src_y_minor_uv;
+	src_y_major_y = src_y_major_uv;
+
+	if (window->offset_y) src_y_minor_y += 16;
+
+	if (window->interlaced_y)
+		reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
+	else
+		reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
+
+	if (window->interlaced_uv)
+		reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
+	else
+		reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
+
+	reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
+	reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
+
+	if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
+		master_height = (window->src_h * 0x00400000) / window->dst_h;
+		if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 3;
+		reg_2930 = master_height;
+		reg_2940 = master_height >> 1;
+		reg_2964_base >>= 3;
+		reg_2968_base >>= 3;
+		reg_296c = 0x00000000;
+	}
+	else if (window->dst_h >= window->src_h) {
+		master_height = (window->src_h * 0x00400000) / window->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height >> 1;
+		reg_296c = 0x00000000;
+		if (window->interlaced_y) {
+			reg_2964_base >>= 3;
+		}
+		else {
+			reg_296c ++;
+			reg_2964_base >>= 2;
+		}
+		if (window->interlaced_uv) reg_2928 >>= 1;
+		reg_2968_base >>= 3;
+	}
+	else if (window->dst_h >= window->src_h / 2) {
+		master_height = (window->src_h * 0x00200000) / window->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height;
+		reg_296c = 0x00000101;
+		if (window->interlaced_y) {
+			reg_2964_base >>= 2;
+		}
+		else {
+			reg_296c ++;
+			reg_2964_base >>= 1;
+		}
+		if (window->interlaced_uv) reg_2928 >>= 1;
+		reg_2968_base >>= 2;
+	}
+	else {
+		master_height = (window->src_h * 0x00100000) / window->dst_h;
+		master_height = (master_height >> 1) + (master_height & 1);
+		reg_2920 = master_height >> 2;
+		reg_2928 = master_height >> 2;
+		reg_2930 = master_height;
+		reg_2940 = master_height;
+		reg_2964_base >>= 1;
+		reg_2968_base >>= 2;
+		reg_296c = 0x00000102;
+	}
+
+	/* FIXME These registers change depending on scaled / unscaled output
+	   We really need to work out what they should be */
+	if (window->src_h == window->dst_h){
+		reg_2934 = 0x00020000;
+		reg_293c = 0x00100000;
+		reg_2944 = 0x00040000;
+		reg_294c = 0x000b0000;
+	}
+	else {
+		reg_2934 = 0x00000FF0;
+		reg_293c = 0x00000FF0;
+		reg_2944 = 0x00000FF0;
+		reg_294c = 0x00000FF0;
+	}
+
+	/* The first line to be displayed */
+	reg_2950 = 0x00010000 + src_y_major_y;
+	if (window->interlaced_y) reg_2950 += 0x00010000;
+	reg_2954 = reg_2950 + 1;
+
+	reg_2958 = 0x00010000 + (src_y_major_y >> 1);
+	if (window->interlaced_uv) reg_2958 += 0x00010000;
+	reg_295c = reg_2958 + 1;
+
+	if (itv->yuv_info.decode_height == 480)
+		reg_289c = 0x011e0017;
+	else
+		reg_289c = 0x01500017;
+
+	if (window->dst_y < 0)
+		reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
+	else
+		reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
+
+	/* How much of the source to decode.
+	   Take into account the source offset */
+	reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
+			((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
+
+	/* Calculate correct value for register 2964 */
+	if (window->src_h == window->dst_h)
+		reg_2964 = 1;
+	else {
+		reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
+		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
+	}
+	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
+	reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
+
+	/* Okay, we've wasted time working out the correct value,
+	   but if we use it, it fouls the the window alignment.
+	   Fudge it to what we want... */
+	reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
+	reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
+
+	/* Deviate further from what it should be. I find the flicker headache
+	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
+	   colours foul. */
+	if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
+		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
+
+	if (!window->interlaced_y) reg_2964 -= 0x00010001;
+	if (!window->interlaced_uv) reg_2968 -= 0x00010001;
+
+	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
+	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
+
+	/* Select the vertical filter */
+	if (window->src_h == window->dst_h) {
+		/* An exact size match uses filter 0/1 */
+		v_filter_1 = 0;
+		v_filter_2 = 1;
+	}
+	else {
+		/* Figure out which filter to use */
+		v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
+		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+		/* Only an exact size match can use filter 0 */
+		if (v_filter_1 == 0) v_filter_1 = 1;
+		v_filter_2 = v_filter_1;
+	}
+
+	write_reg(reg_2934, 0x02934);
+	write_reg(reg_293c, 0x0293c);
+	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
+	write_reg(reg_2944, 0x02944);
+	write_reg(reg_294c, 0x0294c);
+	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
+
+	/* Ensure 2970 is 0 (does it ever change ?) */
+/*	write_reg(0,0x02970); */
+/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
+
+	write_reg(reg_2930, 0x02938);
+	write_reg(reg_2930, 0x02930);
+	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
+
+	write_reg(reg_2928, 0x02928);
+	write_reg(reg_2928+0x514, 0x0292C);
+	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
+
+	write_reg(reg_2920, 0x02920);
+	write_reg(reg_2920+0x514, 0x02924);
+	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
+
+	write_reg (reg_2918,0x02918);
+	write_reg (reg_291c,0x0291C);
+	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
+
+	write_reg(reg_296c, 0x0296c);
+	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
+
+	write_reg(reg_2940, 0x02948);
+	write_reg(reg_2940, 0x02940);
+	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
+
+	write_reg(reg_2950, 0x02950);
+	write_reg(reg_2954, 0x02954);
+	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
+
+	write_reg(reg_2958, 0x02958);
+	write_reg(reg_295c, 0x0295C);
+	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
+
+	write_reg(reg_2960, 0x02960);
+	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
+
+	write_reg(reg_2964, 0x02964);
+	write_reg(reg_2968, 0x02968);
+	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
+
+	write_reg( reg_289c,0x0289c);
+	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
+
+	/* Only update filter 1 if we really need to */
+	if (v_filter_1 != itv->yuv_info.v_filter_1) {
+		ivtv_yuv_filter (itv,-1,v_filter_1,-1);
+		itv->yuv_info.v_filter_1 = v_filter_1;
+	}
+
+	/* Only update filter 2 if we really need to */
+	if (v_filter_2 != itv->yuv_info.v_filter_2) {
+		ivtv_yuv_filter (itv,-1,-1,v_filter_2);
+		itv->yuv_info.v_filter_2 = v_filter_2;
+	}
+
+	itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
+}
+
+/* Modify the supplied coordinate information to fit the visible osd area */
+static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
+{
+	int osd_crop, lace_threshold;
+	u32 osd_scale;
+	u32 yuv_update = 0;
+
+	lace_threshold = itv->yuv_info.lace_threshold;
+	if (lace_threshold < 0)
+		lace_threshold = itv->yuv_info.decode_height - 1;
+
+	/* Work out the lace settings */
+	switch (itv->yuv_info.lace_mode) {
+		case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
+			itv->yuv_info.frame_interlaced = 0;
+			if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
+				window->interlaced_y = 0;
+			else
+				window->interlaced_y = 1;
+
+			if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
+				window->interlaced_uv = 0;
+			else
+				window->interlaced_uv = 1;
+			break;
+
+		case IVTV_YUV_MODE_AUTO:
+			if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
+				itv->yuv_info.frame_interlaced = 0;
+				if ((window->tru_h < 512) ||
+				  (window->tru_h > 576 && window->tru_h < 1021) ||
+				  (window->tru_w > 720 && window->tru_h < 1021))
+					window->interlaced_y = 0;
+				else
+					window->interlaced_y = 1;
+
+				if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
+					window->interlaced_uv = 0;
+				else
+					window->interlaced_uv = 1;
+			}
+			else {
+				itv->yuv_info.frame_interlaced = 1;
+				window->interlaced_y = 1;
+				window->interlaced_uv = 1;
+			}
+			break;
+
+			case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
+		default:
+			itv->yuv_info.frame_interlaced = 1;
+			window->interlaced_y = 1;
+			window->interlaced_uv = 1;
+			break;
+	}
+
+	/* Sorry, but no negative coords for src */
+	if (window->src_x < 0) window->src_x = 0;
+	if (window->src_y < 0) window->src_y = 0;
+
+	/* Can only reduce width down to 1/4 original size */
+	if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
+		window->src_x += osd_crop / 2;
+		window->src_w = (window->src_w - osd_crop) & ~3;
+		window->dst_w = window->src_w / 4;
+		window->dst_w += window->dst_w & 1;
+	}
+
+	/* Can only reduce height down to 1/4 original size */
+	if (window->src_h / window->dst_h >= 2) {
+		/* Overflow may be because we're running progressive, so force mode switch */
+		window->interlaced_y = 1;
+		/* Make sure we're still within limits for interlace */
+		if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
+			/* If we reach here we'll have to force the height. */
+			window->src_y += osd_crop / 2;
+			window->src_h = (window->src_h - osd_crop) & ~3;
+			window->dst_h = window->src_h / 4;
+			window->dst_h += window->dst_h & 1;
+		}
+	}
+
+	/* If there's nothing to safe to display, we may as well stop now */
+	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+		return 0;
+	}
+
+	/* Ensure video remains inside OSD area */
+	osd_scale = (window->src_h << 16) / window->dst_h;
+
+	if ((osd_crop = window->pan_y - window->dst_y) > 0) {
+		/* Falls off the upper edge - crop */
+		window->src_y += (osd_scale * osd_crop) >> 16;
+		window->src_h -= (osd_scale * osd_crop) >> 16;
+		window->dst_h -= osd_crop;
+		window->dst_y = 0;
+	}
+	else {
+		window->dst_y -= window->pan_y;
+	}
+
+	if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
+		/* Falls off the lower edge - crop */
+		window->dst_h -= osd_crop;
+		window->src_h -= (osd_scale * osd_crop) >> 16;
+	}
+
+	osd_scale = (window->src_w << 16) / window->dst_w;
+
+	if ((osd_crop = window->pan_x - window->dst_x) > 0) {
+		/* Fall off the left edge - crop */
+		window->src_x += (osd_scale * osd_crop) >> 16;
+		window->src_w -= (osd_scale * osd_crop) >> 16;
+		window->dst_w -= osd_crop;
+		window->dst_x = 0;
+	}
+	else {
+		window->dst_x -= window->pan_x;
+	}
+
+	if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
+		/* Falls off the right edge - crop */
+		window->dst_w -= osd_crop;
+		window->src_w -= (osd_scale * osd_crop) >> 16;
+	}
+
+	/* The OSD can be moved. Track to it */
+	window->dst_x += itv->yuv_info.osd_x_offset;
+	window->dst_y += itv->yuv_info.osd_y_offset;
+
+	/* Width & height for both src & dst must be even.
+	   Same for coordinates. */
+	window->dst_w &= ~1;
+	window->dst_x &= ~1;
+
+	window->src_w += window->src_x & 1;
+	window->src_x &= ~1;
+
+	window->src_w &= ~1;
+	window->dst_w &= ~1;
+
+	window->dst_h &= ~1;
+	window->dst_y &= ~1;
+
+	window->src_h += window->src_y & 1;
+	window->src_y &= ~1;
+
+	window->src_h &= ~1;
+	window->dst_h &= ~1;
+
+	/* Due to rounding, we may have reduced the output size to <1/4 of the source
+	   Check again, but this time just resize. Don't change source coordinates */
+	if (window->dst_w < window->src_w / 4) {
+		window->src_w &= ~3;
+		window->dst_w = window->src_w / 4;
+		window->dst_w += window->dst_w & 1;
+	}
+	if (window->dst_h < window->src_h / 4) {
+		window->src_h &= ~3;
+		window->dst_h = window->src_h / 4;
+		window->dst_h += window->dst_h & 1;
+	}
+
+	/* Check again. If there's nothing to safe to display, stop now */
+	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+		return 0;
+	}
+
+	/* Both x offset & width are linked, so they have to be done together */
+	if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
+	    (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
+	    (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
+	    (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
+	    (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
+	    (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
+		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
+	}
+
+	if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
+	    (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
+	    (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
+	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
+	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
+	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
+	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
+		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
+	}
+
+	return yuv_update;
+}
+
+/* Update the scaling register to the requested value */
+void ivtv_yuv_work_handler (struct ivtv *itv)
+{
+	struct yuv_frame_info window;
+	u32 yuv_update;
+
+	int frame = itv->yuv_info.update_frame;
+
+/*	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
+	memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
+
+	/* Update the osd pan info */
+	window.pan_x = itv->yuv_info.osd_x_pan;
+	window.pan_y = itv->yuv_info.osd_y_pan;
+	window.vis_w = itv->yuv_info.osd_vis_w;
+	window.vis_h = itv->yuv_info.osd_vis_h;
+
+	/* Calculate the display window coordinates. Exit if nothing left */
+	if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
+		return;
+
+	/* Update horizontal settings */
+	if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
+		ivtv_yuv_handle_horizontal(itv, &window);
+
+	if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
+		ivtv_yuv_handle_vertical(itv, &window);
+
+	memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
+}
+
+static void ivtv_yuv_init (struct ivtv *itv)
+{
+	IVTV_DEBUG_YUV("ivtv_yuv_init\n");
+
+	/* Take a snapshot of the current register settings */
+	itv->yuv_info.reg_2834 = read_reg(0x02834);
+	itv->yuv_info.reg_2838 = read_reg(0x02838);
+	itv->yuv_info.reg_283c = read_reg(0x0283c);
+	itv->yuv_info.reg_2840 = read_reg(0x02840);
+	itv->yuv_info.reg_2844 = read_reg(0x02844);
+	itv->yuv_info.reg_2848 = read_reg(0x02848);
+	itv->yuv_info.reg_2854 = read_reg(0x02854);
+	itv->yuv_info.reg_285c = read_reg(0x0285c);
+	itv->yuv_info.reg_2864 = read_reg(0x02864);
+	itv->yuv_info.reg_2870 = read_reg(0x02870);
+	itv->yuv_info.reg_2874 = read_reg(0x02874);
+	itv->yuv_info.reg_2898 = read_reg(0x02898);
+	itv->yuv_info.reg_2890 = read_reg(0x02890);
+
+	itv->yuv_info.reg_289c = read_reg(0x0289c);
+	itv->yuv_info.reg_2918 = read_reg(0x02918);
+	itv->yuv_info.reg_291c = read_reg(0x0291c);
+	itv->yuv_info.reg_2920 = read_reg(0x02920);
+	itv->yuv_info.reg_2924 = read_reg(0x02924);
+	itv->yuv_info.reg_2928 = read_reg(0x02928);
+	itv->yuv_info.reg_292c = read_reg(0x0292c);
+	itv->yuv_info.reg_2930 = read_reg(0x02930);
+	itv->yuv_info.reg_2934 = read_reg(0x02934);
+	itv->yuv_info.reg_2938 = read_reg(0x02938);
+	itv->yuv_info.reg_293c = read_reg(0x0293c);
+	itv->yuv_info.reg_2940 = read_reg(0x02940);
+	itv->yuv_info.reg_2944 = read_reg(0x02944);
+	itv->yuv_info.reg_2948 = read_reg(0x02948);
+	itv->yuv_info.reg_294c = read_reg(0x0294c);
+	itv->yuv_info.reg_2950 = read_reg(0x02950);
+	itv->yuv_info.reg_2954 = read_reg(0x02954);
+	itv->yuv_info.reg_2958 = read_reg(0x02958);
+	itv->yuv_info.reg_295c = read_reg(0x0295c);
+	itv->yuv_info.reg_2960 = read_reg(0x02960);
+	itv->yuv_info.reg_2964 = read_reg(0x02964);
+	itv->yuv_info.reg_2968 = read_reg(0x02968);
+	itv->yuv_info.reg_296c = read_reg(0x0296c);
+	itv->yuv_info.reg_2970 = read_reg(0x02970);
+
+	itv->yuv_info.v_filter_1 = -1;
+	itv->yuv_info.v_filter_2 = -1;
+	itv->yuv_info.h_filter = -1;
+
+	/* Set some valid size info */
+	itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
+	itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
+
+	/* Bit 2 of reg 2878 indicates current decoder output format
+	   0 : NTSC    1 : PAL */
+	if (read_reg(0x2878) & 4)
+		itv->yuv_info.decode_height = 576;
+	else
+		itv->yuv_info.decode_height = 480;
+
+	/* If no visible size set, assume full size */
+	if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
+	if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+
+	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
+	itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
+	if (itv->yuv_info.blanking_ptr) {
+		itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
+	}
+	else {
+		itv->yuv_info.blanking_dmaptr = 0;
+		IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
+	}
+
+	IVTV_DEBUG_WARN("Enable video output\n");
+	write_reg_sync(0x00108080, 0x2898);
+
+	/* Enable YUV decoder output */
+	write_reg_sync(0x01, IVTV_REG_VDM);
+
+	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
+	atomic_set(&itv->yuv_info.next_dma_frame,0);
+}
+
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	DEFINE_WAIT(wait);
+	int rc = 0;
+	int got_sig = 0;
+	int frame, next_fill_frame, last_fill_frame;
+
+	IVTV_DEBUG_INFO("yuv_prep_frame\n");
+
+	if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
+
+	frame = atomic_read(&itv->yuv_info.next_fill_frame);
+	next_fill_frame = (frame + 1) & 0x3;
+	last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
+
+	if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
+		/* Buffers are full - Overwrite the last frame */
+		next_fill_frame = frame;
+		frame = (frame - 1) & 3;
+	}
+
+	/* Take a snapshot of the yuv coordinate information */
+	itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
+	itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
+	itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
+	itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
+	itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
+	itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
+	itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
+	itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
+	itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
+	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
+	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
+
+	/* Are we going to offset the Y plane */
+	if (args->src.height + args->src.top < 512-16)
+		itv->yuv_info.new_frame_info[frame].offset_y = 1;
+	else
+		itv->yuv_info.new_frame_info[frame].offset_y = 0;
+
+	/* Snapshot the osd pan info */
+	itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
+	itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
+	itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
+	itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
+
+	itv->yuv_info.new_frame_info[frame].update = 0;
+	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
+	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+
+	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
+	    sizeof (itv->yuv_info.new_frame_info[frame]))) {
+		memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
+		itv->yuv_info.new_frame_info[frame].update = 1;
+/*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
+	}
+
+	/* DMA the frame */
+	mutex_lock(&itv->udma.lock);
+
+	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
+		mutex_unlock(&itv->udma.lock);
+		return rc;
+	}
+
+	ivtv_udma_prepare(itv);
+	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+	/* if no UDMA is pending and no UDMA is in progress, then the DMA
+	is finished */
+	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
+		/* don't interrupt if the DMA is in progress but break off
+		a still pending DMA. */
+		got_sig = signal_pending(current);
+		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+			break;
+		got_sig = 0;
+		schedule();
+	}
+	finish_wait(&itv->dma_waitq, &wait);
+
+	/* Unmap Last DMA Xfer */
+	ivtv_udma_unmap(itv);
+
+	if (got_sig) {
+		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
+		mutex_unlock(&itv->udma.lock);
+		return -EINTR;
+	}
+
+	atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
+
+	mutex_unlock(&itv->udma.lock);
+	return rc;
+}
+
+void ivtv_yuv_close(struct ivtv *itv)
+{
+	int h_filter, v_filter_1, v_filter_2;
+
+	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
+	ivtv_waitq(&itv->vsync_waitq);
+
+	atomic_set(&itv->yuv_info.next_dma_frame, -1);
+	atomic_set(&itv->yuv_info.next_fill_frame, 0);
+
+	/* Reset registers we have changed so mpeg playback works */
+
+	/* If we fully restore this register, the display may remain active.
+	   Restore, but set one bit to blank the video. Firmware will always
+	   clear this bit when needed, so not a problem. */
+	write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
+
+	write_reg(itv->yuv_info.reg_2834, 0x02834);
+	write_reg(itv->yuv_info.reg_2838, 0x02838);
+	write_reg(itv->yuv_info.reg_283c, 0x0283c);
+	write_reg(itv->yuv_info.reg_2840, 0x02840);
+	write_reg(itv->yuv_info.reg_2844, 0x02844);
+	write_reg(itv->yuv_info.reg_2848, 0x02848);
+	write_reg(itv->yuv_info.reg_2854, 0x02854);
+	write_reg(itv->yuv_info.reg_285c, 0x0285c);
+	write_reg(itv->yuv_info.reg_2864, 0x02864);
+	write_reg(itv->yuv_info.reg_2870, 0x02870);
+	write_reg(itv->yuv_info.reg_2874, 0x02874);
+	write_reg(itv->yuv_info.reg_2890, 0x02890);
+	write_reg(itv->yuv_info.reg_289c, 0x0289c);
+
+	write_reg(itv->yuv_info.reg_2918, 0x02918);
+	write_reg(itv->yuv_info.reg_291c, 0x0291c);
+	write_reg(itv->yuv_info.reg_2920, 0x02920);
+	write_reg(itv->yuv_info.reg_2924, 0x02924);
+	write_reg(itv->yuv_info.reg_2928, 0x02928);
+	write_reg(itv->yuv_info.reg_292c, 0x0292c);
+	write_reg(itv->yuv_info.reg_2930, 0x02930);
+	write_reg(itv->yuv_info.reg_2934, 0x02934);
+	write_reg(itv->yuv_info.reg_2938, 0x02938);
+	write_reg(itv->yuv_info.reg_293c, 0x0293c);
+	write_reg(itv->yuv_info.reg_2940, 0x02940);
+	write_reg(itv->yuv_info.reg_2944, 0x02944);
+	write_reg(itv->yuv_info.reg_2948, 0x02948);
+	write_reg(itv->yuv_info.reg_294c, 0x0294c);
+	write_reg(itv->yuv_info.reg_2950, 0x02950);
+	write_reg(itv->yuv_info.reg_2954, 0x02954);
+	write_reg(itv->yuv_info.reg_2958, 0x02958);
+	write_reg(itv->yuv_info.reg_295c, 0x0295c);
+	write_reg(itv->yuv_info.reg_2960, 0x02960);
+	write_reg(itv->yuv_info.reg_2964, 0x02964);
+	write_reg(itv->yuv_info.reg_2968, 0x02968);
+	write_reg(itv->yuv_info.reg_296c, 0x0296c);
+	write_reg(itv->yuv_info.reg_2970, 0x02970);
+
+	/* Prepare to restore filters */
+
+	/* First the horizontal filter */
+	if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
+		/* An exact size match uses filter 0 */
+		h_filter = 0;
+	}
+	else {
+		/* Figure out which filter to use */
+		h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
+		h_filter = (h_filter >> 1) + (h_filter & 1);
+		/* Only an exact size match can use filter 0. */
+		if (h_filter < 1) h_filter = 1;
+	}
+
+	/* Now the vertical filter */
+	if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
+		/* An exact size match uses filter 0/1 */
+		v_filter_1 = 0;
+		v_filter_2 = 1;
+	}
+	else {
+		/* Figure out which filter to use */
+		v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
+		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
+		/* Only an exact size match can use filter 0 */
+		if (v_filter_1 == 0) v_filter_1 = 1;
+		v_filter_2 = v_filter_1;
+	}
+
+	/* Now restore the filters */
+	ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
+
+	/* and clear a few registers */
+	write_reg(0, 0x02814);
+	write_reg(0, 0x0282c);
+	write_reg(0, 0x02904);
+	write_reg(0, 0x02910);
+
+	/* Release the blanking buffer */
+	if (itv->yuv_info.blanking_ptr) {
+		kfree (itv->yuv_info.blanking_ptr);
+		itv->yuv_info.blanking_ptr = NULL;
+		pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+	}
+
+	/* Invalidate the old dimension information */
+	itv->yuv_info.old_frame_info.src_w = 0;
+	itv->yuv_info.old_frame_info.src_h = 0;
+	itv->yuv_info.old_frame_info_args.src_w = 0;
+	itv->yuv_info.old_frame_info_args.src_h = 0;
+
+	/* All done. */
+	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
+}
+
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
new file mode 100644
index 0000000..88972d3
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -0,0 +1,24 @@
+/*
+    yuv support
+
+    Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.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
+ */
+
+int ivtv_yuv_filter_check(struct ivtv *itv);
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
+void ivtv_yuv_close(struct ivtv *itv);
+void ivtv_yuv_work_handler (struct ivtv *itv);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 98681da..664aba8 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *i
 		if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
 			return -EINVAL;
 		mutex_lock(&meye.lock);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
 				      p->brightness >> 10);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
 				      p->hue >> 10);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
 				      p->colour >> 10);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
 				      p->contrast >> 10);
 		meye.picture = *p;
 		mutex_unlock(&meye.lock);
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *i
 		    meye.params.quality != jp->quality)
 			mchip_hic_stop();	/* need restart */
 		meye.params = *jp;
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
 				      meye.params.sharpness);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
 				      meye.params.agc);
-		sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
+		sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
 				      meye.params.picture);
 		mutex_unlock(&meye.lock);
 		break;
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *i
 		mutex_lock(&meye.lock);
 		switch (c->id) {
 		case V4L2_CID_BRIGHTNESS:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
 			meye.picture.brightness = c->value << 10;
 			break;
 		case V4L2_CID_HUE:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERAHUE, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
 			meye.picture.hue = c->value << 10;
 			break;
 		case V4L2_CID_CONTRAST:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERACONTRAST, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
 			meye.picture.contrast = c->value << 10;
 			break;
 		case V4L2_CID_SATURATION:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERACOLOR, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
 			meye.picture.colour = c->value << 10;
 			break;
 		case V4L2_CID_AGC:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERAAGC, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
 			meye.params.agc = c->value;
 			break;
 		case V4L2_CID_SHARPNESS:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERASHARPNESS, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
 			meye.params.sharpness = c->value;
 			break;
 		case V4L2_CID_PICTURE:
-			sonypi_camera_command(
-				SONYPI_COMMAND_SETCAMERAPICTURE, c->value);
+			sony_pic_camera_command(
+				SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
 			meye.params.picture = c->value;
 			break;
 		case V4L2_CID_JPEGQUAL:
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct p
 	memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
 	meye.video_dev->dev = &meye.mchip_dev->dev;
 
-	if ((ret = sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1))) {
+	if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
 		printk(KERN_ERR "meye: unable to power on the camera\n");
 		printk(KERN_ERR "meye: did you enable the camera in "
 				"sonypi using the module options ?\n");
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct p
 	meye.params.picture = 0;
 	meye.params.framerate = 0;
 
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0);
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
 
 	printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
 	       MEYE_DRIVER_VERSION);
@@ -1953,7 +1953,7 @@ outremap:
 outregions:
 	pci_disable_device(meye.mchip_dev);
 outenabledev:
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 outsonypienable:
 	kfifo_free(meye.doneq);
 outkfifoalloc2:
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct
 
 	pci_disable_device(meye.mchip_dev);
 
-	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+	sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 
 	kfifo_free(meye.doneq);
 	kfifo_free(meye.grabq);
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index ea107cb..323d007 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -255,7 +255,7 @@ #define MCHIP_VRJ_START_COMMAND		0x1a0
 /****************************************************************************/
 
 /* Sony Programmable I/O Controller for accessing the camera commands */
-#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
 
 /* private API definitions */
 #include <linux/meye.h>
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index ba1af3c..3bb7d66 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -773,6 +773,9 @@ #endif
 		break;
 	}
 
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2);
+
 	default:
 		/* unknown */
 		return -EINVAL;
@@ -872,6 +875,8 @@ static int msp_attach(struct i2c_adapter
 	snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d",
 			msp_family, msp_product,
 			msp_revision, msp_hard, msp_rom);
+	/* Rev B=2, C=3, D=4, G=7 */
+	state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@';
 
 	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
 	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index 7531efa..ab69a29 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -50,6 +50,7 @@ extern int msp_stereo_thresh;
 
 struct msp_state {
 	int rev1, rev2;
+	int ident;
 	u8 has_nicam;
 	u8 has_radio;
 	u8 has_headphones;
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 68b082b..18c6422 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -4,7 +4,6 @@ #define __LINUX_OV511_H
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 5ed0adc..03bc369 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -5,6 +5,8 @@
  * by Jonathan Corbet with substantial inspiration from Mark
  * McClelland's ovcamchip code.
  *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
  * This file may be distributed under the terms of the GNU General
  * Public License, version 2.
  */
@@ -15,6 +17,7 @@ #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <linux/i2c.h>
 
 
@@ -162,6 +165,10 @@ #define REG_CONTRAS	0x56	/* Contrast con
 
 #define REG_GFIX	0x69	/* Fix gain control */
 
+#define REG_REG76	0x76	/* OV's name */
+#define   R76_BLKPCOR	  0x80	  /* Black pixel correction enable */
+#define   R76_WHTPCOR	  0x40	  /* White pixel correction enable */
+
 #define REG_RGB444	0x8c	/* RGB 444 control */
 #define   R444_ENABLE	  0x02	  /* Turn on RGB444, overrides 5x5 */
 #define   R444_RGBX	  0x01	  /* Empty nibble at end */
@@ -255,7 +262,7 @@ static struct regval_list ov7670_default
 
 	/* Almost all of these are magic "reserved" values.  */
 	{ REG_COM5, 0x61 },	{ REG_COM6, 0x4b },
-	{ 0x16, 0x02 },		{ REG_MVFP, 0x07|MVFP_MIRROR },
+	{ 0x16, 0x02 },		{ REG_MVFP, 0x07 },
 	{ 0x21, 0x02 },		{ 0x22, 0x91 },
 	{ 0x29, 0x07 },		{ 0x33, 0x0b },
 	{ 0x35, 0x0b },		{ 0x37, 0x1d },
@@ -380,6 +387,13 @@ static struct regval_list ov7670_fmt_rgb
 	{ 0xff, 0xff },
 };
 
+static struct regval_list ov7670_fmt_raw[] = {
+	{ REG_COM7, COM7_BAYER },
+	{ REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */
+	{ REG_COM16, 0x3d }, /* Edge enhancement, denoise */
+	{ REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */
+	{ 0xff, 0xff },
+};
 
 
 
@@ -483,32 +497,39 @@ static struct ov7670_format_struct {
 	__u32 pixelformat;
 	struct regval_list *regs;
 	int cmatrix[CMATRIX_LEN];
+	int bpp;   /* Bytes per pixel */
 } ov7670_formats[] = {
 	{
 		.desc		= "YUYV 4:2:2",
 		.pixelformat	= V4L2_PIX_FMT_YUYV,
 		.regs 		= ov7670_fmt_yuv422,
 		.cmatrix	= { 128, -128, 0, -34, -94, 128 },
+		.bpp		= 2,
 	},
 	{
 		.desc		= "RGB 444",
 		.pixelformat	= V4L2_PIX_FMT_RGB444,
 		.regs		= ov7670_fmt_rgb444,
 		.cmatrix	= { 179, -179, 0, -61, -176, 228 },
+		.bpp		= 2,
 	},
 	{
 		.desc		= "RGB 565",
 		.pixelformat	= V4L2_PIX_FMT_RGB565,
 		.regs		= ov7670_fmt_rgb565,
 		.cmatrix	= { 179, -179, 0, -61, -176, 228 },
+		.bpp		= 2,
+	},
+	{
+		.desc		= "Raw RGB Bayer",
+		.pixelformat	= V4L2_PIX_FMT_SBGGR8,
+		.regs 		= ov7670_fmt_raw,
+		.cmatrix	= { 0, 0, 0, 0, 0, 0 },
+		.bpp		= 1
 	},
 };
-#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0]))
+#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)
 
-/*
- * All formats we support are 2 bytes/pixel.
- */
-#define BYTES_PER_PIXEL 2
 
 /*
  * Then there is the issue of window sizes.  Try to capture the info here.
@@ -685,7 +706,7 @@ static int ov7670_try_fmt(struct i2c_cli
 	 */
 	pix->width = wsize->width;
 	pix->height = wsize->height;
-	pix->bytesperline = pix->width*BYTES_PER_PIXEL;
+	pix->bytesperline = pix->width*ov7670_formats[index].bpp;
 	pix->sizeimage = pix->height*pix->bytesperline;
 	return 0;
 }
@@ -1270,9 +1291,8 @@ static int ov7670_command(struct i2c_cli
 		void *arg)
 {
 	switch (cmd) {
-	case VIDIOC_INT_G_CHIP_IDENT:
-		* (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670;
-		return 0;
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
 
 	case VIDIOC_INT_RESET:
 		ov7670_reset(client);
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 1231335..50c7763 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -15,6 +15,7 @@
 #ifndef __LINUX_OVCAMCHIP_PRIV_H
 #define __LINUX_OVCAMCHIP_PRIV_H
 
+#include <linux/i2c.h>
 #include <media/ovcamchip.h>
 
 #ifdef DEBUG
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 86d2884..1455a8f 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -2160,7 +2160,7 @@ static int find_planb(void)
 	if (!machine_is(powermac))
 		return 0;
 
-	planb_devices = find_devices("planb");
+	planb_devices = of_find_node_by_name(NULL, "planb");
 	if (planb_devices == 0) {
 		planb_num=0;
 		printk(KERN_WARNING "PlanB: no device found!\n");
@@ -2175,12 +2175,14 @@ static int find_planb(void)
 	if (planb_devices->n_addrs != 1) {
 		printk (KERN_WARNING "PlanB: expecting 1 address for planb "
 			"(got %d)", planb_devices->n_addrs);
+		of_node_put(planb_devices);
 		return 0;
 	}
 
 	if (planb_devices->n_intrs == 0) {
 		printk(KERN_WARNING "PlanB: no intrs for device %s\n",
 		       planb_devices->full_name);
+		of_node_put(planb_devices);
 		return 0;
 	} else {
 		irq = planb_devices->intrs[0].line;
@@ -2202,12 +2204,13 @@ static int find_planb(void)
 	confreg = planb_devices->addrs[0].space & 0xff;
 	old_base = planb_devices->addrs[0].address;
 	new_base = 0xf1000000;
+	of_node_put(planb_devices);
 
 	DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
 		"membase 0x%x (base reg. 0x%x)\n",
 		bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
 
-	pdev = pci_find_slot (bus, dev_fn);
+	pdev = pci_get_bus_and_slot(bus, dev_fn);
 	if (!pdev) {
 		printk(KERN_ERR "planb: cannot find slot\n");
 		goto err_out;
@@ -2237,6 +2240,7 @@ static int find_planb(void)
 	pb->planb_base = planb_regs;
 	pb->planb_base_phys = (struct planb_registers *)new_base;
 	pb->irq	= irq;
+	pb->dev = pdev;
 
 	return planb_num;
 
@@ -2244,6 +2248,7 @@ err_out_disable:
 	pci_disable_device(pdev);
 err_out:
 	/* FIXME handle error */   /* comment moved from pci_find_slot, above */
+	pci_dev_put(pdev);
 	return 0;
 }
 
@@ -2271,6 +2276,8 @@ static void release_planb(void)
 		printk(KERN_INFO "PlanB: unregistering with v4l\n");
 		video_unregister_device(&pb->video_dev);
 
+		pci_dev_put(pb->dev);
+
 		/* note that iounmap() does nothing on the PPC right now */
 		iounmap ((void *)pb->planb_base);
 	}
diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h
index 9282321..e21b573 100644
--- a/drivers/media/video/planb.h
+++ b/drivers/media/video/planb.h
@@ -177,6 +177,7 @@ struct planb {
 	struct mutex lock;
 	unsigned int	irq;			/* interrupt number */
 	volatile unsigned int intr_mask;
+	struct pci_dev *dev;			/* Our PCI device */
 
 	int	overlay;			/* overlay running? */
 	struct	planb_window win;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 5786faf..5669c8c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -324,7 +324,7 @@ static int pvr2_encoder_vcmd(struct pvr2
 
 /* This implements some extra setup for the encoder that seems to be
    specific to the PVR USB2 hardware. */
-int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
 {
 	int ret = 0;
 	int encMisc3Arg = 0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 16bd741..ce66ab8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -283,6 +283,8 @@ struct pvr2_hdw {
 	int unit_number;             /* ID for driver instance */
 	unsigned long serial_number; /* ID for hardware itself */
 
+	char bus_info[32]; /* Bus location info */
+
 	/* Minor numbers used by v4l logic (yes, this is a hack, as there
 	   should be no v4l junk here).  Probably a better way to do this. */
 	int v4l_minor_number_video;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 9916cf3..acf651e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1008,6 +1008,13 @@ unsigned long pvr2_hdw_get_sn(struct pvr
 	return hdw->serial_number;
 }
 
+
+const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
+{
+	return hdw->bus_info;
+}
+
+
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
 {
 	return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
@@ -2105,6 +2112,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct 
 	hdw->usb_intf = intf;
 	hdw->usb_dev = interface_to_usbdev(intf);
 
+	scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
+		  "usb %s address %d",
+		  hdw->usb_dev->dev.bus_id,
+		  hdw->usb_dev->devnum);
+
 	ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
 	usb_set_interface(hdw->usb_dev,ifnum,0);
 
@@ -3275,7 +3287,9 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 	mutex_lock(&hdw->i2c_list_lock); do {
 		list_for_each(item,&hdw->i2c_clients) {
 			cp = list_entry(item,struct pvr2_i2c_client,list);
-			if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) {
+			if (!v4l2_chip_match_i2c_client(
+				    cp->client,
+				    req.match_type, req.match_chip)) {
 				continue;
 			}
 			stat = pvr2_i2c_client_cmd(
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 0c9cca4..4dba8d0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -124,6 +124,9 @@ struct usb_device *pvr2_hdw_get_dev(stru
 /* Retrieve serial number of device */
 unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
 
+/* Retrieve bus location info of device */
+const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *);
+
 /* Called when hardware has been unplugged */
 void pvr2_hdw_disconnect(struct pvr2_hdw *);
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index e976c48..9ea41c6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -25,7 +25,6 @@ #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 91396fd..a741c55 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -42,9 +42,11 @@ #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC 
 	struct class_device_attribute attr_v4l_minor_number;
 	struct class_device_attribute attr_v4l_radio_minor_number;
 	struct class_device_attribute attr_unit_number;
+	struct class_device_attribute attr_bus_info;
 	int v4l_minor_number_created_ok;
 	int v4l_radio_minor_number_created_ok;
 	int unit_number_created_ok;
+	int bus_info_created_ok;
 };
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
@@ -705,6 +707,10 @@ #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
 	pvr2_sysfs_tear_down_debugifc(sfp);
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 	pvr2_sysfs_tear_down_controls(sfp);
+	if (sfp->bus_info_created_ok) {
+		class_device_remove_file(sfp->class_dev,
+					 &sfp->attr_bus_info);
+	}
 	if (sfp->v4l_minor_number_created_ok) {
 		class_device_remove_file(sfp->class_dev,
 					 &sfp->attr_v4l_minor_number);
@@ -735,6 +741,16 @@ static ssize_t v4l_minor_number_show(str
 }
 
 
+static ssize_t bus_info_show(struct class_device *class_dev,char *buf)
+{
+	struct pvr2_sysfs *sfp;
+	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	if (!sfp) return -EINVAL;
+	return scnprintf(buf,PAGE_SIZE,"%s\n",
+			 pvr2_hdw_get_bus_info(sfp->channel.hdw));
+}
+
+
 static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
 					   char *buf)
 {
@@ -836,6 +852,20 @@ static void class_dev_create(struct pvr2
 		sfp->unit_number_created_ok = !0;
 	}
 
+	sfp->attr_bus_info.attr.owner = THIS_MODULE;
+	sfp->attr_bus_info.attr.name = "bus_info_str";
+	sfp->attr_bus_info.attr.mode = S_IRUGO;
+	sfp->attr_bus_info.show = bus_info_show;
+	sfp->attr_bus_info.store = NULL;
+	ret = class_device_create_file(sfp->class_dev,
+				       &sfp->attr_bus_info);
+	if (ret < 0) {
+		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		       __FUNCTION__, ret);
+	} else {
+		sfp->bus_info_created_ok = !0;
+	}
+
 	pvr2_sysfs_add_controls(sfp);
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
 	pvr2_sysfs_add_debugifc(sfp);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 25d3830..4563b3d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -203,6 +203,8 @@ static int pvr2_v4l2_do_ioctl(struct ino
 		struct v4l2_capability *cap = arg;
 
 		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+		strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
+			sizeof(cap->bus_info));
 
 		ret = 0;
 		break;
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 0bd1155..338ced7 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -140,6 +140,8 @@ static const char *size2name[PSZ_MAX] =
    An alternate value of 0 means this mode is not available at all.
  */
 
+#define PWC_FPS_MAX_NALA 8
+
 struct Nala_table_entry {
 	char alternate;			/* USB alternate setting */
 	int compressed;			/* Compressed yes/no */
@@ -147,7 +149,9 @@ struct Nala_table_entry {
 	unsigned char mode[3];		/* precomputed mode table */
 };
 
-static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
+static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 };
+
+static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
 {
 #include "pwc-nala.h"
 };
@@ -423,6 +427,59 @@ int pwc_set_video_mode(struct pwc_device
 	return 0;
 }
 
+static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size)
+{
+	unsigned int i;
+
+	for (i = 0; i < PWC_FPS_MAX_NALA; i++) {
+		if (Nala_table[size][i].alternate) {
+			if (index--==0) return Nala_fps_vector[i];
+		}
+	}
+	return 0;
+}
+
+static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size)
+{
+	unsigned int i;
+
+	for (i = 0; i < PWC_FPS_MAX_KIARA; i++) {
+		if (Kiara_table[size][i][3].alternate) {
+			if (index--==0) return Kiara_fps_vector[i];
+		}
+	}
+	return 0;
+}
+
+static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size)
+{
+	unsigned int i;
+
+	for (i=0; i < PWC_FPS_MAX_TIMON; i++) {
+		if (Timon_table[size][i][3].alternate) {
+			if (index--==0) return Timon_fps_vector[i];
+		}
+	}
+	return 0;
+}
+
+unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size)
+{
+	unsigned int ret;
+
+	if (DEVICE_USE_CODEC1(pdev->type)) {
+		ret = pwc_get_fps_Nala(pdev, index, size);
+
+	} else if (DEVICE_USE_CODEC3(pdev->type)) {
+		ret = pwc_get_fps_Kiara(pdev, index, size);
+
+	} else {
+		ret = pwc_get_fps_Timon(pdev, index, size);
+	}
+
+	return ret;
+}
+
 #define BLACK_Y 0
 #define BLACK_U 128
 #define BLACK_V 128
@@ -1343,7 +1400,7 @@ int pwc_ioctl(struct pwc_device *pdev, u
 				ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
 				if (ret < 0)
 					break;
-				ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
+				ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
 				if (ret < 0)
 					break;
 			}
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 27ed769..085332a 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -95,8 +95,8 @@ static const struct usb_device_id pwc_de
 	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
 	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
 	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
-	{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
-	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
+	{ USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
+	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
 	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
 	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
 	{ USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
@@ -1493,7 +1493,7 @@ static int usb_pwc_probe(struct usb_inte
 		case 0x0329:
 			PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
 			name = "Philips SPC 900NC webcam";
-			type_id = 720;
+			type_id = 740;
 			break;
 		default:
 			return -ENODEV;
@@ -1547,8 +1547,16 @@ static int usb_pwc_probe(struct usb_inte
 			features |= FEATURE_MOTOR_PANTILT;
 			break;
 		case 0x08b6:
+			PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
+			name = "Cisco VT Camera";
+			type_id = 740; /* CCD sensor */
+			break;
 		case 0x08b7:
-		case 0x08b8:
+			PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
+			name = "Logitech ViewPort AV 100";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b8: /* Where this released? */
 			PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
 			name = "Logitech QuickCam (res.)";
 			type_id = 730; /* Assuming CMOS */
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
index 784bc72..cec6602 100644
--- a/drivers/media/video/pwc/pwc-ioctl.h
+++ b/drivers/media/video/pwc/pwc-ioctl.h
@@ -2,7 +2,7 @@ #ifndef PWC_IOCTL_H
 #define PWC_IOCTL_H
 
 /* (C) 2001-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
@@ -25,7 +25,7 @@ #define PWC_IOCTL_H
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/* This is pwc-ioctl.h belonging to PWC 8.12.1
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
    It contains structures and defines to communicate from user space
    directly to the driver.
  */
@@ -51,6 +51,9 @@ #define PWC_IOCTL_H
 	     ... 	the function
  */
 
+#include <linux/types.h>
+#include <linux/version.h>
+
 
  /* Enumeration of image sizes */
 #define PSZ_SQCIF	0x00
@@ -65,6 +68,8 @@ #define PSZ_MAX		6
 /* The frame rate is encoded in the video_window.flags parameter using
    the upper 16 bits, since some flags are defined nowadays. The following
    defines provide a mask and shift to filter out this value.
+   This value can also be passing using the private flag when using v4l2 and
+   VIDIOC_S_FMT ioctl.
 
    In 'Snapshot' mode the camera freezes its automatic exposure and colour
    balance controls.
@@ -73,6 +78,8 @@ #define PWC_FPS_SHIFT		16
 #define PWC_FPS_MASK		0x00FF0000
 #define PWC_FPS_FRMASK		0x003F0000
 #define PWC_FPS_SNAPSHOT	0x00400000
+#define PWC_QLT_MASK		0x03000000
+#define PWC_QLT_SHIFT		24
 
 
 /* structure for transferring x & y coordinates */
@@ -289,4 +296,29 @@ struct pwc_table_init_buffer {
 };
 #define VIDIOCPWCGVIDTABLE	_IOR('v', 216, struct pwc_table_init_buffer)
 
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+   __le16 type;		/* type of the webcam */
+   __le16 vbandlength;	/* Size of 4lines compressed (used by the decompressor) */
+   __u8   cmd[4];	/* the four byte of the command (in case of nala,
+			   only the first 3 bytes is filled) */
+   __u8   rawframe[0];	/* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
 #endif
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
index fec39cc..f4ae83c 100644
--- a/drivers/media/video/pwc/pwc-kiara.c
+++ b/drivers/media/video/pwc/pwc-kiara.c
@@ -42,6 +42,8 @@
 #include "pwc-kiara.h"
 #include "pwc-uncompress.h"
 
+const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 };
+
 const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
 {
    /* SQCIF */
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
index 0bdb225..047dad8 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/video/pwc/pwc-kiara.h
@@ -29,6 +29,8 @@ #define PWC_KIARA_H
 
 #include <media/pwc-ioctl.h>
 
+#define PWC_FPS_MAX_KIARA 6
+
 struct Kiara_table_entry
 {
 	char alternate;			/* USB alternate interface */
@@ -37,8 +39,9 @@ struct Kiara_table_entry
 	unsigned char mode[12];		/* precomputed mode settings for cam */
 };
 
-extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4];
 extern const unsigned int KiaraRomTable[8][2][16][8];
+extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA];
 
 #endif
 
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
index be65bdc..c56c174 100644
--- a/drivers/media/video/pwc/pwc-timon.c
+++ b/drivers/media/video/pwc/pwc-timon.c
@@ -40,7 +40,9 @@
 
 #include "pwc-timon.h"
 
-const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
+const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 };
+
+const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] =
 {
    /* SQCIF */
    {
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
index eef9e2c..a6e2222 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/video/pwc/pwc-timon.h
@@ -44,6 +44,8 @@ #define PWC_TIMON_H
 
 #include <media/pwc-ioctl.h>
 
+#define PWC_FPS_MAX_TIMON 6
+
 struct Timon_table_entry
 {
 	char alternate;			/* USB alternate interface */
@@ -52,9 +54,9 @@ struct Timon_table_entry
 	unsigned char mode[13];		/* precomputed mode settings for cam */
 };
 
-extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4];
 extern const unsigned int TimonRomTable [16][2][16][8];
-
+extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON];
 
 #endif
 
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index d5e6bc8..32fbe1a 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -1168,7 +1168,7 @@ #endif
 			buf->sequence = 0;
 			buf->memory = V4L2_MEMORY_MMAP;
 			buf->m.offset = pdev->fill_image * pdev->len_per_image;
-			buf->length = buf->bytesused;
+			buf->length = pdev->len_per_image;
 			pwc_next_image(pdev);
 
 			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
@@ -1193,6 +1193,64 @@ #endif
 			return 0;
 		}
 
+		case VIDIOC_ENUM_FRAMESIZES:
+		{
+			struct v4l2_frmsizeenum *fsize = arg;
+			unsigned int i = 0, index = fsize->index;
+
+			if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
+				for (i = 0; i < PSZ_MAX; i++) {
+					if (pdev->image_mask & (1UL << i)) {
+						if (!index--) {
+							fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+							fsize->discrete.width = pwc_image_sizes[i].x;
+							fsize->discrete.height = pwc_image_sizes[i].y;
+							return 0;
+						}
+					}
+				}
+			} else if (fsize->index == 0 &&
+				   ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
+				    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
+
+				fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+				fsize->discrete.width = pdev->abs_max.x;
+				fsize->discrete.height = pdev->abs_max.y;
+				return 0;
+			}
+			return -EINVAL;
+		}
+
+		case VIDIOC_ENUM_FRAMEINTERVALS:
+		{
+			struct v4l2_frmivalenum *fival = arg;
+			int size = -1;
+			unsigned int i;
+
+			for (i = 0; i < PSZ_MAX; i++) {
+				if (pwc_image_sizes[i].x == fival->width &&
+				    pwc_image_sizes[i].y == fival->height) {
+					size = i;
+					break;
+				}
+			}
+
+			/* TODO: Support raw format */
+			if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
+				return -EINVAL;
+			}
+
+			i = pwc_get_fps(pdev, fival->index, size);
+			if (!i)
+				return -EINVAL;
+
+			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+			fival->discrete.numerator = 1;
+			fival->discrete.denominator = i;
+
+			return 0;
+		}
+
 		default:
 			return pwc_ioctl(pdev, cmd, arg);
 	} /* ..switch */
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index e778a2b..acbb931 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -44,7 +44,7 @@ #define PWC_MAJOR	10
 #define PWC_MINOR	0
 #define PWC_EXTRAMINOR	12
 #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
-#define PWC_VERSION 	"10.0.12"
+#define PWC_VERSION 	"10.0.13"
 #define PWC_NAME 	"pwc"
 #define PFX		PWC_NAME ": "
 
@@ -85,7 +85,7 @@ #define PWC_WARNING(fmt, args...) printk
 #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
 #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
 
-#else /* if ! CONFIG_PWC_DEBUG */
+#else /* if ! CONFIG_USB_PWC_DEBUG */
 
 #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
 #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
@@ -287,6 +287,7 @@ void pwc_construct(struct pwc_device *pd
 /** Functions in pwc-ctrl.c */
 /* Request a certain video mode. Returns < 0 if not possible */
 extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size);
 /* Calculate the number of bytes per image (not frame) */
 extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
 extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index 44dc747..74839f9 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -36,7 +36,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 2ce3321..87c3144 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -39,7 +39,6 @@ #include <linux/major.h>
 #include <linux/slab.h>
 
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 4d5bbd8..2d18f00 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -45,6 +45,7 @@ #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
@@ -80,7 +81,7 @@ struct saa711x_state {
 	int sat;
 	int width;
 	int height;
-	enum v4l2_chip_ident ident;
+	u32 ident;
 	u32 audclk_freq;
 	u32 crystal_freq;
 	u8 ucgc;
@@ -1232,7 +1233,6 @@ static void saa711x_decode_vbi_line(stru
 static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct saa711x_state *state = i2c_get_clientdata(client);
-	int *iarg = arg;
 
 	/* ioctls to allow direct access to the saa7115 registers for testing */
 	switch (cmd) {
@@ -1437,9 +1437,8 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 	}
 #endif
 
-	case VIDIOC_INT_G_CHIP_IDENT:
-		*iarg = state->ident;
-		break;
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
 
 	default:
 		return -EINVAL;
@@ -1487,6 +1486,7 @@ static int saa711x_attach(struct i2c_ada
 	if (memcmp(name, "1f711", 5)) {
 		v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
 			address << 1, name);
+		kfree(client);
 		return 0;
 	}
 
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 269d711..80bf911 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -30,7 +30,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 654863d..9f98693 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -54,6 +54,7 @@ #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/saa7127.h>
 
 static int debug = 0;
@@ -234,7 +235,7 @@ static struct i2c_reg_value saa7127_init
 
 struct saa7127_state {
 	v4l2_std_id std;
-	enum v4l2_chip_ident ident;
+	u32 ident;
 	enum saa7127_input_type input_type;
 	enum saa7127_output_type output_type;
 	int video_enable;
@@ -550,12 +551,12 @@ static int saa7127_command(struct i2c_cl
 	struct v4l2_routing *route = arg;
 
 	switch (cmd) {
-	case VIDIOC_S_STD:
+	case VIDIOC_INT_S_STD_OUTPUT:
 		if (state->std == *(v4l2_std_id *)arg)
 			break;
 		return saa7127_set_std(client, *(v4l2_std_id *)arg);
 
-	case VIDIOC_G_STD:
+	case VIDIOC_INT_G_STD_OUTPUT:
 		*(v4l2_std_id *)arg = state->std;
 		break;
 
@@ -650,9 +651,8 @@ #endif
 		break;
 	}
 
-	case VIDIOC_INT_G_CHIP_IDENT:
-		*(enum v4l2_chip_ident *)arg = state->ident;
-		break;
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
 
 	default:
 		return -EINVAL;
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 59da79c..309dca3 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -46,6 +46,7 @@ config VIDEO_SAA7134_DVB
 	select DVB_NXT200X if !DVB_FE_CUSTOMISE
 	select DVB_TDA10086 if !DVB_FE_CUSTOMISE
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
+	select DVB_TDA827X if !DVB_FE_CUSTOMISE
 	select DVB_ISL6421 if !DVB_FE_CUSTOMISE
 	---help---
 	  This adds support for DVB cards based on the
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 89f3210..4ea479b 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1543,12 +1543,12 @@ struct saa7134_board saa7134_boards[] = 
 		},{
 			.name = name_comp1,
 			.vmux = 0,
-			.amux = LINE2,
+			.amux = LINE1,
 			.gpio = 0x02,
 		},{
 			.name = name_svideo,
 			.vmux = 6,
-			.amux = LINE2,
+			.amux = LINE1,
 			.gpio = 0x02,
 		}},
 		.radio = {
@@ -1778,17 +1778,19 @@ struct saa7134_board saa7134_boards[] = 
 	[SAA7134_BOARD_FLYDVBTDUO] = {
 		/* LifeView FlyDVB-T DUO */
 		/* "Nico Sabbi <nsabbi@tiscali.it>  Hartmut Hackmann hartmut.hackmann@t-online.de*/
-		.name           = "LifeView FlyDVB-T DUO",
+		.name           = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.gpiomask	= 0x00200000,
 		.mpeg           = SAA7134_MPEG_DVB,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
 			.amux = TV,
+			.gpio = 0x200000,	/* GPIO21=High for TV input */
 			.tv   = 1,
 		},{
 			.name = name_comp1,	/* Composite signal on S-Video input */
@@ -1803,6 +1805,11 @@ struct saa7134_board saa7134_boards[] = 
 			.vmux = 8,
 			.amux = LINE2,
 		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x000000,	/* GPIO21=Low for FM radio antenna */
+		},
 	},
 	[SAA7134_BOARD_PHILIPS_TOUGH] = {
 		.name           = "Philips TOUGH DVB-T reference design",
@@ -2546,8 +2553,9 @@ struct saa7134_board saa7134_boards[] = 
 		.radio_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 0,
 		.mpeg           = SAA7134_MPEG_DVB,
-		.gpiomask       = 1 << 21,
+		.gpiomask       = 0x0200000,
 		.inputs = {{
 			.name   = name_tv,
 			.vmux   = 1,
@@ -2624,7 +2632,7 @@ struct saa7134_board saa7134_boards[] = 
 		}},
 		.radio = {
 			.name   = name_radio,
-			.amux   = LINE1,
+			.amux   = TV,
 			.gpio   = 0x0200000,
 		},
 	},
@@ -3043,6 +3051,7 @@ struct saa7134_board saa7134_boards[] = 
 		.radio_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 1,
 		.mpeg           = SAA7134_MPEG_DVB,
 		.gpiomask       = 0x000200000,
 		.inputs         = {{
@@ -3289,6 +3298,115 @@ struct saa7134_board saa7134_boards[] = 
 			.amux   = LINE1,
 		}},
 	},
+	[SAA7134_BOARD_PHILIPS_TIGER_S] = {
+		.name           = "Philips Tiger - S Reference design",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = TV,
+			.gpio   = 0x0200000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_M102] = {
+		.name           = "Avermedia M102",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.gpiomask       = 1<<21,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 0,
+			.amux = LINE2,
+		},{
+			.name = name_svideo,
+			.vmux = 6,
+			.amux = LINE2,
+		}},
+	},
+	[SAA7134_BOARD_ASUS_P7131_4871] = {
+		.name           = "ASUS P7131 4871",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 0x0200000,
+		.inputs = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+			.gpio   = 0x0200000,
+		}},
+	},
+	[SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = {
+		.name           = "ASUSTeK P7131 Hybrid",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.tuner_config   = 2,
+		.gpiomask	= 1 << 21,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = TV,
+			.tv   = 1,
+			.gpio = 0x0000000,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_comp2,
+			.vmux = 0,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE2,
+			.gpio = 0x0200000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = TV,
+			.gpio = 0x0200000,
+		},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3914,7 +4032,7 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1043,
 		.subdevice    = 0x4876,
-		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -3958,6 +4076,30 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.subdevice    = 0x1175,
 		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCI,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf31e,
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_M102,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4E42,         /* MSI */
+		.subdevice    = 0x0306,         /* TV@nywhere DUO */
+		.driver_data  = SAA7134_BOARD_FLYDVBTDUO,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4871,
+		.driver_data  = SAA7134_BOARD_ASUS_P7131_4871,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1043,
+		.subdevice    = 0x4857,
+		.driver_data  = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3971,7 +4113,6 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.subdevice    = 0,
 		.driver_data  = SAA7134_BOARD_NOAUTO,
 	},{
-
 		/* --- default catch --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -4063,6 +4204,7 @@ int saa7134_board_init1(struct saa7134_d
 	case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
 	case SAA7134_BOARD_FLYDVBT_LR301:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_FLYDVBTDUO:
 	case SAA7134_BOARD_PROTEUS_2309:
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -4103,8 +4245,8 @@ int saa7134_board_init1(struct saa7134_d
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-		saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
-		saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
 		/* power-up tuner chip */
@@ -4137,6 +4279,11 @@ int saa7134_board_init1(struct saa7134_d
 		       "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
 		       dev->name,card(dev).name,dev->name,dev->name);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_M102:
+		/* enable tuner */
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
+		break;
 	}
 	return 0;
 }
@@ -4146,6 +4293,9 @@ int saa7134_board_init2(struct saa7134_d
 {
 	unsigned char buf;
 	int board;
+	struct tuner_setup tun_setup;
+	tun_setup.config = 0;
+	tun_setup.tuner_callback = saa7134_tuner_callback;
 
 	switch (dev->board) {
 	case SAA7134_BOARD_BMK_MPEX_NOTUNER:
@@ -4162,8 +4312,6 @@ int saa7134_board_init2(struct saa7134_d
 		dev->tuner_type = saa7134_boards[dev->board].tuner_type;
 
 		if (TUNER_ABSENT != dev->tuner_type) {
-				struct tuner_setup tun_setup;
-
 				tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
 				tun_setup.type = dev->tuner_type;
 				tun_setup.addr = ADDR_UNSET;
@@ -4173,7 +4321,6 @@ int saa7134_board_init2(struct saa7134_d
 		break;
 	case SAA7134_BOARD_MD7134:
 		{
-		struct tuner_setup tun_setup;
 		u8 subaddr;
 		u8 data[3];
 		int ret, tuner_t;
@@ -4245,7 +4392,6 @@ int saa7134_board_init2(struct saa7134_d
 		 * the channel decoder. We have to make it transparent to find it
 		 */
 		{
-		struct tuner_setup tun_setup;
 		u8 data[] = { 0x07, 0x02};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
@@ -4258,16 +4404,38 @@ int saa7134_board_init2(struct saa7134_d
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+		{
+		u8 data[] = { 0x3c, 0x33, 0x60};
+		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+		if(dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+			dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
+			printk(KERN_INFO "%s: Reconfigured board as %s\n",
+				dev->name, saa7134_boards[dev->board].name);
+		}
+		if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+			tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+			tun_setup.type = TUNER_PHILIPS_TDA8290;
+			tun_setup.addr = 0x4b;
+			tun_setup.config = 2;
+
+			saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+			data[2] = 0x68;
+		}
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
+		}
+		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
 		/* this is a hybrid board, initialize to analog mode
 		 * and configure firmware eeprom address
 		 */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x68};
+		u8 data[] = { 0x3c, 0x33, 0x60};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
@@ -4281,18 +4449,18 @@ int saa7134_board_init2(struct saa7134_d
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
 	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
-		/* make the tda10046 find its eeprom */
+		/* initialize analog mode  */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x62};
+		u8 data[] = { 0x3c, 0x33, 0x6a};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		/* make the tda10046 find its eeprom */
+		/* initialize analog mode */
 		{
-		u8 data[] = { 0x3c, 0x33, 0x60};
+		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);
 		}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index ed038ff..25f8470 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -117,6 +117,64 @@ void saa7134_track_gpio(struct saa7134_d
 	       dev->name, mode, (~mode) & status, mode & status, msg);
 }
 
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value)
+{
+	u32 index, bitval;
+
+	index = 1 << bit_no;
+	switch (value) {
+	case 0: /* static value */
+	case 1:	dprintk("setting GPIO%d to static %d\n", bit_no, value);
+		/* turn sync mode off if necessary */
+		if (index & 0x00c00000)
+			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00);
+		if (value)
+			bitval = index;
+		else
+			bitval = 0;
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index);
+		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval);
+		break;
+	case 3:	/* tristate */
+		dprintk("setting GPIO%d to tristate\n", bit_no);
+		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0);
+		break;
+	}
+}
+
+int saa7134_tuner_callback(void *ptr, int command, int arg)
+{
+	u8 sync_control;
+	struct saa7134_dev *dev = ptr;
+
+	switch (dev->tuner_type) {
+	case TUNER_PHILIPS_TDA8290:
+		switch (command) {
+		case 0: /* switch LNA gain through GPIO 22*/
+			saa7134_set_gpio(dev, 22, arg) ;
+			break;
+		case 1: /* vsync output at GPIO22. 50 / 60Hz */
+			dprintk("setting GPIO22 to vsync %d\n", arg);
+			saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
+			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
+			if (arg == 1)
+				sync_control = 11;
+			else
+				sync_control = 17;
+			saa_writeb(SAA7134_VGATE_START, sync_control);
+			saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
+			saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -ENODEV;
+	}
+	return 0;
+}
+
 /* ------------------------------------------------------------------ */
 
 
@@ -124,55 +182,28 @@ void saa7134_track_gpio(struct saa7134_d
 /* delayed request_module                                      */
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
-static int need_empress;
-static int need_dvb;
-static int need_alsa;
-static int need_oss;
 
-static int pending_call(struct notifier_block *self, unsigned long state,
-			void *module)
-{
-	if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
-		return NOTIFY_DONE;
 
-	if (need_empress)
+static void request_module_async(struct work_struct *work){
+	struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk);
+	if (card_is_empress(dev))
 		request_module("saa7134-empress");
-	if (need_dvb)
+	if (card_is_dvb(dev))
 		request_module("saa7134-dvb");
-	if (need_alsa)
+	if (alsa)
 		request_module("saa7134-alsa");
-	if (need_oss)
+	if (oss)
 		request_module("saa7134-oss");
-	return NOTIFY_DONE;
 }
 
-static int pending_registered;
-static struct notifier_block pending_notifier = {
-	.notifier_call = pending_call,
-};
-
-static void request_module_depend(char *name, int *flag)
+static void request_submodules(struct saa7134_dev *dev)
 {
-	int err;
-	switch (THIS_MODULE->state) {
-	case MODULE_STATE_COMING:
-		if (!pending_registered) {
-			err = register_module_notifier(&pending_notifier);
-			pending_registered = 1;
-		}
-		*flag = 1;
-		break;
-	case MODULE_STATE_LIVE:
-		request_module(name);
-		break;
-	default:
-		/* nothing */;
-		break;
-	}
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
 }
 
 #else
-#define request_module_depend(name,flag)
+#define request_submodules(dev)
 #endif /* CONFIG_MODULES */
 
 /* ------------------------------------------------------------------ */
@@ -703,7 +734,6 @@ static int saa7134_hwfini(struct saa7134
 		saa7134_ts_fini(dev);
 	saa7134_input_fini(dev);
 	saa7134_vbi_fini(dev);
-	saa7134_video_fini(dev);
 	saa7134_tvaudio_fini(dev);
 	return 0;
 }
@@ -944,18 +974,9 @@ #endif
 		request_module("tuner");
 	if (card_is_empress(dev)) {
 		request_module("saa6752hs");
-		request_module_depend("saa7134-empress",&need_empress);
 	}
 
-	if (card_is_dvb(dev))
-		request_module_depend("saa7134-dvb",&need_dvb);
-
-
-	if (alsa)
-		request_module_depend("saa7134-alsa",&need_alsa);
-
-	if (oss)
-		request_module_depend("saa7134-oss",&need_oss);
+	request_submodules(dev);
 
 	v4l2_prio_init(&dev->prio);
 
@@ -1013,6 +1034,9 @@ #endif
 		saa7134_dmasound_init(dev);
 	}
 
+	if (TUNER_ABSENT != dev->tuner_type)
+		saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
 	return 0;
 
  fail4:
@@ -1152,10 +1176,6 @@ #endif
 
 static void saa7134_fini(void)
 {
-#if defined(CONFIG_MODULES) && defined(MODULE)
-	if (pending_registered)
-		unregister_module_notifier(&pending_notifier);
-#endif /* CONFIG_MODULES */
 	pci_unregister_driver(&saa7134_pci_driver);
 }
 
@@ -1164,6 +1184,7 @@ module_exit(saa7134_fini);
 
 /* ----------------------------------------------------------- */
 
+EXPORT_SYMBOL(saa7134_set_gpio);
 EXPORT_SYMBOL(saa7134_i2c_call_clients);
 EXPORT_SYMBOL(saa7134_devlist);
 EXPORT_SYMBOL(saa7134_boards);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e3059fd..65aec88 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -41,7 +41,9 @@ #include "nxt200x.h"
 
 #include "tda10086.h"
 #include "tda826x.h"
+#include "tda827x.h"
 #include "isl6421.h"
+
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
@@ -54,7 +56,21 @@ static int use_frontend = 0;
 module_param(use_frontend, int, 0644);
 MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
 
-/* ------------------------------------------------------------------ */
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
+
+#define dprintk(fmt, arg...)	do { if (debug) \
+	printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
+
+/* Print a warning */
+#define wprintk(fmt, arg...) \
+	printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
 static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
 {
 	u32 ok;
@@ -75,8 +91,7 @@ static int pinnacle_antenna_pwr(struct s
 	saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 28));
 	udelay(10);
 	ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
-	printk("%s: %s %s\n", dev->name, __FUNCTION__,
-	       ok ? "on" : "off");
+	dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off");
 
 	if (!ok)
 		saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2,   (1 << 26));
@@ -96,7 +111,7 @@ static int mt352_pinnacle_init(struct dv
 	static u8 irq_cfg []       = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
 	struct saa7134_dev *dev= fe->dvb->priv;
 
-	printk("%s: %s called\n",dev->name,__FUNCTION__);
+	dprintk("%s called\n", __FUNCTION__);
 
 	mt352_write(fe, clock_config,   sizeof(clock_config));
 	udelay(200);
@@ -185,10 +200,26 @@ static struct mt352_config avermedia_777
 	.demod_init    = mt352_aver777_init,
 };
 
-/* ------------------------------------------------------------------ */
-static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+/* ==================================================================
+ * tda1004x based DVB-T cards, helper functions
+ */
+
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
+					   const struct firmware **fw, char *name)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	return request_firmware(fw, name, &dev->pci->dev);
+}
+
+/* ------------------------------------------------------------------
+ * these tuners are tu1216, td1316(a)
+ */
+
+static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	u8 tuner_buf[4];
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
 			sizeof(tuner_buf) };
@@ -263,15 +294,20 @@ static int philips_tda6651_pll_set(u8 ad
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		wprintk("could not write to tuner at addr: 0x%02x\n",
+			addr << 1);
 		return -EIO;
+	}
 	msleep(1);
 	return 0;
 }
 
-static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+static int philips_tu1216_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
 	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
 
@@ -287,46 +323,17 @@ static int philips_tda6651_pll_init(u8 a
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe)
-{
-	return philips_tda6651_pll_init(0x60, fe);
-}
-
-static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	return philips_tda6651_pll_set(0x60, fe, params);
-}
-
-static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
-					   const struct firmware **fw, char *name)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	return request_firmware(fw, name, &dev->pci->dev);
-}
-
 static struct tda1004x_config philips_tu1216_60_config = {
-
 	.demod_address = 0x8,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe)
-{
-	return philips_tda6651_pll_init(0x61, fe);
-}
-
-static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	return philips_tda6651_pll_set(0x61, fe, params);
-}
-
 static struct tda1004x_config philips_tu1216_61_config = {
 
 	.demod_address = 0x8,
@@ -335,7 +342,8 @@ static struct tda1004x_config philips_tu
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_DEFAULT,
 	.if_freq       = TDA10046_FREQ_3617,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
@@ -343,24 +351,42 @@ static struct tda1004x_config philips_tu
 static int philips_td1316_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
-	struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+	struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
 
 	/* setup PLL configuration */
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
 		return -EIO;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
 	return 0;
 }
 
 static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
-	return philips_tda6651_pll_set(0x61, fe, params);
+	return philips_tda6651_pll_set(fe, params);
 }
 
+static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
+{
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
+	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+	struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	/* switch the tuner to analog mode */
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1);
+	if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+		return -EIO;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
 static int philips_europa_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
@@ -380,18 +406,14 @@ static int philips_europa_tuner_init(str
 static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
-	/* this message actually turns the tuner back to analog mode */
-	static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
-	struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
 
-	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
-	msleep(1);
+	static u8 msg[] = { 0x00, 0x14 };
+	struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+	if (philips_td1316_tuner_sleep(fe))
+		return -EIO;
 
 	/* switch the board to analog mode */
-	analog_msg.addr = 0x43;
-	analog_msg.len  = 0x02;
-	msg[0] = 0x00;
-	msg[1] = 0x14;
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
@@ -416,7 +438,8 @@ static struct tda1004x_config philips_eu
 	.xtal_freq     = TDA10046_XTAL_4M,
 	.agc_config    = TDA10046_AGC_IFO_AUTO_POS,
 	.if_freq       = TDA10046_FREQ_052,
-	.request_firmware = NULL,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
 /* ------------------------------------------------------------------ */
@@ -424,9 +447,11 @@ static struct tda1004x_config philips_eu
 static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	/* this message is to set up ATC and ALC */
 	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -440,9 +465,11 @@ static int philips_fmd1216_tuner_init(st
 static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	/* this message actually turns the tuner back to analog mode */
-	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+	u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
@@ -460,8 +487,10 @@ static int philips_fmd1216_tuner_sleep(s
 static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->tuner_address;
 	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len =
+	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
 			sizeof(tuner_buf) };
 	int tuner_frequency = 0;
 	int divider = 0;
@@ -536,8 +565,11 @@ static int philips_fmd1216_tuner_set_par
 
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+		wprintk("could not write to tuner at addr: 0x%02x\n",
+			addr << 1);
 		return -EIO;
+	}
 	return 0;
 }
 
@@ -548,582 +580,365 @@ static struct tda1004x_config medion_car
 	.xtal_freq     = TDA10046_XTAL_16M,
 	.agc_config    = TDA10046_AGC_IFO_AUTO_NEG,
 	.if_freq       = TDA10046_FREQ_3613,
-	.request_firmware = NULL,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-struct tda827x_data {
-	u32 lomax;
-	u8  spd;
-	u8  bs;
-	u8  bp;
-	u8  cp;
-	u8  gc3;
-	u8 div1p5;
-};
-
-static struct tda827x_data tda827x_dvbt[] = {
-	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
-	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-	{ .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
-	{ .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
-	{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
-	{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
-	{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
-	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
-};
-
-static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
-{
-	return 0;
-}
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
 
-static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high)
 {
 	struct saa7134_dev *dev = fe->dvb->priv;
-	u8 tuner_buf[14];
-
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
-					.len = sizeof(tuner_buf) };
-	int i, tuner_freq, if_freq;
-	u32 N;
-	switch (params->u.ofdm.bandwidth) {
-	case BANDWIDTH_6_MHZ:
-		if_freq = 4000000;
-		break;
-	case BANDWIDTH_7_MHZ:
-		if_freq = 4500000;
-		break;
-	default:		   /* 8 MHz or Auto */
-		if_freq = 5000000;
-		break;
-	}
-	tuner_freq = params->frequency + if_freq;
-
-	i = 0;
-	while (tda827x_dvbt[i].lomax < tuner_freq) {
-		if(tda827x_dvbt[i + 1].lomax == 0)
-			break;
-		i++;
+	struct tda1004x_state *state = fe->demodulator_priv;
+	u8 addr = state->config->i2c_gate;
+	u8 config = state->config->tuner_config;
+	u8 GP00_CF[] = {0x20, 0x01};
+	u8 GP00_LEV[] = {0x22, 0x00};
+
+	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2};
+	if (config) {
+		if (high) {
+			dprintk("setting LNA to high gain\n");
+		} else {
+			dprintk("setting LNA to low gain\n");
+		}
 	}
-
-	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
-	tuner_buf[0] = 0;
-	tuner_buf[1] = (N>>8) | 0x40;
-	tuner_buf[2] = N & 0xff;
-	tuner_buf[3] = 0;
-	tuner_buf[4] = 0x52;
-	tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
-				   (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
-	tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
-	tuner_buf[7] = 0xbf;
-	tuner_buf[8] = 0x2a;
-	tuner_buf[9] = 0x05;
-	tuner_buf[10] = 0xff;
-	tuner_buf[11] = 0x00;
-	tuner_buf[12] = 0x00;
-	tuner_buf[13] = 0x40;
-
-	tuner_msg.len = 14;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-	msleep(500);
-	/* correct CP value */
-	tuner_buf[0] = 0x30;
-	tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
-	tuner_msg.len = 2;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
-	return 0;
-}
-
-static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 tda827x_sleep[] = { 0x30, 0xd0};
-	struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
-				    .len = sizeof(tda827x_sleep) };
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-	return 0;
-}
-
-static struct tda1004x_config tda827x_lifeview_config = {
-	.demod_address = 0x08,
-	.invert        = 1,
-	.invert_oclk   = 0,
-	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
-	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
-};
-
-/* ------------------------------------------------------------------ */
-
-struct tda827xa_data {
-	u32 lomax;
-	u8  svco;
-	u8  spd;
-	u8  scr;
-	u8  sbs;
-	u8  gc3;
-};
-
-static struct tda827xa_data tda827xa_dvbt[] = {
-	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
-	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
-	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
-	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
-	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
-	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
-	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
-	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
-	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
-
-
-static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	u8 tuner_buf[14];
-	unsigned char reg2[2];
-
-	struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
-	int i, tuner_freq, if_freq;
-	u32 N;
-
-	switch (params->u.ofdm.bandwidth) {
-	case BANDWIDTH_6_MHZ:
-		if_freq = 4000000;
+	switch (config) {
+	case 0: /* no LNA */
 		break;
-	case BANDWIDTH_7_MHZ:
-		if_freq = 4500000;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync off */
+		saa7134_set_gpio(dev, 22, 0);
+		GP00_LEV[1] = high ? 0 : 1;
+		if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+			wprintk("could not access tda8290 at addr: 0x%02x\n",
+				addr << 1);
+			return;
+		}
+		msg.buf = GP00_LEV;
+		if (config == 2)
+			GP00_LEV[1] = high ? 1 : 0;
+		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		break;
-	default:		   /* 8 MHz or Auto */
-		if_freq = 5000000;
+	case 3: /* switch with GPIO of saa713x */
+		saa7134_set_gpio(dev, 22, high);
 		break;
 	}
-	tuner_freq = params->frequency + if_freq;
-
-	i = 0;
-	while (tda827xa_dvbt[i].lomax < tuner_freq) {
-		if(tda827xa_dvbt[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
-	tuner_buf[0] = 0;            // subaddress
-	tuner_buf[1] = N >> 8;
-	tuner_buf[2] = N & 0xff;
-	tuner_buf[3] = 0;
-	tuner_buf[4] = 0x16;
-	tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
-			tda827xa_dvbt[i].sbs;
-	tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
-	tuner_buf[7] = 0x0c;
-	tuner_buf[8] = 0x06;
-	tuner_buf[9] = 0x24;
-	tuner_buf[10] = 0xff;
-	tuner_buf[11] = 0x60;
-	tuner_buf[12] = 0x00;
-	tuner_buf[13] = 0x39;  // lpsel
-	msg.len = 14;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-
-	msg.buf= reg2;
-	msg.len = 2;
-	reg2[0] = 0x60;
-	reg2[1] = 0x3c;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-	reg2[0] = 0xa0;
-	reg2[1] = 0x40;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-	msleep(2);
-	/* correct CP value */
-	reg2[0] = 0x30;
-	reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
-	msg.len = 2;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-	msleep(550);
-	reg2[0] = 0x50;
-	reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-
-	return 0;
-
 }
 
-static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
 {
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 tda827xa_sleep[] = { 0x30, 0x90};
-	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
-				    .len = sizeof(tda827xa_sleep) };
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 0);
-	return 0;
-}
+	struct tda1004x_state *state = fe->demodulator_priv;
 
-/* ------------------------------------------------------------------ */
-
-static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
+	u8 addr = state->config->i2c_gate;
 	static u8 tda8290_close[] = { 0x21, 0xc0};
 	static u8 tda8290_open[]  = { 0x21, 0x80};
-	struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+	struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
 	if (enable) {
 		tda8290_msg.buf = tda8290_close;
 	} else {
 		tda8290_msg.buf = tda8290_open;
 	}
-	if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1)
+	if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) {
+		struct saa7134_dev *dev = fe->dvb->priv;
+		wprintk("could not access tda8290 I2C gate\n");
 		return -EIO;
+	}
 	msleep(20);
 	return 0;
 }
 
 /* ------------------------------------------------------------------ */
 
-static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
 {
-	int ret;
+	struct saa7134_dev *dev = fe->dvb->priv;
+	struct tda1004x_state *state = fe->demodulator_priv;
 
-	ret = philips_tda827xa_pll_set(0x61, fe, params);
-	if (ret != 0)
-		return ret;
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	}
 	return 0;
 }
 
-static int philips_tiger_tuner_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(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)};
+	struct tda1004x_state *state = fe->demodulator_priv;
 
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
+	switch (state->config->antenna_switch) {
+	case 0: break;
+	case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n");
+		saa7134_set_gpio(dev, 21, 1);
+		break;
+	case 2:	dprintk("setting GPIO21 to 0 (TV antenna?)\n");
+		saa7134_set_gpio(dev, 21, 0);
+		break;
+	}
 	return 0;
 }
 
-static int philips_tiger_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)};
+static struct tda827x_config tda827x_cfg = {
+	.lna_gain = philips_tda827x_lna_gain,
+	.init = philips_tda827x_tuner_init,
+	.sleep = philips_tda827x_tuner_sleep
+};
 
-	i2c_transfer(&dev->i2c_adap, &msg, 1);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
+static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf)
+{
+	dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap);
+	if (dev->dvb.frontend) {
+		if (tda_conf->i2c_gate)
+			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+		if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address,
+						&dev->i2c_adap,&tda827x_cfg) == NULL) {
+			wprintk("no tda827x tuner found at addr: %02x\n",
+				tda_conf->tuner_address);
+		}
+	}
 }
 
-static struct tda1004x_config philips_tiger_config = {
+/* ------------------------------------------------------------------ */
+static struct tda1004x_config tda827x_lifeview_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
-/* ------------------------------------------------------------------ */
-
-static int cinergy_ht_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x62};
-	struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
 
-	if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
-		return -EIO;
-	return 0;
-}
-
-static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	static u8 data[] = { 0x3c, 0x33, 0x60};
-	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 struct tda1004x_config philips_tiger_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
 static struct tda1004x_config cinergy_ht_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP01,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config cinergy_ht_pci_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
-static struct tda1004x_config pinnacle_pctv_310i_config = {
+static struct tda1004x_config philips_tiger_s_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 2,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
 static struct tda1004x_config hauppauge_hvr_1110_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
 static struct tda1004x_config asus_p7131_dual_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = philips_tda1004x_request_firmware,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 0,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-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;
-
-	ret = philips_tda827xa_pll_set(0x60, fe, params);
-	return ret;
-}
-
-static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
-{
-	philips_tda827xa_tuner_sleep(0x60, fe);
-	return 0;
-}
-
 static struct tda1004x_config lifeview_trio_config = {
 	.demod_address = 0x09,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP00,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP00_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-
-	ret = philips_tda827xa_pll_set(0x61, fe, params);
-	return ret;
-}
-
-static int ads_duo_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	/* route TDA8275a AGC input to the channel decoder */
-	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60);
-	return 0;
-}
-
-static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	/* route TDA8275a AGC input to the analog IF chip*/
-	saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
-
-static struct tda1004x_config ads_tech_duo_config = {
+static struct tda1004x_config tevion_dvbt220rf_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP00,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.tuner_address = 0x60,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
-
-static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	int ret;
-	ret = philips_tda827xa_pll_set(0x60, fe, params);
-	return ret;
-}
-
-static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
-{
-	philips_tda827xa_tuner_sleep( 0x61, fe);
-	return 0;
-}
+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,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.tuner_config  = 0,
+	.request_firmware = philips_tda1004x_request_firmware
+};
 
-static struct tda1004x_config tevion_dvbt220rf_config = {
+static struct tda1004x_config asus_p7131_4871_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 2,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
-/* ------------------------------------------------------------------ */
+static struct tda1004x_config asus_p7131_hybrid_lna_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP11_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x61,
+	.tuner_config  = 2,
+	.antenna_switch= 2,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
 
-static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(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);
+	philips_tda827x_tuner_init(fe);
+	/* route TDA8275a AGC input to the channel decoder */
+	saa7134_set_gpio(dev, 22, 1);
 	return 0;
 }
 
-static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
 {
-	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;
+	/* route TDA8275a AGC input to the analog IF chip*/
+	saa7134_set_gpio(dev, 22, 0);
+	philips_tda827x_tuner_sleep(fe);
+	return 0;
 }
 
-static struct tda1004x_config md8800_dvbt_config = {
+static struct tda827x_config ads_duo_cfg = {
+	.lna_gain = philips_tda827x_lna_gain,
+	.init = ads_duo_tuner_init,
+	.sleep = ads_duo_tuner_sleep
+};
+
+static struct tda1004x_config ads_tech_duo_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
 	.invert_oclk   = 0,
 	.xtal_freq     = TDA10046_XTAL_16M,
-	.agc_config    = TDA10046_AGC_TDA827X_GP11,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP00_I,
 	.if_freq       = TDA10046_FREQ_045,
-	.request_firmware = NULL,
+	.tuner_address = 0x61,
+	.request_firmware = philips_tda1004x_request_firmware
 };
 
+/* ==================================================================
+ * tda10086 based DVB-S cards, helper functions
+ */
+
 static struct tda10086_config flydvbs = {
 	.demod_address = 0x0e,
 	.invert = 0,
 };
 
-/* ------------------------------------------------------------------ */
+/* ==================================================================
+ * nxt200x based ATSC cards, helper functions
+ */
 
 static struct nxt200x_config avertvhda180 = {
 	.demod_address    = 0x0a,
@@ -1143,10 +958,13 @@ static struct nxt200x_config kworldatsc1
 	.set_pll_input    = nxt200x_set_pll_input,
 };
 
-/* ------------------------------------------------------------------ */
+/* ==================================================================
+ * Core code
+ */
 
 static int dvb_init(struct saa7134_dev *dev)
 {
+	int ret;
 	/* init struct videobuf_dvb */
 	dev->ts.nr_bufs    = 32;
 	dev->ts.nr_packets = 32*4;
@@ -1160,7 +978,7 @@ static int dvb_init(struct saa7134_dev *
 
 	switch (dev->board) {
 	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
-		printk("%s: pinnacle 300i dvb setup\n",dev->name);
+		dprintk("pinnacle 300i dvb setup\n");
 		dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
@@ -1169,7 +987,7 @@ static int dvb_init(struct saa7134_dev *
 		break;
 	case SAA7134_BOARD_AVERMEDIA_777:
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
-		printk("%s: avertv 777 dvb setup\n",dev->name);
+		dprintk("avertv 777 dvb setup\n");
 		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
@@ -1191,42 +1009,15 @@ static int dvb_init(struct saa7134_dev *
 					       &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;
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBTDUO:
-		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;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
-		break;
 	case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
-		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;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &tda827x_lifeview_config);
 		break;
 	case SAA7134_BOARD_PHILIPS_EUROPA:
-		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_300:
 		dev->dvb.frontend = dvb_attach(tda10046_attach,
 					       &philips_europa_config,
@@ -1244,125 +1035,61 @@ static int dvb_init(struct saa7134_dev *
 					       &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;
+			dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &philips_tiger_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			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.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &philips_tiger_config);
 		break;
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &pinnacle_pctv_310i_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			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.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &pinnacle_pctv_310i_config);
 		break;
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &hauppauge_hvr_1110_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			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.set_params = philips_tiger_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &hauppauge_hvr_1110_config);
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &asus_p7131_dual_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			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;
-		}
+		configure_tda827x_fe(dev, &asus_p7131_dual_config);
 		break;
 	case SAA7134_BOARD_FLYDVBT_LR301:
-		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;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
-		}
+		configure_tda827x_fe(dev, &tda827x_lifeview_config);
 		break;
 	case SAA7134_BOARD_FLYDVB_TRIO:
 		if(! use_frontend) {	//terrestrial
-			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;
-			}
+			configure_tda827x_fe(dev, &lifeview_trio_config);
 		} else {  	      //satellite
 			dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
 			if (dev->dvb.frontend) {
 				if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
 									&dev->i2c_adap, 0) == NULL) {
-					printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+					wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
 				}
 				if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
 										0x08, 0, 0) == NULL) {
-					printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+					wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
 				}
 			}
 		}
 		break;
 	case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+	case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
 		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;
+			if (dvb_attach(tda827x_attach,dev->dvb.frontend,
+				   ads_tech_duo_config.tuner_address,
+				   &dev->i2c_adap,&ads_duo_cfg) == NULL) {
+				wprintk("no tda827x tuner found at addr: %02x\n",
+					ads_tech_duo_config.tuner_address);
+			}
 		}
 		break;
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
-		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 = 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;
-		}
+		configure_tda827x_fe(dev, &tevion_dvbt220rf_config);
 		break;
 	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;
-		}
+		configure_tda827x_fe(dev, &md8800_dvbt_config);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
 		dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
@@ -1386,11 +1113,11 @@ static int dvb_init(struct saa7134_dev *
 		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__);
+				wprintk("%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__);
+				wprintk("%s: No ISL6421 found!\n", __FUNCTION__);
 			}
 		}
 		break;
@@ -1415,41 +1142,45 @@ static int dvb_init(struct saa7134_dev *
 		}
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCMCIA:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &cinergy_ht_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
-
-		}
+		configure_tda827x_fe(dev, &cinergy_ht_config);
 		break;
 	case SAA7134_BOARD_CINERGY_HT_PCI:
-		dev->dvb.frontend = dvb_attach(tda10046_attach,
-					       &cinergy_ht_config,
-					       &dev->i2c_adap);
-		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
-			dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
-
-		}
+		configure_tda827x_fe(dev, &cinergy_ht_pci_config);
+		break;
+	case SAA7134_BOARD_PHILIPS_TIGER_S:
+		configure_tda827x_fe(dev, &philips_tiger_s_config);
+		break;
+	case SAA7134_BOARD_ASUS_P7131_4871:
+		configure_tda827x_fe(dev, &asus_p7131_4871_config);
+		break;
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+		configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
 		break;
 	default:
-		printk("%s: Huh? unknown DVB card?\n",dev->name);
+		wprintk("Huh? unknown DVB card?\n");
 		break;
 	}
 
 	if (NULL == dev->dvb.frontend) {
-		printk("%s: frontend initialization failed\n",dev->name);
+		printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
 		return -1;
 	}
 
 	/* register everything else */
-	return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+	ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+
+	/* this sequence is necessary to make the tda1004x load its firmware
+	 * and to enter analog mode of hybrid boards
+	 */
+	if (!ret) {
+		if (dev->dvb.frontend->ops.init)
+			dev->dvb.frontend->ops.init(dev->dvb.frontend);
+		if (dev->dvb.frontend->ops.sleep)
+			dev->dvb.frontend->ops.sleep(dev->dvb.frontend);
+		if (dev->dvb.frontend->ops.tuner_ops.sleep)
+			dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend);
+	}
+	return ret;
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index cce8da6..1cb8c70 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -370,6 +370,8 @@ static int attach_inform(struct i2c_clie
 
 		tun_setup.type = tuner;
 		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+		tun_setup.config = saa7134_boards[dev->board].tuner_config;
+		tun_setup.tuner_callback = saa7134_tuner_callback;
 
 		if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
 
@@ -445,7 +447,7 @@ static void do_i2c_scan(char *name, stru
 	unsigned char buf;
 	int i,rc;
 
-	for (i = 0; i < 128; i++) {
+	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
 		c->addr = i;
 		rc = i2c_master_recv(c,&buf,0);
 		if (rc < 0)
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 46c583f..c0de37e 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -321,6 +321,7 @@ int saa7134_input_init1(struct saa7134_d
 		mask_keydown = 0x0040000;
 		break;
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 		ir_codes     = ir_codes_asus_pc39;
 		mask_keydown = 0x0040000;
 		rc5_gpio = 1;
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index dd759d6..7b56041 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -27,7 +27,6 @@ #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
 #include <asm/div64.h>
 
 #include "saa7134-reg.h"
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index f2cb630..9985ded 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -26,6 +26,7 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/sort.h>
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
@@ -516,14 +517,12 @@ static int res_get(struct saa7134_dev *d
 	return 1;
 }
 
-static
-int res_check(struct saa7134_fh *fh, unsigned int bit)
+static int res_check(struct saa7134_fh *fh, unsigned int bit)
 {
 	return (fh->resources & bit);
 }
 
-static
-int res_locked(struct saa7134_dev *dev, unsigned int bit)
+static int res_locked(struct saa7134_dev *dev, unsigned int bit)
 {
 	return (dev->resources & bit);
 }
@@ -603,7 +602,14 @@ static void set_tvnorm(struct saa7134_de
 	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
 	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 
-	saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+	/* only tell the tuner if this is a tv input */
+	if (card_in(dev,dev->ctl_input).tv) {
+		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
+				&& ((card(dev).tuner_config == 1)
+				||  (card(dev).tuner_config == 2)))
+			saa7134_set_gpio(dev, 22, 5);
+		saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+	}
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -732,25 +738,6 @@ struct cliplist {
 	__u8  disable;
 };
 
-static void sort_cliplist(struct cliplist *cl, int entries)
-{
-	struct cliplist swap;
-	int i,j,n;
-
-	for (i = entries-2; i >= 0; i--) {
-		for (n = 0, j = 0; j <= i; j++) {
-			if (cl[j].position > cl[j+1].position) {
-				swap = cl[j];
-				cl[j] = cl[j+1];
-				cl[j+1] = swap;
-				n++;
-			}
-		}
-		if (0 == n)
-			break;
-	}
-}
-
 static void set_cliplist(struct saa7134_dev *dev, int reg,
 			struct cliplist *cl, int entries, char *name)
 {
@@ -784,15 +771,27 @@ static int clip_range(int val)
 	return val;
 }
 
+/* Sort into smallest position first order */
+static int cliplist_cmp(const void *a, const void *b)
+{
+	const struct cliplist *cla = a;
+	const struct cliplist *clb = b;
+	if (cla->position < clb->position)
+		return -1;
+	if (cla->position > clb->position)
+		return 1;
+	return 0;
+}
+
 static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,
 			  int nclips, int interlace)
 {
 	struct cliplist col[16], row[16];
-	int cols, rows, i;
+	int cols = 0, rows = 0, i;
 	int div = interlace ? 2 : 1;
 
-	memset(col,0,sizeof(col)); cols = 0;
-	memset(row,0,sizeof(row)); rows = 0;
+	memset(col, 0, sizeof(col));
+	memset(row, 0, sizeof(row));
 	for (i = 0; i < nclips && i < 8; i++) {
 		col[cols].position = clip_range(clips[i].c.left);
 		col[cols].enable   = (1 << i);
@@ -808,8 +807,8 @@ static int setup_clipping(struct saa7134
 		row[rows].disable  = (1 << i);
 		rows++;
 	}
-	sort_cliplist(col,cols);
-	sort_cliplist(row,rows);
+	sort(col, cols, sizeof col[0], cliplist_cmp, NULL);
+	sort(row, rows, sizeof row[0], cliplist_cmp, NULL);
 	set_cliplist(dev,0x380,col,cols,"cols");
 	set_cliplist(dev,0x384,row,rows,"rows");
 	return 0;
@@ -1261,19 +1260,14 @@ static struct videobuf_queue* saa7134_qu
 
 static int saa7134_resource(struct saa7134_fh *fh)
 {
-	int res = 0;
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return RESOURCE_VIDEO;
 
-	switch (fh->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		res = RESOURCE_VIDEO;
-		break;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		res = RESOURCE_VBI;
-		break;
-	default:
-		BUG();
-	}
-	return res;
+	if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+		return RESOURCE_VBI;
+
+	BUG();
+	return 0;
 }
 
 static int video_open(struct inode *inode, struct file *file)
@@ -1461,8 +1455,7 @@ static int video_release(struct inode *i
 	return 0;
 }
 
-static int
-video_mmap(struct file *file, struct vm_area_struct * vma)
+static int video_mmap(struct file *file, struct vm_area_struct * vma)
 {
 	struct saa7134_fh *fh = file->private_data;
 
@@ -2461,12 +2454,6 @@ int saa7134_video_init2(struct saa7134_d
 	return 0;
 }
 
-int saa7134_video_fini(struct saa7134_dev *dev)
-{
-	/* nothing */
-	return 0;
-}
-
 void saa7134_irq_video_intl(struct saa7134_dev *dev)
 {
 	static const char *st[] = {
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index b3e3957..62224cc 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -231,6 +231,10 @@ #define SAA7134_BOARD_CINERGY_HT_PCMCIA 
 #define SAA7134_BOARD_ENCORE_ENLTV         106
 #define SAA7134_BOARD_ENCORE_ENLTV_FM      107
 #define SAA7134_BOARD_CINERGY_HT_PCI       108
+#define SAA7134_BOARD_PHILIPS_TIGER_S      109
+#define SAA7134_BOARD_AVERMEDIA_M102	   110
+#define SAA7134_BOARD_ASUS_P7131_4871	   111
+#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -280,6 +284,7 @@ struct saa7134_board {
 	unsigned char		radio_addr;
 
 	unsigned int            tda9887_conf;
+	unsigned int            tuner_config;
 
 	/* peripheral I/O */
 	enum saa7134_video_out  video_out;
@@ -435,6 +440,8 @@ struct saa7134_dev {
 #ifdef VIDIOC_G_PRIORITY
 	struct v4l2_prio_state     prio;
 #endif
+	/* workstruct for loading modules */
+	struct work_struct request_module_wk;
 
 	/* insmod option/autodetected */
 	int                        autodetected;
@@ -562,6 +569,8 @@ extern struct list_head  saa7134_devlist
 extern int saa7134_no_overlay;
 
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
+int saa7134_tuner_callback(void *ptr, int command, int arg);
 
 #define SAA7134_PGTABLE_SIZE 4096
 
@@ -620,7 +629,6 @@ int saa7134_common_ioctl(struct saa7134_
 
 int saa7134_video_init1(struct saa7134_dev *dev);
 int saa7134_video_init2(struct saa7134_dev *dev);
-int saa7134_video_fini(struct saa7134_dev *dev);
 void saa7134_irq_video_intl(struct saa7134_dev *dev);
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
 
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index e0fdb1a..339592e 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -33,7 +33,6 @@ #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/pci.h>
 #include <linux/signal.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index 038448f..93fb04e 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -450,6 +450,13 @@ static int se401_start_stream(struct usb
 	}
 	for (i=0; i<SE401_NUMSBUF; i++) {
 		se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+		if (!se401->sbuf[i].data) {
+			for(i = i - 1; i >= 0; i--) {
+				kfree(se401->sbuf[i].data);
+				se401->sbuf[i].data = NULL;
+			}
+			return -ENOMEM;
+		}
 	}
 
 	se401->bayeroffset=0;
@@ -458,13 +465,26 @@ static int se401_start_stream(struct usb
 	se401->scratch_overflow=0;
 	for (i=0; i<SE401_NUMSCRATCH; i++) {
 		se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+		if (!se401->scratch[i].data) {
+			for(i = i - 1; i >= 0; i--) {
+				kfree(se401->scratch[i].data);
+				se401->scratch[i].data = NULL;
+			}
+			goto nomem_sbuf;
+		}
 		se401->scratch[i].state=BUFFER_UNUSED;
 	}
 
 	for (i=0; i<SE401_NUMSBUF; i++) {
 		urb=usb_alloc_urb(0, GFP_KERNEL);
-		if(!urb)
-			return -ENOMEM;
+		if(!urb) {
+			for(i = i - 1; i >= 0; i--) {
+				usb_kill_urb(se401->urb[i]);
+				usb_free_urb(se401->urb[i]);
+				se401->urb[i] = NULL;
+			}
+			goto nomem_scratch;
+		}
 
 		usb_fill_bulk_urb(urb, se401->dev,
 			usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
@@ -482,6 +502,18 @@ static int se401_start_stream(struct usb
 	se401->framecount=0;
 
 	return 0;
+
+ nomem_scratch:
+	for (i=0; i<SE401_NUMSCRATCH; i++) {
+		kfree(se401->scratch[i].data);
+		se401->scratch[i].data = NULL;
+	}
+ nomem_sbuf:
+	for (i=0; i<SE401_NUMSBUF; i++) {
+		kfree(se401->sbuf[i].data);
+		se401->sbuf[i].data = NULL;
+	}
+	return -ENOMEM;
 }
 
 static int se401_stop_stream(struct usb_se401 *se401)
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
index c0891b3..835ef87 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/media/video/se401.h
@@ -5,7 +5,6 @@ #define __LINUX_se401_H
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 
 #define se401_DEBUG	/* Turn on debug messages */
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
index 1a7ccb6..19204f5 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -1,6 +1,6 @@
 config USB_SN9C102
 	tristate "USB SN9C1xx PC Camera Controller support"
-	depends on USB && VIDEO_V4L1
+	depends on USB && VIDEO_V4L2
 	---help---
 	  Say Y here if you want support for cameras based on SONiX SN9C101,
 	  SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
index 30e3dfe..a56d16f 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/video/sn9c102/Makefile
@@ -1,7 +1,14 @@
-sn9c102-objs    := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
-		   sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
-		   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
-		   sn9c102_tas5130d1b.o
+sn9c102-objs := sn9c102_core.o \
+		sn9c102_hv7131d.o \
+		sn9c102_hv7131r.o \
+		sn9c102_mi0343.o \
+		sn9c102_mi0360.o \
+		sn9c102_ov7630.o \
+		sn9c102_ov7660.o \
+		sn9c102_pas106b.o \
+		sn9c102_pas202bcb.o \
+		sn9c102_tas5110c1b.o \
+		sn9c102_tas5110d.o \
+		sn9c102_tas5130d1b.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102.o
-
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 5428f34..680e746 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -78,8 +78,13 @@ enum sn9c102_stream_state {
 
 typedef char sn9c102_sof_header_t[62];
 
+struct sn9c102_sof_t {
+	sn9c102_sof_header_t header;
+	u16 bytesread;
+};
+
 struct sn9c102_sysfs_attr {
-	u8 reg, i2c_reg;
+	u16 reg, i2c_reg;
 	sn9c102_sof_header_t frame_header;
 };
 
@@ -112,7 +117,7 @@ struct sn9c102_device {
 	struct v4l2_jpegcompression compression;
 
 	struct sn9c102_sysfs_attr sysfs;
-	sn9c102_sof_header_t sof_header;
+	struct sn9c102_sof_t sof;
 	u16 reg[384];
 
 	struct sn9c102_module_param module_param;
@@ -182,8 +187,8 @@ do {                                    
 		if ((level) == 1 || (level) == 2)                             \
 			pr_info("sn9c102: " fmt "\n", ## args);               \
 		else if ((level) == 3)                                        \
-			pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
-				 __LINE__ , ## args);                         \
+			pr_debug("sn9c102: [%s:%d] " fmt "\n",                \
+				 __FUNCTION__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #else
@@ -194,8 +199,8 @@ #endif
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-	 __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+	 __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index d0e2b40..89f8335 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -44,11 +44,12 @@ #include "sn9c102.h"
 /*****************************************************************************/
 
 #define SN9C102_MODULE_NAME     "V4L2 driver for SN9C1xx PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
+#define SN9C102_MODULE_ALIAS    "sn9c1xx"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.34"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 34)
+#define SN9C102_MODULE_VERSION  "1:1.39"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 39)
 
 /*****************************************************************************/
 
@@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_tabl
 
 MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
 MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
+MODULE_ALIAS(SN9C102_MODULE_ALIAS);
 MODULE_VERSION(SN9C102_MODULE_VERSION);
 MODULE_LICENSE(SN9C102_MODULE_LICENSE);
 
@@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug,
 		 "\n1 = critical errors"
 		 "\n2 = significant informations"
 		 "\n3 = more verbose messages"
-		 "\nLevel 3 is useful for testing only, when only "
-		 "one device is used."
+		 "\nLevel 3 is useful for testing only."
 		 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
 		 "\n");
 #endif
@@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_d
 	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
 	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
 	size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
-				 (p->width * p->height * p->priv) / 8 :
-				 (r->width * r->height * p->priv) / 8;
+			   (p->width * p->height * p->priv) / 8 :
+			   (r->width * r->height * p->priv) / 8;
 	void* buff = NULL;
 	u32 i;
 
@@ -208,27 +209,40 @@ static void sn9c102_queue_unusedframes(s
 }
 
 /*****************************************************************************/
-
-int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
+/*
+ * Write a sequence of count value/register pairs.  Returns -1 after the
+ * first failed write, or 0 for no errors.
+ */
+int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
+		       int count)
 {
 	struct usb_device* udev = cam->usbdev;
+	u8* value = cam->control_buffer;  /* Needed for DMA'able memory */
 	int i, res;
 
-	if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
-		return -1;
+	for (i = 0; i < count; i++) {
+		u8 index = valreg[i][1];
+
+		/*
+		 * index is a u8, so it must be <256 and can't be out of range.
+		 * If we put in a check anyway, gcc annoys us with a warning
+		 * that our check is useless.  People get all uppity when they
+		 * see warnings in the kernel compile.
+		 */
+
+		*value = valreg[i][0];
+		res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				      0x08, 0x41, index, 0,
+				      value, 1, SN9C102_CTRL_TIMEOUT);
+		if (res < 0) {
+			DBG(3, "Failed to write a register (value 0x%02X, "
+			       "index 0x%02X, error %d)", *value, index, res);
+			return -1;
+		}
 
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-			      index, 0, buff, sizeof(buff),
-			      SN9C102_CTRL_TIMEOUT*sizeof(buff));
-	if (res < 0) {
-		DBG(3, "Failed to write registers (index 0x%02X, error %d)",
-		    index, res);
-		return -1;
+		cam->reg[index] = *value;
 	}
 
-	for (i = 0; i < sizeof(buff); i++)
-		cam->reg[index+i] = buff[i];
-
 	return 0;
 }
 
@@ -485,18 +499,43 @@ static size_t sn9c102_sof_length(struct 
 static void*
 sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
-	char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
-	size_t soflen = 0, i;
+	static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+	const char *m = mem;
+	size_t soflen = 0, i, j;
 
 	soflen = sn9c102_sof_length(cam);
 
-	for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
-		if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
-			memcpy(cam->sof_header, mem + i,
-			       sizeof(sn9c102_sof_header_t));
-				/* Skip the header */
-				return mem + i + soflen;
+	for (i = 0; i < len; i++) {
+		size_t b;
+
+		/* Read the variable part of the header */
+		if (unlikely(cam->sof.bytesread >= sizeof(marker))) {
+			cam->sof.header[cam->sof.bytesread] = *(m+i);
+			if (++cam->sof.bytesread == soflen) {
+				cam->sof.bytesread = 0;
+				return mem + i;
+			}
+			continue;
+		}
+
+		/* Search for the SOF marker (fixed part) in the header */
+		for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
+			if (unlikely(i+j) == len)
+				return NULL;
+			if (*(m+i+j) == marker[cam->sof.bytesread]) {
+				cam->sof.header[cam->sof.bytesread] = *(m+i+j);
+				if (++cam->sof.bytesread == sizeof(marker)) {
+					PDBGG("Bytes to analyze: %zd. SOF "
+					      "starts at byte #%zd", len, i);
+					i += j+1;
+					break;
+				}
+			} else {
+				cam->sof.bytesread = 0;
+				break;
 			}
+		}
+	}
 
 	return NULL;
 }
@@ -505,7 +544,7 @@ sn9c102_find_sof_header(struct sn9c102_d
 static void*
 sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
-	char eof_header[4][4] = {
+	static const u8 eof_header[4][4] = {
 		{0x00, 0x00, 0x00, 0x00},
 		{0x40, 0x00, 0x00, 0x00},
 		{0x80, 0x00, 0x00, 0x00},
@@ -513,10 +552,16 @@ sn9c102_find_eof_header(struct sn9c102_d
 	};
 	size_t i, j;
 
+	/* The EOF header does not exist in compressed data */
 	if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
 	    cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
-		return NULL; /* EOF header does not exist in compressed data */
+		return NULL;
 
+	/*
+	   The EOF header might cross the packet boundary, but this is not a
+	   problem, since the end of a frame is determined by checking its size
+	   in the first place.
+	*/
 	for (i = 0; (len >= 4) && (i <= len - 4); i++)
 		for (j = 0; j < ARRAY_SIZE(eof_header); j++)
 			if (!memcmp(mem + i, eof_header[j], 4))
@@ -529,7 +574,7 @@ sn9c102_find_eof_header(struct sn9c102_d
 static void
 sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
 {
-	static u8 jpeg_header[589] = {
+	static const u8 jpeg_header[589] = {
 		0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
 		0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
 		0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
@@ -639,6 +684,7 @@ static void sn9c102_urb_complete(struct 
 		cam->stream = STREAM_OFF;
 		if ((*f))
 			(*f)->state = F_QUEUED;
+		cam->sof.bytesread = 0;
 		DBG(3, "Stream interrupted by application");
 		wake_up(&cam->wait_stream);
 	}
@@ -676,6 +722,7 @@ static void sn9c102_urb_complete(struct 
 		if (status) {
 			DBG(3, "Error in isochronous frame");
 			(*f)->state = F_ERROR;
+			cam->sof.bytesread = 0;
 			continue;
 		}
 
@@ -692,13 +739,13 @@ end_of_frame:
 				if (eof)
 					img = (eof > pos) ? eof - pos - 1 : 0;
 
-				if ((*f)->buf.bytesused+img > imagesize) {
+				if ((*f)->buf.bytesused + img > imagesize) {
 					u32 b;
 					b = (*f)->buf.bytesused + img -
 					    imagesize;
 					img = imagesize - (*f)->buf.bytesused;
-					DBG(3, "Expected EOF not found: "
-					       "video frame cut");
+					PDBGG("Expected EOF not found: video "
+					      "frame cut");
 					if (eof)
 						DBG(3, "Exceeded limit: +%u "
 						       "bytes", (unsigned)(b));
@@ -719,11 +766,6 @@ end_of_frame:
 				      V4L2_PIX_FMT_JPEG) && eof)) {
 					u32 b;
 
-					if (cam->sensor.pix_format.pixelformat
-					    == V4L2_PIX_FMT_JPEG)
-						sn9c102_write_eoimarker(cam,
-									(*f));
-
 					b = (*f)->buf.bytesused;
 					(*f)->state = F_DONE;
 					(*f)->buf.sequence= ++cam->frame_count;
@@ -741,7 +783,7 @@ end_of_frame:
 					spin_unlock(&cam->queue_lock);
 
 					memcpy(cam->sysfs.frame_header,
-					       cam->sof_header, soflen);
+					       cam->sof.header, soflen);
 
 					DBG(3, "Video frame captured: %lu "
 					       "bytes", (unsigned long)(b));
@@ -791,7 +833,13 @@ start_of_frame:
 				    V4L2_PIX_FMT_SN9C10X ||
 				    cam->sensor.pix_format.pixelformat ==
 				    V4L2_PIX_FMT_JPEG) {
-					eof = sof - soflen;
+					if (sof - pos >= soflen) {
+						eof = sof - soflen;
+					} else { /* remove header */
+						eof = pos;
+						(*f)->buf.bytesused -=
+							(soflen - (sof - pos));
+					}
 					goto end_of_frame;
 				} else {
 					DBG(3, "SOF before expected EOF after "
@@ -878,6 +926,7 @@ static int sn9c102_start_transfer(struct
 	}
 
 	cam->frame_current = NULL;
+	cam->sof.bytesread = 0;
 
 	for (i = 0; i < SN9C102_URBS; i++) {
 		err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
@@ -959,9 +1008,9 @@ static u16 sn9c102_strtou16(const char* 
 
 	if (len < 6) {
 		strncpy(str, buff, len);
-		str[len+1] = '\0';
+		str[len] = '\0';
 	} else {
-		strncpy(str, buff, 4);
+		strncpy(str, buff, 6);
 		str[6] = '\0';
 	}
 
@@ -1062,7 +1111,7 @@ static ssize_t sn9c102_show_val(struct c
 
 	count = sprintf(buf, "%d\n", val);
 
-	DBG(3, "Read bytes: %zd", count);
+	DBG(3, "Read bytes: %zd, value: %d", count, val);
 
 	mutex_unlock(&sn9c102_sysfs_lock);
 
@@ -1197,7 +1246,7 @@ static ssize_t sn9c102_show_i2c_val(stru
 
 	count = sprintf(buf, "%d\n", val);
 
-	DBG(3, "Read bytes: %zd", count);
+	DBG(3, "Read bytes: %zd, value: %d", count, val);
 
 	mutex_unlock(&sn9c102_sysfs_lock);
 
@@ -1371,35 +1420,35 @@ static CLASS_DEVICE_ATTR(frame_header, S
 
 static int sn9c102_create_sysfs(struct sn9c102_device* cam)
 {
-	struct video_device *v4ldev = cam->v4ldev;
+	struct class_device *classdev = &(cam->v4ldev->class_dev);
 	int err = 0;
 
-	if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+	if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
 		goto err_out;
-	if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+	if ((err = class_device_create_file(classdev, &class_device_attr_val)))
 		goto err_reg;
-	if ((err = video_device_create_file(v4ldev,
+	if ((err = class_device_create_file(classdev,
 					    &class_device_attr_frame_header)))
 		goto err_val;
 
 	if (cam->sensor.sysfs_ops) {
-		if ((err = video_device_create_file(v4ldev,
+		if ((err = class_device_create_file(classdev,
 						  &class_device_attr_i2c_reg)))
 			goto err_frame_header;
-		if ((err = video_device_create_file(v4ldev,
+		if ((err = class_device_create_file(classdev,
 						  &class_device_attr_i2c_val)))
 			goto err_i2c_reg;
 	}
 
 	if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
-		if ((err = video_device_create_file(v4ldev,
+		if ((err = class_device_create_file(classdev,
 						    &class_device_attr_green)))
 			goto err_i2c_val;
 	} else {
-		if ((err = video_device_create_file(v4ldev,
+		if ((err = class_device_create_file(classdev,
 						    &class_device_attr_blue)))
 			goto err_i2c_val;
-		if ((err = video_device_create_file(v4ldev,
+		if ((err = class_device_create_file(classdev,
 						    &class_device_attr_red)))
 			goto err_blue;
 	}
@@ -1407,19 +1456,19 @@ static int sn9c102_create_sysfs(struct s
 	return 0;
 
 err_blue:
-	video_device_remove_file(v4ldev, &class_device_attr_blue);
+	class_device_remove_file(classdev, &class_device_attr_blue);
 err_i2c_val:
 	if (cam->sensor.sysfs_ops)
-		video_device_remove_file(v4ldev, &class_device_attr_i2c_val);
+		class_device_remove_file(classdev, &class_device_attr_i2c_val);
 err_i2c_reg:
 	if (cam->sensor.sysfs_ops)
-		video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+		class_device_remove_file(classdev, &class_device_attr_i2c_reg);
 err_frame_header:
-	video_device_remove_file(v4ldev, &class_device_attr_frame_header);
+	class_device_remove_file(classdev, &class_device_attr_frame_header);
 err_val:
-	video_device_remove_file(v4ldev, &class_device_attr_val);
+	class_device_remove_file(classdev, &class_device_attr_val);
 err_reg:
-	video_device_remove_file(v4ldev, &class_device_attr_reg);
+	class_device_remove_file(classdev, &class_device_attr_reg);
 err_out:
 	return err;
 }
@@ -1477,10 +1526,10 @@ sn9c102_set_compression(struct sn9c102_d
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
 	case BRIDGE_SN9C103:
-	if (compression->quality == 0)
+		if (compression->quality == 0)
 			err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
 						 0x17);
-	else if (compression->quality == 1)
+		else if (compression->quality == 1)
 			err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
 						 0x17);
 		break;
@@ -1489,10 +1538,10 @@ sn9c102_set_compression(struct sn9c102_d
 		if (compression->quality == 0) {
 			for (i = 0; i <= 63; i++) {
 				err += sn9c102_write_reg(cam,
-							 SN9C102_Y_QTABLE0[i],
+							 SN9C102_Y_QTABLE1[i],
 							 0x100 + i);
 				err += sn9c102_write_reg(cam,
-							 SN9C102_UV_QTABLE0[i],
+							 SN9C102_UV_QTABLE1[i],
 							 0x140 + i);
 			}
 			err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
@@ -1597,9 +1646,13 @@ static int sn9c102_init(struct sn9c102_d
 		if (cam->bridge == BRIDGE_SN9C101 ||
 		    cam->bridge == BRIDGE_SN9C102 ||
 		    cam->bridge == BRIDGE_SN9C103) {
+			if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
+				s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
 			cam->compression.quality =  cam->reg[0x17] & 0x01 ?
 						    0 : 1;
 		} else {
+			if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+				s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG;
 			cam->compression.quality =  cam->reg[0x18] & 0x40 ?
 						    0 : 1;
 			err += sn9c102_set_compression(cam, &cam->compression);
@@ -1805,7 +1858,7 @@ sn9c102_read(struct file* filp, char __u
 		DBG(3, "Close and open the device again to choose "
 		       "the read method");
 		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	if (cam->io == IO_NONE) {
@@ -1845,16 +1898,16 @@ sn9c102_read(struct file* filp, char __u
 				return err;
 			}
 		} else {
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    cam->module_param.frame_timeout *
-			    1000 * msecs_to_jiffies(1) );
-		if (timeout < 0) {
-			mutex_unlock(&cam->fileop_mutex);
-			return timeout;
+			timeout = wait_event_interruptible_timeout
+				  ( cam->wait_frame,
+				    (!list_empty(&cam->outqueue)) ||
+				    (cam->state & DEV_DISCONNECTED) ||
+				    (cam->state & DEV_MISCONFIGURED),
+				    cam->module_param.frame_timeout *
+				    1000 * msecs_to_jiffies(1) );
+			if (timeout < 0) {
+				mutex_unlock(&cam->fileop_mutex);
+				return timeout;
 			} else if (timeout == 0 &&
 				   !(cam->state & DEV_DISCONNECTED)) {
 				DBG(1, "Video frame timeout elapsed");
@@ -2001,7 +2054,12 @@ static int sn9c102_mmap(struct file* fil
 		return -EIO;
 	}
 
-	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+		mutex_unlock(&cam->fileop_mutex);
+		return -EACCES;
+	}
+
+	if (cam->io != IO_MMAP ||
 	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
 		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
@@ -2267,7 +2325,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_dev
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_CROP failed. "
 				       "Unmap the buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	/* Preserve R,G or B origin */
@@ -2410,8 +2468,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_d
 		case BRIDGE_SN9C101:
 		case BRIDGE_SN9C102:
 		case BRIDGE_SN9C103:
-		strcpy(fmtd.description, "compressed");
-		fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+			strcpy(fmtd.description, "compressed");
+			fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
 			break;
 		case BRIDGE_SN9C105:
 		case BRIDGE_SN9C120:
@@ -2445,8 +2503,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_devi
 	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
-			      pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
+	pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ?
+			   V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
+	pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+			      pfmt->pixelformat == V4L2_PIX_FMT_JPEG)
 			     ? 0 : (pfmt->width * pfmt->priv) / 8;
 	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
 	pfmt->field = V4L2_FIELD_NONE;
@@ -2521,9 +2581,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
 	case BRIDGE_SN9C103:
-	if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-		pix->pixelformat = pfmt->pixelformat;
+		if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+		    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+			pix->pixelformat = pfmt->pixelformat;
 		break;
 	case BRIDGE_SN9C105:
 	case BRIDGE_SN9C120:
@@ -2533,7 +2593,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_
 		break;
 	}
 	pix->priv = pfmt->priv; /* bpp */
-	pix->colorspace = pfmt->colorspace;
+	pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ?
+			  V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
 	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
 			     pix->pixelformat == V4L2_PIX_FMT_JPEG)
 			    ? 0 : (pix->width * pix->priv) / 8;
@@ -2551,7 +2612,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_FMT failed. Unmap the "
 				       "buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	if (cam->stream == STREAM_ON)
@@ -2666,14 +2727,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_de
 	if (cam->io == IO_READ) {
 		DBG(3, "Close and open the device again to choose the mmap "
 		       "I/O method");
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	for (i = 0; i < cam->nbuffers; i++)
 		if (cam->frame[i].vma_use_count) {
 			DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
 			       "still mapped.");
-			return -EINVAL;
+			return -EBUSY;
 		}
 
 	if (cam->stream == STREAM_ON)
@@ -2785,15 +2846,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_devi
 			if (err)
 				return err;
 		} else {
-		timeout = wait_event_interruptible_timeout
-			  ( cam->wait_frame,
-			    (!list_empty(&cam->outqueue)) ||
-			    (cam->state & DEV_DISCONNECTED) ||
-			    (cam->state & DEV_MISCONFIGURED),
-			    cam->module_param.frame_timeout *
-			    1000 * msecs_to_jiffies(1) );
-		if (timeout < 0)
-			return timeout;
+			timeout = wait_event_interruptible_timeout
+				  ( cam->wait_frame,
+				    (!list_empty(&cam->outqueue)) ||
+				    (cam->state & DEV_DISCONNECTED) ||
+				    (cam->state & DEV_MISCONFIGURED),
+				    cam->module_param.frame_timeout *
+				    1000 * msecs_to_jiffies(1) );
+			if (timeout < 0)
+				return timeout;
 			else if (timeout == 0 &&
 				 !(cam->state & DEV_DISCONNECTED)) {
 				DBG(1, "Video frame timeout elapsed");
@@ -2837,9 +2898,6 @@ sn9c102_vidioc_streamon(struct sn9c102_d
 	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
 		return -EINVAL;
 
-	if (list_empty(&cam->inqueue))
-		return -EINVAL;
-
 	cam->stream = STREAM_ON;
 
 	DBG(3, "Stream on");
@@ -3166,8 +3224,8 @@ sn9c102_usb_probe(struct usb_interface* 
 
 	r = sn9c102_read_reg(cam, 0x00);
 	if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
-		DBG(1, "Sorry, this is not a SN9C1xx based camera "
-		       "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+		DBG(1, "Sorry, this is not a SN9C1xx-based camera "
+		       "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 		err = -ENODEV;
 		goto fail;
 	}
@@ -3177,19 +3235,19 @@ sn9c102_usb_probe(struct usb_interface* 
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
 		DBG(2, "SN9C10[12] PC Camera Controller detected "
-		       "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+		       "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 		break;
 	case BRIDGE_SN9C103:
 		DBG(2, "SN9C103 PC Camera Controller detected "
-		       "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+		       "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 		break;
 	case BRIDGE_SN9C105:
 		DBG(2, "SN9C105 PC Camera Controller detected "
-		       "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+		       "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 		break;
 	case BRIDGE_SN9C120:
 		DBG(2, "SN9C120 PC Camera Controller detected "
-		       "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+		       "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
 		break;
 	}
 
@@ -3260,6 +3318,8 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 		       "device controlling. Error #%d", err);
 #else
 	DBG(2, "Optional device control through 'sysfs' interface disabled");
+	DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+	       "configuration option to enable it.");
 #endif
 
 	usb_set_intfdata(intf, cam);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 3a682ec..f49bd8c 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -89,16 +89,22 @@ static const struct usb_device_id sn9c10
 	{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
 	/* SN9C120 */
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
+	{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
 	{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
@@ -114,12 +120,15 @@ static const struct usb_device_id sn9c10
    Functions must return 0 on success, the appropriate error otherwise.
 */
 extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
 
 /*
@@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(stru
    the order of the list below, from top to bottom.
 */
 static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
-	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+	&sn9c102_probe_tas5110d, /* detection based on USB pid/vid */
 	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
 	NULL,
 };
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index 7ae368f..28a861a 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -22,19 +22,13 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor hv7131d;
-
-
 static int hv7131d_init(struct sn9c102_device* cam)
 {
-	int err = 0;
+	int err;
 
-	err += sn9c102_write_reg(cam, 0x00, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x00, 0x14);
-	err += sn9c102_write_reg(cam, 0x60, 0x17);
-	err += sn9c102_write_reg(cam, 0x0e, 0x18);
-	err += sn9c102_write_reg(cam, 0xf2, 0x19);
+	err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
+				       {0x00, 0x14}, {0x60, 0x17},
+				       {0x0e, 0x18}, {0xf2, 0x19});
 
 	err += sn9c102_i2c_write(cam, 0x01, 0x04);
 	err += sn9c102_i2c_write(cam, 0x02, 0x00);
@@ -153,7 +147,7 @@ static int hv7131d_set_pix_format(struct
 static struct sn9c102_sensor hv7131d = {
 	.name = "HV7131D",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
 	.frequency = SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_2WIRES,
@@ -250,11 +244,10 @@ static struct sn9c102_sensor hv7131d = {
 
 int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
 {
-	int r0 = 0, r1 = 0, err = 0;
+	int r0 = 0, r1 = 0, err;
 
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x00, 0x01);
-	err += sn9c102_write_reg(cam, 0x28, 0x17);
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
+				       {0x28, 0x17});
 	if (err)
 		return -EIO;
 
@@ -263,7 +256,7 @@ int sn9c102_probe_hv7131d(struct sn9c102
 	if (r0 < 0 || r1 < 0)
 		return -EIO;
 
-	if (r0 != 0x00 && r1 != 0x04)
+	if (r0 != 0x00 || r1 != 0x04)
 		return -ENODEV;
 
 	sn9c102_attach_sensor(cam, &hv7131d);
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
new file mode 100644
index 0000000..5a495ba
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c
@@ -0,0 +1,366 @@
+/***************************************************************************
+ * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static int hv7131r_init(struct sn9c102_device* cam)
+{
+	int err = 0;
+
+	switch (sn9c102_get_bridge(cam)) {
+	case BRIDGE_SN9C103:
+		err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04},
+					       {0x20, 0x05}, {0x20, 0x06},
+					       {0x03, 0x10}, {0x00, 0x14},
+					       {0x60, 0x17}, {0x0a, 0x18},
+					       {0xf0, 0x19}, {0x1d, 0x1a},
+					       {0x10, 0x1b}, {0x02, 0x1c},
+					       {0x03, 0x1d}, {0x0f, 0x1e},
+					       {0x0c, 0x1f}, {0x00, 0x20},
+					       {0x10, 0x21}, {0x20, 0x22},
+					       {0x30, 0x23}, {0x40, 0x24},
+					       {0x50, 0x25}, {0x60, 0x26},
+					       {0x70, 0x27}, {0x80, 0x28},
+					       {0x90, 0x29}, {0xa0, 0x2a},
+					       {0xb0, 0x2b}, {0xc0, 0x2c},
+					       {0xd0, 0x2d}, {0xe0, 0x2e},
+					       {0xf0, 0x2f}, {0xff, 0x30});
+
+		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+		err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
+					       {0x00, 0x03}, {0x1a, 0x04},
+					       {0x44, 0x05}, {0x3e, 0x06},
+					       {0x1a, 0x07}, {0x03, 0x10},
+					       {0x08, 0x14}, {0xa3, 0x17},
+					       {0x4b, 0x18}, {0x00, 0x19},
+					       {0x1d, 0x1a}, {0x10, 0x1b},
+					       {0x02, 0x1c}, {0x03, 0x1d},
+					       {0x0f, 0x1e}, {0x0c, 0x1f},
+					       {0x00, 0x20}, {0x29, 0x21},
+					       {0x40, 0x22}, {0x54, 0x23},
+					       {0x66, 0x24}, {0x76, 0x25},
+					       {0x85, 0x26}, {0x94, 0x27},
+					       {0xa1, 0x28}, {0xae, 0x29},
+					       {0xbb, 0x2a}, {0xc7, 0x2b},
+					       {0xd3, 0x2c}, {0xde, 0x2d},
+					       {0xea, 0x2e}, {0xf4, 0x2f},
+					       {0xff, 0x30}, {0x00, 0x3F},
+					       {0xC7, 0x40}, {0x01, 0x41},
+					       {0x44, 0x42}, {0x00, 0x43},
+					       {0x44, 0x44}, {0x00, 0x45},
+					       {0x44, 0x46}, {0x00, 0x47},
+					       {0xC7, 0x48}, {0x01, 0x49},
+					       {0xC7, 0x4A}, {0x01, 0x4B},
+					       {0xC7, 0x4C}, {0x01, 0x4D},
+					       {0x44, 0x4E}, {0x00, 0x4F},
+					       {0x44, 0x50}, {0x00, 0x51},
+					       {0x44, 0x52}, {0x00, 0x53},
+					       {0xC7, 0x54}, {0x01, 0x55},
+					       {0xC7, 0x56}, {0x01, 0x57},
+					       {0xC7, 0x58}, {0x01, 0x59},
+					       {0x44, 0x5A}, {0x00, 0x5B},
+					       {0x44, 0x5C}, {0x00, 0x5D},
+					       {0x44, 0x5E}, {0x00, 0x5F},
+					       {0xC7, 0x60}, {0x01, 0x61},
+					       {0xC7, 0x62}, {0x01, 0x63},
+					       {0xC7, 0x64}, {0x01, 0x65},
+					       {0x44, 0x66}, {0x00, 0x67},
+					       {0x44, 0x68}, {0x00, 0x69},
+					       {0x44, 0x6A}, {0x00, 0x6B},
+					       {0xC7, 0x6C}, {0x01, 0x6D},
+					       {0xC7, 0x6E}, {0x01, 0x6F},
+					       {0xC7, 0x70}, {0x01, 0x71},
+					       {0x44, 0x72}, {0x00, 0x73},
+					       {0x44, 0x74}, {0x00, 0x75},
+					       {0x44, 0x76}, {0x00, 0x77},
+					       {0xC7, 0x78}, {0x01, 0x79},
+					       {0xC7, 0x7A}, {0x01, 0x7B},
+					       {0xC7, 0x7C}, {0x01, 0x7D},
+					       {0x44, 0x7E}, {0x00, 0x7F},
+					       {0x14, 0x84}, {0x00, 0x85},
+					       {0x27, 0x86}, {0x00, 0x87},
+					       {0x07, 0x88}, {0x00, 0x89},
+					       {0xEC, 0x8A}, {0x0f, 0x8B},
+					       {0xD8, 0x8C}, {0x0f, 0x8D},
+					       {0x3D, 0x8E}, {0x00, 0x8F},
+					       {0x3D, 0x90}, {0x00, 0x91},
+					       {0xCD, 0x92}, {0x0f, 0x93},
+					       {0xf7, 0x94}, {0x0f, 0x95},
+					       {0x0C, 0x96}, {0x00, 0x97},
+					       {0x00, 0x98}, {0x66, 0x99},
+					       {0x05, 0x9A}, {0x00, 0x9B},
+					       {0x04, 0x9C}, {0x00, 0x9D},
+					       {0x08, 0x9E}, {0x00, 0x9F},
+					       {0x2D, 0xC0}, {0x2D, 0xC1},
+					       {0x3A, 0xC2}, {0x05, 0xC3},
+					       {0x04, 0xC4}, {0x3F, 0xC5},
+					       {0x00, 0xC6}, {0x00, 0xC7},
+					       {0x50, 0xC8}, {0x3C, 0xC9},
+					       {0x28, 0xCA}, {0xD8, 0xCB},
+					       {0x14, 0xCC}, {0xEC, 0xCD},
+					       {0x32, 0xCE}, {0xDD, 0xCF},
+					       {0x32, 0xD0}, {0xDD, 0xD1},
+					       {0x6A, 0xD2}, {0x50, 0xD3},
+					       {0x00, 0xD4}, {0x00, 0xD5},
+					       {0x00, 0xD6});
+		break;
+	default:
+		break;
+	}
+
+	err += sn9c102_i2c_write(cam, 0x20, 0x00);
+	err += sn9c102_i2c_write(cam, 0x21, 0xd6);
+	err += sn9c102_i2c_write(cam, 0x25, 0x06);
+
+	return err;
+}
+
+
+static int hv7131r_get_ctrl(struct sn9c102_device* cam,
+			    struct v4l2_control* ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
+			return -EIO;
+		return 0;
+	case V4L2_CID_RED_BALANCE:
+		if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
+			return -EIO;
+		ctrl->value = ctrl->value & 0x3f;
+		return 0;
+	case V4L2_CID_BLUE_BALANCE:
+		if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
+			return -EIO;
+		ctrl->value = ctrl->value & 0x3f;
+		return 0;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
+			return -EIO;
+		ctrl->value = ctrl->value & 0x3f;
+		return 0;
+	case V4L2_CID_BLACK_LEVEL:
+		if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
+			return -EIO;
+		ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static int hv7131r_set_ctrl(struct sn9c102_device* cam,
+			    const struct v4l2_control* ctrl)
+{
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_GAIN:
+		err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
+		break;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
+		break;
+	case V4L2_CID_BLACK_LEVEL:
+		{
+			int r = sn9c102_i2c_read(cam, 0x01);
+			if (r < 0)
+				return -EIO;
+			err += sn9c102_i2c_write(cam, 0x01,
+						 (ctrl->value<<3) | (r&0xf7));
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return err ? -EIO : 0;
+}
+
+
+static int hv7131r_set_crop(struct sn9c102_device* cam,
+			    const struct v4l2_rect* rect)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+	err += sn9c102_write_reg(cam, h_start, 0x12);
+	err += sn9c102_write_reg(cam, v_start, 0x13);
+
+	return err;
+}
+
+
+static int hv7131r_set_pix_format(struct sn9c102_device* cam,
+				  const struct v4l2_pix_format* pix)
+{
+	int err = 0;
+
+	switch (sn9c102_get_bridge(cam)) {
+	case BRIDGE_SN9C103:
+		if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+			err += sn9c102_write_reg(cam, 0xa0, 0x19);
+			err += sn9c102_i2c_write(cam, 0x01, 0x04);
+		} else {
+			err += sn9c102_write_reg(cam, 0x30, 0x19);
+			err += sn9c102_i2c_write(cam, 0x01, 0x04);
+		}
+		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+		if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+			err += sn9c102_write_reg(cam, 0xa5, 0x17);
+			err += sn9c102_i2c_write(cam, 0x01, 0x24);
+		} else {
+			err += sn9c102_write_reg(cam, 0xa3, 0x17);
+			err += sn9c102_i2c_write(cam, 0x01, 0x04);
+		}
+		break;
+	default:
+		break;
+	}
+
+	return err;
+}
+
+
+static struct sn9c102_sensor hv7131r = {
+	.name = "HV7131R",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
+	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+	.frequency = SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x11,
+	.init = &hv7131r_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "global gain",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = 0x40,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "red balance",
+			.minimum = 0x00,
+			.maximum = 0x3f,
+			.step = 0x01,
+			.default_value = 0x08,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "blue balance",
+			.minimum = 0x00,
+			.maximum = 0x3f,
+			.step = 0x01,
+			.default_value = 0x1a,
+			.flags = 0,
+		},
+		{
+			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "green balance",
+			.minimum = 0x00,
+			.maximum = 0x3f,
+			.step = 0x01,
+			.default_value = 0x2f,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_BLACK_LEVEL,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "auto black level compensation",
+			.minimum = 0x00,
+			.maximum = 0x01,
+			.step = 0x01,
+			.default_value = 0x00,
+			.flags = 0,
+		},
+	},
+	.get_ctrl = &hv7131r_get_ctrl,
+	.set_ctrl = &hv7131r_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.set_crop = &hv7131r_set_crop,
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &hv7131r_set_pix_format
+};
+
+
+int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
+{
+	int devid, err;
+
+	err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02},
+				       {0x34, 0x01}, {0x20, 0x17},
+				       {0x34, 0x01}, {0x46, 0x01});
+
+	if (err)
+		return -EIO;
+
+	devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
+	if (devid < 0)
+		return -EIO;
+
+	if (devid != 0x02)
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &hv7131r);
+
+	return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
index a33d1bc..9200845 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0343.c
+++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c
@@ -22,36 +22,30 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor mi0343;
-static u8 mi0343_i2c_data[5+1];
-
-
 static int mi0343_init(struct sn9c102_device* cam)
 {
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 	int err = 0;
 
-	err += sn9c102_write_reg(cam, 0x00, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x0a, 0x14);
-	err += sn9c102_write_reg(cam, 0x40, 0x01);
-	err += sn9c102_write_reg(cam, 0x20, 0x17);
-	err += sn9c102_write_reg(cam, 0x07, 0x18);
-	err += sn9c102_write_reg(cam, 0xa0, 0x19);
-
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x0d, 0x00, 0x01, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x0d, 0x00, 0x00, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x03, 0x01, 0xe1, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x04, 0x02, 0x81, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x05, 0x00, 0x17, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x06, 0x00, 0x11, 0, 0);
-	err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-					 0x62, 0x04, 0x9a, 0, 0);
+	err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
+				       {0x0a, 0x14}, {0x40, 0x01},
+				       {0x20, 0x17}, {0x07, 0x18},
+				       {0xa0, 0x19});
+
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x01, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
+					 0x01, 0xe1, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
+					 0x02, 0x81, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
+					 0x00, 0x17, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
+					 0x00, 0x11, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
+					 0x04, 0x9a, 0, 0);
 
 	return err;
 }
@@ -60,43 +54,46 @@ static int mi0343_init(struct sn9c102_de
 static int mi0343_get_ctrl(struct sn9c102_device* cam,
 			   struct v4l2_control* ctrl)
 {
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	u8 data[5+1];
+
 	switch (ctrl->id) {
 	case V4L2_CID_EXPOSURE:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x09, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09,
+					     2+1, data) < 0)
 			return -EIO;
-		ctrl->value = mi0343_i2c_data[2];
+		ctrl->value = data[2];
 		return 0;
 	case V4L2_CID_GAIN:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x35, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35,
+					     2+1, data) < 0)
 			return -EIO;
 		break;
 	case V4L2_CID_HFLIP:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x20, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
+					     2+1, data) < 0)
 			return -EIO;
-		ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
+		ctrl->value = data[3] & 0x20 ? 1 : 0;
 		return 0;
 	case V4L2_CID_VFLIP:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x20, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
+					     2+1, data) < 0)
 			return -EIO;
-		ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
+		ctrl->value = data[3] & 0x80 ? 1 : 0;
 		return 0;
 	case V4L2_CID_RED_BALANCE:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x2d, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d,
+					     2+1, data) < 0)
 			return -EIO;
 		break;
 	case V4L2_CID_BLUE_BALANCE:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x2c, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c,
+					     2+1, data) < 0)
 			return -EIO;
 		break;
 	case SN9C102_V4L2_CID_GREEN_BALANCE:
-		if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-					     0x2e, 2+1, mi0343_i2c_data) < 0)
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e,
+					     2+1, data) < 0)
 			return -EIO;
 		break;
 	default:
@@ -108,7 +105,7 @@ static int mi0343_get_ctrl(struct sn9c10
 	case V4L2_CID_RED_BALANCE:
 	case V4L2_CID_BLUE_BALANCE:
 	case SN9C102_V4L2_CID_GREEN_BALANCE:
-		ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
+		ctrl->value = data[3] | (data[2] << 8);
 		if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
 			ctrl->value -= 0x10;
 		else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
@@ -124,6 +121,7 @@ static int mi0343_get_ctrl(struct sn9c10
 static int mi0343_set_ctrl(struct sn9c102_device* cam,
 			   const struct v4l2_control* ctrl)
 {
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 	u16 reg = 0;
 	int err = 0;
 
@@ -143,50 +141,42 @@ static int mi0343_set_ctrl(struct sn9c10
 
 	switch (ctrl->id) {
 	case V4L2_CID_EXPOSURE:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x09, ctrl->value, 0x00,
 						 0, 0);
 		break;
 	case V4L2_CID_GAIN:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x35, reg >> 8, reg & 0xff,
 						 0, 0);
 		break;
 	case V4L2_CID_HFLIP:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x20, ctrl->value ? 0x40:0x00,
 						 ctrl->value ? 0x20:0x00,
 						 0, 0);
 		break;
 	case V4L2_CID_VFLIP:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x20, ctrl->value ? 0x80:0x00,
 						 ctrl->value ? 0x80:0x00,
 						 0, 0);
 		break;
 	case V4L2_CID_RED_BALANCE:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x2d, reg >> 8, reg & 0xff,
 						 0, 0);
 		break;
 	case V4L2_CID_BLUE_BALANCE:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x2c, reg >> 8, reg & 0xff,
 						 0, 0);
 		break;
 	case SN9C102_V4L2_CID_GREEN_BALANCE:
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x2b, reg >> 8, reg & 0xff,
 						 0, 0);
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x2e, reg >> 8, reg & 0xff,
 						 0, 0);
 		break;
@@ -216,16 +206,15 @@ static int mi0343_set_crop(struct sn9c10
 static int mi0343_set_pix_format(struct sn9c102_device* cam,
 				 const struct v4l2_pix_format* pix)
 {
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 	int err = 0;
 
 	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x0a, 0x00, 0x03, 0, 0);
 		err += sn9c102_write_reg(cam, 0x20, 0x19);
 	} else {
-		err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-						 mi0343.i2c_slave_id,
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 						 0x0a, 0x00, 0x05, 0, 0);
 		err += sn9c102_write_reg(cam, 0xa0, 0x19);
 	}
@@ -237,7 +226,7 @@ static int mi0343_set_pix_format(struct 
 static struct sn9c102_sensor mi0343 = {
 	.name = "MI-0343",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 	.frequency = SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_2WIRES,
 	.i2c_slave_id = 0x5d,
@@ -343,19 +332,20 @@ static struct sn9c102_sensor mi0343 = {
 
 int sn9c102_probe_mi0343(struct sn9c102_device* cam)
 {
+	u8 data[5+1];
 	int err = 0;
 
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x00, 0x01);
-	err += sn9c102_write_reg(cam, 0x28, 0x17);
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
+				       {0x28, 0x17});
+
 	if (err)
 		return -EIO;
 
 	if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
-				     2, mi0343_i2c_data) < 0)
+				     2, data) < 0)
 		return -EIO;
 
-	if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
+	if (data[4] != 0x32 || data[3] != 0xe3)
 		return -ENODEV;
 
 	sn9c102_attach_sensor(cam, &mi0343);
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/video/sn9c102/sn9c102_mi0360.c
new file mode 100644
index 0000000..64698ac
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_mi0360.c
@@ -0,0 +1,338 @@
+/***************************************************************************
+ * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static int mi0360_init(struct sn9c102_device* cam)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+
+	err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
+				       {0x0a, 0x14}, {0x40, 0x01},
+				       {0x20, 0x17}, {0x07, 0x18},
+				       {0xa0, 0x19}, {0x02, 0x1c},
+				       {0x03, 0x1d}, {0x0f, 0x1e},
+				       {0x0c, 0x1f}, {0x00, 0x20},
+				       {0x10, 0x21}, {0x20, 0x22},
+				       {0x30, 0x23}, {0x40, 0x24},
+				       {0x50, 0x25}, {0x60, 0x26},
+				       {0x70, 0x27}, {0x80, 0x28},
+				       {0x90, 0x29}, {0xa0, 0x2a},
+				       {0xb0, 0x2b}, {0xc0, 0x2c},
+				       {0xd0, 0x2d}, {0xe0, 0x2e},
+				       {0xf0, 0x2f}, {0xff, 0x30});
+
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x01, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
+					 0x01, 0xe1, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
+					 0x02, 0x81, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
+					 0x00, 0x17, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
+					 0x00, 0x11, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
+					 0x04, 0x9a, 0, 0);
+
+	return err;
+}
+
+
+static int mi0360_get_ctrl(struct sn9c102_device* cam,
+			   struct v4l2_control* ctrl)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	u8 data[5+1];
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[2];
+		return 0;
+	case V4L2_CID_GAIN:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3];
+		return 0;
+	case V4L2_CID_RED_BALANCE:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3];
+		return 0;
+	case V4L2_CID_BLUE_BALANCE:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3];
+		return 0;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3];
+		return 0;
+	case V4L2_CID_HFLIP:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3] & 0x20 ? 1 : 0;
+		return 0;
+	case V4L2_CID_VFLIP:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
+					     2+1, data) < 0)
+			return -EIO;
+		ctrl->value = data[3] & 0x80 ? 1 : 0;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int mi0360_set_ctrl(struct sn9c102_device* cam,
+			   const struct v4l2_control* ctrl)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x09, ctrl->value, 0x00,
+						 0, 0);
+		break;
+	case V4L2_CID_GAIN:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x35, 0x03, ctrl->value,
+						 0, 0);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x2c, 0x03, ctrl->value,
+						 0, 0);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x2d, 0x03, ctrl->value,
+						 0, 0);
+		break;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x2b, 0x03, ctrl->value,
+						 0, 0);
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x2e, 0x03, ctrl->value,
+						 0, 0);
+		break;
+	case V4L2_CID_HFLIP:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x20, ctrl->value ? 0x40:0x00,
+						 ctrl->value ? 0x20:0x00,
+						 0, 0);
+		break;
+	case V4L2_CID_VFLIP:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x20, ctrl->value ? 0x80:0x00,
+						 ctrl->value ? 0x80:0x00,
+						 0, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return err ? -EIO : 0;
+}
+
+
+static int mi0360_set_crop(struct sn9c102_device* cam,
+			    const struct v4l2_rect* rect)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
+	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+	err += sn9c102_write_reg(cam, h_start, 0x12);
+	err += sn9c102_write_reg(cam, v_start, 0x13);
+
+	return err;
+}
+
+
+static int mi0360_set_pix_format(struct sn9c102_device* cam,
+				 const struct v4l2_pix_format* pix)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x0a, 0x00, 0x02, 0, 0);
+		err += sn9c102_write_reg(cam, 0x20, 0x19);
+	} else {
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x0a, 0x00, 0x05, 0, 0);
+		err += sn9c102_write_reg(cam, 0x60, 0x19);
+	}
+
+	return err;
+}
+
+
+static struct sn9c102_sensor mi0360 = {
+	.name = "MI-0360",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.supported_bridge = BRIDGE_SN9C103,
+	.frequency = SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x5d,
+	.init = &mi0360_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "exposure",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x05,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "global gain",
+			.minimum = 0x00,
+			.maximum = 0x7f,
+			.step = 0x01,
+			.default_value = 0x25,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_HFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "horizontal mirror",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 0,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_VFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "vertical mirror",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 0,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "blue balance",
+			.minimum = 0x00,
+			.maximum = 0x7f,
+			.step = 0x01,
+			.default_value = 0x0f,
+			.flags = 0,
+		},
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "red balance",
+			.minimum = 0x00,
+			.maximum = 0x7f,
+			.step = 0x01,
+			.default_value = 0x32,
+			.flags = 0,
+		},
+		{
+			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "green balance",
+			.minimum = 0x00,
+			.maximum = 0x7f,
+			.step = 0x01,
+			.default_value = 0x25,
+			.flags = 0,
+		},
+	},
+	.get_ctrl = &mi0360_get_ctrl,
+	.set_ctrl = &mi0360_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.set_crop = &mi0360_set_crop,
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &mi0360_set_pix_format
+};
+
+
+int sn9c102_probe_mi0360(struct sn9c102_device* cam)
+{
+	u8 data[5+1];
+	int err;
+
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
+				       {0x28, 0x17});
+	if (err)
+		return -EIO;
+
+	if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00,
+				     2+1, data) < 0)
+		return -EIO;
+
+	if (data[2] != 0x82 || data[3] != 0x43)
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &mi0360);
+
+	return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index 7df09ff..31b6080 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -22,9 +22,6 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor ov7630;
-
-
 static int ov7630_init(struct sn9c102_device* cam)
 {
 	int err = 0;
@@ -32,21 +29,20 @@ static int ov7630_init(struct sn9c102_de
 	switch (sn9c102_get_bridge(cam)) {
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
-	err += sn9c102_write_reg(cam, 0x00, 0x14);
-	err += sn9c102_write_reg(cam, 0x60, 0x17);
-	err += sn9c102_write_reg(cam, 0x0f, 0x18);
-	err += sn9c102_write_reg(cam, 0x50, 0x19);
+		err = sn9c102_write_const_regs(cam, {0x00, 0x14},
+					       {0x60, 0x17}, {0x0f, 0x18},
+					       {0x50, 0x19});
 
 		err += sn9c102_i2c_write(cam, 0x12, 0x8d);
 		err += sn9c102_i2c_write(cam, 0x12, 0x0d);
 		err += sn9c102_i2c_write(cam, 0x11, 0x00);
-	err += sn9c102_i2c_write(cam, 0x15, 0x34);
-	err += sn9c102_i2c_write(cam, 0x16, 0x03);
-	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
-	err += sn9c102_i2c_write(cam, 0x18, 0xbd);
-	err += sn9c102_i2c_write(cam, 0x19, 0x06);
-	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
-	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+		err += sn9c102_i2c_write(cam, 0x15, 0x35);
+		err += sn9c102_i2c_write(cam, 0x16, 0x03);
+		err += sn9c102_i2c_write(cam, 0x17, 0x1c);
+		err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+		err += sn9c102_i2c_write(cam, 0x19, 0x06);
+		err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+		err += sn9c102_i2c_write(cam, 0x1b, 0x04);
 		err += sn9c102_i2c_write(cam, 0x20, 0x44);
 		err += sn9c102_i2c_write(cam, 0x23, 0xee);
 		err += sn9c102_i2c_write(cam, 0x26, 0xa0);
@@ -65,42 +61,26 @@ static int ov7630_init(struct sn9c102_de
 		err += sn9c102_i2c_write(cam, 0x71, 0x00);
 		err += sn9c102_i2c_write(cam, 0x74, 0x21);
 		err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+
 		break;
 	case BRIDGE_SN9C103:
-		err += sn9c102_write_reg(cam, 0x00, 0x02);
-		err += sn9c102_write_reg(cam, 0x00, 0x03);
-		err += sn9c102_write_reg(cam, 0x1a, 0x04);
-		err += sn9c102_write_reg(cam, 0x20, 0x05);
-		err += sn9c102_write_reg(cam, 0x20, 0x06);
-		err += sn9c102_write_reg(cam, 0x20, 0x07);
-		err += sn9c102_write_reg(cam, 0x03, 0x10);
-		err += sn9c102_write_reg(cam, 0x0a, 0x14);
-		err += sn9c102_write_reg(cam, 0x60, 0x17);
-		err += sn9c102_write_reg(cam, 0x0f, 0x18);
-		err += sn9c102_write_reg(cam, 0x50, 0x19);
-		err += sn9c102_write_reg(cam, 0x1d, 0x1a);
-		err += sn9c102_write_reg(cam, 0x10, 0x1b);
-		err += sn9c102_write_reg(cam, 0x02, 0x1c);
-		err += sn9c102_write_reg(cam, 0x03, 0x1d);
-		err += sn9c102_write_reg(cam, 0x0f, 0x1e);
-		err += sn9c102_write_reg(cam, 0x0c, 0x1f);
-		err += sn9c102_write_reg(cam, 0x00, 0x20);
-		err += sn9c102_write_reg(cam, 0x10, 0x21);
-		err += sn9c102_write_reg(cam, 0x20, 0x22);
-		err += sn9c102_write_reg(cam, 0x30, 0x23);
-		err += sn9c102_write_reg(cam, 0x40, 0x24);
-		err += sn9c102_write_reg(cam, 0x50, 0x25);
-		err += sn9c102_write_reg(cam, 0x60, 0x26);
-		err += sn9c102_write_reg(cam, 0x70, 0x27);
-		err += sn9c102_write_reg(cam, 0x80, 0x28);
-		err += sn9c102_write_reg(cam, 0x90, 0x29);
-		err += sn9c102_write_reg(cam, 0xa0, 0x2a);
-		err += sn9c102_write_reg(cam, 0xb0, 0x2b);
-		err += sn9c102_write_reg(cam, 0xc0, 0x2c);
-		err += sn9c102_write_reg(cam, 0xd0, 0x2d);
-		err += sn9c102_write_reg(cam, 0xe0, 0x2e);
-		err += sn9c102_write_reg(cam, 0xf0, 0x2f);
-		err += sn9c102_write_reg(cam, 0xff, 0x30);
+		err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03},
+					       {0x1a, 0x04}, {0x20, 0x05},
+					       {0x20, 0x06}, {0x20, 0x07},
+					       {0x03, 0x10}, {0x0a, 0x14},
+					       {0x60, 0x17}, {0x0f, 0x18},
+					       {0x50, 0x19}, {0x1d, 0x1a},
+					       {0x10, 0x1b}, {0x02, 0x1c},
+					       {0x03, 0x1d}, {0x0f, 0x1e},
+					       {0x0c, 0x1f}, {0x00, 0x20},
+					       {0x10, 0x21}, {0x20, 0x22},
+					       {0x30, 0x23}, {0x40, 0x24},
+					       {0x50, 0x25}, {0x60, 0x26},
+					       {0x70, 0x27}, {0x80, 0x28},
+					       {0x90, 0x29}, {0xa0, 0x2a},
+					       {0xb0, 0x2b}, {0xc0, 0x2c},
+					       {0xd0, 0x2d}, {0xe0, 0x2e},
+					       {0xf0, 0x2f}, {0xff, 0x30});
 
 		err += sn9c102_i2c_write(cam, 0x12, 0x8d);
 		err += sn9c102_i2c_write(cam, 0x12, 0x0d);
@@ -108,23 +88,23 @@ static int ov7630_init(struct sn9c102_de
 		err += sn9c102_i2c_write(cam, 0x11, 0x01);
 		err += sn9c102_i2c_write(cam, 0x1b, 0x04);
 		err += sn9c102_i2c_write(cam, 0x20, 0x44);
-	err += sn9c102_i2c_write(cam, 0x23, 0xee);
-	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
-	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+		err += sn9c102_i2c_write(cam, 0x23, 0xee);
+		err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+		err += sn9c102_i2c_write(cam, 0x27, 0x9a);
 		err += sn9c102_i2c_write(cam, 0x28, 0x20);
-	err += sn9c102_i2c_write(cam, 0x29, 0x30);
-	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
-	err += sn9c102_i2c_write(cam, 0x30, 0x24);
-	err += sn9c102_i2c_write(cam, 0x32, 0x86);
-	err += sn9c102_i2c_write(cam, 0x60, 0xa9);
-	err += sn9c102_i2c_write(cam, 0x61, 0x42);
-	err += sn9c102_i2c_write(cam, 0x65, 0x00);
-	err += sn9c102_i2c_write(cam, 0x69, 0x38);
-	err += sn9c102_i2c_write(cam, 0x6f, 0x88);
-	err += sn9c102_i2c_write(cam, 0x70, 0x0b);
-	err += sn9c102_i2c_write(cam, 0x71, 0x00);
-	err += sn9c102_i2c_write(cam, 0x74, 0x21);
-	err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+		err += sn9c102_i2c_write(cam, 0x29, 0x30);
+		err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+		err += sn9c102_i2c_write(cam, 0x30, 0x24);
+		err += sn9c102_i2c_write(cam, 0x32, 0x86);
+		err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+		err += sn9c102_i2c_write(cam, 0x61, 0x42);
+		err += sn9c102_i2c_write(cam, 0x65, 0x00);
+		err += sn9c102_i2c_write(cam, 0x69, 0x38);
+		err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+		err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+		err += sn9c102_i2c_write(cam, 0x71, 0x00);
+		err += sn9c102_i2c_write(cam, 0x74, 0x21);
+		err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
 		break;
 	default:
 		break;
@@ -428,15 +408,14 @@ int sn9c102_probe_ov7630(struct sn9c102_
 	switch (sn9c102_get_bridge(cam)) {
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x00, 0x01);
-	err += sn9c102_write_reg(cam, 0x28, 0x17);
+		err = sn9c102_write_const_regs(cam, {0x01, 0x01},
+					       {0x00, 0x01}, {0x28, 0x17});
+
 		break;
 	case BRIDGE_SN9C103: /* do _not_ change anything! */
-		err += sn9c102_write_reg(cam, 0x09, 0x01);
-		err += sn9c102_write_reg(cam, 0x42, 0x01);
-		err += sn9c102_write_reg(cam, 0x28, 0x17);
-		err += sn9c102_write_reg(cam, 0x44, 0x02);
+		err = sn9c102_write_const_regs(cam, {0x09, 0x01},
+					       {0x42, 0x01}, {0x28, 0x17},
+					       {0x44, 0x02});
 		pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
 		if (err || pid < 0) { /* try a different initialization */
 			err = sn9c102_write_reg(cam, 0x01, 0x01);
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index d670c24..c898e94 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -22,160 +22,84 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor ov7660;
-
-
 static int ov7660_init(struct sn9c102_device* cam)
 {
 	int err = 0;
 
-	err += sn9c102_write_reg(cam, 0x40, 0x02);
-	err += sn9c102_write_reg(cam, 0x00, 0x03);
-	err += sn9c102_write_reg(cam, 0x1a, 0x04);
-	err += sn9c102_write_reg(cam, 0x03, 0x10);
-	err += sn9c102_write_reg(cam, 0x08, 0x14);
-	err += sn9c102_write_reg(cam, 0x20, 0x17);
-	err += sn9c102_write_reg(cam, 0x8b, 0x18);
-	err += sn9c102_write_reg(cam, 0x00, 0x19);
-	err += sn9c102_write_reg(cam, 0x1d, 0x1a);
-	err += sn9c102_write_reg(cam, 0x10, 0x1b);
-	err += sn9c102_write_reg(cam, 0x02, 0x1c);
-	err += sn9c102_write_reg(cam, 0x03, 0x1d);
-	err += sn9c102_write_reg(cam, 0x0f, 0x1e);
-	err += sn9c102_write_reg(cam, 0x0c, 0x1f);
-	err += sn9c102_write_reg(cam, 0x00, 0x20);
-	err += sn9c102_write_reg(cam, 0x29, 0x21);
-	err += sn9c102_write_reg(cam, 0x40, 0x22);
-	err += sn9c102_write_reg(cam, 0x54, 0x23);
-	err += sn9c102_write_reg(cam, 0x66, 0x24);
-	err += sn9c102_write_reg(cam, 0x76, 0x25);
-	err += sn9c102_write_reg(cam, 0x85, 0x26);
-	err += sn9c102_write_reg(cam, 0x94, 0x27);
-	err += sn9c102_write_reg(cam, 0xa1, 0x28);
-	err += sn9c102_write_reg(cam, 0xae, 0x29);
-	err += sn9c102_write_reg(cam, 0xbb, 0x2a);
-	err += sn9c102_write_reg(cam, 0xc7, 0x2b);
-	err += sn9c102_write_reg(cam, 0xd3, 0x2c);
-	err += sn9c102_write_reg(cam, 0xde, 0x2d);
-	err += sn9c102_write_reg(cam, 0xea, 0x2e);
-	err += sn9c102_write_reg(cam, 0xf4, 0x2f);
-	err += sn9c102_write_reg(cam, 0xff, 0x30);
-	err += sn9c102_write_reg(cam, 0x00, 0x3F);
-	err += sn9c102_write_reg(cam, 0xC7, 0x40);
-	err += sn9c102_write_reg(cam, 0x01, 0x41);
-	err += sn9c102_write_reg(cam, 0x44, 0x42);
-	err += sn9c102_write_reg(cam, 0x00, 0x43);
-	err += sn9c102_write_reg(cam, 0x44, 0x44);
-	err += sn9c102_write_reg(cam, 0x00, 0x45);
-	err += sn9c102_write_reg(cam, 0x44, 0x46);
-	err += sn9c102_write_reg(cam, 0x00, 0x47);
-	err += sn9c102_write_reg(cam, 0xC7, 0x48);
-	err += sn9c102_write_reg(cam, 0x01, 0x49);
-	err += sn9c102_write_reg(cam, 0xC7, 0x4A);
-	err += sn9c102_write_reg(cam, 0x01, 0x4B);
-	err += sn9c102_write_reg(cam, 0xC7, 0x4C);
-	err += sn9c102_write_reg(cam, 0x01, 0x4D);
-	err += sn9c102_write_reg(cam, 0x44, 0x4E);
-	err += sn9c102_write_reg(cam, 0x00, 0x4F);
-	err += sn9c102_write_reg(cam, 0x44, 0x50);
-	err += sn9c102_write_reg(cam, 0x00, 0x51);
-	err += sn9c102_write_reg(cam, 0x44, 0x52);
-	err += sn9c102_write_reg(cam, 0x00, 0x53);
-	err += sn9c102_write_reg(cam, 0xC7, 0x54);
-	err += sn9c102_write_reg(cam, 0x01, 0x55);
-	err += sn9c102_write_reg(cam, 0xC7, 0x56);
-	err += sn9c102_write_reg(cam, 0x01, 0x57);
-	err += sn9c102_write_reg(cam, 0xC7, 0x58);
-	err += sn9c102_write_reg(cam, 0x01, 0x59);
-	err += sn9c102_write_reg(cam, 0x44, 0x5A);
-	err += sn9c102_write_reg(cam, 0x00, 0x5B);
-	err += sn9c102_write_reg(cam, 0x44, 0x5C);
-	err += sn9c102_write_reg(cam, 0x00, 0x5D);
-	err += sn9c102_write_reg(cam, 0x44, 0x5E);
-	err += sn9c102_write_reg(cam, 0x00, 0x5F);
-	err += sn9c102_write_reg(cam, 0xC7, 0x60);
-	err += sn9c102_write_reg(cam, 0x01, 0x61);
-	err += sn9c102_write_reg(cam, 0xC7, 0x62);
-	err += sn9c102_write_reg(cam, 0x01, 0x63);
-	err += sn9c102_write_reg(cam, 0xC7, 0x64);
-	err += sn9c102_write_reg(cam, 0x01, 0x65);
-	err += sn9c102_write_reg(cam, 0x44, 0x66);
-	err += sn9c102_write_reg(cam, 0x00, 0x67);
-	err += sn9c102_write_reg(cam, 0x44, 0x68);
-	err += sn9c102_write_reg(cam, 0x00, 0x69);
-	err += sn9c102_write_reg(cam, 0x44, 0x6A);
-	err += sn9c102_write_reg(cam, 0x00, 0x6B);
-	err += sn9c102_write_reg(cam, 0xC7, 0x6C);
-	err += sn9c102_write_reg(cam, 0x01, 0x6D);
-	err += sn9c102_write_reg(cam, 0xC7, 0x6E);
-	err += sn9c102_write_reg(cam, 0x01, 0x6F);
-	err += sn9c102_write_reg(cam, 0xC7, 0x70);
-	err += sn9c102_write_reg(cam, 0x01, 0x71);
-	err += sn9c102_write_reg(cam, 0x44, 0x72);
-	err += sn9c102_write_reg(cam, 0x00, 0x73);
-	err += sn9c102_write_reg(cam, 0x44, 0x74);
-	err += sn9c102_write_reg(cam, 0x00, 0x75);
-	err += sn9c102_write_reg(cam, 0x44, 0x76);
-	err += sn9c102_write_reg(cam, 0x00, 0x77);
-	err += sn9c102_write_reg(cam, 0xC7, 0x78);
-	err += sn9c102_write_reg(cam, 0x01, 0x79);
-	err += sn9c102_write_reg(cam, 0xC7, 0x7A);
-	err += sn9c102_write_reg(cam, 0x01, 0x7B);
-	err += sn9c102_write_reg(cam, 0xC7, 0x7C);
-	err += sn9c102_write_reg(cam, 0x01, 0x7D);
-	err += sn9c102_write_reg(cam, 0x44, 0x7E);
-	err += sn9c102_write_reg(cam, 0x00, 0x7F);
-	err += sn9c102_write_reg(cam, 0x14, 0x84);
-	err += sn9c102_write_reg(cam, 0x00, 0x85);
-	err += sn9c102_write_reg(cam, 0x27, 0x86);
-	err += sn9c102_write_reg(cam, 0x00, 0x87);
-	err += sn9c102_write_reg(cam, 0x07, 0x88);
-	err += sn9c102_write_reg(cam, 0x00, 0x89);
-	err += sn9c102_write_reg(cam, 0xEC, 0x8A);
-	err += sn9c102_write_reg(cam, 0x0f, 0x8B);
-	err += sn9c102_write_reg(cam, 0xD8, 0x8C);
-	err += sn9c102_write_reg(cam, 0x0f, 0x8D);
-	err += sn9c102_write_reg(cam, 0x3D, 0x8E);
-	err += sn9c102_write_reg(cam, 0x00, 0x8F);
-	err += sn9c102_write_reg(cam, 0x3D, 0x90);
-	err += sn9c102_write_reg(cam, 0x00, 0x91);
-	err += sn9c102_write_reg(cam, 0xCD, 0x92);
-	err += sn9c102_write_reg(cam, 0x0f, 0x93);
-	err += sn9c102_write_reg(cam, 0xf7, 0x94);
-	err += sn9c102_write_reg(cam, 0x0f, 0x95);
-	err += sn9c102_write_reg(cam, 0x0C, 0x96);
-	err += sn9c102_write_reg(cam, 0x00, 0x97);
-	err += sn9c102_write_reg(cam, 0x00, 0x98);
-	err += sn9c102_write_reg(cam, 0x66, 0x99);
-	err += sn9c102_write_reg(cam, 0x05, 0x9A);
-	err += sn9c102_write_reg(cam, 0x00, 0x9B);
-	err += sn9c102_write_reg(cam, 0x04, 0x9C);
-	err += sn9c102_write_reg(cam, 0x00, 0x9D);
-	err += sn9c102_write_reg(cam, 0x08, 0x9E);
-	err += sn9c102_write_reg(cam, 0x00, 0x9F);
-	err += sn9c102_write_reg(cam, 0x2D, 0xC0);
-	err += sn9c102_write_reg(cam, 0x2D, 0xC1);
-	err += sn9c102_write_reg(cam, 0x3A, 0xC2);
-	err += sn9c102_write_reg(cam, 0x05, 0xC3);
-	err += sn9c102_write_reg(cam, 0x04, 0xC4);
-	err += sn9c102_write_reg(cam, 0x3F, 0xC5);
-	err += sn9c102_write_reg(cam, 0x00, 0xC6);
-	err += sn9c102_write_reg(cam, 0x00, 0xC7);
-	err += sn9c102_write_reg(cam, 0x50, 0xC8);
-	err += sn9c102_write_reg(cam, 0x3C, 0xC9);
-	err += sn9c102_write_reg(cam, 0x28, 0xCA);
-	err += sn9c102_write_reg(cam, 0xD8, 0xCB);
-	err += sn9c102_write_reg(cam, 0x14, 0xCC);
-	err += sn9c102_write_reg(cam, 0xEC, 0xCD);
-	err += sn9c102_write_reg(cam, 0x32, 0xCE);
-	err += sn9c102_write_reg(cam, 0xDD, 0xCF);
-	err += sn9c102_write_reg(cam, 0x32, 0xD0);
-	err += sn9c102_write_reg(cam, 0xDD, 0xD1);
-	err += sn9c102_write_reg(cam, 0x6A, 0xD2);
-	err += sn9c102_write_reg(cam, 0x50, 0xD3);
-	err += sn9c102_write_reg(cam, 0x00, 0xD4);
-	err += sn9c102_write_reg(cam, 0x00, 0xD5);
-	err += sn9c102_write_reg(cam, 0x00, 0xD6);
+	err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+				       {0x1a, 0x04}, {0x03, 0x10},
+				       {0x08, 0x14}, {0x20, 0x17},
+				       {0x8b, 0x18}, {0x00, 0x19},
+				       {0x1d, 0x1a}, {0x10, 0x1b},
+				       {0x02, 0x1c}, {0x03, 0x1d},
+				       {0x0f, 0x1e}, {0x0c, 0x1f},
+				       {0x00, 0x20}, {0x29, 0x21},
+				       {0x40, 0x22}, {0x54, 0x23},
+				       {0x66, 0x24}, {0x76, 0x25},
+				       {0x85, 0x26}, {0x94, 0x27},
+				       {0xa1, 0x28}, {0xae, 0x29},
+				       {0xbb, 0x2a}, {0xc7, 0x2b},
+				       {0xd3, 0x2c}, {0xde, 0x2d},
+				       {0xea, 0x2e}, {0xf4, 0x2f},
+				       {0xff, 0x30}, {0x00, 0x3F},
+				       {0xC7, 0x40}, {0x01, 0x41},
+				       {0x44, 0x42}, {0x00, 0x43},
+				       {0x44, 0x44}, {0x00, 0x45},
+				       {0x44, 0x46}, {0x00, 0x47},
+				       {0xC7, 0x48}, {0x01, 0x49},
+				       {0xC7, 0x4A}, {0x01, 0x4B},
+				       {0xC7, 0x4C}, {0x01, 0x4D},
+				       {0x44, 0x4E}, {0x00, 0x4F},
+				       {0x44, 0x50}, {0x00, 0x51},
+				       {0x44, 0x52}, {0x00, 0x53},
+				       {0xC7, 0x54}, {0x01, 0x55},
+				       {0xC7, 0x56}, {0x01, 0x57},
+				       {0xC7, 0x58}, {0x01, 0x59},
+				       {0x44, 0x5A}, {0x00, 0x5B},
+				       {0x44, 0x5C}, {0x00, 0x5D},
+				       {0x44, 0x5E}, {0x00, 0x5F},
+				       {0xC7, 0x60}, {0x01, 0x61},
+				       {0xC7, 0x62}, {0x01, 0x63},
+				       {0xC7, 0x64}, {0x01, 0x65},
+				       {0x44, 0x66}, {0x00, 0x67},
+				       {0x44, 0x68}, {0x00, 0x69},
+				       {0x44, 0x6A}, {0x00, 0x6B},
+				       {0xC7, 0x6C}, {0x01, 0x6D},
+				       {0xC7, 0x6E}, {0x01, 0x6F},
+				       {0xC7, 0x70}, {0x01, 0x71},
+				       {0x44, 0x72}, {0x00, 0x73},
+				       {0x44, 0x74}, {0x00, 0x75},
+				       {0x44, 0x76}, {0x00, 0x77},
+				       {0xC7, 0x78}, {0x01, 0x79},
+				       {0xC7, 0x7A}, {0x01, 0x7B},
+				       {0xC7, 0x7C}, {0x01, 0x7D},
+				       {0x44, 0x7E}, {0x00, 0x7F},
+				       {0x14, 0x84}, {0x00, 0x85},
+				       {0x27, 0x86}, {0x00, 0x87},
+				       {0x07, 0x88}, {0x00, 0x89},
+				       {0xEC, 0x8A}, {0x0f, 0x8B},
+				       {0xD8, 0x8C}, {0x0f, 0x8D},
+				       {0x3D, 0x8E}, {0x00, 0x8F},
+				       {0x3D, 0x90}, {0x00, 0x91},
+				       {0xCD, 0x92}, {0x0f, 0x93},
+				       {0xf7, 0x94}, {0x0f, 0x95},
+				       {0x0C, 0x96}, {0x00, 0x97},
+				       {0x00, 0x98}, {0x66, 0x99},
+				       {0x05, 0x9A}, {0x00, 0x9B},
+				       {0x04, 0x9C}, {0x00, 0x9D},
+				       {0x08, 0x9E}, {0x00, 0x9F},
+				       {0x2D, 0xC0}, {0x2D, 0xC1},
+				       {0x3A, 0xC2}, {0x05, 0xC3},
+				       {0x04, 0xC4}, {0x3F, 0xC5},
+				       {0x00, 0xC6}, {0x00, 0xC7},
+				       {0x50, 0xC8}, {0x3C, 0xC9},
+				       {0x28, 0xCA}, {0xD8, 0xCB},
+				       {0x14, 0xCC}, {0xEC, 0xCD},
+				       {0x32, 0xCE}, {0xDD, 0xCF},
+				       {0x32, 0xD0}, {0xDD, 0xD1},
+				       {0x6A, 0xD2}, {0x50, 0xD3},
+				       {0x00, 0xD4}, {0x00, 0xD5},
+				       {0x00, 0xD6});
 
 	err += sn9c102_i2c_write(cam, 0x12, 0x80);
 	err += sn9c102_i2c_write(cam, 0x11, 0x09);
@@ -572,13 +496,11 @@ static struct sn9c102_sensor ov7660 = {
 
 int sn9c102_probe_ov7660(struct sn9c102_device* cam)
 {
-	int pid, ver, err = 0;
+	int pid, ver, err;
 
-	err += sn9c102_write_reg(cam, 0x01, 0xf1);
-	err += sn9c102_write_reg(cam, 0x00, 0xf1);
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x00, 0x01);
-	err += sn9c102_write_reg(cam, 0x28, 0x17);
+	err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+				       {0x01, 0x01}, {0x00, 0x01},
+				       {0x28, 0x17});
 
 	pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
 	ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
index 8d79a5f..6715196 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas106b.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c
@@ -23,19 +23,13 @@ #include <linux/delay.h>
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor pas106b;
-
-
 static int pas106b_init(struct sn9c102_device* cam)
 {
 	int err = 0;
 
-	err += sn9c102_write_reg(cam, 0x00, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x00, 0x14);
-	err += sn9c102_write_reg(cam, 0x20, 0x17);
-	err += sn9c102_write_reg(cam, 0x20, 0x19);
-	err += sn9c102_write_reg(cam, 0x09, 0x18);
+	err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
+				       {0x00, 0x14}, {0x20, 0x17},
+				       {0x20, 0x19}, {0x09, 0x18});
 
 	err += sn9c102_i2c_write(cam, 0x02, 0x0c);
 	err += sn9c102_i2c_write(cam, 0x05, 0x5a);
@@ -172,7 +166,7 @@ static int pas106b_set_pix_format(struct
 static struct sn9c102_sensor pas106b = {
 	.name = "PAS106B",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
 	.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_2WIRES,
@@ -279,16 +273,17 @@ static struct sn9c102_sensor pas106b = {
 
 int sn9c102_probe_pas106b(struct sn9c102_device* cam)
 {
-	int r0 = 0, r1 = 0, err = 0;
+	int r0 = 0, r1 = 0, err;
 	unsigned int pid = 0;
 
 	/*
 	   Minimal initialization to enable the I2C communication
 	   NOTE: do NOT change the values!
 	*/
-	err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-	err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
-	err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+	err = sn9c102_write_const_regs(cam,
+				       {0x01, 0x01}, /* sensor power down */
+				       {0x00, 0x01}, /* sensor power on */
+				       {0x28, 0x17});/* sensor clock 24 MHz */
 	if (err)
 		return -EIO;
 
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index 7894f01..c1b8d6b 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -28,9 +28,6 @@ #include <linux/delay.h>
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor pas202bcb;
-
-
 static int pas202bcb_init(struct sn9c102_device* cam)
 {
 	int err = 0;
@@ -38,47 +35,29 @@ static int pas202bcb_init(struct sn9c102
 	switch (sn9c102_get_bridge(cam)) {
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
-	err += sn9c102_write_reg(cam, 0x00, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x00, 0x14);
-	err += sn9c102_write_reg(cam, 0x20, 0x17);
-	err += sn9c102_write_reg(cam, 0x30, 0x19);
-	err += sn9c102_write_reg(cam, 0x09, 0x18);
+		err = sn9c102_write_const_regs(cam, {0x00, 0x10},
+					       {0x00, 0x11}, {0x00, 0x14},
+					       {0x20, 0x17}, {0x30, 0x19},
+					       {0x09, 0x18});
 		break;
 	case BRIDGE_SN9C103:
-		err += sn9c102_write_reg(cam, 0x00, 0x02);
-		err += sn9c102_write_reg(cam, 0x00, 0x03);
-		err += sn9c102_write_reg(cam, 0x1a, 0x04);
-		err += sn9c102_write_reg(cam, 0x20, 0x05);
-		err += sn9c102_write_reg(cam, 0x20, 0x06);
-		err += sn9c102_write_reg(cam, 0x20, 0x07);
-		err += sn9c102_write_reg(cam, 0x00, 0x10);
-		err += sn9c102_write_reg(cam, 0x00, 0x11);
-		err += sn9c102_write_reg(cam, 0x00, 0x14);
-		err += sn9c102_write_reg(cam, 0x20, 0x17);
-		err += sn9c102_write_reg(cam, 0x30, 0x19);
-		err += sn9c102_write_reg(cam, 0x09, 0x18);
-		err += sn9c102_write_reg(cam, 0x02, 0x1c);
-		err += sn9c102_write_reg(cam, 0x03, 0x1d);
-		err += sn9c102_write_reg(cam, 0x0f, 0x1e);
-		err += sn9c102_write_reg(cam, 0x0c, 0x1f);
-		err += sn9c102_write_reg(cam, 0x00, 0x20);
-		err += sn9c102_write_reg(cam, 0x10, 0x21);
-		err += sn9c102_write_reg(cam, 0x20, 0x22);
-		err += sn9c102_write_reg(cam, 0x30, 0x23);
-		err += sn9c102_write_reg(cam, 0x40, 0x24);
-		err += sn9c102_write_reg(cam, 0x50, 0x25);
-		err += sn9c102_write_reg(cam, 0x60, 0x26);
-		err += sn9c102_write_reg(cam, 0x70, 0x27);
-		err += sn9c102_write_reg(cam, 0x80, 0x28);
-		err += sn9c102_write_reg(cam, 0x90, 0x29);
-		err += sn9c102_write_reg(cam, 0xa0, 0x2a);
-		err += sn9c102_write_reg(cam, 0xb0, 0x2b);
-		err += sn9c102_write_reg(cam, 0xc0, 0x2c);
-		err += sn9c102_write_reg(cam, 0xd0, 0x2d);
-		err += sn9c102_write_reg(cam, 0xe0, 0x2e);
-		err += sn9c102_write_reg(cam, 0xf0, 0x2f);
-		err += sn9c102_write_reg(cam, 0xff, 0x30);
+		err = sn9c102_write_const_regs(cam, {0x00, 0x02},
+					       {0x00, 0x03}, {0x1a, 0x04},
+					       {0x20, 0x05}, {0x20, 0x06},
+					       {0x20, 0x07}, {0x00, 0x10},
+					       {0x00, 0x11}, {0x00, 0x14},
+					       {0x20, 0x17}, {0x30, 0x19},
+					       {0x09, 0x18}, {0x02, 0x1c},
+					       {0x03, 0x1d}, {0x0f, 0x1e},
+					       {0x0c, 0x1f}, {0x00, 0x20},
+					       {0x10, 0x21}, {0x20, 0x22},
+					       {0x30, 0x23}, {0x40, 0x24},
+					       {0x50, 0x25}, {0x60, 0x26},
+					       {0x70, 0x27}, {0x80, 0x28},
+					       {0x90, 0x29}, {0xa0, 0x2a},
+					       {0xb0, 0x2b}, {0xc0, 0x2c},
+					       {0xd0, 0x2d}, {0xe0, 0x2e},
+					       {0xf0, 0x2f}, {0xff, 0x30});
 		break;
 	default:
 		break;
@@ -328,15 +307,15 @@ int sn9c102_probe_pas202bcb(struct sn9c1
 	switch (sn9c102_get_bridge(cam)) {
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
-		err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
-		err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
-		err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
+		err = sn9c102_write_const_regs(cam,
+					       {0x01, 0x01}, /* power down */
+					       {0x40, 0x01}, /* power on */
+					       {0x28, 0x17});/* clock 24 MHz */
 		break;
 	case BRIDGE_SN9C103: /* do _not_ change anything! */
-		err += sn9c102_write_reg(cam, 0x09, 0x01);
-		err += sn9c102_write_reg(cam, 0x44, 0x01);
-		err += sn9c102_write_reg(cam, 0x44, 0x02);
-		err += sn9c102_write_reg(cam, 0x29, 0x17);
+		err = sn9c102_write_const_regs(cam, {0x09, 0x01},
+					       {0x44, 0x01}, {0x44, 0x02},
+					       {0x29, 0x17});
 		break;
 	default:
 		break;
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 05f2942..1bbf64c 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -114,9 +114,17 @@ extern int sn9c102_i2c_write(struct sn9c
 extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
 
 /* I/O on registers in the bridge. Could be used by the sensor methods too */
-extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
-extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
 extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
+extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
+extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2],
+			      int count);
+/*
+ * Write multiple registers with constant values.  For example:
+ * sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18});
+ */
+#define sn9c102_write_const_regs(device, data...) \
+	({ const static u8 _data[][2] = {data}; \
+	sn9c102_write_regs(device, _data, ARRAY_SIZE(_data)); })
 
 /*****************************************************************************/
 
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
index 90023ad..0e7ec86 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
@@ -22,21 +22,14 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor tas5110c1b;
-
-
 static int tas5110c1b_init(struct sn9c102_device* cam)
 {
 	int err = 0;
 
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x44, 0x01);
-	err += sn9c102_write_reg(cam, 0x00, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x0a, 0x14);
-	err += sn9c102_write_reg(cam, 0x60, 0x17);
-	err += sn9c102_write_reg(cam, 0x06, 0x18);
-	err += sn9c102_write_reg(cam, 0xfb, 0x19);
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01},
+				       {0x00, 0x10}, {0x00, 0x11},
+				       {0x0a, 0x14}, {0x60, 0x17},
+				       {0x06, 0x18}, {0xfb, 0x19});
 
 	err += sn9c102_i2c_write(cam, 0xc0, 0x80);
 
@@ -98,7 +91,7 @@ static int tas5110c1b_set_pix_format(str
 static struct sn9c102_sensor tas5110c1b = {
 	.name = "TAS5110C1B",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 	.sysfs_ops = SN9C102_I2C_WRITE,
 	.frequency = SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_3WIRES,
@@ -146,7 +139,6 @@ int sn9c102_probe_tas5110c1b(struct sn9c
 	const struct usb_device_id tas5110c1b_id_table[] = {
 		{ USB_DEVICE(0x0c45, 0x6001), },
 		{ USB_DEVICE(0x0c45, 0x6005), },
-		{ USB_DEVICE(0x0c45, 0x6007), },
 		{ USB_DEVICE(0x0c45, 0x60ab), },
 		{ }
 	};
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
new file mode 100644
index 0000000..83a39e8
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110d.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera    *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static int tas5110d_init(struct sn9c102_device* cam)
+{
+	int err;
+
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01},
+				       {0x0a, 0x14}, {0x60, 0x17},
+				       {0x06, 0x18}, {0xfb, 0x19});
+
+	err += sn9c102_i2c_write(cam, 0x9a, 0xca);
+
+	return err;
+}
+
+
+static int tas5110d_set_crop(struct sn9c102_device* cam,
+			     const struct v4l2_rect* rect)
+{
+	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+	int err = 0;
+	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
+	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
+
+	err += sn9c102_write_reg(cam, h_start, 0x12);
+	err += sn9c102_write_reg(cam, v_start, 0x13);
+
+	err += sn9c102_write_reg(cam, 0x14, 0x1a);
+	err += sn9c102_write_reg(cam, 0x0a, 0x1b);
+
+	return err;
+}
+
+
+static int tas5110d_set_pix_format(struct sn9c102_device* cam,
+				     const struct v4l2_pix_format* pix)
+{
+	int err = 0;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+		err += sn9c102_write_reg(cam, 0x3b, 0x19);
+	else
+		err += sn9c102_write_reg(cam, 0xfb, 0x19);
+
+	return err;
+}
+
+
+static struct sn9c102_sensor tas5110d = {
+	.name = "TAS5110D",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
+	.sysfs_ops = SN9C102_I2C_WRITE,
+	.frequency = SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x61,
+	.init = &tas5110d_init,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 352,
+			.height = 288,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 352,
+			.height = 288,
+		},
+	},
+	.set_crop = &tas5110d_set_crop,
+	.pix_format = {
+		.width = 352,
+		.height = 288,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &tas5110d_set_pix_format
+};
+
+
+int sn9c102_probe_tas5110d(struct sn9c102_device* cam)
+{
+	const struct usb_device_id tas5110d_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x6007), },
+		{ }
+	};
+
+	if (!sn9c102_match_id(cam, tas5110d_id_table))
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &tas5110d);
+
+	return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
index cb1b318..5040650 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
@@ -22,21 +22,14 @@
 #include "sn9c102_sensor.h"
 
 
-static struct sn9c102_sensor tas5130d1b;
-
-
 static int tas5130d1b_init(struct sn9c102_device* cam)
 {
-	int err = 0;
+	int err;
 
-	err += sn9c102_write_reg(cam, 0x01, 0x01);
-	err += sn9c102_write_reg(cam, 0x20, 0x17);
-	err += sn9c102_write_reg(cam, 0x04, 0x01);
-	err += sn9c102_write_reg(cam, 0x01, 0x10);
-	err += sn9c102_write_reg(cam, 0x00, 0x11);
-	err += sn9c102_write_reg(cam, 0x00, 0x14);
-	err += sn9c102_write_reg(cam, 0x60, 0x17);
-	err += sn9c102_write_reg(cam, 0x07, 0x18);
+	err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17},
+				       {0x04, 0x01}, {0x01, 0x10},
+				       {0x00, 0x11}, {0x00, 0x14},
+				       {0x60, 0x17}, {0x07, 0x18});
 
 	return err;
 }
@@ -99,7 +92,7 @@ static int tas5130d1b_set_pix_format(str
 static struct sn9c102_sensor tas5130d1b = {
 	.name = "TAS5130D1B",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 	.sysfs_ops = SN9C102_I2C_WRITE,
 	.frequency = SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_3WIRES,
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index d1ccc06..4322580 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -45,7 +45,6 @@ #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 
 #include <media/v4l2-common.h>
 #include <media/i2c-addr.h>
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 027c8a0..1a1bef0 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -192,14 +192,52 @@ static struct tda827xa_data tda827xa_ana
 	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
 };
 
+static void tda827xa_lna_gain(struct i2c_client *c, int high)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
+	if (t->config) {
+		if (high)
+			tuner_dbg("setting LNA to high gain\n");
+		else
+			tuner_dbg("setting LNA to low gain\n");
+	}
+	switch (t->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync on */
+		if (t->std & V4L2_STD_MN)
+			arg = 1;
+		else
+			arg = 0;
+		if (t->tuner_callback)
+			t->tuner_callback(c->adapter->algo_data, 1, arg);
+		buf[1] = high ? 0 : 1;
+		if (t->config == 2)
+			buf[1] = high ? 1 : 0;
+		i2c_transfer(c->adapter, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (t->tuner_callback)
+			t->tuner_callback(c->adapter->algo_data, 0, high);
+		break;
+	}
+}
+
 static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
 {
-	unsigned char tuner_reg[14];
-	unsigned char reg2[2];
+	unsigned char tuner_reg[11];
 	u32 N;
 	int i;
 	struct tuner *t = i2c_get_clientdata(c);
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+
+	tda827xa_lna_gain( c, 1);
+	msleep(10);
 
 	if (t->mode == V4L2_TUNER_RADIO)
 		freq = freq / 1000;
@@ -222,48 +260,58 @@ static void tda827xa_tune(struct i2c_cli
 	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
 			tda827xa_analog[i].sbs;
 	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-	tuner_reg[7] = 0x0c;
+	tuner_reg[7] = 0x1c;
 	tuner_reg[8] = 4;
 	tuner_reg[9] = 0x20;
-	tuner_reg[10] = 0xff;
-	tuner_reg[11] = 0xe0;
-	tuner_reg[12] = 0;
-	tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
+	tuner_reg[10] = 0x00;
+	msg.len = 11;
+	i2c_transfer(c->adapter, &msg, 1);
 
-	msg.buf = tuner_reg;
-	msg.len = 14;
+	tuner_reg[0] = 0x90;
+	tuner_reg[1] = 0xff;
+	tuner_reg[2] = 0xe0;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+	msg.len = 5;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msg.buf= reg2;
+	tuner_reg[0] = 0xa0;
+	tuner_reg[1] = 0xc0;
 	msg.len = 2;
-	reg2[0] = 0x60;
-	reg2[1] = 0x3c;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xa0;
-	reg2[1] = 0xc0;
+	tuner_reg[0] = 0x30;
+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msleep(2);
-	reg2[0] = 0x30;
-	reg2[1] = 0x10 + tda827xa_analog[i].scr;
+	msg.flags = I2C_M_RD;
+	i2c_transfer(c->adapter, &msg, 1);
+	msg.flags = 0;
+	tuner_reg[1] >>= 4;
+	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
+	if (tuner_reg[1] < 1)
+		tda827xa_lna_gain( c, 0);
+
+	msleep(100);
+	tuner_reg[0] = 0x60;
+	tuner_reg[1] = 0x3c;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	msleep(550);
-	reg2[0] = 0x50;
-	reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	msleep(163);
+	tuner_reg[0] = 0x50;
+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0x80;
-	reg2[1] = 0x28;
+	tuner_reg[0] = 0x80;
+	tuner_reg[1] = 0x28;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xb0;
-	reg2[1] = 0x01;
+	tuner_reg[0] = 0xb0;
+	tuner_reg[1] = 0x01;
 	i2c_transfer(c->adapter, &msg, 1);
 
-	reg2[0] = 0xc0;
-	reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+	tuner_reg[0] = 0xc0;
+	tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
 	i2c_transfer(c->adapter, &msg, 1);
 }
 
@@ -319,7 +367,9 @@ static int tda8290_tune(struct i2c_clien
 	unsigned char addr_pll_stat = 0x1b;
 	unsigned char adc_sat, agc_stat,
 		      pll_stat;
+	int i;
 
+	tuner_dbg("tda827xa config is 0x%02x\n", t->config);
 	i2c_master_send(c, easy_mode, 2);
 	i2c_master_send(c, agc_out_on, 2);
 	i2c_master_send(c, soft_reset, 2);
@@ -340,17 +390,22 @@ static int tda8290_tune(struct i2c_clien
 		tda827xa_tune(c, ifc, freq);
 	else
 		tda827x_tune(c, ifc, freq);
+	for (i = 0; i < 3; i++) {
+		i2c_master_send(c, &addr_pll_stat, 1);
+		i2c_master_recv(c, &pll_stat, 1);
+		if (pll_stat & 0x80) {
+			i2c_master_send(c, &addr_adc_sat, 1);
+			i2c_master_recv(c, &adc_sat, 1);
+			i2c_master_send(c, &addr_agc_stat, 1);
+			i2c_master_recv(c, &agc_stat, 1);
+			tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+			break;
+		} else {
+			tuner_dbg("tda8290 not locked, no signal?\n");
+			msleep(100);
+		}
+	}
 	/* adjust headroom resp. gain */
-	i2c_master_send(c, &addr_adc_sat, 1);
-	i2c_master_recv(c, &adc_sat, 1);
-	i2c_master_send(c, &addr_agc_stat, 1);
-	i2c_master_recv(c, &agc_stat, 1);
-	i2c_master_send(c, &addr_pll_stat, 1);
-	i2c_master_recv(c, &pll_stat, 1);
-	if (pll_stat & 0x80)
-		tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
-	else
-		tuner_dbg("tda8290 not locked, no signal?\n");
 	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
 		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
 			   agc_stat, adc_sat, pll_stat & 0x80);
@@ -407,7 +462,6 @@ static void set_audio(struct tuner *t)
 	char* mode;
 
 	t->tda827x_lpsel = 0;
-	mode = "xx";
 	if (t->std & V4L2_STD_MN) {
 		t->sgIF = 92;
 		t->tda8290_easy_mode = 0x01;
@@ -437,8 +491,12 @@ static void set_audio(struct tuner *t)
 		t->sgIF = 20;
 		t->tda8290_easy_mode = 0x40;
 		mode = "LC";
+	} else {
+		t->sgIF = 124;
+		t->tda8290_easy_mode = 0x10;
+		mode = "xx";
 	}
-    tuner_dbg("setting tda8290 to system %s\n", mode);
+	tuner_dbg("setting tda8290 to system %s\n", mode);
 }
 
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
@@ -487,11 +545,16 @@ static void standby(struct i2c_client *c
 
 static void tda8290_init_if(struct i2c_client *c)
 {
+	struct tuner *t = i2c_get_clientdata(c);
 	unsigned char set_VS[] = { 0x30, 0x6F };
+	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
+	if ((t->config == 1) || (t->config == 2))
+		i2c_master_send(c, set_GP00_CF, 2);
+	else
+		i2c_master_send(c, set_GP01_CF, 2);
 	i2c_master_send(c, set_VS, 2);
-	i2c_master_send(c, set_GP01_CF, 2);
 }
 
 static void tda8290_init_tuner(struct i2c_client *c)
@@ -576,6 +639,7 @@ int tda8290_init(struct i2c_client *c)
 	t->has_signal = has_signal;
 	t->standby = standby;
 	t->tda827x_lpsel = 0;
+	t->mode = V4L2_TUNER_ANALOG_TV;
 
 	tda8290_init_tuner(c);
 	tda8290_init_if(c);
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 00f0e8b..d110441 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -27,7 +27,6 @@ #include <linux/slab.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
 
 
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 15dbc6b..505591a 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -144,7 +144,8 @@ static void set_freq(struct i2c_client *
 }
 
 static void set_type(struct i2c_client *c, unsigned int type,
-		     unsigned int new_mode_mask)
+		     unsigned int new_mode_mask, unsigned int new_config,
+		     int (*tuner_callback) (void *dev, int command,int arg))
 {
 	struct tuner *t = i2c_get_clientdata(c);
 	unsigned char buffer[4];
@@ -159,15 +160,20 @@ static void set_type(struct i2c_client *
 		return;
 	}
 
+	t->type = type;
+	t->config = new_config;
+	if (tuner_callback != NULL) {
+		tuner_dbg("defining GPIO callback\n");
+		t->tuner_callback = tuner_callback;
+	}
+
 	/* This code detects calls by card attach_inform */
 	if (NULL == t->i2c.dev.driver) {
 		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
 
-		t->type=type;
 		return;
 	}
 
-	t->type = type;
 	switch (t->type) {
 	case TUNER_MT2032:
 		microtune_init(c);
@@ -234,10 +240,11 @@ static void set_addr(struct i2c_client *
 
 	tuner_dbg("set addr for type %i\n", t->type);
 
-	if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
-		(t->mode_mask & tun_setup->mode_mask)) ||
-		tun_setup->addr == c->addr)) {
-			set_type(c, tun_setup->type, tun_setup->mode_mask);
+	if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
+		(t->mode_mask & tun_setup->mode_mask))) ||
+		(tun_setup->addr == c->addr)) {
+			set_type(c, tun_setup->type, tun_setup->mode_mask,
+				 tun_setup->config, tun_setup->tuner_callback);
 	}
 }
 
@@ -496,7 +503,7 @@ static int tuner_attach(struct i2c_adapt
 register_client:
 	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
 	i2c_attach_client (&t->i2c);
-	set_type (&t->i2c,t->type, t->mode_mask);
+	set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
 	return 0;
 }
 
@@ -576,10 +583,11 @@ static int tuner_command(struct i2c_clie
 	switch (cmd) {
 	/* --- configuration --- */
 	case TUNER_SET_TYPE_ADDR:
-		tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n",
+		tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
 				((struct tuner_setup *)arg)->type,
 				((struct tuner_setup *)arg)->addr,
-				((struct tuner_setup *)arg)->mode_mask);
+				((struct tuner_setup *)arg)->mode_mask,
+				((struct tuner_setup *)arg)->config);
 
 		set_addr(client, (struct tuner_setup *)arg);
 		break;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index d506dfa..c9bf9db 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -25,14 +25,13 @@ #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/videodev.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
 #include <media/tvaudio.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 #include <media/i2c-addr.h>
 
@@ -1775,6 +1774,9 @@ static int chip_command(struct i2c_clien
 			/* the thread will call checkmode() later */
 		}
 		break;
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0);
 	}
 	return 0;
 }
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 4e7c1fa..a1136da 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -163,7 +163,7 @@ hauppauge_tuner[] =
 	/* 60-69 */
 	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
 	{ TUNER_ABSENT,        "LG M001D MK3"},
-	{ TUNER_ABSENT,        "LG S701D MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
 	{ TUNER_ABSENT,        "LG M701D MK3"},
 	{ TUNER_ABSENT,        "Temic 4146FM5"},
 	{ TUNER_ABSENT,        "Temic 4136FY5"},
@@ -229,6 +229,36 @@ hauppauge_tuner[] =
 	/* 120-129 */
 	{ TUNER_ABSENT,        "Xceive XC3028"},
 	{ TUNER_ABSENT,        "Philips FQ1216LME MK5"},
+	{ TUNER_ABSENT,        "Philips FQD1216LME"},
+	{ TUNER_ABSENT,        "Conexant CX24118A"},
+	{ TUNER_ABSENT,        "TCL DMF11WIP"},
+	{ TUNER_ABSENT,        "TCL MFNM05_4H_E"},
+	{ TUNER_ABSENT,        "TCL MNM05_4H_E"},
+	{ TUNER_ABSENT,        "TCL MPE05_2H_E"},
+	{ TUNER_ABSENT,        "TCL MQNM05_4_U"},
+	{ TUNER_ABSENT,        "TCL M2523_5NH_E"},
+	/* 130-139 */
+	{ TUNER_ABSENT,        "TCL M2523_3DBH_E"},
+	{ TUNER_ABSENT,        "TCL M2523_3DIH_E"},
+	{ TUNER_ABSENT,        "TCL MFPE05_2_U"},
+	{ TUNER_ABSENT,        "Philips FMD1216MEX"},
+	{ TUNER_ABSENT,        "Philips FRH2036B"},
+	{ TUNER_ABSENT,        "Panasonic ENGF75_01GF"},
+	{ TUNER_ABSENT,        "MaxLinear MXL5005"},
+	{ TUNER_ABSENT,        "MaxLinear MXL5003"},
+	{ TUNER_ABSENT,        "Xceive XC2028"},
+	{ TUNER_ABSENT,        "Microtune MT2131"},
+	/* 140-149 */
+	{ TUNER_ABSENT,        "Philips 8275A_8295"},
+	{ TUNER_ABSENT,        "TCL MF02GIP_5N_E"},
+	{ TUNER_ABSENT,        "TCL MF02GIP_3DB_E"},
+	{ TUNER_ABSENT,        "TCL MF02GIP_3DI_E"},
+	{ TUNER_ABSENT,        "Microtune MT2266"},
+	{ TUNER_ABSENT,        "TCL MF10WPP_4N_E"},
+	{ TUNER_ABSENT,        "LG TAPQ_H702F"},
+	{ TUNER_ABSENT,        "TCL M09WPP_4N_E"},
+	{ TUNER_ABSENT,        "MaxLinear MXL5005_v2"},
+	{ TUNER_ABSENT,        "Philips 18271_8295"},
 };
 
 static struct HAUPPAUGE_AUDIOIC
@@ -280,11 +310,16 @@ audioIC[] =
 	{AUDIO_CHIP_INTERNAL, "CX883"},
 	{AUDIO_CHIP_INTERNAL, "CX882"},
 	{AUDIO_CHIP_INTERNAL, "CX25840"},
-	/* 35-38 */
+	/* 35-39 */
 	{AUDIO_CHIP_INTERNAL, "CX25841"},
 	{AUDIO_CHIP_INTERNAL, "CX25842"},
 	{AUDIO_CHIP_INTERNAL, "CX25843"},
 	{AUDIO_CHIP_INTERNAL, "CX23418"},
+	{AUDIO_CHIP_INTERNAL, "CX23885"},
+	/* 40-42 */
+	{AUDIO_CHIP_INTERNAL, "CX23888"},
+	{AUDIO_CHIP_INTERNAL, "SAA7131"},
+	{AUDIO_CHIP_INTERNAL, "CX23887"},
 };
 
 /* This list is supplied by Hauppauge. Thanks! */
@@ -301,8 +336,10 @@ static const char *decoderIC[] = {
 	"CX880", "CX881", "CX883", "SAA7111", "SAA7113",
 	/* 25-29 */
 	"CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
-	/* 30-31 */
-	"CX25843", "CX23418",
+	/* 30-34 */
+	"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
+	/* 35-37 */
+	"SAA7131", "CX25837", "CX23887"
 };
 
 static int hasRadioTuner(int tunerType)
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 28d1133..0b2a961 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -27,6 +27,7 @@ #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/upd64031a.h>
 
 // --------------------- read registers functions define -----------------------
@@ -179,6 +180,9 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 	}
 #endif
 
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0);
+
 	default:
 		break;
 	}
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index fe38224..401bd21 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -26,6 +26,7 @@ #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
@@ -155,6 +156,10 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 		break;
 	}
 #endif
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0);
+
 	default:
 		break;
 	}
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index d34d8c8..37ce36b 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -20,7 +20,6 @@ #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
@@ -628,24 +627,21 @@ #endif
 /* ******************************************************************** */
 
 /* XXX: this piece of crap really wants some error handling.. */
-static void usbvideo_ClientIncModCount(struct uvd *uvd)
+static int usbvideo_ClientIncModCount(struct uvd *uvd)
 {
 	if (uvd == NULL) {
 		err("%s: uvd == NULL", __FUNCTION__);
-		return;
+		return -EINVAL;
 	}
 	if (uvd->handle == NULL) {
 		err("%s: uvd->handle == NULL", __FUNCTION__);
-		return;
-	}
-	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
-		return;
+		return -EINVAL;
 	}
 	if (!try_module_get(uvd->handle->md_module)) {
 		err("%s: try_module_get() == 0", __FUNCTION__);
-		return;
+		return -ENODEV;
 	}
+	return 0;
 }
 
 static void usbvideo_ClientDecModCount(struct uvd *uvd)
@@ -712,8 +708,6 @@ int usbvideo_register(
 	cams->num_cameras = num_cams;
 	cams->cam = (struct uvd *) &cams[1];
 	cams->md_module = md;
-	if (cams->md_module == NULL)
-		warn("%s: module == NULL!", __FUNCTION__);
 	mutex_init(&cams->lock);	/* to 1 == available */
 
 	for (i = 0; i < num_cams; i++) {
@@ -1119,7 +1113,8 @@ static int usbvideo_v4l_open(struct inod
 	if (uvd->debug > 1)
 		info("%s($%p)", __FUNCTION__, dev);
 
-	usbvideo_ClientIncModCount(uvd);
+	if (0 < usbvideo_ClientIncModCount(uvd))
+		return -ENODEV;
 	mutex_lock(&uvd->lock);
 
 	if (uvd->user) {
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index a40e583..51ab265 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -1,6 +1,6 @@
 /*
- * USBVISION.H
- *  usbvision header file
+ *  usbvision-cards.c
+ *  usbvision cards definition file
  *
  * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
  *
@@ -24,133 +24,1063 @@
 
 
 #include <linux/list.h>
-#include <linux/i2c.h>
 #include <media/v4l2-dev.h>
 #include <media/tuner.h>
 #include "usbvision.h"
+#include "usbvision-cards.h"
 
 /* Supported Devices: A table for usbvision.c*/
 struct usbvision_device_data_st  usbvision_device_data[] = {
-	{0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"},
-	{0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "Xanboo"},
-	{0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Belkin USBView II"},
-	{0x0571, 0x0002,  0, CODEC_SAA7111, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1, -1, -1,  7, "echoFX InterView Lite"},
-	{0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"},
-	{0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC,  0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "D-Link V100"},
-	{0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1, -1, -1, -1, "X10 USB Camera"},
-	{0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1, -1,  3,  7, "Osprey 50"},
-	{0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC,  0, 0, 1, 0, 0,			       -1, -1,  0,  3,  7, "Hauppauge USB-Live Model 600"},
-	{0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   2, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"},
-	{0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"},
-	{0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"},
-	{0x0573, 0x4450,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "PixelView PlayTv-USB PRO (PAL) FM"},
-	{0x0573, 0x4550,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "ZTV ZT-721 2.4GHz USB A/V Receiver"},
-	{0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"},
-	{0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
-	{0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"},
-	{0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "},
-	{0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"},
-	{0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
-	{0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"},
-	{0x0573, 0x4d2a,  0, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"},
-	{0x0573, 0x4d2b,  0, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"},
-	{0x0573, 0x4d2c,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1,  0,  3,  7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"},
-	{0x0573, 0x4d20,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"},
-	{0x0573, 0x4d21,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL)"},
-	{0x0573, 0x4d22,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB II (PAL) MODEL 566"},
-	{0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) 4D23"},
-	{0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"},
-	{0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1,  0,  3,  7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"},
-	{0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40204 Rev B281"},
-	{0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40204 Rev B283"},
-	{0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB Model 40205 Rev B298"},
-	{0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1,  0,  3,  7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"},
-	{0x0573, 0x4d31,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 568"},
-	{0x0573, 0x4d32,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 573"},
-	{0x0573, 0x4d35,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_MICROTUNE_4049FM5,    -1, -1,  0,  3,  7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"},
-	{0x0573, 0x4d37,  0, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1,  0,  3,  7, "Hauppauge WinTV USB device Model 40219 Rev E189"},
-	{0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1,  5,  5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"},
-	{0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Digital Video Creator I"},
-	{0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC,  0, 0, 1, 0, 0,   		       -1, -1, 82, 20,  7, "Global Village GV-007 (NTSC)"},
-	{0x07d0, 0x0003,  0, CODEC_SAA7113, 2, V4L2_STD_NTSC,  0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"},
-	{0x07d0, 0x0004,  0, CODEC_SAA7113, 2, V4L2_STD_PAL,   0, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"},
-	{0x07d0, 0x0005,  0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0,			       -1, -1,  0,  3,  7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"},
-	{0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I,  -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"},
-	{0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM,        -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"},
-	{0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_PHILIPS_PAL,          -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"},
-	{0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL,   1, 0, 1, 1, TUNER_PHILIPS_PAL,          -1, -1, -1, -1, -1, "Miro PCTV USB"},
-	{0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"},
-	{0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (PAL) FM"},
-	{0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC,   -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (NTSC) FM"},
-	{0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle Studio PCTV USB (PAL) FM"},
-	{0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC,  1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Pinnacle Studio Linx Video input cable (NTSC)"},
-	{0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL,   1, 0, 1, 0, 0,                          -1, -1,  0,  3,  7, "Pinnacle Studio Linx Video input cable (PAL)"},
-	{0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL,   1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL,    -1, -1,  0,  3,  7, "Pinnacle PCTV Bungee USB (PAL) FM"},
-	{0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC,  1, 0, 1, 1, TUNER_PHILIPS_NTSC_M,       -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"},
-	{}  /* Terminating entry */
+	[XANBOO] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 4,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Xanboo",
+	},
+	[BELKIN_VIDEOBUS_II] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Belkin USB VideoBus II Adapter",
+	},
+	[BELKIN_VIDEOBUS] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Belkin Components USB VideoBus",
+	},
+	[BELKIN_USB_VIDEOBUS_II] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Belkin USB VideoBus II",
+	},
+	[ECHOFX_INTERVIEW_LITE] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "echoFX InterView Lite",
+	},
+	[USBGEAR_USBG_V1] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "USBGear USBG-V1 resp. HAMA USB",
+	},
+	[D_LINK_V100] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 4,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "D-Link V100",
+	},
+	[X10_USB_CAMERA] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "X10 USB Camera",
+	},
+	[HPG_WINTV_LIVE_PAL_BG] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = -1,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Live (PAL B/G)",
+	},
+	[HPG_WINTV_LIVE_PRO_NTSC_MN] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Live Pro (NTSC M/N)",
+	},
+	[ZORAN_PMD_NOGATECH] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 2,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan",
+	},
+	[NOGATECH_USB_TV_NTSC_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = 20,
+		.ModelString   = "Nogatech USB-TV (NTSC) FM",
+	},
+	[PNY_USB_TV_NTSC_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = 20,
+		.ModelString   = "PNY USB-TV (NTSC) FM",
+	},
+	[PV_PLAYTV_USB_PRO_PAL_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "PixelView PlayTv-USB PRO (PAL) FM",
+	},
+	[ZT_721] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "ZTV ZT-721 2.4GHz USB A/V Receiver",
+	},
+	[HPG_WINTV_NTSC_MN] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = 20,
+		.ModelString   = "Hauppauge WinTV USB (NTSC M/N)",
+	},
+	[HPG_WINTV_PAL_BG] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL B/G)",
+	},
+	[HPG_WINTV_PAL_I] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL I)",
+	},
+	[HPG_WINTV_PAL_SECAM_L] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_SECAM,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL/SECAM L)",
+	},
+	[HPG_WINTV_PAL_D_K] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL D/K)",
+	},
+	[HPG_WINTV_NTSC_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (NTSC FM)",
+	},
+	[HPG_WINTV_PAL_BG_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL B/G FM)",
+	},
+	[HPG_WINTV_PAL_I_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL I FM)",
+	},
+	[HPG_WINTV_PAL_D_K_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTV USB (PAL D/K FM)",
+	},
+	[HPG_WINTV_PRO_NTSC_MN] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_MICROTUNE_4049FM5,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (NTSC M/N)",
+	},
+	[HPG_WINTV_PRO_NTSC_MN_V2] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_MICROTUNE_4049FM5,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (NTSC M/N) V2",
+	},
+	[HPG_WINTV_PRO_PAL] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_FM1216ME_MK3,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)",
+	},
+	[HPG_WINTV_PRO_NTSC_MN_V3] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (NTSC M/N) V3",
+	},
+	[HPG_WINTV_PRO_PAL_BG] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL B/G)",
+	},
+	[HPG_WINTV_PRO_PAL_I] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL I)",
+	},
+	[HPG_WINTV_PRO_PAL_SECAM_L] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_SECAM,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL/SECAM L)",
+	},
+	[HPG_WINTV_PRO_PAL_D_K] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL D/K)",
+	},
+	[HPG_WINTV_PRO_PAL_SECAM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_SECAM,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)",
+	},
+	[HPG_WINTV_PRO_PAL_SECAM_V2] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_SECAM,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2",
+	},
+	[HPG_WINTV_PRO_PAL_BG_V2] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_ALPS_TSBE1_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL B/G) V2",
+	},
+	[HPG_WINTV_PRO_PAL_BG_D_K] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_ALPS_TSBE1_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL B/G,D/K)",
+	},
+	[HPG_WINTV_PRO_PAL_I_D_K] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL I,D/K)",
+	},
+	[HPG_WINTV_PRO_NTSC_MN_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (NTSC M/N FM)",
+	},
+	[HPG_WINTV_PRO_PAL_BG_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL B/G FM)",
+	},
+	[HPG_WINTV_PRO_PAL_I_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL I FM)",
+	},
+	[HPG_WINTV_PRO_PAL_D_K_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL D/K FM)",
+	},
+	[HPG_WINTV_PRO_TEMIC_PAL_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_MICROTUNE_4049FM5,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)",
+	},
+	[HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_MICROTUNE_4049FM5,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)",
+	},
+	[HPG_WINTV_PRO_PAL_FM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_FM1216ME_MK3,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)",
+	},
+	[HPG_WINTV_PRO_NTSC_MN_FM_V2] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2",
+	},
+	[CAMTEL_TVB330] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = 5,
+		.Y_Offset      = 5,
+		.ModelString   = "Camtel Technology USB TV Genie Pro FM Model TVB330",
+	},
+	[DIGITAL_VIDEO_CREATOR_I] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Digital Video Creator I",
+	},
+	[GLOBAL_VILLAGE_GV_007_NTSC] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 82,
+		.Y_Offset      = 20,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Global Village GV-007 (NTSC)",
+	},
+	[DAZZLE_DVC_50_REV_1_NTSC] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)",
+	},
+	[DAZZLE_DVC_80_REV_1_PAL] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)",
+	},
+	[DAZZLE_DVC_90_REV_1_SECAM] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 0,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)",
+	},
+	[ESKAPE_LABS_MYTV2GO] = {
+		.Interface     = 0,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_FM1216ME_MK3,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Eskape Labs MyTV2Go",
+	},
+	[PINNA_PCTV_USB_PAL] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 0,
+		.Tuner         = 1,
+		.TunerType     = TUNER_TEMIC_4066FY5_PAL_I,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Pinnacle Studio PCTV USB (PAL)",
+	},
+	[PINNA_PCTV_USB_SECAM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_SECAM,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_SECAM,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Pinnacle Studio PCTV USB (SECAM)",
+	},
+	[PINNA_PCTV_USB_PAL_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = 128,
+		.Y_Offset      = 23,
+		.ModelString   = "Pinnacle Studio PCTV USB (PAL) FM",
+	},
+	[MIRO_PCTV_USB] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_PAL,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Miro PCTV USB",
+	},
+	[PINNA_PCTV_USB_NTSC_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM",
+	},
+	[PINNA_PCTV_USB_PAL_FM_V2] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_TEMIC_4009FR5_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle Studio PCTV USB (PAL) FM V2",
+	},
+	[PINNA_PCTV_USB_NTSC_FM_V2] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_TEMIC_4039FR5_NTSC,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM V2",
+	},
+	[PINNA_PCTV_USB_PAL_FM_V3] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_TEMIC_4009FR5_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle Studio PCTV USB (PAL) FM V3",
+	},
+	[PINNA_LINX_VD_IN_CAB_NTSC] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle Studio Linx Video input cable (NTSC)",
+	},
+	[PINNA_LINX_VD_IN_CAB_PAL] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 2,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 0,
+		.TunerType     = 0,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle Studio Linx Video input cable (PAL)",
+	},
+	[PINNA_PCTV_BUNGEE_PAL_FM] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7113,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_PAL,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_TEMIC_4009FR5_PAL,
+		.X_Offset      = 0,
+		.Y_Offset      = 3,
+		.Dvi_yuv_override = 1,
+		.Dvi_yuv       = 7,
+		.ModelString   = "Pinnacle PCTV Bungee USB (PAL) FM",
+	},
+	[HPG_WINTV] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 0,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Hauppauge WinTv-USB",
+	},
 };
+const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data);
 
 /* Supported Devices */
 
 struct usb_device_id usbvision_table [] = {
-	{ USB_DEVICE(0xFFF0, 0xFFF0) },  /* Custom Dummy USBVision Device */
-	{ USB_DEVICE(0x0A6F, 0x0400) },  /* Xanboo */
-	{ USB_DEVICE(0x050d, 0x0208) },  /* Belkin USBView II */
-	{ USB_DEVICE(0x0571, 0x0002) },  /* echoFX InterView Lite */
-	{ USB_DEVICE(0x0573, 0x0003) },  /* USBGear USBG-V1 */
-	{ USB_DEVICE(0x0573, 0x0400) },  /* D-Link V100 */
-	{ USB_DEVICE(0x0573, 0x2000) },  /* X10 USB Camera */
-	{ USB_DEVICE(0x0573, 0x2d00) },  /* Osprey 50 */
-	{ USB_DEVICE(0x0573, 0x2d01) },  /* Hauppauge USB-Live Model 600 */
-	{ USB_DEVICE(0x0573, 0x2101) },  /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */
-	{ USB_DEVICE(0x0573, 0x4100) },  /* Nogatech USB-TV FM (NTSC) */
-	{ USB_DEVICE(0x0573, 0x4110) },  /* PNY USB-TV (NTSC) FM */
-	{ USB_DEVICE(0x0573, 0x4450) },  /* PixelView PlayTv-USB PRO (PAL) FM */
-	{ USB_DEVICE(0x0573, 0x4550) },  /* ZTV ZT-721 2.4GHz USB A/V Receiver */
-	{ USB_DEVICE(0x0573, 0x4d00) },  /* Hauppauge WinTv-USB USA */
-	{ USB_DEVICE(0x0573, 0x4d01) },  /* Hauppauge WinTv-USB */
-	{ USB_DEVICE(0x0573, 0x4d02) },  /* Hauppauge WinTv-USB UK */
-	{ USB_DEVICE(0x0573, 0x4d03) },  /* Hauppauge WinTv-USB France */
-	{ USB_DEVICE(0x0573, 0x4d10) },  /* Hauppauge WinTv-USB with FM USA radio */
-	{ USB_DEVICE(0x0573, 0x4d11) },  /* Hauppauge WinTv-USB (PAL) with FM radio */
-	{ USB_DEVICE(0x0573, 0x4d12) },  /* Hauppauge WinTv-USB UK with FM Radio */
-	{ USB_DEVICE(0x0573, 0x4d2a) },  /* Hauppague WinTv USB Model 602 40201 Rev B285 */
-	{ USB_DEVICE(0x0573, 0x4d2b) },  /* Hauppague WinTv USB Model 602 40201 Rev B282 */
-	{ USB_DEVICE(0x0573, 0x4d2c) },  /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/
-	{ USB_DEVICE(0x0573, 0x4d20) },  /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */
-	{ USB_DEVICE(0x0573, 0x4d21) },  /* Hauppauge WinTv-USB II (PAL) with FM radio*/
-	{ USB_DEVICE(0x0573, 0x4d22) },  /* Hauppauge WinTv-USB II (PAL) Model 566 */
-	{ USB_DEVICE(0x0573, 0x4d23) },  /* Hauppauge WinTv-USB France 4D23*/
-	{ USB_DEVICE(0x0573, 0x4d25) },  /* Hauppauge WinTv-USB Model 40209 rev B234 */
-	{ USB_DEVICE(0x0573, 0x4d26) },  /* Hauppauge WinTv-USB Model 40209 Rev B243 */
-	{ USB_DEVICE(0x0573, 0x4d27) },  /* Hauppauge WinTv-USB Model 40204 Rev B281 */
-	{ USB_DEVICE(0x0573, 0x4d28) },  /* Hauppauge WinTv-USB Model 40204 Rev B283 */
-	{ USB_DEVICE(0x0573, 0x4d29) },  /* Hauppauge WinTv-USB Model 40205 Rev B298 */
-	{ USB_DEVICE(0x0573, 0x4d30) },  /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */
-	{ USB_DEVICE(0x0573, 0x4d31) },  /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */
-	{ USB_DEVICE(0x0573, 0x4d32) },  /* Hauppauge WinTv-USB III (PAL) FM Model 573 */
-	{ USB_DEVICE(0x0573, 0x4d35) },  /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */
-	{ USB_DEVICE(0x0573, 0x4d37) },  /* Hauppauge WinTv-USB Model 40219 Rev E189 */
-	{ USB_DEVICE(0x0768, 0x0006) },  /* Camtel Technology USB TV Genie Pro FM Model TVB330 */
-	{ USB_DEVICE(0x07d0, 0x0001) },  /* Digital Video Creator I */
-	{ USB_DEVICE(0x07d0, 0x0002) },  /* Global Village GV-007 (NTSC) */
-	{ USB_DEVICE(0x07d0, 0x0003) },  /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */
-	{ USB_DEVICE(0x07d0, 0x0004) },  /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */
-	{ USB_DEVICE(0x07d0, 0x0005) },  /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */
-	{ USB_DEVICE(0x2304, 0x010d) },  /* Pinnacle Studio PCTV USB (PAL) */
-	{ USB_DEVICE(0x2304, 0x0109) },  /* Pinnacle Studio PCTV USB (SECAM) */
-	{ USB_DEVICE(0x2304, 0x0110) },  /* Pinnacle Studio PCTV USB (PAL) */
-	{ USB_DEVICE(0x2304, 0x0111) },  /* Miro PCTV USB */
-	{ USB_DEVICE(0x2304, 0x0112) },  /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
-	{ USB_DEVICE(0x2304, 0x0210) },  /* Pinnacle Studio PCTV USB (PAL) with FM radio */
-	{ USB_DEVICE(0x2304, 0x0212) },  /* Pinnacle Studio PCTV USB (NTSC) with FM radio */
-	{ USB_DEVICE(0x2304, 0x0214) },  /* Pinnacle Studio PCTV USB (PAL) with FM radio */
-	{ USB_DEVICE(0x2304, 0x0300) },  /* Pinnacle Studio Linx Video input cable (NTSC) */
-	{ USB_DEVICE(0x2304, 0x0301) },  /* Pinnacle Studio Linx Video input cable (PAL) */
-	{ USB_DEVICE(0x2304, 0x0419) },  /* Pinnacle PCTV Bungee USB (PAL) FM */
-	{ USB_DEVICE(0x2400, 0x4200) },  /* Hauppauge WinTv-USB2 Model 42012 */
-
-	{ }  /* Terminating entry */
+	{ USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO },
+	{ USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II },
+	{ USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS },
+	{ USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II },
+	{ USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE },
+	{ USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 },
+	{ USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 },
+	{ USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA },
+	{ USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG },
+	{ USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN },
+	{ USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH },
+	{ USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM },
+	{ USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM },
+	{ USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM },
+	{ USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 },
+	{ USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN },
+	{ USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG },
+	{ USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I },
+	{ USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L },
+	{ USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K },
+	{ USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM },
+	{ USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM },
+	{ USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM },
+	{ USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM },
+	{ USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
+	{ USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
+	{ USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
+	{ USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 },
+	{ USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
+	{ USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
+	{ USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
+	{ USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K },
+	{ USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM },
+	{ USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 },
+	{ USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 },
+	{ USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K },
+	{ USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K },
+	{ USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM },
+	{ USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM },
+	{ USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM },
+	{ USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM },
+	{ USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM },
+	{ USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM },
+	{ USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM },
+	{ USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 },
+	{ USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 },
+	{ USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I },
+	{ USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC },
+	{ USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC },
+	{ USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL },
+	{ USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM },
+	{ USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO },
+	{ USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL },
+	{ USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM },
+	{ USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
+	{ USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
+	{ USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
+	{ USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
+	{ USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
+	{ USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
+	{ USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC },
+	{ USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL },
+	{ USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM },
+	{ USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV },
 };
 
 MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
new file mode 100644
index 0000000..512c5ce
--- /dev/null
+++ b/drivers/media/video/usbvision/usbvision-cards.h
@@ -0,0 +1,66 @@
+#define XANBOO                                   0
+#define BELKIN_VIDEOBUS_II                       1
+#define BELKIN_VIDEOBUS                          2
+#define BELKIN_USB_VIDEOBUS_II                   3
+#define ECHOFX_INTERVIEW_LITE                    4
+#define USBGEAR_USBG_V1                          5
+#define D_LINK_V100                              6
+#define X10_USB_CAMERA                           7
+#define HPG_WINTV_LIVE_PAL_BG                    8
+#define HPG_WINTV_LIVE_PRO_NTSC_MN               9
+#define ZORAN_PMD_NOGATECH                       10
+#define NOGATECH_USB_TV_NTSC_FM                  11
+#define PNY_USB_TV_NTSC_FM                       12
+#define PV_PLAYTV_USB_PRO_PAL_FM                 13
+#define ZT_721                                   14
+#define HPG_WINTV_NTSC_MN                        15
+#define HPG_WINTV_PAL_BG                         16
+#define HPG_WINTV_PAL_I                          17
+#define HPG_WINTV_PAL_SECAM_L                    18
+#define HPG_WINTV_PAL_D_K                        19
+#define HPG_WINTV_NTSC_FM                        20
+#define HPG_WINTV_PAL_BG_FM                      21
+#define HPG_WINTV_PAL_I_FM                       22
+#define HPG_WINTV_PAL_D_K_FM                     23
+#define HPG_WINTV_PRO_NTSC_MN                    24
+#define HPG_WINTV_PRO_NTSC_MN_V2                 25
+#define HPG_WINTV_PRO_PAL                        26
+#define HPG_WINTV_PRO_NTSC_MN_V3                 27
+#define HPG_WINTV_PRO_PAL_BG                     28
+#define HPG_WINTV_PRO_PAL_I                      29
+#define HPG_WINTV_PRO_PAL_SECAM_L                30
+#define HPG_WINTV_PRO_PAL_D_K                    31
+#define HPG_WINTV_PRO_PAL_SECAM                  32
+#define HPG_WINTV_PRO_PAL_SECAM_V2               33
+#define HPG_WINTV_PRO_PAL_BG_V2                  34
+#define HPG_WINTV_PRO_PAL_BG_D_K                 35
+#define HPG_WINTV_PRO_PAL_I_D_K                  36
+#define HPG_WINTV_PRO_NTSC_MN_FM                 37
+#define HPG_WINTV_PRO_PAL_BG_FM                  38
+#define HPG_WINTV_PRO_PAL_I_FM                   39
+#define HPG_WINTV_PRO_PAL_D_K_FM                 40
+#define HPG_WINTV_PRO_TEMIC_PAL_FM               41
+#define HPG_WINTV_PRO_TEMIC_PAL_BG_FM            42
+#define HPG_WINTV_PRO_PAL_FM                     43
+#define HPG_WINTV_PRO_NTSC_MN_FM_V2              44
+#define CAMTEL_TVB330                            45
+#define DIGITAL_VIDEO_CREATOR_I                  46
+#define GLOBAL_VILLAGE_GV_007_NTSC               47
+#define DAZZLE_DVC_50_REV_1_NTSC                 48
+#define DAZZLE_DVC_80_REV_1_PAL                  49
+#define DAZZLE_DVC_90_REV_1_SECAM                50
+#define ESKAPE_LABS_MYTV2GO                      51
+#define PINNA_PCTV_USB_PAL                       52
+#define PINNA_PCTV_USB_SECAM                     53
+#define PINNA_PCTV_USB_PAL_FM                    54
+#define MIRO_PCTV_USB                            55
+#define PINNA_PCTV_USB_NTSC_FM                   56
+#define PINNA_PCTV_USB_PAL_FM_V2                 57
+#define PINNA_PCTV_USB_NTSC_FM_V2                58
+#define PINNA_PCTV_USB_PAL_FM_V3                 59
+#define PINNA_LINX_VD_IN_CAB_NTSC                60
+#define PINNA_LINX_VD_IN_CAB_PAL                 61
+#define PINNA_PCTV_BUNGEE_PAL_FM                 62
+#define HPG_WINTV                                63
+
+extern const int usbvision_device_data_size;
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index f2154dc..9118a62 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -30,7 +30,6 @@ #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
 #include <linux/videodev.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
@@ -2040,8 +2039,8 @@ int usbvision_set_input(struct usb_usbvi
 		return 0;
 
 	/* Set input format expected from decoder*/
-	if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) {
-		value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff;
+	if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) {
+		value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1;
 	} else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
 		/* SAA7113 uses 8 bit output */
 		value[0] = USBVISION_8_422_SYNC;
@@ -2112,8 +2111,8 @@ int usbvision_set_input(struct usb_usbvi
 
 	dvi_yuv_value = 0x00;	/* U comes after V, Ya comes after U/V, Yb comes after Yb */
 
-	if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){
-		dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff;
+	if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){
+		dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv;
 	}
 	else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
 	/* This changes as the fine sync control changes. Further investigation necessary */
@@ -2238,7 +2237,7 @@ static void call_usbvision_power_off(str
 	PDEBUG(DBG_FUNC, "");
 	down_interruptible(&usbvision->lock);
 	if(usbvision->user == 0) {
-		usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+		usbvision_i2c_unregister(usbvision);
 
 		usbvision_power_off(usbvision);
 		usbvision->initialized = 0;
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 609e1fd..025be55 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -1,8 +1,8 @@
 /*
- * I2C_ALGO_USB.C
+ * usbvision_i2c.c
  *  i2c algorithm for USB-I2C Bridges
  *
- * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de>
+ * Copyright (c) 1999-2007 Joerg Heckenbach <joerg@heckenbach-aw.de>
  *                         Dwaine Garden <dwainegarden@rogers.com>
  *
  * This module is part of usbvision driver project.
@@ -39,7 +39,6 @@ #include <linux/i2c.h>
 #include "usbvision.h"
 
 #define DBG_I2C		1<<0
-#define DBG_ALGO	1<<1
 
 static int i2c_debug = 0;
 
@@ -49,22 +48,22 @@ MODULE_PARM_DESC(i2c_debug, "enable debu
 #define PDEBUG(level, fmt, args...) \
 		if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
 
-static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
 			    short len);
-static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
 			   short len);
 
 static inline int try_write_address(struct i2c_adapter *i2c_adap,
 				    unsigned char addr, int retries)
 {
-	void *data;
+	struct usb_usbvision *usbvision;
 	int i, ret = -1;
 	char buf[4];
 
-	data = i2c_get_adapdata(i2c_adap);
+	usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap);
 	buf[0] = 0x00;
 	for (i = 0; i <= retries; i++) {
-		ret = (usbvision_i2c_write(data, addr, buf, 1));
+		ret = (usbvision_i2c_write(usbvision, addr, buf, 1));
 		if (ret == 1)
 			break;	/* success! */
 		udelay(5);
@@ -73,8 +72,8 @@ static inline int try_write_address(stru
 		udelay(10);
 	}
 	if (i) {
-		PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
-		PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+		PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
+		PDEBUG(DBG_I2C,"Maybe there's no device at this address");
 	}
 	return ret;
 }
@@ -82,13 +81,13 @@ static inline int try_write_address(stru
 static inline int try_read_address(struct i2c_adapter *i2c_adap,
 				   unsigned char addr, int retries)
 {
-	void *data;
+	struct usb_usbvision *usbvision;
 	int i, ret = -1;
 	char buf[4];
 
-	data = i2c_get_adapdata(i2c_adap);
+	usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap);
 	for (i = 0; i <= retries; i++) {
-		ret = (usbvision_i2c_read(data, addr, buf, 1));
+		ret = (usbvision_i2c_read(usbvision, addr, buf, 1));
 		if (ret == 1)
 			break;	/* success! */
 		udelay(5);
@@ -97,8 +96,8 @@ static inline int try_read_address(struc
 		udelay(10);
 	}
 	if (i) {
-		PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr);
-		PDEBUG(DBG_ALGO,"Maybe there's no device at this address");
+		PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
+		PDEBUG(DBG_I2C,"Maybe there's no device at this address");
 	}
 	return ret;
 }
@@ -152,32 +151,32 @@ static inline int usb_find_address(struc
 }
 
 static int
-usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_msg *pmsg;
-	void *data;
+	struct usb_usbvision *usbvision;
 	int i, ret;
 	unsigned char addr;
 
-	data = i2c_get_adapdata(i2c_adap);
+	usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap);
 
 	for (i = 0; i < num; i++) {
 		pmsg = &msgs[i];
 		ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr);
 		if (ret != 0) {
-			PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i);
+			PDEBUG(DBG_I2C,"got NAK from device, message #%d", i);
 			return (ret < 0) ? ret : -EREMOTEIO;
 		}
 
 		if (pmsg->flags & I2C_M_RD) {
 			/* read bytes into buffer */
-			ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len));
+			ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len));
 			if (ret < pmsg->len) {
 				return (ret < 0) ? ret : -EREMOTEIO;
 			}
 		} else {
 			/* write bytes from buffer */
-			ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len));
+			ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len));
 			if (ret < pmsg->len) {
 				return (ret < 0) ? ret : -EREMOTEIO;
 			}
@@ -191,7 +190,7 @@ static int algo_control(struct i2c_adapt
 	return 0;
 }
 
-static u32 usb_func(struct i2c_adapter *adap)
+static u32 functionality(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
 }
@@ -199,11 +198,11 @@ static u32 usb_func(struct i2c_adapter *
 
 /* -----exported algorithm data: -------------------------------------	*/
 
-static struct i2c_algorithm i2c_usb_algo = {
-	.master_xfer   = usb_xfer,
+static struct i2c_algorithm usbvision_algo = {
+	.master_xfer   = usbvision_i2c_xfer,
 	.smbus_xfer    = NULL,
 	.algo_control  = algo_control,
-	.functionality = usb_func,
+	.functionality = functionality,
 };
 
 
@@ -213,41 +212,29 @@ static struct i2c_algorithm i2c_usb_algo
 static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
 {
 	PDEBUG(DBG_I2C, "I2C   debugging is enabled [i2c]");
-	PDEBUG(DBG_ALGO, "ALGO   debugging is enabled [i2c]");
+	PDEBUG(DBG_I2C, "ALGO   debugging is enabled [i2c]");
 
 	/* register new adapter to i2c module... */
 
-	adap->algo = &i2c_usb_algo;
+	adap->algo = &usbvision_algo;
 
 	adap->timeout = 100;	/* default values, should       */
 	adap->retries = 3;	/* be replaced by defines       */
 
 	i2c_add_adapter(adap);
 
-	PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name);
-
-	return 0;
-}
-
-
-int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap)
-{
-
-	i2c_del_adapter(adap);
-
-	PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name);
+	PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name);
 
 	return 0;
 }
 
-
 /* ----------------------------------------------------------------------- */
 /* usbvision specific I2C functions                                        */
 /* ----------------------------------------------------------------------- */
 static struct i2c_adapter i2c_adap_template;
 static struct i2c_client i2c_client_template;
 
-int usbvision_init_i2c(struct usb_usbvision *usbvision)
+int usbvision_i2c_register(struct usb_usbvision *usbvision)
 {
 	memcpy(&usbvision->i2c_adap, &i2c_adap_template,
 	       sizeof(struct i2c_adapter));
@@ -265,7 +252,7 @@ int usbvision_init_i2c(struct usb_usbvis
 	usbvision->i2c_client.adapter = &usbvision->i2c_adap;
 
 	if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
-		printk(KERN_ERR "usbvision_init_i2c: can't write reg\n");
+		printk(KERN_ERR "usbvision_register: can't write reg\n");
 		return -EBUSY;
 	}
 
@@ -287,6 +274,16 @@ #endif
 	return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
 }
 
+int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
+{
+
+	i2c_del_adapter(&(usbvision->i2c_adap));
+
+	PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name);
+
+	return 0;
+}
+
 void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
 		      void *arg)
 {
@@ -300,19 +297,12 @@ static int attach_inform(struct i2c_clie
 	usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
 
 	switch (client->addr << 1) {
-		case 0x43:
-		case 0x4b:
-		{
-			struct tuner_setup tun_setup;
-
-			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-			tun_setup.type = TUNER_TDA9887;
-			tun_setup.addr = client->addr;
-
-			call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
-
+		case 0x42 << 1:
+		case 0x43 << 1:
+		case 0x4a << 1:
+		case 0x4b << 1:
+			PDEBUG(DBG_I2C,"attach_inform: tda9887 detected.");
 			break;
-		}
 		case 0x42:
 			PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
 			break;
@@ -480,7 +470,7 @@ static int usbvision_i2c_write_max4(stru
 	return len;
 }
 
-static int usbvision_i2c_write(void *data, unsigned char addr, char *buf,
+static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
 			    short len)
 {
 	char *bufPtr = buf;
@@ -488,7 +478,6 @@ static int usbvision_i2c_write(void *dat
 	int wrcount = 0;
 	int count;
 	int maxLen = 4;
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
 
 	while (len > 0) {
 		count = (len > maxLen) ? maxLen : len;
@@ -503,14 +492,13 @@ static int usbvision_i2c_write(void *dat
 	return wrcount;
 }
 
-static int usbvision_i2c_read(void *data, unsigned char addr, char *buf,
+static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
 			   short len)
 {
 	char temp[4];
 	int retval, i;
 	int rdcount = 0;
 	int count;
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) data;
 
 	while (len > 0) {
 		count = (len > 3) ? 4 : len;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 6fc1455..aa3258b 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -52,7 +52,6 @@ #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
 #include <linux/videodev.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
@@ -76,6 +75,7 @@ #include <linux/kmod.h>
 #endif
 
 #include "usbvision.h"
+#include "usbvision-cards.h"
 
 #define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
 #define DRIVER_NAME "usbvision"
@@ -150,7 +150,6 @@ static int PowerOnAtOpen = 1;				// Set 
 static int video_nr = -1;				// Sequential Number of Video Device
 static int radio_nr = -1;				// Sequential Number of Radio Device
 static int vbi_nr = -1;					// Sequential Number of VBI Device
-static char *CustomDevice=NULL;				// Set as nothing....
 
 // Grab parameters for the device driver
 
@@ -161,7 +160,6 @@ module_param(PowerOnAtOpen, int, 0444);
 module_param(video_nr, int, 0444);
 module_param(radio_nr, int, 0444);
 module_param(vbi_nr, int, 0444);
-module_param(CustomDevice, charp, 0444);
 #else							// Old Style
 MODULE_PARAM(isocMode, "i");
 MODULE_PARM(video_debug, "i");				// Grab the Debug Mode of the device driver
@@ -171,7 +169,6 @@ MODULE_PARM(SwitchSVideoInput, "i");			/
 MODULE_PARM(video_nr, "i");				// video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
 MODULE_PARM(radio_nr, "i");				// radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
 MODULE_PARM(vbi_nr, "i");				// vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-MODULE_PARM(CustomDevice, "s");				// .... CustomDevice
 #endif
 
 MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
@@ -180,7 +177,6 @@ MODULE_PARM_DESC(PowerOnAtOpen, " Set th
 MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX).  Default: -1 (autodetect)");
 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
 MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX).  Default: -1 (autodetect)");
-MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device.  Default: null");
 
 
 // Misc stuff
@@ -409,7 +405,7 @@ static int usbvision_v4l2_open(struct in
 		down(&usbvision->lock);
 		if (usbvision->power == 0) {
 			usbvision_power_on(usbvision);
-			usbvision_init_i2c(usbvision);
+			usbvision_i2c_register(usbvision);
 		}
 
 		/* Send init sequence only once, it's large! */
@@ -431,7 +427,7 @@ static int usbvision_v4l2_open(struct in
 		}
 		else {
 			if (PowerOnAtOpen) {
-				usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+				usbvision_i2c_unregister(usbvision);
 				usbvision_power_off(usbvision);
 				usbvision->initialized = 0;
 			}
@@ -1239,7 +1235,7 @@ static int usbvision_radio_open(struct i
 			usbvision_reset_powerOffTimer(usbvision);
 			if (usbvision->power == 0) {
 				usbvision_power_on(usbvision);
-				usbvision_init_i2c(usbvision);
+				usbvision_i2c_register(usbvision);
 			}
 		}
 
@@ -1261,7 +1257,7 @@ static int usbvision_radio_open(struct i
 
 	if (errCode) {
 		if (PowerOnAtOpen) {
-			usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+			usbvision_i2c_unregister(usbvision);
 			usbvision_power_off(usbvision);
 			usbvision->initialized = 0;
 		}
@@ -1744,8 +1740,8 @@ static void usbvision_configure_video(st
 	model = usbvision->DevModel;
 	usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
 
-	if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) {
-		usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff;
+	if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
+		usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
 	} else {
 		usbvision->Vin_Reg2_Preset = 0;
 	}
@@ -1764,7 +1760,7 @@ static void usbvision_configure_video(st
 	usbvision_audio_off(usbvision);	//first switch off audio
 	if (!PowerOnAtOpen) {
 		usbvision_power_on(usbvision);	//and then power up the noisy tuner
-		usbvision_init_i2c(usbvision);
+		usbvision_i2c_register(usbvision);
 	}
 }
 
@@ -1775,7 +1771,8 @@ static void usbvision_configure_video(st
  * if it looks like USBVISION video device
  *
  */
-static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+static int __devinit usbvision_probe(struct usb_interface *intf,
+				     const struct usb_device_id *devid)
 {
 	struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
 	struct usb_interface *uif;
@@ -1786,25 +1783,17 @@ static int __devinit usbvision_probe(str
 	int model,i;
 
 	PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
-					dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+				dev->descriptor.idVendor,
+				dev->descriptor.idProduct, ifnum);
 
-	/* Is it an USBVISION video dev? */
-	model = 0;
-	for(model = 0; usbvision_device_data[model].idVendor; model++) {
-		if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) {
-			continue;
-		}
-		if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) {
-			continue;
-		}
-
-		printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString);
-		break;
+	model = devid->driver_info;
+	if ( (model<0) || (model>=usbvision_device_data_size) ) {
+		PDEBUG(DBG_PROBE, "model out of bounds %d",model);
+		return -ENODEV;
 	}
+	printk(KERN_INFO "%s: %s found\n", __FUNCTION__,
+				usbvision_device_data[model].ModelString);
 
-	if (usbvision_device_data[model].idVendor == 0) {
-		return -ENODEV; //no matching device
-	}
 	if (usbvision_device_data[model].Interface >= 0) {
 		interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
 	}
@@ -1822,16 +1811,15 @@ static int __devinit usbvision_probe(str
 		return -ENODEV;
 	}
 
-	usb_get_dev(dev);
-
 	if ((usbvision = usbvision_alloc(dev)) == NULL) {
 		err("%s: couldn't allocate USBVision struct", __FUNCTION__);
 		return -ENOMEM;
 	}
+
 	if (dev->descriptor.bNumConfigurations > 1) {
 		usbvision->bridgeType = BRIDGE_NT1004;
 	}
-	else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") {
+	else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
 		usbvision->bridgeType = BRIDGE_NT1005;
 	}
 	else {
@@ -1920,7 +1908,7 @@ static void __devexit usbvision_disconne
 	usbvision_stop_isoc(usbvision);
 
 	if (usbvision->power) {
-		usbvision_i2c_usb_del_bus(&usbvision->i2c_adap);
+		usbvision_i2c_unregister(usbvision);
 		usbvision_power_off(usbvision);
 	}
 	usbvision->remove_pending = 1;	// Now all ISO data will be ignored
@@ -1951,124 +1939,6 @@ static struct usb_driver usbvision_drive
 };
 
 /*
- * customdevice_process()
- *
- * This procedure preprocesses CustomDevice parameter if any
- *
- */
-static void customdevice_process(void)
-{
-	usbvision_device_data[0]=usbvision_device_data[1];
-	usbvision_table[0]=usbvision_table[1];
-
-	if(CustomDevice)
-	{
-		char *parse=CustomDevice;
-
-		PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice);
-
-		/*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1"
-		usbvision_device_data[0].idVendor;
-		usbvision_device_data[0].idProduct;
-		usbvision_device_data[0].Interface;
-		usbvision_device_data[0].Codec;
-		usbvision_device_data[0].VideoChannels;
-		usbvision_device_data[0].VideoNorm;
-		usbvision_device_data[0].AudioChannels;
-		usbvision_device_data[0].Radio;
-		usbvision_device_data[0].Tuner;
-		usbvision_device_data[0].TunerType;
-		usbvision_device_data[0].Vin_Reg1;
-		usbvision_device_data[0].Vin_Reg2;
-		usbvision_device_data[0].X_Offset;
-		usbvision_device_data[0].Y_Offset;
-		usbvision_device_data[0].Dvi_yuv;
-		usbvision_device_data[0].ModelString;
-		*/
-
-		rmspace(parse);
-		usbvision_device_data[0].ModelString="USBVISION Custom Device";
-
-		parse+=2;
-		sscanf(parse,"%x",&usbvision_device_data[0].idVendor);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor);
-		parse+=2;
-		sscanf(parse,"%x",&usbvision_device_data[0].idProduct);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct);
-		sscanf(parse,"%d",&usbvision_device_data[0].Interface);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface);
-		sscanf(parse,"%d",&usbvision_device_data[0].Codec);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec);
-		sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels);
-
-		switch(*parse)
-		{
-			case 'P':
-				PDEBUG(DBG_PROBE, "VideoNorm=PAL");
-				usbvision_device_data[0].VideoNorm=V4L2_STD_PAL;
-				break;
-
-			case 'S':
-				PDEBUG(DBG_PROBE, "VideoNorm=SECAM");
-				usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM;
-				break;
-
-			case 'N':
-				PDEBUG(DBG_PROBE, "VideoNorm=NTSC");
-				usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC;
-				break;
-
-			default:
-				PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)");
-				usbvision_device_data[0].VideoNorm=V4L2_STD_PAL;
-				break;
-		}
-		goto2next(parse);
-
-		sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels);
-		sscanf(parse,"%d",&usbvision_device_data[0].Radio);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio);
-		sscanf(parse,"%d",&usbvision_device_data[0].Tuner);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner);
-		sscanf(parse,"%d",&usbvision_device_data[0].TunerType);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType);
-		sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1);
-		sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2);
-		sscanf(parse,"%d",&usbvision_device_data[0].X_Offset);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset);
-		sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset);
-		goto2next(parse);
-		PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset);
-		sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv);
-		PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv);
-
-		//add to usbvision_table also
-		usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE;
-		usbvision_table[0].idVendor=usbvision_device_data[0].idVendor;
-		usbvision_table[0].idProduct=usbvision_device_data[0].idProduct;
-
-	}
-}
-
-
-
-/*
  * usbvision_init()
  *
  * This code is run to initialize the driver.
@@ -2092,8 +1962,6 @@ static int __init usbvision_init(void)
 		usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P
 	}
 
-	customdevice_process();
-
 	errCode = usb_register(&usbvision_driver);
 
 	if (errCode == 0) {
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index ad6afd3..bd6f642 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -342,23 +342,24 @@ #define BRIDGE_NT1004	1004
 #define BRIDGE_NT1005   1005
 
 struct usbvision_device_data_st {
-	int idVendor;
-	int idProduct;
-	int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
-	int Codec;
-	int VideoChannels;
 	__u64 VideoNorm;
-	int AudioChannels;
-	int Radio;
-	int vbi;
-	int Tuner;
-	int TunerType;
-	int Vin_Reg1;
-	int Vin_Reg2;
-	int X_Offset;
-	int Y_Offset;
-	int Dvi_yuv;
-	char *ModelString;
+	const char *ModelString;
+	int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
+	__u16 Codec;
+	unsigned VideoChannels:3;
+	unsigned AudioChannels:2;
+	unsigned Radio:1;
+	unsigned vbi:1;
+	unsigned Tuner:1;
+	unsigned Vin_Reg1_override:1;	/* Override default value with */
+	unsigned Vin_Reg2_override:1;   /* Vin_Reg1, Vin_Reg2, etc. */
+	unsigned Dvi_yuv_override:1;
+	__u8 Vin_Reg1;
+	__u8 Vin_Reg2;
+	__u8 Dvi_yuv;
+	__u8 TunerType;
+	__s16 X_Offset;
+	__s16 Y_Offset;
 };
 
 /* Declared on usbvision-cards.c */
@@ -481,13 +482,11 @@ struct usb_usbvision {
 /* i2c-algo-usb declaration                                        */
 /* --------------------------------------------------------------- */
 
-int usbvision_i2c_usb_del_bus(struct i2c_adapter *);
-
-
 /* ----------------------------------------------------------------------- */
 /* usbvision specific I2C functions                                        */
 /* ----------------------------------------------------------------------- */
-int usbvision_init_i2c(struct usb_usbvision *usbvision);
+int usbvision_i2c_register(struct usb_usbvision *usbvision);
+int usbvision_i2c_unregister(struct usb_usbvision *usbvision);
 void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
 
 /* defined in usbvision-core.c                                      */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d2c1ae0..a861e15 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -23,7 +23,6 @@ #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/file.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 5474760..13ee550 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -47,7 +47,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -60,6 +59,7 @@ #include <asm/div64.h>
 #include <linux/video_decoder.h>
 #define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
@@ -260,6 +260,8 @@ char *v4l2_field_names[] = {
 	[V4L2_FIELD_SEQ_TB]     = "seq-tb",
 	[V4L2_FIELD_SEQ_BT]     = "seq-bt",
 	[V4L2_FIELD_ALTERNATE]  = "alternate",
+	[V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
+	[V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
 };
 
 char *v4l2_type_names[] = {
@@ -269,7 +271,8 @@ char *v4l2_type_names[] = {
 	[V4L2_BUF_TYPE_VBI_CAPTURE]        = "vbi-cap",
 	[V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
 	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap",
-	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "slicec-vbi-out",
+	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
 };
 
 
@@ -380,6 +383,8 @@ #if 1
 
 	[_IOC_NR(VIDIOC_DBG_S_REGISTER)]   = "VIDIOC_DBG_S_REGISTER",
 	[_IOC_NR(VIDIOC_DBG_G_REGISTER)]   = "VIDIOC_DBG_G_REGISTER",
+
+	[_IOC_NR(VIDIOC_G_CHIP_IDENT)]     = "VIDIOC_G_CHIP_IDENT",
 #endif
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -410,14 +415,16 @@ #endif
 	[_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)]  = "VIDIOC_INT_DECODE_VBI_LINE",
 	[_IOC_NR(VIDIOC_INT_S_VBI_DATA)]       = "VIDIOC_INT_S_VBI_DATA",
 	[_IOC_NR(VIDIOC_INT_G_VBI_DATA)]       = "VIDIOC_INT_G_VBI_DATA",
-	[_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)]     = "VIDIOC_INT_G_CHIP_IDENT",
 	[_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)]   = "VIDIOC_INT_I2S_CLOCK_FREQ",
 	[_IOC_NR(VIDIOC_INT_S_STANDBY)]        = "VIDIOC_INT_S_STANDBY",
 	[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)]  = "VIDIOC_INT_S_AUDIO_ROUTING",
 	[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)]  = "VIDIOC_INT_G_AUDIO_ROUTING",
 	[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)]  = "VIDIOC_INT_S_VIDEO_ROUTING",
 	[_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)]  = "VIDIOC_INT_G_VIDEO_ROUTING",
-	[_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)]   = "VIDIOC_INT_S_CRYSTAL_FREQ"
+	[_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)]   = "VIDIOC_INT_S_CRYSTAL_FREQ",
+	[_IOC_NR(VIDIOC_INT_INIT)]   	       = "VIDIOC_INT_INIT",
+	[_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)]     = "VIDIOC_INT_G_STD_OUTPUT",
+	[_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)]     = "VIDIOC_INT_S_STD_OUTPUT",
 };
 #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
 
@@ -680,6 +687,7 @@ int v4l2_ctrl_query_fill(struct v4l2_que
 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
 	case V4L2_CID_MPEG_AUDIO_EMPHASIS: 	name = "Audio Emphasis"; break;
 	case V4L2_CID_MPEG_AUDIO_CRC: 		name = "Audio CRC"; break;
+	case V4L2_CID_MPEG_AUDIO_MUTE: 		name = "Audio Mute"; break;
 	case V4L2_CID_MPEG_VIDEO_ENCODING: 	name = "Video Encoding"; break;
 	case V4L2_CID_MPEG_VIDEO_ASPECT: 	name = "Video Aspect"; break;
 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: 	name = "Video B Frames"; break;
@@ -690,6 +698,8 @@ int v4l2_ctrl_query_fill(struct v4l2_que
 	case V4L2_CID_MPEG_VIDEO_BITRATE: 	name = "Video Bitrate"; break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: 	name = "Video Peak Bitrate"; break;
 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+	case V4L2_CID_MPEG_VIDEO_MUTE: 		name = "Video Mute"; break;
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:	name = "Video Mute YUV"; break;
 	case V4L2_CID_MPEG_STREAM_TYPE: 	name = "Stream Type"; break;
 	case V4L2_CID_MPEG_STREAM_PID_PMT: 	name = "Stream PMT Program ID"; break;
 	case V4L2_CID_MPEG_STREAM_PID_AUDIO: 	name = "Stream Audio Program ID"; break;
@@ -705,6 +715,7 @@ int v4l2_ctrl_query_fill(struct v4l2_que
 	switch (qctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_LOUDNESS:
+	case V4L2_CID_MPEG_AUDIO_MUTE:
 	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
 	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
 		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
@@ -838,6 +849,8 @@ int v4l2_ctrl_query_fill_std(struct v4l2
 				V4L2_MPEG_AUDIO_CRC_NONE,
 				V4L2_MPEG_AUDIO_CRC_CRC16, 1,
 				V4L2_MPEG_AUDIO_CRC_NONE);
+	case V4L2_CID_MPEG_AUDIO_MUTE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
 	case V4L2_CID_MPEG_VIDEO_ENCODING:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
@@ -867,6 +880,10 @@ int v4l2_ctrl_query_fill_std(struct v4l2
 		return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
 		return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+	case V4L2_CID_MPEG_VIDEO_MUTE:
+		return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:  /* Init YUV (really YCbCr) to black */
+		return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
 	case V4L2_CID_MPEG_STREAM_TYPE:
 		return v4l2_ctrl_query_fill(qctrl,
 				V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
@@ -965,6 +982,22 @@ int v4l2_chip_match_i2c_client(struct i2
 	}
 }
 
+int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
+		u32 ident, u32 revision)
+{
+	if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip))
+		return 0;
+	if (chip->ident == V4L2_IDENT_NONE) {
+		chip->ident = ident;
+		chip->revision = revision;
+	}
+	else {
+		chip->ident = V4L2_IDENT_AMBIGUOUS;
+		chip->revision = 0;
+	}
+	return 0;
+}
+
 int v4l2_chip_match_host(u32 match_type, u32 match_chip)
 {
 	switch (match_type) {
@@ -999,6 +1032,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
 EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
 
 EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
+EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
 EXPORT_SYMBOL(v4l2_chip_match_host);
 
 /*
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 290e641..f2bbd7a 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -348,6 +348,9 @@ #define LINESIZE 100
 	kfree(videocodec_buf);
 	videocodec_buf = kmalloc(size, GFP_KERNEL);
 
+	if (!videocodec_buf)
+		return 0;
+
 	i = 0;
 	i += scnprintf(videocodec_buf + i, size - 1,
 		      "<S>lave or attached <M>aster name  type flags    magic    ");
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 011938f..5263b50 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -30,7 +30,6 @@ #define dbgarg2(fmt, arg...) \
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -318,6 +317,7 @@ static char *v4l2_type_names_FIXME[] = {
 	[V4L2_BUF_TYPE_VBI_OUTPUT]         = "vbi-out",
 	[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT]  = "sliced-vbi-out",
 	[V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over",
 	[V4L2_BUF_TYPE_PRIVATE]            = "private",
 };
 
@@ -330,6 +330,8 @@ static char *v4l2_field_names_FIXME[] = 
 	[V4L2_FIELD_SEQ_TB]     = "seq-tb",
 	[V4L2_FIELD_SEQ_BT]     = "seq-bt",
 	[V4L2_FIELD_ALTERNATE]  = "alternate",
+	[V4L2_FIELD_INTERLACED_TB] = "interlaced-tb",
+	[V4L2_FIELD_INTERLACED_BT] = "interlaced-bt",
 };
 
 #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
@@ -411,6 +413,10 @@ static int check_fmt (struct video_devic
 		if (vfd->vidioc_try_fmt_vbi_output)
 			return (0);
 		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+		if (vfd->vidioc_try_fmt_output_overlay)
+			return (0);
+		break;
 	case V4L2_BUF_TYPE_PRIVATE:
 		if (vfd->vidioc_try_fmt_type_private)
 			return (0);
@@ -525,6 +531,10 @@ static int __video_do_ioctl(struct inode
 				ret=vfd->vidioc_enum_fmt_vbi_output(file,
 								fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+			if (vfd->vidioc_enum_fmt_output_overlay)
+				ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f);
+			break;
 		case V4L2_BUF_TYPE_PRIVATE:
 			if (vfd->vidioc_enum_fmt_type_private)
 				ret=vfd->vidioc_enum_fmt_type_private(file,
@@ -582,6 +592,10 @@ static int __video_do_ioctl(struct inode
 				ret=vfd->vidioc_g_fmt_video_output(file,
 								fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+			if (vfd->vidioc_g_fmt_output_overlay)
+				ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f);
+			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
 			if (vfd->vidioc_g_fmt_vbi_output)
 				ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
@@ -630,6 +644,10 @@ static int __video_do_ioctl(struct inode
 				ret=vfd->vidioc_s_fmt_video_output(file,
 								fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+			if (vfd->vidioc_s_fmt_output_overlay)
+				ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f);
+			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
 			if (vfd->vidioc_s_fmt_vbi_output)
 				ret=vfd->vidioc_s_fmt_vbi_output(file,
@@ -680,6 +698,10 @@ static int __video_do_ioctl(struct inode
 				ret=vfd->vidioc_try_fmt_video_output(file,
 								fh, f);
 			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+			if (vfd->vidioc_try_fmt_output_overlay)
+				ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f);
+			break;
 		case V4L2_BUF_TYPE_VBI_OUTPUT:
 			if (vfd->vidioc_try_fmt_vbi_output)
 				ret=vfd->vidioc_try_fmt_vbi_output(file,
@@ -1381,6 +1403,11 @@ #endif
 	case VIDIOC_G_PARM:
 	{
 		struct v4l2_streamparm *p=arg;
+		__u32 type=p->type;
+
+		memset(p,0,sizeof(*p));
+		p->type=type;
+
 		if (vfd->vidioc_g_parm) {
 			ret=vfd->vidioc_g_parm(file, fh, p);
 		} else {
@@ -1392,8 +1419,6 @@ #endif
 			v4l2_video_std_construct(&s, vfd->current_norm,
 						 v4l2_norm_to_name(vfd->current_norm));
 
-			memset(p,0,sizeof(*p));
-
 			p->parm.capture.timeperframe = s.frameperiod;
 			ret=0;
 		}
@@ -1509,6 +1534,16 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 		break;
 	}
 #endif
+	case VIDIOC_G_CHIP_IDENT:
+	{
+		struct v4l2_chip_ident *p=arg;
+		if (!vfd->vidioc_g_chip_ident)
+			break;
+		ret=vfd->vidioc_g_chip_ident(file, fh, p);
+		if (!ret)
+			dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
+		break;
+	}
 	} /* switch */
 
 	if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index a9b59c3..8f6741a 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -29,6 +29,7 @@ #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("wm8739 driver");
 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
@@ -236,6 +237,9 @@ static int wm8739_command(struct i2c_cli
 		return -EINVAL;
 	}
 
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
+
 	case VIDIOC_LOG_STATUS:
 		v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
 		v4l_info(client, "Volume L:  %02x%s\n", state->vol_l & 0x1f,
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index d81a88b..4df5d30 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -33,6 +33,7 @@ #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -124,6 +125,9 @@ static int wm8775_command(struct i2c_cli
 			wm8775_write(client, R21, 0x100 + state->input);
 		break;
 
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0);
+
 	case VIDIOC_LOG_STATUS:
 		v4l_info(client, "Input: %d%s\n", state->input,
 			    state->muted ? " (muted)" : "");
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 0743237..cf0ed6c 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -2034,7 +2034,7 @@ zoran_do_ioctl (struct inode *inode,
 	 * but moving the free code outside the munmap() handler fixes
 	 * all this... If someone knows why, please explain me (Ronald)
 	 */
-	if (!!mutex_trylock(&zr->resource_lock)) {
+	if (mutex_trylock(&zr->resource_lock)) {
 		/* we obtained it! Let's try to free some things */
 		if (fh->jpg_buffers.ready_to_be_freed)
 			jpg_fbuffer_free(file);
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
new file mode 100644
index 0000000..b5d3364
--- /dev/null
+++ b/drivers/media/video/zr364xx.c
@@ -0,0 +1,929 @@
+/*
+ * Zoran 364xx based USB webcam module version 0.72
+ *
+ * Allows you to use your USB webcam with V4L2 applications
+ * This is still in heavy developpement !
+ *
+ * Copyright (C) 2004  Antoine Jacquet <royale@zerezo.com>
+ * http://royale.zerezo.com/zr364xx/
+ *
+ * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
+ * V4L2 version inspired by meye.c 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/highmem.h>
+#include <media/v4l2-common.h>
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.72"
+#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
+#define DRIVER_DESC "Zoran 364xx"
+
+
+/* Camera */
+#define FRAMES 2
+#define MAX_FRAME_SIZE 100000
+#define BUFFER_SIZE 0x1000
+#define CTRL_TIMEOUT 500
+
+
+/* Debug macro */
+#define DBG(x...) if (debug) info(x)
+
+
+/* Init methods, need to find nicer names for these
+ * the exact names of the chipsets would be the best if someone finds it */
+#define METHOD0 0
+#define METHOD1 1
+#define METHOD2 2
+
+
+/* Module parameters */
+static int debug = 0;
+static int mode = 0;
+
+
+/* Module parameters interface */
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level");
+module_param(mode, int, 0644);
+MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480");
+
+
+/* Devices supported by this driver
+ * .driver_info contains the init method used by the camera */
+static struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 },
+	{USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 },
+	{USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 },
+	{USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 },
+	{USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 },
+	{USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 },
+	{USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
+	{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
+	{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+
+/* Camera stuff */
+struct zr364xx_camera {
+	struct usb_device *udev;	/* save off the usb device pointer */
+	struct usb_interface *interface;/* the interface for this device */
+	struct video_device *vdev;	/* v4l video device */
+	u8 *framebuf;
+	int nb;
+	unsigned char *buffer;
+	int skip;
+	int brightness;
+	int width;
+	int height;
+	int method;
+	struct mutex lock;
+};
+
+
+/* function used to send initialisation commands to the camera */
+static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
+			    u16 index, unsigned char *cp, u16 size)
+{
+	int status;
+
+	unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
+	if (!transfer_buffer) {
+		info("kmalloc(%d) failed", size);
+		return -ENOMEM;
+	}
+
+	memcpy(transfer_buffer, cp, size);
+
+	status = usb_control_msg(udev,
+				 usb_sndctrlpipe(udev, 0),
+				 request,
+				 USB_DIR_OUT | USB_TYPE_VENDOR |
+				 USB_RECIP_DEVICE, value, index,
+				 transfer_buffer, size, CTRL_TIMEOUT);
+
+	kfree(transfer_buffer);
+
+	if (status < 0)
+		info("Failed sending control message, error %d.", status);
+
+	return status;
+}
+
+
+/* Control messages sent to the camera to initialize it
+ * and launch the capture */
+typedef struct {
+	unsigned int value;
+	unsigned int size;
+	unsigned char *bytes;
+} message;
+
+/* method 0 */
+static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 };
+static unsigned char m0d3[] = { 0, 0 };
+static message m0[] = {
+	{0x1f30, 0, NULL},
+	{0xd000, 0, NULL},
+	{0x3370, sizeof(m0d1), m0d1},
+	{0x2000, 0, NULL},
+	{0x2f0f, 0, NULL},
+	{0x2610, sizeof(m0d2), m0d2},
+	{0xe107, 0, NULL},
+	{0x2502, 0, NULL},
+	{0x1f70, 0, NULL},
+	{0xd000, 0, NULL},
+	{0x9a01, sizeof(m0d3), m0d3},
+	{-1, -1, NULL}
+};
+
+/* method 1 */
+static unsigned char m1d1[] = { 0xff, 0xff };
+static unsigned char m1d2[] = { 0x00, 0x00 };
+static message m1[] = {
+	{0x1f30, 0, NULL},
+	{0xd000, 0, NULL},
+	{0xf000, 0, NULL},
+	{0x2000, 0, NULL},
+	{0x2f0f, 0, NULL},
+	{0x2650, 0, NULL},
+	{0xe107, 0, NULL},
+	{0x2502, sizeof(m1d1), m1d1},
+	{0x1f70, 0, NULL},
+	{0xd000, 0, NULL},
+	{0xd000, 0, NULL},
+	{0xd000, 0, NULL},
+	{0x9a01, sizeof(m1d2), m1d2},
+	{-1, -1, NULL}
+};
+
+/* method 2 */
+static unsigned char m2d1[] = { 0xff, 0xff };
+static message m2[] = {
+	{0x1f30, 0, NULL},
+	{0xf000, 0, NULL},
+	{0x2000, 0, NULL},
+	{0x2f0f, 0, NULL},
+	{0x2650, 0, NULL},
+	{0xe107, 0, NULL},
+	{0x2502, sizeof(m2d1), m2d1},
+	{0x1f70, 0, NULL},
+	{-1, -1, NULL}
+};
+
+/* init table */
+static message *init[3] = { m0, m1, m2 };
+
+
+/* JPEG static data in header (Huffman table, etc) */
+static unsigned char header1[] = {
+	0xFF, 0xD8,
+	/*
+	0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F',
+	0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88,
+	*/
+	0xFF, 0xDB, 0x00, 0x84
+};
+static unsigned char header2[] = {
+	0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+	0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
+	0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01,
+	0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
+	0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
+	0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33,
+	0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25,
+	0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+	0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,
+	0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
+	0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
+	0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94,
+	0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+	0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8,
+	0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
+	0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
+	0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3,
+	0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F,
+	0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
+	0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5,
+	0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
+	0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11,
+	0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+	0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1,
+	0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16,
+	0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27,
+	0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44,
+	0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
+	0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84,
+	0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
+	0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+	0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA,
+	0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3,
+	0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5,
+	0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+	0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01,
+	0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
+	0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
+	0x00, 0x3F, 0x00
+};
+static unsigned char header3;
+
+
+
+/********************/
+/* V4L2 integration */
+/********************/
+
+/* this function reads a full JPEG picture synchronously
+ * TODO: do it asynchronously... */
+static int read_frame(struct zr364xx_camera *cam, int framenum)
+{
+	int i, n, temp, head, size, actual_length;
+	unsigned char *ptr = NULL, *jpeg;
+
+      redo:
+	/* hardware brightness */
+	n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+	temp = (0x60 << 8) + 127 - cam->brightness;
+	n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+
+	/* during the first loop we are going to insert JPEG header */
+	head = 0;
+	/* this is the place in memory where we are going to build
+	 * the JPEG image */
+	jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
+	/* read data... */
+	do {
+		n = usb_bulk_msg(cam->udev,
+				 usb_rcvbulkpipe(cam->udev, 0x81),
+				 cam->buffer, BUFFER_SIZE, &actual_length,
+				 CTRL_TIMEOUT);
+		DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
+		DBG("bulk : n=%d size=%d", n, actual_length);
+		if (n < 0) {
+			info("error reading bulk msg");
+			return 0;
+		}
+		if (actual_length < 0 || actual_length > BUFFER_SIZE) {
+			info("wrong number of bytes");
+			return 0;
+		}
+
+		/* swap bytes if camera needs it */
+		if (cam->method == METHOD0) {
+			u16 *buf = (u16*)cam->buffer;
+			for (i = 0; i < BUFFER_SIZE/2; i++)
+				swab16s(buf + i);
+		}
+
+		/* write the JPEG header */
+		if (!head) {
+			DBG("jpeg header");
+			ptr = jpeg;
+			memcpy(ptr, header1, sizeof(header1));
+			ptr += sizeof(header1);
+			header3 = 0;
+			memcpy(ptr, &header3, 1);
+			ptr++;
+			memcpy(ptr, cam->buffer, 64);
+			ptr += 64;
+			header3 = 1;
+			memcpy(ptr, &header3, 1);
+			ptr++;
+			memcpy(ptr, cam->buffer + 64, 64);
+			ptr += 64;
+			memcpy(ptr, header2, sizeof(header2));
+			ptr += sizeof(header2);
+			memcpy(ptr, cam->buffer + 128,
+			       actual_length - 128);
+			ptr += actual_length - 128;
+			head = 1;
+			DBG("header : %d %d %d %d %d %d %d %d %d",
+			    cam->buffer[0], cam->buffer[1], cam->buffer[2],
+			    cam->buffer[3], cam->buffer[4], cam->buffer[5],
+			    cam->buffer[6], cam->buffer[7], cam->buffer[8]);
+		} else {
+			memcpy(ptr, cam->buffer, actual_length);
+			ptr += actual_length;
+		}
+	}
+	/* ... until there is no more */
+	while (actual_length == BUFFER_SIZE);
+
+	/* we skip the 2 first frames which are usually buggy */
+	if (cam->skip) {
+		cam->skip--;
+		goto redo;
+	}
+
+	/* go back to find the JPEG EOI marker */
+	size = ptr - jpeg;
+	ptr -= 2;
+	while (ptr > jpeg) {
+		if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+		    && *(ptr + 2) == 0xFF)
+			break;
+		ptr--;
+	}
+	if (ptr == jpeg)
+		DBG("No EOI marker");
+
+	/* Sometimes there is junk data in the middle of the picture,
+	 * we want to skip this bogus frames */
+	while (ptr > jpeg) {
+		if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+		    && *(ptr + 2) == 0xFF)
+			break;
+		ptr--;
+	}
+	if (ptr != jpeg) {
+		DBG("Bogus frame ? %d", cam->nb);
+		goto redo;
+	}
+
+	DBG("jpeg : %d %d %d %d %d %d %d %d",
+	    jpeg[0], jpeg[1], jpeg[2], jpeg[3],
+	    jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+
+	return size;
+}
+
+
+static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt,
+			    loff_t * ppos)
+{
+	unsigned long count = cnt;
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	DBG("zr364xx_read: read %d bytes.", (int) count);
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	if (!buf)
+		return -EINVAL;
+
+	if (!count)
+		return -EINVAL;
+
+	/* NoMan Sux ! */
+	count = read_frame(cam, 0);
+
+	if (copy_to_user(buf, cam->framebuf, count))
+		return -EFAULT;
+
+	return count;
+}
+
+
+static int zr364xx_vidioc_querycap(struct file *file, void *priv,
+				   struct v4l2_capability *cap)
+{
+	memset(cap, 0, sizeof(*cap));
+	strcpy(cap->driver, DRIVER_DESC);
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+	return 0;
+}
+
+static int zr364xx_vidioc_enum_input(struct file *file, void *priv,
+				     struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+	memset(i, 0, sizeof(*i));
+	i->index = 0;
+	strcpy(i->name, DRIVER_DESC " Camera");
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	return 0;
+}
+
+static int zr364xx_vidioc_g_input(struct file *file, void *priv,
+				  unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int zr364xx_vidioc_s_input(struct file *file, void *priv,
+				  unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
+				    struct v4l2_queryctrl *c)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->type = V4L2_CTRL_TYPE_INTEGER;
+		strcpy(c->name, "Brightness");
+		c->minimum = 0;
+		c->maximum = 127;
+		c->step = 1;
+		c->default_value = cam->brightness;
+		c->flags = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
+				 struct v4l2_control *c)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		cam->brightness = c->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
+				 struct v4l2_control *c)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = cam->brightness;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int zr364xx_vidioc_enum_fmt_cap(struct file *file,
+				       void *priv, struct v4l2_fmtdesc *f)
+{
+	if (f->index > 0)
+		return -EINVAL;
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	memset(f, 0, sizeof(*f));
+	f->index = 0;
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	strcpy(f->description, "JPEG");
+	f->pixelformat = V4L2_PIX_FMT_JPEG;
+	return 0;
+}
+
+static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv,
+				      struct v4l2_format *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+		return -EINVAL;
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = cam->width;
+	f->fmt.pix.height = cam->height;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = cam->width;
+	f->fmt.pix.height = cam->height;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+	return 0;
+}
+
+static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+		return -EINVAL;
+	if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+	    f->fmt.pix.field != V4L2_FIELD_NONE)
+		return -EINVAL;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.width = cam->width;
+	f->fmt.pix.height = cam->height;
+	f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+	f->fmt.pix.colorspace = 0;
+	f->fmt.pix.priv = 0;
+	DBG("ok!");
+	return 0;
+}
+
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+				   enum v4l2_buf_type type)
+{
+	return 0;
+}
+
+static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
+				    enum v4l2_buf_type type)
+{
+	return 0;
+}
+
+
+/* open the camera */
+static int zr364xx_open(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam = video_get_drvdata(vdev);
+	struct usb_device *udev = cam->udev;
+	int i, err;
+
+	DBG("zr364xx_open");
+
+	cam->skip = 2;
+
+	err = video_exclusive_open(inode, file);
+	if (err < 0)
+		return err;
+
+	if (!cam->framebuf) {
+		cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
+		if (!cam->framebuf) {
+			info("vmalloc_32 failed!");
+			return -ENOMEM;
+		}
+	}
+
+	mutex_lock(&cam->lock);
+	for (i = 0; init[cam->method][i].size != -1; i++) {
+		err =
+		    send_control_msg(udev, 1, init[cam->method][i].value,
+				     0, init[cam->method][i].bytes,
+				     init[cam->method][i].size);
+		if (err < 0) {
+			info("error during open sequence: %d", i);
+			mutex_unlock(&cam->lock);
+			return err;
+		}
+	}
+
+	file->private_data = vdev;
+
+	/* Added some delay here, since opening/closing the camera quickly,
+	 * like Ekiga does during its startup, can crash the webcam
+	 */
+	mdelay(100);
+
+	mutex_unlock(&cam->lock);
+	return 0;
+}
+
+
+/* release the camera */
+static int zr364xx_release(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+	struct usb_device *udev;
+	int i, err;
+
+	DBG("zr364xx_release");
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	udev = cam->udev;
+
+	mutex_lock(&cam->lock);
+	for (i = 0; i < 2; i++) {
+		err =
+		    send_control_msg(udev, 1, init[cam->method][i].value,
+				     0, init[i][cam->method].bytes,
+				     init[cam->method][i].size);
+		if (err < 0) {
+			info("error during release sequence");
+			mutex_unlock(&cam->lock);
+			return err;
+		}
+	}
+
+	file->private_data = NULL;
+	video_exclusive_release(inode, file);
+
+	/* Added some delay here, since opening/closing the camera quickly,
+	 * like Ekiga does during its startup, can crash the webcam
+	 */
+	mdelay(100);
+
+	mutex_unlock(&cam->lock);
+	return 0;
+}
+
+
+static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	void *pos;
+	unsigned long start = vma->vm_start;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	struct video_device *vdev = video_devdata(file);
+	struct zr364xx_camera *cam;
+
+	DBG("zr364xx_mmap: %ld\n", size);
+
+	if (vdev == NULL)
+		return -ENODEV;
+	cam = video_get_drvdata(vdev);
+
+	pos = cam->framebuf;
+	while (size > 0) {
+		if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return 0;
+}
+
+
+static struct file_operations zr364xx_fops = {
+	.owner = THIS_MODULE,
+	.open = zr364xx_open,
+	.release = zr364xx_release,
+	.read = zr364xx_read,
+	.mmap = zr364xx_mmap,
+	.ioctl = video_ioctl2,
+	.llseek = no_llseek,
+};
+
+static struct video_device zr364xx_template = {
+	.owner = THIS_MODULE,
+	.name = DRIVER_DESC,
+	.type = VID_TYPE_CAPTURE,
+	.fops = &zr364xx_fops,
+	.release = video_device_release,
+	.minor = -1,
+
+	.vidioc_querycap	= zr364xx_vidioc_querycap,
+	.vidioc_enum_fmt_cap	= zr364xx_vidioc_enum_fmt_cap,
+	.vidioc_try_fmt_cap	= zr364xx_vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap	= zr364xx_vidioc_s_fmt_cap,
+	.vidioc_g_fmt_cap	= zr364xx_vidioc_g_fmt_cap,
+	.vidioc_enum_input	= zr364xx_vidioc_enum_input,
+	.vidioc_g_input		= zr364xx_vidioc_g_input,
+	.vidioc_s_input		= zr364xx_vidioc_s_input,
+	.vidioc_streamon	= zr364xx_vidioc_streamon,
+	.vidioc_streamoff	= zr364xx_vidioc_streamoff,
+	.vidioc_queryctrl	= zr364xx_vidioc_queryctrl,
+	.vidioc_g_ctrl		= zr364xx_vidioc_g_ctrl,
+	.vidioc_s_ctrl		= zr364xx_vidioc_s_ctrl,
+};
+
+
+
+/*******************/
+/* USB integration */
+/*******************/
+
+static int zr364xx_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct zr364xx_camera *cam = NULL;
+
+	DBG("probing...");
+
+	info(DRIVER_DESC " compatible webcam plugged");
+	info("model %04x:%04x detected", udev->descriptor.idVendor,
+	     udev->descriptor.idProduct);
+
+	if ((cam =
+	     kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+		info("cam: out of memory !");
+		return -ENODEV;
+	}
+	memset(cam, 0x00, sizeof(struct zr364xx_camera));
+	/* save the init method used by this camera */
+	cam->method = id->driver_info;
+
+	cam->vdev = video_device_alloc();
+	if (cam->vdev == NULL) {
+		info("cam->vdev: out of memory !");
+		kfree(cam);
+		return -ENODEV;
+	}
+	memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+	video_set_drvdata(cam->vdev, cam);
+	if (debug)
+		cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
+
+	cam->udev = udev;
+
+	if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
+		info("cam->buffer: out of memory !");
+		video_device_release(cam->vdev);
+		kfree(cam);
+		return -ENODEV;
+	}
+
+	switch (mode) {
+	case 1:
+		info("160x120 mode selected");
+		cam->width = 160;
+		cam->height = 120;
+		break;
+	case 2:
+		info("640x480 mode selected");
+		cam->width = 640;
+		cam->height = 480;
+		break;
+	default:
+		info("320x240 mode selected");
+		cam->width = 320;
+		cam->height = 240;
+		break;
+	}
+
+	m0d1[0] = mode;
+	m1[2].value = 0xf000 + mode;
+	m2[1].value = 0xf000 + mode;
+	header2[437] = cam->height / 256;
+	header2[438] = cam->height % 256;
+	header2[439] = cam->width / 256;
+	header2[440] = cam->width % 256;
+
+	cam->nb = 0;
+	cam->brightness = 64;
+	mutex_init(&cam->lock);
+
+	if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+		info("video_register_device failed");
+		video_device_release(cam->vdev);
+		kfree(cam->buffer);
+		kfree(cam);
+		return -ENODEV;
+	}
+
+	usb_set_intfdata(intf, cam);
+
+	info(DRIVER_DESC " controlling video device %d", cam->vdev->minor);
+	return 0;
+}
+
+
+static void zr364xx_disconnect(struct usb_interface *intf)
+{
+	struct zr364xx_camera *cam = usb_get_intfdata(intf);
+	usb_set_intfdata(intf, NULL);
+	dev_set_drvdata(&intf->dev, NULL);
+	info(DRIVER_DESC " webcam unplugged");
+	if (cam->vdev)
+		video_unregister_device(cam->vdev);
+	cam->vdev = NULL;
+	kfree(cam->buffer);
+	if (cam->framebuf)
+		vfree(cam->framebuf);
+	kfree(cam);
+}
+
+
+
+/**********************/
+/* Module integration */
+/**********************/
+
+static struct usb_driver zr364xx_driver = {
+	.name = "zr364xx",
+	.probe = zr364xx_probe,
+	.disconnect = zr364xx_disconnect,
+	.id_table = device_table
+};
+
+
+static int __init zr364xx_init(void)
+{
+	int retval;
+	retval = usb_register(&zr364xx_driver) < 0;
+	if (retval)
+		info("usb_register failed!");
+	else
+		info(DRIVER_DESC " module loaded");
+	return retval;
+}
+
+
+static void __exit zr364xx_exit(void)
+{
+	info(DRIVER_DESC " module unloaded");
+	usb_deregister(&zr364xx_driver);
+}
+
+
+module_init(zr364xx_init);
+module_exit(zr364xx_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 083acfd..97471af 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1531,6 +1531,7 @@ mpt_resume(struct pci_dev *pdev)
 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
 	u32 device_state = pdev->current_state;
 	int recovery_state;
+	int err;
 
 	printk(MYIOC_s_INFO_FMT
 	"pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
@@ -1538,7 +1539,9 @@ mpt_resume(struct pci_dev *pdev)
 
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev);
-	pci_enable_device(pdev);
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
 
 	/* enable interrupts */
 	CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
@@ -4739,12 +4742,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE
 }
 
 /**
- * mpt_inactive_raid_list_free
- *
- * This clears this link list.
- *
- * @ioc - pointer to per adapter structure
- *
+ * mpt_inactive_raid_list_free - This clears this link list.
+ * @ioc : pointer to per adapter structure
  **/
 static void
 mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
@@ -4764,15 +4763,11 @@ mpt_inactive_raid_list_free(MPT_ADAPTER 
 }
 
 /**
- * mpt_inactive_raid_volumes
- *
- * This sets up link list of phy_disk_nums for devices belonging in an inactive volume
- *
- * @ioc - pointer to per adapter structure
- * @channel - volume channel
- * @id - volume target id
- *
+ * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
  *
+ * @ioc : pointer to per adapter structure
+ * @channel : volume channel
+ * @id : volume target id
  **/
 static void
 mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
@@ -6663,7 +6658,7 @@ #ifdef MPT_DEBUG_REPLY
 /**
  *	mpt_iocstatus_info_config - IOCSTATUS information for config pages
  *	@ioc: Pointer to MPT_ADAPTER structure
- *	ioc_status: U32 IOCStatus word from IOC
+ *	@ioc_status: U32 IOCStatus word from IOC
  *	@mf: Pointer to MPT request frame
  *
  *	Refer to lsi/mpi.h.
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index e3a3927..d25d3be 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -994,6 +994,7 @@ typedef struct _MPT_SCSI_HOST {
 	int			  scandv_wait_done;
 	long			  last_queue_full;
 	u16			  tm_iocstatus;
+	u16			  spi_pending;
 	struct list_head	  target_reset_list;
 } MPT_SCSI_HOST;
 
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index b691292..7dd34bd 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -714,6 +714,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
 	LANSendRequest_t *pSendReq;
 	SGETransaction32_t *pTrans;
 	SGESimple64_t *pSimple;
+	const unsigned char *mac;
 	dma_addr_t dma;
 	unsigned long flags;
 	int ctx;
@@ -753,7 +754,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
 	/* Set the mac.raw pointer, since this apparently isn't getting
 	 * done before we get the skb. Pull the data pointer past the mac data.
 	 */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, 12);
 
         dma = pci_map_single(mpt_dev->pcidev, skb->data, skb->len,
@@ -784,6 +785,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, s
 //			IOC_AND_NETDEV_NAMES_s_s(dev),
 //			ctx, skb, skb->data));
 
+	mac = skb_mac_header(skb);
 #ifdef QLOGIC_NAA_WORKAROUND
 {
 	struct NAA_Hosed *nh;
@@ -793,12 +795,12 @@ #ifdef QLOGIC_NAA_WORKAROUND
 	   drops. */
 	read_lock_irq(&bad_naa_lock);
 	for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) {
-		if ((nh->ieee[0] == skb->mac.raw[0]) &&
-		    (nh->ieee[1] == skb->mac.raw[1]) &&
-		    (nh->ieee[2] == skb->mac.raw[2]) &&
-		    (nh->ieee[3] == skb->mac.raw[3]) &&
-		    (nh->ieee[4] == skb->mac.raw[4]) &&
-		    (nh->ieee[5] == skb->mac.raw[5])) {
+		if ((nh->ieee[0] == mac[0]) &&
+		    (nh->ieee[1] == mac[1]) &&
+		    (nh->ieee[2] == mac[2]) &&
+		    (nh->ieee[3] == mac[3]) &&
+		    (nh->ieee[4] == mac[4]) &&
+		    (nh->ieee[5] == mac[5])) {
 			cur_naa = nh->NAA;
 			dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value "
 				  "= %04x.\n", cur_naa));
@@ -810,12 +812,12 @@ #ifdef QLOGIC_NAA_WORKAROUND
 #endif
 
 	pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa         << 16) |
-						    (skb->mac.raw[0] <<  8) |
-						    (skb->mac.raw[1] <<  0));
-	pTrans->TransactionDetails[1] = cpu_to_le32((skb->mac.raw[2] << 24) |
-						    (skb->mac.raw[3] << 16) |
-						    (skb->mac.raw[4] <<  8) |
-						    (skb->mac.raw[5] <<  0));
+						    (mac[0] <<  8) |
+						    (mac[1] <<  0));
+	pTrans->TransactionDetails[1] = cpu_to_le32((mac[2] << 24) |
+						    (mac[3] << 16) |
+						    (mac[4] <<  8) |
+						    (mac[5] <<  0));
 
 	pSimple = (SGESimple64_t *) &pTrans->TransactionDetails[2];
 
@@ -930,7 +932,7 @@ mpt_lan_receive_post_turbo(struct net_de
 		pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
 					    priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
 
-		memcpy(skb_put(skb, len), old_skb->data, len);
+		skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
 
 		pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma,
 					       priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE);
@@ -1091,7 +1093,7 @@ mpt_lan_receive_post_reply(struct net_de
 						    priv->RcvCtl[ctx].dma,
 						    priv->RcvCtl[ctx].len,
 						    PCI_DMA_FROMDEVICE);
-			memcpy(skb_put(skb, l), old_skb->data, l);
+			skb_copy_from_linear_data(old_skb, skb_put(skb, l), l);
 
 			pci_dma_sync_single_for_device(mpt_dev->pcidev,
 						       priv->RcvCtl[ctx].dma,
@@ -1120,7 +1122,7 @@ mpt_lan_receive_post_reply(struct net_de
 					    priv->RcvCtl[ctx].len,
 					    PCI_DMA_FROMDEVICE);
 
-		memcpy(skb_put(skb, len), old_skb->data, len);
+		skb_copy_from_linear_data(old_skb, skb_put(skb, len), len);
 
 		pci_dma_sync_single_for_device(mpt_dev->pcidev,
 					       priv->RcvCtl[ctx].dma,
@@ -1549,7 +1551,7 @@ mpt_lan_type_trans(struct sk_buff *skb, 
 	struct mpt_lan_ohdr *fch = (struct mpt_lan_ohdr *)skb->data;
 	struct fcllc *fcllc;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, sizeof(struct mpt_lan_ohdr));
 
 	if (fch->dtype == htons(0xffff)) {
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 2a3e9e6..fa0f776 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -819,10 +819,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_F
 			sc->resid=0;
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
-			if (scsi_status == MPI_SCSI_STATUS_BUSY)
-				sc->result = (DID_BUS_BUSY << 16) | scsi_status;
-			else
-				sc->result = (DID_OK << 16) | scsi_status;
+			sc->result = (DID_OK << 16) | scsi_status;
 			if (scsi_state == 0) {
 				;
 			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -1188,20 +1185,7 @@ mptscsih_suspend(struct pci_dev *pdev, p
 int
 mptscsih_resume(struct pci_dev *pdev)
 {
-	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
-	struct Scsi_Host 	*host = ioc->sh;
-	MPT_SCSI_HOST		*hd;
-
-	mpt_resume(pdev);
-
-	if(!host)
-		return 0;
-
-	hd = (MPT_SCSI_HOST *)host->hostdata;
-	if(!hd)
-		return 0;
-
-	return 0;
+	return mpt_resume(pdev);
 }
 
 #endif
@@ -1537,21 +1521,23 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *i
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptscsih_TMHandler - Generic handler for SCSI Task Management.
- *	Fall through to mpt_HardResetHandler if: not operational, too many
- *	failed TM requests or handshake failure.
- *
- *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@hd: Pointer to MPT SCSI HOST structure
  *	@type: Task Management type
+ *	@channel: channel number for task management
  *	@id: Logical Target ID for reset (if appropriate)
  *	@lun: Logical Unit for reset (if appropriate)
  *	@ctx2abort: Context for the task to be aborted (if appropriate)
+ *	@timeout: timeout for task management control
+ *
+ *	Fall through to mpt_HardResetHandler if: not operational, too many
+ *	failed TM requests or handshake failure.
  *
  *	Remark: Currently invoked from a non-interrupt thread (_bh).
  *
  *	Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
  *	will be active.
  *
- *	Returns 0 for SUCCESS, or FAILED.
+ *	Returns 0 for SUCCESS, or %FAILED.
  **/
 int
 mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
@@ -1650,9 +1636,11 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8
  *	mptscsih_IssueTaskMgmt - Generic send Task Management function.
  *	@hd: Pointer to MPT_SCSI_HOST structure
  *	@type: Task Management type
+ *	@channel: channel number for task management
  *	@id: Logical Target ID for reset (if appropriate)
  *	@lun: Logical Unit for reset (if appropriate)
  *	@ctx2abort: Context for the task to be aborted (if appropriate)
+ *	@timeout: timeout for task management control
  *
  *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
  *	or a non-interrupt thread.  In the former, must not call schedule().
@@ -2022,6 +2010,7 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST *
 /**
  *	mptscsih_tm_wait_for_completion - wait for completion of TM task
  *	@hd: Pointer to MPT host structure.
+ *	@timeout: timeout value
  *
  *	Returns {SUCCESS,FAILED}.
  */
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 85f21b5..d75f7ff 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -96,14 +96,13 @@ static int	mptspiTaskCtx = -1;
 static int	mptspiInternalCtx = -1; /* Used only for internal commands */
 
 /**
- * 	mptspi_setTargetNegoParms  - Update the target negotiation
- *	parameters based on the the Inquiry data, adapter capabilities,
- *	and NVRAM settings
- *
+ * 	mptspi_setTargetNegoParms  - Update the target negotiation parameters
  *	@hd: Pointer to a SCSI Host Structure
- *	@vtarget: per target private data
+ *	@target: per target private data
  *	@sdev: SCSI device
  *
+ * 	Update the target negotiation parameters based on the the Inquiry
+ *	data, adapter capabilities, and NVRAM settings.
  **/
 static void
 mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
@@ -234,7 +233,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST 
 /**
  * 	mptspi_writeIOCPage4  - write IOC Page 4
  *	@hd: Pointer to a SCSI Host Structure
- *	@channel:
+ *	@channel: channel number
  *	@id: write IOC Page4 for this ID & Bus
  *
  *	Return: -EAGAIN if unable to obtain a Message Frame
@@ -446,7 +445,7 @@ static int mptspi_target_alloc(struct sc
 	return 0;
 }
 
-void
+static void
 mptspi_target_destroy(struct scsi_target *starget)
 {
 	if (starget->hostdata)
@@ -677,7 +676,9 @@ static void mptspi_dv_device(struct _MPT
 		return;
 	}
 
+	hd->spi_pending |= (1 << sdev->id);
 	spi_dv_device(sdev);
+	hd->spi_pending &= ~(1 << sdev->id);
 
 	if (sdev->channel == 1 &&
 	    mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
@@ -1203,11 +1204,27 @@ mptspi_dv_renegotiate_work(struct work_s
 		container_of(work, struct work_queue_wrapper, work);
 	struct _MPT_SCSI_HOST *hd = wqw->hd;
 	struct scsi_device *sdev;
+	struct scsi_target *starget;
+	struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
+	u32 nego;
 
 	kfree(wqw);
 
-	shost_for_each_device(sdev, hd->ioc->sh)
-		mptspi_dv_device(hd, sdev);
+	if (hd->spi_pending) {
+		shost_for_each_device(sdev, hd->ioc->sh) {
+			if  (hd->spi_pending & (1 << sdev->id))
+				continue;
+			starget = scsi_target(sdev);
+			nego = mptspi_getRP(starget);
+			pg1.RequestedParameters = cpu_to_le32(nego);
+			pg1.Reserved = 0;
+			pg1.Configuration = 0;
+			mptspi_write_spi_device_pg1(starget, &pg1);
+		}
+	} else {
+		shost_for_each_device(sdev, hd->ioc->sh)
+			mptspi_dv_device(hd, sdev);
+	}
 }
 
 static void
@@ -1453,6 +1470,7 @@ mptspi_probe(struct pci_dev *pdev, const
 	init_waitqueue_head(&hd->scandv_waitq);
 	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
+	hd->spi_pending = 0;
 
 	/* Some versions of the firmware don't support page 0; without
 	 * that we can't get the parameters */
diff --git a/drivers/message/i2o/i2o_lan.h b/drivers/message/i2o/i2o_lan.h
deleted file mode 100644
index 6502b81..0000000
--- a/drivers/message/i2o/i2o_lan.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *   	i2o_lan.h			I2O LAN Class definitions
- *
- *      I2O LAN CLASS OSM       	May 26th 2000
- *
- *      (C) Copyright 1999, 2000	University of Helsinki,
- *					Department of Computer Science
- *
- *      This code is still under development / test.
- *
- *	Author:		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- *			Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- *			Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
- */
-
-#ifndef _I2O_LAN_H
-#define _I2O_LAN_H
-
-/* Default values for tunable parameters first */
-
-#define I2O_LAN_MAX_BUCKETS_OUT 96
-#define I2O_LAN_BUCKET_THRESH	18	/* 9 buckets in one message */
-#define I2O_LAN_RX_COPYBREAK	200
-#define I2O_LAN_TX_TIMEOUT 	(1*HZ)
-#define I2O_LAN_TX_BATCH_MODE	2	/* 2=automatic, 1=on, 0=off */
-#define I2O_LAN_EVENT_MASK	0	/* 0=None, 0xFFC00002=All */
-
-/* LAN types */
-#define I2O_LAN_ETHERNET	0x0030
-#define I2O_LAN_100VG		0x0040
-#define I2O_LAN_TR		0x0050
-#define I2O_LAN_FDDI		0x0060
-#define I2O_LAN_FIBRE_CHANNEL	0x0070
-#define I2O_LAN_UNKNOWN		0x00000000
-
-/* Connector types */
-
-/* Ethernet */
-#define I2O_LAN_AUI		(I2O_LAN_ETHERNET << 4) + 0x00000001
-#define I2O_LAN_10BASE5		(I2O_LAN_ETHERNET << 4) + 0x00000002
-#define I2O_LAN_FIORL		(I2O_LAN_ETHERNET << 4) + 0x00000003
-#define I2O_LAN_10BASE2		(I2O_LAN_ETHERNET << 4) + 0x00000004
-#define I2O_LAN_10BROAD36	(I2O_LAN_ETHERNET << 4) + 0x00000005
-#define I2O_LAN_10BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000006
-#define I2O_LAN_10BASE_FP	(I2O_LAN_ETHERNET << 4) + 0x00000007
-#define I2O_LAN_10BASE_FB	(I2O_LAN_ETHERNET << 4) + 0x00000008
-#define I2O_LAN_10BASE_FL	(I2O_LAN_ETHERNET << 4) + 0x00000009
-#define I2O_LAN_100BASE_TX	(I2O_LAN_ETHERNET << 4) + 0x0000000A
-#define I2O_LAN_100BASE_FX	(I2O_LAN_ETHERNET << 4) + 0x0000000B
-#define I2O_LAN_100BASE_T4	(I2O_LAN_ETHERNET << 4) + 0x0000000C
-#define I2O_LAN_1000BASE_SX	(I2O_LAN_ETHERNET << 4) + 0x0000000D
-#define I2O_LAN_1000BASE_LX	(I2O_LAN_ETHERNET << 4) + 0x0000000E
-#define I2O_LAN_1000BASE_CX	(I2O_LAN_ETHERNET << 4) + 0x0000000F
-#define I2O_LAN_1000BASE_T	(I2O_LAN_ETHERNET << 4) + 0x00000010
-
-/* AnyLAN */
-#define I2O_LAN_100VG_ETHERNET	(I2O_LAN_100VG << 4) + 0x00000001
-#define I2O_LAN_100VG_TR	(I2O_LAN_100VG << 4) + 0x00000002
-
-/* Token Ring */
-#define I2O_LAN_4MBIT		(I2O_LAN_TR << 4) + 0x00000001
-#define I2O_LAN_16MBIT		(I2O_LAN_TR << 4) + 0x00000002
-
-/* FDDI */
-#define I2O_LAN_125MBAUD	(I2O_LAN_FDDI << 4) + 0x00000001
-
-/* Fibre Channel */
-#define I2O_LAN_POINT_POINT	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001
-#define I2O_LAN_ARB_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002
-#define I2O_LAN_PUBLIC_LOOP	(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003
-#define I2O_LAN_FABRIC		(I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004
-
-#define I2O_LAN_EMULATION	0x00000F00
-#define I2O_LAN_OTHER		0x00000F01
-#define I2O_LAN_DEFAULT		0xFFFFFFFF
-
-/* LAN class functions */
-
-#define LAN_PACKET_SEND		0x3B
-#define LAN_SDU_SEND		0x3D
-#define LAN_RECEIVE_POST	0x3E
-#define LAN_RESET		0x35
-#define LAN_SUSPEND		0x37
-
-/* LAN DetailedStatusCode defines */
-#define I2O_LAN_DSC_SUCCESS			0x00
-#define I2O_LAN_DSC_DEVICE_FAILURE		0x01
-#define I2O_LAN_DSC_DESTINATION_NOT_FOUND	0x02
-#define	I2O_LAN_DSC_TRANSMIT_ERROR		0x03
-#define I2O_LAN_DSC_TRANSMIT_ABORTED		0x04
-#define I2O_LAN_DSC_RECEIVE_ERROR		0x05
-#define I2O_LAN_DSC_RECEIVE_ABORTED		0x06
-#define I2O_LAN_DSC_DMA_ERROR			0x07
-#define I2O_LAN_DSC_BAD_PACKET_DETECTED		0x08
-#define I2O_LAN_DSC_OUT_OF_MEMORY		0x09
-#define I2O_LAN_DSC_BUCKET_OVERRUN		0x0A
-#define I2O_LAN_DSC_IOP_INTERNAL_ERROR		0x0B
-#define I2O_LAN_DSC_CANCELED			0x0C
-#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT	0x0D
-#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED	0x0E
-#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED	0x0F
-#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED	0x10
-#define I2O_LAN_DSC_SUSPENDED			0x11
-
-struct i2o_packet_info {
-	u32 offset:24;
-	u32 flags:8;
-	u32 len:24;
-	u32 status:8;
-};
-
-struct i2o_bucket_descriptor {
-	u32 context;		/* FIXME: 64bit support */
-	struct i2o_packet_info packet_info[1];
-};
-
-/* Event Indicator Mask Flags for LAN OSM */
-
-#define I2O_LAN_EVT_LINK_DOWN		0x01
-#define I2O_LAN_EVT_LINK_UP		0x02
-#define I2O_LAN_EVT_MEDIA_CHANGE 	0x04
-
-#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
-
-struct i2o_lan_local {
-	u8 unit;
-	struct i2o_device *i2o_dev;
-
-	struct fddi_statistics stats;	/* see also struct net_device_stats */
-	unsigned short (*type_trans) (struct sk_buff *, struct net_device *);
-	atomic_t buckets_out;	/* nbr of unused buckets on DDM */
-	atomic_t tx_out;	/* outstanding TXes */
-	u8 tx_count;		/* packets in one TX message frame */
-	u16 tx_max_out;		/* DDM's Tx queue len */
-	u8 sgl_max;		/* max SGLs in one message frame */
-	u32 m;			/* IOP address of the batch msg frame */
-
-	struct work_struct i2o_batch_send_task;
-	int send_active;
-	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
-	int i2o_fbl_tail;
-	spinlock_t fbl_lock;
-
-	spinlock_t tx_lock;
-
-	u32 max_size_mc_table;	/* max number of multicast addresses */
-
-	/* LAN OSM configurable parameters are here: */
-
-	u16 max_buckets_out;	/* max nbr of buckets to send to DDM */
-	u16 bucket_thresh;	/* send more when this many used */
-	u16 rx_copybreak;
-
-	u8 tx_batch_mode;	/* Set when using batch mode sends */
-	u32 i2o_event_mask;	/* To turn on interesting event flags */
-};
-
-#endif				/* _I2O_LAN_H */
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index ce1a481..cb8c264 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -21,7 +21,6 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 80b199f..877e790 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -25,6 +25,15 @@ config IBM_ASM
 	  information on the specific driver level and support statement
 	  for your IBM server.
 
+config PHANTOM
+	tristate "Sensable PHANToM"
+	depends on PCI
+	help
+	  Say Y here if you want to build a driver for Sensable PHANToM device.
+
+	  If you choose to build module, its name will be phantom. If unsure,
+	  say N here.
+
 
 	  If unsure, say N.
 
@@ -112,14 +121,79 @@ config SONY_LAPTOP
 	depends on X86 && ACPI
 	select BACKLIGHT_CLASS_DEVICE
 	  ---help---
-	  This mini-driver drives the SNC device present in the ACPI BIOS of
-	  the Sony Vaio laptops.
+	  This mini-driver drives the SNC and SPIC devices present in the ACPI
+	  BIOS of the Sony Vaio laptops.
 
-	  It gives access to some extra laptop functionalities. In its current
-	  form, this driver let the user set or query the screen brightness
-	  through the backlight subsystem and remove/apply power to some
+	  It gives access to some extra laptop functionalities like Bluetooth,
+	  screen brightness control, Fn keys and allows powering on/off some
 	  devices.
 
 	  Read <file:Documentation/sony-laptop.txt> for more information.
 
+config SONY_LAPTOP_OLD
+	bool "Sonypi compatibility"
+	depends on SONY_LAPTOP
+	  ---help---
+	  Build the sonypi driver compatibility code into the sony-laptop driver.
+
+config THINKPAD_ACPI
+	tristate "ThinkPad ACPI Laptop Extras"
+	depends on X86 && ACPI
+	select BACKLIGHT_CLASS_DEVICE
+	select HWMON
+	---help---
+	  This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
+	  support for Fn-Fx key combinations, Bluetooth control, video
+	  output switching, ThinkLight control, UltraBay eject and more.
+	  For more information about this driver see 
+	  <file:Documentation/thinkpad-acpi.txt> and <http://ibm-acpi.sf.net/> .
+
+	  This driver was formely known as ibm-acpi.
+
+	  If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
+
+config THINKPAD_ACPI_DEBUG
+	bool "Verbose debug mode"
+	depends on THINKPAD_ACPI
+	default n
+	---help---
+	  Enables extra debugging information, at the expense of a slightly
+	  increase in driver size.
+
+	  If you are not sure, say N here.
+
+config THINKPAD_ACPI_DOCK
+	bool "Legacy Docking Station Support"
+	depends on THINKPAD_ACPI
+	depends on ACPI_DOCK=n
+	default n
+	---help---
+	  Allows the thinkpad_acpi driver to handle docking station events.
+	  This support was made obsolete by the generic ACPI docking station
+	  support (CONFIG_ACPI_DOCK).  It will allow locking and removing the
+	  laptop from the docking station, but will not properly connect PCI
+	  devices.
+
+	  If you are not sure, say N here.
+
+config THINKPAD_ACPI_BAY
+	bool "Legacy Removable Bay Support"
+	depends on THINKPAD_ACPI
+	default y
+	---help---
+	  Allows the thinkpad_acpi driver to handle removable bays.  It will
+	  eletrically disable the device in the bay, and also generate
+	  notifications when the bay lever is ejected or inserted.
+
+	  If you are not sure, say Y here.
+
+config BLINK
+	tristate "Keyboard blink driver"
+	help
+	  Driver that when loaded will blink the keyboard LEDs continuously.
+	  This is useful for debugging and for kernels that cannot necessarily
+	  output something to the screen like kexec kernels to give the user
+	  a visual indication that the kernel is doing something.
+
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7793ccd..5b6d46d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,8 +7,11 @@ obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
+obj-$(CONFIG_BLINK)		+= blink.o
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
+obj-$(CONFIG_PHANTOM)		+= phantom.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
+obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 4b23212..65c32a9 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -3,7 +3,7 @@
  *
  *
  *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *  Copyright (C) 2006 Corentin Chary
+ *  Copyright (C) 2006-2007 Corentin Chary
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@ #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 
-#define ASUS_LAPTOP_VERSION "0.40"
+#define ASUS_LAPTOP_VERSION "0.41"
 
 #define ASUS_HOTK_NAME          "Asus Laptop Support"
 #define ASUS_HOTK_CLASS         "hotkey"
@@ -81,7 +81,8 @@ #define MLED_ON     0x04	//mail LED
 #define TLED_ON     0x08	//touchpad LED
 #define RLED_ON     0x10	//Record LED
 #define PLED_ON     0x20	//Phone LED
-#define LCD_ON      0x40	//LCD backlight
+#define GLED_ON     0x40	//Gaming LED
+#define LCD_ON      0x80	//LCD backlight
 
 #define ASUS_LOG    ASUS_HOTK_FILE ": "
 #define ASUS_ERR    KERN_ERR    ASUS_LOG
@@ -94,6 +95,19 @@ MODULE_AUTHOR("Julien Lerouge, Karol Koz
 MODULE_DESCRIPTION(ASUS_HOTK_NAME);
 MODULE_LICENSE("GPL");
 
+/* WAPF defines the behavior of the Fn+Fx wlan key
+ * The significance of values is yet to be found, but
+ * most of the time:
+ * 0x0 will do nothing
+ * 0x1 will allow to control the device with Fn+Fx key.
+ * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
+ * 0x5 like 0x1 or 0x4
+ * So, if something doesn't work as you want, just try other values =)
+ */
+static uint wapf = 1;
+module_param(wapf, uint, 0644);
+MODULE_PARM_DESC(wapf, "WAPF value");
+
 #define ASUS_HANDLE(object, paths...)					\
 	static acpi_handle  object##_handle = NULL;			\
 	static char *object##_paths[] = { paths }
@@ -103,6 +117,7 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "
 ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
 ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED");	/* W1JC */
 ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED");	/* A7J */
+ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED");	/* G1, G2 (probably) */
 
 /* LEDD */
 ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
@@ -221,6 +236,7 @@ ASUS_LED(mled, "mail");
 ASUS_LED(tled, "touchpad");
 ASUS_LED(rled, "record");
 ASUS_LED(pled, "phone");
+ASUS_LED(gled, "gaming");
 
 /*
  * This function evaluates an ACPI method, given an int as parameter, the
@@ -245,32 +261,19 @@ static int write_acpi_int(acpi_handle ha
 	return (status == AE_OK);
 }
 
-static int read_acpi_int(acpi_handle handle, const char *method, int *val,
-			 struct acpi_object_list *params)
-{
-	struct acpi_buffer output;
-	union acpi_object out_obj;
-	acpi_status status;
-
-	output.length = sizeof(out_obj);
-	output.pointer = &out_obj;
-
-	status = acpi_evaluate_object(handle, (char *)method, params, &output);
-	*val = out_obj.integer.value;
-	return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
 static int read_wireless_status(int mask)
 {
-	int status;
+	ulong status;
+	acpi_status rv = AE_OK;
 
 	if (!wireless_status_handle)
 		return (hotk->status & mask) ? 1 : 0;
 
-	if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
-		return (status & mask) ? 1 : 0;
-	} else
+	rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
+	if (ACPI_FAILURE(rv))
 		printk(ASUS_WARNING "Error reading Wireless status\n");
+	else
+		return (status & mask) ? 1 : 0;
 
 	return (hotk->status & mask) ? 1 : 0;
 }
@@ -285,19 +288,28 @@ static int read_status(int mask)
 	return (hotk->status & mask) ? 1 : 0;
 }
 
-static void write_status(acpi_handle handle, int out, int mask, int invert)
+static void write_status(acpi_handle handle, int out, int mask)
 {
 	hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
 
-	if (invert)		/* invert target value */
+	switch (mask) {
+	case MLED_ON:
 		out = !out & 0x1;
+		break;
+	case GLED_ON:
+		out = (out & 0x1) + 1;
+		break;
+	default:
+		out &= 0x1;
+		break;
+	}
 
 	if (handle && !write_acpi_int(handle, NULL, out, NULL))
-		printk(ASUS_WARNING " write failed\n");
+		printk(ASUS_WARNING " write failed %x\n", mask);
 }
 
 /* /sys/class/led handlers */
-#define ASUS_LED_HANDLER(object, mask, invert)				\
+#define ASUS_LED_HANDLER(object, mask)					\
 	static void object##_led_set(struct led_classdev *led_cdev,	\
 				     enum led_brightness value)		\
 	{								\
@@ -307,13 +319,14 @@ #define ASUS_LED_HANDLER(object, mask, i
 	static void object##_led_update(struct work_struct *ignored)	\
 	{								\
 		int value = object##_led_wk;				\
-		write_status(object##_set_handle, value, (mask), (invert)); \
+		write_status(object##_set_handle, value, (mask));	\
 	}
 
-ASUS_LED_HANDLER(mled, MLED_ON, 1);
-ASUS_LED_HANDLER(pled, PLED_ON, 0);
-ASUS_LED_HANDLER(rled, RLED_ON, 0);
-ASUS_LED_HANDLER(tled, TLED_ON, 0);
+ASUS_LED_HANDLER(mled, MLED_ON);
+ASUS_LED_HANDLER(pled, PLED_ON);
+ASUS_LED_HANDLER(rled, RLED_ON);
+ASUS_LED_HANDLER(tled, TLED_ON);
+ASUS_LED_HANDLER(gled, GLED_ON);
 
 static int get_lcd_state(void)
 {
@@ -338,7 +351,7 @@ static int set_lcd_state(int value)
 			printk(ASUS_WARNING "Error switching LCD\n");
 	}
 
-	write_status(NULL, lcd, LCD_ON, 0);
+	write_status(NULL, lcd, LCD_ON);
 	return 0;
 }
 
@@ -354,9 +367,11 @@ static void lcd_blank(int blank)
 
 static int read_brightness(struct backlight_device *bd)
 {
-	int value;
+	ulong value;
+	acpi_status rv = AE_OK;
 
-	if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+	rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
+	if (ACPI_FAILURE(rv))
 		printk(ASUS_WARNING "Error reading brightness\n");
 
 	return value;
@@ -403,8 +418,10 @@ static ssize_t show_infos(struct device 
 			  struct device_attribute *attr, char *page)
 {
 	int len = 0;
-	int temp;
+	ulong temp;
 	char buf[16];		//enough for all info
+	acpi_status rv = AE_OK;
+
 	/*
 	 * We use the easy way, we don't care of off and count, so we don't set eof
 	 * to 1
@@ -418,9 +435,10 @@ static ssize_t show_infos(struct device 
 	 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
 	 * The significance of others is yet to be found.
 	 */
-	if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
-		len +=
-		    sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
+	rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
+	if (!ACPI_FAILURE(rv))
+		len += sprintf(page + len, "SFUN value         : 0x%04x\n",
+			       (uint) temp);
 	/*
 	 * Another value for userspace: the ASYM method returns 0x02 for
 	 * battery low and 0x04 for battery critical, its readings tend to be
@@ -428,9 +446,10 @@ static ssize_t show_infos(struct device 
 	 * Note: since not all the laptops provide this method, errors are
 	 * silently ignored.
 	 */
-	if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
-		len +=
-		    sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
+	rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
+	if (!ACPI_FAILURE(rv))
+		len += sprintf(page + len, "ASYM value         : 0x%04x\n",
+			       (uint) temp);
 	if (asus_info) {
 		snprintf(buf, 16, "%d", asus_info->length);
 		len += sprintf(page + len, "DSDT length        : %s\n", buf);
@@ -465,7 +484,7 @@ static int parse_arg(const char *buf, un
 }
 
 static ssize_t store_status(const char *buf, size_t count,
-			    acpi_handle handle, int mask, int invert)
+			    acpi_handle handle, int mask)
 {
 	int rv, value;
 	int out = 0;
@@ -474,7 +493,7 @@ static ssize_t store_status(const char *
 	if (rv > 0)
 		out = value ? 1 : 0;
 
-	write_status(handle, out, mask, invert);
+	write_status(handle, out, mask);
 
 	return rv;
 }
@@ -515,7 +534,7 @@ static ssize_t show_wlan(struct device *
 static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
-	return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+	return store_status(buf, count, wl_switch_handle, WL_ON);
 }
 
 /*
@@ -531,7 +550,7 @@ static ssize_t store_bluetooth(struct de
 			       struct device_attribute *attr, const char *buf,
 			       size_t count)
 {
-	return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+	return store_status(buf, count, bt_switch_handle, BT_ON);
 }
 
 /*
@@ -547,12 +566,15 @@ static void set_display(int value)
 
 static int read_display(void)
 {
-	int value = 0;
+	ulong value = 0;
+	acpi_status rv = AE_OK;
 
 	/* In most of the case, we know how to set the display, but sometime
 	   we can't read it */
 	if (display_get_handle) {
-		if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+		rv = acpi_evaluate_integer(display_get_handle, NULL,
+					   NULL, &value);
+		if (ACPI_FAILURE(rv))
 			printk(ASUS_WARNING "Error reading display status\n");
 	}
 
@@ -656,10 +678,10 @@ static void asus_hotk_notify(acpi_handle
 	 * switched
 	 */
 	if (event == ATKD_LCD_ON) {
-		write_status(NULL, 1, LCD_ON, 0);
+		write_status(NULL, 1, LCD_ON);
 		lcd_blank(FB_BLANK_UNBLANK);
 	} else if (event == ATKD_LCD_OFF) {
-		write_status(NULL, 0, LCD_ON, 0);
+		write_status(NULL, 0, LCD_ON);
 		lcd_blank(FB_BLANK_POWERDOWN);
 	}
 
@@ -771,7 +793,7 @@ static int asus_hotk_get_info(void)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *model = NULL;
-	int bsts_result, hwrs_result;
+	ulong bsts_result, hwrs_result;
 	char *string = NULL;
 	acpi_status status;
 
@@ -794,11 +816,16 @@ static int asus_hotk_get_info(void)
 	}
 
 	/* This needs to be called for some laptops to init properly */
-	if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+	status =
+	    acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
+	if (ACPI_FAILURE(status))
 		printk(ASUS_WARNING "Error calling BSTS\n");
 	else if (bsts_result)
 		printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
-		       bsts_result);
+		       (uint) bsts_result);
+
+	/* This too ... */
+	write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
 
 	/*
 	 * Try to match the object returned by INIT to the specific model.
@@ -831,6 +858,7 @@ static int asus_hotk_get_info(void)
 	ASUS_HANDLE_INIT(tled_set);
 	ASUS_HANDLE_INIT(rled_set);
 	ASUS_HANDLE_INIT(pled_set);
+	ASUS_HANDLE_INIT(gled_set);
 
 	ASUS_HANDLE_INIT(ledd_set);
 
@@ -840,7 +868,9 @@ static int asus_hotk_get_info(void)
 	 * The significance of others is yet to be found.
 	 * If we don't find the method, we assume the device are present.
 	 */
-	if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+	status =
+	    acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
+	if (ACPI_FAILURE(status))
 		hwrs_result = WL_HWRS | BT_HWRS;
 
 	if (hwrs_result & WL_HWRS)
@@ -928,11 +958,15 @@ static int asus_hotk_add(struct acpi_dev
 	asus_hotk_found = 1;
 
 	/* WLED and BLED are on by default */
-	write_status(bt_switch_handle, 1, BT_ON, 0);
-	write_status(wl_switch_handle, 1, WL_ON, 0);
+	write_status(bt_switch_handle, 1, BT_ON);
+	write_status(wl_switch_handle, 1, WL_ON);
+
+	/* If the h/w switch is off, we need to check the real status */
+	write_status(NULL, read_status(BT_ON), BT_ON);
+	write_status(NULL, read_status(WL_ON), WL_ON);
 
 	/* LCD Backlight is on by default */
-	write_status(NULL, 1, LCD_ON, 0);
+	write_status(NULL, 1, LCD_ON);
 
 	/* LED display is off by default */
 	hotk->ledd_status = 0xFFF;
@@ -991,6 +1025,7 @@ static void asus_led_exit(void)
 	ASUS_LED_UNREGISTER(tled);
 	ASUS_LED_UNREGISTER(pled);
 	ASUS_LED_UNREGISTER(rled);
+	ASUS_LED_UNREGISTER(gled);
 
 	destroy_workqueue(led_workqueue);
 }
@@ -1062,6 +1097,10 @@ static int asus_led_init(struct device *
 	if (rv)
 		return rv;
 
+	rv = ASUS_LED_REGISTER(gled, dev);
+	if (rv)
+		return rv;
+
 	led_workqueue = create_singlethread_workqueue("led_workqueue");
 	if (!led_workqueue)
 		return -ENOMEM;
diff --git a/drivers/misc/blink.c b/drivers/misc/blink.c
new file mode 100644
index 0000000..634431c
--- /dev/null
+++ b/drivers/misc/blink.c
@@ -0,0 +1,27 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+static void do_blink(unsigned long data);
+
+static DEFINE_TIMER(blink_timer, do_blink, 0 ,0);
+
+static void do_blink(unsigned long data)
+{
+	static long count;
+	if (panic_blink)
+		panic_blink(count++);
+	blink_timer.expires = jiffies + msecs_to_jiffies(1);
+	add_timer(&blink_timer);
+}
+
+static int blink_init(void)
+{
+	printk(KERN_INFO "Enabling keyboard blinking\n");
+	do_blink(0);
+	return 0;
+}
+
+module_init(blink_init);
+
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index ca86f11..276ba3c 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -18,7 +18,6 @@ #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
 #include <asm/uaccess.h>
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 6a51e99..60c8b26 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -18,7 +18,6 @@ #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/hdpu_features.h>
-#include <linux/pci.h>
 
 #include <linux/platform_device.h>
 
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
new file mode 100644
index 0000000..35b139b
--- /dev/null
+++ b/drivers/misc/phantom.c
@@ -0,0 +1,463 @@
+/*
+ *  Copyright (C) 2005-2007 Jiri Slaby <jirislaby@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.
+ *
+ *  You need an userspace library to cooperate with this driver. It (and other
+ *  info) may be obtained here:
+ *  http://www.fi.muni.cz/~xslaby/phantom.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/phantom.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+#define PHANTOM_VERSION		"n0.9.5"
+
+#define PHANTOM_MAX_MINORS	8
+
+#define PHN_IRQCTL		0x4c    /* irq control in caddr space */
+
+#define PHB_RUNNING		1
+
+static struct class *phantom_class;
+static int phantom_major;
+
+struct phantom_device {
+	unsigned int opened;
+	void __iomem *caddr;
+	u32 __iomem *iaddr;
+	u32 __iomem *oaddr;
+	unsigned long status;
+	atomic_t counter;
+
+	wait_queue_head_t wait;
+	struct cdev cdev;
+
+	struct mutex open_lock;
+};
+
+static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
+
+static int phantom_status(struct phantom_device *dev, unsigned long newstat)
+{
+	pr_debug("phantom_status %lx %lx\n", dev->status, newstat);
+
+	if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) {
+		atomic_set(&dev->counter, 0);
+		iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL);
+		iowrite32(0x43, dev->caddr + PHN_IRQCTL);
+	} else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING))
+		iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+	dev->status = newstat;
+
+	return 0;
+}
+
+/*
+ * File ops
+ */
+
+static int phantom_ioctl(struct inode *inode, struct file *file, u_int cmd,
+	u_long arg)
+{
+	struct phantom_device *dev = file->private_data;
+	struct phm_regs rs;
+	struct phm_reg r;
+	void __user *argp = (void __user *)arg;
+	unsigned int i;
+
+	if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
+			_IOC_NR(cmd) > PH_IOC_MAXNR)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case PHN_SET_REG:
+		if (copy_from_user(&r, argp, sizeof(r)))
+			return -EFAULT;
+
+		if (r.reg > 7)
+			return -EINVAL;
+
+		if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
+				phantom_status(dev, dev->status | PHB_RUNNING))
+			return -ENODEV;
+
+		pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
+		iowrite32(r.value, dev->iaddr + r.reg);
+
+		if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
+			phantom_status(dev, dev->status & ~PHB_RUNNING);
+		break;
+	case PHN_SET_REGS:
+		if (copy_from_user(&rs, argp, sizeof(rs)))
+			return -EFAULT;
+
+		pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
+		for (i = 0; i < min(rs.count, 8U); i++)
+			if ((1 << i) & rs.mask)
+				iowrite32(rs.values[i], dev->oaddr + i);
+		break;
+	case PHN_GET_REG:
+		if (copy_from_user(&r, argp, sizeof(r)))
+			return -EFAULT;
+
+		if (r.reg > 7)
+			return -EINVAL;
+
+		r.value = ioread32(dev->iaddr + r.reg);
+
+		if (copy_to_user(argp, &r, sizeof(r)))
+			return -EFAULT;
+		break;
+	case PHN_GET_REGS:
+		if (copy_from_user(&rs, argp, sizeof(rs)))
+			return -EFAULT;
+
+		pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
+		for (i = 0; i < min(rs.count, 8U); i++)
+			if ((1 << i) & rs.mask)
+				rs.values[i] = ioread32(dev->iaddr + i);
+
+		if (copy_to_user(argp, &rs, sizeof(rs)))
+			return -EFAULT;
+		break;
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static int phantom_open(struct inode *inode, struct file *file)
+{
+	struct phantom_device *dev = container_of(inode->i_cdev,
+			struct phantom_device, cdev);
+
+	nonseekable_open(inode, file);
+
+	if (mutex_lock_interruptible(&dev->open_lock))
+		return -ERESTARTSYS;
+
+	if (dev->opened) {
+		mutex_unlock(&dev->open_lock);
+		return -EINVAL;
+	}
+
+	file->private_data = dev;
+
+	dev->opened++;
+	mutex_unlock(&dev->open_lock);
+
+	return 0;
+}
+
+static int phantom_release(struct inode *inode, struct file *file)
+{
+	struct phantom_device *dev = file->private_data;
+
+	mutex_lock(&dev->open_lock);
+
+	dev->opened = 0;
+	phantom_status(dev, dev->status & ~PHB_RUNNING);
+
+	mutex_unlock(&dev->open_lock);
+
+	return 0;
+}
+
+static unsigned int phantom_poll(struct file *file, poll_table *wait)
+{
+	struct phantom_device *dev = file->private_data;
+	unsigned int mask = 0;
+
+	pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
+	poll_wait(file, &dev->wait, wait);
+	if (atomic_read(&dev->counter)) {
+		mask = POLLIN | POLLRDNORM;
+		atomic_dec(&dev->counter);
+	} else if ((dev->status & PHB_RUNNING) == 0)
+		mask = POLLIN | POLLRDNORM | POLLERR;
+	pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
+
+	return mask;
+}
+
+static struct file_operations phantom_file_ops = {
+	.open = phantom_open,
+	.release = phantom_release,
+	.ioctl = phantom_ioctl,
+	.poll = phantom_poll,
+};
+
+static irqreturn_t phantom_isr(int irq, void *data)
+{
+	struct phantom_device *dev = data;
+
+	if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ))
+		return IRQ_NONE;
+
+	iowrite32(0, dev->iaddr);
+	iowrite32(0xc0, dev->iaddr);
+
+	atomic_inc(&dev->counter);
+	wake_up_interruptible(&dev->wait);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Init and deinit driver
+ */
+
+static unsigned int __devinit phantom_get_free(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < PHANTOM_MAX_MINORS; i++)
+		if (phantom_devices[i] == 0)
+			break;
+
+	return i;
+}
+
+static int __devinit phantom_probe(struct pci_dev *pdev,
+	const struct pci_device_id *pci_id)
+{
+	struct phantom_device *pht;
+	unsigned int minor;
+	int retval;
+
+	retval = pci_enable_device(pdev);
+	if (retval)
+		goto err;
+
+	minor = phantom_get_free();
+	if (minor == PHANTOM_MAX_MINORS) {
+		dev_err(&pdev->dev, "too many devices found!\n");
+		retval = -EIO;
+		goto err_dis;
+	}
+
+	phantom_devices[minor] = 1;
+
+	retval = pci_request_regions(pdev, "phantom");
+	if (retval)
+		goto err_null;
+
+	retval = -ENOMEM;
+	pht = kzalloc(sizeof(*pht), GFP_KERNEL);
+	if (pht == NULL) {
+		dev_err(&pdev->dev, "unable to allocate device\n");
+		goto err_reg;
+	}
+
+	pht->caddr = pci_iomap(pdev, 0, 0);
+	if (pht->caddr == NULL) {
+		dev_err(&pdev->dev, "can't remap conf space\n");
+		goto err_fr;
+	}
+	pht->iaddr = pci_iomap(pdev, 2, 0);
+	if (pht->iaddr == NULL) {
+		dev_err(&pdev->dev, "can't remap input space\n");
+		goto err_unmc;
+	}
+	pht->oaddr = pci_iomap(pdev, 3, 0);
+	if (pht->oaddr == NULL) {
+		dev_err(&pdev->dev, "can't remap output space\n");
+		goto err_unmi;
+	}
+
+	mutex_init(&pht->open_lock);
+	init_waitqueue_head(&pht->wait);
+	cdev_init(&pht->cdev, &phantom_file_ops);
+	pht->cdev.owner = THIS_MODULE;
+
+	iowrite32(0, pht->caddr + PHN_IRQCTL);
+	retval = request_irq(pdev->irq, phantom_isr,
+			IRQF_SHARED | IRQF_DISABLED, "phantom", pht);
+	if (retval) {
+		dev_err(&pdev->dev, "can't establish ISR\n");
+		goto err_unmo;
+	}
+
+	retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1);
+	if (retval) {
+		dev_err(&pdev->dev, "chardev registration failed\n");
+		goto err_irq;
+	}
+
+	if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major,
+			minor), "phantom%u", minor)))
+		dev_err(&pdev->dev, "can't create device\n");
+
+	pci_set_drvdata(pdev, pht);
+
+	return 0;
+err_irq:
+	free_irq(pdev->irq, pht);
+err_unmo:
+	pci_iounmap(pdev, pht->oaddr);
+err_unmi:
+	pci_iounmap(pdev, pht->iaddr);
+err_unmc:
+	pci_iounmap(pdev, pht->caddr);
+err_fr:
+	kfree(pht);
+err_reg:
+	pci_release_regions(pdev);
+err_null:
+	phantom_devices[minor] = 0;
+err_dis:
+	pci_disable_device(pdev);
+err:
+	return retval;
+}
+
+static void __devexit phantom_remove(struct pci_dev *pdev)
+{
+	struct phantom_device *pht = pci_get_drvdata(pdev);
+	unsigned int minor = MINOR(pht->cdev.dev);
+
+	device_destroy(phantom_class, MKDEV(phantom_major, minor));
+
+	cdev_del(&pht->cdev);
+
+	iowrite32(0, pht->caddr + PHN_IRQCTL);
+	free_irq(pdev->irq, pht);
+
+	pci_iounmap(pdev, pht->oaddr);
+	pci_iounmap(pdev, pht->iaddr);
+	pci_iounmap(pdev, pht->caddr);
+
+	kfree(pht);
+
+	pci_release_regions(pdev);
+
+	phantom_devices[minor] = 0;
+
+	pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int phantom_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct phantom_device *dev = pci_get_drvdata(pdev);
+
+	iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+	return 0;
+}
+
+static int phantom_resume(struct pci_dev *pdev)
+{
+	struct phantom_device *dev = pci_get_drvdata(pdev);
+
+	iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+	return 0;
+}
+#else
+#define phantom_suspend	NULL
+#define phantom_resume	NULL
+#endif
+
+static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
+		.class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
+
+static struct pci_driver phantom_pci_driver = {
+	.name = "phantom",
+	.id_table = phantom_pci_tbl,
+	.probe = phantom_probe,
+	.remove = __devexit_p(phantom_remove),
+	.suspend = phantom_suspend,
+	.resume = phantom_resume
+};
+
+static ssize_t phantom_show_version(struct class *cls, char *buf)
+{
+	return sprintf(buf, PHANTOM_VERSION "\n");
+}
+
+static CLASS_ATTR(version, 0444, phantom_show_version, NULL);
+
+static int __init phantom_init(void)
+{
+	int retval;
+	dev_t dev;
+
+	phantom_class = class_create(THIS_MODULE, "phantom");
+	if (IS_ERR(phantom_class)) {
+		retval = PTR_ERR(phantom_class);
+		printk(KERN_ERR "phantom: can't register phantom class\n");
+		goto err;
+	}
+	retval = class_create_file(phantom_class, &class_attr_version);
+	if (retval) {
+		printk(KERN_ERR "phantom: can't create sysfs version file\n");
+		goto err_class;
+	}
+
+	retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom");
+	if (retval) {
+		printk(KERN_ERR "phantom: can't register character device\n");
+		goto err_attr;
+	}
+	phantom_major = MAJOR(dev);
+
+	retval = pci_register_driver(&phantom_pci_driver);
+	if (retval) {
+		printk(KERN_ERR "phantom: can't register pci driver\n");
+		goto err_unchr;
+	}
+
+	printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", "
+			"init OK\n");
+
+	return 0;
+err_unchr:
+	unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
+err_attr:
+	class_remove_file(phantom_class, &class_attr_version);
+err_class:
+	class_destroy(phantom_class);
+err:
+	return retval;
+}
+
+static void __exit phantom_exit(void)
+{
+	pci_unregister_driver(&phantom_pci_driver);
+
+	unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
+
+	class_remove_file(phantom_class, &class_attr_version);
+	class_destroy(phantom_class);
+
+	pr_debug("phantom: module successfully removed\n");
+}
+
+module_init(phantom_init);
+module_exit(phantom_exit);
+
+MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
+MODULE_DESCRIPTION("Sensable Phantom driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PHANTOM_VERSION);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index ac708bc..c15c1f6 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -1,5 +1,5 @@
 /*
- * ACPI Sony Notebook Control Driver (SNC)
+ * ACPI Sony Notebook Control Driver (SNC and SPIC)
  *
  * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
  * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
@@ -7,6 +7,25 @@
  * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
  * which are copyrighted by their respective authors.
  *
+ * The SNY6001 driver part is based on the sonypi driver which includes
+ * material from:
+ *
+ * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -31,40 +50,404 @@ #include <linux/types.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/acpi.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
+#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
+#ifdef CONFIG_SONY_LAPTOP_OLD
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#endif
 
-#define ACPI_SNC_CLASS		"sony"
-#define ACPI_SNC_HID		"SNY5001"
-#define ACPI_SNC_DRIVER_NAME	"ACPI Sony Notebook Control Driver v0.4"
+#define DRV_PFX			"sony-laptop: "
+#define dprintk(msg...)		do {			\
+	if (debug) printk(KERN_WARNING DRV_PFX  msg);	\
+} while (0)
 
-/* the device uses 1-based values, while the backlight subsystem uses
-   0-based values */
-#define SONY_MAX_BRIGHTNESS	8
+#define SONY_LAPTOP_DRIVER_VERSION	"0.5"
+
+#define SONY_NC_CLASS		"sony-nc"
+#define SONY_NC_HID		"SNY5001"
+#define SONY_NC_DRIVER_NAME	"Sony Notebook Control Driver"
 
-#define LOG_PFX			KERN_WARNING "sony-laptop: "
+#define SONY_PIC_CLASS		"sony-pic"
+#define SONY_PIC_HID		"SNY6001"
+#define SONY_PIC_DRIVER_NAME	"Sony Programmable IO Control Driver"
 
 MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
-MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
 
 static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
 		 "the development of this driver");
 
-static ssize_t sony_acpi_show(struct device *, struct device_attribute *,
+static int no_spic;		/* = 0 */
+module_param(no_spic, int, 0444);
+MODULE_PARM_DESC(no_spic,
+		 "set this if you don't want to enable the SPIC device");
+
+static int compat;		/* = 0 */
+module_param(compat, int, 0444);
+MODULE_PARM_DESC(compat,
+		 "set this if you want to enable backward compatibility mode");
+
+static unsigned long mask = 0xffffffff;
+module_param(mask, ulong, 0644);
+MODULE_PARM_DESC(mask,
+		 "set this to the mask of event you want to enable (see doc)");
+
+static int camera;		/* = 0 */
+module_param(camera, int, 0444);
+MODULE_PARM_DESC(camera,
+		 "set this to 1 to enable Motion Eye camera controls "
+		 "(only use it if you have a C1VE or C1VN model)");
+
+#ifdef CONFIG_SONY_LAPTOP_OLD
+static int minor = -1;
+module_param(minor, int, 0);
+MODULE_PARM_DESC(minor,
+		 "minor number of the misc device for the SPIC compatibility code, "
+		 "default is -1 (automatic)");
+#endif
+
+/*********** Input Devices ***********/
+
+#define SONY_LAPTOP_BUF_SIZE	128
+struct sony_laptop_input_s {
+	atomic_t		users;
+	struct input_dev	*jog_dev;
+	struct input_dev	*key_dev;
+	struct kfifo		*fifo;
+	spinlock_t		fifo_lock;
+	struct workqueue_struct	*wq;
+};
+static struct sony_laptop_input_s sony_laptop_input = {
+	.users = ATOMIC_INIT(0),
+};
+
+struct sony_laptop_keypress {
+	struct input_dev *dev;
+	int key;
+};
+
+/* Correspondance table between sonypi events and input layer events */
+static struct {
+	int sonypiev;
+	int inputev;
+} sony_laptop_inputkeys[] = {
+	{ SONYPI_EVENT_CAPTURE_PRESSED,	 	KEY_CAMERA },
+	{ SONYPI_EVENT_FNKEY_ONLY, 		KEY_FN },
+	{ SONYPI_EVENT_FNKEY_ESC, 		KEY_FN_ESC },
+	{ SONYPI_EVENT_FNKEY_F1, 		KEY_FN_F1 },
+	{ SONYPI_EVENT_FNKEY_F2, 		KEY_FN_F2 },
+	{ SONYPI_EVENT_FNKEY_F3, 		KEY_FN_F3 },
+	{ SONYPI_EVENT_FNKEY_F4, 		KEY_FN_F4 },
+	{ SONYPI_EVENT_FNKEY_F5, 		KEY_FN_F5 },
+	{ SONYPI_EVENT_FNKEY_F6, 		KEY_FN_F6 },
+	{ SONYPI_EVENT_FNKEY_F7, 		KEY_FN_F7 },
+	{ SONYPI_EVENT_FNKEY_F8, 		KEY_FN_F8 },
+	{ SONYPI_EVENT_FNKEY_F9,		KEY_FN_F9 },
+	{ SONYPI_EVENT_FNKEY_F10,		KEY_FN_F10 },
+	{ SONYPI_EVENT_FNKEY_F11, 		KEY_FN_F11 },
+	{ SONYPI_EVENT_FNKEY_F12,		KEY_FN_F12 },
+	{ SONYPI_EVENT_FNKEY_1, 		KEY_FN_1 },
+	{ SONYPI_EVENT_FNKEY_2, 		KEY_FN_2 },
+	{ SONYPI_EVENT_FNKEY_D,			KEY_FN_D },
+	{ SONYPI_EVENT_FNKEY_E,			KEY_FN_E },
+	{ SONYPI_EVENT_FNKEY_F,			KEY_FN_F },
+	{ SONYPI_EVENT_FNKEY_S,			KEY_FN_S },
+	{ SONYPI_EVENT_FNKEY_B,			KEY_FN_B },
+	{ SONYPI_EVENT_BLUETOOTH_PRESSED, 	KEY_BLUE },
+	{ SONYPI_EVENT_BLUETOOTH_ON, 		KEY_BLUE },
+	{ SONYPI_EVENT_PKEY_P1, 		KEY_PROG1 },
+	{ SONYPI_EVENT_PKEY_P2, 		KEY_PROG2 },
+	{ SONYPI_EVENT_PKEY_P3, 		KEY_PROG3 },
+	{ SONYPI_EVENT_BACK_PRESSED, 		KEY_BACK },
+	{ SONYPI_EVENT_HELP_PRESSED, 		KEY_HELP },
+	{ SONYPI_EVENT_ZOOM_PRESSED, 		KEY_ZOOM },
+	{ SONYPI_EVENT_THUMBPHRASE_PRESSED, 	BTN_THUMB },
+	{ 0, 0 },
+};
+
+/* release buttons after a short delay if pressed */
+static void do_sony_laptop_release_key(struct work_struct *work)
+{
+	struct sony_laptop_keypress kp;
+
+	while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
+			 sizeof(kp)) == sizeof(kp)) {
+		msleep(10);
+		input_report_key(kp.dev, kp.key, 0);
+		input_sync(kp.dev);
+	}
+}
+static DECLARE_WORK(sony_laptop_release_key_work,
+		do_sony_laptop_release_key);
+
+/* forward event to the input subsytem */
+static void sony_laptop_report_input_event(u8 event)
+{
+	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
+	struct input_dev *key_dev = sony_laptop_input.key_dev;
+	struct sony_laptop_keypress kp = { NULL };
+	int i;
+
+	if (event == SONYPI_EVENT_FNKEY_RELEASED) {
+		/* Nothing, not all VAIOs generate this event */
+		return;
+	}
+
+	/* report events */
+	switch (event) {
+	/* jog_dev events */
+	case SONYPI_EVENT_JOGDIAL_UP:
+	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
+		input_report_rel(jog_dev, REL_WHEEL, 1);
+		input_sync(jog_dev);
+		return;
+
+	case SONYPI_EVENT_JOGDIAL_DOWN:
+	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
+		input_report_rel(jog_dev, REL_WHEEL, -1);
+		input_sync(jog_dev);
+		return;
+
+	/* key_dev events */
+	case SONYPI_EVENT_JOGDIAL_PRESSED:
+		kp.key = BTN_MIDDLE;
+		kp.dev = jog_dev;
+		break;
+
+	default:
+		for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+			if (event == sony_laptop_inputkeys[i].sonypiev) {
+				kp.dev = key_dev;
+				kp.key = sony_laptop_inputkeys[i].inputev;
+				break;
+			}
+		break;
+	}
+
+	if (kp.dev) {
+		input_report_key(kp.dev, kp.key, 1);
+		input_sync(kp.dev);
+		kfifo_put(sony_laptop_input.fifo,
+			  (unsigned char *)&kp, sizeof(kp));
+
+		if (!work_pending(&sony_laptop_release_key_work))
+			queue_work(sony_laptop_input.wq,
+					&sony_laptop_release_key_work);
+	} else
+		dprintk("unknown input event %.2x\n", event);
+}
+
+static int sony_laptop_setup_input(void)
+{
+	struct input_dev *jog_dev;
+	struct input_dev *key_dev;
+	int i;
+	int error;
+
+	/* don't run again if already initialized */
+	if (atomic_add_return(1, &sony_laptop_input.users) > 1)
+		return 0;
+
+	/* kfifo */
+	spin_lock_init(&sony_laptop_input.fifo_lock);
+	sony_laptop_input.fifo =
+		kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+			    &sony_laptop_input.fifo_lock);
+	if (IS_ERR(sony_laptop_input.fifo)) {
+		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+		error = PTR_ERR(sony_laptop_input.fifo);
+		goto err_dec_users;
+	}
+
+	/* init workqueue */
+	sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
+	if (!sony_laptop_input.wq) {
+		printk(KERN_ERR DRV_PFX
+				"Unabe to create workqueue.\n");
+		error = -ENXIO;
+		goto err_free_kfifo;
+	}
+
+	/* input keys */
+	key_dev = input_allocate_device();
+	if (!key_dev) {
+		error = -ENOMEM;
+		goto err_destroy_wq;
+	}
+
+	key_dev->name = "Sony Vaio Keys";
+	key_dev->id.bustype = BUS_ISA;
+	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+	/* Initialize the Input Drivers: special keys */
+	key_dev->evbit[0] = BIT(EV_KEY);
+	for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+		if (sony_laptop_inputkeys[i].inputev)
+			set_bit(sony_laptop_inputkeys[i].inputev,
+					key_dev->keybit);
+
+	error = input_register_device(key_dev);
+	if (error)
+		goto err_free_keydev;
+
+	sony_laptop_input.key_dev = key_dev;
+
+	/* jogdial */
+	jog_dev = input_allocate_device();
+	if (!jog_dev) {
+		error = -ENOMEM;
+		goto err_unregister_keydev;
+	}
+
+	jog_dev->name = "Sony Vaio Jogdial";
+	jog_dev->id.bustype = BUS_ISA;
+	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+	jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+	jog_dev->relbit[0] = BIT(REL_WHEEL);
+
+	error = input_register_device(jog_dev);
+	if (error)
+		goto err_free_jogdev;
+
+	sony_laptop_input.jog_dev = jog_dev;
+
+	return 0;
+
+err_free_jogdev:
+	input_free_device(jog_dev);
+
+err_unregister_keydev:
+	input_unregister_device(key_dev);
+	/* to avoid kref underflow below at input_free_device */
+	key_dev = NULL;
+
+err_free_keydev:
+	input_free_device(key_dev);
+
+err_destroy_wq:
+	destroy_workqueue(sony_laptop_input.wq);
+
+err_free_kfifo:
+	kfifo_free(sony_laptop_input.fifo);
+
+err_dec_users:
+	atomic_dec(&sony_laptop_input.users);
+	return error;
+}
+
+static void sony_laptop_remove_input(void)
+{
+	/* cleanup only after the last user has gone */
+	if (!atomic_dec_and_test(&sony_laptop_input.users))
+		return;
+
+	/* flush workqueue first */
+	flush_workqueue(sony_laptop_input.wq);
+
+	/* destroy input devs */
+	input_unregister_device(sony_laptop_input.key_dev);
+	sony_laptop_input.key_dev = NULL;
+
+	if (sony_laptop_input.jog_dev) {
+		input_unregister_device(sony_laptop_input.jog_dev);
+		sony_laptop_input.jog_dev = NULL;
+	}
+
+	destroy_workqueue(sony_laptop_input.wq);
+	kfifo_free(sony_laptop_input.fifo);
+}
+
+/*********** Platform Device ***********/
+
+static atomic_t sony_pf_users = ATOMIC_INIT(0);
+static struct platform_driver sony_pf_driver = {
+	.driver = {
+		   .name = "sony-laptop",
+		   .owner = THIS_MODULE,
+		   }
+};
+static struct platform_device *sony_pf_device;
+
+static int sony_pf_add(void)
+{
+	int ret = 0;
+
+	/* don't run again if already initialized */
+	if (atomic_add_return(1, &sony_pf_users) > 1)
+		return 0;
+
+	ret = platform_driver_register(&sony_pf_driver);
+	if (ret)
+		goto out;
+
+	sony_pf_device = platform_device_alloc("sony-laptop", -1);
+	if (!sony_pf_device) {
+		ret = -ENOMEM;
+		goto out_platform_registered;
+	}
+
+	ret = platform_device_add(sony_pf_device);
+	if (ret)
+		goto out_platform_alloced;
+
+	return 0;
+
+      out_platform_alloced:
+	platform_device_put(sony_pf_device);
+	sony_pf_device = NULL;
+      out_platform_registered:
+	platform_driver_unregister(&sony_pf_driver);
+      out:
+	atomic_dec(&sony_pf_users);
+	return ret;
+}
+
+static void sony_pf_remove(void)
+{
+	/* deregister only after the last user has gone */
+	if (!atomic_dec_and_test(&sony_pf_users))
+		return;
+
+	platform_device_del(sony_pf_device);
+	platform_device_put(sony_pf_device);
+	platform_driver_unregister(&sony_pf_driver);
+}
+
+/*********** SNC (SNY5001) Device ***********/
+
+/* the device uses 1-based values, while the backlight subsystem uses
+   0-based values */
+#define SONY_MAX_BRIGHTNESS	8
+
+#define SNC_VALIDATE_IN		0
+#define SNC_VALIDATE_OUT	1
+
+static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
 			      char *);
-static ssize_t sony_acpi_store(struct device *, struct device_attribute *,
+static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
 			       const char *, size_t);
 static int boolean_validate(const int, const int);
 static int brightness_default_validate(const int, const int);
 
-#define SNC_VALIDATE_IN		0
-#define SNC_VALIDATE_OUT	1
-
-struct sony_acpi_value {
+struct sony_nc_value {
 	char *name;		/* name of the entry */
 	char **acpiget;		/* names of the ACPI get function */
 	char **acpiset;		/* names of the ACPI set function */
@@ -75,65 +458,65 @@ struct sony_acpi_value {
 	struct device_attribute devattr;	/* sysfs atribute */
 };
 
-#define HANDLE_NAMES(_name, _values...) \
+#define SNC_HANDLE_NAMES(_name, _values...) \
 	static char *snc_##_name[] = { _values, NULL }
 
-#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \
+#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
 	{ \
 		.name		= __stringify(_name), \
 		.acpiget	= _getters, \
 		.acpiset	= _setters, \
 		.validate	= _validate, \
 		.debug		= _debug, \
-		.devattr	= __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \
+		.devattr	= __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
 	}
 
-#define SONY_ACPI_VALUE_NULL	{ .name = NULL }
+#define SNC_HANDLE_NULL	{ .name = NULL }
 
-HANDLE_NAMES(fnkey_get, "GHKE");
+SNC_HANDLE_NAMES(fnkey_get, "GHKE");
 
-HANDLE_NAMES(brightness_def_get, "GPBR");
-HANDLE_NAMES(brightness_def_set, "SPBR");
+SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
+SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
 
-HANDLE_NAMES(cdpower_get, "GCDP");
-HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
+SNC_HANDLE_NAMES(cdpower_get, "GCDP");
+SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
 
-HANDLE_NAMES(audiopower_get, "GAZP");
-HANDLE_NAMES(audiopower_set, "AZPW");
+SNC_HANDLE_NAMES(audiopower_get, "GAZP");
+SNC_HANDLE_NAMES(audiopower_set, "AZPW");
 
-HANDLE_NAMES(lanpower_get, "GLNP");
-HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lanpower_get, "GLNP");
+SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 
-HANDLE_NAMES(PID_get, "GPID");
+SNC_HANDLE_NAMES(PID_get, "GPID");
 
-HANDLE_NAMES(CTR_get, "GCTR");
-HANDLE_NAMES(CTR_set, "SCTR");
+SNC_HANDLE_NAMES(CTR_get, "GCTR");
+SNC_HANDLE_NAMES(CTR_set, "SCTR");
 
-HANDLE_NAMES(PCR_get, "GPCR");
-HANDLE_NAMES(PCR_set, "SPCR");
+SNC_HANDLE_NAMES(PCR_get, "GPCR");
+SNC_HANDLE_NAMES(PCR_set, "SPCR");
 
-HANDLE_NAMES(CMI_get, "GCMI");
-HANDLE_NAMES(CMI_set, "SCMI");
+SNC_HANDLE_NAMES(CMI_get, "GCMI");
+SNC_HANDLE_NAMES(CMI_set, "SCMI");
 
-static struct sony_acpi_value sony_acpi_values[] = {
-	SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get,
+static struct sony_nc_value sony_nc_values[] = {
+	SNC_HANDLE(brightness_default, snc_brightness_def_get,
 			snc_brightness_def_set, brightness_default_validate, 0),
-	SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0),
-	SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
-	SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set,
+	SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
+	SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+	SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
 			boolean_validate, 0),
-	SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set,
+	SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
 			boolean_validate, 1),
 	/* unknown methods */
-	SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1),
-	SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
-	SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
-	SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
-	SONY_ACPI_VALUE_NULL
+	SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
+	SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
+	SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
+	SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
+	SNC_HANDLE_NULL
 };
 
-static acpi_handle sony_acpi_handle;
-static struct acpi_device *sony_acpi_acpi_device = NULL;
+static acpi_handle sony_nc_acpi_handle;
+static struct acpi_device *sony_nc_acpi_device = NULL;
 
 /*
  * acpi_evaluate_object wrappers
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle 
 		return 0;
 	}
 
-	printk(LOG_PFX "acpi_callreadfunc failed\n");
+	printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
 
 	return -1;
 }
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle 
 	if (status == AE_OK) {
 		if (result != NULL) {
 			if (out_obj.type != ACPI_TYPE_INTEGER) {
-				printk(LOG_PFX "acpi_evaluate_object bad "
+				printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
 				       "return type\n");
 				return -1;
 			}
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle 
 		return 0;
 	}
 
-	printk(LOG_PFX "acpi_evaluate_object failed\n");
+	printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
 
 	return -1;
 }
 
 /*
- * sony_acpi_values input/output validate functions
+ * sony_nc_values input/output validate functions
  */
 
 /* brightness_default_validate:
@@ -229,19 +612,19 @@ static int boolean_validate(const int di
 }
 
 /*
- * Sysfs show/store common to all sony_acpi_values
+ * Sysfs show/store common to all sony_nc_values
  */
-static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
 			      char *buffer)
 {
 	int value;
-	struct sony_acpi_value *item =
-	    container_of(attr, struct sony_acpi_value, devattr);
+	struct sony_nc_value *item =
+	    container_of(attr, struct sony_nc_value, devattr);
 
 	if (!*item->acpiget)
 		return -EIO;
 
-	if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0)
+	if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
 		return -EIO;
 
 	if (item->validate)
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct dev
 	return snprintf(buffer, PAGE_SIZE, "%d\n", value);
 }
 
-static ssize_t sony_acpi_store(struct device *dev,
+static ssize_t sony_nc_sysfs_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
 	int value;
-	struct sony_acpi_value *item =
-	    container_of(attr, struct sony_acpi_value, devattr);
+	struct sony_nc_value *item =
+	    container_of(attr, struct sony_nc_value, devattr);
 
 	if (!item->acpiset)
 		return -EIO;
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct de
 	if (value < 0)
 		return value;
 
-	if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0)
+	if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
 		return -EIO;
 	item->value = value;
 	item->valid = 1;
 	return count;
 }
 
-/*
- * Platform device
- */
-static struct platform_driver sncpf_driver = {
-	.driver = {
-		   .name = "sony-laptop",
-		   .owner = THIS_MODULE,
-		   }
-};
-static struct platform_device *sncpf_device;
-
-static int sony_snc_pf_add(void)
-{
-	acpi_handle handle;
-	struct sony_acpi_value *item;
-	int ret = 0;
-
-	ret = platform_driver_register(&sncpf_driver);
-	if (ret)
-		goto out;
-
-	sncpf_device = platform_device_alloc("sony-laptop", -1);
-	if (!sncpf_device) {
-		ret = -ENOMEM;
-		goto out_platform_registered;
-	}
-
-	ret = platform_device_add(sncpf_device);
-	if (ret)
-		goto out_platform_alloced;
-
-	for (item = sony_acpi_values; item->name; ++item) {
-
-		if (!debug && item->debug)
-			continue;
-
-		/* find the available acpiget as described in the DSDT */
-		for (; item->acpiget && *item->acpiget; ++item->acpiget) {
-			if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
-							 *item->acpiget,
-							 &handle))) {
-				if (debug)
-					printk(LOG_PFX "Found %s getter: %s\n",
-					       item->name, *item->acpiget);
-				item->devattr.attr.mode |= S_IRUGO;
-				break;
-			}
-		}
-
-		/* find the available acpiset as described in the DSDT */
-		for (; item->acpiset && *item->acpiset; ++item->acpiset) {
-			if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
-							 *item->acpiset,
-							 &handle))) {
-				if (debug)
-					printk(LOG_PFX "Found %s setter: %s\n",
-					       item->name, *item->acpiset);
-				item->devattr.attr.mode |= S_IWUSR;
-				break;
-			}
-		}
-
-		if (item->devattr.attr.mode != 0) {
-			ret =
-			    device_create_file(&sncpf_device->dev,
-					       &item->devattr);
-			if (ret)
-				goto out_sysfs;
-		}
-	}
-
-	return 0;
-
-      out_sysfs:
-	for (item = sony_acpi_values; item->name; ++item) {
-		device_remove_file(&sncpf_device->dev, &item->devattr);
-	}
-	platform_device_del(sncpf_device);
-      out_platform_alloced:
-	platform_device_put(sncpf_device);
-      out_platform_registered:
-	platform_driver_unregister(&sncpf_driver);
-      out:
-	return ret;
-}
-
-static void sony_snc_pf_remove(void)
-{
-	struct sony_acpi_value *item;
-
-	for (item = sony_acpi_values; item->name; ++item) {
-		device_remove_file(&sncpf_device->dev, &item->devattr);
-	}
-
-	platform_device_del(sncpf_device);
-	platform_device_put(sncpf_device);
-	platform_driver_unregister(&sncpf_driver);
-}
 
 /*
  * Backlight device
  */
 static int sony_backlight_update_status(struct backlight_device *bd)
 {
-	return acpi_callsetfunc(sony_acpi_handle, "SBRT",
+	return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
 				bd->props.brightness + 1, NULL);
 }
 
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness
 {
 	int value;
 
-	if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value))
+	if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
 		return 0;
 	/* brightness levels are 1-based, while backlight ones are 0-based */
 	return value - 1;
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlig
  */
 static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
-	if (debug)
-		printk(LOG_PFX "sony_acpi_notify, event: %d\n", event);
-	acpi_bus_generate_event(sony_acpi_acpi_device, 1, event);
+	dprintk("sony_acpi_notify, event: %d\n", event);
+	sony_laptop_report_input_event(event);
+	acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(ac
 	node = (struct acpi_namespace_node *)handle;
 	operand = (union acpi_operand_object *)node->object;
 
-	printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+	printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
 	       (u32) operand->method.param_count);
 
 	return AE_OK;
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(ac
 /*
  * ACPI device
  */
-static int sony_acpi_resume(struct acpi_device *device)
+static int sony_nc_resume(struct acpi_device *device)
 {
-	struct sony_acpi_value *item;
+	struct sony_nc_value *item;
 
-	for (item = sony_acpi_values; item->name; item++) {
+	for (item = sony_nc_values; item->name; item++) {
 		int ret;
 
 		if (!item->valid)
 			continue;
-		ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset,
+		ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
 				       item->value, NULL);
 		if (ret < 0) {
 			printk("%s: %d\n", __FUNCTION__, ret);
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_
 	return 0;
 }
 
-static int sony_acpi_add(struct acpi_device *device)
+static int sony_nc_add(struct acpi_device *device)
 {
 	acpi_status status;
 	int result = 0;
 	acpi_handle handle;
+	struct sony_nc_value *item;
+
+	printk(KERN_INFO DRV_PFX "%s v%s.\n",
+		SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
-	sony_acpi_acpi_device = device;
+	sony_nc_acpi_device = device;
+	strcpy(acpi_device_class(device), "sony/hotkey");
 
-	sony_acpi_handle = device->handle;
+	sony_nc_acpi_handle = device->handle;
 
 	if (debug) {
-		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
 					     1, sony_walk_callback, NULL, NULL);
 		if (ACPI_FAILURE(status)) {
-			printk(LOG_PFX "unable to walk acpi resources\n");
+			printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
 			result = -ENODEV;
 			goto outwalk;
 		}
 	}
 
-	status = acpi_install_notify_handler(sony_acpi_handle,
+	/* setup input devices and helper fifo */
+	result = sony_laptop_setup_input();
+	if (result) {
+		printk(KERN_ERR DRV_PFX
+				"Unabe to create input devices.\n");
+		goto outwalk;
+	}
+
+	status = acpi_install_notify_handler(sony_nc_acpi_handle,
 					     ACPI_DEVICE_NOTIFY,
 					     sony_acpi_notify, NULL);
 	if (ACPI_FAILURE(status)) {
-		printk(LOG_PFX "unable to install notify handler\n");
+		printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
 		result = -ENODEV;
-		goto outwalk;
+		goto outinput;
 	}
 
-	if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) {
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
 		sony_backlight_device = backlight_device_register("sony", NULL,
 								  NULL,
 								  &sony_backlight_ops);
 
 		if (IS_ERR(sony_backlight_device)) {
-			printk(LOG_PFX "unable to register backlight device\n");
+			printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
 			sony_backlight_device = NULL;
 		} else {
 			sony_backlight_device->props.brightness =
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_dev
 
 	}
 
-	if (sony_snc_pf_add())
+	result = sony_pf_add();
+	if (result)
 		goto outbacklight;
 
-	printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+	/* create sony_pf sysfs attributes related to the SNC device */
+	for (item = sony_nc_values; item->name; ++item) {
+
+		if (!debug && item->debug)
+			continue;
+
+		/* find the available acpiget as described in the DSDT */
+		for (; item->acpiget && *item->acpiget; ++item->acpiget) {
+			if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+							 *item->acpiget,
+							 &handle))) {
+				dprintk("Found %s getter: %s\n",
+						item->name, *item->acpiget);
+				item->devattr.attr.mode |= S_IRUGO;
+				break;
+			}
+		}
+
+		/* find the available acpiset as described in the DSDT */
+		for (; item->acpiset && *item->acpiset; ++item->acpiset) {
+			if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+							 *item->acpiset,
+							 &handle))) {
+				dprintk("Found %s setter: %s\n",
+						item->name, *item->acpiset);
+				item->devattr.attr.mode |= S_IWUSR;
+				break;
+			}
+		}
+
+		if (item->devattr.attr.mode != 0) {
+			result =
+			    device_create_file(&sony_pf_device->dev,
+					       &item->devattr);
+			if (result)
+				goto out_sysfs;
+		}
+	}
 
 	return 0;
 
+      out_sysfs:
+	for (item = sony_nc_values; item->name; ++item) {
+		device_remove_file(&sony_pf_device->dev, &item->devattr);
+	}
+	sony_pf_remove();
+
       outbacklight:
 	if (sony_backlight_device)
 		backlight_device_unregister(sony_backlight_device);
 
-	status = acpi_remove_notify_handler(sony_acpi_handle,
+	status = acpi_remove_notify_handler(sony_nc_acpi_handle,
 					    ACPI_DEVICE_NOTIFY,
 					    sony_acpi_notify);
 	if (ACPI_FAILURE(status))
-		printk(LOG_PFX "unable to remove notify handler\n");
+		printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
+
+      outinput:
+	sony_laptop_remove_input();
+
       outwalk:
 	return result;
 }
 
-static int sony_acpi_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device, int type)
 {
 	acpi_status status;
+	struct sony_nc_value *item;
 
 	if (sony_backlight_device)
 		backlight_device_unregister(sony_backlight_device);
 
-	sony_acpi_acpi_device = NULL;
+	sony_nc_acpi_device = NULL;
 
-	status = acpi_remove_notify_handler(sony_acpi_handle,
+	status = acpi_remove_notify_handler(sony_nc_acpi_handle,
 					    ACPI_DEVICE_NOTIFY,
 					    sony_acpi_notify);
 	if (ACPI_FAILURE(status))
-		printk(LOG_PFX "unable to remove notify handler\n");
+		printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
 
-	sony_snc_pf_remove();
+	for (item = sony_nc_values; item->name; ++item) {
+		device_remove_file(&sony_pf_device->dev, &item->devattr);
+	}
 
-	printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+	sony_pf_remove();
+	sony_laptop_remove_input();
+	dprintk(SONY_NC_DRIVER_NAME " removed.\n");
 
 	return 0;
 }
 
-static struct acpi_driver sony_acpi_driver = {
-	.name = ACPI_SNC_DRIVER_NAME,
-	.class = ACPI_SNC_CLASS,
-	.ids = ACPI_SNC_HID,
+static struct acpi_driver sony_nc_driver = {
+	.name = SONY_NC_DRIVER_NAME,
+	.class = SONY_NC_CLASS,
+	.ids = SONY_NC_HID,
+	.owner = THIS_MODULE,
 	.ops = {
-		.add = sony_acpi_add,
-		.remove = sony_acpi_remove,
-		.resume = sony_acpi_resume,
+		.add = sony_nc_add,
+		.remove = sony_nc_remove,
+		.resume = sony_nc_resume,
 		},
 };
 
-static int __init sony_acpi_init(void)
+/*********** SPIC (SNY6001) Device ***********/
+
+#define SONYPI_DEVICE_TYPE1	0x00000001
+#define SONYPI_DEVICE_TYPE2	0x00000002
+#define SONYPI_DEVICE_TYPE3	0x00000004
+
+#define SONY_PIC_EV_MASK	0xff
+
+struct sony_pic_ioport {
+	struct acpi_resource_io	io;
+	struct list_head	list;
+};
+
+struct sony_pic_irq {
+	struct acpi_resource_irq	irq;
+	struct list_head		list;
+};
+
+struct sony_pic_dev {
+	int			model;
+	u8			camera_power;
+	u8			bluetooth_power;
+	u8			wwan_power;
+	struct acpi_device	*acpi_dev;
+	struct sony_pic_irq	*cur_irq;
+	struct sony_pic_ioport	*cur_ioport;
+	struct list_head	interrupts;
+	struct list_head	ioports;
+	struct mutex		lock;
+};
+
+static struct sony_pic_dev spic_dev = {
+	.interrupts	= LIST_HEAD_INIT(spic_dev.interrupts),
+	.ioports	= LIST_HEAD_INIT(spic_dev.ioports),
+};
+
+/* Event masks */
+#define SONYPI_JOGGER_MASK			0x00000001
+#define SONYPI_CAPTURE_MASK			0x00000002
+#define SONYPI_FNKEY_MASK			0x00000004
+#define SONYPI_BLUETOOTH_MASK			0x00000008
+#define SONYPI_PKEY_MASK			0x00000010
+#define SONYPI_BACK_MASK			0x00000020
+#define SONYPI_HELP_MASK			0x00000040
+#define SONYPI_LID_MASK				0x00000080
+#define SONYPI_ZOOM_MASK			0x00000100
+#define SONYPI_THUMBPHRASE_MASK			0x00000200
+#define SONYPI_MEYE_MASK			0x00000400
+#define SONYPI_MEMORYSTICK_MASK			0x00000800
+#define SONYPI_BATTERY_MASK			0x00001000
+#define SONYPI_WIRELESS_MASK			0x00002000
+
+struct sonypi_event {
+	u8	data;
+	u8	event;
+};
+
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+	{ 0, 0 }
+};
+
+/* The set of possible jogger events  */
+static struct sonypi_event sonypi_joggerev[] = {
+	{ 0x1f, SONYPI_EVENT_JOGDIAL_UP },
+	{ 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
+	{ 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
+	{ 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
+	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible capture button events */
+static struct sonypi_event sonypi_captureev[] = {
+	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
+	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
+	{ 0, 0 }
+};
+
+/* The set of possible fnkeys events */
+static struct sonypi_event sonypi_fnkeyev[] = {
+	{ 0x10, SONYPI_EVENT_FNKEY_ESC },
+	{ 0x11, SONYPI_EVENT_FNKEY_F1 },
+	{ 0x12, SONYPI_EVENT_FNKEY_F2 },
+	{ 0x13, SONYPI_EVENT_FNKEY_F3 },
+	{ 0x14, SONYPI_EVENT_FNKEY_F4 },
+	{ 0x15, SONYPI_EVENT_FNKEY_F5 },
+	{ 0x16, SONYPI_EVENT_FNKEY_F6 },
+	{ 0x17, SONYPI_EVENT_FNKEY_F7 },
+	{ 0x18, SONYPI_EVENT_FNKEY_F8 },
+	{ 0x19, SONYPI_EVENT_FNKEY_F9 },
+	{ 0x1a, SONYPI_EVENT_FNKEY_F10 },
+	{ 0x1b, SONYPI_EVENT_FNKEY_F11 },
+	{ 0x1c, SONYPI_EVENT_FNKEY_F12 },
+	{ 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x21, SONYPI_EVENT_FNKEY_1 },
+	{ 0x22, SONYPI_EVENT_FNKEY_2 },
+	{ 0x31, SONYPI_EVENT_FNKEY_D },
+	{ 0x32, SONYPI_EVENT_FNKEY_E },
+	{ 0x33, SONYPI_EVENT_FNKEY_F },
+	{ 0x34, SONYPI_EVENT_FNKEY_S },
+	{ 0x35, SONYPI_EVENT_FNKEY_B },
+	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
+	{ 0, 0 }
+};
+
+/* The set of possible program key events */
+static struct sonypi_event sonypi_pkeyev[] = {
+	{ 0x01, SONYPI_EVENT_PKEY_P1 },
+	{ 0x02, SONYPI_EVENT_PKEY_P2 },
+	{ 0x04, SONYPI_EVENT_PKEY_P3 },
+	{ 0x5c, SONYPI_EVENT_PKEY_P1 },
+	{ 0, 0 }
+};
+
+/* The set of possible bluetooth events */
+static struct sonypi_event sonypi_blueev[] = {
+	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
+	{ 0, 0 }
+};
+
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+	{ 0x59, SONYPI_EVENT_WIRELESS_ON },
+	{ 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+	{ 0, 0 }
+};
+
+/* The set of possible back button events */
+static struct sonypi_event sonypi_backev[] = {
+	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
+	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
+	{ 0, 0 }
+};
+
+
+/* The set of possible lid events */
+static struct sonypi_event sonypi_lidev[] = {
+	{ 0x51, SONYPI_EVENT_LID_CLOSED },
+	{ 0x50, SONYPI_EVENT_LID_OPENED },
+	{ 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+	{ 0x00, SONYPI_EVENT_MEYE_FACE },
+	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+	{ 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+	{ 0, 0 }
+};
+
+/* The set of possible battery events */
+static struct sonypi_event sonypi_batteryev[] = {
+	{ 0x20, SONYPI_EVENT_BATTERY_INSERT },
+	{ 0x30, SONYPI_EVENT_BATTERY_REMOVE },
+	{ 0, 0 }
+};
+
+static struct sonypi_eventtypes {
+	int			model;
+	u8			data;
+	unsigned long		mask;
+	struct sonypi_event *	events;
+} sony_pic_eventtypes[] = {
+	{ SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+	{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+
+	{ SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
+	{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+	{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+	{ SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+	{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+	{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+	{ SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+	{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+	{ SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+	{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ 0 }
+};
+
+static int sony_pic_detect_device_type(void)
+{
+	struct pci_dev *pcidev;
+	int model = 0;
+
+	if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				     PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+		model = SONYPI_DEVICE_TYPE1;
+
+	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					  PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+		model = SONYPI_DEVICE_TYPE3;
+
+	else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					  PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+		model = SONYPI_DEVICE_TYPE3;
+
+	else
+		model = SONYPI_DEVICE_TYPE2;
+
+	if (pcidev)
+		pci_dev_put(pcidev);
+
+	printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+			model == SONYPI_DEVICE_TYPE1 ? 1 :
+			model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+	return model;
+}
+
+#define ITERATIONS_LONG		10000
+#define ITERATIONS_SHORT	10
+#define wait_on_command(command, iterations) {				\
+	unsigned int n = iterations;					\
+	while (--n && (command))					\
+		udelay(1);						\
+	if (!n)								\
+		dprintk("command failed at %s : %s (line %d)\n",	\
+				__FILE__, __FUNCTION__, __LINE__);	\
+}
+
+static u8 sony_pic_call1(u8 dev)
+{
+	u8 v1, v2;
+
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+			ITERATIONS_LONG);
+	outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+	v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
+	v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+	dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+	return v2;
+}
+
+static u8 sony_pic_call2(u8 dev, u8 fn)
+{
+	u8 v1;
+
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+			ITERATIONS_LONG);
+	outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+			ITERATIONS_LONG);
+	outb(fn, spic_dev.cur_ioport->io.minimum);
+	v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+	dprintk("sony_pic_call2: 0x%.4x\n", v1);
+	return v1;
+}
+
+static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
+{
+	u8 v1;
+
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+	outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+	outb(fn, spic_dev.cur_ioport->io.minimum);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+	outb(v, spic_dev.cur_ioport->io.minimum);
+	v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+	dprintk("sony_pic_call3: 0x%.4x\n", v1);
+	return v1;
+}
+
+/* camera tests and poweron/poweroff */
+#define SONYPI_CAMERA_PICTURE		5
+#define SONYPI_CAMERA_CONTROL		0x10
+
+#define SONYPI_CAMERA_BRIGHTNESS		0
+#define SONYPI_CAMERA_CONTRAST			1
+#define SONYPI_CAMERA_HUE			2
+#define SONYPI_CAMERA_COLOR			3
+#define SONYPI_CAMERA_SHARPNESS			4
+
+#define SONYPI_CAMERA_EXPOSURE_MASK		0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK	0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK		0x30
+#define SONYPI_CAMERA_MUTE_MASK			0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC			6
+#define SONYPI_CAMERA_AGC_MASK			0x30
+#define SONYPI_CAMERA_SHUTTER_MASK 		0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST		7
+#define SONYPI_CAMERA_CONTROL			0x10
+
+#define SONYPI_CAMERA_STATUS 			7
+#define SONYPI_CAMERA_STATUS_READY 		0x2
+#define SONYPI_CAMERA_STATUS_POSITION		0x4
+
+#define SONYPI_DIRECTION_BACKWARDS 		0x4
+
+#define SONYPI_CAMERA_REVISION 			8
+#define SONYPI_CAMERA_ROMVERSION 		9
+
+static int __sony_pic_camera_ready(void)
+{
+	u8 v;
+
+	v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
+	return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
+}
+
+static int __sony_pic_camera_off(void)
+{
+	if (!camera) {
+		printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+		return -ENODEV;
+	}
+
+	wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
+				SONYPI_CAMERA_MUTE_MASK),
+			ITERATIONS_SHORT);
+
+	if (spic_dev.camera_power) {
+		sony_pic_call2(0x91, 0);
+		spic_dev.camera_power = 0;
+	}
+	return 0;
+}
+
+static int __sony_pic_camera_on(void)
 {
-	return acpi_bus_register_driver(&sony_acpi_driver);
+	int i, j, x;
+
+	if (!camera) {
+		printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+		return -ENODEV;
+	}
+
+	if (spic_dev.camera_power)
+		return 0;
+
+	for (j = 5; j > 0; j--) {
+
+		for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
+			msleep(10);
+		sony_pic_call1(0x93);
+
+		for (i = 400; i > 0; i--) {
+			if (__sony_pic_camera_ready())
+				break;
+			msleep(10);
+		}
+		if (i)
+			break;
+	}
+
+	if (j == 0) {
+		printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+		return -ENODEV;
+	}
+
+	wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
+				0x5a),
+			ITERATIONS_SHORT);
+
+	spic_dev.camera_power = 1;
+	return 0;
+}
+
+/* External camera command (exported to the motion eye v4l driver) */
+int sony_pic_camera_command(int command, u8 value)
+{
+	if (!camera)
+		return -EIO;
+
+	mutex_lock(&spic_dev.lock);
+
+	switch (command) {
+	case SONY_PIC_COMMAND_SETCAMERA:
+		if (value)
+			__sony_pic_camera_on();
+		else
+			__sony_pic_camera_off();
+		break;
+	case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERACONTRAST:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERAHUE:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERACOLOR:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERAPICTURE:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
+				ITERATIONS_SHORT);
+		break;
+	case SONY_PIC_COMMAND_SETCAMERAAGC:
+		wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
+				ITERATIONS_SHORT);
+		break;
+	default:
+		printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+		       command);
+		break;
+	}
+	mutex_unlock(&spic_dev.lock);
+	return 0;
+}
+EXPORT_SYMBOL(sony_pic_camera_command);
+
+/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
+static void sony_pic_set_wwanpower(u8 state)
+{
+	state = !!state;
+	mutex_lock(&spic_dev.lock);
+	if (spic_dev.wwan_power == state) {
+		mutex_unlock(&spic_dev.lock);
+		return;
+	}
+	sony_pic_call2(0xB0, state);
+	spic_dev.wwan_power = state;
+	mutex_unlock(&spic_dev.lock);
+}
+
+static ssize_t sony_pic_wwanpower_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+	if (count > 31)
+		return -EINVAL;
+
+	value = simple_strtoul(buffer, NULL, 10);
+	sony_pic_set_wwanpower(value);
+
+	return count;
+}
+
+static ssize_t sony_pic_wwanpower_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count;
+	mutex_lock(&spic_dev.lock);
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
+	mutex_unlock(&spic_dev.lock);
+	return count;
+}
+
+/* bluetooth subsystem power state */
+static void __sony_pic_set_bluetoothpower(u8 state)
+{
+	state = !!state;
+	if (spic_dev.bluetooth_power == state)
+		return;
+	sony_pic_call2(0x96, state);
+	sony_pic_call1(0x82);
+	spic_dev.bluetooth_power = state;
+}
+
+static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+	if (count > 31)
+		return -EINVAL;
+
+	value = simple_strtoul(buffer, NULL, 10);
+	mutex_lock(&spic_dev.lock);
+	__sony_pic_set_bluetoothpower(value);
+	mutex_unlock(&spic_dev.lock);
+
+	return count;
+}
+
+static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	mutex_lock(&spic_dev.lock);
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+	mutex_unlock(&spic_dev.lock);
+	return count;
+}
+
+/* fan speed */
+/* FAN0 information (reverse engineered from ACPI tables) */
+#define SONY_PIC_FAN0_STATUS	0x93
+static int sony_pic_set_fanspeed(unsigned long value)
+{
+	return ec_write(SONY_PIC_FAN0_STATUS, value);
+}
+
+static int sony_pic_get_fanspeed(u8 *value)
+{
+	return ec_read(SONY_PIC_FAN0_STATUS, value);
+}
+
+static ssize_t sony_pic_fanspeed_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+	if (count > 31)
+		return -EINVAL;
+
+	value = simple_strtoul(buffer, NULL, 10);
+	if (sony_pic_set_fanspeed(value))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_pic_fanspeed_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	u8 value = 0;
+	if (sony_pic_get_fanspeed(&value))
+		return -EIO;
+
+	return snprintf(buffer, PAGE_SIZE, "%d\n", value);
+}
+
+#define SPIC_ATTR(_name, _mode)					\
+struct device_attribute spic_attr_##_name = __ATTR(_name,	\
+		_mode, sony_pic_## _name ##_show,		\
+		sony_pic_## _name ##_store)
+
+static SPIC_ATTR(bluetoothpower, 0644);
+static SPIC_ATTR(wwanpower, 0644);
+static SPIC_ATTR(fanspeed, 0644);
+
+static struct attribute *spic_attributes[] = {
+	&spic_attr_bluetoothpower.attr,
+	&spic_attr_wwanpower.attr,
+	&spic_attr_fanspeed.attr,
+	NULL
+};
+
+static struct attribute_group spic_attribute_group = {
+	.attrs = spic_attributes
+};
+
+/******** SONYPI compatibility **********/
+#ifdef CONFIG_SONY_LAPTOP_OLD
+
+/* battery / brightness / temperature  addresses */
+#define SONYPI_BAT_FLAGS	0x81
+#define SONYPI_LCD_LIGHT	0x96
+#define SONYPI_BAT1_PCTRM	0xa0
+#define SONYPI_BAT1_LEFT	0xa2
+#define SONYPI_BAT1_MAXRT	0xa4
+#define SONYPI_BAT2_PCTRM	0xa8
+#define SONYPI_BAT2_LEFT	0xaa
+#define SONYPI_BAT2_MAXRT	0xac
+#define SONYPI_BAT1_MAXTK	0xb0
+#define SONYPI_BAT1_FULL	0xb2
+#define SONYPI_BAT2_MAXTK	0xb8
+#define SONYPI_BAT2_FULL	0xba
+#define SONYPI_TEMP_STATUS	0xC1
+
+struct sonypi_compat_s {
+	struct fasync_struct	*fifo_async;
+	struct kfifo		*fifo;
+	spinlock_t		fifo_lock;
+	wait_queue_head_t	fifo_proc_list;
+	atomic_t		open_count;
+};
+static struct sonypi_compat_s sonypi_compat = {
+	.open_count = ATOMIC_INIT(0),
+};
+
+static int sonypi_misc_fasync(int fd, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int sonypi_misc_release(struct inode *inode, struct file *file)
+{
+	sonypi_misc_fasync(-1, file, 0);
+	atomic_dec(&sonypi_compat.open_count);
+	return 0;
+}
+
+static int sonypi_misc_open(struct inode *inode, struct file *file)
+{
+	/* Flush input queue on first open */
+	if (atomic_inc_return(&sonypi_compat.open_count) == 1)
+		kfifo_reset(sonypi_compat.fifo);
+	return 0;
+}
+
+static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
+				size_t count, loff_t *pos)
+{
+	ssize_t ret;
+	unsigned char c;
+
+	if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+	    (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
+				       kfifo_len(sonypi_compat.fifo) != 0);
+	if (ret)
+		return ret;
+
+	while (ret < count &&
+	       (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+		if (put_user(c, buf++))
+			return -EFAULT;
+		ret++;
+	}
+
+	if (ret > 0) {
+		struct inode *inode = file->f_path.dentry->d_inode;
+		inode->i_atime = current_fs_time(inode->i_sb);
+	}
+
+	return ret;
+}
+
+static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
+	if (kfifo_len(sonypi_compat.fifo))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int ec_read16(u8 addr, u16 *value)
+{
+	u8 val_lb, val_hb;
+	if (ec_read(addr, &val_lb))
+		return -1;
+	if (ec_read(addr + 1, &val_hb))
+		return -1;
+	*value = val_lb | (val_hb << 8);
+	return 0;
+}
+
+static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
+			     unsigned int cmd, unsigned long arg)
+{
+	int ret = 0;
+	void __user *argp = (void __user *)arg;
+	u8 val8;
+	u16 val16;
+	int value;
+
+	mutex_lock(&spic_dev.lock);
+	switch (cmd) {
+	case SONYPI_IOCGBRT:
+		if (sony_backlight_device == NULL) {
+			ret = -EIO;
+			break;
+		}
+		if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
+			ret = -EIO;
+			break;
+		}
+		val8 = ((value & 0xff) - 1) << 5;
+		if (copy_to_user(argp, &val8, sizeof(val8)))
+				ret = -EFAULT;
+		break;
+	case SONYPI_IOCSBRT:
+		if (sony_backlight_device == NULL) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_from_user(&val8, argp, sizeof(val8))) {
+			ret = -EFAULT;
+			break;
+		}
+		if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
+				(val8 >> 5) + 1, NULL)) {
+			ret = -EIO;
+			break;
+		}
+		/* sync the backlight device status */
+		sony_backlight_device->props.brightness =
+		    sony_backlight_get_brightness(sony_backlight_device);
+		break;
+	case SONYPI_IOCGBAT1CAP:
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val16, sizeof(val16)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCGBAT1REM:
+		if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val16, sizeof(val16)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCGBAT2CAP:
+		if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val16, sizeof(val16)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCGBAT2REM:
+		if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val16, sizeof(val16)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCGBATFLAGS:
+		if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+			ret = -EIO;
+			break;
+		}
+		val8 &= 0x07;
+		if (copy_to_user(argp, &val8, sizeof(val8)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCGBLUE:
+		val8 = spic_dev.bluetooth_power;
+		if (copy_to_user(argp, &val8, sizeof(val8)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCSBLUE:
+		if (copy_from_user(&val8, argp, sizeof(val8))) {
+			ret = -EFAULT;
+			break;
+		}
+		__sony_pic_set_bluetoothpower(val8);
+		break;
+	/* FAN Controls */
+	case SONYPI_IOCGFAN:
+		if (sony_pic_get_fanspeed(&val8)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val8, sizeof(val8)))
+			ret = -EFAULT;
+		break;
+	case SONYPI_IOCSFAN:
+		if (copy_from_user(&val8, argp, sizeof(val8))) {
+			ret = -EFAULT;
+			break;
+		}
+		if (sony_pic_set_fanspeed(val8))
+			ret = -EIO;
+		break;
+	/* GET Temperature (useful under APM) */
+	case SONYPI_IOCGTEMP:
+		if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
+			ret = -EIO;
+			break;
+		}
+		if (copy_to_user(argp, &val8, sizeof(val8)))
+			ret = -EFAULT;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	mutex_unlock(&spic_dev.lock);
+	return ret;
+}
+
+static const struct file_operations sonypi_misc_fops = {
+	.owner		= THIS_MODULE,
+	.read		= sonypi_misc_read,
+	.poll		= sonypi_misc_poll,
+	.open		= sonypi_misc_open,
+	.release	= sonypi_misc_release,
+	.fasync		= sonypi_misc_fasync,
+	.ioctl		= sonypi_misc_ioctl,
+};
+
+static struct miscdevice sonypi_misc_device = {
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= "sonypi",
+	.fops		= &sonypi_misc_fops,
+};
+
+static void sonypi_compat_report_event(u8 event)
+{
+	kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+	kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
+	wake_up_interruptible(&sonypi_compat.fifo_proc_list);
+}
+
+static int sonypi_compat_init(void)
+{
+	int error;
+
+	spin_lock_init(&sonypi_compat.fifo_lock);
+	sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+					 &sonypi_compat.fifo_lock);
+	if (IS_ERR(sonypi_compat.fifo)) {
+		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+		return PTR_ERR(sonypi_compat.fifo);
+	}
+
+	init_waitqueue_head(&sonypi_compat.fifo_proc_list);
+
+	if (minor != -1)
+		sonypi_misc_device.minor = minor;
+	error = misc_register(&sonypi_misc_device);
+	if (error) {
+		printk(KERN_ERR DRV_PFX "misc_register failed\n");
+		goto err_free_kfifo;
+	}
+	if (minor == -1)
+		printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+		       sonypi_misc_device.minor);
+
+	return 0;
+
+err_free_kfifo:
+	kfifo_free(sonypi_compat.fifo);
+	return error;
+}
+
+static void sonypi_compat_exit(void)
+{
+	misc_deregister(&sonypi_misc_device);
+	kfifo_free(sonypi_compat.fifo);
+}
+#else
+static int sonypi_compat_init(void) { return 0; }
+static void sonypi_compat_exit(void) { }
+static void sonypi_compat_report_event(u8 event) { }
+#endif /* CONFIG_SONY_LAPTOP_OLD */
+
+/*
+ * ACPI callbacks
+ */
+static acpi_status
+sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
+{
+	u32 i;
+	struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
+
+	switch (resource->type) {
+	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+		return AE_OK;
+
+	case ACPI_RESOURCE_TYPE_IRQ:
+		{
+			struct acpi_resource_irq *p = &resource->data.irq;
+			struct sony_pic_irq *interrupt = NULL;
+			if (!p || !p->interrupt_count) {
+				/*
+				 * IRQ descriptors may have no IRQ# bits set,
+				 * particularly those those w/ _STA disabled
+				 */
+				dprintk("Blank IRQ resource\n");
+				return AE_OK;
+			}
+			for (i = 0; i < p->interrupt_count; i++) {
+				if (!p->interrupts[i]) {
+					printk(KERN_WARNING DRV_PFX
+							"Invalid IRQ %d\n",
+							p->interrupts[i]);
+					continue;
+				}
+				interrupt = kzalloc(sizeof(*interrupt),
+						GFP_KERNEL);
+				if (!interrupt)
+					return AE_ERROR;
+
+				list_add_tail(&interrupt->list, &dev->interrupts);
+				interrupt->irq.triggering = p->triggering;
+				interrupt->irq.polarity = p->polarity;
+				interrupt->irq.sharable = p->sharable;
+				interrupt->irq.interrupt_count = 1;
+				interrupt->irq.interrupts[0] = p->interrupts[i];
+			}
+			return AE_OK;
+		}
+	case ACPI_RESOURCE_TYPE_IO:
+		{
+			struct acpi_resource_io *io = &resource->data.io;
+			struct sony_pic_ioport *ioport = NULL;
+			if (!io) {
+				dprintk("Blank IO resource\n");
+				return AE_OK;
+			}
+
+			ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+			if (!ioport)
+				return AE_ERROR;
+
+			list_add_tail(&ioport->list, &dev->ioports);
+			memcpy(&ioport->io, io, sizeof(*io));
+			return AE_OK;
+		}
+	default:
+		dprintk("Resource %d isn't an IRQ nor an IO port\n",
+				resource->type);
+
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		return AE_OK;
+	}
+	return AE_CTRL_TERMINATE;
+}
+
+static int sony_pic_possible_resources(struct acpi_device *device)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+
+	if (!device)
+		return -EINVAL;
+
+	/* get device status */
+	/* see acpi_pci_link_get_current acpi_pci_link_get_possible */
+	dprintk("Evaluating _STA\n");
+	result = acpi_bus_get_status(device);
+	if (result) {
+		printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+		goto end;
+	}
+
+	if (!device->status.enabled)
+		dprintk("Device disabled\n");
+	else
+		dprintk("Device enabled\n");
+
+	/*
+	 * Query and parse 'method'
+	 */
+	dprintk("Evaluating %s\n", METHOD_NAME__PRS);
+	status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
+			sony_pic_read_possible_resource, &spic_dev);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_WARNING DRV_PFX
+				"Failure evaluating %s\n",
+				METHOD_NAME__PRS);
+		result = -ENODEV;
+	}
+end:
+	return result;
+}
+
+/*
+ *  Disable the spic device by calling its _DIS method
+ */
+static int sony_pic_disable(struct acpi_device *device)
+{
+	if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
+		return -ENXIO;
+
+	dprintk("Device disabled\n");
+	return 0;
+}
+
+
+/*
+ *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set
+ *
+ *  Call _SRS to set current resources
+ */
+static int sony_pic_enable(struct acpi_device *device,
+		struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
+{
+	acpi_status status;
+	int result = 0;
+	struct {
+		struct acpi_resource io_res;
+		struct acpi_resource irq_res;
+		struct acpi_resource end;
+	} *resource;
+	struct acpi_buffer buffer = { 0, NULL };
+
+	if (!ioport || !irq)
+		return -EINVAL;
+
+	/* init acpi_buffer */
+	resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
+	if (!resource)
+		return -ENOMEM;
+
+	buffer.length = sizeof(*resource) + 1;
+	buffer.pointer = resource;
+
+	/* setup io resource */
+	resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
+	resource->io_res.length = sizeof(struct acpi_resource);
+	memcpy(&resource->io_res.data.io, &ioport->io,
+			sizeof(struct acpi_resource_io));
+
+	/* setup irq resource */
+	resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
+	resource->irq_res.length = sizeof(struct acpi_resource);
+	memcpy(&resource->irq_res.data.irq, &irq->irq,
+			sizeof(struct acpi_resource_irq));
+	/* we requested a shared irq */
+	resource->irq_res.data.irq.sharable = ACPI_SHARED;
+
+	resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+	/* Attempt to set the resource */
+	dprintk("Evaluating _SRS\n");
+	status = acpi_set_current_resources(device->handle, &buffer);
+
+	/* check for total failure */
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+		result = -ENODEV;
+		goto end;
+	}
+
+	/* Necessary device initializations calls (from sonypi) */
+	sony_pic_call1(0x82);
+	sony_pic_call2(0x81, 0xff);
+	sony_pic_call1(compat ? 0x92 : 0x82);
+
+end:
+	kfree(resource);
+	return result;
+}
+
+/*****************
+ *
+ * ISR: some event is available
+ *
+ *****************/
+static irqreturn_t sony_pic_irq(int irq, void *dev_id)
+{
+	int i, j;
+	u32 port_val = 0;
+	u8 ev = 0;
+	u8 data_mask = 0;
+	u8 device_event = 0;
+
+	struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
+
+	acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
+			dev->cur_ioport->io.address_length);
+	ev = port_val & SONY_PIC_EV_MASK;
+	data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+
+	dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
+			port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+
+	if (ev == 0x00 || ev == 0xff)
+		return IRQ_HANDLED;
+
+	for (i = 0; sony_pic_eventtypes[i].model; i++) {
+
+		if (spic_dev.model != sony_pic_eventtypes[i].model)
+			continue;
+
+		if ((data_mask & sony_pic_eventtypes[i].data) !=
+		    sony_pic_eventtypes[i].data)
+			continue;
+
+		if (!(mask & sony_pic_eventtypes[i].mask))
+			continue;
+
+		for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
+			if (ev == sony_pic_eventtypes[i].events[j].data) {
+				device_event =
+					sony_pic_eventtypes[i].events[j].event;
+				goto found;
+			}
+		}
+	}
+	return IRQ_HANDLED;
+
+found:
+	sony_laptop_report_input_event(device_event);
+	acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+	sonypi_compat_report_event(device_event);
+
+	return IRQ_HANDLED;
+}
+
+/*****************
+ *
+ *  ACPI driver
+ *
+ *****************/
+static int sony_pic_remove(struct acpi_device *device, int type)
+{
+	struct sony_pic_ioport *io, *tmp_io;
+	struct sony_pic_irq *irq, *tmp_irq;
+
+	sonypi_compat_exit();
+
+	if (sony_pic_disable(device)) {
+		printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+		return -ENXIO;
+	}
+
+	free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+	release_region(spic_dev.cur_ioport->io.minimum,
+			spic_dev.cur_ioport->io.address_length);
+
+	sony_laptop_remove_input();
+
+	/* pf attrs */
+	sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+	sony_pf_remove();
+
+	list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+		list_del(&io->list);
+		kfree(io);
+	}
+	list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+		list_del(&irq->list);
+		kfree(irq);
+	}
+	spic_dev.cur_ioport = NULL;
+	spic_dev.cur_irq = NULL;
+
+	dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
+	return 0;
+}
+
+static int sony_pic_add(struct acpi_device *device)
+{
+	int result;
+	struct sony_pic_ioport *io, *tmp_io;
+	struct sony_pic_irq *irq, *tmp_irq;
+
+	printk(KERN_INFO DRV_PFX "%s v%s.\n",
+		SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+
+	spic_dev.acpi_dev = device;
+	strcpy(acpi_device_class(device), "sony/hotkey");
+	spic_dev.model = sony_pic_detect_device_type();
+	mutex_init(&spic_dev.lock);
+
+	/* read _PRS resources */
+	result = sony_pic_possible_resources(device);
+	if (result) {
+		printk(KERN_ERR DRV_PFX
+				"Unabe to read possible resources.\n");
+		goto err_free_resources;
+	}
+
+	/* setup input devices and helper fifo */
+	result = sony_laptop_setup_input();
+	if (result) {
+		printk(KERN_ERR DRV_PFX
+				"Unabe to create input devices.\n");
+		goto err_free_resources;
+	}
+
+	/* request io port */
+	list_for_each_entry(io, &spic_dev.ioports, list) {
+		if (request_region(io->io.minimum, io->io.address_length,
+					"Sony Programable I/O Device")) {
+			dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
+					io->io.minimum, io->io.maximum,
+					io->io.address_length);
+			spic_dev.cur_ioport = io;
+			break;
+		}
+	}
+	if (!spic_dev.cur_ioport) {
+		printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+		result = -ENODEV;
+		goto err_remove_input;
+	}
+
+	/* request IRQ */
+	list_for_each_entry(irq, &spic_dev.interrupts, list) {
+		if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
+					IRQF_SHARED, "sony-laptop", &spic_dev)) {
+			dprintk("IRQ: %d - triggering: %d - "
+					"polarity: %d - shr: %d\n",
+					irq->irq.interrupts[0],
+					irq->irq.triggering,
+					irq->irq.polarity,
+					irq->irq.sharable);
+			spic_dev.cur_irq = irq;
+			break;
+		}
+	}
+	if (!spic_dev.cur_irq) {
+		printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+		result = -ENODEV;
+		goto err_release_region;
+	}
+
+	/* set resource status _SRS */
+	result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+	if (result) {
+		printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+		goto err_free_irq;
+	}
+
+	spic_dev.bluetooth_power = -1;
+	/* create device attributes */
+	result = sony_pf_add();
+	if (result)
+		goto err_disable_device;
+
+	result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+	if (result)
+		goto err_remove_pf;
+
+	if (sonypi_compat_init())
+		goto err_remove_pf;
+
+	return 0;
+
+err_remove_pf:
+	sony_pf_remove();
+
+err_disable_device:
+	sony_pic_disable(device);
+
+err_free_irq:
+	free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+
+err_release_region:
+	release_region(spic_dev.cur_ioport->io.minimum,
+			spic_dev.cur_ioport->io.address_length);
+
+err_remove_input:
+	sony_laptop_remove_input();
+
+err_free_resources:
+	list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+		list_del(&io->list);
+		kfree(io);
+	}
+	list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+		list_del(&irq->list);
+		kfree(irq);
+	}
+	spic_dev.cur_ioport = NULL;
+	spic_dev.cur_irq = NULL;
+
+	return result;
+}
+
+static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+{
+	if (sony_pic_disable(device))
+		return -ENXIO;
+	return 0;
+}
+
+static int sony_pic_resume(struct acpi_device *device)
+{
+	sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+	return 0;
+}
+
+static struct acpi_driver sony_pic_driver = {
+	.name = SONY_PIC_DRIVER_NAME,
+	.class = SONY_PIC_CLASS,
+	.ids = SONY_PIC_HID,
+	.owner = THIS_MODULE,
+	.ops = {
+		.add = sony_pic_add,
+		.remove = sony_pic_remove,
+		.suspend = sony_pic_suspend,
+		.resume = sony_pic_resume,
+		},
+};
+
+static struct dmi_system_id __initdata sonypi_dmi_table[] = {
+	{
+		.ident = "Sony Vaio",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
+		},
+	},
+	{
+		.ident = "Sony Vaio",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
+		},
+	},
+	{ }
+};
+
+static int __init sony_laptop_init(void)
+{
+	int result;
+
+	if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
+		result = acpi_bus_register_driver(&sony_pic_driver);
+		if (result) {
+			printk(KERN_ERR DRV_PFX
+					"Unable to register SPIC driver.");
+			goto out;
+		}
+	}
+
+	result = acpi_bus_register_driver(&sony_nc_driver);
+	if (result) {
+		printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+		goto out_unregister_pic;
+	}
+
+	return 0;
+
+out_unregister_pic:
+	if (!no_spic)
+		acpi_bus_unregister_driver(&sony_pic_driver);
+out:
+	return result;
 }
 
-static void __exit sony_acpi_exit(void)
+static void __exit sony_laptop_exit(void)
 {
-	acpi_bus_unregister_driver(&sony_acpi_driver);
+	acpi_bus_unregister_driver(&sony_nc_driver);
+	if (!no_spic)
+		acpi_bus_unregister_driver(&sony_pic_driver);
 }
 
-module_init(sony_acpi_init);
-module_exit(sony_acpi_exit);
+module_init(sony_laptop_init);
+module_exit(sony_laptop_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
new file mode 100644
index 0000000..6c36a55
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.c
@@ -0,0 +1,4312 @@
+/*
+ *  thinkpad_acpi.c - ThinkPad ACPI Extras
+ *
+ *
+ *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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.
+ */
+
+#define IBM_VERSION "0.14"
+#define TPACPI_SYSFS_VERSION 0x000100
+
+/*
+ *  Changelog:
+ *  2007-03-27  0.14	renamed to thinkpad_acpi and moved to
+ *  			drivers/misc.
+ *
+ *  2006-11-22	0.13	new maintainer
+ *  			changelog now lives in git commit history, and will
+ *  			not be updated further in-file.
+ *
+ *  2005-08-17  0.12	fix compilation on 2.6.13-rc kernels
+ *  2005-03-17	0.11	support for 600e, 770x
+ *			    thanks to Jamie Lentin <lentinj@dial.pipex.com>
+ *			support for 770e, G41
+ *			G40 and G41 don't have a thinklight
+ *			temperatures no longer experimental
+ *			experimental brightness control
+ *			experimental volume control
+ *			experimental fan enable/disable
+ *  2005-01-16	0.10	fix module loading on R30, R31
+ *  2005-01-16	0.9	support for 570, R30, R31
+ *			ultrabay support on A22p, A3x
+ *			limit arg for cmos, led, beep, drop experimental status
+ *			more capable led control on A21e, A22p, T20-22, X20
+ *			experimental temperatures and fan speed
+ *			experimental embedded controller register dump
+ *			mark more functions as __init, drop incorrect __exit
+ *			use MODULE_VERSION
+ *			    thanks to Henrik Brix Andersen <brix@gentoo.org>
+ *			fix parameter passing on module loading
+ *			    thanks to Rusty Russell <rusty@rustcorp.com.au>
+ *			    thanks to Jim Radford <radford@blackbean.org>
+ *  2004-11-08	0.8	fix init error case, don't return from a macro
+ *			    thanks to Chris Wright <chrisw@osdl.org>
+ *  2004-10-23	0.7	fix module loading on A21e, A22p, T20, T21, X20
+ *			fix led control on A21e
+ *  2004-10-19	0.6	use acpi_bus_register_driver() to claim HKEY device
+ *  2004-10-18	0.5	thinklight support on A21e, G40, R32, T20, T21, X20
+ *			proc file format changed
+ *			video_switch command
+ *			experimental cmos control
+ *			experimental led control
+ *			experimental acpi sounds
+ *  2004-09-16	0.4	support for module parameters
+ *			hotkey mask can be prefixed by 0x
+ *			video output switching
+ *			video expansion control
+ *			ultrabay eject support
+ *			removed lcd brightness/on/off control, didn't work
+ *  2004-08-17	0.3	support for R40
+ *			lcd off, brightness control
+ *			thinklight on/off
+ *  2004-08-14	0.2	support for T series, X20
+ *			bluetooth enable/disable
+ *			hotkey events disabled by default
+ *			removed fan control, currently useless
+ *  2004-08-09	0.1	initial release, support for X series
+ */
+
+#include "thinkpad_acpi.h"
+
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_VERSION(IBM_VERSION);
+MODULE_LICENSE("GPL");
+
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
+
+#define __unused __attribute__ ((unused))
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * ACPI Helpers and device model
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * ACPI basic handles
+ */
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...)			\
+	static acpi_handle  object##_handle;			\
+	static acpi_handle *object##_parent = &parent##_handle;	\
+	static char        *object##_path;			\
+	static char        *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",	/* 240, 240x */
+	   "\\_SB.PCI.ISA.EC",	/* 570 */
+	   "\\_SB.PCI0.ISA0.EC0",	/* 600e/x, 770e, 770x */
+	   "\\_SB.PCI0.ISA.EC",	/* A21e, A2xm/p, T20-22, X20-21 */
+	   "\\_SB.PCI0.AD4S.EC0",	/* i1400, R30 */
+	   "\\_SB.PCI0.ICH3.EC0",	/* R31 */
+	   "\\_SB.PCI0.LPC.EC",	/* all others */
+	   );
+
+IBM_HANDLE(ecrd, ec, "ECRD");	/* 570 */
+IBM_HANDLE(ecwr, ec, "ECWR");	/* 570 */
+
+
+/*************************************************************************
+ * Misc ACPI handles
+ */
+
+IBM_HANDLE(cmos, root, "\\UCMS",	/* R50, R50e, R50p, R51, T4x, X31, X40 */
+	   "\\CMOS",		/* A3x, G4x, R32, T23, T30, X22-24, X30 */
+	   "\\CMS",		/* R40, R40e */
+	   );			/* all others */
+
+IBM_HANDLE(hkey, ec, "\\_SB.HKEY",	/* 600e/x, 770e, 770x */
+	   "^HKEY",		/* R30, R31 */
+	   "HKEY",		/* all others */
+	   );			/* 570 */
+
+
+/*************************************************************************
+ * ACPI helpers
+ */
+
+static int acpi_evalf(acpi_handle handle,
+		      void *res, char *method, char *fmt, ...)
+{
+	char *fmt0 = fmt;
+	struct acpi_object_list params;
+	union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+	struct acpi_buffer result, *resultp;
+	union acpi_object out_obj;
+	acpi_status status;
+	va_list ap;
+	char res_type;
+	int success;
+	int quiet;
+
+	if (!*fmt) {
+		printk(IBM_ERR "acpi_evalf() called with empty format\n");
+		return 0;
+	}
+
+	if (*fmt == 'q') {
+		quiet = 1;
+		fmt++;
+	} else
+		quiet = 0;
+
+	res_type = *(fmt++);
+
+	params.count = 0;
+	params.pointer = &in_objs[0];
+
+	va_start(ap, fmt);
+	while (*fmt) {
+		char c = *(fmt++);
+		switch (c) {
+		case 'd':	/* int */
+			in_objs[params.count].integer.value = va_arg(ap, int);
+			in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+			break;
+			/* add more types as needed */
+		default:
+			printk(IBM_ERR "acpi_evalf() called "
+			       "with invalid format character '%c'\n", c);
+			return 0;
+		}
+	}
+	va_end(ap);
+
+	if (res_type != 'v') {
+		result.length = sizeof(out_obj);
+		result.pointer = &out_obj;
+		resultp = &result;
+	} else
+		resultp = NULL;
+
+	status = acpi_evaluate_object(handle, method, &params, resultp);
+
+	switch (res_type) {
+	case 'd':		/* int */
+		if (res)
+			*(int *)res = out_obj.integer.value;
+		success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+		break;
+	case 'v':		/* void */
+		success = status == AE_OK;
+		break;
+		/* add more types as needed */
+	default:
+		printk(IBM_ERR "acpi_evalf() called "
+		       "with invalid format character '%c'\n", res_type);
+		return 0;
+	}
+
+	if (!success && !quiet)
+		printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+		       method, fmt0, status);
+
+	return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+	int i;
+
+	if (acpi_evalf(handle, &i, method, "d"))
+		printk(IBM_INFO "%s = 0x%x\n", method, i);
+	else
+		printk(IBM_ERR "error calling %s\n", method);
+}
+
+static int acpi_ec_read(int i, u8 * p)
+{
+	int v;
+
+	if (ecrd_handle) {
+		if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
+			return 0;
+		*p = v;
+	} else {
+		if (ec_read(i, p) < 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int acpi_ec_write(int i, u8 v)
+{
+	if (ecwr_handle) {
+		if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
+			return 0;
+	} else {
+		if (ec_write(i, v) < 0)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int _sta(acpi_handle handle)
+{
+	int status;
+
+	if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+		status = 0;
+
+	return status;
+}
+
+static int issue_thinkpad_cmos_command(int cmos_cmd)
+{
+	if (!cmos_handle)
+		return -ENXIO;
+
+	if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+		return -EIO;
+
+	return 0;
+}
+
+/*************************************************************************
+ * ACPI device model
+ */
+
+static void drv_acpi_handle_init(char *name,
+			   acpi_handle *handle, acpi_handle parent,
+			   char **paths, int num_paths, char **path)
+{
+	int i;
+	acpi_status status;
+
+	vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
+		name);
+
+	for (i = 0; i < num_paths; i++) {
+		status = acpi_get_handle(parent, paths[i], handle);
+		if (ACPI_SUCCESS(status)) {
+			*path = paths[i];
+			dbg_printk(TPACPI_DBG_INIT,
+				   "Found ACPI handle %s for %s\n",
+				   *path, name);
+			return;
+		}
+	}
+
+	vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
+		    name);
+	*handle = NULL;
+}
+
+static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct ibm_struct *ibm = data;
+
+	if (!ibm || !ibm->acpi || !ibm->acpi->notify)
+		return;
+
+	ibm->acpi->notify(ibm, event);
+}
+
+static int __init setup_acpi_notify(struct ibm_struct *ibm)
+{
+	acpi_status status;
+	int rc;
+
+	BUG_ON(!ibm->acpi);
+
+	if (!*ibm->acpi->handle)
+		return 0;
+
+	vdbg_printk(TPACPI_DBG_INIT,
+		"setting up ACPI notify for %s\n", ibm->name);
+
+	rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
+	if (rc < 0) {
+		printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+			ibm->name, rc);
+		return -ENODEV;
+	}
+
+	acpi_driver_data(ibm->acpi->device) = ibm;
+	sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
+		IBM_ACPI_EVENT_PREFIX,
+		ibm->name);
+
+	status = acpi_install_notify_handler(*ibm->acpi->handle,
+			ibm->acpi->type, dispatch_acpi_notify, ibm);
+	if (ACPI_FAILURE(status)) {
+		if (status == AE_ALREADY_EXISTS) {
+			printk(IBM_NOTICE "another device driver is already handling %s events\n",
+				ibm->name);
+		} else {
+			printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+				ibm->name, status);
+		}
+		return -ENODEV;
+	}
+	ibm->flags.acpi_notify_installed = 1;
+	return 0;
+}
+
+static int __init tpacpi_device_add(struct acpi_device *device)
+{
+	return 0;
+}
+
+static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
+{
+	int rc;
+
+	dbg_printk(TPACPI_DBG_INIT,
+		"registering %s as an ACPI driver\n", ibm->name);
+
+	BUG_ON(!ibm->acpi);
+
+	ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+	if (!ibm->acpi->driver) {
+		printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+		return -ENOMEM;
+	}
+
+	sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+	ibm->acpi->driver->ids = ibm->acpi->hid;
+	ibm->acpi->driver->ops.add = &tpacpi_device_add;
+
+	rc = acpi_bus_register_driver(ibm->acpi->driver);
+	if (rc < 0) {
+		printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+		       ibm->acpi->hid, rc);
+		kfree(ibm->acpi->driver);
+		ibm->acpi->driver = NULL;
+	} else if (!rc)
+		ibm->flags.acpi_driver_registered = 1;
+
+	return rc;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Procfs Helpers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	struct ibm_struct *ibm = data;
+	int len;
+
+	if (!ibm || !ibm->read)
+		return -EINVAL;
+
+	len = ibm->read(page);
+	if (len < 0)
+		return len;
+
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int dispatch_procfs_write(struct file *file,
+			const char __user * userbuf,
+			unsigned long count, void *data)
+{
+	struct ibm_struct *ibm = data;
+	char *kernbuf;
+	int ret;
+
+	if (!ibm || !ibm->write)
+		return -EINVAL;
+
+	kernbuf = kmalloc(count + 2, GFP_KERNEL);
+	if (!kernbuf)
+		return -ENOMEM;
+
+	if (copy_from_user(kernbuf, userbuf, count)) {
+		kfree(kernbuf);
+		return -EFAULT;
+	}
+
+	kernbuf[count] = 0;
+	strcat(kernbuf, ",");
+	ret = ibm->write(kernbuf);
+	if (ret == 0)
+		ret = count;
+
+	kfree(kernbuf);
+
+	return ret;
+}
+
+static char *next_cmd(char **cmds)
+{
+	char *start = *cmds;
+	char *end;
+
+	while ((end = strchr(start, ',')) && end == start)
+		start = end + 1;
+
+	if (!end)
+		return NULL;
+
+	*end = 0;
+	*cmds = end + 1;
+	return start;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Device model: hwmon and platform
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static struct platform_device *tpacpi_pdev = NULL;
+static struct class_device *tpacpi_hwmon = NULL;
+
+static struct platform_driver tpacpi_pdriver = {
+	.driver = {
+		.name = IBM_DRVR_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+
+/*************************************************************************
+ * thinkpad-acpi driver attributes
+ */
+
+/* interface_version --------------------------------------------------- */
+static ssize_t tpacpi_driver_interface_version_show(
+				struct device_driver *drv,
+				char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
+}
+
+static DRIVER_ATTR(interface_version, S_IRUGO,
+		tpacpi_driver_interface_version_show, NULL);
+
+/* debug_level --------------------------------------------------------- */
+static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
+						char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
+}
+
+static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
+						const char *buf, size_t count)
+{
+	unsigned long t;
+
+	if (parse_strtoul(buf, 0xffff, &t))
+		return -EINVAL;
+
+	dbg_level = t;
+
+	return count;
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+		tpacpi_driver_debug_show, tpacpi_driver_debug_store);
+
+/* version ------------------------------------------------------------- */
+static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
+						char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO,
+		tpacpi_driver_version_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct driver_attribute* tpacpi_driver_attributes[] = {
+	&driver_attr_debug_level, &driver_attr_version,
+	&driver_attr_interface_version,
+};
+
+static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
+{
+	int i, res;
+
+	i = 0;
+	res = 0;
+	while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
+		res = driver_create_file(drv, tpacpi_driver_attributes[i]);
+		i++;
+	}
+
+	return res;
+}
+
+static void tpacpi_remove_driver_attributes(struct device_driver *drv)
+{
+	int i;
+
+	for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+		driver_remove_file(drv, tpacpi_driver_attributes[i]);
+}
+
+/*************************************************************************
+ * sysfs support helpers
+ */
+
+struct attribute_set_obj {
+	struct attribute_set s;
+	struct attribute *a;
+} __attribute__((packed));
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+						const char* name)
+{
+	struct attribute_set_obj *sobj;
+
+	if (max_members == 0)
+		return NULL;
+
+	/* Allocates space for implicit NULL at the end too */
+	sobj = kzalloc(sizeof(struct attribute_set_obj) +
+		    max_members * sizeof(struct attribute *),
+		    GFP_KERNEL);
+	if (!sobj)
+		return NULL;
+	sobj->s.max_members = max_members;
+	sobj->s.group.attrs = &sobj->a;
+	sobj->s.group.name = name;
+
+	return &sobj->s;
+}
+
+/* not multi-threaded safe, use it in a single thread per set */
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
+{
+	if (!s || !attr)
+		return -EINVAL;
+
+	if (s->members >= s->max_members)
+		return -ENOMEM;
+
+	s->group.attrs[s->members] = attr;
+	s->members++;
+
+	return 0;
+}
+
+static int add_many_to_attr_set(struct attribute_set* s,
+			struct attribute **attr,
+			unsigned int count)
+{
+	int i, res;
+
+	for (i = 0; i < count; i++) {
+		res = add_to_attr_set(s, attr[i]);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
+{
+	sysfs_remove_group(kobj, &s->group);
+	destroy_attr_set(s);
+}
+
+static int parse_strtoul(const char *buf,
+		unsigned long max, unsigned long *value)
+{
+	char *endp;
+
+	*value = simple_strtoul(buf, &endp, 0);
+	while (*endp && isspace(*endp))
+		endp++;
+	if (*endp || *value > max)
+		return -EINVAL;
+
+	return 0;
+}
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Subdrivers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * thinkpad-acpi init subdriver
+ */
+
+static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
+{
+	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+	printk(IBM_INFO "%s\n", IBM_URL);
+
+	if (ibm_thinkpad_ec_found)
+		printk(IBM_INFO "ThinkPad EC firmware %s\n",
+		       ibm_thinkpad_ec_found);
+
+	return 0;
+}
+
+static int thinkpad_acpi_driver_read(char *p)
+{
+	int len = 0;
+
+	len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+	len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+	return len;
+}
+
+static struct ibm_struct thinkpad_acpi_driver_data = {
+	.name = "driver",
+	.read = thinkpad_acpi_driver_read,
+};
+
+/*************************************************************************
+ * Hotkey subdriver
+ */
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct attribute_set *hotkey_dev_attributes = NULL;
+
+/* sysfs hotkey enable ------------------------------------------------- */
+static ssize_t hotkey_enable_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res, status, mask;
+
+	res = hotkey_get(&status, &mask);
+	if (res)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t hotkey_enable_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long t;
+	int res, status, mask;
+
+	if (parse_strtoul(buf, 1, &t))
+		return -EINVAL;
+
+	res = hotkey_get(&status, &mask);
+	if (!res)
+		res = hotkey_set(t, mask);
+
+	return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_enable =
+	__ATTR(enable, S_IWUSR | S_IRUGO,
+		hotkey_enable_show, hotkey_enable_store);
+
+/* sysfs hotkey mask --------------------------------------------------- */
+static ssize_t hotkey_mask_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res, status, mask;
+
+	res = hotkey_get(&status, &mask);
+	if (res)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+}
+
+static ssize_t hotkey_mask_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long t;
+	int res, status, mask;
+
+	if (parse_strtoul(buf, 0xffff, &t))
+		return -EINVAL;
+
+	res = hotkey_get(&status, &mask);
+	if (!res)
+		hotkey_set(status, t);
+
+	return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_mask =
+	__ATTR(mask, S_IWUSR | S_IRUGO,
+		hotkey_mask_show, hotkey_mask_store);
+
+/* sysfs hotkey bios_enabled ------------------------------------------- */
+static ssize_t hotkey_bios_enabled_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_enabled =
+	__ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
+
+/* sysfs hotkey bios_mask ---------------------------------------------- */
+static ssize_t hotkey_bios_mask_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_mask =
+	__ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *hotkey_mask_attributes[] = {
+	&dev_attr_hotkey_mask.attr,
+	&dev_attr_hotkey_bios_enabled.attr,
+	&dev_attr_hotkey_bios_mask.attr,
+};
+
+static int __init hotkey_init(struct ibm_init_struct *iibm)
+{
+	int res;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(hkey);
+	mutex_init(&hotkey_mutex);
+
+	/* hotkey not supported on 570 */
+	tp_features.hotkey = hkey_handle != NULL;
+
+	vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
+		str_supported(tp_features.hotkey));
+
+	if (tp_features.hotkey) {
+		hotkey_dev_attributes = create_attr_set(4,
+						TPACPI_HOTKEY_SYSFS_GROUP);
+		if (!hotkey_dev_attributes)
+			return -ENOMEM;
+		res = add_to_attr_set(hotkey_dev_attributes,
+				&dev_attr_hotkey_enable.attr);
+		if (res)
+			return res;
+
+		/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+		   A30, R30, R31, T20-22, X20-21, X22-24 */
+		tp_features.hotkey_mask =
+			acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+
+		vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+			str_supported(tp_features.hotkey_mask));
+
+		res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+		if (!res && tp_features.hotkey_mask) {
+			res = add_many_to_attr_set(hotkey_dev_attributes,
+				hotkey_mask_attributes,
+				ARRAY_SIZE(hotkey_mask_attributes));
+		}
+		if (!res)
+			res = register_attr_set_with_sysfs(
+					hotkey_dev_attributes,
+					&tpacpi_pdev->dev.kobj);
+
+		if (res)
+			return res;
+	}
+
+	return (tp_features.hotkey)? 0 : 1;
+}
+
+static void hotkey_exit(void)
+{
+	int res;
+
+	if (tp_features.hotkey) {
+		dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
+		res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
+		if (res)
+			printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+	}
+
+	if (hotkey_dev_attributes) {
+		delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+		hotkey_dev_attributes = NULL;
+	}
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+	int hkey;
+
+	if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+		acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+	else {
+		printk(IBM_ERR "unknown hotkey event %d\n", event);
+		acpi_bus_generate_event(ibm->acpi->device, event, 0);
+	}
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_get(int *status, int *mask)
+{
+	if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+		return -EIO;
+
+	if (tp_features.hotkey_mask)
+		if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
+			return -EIO;
+
+	return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_set(int status, int mask)
+{
+	int i;
+
+	if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+		return -EIO;
+
+	if (tp_features.hotkey_mask)
+		for (i = 0; i < 32; i++) {
+			int bit = ((1 << i) & mask) != 0;
+			if (!acpi_evalf(hkey_handle,
+					NULL, "MHKM", "vdd", i + 1, bit))
+				return -EIO;
+		}
+
+	return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int hotkey_read(char *p)
+{
+	int res, status, mask;
+	int len = 0;
+
+	if (!tp_features.hotkey) {
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+		return len;
+	}
+
+	res = mutex_lock_interruptible(&hotkey_mutex);
+	if (res < 0)
+		return res;
+	res = hotkey_get(&status, &mask);
+	mutex_unlock(&hotkey_mutex);
+	if (res)
+		return res;
+
+	len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+	if (tp_features.hotkey_mask) {
+		len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+		len += sprintf(p + len,
+			       "commands:\tenable, disable, reset, <mask>\n");
+	} else {
+		len += sprintf(p + len, "mask:\t\tnot supported\n");
+		len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+	}
+
+	return len;
+}
+
+static int hotkey_write(char *buf)
+{
+	int res, status, mask;
+	char *cmd;
+	int do_cmd = 0;
+
+	if (!tp_features.hotkey)
+		return -ENODEV;
+
+	res = mutex_lock_interruptible(&hotkey_mutex);
+	if (res < 0)
+		return res;
+
+	res = hotkey_get(&status, &mask);
+	if (res)
+		goto errexit;
+
+	res = 0;
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "enable") == 0) {
+			status = 1;
+		} else if (strlencmp(cmd, "disable") == 0) {
+			status = 0;
+		} else if (strlencmp(cmd, "reset") == 0) {
+			status = hotkey_orig_status;
+			mask = hotkey_orig_mask;
+		} else if (sscanf(cmd, "0x%x", &mask) == 1) {
+			/* mask set */
+		} else if (sscanf(cmd, "%x", &mask) == 1) {
+			/* mask set */
+		} else {
+			res = -EINVAL;
+			goto errexit;
+		}
+		do_cmd = 1;
+	}
+
+	if (do_cmd)
+		res = hotkey_set(status, mask);
+
+errexit:
+	mutex_unlock(&hotkey_mutex);
+	return res;
+}
+
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
+	.hid = IBM_HKEY_HID,
+	.notify = hotkey_notify,
+	.handle = &hkey_handle,
+	.type = ACPI_DEVICE_NOTIFY,
+};
+
+static struct ibm_struct hotkey_driver_data = {
+	.name = "hotkey",
+	.read = hotkey_read,
+	.write = hotkey_write,
+	.exit = hotkey_exit,
+	.acpi = &ibm_hotkey_acpidriver,
+};
+
+/*************************************************************************
+ * Bluetooth subdriver
+ */
+
+/* sysfs bluetooth enable ---------------------------------------------- */
+static ssize_t bluetooth_enable_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int status;
+
+	status = bluetooth_get_radiosw();
+	if (status < 0)
+		return status;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t bluetooth_enable_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long t;
+	int res;
+
+	if (parse_strtoul(buf, 1, &t))
+		return -EINVAL;
+
+	res = bluetooth_set_radiosw(t);
+
+	return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_bluetooth_enable =
+	__ATTR(enable, S_IWUSR | S_IRUGO,
+		bluetooth_enable_show, bluetooth_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *bluetooth_attributes[] = {
+	&dev_attr_bluetooth_enable.attr,
+	NULL
+};
+
+static const struct attribute_group bluetooth_attr_group = {
+	.name = TPACPI_BLUETH_SYSFS_GROUP,
+	.attrs = bluetooth_attributes,
+};
+
+static int __init bluetooth_init(struct ibm_init_struct *iibm)
+{
+	int res;
+	int status = 0;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(hkey);
+
+	/* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+	   G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
+	tp_features.bluetooth = hkey_handle &&
+	    acpi_evalf(hkey_handle, &status, "GBDC", "qd");
+
+	vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
+		str_supported(tp_features.bluetooth),
+		status);
+
+	if (tp_features.bluetooth) {
+		if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
+			/* no bluetooth hardware present in system */
+			tp_features.bluetooth = 0;
+			dbg_printk(TPACPI_DBG_INIT,
+				   "bluetooth hardware not installed\n");
+		} else {
+			res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+					&bluetooth_attr_group);
+			if (res)
+				return res;
+		}
+	}
+
+	return (tp_features.bluetooth)? 0 : 1;
+}
+
+static void bluetooth_exit(void)
+{
+	sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+			&bluetooth_attr_group);
+}
+
+static int bluetooth_get_radiosw(void)
+{
+	int status;
+
+	if (!tp_features.bluetooth)
+		return -ENODEV;
+
+	if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+		return -EIO;
+
+	return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
+}
+
+static int bluetooth_set_radiosw(int radio_on)
+{
+	int status;
+
+	if (!tp_features.bluetooth)
+		return -ENODEV;
+
+	if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+		return -EIO;
+	if (radio_on)
+		status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+	else
+		status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+	if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+		return -EIO;
+
+	return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int bluetooth_read(char *p)
+{
+	int len = 0;
+	int status = bluetooth_get_radiosw();
+
+	if (!tp_features.bluetooth)
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	else {
+		len += sprintf(p + len, "status:\t\t%s\n",
+				(status)? "enabled" : "disabled");
+		len += sprintf(p + len, "commands:\tenable, disable\n");
+	}
+
+	return len;
+}
+
+static int bluetooth_write(char *buf)
+{
+	char *cmd;
+
+	if (!tp_features.bluetooth)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "enable") == 0) {
+			bluetooth_set_radiosw(1);
+		} else if (strlencmp(cmd, "disable") == 0) {
+			bluetooth_set_radiosw(0);
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct bluetooth_driver_data = {
+	.name = "bluetooth",
+	.read = bluetooth_read,
+	.write = bluetooth_write,
+	.exit = bluetooth_exit,
+};
+
+/*************************************************************************
+ * Wan subdriver
+ */
+
+/* sysfs wan enable ---------------------------------------------------- */
+static ssize_t wan_enable_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int status;
+
+	status = wan_get_radiosw();
+	if (status < 0)
+		return status;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t wan_enable_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long t;
+	int res;
+
+	if (parse_strtoul(buf, 1, &t))
+		return -EINVAL;
+
+	res = wan_set_radiosw(t);
+
+	return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_wan_enable =
+	__ATTR(enable, S_IWUSR | S_IRUGO,
+		wan_enable_show, wan_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *wan_attributes[] = {
+	&dev_attr_wan_enable.attr,
+	NULL
+};
+
+static const struct attribute_group wan_attr_group = {
+	.name = TPACPI_WAN_SYSFS_GROUP,
+	.attrs = wan_attributes,
+};
+
+static int __init wan_init(struct ibm_init_struct *iibm)
+{
+	int res;
+	int status = 0;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(hkey);
+
+	tp_features.wan = hkey_handle &&
+	    acpi_evalf(hkey_handle, &status, "GWAN", "qd");
+
+	vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
+		str_supported(tp_features.wan),
+		status);
+
+	if (tp_features.wan) {
+		if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
+			/* no wan hardware present in system */
+			tp_features.wan = 0;
+			dbg_printk(TPACPI_DBG_INIT,
+				   "wan hardware not installed\n");
+		} else {
+			res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+					&wan_attr_group);
+			if (res)
+				return res;
+		}
+	}
+
+	return (tp_features.wan)? 0 : 1;
+}
+
+static void wan_exit(void)
+{
+	sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+		&wan_attr_group);
+}
+
+static int wan_get_radiosw(void)
+{
+	int status;
+
+	if (!tp_features.wan)
+		return -ENODEV;
+
+	if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+		return -EIO;
+
+	return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
+}
+
+static int wan_set_radiosw(int radio_on)
+{
+	int status;
+
+	if (!tp_features.wan)
+		return -ENODEV;
+
+	if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+		return -EIO;
+	if (radio_on)
+		status |= TP_ACPI_WANCARD_RADIOSSW;
+	else
+		status &= ~TP_ACPI_WANCARD_RADIOSSW;
+	if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
+		return -EIO;
+
+	return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int wan_read(char *p)
+{
+	int len = 0;
+	int status = wan_get_radiosw();
+
+	if (!tp_features.wan)
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	else {
+		len += sprintf(p + len, "status:\t\t%s\n",
+				(status)? "enabled" : "disabled");
+		len += sprintf(p + len, "commands:\tenable, disable\n");
+	}
+
+	return len;
+}
+
+static int wan_write(char *buf)
+{
+	char *cmd;
+
+	if (!tp_features.wan)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "enable") == 0) {
+			wan_set_radiosw(1);
+		} else if (strlencmp(cmd, "disable") == 0) {
+			wan_set_radiosw(0);
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct wan_driver_data = {
+	.name = "wan",
+	.read = wan_read,
+	.write = wan_write,
+	.exit = wan_exit,
+	.flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Video subdriver
+ */
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+
+IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",	/* 570 */
+	   "\\_SB.PCI0.AGP0.VID0",	/* 600e/x, 770x */
+	   "\\_SB.PCI0.VID0",	/* 770e */
+	   "\\_SB.PCI0.VID",	/* A21e, G4x, R50e, X30, X40 */
+	   "\\_SB.PCI0.AGP.VID",	/* all others */
+	   );				/* R30, R31 */
+
+IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");	/* G41 */
+
+static int __init video_init(struct ibm_init_struct *iibm)
+{
+	int ivga;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(vid);
+	IBM_ACPIHANDLE_INIT(vid2);
+
+	if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
+		/* G41, assume IVGA doesn't change */
+		vid_handle = vid2_handle;
+
+	if (!vid_handle)
+		/* video switching not supported on R30, R31 */
+		video_supported = TPACPI_VIDEO_NONE;
+	else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
+		/* 570 */
+		video_supported = TPACPI_VIDEO_570;
+	else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
+		/* 600e/x, 770e, 770x */
+		video_supported = TPACPI_VIDEO_770;
+	else
+		/* all others */
+		video_supported = TPACPI_VIDEO_NEW;
+
+	vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
+		str_supported(video_supported != TPACPI_VIDEO_NONE),
+		video_supported);
+
+	return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
+}
+
+static void video_exit(void)
+{
+	dbg_printk(TPACPI_DBG_EXIT,
+		   "restoring original video autoswitch mode\n");
+	if (video_autosw_set(video_orig_autosw))
+		printk(IBM_ERR "error while trying to restore original "
+			"video autoswitch mode\n");
+}
+
+static int video_outputsw_get(void)
+{
+	int status = 0;
+	int i;
+
+	switch (video_supported) {
+	case TPACPI_VIDEO_570:
+		if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
+				 TP_ACPI_VIDEO_570_PHSCMD))
+			return -EIO;
+		status = i & TP_ACPI_VIDEO_570_PHSMASK;
+		break;
+	case TPACPI_VIDEO_770:
+		if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
+			return -EIO;
+		if (i)
+			status |= TP_ACPI_VIDEO_S_LCD;
+		if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
+			return -EIO;
+		if (i)
+			status |= TP_ACPI_VIDEO_S_CRT;
+		break;
+	case TPACPI_VIDEO_NEW:
+		if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
+		    !acpi_evalf(NULL, &i, "\\VCDC", "d"))
+			return -EIO;
+		if (i)
+			status |= TP_ACPI_VIDEO_S_CRT;
+
+		if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
+		    !acpi_evalf(NULL, &i, "\\VCDL", "d"))
+			return -EIO;
+		if (i)
+			status |= TP_ACPI_VIDEO_S_LCD;
+		if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
+			return -EIO;
+		if (i)
+			status |= TP_ACPI_VIDEO_S_DVI;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	return status;
+}
+
+static int video_outputsw_set(int status)
+{
+	int autosw;
+	int res = 0;
+
+	switch (video_supported) {
+	case TPACPI_VIDEO_570:
+		res = acpi_evalf(NULL, NULL,
+				 "\\_SB.PHS2", "vdd",
+				 TP_ACPI_VIDEO_570_PHS2CMD,
+				 status | TP_ACPI_VIDEO_570_PHS2SET);
+		break;
+	case TPACPI_VIDEO_770:
+		autosw = video_autosw_get();
+		if (autosw < 0)
+			return autosw;
+
+		res = video_autosw_set(1);
+		if (res)
+			return res;
+		res = acpi_evalf(vid_handle, NULL,
+				 "ASWT", "vdd", status * 0x100, 0);
+		if (!autosw && video_autosw_set(autosw)) {
+			printk(IBM_ERR "video auto-switch left enabled due to error\n");
+			return -EIO;
+		}
+		break;
+	case TPACPI_VIDEO_NEW:
+		res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
+			acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	return (res)? 0 : -EIO;
+}
+
+static int video_autosw_get(void)
+{
+	int autosw = 0;
+
+	switch (video_supported) {
+	case TPACPI_VIDEO_570:
+		if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
+			return -EIO;
+		break;
+	case TPACPI_VIDEO_770:
+	case TPACPI_VIDEO_NEW:
+		if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
+			return -EIO;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	return autosw & 1;
+}
+
+static int video_autosw_set(int enable)
+{
+	if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
+		return -EIO;
+	return 0;
+}
+
+static int video_outputsw_cycle(void)
+{
+	int autosw = video_autosw_get();
+	int res;
+
+	if (autosw < 0)
+		return autosw;
+
+	switch (video_supported) {
+	case TPACPI_VIDEO_570:
+		res = video_autosw_set(1);
+		if (res)
+			return res;
+		res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
+		break;
+	case TPACPI_VIDEO_770:
+	case TPACPI_VIDEO_NEW:
+		res = video_autosw_set(1);
+		if (res)
+			return res;
+		res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
+		break;
+	default:
+		return -ENOSYS;
+	}
+	if (!autosw && video_autosw_set(autosw)) {
+		printk(IBM_ERR "video auto-switch left enabled due to error\n");
+		return -EIO;
+	}
+
+	return (res)? 0 : -EIO;
+}
+
+static int video_expand_toggle(void)
+{
+	switch (video_supported) {
+	case TPACPI_VIDEO_570:
+		return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
+			0 : -EIO;
+	case TPACPI_VIDEO_770:
+		return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
+			0 : -EIO;
+	case TPACPI_VIDEO_NEW:
+		return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
+			0 : -EIO;
+	default:
+		return -ENOSYS;
+	}
+	/* not reached */
+}
+
+static int video_read(char *p)
+{
+	int status, autosw;
+	int len = 0;
+
+	if (video_supported == TPACPI_VIDEO_NONE) {
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+		return len;
+	}
+
+	status = video_outputsw_get();
+	if (status < 0)
+		return status;
+
+	autosw = video_autosw_get();
+	if (autosw < 0)
+		return autosw;
+
+	len += sprintf(p + len, "status:\t\tsupported\n");
+	len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+	len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+	if (video_supported == TPACPI_VIDEO_NEW)
+		len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+	len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
+	len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
+	len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
+	if (video_supported == TPACPI_VIDEO_NEW)
+		len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
+	len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
+	len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+	return len;
+}
+
+static int video_write(char *buf)
+{
+	char *cmd;
+	int enable, disable, status;
+	int res;
+
+	if (video_supported == TPACPI_VIDEO_NONE)
+		return -ENODEV;
+
+	enable = 0;
+	disable = 0;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "lcd_enable") == 0) {
+			enable |= TP_ACPI_VIDEO_S_LCD;
+		} else if (strlencmp(cmd, "lcd_disable") == 0) {
+			disable |= TP_ACPI_VIDEO_S_LCD;
+		} else if (strlencmp(cmd, "crt_enable") == 0) {
+			enable |= TP_ACPI_VIDEO_S_CRT;
+		} else if (strlencmp(cmd, "crt_disable") == 0) {
+			disable |= TP_ACPI_VIDEO_S_CRT;
+		} else if (video_supported == TPACPI_VIDEO_NEW &&
+			   strlencmp(cmd, "dvi_enable") == 0) {
+			enable |= TP_ACPI_VIDEO_S_DVI;
+		} else if (video_supported == TPACPI_VIDEO_NEW &&
+			   strlencmp(cmd, "dvi_disable") == 0) {
+			disable |= TP_ACPI_VIDEO_S_DVI;
+		} else if (strlencmp(cmd, "auto_enable") == 0) {
+			res = video_autosw_set(1);
+			if (res)
+				return res;
+		} else if (strlencmp(cmd, "auto_disable") == 0) {
+			res = video_autosw_set(0);
+			if (res)
+				return res;
+		} else if (strlencmp(cmd, "video_switch") == 0) {
+			res = video_outputsw_cycle();
+			if (res)
+				return res;
+		} else if (strlencmp(cmd, "expand_toggle") == 0) {
+			res = video_expand_toggle();
+			if (res)
+				return res;
+		} else
+			return -EINVAL;
+	}
+
+	if (enable || disable) {
+		status = video_outputsw_get();
+		if (status < 0)
+			return status;
+		res = video_outputsw_set((status & ~disable) | enable);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct video_driver_data = {
+	.name = "video",
+	.read = video_read,
+	.write = video_write,
+	.exit = video_exit,
+};
+
+/*************************************************************************
+ * Light (thinklight) subdriver
+ */
+
+IBM_HANDLE(lght, root, "\\LGHT");	/* A21e, A2xm/p, T20-22, X20-21 */
+IBM_HANDLE(ledb, ec, "LEDB");		/* G4x */
+
+static int __init light_init(struct ibm_init_struct *iibm)
+{
+	vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(ledb);
+	IBM_ACPIHANDLE_INIT(lght);
+	IBM_ACPIHANDLE_INIT(cmos);
+
+	/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
+	tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
+
+	if (tp_features.light)
+		/* light status not supported on
+		   570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
+		tp_features.light_status =
+			acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+	vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
+		str_supported(tp_features.light));
+
+	return (tp_features.light)? 0 : 1;
+}
+
+static int light_read(char *p)
+{
+	int len = 0;
+	int status = 0;
+
+	if (!tp_features.light) {
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	} else if (!tp_features.light_status) {
+		len += sprintf(p + len, "status:\t\tunknown\n");
+		len += sprintf(p + len, "commands:\ton, off\n");
+	} else {
+		if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+			return -EIO;
+		len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+		len += sprintf(p + len, "commands:\ton, off\n");
+	}
+
+	return len;
+}
+
+static int light_write(char *buf)
+{
+	int cmos_cmd, lght_cmd;
+	char *cmd;
+	int success;
+
+	if (!tp_features.light)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "on") == 0) {
+			cmos_cmd = 0x0c;
+			lght_cmd = 1;
+		} else if (strlencmp(cmd, "off") == 0) {
+			cmos_cmd = 0x0d;
+			lght_cmd = 0;
+		} else
+			return -EINVAL;
+
+		success = cmos_handle ?
+		    acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+		    acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+		if (!success)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct light_driver_data = {
+	.name = "light",
+	.read = light_read,
+	.write = light_write,
+};
+
+/*************************************************************************
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+
+IBM_HANDLE(dock, root, "\\_SB.GDCK",	/* X30, X31, X40 */
+	   "\\_SB.PCI0.DOCK",	/* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
+	   "\\_SB.PCI0.PCI1.DOCK",	/* all others */
+	   "\\_SB.PCI.ISA.SLCE",	/* 570 */
+    );				/* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
+
+/* don't list other alternatives as we install a notify handler on the 570 */
+IBM_HANDLE(pci, root, "\\_SB.PCI");	/* 570 */
+
+static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
+	{
+	 .notify = dock_notify,
+	 .handle = &dock_handle,
+	 .type = ACPI_SYSTEM_NOTIFY,
+	},
+	{
+	 .hid = IBM_PCI_HID,
+	 .notify = dock_notify,
+	 .handle = &pci_handle,
+	 .type = ACPI_SYSTEM_NOTIFY,
+	},
+};
+
+static struct ibm_struct dock_driver_data[2] = {
+	{
+	 .name = "dock",
+	 .read = dock_read,
+	 .write = dock_write,
+	 .acpi = &ibm_dock_acpidriver[0],
+	},
+	{
+	 .name = "dock",
+	 .acpi = &ibm_dock_acpidriver[1],
+	},
+};
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int __init dock_init(struct ibm_init_struct *iibm)
+{
+	vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(dock);
+
+	vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
+		str_supported(dock_handle != NULL));
+
+	return (dock_handle)? 0 : 1;
+}
+
+static int __init dock_init2(struct ibm_init_struct *iibm)
+{
+	int dock2_needed;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
+
+	if (dock_driver_data[0].flags.acpi_driver_registered &&
+	    dock_driver_data[0].flags.acpi_notify_installed) {
+		IBM_ACPIHANDLE_INIT(pci);
+		dock2_needed = (pci_handle != NULL);
+		vdbg_printk(TPACPI_DBG_INIT,
+			    "dock PCI handler for the TP 570 is %s\n",
+			    str_supported(dock2_needed));
+	} else {
+		vdbg_printk(TPACPI_DBG_INIT,
+		"dock subdriver part 2 not required\n");
+		dock2_needed = 0;
+	}
+
+	return (dock2_needed)? 0 : 1;
+}
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+	int docked = dock_docked();
+	int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+
+	if (event == 1 && !pci)	/* 570 */
+		acpi_bus_generate_event(ibm->acpi->device, event, 1);	/* button */
+	else if (event == 1 && pci)	/* 570 */
+		acpi_bus_generate_event(ibm->acpi->device, event, 3);	/* dock */
+	else if (event == 3 && docked)
+		acpi_bus_generate_event(ibm->acpi->device, event, 1);	/* button */
+	else if (event == 3 && !docked)
+		acpi_bus_generate_event(ibm->acpi->device, event, 2);	/* undock */
+	else if (event == 0 && docked)
+		acpi_bus_generate_event(ibm->acpi->device, event, 3);	/* dock */
+	else {
+		printk(IBM_ERR "unknown dock event %d, status %d\n",
+		       event, _sta(dock_handle));
+		acpi_bus_generate_event(ibm->acpi->device, event, 0);	/* unknown */
+	}
+}
+
+static int dock_read(char *p)
+{
+	int len = 0;
+	int docked = dock_docked();
+
+	if (!dock_handle)
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	else if (!docked)
+		len += sprintf(p + len, "status:\t\tundocked\n");
+	else {
+		len += sprintf(p + len, "status:\t\tdocked\n");
+		len += sprintf(p + len, "commands:\tdock, undock\n");
+	}
+
+	return len;
+}
+
+static int dock_write(char *buf)
+{
+	char *cmd;
+
+	if (!dock_docked())
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (strlencmp(cmd, "undock") == 0) {
+			if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
+			    !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+				return -EIO;
+		} else if (strlencmp(cmd, "dock") == 0) {
+			if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+				return -EIO;
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+/*************************************************************************
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",	/* 570 */
+	   "\\_SB.PCI0.IDE0.IDES.IDSM",	/* 600e/x, 770e, 770x */
+	   "\\_SB.PCI0.SATA.SCND.MSTR",	/* T60, X60, Z60 */
+	   "\\_SB.PCI0.IDE0.SCND.MSTR",	/* all others */
+	   );				/* A21e, R30, R31 */
+IBM_HANDLE(bay_ej, bay, "_EJ3",	/* 600e/x, A2xm/p, A3x */
+	   "_EJ0",		/* all others */
+	   );			/* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
+IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV",	/* A3x, R32 */
+	   "\\_SB.PCI0.IDE0.IDEP.IDPS",	/* 600e/x, 770e, 770x */
+	   );				/* all others */
+IBM_HANDLE(bay2_ej, bay2, "_EJ3",	/* 600e/x, 770e, A3x */
+	   "_EJ0",			/* 770x */
+	   );				/* all others */
+
+static int __init bay_init(struct ibm_init_struct *iibm)
+{
+	vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(bay);
+	if (bay_handle)
+		IBM_ACPIHANDLE_INIT(bay_ej);
+	IBM_ACPIHANDLE_INIT(bay2);
+	if (bay2_handle)
+		IBM_ACPIHANDLE_INIT(bay2_ej);
+
+	tp_features.bay_status = bay_handle &&
+		acpi_evalf(bay_handle, NULL, "_STA", "qv");
+	tp_features.bay_status2 = bay2_handle &&
+		acpi_evalf(bay2_handle, NULL, "_STA", "qv");
+
+	tp_features.bay_eject = bay_handle && bay_ej_handle &&
+		(strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
+	tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
+		(strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
+
+	vdbg_printk(TPACPI_DBG_INIT,
+		"bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
+		str_supported(tp_features.bay_status),
+		str_supported(tp_features.bay_eject),
+		str_supported(tp_features.bay_status2),
+		str_supported(tp_features.bay_eject2));
+
+	return (tp_features.bay_status || tp_features.bay_eject ||
+		tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
+}
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+	acpi_bus_generate_event(ibm->acpi->device, event, 0);
+}
+
+#define bay_occupied(b) (_sta(b##_handle) & 1)
+
+static int bay_read(char *p)
+{
+	int len = 0;
+	int occupied = bay_occupied(bay);
+	int occupied2 = bay_occupied(bay2);
+	int eject, eject2;
+
+	len += sprintf(p + len, "status:\t\t%s\n",
+		tp_features.bay_status ?
+			(occupied ? "occupied" : "unoccupied") :
+				"not supported");
+	if (tp_features.bay_status2)
+		len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
+			       "occupied" : "unoccupied");
+
+	eject = tp_features.bay_eject && occupied;
+	eject2 = tp_features.bay_eject2 && occupied2;
+
+	if (eject && eject2)
+		len += sprintf(p + len, "commands:\teject, eject2\n");
+	else if (eject)
+		len += sprintf(p + len, "commands:\teject\n");
+	else if (eject2)
+		len += sprintf(p + len, "commands:\teject2\n");
+
+	return len;
+}
+
+static int bay_write(char *buf)
+{
+	char *cmd;
+
+	if (!tp_features.bay_eject && !tp_features.bay_eject2)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
+			if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
+				return -EIO;
+		} else if (tp_features.bay_eject2 &&
+			   strlencmp(cmd, "eject2") == 0) {
+			if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
+				return -EIO;
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
+	.notify = bay_notify,
+	.handle = &bay_handle,
+	.type = ACPI_SYSTEM_NOTIFY,
+};
+
+static struct ibm_struct bay_driver_data = {
+	.name = "bay",
+	.read = bay_read,
+	.write = bay_write,
+	.acpi = &ibm_bay_acpidriver,
+};
+
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+/*************************************************************************
+ * CMOS subdriver
+ */
+
+/* sysfs cmos_command -------------------------------------------------- */
+static ssize_t cmos_command_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned long cmos_cmd;
+	int res;
+
+	if (parse_strtoul(buf, 21, &cmos_cmd))
+		return -EINVAL;
+
+	res = issue_thinkpad_cmos_command(cmos_cmd);
+	return (res)? res : count;
+}
+
+static struct device_attribute dev_attr_cmos_command =
+	__ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
+
+/* --------------------------------------------------------------------- */
+
+static int __init cmos_init(struct ibm_init_struct *iibm)
+{
+	int res;
+
+	vdbg_printk(TPACPI_DBG_INIT,
+		"initializing cmos commands subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(cmos);
+
+	vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
+		str_supported(cmos_handle != NULL));
+
+	res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+	if (res)
+		return res;
+
+	return (cmos_handle)? 0 : 1;
+}
+
+static void cmos_exit(void)
+{
+	device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+}
+
+static int cmos_read(char *p)
+{
+	int len = 0;
+
+	/* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+	   R30, R31, T20-22, X20-21 */
+	if (!cmos_handle)
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	else {
+		len += sprintf(p + len, "status:\t\tsupported\n");
+		len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
+	}
+
+	return len;
+}
+
+static int cmos_write(char *buf)
+{
+	char *cmd;
+	int cmos_cmd, res;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
+		    cmos_cmd >= 0 && cmos_cmd <= 21) {
+			/* cmos_cmd set */
+		} else
+			return -EINVAL;
+
+		res = issue_thinkpad_cmos_command(cmos_cmd);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct cmos_driver_data = {
+	.name = "cmos",
+	.read = cmos_read,
+	.write = cmos_write,
+	.exit = cmos_exit,
+};
+
+/*************************************************************************
+ * LED subdriver
+ */
+
+static enum led_access_mode led_supported;
+
+IBM_HANDLE(led, ec, "SLED",	/* 570 */
+	   "SYSL",		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+	   "LED",		/* all others */
+	   );			/* R30, R31 */
+
+static int __init led_init(struct ibm_init_struct *iibm)
+{
+	vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(led);
+
+	if (!led_handle)
+		/* led not supported on R30, R31 */
+		led_supported = TPACPI_LED_NONE;
+	else if (strlencmp(led_path, "SLED") == 0)
+		/* 570 */
+		led_supported = TPACPI_LED_570;
+	else if (strlencmp(led_path, "SYSL") == 0)
+		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+		led_supported = TPACPI_LED_OLD;
+	else
+		/* all others */
+		led_supported = TPACPI_LED_NEW;
+
+	vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
+		str_supported(led_supported), led_supported);
+
+	return (led_supported != TPACPI_LED_NONE)? 0 : 1;
+}
+
+#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+
+static int led_read(char *p)
+{
+	int len = 0;
+
+	if (!led_supported) {
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+		return len;
+	}
+	len += sprintf(p + len, "status:\t\tsupported\n");
+
+	if (led_supported == TPACPI_LED_570) {
+		/* 570 */
+		int i, status;
+		for (i = 0; i < 8; i++) {
+			if (!acpi_evalf(ec_handle,
+					&status, "GLED", "dd", 1 << i))
+				return -EIO;
+			len += sprintf(p + len, "%d:\t\t%s\n",
+				       i, led_status(status));
+		}
+	}
+
+	len += sprintf(p + len, "commands:\t"
+		       "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
+
+	return len;
+}
+
+/* off, on, blink */
+static const int led_sled_arg1[] = { 0, 1, 3 };
+static const int led_exp_hlbl[] = { 0, 0, 1 };	/* led# * */
+static const int led_exp_hlcl[] = { 0, 1, 1 };	/* led# * */
+static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+static int led_write(char *buf)
+{
+	char *cmd;
+	int led, ind, ret;
+
+	if (!led_supported)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
+			return -EINVAL;
+
+		if (strstr(cmd, "off")) {
+			ind = 0;
+		} else if (strstr(cmd, "on")) {
+			ind = 1;
+		} else if (strstr(cmd, "blink")) {
+			ind = 2;
+		} else
+			return -EINVAL;
+
+		if (led_supported == TPACPI_LED_570) {
+			/* 570 */
+			led = 1 << led;
+			if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+					led, led_sled_arg1[ind]))
+				return -EIO;
+		} else if (led_supported == TPACPI_LED_OLD) {
+			/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+			led = 1 << led;
+			ret = ec_write(TPACPI_LED_EC_HLMS, led);
+			if (ret >= 0)
+				ret =
+				    ec_write(TPACPI_LED_EC_HLBL,
+				    	     led * led_exp_hlbl[ind]);
+			if (ret >= 0)
+				ret =
+				    ec_write(TPACPI_LED_EC_HLCL,
+				    	     led * led_exp_hlcl[ind]);
+			if (ret < 0)
+				return ret;
+		} else {
+			/* all others */
+			if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+					led, led_led_arg1[ind]))
+				return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static struct ibm_struct led_driver_data = {
+	.name = "led",
+	.read = led_read,
+	.write = led_write,
+};
+
+/*************************************************************************
+ * Beep subdriver
+ */
+
+IBM_HANDLE(beep, ec, "BEEP");	/* all except R30, R31 */
+
+static int __init beep_init(struct ibm_init_struct *iibm)
+{
+	vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
+
+	IBM_ACPIHANDLE_INIT(beep);
+
+	vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
+		str_supported(beep_handle != NULL));
+
+	return (beep_handle)? 0 : 1;
+}
+
+static int beep_read(char *p)
+{
+	int len = 0;
+
+	if (!beep_handle)
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	else {
+		len += sprintf(p + len, "status:\t\tsupported\n");
+		len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
+	}
+
+	return len;
+}
+
+static int beep_write(char *buf)
+{
+	char *cmd;
+	int beep_cmd;
+
+	if (!beep_handle)
+		return -ENODEV;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
+		    beep_cmd >= 0 && beep_cmd <= 17) {
+			/* beep_cmd set */
+		} else
+			return -EINVAL;
+		if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct beep_driver_data = {
+	.name = "beep",
+	.read = beep_read,
+	.write = beep_write,
+};
+
+/*************************************************************************
+ * Thermal subdriver
+ */
+
+static enum thermal_access_mode thermal_read_mode;
+
+/* sysfs temp##_input -------------------------------------------------- */
+
+static ssize_t thermal_temp_input_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct sensor_device_attribute *sensor_attr =
+					to_sensor_dev_attr(attr);
+	int idx = sensor_attr->index;
+	s32 value;
+	int res;
+
+	res = thermal_get_sensor(idx, &value);
+	if (res)
+		return res;
+	if (value == TP_EC_THERMAL_TMP_NA * 1000)
+		return -ENXIO;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
+	 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
+
+static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
+	THERMAL_SENSOR_ATTR_TEMP(1, 0),
+	THERMAL_SENSOR_ATTR_TEMP(2, 1),
+	THERMAL_SENSOR_ATTR_TEMP(3, 2),
+	THERMAL_SENSOR_ATTR_TEMP(4, 3),
+	THERMAL_SENSOR_ATTR_TEMP(5, 4),
+	THERMAL_SENSOR_ATTR_TEMP(6, 5),
+	THERMAL_SENSOR_ATTR_TEMP(7, 6),
+	THERMAL_SENSOR_ATTR_TEMP(8, 7),
+	THERMAL_SENSOR_ATTR_TEMP(9, 8),
+	THERMAL_SENSOR_ATTR_TEMP(10, 9),
+	THERMAL_SENSOR_ATTR_TEMP(11, 10),
+	THERMAL_SENSOR_ATTR_TEMP(12, 11),
+	THERMAL_SENSOR_ATTR_TEMP(13, 12),
+	THERMAL_SENSOR_ATTR_TEMP(14, 13),
+	THERMAL_SENSOR_ATTR_TEMP(15, 14),
+	THERMAL_SENSOR_ATTR_TEMP(16, 15),
+};
+
+#define THERMAL_ATTRS(X) \
+	&sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
+
+static struct attribute *thermal_temp_input_attr[] = {
+	THERMAL_ATTRS(8),
+	THERMAL_ATTRS(9),
+	THERMAL_ATTRS(10),
+	THERMAL_ATTRS(11),
+	THERMAL_ATTRS(12),
+	THERMAL_ATTRS(13),
+	THERMAL_ATTRS(14),
+	THERMAL_ATTRS(15),
+	THERMAL_ATTRS(0),
+	THERMAL_ATTRS(1),
+	THERMAL_ATTRS(2),
+	THERMAL_ATTRS(3),
+	THERMAL_ATTRS(4),
+	THERMAL_ATTRS(5),
+	THERMAL_ATTRS(6),
+	THERMAL_ATTRS(7),
+	NULL
+};
+
+static const struct attribute_group thermal_temp_input16_group = {
+	.attrs = thermal_temp_input_attr
+};
+
+static const struct attribute_group thermal_temp_input8_group = {
+	.attrs = &thermal_temp_input_attr[8]
+};
+
+#undef THERMAL_SENSOR_ATTR_TEMP
+#undef THERMAL_ATTRS
+
+/* --------------------------------------------------------------------- */
+
+static int __init thermal_init(struct ibm_init_struct *iibm)
+{
+	u8 t, ta1, ta2;
+	int i;
+	int acpi_tmp7;
+	int res;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
+
+	acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+
+	if (ibm_thinkpad_ec_found && experimental) {
+		/*
+		 * Direct EC access mode: sensors at registers
+		 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
+		 * non-implemented, thermal sensors return 0x80 when
+		 * not available
+		 */
+
+		ta1 = ta2 = 0;
+		for (i = 0; i < 8; i++) {
+			if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
+				ta1 |= t;
+			} else {
+				ta1 = 0;
+				break;
+			}
+			if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
+				ta2 |= t;
+			} else {
+				ta1 = 0;
+				break;
+			}
+		}
+		if (ta1 == 0) {
+			/* This is sheer paranoia, but we handle it anyway */
+			if (acpi_tmp7) {
+				printk(IBM_ERR
+				       "ThinkPad ACPI EC access misbehaving, "
+				       "falling back to ACPI TMPx access mode\n");
+				thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+			} else {
+				printk(IBM_ERR
+				       "ThinkPad ACPI EC access misbehaving, "
+				       "disabling thermal sensors access\n");
+				thermal_read_mode = TPACPI_THERMAL_NONE;
+			}
+		} else {
+			thermal_read_mode =
+			    (ta2 != 0) ?
+			    TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
+		}
+	} else if (acpi_tmp7) {
+		if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+			/* 600e/x, 770e, 770x */
+			thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
+		} else {
+			/* Standard ACPI TMPx access, max 8 sensors */
+			thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+		}
+	} else {
+		/* temperatures not supported on 570, G4x, R30, R31, R32 */
+		thermal_read_mode = TPACPI_THERMAL_NONE;
+	}
+
+	vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
+		str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
+		thermal_read_mode);
+
+	switch(thermal_read_mode) {
+	case TPACPI_THERMAL_TPEC_16:
+		res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+				&thermal_temp_input16_group);
+		if (res)
+			return res;
+		break;
+	case TPACPI_THERMAL_TPEC_8:
+	case TPACPI_THERMAL_ACPI_TMP07:
+	case TPACPI_THERMAL_ACPI_UPDT:
+		res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+				&thermal_temp_input8_group);
+		if (res)
+			return res;
+		break;
+	case TPACPI_THERMAL_NONE:
+	default:
+		return 1;
+	}
+
+	return 0;
+}
+
+static void thermal_exit(void)
+{
+	switch(thermal_read_mode) {
+	case TPACPI_THERMAL_TPEC_16:
+		sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+				   &thermal_temp_input16_group);
+		break;
+	case TPACPI_THERMAL_TPEC_8:
+	case TPACPI_THERMAL_ACPI_TMP07:
+	case TPACPI_THERMAL_ACPI_UPDT:
+		sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+				   &thermal_temp_input16_group);
+		break;
+	case TPACPI_THERMAL_NONE:
+	default:
+		break;
+	}
+}
+
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
+{
+	int t;
+	s8 tmp;
+	char tmpi[5];
+
+	t = TP_EC_THERMAL_TMP0;
+
+	switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+	case TPACPI_THERMAL_TPEC_16:
+		if (idx >= 8 && idx <= 15) {
+			t = TP_EC_THERMAL_TMP8;
+			idx -= 8;
+		}
+		/* fallthrough */
+#endif
+	case TPACPI_THERMAL_TPEC_8:
+		if (idx <= 7) {
+			if (!acpi_ec_read(t + idx, &tmp))
+				return -EIO;
+			*value = tmp * 1000;
+			return 0;
+		}
+		break;
+
+	case TPACPI_THERMAL_ACPI_UPDT:
+		if (idx <= 7) {
+			snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+			if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+				return -EIO;
+			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+				return -EIO;
+			*value = (t - 2732) * 100;
+			return 0;
+		}
+		break;
+
+	case TPACPI_THERMAL_ACPI_TMP07:
+		if (idx <= 7) {
+			snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+				return -EIO;
+			*value = t * 1000;
+			return 0;
+		}
+		break;
+
+	case TPACPI_THERMAL_NONE:
+	default:
+		return -ENOSYS;
+	}
+
+	return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+	int res, i;
+	int n;
+
+	n = 8;
+	i = 0;
+
+	if (!s)
+		return -EINVAL;
+
+	if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+		n = 16;
+
+	for(i = 0 ; i < n; i++) {
+		res = thermal_get_sensor(i, &s->temp[i]);
+		if (res)
+			return res;
+	}
+
+	return n;
+}
+
+static int thermal_read(char *p)
+{
+	int len = 0;
+	int n, i;
+	struct ibm_thermal_sensors_struct t;
+
+	n = thermal_get_sensors(&t);
+	if (unlikely(n < 0))
+		return n;
+
+	len += sprintf(p + len, "temperatures:\t");
+
+	if (n > 0) {
+		for (i = 0; i < (n - 1); i++)
+			len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+		len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+	} else
+		len += sprintf(p + len, "not supported\n");
+
+	return len;
+}
+
+static struct ibm_struct thermal_driver_data = {
+	.name = "thermal",
+	.read = thermal_read,
+	.exit = thermal_exit,
+};
+
+/*************************************************************************
+ * EC Dump subdriver
+ */
+
+static u8 ecdump_regs[256];
+
+static int ecdump_read(char *p)
+{
+	int len = 0;
+	int i, j;
+	u8 v;
+
+	len += sprintf(p + len, "EC      "
+		       " +00 +01 +02 +03 +04 +05 +06 +07"
+		       " +08 +09 +0a +0b +0c +0d +0e +0f\n");
+	for (i = 0; i < 256; i += 16) {
+		len += sprintf(p + len, "EC 0x%02x:", i);
+		for (j = 0; j < 16; j++) {
+			if (!acpi_ec_read(i + j, &v))
+				break;
+			if (v != ecdump_regs[i + j])
+				len += sprintf(p + len, " *%02x", v);
+			else
+				len += sprintf(p + len, "  %02x", v);
+			ecdump_regs[i + j] = v;
+		}
+		len += sprintf(p + len, "\n");
+		if (j != 16)
+			break;
+	}
+
+	/* These are way too dangerous to advertise openly... */
+#if 0
+	len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
+		       " (<offset> is 00-ff, <value> is 00-ff)\n");
+	len += sprintf(p + len, "commands:\t0x<offset> <value>  "
+		       " (<offset> is 00-ff, <value> is 0-255)\n");
+#endif
+	return len;
+}
+
+static int ecdump_write(char *buf)
+{
+	char *cmd;
+	int i, v;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
+			/* i and v set */
+		} else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
+			/* i and v set */
+		} else
+			return -EINVAL;
+		if (i >= 0 && i < 256 && v >= 0 && v < 256) {
+			if (!acpi_ec_write(i, v))
+				return -EIO;
+		} else
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct ibm_struct ecdump_driver_data = {
+	.name = "ecdump",
+	.read = ecdump_read,
+	.write = ecdump_write,
+	.flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Backlight/brightness subdriver
+ */
+
+static struct backlight_device *ibm_backlight_device = NULL;
+
+static struct backlight_ops ibm_backlight_data = {
+        .get_brightness = brightness_get,
+        .update_status  = brightness_update_status,
+};
+
+static int __init brightness_init(struct ibm_init_struct *iibm)
+{
+	int b;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+
+	b = brightness_get(NULL);
+	if (b < 0)
+		return b;
+
+	ibm_backlight_device = backlight_device_register(
+					TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
+					&ibm_backlight_data);
+	if (IS_ERR(ibm_backlight_device)) {
+		printk(IBM_ERR "Could not register backlight device\n");
+		return PTR_ERR(ibm_backlight_device);
+	}
+	vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
+
+	ibm_backlight_device->props.max_brightness = 7;
+	ibm_backlight_device->props.brightness = b;
+	backlight_update_status(ibm_backlight_device);
+
+	return 0;
+}
+
+static void brightness_exit(void)
+{
+	if (ibm_backlight_device) {
+		vdbg_printk(TPACPI_DBG_EXIT,
+			    "calling backlight_device_unregister()\n");
+		backlight_device_unregister(ibm_backlight_device);
+		ibm_backlight_device = NULL;
+	}
+}
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+	return brightness_set(
+		(bd->props.fb_blank == FB_BLANK_UNBLANK &&
+		 bd->props.power == FB_BLANK_UNBLANK) ?
+				bd->props.brightness : 0);
+}
+
+static int brightness_get(struct backlight_device *bd)
+{
+	u8 level;
+	if (!acpi_ec_read(brightness_offset, &level))
+		return -EIO;
+
+	level &= 0x7;
+
+	return level;
+}
+
+static int brightness_set(int value)
+{
+	int cmos_cmd, inc, i;
+	int current_value = brightness_get(NULL);
+
+	value &= 7;
+
+	cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+	inc = value > current_value ? 1 : -1;
+	for (i = current_value; i != value; i += inc) {
+		if (issue_thinkpad_cmos_command(cmos_cmd))
+			return -EIO;
+		if (!acpi_ec_write(brightness_offset, i + inc))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int brightness_read(char *p)
+{
+	int len = 0;
+	int level;
+
+	if ((level = brightness_get(NULL)) < 0) {
+		len += sprintf(p + len, "level:\t\tunreadable\n");
+	} else {
+		len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+		len += sprintf(p + len, "commands:\tup, down\n");
+		len += sprintf(p + len, "commands:\tlevel <level>"
+			       " (<level> is 0-7)\n");
+	}
+
+	return len;
+}
+
+static int brightness_write(char *buf)
+{
+	int level;
+	int new_level;
+	char *cmd;
+
+	while ((cmd = next_cmd(&buf))) {
+		if ((level = brightness_get(NULL)) < 0)
+			return level;
+		level &= 7;
+
+		if (strlencmp(cmd, "up") == 0) {
+			new_level = level == 7 ? 7 : level + 1;
+		} else if (strlencmp(cmd, "down") == 0) {
+			new_level = level == 0 ? 0 : level - 1;
+		} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+			   new_level >= 0 && new_level <= 7) {
+			/* new_level set */
+		} else
+			return -EINVAL;
+
+		brightness_set(new_level);
+	}
+
+	return 0;
+}
+
+static struct ibm_struct brightness_driver_data = {
+	.name = "brightness",
+	.read = brightness_read,
+	.write = brightness_write,
+	.exit = brightness_exit,
+};
+
+/*************************************************************************
+ * Volume subdriver
+ */
+
+static int volume_read(char *p)
+{
+	int len = 0;
+	u8 level;
+
+	if (!acpi_ec_read(volume_offset, &level)) {
+		len += sprintf(p + len, "level:\t\tunreadable\n");
+	} else {
+		len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
+		len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
+		len += sprintf(p + len, "commands:\tup, down, mute\n");
+		len += sprintf(p + len, "commands:\tlevel <level>"
+			       " (<level> is 0-15)\n");
+	}
+
+	return len;
+}
+
+static int volume_write(char *buf)
+{
+	int cmos_cmd, inc, i;
+	u8 level, mute;
+	int new_level, new_mute;
+	char *cmd;
+
+	while ((cmd = next_cmd(&buf))) {
+		if (!acpi_ec_read(volume_offset, &level))
+			return -EIO;
+		new_mute = mute = level & 0x40;
+		new_level = level = level & 0xf;
+
+		if (strlencmp(cmd, "up") == 0) {
+			if (mute)
+				new_mute = 0;
+			else
+				new_level = level == 15 ? 15 : level + 1;
+		} else if (strlencmp(cmd, "down") == 0) {
+			if (mute)
+				new_mute = 0;
+			else
+				new_level = level == 0 ? 0 : level - 1;
+		} else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+			   new_level >= 0 && new_level <= 15) {
+			/* new_level set */
+		} else if (strlencmp(cmd, "mute") == 0) {
+			new_mute = 0x40;
+		} else
+			return -EINVAL;
+
+		if (new_level != level) {	/* mute doesn't change */
+			cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+			inc = new_level > level ? 1 : -1;
+
+			if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
+				     !acpi_ec_write(volume_offset, level)))
+				return -EIO;
+
+			for (i = level; i != new_level; i += inc)
+				if (issue_thinkpad_cmos_command(cmos_cmd) ||
+				    !acpi_ec_write(volume_offset, i + inc))
+					return -EIO;
+
+			if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+				     !acpi_ec_write(volume_offset,
+						    new_level + mute)))
+				return -EIO;
+		}
+
+		if (new_mute != mute) {	/* level doesn't change */
+			cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+
+			if (issue_thinkpad_cmos_command(cmos_cmd) ||
+			    !acpi_ec_write(volume_offset, level + new_mute))
+				return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static struct ibm_struct volume_driver_data = {
+	.name = "volume",
+	.read = volume_read,
+	.write = volume_write,
+};
+
+/*************************************************************************
+ * Fan subdriver
+ */
+
+/*
+ * FAN ACCESS MODES
+ *
+ * TPACPI_FAN_RD_ACPI_GFAN:
+ * 	ACPI GFAN method: returns fan level
+ *
+ * 	see TPACPI_FAN_WR_ACPI_SFAN
+ * 	EC 0x2f (HFSP) not available if GFAN exists
+ *
+ * TPACPI_FAN_WR_ACPI_SFAN:
+ * 	ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * 	EC 0x2f (HFSP) might be available *for reading*, but do not use
+ * 	it for writing.
+ *
+ * TPACPI_FAN_WR_TPEC:
+ * 	ThinkPad EC register 0x2f (HFSP): fan control loop mode
+ * 	Supported on almost all ThinkPads
+ *
+ * 	Fan speed changes of any sort (including those caused by the
+ * 	disengaged mode) are usually done slowly by the firmware as the
+ * 	maximum ammount of fan duty cycle change per second seems to be
+ * 	limited.
+ *
+ * 	Reading is not available if GFAN exists.
+ * 	Writing is not available if SFAN exists.
+ *
+ * 	Bits
+ *	 7	automatic mode engaged;
+ *  		(default operation mode of the ThinkPad)
+ * 		fan level is ignored in this mode.
+ *	 6	full speed mode (takes precedence over bit 7);
+ *		not available on all thinkpads.  May disable
+ *		the tachometer while the fan controller ramps up
+ *		the speed (which can take up to a few *minutes*).
+ *		Speeds up fan to 100% duty-cycle, which is far above
+ *		the standard RPM levels.  It is not impossible that
+ *		it could cause hardware damage.
+ *	5-3	unused in some models.  Extra bits for fan level
+ *		in others, but still useless as all values above
+ *		7 map to the same speed as level 7 in these models.
+ *	2-0	fan level (0..7 usually)
+ *			0x00 = stop
+ * 			0x07 = max (set when temperatures critical)
+ * 		Some ThinkPads may have other levels, see
+ * 		TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ *	FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ *	boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ *	does so, its initial value is meaningless (0x07).
+ *
+ *	For firmware bugs, refer to:
+ *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * 	----
+ *
+ *	ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ *	Main fan tachometer reading (in RPM)
+ *
+ *	This register is present on all ThinkPads with a new-style EC, and
+ *	it is known not to be present on the A21m/e, and T22, as there is
+ *	something else in offset 0x84 according to the ACPI DSDT.  Other
+ *	ThinkPads from this same time period (and earlier) probably lack the
+ *	tachometer as well.
+ *
+ *	Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ *	was never fixed by IBM to report the EC firmware version string
+ *	probably support the tachometer (like the early X models), so
+ *	detecting it is quite hard.  We need more data to know for sure.
+ *
+ *	FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ *	might result.
+ *
+ *	FIRMWARE BUG: may go stale while the EC is switching to full speed
+ *	mode.
+ *
+ *	For firmware bugs, refer to:
+ *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * TPACPI_FAN_WR_ACPI_FANS:
+ *	ThinkPad X31, X40, X41.  Not available in the X60.
+ *
+ *	FANS ACPI handle: takes three arguments: low speed, medium speed,
+ *	high speed.  ACPI DSDT seems to map these three speeds to levels
+ *	as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ *	(this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * 	The speeds are stored on handles
+ * 	(FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * 	There are three default speed sets, acessible as handles:
+ * 	FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * 	ACPI DSDT switches which set is in use depending on various
+ * 	factors.
+ *
+ * 	TPACPI_FAN_WR_TPEC is also available and should be used to
+ * 	command the fan.  The X31/X40/X41 seems to have 8 fan levels,
+ * 	but the ACPI tables just mention level 7.
+ */
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+IBM_HANDLE(fans, ec, "FANS");	/* X31, X40, X41 */
+IBM_HANDLE(gfan, ec, "GFAN",	/* 570 */
+	   "\\FSPD",		/* 600e/x, 770e, 770x */
+	   );			/* all others */
+IBM_HANDLE(sfan, ec, "SFAN",	/* 570 */
+	   "JFNS",		/* 770x-JL */
+	   );			/* all others */
+
+/*
+ * SYSFS fan layout: hwmon compatible (device)
+ *
+ * pwm*_enable:
+ * 	0: "disengaged" mode
+ * 	1: manual mode
+ * 	2: native EC "auto" mode (recommended, hardware default)
+ *
+ * pwm*: set speed in manual mode, ignored otherwise.
+ * 	0 is level 0; 255 is level 7. Intermediate points done with linear
+ * 	interpolation.
+ *
+ * fan*_input: tachometer reading, RPM
+ *
+ *
+ * SYSFS fan layout: extensions
+ *
+ * fan_watchdog (driver):
+ * 	fan watchdog interval in seconds, 0 disables (default), max 120
+ */
+
+/* sysfs fan pwm1_enable ----------------------------------------------- */
+static ssize_t fan_pwm1_enable_show(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	int res, mode;
+	u8 status;
+
+	res = fan_get_status_safe(&status);
+	if (res)
+		return res;
+
+	if (unlikely(tp_features.fan_ctrl_status_undef)) {
+		if (status != fan_control_initial_status) {
+			tp_features.fan_ctrl_status_undef = 0;
+		} else {
+			/* Return most likely status. In fact, it
+			 * might be the only possible status */
+			status = TP_EC_FAN_AUTO;
+		}
+	}
+
+	if (status & TP_EC_FAN_FULLSPEED) {
+		mode = 0;
+	} else if (status & TP_EC_FAN_AUTO) {
+		mode = 2;
+	} else
+		mode = 1;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t fan_pwm1_enable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	unsigned long t;
+	int res, level;
+
+	if (parse_strtoul(buf, 2, &t))
+		return -EINVAL;
+
+	switch (t) {
+	case 0:
+		level = TP_EC_FAN_FULLSPEED;
+		break;
+	case 1:
+		level = TPACPI_FAN_LAST_LEVEL;
+		break;
+	case 2:
+		level = TP_EC_FAN_AUTO;
+		break;
+	case 3:
+		/* reserved for software-controlled auto mode */
+		return -ENOSYS;
+	default:
+		return -EINVAL;
+	}
+
+	res = fan_set_level_safe(level);
+	if (res == -ENXIO)
+		return -EINVAL;
+	else if (res < 0)
+		return res;
+
+	fan_watchdog_reset();
+
+	return count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1_enable =
+	__ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+		fan_pwm1_enable_show, fan_pwm1_enable_store);
+
+/* sysfs fan pwm1 ------------------------------------------------------ */
+static ssize_t fan_pwm1_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	int res;
+	u8 status;
+
+	res = fan_get_status_safe(&status);
+	if (res)
+		return res;
+
+	if (unlikely(tp_features.fan_ctrl_status_undef)) {
+		if (status != fan_control_initial_status) {
+			tp_features.fan_ctrl_status_undef = 0;
+		} else {
+			status = TP_EC_FAN_AUTO;
+		}
+	}
+
+	if ((status &
+	     (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
+		status = fan_control_desired_level;
+
+	if (status > 7)
+		status = 7;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
+}
+
+static ssize_t fan_pwm1_store(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	unsigned long s;
+	int rc;
+	u8 status, newlevel;
+
+	if (parse_strtoul(buf, 255, &s))
+		return -EINVAL;
+
+	/* scale down from 0-255 to 0-7 */
+	newlevel = (s >> 5) & 0x07;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+
+	rc = fan_get_status(&status);
+	if (!rc && (status &
+		    (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+		rc = fan_set_level(newlevel);
+		if (rc == -ENXIO)
+			rc = -EINVAL;
+		else if (!rc) {
+			fan_update_desired_level(newlevel);
+			fan_watchdog_reset();
+		}
+	}
+
+	mutex_unlock(&fan_mutex);
+	return (rc)? rc : count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1 =
+	__ATTR(pwm1, S_IWUSR | S_IRUGO,
+		fan_pwm1_show, fan_pwm1_store);
+
+/* sysfs fan fan1_input ------------------------------------------------ */
+static ssize_t fan_fan1_input_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res;
+	unsigned int speed;
+
+	res = fan_get_speed(&speed);
+	if (res < 0)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
+
+static struct device_attribute dev_attr_fan_fan1_input =
+	__ATTR(fan1_input, S_IRUGO,
+		fan_fan1_input_show, NULL);
+
+/* sysfs fan fan_watchdog (driver) ------------------------------------- */
+static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
+				     char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
+}
+
+static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
+				      const char *buf, size_t count)
+{
+	unsigned long t;
+
+	if (parse_strtoul(buf, 120, &t))
+		return -EINVAL;
+
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	fan_watchdog_maxinterval = t;
+	fan_watchdog_reset();
+
+	return count;
+}
+
+static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
+		fan_fan_watchdog_show, fan_fan_watchdog_store);
+
+/* --------------------------------------------------------------------- */
+static struct attribute *fan_attributes[] = {
+	&dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
+	&dev_attr_fan_fan1_input.attr,
+	NULL
+};
+
+static const struct attribute_group fan_attr_group = {
+	.attrs = fan_attributes,
+};
+
+static int __init fan_init(struct ibm_init_struct *iibm)
+{
+	int rc;
+
+	vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+
+	mutex_init(&fan_mutex);
+	fan_status_access_mode = TPACPI_FAN_NONE;
+	fan_control_access_mode = TPACPI_FAN_WR_NONE;
+	fan_control_commands = 0;
+	fan_watchdog_maxinterval = 0;
+	tp_features.fan_ctrl_status_undef = 0;
+	fan_control_desired_level = 7;
+
+	IBM_ACPIHANDLE_INIT(fans);
+	IBM_ACPIHANDLE_INIT(gfan);
+	IBM_ACPIHANDLE_INIT(sfan);
+
+	if (gfan_handle) {
+		/* 570, 600e/x, 770e, 770x */
+		fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+	} else {
+		/* all other ThinkPads: note that even old-style
+		 * ThinkPad ECs supports the fan control register */
+		if (likely(acpi_ec_read(fan_status_offset,
+					&fan_control_initial_status))) {
+			fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+
+			/* In some ThinkPads, neither the EC nor the ACPI
+			 * DSDT initialize the fan status, and it ends up
+			 * being set to 0x07 when it *could* be either
+			 * 0x07 or 0x80.
+			 *
+			 * Enable for TP-1Y (T43), TP-78 (R51e),
+			 * TP-76 (R52), TP-70 (T43, R52), which are known
+			 * to be buggy. */
+			if (fan_control_initial_status == 0x07 &&
+			    ibm_thinkpad_ec_found &&
+			    ((ibm_thinkpad_ec_found[0] == '1' &&
+			      ibm_thinkpad_ec_found[1] == 'Y') ||
+			     (ibm_thinkpad_ec_found[0] == '7' &&
+			      (ibm_thinkpad_ec_found[1] == '6' ||
+			       ibm_thinkpad_ec_found[1] == '8' ||
+			       ibm_thinkpad_ec_found[1] == '0'))
+			    )) {
+				printk(IBM_NOTICE
+				       "fan_init: initial fan status is "
+				       "unknown, assuming it is in auto "
+				       "mode\n");
+				tp_features.fan_ctrl_status_undef = 1;
+			}
+		} else {
+			printk(IBM_ERR
+			       "ThinkPad ACPI EC access misbehaving, "
+			       "fan status and control unavailable\n");
+			return 1;
+		}
+	}
+
+	if (sfan_handle) {
+		/* 570, 770x-JL */
+		fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
+		fan_control_commands |=
+		    TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+	} else {
+		if (!gfan_handle) {
+			/* gfan without sfan means no fan control */
+			/* all other models implement TP EC 0x2f control */
+
+			if (fans_handle) {
+				/* X31, X40, X41 */
+				fan_control_access_mode =
+				    TPACPI_FAN_WR_ACPI_FANS;
+				fan_control_commands |=
+				    TPACPI_FAN_CMD_SPEED |
+				    TPACPI_FAN_CMD_LEVEL |
+				    TPACPI_FAN_CMD_ENABLE;
+			} else {
+				fan_control_access_mode = TPACPI_FAN_WR_TPEC;
+				fan_control_commands |=
+				    TPACPI_FAN_CMD_LEVEL |
+				    TPACPI_FAN_CMD_ENABLE;
+			}
+		}
+	}
+
+	vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
+		str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
+		  fan_control_access_mode != TPACPI_FAN_WR_NONE),
+		fan_status_access_mode, fan_control_access_mode);
+
+	/* fan control master switch */
+	if (!fan_control_allowed) {
+		fan_control_access_mode = TPACPI_FAN_WR_NONE;
+		fan_control_commands = 0;
+		dbg_printk(TPACPI_DBG_INIT,
+			   "fan control features disabled by parameter\n");
+	}
+
+	/* update fan_control_desired_level */
+	if (fan_status_access_mode != TPACPI_FAN_NONE)
+		fan_get_status_safe(NULL);
+
+	if (fan_status_access_mode != TPACPI_FAN_NONE ||
+	    fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+		rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+					 &fan_attr_group);
+		if (!(rc < 0))
+			rc = driver_create_file(&tpacpi_pdriver.driver,
+					&driver_attr_fan_watchdog);
+		if (rc < 0)
+			return rc;
+		return 0;
+	} else
+		return 1;
+}
+
+/*
+ * Call with fan_mutex held
+ */
+static void fan_update_desired_level(u8 status)
+{
+	if ((status &
+	     (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+		if (status > 7)
+			fan_control_desired_level = 7;
+		else
+			fan_control_desired_level = status;
+	}
+}
+
+static int fan_get_status(u8 *status)
+{
+	u8 s;
+
+	/* TODO:
+	 * Add TPACPI_FAN_RD_ACPI_FANS ? */
+
+	switch (fan_status_access_mode) {
+	case TPACPI_FAN_RD_ACPI_GFAN:
+		/* 570, 600e/x, 770e, 770x */
+
+		if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+			return -EIO;
+
+		if (likely(status))
+			*status = s & 0x07;
+
+		break;
+
+	case TPACPI_FAN_RD_TPEC:
+		/* all except 570, 600e/x, 770e, 770x */
+		if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+			return -EIO;
+
+		if (likely(status))
+			*status = s;
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int fan_get_status_safe(u8 *status)
+{
+	int rc;
+	u8 s;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+	rc = fan_get_status(&s);
+	if (!rc)
+		fan_update_desired_level(s);
+	mutex_unlock(&fan_mutex);
+
+	if (status)
+		*status = s;
+
+	return rc;
+}
+
+static void fan_exit(void)
+{
+	vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+
+	/* FIXME: can we really do this unconditionally? */
+	sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
+	driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+
+	cancel_delayed_work(&fan_watchdog_task);
+	flush_scheduled_work();
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+	u8 hi, lo;
+
+	switch (fan_status_access_mode) {
+	case TPACPI_FAN_RD_TPEC:
+		/* all except 570, 600e/x, 770e, 770x */
+		if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+			     !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+			return -EIO;
+
+		if (likely(speed))
+			*speed = (hi << 8) | lo;
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+	int rc;
+
+	printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+	rc = fan_set_enable();
+	if (rc < 0) {
+		printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
+			"will try again later...\n", -rc);
+		/* reschedule for later */
+		fan_watchdog_reset();
+	}
+}
+
+static void fan_watchdog_reset(void)
+{
+	static int fan_watchdog_active = 0;
+
+	if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
+		return;
+
+	if (fan_watchdog_active)
+		cancel_delayed_work(&fan_watchdog_task);
+
+	if (fan_watchdog_maxinterval > 0) {
+		fan_watchdog_active = 1;
+		if (!schedule_delayed_work(&fan_watchdog_task,
+				msecs_to_jiffies(fan_watchdog_maxinterval
+						 * 1000))) {
+			printk(IBM_ERR "failed to schedule the fan watchdog, "
+			       "watchdog will not trigger\n");
+		}
+	} else
+		fan_watchdog_active = 0;
+}
+
+static int fan_set_level(int level)
+{
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	switch (fan_control_access_mode) {
+	case TPACPI_FAN_WR_ACPI_SFAN:
+		if (level >= 0 && level <= 7) {
+			if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+				return -EIO;
+		} else
+			return -EINVAL;
+		break;
+
+	case TPACPI_FAN_WR_ACPI_FANS:
+	case TPACPI_FAN_WR_TPEC:
+		if ((level != TP_EC_FAN_AUTO) &&
+		    (level != TP_EC_FAN_FULLSPEED) &&
+		    ((level < 0) || (level > 7)))
+			return -EINVAL;
+
+		/* safety net should the EC not support AUTO
+		 * or FULLSPEED mode bits and just ignore them */
+		if (level & TP_EC_FAN_FULLSPEED)
+			level |= 7;	/* safety min speed 7 */
+		else if (level & TP_EC_FAN_FULLSPEED)
+			level |= 4;	/* safety min speed 4 */
+
+		if (!acpi_ec_write(fan_status_offset, level))
+			return -EIO;
+		else
+			tp_features.fan_ctrl_status_undef = 0;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int fan_set_level_safe(int level)
+{
+	int rc;
+
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+
+	if (level == TPACPI_FAN_LAST_LEVEL)
+		level = fan_control_desired_level;
+
+	rc = fan_set_level(level);
+	if (!rc)
+		fan_update_desired_level(level);
+
+	mutex_unlock(&fan_mutex);
+	return rc;
+}
+
+static int fan_set_enable(void)
+{
+	u8 s;
+	int rc;
+
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+
+	switch (fan_control_access_mode) {
+	case TPACPI_FAN_WR_ACPI_FANS:
+	case TPACPI_FAN_WR_TPEC:
+		rc = fan_get_status(&s);
+		if (rc < 0)
+			break;
+
+		/* Don't go out of emergency fan mode */
+		if (s != 7) {
+			s &= 0x07;
+			s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+		}
+
+		if (!acpi_ec_write(fan_status_offset, s))
+			rc = -EIO;
+		else {
+			tp_features.fan_ctrl_status_undef = 0;
+			rc = 0;
+		}
+		break;
+
+	case TPACPI_FAN_WR_ACPI_SFAN:
+		rc = fan_get_status(&s);
+		if (rc < 0)
+			break;
+
+		s &= 0x07;
+
+		/* Set fan to at least level 4 */
+		s |= 4;
+
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+			rc= -EIO;
+		else
+			rc = 0;
+		break;
+
+	default:
+		rc = -ENXIO;
+	}
+
+	mutex_unlock(&fan_mutex);
+	return rc;
+}
+
+static int fan_set_disable(void)
+{
+	int rc;
+
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+
+	rc = 0;
+	switch (fan_control_access_mode) {
+	case TPACPI_FAN_WR_ACPI_FANS:
+	case TPACPI_FAN_WR_TPEC:
+		if (!acpi_ec_write(fan_status_offset, 0x00))
+			rc = -EIO;
+		else {
+			fan_control_desired_level = 0;
+			tp_features.fan_ctrl_status_undef = 0;
+		}
+		break;
+
+	case TPACPI_FAN_WR_ACPI_SFAN:
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+			rc = -EIO;
+		else
+			fan_control_desired_level = 0;
+		break;
+
+	default:
+		rc = -ENXIO;
+	}
+
+
+	mutex_unlock(&fan_mutex);
+	return rc;
+}
+
+static int fan_set_speed(int speed)
+{
+	int rc;
+
+	if (!fan_control_allowed)
+		return -EPERM;
+
+	rc = mutex_lock_interruptible(&fan_mutex);
+	if (rc < 0)
+		return rc;
+
+	rc = 0;
+	switch (fan_control_access_mode) {
+	case TPACPI_FAN_WR_ACPI_FANS:
+		if (speed >= 0 && speed <= 65535) {
+			if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+					speed, speed, speed))
+				rc = -EIO;
+		} else
+			rc = -EINVAL;
+		break;
+
+	default:
+		rc = -ENXIO;
+	}
+
+	mutex_unlock(&fan_mutex);
+	return rc;
+}
+
+static int fan_read(char *p)
+{
+	int len = 0;
+	int rc;
+	u8 status;
+	unsigned int speed = 0;
+
+	switch (fan_status_access_mode) {
+	case TPACPI_FAN_RD_ACPI_GFAN:
+		/* 570, 600e/x, 770e, 770x */
+		if ((rc = fan_get_status_safe(&status)) < 0)
+			return rc;
+
+		len += sprintf(p + len, "status:\t\t%s\n"
+			       "level:\t\t%d\n",
+			       (status != 0) ? "enabled" : "disabled", status);
+		break;
+
+	case TPACPI_FAN_RD_TPEC:
+		/* all except 570, 600e/x, 770e, 770x */
+		if ((rc = fan_get_status_safe(&status)) < 0)
+			return rc;
+
+		if (unlikely(tp_features.fan_ctrl_status_undef)) {
+			if (status != fan_control_initial_status)
+				tp_features.fan_ctrl_status_undef = 0;
+			else
+				/* Return most likely status. In fact, it
+				 * might be the only possible status */
+				status = TP_EC_FAN_AUTO;
+		}
+
+		len += sprintf(p + len, "status:\t\t%s\n",
+			       (status != 0) ? "enabled" : "disabled");
+
+		if ((rc = fan_get_speed(&speed)) < 0)
+			return rc;
+
+		len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+		if (status & TP_EC_FAN_FULLSPEED)
+			/* Disengaged mode takes precedence */
+			len += sprintf(p + len, "level:\t\tdisengaged\n");
+		else if (status & TP_EC_FAN_AUTO)
+			len += sprintf(p + len, "level:\t\tauto\n");
+		else
+			len += sprintf(p + len, "level:\t\t%d\n", status);
+		break;
+
+	case TPACPI_FAN_NONE:
+	default:
+		len += sprintf(p + len, "status:\t\tnot supported\n");
+	}
+
+	if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
+		len += sprintf(p + len, "commands:\tlevel <level>");
+
+		switch (fan_control_access_mode) {
+		case TPACPI_FAN_WR_ACPI_SFAN:
+			len += sprintf(p + len, " (<level> is 0-7)\n");
+			break;
+
+		default:
+			len += sprintf(p + len, " (<level> is 0-7, "
+				       "auto, disengaged, full-speed)\n");
+			break;
+		}
+	}
+
+	if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
+		len += sprintf(p + len, "commands:\tenable, disable\n"
+			       "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+			       "1-120 (seconds))\n");
+
+	if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
+		len += sprintf(p + len, "commands:\tspeed <speed>"
+			       " (<speed> is 0-65535)\n");
+
+	return len;
+}
+
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+	int level;
+
+	if (strlencmp(cmd, "level auto") == 0)
+		level = TP_EC_FAN_AUTO;
+	else if ((strlencmp(cmd, "level disengaged") == 0) |
+	         (strlencmp(cmd, "level full-speed") == 0))
+		level = TP_EC_FAN_FULLSPEED;
+	else if (sscanf(cmd, "level %d", &level) != 1)
+		return 0;
+
+	if ((*rc = fan_set_level_safe(level)) == -ENXIO)
+		printk(IBM_ERR "level command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+	if (strlencmp(cmd, "enable") != 0)
+		return 0;
+
+	if ((*rc = fan_set_enable()) == -ENXIO)
+		printk(IBM_ERR "enable command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+	if (strlencmp(cmd, "disable") != 0)
+		return 0;
+
+	if ((*rc = fan_set_disable()) == -ENXIO)
+		printk(IBM_ERR "disable command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+	int speed;
+
+	/* TODO:
+	 * Support speed <low> <medium> <high> ? */
+
+	if (sscanf(cmd, "speed %d", &speed) != 1)
+		return 0;
+
+	if ((*rc = fan_set_speed(speed)) == -ENXIO)
+		printk(IBM_ERR "speed command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+	int interval;
+
+	if (sscanf(cmd, "watchdog %d", &interval) != 1)
+		return 0;
+
+	if (interval < 0 || interval > 120)
+		*rc = -EINVAL;
+	else
+		fan_watchdog_maxinterval = interval;
+
+	return 1;
+}
+
+static int fan_write(char *buf)
+{
+	char *cmd;
+	int rc = 0;
+
+	while (!rc && (cmd = next_cmd(&buf))) {
+		if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
+		      fan_write_cmd_level(cmd, &rc)) &&
+		    !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
+		      (fan_write_cmd_enable(cmd, &rc) ||
+		       fan_write_cmd_disable(cmd, &rc) ||
+		       fan_write_cmd_watchdog(cmd, &rc))) &&
+		    !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
+		      fan_write_cmd_speed(cmd, &rc))
+		    )
+			rc = -EINVAL;
+		else if (!rc)
+			fan_watchdog_reset();
+	}
+
+	return rc;
+}
+
+static struct ibm_struct fan_driver_data = {
+	.name = "fan",
+	.read = fan_read,
+	.write = fan_write,
+	.exit = fan_exit,
+};
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Infrastructure
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/* /proc support */
+static struct proc_dir_entry *proc_dir = NULL;
+
+/* Subdriver registry */
+static LIST_HEAD(tpacpi_all_drivers);
+
+
+/*
+ * Module and infrastructure proble, init and exit handling
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+static const char * __init str_supported(int is_supported)
+{
+	static char text_unsupported[] __initdata = "not supported";
+
+	return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
+}
+#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
+
+static int __init ibm_init(struct ibm_init_struct *iibm)
+{
+	int ret;
+	struct ibm_struct *ibm = iibm->data;
+	struct proc_dir_entry *entry;
+
+	BUG_ON(ibm == NULL);
+
+	INIT_LIST_HEAD(&ibm->all_drivers);
+
+	if (ibm->flags.experimental && !experimental)
+		return 0;
+
+	dbg_printk(TPACPI_DBG_INIT,
+		"probing for %s\n", ibm->name);
+
+	if (iibm->init) {
+		ret = iibm->init(iibm);
+		if (ret > 0)
+			return 0;	/* probe failed */
+		if (ret)
+			return ret;
+
+		ibm->flags.init_called = 1;
+	}
+
+	if (ibm->acpi) {
+		if (ibm->acpi->hid) {
+			ret = register_tpacpi_subdriver(ibm);
+			if (ret)
+				goto err_out;
+		}
+
+		if (ibm->acpi->notify) {
+			ret = setup_acpi_notify(ibm);
+			if (ret == -ENODEV) {
+				printk(IBM_NOTICE "disabling subdriver %s\n",
+					ibm->name);
+				ret = 0;
+				goto err_out;
+			}
+			if (ret < 0)
+				goto err_out;
+		}
+	}
+
+	dbg_printk(TPACPI_DBG_INIT,
+		"%s installed\n", ibm->name);
+
+	if (ibm->read) {
+		entry = create_proc_entry(ibm->name,
+					  S_IFREG | S_IRUGO | S_IWUSR,
+					  proc_dir);
+		if (!entry) {
+			printk(IBM_ERR "unable to create proc entry %s\n",
+			       ibm->name);
+			ret = -ENODEV;
+			goto err_out;
+		}
+		entry->owner = THIS_MODULE;
+		entry->data = ibm;
+		entry->read_proc = &dispatch_procfs_read;
+		if (ibm->write)
+			entry->write_proc = &dispatch_procfs_write;
+		ibm->flags.proc_created = 1;
+	}
+
+	list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
+
+	return 0;
+
+err_out:
+	dbg_printk(TPACPI_DBG_INIT,
+		"%s: at error exit path with result %d\n",
+		ibm->name, ret);
+
+	ibm_exit(ibm);
+	return (ret < 0)? ret : 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+	dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+
+	list_del_init(&ibm->all_drivers);
+
+	if (ibm->flags.acpi_notify_installed) {
+		dbg_printk(TPACPI_DBG_EXIT,
+			"%s: acpi_remove_notify_handler\n", ibm->name);
+		BUG_ON(!ibm->acpi);
+		acpi_remove_notify_handler(*ibm->acpi->handle,
+					   ibm->acpi->type,
+					   dispatch_acpi_notify);
+		ibm->flags.acpi_notify_installed = 0;
+		ibm->flags.acpi_notify_installed = 0;
+	}
+
+	if (ibm->flags.proc_created) {
+		dbg_printk(TPACPI_DBG_EXIT,
+			"%s: remove_proc_entry\n", ibm->name);
+		remove_proc_entry(ibm->name, proc_dir);
+		ibm->flags.proc_created = 0;
+	}
+
+	if (ibm->flags.acpi_driver_registered) {
+		dbg_printk(TPACPI_DBG_EXIT,
+			"%s: acpi_bus_unregister_driver\n", ibm->name);
+		BUG_ON(!ibm->acpi);
+		acpi_bus_unregister_driver(ibm->acpi->driver);
+		kfree(ibm->acpi->driver);
+		ibm->acpi->driver = NULL;
+		ibm->flags.acpi_driver_registered = 0;
+	}
+
+	if (ibm->flags.init_called && ibm->exit) {
+		ibm->exit();
+		ibm->flags.init_called = 0;
+	}
+
+	dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+}
+
+/* Probing */
+
+static char *ibm_thinkpad_ec_found = NULL;
+
+static char* __init check_dmi_for_ec(void)
+{
+	struct dmi_device *dev = NULL;
+	char ec_fw_string[18];
+
+	/*
+	 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+	 * X32 or newer, all Z series;  Some models must have an
+	 * up-to-date BIOS or they will not be detected.
+	 *
+	 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+	 */
+	while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+		if (sscanf(dev->name,
+			   "IBM ThinkPad Embedded Controller -[%17c",
+			   ec_fw_string) == 1) {
+			ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+			ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+			return kstrdup(ec_fw_string, GFP_KERNEL);
+		}
+	}
+	return NULL;
+}
+
+static int __init probe_for_thinkpad(void)
+{
+	int is_thinkpad;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	/*
+	 * Non-ancient models have better DMI tagging, but very old models
+	 * don't.
+	 */
+	is_thinkpad = dmi_name_in_vendors("ThinkPad");
+
+	/* ec is required because many other handles are relative to it */
+	IBM_ACPIHANDLE_INIT(ec);
+	if (!ec_handle) {
+		if (is_thinkpad)
+			printk(IBM_ERR
+				"Not yet supported ThinkPad detected!\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Risks a regression on very old machines, but reduces potential
+	 * false positives a damn great deal
+	 */
+	if (!is_thinkpad)
+		is_thinkpad = dmi_name_in_vendors("IBM");
+
+	if (!is_thinkpad && !force_load)
+		return -ENODEV;
+
+	return 0;
+}
+
+
+/* Module init, exit, parameters */
+
+static struct ibm_init_struct ibms_init[] __initdata = {
+	{
+		.init = thinkpad_acpi_driver_init,
+		.data = &thinkpad_acpi_driver_data,
+	},
+	{
+		.init = hotkey_init,
+		.data = &hotkey_driver_data,
+	},
+	{
+		.init = bluetooth_init,
+		.data = &bluetooth_driver_data,
+	},
+	{
+		.init = wan_init,
+		.data = &wan_driver_data,
+	},
+	{
+		.init = video_init,
+		.data = &video_driver_data,
+	},
+	{
+		.init = light_init,
+		.data = &light_driver_data,
+	},
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+	{
+		.init = dock_init,
+		.data = &dock_driver_data[0],
+	},
+	{
+		.init = dock_init2,
+		.data = &dock_driver_data[1],
+	},
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+	{
+		.init = bay_init,
+		.data = &bay_driver_data,
+	},
+#endif
+	{
+		.init = cmos_init,
+		.data = &cmos_driver_data,
+	},
+	{
+		.init = led_init,
+		.data = &led_driver_data,
+	},
+	{
+		.init = beep_init,
+		.data = &beep_driver_data,
+	},
+	{
+		.init = thermal_init,
+		.data = &thermal_driver_data,
+	},
+	{
+		.data = &ecdump_driver_data,
+	},
+	{
+		.init = brightness_init,
+		.data = &brightness_driver_data,
+	},
+	{
+		.data = &volume_driver_data,
+	},
+	{
+		.init = fan_init,
+		.data = &fan_driver_data,
+	},
+};
+
+static int __init set_ibm_param(const char *val, struct kernel_param *kp)
+{
+	unsigned int i;
+	struct ibm_struct *ibm;
+
+	for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+		ibm = ibms_init[i].data;
+		BUG_ON(ibm == NULL);
+
+		if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
+			if (strlen(val) > sizeof(ibms_init[i].param) - 2)
+				return -ENOSPC;
+			strcpy(ibms_init[i].param, val);
+			strcat(ibms_init[i].param, ",");
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static u32 dbg_level;
+module_param_named(debug, dbg_level, uint, 0);
+
+static int force_load;
+module_param(force_load, int, 0);
+
+static int fan_control_allowed;
+module_param_named(fan_control, fan_control_allowed, int, 0);
+
+#define IBM_PARAM(feature) \
+	module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+IBM_PARAM(dock);
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_PARAM(bay);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
+IBM_PARAM(ecdump);
+IBM_PARAM(brightness);
+IBM_PARAM(volume);
+IBM_PARAM(fan);
+
+static int __init thinkpad_acpi_module_init(void)
+{
+	int ret, i;
+
+	/* Driver-level probe */
+	ret = probe_for_thinkpad();
+	if (ret)
+		return ret;
+
+	/* Driver initialization */
+	ibm_thinkpad_ec_found = check_dmi_for_ec();
+	IBM_ACPIHANDLE_INIT(ecrd);
+	IBM_ACPIHANDLE_INIT(ecwr);
+
+	proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
+	if (!proc_dir) {
+		printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
+		thinkpad_acpi_module_exit();
+		return -ENODEV;
+	}
+	proc_dir->owner = THIS_MODULE;
+
+	ret = platform_driver_register(&tpacpi_pdriver);
+	if (ret) {
+		printk(IBM_ERR "unable to register platform driver\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	}
+	ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+	if (ret) {
+		printk(IBM_ERR "unable to create sysfs driver attributes\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	}
+
+
+	/* Device initialization */
+	tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
+							NULL, 0);
+	if (IS_ERR(tpacpi_pdev)) {
+		ret = PTR_ERR(tpacpi_pdev);
+		tpacpi_pdev = NULL;
+		printk(IBM_ERR "unable to register platform device\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	}
+	tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+	if (IS_ERR(tpacpi_hwmon)) {
+		ret = PTR_ERR(tpacpi_hwmon);
+		tpacpi_hwmon = NULL;
+		printk(IBM_ERR "unable to register hwmon device\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	}
+	for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+		ret = ibm_init(&ibms_init[i]);
+		if (ret >= 0 && *ibms_init[i].param)
+			ret = ibms_init[i].data->write(ibms_init[i].param);
+		if (ret < 0) {
+			thinkpad_acpi_module_exit();
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void thinkpad_acpi_module_exit(void)
+{
+	struct ibm_struct *ibm, *itmp;
+
+	list_for_each_entry_safe_reverse(ibm, itmp,
+					 &tpacpi_all_drivers,
+					 all_drivers) {
+		ibm_exit(ibm);
+	}
+
+	dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+
+	if (tpacpi_hwmon)
+		hwmon_device_unregister(tpacpi_hwmon);
+
+	if (tpacpi_pdev)
+		platform_device_unregister(tpacpi_pdev);
+
+	tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+	platform_driver_unregister(&tpacpi_pdriver);
+
+	if (proc_dir)
+		remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+
+	kfree(ibm_thinkpad_ec_found);
+}
+
+module_init(thinkpad_acpi_module_init);
+module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
new file mode 100644
index 0000000..440145a
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.h
@@ -0,0 +1,572 @@
+/*
+ *  thinkpad_acpi.h - ThinkPad ACPI Extras
+ *
+ *
+ *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ *  Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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.
+ */
+
+#ifndef __THINKPAD_ACPI_H__
+#define __THINKPAD_ACPI_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/uaccess.h>
+
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+
+/****************************************************************************
+ * Main driver
+ */
+
+#define IBM_NAME "thinkpad"
+#define IBM_DESC "ThinkPad ACPI Extras"
+#define IBM_FILE "thinkpad_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
+
+#define IBM_PROC_DIR "ibm"
+#define IBM_ACPI_EVENT_PREFIX "ibm"
+#define IBM_DRVR_NAME IBM_FILE
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR	   KERN_ERR    IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO   KERN_INFO   IBM_LOG
+#define IBM_DEBUG  KERN_DEBUG  IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN	0
+#define TP_CMOS_VOLUME_UP	1
+#define TP_CMOS_VOLUME_MUTE	2
+#define TP_CMOS_BRIGHTNESS_UP	4
+#define TP_CMOS_BRIGHTNESS_DOWN	5
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+/* Debugging */
+#define TPACPI_DBG_ALL		0xffff
+#define TPACPI_DBG_ALL		0xffff
+#define TPACPI_DBG_INIT		0x0001
+#define TPACPI_DBG_EXIT		0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+	do { if (dbg_level & a_dbg_level) \
+		printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+	dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+/* ACPI HIDs */
+#define IBM_HKEY_HID    "IBM0068"
+#define IBM_PCI_HID     "PNP0A03"
+
+/* ACPI helpers */
+static int __must_check acpi_evalf(acpi_handle handle,
+		      void *res, char *method, char *fmt, ...);
+static int __must_check acpi_ec_read(int i, u8 * p);
+static int __must_check acpi_ec_write(int i, u8 v);
+static int __must_check _sta(acpi_handle handle);
+
+/* ACPI handles */
+static acpi_handle root_handle;			/* root namespace */
+static acpi_handle ec_handle;			/* EC */
+static acpi_handle ecrd_handle, ecwr_handle;	/* 570 EC access */
+static acpi_handle cmos_handle, hkey_handle;	/* basic thinkpad handles */
+
+static void drv_acpi_handle_init(char *name,
+		   acpi_handle *handle, acpi_handle parent,
+		   char **paths, int num_paths, char **path);
+#define IBM_ACPIHANDLE_INIT(object)						\
+	drv_acpi_handle_init(#object, &object##_handle, *object##_parent,	\
+		object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
+/* ThinkPad ACPI helpers */
+static int issue_thinkpad_cmos_command(int cmos_cmd);
+
+/* procfs support */
+static struct proc_dir_entry *proc_dir;
+
+/* procfs helpers */
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+		int count, int *eof, void *data);
+static int dispatch_procfs_write(struct file *file,
+		const char __user * userbuf,
+		unsigned long count, void *data);
+static char *next_cmd(char **cmds);
+
+/* sysfs support */
+struct attribute_set {
+	unsigned int members, max_members;
+	struct attribute_group group;
+};
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+						const char* name);
+#define destroy_attr_set(_set) \
+	kfree(_set);
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
+static int add_many_to_attr_set(struct attribute_set* s,
+			struct attribute **attr,
+			unsigned int count);
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+	sysfs_create_group(_kobj, &_attr_set->group)
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
+
+static int parse_strtoul(const char *buf, unsigned long max,
+			unsigned long *value);
+
+/* Device model */
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct platform_driver tpacpi_pdriver;
+static int tpacpi_create_driver_attributes(struct device_driver *drv);
+static void tpacpi_remove_driver_attributes(struct device_driver *drv);
+
+/* Module */
+static int experimental;
+static u32 dbg_level;
+static int force_load;
+static char *ibm_thinkpad_ec_found;
+
+static char* check_dmi_for_ec(void);
+static int thinkpad_acpi_module_init(void);
+static void thinkpad_acpi_module_exit(void);
+
+
+/****************************************************************************
+ * Subdrivers
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+	char *hid;
+	struct acpi_driver *driver;
+
+	void (*notify) (struct ibm_struct *, u32);
+	acpi_handle *handle;
+	u32 type;
+	struct acpi_device *device;
+};
+
+struct ibm_struct {
+	char *name;
+
+	int (*read) (char *);
+	int (*write) (char *);
+	void (*exit) (void);
+
+	struct list_head all_drivers;
+
+	struct tp_acpi_drv_struct *acpi;
+
+	struct {
+		u8 acpi_driver_registered:1;
+		u8 acpi_notify_installed:1;
+		u8 proc_created:1;
+		u8 init_called:1;
+		u8 experimental:1;
+	} flags;
+};
+
+struct ibm_init_struct {
+	char param[32];
+
+	int (*init) (struct ibm_init_struct *);
+	struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+	u16 bay_status:1;
+	u16 bay_eject:1;
+	u16 bay_status2:1;
+	u16 bay_eject2:1;
+#endif
+	u16 bluetooth:1;
+	u16 hotkey:1;
+	u16 hotkey_mask:1;
+	u16 light:1;
+	u16 light_status:1;
+	u16 wan:1;
+	u16 fan_ctrl_status_undef:1;
+} tp_features;
+
+static struct list_head tpacpi_all_drivers;
+
+static struct ibm_init_struct ibms_init[];
+static int set_ibm_param(const char *val, struct kernel_param *kp);
+static int ibm_init(struct ibm_init_struct *iibm);
+static void ibm_exit(struct ibm_struct *ibm);
+
+
+/*
+ * procfs master subdriver
+ */
+static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
+static int thinkpad_acpi_driver_read(char *p);
+
+
+/*
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+static acpi_handle bay_handle, bay_ej_handle;
+static acpi_handle bay2_handle, bay2_ej_handle;
+
+static int bay_init(struct ibm_init_struct *iibm);
+static void bay_notify(struct ibm_struct *ibm, u32 event);
+static int bay_read(char *p);
+static int bay_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+
+/*
+ * Beep subdriver
+ */
+
+static acpi_handle beep_handle;
+
+static int beep_read(char *p);
+static int beep_write(char *buf);
+
+
+/*
+ * Bluetooth subdriver
+ */
+
+#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth"
+
+enum {
+	/* ACPI GBDC/SBDC bits */
+	TP_ACPI_BLUETOOTH_HWPRESENT	= 0x01,	/* Bluetooth hw available */
+	TP_ACPI_BLUETOOTH_RADIOSSW	= 0x02,	/* Bluetooth radio enabled */
+	TP_ACPI_BLUETOOTH_UNK		= 0x04,	/* unknown function */
+};
+
+static int bluetooth_init(struct ibm_init_struct *iibm);
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+static int bluetooth_read(char *p);
+static int bluetooth_write(char *buf);
+
+
+/*
+ * Brightness (backlight) subdriver
+ */
+
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+
+static int brightness_init(struct ibm_init_struct *iibm);
+static void brightness_exit(void);
+static int brightness_get(struct backlight_device *bd);
+static int brightness_set(int value);
+static int brightness_update_status(struct backlight_device *bd);
+static int brightness_read(char *p);
+static int brightness_write(char *buf);
+
+
+/*
+ * CMOS subdriver
+ */
+
+static int cmos_read(char *p);
+static int cmos_write(char *buf);
+
+
+/*
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+static acpi_handle pci_handle;
+static acpi_handle dock_handle;
+
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+
+/*
+ * EC dump subdriver
+ */
+
+static int ecdump_read(char *p) ;
+static int ecdump_write(char *buf);
+
+
+/*
+ * Fan subdriver
+ */
+
+enum {					/* Fan control constants */
+	fan_status_offset = 0x2f,	/* EC register 0x2f */
+	fan_rpm_offset = 0x84,		/* EC register 0x84: LSB, 0x85 MSB (RPM)
+					 * 0x84 must be read before 0x85 */
+
+	TP_EC_FAN_FULLSPEED = 0x40,	/* EC fan mode: full speed */
+	TP_EC_FAN_AUTO	    = 0x80,	/* EC fan mode: auto fan control */
+
+	TPACPI_FAN_LAST_LEVEL = 0x100,	/* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+	TPACPI_FAN_NONE = 0,		/* No fan status or control */
+	TPACPI_FAN_RD_ACPI_GFAN,	/* Use ACPI GFAN */
+	TPACPI_FAN_RD_TPEC,		/* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+	TPACPI_FAN_WR_NONE = 0,		/* No fan control */
+	TPACPI_FAN_WR_ACPI_SFAN,	/* Use ACPI SFAN */
+	TPACPI_FAN_WR_TPEC,		/* Use ACPI EC reg 0x2f */
+	TPACPI_FAN_WR_ACPI_FANS,	/* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+	TPACPI_FAN_CMD_SPEED 	= 0x0001,	/* speed command */
+	TPACPI_FAN_CMD_LEVEL 	= 0x0002,	/* level command  */
+	TPACPI_FAN_CMD_ENABLE	= 0x0004,	/* enable/disable cmd,
+						 * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
+
+static acpi_handle fans_handle, gfan_handle, sfan_handle;
+
+static int fan_init(struct ibm_init_struct *iibm);
+static void fan_exit(void);
+static int fan_get_status(u8 *status);
+static int fan_get_status_safe(u8 *status);
+static int fan_get_speed(unsigned int *speed);
+static void fan_update_desired_level(u8 status);
+static void fan_watchdog_fire(struct work_struct *ignored);
+static void fan_watchdog_reset(void);
+static int fan_set_level(int level);
+static int fan_set_level_safe(int level);
+static int fan_set_enable(void);
+static int fan_set_disable(void);
+static int fan_set_speed(int speed);
+static int fan_read(char *p);
+static int fan_write(char *buf);
+static int fan_write_cmd_level(const char *cmd, int *rc);
+static int fan_write_cmd_enable(const char *cmd, int *rc);
+static int fan_write_cmd_disable(const char *cmd, int *rc);
+static int fan_write_cmd_speed(const char *cmd, int *rc);
+static int fan_write_cmd_watchdog(const char *cmd, int *rc);
+
+
+/*
+ * Hotkey subdriver
+ */
+
+#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey"
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct mutex hotkey_mutex;
+
+static int hotkey_init(struct ibm_init_struct *iibm);
+static void hotkey_exit(void);
+static int hotkey_get(int *status, int *mask);
+static int hotkey_set(int status, int mask);
+static void hotkey_notify(struct ibm_struct *ibm, u32 event);
+static int hotkey_read(char *p);
+static int hotkey_write(char *buf);
+
+
+/*
+ * LED subdriver
+ */
+
+enum led_access_mode {
+	TPACPI_LED_NONE = 0,
+	TPACPI_LED_570,	/* 570 */
+	TPACPI_LED_OLD,	/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+	TPACPI_LED_NEW,	/* all others */
+};
+
+enum {	/* For TPACPI_LED_OLD */
+	TPACPI_LED_EC_HLCL = 0x0c,	/* EC reg to get led to power on */
+	TPACPI_LED_EC_HLBL = 0x0d,	/* EC reg to blink a lit led */
+	TPACPI_LED_EC_HLMS = 0x0e,	/* EC reg to select led to command */
+};
+
+static enum led_access_mode led_supported;
+static acpi_handle led_handle;
+
+static int led_init(struct ibm_init_struct *iibm);
+static int led_read(char *p);
+static int led_write(char *buf);
+
+/*
+ * Light (thinklight) subdriver
+ */
+
+static acpi_handle lght_handle, ledb_handle;
+
+static int light_init(struct ibm_init_struct *iibm);
+static int light_read(char *p);
+static int light_write(char *buf);
+
+
+/*
+ * Thermal subdriver
+ */
+
+enum thermal_access_mode {
+	TPACPI_THERMAL_NONE = 0,	/* No thermal support */
+	TPACPI_THERMAL_ACPI_TMP07,	/* Use ACPI TMP0-7 */
+	TPACPI_THERMAL_ACPI_UPDT,	/* Use ACPI TMP0-7 with UPDT */
+	TPACPI_THERMAL_TPEC_8,		/* Use ACPI EC regs, 8 sensors */
+	TPACPI_THERMAL_TPEC_16,		/* Use ACPI EC regs, 16 sensors */
+};
+
+enum { /* TPACPI_THERMAL_TPEC_* */
+	TP_EC_THERMAL_TMP0 = 0x78,	/* ACPI EC regs TMP 0..7 */
+	TP_EC_THERMAL_TMP8 = 0xC0,	/* ACPI EC regs TMP 8..15 */
+	TP_EC_THERMAL_TMP_NA = -128,	/* ACPI EC sensor not available */
+};
+
+#define TPACPI_MAX_THERMAL_SENSORS 16	/* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+	s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+};
+
+static enum thermal_access_mode thermal_read_mode;
+
+static int thermal_init(struct ibm_init_struct *iibm);
+static int thermal_get_sensor(int idx, s32 *value);
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
+static int thermal_read(char *p);
+
+
+/*
+ * Video subdriver
+ */
+
+enum video_access_mode {
+	TPACPI_VIDEO_NONE = 0,
+	TPACPI_VIDEO_570,	/* 570 */
+	TPACPI_VIDEO_770,	/* 600e/x, 770e, 770x */
+	TPACPI_VIDEO_NEW,	/* all others */
+};
+
+enum {	/* video status flags, based on VIDEO_570 */
+	TP_ACPI_VIDEO_S_LCD = 0x01,	/* LCD output enabled */
+	TP_ACPI_VIDEO_S_CRT = 0x02,	/* CRT output enabled */
+	TP_ACPI_VIDEO_S_DVI = 0x08,	/* DVI output enabled */
+};
+
+enum {  /* TPACPI_VIDEO_570 constants */
+	TP_ACPI_VIDEO_570_PHSCMD = 0x87,	/* unknown magic constant :( */
+	TP_ACPI_VIDEO_570_PHSMASK = 0x03,	/* PHS bits that map to
+						 * video_status_flags */
+	TP_ACPI_VIDEO_570_PHS2CMD = 0x8b,	/* unknown magic constant :( */
+	TP_ACPI_VIDEO_570_PHS2SET = 0x80,	/* unknown magic constant :( */
+};
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+static acpi_handle vid_handle, vid2_handle;
+
+static int video_init(struct ibm_init_struct *iibm);
+static void video_exit(void);
+static int video_outputsw_get(void);
+static int video_outputsw_set(int status);
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+static int video_outputsw_cycle(void);
+static int video_expand_toggle(void);
+static int video_read(char *p);
+static int video_write(char *buf);
+
+
+/*
+ * Volume subdriver
+ */
+
+static int volume_offset = 0x30;
+
+static int volume_read(char *p);
+static int volume_write(char *buf);
+
+
+/*
+ * Wan subdriver
+ */
+
+#define TPACPI_WAN_SYSFS_GROUP "wwan"
+
+enum {
+	/* ACPI GWAN/SWAN bits */
+	TP_ACPI_WANCARD_HWPRESENT	= 0x01,	/* Wan hw available */
+	TP_ACPI_WANCARD_RADIOSSW	= 0x02,	/* Wan radio enabled */
+	TP_ACPI_WANCARD_UNK		= 0x04,	/* unknown function */
+};
+
+static int wan_init(struct ibm_init_struct *iibm);
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+static int wan_read(char *p);
+static int wan_write(char *buf);
+
+
+#endif /* __THINKPAD_ACPI_H */
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index bc60e2f..1ba6c08 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,10 +11,20 @@
 
 #include <linux/tifm.h>
 #include <linux/dma-mapping.h>
-#include <linux/freezer.h>
 
 #define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8"
+
+#define TIFM_IRQ_ENABLE           0x80000000
+#define TIFM_IRQ_SOCKMASK(x)      (x)
+#define TIFM_IRQ_CARDMASK(x)      ((x) << 8)
+#define TIFM_IRQ_FIFOMASK(x)      ((x) << 16)
+#define TIFM_IRQ_SETALL           0xffffffff
+
+static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm,
+				  struct tifm_dev *sock)
+{
+}
 
 static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
 {
@@ -22,7 +32,7 @@ static void tifm_7xx1_eject(struct tifm_
 
 	spin_lock_irqsave(&fm->lock, flags);
 	fm->socket_change_set |= 1 << sock->socket_id;
-	wake_up_all(&fm->change_set_notify);
+	tifm_queue_work(&fm->media_switcher);
 	spin_unlock_irqrestore(&fm->lock, flags);
 }
 
@@ -30,8 +40,7 @@ static irqreturn_t tifm_7xx1_isr(int irq
 {
 	struct tifm_adapter *fm = dev_id;
 	struct tifm_dev *sock;
-	unsigned int irq_status;
-	unsigned int sock_irq_status, cnt;
+	unsigned int irq_status, cnt;
 
 	spin_lock(&fm->lock);
 	irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
@@ -45,12 +54,12 @@ static irqreturn_t tifm_7xx1_isr(int irq
 
 		for (cnt = 0; cnt < fm->num_sockets; cnt++) {
 			sock = fm->sockets[cnt];
-			sock_irq_status = (irq_status >> cnt)
-					  & (TIFM_IRQ_FIFOMASK(1)
-					     | TIFM_IRQ_CARDMASK(1));
-
-			if (sock && sock_irq_status)
-				sock->signal_irq(sock, sock_irq_status);
+			if (sock) {
+				if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))
+					sock->data_event(sock);
+				if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))
+					sock->card_event(sock);
+			}
 		}
 
 		fm->socket_change_set |= irq_status
@@ -58,57 +67,57 @@ static irqreturn_t tifm_7xx1_isr(int irq
 	}
 	writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
 
-	if (!fm->socket_change_set)
+	if (fm->finish_me)
+		complete_all(fm->finish_me);
+	else if (!fm->socket_change_set)
 		writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
 	else
-		wake_up_all(&fm->change_set_notify);
+		tifm_queue_work(&fm->media_switcher);
 
 	spin_unlock(&fm->lock);
 	return IRQ_HANDLED;
 }
 
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
-						 int is_x2)
+static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
 {
 	unsigned int s_state;
 	int cnt;
 
 	writel(0x0e00, sock_addr + SOCK_CONTROL);
 
-	for (cnt = 0; cnt < 100; cnt++) {
+	for (cnt = 16; cnt <= 256; cnt <<= 1) {
 		if (!(TIFM_SOCK_STATE_POWERED
 		      & readl(sock_addr + SOCK_PRESENT_STATE)))
 			break;
-		msleep(10);
+
+		msleep(cnt);
 	}
 
 	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);
-	}
+		return 0;
 
-	for (cnt = 0; cnt < 100; cnt++) {
+	writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+	       sock_addr + SOCK_CONTROL);
+
+	/* xd needs some extra time before power on */
+	if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7)
+	    == TIFM_TYPE_XD)
+		msleep(40);
+
+	writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+	/* wait for power to stabilize */
+	msleep(20);
+	for (cnt = 16; cnt <= 256; cnt <<= 1) {
 		if ((TIFM_SOCK_STATE_POWERED
 		     & readl(sock_addr + SOCK_PRESENT_STATE)))
 			break;
-		msleep(10);
+
+		msleep(cnt);
 	}
 
-	if (!is_x2)
-		writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
-		       sock_addr + SOCK_CONTROL);
+	writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+	       sock_addr + SOCK_CONTROL);
 
 	return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
 }
@@ -119,127 +128,77 @@ tifm_7xx1_sock_addr(char __iomem *base_a
 	return base_addr + ((sock_num + 1) << 10);
 }
 
-static int tifm_7xx1_switch_media(void *data)
+static void tifm_7xx1_switch_media(struct work_struct *work)
 {
-	struct tifm_adapter *fm = data;
-	unsigned long flags;
-	tifm_media_id media_id;
-	char *card_name = "xx";
-	int cnt, rc;
+	struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
+					       media_switcher);
 	struct tifm_dev *sock;
-	unsigned int socket_change_set;
-
-	while (1) {
-		rc = wait_event_interruptible(fm->change_set_notify,
-					      fm->socket_change_set);
-		if (rc == -ERESTARTSYS)
-			try_to_freeze();
+	unsigned long flags;
+	unsigned char media_id;
+	unsigned int socket_change_set, cnt;
 
-		spin_lock_irqsave(&fm->lock, flags);
-		socket_change_set = fm->socket_change_set;
-		fm->socket_change_set = 0;
+	spin_lock_irqsave(&fm->lock, flags);
+	socket_change_set = fm->socket_change_set;
+	fm->socket_change_set = 0;
 
-		dev_dbg(fm->dev, "checking media set %x\n",
-			socket_change_set);
+	dev_dbg(fm->cdev.dev, "checking media set %x\n",
+		socket_change_set);
 
-		if (kthread_should_stop())
-			socket_change_set = (1 << fm->num_sockets) - 1;
+	if (!socket_change_set) {
 		spin_unlock_irqrestore(&fm->lock, flags);
+		return;
+	}
 
-		if (!socket_change_set)
+	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+		if (!(socket_change_set & (1 << cnt)))
 			continue;
-
-		spin_lock_irqsave(&fm->lock, flags);
-		for (cnt = 0; cnt < fm->num_sockets; cnt++) {
-			if (!(socket_change_set & (1 << cnt)))
-				continue;
-			sock = fm->sockets[cnt];
-			if (sock) {
-				printk(KERN_INFO DRIVER_NAME
-				       ": demand removing card from socket %d\n",
-				       cnt);
-				fm->sockets[cnt] = NULL;
-				spin_unlock_irqrestore(&fm->lock, flags);
-				device_unregister(&sock->dev);
-				spin_lock_irqsave(&fm->lock, flags);
-				writel(0x0e00,
-				       tifm_7xx1_sock_addr(fm->addr, cnt)
-				       + SOCK_CONTROL);
-			}
-			if (kthread_should_stop())
-				continue;
-
+		sock = fm->sockets[cnt];
+		if (sock) {
+			printk(KERN_INFO
+			       "%s : demand removing card from socket %u:%u\n",
+			       fm->cdev.class_id, fm->id, cnt);
+			fm->sockets[cnt] = NULL;
 			spin_unlock_irqrestore(&fm->lock, flags);
-			media_id = tifm_7xx1_toggle_sock_power(
-					tifm_7xx1_sock_addr(fm->addr, cnt),
-					fm->num_sockets == 2);
-			if (media_id) {
-				sock = tifm_alloc_device(fm);
-				if (sock) {
-					sock->addr = tifm_7xx1_sock_addr(fm->addr,
-									 cnt);
-					sock->media_id = media_id;
-					sock->socket_id = cnt;
-					switch (media_id) {
-					case 1:
-						card_name = "xd";
-						break;
-					case 2:
-						card_name = "ms";
-						break;
-					case 3:
-						card_name = "sd";
-						break;
-					default:
-						tifm_free_device(&sock->dev);
-						spin_lock_irqsave(&fm->lock, flags);
-						continue;
-					}
-					snprintf(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);
-					if (!device_register(&sock->dev)) {
-						spin_lock_irqsave(&fm->lock, flags);
-						if (!fm->sockets[cnt]) {
-							fm->sockets[cnt] = sock;
-							sock = NULL;
-						}
-						spin_unlock_irqrestore(&fm->lock, flags);
-					}
-					if (sock)
-						tifm_free_device(&sock->dev);
-				}
-				spin_lock_irqsave(&fm->lock, flags);
-			}
+			device_unregister(&sock->dev);
+			spin_lock_irqsave(&fm->lock, flags);
+			writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
+			       + SOCK_CONTROL);
 		}
 
-		if (!kthread_should_stop()) {
-			writel(TIFM_IRQ_FIFOMASK(socket_change_set)
-			       | TIFM_IRQ_CARDMASK(socket_change_set),
-			       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-			writel(TIFM_IRQ_FIFOMASK(socket_change_set)
-			       | TIFM_IRQ_CARDMASK(socket_change_set),
-			       fm->addr + FM_SET_INTERRUPT_ENABLE);
-			writel(TIFM_IRQ_ENABLE,
-			       fm->addr + FM_SET_INTERRUPT_ENABLE);
-			spin_unlock_irqrestore(&fm->lock, flags);
-		} else {
-			for (cnt = 0; cnt < fm->num_sockets; cnt++) {
-				if (fm->sockets[cnt])
-					fm->socket_change_set |= 1 << cnt;
-			}
-			if (!fm->socket_change_set) {
-				spin_unlock_irqrestore(&fm->lock, flags);
-				return 0;
-			} else {
+		spin_unlock_irqrestore(&fm->lock, flags);
+
+		media_id = tifm_7xx1_toggle_sock_power(
+				tifm_7xx1_sock_addr(fm->addr, cnt));
+
+		// tifm_alloc_device will check if media_id is valid
+		sock = tifm_alloc_device(fm, cnt, media_id);
+		if (sock) {
+			sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt);
+
+			if (!device_register(&sock->dev)) {
+				spin_lock_irqsave(&fm->lock, flags);
+				if (!fm->sockets[cnt]) {
+					fm->sockets[cnt] = sock;
+					sock = NULL;
+				}
 				spin_unlock_irqrestore(&fm->lock, flags);
 			}
+			if (sock)
+				tifm_free_device(&sock->dev);
 		}
+		spin_lock_irqsave(&fm->lock, flags);
 	}
-	return 0;
+
+	writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+	       | TIFM_IRQ_CARDMASK(socket_change_set),
+	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+	writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+	       | TIFM_IRQ_CARDMASK(socket_change_set),
+	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+	writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+	spin_unlock_irqrestore(&fm->lock, flags);
 }
 
 #ifdef CONFIG_PM
@@ -258,9 +217,11 @@ static int tifm_7xx1_suspend(struct pci_
 static int tifm_7xx1_resume(struct pci_dev *dev)
 {
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
-	int cnt, rc;
+	int rc;
+	unsigned int good_sockets = 0, bad_sockets = 0;
 	unsigned long flags;
-	tifm_media_id new_ids[fm->num_sockets];
+	unsigned char new_ids[fm->num_sockets];
+	DECLARE_COMPLETION_ONSTACK(finish_resume);
 
 	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
@@ -271,45 +232,49 @@ static int tifm_7xx1_resume(struct pci_d
 
 	dev_dbg(&dev->dev, "resuming host\n");
 
-	for (cnt = 0; cnt < fm->num_sockets; cnt++)
-		new_ids[cnt] = tifm_7xx1_toggle_sock_power(
-					tifm_7xx1_sock_addr(fm->addr, cnt),
-					fm->num_sockets == 2);
+	for (rc = 0; rc < fm->num_sockets; rc++)
+		new_ids[rc] = tifm_7xx1_toggle_sock_power(
+					tifm_7xx1_sock_addr(fm->addr, rc));
 	spin_lock_irqsave(&fm->lock, flags);
-	fm->socket_change_set = 0;
-	for (cnt = 0; cnt < fm->num_sockets; cnt++) {
-		if (fm->sockets[cnt]) {
-			if (fm->sockets[cnt]->media_id == new_ids[cnt])
-				fm->socket_change_set |= 1 << cnt;
-
-			fm->sockets[cnt]->media_id = new_ids[cnt];
+	for (rc = 0; rc < fm->num_sockets; rc++) {
+		if (fm->sockets[rc]) {
+			if (fm->sockets[rc]->type == new_ids[rc])
+				good_sockets |= 1 << rc;
+			else
+				bad_sockets |= 1 << rc;
 		}
 	}
 
 	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
 	       fm->addr + FM_SET_INTERRUPT_ENABLE);
-	if (!fm->socket_change_set) {
-		spin_unlock_irqrestore(&fm->lock, flags);
-		return 0;
-	} else {
-		fm->socket_change_set = 0;
+	dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
+		good_sockets, bad_sockets);
+
+	fm->socket_change_set = 0;
+	if (good_sockets) {
+		fm->finish_me = &finish_resume;
 		spin_unlock_irqrestore(&fm->lock, flags);
+		rc = wait_for_completion_timeout(&finish_resume, HZ);
+		dev_dbg(&dev->dev, "wait returned %d\n", rc);
+		writel(TIFM_IRQ_FIFOMASK(good_sockets)
+		       | TIFM_IRQ_CARDMASK(good_sockets),
+		       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+		writel(TIFM_IRQ_FIFOMASK(good_sockets)
+		       | TIFM_IRQ_CARDMASK(good_sockets),
+		       fm->addr + FM_SET_INTERRUPT_ENABLE);
+		spin_lock_irqsave(&fm->lock, flags);
+		fm->finish_me = NULL;
+		fm->socket_change_set ^= good_sockets & fm->socket_change_set;
 	}
 
-	wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+	fm->socket_change_set |= bad_sockets;
+	if (fm->socket_change_set)
+		tifm_queue_work(&fm->media_switcher);
 
-	spin_lock_irqsave(&fm->lock, flags);
-	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
-	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
-	       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-	writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
-	       | TIFM_IRQ_CARDMASK(fm->socket_change_set),
-	       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	spin_unlock_irqrestore(&fm->lock, flags);
 	writel(TIFM_IRQ_ENABLE,
 	       fm->addr + FM_SET_INTERRUPT_ENABLE);
-	fm->socket_change_set = 0;
 
-	spin_unlock_irqrestore(&fm->lock, flags);
 	return 0;
 }
 
@@ -345,20 +310,14 @@ static int tifm_7xx1_probe(struct pci_de
 
 	pci_intx(dev, 1);
 
-	fm = tifm_alloc_adapter();
+	fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM
+				? 4 : 2, &dev->dev);
 	if (!fm) {
 		rc = -ENOMEM;
 		goto err_out_int;
 	}
 
-	fm->dev = &dev->dev;
-	fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
-			  ? 4 : 2;
-	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
-			      GFP_KERNEL);
-	if (!fm->sockets)
-		goto err_out_free;
-
+	INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
 	fm->eject = tifm_7xx1_eject;
 	pci_set_drvdata(dev, fm);
 
@@ -367,19 +326,16 @@ static int tifm_7xx1_probe(struct pci_de
 	if (!fm->addr)
 		goto err_out_free;
 
-	rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm);
+	rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
 	if (rc)
 		goto err_out_unmap;
 
-	init_waitqueue_head(&fm->change_set_notify);
-	rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
+	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_SOCKMASK((1 << fm->num_sockets) - 1),
 	       fm->addr + FM_SET_INTERRUPT_ENABLE);
-	wake_up_process(fm->media_switcher);
 	return 0;
 
 err_out_irq:
@@ -401,18 +357,12 @@ err_out:
 static void tifm_7xx1_remove(struct pci_dev *dev)
 {
 	struct tifm_adapter *fm = pci_get_drvdata(dev);
-	unsigned long flags;
 
+	fm->eject = tifm_7xx1_dummy_eject;
 	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
 	mmiowb();
 	free_irq(dev->irq, fm);
 
-	spin_lock_irqsave(&fm->lock, flags);
-	fm->socket_change_set = (1 << fm->num_sockets) - 1;
-	spin_unlock_irqrestore(&fm->lock, flags);
-
-	kthread_stop(fm->media_switcher);
-
 	tifm_remove_adapter(fm);
 
 	pci_set_drvdata(dev, NULL);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 6b10ebe..d195fb0 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,71 +14,124 @@ #include <linux/init.h>
 #include <linux/idr.h>
 
 #define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8"
 
+static struct workqueue_struct *workqueue;
 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)
+static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
 {
-	while (*ids) {
-		if (dev->media_id == *ids)
-			return ids;
-		ids++;
-	}
-	return NULL;
+	const char *card_type_name[3][3] = {
+		{ "SmartMedia/xD", "MemoryStick", "MMC/SD" },
+		{ "XD", "MS", "SD"},
+		{ "xd", "ms", "sd"}
+	};
+
+	if (nt > 2 || type < 1 || type > 3)
+		return NULL;
+	return card_type_name[nt][type - 1];
 }
 
-static int tifm_match(struct device *dev, struct device_driver *drv)
+static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
 {
-	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))
+	if (sock->type == id->type)
 		return 1;
-	return -ENODEV;
+	return 0;
+}
+
+static int tifm_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
+						  driver);
+	struct tifm_device_id *ids = fm_drv->id_table;
+
+	if (ids) {
+		while (ids->type) {
+			if (tifm_dev_match(sock, ids))
+				return 1;
+			++ids;
+		}
+	}
+	return 0;
 }
 
 static int tifm_uevent(struct device *dev, char **envp, int num_envp,
 		       char *buffer, int buffer_size)
 {
-	struct tifm_dev *fm_dev;
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, 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]))
+			   "TIFM_CARD_TYPE=%s",
+			   tifm_media_type_name(sock->type, 1)))
 		return -ENOMEM;
 
 	return 0;
 }
 
+static int tifm_device_probe(struct device *dev)
+{
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+					       driver);
+	int rc = -ENODEV;
+
+	get_device(dev);
+	if (dev->driver && drv->probe) {
+		rc = drv->probe(sock);
+		if (!rc)
+			return 0;
+	}
+	put_device(dev);
+	return rc;
+}
+
+static void tifm_dummy_event(struct tifm_dev *sock)
+{
+	return;
+}
+
+static int tifm_device_remove(struct device *dev)
+{
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+					       driver);
+
+	if (dev->driver && drv->remove) {
+		sock->card_event = tifm_dummy_event;
+		sock->data_event = tifm_dummy_event;
+		drv->remove(sock);
+		sock->dev.driver = NULL;
+	}
+
+	put_device(dev);
+	return 0;
+}
+
 #ifdef CONFIG_PM
 
 static int tifm_device_suspend(struct device *dev, pm_message_t state)
 {
-	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-	struct tifm_driver *drv = fm_dev->drv;
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+					       driver);
 
-	if (drv && drv->suspend)
-		return drv->suspend(fm_dev, state);
+	if (dev->driver && drv->suspend)
+		return drv->suspend(sock, state);
 	return 0;
 }
 
 static int tifm_device_resume(struct device *dev)
 {
-	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-	struct tifm_driver *drv = fm_dev->drv;
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+					       driver);
 
-	if (drv && drv->resume)
-		return drv->resume(fm_dev);
+	if (dev->driver && drv->resume)
+		return drv->resume(sock);
 	return 0;
 }
 
@@ -89,19 +142,33 @@ #define tifm_device_resume NULL
 
 #endif /* CONFIG_PM */
 
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	return sprintf(buf, "%x", sock->type);
+}
+
+static struct device_attribute tifm_dev_attrs[] = {
+	__ATTR(type, S_IRUGO, type_show, NULL),
+	__ATTR_NULL
+};
+
 static struct bus_type tifm_bus_type = {
-	.name    = "tifm",
-	.match   = tifm_match,
-	.uevent  = tifm_uevent,
-	.suspend = tifm_device_suspend,
-	.resume  = tifm_device_resume
+	.name      = "tifm",
+	.dev_attrs = tifm_dev_attrs,
+	.match     = tifm_bus_match,
+	.uevent    = tifm_uevent,
+	.probe     = tifm_device_probe,
+	.remove    = tifm_device_remove,
+	.suspend   = tifm_device_suspend,
+	.resume    = tifm_device_resume
 };
 
 static void tifm_free(struct class_device *cdev)
 {
 	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
 
-	kfree(fm->sockets);
 	kfree(fm);
 }
 
@@ -110,28 +177,25 @@ static struct class tifm_adapter_class =
 	.release = tifm_free
 };
 
-struct tifm_adapter *tifm_alloc_adapter(void)
+struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+					struct device *dev)
 {
 	struct tifm_adapter *fm;
 
-	fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
+	fm = kzalloc(sizeof(struct tifm_adapter)
+		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
 	if (fm) {
 		fm->cdev.class = &tifm_adapter_class;
-		spin_lock_init(&fm->lock);
+		fm->cdev.dev = dev;
 		class_device_initialize(&fm->cdev);
+		spin_lock_init(&fm->lock);
+		fm->num_sockets = num_sockets;
 	}
 	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 (*mediathreadfn)(void *data))
+int tifm_add_adapter(struct tifm_adapter *fm)
 {
 	int rc;
 
@@ -141,59 +205,80 @@ int tifm_add_adapter(struct tifm_adapter
 	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);
-		fm->media_switcher = kthread_create(mediathreadfn,
-						    fm, "tifm/%u", fm->id);
-
-		if (!IS_ERR(fm->media_switcher))
-			return class_device_add(&fm->cdev);
+	if (rc)
+		return rc;
 
+	snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+	rc = class_device_add(&fm->cdev);
+	if (rc) {
 		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);
+	unsigned int cnt;
+
+	flush_workqueue(workqueue);
+	for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
+		if (fm->sockets[cnt])
+			device_unregister(&fm->sockets[cnt]->dev);
+	}
 
 	spin_lock(&tifm_adapter_lock);
 	idr_remove(&tifm_adapter_idr, fm->id);
 	spin_unlock(&tifm_adapter_lock);
+	class_device_del(&fm->cdev);
 }
 EXPORT_SYMBOL(tifm_remove_adapter);
 
-void tifm_free_device(struct device *dev)
+void tifm_free_adapter(struct tifm_adapter *fm)
 {
-	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-	kfree(fm_dev);
+	class_device_put(&fm->cdev);
 }
-EXPORT_SYMBOL(tifm_free_device);
+EXPORT_SYMBOL(tifm_free_adapter);
 
-static void tifm_dummy_signal_irq(struct tifm_dev *sock,
-				  unsigned int sock_irq_status)
+void tifm_free_device(struct device *dev)
 {
-	return;
+	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+	kfree(sock);
 }
+EXPORT_SYMBOL(tifm_free_device);
 
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
+				   unsigned char type)
 {
-	struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
-
-	if (dev) {
-		spin_lock_init(&dev->lock);
-
-		dev->dev.parent = fm->dev;
-		dev->dev.bus = &tifm_bus_type;
-		dev->dev.release = tifm_free_device;
-		dev->signal_irq = tifm_dummy_signal_irq;
+	struct tifm_dev *sock = NULL;
+
+	if (!tifm_media_type_name(type, 0))
+		return sock;
+
+	sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
+	if (sock) {
+		spin_lock_init(&sock->lock);
+		sock->type = type;
+		sock->socket_id = id;
+		sock->card_event = tifm_dummy_event;
+		sock->data_event = tifm_dummy_event;
+
+		sock->dev.parent = fm->cdev.dev;
+		sock->dev.bus = &tifm_bus_type;
+		sock->dev.dma_mask = fm->cdev.dev->dma_mask;
+		sock->dev.release = tifm_free_device;
+
+		snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+			 "tifm_%s%u:%u", tifm_media_type_name(type, 2),
+			 fm->id, id);
+		printk(KERN_INFO DRIVER_NAME
+		       ": %s card detected in socket %u:%u\n",
+		       tifm_media_type_name(type, 0), fm->id, id);
 	}
-	return dev;
+	return sock;
 }
 EXPORT_SYMBOL(tifm_alloc_device);
 
@@ -218,54 +303,15 @@ void tifm_unmap_sg(struct tifm_dev *sock
 }
 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)
+void tifm_queue_work(struct work_struct *work)
 {
-	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-	struct tifm_driver *drv = fm_dev->drv;
-
-	if (drv) {
-		fm_dev->signal_irq = tifm_dummy_signal_irq;
-		if (drv->remove)
-			drv->remove(fm_dev);
-		fm_dev->drv = NULL;
-	}
-
-	put_device(dev);
-	return 0;
+	queue_work(workqueue, work);
 }
+EXPORT_SYMBOL(tifm_queue_work);
 
 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;
-	drv->driver.suspend = tifm_device_suspend;
-	drv->driver.resume = tifm_device_resume;
 
 	return driver_register(&drv->driver);
 }
@@ -279,13 +325,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);
 
 static int __init tifm_init(void)
 {
-	int rc = bus_register(&tifm_bus_type);
+	int rc;
 
-	if (!rc) {
-		rc = class_register(&tifm_adapter_class);
-		if (rc)
-			bus_unregister(&tifm_bus_type);
-	}
+	workqueue = create_freezeable_workqueue("tifm");
+	if (!workqueue)
+		return -ENOMEM;
+
+	rc = bus_register(&tifm_bus_type);
+
+	if (rc)
+		goto err_out_wq;
+
+	rc = class_register(&tifm_adapter_class);
+	if (!rc)
+		return 0;
+
+	bus_unregister(&tifm_bus_type);
+
+err_out_wq:
+	destroy_workqueue(workqueue);
 
 	return rc;
 }
@@ -294,6 +352,7 @@ static void __exit tifm_exit(void)
 {
 	class_unregister(&tifm_adapter_class);
 	bus_unregister(&tifm_bus_type);
+	destroy_workqueue(workqueue);
 }
 
 subsys_initcall(tifm_init);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 12af9c7..6c97491 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -19,110 +19,10 @@ config MMC_DEBUG
 	  This is an option for use by developers; most people should
 	  say N here.  This enables MMC core and driver debugging.
 
-config MMC_BLOCK
-	tristate "MMC block device driver"
-	depends on MMC && BLOCK
-	default y
-	help
-	  Say Y here to enable the MMC block device driver support.
-	  This provides a block device driver, which you can use to
-	  mount the filesystem. Almost everyone wishing MMC support
-	  should say Y or M here.
-
-config MMC_ARMMMCI
-	tristate "ARM AMBA Multimedia Card Interface support"
-	depends on ARM_AMBA && MMC
-	help
-	  This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
-	  Interface (PL180 and PL181) support.  If you have an ARM(R)
-	  platform with a Multimedia Card slot, say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_PXA
-	tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
-	depends on ARCH_PXA && MMC
-	help
-	  This selects the Intel(R) PXA(R) Multimedia card Interface.
-	  If you have a PXA(R) platform with a Multimedia Card slot,
-	  say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_SDHCI
-	tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
-	depends on PCI && MMC && EXPERIMENTAL
-	help
-	  This select the generic Secure Digital Host Controller Interface.
-	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
-	  and Toshiba(R). Most controllers found in laptops are of this type.
-	  If you have a controller with this interface, say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_OMAP
-	tristate "TI OMAP Multimedia Card Interface support"
-	depends on ARCH_OMAP && MMC
-	select TPS65010 if MACH_OMAP_H2
-	help
-	  This selects the TI OMAP Multimedia card Interface.
-	  If you have an OMAP board with a Multimedia Card slot,
-	  say Y or M here.
-
-	  If unsure, say N.
+source "drivers/mmc/core/Kconfig"
 
-config MMC_WBSD
-	tristate "Winbond W83L51xD SD/MMC Card Interface support"
-	depends on MMC && ISA_DMA_API
-	help
-	  This selects the Winbond(R) W83L51xD Secure digital and
-          Multimedia card Interface.
-	  If you have a machine with a integrated W83L518D or W83L519D
-	  SD/MMC card reader, say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_AU1X
-	tristate "Alchemy AU1XX0 MMC Card Interface support"
-	depends on MMC && SOC_AU1200
-	help
-	  This selects the AMD Alchemy(R) Multimedia card interface.
-	  If you have a Alchemy platform with a MMC slot, say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_AT91
-	tristate "AT91 SD/MMC Card Interface support"
-	depends on ARCH_AT91 && MMC
-	help
-	  This selects the AT91 MCI controller.
-
-	  If unsure, say N.
-
-config MMC_IMX
-	tristate "Motorola i.MX Multimedia Card Interface support"
-	depends on ARCH_IMX && MMC
-	help
-	  This selects the Motorola i.MX Multimedia card Interface.
-	  If you have a i.MX platform with a Multimedia Card slot,
-	  say Y or M here.
-
-	  If unsure, say N.
-
-config MMC_TIFM_SD
-	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
-	depends on MMC && EXPERIMENTAL && PCI
-	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)'.
+source "drivers/mmc/card/Kconfig"
 
-          To compile this driver as a module, choose M here: the
-	  module will be called tifm_sd.
+source "drivers/mmc/host/Kconfig"
 
 endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 83ffb93..9979f5e 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -2,32 +2,11 @@ #
 # Makefile for the kernel mmc device drivers.
 #
 
-#
-# Core
-#
-obj-$(CONFIG_MMC)		+= mmc_core.o
-
-#
-# Media drivers
-#
-obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
-
-#
-# Host drivers
-#
-obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
-obj-$(CONFIG_MMC_PXA)		+= pxamci.o
-obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
-obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
-obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
-obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
-obj-$(CONFIG_MMC_OMAP)		+= omap.o
-obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
-obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
-
-mmc_core-y := mmc.o mmc_sysfs.o
-mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
-
 ifeq ($(CONFIG_MMC_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
+	EXTRA_CFLAGS		+= -DDEBUG
 endif
+
+obj-$(CONFIG_MMC)		+= core/
+obj-$(CONFIG_MMC)		+= card/
+obj-$(CONFIG_MMC)		+= host/
+
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
deleted file mode 100644
index 459f4b4..0000000
--- a/drivers/mmc/at91_mci.c
+++ /dev/null
@@ -1,1002 +0,0 @@
-/*
- *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
- *
- *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- *  Copyright (C) 2006 Malcolm Noyes
- *
- * This program is free software; you can 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 is the AT91 MCI driver that has been tested with both MMC cards
-   and SD-cards.  Boards that support write protect are now supported.
-   The CCAT91SBC001 board does not support SD cards.
-
-   The three entry points are at91_mci_request, at91_mci_set_ios
-   and at91_mci_get_ro.
-
-   SET IOS
-     This configures the device to put it into the correct mode and clock speed
-     required.
-
-   MCI REQUEST
-     MCI request processes the commands sent in the mmc_request structure. This
-     can consist of a processing command and a stop command in the case of
-     multiple block transfers.
-
-     There are three main types of request, commands, reads and writes.
-
-     Commands are straight forward. The command is submitted to the controller and
-     the request function returns. When the controller generates an interrupt to indicate
-     the command is finished, the response to the command are read and the mmc_request_done
-     function called to end the request.
-
-     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
-     controller to manage the transfers.
-
-     A read is done from the controller directly to the scatterlist passed in from the request.
-     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
-     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
-
-     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
-     A write is slightly different in that the bytes to write are read from the scatterlist
-     into a dma memory buffer (this is in case the source buffer should be read only). The
-     entire write buffer is then done from this single dma memory buffer.
-
-     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
-   GET RO
-     Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/mmc.h>
-#include <asm/arch/board.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/at91_mci.h>
-
-#define DRIVER_NAME "at91_mci"
-
-#undef	SUPPORT_4WIRE
-
-#define FL_SENT_COMMAND	(1 << 0)
-#define FL_SENT_STOP	(1 << 1)
-
-#define AT91_MCI_ERRORS	(AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE	\
-		| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE		\
-		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)			
-
-#define at91_mci_read(host, reg)	__raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val)	__raw_writel((val), (host)->baseaddr + (reg))
-
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
-	struct mmc_host *mmc;
-	struct mmc_command *cmd;
-	struct mmc_request *request;
-
-	void __iomem *baseaddr;
-	int irq;
-
-	struct at91_mmc_data *board;
-	int present;
-
-	struct clk *mci_clk;
-
-	/*
-	 * Flag indicating when the command has been sent. This is used to
-	 * work out whether or not to send the stop
-	 */
-	unsigned int flags;
-	/* flag for current bus settings */
-	u32 bus_mode;
-
-	/* DMA buffer used for transmitting */
-	unsigned int* buffer;
-	dma_addr_t physical_address;
-	unsigned int total_length;
-
-	/* Latest in the scatterlist that has been enabled for transfer, but not freed */
-	int in_use_index;
-
-	/* Latest in the scatterlist that has been enabled for transfer */
-	int transfer_index;
-};
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
-	unsigned int len, i, size;
-	unsigned *dmabuf = host->buffer;
-
-	size = host->total_length;
-	len = data->sg_len;
-
-	/*
-	 * Just loop through all entries. Size might not
-	 * be the entire list though so make sure that
-	 * we do not transfer too much.
-	 */
-	for (i = 0; i < len; i++) {
-		struct scatterlist *sg;
-		int amount;
-		unsigned int *sgbuffer;
-
-		sg = &data->sg[i];
-
-		sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-		amount = min(size, sg->length);
-		size -= amount;
-
-		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */
-			int index;
-
-			for (index = 0; index < (amount / 4); index++)
-				*dmabuf++ = swab32(sgbuffer[index]);
-		}
-		else
-			memcpy(dmabuf, sgbuffer, amount);
-
-		kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
-
-		if (size == 0)
-			break;
-	}
-
-	/*
-	 * Check that we didn't get a request to transfer
-	 * more data than can fit into the SG list.
-	 */
-	BUG_ON(size != 0);
-}
-
-/*
- * Prepare a dma read
- */
-static void at91mci_pre_dma_read(struct at91mci_host *host)
-{
-	int i;
-	struct scatterlist *sg;
-	struct mmc_command *cmd;
-	struct mmc_data *data;
-
-	pr_debug("pre dma read\n");
-
-	cmd = host->cmd;
-	if (!cmd) {
-		pr_debug("no command\n");
-		return;
-	}
-
-	data = cmd->data;
-	if (!data) {
-		pr_debug("no data\n");
-		return;
-	}
-
-	for (i = 0; i < 2; i++) {
-		/* nothing left to transfer */
-		if (host->transfer_index >= data->sg_len) {
-			pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
-			break;
-		}
-
-		/* Check to see if this needs filling */
-		if (i == 0) {
-			if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
-				pr_debug("Transfer active in current\n");
-				continue;
-			}
-		}
-		else {
-			if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
-				pr_debug("Transfer active in next\n");
-				continue;
-			}
-		}
-
-		/* Setup the next transfer */
-		pr_debug("Using transfer index %d\n", host->transfer_index);
-
-		sg = &data->sg[host->transfer_index++];
-		pr_debug("sg = %p\n", sg);
-
-		sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
-
-		pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
-
-		if (i == 0) {
-			at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
-			at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
-		}
-		else {
-			at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
-			at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
-		}
-	}
-
-	pr_debug("pre dma read done\n");
-}
-
-/*
- * Handle after a dma read
- */
-static void at91mci_post_dma_read(struct at91mci_host *host)
-{
-	struct mmc_command *cmd;
-	struct mmc_data *data;
-
-	pr_debug("post dma read\n");
-
-	cmd = host->cmd;
-	if (!cmd) {
-		pr_debug("no command\n");
-		return;
-	}
-
-	data = cmd->data;
-	if (!data) {
-		pr_debug("no data\n");
-		return;
-	}
-
-	while (host->in_use_index < host->transfer_index) {
-		unsigned int *buffer;
-
-		struct scatterlist *sg;
-
-		pr_debug("finishing index %d\n", host->in_use_index);
-
-		sg = &data->sg[host->in_use_index++];
-
-		pr_debug("Unmapping page %08X\n", sg->dma_address);
-
-		dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
-
-		/* Swap the contents of the buffer */
-		buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-		pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
-
-		data->bytes_xfered += sg->length;
-
-		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */
-			int index;
-
-			for (index = 0; index < (sg->length / 4); index++)
-				buffer[index] = swab32(buffer[index]);
-		}
-
-		kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-		flush_dcache_page(sg->page);
-	}
-
-	/* Is there another transfer to trigger? */
-	if (host->transfer_index < data->sg_len)
-		at91mci_pre_dma_read(host);
-	else {
-		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-	}
-
-	pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
-	struct mmc_command *cmd;
-	struct mmc_data *data;
-
-	pr_debug("Handling the transmit\n");
-
-	/* Disable the transfer */
-	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-	/* Now wait for cmd ready */
-	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-
-	cmd = host->cmd;
-	if (!cmd) return;
-
-	data = cmd->data;
-	if (!data) return;
-
-	data->bytes_xfered = host->total_length;
-}
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
-	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-	at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-	at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
-
-	/* use Slot A or B (only one at same time) */
-	at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
-	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- * return the interrupts to enable
- */
-static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
-	unsigned int cmdr, mr;
-	unsigned int block_length;
-	struct mmc_data *data = cmd->data;
-
-	unsigned int blocks;
-	unsigned int ier = 0;
-
-	host->cmd = cmd;
-
-	/* Not sure if this is needed */
-#if 0
-	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
-		pr_debug("Clearing timeout\n");
-		at91_mci_write(host, AT91_MCI_ARGR, 0);
-		at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-		while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
-			/* spin */
-			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
-		}
-	}
-#endif
-	cmdr = cmd->opcode;
-
-	if (mmc_resp_type(cmd) == MMC_RSP_NONE)
-		cmdr |= AT91_MCI_RSPTYP_NONE;
-	else {
-		/* if a response is expected then allow maximum response latancy */
-		cmdr |= AT91_MCI_MAXLAT;
-		/* set 136 bit response for R2, 48 bit response otherwise */
-		if (mmc_resp_type(cmd) == MMC_RSP_R2)
-			cmdr |= AT91_MCI_RSPTYP_136;
-		else
-			cmdr |= AT91_MCI_RSPTYP_48;
-	}
-
-	if (data) {
-		block_length = data->blksz;
-		blocks = data->blocks;
-
-		/* always set data start - also set direction flag for read */
-		if (data->flags & MMC_DATA_READ)
-			cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
-		else if (data->flags & MMC_DATA_WRITE)
-			cmdr |= AT91_MCI_TRCMD_START;
-
-		if (data->flags & MMC_DATA_STREAM)
-			cmdr |= AT91_MCI_TRTYP_STREAM;
-		if (data->flags & MMC_DATA_MULTI)
-			cmdr |= AT91_MCI_TRTYP_MULTIPLE;
-	}
-	else {
-		block_length = 0;
-		blocks = 0;
-	}
-
-	if (cmd->opcode == MMC_STOP_TRANSMISSION)
-		cmdr |= AT91_MCI_TRCMD_STOP;
-
-	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
-		cmdr |= AT91_MCI_OPDCMD;
-
-	/*
-	 * Set the arguments and send the command
-	 */
-	pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
-		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
-	if (!data) {
-		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
-		at91_mci_write(host, ATMEL_PDC_RPR, 0);
-		at91_mci_write(host, ATMEL_PDC_RCR, 0);
-		at91_mci_write(host, ATMEL_PDC_RNPR, 0);
-		at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-		at91_mci_write(host, ATMEL_PDC_TPR, 0);
-		at91_mci_write(host, ATMEL_PDC_TCR, 0);
-		at91_mci_write(host, ATMEL_PDC_TNPR, 0);
-		at91_mci_write(host, ATMEL_PDC_TNCR, 0);
-
-		at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-		at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-		return AT91_MCI_CMDRDY;
-	}
-
-	mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;	/* zero block length and PDC mode */
-	at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
-
-	/*
-	 * Disable the PDC controller
-	 */
-	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-	if (cmdr & AT91_MCI_TRCMD_START) {
-		data->bytes_xfered = 0;
-		host->transfer_index = 0;
-		host->in_use_index = 0;
-		if (cmdr & AT91_MCI_TRDIR) {
-			/*
-			 * Handle a read
-			 */
-			host->buffer = NULL;
-			host->total_length = 0;
-
-			at91mci_pre_dma_read(host);
-			ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
-		}
-		else {
-			/*
-			 * Handle a write
-			 */
-			host->total_length = block_length * blocks;
-			host->buffer = dma_alloc_coherent(NULL,
-						  host->total_length,
-						  &host->physical_address, GFP_KERNEL);
-
-			at91mci_sg_to_dma(host, data);
-
-			pr_debug("Transmitting %d bytes\n", host->total_length);
-
-			at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
-			at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
-			ier = AT91_MCI_TXBUFE;
-		}
-	}
-
-	/*
-	 * Send the command and then enable the PDC - not the other way round as
-	 * the data sheet says
-	 */
-
-	at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-	at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
-	if (cmdr & AT91_MCI_TRCMD_START) {
-		if (cmdr & AT91_MCI_TRDIR)
-			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
-		else
-			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-	}
-	return ier;
-}
-
-/*
- * Wait for a command to complete
- */
-static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
-	unsigned int ier;
-
-	ier = at91_mci_send_command(host, cmd);
-
-	pr_debug("setting ier to %08X\n", ier);
-
-	/* Stop on errors or the required value */
-	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91mci_process_next(struct at91mci_host *host)
-{
-	if (!(host->flags & FL_SENT_COMMAND)) {
-		host->flags |= FL_SENT_COMMAND;
-		at91mci_process_command(host, host->request->cmd);
-	}
-	else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
-		host->flags |= FL_SENT_STOP;
-		at91mci_process_command(host, host->request->stop);
-	}
-	else
-		mmc_request_done(host->mmc, host->request);
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91mci_completed_command(struct at91mci_host *host)
-{
-	struct mmc_command *cmd = host->cmd;
-	unsigned int status;
-
-	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
-	cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
-	cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
-	cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
-	cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
-	if (host->buffer) {
-		dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
-		host->buffer = NULL;
-	}
-
-	status = at91_mci_read(host, AT91_MCI_SR);
-
-	pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
-		 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
-	if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
-			AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
-			AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
-		if ((status & AT91_MCI_RCRCE) &&
-			((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
-			cmd->error = MMC_ERR_NONE;
-		}
-		else {
-			if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
-				cmd->error = MMC_ERR_TIMEOUT;
-			else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
-				cmd->error = MMC_ERR_BADCRC;
-			else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
-				cmd->error = MMC_ERR_FIFO;
-			else
-				cmd->error = MMC_ERR_FAILED;
-
-			pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
-				 cmd->error, cmd->opcode, cmd->retries);
-		}
-	}
-	else
-		cmd->error = MMC_ERR_NONE;
-
-	at91mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct at91mci_host *host = mmc_priv(mmc);
-	host->request = mrq;
-	host->flags = 0;
-
-	at91mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	int clkdiv;
-	struct at91mci_host *host = mmc_priv(mmc);
-	unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
-	host->bus_mode = ios->bus_mode;
-
-	if (ios->clock == 0) {
-		/* Disable the MCI controller */
-		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
-		clkdiv = 0;
-	}
-	else {
-		/* Enable the MCI controller */
-		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
-		if ((at91_master_clock % (ios->clock * 2)) == 0)
-			clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
-		else
-			clkdiv = (at91_master_clock / ios->clock) / 2;
-
-		pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
-			at91_master_clock / (2 * (clkdiv + 1)));
-	}
-	if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
-		pr_debug("MMC: Setting controller bus width to 4\n");
-		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
-	}
-	else {
-		pr_debug("MMC: Setting controller bus width to 1\n");
-		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-	}
-
-	/* Set the clock divider */
-	at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
-	/* maybe switch power to the card */
-	if (host->board->vcc_pin) {
-		switch (ios->power_mode) {
-			case MMC_POWER_OFF:
-				at91_set_gpio_value(host->board->vcc_pin, 0);
-				break;
-			case MMC_POWER_UP:
-			case MMC_POWER_ON:
-				at91_set_gpio_value(host->board->vcc_pin, 1);
-				break;
-		}
-	}
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
-	struct at91mci_host *host = devid;
-	int completed = 0;
-	unsigned int int_status, int_mask;
-
-	int_status = at91_mci_read(host, AT91_MCI_SR);
-	int_mask = at91_mci_read(host, AT91_MCI_IMR);
-	
-	pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
-		int_status & int_mask);
-	
-	int_status = int_status & int_mask;
-
-	if (int_status & AT91_MCI_ERRORS) {
-		completed = 1;
-		
-		if (int_status & AT91_MCI_UNRE)
-			pr_debug("MMC: Underrun error\n");
-		if (int_status & AT91_MCI_OVRE)
-			pr_debug("MMC: Overrun error\n");
-		if (int_status & AT91_MCI_DTOE)
-			pr_debug("MMC: Data timeout\n");
-		if (int_status & AT91_MCI_DCRCE)
-			pr_debug("MMC: CRC error in data\n");
-		if (int_status & AT91_MCI_RTOE)
-			pr_debug("MMC: Response timeout\n");
-		if (int_status & AT91_MCI_RENDE)
-			pr_debug("MMC: Response end bit error\n");
-		if (int_status & AT91_MCI_RCRCE)
-			pr_debug("MMC: Response CRC error\n");
-		if (int_status & AT91_MCI_RDIRE)
-			pr_debug("MMC: Response direction error\n");
-		if (int_status & AT91_MCI_RINDE)
-			pr_debug("MMC: Response index error\n");
-	} else {
-		/* Only continue processing if no errors */
-
-		if (int_status & AT91_MCI_TXBUFE) {
-			pr_debug("TX buffer empty\n");
-			at91_mci_handle_transmitted(host);
-		}
-
-		if (int_status & AT91_MCI_RXBUFF) {
-			pr_debug("RX buffer full\n");
-			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
-		}
-
-		if (int_status & AT91_MCI_ENDTX)
-			pr_debug("Transmit has ended\n");
-
-		if (int_status & AT91_MCI_ENDRX) {
-			pr_debug("Receive has ended\n");
-			at91mci_post_dma_read(host);
-		}
-
-		if (int_status & AT91_MCI_NOTBUSY) {
-			pr_debug("Card is ready\n");
-			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
-		}
-
-		if (int_status & AT91_MCI_DTIP)
-			pr_debug("Data transfer in progress\n");
-
-		if (int_status & AT91_MCI_BLKE)
-			pr_debug("Block transfer has ended\n");
-
-		if (int_status & AT91_MCI_TXRDY)
-			pr_debug("Ready to transmit\n");
-
-		if (int_status & AT91_MCI_RXRDY)
-			pr_debug("Ready to receive\n");
-
-		if (int_status & AT91_MCI_CMDRDY) {
-			pr_debug("Command ready\n");
-			completed = 1;
-		}
-	}
-
-	if (completed) {
-		pr_debug("Completed command\n");
-		at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-		at91mci_completed_command(host);
-	} else
-		at91_mci_write(host, AT91_MCI_IDR, int_status);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
-	struct at91mci_host *host = _host;
-	int present = !at91_get_gpio_value(irq);
-
-	/*
-	 * we expect this irq on both insert and remove,
-	 * and use a short delay to debounce.
-	 */
-	if (present != host->present) {
-		host->present = present;
-		pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
-			present ? "insert" : "remove");
-		if (!present) {
-			pr_debug("****** Resetting SD-card bus width ******\n");
-			at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-		}
-		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-	}
-	return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
-	int read_only = 0;
-	struct at91mci_host *host = mmc_priv(mmc);
-
-	if (host->board->wp_pin) {
-		read_only = at91_get_gpio_value(host->board->wp_pin);
-		printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
-				(read_only ? "read-only" : "read-write") );
-	}
-	else {
-		printk(KERN_WARNING "%s: host does not support reading read-only "
-				"switch.  Assuming write-enable.\n", mmc_hostname(mmc));
-	}
-	return read_only;
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
-	.request	= at91_mci_request,
-	.set_ios	= at91_mci_set_ios,
-	.get_ro		= at91_mci_get_ro,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
-	struct mmc_host *mmc;
-	struct at91mci_host *host;
-	struct resource *res;
-	int ret;
-
-	pr_debug("Probe MCI devices\n");
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENXIO;
-
-	if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
-		return -EBUSY;
-
-	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
-	if (!mmc) {
-		pr_debug("Failed to allocate mmc host\n");
-		release_mem_region(res->start, res->end - res->start + 1);
-		return -ENOMEM;
-	}
-
-	mmc->ops = &at91_mci_ops;
-	mmc->f_min = 375000;
-	mmc->f_max = 25000000;
-	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps = MMC_CAP_BYTEBLOCK;
-
-	mmc->max_blk_size = 4095;
-	mmc->max_blk_count = mmc->max_req_size;
-
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
-	host->buffer = NULL;
-	host->bus_mode = 0;
-	host->board = pdev->dev.platform_data;
-	if (host->board->wire4) {
-#ifdef SUPPORT_4WIRE
-		mmc->caps |= MMC_CAP_4_BIT_DATA;
-#else
-		printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
-#endif
-	}
-
-	/*
-	 * Get Clock
-	 */
-	host->mci_clk = clk_get(&pdev->dev, "mci_clk");
-	if (IS_ERR(host->mci_clk)) {
-		printk(KERN_ERR "AT91 MMC: no clock defined.\n");
-		mmc_free_host(mmc);
-		release_mem_region(res->start, res->end - res->start + 1);
-		return -ENODEV;
-	}
-
-	/*
-	 * Map I/O region
-	 */
-	host->baseaddr = ioremap(res->start, res->end - res->start + 1);
-	if (!host->baseaddr) {
-		clk_put(host->mci_clk);
-		mmc_free_host(mmc);
-		release_mem_region(res->start, res->end - res->start + 1);
-		return -ENOMEM;
-	}
-
-	/*
-	 * Reset hardware
-	 */
-	clk_enable(host->mci_clk);		/* Enable the peripheral clock */
-	at91_mci_disable(host);
-	at91_mci_enable(host);
-
-	/*
-	 * Allocate the MCI interrupt
-	 */
-	host->irq = platform_get_irq(pdev, 0);
-	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
-	if (ret) {
-		printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
-		clk_disable(host->mci_clk);
-		clk_put(host->mci_clk);
-		mmc_free_host(mmc);
-		iounmap(host->baseaddr);
-		release_mem_region(res->start, res->end - res->start + 1);
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, mmc);
-
-	/*
-	 * Add host to MMC layer
-	 */
-	if (host->board->det_pin)
-		host->present = !at91_get_gpio_value(host->board->det_pin);
-	else
-		host->present = -1;
-
-	mmc_add_host(mmc);
-
-	/*
-	 * monitor card insertion/removal if we can
-	 */
-	if (host->board->det_pin) {
-		ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
-				0, DRIVER_NAME, host);
-		if (ret)
-			printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
-	}
-
-	pr_debug("Added MCI driver\n");
-
-	return 0;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(pdev);
-	struct at91mci_host *host;
-	struct resource *res;
-
-	if (!mmc)
-		return -1;
-
-	host = mmc_priv(mmc);
-
-	if (host->present != -1) {
-		free_irq(host->board->det_pin, host);
-		cancel_delayed_work(&host->mmc->detect);
-	}
-
-	at91_mci_disable(host);
-	mmc_remove_host(mmc);
-	free_irq(host->irq, host);
-
-	clk_disable(host->mci_clk);			/* Disable the peripheral clock */
-	clk_put(host->mci_clk);
-
-	iounmap(host->baseaddr);
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, res->end - res->start + 1);
-
-	mmc_free_host(mmc);
-	platform_set_drvdata(pdev, NULL);
-	pr_debug("MCI Removed\n");
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	struct mmc_host *mmc = platform_get_drvdata(pdev);
-	int ret = 0;
-
-	if (mmc)
-		ret = mmc_suspend_host(mmc, state);
-
-	return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(pdev);
-	int ret = 0;
-
-	if (mmc)
-		ret = mmc_resume_host(mmc);
-
-	return ret;
-}
-#else
-#define at91_mci_suspend	NULL
-#define at91_mci_resume		NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
-	.remove		= __exit_p(at91_mci_remove),
-	.suspend	= at91_mci_suspend,
-	.resume		= at91_mci_resume,
-	.driver		= {
-		.name	= DRIVER_NAME,
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init at91_mci_init(void)
-{
-	return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
-	platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
deleted file mode 100644
index b834be2..0000000
--- a/drivers/mmc/au1xmmc.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
- *
- *  Copyright (c) 2005, Advanced Micro Devices, Inc.
- *
- *  Developed with help from the 2.4.30 MMC AU1XXX controller including
- *  the following copyright notices:
- *     Copyright (c) 2003-2004 Embedded Edge, LLC.
- *     Portions Copyright (C) 2002 Embedix, Inc
- *     Copyright 2002 Hewlett-Packard Company
-
- *  2.6 version of this driver inspired by:
- *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
- *     All Rights Reserved.
- *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
- *     All Rights Reserved.
- *
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* Why is a timer used to detect insert events?
- *
- * From the AU1100 MMC application guide:
- * If the Au1100-based design is intended to support both MultiMediaCards
- * and 1- or 4-data bit SecureDigital cards, then the solution is to
- * connect a weak (560KOhm) pull-up resistor to connector pin 1.
- * In doing so, a MMC card never enters SPI-mode communications,
- * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
- * (the low to high transition will not occur).
- *
- * So we use the timer to check the status manually.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-#include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1100_mmc.h>
-#include <asm/scatterlist.h>
-
-#include <au1xxx.h>
-#include "au1xmmc.h"
-
-#define DRIVER_NAME "au1xxx-mmc"
-
-/* Set this to enable special debugging macros */
-
-#ifdef DEBUG
-#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)
-#else
-#define DBG(fmt, idx, args...)
-#endif
-
-const struct {
-	u32 iobase;
-	u32 tx_devid, rx_devid;
-	u16 bcsrpwr;
-	u16 bcsrstatus;
-	u16 wpstatus;
-} au1xmmc_card_table[] = {
-	{ SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
-	  BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
-#ifndef CONFIG_MIPS_DB1200
-	{ SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
-	  BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
-#endif
-};
-
-#define AU1XMMC_CONTROLLER_COUNT \
-	(sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
-
-/* This array stores pointers for the hosts (used by the IRQ handler) */
-struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
-static int dma = 1;
-
-#ifdef MODULE
-module_param(dma, bool, 0);
-MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
-#endif
-
-static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
-{
-	u32 val = au_readl(HOST_CONFIG(host));
-	val |= mask;
-	au_writel(val, HOST_CONFIG(host));
-	au_sync();
-}
-
-static inline void FLUSH_FIFO(struct au1xmmc_host *host)
-{
-	u32 val = au_readl(HOST_CONFIG2(host));
-
-	au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
-	au_sync_delay(1);
-
-	/* SEND_STOP will turn off clock control - this re-enables it */
-	val &= ~SD_CONFIG2_DF;
-
-	au_writel(val, HOST_CONFIG2(host));
-	au_sync();
-}
-
-static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
-{
-	u32 val = au_readl(HOST_CONFIG(host));
-	val &= ~mask;
-	au_writel(val, HOST_CONFIG(host));
-	au_sync();
-}
-
-static inline void SEND_STOP(struct au1xmmc_host *host)
-{
-
-	/* We know the value of CONFIG2, so avoid a read we don't need */
-	u32 mask = SD_CONFIG2_EN;
-
-	WARN_ON(host->status != HOST_S_DATA);
-	host->status = HOST_S_STOP;
-
-	au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
-	au_sync();
-
-	/* Send the stop commmand */
-	au_writel(STOP_CMD, HOST_CMD(host));
-}
-
-static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
-{
-
-	u32 val = au1xmmc_card_table[host->id].bcsrpwr;
-
-	bcsr->board &= ~val;
-	if (state) bcsr->board |= val;
-
-	au_sync_delay(1);
-}
-
-static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
-{
-	return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
-		? 1 : 0;
-}
-
-static int au1xmmc_card_readonly(struct mmc_host *mmc)
-{
-	struct au1xmmc_host *host = mmc_priv(mmc);
-	return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
-		? 1 : 0;
-}
-
-static void au1xmmc_finish_request(struct au1xmmc_host *host)
-{
-
-	struct mmc_request *mrq = host->mrq;
-
-	host->mrq = NULL;
-	host->flags &= HOST_F_ACTIVE;
-
-	host->dma.len = 0;
-	host->dma.dir = 0;
-
-	host->pio.index  = 0;
-	host->pio.offset = 0;
-	host->pio.len = 0;
-
-	host->status = HOST_S_IDLE;
-
-	bcsr->disk_leds |= (1 << 8);
-
-	mmc_request_done(host->mmc, mrq);
-}
-
-static void au1xmmc_tasklet_finish(unsigned long param)
-{
-	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
-	au1xmmc_finish_request(host);
-}
-
-static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
-				struct mmc_command *cmd)
-{
-
-	u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
-
-	switch (mmc_resp_type(cmd)) {
-	case MMC_RSP_NONE:
-		break;
-	case MMC_RSP_R1:
-		mmccmd |= SD_CMD_RT_1;
-		break;
-	case MMC_RSP_R1B:
-		mmccmd |= SD_CMD_RT_1B;
-		break;
-	case MMC_RSP_R2:
-		mmccmd |= SD_CMD_RT_2;
-		break;
-	case MMC_RSP_R3:
-		mmccmd |= SD_CMD_RT_3;
-		break;
-	default:
-		printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
-			mmc_resp_type(cmd));
-		return MMC_ERR_INVALID;
-	}
-
-	switch(cmd->opcode) {
-	case MMC_READ_SINGLE_BLOCK:
-	case SD_APP_SEND_SCR:
-		mmccmd |= SD_CMD_CT_2;
-		break;
-	case MMC_READ_MULTIPLE_BLOCK:
-		mmccmd |= SD_CMD_CT_4;
-		break;
-	case MMC_WRITE_BLOCK:
-		mmccmd |= SD_CMD_CT_1;
-		break;
-
-	case MMC_WRITE_MULTIPLE_BLOCK:
-		mmccmd |= SD_CMD_CT_3;
-		break;
-	case MMC_STOP_TRANSMISSION:
-		mmccmd |= SD_CMD_CT_7;
-		break;
-	}
-
-	au_writel(cmd->arg, HOST_CMDARG(host));
-	au_sync();
-
-	if (wait)
-		IRQ_OFF(host, SD_CONFIG_CR);
-
-	au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
-	au_sync();
-
-	/* Wait for the command to go on the line */
-
-	while(1) {
-		if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
-			break;
-	}
-
-	/* Wait for the command to come back */
-
-	if (wait) {
-		u32 status = au_readl(HOST_STATUS(host));
-
-		while(!(status & SD_STATUS_CR))
-			status = au_readl(HOST_STATUS(host));
-
-		/* Clear the CR status */
-		au_writel(SD_STATUS_CR, HOST_STATUS(host));
-
-		IRQ_ON(host, SD_CONFIG_CR);
-	}
-
-	return MMC_ERR_NONE;
-}
-
-static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
-{
-
-	struct mmc_request *mrq = host->mrq;
-	struct mmc_data *data;
-	u32 crc;
-
-	WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
-
-	if (host->mrq == NULL)
-		return;
-
-	data = mrq->cmd->data;
-
-	if (status == 0)
-		status = au_readl(HOST_STATUS(host));
-
-	/* The transaction is really over when the SD_STATUS_DB bit is clear */
-
-	while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
-		status = au_readl(HOST_STATUS(host));
-
-	data->error = MMC_ERR_NONE;
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
-
-        /* Process any errors */
-
-	crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
-	if (host->flags & HOST_F_XMIT)
-		crc |= ((status & 0x07) == 0x02) ? 0 : 1;
-
-	if (crc)
-		data->error = MMC_ERR_BADCRC;
-
-	/* Clear the CRC bits */
-	au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
-
-	data->bytes_xfered = 0;
-
-	if (data->error == MMC_ERR_NONE) {
-		if (host->flags & HOST_F_DMA) {
-			u32 chan = DMA_CHANNEL(host);
-
-			chan_tab_t *c = *((chan_tab_t **) chan);
-			au1x_dma_chan_t *cp = c->chan_ptr;
-			data->bytes_xfered = cp->ddma_bytecnt;
-		}
-		else
-			data->bytes_xfered =
-				(data->blocks * data->blksz) -
-				host->pio.len;
-	}
-
-	au1xmmc_finish_request(host);
-}
-
-static void au1xmmc_tasklet_data(unsigned long param)
-{
-	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
-
-	u32 status = au_readl(HOST_STATUS(host));
-	au1xmmc_data_complete(host, status);
-}
-
-#define AU1XMMC_MAX_TRANSFER 8
-
-static void au1xmmc_send_pio(struct au1xmmc_host *host)
-{
-
-	struct mmc_data *data = 0;
-	int sg_len, max, count = 0;
-	unsigned char *sg_ptr;
-	u32 status = 0;
-	struct scatterlist *sg;
-
-	data = host->mrq->data;
-
-	if (!(host->flags & HOST_F_XMIT))
-		return;
-
-	/* This is the pointer to the data buffer */
-	sg = &data->sg[host->pio.index];
-	sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
-
-	/* This is the space left inside the buffer */
-	sg_len = data->sg[host->pio.index].length - host->pio.offset;
-
-	/* Check to if we need less then the size of the sg_buffer */
-
-	max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
-	if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
-
-	for(count = 0; count < max; count++ ) {
-		unsigned char val;
-
-		status = au_readl(HOST_STATUS(host));
-
-		if (!(status & SD_STATUS_TH))
-			break;
-
-		val = *sg_ptr++;
-
-		au_writel((unsigned long) val, HOST_TXPORT(host));
-		au_sync();
-	}
-
-	host->pio.len -= count;
-	host->pio.offset += count;
-
-	if (count == sg_len) {
-		host->pio.index++;
-		host->pio.offset = 0;
-	}
-
-	if (host->pio.len == 0) {
-		IRQ_OFF(host, SD_CONFIG_TH);
-
-		if (host->flags & HOST_F_STOP)
-			SEND_STOP(host);
-
-		tasklet_schedule(&host->data_task);
-	}
-}
-
-static void au1xmmc_receive_pio(struct au1xmmc_host *host)
-{
-
-	struct mmc_data *data = 0;
-	int sg_len = 0, max = 0, count = 0;
-	unsigned char *sg_ptr = 0;
-	u32 status = 0;
-	struct scatterlist *sg;
-
-	data = host->mrq->data;
-
-	if (!(host->flags & HOST_F_RECV))
-		return;
-
-	max = host->pio.len;
-
-	if (host->pio.index < host->dma.len) {
-		sg = &data->sg[host->pio.index];
-		sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
-
-		/* This is the space left inside the buffer */
-		sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
-
-		/* Check to if we need less then the size of the sg_buffer */
-		if (sg_len < max) max = sg_len;
-	}
-
-	if (max > AU1XMMC_MAX_TRANSFER)
-		max = AU1XMMC_MAX_TRANSFER;
-
-	for(count = 0; count < max; count++ ) {
-		u32 val;
-		status = au_readl(HOST_STATUS(host));
-
-		if (!(status & SD_STATUS_NE))
-			break;
-
-		if (status & SD_STATUS_RC) {
-			DBG("RX CRC Error [%d + %d].\n", host->id,
-					host->pio.len, count);
-			break;
-		}
-
-		if (status & SD_STATUS_RO) {
-			DBG("RX Overrun [%d + %d]\n", host->id,
-					host->pio.len, count);
-			break;
-		}
-		else if (status & SD_STATUS_RU) {
-			DBG("RX Underrun [%d + %d]\n", host->id,
-					host->pio.len,	count);
-			break;
-		}
-
-		val = au_readl(HOST_RXPORT(host));
-
-		if (sg_ptr)
-			*sg_ptr++ = (unsigned char) (val & 0xFF);
-	}
-
-	host->pio.len -= count;
-	host->pio.offset += count;
-
-	if (sg_len && count == sg_len) {
-		host->pio.index++;
-		host->pio.offset = 0;
-	}
-
-	if (host->pio.len == 0) {
-		//IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
-		IRQ_OFF(host, SD_CONFIG_NE);
-
-		if (host->flags & HOST_F_STOP)
-			SEND_STOP(host);
-
-		tasklet_schedule(&host->data_task);
-	}
-}
-
-/* static void au1xmmc_cmd_complete
-   This is called when a command has been completed - grab the response
-   and check for errors.  Then start the data transfer if it is indicated.
-*/
-
-static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
-{
-
-	struct mmc_request *mrq = host->mrq;
-	struct mmc_command *cmd;
-	int trans;
-
-	if (!host->mrq)
-		return;
-
-	cmd = mrq->cmd;
-	cmd->error = MMC_ERR_NONE;
-
-	if (cmd->flags & MMC_RSP_PRESENT) {
-		if (cmd->flags & MMC_RSP_136) {
-			u32 r[4];
-			int i;
-
-			r[0] = au_readl(host->iobase + SD_RESP3);
-			r[1] = au_readl(host->iobase + SD_RESP2);
-			r[2] = au_readl(host->iobase + SD_RESP1);
-			r[3] = au_readl(host->iobase + SD_RESP0);
-
-			/* The CRC is omitted from the response, so really
-			 * we only got 120 bytes, but the engine expects
-			 * 128 bits, so we have to shift things up
-			 */
-
-			for(i = 0; i < 4; i++) {
-				cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
-				if (i != 3)
-					cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
-			}
-		} else {
-			/* Techincally, we should be getting all 48 bits of
-			 * the response (SD_RESP1 + SD_RESP2), but because
-			 * our response omits the CRC, our data ends up
-			 * being shifted 8 bits to the right.  In this case,
-			 * that means that the OSR data starts at bit 31,
-			 * so we can just read RESP0 and return that
-			 */
-			cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
-		}
-	}
-
-        /* Figure out errors */
-
-	if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
-		cmd->error = MMC_ERR_BADCRC;
-
-	trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
-
-	if (!trans || cmd->error != MMC_ERR_NONE) {
-
-		IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
-		tasklet_schedule(&host->finish_task);
-		return;
-	}
-
-	host->status = HOST_S_DATA;
-
-	if (host->flags & HOST_F_DMA) {
-		u32 channel = DMA_CHANNEL(host);
-
-		/* Start the DMA as soon as the buffer gets something in it */
-
-		if (host->flags & HOST_F_RECV) {
-			u32 mask = SD_STATUS_DB | SD_STATUS_NE;
-
-			while((status & mask) != mask)
-				status = au_readl(HOST_STATUS(host));
-		}
-
-		au1xxx_dbdma_start(channel);
-	}
-}
-
-static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
-{
-
-	unsigned int pbus = get_au1x00_speed();
-	unsigned int divisor;
-	u32 config;
-
-	/* From databook:
-	   divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
-	*/
-
-	pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
-	pbus /= 2;
-
-	divisor = ((pbus / rate) / 2) - 1;
-
-	config = au_readl(HOST_CONFIG(host));
-
-	config &= ~(SD_CONFIG_DIV);
-	config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
-
-	au_writel(config, HOST_CONFIG(host));
-	au_sync();
-}
-
-static int
-au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
-{
-
-	int datalen = data->blocks * data->blksz;
-
-	if (dma != 0)
-		host->flags |= HOST_F_DMA;
-
-	if (data->flags & MMC_DATA_READ)
-		host->flags |= HOST_F_RECV;
-	else
-		host->flags |= HOST_F_XMIT;
-
-	if (host->mrq->stop)
-		host->flags |= HOST_F_STOP;
-
-	host->dma.dir = DMA_BIDIRECTIONAL;
-
-	host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
-				   data->sg_len, host->dma.dir);
-
-	if (host->dma.len == 0)
-		return MMC_ERR_TIMEOUT;
-
-	au_writel(data->blksz - 1, HOST_BLKSIZE(host));
-
-	if (host->flags & HOST_F_DMA) {
-		int i;
-		u32 channel = DMA_CHANNEL(host);
-
-		au1xxx_dbdma_stop(channel);
-
-		for(i = 0; i < host->dma.len; i++) {
-			u32 ret = 0, flags = DDMA_FLAGS_NOIE;
-			struct scatterlist *sg = &data->sg[i];
-			int sg_len = sg->length;
-
-			int len = (datalen > sg_len) ? sg_len : datalen;
-
-			if (i == host->dma.len - 1)
-				flags = DDMA_FLAGS_IE;
-
-    			if (host->flags & HOST_F_XMIT){
-      				ret = au1xxx_dbdma_put_source_flags(channel,
-					(void *) (page_address(sg->page) +
-						  sg->offset),
-					len, flags);
-			}
-    			else {
-      				ret = au1xxx_dbdma_put_dest_flags(channel,
-					(void *) (page_address(sg->page) +
-						  sg->offset),
-					len, flags);
-			}
-
-    			if (!ret)
-				goto dataerr;
-
-			datalen -= len;
-		}
-	}
-	else {
-		host->pio.index = 0;
-		host->pio.offset = 0;
-		host->pio.len = datalen;
-
-		if (host->flags & HOST_F_XMIT)
-			IRQ_ON(host, SD_CONFIG_TH);
-		else
-			IRQ_ON(host, SD_CONFIG_NE);
-			//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
-	}
-
-	return MMC_ERR_NONE;
-
- dataerr:
-	dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
-	return MMC_ERR_TIMEOUT;
-}
-
-/* static void au1xmmc_request
-   This actually starts a command or data transaction
-*/
-
-static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
-{
-
-	struct au1xmmc_host *host = mmc_priv(mmc);
-	int ret = MMC_ERR_NONE;
-
-	WARN_ON(irqs_disabled());
-	WARN_ON(host->status != HOST_S_IDLE);
-
-	host->mrq = mrq;
-	host->status = HOST_S_CMD;
-
-	bcsr->disk_leds &= ~(1 << 8);
-
-	if (mrq->data) {
-		FLUSH_FIFO(host);
-		ret = au1xmmc_prepare_data(host, mrq->data);
-	}
-
-	if (ret == MMC_ERR_NONE)
-		ret = au1xmmc_send_command(host, 0, mrq->cmd);
-
-	if (ret != MMC_ERR_NONE) {
-		mrq->cmd->error = ret;
-		au1xmmc_finish_request(host);
-	}
-}
-
-static void au1xmmc_reset_controller(struct au1xmmc_host *host)
-{
-
-	/* Apply the clock */
-	au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
-        au_sync_delay(1);
-
-	au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
-	au_sync_delay(5);
-
-	au_writel(~0, HOST_STATUS(host));
-	au_sync();
-
-	au_writel(0, HOST_BLKSIZE(host));
-	au_writel(0x001fffff, HOST_TIMEOUT(host));
-	au_sync();
-
-	au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
-        au_sync();
-
-	au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
-	au_sync_delay(1);
-
-	au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
-	au_sync();
-
-	/* Configure interrupts */
-	au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
-	au_sync();
-}
-
-
-static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
-{
-	struct au1xmmc_host *host = mmc_priv(mmc);
-
-	if (ios->power_mode == MMC_POWER_OFF)
-		au1xmmc_set_power(host, 0);
-	else if (ios->power_mode == MMC_POWER_ON) {
-		au1xmmc_set_power(host, 1);
-	}
-
-	if (ios->clock && ios->clock != host->clock) {
-		au1xmmc_set_clock(host, ios->clock);
-		host->clock = ios->clock;
-	}
-}
-
-static void au1xmmc_dma_callback(int irq, void *dev_id)
-{
-	struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
-
-	/* Avoid spurious interrupts */
-
-	if (!host->mrq)
-		return;
-
-	if (host->flags & HOST_F_STOP)
-		SEND_STOP(host);
-
-	tasklet_schedule(&host->data_task);
-}
-
-#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
-#define STATUS_DATA_IN  (SD_STATUS_NE)
-#define STATUS_DATA_OUT (SD_STATUS_TH)
-
-static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
-{
-
-	u32 status;
-	int i, ret = 0;
-
-	disable_irq(AU1100_SD_IRQ);
-
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct au1xmmc_host * host = au1xmmc_hosts[i];
-		u32 handled = 1;
-
-		status = au_readl(HOST_STATUS(host));
-
-		if (host->mrq && (status & STATUS_TIMEOUT)) {
-			if (status & SD_STATUS_RAT)
-				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-
-			else if (status & SD_STATUS_DT)
-				host->mrq->data->error = MMC_ERR_TIMEOUT;
-
-			/* In PIO mode, interrupts might still be enabled */
-			IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
-
-			//IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
-			tasklet_schedule(&host->finish_task);
-		}
-#if 0
-		else if (status & SD_STATUS_DD) {
-
-			/* Sometimes we get a DD before a NE in PIO mode */
-
-			if (!(host->flags & HOST_F_DMA) &&
-					(status & SD_STATUS_NE))
-				au1xmmc_receive_pio(host);
-			else {
-				au1xmmc_data_complete(host, status);
-				//tasklet_schedule(&host->data_task);
-			}
-		}
-#endif
-		else if (status & (SD_STATUS_CR)) {
-			if (host->status == HOST_S_CMD)
-				au1xmmc_cmd_complete(host,status);
-		}
-		else if (!(host->flags & HOST_F_DMA)) {
-			if ((host->flags & HOST_F_XMIT) &&
-			    (status & STATUS_DATA_OUT))
-				au1xmmc_send_pio(host);
-			else if ((host->flags & HOST_F_RECV) &&
-			    (status & STATUS_DATA_IN))
-				au1xmmc_receive_pio(host);
-		}
-		else if (status & 0x203FBC70) {
-			DBG("Unhandled status %8.8x\n", host->id, status);
-			handled = 0;
-		}
-
-		au_writel(status, HOST_STATUS(host));
-		au_sync();
-
-		ret |= handled;
-	}
-
-	enable_irq(AU1100_SD_IRQ);
-	return ret;
-}
-
-static void au1xmmc_poll_event(unsigned long arg)
-{
-	struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
-
-	int card = au1xmmc_card_inserted(host);
-        int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
-
-	if (card != controller) {
-		host->flags &= ~HOST_F_ACTIVE;
-		if (card) host->flags |= HOST_F_ACTIVE;
-		mmc_detect_change(host->mmc, 0);
-	}
-
-	if (host->mrq != NULL) {
-		u32 status = au_readl(HOST_STATUS(host));
-		DBG("PENDING - %8.8x\n", host->id, status);
-	}
-
-	mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
-}
-
-static dbdev_tab_t au1xmmc_mem_dbdev =
-{
-	DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
-};
-
-static void au1xmmc_init_dma(struct au1xmmc_host *host)
-{
-
-	u32 rxchan, txchan;
-
-	int txid = au1xmmc_card_table[host->id].tx_devid;
-	int rxid = au1xmmc_card_table[host->id].rx_devid;
-
-	/* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
-	   of 8 bits.  And since devices are shared, we need to create
-	   our own to avoid freaking out other devices
-	*/
-
-	int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
-
-	txchan = au1xxx_dbdma_chan_alloc(memid, txid,
-					 au1xmmc_dma_callback, (void *) host);
-
-	rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
-					 au1xmmc_dma_callback, (void *) host);
-
-	au1xxx_dbdma_set_devwidth(txchan, 8);
-	au1xxx_dbdma_set_devwidth(rxchan, 8);
-
-	au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);
-	au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);
-
-	host->tx_chan = txchan;
-	host->rx_chan = rxchan;
-}
-
-static const struct mmc_host_ops au1xmmc_ops = {
-	.request	= au1xmmc_request,
-	.set_ios	= au1xmmc_set_ios,
-	.get_ro		= au1xmmc_card_readonly,
-};
-
-static int __devinit au1xmmc_probe(struct platform_device *pdev)
-{
-
-	int i, ret = 0;
-
-	/* THe interrupt is shared among all controllers */
-	ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
-
-	if (ret) {
-		printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
-				AU1100_SD_IRQ, ret);
-		return -ENXIO;
-	}
-
-	disable_irq(AU1100_SD_IRQ);
-
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
-		struct au1xmmc_host *host = 0;
-
-		if (!mmc) {
-			printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
-			au1xmmc_hosts[i] = 0;
-			continue;
-		}
-
-		mmc->ops = &au1xmmc_ops;
-
-		mmc->f_min =   450000;
-		mmc->f_max = 24000000;
-
-		mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
-
-		mmc->max_blk_size = 2048;
-		mmc->max_blk_count = 512;
-
-		mmc->ocr_avail = AU1XMMC_OCR;
-
-		host = mmc_priv(mmc);
-		host->mmc = mmc;
-
-		host->id = i;
-		host->iobase = au1xmmc_card_table[host->id].iobase;
-		host->clock = 0;
-		host->power_mode = MMC_POWER_OFF;
-
-		host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
-		host->status = HOST_S_IDLE;
-
-		init_timer(&host->timer);
-
-		host->timer.function = au1xmmc_poll_event;
-		host->timer.data = (unsigned long) host;
-		host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
-
-		tasklet_init(&host->data_task, au1xmmc_tasklet_data,
-				(unsigned long) host);
-
-		tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
-				(unsigned long) host);
-
-		spin_lock_init(&host->lock);
-
-		if (dma != 0)
-			au1xmmc_init_dma(host);
-
-		au1xmmc_reset_controller(host);
-
-		mmc_add_host(mmc);
-		au1xmmc_hosts[i] = host;
-
-		add_timer(&host->timer);
-
-		printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
-		       host->id, host->iobase, dma ? "dma" : "pio");
-	}
-
-	enable_irq(AU1100_SD_IRQ);
-
-	return 0;
-}
-
-static int __devexit au1xmmc_remove(struct platform_device *pdev)
-{
-
-	int i;
-
-	disable_irq(AU1100_SD_IRQ);
-
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct au1xmmc_host *host = au1xmmc_hosts[i];
-		if (!host) continue;
-
-		tasklet_kill(&host->data_task);
-		tasklet_kill(&host->finish_task);
-
-		del_timer_sync(&host->timer);
-		au1xmmc_set_power(host, 0);
-
-		mmc_remove_host(host->mmc);
-
-		au1xxx_dbdma_chan_free(host->tx_chan);
-		au1xxx_dbdma_chan_free(host->rx_chan);
-
-		au_writel(0x0, HOST_ENABLE(host));
-		au_sync();
-	}
-
-	free_irq(AU1100_SD_IRQ, 0);
-	return 0;
-}
-
-static struct platform_driver au1xmmc_driver = {
-	.probe         = au1xmmc_probe,
-	.remove        = au1xmmc_remove,
-	.suspend       = NULL,
-	.resume        = NULL,
-	.driver        = {
-		.name  = DRIVER_NAME,
-	},
-};
-
-static int __init au1xmmc_init(void)
-{
-	return platform_driver_register(&au1xmmc_driver);
-}
-
-static void __exit au1xmmc_exit(void)
-{
-	platform_driver_unregister(&au1xmmc_driver);
-}
-
-module_init(au1xmmc_init);
-module_exit(au1xmmc_exit);
-
-#ifdef MODULE
-MODULE_AUTHOR("Advanced Micro Devices, Inc");
-MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
-MODULE_LICENSE("GPL");
-#endif
-
diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/au1xmmc.h
deleted file mode 100644
index 341cbdf..0000000
--- a/drivers/mmc/au1xmmc.h
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef _AU1XMMC_H_
-#define _AU1XMMC_H_
-
-/* Hardware definitions */
-
-#define AU1XMMC_DESCRIPTOR_COUNT 1
-#define AU1XMMC_DESCRIPTOR_SIZE  2048
-
-#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30  | \
-		      MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33  | \
-		      MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
-
-/* Easy access macros */
-
-#define HOST_STATUS(h)	((h)->iobase + SD_STATUS)
-#define HOST_CONFIG(h)	((h)->iobase + SD_CONFIG)
-#define HOST_ENABLE(h)	((h)->iobase + SD_ENABLE)
-#define HOST_TXPORT(h)	((h)->iobase + SD_TXPORT)
-#define HOST_RXPORT(h)	((h)->iobase + SD_RXPORT)
-#define HOST_CMDARG(h)	((h)->iobase + SD_CMDARG)
-#define HOST_BLKSIZE(h)	((h)->iobase + SD_BLKSIZE)
-#define HOST_CMD(h)	((h)->iobase + SD_CMD)
-#define HOST_CONFIG2(h)	((h)->iobase + SD_CONFIG2)
-#define HOST_TIMEOUT(h)	((h)->iobase + SD_TIMEOUT)
-#define HOST_DEBUG(h)	((h)->iobase + SD_DEBUG)
-
-#define DMA_CHANNEL(h) \
-	( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
-
-/* This gives us a hard value for the stop command that we can write directly
- * to the command register
- */
-
-#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
-
-/* This is the set of interrupts that we configure by default */
-
-#if 0
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
-		SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-#endif
-
-#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
-		SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
-/* The poll event (looking for insert/remove events runs twice a second */
-#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
-
-struct au1xmmc_host {
-  struct mmc_host *mmc;
-  struct mmc_request *mrq;
-
-  u32 id;
-
-  u32 flags;
-  u32 iobase;
-  u32 clock;
-  u32 bus_width;
-  u32 power_mode;
-
-  int status;
-
-   struct {
-	   int len;
-	   int dir;
-  } dma;
-
-   struct {
-	   int index;
-	   int offset;
-	   int len;
-  } pio;
-
-  u32 tx_chan;
-  u32 rx_chan;
-
-  struct timer_list timer;
-  struct tasklet_struct finish_task;
-  struct tasklet_struct data_task;
-
-  spinlock_t lock;
-};
-
-/* Status flags used by the host structure */
-
-#define HOST_F_XMIT   0x0001
-#define HOST_F_RECV   0x0002
-#define HOST_F_DMA    0x0010
-#define HOST_F_ACTIVE 0x0100
-#define HOST_F_STOP   0x1000
-
-#define HOST_S_IDLE   0x0001
-#define HOST_S_CMD    0x0002
-#define HOST_S_DATA   0x0003
-#define HOST_S_STOP   0x0004
-
-#endif
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
new file mode 100644
index 0000000..01a9fd3
--- /dev/null
+++ b/drivers/mmc/card/Kconfig
@@ -0,0 +1,17 @@
+#
+# MMC/SD card drivers
+#
+
+comment "MMC/SD Card Drivers"
+	depends MMC
+
+config MMC_BLOCK
+	tristate "MMC block device driver"
+	depends on MMC && BLOCK
+	default y
+	help
+	  Say Y here to enable the MMC block device driver support.
+	  This provides a block device driver, which you can use to
+	  mount the filesystem. Almost everyone wishing MMC support
+	  should say Y or M here.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
new file mode 100644
index 0000000..cf8c939
--- /dev/null
+++ b/drivers/mmc/card/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for MMC/SD card drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+	EXTRA_CFLAGS		+= -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
+mmc_block-objs			:= block.o queue.o
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
new file mode 100644
index 0000000..d24ab23
--- /dev/null
+++ b/drivers/mmc/card/block.c
@@ -0,0 +1,665 @@
+/*
+ * Block driver for media (i.e., flash cards)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ * Copyright 2005-2007 Pierre Ossman
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          28 May 2002
+ */
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#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/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "queue.h"
+
+/*
+ * max 8 partitions per card
+ */
+#define MMC_SHIFT	3
+
+static int major;
+
+/*
+ * There is one mmc_blk_data per slot.
+ */
+struct mmc_blk_data {
+	spinlock_t	lock;
+	struct gendisk	*disk;
+	struct mmc_queue queue;
+
+	unsigned int	usage;
+	unsigned int	block_bits;
+	unsigned int	read_only;
+};
+
+static DEFINE_MUTEX(open_lock);
+
+static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
+{
+	struct mmc_blk_data *md;
+
+	mutex_lock(&open_lock);
+	md = disk->private_data;
+	if (md && md->usage == 0)
+		md = NULL;
+	if (md)
+		md->usage++;
+	mutex_unlock(&open_lock);
+
+	return md;
+}
+
+static void mmc_blk_put(struct mmc_blk_data *md)
+{
+	mutex_lock(&open_lock);
+	md->usage--;
+	if (md->usage == 0) {
+		put_disk(md->disk);
+		kfree(md);
+	}
+	mutex_unlock(&open_lock);
+}
+
+static int mmc_blk_open(struct inode *inode, struct file *filp)
+{
+	struct mmc_blk_data *md;
+	int ret = -ENXIO;
+
+	md = mmc_blk_get(inode->i_bdev->bd_disk);
+	if (md) {
+		if (md->usage == 2)
+			check_disk_change(inode->i_bdev);
+		ret = 0;
+
+		if ((filp->f_mode & FMODE_WRITE) && md->read_only)
+			ret = -EROFS;
+	}
+
+	return ret;
+}
+
+static int mmc_blk_release(struct inode *inode, struct file *filp)
+{
+	struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
+
+	mmc_blk_put(md);
+	return 0;
+}
+
+static int
+mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+	geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
+	geo->heads = 4;
+	geo->sectors = 16;
+	return 0;
+}
+
+static struct block_device_operations mmc_bdops = {
+	.open			= mmc_blk_open,
+	.release		= mmc_blk_release,
+	.getgeo			= mmc_blk_getgeo,
+	.owner			= THIS_MODULE,
+};
+
+struct mmc_blk_request {
+	struct mmc_request	mrq;
+	struct mmc_command	cmd;
+	struct mmc_command	stop;
+	struct mmc_data		data;
+};
+
+static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
+{
+	struct mmc_blk_data *md = mq->data;
+	int stat = BLKPREP_OK;
+
+	/*
+	 * If we have no device, we haven't finished initialising.
+	 */
+	if (!md || !mq->card) {
+		printk(KERN_ERR "%s: killing request - no device/host\n",
+		       req->rq_disk->disk_name);
+		stat = BLKPREP_KILL;
+	}
+
+	return stat;
+}
+
+static 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 = 1, sg_pos, data_size;
+
+	mmc_claim_host(card->host);
+
+	do {
+		struct mmc_command cmd;
+		u32 readcmd, writecmd;
+
+		memset(&brq, 0, sizeof(struct mmc_blk_request));
+		brq.mrq.cmd = &brq.cmd;
+		brq.mrq.data = &brq.data;
+
+		brq.cmd.arg = req->sector;
+		if (!mmc_card_blockaddr(card))
+			brq.cmd.arg <<= 9;
+		brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		brq.data.blksz = 1 << md->block_bits;
+		brq.stop.opcode = MMC_STOP_TRANSMISSION;
+		brq.stop.arg = 0;
+		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+		if (brq.data.blocks > card->host->max_blk_count)
+			brq.data.blocks = card->host->max_blk_count;
+
+		mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
+
+		/*
+		 * 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;
+		brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
+
+		if (brq.data.blocks !=
+		    (req->nr_sectors >> (md->block_bits - 9))) {
+			data_size = brq.data.blocks * brq.data.blksz;
+			for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
+				data_size -= mq->sg[sg_pos].length;
+				if (data_size <= 0) {
+					mq->sg[sg_pos].length += data_size;
+					sg_pos++;
+					break;
+				}
+			}
+			brq.data.sg_len = sg_pos;
+		}
+
+		mmc_wait_for_req(card->host, &brq.mrq);
+		if (brq.cmd.error) {
+			printk(KERN_ERR "%s: error %d sending read/write command\n",
+			       req->rq_disk->disk_name, brq.cmd.error);
+			goto cmd_err;
+		}
+
+		if (brq.data.error) {
+			printk(KERN_ERR "%s: error %d transferring data\n",
+			       req->rq_disk->disk_name, brq.data.error);
+			goto cmd_err;
+		}
+
+		if (brq.stop.error) {
+			printk(KERN_ERR "%s: error %d sending stop command\n",
+			       req->rq_disk->disk_name, brq.stop.error);
+			goto cmd_err;
+		}
+
+		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;
+#endif
+		}
+
+		/*
+		 * A block was successfully transferred.
+		 */
+		spin_lock_irq(&md->lock);
+		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+		if (!ret) {
+			/*
+			 * The whole request completed successfully.
+			 */
+			add_disk_randomness(req->rq_disk);
+			blkdev_dequeue_request(req);
+			end_that_request_last(req, 1);
+		}
+		spin_unlock_irq(&md->lock);
+	} while (ret);
+
+	mmc_release_host(card->host);
+
+	return 1;
+
+ cmd_err:
+ 	/*
+ 	 * 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_release_host(card->host);
+
+	spin_lock_irq(&md->lock);
+	while (ret) {
+		ret = end_that_request_chunk(req, 0,
+				req->current_nr_sectors << 9);
+	}
+
+	add_disk_randomness(req->rq_disk);
+	blkdev_dequeue_request(req);
+	end_that_request_last(req, 0);
+	spin_unlock_irq(&md->lock);
+
+	return 0;
+}
+
+#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)
+
+static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
+
+static inline int mmc_blk_readonly(struct mmc_card *card)
+{
+	return mmc_card_readonly(card) ||
+	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+	struct mmc_blk_data *md;
+	int devidx, ret;
+
+	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
+	if (devidx >= MMC_NUM_MINORS)
+		return ERR_PTR(-ENOSPC);
+	__set_bit(devidx, dev_use);
+
+	md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+	if (!md) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(md, 0, sizeof(struct mmc_blk_data));
+
+	/*
+	 * Set the read-only status based on the supported commands
+	 * and the write protect switch.
+	 */
+	md->read_only = mmc_blk_readonly(card);
+
+	/*
+	 * Both SD and MMC specifications state (although a bit
+	 * unclearly in the MMC case) that a block size of 512
+	 * bytes must always be supported by the card.
+	 */
+	md->block_bits = 9;
+
+	md->disk = alloc_disk(1 << MMC_SHIFT);
+	if (md->disk == NULL) {
+		ret = -ENOMEM;
+		goto err_kfree;
+	}
+
+	spin_lock_init(&md->lock);
+	md->usage = 1;
+
+	ret = mmc_init_queue(&md->queue, card, &md->lock);
+	if (ret)
+		goto err_putdisk;
+
+	md->queue.prep_fn = mmc_blk_prep_rq;
+	md->queue.issue_fn = mmc_blk_issue_rq;
+	md->queue.data = md;
+
+	md->disk->major	= major;
+	md->disk->first_minor = devidx << MMC_SHIFT;
+	md->disk->fops = &mmc_bdops;
+	md->disk->private_data = md;
+	md->disk->queue = md->queue.queue;
+	md->disk->driverfs_dev = &card->dev;
+
+	/*
+	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
+	 *
+	 * - be set for removable media with permanent block devices
+	 * - be unset for removable block devices with permanent media
+	 *
+	 * Since MMC block devices clearly fall under the second
+	 * case, we do not set GENHD_FL_REMOVABLE.  Userspace
+	 * should use the block device creation/destruction hotplug
+	 * messages to tell when the card is present.
+	 */
+
+	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+
+	blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+
+	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+		/*
+		 * The EXT_CSD sector count is in number or 512 byte
+		 * sectors.
+		 */
+		set_capacity(md->disk, card->ext_csd.sectors);
+	} else {
+		/*
+		 * The CSD capacity field is in units of read_blkbits.
+		 * set_capacity takes units of 512 bytes.
+		 */
+		set_capacity(md->disk,
+			card->csd.capacity << (card->csd.read_blkbits - 9));
+	}
+	return md;
+
+ err_putdisk:
+	put_disk(md->disk);
+ err_kfree:
+	kfree(md);
+ out:
+	return ERR_PTR(ret);
+}
+
+static int
+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+{
+	struct mmc_command cmd;
+	int err;
+
+	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+	if (mmc_card_blockaddr(card))
+		return 0;
+
+	mmc_claim_host(card->host);
+	cmd.opcode = MMC_SET_BLOCKLEN;
+	cmd.arg = 1 << md->block_bits;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd, 5);
+	mmc_release_host(card->host);
+
+	if (err) {
+		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
+			md->disk->disk_name, cmd.arg, err);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mmc_blk_probe(struct mmc_card *card)
+{
+	struct mmc_blk_data *md;
+	int err;
+
+	/*
+	 * Check that the card supports the command class(es) we need.
+	 */
+	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
+		return -ENODEV;
+
+	md = mmc_blk_alloc(card);
+	if (IS_ERR(md))
+		return PTR_ERR(md);
+
+	err = mmc_blk_set_blksize(md, card);
+	if (err)
+		goto out;
+
+	printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
+		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
+		(unsigned long long)(get_capacity(md->disk) >> 1),
+		md->read_only ? "(ro)" : "");
+
+	mmc_set_drvdata(card, md);
+	add_disk(md->disk);
+	return 0;
+
+ out:
+	mmc_blk_put(md);
+
+	return err;
+}
+
+static void mmc_blk_remove(struct mmc_card *card)
+{
+	struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+	if (md) {
+		int devidx;
+
+		/* Stop new requests from getting into the queue */
+		del_gendisk(md->disk);
+
+		/* Then flush out any already in there */
+		mmc_cleanup_queue(&md->queue);
+
+		devidx = md->disk->first_minor >> MMC_SHIFT;
+		__clear_bit(devidx, dev_use);
+
+		mmc_blk_put(md);
+	}
+	mmc_set_drvdata(card, NULL);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
+{
+	struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+	if (md) {
+		mmc_queue_suspend(&md->queue);
+	}
+	return 0;
+}
+
+static int mmc_blk_resume(struct mmc_card *card)
+{
+	struct mmc_blk_data *md = mmc_get_drvdata(card);
+
+	if (md) {
+		mmc_blk_set_blksize(md, card);
+		mmc_queue_resume(&md->queue);
+	}
+	return 0;
+}
+#else
+#define	mmc_blk_suspend	NULL
+#define mmc_blk_resume	NULL
+#endif
+
+static struct mmc_driver mmc_driver = {
+	.drv		= {
+		.name	= "mmcblk",
+	},
+	.probe		= mmc_blk_probe,
+	.remove		= mmc_blk_remove,
+	.suspend	= mmc_blk_suspend,
+	.resume		= mmc_blk_resume,
+};
+
+static int __init mmc_blk_init(void)
+{
+	int res = -ENOMEM;
+
+	res = register_blkdev(major, "mmc");
+	if (res < 0) {
+		printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
+		       major, res);
+		goto out;
+	}
+	if (major == 0)
+		major = res;
+
+	return mmc_register_driver(&mmc_driver);
+
+ out:
+	return res;
+}
+
+static void __exit mmc_blk_exit(void)
+{
+	mmc_unregister_driver(&mmc_driver);
+	unregister_blkdev(major, "mmc");
+}
+
+module_init(mmc_blk_init);
+module_exit(mmc_blk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
+
+module_param(major, int, 0444);
+MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
new file mode 100644
index 0000000..2e77963
--- /dev/null
+++ b/drivers/mmc/card/queue.c
@@ -0,0 +1,252 @@
+/*
+ *  linux/drivers/mmc/queue.c
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can 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/blkdev.h>
+#include <linux/kthread.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include "queue.h"
+
+#define MMC_QUEUE_SUSPENDED	(1 << 0)
+
+/*
+ * Prepare a MMC request.  Essentially, this means passing the
+ * preparation off to the media driver.  The media driver will
+ * create a mmc_io_request in req->special.
+ */
+static int mmc_prep_request(struct request_queue *q, struct request *req)
+{
+	struct mmc_queue *mq = q->queuedata;
+	int ret = BLKPREP_KILL;
+
+	if (blk_special_request(req)) {
+		/*
+		 * Special commands already have the command
+		 * blocks already setup in req->special.
+		 */
+		BUG_ON(!req->special);
+
+		ret = BLKPREP_OK;
+	} else if (blk_fs_request(req) || blk_pc_request(req)) {
+		/*
+		 * Block I/O requests need translating according
+		 * to the protocol.
+		 */
+		ret = mq->prep_fn(mq, req);
+	} else {
+		/*
+		 * Everything else is invalid.
+		 */
+		blk_dump_rq_flags(req, "MMC bad request");
+	}
+
+	if (ret == BLKPREP_OK)
+		req->cmd_flags |= REQ_DONTPREP;
+
+	return ret;
+}
+
+static int mmc_queue_thread(void *d)
+{
+	struct mmc_queue *mq = d;
+	struct request_queue *q = mq->queue;
+
+	/*
+	 * Set iothread to ensure that we aren't put to sleep by
+	 * the process freezing.  We handle suspension ourselves.
+	 */
+	current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+
+	down(&mq->thread_sem);
+	do {
+		struct request *req = NULL;
+
+		spin_lock_irq(q->queue_lock);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!blk_queue_plugged(q))
+			req = elv_next_request(q);
+		mq->req = req;
+		spin_unlock_irq(q->queue_lock);
+
+		if (!req) {
+			if (kthread_should_stop()) {
+				set_current_state(TASK_RUNNING);
+				break;
+			}
+			up(&mq->thread_sem);
+			schedule();
+			down(&mq->thread_sem);
+			continue;
+		}
+		set_current_state(TASK_RUNNING);
+
+		mq->issue_fn(mq, req);
+	} while (1);
+	up(&mq->thread_sem);
+
+	return 0;
+}
+
+/*
+ * Generic MMC request handler.  This is called for any queue on a
+ * particular host.  When the host is not busy, we look for a request
+ * on any queue on this host, and attempt to issue it.  This may
+ * not be the queue we were asked to process.
+ */
+static void mmc_request(request_queue_t *q)
+{
+	struct mmc_queue *mq = q->queuedata;
+	struct request *req;
+	int ret;
+
+	if (!mq) {
+		printk(KERN_ERR "MMC: killing requests for dead queue\n");
+		while ((req = elv_next_request(q)) != NULL) {
+			do {
+				ret = end_that_request_chunk(req, 0,
+					req->current_nr_sectors << 9);
+			} while (ret);
+		}
+		return;
+	}
+
+	if (!mq->req)
+		wake_up_process(mq->thread);
+}
+
+/**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+ * @card: mmc card to attach this queue
+ * @lock: queue lock
+ *
+ * Initialise a MMC card request queue.
+ */
+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
+{
+	struct mmc_host *host = card->host;
+	u64 limit = BLK_BOUNCE_HIGH;
+	int ret;
+
+	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+		limit = *mmc_dev(host)->dma_mask;
+
+	mq->card = card;
+	mq->queue = blk_init_queue(mmc_request, lock);
+	if (!mq->queue)
+		return -ENOMEM;
+
+	blk_queue_prep_rq(mq->queue, mmc_prep_request);
+	blk_queue_bounce_limit(mq->queue, limit);
+	blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+	blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
+	blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+	blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+
+	mq->queue->queuedata = mq;
+	mq->req = NULL;
+
+	mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
+			 GFP_KERNEL);
+	if (!mq->sg) {
+		ret = -ENOMEM;
+		goto cleanup_queue;
+	}
+
+	init_MUTEX(&mq->thread_sem);
+
+	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
+	if (IS_ERR(mq->thread)) {
+		ret = PTR_ERR(mq->thread);
+		goto free_sg;
+	}
+
+	return 0;
+
+ free_sg:
+	kfree(mq->sg);
+	mq->sg = NULL;
+ cleanup_queue:
+	blk_cleanup_queue(mq->queue);
+	return ret;
+}
+
+void mmc_cleanup_queue(struct mmc_queue *mq)
+{
+	request_queue_t *q = mq->queue;
+	unsigned long flags;
+
+	/* Mark that we should start throwing out stragglers */
+	spin_lock_irqsave(q->queue_lock, flags);
+	q->queuedata = NULL;
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	/* Make sure the queue isn't suspended, as that will deadlock */
+	mmc_queue_resume(mq);
+
+	/* Then terminate our worker thread */
+	kthread_stop(mq->thread);
+
+	kfree(mq->sg);
+	mq->sg = NULL;
+
+	blk_cleanup_queue(mq->queue);
+
+	mq->card = NULL;
+}
+EXPORT_SYMBOL(mmc_cleanup_queue);
+
+/**
+ * mmc_queue_suspend - suspend a MMC request queue
+ * @mq: MMC queue to suspend
+ *
+ * Stop the block request queue, and wait for our thread to
+ * complete any outstanding requests.  This ensures that we
+ * won't suspend while a request is being processed.
+ */
+void mmc_queue_suspend(struct mmc_queue *mq)
+{
+	request_queue_t *q = mq->queue;
+	unsigned long flags;
+
+	if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
+		mq->flags |= MMC_QUEUE_SUSPENDED;
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		blk_stop_queue(q);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+
+		down(&mq->thread_sem);
+	}
+}
+
+/**
+ * mmc_queue_resume - resume a previously suspended MMC request queue
+ * @mq: MMC queue to resume
+ */
+void mmc_queue_resume(struct mmc_queue *mq)
+{
+	request_queue_t *q = mq->queue;
+	unsigned long flags;
+
+	if (mq->flags & MMC_QUEUE_SUSPENDED) {
+		mq->flags &= ~MMC_QUEUE_SUSPENDED;
+
+		up(&mq->thread_sem);
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		blk_start_queue(q);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+	}
+}
+
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
new file mode 100644
index 0000000..c9f139e
--- /dev/null
+++ b/drivers/mmc/card/queue.h
@@ -0,0 +1,32 @@
+#ifndef MMC_QUEUE_H
+#define MMC_QUEUE_H
+
+struct request;
+struct task_struct;
+
+struct mmc_queue {
+	struct mmc_card		*card;
+	struct task_struct	*thread;
+	struct semaphore	thread_sem;
+	unsigned int		flags;
+	struct request		*req;
+	int			(*prep_fn)(struct mmc_queue *, struct request *);
+	int			(*issue_fn)(struct mmc_queue *, struct request *);
+	void			*data;
+	struct request_queue	*queue;
+	struct scatterlist	*sg;
+};
+
+struct mmc_io_request {
+	struct request		*rq;
+	int			num;
+	struct mmc_command	selcmd;		/* mmc_queue private */
+	struct mmc_command	cmd[4];		/* max 4 commands */
+};
+
+extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
+extern void mmc_cleanup_queue(struct mmc_queue *);
+extern void mmc_queue_suspend(struct mmc_queue *);
+extern void mmc_queue_resume(struct mmc_queue *);
+
+#endif
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
new file mode 100644
index 0000000..94222b9
--- /dev/null
+++ b/drivers/mmc/core/Kconfig
@@ -0,0 +1,17 @@
+#
+# MMC core configuration
+#
+
+config MMC_UNSAFE_RESUME
+	bool "Allow unsafe resume (DANGEROUS)"
+	depends on MMC != n
+	help
+	  If you say Y here, the MMC layer will assume that all cards
+	  stayed in their respective slots during the suspend. The
+	  normal behaviour is to remove them at suspend and
+	  redetecting them at resume. Breaking this assumption will
+	  in most cases result in data corruption.
+
+	  This option is usually just for embedded systems which use
+	  a MMC/SD card for rootfs. Most people should say N here.
+
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
new file mode 100644
index 0000000..1075b02
--- /dev/null
+++ b/drivers/mmc/core/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the kernel mmc core.
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+	EXTRA_CFLAGS		+= -DDEBUG
+endif
+
+obj-$(CONFIG_MMC)		+= mmc_core.o
+mmc_core-y			:= core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o
+
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
new file mode 100644
index 0000000..72c7cf4
--- /dev/null
+++ b/drivers/mmc/core/core.c
@@ -0,0 +1,727 @@
+/*
+ *  linux/drivers/mmc/core/core.c
+ *
+ *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *  MMCv4 support Copyright (C) 2006 Philip Langdale, 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/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include "core.h"
+#include "sysfs.h"
+
+#include "mmc_ops.h"
+#include "sd_ops.h"
+
+extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+
+/**
+ *	mmc_request_done - finish processing an MMC request
+ *	@host: MMC host which completed request
+ *	@mrq: MMC request which request
+ *
+ *	MMC drivers should call this function when they have completed
+ *	their processing of a request.
+ */
+void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+	struct mmc_command *cmd = mrq->cmd;
+	int err = cmd->error;
+
+	pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
+		 mmc_hostname(host), cmd->opcode, err,
+		 mrq->data ? mrq->data->error : 0,
+		 mrq->stop ? mrq->stop->error : 0,
+		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+	if (err && cmd->retries) {
+		cmd->retries--;
+		cmd->error = 0;
+		host->ops->request(host, mrq);
+	} else if (mrq->done) {
+		mrq->done(mrq);
+	}
+}
+
+EXPORT_SYMBOL(mmc_request_done);
+
+/**
+ *	mmc_start_request - start a command on a host
+ *	@host: MMC host to start command on
+ *	@mrq: MMC request to start
+ *
+ *	Queue a command on the specified host.  We expect the
+ *	caller to be holding the host lock with interrupts disabled.
+ */
+void
+mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+#ifdef CONFIG_MMC_DEBUG
+	unsigned int i, sz;
+#endif
+
+	pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
+		 mmc_hostname(host), mrq->cmd->opcode,
+		 mrq->cmd->arg, mrq->cmd->flags);
+
+	WARN_ON(!host->claimed);
+
+	mrq->cmd->error = 0;
+	mrq->cmd->mrq = mrq;
+	if (mrq->data) {
+		BUG_ON(mrq->data->blksz > host->max_blk_size);
+		BUG_ON(mrq->data->blocks > host->max_blk_count);
+		BUG_ON(mrq->data->blocks * mrq->data->blksz >
+			host->max_req_size);
+
+#ifdef CONFIG_MMC_DEBUG
+		sz = 0;
+		for (i = 0;i < mrq->data->sg_len;i++)
+			sz += mrq->data->sg[i].length;
+		BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
+#endif
+
+		mrq->cmd->data = mrq->data;
+		mrq->data->error = 0;
+		mrq->data->mrq = mrq;
+		if (mrq->stop) {
+			mrq->data->stop = mrq->stop;
+			mrq->stop->error = 0;
+			mrq->stop->mrq = mrq;
+		}
+	}
+	host->ops->request(host, mrq);
+}
+
+EXPORT_SYMBOL(mmc_start_request);
+
+static void mmc_wait_done(struct mmc_request *mrq)
+{
+	complete(mrq->done_data);
+}
+
+int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+	DECLARE_COMPLETION_ONSTACK(complete);
+
+	mrq->done_data = &complete;
+	mrq->done = mmc_wait_done;
+
+	mmc_start_request(host, mrq);
+
+	wait_for_completion(&complete);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_req);
+
+/**
+ *	mmc_wait_for_cmd - start a command and wait for completion
+ *	@host: MMC host to start command
+ *	@cmd: MMC command to start
+ *	@retries: maximum number of retries
+ *
+ *	Start a new MMC command for a host, and wait for the command
+ *	to complete.  Return any error that occurred while the command
+ *	was executing.  Do not attempt to parse the response.
+ */
+int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
+{
+	struct mmc_request mrq;
+
+	BUG_ON(!host->claimed);
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+
+	memset(cmd->resp, 0, sizeof(cmd->resp));
+	cmd->retries = retries;
+
+	mrq.cmd = cmd;
+	cmd->data = NULL;
+
+	mmc_wait_for_req(host, &mrq);
+
+	return cmd->error;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_cmd);
+
+/**
+ *	mmc_set_data_timeout - set the timeout for a data command
+ *	@data: data phase for command
+ *	@card: the MMC card associated with the data transfer
+ *	@write: flag to differentiate reads from writes
+ */
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+			  int write)
+{
+	unsigned int mult;
+
+	/*
+	 * SD cards use a 100 multiplier rather than 10
+	 */
+	mult = mmc_card_sd(card) ? 100 : 10;
+
+	/*
+	 * Scale up the multiplier (and therefore the timeout) by
+	 * the r2w factor for writes.
+	 */
+	if (write)
+		mult <<= card->csd.r2w_factor;
+
+	data->timeout_ns = card->csd.tacc_ns * mult;
+	data->timeout_clks = card->csd.tacc_clks * mult;
+
+	/*
+	 * SD cards also have an upper limit on the timeout.
+	 */
+	if (mmc_card_sd(card)) {
+		unsigned int timeout_us, limit_us;
+
+		timeout_us = data->timeout_ns / 1000;
+		timeout_us += data->timeout_clks * 1000 /
+			(card->host->ios.clock / 1000);
+
+		if (write)
+			limit_us = 250000;
+		else
+			limit_us = 100000;
+
+		/*
+		 * SDHC cards always use these fixed values.
+		 */
+		if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+			data->timeout_ns = limit_us * 1000;
+			data->timeout_clks = 0;
+		}
+	}
+}
+EXPORT_SYMBOL(mmc_set_data_timeout);
+
+/**
+ *	__mmc_claim_host - exclusively claim a host
+ *	@host: mmc host to claim
+ *	@card: mmc card to claim host for
+ *
+ *	Claim a host for a set of operations.  If a valid card
+ *	is passed and this wasn't the last card selected, select
+ *	the card before returning.
+ *
+ *	Note: you should use mmc_card_claim_host or mmc_claim_host.
+ */
+void mmc_claim_host(struct mmc_host *host)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+
+	add_wait_queue(&host->wq, &wait);
+	spin_lock_irqsave(&host->lock, flags);
+	while (1) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!host->claimed)
+			break;
+		spin_unlock_irqrestore(&host->lock, flags);
+		schedule();
+		spin_lock_irqsave(&host->lock, flags);
+	}
+	set_current_state(TASK_RUNNING);
+	host->claimed = 1;
+	spin_unlock_irqrestore(&host->lock, flags);
+	remove_wait_queue(&host->wq, &wait);
+}
+
+EXPORT_SYMBOL(mmc_claim_host);
+
+/**
+ *	mmc_release_host - release a host
+ *	@host: mmc host to release
+ *
+ *	Release a MMC host, allowing others to claim the host
+ *	for their operations.
+ */
+void mmc_release_host(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	BUG_ON(!host->claimed);
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->claimed = 0;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	wake_up(&host->wq);
+}
+
+EXPORT_SYMBOL(mmc_release_host);
+
+/*
+ * Internal function that does the actual ios call to the host driver,
+ * optionally printing some debug output.
+ */
+static inline void mmc_set_ios(struct mmc_host *host)
+{
+	struct mmc_ios *ios = &host->ios;
+
+	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
+		"width %u timing %u\n",
+		 mmc_hostname(host), ios->clock, ios->bus_mode,
+		 ios->power_mode, ios->chip_select, ios->vdd,
+		 ios->bus_width, ios->timing);
+
+	host->ops->set_ios(host, ios);
+}
+
+/*
+ * Control chip select pin on a host.
+ */
+void mmc_set_chip_select(struct mmc_host *host, int mode)
+{
+	host->ios.chip_select = mode;
+	mmc_set_ios(host);
+}
+
+/*
+ * Sets the host clock to the highest possible frequency that
+ * is below "hz".
+ */
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+	WARN_ON(hz < host->f_min);
+
+	if (hz > host->f_max)
+		hz = host->f_max;
+
+	host->ios.clock = hz;
+	mmc_set_ios(host);
+}
+
+/*
+ * Change the bus mode (open drain/push-pull) of a host.
+ */
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
+{
+	host->ios.bus_mode = mode;
+	mmc_set_ios(host);
+}
+
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+	host->ios.bus_width = width;
+	mmc_set_ios(host);
+}
+
+/*
+ * Mask off any voltages we don't support and select
+ * the lowest voltage
+ */
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+	int bit;
+
+	ocr &= host->ocr_avail;
+
+	bit = ffs(ocr);
+	if (bit) {
+		bit -= 1;
+
+		ocr &= 3 << bit;
+
+		host->ios.vdd = bit;
+		mmc_set_ios(host);
+	} else {
+		ocr = 0;
+	}
+
+	return ocr;
+}
+
+/*
+ * Select timing parameters for host.
+ */
+void mmc_set_timing(struct mmc_host *host, unsigned int timing)
+{
+	host->ios.timing = timing;
+	mmc_set_ios(host);
+}
+
+/*
+ * Allocate a new MMC card
+ */
+struct mmc_card *mmc_alloc_card(struct mmc_host *host)
+{
+	struct mmc_card *card;
+
+	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+	if (!card)
+		return ERR_PTR(-ENOMEM);
+
+	mmc_init_card(card, host);
+
+	return card;
+}
+
+/*
+ * Apply power to the MMC stack.  This is a two-stage process.
+ * First, we enable power to the card without the clock running.
+ * We then wait a bit for the power to stabilise.  Finally,
+ * enable the bus drivers and clock to the card.
+ *
+ * We must _NOT_ enable the clock prior to power stablising.
+ *
+ * If a host does all the power sequencing itself, ignore the
+ * initial MMC_POWER_UP stage.
+ */
+static void mmc_power_up(struct mmc_host *host)
+{
+	int bit = fls(host->ocr_avail) - 1;
+
+	host->ios.vdd = bit;
+	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	host->ios.chip_select = MMC_CS_DONTCARE;
+	host->ios.power_mode = MMC_POWER_UP;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	mmc_set_ios(host);
+
+	mmc_delay(1);
+
+	host->ios.clock = host->f_min;
+	host->ios.power_mode = MMC_POWER_ON;
+	mmc_set_ios(host);
+
+	mmc_delay(2);
+}
+
+static void mmc_power_off(struct mmc_host *host)
+{
+	host->ios.clock = 0;
+	host->ios.vdd = 0;
+	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	host->ios.chip_select = MMC_CS_DONTCARE;
+	host->ios.power_mode = MMC_POWER_OFF;
+	host->ios.bus_width = MMC_BUS_WIDTH_1;
+	host->ios.timing = MMC_TIMING_LEGACY;
+	mmc_set_ios(host);
+}
+
+/*
+ * Assign a mmc bus handler to a host. Only one bus handler may control a
+ * host at any given time.
+ */
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
+{
+	unsigned long flags;
+
+	BUG_ON(!host);
+	BUG_ON(!ops);
+
+	BUG_ON(!host->claimed);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	BUG_ON(host->bus_ops);
+	BUG_ON(host->bus_refs);
+
+	host->bus_ops = ops;
+	host->bus_refs = 1;
+	host->bus_dead = 0;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * Remove the current bus handler from a host. Assumes that there are
+ * no interesting cards left, so the bus is powered down.
+ */
+void mmc_detach_bus(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	BUG_ON(!host);
+
+	BUG_ON(!host->claimed);
+	BUG_ON(!host->bus_ops);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	host->bus_dead = 1;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	mmc_power_off(host);
+
+	mmc_bus_put(host);
+}
+
+/*
+ * Cleanup when the last reference to the bus operator is dropped.
+ */
+void __mmc_release_bus(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(host->bus_refs);
+	BUG_ON(!host->bus_dead);
+
+	host->bus_ops = NULL;
+}
+
+/**
+ *	mmc_detect_change - process change of state on a MMC socket
+ *	@host: host which changed state.
+ *	@delay: optional delay to wait before detection (jiffies)
+ *
+ *	All we know is that card(s) have been inserted or removed
+ *	from the socket(s).  We don't know which socket or cards.
+ */
+void mmc_detect_change(struct mmc_host *host, unsigned long delay)
+{
+#ifdef CONFIG_MMC_DEBUG
+	mmc_claim_host(host);
+	BUG_ON(host->removed);
+	mmc_release_host(host);
+#endif
+
+	mmc_schedule_delayed_work(&host->detect, delay);
+}
+
+EXPORT_SYMBOL(mmc_detect_change);
+
+
+static void mmc_rescan(struct work_struct *work)
+{
+	struct mmc_host *host =
+		container_of(work, struct mmc_host, detect.work);
+	u32 ocr;
+	int err;
+
+	mmc_bus_get(host);
+
+	if (host->bus_ops == NULL) {
+		/*
+		 * Only we can add a new handler, so it's safe to
+		 * release the lock here.
+		 */
+		mmc_bus_put(host);
+
+		mmc_claim_host(host);
+
+		mmc_power_up(host);
+		mmc_go_idle(host);
+
+		mmc_send_if_cond(host, host->ocr_avail);
+
+		err = mmc_send_app_op_cond(host, 0, &ocr);
+		if (err == MMC_ERR_NONE) {
+			if (mmc_attach_sd(host, ocr))
+				mmc_power_off(host);
+		} else {
+			/*
+			 * If we fail to detect any SD cards then try
+			 * searching for MMC cards.
+			 */
+			err = mmc_send_op_cond(host, 0, &ocr);
+			if (err == MMC_ERR_NONE) {
+				if (mmc_attach_mmc(host, ocr))
+					mmc_power_off(host);
+			} else {
+				mmc_power_off(host);
+				mmc_release_host(host);
+			}
+		}
+	} else {
+		if (host->bus_ops->detect && !host->bus_dead)
+			host->bus_ops->detect(host);
+
+		mmc_bus_put(host);
+	}
+}
+
+
+/**
+ *	mmc_alloc_host - initialise the per-host structure.
+ *	@extra: sizeof private data structure
+ *	@dev: pointer to host device model structure
+ *
+ *	Initialise the per-host structure.
+ */
+struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+{
+	struct mmc_host *host;
+
+	host = mmc_alloc_host_sysfs(extra, dev);
+	if (host) {
+		spin_lock_init(&host->lock);
+		init_waitqueue_head(&host->wq);
+		INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+
+		/*
+		 * By default, hosts do not support SGIO or large requests.
+		 * They have to set these according to their abilities.
+		 */
+		host->max_hw_segs = 1;
+		host->max_phys_segs = 1;
+		host->max_seg_size = PAGE_CACHE_SIZE;
+
+		host->max_req_size = PAGE_CACHE_SIZE;
+		host->max_blk_size = 512;
+		host->max_blk_count = PAGE_CACHE_SIZE / 512;
+	}
+
+	return host;
+}
+
+EXPORT_SYMBOL(mmc_alloc_host);
+
+/**
+ *	mmc_add_host - initialise host hardware
+ *	@host: mmc host
+ */
+int mmc_add_host(struct mmc_host *host)
+{
+	int ret;
+
+	ret = mmc_add_host_sysfs(host);
+	if (ret == 0) {
+		mmc_power_off(host);
+		mmc_detect_change(host, 0);
+	}
+
+	return ret;
+}
+
+EXPORT_SYMBOL(mmc_add_host);
+
+/**
+ *	mmc_remove_host - remove host hardware
+ *	@host: mmc host
+ *
+ *	Unregister and remove all cards associated with this host,
+ *	and power down the MMC bus.
+ */
+void mmc_remove_host(struct mmc_host *host)
+{
+#ifdef CONFIG_MMC_DEBUG
+	mmc_claim_host(host);
+	host->removed = 1;
+	mmc_release_host(host);
+#endif
+
+	mmc_flush_scheduled_work();
+
+	mmc_bus_get(host);
+	if (host->bus_ops && !host->bus_dead) {
+		if (host->bus_ops->remove)
+			host->bus_ops->remove(host);
+
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		mmc_release_host(host);
+	}
+	mmc_bus_put(host);
+
+	BUG_ON(host->card);
+
+	mmc_power_off(host);
+	mmc_remove_host_sysfs(host);
+}
+
+EXPORT_SYMBOL(mmc_remove_host);
+
+/**
+ *	mmc_free_host - free the host structure
+ *	@host: mmc host
+ *
+ *	Free the host once all references to it have been dropped.
+ */
+void mmc_free_host(struct mmc_host *host)
+{
+	mmc_free_host_sysfs(host);
+}
+
+EXPORT_SYMBOL(mmc_free_host);
+
+#ifdef CONFIG_PM
+
+/**
+ *	mmc_suspend_host - suspend a host
+ *	@host: mmc host
+ *	@state: suspend mode (PM_SUSPEND_xxx)
+ */
+int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+{
+	mmc_flush_scheduled_work();
+
+	mmc_bus_get(host);
+	if (host->bus_ops && !host->bus_dead) {
+		if (host->bus_ops->suspend)
+			host->bus_ops->suspend(host);
+		if (!host->bus_ops->resume) {
+			if (host->bus_ops->remove)
+				host->bus_ops->remove(host);
+
+			mmc_claim_host(host);
+			mmc_detach_bus(host);
+			mmc_release_host(host);
+		}
+	}
+	mmc_bus_put(host);
+
+	mmc_power_off(host);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(mmc_suspend_host);
+
+/**
+ *	mmc_resume_host - resume a previously suspended host
+ *	@host: mmc host
+ */
+int mmc_resume_host(struct mmc_host *host)
+{
+	mmc_bus_get(host);
+	if (host->bus_ops && !host->bus_dead) {
+		mmc_power_up(host);
+		BUG_ON(!host->bus_ops->resume);
+		host->bus_ops->resume(host);
+	}
+	mmc_bus_put(host);
+
+	/*
+	 * We add a slight delay here so that resume can progress
+	 * in parallel.
+	 */
+	mmc_detect_change(host, 1);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(mmc_resume_host);
+
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
new file mode 100644
index 0000000..177264d
--- /dev/null
+++ b/drivers/mmc/core/core.h
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/mmc/core/core.h
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _MMC_CORE_CORE_H
+#define _MMC_CORE_CORE_H
+
+#include <linux/delay.h>
+
+#define MMC_CMD_RETRIES        3
+
+struct mmc_bus_ops {
+	void (*remove)(struct mmc_host *);
+	void (*detect)(struct mmc_host *);
+	void (*suspend)(struct mmc_host *);
+	void (*resume)(struct mmc_host *);
+};
+
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
+void mmc_detach_bus(struct mmc_host *host);
+
+void __mmc_release_bus(struct mmc_host *host);
+
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->bus_refs++;
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->bus_refs--;
+	if ((host->bus_refs == 0) && host->bus_ops)
+		__mmc_release_bus(host);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+void mmc_set_chip_select(struct mmc_host *host, int mode);
+void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+
+struct mmc_card *mmc_alloc_card(struct mmc_host *host);
+
+static inline void mmc_delay(unsigned int ms)
+{
+	if (ms < 1000 / HZ) {
+		cond_resched();
+		mdelay(ms);
+	} else {
+		msleep(ms);
+	}
+}
+
+#endif
+
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
new file mode 100644
index 0000000..42cc286
--- /dev/null
+++ b/drivers/mmc/core/mmc.c
@@ -0,0 +1,537 @@
+/*
+ *  linux/drivers/mmc/mmc.c
+ *
+ *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *  MMCv4 support Copyright (C) 2006 Philip Langdale, 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/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+
+static const unsigned int tran_exp[] = {
+	10000,		100000,		1000000,	10000000,
+	0,		0,		0,		0
+};
+
+static const unsigned char tran_mant[] = {
+	0,	10,	12,	13,	15,	20,	25,	30,
+	35,	40,	45,	50,	55,	60,	70,	80,
+};
+
+static const unsigned int tacc_exp[] = {
+	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+	0,	10,	12,	13,	15,	20,	25,	30,
+	35,	40,	45,	50,	55,	60,	70,	80,
+};
+
+#define UNSTUFF_BITS(resp,start,size)					\
+	({								\
+		const int __size = size;				\
+		const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1;	\
+		const int __off = 3 - ((start) / 32);			\
+		const int __shft = (start) & 31;			\
+		u32 __res;						\
+									\
+		__res = resp[__off] >> __shft;				\
+		if (__size + __shft > 32)				\
+			__res |= resp[__off-1] << ((32 - __shft) % 32);	\
+		__res & __mask;						\
+	})
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static int mmc_decode_cid(struct mmc_card *card)
+{
+	u32 *resp = card->raw_cid;
+
+	/*
+	 * The selection of the format here is based upon published
+	 * specs from sandisk and from what people have reported.
+	 */
+	switch (card->csd.mmca_vsn) {
+	case 0: /* MMC v1.0 - v1.2 */
+	case 1: /* MMC v1.4 */
+		card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
+		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+		card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
+		card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
+		card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
+		card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
+		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+		break;
+
+	case 2: /* MMC v2.0 - v2.2 */
+	case 3: /* MMC v3.1 - v3.3 */
+	case 4: /* MMC v4 */
+		card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
+		card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
+		card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
+		card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
+		card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
+		card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
+		card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
+		card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
+		card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
+		card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
+		card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
+		break;
+
+	default:
+		printk("%s: card has unknown MMCA version %d\n",
+			mmc_hostname(card->host), card->csd.mmca_vsn);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static int mmc_decode_csd(struct mmc_card *card)
+{
+	struct mmc_csd *csd = &card->csd;
+	unsigned int e, m, csd_struct;
+	u32 *resp = card->raw_csd;
+
+	/*
+	 * We only understand CSD structure v1.1 and v1.2.
+	 * v1.2 has extra information in bits 15, 11 and 10.
+	 */
+	csd_struct = UNSTUFF_BITS(resp, 126, 2);
+	if (csd_struct != 1 && csd_struct != 2) {
+		printk("%s: unrecognised CSD structure version %d\n",
+			mmc_hostname(card->host), csd_struct);
+		return -EINVAL;
+	}
+
+	csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
+	m = UNSTUFF_BITS(resp, 115, 4);
+	e = UNSTUFF_BITS(resp, 112, 3);
+	csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+	csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+	m = UNSTUFF_BITS(resp, 99, 4);
+	e = UNSTUFF_BITS(resp, 96, 3);
+	csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+	csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+	e = UNSTUFF_BITS(resp, 47, 3);
+	m = UNSTUFF_BITS(resp, 62, 12);
+	csd->capacity	  = (1 + m) << (e + 2);
+
+	csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+	csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+	csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+	csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+	csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+	csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+	csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+
+	return 0;
+}
+
+/*
+ * Read and decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card)
+{
+	int err;
+	u8 *ext_csd;
+
+	BUG_ON(!card);
+
+	err = MMC_ERR_FAILED;
+
+	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+		return MMC_ERR_NONE;
+
+	/*
+	 * As the ext_csd is so large and mostly unused, we don't store the
+	 * raw block in mmc_card.
+	 */
+	ext_csd = kmalloc(512, GFP_KERNEL);
+	if (!ext_csd) {
+		printk(KERN_ERR "%s: could not allocate a buffer to "
+			"receive the ext_csd. mmc v4 cards will be "
+			"treated as v3.\n", mmc_hostname(card->host));
+		return MMC_ERR_FAILED;
+	}
+
+	err = mmc_send_ext_csd(card, ext_csd);
+	if (err != MMC_ERR_NONE) {
+		/*
+		 * High capacity cards should have this "magic" size
+		 * stored in their CSD.
+		 */
+		if (card->csd.capacity == (4096 * 512)) {
+			printk(KERN_ERR "%s: unable to read EXT_CSD "
+				"on a possible high capacity card. "
+				"Card will be ignored.\n",
+				mmc_hostname(card->host));
+		} else {
+			printk(KERN_WARNING "%s: unable to read "
+				"EXT_CSD, performance might "
+				"suffer.\n",
+				mmc_hostname(card->host));
+			err = MMC_ERR_NONE;
+		}
+		goto out;
+	}
+
+	card->ext_csd.sectors =
+		ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+		ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+		ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+		ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+	if (card->ext_csd.sectors)
+		mmc_card_set_blockaddr(card);
+
+	switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
+		card->ext_csd.hs_max_dtr = 52000000;
+		break;
+	case EXT_CSD_CARD_TYPE_26:
+		card->ext_csd.hs_max_dtr = 26000000;
+		break;
+	default:
+		/* MMC v4 spec says this cannot happen */
+		printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
+			"support any high-speed modes.\n",
+			mmc_hostname(card->host));
+		goto out;
+	}
+
+out:
+	kfree(ext_csd);
+
+	return err;
+}
+
+/*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "curcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+	struct mmc_card *oldcard)
+{
+	struct mmc_card *card;
+	int err;
+	u32 cid[4];
+	unsigned int max_dtr;
+
+	BUG_ON(!host);
+	BUG_ON(!host->claimed);
+
+	/*
+	 * Since we're changing the OCR value, we seem to
+	 * need to tell some cards to go back to the idle
+	 * state.  We wait 1ms to give cards time to
+	 * respond.
+	 */
+	mmc_go_idle(host);
+
+	/* The extra bit indicates that we support high capacity */
+	err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	/*
+	 * Fetch CID from card.
+	 */
+	err = mmc_all_send_cid(host, cid);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	if (oldcard) {
+		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+			goto err;
+
+		card = oldcard;
+	} else {
+		/*
+		 * Allocate card structure.
+		 */
+		card = mmc_alloc_card(host);
+		if (IS_ERR(card))
+			goto err;
+
+		card->type = MMC_TYPE_MMC;
+		card->rca = 1;
+		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+	}
+
+	/*
+	 * Set card RCA.
+	 */
+	err = mmc_set_relative_addr(card);
+	if (err != MMC_ERR_NONE)
+		goto free_card;
+
+	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+	if (!oldcard) {
+		/*
+		 * Fetch CSD from card.
+		 */
+		err = mmc_send_csd(card, card->raw_csd);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		err = mmc_decode_csd(card);
+		if (err < 0)
+			goto free_card;
+		err = mmc_decode_cid(card);
+		if (err < 0)
+			goto free_card;
+	}
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	err = mmc_select_card(card);
+	if (err != MMC_ERR_NONE)
+		goto free_card;
+
+	if (!oldcard) {
+		/*
+		 * Fetch and process extened CSD.
+		 */
+		err = mmc_read_ext_csd(card);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+	}
+
+	/*
+	 * Activate high speed (if supported)
+	 */
+	if ((card->ext_csd.hs_max_dtr != 0) &&
+		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_HS_TIMING, 1);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		mmc_card_set_highspeed(card);
+
+		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+	}
+
+	/*
+	 * Compute bus speed.
+	 */
+	max_dtr = (unsigned int)-1;
+
+	if (mmc_card_highspeed(card)) {
+		if (max_dtr > card->ext_csd.hs_max_dtr)
+			max_dtr = card->ext_csd.hs_max_dtr;
+	} else if (max_dtr > card->csd.max_dtr) {
+		max_dtr = card->csd.max_dtr;
+	}
+
+	mmc_set_clock(host, max_dtr);
+
+	/*
+	 * Activate wide bus (if supported).
+	 */
+	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+		(host->caps & MMC_CAP_4_BIT_DATA)) {
+		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+	}
+
+	if (!oldcard)
+		host->card = card;
+
+	return MMC_ERR_NONE;
+
+free_card:
+	if (!oldcard)
+		mmc_remove_card(card);
+err:
+
+	return MMC_ERR_FAILED;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_remove(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_remove_card(host->card);
+	host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_detect(struct mmc_host *host)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+
+	/*
+	 * Just check if our card has been removed.
+	 */
+	err = mmc_send_status(host->card, NULL);
+
+	mmc_release_host(host);
+
+	if (err != MMC_ERR_NONE) {
+		mmc_remove_card(host->card);
+		host->card = NULL;
+
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		mmc_release_host(host);
+	}
+}
+
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+/*
+ * Suspend callback from host.
+ */
+static void mmc_suspend(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+	mmc_deselect_cards(host);
+	host->card->state &= ~MMC_STATE_HIGHSPEED;
+	mmc_release_host(host);
+}
+
+/*
+ * Resume callback from host.
+ *
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static void mmc_resume(struct mmc_host *host)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+
+	err = mmc_sd_init_card(host, host->ocr, host->card);
+	if (err != MMC_ERR_NONE) {
+		mmc_remove_card(host->card);
+		host->card = NULL;
+
+		mmc_detach_bus(host);
+	}
+
+	mmc_release_host(host);
+}
+
+#else
+
+#define mmc_suspend NULL
+#define mmc_resume NULL
+
+#endif
+
+static const struct mmc_bus_ops mmc_ops = {
+	.remove = mmc_remove,
+	.detect = mmc_detect,
+	.suspend = mmc_suspend,
+	.resume = mmc_resume,
+};
+
+/*
+ * Starting point for MMC card init.
+ */
+int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->claimed);
+
+	mmc_attach_bus(host, &mmc_ops);
+
+	/*
+	 * Sanity check the voltages that the card claims to
+	 * support.
+	 */
+	if (ocr & 0x7F) {
+		printk(KERN_WARNING "%s: card claims to support voltages "
+		       "below the defined range. These will be ignored.\n",
+		       mmc_hostname(host));
+		ocr &= ~0x7F;
+	}
+
+	host->ocr = mmc_select_voltage(host, ocr);
+
+	/*
+	 * Can we support the voltage of the card?
+	 */
+	if (!host->ocr)
+		goto err;
+
+	/*
+	 * Detect and init the card.
+	 */
+	err = mmc_sd_init_card(host, host->ocr, NULL);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	mmc_release_host(host);
+
+	err = mmc_register_card(host->card);
+	if (err)
+		goto reclaim_host;
+
+	return 0;
+
+reclaim_host:
+	mmc_claim_host(host);
+	mmc_remove_card(host->card);
+	host->card = NULL;
+err:
+	mmc_detach_bus(host);
+	mmc_release_host(host);
+
+	return 0;
+}
+
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
new file mode 100644
index 0000000..7dd720f
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.c
@@ -0,0 +1,276 @@
+/*
+ *  linux/drivers/mmc/mmc_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "mmc_ops.h"
+
+static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SELECT_CARD;
+
+	if (card) {
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+	}
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_select_card(struct mmc_card *card)
+{
+	BUG_ON(!card);
+
+	return _mmc_select_card(card->host, card);
+}
+
+int mmc_deselect_cards(struct mmc_host *host)
+{
+	return _mmc_select_card(host, NULL);
+}
+
+int mmc_go_idle(struct mmc_host *host)
+{
+	int err;
+	struct mmc_command cmd;
+
+	mmc_set_chip_select(host, MMC_CS_HIGH);
+
+	mmc_delay(1);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_GO_IDLE_STATE;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+
+	mmc_delay(1);
+
+	mmc_set_chip_select(host, MMC_CS_DONTCARE);
+
+	mmc_delay(1);
+
+	return err;
+}
+
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(!cid);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_ALL_SEND_CID;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memcpy(cid, cmd.resp, sizeof(u32) * 4);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_set_relative_addr(struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SET_RELATIVE_ADDR;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!csd);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_CSD;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memcpy(csd, cmd.resp, sizeof(u32) * 4);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!ext_csd);
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = MMC_SEND_EXT_CSD;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 512;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, ext_csd, 512);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SWITCH;
+	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+		  (index << 16) |
+		  (value << 8) |
+		  set;
+	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_status(struct mmc_card *card, u32 *status)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	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, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	if (status)
+		*status = cmd.resp[0];
+
+	return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
new file mode 100644
index 0000000..7a481e8
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.h
@@ -0,0 +1,27 @@
+/*
+ *  linux/drivers/mmc/mmc_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 _MMC_MMC_OPS_H
+#define _MMC_MMC_OPS_H
+
+int mmc_select_card(struct mmc_card *card);
+int mmc_deselect_cards(struct mmc_host *host);
+int mmc_go_idle(struct mmc_host *host);
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_csd(struct mmc_card *card, u32 *csd);
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
+int mmc_send_status(struct mmc_card *card, u32 *status);
+
+#endif
+
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
new file mode 100644
index 0000000..c1dfd03
--- /dev/null
+++ b/drivers/mmc/core/sd.c
@@ -0,0 +1,587 @@
+/*
+ *  linux/drivers/mmc/sd.c
+ *
+ *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ *  Copyright (C) 2005-2007 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.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+
+#include "core.h"
+
+static const unsigned int tran_exp[] = {
+	10000,		100000,		1000000,	10000000,
+	0,		0,		0,		0
+};
+
+static const unsigned char tran_mant[] = {
+	0,	10,	12,	13,	15,	20,	25,	30,
+	35,	40,	45,	50,	55,	60,	70,	80,
+};
+
+static const unsigned int tacc_exp[] = {
+	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+	0,	10,	12,	13,	15,	20,	25,	30,
+	35,	40,	45,	50,	55,	60,	70,	80,
+};
+
+#define UNSTUFF_BITS(resp,start,size)					\
+	({								\
+		const int __size = size;				\
+		const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1;	\
+		const int __off = 3 - ((start) / 32);			\
+		const int __shft = (start) & 31;			\
+		u32 __res;						\
+									\
+		__res = resp[__off] >> __shft;				\
+		if (__size + __shft > 32)				\
+			__res |= resp[__off-1] << ((32 - __shft) % 32);	\
+		__res & __mask;						\
+	})
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(struct mmc_card *card)
+{
+	u32 *resp = card->raw_cid;
+
+	memset(&card->cid, 0, sizeof(struct mmc_cid));
+
+	/*
+	 * SD doesn't currently have a version field so we will
+	 * have to assume we can parse this.
+	 */
+	card->cid.manfid		= UNSTUFF_BITS(resp, 120, 8);
+	card->cid.oemid			= UNSTUFF_BITS(resp, 104, 16);
+	card->cid.prod_name[0]		= UNSTUFF_BITS(resp, 96, 8);
+	card->cid.prod_name[1]		= UNSTUFF_BITS(resp, 88, 8);
+	card->cid.prod_name[2]		= UNSTUFF_BITS(resp, 80, 8);
+	card->cid.prod_name[3]		= UNSTUFF_BITS(resp, 72, 8);
+	card->cid.prod_name[4]		= UNSTUFF_BITS(resp, 64, 8);
+	card->cid.hwrev			= UNSTUFF_BITS(resp, 60, 4);
+	card->cid.fwrev			= UNSTUFF_BITS(resp, 56, 4);
+	card->cid.serial		= UNSTUFF_BITS(resp, 24, 32);
+	card->cid.year			= UNSTUFF_BITS(resp, 12, 8);
+	card->cid.month			= UNSTUFF_BITS(resp, 8, 4);
+
+	card->cid.year += 2000; /* SD cards year offset */
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static int mmc_decode_csd(struct mmc_card *card)
+{
+	struct mmc_csd *csd = &card->csd;
+	unsigned int e, m, csd_struct;
+	u32 *resp = card->raw_csd;
+
+	csd_struct = UNSTUFF_BITS(resp, 126, 2);
+
+	switch (csd_struct) {
+	case 0:
+		m = UNSTUFF_BITS(resp, 115, 4);
+		e = UNSTUFF_BITS(resp, 112, 3);
+		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+		e = UNSTUFF_BITS(resp, 47, 3);
+		m = UNSTUFF_BITS(resp, 62, 12);
+		csd->capacity	  = (1 + m) << (e + 2);
+
+		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+		break;
+	case 1:
+		/*
+		 * This is a block-addressed SDHC card. Most
+		 * interesting fields are unused and have fixed
+		 * values. To avoid getting tripped by buggy cards,
+		 * we assume those fixed values ourselves.
+		 */
+		mmc_card_set_blockaddr(card);
+
+		csd->tacc_ns	 = 0; /* Unused */
+		csd->tacc_clks	 = 0; /* Unused */
+
+		m = UNSTUFF_BITS(resp, 99, 4);
+		e = UNSTUFF_BITS(resp, 96, 3);
+		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
+		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
+
+		m = UNSTUFF_BITS(resp, 48, 22);
+		csd->capacity     = (1 + m) << 10;
+
+		csd->read_blkbits = 9;
+		csd->read_partial = 0;
+		csd->write_misalign = 0;
+		csd->read_misalign = 0;
+		csd->r2w_factor = 4; /* Unused */
+		csd->write_blkbits = 9;
+		csd->write_partial = 0;
+		break;
+	default:
+		printk("%s: unrecognised CSD structure version %d\n",
+			mmc_hostname(card->host), csd_struct);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static int mmc_decode_scr(struct mmc_card *card)
+{
+	struct sd_scr *scr = &card->scr;
+	unsigned int scr_struct;
+	u32 resp[4];
+
+	BUG_ON(!mmc_card_sd(card));
+
+	resp[3] = card->raw_scr[1];
+	resp[2] = card->raw_scr[0];
+
+	scr_struct = UNSTUFF_BITS(resp, 60, 4);
+	if (scr_struct != 0) {
+		printk("%s: unrecognised SCR structure version %d\n",
+			mmc_hostname(card->host), scr_struct);
+		return -EINVAL;
+	}
+
+	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+
+	return 0;
+}
+
+/*
+ * Fetches and decodes switch information
+ */
+static int mmc_read_switch(struct mmc_card *card)
+{
+	int err;
+	u8 *status;
+
+	err = MMC_ERR_FAILED;
+
+	status = kmalloc(64, GFP_KERNEL);
+	if (!status) {
+		printk("%s: could not allocate a buffer for switch "
+		       "capabilities.\n",
+			mmc_hostname(card->host));
+		return err;
+	}
+
+	err = mmc_sd_switch(card, 0, 0, 1, status);
+	if (err != MMC_ERR_NONE) {
+		/*
+		 * Card not supporting high-speed will ignore the
+		 * command.
+		 */
+		err = MMC_ERR_NONE;
+		goto out;
+	}
+
+	if (status[13] & 0x02)
+		card->sw_caps.hs_max_dtr = 50000000;
+
+out:
+	kfree(status);
+
+	return err;
+}
+
+/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int mmc_switch_hs(struct mmc_card *card)
+{
+	int err;
+	u8 *status;
+
+	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+		return MMC_ERR_NONE;
+
+	if (card->sw_caps.hs_max_dtr == 0)
+		return MMC_ERR_NONE;
+
+	err = MMC_ERR_FAILED;
+
+	status = kmalloc(64, GFP_KERNEL);
+	if (!status) {
+		printk("%s: could not allocate a buffer for switch "
+		       "capabilities.\n",
+			mmc_hostname(card->host));
+		return err;
+	}
+
+	err = mmc_sd_switch(card, 1, 0, 1, status);
+	if (err != MMC_ERR_NONE)
+		goto out;
+
+	if ((status[16] & 0xF) != 1) {
+		printk(KERN_WARNING "%s: Problem switching card "
+			"into high-speed mode!\n",
+			mmc_hostname(card->host));
+	} else {
+		mmc_card_set_highspeed(card);
+		mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+	}
+
+out:
+	kfree(status);
+
+	return err;
+}
+
+/*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "curcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+	struct mmc_card *oldcard)
+{
+	struct mmc_card *card;
+	int err;
+	u32 cid[4];
+	unsigned int max_dtr;
+
+	BUG_ON(!host);
+	BUG_ON(!host->claimed);
+
+	/*
+	 * Since we're changing the OCR value, we seem to
+	 * need to tell some cards to go back to the idle
+	 * state.  We wait 1ms to give cards time to
+	 * respond.
+	 */
+	mmc_go_idle(host);
+
+	/*
+	 * If SD_SEND_IF_COND indicates an SD 2.0
+	 * compliant card and we should set bit 30
+	 * of the ocr to indicate that we can handle
+	 * block-addressed SDHC cards.
+	 */
+	err = mmc_send_if_cond(host, ocr);
+	if (err == MMC_ERR_NONE)
+		ocr |= 1 << 30;
+
+	err = mmc_send_app_op_cond(host, ocr, NULL);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	/*
+	 * Fetch CID from card.
+	 */
+	err = mmc_all_send_cid(host, cid);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	if (oldcard) {
+		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+			goto err;
+
+		card = oldcard;
+	} else {
+		/*
+		 * Allocate card structure.
+		 */
+		card = mmc_alloc_card(host);
+		if (IS_ERR(card))
+			goto err;
+
+		card->type = MMC_TYPE_SD;
+		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+	}
+
+	/*
+	 * Set card RCA.
+	 */
+	err = mmc_send_relative_addr(host, &card->rca);
+	if (err != MMC_ERR_NONE)
+		goto free_card;
+
+	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+	if (!oldcard) {
+		/*
+		 * Fetch CSD from card.
+		 */
+		err = mmc_send_csd(card, card->raw_csd);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		err = mmc_decode_csd(card);
+		if (err < 0)
+			goto free_card;
+
+		mmc_decode_cid(card);
+	}
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	err = mmc_select_card(card);
+	if (err != MMC_ERR_NONE)
+		goto free_card;
+
+	if (!oldcard) {
+		/*
+		 * Fetch SCR from card.
+		 */
+		err = mmc_app_send_scr(card, card->raw_scr);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		err = mmc_decode_scr(card);
+		if (err < 0)
+			goto free_card;
+
+		/*
+		 * Fetch switch information from card.
+		 */
+		err = mmc_read_switch(card);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+	}
+
+	/*
+	 * Attempt to change to high-speed (if supported)
+	 */
+	err = mmc_switch_hs(card);
+	if (err != MMC_ERR_NONE)
+		goto free_card;
+
+	/*
+	 * Compute bus speed.
+	 */
+	max_dtr = (unsigned int)-1;
+
+	if (mmc_card_highspeed(card)) {
+		if (max_dtr > card->sw_caps.hs_max_dtr)
+			max_dtr = card->sw_caps.hs_max_dtr;
+	} else if (max_dtr > card->csd.max_dtr) {
+		max_dtr = card->csd.max_dtr;
+	}
+
+	mmc_set_clock(host, max_dtr);
+
+	/*
+	 * Switch to wider bus (if supported).
+	 */
+	if ((host->caps && MMC_CAP_4_BIT_DATA) &&
+		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+		err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+		if (err != MMC_ERR_NONE)
+			goto free_card;
+
+		mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+	}
+
+	if (!oldcard)
+		host->card = card;
+
+	return MMC_ERR_NONE;
+
+free_card:
+	if (!oldcard)
+		mmc_remove_card(card);
+err:
+
+	return MMC_ERR_FAILED;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sd_remove(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_remove_card(host->card);
+	host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sd_detect(struct mmc_host *host)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+
+	/*
+	 * Just check if our card has been removed.
+	 */
+	err = mmc_send_status(host->card, NULL);
+
+	mmc_release_host(host);
+
+	if (err != MMC_ERR_NONE) {
+		mmc_remove_card(host->card);
+		host->card = NULL;
+
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		mmc_release_host(host);
+	}
+}
+
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+/*
+ * Suspend callback from host.
+ */
+static void mmc_sd_suspend(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+	mmc_deselect_cards(host);
+	host->card->state &= ~MMC_STATE_HIGHSPEED;
+	mmc_release_host(host);
+}
+
+/*
+ * Resume callback from host.
+ *
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static void mmc_sd_resume(struct mmc_host *host)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+
+	err = mmc_sd_init_card(host, host->ocr, host->card);
+	if (err != MMC_ERR_NONE) {
+		mmc_remove_card(host->card);
+		host->card = NULL;
+
+		mmc_detach_bus(host);
+	}
+
+	mmc_release_host(host);
+}
+
+#else
+
+#define mmc_sd_suspend NULL
+#define mmc_sd_resume NULL
+
+#endif
+
+static const struct mmc_bus_ops mmc_sd_ops = {
+	.remove = mmc_sd_remove,
+	.detect = mmc_sd_detect,
+	.suspend = mmc_sd_suspend,
+	.resume = mmc_sd_resume,
+};
+
+/*
+ * Starting point for SD card init.
+ */
+int mmc_attach_sd(struct mmc_host *host, u32 ocr)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->claimed);
+
+	mmc_attach_bus(host, &mmc_sd_ops);
+
+	/*
+	 * Sanity check the voltages that the card claims to
+	 * support.
+	 */
+	if (ocr & 0x7F) {
+		printk(KERN_WARNING "%s: card claims to support voltages "
+		       "below the defined range. These will be ignored.\n",
+		       mmc_hostname(host));
+		ocr &= ~0x7F;
+	}
+
+	if (ocr & MMC_VDD_165_195) {
+		printk(KERN_WARNING "%s: SD card claims to support the "
+		       "incompletely defined 'low voltage range'. This "
+		       "will be ignored.\n", mmc_hostname(host));
+		ocr &= ~MMC_VDD_165_195;
+	}
+
+	host->ocr = mmc_select_voltage(host, ocr);
+
+	/*
+	 * Can we support the voltage(s) of the card(s)?
+	 */
+	if (!host->ocr)
+		goto err;
+
+	/*
+	 * Detect and init the card.
+	 */
+	err = mmc_sd_init_card(host, host->ocr, NULL);
+	if (err != MMC_ERR_NONE)
+		goto err;
+
+	mmc_release_host(host);
+
+	err = mmc_register_card(host->card);
+	if (err)
+		goto reclaim_host;
+
+	return 0;
+
+reclaim_host:
+	mmc_claim_host(host);
+	mmc_remove_card(host->card);
+	host->card = NULL;
+err:
+	mmc_detach_bus(host);
+	mmc_release_host(host);
+
+	return 0;
+}
+
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
new file mode 100644
index 0000000..9697ce5
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.c
@@ -0,0 +1,316 @@
+/*
+ *  linux/drivers/mmc/sd_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include "core.h"
+#include "sd_ops.h"
+
+/**
+ *	mmc_wait_for_app_cmd - start an application command and wait for
+ 			       completion
+ *	@host: MMC host to start command
+ *	@rca: RCA to send MMC_APP_CMD to
+ *	@cmd: MMC command to start
+ *	@retries: maximum number of retries
+ *
+ *	Sends a MMC_APP_CMD, checks the card response, sends the command
+ *	in the parameter and waits for it to complete. Return any error
+ *	that occurred while the command was executing.  Do not attempt to
+ *	parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+	struct mmc_command *cmd, int retries)
+{
+	struct mmc_request mrq;
+
+	int i, err;
+
+	BUG_ON(!cmd);
+	BUG_ON(retries < 0);
+
+	err = MMC_ERR_INVALID;
+
+	/*
+	 * We have to resend MMC_APP_CMD for each attempt so
+	 * we cannot use the retries field in mmc_command.
+	 */
+	for (i = 0;i <= retries;i++) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		err = mmc_app_cmd(host, card);
+		if (err != MMC_ERR_NONE)
+			continue;
+
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		memset(cmd->resp, 0, sizeof(cmd->resp));
+		cmd->retries = 0;
+
+		mrq.cmd = cmd;
+		cmd->data = NULL;
+
+		mmc_wait_for_req(host, &mrq);
+
+		err = cmd->error;
+		if (cmd->error == MMC_ERR_NONE)
+			break;
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(card && (card->host != host));
+
+	cmd.opcode = MMC_APP_CMD;
+
+	if (card) {
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+	}
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	/* Check that card supported application commands */
+	if (!(cmd.resp[0] & R1_APP_CMD))
+		return MMC_ERR_FAILED;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_app_set_bus_width(struct mmc_card *card, int width)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_APP_SET_BUS_WIDTH;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	switch (width) {
+	case MMC_BUS_WIDTH_1:
+		cmd.arg = SD_BUS_WIDTH_1;
+		break;
+	case MMC_BUS_WIDTH_4:
+		cmd.arg = SD_BUS_WIDTH_4;
+		break;
+	default:
+		return MMC_ERR_INVALID;
+	}
+
+	err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_APP_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
+		if (err != MMC_ERR_NONE)
+			break;
+
+		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+			break;
+
+		err = MMC_ERR_TIMEOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[0];
+
+	return err;
+}
+
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+	struct mmc_command cmd;
+	int err;
+	static const u8 test_pattern = 0xAA;
+
+	/*
+	 * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+	 * before SD_APP_OP_COND. This command will harmlessly fail for
+	 * SD 1.0 cards.
+	 */
+	cmd.opcode = SD_SEND_IF_COND;
+	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	if ((cmd.resp[0] & 0xFF) != test_pattern)
+		return MMC_ERR_FAILED;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(!rca);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_SEND_RELATIVE_ADDR;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
+
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	*rca = cmd.resp[0] >> 16;
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
+{
+	int err;
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!scr);
+
+	err = mmc_app_cmd(card->host, card);
+	if (err != MMC_ERR_NONE)
+		return err;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_APP_SEND_SCR;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 8;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, scr, 8);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	scr[0] = ntohl(scr[0]);
+	scr[1] = ntohl(scr[1]);
+
+	return MMC_ERR_NONE;
+}
+
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+	u8 value, u8 *resp)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+
+	mode = !!mode;
+	value &= 0xF;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_SWITCH;
+	cmd.arg = mode << 31 | 0x00FFFFFF;
+	cmd.arg &= ~(0xF << (group * 4));
+	cmd.arg |= value << (group * 4);
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 64;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, resp, 64);
+
+	mmc_set_data_timeout(&data, card, 0);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error != MMC_ERR_NONE)
+		return cmd.error;
+	if (data.error != MMC_ERR_NONE)
+		return data.error;
+
+	return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
new file mode 100644
index 0000000..1240fdd
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.h
@@ -0,0 +1,25 @@
+/*
+ *  linux/drivers/mmc/sd_ops.h
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 _MMC_SD_OPS_H
+#define _MMC_SD_OPS_H
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+int mmc_app_set_bus_width(struct mmc_card *card, int width);
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+	u8 value, u8 *resp);
+
+#endif
+
diff --git a/drivers/mmc/core/sysfs.c b/drivers/mmc/core/sysfs.c
new file mode 100644
index 0000000..843b1fb
--- /dev/null
+++ b/drivers/mmc/core/sysfs.c
@@ -0,0 +1,360 @@
+/*
+ *  linux/drivers/mmc/core/sysfs.c
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  MMC sysfs/driver model support.
+ */
+#include <linux/module.h>
+#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>
+
+#include "sysfs.h"
+
+#define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
+#define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
+#define cls_dev_to_mmc_host(d)	container_of(d, struct mmc_host, class_dev)
+
+#define MMC_ATTR(name, fmt, args...)					\
+static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
+{									\
+	struct mmc_card *card = dev_to_mmc_card(dev);			\
+	return sprintf(buf, fmt, args);					\
+}
+
+MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
+	card->raw_cid[2], card->raw_cid[3]);
+MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
+	card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
+MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
+MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
+MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
+MMC_ATTR(name, "%s\n", card->cid.prod_name);
+MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
+
+#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
+
+static struct device_attribute mmc_dev_attrs[] = {
+	MMC_ATTR_RO(cid),
+	MMC_ATTR_RO(csd),
+	MMC_ATTR_RO(date),
+	MMC_ATTR_RO(fwrev),
+	MMC_ATTR_RO(hwrev),
+	MMC_ATTR_RO(manfid),
+	MMC_ATTR_RO(name),
+	MMC_ATTR_RO(oemid),
+	MMC_ATTR_RO(serial),
+	__ATTR_NULL
+};
+
+static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+
+
+static void mmc_release_card(struct device *dev)
+{
+	struct mmc_card *card = dev_to_mmc_card(dev);
+
+	kfree(card);
+}
+
+/*
+ * This currently matches any MMC driver to any MMC card - drivers
+ * themselves make the decision whether to drive this card in their
+ * probe method.
+ */
+static int mmc_bus_match(struct device *dev, struct device_driver *drv)
+{
+	return 1;
+}
+
+static int
+mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
+		int buf_size)
+{
+	struct mmc_card *card = dev_to_mmc_card(dev);
+	char ccc[13];
+	int retval = 0, i = 0, length = 0;
+
+#define add_env(fmt,val) do {					\
+	retval = add_uevent_var(envp, num_envp, &i,		\
+				buf, buf_size, &length,		\
+				fmt, val);			\
+	if (retval)						\
+		return retval;					\
+} while (0);
+
+	for (i = 0; i < 12; i++)
+		ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
+	ccc[12] = '\0';
+
+	add_env("MMC_CCC=%s", ccc);
+	add_env("MMC_MANFID=%06x", card->cid.manfid);
+	add_env("MMC_NAME=%s", mmc_card_name(card));
+	add_env("MMC_OEMID=%04x", card->cid.oemid);
+#undef add_env
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static int mmc_bus_suspend(struct device *dev, pm_message_t state)
+{
+	struct mmc_driver *drv = to_mmc_driver(dev->driver);
+	struct mmc_card *card = dev_to_mmc_card(dev);
+	int ret = 0;
+
+	if (dev->driver && drv->suspend)
+		ret = drv->suspend(card, state);
+	return ret;
+}
+
+static int mmc_bus_resume(struct device *dev)
+{
+	struct mmc_driver *drv = to_mmc_driver(dev->driver);
+	struct mmc_card *card = dev_to_mmc_card(dev);
+	int ret = 0;
+
+	if (dev->driver && drv->resume)
+		ret = drv->resume(card);
+	return ret;
+}
+
+static int mmc_bus_probe(struct device *dev)
+{
+	struct mmc_driver *drv = to_mmc_driver(dev->driver);
+	struct mmc_card *card = dev_to_mmc_card(dev);
+
+	return drv->probe(card);
+}
+
+static int mmc_bus_remove(struct device *dev)
+{
+	struct mmc_driver *drv = to_mmc_driver(dev->driver);
+	struct mmc_card *card = dev_to_mmc_card(dev);
+
+	drv->remove(card);
+
+	return 0;
+}
+
+static struct bus_type mmc_bus_type = {
+	.name		= "mmc",
+	.dev_attrs	= mmc_dev_attrs,
+	.match		= mmc_bus_match,
+	.uevent		= mmc_bus_uevent,
+	.probe		= mmc_bus_probe,
+	.remove		= mmc_bus_remove,
+	.suspend	= mmc_bus_suspend,
+	.resume		= mmc_bus_resume,
+};
+
+/**
+ *	mmc_register_driver - register a media driver
+ *	@drv: MMC media driver
+ */
+int mmc_register_driver(struct mmc_driver *drv)
+{
+	drv->drv.bus = &mmc_bus_type;
+	return driver_register(&drv->drv);
+}
+
+EXPORT_SYMBOL(mmc_register_driver);
+
+/**
+ *	mmc_unregister_driver - unregister a media driver
+ *	@drv: MMC media driver
+ */
+void mmc_unregister_driver(struct mmc_driver *drv)
+{
+	drv->drv.bus = &mmc_bus_type;
+	driver_unregister(&drv->drv);
+}
+
+EXPORT_SYMBOL(mmc_unregister_driver);
+
+
+/*
+ * Internal function.  Initialise a MMC card structure.
+ */
+void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
+{
+	memset(card, 0, sizeof(struct mmc_card));
+	card->host = host;
+	device_initialize(&card->dev);
+	card->dev.parent = mmc_classdev(host);
+	card->dev.bus = &mmc_bus_type;
+	card->dev.release = mmc_release_card;
+}
+
+/*
+ * Internal function.  Register a new MMC card with the driver model.
+ */
+int mmc_register_card(struct mmc_card *card)
+{
+	int ret;
+
+	snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
+		 "%s:%04x", mmc_hostname(card->host), card->rca);
+
+	ret = device_add(&card->dev);
+	if (ret == 0) {
+		if (mmc_card_sd(card)) {
+			ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
+			if (ret)
+				device_del(&card->dev);
+		}
+	}
+	if (ret == 0)
+		mmc_card_set_present(card);
+	return ret;
+}
+
+/*
+ * Internal function.  Unregister a new MMC card with the
+ * driver model, and (eventually) free it.
+ */
+void mmc_remove_card(struct mmc_card *card)
+{
+	if (mmc_card_present(card)) {
+		if (mmc_card_sd(card))
+			device_remove_file(&card->dev, &mmc_dev_attr_scr);
+
+		device_del(&card->dev);
+	}
+
+	put_device(&card->dev);
+}
+
+
+static void mmc_host_classdev_release(struct device *dev)
+{
+	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	kfree(host);
+}
+
+static struct class mmc_host_class = {
+	.name		= "mmc_host",
+	.dev_release	= mmc_host_classdev_release,
+};
+
+static DEFINE_IDR(mmc_host_idr);
+static DEFINE_SPINLOCK(mmc_host_lock);
+
+/*
+ * Internal function. Allocate a new MMC host.
+ */
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
+{
+	struct mmc_host *host;
+
+	host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+	if (host) {
+		memset(host, 0, sizeof(struct mmc_host) + extra);
+
+		host->parent = dev;
+		host->class_dev.parent = dev;
+		host->class_dev.class = &mmc_host_class;
+		device_initialize(&host->class_dev);
+	}
+
+	return host;
+}
+
+/*
+ * Internal function. Register a new MMC host with the MMC class.
+ */
+int mmc_add_host_sysfs(struct mmc_host *host)
+{
+	int err;
+
+	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(&mmc_host_lock);
+	err = idr_get_new(&mmc_host_idr, host, &host->index);
+	spin_unlock(&mmc_host_lock);
+	if (err)
+		return err;
+
+	snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
+		 "mmc%d", host->index);
+
+	return device_add(&host->class_dev);
+}
+
+/*
+ * Internal function. Unregister a MMC host with the MMC class.
+ */
+void mmc_remove_host_sysfs(struct mmc_host *host)
+{
+	device_del(&host->class_dev);
+
+	spin_lock(&mmc_host_lock);
+	idr_remove(&mmc_host_idr, host->index);
+	spin_unlock(&mmc_host_lock);
+}
+
+/*
+ * Internal function. Free a MMC host.
+ */
+void mmc_free_host_sysfs(struct mmc_host *host)
+{
+	put_device(&host->class_dev);
+}
+
+static struct workqueue_struct *workqueue;
+
+/*
+ * Internal function. Schedule delayed work in the MMC work queue.
+ */
+int mmc_schedule_delayed_work(struct delayed_work *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;
+
+	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)
+			bus_unregister(&mmc_bus_type);
+	}
+	return ret;
+}
+
+static void __exit mmc_exit(void)
+{
+	class_unregister(&mmc_host_class);
+	bus_unregister(&mmc_bus_type);
+	destroy_workqueue(workqueue);
+}
+
+module_init(mmc_init);
+module_exit(mmc_exit);
diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h
new file mode 100644
index 0000000..80e29b3
--- /dev/null
+++ b/drivers/mmc/core/sysfs.h
@@ -0,0 +1,27 @@
+/*
+ *  linux/drivers/mmc/core/sysfs.h
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _MMC_CORE_SYSFS_H
+#define _MMC_CORE_SYSFS_H
+
+void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
+int mmc_register_card(struct mmc_card *card);
+void mmc_remove_card(struct mmc_card *card);
+
+struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
+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 delayed_work *work, unsigned long delay);
+void mmc_flush_scheduled_work(void);
+
+#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
new file mode 100644
index 0000000..ed4deab
--- /dev/null
+++ b/drivers/mmc/host/Kconfig
@@ -0,0 +1,103 @@
+#
+# MMC/SD host controller drivers
+#
+
+comment "MMC/SD Host Controller Drivers"
+	depends on MMC
+
+config MMC_ARMMMCI
+	tristate "ARM AMBA Multimedia Card Interface support"
+	depends on ARM_AMBA && MMC
+	help
+	  This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
+	  Interface (PL180 and PL181) support.  If you have an ARM(R)
+	  platform with a Multimedia Card slot, say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_PXA
+	tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
+	depends on ARCH_PXA && MMC
+	help
+	  This selects the Intel(R) PXA(R) Multimedia card Interface.
+	  If you have a PXA(R) platform with a Multimedia Card slot,
+	  say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_SDHCI
+	tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
+	depends on PCI && MMC && EXPERIMENTAL
+	help
+	  This select the generic Secure Digital Host Controller Interface.
+	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
+	  and Toshiba(R). Most controllers found in laptops are of this type.
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_OMAP
+	tristate "TI OMAP Multimedia Card Interface support"
+	depends on ARCH_OMAP && MMC
+	select TPS65010 if MACH_OMAP_H2
+	help
+	  This selects the TI OMAP Multimedia card Interface.
+	  If you have an OMAP board with a Multimedia Card slot,
+	  say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_WBSD
+	tristate "Winbond W83L51xD SD/MMC Card Interface support"
+	depends on MMC && ISA_DMA_API
+	help
+	  This selects the Winbond(R) W83L51xD Secure digital and
+          Multimedia card Interface.
+	  If you have a machine with a integrated W83L518D or W83L519D
+	  SD/MMC card reader, say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_AU1X
+	tristate "Alchemy AU1XX0 MMC Card Interface support"
+	depends on MMC && SOC_AU1200
+	help
+	  This selects the AMD Alchemy(R) Multimedia card interface.
+	  If you have a Alchemy platform with a MMC slot, say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_AT91
+	tristate "AT91 SD/MMC Card Interface support"
+	depends on ARCH_AT91 && MMC
+	help
+	  This selects the AT91 MCI controller.
+
+	  If unsure, say N.
+
+config MMC_IMX
+	tristate "Motorola i.MX Multimedia Card Interface support"
+	depends on ARCH_IMX && MMC
+	help
+	  This selects the Motorola i.MX Multimedia card Interface.
+	  If you have a i.MX platform with a Multimedia Card slot,
+	  say Y or M here.
+
+	  If unsure, say N.
+
+config MMC_TIFM_SD
+	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
+	depends on MMC && EXPERIMENTAL && PCI
+	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.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
new file mode 100644
index 0000000..6685f64
--- /dev/null
+++ b/drivers/mmc/host/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for MMC/SD host controller drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+	EXTRA_CFLAGS		+= -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
+obj-$(CONFIG_MMC_PXA)		+= pxamci.o
+obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
+obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
+obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
+obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
+obj-$(CONFIG_MMC_OMAP)		+= omap.o
+obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
+
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
new file mode 100644
index 0000000..e37943c
--- /dev/null
+++ b/drivers/mmc/host/at91_mci.c
@@ -0,0 +1,1001 @@
+/*
+ *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
+ *
+ *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
+ *
+ *  Copyright (C) 2006 Malcolm Noyes
+ *
+ * This program is free software; you can 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 is the AT91 MCI driver that has been tested with both MMC cards
+   and SD-cards.  Boards that support write protect are now supported.
+   The CCAT91SBC001 board does not support SD cards.
+
+   The three entry points are at91_mci_request, at91_mci_set_ios
+   and at91_mci_get_ro.
+
+   SET IOS
+     This configures the device to put it into the correct mode and clock speed
+     required.
+
+   MCI REQUEST
+     MCI request processes the commands sent in the mmc_request structure. This
+     can consist of a processing command and a stop command in the case of
+     multiple block transfers.
+
+     There are three main types of request, commands, reads and writes.
+
+     Commands are straight forward. The command is submitted to the controller and
+     the request function returns. When the controller generates an interrupt to indicate
+     the command is finished, the response to the command are read and the mmc_request_done
+     function called to end the request.
+
+     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
+     controller to manage the transfers.
+
+     A read is done from the controller directly to the scatterlist passed in from the request.
+     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
+     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
+
+     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
+
+     A write is slightly different in that the bytes to write are read from the scatterlist
+     into a dma memory buffer (this is in case the source buffer should be read only). The
+     entire write buffer is then done from this single dma memory buffer.
+
+     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
+
+   GET RO
+     Gets the status of the write protect pin, if available.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/mmc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91_mci.h>
+
+#define DRIVER_NAME "at91_mci"
+
+#undef	SUPPORT_4WIRE
+
+#define FL_SENT_COMMAND	(1 << 0)
+#define FL_SENT_STOP	(1 << 1)
+
+#define AT91_MCI_ERRORS	(AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE	\
+		| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE		\
+		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)			
+
+#define at91_mci_read(host, reg)	__raw_readl((host)->baseaddr + (reg))
+#define at91_mci_write(host, reg, val)	__raw_writel((val), (host)->baseaddr + (reg))
+
+
+/*
+ * Low level type for this driver
+ */
+struct at91mci_host
+{
+	struct mmc_host *mmc;
+	struct mmc_command *cmd;
+	struct mmc_request *request;
+
+	void __iomem *baseaddr;
+	int irq;
+
+	struct at91_mmc_data *board;
+	int present;
+
+	struct clk *mci_clk;
+
+	/*
+	 * Flag indicating when the command has been sent. This is used to
+	 * work out whether or not to send the stop
+	 */
+	unsigned int flags;
+	/* flag for current bus settings */
+	u32 bus_mode;
+
+	/* DMA buffer used for transmitting */
+	unsigned int* buffer;
+	dma_addr_t physical_address;
+	unsigned int total_length;
+
+	/* Latest in the scatterlist that has been enabled for transfer, but not freed */
+	int in_use_index;
+
+	/* Latest in the scatterlist that has been enabled for transfer */
+	int transfer_index;
+};
+
+/*
+ * Copy from sg to a dma block - used for transfers
+ */
+static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
+{
+	unsigned int len, i, size;
+	unsigned *dmabuf = host->buffer;
+
+	size = host->total_length;
+	len = data->sg_len;
+
+	/*
+	 * Just loop through all entries. Size might not
+	 * be the entire list though so make sure that
+	 * we do not transfer too much.
+	 */
+	for (i = 0; i < len; i++) {
+		struct scatterlist *sg;
+		int amount;
+		unsigned int *sgbuffer;
+
+		sg = &data->sg[i];
+
+		sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+		amount = min(size, sg->length);
+		size -= amount;
+
+		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */
+			int index;
+
+			for (index = 0; index < (amount / 4); index++)
+				*dmabuf++ = swab32(sgbuffer[index]);
+		}
+		else
+			memcpy(dmabuf, sgbuffer, amount);
+
+		kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
+
+		if (size == 0)
+			break;
+	}
+
+	/*
+	 * Check that we didn't get a request to transfer
+	 * more data than can fit into the SG list.
+	 */
+	BUG_ON(size != 0);
+}
+
+/*
+ * Prepare a dma read
+ */
+static void at91mci_pre_dma_read(struct at91mci_host *host)
+{
+	int i;
+	struct scatterlist *sg;
+	struct mmc_command *cmd;
+	struct mmc_data *data;
+
+	pr_debug("pre dma read\n");
+
+	cmd = host->cmd;
+	if (!cmd) {
+		pr_debug("no command\n");
+		return;
+	}
+
+	data = cmd->data;
+	if (!data) {
+		pr_debug("no data\n");
+		return;
+	}
+
+	for (i = 0; i < 2; i++) {
+		/* nothing left to transfer */
+		if (host->transfer_index >= data->sg_len) {
+			pr_debug("Nothing left to transfer (index = %d)\n", host->transfer_index);
+			break;
+		}
+
+		/* Check to see if this needs filling */
+		if (i == 0) {
+			if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
+				pr_debug("Transfer active in current\n");
+				continue;
+			}
+		}
+		else {
+			if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
+				pr_debug("Transfer active in next\n");
+				continue;
+			}
+		}
+
+		/* Setup the next transfer */
+		pr_debug("Using transfer index %d\n", host->transfer_index);
+
+		sg = &data->sg[host->transfer_index++];
+		pr_debug("sg = %p\n", sg);
+
+		sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+
+		pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
+
+		if (i == 0) {
+			at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
+			at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
+		}
+		else {
+			at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
+			at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
+		}
+	}
+
+	pr_debug("pre dma read done\n");
+}
+
+/*
+ * Handle after a dma read
+ */
+static void at91mci_post_dma_read(struct at91mci_host *host)
+{
+	struct mmc_command *cmd;
+	struct mmc_data *data;
+
+	pr_debug("post dma read\n");
+
+	cmd = host->cmd;
+	if (!cmd) {
+		pr_debug("no command\n");
+		return;
+	}
+
+	data = cmd->data;
+	if (!data) {
+		pr_debug("no data\n");
+		return;
+	}
+
+	while (host->in_use_index < host->transfer_index) {
+		unsigned int *buffer;
+
+		struct scatterlist *sg;
+
+		pr_debug("finishing index %d\n", host->in_use_index);
+
+		sg = &data->sg[host->in_use_index++];
+
+		pr_debug("Unmapping page %08X\n", sg->dma_address);
+
+		dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);
+
+		/* Swap the contents of the buffer */
+		buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+		pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
+
+		data->bytes_xfered += sg->length;
+
+		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */
+			int index;
+
+			for (index = 0; index < (sg->length / 4); index++)
+				buffer[index] = swab32(buffer[index]);
+		}
+
+		kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+		flush_dcache_page(sg->page);
+	}
+
+	/* Is there another transfer to trigger? */
+	if (host->transfer_index < data->sg_len)
+		at91mci_pre_dma_read(host);
+	else {
+		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
+		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+	}
+
+	pr_debug("post dma read done\n");
+}
+
+/*
+ * Handle transmitted data
+ */
+static void at91_mci_handle_transmitted(struct at91mci_host *host)
+{
+	struct mmc_command *cmd;
+	struct mmc_data *data;
+
+	pr_debug("Handling the transmit\n");
+
+	/* Disable the transfer */
+	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+	/* Now wait for cmd ready */
+	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
+	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
+
+	cmd = host->cmd;
+	if (!cmd) return;
+
+	data = cmd->data;
+	if (!data) return;
+
+	data->bytes_xfered = host->total_length;
+}
+
+/*
+ * Enable the controller
+ */
+static void at91_mci_enable(struct at91mci_host *host)
+{
+	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+	at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
+	at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
+
+	/* use Slot A or B (only one at same time) */
+	at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
+}
+
+/*
+ * Disable the controller
+ */
+static void at91_mci_disable(struct at91mci_host *host)
+{
+	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
+}
+
+/*
+ * Send a command
+ * return the interrupts to enable
+ */
+static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+	unsigned int cmdr, mr;
+	unsigned int block_length;
+	struct mmc_data *data = cmd->data;
+
+	unsigned int blocks;
+	unsigned int ier = 0;
+
+	host->cmd = cmd;
+
+	/* Not sure if this is needed */
+#if 0
+	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
+		pr_debug("Clearing timeout\n");
+		at91_mci_write(host, AT91_MCI_ARGR, 0);
+		at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
+		while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
+			/* spin */
+			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
+		}
+	}
+#endif
+	cmdr = cmd->opcode;
+
+	if (mmc_resp_type(cmd) == MMC_RSP_NONE)
+		cmdr |= AT91_MCI_RSPTYP_NONE;
+	else {
+		/* if a response is expected then allow maximum response latancy */
+		cmdr |= AT91_MCI_MAXLAT;
+		/* set 136 bit response for R2, 48 bit response otherwise */
+		if (mmc_resp_type(cmd) == MMC_RSP_R2)
+			cmdr |= AT91_MCI_RSPTYP_136;
+		else
+			cmdr |= AT91_MCI_RSPTYP_48;
+	}
+
+	if (data) {
+		block_length = data->blksz;
+		blocks = data->blocks;
+
+		/* always set data start - also set direction flag for read */
+		if (data->flags & MMC_DATA_READ)
+			cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
+		else if (data->flags & MMC_DATA_WRITE)
+			cmdr |= AT91_MCI_TRCMD_START;
+
+		if (data->flags & MMC_DATA_STREAM)
+			cmdr |= AT91_MCI_TRTYP_STREAM;
+		if (data->flags & MMC_DATA_MULTI)
+			cmdr |= AT91_MCI_TRTYP_MULTIPLE;
+	}
+	else {
+		block_length = 0;
+		blocks = 0;
+	}
+
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmdr |= AT91_MCI_TRCMD_STOP;
+
+	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+		cmdr |= AT91_MCI_OPDCMD;
+
+	/*
+	 * Set the arguments and send the command
+	 */
+	pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
+		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
+
+	if (!data) {
+		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
+		at91_mci_write(host, ATMEL_PDC_RPR, 0);
+		at91_mci_write(host, ATMEL_PDC_RCR, 0);
+		at91_mci_write(host, ATMEL_PDC_RNPR, 0);
+		at91_mci_write(host, ATMEL_PDC_RNCR, 0);
+		at91_mci_write(host, ATMEL_PDC_TPR, 0);
+		at91_mci_write(host, ATMEL_PDC_TCR, 0);
+		at91_mci_write(host, ATMEL_PDC_TNPR, 0);
+		at91_mci_write(host, ATMEL_PDC_TNCR, 0);
+
+		at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+		at91_mci_write(host, AT91_MCI_CMDR, cmdr);
+		return AT91_MCI_CMDRDY;
+	}
+
+	mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;	/* zero block length and PDC mode */
+	at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
+
+	/*
+	 * Disable the PDC controller
+	 */
+	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+	if (cmdr & AT91_MCI_TRCMD_START) {
+		data->bytes_xfered = 0;
+		host->transfer_index = 0;
+		host->in_use_index = 0;
+		if (cmdr & AT91_MCI_TRDIR) {
+			/*
+			 * Handle a read
+			 */
+			host->buffer = NULL;
+			host->total_length = 0;
+
+			at91mci_pre_dma_read(host);
+			ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
+		}
+		else {
+			/*
+			 * Handle a write
+			 */
+			host->total_length = block_length * blocks;
+			host->buffer = dma_alloc_coherent(NULL,
+						  host->total_length,
+						  &host->physical_address, GFP_KERNEL);
+
+			at91mci_sg_to_dma(host, data);
+
+			pr_debug("Transmitting %d bytes\n", host->total_length);
+
+			at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
+			at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
+			ier = AT91_MCI_TXBUFE;
+		}
+	}
+
+	/*
+	 * Send the command and then enable the PDC - not the other way round as
+	 * the data sheet says
+	 */
+
+	at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
+	at91_mci_write(host, AT91_MCI_CMDR, cmdr);
+
+	if (cmdr & AT91_MCI_TRCMD_START) {
+		if (cmdr & AT91_MCI_TRDIR)
+			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
+		else
+			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
+	}
+	return ier;
+}
+
+/*
+ * Wait for a command to complete
+ */
+static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)
+{
+	unsigned int ier;
+
+	ier = at91_mci_send_command(host, cmd);
+
+	pr_debug("setting ier to %08X\n", ier);
+
+	/* Stop on errors or the required value */
+	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
+}
+
+/*
+ * Process the next step in the request
+ */
+static void at91mci_process_next(struct at91mci_host *host)
+{
+	if (!(host->flags & FL_SENT_COMMAND)) {
+		host->flags |= FL_SENT_COMMAND;
+		at91mci_process_command(host, host->request->cmd);
+	}
+	else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
+		host->flags |= FL_SENT_STOP;
+		at91mci_process_command(host, host->request->stop);
+	}
+	else
+		mmc_request_done(host->mmc, host->request);
+}
+
+/*
+ * Handle a command that has been completed
+ */
+static void at91mci_completed_command(struct at91mci_host *host)
+{
+	struct mmc_command *cmd = host->cmd;
+	unsigned int status;
+
+	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+
+	cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
+	cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
+	cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
+	cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
+
+	if (host->buffer) {
+		dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
+		host->buffer = NULL;
+	}
+
+	status = at91_mci_read(host, AT91_MCI_SR);
+
+	pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
+		 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+	if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
+			AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
+			AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+		if ((status & AT91_MCI_RCRCE) &&
+			((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
+			cmd->error = MMC_ERR_NONE;
+		}
+		else {
+			if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
+				cmd->error = MMC_ERR_TIMEOUT;
+			else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
+				cmd->error = MMC_ERR_BADCRC;
+			else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
+				cmd->error = MMC_ERR_FIFO;
+			else
+				cmd->error = MMC_ERR_FAILED;
+
+			pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
+				 cmd->error, cmd->opcode, cmd->retries);
+		}
+	}
+	else
+		cmd->error = MMC_ERR_NONE;
+
+	at91mci_process_next(host);
+}
+
+/*
+ * Handle an MMC request
+ */
+static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct at91mci_host *host = mmc_priv(mmc);
+	host->request = mrq;
+	host->flags = 0;
+
+	at91mci_process_next(host);
+}
+
+/*
+ * Set the IOS
+ */
+static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	int clkdiv;
+	struct at91mci_host *host = mmc_priv(mmc);
+	unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
+
+	host->bus_mode = ios->bus_mode;
+
+	if (ios->clock == 0) {
+		/* Disable the MCI controller */
+		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
+		clkdiv = 0;
+	}
+	else {
+		/* Enable the MCI controller */
+		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
+
+		if ((at91_master_clock % (ios->clock * 2)) == 0)
+			clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
+		else
+			clkdiv = (at91_master_clock / ios->clock) / 2;
+
+		pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
+			at91_master_clock / (2 * (clkdiv + 1)));
+	}
+	if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
+		pr_debug("MMC: Setting controller bus width to 4\n");
+		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
+	}
+	else {
+		pr_debug("MMC: Setting controller bus width to 1\n");
+		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+	}
+
+	/* Set the clock divider */
+	at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
+
+	/* maybe switch power to the card */
+	if (host->board->vcc_pin) {
+		switch (ios->power_mode) {
+			case MMC_POWER_OFF:
+				at91_set_gpio_value(host->board->vcc_pin, 0);
+				break;
+			case MMC_POWER_UP:
+			case MMC_POWER_ON:
+				at91_set_gpio_value(host->board->vcc_pin, 1);
+				break;
+		}
+	}
+}
+
+/*
+ * Handle an interrupt
+ */
+static irqreturn_t at91_mci_irq(int irq, void *devid)
+{
+	struct at91mci_host *host = devid;
+	int completed = 0;
+	unsigned int int_status, int_mask;
+
+	int_status = at91_mci_read(host, AT91_MCI_SR);
+	int_mask = at91_mci_read(host, AT91_MCI_IMR);
+	
+	pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
+		int_status & int_mask);
+	
+	int_status = int_status & int_mask;
+
+	if (int_status & AT91_MCI_ERRORS) {
+		completed = 1;
+		
+		if (int_status & AT91_MCI_UNRE)
+			pr_debug("MMC: Underrun error\n");
+		if (int_status & AT91_MCI_OVRE)
+			pr_debug("MMC: Overrun error\n");
+		if (int_status & AT91_MCI_DTOE)
+			pr_debug("MMC: Data timeout\n");
+		if (int_status & AT91_MCI_DCRCE)
+			pr_debug("MMC: CRC error in data\n");
+		if (int_status & AT91_MCI_RTOE)
+			pr_debug("MMC: Response timeout\n");
+		if (int_status & AT91_MCI_RENDE)
+			pr_debug("MMC: Response end bit error\n");
+		if (int_status & AT91_MCI_RCRCE)
+			pr_debug("MMC: Response CRC error\n");
+		if (int_status & AT91_MCI_RDIRE)
+			pr_debug("MMC: Response direction error\n");
+		if (int_status & AT91_MCI_RINDE)
+			pr_debug("MMC: Response index error\n");
+	} else {
+		/* Only continue processing if no errors */
+
+		if (int_status & AT91_MCI_TXBUFE) {
+			pr_debug("TX buffer empty\n");
+			at91_mci_handle_transmitted(host);
+		}
+
+		if (int_status & AT91_MCI_RXBUFF) {
+			pr_debug("RX buffer full\n");
+			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
+		}
+
+		if (int_status & AT91_MCI_ENDTX)
+			pr_debug("Transmit has ended\n");
+
+		if (int_status & AT91_MCI_ENDRX) {
+			pr_debug("Receive has ended\n");
+			at91mci_post_dma_read(host);
+		}
+
+		if (int_status & AT91_MCI_NOTBUSY) {
+			pr_debug("Card is ready\n");
+			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
+		}
+
+		if (int_status & AT91_MCI_DTIP)
+			pr_debug("Data transfer in progress\n");
+
+		if (int_status & AT91_MCI_BLKE)
+			pr_debug("Block transfer has ended\n");
+
+		if (int_status & AT91_MCI_TXRDY)
+			pr_debug("Ready to transmit\n");
+
+		if (int_status & AT91_MCI_RXRDY)
+			pr_debug("Ready to receive\n");
+
+		if (int_status & AT91_MCI_CMDRDY) {
+			pr_debug("Command ready\n");
+			completed = 1;
+		}
+	}
+
+	if (completed) {
+		pr_debug("Completed command\n");
+		at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
+		at91mci_completed_command(host);
+	} else
+		at91_mci_write(host, AT91_MCI_IDR, int_status);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
+{
+	struct at91mci_host *host = _host;
+	int present = !at91_get_gpio_value(irq);
+
+	/*
+	 * we expect this irq on both insert and remove,
+	 * and use a short delay to debounce.
+	 */
+	if (present != host->present) {
+		host->present = present;
+		pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
+			present ? "insert" : "remove");
+		if (!present) {
+			pr_debug("****** Resetting SD-card bus width ******\n");
+			at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
+		}
+		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+	}
+	return IRQ_HANDLED;
+}
+
+static int at91_mci_get_ro(struct mmc_host *mmc)
+{
+	int read_only = 0;
+	struct at91mci_host *host = mmc_priv(mmc);
+
+	if (host->board->wp_pin) {
+		read_only = at91_get_gpio_value(host->board->wp_pin);
+		printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc),
+				(read_only ? "read-only" : "read-write") );
+	}
+	else {
+		printk(KERN_WARNING "%s: host does not support reading read-only "
+				"switch.  Assuming write-enable.\n", mmc_hostname(mmc));
+	}
+	return read_only;
+}
+
+static const struct mmc_host_ops at91_mci_ops = {
+	.request	= at91_mci_request,
+	.set_ios	= at91_mci_set_ios,
+	.get_ro		= at91_mci_get_ro,
+};
+
+/*
+ * Probe for the device
+ */
+static int __init at91_mci_probe(struct platform_device *pdev)
+{
+	struct mmc_host *mmc;
+	struct at91mci_host *host;
+	struct resource *res;
+	int ret;
+
+	pr_debug("Probe MCI devices\n");
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+		return -EBUSY;
+
+	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
+	if (!mmc) {
+		pr_debug("Failed to allocate mmc host\n");
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENOMEM;
+	}
+
+	mmc->ops = &at91_mci_ops;
+	mmc->f_min = 375000;
+	mmc->f_max = 25000000;
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->caps = MMC_CAP_BYTEBLOCK;
+
+	mmc->max_blk_size = 4095;
+	mmc->max_blk_count = mmc->max_req_size;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->buffer = NULL;
+	host->bus_mode = 0;
+	host->board = pdev->dev.platform_data;
+	if (host->board->wire4) {
+#ifdef SUPPORT_4WIRE
+		mmc->caps |= MMC_CAP_4_BIT_DATA;
+#else
+		printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
+#endif
+	}
+
+	/*
+	 * Get Clock
+	 */
+	host->mci_clk = clk_get(&pdev->dev, "mci_clk");
+	if (IS_ERR(host->mci_clk)) {
+		printk(KERN_ERR "AT91 MMC: no clock defined.\n");
+		mmc_free_host(mmc);
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENODEV;
+	}
+
+	/*
+	 * Map I/O region
+	 */
+	host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+	if (!host->baseaddr) {
+		clk_put(host->mci_clk);
+		mmc_free_host(mmc);
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Reset hardware
+	 */
+	clk_enable(host->mci_clk);		/* Enable the peripheral clock */
+	at91_mci_disable(host);
+	at91_mci_enable(host);
+
+	/*
+	 * Allocate the MCI interrupt
+	 */
+	host->irq = platform_get_irq(pdev, 0);
+	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+	if (ret) {
+		printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
+		clk_disable(host->mci_clk);
+		clk_put(host->mci_clk);
+		mmc_free_host(mmc);
+		iounmap(host->baseaddr);
+		release_mem_region(res->start, res->end - res->start + 1);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, mmc);
+
+	/*
+	 * Add host to MMC layer
+	 */
+	if (host->board->det_pin)
+		host->present = !at91_get_gpio_value(host->board->det_pin);
+	else
+		host->present = -1;
+
+	mmc_add_host(mmc);
+
+	/*
+	 * monitor card insertion/removal if we can
+	 */
+	if (host->board->det_pin) {
+		ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
+				0, DRIVER_NAME, host);
+		if (ret)
+			printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
+	}
+
+	pr_debug("Added MCI driver\n");
+
+	return 0;
+}
+
+/*
+ * Remove a device
+ */
+static int __exit at91_mci_remove(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct at91mci_host *host;
+	struct resource *res;
+
+	if (!mmc)
+		return -1;
+
+	host = mmc_priv(mmc);
+
+	if (host->present != -1) {
+		free_irq(host->board->det_pin, host);
+		cancel_delayed_work(&host->mmc->detect);
+	}
+
+	at91_mci_disable(host);
+	mmc_remove_host(mmc);
+	free_irq(host->irq, host);
+
+	clk_disable(host->mci_clk);			/* Disable the peripheral clock */
+	clk_put(host->mci_clk);
+
+	iounmap(host->baseaddr);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	mmc_free_host(mmc);
+	platform_set_drvdata(pdev, NULL);
+	pr_debug("MCI Removed\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	if (mmc)
+		ret = mmc_suspend_host(mmc, state);
+
+	return ret;
+}
+
+static int at91_mci_resume(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	if (mmc)
+		ret = mmc_resume_host(mmc);
+
+	return ret;
+}
+#else
+#define at91_mci_suspend	NULL
+#define at91_mci_resume		NULL
+#endif
+
+static struct platform_driver at91_mci_driver = {
+	.remove		= __exit_p(at91_mci_remove),
+	.suspend	= at91_mci_suspend,
+	.resume		= at91_mci_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91_mci_init(void)
+{
+	return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
+}
+
+static void __exit at91_mci_exit(void)
+{
+	platform_driver_unregister(&at91_mci_driver);
+}
+
+module_init(at91_mci_init);
+module_exit(at91_mci_exit);
+
+MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
+MODULE_AUTHOR("Nick Randell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
new file mode 100644
index 0000000..b7156a4
--- /dev/null
+++ b/drivers/mmc/host/au1xmmc.c
@@ -0,0 +1,1031 @@
+/*
+ * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
+ *
+ *  Copyright (c) 2005, Advanced Micro Devices, Inc.
+ *
+ *  Developed with help from the 2.4.30 MMC AU1XXX controller including
+ *  the following copyright notices:
+ *     Copyright (c) 2003-2004 Embedded Edge, LLC.
+ *     Portions Copyright (C) 2002 Embedix, Inc
+ *     Copyright 2002 Hewlett-Packard Company
+
+ *  2.6 version of this driver inspired by:
+ *     (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
+ *     All Rights Reserved.
+ *     (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
+ *     All Rights Reserved.
+ *
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Why is a timer used to detect insert events?
+ *
+ * From the AU1100 MMC application guide:
+ * If the Au1100-based design is intended to support both MultiMediaCards
+ * and 1- or 4-data bit SecureDigital cards, then the solution is to
+ * connect a weak (560KOhm) pull-up resistor to connector pin 1.
+ * In doing so, a MMC card never enters SPI-mode communications,
+ * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
+ * (the low to high transition will not occur).
+ *
+ * So we use the timer to check the status manually.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/host.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/scatterlist.h>
+
+#include <au1xxx.h>
+#include "au1xmmc.h"
+
+#define DRIVER_NAME "au1xxx-mmc"
+
+/* Set this to enable special debugging macros */
+
+#ifdef DEBUG
+#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)
+#else
+#define DBG(fmt, idx, args...)
+#endif
+
+const struct {
+	u32 iobase;
+	u32 tx_devid, rx_devid;
+	u16 bcsrpwr;
+	u16 bcsrstatus;
+	u16 wpstatus;
+} au1xmmc_card_table[] = {
+	{ SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
+	  BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
+#ifndef CONFIG_MIPS_DB1200
+	{ SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
+	  BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
+#endif
+};
+
+#define AU1XMMC_CONTROLLER_COUNT \
+	(sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
+
+/* This array stores pointers for the hosts (used by the IRQ handler) */
+struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
+static int dma = 1;
+
+#ifdef MODULE
+module_param(dma, bool, 0);
+MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)");
+#endif
+
+static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
+{
+	u32 val = au_readl(HOST_CONFIG(host));
+	val |= mask;
+	au_writel(val, HOST_CONFIG(host));
+	au_sync();
+}
+
+static inline void FLUSH_FIFO(struct au1xmmc_host *host)
+{
+	u32 val = au_readl(HOST_CONFIG2(host));
+
+	au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
+	au_sync_delay(1);
+
+	/* SEND_STOP will turn off clock control - this re-enables it */
+	val &= ~SD_CONFIG2_DF;
+
+	au_writel(val, HOST_CONFIG2(host));
+	au_sync();
+}
+
+static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
+{
+	u32 val = au_readl(HOST_CONFIG(host));
+	val &= ~mask;
+	au_writel(val, HOST_CONFIG(host));
+	au_sync();
+}
+
+static inline void SEND_STOP(struct au1xmmc_host *host)
+{
+
+	/* We know the value of CONFIG2, so avoid a read we don't need */
+	u32 mask = SD_CONFIG2_EN;
+
+	WARN_ON(host->status != HOST_S_DATA);
+	host->status = HOST_S_STOP;
+
+	au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
+	au_sync();
+
+	/* Send the stop commmand */
+	au_writel(STOP_CMD, HOST_CMD(host));
+}
+
+static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
+{
+
+	u32 val = au1xmmc_card_table[host->id].bcsrpwr;
+
+	bcsr->board &= ~val;
+	if (state) bcsr->board |= val;
+
+	au_sync_delay(1);
+}
+
+static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
+{
+	return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus)
+		? 1 : 0;
+}
+
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
+{
+	struct au1xmmc_host *host = mmc_priv(mmc);
+	return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
+		? 1 : 0;
+}
+
+static void au1xmmc_finish_request(struct au1xmmc_host *host)
+{
+
+	struct mmc_request *mrq = host->mrq;
+
+	host->mrq = NULL;
+	host->flags &= HOST_F_ACTIVE;
+
+	host->dma.len = 0;
+	host->dma.dir = 0;
+
+	host->pio.index  = 0;
+	host->pio.offset = 0;
+	host->pio.len = 0;
+
+	host->status = HOST_S_IDLE;
+
+	bcsr->disk_leds |= (1 << 8);
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+static void au1xmmc_tasklet_finish(unsigned long param)
+{
+	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+	au1xmmc_finish_request(host);
+}
+
+static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
+				struct mmc_command *cmd)
+{
+
+	u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		break;
+	case MMC_RSP_R1:
+		mmccmd |= SD_CMD_RT_1;
+		break;
+	case MMC_RSP_R1B:
+		mmccmd |= SD_CMD_RT_1B;
+		break;
+	case MMC_RSP_R2:
+		mmccmd |= SD_CMD_RT_2;
+		break;
+	case MMC_RSP_R3:
+		mmccmd |= SD_CMD_RT_3;
+		break;
+	default:
+		printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+			mmc_resp_type(cmd));
+		return MMC_ERR_INVALID;
+	}
+
+	switch(cmd->opcode) {
+	case MMC_READ_SINGLE_BLOCK:
+	case SD_APP_SEND_SCR:
+		mmccmd |= SD_CMD_CT_2;
+		break;
+	case MMC_READ_MULTIPLE_BLOCK:
+		mmccmd |= SD_CMD_CT_4;
+		break;
+	case MMC_WRITE_BLOCK:
+		mmccmd |= SD_CMD_CT_1;
+		break;
+
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		mmccmd |= SD_CMD_CT_3;
+		break;
+	case MMC_STOP_TRANSMISSION:
+		mmccmd |= SD_CMD_CT_7;
+		break;
+	}
+
+	au_writel(cmd->arg, HOST_CMDARG(host));
+	au_sync();
+
+	if (wait)
+		IRQ_OFF(host, SD_CONFIG_CR);
+
+	au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
+	au_sync();
+
+	/* Wait for the command to go on the line */
+
+	while(1) {
+		if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
+			break;
+	}
+
+	/* Wait for the command to come back */
+
+	if (wait) {
+		u32 status = au_readl(HOST_STATUS(host));
+
+		while(!(status & SD_STATUS_CR))
+			status = au_readl(HOST_STATUS(host));
+
+		/* Clear the CR status */
+		au_writel(SD_STATUS_CR, HOST_STATUS(host));
+
+		IRQ_ON(host, SD_CONFIG_CR);
+	}
+
+	return MMC_ERR_NONE;
+}
+
+static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
+{
+
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_data *data;
+	u32 crc;
+
+	WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
+
+	if (host->mrq == NULL)
+		return;
+
+	data = mrq->cmd->data;
+
+	if (status == 0)
+		status = au_readl(HOST_STATUS(host));
+
+	/* The transaction is really over when the SD_STATUS_DB bit is clear */
+
+	while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
+		status = au_readl(HOST_STATUS(host));
+
+	data->error = MMC_ERR_NONE;
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
+
+        /* Process any errors */
+
+	crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
+	if (host->flags & HOST_F_XMIT)
+		crc |= ((status & 0x07) == 0x02) ? 0 : 1;
+
+	if (crc)
+		data->error = MMC_ERR_BADCRC;
+
+	/* Clear the CRC bits */
+	au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
+
+	data->bytes_xfered = 0;
+
+	if (data->error == MMC_ERR_NONE) {
+		if (host->flags & HOST_F_DMA) {
+			u32 chan = DMA_CHANNEL(host);
+
+			chan_tab_t *c = *((chan_tab_t **) chan);
+			au1x_dma_chan_t *cp = c->chan_ptr;
+			data->bytes_xfered = cp->ddma_bytecnt;
+		}
+		else
+			data->bytes_xfered =
+				(data->blocks * data->blksz) -
+				host->pio.len;
+	}
+
+	au1xmmc_finish_request(host);
+}
+
+static void au1xmmc_tasklet_data(unsigned long param)
+{
+	struct au1xmmc_host *host = (struct au1xmmc_host *) param;
+
+	u32 status = au_readl(HOST_STATUS(host));
+	au1xmmc_data_complete(host, status);
+}
+
+#define AU1XMMC_MAX_TRANSFER 8
+
+static void au1xmmc_send_pio(struct au1xmmc_host *host)
+{
+
+	struct mmc_data *data = 0;
+	int sg_len, max, count = 0;
+	unsigned char *sg_ptr;
+	u32 status = 0;
+	struct scatterlist *sg;
+
+	data = host->mrq->data;
+
+	if (!(host->flags & HOST_F_XMIT))
+		return;
+
+	/* This is the pointer to the data buffer */
+	sg = &data->sg[host->pio.index];
+	sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+
+	/* This is the space left inside the buffer */
+	sg_len = data->sg[host->pio.index].length - host->pio.offset;
+
+	/* Check to if we need less then the size of the sg_buffer */
+
+	max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
+	if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
+
+	for(count = 0; count < max; count++ ) {
+		unsigned char val;
+
+		status = au_readl(HOST_STATUS(host));
+
+		if (!(status & SD_STATUS_TH))
+			break;
+
+		val = *sg_ptr++;
+
+		au_writel((unsigned long) val, HOST_TXPORT(host));
+		au_sync();
+	}
+
+	host->pio.len -= count;
+	host->pio.offset += count;
+
+	if (count == sg_len) {
+		host->pio.index++;
+		host->pio.offset = 0;
+	}
+
+	if (host->pio.len == 0) {
+		IRQ_OFF(host, SD_CONFIG_TH);
+
+		if (host->flags & HOST_F_STOP)
+			SEND_STOP(host);
+
+		tasklet_schedule(&host->data_task);
+	}
+}
+
+static void au1xmmc_receive_pio(struct au1xmmc_host *host)
+{
+
+	struct mmc_data *data = 0;
+	int sg_len = 0, max = 0, count = 0;
+	unsigned char *sg_ptr = 0;
+	u32 status = 0;
+	struct scatterlist *sg;
+
+	data = host->mrq->data;
+
+	if (!(host->flags & HOST_F_RECV))
+		return;
+
+	max = host->pio.len;
+
+	if (host->pio.index < host->dma.len) {
+		sg = &data->sg[host->pio.index];
+		sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+
+		/* This is the space left inside the buffer */
+		sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
+
+		/* Check to if we need less then the size of the sg_buffer */
+		if (sg_len < max) max = sg_len;
+	}
+
+	if (max > AU1XMMC_MAX_TRANSFER)
+		max = AU1XMMC_MAX_TRANSFER;
+
+	for(count = 0; count < max; count++ ) {
+		u32 val;
+		status = au_readl(HOST_STATUS(host));
+
+		if (!(status & SD_STATUS_NE))
+			break;
+
+		if (status & SD_STATUS_RC) {
+			DBG("RX CRC Error [%d + %d].\n", host->id,
+					host->pio.len, count);
+			break;
+		}
+
+		if (status & SD_STATUS_RO) {
+			DBG("RX Overrun [%d + %d]\n", host->id,
+					host->pio.len, count);
+			break;
+		}
+		else if (status & SD_STATUS_RU) {
+			DBG("RX Underrun [%d + %d]\n", host->id,
+					host->pio.len,	count);
+			break;
+		}
+
+		val = au_readl(HOST_RXPORT(host));
+
+		if (sg_ptr)
+			*sg_ptr++ = (unsigned char) (val & 0xFF);
+	}
+
+	host->pio.len -= count;
+	host->pio.offset += count;
+
+	if (sg_len && count == sg_len) {
+		host->pio.index++;
+		host->pio.offset = 0;
+	}
+
+	if (host->pio.len == 0) {
+		//IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
+		IRQ_OFF(host, SD_CONFIG_NE);
+
+		if (host->flags & HOST_F_STOP)
+			SEND_STOP(host);
+
+		tasklet_schedule(&host->data_task);
+	}
+}
+
+/* static void au1xmmc_cmd_complete
+   This is called when a command has been completed - grab the response
+   and check for errors.  Then start the data transfer if it is indicated.
+*/
+
+static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
+{
+
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_command *cmd;
+	int trans;
+
+	if (!host->mrq)
+		return;
+
+	cmd = mrq->cmd;
+	cmd->error = MMC_ERR_NONE;
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136) {
+			u32 r[4];
+			int i;
+
+			r[0] = au_readl(host->iobase + SD_RESP3);
+			r[1] = au_readl(host->iobase + SD_RESP2);
+			r[2] = au_readl(host->iobase + SD_RESP1);
+			r[3] = au_readl(host->iobase + SD_RESP0);
+
+			/* The CRC is omitted from the response, so really
+			 * we only got 120 bytes, but the engine expects
+			 * 128 bits, so we have to shift things up
+			 */
+
+			for(i = 0; i < 4; i++) {
+				cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
+				if (i != 3)
+					cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+			}
+		} else {
+			/* Techincally, we should be getting all 48 bits of
+			 * the response (SD_RESP1 + SD_RESP2), but because
+			 * our response omits the CRC, our data ends up
+			 * being shifted 8 bits to the right.  In this case,
+			 * that means that the OSR data starts at bit 31,
+			 * so we can just read RESP0 and return that
+			 */
+			cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
+		}
+	}
+
+        /* Figure out errors */
+
+	if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
+		cmd->error = MMC_ERR_BADCRC;
+
+	trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
+
+	if (!trans || cmd->error != MMC_ERR_NONE) {
+
+		IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
+		tasklet_schedule(&host->finish_task);
+		return;
+	}
+
+	host->status = HOST_S_DATA;
+
+	if (host->flags & HOST_F_DMA) {
+		u32 channel = DMA_CHANNEL(host);
+
+		/* Start the DMA as soon as the buffer gets something in it */
+
+		if (host->flags & HOST_F_RECV) {
+			u32 mask = SD_STATUS_DB | SD_STATUS_NE;
+
+			while((status & mask) != mask)
+				status = au_readl(HOST_STATUS(host));
+		}
+
+		au1xxx_dbdma_start(channel);
+	}
+}
+
+static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
+{
+
+	unsigned int pbus = get_au1x00_speed();
+	unsigned int divisor;
+	u32 config;
+
+	/* From databook:
+	   divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
+	*/
+
+	pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
+	pbus /= 2;
+
+	divisor = ((pbus / rate) / 2) - 1;
+
+	config = au_readl(HOST_CONFIG(host));
+
+	config &= ~(SD_CONFIG_DIV);
+	config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
+
+	au_writel(config, HOST_CONFIG(host));
+	au_sync();
+}
+
+static int
+au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
+{
+
+	int datalen = data->blocks * data->blksz;
+
+	if (dma != 0)
+		host->flags |= HOST_F_DMA;
+
+	if (data->flags & MMC_DATA_READ)
+		host->flags |= HOST_F_RECV;
+	else
+		host->flags |= HOST_F_XMIT;
+
+	if (host->mrq->stop)
+		host->flags |= HOST_F_STOP;
+
+	host->dma.dir = DMA_BIDIRECTIONAL;
+
+	host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+				   data->sg_len, host->dma.dir);
+
+	if (host->dma.len == 0)
+		return MMC_ERR_TIMEOUT;
+
+	au_writel(data->blksz - 1, HOST_BLKSIZE(host));
+
+	if (host->flags & HOST_F_DMA) {
+		int i;
+		u32 channel = DMA_CHANNEL(host);
+
+		au1xxx_dbdma_stop(channel);
+
+		for(i = 0; i < host->dma.len; i++) {
+			u32 ret = 0, flags = DDMA_FLAGS_NOIE;
+			struct scatterlist *sg = &data->sg[i];
+			int sg_len = sg->length;
+
+			int len = (datalen > sg_len) ? sg_len : datalen;
+
+			if (i == host->dma.len - 1)
+				flags = DDMA_FLAGS_IE;
+
+    			if (host->flags & HOST_F_XMIT){
+      				ret = au1xxx_dbdma_put_source_flags(channel,
+					(void *) (page_address(sg->page) +
+						  sg->offset),
+					len, flags);
+			}
+    			else {
+      				ret = au1xxx_dbdma_put_dest_flags(channel,
+					(void *) (page_address(sg->page) +
+						  sg->offset),
+					len, flags);
+			}
+
+    			if (!ret)
+				goto dataerr;
+
+			datalen -= len;
+		}
+	}
+	else {
+		host->pio.index = 0;
+		host->pio.offset = 0;
+		host->pio.len = datalen;
+
+		if (host->flags & HOST_F_XMIT)
+			IRQ_ON(host, SD_CONFIG_TH);
+		else
+			IRQ_ON(host, SD_CONFIG_NE);
+			//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
+	}
+
+	return MMC_ERR_NONE;
+
+ dataerr:
+	dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
+	return MMC_ERR_TIMEOUT;
+}
+
+/* static void au1xmmc_request
+   This actually starts a command or data transaction
+*/
+
+static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
+{
+
+	struct au1xmmc_host *host = mmc_priv(mmc);
+	int ret = MMC_ERR_NONE;
+
+	WARN_ON(irqs_disabled());
+	WARN_ON(host->status != HOST_S_IDLE);
+
+	host->mrq = mrq;
+	host->status = HOST_S_CMD;
+
+	bcsr->disk_leds &= ~(1 << 8);
+
+	if (mrq->data) {
+		FLUSH_FIFO(host);
+		ret = au1xmmc_prepare_data(host, mrq->data);
+	}
+
+	if (ret == MMC_ERR_NONE)
+		ret = au1xmmc_send_command(host, 0, mrq->cmd);
+
+	if (ret != MMC_ERR_NONE) {
+		mrq->cmd->error = ret;
+		au1xmmc_finish_request(host);
+	}
+}
+
+static void au1xmmc_reset_controller(struct au1xmmc_host *host)
+{
+
+	/* Apply the clock */
+	au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
+        au_sync_delay(1);
+
+	au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
+	au_sync_delay(5);
+
+	au_writel(~0, HOST_STATUS(host));
+	au_sync();
+
+	au_writel(0, HOST_BLKSIZE(host));
+	au_writel(0x001fffff, HOST_TIMEOUT(host));
+	au_sync();
+
+	au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+        au_sync();
+
+	au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
+	au_sync_delay(1);
+
+	au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
+	au_sync();
+
+	/* Configure interrupts */
+	au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
+	au_sync();
+}
+
+
+static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
+{
+	struct au1xmmc_host *host = mmc_priv(mmc);
+
+	if (ios->power_mode == MMC_POWER_OFF)
+		au1xmmc_set_power(host, 0);
+	else if (ios->power_mode == MMC_POWER_ON) {
+		au1xmmc_set_power(host, 1);
+	}
+
+	if (ios->clock && ios->clock != host->clock) {
+		au1xmmc_set_clock(host, ios->clock);
+		host->clock = ios->clock;
+	}
+}
+
+static void au1xmmc_dma_callback(int irq, void *dev_id)
+{
+	struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
+
+	/* Avoid spurious interrupts */
+
+	if (!host->mrq)
+		return;
+
+	if (host->flags & HOST_F_STOP)
+		SEND_STOP(host);
+
+	tasklet_schedule(&host->data_task);
+}
+
+#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
+#define STATUS_DATA_IN  (SD_STATUS_NE)
+#define STATUS_DATA_OUT (SD_STATUS_TH)
+
+static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
+{
+
+	u32 status;
+	int i, ret = 0;
+
+	disable_irq(AU1100_SD_IRQ);
+
+	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+		struct au1xmmc_host * host = au1xmmc_hosts[i];
+		u32 handled = 1;
+
+		status = au_readl(HOST_STATUS(host));
+
+		if (host->mrq && (status & STATUS_TIMEOUT)) {
+			if (status & SD_STATUS_RAT)
+				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+
+			else if (status & SD_STATUS_DT)
+				host->mrq->data->error = MMC_ERR_TIMEOUT;
+
+			/* In PIO mode, interrupts might still be enabled */
+			IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
+
+			//IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
+			tasklet_schedule(&host->finish_task);
+		}
+#if 0
+		else if (status & SD_STATUS_DD) {
+
+			/* Sometimes we get a DD before a NE in PIO mode */
+
+			if (!(host->flags & HOST_F_DMA) &&
+					(status & SD_STATUS_NE))
+				au1xmmc_receive_pio(host);
+			else {
+				au1xmmc_data_complete(host, status);
+				//tasklet_schedule(&host->data_task);
+			}
+		}
+#endif
+		else if (status & (SD_STATUS_CR)) {
+			if (host->status == HOST_S_CMD)
+				au1xmmc_cmd_complete(host,status);
+		}
+		else if (!(host->flags & HOST_F_DMA)) {
+			if ((host->flags & HOST_F_XMIT) &&
+			    (status & STATUS_DATA_OUT))
+				au1xmmc_send_pio(host);
+			else if ((host->flags & HOST_F_RECV) &&
+			    (status & STATUS_DATA_IN))
+				au1xmmc_receive_pio(host);
+		}
+		else if (status & 0x203FBC70) {
+			DBG("Unhandled status %8.8x\n", host->id, status);
+			handled = 0;
+		}
+
+		au_writel(status, HOST_STATUS(host));
+		au_sync();
+
+		ret |= handled;
+	}
+
+	enable_irq(AU1100_SD_IRQ);
+	return ret;
+}
+
+static void au1xmmc_poll_event(unsigned long arg)
+{
+	struct au1xmmc_host *host = (struct au1xmmc_host *) arg;
+
+	int card = au1xmmc_card_inserted(host);
+        int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
+
+	if (card != controller) {
+		host->flags &= ~HOST_F_ACTIVE;
+		if (card) host->flags |= HOST_F_ACTIVE;
+		mmc_detect_change(host->mmc, 0);
+	}
+
+	if (host->mrq != NULL) {
+		u32 status = au_readl(HOST_STATUS(host));
+		DBG("PENDING - %8.8x\n", host->id, status);
+	}
+
+	mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
+}
+
+static dbdev_tab_t au1xmmc_mem_dbdev =
+{
+	DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0
+};
+
+static void au1xmmc_init_dma(struct au1xmmc_host *host)
+{
+
+	u32 rxchan, txchan;
+
+	int txid = au1xmmc_card_table[host->id].tx_devid;
+	int rxid = au1xmmc_card_table[host->id].rx_devid;
+
+	/* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
+	   of 8 bits.  And since devices are shared, we need to create
+	   our own to avoid freaking out other devices
+	*/
+
+	int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
+
+	txchan = au1xxx_dbdma_chan_alloc(memid, txid,
+					 au1xmmc_dma_callback, (void *) host);
+
+	rxchan = au1xxx_dbdma_chan_alloc(rxid, memid,
+					 au1xmmc_dma_callback, (void *) host);
+
+	au1xxx_dbdma_set_devwidth(txchan, 8);
+	au1xxx_dbdma_set_devwidth(rxchan, 8);
+
+	au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT);
+	au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT);
+
+	host->tx_chan = txchan;
+	host->rx_chan = rxchan;
+}
+
+static const struct mmc_host_ops au1xmmc_ops = {
+	.request	= au1xmmc_request,
+	.set_ios	= au1xmmc_set_ios,
+	.get_ro		= au1xmmc_card_readonly,
+};
+
+static int __devinit au1xmmc_probe(struct platform_device *pdev)
+{
+
+	int i, ret = 0;
+
+	/* THe interrupt is shared among all controllers */
+	ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
+
+	if (ret) {
+		printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
+				AU1100_SD_IRQ, ret);
+		return -ENXIO;
+	}
+
+	disable_irq(AU1100_SD_IRQ);
+
+	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+		struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
+		struct au1xmmc_host *host = 0;
+
+		if (!mmc) {
+			printk(DRIVER_NAME "ERROR: no mem for host %d\n", i);
+			au1xmmc_hosts[i] = 0;
+			continue;
+		}
+
+		mmc->ops = &au1xmmc_ops;
+
+		mmc->f_min =   450000;
+		mmc->f_max = 24000000;
+
+		mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
+		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+
+		mmc->max_blk_size = 2048;
+		mmc->max_blk_count = 512;
+
+		mmc->ocr_avail = AU1XMMC_OCR;
+
+		host = mmc_priv(mmc);
+		host->mmc = mmc;
+
+		host->id = i;
+		host->iobase = au1xmmc_card_table[host->id].iobase;
+		host->clock = 0;
+		host->power_mode = MMC_POWER_OFF;
+
+		host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
+		host->status = HOST_S_IDLE;
+
+		init_timer(&host->timer);
+
+		host->timer.function = au1xmmc_poll_event;
+		host->timer.data = (unsigned long) host;
+		host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+
+		tasklet_init(&host->data_task, au1xmmc_tasklet_data,
+				(unsigned long) host);
+
+		tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
+				(unsigned long) host);
+
+		spin_lock_init(&host->lock);
+
+		if (dma != 0)
+			au1xmmc_init_dma(host);
+
+		au1xmmc_reset_controller(host);
+
+		mmc_add_host(mmc);
+		au1xmmc_hosts[i] = host;
+
+		add_timer(&host->timer);
+
+		printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n",
+		       host->id, host->iobase, dma ? "dma" : "pio");
+	}
+
+	enable_irq(AU1100_SD_IRQ);
+
+	return 0;
+}
+
+static int __devexit au1xmmc_remove(struct platform_device *pdev)
+{
+
+	int i;
+
+	disable_irq(AU1100_SD_IRQ);
+
+	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
+		struct au1xmmc_host *host = au1xmmc_hosts[i];
+		if (!host) continue;
+
+		tasklet_kill(&host->data_task);
+		tasklet_kill(&host->finish_task);
+
+		del_timer_sync(&host->timer);
+		au1xmmc_set_power(host, 0);
+
+		mmc_remove_host(host->mmc);
+
+		au1xxx_dbdma_chan_free(host->tx_chan);
+		au1xxx_dbdma_chan_free(host->rx_chan);
+
+		au_writel(0x0, HOST_ENABLE(host));
+		au_sync();
+	}
+
+	free_irq(AU1100_SD_IRQ, 0);
+	return 0;
+}
+
+static struct platform_driver au1xmmc_driver = {
+	.probe         = au1xmmc_probe,
+	.remove        = au1xmmc_remove,
+	.suspend       = NULL,
+	.resume        = NULL,
+	.driver        = {
+		.name  = DRIVER_NAME,
+	},
+};
+
+static int __init au1xmmc_init(void)
+{
+	return platform_driver_register(&au1xmmc_driver);
+}
+
+static void __exit au1xmmc_exit(void)
+{
+	platform_driver_unregister(&au1xmmc_driver);
+}
+
+module_init(au1xmmc_init);
+module_exit(au1xmmc_exit);
+
+#ifdef MODULE
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
+MODULE_LICENSE("GPL");
+#endif
+
diff --git a/drivers/mmc/host/au1xmmc.h b/drivers/mmc/host/au1xmmc.h
new file mode 100644
index 0000000..341cbdf
--- /dev/null
+++ b/drivers/mmc/host/au1xmmc.h
@@ -0,0 +1,96 @@
+#ifndef _AU1XMMC_H_
+#define _AU1XMMC_H_
+
+/* Hardware definitions */
+
+#define AU1XMMC_DESCRIPTOR_COUNT 1
+#define AU1XMMC_DESCRIPTOR_SIZE  2048
+
+#define AU1XMMC_OCR ( MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30  | \
+		      MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33  | \
+		      MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
+
+/* Easy access macros */
+
+#define HOST_STATUS(h)	((h)->iobase + SD_STATUS)
+#define HOST_CONFIG(h)	((h)->iobase + SD_CONFIG)
+#define HOST_ENABLE(h)	((h)->iobase + SD_ENABLE)
+#define HOST_TXPORT(h)	((h)->iobase + SD_TXPORT)
+#define HOST_RXPORT(h)	((h)->iobase + SD_RXPORT)
+#define HOST_CMDARG(h)	((h)->iobase + SD_CMDARG)
+#define HOST_BLKSIZE(h)	((h)->iobase + SD_BLKSIZE)
+#define HOST_CMD(h)	((h)->iobase + SD_CMD)
+#define HOST_CONFIG2(h)	((h)->iobase + SD_CONFIG2)
+#define HOST_TIMEOUT(h)	((h)->iobase + SD_TIMEOUT)
+#define HOST_DEBUG(h)	((h)->iobase + SD_DEBUG)
+
+#define DMA_CHANNEL(h) \
+	( ((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
+
+/* This gives us a hard value for the stop command that we can write directly
+ * to the command register
+ */
+
+#define STOP_CMD (SD_CMD_RT_1B|SD_CMD_CT_7|(0xC << SD_CMD_CI_SHIFT)|SD_CMD_GO)
+
+/* This is the set of interrupts that we configure by default */
+
+#if 0
+#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_DD | \
+		SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
+#endif
+
+#define AU1XMMC_INTERRUPTS (SD_CONFIG_SC | SD_CONFIG_DT | \
+		SD_CONFIG_RAT | SD_CONFIG_CR | SD_CONFIG_I)
+/* The poll event (looking for insert/remove events runs twice a second */
+#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
+
+struct au1xmmc_host {
+  struct mmc_host *mmc;
+  struct mmc_request *mrq;
+
+  u32 id;
+
+  u32 flags;
+  u32 iobase;
+  u32 clock;
+  u32 bus_width;
+  u32 power_mode;
+
+  int status;
+
+   struct {
+	   int len;
+	   int dir;
+  } dma;
+
+   struct {
+	   int index;
+	   int offset;
+	   int len;
+  } pio;
+
+  u32 tx_chan;
+  u32 rx_chan;
+
+  struct timer_list timer;
+  struct tasklet_struct finish_task;
+  struct tasklet_struct data_task;
+
+  spinlock_t lock;
+};
+
+/* Status flags used by the host structure */
+
+#define HOST_F_XMIT   0x0001
+#define HOST_F_RECV   0x0002
+#define HOST_F_DMA    0x0010
+#define HOST_F_ACTIVE 0x0100
+#define HOST_F_STOP   0x1000
+
+#define HOST_S_IDLE   0x0001
+#define HOST_S_CMD    0x0002
+#define HOST_S_DATA   0x0003
+#define HOST_S_STOP   0x0004
+
+#endif
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
new file mode 100644
index 0000000..7ee2045
--- /dev/null
+++ b/drivers/mmc/host/imxmmc.c
@@ -0,0 +1,1137 @@
+/*
+ *  linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ *
+ *  Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
+ *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ *  derived from pxamci.c by 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.
+ *
+ *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Changed to conform redesigned i.MX scatter gather DMA interface
+ *
+ *  2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             Updated for 2.6.14 kernel
+ *
+ *  2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
+ *             Found and corrected problems in the write path
+ *
+ *  2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *             The event handling rewritten right way in softirq.
+ *             Added many ugly hacks and delays to overcome SDHC
+ *             deficiencies
+ *
+ */
+
+#ifdef CONFIG_MMC_DEBUG
+#define DEBUG
+#else
+#undef  DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/delay.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/imx-dma.h>
+
+#include "imxmmc.h"
+
+#define DRIVER_NAME "imx-mmc"
+
+#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
+	              INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
+		      INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
+
+struct imxmci_host {
+	struct mmc_host		*mmc;
+	spinlock_t		lock;
+	struct resource		*res;
+	int			irq;
+	imx_dmach_t		dma;
+	unsigned int		clkrt;
+	unsigned int		cmdat;
+	volatile unsigned int	imask;
+	unsigned int		power_mode;
+	unsigned int		present;
+	struct imxmmc_platform_data *pdata;
+
+	struct mmc_request	*req;
+	struct mmc_command	*cmd;
+	struct mmc_data		*data;
+
+	struct timer_list	timer;
+	struct tasklet_struct	tasklet;
+	unsigned int		status_reg;
+	unsigned long		pending_events;
+	/* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
+	u16			*data_ptr;
+	unsigned int		data_cnt;
+	atomic_t		stuck_timeout;
+
+	unsigned int		dma_nents;
+	unsigned int		dma_size;
+	unsigned int		dma_dir;
+	int			dma_allocated;
+
+	unsigned char		actual_bus_width;
+
+	int			prev_cmd_code;
+};
+
+#define IMXMCI_PEND_IRQ_b	0
+#define IMXMCI_PEND_DMA_END_b	1
+#define IMXMCI_PEND_DMA_ERR_b	2
+#define IMXMCI_PEND_WAIT_RESP_b	3
+#define IMXMCI_PEND_DMA_DATA_b	4
+#define IMXMCI_PEND_CPU_DATA_b	5
+#define IMXMCI_PEND_CARD_XCHG_b	6
+#define IMXMCI_PEND_SET_INIT_b	7
+#define IMXMCI_PEND_STARTED_b	8
+
+#define IMXMCI_PEND_IRQ_m	(1 << IMXMCI_PEND_IRQ_b)
+#define IMXMCI_PEND_DMA_END_m	(1 << IMXMCI_PEND_DMA_END_b)
+#define IMXMCI_PEND_DMA_ERR_m	(1 << IMXMCI_PEND_DMA_ERR_b)
+#define IMXMCI_PEND_WAIT_RESP_m	(1 << IMXMCI_PEND_WAIT_RESP_b)
+#define IMXMCI_PEND_DMA_DATA_m	(1 << IMXMCI_PEND_DMA_DATA_b)
+#define IMXMCI_PEND_CPU_DATA_m	(1 << IMXMCI_PEND_CPU_DATA_b)
+#define IMXMCI_PEND_CARD_XCHG_m	(1 << IMXMCI_PEND_CARD_XCHG_b)
+#define IMXMCI_PEND_SET_INIT_m	(1 << IMXMCI_PEND_SET_INIT_b)
+#define IMXMCI_PEND_STARTED_m	(1 << IMXMCI_PEND_STARTED_b)
+
+static void imxmci_stop_clock(struct imxmci_host *host)
+{
+	int i = 0;
+	MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
+	while(i < 0x1000) {
+	        if(!(i & 0x7f))
+			MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
+
+		if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
+			/* Check twice before cut */
+			if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
+				return;
+		}
+
+		i++;
+	}
+	dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
+}
+
+static int imxmci_start_clock(struct imxmci_host *host)
+{
+	unsigned int trials = 0;
+	unsigned int delay_limit = 128;
+	unsigned long flags;
+
+	MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
+
+	clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
+
+	/*
+	 * Command start of the clock, this usually succeeds in less
+	 * then 6 delay loops, but during card detection (low clockrate)
+	 * it takes up to 5000 delay loops and sometimes fails for the first time
+	 */
+	MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+
+	do {
+		unsigned int delay = delay_limit;
+
+		while(delay--){
+			if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+				/* Check twice before cut */
+				if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+					return 0;
+
+			if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+				return 0;
+		}
+
+		local_irq_save(flags);
+		/*
+		 * Ensure, that request is not doubled under all possible circumstances.
+		 * It is possible, that cock running state is missed, because some other
+		 * IRQ or schedule delays this function execution and the clocks has
+		 * been already stopped by other means (response processing, SDHC HW)
+		 */
+		if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+			MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+		local_irq_restore(flags);
+
+	} while(++trials<256);
+
+	dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
+
+	return -1;
+}
+
+static void imxmci_softreset(void)
+{
+	/* reset sequence */
+	MMC_STR_STP_CLK = 0x8;
+	MMC_STR_STP_CLK = 0xD;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+	MMC_STR_STP_CLK = 0x5;
+
+	MMC_RES_TO = 0xff;
+	MMC_BLK_LEN = 512;
+	MMC_NOB = 1;
+}
+
+static int imxmci_busy_wait_for_status(struct imxmci_host *host,
+			unsigned int *pstat, unsigned int stat_mask,
+			int timeout, const char *where)
+{
+	int loops=0;
+	while(!(*pstat & stat_mask)) {
+		loops+=2;
+		if(loops >= timeout) {
+			dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
+				where, *pstat, stat_mask);
+			return -1;
+		}
+		udelay(2);
+		*pstat |= MMC_STATUS;
+	}
+	if(!loops)
+		return 0;
+
+	/* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
+	if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
+		dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
+			loops, where, *pstat, stat_mask);
+	return loops;
+}
+
+static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
+{
+	unsigned int nob = data->blocks;
+	unsigned int blksz = data->blksz;
+	unsigned int datasz = nob * blksz;
+	int i;
+
+	if (data->flags & MMC_DATA_STREAM)
+		nob = 0xffff;
+
+	host->data = data;
+	data->bytes_xfered = 0;
+
+	MMC_NOB = nob;
+	MMC_BLK_LEN = blksz;
+
+	/*
+	 * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
+	 * We are in big troubles for non-512 byte transfers according to note in the paragraph
+	 * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
+	 * The situation is even more complex in reality. The SDHC in not able to handle wll
+	 * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
+	 * This is required for SCR read at least.
+	 */
+	if (datasz < 512) {
+		host->dma_size = datasz;
+		if (data->flags & MMC_DATA_READ) {
+			host->dma_dir = DMA_FROM_DEVICE;
+
+			/* Hack to enable read SCR */
+			MMC_NOB = 1;
+			MMC_BLK_LEN = 512;
+		} else {
+			host->dma_dir = DMA_TO_DEVICE;
+		}
+
+		/* Convert back to virtual address */
+		host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+		host->data_cnt = 0;
+
+		clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+		set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+		return;
+	}
+
+	if (data->flags & MMC_DATA_READ) {
+		host->dma_dir = DMA_FROM_DEVICE;
+		host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+						data->sg_len,  host->dma_dir);
+
+		imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+			host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
+
+		/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
+		CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
+	} else {
+		host->dma_dir = DMA_TO_DEVICE;
+
+		host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
+						data->sg_len,  host->dma_dir);
+
+		imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
+			host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
+
+		/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
+		CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
+	}
+
+#if 1	/* This code is there only for consistency checking and can be disabled in future */
+	host->dma_size = 0;
+	for(i=0; i<host->dma_nents; i++)
+		host->dma_size+=data->sg[i].length;
+
+	if (datasz > host->dma_size) {
+		dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
+		       datasz, host->dma_size);
+	}
+#endif
+
+	host->dma_size = datasz;
+
+	wmb();
+
+	if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+		BLR(host->dma) = 0;	/* burst 64 byte read / 64 bytes write */
+	else
+		BLR(host->dma) = 16;	/* burst 16 byte read / 16 bytes write */
+
+	RSSR(host->dma) = DMA_REQ_SDHC;
+
+	set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
+	clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
+
+	/* start DMA engine for read, write is delayed after initial response */
+	if (host->dma_dir == DMA_FROM_DEVICE) {
+		imx_dma_enable(host->dma);
+	}
+}
+
+static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+	unsigned long flags;
+	u32 imask;
+
+	WARN_ON(host->cmd != NULL);
+	host->cmd = cmd;
+
+	/* Ensure, that clock are stopped else command programming and start fails */
+	imxmci_stop_clock(host);
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		cmdat |= CMD_DAT_CONT_BUSY;
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_R1: /* short CRC, OPCODE */
+	case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
+		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
+		break;
+	case MMC_RSP_R2: /* long 136 bit + CRC */
+		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
+		break;
+	case MMC_RSP_R3: /* short */
+		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
+		break;
+	default:
+		break;
+	}
+
+	if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
+		cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
+
+	if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
+		cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+
+	MMC_CMD = cmd->opcode;
+	MMC_ARGH = cmd->arg >> 16;
+	MMC_ARGL = cmd->arg & 0xffff;
+	MMC_CMD_DAT_CONT = cmdat;
+
+	atomic_set(&host->stuck_timeout, 0);
+	set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
+
+
+	imask = IMXMCI_INT_MASK_DEFAULT;
+	imask &= ~INT_MASK_END_CMD_RES;
+	if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
+		/*imask &= ~INT_MASK_BUF_READY;*/
+		imask &= ~INT_MASK_DATA_TRAN;
+		if ( cmdat & CMD_DAT_CONT_WRITE )
+			imask &= ~INT_MASK_WRITE_OP_DONE;
+		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+			imask &= ~INT_MASK_BUF_READY;
+	}
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->imask = imask;
+	MMC_INT_MASK = host->imask;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
+		cmd->opcode, cmd->opcode, imask);
+
+	imxmci_start_clock(host);
+}
+
+static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
+			IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
+
+	host->imask = IMXMCI_INT_MASK_DEFAULT;
+	MMC_INT_MASK = host->imask;
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if(req && req->cmd)
+		host->prev_cmd_code = req->cmd->opcode;
+
+	host->req = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+	mmc_request_done(host->mmc, req);
+}
+
+static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
+{
+	struct mmc_data *data = host->data;
+	int data_error;
+
+	if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
+		imx_dma_disable(host->dma);
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
+			     host->dma_dir);
+	}
+
+	if ( stat & STATUS_ERR_MASK ) {
+		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
+		if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
+			data->error = MMC_ERR_BADCRC;
+		else if(stat & STATUS_TIME_OUT_READ)
+			data->error = MMC_ERR_TIMEOUT;
+		else
+			data->error = MMC_ERR_FAILED;
+	} else {
+		data->bytes_xfered = host->dma_size;
+	}
+
+	data_error = data->error;
+
+	host->data = NULL;
+
+	return data_error;
+}
+
+static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
+{
+	struct mmc_command *cmd = host->cmd;
+	int i;
+	u32 a,b,c;
+	struct mmc_data *data = host->data;
+
+	if (!cmd)
+		return 0;
+
+	host->cmd = NULL;
+
+	if (stat & STATUS_TIME_OUT_RESP) {
+		dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
+		cmd->error = MMC_ERR_TIMEOUT;
+	} else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+		dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
+		cmd->error = MMC_ERR_BADCRC;
+	}
+
+	if(cmd->flags & MMC_RSP_PRESENT) {
+		if(cmd->flags & MMC_RSP_136) {
+			for (i = 0; i < 4; i++) {
+				u32 a = MMC_RES_FIFO & 0xffff;
+				u32 b = MMC_RES_FIFO & 0xffff;
+				cmd->resp[i] = a<<16 | b;
+			}
+		} else {
+			a = MMC_RES_FIFO & 0xffff;
+			b = MMC_RES_FIFO & 0xffff;
+			c = MMC_RES_FIFO & 0xffff;
+			cmd->resp[0] = a<<24 | b<<8 | c>>8;
+		}
+	}
+
+	dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
+		cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
+
+	if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+		if (host->req->data->flags & MMC_DATA_WRITE) {
+
+			/* Wait for FIFO to be empty before starting DMA write */
+
+			stat = MMC_STATUS;
+			if(imxmci_busy_wait_for_status(host, &stat,
+				STATUS_APPL_BUFF_FE,
+				40, "imxmci_cmd_done DMA WR") < 0) {
+				cmd->error = MMC_ERR_FIFO;
+				imxmci_finish_data(host, stat);
+				if(host->req)
+					imxmci_finish_request(host, host->req);
+				dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
+				       stat);
+				return 0;
+			}
+
+			if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+				imx_dma_enable(host->dma);
+			}
+		}
+	} else {
+		struct mmc_request *req;
+		imxmci_stop_clock(host);
+		req = host->req;
+
+		if(data)
+			imxmci_finish_data(host, stat);
+
+		if( req ) {
+			imxmci_finish_request(host, req);
+		} else {
+			dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
+		}
+	}
+
+	return 1;
+}
+
+static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
+{
+	struct mmc_data *data = host->data;
+	int data_error;
+
+	if (!data)
+		return 0;
+
+	data_error = imxmci_finish_data(host, stat);
+
+	if (host->req->stop) {
+		imxmci_stop_clock(host);
+		imxmci_start_cmd(host, host->req->stop, 0);
+	} else {
+		struct mmc_request *req;
+		req = host->req;
+		if( req ) {
+			imxmci_finish_request(host, req);
+		} else {
+			dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
+		}
+	}
+
+	return 1;
+}
+
+static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
+{
+	int i;
+	int burst_len;
+	int trans_done = 0;
+	unsigned int stat = *pstat;
+
+	if(host->actual_bus_width != MMC_BUS_WIDTH_4)
+		burst_len = 16;
+	else
+		burst_len = 64;
+
+	/* This is unfortunately required */
+	dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
+		stat);
+
+	udelay(20);	/* required for clocks < 8MHz*/
+
+	if(host->dma_dir == DMA_FROM_DEVICE) {
+		imxmci_busy_wait_for_status(host, &stat,
+				STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
+				STATUS_TIME_OUT_READ,
+				50, "imxmci_cpu_driven_data read");
+
+		while((stat & (STATUS_APPL_BUFF_FF |  STATUS_DATA_TRANS_DONE)) &&
+		      !(stat & STATUS_TIME_OUT_READ) &&
+		      (host->data_cnt < 512)) {
+
+			udelay(20);	/* required for clocks < 8MHz*/
+
+			for(i = burst_len; i>=2 ; i-=2) {
+				u16 data;
+				data = MMC_BUFFER_ACCESS;
+				udelay(10);	/* required for clocks < 8MHz*/
+				if(host->data_cnt+2 <= host->dma_size) {
+					*(host->data_ptr++) = data;
+				} else {
+					if(host->data_cnt < host->dma_size)
+						*(u8*)(host->data_ptr) = data;
+				}
+				host->data_cnt += 2;
+			}
+
+			stat = MMC_STATUS;
+
+			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
+				host->data_cnt, burst_len, stat);
+		}
+
+		if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
+			trans_done = 1;
+
+		if(host->dma_size & 0x1ff)
+			stat &= ~STATUS_CRC_READ_ERR;
+
+		if(stat & STATUS_TIME_OUT_READ) {
+			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
+				stat);
+			trans_done = -1;
+		}
+
+	} else {
+		imxmci_busy_wait_for_status(host, &stat,
+				STATUS_APPL_BUFF_FE,
+				20, "imxmci_cpu_driven_data write");
+
+		while((stat & STATUS_APPL_BUFF_FE) &&
+		      (host->data_cnt < host->dma_size)) {
+			if(burst_len >= host->dma_size - host->data_cnt) {
+				burst_len = host->dma_size - host->data_cnt;
+				host->data_cnt = host->dma_size;
+				trans_done = 1;
+			} else {
+				host->data_cnt += burst_len;
+			}
+
+			for(i = burst_len; i>0 ; i-=2)
+				MMC_BUFFER_ACCESS = *(host->data_ptr++);
+
+			stat = MMC_STATUS;
+
+			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
+				burst_len, stat);
+		}
+	}
+
+	*pstat = stat;
+
+	return trans_done;
+}
+
+static void imxmci_dma_irq(int dma, void *devid)
+{
+	struct imxmci_host *host = devid;
+	uint32_t stat = MMC_STATUS;
+
+	atomic_set(&host->stuck_timeout, 0);
+	host->status_reg = stat;
+	set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+	tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t imxmci_irq(int irq, void *devid)
+{
+	struct imxmci_host *host = devid;
+	uint32_t stat = MMC_STATUS;
+	int handled = 1;
+
+	MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
+
+	atomic_set(&host->stuck_timeout, 0);
+	host->status_reg = stat;
+	set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+	set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
+	tasklet_schedule(&host->tasklet);
+
+	return IRQ_RETVAL(handled);;
+}
+
+static void imxmci_tasklet_fnc(unsigned long data)
+{
+	struct imxmci_host *host = (struct imxmci_host *)data;
+	u32 stat;
+	unsigned int data_dir_mask = 0;	/* STATUS_WR_CRC_ERROR_CODE_MASK */
+	int timeout = 0;
+
+	if(atomic_read(&host->stuck_timeout) > 4) {
+		char *what;
+		timeout = 1;
+		stat = MMC_STATUS;
+		host->status_reg = stat;
+		if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+			if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+				what = "RESP+DMA";
+			else
+				what = "RESP";
+		else
+			if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
+				if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
+					what = "DATA";
+				else
+					what = "DMA";
+			else
+				what = "???";
+
+		dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
+		       what, stat, MMC_INT_MASK);
+		dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
+		       MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
+		dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
+		       host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
+	}
+
+	if(!host->present || timeout)
+		host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
+				    STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
+
+	if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
+		clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
+
+		stat = MMC_STATUS;
+		/*
+		 * This is not required in theory, but there is chance to miss some flag
+		 * which clears automatically by mask write, FreeScale original code keeps
+		 * stat from IRQ time so do I
+		 */
+		stat |= host->status_reg;
+
+		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+			stat &= ~STATUS_CRC_READ_ERR;
+
+		if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+			imxmci_busy_wait_for_status(host, &stat,
+					STATUS_END_CMD_RESP | STATUS_ERR_MASK,
+					20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
+		}
+
+		if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
+			if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+				imxmci_cmd_done(host, stat);
+			if(host->data && (stat & STATUS_ERR_MASK))
+				imxmci_data_done(host, stat);
+		}
+
+		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
+			stat |= MMC_STATUS;
+			if(imxmci_cpu_driven_data(host, &stat)){
+				if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+					imxmci_cmd_done(host, stat);
+				atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
+							&host->pending_events);
+				imxmci_data_done(host, stat);
+			}
+		}
+	}
+
+	if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
+	   !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+
+		stat = MMC_STATUS;
+		/* Same as above */
+		stat |= host->status_reg;
+
+		if(host->dma_dir == DMA_TO_DEVICE) {
+			data_dir_mask = STATUS_WRITE_OP_DONE;
+		} else {
+			data_dir_mask = STATUS_DATA_TRANS_DONE;
+		}
+
+		if(stat & data_dir_mask) {
+			clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
+			imxmci_data_done(host, stat);
+		}
+	}
+
+	if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
+
+		if(host->cmd)
+			imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
+
+		if(host->data)
+			imxmci_data_done(host, STATUS_TIME_OUT_READ |
+					 STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
+
+		if(host->req)
+			imxmci_finish_request(host, host->req);
+
+		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+
+	}
+}
+
+static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+	struct imxmci_host *host = mmc_priv(mmc);
+	unsigned int cmdat;
+
+	WARN_ON(host->req != NULL);
+
+	host->req = req;
+
+	cmdat = 0;
+
+	if (req->data) {
+		imxmci_setup_data(host, req->data);
+
+		cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+		if (req->data->flags & MMC_DATA_WRITE)
+			cmdat |= CMD_DAT_CONT_WRITE;
+
+		if (req->data->flags & MMC_DATA_STREAM) {
+			cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
+		}
+	}
+
+	imxmci_start_cmd(host, req->cmd, cmdat);
+}
+
+#define CLK_RATE 19200000
+
+static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct imxmci_host *host = mmc_priv(mmc);
+	int prescaler;
+
+	if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
+		host->actual_bus_width = MMC_BUS_WIDTH_4;
+		imx_gpio_mode(PB11_PF_SD_DAT3);
+	}else{
+		host->actual_bus_width = MMC_BUS_WIDTH_1;
+		imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+	}
+
+	if ( host->power_mode != ios->power_mode ) {
+		switch (ios->power_mode) {
+		case MMC_POWER_OFF:
+        		break;
+		case MMC_POWER_UP:
+			set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+        		break;
+		case MMC_POWER_ON:
+        		break;
+		}
+		host->power_mode = ios->power_mode;
+	}
+
+	if ( ios->clock ) {
+		unsigned int clk;
+
+		/* The prescaler is 5 for PERCLK2 equal to 96MHz
+		 * then 96MHz / 5 = 19.2 MHz
+		 */
+		clk=imx_get_perclk2();
+		prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
+		switch(prescaler) {
+		case 0:
+		case 1:	prescaler = 0;
+			break;
+		case 2:	prescaler = 1;
+			break;
+		case 3:	prescaler = 2;
+			break;
+		case 4:	prescaler = 4;
+			break;
+		default:
+		case 5:	prescaler = 5;
+			break;
+		}
+
+		dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
+			clk, prescaler);
+
+		for(clk=0; clk<8; clk++) {
+			int x;
+			x = CLK_RATE / (1<<clk);
+			if( x <= ios->clock)
+				break;
+		}
+
+		MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
+
+		imxmci_stop_clock(host);
+		MMC_CLK_RATE = (prescaler<<3) | clk;
+		/*
+		 * Under my understanding, clock should not be started there, because it would
+		 * initiate SDHC sequencer and send last or random command into card
+		 */
+		/*imxmci_start_clock(host);*/
+
+		dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
+	} else {
+		imxmci_stop_clock(host);
+	}
+}
+
+static const struct mmc_host_ops imxmci_ops = {
+	.request	= imxmci_request,
+	.set_ios	= imxmci_set_ios,
+};
+
+static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++)
+		if (dev->resource[i].flags == mask && nr-- == 0)
+			return &dev->resource[i];
+	return NULL;
+}
+
+static int platform_device_irq(struct platform_device *dev, int nr)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++)
+		if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
+			return dev->resource[i].start;
+	return NO_IRQ;
+}
+
+static void imxmci_check_status(unsigned long data)
+{
+	struct imxmci_host *host = (struct imxmci_host *)data;
+
+	if( host->pdata->card_present() != host->present ) {
+		host->present ^= 1;
+		dev_info(mmc_dev(host->mmc), "card %s\n",
+		      host->present ? "inserted" : "removed");
+
+		set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
+		tasklet_schedule(&host->tasklet);
+	}
+
+	if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
+	   test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+		atomic_inc(&host->stuck_timeout);
+		if(atomic_read(&host->stuck_timeout) > 4)
+			tasklet_schedule(&host->tasklet);
+	} else {
+		atomic_set(&host->stuck_timeout, 0);
+
+	}
+
+	mod_timer(&host->timer, jiffies + (HZ>>1));
+}
+
+static int imxmci_probe(struct platform_device *pdev)
+{
+	struct mmc_host *mmc;
+	struct imxmci_host *host = NULL;
+	struct resource *r;
+	int ret = 0, irq;
+
+	printk(KERN_INFO "i.MX mmc driver\n");
+
+	r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_device_irq(pdev, 0);
+	if (!r || irq == NO_IRQ)
+		return -ENXIO;
+
+	r = request_mem_region(r->start, 0x100, "IMXMCI");
+	if (!r)
+		return -EBUSY;
+
+	mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
+	if (!mmc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mmc->ops = &imxmci_ops;
+	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_CAP_BYTEBLOCK;
+
+	/* MMC core transfer sizes tunable parameters */
+	mmc->max_hw_segs = 64;
+	mmc->max_phys_segs = 64;
+	mmc->max_seg_size = 64*512;	/* default PAGE_CACHE_SIZE */
+	mmc->max_req_size = 64*512;	/* default PAGE_CACHE_SIZE */
+	mmc->max_blk_size = 2048;
+	mmc->max_blk_count = 65535;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->dma_allocated = 0;
+	host->pdata = pdev->dev.platform_data;
+
+	spin_lock_init(&host->lock);
+	host->res = r;
+	host->irq = irq;
+
+	imx_gpio_mode(PB8_PF_SD_DAT0);
+	imx_gpio_mode(PB9_PF_SD_DAT1);
+	imx_gpio_mode(PB10_PF_SD_DAT2);
+	/* Configured as GPIO with pull-up to ensure right MCC card mode */
+	/* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
+	imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
+	/* imx_gpio_mode(PB11_PF_SD_DAT3); */
+	imx_gpio_mode(PB12_PF_SD_CLK);
+	imx_gpio_mode(PB13_PF_SD_CMD);
+
+	imxmci_softreset();
+
+	if ( MMC_REV_NO != 0x390 ) {
+		dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
+		        MMC_REV_NO);
+		goto out;
+	}
+
+	MMC_READ_TO = 0x2db4; /* recommended in data sheet */
+
+	host->imask = IMXMCI_INT_MASK_DEFAULT;
+	MMC_INT_MASK = host->imask;
+
+
+	if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
+		dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
+		ret = -EBUSY;
+		goto out;
+	}
+	host->dma_allocated=1;
+	imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
+
+	tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
+	host->status_reg=0;
+	host->pending_events=0;
+
+	ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
+	if (ret)
+		goto out;
+
+	host->present = host->pdata->card_present();
+	init_timer(&host->timer);
+	host->timer.data = (unsigned long)host;
+	host->timer.function = imxmci_check_status;
+	add_timer(&host->timer);
+	mod_timer(&host->timer, jiffies + (HZ>>1));
+
+	platform_set_drvdata(pdev, mmc);
+
+	mmc_add_host(mmc);
+
+	return 0;
+
+out:
+	if (host) {
+		if(host->dma_allocated){
+			imx_dma_free(host->dma);
+			host->dma_allocated=0;
+		}
+	}
+	if (mmc)
+		mmc_free_host(mmc);
+	release_resource(r);
+	return ret;
+}
+
+static int imxmci_remove(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (mmc) {
+		struct imxmci_host *host = mmc_priv(mmc);
+
+		tasklet_disable(&host->tasklet);
+
+		del_timer_sync(&host->timer);
+		mmc_remove_host(mmc);
+
+		free_irq(host->irq, host);
+		if(host->dma_allocated){
+			imx_dma_free(host->dma);
+			host->dma_allocated=0;
+		}
+
+		tasklet_kill(&host->tasklet);
+
+		release_resource(host->res);
+
+		mmc_free_host(mmc);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	int ret = 0;
+
+	if (mmc)
+		ret = mmc_suspend_host(mmc, state);
+
+	return ret;
+}
+
+static int imxmci_resume(struct platform_device *dev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	struct imxmci_host *host;
+	int ret = 0;
+
+	if (mmc) {
+		host = mmc_priv(mmc);
+		if(host)
+			set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
+		ret = mmc_resume_host(mmc);
+	}
+
+	return ret;
+}
+#else
+#define imxmci_suspend  NULL
+#define imxmci_resume   NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver imxmci_driver = {
+	.probe		= imxmci_probe,
+	.remove		= imxmci_remove,
+	.suspend	= imxmci_suspend,
+	.resume		= imxmci_resume,
+	.driver		= {
+		.name		= DRIVER_NAME,
+	}
+};
+
+static int __init imxmci_init(void)
+{
+	return platform_driver_register(&imxmci_driver);
+}
+
+static void __exit imxmci_exit(void)
+{
+	platform_driver_unregister(&imxmci_driver);
+}
+
+module_init(imxmci_init);
+module_exit(imxmci_exit);
+
+MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/imxmmc.h b/drivers/mmc/host/imxmmc.h
new file mode 100644
index 0000000..e5339e3
--- /dev/null
+++ b/drivers/mmc/host/imxmmc.h
@@ -0,0 +1,67 @@
+
+# define __REG16(x)	(*((volatile u16 *)IO_ADDRESS(x)))
+
+#define MMC_STR_STP_CLK  __REG16(IMX_MMC_BASE + 0x00)
+#define MMC_STATUS       __REG16(IMX_MMC_BASE + 0x04)
+#define MMC_CLK_RATE     __REG16(IMX_MMC_BASE + 0x08)
+#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
+#define MMC_RES_TO       __REG16(IMX_MMC_BASE + 0x10)
+#define MMC_READ_TO      __REG16(IMX_MMC_BASE + 0x14)
+#define MMC_BLK_LEN      __REG16(IMX_MMC_BASE + 0x18)
+#define MMC_NOB          __REG16(IMX_MMC_BASE + 0x1C)
+#define MMC_REV_NO       __REG16(IMX_MMC_BASE + 0x20)
+#define MMC_INT_MASK     __REG16(IMX_MMC_BASE + 0x24)
+#define MMC_CMD          __REG16(IMX_MMC_BASE + 0x28)
+#define MMC_ARGH         __REG16(IMX_MMC_BASE + 0x2C)
+#define MMC_ARGL         __REG16(IMX_MMC_BASE + 0x30)
+#define MMC_RES_FIFO     __REG16(IMX_MMC_BASE + 0x34)
+#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
+#define MMC_BUFFER_ACCESS_OFS 0x38
+
+
+#define STR_STP_CLK_ENDIAN              (1<<5)
+#define STR_STP_CLK_RESET               (1<<3)
+#define STR_STP_CLK_ENABLE              (1<<2)
+#define STR_STP_CLK_START_CLK           (1<<1)
+#define STR_STP_CLK_STOP_CLK            (1<<0)
+#define STATUS_CARD_PRESENCE            (1<<15)
+#define STATUS_SDIO_INT_ACTIVE          (1<<14)
+#define STATUS_END_CMD_RESP             (1<<13)
+#define STATUS_WRITE_OP_DONE            (1<<12)
+#define STATUS_DATA_TRANS_DONE          (1<<11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK   (3<<10)
+#define STATUS_CARD_BUS_CLK_RUN         (1<<8)
+#define STATUS_APPL_BUFF_FF             (1<<7)
+#define STATUS_APPL_BUFF_FE             (1<<6)
+#define STATUS_RESP_CRC_ERR             (1<<5)
+#define STATUS_CRC_READ_ERR             (1<<3)
+#define STATUS_CRC_WRITE_ERR            (1<<2)
+#define STATUS_TIME_OUT_RESP            (1<<1)
+#define STATUS_TIME_OUT_READ            (1<<0)
+#define STATUS_ERR_MASK                 0x2f
+#define CLK_RATE_PRESCALER(x)           ((x) & 0x7)
+#define CLK_RATE_CLK_RATE(x)            (((x) & 0x7) << 3)
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF  (1<<12)
+#define CMD_DAT_CONT_STOP_READWAIT      (1<<11)
+#define CMD_DAT_CONT_START_READWAIT     (1<<10)
+#define CMD_DAT_CONT_BUS_WIDTH_1        (0<<8)
+#define CMD_DAT_CONT_BUS_WIDTH_4        (2<<8)
+#define CMD_DAT_CONT_INIT               (1<<7)
+#define CMD_DAT_CONT_BUSY               (1<<6)
+#define CMD_DAT_CONT_STREAM_BLOCK       (1<<5)
+#define CMD_DAT_CONT_WRITE              (1<<4)
+#define CMD_DAT_CONT_DATA_ENABLE        (1<<3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
+#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
+#define INT_MASK_AUTO_CARD_DETECT       (1<<6)
+#define INT_MASK_DAT0_EN                (1<<5)
+#define INT_MASK_SDIO                   (1<<4)
+#define INT_MASK_BUF_READY              (1<<3)
+#define INT_MASK_END_CMD_RES            (1<<2)
+#define INT_MASK_WRITE_OP_DONE          (1<<1)
+#define INT_MASK_DATA_TRAN              (1<<0)
+#define INT_ALL                         (0x7f)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
new file mode 100644
index 0000000..d11c2d2
--- /dev/null
+++ b/drivers/mmc/host/mmci.c
@@ -0,0 +1,702 @@
+/*
+ *  linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/highmem.h>
+#include <linux/mmc/host.h>
+#include <linux/amba/bus.h>
+#include <linux/clk.h>
+
+#include <asm/cacheflush.h>
+#include <asm/div64.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+#include <asm/mach/mmc.h>
+
+#include "mmci.h"
+
+#define DRIVER_NAME "mmci-pl18x"
+
+#define DBG(host,fmt,args...)	\
+	pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
+
+static unsigned int fmax = 515633;
+
+static void
+mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
+{
+	writel(0, host->base + MMCICOMMAND);
+
+	BUG_ON(host->data);
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+
+	if (mrq->data)
+		mrq->data->bytes_xfered = host->data_xfered;
+
+	/*
+	 * Need to drop the host lock here; mmc_request_done may call
+	 * back into the driver...
+	 */
+	spin_unlock(&host->lock);
+	mmc_request_done(host->mmc, mrq);
+	spin_lock(&host->lock);
+}
+
+static void mmci_stop_data(struct mmci_host *host)
+{
+	writel(0, host->base + MMCIDATACTRL);
+	writel(0, host->base + MMCIMASK1);
+	host->data = NULL;
+}
+
+static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
+{
+	unsigned int datactrl, timeout, irqmask;
+	unsigned long long clks;
+	void __iomem *base;
+	int blksz_bits;
+
+	DBG(host, "blksz %04x blks %04x flags %08x\n",
+	    data->blksz, data->blocks, data->flags);
+
+	host->data = data;
+	host->size = data->blksz;
+	host->data_xfered = 0;
+
+	mmci_init_sg(host, data);
+
+	clks = (unsigned long long)data->timeout_ns * host->cclk;
+	do_div(clks, 1000000000UL);
+
+	timeout = data->timeout_clks + (unsigned int)clks;
+
+	base = host->base;
+	writel(timeout, base + MMCIDATATIMER);
+	writel(host->size, base + MMCIDATALENGTH);
+
+	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;
+
+		/*
+		 * If we have less than a FIFOSIZE of bytes to transfer,
+		 * trigger a PIO interrupt as soon as any data is available.
+		 */
+		if (host->size < MCI_FIFOSIZE)
+			irqmask |= MCI_RXDATAAVLBLMASK;
+	} else {
+		/*
+		 * We don't actually need to include "FIFO empty" here
+		 * since its implicit in "FIFO half empty".
+		 */
+		irqmask = MCI_TXFIFOHALFEMPTYMASK;
+	}
+
+	writel(datactrl, base + MMCIDATACTRL);
+	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
+	writel(irqmask, base + MMCIMASK1);
+}
+
+static void
+mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
+{
+	void __iomem *base = host->base;
+
+	DBG(host, "op %02x arg %08x flags %08x\n",
+	    cmd->opcode, cmd->arg, cmd->flags);
+
+	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+		writel(0, base + MMCICOMMAND);
+		udelay(1);
+	}
+
+	c |= cmd->opcode | MCI_CPSM_ENABLE;
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136)
+			c |= MCI_CPSM_LONGRSP;
+		c |= MCI_CPSM_RESPONSE;
+	}
+	if (/*interrupt*/0)
+		c |= MCI_CPSM_INTERRUPT;
+
+	host->cmd = cmd;
+
+	writel(cmd->arg, base + MMCIARGUMENT);
+	writel(c, base + MMCICOMMAND);
+}
+
+static void
+mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
+	      unsigned int status)
+{
+	if (status & MCI_DATABLOCKEND) {
+		host->data_xfered += data->blksz;
+	}
+	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+		if (status & MCI_DATACRCFAIL)
+			data->error = MMC_ERR_BADCRC;
+		else if (status & MCI_DATATIMEOUT)
+			data->error = MMC_ERR_TIMEOUT;
+		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
+			data->error = MMC_ERR_FIFO;
+		status |= MCI_DATAEND;
+
+		/*
+		 * We hit an error condition.  Ensure that any data
+		 * partially written to a page is properly coherent.
+		 */
+		if (host->sg_len && data->flags & MMC_DATA_READ)
+			flush_dcache_page(host->sg_ptr->page);
+	}
+	if (status & MCI_DATAEND) {
+		mmci_stop_data(host);
+
+		if (!data->stop) {
+			mmci_request_end(host, data->mrq);
+		} else {
+			mmci_start_command(host, data->stop, 0);
+		}
+	}
+}
+
+static void
+mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
+	     unsigned int status)
+{
+	void __iomem *base = host->base;
+
+	host->cmd = NULL;
+
+	cmd->resp[0] = readl(base + MMCIRESPONSE0);
+	cmd->resp[1] = readl(base + MMCIRESPONSE1);
+	cmd->resp[2] = readl(base + MMCIRESPONSE2);
+	cmd->resp[3] = readl(base + MMCIRESPONSE3);
+
+	if (status & MCI_CMDTIMEOUT) {
+		cmd->error = MMC_ERR_TIMEOUT;
+	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
+		cmd->error = MMC_ERR_BADCRC;
+	}
+
+	if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+		if (host->data)
+			mmci_stop_data(host);
+		mmci_request_end(host, cmd->mrq);
+	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
+		mmci_start_data(host, cmd->data);
+	}
+}
+
+static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
+{
+	void __iomem *base = host->base;
+	char *ptr = buffer;
+	u32 status;
+
+	do {
+		int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+
+		if (count > remain)
+			count = remain;
+
+		if (count <= 0)
+			break;
+
+		readsl(base + MMCIFIFO, ptr, count >> 2);
+
+		ptr += count;
+		remain -= count;
+
+		if (remain == 0)
+			break;
+
+		status = readl(base + MMCISTATUS);
+	} while (status & MCI_RXDATAAVLBL);
+
+	return ptr - buffer;
+}
+
+static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
+{
+	void __iomem *base = host->base;
+	char *ptr = buffer;
+
+	do {
+		unsigned int count, maxcnt;
+
+		maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+		count = min(remain, maxcnt);
+
+		writesl(base + MMCIFIFO, ptr, count >> 2);
+
+		ptr += count;
+		remain -= count;
+
+		if (remain == 0)
+			break;
+
+		status = readl(base + MMCISTATUS);
+	} while (status & MCI_TXFIFOHALFEMPTY);
+
+	return ptr - buffer;
+}
+
+/*
+ * PIO data transfer IRQ handler.
+ */
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
+{
+	struct mmci_host *host = dev_id;
+	void __iomem *base = host->base;
+	u32 status;
+
+	status = readl(base + MMCISTATUS);
+
+	DBG(host, "irq1 %08x\n", status);
+
+	do {
+		unsigned long flags;
+		unsigned int remain, len;
+		char *buffer;
+
+		/*
+		 * For write, we only need to test the half-empty flag
+		 * here - if the FIFO is completely empty, then by
+		 * definition it is more than half empty.
+		 *
+		 * For read, check for data available.
+		 */
+		if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
+			break;
+
+		/*
+		 * Map the current scatter buffer.
+		 */
+		buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
+		remain = host->sg_ptr->length - host->sg_off;
+
+		len = 0;
+		if (status & MCI_RXACTIVE)
+			len = mmci_pio_read(host, buffer, remain);
+		if (status & MCI_TXACTIVE)
+			len = mmci_pio_write(host, buffer, remain, status);
+
+		/*
+		 * Unmap the buffer.
+		 */
+		mmci_kunmap_atomic(host, buffer, &flags);
+
+		host->sg_off += len;
+		host->size -= len;
+		remain -= len;
+
+		if (remain)
+			break;
+
+		/*
+		 * If we were reading, and we have completed this
+		 * page, ensure that the data cache is coherent.
+		 */
+		if (status & MCI_RXACTIVE)
+			flush_dcache_page(host->sg_ptr->page);
+
+		if (!mmci_next_sg(host))
+			break;
+
+		status = readl(base + MMCISTATUS);
+	} while (1);
+
+	/*
+	 * If we're nearing the end of the read, switch to
+	 * "any data available" mode.
+	 */
+	if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
+		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+
+	/*
+	 * If we run out of data, disable the data IRQs; this
+	 * prevents a race where the FIFO becomes empty before
+	 * the chip itself has disabled the data path, and
+	 * stops us racing with our data end IRQ.
+	 */
+	if (host->size == 0) {
+		writel(0, base + MMCIMASK1);
+		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Handle completion of command and data transfers.
+ */
+static irqreturn_t mmci_irq(int irq, void *dev_id)
+{
+	struct mmci_host *host = dev_id;
+	u32 status;
+	int ret = 0;
+
+	spin_lock(&host->lock);
+
+	do {
+		struct mmc_command *cmd;
+		struct mmc_data *data;
+
+		status = readl(host->base + MMCISTATUS);
+		status &= readl(host->base + MMCIMASK0);
+		writel(status, host->base + MMCICLEAR);
+
+		DBG(host, "irq0 %08x\n", status);
+
+		data = host->data;
+		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
+			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
+			mmci_data_irq(host, data, status);
+
+		cmd = host->cmd;
+		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
+			mmci_cmd_irq(host, cmd, status);
+
+		ret = 1;
+	} while (status);
+
+	spin_unlock(&host->lock);
+
+	return IRQ_RETVAL(ret);
+}
+
+static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmci_host *host = mmc_priv(mmc);
+
+	WARN_ON(host->mrq != NULL);
+
+	spin_lock_irq(&host->lock);
+
+	host->mrq = mrq;
+
+	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
+		mmci_start_data(host, mrq->data);
+
+	mmci_start_command(host, mrq->cmd, 0);
+
+	spin_unlock_irq(&host->lock);
+}
+
+static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct mmci_host *host = mmc_priv(mmc);
+	u32 clk = 0, pwr = 0;
+
+	if (ios->clock) {
+		if (ios->clock >= host->mclk) {
+			clk = MCI_CLK_BYPASS;
+			host->cclk = host->mclk;
+		} else {
+			clk = host->mclk / (2 * ios->clock) - 1;
+			if (clk > 256)
+				clk = 255;
+			host->cclk = host->mclk / (2 * (clk + 1));
+		}
+		clk |= MCI_CLK_ENABLE;
+	}
+
+	if (host->plat->translate_vdd)
+		pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		break;
+	case MMC_POWER_UP:
+		pwr |= MCI_PWR_UP;
+		break;
+	case MMC_POWER_ON:
+		pwr |= MCI_PWR_ON;
+		break;
+	}
+
+	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+		pwr |= MCI_ROD;
+
+	writel(clk, host->base + MMCICLOCK);
+
+	if (host->pwr != pwr) {
+		host->pwr = pwr;
+		writel(pwr, host->base + MMCIPOWER);
+	}
+}
+
+static const struct mmc_host_ops mmci_ops = {
+	.request	= mmci_request,
+	.set_ios	= mmci_set_ios,
+};
+
+static void mmci_check_status(unsigned long data)
+{
+	struct mmci_host *host = (struct mmci_host *)data;
+	unsigned int status;
+
+	status = host->plat->status(mmc_dev(host->mmc));
+	if (status ^ host->oldstat)
+		mmc_detect_change(host->mmc, 0);
+
+	host->oldstat = status;
+	mod_timer(&host->timer, jiffies + HZ);
+}
+
+static int mmci_probe(struct amba_device *dev, void *id)
+{
+	struct mmc_platform_data *plat = dev->dev.platform_data;
+	struct mmci_host *host;
+	struct mmc_host *mmc;
+	int ret;
+
+	/* must have platform data */
+	if (!plat) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = amba_request_regions(dev, DRIVER_NAME);
+	if (ret)
+		goto out;
+
+	mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
+	if (!mmc) {
+		ret = -ENOMEM;
+		goto rel_regions;
+	}
+
+	host = mmc_priv(mmc);
+	host->clk = clk_get(&dev->dev, "MCLK");
+	if (IS_ERR(host->clk)) {
+		ret = PTR_ERR(host->clk);
+		host->clk = NULL;
+		goto host_free;
+	}
+
+	ret = clk_enable(host->clk);
+	if (ret)
+		goto clk_free;
+
+	host->plat = plat;
+	host->mclk = clk_get_rate(host->clk);
+	host->mmc = mmc;
+	host->base = ioremap(dev->res.start, SZ_4K);
+	if (!host->base) {
+		ret = -ENOMEM;
+		goto clk_disable;
+	}
+
+	mmc->ops = &mmci_ops;
+	mmc->f_min = (host->mclk + 511) / 512;
+	mmc->f_max = min(host->mclk, fmax);
+	mmc->ocr_avail = plat->ocr_mask;
+	mmc->caps = MMC_CAP_MULTIWRITE;
+
+	/*
+	 * We can do SGIO
+	 */
+	mmc->max_hw_segs = 16;
+	mmc->max_phys_segs = NR_SG;
+
+	/*
+	 * Since we only have a 16-bit data length register, we must
+	 * ensure that we don't exceed 2^16-1 bytes in a single request.
+	 */
+	mmc->max_req_size = 65535;
+
+	/*
+	 * Set the maximum segment size.  Since we aren't doing DMA
+	 * (yet) we are only limited by the data length register.
+	 */
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Block size can be up to 2048 bytes, but must be a power of two.
+	 */
+	mmc->max_blk_size = 2048;
+
+	/*
+	 * No limit on the number of blocks transferred.
+	 */
+	mmc->max_blk_count = mmc->max_req_size;
+
+	spin_lock_init(&host->lock);
+
+	writel(0, host->base + MMCIMASK0);
+	writel(0, host->base + MMCIMASK1);
+	writel(0xfff, host->base + MMCICLEAR);
+
+	ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
+	if (ret)
+		goto unmap;
+
+	ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
+	if (ret)
+		goto irq0_free;
+
+	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+	amba_set_drvdata(dev, mmc);
+
+	mmc_add_host(mmc);
+
+	printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
+		mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
+		(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
+
+	init_timer(&host->timer);
+	host->timer.data = (unsigned long)host;
+	host->timer.function = mmci_check_status;
+	host->timer.expires = jiffies + HZ;
+	add_timer(&host->timer);
+
+	return 0;
+
+ irq0_free:
+	free_irq(dev->irq[0], host);
+ unmap:
+	iounmap(host->base);
+ clk_disable:
+	clk_disable(host->clk);
+ clk_free:
+	clk_put(host->clk);
+ host_free:
+	mmc_free_host(mmc);
+ rel_regions:
+	amba_release_regions(dev);
+ out:
+	return ret;
+}
+
+static int mmci_remove(struct amba_device *dev)
+{
+	struct mmc_host *mmc = amba_get_drvdata(dev);
+
+	amba_set_drvdata(dev, NULL);
+
+	if (mmc) {
+		struct mmci_host *host = mmc_priv(mmc);
+
+		del_timer_sync(&host->timer);
+
+		mmc_remove_host(mmc);
+
+		writel(0, host->base + MMCIMASK0);
+		writel(0, host->base + MMCIMASK1);
+
+		writel(0, host->base + MMCICOMMAND);
+		writel(0, host->base + MMCIDATACTRL);
+
+		free_irq(dev->irq[0], host);
+		free_irq(dev->irq[1], host);
+
+		iounmap(host->base);
+		clk_disable(host->clk);
+		clk_put(host->clk);
+
+		mmc_free_host(mmc);
+
+		amba_release_regions(dev);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmci_suspend(struct amba_device *dev, pm_message_t state)
+{
+	struct mmc_host *mmc = amba_get_drvdata(dev);
+	int ret = 0;
+
+	if (mmc) {
+		struct mmci_host *host = mmc_priv(mmc);
+
+		ret = mmc_suspend_host(mmc, state);
+		if (ret == 0)
+			writel(0, host->base + MMCIMASK0);
+	}
+
+	return ret;
+}
+
+static int mmci_resume(struct amba_device *dev)
+{
+	struct mmc_host *mmc = amba_get_drvdata(dev);
+	int ret = 0;
+
+	if (mmc) {
+		struct mmci_host *host = mmc_priv(mmc);
+
+		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+
+		ret = mmc_resume_host(mmc);
+	}
+
+	return ret;
+}
+#else
+#define mmci_suspend	NULL
+#define mmci_resume	NULL
+#endif
+
+static struct amba_id mmci_ids[] = {
+	{
+		.id	= 0x00041180,
+		.mask	= 0x000fffff,
+	},
+	{
+		.id	= 0x00041181,
+		.mask	= 0x000fffff,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver mmci_driver = {
+	.drv		= {
+		.name	= DRIVER_NAME,
+	},
+	.probe		= mmci_probe,
+	.remove		= mmci_remove,
+	.suspend	= mmci_suspend,
+	.resume		= mmci_resume,
+	.id_table	= mmci_ids,
+};
+
+static int __init mmci_init(void)
+{
+	return amba_driver_register(&mmci_driver);
+}
+
+static void __exit mmci_exit(void)
+{
+	amba_driver_unregister(&mmci_driver);
+}
+
+module_init(mmci_init);
+module_exit(mmci_exit);
+module_param(fmax, uint, 0444);
+
+MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
new file mode 100644
index 0000000..6d7eadc
--- /dev/null
+++ b/drivers/mmc/host/mmci.h
@@ -0,0 +1,179 @@
+/*
+ *  linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
+ *
+ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define MMCIPOWER		0x000
+#define MCI_PWR_OFF		0x00
+#define MCI_PWR_UP		0x02
+#define MCI_PWR_ON		0x03
+#define MCI_OD			(1 << 6)
+#define MCI_ROD			(1 << 7)
+
+#define MMCICLOCK		0x004
+#define MCI_CLK_ENABLE		(1 << 8)
+#define MCI_CLK_PWRSAVE		(1 << 9)
+#define MCI_CLK_BYPASS		(1 << 10)
+
+#define MMCIARGUMENT		0x008
+#define MMCICOMMAND		0x00c
+#define MCI_CPSM_RESPONSE	(1 << 6)
+#define MCI_CPSM_LONGRSP	(1 << 7)
+#define MCI_CPSM_INTERRUPT	(1 << 8)
+#define MCI_CPSM_PENDING	(1 << 9)
+#define MCI_CPSM_ENABLE		(1 << 10)
+
+#define MMCIRESPCMD		0x010
+#define MMCIRESPONSE0		0x014
+#define MMCIRESPONSE1		0x018
+#define MMCIRESPONSE2		0x01c
+#define MMCIRESPONSE3		0x020
+#define MMCIDATATIMER		0x024
+#define MMCIDATALENGTH		0x028
+#define MMCIDATACTRL		0x02c
+#define MCI_DPSM_ENABLE		(1 << 0)
+#define MCI_DPSM_DIRECTION	(1 << 1)
+#define MCI_DPSM_MODE		(1 << 2)
+#define MCI_DPSM_DMAENABLE	(1 << 3)
+
+#define MMCIDATACNT		0x030
+#define MMCISTATUS		0x034
+#define MCI_CMDCRCFAIL		(1 << 0)
+#define MCI_DATACRCFAIL		(1 << 1)
+#define MCI_CMDTIMEOUT		(1 << 2)
+#define MCI_DATATIMEOUT		(1 << 3)
+#define MCI_TXUNDERRUN		(1 << 4)
+#define MCI_RXOVERRUN		(1 << 5)
+#define MCI_CMDRESPEND		(1 << 6)
+#define MCI_CMDSENT		(1 << 7)
+#define MCI_DATAEND		(1 << 8)
+#define MCI_DATABLOCKEND	(1 << 10)
+#define MCI_CMDACTIVE		(1 << 11)
+#define MCI_TXACTIVE		(1 << 12)
+#define MCI_RXACTIVE		(1 << 13)
+#define MCI_TXFIFOHALFEMPTY	(1 << 14)
+#define MCI_RXFIFOHALFFULL	(1 << 15)
+#define MCI_TXFIFOFULL		(1 << 16)
+#define MCI_RXFIFOFULL		(1 << 17)
+#define MCI_TXFIFOEMPTY		(1 << 18)
+#define MCI_RXFIFOEMPTY		(1 << 19)
+#define MCI_TXDATAAVLBL		(1 << 20)
+#define MCI_RXDATAAVLBL		(1 << 21)
+
+#define MMCICLEAR		0x038
+#define MCI_CMDCRCFAILCLR	(1 << 0)
+#define MCI_DATACRCFAILCLR	(1 << 1)
+#define MCI_CMDTIMEOUTCLR	(1 << 2)
+#define MCI_DATATIMEOUTCLR	(1 << 3)
+#define MCI_TXUNDERRUNCLR	(1 << 4)
+#define MCI_RXOVERRUNCLR	(1 << 5)
+#define MCI_CMDRESPENDCLR	(1 << 6)
+#define MCI_CMDSENTCLR		(1 << 7)
+#define MCI_DATAENDCLR		(1 << 8)
+#define MCI_DATABLOCKENDCLR	(1 << 10)
+
+#define MMCIMASK0		0x03c
+#define MCI_CMDCRCFAILMASK	(1 << 0)
+#define MCI_DATACRCFAILMASK	(1 << 1)
+#define MCI_CMDTIMEOUTMASK	(1 << 2)
+#define MCI_DATATIMEOUTMASK	(1 << 3)
+#define MCI_TXUNDERRUNMASK	(1 << 4)
+#define MCI_RXOVERRUNMASK	(1 << 5)
+#define MCI_CMDRESPENDMASK	(1 << 6)
+#define MCI_CMDSENTMASK		(1 << 7)
+#define MCI_DATAENDMASK		(1 << 8)
+#define MCI_DATABLOCKENDMASK	(1 << 10)
+#define MCI_CMDACTIVEMASK	(1 << 11)
+#define MCI_TXACTIVEMASK	(1 << 12)
+#define MCI_RXACTIVEMASK	(1 << 13)
+#define MCI_TXFIFOHALFEMPTYMASK	(1 << 14)
+#define MCI_RXFIFOHALFFULLMASK	(1 << 15)
+#define MCI_TXFIFOFULLMASK	(1 << 16)
+#define MCI_RXFIFOFULLMASK	(1 << 17)
+#define MCI_TXFIFOEMPTYMASK	(1 << 18)
+#define MCI_RXFIFOEMPTYMASK	(1 << 19)
+#define MCI_TXDATAAVLBLMASK	(1 << 20)
+#define MCI_RXDATAAVLBLMASK	(1 << 21)
+
+#define MMCIMASK1		0x040
+#define MMCIFIFOCNT		0x048
+#define MMCIFIFO		0x080 /* to 0x0bc */
+
+#define MCI_IRQENABLE	\
+	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\
+	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
+	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+
+/*
+ * The size of the FIFO in bytes.
+ */
+#define MCI_FIFOSIZE	(16*4)
+	
+#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
+
+#define NR_SG		16
+
+struct clk;
+
+struct mmci_host {
+	void __iomem		*base;
+	struct mmc_request	*mrq;
+	struct mmc_command	*cmd;
+	struct mmc_data		*data;
+	struct mmc_host		*mmc;
+	struct clk		*clk;
+
+	unsigned int		data_xfered;
+
+	spinlock_t		lock;
+
+	unsigned int		mclk;
+	unsigned int		cclk;
+	u32			pwr;
+	struct mmc_platform_data *plat;
+
+	struct timer_list	timer;
+	unsigned int		oldstat;
+
+	unsigned int		sg_len;
+
+	/* pio stuff */
+	struct scatterlist	*sg_ptr;
+	unsigned int		sg_off;
+	unsigned int		size;
+};
+
+static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
+{
+	/*
+	 * Ideally, we want the higher levels to pass us a scatter list.
+	 */
+	host->sg_len = data->sg_len;
+	host->sg_ptr = data->sg;
+	host->sg_off = 0;
+}
+
+static inline int mmci_next_sg(struct mmci_host *host)
+{
+	host->sg_ptr++;
+	host->sg_off = 0;
+	return --host->sg_len;
+}
+
+static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
+{
+	struct scatterlist *sg = host->sg_ptr;
+
+	local_irq_save(*flags);
+	return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+}
+
+static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
+{
+	kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
+	local_irq_restore(*flags);
+}
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
new file mode 100644
index 0000000..1914e65
--- /dev/null
+++ b/drivers/mmc/host/omap.c
@@ -0,0 +1,1295 @@
+/*
+ *  linux/drivers/media/mmc/omap.c
+ *
+ *  Copyright (C) 2004 Nokia Corporation
+ *  Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
+ *  Misc hacks here and there by Tony Lindgren <tony@atomide.com>
+ *  Other hacks (DMA, SD, etc) 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+#include <asm/arch/tps65010.h>
+
+#define	OMAP_MMC_REG_CMD	0x00
+#define	OMAP_MMC_REG_ARGL	0x04
+#define	OMAP_MMC_REG_ARGH	0x08
+#define	OMAP_MMC_REG_CON	0x0c
+#define	OMAP_MMC_REG_STAT	0x10
+#define	OMAP_MMC_REG_IE		0x14
+#define	OMAP_MMC_REG_CTO	0x18
+#define	OMAP_MMC_REG_DTO	0x1c
+#define	OMAP_MMC_REG_DATA	0x20
+#define	OMAP_MMC_REG_BLEN	0x24
+#define	OMAP_MMC_REG_NBLK	0x28
+#define	OMAP_MMC_REG_BUF	0x2c
+#define OMAP_MMC_REG_SDIO	0x34
+#define	OMAP_MMC_REG_REV	0x3c
+#define	OMAP_MMC_REG_RSP0	0x40
+#define	OMAP_MMC_REG_RSP1	0x44
+#define	OMAP_MMC_REG_RSP2	0x48
+#define	OMAP_MMC_REG_RSP3	0x4c
+#define	OMAP_MMC_REG_RSP4	0x50
+#define	OMAP_MMC_REG_RSP5	0x54
+#define	OMAP_MMC_REG_RSP6	0x58
+#define	OMAP_MMC_REG_RSP7	0x5c
+#define	OMAP_MMC_REG_IOSR	0x60
+#define	OMAP_MMC_REG_SYSC	0x64
+#define	OMAP_MMC_REG_SYSS	0x68
+
+#define	OMAP_MMC_STAT_CARD_ERR		(1 << 14)
+#define	OMAP_MMC_STAT_CARD_IRQ		(1 << 13)
+#define	OMAP_MMC_STAT_OCR_BUSY		(1 << 12)
+#define	OMAP_MMC_STAT_A_EMPTY		(1 << 11)
+#define	OMAP_MMC_STAT_A_FULL		(1 << 10)
+#define	OMAP_MMC_STAT_CMD_CRC		(1 <<  8)
+#define	OMAP_MMC_STAT_CMD_TOUT		(1 <<  7)
+#define	OMAP_MMC_STAT_DATA_CRC		(1 <<  6)
+#define	OMAP_MMC_STAT_DATA_TOUT		(1 <<  5)
+#define	OMAP_MMC_STAT_END_BUSY		(1 <<  4)
+#define	OMAP_MMC_STAT_END_OF_DATA	(1 <<  3)
+#define	OMAP_MMC_STAT_CARD_BUSY		(1 <<  2)
+#define	OMAP_MMC_STAT_END_OF_CMD	(1 <<  0)
+
+#define OMAP_MMC_READ(host, reg)	__raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
+#define OMAP_MMC_WRITE(host, reg, val)	__raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
+
+/*
+ * Command types
+ */
+#define OMAP_MMC_CMDTYPE_BC	0
+#define OMAP_MMC_CMDTYPE_BCR	1
+#define OMAP_MMC_CMDTYPE_AC	2
+#define OMAP_MMC_CMDTYPE_ADTC	3
+
+
+#define DRIVER_NAME "mmci-omap"
+
+/* Specifies how often in millisecs to poll for card status changes
+ * when the cover switch is open */
+#define OMAP_MMC_SWITCH_POLL_DELAY	500
+
+static int mmc_omap_enable_poll = 1;
+
+struct mmc_omap_host {
+	int			initialized;
+	int			suspended;
+	struct mmc_request *	mrq;
+	struct mmc_command *	cmd;
+	struct mmc_data *	data;
+	struct mmc_host *	mmc;
+	struct device *		dev;
+	unsigned char		id; /* 16xx chips have 2 MMC blocks */
+	struct clk *		iclk;
+	struct clk *		fclk;
+	struct resource		*mem_res;
+	void __iomem		*virt_base;
+	unsigned int		phys_base;
+	int			irq;
+	unsigned char		bus_mode;
+	unsigned char		hw_bus_mode;
+
+	unsigned int		sg_len;
+	int			sg_idx;
+	u16 *			buffer;
+	u32			buffer_bytes_left;
+	u32			total_bytes_left;
+
+	unsigned		use_dma:1;
+	unsigned		brs_received:1, dma_done:1;
+	unsigned		dma_is_read:1;
+	unsigned		dma_in_use:1;
+	int			dma_ch;
+	spinlock_t		dma_lock;
+	struct timer_list	dma_timer;
+	unsigned		dma_len;
+
+	short			power_pin;
+	short			wp_pin;
+
+	int			switch_pin;
+	struct work_struct	switch_work;
+	struct timer_list	switch_timer;
+	int			switch_last_state;
+};
+
+static inline int
+mmc_omap_cover_is_open(struct mmc_omap_host *host)
+{
+	if (host->switch_pin < 0)
+		return 0;
+	return omap_get_gpio_datain(host->switch_pin);
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" :
+			"closed");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
+static ssize_t
+mmc_omap_show_enable_poll(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll);
+}
+
+static ssize_t
+mmc_omap_store_enable_poll(struct device *dev,
+	struct device_attribute *attr, const char *buf,
+	size_t size)
+{
+	int enable_poll;
+
+	if (sscanf(buf, "%10d", &enable_poll) != 1)
+		return -EINVAL;
+
+	if (enable_poll != mmc_omap_enable_poll) {
+		struct mmc_omap_host *host = dev_get_drvdata(dev);
+
+		mmc_omap_enable_poll = enable_poll;
+		if (enable_poll && host->switch_pin >= 0)
+			schedule_work(&host->switch_work);
+	}
+	return size;
+}
+
+static DEVICE_ATTR(enable_poll, 0664,
+		   mmc_omap_show_enable_poll, mmc_omap_store_enable_poll);
+
+static void
+mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+	u32 cmdreg;
+	u32 resptype;
+	u32 cmdtype;
+
+	host->cmd = cmd;
+
+	resptype = 0;
+	cmdtype = 0;
+
+	/* Our hardware needs to know exact type */
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		break;
+	case MMC_RSP_R1:
+	case MMC_RSP_R1B:
+		/* resp 1, 1b, 6, 7 */
+		resptype = 1;
+		break;
+	case MMC_RSP_R2:
+		resptype = 2;
+		break;
+	case MMC_RSP_R3:
+		resptype = 3;
+		break;
+	default:
+		dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
+		break;
+	}
+
+	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) {
+		cmdtype = OMAP_MMC_CMDTYPE_ADTC;
+	} else if (mmc_cmd_type(cmd) == MMC_CMD_BC) {
+		cmdtype = OMAP_MMC_CMDTYPE_BC;
+	} else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) {
+		cmdtype = OMAP_MMC_CMDTYPE_BCR;
+	} else {
+		cmdtype = OMAP_MMC_CMDTYPE_AC;
+	}
+
+	cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
+
+	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
+		cmdreg |= 1 << 6;
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		cmdreg |= 1 << 11;
+
+	if (host->data && !(host->data->flags & MMC_DATA_WRITE))
+		cmdreg |= 1 << 15;
+
+	clk_enable(host->fclk);
+
+	OMAP_MMC_WRITE(host, CTO, 200);
+	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
+	OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
+	OMAP_MMC_WRITE(host, IE,
+		       OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
+		       OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
+		       OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
+		       OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
+		       OMAP_MMC_STAT_END_OF_DATA);
+	OMAP_MMC_WRITE(host, CMD, cmdreg);
+}
+
+static void
+mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+	if (host->dma_in_use) {
+		enum dma_data_direction dma_data_dir;
+
+		BUG_ON(host->dma_ch < 0);
+		if (data->error != MMC_ERR_NONE)
+			omap_stop_dma(host->dma_ch);
+		/* Release DMA channel lazily */
+		mod_timer(&host->dma_timer, jiffies + HZ);
+		if (data->flags & MMC_DATA_WRITE)
+			dma_data_dir = DMA_TO_DEVICE;
+		else
+			dma_data_dir = DMA_FROM_DEVICE;
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
+			     dma_data_dir);
+	}
+	host->data = NULL;
+	host->sg_len = 0;
+	clk_disable(host->fclk);
+
+	/* NOTE:  MMC layer will sometimes poll-wait CMD13 next, issuing
+	 * dozens of requests until the card finishes writing data.
+	 * It'd be cheaper to just wait till an EOFB interrupt arrives...
+	 */
+
+	if (!data->stop) {
+		host->mrq = NULL;
+		mmc_request_done(host->mmc, data->mrq);
+		return;
+	}
+
+	mmc_omap_start_command(host, data->stop);
+}
+
+static void
+mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
+{
+	unsigned long flags;
+	int done;
+
+	if (!host->dma_in_use) {
+		mmc_omap_xfer_done(host, data);
+		return;
+	}
+	done = 0;
+	spin_lock_irqsave(&host->dma_lock, flags);
+	if (host->dma_done)
+		done = 1;
+	else
+		host->brs_received = 1;
+	spin_unlock_irqrestore(&host->dma_lock, flags);
+	if (done)
+		mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_dma_timer(unsigned long data)
+{
+	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+
+	BUG_ON(host->dma_ch < 0);
+	omap_free_dma(host->dma_ch);
+	host->dma_ch = -1;
+}
+
+static void
+mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+	unsigned long flags;
+	int done;
+
+	done = 0;
+	spin_lock_irqsave(&host->dma_lock, flags);
+	if (host->brs_received)
+		done = 1;
+	else
+		host->dma_done = 1;
+	spin_unlock_irqrestore(&host->dma_lock, flags);
+	if (done)
+		mmc_omap_xfer_done(host, data);
+}
+
+static void
+mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+	host->cmd = NULL;
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136) {
+			/* response type 2 */
+			cmd->resp[3] =
+				OMAP_MMC_READ(host, RSP0) |
+				(OMAP_MMC_READ(host, RSP1) << 16);
+			cmd->resp[2] =
+				OMAP_MMC_READ(host, RSP2) |
+				(OMAP_MMC_READ(host, RSP3) << 16);
+			cmd->resp[1] =
+				OMAP_MMC_READ(host, RSP4) |
+				(OMAP_MMC_READ(host, RSP5) << 16);
+			cmd->resp[0] =
+				OMAP_MMC_READ(host, RSP6) |
+				(OMAP_MMC_READ(host, RSP7) << 16);
+		} else {
+			/* response types 1, 1b, 3, 4, 5, 6 */
+			cmd->resp[0] =
+				OMAP_MMC_READ(host, RSP6) |
+				(OMAP_MMC_READ(host, RSP7) << 16);
+		}
+	}
+
+	if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+		host->mrq = NULL;
+		clk_disable(host->fclk);
+		mmc_request_done(host->mmc, cmd->mrq);
+	}
+}
+
+/* PIO only */
+static void
+mmc_omap_sg_to_buf(struct mmc_omap_host *host)
+{
+	struct scatterlist *sg;
+
+	sg = host->data->sg + host->sg_idx;
+	host->buffer_bytes_left = sg->length;
+	host->buffer = page_address(sg->page) + sg->offset;
+	if (host->buffer_bytes_left > host->total_bytes_left)
+		host->buffer_bytes_left = host->total_bytes_left;
+}
+
+/* PIO only */
+static void
+mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
+{
+	int n;
+
+	if (host->buffer_bytes_left == 0) {
+		host->sg_idx++;
+		BUG_ON(host->sg_idx == host->sg_len);
+		mmc_omap_sg_to_buf(host);
+	}
+	n = 64;
+	if (n > host->buffer_bytes_left)
+		n = host->buffer_bytes_left;
+	host->buffer_bytes_left -= n;
+	host->total_bytes_left -= n;
+	host->data->bytes_xfered += n;
+
+	if (write) {
+		__raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+	} else {
+		__raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+	}
+}
+
+static inline void mmc_omap_report_irq(u16 status)
+{
+	static const char *mmc_omap_status_bits[] = {
+		"EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
+		"CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
+	};
+	int i, c = 0;
+
+	for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
+		if (status & (1 << i)) {
+			if (c)
+				printk(" ");
+			printk("%s", mmc_omap_status_bits[i]);
+			c++;
+		}
+}
+
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+{
+	struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
+	u16 status;
+	int end_command;
+	int end_transfer;
+	int transfer_error;
+
+	if (host->cmd == NULL && host->data == NULL) {
+		status = OMAP_MMC_READ(host, STAT);
+		dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
+		if (status != 0) {
+			OMAP_MMC_WRITE(host, STAT, status);
+			OMAP_MMC_WRITE(host, IE, 0);
+		}
+		return IRQ_HANDLED;
+	}
+
+	end_command = 0;
+	end_transfer = 0;
+	transfer_error = 0;
+
+	while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
+		OMAP_MMC_WRITE(host, STAT, status);
+#ifdef CONFIG_MMC_DEBUG
+		dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
+			status, host->cmd != NULL ? host->cmd->opcode : -1);
+		mmc_omap_report_irq(status);
+		printk("\n");
+#endif
+		if (host->total_bytes_left) {
+			if ((status & OMAP_MMC_STAT_A_FULL) ||
+			    (status & OMAP_MMC_STAT_END_OF_DATA))
+				mmc_omap_xfer_data(host, 0);
+			if (status & OMAP_MMC_STAT_A_EMPTY)
+				mmc_omap_xfer_data(host, 1);
+		}
+
+		if (status & OMAP_MMC_STAT_END_OF_DATA) {
+			end_transfer = 1;
+		}
+
+		if (status & OMAP_MMC_STAT_DATA_TOUT) {
+			dev_dbg(mmc_dev(host->mmc), "data timeout\n");
+			if (host->data) {
+				host->data->error |= MMC_ERR_TIMEOUT;
+				transfer_error = 1;
+			}
+		}
+
+		if (status & OMAP_MMC_STAT_DATA_CRC) {
+			if (host->data) {
+				host->data->error |= MMC_ERR_BADCRC;
+				dev_dbg(mmc_dev(host->mmc),
+					 "data CRC error, bytes left %d\n",
+					host->total_bytes_left);
+				transfer_error = 1;
+			} else {
+				dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
+			}
+		}
+
+		if (status & OMAP_MMC_STAT_CMD_TOUT) {
+			/* Timeouts are routine with some commands */
+			if (host->cmd) {
+				if (host->cmd->opcode != MMC_ALL_SEND_CID &&
+						host->cmd->opcode !=
+						MMC_SEND_OP_COND &&
+						host->cmd->opcode !=
+						MMC_APP_CMD &&
+						!mmc_omap_cover_is_open(host))
+					dev_err(mmc_dev(host->mmc),
+						"command timeout, CMD %d\n",
+						host->cmd->opcode);
+				host->cmd->error = MMC_ERR_TIMEOUT;
+				end_command = 1;
+			}
+		}
+
+		if (status & OMAP_MMC_STAT_CMD_CRC) {
+			if (host->cmd) {
+				dev_err(mmc_dev(host->mmc),
+					"command CRC error (CMD%d, arg 0x%08x)\n",
+					host->cmd->opcode, host->cmd->arg);
+				host->cmd->error = MMC_ERR_BADCRC;
+				end_command = 1;
+			} else
+				dev_err(mmc_dev(host->mmc),
+					"command CRC error without cmd?\n");
+		}
+
+		if (status & OMAP_MMC_STAT_CARD_ERR) {
+			if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
+				u32 response = OMAP_MMC_READ(host, RSP6)
+					| (OMAP_MMC_READ(host, RSP7) << 16);
+				/* STOP sometimes sets must-ignore bits */
+				if (!(response & (R1_CC_ERROR
+								| R1_ILLEGAL_COMMAND
+								| R1_COM_CRC_ERROR))) {
+					end_command = 1;
+					continue;
+				}
+			}
+
+			dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n",
+				host->cmd->opcode);
+			if (host->cmd) {
+				host->cmd->error = MMC_ERR_FAILED;
+				end_command = 1;
+			}
+			if (host->data) {
+				host->data->error = MMC_ERR_FAILED;
+				transfer_error = 1;
+			}
+		}
+
+		/*
+		 * NOTE: On 1610 the END_OF_CMD may come too early when
+		 * starting a write 
+		 */
+		if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
+		    (!(status & OMAP_MMC_STAT_A_EMPTY))) {
+			end_command = 1;
+		}
+	}
+
+	if (end_command) {
+		mmc_omap_cmd_done(host, host->cmd);
+	}
+	if (transfer_error)
+		mmc_omap_xfer_done(host, host->data);
+	else if (end_transfer)
+		mmc_omap_end_of_data(host, host->data);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
+{
+	struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
+
+	schedule_work(&host->switch_work);
+
+	return IRQ_HANDLED;
+}
+
+static void mmc_omap_switch_timer(unsigned long arg)
+{
+	struct mmc_omap_host *host = (struct mmc_omap_host *) arg;
+
+	schedule_work(&host->switch_work);
+}
+
+static void mmc_omap_switch_handler(struct work_struct *work)
+{
+	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
+	struct mmc_card *card;
+	static int complained = 0;
+	int cards = 0, cover_open;
+
+	if (host->switch_pin == -1)
+		return;
+	cover_open = mmc_omap_cover_is_open(host);
+	if (cover_open != host->switch_last_state) {
+		kobject_uevent(&host->dev->kobj, KOBJ_CHANGE);
+		host->switch_last_state = cover_open;
+	}
+	mmc_detect_change(host->mmc, 0);
+	list_for_each_entry(card, &host->mmc->cards, node) {
+		if (mmc_card_present(card))
+			cards++;
+	}
+	if (mmc_omap_cover_is_open(host)) {
+		if (!complained) {
+			dev_info(mmc_dev(host->mmc), "cover is open\n");
+			complained = 1;
+		}
+		if (mmc_omap_enable_poll)
+			mod_timer(&host->switch_timer, jiffies +
+				msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY));
+	} else {
+		complained = 0;
+	}
+}
+
+/* Prepare to transfer the next segment of a scatterlist */
+static void
+mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
+{
+	int dma_ch = host->dma_ch;
+	unsigned long data_addr;
+	u16 buf, frame;
+	u32 count;
+	struct scatterlist *sg = &data->sg[host->sg_idx];
+	int src_port = 0;
+	int dst_port = 0;
+	int sync_dev = 0;
+
+	data_addr = host->phys_base + OMAP_MMC_REG_DATA;
+	frame = data->blksz;
+	count = sg_dma_len(sg);
+
+	if ((data->blocks == 1) && (count > data->blksz))
+		count = frame;
+
+	host->dma_len = count;
+
+	/* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
+	 * Use 16 or 32 word frames when the blocksize is at least that large.
+	 * Blocksize is usually 512 bytes; but not for some SD reads.
+	 */
+	if (cpu_is_omap15xx() && frame > 32)
+		frame = 32;
+	else if (frame > 64)
+		frame = 64;
+	count /= frame;
+	frame >>= 1;
+
+	if (!(data->flags & MMC_DATA_WRITE)) {
+		buf = 0x800f | ((frame - 1) << 8);
+
+		if (cpu_class_is_omap1()) {
+			src_port = OMAP_DMA_PORT_TIPB;
+			dst_port = OMAP_DMA_PORT_EMIFF;
+		}
+		if (cpu_is_omap24xx())
+			sync_dev = OMAP24XX_DMA_MMC1_RX;
+
+		omap_set_dma_src_params(dma_ch, src_port,
+					OMAP_DMA_AMODE_CONSTANT,
+					data_addr, 0, 0);
+		omap_set_dma_dest_params(dma_ch, dst_port,
+					 OMAP_DMA_AMODE_POST_INC,
+					 sg_dma_address(sg), 0, 0);
+		omap_set_dma_dest_data_pack(dma_ch, 1);
+		omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+	} else {
+		buf = 0x0f80 | ((frame - 1) << 0);
+
+		if (cpu_class_is_omap1()) {
+			src_port = OMAP_DMA_PORT_EMIFF;
+			dst_port = OMAP_DMA_PORT_TIPB;
+		}
+		if (cpu_is_omap24xx())
+			sync_dev = OMAP24XX_DMA_MMC1_TX;
+
+		omap_set_dma_dest_params(dma_ch, dst_port,
+					 OMAP_DMA_AMODE_CONSTANT,
+					 data_addr, 0, 0);
+		omap_set_dma_src_params(dma_ch, src_port,
+					OMAP_DMA_AMODE_POST_INC,
+					sg_dma_address(sg), 0, 0);
+		omap_set_dma_src_data_pack(dma_ch, 1);
+		omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+	}
+
+	/* Max limit for DMA frame count is 0xffff */
+	BUG_ON(count > 0xffff);
+
+	OMAP_MMC_WRITE(host, BUF, buf);
+	omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
+				     frame, count, OMAP_DMA_SYNC_FRAME,
+				     sync_dev, 0);
+}
+
+/* A scatterlist segment completed */
+static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
+	struct mmc_data *mmcdat = host->data;
+
+	if (unlikely(host->dma_ch < 0)) {
+		dev_err(mmc_dev(host->mmc),
+			"DMA callback while DMA not enabled\n");
+		return;
+	}
+	/* FIXME: We really should do something to _handle_ the errors */
+	if (ch_status & OMAP1_DMA_TOUT_IRQ) {
+		dev_err(mmc_dev(host->mmc),"DMA timeout\n");
+		return;
+	}
+	if (ch_status & OMAP_DMA_DROP_IRQ) {
+		dev_err(mmc_dev(host->mmc), "DMA sync error\n");
+		return;
+	}
+	if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
+		return;
+	}
+	mmcdat->bytes_xfered += host->dma_len;
+	host->sg_idx++;
+	if (host->sg_idx < host->sg_len) {
+		mmc_omap_prepare_dma(host, host->data);
+		omap_start_dma(host->dma_ch);
+	} else
+		mmc_omap_dma_done(host, host->data);
+}
+
+static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
+{
+	const char *dev_name;
+	int sync_dev, dma_ch, is_read, r;
+
+	is_read = !(data->flags & MMC_DATA_WRITE);
+	del_timer_sync(&host->dma_timer);
+	if (host->dma_ch >= 0) {
+		if (is_read == host->dma_is_read)
+			return 0;
+		omap_free_dma(host->dma_ch);
+		host->dma_ch = -1;
+	}
+
+	if (is_read) {
+		if (host->id == 1) {
+			sync_dev = OMAP_DMA_MMC_RX;
+			dev_name = "MMC1 read";
+		} else {
+			sync_dev = OMAP_DMA_MMC2_RX;
+			dev_name = "MMC2 read";
+		}
+	} else {
+		if (host->id == 1) {
+			sync_dev = OMAP_DMA_MMC_TX;
+			dev_name = "MMC1 write";
+		} else {
+			sync_dev = OMAP_DMA_MMC2_TX;
+			dev_name = "MMC2 write";
+		}
+	}
+	r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
+			     host, &dma_ch);
+	if (r != 0) {
+		dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
+		return r;
+	}
+	host->dma_ch = dma_ch;
+	host->dma_is_read = is_read;
+
+	return 0;
+}
+
+static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+	u16 reg;
+
+	reg = OMAP_MMC_READ(host, SDIO);
+	reg &= ~(1 << 5);
+	OMAP_MMC_WRITE(host, SDIO, reg);
+	/* Set maximum timeout */
+	OMAP_MMC_WRITE(host, CTO, 0xff);
+}
+
+static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
+{
+	int timeout;
+	u16 reg;
+
+	/* Convert ns to clock cycles by assuming 20MHz frequency
+	 * 1 cycle at 20MHz = 500 ns
+	 */
+	timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
+
+	/* Check if we need to use timeout multiplier register */
+	reg = OMAP_MMC_READ(host, SDIO);
+	if (timeout > 0xffff) {
+		reg |= (1 << 5);
+		timeout /= 1024;
+	} else
+		reg &= ~(1 << 5);
+	OMAP_MMC_WRITE(host, SDIO, reg);
+	OMAP_MMC_WRITE(host, DTO, timeout);
+}
+
+static void
+mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
+{
+	struct mmc_data *data = req->data;
+	int i, use_dma, block_size;
+	unsigned sg_len;
+
+	host->data = data;
+	if (data == NULL) {
+		OMAP_MMC_WRITE(host, BLEN, 0);
+		OMAP_MMC_WRITE(host, NBLK, 0);
+		OMAP_MMC_WRITE(host, BUF, 0);
+		host->dma_in_use = 0;
+		set_cmd_timeout(host, req);
+		return;
+	}
+
+	block_size = data->blksz;
+
+	OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
+	OMAP_MMC_WRITE(host, BLEN, block_size - 1);
+	set_data_timeout(host, req);
+
+	/* cope with calling layer confusion; it issues "single
+	 * block" writes using multi-block scatterlists.
+	 */
+	sg_len = (data->blocks == 1) ? 1 : data->sg_len;
+
+	/* Only do DMA for entire blocks */
+	use_dma = host->use_dma;
+	if (use_dma) {
+		for (i = 0; i < sg_len; i++) {
+			if ((data->sg[i].length % block_size) != 0) {
+				use_dma = 0;
+				break;
+			}
+		}
+	}
+
+	host->sg_idx = 0;
+	if (use_dma) {
+		if (mmc_omap_get_dma_channel(host, data) == 0) {
+			enum dma_data_direction dma_data_dir;
+
+			if (data->flags & MMC_DATA_WRITE)
+				dma_data_dir = DMA_TO_DEVICE;
+			else
+				dma_data_dir = DMA_FROM_DEVICE;
+
+			host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+						sg_len, dma_data_dir);
+			host->total_bytes_left = 0;
+			mmc_omap_prepare_dma(host, req->data);
+			host->brs_received = 0;
+			host->dma_done = 0;
+			host->dma_in_use = 1;
+		} else
+			use_dma = 0;
+	}
+
+	/* Revert to PIO? */
+	if (!use_dma) {
+		OMAP_MMC_WRITE(host, BUF, 0x1f1f);
+		host->total_bytes_left = data->blocks * block_size;
+		host->sg_len = sg_len;
+		mmc_omap_sg_to_buf(host);
+		host->dma_in_use = 0;
+	}
+}
+
+static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+	struct mmc_omap_host *host = mmc_priv(mmc);
+
+	WARN_ON(host->mrq != NULL);
+
+	host->mrq = req;
+
+	/* only touch fifo AFTER the controller readies it */
+	mmc_omap_prepare_data(host, req);
+	mmc_omap_start_command(host, req->cmd);
+	if (host->dma_in_use)
+		omap_start_dma(host->dma_ch);
+}
+
+static void innovator_fpga_socket_power(int on)
+{
+#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
+	if (on) {
+		fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
+		     OMAP1510_FPGA_POWER);
+	} else {
+		fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
+		     OMAP1510_FPGA_POWER);
+	}
+#endif
+}
+
+/*
+ * Turn the socket power on/off. Innovator uses FPGA, most boards
+ * probably use GPIO.
+ */
+static void mmc_omap_power(struct mmc_omap_host *host, int on)
+{
+	if (on) {
+		if (machine_is_omap_innovator())
+			innovator_fpga_socket_power(1);
+		else if (machine_is_omap_h2())
+			tps65010_set_gpio_out_value(GPIO3, HIGH);
+		else if (machine_is_omap_h3())
+			/* GPIO 4 of TPS65010 sends SD_EN signal */
+			tps65010_set_gpio_out_value(GPIO4, HIGH);
+		else if (cpu_is_omap24xx()) {
+			u16 reg = OMAP_MMC_READ(host, CON);
+			OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
+		} else
+			if (host->power_pin >= 0)
+				omap_set_gpio_dataout(host->power_pin, 1);
+	} else {
+		if (machine_is_omap_innovator())
+			innovator_fpga_socket_power(0);
+		else if (machine_is_omap_h2())
+			tps65010_set_gpio_out_value(GPIO3, LOW);
+		else if (machine_is_omap_h3())
+			tps65010_set_gpio_out_value(GPIO4, LOW);
+		else if (cpu_is_omap24xx()) {
+			u16 reg = OMAP_MMC_READ(host, CON);
+			OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
+		} else
+			if (host->power_pin >= 0)
+				omap_set_gpio_dataout(host->power_pin, 0);
+	}
+}
+
+static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct mmc_omap_host *host = mmc_priv(mmc);
+	int func_clk_rate = clk_get_rate(host->fclk);
+	int dsor;
+
+	if (ios->clock == 0)
+		return 0;
+
+	dsor = func_clk_rate / ios->clock;
+	if (dsor < 1)
+		dsor = 1;
+
+	if (func_clk_rate / dsor > ios->clock)
+		dsor++;
+
+	if (dsor > 250)
+		dsor = 250;
+	dsor++;
+
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		dsor |= 1 << 15;
+
+	return dsor;
+}
+
+static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct mmc_omap_host *host = mmc_priv(mmc);
+	int dsor;
+	int i;
+
+	dsor = mmc_omap_calc_divisor(mmc, ios);
+	host->bus_mode = ios->bus_mode;
+	host->hw_bus_mode = host->bus_mode;
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		mmc_omap_power(host, 0);
+		break;
+	case MMC_POWER_UP:
+		/* Cannot touch dsor yet, just power up MMC */
+		mmc_omap_power(host, 1);
+		return;
+	case MMC_POWER_ON:
+		dsor |= 1 << 11;
+		break;
+	}
+
+	clk_enable(host->fclk);
+
+	/* On insanely high arm_per frequencies something sometimes
+	 * goes somehow out of sync, and the POW bit is not being set,
+	 * which results in the while loop below getting stuck.
+	 * Writing to the CON register twice seems to do the trick. */
+	for (i = 0; i < 2; i++)
+		OMAP_MMC_WRITE(host, CON, dsor);
+	if (ios->power_mode == MMC_POWER_ON) {
+		/* Send clock cycles, poll completion */
+		OMAP_MMC_WRITE(host, IE, 0);
+		OMAP_MMC_WRITE(host, STAT, 0xffff);
+		OMAP_MMC_WRITE(host, CMD, 1 << 7);
+		while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
+		OMAP_MMC_WRITE(host, STAT, 1);
+	}
+	clk_disable(host->fclk);
+}
+
+static int mmc_omap_get_ro(struct mmc_host *mmc)
+{
+	struct mmc_omap_host *host = mmc_priv(mmc);
+
+	return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
+}
+
+static const struct mmc_host_ops mmc_omap_ops = {
+	.request	= mmc_omap_request,
+	.set_ios	= mmc_omap_set_ios,
+	.get_ro		= mmc_omap_get_ro,
+};
+
+static int __init mmc_omap_probe(struct platform_device *pdev)
+{
+	struct omap_mmc_conf *minfo = pdev->dev.platform_data;
+	struct mmc_host *mmc;
+	struct mmc_omap_host *host = NULL;
+	struct resource *res;
+	int ret = 0;
+	int irq;
+
+	if (minfo == NULL) {
+		dev_err(&pdev->dev, "platform data missing\n");
+		return -ENXIO;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (res == NULL || irq < 0)
+		return -ENXIO;
+
+	res = request_mem_region(res->start, res->end - res->start + 1,
+			         pdev->name);
+	if (res == NULL)
+		return -EBUSY;
+
+	mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
+	if (mmc == NULL) {
+		ret = -ENOMEM;
+		goto err_free_mem_region;
+	}
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+
+	spin_lock_init(&host->dma_lock);
+	init_timer(&host->dma_timer);
+	host->dma_timer.function = mmc_omap_dma_timer;
+	host->dma_timer.data = (unsigned long) host;
+
+	host->id = pdev->id;
+	host->mem_res = res;
+	host->irq = irq;
+
+	if (cpu_is_omap24xx()) {
+		host->iclk = clk_get(&pdev->dev, "mmc_ick");
+		if (IS_ERR(host->iclk))
+			goto err_free_mmc_host;
+		clk_enable(host->iclk);
+	}
+
+	if (!cpu_is_omap24xx())
+		host->fclk = clk_get(&pdev->dev, "mmc_ck");
+	else
+		host->fclk = clk_get(&pdev->dev, "mmc_fck");
+
+	if (IS_ERR(host->fclk)) {
+		ret = PTR_ERR(host->fclk);
+		goto err_free_iclk;
+	}
+
+	/* REVISIT:
+	 * Also, use minfo->cover to decide how to manage
+	 * the card detect sensing.
+	 */
+	host->power_pin = minfo->power_pin;
+	host->switch_pin = minfo->switch_pin;
+	host->wp_pin = minfo->wp_pin;
+	host->use_dma = 1;
+	host->dma_ch = -1;
+
+	host->irq = irq;
+	host->phys_base = host->mem_res->start;
+	host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
+
+	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_MULTIWRITE | 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
+	 * normally used (except e.g. for reading SD registers).
+	 */
+	mmc->max_phys_segs = 32;
+	mmc->max_hw_segs = 32;
+	mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */
+	mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */
+	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	if (host->power_pin >= 0) {
+		if ((ret = omap_request_gpio(host->power_pin)) != 0) {
+			dev_err(mmc_dev(host->mmc),
+				"Unable to get GPIO pin for MMC power\n");
+			goto err_free_fclk;
+		}
+		omap_set_gpio_direction(host->power_pin, 0);
+	}
+
+	ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
+	if (ret)
+		goto err_free_power_gpio;
+
+	host->dev = &pdev->dev;
+	platform_set_drvdata(pdev, host);
+
+	if (host->switch_pin >= 0) {
+		INIT_WORK(&host->switch_work, mmc_omap_switch_handler);
+		init_timer(&host->switch_timer);
+		host->switch_timer.function = mmc_omap_switch_timer;
+		host->switch_timer.data = (unsigned long) host;
+		if (omap_request_gpio(host->switch_pin) != 0) {
+			dev_warn(mmc_dev(host->mmc), "Unable to get GPIO pin for MMC cover switch\n");
+			host->switch_pin = -1;
+			goto no_switch;
+		}
+
+		omap_set_gpio_direction(host->switch_pin, 1);
+		ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
+				  mmc_omap_switch_irq, IRQF_TRIGGER_RISING, DRIVER_NAME, host);
+		if (ret) {
+			dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n");
+			omap_free_gpio(host->switch_pin);
+			host->switch_pin = -1;
+			goto no_switch;
+		}
+		ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
+		if (ret == 0) {
+			ret = device_create_file(&pdev->dev, &dev_attr_enable_poll);
+			if (ret != 0)
+				device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+		}
+		if (ret) {
+			dev_warn(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
+			free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+			omap_free_gpio(host->switch_pin);
+			host->switch_pin = -1;
+			goto no_switch;
+		}
+		if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host))
+			schedule_work(&host->switch_work);
+	}
+
+	mmc_add_host(mmc);
+
+	return 0;
+
+no_switch:
+	/* FIXME: Free other resources too. */
+	if (host) {
+		if (host->iclk && !IS_ERR(host->iclk))
+			clk_put(host->iclk);
+		if (host->fclk && !IS_ERR(host->fclk))
+			clk_put(host->fclk);
+		mmc_free_host(host->mmc);
+	}
+err_free_power_gpio:
+	if (host->power_pin >= 0)
+		omap_free_gpio(host->power_pin);
+err_free_fclk:
+	clk_put(host->fclk);
+err_free_iclk:
+	if (host->iclk != NULL) {
+		clk_disable(host->iclk);
+		clk_put(host->iclk);
+	}
+err_free_mmc_host:
+	mmc_free_host(host->mmc);
+err_free_mem_region:
+	release_mem_region(res->start, res->end - res->start + 1);
+	return ret;
+}
+
+static int mmc_omap_remove(struct platform_device *pdev)
+{
+	struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	BUG_ON(host == NULL);
+
+	mmc_remove_host(host->mmc);
+	free_irq(host->irq, host);
+
+	if (host->power_pin >= 0)
+		omap_free_gpio(host->power_pin);
+	if (host->switch_pin >= 0) {
+		device_remove_file(&pdev->dev, &dev_attr_enable_poll);
+		device_remove_file(&pdev->dev, &dev_attr_cover_switch);
+		free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
+		omap_free_gpio(host->switch_pin);
+		host->switch_pin = -1;
+		del_timer_sync(&host->switch_timer);
+		flush_scheduled_work();
+	}
+	if (host->iclk && !IS_ERR(host->iclk))
+		clk_put(host->iclk);
+	if (host->fclk && !IS_ERR(host->fclk))
+		clk_put(host->fclk);
+
+	release_mem_region(pdev->resource[0].start,
+			   pdev->resource[0].end - pdev->resource[0].start + 1);
+
+	mmc_free_host(host->mmc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	int ret = 0;
+	struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+	if (host && host->suspended)
+		return 0;
+
+	if (host) {
+		ret = mmc_suspend_host(host->mmc, mesg);
+		if (ret == 0)
+			host->suspended = 1;
+	}
+	return ret;
+}
+
+static int mmc_omap_resume(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+	if (host && !host->suspended)
+		return 0;
+
+	if (host) {
+		ret = mmc_resume_host(host->mmc);
+		if (ret == 0)
+			host->suspended = 0;
+	}
+
+	return ret;
+}
+#else
+#define mmc_omap_suspend	NULL
+#define mmc_omap_resume		NULL
+#endif
+
+static struct platform_driver mmc_omap_driver = {
+	.probe		= mmc_omap_probe,
+	.remove		= mmc_omap_remove,
+	.suspend	= mmc_omap_suspend,
+	.resume		= mmc_omap_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init mmc_omap_init(void)
+{
+	return platform_driver_register(&mmc_omap_driver);
+}
+
+static void __exit mmc_omap_exit(void)
+{
+	platform_driver_unregister(&mmc_omap_driver);
+}
+
+module_init(mmc_omap_init);
+module_exit(mmc_omap_exit);
+
+MODULE_DESCRIPTION("OMAP Multimedia Card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Juha Yrjölä");
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
new file mode 100644
index 0000000..d97d386
--- /dev/null
+++ b/drivers/mmc/host/pxamci.c
@@ -0,0 +1,616 @@
+/*
+ *  linux/drivers/mmc/pxa.c - PXA MMCI driver
+ *
+ *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This hardware is really sick:
+ *   - No way to clear interrupts.
+ *   - Have to turn off the clock whenever we touch the device.
+ *   - Doesn't tell you how many data blocks were transferred.
+ *  Yuck!
+ *
+ *	1 and 3 byte data transfers not supported
+ *	max block length up to 1023
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mmc.h>
+
+#include "pxamci.h"
+
+#define DRIVER_NAME	"pxa2xx-mci"
+
+#define NR_SG	1
+
+struct pxamci_host {
+	struct mmc_host		*mmc;
+	spinlock_t		lock;
+	struct resource		*res;
+	void __iomem		*base;
+	int			irq;
+	int			dma;
+	unsigned int		clkrt;
+	unsigned int		cmdat;
+	unsigned int		imask;
+	unsigned int		power_mode;
+	struct pxamci_platform_data *pdata;
+
+	struct mmc_request	*mrq;
+	struct mmc_command	*cmd;
+	struct mmc_data		*data;
+
+	dma_addr_t		sg_dma;
+	struct pxa_dma_desc	*sg_cpu;
+	unsigned int		dma_len;
+
+	unsigned int		dma_dir;
+};
+
+static void pxamci_stop_clock(struct pxamci_host *host)
+{
+	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
+		unsigned long timeout = 10000;
+		unsigned int v;
+
+		writel(STOP_CLOCK, host->base + MMC_STRPCL);
+
+		do {
+			v = readl(host->base + MMC_STAT);
+			if (!(v & STAT_CLK_EN))
+				break;
+			udelay(1);
+		} while (timeout--);
+
+		if (v & STAT_CLK_EN)
+			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
+	}
+}
+
+static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->imask &= ~mask;
+	writel(host->imask, host->base + MMC_I_MASK);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->imask |= mask;
+	writel(host->imask, host->base + MMC_I_MASK);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
+{
+	unsigned int nob = data->blocks;
+	unsigned long long clks;
+	unsigned int timeout;
+	u32 dcmd;
+	int i;
+
+	host->data = data;
+
+	if (data->flags & MMC_DATA_STREAM)
+		nob = 0xffff;
+
+	writel(nob, host->base + MMC_NOB);
+	writel(data->blksz, host->base + MMC_BLKLEN);
+
+	clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+	do_div(clks, 1000000000UL);
+	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
+	writel((timeout + 255) / 256, host->base + MMC_RDTO);
+
+	if (data->flags & MMC_DATA_READ) {
+		host->dma_dir = DMA_FROM_DEVICE;
+		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+		DRCMRTXMMC = 0;
+		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
+	} else {
+		host->dma_dir = DMA_TO_DEVICE;
+		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+		DRCMRRXMMC = 0;
+		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
+	}
+
+	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
+
+	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+				   host->dma_dir);
+
+	for (i = 0; i < host->dma_len; i++) {
+		if (data->flags & MMC_DATA_READ) {
+			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
+			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
+		} else {
+			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
+			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
+		}
+		host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
+		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
+					sizeof(struct pxa_dma_desc);
+	}
+	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
+	wmb();
+
+	DDADR(host->dma) = host->sg_dma;
+	DCSR(host->dma) = DCSR_RUN;
+}
+
+static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
+{
+	WARN_ON(host->cmd != NULL);
+	host->cmd = cmd;
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		cmdat |= CMDAT_BUSY;
+
+#define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+	switch (RSP_TYPE(mmc_resp_type(cmd))) {
+	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
+		cmdat |= CMDAT_RESP_SHORT;
+		break;
+	case RSP_TYPE(MMC_RSP_R3):
+		cmdat |= CMDAT_RESP_R3;
+		break;
+	case RSP_TYPE(MMC_RSP_R2):
+		cmdat |= CMDAT_RESP_R2;
+		break;
+	default:
+		break;
+	}
+
+	writel(cmd->opcode, host->base + MMC_CMD);
+	writel(cmd->arg >> 16, host->base + MMC_ARGH);
+	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
+	writel(cmdat, host->base + MMC_CMDAT);
+	writel(host->clkrt, host->base + MMC_CLKRT);
+
+	writel(START_CLOCK, host->base + MMC_STRPCL);
+
+	pxamci_enable_irq(host, END_CMD_RES);
+}
+
+static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
+{
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+	mmc_request_done(host->mmc, mrq);
+}
+
+static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
+{
+	struct mmc_command *cmd = host->cmd;
+	int i;
+	u32 v;
+
+	if (!cmd)
+		return 0;
+
+	host->cmd = NULL;
+
+	/*
+	 * Did I mention this is Sick.  We always need to
+	 * discard the upper 8 bits of the first 16-bit word.
+	 */
+	v = readl(host->base + MMC_RES) & 0xffff;
+	for (i = 0; i < 4; i++) {
+		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
+		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
+		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
+		v = w2;
+	}
+
+	if (stat & STAT_TIME_OUT_RESPONSE) {
+		cmd->error = MMC_ERR_TIMEOUT;
+	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
+#ifdef CONFIG_PXA27x
+		/*
+		 * workaround for erratum #42:
+		 * Intel PXA27x Family Processor Specification Update Rev 001
+		 */
+		if (cmd->opcode == MMC_ALL_SEND_CID ||
+		    cmd->opcode == MMC_SEND_CSD ||
+		    cmd->opcode == MMC_SEND_CID) {
+			/* a bogus CRC error can appear if the msb of
+			   the 15 byte response is a one */
+			if ((cmd->resp[0] & 0x80000000) == 0)
+				cmd->error = MMC_ERR_BADCRC;
+		} else {
+			pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode);
+		}
+#else
+		cmd->error = MMC_ERR_BADCRC;
+#endif
+	}
+
+	pxamci_disable_irq(host, END_CMD_RES);
+	if (host->data && cmd->error == MMC_ERR_NONE) {
+		pxamci_enable_irq(host, DATA_TRAN_DONE);
+	} else {
+		pxamci_finish_request(host, host->mrq);
+	}
+
+	return 1;
+}
+
+static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
+{
+	struct mmc_data *data = host->data;
+
+	if (!data)
+		return 0;
+
+	DCSR(host->dma) = 0;
+	dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+		     host->dma_dir);
+
+	if (stat & STAT_READ_TIME_OUT)
+		data->error = MMC_ERR_TIMEOUT;
+	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
+		data->error = MMC_ERR_BADCRC;
+
+	/*
+	 * There appears to be a hardware design bug here.  There seems to
+	 * be no way to find out how much data was transferred to the card.
+	 * This means that if there was an error on any block, we mark all
+	 * data blocks as being in error.
+	 */
+	if (data->error == MMC_ERR_NONE)
+		data->bytes_xfered = data->blocks * data->blksz;
+	else
+		data->bytes_xfered = 0;
+
+	pxamci_disable_irq(host, DATA_TRAN_DONE);
+
+	host->data = NULL;
+	if (host->mrq->stop) {
+		pxamci_stop_clock(host);
+		pxamci_start_cmd(host, host->mrq->stop, 0);
+	} else {
+		pxamci_finish_request(host, host->mrq);
+	}
+
+	return 1;
+}
+
+static irqreturn_t pxamci_irq(int irq, void *devid)
+{
+	struct pxamci_host *host = devid;
+	unsigned int ireg;
+	int handled = 0;
+
+	ireg = readl(host->base + MMC_I_REG);
+
+	if (ireg) {
+		unsigned stat = readl(host->base + MMC_STAT);
+
+		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
+
+		if (ireg & END_CMD_RES)
+			handled |= pxamci_cmd_done(host, stat);
+		if (ireg & DATA_TRAN_DONE)
+			handled |= pxamci_data_done(host, stat);
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct pxamci_host *host = mmc_priv(mmc);
+	unsigned int cmdat;
+
+	WARN_ON(host->mrq != NULL);
+
+	host->mrq = mrq;
+
+	pxamci_stop_clock(host);
+
+	cmdat = host->cmdat;
+	host->cmdat &= ~CMDAT_INIT;
+
+	if (mrq->data) {
+		pxamci_setup_data(host, mrq->data);
+
+		cmdat &= ~CMDAT_BUSY;
+		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
+		if (mrq->data->flags & MMC_DATA_WRITE)
+			cmdat |= CMDAT_WRITE;
+
+		if (mrq->data->flags & MMC_DATA_STREAM)
+			cmdat |= CMDAT_STREAM;
+	}
+
+	pxamci_start_cmd(host, mrq->cmd, cmdat);
+}
+
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+	struct pxamci_host *host = mmc_priv(mmc);
+
+	if (host->pdata && host->pdata->get_ro)
+		return host->pdata->get_ro(mmc_dev(mmc));
+	/* Host doesn't support read only detection so assume writeable */
+	return 0;
+}
+
+static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct pxamci_host *host = mmc_priv(mmc);
+
+	if (ios->clock) {
+		unsigned int clk = CLOCKRATE / ios->clock;
+		if (CLOCKRATE / clk > ios->clock)
+			clk <<= 1;
+		host->clkrt = fls(clk) - 1;
+		pxa_set_cken(CKEN_MMC, 1);
+
+		/*
+		 * we write clkrt on the next command
+		 */
+	} else {
+		pxamci_stop_clock(host);
+		pxa_set_cken(CKEN_MMC, 0);
+	}
+
+	if (host->power_mode != ios->power_mode) {
+		host->power_mode = ios->power_mode;
+
+		if (host->pdata && host->pdata->setpower)
+			host->pdata->setpower(mmc_dev(mmc), ios->vdd);
+
+		if (ios->power_mode == MMC_POWER_ON)
+			host->cmdat |= CMDAT_INIT;
+	}
+
+	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
+		 host->clkrt, host->cmdat);
+}
+
+static const struct mmc_host_ops pxamci_ops = {
+	.request	= pxamci_request,
+	.get_ro		= pxamci_get_ro,
+	.set_ios	= pxamci_set_ios,
+};
+
+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 pxamci_host *host = mmc_priv(devid);
+
+	mmc_detect_change(devid, host->pdata->detect_delay);
+	return IRQ_HANDLED;
+}
+
+static int pxamci_probe(struct platform_device *pdev)
+{
+	struct mmc_host *mmc;
+	struct pxamci_host *host = NULL;
+	struct resource *r;
+	int ret, irq;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!r || irq < 0)
+		return -ENXIO;
+
+	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
+	if (!r)
+		return -EBUSY;
+
+	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
+	if (!mmc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mmc->ops = &pxamci_ops;
+	mmc->f_min = CLOCKRATE_MIN;
+	mmc->f_max = CLOCKRATE_MAX;
+
+	/*
+	 * We can do SG-DMA, but we don't because we never know how much
+	 * data we successfully wrote to the card.
+	 */
+	mmc->max_phys_segs = NR_SG;
+
+	/*
+	 * Our hardware DMA can handle a maximum of one page per SG entry.
+	 */
+	mmc->max_seg_size = PAGE_SIZE;
+
+	/*
+	 * Block length register is 10 bits.
+	 */
+	mmc->max_blk_size = 1023;
+
+	/*
+	 * Block count register is 16 bits.
+	 */
+	mmc->max_blk_count = 65535;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->dma = -1;
+	host->pdata = pdev->dev.platform_data;
+	mmc->ocr_avail = host->pdata ?
+			 host->pdata->ocr_mask :
+			 MMC_VDD_32_33|MMC_VDD_33_34;
+
+	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
+	if (!host->sg_cpu) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	spin_lock_init(&host->lock);
+	host->res = r;
+	host->irq = irq;
+	host->imask = MMC_I_MASK_ALL;
+
+	host->base = ioremap(r->start, SZ_4K);
+	if (!host->base) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Ensure that the host controller is shut down, and setup
+	 * with our defaults.
+	 */
+	pxamci_stop_clock(host);
+	writel(0, host->base + MMC_SPI);
+	writel(64, host->base + MMC_RESTO);
+	writel(host->imask, host->base + MMC_I_MASK);
+
+	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
+				    pxamci_dma_irq, host);
+	if (host->dma < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
+	if (ret)
+		goto out;
+
+	platform_set_drvdata(pdev, mmc);
+
+	if (host->pdata && host->pdata->init)
+		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
+
+	mmc_add_host(mmc);
+
+	return 0;
+
+ out:
+	if (host) {
+		if (host->dma >= 0)
+			pxa_free_dma(host->dma);
+		if (host->base)
+			iounmap(host->base);
+		if (host->sg_cpu)
+			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	}
+	if (mmc)
+		mmc_free_host(mmc);
+	release_resource(r);
+	return ret;
+}
+
+static int pxamci_remove(struct platform_device *pdev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (mmc) {
+		struct pxamci_host *host = mmc_priv(mmc);
+
+		if (host->pdata && host->pdata->exit)
+			host->pdata->exit(&pdev->dev, mmc);
+
+		mmc_remove_host(mmc);
+
+		pxamci_stop_clock(host);
+		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+		       host->base + MMC_I_MASK);
+
+		DRCMRRXMMC = 0;
+		DRCMRTXMMC = 0;
+
+		free_irq(host->irq, host);
+		pxa_free_dma(host->dma);
+		iounmap(host->base);
+		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+
+		release_resource(host->res);
+
+		mmc_free_host(mmc);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	int ret = 0;
+
+	if (mmc)
+		ret = mmc_suspend_host(mmc, state);
+
+	return ret;
+}
+
+static int pxamci_resume(struct platform_device *dev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	int ret = 0;
+
+	if (mmc)
+		ret = mmc_resume_host(mmc);
+
+	return ret;
+}
+#else
+#define pxamci_suspend	NULL
+#define pxamci_resume	NULL
+#endif
+
+static struct platform_driver pxamci_driver = {
+	.probe		= pxamci_probe,
+	.remove		= pxamci_remove,
+	.suspend	= pxamci_suspend,
+	.resume		= pxamci_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init pxamci_init(void)
+{
+	return platform_driver_register(&pxamci_driver);
+}
+
+static void __exit pxamci_exit(void)
+{
+	platform_driver_unregister(&pxamci_driver);
+}
+
+module_init(pxamci_init);
+module_exit(pxamci_exit);
+
+MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
new file mode 100644
index 0000000..1b16322
--- /dev/null
+++ b/drivers/mmc/host/pxamci.h
@@ -0,0 +1,124 @@
+#undef MMC_STRPCL
+#undef MMC_STAT
+#undef MMC_CLKRT
+#undef MMC_SPI
+#undef MMC_CMDAT
+#undef MMC_RESTO
+#undef MMC_RDTO
+#undef MMC_BLKLEN
+#undef MMC_NOB
+#undef MMC_PRTBUF
+#undef MMC_I_MASK
+#undef END_CMD_RES
+#undef PRG_DONE
+#undef DATA_TRAN_DONE
+#undef MMC_I_REG
+#undef MMC_CMD
+#undef MMC_ARGH
+#undef MMC_ARGL
+#undef MMC_RES
+#undef MMC_RXFIFO
+#undef MMC_TXFIFO
+
+#define MMC_STRPCL	0x0000
+#define STOP_CLOCK		(1 << 0)
+#define START_CLOCK		(2 << 0)
+
+#define MMC_STAT	0x0004
+#define STAT_END_CMD_RES		(1 << 13)
+#define STAT_PRG_DONE			(1 << 12)
+#define STAT_DATA_TRAN_DONE		(1 << 11)
+#define STAT_CLK_EN			(1 << 8)
+#define STAT_RECV_FIFO_FULL		(1 << 7)
+#define STAT_XMIT_FIFO_EMPTY		(1 << 6)
+#define STAT_RES_CRC_ERR		(1 << 5)
+#define STAT_SPI_READ_ERROR_TOKEN	(1 << 4)
+#define STAT_CRC_READ_ERROR		(1 << 3)
+#define STAT_CRC_WRITE_ERROR		(1 << 2)
+#define STAT_TIME_OUT_RESPONSE		(1 << 1)
+#define STAT_READ_TIME_OUT		(1 << 0)
+
+#define MMC_CLKRT	0x0008		/* 3 bit */
+
+#define MMC_SPI		0x000c
+#define SPI_CS_ADDRESS		(1 << 3)
+#define SPI_CS_EN		(1 << 2)
+#define CRC_ON			(1 << 1)
+#define SPI_EN			(1 << 0)
+
+#define MMC_CMDAT	0x0010
+#define CMDAT_DMAEN		(1 << 7)
+#define CMDAT_INIT		(1 << 6)
+#define CMDAT_BUSY		(1 << 5)
+#define CMDAT_STREAM		(1 << 4)	/* 1 = stream */
+#define CMDAT_WRITE		(1 << 3)	/* 1 = write */
+#define CMDAT_DATAEN		(1 << 2)
+#define CMDAT_RESP_NONE		(0 << 0)
+#define CMDAT_RESP_SHORT	(1 << 0)
+#define CMDAT_RESP_R2		(2 << 0)
+#define CMDAT_RESP_R3		(3 << 0)
+
+#define MMC_RESTO	0x0014	/* 7 bit */
+
+#define MMC_RDTO	0x0018	/* 16 bit */
+
+#define MMC_BLKLEN	0x001c	/* 10 bit */
+
+#define MMC_NOB		0x0020	/* 16 bit */
+
+#define MMC_PRTBUF	0x0024
+#define BUF_PART_FULL		(1 << 0)
+
+#define MMC_I_MASK	0x0028
+
+/*PXA27x MMC interrupts*/
+#define SDIO_SUSPEND_ACK  	(1 << 12)
+#define SDIO_INT          	(1 << 11)
+#define RD_STALLED        	(1 << 10)
+#define RES_ERR           	(1 << 9)
+#define DAT_ERR           	(1 << 8)
+#define TINT              	(1 << 7)
+
+/*PXA2xx MMC interrupts*/
+#define TXFIFO_WR_REQ		(1 << 6)
+#define RXFIFO_RD_REQ		(1 << 5)
+#define CLK_IS_OFF		(1 << 4)
+#define STOP_CMD		(1 << 3)
+#define END_CMD_RES		(1 << 2)
+#define PRG_DONE		(1 << 1)
+#define DATA_TRAN_DONE		(1 << 0)
+
+#ifdef CONFIG_PXA27x
+#define MMC_I_MASK_ALL          0x00001fff
+#else
+#define MMC_I_MASK_ALL          0x0000007f
+#endif
+
+#define MMC_I_REG	0x002c
+/* same as MMC_I_MASK */
+
+#define MMC_CMD		0x0030
+
+#define MMC_ARGH	0x0034	/* 16 bit */
+
+#define MMC_ARGL	0x0038	/* 16 bit */
+
+#define MMC_RES		0x003c	/* 16 bit */
+
+#define MMC_RXFIFO	0x0040	/* 8 bit */
+
+#define MMC_TXFIFO	0x0044	/* 8 bit */
+
+/*
+ * The base MMC clock rate
+ */
+#ifdef CONFIG_PXA27x
+#define CLOCKRATE_MIN	304688
+#define CLOCKRATE_MAX	19500000
+#else
+#define CLOCKRATE_MIN	312500
+#define CLOCKRATE_MAX	20000000
+#endif
+
+#define CLOCKRATE	CLOCKRATE_MAX
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
new file mode 100644
index 0000000..ff5bf73
--- /dev/null
+++ b/drivers/mmc/host/sdhci.c
@@ -0,0 +1,1535 @@
+/*
+ *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005-2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/scatterlist.h>
+
+#include "sdhci.h"
+
+#define DRIVER_NAME "sdhci"
+
+#define DBG(f, x...) \
+	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+
+static unsigned int debug_nodma = 0;
+static unsigned int debug_forcedma = 0;
+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)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_VENDOR_ID_IBM,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+				  SDHCI_QUIRK_FORCE_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
+				  SDHCI_QUIRK_NO_CARD_NO_RESET,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_TI,
+		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
+	},
+
+	{	/* Generic SD host controller */
+		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+	},
+
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
+static void sdhci_finish_data(struct sdhci_host *);
+
+static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
+static void sdhci_finish_command(struct sdhci_host *);
+
+static void sdhci_dumpregs(struct sdhci_host *host)
+{
+	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+
+	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
+		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
+		readw(host->ioaddr + SDHCI_HOST_VERSION));
+	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
+		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
+	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_ARGUMENT),
+		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
+	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_PRESENT_STATE),
+		readb(host->ioaddr + SDHCI_HOST_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
+		readb(host->ioaddr + SDHCI_POWER_CONTROL),
+		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
+		readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
+	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
+		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
+		readl(host->ioaddr + SDHCI_INT_STATUS));
+	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_INT_ENABLE),
+		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
+	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
+		readw(host->ioaddr + SDHCI_ACMD12_ERR),
+		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
+	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
+		readl(host->ioaddr + SDHCI_CAPABILITIES),
+		readl(host->ioaddr + SDHCI_MAX_CURRENT));
+
+	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Low level functions                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	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)
+		host->clock = 0;
+
+	/* Wait max 100 ms */
+	timeout = 100;
+
+	/* hw clears the bit when it's done */
+	while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
+		if (timeout == 0) {
+			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
+				mmc_hostname(host->mmc), (int)mask);
+			sdhci_dumpregs(host);
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+}
+
+static void sdhci_init(struct sdhci_host *host)
+{
+	u32 intmask;
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
+		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
+		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
+		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
+		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
+
+	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
+	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_activate_led(struct sdhci_host *host)
+{
+	u8 ctrl;
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+	ctrl |= SDHCI_CTRL_LED;
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+static void sdhci_deactivate_led(struct sdhci_host *host)
+{
+	u8 ctrl;
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+	ctrl &= ~SDHCI_CTRL_LED;
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Core functions                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
+{
+	return page_address(host->cur_sg->page) + host->cur_sg->offset;
+}
+
+static inline int sdhci_next_sg(struct sdhci_host* host)
+{
+	/*
+	 * Skip to next SG entry.
+	 */
+	host->cur_sg++;
+	host->num_sg--;
+
+	/*
+	 * Any entries left?
+	 */
+	if (host->num_sg > 0) {
+		host->offset = 0;
+		host->remain = host->cur_sg->length;
+	}
+
+	return host->num_sg;
+}
+
+static void sdhci_read_block_pio(struct sdhci_host *host)
+{
+	int blksize, chunk_remain;
+	u32 data;
+	char *buffer;
+	int size;
+
+	DBG("PIO reading\n");
+
+	blksize = host->data->blksz;
+	chunk_remain = 0;
+	data = 0;
+
+	buffer = sdhci_sg_to_buffer(host) + host->offset;
+
+	while (blksize) {
+		if (chunk_remain == 0) {
+			data = readl(host->ioaddr + SDHCI_BUFFER);
+			chunk_remain = min(blksize, 4);
+		}
+
+		size = min(host->remain, chunk_remain);
+
+		chunk_remain -= size;
+		blksize -= size;
+		host->offset += size;
+		host->remain -= size;
+
+		while (size) {
+			*buffer = data & 0xFF;
+			buffer++;
+			data >>= 8;
+			size--;
+		}
+
+		if (host->remain == 0) {
+			if (sdhci_next_sg(host) == 0) {
+				BUG_ON(blksize != 0);
+				return;
+			}
+			buffer = sdhci_sg_to_buffer(host);
+		}
+	}
+}
+
+static void sdhci_write_block_pio(struct sdhci_host *host)
+{
+	int blksize, chunk_remain;
+	u32 data;
+	char *buffer;
+	int bytes, size;
+
+	DBG("PIO writing\n");
+
+	blksize = host->data->blksz;
+	chunk_remain = 4;
+	data = 0;
+
+	bytes = 0;
+	buffer = sdhci_sg_to_buffer(host) + host->offset;
+
+	while (blksize) {
+		size = min(host->remain, chunk_remain);
+
+		chunk_remain -= size;
+		blksize -= size;
+		host->offset += size;
+		host->remain -= size;
+
+		while (size) {
+			data >>= 8;
+			data |= (u32)*buffer << 24;
+			buffer++;
+			size--;
+		}
+
+		if (chunk_remain == 0) {
+			writel(data, host->ioaddr + SDHCI_BUFFER);
+			chunk_remain = min(blksize, 4);
+		}
+
+		if (host->remain == 0) {
+			if (sdhci_next_sg(host) == 0) {
+				BUG_ON(blksize != 0);
+				return;
+			}
+			buffer = sdhci_sg_to_buffer(host);
+		}
+	}
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host)
+{
+	u32 mask;
+
+	BUG_ON(!host->data);
+
+	if (host->num_sg == 0)
+		return;
+
+	if (host->data->flags & MMC_DATA_READ)
+		mask = SDHCI_DATA_AVAILABLE;
+	else
+		mask = SDHCI_SPACE_AVAILABLE;
+
+	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+		if (host->data->flags & MMC_DATA_READ)
+			sdhci_read_block_pio(host);
+		else
+			sdhci_write_block_pio(host);
+
+		if (host->num_sg == 0)
+			break;
+	}
+
+	DBG("PIO transfer complete.\n");
+}
+
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+{
+	u8 count;
+	unsigned target_timeout, current_timeout;
+
+	WARN_ON(host->data);
+
+	if (data == NULL)
+		return;
+
+	DBG("blksz %04x blks %04x flags %08x\n",
+		data->blksz, data->blocks, data->flags);
+	DBG("tsac %d ms nsac %d clk\n",
+		data->timeout_ns / 1000000, data->timeout_clks);
+
+	/* Sanity checks */
+	BUG_ON(data->blksz * data->blocks > 524288);
+	BUG_ON(data->blksz > host->mmc->max_blk_size);
+	BUG_ON(data->blocks > 65535);
+
+	/* timeout in us */
+	target_timeout = data->timeout_ns / 1000 +
+		data->timeout_clks / host->clock;
+
+	/*
+	 * Figure out needed cycles.
+	 * We do this in steps in order to fit inside a 32 bit int.
+	 * The first step is the minimum timeout, which will have a
+	 * minimum resolution of 6 bits:
+	 * (1) 2^13*1000 > 2^22,
+	 * (2) host->timeout_clk < 2^16
+	 *     =>
+	 *     (1) / (2) > 2^6
+	 */
+	count = 0;
+	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+	while (current_timeout < target_timeout) {
+		count++;
+		current_timeout <<= 1;
+		if (count >= 0xF)
+			break;
+	}
+
+	if (count >= 0xF) {
+		printk(KERN_WARNING "%s: Too large timeout requested!\n",
+			mmc_hostname(host->mmc));
+		count = 0xE;
+	}
+
+	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
+
+	if (host->flags & SDHCI_USE_DMA) {
+		int count;
+
+		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
+			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+		BUG_ON(count != 1);
+
+		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
+	} else {
+		host->cur_sg = data->sg;
+		host->num_sg = data->sg_len;
+
+		host->offset = 0;
+		host->remain = host->cur_sg->length;
+	}
+
+	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
+	writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
+		host->ioaddr + SDHCI_BLOCK_SIZE);
+	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+}
+
+static void sdhci_set_transfer_mode(struct sdhci_host *host,
+	struct mmc_data *data)
+{
+	u16 mode;
+
+	WARN_ON(host->data);
+
+	if (data == NULL)
+		return;
+
+	mode = SDHCI_TRNS_BLK_CNT_EN;
+	if (data->blocks > 1)
+		mode |= SDHCI_TRNS_MULTI;
+	if (data->flags & MMC_DATA_READ)
+		mode |= SDHCI_TRNS_READ;
+	if (host->flags & SDHCI_USE_DMA)
+		mode |= SDHCI_TRNS_DMA;
+
+	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
+}
+
+static void sdhci_finish_data(struct sdhci_host *host)
+{
+	struct mmc_data *data;
+	u16 blocks;
+
+	BUG_ON(!host->data);
+
+	data = host->data;
+	host->data = NULL;
+
+	if (host->flags & SDHCI_USE_DMA) {
+		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
+			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+	}
+
+	/*
+	 * Controller doesn't count down when in single block mode.
+	 */
+	if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
+		blocks = 0;
+	else
+		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
+	data->bytes_xfered = data->blksz * (data->blocks - blocks);
+
+	if ((data->error == MMC_ERR_NONE) && blocks) {
+		printk(KERN_ERR "%s: Controller signalled completion even "
+			"though there were blocks left.\n",
+			mmc_hostname(host->mmc));
+		data->error = MMC_ERR_FAILED;
+	}
+
+	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+
+	if (data->stop) {
+		/*
+		 * The controller needs a reset of internal state machines
+		 * upon error conditions.
+		 */
+		if (data->error != MMC_ERR_NONE) {
+			sdhci_reset(host, SDHCI_RESET_CMD);
+			sdhci_reset(host, SDHCI_RESET_DATA);
+		}
+
+		sdhci_send_command(host, data->stop);
+	} else
+		tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+{
+	int flags;
+	u32 mask;
+	unsigned long timeout;
+
+	WARN_ON(host->cmd);
+
+	DBG("Sending cmd (%x)\n", cmd->opcode);
+
+	/* Wait max 10 ms */
+	timeout = 10;
+
+	mask = SDHCI_CMD_INHIBIT;
+	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+		mask |= SDHCI_DATA_INHIBIT;
+
+	/* We shouldn't wait for data inihibit for stop commands, even
+	   though they might use busy signaling */
+	if (host->mrq->data && (cmd == host->mrq->data->stop))
+		mask &= ~SDHCI_DATA_INHIBIT;
+
+	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+		if (timeout == 0) {
+			printk(KERN_ERR "%s: Controller never released "
+				"inhibit bit(s).\n", mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			cmd->error = MMC_ERR_FAILED;
+			tasklet_schedule(&host->finish_tasklet);
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	mod_timer(&host->timer, jiffies + 10 * HZ);
+
+	host->cmd = cmd;
+
+	sdhci_prepare_data(host, cmd->data);
+
+	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
+
+	sdhci_set_transfer_mode(host, cmd->data);
+
+	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
+		printk(KERN_ERR "%s: Unsupported response type!\n",
+			mmc_hostname(host->mmc));
+		cmd->error = MMC_ERR_INVALID;
+		tasklet_schedule(&host->finish_tasklet);
+		return;
+	}
+
+	if (!(cmd->flags & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->flags & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->flags & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->flags & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->flags & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+	if (cmd->data)
+		flags |= SDHCI_CMD_DATA;
+
+	writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
+		host->ioaddr + SDHCI_COMMAND);
+}
+
+static void sdhci_finish_command(struct sdhci_host *host)
+{
+	int i;
+
+	BUG_ON(host->cmd == NULL);
+
+	if (host->cmd->flags & MMC_RSP_PRESENT) {
+		if (host->cmd->flags & MMC_RSP_136) {
+			/* CRC is stripped so we need to do some shifting. */
+			for (i = 0;i < 4;i++) {
+				host->cmd->resp[i] = readl(host->ioaddr +
+					SDHCI_RESPONSE + (3-i)*4) << 8;
+				if (i != 3)
+					host->cmd->resp[i] |=
+						readb(host->ioaddr +
+						SDHCI_RESPONSE + (3-i)*4-1);
+			}
+		} else {
+			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
+		}
+	}
+
+	host->cmd->error = MMC_ERR_NONE;
+
+	DBG("Ending cmd (%x)\n", host->cmd->opcode);
+
+	if (host->cmd->data)
+		host->data = host->cmd->data;
+	else
+		tasklet_schedule(&host->finish_tasklet);
+
+	host->cmd = NULL;
+}
+
+static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	int div;
+	u16 clk;
+	unsigned long timeout;
+
+	if (clock == host->clock)
+		return;
+
+	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		goto out;
+
+	for (div = 1;div < 256;div *= 2) {
+		if ((host->max_clk / div) <= clock)
+			break;
+	}
+	div >>= 1;
+
+	clk = div << SDHCI_DIVIDER_SHIFT;
+	clk |= SDHCI_CLOCK_INT_EN;
+	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 10 ms */
+	timeout = 10;
+	while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
+		& SDHCI_CLOCK_INT_STABLE)) {
+		if (timeout == 0) {
+			printk(KERN_ERR "%s: Internal clock never "
+				"stabilised.\n", mmc_hostname(host->mmc));
+			sdhci_dumpregs(host);
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+out:
+	host->clock = clock;
+}
+
+static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+{
+	u8 pwr;
+
+	if (host->power == power)
+		return;
+
+	if (power == (unsigned short)-1) {
+		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+		goto out;
+	}
+
+	/*
+	 * Spec says that we should clear the power reg before setting
+	 * a new value. Some controllers don't seem to like this though.
+	 */
+	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+
+	pwr = SDHCI_POWER_ON;
+
+	switch (1 << power) {
+	case MMC_VDD_165_195:
+		pwr |= SDHCI_POWER_180;
+		break;
+	case MMC_VDD_29_30:
+	case MMC_VDD_30_31:
+		pwr |= SDHCI_POWER_300;
+		break;
+	case MMC_VDD_32_33:
+	case MMC_VDD_33_34:
+		pwr |= SDHCI_POWER_330;
+		break;
+	default:
+		BUG();
+	}
+
+	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
+
+out:
+	host->power = power;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * MMC callbacks                                                             *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	WARN_ON(host->mrq != NULL);
+
+	sdhci_activate_led(host);
+
+	host->mrq = mrq;
+
+	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+		host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+		tasklet_schedule(&host->finish_tasklet);
+	} else
+		sdhci_send_command(host, mrq->cmd);
+
+	mmiowb();
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	u8 ctrl;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	/*
+	 * Reset the chip on each power off.
+	 * Should clear out any weird states.
+	 */
+	if (ios->power_mode == MMC_POWER_OFF) {
+		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+		sdhci_init(host);
+	}
+
+	sdhci_set_clock(host, ios->clock);
+
+	if (ios->power_mode == MMC_POWER_OFF)
+		sdhci_set_power(host, -1);
+	else
+		sdhci_set_power(host, ios->vdd);
+
+	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		ctrl |= SDHCI_CTRL_4BITBUS;
+	else
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+
+	if (ios->timing == MMC_TIMING_SD_HS)
+		ctrl |= SDHCI_CTRL_HISPD;
+	else
+		ctrl &= ~SDHCI_CTRL_HISPD;
+
+	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+
+	mmiowb();
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	int present;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return !(present & SDHCI_WRITE_PROTECT);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+	.request	= sdhci_request,
+	.set_ios	= sdhci_set_ios,
+	.get_ro		= sdhci_get_ro,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Tasklets                                                                  *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = (struct sdhci_host*)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+		if (host->mrq) {
+			printk(KERN_ERR "%s: Card removed during transfer!\n",
+				mmc_hostname(host->mmc));
+			printk(KERN_ERR "%s: Resetting controller.\n",
+				mmc_hostname(host->mmc));
+
+			sdhci_reset(host, SDHCI_RESET_CMD);
+			sdhci_reset(host, SDHCI_RESET_DATA);
+
+			host->mrq->cmd->error = MMC_ERR_FAILED;
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+}
+
+static void sdhci_tasklet_finish(unsigned long param)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	struct mmc_request *mrq;
+
+	host = (struct sdhci_host*)param;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	del_timer(&host->timer);
+
+	mrq = host->mrq;
+
+	DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+
+	/*
+	 * The controller needs a reset of internal state machines
+	 * upon error conditions.
+	 */
+	if ((mrq->cmd->error != MMC_ERR_NONE) ||
+		(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
+		(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+
+		/* Some controllers need this kick or reset won't work here */
+		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+			unsigned int clock;
+
+			/* This is to force an update */
+			clock = host->clock;
+			host->clock = 0;
+			sdhci_set_clock(host, clock);
+		}
+
+		/* Spec says we should do both at the same time, but Ricoh
+		   controllers do not like that. */
+		sdhci_reset(host, SDHCI_RESET_CMD);
+		sdhci_reset(host, SDHCI_RESET_DATA);
+	}
+
+	host->mrq = NULL;
+	host->cmd = NULL;
+	host->data = NULL;
+
+	sdhci_deactivate_led(host);
+
+	mmiowb();
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+static void sdhci_timeout_timer(unsigned long data)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+
+	host = (struct sdhci_host*)data;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	if (host->mrq) {
+		printk(KERN_ERR "%s: Timeout waiting for hardware "
+			"interrupt.\n", mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+
+		if (host->data) {
+			host->data->error = MMC_ERR_TIMEOUT;
+			sdhci_finish_data(host);
+		} else {
+			if (host->cmd)
+				host->cmd->error = MMC_ERR_TIMEOUT;
+			else
+				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+
+			tasklet_schedule(&host->finish_tasklet);
+		}
+	}
+
+	mmiowb();
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+{
+	BUG_ON(intmask == 0);
+
+	if (!host->cmd) {
+		printk(KERN_ERR "%s: Got command interrupt even though no "
+			"command operation was in progress.\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+		return;
+	}
+
+	if (intmask & SDHCI_INT_RESPONSE)
+		sdhci_finish_command(host);
+	else {
+		if (intmask & SDHCI_INT_TIMEOUT)
+			host->cmd->error = MMC_ERR_TIMEOUT;
+		else if (intmask & SDHCI_INT_CRC)
+			host->cmd->error = MMC_ERR_BADCRC;
+		else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
+			host->cmd->error = MMC_ERR_FAILED;
+		else
+			host->cmd->error = MMC_ERR_INVALID;
+
+		tasklet_schedule(&host->finish_tasklet);
+	}
+}
+
+static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+{
+	BUG_ON(intmask == 0);
+
+	if (!host->data) {
+		/*
+		 * A data end interrupt is sent together with the response
+		 * for the stop command.
+		 */
+		if (intmask & SDHCI_INT_DATA_END)
+			return;
+
+		printk(KERN_ERR "%s: Got data interrupt even though no "
+			"data operation was in progress.\n",
+			mmc_hostname(host->mmc));
+		sdhci_dumpregs(host);
+
+		return;
+	}
+
+	if (intmask & SDHCI_INT_DATA_TIMEOUT)
+		host->data->error = MMC_ERR_TIMEOUT;
+	else if (intmask & SDHCI_INT_DATA_CRC)
+		host->data->error = MMC_ERR_BADCRC;
+	else if (intmask & SDHCI_INT_DATA_END_BIT)
+		host->data->error = MMC_ERR_FAILED;
+
+	if (host->data->error != MMC_ERR_NONE)
+		sdhci_finish_data(host);
+	else {
+		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
+			sdhci_transfer_pio(host);
+
+		if (intmask & SDHCI_INT_DATA_END)
+			sdhci_finish_data(host);
+	}
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
+{
+	irqreturn_t result;
+	struct sdhci_host* host = dev_id;
+	u32 intmask;
+
+	spin_lock(&host->lock);
+
+	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
+
+	if (!intmask || intmask == 0xffffffff) {
+		result = IRQ_NONE;
+		goto out;
+	}
+
+	DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
+
+	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+		writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
+			host->ioaddr + SDHCI_INT_STATUS);
+		tasklet_schedule(&host->card_tasklet);
+	}
+
+	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
+
+	if (intmask & SDHCI_INT_CMD_MASK) {
+		writel(intmask & SDHCI_INT_CMD_MASK,
+			host->ioaddr + SDHCI_INT_STATUS);
+		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+	}
+
+	if (intmask & SDHCI_INT_DATA_MASK) {
+		writel(intmask & SDHCI_INT_DATA_MASK,
+			host->ioaddr + SDHCI_INT_STATUS);
+		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+	}
+
+	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+
+	if (intmask & SDHCI_INT_BUS_POWER) {
+		printk(KERN_ERR "%s: Card is consuming too much power!\n",
+			mmc_hostname(host->mmc));
+		writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
+	}
+
+	intmask &= SDHCI_INT_BUS_POWER;
+
+	if (intmask) {
+		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
+			mmc_hostname(host->mmc), intmask);
+		sdhci_dumpregs(host);
+
+		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
+	}
+
+	result = IRQ_HANDLED;
+
+	mmiowb();
+out:
+	spin_unlock(&host->lock);
+
+	return result;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Suspend/resume                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+#ifdef CONFIG_PM
+
+static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+	struct sdhci_chip *chip;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	DBG("Suspending...\n");
+
+	for (i = 0;i < chip->num_slots;i++) {
+		if (!chip->hosts[i])
+			continue;
+		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
+		if (ret) {
+			for (i--;i >= 0;i--)
+				mmc_resume_host(chip->hosts[i]->mmc);
+			return ret;
+		}
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+
+	for (i = 0;i < chip->num_slots;i++) {
+		if (!chip->hosts[i])
+			continue;
+		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
+	}
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int sdhci_resume (struct pci_dev *pdev)
+{
+	struct sdhci_chip *chip;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	DBG("Resuming...\n");
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	for (i = 0;i < chip->num_slots;i++) {
+		if (!chip->hosts[i])
+			continue;
+		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
+			pci_set_master(pdev);
+		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
+			IRQF_SHARED, chip->hosts[i]->slot_descr,
+			chip->hosts[i]);
+		if (ret)
+			return ret;
+		sdhci_init(chip->hosts[i]);
+		mmiowb();
+		ret = mmc_resume_host(chip->hosts[i]->mmc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define sdhci_suspend NULL
+#define sdhci_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
+{
+	int ret;
+	unsigned int version;
+	struct sdhci_chip *chip;
+	struct mmc_host *mmc;
+	struct sdhci_host *host;
+
+	u8 first_bar;
+	unsigned int caps;
+
+	chip = pci_get_drvdata(pdev);
+	BUG_ON(!chip);
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+	if (ret)
+		return ret;
+
+	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+
+	if (first_bar > 5) {
+		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
+		return -ENODEV;
+	}
+
+	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
+		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
+		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
+			"You may experience problems.\n");
+	}
+
+	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
+		return -ENODEV;
+	}
+
+	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
+		return -ENODEV;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	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);
+	host->irq = pdev->irq;
+
+	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
+
+	snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
+
+	ret = pci_request_region(pdev, host->bar, host->slot_descr);
+	if (ret)
+		goto free;
+
+	host->ioaddr = ioremap_nocache(host->addr,
+		pci_resource_len(pdev, host->bar));
+	if (!host->ioaddr) {
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+	if (version != 0) {
+		printk(KERN_ERR "%s: Unknown controller version (%d). "
+			"You may experience problems.\n", host->slot_descr,
+			version);
+	}
+
+	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
+
+	if (debug_nodma)
+		DBG("DMA forced off\n");
+	else if (debug_forcedma) {
+		DBG("DMA forced on\n");
+		host->flags |= SDHCI_USE_DMA;
+	} else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+		host->flags |= SDHCI_USE_DMA;
+	else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+		DBG("Controller doesn't have DMA interface\n");
+	else if (!(caps & SDHCI_CAN_DO_DMA))
+		DBG("Controller doesn't have DMA capability\n");
+	else
+		host->flags |= SDHCI_USE_DMA;
+
+	if (host->flags & SDHCI_USE_DMA) {
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+			printk(KERN_WARNING "%s: No suitable DMA available. "
+				"Falling back to PIO.\n", host->slot_descr);
+			host->flags &= ~SDHCI_USE_DMA;
+		}
+	}
+
+	if (host->flags & SDHCI_USE_DMA)
+		pci_set_master(pdev);
+	else /* XXX: Hack to get MMC layer to avoid highmem */
+		pdev->dma_mask = 0;
+
+	host->max_clk =
+		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+	if (host->max_clk == 0) {
+		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
+			"frequency.\n", host->slot_descr);
+		ret = -ENODEV;
+		goto unmap;
+	}
+	host->max_clk *= 1000000;
+
+	host->timeout_clk =
+		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+	if (host->timeout_clk == 0) {
+		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
+			"frequency.\n", host->slot_descr);
+		ret = -ENODEV;
+		goto unmap;
+	}
+	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+		host->timeout_clk *= 1000;
+
+	/*
+	 * Set host parameters.
+	 */
+	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_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+	if (caps & SDHCI_CAN_DO_HISPD)
+		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+
+	mmc->ocr_avail = 0;
+	if (caps & SDHCI_CAN_VDD_330)
+		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
+	if (caps & SDHCI_CAN_VDD_300)
+		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
+	if (caps & SDHCI_CAN_VDD_180)
+		mmc->ocr_avail |= MMC_VDD_165_195;
+
+	if (mmc->ocr_avail == 0) {
+		printk(KERN_ERR "%s: Hardware doesn't report any "
+			"support voltages.\n", host->slot_descr);
+		ret = -ENODEV;
+		goto unmap;
+	}
+
+	spin_lock_init(&host->lock);
+
+	/*
+	 * Maximum number of segments. Hardware cannot do scatter lists.
+	 */
+	if (host->flags & SDHCI_USE_DMA)
+		mmc->max_hw_segs = 1;
+	else
+		mmc->max_hw_segs = 16;
+	mmc->max_phys_segs = 16;
+
+	/*
+	 * Maximum number of sectors in one transfer. Limited by DMA boundary
+	 * size (512KiB).
+	 */
+	mmc->max_req_size = 524288;
+
+	/*
+	 * Maximum segment size. Could be one segment with the maximum number
+	 * of bytes.
+	 */
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Maximum block size. This varies from controller to controller and
+	 * is specified in the capabilities register.
+	 */
+	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+	if (mmc->max_blk_size >= 3) {
+		printk(KERN_ERR "%s: Invalid maximum block size.\n",
+			host->slot_descr);
+		ret = -ENODEV;
+		goto unmap;
+	}
+	mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+	/*
+	 * Maximum block count.
+	 */
+	mmc->max_blk_count = 65535;
+
+	/*
+	 * Init tasklets.
+	 */
+	tasklet_init(&host->card_tasklet,
+		sdhci_tasklet_card, (unsigned long)host);
+	tasklet_init(&host->finish_tasklet,
+		sdhci_tasklet_finish, (unsigned 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);
+	if (ret)
+		goto untasklet;
+
+	sdhci_init(host);
+
+#ifdef CONFIG_MMC_DEBUG
+	sdhci_dumpregs(host);
+#endif
+
+	mmiowb();
+
+	mmc_add_host(mmc);
+
+	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
+		host->addr, host->irq,
+		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
+
+	return 0;
+
+untasklet:
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+unmap:
+	iounmap(host->ioaddr);
+release:
+	pci_release_region(pdev, host->bar);
+free:
+	mmc_free_host(mmc);
+
+	return ret;
+}
+
+static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
+{
+	struct sdhci_chip *chip;
+	struct mmc_host *mmc;
+	struct sdhci_host *host;
+
+	chip = pci_get_drvdata(pdev);
+	host = chip->hosts[slot];
+	mmc = host->mmc;
+
+	chip->hosts[slot] = NULL;
+
+	mmc_remove_host(mmc);
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+
+	free_irq(host->irq, host);
+
+	del_timer_sync(&host->timer);
+
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+
+	iounmap(host->ioaddr);
+
+	pci_release_region(pdev, host->bar);
+
+	mmc_free_host(mmc);
+}
+
+static int __devinit sdhci_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	int ret, i;
+	u8 slots, rev;
+	struct sdhci_chip *chip;
+
+	BUG_ON(pdev == NULL);
+	BUG_ON(ent == NULL);
+
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+	printk(KERN_INFO DRIVER_NAME
+		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
+		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+		(int)rev);
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
+	if (ret)
+		return ret;
+
+	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
+	DBG("found %d slot(s)\n", slots);
+	if (slots == 0)
+		return -ENODEV;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	chip = kzalloc(sizeof(struct sdhci_chip) +
+		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
+	if (!chip) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	chip->pdev = pdev;
+	chip->quirks = ent->driver_data;
+
+	if (debug_quirks)
+		chip->quirks = debug_quirks;
+
+	chip->num_slots = slots;
+	pci_set_drvdata(pdev, chip);
+
+	for (i = 0;i < slots;i++) {
+		ret = sdhci_probe_slot(pdev, i);
+		if (ret) {
+			for (i--;i >= 0;i--)
+				sdhci_remove_slot(pdev, i);
+			goto free;
+		}
+	}
+
+	return 0;
+
+free:
+	pci_set_drvdata(pdev, NULL);
+	kfree(chip);
+
+err:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit sdhci_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct sdhci_chip *chip;
+
+	chip = pci_get_drvdata(pdev);
+
+	if (chip) {
+		for (i = 0;i < chip->num_slots;i++)
+			sdhci_remove_slot(pdev, i);
+
+		pci_set_drvdata(pdev, NULL);
+
+		kfree(chip);
+	}
+
+	pci_disable_device(pdev);
+}
+
+static struct pci_driver sdhci_driver = {
+	.name = 	DRIVER_NAME,
+	.id_table =	pci_ids,
+	.probe = 	sdhci_probe,
+	.remove =	__devexit_p(sdhci_remove),
+	.suspend =	sdhci_suspend,
+	.resume	=	sdhci_resume,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+	printk(KERN_INFO DRIVER_NAME
+		": Secure Digital Host Controller Interface driver\n");
+	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+	return pci_register_driver(&sdhci_driver);
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+	DBG("Exiting\n");
+
+	pci_unregister_driver(&sdhci_driver);
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+module_param(debug_nodma, uint, 0444);
+module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
+
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
new file mode 100644
index 0000000..7400f4b
--- /dev/null
+++ b/drivers/mmc/host/sdhci.h
@@ -0,0 +1,210 @@
+/*
+ *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
+ *
+ *  Copyright (C) 2005-2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * PCI registers
+ */
+
+#define PCI_SDHCI_IFPIO			0x00
+#define PCI_SDHCI_IFDMA			0x01
+#define PCI_SDHCI_IFVENDOR		0x02
+
+#define PCI_SLOT_INFO			0x40	/* 8 bits */
+#define  PCI_SLOT_INFO_SLOTS(x)		((x >> 4) & 7)
+#define  PCI_SLOT_INFO_FIRST_BAR_MASK	0x07
+
+/*
+ * Controller registers
+ */
+
+#define SDHCI_DMA_ADDRESS	0x00
+
+#define SDHCI_BLOCK_SIZE	0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
+
+#define SDHCI_BLOCK_COUNT	0x06
+
+#define SDHCI_ARGUMENT		0x08
+
+#define SDHCI_TRANSFER_MODE	0x0C
+#define  SDHCI_TRNS_DMA		0x01
+#define  SDHCI_TRNS_BLK_CNT_EN	0x02
+#define  SDHCI_TRNS_ACMD12	0x04
+#define  SDHCI_TRNS_READ	0x10
+#define  SDHCI_TRNS_MULTI	0x20
+
+#define SDHCI_COMMAND		0x0E
+#define  SDHCI_CMD_RESP_MASK	0x03
+#define  SDHCI_CMD_CRC		0x08
+#define  SDHCI_CMD_INDEX	0x10
+#define  SDHCI_CMD_DATA		0x20
+
+#define  SDHCI_CMD_RESP_NONE	0x00
+#define  SDHCI_CMD_RESP_LONG	0x01
+#define  SDHCI_CMD_RESP_SHORT	0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+
+#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
+
+#define SDHCI_RESPONSE		0x10
+
+#define SDHCI_BUFFER		0x20
+
+#define SDHCI_PRESENT_STATE	0x24
+#define  SDHCI_CMD_INHIBIT	0x00000001
+#define  SDHCI_DATA_INHIBIT	0x00000002
+#define  SDHCI_DOING_WRITE	0x00000100
+#define  SDHCI_DOING_READ	0x00000200
+#define  SDHCI_SPACE_AVAILABLE	0x00000400
+#define  SDHCI_DATA_AVAILABLE	0x00000800
+#define  SDHCI_CARD_PRESENT	0x00010000
+#define  SDHCI_WRITE_PROTECT	0x00080000
+
+#define SDHCI_HOST_CONTROL 	0x28
+#define  SDHCI_CTRL_LED		0x01
+#define  SDHCI_CTRL_4BITBUS	0x02
+#define  SDHCI_CTRL_HISPD	0x04
+
+#define SDHCI_POWER_CONTROL	0x29
+#define  SDHCI_POWER_ON		0x01
+#define  SDHCI_POWER_180	0x0A
+#define  SDHCI_POWER_300	0x0C
+#define  SDHCI_POWER_330	0x0E
+
+#define SDHCI_BLOCK_GAP_CONTROL	0x2A
+
+#define SDHCI_WALK_UP_CONTROL	0x2B
+
+#define SDHCI_CLOCK_CONTROL	0x2C
+#define  SDHCI_DIVIDER_SHIFT	8
+#define  SDHCI_CLOCK_CARD_EN	0x0004
+#define  SDHCI_CLOCK_INT_STABLE	0x0002
+#define  SDHCI_CLOCK_INT_EN	0x0001
+
+#define SDHCI_TIMEOUT_CONTROL	0x2E
+
+#define SDHCI_SOFTWARE_RESET	0x2F
+#define  SDHCI_RESET_ALL	0x01
+#define  SDHCI_RESET_CMD	0x02
+#define  SDHCI_RESET_DATA	0x04
+
+#define SDHCI_INT_STATUS	0x30
+#define SDHCI_INT_ENABLE	0x34
+#define SDHCI_SIGNAL_ENABLE	0x38
+#define  SDHCI_INT_RESPONSE	0x00000001
+#define  SDHCI_INT_DATA_END	0x00000002
+#define  SDHCI_INT_DMA_END	0x00000008
+#define  SDHCI_INT_SPACE_AVAIL	0x00000010
+#define  SDHCI_INT_DATA_AVAIL	0x00000020
+#define  SDHCI_INT_CARD_INSERT	0x00000040
+#define  SDHCI_INT_CARD_REMOVE	0x00000080
+#define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_TIMEOUT	0x00010000
+#define  SDHCI_INT_CRC		0x00020000
+#define  SDHCI_INT_END_BIT	0x00040000
+#define  SDHCI_INT_INDEX	0x00080000
+#define  SDHCI_INT_DATA_TIMEOUT	0x00100000
+#define  SDHCI_INT_DATA_CRC	0x00200000
+#define  SDHCI_INT_DATA_END_BIT	0x00400000
+#define  SDHCI_INT_BUS_POWER	0x00800000
+#define  SDHCI_INT_ACMD12ERR	0x01000000
+
+#define  SDHCI_INT_NORMAL_MASK	0x00007FFF
+#define  SDHCI_INT_ERROR_MASK	0xFFFF8000
+
+#define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
+		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+#define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
+		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
+		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
+		SDHCI_INT_DATA_END_BIT)
+
+#define SDHCI_ACMD12_ERR	0x3C
+
+/* 3E-3F reserved */
+
+#define SDHCI_CAPABILITIES	0x40
+#define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
+#define  SDHCI_TIMEOUT_CLK_SHIFT 0
+#define  SDHCI_TIMEOUT_CLK_UNIT	0x00000080
+#define  SDHCI_CLOCK_BASE_MASK	0x00003F00
+#define  SDHCI_CLOCK_BASE_SHIFT	8
+#define  SDHCI_MAX_BLOCK_MASK	0x00030000
+#define  SDHCI_MAX_BLOCK_SHIFT  16
+#define  SDHCI_CAN_DO_HISPD	0x00200000
+#define  SDHCI_CAN_DO_DMA	0x00400000
+#define  SDHCI_CAN_VDD_330	0x01000000
+#define  SDHCI_CAN_VDD_300	0x02000000
+#define  SDHCI_CAN_VDD_180	0x04000000
+
+/* 44-47 reserved for more caps */
+
+#define SDHCI_MAX_CURRENT	0x48
+
+/* 4C-4F reserved for more max current */
+
+/* 50-FB reserved */
+
+#define SDHCI_SLOT_INT_STATUS	0xFC
+
+#define SDHCI_HOST_VERSION	0xFE
+#define  SDHCI_VENDOR_VER_MASK	0xFF00
+#define  SDHCI_VENDOR_VER_SHIFT	8
+#define  SDHCI_SPEC_VER_MASK	0x00FF
+#define  SDHCI_SPEC_VER_SHIFT	0
+
+struct sdhci_chip;
+
+struct sdhci_host {
+	struct sdhci_chip	*chip;
+	struct mmc_host		*mmc;		/* MMC structure */
+
+	spinlock_t		lock;		/* Mutex */
+
+	int			flags;		/* Host attributes */
+#define SDHCI_USE_DMA		(1<<0)
+
+	unsigned int		max_clk;	/* Max possible freq (MHz) */
+	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
+
+	unsigned int		clock;		/* Current clock (MHz) */
+	unsigned short		power;		/* Current voltage */
+
+	struct mmc_request	*mrq;		/* Current request */
+	struct mmc_command	*cmd;		/* Current command */
+	struct mmc_data		*data;		/* Current data request */
+
+	struct scatterlist	*cur_sg;	/* We're working on this */
+	int			num_sg;		/* Entries left */
+	int			offset;		/* Offset into current sg */
+	int			remain;		/* Bytes left in current */
+
+	char			slot_descr[20];	/* Name for reservations */
+
+	int			irq;		/* Device IRQ */
+	int			bar;		/* PCI BAR index */
+	unsigned long		addr;		/* Bus address */
+	void __iomem *		ioaddr;		/* Mapped address */
+
+	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
+	struct tasklet_struct	finish_tasklet;
+
+	struct timer_list	timer;		/* Timer for timeouts */
+};
+
+struct sdhci_chip {
+	struct pci_dev		*pdev;
+
+	unsigned long		quirks;
+
+	int			num_slots;	/* Slots on controller */
+	struct sdhci_host	*hosts[0];	/* Pointers to hosts */
+};
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
new file mode 100644
index 0000000..7511f96
--- /dev/null
+++ b/drivers/mmc/host/tifm_sd.c
@@ -0,0 +1,1102 @@
+/*
+ *  tifm_sd.c - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@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.
+ *
+ * Special thanks to Brad Campbell for extensive testing of this driver.
+ *
+ */
+
+
+#include <linux/tifm.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <asm/io.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.8"
+
+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_ERRMASK    0x01e0   /* set bits: CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */
+#define TIFM_MMCSD_CD         0x0002   /* card detect           */
+#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_OCRB       0x1000   /* OCR busy              */
+#define TIFM_MMCSD_CIRQ       0x2000   /* card irq (cmd40/sdio) */
+#define TIFM_MMCSD_CERR       0x4000   /* card status error     */
+
+#define TIFM_MMCSD_ODTO       0x0040   /* open drain / extended timeout */
+#define TIFM_MMCSD_CARD_RO    0x0200   /* card is read-only     */
+
+#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
+
+#define TIFM_MMCSD_MAX_BLOCK_SIZE  0x0800UL
+
+enum {
+	CMD_READY    = 0x0001,
+	FIFO_READY   = 0x0002,
+	BRS_READY    = 0x0004,
+	SCMD_ACTIVE  = 0x0008,
+	SCMD_READY   = 0x0010,
+	CARD_BUSY    = 0x0020,
+	DATA_CARRY   = 0x0040
+};
+
+struct tifm_sd {
+	struct tifm_dev       *dev;
+
+	unsigned short        eject:1,
+			      open_drain:1,
+			      no_dma:1;
+	unsigned short        cmd_flags;
+
+	unsigned int          clk_freq;
+	unsigned int          clk_div;
+	unsigned long         timeout_jiffies;
+
+	struct tasklet_struct finish_tasklet;
+	struct timer_list     timer;
+	struct mmc_request    *req;
+
+	int                   sg_len;
+	int                   sg_pos;
+	unsigned int          block_pos;
+	struct scatterlist    bounce_buf;
+	unsigned char         bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
+};
+
+/* for some reason, host won't respond correctly to readw/writew */
+static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
+			      unsigned int off, unsigned int cnt)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned char *buf;
+	unsigned int pos = 0, val;
+
+	buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+	if (host->cmd_flags & DATA_CARRY) {
+		buf[pos++] = host->bounce_buf_data[0];
+		host->cmd_flags &= ~DATA_CARRY;
+	}
+
+	while (pos < cnt) {
+		val = readl(sock->addr + SOCK_MMCSD_DATA);
+		buf[pos++] = val & 0xff;
+		if (pos == cnt) {
+			host->bounce_buf_data[0] = (val >> 8) & 0xff;
+			host->cmd_flags |= DATA_CARRY;
+			break;
+		}
+		buf[pos++] = (val >> 8) & 0xff;
+	}
+	kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
+}
+
+static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
+			       unsigned int off, unsigned int cnt)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned char *buf;
+	unsigned int pos = 0, val;
+
+	buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+	if (host->cmd_flags & DATA_CARRY) {
+		val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
+		writel(val, sock->addr + SOCK_MMCSD_DATA);
+		host->cmd_flags &= ~DATA_CARRY;
+	}
+
+	while (pos < cnt) {
+		val = buf[pos++];
+		if (pos == cnt) {
+			host->bounce_buf_data[0] = val & 0xff;
+			host->cmd_flags |= DATA_CARRY;
+			break;
+		}
+		val |= (buf[pos++] << 8) & 0xff00;
+		writel(val, sock->addr + SOCK_MMCSD_DATA);
+	}
+	kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_transfer_data(struct tifm_sd *host)
+{
+	struct mmc_data *r_data = host->req->cmd->data;
+	struct scatterlist *sg = r_data->sg;
+	unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
+	unsigned int p_off, p_cnt;
+	struct page *pg;
+
+	if (host->sg_pos == host->sg_len)
+		return;
+	while (t_size) {
+		cnt = sg[host->sg_pos].length - host->block_pos;
+		if (!cnt) {
+			host->block_pos = 0;
+			host->sg_pos++;
+			if (host->sg_pos == host->sg_len) {
+				if ((r_data->flags & MMC_DATA_WRITE)
+				    && DATA_CARRY)
+					writel(host->bounce_buf_data[0],
+					       host->dev->addr
+					       + SOCK_MMCSD_DATA);
+
+				return;
+			}
+			cnt = sg[host->sg_pos].length;
+		}
+		off = sg[host->sg_pos].offset + host->block_pos;
+
+		pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+		p_off = offset_in_page(off);
+		p_cnt = PAGE_SIZE - p_off;
+		p_cnt = min(p_cnt, cnt);
+		p_cnt = min(p_cnt, t_size);
+
+		if (r_data->flags & MMC_DATA_READ)
+			tifm_sd_read_fifo(host, pg, p_off, p_cnt);
+		else if (r_data->flags & MMC_DATA_WRITE)
+			tifm_sd_write_fifo(host, pg, p_off, p_cnt);
+
+		t_size -= p_cnt;
+		host->block_pos += p_cnt;
+	}
+}
+
+static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
+			      struct page *src, unsigned int src_off,
+			      unsigned int count)
+{
+	unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
+	unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+
+	memcpy(dst_buf, src_buf, count);
+
+	kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
+	kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
+{
+	struct scatterlist *sg = r_data->sg;
+	unsigned int t_size = r_data->blksz;
+	unsigned int off, cnt;
+	unsigned int p_off, p_cnt;
+	struct page *pg;
+
+	dev_dbg(&host->dev->dev, "bouncing block\n");
+	while (t_size) {
+		cnt = sg[host->sg_pos].length - host->block_pos;
+		if (!cnt) {
+			host->block_pos = 0;
+			host->sg_pos++;
+			if (host->sg_pos == host->sg_len)
+				return;
+			cnt = sg[host->sg_pos].length;
+		}
+		off = sg[host->sg_pos].offset + host->block_pos;
+
+		pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+		p_off = offset_in_page(off);
+		p_cnt = PAGE_SIZE - p_off;
+		p_cnt = min(p_cnt, cnt);
+		p_cnt = min(p_cnt, t_size);
+
+		if (r_data->flags & MMC_DATA_WRITE)
+			tifm_sd_copy_page(host->bounce_buf.page,
+					  r_data->blksz - t_size,
+					  pg, p_off, p_cnt);
+		else if (r_data->flags & MMC_DATA_READ)
+			tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+					  r_data->blksz - t_size, p_cnt);
+
+		t_size -= p_cnt;
+		host->block_pos += p_cnt;
+	}
+}
+
+static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
+	unsigned int dma_len, dma_blk_cnt, dma_off;
+	struct scatterlist *sg = NULL;
+	unsigned long flags;
+
+	if (host->sg_pos == host->sg_len)
+		return 1;
+
+	if (host->cmd_flags & DATA_CARRY) {
+		host->cmd_flags &= ~DATA_CARRY;
+		local_irq_save(flags);
+		tifm_sd_bounce_block(host, r_data);
+		local_irq_restore(flags);
+		if (host->sg_pos == host->sg_len)
+			return 1;
+	}
+
+	dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos;
+	if (!dma_len) {
+		host->block_pos = 0;
+		host->sg_pos++;
+		if (host->sg_pos == host->sg_len)
+			return 1;
+		dma_len = sg_dma_len(&r_data->sg[host->sg_pos]);
+	}
+
+	if (dma_len < t_size) {
+		dma_blk_cnt = dma_len / r_data->blksz;
+		dma_off = host->block_pos;
+		host->block_pos += dma_blk_cnt * r_data->blksz;
+	} else {
+		dma_blk_cnt = TIFM_DMA_TSIZE;
+		dma_off = host->block_pos;
+		host->block_pos += t_size;
+	}
+
+	if (dma_blk_cnt)
+		sg = &r_data->sg[host->sg_pos];
+	else if (dma_len) {
+		if (r_data->flags & MMC_DATA_WRITE) {
+			local_irq_save(flags);
+			tifm_sd_bounce_block(host, r_data);
+			local_irq_restore(flags);
+		} else
+			host->cmd_flags |= DATA_CARRY;
+
+		sg = &host->bounce_buf;
+		dma_off = 0;
+		dma_blk_cnt = 1;
+	} else
+		return 1;
+
+	dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
+	writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
+	if (r_data->flags & MMC_DATA_WRITE)
+		writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
+		       sock->addr + SOCK_DMA_CONTROL);
+	else
+		writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
+		       sock->addr + SOCK_DMA_CONTROL);
+
+	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;
+	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);
+
+	if (host->open_drain)
+		cmd_mask |= TIFM_MMCSD_ODTO;
+
+	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_check_status(struct tifm_sd *host)
+{
+	struct tifm_dev *sock = host->dev;
+	struct mmc_command *cmd = host->req->cmd;
+
+	if (cmd->error != MMC_ERR_NONE)
+		goto finish_request;
+
+	if (!(host->cmd_flags & CMD_READY))
+		return;
+
+	if (cmd->data) {
+		if (cmd->data->error != MMC_ERR_NONE) {
+			if ((host->cmd_flags & SCMD_ACTIVE)
+			    && !(host->cmd_flags & SCMD_READY))
+				return;
+
+			goto finish_request;
+		}
+
+		if (!(host->cmd_flags & BRS_READY))
+			return;
+
+		if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
+			return;
+
+		if (cmd->data->flags & MMC_DATA_WRITE) {
+			if (host->req->stop) {
+				if (!(host->cmd_flags & SCMD_ACTIVE)) {
+					host->cmd_flags |= SCMD_ACTIVE;
+					writel(TIFM_MMCSD_EOFB
+					       | readl(sock->addr
+						       + SOCK_MMCSD_INT_ENABLE),
+					       sock->addr
+					       + SOCK_MMCSD_INT_ENABLE);
+					tifm_sd_exec(host, host->req->stop);
+					return;
+				} else {
+					if (!(host->cmd_flags & SCMD_READY)
+					    || (host->cmd_flags & CARD_BUSY))
+						return;
+					writel((~TIFM_MMCSD_EOFB)
+					       & readl(sock->addr
+						       + SOCK_MMCSD_INT_ENABLE),
+					       sock->addr
+					       + SOCK_MMCSD_INT_ENABLE);
+				}
+			} else {
+				if (host->cmd_flags & CARD_BUSY)
+					return;
+				writel((~TIFM_MMCSD_EOFB)
+				       & readl(sock->addr
+					       + SOCK_MMCSD_INT_ENABLE),
+				       sock->addr + SOCK_MMCSD_INT_ENABLE);
+			}
+		} else {
+			if (host->req->stop) {
+				if (!(host->cmd_flags & SCMD_ACTIVE)) {
+					host->cmd_flags |= SCMD_ACTIVE;
+					tifm_sd_exec(host, host->req->stop);
+					return;
+				} else {
+					if (!(host->cmd_flags & SCMD_READY))
+						return;
+				}
+			}
+		}
+	}
+finish_request:
+	tasklet_schedule(&host->finish_tasklet);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_data_event(struct tifm_dev *sock)
+{
+	struct tifm_sd *host;
+	unsigned int fifo_status = 0;
+	struct mmc_data *r_data = NULL;
+
+	spin_lock(&sock->lock);
+	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+	fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+	dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
+		fifo_status, host->cmd_flags);
+
+	if (host->req) {
+		r_data = host->req->cmd->data;
+
+		if (r_data && (fifo_status & TIFM_FIFO_READY)) {
+			if (tifm_sd_set_dma_data(host, r_data)) {
+				host->cmd_flags |= FIFO_READY;
+				tifm_sd_check_status(host);
+			}
+		}
+	}
+
+	writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+	spin_unlock(&sock->lock);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_card_event(struct tifm_dev *sock)
+{
+	struct tifm_sd *host;
+	unsigned int host_status = 0;
+	int cmd_error = MMC_ERR_NONE;
+	struct mmc_command *cmd = NULL;
+	unsigned long flags;
+
+	spin_lock(&sock->lock);
+	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+	host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+	dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
+		host_status, host->cmd_flags);
+
+	if (host->req) {
+		cmd = host->req->cmd;
+
+		if (host_status & TIFM_MMCSD_ERRMASK) {
+			writel(host_status & TIFM_MMCSD_ERRMASK,
+			       sock->addr + SOCK_MMCSD_STATUS);
+			if (host_status & TIFM_MMCSD_CTO)
+				cmd_error = MMC_ERR_TIMEOUT;
+			else if (host_status & TIFM_MMCSD_CCRC)
+				cmd_error = MMC_ERR_BADCRC;
+
+			if (cmd->data) {
+				if (host_status & TIFM_MMCSD_DTO)
+					cmd->data->error = MMC_ERR_TIMEOUT;
+				else if (host_status & TIFM_MMCSD_DCRC)
+					cmd->data->error = 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->cmd_flags & SCMD_ACTIVE) {
+					host->req->stop->error = cmd_error;
+					host->cmd_flags |= SCMD_READY;
+				} else {
+					cmd->error = cmd_error;
+					host->cmd_flags |= SCMD_ACTIVE;
+					tifm_sd_exec(host, host->req->stop);
+					goto done;
+				}
+			} else
+				cmd->error = cmd_error;
+		} else {
+			if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
+				if (!(host->cmd_flags & CMD_READY)) {
+					host->cmd_flags |= CMD_READY;
+					tifm_sd_fetch_resp(cmd, sock);
+				} else if (host->cmd_flags & SCMD_ACTIVE) {
+					host->cmd_flags |= SCMD_READY;
+					tifm_sd_fetch_resp(host->req->stop,
+							   sock);
+				}
+			}
+			if (host_status & TIFM_MMCSD_BRS)
+				host->cmd_flags |= BRS_READY;
+		}
+
+		if (host->no_dma && cmd->data) {
+			if (host_status & TIFM_MMCSD_AE)
+				writel(host_status & TIFM_MMCSD_AE,
+				       sock->addr + SOCK_MMCSD_STATUS);
+
+			if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
+					   | TIFM_MMCSD_BRS)) {
+				local_irq_save(flags);
+				tifm_sd_transfer_data(host);
+				local_irq_restore(flags);
+				host_status &= ~TIFM_MMCSD_AE;
+			}
+		}
+
+		if (host_status & TIFM_MMCSD_EOFB)
+			host->cmd_flags &= ~CARD_BUSY;
+		else if (host_status & TIFM_MMCSD_CB)
+			host->cmd_flags |= CARD_BUSY;
+
+		tifm_sd_check_status(host);
+	}
+done:
+	writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+	spin_unlock(&sock->lock);
+}
+
+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 /
+			((1000000000UL / host->clk_freq) * host->clk_div);
+
+	if (data_timeout < 0xffff) {
+		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+		writel((~TIFM_MMCSD_DPE)
+		       & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+	} else {
+		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);
+		writel(TIFM_MMCSD_DPE
+		       | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+	}
+}
+
+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;
+	struct mmc_data *r_data = mrq->cmd->data;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	if (host->eject) {
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	if (host->req) {
+		printk(KERN_ERR "%s : unfinished request detected\n",
+		       sock->dev.bus_id);
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	host->cmd_flags = 0;
+	host->block_pos = 0;
+	host->sg_pos = 0;
+
+	if (r_data) {
+		tifm_sd_set_data_timeout(host, r_data);
+
+		if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
+			 writel(TIFM_MMCSD_EOFB
+				| readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+				sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+		if (host->no_dma) {
+			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->sg_len = r_data->sg_len;
+		} else {
+			sg_init_one(&host->bounce_buf, host->bounce_buf_data,
+				    r_data->blksz);
+
+			if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
+					    r_data->flags & MMC_DATA_WRITE
+					    ? PCI_DMA_TODEVICE
+					    : PCI_DMA_FROMDEVICE)) {
+				printk(KERN_ERR "%s : scatterlist map failed\n",
+				       sock->dev.bus_id);
+				spin_unlock_irqrestore(&sock->lock, flags);
+				goto err_out;
+			}
+			host->sg_len = tifm_map_sg(sock, r_data->sg,
+						   r_data->sg_len,
+						   r_data->flags
+						   & MMC_DATA_WRITE
+						   ? PCI_DMA_TODEVICE
+						   : PCI_DMA_FROMDEVICE);
+			if (host->sg_len < 1) {
+				printk(KERN_ERR "%s : scatterlist map failed\n",
+				       sock->dev.bus_id);
+				tifm_unmap_sg(sock, &host->bounce_buf, 1,
+					      r_data->flags & MMC_DATA_WRITE
+					      ? PCI_DMA_TODEVICE
+					      : PCI_DMA_FROMDEVICE);
+				spin_unlock_irqrestore(&sock->lock, flags);
+				goto err_out;
+			}
+
+			writel(TIFM_FIFO_INT_SETALL,
+			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+			writel(ilog2(r_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);
+
+			if (r_data->flags & MMC_DATA_WRITE)
+				writel(TIFM_MMCSD_TXDE,
+				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+			else
+				writel(TIFM_MMCSD_RXDE,
+				       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+			tifm_sd_set_dma_data(host, r_data);
+		}
+
+		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;
+	mod_timer(&host->timer, jiffies + 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:
+	mrq->cmd->error = MMC_ERR_TIMEOUT;
+	mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(unsigned long 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);
+
+	del_timer(&host->timer);
+	mrq = host->req;
+	host->req = NULL;
+
+	if (!mrq) {
+		printk(KERN_ERR " %s : no request to complete?\n",
+		       sock->dev.bus_id);
+		spin_unlock_irqrestore(&sock->lock, flags);
+		return;
+	}
+
+	r_data = mrq->cmd->data;
+	if (r_data) {
+		if (host->no_dma) {
+			writel((~TIFM_MMCSD_BUFINT)
+			       & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+			       sock->addr + SOCK_MMCSD_INT_ENABLE);
+		} else {
+			tifm_unmap_sg(sock, &host->bounce_buf, 1,
+				      (r_data->flags & MMC_DATA_WRITE)
+				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+			tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+				      (r_data->flags & MMC_DATA_WRITE)
+				      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		}
+
+		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;
+	}
+
+	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_abort(unsigned long data)
+{
+	struct tifm_sd *host = (struct tifm_sd*)data;
+
+	printk(KERN_ERR
+	       "%s : card failed to respond for a long period of time "
+	       "(%x, %x)\n",
+	       host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);
+
+	tifm_eject(host->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, "ios: clock = %u, vdd = %x, bus_mode = %x, "
+		"chip_select = %x, power_mode = %x, bus_width = %x\n",
+		ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
+		ios->power_mode, ios->bus_width);
+
+	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);
+
+	host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
+
+	/* chip_select : maybe later */
+	//vdd
+	//power is set before probe / after remove
+
+	spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+	int rc = 0;
+	struct tifm_sd *host = mmc_priv(mmc);
+	struct tifm_dev *sock = host->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
+		rc = 1;
+	spin_unlock_irqrestore(&sock->lock, flags);
+	return rc;
+}
+
+static const struct mmc_host_ops tifm_sd_ops = {
+	.request = tifm_sd_request,
+	.set_ios = tifm_sd_ios,
+	.get_ro  = tifm_sd_ro
+};
+
+static int tifm_sd_initialize_host(struct tifm_sd *host)
+{
+	int rc;
+	unsigned int host_status = 0;
+	struct tifm_dev *sock = host->dev;
+
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+	host->clk_div = 61;
+	host->clk_freq = 20000000;
+	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+	       sock->addr + SOCK_MMCSD_CONFIG);
+
+	/* wait up to 0.51 sec for reset */
+	for (rc = 32; rc <= 256; rc <<= 1) {
+		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+			rc = 0;
+			break;
+		}
+		msleep(rc);
+	}
+
+	if (rc) {
+		printk(KERN_ERR "%s : controller failed to reset\n",
+		       sock->dev.bus_id);
+		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);
+
+	// command timeout fixed to 64 clocks for now
+	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+	for (rc = 16; rc <= 64; rc <<= 1) {
+		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+		if (!(host_status & TIFM_MMCSD_ERRMASK)
+		    && (host_status & TIFM_MMCSD_EOC)) {
+			rc = 0;
+			break;
+		}
+		msleep(rc);
+	}
+
+	if (rc) {
+		printk(KERN_ERR
+		       "%s : card not ready - probe failed on initialization\n",
+		       sock->dev.bus_id);
+		return -ENODEV;
+	}
+
+	writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
+	       | TIFM_MMCSD_ERRMASK,
+	       sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+
+	return 0;
+}
+
+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 "%s : card gone, unexpectedly\n",
+		       sock->dev.bus_id);
+		return rc;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	host = mmc_priv(mmc);
+	host->no_dma = no_dma;
+	tifm_set_drvdata(sock, mmc);
+	host->dev = sock;
+	host->timeout_jiffies = msecs_to_jiffies(1000);
+
+	tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
+		     (unsigned long)host);
+	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
+	mmc->ops = &tifm_sd_ops;
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
+	mmc->f_min = 20000000 / 60;
+	mmc->f_max = 24000000;
+
+	mmc->max_blk_count = 2048;
+	mmc->max_hw_segs = mmc->max_blk_count;
+	mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
+	mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
+	mmc->max_req_size = mmc->max_seg_size;
+	mmc->max_phys_segs = mmc->max_hw_segs;
+
+	sock->card_event = tifm_sd_card_event;
+	sock->data_event = tifm_sd_data_event;
+	rc = tifm_sd_initialize_host(host);
+
+	if (!rc)
+		rc = mmc_add_host(mmc);
+	if (!rc)
+		return 0;
+
+	mmc_free_host(mmc);
+	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->eject = 1;
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	mmiowb();
+	spin_unlock_irqrestore(&sock->lock, flags);
+
+	tasklet_kill(&host->finish_tasklet);
+
+	spin_lock_irqsave(&sock->lock, flags);
+	if (host->req) {
+		writel(TIFM_FIFO_INT_SETALL,
+		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+		host->req->cmd->error = MMC_ERR_TIMEOUT;
+		if (host->req->stop)
+			host->req->stop->error = MMC_ERR_TIMEOUT;
+		tasklet_schedule(&host->finish_tasklet);
+	}
+	spin_unlock_irqrestore(&sock->lock, flags);
+	mmc_remove_host(mmc);
+	dev_dbg(&sock->dev, "after remove\n");
+
+	/* The meaning of the bit majority in this constant is unknown. */
+	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+	       sock->addr + SOCK_CONTROL);
+
+	mmc_free_host(mmc);
+}
+
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	int rc;
+
+	rc = mmc_suspend_host(mmc, state);
+	/* The meaning of the bit majority in this constant is unknown. */
+	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+	       sock->addr + SOCK_CONTROL);
+	return rc;
+}
+
+static int tifm_sd_resume(struct tifm_dev *sock)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct tifm_sd *host = mmc_priv(mmc);
+	int rc;
+
+	rc = tifm_sd_initialize_host(host);
+	dev_dbg(&sock->dev, "resume initialize %d\n", rc);
+
+	if (rc)
+		host->eject = 1;
+	else
+		rc = mmc_resume_host(mmc);
+
+	return rc;
+}
+
+#else
+
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct tifm_device_id tifm_sd_id_tbl[] = {
+	{ TIFM_TYPE_SD }, { }
+};
+
+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,
+	.suspend  = tifm_sd_suspend,
+	.resume   = tifm_sd_resume
+};
+
+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/host/wbsd.c b/drivers/mmc/host/wbsd.c
new file mode 100644
index 0000000..867ca6a
--- /dev/null
+++ b/drivers/mmc/host/wbsd.c
@@ -0,0 +1,2061 @@
+/*
+ *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
+ *
+ *  Copyright (C) 2004-2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ *
+ * Warning!
+ *
+ * Changes to the FIFO system should be done with extreme care since
+ * the hardware is full of bugs related to the FIFO. Known issues are:
+ *
+ * - FIFO size field in FSR is always zero.
+ *
+ * - FIFO interrupts tend not to work as they should. Interrupts are
+ *   triggered only for full/empty events, not for threshold values.
+ *
+ * - On APIC systems the FIFO empty interrupt is sometimes lost.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/pnp.h>
+#include <linux/highmem.h>
+#include <linux/mmc/host.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/scatterlist.h>
+
+#include "wbsd.h"
+
+#define DRIVER_NAME "wbsd"
+
+#define DBG(x...) \
+	pr_debug(DRIVER_NAME ": " x)
+#define DBGF(f, x...) \
+	pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x)
+
+/*
+ * Device resources
+ */
+
+#ifdef CONFIG_PNP
+
+static const struct pnp_device_id pnp_dev_table[] = {
+	{ "WEC0517", 0 },
+	{ "WEC0518", 0 },
+	{ "", 0 },
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+#endif /* CONFIG_PNP */
+
+static const int config_ports[] = { 0x2E, 0x4E };
+static const int unlock_codes[] = { 0x83, 0x87 };
+
+static const int valid_ids[] = {
+	0x7112,
+	};
+
+#ifdef CONFIG_PNP
+static unsigned int nopnp = 0;
+#else
+static const unsigned int nopnp = 1;
+#endif
+static unsigned int io = 0x248;
+static unsigned int irq = 6;
+static int dma = 2;
+
+/*
+ * Basic functions
+ */
+
+static inline void wbsd_unlock_config(struct wbsd_host *host)
+{
+	BUG_ON(host->config == 0);
+
+	outb(host->unlock_code, host->config);
+	outb(host->unlock_code, host->config);
+}
+
+static inline void wbsd_lock_config(struct wbsd_host *host)
+{
+	BUG_ON(host->config == 0);
+
+	outb(LOCK_CODE, host->config);
+}
+
+static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
+{
+	BUG_ON(host->config == 0);
+
+	outb(reg, host->config);
+	outb(value, host->config + 1);
+}
+
+static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
+{
+	BUG_ON(host->config == 0);
+
+	outb(reg, host->config);
+	return inb(host->config + 1);
+}
+
+static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
+{
+	outb(index, host->base + WBSD_IDXR);
+	outb(value, host->base + WBSD_DATAR);
+}
+
+static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
+{
+	outb(index, host->base + WBSD_IDXR);
+	return inb(host->base + WBSD_DATAR);
+}
+
+/*
+ * Common routines
+ */
+
+static void wbsd_init_device(struct wbsd_host *host)
+{
+	u8 setup, ier;
+
+	/*
+	 * Reset chip (SD/MMC part) and fifo.
+	 */
+	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+	setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+	/*
+	 * Set DAT3 to input
+	 */
+	setup &= ~WBSD_DAT3_H;
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+	host->flags &= ~WBSD_FIGNORE_DETECT;
+
+	/*
+	 * Read back default clock.
+	 */
+	host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
+
+	/*
+	 * Power down port.
+	 */
+	outb(WBSD_POWER_N, host->base + WBSD_CSR);
+
+	/*
+	 * Set maximum timeout.
+	 */
+	wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
+
+	/*
+	 * Test for card presence
+	 */
+	if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
+		host->flags |= WBSD_FCARD_PRESENT;
+	else
+		host->flags &= ~WBSD_FCARD_PRESENT;
+
+	/*
+	 * Enable interesting interrupts.
+	 */
+	ier = 0;
+	ier |= WBSD_EINT_CARD;
+	ier |= WBSD_EINT_FIFO_THRE;
+	ier |= WBSD_EINT_CRC;
+	ier |= WBSD_EINT_TIMEOUT;
+	ier |= WBSD_EINT_TC;
+
+	outb(ier, host->base + WBSD_EIR);
+
+	/*
+	 * Clear interrupts.
+	 */
+	inb(host->base + WBSD_ISR);
+}
+
+static void wbsd_reset(struct wbsd_host *host)
+{
+	u8 setup;
+
+	printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc));
+
+	/*
+	 * Soft reset of chip (SD/MMC part).
+	 */
+	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+	setup |= WBSD_SOFT_RESET;
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+}
+
+static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
+{
+	unsigned long dmaflags;
+
+	DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
+
+	if (host->dma >= 0) {
+		/*
+		 * Release ISA DMA controller.
+		 */
+		dmaflags = claim_dma_lock();
+		disable_dma(host->dma);
+		clear_dma_ff(host->dma);
+		release_dma_lock(dmaflags);
+
+		/*
+		 * Disable DMA on host.
+		 */
+		wbsd_write_index(host, WBSD_IDX_DMA, 0);
+	}
+
+	host->mrq = NULL;
+
+	/*
+	 * MMC layer might call back into the driver so first unlock.
+	 */
+	spin_unlock(&host->lock);
+	mmc_request_done(host->mmc, mrq);
+	spin_lock(&host->lock);
+}
+
+/*
+ * Scatter/gather functions
+ */
+
+static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
+{
+	/*
+	 * Get info. about SG list from data structure.
+	 */
+	host->cur_sg = data->sg;
+	host->num_sg = data->sg_len;
+
+	host->offset = 0;
+	host->remain = host->cur_sg->length;
+}
+
+static inline int wbsd_next_sg(struct wbsd_host *host)
+{
+	/*
+	 * Skip to next SG entry.
+	 */
+	host->cur_sg++;
+	host->num_sg--;
+
+	/*
+	 * Any entries left?
+	 */
+	if (host->num_sg > 0) {
+		host->offset = 0;
+		host->remain = host->cur_sg->length;
+	}
+
+	return host->num_sg;
+}
+
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
+{
+	return page_address(host->cur_sg->page) + host->cur_sg->offset;
+}
+
+static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
+{
+	unsigned int len, i;
+	struct scatterlist *sg;
+	char *dmabuf = host->dma_buffer;
+	char *sgbuf;
+
+	sg = data->sg;
+	len = data->sg_len;
+
+	for (i = 0; i < len; i++) {
+		sgbuf = page_address(sg[i].page) + sg[i].offset;
+		memcpy(dmabuf, sgbuf, sg[i].length);
+		dmabuf += sg[i].length;
+	}
+}
+
+static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
+{
+	unsigned int len, i;
+	struct scatterlist *sg;
+	char *dmabuf = host->dma_buffer;
+	char *sgbuf;
+
+	sg = data->sg;
+	len = data->sg_len;
+
+	for (i = 0; i < len; i++) {
+		sgbuf = page_address(sg[i].page) + sg[i].offset;
+		memcpy(sgbuf, dmabuf, sg[i].length);
+		dmabuf += sg[i].length;
+	}
+}
+
+/*
+ * Command handling
+ */
+
+static inline void wbsd_get_short_reply(struct wbsd_host *host,
+					struct mmc_command *cmd)
+{
+	/*
+	 * Correct response type?
+	 */
+	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
+		cmd->error = MMC_ERR_INVALID;
+		return;
+	}
+
+	cmd->resp[0]  = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
+	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
+	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
+	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
+	cmd->resp[1]  = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
+}
+
+static inline void wbsd_get_long_reply(struct wbsd_host *host,
+	struct mmc_command *cmd)
+{
+	int i;
+
+	/*
+	 * Correct response type?
+	 */
+	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
+		cmd->error = MMC_ERR_INVALID;
+		return;
+	}
+
+	for (i = 0; i < 4; i++) {
+		cmd->resp[i] =
+			wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
+		cmd->resp[i] |=
+			wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
+		cmd->resp[i] |=
+			wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
+		cmd->resp[i] |=
+			wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
+	}
+}
+
+static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
+{
+	int i;
+	u8 status, isr;
+
+	DBGF("Sending cmd (%x)\n", cmd->opcode);
+
+	/*
+	 * Clear accumulated ISR. The interrupt routine
+	 * will fill this one with events that occur during
+	 * transfer.
+	 */
+	host->isr = 0;
+
+	/*
+	 * Send the command (CRC calculated by host).
+	 */
+	outb(cmd->opcode, host->base + WBSD_CMDR);
+	for (i = 3; i >= 0; i--)
+		outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
+
+	cmd->error = MMC_ERR_NONE;
+
+	/*
+	 * Wait for the request to complete.
+	 */
+	do {
+		status = wbsd_read_index(host, WBSD_IDX_STATUS);
+	} while (status & WBSD_CARDTRAFFIC);
+
+	/*
+	 * Do we expect a reply?
+	 */
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		/*
+		 * Read back status.
+		 */
+		isr = host->isr;
+
+		/* Card removed? */
+		if (isr & WBSD_INT_CARD)
+			cmd->error = MMC_ERR_TIMEOUT;
+		/* Timeout? */
+		else if (isr & WBSD_INT_TIMEOUT)
+			cmd->error = MMC_ERR_TIMEOUT;
+		/* CRC? */
+		else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
+			cmd->error = MMC_ERR_BADCRC;
+		/* All ok */
+		else {
+			if (cmd->flags & MMC_RSP_136)
+				wbsd_get_long_reply(host, cmd);
+			else
+				wbsd_get_short_reply(host, cmd);
+		}
+	}
+
+	DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
+}
+
+/*
+ * Data functions
+ */
+
+static void wbsd_empty_fifo(struct wbsd_host *host)
+{
+	struct mmc_data *data = host->mrq->cmd->data;
+	char *buffer;
+	int i, fsr, fifo;
+
+	/*
+	 * Handle excessive data.
+	 */
+	if (host->num_sg == 0)
+		return;
+
+	buffer = wbsd_sg_to_buffer(host) + host->offset;
+
+	/*
+	 * Drain the fifo. This has a tendency to loop longer
+	 * than the FIFO length (usually one block).
+	 */
+	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
+		/*
+		 * The size field in the FSR is broken so we have to
+		 * do some guessing.
+		 */
+		if (fsr & WBSD_FIFO_FULL)
+			fifo = 16;
+		else if (fsr & WBSD_FIFO_FUTHRE)
+			fifo = 8;
+		else
+			fifo = 1;
+
+		for (i = 0; i < fifo; i++) {
+			*buffer = inb(host->base + WBSD_DFR);
+			buffer++;
+			host->offset++;
+			host->remain--;
+
+			data->bytes_xfered++;
+
+			/*
+			 * End of scatter list entry?
+			 */
+			if (host->remain == 0) {
+				/*
+				 * Get next entry. Check if last.
+				 */
+				if (!wbsd_next_sg(host))
+					return;
+
+				buffer = wbsd_sg_to_buffer(host);
+			}
+		}
+	}
+
+	/*
+	 * This is a very dirty hack to solve a
+	 * hardware problem. The chip doesn't trigger
+	 * FIFO threshold interrupts properly.
+	 */
+	if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
+		tasklet_schedule(&host->fifo_tasklet);
+}
+
+static void wbsd_fill_fifo(struct wbsd_host *host)
+{
+	struct mmc_data *data = host->mrq->cmd->data;
+	char *buffer;
+	int i, fsr, fifo;
+
+	/*
+	 * Check that we aren't being called after the
+	 * entire buffer has been transfered.
+	 */
+	if (host->num_sg == 0)
+		return;
+
+	buffer = wbsd_sg_to_buffer(host) + host->offset;
+
+	/*
+	 * Fill the fifo. This has a tendency to loop longer
+	 * than the FIFO length (usually one block).
+	 */
+	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
+		/*
+		 * The size field in the FSR is broken so we have to
+		 * do some guessing.
+		 */
+		if (fsr & WBSD_FIFO_EMPTY)
+			fifo = 0;
+		else if (fsr & WBSD_FIFO_EMTHRE)
+			fifo = 8;
+		else
+			fifo = 15;
+
+		for (i = 16; i > fifo; i--) {
+			outb(*buffer, host->base + WBSD_DFR);
+			buffer++;
+			host->offset++;
+			host->remain--;
+
+			data->bytes_xfered++;
+
+			/*
+			 * End of scatter list entry?
+			 */
+			if (host->remain == 0) {
+				/*
+				 * Get next entry. Check if last.
+				 */
+				if (!wbsd_next_sg(host))
+					return;
+
+				buffer = wbsd_sg_to_buffer(host);
+			}
+		}
+	}
+
+	/*
+	 * The controller stops sending interrupts for
+	 * 'FIFO empty' under certain conditions. So we
+	 * need to be a bit more pro-active.
+	 */
+	tasklet_schedule(&host->fifo_tasklet);
+}
+
+static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
+{
+	u16 blksize;
+	u8 setup;
+	unsigned long dmaflags;
+	unsigned int size;
+
+	DBGF("blksz %04x blks %04x flags %08x\n",
+		data->blksz, data->blocks, data->flags);
+	DBGF("tsac %d ms nsac %d clk\n",
+		data->timeout_ns / 1000000, data->timeout_clks);
+
+	/*
+	 * Calculate size.
+	 */
+	size = data->blocks * data->blksz;
+
+	/*
+	 * Check timeout values for overflow.
+	 * (Yes, some cards cause this value to overflow).
+	 */
+	if (data->timeout_ns > 127000000)
+		wbsd_write_index(host, WBSD_IDX_TAAC, 127);
+	else {
+		wbsd_write_index(host, WBSD_IDX_TAAC,
+			data->timeout_ns / 1000000);
+	}
+
+	if (data->timeout_clks > 255)
+		wbsd_write_index(host, WBSD_IDX_NSAC, 255);
+	else
+		wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
+
+	/*
+	 * Inform the chip of how large blocks will be
+	 * sent. It needs this to determine when to
+	 * calculate CRC.
+	 *
+	 * Space for CRC must be included in the size.
+	 * Two bytes are needed for each data line.
+	 */
+	if (host->bus_width == MMC_BUS_WIDTH_1) {
+		blksize = data->blksz + 2;
+
+		wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
+		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+	} else if (host->bus_width == MMC_BUS_WIDTH_4) {
+		blksize = data->blksz + 2 * 4;
+
+		wbsd_write_index(host, WBSD_IDX_PBSMSB,
+			((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
+		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
+	} else {
+		data->error = MMC_ERR_INVALID;
+		return;
+	}
+
+	/*
+	 * Clear the FIFO. This is needed even for DMA
+	 * transfers since the chip still uses the FIFO
+	 * internally.
+	 */
+	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+	setup |= WBSD_FIFO_RESET;
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+	/*
+	 * DMA transfer?
+	 */
+	if (host->dma >= 0) {
+		/*
+		 * The buffer for DMA is only 64 kB.
+		 */
+		BUG_ON(size > 0x10000);
+		if (size > 0x10000) {
+			data->error = MMC_ERR_INVALID;
+			return;
+		}
+
+		/*
+		 * Transfer data from the SG list to
+		 * the DMA buffer.
+		 */
+		if (data->flags & MMC_DATA_WRITE)
+			wbsd_sg_to_dma(host, data);
+
+		/*
+		 * Initialise the ISA DMA controller.
+		 */
+		dmaflags = claim_dma_lock();
+		disable_dma(host->dma);
+		clear_dma_ff(host->dma);
+		if (data->flags & MMC_DATA_READ)
+			set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
+		else
+			set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
+		set_dma_addr(host->dma, host->dma_addr);
+		set_dma_count(host->dma, size);
+
+		enable_dma(host->dma);
+		release_dma_lock(dmaflags);
+
+		/*
+		 * Enable DMA on the host.
+		 */
+		wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
+	} else {
+		/*
+		 * This flag is used to keep printk
+		 * output to a minimum.
+		 */
+		host->firsterr = 1;
+
+		/*
+		 * Initialise the SG list.
+		 */
+		wbsd_init_sg(host, data);
+
+		/*
+		 * Turn off DMA.
+		 */
+		wbsd_write_index(host, WBSD_IDX_DMA, 0);
+
+		/*
+		 * Set up FIFO threshold levels (and fill
+		 * buffer if doing a write).
+		 */
+		if (data->flags & MMC_DATA_READ) {
+			wbsd_write_index(host, WBSD_IDX_FIFOEN,
+				WBSD_FIFOEN_FULL | 8);
+		} else {
+			wbsd_write_index(host, WBSD_IDX_FIFOEN,
+				WBSD_FIFOEN_EMPTY | 8);
+			wbsd_fill_fifo(host);
+		}
+	}
+
+	data->error = MMC_ERR_NONE;
+}
+
+static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
+{
+	unsigned long dmaflags;
+	int count;
+	u8 status;
+
+	WARN_ON(host->mrq == NULL);
+
+	/*
+	 * Send a stop command if needed.
+	 */
+	if (data->stop)
+		wbsd_send_command(host, data->stop);
+
+	/*
+	 * Wait for the controller to leave data
+	 * transfer state.
+	 */
+	do {
+		status = wbsd_read_index(host, WBSD_IDX_STATUS);
+	} while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
+
+	/*
+	 * DMA transfer?
+	 */
+	if (host->dma >= 0) {
+		/*
+		 * Disable DMA on the host.
+		 */
+		wbsd_write_index(host, WBSD_IDX_DMA, 0);
+
+		/*
+		 * Turn of ISA DMA controller.
+		 */
+		dmaflags = claim_dma_lock();
+		disable_dma(host->dma);
+		clear_dma_ff(host->dma);
+		count = get_dma_residue(host->dma);
+		release_dma_lock(dmaflags);
+
+		data->bytes_xfered = host->mrq->data->blocks *
+			host->mrq->data->blksz - count;
+		data->bytes_xfered -= data->bytes_xfered % data->blksz;
+
+		/*
+		 * Any leftover data?
+		 */
+		if (count) {
+			printk(KERN_ERR "%s: Incomplete DMA transfer. "
+				"%d bytes left.\n",
+				mmc_hostname(host->mmc), count);
+
+			if (data->error == MMC_ERR_NONE)
+				data->error = MMC_ERR_FAILED;
+		} else {
+			/*
+			 * Transfer data from DMA buffer to
+			 * SG list.
+			 */
+			if (data->flags & MMC_DATA_READ)
+				wbsd_dma_to_sg(host, data);
+		}
+
+		if (data->error != MMC_ERR_NONE) {
+			if (data->bytes_xfered)
+				data->bytes_xfered -= data->blksz;
+		}
+	}
+
+	DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
+
+	wbsd_request_end(host, host->mrq);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * MMC layer callbacks                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct wbsd_host *host = mmc_priv(mmc);
+	struct mmc_command *cmd;
+
+	/*
+	 * Disable tasklets to avoid a deadlock.
+	 */
+	spin_lock_bh(&host->lock);
+
+	BUG_ON(host->mrq != NULL);
+
+	cmd = mrq->cmd;
+
+	host->mrq = mrq;
+
+	/*
+	 * If there is no card in the slot then
+	 * timeout immediatly.
+	 */
+	if (!(host->flags & WBSD_FCARD_PRESENT)) {
+		cmd->error = MMC_ERR_TIMEOUT;
+		goto done;
+	}
+
+	if (cmd->data) {
+		/*
+		 * The hardware is so delightfully stupid that it has a list
+		 * of "data" commands. If a command isn't on this list, it'll
+		 * just go back to the idle state and won't send any data
+		 * interrupts.
+		 */
+		switch (cmd->opcode) {
+		case 11:
+		case 17:
+		case 18:
+		case 20:
+		case 24:
+		case 25:
+		case 26:
+		case 27:
+		case 30:
+		case 42:
+		case 56:
+			break;
+
+		/* ACMDs. We don't keep track of state, so we just treat them
+		 * like any other command. */
+		case 51:
+			break;
+
+		default:
+#ifdef CONFIG_MMC_DEBUG
+			printk(KERN_WARNING "%s: Data command %d is not "
+				"supported by this controller.\n",
+				mmc_hostname(host->mmc), cmd->opcode);
+#endif
+			cmd->error = MMC_ERR_INVALID;
+
+			goto done;
+		};
+	}
+
+	/*
+	 * Does the request include data?
+	 */
+	if (cmd->data) {
+		wbsd_prepare_data(host, cmd->data);
+
+		if (cmd->data->error != MMC_ERR_NONE)
+			goto done;
+	}
+
+	wbsd_send_command(host, cmd);
+
+	/*
+	 * If this is a data transfer the request
+	 * will be finished after the data has
+	 * transfered.
+	 */
+	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+		/*
+		 * Dirty fix for hardware bug.
+		 */
+		if (host->dma == -1)
+			tasklet_schedule(&host->fifo_tasklet);
+
+		spin_unlock_bh(&host->lock);
+
+		return;
+	}
+
+done:
+	wbsd_request_end(host, mrq);
+
+	spin_unlock_bh(&host->lock);
+}
+
+static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct wbsd_host *host = mmc_priv(mmc);
+	u8 clk, setup, pwr;
+
+	spin_lock_bh(&host->lock);
+
+	/*
+	 * Reset the chip on each power off.
+	 * Should clear out any weird states.
+	 */
+	if (ios->power_mode == MMC_POWER_OFF)
+		wbsd_init_device(host);
+
+	if (ios->clock >= 24000000)
+		clk = WBSD_CLK_24M;
+	else if (ios->clock >= 16000000)
+		clk = WBSD_CLK_16M;
+	else if (ios->clock >= 12000000)
+		clk = WBSD_CLK_12M;
+	else
+		clk = WBSD_CLK_375K;
+
+	/*
+	 * Only write to the clock register when
+	 * there is an actual change.
+	 */
+	if (clk != host->clk) {
+		wbsd_write_index(host, WBSD_IDX_CLK, clk);
+		host->clk = clk;
+	}
+
+	/*
+	 * Power up card.
+	 */
+	if (ios->power_mode != MMC_POWER_OFF) {
+		pwr = inb(host->base + WBSD_CSR);
+		pwr &= ~WBSD_POWER_N;
+		outb(pwr, host->base + WBSD_CSR);
+	}
+
+	/*
+	 * MMC cards need to have pin 1 high during init.
+	 * It wreaks havoc with the card detection though so
+	 * that needs to be disabled.
+	 */
+	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+	if (ios->chip_select == MMC_CS_HIGH) {
+		BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
+		setup |= WBSD_DAT3_H;
+		host->flags |= WBSD_FIGNORE_DETECT;
+	} else {
+		if (setup & WBSD_DAT3_H) {
+			setup &= ~WBSD_DAT3_H;
+
+			/*
+			 * We cannot resume card detection immediatly
+			 * because of capacitance and delays in the chip.
+			 */
+			mod_timer(&host->ignore_timer, jiffies + HZ / 100);
+		}
+	}
+	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+
+	/*
+	 * Store bus width for later. Will be used when
+	 * setting up the data transfer.
+	 */
+	host->bus_width = ios->bus_width;
+
+	spin_unlock_bh(&host->lock);
+}
+
+static int wbsd_get_ro(struct mmc_host *mmc)
+{
+	struct wbsd_host *host = mmc_priv(mmc);
+	u8 csr;
+
+	spin_lock_bh(&host->lock);
+
+	csr = inb(host->base + WBSD_CSR);
+	csr |= WBSD_MSLED;
+	outb(csr, host->base + WBSD_CSR);
+
+	mdelay(1);
+
+	csr = inb(host->base + WBSD_CSR);
+	csr &= ~WBSD_MSLED;
+	outb(csr, host->base + WBSD_CSR);
+
+	spin_unlock_bh(&host->lock);
+
+	return csr & WBSD_WRPT;
+}
+
+static const struct mmc_host_ops wbsd_ops = {
+	.request	= wbsd_request,
+	.set_ios	= wbsd_set_ios,
+	.get_ro		= wbsd_get_ro,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+/*
+ * Helper function to reset detection ignore
+ */
+
+static void wbsd_reset_ignore(unsigned long data)
+{
+	struct wbsd_host *host = (struct wbsd_host *)data;
+
+	BUG_ON(host == NULL);
+
+	DBG("Resetting card detection ignore\n");
+
+	spin_lock_bh(&host->lock);
+
+	host->flags &= ~WBSD_FIGNORE_DETECT;
+
+	/*
+	 * Card status might have changed during the
+	 * blackout.
+	 */
+	tasklet_schedule(&host->card_tasklet);
+
+	spin_unlock_bh(&host->lock);
+}
+
+/*
+ * Tasklets
+ */
+
+static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
+{
+	WARN_ON(!host->mrq);
+	if (!host->mrq)
+		return NULL;
+
+	WARN_ON(!host->mrq->cmd);
+	if (!host->mrq->cmd)
+		return NULL;
+
+	WARN_ON(!host->mrq->cmd->data);
+	if (!host->mrq->cmd->data)
+		return NULL;
+
+	return host->mrq->cmd->data;
+}
+
+static void wbsd_tasklet_card(unsigned long param)
+{
+	struct wbsd_host *host = (struct wbsd_host *)param;
+	u8 csr;
+	int delay = -1;
+
+	spin_lock(&host->lock);
+
+	if (host->flags & WBSD_FIGNORE_DETECT) {
+		spin_unlock(&host->lock);
+		return;
+	}
+
+	csr = inb(host->base + WBSD_CSR);
+	WARN_ON(csr == 0xff);
+
+	if (csr & WBSD_CARDPRESENT) {
+		if (!(host->flags & WBSD_FCARD_PRESENT)) {
+			DBG("Card inserted\n");
+			host->flags |= WBSD_FCARD_PRESENT;
+
+			delay = 500;
+		}
+	} else if (host->flags & WBSD_FCARD_PRESENT) {
+		DBG("Card removed\n");
+		host->flags &= ~WBSD_FCARD_PRESENT;
+
+		if (host->mrq) {
+			printk(KERN_ERR "%s: Card removed during transfer!\n",
+				mmc_hostname(host->mmc));
+			wbsd_reset(host);
+
+			host->mrq->cmd->error = MMC_ERR_FAILED;
+			tasklet_schedule(&host->finish_tasklet);
+		}
+
+		delay = 0;
+	}
+
+	/*
+	 * Unlock first since we might get a call back.
+	 */
+
+	spin_unlock(&host->lock);
+
+	if (delay != -1)
+		mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
+}
+
+static void wbsd_tasklet_fifo(unsigned long param)
+{
+	struct wbsd_host *host = (struct wbsd_host *)param;
+	struct mmc_data *data;
+
+	spin_lock(&host->lock);
+
+	if (!host->mrq)
+		goto end;
+
+	data = wbsd_get_data(host);
+	if (!data)
+		goto end;
+
+	if (data->flags & MMC_DATA_WRITE)
+		wbsd_fill_fifo(host);
+	else
+		wbsd_empty_fifo(host);
+
+	/*
+	 * Done?
+	 */
+	if (host->num_sg == 0) {
+		wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
+		tasklet_schedule(&host->finish_tasklet);
+	}
+
+end:
+	spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_crc(unsigned long param)
+{
+	struct wbsd_host *host = (struct wbsd_host *)param;
+	struct mmc_data *data;
+
+	spin_lock(&host->lock);
+
+	if (!host->mrq)
+		goto end;
+
+	data = wbsd_get_data(host);
+	if (!data)
+		goto end;
+
+	DBGF("CRC error\n");
+
+	data->error = MMC_ERR_BADCRC;
+
+	tasklet_schedule(&host->finish_tasklet);
+
+end:
+	spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_timeout(unsigned long param)
+{
+	struct wbsd_host *host = (struct wbsd_host *)param;
+	struct mmc_data *data;
+
+	spin_lock(&host->lock);
+
+	if (!host->mrq)
+		goto end;
+
+	data = wbsd_get_data(host);
+	if (!data)
+		goto end;
+
+	DBGF("Timeout\n");
+
+	data->error = MMC_ERR_TIMEOUT;
+
+	tasklet_schedule(&host->finish_tasklet);
+
+end:
+	spin_unlock(&host->lock);
+}
+
+static void wbsd_tasklet_finish(unsigned long param)
+{
+	struct wbsd_host *host = (struct wbsd_host *)param;
+	struct mmc_data *data;
+
+	spin_lock(&host->lock);
+
+	WARN_ON(!host->mrq);
+	if (!host->mrq)
+		goto end;
+
+	data = wbsd_get_data(host);
+	if (!data)
+		goto end;
+
+	wbsd_finish_data(host, data);
+
+end:
+	spin_unlock(&host->lock);
+}
+
+/*
+ * Interrupt handling
+ */
+
+static irqreturn_t wbsd_irq(int irq, void *dev_id)
+{
+	struct wbsd_host *host = dev_id;
+	int isr;
+
+	isr = inb(host->base + WBSD_ISR);
+
+	/*
+	 * Was it actually our hardware that caused the interrupt?
+	 */
+	if (isr == 0xff || isr == 0x00)
+		return IRQ_NONE;
+
+	host->isr |= isr;
+
+	/*
+	 * Schedule tasklets as needed.
+	 */
+	if (isr & WBSD_INT_CARD)
+		tasklet_schedule(&host->card_tasklet);
+	if (isr & WBSD_INT_FIFO_THRE)
+		tasklet_schedule(&host->fifo_tasklet);
+	if (isr & WBSD_INT_CRC)
+		tasklet_hi_schedule(&host->crc_tasklet);
+	if (isr & WBSD_INT_TIMEOUT)
+		tasklet_hi_schedule(&host->timeout_tasklet);
+	if (isr & WBSD_INT_TC)
+		tasklet_schedule(&host->finish_tasklet);
+
+	return IRQ_HANDLED;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device initialisation and shutdown                                        *
+ *                                                                           *
+\*****************************************************************************/
+
+/*
+ * Allocate/free MMC structure.
+ */
+
+static int __devinit wbsd_alloc_mmc(struct device *dev)
+{
+	struct mmc_host *mmc;
+	struct wbsd_host *host;
+
+	/*
+	 * Allocate MMC structure.
+	 */
+	mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+
+	host->dma = -1;
+
+	/*
+	 * Set host parameters.
+	 */
+	mmc->ops = &wbsd_ops;
+	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_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+	spin_lock_init(&host->lock);
+
+	/*
+	 * Set up timers
+	 */
+	init_timer(&host->ignore_timer);
+	host->ignore_timer.data = (unsigned long)host;
+	host->ignore_timer.function = wbsd_reset_ignore;
+
+	/*
+	 * Maximum number of segments. Worst case is one sector per segment
+	 * so this will be 64kB/512.
+	 */
+	mmc->max_hw_segs = 128;
+	mmc->max_phys_segs = 128;
+
+	/*
+	 * Maximum request size. Also limited by 64KiB buffer.
+	 */
+	mmc->max_req_size = 65536;
+
+	/*
+	 * Maximum segment size. Could be one segment with the maximum number
+	 * of bytes.
+	 */
+	mmc->max_seg_size = mmc->max_req_size;
+
+	/*
+	 * Maximum block size. We have 12 bits (= 4095) but have to subtract
+	 * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+	 */
+	mmc->max_blk_size = 4087;
+
+	/*
+	 * Maximum block count. There is no real limit so the maximum
+	 * request size will be the only restriction.
+	 */
+	mmc->max_blk_count = mmc->max_req_size;
+
+	dev_set_drvdata(dev, mmc);
+
+	return 0;
+}
+
+static void __devexit wbsd_free_mmc(struct device *dev)
+{
+	struct mmc_host *mmc;
+	struct wbsd_host *host;
+
+	mmc = dev_get_drvdata(dev);
+	if (!mmc)
+		return;
+
+	host = mmc_priv(mmc);
+	BUG_ON(host == NULL);
+
+	del_timer_sync(&host->ignore_timer);
+
+	mmc_free_host(mmc);
+
+	dev_set_drvdata(dev, NULL);
+}
+
+/*
+ * Scan for known chip id:s
+ */
+
+static int __devinit wbsd_scan(struct wbsd_host *host)
+{
+	int i, j, k;
+	int id;
+
+	/*
+	 * Iterate through all ports, all codes to
+	 * find hardware that is in our known list.
+	 */
+	for (i = 0; i < ARRAY_SIZE(config_ports); i++) {
+		if (!request_region(config_ports[i], 2, DRIVER_NAME))
+			continue;
+
+		for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
+			id = 0xFFFF;
+
+			host->config = config_ports[i];
+			host->unlock_code = unlock_codes[j];
+
+			wbsd_unlock_config(host);
+
+			outb(WBSD_CONF_ID_HI, config_ports[i]);
+			id = inb(config_ports[i] + 1) << 8;
+
+			outb(WBSD_CONF_ID_LO, config_ports[i]);
+			id |= inb(config_ports[i] + 1);
+
+			wbsd_lock_config(host);
+
+			for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
+				if (id == valid_ids[k]) {
+					host->chip_id = id;
+
+					return 0;
+				}
+			}
+
+			if (id != 0xFFFF) {
+				DBG("Unknown hardware (id %x) found at %x\n",
+					id, config_ports[i]);
+			}
+		}
+
+		release_region(config_ports[i], 2);
+	}
+
+	host->config = 0;
+	host->unlock_code = 0;
+
+	return -ENODEV;
+}
+
+/*
+ * Allocate/free io port ranges
+ */
+
+static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
+{
+	if (base & 0x7)
+		return -EINVAL;
+
+	if (!request_region(base, 8, DRIVER_NAME))
+		return -EIO;
+
+	host->base = base;
+
+	return 0;
+}
+
+static void __devexit wbsd_release_regions(struct wbsd_host *host)
+{
+	if (host->base)
+		release_region(host->base, 8);
+
+	host->base = 0;
+
+	if (host->config)
+		release_region(host->config, 2);
+
+	host->config = 0;
+}
+
+/*
+ * Allocate/free DMA port and buffer
+ */
+
+static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
+{
+	if (dma < 0)
+		return;
+
+	if (request_dma(dma, DRIVER_NAME))
+		goto err;
+
+	/*
+	 * We need to allocate a special buffer in
+	 * order for ISA to be able to DMA to it.
+	 */
+	host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
+		GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
+	if (!host->dma_buffer)
+		goto free;
+
+	/*
+	 * Translate the address to a physical address.
+	 */
+	host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,
+		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+
+	/*
+	 * ISA DMA must be aligned on a 64k basis.
+	 */
+	if ((host->dma_addr & 0xffff) != 0)
+		goto kfree;
+	/*
+	 * ISA cannot access memory above 16 MB.
+	 */
+	else if (host->dma_addr >= 0x1000000)
+		goto kfree;
+
+	host->dma = dma;
+
+	return;
+
+kfree:
+	/*
+	 * If we've gotten here then there is some kind of alignment bug
+	 */
+	BUG_ON(1);
+
+	dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
+		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+	host->dma_addr = (dma_addr_t)NULL;
+
+	kfree(host->dma_buffer);
+	host->dma_buffer = NULL;
+
+free:
+	free_dma(dma);
+
+err:
+	printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
+		"Falling back on FIFO.\n", dma);
+}
+
+static void __devexit wbsd_release_dma(struct wbsd_host *host)
+{
+	if (host->dma_addr) {
+		dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
+			WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+	}
+	kfree(host->dma_buffer);
+	if (host->dma >= 0)
+		free_dma(host->dma);
+
+	host->dma = -1;
+	host->dma_buffer = NULL;
+	host->dma_addr = (dma_addr_t)NULL;
+}
+
+/*
+ * Allocate/free IRQ.
+ */
+
+static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
+{
+	int ret;
+
+	/*
+	 * Allocate interrupt.
+	 */
+
+	ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
+	if (ret)
+		return ret;
+
+	host->irq = irq;
+
+	/*
+	 * Set up tasklets.
+	 */
+	tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
+			(unsigned long)host);
+	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
+			(unsigned long)host);
+	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
+			(unsigned long)host);
+	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
+			(unsigned long)host);
+	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
+			(unsigned long)host);
+
+	return 0;
+}
+
+static void __devexit wbsd_release_irq(struct wbsd_host *host)
+{
+	if (!host->irq)
+		return;
+
+	free_irq(host->irq, host);
+
+	host->irq = 0;
+
+	tasklet_kill(&host->card_tasklet);
+	tasklet_kill(&host->fifo_tasklet);
+	tasklet_kill(&host->crc_tasklet);
+	tasklet_kill(&host->timeout_tasklet);
+	tasklet_kill(&host->finish_tasklet);
+}
+
+/*
+ * Allocate all resources for the host.
+ */
+
+static int __devinit wbsd_request_resources(struct wbsd_host *host,
+	int base, int irq, int dma)
+{
+	int ret;
+
+	/*
+	 * Allocate I/O ports.
+	 */
+	ret = wbsd_request_region(host, base);
+	if (ret)
+		return ret;
+
+	/*
+	 * Allocate interrupt.
+	 */
+	ret = wbsd_request_irq(host, irq);
+	if (ret)
+		return ret;
+
+	/*
+	 * Allocate DMA.
+	 */
+	wbsd_request_dma(host, dma);
+
+	return 0;
+}
+
+/*
+ * Release all resources for the host.
+ */
+
+static void __devexit wbsd_release_resources(struct wbsd_host *host)
+{
+	wbsd_release_dma(host);
+	wbsd_release_irq(host);
+	wbsd_release_regions(host);
+}
+
+/*
+ * Configure the resources the chip should use.
+ */
+
+static void wbsd_chip_config(struct wbsd_host *host)
+{
+	wbsd_unlock_config(host);
+
+	/*
+	 * Reset the chip.
+	 */
+	wbsd_write_config(host, WBSD_CONF_SWRST, 1);
+	wbsd_write_config(host, WBSD_CONF_SWRST, 0);
+
+	/*
+	 * Select SD/MMC function.
+	 */
+	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+
+	/*
+	 * Set up card detection.
+	 */
+	wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
+
+	/*
+	 * Configure chip
+	 */
+	wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
+	wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
+
+	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
+
+	if (host->dma >= 0)
+		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
+
+	/*
+	 * Enable and power up chip.
+	 */
+	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+
+	wbsd_lock_config(host);
+}
+
+/*
+ * Check that configured resources are correct.
+ */
+
+static int wbsd_chip_validate(struct wbsd_host *host)
+{
+	int base, irq, dma;
+
+	wbsd_unlock_config(host);
+
+	/*
+	 * Select SD/MMC function.
+	 */
+	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+
+	/*
+	 * Read configuration.
+	 */
+	base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
+	base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
+
+	irq = wbsd_read_config(host, WBSD_CONF_IRQ);
+
+	dma = wbsd_read_config(host, WBSD_CONF_DRQ);
+
+	wbsd_lock_config(host);
+
+	/*
+	 * Validate against given configuration.
+	 */
+	if (base != host->base)
+		return 0;
+	if (irq != host->irq)
+		return 0;
+	if ((dma != host->dma) && (host->dma != -1))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Powers down the SD function
+ */
+
+static void wbsd_chip_poweroff(struct wbsd_host *host)
+{
+	wbsd_unlock_config(host);
+
+	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+	wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
+
+	wbsd_lock_config(host);
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Devices setup and shutdown                                                *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
+	int pnp)
+{
+	struct wbsd_host *host = NULL;
+	struct mmc_host *mmc = NULL;
+	int ret;
+
+	ret = wbsd_alloc_mmc(dev);
+	if (ret)
+		return ret;
+
+	mmc = dev_get_drvdata(dev);
+	host = mmc_priv(mmc);
+
+	/*
+	 * Scan for hardware.
+	 */
+	ret = wbsd_scan(host);
+	if (ret) {
+		if (pnp && (ret == -ENODEV)) {
+			printk(KERN_WARNING DRIVER_NAME
+				": Unable to confirm device presence. You may "
+				"experience lock-ups.\n");
+		} else {
+			wbsd_free_mmc(dev);
+			return ret;
+		}
+	}
+
+	/*
+	 * Request resources.
+	 */
+	ret = wbsd_request_resources(host, base, irq, dma);
+	if (ret) {
+		wbsd_release_resources(host);
+		wbsd_free_mmc(dev);
+		return ret;
+	}
+
+	/*
+	 * See if chip needs to be configured.
+	 */
+	if (pnp) {
+		if ((host->config != 0) && !wbsd_chip_validate(host)) {
+			printk(KERN_WARNING DRIVER_NAME
+				": PnP active but chip not configured! "
+				"You probably have a buggy BIOS. "
+				"Configuring chip manually.\n");
+			wbsd_chip_config(host);
+		}
+	} else
+		wbsd_chip_config(host);
+
+	/*
+	 * Power Management stuff. No idea how this works.
+	 * Not tested.
+	 */
+#ifdef CONFIG_PM
+	if (host->config) {
+		wbsd_unlock_config(host);
+		wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
+		wbsd_lock_config(host);
+	}
+#endif
+	/*
+	 * Allow device to initialise itself properly.
+	 */
+	mdelay(5);
+
+	/*
+	 * Reset the chip into a known state.
+	 */
+	wbsd_init_device(host);
+
+	mmc_add_host(mmc);
+
+	printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
+	if (host->chip_id != 0)
+		printk(" id %x", (int)host->chip_id);
+	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
+	if (host->dma >= 0)
+		printk(" dma %d", (int)host->dma);
+	else
+		printk(" FIFO");
+	if (pnp)
+		printk(" PnP");
+	printk("\n");
+
+	return 0;
+}
+
+static void __devexit wbsd_shutdown(struct device *dev, int pnp)
+{
+	struct mmc_host *mmc = dev_get_drvdata(dev);
+	struct wbsd_host *host;
+
+	if (!mmc)
+		return;
+
+	host = mmc_priv(mmc);
+
+	mmc_remove_host(mmc);
+
+	/*
+	 * Power down the SD/MMC function.
+	 */
+	if (!pnp)
+		wbsd_chip_poweroff(host);
+
+	wbsd_release_resources(host);
+
+	wbsd_free_mmc(dev);
+}
+
+/*
+ * Non-PnP
+ */
+
+static int __devinit wbsd_probe(struct platform_device *dev)
+{
+	/* Use the module parameters for resources */
+	return wbsd_init(&dev->dev, io, irq, dma, 0);
+}
+
+static int __devexit wbsd_remove(struct platform_device *dev)
+{
+	wbsd_shutdown(&dev->dev, 0);
+
+	return 0;
+}
+
+/*
+ * PnP
+ */
+
+#ifdef CONFIG_PNP
+
+static int __devinit
+wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
+{
+	int io, irq, dma;
+
+	/*
+	 * Get resources from PnP layer.
+	 */
+	io = pnp_port_start(pnpdev, 0);
+	irq = pnp_irq(pnpdev, 0);
+	if (pnp_dma_valid(pnpdev, 0))
+		dma = pnp_dma(pnpdev, 0);
+	else
+		dma = -1;
+
+	DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
+
+	return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
+}
+
+static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
+{
+	wbsd_shutdown(&dev->dev, 1);
+}
+
+#endif /* CONFIG_PNP */
+
+/*
+ * Power management
+ */
+
+#ifdef CONFIG_PM
+
+static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
+{
+	BUG_ON(host == NULL);
+
+	return mmc_suspend_host(host->mmc, state);
+}
+
+static int wbsd_resume(struct wbsd_host *host)
+{
+	BUG_ON(host == NULL);
+
+	wbsd_init_device(host);
+
+	return mmc_resume_host(host->mmc);
+}
+
+static int wbsd_platform_suspend(struct platform_device *dev,
+				 pm_message_t state)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	struct wbsd_host *host;
+	int ret;
+
+	if (mmc == NULL)
+		return 0;
+
+	DBGF("Suspending...\n");
+
+	host = mmc_priv(mmc);
+
+	ret = wbsd_suspend(host, state);
+	if (ret)
+		return ret;
+
+	wbsd_chip_poweroff(host);
+
+	return 0;
+}
+
+static int wbsd_platform_resume(struct platform_device *dev)
+{
+	struct mmc_host *mmc = platform_get_drvdata(dev);
+	struct wbsd_host *host;
+
+	if (mmc == NULL)
+		return 0;
+
+	DBGF("Resuming...\n");
+
+	host = mmc_priv(mmc);
+
+	wbsd_chip_config(host);
+
+	/*
+	 * Allow device to initialise itself properly.
+	 */
+	mdelay(5);
+
+	return wbsd_resume(host);
+}
+
+#ifdef CONFIG_PNP
+
+static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+	struct wbsd_host *host;
+
+	if (mmc == NULL)
+		return 0;
+
+	DBGF("Suspending...\n");
+
+	host = mmc_priv(mmc);
+
+	return wbsd_suspend(host, state);
+}
+
+static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
+{
+	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
+	struct wbsd_host *host;
+
+	if (mmc == NULL)
+		return 0;
+
+	DBGF("Resuming...\n");
+
+	host = mmc_priv(mmc);
+
+	/*
+	 * See if chip needs to be configured.
+	 */
+	if (host->config != 0) {
+		if (!wbsd_chip_validate(host)) {
+			printk(KERN_WARNING DRIVER_NAME
+				": PnP active but chip not configured! "
+				"You probably have a buggy BIOS. "
+				"Configuring chip manually.\n");
+			wbsd_chip_config(host);
+		}
+	}
+
+	/*
+	 * Allow device to initialise itself properly.
+	 */
+	mdelay(5);
+
+	return wbsd_resume(host);
+}
+
+#endif /* CONFIG_PNP */
+
+#else /* CONFIG_PM */
+
+#define wbsd_platform_suspend NULL
+#define wbsd_platform_resume NULL
+
+#define wbsd_pnp_suspend NULL
+#define wbsd_pnp_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct platform_device *wbsd_device;
+
+static struct platform_driver wbsd_driver = {
+	.probe		= wbsd_probe,
+	.remove		= __devexit_p(wbsd_remove),
+
+	.suspend	= wbsd_platform_suspend,
+	.resume		= wbsd_platform_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+#ifdef CONFIG_PNP
+
+static struct pnp_driver wbsd_pnp_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= pnp_dev_table,
+	.probe		= wbsd_pnp_probe,
+	.remove		= __devexit_p(wbsd_pnp_remove),
+
+	.suspend	= wbsd_pnp_suspend,
+	.resume		= wbsd_pnp_resume,
+};
+
+#endif /* CONFIG_PNP */
+
+/*
+ * Module loading/unloading
+ */
+
+static int __init wbsd_drv_init(void)
+{
+	int result;
+
+	printk(KERN_INFO DRIVER_NAME
+		": Winbond W83L51xD SD/MMC card interface driver\n");
+	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+
+#ifdef CONFIG_PNP
+
+	if (!nopnp) {
+		result = pnp_register_driver(&wbsd_pnp_driver);
+		if (result < 0)
+			return result;
+	}
+#endif /* CONFIG_PNP */
+
+	if (nopnp) {
+		result = platform_driver_register(&wbsd_driver);
+		if (result < 0)
+			return result;
+
+		wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
+		if (!wbsd_device) {
+			platform_driver_unregister(&wbsd_driver);
+			return -ENOMEM;
+		}
+
+		result = platform_device_add(wbsd_device);
+		if (result) {
+			platform_device_put(wbsd_device);
+			platform_driver_unregister(&wbsd_driver);
+			return result;
+		}
+	}
+
+	return 0;
+}
+
+static void __exit wbsd_drv_exit(void)
+{
+#ifdef CONFIG_PNP
+
+	if (!nopnp)
+		pnp_unregister_driver(&wbsd_pnp_driver);
+
+#endif /* CONFIG_PNP */
+
+	if (nopnp) {
+		platform_device_unregister(wbsd_device);
+
+		platform_driver_unregister(&wbsd_driver);
+	}
+
+	DBG("unloaded\n");
+}
+
+module_init(wbsd_drv_init);
+module_exit(wbsd_drv_exit);
+#ifdef CONFIG_PNP
+module_param(nopnp, uint, 0444);
+#endif
+module_param(io, uint, 0444);
+module_param(irq, uint, 0444);
+module_param(dma, int, 0444);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
+
+#ifdef CONFIG_PNP
+MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
+#endif
+MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
+MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
+MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/host/wbsd.h b/drivers/mmc/host/wbsd.h
new file mode 100644
index 0000000..873bda1
--- /dev/null
+++ b/drivers/mmc/host/wbsd.h
@@ -0,0 +1,185 @@
+/*
+ *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
+ *
+ *  Copyright (C) 2004-2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#define LOCK_CODE		0xAA
+
+#define WBSD_CONF_SWRST		0x02
+#define WBSD_CONF_DEVICE	0x07
+#define WBSD_CONF_ID_HI		0x20
+#define WBSD_CONF_ID_LO		0x21
+#define WBSD_CONF_POWER		0x22
+#define WBSD_CONF_PME		0x23
+#define WBSD_CONF_PMES		0x24
+
+#define WBSD_CONF_ENABLE	0x30
+#define WBSD_CONF_PORT_HI	0x60
+#define WBSD_CONF_PORT_LO	0x61
+#define WBSD_CONF_IRQ		0x70
+#define WBSD_CONF_DRQ		0x74
+
+#define WBSD_CONF_PINS		0xF0
+
+#define DEVICE_SD		0x03
+
+#define WBSD_PINS_DAT3_HI	0x20
+#define WBSD_PINS_DAT3_OUT	0x10
+#define WBSD_PINS_GP11_HI	0x04
+#define WBSD_PINS_DETECT_GP11	0x02
+#define WBSD_PINS_DETECT_DAT3	0x01
+
+#define WBSD_CMDR		0x00
+#define WBSD_DFR		0x01
+#define WBSD_EIR		0x02
+#define WBSD_ISR		0x03
+#define WBSD_FSR		0x04
+#define WBSD_IDXR		0x05
+#define WBSD_DATAR		0x06
+#define WBSD_CSR		0x07
+
+#define WBSD_EINT_CARD		0x40
+#define WBSD_EINT_FIFO_THRE	0x20
+#define WBSD_EINT_CRC		0x10
+#define WBSD_EINT_TIMEOUT	0x08
+#define WBSD_EINT_PROGEND	0x04
+#define WBSD_EINT_BUSYEND	0x02
+#define WBSD_EINT_TC		0x01
+
+#define WBSD_INT_PENDING	0x80
+#define WBSD_INT_CARD		0x40
+#define WBSD_INT_FIFO_THRE	0x20
+#define WBSD_INT_CRC		0x10
+#define WBSD_INT_TIMEOUT	0x08
+#define WBSD_INT_PROGEND	0x04
+#define WBSD_INT_BUSYEND	0x02
+#define WBSD_INT_TC		0x01
+
+#define WBSD_FIFO_EMPTY		0x80
+#define WBSD_FIFO_FULL		0x40
+#define WBSD_FIFO_EMTHRE	0x20
+#define WBSD_FIFO_FUTHRE	0x10
+#define WBSD_FIFO_SZMASK	0x0F
+
+#define WBSD_MSLED		0x20
+#define WBSD_POWER_N		0x10
+#define WBSD_WRPT		0x04
+#define WBSD_CARDPRESENT	0x01
+
+#define WBSD_IDX_CLK		0x01
+#define WBSD_IDX_PBSMSB		0x02
+#define WBSD_IDX_TAAC		0x03
+#define WBSD_IDX_NSAC		0x04
+#define WBSD_IDX_PBSLSB		0x05
+#define WBSD_IDX_SETUP		0x06
+#define WBSD_IDX_DMA		0x07
+#define WBSD_IDX_FIFOEN		0x08
+#define WBSD_IDX_STATUS		0x10
+#define WBSD_IDX_RSPLEN		0x1E
+#define WBSD_IDX_RESP0		0x1F
+#define WBSD_IDX_RESP1		0x20
+#define WBSD_IDX_RESP2		0x21
+#define WBSD_IDX_RESP3		0x22
+#define WBSD_IDX_RESP4		0x23
+#define WBSD_IDX_RESP5		0x24
+#define WBSD_IDX_RESP6		0x25
+#define WBSD_IDX_RESP7		0x26
+#define WBSD_IDX_RESP8		0x27
+#define WBSD_IDX_RESP9		0x28
+#define WBSD_IDX_RESP10		0x29
+#define WBSD_IDX_RESP11		0x2A
+#define WBSD_IDX_RESP12		0x2B
+#define WBSD_IDX_RESP13		0x2C
+#define WBSD_IDX_RESP14		0x2D
+#define WBSD_IDX_RESP15		0x2E
+#define WBSD_IDX_RESP16		0x2F
+#define WBSD_IDX_CRCSTATUS	0x30
+#define WBSD_IDX_ISR		0x3F
+
+#define WBSD_CLK_375K		0x00
+#define WBSD_CLK_12M		0x01
+#define WBSD_CLK_16M		0x02
+#define WBSD_CLK_24M		0x03
+
+#define WBSD_DATA_WIDTH		0x01
+
+#define WBSD_DAT3_H		0x08
+#define WBSD_FIFO_RESET		0x04
+#define WBSD_SOFT_RESET		0x02
+#define WBSD_INC_INDEX		0x01
+
+#define WBSD_DMA_SINGLE		0x02
+#define WBSD_DMA_ENABLE		0x01
+
+#define WBSD_FIFOEN_EMPTY	0x20
+#define WBSD_FIFOEN_FULL	0x10
+#define WBSD_FIFO_THREMASK	0x0F
+
+#define WBSD_BLOCK_READ		0x80
+#define WBSD_BLOCK_WRITE	0x40
+#define WBSD_BUSY		0x20
+#define WBSD_CARDTRAFFIC	0x04
+#define WBSD_SENDCMD		0x02
+#define WBSD_RECVRES		0x01
+
+#define WBSD_RSP_SHORT		0x00
+#define WBSD_RSP_LONG		0x01
+
+#define WBSD_CRC_MASK		0x1F
+#define WBSD_CRC_OK		0x05 /* S010E (00101) */
+#define WBSD_CRC_FAIL		0x0B /* S101E (01011) */
+
+#define WBSD_DMA_SIZE		65536
+
+struct wbsd_host
+{
+	struct mmc_host*	mmc;		/* MMC structure */
+
+	spinlock_t		lock;		/* Mutex */
+
+	int			flags;		/* Driver states */
+
+#define WBSD_FCARD_PRESENT	(1<<0)		/* Card is present */
+#define WBSD_FIGNORE_DETECT	(1<<1)		/* Ignore card detection */
+
+	struct mmc_request*	mrq;		/* Current request */
+
+	u8			isr;		/* Accumulated ISR */
+
+	struct scatterlist*	cur_sg;		/* Current SG entry */
+	unsigned int		num_sg;		/* Number of entries left */
+
+	unsigned int		offset;		/* Offset into current entry */
+	unsigned int		remain;		/* Data left in curren entry */
+
+	char*			dma_buffer;	/* ISA DMA buffer */
+	dma_addr_t		dma_addr;	/* Physical address for same */
+
+	int			firsterr;	/* See fifo functions */
+
+	u8			clk;		/* Current clock speed */
+	unsigned char		bus_width;	/* Current bus width */
+
+	int			config;		/* Config port */
+	u8			unlock_code;	/* Code to unlock config */
+
+	int			chip_id;	/* ID of controller */
+
+	int			base;		/* I/O port base */
+	int			irq;		/* Interrupt */
+	int			dma;		/* DMA channel */
+
+	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
+	struct tasklet_struct	fifo_tasklet;
+	struct tasklet_struct	crc_tasklet;
+	struct tasklet_struct	timeout_tasklet;
+	struct tasklet_struct	finish_tasklet;
+
+	struct timer_list	ignore_timer;	/* Ignore detection timer */
+};
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
deleted file mode 100644
index 0de5c9e..0000000
--- a/drivers/mmc/imxmmc.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- *  linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
- *
- *  Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
- *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- *  derived from pxamci.c by 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.
- *
- *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Changed to conform redesigned i.MX scatter gather DMA interface
- *
- *  2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Updated for 2.6.14 kernel
- *
- *  2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
- *             Found and corrected problems in the write path
- *
- *  2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             The event handling rewritten right way in softirq.
- *             Added many ugly hacks and delays to overcome SDHC
- *             deficiencies
- *
- */
-
-#ifdef CONFIG_MMC_DEBUG
-#define DEBUG
-#else
-#undef  DEBUG
-#endif
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/protocol.h>
-#include <linux/delay.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <asm/arch/mmc.h>
-#include <asm/arch/imx-dma.h>
-
-#include "imxmmc.h"
-
-#define DRIVER_NAME "imx-mmc"
-
-#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
-	              INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
-		      INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
-
-struct imxmci_host {
-	struct mmc_host		*mmc;
-	spinlock_t		lock;
-	struct resource		*res;
-	int			irq;
-	imx_dmach_t		dma;
-	unsigned int		clkrt;
-	unsigned int		cmdat;
-	volatile unsigned int	imask;
-	unsigned int		power_mode;
-	unsigned int		present;
-	struct imxmmc_platform_data *pdata;
-
-	struct mmc_request	*req;
-	struct mmc_command	*cmd;
-	struct mmc_data		*data;
-
-	struct timer_list	timer;
-	struct tasklet_struct	tasklet;
-	unsigned int		status_reg;
-	unsigned long		pending_events;
-	/* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
-	u16			*data_ptr;
-	unsigned int		data_cnt;
-	atomic_t		stuck_timeout;
-
-	unsigned int		dma_nents;
-	unsigned int		dma_size;
-	unsigned int		dma_dir;
-	int			dma_allocated;
-
-	unsigned char		actual_bus_width;
-
-	int			prev_cmd_code;
-};
-
-#define IMXMCI_PEND_IRQ_b	0
-#define IMXMCI_PEND_DMA_END_b	1
-#define IMXMCI_PEND_DMA_ERR_b	2
-#define IMXMCI_PEND_WAIT_RESP_b	3
-#define IMXMCI_PEND_DMA_DATA_b	4
-#define IMXMCI_PEND_CPU_DATA_b	5
-#define IMXMCI_PEND_CARD_XCHG_b	6
-#define IMXMCI_PEND_SET_INIT_b	7
-#define IMXMCI_PEND_STARTED_b	8
-
-#define IMXMCI_PEND_IRQ_m	(1 << IMXMCI_PEND_IRQ_b)
-#define IMXMCI_PEND_DMA_END_m	(1 << IMXMCI_PEND_DMA_END_b)
-#define IMXMCI_PEND_DMA_ERR_m	(1 << IMXMCI_PEND_DMA_ERR_b)
-#define IMXMCI_PEND_WAIT_RESP_m	(1 << IMXMCI_PEND_WAIT_RESP_b)
-#define IMXMCI_PEND_DMA_DATA_m	(1 << IMXMCI_PEND_DMA_DATA_b)
-#define IMXMCI_PEND_CPU_DATA_m	(1 << IMXMCI_PEND_CPU_DATA_b)
-#define IMXMCI_PEND_CARD_XCHG_m	(1 << IMXMCI_PEND_CARD_XCHG_b)
-#define IMXMCI_PEND_SET_INIT_m	(1 << IMXMCI_PEND_SET_INIT_b)
-#define IMXMCI_PEND_STARTED_m	(1 << IMXMCI_PEND_STARTED_b)
-
-static void imxmci_stop_clock(struct imxmci_host *host)
-{
-	int i = 0;
-	MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
-	while(i < 0x1000) {
-	        if(!(i & 0x7f))
-			MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
-
-		if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
-			/* Check twice before cut */
-			if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
-				return;
-		}
-
-		i++;
-	}
-	dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
-}
-
-static int imxmci_start_clock(struct imxmci_host *host)
-{
-	unsigned int trials = 0;
-	unsigned int delay_limit = 128;
-	unsigned long flags;
-
-	MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
-
-	clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
-
-	/*
-	 * Command start of the clock, this usually succeeds in less
-	 * then 6 delay loops, but during card detection (low clockrate)
-	 * it takes up to 5000 delay loops and sometimes fails for the first time
-	 */
-	MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
-
-	do {
-		unsigned int delay = delay_limit;
-
-		while(delay--){
-			if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
-				/* Check twice before cut */
-				if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
-					return 0;
-
-			if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
-				return 0;
-		}
-
-		local_irq_save(flags);
-		/*
-		 * Ensure, that request is not doubled under all possible circumstances.
-		 * It is possible, that cock running state is missed, because some other
-		 * IRQ or schedule delays this function execution and the clocks has
-		 * been already stopped by other means (response processing, SDHC HW)
-		 */
-		if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
-			MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
-		local_irq_restore(flags);
-
-	} while(++trials<256);
-
-	dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
-
-	return -1;
-}
-
-static void imxmci_softreset(void)
-{
-	/* reset sequence */
-	MMC_STR_STP_CLK = 0x8;
-	MMC_STR_STP_CLK = 0xD;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-	MMC_STR_STP_CLK = 0x5;
-
-	MMC_RES_TO = 0xff;
-	MMC_BLK_LEN = 512;
-	MMC_NOB = 1;
-}
-
-static int imxmci_busy_wait_for_status(struct imxmci_host *host,
-			unsigned int *pstat, unsigned int stat_mask,
-			int timeout, const char *where)
-{
-	int loops=0;
-	while(!(*pstat & stat_mask)) {
-		loops+=2;
-		if(loops >= timeout) {
-			dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
-				where, *pstat, stat_mask);
-			return -1;
-		}
-		udelay(2);
-		*pstat |= MMC_STATUS;
-	}
-	if(!loops)
-		return 0;
-
-	/* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
-	if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
-		dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
-			loops, where, *pstat, stat_mask);
-	return loops;
-}
-
-static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
-{
-	unsigned int nob = data->blocks;
-	unsigned int blksz = data->blksz;
-	unsigned int datasz = nob * blksz;
-	int i;
-
-	if (data->flags & MMC_DATA_STREAM)
-		nob = 0xffff;
-
-	host->data = data;
-	data->bytes_xfered = 0;
-
-	MMC_NOB = nob;
-	MMC_BLK_LEN = blksz;
-
-	/*
-	 * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
-	 * We are in big troubles for non-512 byte transfers according to note in the paragraph
-	 * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
-	 * The situation is even more complex in reality. The SDHC in not able to handle wll
-	 * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
-	 * This is required for SCR read at least.
-	 */
-	if (datasz < 512) {
-		host->dma_size = datasz;
-		if (data->flags & MMC_DATA_READ) {
-			host->dma_dir = DMA_FROM_DEVICE;
-
-			/* Hack to enable read SCR */
-			MMC_NOB = 1;
-			MMC_BLK_LEN = 512;
-		} else {
-			host->dma_dir = DMA_TO_DEVICE;
-		}
-
-		/* Convert back to virtual address */
-		host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
-		host->data_cnt = 0;
-
-		clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
-		set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
-		return;
-	}
-
-	if (data->flags & MMC_DATA_READ) {
-		host->dma_dir = DMA_FROM_DEVICE;
-		host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-						data->sg_len,  host->dma_dir);
-
-		imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-			host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
-
-		/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
-		CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
-	} else {
-		host->dma_dir = DMA_TO_DEVICE;
-
-		host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-						data->sg_len,  host->dma_dir);
-
-		imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-			host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
-
-		/*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
-		CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
-	}
-
-#if 1	/* This code is there only for consistency checking and can be disabled in future */
-	host->dma_size = 0;
-	for(i=0; i<host->dma_nents; i++)
-		host->dma_size+=data->sg[i].length;
-
-	if (datasz > host->dma_size) {
-		dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
-		       datasz, host->dma_size);
-	}
-#endif
-
-	host->dma_size = datasz;
-
-	wmb();
-
-	if(host->actual_bus_width == MMC_BUS_WIDTH_4)
-		BLR(host->dma) = 0;	/* burst 64 byte read / 64 bytes write */
-	else
-		BLR(host->dma) = 16;	/* burst 16 byte read / 16 bytes write */
-
-	RSSR(host->dma) = DMA_REQ_SDHC;
-
-	set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
-	clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
-	/* start DMA engine for read, write is delayed after initial response */
-	if (host->dma_dir == DMA_FROM_DEVICE) {
-		imx_dma_enable(host->dma);
-	}
-}
-
-static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
-	unsigned long flags;
-	u32 imask;
-
-	WARN_ON(host->cmd != NULL);
-	host->cmd = cmd;
-
-	/* Ensure, that clock are stopped else command programming and start fails */
-	imxmci_stop_clock(host);
-
-	if (cmd->flags & MMC_RSP_BUSY)
-		cmdat |= CMD_DAT_CONT_BUSY;
-
-	switch (mmc_resp_type(cmd)) {
-	case MMC_RSP_R1: /* short CRC, OPCODE */
-	case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
-		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
-		break;
-	case MMC_RSP_R2: /* long 136 bit + CRC */
-		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
-		break;
-	case MMC_RSP_R3: /* short */
-		cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
-		break;
-	default:
-		break;
-	}
-
-	if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
-		cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
-
-	if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
-		cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
-
-	MMC_CMD = cmd->opcode;
-	MMC_ARGH = cmd->arg >> 16;
-	MMC_ARGL = cmd->arg & 0xffff;
-	MMC_CMD_DAT_CONT = cmdat;
-
-	atomic_set(&host->stuck_timeout, 0);
-	set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
-
-
-	imask = IMXMCI_INT_MASK_DEFAULT;
-	imask &= ~INT_MASK_END_CMD_RES;
-	if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
-		/*imask &= ~INT_MASK_BUF_READY;*/
-		imask &= ~INT_MASK_DATA_TRAN;
-		if ( cmdat & CMD_DAT_CONT_WRITE )
-			imask &= ~INT_MASK_WRITE_OP_DONE;
-		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
-			imask &= ~INT_MASK_BUF_READY;
-	}
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->imask = imask;
-	MMC_INT_MASK = host->imask;
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
-		cmd->opcode, cmd->opcode, imask);
-
-	imxmci_start_clock(host);
-}
-
-static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
-			IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
-
-	host->imask = IMXMCI_INT_MASK_DEFAULT;
-	MMC_INT_MASK = host->imask;
-
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	if(req && req->cmd)
-		host->prev_cmd_code = req->cmd->opcode;
-
-	host->req = NULL;
-	host->cmd = NULL;
-	host->data = NULL;
-	mmc_request_done(host->mmc, req);
-}
-
-static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
-{
-	struct mmc_data *data = host->data;
-	int data_error;
-
-	if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
-		imx_dma_disable(host->dma);
-		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
-			     host->dma_dir);
-	}
-
-	if ( stat & STATUS_ERR_MASK ) {
-		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
-		if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
-			data->error = MMC_ERR_BADCRC;
-		else if(stat & STATUS_TIME_OUT_READ)
-			data->error = MMC_ERR_TIMEOUT;
-		else
-			data->error = MMC_ERR_FAILED;
-	} else {
-		data->bytes_xfered = host->dma_size;
-	}
-
-	data_error = data->error;
-
-	host->data = NULL;
-
-	return data_error;
-}
-
-static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
-{
-	struct mmc_command *cmd = host->cmd;
-	int i;
-	u32 a,b,c;
-	struct mmc_data *data = host->data;
-
-	if (!cmd)
-		return 0;
-
-	host->cmd = NULL;
-
-	if (stat & STATUS_TIME_OUT_RESP) {
-		dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
-		cmd->error = MMC_ERR_TIMEOUT;
-	} else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
-		dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
-		cmd->error = MMC_ERR_BADCRC;
-	}
-
-	if(cmd->flags & MMC_RSP_PRESENT) {
-		if(cmd->flags & MMC_RSP_136) {
-			for (i = 0; i < 4; i++) {
-				u32 a = MMC_RES_FIFO & 0xffff;
-				u32 b = MMC_RES_FIFO & 0xffff;
-				cmd->resp[i] = a<<16 | b;
-			}
-		} else {
-			a = MMC_RES_FIFO & 0xffff;
-			b = MMC_RES_FIFO & 0xffff;
-			c = MMC_RES_FIFO & 0xffff;
-			cmd->resp[0] = a<<24 | b<<8 | c>>8;
-		}
-	}
-
-	dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
-		cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
-
-	if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
-		if (host->req->data->flags & MMC_DATA_WRITE) {
-
-			/* Wait for FIFO to be empty before starting DMA write */
-
-			stat = MMC_STATUS;
-			if(imxmci_busy_wait_for_status(host, &stat,
-				STATUS_APPL_BUFF_FE,
-				40, "imxmci_cmd_done DMA WR") < 0) {
-				cmd->error = MMC_ERR_FIFO;
-				imxmci_finish_data(host, stat);
-				if(host->req)
-					imxmci_finish_request(host, host->req);
-				dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
-				       stat);
-				return 0;
-			}
-
-			if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
-				imx_dma_enable(host->dma);
-			}
-		}
-	} else {
-		struct mmc_request *req;
-		imxmci_stop_clock(host);
-		req = host->req;
-
-		if(data)
-			imxmci_finish_data(host, stat);
-
-		if( req ) {
-			imxmci_finish_request(host, req);
-		} else {
-			dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
-		}
-	}
-
-	return 1;
-}
-
-static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
-{
-	struct mmc_data *data = host->data;
-	int data_error;
-
-	if (!data)
-		return 0;
-
-	data_error = imxmci_finish_data(host, stat);
-
-	if (host->req->stop) {
-		imxmci_stop_clock(host);
-		imxmci_start_cmd(host, host->req->stop, 0);
-	} else {
-		struct mmc_request *req;
-		req = host->req;
-		if( req ) {
-			imxmci_finish_request(host, req);
-		} else {
-			dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
-		}
-	}
-
-	return 1;
-}
-
-static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
-{
-	int i;
-	int burst_len;
-	int trans_done = 0;
-	unsigned int stat = *pstat;
-
-	if(host->actual_bus_width != MMC_BUS_WIDTH_4)
-		burst_len = 16;
-	else
-		burst_len = 64;
-
-	/* This is unfortunately required */
-	dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
-		stat);
-
-	udelay(20);	/* required for clocks < 8MHz*/
-
-	if(host->dma_dir == DMA_FROM_DEVICE) {
-		imxmci_busy_wait_for_status(host, &stat,
-				STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
-				STATUS_TIME_OUT_READ,
-				50, "imxmci_cpu_driven_data read");
-
-		while((stat & (STATUS_APPL_BUFF_FF |  STATUS_DATA_TRANS_DONE)) &&
-		      !(stat & STATUS_TIME_OUT_READ) &&
-		      (host->data_cnt < 512)) {
-
-			udelay(20);	/* required for clocks < 8MHz*/
-
-			for(i = burst_len; i>=2 ; i-=2) {
-				u16 data;
-				data = MMC_BUFFER_ACCESS;
-				udelay(10);	/* required for clocks < 8MHz*/
-				if(host->data_cnt+2 <= host->dma_size) {
-					*(host->data_ptr++) = data;
-				} else {
-					if(host->data_cnt < host->dma_size)
-						*(u8*)(host->data_ptr) = data;
-				}
-				host->data_cnt += 2;
-			}
-
-			stat = MMC_STATUS;
-
-			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
-				host->data_cnt, burst_len, stat);
-		}
-
-		if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
-			trans_done = 1;
-
-		if(host->dma_size & 0x1ff)
-			stat &= ~STATUS_CRC_READ_ERR;
-
-		if(stat & STATUS_TIME_OUT_READ) {
-			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
-				stat);
-			trans_done = -1;
-		}
-
-	} else {
-		imxmci_busy_wait_for_status(host, &stat,
-				STATUS_APPL_BUFF_FE,
-				20, "imxmci_cpu_driven_data write");
-
-		while((stat & STATUS_APPL_BUFF_FE) &&
-		      (host->data_cnt < host->dma_size)) {
-			if(burst_len >= host->dma_size - host->data_cnt) {
-				burst_len = host->dma_size - host->data_cnt;
-				host->data_cnt = host->dma_size;
-				trans_done = 1;
-			} else {
-				host->data_cnt += burst_len;
-			}
-
-			for(i = burst_len; i>0 ; i-=2)
-				MMC_BUFFER_ACCESS = *(host->data_ptr++);
-
-			stat = MMC_STATUS;
-
-			dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
-				burst_len, stat);
-		}
-	}
-
-	*pstat = stat;
-
-	return trans_done;
-}
-
-static void imxmci_dma_irq(int dma, void *devid)
-{
-	struct imxmci_host *host = devid;
-	uint32_t stat = MMC_STATUS;
-
-	atomic_set(&host->stuck_timeout, 0);
-	host->status_reg = stat;
-	set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
-	tasklet_schedule(&host->tasklet);
-}
-
-static irqreturn_t imxmci_irq(int irq, void *devid)
-{
-	struct imxmci_host *host = devid;
-	uint32_t stat = MMC_STATUS;
-	int handled = 1;
-
-	MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
-
-	atomic_set(&host->stuck_timeout, 0);
-	host->status_reg = stat;
-	set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
-	set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
-	tasklet_schedule(&host->tasklet);
-
-	return IRQ_RETVAL(handled);;
-}
-
-static void imxmci_tasklet_fnc(unsigned long data)
-{
-	struct imxmci_host *host = (struct imxmci_host *)data;
-	u32 stat;
-	unsigned int data_dir_mask = 0;	/* STATUS_WR_CRC_ERROR_CODE_MASK */
-	int timeout = 0;
-
-	if(atomic_read(&host->stuck_timeout) > 4) {
-		char *what;
-		timeout = 1;
-		stat = MMC_STATUS;
-		host->status_reg = stat;
-		if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-			if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
-				what = "RESP+DMA";
-			else
-				what = "RESP";
-		else
-			if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
-				if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
-					what = "DATA";
-				else
-					what = "DMA";
-			else
-				what = "???";
-
-		dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
-		       what, stat, MMC_INT_MASK);
-		dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
-		       MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
-		dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
-		       host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
-	}
-
-	if(!host->present || timeout)
-		host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
-				    STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
-
-	if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
-		clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
-
-		stat = MMC_STATUS;
-		/*
-		 * This is not required in theory, but there is chance to miss some flag
-		 * which clears automatically by mask write, FreeScale original code keeps
-		 * stat from IRQ time so do I
-		 */
-		stat |= host->status_reg;
-
-		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
-			stat &= ~STATUS_CRC_READ_ERR;
-
-		if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
-			imxmci_busy_wait_for_status(host, &stat,
-					STATUS_END_CMD_RESP | STATUS_ERR_MASK,
-					20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
-		}
-
-		if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
-			if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-				imxmci_cmd_done(host, stat);
-			if(host->data && (stat & STATUS_ERR_MASK))
-				imxmci_data_done(host, stat);
-		}
-
-		if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
-			stat |= MMC_STATUS;
-			if(imxmci_cpu_driven_data(host, &stat)){
-				if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
-					imxmci_cmd_done(host, stat);
-				atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
-							&host->pending_events);
-				imxmci_data_done(host, stat);
-			}
-		}
-	}
-
-	if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
-	   !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
-
-		stat = MMC_STATUS;
-		/* Same as above */
-		stat |= host->status_reg;
-
-		if(host->dma_dir == DMA_TO_DEVICE) {
-			data_dir_mask = STATUS_WRITE_OP_DONE;
-		} else {
-			data_dir_mask = STATUS_DATA_TRANS_DONE;
-		}
-
-		if(stat & data_dir_mask) {
-			clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
-			imxmci_data_done(host, stat);
-		}
-	}
-
-	if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
-
-		if(host->cmd)
-			imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
-
-		if(host->data)
-			imxmci_data_done(host, STATUS_TIME_OUT_READ |
-					 STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
-
-		if(host->req)
-			imxmci_finish_request(host, host->req);
-
-		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-
-	}
-}
-
-static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
-{
-	struct imxmci_host *host = mmc_priv(mmc);
-	unsigned int cmdat;
-
-	WARN_ON(host->req != NULL);
-
-	host->req = req;
-
-	cmdat = 0;
-
-	if (req->data) {
-		imxmci_setup_data(host, req->data);
-
-		cmdat |= CMD_DAT_CONT_DATA_ENABLE;
-
-		if (req->data->flags & MMC_DATA_WRITE)
-			cmdat |= CMD_DAT_CONT_WRITE;
-
-		if (req->data->flags & MMC_DATA_STREAM) {
-			cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
-		}
-	}
-
-	imxmci_start_cmd(host, req->cmd, cmdat);
-}
-
-#define CLK_RATE 19200000
-
-static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct imxmci_host *host = mmc_priv(mmc);
-	int prescaler;
-
-	if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
-		host->actual_bus_width = MMC_BUS_WIDTH_4;
-		imx_gpio_mode(PB11_PF_SD_DAT3);
-	}else{
-		host->actual_bus_width = MMC_BUS_WIDTH_1;
-		imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
-	}
-
-	if ( host->power_mode != ios->power_mode ) {
-		switch (ios->power_mode) {
-		case MMC_POWER_OFF:
-        		break;
-		case MMC_POWER_UP:
-			set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
-        		break;
-		case MMC_POWER_ON:
-        		break;
-		}
-		host->power_mode = ios->power_mode;
-	}
-
-	if ( ios->clock ) {
-		unsigned int clk;
-
-		/* The prescaler is 5 for PERCLK2 equal to 96MHz
-		 * then 96MHz / 5 = 19.2 MHz
-		 */
-		clk=imx_get_perclk2();
-		prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
-		switch(prescaler) {
-		case 0:
-		case 1:	prescaler = 0;
-			break;
-		case 2:	prescaler = 1;
-			break;
-		case 3:	prescaler = 2;
-			break;
-		case 4:	prescaler = 4;
-			break;
-		default:
-		case 5:	prescaler = 5;
-			break;
-		}
-
-		dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
-			clk, prescaler);
-
-		for(clk=0; clk<8; clk++) {
-			int x;
-			x = CLK_RATE / (1<<clk);
-			if( x <= ios->clock)
-				break;
-		}
-
-		MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
-
-		imxmci_stop_clock(host);
-		MMC_CLK_RATE = (prescaler<<3) | clk;
-		/*
-		 * Under my understanding, clock should not be started there, because it would
-		 * initiate SDHC sequencer and send last or random command into card
-		 */
-		/*imxmci_start_clock(host);*/
-
-		dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
-	} else {
-		imxmci_stop_clock(host);
-	}
-}
-
-static const struct mmc_host_ops imxmci_ops = {
-	.request	= imxmci_request,
-	.set_ios	= imxmci_set_ios,
-};
-
-static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
-{
-	int i;
-
-	for (i = 0; i < dev->num_resources; i++)
-		if (dev->resource[i].flags == mask && nr-- == 0)
-			return &dev->resource[i];
-	return NULL;
-}
-
-static int platform_device_irq(struct platform_device *dev, int nr)
-{
-	int i;
-
-	for (i = 0; i < dev->num_resources; i++)
-		if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
-			return dev->resource[i].start;
-	return NO_IRQ;
-}
-
-static void imxmci_check_status(unsigned long data)
-{
-	struct imxmci_host *host = (struct imxmci_host *)data;
-
-	if( host->pdata->card_present() != host->present ) {
-		host->present ^= 1;
-		dev_info(mmc_dev(host->mmc), "card %s\n",
-		      host->present ? "inserted" : "removed");
-
-		set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
-		tasklet_schedule(&host->tasklet);
-	}
-
-	if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
-	   test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
-		atomic_inc(&host->stuck_timeout);
-		if(atomic_read(&host->stuck_timeout) > 4)
-			tasklet_schedule(&host->tasklet);
-	} else {
-		atomic_set(&host->stuck_timeout, 0);
-
-	}
-
-	mod_timer(&host->timer, jiffies + (HZ>>1));
-}
-
-static int imxmci_probe(struct platform_device *pdev)
-{
-	struct mmc_host *mmc;
-	struct imxmci_host *host = NULL;
-	struct resource *r;
-	int ret = 0, irq;
-
-	printk(KERN_INFO "i.MX mmc driver\n");
-
-	r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
-	irq = platform_device_irq(pdev, 0);
-	if (!r || irq == NO_IRQ)
-		return -ENXIO;
-
-	r = request_mem_region(r->start, 0x100, "IMXMCI");
-	if (!r)
-		return -EBUSY;
-
-	mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
-	if (!mmc) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	mmc->ops = &imxmci_ops;
-	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_CAP_BYTEBLOCK;
-
-	/* MMC core transfer sizes tunable parameters */
-	mmc->max_hw_segs = 64;
-	mmc->max_phys_segs = 64;
-	mmc->max_seg_size = 64*512;	/* default PAGE_CACHE_SIZE */
-	mmc->max_req_size = 64*512;	/* default PAGE_CACHE_SIZE */
-	mmc->max_blk_size = 2048;
-	mmc->max_blk_count = 65535;
-
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
-	host->dma_allocated = 0;
-	host->pdata = pdev->dev.platform_data;
-
-	spin_lock_init(&host->lock);
-	host->res = r;
-	host->irq = irq;
-
-	imx_gpio_mode(PB8_PF_SD_DAT0);
-	imx_gpio_mode(PB9_PF_SD_DAT1);
-	imx_gpio_mode(PB10_PF_SD_DAT2);
-	/* Configured as GPIO with pull-up to ensure right MCC card mode */
-	/* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
-	imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
-	/* imx_gpio_mode(PB11_PF_SD_DAT3); */
-	imx_gpio_mode(PB12_PF_SD_CLK);
-	imx_gpio_mode(PB13_PF_SD_CMD);
-
-	imxmci_softreset();
-
-	if ( MMC_REV_NO != 0x390 ) {
-		dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
-		        MMC_REV_NO);
-		goto out;
-	}
-
-	MMC_READ_TO = 0x2db4; /* recommended in data sheet */
-
-	host->imask = IMXMCI_INT_MASK_DEFAULT;
-	MMC_INT_MASK = host->imask;
-
-
-	if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){
-		dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
-		ret = -EBUSY;
-		goto out;
-	}
-	host->dma_allocated=1;
-	imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
-
-	tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
-	host->status_reg=0;
-	host->pending_events=0;
-
-	ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
-	if (ret)
-		goto out;
-
-	host->present = host->pdata->card_present();
-	init_timer(&host->timer);
-	host->timer.data = (unsigned long)host;
-	host->timer.function = imxmci_check_status;
-	add_timer(&host->timer);
-	mod_timer(&host->timer, jiffies + (HZ>>1));
-
-	platform_set_drvdata(pdev, mmc);
-
-	mmc_add_host(mmc);
-
-	return 0;
-
-out:
-	if (host) {
-		if(host->dma_allocated){
-			imx_dma_free(host->dma);
-			host->dma_allocated=0;
-		}
-	}
-	if (mmc)
-		mmc_free_host(mmc);
-	release_resource(r);
-	return ret;
-}
-
-static int imxmci_remove(struct platform_device *pdev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
-
-	if (mmc) {
-		struct imxmci_host *host = mmc_priv(mmc);
-
-		tasklet_disable(&host->tasklet);
-
-		del_timer_sync(&host->timer);
-		mmc_remove_host(mmc);
-
-		free_irq(host->irq, host);
-		if(host->dma_allocated){
-			imx_dma_free(host->dma);
-			host->dma_allocated=0;
-		}
-
-		tasklet_kill(&host->tasklet);
-
-		release_resource(host->res);
-
-		mmc_free_host(mmc);
-	}
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	int ret = 0;
-
-	if (mmc)
-		ret = mmc_suspend_host(mmc, state);
-
-	return ret;
-}
-
-static int imxmci_resume(struct platform_device *dev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	struct imxmci_host *host;
-	int ret = 0;
-
-	if (mmc) {
-		host = mmc_priv(mmc);
-		if(host)
-			set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
-		ret = mmc_resume_host(mmc);
-	}
-
-	return ret;
-}
-#else
-#define imxmci_suspend  NULL
-#define imxmci_resume   NULL
-#endif /* CONFIG_PM */
-
-static struct platform_driver imxmci_driver = {
-	.probe		= imxmci_probe,
-	.remove		= imxmci_remove,
-	.suspend	= imxmci_suspend,
-	.resume		= imxmci_resume,
-	.driver		= {
-		.name		= DRIVER_NAME,
-	}
-};
-
-static int __init imxmci_init(void)
-{
-	return platform_driver_register(&imxmci_driver);
-}
-
-static void __exit imxmci_exit(void)
-{
-	platform_driver_unregister(&imxmci_driver);
-}
-
-module_init(imxmci_init);
-module_exit(imxmci_exit);
-
-MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/imxmmc.h
deleted file mode 100644
index e5339e3..0000000
--- a/drivers/mmc/imxmmc.h
+++ /dev/null
@@ -1,67 +0,0 @@
-
-# define __REG16(x)	(*((volatile u16 *)IO_ADDRESS(x)))
-
-#define MMC_STR_STP_CLK  __REG16(IMX_MMC_BASE + 0x00)
-#define MMC_STATUS       __REG16(IMX_MMC_BASE + 0x04)
-#define MMC_CLK_RATE     __REG16(IMX_MMC_BASE + 0x08)
-#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
-#define MMC_RES_TO       __REG16(IMX_MMC_BASE + 0x10)
-#define MMC_READ_TO      __REG16(IMX_MMC_BASE + 0x14)
-#define MMC_BLK_LEN      __REG16(IMX_MMC_BASE + 0x18)
-#define MMC_NOB          __REG16(IMX_MMC_BASE + 0x1C)
-#define MMC_REV_NO       __REG16(IMX_MMC_BASE + 0x20)
-#define MMC_INT_MASK     __REG16(IMX_MMC_BASE + 0x24)
-#define MMC_CMD          __REG16(IMX_MMC_BASE + 0x28)
-#define MMC_ARGH         __REG16(IMX_MMC_BASE + 0x2C)
-#define MMC_ARGL         __REG16(IMX_MMC_BASE + 0x30)
-#define MMC_RES_FIFO     __REG16(IMX_MMC_BASE + 0x34)
-#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
-#define MMC_BUFFER_ACCESS_OFS 0x38
-
-
-#define STR_STP_CLK_ENDIAN              (1<<5)
-#define STR_STP_CLK_RESET               (1<<3)
-#define STR_STP_CLK_ENABLE              (1<<2)
-#define STR_STP_CLK_START_CLK           (1<<1)
-#define STR_STP_CLK_STOP_CLK            (1<<0)
-#define STATUS_CARD_PRESENCE            (1<<15)
-#define STATUS_SDIO_INT_ACTIVE          (1<<14)
-#define STATUS_END_CMD_RESP             (1<<13)
-#define STATUS_WRITE_OP_DONE            (1<<12)
-#define STATUS_DATA_TRANS_DONE          (1<<11)
-#define STATUS_WR_CRC_ERROR_CODE_MASK   (3<<10)
-#define STATUS_CARD_BUS_CLK_RUN         (1<<8)
-#define STATUS_APPL_BUFF_FF             (1<<7)
-#define STATUS_APPL_BUFF_FE             (1<<6)
-#define STATUS_RESP_CRC_ERR             (1<<5)
-#define STATUS_CRC_READ_ERR             (1<<3)
-#define STATUS_CRC_WRITE_ERR            (1<<2)
-#define STATUS_TIME_OUT_RESP            (1<<1)
-#define STATUS_TIME_OUT_READ            (1<<0)
-#define STATUS_ERR_MASK                 0x2f
-#define CLK_RATE_PRESCALER(x)           ((x) & 0x7)
-#define CLK_RATE_CLK_RATE(x)            (((x) & 0x7) << 3)
-#define CMD_DAT_CONT_CMD_RESP_LONG_OFF  (1<<12)
-#define CMD_DAT_CONT_STOP_READWAIT      (1<<11)
-#define CMD_DAT_CONT_START_READWAIT     (1<<10)
-#define CMD_DAT_CONT_BUS_WIDTH_1        (0<<8)
-#define CMD_DAT_CONT_BUS_WIDTH_4        (2<<8)
-#define CMD_DAT_CONT_INIT               (1<<7)
-#define CMD_DAT_CONT_BUSY               (1<<6)
-#define CMD_DAT_CONT_STREAM_BLOCK       (1<<5)
-#define CMD_DAT_CONT_WRITE              (1<<4)
-#define CMD_DAT_CONT_DATA_ENABLE        (1<<3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
-#define INT_MASK_AUTO_CARD_DETECT       (1<<6)
-#define INT_MASK_DAT0_EN                (1<<5)
-#define INT_MASK_SDIO                   (1<<4)
-#define INT_MASK_BUF_READY              (1<<3)
-#define INT_MASK_END_CMD_RES            (1<<2)
-#define INT_MASK_WRITE_OP_DONE          (1<<1)
-#define INT_MASK_DATA_TRAN              (1<<0)
-#define INT_ALL                         (0x7f)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
deleted file mode 100644
index 4a73e8b..0000000
--- a/drivers/mmc/mmc.c
+++ /dev/null
@@ -1,1724 +0,0 @@
-/*
- *  linux/drivers/mmc/mmc.c
- *
- *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
- *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
- *  MMCv4 support Copyright (C) 2006 Philip Langdale, 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/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/pagemap.h>
-#include <linux/err.h>
-#include <asm/scatterlist.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include "mmc.h"
-
-#define CMD_RETRIES	3
-
-/*
- * OCR Bit positions to 10s of Vdd mV.
- */
-static const unsigned short mmc_ocr_bit_to_vdd[] = {
-	150,	155,	160,	165,	170,	180,	190,	200,
-	210,	220,	230,	240,	250,	260,	270,	280,
-	290,	300,	310,	320,	330,	340,	350,	360
-};
-
-static const unsigned int tran_exp[] = {
-	10000,		100000,		1000000,	10000000,
-	0,		0,		0,		0
-};
-
-static const unsigned char tran_mant[] = {
-	0,	10,	12,	13,	15,	20,	25,	30,
-	35,	40,	45,	50,	55,	60,	70,	80,
-};
-
-static const unsigned int tacc_exp[] = {
-	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,
-};
-
-static const unsigned int tacc_mant[] = {
-	0,	10,	12,	13,	15,	20,	25,	30,
-	35,	40,	45,	50,	55,	60,	70,	80,
-};
-
-
-/**
- *	mmc_request_done - finish processing an MMC request
- *	@host: MMC host which completed request
- *	@mrq: MMC request which request
- *
- *	MMC drivers should call this function when they have completed
- *	their processing of a request.
- */
-void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
-{
-	struct mmc_command *cmd = mrq->cmd;
-	int err = cmd->error;
-
-	pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
-		 mmc_hostname(host), cmd->opcode, err,
-		 mrq->data ? mrq->data->error : 0,
-		 mrq->stop ? mrq->stop->error : 0,
-		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
-	if (err && cmd->retries) {
-		cmd->retries--;
-		cmd->error = 0;
-		host->ops->request(host, mrq);
-	} else if (mrq->done) {
-		mrq->done(mrq);
-	}
-}
-
-EXPORT_SYMBOL(mmc_request_done);
-
-/**
- *	mmc_start_request - start a command on a host
- *	@host: MMC host to start command on
- *	@mrq: MMC request to start
- *
- *	Queue a command on the specified host.  We expect the
- *	caller to be holding the host lock with interrupts disabled.
- */
-void
-mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
-{
-	pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
-		 mmc_hostname(host), mrq->cmd->opcode,
-		 mrq->cmd->arg, mrq->cmd->flags);
-
-	WARN_ON(!host->claimed);
-
-	mrq->cmd->error = 0;
-	mrq->cmd->mrq = mrq;
-	if (mrq->data) {
-		BUG_ON(mrq->data->blksz > host->max_blk_size);
-		BUG_ON(mrq->data->blocks > host->max_blk_count);
-		BUG_ON(mrq->data->blocks * mrq->data->blksz >
-			host->max_req_size);
-
-		mrq->cmd->data = mrq->data;
-		mrq->data->error = 0;
-		mrq->data->mrq = mrq;
-		if (mrq->stop) {
-			mrq->data->stop = mrq->stop;
-			mrq->stop->error = 0;
-			mrq->stop->mrq = mrq;
-		}
-	}
-	host->ops->request(host, mrq);
-}
-
-EXPORT_SYMBOL(mmc_start_request);
-
-static void mmc_wait_done(struct mmc_request *mrq)
-{
-	complete(mrq->done_data);
-}
-
-int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
-{
-	DECLARE_COMPLETION_ONSTACK(complete);
-
-	mrq->done_data = &complete;
-	mrq->done = mmc_wait_done;
-
-	mmc_start_request(host, mrq);
-
-	wait_for_completion(&complete);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_req);
-
-/**
- *	mmc_wait_for_cmd - start a command and wait for completion
- *	@host: MMC host to start command
- *	@cmd: MMC command to start
- *	@retries: maximum number of retries
- *
- *	Start a new MMC command for a host, and wait for the command
- *	to complete.  Return any error that occurred while the command
- *	was executing.  Do not attempt to parse the response.
- */
-int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
-{
-	struct mmc_request mrq;
-
-	BUG_ON(!host->claimed);
-
-	memset(&mrq, 0, sizeof(struct mmc_request));
-
-	memset(cmd->resp, 0, sizeof(cmd->resp));
-	cmd->retries = retries;
-
-	mrq.cmd = cmd;
-	cmd->data = NULL;
-
-	mmc_wait_for_req(host, &mrq);
-
-	return cmd->error;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_cmd);
-
-/**
- *	mmc_wait_for_app_cmd - start an application command and wait for
- 			       completion
- *	@host: MMC host to start command
- *	@rca: RCA to send MMC_APP_CMD to
- *	@cmd: MMC command to start
- *	@retries: maximum number of retries
- *
- *	Sends a MMC_APP_CMD, checks the card response, sends the command
- *	in the parameter and waits for it to complete. Return any error
- *	that occurred while the command was executing.  Do not attempt to
- *	parse the response.
- */
-int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
-	struct mmc_command *cmd, int retries)
-{
-	struct mmc_request mrq;
-	struct mmc_command appcmd;
-
-	int i, err;
-
-	BUG_ON(!host->claimed);
-	BUG_ON(retries < 0);
-
-	err = MMC_ERR_INVALID;
-
-	/*
-	 * We have to resend MMC_APP_CMD for each attempt so
-	 * we cannot use the retries field in mmc_command.
-	 */
-	for (i = 0;i <= retries;i++) {
-		memset(&mrq, 0, sizeof(struct mmc_request));
-
-		appcmd.opcode = MMC_APP_CMD;
-		appcmd.arg = rca << 16;
-		appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-		appcmd.retries = 0;
-		memset(appcmd.resp, 0, sizeof(appcmd.resp));
-		appcmd.data = NULL;
-
-		mrq.cmd = &appcmd;
-		appcmd.data = NULL;
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (appcmd.error) {
-			err = appcmd.error;
-			continue;
-		}
-
-		/* Check that card supported application commands */
-		if (!(appcmd.resp[0] & R1_APP_CMD))
-			return MMC_ERR_FAILED;
-
-		memset(&mrq, 0, sizeof(struct mmc_request));
-
-		memset(cmd->resp, 0, sizeof(cmd->resp));
-		cmd->retries = 0;
-
-		mrq.cmd = cmd;
-		cmd->data = NULL;
-
-		mmc_wait_for_req(host, &mrq);
-
-		err = cmd->error;
-		if (cmd->error == MMC_ERR_NONE)
-			break;
-	}
-
-	return err;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-
-/**
- *	mmc_set_data_timeout - set the timeout for a data command
- *	@data: data phase for command
- *	@card: the MMC card associated with the data transfer
- *	@write: flag to differentiate reads from writes
- */
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
-			  int write)
-{
-	unsigned int mult;
-
-	/*
-	 * SD cards use a 100 multiplier rather than 10
-	 */
-	mult = mmc_card_sd(card) ? 100 : 10;
-
-	/*
-	 * Scale up the multiplier (and therefore the timeout) by
-	 * the r2w factor for writes.
-	 */
-	if (write)
-		mult <<= card->csd.r2w_factor;
-
-	data->timeout_ns = card->csd.tacc_ns * mult;
-	data->timeout_clks = card->csd.tacc_clks * mult;
-
-	/*
-	 * SD cards also have an upper limit on the timeout.
-	 */
-	if (mmc_card_sd(card)) {
-		unsigned int timeout_us, limit_us;
-
-		timeout_us = data->timeout_ns / 1000;
-		timeout_us += data->timeout_clks * 1000 /
-			(card->host->ios.clock / 1000);
-
-		if (write)
-			limit_us = 250000;
-		else
-			limit_us = 100000;
-
-		/*
-		 * SDHC cards always use these fixed values.
-		 */
-		if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
-			data->timeout_ns = limit_us * 1000;
-			data->timeout_clks = 0;
-		}
-	}
-}
-EXPORT_SYMBOL(mmc_set_data_timeout);
-
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
-
-/**
- *	__mmc_claim_host - exclusively claim a host
- *	@host: mmc host to claim
- *	@card: mmc card to claim host for
- *
- *	Claim a host for a set of operations.  If a valid card
- *	is passed and this wasn't the last card selected, select
- *	the card before returning.
- *
- *	Note: you should use mmc_card_claim_host or mmc_claim_host.
- */
-int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int err = 0;
-
-	add_wait_queue(&host->wq, &wait);
-	spin_lock_irqsave(&host->lock, flags);
-	while (1) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!host->claimed)
-			break;
-		spin_unlock_irqrestore(&host->lock, flags);
-		schedule();
-		spin_lock_irqsave(&host->lock, flags);
-	}
-	set_current_state(TASK_RUNNING);
-	host->claimed = 1;
-	spin_unlock_irqrestore(&host->lock, flags);
-	remove_wait_queue(&host->wq, &wait);
-
-	if (card != (void *)-1) {
-		err = mmc_select_card(host, card);
-		if (err != MMC_ERR_NONE)
-			return err;
-	}
-
-	return err;
-}
-
-EXPORT_SYMBOL(__mmc_claim_host);
-
-/**
- *	mmc_release_host - release a host
- *	@host: mmc host to release
- *
- *	Release a MMC host, allowing others to claim the host
- *	for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	BUG_ON(!host->claimed);
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->claimed = 0;
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	wake_up(&host->wq);
-}
-
-EXPORT_SYMBOL(mmc_release_host);
-
-static inline void mmc_set_ios(struct mmc_host *host)
-{
-	struct mmc_ios *ios = &host->ios;
-
-	pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
-		"width %u timing %u\n",
-		 mmc_hostname(host), ios->clock, ios->bus_mode,
-		 ios->power_mode, ios->chip_select, ios->vdd,
-		 ios->bus_width, ios->timing);
-
-	host->ops->set_ios(host, ios);
-}
-
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
-{
-	int err;
-	struct mmc_command cmd;
-
-	BUG_ON(!host->claimed);
-
-	if (host->card_selected == card)
-		return MMC_ERR_NONE;
-
-	host->card_selected = card;
-
-	cmd.opcode = MMC_SELECT_CARD;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
-		return err;
-
-	/*
-	 * We can only change the bus width of SD cards when
-	 * they are selected so we have to put the handling
-	 * here.
-	 *
-	 * The card is in 1 bit mode by default so
-	 * we only need to change if it supports the
-	 * wider version.
-	 */
-	if (mmc_card_sd(card) &&
-		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
-
-		/*
-		* Default bus width is 1 bit.
-		*/
-		host->ios.bus_width = MMC_BUS_WIDTH_1;
-
-		if (host->caps & MMC_CAP_4_BIT_DATA) {
-			struct mmc_command cmd;
-			cmd.opcode = SD_APP_SET_BUS_WIDTH;
-			cmd.arg = SD_BUS_WIDTH_4;
-			cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-			err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
-				CMD_RETRIES);
-			if (err != MMC_ERR_NONE)
-				return err;
-
-			host->ios.bus_width = MMC_BUS_WIDTH_4;
-		}
-	}
-
-	mmc_set_ios(host);
-
-	return MMC_ERR_NONE;
-}
-
-/*
- * Ensure that no card is selected.
- */
-static void mmc_deselect_cards(struct mmc_host *host)
-{
-	struct mmc_command cmd;
-
-	if (host->card_selected) {
-		host->card_selected = NULL;
-
-		cmd.opcode = MMC_SELECT_CARD;
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
-
-		mmc_wait_for_cmd(host, &cmd, 0);
-	}
-}
-
-
-static inline void mmc_delay(unsigned int ms)
-{
-	if (ms < 1000 / HZ) {
-		cond_resched();
-		mdelay(ms);
-	} else {
-		msleep(ms);
-	}
-}
-
-/*
- * Mask off any voltages we don't support and select
- * the lowest voltage
- */
-static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
-{
-	int bit;
-
-	ocr &= host->ocr_avail;
-
-	bit = ffs(ocr);
-	if (bit) {
-		bit -= 1;
-
-		ocr &= 3 << bit;
-
-		host->ios.vdd = bit;
-		mmc_set_ios(host);
-	} else {
-		ocr = 0;
-	}
-
-	return ocr;
-}
-
-#define UNSTUFF_BITS(resp,start,size)					\
-	({								\
-		const int __size = size;				\
-		const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1;	\
-		const int __off = 3 - ((start) / 32);			\
-		const int __shft = (start) & 31;			\
-		u32 __res;						\
-									\
-		__res = resp[__off] >> __shft;				\
-		if (__size + __shft > 32)				\
-			__res |= resp[__off-1] << ((32 - __shft) % 32);	\
-		__res & __mask;						\
-	})
-
-/*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-static void mmc_decode_cid(struct mmc_card *card)
-{
-	u32 *resp = card->raw_cid;
-
-	memset(&card->cid, 0, sizeof(struct mmc_cid));
-
-	if (mmc_card_sd(card)) {
-		/*
-		 * SD doesn't currently have a version field so we will
-		 * have to assume we can parse this.
-		 */
-		card->cid.manfid		= UNSTUFF_BITS(resp, 120, 8);
-		card->cid.oemid			= UNSTUFF_BITS(resp, 104, 16);
-		card->cid.prod_name[0]		= UNSTUFF_BITS(resp, 96, 8);
-		card->cid.prod_name[1]		= UNSTUFF_BITS(resp, 88, 8);
-		card->cid.prod_name[2]		= UNSTUFF_BITS(resp, 80, 8);
-		card->cid.prod_name[3]		= UNSTUFF_BITS(resp, 72, 8);
-		card->cid.prod_name[4]		= UNSTUFF_BITS(resp, 64, 8);
-		card->cid.hwrev			= UNSTUFF_BITS(resp, 60, 4);
-		card->cid.fwrev			= UNSTUFF_BITS(resp, 56, 4);
-		card->cid.serial		= UNSTUFF_BITS(resp, 24, 32);
-		card->cid.year			= UNSTUFF_BITS(resp, 12, 8);
-		card->cid.month			= UNSTUFF_BITS(resp, 8, 4);
-
-		card->cid.year += 2000; /* SD cards year offset */
-	} else {
-		/*
-		 * The selection of the format here is based upon published
-		 * specs from sandisk and from what people have reported.
-		 */
-		switch (card->csd.mmca_vsn) {
-		case 0: /* MMC v1.0 - v1.2 */
-		case 1: /* MMC v1.4 */
-			card->cid.manfid	= UNSTUFF_BITS(resp, 104, 24);
-			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-			card->cid.prod_name[6]	= UNSTUFF_BITS(resp, 48, 8);
-			card->cid.hwrev		= UNSTUFF_BITS(resp, 44, 4);
-			card->cid.fwrev		= UNSTUFF_BITS(resp, 40, 4);
-			card->cid.serial	= UNSTUFF_BITS(resp, 16, 24);
-			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-			break;
-
-		case 2: /* MMC v2.0 - v2.2 */
-		case 3: /* MMC v3.1 - v3.3 */
-		case 4: /* MMC v4 */
-			card->cid.manfid	= UNSTUFF_BITS(resp, 120, 8);
-			card->cid.oemid		= UNSTUFF_BITS(resp, 104, 16);
-			card->cid.prod_name[0]	= UNSTUFF_BITS(resp, 96, 8);
-			card->cid.prod_name[1]	= UNSTUFF_BITS(resp, 88, 8);
-			card->cid.prod_name[2]	= UNSTUFF_BITS(resp, 80, 8);
-			card->cid.prod_name[3]	= UNSTUFF_BITS(resp, 72, 8);
-			card->cid.prod_name[4]	= UNSTUFF_BITS(resp, 64, 8);
-			card->cid.prod_name[5]	= UNSTUFF_BITS(resp, 56, 8);
-			card->cid.serial	= UNSTUFF_BITS(resp, 16, 32);
-			card->cid.month		= UNSTUFF_BITS(resp, 12, 4);
-			card->cid.year		= UNSTUFF_BITS(resp, 8, 4) + 1997;
-			break;
-
-		default:
-			printk("%s: card has unknown MMCA version %d\n",
-				mmc_hostname(card->host), card->csd.mmca_vsn);
-			mmc_card_set_bad(card);
-			break;
-		}
-	}
-}
-
-/*
- * Given a 128-bit response, decode to our card CSD structure.
- */
-static void mmc_decode_csd(struct mmc_card *card)
-{
-	struct mmc_csd *csd = &card->csd;
-	unsigned int e, m, csd_struct;
-	u32 *resp = card->raw_csd;
-
-	if (mmc_card_sd(card)) {
-		csd_struct = UNSTUFF_BITS(resp, 126, 2);
-
-		switch (csd_struct) {
-		case 0:
-			m = UNSTUFF_BITS(resp, 115, 4);
-			e = UNSTUFF_BITS(resp, 112, 3);
-			csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-			csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
-
-			m = UNSTUFF_BITS(resp, 99, 4);
-			e = UNSTUFF_BITS(resp, 96, 3);
-			csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-			csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
-
-			e = UNSTUFF_BITS(resp, 47, 3);
-			m = UNSTUFF_BITS(resp, 62, 12);
-			csd->capacity	  = (1 + m) << (e + 2);
-
-			csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
-			csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
-			csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
-			csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
-			csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
-			csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
-			csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
-			break;
-		case 1:
-			/*
-			 * This is a block-addressed SDHC card. Most
-			 * interesting fields are unused and have fixed
-			 * values. To avoid getting tripped by buggy cards,
-			 * we assume those fixed values ourselves.
-			 */
-			mmc_card_set_blockaddr(card);
-
-			csd->tacc_ns	 = 0; /* Unused */
-			csd->tacc_clks	 = 0; /* Unused */
-
-			m = UNSTUFF_BITS(resp, 99, 4);
-			e = UNSTUFF_BITS(resp, 96, 3);
-			csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-			csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
-
-			m = UNSTUFF_BITS(resp, 48, 22);
-			csd->capacity     = (1 + m) << 10;
-
-			csd->read_blkbits = 9;
-			csd->read_partial = 0;
-			csd->write_misalign = 0;
-			csd->read_misalign = 0;
-			csd->r2w_factor = 4; /* Unused */
-			csd->write_blkbits = 9;
-			csd->write_partial = 0;
-			break;
-		default:
-			printk("%s: unrecognised CSD structure version %d\n",
-				mmc_hostname(card->host), csd_struct);
-			mmc_card_set_bad(card);
-			return;
-		}
-	} else {
-		/*
-		 * We only understand CSD structure v1.1 and v1.2.
-		 * v1.2 has extra information in bits 15, 11 and 10.
-		 */
-		csd_struct = UNSTUFF_BITS(resp, 126, 2);
-		if (csd_struct != 1 && csd_struct != 2) {
-			printk("%s: unrecognised CSD structure version %d\n",
-				mmc_hostname(card->host), csd_struct);
-			mmc_card_set_bad(card);
-			return;
-		}
-
-		csd->mmca_vsn	 = UNSTUFF_BITS(resp, 122, 4);
-		m = UNSTUFF_BITS(resp, 115, 4);
-		e = UNSTUFF_BITS(resp, 112, 3);
-		csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-		csd->tacc_clks	 = UNSTUFF_BITS(resp, 104, 8) * 100;
-
-		m = UNSTUFF_BITS(resp, 99, 4);
-		e = UNSTUFF_BITS(resp, 96, 3);
-		csd->max_dtr	  = tran_exp[e] * tran_mant[m];
-		csd->cmdclass	  = UNSTUFF_BITS(resp, 84, 12);
-
-		e = UNSTUFF_BITS(resp, 47, 3);
-		m = UNSTUFF_BITS(resp, 62, 12);
-		csd->capacity	  = (1 + m) << (e + 2);
-
-		csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
-		csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
-		csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
-		csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
-		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
-		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
-		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
-	}
-}
-
-/*
- * Given a 64-bit response, decode to our card SCR structure.
- */
-static void mmc_decode_scr(struct mmc_card *card)
-{
-	struct sd_scr *scr = &card->scr;
-	unsigned int scr_struct;
-	u32 resp[4];
-
-	BUG_ON(!mmc_card_sd(card));
-
-	resp[3] = card->raw_scr[1];
-	resp[2] = card->raw_scr[0];
-
-	scr_struct = UNSTUFF_BITS(resp, 60, 4);
-	if (scr_struct != 0) {
-		printk("%s: unrecognised SCR structure version %d\n",
-			mmc_hostname(card->host), scr_struct);
-		mmc_card_set_bad(card);
-		return;
-	}
-
-	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
-	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
-}
-
-/*
- * Locate a MMC card on this MMC host given a raw CID.
- */
-static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
-{
-	struct mmc_card *card;
-
-	list_for_each_entry(card, &host->cards, node) {
-		if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0)
-			return card;
-	}
-	return NULL;
-}
-
-/*
- * Allocate a new MMC card, and assign a unique RCA.
- */
-static struct mmc_card *
-mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
-{
-	struct mmc_card *card, *c;
-	unsigned int rca = *frca;
-
-	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
-	if (!card)
-		return ERR_PTR(-ENOMEM);
-
-	mmc_init_card(card, host);
-	memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
-
- again:
-	list_for_each_entry(c, &host->cards, node)
-		if (c->rca == rca) {
-			rca++;
-			goto again;
-		}
-
-	card->rca = rca;
-
-	*frca = rca;
-
-	return card;
-}
-
-/*
- * Tell attached cards to go to IDLE state
- */
-static void mmc_idle_cards(struct mmc_host *host)
-{
-	struct mmc_command cmd;
-
-	host->ios.chip_select = MMC_CS_HIGH;
-	mmc_set_ios(host);
-
-	mmc_delay(1);
-
-	cmd.opcode = MMC_GO_IDLE_STATE;
-	cmd.arg = 0;
-	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
-
-	mmc_wait_for_cmd(host, &cmd, 0);
-
-	mmc_delay(1);
-
-	host->ios.chip_select = MMC_CS_DONTCARE;
-	mmc_set_ios(host);
-
-	mmc_delay(1);
-}
-
-/*
- * Apply power to the MMC stack.  This is a two-stage process.
- * First, we enable power to the card without the clock running.
- * We then wait a bit for the power to stabilise.  Finally,
- * enable the bus drivers and clock to the card.
- *
- * We must _NOT_ enable the clock prior to power stablising.
- *
- * If a host does all the power sequencing itself, ignore the
- * initial MMC_POWER_UP stage.
- */
-static void mmc_power_up(struct mmc_host *host)
-{
-	int bit = fls(host->ocr_avail) - 1;
-
-	host->ios.vdd = bit;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
-	host->ios.power_mode = MMC_POWER_UP;
-	host->ios.bus_width = MMC_BUS_WIDTH_1;
-	host->ios.timing = MMC_TIMING_LEGACY;
-	mmc_set_ios(host);
-
-	mmc_delay(1);
-
-	host->ios.clock = host->f_min;
-	host->ios.power_mode = MMC_POWER_ON;
-	mmc_set_ios(host);
-
-	mmc_delay(2);
-}
-
-static void mmc_power_off(struct mmc_host *host)
-{
-	host->ios.clock = 0;
-	host->ios.vdd = 0;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
-	host->ios.power_mode = MMC_POWER_OFF;
-	host->ios.bus_width = MMC_BUS_WIDTH_1;
-	host->ios.timing = MMC_TIMING_LEGACY;
-	mmc_set_ios(host);
-}
-
-static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
-	struct mmc_command cmd;
-	int i, err = 0;
-
-	cmd.opcode = MMC_SEND_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
-	for (i = 100; i; i--) {
-		err = mmc_wait_for_cmd(host, &cmd, 0);
-		if (err != MMC_ERR_NONE)
-			break;
-
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
-			break;
-
-		err = MMC_ERR_TIMEOUT;
-
-		mmc_delay(10);
-	}
-
-	if (rocr)
-		*rocr = cmd.resp[0];
-
-	return err;
-}
-
-static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
-	struct mmc_command cmd;
-	int i, err = 0;
-
-	cmd.opcode = SD_APP_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
-	for (i = 100; i; i--) {
-		err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
-			break;
-
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
-			break;
-
-		err = MMC_ERR_TIMEOUT;
-
-		mmc_delay(10);
-	}
-
-	if (rocr)
-		*rocr = cmd.resp[0];
-
-	return err;
-}
-
-static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
-{
-	struct mmc_command cmd;
-	int err, sd2;
-	static const u8 test_pattern = 0xAA;
-
-	/*
-	* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
-	* before SD_APP_OP_COND. This command will harmlessly fail for
-	* SD 1.0 cards.
-	*/
-	cmd.opcode = SD_SEND_IF_COND;
-	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
-	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
-
-	err = mmc_wait_for_cmd(host, &cmd, 0);
-	if (err == MMC_ERR_NONE) {
-		if ((cmd.resp[0] & 0xFF) == test_pattern) {
-			sd2 = 1;
-		} else {
-			sd2 = 0;
-			err = MMC_ERR_FAILED;
-		}
-	} else {
-		/*
-		 * Treat errors as SD 1.0 card.
-		 */
-		sd2 = 0;
-		err = MMC_ERR_NONE;
-	}
-	if (rsd2)
-		*rsd2 = sd2;
-	return err;
-}
-
-/*
- * Discover cards by requesting their CID.  If this command
- * times out, it is not an error; there are no further cards
- * to be discovered.  Add new cards to the list.
- *
- * Create a mmc_card entry for each discovered card, assigning
- * it an RCA, and save the raw CID for decoding later.
- */
-static void mmc_discover_cards(struct mmc_host *host)
-{
-	struct mmc_card *card;
-	unsigned int first_rca = 1, err;
-
-	while (1) {
-		struct mmc_command cmd;
-
-		cmd.opcode = MMC_ALL_SEND_CID;
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-		if (err == MMC_ERR_TIMEOUT) {
-			err = MMC_ERR_NONE;
-			break;
-		}
-		if (err != MMC_ERR_NONE) {
-			printk(KERN_ERR "%s: error requesting CID: %d\n",
-				mmc_hostname(host), err);
-			break;
-		}
-
-		card = mmc_find_card(host, cmd.resp);
-		if (!card) {
-			card = mmc_alloc_card(host, cmd.resp, &first_rca);
-			if (IS_ERR(card)) {
-				err = PTR_ERR(card);
-				break;
-			}
-			list_add(&card->node, &host->cards);
-		}
-
-		card->state &= ~MMC_STATE_DEAD;
-
-		if (host->mode == MMC_MODE_SD) {
-			mmc_card_set_sd(card);
-
-			cmd.opcode = SD_SEND_RELATIVE_ADDR;
-			cmd.arg = 0;
-			cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
-
-			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-			if (err != MMC_ERR_NONE)
-				mmc_card_set_dead(card);
-			else {
-				card->rca = cmd.resp[0] >> 16;
-
-				if (!host->ops->get_ro) {
-					printk(KERN_WARNING "%s: host does not "
-						"support reading read-only "
-						"switch. assuming write-enable.\n",
-						mmc_hostname(host));
-				} else {
-					if (host->ops->get_ro(host))
-						mmc_card_set_readonly(card);
-				}
-			}
-		} else {
-			cmd.opcode = MMC_SET_RELATIVE_ADDR;
-			cmd.arg = card->rca << 16;
-			cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-			if (err != MMC_ERR_NONE)
-				mmc_card_set_dead(card);
-		}
-	}
-}
-
-static void mmc_read_csds(struct mmc_host *host)
-{
-	struct mmc_card *card;
-
-	list_for_each_entry(card, &host->cards, node) {
-		struct mmc_command cmd;
-		int err;
-
-		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
-			continue;
-
-		cmd.opcode = MMC_SEND_CSD;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-		if (err != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));
-
-		mmc_decode_csd(card);
-		mmc_decode_cid(card);
-	}
-}
-
-static void mmc_process_ext_csds(struct mmc_host *host)
-{
-	int err;
-	struct mmc_card *card;
-
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-
-	struct scatterlist sg;
-
-	/*
-	 * As the ext_csd is so large and mostly unused, we don't store the
-	 * raw block in mmc_card.
-	 */
-	u8 *ext_csd;
-	ext_csd = kmalloc(512, GFP_KERNEL);
-	if (!ext_csd) {
-		printk("%s: could not allocate a buffer to receive the ext_csd."
-		       "mmc v4 cards will be treated as v3.\n",
-			mmc_hostname(host));
-		return;
-	}
-
-	list_for_each_entry(card, &host->cards, node) {
-		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
-			continue;
-		if (mmc_card_sd(card))
-			continue;
-		if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
-			continue;
-
-		err = mmc_select_card(host, card);
-		if (err != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		memset(&cmd, 0, sizeof(struct mmc_command));
-
-		cmd.opcode = MMC_SEND_EXT_CSD;
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-		memset(&data, 0, sizeof(struct mmc_data));
-
-		mmc_set_data_timeout(&data, card, 0);
-
-		data.blksz = 512;
-		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, ext_csd, 512);
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			printk("%s: unable to read EXT_CSD, performance "
-				"might suffer.\n", mmc_hostname(card->host));
-			continue;
-		}
-
-		switch (ext_csd[EXT_CSD_CARD_TYPE]) {
-		case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
-			card->ext_csd.hs_max_dtr = 52000000;
-			break;
-		case EXT_CSD_CARD_TYPE_26:
-			card->ext_csd.hs_max_dtr = 26000000;
-			break;
-		default:
-			/* MMC v4 spec says this cannot happen */
-			printk("%s: card is mmc v4 but doesn't support "
-			       "any high-speed modes.\n",
-				mmc_hostname(card->host));
-			continue;
-		}
-
-		if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
-			/* Activate highspeed support. */
-			cmd.opcode = MMC_SWITCH;
-			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-				  (EXT_CSD_HS_TIMING << 16) |
-				  (1 << 8) |
-				  EXT_CSD_CMD_SET_NORMAL;
-			cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
-			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-			if (err != MMC_ERR_NONE) {
-				printk("%s: failed to switch card to mmc v4 "
-				       "high-speed mode.\n",
-				       mmc_hostname(card->host));
-				continue;
-			}
-
-			mmc_card_set_highspeed(card);
-
-			host->ios.timing = MMC_TIMING_SD_HS;
-			mmc_set_ios(host);
-		}
-
-		/* Check for host support for wide-bus modes. */
-		if (host->caps & MMC_CAP_4_BIT_DATA) {
-			/* Activate 4-bit support. */
-			cmd.opcode = MMC_SWITCH;
-			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
-				  (EXT_CSD_BUS_WIDTH << 16) |
-				  (EXT_CSD_BUS_WIDTH_4 << 8) |
-				  EXT_CSD_CMD_SET_NORMAL;
-			cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
-			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-			if (err != MMC_ERR_NONE) {
-				printk("%s: failed to switch card to "
-				       "mmc v4 4-bit bus mode.\n",
-				       mmc_hostname(card->host));
-				continue;
-			}
-
-			host->ios.bus_width = MMC_BUS_WIDTH_4;
-			mmc_set_ios(host);
-		}
-	}
-
-	kfree(ext_csd);
-
-	mmc_deselect_cards(host);
-}
-
-static void mmc_read_scrs(struct mmc_host *host)
-{
-	int err;
-	struct mmc_card *card;
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-	struct scatterlist sg;
-
-	list_for_each_entry(card, &host->cards, node) {
-		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
-			continue;
-		if (!mmc_card_sd(card))
-			continue;
-
-		err = mmc_select_card(host, card);
-		if (err != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		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(host, &cmd, 0);
-		if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		memset(&cmd, 0, sizeof(struct mmc_command));
-
-		cmd.opcode = SD_APP_SEND_SCR;
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-		memset(&data, 0, sizeof(struct mmc_data));
-
-		mmc_set_data_timeout(&data, card, 0);
-
-		data.blksz = 1 << 3;
-		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, (u8*)card->raw_scr, 8);
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		card->raw_scr[0] = ntohl(card->raw_scr[0]);
-		card->raw_scr[1] = ntohl(card->raw_scr[1]);
-
-		mmc_decode_scr(card);
-	}
-
-	mmc_deselect_cards(host);
-}
-
-static void mmc_read_switch_caps(struct mmc_host *host)
-{
-	int err;
-	struct mmc_card *card;
-	struct mmc_request mrq;
-	struct mmc_command cmd;
-	struct mmc_data data;
-	unsigned char *status;
-	struct scatterlist sg;
-
-	if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
-		return;
-
-	status = kmalloc(64, GFP_KERNEL);
-	if (!status) {
-		printk(KERN_WARNING "%s: Unable to allocate buffer for "
-			"reading switch capabilities.\n",
-			mmc_hostname(host));
-		return;
-	}
-
-	list_for_each_entry(card, &host->cards, node) {
-		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
-			continue;
-		if (!mmc_card_sd(card))
-			continue;
-		if (card->scr.sda_vsn < SCR_SPEC_VER_1)
-			continue;
-
-		err = mmc_select_card(host, card);
-		if (err != MMC_ERR_NONE) {
-			mmc_card_set_dead(card);
-			continue;
-		}
-
-		memset(&cmd, 0, sizeof(struct mmc_command));
-
-		cmd.opcode = SD_SWITCH;
-		cmd.arg = 0x00FFFFF1;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-		memset(&data, 0, sizeof(struct mmc_data));
-
-		mmc_set_data_timeout(&data, card, 0);
-
-		data.blksz = 64;
-		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, status, 64);
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-			printk("%s: unable to read switch capabilities, "
-				"performance might suffer.\n",
-				mmc_hostname(card->host));
-			continue;
-		}
-
-		if (status[13] & 0x02)
-			card->sw_caps.hs_max_dtr = 50000000;
-
-		memset(&cmd, 0, sizeof(struct mmc_command));
-
-		cmd.opcode = SD_SWITCH;
-		cmd.arg = 0x80FFFFF1;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
-		memset(&data, 0, sizeof(struct mmc_data));
-
-		mmc_set_data_timeout(&data, card, 0);
-
-		data.blksz = 64;
-		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, status, 64);
-
-		mmc_wait_for_req(host, &mrq);
-
-		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
-			(status[16] & 0xF) != 1) {
-			printk(KERN_WARNING "%s: Problem switching card "
-				"into high-speed mode!\n",
-				mmc_hostname(host));
-			continue;
-		}
-
-		mmc_card_set_highspeed(card);
-
-		host->ios.timing = MMC_TIMING_SD_HS;
-		mmc_set_ios(host);
-	}
-
-	kfree(status);
-
-	mmc_deselect_cards(host);
-}
-
-static unsigned int mmc_calculate_clock(struct mmc_host *host)
-{
-	struct mmc_card *card;
-	unsigned int max_dtr = host->f_max;
-
-	list_for_each_entry(card, &host->cards, node)
-		if (!mmc_card_dead(card)) {
-			if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
-				if (max_dtr > card->sw_caps.hs_max_dtr)
-					max_dtr = card->sw_caps.hs_max_dtr;
-			} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
-				if (max_dtr > card->ext_csd.hs_max_dtr)
-					max_dtr = card->ext_csd.hs_max_dtr;
-			} else if (max_dtr > card->csd.max_dtr) {
-				max_dtr = card->csd.max_dtr;
-			}
-		}
-
-	pr_debug("%s: selected %d.%03dMHz transfer rate\n",
-		 mmc_hostname(host),
-		 max_dtr / 1000000, (max_dtr / 1000) % 1000);
-
-	return max_dtr;
-}
-
-/*
- * Check whether cards we already know about are still present.
- * We do this by requesting status, and checking whether a card
- * responds.
- *
- * A request for status does not cause a state change in data
- * transfer mode.
- */
-static void mmc_check_cards(struct mmc_host *host)
-{
-	struct list_head *l, *n;
-
-	mmc_deselect_cards(host);
-
-	list_for_each_safe(l, n, &host->cards) {
-		struct mmc_card *card = mmc_list_to_card(l);
-		struct mmc_command cmd;
-		int err;
-
-		cmd.opcode = MMC_SEND_STATUS;
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
-		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
-		if (err == MMC_ERR_NONE)
-			continue;
-
-		mmc_card_set_dead(card);
-	}
-}
-
-static void mmc_setup(struct mmc_host *host)
-{
-	if (host->ios.power_mode != MMC_POWER_ON) {
-		int err;
-		u32 ocr;
-
-		host->mode = MMC_MODE_SD;
-
-		mmc_power_up(host);
-		mmc_idle_cards(host);
-
-		err = mmc_send_if_cond(host, host->ocr_avail, NULL);
-		if (err != MMC_ERR_NONE) {
-			return;
-		}
-		err = mmc_send_app_op_cond(host, 0, &ocr);
-
-		/*
-		 * If we fail to detect any SD cards then try
-		 * searching for MMC cards.
-		 */
-		if (err != MMC_ERR_NONE) {
-			host->mode = MMC_MODE_MMC;
-
-			err = mmc_send_op_cond(host, 0, &ocr);
-			if (err != MMC_ERR_NONE)
-				return;
-		}
-
-		host->ocr = mmc_select_voltage(host, ocr);
-
-		/*
-		 * Since we're changing the OCR value, we seem to
-		 * need to tell some cards to go back to the idle
-		 * state.  We wait 1ms to give cards time to
-		 * respond.
-		 */
-		if (host->ocr)
-			mmc_idle_cards(host);
-	} else {
-		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-		host->ios.clock = host->f_min;
-		mmc_set_ios(host);
-
-		/*
-		 * We should remember the OCR mask from the existing
-		 * cards, and detect the new cards OCR mask, combine
-		 * the two and re-select the VDD.  However, if we do
-		 * change VDD, we should do an idle, and then do a
-		 * full re-initialisation.  We would need to notify
-		 * drivers so that they can re-setup the cards as
-		 * well, while keeping their queues at bay.
-		 *
-		 * For the moment, we take the easy way out - if the
-		 * new cards don't like our currently selected VDD,
-		 * they drop off the bus.
-		 */
-	}
-
-	if (host->ocr == 0)
-		return;
-
-	/*
-	 * Send the selected OCR multiple times... until the cards
-	 * all get the idea that they should be ready for CMD2.
-	 * (My SanDisk card seems to need this.)
-	 */
-	if (host->mode == MMC_MODE_SD) {
-		int err, sd2;
-		err = mmc_send_if_cond(host, host->ocr, &sd2);
-		if (err == MMC_ERR_NONE) {
-			/*
-			* If SD_SEND_IF_COND indicates an SD 2.0
-			* compliant card and we should set bit 30
-			* of the ocr to indicate that we can handle
-			* block-addressed SDHC cards.
-			*/
-			mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
-		}
-	} else {
-		mmc_send_op_cond(host, host->ocr, NULL);
-	}
-
-	mmc_discover_cards(host);
-
-	/*
-	 * Ok, now switch to push-pull mode.
-	 */
-	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
-	mmc_set_ios(host);
-
-	mmc_read_csds(host);
-
-	if (host->mode == MMC_MODE_SD) {
-		mmc_read_scrs(host);
-		mmc_read_switch_caps(host);
-	} else
-		mmc_process_ext_csds(host);
-}
-
-
-/**
- *	mmc_detect_change - process change of state on a MMC socket
- *	@host: host which changed state.
- *	@delay: optional delay to wait before detection (jiffies)
- *
- *	All we know is that card(s) have been inserted or removed
- *	from the socket(s).  We don't know which socket or cards.
- */
-void mmc_detect_change(struct mmc_host *host, unsigned long delay)
-{
-	mmc_schedule_delayed_work(&host->detect, delay);
-}
-
-EXPORT_SYMBOL(mmc_detect_change);
-
-
-static void mmc_rescan(struct work_struct *work)
-{
-	struct mmc_host *host =
-		container_of(work, struct mmc_host, detect.work);
-	struct list_head *l, *n;
-	unsigned char power_mode;
-
-	mmc_claim_host(host);
-
-	/*
-	 * Check for removed cards and newly inserted ones. We check for
-	 * removed cards first so we can intelligently re-select the VDD.
-	 */
-	power_mode = host->ios.power_mode;
-	if (power_mode == MMC_POWER_ON)
-		mmc_check_cards(host);
-
-	mmc_setup(host);
-
-	/*
-	 * Some broken cards process CMD1 even in stand-by state. There is
-	 * no reply, but an ILLEGAL_COMMAND error is cached and returned
-	 * after next command. We poll for card status here to clear any
-	 * possibly pending error.
-	 */
-	if (power_mode == MMC_POWER_ON)
-		mmc_check_cards(host);
-
-	if (!list_empty(&host->cards)) {
-		/*
-		 * (Re-)calculate the fastest clock rate which the
-		 * attached cards and the host support.
-		 */
-		host->ios.clock = mmc_calculate_clock(host);
-		mmc_set_ios(host);
-	}
-
-	mmc_release_host(host);
-
-	list_for_each_safe(l, n, &host->cards) {
-		struct mmc_card *card = mmc_list_to_card(l);
-
-		/*
-		 * If this is a new and good card, register it.
-		 */
-		if (!mmc_card_present(card) && !mmc_card_dead(card)) {
-			if (mmc_register_card(card))
-				mmc_card_set_dead(card);
-			else
-				mmc_card_set_present(card);
-		}
-
-		/*
-		 * If this card is dead, destroy it.
-		 */
-		if (mmc_card_dead(card)) {
-			list_del(&card->node);
-			mmc_remove_card(card);
-		}
-	}
-
-	/*
-	 * If we discover that there are no cards on the
-	 * bus, turn off the clock and power down.
-	 */
-	if (list_empty(&host->cards))
-		mmc_power_off(host);
-}
-
-
-/**
- *	mmc_alloc_host - initialise the per-host structure.
- *	@extra: sizeof private data structure
- *	@dev: pointer to host device model structure
- *
- *	Initialise the per-host structure.
- */
-struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
-{
-	struct mmc_host *host;
-
-	host = mmc_alloc_host_sysfs(extra, dev);
-	if (host) {
-		spin_lock_init(&host->lock);
-		init_waitqueue_head(&host->wq);
-		INIT_LIST_HEAD(&host->cards);
-		INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-
-		/*
-		 * By default, hosts do not support SGIO or large requests.
-		 * They have to set these according to their abilities.
-		 */
-		host->max_hw_segs = 1;
-		host->max_phys_segs = 1;
-		host->max_seg_size = PAGE_CACHE_SIZE;
-
-		host->max_req_size = PAGE_CACHE_SIZE;
-		host->max_blk_size = 512;
-		host->max_blk_count = PAGE_CACHE_SIZE / 512;
-	}
-
-	return host;
-}
-
-EXPORT_SYMBOL(mmc_alloc_host);
-
-/**
- *	mmc_add_host - initialise host hardware
- *	@host: mmc host
- */
-int mmc_add_host(struct mmc_host *host)
-{
-	int ret;
-
-	ret = mmc_add_host_sysfs(host);
-	if (ret == 0) {
-		mmc_power_off(host);
-		mmc_detect_change(host, 0);
-	}
-
-	return ret;
-}
-
-EXPORT_SYMBOL(mmc_add_host);
-
-/**
- *	mmc_remove_host - remove host hardware
- *	@host: mmc host
- *
- *	Unregister and remove all cards associated with this host,
- *	and power down the MMC bus.
- */
-void mmc_remove_host(struct mmc_host *host)
-{
-	struct list_head *l, *n;
-
-	list_for_each_safe(l, n, &host->cards) {
-		struct mmc_card *card = mmc_list_to_card(l);
-
-		mmc_remove_card(card);
-	}
-
-	mmc_power_off(host);
-	mmc_remove_host_sysfs(host);
-}
-
-EXPORT_SYMBOL(mmc_remove_host);
-
-/**
- *	mmc_free_host - free the host structure
- *	@host: mmc host
- *
- *	Free the host once all references to it have been dropped.
- */
-void mmc_free_host(struct mmc_host *host)
-{
-	mmc_flush_scheduled_work();
-	mmc_free_host_sysfs(host);
-}
-
-EXPORT_SYMBOL(mmc_free_host);
-
-#ifdef CONFIG_PM
-
-/**
- *	mmc_suspend_host - suspend a host
- *	@host: mmc host
- *	@state: suspend mode (PM_SUSPEND_xxx)
- */
-int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
-{
-	mmc_claim_host(host);
-	mmc_deselect_cards(host);
-	mmc_power_off(host);
-	mmc_release_host(host);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(mmc_suspend_host);
-
-/**
- *	mmc_resume_host - resume a previously suspended host
- *	@host: mmc host
- */
-int mmc_resume_host(struct mmc_host *host)
-{
-	mmc_rescan(&host->detect.work);
-
-	return 0;
-}
-
-EXPORT_SYMBOL(mmc_resume_host);
-
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
deleted file mode 100644
index 149affe..0000000
--- a/drivers/mmc/mmc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *  linux/drivers/mmc/mmc.h
- *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _MMC_H
-#define _MMC_H
-/* core-internal functions */
-void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
-int mmc_register_card(struct mmc_card *card);
-void mmc_remove_card(struct mmc_card *card);
-
-struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
-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 delayed_work *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
deleted file mode 100644
index 86439a0..0000000
--- a/drivers/mmc/mmc_block.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * Block driver for media (i.e., flash cards)
- *
- * Copyright 2002 Hewlett-Packard Company
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Many thanks to Alessandro Rubini and Jonathan Corbet!
- *
- * Author:  Andrew Christian
- *          28 May 2002
- */
-#include <linux/moduleparam.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#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>
-
-#include "mmc_queue.h"
-
-/*
- * max 8 partitions per card
- */
-#define MMC_SHIFT	3
-
-static int major;
-
-/*
- * There is one mmc_blk_data per slot.
- */
-struct mmc_blk_data {
-	spinlock_t	lock;
-	struct gendisk	*disk;
-	struct mmc_queue queue;
-
-	unsigned int	usage;
-	unsigned int	block_bits;
-	unsigned int	read_only;
-};
-
-static DEFINE_MUTEX(open_lock);
-
-static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
-{
-	struct mmc_blk_data *md;
-
-	mutex_lock(&open_lock);
-	md = disk->private_data;
-	if (md && md->usage == 0)
-		md = NULL;
-	if (md)
-		md->usage++;
-	mutex_unlock(&open_lock);
-
-	return md;
-}
-
-static void mmc_blk_put(struct mmc_blk_data *md)
-{
-	mutex_lock(&open_lock);
-	md->usage--;
-	if (md->usage == 0) {
-		put_disk(md->disk);
-		kfree(md);
-	}
-	mutex_unlock(&open_lock);
-}
-
-static int mmc_blk_open(struct inode *inode, struct file *filp)
-{
-	struct mmc_blk_data *md;
-	int ret = -ENXIO;
-
-	md = mmc_blk_get(inode->i_bdev->bd_disk);
-	if (md) {
-		if (md->usage == 2)
-			check_disk_change(inode->i_bdev);
-		ret = 0;
-
-		if ((filp->f_mode & FMODE_WRITE) && md->read_only)
-			ret = -EROFS;
-	}
-
-	return ret;
-}
-
-static int mmc_blk_release(struct inode *inode, struct file *filp)
-{
-	struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
-
-	mmc_blk_put(md);
-	return 0;
-}
-
-static int
-mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-	geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
-	geo->heads = 4;
-	geo->sectors = 16;
-	return 0;
-}
-
-static struct block_device_operations mmc_bdops = {
-	.open			= mmc_blk_open,
-	.release		= mmc_blk_release,
-	.getgeo			= mmc_blk_getgeo,
-	.owner			= THIS_MODULE,
-};
-
-struct mmc_blk_request {
-	struct mmc_request	mrq;
-	struct mmc_command	cmd;
-	struct mmc_command	stop;
-	struct mmc_data		data;
-};
-
-static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
-{
-	struct mmc_blk_data *md = mq->data;
-	int stat = BLKPREP_OK;
-
-	/*
-	 * If we have no device, we haven't finished initialising.
-	 */
-	if (!md || !mq->card) {
-		printk(KERN_ERR "%s: killing request - no device/host\n",
-		       req->rq_disk->disk_name);
-		stat = BLKPREP_KILL;
-	}
-
-	return stat;
-}
-
-static 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 = 1;
-
-	if (mmc_card_claim_host(card))
-		goto flush_queue;
-
-	do {
-		struct mmc_command cmd;
-		u32 readcmd, writecmd;
-
-		memset(&brq, 0, sizeof(struct mmc_blk_request));
-		brq.mrq.cmd = &brq.cmd;
-		brq.mrq.data = &brq.data;
-
-		brq.cmd.arg = req->sector;
-		if (!mmc_card_blockaddr(card))
-			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-		brq.data.blksz = 1 << md->block_bits;
-		brq.stop.opcode = MMC_STOP_TRANSMISSION;
-		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
-		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
-		if (brq.data.blocks > card->host->max_blk_count)
-			brq.data.blocks = card->host->max_blk_count;
-
-		mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
-
-		/*
-		 * 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;
-		brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
-
-		mmc_wait_for_req(card->host, &brq.mrq);
-		if (brq.cmd.error) {
-			printk(KERN_ERR "%s: error %d sending read/write command\n",
-			       req->rq_disk->disk_name, brq.cmd.error);
-			goto cmd_err;
-		}
-
-		if (brq.data.error) {
-			printk(KERN_ERR "%s: error %d transferring data\n",
-			       req->rq_disk->disk_name, brq.data.error);
-			goto cmd_err;
-		}
-
-		if (brq.stop.error) {
-			printk(KERN_ERR "%s: error %d sending stop command\n",
-			       req->rq_disk->disk_name, brq.stop.error);
-			goto cmd_err;
-		}
-
-		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;
-#endif
-		}
-
-		/*
-		 * A block was successfully transferred.
-		 */
-		spin_lock_irq(&md->lock);
-		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
-		if (!ret) {
-			/*
-			 * The whole request completed successfully.
-			 */
-			add_disk_randomness(req->rq_disk);
-			blkdev_dequeue_request(req);
-			end_that_request_last(req, 1);
-		}
-		spin_unlock_irq(&md->lock);
-	} while (ret);
-
-	mmc_card_release_host(card);
-
-	return 1;
-
- cmd_err:
- 	/*
- 	 * 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);
-	}
-
-flush_queue:
-
-	mmc_card_release_host(card);
-
-	spin_lock_irq(&md->lock);
-	while (ret) {
-		ret = end_that_request_chunk(req, 0,
-				req->current_nr_sectors << 9);
-	}
-
-	add_disk_randomness(req->rq_disk);
-	blkdev_dequeue_request(req);
-	end_that_request_last(req, 0);
-	spin_unlock_irq(&md->lock);
-
-	return 0;
-}
-
-#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)
-
-static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
-
-static inline int mmc_blk_readonly(struct mmc_card *card)
-{
-	return mmc_card_readonly(card) ||
-	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
-}
-
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
-{
-	struct mmc_blk_data *md;
-	int devidx, ret;
-
-	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-	if (devidx >= MMC_NUM_MINORS)
-		return ERR_PTR(-ENOSPC);
-	__set_bit(devidx, dev_use);
-
-	md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
-	if (!md) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	memset(md, 0, sizeof(struct mmc_blk_data));
-
-	/*
-	 * Set the read-only status based on the supported commands
-	 * and the write protect switch.
-	 */
-	md->read_only = mmc_blk_readonly(card);
-
-	/*
-	 * Both SD and MMC specifications state (although a bit
-	 * unclearly in the MMC case) that a block size of 512
-	 * bytes must always be supported by the card.
-	 */
-	md->block_bits = 9;
-
-	md->disk = alloc_disk(1 << MMC_SHIFT);
-	if (md->disk == NULL) {
-		ret = -ENOMEM;
-		goto err_kfree;
-	}
-
-	spin_lock_init(&md->lock);
-	md->usage = 1;
-
-	ret = mmc_init_queue(&md->queue, card, &md->lock);
-	if (ret)
-		goto err_putdisk;
-
-	md->queue.prep_fn = mmc_blk_prep_rq;
-	md->queue.issue_fn = mmc_blk_issue_rq;
-	md->queue.data = md;
-
-	md->disk->major	= major;
-	md->disk->first_minor = devidx << MMC_SHIFT;
-	md->disk->fops = &mmc_bdops;
-	md->disk->private_data = md;
-	md->disk->queue = md->queue.queue;
-	md->disk->driverfs_dev = &card->dev;
-
-	/*
-	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
-	 *
-	 * - be set for removable media with permanent block devices
-	 * - be unset for removable block devices with permanent media
-	 *
-	 * Since MMC block devices clearly fall under the second
-	 * case, we do not set GENHD_FL_REMOVABLE.  Userspace
-	 * should use the block device creation/destruction hotplug
-	 * messages to tell when the card is present.
-	 */
-
-	sprintf(md->disk->disk_name, "mmcblk%d", devidx);
-
-	blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
-
-	/*
-	 * The CSD capacity field is in units of read_blkbits.
-	 * set_capacity takes units of 512 bytes.
-	 */
-	set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
-	return md;
-
- err_putdisk:
-	put_disk(md->disk);
- err_kfree:
-	kfree(md);
- out:
-	return ERR_PTR(ret);
-}
-
-static int
-mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
-{
-	struct mmc_command cmd;
-	int err;
-
-	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-	if (mmc_card_blockaddr(card))
-		return 0;
-
-	mmc_card_claim_host(card);
-	cmd.opcode = MMC_SET_BLOCKLEN;
-	cmd.arg = 1 << md->block_bits;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-	err = mmc_wait_for_cmd(card->host, &cmd, 5);
-	mmc_card_release_host(card);
-
-	if (err) {
-		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-			md->disk->disk_name, cmd.arg, err);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int mmc_blk_probe(struct mmc_card *card)
-{
-	struct mmc_blk_data *md;
-	int err;
-
-	/*
-	 * Check that the card supports the command class(es) we need.
-	 */
-	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
-		return -ENODEV;
-
-	md = mmc_blk_alloc(card);
-	if (IS_ERR(md))
-		return PTR_ERR(md);
-
-	err = mmc_blk_set_blksize(md, card);
-	if (err)
-		goto out;
-
-	printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
-		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		(unsigned long long)(get_capacity(md->disk) >> 1),
-		md->read_only ? "(ro)" : "");
-
-	mmc_set_drvdata(card, md);
-	add_disk(md->disk);
-	return 0;
-
- out:
-	mmc_blk_put(md);
-
-	return err;
-}
-
-static void mmc_blk_remove(struct mmc_card *card)
-{
-	struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-	if (md) {
-		int devidx;
-
-		/* Stop new requests from getting into the queue */
-		del_gendisk(md->disk);
-
-		/* Then flush out any already in there */
-		mmc_cleanup_queue(&md->queue);
-
-		devidx = md->disk->first_minor >> MMC_SHIFT;
-		__clear_bit(devidx, dev_use);
-
-		mmc_blk_put(md);
-	}
-	mmc_set_drvdata(card, NULL);
-}
-
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
-{
-	struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-	if (md) {
-		mmc_queue_suspend(&md->queue);
-	}
-	return 0;
-}
-
-static int mmc_blk_resume(struct mmc_card *card)
-{
-	struct mmc_blk_data *md = mmc_get_drvdata(card);
-
-	if (md) {
-		mmc_blk_set_blksize(md, card);
-		mmc_queue_resume(&md->queue);
-	}
-	return 0;
-}
-#else
-#define	mmc_blk_suspend	NULL
-#define mmc_blk_resume	NULL
-#endif
-
-static struct mmc_driver mmc_driver = {
-	.drv		= {
-		.name	= "mmcblk",
-	},
-	.probe		= mmc_blk_probe,
-	.remove		= mmc_blk_remove,
-	.suspend	= mmc_blk_suspend,
-	.resume		= mmc_blk_resume,
-};
-
-static int __init mmc_blk_init(void)
-{
-	int res = -ENOMEM;
-
-	res = register_blkdev(major, "mmc");
-	if (res < 0) {
-		printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
-		       major, res);
-		goto out;
-	}
-	if (major == 0)
-		major = res;
-
-	return mmc_register_driver(&mmc_driver);
-
- out:
-	return res;
-}
-
-static void __exit mmc_blk_exit(void)
-{
-	mmc_unregister_driver(&mmc_driver);
-	unregister_blkdev(major, "mmc");
-}
-
-module_init(mmc_blk_init);
-module_exit(mmc_blk_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
-module_param(major, int, 0444);
-MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
deleted file mode 100644
index c27e426..0000000
--- a/drivers/mmc/mmc_queue.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- *  linux/drivers/mmc/mmc_queue.c
- *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/kthread.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include "mmc_queue.h"
-
-#define MMC_QUEUE_SUSPENDED	(1 << 0)
-
-/*
- * Prepare a MMC request.  Essentially, this means passing the
- * preparation off to the media driver.  The media driver will
- * create a mmc_io_request in req->special.
- */
-static int mmc_prep_request(struct request_queue *q, struct request *req)
-{
-	struct mmc_queue *mq = q->queuedata;
-	int ret = BLKPREP_KILL;
-
-	if (blk_special_request(req)) {
-		/*
-		 * Special commands already have the command
-		 * blocks already setup in req->special.
-		 */
-		BUG_ON(!req->special);
-
-		ret = BLKPREP_OK;
-	} else if (blk_fs_request(req) || blk_pc_request(req)) {
-		/*
-		 * Block I/O requests need translating according
-		 * to the protocol.
-		 */
-		ret = mq->prep_fn(mq, req);
-	} else {
-		/*
-		 * Everything else is invalid.
-		 */
-		blk_dump_rq_flags(req, "MMC bad request");
-	}
-
-	if (ret == BLKPREP_OK)
-		req->cmd_flags |= REQ_DONTPREP;
-
-	return ret;
-}
-
-static int mmc_queue_thread(void *d)
-{
-	struct mmc_queue *mq = d;
-	struct request_queue *q = mq->queue;
-
-	/*
-	 * Set iothread to ensure that we aren't put to sleep by
-	 * the process freezing.  We handle suspension ourselves.
-	 */
-	current->flags |= PF_MEMALLOC|PF_NOFREEZE;
-
-	down(&mq->thread_sem);
-	do {
-		struct request *req = NULL;
-
-		spin_lock_irq(q->queue_lock);
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (!blk_queue_plugged(q))
-			req = elv_next_request(q);
-		mq->req = req;
-		spin_unlock_irq(q->queue_lock);
-
-		if (!req) {
-			if (kthread_should_stop()) {
-				set_current_state(TASK_RUNNING);
-				break;
-			}
-			up(&mq->thread_sem);
-			schedule();
-			down(&mq->thread_sem);
-			continue;
-		}
-		set_current_state(TASK_RUNNING);
-
-		mq->issue_fn(mq, req);
-	} while (1);
-	up(&mq->thread_sem);
-
-	return 0;
-}
-
-/*
- * Generic MMC request handler.  This is called for any queue on a
- * particular host.  When the host is not busy, we look for a request
- * on any queue on this host, and attempt to issue it.  This may
- * not be the queue we were asked to process.
- */
-static void mmc_request(request_queue_t *q)
-{
-	struct mmc_queue *mq = q->queuedata;
-	struct request *req;
-	int ret;
-
-	if (!mq) {
-		printk(KERN_ERR "MMC: killing requests for dead queue\n");
-		while ((req = elv_next_request(q)) != NULL) {
-			do {
-				ret = end_that_request_chunk(req, 0,
-					req->current_nr_sectors << 9);
-			} while (ret);
-		}
-		return;
-	}
-
-	if (!mq->req)
-		wake_up_process(mq->thread);
-}
-
-/**
- * mmc_init_queue - initialise a queue structure.
- * @mq: mmc queue
- * @card: mmc card to attach this queue
- * @lock: queue lock
- *
- * Initialise a MMC card request queue.
- */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
-{
-	struct mmc_host *host = card->host;
-	u64 limit = BLK_BOUNCE_HIGH;
-	int ret;
-
-	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
-		limit = *mmc_dev(host)->dma_mask;
-
-	mq->card = card;
-	mq->queue = blk_init_queue(mmc_request, lock);
-	if (!mq->queue)
-		return -ENOMEM;
-
-	blk_queue_prep_rq(mq->queue, mmc_prep_request);
-	blk_queue_bounce_limit(mq->queue, limit);
-	blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
-	blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
-	blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
-	blk_queue_max_segment_size(mq->queue, host->max_seg_size);
-
-	mq->queue->queuedata = mq;
-	mq->req = NULL;
-
-	mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
-			 GFP_KERNEL);
-	if (!mq->sg) {
-		ret = -ENOMEM;
-		goto cleanup_queue;
-	}
-
-	init_MUTEX(&mq->thread_sem);
-
-	mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
-	if (IS_ERR(mq->thread)) {
-		ret = PTR_ERR(mq->thread);
-		goto free_sg;
-	}
-
-	return 0;
-
- free_sg:
-	kfree(mq->sg);
-	mq->sg = NULL;
- cleanup_queue:
-	blk_cleanup_queue(mq->queue);
-	return ret;
-}
-EXPORT_SYMBOL(mmc_init_queue);
-
-void mmc_cleanup_queue(struct mmc_queue *mq)
-{
-	request_queue_t *q = mq->queue;
-	unsigned long flags;
-
-	/* Mark that we should start throwing out stragglers */
-	spin_lock_irqsave(q->queue_lock, flags);
-	q->queuedata = NULL;
-	spin_unlock_irqrestore(q->queue_lock, flags);
-
-	/* Then terminate our worker thread */
-	kthread_stop(mq->thread);
-
-	kfree(mq->sg);
-	mq->sg = NULL;
-
-	blk_cleanup_queue(mq->queue);
-
-	mq->card = NULL;
-}
-EXPORT_SYMBOL(mmc_cleanup_queue);
-
-/**
- * mmc_queue_suspend - suspend a MMC request queue
- * @mq: MMC queue to suspend
- *
- * Stop the block request queue, and wait for our thread to
- * complete any outstanding requests.  This ensures that we
- * won't suspend while a request is being processed.
- */
-void mmc_queue_suspend(struct mmc_queue *mq)
-{
-	request_queue_t *q = mq->queue;
-	unsigned long flags;
-
-	if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
-		mq->flags |= MMC_QUEUE_SUSPENDED;
-
-		spin_lock_irqsave(q->queue_lock, flags);
-		blk_stop_queue(q);
-		spin_unlock_irqrestore(q->queue_lock, flags);
-
-		down(&mq->thread_sem);
-	}
-}
-EXPORT_SYMBOL(mmc_queue_suspend);
-
-/**
- * mmc_queue_resume - resume a previously suspended MMC request queue
- * @mq: MMC queue to resume
- */
-void mmc_queue_resume(struct mmc_queue *mq)
-{
-	request_queue_t *q = mq->queue;
-	unsigned long flags;
-
-	if (mq->flags & MMC_QUEUE_SUSPENDED) {
-		mq->flags &= ~MMC_QUEUE_SUSPENDED;
-
-		up(&mq->thread_sem);
-
-		spin_lock_irqsave(q->queue_lock, flags);
-		blk_start_queue(q);
-		spin_unlock_irqrestore(q->queue_lock, flags);
-	}
-}
-EXPORT_SYMBOL(mmc_queue_resume);
diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/mmc_queue.h
deleted file mode 100644
index c9f139e..0000000
--- a/drivers/mmc/mmc_queue.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef MMC_QUEUE_H
-#define MMC_QUEUE_H
-
-struct request;
-struct task_struct;
-
-struct mmc_queue {
-	struct mmc_card		*card;
-	struct task_struct	*thread;
-	struct semaphore	thread_sem;
-	unsigned int		flags;
-	struct request		*req;
-	int			(*prep_fn)(struct mmc_queue *, struct request *);
-	int			(*issue_fn)(struct mmc_queue *, struct request *);
-	void			*data;
-	struct request_queue	*queue;
-	struct scatterlist	*sg;
-};
-
-struct mmc_io_request {
-	struct request		*rq;
-	int			num;
-	struct mmc_command	selcmd;		/* mmc_queue private */
-	struct mmc_command	cmd[4];		/* max 4 commands */
-};
-
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
-extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
-extern void mmc_queue_resume(struct mmc_queue *);
-
-#endif
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
deleted file mode 100644
index d32698b..0000000
--- a/drivers/mmc/mmc_sysfs.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- *  linux/drivers/mmc/mmc_sysfs.c
- *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  MMC sysfs/driver model support.
- */
-#include <linux/module.h>
-#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>
-
-#include "mmc.h"
-
-#define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
-#define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
-#define cls_dev_to_mmc_host(d)	container_of(d, struct mmc_host, class_dev)
-
-#define MMC_ATTR(name, fmt, args...)					\
-static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	struct mmc_card *card = dev_to_mmc_card(dev);			\
-	return sprintf(buf, fmt, args);					\
-}
-
-MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
-	card->raw_cid[2], card->raw_cid[3]);
-MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
-	card->raw_csd[2], card->raw_csd[3]);
-MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
-MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
-MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
-MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
-MMC_ATTR(name, "%s\n", card->cid.prod_name);
-MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
-MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
-
-#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
-
-static struct device_attribute mmc_dev_attrs[] = {
-	MMC_ATTR_RO(cid),
-	MMC_ATTR_RO(csd),
-	MMC_ATTR_RO(date),
-	MMC_ATTR_RO(fwrev),
-	MMC_ATTR_RO(hwrev),
-	MMC_ATTR_RO(manfid),
-	MMC_ATTR_RO(name),
-	MMC_ATTR_RO(oemid),
-	MMC_ATTR_RO(serial),
-	__ATTR_NULL
-};
-
-static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
-
-
-static void mmc_release_card(struct device *dev)
-{
-	struct mmc_card *card = dev_to_mmc_card(dev);
-
-	kfree(card);
-}
-
-/*
- * This currently matches any MMC driver to any MMC card - drivers
- * themselves make the decision whether to drive this card in their
- * probe method.  However, we force "bad" cards to fail.
- */
-static int mmc_bus_match(struct device *dev, struct device_driver *drv)
-{
-	struct mmc_card *card = dev_to_mmc_card(dev);
-	return !mmc_card_bad(card);
-}
-
-static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-		int buf_size)
-{
-	struct mmc_card *card = dev_to_mmc_card(dev);
-	char ccc[13];
-	int i = 0;
-
-#define add_env(fmt,val)						\
-	({								\
-		int len, ret = -ENOMEM;					\
-		if (i < num_envp) {					\
-			envp[i++] = buf;				\
-			len = snprintf(buf, buf_size, fmt, val) + 1;	\
-			buf_size -= len;				\
-			buf += len;					\
-			if (buf_size >= 0)				\
-				ret = 0;				\
-		}							\
-		ret;							\
-	})
-
-	for (i = 0; i < 12; i++)
-		ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
-	ccc[12] = '\0';
-
-	i = 0;
-	add_env("MMC_CCC=%s", ccc);
-	add_env("MMC_MANFID=%06x", card->cid.manfid);
-	add_env("MMC_NAME=%s", mmc_card_name(card));
-	add_env("MMC_OEMID=%04x", card->cid.oemid);
-
-	return 0;
-}
-
-static int mmc_bus_suspend(struct device *dev, pm_message_t state)
-{
-	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
-	int ret = 0;
-
-	if (dev->driver && drv->suspend)
-		ret = drv->suspend(card, state);
-	return ret;
-}
-
-static int mmc_bus_resume(struct device *dev)
-{
-	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
-	int ret = 0;
-
-	if (dev->driver && drv->resume)
-		ret = drv->resume(card);
-	return ret;
-}
-
-static int mmc_bus_probe(struct device *dev)
-{
-	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
-
-	return drv->probe(card);
-}
-
-static int mmc_bus_remove(struct device *dev)
-{
-	struct mmc_driver *drv = to_mmc_driver(dev->driver);
-	struct mmc_card *card = dev_to_mmc_card(dev);
-
-	drv->remove(card);
-
-	return 0;
-}
-
-static struct bus_type mmc_bus_type = {
-	.name		= "mmc",
-	.dev_attrs	= mmc_dev_attrs,
-	.match		= mmc_bus_match,
-	.uevent		= mmc_bus_uevent,
-	.probe		= mmc_bus_probe,
-	.remove		= mmc_bus_remove,
-	.suspend	= mmc_bus_suspend,
-	.resume		= mmc_bus_resume,
-};
-
-/**
- *	mmc_register_driver - register a media driver
- *	@drv: MMC media driver
- */
-int mmc_register_driver(struct mmc_driver *drv)
-{
-	drv->drv.bus = &mmc_bus_type;
-	return driver_register(&drv->drv);
-}
-
-EXPORT_SYMBOL(mmc_register_driver);
-
-/**
- *	mmc_unregister_driver - unregister a media driver
- *	@drv: MMC media driver
- */
-void mmc_unregister_driver(struct mmc_driver *drv)
-{
-	drv->drv.bus = &mmc_bus_type;
-	driver_unregister(&drv->drv);
-}
-
-EXPORT_SYMBOL(mmc_unregister_driver);
-
-
-/*
- * Internal function.  Initialise a MMC card structure.
- */
-void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
-{
-	memset(card, 0, sizeof(struct mmc_card));
-	card->host = host;
-	device_initialize(&card->dev);
-	card->dev.parent = mmc_classdev(host);
-	card->dev.bus = &mmc_bus_type;
-	card->dev.release = mmc_release_card;
-}
-
-/*
- * Internal function.  Register a new MMC card with the driver model.
- */
-int mmc_register_card(struct mmc_card *card)
-{
-	int ret;
-
-	snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
-		 "%s:%04x", mmc_hostname(card->host), card->rca);
-
-	ret = device_add(&card->dev);
-	if (ret == 0) {
-		if (mmc_card_sd(card)) {
-			ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
-			if (ret)
-				device_del(&card->dev);
-		}
-	}
-	return ret;
-}
-
-/*
- * Internal function.  Unregister a new MMC card with the
- * driver model, and (eventually) free it.
- */
-void mmc_remove_card(struct mmc_card *card)
-{
-	if (mmc_card_present(card)) {
-		if (mmc_card_sd(card))
-			device_remove_file(&card->dev, &mmc_dev_attr_scr);
-
-		device_del(&card->dev);
-	}
-
-	put_device(&card->dev);
-}
-
-
-static void mmc_host_classdev_release(struct device *dev)
-{
-	struct mmc_host *host = cls_dev_to_mmc_host(dev);
-	kfree(host);
-}
-
-static struct class mmc_host_class = {
-	.name		= "mmc_host",
-	.dev_release	= mmc_host_classdev_release,
-};
-
-static DEFINE_IDR(mmc_host_idr);
-static DEFINE_SPINLOCK(mmc_host_lock);
-
-/*
- * Internal function. Allocate a new MMC host.
- */
-struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
-{
-	struct mmc_host *host;
-
-	host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
-	if (host) {
-		memset(host, 0, sizeof(struct mmc_host) + extra);
-
-		host->parent = dev;
-		host->class_dev.parent = dev;
-		host->class_dev.class = &mmc_host_class;
-		device_initialize(&host->class_dev);
-	}
-
-	return host;
-}
-
-/*
- * Internal function. Register a new MMC host with the MMC class.
- */
-int mmc_add_host_sysfs(struct mmc_host *host)
-{
-	int err;
-
-	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
-		return -ENOMEM;
-
-	spin_lock(&mmc_host_lock);
-	err = idr_get_new(&mmc_host_idr, host, &host->index);
-	spin_unlock(&mmc_host_lock);
-	if (err)
-		return err;
-
-	snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
-		 "mmc%d", host->index);
-
-	return device_add(&host->class_dev);
-}
-
-/*
- * Internal function. Unregister a MMC host with the MMC class.
- */
-void mmc_remove_host_sysfs(struct mmc_host *host)
-{
-	device_del(&host->class_dev);
-
-	spin_lock(&mmc_host_lock);
-	idr_remove(&mmc_host_idr, host->index);
-	spin_unlock(&mmc_host_lock);
-}
-
-/*
- * Internal function. Free a MMC host.
- */
-void mmc_free_host_sysfs(struct mmc_host *host)
-{
-	put_device(&host->class_dev);
-}
-
-static struct workqueue_struct *workqueue;
-
-/*
- * Internal function. Schedule delayed work in the MMC work queue.
- */
-int mmc_schedule_delayed_work(struct delayed_work *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;
-
-	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)
-			bus_unregister(&mmc_bus_type);
-	}
-	return ret;
-}
-
-static void __exit mmc_exit(void)
-{
-	class_unregister(&mmc_host_class);
-	bus_unregister(&mmc_bus_type);
-	destroy_workqueue(workqueue);
-}
-
-module_init(mmc_init);
-module_exit(mmc_exit);
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
deleted file mode 100644
index 5941dd9..0000000
--- a/drivers/mmc/mmci.c
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- *  linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
- *
- *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/highmem.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-#include <linux/amba/bus.h>
-#include <linux/clk.h>
-
-#include <asm/cacheflush.h>
-#include <asm/div64.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-#include <asm/mach/mmc.h>
-
-#include "mmci.h"
-
-#define DRIVER_NAME "mmci-pl18x"
-
-#define DBG(host,fmt,args...)	\
-	pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-
-static unsigned int fmax = 515633;
-
-static void
-mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
-{
-	writel(0, host->base + MMCICOMMAND);
-
-	BUG_ON(host->data);
-
-	host->mrq = NULL;
-	host->cmd = NULL;
-
-	if (mrq->data)
-		mrq->data->bytes_xfered = host->data_xfered;
-
-	/*
-	 * Need to drop the host lock here; mmc_request_done may call
-	 * back into the driver...
-	 */
-	spin_unlock(&host->lock);
-	mmc_request_done(host->mmc, mrq);
-	spin_lock(&host->lock);
-}
-
-static void mmci_stop_data(struct mmci_host *host)
-{
-	writel(0, host->base + MMCIDATACTRL);
-	writel(0, host->base + MMCIMASK1);
-	host->data = NULL;
-}
-
-static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
-{
-	unsigned int datactrl, timeout, irqmask;
-	unsigned long long clks;
-	void __iomem *base;
-	int blksz_bits;
-
-	DBG(host, "blksz %04x blks %04x flags %08x\n",
-	    data->blksz, data->blocks, data->flags);
-
-	host->data = data;
-	host->size = data->blksz;
-	host->data_xfered = 0;
-
-	mmci_init_sg(host, data);
-
-	clks = (unsigned long long)data->timeout_ns * host->cclk;
-	do_div(clks, 1000000000UL);
-
-	timeout = data->timeout_clks + (unsigned int)clks;
-
-	base = host->base;
-	writel(timeout, base + MMCIDATATIMER);
-	writel(host->size, base + MMCIDATALENGTH);
-
-	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;
-
-		/*
-		 * If we have less than a FIFOSIZE of bytes to transfer,
-		 * trigger a PIO interrupt as soon as any data is available.
-		 */
-		if (host->size < MCI_FIFOSIZE)
-			irqmask |= MCI_RXDATAAVLBLMASK;
-	} else {
-		/*
-		 * We don't actually need to include "FIFO empty" here
-		 * since its implicit in "FIFO half empty".
-		 */
-		irqmask = MCI_TXFIFOHALFEMPTYMASK;
-	}
-
-	writel(datactrl, base + MMCIDATACTRL);
-	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
-	writel(irqmask, base + MMCIMASK1);
-}
-
-static void
-mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-{
-	void __iomem *base = host->base;
-
-	DBG(host, "op %02x arg %08x flags %08x\n",
-	    cmd->opcode, cmd->arg, cmd->flags);
-
-	if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
-		writel(0, base + MMCICOMMAND);
-		udelay(1);
-	}
-
-	c |= cmd->opcode | MCI_CPSM_ENABLE;
-	if (cmd->flags & MMC_RSP_PRESENT) {
-		if (cmd->flags & MMC_RSP_136)
-			c |= MCI_CPSM_LONGRSP;
-		c |= MCI_CPSM_RESPONSE;
-	}
-	if (/*interrupt*/0)
-		c |= MCI_CPSM_INTERRUPT;
-
-	host->cmd = cmd;
-
-	writel(cmd->arg, base + MMCIARGUMENT);
-	writel(c, base + MMCICOMMAND);
-}
-
-static void
-mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
-	      unsigned int status)
-{
-	if (status & MCI_DATABLOCKEND) {
-		host->data_xfered += data->blksz;
-	}
-	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
-		if (status & MCI_DATACRCFAIL)
-			data->error = MMC_ERR_BADCRC;
-		else if (status & MCI_DATATIMEOUT)
-			data->error = MMC_ERR_TIMEOUT;
-		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
-			data->error = MMC_ERR_FIFO;
-		status |= MCI_DATAEND;
-
-		/*
-		 * We hit an error condition.  Ensure that any data
-		 * partially written to a page is properly coherent.
-		 */
-		if (host->sg_len && data->flags & MMC_DATA_READ)
-			flush_dcache_page(host->sg_ptr->page);
-	}
-	if (status & MCI_DATAEND) {
-		mmci_stop_data(host);
-
-		if (!data->stop) {
-			mmci_request_end(host, data->mrq);
-		} else {
-			mmci_start_command(host, data->stop, 0);
-		}
-	}
-}
-
-static void
-mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
-	     unsigned int status)
-{
-	void __iomem *base = host->base;
-
-	host->cmd = NULL;
-
-	cmd->resp[0] = readl(base + MMCIRESPONSE0);
-	cmd->resp[1] = readl(base + MMCIRESPONSE1);
-	cmd->resp[2] = readl(base + MMCIRESPONSE2);
-	cmd->resp[3] = readl(base + MMCIRESPONSE3);
-
-	if (status & MCI_CMDTIMEOUT) {
-		cmd->error = MMC_ERR_TIMEOUT;
-	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
-		cmd->error = MMC_ERR_BADCRC;
-	}
-
-	if (!cmd->data || cmd->error != MMC_ERR_NONE) {
-		if (host->data)
-			mmci_stop_data(host);
-		mmci_request_end(host, cmd->mrq);
-	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
-		mmci_start_data(host, cmd->data);
-	}
-}
-
-static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
-{
-	void __iomem *base = host->base;
-	char *ptr = buffer;
-	u32 status;
-
-	do {
-		int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
-
-		if (count > remain)
-			count = remain;
-
-		if (count <= 0)
-			break;
-
-		readsl(base + MMCIFIFO, ptr, count >> 2);
-
-		ptr += count;
-		remain -= count;
-
-		if (remain == 0)
-			break;
-
-		status = readl(base + MMCISTATUS);
-	} while (status & MCI_RXDATAAVLBL);
-
-	return ptr - buffer;
-}
-
-static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
-{
-	void __iomem *base = host->base;
-	char *ptr = buffer;
-
-	do {
-		unsigned int count, maxcnt;
-
-		maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
-		count = min(remain, maxcnt);
-
-		writesl(base + MMCIFIFO, ptr, count >> 2);
-
-		ptr += count;
-		remain -= count;
-
-		if (remain == 0)
-			break;
-
-		status = readl(base + MMCISTATUS);
-	} while (status & MCI_TXFIFOHALFEMPTY);
-
-	return ptr - buffer;
-}
-
-/*
- * PIO data transfer IRQ handler.
- */
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
-{
-	struct mmci_host *host = dev_id;
-	void __iomem *base = host->base;
-	u32 status;
-
-	status = readl(base + MMCISTATUS);
-
-	DBG(host, "irq1 %08x\n", status);
-
-	do {
-		unsigned long flags;
-		unsigned int remain, len;
-		char *buffer;
-
-		/*
-		 * For write, we only need to test the half-empty flag
-		 * here - if the FIFO is completely empty, then by
-		 * definition it is more than half empty.
-		 *
-		 * For read, check for data available.
-		 */
-		if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
-			break;
-
-		/*
-		 * Map the current scatter buffer.
-		 */
-		buffer = mmci_kmap_atomic(host, &flags) + host->sg_off;
-		remain = host->sg_ptr->length - host->sg_off;
-
-		len = 0;
-		if (status & MCI_RXACTIVE)
-			len = mmci_pio_read(host, buffer, remain);
-		if (status & MCI_TXACTIVE)
-			len = mmci_pio_write(host, buffer, remain, status);
-
-		/*
-		 * Unmap the buffer.
-		 */
-		mmci_kunmap_atomic(host, buffer, &flags);
-
-		host->sg_off += len;
-		host->size -= len;
-		remain -= len;
-
-		if (remain)
-			break;
-
-		/*
-		 * If we were reading, and we have completed this
-		 * page, ensure that the data cache is coherent.
-		 */
-		if (status & MCI_RXACTIVE)
-			flush_dcache_page(host->sg_ptr->page);
-
-		if (!mmci_next_sg(host))
-			break;
-
-		status = readl(base + MMCISTATUS);
-	} while (1);
-
-	/*
-	 * If we're nearing the end of the read, switch to
-	 * "any data available" mode.
-	 */
-	if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
-		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
-
-	/*
-	 * If we run out of data, disable the data IRQs; this
-	 * prevents a race where the FIFO becomes empty before
-	 * the chip itself has disabled the data path, and
-	 * stops us racing with our data end IRQ.
-	 */
-	if (host->size == 0) {
-		writel(0, base + MMCIMASK1);
-		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * Handle completion of command and data transfers.
- */
-static irqreturn_t mmci_irq(int irq, void *dev_id)
-{
-	struct mmci_host *host = dev_id;
-	u32 status;
-	int ret = 0;
-
-	spin_lock(&host->lock);
-
-	do {
-		struct mmc_command *cmd;
-		struct mmc_data *data;
-
-		status = readl(host->base + MMCISTATUS);
-		status &= readl(host->base + MMCIMASK0);
-		writel(status, host->base + MMCICLEAR);
-
-		DBG(host, "irq0 %08x\n", status);
-
-		data = host->data;
-		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
-			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data)
-			mmci_data_irq(host, data, status);
-
-		cmd = host->cmd;
-		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-			mmci_cmd_irq(host, cmd, status);
-
-		ret = 1;
-	} while (status);
-
-	spin_unlock(&host->lock);
-
-	return IRQ_RETVAL(ret);
-}
-
-static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct mmci_host *host = mmc_priv(mmc);
-
-	WARN_ON(host->mrq != NULL);
-
-	spin_lock_irq(&host->lock);
-
-	host->mrq = mrq;
-
-	if (mrq->data && mrq->data->flags & MMC_DATA_READ)
-		mmci_start_data(host, mrq->data);
-
-	mmci_start_command(host, mrq->cmd, 0);
-
-	spin_unlock_irq(&host->lock);
-}
-
-static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct mmci_host *host = mmc_priv(mmc);
-	u32 clk = 0, pwr = 0;
-
-	if (ios->clock) {
-		if (ios->clock >= host->mclk) {
-			clk = MCI_CLK_BYPASS;
-			host->cclk = host->mclk;
-		} else {
-			clk = host->mclk / (2 * ios->clock) - 1;
-			if (clk > 256)
-				clk = 255;
-			host->cclk = host->mclk / (2 * (clk + 1));
-		}
-		clk |= MCI_CLK_ENABLE;
-	}
-
-	if (host->plat->translate_vdd)
-		pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
-
-	switch (ios->power_mode) {
-	case MMC_POWER_OFF:
-		break;
-	case MMC_POWER_UP:
-		pwr |= MCI_PWR_UP;
-		break;
-	case MMC_POWER_ON:
-		pwr |= MCI_PWR_ON;
-		break;
-	}
-
-	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-		pwr |= MCI_ROD;
-
-	writel(clk, host->base + MMCICLOCK);
-
-	if (host->pwr != pwr) {
-		host->pwr = pwr;
-		writel(pwr, host->base + MMCIPOWER);
-	}
-}
-
-static const struct mmc_host_ops mmci_ops = {
-	.request	= mmci_request,
-	.set_ios	= mmci_set_ios,
-};
-
-static void mmci_check_status(unsigned long data)
-{
-	struct mmci_host *host = (struct mmci_host *)data;
-	unsigned int status;
-
-	status = host->plat->status(mmc_dev(host->mmc));
-	if (status ^ host->oldstat)
-		mmc_detect_change(host->mmc, 0);
-
-	host->oldstat = status;
-	mod_timer(&host->timer, jiffies + HZ);
-}
-
-static int mmci_probe(struct amba_device *dev, void *id)
-{
-	struct mmc_platform_data *plat = dev->dev.platform_data;
-	struct mmci_host *host;
-	struct mmc_host *mmc;
-	int ret;
-
-	/* must have platform data */
-	if (!plat) {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	ret = amba_request_regions(dev, DRIVER_NAME);
-	if (ret)
-		goto out;
-
-	mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
-	if (!mmc) {
-		ret = -ENOMEM;
-		goto rel_regions;
-	}
-
-	host = mmc_priv(mmc);
-	host->clk = clk_get(&dev->dev, "MCLK");
-	if (IS_ERR(host->clk)) {
-		ret = PTR_ERR(host->clk);
-		host->clk = NULL;
-		goto host_free;
-	}
-
-	ret = clk_enable(host->clk);
-	if (ret)
-		goto clk_free;
-
-	host->plat = plat;
-	host->mclk = clk_get_rate(host->clk);
-	host->mmc = mmc;
-	host->base = ioremap(dev->res.start, SZ_4K);
-	if (!host->base) {
-		ret = -ENOMEM;
-		goto clk_disable;
-	}
-
-	mmc->ops = &mmci_ops;
-	mmc->f_min = (host->mclk + 511) / 512;
-	mmc->f_max = min(host->mclk, fmax);
-	mmc->ocr_avail = plat->ocr_mask;
-	mmc->caps = MMC_CAP_MULTIWRITE;
-
-	/*
-	 * We can do SGIO
-	 */
-	mmc->max_hw_segs = 16;
-	mmc->max_phys_segs = NR_SG;
-
-	/*
-	 * Since we only have a 16-bit data length register, we must
-	 * ensure that we don't exceed 2^16-1 bytes in a single request.
-	 */
-	mmc->max_req_size = 65535;
-
-	/*
-	 * Set the maximum segment size.  Since we aren't doing DMA
-	 * (yet) we are only limited by the data length register.
-	 */
-	mmc->max_seg_size = mmc->max_req_size;
-
-	/*
-	 * Block size can be up to 2048 bytes, but must be a power of two.
-	 */
-	mmc->max_blk_size = 2048;
-
-	/*
-	 * No limit on the number of blocks transferred.
-	 */
-	mmc->max_blk_count = mmc->max_req_size;
-
-	spin_lock_init(&host->lock);
-
-	writel(0, host->base + MMCIMASK0);
-	writel(0, host->base + MMCIMASK1);
-	writel(0xfff, host->base + MMCICLEAR);
-
-	ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
-	if (ret)
-		goto unmap;
-
-	ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
-	if (ret)
-		goto irq0_free;
-
-	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-
-	amba_set_drvdata(dev, mmc);
-
-	mmc_add_host(mmc);
-
-	printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
-		mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
-		(unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
-
-	init_timer(&host->timer);
-	host->timer.data = (unsigned long)host;
-	host->timer.function = mmci_check_status;
-	host->timer.expires = jiffies + HZ;
-	add_timer(&host->timer);
-
-	return 0;
-
- irq0_free:
-	free_irq(dev->irq[0], host);
- unmap:
-	iounmap(host->base);
- clk_disable:
-	clk_disable(host->clk);
- clk_free:
-	clk_put(host->clk);
- host_free:
-	mmc_free_host(mmc);
- rel_regions:
-	amba_release_regions(dev);
- out:
-	return ret;
-}
-
-static int mmci_remove(struct amba_device *dev)
-{
-	struct mmc_host *mmc = amba_get_drvdata(dev);
-
-	amba_set_drvdata(dev, NULL);
-
-	if (mmc) {
-		struct mmci_host *host = mmc_priv(mmc);
-
-		del_timer_sync(&host->timer);
-
-		mmc_remove_host(mmc);
-
-		writel(0, host->base + MMCIMASK0);
-		writel(0, host->base + MMCIMASK1);
-
-		writel(0, host->base + MMCICOMMAND);
-		writel(0, host->base + MMCIDATACTRL);
-
-		free_irq(dev->irq[0], host);
-		free_irq(dev->irq[1], host);
-
-		iounmap(host->base);
-		clk_disable(host->clk);
-		clk_put(host->clk);
-
-		mmc_free_host(mmc);
-
-		amba_release_regions(dev);
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int mmci_suspend(struct amba_device *dev, pm_message_t state)
-{
-	struct mmc_host *mmc = amba_get_drvdata(dev);
-	int ret = 0;
-
-	if (mmc) {
-		struct mmci_host *host = mmc_priv(mmc);
-
-		ret = mmc_suspend_host(mmc, state);
-		if (ret == 0)
-			writel(0, host->base + MMCIMASK0);
-	}
-
-	return ret;
-}
-
-static int mmci_resume(struct amba_device *dev)
-{
-	struct mmc_host *mmc = amba_get_drvdata(dev);
-	int ret = 0;
-
-	if (mmc) {
-		struct mmci_host *host = mmc_priv(mmc);
-
-		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-
-		ret = mmc_resume_host(mmc);
-	}
-
-	return ret;
-}
-#else
-#define mmci_suspend	NULL
-#define mmci_resume	NULL
-#endif
-
-static struct amba_id mmci_ids[] = {
-	{
-		.id	= 0x00041180,
-		.mask	= 0x000fffff,
-	},
-	{
-		.id	= 0x00041181,
-		.mask	= 0x000fffff,
-	},
-	{ 0, 0 },
-};
-
-static struct amba_driver mmci_driver = {
-	.drv		= {
-		.name	= DRIVER_NAME,
-	},
-	.probe		= mmci_probe,
-	.remove		= mmci_remove,
-	.suspend	= mmci_suspend,
-	.resume		= mmci_resume,
-	.id_table	= mmci_ids,
-};
-
-static int __init mmci_init(void)
-{
-	return amba_driver_register(&mmci_driver);
-}
-
-static void __exit mmci_exit(void)
-{
-	amba_driver_unregister(&mmci_driver);
-}
-
-module_init(mmci_init);
-module_exit(mmci_exit);
-module_param(fmax, uint, 0444);
-
-MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h
deleted file mode 100644
index 6d7eadc..0000000
--- a/drivers/mmc/mmci.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
- *
- *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define MMCIPOWER		0x000
-#define MCI_PWR_OFF		0x00
-#define MCI_PWR_UP		0x02
-#define MCI_PWR_ON		0x03
-#define MCI_OD			(1 << 6)
-#define MCI_ROD			(1 << 7)
-
-#define MMCICLOCK		0x004
-#define MCI_CLK_ENABLE		(1 << 8)
-#define MCI_CLK_PWRSAVE		(1 << 9)
-#define MCI_CLK_BYPASS		(1 << 10)
-
-#define MMCIARGUMENT		0x008
-#define MMCICOMMAND		0x00c
-#define MCI_CPSM_RESPONSE	(1 << 6)
-#define MCI_CPSM_LONGRSP	(1 << 7)
-#define MCI_CPSM_INTERRUPT	(1 << 8)
-#define MCI_CPSM_PENDING	(1 << 9)
-#define MCI_CPSM_ENABLE		(1 << 10)
-
-#define MMCIRESPCMD		0x010
-#define MMCIRESPONSE0		0x014
-#define MMCIRESPONSE1		0x018
-#define MMCIRESPONSE2		0x01c
-#define MMCIRESPONSE3		0x020
-#define MMCIDATATIMER		0x024
-#define MMCIDATALENGTH		0x028
-#define MMCIDATACTRL		0x02c
-#define MCI_DPSM_ENABLE		(1 << 0)
-#define MCI_DPSM_DIRECTION	(1 << 1)
-#define MCI_DPSM_MODE		(1 << 2)
-#define MCI_DPSM_DMAENABLE	(1 << 3)
-
-#define MMCIDATACNT		0x030
-#define MMCISTATUS		0x034
-#define MCI_CMDCRCFAIL		(1 << 0)
-#define MCI_DATACRCFAIL		(1 << 1)
-#define MCI_CMDTIMEOUT		(1 << 2)
-#define MCI_DATATIMEOUT		(1 << 3)
-#define MCI_TXUNDERRUN		(1 << 4)
-#define MCI_RXOVERRUN		(1 << 5)
-#define MCI_CMDRESPEND		(1 << 6)
-#define MCI_CMDSENT		(1 << 7)
-#define MCI_DATAEND		(1 << 8)
-#define MCI_DATABLOCKEND	(1 << 10)
-#define MCI_CMDACTIVE		(1 << 11)
-#define MCI_TXACTIVE		(1 << 12)
-#define MCI_RXACTIVE		(1 << 13)
-#define MCI_TXFIFOHALFEMPTY	(1 << 14)
-#define MCI_RXFIFOHALFFULL	(1 << 15)
-#define MCI_TXFIFOFULL		(1 << 16)
-#define MCI_RXFIFOFULL		(1 << 17)
-#define MCI_TXFIFOEMPTY		(1 << 18)
-#define MCI_RXFIFOEMPTY		(1 << 19)
-#define MCI_TXDATAAVLBL		(1 << 20)
-#define MCI_RXDATAAVLBL		(1 << 21)
-
-#define MMCICLEAR		0x038
-#define MCI_CMDCRCFAILCLR	(1 << 0)
-#define MCI_DATACRCFAILCLR	(1 << 1)
-#define MCI_CMDTIMEOUTCLR	(1 << 2)
-#define MCI_DATATIMEOUTCLR	(1 << 3)
-#define MCI_TXUNDERRUNCLR	(1 << 4)
-#define MCI_RXOVERRUNCLR	(1 << 5)
-#define MCI_CMDRESPENDCLR	(1 << 6)
-#define MCI_CMDSENTCLR		(1 << 7)
-#define MCI_DATAENDCLR		(1 << 8)
-#define MCI_DATABLOCKENDCLR	(1 << 10)
-
-#define MMCIMASK0		0x03c
-#define MCI_CMDCRCFAILMASK	(1 << 0)
-#define MCI_DATACRCFAILMASK	(1 << 1)
-#define MCI_CMDTIMEOUTMASK	(1 << 2)
-#define MCI_DATATIMEOUTMASK	(1 << 3)
-#define MCI_TXUNDERRUNMASK	(1 << 4)
-#define MCI_RXOVERRUNMASK	(1 << 5)
-#define MCI_CMDRESPENDMASK	(1 << 6)
-#define MCI_CMDSENTMASK		(1 << 7)
-#define MCI_DATAENDMASK		(1 << 8)
-#define MCI_DATABLOCKENDMASK	(1 << 10)
-#define MCI_CMDACTIVEMASK	(1 << 11)
-#define MCI_TXACTIVEMASK	(1 << 12)
-#define MCI_RXACTIVEMASK	(1 << 13)
-#define MCI_TXFIFOHALFEMPTYMASK	(1 << 14)
-#define MCI_RXFIFOHALFFULLMASK	(1 << 15)
-#define MCI_TXFIFOFULLMASK	(1 << 16)
-#define MCI_RXFIFOFULLMASK	(1 << 17)
-#define MCI_TXFIFOEMPTYMASK	(1 << 18)
-#define MCI_RXFIFOEMPTYMASK	(1 << 19)
-#define MCI_TXDATAAVLBLMASK	(1 << 20)
-#define MCI_RXDATAAVLBLMASK	(1 << 21)
-
-#define MMCIMASK1		0x040
-#define MMCIFIFOCNT		0x048
-#define MMCIFIFO		0x080 /* to 0x0bc */
-
-#define MCI_IRQENABLE	\
-	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\
-	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
-	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
-
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE	(16*4)
-	
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-
-#define NR_SG		16
-
-struct clk;
-
-struct mmci_host {
-	void __iomem		*base;
-	struct mmc_request	*mrq;
-	struct mmc_command	*cmd;
-	struct mmc_data		*data;
-	struct mmc_host		*mmc;
-	struct clk		*clk;
-
-	unsigned int		data_xfered;
-
-	spinlock_t		lock;
-
-	unsigned int		mclk;
-	unsigned int		cclk;
-	u32			pwr;
-	struct mmc_platform_data *plat;
-
-	struct timer_list	timer;
-	unsigned int		oldstat;
-
-	unsigned int		sg_len;
-
-	/* pio stuff */
-	struct scatterlist	*sg_ptr;
-	unsigned int		sg_off;
-	unsigned int		size;
-};
-
-static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
-	/*
-	 * Ideally, we want the higher levels to pass us a scatter list.
-	 */
-	host->sg_len = data->sg_len;
-	host->sg_ptr = data->sg;
-	host->sg_off = 0;
-}
-
-static inline int mmci_next_sg(struct mmci_host *host)
-{
-	host->sg_ptr++;
-	host->sg_off = 0;
-	return --host->sg_len;
-}
-
-static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flags)
-{
-	struct scatterlist *sg = host->sg_ptr;
-
-	local_irq_save(*flags);
-	return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
-}
-
-static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
-{
-	kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
-	local_irq_restore(*flags);
-}
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
deleted file mode 100644
index 1e96a2f..0000000
--- a/drivers/mmc/omap.c
+++ /dev/null
@@ -1,1289 +0,0 @@
-/*
- *  linux/drivers/media/mmc/omap.c
- *
- *  Copyright (C) 2004 Nokia Corporation
- *  Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
- *  Misc hacks here and there by Tony Lindgren <tony@atomide.com>
- *  Other hacks (DMA, SD, etc) 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-#include <linux/mmc/card.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/scatterlist.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
-#include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/fpga.h>
-#include <asm/arch/tps65010.h>
-
-#define	OMAP_MMC_REG_CMD	0x00
-#define	OMAP_MMC_REG_ARGL	0x04
-#define	OMAP_MMC_REG_ARGH	0x08
-#define	OMAP_MMC_REG_CON	0x0c
-#define	OMAP_MMC_REG_STAT	0x10
-#define	OMAP_MMC_REG_IE		0x14
-#define	OMAP_MMC_REG_CTO	0x18
-#define	OMAP_MMC_REG_DTO	0x1c
-#define	OMAP_MMC_REG_DATA	0x20
-#define	OMAP_MMC_REG_BLEN	0x24
-#define	OMAP_MMC_REG_NBLK	0x28
-#define	OMAP_MMC_REG_BUF	0x2c
-#define OMAP_MMC_REG_SDIO	0x34
-#define	OMAP_MMC_REG_REV	0x3c
-#define	OMAP_MMC_REG_RSP0	0x40
-#define	OMAP_MMC_REG_RSP1	0x44
-#define	OMAP_MMC_REG_RSP2	0x48
-#define	OMAP_MMC_REG_RSP3	0x4c
-#define	OMAP_MMC_REG_RSP4	0x50
-#define	OMAP_MMC_REG_RSP5	0x54
-#define	OMAP_MMC_REG_RSP6	0x58
-#define	OMAP_MMC_REG_RSP7	0x5c
-#define	OMAP_MMC_REG_IOSR	0x60
-#define	OMAP_MMC_REG_SYSC	0x64
-#define	OMAP_MMC_REG_SYSS	0x68
-
-#define	OMAP_MMC_STAT_CARD_ERR		(1 << 14)
-#define	OMAP_MMC_STAT_CARD_IRQ		(1 << 13)
-#define	OMAP_MMC_STAT_OCR_BUSY		(1 << 12)
-#define	OMAP_MMC_STAT_A_EMPTY		(1 << 11)
-#define	OMAP_MMC_STAT_A_FULL		(1 << 10)
-#define	OMAP_MMC_STAT_CMD_CRC		(1 <<  8)
-#define	OMAP_MMC_STAT_CMD_TOUT		(1 <<  7)
-#define	OMAP_MMC_STAT_DATA_CRC		(1 <<  6)
-#define	OMAP_MMC_STAT_DATA_TOUT		(1 <<  5)
-#define	OMAP_MMC_STAT_END_BUSY		(1 <<  4)
-#define	OMAP_MMC_STAT_END_OF_DATA	(1 <<  3)
-#define	OMAP_MMC_STAT_CARD_BUSY		(1 <<  2)
-#define	OMAP_MMC_STAT_END_OF_CMD	(1 <<  0)
-
-#define OMAP_MMC_READ(host, reg)	__raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
-#define OMAP_MMC_WRITE(host, reg, val)	__raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
-
-/*
- * Command types
- */
-#define OMAP_MMC_CMDTYPE_BC	0
-#define OMAP_MMC_CMDTYPE_BCR	1
-#define OMAP_MMC_CMDTYPE_AC	2
-#define OMAP_MMC_CMDTYPE_ADTC	3
-
-
-#define DRIVER_NAME "mmci-omap"
-
-/* Specifies how often in millisecs to poll for card status changes
- * when the cover switch is open */
-#define OMAP_MMC_SWITCH_POLL_DELAY	500
-
-static int mmc_omap_enable_poll = 1;
-
-struct mmc_omap_host {
-	int			initialized;
-	int			suspended;
-	struct mmc_request *	mrq;
-	struct mmc_command *	cmd;
-	struct mmc_data *	data;
-	struct mmc_host *	mmc;
-	struct device *		dev;
-	unsigned char		id; /* 16xx chips have 2 MMC blocks */
-	struct clk *		iclk;
-	struct clk *		fclk;
-	struct resource		*mem_res;
-	void __iomem		*virt_base;
-	unsigned int		phys_base;
-	int			irq;
-	unsigned char		bus_mode;
-	unsigned char		hw_bus_mode;
-
-	unsigned int		sg_len;
-	int			sg_idx;
-	u16 *			buffer;
-	u32			buffer_bytes_left;
-	u32			total_bytes_left;
-
-	unsigned		use_dma:1;
-	unsigned		brs_received:1, dma_done:1;
-	unsigned		dma_is_read:1;
-	unsigned		dma_in_use:1;
-	int			dma_ch;
-	spinlock_t		dma_lock;
-	struct timer_list	dma_timer;
-	unsigned		dma_len;
-
-	short			power_pin;
-	short			wp_pin;
-
-	int			switch_pin;
-	struct work_struct	switch_work;
-	struct timer_list	switch_timer;
-	int			switch_last_state;
-};
-
-static inline int
-mmc_omap_cover_is_open(struct mmc_omap_host *host)
-{
-	if (host->switch_pin < 0)
-		return 0;
-	return omap_get_gpio_datain(host->switch_pin);
-}
-
-static ssize_t
-mmc_omap_show_cover_switch(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	struct mmc_omap_host *host = dev_get_drvdata(dev);
-
-	return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" :
-			"closed");
-}
-
-static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
-
-static ssize_t
-mmc_omap_show_enable_poll(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll);
-}
-
-static ssize_t
-mmc_omap_store_enable_poll(struct device *dev,
-	struct device_attribute *attr, const char *buf,
-	size_t size)
-{
-	int enable_poll;
-
-	if (sscanf(buf, "%10d", &enable_poll) != 1)
-		return -EINVAL;
-
-	if (enable_poll != mmc_omap_enable_poll) {
-		struct mmc_omap_host *host = dev_get_drvdata(dev);
-
-		mmc_omap_enable_poll = enable_poll;
-		if (enable_poll && host->switch_pin >= 0)
-			schedule_work(&host->switch_work);
-	}
-	return size;
-}
-
-static DEVICE_ATTR(enable_poll, 0664,
-		   mmc_omap_show_enable_poll, mmc_omap_store_enable_poll);
-
-static void
-mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
-	u32 cmdreg;
-	u32 resptype;
-	u32 cmdtype;
-
-	host->cmd = cmd;
-
-	resptype = 0;
-	cmdtype = 0;
-
-	/* Our hardware needs to know exact type */
-	switch (mmc_resp_type(cmd)) {
-	case MMC_RSP_NONE:
-		break;
-	case MMC_RSP_R1:
-	case MMC_RSP_R1B:
-		/* resp 1, 1b, 6, 7 */
-		resptype = 1;
-		break;
-	case MMC_RSP_R2:
-		resptype = 2;
-		break;
-	case MMC_RSP_R3:
-		resptype = 3;
-		break;
-	default:
-		dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
-		break;
-	}
-
-	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) {
-		cmdtype = OMAP_MMC_CMDTYPE_ADTC;
-	} else if (mmc_cmd_type(cmd) == MMC_CMD_BC) {
-		cmdtype = OMAP_MMC_CMDTYPE_BC;
-	} else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) {
-		cmdtype = OMAP_MMC_CMDTYPE_BCR;
-	} else {
-		cmdtype = OMAP_MMC_CMDTYPE_AC;
-	}
-
-	cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
-
-	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
-		cmdreg |= 1 << 6;
-
-	if (cmd->flags & MMC_RSP_BUSY)
-		cmdreg |= 1 << 11;
-
-	if (host->data && !(host->data->flags & MMC_DATA_WRITE))
-		cmdreg |= 1 << 15;
-
-	clk_enable(host->fclk);
-
-	OMAP_MMC_WRITE(host, CTO, 200);
-	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
-	OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
-	OMAP_MMC_WRITE(host, IE,
-		       OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
-		       OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
-		       OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
-		       OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
-		       OMAP_MMC_STAT_END_OF_DATA);
-	OMAP_MMC_WRITE(host, CMD, cmdreg);
-}
-
-static void
-mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
-	if (host->dma_in_use) {
-		enum dma_data_direction dma_data_dir;
-
-		BUG_ON(host->dma_ch < 0);
-		if (data->error != MMC_ERR_NONE)
-			omap_stop_dma(host->dma_ch);
-		/* Release DMA channel lazily */
-		mod_timer(&host->dma_timer, jiffies + HZ);
-		if (data->flags & MMC_DATA_WRITE)
-			dma_data_dir = DMA_TO_DEVICE;
-		else
-			dma_data_dir = DMA_FROM_DEVICE;
-		dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
-			     dma_data_dir);
-	}
-	host->data = NULL;
-	host->sg_len = 0;
-	clk_disable(host->fclk);
-
-	/* NOTE:  MMC layer will sometimes poll-wait CMD13 next, issuing
-	 * dozens of requests until the card finishes writing data.
-	 * It'd be cheaper to just wait till an EOFB interrupt arrives...
-	 */
-
-	if (!data->stop) {
-		host->mrq = NULL;
-		mmc_request_done(host->mmc, data->mrq);
-		return;
-	}
-
-	mmc_omap_start_command(host, data->stop);
-}
-
-static void
-mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
-{
-	unsigned long flags;
-	int done;
-
-	if (!host->dma_in_use) {
-		mmc_omap_xfer_done(host, data);
-		return;
-	}
-	done = 0;
-	spin_lock_irqsave(&host->dma_lock, flags);
-	if (host->dma_done)
-		done = 1;
-	else
-		host->brs_received = 1;
-	spin_unlock_irqrestore(&host->dma_lock, flags);
-	if (done)
-		mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_dma_timer(unsigned long data)
-{
-	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-
-	BUG_ON(host->dma_ch < 0);
-	omap_free_dma(host->dma_ch);
-	host->dma_ch = -1;
-}
-
-static void
-mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
-	unsigned long flags;
-	int done;
-
-	done = 0;
-	spin_lock_irqsave(&host->dma_lock, flags);
-	if (host->brs_received)
-		done = 1;
-	else
-		host->dma_done = 1;
-	spin_unlock_irqrestore(&host->dma_lock, flags);
-	if (done)
-		mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
-	host->cmd = NULL;
-
-	if (cmd->flags & MMC_RSP_PRESENT) {
-		if (cmd->flags & MMC_RSP_136) {
-			/* response type 2 */
-			cmd->resp[3] =
-				OMAP_MMC_READ(host, RSP0) |
-				(OMAP_MMC_READ(host, RSP1) << 16);
-			cmd->resp[2] =
-				OMAP_MMC_READ(host, RSP2) |
-				(OMAP_MMC_READ(host, RSP3) << 16);
-			cmd->resp[1] =
-				OMAP_MMC_READ(host, RSP4) |
-				(OMAP_MMC_READ(host, RSP5) << 16);
-			cmd->resp[0] =
-				OMAP_MMC_READ(host, RSP6) |
-				(OMAP_MMC_READ(host, RSP7) << 16);
-		} else {
-			/* response types 1, 1b, 3, 4, 5, 6 */
-			cmd->resp[0] =
-				OMAP_MMC_READ(host, RSP6) |
-				(OMAP_MMC_READ(host, RSP7) << 16);
-		}
-	}
-
-	if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
-		host->mrq = NULL;
-		clk_disable(host->fclk);
-		mmc_request_done(host->mmc, cmd->mrq);
-	}
-}
-
-/* PIO only */
-static void
-mmc_omap_sg_to_buf(struct mmc_omap_host *host)
-{
-	struct scatterlist *sg;
-
-	sg = host->data->sg + host->sg_idx;
-	host->buffer_bytes_left = sg->length;
-	host->buffer = page_address(sg->page) + sg->offset;
-	if (host->buffer_bytes_left > host->total_bytes_left)
-		host->buffer_bytes_left = host->total_bytes_left;
-}
-
-/* PIO only */
-static void
-mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
-{
-	int n;
-
-	if (host->buffer_bytes_left == 0) {
-		host->sg_idx++;
-		BUG_ON(host->sg_idx == host->sg_len);
-		mmc_omap_sg_to_buf(host);
-	}
-	n = 64;
-	if (n > host->buffer_bytes_left)
-		n = host->buffer_bytes_left;
-	host->buffer_bytes_left -= n;
-	host->total_bytes_left -= n;
-	host->data->bytes_xfered += n;
-
-	if (write) {
-		__raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
-	} else {
-		__raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
-	}
-}
-
-static inline void mmc_omap_report_irq(u16 status)
-{
-	static const char *mmc_omap_status_bits[] = {
-		"EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
-		"CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
-	};
-	int i, c = 0;
-
-	for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
-		if (status & (1 << i)) {
-			if (c)
-				printk(" ");
-			printk("%s", mmc_omap_status_bits[i]);
-			c++;
-		}
-}
-
-static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
-{
-	struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
-	u16 status;
-	int end_command;
-	int end_transfer;
-	int transfer_error;
-
-	if (host->cmd == NULL && host->data == NULL) {
-		status = OMAP_MMC_READ(host, STAT);
-		dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
-		if (status != 0) {
-			OMAP_MMC_WRITE(host, STAT, status);
-			OMAP_MMC_WRITE(host, IE, 0);
-		}
-		return IRQ_HANDLED;
-	}
-
-	end_command = 0;
-	end_transfer = 0;
-	transfer_error = 0;
-
-	while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
-		OMAP_MMC_WRITE(host, STAT, status);
-#ifdef CONFIG_MMC_DEBUG
-		dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
-			status, host->cmd != NULL ? host->cmd->opcode : -1);
-		mmc_omap_report_irq(status);
-		printk("\n");
-#endif
-		if (host->total_bytes_left) {
-			if ((status & OMAP_MMC_STAT_A_FULL) ||
-			    (status & OMAP_MMC_STAT_END_OF_DATA))
-				mmc_omap_xfer_data(host, 0);
-			if (status & OMAP_MMC_STAT_A_EMPTY)
-				mmc_omap_xfer_data(host, 1);
-		}
-
-		if (status & OMAP_MMC_STAT_END_OF_DATA) {
-			end_transfer = 1;
-		}
-
-		if (status & OMAP_MMC_STAT_DATA_TOUT) {
-			dev_dbg(mmc_dev(host->mmc), "data timeout\n");
-			if (host->data) {
-				host->data->error |= MMC_ERR_TIMEOUT;
-				transfer_error = 1;
-			}
-		}
-
-		if (status & OMAP_MMC_STAT_DATA_CRC) {
-			if (host->data) {
-				host->data->error |= MMC_ERR_BADCRC;
-				dev_dbg(mmc_dev(host->mmc),
-					 "data CRC error, bytes left %d\n",
-					host->total_bytes_left);
-				transfer_error = 1;
-			} else {
-				dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
-			}
-		}
-
-		if (status & OMAP_MMC_STAT_CMD_TOUT) {
-			/* Timeouts are routine with some commands */
-			if (host->cmd) {
-				if (host->cmd->opcode != MMC_ALL_SEND_CID &&
-						host->cmd->opcode !=
-						MMC_SEND_OP_COND &&
-						host->cmd->opcode !=
-						MMC_APP_CMD &&
-						!mmc_omap_cover_is_open(host))
-					dev_err(mmc_dev(host->mmc),
-						"command timeout, CMD %d\n",
-						host->cmd->opcode);
-				host->cmd->error = MMC_ERR_TIMEOUT;
-				end_command = 1;
-			}
-		}
-
-		if (status & OMAP_MMC_STAT_CMD_CRC) {
-			if (host->cmd) {
-				dev_err(mmc_dev(host->mmc),
-					"command CRC error (CMD%d, arg 0x%08x)\n",
-					host->cmd->opcode, host->cmd->arg);
-				host->cmd->error = MMC_ERR_BADCRC;
-				end_command = 1;
-			} else
-				dev_err(mmc_dev(host->mmc),
-					"command CRC error without cmd?\n");
-		}
-
-		if (status & OMAP_MMC_STAT_CARD_ERR) {
-			if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
-				u32 response = OMAP_MMC_READ(host, RSP6)
-					| (OMAP_MMC_READ(host, RSP7) << 16);
-				/* STOP sometimes sets must-ignore bits */
-				if (!(response & (R1_CC_ERROR
-								| R1_ILLEGAL_COMMAND
-								| R1_COM_CRC_ERROR))) {
-					end_command = 1;
-					continue;
-				}
-			}
-
-			dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n",
-				host->cmd->opcode);
-			if (host->cmd) {
-				host->cmd->error = MMC_ERR_FAILED;
-				end_command = 1;
-			}
-			if (host->data) {
-				host->data->error = MMC_ERR_FAILED;
-				transfer_error = 1;
-			}
-		}
-
-		/*
-		 * NOTE: On 1610 the END_OF_CMD may come too early when
-		 * starting a write 
-		 */
-		if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
-		    (!(status & OMAP_MMC_STAT_A_EMPTY))) {
-			end_command = 1;
-		}
-	}
-
-	if (end_command) {
-		mmc_omap_cmd_done(host, host->cmd);
-	}
-	if (transfer_error)
-		mmc_omap_xfer_done(host, host->data);
-	else if (end_transfer)
-		mmc_omap_end_of_data(host, host->data);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
-{
-	struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
-
-	schedule_work(&host->switch_work);
-
-	return IRQ_HANDLED;
-}
-
-static void mmc_omap_switch_timer(unsigned long arg)
-{
-	struct mmc_omap_host *host = (struct mmc_omap_host *) arg;
-
-	schedule_work(&host->switch_work);
-}
-
-static void mmc_omap_switch_handler(struct work_struct *work)
-{
-	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, switch_work);
-	struct mmc_card *card;
-	static int complained = 0;
-	int cards = 0, cover_open;
-
-	if (host->switch_pin == -1)
-		return;
-	cover_open = mmc_omap_cover_is_open(host);
-	if (cover_open != host->switch_last_state) {
-		kobject_uevent(&host->dev->kobj, KOBJ_CHANGE);
-		host->switch_last_state = cover_open;
-	}
-	mmc_detect_change(host->mmc, 0);
-	list_for_each_entry(card, &host->mmc->cards, node) {
-		if (mmc_card_present(card))
-			cards++;
-	}
-	if (mmc_omap_cover_is_open(host)) {
-		if (!complained) {
-			dev_info(mmc_dev(host->mmc), "cover is open");
-			complained = 1;
-		}
-		if (mmc_omap_enable_poll)
-			mod_timer(&host->switch_timer, jiffies +
-				msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY));
-	} else {
-		complained = 0;
-	}
-}
-
-/* Prepare to transfer the next segment of a scatterlist */
-static void
-mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
-{
-	int dma_ch = host->dma_ch;
-	unsigned long data_addr;
-	u16 buf, frame;
-	u32 count;
-	struct scatterlist *sg = &data->sg[host->sg_idx];
-	int src_port = 0;
-	int dst_port = 0;
-	int sync_dev = 0;
-
-	data_addr = host->phys_base + OMAP_MMC_REG_DATA;
-	frame = data->blksz;
-	count = sg_dma_len(sg);
-
-	if ((data->blocks == 1) && (count > data->blksz))
-		count = frame;
-
-	host->dma_len = count;
-
-	/* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
-	 * Use 16 or 32 word frames when the blocksize is at least that large.
-	 * Blocksize is usually 512 bytes; but not for some SD reads.
-	 */
-	if (cpu_is_omap15xx() && frame > 32)
-		frame = 32;
-	else if (frame > 64)
-		frame = 64;
-	count /= frame;
-	frame >>= 1;
-
-	if (!(data->flags & MMC_DATA_WRITE)) {
-		buf = 0x800f | ((frame - 1) << 8);
-
-		if (cpu_class_is_omap1()) {
-			src_port = OMAP_DMA_PORT_TIPB;
-			dst_port = OMAP_DMA_PORT_EMIFF;
-		}
-		if (cpu_is_omap24xx())
-			sync_dev = OMAP24XX_DMA_MMC1_RX;
-
-		omap_set_dma_src_params(dma_ch, src_port,
-					OMAP_DMA_AMODE_CONSTANT,
-					data_addr, 0, 0);
-		omap_set_dma_dest_params(dma_ch, dst_port,
-					 OMAP_DMA_AMODE_POST_INC,
-					 sg_dma_address(sg), 0, 0);
-		omap_set_dma_dest_data_pack(dma_ch, 1);
-		omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
-	} else {
-		buf = 0x0f80 | ((frame - 1) << 0);
-
-		if (cpu_class_is_omap1()) {
-			src_port = OMAP_DMA_PORT_EMIFF;
-			dst_port = OMAP_DMA_PORT_TIPB;
-		}
-		if (cpu_is_omap24xx())
-			sync_dev = OMAP24XX_DMA_MMC1_TX;
-
-		omap_set_dma_dest_params(dma_ch, dst_port,
-					 OMAP_DMA_AMODE_CONSTANT,
-					 data_addr, 0, 0);
-		omap_set_dma_src_params(dma_ch, src_port,
-					OMAP_DMA_AMODE_POST_INC,
-					sg_dma_address(sg), 0, 0);
-		omap_set_dma_src_data_pack(dma_ch, 1);
-		omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
-	}
-
-	/* Max limit for DMA frame count is 0xffff */
-	BUG_ON(count > 0xffff);
-
-	OMAP_MMC_WRITE(host, BUF, buf);
-	omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
-				     frame, count, OMAP_DMA_SYNC_FRAME,
-				     sync_dev, 0);
-}
-
-/* A scatterlist segment completed */
-static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
-{
-	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-	struct mmc_data *mmcdat = host->data;
-
-	if (unlikely(host->dma_ch < 0)) {
-		dev_err(mmc_dev(host->mmc),
-			"DMA callback while DMA not enabled\n");
-		return;
-	}
-	/* FIXME: We really should do something to _handle_ the errors */
-	if (ch_status & OMAP1_DMA_TOUT_IRQ) {
-		dev_err(mmc_dev(host->mmc),"DMA timeout\n");
-		return;
-	}
-	if (ch_status & OMAP_DMA_DROP_IRQ) {
-		dev_err(mmc_dev(host->mmc), "DMA sync error\n");
-		return;
-	}
-	if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
-		return;
-	}
-	mmcdat->bytes_xfered += host->dma_len;
-	host->sg_idx++;
-	if (host->sg_idx < host->sg_len) {
-		mmc_omap_prepare_dma(host, host->data);
-		omap_start_dma(host->dma_ch);
-	} else
-		mmc_omap_dma_done(host, host->data);
-}
-
-static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
-{
-	const char *dev_name;
-	int sync_dev, dma_ch, is_read, r;
-
-	is_read = !(data->flags & MMC_DATA_WRITE);
-	del_timer_sync(&host->dma_timer);
-	if (host->dma_ch >= 0) {
-		if (is_read == host->dma_is_read)
-			return 0;
-		omap_free_dma(host->dma_ch);
-		host->dma_ch = -1;
-	}
-
-	if (is_read) {
-		if (host->id == 1) {
-			sync_dev = OMAP_DMA_MMC_RX;
-			dev_name = "MMC1 read";
-		} else {
-			sync_dev = OMAP_DMA_MMC2_RX;
-			dev_name = "MMC2 read";
-		}
-	} else {
-		if (host->id == 1) {
-			sync_dev = OMAP_DMA_MMC_TX;
-			dev_name = "MMC1 write";
-		} else {
-			sync_dev = OMAP_DMA_MMC2_TX;
-			dev_name = "MMC2 write";
-		}
-	}
-	r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
-			     host, &dma_ch);
-	if (r != 0) {
-		dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
-		return r;
-	}
-	host->dma_ch = dma_ch;
-	host->dma_is_read = is_read;
-
-	return 0;
-}
-
-static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
-	u16 reg;
-
-	reg = OMAP_MMC_READ(host, SDIO);
-	reg &= ~(1 << 5);
-	OMAP_MMC_WRITE(host, SDIO, reg);
-	/* Set maximum timeout */
-	OMAP_MMC_WRITE(host, CTO, 0xff);
-}
-
-static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
-	int timeout;
-	u16 reg;
-
-	/* Convert ns to clock cycles by assuming 20MHz frequency
-	 * 1 cycle at 20MHz = 500 ns
-	 */
-	timeout = req->data->timeout_clks + req->data->timeout_ns / 500;
-
-	/* Check if we need to use timeout multiplier register */
-	reg = OMAP_MMC_READ(host, SDIO);
-	if (timeout > 0xffff) {
-		reg |= (1 << 5);
-		timeout /= 1024;
-	} else
-		reg &= ~(1 << 5);
-	OMAP_MMC_WRITE(host, SDIO, reg);
-	OMAP_MMC_WRITE(host, DTO, timeout);
-}
-
-static void
-mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
-{
-	struct mmc_data *data = req->data;
-	int i, use_dma, block_size;
-	unsigned sg_len;
-
-	host->data = data;
-	if (data == NULL) {
-		OMAP_MMC_WRITE(host, BLEN, 0);
-		OMAP_MMC_WRITE(host, NBLK, 0);
-		OMAP_MMC_WRITE(host, BUF, 0);
-		host->dma_in_use = 0;
-		set_cmd_timeout(host, req);
-		return;
-	}
-
-	block_size = data->blksz;
-
-	OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
-	OMAP_MMC_WRITE(host, BLEN, block_size - 1);
-	set_data_timeout(host, req);
-
-	/* cope with calling layer confusion; it issues "single
-	 * block" writes using multi-block scatterlists.
-	 */
-	sg_len = (data->blocks == 1) ? 1 : data->sg_len;
-
-	/* Only do DMA for entire blocks */
-	use_dma = host->use_dma;
-	if (use_dma) {
-		for (i = 0; i < sg_len; i++) {
-			if ((data->sg[i].length % block_size) != 0) {
-				use_dma = 0;
-				break;
-			}
-		}
-	}
-
-	host->sg_idx = 0;
-	if (use_dma) {
-		if (mmc_omap_get_dma_channel(host, data) == 0) {
-			enum dma_data_direction dma_data_dir;
-
-			if (data->flags & MMC_DATA_WRITE)
-				dma_data_dir = DMA_TO_DEVICE;
-			else
-				dma_data_dir = DMA_FROM_DEVICE;
-
-			host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
-						sg_len, dma_data_dir);
-			host->total_bytes_left = 0;
-			mmc_omap_prepare_dma(host, req->data);
-			host->brs_received = 0;
-			host->dma_done = 0;
-			host->dma_in_use = 1;
-		} else
-			use_dma = 0;
-	}
-
-	/* Revert to PIO? */
-	if (!use_dma) {
-		OMAP_MMC_WRITE(host, BUF, 0x1f1f);
-		host->total_bytes_left = data->blocks * block_size;
-		host->sg_len = sg_len;
-		mmc_omap_sg_to_buf(host);
-		host->dma_in_use = 0;
-	}
-}
-
-static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
-{
-	struct mmc_omap_host *host = mmc_priv(mmc);
-
-	WARN_ON(host->mrq != NULL);
-
-	host->mrq = req;
-
-	/* only touch fifo AFTER the controller readies it */
-	mmc_omap_prepare_data(host, req);
-	mmc_omap_start_command(host, req->cmd);
-	if (host->dma_in_use)
-		omap_start_dma(host->dma_ch);
-}
-
-static void innovator_fpga_socket_power(int on)
-{
-#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX)
-	if (on) {
-		fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
-		     OMAP1510_FPGA_POWER);
-	} else {
-		fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
-		     OMAP1510_FPGA_POWER);
-	}
-#endif
-}
-
-/*
- * Turn the socket power on/off. Innovator uses FPGA, most boards
- * probably use GPIO.
- */
-static void mmc_omap_power(struct mmc_omap_host *host, int on)
-{
-	if (on) {
-		if (machine_is_omap_innovator())
-			innovator_fpga_socket_power(1);
-		else if (machine_is_omap_h2())
-			tps65010_set_gpio_out_value(GPIO3, HIGH);
-		else if (machine_is_omap_h3())
-			/* GPIO 4 of TPS65010 sends SD_EN signal */
-			tps65010_set_gpio_out_value(GPIO4, HIGH);
-		else if (cpu_is_omap24xx()) {
-			u16 reg = OMAP_MMC_READ(host, CON);
-			OMAP_MMC_WRITE(host, CON, reg | (1 << 11));
-		} else
-			if (host->power_pin >= 0)
-				omap_set_gpio_dataout(host->power_pin, 1);
-	} else {
-		if (machine_is_omap_innovator())
-			innovator_fpga_socket_power(0);
-		else if (machine_is_omap_h2())
-			tps65010_set_gpio_out_value(GPIO3, LOW);
-		else if (machine_is_omap_h3())
-			tps65010_set_gpio_out_value(GPIO4, LOW);
-		else if (cpu_is_omap24xx()) {
-			u16 reg = OMAP_MMC_READ(host, CON);
-			OMAP_MMC_WRITE(host, CON, reg & ~(1 << 11));
-		} else
-			if (host->power_pin >= 0)
-				omap_set_gpio_dataout(host->power_pin, 0);
-	}
-}
-
-static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct mmc_omap_host *host = mmc_priv(mmc);
-	int dsor;
-	int realclock, i;
-
-	realclock = ios->clock;
-
-	if (ios->clock == 0)
-		dsor = 0;
-	else {
-		int func_clk_rate = clk_get_rate(host->fclk);
-
-		dsor = func_clk_rate / realclock;
-		if (dsor < 1)
-			dsor = 1;
-
-		if (func_clk_rate / dsor > realclock)
-			dsor++;
-
-		if (dsor > 250)
-			dsor = 250;
-		dsor++;
-
-		if (ios->bus_width == MMC_BUS_WIDTH_4)
-			dsor |= 1 << 15;
-	}
-
-	switch (ios->power_mode) {
-	case MMC_POWER_OFF:
-		mmc_omap_power(host, 0);
-		break;
-	case MMC_POWER_UP:
-	case MMC_POWER_ON:
-		mmc_omap_power(host, 1);
-		dsor |= 1 << 11;
-		break;
-	}
-
-	host->bus_mode = ios->bus_mode;
-	host->hw_bus_mode = host->bus_mode;
-
-	clk_enable(host->fclk);
-
-	/* On insanely high arm_per frequencies something sometimes
-	 * goes somehow out of sync, and the POW bit is not being set,
-	 * which results in the while loop below getting stuck.
-	 * Writing to the CON register twice seems to do the trick. */
-	for (i = 0; i < 2; i++)
-		OMAP_MMC_WRITE(host, CON, dsor);
-	if (ios->power_mode == MMC_POWER_UP) {
-		/* Send clock cycles, poll completion */
-		OMAP_MMC_WRITE(host, IE, 0);
-		OMAP_MMC_WRITE(host, STAT, 0xffff);
-		OMAP_MMC_WRITE(host, CMD, 1 << 7);
-		while ((OMAP_MMC_READ(host, STAT) & 1) == 0);
-		OMAP_MMC_WRITE(host, STAT, 1);
-	}
-	clk_disable(host->fclk);
-}
-
-static int mmc_omap_get_ro(struct mmc_host *mmc)
-{
-	struct mmc_omap_host *host = mmc_priv(mmc);
-
-	return host->wp_pin && omap_get_gpio_datain(host->wp_pin);
-}
-
-static const struct mmc_host_ops mmc_omap_ops = {
-	.request	= mmc_omap_request,
-	.set_ios	= mmc_omap_set_ios,
-	.get_ro		= mmc_omap_get_ro,
-};
-
-static int __init mmc_omap_probe(struct platform_device *pdev)
-{
-	struct omap_mmc_conf *minfo = pdev->dev.platform_data;
-	struct mmc_host *mmc;
-	struct mmc_omap_host *host = NULL;
-	struct resource *res;
-	int ret = 0;
-	int irq;
-
-	if (minfo == NULL) {
-		dev_err(&pdev->dev, "platform data missing\n");
-		return -ENXIO;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	irq = platform_get_irq(pdev, 0);
-	if (res == NULL || irq < 0)
-		return -ENXIO;
-
-	res = request_mem_region(res->start, res->end - res->start + 1,
-			         pdev->name);
-	if (res == NULL)
-		return -EBUSY;
-
-	mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
-	if (mmc == NULL) {
-		ret = -ENOMEM;
-		goto err_free_mem_region;
-	}
-
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
-
-	spin_lock_init(&host->dma_lock);
-	init_timer(&host->dma_timer);
-	host->dma_timer.function = mmc_omap_dma_timer;
-	host->dma_timer.data = (unsigned long) host;
-
-	host->id = pdev->id;
-	host->mem_res = res;
-	host->irq = irq;
-
-	if (cpu_is_omap24xx()) {
-		host->iclk = clk_get(&pdev->dev, "mmc_ick");
-		if (IS_ERR(host->iclk))
-			goto err_free_mmc_host;
-		clk_enable(host->iclk);
-	}
-
-	if (!cpu_is_omap24xx())
-		host->fclk = clk_get(&pdev->dev, "mmc_ck");
-	else
-		host->fclk = clk_get(&pdev->dev, "mmc_fck");
-
-	if (IS_ERR(host->fclk)) {
-		ret = PTR_ERR(host->fclk);
-		goto err_free_iclk;
-	}
-
-	/* REVISIT:
-	 * Also, use minfo->cover to decide how to manage
-	 * the card detect sensing.
-	 */
-	host->power_pin = minfo->power_pin;
-	host->switch_pin = minfo->switch_pin;
-	host->wp_pin = minfo->wp_pin;
-	host->use_dma = 1;
-	host->dma_ch = -1;
-
-	host->irq = irq;
-	host->phys_base = host->mem_res->start;
-	host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
-
-	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_MULTIWRITE | 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
-	 * normally used (except e.g. for reading SD registers).
-	 */
-	mmc->max_phys_segs = 32;
-	mmc->max_hw_segs = 32;
-	mmc->max_blk_size = 2048;	/* BLEN is 11 bits (+1) */
-	mmc->max_blk_count = 2048;	/* NBLK is 11 bits (+1) */
-	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-	mmc->max_seg_size = mmc->max_req_size;
-
-	if (host->power_pin >= 0) {
-		if ((ret = omap_request_gpio(host->power_pin)) != 0) {
-			dev_err(mmc_dev(host->mmc),
-				"Unable to get GPIO pin for MMC power\n");
-			goto err_free_fclk;
-		}
-		omap_set_gpio_direction(host->power_pin, 0);
-	}
-
-	ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
-	if (ret)
-		goto err_free_power_gpio;
-
-	host->dev = &pdev->dev;
-	platform_set_drvdata(pdev, host);
-
-	if (host->switch_pin >= 0) {
-		INIT_WORK(&host->switch_work, mmc_omap_switch_handler);
-		init_timer(&host->switch_timer);
-		host->switch_timer.function = mmc_omap_switch_timer;
-		host->switch_timer.data = (unsigned long) host;
-		if (omap_request_gpio(host->switch_pin) != 0) {
-			dev_warn(mmc_dev(host->mmc), "Unable to get GPIO pin for MMC cover switch\n");
-			host->switch_pin = -1;
-			goto no_switch;
-		}
-
-		omap_set_gpio_direction(host->switch_pin, 1);
-		ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
-				  mmc_omap_switch_irq, IRQF_TRIGGER_RISING, DRIVER_NAME, host);
-		if (ret) {
-			dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n");
-			omap_free_gpio(host->switch_pin);
-			host->switch_pin = -1;
-			goto no_switch;
-		}
-		ret = device_create_file(&pdev->dev, &dev_attr_cover_switch);
-		if (ret == 0) {
-			ret = device_create_file(&pdev->dev, &dev_attr_enable_poll);
-			if (ret != 0)
-				device_remove_file(&pdev->dev, &dev_attr_cover_switch);
-		}
-		if (ret) {
-			dev_warn(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
-			free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
-			omap_free_gpio(host->switch_pin);
-			host->switch_pin = -1;
-			goto no_switch;
-		}
-		if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host))
-			schedule_work(&host->switch_work);
-	}
-
-	mmc_add_host(mmc);
-
-	return 0;
-
-no_switch:
-	/* FIXME: Free other resources too. */
-	if (host) {
-		if (host->iclk && !IS_ERR(host->iclk))
-			clk_put(host->iclk);
-		if (host->fclk && !IS_ERR(host->fclk))
-			clk_put(host->fclk);
-		mmc_free_host(host->mmc);
-	}
-err_free_power_gpio:
-	if (host->power_pin >= 0)
-		omap_free_gpio(host->power_pin);
-err_free_fclk:
-	clk_put(host->fclk);
-err_free_iclk:
-	if (host->iclk != NULL) {
-		clk_disable(host->iclk);
-		clk_put(host->iclk);
-	}
-err_free_mmc_host:
-	mmc_free_host(host->mmc);
-err_free_mem_region:
-	release_mem_region(res->start, res->end - res->start + 1);
-	return ret;
-}
-
-static int mmc_omap_remove(struct platform_device *pdev)
-{
-	struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
-
-	BUG_ON(host == NULL);
-
-	mmc_remove_host(host->mmc);
-	free_irq(host->irq, host);
-
-	if (host->power_pin >= 0)
-		omap_free_gpio(host->power_pin);
-	if (host->switch_pin >= 0) {
-		device_remove_file(&pdev->dev, &dev_attr_enable_poll);
-		device_remove_file(&pdev->dev, &dev_attr_cover_switch);
-		free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
-		omap_free_gpio(host->switch_pin);
-		host->switch_pin = -1;
-		del_timer_sync(&host->switch_timer);
-		flush_scheduled_work();
-	}
-	if (host->iclk && !IS_ERR(host->iclk))
-		clk_put(host->iclk);
-	if (host->fclk && !IS_ERR(host->fclk))
-		clk_put(host->fclk);
-
-	release_mem_region(pdev->resource[0].start,
-			   pdev->resource[0].end - pdev->resource[0].start + 1);
-
-	mmc_free_host(host->mmc);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
-	int ret = 0;
-	struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-	if (host && host->suspended)
-		return 0;
-
-	if (host) {
-		ret = mmc_suspend_host(host->mmc, mesg);
-		if (ret == 0)
-			host->suspended = 1;
-	}
-	return ret;
-}
-
-static int mmc_omap_resume(struct platform_device *pdev)
-{
-	int ret = 0;
-	struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
-	if (host && !host->suspended)
-		return 0;
-
-	if (host) {
-		ret = mmc_resume_host(host->mmc);
-		if (ret == 0)
-			host->suspended = 0;
-	}
-
-	return ret;
-}
-#else
-#define mmc_omap_suspend	NULL
-#define mmc_omap_resume		NULL
-#endif
-
-static struct platform_driver mmc_omap_driver = {
-	.probe		= mmc_omap_probe,
-	.remove		= mmc_omap_remove,
-	.suspend	= mmc_omap_suspend,
-	.resume		= mmc_omap_resume,
-	.driver		= {
-		.name	= DRIVER_NAME,
-	},
-};
-
-static int __init mmc_omap_init(void)
-{
-	return platform_driver_register(&mmc_omap_driver);
-}
-
-static void __exit mmc_omap_exit(void)
-{
-	platform_driver_unregister(&mmc_omap_driver);
-}
-
-module_init(mmc_omap_init);
-module_exit(mmc_omap_exit);
-
-MODULE_DESCRIPTION("OMAP Multimedia Card driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS(DRIVER_NAME);
-MODULE_AUTHOR("Juha Yrjölä");
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
deleted file mode 100644
index 9774fc6..0000000
--- a/drivers/mmc/pxamci.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- *  linux/drivers/mmc/pxa.c - PXA MMCI driver
- *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  This hardware is really sick:
- *   - No way to clear interrupts.
- *   - Have to turn off the clock whenever we touch the device.
- *   - Doesn't tell you how many data blocks were transferred.
- *  Yuck!
- *
- *	1 and 3 byte data transfers not supported
- *	max block length up to 1023
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/mmc.h>
-
-#include "pxamci.h"
-
-#define DRIVER_NAME	"pxa2xx-mci"
-
-#define NR_SG	1
-
-struct pxamci_host {
-	struct mmc_host		*mmc;
-	spinlock_t		lock;
-	struct resource		*res;
-	void __iomem		*base;
-	int			irq;
-	int			dma;
-	unsigned int		clkrt;
-	unsigned int		cmdat;
-	unsigned int		imask;
-	unsigned int		power_mode;
-	struct pxamci_platform_data *pdata;
-
-	struct mmc_request	*mrq;
-	struct mmc_command	*cmd;
-	struct mmc_data		*data;
-
-	dma_addr_t		sg_dma;
-	struct pxa_dma_desc	*sg_cpu;
-	unsigned int		dma_len;
-
-	unsigned int		dma_dir;
-};
-
-static void pxamci_stop_clock(struct pxamci_host *host)
-{
-	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
-		unsigned long timeout = 10000;
-		unsigned int v;
-
-		writel(STOP_CLOCK, host->base + MMC_STRPCL);
-
-		do {
-			v = readl(host->base + MMC_STAT);
-			if (!(v & STAT_CLK_EN))
-				break;
-			udelay(1);
-		} while (timeout--);
-
-		if (v & STAT_CLK_EN)
-			dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
-	}
-}
-
-static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->imask &= ~mask;
-	writel(host->imask, host->base + MMC_I_MASK);
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->imask |= mask;
-	writel(host->imask, host->base + MMC_I_MASK);
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
-{
-	unsigned int nob = data->blocks;
-	unsigned long long clks;
-	unsigned int timeout;
-	u32 dcmd;
-	int i;
-
-	host->data = data;
-
-	if (data->flags & MMC_DATA_STREAM)
-		nob = 0xffff;
-
-	writel(nob, host->base + MMC_NOB);
-	writel(data->blksz, host->base + MMC_BLKLEN);
-
-	clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
-	do_div(clks, 1000000000UL);
-	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
-	writel((timeout + 255) / 256, host->base + MMC_RDTO);
-
-	if (data->flags & MMC_DATA_READ) {
-		host->dma_dir = DMA_FROM_DEVICE;
-		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
-		DRCMRTXMMC = 0;
-		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
-	} else {
-		host->dma_dir = DMA_TO_DEVICE;
-		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
-		DRCMRRXMMC = 0;
-		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
-	}
-
-	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
-
-	host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-				   host->dma_dir);
-
-	for (i = 0; i < host->dma_len; i++) {
-		if (data->flags & MMC_DATA_READ) {
-			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
-			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
-		} else {
-			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
-			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
-		}
-		host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
-		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
-					sizeof(struct pxa_dma_desc);
-	}
-	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
-	wmb();
-
-	DDADR(host->dma) = host->sg_dma;
-	DCSR(host->dma) = DCSR_RUN;
-}
-
-static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
-	WARN_ON(host->cmd != NULL);
-	host->cmd = cmd;
-
-	if (cmd->flags & MMC_RSP_BUSY)
-		cmdat |= CMDAT_BUSY;
-
-#define RSP_TYPE(x)	((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
-	switch (RSP_TYPE(mmc_resp_type(cmd))) {
-	case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
-		cmdat |= CMDAT_RESP_SHORT;
-		break;
-	case RSP_TYPE(MMC_RSP_R3):
-		cmdat |= CMDAT_RESP_R3;
-		break;
-	case RSP_TYPE(MMC_RSP_R2):
-		cmdat |= CMDAT_RESP_R2;
-		break;
-	default:
-		break;
-	}
-
-	writel(cmd->opcode, host->base + MMC_CMD);
-	writel(cmd->arg >> 16, host->base + MMC_ARGH);
-	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
-	writel(cmdat, host->base + MMC_CMDAT);
-	writel(host->clkrt, host->base + MMC_CLKRT);
-
-	writel(START_CLOCK, host->base + MMC_STRPCL);
-
-	pxamci_enable_irq(host, END_CMD_RES);
-}
-
-static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
-{
-	host->mrq = NULL;
-	host->cmd = NULL;
-	host->data = NULL;
-	mmc_request_done(host->mmc, mrq);
-}
-
-static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
-{
-	struct mmc_command *cmd = host->cmd;
-	int i;
-	u32 v;
-
-	if (!cmd)
-		return 0;
-
-	host->cmd = NULL;
-
-	/*
-	 * Did I mention this is Sick.  We always need to
-	 * discard the upper 8 bits of the first 16-bit word.
-	 */
-	v = readl(host->base + MMC_RES) & 0xffff;
-	for (i = 0; i < 4; i++) {
-		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
-		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
-		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
-		v = w2;
-	}
-
-	if (stat & STAT_TIME_OUT_RESPONSE) {
-		cmd->error = MMC_ERR_TIMEOUT;
-	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
-#ifdef CONFIG_PXA27x
-		/*
-		 * workaround for erratum #42:
-		 * Intel PXA27x Family Processor Specification Update Rev 001
-		 */
-		if (cmd->opcode == MMC_ALL_SEND_CID ||
-		    cmd->opcode == MMC_SEND_CSD ||
-		    cmd->opcode == MMC_SEND_CID) {
-			/* a bogus CRC error can appear if the msb of
-			   the 15 byte response is a one */
-			if ((cmd->resp[0] & 0x80000000) == 0)
-				cmd->error = MMC_ERR_BADCRC;
-		} else {
-			pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode);
-		}
-#else
-		cmd->error = MMC_ERR_BADCRC;
-#endif
-	}
-
-	pxamci_disable_irq(host, END_CMD_RES);
-	if (host->data && cmd->error == MMC_ERR_NONE) {
-		pxamci_enable_irq(host, DATA_TRAN_DONE);
-	} else {
-		pxamci_finish_request(host, host->mrq);
-	}
-
-	return 1;
-}
-
-static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
-{
-	struct mmc_data *data = host->data;
-
-	if (!data)
-		return 0;
-
-	DCSR(host->dma) = 0;
-	dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
-		     host->dma_dir);
-
-	if (stat & STAT_READ_TIME_OUT)
-		data->error = MMC_ERR_TIMEOUT;
-	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
-		data->error = MMC_ERR_BADCRC;
-
-	/*
-	 * There appears to be a hardware design bug here.  There seems to
-	 * be no way to find out how much data was transferred to the card.
-	 * This means that if there was an error on any block, we mark all
-	 * data blocks as being in error.
-	 */
-	if (data->error == MMC_ERR_NONE)
-		data->bytes_xfered = data->blocks * data->blksz;
-	else
-		data->bytes_xfered = 0;
-
-	pxamci_disable_irq(host, DATA_TRAN_DONE);
-
-	host->data = NULL;
-	if (host->mrq->stop) {
-		pxamci_stop_clock(host);
-		pxamci_start_cmd(host, host->mrq->stop, 0);
-	} else {
-		pxamci_finish_request(host, host->mrq);
-	}
-
-	return 1;
-}
-
-static irqreturn_t pxamci_irq(int irq, void *devid)
-{
-	struct pxamci_host *host = devid;
-	unsigned int ireg;
-	int handled = 0;
-
-	ireg = readl(host->base + MMC_I_REG);
-
-	if (ireg) {
-		unsigned stat = readl(host->base + MMC_STAT);
-
-		pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
-
-		if (ireg & END_CMD_RES)
-			handled |= pxamci_cmd_done(host, stat);
-		if (ireg & DATA_TRAN_DONE)
-			handled |= pxamci_data_done(host, stat);
-	}
-
-	return IRQ_RETVAL(handled);
-}
-
-static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct pxamci_host *host = mmc_priv(mmc);
-	unsigned int cmdat;
-
-	WARN_ON(host->mrq != NULL);
-
-	host->mrq = mrq;
-
-	pxamci_stop_clock(host);
-
-	cmdat = host->cmdat;
-	host->cmdat &= ~CMDAT_INIT;
-
-	if (mrq->data) {
-		pxamci_setup_data(host, mrq->data);
-
-		cmdat &= ~CMDAT_BUSY;
-		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
-		if (mrq->data->flags & MMC_DATA_WRITE)
-			cmdat |= CMDAT_WRITE;
-
-		if (mrq->data->flags & MMC_DATA_STREAM)
-			cmdat |= CMDAT_STREAM;
-	}
-
-	pxamci_start_cmd(host, mrq->cmd, cmdat);
-}
-
-static int pxamci_get_ro(struct mmc_host *mmc)
-{
-	struct pxamci_host *host = mmc_priv(mmc);
-
-	if (host->pdata && host->pdata->get_ro)
-		return host->pdata->get_ro(mmc_dev(mmc));
-	/* Host doesn't support read only detection so assume writeable */
-	return 0;
-}
-
-static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct pxamci_host *host = mmc_priv(mmc);
-
-	if (ios->clock) {
-		unsigned int clk = CLOCKRATE / ios->clock;
-		if (CLOCKRATE / clk > ios->clock)
-			clk <<= 1;
-		host->clkrt = fls(clk) - 1;
-		pxa_set_cken(CKEN12_MMC, 1);
-
-		/*
-		 * we write clkrt on the next command
-		 */
-	} else {
-		pxamci_stop_clock(host);
-		pxa_set_cken(CKEN12_MMC, 0);
-	}
-
-	if (host->power_mode != ios->power_mode) {
-		host->power_mode = ios->power_mode;
-
-		if (host->pdata && host->pdata->setpower)
-			host->pdata->setpower(mmc_dev(mmc), ios->vdd);
-
-		if (ios->power_mode == MMC_POWER_ON)
-			host->cmdat |= CMDAT_INIT;
-	}
-
-	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
-		 host->clkrt, host->cmdat);
-}
-
-static const struct mmc_host_ops pxamci_ops = {
-	.request	= pxamci_request,
-	.get_ro		= pxamci_get_ro,
-	.set_ios	= pxamci_set_ios,
-};
-
-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 pxamci_host *host = mmc_priv(devid);
-
-	mmc_detect_change(devid, host->pdata->detect_delay);
-	return IRQ_HANDLED;
-}
-
-static int pxamci_probe(struct platform_device *pdev)
-{
-	struct mmc_host *mmc;
-	struct pxamci_host *host = NULL;
-	struct resource *r;
-	int ret, irq;
-
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	irq = platform_get_irq(pdev, 0);
-	if (!r || irq < 0)
-		return -ENXIO;
-
-	r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
-	if (!r)
-		return -EBUSY;
-
-	mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
-	if (!mmc) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	mmc->ops = &pxamci_ops;
-	mmc->f_min = CLOCKRATE_MIN;
-	mmc->f_max = CLOCKRATE_MAX;
-
-	/*
-	 * We can do SG-DMA, but we don't because we never know how much
-	 * data we successfully wrote to the card.
-	 */
-	mmc->max_phys_segs = NR_SG;
-
-	/*
-	 * Our hardware DMA can handle a maximum of one page per SG entry.
-	 */
-	mmc->max_seg_size = PAGE_SIZE;
-
-	/*
-	 * Block length register is 10 bits.
-	 */
-	mmc->max_blk_size = 1023;
-
-	/*
-	 * Block count register is 16 bits.
-	 */
-	mmc->max_blk_count = 65535;
-
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
-	host->dma = -1;
-	host->pdata = pdev->dev.platform_data;
-	mmc->ocr_avail = host->pdata ?
-			 host->pdata->ocr_mask :
-			 MMC_VDD_32_33|MMC_VDD_33_34;
-
-	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
-	if (!host->sg_cpu) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	spin_lock_init(&host->lock);
-	host->res = r;
-	host->irq = irq;
-	host->imask = MMC_I_MASK_ALL;
-
-	host->base = ioremap(r->start, SZ_4K);
-	if (!host->base) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	/*
-	 * Ensure that the host controller is shut down, and setup
-	 * with our defaults.
-	 */
-	pxamci_stop_clock(host);
-	writel(0, host->base + MMC_SPI);
-	writel(64, host->base + MMC_RESTO);
-	writel(host->imask, host->base + MMC_I_MASK);
-
-	host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
-				    pxamci_dma_irq, host);
-	if (host->dma < 0) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
-	if (ret)
-		goto out;
-
-	platform_set_drvdata(pdev, mmc);
-
-	if (host->pdata && host->pdata->init)
-		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
-
-	mmc_add_host(mmc);
-
-	return 0;
-
- out:
-	if (host) {
-		if (host->dma >= 0)
-			pxa_free_dma(host->dma);
-		if (host->base)
-			iounmap(host->base);
-		if (host->sg_cpu)
-			dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-	}
-	if (mmc)
-		mmc_free_host(mmc);
-	release_resource(r);
-	return ret;
-}
-
-static int pxamci_remove(struct platform_device *pdev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
-
-	if (mmc) {
-		struct pxamci_host *host = mmc_priv(mmc);
-
-		if (host->pdata && host->pdata->exit)
-			host->pdata->exit(&pdev->dev, mmc);
-
-		mmc_remove_host(mmc);
-
-		pxamci_stop_clock(host);
-		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
-		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
-		       host->base + MMC_I_MASK);
-
-		DRCMRRXMMC = 0;
-		DRCMRTXMMC = 0;
-
-		free_irq(host->irq, host);
-		pxa_free_dma(host->dma);
-		iounmap(host->base);
-		dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-
-		release_resource(host->res);
-
-		mmc_free_host(mmc);
-	}
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pxamci_suspend(struct platform_device *dev, pm_message_t state)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	int ret = 0;
-
-	if (mmc)
-		ret = mmc_suspend_host(mmc, state);
-
-	return ret;
-}
-
-static int pxamci_resume(struct platform_device *dev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	int ret = 0;
-
-	if (mmc)
-		ret = mmc_resume_host(mmc);
-
-	return ret;
-}
-#else
-#define pxamci_suspend	NULL
-#define pxamci_resume	NULL
-#endif
-
-static struct platform_driver pxamci_driver = {
-	.probe		= pxamci_probe,
-	.remove		= pxamci_remove,
-	.suspend	= pxamci_suspend,
-	.resume		= pxamci_resume,
-	.driver		= {
-		.name	= DRIVER_NAME,
-	},
-};
-
-static int __init pxamci_init(void)
-{
-	return platform_driver_register(&pxamci_driver);
-}
-
-static void __exit pxamci_exit(void)
-{
-	platform_driver_unregister(&pxamci_driver);
-}
-
-module_init(pxamci_init);
-module_exit(pxamci_exit);
-
-MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/pxamci.h
deleted file mode 100644
index 1b16322..0000000
--- a/drivers/mmc/pxamci.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#undef MMC_STRPCL
-#undef MMC_STAT
-#undef MMC_CLKRT
-#undef MMC_SPI
-#undef MMC_CMDAT
-#undef MMC_RESTO
-#undef MMC_RDTO
-#undef MMC_BLKLEN
-#undef MMC_NOB
-#undef MMC_PRTBUF
-#undef MMC_I_MASK
-#undef END_CMD_RES
-#undef PRG_DONE
-#undef DATA_TRAN_DONE
-#undef MMC_I_REG
-#undef MMC_CMD
-#undef MMC_ARGH
-#undef MMC_ARGL
-#undef MMC_RES
-#undef MMC_RXFIFO
-#undef MMC_TXFIFO
-
-#define MMC_STRPCL	0x0000
-#define STOP_CLOCK		(1 << 0)
-#define START_CLOCK		(2 << 0)
-
-#define MMC_STAT	0x0004
-#define STAT_END_CMD_RES		(1 << 13)
-#define STAT_PRG_DONE			(1 << 12)
-#define STAT_DATA_TRAN_DONE		(1 << 11)
-#define STAT_CLK_EN			(1 << 8)
-#define STAT_RECV_FIFO_FULL		(1 << 7)
-#define STAT_XMIT_FIFO_EMPTY		(1 << 6)
-#define STAT_RES_CRC_ERR		(1 << 5)
-#define STAT_SPI_READ_ERROR_TOKEN	(1 << 4)
-#define STAT_CRC_READ_ERROR		(1 << 3)
-#define STAT_CRC_WRITE_ERROR		(1 << 2)
-#define STAT_TIME_OUT_RESPONSE		(1 << 1)
-#define STAT_READ_TIME_OUT		(1 << 0)
-
-#define MMC_CLKRT	0x0008		/* 3 bit */
-
-#define MMC_SPI		0x000c
-#define SPI_CS_ADDRESS		(1 << 3)
-#define SPI_CS_EN		(1 << 2)
-#define CRC_ON			(1 << 1)
-#define SPI_EN			(1 << 0)
-
-#define MMC_CMDAT	0x0010
-#define CMDAT_DMAEN		(1 << 7)
-#define CMDAT_INIT		(1 << 6)
-#define CMDAT_BUSY		(1 << 5)
-#define CMDAT_STREAM		(1 << 4)	/* 1 = stream */
-#define CMDAT_WRITE		(1 << 3)	/* 1 = write */
-#define CMDAT_DATAEN		(1 << 2)
-#define CMDAT_RESP_NONE		(0 << 0)
-#define CMDAT_RESP_SHORT	(1 << 0)
-#define CMDAT_RESP_R2		(2 << 0)
-#define CMDAT_RESP_R3		(3 << 0)
-
-#define MMC_RESTO	0x0014	/* 7 bit */
-
-#define MMC_RDTO	0x0018	/* 16 bit */
-
-#define MMC_BLKLEN	0x001c	/* 10 bit */
-
-#define MMC_NOB		0x0020	/* 16 bit */
-
-#define MMC_PRTBUF	0x0024
-#define BUF_PART_FULL		(1 << 0)
-
-#define MMC_I_MASK	0x0028
-
-/*PXA27x MMC interrupts*/
-#define SDIO_SUSPEND_ACK  	(1 << 12)
-#define SDIO_INT          	(1 << 11)
-#define RD_STALLED        	(1 << 10)
-#define RES_ERR           	(1 << 9)
-#define DAT_ERR           	(1 << 8)
-#define TINT              	(1 << 7)
-
-/*PXA2xx MMC interrupts*/
-#define TXFIFO_WR_REQ		(1 << 6)
-#define RXFIFO_RD_REQ		(1 << 5)
-#define CLK_IS_OFF		(1 << 4)
-#define STOP_CMD		(1 << 3)
-#define END_CMD_RES		(1 << 2)
-#define PRG_DONE		(1 << 1)
-#define DATA_TRAN_DONE		(1 << 0)
-
-#ifdef CONFIG_PXA27x
-#define MMC_I_MASK_ALL          0x00001fff
-#else
-#define MMC_I_MASK_ALL          0x0000007f
-#endif
-
-#define MMC_I_REG	0x002c
-/* same as MMC_I_MASK */
-
-#define MMC_CMD		0x0030
-
-#define MMC_ARGH	0x0034	/* 16 bit */
-
-#define MMC_ARGL	0x0038	/* 16 bit */
-
-#define MMC_RES		0x003c	/* 16 bit */
-
-#define MMC_RXFIFO	0x0040	/* 8 bit */
-
-#define MMC_TXFIFO	0x0044	/* 8 bit */
-
-/*
- * The base MMC clock rate
- */
-#ifdef CONFIG_PXA27x
-#define CLOCKRATE_MIN	304688
-#define CLOCKRATE_MAX	19500000
-#else
-#define CLOCKRATE_MIN	312500
-#define CLOCKRATE_MAX	20000000
-#endif
-
-#define CLOCKRATE	CLOCKRATE_MAX
-
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
deleted file mode 100644
index d749f08..0000000
--- a/drivers/mmc/sdhci.c
+++ /dev/null
@@ -1,1550 +0,0 @@
-/*
- *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
- *
- *  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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include <asm/scatterlist.h>
-
-#include "sdhci.h"
-
-#define DRIVER_NAME "sdhci"
-
-#define DBG(f, x...) \
-	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-
-static unsigned int debug_nodma = 0;
-static unsigned int debug_forcedma = 0;
-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)
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
-
-static const struct pci_device_id pci_ids[] __devinitdata = {
-	{
-		.vendor		= PCI_VENDOR_ID_RICOH,
-		.device		= PCI_DEVICE_ID_RICOH_R5C822,
-		.subvendor	= PCI_VENDOR_ID_IBM,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
-				  SDHCI_QUIRK_FORCE_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_RICOH,
-		.device		= PCI_DEVICE_ID_RICOH_R5C822,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
-				  SDHCI_QUIRK_NO_CARD_NO_RESET,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_TI,
-		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_ENE,
-		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
-	},
-
-	{	/* Generic SD host controller */
-		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
-	},
-
-	{ /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
-static void sdhci_finish_data(struct sdhci_host *);
-
-static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
-static void sdhci_finish_command(struct sdhci_host *);
-
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
-	printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
-
-	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
-		readl(host->ioaddr + SDHCI_DMA_ADDRESS),
-		readw(host->ioaddr + SDHCI_HOST_VERSION));
-	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
-		readw(host->ioaddr + SDHCI_BLOCK_SIZE),
-		readw(host->ioaddr + SDHCI_BLOCK_COUNT));
-	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
-		readl(host->ioaddr + SDHCI_ARGUMENT),
-		readw(host->ioaddr + SDHCI_TRANSFER_MODE));
-	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n",
-		readl(host->ioaddr + SDHCI_PRESENT_STATE),
-		readb(host->ioaddr + SDHCI_HOST_CONTROL));
-	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n",
-		readb(host->ioaddr + SDHCI_POWER_CONTROL),
-		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
-	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
-		readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
-		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
-	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
-		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
-		readl(host->ioaddr + SDHCI_INT_STATUS));
-	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
-		readl(host->ioaddr + SDHCI_INT_ENABLE),
-		readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
-	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-		readw(host->ioaddr + SDHCI_ACMD12_ERR),
-		readw(host->ioaddr + SDHCI_SLOT_INT_STATUS));
-	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Max curr: 0x%08x\n",
-		readl(host->ioaddr + SDHCI_CAPABILITIES),
-		readl(host->ioaddr + SDHCI_MAX_CURRENT));
-
-	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n");
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Low level functions                                                       *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
-{
-	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)
-		host->clock = 0;
-
-	/* Wait max 100 ms */
-	timeout = 100;
-
-	/* hw clears the bit when it's done */
-	while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
-		if (timeout == 0) {
-			printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
-				mmc_hostname(host->mmc), (int)mask);
-			sdhci_dumpregs(host);
-			return;
-		}
-		timeout--;
-		mdelay(1);
-	}
-}
-
-static void sdhci_init(struct sdhci_host *host)
-{
-	u32 intmask;
-
-	sdhci_reset(host, SDHCI_RESET_ALL);
-
-	intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
-		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
-		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
-
-	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
-	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_activate_led(struct sdhci_host *host)
-{
-	u8 ctrl;
-
-	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-	ctrl |= SDHCI_CTRL_LED;
-	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-}
-
-static void sdhci_deactivate_led(struct sdhci_host *host)
-{
-	u8 ctrl;
-
-	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-	ctrl &= ~SDHCI_CTRL_LED;
-	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Core functions                                                            *
- *                                                                           *
-\*****************************************************************************/
-
-static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
-{
-	return page_address(host->cur_sg->page) + host->cur_sg->offset;
-}
-
-static inline int sdhci_next_sg(struct sdhci_host* host)
-{
-	/*
-	 * Skip to next SG entry.
-	 */
-	host->cur_sg++;
-	host->num_sg--;
-
-	/*
-	 * Any entries left?
-	 */
-	if (host->num_sg > 0) {
-		host->offset = 0;
-		host->remain = host->cur_sg->length;
-	}
-
-	return host->num_sg;
-}
-
-static void sdhci_read_block_pio(struct sdhci_host *host)
-{
-	int blksize, chunk_remain;
-	u32 data;
-	char *buffer;
-	int size;
-
-	DBG("PIO reading\n");
-
-	blksize = host->data->blksz;
-	chunk_remain = 0;
-	data = 0;
-
-	buffer = sdhci_sg_to_buffer(host) + host->offset;
-
-	while (blksize) {
-		if (chunk_remain == 0) {
-			data = readl(host->ioaddr + SDHCI_BUFFER);
-			chunk_remain = min(blksize, 4);
-		}
-
-		size = min(host->size, host->remain);
-		size = min(size, chunk_remain);
-
-		chunk_remain -= size;
-		blksize -= size;
-		host->offset += size;
-		host->remain -= size;
-		host->size -= size;
-		while (size) {
-			*buffer = data & 0xFF;
-			buffer++;
-			data >>= 8;
-			size--;
-		}
-
-		if (host->remain == 0) {
-			if (sdhci_next_sg(host) == 0) {
-				BUG_ON(blksize != 0);
-				return;
-			}
-			buffer = sdhci_sg_to_buffer(host);
-		}
-	}
-}
-
-static void sdhci_write_block_pio(struct sdhci_host *host)
-{
-	int blksize, chunk_remain;
-	u32 data;
-	char *buffer;
-	int bytes, size;
-
-	DBG("PIO writing\n");
-
-	blksize = host->data->blksz;
-	chunk_remain = 4;
-	data = 0;
-
-	bytes = 0;
-	buffer = sdhci_sg_to_buffer(host) + host->offset;
-
-	while (blksize) {
-		size = min(host->size, host->remain);
-		size = min(size, chunk_remain);
-
-		chunk_remain -= size;
-		blksize -= size;
-		host->offset += size;
-		host->remain -= size;
-		host->size -= size;
-		while (size) {
-			data >>= 8;
-			data |= (u32)*buffer << 24;
-			buffer++;
-			size--;
-		}
-
-		if (chunk_remain == 0) {
-			writel(data, host->ioaddr + SDHCI_BUFFER);
-			chunk_remain = min(blksize, 4);
-		}
-
-		if (host->remain == 0) {
-			if (sdhci_next_sg(host) == 0) {
-				BUG_ON(blksize != 0);
-				return;
-			}
-			buffer = sdhci_sg_to_buffer(host);
-		}
-	}
-}
-
-static void sdhci_transfer_pio(struct sdhci_host *host)
-{
-	u32 mask;
-
-	BUG_ON(!host->data);
-
-	if (host->size == 0)
-		return;
-
-	if (host->data->flags & MMC_DATA_READ)
-		mask = SDHCI_DATA_AVAILABLE;
-	else
-		mask = SDHCI_SPACE_AVAILABLE;
-
-	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
-		if (host->data->flags & MMC_DATA_READ)
-			sdhci_read_block_pio(host);
-		else
-			sdhci_write_block_pio(host);
-
-		if (host->size == 0)
-			break;
-
-		BUG_ON(host->num_sg == 0);
-	}
-
-	DBG("PIO transfer complete.\n");
-}
-
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
-{
-	u8 count;
-	unsigned target_timeout, current_timeout;
-
-	WARN_ON(host->data);
-
-	if (data == NULL)
-		return;
-
-	DBG("blksz %04x blks %04x flags %08x\n",
-		data->blksz, data->blocks, data->flags);
-	DBG("tsac %d ms nsac %d clk\n",
-		data->timeout_ns / 1000000, data->timeout_clks);
-
-	/* Sanity checks */
-	BUG_ON(data->blksz * data->blocks > 524288);
-	BUG_ON(data->blksz > host->mmc->max_blk_size);
-	BUG_ON(data->blocks > 65535);
-
-	/* timeout in us */
-	target_timeout = data->timeout_ns / 1000 +
-		data->timeout_clks / host->clock;
-
-	/*
-	 * Figure out needed cycles.
-	 * We do this in steps in order to fit inside a 32 bit int.
-	 * The first step is the minimum timeout, which will have a
-	 * minimum resolution of 6 bits:
-	 * (1) 2^13*1000 > 2^22,
-	 * (2) host->timeout_clk < 2^16
-	 *     =>
-	 *     (1) / (2) > 2^6
-	 */
-	count = 0;
-	current_timeout = (1 << 13) * 1000 / host->timeout_clk;
-	while (current_timeout < target_timeout) {
-		count++;
-		current_timeout <<= 1;
-		if (count >= 0xF)
-			break;
-	}
-
-	if (count >= 0xF) {
-		printk(KERN_WARNING "%s: Too large timeout requested!\n",
-			mmc_hostname(host->mmc));
-		count = 0xE;
-	}
-
-	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
-
-	if (host->flags & SDHCI_USE_DMA) {
-		int count;
-
-		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
-			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
-		BUG_ON(count != 1);
-
-		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
-	} else {
-		host->size = data->blksz * data->blocks;
-
-		host->cur_sg = data->sg;
-		host->num_sg = data->sg_len;
-
-		host->offset = 0;
-		host->remain = host->cur_sg->length;
-	}
-
-	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
-	writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
-		host->ioaddr + SDHCI_BLOCK_SIZE);
-	writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
-}
-
-static void sdhci_set_transfer_mode(struct sdhci_host *host,
-	struct mmc_data *data)
-{
-	u16 mode;
-
-	WARN_ON(host->data);
-
-	if (data == NULL)
-		return;
-
-	mode = SDHCI_TRNS_BLK_CNT_EN;
-	if (data->blocks > 1)
-		mode |= SDHCI_TRNS_MULTI;
-	if (data->flags & MMC_DATA_READ)
-		mode |= SDHCI_TRNS_READ;
-	if (host->flags & SDHCI_USE_DMA)
-		mode |= SDHCI_TRNS_DMA;
-
-	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
-}
-
-static void sdhci_finish_data(struct sdhci_host *host)
-{
-	struct mmc_data *data;
-	u16 blocks;
-
-	BUG_ON(!host->data);
-
-	data = host->data;
-	host->data = NULL;
-
-	if (host->flags & SDHCI_USE_DMA) {
-		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
-			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
-	}
-
-	/*
-	 * Controller doesn't count down when in single block mode.
-	 */
-	if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
-		blocks = 0;
-	else
-		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
-	data->bytes_xfered = data->blksz * (data->blocks - blocks);
-
-	if ((data->error == MMC_ERR_NONE) && blocks) {
-		printk(KERN_ERR "%s: Controller signalled completion even "
-			"though there were blocks left.\n",
-			mmc_hostname(host->mmc));
-		data->error = MMC_ERR_FAILED;
-	} else if (host->size != 0) {
-		printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
-			mmc_hostname(host->mmc), host->size);
-		data->error = MMC_ERR_FAILED;
-	}
-
-	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
-	if (data->stop) {
-		/*
-		 * The controller needs a reset of internal state machines
-		 * upon error conditions.
-		 */
-		if (data->error != MMC_ERR_NONE) {
-			sdhci_reset(host, SDHCI_RESET_CMD);
-			sdhci_reset(host, SDHCI_RESET_DATA);
-		}
-
-		sdhci_send_command(host, data->stop);
-	} else
-		tasklet_schedule(&host->finish_tasklet);
-}
-
-static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
-{
-	int flags;
-	u32 mask;
-	unsigned long timeout;
-
-	WARN_ON(host->cmd);
-
-	DBG("Sending cmd (%x)\n", cmd->opcode);
-
-	/* Wait max 10 ms */
-	timeout = 10;
-
-	mask = SDHCI_CMD_INHIBIT;
-	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
-		mask |= SDHCI_DATA_INHIBIT;
-
-	/* We shouldn't wait for data inihibit for stop commands, even
-	   though they might use busy signaling */
-	if (host->mrq->data && (cmd == host->mrq->data->stop))
-		mask &= ~SDHCI_DATA_INHIBIT;
-
-	while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
-		if (timeout == 0) {
-			printk(KERN_ERR "%s: Controller never released "
-				"inhibit bit(s).\n", mmc_hostname(host->mmc));
-			sdhci_dumpregs(host);
-			cmd->error = MMC_ERR_FAILED;
-			tasklet_schedule(&host->finish_tasklet);
-			return;
-		}
-		timeout--;
-		mdelay(1);
-	}
-
-	mod_timer(&host->timer, jiffies + 10 * HZ);
-
-	host->cmd = cmd;
-
-	sdhci_prepare_data(host, cmd->data);
-
-	writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
-
-	sdhci_set_transfer_mode(host, cmd->data);
-
-	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
-		printk(KERN_ERR "%s: Unsupported response type!\n",
-			mmc_hostname(host->mmc));
-		cmd->error = MMC_ERR_INVALID;
-		tasklet_schedule(&host->finish_tasklet);
-		return;
-	}
-
-	if (!(cmd->flags & MMC_RSP_PRESENT))
-		flags = SDHCI_CMD_RESP_NONE;
-	else if (cmd->flags & MMC_RSP_136)
-		flags = SDHCI_CMD_RESP_LONG;
-	else if (cmd->flags & MMC_RSP_BUSY)
-		flags = SDHCI_CMD_RESP_SHORT_BUSY;
-	else
-		flags = SDHCI_CMD_RESP_SHORT;
-
-	if (cmd->flags & MMC_RSP_CRC)
-		flags |= SDHCI_CMD_CRC;
-	if (cmd->flags & MMC_RSP_OPCODE)
-		flags |= SDHCI_CMD_INDEX;
-	if (cmd->data)
-		flags |= SDHCI_CMD_DATA;
-
-	writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
-		host->ioaddr + SDHCI_COMMAND);
-}
-
-static void sdhci_finish_command(struct sdhci_host *host)
-{
-	int i;
-
-	BUG_ON(host->cmd == NULL);
-
-	if (host->cmd->flags & MMC_RSP_PRESENT) {
-		if (host->cmd->flags & MMC_RSP_136) {
-			/* CRC is stripped so we need to do some shifting. */
-			for (i = 0;i < 4;i++) {
-				host->cmd->resp[i] = readl(host->ioaddr +
-					SDHCI_RESPONSE + (3-i)*4) << 8;
-				if (i != 3)
-					host->cmd->resp[i] |=
-						readb(host->ioaddr +
-						SDHCI_RESPONSE + (3-i)*4-1);
-			}
-		} else {
-			host->cmd->resp[0] = readl(host->ioaddr + SDHCI_RESPONSE);
-		}
-	}
-
-	host->cmd->error = MMC_ERR_NONE;
-
-	DBG("Ending cmd (%x)\n", host->cmd->opcode);
-
-	if (host->cmd->data)
-		host->data = host->cmd->data;
-	else
-		tasklet_schedule(&host->finish_tasklet);
-
-	host->cmd = NULL;
-}
-
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-	int div;
-	u16 clk;
-	unsigned long timeout;
-
-	if (clock == host->clock)
-		return;
-
-	writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-	if (clock == 0)
-		goto out;
-
-	for (div = 1;div < 256;div *= 2) {
-		if ((host->max_clk / div) <= clock)
-			break;
-	}
-	div >>= 1;
-
-	clk = div << SDHCI_DIVIDER_SHIFT;
-	clk |= SDHCI_CLOCK_INT_EN;
-	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-	/* Wait max 10 ms */
-	timeout = 10;
-	while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
-		& SDHCI_CLOCK_INT_STABLE)) {
-		if (timeout == 0) {
-			printk(KERN_ERR "%s: Internal clock never "
-				"stabilised.\n", mmc_hostname(host->mmc));
-			sdhci_dumpregs(host);
-			return;
-		}
-		timeout--;
-		mdelay(1);
-	}
-
-	clk |= SDHCI_CLOCK_CARD_EN;
-	writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
-out:
-	host->clock = clock;
-}
-
-static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
-{
-	u8 pwr;
-
-	if (host->power == power)
-		return;
-
-	if (power == (unsigned short)-1) {
-		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-		goto out;
-	}
-
-	/*
-	 * Spec says that we should clear the power reg before setting
-	 * a new value. Some controllers don't seem to like this though.
-	 */
-	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
-		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
-	pwr = SDHCI_POWER_ON;
-
-	switch (power) {
-	case MMC_VDD_170:
-	case MMC_VDD_180:
-	case MMC_VDD_190:
-		pwr |= SDHCI_POWER_180;
-		break;
-	case MMC_VDD_290:
-	case MMC_VDD_300:
-	case MMC_VDD_310:
-		pwr |= SDHCI_POWER_300;
-		break;
-	case MMC_VDD_320:
-	case MMC_VDD_330:
-	case MMC_VDD_340:
-		pwr |= SDHCI_POWER_330;
-		break;
-	default:
-		BUG();
-	}
-
-	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
-
-out:
-	host->power = power;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * MMC callbacks                                                             *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-
-	host = mmc_priv(mmc);
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	WARN_ON(host->mrq != NULL);
-
-	sdhci_activate_led(host);
-
-	host->mrq = mrq;
-
-	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-		host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-		tasklet_schedule(&host->finish_tasklet);
-	} else
-		sdhci_send_command(host, mrq->cmd);
-
-	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-	u8 ctrl;
-
-	host = mmc_priv(mmc);
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	/*
-	 * Reset the chip on each power off.
-	 * Should clear out any weird states.
-	 */
-	if (ios->power_mode == MMC_POWER_OFF) {
-		writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-		sdhci_init(host);
-	}
-
-	sdhci_set_clock(host, ios->clock);
-
-	if (ios->power_mode == MMC_POWER_OFF)
-		sdhci_set_power(host, -1);
-	else
-		sdhci_set_power(host, ios->vdd);
-
-	ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
-
-	if (ios->bus_width == MMC_BUS_WIDTH_4)
-		ctrl |= SDHCI_CTRL_4BITBUS;
-	else
-		ctrl &= ~SDHCI_CTRL_4BITBUS;
-
-	if (ios->timing == MMC_TIMING_SD_HS)
-		ctrl |= SDHCI_CTRL_HISPD;
-	else
-		ctrl &= ~SDHCI_CTRL_HISPD;
-
-	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-
-	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-	int present;
-
-	host = mmc_priv(mmc);
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
-
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	return !(present & SDHCI_WRITE_PROTECT);
-}
-
-static const struct mmc_host_ops sdhci_ops = {
-	.request	= sdhci_request,
-	.set_ios	= sdhci_set_ios,
-	.get_ro		= sdhci_get_ro,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Tasklets                                                                  *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-
-	host = (struct sdhci_host*)param;
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-		if (host->mrq) {
-			printk(KERN_ERR "%s: Card removed during transfer!\n",
-				mmc_hostname(host->mmc));
-			printk(KERN_ERR "%s: Resetting controller.\n",
-				mmc_hostname(host->mmc));
-
-			sdhci_reset(host, SDHCI_RESET_CMD);
-			sdhci_reset(host, SDHCI_RESET_DATA);
-
-			host->mrq->cmd->error = MMC_ERR_FAILED;
-			tasklet_schedule(&host->finish_tasklet);
-		}
-	}
-
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-}
-
-static void sdhci_tasklet_finish(unsigned long param)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-	struct mmc_request *mrq;
-
-	host = (struct sdhci_host*)param;
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	del_timer(&host->timer);
-
-	mrq = host->mrq;
-
-	DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
-	/*
-	 * The controller needs a reset of internal state machines
-	 * upon error conditions.
-	 */
-	if ((mrq->cmd->error != MMC_ERR_NONE) ||
-		(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
-		(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
-
-		/* Some controllers need this kick or reset won't work here */
-		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
-			unsigned int clock;
-
-			/* This is to force an update */
-			clock = host->clock;
-			host->clock = 0;
-			sdhci_set_clock(host, clock);
-		}
-
-		/* Spec says we should do both at the same time, but Ricoh
-		   controllers do not like that. */
-		sdhci_reset(host, SDHCI_RESET_CMD);
-		sdhci_reset(host, SDHCI_RESET_DATA);
-	}
-
-	host->mrq = NULL;
-	host->cmd = NULL;
-	host->data = NULL;
-
-	sdhci_deactivate_led(host);
-
-	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
-
-	mmc_request_done(host->mmc, mrq);
-}
-
-static void sdhci_timeout_timer(unsigned long data)
-{
-	struct sdhci_host *host;
-	unsigned long flags;
-
-	host = (struct sdhci_host*)data;
-
-	spin_lock_irqsave(&host->lock, flags);
-
-	if (host->mrq) {
-		printk(KERN_ERR "%s: Timeout waiting for hardware "
-			"interrupt.\n", mmc_hostname(host->mmc));
-		sdhci_dumpregs(host);
-
-		if (host->data) {
-			host->data->error = MMC_ERR_TIMEOUT;
-			sdhci_finish_data(host);
-		} else {
-			if (host->cmd)
-				host->cmd->error = MMC_ERR_TIMEOUT;
-			else
-				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
-
-			tasklet_schedule(&host->finish_tasklet);
-		}
-	}
-
-	mmiowb();
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Interrupt handling                                                        *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
-{
-	BUG_ON(intmask == 0);
-
-	if (!host->cmd) {
-		printk(KERN_ERR "%s: Got command interrupt even though no "
-			"command operation was in progress.\n",
-			mmc_hostname(host->mmc));
-		sdhci_dumpregs(host);
-		return;
-	}
-
-	if (intmask & SDHCI_INT_RESPONSE)
-		sdhci_finish_command(host);
-	else {
-		if (intmask & SDHCI_INT_TIMEOUT)
-			host->cmd->error = MMC_ERR_TIMEOUT;
-		else if (intmask & SDHCI_INT_CRC)
-			host->cmd->error = MMC_ERR_BADCRC;
-		else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
-			host->cmd->error = MMC_ERR_FAILED;
-		else
-			host->cmd->error = MMC_ERR_INVALID;
-
-		tasklet_schedule(&host->finish_tasklet);
-	}
-}
-
-static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
-{
-	BUG_ON(intmask == 0);
-
-	if (!host->data) {
-		/*
-		 * A data end interrupt is sent together with the response
-		 * for the stop command.
-		 */
-		if (intmask & SDHCI_INT_DATA_END)
-			return;
-
-		printk(KERN_ERR "%s: Got data interrupt even though no "
-			"data operation was in progress.\n",
-			mmc_hostname(host->mmc));
-		sdhci_dumpregs(host);
-
-		return;
-	}
-
-	if (intmask & SDHCI_INT_DATA_TIMEOUT)
-		host->data->error = MMC_ERR_TIMEOUT;
-	else if (intmask & SDHCI_INT_DATA_CRC)
-		host->data->error = MMC_ERR_BADCRC;
-	else if (intmask & SDHCI_INT_DATA_END_BIT)
-		host->data->error = MMC_ERR_FAILED;
-
-	if (host->data->error != MMC_ERR_NONE)
-		sdhci_finish_data(host);
-	else {
-		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
-			sdhci_transfer_pio(host);
-
-		if (intmask & SDHCI_INT_DATA_END)
-			sdhci_finish_data(host);
-	}
-}
-
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
-{
-	irqreturn_t result;
-	struct sdhci_host* host = dev_id;
-	u32 intmask;
-
-	spin_lock(&host->lock);
-
-	intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
-
-	if (!intmask || intmask == 0xffffffff) {
-		result = IRQ_NONE;
-		goto out;
-	}
-
-	DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
-
-	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-		writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
-			host->ioaddr + SDHCI_INT_STATUS);
-		tasklet_schedule(&host->card_tasklet);
-	}
-
-	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
-
-	if (intmask & SDHCI_INT_CMD_MASK) {
-		writel(intmask & SDHCI_INT_CMD_MASK,
-			host->ioaddr + SDHCI_INT_STATUS);
-		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-	}
-
-	if (intmask & SDHCI_INT_DATA_MASK) {
-		writel(intmask & SDHCI_INT_DATA_MASK,
-			host->ioaddr + SDHCI_INT_STATUS);
-		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-	}
-
-	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
-
-	if (intmask & SDHCI_INT_BUS_POWER) {
-		printk(KERN_ERR "%s: Card is consuming too much power!\n",
-			mmc_hostname(host->mmc));
-		writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
-	}
-
-	intmask &= SDHCI_INT_BUS_POWER;
-
-	if (intmask) {
-		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
-			mmc_hostname(host->mmc), intmask);
-		sdhci_dumpregs(host);
-
-		writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
-	}
-
-	result = IRQ_HANDLED;
-
-	mmiowb();
-out:
-	spin_unlock(&host->lock);
-
-	return result;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Suspend/resume                                                            *
- *                                                                           *
-\*****************************************************************************/
-
-#ifdef CONFIG_PM
-
-static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
-{
-	struct sdhci_chip *chip;
-	int i, ret;
-
-	chip = pci_get_drvdata(pdev);
-	if (!chip)
-		return 0;
-
-	DBG("Suspending...\n");
-
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
-		if (ret) {
-			for (i--;i >= 0;i--)
-				mmc_resume_host(chip->hosts[i]->mmc);
-			return ret;
-		}
-	}
-
-	pci_save_state(pdev);
-	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
-	}
-
-	pci_disable_device(pdev);
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
-	return 0;
-}
-
-static int sdhci_resume (struct pci_dev *pdev)
-{
-	struct sdhci_chip *chip;
-	int i, ret;
-
-	chip = pci_get_drvdata(pdev);
-	if (!chip)
-		return 0;
-
-	DBG("Resuming...\n");
-
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
-	ret = pci_enable_device(pdev);
-	if (ret)
-		return ret;
-
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
-			pci_set_master(pdev);
-		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
-			IRQF_SHARED, chip->hosts[i]->slot_descr,
-			chip->hosts[i]);
-		if (ret)
-			return ret;
-		sdhci_init(chip->hosts[i]);
-		mmiowb();
-		ret = mmc_resume_host(chip->hosts[i]->mmc);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-#else /* CONFIG_PM */
-
-#define sdhci_suspend NULL
-#define sdhci_resume NULL
-
-#endif /* CONFIG_PM */
-
-/*****************************************************************************\
- *                                                                           *
- * Device probing/removal                                                    *
- *                                                                           *
-\*****************************************************************************/
-
-static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
-{
-	int ret;
-	unsigned int version;
-	struct sdhci_chip *chip;
-	struct mmc_host *mmc;
-	struct sdhci_host *host;
-
-	u8 first_bar;
-	unsigned int caps;
-
-	chip = pci_get_drvdata(pdev);
-	BUG_ON(!chip);
-
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
-	if (ret)
-		return ret;
-
-	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
-
-	if (first_bar > 5) {
-		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
-		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
-		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
-			"You may experience problems.\n");
-	}
-
-	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
-		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
-		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
-		return -ENODEV;
-	}
-
-	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
-	if (!mmc)
-		return -ENOMEM;
-
-	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);
-	host->irq = pdev->irq;
-
-	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
-
-	snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
-
-	ret = pci_request_region(pdev, host->bar, host->slot_descr);
-	if (ret)
-		goto free;
-
-	host->ioaddr = ioremap_nocache(host->addr,
-		pci_resource_len(pdev, host->bar));
-	if (!host->ioaddr) {
-		ret = -ENOMEM;
-		goto release;
-	}
-
-	sdhci_reset(host, SDHCI_RESET_ALL);
-
-	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
-	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
-	if (version != 0) {
-		printk(KERN_ERR "%s: Unknown controller version (%d). "
-			"You may experience problems.\n", host->slot_descr,
-			version);
-	}
-
-	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
-
-	if (debug_nodma)
-		DBG("DMA forced off\n");
-	else if (debug_forcedma) {
-		DBG("DMA forced on\n");
-		host->flags |= SDHCI_USE_DMA;
-	} else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
-		host->flags |= SDHCI_USE_DMA;
-	else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
-		DBG("Controller doesn't have DMA interface\n");
-	else if (!(caps & SDHCI_CAN_DO_DMA))
-		DBG("Controller doesn't have DMA capability\n");
-	else
-		host->flags |= SDHCI_USE_DMA;
-
-	if (host->flags & SDHCI_USE_DMA) {
-		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
-			printk(KERN_WARNING "%s: No suitable DMA available. "
-				"Falling back to PIO.\n", host->slot_descr);
-			host->flags &= ~SDHCI_USE_DMA;
-		}
-	}
-
-	if (host->flags & SDHCI_USE_DMA)
-		pci_set_master(pdev);
-	else /* XXX: Hack to get MMC layer to avoid highmem */
-		pdev->dma_mask = 0;
-
-	host->max_clk =
-		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
-	if (host->max_clk == 0) {
-		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
-			"frequency.\n", host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	host->max_clk *= 1000000;
-
-	host->timeout_clk =
-		(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
-	if (host->timeout_clk == 0) {
-		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
-			"frequency.\n", host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
-		host->timeout_clk *= 1000;
-
-	/*
-	 * Set host parameters.
-	 */
-	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_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
-
-	if (caps & SDHCI_CAN_DO_HISPD)
-		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
-
-	mmc->ocr_avail = 0;
-	if (caps & SDHCI_CAN_VDD_330)
-		mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
-	if (caps & SDHCI_CAN_VDD_300)
-		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
-	if (caps & SDHCI_CAN_VDD_180)
-		mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
-
-	if (mmc->ocr_avail == 0) {
-		printk(KERN_ERR "%s: Hardware doesn't report any "
-			"support voltages.\n", host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-
-	spin_lock_init(&host->lock);
-
-	/*
-	 * Maximum number of segments. Hardware cannot do scatter lists.
-	 */
-	if (host->flags & SDHCI_USE_DMA)
-		mmc->max_hw_segs = 1;
-	else
-		mmc->max_hw_segs = 16;
-	mmc->max_phys_segs = 16;
-
-	/*
-	 * Maximum number of sectors in one transfer. Limited by DMA boundary
-	 * size (512KiB).
-	 */
-	mmc->max_req_size = 524288;
-
-	/*
-	 * Maximum segment size. Could be one segment with the maximum number
-	 * of bytes.
-	 */
-	mmc->max_seg_size = mmc->max_req_size;
-
-	/*
-	 * Maximum block size. This varies from controller to controller and
-	 * is specified in the capabilities register.
-	 */
-	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
-	if (mmc->max_blk_size >= 3) {
-		printk(KERN_ERR "%s: Invalid maximum block size.\n",
-			host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	mmc->max_blk_size = 512 << mmc->max_blk_size;
-
-	/*
-	 * Maximum block count.
-	 */
-	mmc->max_blk_count = 65535;
-
-	/*
-	 * Init tasklets.
-	 */
-	tasklet_init(&host->card_tasklet,
-		sdhci_tasklet_card, (unsigned long)host);
-	tasklet_init(&host->finish_tasklet,
-		sdhci_tasklet_finish, (unsigned 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);
-	if (ret)
-		goto untasklet;
-
-	sdhci_init(host);
-
-#ifdef CONFIG_MMC_DEBUG
-	sdhci_dumpregs(host);
-#endif
-
-	mmiowb();
-
-	mmc_add_host(mmc);
-
-	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
-		host->addr, host->irq,
-		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
-
-	return 0;
-
-untasklet:
-	tasklet_kill(&host->card_tasklet);
-	tasklet_kill(&host->finish_tasklet);
-unmap:
-	iounmap(host->ioaddr);
-release:
-	pci_release_region(pdev, host->bar);
-free:
-	mmc_free_host(mmc);
-
-	return ret;
-}
-
-static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
-{
-	struct sdhci_chip *chip;
-	struct mmc_host *mmc;
-	struct sdhci_host *host;
-
-	chip = pci_get_drvdata(pdev);
-	host = chip->hosts[slot];
-	mmc = host->mmc;
-
-	chip->hosts[slot] = NULL;
-
-	mmc_remove_host(mmc);
-
-	sdhci_reset(host, SDHCI_RESET_ALL);
-
-	free_irq(host->irq, host);
-
-	del_timer_sync(&host->timer);
-
-	tasklet_kill(&host->card_tasklet);
-	tasklet_kill(&host->finish_tasklet);
-
-	iounmap(host->ioaddr);
-
-	pci_release_region(pdev, host->bar);
-
-	mmc_free_host(mmc);
-}
-
-static int __devinit sdhci_probe(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	int ret, i;
-	u8 slots, rev;
-	struct sdhci_chip *chip;
-
-	BUG_ON(pdev == NULL);
-	BUG_ON(ent == NULL);
-
-	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
-
-	printk(KERN_INFO DRIVER_NAME
-		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
-		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
-		(int)rev);
-
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
-	if (ret)
-		return ret;
-
-	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
-	DBG("found %d slot(s)\n", slots);
-	if (slots == 0)
-		return -ENODEV;
-
-	ret = pci_enable_device(pdev);
-	if (ret)
-		return ret;
-
-	chip = kzalloc(sizeof(struct sdhci_chip) +
-		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
-	if (!chip) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	chip->pdev = pdev;
-	chip->quirks = ent->driver_data;
-
-	if (debug_quirks)
-		chip->quirks = debug_quirks;
-
-	chip->num_slots = slots;
-	pci_set_drvdata(pdev, chip);
-
-	for (i = 0;i < slots;i++) {
-		ret = sdhci_probe_slot(pdev, i);
-		if (ret) {
-			for (i--;i >= 0;i--)
-				sdhci_remove_slot(pdev, i);
-			goto free;
-		}
-	}
-
-	return 0;
-
-free:
-	pci_set_drvdata(pdev, NULL);
-	kfree(chip);
-
-err:
-	pci_disable_device(pdev);
-	return ret;
-}
-
-static void __devexit sdhci_remove(struct pci_dev *pdev)
-{
-	int i;
-	struct sdhci_chip *chip;
-
-	chip = pci_get_drvdata(pdev);
-
-	if (chip) {
-		for (i = 0;i < chip->num_slots;i++)
-			sdhci_remove_slot(pdev, i);
-
-		pci_set_drvdata(pdev, NULL);
-
-		kfree(chip);
-	}
-
-	pci_disable_device(pdev);
-}
-
-static struct pci_driver sdhci_driver = {
-	.name = 	DRIVER_NAME,
-	.id_table =	pci_ids,
-	.probe = 	sdhci_probe,
-	.remove =	__devexit_p(sdhci_remove),
-	.suspend =	sdhci_suspend,
-	.resume	=	sdhci_resume,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Driver init/exit                                                          *
- *                                                                           *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
-	printk(KERN_INFO DRIVER_NAME
-		": Secure Digital Host Controller Interface driver\n");
-	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
-	return pci_register_driver(&sdhci_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
-	DBG("Exiting\n");
-
-	pci_unregister_driver(&sdhci_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-module_param(debug_nodma, uint, 0444);
-module_param(debug_forcedma, uint, 0444);
-module_param(debug_quirks, uint, 0444);
-
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
deleted file mode 100644
index e324f0a..0000000
--- a/drivers/mmc/sdhci.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
- *
- *  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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-/*
- * PCI registers
- */
-
-#define PCI_SDHCI_IFPIO			0x00
-#define PCI_SDHCI_IFDMA			0x01
-#define PCI_SDHCI_IFVENDOR		0x02
-
-#define PCI_SLOT_INFO			0x40	/* 8 bits */
-#define  PCI_SLOT_INFO_SLOTS(x)		((x >> 4) & 7)
-#define  PCI_SLOT_INFO_FIRST_BAR_MASK	0x07
-
-/*
- * Controller registers
- */
-
-#define SDHCI_DMA_ADDRESS	0x00
-
-#define SDHCI_BLOCK_SIZE	0x04
-#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
-
-#define SDHCI_BLOCK_COUNT	0x06
-
-#define SDHCI_ARGUMENT		0x08
-
-#define SDHCI_TRANSFER_MODE	0x0C
-#define  SDHCI_TRNS_DMA		0x01
-#define  SDHCI_TRNS_BLK_CNT_EN	0x02
-#define  SDHCI_TRNS_ACMD12	0x04
-#define  SDHCI_TRNS_READ	0x10
-#define  SDHCI_TRNS_MULTI	0x20
-
-#define SDHCI_COMMAND		0x0E
-#define  SDHCI_CMD_RESP_MASK	0x03
-#define  SDHCI_CMD_CRC		0x08
-#define  SDHCI_CMD_INDEX	0x10
-#define  SDHCI_CMD_DATA		0x20
-
-#define  SDHCI_CMD_RESP_NONE	0x00
-#define  SDHCI_CMD_RESP_LONG	0x01
-#define  SDHCI_CMD_RESP_SHORT	0x02
-#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
-
-#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
-
-#define SDHCI_RESPONSE		0x10
-
-#define SDHCI_BUFFER		0x20
-
-#define SDHCI_PRESENT_STATE	0x24
-#define  SDHCI_CMD_INHIBIT	0x00000001
-#define  SDHCI_DATA_INHIBIT	0x00000002
-#define  SDHCI_DOING_WRITE	0x00000100
-#define  SDHCI_DOING_READ	0x00000200
-#define  SDHCI_SPACE_AVAILABLE	0x00000400
-#define  SDHCI_DATA_AVAILABLE	0x00000800
-#define  SDHCI_CARD_PRESENT	0x00010000
-#define  SDHCI_WRITE_PROTECT	0x00080000
-
-#define SDHCI_HOST_CONTROL 	0x28
-#define  SDHCI_CTRL_LED		0x01
-#define  SDHCI_CTRL_4BITBUS	0x02
-#define  SDHCI_CTRL_HISPD	0x04
-
-#define SDHCI_POWER_CONTROL	0x29
-#define  SDHCI_POWER_ON		0x01
-#define  SDHCI_POWER_180	0x0A
-#define  SDHCI_POWER_300	0x0C
-#define  SDHCI_POWER_330	0x0E
-
-#define SDHCI_BLOCK_GAP_CONTROL	0x2A
-
-#define SDHCI_WALK_UP_CONTROL	0x2B
-
-#define SDHCI_CLOCK_CONTROL	0x2C
-#define  SDHCI_DIVIDER_SHIFT	8
-#define  SDHCI_CLOCK_CARD_EN	0x0004
-#define  SDHCI_CLOCK_INT_STABLE	0x0002
-#define  SDHCI_CLOCK_INT_EN	0x0001
-
-#define SDHCI_TIMEOUT_CONTROL	0x2E
-
-#define SDHCI_SOFTWARE_RESET	0x2F
-#define  SDHCI_RESET_ALL	0x01
-#define  SDHCI_RESET_CMD	0x02
-#define  SDHCI_RESET_DATA	0x04
-
-#define SDHCI_INT_STATUS	0x30
-#define SDHCI_INT_ENABLE	0x34
-#define SDHCI_SIGNAL_ENABLE	0x38
-#define  SDHCI_INT_RESPONSE	0x00000001
-#define  SDHCI_INT_DATA_END	0x00000002
-#define  SDHCI_INT_DMA_END	0x00000008
-#define  SDHCI_INT_SPACE_AVAIL	0x00000010
-#define  SDHCI_INT_DATA_AVAIL	0x00000020
-#define  SDHCI_INT_CARD_INSERT	0x00000040
-#define  SDHCI_INT_CARD_REMOVE	0x00000080
-#define  SDHCI_INT_CARD_INT	0x00000100
-#define  SDHCI_INT_TIMEOUT	0x00010000
-#define  SDHCI_INT_CRC		0x00020000
-#define  SDHCI_INT_END_BIT	0x00040000
-#define  SDHCI_INT_INDEX	0x00080000
-#define  SDHCI_INT_DATA_TIMEOUT	0x00100000
-#define  SDHCI_INT_DATA_CRC	0x00200000
-#define  SDHCI_INT_DATA_END_BIT	0x00400000
-#define  SDHCI_INT_BUS_POWER	0x00800000
-#define  SDHCI_INT_ACMD12ERR	0x01000000
-
-#define  SDHCI_INT_NORMAL_MASK	0x00007FFF
-#define  SDHCI_INT_ERROR_MASK	0xFFFF8000
-
-#define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
-		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
-#define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
-		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
-		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
-		SDHCI_INT_DATA_END_BIT)
-
-#define SDHCI_ACMD12_ERR	0x3C
-
-/* 3E-3F reserved */
-
-#define SDHCI_CAPABILITIES	0x40
-#define  SDHCI_TIMEOUT_CLK_MASK	0x0000003F
-#define  SDHCI_TIMEOUT_CLK_SHIFT 0
-#define  SDHCI_TIMEOUT_CLK_UNIT	0x00000080
-#define  SDHCI_CLOCK_BASE_MASK	0x00003F00
-#define  SDHCI_CLOCK_BASE_SHIFT	8
-#define  SDHCI_MAX_BLOCK_MASK	0x00030000
-#define  SDHCI_MAX_BLOCK_SHIFT  16
-#define  SDHCI_CAN_DO_HISPD	0x00200000
-#define  SDHCI_CAN_DO_DMA	0x00400000
-#define  SDHCI_CAN_VDD_330	0x01000000
-#define  SDHCI_CAN_VDD_300	0x02000000
-#define  SDHCI_CAN_VDD_180	0x04000000
-
-/* 44-47 reserved for more caps */
-
-#define SDHCI_MAX_CURRENT	0x48
-
-/* 4C-4F reserved for more max current */
-
-/* 50-FB reserved */
-
-#define SDHCI_SLOT_INT_STATUS	0xFC
-
-#define SDHCI_HOST_VERSION	0xFE
-#define  SDHCI_VENDOR_VER_MASK	0xFF00
-#define  SDHCI_VENDOR_VER_SHIFT	8
-#define  SDHCI_SPEC_VER_MASK	0x00FF
-#define  SDHCI_SPEC_VER_SHIFT	0
-
-struct sdhci_chip;
-
-struct sdhci_host {
-	struct sdhci_chip	*chip;
-	struct mmc_host		*mmc;		/* MMC structure */
-
-	spinlock_t		lock;		/* Mutex */
-
-	int			flags;		/* Host attributes */
-#define SDHCI_USE_DMA		(1<<0)
-
-	unsigned int		max_clk;	/* Max possible freq (MHz) */
-	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
-
-	unsigned int		clock;		/* Current clock (MHz) */
-	unsigned short		power;		/* Current voltage */
-
-	struct mmc_request	*mrq;		/* Current request */
-	struct mmc_command	*cmd;		/* Current command */
-	struct mmc_data		*data;		/* Current data request */
-
-	struct scatterlist	*cur_sg;	/* We're working on this */
-	int			num_sg;		/* Entries left */
-	int			offset;		/* Offset into current sg */
-	int			remain;		/* Bytes left in current */
-
-	int			size;		/* Remaining bytes in transfer */
-
-	char			slot_descr[20];	/* Name for reservations */
-
-	int			irq;		/* Device IRQ */
-	int			bar;		/* PCI BAR index */
-	unsigned long		addr;		/* Bus address */
-	void __iomem *		ioaddr;		/* Mapped address */
-
-	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
-	struct tasklet_struct	finish_tasklet;
-
-	struct timer_list	timer;		/* Timer for timeouts */
-};
-
-struct sdhci_chip {
-	struct pci_dev		*pdev;
-
-	unsigned long		quirks;
-
-	int			num_slots;	/* Slots on controller */
-	struct sdhci_host	*hosts[0];	/* Pointers to hosts */
-};
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
deleted file mode 100644
index 0581d09..0000000
--- a/drivers/mmc/tifm_sd.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- *  tifm_sd.c - TI FlashMedia driver
- *
- *  Copyright (C) 2006 Alex Dubov <oakad@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.7"
-
-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   0x401d   /* set bits: CERR, EOFB, BRS, CB, EOC */
-#define TIFM_MMCSD_ERRMASK    0x01e0   /* set bits: 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 */
-	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;
-
-	struct tasklet_struct finish_tasklet;
-	struct timer_list     timer;
-	struct mmc_request    *req;
-	wait_queue_head_t     notify;
-
-	size_t                written_blocks;
-	size_t                buffer_size;
-	size_t                buffer_pos;
-
-};
-
-static char* tifm_sd_data_buffer(struct mmc_data *data)
-{
-	return page_address(data->sg->page) + data->sg->offset;
-}
-
-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;
-	char *buffer;
-
-	if (host_status & TIFM_MMCSD_BRS) {
-		/* in non-dma rx mode BRS fires when fifo is still not empty */
-		if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
-			buffer = tifm_sd_data_buffer(host->req->data);
-			while (host->buffer_size > host->buffer_pos) {
-				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
-				buffer[host->buffer_pos++] = t_val & 0xff;
-				buffer[host->buffer_pos++] =
-							(t_val >> 8) & 0xff;
-			}
-		}
-		return 1;
-	} else if (no_dma) {
-		buffer = tifm_sd_data_buffer(host->req->data);
-		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) {
-					buffer[host->buffer_pos++] =
-							t_val & 0xff;
-					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 = buffer[host->buffer_pos++]
-						& 0x00ff;
-					t_val |= ((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;
-	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_MMCSD_CERR)) {
-			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 (cmd->data->flags & MMC_DATA_WRITE) {
-				host->state = CARD;
-			} else {
-				if (no_dma) {
-					if (host->req->stop) {
-						tifm_sd_exec(host, host->req->stop);
-						host->state = SCMD;
-					} else {
-						host->state = READY;
-					}
-				} else {
-					host->state = FIFO;
-				}
-			}
-			goto change_state;
-		}
-		break;
-	case SCMD:
-		if (host_status & TIFM_MMCSD_EOC) {
-			tifm_sd_fetch_resp(host->req->stop, sock);
-			host->state = READY;
-			goto change_state;
-		}
-		break;
-	case CARD:
-		dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
-			host->written_blocks);
-		if (!(host->flags & CARD_BUSY)
-		    && (host->written_blocks == cmd->data->blocks)) {
-			if (no_dma) {
-				if (host->req->stop) {
-					tifm_sd_exec(host, host->req->stop);
-					host->state = SCMD;
-				} else {
-					host->state = READY;
-				}
-			} else {
-				host->state = FIFO;
-			}
-			goto change_state;
-		}
-		break;
-	case FIFO:
-		if (host->flags & FIFO_RDY) {
-			host->flags &= ~FIFO_RDY;
-			if (host->req->stop) {
-				tifm_sd_exec(host, host->req->stop);
-				host->state = SCMD;
-			} else {
-				host->state = READY;
-			}
-			goto change_state;
-		}
-		break;
-	case READY:
-		tasklet_schedule(&host->finish_tasklet);
-		return;
-	}
-
-}
-
-/* Called from interrupt handler */
-static void 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));
-
-	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->req)
-			goto done;
-
-		if (host_status & TIFM_MMCSD_ERRMASK) {
-			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->state == CARD
-					   || host->state == FIFO) {
-					host->req->cmd->error = error_code;
-					tifm_sd_exec(host, host->req->stop);
-					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);
-}
-
-static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
-{
-	struct tifm_dev *sock = host->dev;
-	unsigned int dest_cnt;
-
-	/* DMA style IO */
-	dev_dbg(&sock->dev, "setting dma for %d blocks\n",
-		cmd->data->blocks);
-	writel(TIFM_FIFO_INT_SETALL,
-	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-	writel(ilog2(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 /
-			((1000000000UL / host->clk_freq) * host->clk_div);
-
-	if (data_timeout < 0xffff) {
-		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
-		writel((~TIFM_MMCSD_DPE)
-		       & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
-	} else {
-		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);
-		writel(TIFM_MMCSD_DPE
-		       | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
-	}
-}
-
-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;
-	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-	host->state = CMD;
-	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(unsigned long 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);
-
-	del_timer(&host->timer);
-	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;
-
-	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_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;
-	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-	host->state = CMD;
-	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:
-	mrq->cmd->error = MMC_ERR_TIMEOUT;
-	mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd_nodma(unsigned long 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);
-
-	del_timer(&host->timer);
-	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_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);
-
-	mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_terminate(struct tifm_sd *host)
-{
-	struct tifm_dev *sock = host->dev;
-	unsigned long flags;
-
-	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-	mmiowb();
-	spin_lock_irqsave(&sock->lock, flags);
-	host->flags |= EJECT;
-	if (host->req) {
-		writel(TIFM_FIFO_INT_SETALL,
-		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-		tasklet_schedule(&host->finish_tasklet);
-	}
-	spin_unlock_irqrestore(&sock->lock, flags);
-}
-
-static void tifm_sd_abort(unsigned long data)
-{
-	struct tifm_sd *host = (struct tifm_sd*)data;
-
-	printk(KERN_ERR DRIVER_NAME
-	       ": card failed to respond for a long period of time");
-
-	tifm_sd_terminate(host);
-	tifm_eject(host->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->notify);
-	}
-
-	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 int tifm_sd_initialize_host(struct tifm_sd *host)
-{
-	int rc;
-	unsigned int host_status = 0;
-	struct tifm_dev *sock = host->dev;
-
-	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-	mmiowb();
-	host->clk_div = 61;
-	host->clk_freq = 20000000;
-	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
-	writel(host->clk_div | TIFM_MMCSD_POWER,
-	       sock->addr + SOCK_MMCSD_CONFIG);
-
-	/* wait up to 0.51 sec for reset */
-	for (rc = 2; rc <= 256; rc <<= 1) {
-		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
-			rc = 0;
-			break;
-		}
-		msleep(rc);
-	}
-
-	if (rc) {
-		printk(KERN_ERR DRIVER_NAME
-		       ": controller failed to reset\n");
-		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);
-
-	// command timeout fixed to 64 clocks for now
-	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
-	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-
-	/* INAB should take much less than reset */
-	for (rc = 1; rc <= 16; rc <<= 1) {
-		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
-		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
-		if (!(host_status & TIFM_MMCSD_ERRMASK)
-		    && (host_status & TIFM_MMCSD_EOC)) {
-			rc = 0;
-			break;
-		}
-		msleep(rc);
-	}
-
-	if (rc) {
-		printk(KERN_ERR DRIVER_NAME
-		       ": card not ready - probe failed on initialization\n");
-		return -ENODEV;
-	}
-
-	writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
-	       sock->addr + SOCK_MMCSD_INT_ENABLE);
-	mmiowb();
-
-	return 0;
-}
-
-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);
-	tifm_set_drvdata(sock, mmc);
-	host->dev = sock;
-	host->timeout_jiffies = msecs_to_jiffies(1000);
-
-	init_waitqueue_head(&host->notify);
-	tasklet_init(&host->finish_tasklet,
-		     no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
-		     (unsigned long)host);
-	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
-
-	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_CAP_MULTIWRITE;
-	mmc->f_min = 20000000 / 60;
-	mmc->f_max = 24000000;
-	mmc->max_hw_segs = 1;
-	mmc->max_phys_segs = 1;
-	// limited by DMA counter - it's safer to stick with
-	// block counter has 11 bits though
-	mmc->max_blk_count = 256;
-	// 2k maximum hw block length
-	mmc->max_blk_size = 2048;
-	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-	mmc->max_seg_size = mmc->max_req_size;
-	sock->signal_irq = tifm_sd_signal_irq;
-	rc = tifm_sd_initialize_host(host);
-
-	if (!rc)
-		rc = mmc_add_host(mmc);
-	if (rc)
-		goto out_free_mmc;
-
-	return 0;
-out_free_mmc:
-	mmc_free_host(mmc);
-	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);
-
-	del_timer_sync(&host->timer);
-	tifm_sd_terminate(host);
-	wait_event_timeout(host->notify, host->flags & EJECT_DONE,
-			   host->timeout_jiffies);
-	tasklet_kill(&host->finish_tasklet);
-	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);
-
-	tifm_set_drvdata(sock, NULL);
-	mmc_free_host(mmc);
-}
-
-#ifdef CONFIG_PM
-
-static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
-{
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	int rc;
-
-	rc = mmc_suspend_host(mmc, state);
-	/* The meaning of the bit majority in this constant is unknown. */
-	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-	       sock->addr + SOCK_CONTROL);
-	return rc;
-}
-
-static int tifm_sd_resume(struct tifm_dev *sock)
-{
-	struct mmc_host *mmc = tifm_get_drvdata(sock);
-	struct tifm_sd *host = mmc_priv(mmc);
-
-	if (sock->media_id != FM_SD
-	    || tifm_sd_initialize_host(host)) {
-		tifm_eject(sock);
-		return 0;
-	} else {
-		return mmc_resume_host(mmc);
-	}
-}
-
-#else
-
-#define tifm_sd_suspend NULL
-#define tifm_sd_resume NULL
-
-#endif /* CONFIG_PM */
-
-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,
-	.suspend  = tifm_sd_suspend,
-	.resume   = tifm_sd_resume
-};
-
-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
deleted file mode 100644
index 05ccfc4..0000000
--- a/drivers/mmc/wbsd.c
+++ /dev/null
@@ -1,2172 +0,0 @@
-/*
- *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
- *
- *  Copyright (C) 2004-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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- *
- * Warning!
- *
- * Changes to the FIFO system should be done with extreme care since
- * the hardware is full of bugs related to the FIFO. Known issues are:
- *
- * - FIFO size field in FSR is always zero.
- *
- * - FIFO interrupts tend not to work as they should. Interrupts are
- *   triggered only for full/empty events, not for threshold values.
- *
- * - On APIC systems the FIFO empty interrupt is sometimes lost.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/pnp.h>
-#include <linux/highmem.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/scatterlist.h>
-
-#include "wbsd.h"
-
-#define DRIVER_NAME "wbsd"
-
-#define DBG(x...) \
-	pr_debug(DRIVER_NAME ": " x)
-#define DBGF(f, x...) \
-	pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x)
-
-/*
- * Device resources
- */
-
-#ifdef CONFIG_PNP
-
-static const struct pnp_device_id pnp_dev_table[] = {
-	{ "WEC0517", 0 },
-	{ "WEC0518", 0 },
-	{ "", 0 },
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-#endif /* CONFIG_PNP */
-
-static const int config_ports[] = { 0x2E, 0x4E };
-static const int unlock_codes[] = { 0x83, 0x87 };
-
-static const int valid_ids[] = {
-	0x7112,
-	};
-
-#ifdef CONFIG_PNP
-static unsigned int nopnp = 0;
-#else
-static const unsigned int nopnp = 1;
-#endif
-static unsigned int io = 0x248;
-static unsigned int irq = 6;
-static int dma = 2;
-
-/*
- * Basic functions
- */
-
-static inline void wbsd_unlock_config(struct wbsd_host *host)
-{
-	BUG_ON(host->config == 0);
-
-	outb(host->unlock_code, host->config);
-	outb(host->unlock_code, host->config);
-}
-
-static inline void wbsd_lock_config(struct wbsd_host *host)
-{
-	BUG_ON(host->config == 0);
-
-	outb(LOCK_CODE, host->config);
-}
-
-static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
-{
-	BUG_ON(host->config == 0);
-
-	outb(reg, host->config);
-	outb(value, host->config + 1);
-}
-
-static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
-{
-	BUG_ON(host->config == 0);
-
-	outb(reg, host->config);
-	return inb(host->config + 1);
-}
-
-static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
-{
-	outb(index, host->base + WBSD_IDXR);
-	outb(value, host->base + WBSD_DATAR);
-}
-
-static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
-{
-	outb(index, host->base + WBSD_IDXR);
-	return inb(host->base + WBSD_DATAR);
-}
-
-/*
- * Common routines
- */
-
-static void wbsd_init_device(struct wbsd_host *host)
-{
-	u8 setup, ier;
-
-	/*
-	 * Reset chip (SD/MMC part) and fifo.
-	 */
-	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-	setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
-	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-	/*
-	 * Set DAT3 to input
-	 */
-	setup &= ~WBSD_DAT3_H;
-	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-	host->flags &= ~WBSD_FIGNORE_DETECT;
-
-	/*
-	 * Read back default clock.
-	 */
-	host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
-
-	/*
-	 * Power down port.
-	 */
-	outb(WBSD_POWER_N, host->base + WBSD_CSR);
-
-	/*
-	 * Set maximum timeout.
-	 */
-	wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
-
-	/*
-	 * Test for card presence
-	 */
-	if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
-		host->flags |= WBSD_FCARD_PRESENT;
-	else
-		host->flags &= ~WBSD_FCARD_PRESENT;
-
-	/*
-	 * Enable interesting interrupts.
-	 */
-	ier = 0;
-	ier |= WBSD_EINT_CARD;
-	ier |= WBSD_EINT_FIFO_THRE;
-	ier |= WBSD_EINT_CCRC;
-	ier |= WBSD_EINT_TIMEOUT;
-	ier |= WBSD_EINT_CRC;
-	ier |= WBSD_EINT_TC;
-
-	outb(ier, host->base + WBSD_EIR);
-
-	/*
-	 * Clear interrupts.
-	 */
-	inb(host->base + WBSD_ISR);
-}
-
-static void wbsd_reset(struct wbsd_host *host)
-{
-	u8 setup;
-
-	printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc));
-
-	/*
-	 * Soft reset of chip (SD/MMC part).
-	 */
-	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-	setup |= WBSD_SOFT_RESET;
-	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-}
-
-static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
-{
-	unsigned long dmaflags;
-
-	DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
-	if (host->dma >= 0) {
-		/*
-		 * Release ISA DMA controller.
-		 */
-		dmaflags = claim_dma_lock();
-		disable_dma(host->dma);
-		clear_dma_ff(host->dma);
-		release_dma_lock(dmaflags);
-
-		/*
-		 * Disable DMA on host.
-		 */
-		wbsd_write_index(host, WBSD_IDX_DMA, 0);
-	}
-
-	host->mrq = NULL;
-
-	/*
-	 * MMC layer might call back into the driver so first unlock.
-	 */
-	spin_unlock(&host->lock);
-	mmc_request_done(host->mmc, mrq);
-	spin_lock(&host->lock);
-}
-
-/*
- * Scatter/gather functions
- */
-
-static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
-{
-	/*
-	 * Get info. about SG list from data structure.
-	 */
-	host->cur_sg = data->sg;
-	host->num_sg = data->sg_len;
-
-	host->offset = 0;
-	host->remain = host->cur_sg->length;
-}
-
-static inline int wbsd_next_sg(struct wbsd_host *host)
-{
-	/*
-	 * Skip to next SG entry.
-	 */
-	host->cur_sg++;
-	host->num_sg--;
-
-	/*
-	 * Any entries left?
-	 */
-	if (host->num_sg > 0) {
-		host->offset = 0;
-		host->remain = host->cur_sg->length;
-	}
-
-	return host->num_sg;
-}
-
-static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
-{
-	return page_address(host->cur_sg->page) + host->cur_sg->offset;
-}
-
-static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
-{
-	unsigned int len, i, size;
-	struct scatterlist *sg;
-	char *dmabuf = host->dma_buffer;
-	char *sgbuf;
-
-	size = host->size;
-
-	sg = data->sg;
-	len = data->sg_len;
-
-	/*
-	 * Just loop through all entries. Size might not
-	 * be the entire list though so make sure that
-	 * we do not transfer too much.
-	 */
-	for (i = 0; i < len; i++) {
-		sgbuf = page_address(sg[i].page) + sg[i].offset;
-		if (size < sg[i].length)
-			memcpy(dmabuf, sgbuf, size);
-		else
-			memcpy(dmabuf, sgbuf, sg[i].length);
-		dmabuf += sg[i].length;
-
-		if (size < sg[i].length)
-			size = 0;
-		else
-			size -= sg[i].length;
-
-		if (size == 0)
-			break;
-	}
-
-	/*
-	 * Check that we didn't get a request to transfer
-	 * more data than can fit into the SG list.
-	 */
-
-	BUG_ON(size != 0);
-
-	host->size -= size;
-}
-
-static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
-{
-	unsigned int len, i, size;
-	struct scatterlist *sg;
-	char *dmabuf = host->dma_buffer;
-	char *sgbuf;
-
-	size = host->size;
-
-	sg = data->sg;
-	len = data->sg_len;
-
-	/*
-	 * Just loop through all entries. Size might not
-	 * be the entire list though so make sure that
-	 * we do not transfer too much.
-	 */
-	for (i = 0; i < len; i++) {
-		sgbuf = page_address(sg[i].page) + sg[i].offset;
-		if (size < sg[i].length)
-			memcpy(sgbuf, dmabuf, size);
-		else
-			memcpy(sgbuf, dmabuf, sg[i].length);
-		dmabuf += sg[i].length;
-
-		if (size < sg[i].length)
-			size = 0;
-		else
-			size -= sg[i].length;
-
-		if (size == 0)
-			break;
-	}
-
-	/*
-	 * Check that we didn't get a request to transfer
-	 * more data than can fit into the SG list.
-	 */
-
-	BUG_ON(size != 0);
-
-	host->size -= size;
-}
-
-/*
- * Command handling
- */
-
-static inline void wbsd_get_short_reply(struct wbsd_host *host,
-					struct mmc_command *cmd)
-{
-	/*
-	 * Correct response type?
-	 */
-	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
-		cmd->error = MMC_ERR_INVALID;
-		return;
-	}
-
-	cmd->resp[0]  = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
-	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
-	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
-	cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
-	cmd->resp[1]  = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
-}
-
-static inline void wbsd_get_long_reply(struct wbsd_host *host,
-	struct mmc_command *cmd)
-{
-	int i;
-
-	/*
-	 * Correct response type?
-	 */
-	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
-		cmd->error = MMC_ERR_INVALID;
-		return;
-	}
-
-	for (i = 0; i < 4; i++) {
-		cmd->resp[i] =
-			wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
-		cmd->resp[i] |=
-			wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
-		cmd->resp[i] |=
-			wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
-		cmd->resp[i] |=
-			wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
-	}
-}
-
-static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
-{
-	int i;
-	u8 status, isr;
-
-	DBGF("Sending cmd (%x)\n", cmd->opcode);
-
-	/*
-	 * Clear accumulated ISR. The interrupt routine
-	 * will fill this one with events that occur during
-	 * transfer.
-	 */
-	host->isr = 0;
-
-	/*
-	 * Send the command (CRC calculated by host).
-	 */
-	outb(cmd->opcode, host->base + WBSD_CMDR);
-	for (i = 3; i >= 0; i--)
-		outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
-
-	cmd->error = MMC_ERR_NONE;
-
-	/*
-	 * Wait for the request to complete.
-	 */
-	do {
-		status = wbsd_read_index(host, WBSD_IDX_STATUS);
-	} while (status & WBSD_CARDTRAFFIC);
-
-	/*
-	 * Do we expect a reply?
-	 */
-	if (cmd->flags & MMC_RSP_PRESENT) {
-		/*
-		 * Read back status.
-		 */
-		isr = host->isr;
-
-		/* Card removed? */
-		if (isr & WBSD_INT_CARD)
-			cmd->error = MMC_ERR_TIMEOUT;
-		/* Timeout? */
-		else if (isr & WBSD_INT_TIMEOUT)
-			cmd->error = MMC_ERR_TIMEOUT;
-		/* CRC? */
-		else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
-			cmd->error = MMC_ERR_BADCRC;
-		/* All ok */
-		else {
-			if (cmd->flags & MMC_RSP_136)
-				wbsd_get_long_reply(host, cmd);
-			else
-				wbsd_get_short_reply(host, cmd);
-		}
-	}
-
-	DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
-}
-
-/*
- * Data functions
- */
-
-static void wbsd_empty_fifo(struct wbsd_host *host)
-{
-	struct mmc_data *data = host->mrq->cmd->data;
-	char *buffer;
-	int i, fsr, fifo;
-
-	/*
-	 * Handle excessive data.
-	 */
-	if (data->bytes_xfered == host->size)
-		return;
-
-	buffer = wbsd_sg_to_buffer(host) + host->offset;
-
-	/*
-	 * Drain the fifo. This has a tendency to loop longer
-	 * than the FIFO length (usually one block).
-	 */
-	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
-		/*
-		 * The size field in the FSR is broken so we have to
-		 * do some guessing.
-		 */
-		if (fsr & WBSD_FIFO_FULL)
-			fifo = 16;
-		else if (fsr & WBSD_FIFO_FUTHRE)
-			fifo = 8;
-		else
-			fifo = 1;
-
-		for (i = 0; i < fifo; i++) {
-			*buffer = inb(host->base + WBSD_DFR);
-			buffer++;
-			host->offset++;
-			host->remain--;
-
-			data->bytes_xfered++;
-
-			/*
-			 * Transfer done?
-			 */
-			if (data->bytes_xfered == host->size)
-				return;
-
-			/*
-			 * End of scatter list entry?
-			 */
-			if (host->remain == 0) {
-				/*
-				 * Get next entry. Check if last.
-				 */
-				if (!wbsd_next_sg(host)) {
-					/*
-					 * We should never reach this point.
-					 * It means that we're trying to
-					 * transfer more blocks than can fit
-					 * into the scatter list.
-					 */
-					BUG_ON(1);
-
-					host->size = data->bytes_xfered;
-
-					return;
-				}
-
-				buffer = wbsd_sg_to_buffer(host);
-			}
-		}
-	}
-
-	/*
-	 * This is a very dirty hack to solve a
-	 * hardware problem. The chip doesn't trigger
-	 * FIFO threshold interrupts properly.
-	 */
-	if ((host->size - data->bytes_xfered) < 16)
-		tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_fill_fifo(struct wbsd_host *host)
-{
-	struct mmc_data *data = host->mrq->cmd->data;
-	char *buffer;
-	int i, fsr, fifo;
-
-	/*
-	 * Check that we aren't being called after the
-	 * entire buffer has been transfered.
-	 */
-	if (data->bytes_xfered == host->size)
-		return;
-
-	buffer = wbsd_sg_to_buffer(host) + host->offset;
-
-	/*
-	 * Fill the fifo. This has a tendency to loop longer
-	 * than the FIFO length (usually one block).
-	 */
-	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
-		/*
-		 * The size field in the FSR is broken so we have to
-		 * do some guessing.
-		 */
-		if (fsr & WBSD_FIFO_EMPTY)
-			fifo = 0;
-		else if (fsr & WBSD_FIFO_EMTHRE)
-			fifo = 8;
-		else
-			fifo = 15;
-
-		for (i = 16; i > fifo; i--) {
-			outb(*buffer, host->base + WBSD_DFR);
-			buffer++;
-			host->offset++;
-			host->remain--;
-
-			data->bytes_xfered++;
-
-			/*
-			 * Transfer done?
-			 */
-			if (data->bytes_xfered == host->size)
-				return;
-
-			/*
-			 * End of scatter list entry?
-			 */
-			if (host->remain == 0) {
-				/*
-				 * Get next entry. Check if last.
-				 */
-				if (!wbsd_next_sg(host)) {
-					/*
-					 * We should never reach this point.
-					 * It means that we're trying to
-					 * transfer more blocks than can fit
-					 * into the scatter list.
-					 */
-					BUG_ON(1);
-
-					host->size = data->bytes_xfered;
-
-					return;
-				}
-
-				buffer = wbsd_sg_to_buffer(host);
-			}
-		}
-	}
-
-	/*
-	 * The controller stops sending interrupts for
-	 * 'FIFO empty' under certain conditions. So we
-	 * need to be a bit more pro-active.
-	 */
-	tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
-{
-	u16 blksize;
-	u8 setup;
-	unsigned long dmaflags;
-
-	DBGF("blksz %04x blks %04x flags %08x\n",
-		data->blksz, data->blocks, data->flags);
-	DBGF("tsac %d ms nsac %d clk\n",
-		data->timeout_ns / 1000000, data->timeout_clks);
-
-	/*
-	 * Calculate size.
-	 */
-	host->size = data->blocks * data->blksz;
-
-	/*
-	 * Check timeout values for overflow.
-	 * (Yes, some cards cause this value to overflow).
-	 */
-	if (data->timeout_ns > 127000000)
-		wbsd_write_index(host, WBSD_IDX_TAAC, 127);
-	else {
-		wbsd_write_index(host, WBSD_IDX_TAAC,
-			data->timeout_ns / 1000000);
-	}
-
-	if (data->timeout_clks > 255)
-		wbsd_write_index(host, WBSD_IDX_NSAC, 255);
-	else
-		wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
-
-	/*
-	 * Inform the chip of how large blocks will be
-	 * sent. It needs this to determine when to
-	 * calculate CRC.
-	 *
-	 * Space for CRC must be included in the size.
-	 * Two bytes are needed for each data line.
-	 */
-	if (host->bus_width == MMC_BUS_WIDTH_1) {
-		blksize = data->blksz + 2;
-
-		wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
-		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
-	} else if (host->bus_width == MMC_BUS_WIDTH_4) {
-		blksize = data->blksz + 2 * 4;
-
-		wbsd_write_index(host, WBSD_IDX_PBSMSB,
-			((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
-		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
-	} else {
-		data->error = MMC_ERR_INVALID;
-		return;
-	}
-
-	/*
-	 * Clear the FIFO. This is needed even for DMA
-	 * transfers since the chip still uses the FIFO
-	 * internally.
-	 */
-	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-	setup |= WBSD_FIFO_RESET;
-	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-	/*
-	 * DMA transfer?
-	 */
-	if (host->dma >= 0) {
-		/*
-		 * The buffer for DMA is only 64 kB.
-		 */
-		BUG_ON(host->size > 0x10000);
-		if (host->size > 0x10000) {
-			data->error = MMC_ERR_INVALID;
-			return;
-		}
-
-		/*
-		 * Transfer data from the SG list to
-		 * the DMA buffer.
-		 */
-		if (data->flags & MMC_DATA_WRITE)
-			wbsd_sg_to_dma(host, data);
-
-		/*
-		 * Initialise the ISA DMA controller.
-		 */
-		dmaflags = claim_dma_lock();
-		disable_dma(host->dma);
-		clear_dma_ff(host->dma);
-		if (data->flags & MMC_DATA_READ)
-			set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
-		else
-			set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
-		set_dma_addr(host->dma, host->dma_addr);
-		set_dma_count(host->dma, host->size);
-
-		enable_dma(host->dma);
-		release_dma_lock(dmaflags);
-
-		/*
-		 * Enable DMA on the host.
-		 */
-		wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
-	} else {
-		/*
-		 * This flag is used to keep printk
-		 * output to a minimum.
-		 */
-		host->firsterr = 1;
-
-		/*
-		 * Initialise the SG list.
-		 */
-		wbsd_init_sg(host, data);
-
-		/*
-		 * Turn off DMA.
-		 */
-		wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
-		/*
-		 * Set up FIFO threshold levels (and fill
-		 * buffer if doing a write).
-		 */
-		if (data->flags & MMC_DATA_READ) {
-			wbsd_write_index(host, WBSD_IDX_FIFOEN,
-				WBSD_FIFOEN_FULL | 8);
-		} else {
-			wbsd_write_index(host, WBSD_IDX_FIFOEN,
-				WBSD_FIFOEN_EMPTY | 8);
-			wbsd_fill_fifo(host);
-		}
-	}
-
-	data->error = MMC_ERR_NONE;
-}
-
-static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
-{
-	unsigned long dmaflags;
-	int count;
-	u8 status;
-
-	WARN_ON(host->mrq == NULL);
-
-	/*
-	 * Send a stop command if needed.
-	 */
-	if (data->stop)
-		wbsd_send_command(host, data->stop);
-
-	/*
-	 * Wait for the controller to leave data
-	 * transfer state.
-	 */
-	do {
-		status = wbsd_read_index(host, WBSD_IDX_STATUS);
-	} while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
-
-	/*
-	 * DMA transfer?
-	 */
-	if (host->dma >= 0) {
-		/*
-		 * Disable DMA on the host.
-		 */
-		wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
-		/*
-		 * Turn of ISA DMA controller.
-		 */
-		dmaflags = claim_dma_lock();
-		disable_dma(host->dma);
-		clear_dma_ff(host->dma);
-		count = get_dma_residue(host->dma);
-		release_dma_lock(dmaflags);
-
-		/*
-		 * Any leftover data?
-		 */
-		if (count) {
-			printk(KERN_ERR "%s: Incomplete DMA transfer. "
-				"%d bytes left.\n",
-				mmc_hostname(host->mmc), count);
-
-			data->error = MMC_ERR_FAILED;
-		} else {
-			/*
-			 * Transfer data from DMA buffer to
-			 * SG list.
-			 */
-			if (data->flags & MMC_DATA_READ)
-				wbsd_dma_to_sg(host, data);
-
-			data->bytes_xfered = host->size;
-		}
-	}
-
-	DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
-	wbsd_request_end(host, host->mrq);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * MMC layer callbacks                                                       *
- *                                                                           *
-\*****************************************************************************/
-
-static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-	struct wbsd_host *host = mmc_priv(mmc);
-	struct mmc_command *cmd;
-
-	/*
-	 * Disable tasklets to avoid a deadlock.
-	 */
-	spin_lock_bh(&host->lock);
-
-	BUG_ON(host->mrq != NULL);
-
-	cmd = mrq->cmd;
-
-	host->mrq = mrq;
-
-	/*
-	 * If there is no card in the slot then
-	 * timeout immediatly.
-	 */
-	if (!(host->flags & WBSD_FCARD_PRESENT)) {
-		cmd->error = MMC_ERR_TIMEOUT;
-		goto done;
-	}
-
-	/*
-	 * Does the request include data?
-	 */
-	if (cmd->data) {
-		wbsd_prepare_data(host, cmd->data);
-
-		if (cmd->data->error != MMC_ERR_NONE)
-			goto done;
-	}
-
-	wbsd_send_command(host, cmd);
-
-	/*
-	 * If this is a data transfer the request
-	 * will be finished after the data has
-	 * transfered.
-	 */
-	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
-		/*
-		 * The hardware is so delightfully stupid that it has a list
-		 * of "data" commands. If a command isn't on this list, it'll
-		 * just go back to the idle state and won't send any data
-		 * interrupts.
-		 */
-		switch (cmd->opcode) {
-		case 11:
-		case 17:
-		case 18:
-		case 20:
-		case 24:
-		case 25:
-		case 26:
-		case 27:
-		case 30:
-		case 42:
-		case 56:
-			break;
-
-		/* ACMDs. We don't keep track of state, so we just treat them
-		 * like any other command. */
-		case 51:
-			break;
-
-		default:
-#ifdef CONFIG_MMC_DEBUG
-			printk(KERN_WARNING "%s: Data command %d is not "
-				"supported by this controller.\n",
-				mmc_hostname(host->mmc), cmd->opcode);
-#endif
-			cmd->data->error = MMC_ERR_INVALID;
-
-			if (cmd->data->stop)
-				wbsd_send_command(host, cmd->data->stop);
-
-			goto done;
-		};
-
-		/*
-		 * Dirty fix for hardware bug.
-		 */
-		if (host->dma == -1)
-			tasklet_schedule(&host->fifo_tasklet);
-
-		spin_unlock_bh(&host->lock);
-
-		return;
-	}
-
-done:
-	wbsd_request_end(host, mrq);
-
-	spin_unlock_bh(&host->lock);
-}
-
-static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-	struct wbsd_host *host = mmc_priv(mmc);
-	u8 clk, setup, pwr;
-
-	spin_lock_bh(&host->lock);
-
-	/*
-	 * Reset the chip on each power off.
-	 * Should clear out any weird states.
-	 */
-	if (ios->power_mode == MMC_POWER_OFF)
-		wbsd_init_device(host);
-
-	if (ios->clock >= 24000000)
-		clk = WBSD_CLK_24M;
-	else if (ios->clock >= 16000000)
-		clk = WBSD_CLK_16M;
-	else if (ios->clock >= 12000000)
-		clk = WBSD_CLK_12M;
-	else
-		clk = WBSD_CLK_375K;
-
-	/*
-	 * Only write to the clock register when
-	 * there is an actual change.
-	 */
-	if (clk != host->clk) {
-		wbsd_write_index(host, WBSD_IDX_CLK, clk);
-		host->clk = clk;
-	}
-
-	/*
-	 * Power up card.
-	 */
-	if (ios->power_mode != MMC_POWER_OFF) {
-		pwr = inb(host->base + WBSD_CSR);
-		pwr &= ~WBSD_POWER_N;
-		outb(pwr, host->base + WBSD_CSR);
-	}
-
-	/*
-	 * MMC cards need to have pin 1 high during init.
-	 * It wreaks havoc with the card detection though so
-	 * that needs to be disabled.
-	 */
-	setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-	if (ios->chip_select == MMC_CS_HIGH) {
-		BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
-		setup |= WBSD_DAT3_H;
-		host->flags |= WBSD_FIGNORE_DETECT;
-	} else {
-		if (setup & WBSD_DAT3_H) {
-			setup &= ~WBSD_DAT3_H;
-
-			/*
-			 * We cannot resume card detection immediatly
-			 * because of capacitance and delays in the chip.
-			 */
-			mod_timer(&host->ignore_timer, jiffies + HZ / 100);
-		}
-	}
-	wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-	/*
-	 * Store bus width for later. Will be used when
-	 * setting up the data transfer.
-	 */
-	host->bus_width = ios->bus_width;
-
-	spin_unlock_bh(&host->lock);
-}
-
-static int wbsd_get_ro(struct mmc_host *mmc)
-{
-	struct wbsd_host *host = mmc_priv(mmc);
-	u8 csr;
-
-	spin_lock_bh(&host->lock);
-
-	csr = inb(host->base + WBSD_CSR);
-	csr |= WBSD_MSLED;
-	outb(csr, host->base + WBSD_CSR);
-
-	mdelay(1);
-
-	csr = inb(host->base + WBSD_CSR);
-	csr &= ~WBSD_MSLED;
-	outb(csr, host->base + WBSD_CSR);
-
-	spin_unlock_bh(&host->lock);
-
-	return csr & WBSD_WRPT;
-}
-
-static const struct mmc_host_ops wbsd_ops = {
-	.request	= wbsd_request,
-	.set_ios	= wbsd_set_ios,
-	.get_ro		= wbsd_get_ro,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Interrupt handling                                                        *
- *                                                                           *
-\*****************************************************************************/
-
-/*
- * Helper function to reset detection ignore
- */
-
-static void wbsd_reset_ignore(unsigned long data)
-{
-	struct wbsd_host *host = (struct wbsd_host *)data;
-
-	BUG_ON(host == NULL);
-
-	DBG("Resetting card detection ignore\n");
-
-	spin_lock_bh(&host->lock);
-
-	host->flags &= ~WBSD_FIGNORE_DETECT;
-
-	/*
-	 * Card status might have changed during the
-	 * blackout.
-	 */
-	tasklet_schedule(&host->card_tasklet);
-
-	spin_unlock_bh(&host->lock);
-}
-
-/*
- * Tasklets
- */
-
-static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
-{
-	WARN_ON(!host->mrq);
-	if (!host->mrq)
-		return NULL;
-
-	WARN_ON(!host->mrq->cmd);
-	if (!host->mrq->cmd)
-		return NULL;
-
-	WARN_ON(!host->mrq->cmd->data);
-	if (!host->mrq->cmd->data)
-		return NULL;
-
-	return host->mrq->cmd->data;
-}
-
-static void wbsd_tasklet_card(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	u8 csr;
-	int delay = -1;
-
-	spin_lock(&host->lock);
-
-	if (host->flags & WBSD_FIGNORE_DETECT) {
-		spin_unlock(&host->lock);
-		return;
-	}
-
-	csr = inb(host->base + WBSD_CSR);
-	WARN_ON(csr == 0xff);
-
-	if (csr & WBSD_CARDPRESENT) {
-		if (!(host->flags & WBSD_FCARD_PRESENT)) {
-			DBG("Card inserted\n");
-			host->flags |= WBSD_FCARD_PRESENT;
-
-			delay = 500;
-		}
-	} else if (host->flags & WBSD_FCARD_PRESENT) {
-		DBG("Card removed\n");
-		host->flags &= ~WBSD_FCARD_PRESENT;
-
-		if (host->mrq) {
-			printk(KERN_ERR "%s: Card removed during transfer!\n",
-				mmc_hostname(host->mmc));
-			wbsd_reset(host);
-
-			host->mrq->cmd->error = MMC_ERR_FAILED;
-			tasklet_schedule(&host->finish_tasklet);
-		}
-
-		delay = 0;
-	}
-
-	/*
-	 * Unlock first since we might get a call back.
-	 */
-
-	spin_unlock(&host->lock);
-
-	if (delay != -1)
-		mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
-}
-
-static void wbsd_tasklet_fifo(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	struct mmc_data *data;
-
-	spin_lock(&host->lock);
-
-	if (!host->mrq)
-		goto end;
-
-	data = wbsd_get_data(host);
-	if (!data)
-		goto end;
-
-	if (data->flags & MMC_DATA_WRITE)
-		wbsd_fill_fifo(host);
-	else
-		wbsd_empty_fifo(host);
-
-	/*
-	 * Done?
-	 */
-	if (host->size == data->bytes_xfered) {
-		wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
-		tasklet_schedule(&host->finish_tasklet);
-	}
-
-end:
-	spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_crc(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	struct mmc_data *data;
-
-	spin_lock(&host->lock);
-
-	if (!host->mrq)
-		goto end;
-
-	data = wbsd_get_data(host);
-	if (!data)
-		goto end;
-
-	DBGF("CRC error\n");
-
-	data->error = MMC_ERR_BADCRC;
-
-	tasklet_schedule(&host->finish_tasklet);
-
-end:
-	spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_timeout(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	struct mmc_data *data;
-
-	spin_lock(&host->lock);
-
-	if (!host->mrq)
-		goto end;
-
-	data = wbsd_get_data(host);
-	if (!data)
-		goto end;
-
-	DBGF("Timeout\n");
-
-	data->error = MMC_ERR_TIMEOUT;
-
-	tasklet_schedule(&host->finish_tasklet);
-
-end:
-	spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_finish(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	struct mmc_data *data;
-
-	spin_lock(&host->lock);
-
-	WARN_ON(!host->mrq);
-	if (!host->mrq)
-		goto end;
-
-	data = wbsd_get_data(host);
-	if (!data)
-		goto end;
-
-	wbsd_finish_data(host, data);
-
-end:
-	spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_block(unsigned long param)
-{
-	struct wbsd_host *host = (struct wbsd_host *)param;
-	struct mmc_data *data;
-
-	spin_lock(&host->lock);
-
-	if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
-		WBSD_CRC_OK) {
-		data = wbsd_get_data(host);
-		if (!data)
-			goto end;
-
-		DBGF("CRC error\n");
-
-		data->error = MMC_ERR_BADCRC;
-
-		tasklet_schedule(&host->finish_tasklet);
-	}
-
-end:
-	spin_unlock(&host->lock);
-}
-
-/*
- * Interrupt handling
- */
-
-static irqreturn_t wbsd_irq(int irq, void *dev_id)
-{
-	struct wbsd_host *host = dev_id;
-	int isr;
-
-	isr = inb(host->base + WBSD_ISR);
-
-	/*
-	 * Was it actually our hardware that caused the interrupt?
-	 */
-	if (isr == 0xff || isr == 0x00)
-		return IRQ_NONE;
-
-	host->isr |= isr;
-
-	/*
-	 * Schedule tasklets as needed.
-	 */
-	if (isr & WBSD_INT_CARD)
-		tasklet_schedule(&host->card_tasklet);
-	if (isr & WBSD_INT_FIFO_THRE)
-		tasklet_schedule(&host->fifo_tasklet);
-	if (isr & WBSD_INT_CRC)
-		tasklet_hi_schedule(&host->crc_tasklet);
-	if (isr & WBSD_INT_TIMEOUT)
-		tasklet_hi_schedule(&host->timeout_tasklet);
-	if (isr & WBSD_INT_BUSYEND)
-		tasklet_hi_schedule(&host->block_tasklet);
-	if (isr & WBSD_INT_TC)
-		tasklet_schedule(&host->finish_tasklet);
-
-	return IRQ_HANDLED;
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Device initialisation and shutdown                                        *
- *                                                                           *
-\*****************************************************************************/
-
-/*
- * Allocate/free MMC structure.
- */
-
-static int __devinit wbsd_alloc_mmc(struct device *dev)
-{
-	struct mmc_host *mmc;
-	struct wbsd_host *host;
-
-	/*
-	 * Allocate MMC structure.
-	 */
-	mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
-	if (!mmc)
-		return -ENOMEM;
-
-	host = mmc_priv(mmc);
-	host->mmc = mmc;
-
-	host->dma = -1;
-
-	/*
-	 * Set host parameters.
-	 */
-	mmc->ops = &wbsd_ops;
-	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_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
-
-	spin_lock_init(&host->lock);
-
-	/*
-	 * Set up timers
-	 */
-	init_timer(&host->ignore_timer);
-	host->ignore_timer.data = (unsigned long)host;
-	host->ignore_timer.function = wbsd_reset_ignore;
-
-	/*
-	 * Maximum number of segments. Worst case is one sector per segment
-	 * so this will be 64kB/512.
-	 */
-	mmc->max_hw_segs = 128;
-	mmc->max_phys_segs = 128;
-
-	/*
-	 * Maximum request size. Also limited by 64KiB buffer.
-	 */
-	mmc->max_req_size = 65536;
-
-	/*
-	 * Maximum segment size. Could be one segment with the maximum number
-	 * of bytes.
-	 */
-	mmc->max_seg_size = mmc->max_req_size;
-
-	/*
-	 * Maximum block size. We have 12 bits (= 4095) but have to subtract
-	 * space for CRC. So the maximum is 4095 - 4*2 = 4087.
-	 */
-	mmc->max_blk_size = 4087;
-
-	/*
-	 * Maximum block count. There is no real limit so the maximum
-	 * request size will be the only restriction.
-	 */
-	mmc->max_blk_count = mmc->max_req_size;
-
-	dev_set_drvdata(dev, mmc);
-
-	return 0;
-}
-
-static void __devexit wbsd_free_mmc(struct device *dev)
-{
-	struct mmc_host *mmc;
-	struct wbsd_host *host;
-
-	mmc = dev_get_drvdata(dev);
-	if (!mmc)
-		return;
-
-	host = mmc_priv(mmc);
-	BUG_ON(host == NULL);
-
-	del_timer_sync(&host->ignore_timer);
-
-	mmc_free_host(mmc);
-
-	dev_set_drvdata(dev, NULL);
-}
-
-/*
- * Scan for known chip id:s
- */
-
-static int __devinit wbsd_scan(struct wbsd_host *host)
-{
-	int i, j, k;
-	int id;
-
-	/*
-	 * Iterate through all ports, all codes to
-	 * find hardware that is in our known list.
-	 */
-	for (i = 0; i < ARRAY_SIZE(config_ports); i++) {
-		if (!request_region(config_ports[i], 2, DRIVER_NAME))
-			continue;
-
-		for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
-			id = 0xFFFF;
-
-			host->config = config_ports[i];
-			host->unlock_code = unlock_codes[j];
-
-			wbsd_unlock_config(host);
-
-			outb(WBSD_CONF_ID_HI, config_ports[i]);
-			id = inb(config_ports[i] + 1) << 8;
-
-			outb(WBSD_CONF_ID_LO, config_ports[i]);
-			id |= inb(config_ports[i] + 1);
-
-			wbsd_lock_config(host);
-
-			for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
-				if (id == valid_ids[k]) {
-					host->chip_id = id;
-
-					return 0;
-				}
-			}
-
-			if (id != 0xFFFF) {
-				DBG("Unknown hardware (id %x) found at %x\n",
-					id, config_ports[i]);
-			}
-		}
-
-		release_region(config_ports[i], 2);
-	}
-
-	host->config = 0;
-	host->unlock_code = 0;
-
-	return -ENODEV;
-}
-
-/*
- * Allocate/free io port ranges
- */
-
-static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
-{
-	if (base & 0x7)
-		return -EINVAL;
-
-	if (!request_region(base, 8, DRIVER_NAME))
-		return -EIO;
-
-	host->base = base;
-
-	return 0;
-}
-
-static void __devexit wbsd_release_regions(struct wbsd_host *host)
-{
-	if (host->base)
-		release_region(host->base, 8);
-
-	host->base = 0;
-
-	if (host->config)
-		release_region(host->config, 2);
-
-	host->config = 0;
-}
-
-/*
- * Allocate/free DMA port and buffer
- */
-
-static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
-{
-	if (dma < 0)
-		return;
-
-	if (request_dma(dma, DRIVER_NAME))
-		goto err;
-
-	/*
-	 * We need to allocate a special buffer in
-	 * order for ISA to be able to DMA to it.
-	 */
-	host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
-		GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
-	if (!host->dma_buffer)
-		goto free;
-
-	/*
-	 * Translate the address to a physical address.
-	 */
-	host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,
-		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-
-	/*
-	 * ISA DMA must be aligned on a 64k basis.
-	 */
-	if ((host->dma_addr & 0xffff) != 0)
-		goto kfree;
-	/*
-	 * ISA cannot access memory above 16 MB.
-	 */
-	else if (host->dma_addr >= 0x1000000)
-		goto kfree;
-
-	host->dma = dma;
-
-	return;
-
-kfree:
-	/*
-	 * If we've gotten here then there is some kind of alignment bug
-	 */
-	BUG_ON(1);
-
-	dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
-		WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-	host->dma_addr = (dma_addr_t)NULL;
-
-	kfree(host->dma_buffer);
-	host->dma_buffer = NULL;
-
-free:
-	free_dma(dma);
-
-err:
-	printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. "
-		"Falling back on FIFO.\n", dma);
-}
-
-static void __devexit wbsd_release_dma(struct wbsd_host *host)
-{
-	if (host->dma_addr) {
-		dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
-			WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-	}
-	kfree(host->dma_buffer);
-	if (host->dma >= 0)
-		free_dma(host->dma);
-
-	host->dma = -1;
-	host->dma_buffer = NULL;
-	host->dma_addr = (dma_addr_t)NULL;
-}
-
-/*
- * Allocate/free IRQ.
- */
-
-static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
-{
-	int ret;
-
-	/*
-	 * Allocate interrupt.
-	 */
-
-	ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
-	if (ret)
-		return ret;
-
-	host->irq = irq;
-
-	/*
-	 * Set up tasklets.
-	 */
-	tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
-			(unsigned long)host);
-	tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
-			(unsigned long)host);
-	tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
-			(unsigned long)host);
-	tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
-			(unsigned long)host);
-	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
-			(unsigned long)host);
-	tasklet_init(&host->block_tasklet, wbsd_tasklet_block,
-			(unsigned long)host);
-
-	return 0;
-}
-
-static void __devexit wbsd_release_irq(struct wbsd_host *host)
-{
-	if (!host->irq)
-		return;
-
-	free_irq(host->irq, host);
-
-	host->irq = 0;
-
-	tasklet_kill(&host->card_tasklet);
-	tasklet_kill(&host->fifo_tasklet);
-	tasklet_kill(&host->crc_tasklet);
-	tasklet_kill(&host->timeout_tasklet);
-	tasklet_kill(&host->finish_tasklet);
-	tasklet_kill(&host->block_tasklet);
-}
-
-/*
- * Allocate all resources for the host.
- */
-
-static int __devinit wbsd_request_resources(struct wbsd_host *host,
-	int base, int irq, int dma)
-{
-	int ret;
-
-	/*
-	 * Allocate I/O ports.
-	 */
-	ret = wbsd_request_region(host, base);
-	if (ret)
-		return ret;
-
-	/*
-	 * Allocate interrupt.
-	 */
-	ret = wbsd_request_irq(host, irq);
-	if (ret)
-		return ret;
-
-	/*
-	 * Allocate DMA.
-	 */
-	wbsd_request_dma(host, dma);
-
-	return 0;
-}
-
-/*
- * Release all resources for the host.
- */
-
-static void __devexit wbsd_release_resources(struct wbsd_host *host)
-{
-	wbsd_release_dma(host);
-	wbsd_release_irq(host);
-	wbsd_release_regions(host);
-}
-
-/*
- * Configure the resources the chip should use.
- */
-
-static void wbsd_chip_config(struct wbsd_host *host)
-{
-	wbsd_unlock_config(host);
-
-	/*
-	 * Reset the chip.
-	 */
-	wbsd_write_config(host, WBSD_CONF_SWRST, 1);
-	wbsd_write_config(host, WBSD_CONF_SWRST, 0);
-
-	/*
-	 * Select SD/MMC function.
-	 */
-	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
-	/*
-	 * Set up card detection.
-	 */
-	wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
-
-	/*
-	 * Configure chip
-	 */
-	wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
-	wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-
-	wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
-
-	if (host->dma >= 0)
-		wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
-
-	/*
-	 * Enable and power up chip.
-	 */
-	wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
-	wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
-
-	wbsd_lock_config(host);
-}
-
-/*
- * Check that configured resources are correct.
- */
-
-static int wbsd_chip_validate(struct wbsd_host *host)
-{
-	int base, irq, dma;
-
-	wbsd_unlock_config(host);
-
-	/*
-	 * Select SD/MMC function.
-	 */
-	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
-	/*
-	 * Read configuration.
-	 */
-	base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
-	base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
-
-	irq = wbsd_read_config(host, WBSD_CONF_IRQ);
-
-	dma = wbsd_read_config(host, WBSD_CONF_DRQ);
-
-	wbsd_lock_config(host);
-
-	/*
-	 * Validate against given configuration.
-	 */
-	if (base != host->base)
-		return 0;
-	if (irq != host->irq)
-		return 0;
-	if ((dma != host->dma) && (host->dma != -1))
-		return 0;
-
-	return 1;
-}
-
-/*
- * Powers down the SD function
- */
-
-static void wbsd_chip_poweroff(struct wbsd_host *host)
-{
-	wbsd_unlock_config(host);
-
-	wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-	wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
-
-	wbsd_lock_config(host);
-}
-
-/*****************************************************************************\
- *                                                                           *
- * Devices setup and shutdown                                                *
- *                                                                           *
-\*****************************************************************************/
-
-static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
-	int pnp)
-{
-	struct wbsd_host *host = NULL;
-	struct mmc_host *mmc = NULL;
-	int ret;
-
-	ret = wbsd_alloc_mmc(dev);
-	if (ret)
-		return ret;
-
-	mmc = dev_get_drvdata(dev);
-	host = mmc_priv(mmc);
-
-	/*
-	 * Scan for hardware.
-	 */
-	ret = wbsd_scan(host);
-	if (ret) {
-		if (pnp && (ret == -ENODEV)) {
-			printk(KERN_WARNING DRIVER_NAME
-				": Unable to confirm device presence. You may "
-				"experience lock-ups.\n");
-		} else {
-			wbsd_free_mmc(dev);
-			return ret;
-		}
-	}
-
-	/*
-	 * Request resources.
-	 */
-	ret = wbsd_request_resources(host, base, irq, dma);
-	if (ret) {
-		wbsd_release_resources(host);
-		wbsd_free_mmc(dev);
-		return ret;
-	}
-
-	/*
-	 * See if chip needs to be configured.
-	 */
-	if (pnp) {
-		if ((host->config != 0) && !wbsd_chip_validate(host)) {
-			printk(KERN_WARNING DRIVER_NAME
-				": PnP active but chip not configured! "
-				"You probably have a buggy BIOS. "
-				"Configuring chip manually.\n");
-			wbsd_chip_config(host);
-		}
-	} else
-		wbsd_chip_config(host);
-
-	/*
-	 * Power Management stuff. No idea how this works.
-	 * Not tested.
-	 */
-#ifdef CONFIG_PM
-	if (host->config) {
-		wbsd_unlock_config(host);
-		wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
-		wbsd_lock_config(host);
-	}
-#endif
-	/*
-	 * Allow device to initialise itself properly.
-	 */
-	mdelay(5);
-
-	/*
-	 * Reset the chip into a known state.
-	 */
-	wbsd_init_device(host);
-
-	mmc_add_host(mmc);
-
-	printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc));
-	if (host->chip_id != 0)
-		printk(" id %x", (int)host->chip_id);
-	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
-	if (host->dma >= 0)
-		printk(" dma %d", (int)host->dma);
-	else
-		printk(" FIFO");
-	if (pnp)
-		printk(" PnP");
-	printk("\n");
-
-	return 0;
-}
-
-static void __devexit wbsd_shutdown(struct device *dev, int pnp)
-{
-	struct mmc_host *mmc = dev_get_drvdata(dev);
-	struct wbsd_host *host;
-
-	if (!mmc)
-		return;
-
-	host = mmc_priv(mmc);
-
-	mmc_remove_host(mmc);
-
-	/*
-	 * Power down the SD/MMC function.
-	 */
-	if (!pnp)
-		wbsd_chip_poweroff(host);
-
-	wbsd_release_resources(host);
-
-	wbsd_free_mmc(dev);
-}
-
-/*
- * Non-PnP
- */
-
-static int __devinit wbsd_probe(struct platform_device *dev)
-{
-	/* Use the module parameters for resources */
-	return wbsd_init(&dev->dev, io, irq, dma, 0);
-}
-
-static int __devexit wbsd_remove(struct platform_device *dev)
-{
-	wbsd_shutdown(&dev->dev, 0);
-
-	return 0;
-}
-
-/*
- * PnP
- */
-
-#ifdef CONFIG_PNP
-
-static int __devinit
-wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
-{
-	int io, irq, dma;
-
-	/*
-	 * Get resources from PnP layer.
-	 */
-	io = pnp_port_start(pnpdev, 0);
-	irq = pnp_irq(pnpdev, 0);
-	if (pnp_dma_valid(pnpdev, 0))
-		dma = pnp_dma(pnpdev, 0);
-	else
-		dma = -1;
-
-	DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
-
-	return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
-}
-
-static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
-{
-	wbsd_shutdown(&dev->dev, 1);
-}
-
-#endif /* CONFIG_PNP */
-
-/*
- * Power management
- */
-
-#ifdef CONFIG_PM
-
-static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
-{
-	BUG_ON(host == NULL);
-
-	return mmc_suspend_host(host->mmc, state);
-}
-
-static int wbsd_resume(struct wbsd_host *host)
-{
-	BUG_ON(host == NULL);
-
-	wbsd_init_device(host);
-
-	return mmc_resume_host(host->mmc);
-}
-
-static int wbsd_platform_suspend(struct platform_device *dev,
-				 pm_message_t state)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	struct wbsd_host *host;
-	int ret;
-
-	if (mmc == NULL)
-		return 0;
-
-	DBGF("Suspending...\n");
-
-	host = mmc_priv(mmc);
-
-	ret = wbsd_suspend(host, state);
-	if (ret)
-		return ret;
-
-	wbsd_chip_poweroff(host);
-
-	return 0;
-}
-
-static int wbsd_platform_resume(struct platform_device *dev)
-{
-	struct mmc_host *mmc = platform_get_drvdata(dev);
-	struct wbsd_host *host;
-
-	if (mmc == NULL)
-		return 0;
-
-	DBGF("Resuming...\n");
-
-	host = mmc_priv(mmc);
-
-	wbsd_chip_config(host);
-
-	/*
-	 * Allow device to initialise itself properly.
-	 */
-	mdelay(5);
-
-	return wbsd_resume(host);
-}
-
-#ifdef CONFIG_PNP
-
-static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
-{
-	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
-	struct wbsd_host *host;
-
-	if (mmc == NULL)
-		return 0;
-
-	DBGF("Suspending...\n");
-
-	host = mmc_priv(mmc);
-
-	return wbsd_suspend(host, state);
-}
-
-static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
-{
-	struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
-	struct wbsd_host *host;
-
-	if (mmc == NULL)
-		return 0;
-
-	DBGF("Resuming...\n");
-
-	host = mmc_priv(mmc);
-
-	/*
-	 * See if chip needs to be configured.
-	 */
-	if (host->config != 0) {
-		if (!wbsd_chip_validate(host)) {
-			printk(KERN_WARNING DRIVER_NAME
-				": PnP active but chip not configured! "
-				"You probably have a buggy BIOS. "
-				"Configuring chip manually.\n");
-			wbsd_chip_config(host);
-		}
-	}
-
-	/*
-	 * Allow device to initialise itself properly.
-	 */
-	mdelay(5);
-
-	return wbsd_resume(host);
-}
-
-#endif /* CONFIG_PNP */
-
-#else /* CONFIG_PM */
-
-#define wbsd_platform_suspend NULL
-#define wbsd_platform_resume NULL
-
-#define wbsd_pnp_suspend NULL
-#define wbsd_pnp_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct platform_device *wbsd_device;
-
-static struct platform_driver wbsd_driver = {
-	.probe		= wbsd_probe,
-	.remove		= __devexit_p(wbsd_remove),
-
-	.suspend	= wbsd_platform_suspend,
-	.resume		= wbsd_platform_resume,
-	.driver		= {
-		.name	= DRIVER_NAME,
-	},
-};
-
-#ifdef CONFIG_PNP
-
-static struct pnp_driver wbsd_pnp_driver = {
-	.name		= DRIVER_NAME,
-	.id_table	= pnp_dev_table,
-	.probe		= wbsd_pnp_probe,
-	.remove		= __devexit_p(wbsd_pnp_remove),
-
-	.suspend	= wbsd_pnp_suspend,
-	.resume		= wbsd_pnp_resume,
-};
-
-#endif /* CONFIG_PNP */
-
-/*
- * Module loading/unloading
- */
-
-static int __init wbsd_drv_init(void)
-{
-	int result;
-
-	printk(KERN_INFO DRIVER_NAME
-		": Winbond W83L51xD SD/MMC card interface driver\n");
-	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
-#ifdef CONFIG_PNP
-
-	if (!nopnp) {
-		result = pnp_register_driver(&wbsd_pnp_driver);
-		if (result < 0)
-			return result;
-	}
-#endif /* CONFIG_PNP */
-
-	if (nopnp) {
-		result = platform_driver_register(&wbsd_driver);
-		if (result < 0)
-			return result;
-
-		wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
-		if (!wbsd_device) {
-			platform_driver_unregister(&wbsd_driver);
-			return -ENOMEM;
-		}
-
-		result = platform_device_add(wbsd_device);
-		if (result) {
-			platform_device_put(wbsd_device);
-			platform_driver_unregister(&wbsd_driver);
-			return result;
-		}
-	}
-
-	return 0;
-}
-
-static void __exit wbsd_drv_exit(void)
-{
-#ifdef CONFIG_PNP
-
-	if (!nopnp)
-		pnp_unregister_driver(&wbsd_pnp_driver);
-
-#endif /* CONFIG_PNP */
-
-	if (nopnp) {
-		platform_device_unregister(wbsd_device);
-
-		platform_driver_unregister(&wbsd_driver);
-	}
-
-	DBG("unloaded\n");
-}
-
-module_init(wbsd_drv_init);
-module_exit(wbsd_drv_exit);
-#ifdef CONFIG_PNP
-module_param(nopnp, uint, 0444);
-#endif
-module_param(io, uint, 0444);
-module_param(irq, uint, 0444);
-module_param(dma, int, 0444);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
-MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
-
-#ifdef CONFIG_PNP
-MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
-#endif
-MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
-MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
-MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
deleted file mode 100644
index d06718b..0000000
--- a/drivers/mmc/wbsd.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
- *
- *  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 as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#define LOCK_CODE		0xAA
-
-#define WBSD_CONF_SWRST		0x02
-#define WBSD_CONF_DEVICE	0x07
-#define WBSD_CONF_ID_HI		0x20
-#define WBSD_CONF_ID_LO		0x21
-#define WBSD_CONF_POWER		0x22
-#define WBSD_CONF_PME		0x23
-#define WBSD_CONF_PMES		0x24
-
-#define WBSD_CONF_ENABLE	0x30
-#define WBSD_CONF_PORT_HI	0x60
-#define WBSD_CONF_PORT_LO	0x61
-#define WBSD_CONF_IRQ		0x70
-#define WBSD_CONF_DRQ		0x74
-
-#define WBSD_CONF_PINS		0xF0
-
-#define DEVICE_SD		0x03
-
-#define WBSD_PINS_DAT3_HI	0x20
-#define WBSD_PINS_DAT3_OUT	0x10
-#define WBSD_PINS_GP11_HI	0x04
-#define WBSD_PINS_DETECT_GP11	0x02
-#define WBSD_PINS_DETECT_DAT3	0x01
-
-#define WBSD_CMDR		0x00
-#define WBSD_DFR		0x01
-#define WBSD_EIR		0x02
-#define WBSD_ISR		0x03
-#define WBSD_FSR		0x04
-#define WBSD_IDXR		0x05
-#define WBSD_DATAR		0x06
-#define WBSD_CSR		0x07
-
-#define WBSD_EINT_CARD		0x40
-#define WBSD_EINT_FIFO_THRE	0x20
-#define WBSD_EINT_CCRC		0x10
-#define WBSD_EINT_TIMEOUT	0x08
-#define WBSD_EINT_PROGEND	0x04
-#define WBSD_EINT_CRC		0x02
-#define WBSD_EINT_TC		0x01
-
-#define WBSD_INT_PENDING	0x80
-#define WBSD_INT_CARD		0x40
-#define WBSD_INT_FIFO_THRE	0x20
-#define WBSD_INT_CRC		0x10
-#define WBSD_INT_TIMEOUT	0x08
-#define WBSD_INT_PROGEND	0x04
-#define WBSD_INT_BUSYEND	0x02
-#define WBSD_INT_TC		0x01
-
-#define WBSD_FIFO_EMPTY		0x80
-#define WBSD_FIFO_FULL		0x40
-#define WBSD_FIFO_EMTHRE	0x20
-#define WBSD_FIFO_FUTHRE	0x10
-#define WBSD_FIFO_SZMASK	0x0F
-
-#define WBSD_MSLED		0x20
-#define WBSD_POWER_N		0x10
-#define WBSD_WRPT		0x04
-#define WBSD_CARDPRESENT	0x01
-
-#define WBSD_IDX_CLK		0x01
-#define WBSD_IDX_PBSMSB		0x02
-#define WBSD_IDX_TAAC		0x03
-#define WBSD_IDX_NSAC		0x04
-#define WBSD_IDX_PBSLSB		0x05
-#define WBSD_IDX_SETUP		0x06
-#define WBSD_IDX_DMA		0x07
-#define WBSD_IDX_FIFOEN		0x08
-#define WBSD_IDX_STATUS		0x10
-#define WBSD_IDX_RSPLEN		0x1E
-#define WBSD_IDX_RESP0		0x1F
-#define WBSD_IDX_RESP1		0x20
-#define WBSD_IDX_RESP2		0x21
-#define WBSD_IDX_RESP3		0x22
-#define WBSD_IDX_RESP4		0x23
-#define WBSD_IDX_RESP5		0x24
-#define WBSD_IDX_RESP6		0x25
-#define WBSD_IDX_RESP7		0x26
-#define WBSD_IDX_RESP8		0x27
-#define WBSD_IDX_RESP9		0x28
-#define WBSD_IDX_RESP10		0x29
-#define WBSD_IDX_RESP11		0x2A
-#define WBSD_IDX_RESP12		0x2B
-#define WBSD_IDX_RESP13		0x2C
-#define WBSD_IDX_RESP14		0x2D
-#define WBSD_IDX_RESP15		0x2E
-#define WBSD_IDX_RESP16		0x2F
-#define WBSD_IDX_CRCSTATUS	0x30
-#define WBSD_IDX_ISR		0x3F
-
-#define WBSD_CLK_375K		0x00
-#define WBSD_CLK_12M		0x01
-#define WBSD_CLK_16M		0x02
-#define WBSD_CLK_24M		0x03
-
-#define WBSD_DATA_WIDTH		0x01
-
-#define WBSD_DAT3_H		0x08
-#define WBSD_FIFO_RESET		0x04
-#define WBSD_SOFT_RESET		0x02
-#define WBSD_INC_INDEX		0x01
-
-#define WBSD_DMA_SINGLE		0x02
-#define WBSD_DMA_ENABLE		0x01
-
-#define WBSD_FIFOEN_EMPTY	0x20
-#define WBSD_FIFOEN_FULL	0x10
-#define WBSD_FIFO_THREMASK	0x0F
-
-#define WBSD_BLOCK_READ		0x80
-#define WBSD_BLOCK_WRITE	0x40
-#define WBSD_BUSY		0x20
-#define WBSD_CARDTRAFFIC	0x04
-#define WBSD_SENDCMD		0x02
-#define WBSD_RECVRES		0x01
-
-#define WBSD_RSP_SHORT		0x00
-#define WBSD_RSP_LONG		0x01
-
-#define WBSD_CRC_MASK		0x1F
-#define WBSD_CRC_OK		0x05 /* S010E (00101) */
-#define WBSD_CRC_FAIL		0x0B /* S101E (01011) */
-
-#define WBSD_DMA_SIZE		65536
-
-struct wbsd_host
-{
-	struct mmc_host*	mmc;		/* MMC structure */
-
-	spinlock_t		lock;		/* Mutex */
-
-	int			flags;		/* Driver states */
-
-#define WBSD_FCARD_PRESENT	(1<<0)		/* Card is present */
-#define WBSD_FIGNORE_DETECT	(1<<1)		/* Ignore card detection */
-
-	struct mmc_request*	mrq;		/* Current request */
-
-	u8			isr;		/* Accumulated ISR */
-
-	struct scatterlist*	cur_sg;		/* Current SG entry */
-	unsigned int		num_sg;		/* Number of entries left */
-
-	unsigned int		offset;		/* Offset into current entry */
-	unsigned int		remain;		/* Data left in curren entry */
-
-	int			size;		/* Total size of transfer */
-
-	char*			dma_buffer;	/* ISA DMA buffer */
-	dma_addr_t		dma_addr;	/* Physical address for same */
-
-	int			firsterr;	/* See fifo functions */
-
-	u8			clk;		/* Current clock speed */
-	unsigned char		bus_width;	/* Current bus width */
-
-	int			config;		/* Config port */
-	u8			unlock_code;	/* Code to unlock config */
-
-	int			chip_id;	/* ID of controller */
-
-	int			base;		/* I/O port base */
-	int			irq;		/* Interrupt */
-	int			dma;		/* DMA channel */
-
-	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
-	struct tasklet_struct	fifo_tasklet;
-	struct tasklet_struct	crc_tasklet;
-	struct tasklet_struct	timeout_tasklet;
-	struct tasklet_struct	finish_tasklet;
-	struct tasklet_struct	block_tasklet;
-
-	struct timer_list	ignore_timer;	/* Ignore detection timer */
-};
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 26f75c2..c1b47db 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -1,8 +1,6 @@
 # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $
 
-menu "Memory Technology Devices (MTD)"
-
-config MTD
+menuconfig MTD
 	tristate "Memory Technology Device (MTD) support"
 	help
 	  Memory Technology Devices are flash, RAM and similar chips, often
@@ -13,9 +11,10 @@ config MTD
 	  them. It will also allow you to select individual drivers for
 	  particular hardware and users of MTD devices. If unsure, say N.
 
+if MTD
+
 config MTD_DEBUG
 	bool "Debugging"
-	depends on MTD
 	help
 	  This turns on low-level debugging for the entire MTD sub-system.
 	  Normally, you should say 'N'.
@@ -29,7 +28,6 @@ config MTD_DEBUG_VERBOSE
 
 config MTD_CONCAT
 	tristate "MTD concatenating support"
-	depends on MTD
 	help
 	  Support for concatenating several MTD devices into a single
 	  (virtual) one. This allows you to have -for example- a JFFS(2)
@@ -38,7 +36,6 @@ config MTD_CONCAT
 
 config MTD_PARTITIONS
 	bool "MTD partitioning support"
-	depends on MTD
 	help
 	  If you have a device which needs to divide its flash chip(s) up
 	  into multiple 'partitions', each of which appears to the user as
@@ -153,11 +150,9 @@ config MTD_AFS_PARTS
 	  'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
 comment "User Modules And Translation Layers"
-	depends on MTD
 
 config MTD_CHAR
 	tristate "Direct char device access to MTD devices"
-	depends on MTD
 	help
 	  This provides a character device for each MTD device present in
 	  the system, allowing the user to read and write directly to the
@@ -166,12 +161,12 @@ config MTD_CHAR
 
 config MTD_BLKDEVS
 	tristate "Common interface to block layer for MTD 'translation layers'"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	default n
 
 config MTD_BLOCK
 	tristate "Caching block device access to MTD devices"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	---help---
 	  Although most flash chips have an erase size too large to be useful
@@ -194,7 +189,7 @@ config MTD_BLOCK
 
 config MTD_BLOCK_RO
 	tristate "Readonly block device access to MTD devices"
-	depends on MTD_BLOCK!=y && MTD && BLOCK
+	depends on MTD_BLOCK!=y && BLOCK
 	select MTD_BLKDEVS
 	help
 	  This allows you to mount read-only file systems (such as cramfs)
@@ -206,7 +201,7 @@ config MTD_BLOCK_RO
 
 config FTL
 	tristate "FTL (Flash Translation Layer) support"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	---help---
 	  This provides support for the original Flash Translation Layer which
@@ -223,7 +218,7 @@ config FTL
 
 config NFTL
 	tristate "NFTL (NAND Flash Translation Layer) support"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	---help---
 	  This provides support for the NAND Flash Translation Layer which is
@@ -247,7 +242,7 @@ config NFTL_RW
 
 config INFTL
 	tristate "INFTL (Inverse NAND Flash Translation Layer) support"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	---help---
 	  This provides support for the Inverse NAND Flash Translation
@@ -265,7 +260,7 @@ config INFTL
 
 config RFD_FTL
         tristate "Resident Flash Disk (Flash Translation Layer) support"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	---help---
 	  This provides support for the flash translation layer known
@@ -276,7 +271,7 @@ config RFD_FTL
 
 config SSFDC
 	tristate "NAND SSFDC (SmartMedia) read only translation layer"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	select MTD_BLKDEVS
 	help
 	  This enables read only access to SmartMedia formatted NAND
@@ -292,5 +287,6 @@ source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/onenand/Kconfig"
 
-endmenu
+source "drivers/mtd/ubi/Kconfig"
 
+endif # MTD
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index c130e62..9205540 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -28,3 +28,5 @@ nftl-objs		:= nftlcore.o nftlmount.o
 inftl-objs		:= inftlcore.o inftlmount.o
 
 obj-y		+= chips/ maps/ devices/ nand/ onenand/
+
+obj-$(CONFIG_MTD_UBI)		+= ubi/
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 72e6d73..d28e0fc 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers"
 
 config MTD_CFI
 	tristate "Detect flash chips by Common Flash Interface (CFI) probe"
-	depends on MTD
 	select MTD_GEN_PROBE
 	help
 	  The Common Flash Interface specification was developed by Intel,
@@ -18,7 +17,6 @@ config MTD_CFI
 
 config MTD_JEDECPROBE
 	tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
-	depends on MTD
 	select MTD_GEN_PROBE
 	help
 	  This option enables JEDEC-style probing of flash chips which are not
@@ -213,21 +211,18 @@ config MTD_CFI_UTIL
 
 config MTD_RAM
 	tristate "Support for RAM chips in bus mapping"
-	depends on MTD
 	help
 	  This option enables basic support for RAM chips accessed through
 	  a bus mapping driver.
 
 config MTD_ROM
 	tristate "Support for ROM chips in bus mapping"
-	depends on MTD
 	help
 	  This option enables basic support for ROM chips accessed through
 	  a bus mapping driver.
 
 config MTD_ABSENT
 	tristate "Support for absent chips in bus mapping"
-	depends on MTD
 	help
 	  This option enables support for a dummy probing driver used to
 	  allocated placeholder MTD devices on systems that have socketed
@@ -237,7 +232,6 @@ config MTD_ABSENT
 	  with this driver will return -ENODEV upon access.
 
 config MTD_OBSOLETE_CHIPS
-	depends on MTD
 	bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
 	help
 	  This option does not enable any code directly, but will allow you to
@@ -250,7 +244,7 @@ config MTD_OBSOLETE_CHIPS
 
 config MTD_AMDSTD
 	tristate "AMD compatible flash chip support (non-CFI)"
-	depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
+	depends on MTD_OBSOLETE_CHIPS && BROKEN
 	help
 	  This option enables support for flash chips using AMD-compatible
 	  commands, including some which are not CFI-compatible and hence
@@ -260,7 +254,7 @@ config MTD_AMDSTD
 
 config MTD_SHARP
 	tristate "pre-CFI Sharp chip support"
-	depends on MTD && MTD_OBSOLETE_CHIPS
+	depends on MTD_OBSOLETE_CHIPS
 	help
 	  This option enables support for flash chips using Sharp-compatible
 	  commands, including some which are not CFI-compatible and hence
@@ -268,7 +262,7 @@ config MTD_SHARP
 
 config MTD_JEDEC
 	tristate "JEDEC device support"
-	depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
+	depends on MTD_OBSOLETE_CHIPS && BROKEN
 	help
 	  Enable older JEDEC flash interface devices for self
 	  programming flash.  It is commonly used in older AMD chips.  It is
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index f334959..2f19fa7 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -15,6 +15,8 @@
  *	- optimized write buffer method
  * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
  *	- reworked lock/unlock/erase support for var size flash
+ * 21/03/2007   Rodolfo Giometti <giometti@linux.it>
+ * 	- auto unlock sectors on resume for auto locking flash on power up
  */
 
 #include <linux/module.h>
@@ -30,6 +32,7 @@ #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
+#include <linux/bitmap.h>
 #include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(stru
 	}
 }
 
+/*
+ * Some chips power-up with all sectors locked by default.
+ */
+static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+{
+	printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+	mtd->flags |= MTD_STUPID_LOCK;
+}
+
 static struct cfi_fixup cfi_fixup_table[] = {
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
@@ -232,6 +244,7 @@ #if !FORCE_WORD_WRITE
 #endif
 	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
 	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
+	{ MANUFACTURER_INTEL, 0x891c,	      fixup_use_powerup_lock, NULL, },
 	{ 0, 0, NULL, NULL }
 };
 
@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_set
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL);
 		}
 		offset += (ersize * ernum);
 	}
@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mt
 	}
 }
 
-#ifdef DEBUG_LOCK_BITS
-static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+static int __xipram do_getlockstatus_oneblock(struct map_info *map,
 						struct flchip *chip,
 						unsigned long adr,
 						int len, void *thunk)
@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_o
 	chip->state = FL_JEDEC_QUERY;
 	status = cfi_read_query(map, adr+(2*ofs_factor));
 	xip_enable(map, chip, 0);
+	return status;
+}
+
+#ifdef DEBUG_LOCK_BITS
+static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+						struct flchip *chip,
+						unsigned long adr,
+						int len, void *thunk)
+{
 	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
-	       adr, status);
+	       adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk));
 	return 0;
 }
 #endif
@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_in
 
 #endif
 
+static void cfi_intelext_save_locks(struct mtd_info *mtd)
+{
+	struct mtd_erase_region_info *region;
+	int block, status, i;
+	unsigned long adr;
+	size_t len;
+
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		region = &mtd->eraseregions[i];
+		if (!region->lockmap)
+			continue;
+
+		for (block = 0; block < region->numblocks; block++){
+			len = region->erasesize;
+			adr = region->offset + block * len;
+
+			status = cfi_varsize_frob(mtd,
+					do_getlockstatus_oneblock, adr, len, 0);
+			if (status)
+				set_bit(block, region->lockmap);
+			else
+				clear_bit(block, region->lockmap);
+		}
+	}
+}
+
 static int cfi_intelext_suspend(struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 	int i;
 	struct flchip *chip;
 	int ret = 0;
 
+	if ((mtd->flags & MTD_STUPID_LOCK)
+	    && extp && (extp->FeatureSupport & (1 << 5)))
+		cfi_intelext_save_locks(mtd);
+
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
 
@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct m
 	return ret;
 }
 
+static void cfi_intelext_restore_locks(struct mtd_info *mtd)
+{
+	struct mtd_erase_region_info *region;
+	int block, i;
+	unsigned long adr;
+	size_t len;
+
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		region = &mtd->eraseregions[i];
+		if (!region->lockmap)
+			continue;
+
+		for (block = 0; block < region->numblocks; block++) {
+			len = region->erasesize;
+			adr = region->offset + block * len;
+
+			if (!test_bit(block, region->lockmap))
+				cfi_intelext_unlock(mtd, adr, len);
+		}
+	}
+}
+
 static void cfi_intelext_resume(struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 	int i;
 	struct flchip *chip;
 
@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct m
 
 		spin_unlock(chip->mutex);
 	}
+
+	if ((mtd->flags & MTD_STUPID_LOCK)
+	    && extp && (extp->FeatureSupport & (1 << 5)))
+		cfi_intelext_restore_locks(mtd);
 }
 
 static int cfi_intelext_reset(struct mtd_info *mtd)
@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct 
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_erase_region_info *region;
+	int i;
 	cfi_intelext_reset(mtd);
 	unregister_reboot_notifier(&mtd->reboot_notifier);
 	kfree(cfi->cmdset_priv);
 	kfree(cfi->cfiq);
 	kfree(cfi->chips[0].priv);
 	kfree(cfi);
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		region = &mtd->eraseregions[i];
+		if (region->lockmap)
+			kfree(region->lockmap);
+	}
 	kfree(mtd->eraseregions);
 }
 
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index 77303ce..ab44f2b 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -65,11 +65,12 @@ static int fwh_xxlock_oneblock(struct ma
 		return ret;
 	}
 
+	chip->oldstate = chip->state;
 	chip->state = xxlt->state;
 	map_write(map, CMD(xxlt->val), adr);
 
 	/* Done and happy. */
-	chip->state = FL_READY;
+	chip->state = chip->oldstate;
 	put_chip(map, chip, adr);
 	spin_unlock(chip->mutex);
 	return 0;
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 440f685..ff642f8 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers"
 
 config MTD_PMC551
 	tristate "Ramix PMC551 PCI Mezzanine RAM card support"
-	depends on MTD && PCI
+	depends on PCI
 	---help---
 	  This provides a MTD device driver for the Ramix PMC551 RAM PCI card
 	  from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
@@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG
 
 config MTD_MS02NV
 	tristate "DEC MS02-NV NVRAM module support"
-	depends on MTD && MACH_DECSTATION
+	depends on MACH_DECSTATION
 	help
 	  This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
 	  backed-up NVRAM module.  The module was originally meant as an NFS
@@ -49,20 +49,28 @@ config MTD_MS02NV
 
 	  If you want to compile this driver as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/modules.txt>.  The module will
-	  be called ms02-nv.o.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.
+	  The module will be called ms02-nv.ko.
 
 config MTD_DATAFLASH
 	tristate "Support for AT45xxx DataFlash"
-	depends on MTD && SPI_MASTER && EXPERIMENTAL
+	depends on SPI_MASTER && EXPERIMENTAL
 	help
 	  This enables access to AT45xxx DataFlash chips, using SPI.
 	  Sometimes DataFlash chips are packaged inside MMC-format
 	  cards; at this writing, the MMC stack won't handle those.
 
+config MTD_DATAFLASH26
+	tristate "AT91RM9200 DataFlash AT26xxx"
+	depends on MTD && ARCH_AT91RM9200 && AT91_SPI
+	help
+	  This enables access to the DataFlash chip (AT26xxx) on an
+	  AT91RM9200-based board.
+	  If you have such a board and such a DataFlash, say 'Y'.
+
 config MTD_M25P80
 	tristate "Support for M25 SPI Flash"
-	depends on MTD && SPI_MASTER && EXPERIMENTAL
+	depends on SPI_MASTER && EXPERIMENTAL
 	help
 	  This enables access to ST M25P80 and similar SPI flash chips,
 	  used for program and data storage.  Set up your spi devices
@@ -70,7 +78,6 @@ config MTD_M25P80
 
 config MTD_SLRAM
 	tristate "Uncached system RAM"
-	depends on MTD
 	help
 	  If your CPU cannot cache all of the physical memory in your machine,
 	  you can still use it for storage or swap by using this driver to
@@ -78,7 +85,6 @@ config MTD_SLRAM
 
 config MTD_PHRAM
 	tristate "Physical system RAM"
-	depends on MTD
 	help
 	  This is a re-implementation of the slram driver above.
 
@@ -88,7 +94,7 @@ config MTD_PHRAM
 
 config MTD_LART
 	tristate "28F160xx flash driver for LART"
-	depends on SA1100_LART && MTD
+	depends on SA1100_LART
 	help
 	  This enables the flash driver for LART. Please note that you do
 	  not need any mapping/chip driver for LART. This one does it all
@@ -96,7 +102,6 @@ config MTD_LART
 
 config MTD_MTDRAM
 	tristate "Test driver using RAM"
-	depends on MTD
 	help
 	  This enables a test MTD device driver which uses vmalloc() to
 	  provide storage.  You probably want to say 'N' unless you're
@@ -136,7 +141,7 @@ config MTDRAM_ABS_POS
 
 config MTD_BLOCK2MTD
 	tristate "MTD using block device"
-	depends on MTD && BLOCK
+	depends on BLOCK
 	help
 	  This driver allows a block device to appear as an MTD. It would
 	  generally be used in the following cases:
@@ -150,7 +155,6 @@ comment "Disk-On-Chip Device Drivers"
 
 config MTD_DOC2000
 	tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
-	depends on MTD
 	select MTD_DOCPROBE
 	select MTD_NAND_IDS
 	---help---
@@ -173,7 +177,6 @@ config MTD_DOC2000
 
 config MTD_DOC2001
 	tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
-	depends on MTD
 	select MTD_DOCPROBE
 	select MTD_NAND_IDS
 	---help---
@@ -195,7 +198,6 @@ config MTD_DOC2001
 
 config MTD_DOC2001PLUS
 	tristate "M-Systems Disk-On-Chip Millennium Plus"
-	depends on MTD
 	select MTD_DOCPROBE
 	select MTD_NAND_IDS
 	---help---
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 0f788d5..8ab568b 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,4 +16,5 @@ obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
+obj-$(CONFIG_MTD_DATAFLASH26)	+= at91_dataflash26.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c
new file mode 100644
index 0000000..64ce37f
--- /dev/null
+++ b/drivers/mtd/devices/at91_dataflash26.c
@@ -0,0 +1,485 @@
+/*
+ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
+ * This is a largely modified version of at91_dataflash.c that
+ * supports AT26xxx dataflash chips. The original driver supports
+ * AT45xxx chips.
+ *
+ * Note: This driver was only tested with an AT26F004. It should be
+ * easy to make it work with other AT26xxx dataflash devices, though.
+ *
+ * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * original Copyright (C) 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
+ * version 2 as published by the Free Software Foundation.
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+
+#include <asm/arch/at91_spi.h>
+
+#define DATAFLASH_MAX_DEVICES	4	/* max number of dataflash devices */
+
+#define MANUFACTURER_ID_ATMEL		0x1F
+
+/* command codes */
+
+#define AT26_OP_READ_STATUS		0x05
+#define AT26_OP_READ_DEV_ID		0x9F
+#define AT26_OP_ERASE_PAGE_4K		0x20
+#define AT26_OP_READ_ARRAY_FAST		0x0B
+#define AT26_OP_SEQUENTIAL_WRITE	0xAF
+#define AT26_OP_WRITE_ENABLE		0x06
+#define AT26_OP_WRITE_DISABLE		0x04
+#define AT26_OP_SECTOR_PROTECT		0x36
+#define AT26_OP_SECTOR_UNPROTECT	0x39
+
+/* status register bits */
+
+#define AT26_STATUS_BUSY		0x01
+#define AT26_STATUS_WRITE_ENABLE	0x02
+
+struct dataflash_local
+{
+	int spi;			/* SPI chip-select number */
+	unsigned int page_size;		/* number of bytes per page */
+};
+
+
+/* Detected DataFlash devices */
+static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
+static int nr_devices = 0;
+
+/* Allocate a single SPI transfer descriptor.  We're assuming that if multiple
+   SPI transfers occur at the same time, spi_access_bus() will serialize them.
+   If this is not valid, then either (i) each dataflash 'priv' structure
+   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
+   another mechanism.   */
+static struct spi_transfer_list* spi_transfer_desc;
+
+/*
+ * Perform a SPI transfer to access the DataFlash device.
+ */
+static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
+		char* txnext, int txnext_len, char* rxnext, int rxnext_len)
+{
+	struct spi_transfer_list* list = spi_transfer_desc;
+
+	list->tx[0] = tx;	list->txlen[0] = tx_len;
+	list->rx[0] = rx;	list->rxlen[0] = rx_len;
+
+	list->tx[1] = txnext; 	list->txlen[1] = txnext_len;
+	list->rx[1] = rxnext;	list->rxlen[1] = rxnext_len;
+
+	list->nr_transfers = nr;
+	/* Note: spi_transfer() always returns 0, there are no error checks */
+	return spi_transfer(list);
+}
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static unsigned char at91_dataflash26_status(void)
+{
+	unsigned char command[2];
+
+	command[0] = AT26_OP_READ_STATUS;
+	command[1] = 0;
+
+	do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
+
+	return command[1];
+}
+
+/*
+ * Poll the DataFlash device until it is READY.
+ */
+static unsigned char at91_dataflash26_waitready(void)
+{
+	unsigned char status;
+
+	while (1) {
+		status = at91_dataflash26_status();
+		if (!(status & AT26_STATUS_BUSY))
+			return status;
+	}
+}
+
+/*
+ * Enable/disable write access
+ */
+ static void at91_dataflash26_write_enable(int enable)
+{
+	unsigned char cmd[2];
+
+	DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
+
+	if (enable)
+		cmd[0] = AT26_OP_WRITE_ENABLE;
+	else
+		cmd[0] = AT26_OP_WRITE_DISABLE;
+	cmd[1] = 0;
+
+	do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
+}
+
+/*
+ * Protect/unprotect sector
+ */
+ static void at91_dataflash26_sector_protect(loff_t addr, int protect)
+{
+	unsigned char cmd[4];
+
+	DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
+	       addr, protect);
+
+	if (protect)
+		cmd[0] = AT26_OP_SECTOR_PROTECT;
+	else
+		cmd[0] = AT26_OP_SECTOR_UNPROTECT;
+	cmd[1] = (addr & 0x00FF0000) >> 16;
+	cmd[2] = (addr & 0x0000FF00) >> 8;
+	cmd[3] = (addr & 0x000000FF);
+
+	do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
+}
+
+/*
+ * Erase blocks of flash.
+ */
+static int at91_dataflash26_erase(struct mtd_info *mtd,
+				  struct erase_info *instr)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned char cmd[4];
+
+	DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
+	       instr->addr, instr->len);
+
+	/* Sanity checks */
+	if (priv->page_size != 4096)
+		return -EINVAL; /* Can't handle other sizes at the moment */
+
+	if (   ((instr->len % mtd->erasesize) != 0)
+	    || ((instr->len % priv->page_size) != 0)
+	    || ((instr->addr % priv->page_size) != 0)
+	    || ((instr->addr + instr->len) > mtd->size))
+		return -EINVAL;
+
+	spi_access_bus(priv->spi);
+
+	while (instr->len > 0) {
+		at91_dataflash26_write_enable(1);
+		at91_dataflash26_sector_protect(instr->addr, 0);
+		at91_dataflash26_write_enable(1);
+		cmd[0] = AT26_OP_ERASE_PAGE_4K;
+		cmd[1] = (instr->addr & 0x00FF0000) >> 16;
+		cmd[2] = (instr->addr & 0x0000FF00) >> 8;
+		cmd[3] = (instr->addr & 0x000000FF);
+
+		DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
+					"0x%02x\n",
+			cmd[0], cmd[1], cmd[2], cmd[3]);
+
+		do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
+		at91_dataflash26_waitready();
+
+		instr->addr += priv->page_size;	 /* next page */
+		instr->len -= priv->page_size;
+	}
+
+	at91_dataflash26_write_enable(0);
+	spi_release_bus(priv->spi);
+
+	/* Inform MTD subsystem that erase is complete */
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+
+	return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ *   from   : Start offset in flash device
+ *   len    : Number of bytes to read
+ *   retlen : Number of bytes actually read
+ *   buf    : Buffer that will receive data
+ */
+static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
+				 size_t *retlen, u_char *buf)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned char cmd[5];
+
+	DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
+	      from, from+len);
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	cmd[0] = AT26_OP_READ_ARRAY_FAST;
+	cmd[1] = (from & 0x00FF0000) >> 16;
+	cmd[2] = (from & 0x0000FF00) >> 8;
+	cmd[3] = (from & 0x000000FF);
+	/* cmd[4] is a "Don't care" byte  */
+
+	DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
+	       cmd[0], cmd[1], cmd[2], cmd[3]);
+
+	spi_access_bus(priv->spi);
+	do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
+	spi_release_bus(priv->spi);
+
+	*retlen = len;
+	return 0;
+}
+
+/*
+ * Write to the DataFlash device.
+ *   to     : Start offset in flash device
+ *   len    : Number of bytes to write
+ *   retlen : Number of bytes actually written
+ *   buf    : Buffer containing the data
+ */
+static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
+				  size_t *retlen, const u_char *buf)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned int addr, buf_index = 0;
+	int ret = -EIO, sector, last_sector;
+	unsigned char status, cmd[5];
+
+	DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	spi_access_bus(priv->spi);
+
+	addr = to;
+	last_sector = -1;
+
+	while (buf_index < len) {
+		sector = addr / priv->page_size;
+		/* Write first byte if a new sector begins */
+		if (sector != last_sector) {
+			at91_dataflash26_write_enable(1);
+			at91_dataflash26_sector_protect(addr, 0);
+			at91_dataflash26_write_enable(1);
+
+			/* Program first byte of a new sector */
+			cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
+			cmd[1] = (addr & 0x00FF0000) >> 16;
+			cmd[2] = (addr & 0x0000FF00) >> 8;
+			cmd[3] = (addr & 0x000000FF);
+			cmd[4] = buf[buf_index++];
+			do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
+			status = at91_dataflash26_waitready();
+			addr++;
+			/* On write errors, the chip resets the write enable
+			   flag. This also happens after the last byte of a
+			   sector is successfully programmed. */
+			if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
+			    && ((addr % priv->page_size) != 0) ) {
+				DEBUG(MTD_DEBUG_LEVEL1,
+					"write error1: addr=0x%06x, "
+					"status=0x%02x\n", addr, status);
+				goto write_err;
+			}
+			(*retlen)++;
+			last_sector = sector;
+		}
+
+		/* Write subsequent bytes in the same sector */
+		cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
+		cmd[1] = buf[buf_index++];
+		do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
+		status = at91_dataflash26_waitready();
+		addr++;
+
+		if (   ( !(status & AT26_STATUS_WRITE_ENABLE))
+		    && ((addr % priv->page_size) != 0) ) {
+			DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
+				"status=0x%02x\n", addr, status);
+			goto write_err;
+		}
+
+		(*retlen)++;
+	}
+
+	ret = 0;
+	at91_dataflash26_write_enable(0);
+write_err:
+	spi_release_bus(priv->spi);
+	return ret;
+}
+
+/*
+ * Initialize and register DataFlash device with MTD subsystem.
+ */
+static int __init add_dataflash(int channel, char *name, int nr_pages,
+				int pagesize)
+{
+	struct mtd_info *device;
+	struct dataflash_local *priv;
+
+	if (nr_devices >= DATAFLASH_MAX_DEVICES) {
+		printk(KERN_ERR "at91_dataflash26: Too many devices "
+				"detected\n");
+		return 0;
+	}
+
+	device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
+			 GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+
+	device->name = (char *)&device[1];
+	sprintf(device->name, "%s.spi%d", name, channel);
+	device->size = nr_pages * pagesize;
+	device->erasesize = pagesize;
+	device->owner = THIS_MODULE;
+	device->type = MTD_DATAFLASH;
+	device->flags = MTD_CAP_NORFLASH;
+	device->erase = at91_dataflash26_erase;
+	device->read = at91_dataflash26_read;
+	device->write = at91_dataflash26_write;
+
+	priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
+		GFP_KERNEL);
+	if (!priv) {
+		kfree(device);
+		return -ENOMEM;
+	}
+
+	priv->spi = channel;
+	priv->page_size = pagesize;
+	device->priv = priv;
+
+	mtd_devices[nr_devices] = device;
+	nr_devices++;
+	printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
+	       name, channel, device->size);
+
+	return add_mtd_device(device);
+}
+
+/*
+ * Detect and initialize DataFlash device connected to specified SPI channel.
+ *
+ */
+
+struct dataflash26_types {
+	unsigned char id0;
+	unsigned char id1;
+	char *name;
+	int pagesize;
+	int nr_pages;
+};
+
+struct dataflash26_types df26_types[] = {
+	{
+		.id0 = 0x04,
+		.id1 = 0x00,
+		.name = "AT26F004",
+		.pagesize = 4096,
+		.nr_pages = 128,
+	},
+	{
+		.id0 = 0x45,
+		.id1 = 0x01,
+		.name = "AT26DF081A", /* Not tested ! */
+		.pagesize = 4096,
+		.nr_pages = 256,
+	},
+};
+
+static int __init at91_dataflash26_detect(int channel)
+{
+	unsigned char status, cmd[5];
+	int i;
+
+	spi_access_bus(channel);
+	status = at91_dataflash26_status();
+
+	if (status == 0 || status == 0xff) {
+		printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
+			status);
+		spi_release_bus(channel);
+		return -ENODEV;
+	}
+
+	cmd[0] = AT26_OP_READ_DEV_ID;
+	do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
+	spi_release_bus(channel);
+
+	if (cmd[1] != MANUFACTURER_ID_ATMEL)
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
+		if (   cmd[2] == df26_types[i].id0
+		    && cmd[3] == df26_types[i].id1)
+			return add_dataflash(channel,
+						df26_types[i].name,
+						df26_types[i].nr_pages,
+						df26_types[i].pagesize);
+	}
+
+	printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
+			"(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
+	return -ENODEV;
+}
+
+static int __init at91_dataflash26_init(void)
+{
+	spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
+				    GFP_KERNEL);
+	if (!spi_transfer_desc)
+		return -ENOMEM;
+
+	/* DataFlash (SPI chip select 0) */
+	at91_dataflash26_detect(0);
+
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	/* DataFlash card (SPI chip select 3) */
+	at91_dataflash26_detect(3);
+#endif
+	return 0;
+}
+
+static void __exit at91_dataflash26_exit(void)
+{
+	int i;
+
+	for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
+		if (mtd_devices[i]) {
+			del_mtd_device(mtd_devices[i]);
+			kfree(mtd_devices[i]->priv);
+			kfree(mtd_devices[i]);
+		}
+	}
+	nr_devices = 0;
+	kfree(spi_transfer_desc);
+}
+
+module_init(at91_dataflash26_init);
+module_exit(at91_dataflash26_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hans J. Koch");
+MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index f9f2ce7..fc4cc8b 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -40,60 +40,11 @@ struct block2mtd_dev {
 static LIST_HEAD(blkmtd_device_list);
 
 
-#define PAGE_READAHEAD 64
-static void cache_readahead(struct address_space *mapping, int index)
+static struct page *page_read(struct address_space *mapping, int index)
 {
-	filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-	int i, pagei;
-	unsigned ret = 0;
-	unsigned long end_index;
-	struct page *page;
-	LIST_HEAD(page_pool);
-	struct inode *inode = mapping->host;
-	loff_t isize = i_size_read(inode);
-
-	if (!isize) {
-		INFO("iSize=0 in cache_readahead\n");
-		return;
-	}
-
-	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
-
-	read_lock_irq(&mapping->tree_lock);
-	for (i = 0; i < PAGE_READAHEAD; i++) {
-		pagei = index + i;
-		if (pagei > end_index) {
-			INFO("Overrun end of disk in cache readahead\n");
-			break;
-		}
-		page = radix_tree_lookup(&mapping->page_tree, pagei);
-		if (page && (!i))
-			break;
-		if (page)
-			continue;
-		read_unlock_irq(&mapping->tree_lock);
-		page = page_cache_alloc_cold(mapping);
-		read_lock_irq(&mapping->tree_lock);
-		if (!page)
-			break;
-		page->index = pagei;
-		list_add(&page->lru, &page_pool);
-		ret++;
-	}
-	read_unlock_irq(&mapping->tree_lock);
-	if (ret)
-		read_cache_pages(mapping, &page_pool, filler, NULL);
+	return read_mapping_page(mapping, index, NULL);
 }
 
-
-static struct page* page_readahead(struct address_space *mapping, int index)
-{
-	filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-	cache_readahead(mapping, index);
-	return read_cache_page(mapping, index, filler, NULL);
-}
-
-
 /* erase a specified part of the device */
 static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
 {
@@ -105,14 +56,14 @@ static int _block2mtd_erase(struct block
 	u_long *max;
 
 	while (pages) {
-		page = page_readahead(mapping, index);
+		page = page_read(mapping, index);
 		if (!page)
 			return -ENOMEM;
 		if (IS_ERR(page))
 			return PTR_ERR(page);
 
-		max = (u_long*)page_address(page) + PAGE_SIZE;
-		for (p=(u_long*)page_address(page); p<max; p++)
+		max = page_address(page) + PAGE_SIZE;
+		for (p=page_address(page); p<max; p++)
 			if (*p != -1UL) {
 				lock_page(page);
 				memset(page_address(page), 0xff, PAGE_SIZE);
@@ -174,8 +125,7 @@ static int block2mtd_read(struct mtd_inf
 			cpylen = len;	// this page
 		len = len - cpylen;
 
-		//      Get page
-		page = page_readahead(dev->blkdev->bd_inode->i_mapping, index);
+		page = page_read(dev->blkdev->bd_inode->i_mapping, index);
 		if (!page)
 			return -ENOMEM;
 		if (IS_ERR(page))
@@ -213,8 +163,7 @@ static int _block2mtd_write(struct block
 			cpylen = len;			// this page
 		len = len - cpylen;
 
-		//	Get page
-		page = page_readahead(mapping, index);
+		page = page_read(mapping, index);
 		if (!page)
 			return -ENOMEM;
 		if (IS_ERR(page))
@@ -308,9 +257,9 @@ #ifndef MODULE
 		/* We might not have rootfs mounted at this point. Try
 		   to resolve the device name by other means. */
 
-		dev_t dev = name_to_dev_t(devname);
-		if (dev != 0) {
-			bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ);
+		dev_t devt = name_to_dev_t(devname);
+		if (devt) {
+			bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
 		}
 	}
 #endif
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index 8a0c4de..c73e96b 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -13,7 +13,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 6f368ae..6413efc 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -13,7 +13,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 88ba82d..2b30b58 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -17,7 +17,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c
index 52b5d63..fd8a8da 100644
--- a/drivers/mtd/devices/docecc.c
+++ b/drivers/mtd/devices/docecc.c
@@ -29,7 +29,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index acf3ba2..ecac0e4 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -31,7 +31,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index bbf0553..d990d81 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -6,7 +6,6 @@ menu "Mapping drivers for chip access"
 
 config MTD_COMPLEX_MAPPINGS
 	bool "Support non-linear mappings of flash chips"
-	depends on MTD
 	help
 	  This causes the chip drivers to allow for complicated
 	  paged mappings of flash chips.
@@ -69,6 +68,39 @@ config MTD_PHYSMAP_OF
 	  physically into the CPU's memory. The mapping description here is
 	  taken from OF device tree.
 
+config MTD_PMC_MSP_EVM
+	tristate "CFI Flash device mapped on PMC-Sierra MSP"
+	depends on PMC_MSP && MTD_CFI
+	select MTD_PARTITIONS
+	help
+	  This provides a 'mapping' driver which support the way
+          in which user-programmable flash chips are connected on the
+          PMC-Sierra MSP eval/demo boards
+
+choice
+	prompt "Maximum mappable memory avialable for flash IO"
+	depends on MTD_PMC_MSP_EVM
+	default MSP_FLASH_MAP_LIMIT_32M
+
+config MSP_FLASH_MAP_LIMIT_32M
+	bool "32M"
+
+endchoice
+
+config MSP_FLASH_MAP_LIMIT
+	hex
+	default "0x02000000"
+	depends on MSP_FLASH_MAP_LIMIT_32M
+
+config MTD_PMC_MSP_RAMROOT
+	tristate "Embedded RAM block device for root on PMC-Sierra MSP"
+	depends on PMC_MSP_EMBEDDED_ROOTFS && \
+			(MTD_BLOCK || MTD_BLOCK_RO) && \
+			MTD_RAM
+	help
+	  This provides support for the embedded root file system
+          on PMC MSP devices.  This memory is mapped as a MTD block device.
+
 config MTD_SUN_UFLASH
 	tristate "Sun Microsystems userflash support"
 	depends on SPARC && MTD_CFI
@@ -240,13 +272,13 @@ config MTD_NETtel
 
 config MTD_ALCHEMY
 	tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
-	depends on SOC_AU1X00
+	depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI
 	help
 	  Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
 
 config MTD_MTX1
 	tristate "4G Systems MTX-1 Flash device"
-	depends on MIPS && MIPS_MTX1
+	depends on MIPS_MTX1 && MTD_CFI
 	help
 	  Flash memory access on 4G Systems MTX-1 Board. If you have one of
 	  these boards and would like to use the flash chips on it, say 'Y'.
@@ -384,7 +416,7 @@ config MTD_TQM834x
 
 config MTD_OCELOT
 	tristate "Momenco Ocelot boot flash device"
-	depends on MIPS && MOMENCO_OCELOT
+	depends on MOMENCO_OCELOT
 	help
 	  This enables access routines for the boot flash device and for the
 	  NVRAM on the Momenco Ocelot board. If you have one of these boards
@@ -517,7 +549,7 @@ config MTD_OMAP_NOR
 # This needs CFI or JEDEC, depending on the cards found.
 config MTD_PCI
 	tristate "PCI MTD driver"
-	depends on MTD && PCI && MTD_COMPLEX_MAPPINGS
+	depends on PCI && MTD_COMPLEX_MAPPINGS
 	help
 	  Mapping for accessing flash devices on add-in cards like the Intel XScale
 	  IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
@@ -527,7 +559,7 @@ config MTD_PCI
 
 config MTD_PCMCIA
 	tristate "PCMCIA MTD driver"
-	depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
+	depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN
 	help
 	  Map driver for accessing PCMCIA linear flash memory cards. These
 	  cards are usually around 4-16MiB in size. This does not include
@@ -591,13 +623,12 @@ config MTD_BAST_MAXSIZE
 
 config MTD_SHARP_SL
 	bool "ROM mapped on Sharp SL Series"
-	depends on MTD && ARCH_PXA
+	depends on ARCH_PXA
 	help
 	  This enables access to the flash chip on the Sharp SL Series of PDAs.
 
 config MTD_PLATRAM
 	tristate "Map driver for platform device RAM (mtd-ram)"
-	depends on MTD
 	select MTD_RAM
 	help
 	  Map driver for RAM areas described via the platform device
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 071d0bf..de036c5 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -27,6 +27,8 @@ obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)	+= physmap_of.o
+obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
+obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
 obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)	+= pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index 7fc8097..84fbe0e 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -1,10 +1,7 @@
 /*
  * Flash memory access on AMD Alchemy evaluation boards
  *
- * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $
- *
  * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- *
  */
 
 #include <linux/init.h>
@@ -18,12 +15,6 @@ #include <linux/mtd/partitions.h>
 
 #include <asm/io.h>
 
-#ifdef 	DEBUG_RW
-#define	DBG(x...)	printk(x)
-#else
-#define	DBG(x...)
-#endif
-
 #ifdef CONFIG_MIPS_PB1000
 #define BOARD_MAP_NAME "Pb1000 Flash"
 #define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 3d4a4d8..688ef49 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -338,7 +338,7 @@ static int __init init_ck804xrom(void)
 	}
 	return -ENXIO;
 #if 0
-	return pci_module_init(&ck804xrom_driver);
+	return pci_register_driver(&ck804xrom_driver);
 #endif
 }
 
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 7efe744..72107dc 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -48,7 +48,7 @@ static int parse_flash_partitions(struct
 	const  u32  *part;
 	const  char *name;
 
-	part = get_property(node, "partitions", &plen);
+	part = of_get_property(node, "partitions", &plen);
 	if (part == NULL)
 		goto err;
 
@@ -59,7 +59,7 @@ static int parse_flash_partitions(struct
 		goto err;
 	}
 
-	name = get_property(node, "partition-names", &plen);
+	name = of_get_property(node, "partition-names", &plen);
 
 	for (i = 0; i < retval; i++) {
 		(*parts)[i].offset = *part++;
@@ -153,7 +153,7 @@ static int __devinit of_physmap_probe(st
 		goto err_out;
 	}
 
-	width = get_property(dp, "bank-width", NULL);
+	width = of_get_property(dp, "bank-width", NULL);
 	if (width == NULL) {
 		dev_err(&dev->dev, "Can't get the flash bank width!\n");
 		err = -EINVAL;
@@ -174,7 +174,7 @@ static int __devinit of_physmap_probe(st
 
 	simple_map_init(&info->map);
 
-	of_probe = get_property(dp, "probe-type", NULL);
+	of_probe = of_get_property(dp, "probe-type", NULL);
 	if (of_probe == NULL) {
 		probe_type = rom_probe_types;
 		for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
index 2b6504e..894c0b2 100644
--- a/drivers/mtd/maps/plat-ram.c
+++ b/drivers/mtd/maps/plat-ram.c
@@ -169,7 +169,8 @@ static int platram_probe(struct platform
 		goto exit_free;
 	}
 
-	dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start);
+	dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res,
+		(unsigned long long)res->start);
 
 	/* setup map parameters */
 
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
new file mode 100644
index 0000000..7e0377e
--- /dev/null
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -0,0 +1,184 @@
+/*
+ * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
+ * Config with both CFI and JEDEC device support.
+ *
+ * Basically physmap.c with the addition of partitions and
+ * an array of mapping info to accomodate more than one flash type per board.
+ *
+ * Copyright 2005-2007 PMC-Sierra, 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/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#include <msp_prom.h>
+#include <msp_regs.h>
+
+
+static struct mtd_info **msp_flash;
+static struct mtd_partition **msp_parts;
+static struct map_info *msp_maps;
+static int fcnt;
+
+#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__)
+
+int __init init_msp_flash(void)
+{
+	int i, j;
+	int offset, coff;
+	char *env;
+	int pcnt;
+	char flash_name[] = "flash0";
+	char part_name[] = "flash0_0";
+	unsigned addr, size;
+
+	/* If ELB is disabled by "ful-mux" mode, we can't get at flash */
+	if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) &&
+	    (*ELB_1PC_EN_REG & SINGLE_PCCARD)) {
+		printk(KERN_NOTICE "Single PC Card mode: no flash access\n");
+		return -ENXIO;
+	}
+
+	/* examine the prom environment for flash devices */
+	for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++)
+		flash_name[5] = '0' + fcnt + 1;
+
+	if (fcnt < 1)
+		return -ENXIO;
+
+	printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
+	msp_flash = (struct mtd_info **)kmalloc(
+			fcnt * sizeof(struct map_info *), GFP_KERNEL);
+	msp_parts = (struct mtd_partition **)kmalloc(
+			fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+	msp_maps = (struct map_info *)kmalloc(
+			fcnt * sizeof(struct mtd_info), GFP_KERNEL);
+	memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
+
+	/* loop over the flash devices, initializing each */
+	for (i = 0; i < fcnt; i++) {
+		/* examine the prom environment for flash partititions */
+		part_name[5] = '0' + i;
+		part_name[7] = '0';
+		for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++)
+			part_name[7] = '0' + pcnt + 1;
+
+		if (pcnt == 0) {
+			printk(KERN_NOTICE "Skipping flash device %d "
+				"(no partitions defined)\n", i);
+			continue;
+		}
+
+		msp_parts[i] = (struct mtd_partition *)kmalloc(
+			pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
+		memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
+
+		/* now initialize the devices proper */
+		flash_name[5] = '0' + i;
+		env = prom_getenv(flash_name);
+
+		if (sscanf(env, "%x:%x", &addr, &size) < 2)
+			return -ENXIO;
+		addr = CPHYSADDR(addr);
+
+		printk(KERN_NOTICE
+			"MSP flash device \"%s\": 0x%08x at 0x%08x\n",
+			flash_name, size, addr);
+		/* This must matchs the actual size of the flash chip */
+		msp_maps[i].size = size;
+		msp_maps[i].phys = addr;
+
+		/*
+		 * Platforms have a specific limit of the size of memory
+		 * which may be mapped for flash:
+		 */
+		if (size > CONFIG_MSP_FLASH_MAP_LIMIT)
+			size = CONFIG_MSP_FLASH_MAP_LIMIT;
+		msp_maps[i].virt = ioremap(addr, size);
+		msp_maps[i].bankwidth = 1;
+		msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL),
+					flash_name, 7);
+
+		if (msp_maps[i].virt == NULL)
+			return -ENXIO;
+
+		for (j = 0; j < pcnt; j++) {
+			part_name[5] = '0' + i;
+			part_name[7] = '0' + j;
+
+			env = prom_getenv(part_name);
+
+			if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2)
+				return -ENXIO;
+
+			msp_parts[i][j].size = size;
+			msp_parts[i][j].offset = offset;
+			msp_parts[i][j].name = env + coff;
+		}
+
+		/* now probe and add the device */
+		simple_map_init(&msp_maps[i]);
+		msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]);
+		if (msp_flash[i]) {
+			msp_flash[i]->owner = THIS_MODULE;
+			add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt);
+		} else {
+			printk(KERN_ERR "map probe failed for flash\n");
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
+static void __exit cleanup_msp_flash(void)
+{
+	int i;
+
+	for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) {
+		del_mtd_partitions(msp_flash[i]);
+		map_destroy(msp_flash[i]);
+		iounmap((void *)msp_maps[i].virt);
+
+		/* free the memory */
+		kfree(msp_maps[i].name);
+		kfree(msp_parts[i]);
+	}
+
+	kfree(msp_flash);
+	kfree(msp_parts);
+	kfree(msp_maps);
+}
+
+MODULE_AUTHOR("PMC-Sierra, Inc");
+MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards");
+MODULE_LICENSE("GPL");
+
+module_init(init_msp_flash);
+module_exit(cleanup_msp_flash);
diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c
new file mode 100644
index 0000000..18049bc
--- /dev/null
+++ b/drivers/mtd/maps/pmcmsp-ramroot.c
@@ -0,0 +1,105 @@
+/*
+ * Mapping of the rootfs in a physical region of memory
+ *
+ * Copyright (C) 2005-2007 PMC-Sierra Inc.
+ * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.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/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/root_dev.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+#include <asm/io.h>
+
+#include <msp_prom.h>
+
+static struct mtd_info *rr_mtd;
+
+struct map_info rr_map = {
+	.name = "ramroot",
+	.bankwidth = 4,
+};
+
+static int __init init_rrmap(void)
+{
+	void *ramroot_start;
+	unsigned long ramroot_size;
+
+	/* Check for supported rootfs types */
+	if (get_ramroot(&ramroot_start, &ramroot_size)) {
+		rr_map.phys = CPHYSADDR(ramroot_start);
+		rr_map.size = ramroot_size;
+
+		printk(KERN_NOTICE
+			"PMC embedded root device: 0x%08lx @ 0x%08lx\n",
+			rr_map.size, (unsigned long)rr_map.phys);
+	} else {
+		printk(KERN_ERR
+			"init_rrmap: no supported embedded rootfs detected!\n");
+		return -ENXIO;
+	}
+
+	/* Map rootfs to I/O space for block device driver */
+	rr_map.virt = ioremap(rr_map.phys, rr_map.size);
+	if (!rr_map.virt) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		return -EIO;
+	}
+
+	simple_map_init(&rr_map);
+
+	rr_mtd = do_map_probe("map_ram", &rr_map);
+	if (rr_mtd) {
+		rr_mtd->owner = THIS_MODULE;
+
+		add_mtd_device(rr_mtd);
+		ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
+
+		return 0;
+	}
+
+	iounmap(rr_map.virt);
+	return -ENXIO;
+}
+
+static void __exit cleanup_rrmap(void)
+{
+	del_mtd_device(rr_mtd);
+	map_destroy(rr_mtd);
+
+	iounmap(rr_map.virt);
+	rr_map.virt = NULL;
+}
+
+MODULE_AUTHOR("PMC-Sierra, Inc");
+MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem");
+MODULE_LICENSE("GPL");
+
+module_init(init_rrmap);
+module_exit(cleanup_rrmap);
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 4db2055..001af7f 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -39,7 +39,7 @@ MODULE_VERSION("2.0");
 
 static LIST_HEAD(device_list);
 struct uflash_dev {
-	char			*name;	/* device name */
+	const char		*name;	/* device name */
 	struct map_info 	map;	/* mtd map info */
 	struct mtd_info		*mtd;	/* mtd info */
 };
@@ -80,7 +80,7 @@ int uflash_devinit(struct linux_ebus_dev
 
 	up->name = of_get_property(dp, "model", NULL);
 	if (up->name && 0 < strlen(up->name))
-		up->map.name = up->name;
+		up->map.name = (char *)up->name;
 
 	up->map.phys = res->start;
 
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index b879a66..51bc7e2 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -20,6 +20,7 @@ #include <linux/spinlock.h>
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 #include <asm/uaccess.h>
 
 static LIST_HEAD(blktrans_majors);
@@ -28,9 +29,7 @@ extern struct mutex mtd_table_mutex;
 extern struct mtd_info *mtd_table[];
 
 struct mtd_blkcore_priv {
-	struct completion thread_dead;
-	int exiting;
-	wait_queue_head_t thread_wq;
+	struct task_struct *thread;
 	struct request_queue *rq;
 	spinlock_t queue_lock;
 };
@@ -83,38 +82,19 @@ static int mtd_blktrans_thread(void *arg
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	current->flags |= PF_MEMALLOC | PF_NOFREEZE;
 
-	daemonize("%sd", tr->name);
-
-	/* daemonize() doesn't do this for us since some kernel threads
-	   actually want to deal with signals. We can't just call
-	   exit_sighand() since that'll cause an oops when we finally
-	   do exit. */
-	spin_lock_irq(&current->sighand->siglock);
-	sigfillset(&current->blocked);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
 	spin_lock_irq(rq->queue_lock);
-
-	while (!tr->blkcore_priv->exiting) {
+	while (!kthread_should_stop()) {
 		struct request *req;
 		struct mtd_blktrans_dev *dev;
 		int res = 0;
-		DECLARE_WAITQUEUE(wait, current);
 
 		req = elv_next_request(rq);
 
 		if (!req) {
-			add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
 			set_current_state(TASK_INTERRUPTIBLE);
-
 			spin_unlock_irq(rq->queue_lock);
-
 			schedule();
-			remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-
 			spin_lock_irq(rq->queue_lock);
-
 			continue;
 		}
 
@@ -133,13 +113,13 @@ static int mtd_blktrans_thread(void *arg
 	}
 	spin_unlock_irq(rq->queue_lock);
 
-	complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
+	return 0;
 }
 
 static void mtd_blktrans_request(struct request_queue *rq)
 {
 	struct mtd_blktrans_ops *tr = rq->queuedata;
-	wake_up(&tr->blkcore_priv->thread_wq);
+	wake_up_process(tr->blkcore_priv->thread);
 }
 
 
@@ -236,7 +216,7 @@ int add_mtd_blktrans_dev(struct mtd_blkt
 	int last_devnum = -1;
 	struct gendisk *gd;
 
-	if (!!mutex_trylock(&mtd_table_mutex)) {
+	if (mutex_trylock(&mtd_table_mutex)) {
 		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
@@ -314,7 +294,7 @@ int add_mtd_blktrans_dev(struct mtd_blkt
 
 int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
 {
-	if (!!mutex_trylock(&mtd_table_mutex)) {
+	if (mutex_trylock(&mtd_table_mutex)) {
 		mutex_unlock(&mtd_table_mutex);
 		BUG();
 	}
@@ -388,8 +368,6 @@ int register_mtd_blktrans(struct mtd_blk
 		return ret;
 	}
 	spin_lock_init(&tr->blkcore_priv->queue_lock);
-	init_completion(&tr->blkcore_priv->thread_dead);
-	init_waitqueue_head(&tr->blkcore_priv->thread_wq);
 
 	tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
 	if (!tr->blkcore_priv->rq) {
@@ -403,13 +381,14 @@ int register_mtd_blktrans(struct mtd_blk
 	blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
 	tr->blkshift = ffs(tr->blksize) - 1;
 
-	ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
-	if (ret < 0) {
+	tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr,
+			"%sd", tr->name);
+	if (IS_ERR(tr->blkcore_priv->thread)) {
 		blk_cleanup_queue(tr->blkcore_priv->rq);
 		unregister_blkdev(tr->major, tr->name);
 		kfree(tr->blkcore_priv);
 		mutex_unlock(&mtd_table_mutex);
-		return ret;
+		return PTR_ERR(tr->blkcore_priv->thread);
 	}
 
 	INIT_LIST_HEAD(&tr->devs);
@@ -432,9 +411,7 @@ int deregister_mtd_blktrans(struct mtd_b
 	mutex_lock(&mtd_table_mutex);
 
 	/* Clean up the kernel thread */
-	tr->blkcore_priv->exiting = 1;
-	wake_up(&tr->blkcore_priv->thread_wq);
-	wait_for_completion(&tr->blkcore_priv->thread_dead);
+	kthread_stop(tr->blkcore_priv->thread);
 
 	/* Remove it from the list of active majors */
 	list_del(&tr->list);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 1592eac..8c86b80 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -553,7 +553,7 @@ static int mtd_ioctl(struct inode *inode
 		ops.datbuf = NULL;
 		ops.mode = MTD_OOB_PLACE;
 
-		if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
+		if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
 			return -EINVAL;
 
 		ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 2d12dcd..d05873b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,10 +1,7 @@
 # drivers/mtd/nand/Kconfig
 # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
 
-menu "NAND Flash Device Drivers"
-	depends on MTD!=n
-
-config MTD_NAND
+menuconfig MTD_NAND
 	tristate "NAND Device Support"
 	depends on MTD
 	select MTD_NAND_IDS
@@ -13,9 +10,10 @@ config MTD_NAND
 	  devices. For further information see
 	  <http://www.linux-mtd.infradead.org/doc/nand.html>.
 
+if MTD_NAND
+
 config MTD_NAND_VERIFY_WRITE
 	bool "Verify NAND page writes"
-	depends on MTD_NAND
 	help
 	  This adds an extra check when data is written to the flash. The
 	  NAND flash device internally checks only bits transitioning
@@ -25,53 +23,61 @@ config MTD_NAND_VERIFY_WRITE
 
 config MTD_NAND_ECC_SMC
 	bool "NAND ECC Smart Media byte order"
-	depends on MTD_NAND
 	default n
 	help
 	  Software ECC according to the Smart Media Specification.
 	  The original Linux implementation had byte 0 and 1 swapped.
 
+config MTD_NAND_MUSEUM_IDS
+	bool "Enable chip ids for obsolete ancient NAND devices"
+	depends on MTD_NAND
+	default n
+	help
+	  Enable this option only when your board has first generation
+	  NAND chips (page size 256 byte, erase size 4-8KiB). The IDs
+	  of these chips were reused by later, larger chips.
+
 config MTD_NAND_AUTCPU12
 	tristate "SmartMediaCard on autronix autcpu12 board"
-	depends on MTD_NAND && ARCH_AUTCPU12
+	depends on ARCH_AUTCPU12
 	help
 	  This enables the driver for the autronix autcpu12 board to
 	  access the SmartMediaCard.
 
 config MTD_NAND_EDB7312
 	tristate "Support for Cirrus Logic EBD7312 evaluation board"
-	depends on MTD_NAND && ARCH_EDB7312
+	depends on ARCH_EDB7312
 	help
 	  This enables the driver for the Cirrus Logic EBD7312 evaluation
 	  board to access the onboard NAND Flash.
 
 config MTD_NAND_H1900
 	tristate "iPAQ H1900 flash"
-	depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS
+	depends on ARCH_PXA && MTD_PARTITIONS
 	help
 	  This enables the driver for the iPAQ h1900 flash.
 
 config MTD_NAND_SPIA
 	tristate "NAND Flash device on SPIA board"
-	depends on ARCH_P720T && MTD_NAND
+	depends on ARCH_P720T
 	help
 	  If you had to ask, you don't have one. Say 'N'.
 
 config MTD_NAND_AMS_DELTA
 	tristate "NAND Flash device on Amstrad E3"
-	depends on MACH_AMS_DELTA && MTD_NAND
+	depends on MACH_AMS_DELTA
 	help
 	  Support for NAND flash on Amstrad E3 (Delta).
 
 config MTD_NAND_TOTO
 	tristate "NAND Flash device on TOTO board"
-	depends on ARCH_OMAP && MTD_NAND && BROKEN
+	depends on ARCH_OMAP && BROKEN
 	help
 	  Support for NAND flash on Texas Instruments Toto platform.
 
 config MTD_NAND_TS7250
 	tristate "NAND Flash device on TS-7250 board"
-	depends on MACH_TS72XX && MTD_NAND
+	depends on MACH_TS72XX
 	help
 	  Support for NAND flash on Technologic Systems TS-7250 platform.
 
@@ -80,14 +86,14 @@ config MTD_NAND_IDS
 
 config MTD_NAND_AU1550
 	tristate "Au1550/1200 NAND support"
-	depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND
+	depends on SOC_AU1200 || SOC_AU1550
 	help
 	  This enables the driver for the NAND flash controller on the
 	  AMD/Alchemy 1550 SOC.
 
 config MTD_NAND_RTC_FROM4
 	tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
-	depends on MTD_NAND && SH_SOLUTION_ENGINE
+	depends on SH_SOLUTION_ENGINE
 	select REED_SOLOMON
 	select REED_SOLOMON_DEC8
 	select BITREVERSE
@@ -97,13 +103,13 @@ config MTD_NAND_RTC_FROM4
 
 config MTD_NAND_PPCHAMELEONEVB
 	tristate "NAND Flash device on PPChameleonEVB board"
-	depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
+	depends on PPCHAMELEONEVB && BROKEN
 	help
 	  This enables the NAND flash driver on the PPChameleon EVB Board.
 
 config MTD_NAND_S3C2410
 	tristate "NAND Flash support for S3C2410/S3C2440 SoC"
-	depends on ARCH_S3C2410 && MTD_NAND
+	depends on ARCH_S3C2410
 	help
 	  This enables the NAND flash controller on the S3C2410 and S3C2440
 	  SoCs
@@ -128,7 +134,7 @@ config MTD_NAND_S3C2410_HWECC
 
 config MTD_NAND_NDFC
 	tristate "NDFC NanD Flash Controller"
-	depends on MTD_NAND && 44x
+	depends on 44x
 	select MTD_NAND_ECC_SMC
 	help
 	 NDFC Nand Flash Controllers are integrated in EP44x SoCs
@@ -145,7 +151,7 @@ config MTD_NAND_S3C2410_CLKSTOP
 
 config MTD_NAND_DISKONCHIP
 	tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
-	depends on MTD_NAND && EXPERIMENTAL
+	depends on EXPERIMENTAL
 	select REED_SOLOMON
 	select REED_SOLOMON_DEC16
 	help
@@ -215,11 +221,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
 
 config MTD_NAND_SHARPSL
 	tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-	depends on MTD_NAND && ARCH_PXA
+	depends on ARCH_PXA
 
 config MTD_NAND_BASLER_EXCITE
 	tristate  "Support for NAND Flash on Basler eXcite"
-	depends on MTD_NAND && BASLER_EXCITE
+	depends on BASLER_EXCITE
 	help
           This enables the driver for the NAND flash device found on the
           Basler eXcite Smart Camera. If built as a module, the driver
@@ -227,14 +233,14 @@ config MTD_NAND_BASLER_EXCITE
 
 config MTD_NAND_CAFE
        tristate "NAND support for OLPC CAFÃ‰ chip"
-       depends on MTD_NAND && PCI
+       depends on PCI
        help
 	 Use NAND flash attached to the CAFÃ‰ chip designed for the $100
 	 laptop.
 
 config MTD_NAND_CS553X
 	tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
-	depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
+	depends on X86_32 && (X86_PC || X86_GENERICARCH)
 	help
 	  The CS553x companion chips for the AMD Geode processor
 	  include NAND flash controllers with built-in hardware ECC
@@ -247,16 +253,21 @@ config MTD_NAND_CS553X
 
 config MTD_NAND_AT91
 	bool "Support for NAND Flash / SmartMedia on AT91"
-	depends on MTD_NAND && ARCH_AT91
+	depends on ARCH_AT91
 	help
 	  Enables support for NAND Flash / Smart Media Card interface
 	  on Atmel AT91 processors.
 
+config MTD_NAND_CM_X270
+	tristate "Support for NAND Flash on CM-X270 modules"
+	depends on MTD_NAND && MACH_ARMCORE
+
+
 config MTD_NAND_NANDSIM
 	tristate "Support for NAND Flash Simulator"
-	depends on MTD_NAND && MTD_PARTITIONS
+	depends on MTD_PARTITIONS
 	help
 	  The simulator may simulate various NAND flash chips for the
 	  MTD nand layer.
 
-endmenu
+endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 80f1dfc..6872031 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nands
 obj-$(CONFIG_MTD_NAND_CS553X)		+= cs553x_nand.o
 obj-$(CONFIG_MTD_NAND_NDFC)		+= ndfc.o
 obj-$(CONFIG_MTD_NAND_AT91)		+= at91_nand.o
+obj-$(CONFIG_MTD_NAND_CM_X270)		+= cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)	+= excite_nandflash.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
index fd6bb3e..c328a75 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe.c
@@ -530,7 +530,6 @@ static int __devinit cafe_nand_probe(str
 {
 	struct mtd_info *mtd;
 	struct cafe_priv *cafe;
-	uint32_t timing1, timing2, timing3;
 	uint32_t ctrl;
 	int err = 0;
 
@@ -587,21 +586,19 @@ static int __devinit cafe_nand_probe(str
 	}
 
 	if (numtimings == 3) {
-		timing1 = timing[0];
-		timing2 = timing[1];
-		timing3 = timing[2];
 		cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
-			     timing1, timing2, timing3);
+			     timing[0], timing[1], timing[2]);
 	} else {
-		timing1 = cafe_readl(cafe, NAND_TIMING1);
-		timing2 = cafe_readl(cafe, NAND_TIMING2);
-		timing3 = cafe_readl(cafe, NAND_TIMING3);
+		timing[0] = cafe_readl(cafe, NAND_TIMING1);
+		timing[1] = cafe_readl(cafe, NAND_TIMING2);
+		timing[2] = cafe_readl(cafe, NAND_TIMING3);
 
-		if (timing1 | timing2 | timing3) {
-			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
+		if (timing[0] | timing[1] | timing[2]) {
+			cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
+				     timing[0], timing[1], timing[2]);
 		} else {
 			dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
-			timing1 = timing2 = timing3 = 0xffffffff;
+			timing[0] = timing[1] = timing[2] = 0xffffffff;
 		}
 	}
 
@@ -609,9 +606,9 @@ static int __devinit cafe_nand_probe(str
 	cafe_writel(cafe, 1, NAND_RESET);
 	cafe_writel(cafe, 0, NAND_RESET);
 
-	cafe_writel(cafe, timing1, NAND_TIMING1);
-	cafe_writel(cafe, timing2, NAND_TIMING2);
-	cafe_writel(cafe, timing3, NAND_TIMING3);
+	cafe_writel(cafe, timing[0], NAND_TIMING1);
+	cafe_writel(cafe, timing[1], NAND_TIMING2);
+	cafe_writel(cafe, timing[2], NAND_TIMING3);
 
 	cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
 	err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
new file mode 100644
index 0000000..cb663ef
--- /dev/null
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -0,0 +1,267 @@
+/*
+ *  linux/drivers/mtd/nand/cmx270-nand.c
+ *
+ *  Copyright (C) 2006 Compulab, Ltd.
+ *  Mike Rapoport <mike@compulab.co.il>
+ *
+ *  Derived from drivers/mtd/nand/h1910.c
+ *       Copyright (C) 2002 Marius GrÃ¶ger (mag@sysgo.de)
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   CM-X270 board.
+ */
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define GPIO_NAND_CS	(11)
+#define GPIO_NAND_RB	(89)
+
+/* This macro needed to ensure in-order operation of GPIO and local
+ * bus. Without both asm command and dummy uncached read there're
+ * states when NAND access is broken. I've looked for such macro(s) in
+ * include/asm-arm but found nothing approptiate.
+ * dmac_clean_range is close, but is makes cache invalidation
+ * unnecessary here and it cannot be used in module
+ */
+#define DRAIN_WB() \
+	do { \
+		unsigned char dummy; \
+		asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \
+		dummy=*((unsigned char*)UNCACHED_ADDR); \
+	} while(0)
+
+/* MTD structure for CM-X270 board */
+static struct mtd_info *cmx270_nand_mtd;
+
+/* remaped IO address of the device */
+static void __iomem *cmx270_nand_io;
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info[] = {
+	[0] = {
+		.name	= "cmx270-0",
+		.offset	= 0,
+		.size	= MTDPART_SIZ_FULL
+	}
+};
+#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
+
+const char *part_probes[] = { "cmdlinepart", NULL };
+
+static u_char cmx270_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+
+	return (readl(this->IO_ADDR_R) >> 16);
+}
+
+static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+
+	for (i=0; i<len; i++)
+		writel((*buf++ << 16), this->IO_ADDR_W);
+}
+
+static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+
+	for (i=0; i<len; i++)
+		*buf++ = readl(this->IO_ADDR_R) >> 16;
+}
+
+static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	int i;
+	struct nand_chip *this = mtd->priv;
+
+	for (i=0; i<len; i++)
+		if (buf[i] != (u_char)(readl(this->IO_ADDR_R) >> 16))
+			return -EFAULT;
+
+	return 0;
+}
+
+static inline void nand_cs_on(void)
+{
+	GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+static void nand_cs_off(void)
+{
+	DRAIN_WB();
+
+	GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+/*
+ *	hardware specific access to control-lines
+ */
+static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
+			     unsigned int ctrl)
+{
+	struct nand_chip* this = mtd->priv;
+	unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
+
+	DRAIN_WB();
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		if ( ctrl & NAND_ALE )
+			nandaddr |=  (1 << 3);
+		else
+			nandaddr &= ~(1 << 3);
+		if ( ctrl & NAND_CLE )
+			nandaddr |=  (1 << 2);
+		else
+			nandaddr &= ~(1 << 2);
+		if ( ctrl & NAND_NCE )
+			nand_cs_on();
+		else
+			nand_cs_off();
+	}
+
+	DRAIN_WB();
+	this->IO_ADDR_W = (void __iomem*)nandaddr;
+	if (dat != NAND_CMD_NONE)
+		writel((dat << 16), this->IO_ADDR_W);
+
+	DRAIN_WB();
+}
+
+/*
+ *	read device ready pin
+ */
+static int cmx270_device_ready(struct mtd_info *mtd)
+{
+	DRAIN_WB();
+
+	return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB));
+}
+
+/*
+ * Main initialization routine
+ */
+static int cmx270_init(void)
+{
+	struct nand_chip *this;
+	const char *part_type;
+	struct mtd_partition *mtd_parts;
+	int mtd_parts_nb = 0;
+	int ret;
+
+	/* Allocate memory for MTD device structure and private data */
+	cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) +
+				  sizeof(struct nand_chip),
+				  GFP_KERNEL);
+	if (!cmx270_nand_mtd) {
+		printk("Unable to allocate CM-X270 NAND MTD device structure.\n");
+		return -ENOMEM;
+	}
+
+	cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
+	if (!cmx270_nand_io) {
+		printk("Unable to ioremap NAND device\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *)(&cmx270_nand_mtd[1]);
+
+	/* Link the private data with the MTD structure */
+	cmx270_nand_mtd->owner = THIS_MODULE;
+	cmx270_nand_mtd->priv = this;
+
+	/* insert callbacks */
+	this->IO_ADDR_R = cmx270_nand_io;
+	this->IO_ADDR_W = cmx270_nand_io;
+	this->cmd_ctrl = cmx270_hwcontrol;
+	this->dev_ready = cmx270_device_ready;
+
+	/* 15 us command delay time */
+	this->chip_delay = 20;
+	this->ecc.mode = NAND_ECC_SOFT;
+
+	/* read/write functions */
+	this->read_byte = cmx270_read_byte;
+	this->read_buf = cmx270_read_buf;
+	this->write_buf = cmx270_write_buf;
+	this->verify_buf = cmx270_verify_buf;
+
+	/* Scan to find existence of the device */
+	if (nand_scan (cmx270_nand_mtd, 1)) {
+		printk(KERN_NOTICE "No NAND device\n");
+		ret = -ENXIO;
+		goto err2;
+	}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes,
+					    &mtd_parts, 0);
+	if (mtd_parts_nb > 0)
+		part_type = "command line";
+	else
+		mtd_parts_nb = 0;
+#endif
+	if (!mtd_parts_nb) {
+		mtd_parts = partition_info;
+		mtd_parts_nb = NUM_PARTITIONS;
+		part_type = "static";
+	}
+
+	/* Register the partitions */
+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+	ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb);
+	if (ret)
+		goto err2;
+
+	/* Return happy */
+	return 0;
+
+err2:
+	iounmap(cmx270_nand_io);
+err1:
+	kfree(cmx270_nand_mtd);
+
+	return ret;
+
+}
+module_init(cmx270_init);
+
+/*
+ * Clean up routine
+ */
+static void cmx270_cleanup(void)
+{
+	/* Release resources, unregister device */
+	nand_release(cmx270_nand_mtd);
+
+	iounmap(cmx270_nand_io);
+
+	/* Free the MTD device structure */
+	kfree (cmx270_nand_mtd);
+}
+module_exit(cmx270_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 8296305..89deff0 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -20,7 +20,6 @@ #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ecc.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 6af37b8..04de315 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -312,7 +312,7 @@ static int nand_block_bad(struct mtd_inf
 		/* Select the NAND device */
 		chip->select_chip(mtd, chipnr);
 	} else
-		page = (int)ofs;
+		page = (int)(ofs >> chip->page_shift);
 
 	if (chip->options & NAND_BUSWIDTH_16) {
 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
@@ -350,7 +350,7 @@ static int nand_default_block_markbad(st
 	int block, ret;
 
 	/* Get block number */
-	block = ((int)ofs) >> chip->bbt_erase_shift;
+	block = (int)(ofs >> chip->bbt_erase_shift);
 	if (chip->bbt)
 		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
@@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct m
 	uint8_t *ecc_code = chip->buffers->ecccode;
 	int *eccpos = chip->ecc.layout->eccpos;
 
-	nand_read_page_raw(mtd, chip, buf);
+	chip->ecc.read_page_raw(mtd, chip, buf);
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
@@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct
 	for (i = 0; i < chip->ecc.total; i++)
 		chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-	nand_write_page_raw(mtd, chip, buf);
+	chip->ecc.write_page_raw(mtd, chip, buf);
 }
 
 /**
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2e2cdf2..2fc674a 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -24,6 +24,8 @@ #include <linux/mtd/nand.h>
 *	512	512 Byte page size
 */
 struct nand_flash_dev nand_flash_ids[] = {
+
+#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
 	{"NAND 1MiB 5V 8-bit",		0x6e, 256, 1, 0x1000, 0},
 	{"NAND 2MiB 5V 8-bit",		0x64, 256, 2, 0x1000, 0},
 	{"NAND 4MiB 5V 8-bit",		0x6b, 512, 4, 0x2000, 0},
@@ -39,6 +41,7 @@ struct nand_flash_dev nand_flash_ids[] =
 	{"NAND 8MiB 3,3V 8-bit",	0xe6, 512, 8, 0x2000, 0},
 	{"NAND 8MiB 1,8V 16-bit",	0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
 	{"NAND 8MiB 3,3V 16-bit",	0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+#endif
 
 	{"NAND 16MiB 1,8V 8-bit",	0x33, 512, 16, 0x4000, 0},
 	{"NAND 16MiB 3,3V 8-bit",	0x73, 512, 16, 0x4000, 0},
@@ -137,6 +140,7 @@ struct nand_manufacturers nand_manuf_ids
 	{NAND_MFR_RENESAS, "Renesas"},
 	{NAND_MFR_STMICRO, "ST Micro"},
 	{NAND_MFR_HYNIX, "Hynix"},
+	{NAND_MFR_MICRON, "Micron"},
 	{0x0, "Unknown"}
 };
 
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index c3bca95..205df0f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -37,6 +37,8 @@ #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/random.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -90,6 +92,15 @@ static uint bus_width      = CONFIG_NAND
 static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
 static uint log            = CONFIG_NANDSIM_LOG;
 static uint dbg            = CONFIG_NANDSIM_DBG;
+static unsigned long parts[MAX_MTD_DEVICES];
+static unsigned int parts_num;
+static char *badblocks = NULL;
+static char *weakblocks = NULL;
+static char *weakpages = NULL;
+static unsigned int bitflips = 0;
+static char *gravepages = NULL;
+static unsigned int rptwear = 0;
+static unsigned int overridesize = 0;
 
 module_param(first_id_byte,  uint, 0400);
 module_param(second_id_byte, uint, 0400);
@@ -104,8 +115,16 @@ module_param(bus_width,      uint, 0400)
 module_param(do_delays,      uint, 0400);
 module_param(log,            uint, 0400);
 module_param(dbg,            uint, 0400);
-
-MODULE_PARM_DESC(first_id_byte,  "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
+module_param_array(parts, ulong, &parts_num, 0400);
+module_param(badblocks,      charp, 0400);
+module_param(weakblocks,     charp, 0400);
+module_param(weakpages,      charp, 0400);
+module_param(bitflips,       uint, 0400);
+module_param(gravepages,     charp, 0400);
+module_param(rptwear,        uint, 0400);
+module_param(overridesize,   uint, 0400);
+
+MODULE_PARM_DESC(first_id_byte,  "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
 MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
 MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command");
 MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
@@ -118,6 +137,23 @@ MODULE_PARM_DESC(bus_width,      "Chip's
 MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
 MODULE_PARM_DESC(log,            "Perform logging if not zero");
 MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+MODULE_PARM_DESC(parts,          "Partition sizes (in erase blocks) separated by commas");
+/* Page and erase block positions for the following parameters are independent of any partitions */
+MODULE_PARM_DESC(badblocks,      "Erase blocks that are initially marked bad, separated by commas");
+MODULE_PARM_DESC(weakblocks,     "Weak erase blocks [: remaining erase cycles (defaults to 3)]"
+				 " separated by commas e.g. 113:2 means eb 113"
+				 " can be erased only twice before failing");
+MODULE_PARM_DESC(weakpages,      "Weak pages [: maximum writes (defaults to 3)]"
+				 " separated by commas e.g. 1401:2 means page 1401"
+				 " can be written only twice before failing");
+MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (zero by default)");
+MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
+				 " separated by commas e.g. 1401:2 means page 1401"
+				 " can be read only twice before failing");
+MODULE_PARM_DESC(rptwear,        "Number of erases inbetween reporting wear, if not zero");
+MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
+				 "The size is specified in erase blocks and as the exponent of a power of two"
+				 " e.g. 5 means a size of 32 erase blocks");
 
 /* The largest possible page size */
 #define NS_LARGEST_PAGE_SIZE	2048
@@ -131,9 +167,11 @@ #define NS_LOG(args...) \
 #define NS_DBG(args...) \
 	do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)
 #define NS_WARN(args...) \
-	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)
+	do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0)
 #define NS_ERR(args...) \
-	do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)
+	do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0)
+#define NS_INFO(args...) \
+	do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0)
 
 /* Busy-wait delay macros (microseconds, milliseconds) */
 #define NS_UDELAY(us) \
@@ -238,7 +276,8 @@ union ns_mem {
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
-	struct mtd_partition part;
+	struct mtd_partition partitions[MAX_MTD_DEVICES];
+	unsigned int nbparts;
 
 	uint busw;              /* flash chip bus width (8 or 16) */
 	u_char ids[4];          /* chip's ID bytes */
@@ -338,6 +377,38 @@ static struct nandsim_operations {
 			       STATE_DATAOUT, STATE_READY}}
 };
 
+struct weak_block {
+	struct list_head list;
+	unsigned int erase_block_no;
+	unsigned int max_erases;
+	unsigned int erases_done;
+};
+
+static LIST_HEAD(weak_blocks);
+
+struct weak_page {
+	struct list_head list;
+	unsigned int page_no;
+	unsigned int max_writes;
+	unsigned int writes_done;
+};
+
+static LIST_HEAD(weak_pages);
+
+struct grave_page {
+	struct list_head list;
+	unsigned int page_no;
+	unsigned int max_reads;
+	unsigned int reads_done;
+};
+
+static LIST_HEAD(grave_pages);
+
+static unsigned long *erase_block_wear = NULL;
+static unsigned int wear_eb_count = 0;
+static unsigned long total_wear = 0;
+static unsigned int rptwear_cnt = 0;
+
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
@@ -381,6 +452,13 @@ static void free_device(struct nandsim *
 	}
 }
 
+static char *get_partition_name(int i)
+{
+	char buf[64];
+	sprintf(buf, "NAND simulator partition %d", i);
+	return kstrdup(buf, GFP_KERNEL);
+}
+
 /*
  * Initialize the nandsim structure.
  *
@@ -390,7 +468,9 @@ static int init_nandsim(struct mtd_info 
 {
 	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
 	struct nandsim   *ns   = (struct nandsim *)(chip->priv);
-	int i;
+	int i, ret = 0;
+	u_int32_t remains;
+	u_int32_t next_offset;
 
 	if (NS_IS_INITIALIZED(ns)) {
 		NS_ERR("init_nandsim: nandsim is already initialized\n");
@@ -448,6 +528,40 @@ static int init_nandsim(struct mtd_info 
 		}
 	}
 
+	/* Fill the partition_info structure */
+	if (parts_num > ARRAY_SIZE(ns->partitions)) {
+		NS_ERR("too many partitions.\n");
+		ret = -EINVAL;
+		goto error;
+	}
+	remains = ns->geom.totsz;
+	next_offset = 0;
+	for (i = 0; i < parts_num; ++i) {
+		unsigned long part = parts[i];
+		if (!part || part > remains / ns->geom.secsz) {
+			NS_ERR("bad partition size.\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		ns->partitions[i].name   = get_partition_name(i);
+		ns->partitions[i].offset = next_offset;
+		ns->partitions[i].size   = part * ns->geom.secsz;
+		next_offset += ns->partitions[i].size;
+		remains -= ns->partitions[i].size;
+	}
+	ns->nbparts = parts_num;
+	if (remains) {
+		if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) {
+			NS_ERR("too many partitions.\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		ns->partitions[i].name   = get_partition_name(i);
+		ns->partitions[i].offset = next_offset;
+		ns->partitions[i].size   = remains;
+		ns->nbparts += 1;
+	}
+
 	/* Detect how many ID bytes the NAND chip outputs */
         for (i = 0; nand_flash_ids[i].name != NULL; i++) {
                 if (second_id_byte != nand_flash_ids[i].id)
@@ -474,7 +588,7 @@ static int init_nandsim(struct mtd_info 
 	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
 	printk("options: %#x\n",                ns->options);
 
-	if (alloc_device(ns) != 0)
+	if ((ret = alloc_device(ns)) != 0)
 		goto error;
 
 	/* Allocate / initialize the internal buffer */
@@ -482,21 +596,17 @@ static int init_nandsim(struct mtd_info 
 	if (!ns->buf.byte) {
 		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
 			ns->geom.pgszoob);
+		ret = -ENOMEM;
 		goto error;
 	}
 	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
 
-	/* Fill the partition_info structure */
-	ns->part.name   = "NAND simulator partition";
-	ns->part.offset = 0;
-	ns->part.size   = ns->geom.totsz;
-
 	return 0;
 
 error:
 	free_device(ns);
 
-	return -ENOMEM;
+	return ret;
 }
 
 /*
@@ -510,6 +620,287 @@ static void free_nandsim(struct nandsim 
 	return;
 }
 
+static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd)
+{
+	char *w;
+	int zero_ok;
+	unsigned int erase_block_no;
+	loff_t offset;
+
+	if (!badblocks)
+		return 0;
+	w = badblocks;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		erase_block_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !erase_block_no) {
+			NS_ERR("invalid badblocks.\n");
+			return -EINVAL;
+		}
+		offset = erase_block_no * ns->geom.secsz;
+		if (mtd->block_markbad(mtd, offset)) {
+			NS_ERR("invalid badblocks.\n");
+			return -EINVAL;
+		}
+		if (*w == ',')
+			w += 1;
+	} while (*w);
+	return 0;
+}
+
+static int parse_weakblocks(void)
+{
+	char *w;
+	int zero_ok;
+	unsigned int erase_block_no;
+	unsigned int max_erases;
+	struct weak_block *wb;
+
+	if (!weakblocks)
+		return 0;
+	w = weakblocks;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		erase_block_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !erase_block_no) {
+			NS_ERR("invalid weakblocks.\n");
+			return -EINVAL;
+		}
+		max_erases = 3;
+		if (*w == ':') {
+			w += 1;
+			max_erases = simple_strtoul(w, &w, 0);
+		}
+		if (*w == ',')
+			w += 1;
+		wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+		if (!wb) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		wb->erase_block_no = erase_block_no;
+		wb->max_erases = max_erases;
+		list_add(&wb->list, &weak_blocks);
+	} while (*w);
+	return 0;
+}
+
+static int erase_error(unsigned int erase_block_no)
+{
+	struct weak_block *wb;
+
+	list_for_each_entry(wb, &weak_blocks, list)
+		if (wb->erase_block_no == erase_block_no) {
+			if (wb->erases_done >= wb->max_erases)
+				return 1;
+			wb->erases_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static int parse_weakpages(void)
+{
+	char *w;
+	int zero_ok;
+	unsigned int page_no;
+	unsigned int max_writes;
+	struct weak_page *wp;
+
+	if (!weakpages)
+		return 0;
+	w = weakpages;
+	do {
+		zero_ok = (*w == '0' ? 1 : 0);
+		page_no = simple_strtoul(w, &w, 0);
+		if (!zero_ok && !page_no) {
+			NS_ERR("invalid weakpagess.\n");
+			return -EINVAL;
+		}
+		max_writes = 3;
+		if (*w == ':') {
+			w += 1;
+			max_writes = simple_strtoul(w, &w, 0);
+		}
+		if (*w == ',')
+			w += 1;
+		wp = kzalloc(sizeof(*wp), GFP_KERNEL);
+		if (!wp) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		wp->page_no = page_no;
+		wp->max_writes = max_writes;
+		list_add(&wp->list, &weak_pages);
+	} while (*w);
+	return 0;
+}
+
+static int write_error(unsigned int page_no)
+{
+	struct weak_page *wp;
+
+	list_for_each_entry(wp, &weak_pages, list)
+		if (wp->page_no == page_no) {
+			if (wp->writes_done >= wp->max_writes)
+				return 1;
+			wp->writes_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static int parse_gravepages(void)
+{
+	char *g;
+	int zero_ok;
+	unsigned int page_no;
+	unsigned int max_reads;
+	struct grave_page *gp;
+
+	if (!gravepages)
+		return 0;
+	g = gravepages;
+	do {
+		zero_ok = (*g == '0' ? 1 : 0);
+		page_no = simple_strtoul(g, &g, 0);
+		if (!zero_ok && !page_no) {
+			NS_ERR("invalid gravepagess.\n");
+			return -EINVAL;
+		}
+		max_reads = 3;
+		if (*g == ':') {
+			g += 1;
+			max_reads = simple_strtoul(g, &g, 0);
+		}
+		if (*g == ',')
+			g += 1;
+		gp = kzalloc(sizeof(*gp), GFP_KERNEL);
+		if (!gp) {
+			NS_ERR("unable to allocate memory.\n");
+			return -ENOMEM;
+		}
+		gp->page_no = page_no;
+		gp->max_reads = max_reads;
+		list_add(&gp->list, &grave_pages);
+	} while (*g);
+	return 0;
+}
+
+static int read_error(unsigned int page_no)
+{
+	struct grave_page *gp;
+
+	list_for_each_entry(gp, &grave_pages, list)
+		if (gp->page_no == page_no) {
+			if (gp->reads_done >= gp->max_reads)
+				return 1;
+			gp->reads_done += 1;
+			return 0;
+		}
+	return 0;
+}
+
+static void free_lists(void)
+{
+	struct list_head *pos, *n;
+	list_for_each_safe(pos, n, &weak_blocks) {
+		list_del(pos);
+		kfree(list_entry(pos, struct weak_block, list));
+	}
+	list_for_each_safe(pos, n, &weak_pages) {
+		list_del(pos);
+		kfree(list_entry(pos, struct weak_page, list));
+	}
+	list_for_each_safe(pos, n, &grave_pages) {
+		list_del(pos);
+		kfree(list_entry(pos, struct grave_page, list));
+	}
+	kfree(erase_block_wear);
+}
+
+static int setup_wear_reporting(struct mtd_info *mtd)
+{
+	size_t mem;
+
+	if (!rptwear)
+		return 0;
+	wear_eb_count = mtd->size / mtd->erasesize;
+	mem = wear_eb_count * sizeof(unsigned long);
+	if (mem / sizeof(unsigned long) != wear_eb_count) {
+		NS_ERR("Too many erase blocks for wear reporting\n");
+		return -ENOMEM;
+	}
+	erase_block_wear = kzalloc(mem, GFP_KERNEL);
+	if (!erase_block_wear) {
+		NS_ERR("Too many erase blocks for wear reporting\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void update_wear(unsigned int erase_block_no)
+{
+	unsigned long wmin = -1, wmax = 0, avg;
+	unsigned long deciles[10], decile_max[10], tot = 0;
+	unsigned int i;
+
+	if (!erase_block_wear)
+		return;
+	total_wear += 1;
+	if (total_wear == 0)
+		NS_ERR("Erase counter total overflow\n");
+	erase_block_wear[erase_block_no] += 1;
+	if (erase_block_wear[erase_block_no] == 0)
+		NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
+	rptwear_cnt += 1;
+	if (rptwear_cnt < rptwear)
+		return;
+	rptwear_cnt = 0;
+	/* Calc wear stats */
+	for (i = 0; i < wear_eb_count; ++i) {
+		unsigned long wear = erase_block_wear[i];
+		if (wear < wmin)
+			wmin = wear;
+		if (wear > wmax)
+			wmax = wear;
+		tot += wear;
+	}
+	for (i = 0; i < 9; ++i) {
+		deciles[i] = 0;
+		decile_max[i] = (wmax * (i + 1) + 5) / 10;
+	}
+	deciles[9] = 0;
+	decile_max[9] = wmax;
+	for (i = 0; i < wear_eb_count; ++i) {
+		int d;
+		unsigned long wear = erase_block_wear[i];
+		for (d = 0; d < 10; ++d)
+			if (wear <= decile_max[d]) {
+				deciles[d] += 1;
+				break;
+			}
+	}
+	avg = tot / wear_eb_count;
+	/* Output wear report */
+	NS_INFO("*** Wear Report ***\n");
+	NS_INFO("Total numbers of erases:  %lu\n", tot);
+	NS_INFO("Number of erase blocks:   %u\n", wear_eb_count);
+	NS_INFO("Average number of erases: %lu\n", avg);
+	NS_INFO("Maximum number of erases: %lu\n", wmax);
+	NS_INFO("Minimum number of erases: %lu\n", wmin);
+	for (i = 0; i < 10; ++i) {
+		unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+		if (from > decile_max[i])
+			continue;
+		NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
+			from,
+			decile_max[i],
+			deciles[i]);
+	}
+	NS_INFO("*** End of Wear Report ***\n");
+}
+
 /*
  * Returns the string representation of 'state' state.
  */
@@ -822,9 +1213,31 @@ static void read_page(struct nandsim *ns
 		NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
 		memset(ns->buf.byte, 0xFF, num);
 	} else {
+		unsigned int page_no = ns->regs.row;
 		NS_DBG("read_page: page %d allocated, reading from %d\n",
 			ns->regs.row, ns->regs.column + ns->regs.off);
+		if (read_error(page_no)) {
+			int i;
+			memset(ns->buf.byte, 0xFF, num);
+			for (i = 0; i < num; ++i)
+				ns->buf.byte[i] = random32();
+			NS_WARN("simulating read error in page %u\n", page_no);
+			return;
+		}
 		memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+		if (bitflips && random32() < (1 << 22)) {
+			int flips = 1;
+			if (bitflips > 1)
+				flips = (random32() % (int) bitflips) + 1;
+			while (flips--) {
+				int pos = random32() % (num * 8);
+				ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
+				NS_WARN("read_page: flipping bit %d in page %d "
+					"reading from %d ecc: corrected=%u failed=%u\n",
+					pos, ns->regs.row, ns->regs.column + ns->regs.off,
+					nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+			}
+		}
 	}
 }
 
@@ -883,6 +1296,7 @@ static int do_state_action(struct nandsi
 {
 	int num;
 	int busdiv = ns->busw == 8 ? 1 : 2;
+	unsigned int erase_block_no, page_no;
 
 	action &= ACTION_MASK;
 
@@ -942,14 +1356,24 @@ static int do_state_action(struct nandsi
 				8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
 		ns->regs.column = 0;
 
+		erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift);
+
 		NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
 				ns->regs.row, NS_RAW_OFFSET(ns));
-		NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
+		NS_LOG("erase sector %u\n", erase_block_no);
 
 		erase_sector(ns);
 
 		NS_MDELAY(erase_delay);
 
+		if (erase_block_wear)
+			update_wear(erase_block_no);
+
+		if (erase_error(erase_block_no)) {
+			NS_WARN("simulating erase failure in erase block %u\n", erase_block_no);
+			return -1;
+		}
+
 		break;
 
 	case ACTION_PRGPAGE:
@@ -972,6 +1396,8 @@ static int do_state_action(struct nandsi
 		if (prog_page(ns, num) == -1)
 			return -1;
 
+		page_no = ns->regs.row;
+
 		NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
 			num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
 		NS_LOG("programm page %d\n", ns->regs.row);
@@ -979,6 +1405,11 @@ static int do_state_action(struct nandsi
 		NS_UDELAY(programm_delay);
 		NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
 
+		if (write_error(page_no)) {
+			NS_WARN("simulating write failure in page %u\n", page_no);
+			return -1;
+		}
+
 		break;
 
 	case ACTION_ZEROOFF:
@@ -1503,7 +1934,7 @@ static int __init ns_init_module(void)
 {
 	struct nand_chip *chip;
 	struct nandsim *nand;
-	int retval = -ENOMEM;
+	int retval = -ENOMEM, i;
 
 	if (bus_width != 8 && bus_width != 16) {
 		NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
@@ -1533,6 +1964,8 @@ static int __init ns_init_module(void)
 	chip->verify_buf = ns_nand_verify_buf;
 	chip->read_word  = ns_nand_read_word;
 	chip->ecc.mode   = NAND_ECC_SOFT;
+	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+	/* and 'badblocks' parameters to work */
 	chip->options   |= NAND_SKIP_BBTSCAN;
 
 	/*
@@ -1557,6 +1990,15 @@ static int __init ns_init_module(void)
 
 	nsmtd->owner = THIS_MODULE;
 
+	if ((retval = parse_weakblocks()) != 0)
+		goto error;
+
+	if ((retval = parse_weakpages()) != 0)
+		goto error;
+
+	if ((retval = parse_gravepages()) != 0)
+		goto error;
+
 	if ((retval = nand_scan(nsmtd, 1)) != 0) {
 		NS_ERR("can't register NAND Simulator\n");
 		if (retval > 0)
@@ -1564,23 +2006,44 @@ static int __init ns_init_module(void)
 		goto error;
 	}
 
-	if ((retval = init_nandsim(nsmtd)) != 0) {
-		NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
-		goto error;
+	if (overridesize) {
+		u_int32_t new_size = nsmtd->erasesize << overridesize;
+		if (new_size >> overridesize != nsmtd->erasesize) {
+			NS_ERR("overridesize is too big\n");
+			goto err_exit;
+		}
+		/* N.B. This relies on nand_scan not doing anything with the size before we change it */
+		nsmtd->size = new_size;
+		chip->chipsize = new_size;
+		chip->chip_shift = ffs(new_size) - 1;
 	}
 
-	if ((retval = nand_default_bbt(nsmtd)) != 0) {
-		free_nandsim(nand);
-		goto error;
-	}
+	if ((retval = setup_wear_reporting(nsmtd)) != 0)
+		goto err_exit;
+
+	if ((retval = init_nandsim(nsmtd)) != 0)
+		goto err_exit;
 
-	/* Register NAND as one big partition */
-	add_mtd_partitions(nsmtd, &nand->part, 1);
+	if ((retval = parse_badblocks(nand, nsmtd)) != 0)
+		goto err_exit;
+
+	if ((retval = nand_default_bbt(nsmtd)) != 0)
+		goto err_exit;
+
+	/* Register NAND partitions */
+	if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0)
+		goto err_exit;
 
         return 0;
 
+err_exit:
+	free_nandsim(nand);
+	nand_release(nsmtd);
+	for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+		kfree(nand->partitions[i].name);
 error:
 	kfree(nsmtd);
+	free_lists();
 
 	return retval;
 }
@@ -1593,10 +2056,14 @@ module_init(ns_init_module);
 static void __exit ns_cleanup_module(void)
 {
 	struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
+	int i;
 
 	free_nandsim(ns);    /* Free nandsim private resources */
-	nand_release(nsmtd); /* Unregisterd drived */
+	nand_release(nsmtd); /* Unregister driver */
+	for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+		kfree(ns->partitions[i].name);
 	kfree(nsmtd);        /* Free other structures */
+	free_lists();
 }
 
 module_exit(ns_cleanup_module);
@@ -1604,4 +2071,3 @@ module_exit(ns_cleanup_module);
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Artem B. Bityuckiy");
 MODULE_DESCRIPTION ("The NAND flash simulator");
-
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index e6ef7d7..0c9ce19 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -17,7 +17,6 @@ #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 373bddc..c257d39 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -2,20 +2,18 @@ #
 # linux/drivers/mtd/onenand/Kconfig
 #
 
-menu "OneNAND Flash Device Drivers"
-	depends on MTD != n
-
-config MTD_ONENAND
+menuconfig MTD_ONENAND
 	tristate "OneNAND Device Support"
 	depends on MTD
 	help
 	  This enables support for accessing all type of OneNAND flash
 	  devices. For further information see
-	  <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>.
+	  <http://www.samsung.com/Products/Semiconductor/OneNAND/index.htm>
+
+if MTD_ONENAND
 
 config MTD_ONENAND_VERIFY_WRITE
 	bool "Verify OneNAND page writes"
-	depends on MTD_ONENAND
 	help
 	  This adds an extra check when data is written to the flash. The
 	  OneNAND flash device internally checks only bits transitioning
@@ -25,13 +23,12 @@ config MTD_ONENAND_VERIFY_WRITE
 
 config MTD_ONENAND_GENERIC
 	tristate "OneNAND Flash device via platform device driver"
-	depends on MTD_ONENAND && ARM
+	depends on ARM
 	help
 	  Support for OneNAND flash via platform device driver.
 
 config MTD_ONENAND_OTP
 	bool "OneNAND OTP Support"
-	depends on MTD_ONENAND
 	help
 	  One Block of the NAND Flash Array memory is reserved as
 	  a One-Time Programmable Block memory area.
@@ -43,4 +40,4 @@ config MTD_ONENAND_OTP
 
 	  OTP block is fully-guaranteed to be a valid block.
 
-endmenu
+endif # MTD_ONENAND
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 9e14a26..000794c 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -836,9 +836,11 @@ static int onenand_transfer_auto_oob(str
 	int readcol = column;
 	int readend = column + thislen;
 	int lastgap = 0;
+	unsigned int i;
 	uint8_t *oob_buf = this->oob_buf;
 
-	for (free = this->ecclayout->oobfree; free->length; ++free) {
+	free = this->ecclayout->oobfree;
+	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
 		if (readcol >= lastgap)
 			readcol += free->offset - lastgap;
 		if (readend >= lastgap)
@@ -846,7 +848,8 @@ static int onenand_transfer_auto_oob(str
 		lastgap = free->offset + free->length;
 	}
 	this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
-	for (free = this->ecclayout->oobfree; free->length; ++free) {
+	free = this->ecclayout->oobfree;
+	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
 		int free_end = free->offset + free->length;
 		if (free->offset < readend && free_end > readcol) {
 			int st = max_t(int,free->offset,readcol);
@@ -854,7 +857,7 @@ static int onenand_transfer_auto_oob(str
 			int n = ed - st;
 			memcpy(buf, oob_buf + st, n);
 			buf += n;
-		} else
+		} else if (column == 0)
 			break;
 	}
 	return 0;
@@ -1280,15 +1283,18 @@ static int onenand_fill_auto_oob(struct 
 	int writecol = column;
 	int writeend = column + thislen;
 	int lastgap = 0;
+	unsigned int i;
 
-	for (free = this->ecclayout->oobfree; free->length; ++free) {
+	free = this->ecclayout->oobfree;
+	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
 		if (writecol >= lastgap)
 			writecol += free->offset - lastgap;
 		if (writeend >= lastgap)
 			writeend += free->offset - lastgap;
 		lastgap = free->offset + free->length;
 	}
-	for (free = this->ecclayout->oobfree; free->length; ++free) {
+	free = this->ecclayout->oobfree;
+	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
 		int free_end = free->offset + free->length;
 		if (free->offset < writeend && free_end > writecol) {
 			int st = max_t(int,free->offset,writecol);
@@ -1296,7 +1302,7 @@ static int onenand_fill_auto_oob(struct 
 			int n = ed - st;
 			memcpy(oob_buf + st, buf, n);
 			buf += n;
-		} else
+		} else if (column == 0)
 			break;
 	}
 	return 0;
@@ -2386,7 +2392,8 @@ int onenand_scan(struct mtd_info *mtd, i
 	 * the out of band area
 	 */
 	this->ecclayout->oobavail = 0;
-	for (i = 0; this->ecclayout->oobfree[i].length; i++)
+	for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
+	    this->ecclayout->oobfree[i].length; i++)
 		this->ecclayout->oobavail +=
 			this->ecclayout->oobfree[i].length;
 	mtd->oobavail = this->ecclayout->oobavail;
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
new file mode 100644
index 0000000..b9daf15
--- /dev/null
+++ b/drivers/mtd/ubi/Kconfig
@@ -0,0 +1,58 @@
+# drivers/mtd/ubi/Kconfig
+
+menu "UBI - Unsorted block images"
+	depends on MTD
+
+config MTD_UBI
+	tristate "Enable UBI"
+	depends on MTD
+	select CRC32
+	help
+	  UBI is a software layer above MTD layer which admits of LVM-like
+	  logical volumes on top of MTD devices, hides some complexities of
+	  flash chips like wear and bad blocks and provides some other useful
+	  capabilities. Please, consult the MTD web site for more details
+	  (www.linux-mtd.infradead.org).
+
+config MTD_UBI_WL_THRESHOLD
+	int "UBI wear-leveling threshold"
+	default 4096
+	range 2 65536
+	depends on MTD_UBI
+	help
+	  This parameter defines the maximum difference between the highest
+	  erase counter value and the lowest erase counter value of eraseblocks
+	  of UBI devices. When this threshold is exceeded, UBI starts performing
+	  wear leveling by means of moving data from eraseblock with low erase
+	  counter to eraseblocks with high erase counter. Leave the default
+	  value if unsure.
+
+config MTD_UBI_BEB_RESERVE
+	int "Percentage of reserved eraseblocks for bad eraseblocks handling"
+	default 1
+	range 0 25
+	depends on MTD_UBI
+	help
+	  If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI
+	  reserves some amount of physical eraseblocks to handle new bad
+	  eraseblocks. For example, if a flash physical eraseblock becomes bad,
+	  UBI uses these reserved physical eraseblocks to relocate the bad one.
+	  This option specifies how many physical eraseblocks will be reserved
+	  for bad eraseblock handling (percents of total number of good flash
+	  eraseblocks). If the underlying flash does not admit of bad
+	  eraseblocks (e.g. NOR flash), this value is ignored and nothing is
+	  reserved. Leave the default value if unsure.
+
+config MTD_UBI_GLUEBI
+	bool "Emulate MTD devices"
+	default n
+	depends on MTD_UBI
+	help
+	   This option enables MTD devices emulation on top of UBI volumes: for
+	   each UBI volumes an MTD device is created, and all I/O to this MTD
+	   device is redirected to the UBI volume. This is handy to make
+	   MTD-oriented software (like JFFS2) work on top of UBI. Do not enable
+	   this if no legacy software will be used.
+
+source "drivers/mtd/ubi/Kconfig.debug"
+endmenu
diff --git a/drivers/mtd/ubi/Kconfig.debug b/drivers/mtd/ubi/Kconfig.debug
new file mode 100644
index 0000000..1e2ee22
--- /dev/null
+++ b/drivers/mtd/ubi/Kconfig.debug
@@ -0,0 +1,104 @@
+comment "UBI debugging options"
+	depends on MTD_UBI
+
+config MTD_UBI_DEBUG
+	bool "UBI debugging"
+	depends on SYSFS
+	depends on MTD_UBI
+	select DEBUG_FS
+	select KALLSYMS_ALL
+	help
+	  This option enables UBI debugging.
+
+config MTD_UBI_DEBUG_MSG
+	bool "UBI debugging messages"
+	depends on MTD_UBI_DEBUG
+	default n
+	help
+	  This option enables UBI debugging messages.
+
+config MTD_UBI_DEBUG_PARANOID
+	bool "Extra self-checks"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  This option enables extra checks in UBI code. Note this slows UBI down
+	  significantly.
+
+config MTD_UBI_DEBUG_DISABLE_BGT
+	bool "Do not enable the UBI background thread"
+	depends on MTD_UBI_DEBUG
+	default n
+	help
+	  This option switches the background thread off by default. The thread
+	  may be also be enabled/disabled via UBI sysfs.
+
+config MTD_UBI_DEBUG_USERSPACE_IO
+	bool "Direct user-space write/erase support"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  By default, users cannot directly write and erase individual
+	  eraseblocks of dynamic volumes, and have to use update operation
+	  instead. This option enables this capability - it is very useful for
+	  debugging and testing.
+
+config MTD_UBI_DEBUG_EMULATE_BITFLIPS
+	bool "Emulate flash bit-flips"
+	depends on MTD_UBI_DEBUG
+	default n
+	help
+	  This option emulates bit-flips with probability 1/50, which in turn
+	  causes scrubbing. Useful for debugging and stressing UBI.
+
+config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
+	bool "Emulate flash write failures"
+	depends on MTD_UBI_DEBUG
+	default n
+	help
+	  This option emulates write failures with probability 1/100. Useful for
+	  debugging and testing how UBI handlines errors.
+
+config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
+	bool "Emulate flash erase failures"
+	depends on MTD_UBI_DEBUG
+	default n
+	help
+	  This option emulates erase failures with probability 1/100. Useful for
+	  debugging and testing how UBI handlines errors.
+
+menu "Additional UBI debugging messages"
+	depends on MTD_UBI_DEBUG
+
+config MTD_UBI_DEBUG_MSG_BLD
+	bool "Additional UBI initialization and build messages"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  This option enables detailed UBI initialization and device build
+	  debugging messages.
+
+config MTD_UBI_DEBUG_MSG_EBA
+	bool "Eraseblock association unit messages"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  This option enables debugging messages from the UBI eraseblock
+	  association unit.
+
+config MTD_UBI_DEBUG_MSG_WL
+	bool "Wear-leveling unit messages"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  This option enables debugging messages from the UBI wear-leveling
+	  unit.
+
+config MTD_UBI_DEBUG_MSG_IO
+	bool "Input/output unit messages"
+	default n
+	depends on MTD_UBI_DEBUG
+	help
+	  This option enables debugging messages from the UBI input/output unit.
+
+endmenu # UBI debugging messages
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
new file mode 100644
index 0000000..dd834e0
--- /dev/null
+++ b/drivers/mtd/ubi/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MTD_UBI) += ubi.o
+
+ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
+ubi-y += misc.o
+
+ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
+ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
new file mode 100644
index 0000000..555d594
--- /dev/null
+++ b/drivers/mtd/ubi/build.c
@@ -0,0 +1,848 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼),
+ *         Frank Haverkamp
+ */
+
+/*
+ * This file includes UBI initialization and building of UBI devices. At the
+ * moment UBI devices may only be added while UBI is initialized, but dynamic
+ * device add/remove functionality is planned. Also, at the moment we only
+ * attach UBI devices by scanning, which will become a bottleneck when flashes
+ * reach certain large size. Then one may improve UBI and add other methods.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/stringify.h>
+#include <linux/stat.h>
+#include "ubi.h"
+
+/* Maximum length of the 'mtd=' parameter */
+#define MTD_PARAM_LEN_MAX 64
+
+/**
+ * struct mtd_dev_param - MTD device parameter description data structure.
+ * @name: MTD device name or number string
+ * @vid_hdr_offs: VID header offset
+ * @data_offs: data offset
+ */
+struct mtd_dev_param
+{
+	char name[MTD_PARAM_LEN_MAX];
+	int vid_hdr_offs;
+	int data_offs;
+};
+
+/* Numbers of elements set in the @mtd_dev_param array */
+static int mtd_devs = 0;
+
+/* MTD devices specification parameters */
+static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
+
+/* Number of UBI devices in system */
+int ubi_devices_cnt;
+
+/* All UBI devices in system */
+struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
+
+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
+struct class *ubi_class;
+
+/* "Show" method for files in '/<sysfs>/class/ubi/' */
+static ssize_t ubi_version_show(struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", UBI_VERSION);
+}
+
+/* UBI version attribute ('/<sysfs>/class/ubi/version') */
+static struct class_attribute ubi_version =
+	__ATTR(version, S_IRUGO, ubi_version_show, NULL);
+
+static ssize_t dev_attribute_show(struct device *dev,
+				  struct device_attribute *attr, char *buf);
+
+/* UBI device attributes (correspond to files in '/<sysfs>/class/ubi/ubiX') */
+static struct device_attribute dev_eraseblock_size =
+	__ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_avail_eraseblocks =
+	__ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_total_eraseblocks =
+	__ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_volumes_count =
+	__ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_max_ec =
+	__ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_reserved_for_bad =
+	__ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_bad_peb_count =
+	__ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_max_vol_count =
+	__ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_min_io_size =
+	__ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_bgt_enabled =
+	__ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
+
+/* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
+static ssize_t dev_attribute_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	const struct ubi_device *ubi;
+
+	ubi = container_of(dev, struct ubi_device, dev);
+	if (attr == &dev_eraseblock_size)
+		return sprintf(buf, "%d\n", ubi->leb_size);
+	else if (attr == &dev_avail_eraseblocks)
+		return sprintf(buf, "%d\n", ubi->avail_pebs);
+	else if (attr == &dev_total_eraseblocks)
+		return sprintf(buf, "%d\n", ubi->good_peb_count);
+	else if (attr == &dev_volumes_count)
+		return sprintf(buf, "%d\n", ubi->vol_count);
+	else if (attr == &dev_max_ec)
+		return sprintf(buf, "%d\n", ubi->max_ec);
+	else if (attr == &dev_reserved_for_bad)
+		return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
+	else if (attr == &dev_bad_peb_count)
+		return sprintf(buf, "%d\n", ubi->bad_peb_count);
+	else if (attr == &dev_max_vol_count)
+		return sprintf(buf, "%d\n", ubi->vtbl_slots);
+	else if (attr == &dev_min_io_size)
+		return sprintf(buf, "%d\n", ubi->min_io_size);
+	else if (attr == &dev_bgt_enabled)
+		return sprintf(buf, "%d\n", ubi->thread_enabled);
+	else
+		BUG();
+
+	return 0;
+}
+
+/* Fake "release" method for UBI devices */
+static void dev_release(struct device *dev) { }
+
+/**
+ * ubi_sysfs_init - initialize sysfs for an UBI device.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int ubi_sysfs_init(struct ubi_device *ubi)
+{
+	int err;
+
+	ubi->dev.release = dev_release;
+	ubi->dev.devt = MKDEV(ubi->major, 0);
+	ubi->dev.class = ubi_class;
+	sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);
+	err = device_register(&ubi->dev);
+	if (err)
+		goto out;
+
+	err = device_create_file(&ubi->dev, &dev_eraseblock_size);
+	if (err)
+		goto out_unregister;
+	err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
+	if (err)
+		goto out_eraseblock_size;
+	err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
+	if (err)
+		goto out_avail_eraseblocks;
+	err = device_create_file(&ubi->dev, &dev_volumes_count);
+	if (err)
+		goto out_total_eraseblocks;
+	err = device_create_file(&ubi->dev, &dev_max_ec);
+	if (err)
+		goto out_volumes_count;
+	err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
+	if (err)
+		goto out_volumes_max_ec;
+	err = device_create_file(&ubi->dev, &dev_bad_peb_count);
+	if (err)
+		goto out_reserved_for_bad;
+	err = device_create_file(&ubi->dev, &dev_max_vol_count);
+	if (err)
+		goto out_bad_peb_count;
+	err = device_create_file(&ubi->dev, &dev_min_io_size);
+	if (err)
+		goto out_max_vol_count;
+	err = device_create_file(&ubi->dev, &dev_bgt_enabled);
+	if (err)
+		goto out_min_io_size;
+
+	return 0;
+
+out_min_io_size:
+	device_remove_file(&ubi->dev, &dev_min_io_size);
+out_max_vol_count:
+	device_remove_file(&ubi->dev, &dev_max_vol_count);
+out_bad_peb_count:
+	device_remove_file(&ubi->dev, &dev_bad_peb_count);
+out_reserved_for_bad:
+	device_remove_file(&ubi->dev, &dev_reserved_for_bad);
+out_volumes_max_ec:
+	device_remove_file(&ubi->dev, &dev_max_ec);
+out_volumes_count:
+	device_remove_file(&ubi->dev, &dev_volumes_count);
+out_total_eraseblocks:
+	device_remove_file(&ubi->dev, &dev_total_eraseblocks);
+out_avail_eraseblocks:
+	device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
+out_eraseblock_size:
+	device_remove_file(&ubi->dev, &dev_eraseblock_size);
+out_unregister:
+	device_unregister(&ubi->dev);
+out:
+	ubi_err("failed to initialize sysfs for %s", ubi->ubi_name);
+	return err;
+}
+
+/**
+ * ubi_sysfs_close - close sysfs for an UBI device.
+ * @ubi: UBI device description object
+ */
+static void ubi_sysfs_close(struct ubi_device *ubi)
+{
+	device_remove_file(&ubi->dev, &dev_bgt_enabled);
+	device_remove_file(&ubi->dev, &dev_min_io_size);
+	device_remove_file(&ubi->dev, &dev_max_vol_count);
+	device_remove_file(&ubi->dev, &dev_bad_peb_count);
+	device_remove_file(&ubi->dev, &dev_reserved_for_bad);
+	device_remove_file(&ubi->dev, &dev_max_ec);
+	device_remove_file(&ubi->dev, &dev_volumes_count);
+	device_remove_file(&ubi->dev, &dev_total_eraseblocks);
+	device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
+	device_remove_file(&ubi->dev, &dev_eraseblock_size);
+	device_unregister(&ubi->dev);
+}
+
+/**
+ * kill_volumes - destroy all volumes.
+ * @ubi: UBI device description object
+ */
+static void kill_volumes(struct ubi_device *ubi)
+{
+	int i;
+
+	for (i = 0; i < ubi->vtbl_slots; i++)
+		if (ubi->volumes[i])
+			ubi_free_volume(ubi, i);
+}
+
+/**
+ * uif_init - initialize user interfaces for an UBI device.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int uif_init(struct ubi_device *ubi)
+{
+	int i, err;
+	dev_t dev;
+
+	mutex_init(&ubi->vtbl_mutex);
+	spin_lock_init(&ubi->volumes_lock);
+
+	sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
+
+	/*
+	 * Major numbers for the UBI character devices are allocated
+	 * dynamically. Major numbers of volume character devices are
+	 * equivalent to ones of the corresponding UBI character device. Minor
+	 * numbers of UBI character devices are 0, while minor numbers of
+	 * volume character devices start from 1. Thus, we allocate one major
+	 * number and ubi->vtbl_slots + 1 minor numbers.
+	 */
+	err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name);
+	if (err) {
+		ubi_err("cannot register UBI character devices");
+		return err;
+	}
+
+	cdev_init(&ubi->cdev, &ubi_cdev_operations);
+	ubi->major = MAJOR(dev);
+	dbg_msg("%s major is %u", ubi->ubi_name, ubi->major);
+	ubi->cdev.owner = THIS_MODULE;
+
+	dev = MKDEV(ubi->major, 0);
+	err = cdev_add(&ubi->cdev, dev, 1);
+	if (err) {
+		ubi_err("cannot add character device %s", ubi->ubi_name);
+		goto out_unreg;
+	}
+
+	err = ubi_sysfs_init(ubi);
+	if (err)
+		goto out_cdev;
+
+	for (i = 0; i < ubi->vtbl_slots; i++)
+		if (ubi->volumes[i]) {
+			err = ubi_add_volume(ubi, i);
+			if (err)
+				goto out_volumes;
+		}
+
+	return 0;
+
+out_volumes:
+	kill_volumes(ubi);
+	ubi_sysfs_close(ubi);
+out_cdev:
+	cdev_del(&ubi->cdev);
+out_unreg:
+	unregister_chrdev_region(MKDEV(ubi->major, 0),
+				 ubi->vtbl_slots + 1);
+	return err;
+}
+
+/**
+ * uif_close - close user interfaces for an UBI device.
+ * @ubi: UBI device description object
+ */
+static void uif_close(struct ubi_device *ubi)
+{
+	kill_volumes(ubi);
+	ubi_sysfs_close(ubi);
+	cdev_del(&ubi->cdev);
+	unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1);
+}
+
+/**
+ * attach_by_scanning - attach an MTD device using scanning method.
+ * @ubi: UBI device descriptor
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ *
+ * Note, currently this is the only method to attach UBI devices. Hopefully in
+ * the future we'll have more scalable attaching methods and avoid full media
+ * scanning. But even in this case scanning will be needed as a fall-back
+ * attaching method if there are some on-flash table corruptions.
+ */
+static int attach_by_scanning(struct ubi_device *ubi)
+{
+	int err;
+	struct ubi_scan_info *si;
+
+	si = ubi_scan(ubi);
+	if (IS_ERR(si))
+		return PTR_ERR(si);
+
+	ubi->bad_peb_count = si->bad_peb_count;
+	ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
+	ubi->max_ec = si->max_ec;
+	ubi->mean_ec = si->mean_ec;
+
+	err = ubi_read_volume_table(ubi, si);
+	if (err)
+		goto out_si;
+
+	err = ubi_wl_init_scan(ubi, si);
+	if (err)
+		goto out_vtbl;
+
+	err = ubi_eba_init_scan(ubi, si);
+	if (err)
+		goto out_wl;
+
+	ubi_scan_destroy_si(si);
+	return 0;
+
+out_wl:
+	ubi_wl_close(ubi);
+out_vtbl:
+	kfree(ubi->vtbl);
+out_si:
+	ubi_scan_destroy_si(si);
+	return err;
+}
+
+/**
+ * io_init - initialize I/O unit for a given UBI device.
+ * @ubi: UBI device description object
+ *
+ * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are
+ * assumed:
+ *   o EC header is always at offset zero - this cannot be changed;
+ *   o VID header starts just after the EC header at the closest address
+ *   aligned to @io->@hdrs_min_io_size;
+ *   o data starts just after the VID header at the closest address aligned to
+ *     @io->@min_io_size
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int io_init(struct ubi_device *ubi)
+{
+	if (ubi->mtd->numeraseregions != 0) {
+		/*
+		 * Some flashes have several erase regions. Different regions
+		 * may have different eraseblock size and other
+		 * characteristics. It looks like mostly multi-region flashes
+		 * have one "main" region and one or more small regions to
+		 * store boot loader code or boot parameters or whatever. I
+		 * guess we should just pick the largest region. But this is
+		 * not implemented.
+		 */
+		ubi_err("multiple regions, not implemented");
+		return -EINVAL;
+	}
+
+	/*
+	 * Note, in this implementation we support MTD devices with 0x7FFFFFFF
+	 * physical eraseblocks maximum.
+	 */
+
+	ubi->peb_size   = ubi->mtd->erasesize;
+	ubi->peb_count  = ubi->mtd->size / ubi->mtd->erasesize;
+	ubi->flash_size = ubi->mtd->size;
+
+	if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
+		ubi->bad_allowed = 1;
+
+	ubi->min_io_size = ubi->mtd->writesize;
+	ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
+
+	/* Make sure minimal I/O unit is power of 2 */
+	if (ubi->min_io_size == 0 ||
+	    (ubi->min_io_size & (ubi->min_io_size - 1))) {
+		ubi_err("bad min. I/O unit");
+		return -EINVAL;
+	}
+
+	ubi_assert(ubi->hdrs_min_io_size > 0);
+	ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
+	ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
+
+	/* Calculate default aligned sizes of EC and VID headers */
+	ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
+	ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
+
+	dbg_msg("min_io_size      %d", ubi->min_io_size);
+	dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
+	dbg_msg("ec_hdr_alsize    %d", ubi->ec_hdr_alsize);
+	dbg_msg("vid_hdr_alsize   %d", ubi->vid_hdr_alsize);
+
+	if (ubi->vid_hdr_offset == 0)
+		/* Default offset */
+		ubi->vid_hdr_offset = ubi->vid_hdr_aloffset =
+				      ubi->ec_hdr_alsize;
+	else {
+		ubi->vid_hdr_aloffset = ubi->vid_hdr_offset &
+						~(ubi->hdrs_min_io_size - 1);
+		ubi->vid_hdr_shift = ubi->vid_hdr_offset -
+						ubi->vid_hdr_aloffset;
+	}
+
+	/* Similar for the data offset */
+	if (ubi->leb_start == 0) {
+		ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
+		ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
+	}
+
+	dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
+	dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
+	dbg_msg("vid_hdr_shift    %d", ubi->vid_hdr_shift);
+	dbg_msg("leb_start        %d", ubi->leb_start);
+
+	/* The shift must be aligned to 32-bit boundary */
+	if (ubi->vid_hdr_shift % 4) {
+		ubi_err("unaligned VID header shift %d",
+			ubi->vid_hdr_shift);
+		return -EINVAL;
+	}
+
+	/* Check sanity */
+	if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||
+	    ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||
+	    ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||
+	    ubi->leb_start % ubi->min_io_size) {
+		ubi_err("bad VID header (%d) or data offsets (%d)",
+			ubi->vid_hdr_offset, ubi->leb_start);
+		return -EINVAL;
+	}
+
+	/*
+	 * It may happen that EC and VID headers are situated in one minimal
+	 * I/O unit. In this case we can only accept this UBI image in
+	 * read-only mode.
+	 */
+	if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {
+		ubi_warn("EC and VID headers are in the same minimal I/O unit, "
+			 "switch to read-only mode");
+		ubi->ro_mode = 1;
+	}
+
+	ubi->leb_size = ubi->peb_size - ubi->leb_start;
+
+	if (!(ubi->mtd->flags & MTD_WRITEABLE)) {
+		ubi_msg("MTD device %d is write-protected, attach in "
+			"read-only mode", ubi->mtd->index);
+		ubi->ro_mode = 1;
+	}
+
+	dbg_msg("leb_size         %d", ubi->leb_size);
+	dbg_msg("ro_mode          %d", ubi->ro_mode);
+
+	/*
+	 * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+	 * unfortunately, MTD does not provide this information. We should loop
+	 * over all physical eraseblocks and invoke mtd->block_is_bad() for
+	 * each physical eraseblock. So, we skip ubi->bad_peb_count
+	 * uninitialized and initialize it after scanning.
+	 */
+
+	return 0;
+}
+
+/**
+ * attach_mtd_dev - attach an MTD device.
+ * @mtd_dev: MTD device name or number string
+ * @vid_hdr_offset: VID header offset
+ * @data_offset: data offset
+ *
+ * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
+ * MTD device name, and tries to open it by this name. If it is unable to open,
+ * it tries to convert @mtd_dev to an integer and open the MTD device by its
+ * number. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
+			  int data_offset)
+{
+	struct ubi_device *ubi;
+	struct mtd_info *mtd;
+	int i, err;
+
+	mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(mtd)) {
+		int mtd_num;
+		char *endp;
+
+		if (PTR_ERR(mtd) != -ENODEV)
+			return PTR_ERR(mtd);
+
+		/*
+		 * Probably this is not MTD device name but MTD device number -
+		 * check this out.
+		 */
+		mtd_num = simple_strtoul(mtd_dev, &endp, 0);
+		if (*endp != '\0' || mtd_dev == endp) {
+			ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
+			return -ENODEV;
+		}
+
+		mtd = get_mtd_device(NULL, mtd_num);
+		if (IS_ERR(mtd))
+			return PTR_ERR(mtd);
+	}
+
+	/* Check if we already have the same MTD device attached */
+	for (i = 0; i < ubi_devices_cnt; i++)
+		if (ubi_devices[i]->mtd->index == mtd->index) {
+			ubi_err("mtd%d is already attached to ubi%d",
+				mtd->index, i);
+			err = -EINVAL;
+			goto out_mtd;
+		}
+
+	ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
+						      GFP_KERNEL);
+	if (!ubi) {
+		err = -ENOMEM;
+		goto out_mtd;
+	}
+
+	ubi->ubi_num = ubi_devices_cnt;
+	ubi->mtd = mtd;
+
+	dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
+		ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset);
+
+	ubi->vid_hdr_offset = vid_hdr_offset;
+	ubi->leb_start = data_offset;
+	err = io_init(ubi);
+	if (err)
+		goto out_free;
+
+	err = attach_by_scanning(ubi);
+	if (err) {
+		dbg_err("failed to attach by scanning, error %d", err);
+		goto out_free;
+	}
+
+	err = uif_init(ubi);
+	if (err)
+		goto out_detach;
+
+	ubi_devices_cnt += 1;
+
+	ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
+	ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
+	ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
+	ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
+		ubi->peb_size, ubi->peb_size >> 10);
+	ubi_msg("logical eraseblock size:    %d bytes", ubi->leb_size);
+	ubi_msg("number of good PEBs:        %d", ubi->good_peb_count);
+	ubi_msg("number of bad PEBs:         %d", ubi->bad_peb_count);
+	ubi_msg("smallest flash I/O unit:    %d", ubi->min_io_size);
+	ubi_msg("VID header offset:          %d (aligned %d)",
+		ubi->vid_hdr_offset, ubi->vid_hdr_aloffset);
+	ubi_msg("data offset:                %d", ubi->leb_start);
+	ubi_msg("max. allowed volumes:       %d", ubi->vtbl_slots);
+	ubi_msg("wear-leveling threshold:    %d", CONFIG_MTD_UBI_WL_THRESHOLD);
+	ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT);
+	ubi_msg("number of user volumes:     %d",
+		ubi->vol_count - UBI_INT_VOL_COUNT);
+	ubi_msg("available PEBs:             %d", ubi->avail_pebs);
+	ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs);
+	ubi_msg("number of PEBs reserved for bad PEB handling: %d",
+		ubi->beb_rsvd_pebs);
+	ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec);
+
+	/* Enable the background thread */
+	if (!DBG_DISABLE_BGT) {
+		ubi->thread_enabled = 1;
+		wake_up_process(ubi->bgt_thread);
+	}
+
+	return 0;
+
+out_detach:
+	ubi_eba_close(ubi);
+	ubi_wl_close(ubi);
+	kfree(ubi->vtbl);
+out_free:
+	kfree(ubi);
+out_mtd:
+	put_mtd_device(mtd);
+	ubi_devices[ubi_devices_cnt] = NULL;
+	return err;
+}
+
+/**
+ * detach_mtd_dev - detach an MTD device.
+ * @ubi: UBI device description object
+ */
+static void detach_mtd_dev(struct ubi_device *ubi)
+{
+	int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
+
+	dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+	uif_close(ubi);
+	ubi_eba_close(ubi);
+	ubi_wl_close(ubi);
+	kfree(ubi->vtbl);
+	put_mtd_device(ubi->mtd);
+	kfree(ubi_devices[ubi_num]);
+	ubi_devices[ubi_num] = NULL;
+	ubi_devices_cnt -= 1;
+	ubi_assert(ubi_devices_cnt >= 0);
+	ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num);
+}
+
+static int __init ubi_init(void)
+{
+	int err, i, k;
+
+	/* Ensure that EC and VID headers have correct size */
+	BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+	BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+
+	if (mtd_devs > UBI_MAX_DEVICES) {
+		printk("UBI error: too many MTD devices, maximum is %d\n",
+		       UBI_MAX_DEVICES);
+		return -EINVAL;
+	}
+
+	ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
+	if (IS_ERR(ubi_class))
+		return PTR_ERR(ubi_class);
+
+	err = class_create_file(ubi_class, &ubi_version);
+	if (err)
+		goto out_class;
+
+	/* Attach MTD devices */
+	for (i = 0; i < mtd_devs; i++) {
+		struct mtd_dev_param *p = &mtd_dev_param[i];
+
+		cond_resched();
+
+		if (!p->name) {
+			dbg_err("empty name");
+			err = -EINVAL;
+			goto out_detach;
+		}
+
+		err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
+		if (err)
+			goto out_detach;
+	}
+
+	return 0;
+
+out_detach:
+	for (k = 0; k < i; k++)
+		detach_mtd_dev(ubi_devices[k]);
+	class_remove_file(ubi_class, &ubi_version);
+out_class:
+	class_destroy(ubi_class);
+	return err;
+}
+module_init(ubi_init);
+
+static void __exit ubi_exit(void)
+{
+	int i, n = ubi_devices_cnt;
+
+	for (i = 0; i < n; i++)
+		detach_mtd_dev(ubi_devices[i]);
+	class_remove_file(ubi_class, &ubi_version);
+	class_destroy(ubi_class);
+}
+module_exit(ubi_exit);
+
+/**
+ * bytes_str_to_int - convert a string representing number of bytes to an
+ * integer.
+ * @str: the string to convert
+ *
+ * This function returns positive resulting integer in case of success and a
+ * negative error code in case of failure.
+ */
+static int __init bytes_str_to_int(const char *str)
+{
+	char *endp;
+	unsigned long result;
+
+	result = simple_strtoul(str, &endp, 0);
+	if (str == endp || result < 0) {
+		printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+		return -EINVAL;
+	}
+
+	switch (*endp) {
+	case 'G':
+		result *= 1024;
+	case 'M':
+		result *= 1024;
+	case 'K':
+	case 'k':
+		result *= 1024;
+		if (endp[1] == 'i' && (endp[2] == '\0' ||
+			  endp[2] == 'B'  || endp[2] == 'b'))
+			endp += 2;
+	case '\0':
+		break;
+	default:
+		printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+/**
+ * ubi_mtd_param_parse - parse the 'mtd=' UBI parameter.
+ * @val: the parameter value to parse
+ * @kp: not used
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of error.
+ */
+static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
+{
+	int i, len;
+	struct mtd_dev_param *p;
+	char buf[MTD_PARAM_LEN_MAX];
+	char *pbuf = &buf[0];
+	char *tokens[3] = {NULL, NULL, NULL};
+
+	if (mtd_devs == UBI_MAX_DEVICES) {
+		printk("UBI error: too many parameters, max. is %d\n",
+		       UBI_MAX_DEVICES);
+		return -EINVAL;
+	}
+
+	len = strnlen(val, MTD_PARAM_LEN_MAX);
+	if (len == MTD_PARAM_LEN_MAX) {
+		printk("UBI error: parameter \"%s\" is too long, max. is %d\n",
+		       val, MTD_PARAM_LEN_MAX);
+		return -EINVAL;
+	}
+
+	if (len == 0) {
+		printk("UBI warning: empty 'mtd=' parameter - ignored\n");
+		return 0;
+	}
+
+	strcpy(buf, val);
+
+	/* Get rid of the final newline */
+	if (buf[len - 1] == '\n')
+		buf[len - 1] = 0;
+
+	for (i = 0; i < 3; i++)
+		tokens[i] = strsep(&pbuf, ",");
+
+	if (pbuf) {
+		printk("UBI error: too many arguments at \"%s\"\n", val);
+		return -EINVAL;
+	}
+
+	if (tokens[0] == '\0')
+		return -EINVAL;
+
+	p = &mtd_dev_param[mtd_devs];
+	strcpy(&p->name[0], tokens[0]);
+
+	if (tokens[1])
+		p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
+	if (tokens[2])
+		p->data_offs = bytes_str_to_int(tokens[2]);
+
+	if (p->vid_hdr_offs < 0)
+		return p->vid_hdr_offs;
+	if (p->data_offs < 0)
+		return p->data_offs;
+
+	mtd_devs += 1;
+	return 0;
+}
+
+module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
+MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
+		      "mtd=<name|num>[,<vid_hdr_offs>,<data_offs>]. "
+		      "Multiple \"mtd\" parameters may be specified.\n"
+		      "MTD devices may be specified by their number or name. "
+		      "Optional \"vid_hdr_offs\" and \"data_offs\" parameters "
+		      "specify UBI VID header position and data starting "
+		      "position to be used by UBI.\n"
+		      "Example: mtd=content,1984,2048 mtd=4 - attach MTD device"
+		      "with name content using VID header offset 1984 and data "
+		      "start 2048, and MTD device number 4 using default "
+		      "offsets");
+
+MODULE_VERSION(__stringify(UBI_VERSION));
+MODULE_DESCRIPTION("UBI - Unsorted Block Images");
+MODULE_AUTHOR("Artem Bityutskiy");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
new file mode 100644
index 0000000..6612eb7
--- /dev/null
+++ b/drivers/mtd/ubi/cdev.c
@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * This file includes implementation of UBI character device operations.
+ *
+ * There are two kinds of character devices in UBI: UBI character devices and
+ * UBI volume character devices. UBI character devices allow users to
+ * manipulate whole volumes: create, remove, and re-size them. Volume character
+ * devices provide volume I/O capabilities.
+ *
+ * Major and minor numbers are assigned dynamically to both UBI and volume
+ * character devices.
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/ioctl.h>
+#include <linux/capability.h>
+#include <mtd/ubi-user.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+#include "ubi.h"
+
+/*
+ * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
+ * logical eraseblock erase is a debug-only feature).
+ */
+#define UBI_CDEV_IOC_MAX_SEQ 2
+#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
+#define VOL_CDEV_IOC_MAX_SEQ 1
+#else
+#define VOL_CDEV_IOC_MAX_SEQ 2
+#endif
+
+/**
+ * major_to_device - get UBI device object by character device major number.
+ * @major: major number
+ *
+ * This function returns a pointer to the UBI device object.
+ */
+static struct ubi_device *major_to_device(int major)
+{
+	int i;
+
+	for (i = 0; i < ubi_devices_cnt; i++)
+		if (ubi_devices[i] && ubi_devices[i]->major == major)
+			return ubi_devices[i];
+	BUG();
+}
+
+/**
+ * get_exclusive - get exclusive access to an UBI volume.
+ * @desc: volume descriptor
+ *
+ * This function changes UBI volume open mode to "exclusive". Returns previous
+ * mode value (positive integer) in case of success and a negative error code
+ * in case of failure.
+ */
+static int get_exclusive(struct ubi_volume_desc *desc)
+{
+	int users, err;
+	struct ubi_volume *vol = desc->vol;
+
+	spin_lock(&vol->ubi->volumes_lock);
+	users = vol->readers + vol->writers + vol->exclusive;
+	ubi_assert(users > 0);
+	if (users > 1) {
+		dbg_err("%d users for volume %d", users, vol->vol_id);
+		err = -EBUSY;
+	} else {
+		vol->readers = vol->writers = 0;
+		vol->exclusive = 1;
+		err = desc->mode;
+		desc->mode = UBI_EXCLUSIVE;
+	}
+	spin_unlock(&vol->ubi->volumes_lock);
+
+	return err;
+}
+
+/**
+ * revoke_exclusive - revoke exclusive mode.
+ * @desc: volume descriptor
+ * @mode: new mode to switch to
+ */
+static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
+{
+	struct ubi_volume *vol = desc->vol;
+
+	spin_lock(&vol->ubi->volumes_lock);
+	ubi_assert(vol->readers == 0 && vol->writers == 0);
+	ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
+	vol->exclusive = 0;
+	if (mode == UBI_READONLY)
+		vol->readers = 1;
+	else if (mode == UBI_READWRITE)
+		vol->writers = 1;
+	else
+		vol->exclusive = 1;
+	spin_unlock(&vol->ubi->volumes_lock);
+
+	desc->mode = mode;
+}
+
+static int vol_cdev_open(struct inode *inode, struct file *file)
+{
+	struct ubi_volume_desc *desc;
+	const struct ubi_device *ubi = major_to_device(imajor(inode));
+	int vol_id = iminor(inode) - 1;
+	int mode;
+
+	if (file->f_mode & FMODE_WRITE)
+		mode = UBI_READWRITE;
+	else
+		mode = UBI_READONLY;
+
+	dbg_msg("open volume %d, mode %d", vol_id, mode);
+
+	desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
+	if (IS_ERR(desc))
+		return PTR_ERR(desc);
+
+	file->private_data = desc;
+	return 0;
+}
+
+static int vol_cdev_release(struct inode *inode, struct file *file)
+{
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+
+	dbg_msg("release volume %d, mode %d", vol->vol_id, desc->mode);
+
+	if (vol->updating) {
+		ubi_warn("update of volume %d not finished, volume is damaged",
+			 vol->vol_id);
+		vol->updating = 0;
+		kfree(vol->upd_buf);
+	}
+
+	ubi_close_volume(desc);
+	return 0;
+}
+
+static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+	loff_t new_offset;
+
+	if (vol->updating) {
+		 /* Update is in progress, seeking is prohibited */
+		dbg_err("updating");
+		return -EBUSY;
+	}
+
+	switch (origin) {
+	case 0: /* SEEK_SET */
+		new_offset = offset;
+		break;
+	case 1: /* SEEK_CUR */
+		new_offset = file->f_pos + offset;
+		break;
+	case 2: /* SEEK_END */
+		new_offset = vol->used_bytes + offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (new_offset < 0 || new_offset > vol->used_bytes) {
+		dbg_err("bad seek %lld", new_offset);
+		return -EINVAL;
+	}
+
+	dbg_msg("seek volume %d, offset %lld, origin %d, new offset %lld",
+		vol->vol_id, offset, origin, new_offset);
+
+	file->f_pos = new_offset;
+	return new_offset;
+}
+
+static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
+			     loff_t *offp)
+{
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int err, lnum, off, len,  vol_id = desc->vol->vol_id, tbuf_size;
+	size_t count_save = count;
+	void *tbuf;
+	uint64_t tmp;
+
+	dbg_msg("read %zd bytes from offset %lld of volume %d",
+		count, *offp, vol_id);
+
+	if (vol->updating) {
+		dbg_err("updating");
+		return -EBUSY;
+	}
+	if (vol->upd_marker) {
+		dbg_err("damaged volume, update marker is set");
+		return -EBADF;
+	}
+	if (*offp == vol->used_bytes || count == 0)
+		return 0;
+
+	if (vol->corrupted)
+		dbg_msg("read from corrupted volume %d", vol_id);
+
+	if (*offp + count > vol->used_bytes)
+		count_save = count = vol->used_bytes - *offp;
+
+	tbuf_size = vol->usable_leb_size;
+	if (count < tbuf_size)
+		tbuf_size = ALIGN(count, ubi->min_io_size);
+	tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	len = count > tbuf_size ? tbuf_size : count;
+
+	tmp = *offp;
+	off = do_div(tmp, vol->usable_leb_size);
+	lnum = tmp;
+
+	do {
+		cond_resched();
+
+		if (off + len >= vol->usable_leb_size)
+			len = vol->usable_leb_size - off;
+
+		err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0);
+		if (err)
+			break;
+
+		off += len;
+		if (off == vol->usable_leb_size) {
+			lnum += 1;
+			off -= vol->usable_leb_size;
+		}
+
+		count -= len;
+		*offp += len;
+
+		err = copy_to_user(buf, tbuf, len);
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		buf += len;
+		len = count > tbuf_size ? tbuf_size : count;
+	} while (count);
+
+	kfree(tbuf);
+	return err ? err : count_save - count;
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
+
+/*
+ * This function allows to directly write to dynamic UBI volumes, without
+ * issuing the volume update operation. Available only as a debugging feature.
+ * Very useful for testing UBI.
+ */
+static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
+				     size_t count, loff_t *offp)
+{
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0;
+	size_t count_save = count;
+	char *tbuf;
+	uint64_t tmp;
+
+	dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
+		count, *offp, desc->vol->vol_id);
+
+	if (vol->vol_type == UBI_STATIC_VOLUME)
+		return -EROFS;
+
+	tmp = *offp;
+	off = do_div(tmp, vol->usable_leb_size);
+	lnum = tmp;
+
+	if (off % ubi->min_io_size) {
+		dbg_err("unaligned position");
+		return -EINVAL;
+	}
+
+	if (*offp + count > vol->used_bytes)
+		count_save = count = vol->used_bytes - *offp;
+
+	/* We can write only in fractions of the minimum I/O unit */
+	if (count % ubi->min_io_size) {
+		dbg_err("unaligned write length");
+		return -EINVAL;
+	}
+
+	tbuf_size = vol->usable_leb_size;
+	if (count < tbuf_size)
+		tbuf_size = ALIGN(count, ubi->min_io_size);
+	tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	len = count > tbuf_size ? tbuf_size : count;
+
+	while (count) {
+		cond_resched();
+
+		if (off + len >= vol->usable_leb_size)
+			len = vol->usable_leb_size - off;
+
+		err = copy_from_user(tbuf, buf, len);
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
+					UBI_UNKNOWN);
+		if (err)
+			break;
+
+		off += len;
+		if (off == vol->usable_leb_size) {
+			lnum += 1;
+			off -= vol->usable_leb_size;
+		}
+
+		count -= len;
+		*offp += len;
+		buf += len;
+		len = count > tbuf_size ? tbuf_size : count;
+	}
+
+	kfree(tbuf);
+	return err ? err : count_save - count;
+}
+
+#else
+#define vol_cdev_direct_write(file, buf, count, offp) -EPERM
+#endif /* CONFIG_MTD_UBI_DEBUG_USERSPACE_IO */
+
+static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
+			      size_t count, loff_t *offp)
+{
+	int err = 0;
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+
+	if (!vol->updating)
+		return vol_cdev_direct_write(file, buf, count, offp);
+
+	err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
+	if (err < 0) {
+		ubi_err("cannot write %zd bytes of update data", count);
+		return err;
+	}
+
+	if (err) {
+		/*
+		 * Update is finished, @err contains number of actually written
+		 * bytes now.
+		 */
+		count = err;
+
+		err = ubi_check_volume(ubi, vol->vol_id);
+		if (err < 0)
+			return err;
+
+		if (err) {
+			ubi_warn("volume %d on UBI device %d is corrupted",
+				 vol->vol_id, ubi->ubi_num);
+			vol->corrupted = 1;
+		}
+		vol->checked = 1;
+		revoke_exclusive(desc, UBI_READWRITE);
+	}
+
+	*offp += count;
+	return count;
+}
+
+static int vol_cdev_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct ubi_volume_desc *desc = file->private_data;
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	void __user *argp = (void __user *)arg;
+
+	if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
+	    _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
+		return -ENOTTY;
+
+	if (_IOC_DIR(cmd) && _IOC_READ)
+		err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) && _IOC_WRITE)
+		err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	switch (cmd) {
+
+	/* Volume update command */
+	case UBI_IOCVOLUP:
+	{
+		int64_t bytes, rsvd_bytes;
+
+		if (!capable(CAP_SYS_RESOURCE)) {
+			err = -EPERM;
+			break;
+		}
+
+		err = copy_from_user(&bytes, argp, sizeof(int64_t));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (desc->mode == UBI_READONLY) {
+			err = -EROFS;
+			break;
+		}
+
+		rsvd_bytes = vol->reserved_pebs * (ubi->leb_size-vol->data_pad);
+		if (bytes < 0 || bytes > rsvd_bytes) {
+			err = -EINVAL;
+			break;
+		}
+
+		err = get_exclusive(desc);
+		if (err < 0)
+			break;
+
+		err = ubi_start_update(ubi, vol->vol_id, bytes);
+		if (bytes == 0)
+			revoke_exclusive(desc, UBI_READWRITE);
+
+		file->f_pos = 0;
+		break;
+	}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
+	/* Logical eraseblock erasure command */
+	case UBI_IOCEBER:
+	{
+		int32_t lnum;
+
+		err = __get_user(lnum, (__user int32_t *)argp);
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		if (desc->mode == UBI_READONLY) {
+			err = -EROFS;
+			break;
+		}
+
+		if (lnum < 0 || lnum >= vol->reserved_pebs) {
+			err = -EINVAL;
+			break;
+		}
+
+		if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
+			err = -EROFS;
+			break;
+		}
+
+		dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
+		err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum);
+		if (err)
+			break;
+
+		err = ubi_wl_flush(ubi);
+		break;
+	}
+#endif
+
+	default:
+		err = -ENOTTY;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * verify_mkvol_req - verify volume creation request.
+ * @ubi: UBI device description object
+ * @req: the request to check
+ *
+ * This function zero if the request is correct, and %-EINVAL if not.
+ */
+static int verify_mkvol_req(const struct ubi_device *ubi,
+			    const struct ubi_mkvol_req *req)
+{
+	int n, err = -EINVAL;
+
+	if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
+	    req->name_len < 0)
+		goto bad;
+
+	if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
+	    req->vol_id != UBI_VOL_NUM_AUTO)
+		goto bad;
+
+	if (req->alignment == 0)
+		goto bad;
+
+	if (req->bytes == 0)
+		goto bad;
+
+	if (req->vol_type != UBI_DYNAMIC_VOLUME &&
+	    req->vol_type != UBI_STATIC_VOLUME)
+		goto bad;
+
+	if (req->alignment > ubi->leb_size)
+		goto bad;
+
+	n = req->alignment % ubi->min_io_size;
+	if (req->alignment != 1 && n)
+		goto bad;
+
+	if (req->name_len > UBI_VOL_NAME_MAX) {
+		err = -ENAMETOOLONG;
+		goto bad;
+	}
+
+	return 0;
+
+bad:
+	dbg_err("bad volume creation request");
+	ubi_dbg_dump_mkvol_req(req);
+	return err;
+}
+
+/**
+ * verify_rsvol_req - verify volume re-size request.
+ * @ubi: UBI device description object
+ * @req: the request to check
+ *
+ * This function returns zero if the request is correct, and %-EINVAL if not.
+ */
+static int verify_rsvol_req(const struct ubi_device *ubi,
+			    const struct ubi_rsvol_req *req)
+{
+	if (req->bytes <= 0)
+		return -EINVAL;
+
+	if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct ubi_device *ubi;
+	struct ubi_volume_desc *desc;
+	void __user *argp = (void __user *)arg;
+
+	if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
+	    _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
+		return -ENOTTY;
+
+	if (_IOC_DIR(cmd) && _IOC_READ)
+		err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) && _IOC_WRITE)
+		err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	if (!capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+
+	ubi = major_to_device(imajor(inode));
+	if (IS_ERR(ubi))
+		return PTR_ERR(ubi);
+
+	switch (cmd) {
+	/* Create volume command */
+	case UBI_IOCMKVOL:
+	{
+		struct ubi_mkvol_req req;
+
+		dbg_msg("create volume");
+		err = __copy_from_user(&req, argp,
+				       sizeof(struct ubi_mkvol_req));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = verify_mkvol_req(ubi, &req);
+		if (err)
+			break;
+
+		req.name[req.name_len] = '\0';
+
+		err = ubi_create_volume(ubi, &req);
+		if (err)
+			break;
+
+		err = __put_user(req.vol_id, (__user int32_t *)argp);
+		if (err)
+			err = -EFAULT;
+
+		break;
+	}
+
+	/* Remove volume command */
+	case UBI_IOCRMVOL:
+	{
+		int vol_id;
+
+		dbg_msg("remove volume");
+		err = __get_user(vol_id, (__user int32_t *)argp);
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
+		if (IS_ERR(desc)) {
+			err = PTR_ERR(desc);
+			break;
+		}
+
+		err = ubi_remove_volume(desc);
+		if (err)
+			ubi_close_volume(desc);
+
+		break;
+	}
+
+	/* Re-size volume command */
+	case UBI_IOCRSVOL:
+	{
+		int pebs;
+		uint64_t tmp;
+		struct ubi_rsvol_req req;
+
+		dbg_msg("re-size volume");
+		err = __copy_from_user(&req, argp,
+				       sizeof(struct ubi_rsvol_req));
+		if (err) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = verify_rsvol_req(ubi, &req);
+		if (err)
+			break;
+
+		desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);
+		if (IS_ERR(desc)) {
+			err = PTR_ERR(desc);
+			break;
+		}
+
+		tmp = req.bytes;
+		pebs = !!do_div(tmp, desc->vol->usable_leb_size);
+		pebs += tmp;
+
+		err = ubi_resize_volume(desc, pebs);
+		ubi_close_volume(desc);
+		break;
+	}
+
+	default:
+		err = -ENOTTY;
+		break;
+	}
+
+	return err;
+}
+
+/* UBI character device operations */
+struct file_operations ubi_cdev_operations = {
+	.owner = THIS_MODULE,
+	.ioctl = ubi_cdev_ioctl,
+	.llseek = no_llseek
+};
+
+/* UBI volume character device operations */
+struct file_operations ubi_vol_cdev_operations = {
+	.owner   = THIS_MODULE,
+	.open    = vol_cdev_open,
+	.release = vol_cdev_release,
+	.llseek  = vol_cdev_llseek,
+	.read    = vol_cdev_read,
+	.write   = vol_cdev_write,
+	.ioctl   = vol_cdev_ioctl
+};
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
new file mode 100644
index 0000000..8636422
--- /dev/null
+++ b/drivers/mtd/ubi/debug.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * Here we keep all the UBI debugging stuff which should normally be disabled
+ * and compiled-out, but it is extremely helpful when hunting bugs or doing big
+ * changes.
+ */
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG
+
+#include "ubi.h"
+
+/**
+ * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+ * @ec_hdr: the erase counter header to dump
+ */
+void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
+{
+	dbg_msg("erase counter header dump:");
+	dbg_msg("magic          %#08x", ubi32_to_cpu(ec_hdr->magic));
+	dbg_msg("version        %d",    (int)ec_hdr->version);
+	dbg_msg("ec             %llu",  (long long)ubi64_to_cpu(ec_hdr->ec));
+	dbg_msg("vid_hdr_offset %d",    ubi32_to_cpu(ec_hdr->vid_hdr_offset));
+	dbg_msg("data_offset    %d",    ubi32_to_cpu(ec_hdr->data_offset));
+	dbg_msg("hdr_crc        %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+	dbg_msg("erase counter header hexdump:");
+	ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
+}
+
+/**
+ * ubi_dbg_dump_vid_hdr - dump a volume identifier header.
+ * @vid_hdr: the volume identifier header to dump
+ */
+void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+{
+	dbg_msg("volume identifier header dump:");
+	dbg_msg("magic     %08x", ubi32_to_cpu(vid_hdr->magic));
+	dbg_msg("version   %d",   (int)vid_hdr->version);
+	dbg_msg("vol_type  %d",   (int)vid_hdr->vol_type);
+	dbg_msg("copy_flag %d",   (int)vid_hdr->copy_flag);
+	dbg_msg("compat    %d",   (int)vid_hdr->compat);
+	dbg_msg("vol_id    %d",   ubi32_to_cpu(vid_hdr->vol_id));
+	dbg_msg("lnum      %d",   ubi32_to_cpu(vid_hdr->lnum));
+	dbg_msg("leb_ver   %u",   ubi32_to_cpu(vid_hdr->leb_ver));
+	dbg_msg("data_size %d",   ubi32_to_cpu(vid_hdr->data_size));
+	dbg_msg("used_ebs  %d",   ubi32_to_cpu(vid_hdr->used_ebs));
+	dbg_msg("data_pad  %d",   ubi32_to_cpu(vid_hdr->data_pad));
+	dbg_msg("sqnum     %llu",
+		(unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
+	dbg_msg("hdr_crc   %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+	dbg_msg("volume identifier header hexdump:");
+}
+
+/**
+ * ubi_dbg_dump_vol_info- dump volume information.
+ * @vol: UBI volume description object
+ */
+void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
+{
+	dbg_msg("volume information dump:");
+	dbg_msg("vol_id          %d", vol->vol_id);
+	dbg_msg("reserved_pebs   %d", vol->reserved_pebs);
+	dbg_msg("alignment       %d", vol->alignment);
+	dbg_msg("data_pad        %d", vol->data_pad);
+	dbg_msg("vol_type        %d", vol->vol_type);
+	dbg_msg("name_len        %d", vol->name_len);
+	dbg_msg("usable_leb_size %d", vol->usable_leb_size);
+	dbg_msg("used_ebs        %d", vol->used_ebs);
+	dbg_msg("used_bytes      %lld", vol->used_bytes);
+	dbg_msg("last_eb_bytes   %d", vol->last_eb_bytes);
+	dbg_msg("corrupted       %d", vol->corrupted);
+	dbg_msg("upd_marker      %d", vol->upd_marker);
+
+	if (vol->name_len <= UBI_VOL_NAME_MAX &&
+	    strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
+		dbg_msg("name          %s", vol->name);
+	} else {
+		dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
+			vol->name[0], vol->name[1], vol->name[2],
+			vol->name[3], vol->name[4]);
+	}
+}
+
+/**
+ * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * @r: the object to dump
+ * @idx: volume table index
+ */
+void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+{
+	int name_len = ubi16_to_cpu(r->name_len);
+
+	dbg_msg("volume table record %d dump:", idx);
+	dbg_msg("reserved_pebs   %d", ubi32_to_cpu(r->reserved_pebs));
+	dbg_msg("alignment       %d", ubi32_to_cpu(r->alignment));
+	dbg_msg("data_pad        %d", ubi32_to_cpu(r->data_pad));
+	dbg_msg("vol_type        %d", (int)r->vol_type);
+	dbg_msg("upd_marker      %d", (int)r->upd_marker);
+	dbg_msg("name_len        %d", name_len);
+
+	if (r->name[0] == '\0') {
+		dbg_msg("name          NULL");
+		return;
+	}
+
+	if (name_len <= UBI_VOL_NAME_MAX &&
+	    strnlen(&r->name[0], name_len + 1) == name_len) {
+		dbg_msg("name          %s", &r->name[0]);
+	} else {
+		dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
+			r->name[0], r->name[1], r->name[2], r->name[3],
+			r->name[4]);
+	}
+	dbg_msg("crc             %#08x", ubi32_to_cpu(r->crc));
+}
+
+/**
+ * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
+ * @sv: the object to dump
+ */
+void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
+{
+	dbg_msg("volume scanning information dump:");
+	dbg_msg("vol_id         %d", sv->vol_id);
+	dbg_msg("highest_lnum   %d", sv->highest_lnum);
+	dbg_msg("leb_count      %d", sv->leb_count);
+	dbg_msg("compat         %d", sv->compat);
+	dbg_msg("vol_type       %d", sv->vol_type);
+	dbg_msg("used_ebs       %d", sv->used_ebs);
+	dbg_msg("last_data_size %d", sv->last_data_size);
+	dbg_msg("data_pad       %d", sv->data_pad);
+}
+
+/**
+ * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
+ * @seb: the object to dump
+ * @type: object type: 0 - not corrupted, 1 - corrupted
+ */
+void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
+{
+	dbg_msg("eraseblock scanning information dump:");
+	dbg_msg("ec       %d", seb->ec);
+	dbg_msg("pnum     %d", seb->pnum);
+	if (type == 0) {
+		dbg_msg("lnum     %d", seb->lnum);
+		dbg_msg("scrub    %d", seb->scrub);
+		dbg_msg("sqnum    %llu", seb->sqnum);
+		dbg_msg("leb_ver  %u", seb->leb_ver);
+	}
+}
+
+/**
+ * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
+ * @req: the object to dump
+ */
+void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
+{
+	char nm[17];
+
+	dbg_msg("volume creation request dump:");
+	dbg_msg("vol_id    %d",   req->vol_id);
+	dbg_msg("alignment %d",   req->alignment);
+	dbg_msg("bytes     %lld", (long long)req->bytes);
+	dbg_msg("vol_type  %d",   req->vol_type);
+	dbg_msg("name_len  %d",   req->name_len);
+
+	memcpy(nm, req->name, 16);
+	nm[16] = 0;
+	dbg_msg("the 1st 16 characters of the name: %s", nm);
+}
+
+#define BYTES_PER_LINE 32
+
+/**
+ * ubi_dbg_hexdump - dump a buffer.
+ * @ptr: the buffer to dump
+ * @size: buffer size which must be multiple of 4 bytes
+ */
+void ubi_dbg_hexdump(const void *ptr, int size)
+{
+	int i, k = 0, rows, columns;
+	const uint8_t *p = ptr;
+
+	size = ALIGN(size, 4);
+	rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
+	for (i = 0; i < rows; i++) {
+		int j;
+
+		cond_resched();
+		columns = min(size - k, BYTES_PER_LINE) / 4;
+		if (columns == 0)
+			break;
+		printk(KERN_DEBUG "%5d:  ", i * BYTES_PER_LINE);
+		for (j = 0; j < columns; j++) {
+			int n, N;
+
+			N = size - k > 4 ? 4 : size - k;
+			for (n = 0; n < N; n++)
+				printk("%02x", p[k++]);
+			printk(" ");
+		}
+		printk("\n");
+	}
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
new file mode 100644
index 0000000..f816ad9
--- /dev/null
+++ b/drivers/mtd/ubi/debug.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+#ifndef __UBI_DEBUG_H__
+#define __UBI_DEBUG_H__
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+#include <linux/random.h>
+
+#define ubi_assert(expr)  BUG_ON(!(expr))
+#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
+#else
+#define ubi_assert(expr)  ({})
+#define dbg_err(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
+#define DBG_DISABLE_BGT 1
+#else
+#define DBG_DISABLE_BGT 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG
+/* Generic debugging message */
+#define dbg_msg(fmt, ...) \
+	printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+
+#define ubi_dbg_dump_stack() dump_stack()
+
+struct ubi_ec_hdr;
+struct ubi_vid_hdr;
+struct ubi_volume;
+struct ubi_vtbl_record;
+struct ubi_scan_volume;
+struct ubi_scan_leb;
+struct ubi_mkvol_req;
+
+void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
+void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
+void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
+void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
+void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
+void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
+void ubi_dbg_hexdump(const void *buf, int size);
+
+#else
+
+#define dbg_msg(fmt, ...)    ({})
+#define ubi_dbg_dump_stack() ({})
+#define ubi_dbg_print(func, fmt, ...)    ({})
+#define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
+#define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
+#define ubi_dbg_dump_vol_info(vol)       ({})
+#define ubi_dbg_dump_vtbl_record(r, idx) ({})
+#define ubi_dbg_dump_sv(sv)              ({})
+#define ubi_dbg_dump_seb(seb, type)      ({})
+#define ubi_dbg_dump_mkvol_req(req)      ({})
+#define ubi_dbg_hexdump(buf, size)       ({})
+
+#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
+/* Messages from the eraseblock association unit */
+#define dbg_eba(fmt, ...) \
+	printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \
+	       ##__VA_ARGS__)
+#else
+#define dbg_eba(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
+/* Messages from the wear-leveling unit */
+#define dbg_wl(fmt, ...) \
+	printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \
+	       ##__VA_ARGS__)
+#else
+#define dbg_wl(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
+/* Messages from the input/output unit */
+#define dbg_io(fmt, ...) \
+	printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \
+	       ##__VA_ARGS__)
+#else
+#define dbg_io(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
+/* Initialization and build messages */
+#define dbg_bld(fmt, ...) \
+	printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \
+	       ##__VA_ARGS__)
+#else
+#define dbg_bld(fmt, ...) ({})
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
+/**
+ * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
+ *
+ * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
+ */
+static inline int ubi_dbg_is_bitflip(void)
+{
+	return !(random32() % 200);
+}
+#else
+#define ubi_dbg_is_bitflip() 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
+/**
+ * ubi_dbg_is_write_failure - if it is time to emulate a write failure.
+ *
+ * Returns non-zero if a write failure should be emulated, otherwise returns
+ * zero.
+ */
+static inline int ubi_dbg_is_write_failure(void)
+{
+	return !(random32() % 500);
+}
+#else
+#define ubi_dbg_is_write_failure() 0
+#endif
+
+#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
+/**
+ * ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
+ *
+ * Returns non-zero if an erase failure should be emulated, otherwise returns
+ * zero.
+ */
+static inline int ubi_dbg_is_erase_failure(void)
+{
+		return !(random32() % 400);
+}
+#else
+#define ubi_dbg_is_erase_failure() 0
+#endif
+
+#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
new file mode 100644
index 0000000..3dba573
--- /dev/null
+++ b/drivers/mtd/ubi/eba.c
@@ -0,0 +1,1240 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * The UBI Eraseblock Association (EBA) unit.
+ *
+ * This unit is responsible for I/O to/from logical eraseblock.
+ *
+ * Although in this implementation the EBA table is fully kept and managed in
+ * RAM, which assumes poor scalability, it might be (partially) maintained on
+ * flash in future implementations.
+ *
+ * The EBA unit implements per-logical eraseblock locking. Before accessing a
+ * logical eraseblock it is locked for reading or writing. The per-logical
+ * eraseblock locking is implemented by means of the lock tree. The lock tree
+ * is an RB-tree which refers all the currently locked logical eraseblocks. The
+ * lock tree elements are &struct ltree_entry objects. They are indexed by
+ * (@vol_id, @lnum) pairs.
+ *
+ * EBA also maintains the global sequence counter which is incremented each
+ * time a logical eraseblock is mapped to a physical eraseblock and it is
+ * stored in the volume identifier header. This means that each VID header has
+ * a unique sequence number. The sequence number is only increased an we assume
+ * 64 bits is enough to never overflow.
+ */
+
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include "ubi.h"
+
+/**
+ * struct ltree_entry - an entry in the lock tree.
+ * @rb: links RB-tree nodes
+ * @vol_id: volume ID of the locked logical eraseblock
+ * @lnum: locked logical eraseblock number
+ * @users: how many tasks are using this logical eraseblock or wait for it
+ * @mutex: read/write mutex to implement read/write access serialization to
+ * the (@vol_id, @lnum) logical eraseblock
+ *
+ * When a logical eraseblock is being locked - corresponding &struct ltree_entry
+ * object is inserted to the lock tree (@ubi->ltree).
+ */
+struct ltree_entry {
+	struct rb_node rb;
+	int vol_id;
+	int lnum;
+	int users;
+	struct rw_semaphore mutex;
+};
+
+/* Slab cache for lock-tree entries */
+static struct kmem_cache *ltree_slab;
+
+/**
+ * next_sqnum - get next sequence number.
+ * @ubi: UBI device description object
+ *
+ * This function returns next sequence number to use, which is just the current
+ * global sequence counter value. It also increases the global sequence
+ * counter.
+ */
+static unsigned long long next_sqnum(struct ubi_device *ubi)
+{
+	unsigned long long sqnum;
+
+	spin_lock(&ubi->ltree_lock);
+	sqnum = ubi->global_sqnum++;
+	spin_unlock(&ubi->ltree_lock);
+
+	return sqnum;
+}
+
+/**
+ * ubi_get_compat - get compatibility flags of a volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ *
+ * This function returns compatibility flags for an internal volume. User
+ * volumes have no compatibility flags, so %0 is returned.
+ */
+static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
+{
+	if (vol_id == UBI_LAYOUT_VOL_ID)
+		return UBI_LAYOUT_VOLUME_COMPAT;
+	return 0;
+}
+
+/**
+ * ltree_lookup - look up the lock tree.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function returns a pointer to the corresponding &struct ltree_entry
+ * object if the logical eraseblock is locked and %NULL if it is not.
+ * @ubi->ltree_lock has to be locked.
+ */
+static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
+					int lnum)
+{
+	struct rb_node *p;
+
+	p = ubi->ltree.rb_node;
+	while (p) {
+		struct ltree_entry *le;
+
+		le = rb_entry(p, struct ltree_entry, rb);
+
+		if (vol_id < le->vol_id)
+			p = p->rb_left;
+		else if (vol_id > le->vol_id)
+			p = p->rb_right;
+		else {
+			if (lnum < le->lnum)
+				p = p->rb_left;
+			else if (lnum > le->lnum)
+				p = p->rb_right;
+			else
+				return le;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * ltree_add_entry - add new entry to the lock tree.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function adds new entry for logical eraseblock (@vol_id, @lnum) to the
+ * lock tree. If such entry is already there, its usage counter is increased.
+ * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation
+ * failed.
+ */
+static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
+					   int lnum)
+{
+	struct ltree_entry *le, *le1, *le_free;
+
+	le = kmem_cache_alloc(ltree_slab, GFP_KERNEL);
+	if (!le)
+		return ERR_PTR(-ENOMEM);
+
+	le->vol_id = vol_id;
+	le->lnum = lnum;
+
+	spin_lock(&ubi->ltree_lock);
+	le1 = ltree_lookup(ubi, vol_id, lnum);
+
+	if (le1) {
+		/*
+		 * This logical eraseblock is already locked. The newly
+		 * allocated lock entry is not needed.
+		 */
+		le_free = le;
+		le = le1;
+	} else {
+		struct rb_node **p, *parent = NULL;
+
+		/*
+		 * No lock entry, add the newly allocated one to the
+		 * @ubi->ltree RB-tree.
+		 */
+		le_free = NULL;
+
+		p = &ubi->ltree.rb_node;
+		while (*p) {
+			parent = *p;
+			le1 = rb_entry(parent, struct ltree_entry, rb);
+
+			if (vol_id < le1->vol_id)
+				p = &(*p)->rb_left;
+			else if (vol_id > le1->vol_id)
+				p = &(*p)->rb_right;
+			else {
+				ubi_assert(lnum != le1->lnum);
+				if (lnum < le1->lnum)
+					p = &(*p)->rb_left;
+				else
+					p = &(*p)->rb_right;
+			}
+		}
+
+		rb_link_node(&le->rb, parent, p);
+		rb_insert_color(&le->rb, &ubi->ltree);
+	}
+	le->users += 1;
+	spin_unlock(&ubi->ltree_lock);
+
+	if (le_free)
+		kmem_cache_free(ltree_slab, le_free);
+
+	return le;
+}
+
+/**
+ * leb_read_lock - lock logical eraseblock for reading.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for reading. Returns zero in case
+ * of success and a negative error code in case of failure.
+ */
+static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+	struct ltree_entry *le;
+
+	le = ltree_add_entry(ubi, vol_id, lnum);
+	if (IS_ERR(le))
+		return PTR_ERR(le);
+	down_read(&le->mutex);
+	return 0;
+}
+
+/**
+ * leb_read_unlock - unlock logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ */
+static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+	int free = 0;
+	struct ltree_entry *le;
+
+	spin_lock(&ubi->ltree_lock);
+	le = ltree_lookup(ubi, vol_id, lnum);
+	le->users -= 1;
+	ubi_assert(le->users >= 0);
+	if (le->users == 0) {
+		rb_erase(&le->rb, &ubi->ltree);
+		free = 1;
+	}
+	spin_unlock(&ubi->ltree_lock);
+
+	up_read(&le->mutex);
+	if (free)
+		kmem_cache_free(ltree_slab, le);
+}
+
+/**
+ * leb_write_lock - lock logical eraseblock for writing.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for writing. Returns zero in case
+ * of success and a negative error code in case of failure.
+ */
+static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+	struct ltree_entry *le;
+
+	le = ltree_add_entry(ubi, vol_id, lnum);
+	if (IS_ERR(le))
+		return PTR_ERR(le);
+	down_write(&le->mutex);
+	return 0;
+}
+
+/**
+ * leb_write_unlock - unlock logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ */
+static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+	int free;
+	struct ltree_entry *le;
+
+	spin_lock(&ubi->ltree_lock);
+	le = ltree_lookup(ubi, vol_id, lnum);
+	le->users -= 1;
+	ubi_assert(le->users >= 0);
+	if (le->users == 0) {
+		rb_erase(&le->rb, &ubi->ltree);
+		free = 1;
+	} else
+		free = 0;
+	spin_unlock(&ubi->ltree_lock);
+
+	up_write(&le->mutex);
+	if (free)
+		kmem_cache_free(ltree_slab, le);
+}
+
+/**
+ * ubi_eba_unmap_leb - un-map logical eraseblock.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and schedules corresponding
+ * physical eraseblock for erasure. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum)
+{
+	int idx = vol_id2idx(ubi, vol_id), err, pnum;
+	struct ubi_volume *vol = ubi->volumes[idx];
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	err = leb_write_lock(ubi, vol_id, lnum);
+	if (err)
+		return err;
+
+	pnum = vol->eba_tbl[lnum];
+	if (pnum < 0)
+		/* This logical eraseblock is already unmapped */
+		goto out_unlock;
+
+	dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
+
+	vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
+	err = ubi_wl_put_peb(ubi, pnum, 0);
+
+out_unlock:
+	leb_write_unlock(ubi, vol_id, lnum);
+	return err;
+}
+
+/**
+ * ubi_eba_read_leb - read data.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: buffer to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * If the logical eraseblock @lnum is unmapped, @buf is filled with 0xFF
+ * bytes. The @check flag only makes sense for static volumes and forces
+ * eraseblock data CRC checking.
+ *
+ * In case of success this function returns zero. In case of a static volume,
+ * if data CRC mismatches - %-EBADMSG is returned. %-EBADMSG may also be
+ * returned for any volume type if an ECC error was detected by the MTD device
+ * driver. Other negative error cored may be returned in case of other errors.
+ */
+int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
+		     int offset, int len, int check)
+{
+	int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id);
+	struct ubi_vid_hdr *vid_hdr;
+	struct ubi_volume *vol = ubi->volumes[idx];
+	uint32_t crc, crc1;
+
+	err = leb_read_lock(ubi, vol_id, lnum);
+	if (err)
+		return err;
+
+	pnum = vol->eba_tbl[lnum];
+	if (pnum < 0) {
+		/*
+		 * The logical eraseblock is not mapped, fill the whole buffer
+		 * with 0xFF bytes. The exception is static volumes for which
+		 * it is an error to read unmapped logical eraseblocks.
+		 */
+		dbg_eba("read %d bytes from offset %d of LEB %d:%d (unmapped)",
+			len, offset, vol_id, lnum);
+		leb_read_unlock(ubi, vol_id, lnum);
+		ubi_assert(vol->vol_type != UBI_STATIC_VOLUME);
+		memset(buf, 0xFF, len);
+		return 0;
+	}
+
+	dbg_eba("read %d bytes from offset %d of LEB %d:%d, PEB %d",
+		len, offset, vol_id, lnum, pnum);
+
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+		check = 0;
+
+retry:
+	if (check) {
+		vid_hdr = ubi_zalloc_vid_hdr(ubi);
+		if (!vid_hdr) {
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+
+		err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+		if (err && err != UBI_IO_BITFLIPS) {
+			if (err > 0) {
+				/*
+				 * The header is either absent or corrupted.
+				 * The former case means there is a bug -
+				 * switch to read-only mode just in case.
+				 * The latter case means a real corruption - we
+				 * may try to recover data. FIXME: but this is
+				 * not implemented.
+				 */
+				if (err == UBI_IO_BAD_VID_HDR) {
+					ubi_warn("bad VID header at PEB %d, LEB"
+						 "%d:%d", pnum, vol_id, lnum);
+					err = -EBADMSG;
+				} else
+					ubi_ro_mode(ubi);
+			}
+			goto out_free;
+		} else if (err == UBI_IO_BITFLIPS)
+			scrub = 1;
+
+		ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
+		ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+
+		crc = ubi32_to_cpu(vid_hdr->data_crc);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+	}
+
+	err = ubi_io_read_data(ubi, buf, pnum, offset, len);
+	if (err) {
+		if (err == UBI_IO_BITFLIPS) {
+			scrub = 1;
+			err = 0;
+		} else if (err == -EBADMSG) {
+			if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+				goto out_unlock;
+			scrub = 1;
+			if (!check) {
+				ubi_msg("force data checking");
+				check = 1;
+				goto retry;
+			}
+		} else
+			goto out_unlock;
+	}
+
+	if (check) {
+		crc1 = crc32(UBI_CRC32_INIT, buf, len);
+		if (crc1 != crc) {
+			ubi_warn("CRC error: calculated %#08x, must be %#08x",
+				 crc1, crc);
+			err = -EBADMSG;
+			goto out_unlock;
+		}
+	}
+
+	if (scrub)
+		err = ubi_wl_scrub_peb(ubi, pnum);
+
+	leb_read_unlock(ubi, vol_id, lnum);
+	return err;
+
+out_free:
+	ubi_free_vid_hdr(ubi, vid_hdr);
+out_unlock:
+	leb_read_unlock(ubi, vol_id, lnum);
+	return err;
+}
+
+/**
+ * recover_peb - recover from write failure.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to recover
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: data which was not written because of the write failure
+ * @offset: offset of the failed write
+ * @len: how many bytes should have been written
+ *
+ * This function is called in case of a write failure and moves all good data
+ * from the potentially bad physical eraseblock to a good physical eraseblock.
+ * This function also writes the data which was not written due to the failure.
+ * Returns new physical eraseblock number in case of success, and a negative
+ * error code in case of failure.
+ */
+static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
+		       const void *buf, int offset, int len)
+{
+	int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
+	struct ubi_volume *vol = ubi->volumes[idx];
+	struct ubi_vid_hdr *vid_hdr;
+	unsigned char *new_buf;
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr) {
+		return -ENOMEM;
+	}
+
+retry:
+	new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
+	if (new_pnum < 0) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return new_pnum;
+	}
+
+	ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum);
+
+	err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
+	if (err && err != UBI_IO_BITFLIPS) {
+		if (err > 0)
+			err = -EIO;
+		goto out_put;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
+	if (err)
+		goto write_error;
+
+	data_size = offset + len;
+	new_buf = kmalloc(data_size, GFP_KERNEL);
+	if (!new_buf) {
+		err = -ENOMEM;
+		goto out_put;
+	}
+	memset(new_buf + offset, 0xFF, len);
+
+	/* Read everything before the area where the write failure happened */
+	if (offset > 0) {
+		err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
+		if (err && err != UBI_IO_BITFLIPS) {
+			kfree(new_buf);
+			goto out_put;
+		}
+	}
+
+	memcpy(new_buf + offset, buf, len);
+
+	err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
+	if (err) {
+		kfree(new_buf);
+		goto write_error;
+	}
+
+	kfree(new_buf);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+
+	vol->eba_tbl[lnum] = new_pnum;
+	ubi_wl_put_peb(ubi, pnum, 1);
+
+	ubi_msg("data was successfully recovered");
+	return 0;
+
+out_put:
+	ubi_wl_put_peb(ubi, new_pnum, 1);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return err;
+
+write_error:
+	/*
+	 * Bad luck? This physical eraseblock is bad too? Crud. Let's try to
+	 * get another one.
+	 */
+	ubi_warn("failed to write to PEB %d", new_pnum);
+	ubi_wl_put_peb(ubi, new_pnum, 1);
+	if (++tries > UBI_IO_RETRIES) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+	ubi_msg("try again");
+	goto retry;
+}
+
+/**
+ * ubi_eba_write_leb - write data to dynamic volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: the data to write
+ * @offset: offset within the logical eraseblock where to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ *
+ * This function writes data to logical eraseblock @lnum of a dynamic volume
+ * @vol_id. Returns zero in case of success and a negative error code in case
+ * of failure. In case of error, it is possible that something was still
+ * written to the flash media, but may be some garbage.
+ */
+int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
+		      const void *buf, int offset, int len, int dtype)
+{
+	int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0;
+	struct ubi_volume *vol = ubi->volumes[idx];
+	struct ubi_vid_hdr *vid_hdr;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	err = leb_write_lock(ubi, vol_id, lnum);
+	if (err)
+		return err;
+
+	pnum = vol->eba_tbl[lnum];
+	if (pnum >= 0) {
+		dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
+			len, offset, vol_id, lnum, pnum);
+
+		err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+		if (err) {
+			ubi_warn("failed to write data to PEB %d", pnum);
+			if (err == -EIO && ubi->bad_allowed)
+				err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len);
+			if (err)
+				ubi_ro_mode(ubi);
+		}
+		leb_write_unlock(ubi, vol_id, lnum);
+		return err;
+	}
+
+	/*
+	 * The logical eraseblock is not mapped. We have to get a free physical
+	 * eraseblock and write the volume identifier header there first.
+	 */
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr) {
+		leb_write_unlock(ubi, vol_id, lnum);
+		return -ENOMEM;
+	}
+
+	vid_hdr->vol_type = UBI_VID_DYNAMIC;
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
+	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+
+retry:
+	pnum = ubi_wl_get_peb(ubi, dtype);
+	if (pnum < 0) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		leb_write_unlock(ubi, vol_id, lnum);
+		return pnum;
+	}
+
+	dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d",
+		len, offset, vol_id, lnum, pnum);
+
+	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+	if (err) {
+		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+			 vol_id, lnum, pnum);
+		goto write_error;
+	}
+
+	err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+	if (err) {
+		ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, "
+			 "PEB %d", len, offset, vol_id, lnum, pnum);
+		goto write_error;
+	}
+
+	vol->eba_tbl[lnum] = pnum;
+
+	leb_write_unlock(ubi, vol_id, lnum);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return 0;
+
+write_error:
+	if (err != -EIO || !ubi->bad_allowed) {
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	/*
+	 * Fortunately, this is the first write operation to this physical
+	 * eraseblock, so just put it and request a new one. We assume that if
+	 * this physical eraseblock went bad, the erase code will handle that.
+	 */
+	err = ubi_wl_put_peb(ubi, pnum, 1);
+	if (err || ++tries > UBI_IO_RETRIES) {
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	ubi_msg("try another PEB");
+	goto retry;
+}
+
+/**
+ * ubi_eba_write_leb_st - write data to static volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ * @used_ebs: how many logical eraseblocks will this volume contain
+ *
+ * This function writes data to logical eraseblock @lnum of static volume
+ * @vol_id. The @used_ebs argument should contain total number of logical
+ * eraseblock in this static volume.
+ *
+ * When writing to the last logical eraseblock, the @len argument doesn't have
+ * to be aligned to the minimal I/O unit size. Instead, it has to be equivalent
+ * to the real data size, although the @buf buffer has to contain the
+ * alignment. In all other cases, @len has to be aligned.
+ *
+ * It is prohibited to write more then once to logical eraseblocks of static
+ * volumes. This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
+			 const void *buf, int len, int dtype, int used_ebs)
+{
+	int err, pnum, tries = 0, data_size = len;
+	int idx = vol_id2idx(ubi, vol_id);
+	struct ubi_volume *vol = ubi->volumes[idx];
+	struct ubi_vid_hdr *vid_hdr;
+	uint32_t crc;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	if (lnum == used_ebs - 1)
+		/* If this is the last LEB @len may be unaligned */
+		len = ALIGN(data_size, ubi->min_io_size);
+	else
+		ubi_assert(len % ubi->min_io_size == 0);
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	err = leb_write_lock(ubi, vol_id, lnum);
+	if (err) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
+	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+
+	crc = crc32(UBI_CRC32_INIT, buf, data_size);
+	vid_hdr->vol_type = UBI_VID_STATIC;
+	vid_hdr->data_size = cpu_to_ubi32(data_size);
+	vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
+	vid_hdr->data_crc = cpu_to_ubi32(crc);
+
+retry:
+	pnum = ubi_wl_get_peb(ubi, dtype);
+	if (pnum < 0) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		leb_write_unlock(ubi, vol_id, lnum);
+		return pnum;
+	}
+
+	dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d",
+		len, vol_id, lnum, pnum, used_ebs);
+
+	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+	if (err) {
+		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+			 vol_id, lnum, pnum);
+		goto write_error;
+	}
+
+	err = ubi_io_write_data(ubi, buf, pnum, 0, len);
+	if (err) {
+		ubi_warn("failed to write %d bytes of data to PEB %d",
+			 len, pnum);
+		goto write_error;
+	}
+
+	ubi_assert(vol->eba_tbl[lnum] < 0);
+	vol->eba_tbl[lnum] = pnum;
+
+	leb_write_unlock(ubi, vol_id, lnum);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return 0;
+
+write_error:
+	if (err != -EIO || !ubi->bad_allowed) {
+		/*
+		 * This flash device does not admit of bad eraseblocks or
+		 * something nasty and unexpected happened. Switch to read-only
+		 * mode just in case.
+		 */
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	err = ubi_wl_put_peb(ubi, pnum, 1);
+	if (err || ++tries > UBI_IO_RETRIES) {
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	ubi_msg("try another PEB");
+	goto retry;
+}
+
+/*
+ * ubi_eba_atomic_leb_change - change logical eraseblock atomically.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: data type
+ *
+ * This function changes the contents of a logical eraseblock atomically. @buf
+ * has to contain new logical eraseblock data, and @len - the length of the
+ * data, which has to be aligned. This function guarantees that in case of an
+ * unclean reboot the old contents is preserved. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
+			      const void *buf, int len, int dtype)
+{
+	int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id);
+	struct ubi_volume *vol = ubi->volumes[idx];
+	struct ubi_vid_hdr *vid_hdr;
+	uint32_t crc;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	err = leb_write_lock(ubi, vol_id, lnum);
+	if (err) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
+	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
+	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+
+	crc = crc32(UBI_CRC32_INIT, buf, len);
+	vid_hdr->vol_type = UBI_VID_STATIC;
+	vid_hdr->data_size = cpu_to_ubi32(len);
+	vid_hdr->copy_flag = 1;
+	vid_hdr->data_crc = cpu_to_ubi32(crc);
+
+retry:
+	pnum = ubi_wl_get_peb(ubi, dtype);
+	if (pnum < 0) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		leb_write_unlock(ubi, vol_id, lnum);
+		return pnum;
+	}
+
+	dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
+		vol_id, lnum, vol->eba_tbl[lnum], pnum);
+
+	err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
+	if (err) {
+		ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+			 vol_id, lnum, pnum);
+		goto write_error;
+	}
+
+	err = ubi_io_write_data(ubi, buf, pnum, 0, len);
+	if (err) {
+		ubi_warn("failed to write %d bytes of data to PEB %d",
+			 len, pnum);
+		goto write_error;
+	}
+
+	err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+	if (err) {
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		leb_write_unlock(ubi, vol_id, lnum);
+		return err;
+	}
+
+	vol->eba_tbl[lnum] = pnum;
+	leb_write_unlock(ubi, vol_id, lnum);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return 0;
+
+write_error:
+	if (err != -EIO || !ubi->bad_allowed) {
+		/*
+		 * This flash device does not admit of bad eraseblocks or
+		 * something nasty and unexpected happened. Switch to read-only
+		 * mode just in case.
+		 */
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	err = ubi_wl_put_peb(ubi, pnum, 1);
+	if (err || ++tries > UBI_IO_RETRIES) {
+		ubi_ro_mode(ubi);
+		leb_write_unlock(ubi, vol_id, lnum);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return err;
+	}
+
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	ubi_msg("try another PEB");
+	goto retry;
+}
+
+/**
+ * ltree_entry_ctor - lock tree entries slab cache constructor.
+ * @obj: the lock-tree entry to construct
+ * @cache: the lock tree entry slab cache
+ * @flags: constructor flags
+ */
+static void ltree_entry_ctor(void *obj, struct kmem_cache *cache,
+			     unsigned long flags)
+{
+	struct ltree_entry *le = obj;
+
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
+		return;
+
+	le->users = 0;
+	init_rwsem(&le->mutex);
+}
+
+/**
+ * ubi_eba_copy_leb - copy logical eraseblock.
+ * @ubi: UBI device description object
+ * @from: physical eraseblock number from where to copy
+ * @to: physical eraseblock number where to copy
+ * @vid_hdr: VID header of the @from physical eraseblock
+ *
+ * This function copies logical eraseblock from physical eraseblock @from to
+ * physical eraseblock @to. The @vid_hdr buffer may be changed by this
+ * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation
+ * was canceled because bit-flips were detected at the target PEB, and a
+ * negative error code in case of failure.
+ */
+int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+		     struct ubi_vid_hdr *vid_hdr)
+{
+	int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
+	struct ubi_volume *vol;
+	uint32_t crc;
+	void *buf, *buf1 = NULL;
+
+	vol_id = ubi32_to_cpu(vid_hdr->vol_id);
+	lnum = ubi32_to_cpu(vid_hdr->lnum);
+
+	dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
+
+	if (vid_hdr->vol_type == UBI_VID_STATIC) {
+		data_size = ubi32_to_cpu(vid_hdr->data_size);
+		aldata_size = ALIGN(data_size, ubi->min_io_size);
+	} else
+		data_size = aldata_size =
+			    ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+
+	buf = kmalloc(aldata_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/*
+	 * We do not want anybody to write to this logical eraseblock while we
+	 * are moving it, so we lock it.
+	 */
+	err = leb_write_lock(ubi, vol_id, lnum);
+	if (err) {
+		kfree(buf);
+		return err;
+	}
+
+	/*
+	 * But the logical eraseblock might have been put by this time.
+	 * Cancel if it is true.
+	 */
+	idx = vol_id2idx(ubi, vol_id);
+
+	/*
+	 * We may race with volume deletion/re-size, so we have to hold
+	 * @ubi->volumes_lock.
+	 */
+	spin_lock(&ubi->volumes_lock);
+	vol = ubi->volumes[idx];
+	if (!vol) {
+		dbg_eba("volume %d was removed meanwhile", vol_id);
+		spin_unlock(&ubi->volumes_lock);
+		goto out_unlock;
+	}
+
+	pnum = vol->eba_tbl[lnum];
+	if (pnum != from) {
+		dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to "
+			"PEB %d, cancel", vol_id, lnum, from, pnum);
+		spin_unlock(&ubi->volumes_lock);
+		goto out_unlock;
+	}
+	spin_unlock(&ubi->volumes_lock);
+
+	/* OK, now the LEB is locked and we can safely start moving it */
+
+	dbg_eba("read %d bytes of data", aldata_size);
+	err = ubi_io_read_data(ubi, buf, from, 0, aldata_size);
+	if (err && err != UBI_IO_BITFLIPS) {
+		ubi_warn("error %d while reading data from PEB %d",
+			 err, from);
+		goto out_unlock;
+	}
+
+	/*
+	 * Now we have got to calculate how much data we have to to copy. In
+	 * case of a static volume it is fairly easy - the VID header contains
+	 * the data size. In case of a dynamic volume it is more difficult - we
+	 * have to read the contents, cut 0xFF bytes from the end and copy only
+	 * the first part. We must do this to avoid writing 0xFF bytes as it
+	 * may have some side-effects. And not only this. It is important not
+	 * to include those 0xFFs to CRC because later the they may be filled
+	 * by data.
+	 */
+	if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
+		aldata_size = data_size =
+				ubi_calc_data_len(ubi, buf, data_size);
+
+	cond_resched();
+	crc = crc32(UBI_CRC32_INIT, buf, data_size);
+	cond_resched();
+
+	/*
+	 * It may turn out to me that the whole @from physical eraseblock
+	 * contains only 0xFF bytes. Then we have to only write the VID header
+	 * and do not write any data. This also means we should not set
+	 * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc.
+	 */
+	if (data_size > 0) {
+		vid_hdr->copy_flag = 1;
+		vid_hdr->data_size = cpu_to_ubi32(data_size);
+		vid_hdr->data_crc = cpu_to_ubi32(crc);
+	}
+	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+
+	err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
+	if (err)
+		goto out_unlock;
+
+	cond_resched();
+
+	/* Read the VID header back and check if it was written correctly */
+	err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
+	if (err) {
+		if (err != UBI_IO_BITFLIPS)
+			ubi_warn("cannot read VID header back from PEB %d", to);
+		goto out_unlock;
+	}
+
+	if (data_size > 0) {
+		err = ubi_io_write_data(ubi, buf, to, 0, aldata_size);
+		if (err)
+			goto out_unlock;
+
+		/*
+		 * We've written the data and are going to read it back to make
+		 * sure it was written correctly.
+		 */
+		buf1 = kmalloc(aldata_size, GFP_KERNEL);
+		if (!buf1) {
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+
+		cond_resched();
+
+		err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size);
+		if (err) {
+			if (err != UBI_IO_BITFLIPS)
+				ubi_warn("cannot read data back from PEB %d",
+					 to);
+			goto out_unlock;
+		}
+
+		cond_resched();
+
+		if (memcmp(buf, buf1, aldata_size)) {
+			ubi_warn("read data back from PEB %d - it is different",
+				 to);
+			goto out_unlock;
+		}
+	}
+
+	ubi_assert(vol->eba_tbl[lnum] == from);
+	vol->eba_tbl[lnum] = to;
+
+	leb_write_unlock(ubi, vol_id, lnum);
+	kfree(buf);
+	kfree(buf1);
+
+	return 0;
+
+out_unlock:
+	leb_write_unlock(ubi, vol_id, lnum);
+	kfree(buf);
+	kfree(buf1);
+	return err;
+}
+
+/**
+ * ubi_eba_init_scan - initialize the EBA unit using scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+	int i, j, err, num_volumes;
+	struct ubi_scan_volume *sv;
+	struct ubi_volume *vol;
+	struct ubi_scan_leb *seb;
+	struct rb_node *rb;
+
+	dbg_eba("initialize EBA unit");
+
+	spin_lock_init(&ubi->ltree_lock);
+	ubi->ltree = RB_ROOT;
+
+	if (ubi_devices_cnt == 0) {
+		ltree_slab = kmem_cache_create("ubi_ltree_slab",
+					       sizeof(struct ltree_entry), 0,
+					       0, &ltree_entry_ctor, NULL);
+		if (!ltree_slab)
+			return -ENOMEM;
+	}
+
+	ubi->global_sqnum = si->max_sqnum + 1;
+	num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
+
+	for (i = 0; i < num_volumes; i++) {
+		vol = ubi->volumes[i];
+		if (!vol)
+			continue;
+
+		cond_resched();
+
+		vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int),
+				       GFP_KERNEL);
+		if (!vol->eba_tbl) {
+			err = -ENOMEM;
+			goto out_free;
+		}
+
+		for (j = 0; j < vol->reserved_pebs; j++)
+			vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
+
+		sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i));
+		if (!sv)
+			continue;
+
+		ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
+			if (seb->lnum >= vol->reserved_pebs)
+				/*
+				 * This may happen in case of an unclean reboot
+				 * during re-size.
+				 */
+				ubi_scan_move_to_list(sv, seb, &si->erase);
+			vol->eba_tbl[seb->lnum] = seb->pnum;
+		}
+	}
+
+	if (ubi->bad_allowed) {
+		ubi_calculate_reserved(ubi);
+
+		if (ubi->avail_pebs < ubi->beb_rsvd_level) {
+			/* No enough free physical eraseblocks */
+			ubi->beb_rsvd_pebs = ubi->avail_pebs;
+			ubi_warn("cannot reserve enough PEBs for bad PEB "
+				 "handling, reserved %d, need %d",
+				 ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
+		} else
+			ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
+
+		ubi->avail_pebs -= ubi->beb_rsvd_pebs;
+		ubi->rsvd_pebs  += ubi->beb_rsvd_pebs;
+	}
+
+	dbg_eba("EBA unit is initialized");
+	return 0;
+
+out_free:
+	for (i = 0; i < num_volumes; i++) {
+		if (!ubi->volumes[i])
+			continue;
+		kfree(ubi->volumes[i]->eba_tbl);
+	}
+	if (ubi_devices_cnt == 0)
+		kmem_cache_destroy(ltree_slab);
+	return err;
+}
+
+/**
+ * ubi_eba_close - close EBA unit.
+ * @ubi: UBI device description object
+ */
+void ubi_eba_close(const struct ubi_device *ubi)
+{
+	int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
+
+	dbg_eba("close EBA unit");
+
+	for (i = 0; i < num_volumes; i++) {
+		if (!ubi->volumes[i])
+			continue;
+		kfree(ubi->volumes[i]->eba_tbl);
+	}
+	if (ubi_devices_cnt == 1)
+		kmem_cache_destroy(ltree_slab);
+}
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
new file mode 100644
index 0000000..fc9478d
--- /dev/null
+++ b/drivers/mtd/ubi/gluebi.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼), Joern Engel
+ */
+
+/*
+ * This file includes implementation of fake MTD devices for each UBI volume.
+ * This sounds strange, but it is in fact quite useful to make MTD-oriented
+ * software (including all the legacy software) to work on top of UBI.
+ *
+ * Gluebi emulates MTD devices of "MTD_UBIVOLUME" type. Their minimal I/O unit
+ * size (mtd->writesize) is equivalent to the UBI minimal I/O unit. The
+ * eraseblock size is equivalent to the logical eraseblock size of the volume.
+ */
+
+#include <asm/div64.h>
+#include "ubi.h"
+
+/**
+ * gluebi_get_device - get MTD device reference.
+ * @mtd: the MTD device description object
+ *
+ * This function is called every time the MTD device is being opened and
+ * implements the MTD get_device() operation. Returns zero in case of success
+ * and a negative error code in case of failure.
+ */
+static int gluebi_get_device(struct mtd_info *mtd)
+{
+	struct ubi_volume *vol;
+
+	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+
+	/*
+	 * We do not introduce locks for gluebi reference count because the
+	 * get_device()/put_device() calls are already serialized at MTD.
+	 */
+	if (vol->gluebi_refcount > 0) {
+		/*
+		 * The MTD device is already referenced and this is just one
+		 * more reference. MTD allows many users to open the same
+		 * volume simultaneously and do not distinguish between
+		 * readers/writers/exclusive openers as UBI does. So we do not
+		 * open the UBI volume again - just increase the reference
+		 * counter and return.
+		 */
+		vol->gluebi_refcount += 1;
+		return 0;
+	}
+
+	/*
+	 * This is the first reference to this UBI volume via the MTD device
+	 * interface. Open the corresponding volume in read-write mode.
+	 */
+	vol->gluebi_desc = ubi_open_volume(vol->ubi->ubi_num, vol->vol_id,
+					   UBI_READWRITE);
+	if (IS_ERR(vol->gluebi_desc))
+		return PTR_ERR(vol->gluebi_desc);
+	vol->gluebi_refcount += 1;
+	return 0;
+}
+
+/**
+ * gluebi_put_device - put MTD device reference.
+ * @mtd: the MTD device description object
+ *
+ * This function is called every time the MTD device is being put. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static void gluebi_put_device(struct mtd_info *mtd)
+{
+	struct ubi_volume *vol;
+
+	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	vol->gluebi_refcount -= 1;
+	ubi_assert(vol->gluebi_refcount >= 0);
+	if (vol->gluebi_refcount == 0)
+		ubi_close_volume(vol->gluebi_desc);
+}
+
+/**
+ * gluebi_read - read operation of emulated MTD devices.
+ * @mtd: MTD device description object
+ * @from: absolute offset from where to read
+ * @len: how many bytes to read
+ * @retlen: count of read bytes is returned here
+ * @buf: buffer to store the read data
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
+		       size_t *retlen, unsigned char *buf)
+{
+	int err = 0, lnum, offs, total_read;
+	struct ubi_volume *vol;
+	struct ubi_device *ubi;
+	uint64_t tmp = from;
+
+	dbg_msg("read %zd bytes from offset %lld", len, from);
+
+	if (len < 0 || from < 0 || from + len > mtd->size)
+		return -EINVAL;
+
+	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	ubi = vol->ubi;
+
+	offs = do_div(tmp, mtd->erasesize);
+	lnum = tmp;
+
+	total_read = len;
+	while (total_read) {
+		size_t to_read = mtd->erasesize - offs;
+
+		if (to_read > total_read)
+			to_read = total_read;
+
+		err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs,
+				       to_read, 0);
+		if (err)
+			break;
+
+		lnum += 1;
+		offs = 0;
+		total_read -= to_read;
+		buf += to_read;
+	}
+
+	*retlen = len - total_read;
+	return err;
+}
+
+/**
+ * gluebi_write - write operation of emulated MTD devices.
+ * @mtd: MTD device description object
+ * @to: absolute offset where to write
+ * @len: how many bytes to write
+ * @retlen: count of written bytes is returned here
+ * @buf: buffer with data to write
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
+		       size_t *retlen, const u_char *buf)
+{
+	int err = 0, lnum, offs, total_written;
+	struct ubi_volume *vol;
+	struct ubi_device *ubi;
+	uint64_t tmp = to;
+
+	dbg_msg("write %zd bytes to offset %lld", len, to);
+
+	if (len < 0 || to < 0 || len + to > mtd->size)
+		return -EINVAL;
+
+	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	ubi = vol->ubi;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	offs = do_div(tmp, mtd->erasesize);
+	lnum = tmp;
+
+	if (len % mtd->writesize || offs % mtd->writesize)
+		return -EINVAL;
+
+	total_written = len;
+	while (total_written) {
+		size_t to_write = mtd->erasesize - offs;
+
+		if (to_write > total_written)
+			to_write = total_written;
+
+		err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs,
+					to_write, UBI_UNKNOWN);
+		if (err)
+			break;
+
+		lnum += 1;
+		offs = 0;
+		total_written -= to_write;
+		buf += to_write;
+	}
+
+	*retlen = len - total_written;
+	return err;
+}
+
+/**
+ * gluebi_erase - erase operation of emulated MTD devices.
+ * @mtd: the MTD device description object
+ * @instr: the erase operation description
+ *
+ * This function calls the erase callback when finishes. Returns zero in case
+ * of success and a negative error code in case of failure.
+ */
+static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	int err, i, lnum, count;
+	struct ubi_volume *vol;
+	struct ubi_device *ubi;
+
+	dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr);
+
+	if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
+		return -EINVAL;
+
+	if (instr->len < 0 || instr->addr + instr->len > mtd->size)
+		return -EINVAL;
+
+	if (instr->addr % mtd->writesize || instr->len % mtd->writesize)
+		return -EINVAL;
+
+	lnum = instr->addr / mtd->erasesize;
+	count = instr->len / mtd->erasesize;
+
+	vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
+	ubi = vol->ubi;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	for (i = 0; i < count; i++) {
+		err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i);
+		if (err)
+			goto out_err;
+	}
+
+	/*
+	 * MTD erase operations are synchronous, so we have to make sure the
+	 * physical eraseblock is wiped out.
+	 */
+	err = ubi_wl_flush(ubi);
+	if (err)
+		goto out_err;
+
+        instr->state = MTD_ERASE_DONE;
+        mtd_erase_callback(instr);
+	return 0;
+
+out_err:
+	instr->state = MTD_ERASE_FAILED;
+	instr->fail_addr = lnum * mtd->erasesize;
+	return err;
+}
+
+/**
+ * ubi_create_gluebi - initialize gluebi for an UBI volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function is called when an UBI volume is created in order to create
+ * corresponding fake MTD device. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+	struct mtd_info *mtd = &vol->gluebi_mtd;
+
+	mtd->name = kmemdup(vol->name, vol->name_len + 1, GFP_KERNEL);
+	if (!mtd->name)
+		return -ENOMEM;
+
+	mtd->type = MTD_UBIVOLUME;
+	if (!ubi->ro_mode)
+		mtd->flags = MTD_WRITEABLE;
+	mtd->writesize  = ubi->min_io_size;
+	mtd->owner      = THIS_MODULE;
+	mtd->size       = vol->usable_leb_size * vol->reserved_pebs;
+	mtd->erasesize  = vol->usable_leb_size;
+	mtd->read       = gluebi_read;
+	mtd->write      = gluebi_write;
+	mtd->erase      = gluebi_erase;
+	mtd->get_device = gluebi_get_device;
+	mtd->put_device = gluebi_put_device;
+
+	if (add_mtd_device(mtd)) {
+		ubi_err("cannot not add MTD device\n");
+		kfree(mtd->name);
+		return -ENFILE;
+	}
+
+	dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u",
+		mtd->index, mtd->name, mtd->size, mtd->erasesize);
+	return 0;
+}
+
+/**
+ * ubi_destroy_gluebi - close gluebi for an UBI volume.
+ * @vol: volume description object
+ *
+ * This function is called when an UBI volume is removed in order to remove
+ * corresponding fake MTD device. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+int ubi_destroy_gluebi(struct ubi_volume *vol)
+{
+	int err;
+	struct mtd_info *mtd = &vol->gluebi_mtd;
+
+	dbg_msg("remove mtd%d", mtd->index);
+	err = del_mtd_device(mtd);
+	if (err)
+		return err;
+	kfree(mtd->name);
+	return 0;
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
new file mode 100644
index 0000000..438914d
--- /dev/null
+++ b/drivers/mtd/ubi/io.c
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * UBI input/output unit.
+ *
+ * This unit provides a uniform way to work with all kinds of the underlying
+ * MTD devices. It also implements handy functions for reading and writing UBI
+ * headers.
+ *
+ * We are trying to have a paranoid mindset and not to trust to what we read
+ * from the flash media in order to be more secure and robust. So this unit
+ * validates every single header it reads from the flash media.
+ *
+ * Some words about how the eraseblock headers are stored.
+ *
+ * The erase counter header is always stored at offset zero. By default, the
+ * VID header is stored after the EC header at the closest aligned offset
+ * (i.e. aligned to the minimum I/O unit size). Data starts next to the VID
+ * header at the closest aligned offset. But this default layout may be
+ * changed. For example, for different reasons (e.g., optimization) UBI may be
+ * asked to put the VID header at further offset, and even at an unaligned
+ * offset. Of course, if the offset of the VID header is unaligned, UBI adds
+ * proper padding in front of it. Data offset may also be changed but it has to
+ * be aligned.
+ *
+ * About minimal I/O units. In general, UBI assumes flash device model where
+ * there is only one minimal I/O unit size. E.g., in case of NOR flash it is 1,
+ * in case of NAND flash it is a NAND page, etc. This is reported by MTD in the
+ * @ubi->mtd->writesize field. But as an exception, UBI admits of using another
+ * (smaller) minimal I/O unit size for EC and VID headers to make it possible
+ * to do different optimizations.
+ *
+ * This is extremely useful in case of NAND flashes which admit of several
+ * write operations to one NAND page. In this case UBI can fit EC and VID
+ * headers at one NAND page. Thus, UBI may use "sub-page" size as the minimal
+ * I/O unit for the headers (the @ubi->hdrs_min_io_size field). But it still
+ * reports NAND page size (@ubi->min_io_size) as a minimal I/O unit for the UBI
+ * users.
+ *
+ * Example: some Samsung NANDs with 2KiB pages allow 4x 512-byte writes, so
+ * although the minimal I/O unit is 2K, UBI uses 512 bytes for EC and VID
+ * headers.
+ *
+ * Q: why not just to treat sub-page as a minimal I/O unit of this flash
+ * device, e.g., make @ubi->min_io_size = 512 in the example above?
+ *
+ * A: because when writing a sub-page, MTD still writes a full 2K page but the
+ * bytes which are no relevant to the sub-page are 0xFF. So, basically, writing
+ * 4x512 sub-pages is 4 times slower then writing one 2KiB NAND page. Thus, we
+ * prefer to use sub-pages only for EV and VID headers.
+ *
+ * As it was noted above, the VID header may start at a non-aligned offset.
+ * For example, in case of a 2KiB page NAND flash with a 512 bytes sub-page,
+ * the VID header may reside at offset 1984 which is the last 64 bytes of the
+ * last sub-page (EC header is always at offset zero). This causes some
+ * difficulties when reading and writing VID headers.
+ *
+ * Suppose we have a 64-byte buffer and we read a VID header at it. We change
+ * the data and want to write this VID header out. As we can only write in
+ * 512-byte chunks, we have to allocate one more buffer and copy our VID header
+ * to offset 448 of this buffer.
+ *
+ * The I/O unit does the following trick in order to avoid this extra copy.
+ * It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header
+ * and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the
+ * VID header is being written out, it shifts the VID header pointer back and
+ * writes the whole sub-page.
+ */
+
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+				 const struct ubi_ec_hdr *ec_hdr);
+static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
+static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+				  const struct ubi_vid_hdr *vid_hdr);
+static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
+				 int offset, int len);
+#else
+#define paranoid_check_not_bad(ubi, pnum) 0
+#define paranoid_check_peb_ec_hdr(ubi, pnum)  0
+#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr)  0
+#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
+#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
+#define paranoid_check_all_ff(ubi, pnum, offset, len) 0
+#endif
+
+/**
+ * ubi_io_read - read data from a physical eraseblock.
+ * @ubi: UBI device description object
+ * @buf: buffer where to store the read data
+ * @pnum: physical eraseblock number to read from
+ * @offset: offset within the physical eraseblock from where to read
+ * @len: how many bytes to read
+ *
+ * This function reads data from offset @offset of physical eraseblock @pnum
+ * and stores the read data in the @buf buffer. The following return codes are
+ * possible:
+ *
+ * o %0 if all the requested data were successfully read;
+ * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
+ *   correctable bit-flips were detected; this is harmless but may indicate
+ *   that this eraseblock may become bad soon (but do not have to);
+ * o %-EBADMSG if the MTD subsystem reported about data data integrity
+ *   problems, for example it can me an ECC error in case of NAND; this most
+ *   probably means that the data is corrupted;
+ * o %-EIO if some I/O error occurred;
+ * o other negative error codes in case of other errors.
+ */
+int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
+		int len)
+{
+	int err, retries = 0;
+	size_t read;
+	loff_t addr;
+
+	dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset);
+
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+	ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
+	ubi_assert(len > 0);
+
+	err = paranoid_check_not_bad(ubi, pnum);
+	if (err)
+		return err > 0 ? -EINVAL : err;
+
+	addr = (loff_t)pnum * ubi->peb_size + offset;
+retry:
+	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+	if (err) {
+		if (err == -EUCLEAN) {
+			/*
+			 * -EUCLEAN is reported if there was a bit-flip which
+			 * was corrected, so this is harmless.
+			 */
+			ubi_msg("fixable bit-flip detected at PEB %d", pnum);
+			ubi_assert(len == read);
+			return UBI_IO_BITFLIPS;
+		}
+
+		if (read != len && retries++ < UBI_IO_RETRIES) {
+			dbg_io("error %d while reading %d bytes from PEB %d:%d, "
+			       "read only %zd bytes, retry",
+			       err, len, pnum, offset, read);
+			yield();
+			goto retry;
+		}
+
+		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+			"read %zd bytes", err, len, pnum, offset, read);
+		ubi_dbg_dump_stack();
+	} else {
+		ubi_assert(len == read);
+
+		if (ubi_dbg_is_bitflip()) {
+			dbg_msg("bit-flip (emulated)");
+			err = UBI_IO_BITFLIPS;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * ubi_io_write - write data to a physical eraseblock.
+ * @ubi: UBI device description object
+ * @buf: buffer with the data to write
+ * @pnum: physical eraseblock number to write to
+ * @offset: offset within the physical eraseblock where to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data from buffer @buf to offset @offset
+ * of physical eraseblock @pnum. If all the data were successfully written,
+ * zero is returned. If an error occurred, this function returns a negative
+ * error code. If %-EIO is returned, the physical eraseblock most probably went
+ * bad.
+ *
+ * Note, in case of an error, it is possible that something was still written
+ * to the flash media, but may be some garbage.
+ */
+int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
+		 int offset, int len)
+{
+	int err;
+	size_t written;
+	loff_t addr;
+
+	dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset);
+
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+	ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
+	ubi_assert(offset % ubi->hdrs_min_io_size == 0);
+	ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0);
+
+	if (ubi->ro_mode) {
+		ubi_err("read-only mode");
+		return -EROFS;
+	}
+
+	/* The below has to be compiled out if paranoid checks are disabled */
+
+	err = paranoid_check_not_bad(ubi, pnum);
+	if (err)
+		return err > 0 ? -EINVAL : err;
+
+	/* The area we are writing to has to contain all 0xFF bytes */
+	err = paranoid_check_all_ff(ubi, pnum, offset, len);
+	if (err)
+		return err > 0 ? -EINVAL : err;
+
+	if (offset >= ubi->leb_start) {
+		/*
+		 * We write to the data area of the physical eraseblock. Make
+		 * sure it has valid EC and VID headers.
+		 */
+		err = paranoid_check_peb_ec_hdr(ubi, pnum);
+		if (err)
+			return err > 0 ? -EINVAL : err;
+		err = paranoid_check_peb_vid_hdr(ubi, pnum);
+		if (err)
+			return err > 0 ? -EINVAL : err;
+	}
+
+	if (ubi_dbg_is_write_failure()) {
+		dbg_err("cannot write %d bytes to PEB %d:%d "
+			"(emulated)", len, pnum, offset);
+		ubi_dbg_dump_stack();
+		return -EIO;
+	}
+
+	addr = (loff_t)pnum * ubi->peb_size + offset;
+	err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
+	if (err) {
+		ubi_err("error %d while writing %d bytes to PEB %d:%d, written"
+			" %zd bytes", err, len, pnum, offset, written);
+		ubi_dbg_dump_stack();
+	} else
+		ubi_assert(written == len);
+
+	return err;
+}
+
+/**
+ * erase_callback - MTD erasure call-back.
+ * @ei: MTD erase information object.
+ *
+ * Note, even though MTD erase interface is asynchronous, all the current
+ * implementations are synchronous anyway.
+ */
+static void erase_callback(struct erase_info *ei)
+{
+	wake_up_interruptible((wait_queue_head_t *)ei->priv);
+}
+
+/**
+ * do_sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to erase
+ *
+ * This function synchronously erases physical eraseblock @pnum and returns
+ * zero in case of success and a negative error code in case of failure. If
+ * %-EIO is returned, the physical eraseblock most probably went bad.
+ */
+static int do_sync_erase(const struct ubi_device *ubi, int pnum)
+{
+	int err, retries = 0;
+	struct erase_info ei;
+	wait_queue_head_t wq;
+
+	dbg_io("erase PEB %d", pnum);
+
+retry:
+	init_waitqueue_head(&wq);
+	memset(&ei, 0, sizeof(struct erase_info));
+
+	ei.mtd      = ubi->mtd;
+	ei.addr     = pnum * ubi->peb_size;
+	ei.len      = ubi->peb_size;
+	ei.callback = erase_callback;
+	ei.priv     = (unsigned long)&wq;
+
+	err = ubi->mtd->erase(ubi->mtd, &ei);
+	if (err) {
+		if (retries++ < UBI_IO_RETRIES) {
+			dbg_io("error %d while erasing PEB %d, retry",
+			       err, pnum);
+			yield();
+			goto retry;
+		}
+		ubi_err("cannot erase PEB %d, error %d", pnum, err);
+		ubi_dbg_dump_stack();
+		return err;
+	}
+
+	err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE ||
+					   ei.state == MTD_ERASE_FAILED);
+	if (err) {
+		ubi_err("interrupted PEB %d erasure", pnum);
+		return -EINTR;
+	}
+
+	if (ei.state == MTD_ERASE_FAILED) {
+		if (retries++ < UBI_IO_RETRIES) {
+			dbg_io("error while erasing PEB %d, retry", pnum);
+			yield();
+			goto retry;
+		}
+		ubi_err("cannot erase PEB %d", pnum);
+		ubi_dbg_dump_stack();
+		return -EIO;
+	}
+
+	err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+	if (err)
+		return err > 0 ? -EINVAL : err;
+
+	if (ubi_dbg_is_erase_failure() && !err) {
+		dbg_err("cannot erase PEB %d (emulated)", pnum);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+static int check_pattern(const void *buf, uint8_t patt, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		if (((const uint8_t *)buf)[i] != patt)
+			return 0;
+	return 1;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * torture_peb - test a supposedly bad physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to test
+ *
+ * This function returns %-EIO if the physical eraseblock did not pass the
+ * test, a positive number of erase operations done if the test was
+ * successfully passed, and other negative error codes in case of other errors.
+ */
+static int torture_peb(const struct ubi_device *ubi, int pnum)
+{
+	void *buf;
+	int err, i, patt_count;
+
+	buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	patt_count = ARRAY_SIZE(patterns);
+	ubi_assert(patt_count > 0);
+
+	for (i = 0; i < patt_count; i++) {
+		err = do_sync_erase(ubi, pnum);
+		if (err)
+			goto out;
+
+		/* Make sure the PEB contains only 0xFF bytes */
+		err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+		if (err)
+			goto out;
+
+		err = check_pattern(buf, 0xFF, ubi->peb_size);
+		if (err == 0) {
+			ubi_err("erased PEB %d, but a non-0xFF byte found",
+				pnum);
+			err = -EIO;
+			goto out;
+		}
+
+		/* Write a pattern and check it */
+		memset(buf, patterns[i], ubi->peb_size);
+		err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size);
+		if (err)
+			goto out;
+
+		memset(buf, ~patterns[i], ubi->peb_size);
+		err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+		if (err)
+			goto out;
+
+		err = check_pattern(buf, patterns[i], ubi->peb_size);
+		if (err == 0) {
+			ubi_err("pattern %x checking failed for PEB %d",
+				patterns[i], pnum);
+			err = -EIO;
+			goto out;
+		}
+	}
+
+	err = patt_count;
+
+out:
+	if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+		/*
+		 * If a bit-flip or data integrity error was detected, the test
+		 * has not passed because it happened on a freshly erased
+		 * physical eraseblock which means something is wrong with it.
+		 */
+		err = -EIO;
+	kfree(buf);
+	return err;
+}
+
+/**
+ * ubi_io_sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to erase
+ * @torture: if this physical eraseblock has to be tortured
+ *
+ * This function synchronously erases physical eraseblock @pnum. If @torture
+ * flag is not zero, the physical eraseblock is checked by means of writing
+ * different patterns to it and reading them back. If the torturing is enabled,
+ * the physical eraseblock is erased more then once.
+ *
+ * This function returns the number of erasures made in case of success, %-EIO
+ * if the erasure failed or the torturing test failed, and other negative error
+ * codes in case of other errors. Note, %-EIO means that the physical
+ * eraseblock is bad.
+ */
+int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture)
+{
+	int err, ret = 0;
+
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+	err = paranoid_check_not_bad(ubi, pnum);
+	if (err != 0)
+		return err > 0 ? -EINVAL : err;
+
+	if (ubi->ro_mode) {
+		ubi_err("read-only mode");
+		return -EROFS;
+	}
+
+	if (torture) {
+		ret = torture_peb(ubi, pnum);
+		if (ret < 0)
+			return ret;
+	}
+
+	err = do_sync_erase(ubi, pnum);
+	if (err)
+		return err;
+
+	return ret + 1;
+}
+
+/**
+ * ubi_io_is_bad - check if a physical eraseblock is bad.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns a positive number if the physical eraseblock is bad,
+ * zero if not, and a negative error code if an error occurred.
+ */
+int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
+{
+	struct mtd_info *mtd = ubi->mtd;
+
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+	if (ubi->bad_allowed) {
+		int ret;
+
+		ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
+		if (ret < 0)
+			ubi_err("error %d while checking if PEB %d is bad",
+				ret, pnum);
+		else if (ret)
+			dbg_io("PEB %d is bad", pnum);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ubi_io_mark_bad - mark a physical eraseblock as bad.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to mark
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
+{
+	int err;
+	struct mtd_info *mtd = ubi->mtd;
+
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+	if (ubi->ro_mode) {
+		ubi_err("read-only mode");
+		return -EROFS;
+	}
+
+	if (!ubi->bad_allowed)
+		return 0;
+
+	err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
+	if (err)
+		ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
+	return err;
+}
+
+/**
+ * validate_ec_hdr - validate an erase counter header.
+ * @ubi: UBI device description object
+ * @ec_hdr: the erase counter header to check
+ *
+ * This function returns zero if the erase counter header is OK, and %1 if
+ * not.
+ */
+static int validate_ec_hdr(const struct ubi_device *ubi,
+			   const struct ubi_ec_hdr *ec_hdr)
+{
+	long long ec;
+	int vid_hdr_offset, leb_start;
+
+	ec = ubi64_to_cpu(ec_hdr->ec);
+	vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
+	leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+
+	if (ec_hdr->version != UBI_VERSION) {
+		ubi_err("node with incompatible UBI version found: "
+			"this UBI version is %d, image version is %d",
+			UBI_VERSION, (int)ec_hdr->version);
+		goto bad;
+	}
+
+	if (vid_hdr_offset != ubi->vid_hdr_offset) {
+		ubi_err("bad VID header offset %d, expected %d",
+			vid_hdr_offset, ubi->vid_hdr_offset);
+		goto bad;
+	}
+
+	if (leb_start != ubi->leb_start) {
+		ubi_err("bad data offset %d, expected %d",
+			leb_start, ubi->leb_start);
+		goto bad;
+	}
+
+	if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) {
+		ubi_err("bad erase counter %lld", ec);
+		goto bad;
+	}
+
+	return 0;
+
+bad:
+	ubi_err("bad EC header");
+	ubi_dbg_dump_ec_hdr(ec_hdr);
+	ubi_dbg_dump_stack();
+	return 1;
+}
+
+/**
+ * ubi_io_read_ec_hdr - read and check an erase counter header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to read from
+ * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
+ * header
+ * @verbose: be verbose if the header is corrupted or was not found
+ *
+ * This function reads erase counter header from physical eraseblock @pnum and
+ * stores it in @ec_hdr. This function also checks CRC checksum of the read
+ * erase counter header. The following codes may be returned:
+ *
+ * o %0 if the CRC checksum is correct and the header was successfully read;
+ * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
+ *   and corrected by the flash driver; this is harmless but may indicate that
+ *   this eraseblock may become bad soon (but may be not);
+ * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error);
+ * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
+ * o a negative error code in case of failure.
+ */
+int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+		       struct ubi_ec_hdr *ec_hdr, int verbose)
+{
+	int err, read_err = 0;
+	uint32_t crc, magic, hdr_crc;
+
+	dbg_io("read EC header from PEB %d", pnum);
+	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
+
+	err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+	if (err) {
+		if (err != UBI_IO_BITFLIPS && err != -EBADMSG)
+			return err;
+
+		/*
+		 * We read all the data, but either a correctable bit-flip
+		 * occurred, or MTD reported about some data integrity error,
+		 * like an ECC error in case of NAND. The former is harmless,
+		 * the later may mean that the read data is corrupted. But we
+		 * have a CRC check-sum and we will detect this. If the EC
+		 * header is still OK, we just report this as there was a
+		 * bit-flip.
+		 */
+		read_err = err;
+	}
+
+	magic = ubi32_to_cpu(ec_hdr->magic);
+	if (magic != UBI_EC_HDR_MAGIC) {
+		/*
+		 * The magic field is wrong. Let's check if we have read all
+		 * 0xFF. If yes, this physical eraseblock is assumed to be
+		 * empty.
+		 *
+		 * But if there was a read error, we do not test it for all
+		 * 0xFFs. Even if it does contain all 0xFFs, this error
+		 * indicates that something is still wrong with this physical
+		 * eraseblock and we anyway cannot treat it as empty.
+		 */
+		if (read_err != -EBADMSG &&
+		    check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+			/* The physical eraseblock is supposedly empty */
+
+			/*
+			 * The below is just a paranoid check, it has to be
+			 * compiled out if paranoid checks are disabled.
+			 */
+			err = paranoid_check_all_ff(ubi, pnum, 0,
+						    ubi->peb_size);
+			if (err)
+				return err > 0 ? UBI_IO_BAD_EC_HDR : err;
+
+			if (verbose)
+				ubi_warn("no EC header found at PEB %d, "
+					 "only 0xFF bytes", pnum);
+			return UBI_IO_PEB_EMPTY;
+		}
+
+		/*
+		 * This is not a valid erase counter header, and these are not
+		 * 0xFF bytes. Report that the header is corrupted.
+		 */
+		if (verbose) {
+			ubi_warn("bad magic number at PEB %d: %08x instead of "
+				 "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+			ubi_dbg_dump_ec_hdr(ec_hdr);
+		}
+		return UBI_IO_BAD_EC_HDR;
+	}
+
+	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+	hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+
+	if (hdr_crc != crc) {
+		if (verbose) {
+			ubi_warn("bad EC header CRC at PEB %d, calculated %#08x,"
+				 " read %#08x", pnum, crc, hdr_crc);
+			ubi_dbg_dump_ec_hdr(ec_hdr);
+		}
+		return UBI_IO_BAD_EC_HDR;
+	}
+
+	/* And of course validate what has just been read from the media */
+	err = validate_ec_hdr(ubi, ec_hdr);
+	if (err) {
+		ubi_err("validation failed for PEB %d", pnum);
+		return -EINVAL;
+	}
+
+	return read_err ? UBI_IO_BITFLIPS : 0;
+}
+
+/**
+ * ubi_io_write_ec_hdr - write an erase counter header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to write to
+ * @ec_hdr: the erase counter header to write
+ *
+ * This function writes erase counter header described by @ec_hdr to physical
+ * eraseblock @pnum. It also fills most fields of @ec_hdr before writing, so
+ * the caller do not have to fill them. Callers must only fill the @ec_hdr->ec
+ * field.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If %-EIO is returned, the physical eraseblock most probably
+ * went bad.
+ */
+int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+			struct ubi_ec_hdr *ec_hdr)
+{
+	int err;
+	uint32_t crc;
+
+	dbg_io("write EC header to PEB %d", pnum);
+	ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
+
+	ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+	ec_hdr->version = UBI_VERSION;
+	ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
+	ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+	ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+
+	err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+	if (err)
+		return -EINVAL;
+
+	err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
+	return err;
+}
+
+/**
+ * validate_vid_hdr - validate a volume identifier header.
+ * @ubi: UBI device description object
+ * @vid_hdr: the volume identifier header to check
+ *
+ * This function checks that data stored in the volume identifier header
+ * @vid_hdr. Returns zero if the VID header is OK and %1 if not.
+ */
+static int validate_vid_hdr(const struct ubi_device *ubi,
+			    const struct ubi_vid_hdr *vid_hdr)
+{
+	int vol_type = vid_hdr->vol_type;
+	int copy_flag = vid_hdr->copy_flag;
+	int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
+	int lnum = ubi32_to_cpu(vid_hdr->lnum);
+	int compat = vid_hdr->compat;
+	int data_size = ubi32_to_cpu(vid_hdr->data_size);
+	int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
+	int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+	int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+	int usable_leb_size = ubi->leb_size - data_pad;
+
+	if (copy_flag != 0 && copy_flag != 1) {
+		dbg_err("bad copy_flag");
+		goto bad;
+	}
+
+	if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
+	    data_pad < 0) {
+		dbg_err("negative values");
+		goto bad;
+	}
+
+	if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
+		dbg_err("bad vol_id");
+		goto bad;
+	}
+
+	if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
+		dbg_err("bad compat");
+		goto bad;
+	}
+
+	if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
+	    compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
+	    compat != UBI_COMPAT_REJECT) {
+		dbg_err("bad compat");
+		goto bad;
+	}
+
+	if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+		dbg_err("bad vol_type");
+		goto bad;
+	}
+
+	if (data_pad >= ubi->leb_size / 2) {
+		dbg_err("bad data_pad");
+		goto bad;
+	}
+
+	if (vol_type == UBI_VID_STATIC) {
+		/*
+		 * Although from high-level point of view static volumes may
+		 * contain zero bytes of data, but no VID headers can contain
+		 * zero at these fields, because they empty volumes do not have
+		 * mapped logical eraseblocks.
+		 */
+		if (used_ebs == 0) {
+			dbg_err("zero used_ebs");
+			goto bad;
+		}
+		if (data_size == 0) {
+			dbg_err("zero data_size");
+			goto bad;
+		}
+		if (lnum < used_ebs - 1) {
+			if (data_size != usable_leb_size) {
+				dbg_err("bad data_size");
+				goto bad;
+			}
+		} else if (lnum == used_ebs - 1) {
+			if (data_size == 0) {
+				dbg_err("bad data_size at last LEB");
+				goto bad;
+			}
+		} else {
+			dbg_err("too high lnum");
+			goto bad;
+		}
+	} else {
+		if (copy_flag == 0) {
+			if (data_crc != 0) {
+				dbg_err("non-zero data CRC");
+				goto bad;
+			}
+			if (data_size != 0) {
+				dbg_err("non-zero data_size");
+				goto bad;
+			}
+		} else {
+			if (data_size == 0) {
+				dbg_err("zero data_size of copy");
+				goto bad;
+			}
+		}
+		if (used_ebs != 0) {
+			dbg_err("bad used_ebs");
+			goto bad;
+		}
+	}
+
+	return 0;
+
+bad:
+	ubi_err("bad VID header");
+	ubi_dbg_dump_vid_hdr(vid_hdr);
+	ubi_dbg_dump_stack();
+	return 1;
+}
+
+/**
+ * ubi_io_read_vid_hdr - read and check a volume identifier header.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to read from
+ * @vid_hdr: &struct ubi_vid_hdr object where to store the read volume
+ * identifier header
+ * @verbose: be verbose if the header is corrupted or wasn't found
+ *
+ * This function reads the volume identifier header from physical eraseblock
+ * @pnum and stores it in @vid_hdr. It also checks CRC checksum of the read
+ * volume identifier header. The following codes may be returned:
+ *
+ * o %0 if the CRC checksum is correct and the header was successfully read;
+ * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
+ *   and corrected by the flash driver; this is harmless but may indicate that
+ *   this eraseblock may become bad soon;
+ * o %UBI_IO_BAD_VID_HRD if the volume identifier header is corrupted (a CRC
+ *   error detected);
+ * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID
+ *   header there);
+ * o a negative error code in case of failure.
+ */
+int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+			struct ubi_vid_hdr *vid_hdr, int verbose)
+{
+	int err, read_err = 0;
+	uint32_t crc, magic, hdr_crc;
+	void *p;
+
+	dbg_io("read VID header from PEB %d", pnum);
+	ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
+
+	p = (char *)vid_hdr - ubi->vid_hdr_shift;
+	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+			  ubi->vid_hdr_alsize);
+	if (err) {
+		if (err != UBI_IO_BITFLIPS && err != -EBADMSG)
+			return err;
+
+		/*
+		 * We read all the data, but either a correctable bit-flip
+		 * occurred, or MTD reported about some data integrity error,
+		 * like an ECC error in case of NAND. The former is harmless,
+		 * the later may mean the read data is corrupted. But we have a
+		 * CRC check-sum and we will identify this. If the VID header is
+		 * still OK, we just report this as there was a bit-flip.
+		 */
+		read_err = err;
+	}
+
+	magic = ubi32_to_cpu(vid_hdr->magic);
+	if (magic != UBI_VID_HDR_MAGIC) {
+		/*
+		 * If we have read all 0xFF bytes, the VID header probably does
+		 * not exist and the physical eraseblock is assumed to be free.
+		 *
+		 * But if there was a read error, we do not test the data for
+		 * 0xFFs. Even if it does contain all 0xFFs, this error
+		 * indicates that something is still wrong with this physical
+		 * eraseblock and it cannot be regarded as free.
+		 */
+		if (read_err != -EBADMSG &&
+		    check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+			/* The physical eraseblock is supposedly free */
+
+			/*
+			 * The below is just a paranoid check, it has to be
+			 * compiled out if paranoid checks are disabled.
+			 */
+			err = paranoid_check_all_ff(ubi, pnum, ubi->leb_start,
+						    ubi->leb_size);
+			if (err)
+				return err > 0 ? UBI_IO_BAD_VID_HDR : err;
+
+			if (verbose)
+				ubi_warn("no VID header found at PEB %d, "
+					 "only 0xFF bytes", pnum);
+			return UBI_IO_PEB_FREE;
+		}
+
+		/*
+		 * This is not a valid VID header, and these are not 0xFF
+		 * bytes. Report that the header is corrupted.
+		 */
+		if (verbose) {
+			ubi_warn("bad magic number at PEB %d: %08x instead of "
+				 "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+			ubi_dbg_dump_vid_hdr(vid_hdr);
+		}
+		return UBI_IO_BAD_VID_HDR;
+	}
+
+	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
+	hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+
+	if (hdr_crc != crc) {
+		if (verbose) {
+			ubi_warn("bad CRC at PEB %d, calculated %#08x, "
+				 "read %#08x", pnum, crc, hdr_crc);
+			ubi_dbg_dump_vid_hdr(vid_hdr);
+		}
+		return UBI_IO_BAD_VID_HDR;
+	}
+
+	/* Validate the VID header that we have just read */
+	err = validate_vid_hdr(ubi, vid_hdr);
+	if (err) {
+		ubi_err("validation failed for PEB %d", pnum);
+		return -EINVAL;
+	}
+
+	return read_err ? UBI_IO_BITFLIPS : 0;
+}
+
+/**
+ * ubi_io_write_vid_hdr - write a volume identifier header.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to write to
+ * @vid_hdr: the volume identifier header to write
+ *
+ * This function writes the volume identifier header described by @vid_hdr to
+ * physical eraseblock @pnum. This function automatically fills the
+ * @vid_hdr->magic and the @vid_hdr->version fields, as well as calculates
+ * header CRC checksum and stores it at vid_hdr->hdr_crc.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If %-EIO is returned, the physical eraseblock probably went
+ * bad.
+ */
+int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+			 struct ubi_vid_hdr *vid_hdr)
+{
+	int err;
+	uint32_t crc;
+	void *p;
+
+	dbg_io("write VID header to PEB %d", pnum);
+	ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
+
+	err = paranoid_check_peb_ec_hdr(ubi, pnum);
+	if (err)
+		return err > 0 ? -EINVAL: err;
+
+	vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+	vid_hdr->version = UBI_VERSION;
+	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
+	vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+
+	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+	if (err)
+		return -EINVAL;
+
+	p = (char *)vid_hdr - ubi->vid_hdr_shift;
+	err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
+			   ubi->vid_hdr_alsize);
+	return err;
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number to check
+ *
+ * This function returns zero if the physical eraseblock is good, a positive
+ * number if it is bad and a negative error code if an error occurred.
+ */
+static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+{
+	int err;
+
+	err = ubi_io_is_bad(ubi, pnum);
+	if (!err)
+		return err;
+
+	ubi_err("paranoid check failed for PEB %d", pnum);
+	ubi_dbg_dump_stack();
+	return err;
+}
+
+/**
+ * paranoid_check_ec_hdr - check if an erase counter header is all right.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number the erase counter header belongs to
+ * @ec_hdr: the erase counter header to check
+ *
+ * This function returns zero if the erase counter header contains valid
+ * values, and %1 if not.
+ */
+static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+				 const struct ubi_ec_hdr *ec_hdr)
+{
+	int err;
+	uint32_t magic;
+
+	magic = ubi32_to_cpu(ec_hdr->magic);
+	if (magic != UBI_EC_HDR_MAGIC) {
+		ubi_err("bad magic %#08x, must be %#08x",
+			magic, UBI_EC_HDR_MAGIC);
+		goto fail;
+	}
+
+	err = validate_ec_hdr(ubi, ec_hdr);
+	if (err) {
+		ubi_err("paranoid check failed for PEB %d", pnum);
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	ubi_dbg_dump_ec_hdr(ec_hdr);
+	ubi_dbg_dump_stack();
+	return 1;
+}
+
+/**
+ * paranoid_check_peb_ec_hdr - check that the erase counter header of a
+ * physical eraseblock is in-place and is all right.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns zero if the erase counter header is all right, %1 if
+ * not, and a negative error code if an error occurred.
+ */
+static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+{
+	int err;
+	uint32_t crc, hdr_crc;
+	struct ubi_ec_hdr *ec_hdr;
+
+	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ec_hdr)
+		return -ENOMEM;
+
+	err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+		goto exit;
+
+	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+	hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+	if (hdr_crc != crc) {
+		ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
+		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_dbg_dump_ec_hdr(ec_hdr);
+		ubi_dbg_dump_stack();
+		err = 1;
+		goto exit;
+	}
+
+	err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+
+exit:
+	kfree(ec_hdr);
+	return err;
+}
+
+/**
+ * paranoid_check_vid_hdr - check that a volume identifier header is all right.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock number the volume identifier header belongs to
+ * @vid_hdr: the volume identifier header to check
+ *
+ * This function returns zero if the volume identifier header is all right, and
+ * %1 if not.
+ */
+static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+				  const struct ubi_vid_hdr *vid_hdr)
+{
+	int err;
+	uint32_t magic;
+
+	magic = ubi32_to_cpu(vid_hdr->magic);
+	if (magic != UBI_VID_HDR_MAGIC) {
+		ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
+			magic, pnum, UBI_VID_HDR_MAGIC);
+		goto fail;
+	}
+
+	err = validate_vid_hdr(ubi, vid_hdr);
+	if (err) {
+		ubi_err("paranoid check failed for PEB %d", pnum);
+		goto fail;
+	}
+
+	return err;
+
+fail:
+	ubi_err("paranoid check failed for PEB %d", pnum);
+	ubi_dbg_dump_vid_hdr(vid_hdr);
+	ubi_dbg_dump_stack();
+	return 1;
+
+}
+
+/**
+ * paranoid_check_peb_vid_hdr - check that the volume identifier header of a
+ * physical eraseblock is in-place and is all right.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ *
+ * This function returns zero if the volume identifier header is all right,
+ * %1 if not, and a negative error code if an error occurred.
+ */
+static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+{
+	int err;
+	uint32_t crc, hdr_crc;
+	struct ubi_vid_hdr *vid_hdr;
+	void *p;
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	p = (char *)vid_hdr - ubi->vid_hdr_shift;
+	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+			  ubi->vid_hdr_alsize);
+	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+		goto exit;
+
+	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+	hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+	if (hdr_crc != crc) {
+		ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
+			"read %#08x", pnum, crc, hdr_crc);
+		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_dbg_dump_vid_hdr(vid_hdr);
+		ubi_dbg_dump_stack();
+		err = 1;
+		goto exit;
+	}
+
+	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+
+exit:
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return err;
+}
+
+/**
+ * paranoid_check_all_ff - check that a region of flash is empty.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ * @offset: the starting offset within the physical eraseblock to check
+ * @len: the length of the region to check
+ *
+ * This function returns zero if only 0xFF bytes are present at offset
+ * @offset of the physical eraseblock @pnum, %1 if not, and a negative error
+ * code if an error occurred.
+ */
+static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
+				 int offset, int len)
+{
+	size_t read;
+	int err;
+	void *buf;
+	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+	if (err && err != -EUCLEAN) {
+		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+			"read %zd bytes", err, len, pnum, offset, read);
+		goto error;
+	}
+
+	err = check_pattern(buf, 0xFF, len);
+	if (err == 0) {
+		ubi_err("flash region at PEB %d:%d, length %d does not "
+			"contain all 0xFF bytes", pnum, offset, len);
+		goto fail;
+	}
+
+	kfree(buf);
+	return 0;
+
+fail:
+	ubi_err("paranoid check failed for PEB %d", pnum);
+	dbg_msg("hex dump of the %d-%d region", offset, offset + len);
+	ubi_dbg_hexdump(buf, len);
+	err = 1;
+error:
+	ubi_dbg_dump_stack();
+	kfree(buf);
+	return err;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
new file mode 100644
index 0000000..d352c45
--- /dev/null
+++ b/drivers/mtd/ubi/kapi.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/* This file mostly implements UBI kernel API functions */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/div64.h>
+#include "ubi.h"
+
+/**
+ * ubi_get_device_info - get information about UBI device.
+ * @ubi_num: UBI device number
+ * @di: the information is stored here
+ *
+ * This function returns %0 in case of success and a %-ENODEV if there is no
+ * such UBI device.
+ */
+int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
+{
+	const struct ubi_device *ubi;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
+	    !ubi_devices[ubi_num]) {
+		module_put(THIS_MODULE);
+		return -ENODEV;
+	}
+
+	ubi = ubi_devices[ubi_num];
+	di->ubi_num = ubi->ubi_num;
+	di->leb_size = ubi->leb_size;
+	di->min_io_size = ubi->min_io_size;
+	di->ro_mode = ubi->ro_mode;
+	di->cdev = MKDEV(ubi->major, 0);
+	module_put(THIS_MODULE);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ubi_get_device_info);
+
+/**
+ * ubi_get_volume_info - get information about UBI volume.
+ * @desc: volume descriptor
+ * @vi: the information is stored here
+ */
+void ubi_get_volume_info(struct ubi_volume_desc *desc,
+			 struct ubi_volume_info *vi)
+{
+	const struct ubi_volume *vol = desc->vol;
+	const struct ubi_device *ubi = vol->ubi;
+
+	vi->vol_id = vol->vol_id;
+	vi->ubi_num = ubi->ubi_num;
+	vi->size = vol->reserved_pebs;
+	vi->used_bytes = vol->used_bytes;
+	vi->vol_type = vol->vol_type;
+	vi->corrupted = vol->corrupted;
+	vi->upd_marker = vol->upd_marker;
+	vi->alignment = vol->alignment;
+	vi->usable_leb_size = vol->usable_leb_size;
+	vi->name_len = vol->name_len;
+	vi->name = vol->name;
+	vi->cdev = MKDEV(ubi->major, vi->vol_id + 1);
+}
+EXPORT_SYMBOL_GPL(ubi_get_volume_info);
+
+/**
+ * ubi_open_volume - open UBI volume.
+ * @ubi_num: UBI device number
+ * @vol_id: volume ID
+ * @mode: open mode
+ *
+ * The @mode parameter specifies if the volume should be opened in read-only
+ * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that
+ * nobody else will be able to open this volume. UBI allows to have many volume
+ * readers and one writer at a time.
+ *
+ * If a static volume is being opened for the first time since boot, it will be
+ * checked by this function, which means it will be fully read and the CRC
+ * checksum of each logical eraseblock will be checked.
+ *
+ * This function returns volume descriptor in case of success and a negative
+ * error code in case of failure.
+ */
+struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
+{
+	int err;
+	struct ubi_volume_desc *desc;
+	struct ubi_device *ubi = ubi_devices[ubi_num];
+	struct ubi_volume *vol;
+
+	dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
+
+	err = -ENODEV;
+	if (!try_module_get(THIS_MODULE))
+		return ERR_PTR(err);
+
+	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi)
+		goto out_put;
+
+	err = -EINVAL;
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
+		goto out_put;
+	if (mode != UBI_READONLY && mode != UBI_READWRITE &&
+	    mode != UBI_EXCLUSIVE)
+		goto out_put;
+
+	desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL);
+	if (!desc) {
+		err = -ENOMEM;
+		goto out_put;
+	}
+
+	spin_lock(&ubi->volumes_lock);
+	vol = ubi->volumes[vol_id];
+	if (!vol) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	err = -EBUSY;
+	switch (mode) {
+	case UBI_READONLY:
+		if (vol->exclusive)
+			goto out_unlock;
+		vol->readers += 1;
+		break;
+
+	case UBI_READWRITE:
+		if (vol->exclusive || vol->writers > 0)
+			goto out_unlock;
+		vol->writers += 1;
+		break;
+
+	case UBI_EXCLUSIVE:
+		if (vol->exclusive || vol->writers || vol->readers)
+			goto out_unlock;
+		vol->exclusive = 1;
+		break;
+	}
+	spin_unlock(&ubi->volumes_lock);
+
+	desc->vol = vol;
+	desc->mode = mode;
+
+	/*
+	 * To prevent simultaneous checks of the same volume we use @vtbl_mutex,
+	 * although it is not the purpose it was introduced for.
+	 */
+	mutex_lock(&ubi->vtbl_mutex);
+	if (!vol->checked) {
+		/* This is the first open - check the volume */
+		err = ubi_check_volume(ubi, vol_id);
+		if (err < 0) {
+			mutex_unlock(&ubi->vtbl_mutex);
+			ubi_close_volume(desc);
+			return ERR_PTR(err);
+		}
+		if (err == 1) {
+			ubi_warn("volume %d on UBI device %d is corrupted",
+				 vol_id, ubi->ubi_num);
+			vol->corrupted = 1;
+		}
+		vol->checked = 1;
+	}
+	mutex_unlock(&ubi->vtbl_mutex);
+	return desc;
+
+out_unlock:
+	spin_unlock(&ubi->volumes_lock);
+	kfree(desc);
+out_put:
+	module_put(THIS_MODULE);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(ubi_open_volume);
+
+/**
+ * ubi_open_volume_nm - open UBI volume by name.
+ * @ubi_num: UBI device number
+ * @name: volume name
+ * @mode: open mode
+ *
+ * This function is similar to 'ubi_open_volume()', but opens a volume by name.
+ */
+struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
+					   int mode)
+{
+	int i, vol_id = -1, len;
+	struct ubi_volume_desc *ret;
+	struct ubi_device *ubi;
+
+	dbg_msg("open volume %s, mode %d", name, mode);
+
+	if (!name)
+		return ERR_PTR(-EINVAL);
+
+	len = strnlen(name, UBI_VOL_NAME_MAX + 1);
+	if (len > UBI_VOL_NAME_MAX)
+		return ERR_PTR(-EINVAL);
+
+	ret = ERR_PTR(-ENODEV);
+	if (!try_module_get(THIS_MODULE))
+		return ret;
+
+	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num])
+		goto out_put;
+
+	ubi = ubi_devices[ubi_num];
+
+	spin_lock(&ubi->volumes_lock);
+	/* Walk all volumes of this UBI device */
+	for (i = 0; i < ubi->vtbl_slots; i++) {
+		struct ubi_volume *vol = ubi->volumes[i];
+
+		if (vol && len == vol->name_len && !strcmp(name, vol->name)) {
+			vol_id = i;
+			break;
+		}
+	}
+	spin_unlock(&ubi->volumes_lock);
+
+	if (vol_id < 0)
+		goto out_put;
+
+	ret = ubi_open_volume(ubi_num, vol_id, mode);
+
+out_put:
+	module_put(THIS_MODULE);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
+
+/**
+ * ubi_close_volume - close UBI volume.
+ * @desc: volume descriptor
+ */
+void ubi_close_volume(struct ubi_volume_desc *desc)
+{
+	struct ubi_volume *vol = desc->vol;
+
+	dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode);
+
+	spin_lock(&vol->ubi->volumes_lock);
+	switch (desc->mode) {
+	case UBI_READONLY:
+		vol->readers -= 1;
+		break;
+	case UBI_READWRITE:
+		vol->writers -= 1;
+		break;
+	case UBI_EXCLUSIVE:
+		vol->exclusive = 0;
+	}
+	spin_unlock(&vol->ubi->volumes_lock);
+
+	kfree(desc);
+	module_put(THIS_MODULE);
+}
+EXPORT_SYMBOL_GPL(ubi_close_volume);
+
+/**
+ * ubi_leb_read - read data.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @buf: buffer where to store the read data
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ * @check: whether UBI has to check the read data's CRC or not.
+ *
+ * This function reads data from offset @offset of logical eraseblock @lnum and
+ * stores the data at @buf. When reading from static volumes, @check specifies
+ * whether the data has to be checked or not. If yes, the whole logical
+ * eraseblock will be read and its CRC checksum will be checked (i.e., the CRC
+ * checksum is per-eraseblock). So checking may substantially slow down the
+ * read speed. The @check argument is ignored for dynamic volumes.
+ *
+ * In case of success, this function returns zero. In case of failure, this
+ * function returns a negative error code.
+ *
+ * %-EBADMSG error code is returned:
+ * o for both static and dynamic volumes if MTD driver has detected a data
+ *   integrity problem (unrecoverable ECC checksum mismatch in case of NAND);
+ * o for static volumes in case of data CRC mismatch.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF error code.
+ */
+int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+		 int len, int check)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int err, vol_id = vol->vol_id;
+
+	dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
+	    lnum >= vol->used_ebs || offset < 0 || len < 0 ||
+	    offset + len > vol->usable_leb_size)
+		return -EINVAL;
+
+	if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
+	    offset + len > vol->last_eb_bytes)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+	if (len == 0)
+		return 0;
+
+	err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check);
+	if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
+		ubi_warn("mark volume %d as corrupted", vol_id);
+		vol->corrupted = 1;
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ubi_leb_read);
+
+/**
+ * ubi_leb_write - write data.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to write to
+ * @buf: data to write
+ * @offset: offset within the logical eraseblock where to write
+ * @len: how many bytes to write
+ * @dtype: expected data type
+ *
+ * This function writes @len bytes of data from @buf to offset @offset of
+ * logical eraseblock @lnum. The @dtype argument describes expected lifetime of
+ * the data.
+ *
+ * This function takes care of physical eraseblock write failures. If write to
+ * the physical eraseblock write operation fails, the logical eraseblock is
+ * re-mapped to another physical eraseblock, the data is recovered, and the
+ * write finishes. UBI has a pool of reserved physical eraseblocks for this.
+ *
+ * If all the data were successfully written, zero is returned. If an error
+ * occurred and UBI has not been able to recover from it, this function returns
+ * a negative error code. Note, in case of an error, it is possible that
+ * something was still written to the flash media, but that may be some
+ * garbage.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF code.
+ */
+int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+		  int offset, int len, int dtype)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int vol_id = vol->vol_id;
+
+	dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
+		return -EINVAL;
+
+	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+		return -EROFS;
+
+	if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 ||
+	    offset + len > vol->usable_leb_size || offset % ubi->min_io_size ||
+	    len % ubi->min_io_size)
+		return -EINVAL;
+
+	if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+	    dtype != UBI_UNKNOWN)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	if (len == 0)
+		return 0;
+
+	return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_write);
+
+/*
+ * ubi_leb_change - change logical eraseblock atomically.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to change
+ * @buf: data to write
+ * @len: how many bytes to write
+ * @dtype: expected data type
+ *
+ * This function changes the contents of a logical eraseblock atomically. @buf
+ * has to contain new logical eraseblock data, and @len - the length of the
+ * data, which has to be aligned. The length may be shorter then the logical
+ * eraseblock size, ant the logical eraseblock may be appended to more times
+ * later on. This function guarantees that in case of an unclean reboot the old
+ * contents is preserved. Returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+		   int len, int dtype)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int vol_id = vol->vol_id;
+
+	dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum);
+
+	if (vol_id < 0 || vol_id >= ubi->vtbl_slots)
+		return -EINVAL;
+
+	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+		return -EROFS;
+
+	if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 ||
+	    len > vol->usable_leb_size || len % ubi->min_io_size)
+		return -EINVAL;
+
+	if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
+	    dtype != UBI_UNKNOWN)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	if (len == 0)
+		return 0;
+
+	return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_change);
+
+/**
+ * ubi_leb_erase - erase logical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and synchronously erases the
+ * correspondent physical eraseblock. Returns zero in case of success and a
+ * negative error code in case of failure.
+ *
+ * If the volume is damaged because of an interrupted update this function just
+ * returns immediately with %-EBADF code.
+ */
+int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int err, vol_id = vol->vol_id;
+
+	dbg_msg("erase LEB %d:%d", vol_id, lnum);
+
+	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+		return -EROFS;
+
+	if (lnum < 0 || lnum >= vol->reserved_pebs)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	err = ubi_eba_unmap_leb(ubi, vol_id, lnum);
+	if (err)
+		return err;
+
+	return ubi_wl_flush(ubi);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_erase);
+
+/**
+ * ubi_leb_unmap - un-map logical eraseblock.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function un-maps logical eraseblock @lnum and schedules the
+ * corresponding physical eraseblock for erasure, so that it will eventually be
+ * physically erased in background. This operation is much faster then the
+ * erase operation.
+ *
+ * Unlike erase, the un-map operation does not guarantee that the logical
+ * eraseblock will contain all 0xFF bytes when UBI is initialized again. For
+ * example, if several logical eraseblocks are un-mapped, and an unclean reboot
+ * happens after this, the logical eraseblocks will not necessarily be
+ * un-mapped again when this MTD device is attached. They may actually be
+ * mapped to the same physical eraseblocks again. So, this function has to be
+ * used with care.
+ *
+ * In other words, when un-mapping a logical eraseblock, UBI does not store
+ * any information about this on the flash media, it just marks the logical
+ * eraseblock as "un-mapped" in RAM. If UBI is detached before the physical
+ * eraseblock is physically erased, it will be mapped again to the same logical
+ * eraseblock when the MTD device is attached again.
+ *
+ * The main and obvious use-case of this function is when the contents of a
+ * logical eraseblock has to be re-written. Then it is much more efficient to
+ * first un-map it, then write new data, rather then first erase it, then write
+ * new data. Note, once new data has been written to the logical eraseblock,
+ * UBI guarantees that the old contents has gone forever. In other words, if an
+ * unclean reboot happens after the logical eraseblock has been un-mapped and
+ * then written to, it will contain the last written data.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure. If the volume is damaged because of an interrupted update
+ * this function just returns immediately with %-EBADF code.
+ */
+int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int vol_id = vol->vol_id;
+
+	dbg_msg("unmap LEB %d:%d", vol_id, lnum);
+
+	if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME)
+		return -EROFS;
+
+	if (lnum < 0 || lnum >= vol->reserved_pebs)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	return ubi_eba_unmap_leb(ubi, vol_id, lnum);
+}
+EXPORT_SYMBOL_GPL(ubi_leb_unmap);
+
+/**
+ * ubi_is_mapped - check if logical eraseblock is mapped.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number
+ *
+ * This function checks if logical eraseblock @lnum is mapped to a physical
+ * eraseblock. If a logical eraseblock is un-mapped, this does not necessarily
+ * mean it will still be un-mapped after the UBI device is re-attached. The
+ * logical eraseblock may become mapped to the physical eraseblock it was last
+ * mapped to.
+ *
+ * This function returns %1 if the LEB is mapped, %0 if not, and a negative
+ * error code in case of failure. If the volume is damaged because of an
+ * interrupted update this function just returns immediately with %-EBADF error
+ * code.
+ */
+int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum)
+{
+	struct ubi_volume *vol = desc->vol;
+
+	dbg_msg("test LEB %d:%d", vol->vol_id, lnum);
+
+	if (lnum < 0 || lnum >= vol->reserved_pebs)
+		return -EINVAL;
+
+	if (vol->upd_marker)
+		return -EBADF;
+
+	return vol->eba_tbl[lnum] >= 0;
+}
+EXPORT_SYMBOL_GPL(ubi_is_mapped);
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
new file mode 100644
index 0000000..38d4e67
--- /dev/null
+++ b/drivers/mtd/ubi/misc.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/* Here we keep miscellaneous functions which are used all over the UBI code */
+
+#include "ubi.h"
+
+/**
+ * calc_data_len - calculate how much real data is stored in a buffer.
+ * @ubi: UBI device description object
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @length: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and returnes
+ * the length. Continuous 0xFF bytes at the end of the buffer are not
+ * considered as "real data".
+ */
+int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
+		      int length)
+{
+	int i;
+
+	ubi_assert(length % ubi->min_io_size == 0);
+
+	for (i = length - 1; i >= 0; i--)
+		if (((const uint8_t *)buf)[i] != 0xFF)
+			break;
+
+	/* The resulting length must be aligned to the minimum flash I/O size */
+	length = ALIGN(i + 1, ubi->min_io_size);
+	return length;
+}
+
+/**
+ * ubi_check_volume - check the contents of a static volume.
+ * @ubi: UBI device description object
+ * @vol_id: ID of the volume to check
+ *
+ * This function checks if static volume @vol_id is corrupted by fully reading
+ * it and checking data CRC. This function returns %0 if the volume is not
+ * corrupted, %1 if it is corrupted and a negative error code in case of
+ * failure. Dynamic volumes are not checked and zero is returned immediately.
+ */
+int ubi_check_volume(struct ubi_device *ubi, int vol_id)
+{
+	void *buf;
+	int err = 0, i;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	if (vol->vol_type != UBI_STATIC_VOLUME)
+		return 0;
+
+	buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < vol->used_ebs; i++) {
+		int size;
+
+		if (i == vol->used_ebs - 1)
+			size = vol->last_eb_bytes;
+		else
+			size = vol->usable_leb_size;
+
+		err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1);
+		if (err) {
+			if (err == -EBADMSG)
+				err = 1;
+			break;
+		}
+	}
+
+	kfree(buf);
+	return err;
+}
+
+/**
+ * ubi_calculate_rsvd_pool - calculate how many PEBs must be reserved for bad
+ * eraseblock handling.
+ * @ubi: UBI device description object
+ */
+void ubi_calculate_reserved(struct ubi_device *ubi)
+{
+	ubi->beb_rsvd_level = ubi->good_peb_count/100;
+	ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE;
+	if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS)
+		ubi->beb_rsvd_level = MIN_RESEVED_PEBS;
+}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
new file mode 100644
index 0000000..473f320
--- /dev/null
+++ b/drivers/mtd/ubi/scan.c
@@ -0,0 +1,1368 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * UBI scanning unit.
+ *
+ * This unit is responsible for scanning the flash media, checking UBI
+ * headers and providing complete information about the UBI flash image.
+ *
+ * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * Information about found volumes is represented by &struct ubi_scan_volume
+ * objects which are kept in volume RB-tree with root at the @volumes field.
+ * The RB-tree is indexed by the volume ID.
+ *
+ * Found logical eraseblocks are represented by &struct ubi_scan_leb objects.
+ * These objects are kept in per-volume RB-trees with the root at the
+ * corresponding &struct ubi_scan_volume object. To put it differently, we keep
+ * an RB-tree of per-volume objects and each of these objects is the root of
+ * RB-tree of per-eraseblock objects.
+ *
+ * Corrupted physical eraseblocks are put to the @corr list, free physical
+ * eraseblocks are put to the @free list and the physical eraseblock to be
+ * erased are put to the @erase list.
+ */
+
+#include <linux/err.h>
+#include <linux/crc32.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_si(const struct ubi_device *ubi,
+			     struct ubi_scan_info *si);
+#else
+#define paranoid_check_si(ubi, si) 0
+#endif
+
+/* Temporary variables used during scanning */
+static struct ubi_ec_hdr *ech;
+static struct ubi_vid_hdr *vidh;
+
+int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+			 struct list_head *list)
+{
+	struct ubi_scan_leb *seb;
+
+	if (list == &si->free)
+		dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
+	else if (list == &si->erase)
+		dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
+	else if (list == &si->corr)
+		dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
+	else if (list == &si->alien)
+		dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
+	else
+		BUG();
+
+	seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+	if (!seb)
+		return -ENOMEM;
+
+	seb->pnum = pnum;
+	seb->ec = ec;
+	list_add_tail(&seb->u.list, list);
+	return 0;
+}
+
+/**
+ * commit_to_mean_value - commit intermediate results to the final mean erase
+ * counter value.
+ * @si: scanning information
+ *
+ * This is a helper function which calculates partial mean erase counter mean
+ * value and adds it to the resulting mean value. As we can work only in
+ * integer arithmetic and we want to calculate the mean value of erase counter
+ * accurately, we first sum erase counter values in @si->ec_sum variable and
+ * count these components in @si->ec_count. If this temporary @si->ec_sum is
+ * going to overflow, we calculate the partial mean value
+ * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec.
+ */
+static void commit_to_mean_value(struct ubi_scan_info *si)
+{
+	si->ec_sum /= si->ec_count;
+	if (si->ec_sum % si->ec_count >= si->ec_count / 2)
+		si->mean_ec += 1;
+	si->mean_ec += si->ec_sum;
+}
+
+/**
+ * validate_vid_hdr - check that volume identifier header is correct and
+ * consistent.
+ * @vid_hdr: the volume identifier header to check
+ * @sv: information about the volume this logical eraseblock belongs to
+ * @pnum: physical eraseblock number the VID header came from
+ *
+ * This function checks that data stored in @vid_hdr is consistent. Returns
+ * non-zero if an inconsistency was found and zero if not.
+ *
+ * Note, UBI does sanity check of everything it reads from the flash media.
+ * Most of the checks are done in the I/O unit. Here we check that the
+ * information in the VID header is consistent to the information in other VID
+ * headers of the same volume.
+ */
+static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
+			    const struct ubi_scan_volume *sv, int pnum)
+{
+	int vol_type = vid_hdr->vol_type;
+	int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
+	int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
+	int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+
+	if (sv->leb_count != 0) {
+		int sv_vol_type;
+
+		/*
+		 * This is not the first logical eraseblock belonging to this
+		 * volume. Ensure that the data in its VID header is consistent
+		 * to the data in previous logical eraseblock headers.
+		 */
+
+		if (vol_id != sv->vol_id) {
+			dbg_err("inconsistent vol_id");
+			goto bad;
+		}
+
+		if (sv->vol_type == UBI_STATIC_VOLUME)
+			sv_vol_type = UBI_VID_STATIC;
+		else
+			sv_vol_type = UBI_VID_DYNAMIC;
+
+		if (vol_type != sv_vol_type) {
+			dbg_err("inconsistent vol_type");
+			goto bad;
+		}
+
+		if (used_ebs != sv->used_ebs) {
+			dbg_err("inconsistent used_ebs");
+			goto bad;
+		}
+
+		if (data_pad != sv->data_pad) {
+			dbg_err("inconsistent data_pad");
+			goto bad;
+		}
+	}
+
+	return 0;
+
+bad:
+	ubi_err("inconsistent VID header at PEB %d", pnum);
+	ubi_dbg_dump_vid_hdr(vid_hdr);
+	ubi_dbg_dump_sv(sv);
+	return -EINVAL;
+}
+
+/**
+ * add_volume - add volume to the scanning information.
+ * @si: scanning information
+ * @vol_id: ID of the volume to add
+ * @pnum: physical eraseblock number
+ * @vid_hdr: volume identifier header
+ *
+ * If the volume corresponding to the @vid_hdr logical eraseblock is already
+ * present in the scanning information, this function does nothing. Otherwise
+ * it adds corresponding volume to the scanning information. Returns a pointer
+ * to the scanning volume object in case of success and a negative error code
+ * in case of failure.
+ */
+static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
+					  int pnum,
+					  const struct ubi_vid_hdr *vid_hdr)
+{
+	struct ubi_scan_volume *sv;
+	struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
+
+	ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+
+	/* Walk the volume RB-tree to look if this volume is already present */
+	while (*p) {
+		parent = *p;
+		sv = rb_entry(parent, struct ubi_scan_volume, rb);
+
+		if (vol_id == sv->vol_id)
+			return sv;
+
+		if (vol_id > sv->vol_id)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	/* The volume is absent - add it */
+	sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);
+	if (!sv)
+		return ERR_PTR(-ENOMEM);
+
+	sv->highest_lnum = sv->leb_count = 0;
+	si->max_sqnum = 0;
+	sv->vol_id = vol_id;
+	sv->root = RB_ROOT;
+	sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
+	sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+	sv->compat = vid_hdr->compat;
+	sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
+							    : UBI_STATIC_VOLUME;
+	if (vol_id > si->highest_vol_id)
+		si->highest_vol_id = vol_id;
+
+	rb_link_node(&sv->rb, parent, p);
+	rb_insert_color(&sv->rb, &si->volumes);
+	si->vols_found += 1;
+	dbg_bld("added volume %d", vol_id);
+	return sv;
+}
+
+/**
+ * compare_lebs - find out which logical eraseblock is newer.
+ * @ubi: UBI device description object
+ * @seb: first logical eraseblock to compare
+ * @pnum: physical eraseblock number of the second logical eraseblock to
+ * compare
+ * @vid_hdr: volume identifier header of the second logical eraseblock
+ *
+ * This function compares 2 copies of a LEB and informs which one is newer. In
+ * case of success this function returns a positive value, in case of failure, a
+ * negative error code is returned. The success return codes use the following
+ * bits:
+ *     o bit 0 is cleared: the first PEB (described by @seb) is newer then the
+ *       second PEB (described by @pnum and @vid_hdr);
+ *     o bit 0 is set: the second PEB is newer;
+ *     o bit 1 is cleared: no bit-flips were detected in the newer LEB;
+ *     o bit 1 is set: bit-flips were detected in the newer LEB;
+ *     o bit 2 is cleared: the older LEB is not corrupted;
+ *     o bit 2 is set: the older LEB is corrupted.
+ */
+static int compare_lebs(const struct ubi_device *ubi,
+			const struct ubi_scan_leb *seb, int pnum,
+			const struct ubi_vid_hdr *vid_hdr)
+{
+	void *buf;
+	int len, err, second_is_newer, bitflips = 0, corrupted = 0;
+	uint32_t data_crc, crc;
+	struct ubi_vid_hdr *vidh = NULL;
+	unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+
+	if (seb->sqnum == 0 && sqnum2 == 0) {
+		long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+
+		/*
+		 * UBI constantly increases the logical eraseblock version
+		 * number and it can overflow. Thus, we have to bear in mind
+		 * that versions that are close to %0xFFFFFFFF are less then
+		 * versions that are close to %0.
+		 *
+		 * The UBI WL unit guarantees that the number of pending tasks
+		 * is not greater then %0x7FFFFFFF. So, if the difference
+		 * between any two versions is greater or equivalent to
+		 * %0x7FFFFFFF, there was an overflow and the logical
+		 * eraseblock with lower version is actually newer then the one
+		 * with higher version.
+		 *
+		 * FIXME: but this is anyway obsolete and will be removed at
+		 * some point.
+		 */
+
+		dbg_bld("using old crappy leb_ver stuff");
+
+		abs = v1 - v2;
+		if (abs < 0)
+			abs = -abs;
+
+		if (abs < 0x7FFFFFFF)
+			/* Non-overflow situation */
+			second_is_newer = (v2 > v1);
+		else
+			second_is_newer = (v2 < v1);
+	} else
+		/* Obviously the LEB with lower sequence counter is older */
+		second_is_newer = sqnum2 > seb->sqnum;
+
+	/*
+	 * Now we know which copy is newer. If the copy flag of the PEB with
+	 * newer version is not set, then we just return, otherwise we have to
+	 * check data CRC. For the second PEB we already have the VID header,
+	 * for the first one - we'll need to re-read it from flash.
+	 *
+	 * FIXME: this may be optimized so that we wouldn't read twice.
+	 */
+
+	if (second_is_newer) {
+		if (!vid_hdr->copy_flag) {
+			/* It is not a copy, so it is newer */
+			dbg_bld("second PEB %d is newer, copy_flag is unset",
+				pnum);
+			return 1;
+		}
+	} else {
+		pnum = seb->pnum;
+
+		vidh = ubi_zalloc_vid_hdr(ubi);
+		if (!vidh)
+			return -ENOMEM;
+
+		err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+		if (err) {
+			if (err == UBI_IO_BITFLIPS)
+				bitflips = 1;
+			else {
+				dbg_err("VID of PEB %d header is bad, but it "
+					"was OK earlier", pnum);
+				if (err > 0)
+					err = -EIO;
+
+				goto out_free_vidh;
+			}
+		}
+
+		if (!vidh->copy_flag) {
+			/* It is not a copy, so it is newer */
+			dbg_bld("first PEB %d is newer, copy_flag is unset",
+				pnum);
+			err = bitflips << 1;
+			goto out_free_vidh;
+		}
+
+		vid_hdr = vidh;
+	}
+
+	/* Read the data of the copy and check the CRC */
+
+	len = ubi32_to_cpu(vid_hdr->data_size);
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out_free_vidh;
+	}
+
+	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
+	if (err && err != UBI_IO_BITFLIPS)
+		goto out_free_buf;
+
+	data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+	crc = crc32(UBI_CRC32_INIT, buf, len);
+	if (crc != data_crc) {
+		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
+			pnum, crc, data_crc);
+		corrupted = 1;
+		bitflips = 0;
+		second_is_newer = !second_is_newer;
+	} else {
+		dbg_bld("PEB %d CRC is OK", pnum);
+		bitflips = !!err;
+	}
+
+	kfree(buf);
+	ubi_free_vid_hdr(ubi, vidh);
+
+	if (second_is_newer)
+		dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
+	else
+		dbg_bld("first PEB %d is newer, copy_flag is set", pnum);
+
+	return second_is_newer | (bitflips << 1) | (corrupted << 2);
+
+out_free_buf:
+	kfree(buf);
+out_free_vidh:
+	ubi_free_vid_hdr(ubi, vidh);
+	ubi_assert(err < 0);
+	return err;
+}
+
+/**
+ * ubi_scan_add_used - add information about a physical eraseblock to the
+ * scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: the physical eraseblock number
+ * @ec: erase counter
+ * @vid_hdr: the volume identifier header
+ * @bitflips: if bit-flips were detected when this physical eraseblock was read
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
+		      int bitflips)
+{
+	int err, vol_id, lnum;
+	uint32_t leb_ver;
+	unsigned long long sqnum;
+	struct ubi_scan_volume *sv;
+	struct ubi_scan_leb *seb;
+	struct rb_node **p, *parent = NULL;
+
+	vol_id = ubi32_to_cpu(vid_hdr->vol_id);
+	lnum = ubi32_to_cpu(vid_hdr->lnum);
+	sqnum = ubi64_to_cpu(vid_hdr->sqnum);
+	leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+
+	dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
+		pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
+
+	sv = add_volume(si, vol_id, pnum, vid_hdr);
+	if (IS_ERR(sv) < 0)
+		return PTR_ERR(sv);
+
+	/*
+	 * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
+	 * if this is the first instance of this logical eraseblock or not.
+	 */
+	p = &sv->root.rb_node;
+	while (*p) {
+		int cmp_res;
+
+		parent = *p;
+		seb = rb_entry(parent, struct ubi_scan_leb, u.rb);
+		if (lnum != seb->lnum) {
+			if (lnum < seb->lnum)
+				p = &(*p)->rb_left;
+			else
+				p = &(*p)->rb_right;
+			continue;
+		}
+
+		/*
+		 * There is already a physical eraseblock describing the same
+		 * logical eraseblock present.
+		 */
+
+		dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
+			"LEB ver %u, EC %d", seb->pnum, seb->sqnum,
+			seb->leb_ver, seb->ec);
+
+		/*
+		 * Make sure that the logical eraseblocks have different
+		 * versions. Otherwise the image is bad.
+		 */
+		if (seb->leb_ver == leb_ver && leb_ver != 0) {
+			ubi_err("two LEBs with same version %u", leb_ver);
+			ubi_dbg_dump_seb(seb, 0);
+			ubi_dbg_dump_vid_hdr(vid_hdr);
+			return -EINVAL;
+		}
+
+		/*
+		 * Make sure that the logical eraseblocks have different
+		 * sequence numbers. Otherwise the image is bad.
+		 *
+		 * FIXME: remove 'sqnum != 0' check when leb_ver is removed.
+		 */
+		if (seb->sqnum == sqnum && sqnum != 0) {
+			ubi_err("two LEBs with same sequence number %llu",
+				sqnum);
+			ubi_dbg_dump_seb(seb, 0);
+			ubi_dbg_dump_vid_hdr(vid_hdr);
+			return -EINVAL;
+		}
+
+		/*
+		 * Now we have to drop the older one and preserve the newer
+		 * one.
+		 */
+		cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);
+		if (cmp_res < 0)
+			return cmp_res;
+
+		if (cmp_res & 1) {
+			/*
+			 * This logical eraseblock is newer then the one
+			 * found earlier.
+			 */
+			err = validate_vid_hdr(vid_hdr, sv, pnum);
+			if (err)
+				return err;
+
+			if (cmp_res & 4)
+				err = ubi_scan_add_to_list(si, seb->pnum,
+							   seb->ec, &si->corr);
+			else
+				err = ubi_scan_add_to_list(si, seb->pnum,
+							   seb->ec, &si->erase);
+			if (err)
+				return err;
+
+			seb->ec = ec;
+			seb->pnum = pnum;
+			seb->scrub = ((cmp_res & 2) || bitflips);
+			seb->sqnum = sqnum;
+			seb->leb_ver = leb_ver;
+
+			if (sv->highest_lnum == lnum)
+				sv->last_data_size =
+					ubi32_to_cpu(vid_hdr->data_size);
+
+			return 0;
+		} else {
+			/*
+			 * This logical eraseblock is older then the one found
+			 * previously.
+			 */
+			if (cmp_res & 4)
+				return ubi_scan_add_to_list(si, pnum, ec,
+							    &si->corr);
+			else
+				return ubi_scan_add_to_list(si, pnum, ec,
+							    &si->erase);
+		}
+	}
+
+	/*
+	 * We've met this logical eraseblock for the first time, add it to the
+	 * scanning information.
+	 */
+
+	err = validate_vid_hdr(vid_hdr, sv, pnum);
+	if (err)
+		return err;
+
+	seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+	if (!seb)
+		return -ENOMEM;
+
+	seb->ec = ec;
+	seb->pnum = pnum;
+	seb->lnum = lnum;
+	seb->sqnum = sqnum;
+	seb->scrub = bitflips;
+	seb->leb_ver = leb_ver;
+
+	if (sv->highest_lnum <= lnum) {
+		sv->highest_lnum = lnum;
+		sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+	}
+
+	if (si->max_sqnum < sqnum)
+		si->max_sqnum = sqnum;
+
+	sv->leb_count += 1;
+	rb_link_node(&seb->u.rb, parent, p);
+	rb_insert_color(&seb->u.rb, &sv->root);
+	return 0;
+}
+
+/**
+ * ubi_scan_find_sv - find information about a particular volume in the
+ * scanning information.
+ * @si: scanning information
+ * @vol_id: the requested volume ID
+ *
+ * This function returns a pointer to the volume description or %NULL if there
+ * are no data about this volume in the scanning information.
+ */
+struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
+					 int vol_id)
+{
+	struct ubi_scan_volume *sv;
+	struct rb_node *p = si->volumes.rb_node;
+
+	while (p) {
+		sv = rb_entry(p, struct ubi_scan_volume, rb);
+
+		if (vol_id == sv->vol_id)
+			return sv;
+
+		if (vol_id > sv->vol_id)
+			p = p->rb_left;
+		else
+			p = p->rb_right;
+	}
+
+	return NULL;
+}
+
+/**
+ * ubi_scan_find_seb - find information about a particular logical
+ * eraseblock in the volume scanning information.
+ * @sv: a pointer to the volume scanning information
+ * @lnum: the requested logical eraseblock
+ *
+ * This function returns a pointer to the scanning logical eraseblock or %NULL
+ * if there are no data about it in the scanning volume information.
+ */
+struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
+				       int lnum)
+{
+	struct ubi_scan_leb *seb;
+	struct rb_node *p = sv->root.rb_node;
+
+	while (p) {
+		seb = rb_entry(p, struct ubi_scan_leb, u.rb);
+
+		if (lnum == seb->lnum)
+			return seb;
+
+		if (lnum > seb->lnum)
+			p = p->rb_left;
+		else
+			p = p->rb_right;
+	}
+
+	return NULL;
+}
+
+/**
+ * ubi_scan_rm_volume - delete scanning information about a volume.
+ * @si: scanning information
+ * @sv: the volume scanning information to delete
+ */
+void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+{
+	struct rb_node *rb;
+	struct ubi_scan_leb *seb;
+
+	dbg_bld("remove scanning information about volume %d", sv->vol_id);
+
+	while ((rb = rb_first(&sv->root))) {
+		seb = rb_entry(rb, struct ubi_scan_leb, u.rb);
+		rb_erase(&seb->u.rb, &sv->root);
+		list_add_tail(&seb->u.list, &si->erase);
+	}
+
+	rb_erase(&sv->rb, &si->volumes);
+	kfree(sv);
+	si->vols_found -= 1;
+}
+
+/**
+ * ubi_scan_erase_peb - erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: physical eraseblock number to erase;
+ * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ *
+ * This function erases physical eraseblock 'pnum', and writes the erase
+ * counter header to it. This function should only be used on UBI device
+ * initialization stages, when the EBA unit had not been yet initialized. This
+ * function returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+int ubi_scan_erase_peb(const struct ubi_device *ubi,
+		       const struct ubi_scan_info *si, int pnum, int ec)
+{
+	int err;
+	struct ubi_ec_hdr *ec_hdr;
+
+	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ec_hdr)
+		return -ENOMEM;
+
+	if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
+		/*
+		 * Erase counter overflow. Upgrade UBI and use 64-bit
+		 * erase counters internally.
+		 */
+		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
+		return -EINVAL;
+	}
+
+	ec_hdr->ec = cpu_to_ubi64(ec);
+
+	err = ubi_io_sync_erase(ubi, pnum, 0);
+	if (err < 0)
+		goto out_free;
+
+	err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
+
+out_free:
+	kfree(ec_hdr);
+	return err;
+}
+
+/**
+ * ubi_scan_get_free_peb - get a free physical eraseblock.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns a free physical eraseblock. It is supposed to be
+ * called on the UBI initialization stages when the wear-leveling unit is not
+ * initialized yet. This function picks a physical eraseblocks from one of the
+ * lists, writes the EC header if it is needed, and removes it from the list.
+ *
+ * This function returns scanning physical eraseblock information in case of
+ * success and an error code in case of failure.
+ */
+struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+					   struct ubi_scan_info *si)
+{
+	int err = 0, i;
+	struct ubi_scan_leb *seb;
+
+	if (!list_empty(&si->free)) {
+		seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);
+		list_del(&seb->u.list);
+		dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);
+		return seb;
+	}
+
+	for (i = 0; i < 2; i++) {
+		struct list_head *head;
+		struct ubi_scan_leb *tmp_seb;
+
+		if (i == 0)
+			head = &si->erase;
+		else
+			head = &si->corr;
+
+		/*
+		 * We try to erase the first physical eraseblock from the @head
+		 * list and pick it if we succeed, or try to erase the
+		 * next one if not. And so forth. We don't want to take care
+		 * about bad eraseblocks here - they'll be handled later.
+		 */
+		list_for_each_entry_safe(seb, tmp_seb, head, u.list) {
+			if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+				seb->ec = si->mean_ec;
+
+			err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);
+			if (err)
+				continue;
+
+			seb->ec += 1;
+			list_del(&seb->u.list);
+			dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);
+			return seb;
+		}
+	}
+
+	ubi_err("no eraseblocks found");
+	return ERR_PTR(-ENOSPC);
+}
+
+/**
+ * process_eb - read UBI headers, check them and add corresponding data
+ * to the scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @pnum: the physical eraseblock number
+ *
+ * This function returns a zero if the physical eraseblock was succesfully
+ * handled and a negative error code in case of failure.
+ */
+static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
+{
+	long long ec;
+	int err, bitflips = 0, vol_id, ec_corr = 0;
+
+	dbg_bld("scan PEB %d", pnum);
+
+	/* Skip bad physical eraseblocks */
+	err = ubi_io_is_bad(ubi, pnum);
+	if (err < 0)
+		return err;
+	else if (err) {
+		/*
+		 * FIXME: this is actually duty of the I/O unit to initialize
+		 * this, but MTD does not provide enough information.
+		 */
+		si->bad_peb_count += 1;
+		return 0;
+	}
+
+	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
+	if (err < 0)
+		return err;
+	else if (err == UBI_IO_BITFLIPS)
+		bitflips = 1;
+	else if (err == UBI_IO_PEB_EMPTY)
+		return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
+					    &si->erase);
+	else if (err == UBI_IO_BAD_EC_HDR) {
+		/*
+		 * We have to also look at the VID header, possibly it is not
+		 * corrupted. Set %bitflips flag in order to make this PEB be
+		 * moved and EC be re-created.
+		 */
+		ec_corr = 1;
+		ec = UBI_SCAN_UNKNOWN_EC;
+		bitflips = 1;
+	}
+
+	si->is_empty = 0;
+
+	if (!ec_corr) {
+		/* Make sure UBI version is OK */
+		if (ech->version != UBI_VERSION) {
+			ubi_err("this UBI version is %d, image version is %d",
+				UBI_VERSION, (int)ech->version);
+			return -EINVAL;
+		}
+
+		ec = ubi64_to_cpu(ech->ec);
+		if (ec > UBI_MAX_ERASECOUNTER) {
+			/*
+			 * Erase counter overflow. The EC headers have 64 bits
+			 * reserved, but we anyway make use of only 31 bit
+			 * values, as this seems to be enough for any existing
+			 * flash. Upgrade UBI and use 64-bit erase counters
+			 * internally.
+			 */
+			ubi_err("erase counter overflow, max is %d",
+				UBI_MAX_ERASECOUNTER);
+			ubi_dbg_dump_ec_hdr(ech);
+			return -EINVAL;
+		}
+	}
+
+	/* OK, we've done with the EC header, let's look at the VID header */
+
+	err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+	if (err < 0)
+		return err;
+	else if (err == UBI_IO_BITFLIPS)
+		bitflips = 1;
+	else if (err == UBI_IO_BAD_VID_HDR ||
+		 (err == UBI_IO_PEB_FREE && ec_corr)) {
+		/* VID header is corrupted */
+		err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+		if (err)
+			return err;
+		goto adjust_mean_ec;
+	} else if (err == UBI_IO_PEB_FREE) {
+		/* No VID header - the physical eraseblock is free */
+		err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+		if (err)
+			return err;
+		goto adjust_mean_ec;
+	}
+
+	vol_id = ubi32_to_cpu(vidh->vol_id);
+	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
+		int lnum = ubi32_to_cpu(vidh->lnum);
+
+		/* Unsupported internal volume */
+		switch (vidh->compat) {
+		case UBI_COMPAT_DELETE:
+			ubi_msg("\"delete\" compatible internal volume %d:%d"
+				" found, remove it", vol_id, lnum);
+			err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+			if (err)
+				return err;
+			break;
+
+		case UBI_COMPAT_RO:
+			ubi_msg("read-only compatible internal volume %d:%d"
+				" found, switch to read-only mode",
+				vol_id, lnum);
+			ubi->ro_mode = 1;
+			break;
+
+		case UBI_COMPAT_PRESERVE:
+			ubi_msg("\"preserve\" compatible internal volume %d:%d"
+				" found", vol_id, lnum);
+			err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+			if (err)
+				return err;
+			si->alien_peb_count += 1;
+			return 0;
+
+		case UBI_COMPAT_REJECT:
+			ubi_err("incompatible internal volume %d:%d found",
+				vol_id, lnum);
+			return -EINVAL;
+		}
+	}
+
+	/* Both UBI headers seem to be fine */
+	err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
+	if (err)
+		return err;
+
+adjust_mean_ec:
+	if (!ec_corr) {
+		if (si->ec_sum + ec < ec) {
+			commit_to_mean_value(si);
+			si->ec_sum = 0;
+			si->ec_count = 0;
+		} else {
+			si->ec_sum += ec;
+			si->ec_count += 1;
+		}
+
+		if (ec > si->max_ec)
+			si->max_ec = ec;
+		if (ec < si->min_ec)
+			si->min_ec = ec;
+	}
+
+	return 0;
+}
+
+/**
+ * ubi_scan - scan an MTD device.
+ * @ubi: UBI device description object
+ *
+ * This function does full scanning of an MTD device and returns complete
+ * information about it. In case of failure, an error code is returned.
+ */
+struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
+{
+	int err, pnum;
+	struct rb_node *rb1, *rb2;
+	struct ubi_scan_volume *sv;
+	struct ubi_scan_leb *seb;
+	struct ubi_scan_info *si;
+
+	si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
+	if (!si)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&si->corr);
+	INIT_LIST_HEAD(&si->free);
+	INIT_LIST_HEAD(&si->erase);
+	INIT_LIST_HEAD(&si->alien);
+	si->volumes = RB_ROOT;
+	si->is_empty = 1;
+
+	err = -ENOMEM;
+	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ech)
+		goto out_si;
+
+	vidh = ubi_zalloc_vid_hdr(ubi);
+	if (!vidh)
+		goto out_ech;
+
+	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+		cond_resched();
+
+		dbg_msg("process PEB %d", pnum);
+		err = process_eb(ubi, si, pnum);
+		if (err < 0)
+			goto out_vidh;
+	}
+
+	dbg_msg("scanning is finished");
+
+	/* Finish mean erase counter calculations */
+	if (si->ec_count)
+		commit_to_mean_value(si);
+
+	if (si->is_empty)
+		ubi_msg("empty MTD device detected");
+
+	/*
+	 * In case of unknown erase counter we use the mean erase counter
+	 * value.
+	 */
+	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
+			if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+				seb->ec = si->mean_ec;
+	}
+
+	list_for_each_entry(seb, &si->free, u.list) {
+		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+			seb->ec = si->mean_ec;
+	}
+
+	list_for_each_entry(seb, &si->corr, u.list)
+		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+			seb->ec = si->mean_ec;
+
+	list_for_each_entry(seb, &si->erase, u.list)
+		if (seb->ec == UBI_SCAN_UNKNOWN_EC)
+			seb->ec = si->mean_ec;
+
+	err = paranoid_check_si(ubi, si);
+	if (err) {
+		if (err > 0)
+			err = -EINVAL;
+		goto out_vidh;
+	}
+
+	ubi_free_vid_hdr(ubi, vidh);
+	kfree(ech);
+
+	return si;
+
+out_vidh:
+	ubi_free_vid_hdr(ubi, vidh);
+out_ech:
+	kfree(ech);
+out_si:
+	ubi_scan_destroy_si(si);
+	return ERR_PTR(err);
+}
+
+/**
+ * destroy_sv - free the scanning volume information
+ * @sv: scanning volume information
+ *
+ * This function destroys the volume RB-tree (@sv->root) and the scanning
+ * volume information.
+ */
+static void destroy_sv(struct ubi_scan_volume *sv)
+{
+	struct ubi_scan_leb *seb;
+	struct rb_node *this = sv->root.rb_node;
+
+	while (this) {
+		if (this->rb_left)
+			this = this->rb_left;
+		else if (this->rb_right)
+			this = this->rb_right;
+		else {
+			seb = rb_entry(this, struct ubi_scan_leb, u.rb);
+			this = rb_parent(this);
+			if (this) {
+				if (this->rb_left == &seb->u.rb)
+					this->rb_left = NULL;
+				else
+					this->rb_right = NULL;
+			}
+
+			kfree(seb);
+		}
+	}
+	kfree(sv);
+}
+
+/**
+ * ubi_scan_destroy_si - destroy scanning information.
+ * @si: scanning information
+ */
+void ubi_scan_destroy_si(struct ubi_scan_info *si)
+{
+	struct ubi_scan_leb *seb, *seb_tmp;
+	struct ubi_scan_volume *sv;
+	struct rb_node *rb;
+
+	list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
+		list_del(&seb->u.list);
+		kfree(seb);
+	}
+	list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
+		list_del(&seb->u.list);
+		kfree(seb);
+	}
+	list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
+		list_del(&seb->u.list);
+		kfree(seb);
+	}
+	list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
+		list_del(&seb->u.list);
+		kfree(seb);
+	}
+
+	/* Destroy the volume RB-tree */
+	rb = si->volumes.rb_node;
+	while (rb) {
+		if (rb->rb_left)
+			rb = rb->rb_left;
+		else if (rb->rb_right)
+			rb = rb->rb_right;
+		else {
+			sv = rb_entry(rb, struct ubi_scan_volume, rb);
+
+			rb = rb_parent(rb);
+			if (rb) {
+				if (rb->rb_left == &sv->rb)
+					rb->rb_left = NULL;
+				else
+					rb->rb_right = NULL;
+			}
+
+			destroy_sv(sv);
+		}
+	}
+
+	kfree(si);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_si - check if the scanning information is correct and
+ * consistent.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero if the scanning information is all right, %1 if
+ * not and a negative error code if an error occurred.
+ */
+static int paranoid_check_si(const struct ubi_device *ubi,
+			     struct ubi_scan_info *si)
+{
+	int pnum, err, vols_found = 0;
+	struct rb_node *rb1, *rb2;
+	struct ubi_scan_volume *sv;
+	struct ubi_scan_leb *seb, *last_seb;
+	uint8_t *buf;
+
+	/*
+	 * At first, check that scanning information is ok.
+	 */
+	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+		int leb_count = 0;
+
+		cond_resched();
+
+		vols_found += 1;
+
+		if (si->is_empty) {
+			ubi_err("bad is_empty flag");
+			goto bad_sv;
+		}
+
+		if (sv->vol_id < 0 || sv->highest_lnum < 0 ||
+		    sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 ||
+		    sv->data_pad < 0 || sv->last_data_size < 0) {
+			ubi_err("negative values");
+			goto bad_sv;
+		}
+
+		if (sv->vol_id >= UBI_MAX_VOLUMES &&
+		    sv->vol_id < UBI_INTERNAL_VOL_START) {
+			ubi_err("bad vol_id");
+			goto bad_sv;
+		}
+
+		if (sv->vol_id > si->highest_vol_id) {
+			ubi_err("highest_vol_id is %d, but vol_id %d is there",
+				si->highest_vol_id, sv->vol_id);
+			goto out;
+		}
+
+		if (sv->vol_type != UBI_DYNAMIC_VOLUME &&
+		    sv->vol_type != UBI_STATIC_VOLUME) {
+			ubi_err("bad vol_type");
+			goto bad_sv;
+		}
+
+		if (sv->data_pad > ubi->leb_size / 2) {
+			ubi_err("bad data_pad");
+			goto bad_sv;
+		}
+
+		last_seb = NULL;
+		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+			cond_resched();
+
+			last_seb = seb;
+			leb_count += 1;
+
+			if (seb->pnum < 0 || seb->ec < 0) {
+				ubi_err("negative values");
+				goto bad_seb;
+			}
+
+			if (seb->ec < si->min_ec) {
+				ubi_err("bad si->min_ec (%d), %d found",
+					si->min_ec, seb->ec);
+				goto bad_seb;
+			}
+
+			if (seb->ec > si->max_ec) {
+				ubi_err("bad si->max_ec (%d), %d found",
+					si->max_ec, seb->ec);
+				goto bad_seb;
+			}
+
+			if (seb->pnum >= ubi->peb_count) {
+				ubi_err("too high PEB number %d, total PEBs %d",
+					seb->pnum, ubi->peb_count);
+				goto bad_seb;
+			}
+
+			if (sv->vol_type == UBI_STATIC_VOLUME) {
+				if (seb->lnum >= sv->used_ebs) {
+					ubi_err("bad lnum or used_ebs");
+					goto bad_seb;
+				}
+			} else {
+				if (sv->used_ebs != 0) {
+					ubi_err("non-zero used_ebs");
+					goto bad_seb;
+				}
+			}
+
+			if (seb->lnum > sv->highest_lnum) {
+				ubi_err("incorrect highest_lnum or lnum");
+				goto bad_seb;
+			}
+		}
+
+		if (sv->leb_count != leb_count) {
+			ubi_err("bad leb_count, %d objects in the tree",
+				leb_count);
+			goto bad_sv;
+		}
+
+		if (!last_seb)
+			continue;
+
+		seb = last_seb;
+
+		if (seb->lnum != sv->highest_lnum) {
+			ubi_err("bad highest_lnum");
+			goto bad_seb;
+		}
+	}
+
+	if (vols_found != si->vols_found) {
+		ubi_err("bad si->vols_found %d, should be %d",
+			si->vols_found, vols_found);
+		goto out;
+	}
+
+	/* Check that scanning information is correct */
+	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+		last_seb = NULL;
+		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+			int vol_type;
+
+			cond_resched();
+
+			last_seb = seb;
+
+			err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1);
+			if (err && err != UBI_IO_BITFLIPS) {
+				ubi_err("VID header is not OK (%d)", err);
+				if (err > 0)
+					err = -EIO;
+				return err;
+			}
+
+			vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
+				   UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
+			if (sv->vol_type != vol_type) {
+				ubi_err("bad vol_type");
+				goto bad_vid_hdr;
+			}
+
+			if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+				ubi_err("bad sqnum %llu", seb->sqnum);
+				goto bad_vid_hdr;
+			}
+
+			if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+				ubi_err("bad vol_id %d", sv->vol_id);
+				goto bad_vid_hdr;
+			}
+
+			if (sv->compat != vidh->compat) {
+				ubi_err("bad compat %d", vidh->compat);
+				goto bad_vid_hdr;
+			}
+
+			if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+				ubi_err("bad lnum %d", seb->lnum);
+				goto bad_vid_hdr;
+			}
+
+			if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+				ubi_err("bad used_ebs %d", sv->used_ebs);
+				goto bad_vid_hdr;
+			}
+
+			if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+				ubi_err("bad data_pad %d", sv->data_pad);
+				goto bad_vid_hdr;
+			}
+
+			if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+				ubi_err("bad leb_ver %u", seb->leb_ver);
+				goto bad_vid_hdr;
+			}
+		}
+
+		if (!last_seb)
+			continue;
+
+		if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+			ubi_err("bad highest_lnum %d", sv->highest_lnum);
+			goto bad_vid_hdr;
+		}
+
+		if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+			ubi_err("bad last_data_size %d", sv->last_data_size);
+			goto bad_vid_hdr;
+		}
+	}
+
+	/*
+	 * Make sure that all the physical eraseblocks are in one of the lists
+	 * or trees.
+	 */
+	buf = kmalloc(ubi->peb_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memset(buf, 1, ubi->peb_count);
+	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
+		err = ubi_io_is_bad(ubi, pnum);
+		if (err < 0)
+			return err;
+		else if (err)
+			buf[pnum] = 0;
+	}
+
+	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
+		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
+			buf[seb->pnum] = 0;
+
+	list_for_each_entry(seb, &si->free, u.list)
+		buf[seb->pnum] = 0;
+
+	list_for_each_entry(seb, &si->corr, u.list)
+		buf[seb->pnum] = 0;
+
+	list_for_each_entry(seb, &si->erase, u.list)
+		buf[seb->pnum] = 0;
+
+	list_for_each_entry(seb, &si->alien, u.list)
+		buf[seb->pnum] = 0;
+
+	err = 0;
+	for (pnum = 0; pnum < ubi->peb_count; pnum++)
+		if (buf[pnum]) {
+			ubi_err("PEB %d is not referred", pnum);
+			err = 1;
+		}
+
+	kfree(buf);
+	if (err)
+		goto out;
+	return 0;
+
+bad_seb:
+	ubi_err("bad scanning information about LEB %d", seb->lnum);
+	ubi_dbg_dump_seb(seb, 0);
+	ubi_dbg_dump_sv(sv);
+	goto out;
+
+bad_sv:
+	ubi_err("bad scanning information about volume %d", sv->vol_id);
+	ubi_dbg_dump_sv(sv);
+	goto out;
+
+bad_vid_hdr:
+	ubi_err("bad scanning information about volume %d", sv->vol_id);
+	ubi_dbg_dump_sv(sv);
+	ubi_dbg_dump_vid_hdr(vidh);
+
+out:
+	ubi_dbg_dump_stack();
+	return 1;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
new file mode 100644
index 0000000..3949f61
--- /dev/null
+++ b/drivers/mtd/ubi/scan.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+#ifndef __UBI_SCAN_H__
+#define __UBI_SCAN_H__
+
+/* The erase counter value for this physical eraseblock is unknown */
+#define UBI_SCAN_UNKNOWN_EC (-1)
+
+/**
+ * struct ubi_scan_leb - scanning information about a physical eraseblock.
+ * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ * @pnum: physical eraseblock number
+ * @lnum: logical eraseblock number
+ * @scrub: if this physical eraseblock needs scrubbing
+ * @sqnum: sequence number
+ * @u: unions RB-tree or @list links
+ * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
+ * @u.list: link in one of the eraseblock lists
+ * @leb_ver: logical eraseblock version (obsolete)
+ *
+ * One object of this type is allocated for each physical eraseblock during
+ * scanning.
+ */
+struct ubi_scan_leb {
+	int ec;
+	int pnum;
+	int lnum;
+	int scrub;
+	unsigned long long sqnum;
+	union {
+		struct rb_node rb;
+		struct list_head list;
+	} u;
+	uint32_t leb_ver;
+};
+
+/**
+ * struct ubi_scan_volume - scanning information about a volume.
+ * @vol_id: volume ID
+ * @highest_lnum: highest logical eraseblock number in this volume
+ * @leb_count: number of logical eraseblocks in this volume
+ * @vol_type: volume type
+ * @used_ebs: number of used logical eraseblocks in this volume (only for
+ * static volumes)
+ * @last_data_size: amount of data in the last logical eraseblock of this
+ * volume (always equivalent to the usable logical eraseblock size in case of
+ * dynamic volumes)
+ * @data_pad: how many bytes at the end of logical eraseblocks of this volume
+ * are not used (due to volume alignment)
+ * @compat: compatibility flags of this volume
+ * @rb: link in the volume RB-tree
+ * @root: root of the RB-tree containing all the eraseblock belonging to this
+ * volume (&struct ubi_scan_leb objects)
+ *
+ * One object of this type is allocated for each volume during scanning.
+ */
+struct ubi_scan_volume {
+	int vol_id;
+	int highest_lnum;
+	int leb_count;
+	int vol_type;
+	int used_ebs;
+	int last_data_size;
+	int data_pad;
+	int compat;
+	struct rb_node rb;
+	struct rb_root root;
+};
+
+/**
+ * struct ubi_scan_info - UBI scanning information.
+ * @volumes: root of the volume RB-tree
+ * @corr: list of corrupted physical eraseblocks
+ * @free: list of free physical eraseblocks
+ * @erase: list of physical eraseblocks which have to be erased
+ * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
+ * @bad_peb_count: count of bad physical eraseblocks
+ * those belonging to "preserve"-compatible internal volumes)
+ * @vols_found: number of volumes found during scanning
+ * @highest_vol_id: highest volume ID
+ * @alien_peb_count: count of physical eraseblocks in the @alien list
+ * @is_empty: flag indicating whether the MTD device is empty or not
+ * @min_ec: lowest erase counter value
+ * @max_ec: highest erase counter value
+ * @max_sqnum: highest sequence number value
+ * @mean_ec: mean erase counter value
+ * @ec_sum: a temporary variable used when calculating @mean_ec
+ * @ec_count: a temporary variable used when calculating @mean_ec
+ *
+ * This data structure contains the result of scanning and may be used by other
+ * UBI units to build final UBI data structures, further error-recovery and so
+ * on.
+ */
+struct ubi_scan_info {
+	struct rb_root volumes;
+	struct list_head corr;
+	struct list_head free;
+	struct list_head erase;
+	struct list_head alien;
+	int bad_peb_count;
+	int vols_found;
+	int highest_vol_id;
+	int alien_peb_count;
+	int is_empty;
+	int min_ec;
+	int max_ec;
+	unsigned long long max_sqnum;
+	int mean_ec;
+	int ec_sum;
+	int ec_count;
+};
+
+struct ubi_device;
+struct ubi_vid_hdr;
+
+/*
+ * ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a
+ * list.
+ *
+ * @sv: volume scanning information
+ * @seb: scanning eraseblock infprmation
+ * @list: the list to move to
+ */
+static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
+					 struct ubi_scan_leb *seb,
+					 struct list_head *list)
+{
+		rb_erase(&seb->u.rb, &sv->root);
+		list_add_tail(&seb->u.list, list);
+}
+
+int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+			 struct list_head *list);
+int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
+		      int bitflips);
+struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
+					 int vol_id);
+struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
+				       int lnum);
+void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
+struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+					   struct ubi_scan_info *si);
+int ubi_scan_erase_peb(const struct ubi_device *ubi,
+		       const struct ubi_scan_info *si, int pnum, int ec);
+struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
+void ubi_scan_destroy_si(struct ubi_scan_info *si);
+
+#endif /* !__UBI_SCAN_H__ */
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
new file mode 100644
index 0000000..feb647f
--- /dev/null
+++ b/drivers/mtd/ubi/ubi.h
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+#ifndef __UBI_UBI_H__
+#define __UBI_UBI_H__
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+
+#include <mtd/ubi-header.h>
+#include <linux/mtd/ubi.h>
+
+#include "scan.h"
+#include "debug.h"
+
+/* Maximum number of supported UBI devices */
+#define UBI_MAX_DEVICES 32
+
+/* UBI name used for character devices, sysfs, etc */
+#define UBI_NAME_STR "ubi"
+
+/* Normal UBI messages */
+#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__)
+/* UBI warning messages */
+#define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \
+				  __FUNCTION__, ##__VA_ARGS__)
+/* UBI error messages */
+#define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \
+				 __FUNCTION__, ##__VA_ARGS__)
+
+/* Lowest number PEBs reserved for bad PEB handling */
+#define MIN_RESEVED_PEBS 2
+
+/* Background thread name pattern */
+#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
+
+/* This marker in the EBA table means that the LEB is um-mapped */
+#define UBI_LEB_UNMAPPED -1
+
+/*
+ * In case of errors, UBI tries to repeat the operation several times before
+ * returning error. The below constant defines how many times UBI re-tries.
+ */
+#define UBI_IO_RETRIES 3
+
+/*
+ * Error codes returned by the I/O unit.
+ *
+ * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only
+ * 0xFF bytes
+ * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
+ * valid erase counter header, and the rest are %0xFF bytes
+ * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
+ * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
+ * CRC)
+ * UBI_IO_BITFLIPS: bit-flips were detected and corrected
+ */
+enum {
+	UBI_IO_PEB_EMPTY = 1,
+	UBI_IO_PEB_FREE,
+	UBI_IO_BAD_EC_HDR,
+	UBI_IO_BAD_VID_HDR,
+	UBI_IO_BITFLIPS
+};
+
+extern int ubi_devices_cnt;
+extern struct ubi_device *ubi_devices[];
+
+struct ubi_volume_desc;
+
+/**
+ * struct ubi_volume - UBI volume description data structure.
+ * @dev: device object to make use of the the Linux device model
+ * @cdev: character device object to create character device
+ * @ubi: reference to the UBI device description object
+ * @vol_id: volume ID
+ * @readers: number of users holding this volume in read-only mode
+ * @writers: number of users holding this volume in read-write mode
+ * @exclusive: whether somebody holds this volume in exclusive mode
+ * @removed: if the volume was removed
+ * @checked: if this static volume was checked
+ *
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @usable_leb_size: logical eraseblock size without padding
+ * @used_ebs: how many logical eraseblocks in this volume contain data
+ * @last_eb_bytes: how many bytes are stored in the last logical eraseblock
+ * @used_bytes: how many bytes of data this volume contains
+ * @upd_marker: non-zero if the update marker is set for this volume
+ * @corrupted: non-zero if the volume is corrupted (static volumes only)
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are not used at the end of physical eraseblocks to
+ * satisfy the requested alignment
+ * @name_len: volume name length
+ * @name: volume name
+ *
+ * @updating: whether the volume is being updated
+ * @upd_ebs: how many eraseblocks are expected to be updated
+ * @upd_bytes: how many bytes are expected to be received
+ * @upd_received: how many update bytes were already received
+ * @upd_buf: update buffer which is used to collect update data
+ *
+ * @eba_tbl: EBA table of this volume (LEB->PEB mapping)
+ *
+ * @gluebi_desc: gluebi UBI volume descriptor
+ * @gluebi_refcount: reference count of the gluebi MTD device
+ * @gluebi_mtd: MTD device description object of the gluebi MTD device
+ *
+ * The @corrupted field indicates that the volume's contents is corrupted.
+ * Since UBI protects only static volumes, this field is not relevant to
+ * dynamic volumes - it is user's responsibility to assure their data
+ * integrity.
+ *
+ * The @upd_marker flag indicates that this volume is either being updated at
+ * the moment or is damaged because of an unclean reboot.
+ */
+struct ubi_volume {
+	struct device dev;
+	struct cdev cdev;
+	struct ubi_device *ubi;
+	int vol_id;
+	int readers;
+	int writers;
+	int exclusive;
+	int removed;
+	int checked;
+
+	int reserved_pebs;
+	int vol_type;
+	int usable_leb_size;
+	int used_ebs;
+	int last_eb_bytes;
+	long long used_bytes;
+	int upd_marker;
+	int corrupted;
+	int alignment;
+	int data_pad;
+	int name_len;
+	char name[UBI_VOL_NAME_MAX+1];
+
+	int updating;
+	int upd_ebs;
+	long long upd_bytes;
+	long long upd_received;
+	void *upd_buf;
+
+	int *eba_tbl;
+
+#ifdef CONFIG_MTD_UBI_GLUEBI
+	/* Gluebi-related stuff may be compiled out */
+	struct ubi_volume_desc *gluebi_desc;
+	int gluebi_refcount;
+	struct mtd_info gluebi_mtd;
+#endif
+};
+
+/**
+ * struct ubi_volume_desc - descriptor of the UBI volume returned when it is
+ * opened.
+ * @vol: reference to the corresponding volume description object
+ * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
+ */
+struct ubi_volume_desc {
+	struct ubi_volume *vol;
+	int mode;
+};
+
+struct ubi_wl_entry;
+
+/**
+ * struct ubi_device - UBI device description structure
+ * @dev: class device object to use the the Linux device model
+ * @cdev: character device object to create character device
+ * @ubi_num: UBI device number
+ * @ubi_name: UBI device name
+ * @major: character device major number
+ * @vol_count: number of volumes in this UBI device
+ * @volumes: volumes of this UBI device
+ * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
+ * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers,
+ * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and
+ * @vol->eba_tbl.
+ *
+ * @rsvd_pebs: count of reserved physical eraseblocks
+ * @avail_pebs: count of available physical eraseblocks
+ * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB
+ * handling
+ * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling
+ *
+ * @vtbl_slots: how many slots are available in the volume table
+ * @vtbl_size: size of the volume table in bytes
+ * @vtbl: in-RAM volume table copy
+ *
+ * @max_ec: current highest erase counter value
+ * @mean_ec: current mean erase counter value
+ *
+ * global_sqnum: global sequence number
+ * @ltree_lock: protects the lock tree and @global_sqnum
+ * @ltree: the lock tree
+ * @vtbl_mutex: protects on-flash volume table
+ *
+ * @used: RB-tree of used physical eraseblocks
+ * @free: RB-tree of free physical eraseblocks
+ * @scrub: RB-tree of physical eraseblocks which need scrubbing
+ * @prot: protection trees
+ * @prot.pnum: protection tree indexed by physical eraseblock numbers
+ * @prot.aec: protection tree indexed by absolute erase counter value
+ * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from,
+ * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works
+ * fields
+ * @wl_scheduled: non-zero if the wear-leveling was scheduled
+ * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any
+ * physical eraseblock
+ * @abs_ec: absolute erase counter
+ * @move_from: physical eraseblock from where the data is being moved
+ * @move_to: physical eraseblock where the data is being moved to
+ * @move_from_put: if the "from" PEB was put
+ * @move_to_put: if the "to" PEB was put
+ * @works: list of pending works
+ * @works_count: count of pending works
+ * @bgt_thread: background thread description object
+ * @thread_enabled: if the background thread is enabled
+ * @bgt_name: background thread name
+ *
+ * @flash_size: underlying MTD device size (in bytes)
+ * @peb_count: count of physical eraseblocks on the MTD device
+ * @peb_size: physical eraseblock size
+ * @bad_peb_count: count of bad physical eraseblocks
+ * @good_peb_count: count of good physical eraseblocks
+ * @min_io_size: minimal input/output unit size of the underlying MTD device
+ * @hdrs_min_io_size: minimal I/O unit size used for VID and EC headers
+ * @ro_mode: if the UBI device is in read-only mode
+ * @leb_size: logical eraseblock size
+ * @leb_start: starting offset of logical eraseblocks within physical
+ * eraseblocks
+ * @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size
+ * @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size
+ * @vid_hdr_offset: starting offset of the volume identifier header (might be
+ * unaligned)
+ * @vid_hdr_aloffset: starting offset of the VID header aligned to
+ * @hdrs_min_io_size
+ * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
+ * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
+ * not
+ * @mtd: MTD device descriptor
+ */
+struct ubi_device {
+	struct cdev cdev;
+	struct device dev;
+	int ubi_num;
+	char ubi_name[sizeof(UBI_NAME_STR)+5];
+	int major;
+	int vol_count;
+	struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];
+	spinlock_t volumes_lock;
+
+	int rsvd_pebs;
+	int avail_pebs;
+	int beb_rsvd_pebs;
+	int beb_rsvd_level;
+
+	int vtbl_slots;
+	int vtbl_size;
+	struct ubi_vtbl_record *vtbl;
+	struct mutex vtbl_mutex;
+
+	int max_ec;
+	int mean_ec;
+
+	/* EBA unit's stuff */
+	unsigned long long global_sqnum;
+	spinlock_t ltree_lock;
+	struct rb_root ltree;
+
+	/* Wear-leveling unit's stuff */
+	struct rb_root used;
+	struct rb_root free;
+	struct rb_root scrub;
+	struct {
+		struct rb_root pnum;
+		struct rb_root aec;
+	} prot;
+	spinlock_t wl_lock;
+	int wl_scheduled;
+	struct ubi_wl_entry **lookuptbl;
+	unsigned long long abs_ec;
+	struct ubi_wl_entry *move_from;
+	struct ubi_wl_entry *move_to;
+	int move_from_put;
+	int move_to_put;
+	struct list_head works;
+	int works_count;
+	struct task_struct *bgt_thread;
+	int thread_enabled;
+	char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2];
+
+	/* I/O unit's stuff */
+	long long flash_size;
+	int peb_count;
+	int peb_size;
+	int bad_peb_count;
+	int good_peb_count;
+	int min_io_size;
+	int hdrs_min_io_size;
+	int ro_mode;
+	int leb_size;
+	int leb_start;
+	int ec_hdr_alsize;
+	int vid_hdr_alsize;
+	int vid_hdr_offset;
+	int vid_hdr_aloffset;
+	int vid_hdr_shift;
+	int bad_allowed;
+	struct mtd_info *mtd;
+};
+
+extern struct file_operations ubi_cdev_operations;
+extern struct file_operations ubi_vol_cdev_operations;
+extern struct class *ubi_class;
+
+/* vtbl.c */
+int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
+			   struct ubi_vtbl_record *vtbl_rec);
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
+
+/* vmt.c */
+int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
+int ubi_remove_volume(struct ubi_volume_desc *desc);
+int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs);
+int ubi_add_volume(struct ubi_device *ubi, int vol_id);
+void ubi_free_volume(struct ubi_device *ubi, int vol_id);
+
+/* upd.c */
+int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes);
+int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
+			 const void __user *buf, int count);
+
+/* misc.c */
+int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length);
+int ubi_check_volume(struct ubi_device *ubi, int vol_id);
+void ubi_calculate_reserved(struct ubi_device *ubi);
+
+/* gluebi.c */
+#ifdef CONFIG_MTD_UBI_GLUEBI
+int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
+int ubi_destroy_gluebi(struct ubi_volume *vol);
+#else
+#define ubi_create_gluebi(ubi, vol) 0
+#define ubi_destroy_gluebi(vol) 0
+#endif
+
+/* eba.c */
+int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum);
+int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
+		     int offset, int len, int check);
+int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
+		      const void *buf, int offset, int len, int dtype);
+int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
+			 const void *buf, int len, int dtype,
+			 int used_ebs);
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
+			      const void *buf, int len, int dtype);
+int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+		     struct ubi_vid_hdr *vid_hdr);
+int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+void ubi_eba_close(const struct ubi_device *ubi);
+
+/* wl.c */
+int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
+int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture);
+int ubi_wl_flush(struct ubi_device *ubi);
+int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
+int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+void ubi_wl_close(struct ubi_device *ubi);
+
+/* io.c */
+int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
+		int len);
+int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
+		 int offset, int len);
+int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
+int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
+int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+		       struct ubi_ec_hdr *ec_hdr, int verbose);
+int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+			struct ubi_ec_hdr *ec_hdr);
+int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+			struct ubi_vid_hdr *vid_hdr, int verbose);
+int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+			 struct ubi_vid_hdr *vid_hdr);
+
+/*
+ * ubi_rb_for_each_entry - walk an RB-tree.
+ * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
+ * @pos: a pointer to RB-tree entry type to use as a loop counter
+ * @root: RB-tree's root
+ * @member: the name of the 'struct rb_node' within the RB-tree entry
+ */
+#define ubi_rb_for_each_entry(rb, pos, root, member)                         \
+	for (rb = rb_first(root),                                            \
+	     pos = (rb ? container_of(rb, typeof(*pos), member) : NULL);     \
+	     rb;                                                             \
+	     rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
+
+/**
+ * ubi_zalloc_vid_hdr - allocate a volume identifier header object.
+ * @ubi: UBI device description object
+ *
+ * This function returns a pointer to the newly allocated and zero-filled
+ * volume identifier header object in case of success and %NULL in case of
+ * failure.
+ */
+static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi)
+{
+	void *vid_hdr;
+
+	vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL);
+	if (!vid_hdr)
+		return NULL;
+
+	/*
+	 * VID headers may be stored at un-aligned flash offsets, so we shift
+	 * the pointer.
+	 */
+	return vid_hdr + ubi->vid_hdr_shift;
+}
+
+/**
+ * ubi_free_vid_hdr - free a volume identifier header object.
+ * @ubi: UBI device description object
+ * @vid_hdr: the object to free
+ */
+static inline void ubi_free_vid_hdr(const struct ubi_device *ubi,
+				    struct ubi_vid_hdr *vid_hdr)
+{
+	void *p = vid_hdr;
+
+	if (!p)
+		return;
+
+	kfree(p - ubi->vid_hdr_shift);
+}
+
+/*
+ * This function is equivalent to 'ubi_io_read()', but @offset is relative to
+ * the beginning of the logical eraseblock, not to the beginning of the
+ * physical eraseblock.
+ */
+static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
+				   int pnum, int offset, int len)
+{
+	ubi_assert(offset >= 0);
+	return ubi_io_read(ubi, buf, pnum, offset + ubi->leb_start, len);
+}
+
+/*
+ * This function is equivalent to 'ubi_io_write()', but @offset is relative to
+ * the beginning of the logical eraseblock, not to the beginning of the
+ * physical eraseblock.
+ */
+static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf,
+				    int pnum, int offset, int len)
+{
+	ubi_assert(offset >= 0);
+	return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len);
+}
+
+/**
+ * ubi_ro_mode - switch to read-only mode.
+ * @ubi: UBI device description object
+ */
+static inline void ubi_ro_mode(struct ubi_device *ubi)
+{
+	ubi->ro_mode = 1;
+	ubi_warn("switch to read-only mode");
+}
+
+/**
+ * vol_id2idx - get table index by volume ID.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ */
+static inline int vol_id2idx(const struct ubi_device *ubi, int vol_id)
+{
+	if (vol_id >= UBI_INTERNAL_VOL_START)
+		return vol_id - UBI_INTERNAL_VOL_START + ubi->vtbl_slots;
+	else
+		return vol_id;
+}
+
+/**
+ * idx2vol_id - get volume ID by table index.
+ * @ubi: UBI device description object
+ * @idx: table index
+ */
+static inline int idx2vol_id(const struct ubi_device *ubi, int idx)
+{
+	if (idx >= ubi->vtbl_slots)
+		return idx - ubi->vtbl_slots + UBI_INTERNAL_VOL_START;
+	else
+		return idx;
+}
+
+#endif /* !__UBI_UBI_H__ */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
new file mode 100644
index 0000000..8925b97
--- /dev/null
+++ b/drivers/mtd/ubi/upd.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ *
+ * Jan 2007: Alexander Schmidt, hacked per-volume update.
+ */
+
+/*
+ * This file contains implementation of the volume update functionality.
+ *
+ * The update operation is based on the per-volume update marker which is
+ * stored in the volume table. The update marker is set before the update
+ * starts, and removed after the update has been finished. So if the update was
+ * interrupted by an unclean re-boot or due to some other reasons, the update
+ * marker stays on the flash media and UBI finds it when it attaches the MTD
+ * device next time. If the update marker is set for a volume, the volume is
+ * treated as damaged and most I/O operations are prohibited. Only a new update
+ * operation is allowed.
+ *
+ * Note, in general it is possible to implement the update operation as a
+ * transaction with a roll-back capability.
+ */
+
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+#include "ubi.h"
+
+/**
+ * set_update_marker - set update marker.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ *
+ * This function sets the update marker flag for volume @vol_id. Returns zero
+ * in case of success and a negative error code in case of failure.
+ */
+static int set_update_marker(struct ubi_device *ubi, int vol_id)
+{
+	int err;
+	struct ubi_vtbl_record vtbl_rec;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	dbg_msg("set update marker for volume %d", vol_id);
+
+	if (vol->upd_marker) {
+		ubi_assert(ubi->vtbl[vol_id].upd_marker);
+		dbg_msg("already set");
+		return 0;
+	}
+
+	memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+	vtbl_rec.upd_marker = 1;
+
+	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+	vol->upd_marker = 1;
+	return err;
+}
+
+/**
+ * clear_update_marker - clear update marker.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @bytes: new data size in bytes
+ *
+ * This function clears the update marker for volume @vol_id, sets new volume
+ * data size and clears the "corrupted" flag (static volumes only). Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes)
+{
+	int err;
+	uint64_t tmp;
+	struct ubi_vtbl_record vtbl_rec;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	dbg_msg("clear update marker for volume %d", vol_id);
+
+	memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+	ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
+	vtbl_rec.upd_marker = 0;
+
+	if (vol->vol_type == UBI_STATIC_VOLUME) {
+		vol->corrupted = 0;
+		vol->used_bytes = tmp = bytes;
+		vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size);
+		vol->used_ebs = tmp;
+		if (vol->last_eb_bytes)
+			vol->used_ebs += 1;
+		else
+			vol->last_eb_bytes = vol->usable_leb_size;
+	}
+
+	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+	vol->upd_marker = 0;
+	return err;
+}
+
+/**
+ * ubi_start_update - start volume update.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @bytes: update bytes
+ *
+ * This function starts volume update operation. If @bytes is zero, the volume
+ * is just wiped out. Returns zero in case of success and a negative error code
+ * in case of failure.
+ */
+int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
+{
+	int i, err;
+	uint64_t tmp;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes);
+	vol->updating = 1;
+
+	err = set_update_marker(ubi, vol_id);
+	if (err)
+		return err;
+
+	/* Before updating - wipe out the volume */
+	for (i = 0; i < vol->reserved_pebs; i++) {
+		err = ubi_eba_unmap_leb(ubi, vol_id, i);
+		if (err)
+			return err;
+	}
+
+	if (bytes == 0) {
+		err = clear_update_marker(ubi, vol_id, 0);
+		if (err)
+			return err;
+		err = ubi_wl_flush(ubi);
+		if (!err)
+			vol->updating = 0;
+	}
+
+	vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+	if (!vol->upd_buf)
+		return -ENOMEM;
+
+	tmp = bytes;
+	vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size);
+	vol->upd_ebs += tmp;
+	vol->upd_bytes = bytes;
+	vol->upd_received = 0;
+	return 0;
+}
+
+/**
+ * write_leb - write update data.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ * @buf: data to write
+ * @len: data size
+ * @used_ebs: how many logical eraseblocks will this volume contain (static
+ * volumes only)
+ *
+ * This function writes update data to corresponding logical eraseblock. In
+ * case of dynamic volume, this function checks if the data contains 0xFF bytes
+ * at the end. If yes, the 0xFF bytes are cut and not written. So if the whole
+ * buffer contains only 0xFF bytes, the LEB is left unmapped.
+ *
+ * The reason why we skip the trailing 0xFF bytes in case of dynamic volume is
+ * that we want to make sure that more data may be appended to the logical
+ * eraseblock in future. Indeed, writing 0xFF bytes may have side effects and
+ * this PEB won't be writable anymore. So if one writes the file-system image
+ * to the UBI volume where 0xFFs mean free space - UBI makes sure this free
+ * space is writable after the update.
+ *
+ * We do not do this for static volumes because they are read-only. But this
+ * also cannot be done because we have to store per-LEB CRC and the correct
+ * data length.
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
+		     int len, int used_ebs)
+{
+	int err, l;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+		l = ALIGN(len, ubi->min_io_size);
+		memset(buf + len, 0xFF, l - len);
+
+		l = ubi_calc_data_len(ubi, buf, l);
+		if (l == 0) {
+			dbg_msg("all %d bytes contain 0xFF - skip", len);
+			return 0;
+		}
+		if (len != l)
+			dbg_msg("skip last %d bytes (0xFF)", len - l);
+
+		err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l,
+					UBI_UNKNOWN);
+	} else {
+		/*
+		 * When writing static volume, and this is the last logical
+		 * eraseblock, the length (@len) does not have to be aligned to
+		 * the minimal flash I/O unit. The 'ubi_eba_write_leb_st()'
+		 * function accepts exact (unaligned) length and stores it in
+		 * the VID header. And it takes care of proper alignment by
+		 * padding the buffer. Here we just make sure the padding will
+		 * contain zeros, not random trash.
+		 */
+		memset(buf + len, 0, vol->usable_leb_size - len);
+		err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len,
+					   UBI_UNKNOWN, used_ebs);
+	}
+
+	return err;
+}
+
+/**
+ * ubi_more_update_data - write more update data.
+ * @vol: volume description object
+ * @buf: write data (user-space memory buffer)
+ * @count: how much bytes to write
+ *
+ * This function writes more data to the volume which is being updated. It may
+ * be called arbitrary number of times until all of the update data arrive.
+ * This function returns %0 in case of success, number of bytes written during
+ * the last call if the whole volume update was successfully finished, and a
+ * negative error code in case of failure.
+ */
+int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
+			 const void __user *buf, int count)
+{
+	uint64_t tmp;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+	int lnum, offs, err = 0, len, to_write = count;
+
+	dbg_msg("write %d of %lld bytes, %lld already passed",
+		count, vol->upd_bytes, vol->upd_received);
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	tmp = vol->upd_received;
+	offs = do_div(tmp, vol->usable_leb_size);
+	lnum = tmp;
+
+	if (vol->upd_received + count > vol->upd_bytes)
+		to_write = count = vol->upd_bytes - vol->upd_received;
+
+	/*
+	 * When updating volumes, we accumulate whole logical eraseblock of
+	 * data and write it at once.
+	 */
+	if (offs != 0) {
+		/*
+		 * This is a write to the middle of the logical eraseblock. We
+		 * copy the data to our update buffer and wait for more data or
+		 * flush it if the whole eraseblock is written or the update
+		 * is finished.
+		 */
+
+		len = vol->usable_leb_size - offs;
+		if (len > count)
+			len = count;
+
+		err = copy_from_user(vol->upd_buf + offs, buf, len);
+		if (err)
+			return -EFAULT;
+
+		if (offs + len == vol->usable_leb_size ||
+		    vol->upd_received + len == vol->upd_bytes) {
+			int flush_len = offs + len;
+
+			/*
+			 * OK, we gathered either the whole eraseblock or this
+			 * is the last chunk, it's time to flush the buffer.
+			 */
+			ubi_assert(flush_len <= vol->usable_leb_size);
+			err = write_leb(ubi, vol_id, lnum, vol->upd_buf,
+					flush_len, vol->upd_ebs);
+			if (err)
+				return err;
+		}
+
+		vol->upd_received += len;
+		count -= len;
+		buf += len;
+		lnum += 1;
+	}
+
+	/*
+	 * If we've got more to write, let's continue. At this point we know we
+	 * are starting from the beginning of an eraseblock.
+	 */
+	while (count) {
+		if (count > vol->usable_leb_size)
+			len = vol->usable_leb_size;
+		else
+			len = count;
+
+		err = copy_from_user(vol->upd_buf, buf, len);
+		if (err)
+			return -EFAULT;
+
+		if (len == vol->usable_leb_size ||
+		    vol->upd_received + len == vol->upd_bytes) {
+			err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len,
+					vol->upd_ebs);
+			if (err)
+				break;
+		}
+
+		vol->upd_received += len;
+		count -= len;
+		lnum += 1;
+		buf += len;
+	}
+
+	ubi_assert(vol->upd_received <= vol->upd_bytes);
+	if (vol->upd_received == vol->upd_bytes) {
+		/* The update is finished, clear the update marker */
+		err = clear_update_marker(ubi, vol_id, vol->upd_bytes);
+		if (err)
+			return err;
+		err = ubi_wl_flush(ubi);
+		if (err == 0) {
+			err = to_write;
+			kfree(vol->upd_buf);
+			vol->updating = 0;
+		}
+	}
+
+	return err;
+}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
new file mode 100644
index 0000000..622d0d1
--- /dev/null
+++ b/drivers/mtd/ubi/vmt.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * This file contains implementation of volume creation, deletion, updating and
+ * resizing.
+ */
+
+#include <linux/err.h>
+#include <asm/div64.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static void paranoid_check_volumes(struct ubi_device *ubi);
+#else
+#define paranoid_check_volumes(ubi)
+#endif
+
+static ssize_t vol_attribute_show(struct device *dev,
+				  struct device_attribute *attr, char *buf);
+
+/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
+static struct device_attribute vol_reserved_ebs =
+	__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_type =
+	__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_name =
+	__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_corrupted =
+	__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_alignment =
+	__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_usable_eb_size =
+	__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_data_bytes =
+	__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
+static struct device_attribute vol_upd_marker =
+	__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
+
+/*
+ * "Show" method for files in '/<sysfs>/class/ubi/ubiX_Y/'.
+ *
+ * Consider a situation:
+ * A. process 1 opens a sysfs file related to volume Y, say
+ *    /<sysfs>/class/ubi/ubiX_Y/reserved_ebs;
+ * B. process 2 removes volume Y;
+ * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file;
+ *
+ * What we want to do in a situation like that is to return error when the file
+ * is read. This is done by means of the 'removed' flag and the 'vol_lock' of
+ * the UBI volume description object.
+ */
+static ssize_t vol_attribute_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	int ret;
+	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
+
+	spin_lock(&vol->ubi->volumes_lock);
+	if (vol->removed) {
+		spin_unlock(&vol->ubi->volumes_lock);
+		return -ENODEV;
+	}
+	if (attr == &vol_reserved_ebs)
+		ret = sprintf(buf, "%d\n", vol->reserved_pebs);
+	else if (attr == &vol_type) {
+		const char *tp;
+		tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static";
+		ret = sprintf(buf, "%s\n", tp);
+	} else if (attr == &vol_name)
+		ret = sprintf(buf, "%s\n", vol->name);
+	else if (attr == &vol_corrupted)
+		ret = sprintf(buf, "%d\n", vol->corrupted);
+	else if (attr == &vol_alignment)
+		ret = sprintf(buf, "%d\n", vol->alignment);
+	else if (attr == &vol_usable_eb_size) {
+		ret = sprintf(buf, "%d\n", vol->usable_leb_size);
+	} else if (attr == &vol_data_bytes)
+		ret = sprintf(buf, "%lld\n", vol->used_bytes);
+	else if (attr == &vol_upd_marker)
+		ret = sprintf(buf, "%d\n", vol->upd_marker);
+	else
+		BUG();
+	spin_unlock(&vol->ubi->volumes_lock);
+	return ret;
+}
+
+/* Release method for volume devices */
+static void vol_release(struct device *dev)
+{
+	struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev);
+	ubi_assert(vol->removed);
+	kfree(vol);
+}
+
+/**
+ * volume_sysfs_init - initialize sysfs for new volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ *
+ * Note, this function does not free allocated resources in case of failure -
+ * the caller does it. This is because this would cause release() here and the
+ * caller would oops.
+ */
+static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
+{
+	int err;
+
+	err = device_create_file(&vol->dev, &vol_reserved_ebs);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_type);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_name);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_corrupted);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_alignment);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_usable_eb_size);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_data_bytes);
+	if (err)
+		return err;
+	err = device_create_file(&vol->dev, &vol_upd_marker);
+	if (err)
+		return err;
+	return 0;
+}
+
+/**
+ * volume_sysfs_close - close sysfs for a volume.
+ * @vol: volume description object
+ */
+static void volume_sysfs_close(struct ubi_volume *vol)
+{
+	device_remove_file(&vol->dev, &vol_upd_marker);
+	device_remove_file(&vol->dev, &vol_data_bytes);
+	device_remove_file(&vol->dev, &vol_usable_eb_size);
+	device_remove_file(&vol->dev, &vol_alignment);
+	device_remove_file(&vol->dev, &vol_corrupted);
+	device_remove_file(&vol->dev, &vol_name);
+	device_remove_file(&vol->dev, &vol_type);
+	device_remove_file(&vol->dev, &vol_reserved_ebs);
+	device_unregister(&vol->dev);
+}
+
+/**
+ * ubi_create_volume - create volume.
+ * @ubi: UBI device description object
+ * @req: volume creation request
+ *
+ * This function creates volume described by @req. If @req->vol_id id
+ * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume
+ * and saves it in @req->vol_id. Returns zero in case of success and a negative
+ * error code in case of failure.
+ */
+int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
+{
+	int i, err, vol_id = req->vol_id;
+	struct ubi_volume *vol;
+	struct ubi_vtbl_record vtbl_rec;
+	uint64_t bytes;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+	if (!vol)
+		return -ENOMEM;
+
+	spin_lock(&ubi->volumes_lock);
+
+	if (vol_id == UBI_VOL_NUM_AUTO) {
+		/* Find unused volume ID */
+		dbg_msg("search for vacant volume ID");
+		for (i = 0; i < ubi->vtbl_slots; i++)
+			if (!ubi->volumes[i]) {
+				vol_id = i;
+				break;
+			}
+
+		if (vol_id == UBI_VOL_NUM_AUTO) {
+			dbg_err("out of volume IDs");
+			err = -ENFILE;
+			goto out_unlock;
+		}
+		req->vol_id = vol_id;
+	}
+
+	dbg_msg("volume ID %d, %llu bytes, type %d, name %s",
+		vol_id, (unsigned long long)req->bytes,
+		(int)req->vol_type, req->name);
+
+	/* Ensure that this volume does not exist */
+	err = -EEXIST;
+	if (ubi->volumes[vol_id]) {
+		dbg_err("volume %d already exists", vol_id);
+		goto out_unlock;
+	}
+
+	/* Ensure that the name is unique */
+	for (i = 0; i < ubi->vtbl_slots; i++)
+		if (ubi->volumes[i] &&
+		    ubi->volumes[i]->name_len == req->name_len &&
+		    strcmp(ubi->volumes[i]->name, req->name) == 0) {
+			dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
+			goto out_unlock;
+		}
+
+        /* Calculate how many eraseblocks are requested */
+	vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;
+	bytes = req->bytes;
+	if (do_div(bytes, vol->usable_leb_size))
+		vol->reserved_pebs = 1;
+	vol->reserved_pebs += bytes;
+
+	/* Reserve physical eraseblocks */
+	if (vol->reserved_pebs > ubi->avail_pebs) {
+		dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
+		spin_unlock(&ubi->volumes_lock);
+		err = -ENOSPC;
+		goto out_unlock;
+	}
+	ubi->avail_pebs -= vol->reserved_pebs;
+	ubi->rsvd_pebs += vol->reserved_pebs;
+
+	vol->vol_id    = vol_id;
+	vol->alignment = req->alignment;
+	vol->data_pad  = ubi->leb_size % vol->alignment;
+	vol->vol_type  = req->vol_type;
+	vol->name_len  = req->name_len;
+	memcpy(vol->name, req->name, vol->name_len + 1);
+	vol->exclusive = 1;
+	vol->ubi = ubi;
+	ubi->volumes[vol_id] = vol;
+	spin_unlock(&ubi->volumes_lock);
+
+	/*
+	 * Finish all pending erases because there may be some LEBs belonging
+	 * to the same volume ID.
+	 */
+	err = ubi_wl_flush(ubi);
+	if (err)
+		goto out_acc;
+
+	vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);
+	if (!vol->eba_tbl) {
+		err = -ENOMEM;
+		goto out_acc;
+	}
+
+	for (i = 0; i < vol->reserved_pebs; i++)
+		vol->eba_tbl[i] = UBI_LEB_UNMAPPED;
+
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+		vol->used_ebs = vol->reserved_pebs;
+		vol->last_eb_bytes = vol->usable_leb_size;
+		vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+	} else {
+		bytes = vol->used_bytes;
+		vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
+		vol->used_ebs = bytes;
+		if (vol->last_eb_bytes)
+			vol->used_ebs += 1;
+		else
+			vol->last_eb_bytes = vol->usable_leb_size;
+	}
+
+	/* Register character device for the volume */
+	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
+	vol->cdev.owner = THIS_MODULE;
+	err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1);
+	if (err) {
+		ubi_err("cannot add character device for volume %d", vol_id);
+		goto out_mapping;
+	}
+
+	err = ubi_create_gluebi(ubi, vol);
+	if (err)
+		goto out_cdev;
+
+	vol->dev.release = vol_release;
+	vol->dev.parent = &ubi->dev;
+	vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1);
+	vol->dev.class = ubi_class;
+	sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
+	err = device_register(&vol->dev);
+	if (err)
+		goto out_gluebi;
+
+	err = volume_sysfs_init(ubi, vol);
+	if (err)
+		goto out_sysfs;
+
+	/* Fill volume table record */
+	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
+	vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
+	vtbl_rec.alignment     = cpu_to_ubi32(vol->alignment);
+	vtbl_rec.data_pad      = cpu_to_ubi32(vol->data_pad);
+	vtbl_rec.name_len      = cpu_to_ubi16(vol->name_len);
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+		vtbl_rec.vol_type = UBI_VID_DYNAMIC;
+	else
+		vtbl_rec.vol_type = UBI_VID_STATIC;
+	memcpy(vtbl_rec.name, vol->name, vol->name_len + 1);
+
+	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+	if (err)
+		goto out_sysfs;
+
+	spin_lock(&ubi->volumes_lock);
+	ubi->vol_count += 1;
+	vol->exclusive = 0;
+	spin_unlock(&ubi->volumes_lock);
+
+	paranoid_check_volumes(ubi);
+	return 0;
+
+out_gluebi:
+	err = ubi_destroy_gluebi(vol);
+out_cdev:
+	cdev_del(&vol->cdev);
+out_mapping:
+	kfree(vol->eba_tbl);
+out_acc:
+	spin_lock(&ubi->volumes_lock);
+	ubi->rsvd_pebs -= vol->reserved_pebs;
+	ubi->avail_pebs += vol->reserved_pebs;
+out_unlock:
+	spin_unlock(&ubi->volumes_lock);
+	kfree(vol);
+	return err;
+
+	/*
+	 * We are registered, so @vol is destroyed in the release function and
+	 * we have to de-initialize differently.
+	 */
+out_sysfs:
+	err = ubi_destroy_gluebi(vol);
+	cdev_del(&vol->cdev);
+	kfree(vol->eba_tbl);
+	spin_lock(&ubi->volumes_lock);
+	ubi->rsvd_pebs -= vol->reserved_pebs;
+	ubi->avail_pebs += vol->reserved_pebs;
+	spin_unlock(&ubi->volumes_lock);
+	volume_sysfs_close(vol);
+	return err;
+}
+
+/**
+ * ubi_remove_volume - remove volume.
+ * @desc: volume descriptor
+ *
+ * This function removes volume described by @desc. The volume has to be opened
+ * in "exclusive" mode. Returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_remove_volume(struct ubi_volume_desc *desc)
+{
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs;
+
+	dbg_msg("remove UBI volume %d", vol_id);
+	ubi_assert(desc->mode == UBI_EXCLUSIVE);
+	ubi_assert(vol == ubi->volumes[vol_id]);
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	err = ubi_destroy_gluebi(vol);
+	if (err)
+		return err;
+
+	err = ubi_change_vtbl_record(ubi, vol_id, NULL);
+	if (err)
+		return err;
+
+	for (i = 0; i < vol->reserved_pebs; i++) {
+		err = ubi_eba_unmap_leb(ubi, vol_id, i);
+		if (err)
+			return err;
+	}
+
+	spin_lock(&ubi->volumes_lock);
+	vol->removed = 1;
+	ubi->volumes[vol_id] = NULL;
+	spin_unlock(&ubi->volumes_lock);
+
+	kfree(vol->eba_tbl);
+	vol->eba_tbl = NULL;
+	cdev_del(&vol->cdev);
+	volume_sysfs_close(vol);
+	kfree(desc);
+
+	spin_lock(&ubi->volumes_lock);
+	ubi->rsvd_pebs -= reserved_pebs;
+	ubi->avail_pebs += reserved_pebs;
+	i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+	if (i > 0) {
+		i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
+		ubi->avail_pebs -= i;
+		ubi->rsvd_pebs += i;
+		ubi->beb_rsvd_pebs += i;
+		if (i > 0)
+			ubi_msg("reserve more %d PEBs", i);
+	}
+	ubi->vol_count -= 1;
+	spin_unlock(&ubi->volumes_lock);
+
+	paranoid_check_volumes(ubi);
+	module_put(THIS_MODULE);
+	return 0;
+}
+
+/**
+ * ubi_resize_volume - re-size volume.
+ * @desc: volume descriptor
+ * @reserved_pebs: new size in physical eraseblocks
+ *
+ * This function returns zero in case of success, and a negative error code in
+ * case of failure.
+ */
+int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
+{
+	int i, err, pebs, *new_mapping;
+	struct ubi_volume *vol = desc->vol;
+	struct ubi_device *ubi = vol->ubi;
+	struct ubi_vtbl_record vtbl_rec;
+	int vol_id = vol->vol_id;
+
+	if (ubi->ro_mode)
+		return -EROFS;
+
+	dbg_msg("re-size volume %d to from %d to %d PEBs",
+		vol_id, vol->reserved_pebs, reserved_pebs);
+	ubi_assert(desc->mode == UBI_EXCLUSIVE);
+	ubi_assert(vol == ubi->volumes[vol_id]);
+
+	if (vol->vol_type == UBI_STATIC_VOLUME &&
+	    reserved_pebs < vol->used_ebs) {
+		dbg_err("too small size %d, %d LEBs contain data",
+			reserved_pebs, vol->used_ebs);
+		return -EINVAL;
+	}
+
+	/* If the size is the same, we have nothing to do */
+	if (reserved_pebs == vol->reserved_pebs)
+		return 0;
+
+	new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL);
+	if (!new_mapping)
+		return -ENOMEM;
+
+	for (i = 0; i < reserved_pebs; i++)
+		new_mapping[i] = UBI_LEB_UNMAPPED;
+
+	/* Reserve physical eraseblocks */
+	pebs = reserved_pebs - vol->reserved_pebs;
+	if (pebs > 0) {
+		spin_lock(&ubi->volumes_lock);
+		if (pebs > ubi->avail_pebs) {
+			dbg_err("not enough PEBs: requested %d, available %d",
+				pebs, ubi->avail_pebs);
+			spin_unlock(&ubi->volumes_lock);
+			err = -ENOSPC;
+			goto out_free;
+		}
+		ubi->avail_pebs -= pebs;
+		ubi->rsvd_pebs += pebs;
+		for (i = 0; i < vol->reserved_pebs; i++)
+			new_mapping[i] = vol->eba_tbl[i];
+		kfree(vol->eba_tbl);
+		vol->eba_tbl = new_mapping;
+		spin_unlock(&ubi->volumes_lock);
+	}
+
+	/* Change volume table record */
+	memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+	vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
+	if (err)
+		goto out_acc;
+
+	if (pebs < 0) {
+		for (i = 0; i < -pebs; i++) {
+			err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i);
+			if (err)
+				goto out_acc;
+		}
+		spin_lock(&ubi->volumes_lock);
+		ubi->rsvd_pebs += pebs;
+		ubi->avail_pebs -= pebs;
+		pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+		if (pebs > 0) {
+			pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs;
+			ubi->avail_pebs -= pebs;
+			ubi->rsvd_pebs += pebs;
+			ubi->beb_rsvd_pebs += pebs;
+			if (pebs > 0)
+				ubi_msg("reserve more %d PEBs", pebs);
+		}
+		for (i = 0; i < reserved_pebs; i++)
+			new_mapping[i] = vol->eba_tbl[i];
+		kfree(vol->eba_tbl);
+		vol->eba_tbl = new_mapping;
+		spin_unlock(&ubi->volumes_lock);
+	}
+
+	vol->reserved_pebs = reserved_pebs;
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+		vol->used_ebs = reserved_pebs;
+		vol->last_eb_bytes = vol->usable_leb_size;
+		vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+	}
+
+	paranoid_check_volumes(ubi);
+	return 0;
+
+out_acc:
+	if (pebs > 0) {
+		spin_lock(&ubi->volumes_lock);
+		ubi->rsvd_pebs -= pebs;
+		ubi->avail_pebs += pebs;
+		spin_unlock(&ubi->volumes_lock);
+	}
+out_free:
+	kfree(new_mapping);
+	return err;
+}
+
+/**
+ * ubi_add_volume - add volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ *
+ * This function adds an existin volume and initializes all its data
+ * structures. Returnes zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_add_volume(struct ubi_device *ubi, int vol_id)
+{
+	int err;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	dbg_msg("add volume %d", vol_id);
+	ubi_dbg_dump_vol_info(vol);
+	ubi_assert(vol);
+
+	/* Register character device for the volume */
+	cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
+	vol->cdev.owner = THIS_MODULE;
+	err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1);
+	if (err) {
+		ubi_err("cannot add character device for volume %d", vol_id);
+		return err;
+	}
+
+	err = ubi_create_gluebi(ubi, vol);
+	if (err)
+		goto out_cdev;
+
+	vol->dev.release = vol_release;
+	vol->dev.parent = &ubi->dev;
+	vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1);
+	vol->dev.class = ubi_class;
+	sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);
+	err = device_register(&vol->dev);
+	if (err)
+		goto out_gluebi;
+
+	err = volume_sysfs_init(ubi, vol);
+	if (err) {
+		cdev_del(&vol->cdev);
+		err = ubi_destroy_gluebi(vol);
+		volume_sysfs_close(vol);
+		return err;
+	}
+
+	paranoid_check_volumes(ubi);
+	return 0;
+
+out_gluebi:
+	err = ubi_destroy_gluebi(vol);
+out_cdev:
+	cdev_del(&vol->cdev);
+	return err;
+}
+
+/**
+ * ubi_free_volume - free volume.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ *
+ * This function frees all resources for volume @vol_id but does not remove it.
+ * Used only when the UBI device is detached.
+ */
+void ubi_free_volume(struct ubi_device *ubi, int vol_id)
+{
+	int err;
+	struct ubi_volume *vol = ubi->volumes[vol_id];
+
+	dbg_msg("free volume %d", vol_id);
+	ubi_assert(vol);
+
+	vol->removed = 1;
+	err = ubi_destroy_gluebi(vol);
+	ubi->volumes[vol_id] = NULL;
+	cdev_del(&vol->cdev);
+	volume_sysfs_close(vol);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_volume - check volume information.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ */
+static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+{
+	int idx = vol_id2idx(ubi, vol_id);
+	int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
+	const struct ubi_volume *vol = ubi->volumes[idx];
+	long long n;
+	const char *name;
+
+	reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+
+	if (!vol) {
+		if (reserved_pebs) {
+			ubi_err("no volume info, but volume exists");
+			goto fail;
+		}
+		return;
+	}
+
+	if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 ||
+	    vol->name_len < 0) {
+		ubi_err("negative values");
+		goto fail;
+	}
+	if (vol->alignment > ubi->leb_size || vol->alignment == 0) {
+		ubi_err("bad alignment");
+		goto fail;
+	}
+
+	n = vol->alignment % ubi->min_io_size;
+	if (vol->alignment != 1 && n) {
+		ubi_err("alignment is not multiple of min I/O unit");
+		goto fail;
+	}
+
+	n = ubi->leb_size % vol->alignment;
+	if (vol->data_pad != n) {
+		ubi_err("bad data_pad, has to be %lld", n);
+		goto fail;
+	}
+
+	if (vol->vol_type != UBI_DYNAMIC_VOLUME &&
+	    vol->vol_type != UBI_STATIC_VOLUME) {
+		ubi_err("bad vol_type");
+		goto fail;
+	}
+
+	if (vol->upd_marker != 0 && vol->upd_marker != 1) {
+		ubi_err("bad upd_marker");
+		goto fail;
+	}
+
+	if (vol->upd_marker && vol->corrupted) {
+		dbg_err("update marker and corrupted simultaneously");
+		goto fail;
+	}
+
+	if (vol->reserved_pebs > ubi->good_peb_count) {
+		ubi_err("too large reserved_pebs");
+		goto fail;
+	}
+
+	n = ubi->leb_size - vol->data_pad;
+	if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) {
+		ubi_err("bad usable_leb_size, has to be %lld", n);
+		goto fail;
+	}
+
+	if (vol->name_len > UBI_VOL_NAME_MAX) {
+		ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX);
+		goto fail;
+	}
+
+	if (!vol->name) {
+		ubi_err("NULL volume name");
+		goto fail;
+	}
+
+	n = strnlen(vol->name, vol->name_len + 1);
+	if (n != vol->name_len) {
+		ubi_err("bad name_len %lld", n);
+		goto fail;
+	}
+
+	n = vol->used_ebs * vol->usable_leb_size;
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+		if (vol->corrupted != 0) {
+			ubi_err("corrupted dynamic volume");
+			goto fail;
+		}
+		if (vol->used_ebs != vol->reserved_pebs) {
+			ubi_err("bad used_ebs");
+			goto fail;
+		}
+		if (vol->last_eb_bytes != vol->usable_leb_size) {
+			ubi_err("bad last_eb_bytes");
+			goto fail;
+		}
+		if (vol->used_bytes != n) {
+			ubi_err("bad used_bytes");
+			goto fail;
+		}
+	} else {
+		if (vol->corrupted != 0 && vol->corrupted != 1) {
+			ubi_err("bad corrupted");
+			goto fail;
+		}
+		if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) {
+			ubi_err("bad used_ebs");
+			goto fail;
+		}
+		if (vol->last_eb_bytes < 0 ||
+		    vol->last_eb_bytes > vol->usable_leb_size) {
+			ubi_err("bad last_eb_bytes");
+			goto fail;
+		}
+		if (vol->used_bytes < 0 || vol->used_bytes > n ||
+		    vol->used_bytes < n - vol->usable_leb_size) {
+			ubi_err("bad used_bytes");
+			goto fail;
+		}
+	}
+
+	alignment  = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
+	data_pad   = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
+	name_len   = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+	upd_marker = ubi->vtbl[vol_id].upd_marker;
+	name       = &ubi->vtbl[vol_id].name[0];
+	if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
+		vol_type = UBI_DYNAMIC_VOLUME;
+	else
+		vol_type = UBI_STATIC_VOLUME;
+
+	if (alignment != vol->alignment || data_pad != vol->data_pad ||
+	    upd_marker != vol->upd_marker || vol_type != vol->vol_type ||
+	    name_len!= vol->name_len || strncmp(name, vol->name, name_len)) {
+		ubi_err("volume info is different");
+		goto fail;
+	}
+
+	return;
+
+fail:
+	ubi_err("paranoid check failed");
+	ubi_dbg_dump_vol_info(vol);
+	ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+	BUG();
+}
+
+/**
+ * paranoid_check_volumes - check information about all volumes.
+ * @ubi: UBI device description object
+ */
+static void paranoid_check_volumes(struct ubi_device *ubi)
+{
+	int i;
+
+	mutex_lock(&ubi->vtbl_mutex);
+	spin_lock(&ubi->volumes_lock);
+	for (i = 0; i < ubi->vtbl_slots; i++)
+		paranoid_check_volume(ubi, i);
+	spin_unlock(&ubi->volumes_lock);
+	mutex_unlock(&ubi->vtbl_mutex);
+}
+#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
new file mode 100644
index 0000000..b6fd6bb
--- /dev/null
+++ b/drivers/mtd/ubi/vtbl.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) Nokia Corporation, 2006, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+/*
+ * This file includes volume table manipulation code. The volume table is an
+ * on-flash table containing volume meta-data like name, number of reserved
+ * physical eraseblocks, type, etc. The volume table is stored in the so-called
+ * "layout volume".
+ *
+ * The layout volume is an internal volume which is organized as follows. It
+ * consists of two logical eraseblocks - LEB 0 and LEB 1. Each logical
+ * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each
+ * other. This redundancy guarantees robustness to unclean reboots. The volume
+ * table is basically an array of volume table records. Each record contains
+ * full information about the volume and protected by a CRC checksum.
+ *
+ * The volume table is changed, it is first changed in RAM. Then LEB 0 is
+ * erased, and the updated volume table is written back to LEB 0. Then same for
+ * LEB 1. This scheme guarantees recoverability from unclean reboots.
+ *
+ * In this UBI implementation the on-flash volume table does not contain any
+ * information about how many data static volumes contain. This information may
+ * be found from the scanning data.
+ *
+ * But it would still be beneficial to store this information in the volume
+ * table. For example, suppose we have a static volume X, and all its physical
+ * eraseblocks became bad for some reasons. Suppose we are attaching the
+ * corresponding MTD device, the scanning has found no logical eraseblocks
+ * corresponding to the volume X. According to the volume table volume X does
+ * exist. So we don't know whether it is just empty or all its physical
+ * eraseblocks went bad. So we cannot alarm the user about this corruption.
+ *
+ * The volume table also stores so-called "update marker", which is used for
+ * volume updates. Before updating the volume, the update marker is set, and
+ * after the update operation is finished, the update marker is cleared. So if
+ * the update operation was interrupted (e.g. by an unclean reboot) - the
+ * update marker is still there and we know that the volume's contents is
+ * damaged.
+ */
+
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include <asm/div64.h>
+#include "ubi.h"
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static void paranoid_vtbl_check(const struct ubi_device *ubi);
+#else
+#define paranoid_vtbl_check(ubi)
+#endif
+
+/* Empty volume table record */
+static struct ubi_vtbl_record empty_vtbl_record;
+
+/**
+ * ubi_change_vtbl_record - change volume table record.
+ * @ubi: UBI device description object
+ * @idx: table index to change
+ * @vtbl_rec: new volume table record
+ *
+ * This function changes volume table record @idx. If @vtbl_rec is %NULL, empty
+ * volume table record is written. The caller does not have to calculate CRC of
+ * the record as it is done by this function. Returns zero in case of success
+ * and a negative error code in case of failure.
+ */
+int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
+			   struct ubi_vtbl_record *vtbl_rec)
+{
+	int i, err;
+	uint32_t crc;
+
+	ubi_assert(idx >= 0 && idx < ubi->vtbl_slots);
+
+	if (!vtbl_rec)
+		vtbl_rec = &empty_vtbl_record;
+	else {
+		crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
+		vtbl_rec->crc = cpu_to_ubi32(crc);
+	}
+
+	dbg_msg("change record %d", idx);
+	ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
+
+	mutex_lock(&ubi->vtbl_mutex);
+	memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
+	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
+		err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i);
+		if (err) {
+			mutex_unlock(&ubi->vtbl_mutex);
+			return err;
+		}
+		err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0,
+					ubi->vtbl_size, UBI_LONGTERM);
+		if (err) {
+			mutex_unlock(&ubi->vtbl_mutex);
+			return err;
+		}
+	}
+
+	paranoid_vtbl_check(ubi);
+	mutex_unlock(&ubi->vtbl_mutex);
+	return ubi_wl_flush(ubi);
+}
+
+/**
+ * vol_til_check - check if volume table is not corrupted and contains sensible
+ * data.
+ *
+ * @ubi: UBI device description object
+ * @vtbl: volume table
+ *
+ * This function returns zero if @vtbl is all right, %1 if CRC is incorrect,
+ * and %-EINVAL if it contains inconsistent data.
+ */
+static int vtbl_check(const struct ubi_device *ubi,
+		      const struct ubi_vtbl_record *vtbl)
+{
+	int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len;
+	int upd_marker;
+	uint32_t crc;
+	const char *name;
+
+	for (i = 0; i < ubi->vtbl_slots; i++) {
+		cond_resched();
+
+		reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
+		alignment = ubi32_to_cpu(vtbl[i].alignment);
+		data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+		upd_marker = vtbl[i].upd_marker;
+		vol_type = vtbl[i].vol_type;
+		name_len = ubi16_to_cpu(vtbl[i].name_len);
+		name = &vtbl[i].name[0];
+
+		crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
+		if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+			ubi_err("bad CRC at record %u: %#08x, not %#08x",
+				 i, crc, ubi32_to_cpu(vtbl[i].crc));
+			ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+			return 1;
+		}
+
+		if (reserved_pebs == 0) {
+			if (memcmp(&vtbl[i], &empty_vtbl_record,
+						UBI_VTBL_RECORD_SIZE)) {
+				dbg_err("bad empty record");
+				goto bad;
+			}
+			continue;
+		}
+
+		if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 ||
+		    name_len < 0) {
+			dbg_err("negative values");
+			goto bad;
+		}
+
+		if (alignment > ubi->leb_size || alignment == 0) {
+			dbg_err("bad alignment");
+			goto bad;
+		}
+
+		n = alignment % ubi->min_io_size;
+		if (alignment != 1 && n) {
+			dbg_err("alignment is not multiple of min I/O unit");
+			goto bad;
+		}
+
+		n = ubi->leb_size % alignment;
+		if (data_pad != n) {
+			dbg_err("bad data_pad, has to be %d", n);
+			goto bad;
+		}
+
+		if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
+			dbg_err("bad vol_type");
+			goto bad;
+		}
+
+		if (upd_marker != 0 && upd_marker != 1) {
+			dbg_err("bad upd_marker");
+			goto bad;
+		}
+
+		if (reserved_pebs > ubi->good_peb_count) {
+			dbg_err("too large reserved_pebs, good PEBs %d",
+				ubi->good_peb_count);
+			goto bad;
+		}
+
+		if (name_len > UBI_VOL_NAME_MAX) {
+			dbg_err("too long volume name, max %d",
+				UBI_VOL_NAME_MAX);
+			goto bad;
+		}
+
+		if (name[0] == '\0') {
+			dbg_err("NULL volume name");
+			goto bad;
+		}
+
+		if (name_len != strnlen(name, name_len + 1)) {
+			dbg_err("bad name_len");
+			goto bad;
+		}
+	}
+
+	/* Checks that all names are unique */
+	for (i = 0; i < ubi->vtbl_slots - 1; i++) {
+		for (n = i + 1; n < ubi->vtbl_slots; n++) {
+			int len1 = ubi16_to_cpu(vtbl[i].name_len);
+			int len2 = ubi16_to_cpu(vtbl[n].name_len);
+
+			if (len1 > 0 && len1 == len2 &&
+			    !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
+				ubi_err("volumes %d and %d have the same name"
+					" \"%s\"", i, n, vtbl[i].name);
+				ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+				ubi_dbg_dump_vtbl_record(&vtbl[n], n);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+
+bad:
+	ubi_err("volume table check failed, record %d", i);
+	ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+	return -EINVAL;
+}
+
+/**
+ * create_vtbl - create a copy of volume table.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @copy: number of the volume table copy
+ * @vtbl: contents of the volume table
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
+		       int copy, void *vtbl)
+{
+	int err, tries = 0;
+	static struct ubi_vid_hdr *vid_hdr;
+	struct ubi_scan_volume *sv;
+	struct ubi_scan_leb *new_seb, *old_seb = NULL;
+
+	ubi_msg("create volume table (copy #%d)", copy + 1);
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	/*
+	 * Check if there is a logical eraseblock which would have to contain
+	 * this volume table copy was found during scanning. It has to be wiped
+	 * out.
+	 */
+	sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
+	if (sv)
+		old_seb = ubi_scan_find_seb(sv, copy);
+
+retry:
+	new_seb = ubi_scan_get_free_peb(ubi, si);
+	if (IS_ERR(new_seb)) {
+		err = PTR_ERR(new_seb);
+		goto out_free;
+	}
+
+	vid_hdr->vol_type = UBI_VID_DYNAMIC;
+	vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+	vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
+	vid_hdr->data_size = vid_hdr->used_ebs =
+			     vid_hdr->data_pad = cpu_to_ubi32(0);
+	vid_hdr->lnum = cpu_to_ubi32(copy);
+	vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
+	vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+
+	/* The EC header is already there, write the VID header */
+	err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+	if (err)
+		goto write_error;
+
+	/* Write the layout volume contents */
+	err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
+	if (err)
+		goto write_error;
+
+	/*
+	 * And add it to the scanning information. Don't delete the old
+	 * @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'.
+	 */
+	err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
+				vid_hdr, 0);
+	kfree(new_seb);
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return err;
+
+write_error:
+	kfree(new_seb);
+	/* May be this physical eraseblock went bad, try to pick another one */
+	if (++tries <= 5) {
+		err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
+					   &si->corr);
+		if (!err)
+			goto retry;
+	}
+out_free:
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	return err;
+
+}
+
+/**
+ * process_lvol - process the layout volume.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @sv: layout volume scanning information
+ *
+ * This function is responsible for reading the layout volume, ensuring it is
+ * not corrupted, and recovering from corruptions if needed. Returns volume
+ * table in case of success and a negative error code in case of failure.
+ */
+static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
+					    struct ubi_scan_info *si,
+					    struct ubi_scan_volume *sv)
+{
+	int err;
+	struct rb_node *rb;
+	struct ubi_scan_leb *seb;
+	struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
+	int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
+
+	/*
+	 * UBI goes through the following steps when it changes the layout
+	 * volume:
+	 * a. erase LEB 0;
+	 * b. write new data to LEB 0;
+	 * c. erase LEB 1;
+	 * d. write new data to LEB 1.
+	 *
+	 * Before the change, both LEBs contain the same data.
+	 *
+	 * Due to unclean reboots, the contents of LEB 0 may be lost, but there
+	 * should LEB 1. So it is OK if LEB 0 is corrupted while LEB 1 is not.
+	 * Similarly, LEB 1 may be lost, but there should be LEB 0. And
+	 * finally, unclean reboots may result in a situation when neither LEB
+	 * 0 nor LEB 1 are corrupted, but they are different. In this case, LEB
+	 * 0 contains more recent information.
+	 *
+	 * So the plan is to first check LEB 0. Then
+	 * a. if LEB 0 is OK, it must be containing the most resent data; then
+	 *    we compare it with LEB 1, and if they are different, we copy LEB
+	 *    0 to LEB 1;
+	 * b. if LEB 0 is corrupted, but LEB 1 has to be OK, and we copy LEB 1
+	 *    to LEB 0.
+	 */
+
+	dbg_msg("check layout volume");
+
+	/* Read both LEB 0 and LEB 1 into memory */
+	ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
+		leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+		if (!leb[seb->lnum]) {
+			err = -ENOMEM;
+			goto out_free;
+		}
+
+		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+				       ubi->vtbl_size);
+		if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+			/* Scrub the PEB later */
+			seb->scrub = 1;
+		else if (err)
+			goto out_free;
+	}
+
+	err = -EINVAL;
+	if (leb[0]) {
+		leb_corrupted[0] = vtbl_check(ubi, leb[0]);
+		if (leb_corrupted[0] < 0)
+			goto out_free;
+	}
+
+	if (!leb_corrupted[0]) {
+		/* LEB 0 is OK */
+		if (leb[1])
+			leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size);
+		if (leb_corrupted[1]) {
+			ubi_warn("volume table copy #2 is corrupted");
+			err = create_vtbl(ubi, si, 1, leb[0]);
+			if (err)
+				goto out_free;
+			ubi_msg("volume table was restored");
+		}
+
+		/* Both LEB 1 and LEB 2 are OK and consistent */
+		kfree(leb[1]);
+		return leb[0];
+	} else {
+		/* LEB 0 is corrupted or does not exist */
+		if (leb[1]) {
+			leb_corrupted[1] = vtbl_check(ubi, leb[1]);
+			if (leb_corrupted[1] < 0)
+				goto out_free;
+		}
+		if (leb_corrupted[1]) {
+			/* Both LEB 0 and LEB 1 are corrupted */
+			ubi_err("both volume tables are corrupted");
+			goto out_free;
+		}
+
+		ubi_warn("volume table copy #1 is corrupted");
+		err = create_vtbl(ubi, si, 0, leb[1]);
+		if (err)
+			goto out_free;
+		ubi_msg("volume table was restored");
+
+		kfree(leb[0]);
+		return leb[1];
+	}
+
+out_free:
+	kfree(leb[0]);
+	kfree(leb[1]);
+	return ERR_PTR(err);
+}
+
+/**
+ * create_empty_lvol - create empty layout volume.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns volume table contents in case of success and a
+ * negative error code in case of failure.
+ */
+static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
+						 struct ubi_scan_info *si)
+{
+	int i;
+	struct ubi_vtbl_record *vtbl;
+
+	vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+	if (!vtbl)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < ubi->vtbl_slots; i++)
+		memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
+
+	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
+		int err;
+
+		err = create_vtbl(ubi, si, i, vtbl);
+		if (err) {
+			kfree(vtbl);
+			return ERR_PTR(err);
+		}
+	}
+
+	return vtbl;
+}
+
+/**
+ * init_volumes - initialize volume information for existing volumes.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ * @vtbl: volume table
+ *
+ * This function allocates volume description objects for existing volumes.
+ * Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+			const struct ubi_vtbl_record *vtbl)
+{
+	int i, reserved_pebs = 0;
+	struct ubi_scan_volume *sv;
+	struct ubi_volume *vol;
+
+	for (i = 0; i < ubi->vtbl_slots; i++) {
+		cond_resched();
+
+		if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+			continue; /* Empty record */
+
+		vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+		if (!vol)
+			return -ENOMEM;
+
+		vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
+		vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
+		vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+		vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
+					UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
+		vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+		vol->usable_leb_size = ubi->leb_size - vol->data_pad;
+		memcpy(vol->name, vtbl[i].name, vol->name_len);
+		vol->name[vol->name_len] = '\0';
+		vol->vol_id = i;
+
+		ubi_assert(!ubi->volumes[i]);
+		ubi->volumes[i] = vol;
+		ubi->vol_count += 1;
+		vol->ubi = ubi;
+		reserved_pebs += vol->reserved_pebs;
+
+		/*
+		 * In case of dynamic volume UBI knows nothing about how many
+		 * data is stored there. So assume the whole volume is used.
+		 */
+		if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
+			vol->used_ebs = vol->reserved_pebs;
+			vol->last_eb_bytes = vol->usable_leb_size;
+			vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+			continue;
+		}
+
+		/* Static volumes only */
+		sv = ubi_scan_find_sv(si, i);
+		if (!sv) {
+			/*
+			 * No eraseblocks belonging to this volume found. We
+			 * don't actually know whether this static volume is
+			 * completely corrupted or just contains no data. And
+			 * we cannot know this as long as data size is not
+			 * stored on flash. So we just assume the volume is
+			 * empty. FIXME: this should be handled.
+			 */
+			continue;
+		}
+
+		if (sv->leb_count != sv->used_ebs) {
+			/*
+			 * We found a static volume which misses several
+			 * eraseblocks. Treat it as corrupted.
+			 */
+			ubi_warn("static volume %d misses %d LEBs - corrupted",
+				 sv->vol_id, sv->used_ebs - sv->leb_count);
+			vol->corrupted = 1;
+			continue;
+		}
+
+		vol->used_ebs = sv->used_ebs;
+		vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+		vol->used_bytes += sv->last_data_size;
+		vol->last_eb_bytes = sv->last_data_size;
+	}
+
+	vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
+	if (!vol)
+		return -ENOMEM;
+
+	vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS;
+	vol->alignment = 1;
+	vol->vol_type = UBI_DYNAMIC_VOLUME;
+	vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1;
+	memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1);
+	vol->usable_leb_size = ubi->leb_size;
+	vol->used_ebs = vol->reserved_pebs;
+	vol->last_eb_bytes = vol->reserved_pebs;
+	vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+	vol->vol_id = UBI_LAYOUT_VOL_ID;
+
+	ubi_assert(!ubi->volumes[i]);
+	ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol;
+	reserved_pebs += vol->reserved_pebs;
+	ubi->vol_count += 1;
+	vol->ubi = ubi;
+
+	if (reserved_pebs > ubi->avail_pebs)
+		ubi_err("not enough PEBs, required %d, available %d",
+			reserved_pebs, ubi->avail_pebs);
+	ubi->rsvd_pebs += reserved_pebs;
+	ubi->avail_pebs -= reserved_pebs;
+
+	return 0;
+}
+
+/**
+ * check_sv - check volume scanning information.
+ * @vol: UBI volume description object
+ * @sv: volume scanning information
+ *
+ * This function returns zero if the volume scanning information is consistent
+ * to the data read from the volume tabla, and %-EINVAL if not.
+ */
+static int check_sv(const struct ubi_volume *vol,
+		    const struct ubi_scan_volume *sv)
+{
+	if (sv->highest_lnum >= vol->reserved_pebs) {
+		dbg_err("bad highest_lnum");
+		goto bad;
+	}
+	if (sv->leb_count > vol->reserved_pebs) {
+		dbg_err("bad leb_count");
+		goto bad;
+	}
+	if (sv->vol_type != vol->vol_type) {
+		dbg_err("bad vol_type");
+		goto bad;
+	}
+	if (sv->used_ebs > vol->reserved_pebs) {
+		dbg_err("bad used_ebs");
+		goto bad;
+	}
+	if (sv->data_pad != vol->data_pad) {
+		dbg_err("bad data_pad");
+		goto bad;
+	}
+	return 0;
+
+bad:
+	ubi_err("bad scanning information");
+	ubi_dbg_dump_sv(sv);
+	ubi_dbg_dump_vol_info(vol);
+	return -EINVAL;
+}
+
+/**
+ * check_scanning_info - check that scanning information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * Even though we protect on-flash data by CRC checksums, we still don't trust
+ * the media. This function ensures that scanning information is consistent to
+ * the information read from the volume table. Returns zero if the scanning
+ * information is OK and %-EINVAL if it is not.
+ */
+static int check_scanning_info(const struct ubi_device *ubi,
+			       struct ubi_scan_info *si)
+{
+	int err, i;
+	struct ubi_scan_volume *sv;
+	struct ubi_volume *vol;
+
+	if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
+		ubi_err("scanning found %d volumes, maximum is %d + %d",
+			si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
+		return -EINVAL;
+	}
+
+	if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT&&
+	    si->highest_vol_id < UBI_INTERNAL_VOL_START) {
+		ubi_err("too large volume ID %d found by scanning",
+			si->highest_vol_id);
+		return -EINVAL;
+	}
+
+
+	for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+		cond_resched();
+
+		sv = ubi_scan_find_sv(si, i);
+		vol = ubi->volumes[i];
+		if (!vol) {
+			if (sv)
+				ubi_scan_rm_volume(si, sv);
+			continue;
+		}
+
+		if (vol->reserved_pebs == 0) {
+			ubi_assert(i < ubi->vtbl_slots);
+
+			if (!sv)
+				continue;
+
+			/*
+			 * During scanning we found a volume which does not
+			 * exist according to the information in the volume
+			 * table. This must have happened due to an unclean
+			 * reboot while the volume was being removed. Discard
+			 * these eraseblocks.
+			 */
+			ubi_msg("finish volume %d removal", sv->vol_id);
+			ubi_scan_rm_volume(si, sv);
+		} else if (sv) {
+			err = check_sv(vol, sv);
+			if (err)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ubi_read_volume_table - read volume table.
+ * information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function reads volume table, checks it, recover from errors if needed,
+ * or creates it if needed. Returns zero in case of success and a negative
+ * error code in case of failure.
+ */
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+	int i, err;
+	struct ubi_scan_volume *sv;
+
+	empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+
+	/*
+	 * The number of supported volumes is limited by the eraseblock size
+	 * and by the UBI_MAX_VOLUMES constant.
+	 */
+	ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE;
+	if (ubi->vtbl_slots > UBI_MAX_VOLUMES)
+		ubi->vtbl_slots = UBI_MAX_VOLUMES;
+
+	ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
+	ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
+
+	sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID);
+	if (!sv) {
+		/*
+		 * No logical eraseblocks belonging to the layout volume were
+		 * found. This could mean that the flash is just empty. In
+		 * this case we create empty layout volume.
+		 *
+		 * But if flash is not empty this must be a corruption or the
+		 * MTD device just contains garbage.
+		 */
+		if (si->is_empty) {
+			ubi->vtbl = create_empty_lvol(ubi, si);
+			if (IS_ERR(ubi->vtbl))
+				return PTR_ERR(ubi->vtbl);
+		} else {
+			ubi_err("the layout volume was not found");
+			return -EINVAL;
+		}
+	} else {
+		if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
+			/* This must not happen with proper UBI images */
+			dbg_err("too many LEBs (%d) in layout volume",
+				sv->leb_count);
+			return -EINVAL;
+		}
+
+		ubi->vtbl = process_lvol(ubi, si, sv);
+		if (IS_ERR(ubi->vtbl))
+			return PTR_ERR(ubi->vtbl);
+	}
+
+	ubi->avail_pebs = ubi->good_peb_count;
+
+	/*
+	 * The layout volume is OK, initialize the corresponding in-RAM data
+	 * structures.
+	 */
+	err = init_volumes(ubi, si, ubi->vtbl);
+	if (err)
+		goto out_free;
+
+	/*
+	 * Get sure that the scanning information is consistent to the
+	 * information stored in the volume table.
+	 */
+	err = check_scanning_info(ubi, si);
+	if (err)
+		goto out_free;
+
+	return 0;
+
+out_free:
+	kfree(ubi->vtbl);
+	for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
+		if (ubi->volumes[i]) {
+			kfree(ubi->volumes[i]);
+			ubi->volumes[i] = NULL;
+		}
+	return err;
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_vtbl_check - check volume table.
+ * @ubi: UBI device description object
+ */
+static void paranoid_vtbl_check(const struct ubi_device *ubi)
+{
+	if (vtbl_check(ubi, ubi->vtbl)) {
+		ubi_err("paranoid check failed");
+		BUG();
+	}
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
new file mode 100644
index 0000000..9ecaf77
--- /dev/null
+++ b/drivers/mtd/ubi/wl.c
@@ -0,0 +1,1671 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Authors: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼), Thomas Gleixner
+ */
+
+/*
+ * UBI wear-leveling unit.
+ *
+ * This unit is responsible for wear-leveling. It works in terms of physical
+ * eraseblocks and erase counters and knows nothing about logical eraseblocks,
+ * volumes, etc. From this unit's perspective all physical eraseblocks are of
+ * two types - used and free. Used physical eraseblocks are those that were
+ * "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are
+ * those that were put by the 'ubi_wl_put_peb()' function.
+ *
+ * Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter
+ * header. The rest of the physical eraseblock contains only 0xFF bytes.
+ *
+ * When physical eraseblocks are returned to the WL unit by means of the
+ * 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is
+ * done asynchronously in context of the per-UBI device background thread,
+ * which is also managed by the WL unit.
+ *
+ * The wear-leveling is ensured by means of moving the contents of used
+ * physical eraseblocks with low erase counter to free physical eraseblocks
+ * with high erase counter.
+ *
+ * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
+ * an "optimal" physical eraseblock. For example, when it is known that the
+ * physical eraseblock will be "put" soon because it contains short-term data,
+ * the WL unit may pick a free physical eraseblock with low erase counter, and
+ * so forth.
+ *
+ * If the WL unit fails to erase a physical eraseblock, it marks it as bad.
+ *
+ * This unit is also responsible for scrubbing. If a bit-flip is detected in a
+ * physical eraseblock, it has to be moved. Technically this is the same as
+ * moving it for wear-leveling reasons.
+ *
+ * As it was said, for the UBI unit all physical eraseblocks are either "free"
+ * or "used". Free eraseblock are kept in the @wl->free RB-tree, while used
+ * eraseblocks are kept in a set of different RB-trees: @wl->used,
+ * @wl->prot.pnum, @wl->prot.aec, and @wl->scrub.
+ *
+ * Note, in this implementation, we keep a small in-RAM object for each physical
+ * eraseblock. This is surely not a scalable solution. But it appears to be good
+ * enough for moderately large flashes and it is simple. In future, one may
+ * re-work this unit and make it more scalable.
+ *
+ * At the moment this unit does not utilize the sequence number, which was
+ * introduced relatively recently. But it would be wise to do this because the
+ * sequence number of a logical eraseblock characterizes how old is it. For
+ * example, when we move a PEB with low erase counter, and we need to pick the
+ * target PEB, we pick a PEB with the highest EC if our PEB is "old" and we
+ * pick target PEB with an average EC if our PEB is not very "old". This is a
+ * room for future re-works of the WL unit.
+ *
+ * FIXME: looks too complex, should be simplified (later).
+ */
+
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+#include "ubi.h"
+
+/* Number of physical eraseblocks reserved for wear-leveling purposes */
+#define WL_RESERVED_PEBS 1
+
+/*
+ * How many erase cycles are short term, unknown, and long term physical
+ * eraseblocks protected.
+ */
+#define ST_PROTECTION 16
+#define U_PROTECTION  10
+#define LT_PROTECTION 4
+
+/*
+ * Maximum difference between two erase counters. If this threshold is
+ * exceeded, the WL unit starts moving data from used physical eraseblocks with
+ * low erase counter to free physical eraseblocks with high erase counter.
+ */
+#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD
+
+/*
+ * When a physical eraseblock is moved, the WL unit has to pick the target
+ * physical eraseblock to move to. The simplest way would be just to pick the
+ * one with the highest erase counter. But in certain workloads this could lead
+ * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a
+ * situation when the picked physical eraseblock is constantly erased after the
+ * data is written to it. So, we have a constant which limits the highest erase
+ * counter of the free physical eraseblock to pick. Namely, the WL unit does
+ * not pick eraseblocks with erase counter greater then the lowest erase
+ * counter plus %WL_FREE_MAX_DIFF.
+ */
+#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
+
+/*
+ * Maximum number of consecutive background thread failures which is enough to
+ * switch to read-only mode.
+ */
+#define WL_MAX_FAILURES 32
+
+/**
+ * struct ubi_wl_entry - wear-leveling entry.
+ * @rb: link in the corresponding RB-tree
+ * @ec: erase counter
+ * @pnum: physical eraseblock number
+ *
+ * Each physical eraseblock has a corresponding &struct wl_entry object which
+ * may be kept in different RB-trees.
+ */
+struct ubi_wl_entry {
+	struct rb_node rb;
+	int ec;
+	int pnum;
+};
+
+/**
+ * struct ubi_wl_prot_entry - PEB protection entry.
+ * @rb_pnum: link in the @wl->prot.pnum RB-tree
+ * @rb_aec: link in the @wl->prot.aec RB-tree
+ * @abs_ec: the absolute erase counter value when the protection ends
+ * @e: the wear-leveling entry of the physical eraseblock under protection
+ *
+ * When the WL unit returns a physical eraseblock, the physical eraseblock is
+ * protected from being moved for some "time". For this reason, the physical
+ * eraseblock is not directly moved from the @wl->free tree to the @wl->used
+ * tree. There is one more tree in between where this physical eraseblock is
+ * temporarily stored (@wl->prot).
+ *
+ * All this protection stuff is needed because:
+ *  o we don't want to move physical eraseblocks just after we have given them
+ *    to the user; instead, we first want to let users fill them up with data;
+ *
+ *  o there is a chance that the user will put the physical eraseblock very
+ *    soon, so it makes sense not to move it for some time, but wait; this is
+ *    especially important in case of "short term" physical eraseblocks.
+ *
+ * Physical eraseblocks stay protected only for limited time. But the "time" is
+ * measured in erase cycles in this case. This is implemented with help of the
+ * absolute erase counter (@wl->abs_ec). When it reaches certain value, the
+ * physical eraseblocks are moved from the protection trees (@wl->prot.*) to
+ * the @wl->used tree.
+ *
+ * Protected physical eraseblocks are searched by physical eraseblock number
+ * (when they are put) and by the absolute erase counter (to check if it is
+ * time to move them to the @wl->used tree). So there are actually 2 RB-trees
+ * storing the protected physical eraseblocks: @wl->prot.pnum and
+ * @wl->prot.aec. They are referred to as the "protection" trees. The
+ * first one is indexed by the physical eraseblock number. The second one is
+ * indexed by the absolute erase counter. Both trees store
+ * &struct ubi_wl_prot_entry objects.
+ *
+ * Each physical eraseblock has 2 main states: free and used. The former state
+ * corresponds to the @wl->free tree. The latter state is split up on several
+ * sub-states:
+ * o the WL movement is allowed (@wl->used tree);
+ * o the WL movement is temporarily prohibited (@wl->prot.pnum and
+ * @wl->prot.aec trees);
+ * o scrubbing is needed (@wl->scrub tree).
+ *
+ * Depending on the sub-state, wear-leveling entries of the used physical
+ * eraseblocks may be kept in one of those trees.
+ */
+struct ubi_wl_prot_entry {
+	struct rb_node rb_pnum;
+	struct rb_node rb_aec;
+	unsigned long long abs_ec;
+	struct ubi_wl_entry *e;
+};
+
+/**
+ * struct ubi_work - UBI work description data structure.
+ * @list: a link in the list of pending works
+ * @func: worker function
+ * @priv: private data of the worker function
+ *
+ * @e: physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * The @func pointer points to the worker function. If the @cancel argument is
+ * not zero, the worker has to free the resources and exit immediately. The
+ * worker has to return zero in case of success and a negative error code in
+ * case of failure.
+ */
+struct ubi_work {
+	struct list_head list;
+	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
+	/* The below fields are only relevant to erasure works */
+	struct ubi_wl_entry *e;
+	int torture;
+};
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec);
+static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
+				     struct rb_root *root);
+#else
+#define paranoid_check_ec(ubi, pnum, ec) 0
+#define paranoid_check_in_wl_tree(e, root)
+#endif
+
+/* Slab cache for wear-leveling entries */
+static struct kmem_cache *wl_entries_slab;
+
+/**
+ * tree_empty - a helper function to check if an RB-tree is empty.
+ * @root: the root of the tree
+ *
+ * This function returns non-zero if the RB-tree is empty and zero if not.
+ */
+static inline int tree_empty(struct rb_root *root)
+{
+	return root->rb_node == NULL;
+}
+
+/**
+ * wl_tree_add - add a wear-leveling entry to a WL RB-tree.
+ * @e: the wear-leveling entry to add
+ * @root: the root of the tree
+ *
+ * Note, we use (erase counter, physical eraseblock number) pairs as keys in
+ * the @ubi->used and @ubi->free RB-trees.
+ */
+static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
+{
+	struct rb_node **p, *parent = NULL;
+
+	p = &root->rb_node;
+	while (*p) {
+		struct ubi_wl_entry *e1;
+
+		parent = *p;
+		e1 = rb_entry(parent, struct ubi_wl_entry, rb);
+
+		if (e->ec < e1->ec)
+			p = &(*p)->rb_left;
+		else if (e->ec > e1->ec)
+			p = &(*p)->rb_right;
+		else {
+			ubi_assert(e->pnum != e1->pnum);
+			if (e->pnum < e1->pnum)
+				p = &(*p)->rb_left;
+			else
+				p = &(*p)->rb_right;
+		}
+	}
+
+	rb_link_node(&e->rb, parent, p);
+	rb_insert_color(&e->rb, root);
+}
+
+
+/*
+ * Helper functions to add and delete wear-leveling entries from different
+ * trees.
+ */
+
+static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
+{
+	wl_tree_add(e, &ubi->free);
+}
+static inline void used_tree_add(struct ubi_device *ubi,
+				 struct ubi_wl_entry *e)
+{
+	wl_tree_add(e, &ubi->used);
+}
+static inline void scrub_tree_add(struct ubi_device *ubi,
+				  struct ubi_wl_entry *e)
+{
+	wl_tree_add(e, &ubi->scrub);
+}
+static inline void free_tree_del(struct ubi_device *ubi,
+				 struct ubi_wl_entry *e)
+{
+	paranoid_check_in_wl_tree(e, &ubi->free);
+	rb_erase(&e->rb, &ubi->free);
+}
+static inline void used_tree_del(struct ubi_device *ubi,
+				 struct ubi_wl_entry *e)
+{
+	paranoid_check_in_wl_tree(e, &ubi->used);
+	rb_erase(&e->rb, &ubi->used);
+}
+static inline void scrub_tree_del(struct ubi_device *ubi,
+				  struct ubi_wl_entry *e)
+{
+	paranoid_check_in_wl_tree(e, &ubi->scrub);
+	rb_erase(&e->rb, &ubi->scrub);
+}
+
+/**
+ * do_work - do one pending work.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int do_work(struct ubi_device *ubi)
+{
+	int err;
+	struct ubi_work *wrk;
+
+	spin_lock(&ubi->wl_lock);
+
+	if (list_empty(&ubi->works)) {
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	}
+
+	wrk = list_entry(ubi->works.next, struct ubi_work, list);
+	list_del(&wrk->list);
+	spin_unlock(&ubi->wl_lock);
+
+	/*
+	 * Call the worker function. Do not touch the work structure
+	 * after this call as it will have been freed or reused by that
+	 * time by the worker function.
+	 */
+	err = wrk->func(ubi, wrk, 0);
+	if (err)
+		ubi_err("work failed with error code %d", err);
+
+	spin_lock(&ubi->wl_lock);
+	ubi->works_count -= 1;
+	ubi_assert(ubi->works_count >= 0);
+	spin_unlock(&ubi->wl_lock);
+	return err;
+}
+
+/**
+ * produce_free_peb - produce a free physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function tries to make a free PEB by means of synchronous execution of
+ * pending works. This may be needed if, for example the background thread is
+ * disabled. Returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+static int produce_free_peb(struct ubi_device *ubi)
+{
+	int err;
+
+	spin_lock(&ubi->wl_lock);
+	while (tree_empty(&ubi->free)) {
+		spin_unlock(&ubi->wl_lock);
+
+		dbg_wl("do one work synchronously");
+		err = do_work(ubi);
+		if (err)
+			return err;
+
+		spin_lock(&ubi->wl_lock);
+	}
+	spin_unlock(&ubi->wl_lock);
+
+	return 0;
+}
+
+/**
+ * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree.
+ * @e: the wear-leveling entry to check
+ * @root: the root of the tree
+ *
+ * This function returns non-zero if @e is in the @root RB-tree and zero if it
+ * is not.
+ */
+static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root)
+{
+	struct rb_node *p;
+
+	p = root->rb_node;
+	while (p) {
+		struct ubi_wl_entry *e1;
+
+		e1 = rb_entry(p, struct ubi_wl_entry, rb);
+
+		if (e->pnum == e1->pnum) {
+			ubi_assert(e == e1);
+			return 1;
+		}
+
+		if (e->ec < e1->ec)
+			p = p->rb_left;
+		else if (e->ec > e1->ec)
+			p = p->rb_right;
+		else {
+			ubi_assert(e->pnum != e1->pnum);
+			if (e->pnum < e1->pnum)
+				p = p->rb_left;
+			else
+				p = p->rb_right;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * prot_tree_add - add physical eraseblock to protection trees.
+ * @ubi: UBI device description object
+ * @e: the physical eraseblock to add
+ * @pe: protection entry object to use
+ * @abs_ec: absolute erase counter value when this physical eraseblock has
+ * to be removed from the protection trees.
+ *
+ * @wl->lock has to be locked.
+ */
+static void prot_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e,
+			  struct ubi_wl_prot_entry *pe, int abs_ec)
+{
+	struct rb_node **p, *parent = NULL;
+	struct ubi_wl_prot_entry *pe1;
+
+	pe->e = e;
+	pe->abs_ec = ubi->abs_ec + abs_ec;
+
+	p = &ubi->prot.pnum.rb_node;
+	while (*p) {
+		parent = *p;
+		pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_pnum);
+
+		if (e->pnum < pe1->e->pnum)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+	rb_link_node(&pe->rb_pnum, parent, p);
+	rb_insert_color(&pe->rb_pnum, &ubi->prot.pnum);
+
+	p = &ubi->prot.aec.rb_node;
+	parent = NULL;
+	while (*p) {
+		parent = *p;
+		pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_aec);
+
+		if (pe->abs_ec < pe1->abs_ec)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+	rb_link_node(&pe->rb_aec, parent, p);
+	rb_insert_color(&pe->rb_aec, &ubi->prot.aec);
+}
+
+/**
+ * find_wl_entry - find wear-leveling entry closest to certain erase counter.
+ * @root: the RB-tree where to look for
+ * @max: highest possible erase counter
+ *
+ * This function looks for a wear leveling entry with erase counter closest to
+ * @max and less then @max.
+ */
+static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
+{
+	struct rb_node *p;
+	struct ubi_wl_entry *e;
+
+	e = rb_entry(rb_first(root), struct ubi_wl_entry, rb);
+	max += e->ec;
+
+	p = root->rb_node;
+	while (p) {
+		struct ubi_wl_entry *e1;
+
+		e1 = rb_entry(p, struct ubi_wl_entry, rb);
+		if (e1->ec >= max)
+			p = p->rb_left;
+		else {
+			p = p->rb_right;
+			e = e1;
+		}
+	}
+
+	return e;
+}
+
+/**
+ * ubi_wl_get_peb - get a physical eraseblock.
+ * @ubi: UBI device description object
+ * @dtype: type of data which will be stored in this physical eraseblock
+ *
+ * This function returns a physical eraseblock in case of success and a
+ * negative error code in case of failure. Might sleep.
+ */
+int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+{
+	int err, protect, medium_ec;
+	struct ubi_wl_entry *e, *first, *last;
+	struct ubi_wl_prot_entry *pe;
+
+	ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
+		   dtype == UBI_UNKNOWN);
+
+	pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL);
+	if (!pe)
+		return -ENOMEM;
+
+retry:
+	spin_lock(&ubi->wl_lock);
+	if (tree_empty(&ubi->free)) {
+		if (ubi->works_count == 0) {
+			ubi_assert(list_empty(&ubi->works));
+			ubi_err("no free eraseblocks");
+			spin_unlock(&ubi->wl_lock);
+			kfree(pe);
+			return -ENOSPC;
+		}
+		spin_unlock(&ubi->wl_lock);
+
+		err = produce_free_peb(ubi);
+		if (err < 0) {
+			kfree(pe);
+			return err;
+		}
+		goto retry;
+	}
+
+	switch (dtype) {
+		case UBI_LONGTERM:
+			/*
+			 * For long term data we pick a physical eraseblock
+			 * with high erase counter. But the highest erase
+			 * counter we can pick is bounded by the the lowest
+			 * erase counter plus %WL_FREE_MAX_DIFF.
+			 */
+			e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+			protect = LT_PROTECTION;
+			break;
+		case UBI_UNKNOWN:
+			/*
+			 * For unknown data we pick a physical eraseblock with
+			 * medium erase counter. But we by no means can pick a
+			 * physical eraseblock with erase counter greater or
+			 * equivalent than the lowest erase counter plus
+			 * %WL_FREE_MAX_DIFF.
+			 */
+			first = rb_entry(rb_first(&ubi->free),
+					 struct ubi_wl_entry, rb);
+			last = rb_entry(rb_last(&ubi->free),
+					struct ubi_wl_entry, rb);
+
+			if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+				e = rb_entry(ubi->free.rb_node,
+						struct ubi_wl_entry, rb);
+			else {
+				medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
+				e = find_wl_entry(&ubi->free, medium_ec);
+			}
+			protect = U_PROTECTION;
+			break;
+		case UBI_SHORTTERM:
+			/*
+			 * For short term data we pick a physical eraseblock
+			 * with the lowest erase counter as we expect it will
+			 * be erased soon.
+			 */
+			e = rb_entry(rb_first(&ubi->free),
+				     struct ubi_wl_entry, rb);
+			protect = ST_PROTECTION;
+			break;
+		default:
+			protect = 0;
+			e = NULL;
+			BUG();
+	}
+
+	/*
+	 * Move the physical eraseblock to the protection trees where it will
+	 * be protected from being moved for some time.
+	 */
+	free_tree_del(ubi, e);
+	prot_tree_add(ubi, e, pe, protect);
+
+	dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect);
+	spin_unlock(&ubi->wl_lock);
+
+	return e->pnum;
+}
+
+/**
+ * prot_tree_del - remove a physical eraseblock from the protection trees
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to remove
+ */
+static void prot_tree_del(struct ubi_device *ubi, int pnum)
+{
+	struct rb_node *p;
+	struct ubi_wl_prot_entry *pe = NULL;
+
+	p = ubi->prot.pnum.rb_node;
+	while (p) {
+
+		pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum);
+
+		if (pnum == pe->e->pnum)
+			break;
+
+		if (pnum < pe->e->pnum)
+			p = p->rb_left;
+		else
+			p = p->rb_right;
+	}
+
+	ubi_assert(pe->e->pnum == pnum);
+	rb_erase(&pe->rb_aec, &ubi->prot.aec);
+	rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
+	kfree(pe);
+}
+
+/**
+ * sync_erase - synchronously erase a physical eraseblock.
+ * @ubi: UBI device description object
+ * @e: the the physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture)
+{
+	int err;
+	struct ubi_ec_hdr *ec_hdr;
+	unsigned long long ec = e->ec;
+
+	dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
+
+	err = paranoid_check_ec(ubi, e->pnum, e->ec);
+	if (err > 0)
+		return -EINVAL;
+
+	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ec_hdr)
+		return -ENOMEM;
+
+	err = ubi_io_sync_erase(ubi, e->pnum, torture);
+	if (err < 0)
+		goto out_free;
+
+	ec += err;
+	if (ec > UBI_MAX_ERASECOUNTER) {
+		/*
+		 * Erase counter overflow. Upgrade UBI and use 64-bit
+		 * erase counters internally.
+		 */
+		ubi_err("erase counter overflow at PEB %d, EC %llu",
+			e->pnum, ec);
+		err = -EINVAL;
+		goto out_free;
+	}
+
+	dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
+
+	ec_hdr->ec = cpu_to_ubi64(ec);
+
+	err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
+	if (err)
+		goto out_free;
+
+	e->ec = ec;
+	spin_lock(&ubi->wl_lock);
+	if (e->ec > ubi->max_ec)
+		ubi->max_ec = e->ec;
+	spin_unlock(&ubi->wl_lock);
+
+out_free:
+	kfree(ec_hdr);
+	return err;
+}
+
+/**
+ * check_protection_over - check if it is time to stop protecting some
+ * physical eraseblocks.
+ * @ubi: UBI device description object
+ *
+ * This function is called after each erase operation, when the absolute erase
+ * counter is incremented, to check if some physical eraseblock  have not to be
+ * protected any longer. These physical eraseblocks are moved from the
+ * protection trees to the used tree.
+ */
+static void check_protection_over(struct ubi_device *ubi)
+{
+	struct ubi_wl_prot_entry *pe;
+
+	/*
+	 * There may be several protected physical eraseblock to remove,
+	 * process them all.
+	 */
+	while (1) {
+		spin_lock(&ubi->wl_lock);
+		if (tree_empty(&ubi->prot.aec)) {
+			spin_unlock(&ubi->wl_lock);
+			break;
+		}
+
+		pe = rb_entry(rb_first(&ubi->prot.aec),
+			      struct ubi_wl_prot_entry, rb_aec);
+
+		if (pe->abs_ec > ubi->abs_ec) {
+			spin_unlock(&ubi->wl_lock);
+			break;
+		}
+
+		dbg_wl("PEB %d protection over, abs_ec %llu, PEB abs_ec %llu",
+		       pe->e->pnum, ubi->abs_ec, pe->abs_ec);
+		rb_erase(&pe->rb_aec, &ubi->prot.aec);
+		rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
+		used_tree_add(ubi, pe->e);
+		spin_unlock(&ubi->wl_lock);
+
+		kfree(pe);
+		cond_resched();
+	}
+}
+
+/**
+ * schedule_ubi_work - schedule a work.
+ * @ubi: UBI device description object
+ * @wrk: the work to schedule
+ *
+ * This function enqueues a work defined by @wrk to the tail of the pending
+ * works list.
+ */
+static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
+{
+	spin_lock(&ubi->wl_lock);
+	list_add_tail(&wrk->list, &ubi->works);
+	ubi_assert(ubi->works_count >= 0);
+	ubi->works_count += 1;
+	if (ubi->thread_enabled)
+		wake_up_process(ubi->bgt_thread);
+	spin_unlock(&ubi->wl_lock);
+}
+
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+			int cancel);
+
+/**
+ * schedule_erase - schedule an erase work.
+ * @ubi: UBI device description object
+ * @e: the WL entry of the physical eraseblock to erase
+ * @torture: if the physical eraseblock has to be tortured
+ *
+ * This function returns zero in case of success and a %-ENOMEM in case of
+ * failure.
+ */
+static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
+			  int torture)
+{
+	struct ubi_work *wl_wrk;
+
+	dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
+	       e->pnum, e->ec, torture);
+
+	wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+	if (!wl_wrk)
+		return -ENOMEM;
+
+	wl_wrk->func = &erase_worker;
+	wl_wrk->e = e;
+	wl_wrk->torture = torture;
+
+	schedule_ubi_work(ubi, wl_wrk);
+	return 0;
+}
+
+/**
+ * wear_leveling_worker - wear-leveling worker function.
+ * @ubi: UBI device description object
+ * @wrk: the work object
+ * @cancel: non-zero if the worker has to free memory and exit
+ *
+ * This function copies a more worn out physical eraseblock to a less worn out
+ * one. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
+				int cancel)
+{
+	int err, put = 0;
+	struct ubi_wl_entry *e1, *e2;
+	struct ubi_vid_hdr *vid_hdr;
+
+	kfree(wrk);
+
+	if (cancel)
+		return 0;
+
+	vid_hdr = ubi_zalloc_vid_hdr(ubi);
+	if (!vid_hdr)
+		return -ENOMEM;
+
+	spin_lock(&ubi->wl_lock);
+
+	/*
+	 * Only one WL worker at a time is supported at this implementation, so
+	 * make sure a PEB is not being moved already.
+	 */
+	if (ubi->move_to || tree_empty(&ubi->free) ||
+	    (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) {
+		/*
+		 * Only one WL worker at a time is supported at this
+		 * implementation, so if a LEB is already being moved, cancel.
+		 *
+		 * No free physical eraseblocks? Well, we cancel wear-leveling
+		 * then. It will be triggered again when a free physical
+		 * eraseblock appears.
+		 *
+		 * No used physical eraseblocks? They must be temporarily
+		 * protected from being moved. They will be moved to the
+		 * @ubi->used tree later and the wear-leveling will be
+		 * triggered again.
+		 */
+		dbg_wl("cancel WL, a list is empty: free %d, used %d",
+		       tree_empty(&ubi->free), tree_empty(&ubi->used));
+		ubi->wl_scheduled = 0;
+		spin_unlock(&ubi->wl_lock);
+		ubi_free_vid_hdr(ubi, vid_hdr);
+		return 0;
+	}
+
+	if (tree_empty(&ubi->scrub)) {
+		/*
+		 * Now pick the least worn-out used physical eraseblock and a
+		 * highly worn-out free physical eraseblock. If the erase
+		 * counters differ much enough, start wear-leveling.
+		 */
+		e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb);
+		e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+
+		if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
+			dbg_wl("no WL needed: min used EC %d, max free EC %d",
+			       e1->ec, e2->ec);
+			ubi->wl_scheduled = 0;
+			spin_unlock(&ubi->wl_lock);
+			ubi_free_vid_hdr(ubi, vid_hdr);
+			return 0;
+		}
+		used_tree_del(ubi, e1);
+		dbg_wl("move PEB %d EC %d to PEB %d EC %d",
+		       e1->pnum, e1->ec, e2->pnum, e2->ec);
+	} else {
+		e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
+		e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+		scrub_tree_del(ubi, e1);
+		dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
+	}
+
+	free_tree_del(ubi, e2);
+	ubi_assert(!ubi->move_from && !ubi->move_to);
+	ubi_assert(!ubi->move_to_put && !ubi->move_from_put);
+	ubi->move_from = e1;
+	ubi->move_to = e2;
+	spin_unlock(&ubi->wl_lock);
+
+	/*
+	 * Now we are going to copy physical eraseblock @e1->pnum to @e2->pnum.
+	 * We so far do not know which logical eraseblock our physical
+	 * eraseblock (@e1) belongs to. We have to read the volume identifier
+	 * header first.
+	 */
+
+	err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
+	if (err && err != UBI_IO_BITFLIPS) {
+		if (err == UBI_IO_PEB_FREE) {
+			/*
+			 * We are trying to move PEB without a VID header. UBI
+			 * always write VID headers shortly after the PEB was
+			 * given, so we have a situation when it did not have
+			 * chance to write it down because it was preempted.
+			 * Just re-schedule the work, so that next time it will
+			 * likely have the VID header in place.
+			 */
+			dbg_wl("PEB %d has no VID header", e1->pnum);
+			err = 0;
+		} else {
+			ubi_err("error %d while reading VID header from PEB %d",
+				err, e1->pnum);
+			if (err > 0)
+				err = -EIO;
+		}
+		goto error;
+	}
+
+	err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr);
+	if (err) {
+		if (err == UBI_IO_BITFLIPS)
+			err = 0;
+		goto error;
+	}
+
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	spin_lock(&ubi->wl_lock);
+	if (!ubi->move_to_put)
+		used_tree_add(ubi, e2);
+	else
+		put = 1;
+	ubi->move_from = ubi->move_to = NULL;
+	ubi->move_from_put = ubi->move_to_put = 0;
+	ubi->wl_scheduled = 0;
+	spin_unlock(&ubi->wl_lock);
+
+	if (put) {
+		/*
+		 * Well, the target PEB was put meanwhile, schedule it for
+		 * erasure.
+		 */
+		dbg_wl("PEB %d was put meanwhile, erase", e2->pnum);
+		err = schedule_erase(ubi, e2, 0);
+		if (err) {
+			kmem_cache_free(wl_entries_slab, e2);
+			ubi_ro_mode(ubi);
+		}
+	}
+
+	err = schedule_erase(ubi, e1, 0);
+	if (err) {
+		kmem_cache_free(wl_entries_slab, e1);
+		ubi_ro_mode(ubi);
+	}
+
+	dbg_wl("done");
+	return err;
+
+	/*
+	 * Some error occurred. @e1 was not changed, so return it back. @e2
+	 * might be changed, schedule it for erasure.
+	 */
+error:
+	if (err)
+		dbg_wl("error %d occurred, cancel operation", err);
+	ubi_assert(err <= 0);
+
+	ubi_free_vid_hdr(ubi, vid_hdr);
+	spin_lock(&ubi->wl_lock);
+	ubi->wl_scheduled = 0;
+	if (ubi->move_from_put)
+		put = 1;
+	else
+		used_tree_add(ubi, e1);
+	ubi->move_from = ubi->move_to = NULL;
+	ubi->move_from_put = ubi->move_to_put = 0;
+	spin_unlock(&ubi->wl_lock);
+
+	if (put) {
+		/*
+		 * Well, the target PEB was put meanwhile, schedule it for
+		 * erasure.
+		 */
+		dbg_wl("PEB %d was put meanwhile, erase", e1->pnum);
+		err = schedule_erase(ubi, e1, 0);
+		if (err) {
+			kmem_cache_free(wl_entries_slab, e1);
+			ubi_ro_mode(ubi);
+		}
+	}
+
+	err = schedule_erase(ubi, e2, 0);
+	if (err) {
+		kmem_cache_free(wl_entries_slab, e2);
+		ubi_ro_mode(ubi);
+	}
+
+	yield();
+	return err;
+}
+
+/**
+ * ensure_wear_leveling - schedule wear-leveling if it is needed.
+ * @ubi: UBI device description object
+ *
+ * This function checks if it is time to start wear-leveling and schedules it
+ * if yes. This function returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+static int ensure_wear_leveling(struct ubi_device *ubi)
+{
+	int err = 0;
+	struct ubi_wl_entry *e1;
+	struct ubi_wl_entry *e2;
+	struct ubi_work *wrk;
+
+	spin_lock(&ubi->wl_lock);
+	if (ubi->wl_scheduled)
+		/* Wear-leveling is already in the work queue */
+		goto out_unlock;
+
+	/*
+	 * If the ubi->scrub tree is not empty, scrubbing is needed, and the
+	 * the WL worker has to be scheduled anyway.
+	 */
+	if (tree_empty(&ubi->scrub)) {
+		if (tree_empty(&ubi->used) || tree_empty(&ubi->free))
+			/* No physical eraseblocks - no deal */
+			goto out_unlock;
+
+		/*
+		 * We schedule wear-leveling only if the difference between the
+		 * lowest erase counter of used physical eraseblocks and a high
+		 * erase counter of free physical eraseblocks is greater then
+		 * %UBI_WL_THRESHOLD.
+		 */
+		e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb);
+		e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+
+		if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD))
+			goto out_unlock;
+		dbg_wl("schedule wear-leveling");
+	} else
+		dbg_wl("schedule scrubbing");
+
+	ubi->wl_scheduled = 1;
+	spin_unlock(&ubi->wl_lock);
+
+	wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+	if (!wrk) {
+		err = -ENOMEM;
+		goto out_cancel;
+	}
+
+	wrk->func = &wear_leveling_worker;
+	schedule_ubi_work(ubi, wrk);
+	return err;
+
+out_cancel:
+	spin_lock(&ubi->wl_lock);
+	ubi->wl_scheduled = 0;
+out_unlock:
+	spin_unlock(&ubi->wl_lock);
+	return err;
+}
+
+/**
+ * erase_worker - physical eraseblock erase worker function.
+ * @ubi: UBI device description object
+ * @wl_wrk: the work object
+ * @cancel: non-zero if the worker has to free memory and exit
+ *
+ * This function erases a physical eraseblock and perform torture testing if
+ * needed. It also takes care about marking the physical eraseblock bad if
+ * needed. Returns zero in case of success and a negative error code in case of
+ * failure.
+ */
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+			int cancel)
+{
+	int err;
+	struct ubi_wl_entry *e = wl_wrk->e;
+	int pnum = e->pnum;
+
+	if (cancel) {
+		dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
+		kfree(wl_wrk);
+		kmem_cache_free(wl_entries_slab, e);
+		return 0;
+	}
+
+	dbg_wl("erase PEB %d EC %d", pnum, e->ec);
+
+	err = sync_erase(ubi, e, wl_wrk->torture);
+	if (!err) {
+		/* Fine, we've erased it successfully */
+		kfree(wl_wrk);
+
+		spin_lock(&ubi->wl_lock);
+		ubi->abs_ec += 1;
+		free_tree_add(ubi, e);
+		spin_unlock(&ubi->wl_lock);
+
+		/*
+		 * One more erase operation has happened, take care about protected
+		 * physical eraseblocks.
+		 */
+		check_protection_over(ubi);
+
+		/* And take care about wear-leveling */
+		err = ensure_wear_leveling(ubi);
+		return err;
+	}
+
+	kfree(wl_wrk);
+	kmem_cache_free(wl_entries_slab, e);
+
+	if (err != -EIO) {
+		/*
+		 * If this is not %-EIO, we have no idea what to do. Scheduling
+		 * this physical eraseblock for erasure again would cause
+		 * errors again and again. Well, lets switch to RO mode.
+		 */
+		ubi_ro_mode(ubi);
+		return err;
+	}
+
+	/* It is %-EIO, the PEB went bad */
+
+	if (!ubi->bad_allowed) {
+		ubi_err("bad physical eraseblock %d detected", pnum);
+		ubi_ro_mode(ubi);
+		err = -EIO;
+	} else {
+		int need;
+
+		spin_lock(&ubi->volumes_lock);
+		need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+		if (need > 0) {
+			need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+			ubi->avail_pebs -= need;
+			ubi->rsvd_pebs += need;
+			ubi->beb_rsvd_pebs += need;
+			if (need > 0)
+				ubi_msg("reserve more %d PEBs", need);
+		}
+
+		if (ubi->beb_rsvd_pebs == 0) {
+			spin_unlock(&ubi->volumes_lock);
+			ubi_err("no reserved physical eraseblocks");
+			ubi_ro_mode(ubi);
+			return -EIO;
+		}
+
+		spin_unlock(&ubi->volumes_lock);
+		ubi_msg("mark PEB %d as bad", pnum);
+
+		err = ubi_io_mark_bad(ubi, pnum);
+		if (err) {
+			ubi_ro_mode(ubi);
+			return err;
+		}
+
+		spin_lock(&ubi->volumes_lock);
+		ubi->beb_rsvd_pebs -= 1;
+		ubi->bad_peb_count += 1;
+		ubi->good_peb_count -= 1;
+		ubi_calculate_reserved(ubi);
+		if (ubi->beb_rsvd_pebs == 0)
+			ubi_warn("last PEB from the reserved pool was used");
+		spin_unlock(&ubi->volumes_lock);
+	}
+
+	return err;
+}
+
+/**
+ * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling
+ * unit.
+ * @ubi: UBI device description object
+ * @pnum: physical eraseblock to return
+ * @torture: if this physical eraseblock has to be tortured
+ *
+ * This function is called to return physical eraseblock @pnum to the pool of
+ * free physical eraseblocks. The @torture flag has to be set if an I/O error
+ * occurred to this @pnum and it has to be tested. This function returns zero
+ * in case of success and a negative error code in case of failure.
+ */
+int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
+{
+	int err;
+	struct ubi_wl_entry *e;
+
+	dbg_wl("PEB %d", pnum);
+	ubi_assert(pnum >= 0);
+	ubi_assert(pnum < ubi->peb_count);
+
+	spin_lock(&ubi->wl_lock);
+
+	e = ubi->lookuptbl[pnum];
+	if (e == ubi->move_from) {
+		/*
+		 * User is putting the physical eraseblock which was selected to
+		 * be moved. It will be scheduled for erasure in the
+		 * wear-leveling worker.
+		 */
+		dbg_wl("PEB %d is being moved", pnum);
+		ubi_assert(!ubi->move_from_put);
+		ubi->move_from_put = 1;
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	} else if (e == ubi->move_to) {
+		/*
+		 * User is putting the physical eraseblock which was selected
+		 * as the target the data is moved to. It may happen if the EBA
+		 * unit already re-mapped the LEB but the WL unit did has not
+		 * put the PEB to the "used" tree.
+		 */
+		dbg_wl("PEB %d is the target of data moving", pnum);
+		ubi_assert(!ubi->move_to_put);
+		ubi->move_to_put = 1;
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	} else {
+		if (in_wl_tree(e, &ubi->used))
+			used_tree_del(ubi, e);
+		else if (in_wl_tree(e, &ubi->scrub))
+			scrub_tree_del(ubi, e);
+		else
+			prot_tree_del(ubi, e->pnum);
+	}
+	spin_unlock(&ubi->wl_lock);
+
+	err = schedule_erase(ubi, e, torture);
+	if (err) {
+		spin_lock(&ubi->wl_lock);
+		used_tree_add(ubi, e);
+		spin_unlock(&ubi->wl_lock);
+	}
+
+	return err;
+}
+
+/**
+ * ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock to schedule
+ *
+ * If a bit-flip in a physical eraseblock is detected, this physical eraseblock
+ * needs scrubbing. This function schedules a physical eraseblock for
+ * scrubbing which is done in background. This function returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum)
+{
+	struct ubi_wl_entry *e;
+
+	ubi_msg("schedule PEB %d for scrubbing", pnum);
+
+retry:
+	spin_lock(&ubi->wl_lock);
+	e = ubi->lookuptbl[pnum];
+	if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub)) {
+		spin_unlock(&ubi->wl_lock);
+		return 0;
+	}
+
+	if (e == ubi->move_to) {
+		/*
+		 * This physical eraseblock was used to move data to. The data
+		 * was moved but the PEB was not yet inserted to the proper
+		 * tree. We should just wait a little and let the WL worker
+		 * proceed.
+		 */
+		spin_unlock(&ubi->wl_lock);
+		dbg_wl("the PEB %d is not in proper tree, retry", pnum);
+		yield();
+		goto retry;
+	}
+
+	if (in_wl_tree(e, &ubi->used))
+		used_tree_del(ubi, e);
+	else
+		prot_tree_del(ubi, pnum);
+
+	scrub_tree_add(ubi, e);
+	spin_unlock(&ubi->wl_lock);
+
+	/*
+	 * Technically scrubbing is the same as wear-leveling, so it is done
+	 * by the WL worker.
+	 */
+	return ensure_wear_leveling(ubi);
+}
+
+/**
+ * ubi_wl_flush - flush all pending works.
+ * @ubi: UBI device description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+int ubi_wl_flush(struct ubi_device *ubi)
+{
+	int err, pending_count;
+
+	pending_count = ubi->works_count;
+
+	dbg_wl("flush (%d pending works)", pending_count);
+
+	/*
+	 * Erase while the pending works queue is not empty, but not more then
+	 * the number of currently pending works.
+	 */
+	while (pending_count-- > 0) {
+		err = do_work(ubi);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * tree_destroy - destroy an RB-tree.
+ * @root: the root of the tree to destroy
+ */
+static void tree_destroy(struct rb_root *root)
+{
+	struct rb_node *rb;
+	struct ubi_wl_entry *e;
+
+	rb = root->rb_node;
+	while (rb) {
+		if (rb->rb_left)
+			rb = rb->rb_left;
+		else if (rb->rb_right)
+			rb = rb->rb_right;
+		else {
+			e = rb_entry(rb, struct ubi_wl_entry, rb);
+
+			rb = rb_parent(rb);
+			if (rb) {
+				if (rb->rb_left == &e->rb)
+					rb->rb_left = NULL;
+				else
+					rb->rb_right = NULL;
+			}
+
+			kmem_cache_free(wl_entries_slab, e);
+		}
+	}
+}
+
+/**
+ * ubi_thread - UBI background thread.
+ * @u: the UBI device description object pointer
+ */
+static int ubi_thread(void *u)
+{
+	int failures = 0;
+	struct ubi_device *ubi = u;
+
+	ubi_msg("background thread \"%s\" started, PID %d",
+		ubi->bgt_name, current->pid);
+
+	for (;;) {
+		int err;
+
+		if (kthread_should_stop())
+			goto out;
+
+		if (try_to_freeze())
+			continue;
+
+		spin_lock(&ubi->wl_lock);
+		if (list_empty(&ubi->works) || ubi->ro_mode ||
+			       !ubi->thread_enabled) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock(&ubi->wl_lock);
+			schedule();
+			continue;
+		}
+		spin_unlock(&ubi->wl_lock);
+
+		err = do_work(ubi);
+		if (err) {
+			ubi_err("%s: work failed with error code %d",
+				ubi->bgt_name, err);
+			if (failures++ > WL_MAX_FAILURES) {
+				/*
+				 * Too many failures, disable the thread and
+				 * switch to read-only mode.
+				 */
+				ubi_msg("%s: %d consecutive failures",
+					ubi->bgt_name, WL_MAX_FAILURES);
+				ubi_ro_mode(ubi);
+				break;
+			}
+		} else
+			failures = 0;
+
+		cond_resched();
+	}
+
+out:
+	dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
+	return 0;
+}
+
+/**
+ * cancel_pending - cancel all pending works.
+ * @ubi: UBI device description object
+ */
+static void cancel_pending(struct ubi_device *ubi)
+{
+	while (!list_empty(&ubi->works)) {
+		struct ubi_work *wrk;
+
+		wrk = list_entry(ubi->works.next, struct ubi_work, list);
+		list_del(&wrk->list);
+		wrk->func(ubi, wrk, 1);
+		ubi->works_count -= 1;
+		ubi_assert(ubi->works_count >= 0);
+	}
+}
+
+/**
+ * ubi_wl_init_scan - initialize the wear-leveling unit using scanning
+ * information.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This function returns zero in case of success, and a negative error code in
+ * case of failure.
+ */
+int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+{
+	int err;
+	struct rb_node *rb1, *rb2;
+	struct ubi_scan_volume *sv;
+	struct ubi_scan_leb *seb, *tmp;
+	struct ubi_wl_entry *e;
+
+
+	ubi->used = ubi->free = ubi->scrub = RB_ROOT;
+	ubi->prot.pnum = ubi->prot.aec = RB_ROOT;
+	spin_lock_init(&ubi->wl_lock);
+	ubi->max_ec = si->max_ec;
+	INIT_LIST_HEAD(&ubi->works);
+
+	sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
+
+	ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+	if (IS_ERR(ubi->bgt_thread)) {
+		err = PTR_ERR(ubi->bgt_thread);
+		ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+			err);
+		return err;
+	}
+
+	if (ubi_devices_cnt == 0) {
+		wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
+						    sizeof(struct ubi_wl_entry),
+						    0, 0, NULL, NULL);
+		if (!wl_entries_slab)
+			return -ENOMEM;
+	}
+
+	err = -ENOMEM;
+	ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL);
+	if (!ubi->lookuptbl)
+		goto out_free;
+
+	list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
+		cond_resched();
+
+		e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+		if (!e)
+			goto out_free;
+
+		e->pnum = seb->pnum;
+		e->ec = seb->ec;
+		ubi->lookuptbl[e->pnum] = e;
+		if (schedule_erase(ubi, e, 0)) {
+			kmem_cache_free(wl_entries_slab, e);
+			goto out_free;
+		}
+	}
+
+	list_for_each_entry(seb, &si->free, u.list) {
+		cond_resched();
+
+		e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+		if (!e)
+			goto out_free;
+
+		e->pnum = seb->pnum;
+		e->ec = seb->ec;
+		ubi_assert(e->ec >= 0);
+		free_tree_add(ubi, e);
+		ubi->lookuptbl[e->pnum] = e;
+	}
+
+	list_for_each_entry(seb, &si->corr, u.list) {
+		cond_resched();
+
+		e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+		if (!e)
+			goto out_free;
+
+		e->pnum = seb->pnum;
+		e->ec = seb->ec;
+		ubi->lookuptbl[e->pnum] = e;
+		if (schedule_erase(ubi, e, 0)) {
+			kmem_cache_free(wl_entries_slab, e);
+			goto out_free;
+		}
+	}
+
+	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+		ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+			cond_resched();
+
+			e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL);
+			if (!e)
+				goto out_free;
+
+			e->pnum = seb->pnum;
+			e->ec = seb->ec;
+			ubi->lookuptbl[e->pnum] = e;
+			if (!seb->scrub) {
+				dbg_wl("add PEB %d EC %d to the used tree",
+				       e->pnum, e->ec);
+				used_tree_add(ubi, e);
+			} else {
+				dbg_wl("add PEB %d EC %d to the scrub tree",
+				       e->pnum, e->ec);
+				scrub_tree_add(ubi, e);
+			}
+		}
+	}
+
+	if (WL_RESERVED_PEBS > ubi->avail_pebs) {
+		ubi_err("no enough physical eraseblocks (%d, need %d)",
+			ubi->avail_pebs, WL_RESERVED_PEBS);
+		goto out_free;
+	}
+	ubi->avail_pebs -= WL_RESERVED_PEBS;
+	ubi->rsvd_pebs += WL_RESERVED_PEBS;
+
+	/* Schedule wear-leveling if needed */
+	err = ensure_wear_leveling(ubi);
+	if (err)
+		goto out_free;
+
+	return 0;
+
+out_free:
+	cancel_pending(ubi);
+	tree_destroy(&ubi->used);
+	tree_destroy(&ubi->free);
+	tree_destroy(&ubi->scrub);
+	kfree(ubi->lookuptbl);
+	if (ubi_devices_cnt == 0)
+		kmem_cache_destroy(wl_entries_slab);
+	return err;
+}
+
+/**
+ * protection_trees_destroy - destroy the protection RB-trees.
+ * @ubi: UBI device description object
+ */
+static void protection_trees_destroy(struct ubi_device *ubi)
+{
+	struct rb_node *rb;
+	struct ubi_wl_prot_entry *pe;
+
+	rb = ubi->prot.aec.rb_node;
+	while (rb) {
+		if (rb->rb_left)
+			rb = rb->rb_left;
+		else if (rb->rb_right)
+			rb = rb->rb_right;
+		else {
+			pe = rb_entry(rb, struct ubi_wl_prot_entry, rb_aec);
+
+			rb = rb_parent(rb);
+			if (rb) {
+				if (rb->rb_left == &pe->rb_aec)
+					rb->rb_left = NULL;
+				else
+					rb->rb_right = NULL;
+			}
+
+			kmem_cache_free(wl_entries_slab, pe->e);
+			kfree(pe);
+		}
+	}
+}
+
+/**
+ * ubi_wl_close - close the wear-leveling unit.
+ * @ubi: UBI device description object
+ */
+void ubi_wl_close(struct ubi_device *ubi)
+{
+	dbg_wl("disable \"%s\"", ubi->bgt_name);
+	if (ubi->bgt_thread)
+		kthread_stop(ubi->bgt_thread);
+
+	dbg_wl("close the UBI wear-leveling unit");
+
+	cancel_pending(ubi);
+	protection_trees_destroy(ubi);
+	tree_destroy(&ubi->used);
+	tree_destroy(&ubi->free);
+	tree_destroy(&ubi->scrub);
+	kfree(ubi->lookuptbl);
+	if (ubi_devices_cnt == 1)
+		kmem_cache_destroy(wl_entries_slab);
+}
+
+#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+
+/**
+ * paranoid_check_ec - make sure that the erase counter of a physical eraseblock
+ * is correct.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to check
+ * @ec: the erase counter to check
+ *
+ * This function returns zero if the erase counter of physical eraseblock @pnum
+ * is equivalent to @ec, %1 if not, and a negative error code if an error
+ * occurred.
+ */
+static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
+{
+	int err;
+	long long read_ec;
+	struct ubi_ec_hdr *ec_hdr;
+
+	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+	if (!ec_hdr)
+		return -ENOMEM;
+
+	err = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0);
+	if (err && err != UBI_IO_BITFLIPS) {
+		/* The header does not have to exist */
+		err = 0;
+		goto out_free;
+	}
+
+	read_ec = ubi64_to_cpu(ec_hdr->ec);
+	if (ec != read_ec) {
+		ubi_err("paranoid check failed for PEB %d", pnum);
+		ubi_err("read EC is %lld, should be %d", read_ec, ec);
+		ubi_dbg_dump_stack();
+		err = 1;
+	} else
+		err = 0;
+
+out_free:
+	kfree(ec_hdr);
+	return err;
+}
+
+/**
+ * paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present
+ * in a WL RB-tree.
+ * @e: the wear-leveling entry to check
+ * @root: the root of the tree
+ *
+ * This function returns zero if @e is in the @root RB-tree and %1 if it
+ * is not.
+ */
+static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
+				     struct rb_root *root)
+{
+	if (in_wl_tree(e, root))
+		return 0;
+
+	ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
+		e->pnum, e->ec, root);
+	ubi_dbg_dump_stack();
+	return 1;
+}
+
+#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 06e3378..4bee99b 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -735,7 +735,6 @@ static void el_receive(struct net_device
 	else
 	{
     		skb_reserve(skb,2);	/* Force 16 byte alignment */
-		skb->dev = dev;
 		/*
 		 *	The read increments through the bytes. The interrupt
 		 *	handler will fix the pointer when it returns to
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 702bfb2..e985a85 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -615,7 +615,6 @@ static void receive_packet(struct net_de
 	if (test_and_set_bit(0, (void *) &adapter->dmaing))
 		printk(KERN_ERR "%s: rx blocked, DMA in progress, dir %d\n", dev->name, adapter->current_dma.direction);
 
-	skb->dev = dev;
 	adapter->current_dma.direction = 0;
 	adapter->current_dma.length = rlen;
 	adapter->current_dma.skb = skb;
@@ -1026,7 +1025,7 @@ static int send_packet(struct net_device
 	adapter->current_dma.start_time = jiffies;
 
 	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
-		memcpy(adapter->dma_buffer, skb->data, nlen);
+		skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
 		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
 		target = isa_virt_to_bus(adapter->dma_buffer);
 	}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 54e1d5a..eed4299 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -873,7 +873,6 @@ static void el16_rx(struct net_device *d
 			}
 
 			skb_reserve(skb,2);
-			skb->dev = dev;
 
 			/* 'skb->data' points to the start of sk_buff data area. */
 			memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index f791bf0..9588da3 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -83,7 +83,6 @@ #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
 #include <linux/spinlock.h>
@@ -1091,7 +1090,6 @@ el3_rx(struct net_device *dev)
 				printk("Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 			if (skb != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);     /* Align IP on 16 byte */
 
 				/* 'skb->data' points to the start of sk_buff data area. */
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index c307ce6..290166d 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -1292,7 +1292,6 @@ static int corkscrew_rx(struct net_devic
 				printk("Receiving packet size %d status %4.4x.\n",
 				     pkt_len, rx_status);
 			if (skb != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				insl(ioaddr + RX_FIFO,
@@ -1363,7 +1362,6 @@ static int boomerang_rx(struct net_devic
 			   copying to a properly sized skbuff. */
 			if (pkt_len < rx_copybreak
 			    && (skb = dev_alloc_skb(pkt_len + 4)) != 0) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 17d61eb..da1a22c 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -988,7 +988,6 @@ static void elmc_rcv_int(struct net_devi
 				rbd->status = 0;
 				skb = (struct sk_buff *) dev_alloc_skb(totlen + 2);
 				if (skb != NULL) {
-					skb->dev = dev;
 					skb_reserve(skb, 2);	/* 16 byte alignment */
 					skb_put(skb,totlen);
 					eth_copy_and_sum(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen,0);
@@ -1146,7 +1145,7 @@ #endif
 
 	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);
+	skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
 
 #if (NUM_XMIT_BUFFS == 1)
 #ifdef NO_NOPCOMMANDS
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 6c7437e..c7b571b 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1189,7 +1189,6 @@ static void mc32_rx_ring(struct net_devi
 			}
 
 			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;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index b406ecf..80924f7 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2414,7 +2414,6 @@ static int vortex_rx(struct net_device *
 				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
 					   pkt_len, rx_status);
 			if (skb != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				if (vp->bus_master &&
@@ -2491,7 +2490,6 @@ boomerang_rx(struct net_device *dev)
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
 			if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* 'skb_put()' points to the start of sk_buff data area. */
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 1b3d11e..0877fc3 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -331,7 +331,6 @@ #endif
                                 return 0;
                         }
 
-                        skb->dev = dev;
                         skb_reserve (skb, 2);           /* 16 byte align */
                         skb_put (skb, len);             /* make room */
                         eth_copy_and_sum(skb,
@@ -566,9 +565,9 @@ #endif
         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);
+	if (skb->len < ETH_ZLEN)
+		memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
+        skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
 
         /* Now, give the packet to the lance */
         ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 12c8453..e8c9f27 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -573,7 +573,6 @@ rx_status_loop:
 		}
 
 		skb_reserve(new_skb, RX_OFFSET);
-		new_skb->dev = dev;
 
 		pci_unmap_single(cp->pdev, mapping,
 				 buflen, PCI_DMA_FROMDEVICE);
@@ -807,7 +806,7 @@ #endif
 		if (mss)
 			flags |= LargeSend | ((mss & MSSMask) << MSSShift);
 		else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-			const struct iphdr *ip = skb->nh.iph;
+			const struct iphdr *ip = ip_hdr(skb);
 			if (ip->protocol == IPPROTO_TCP)
 				flags |= IPCS | TCPCS;
 			else if (ip->protocol == IPPROTO_UDP)
@@ -826,7 +825,7 @@ #endif
 		u32 first_len, first_eor;
 		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
-		const struct iphdr *ip = skb->nh.iph;
+		const struct iphdr *ip = ip_hdr(skb);
 
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
@@ -1082,7 +1081,6 @@ static int cp_refill_rx (struct cp_priva
 		if (!skb)
 			goto err_out;
 
-		skb->dev = cp->dev;
 		skb_reserve(skb, RX_OFFSET);
 
 		mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 99304b2..a844b1f 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1904,10 +1904,10 @@ static __inline__ void wrap_copy(struct 
 	u32 left = RX_BUF_LEN - offset;
 
 	if (size > left) {
-		memcpy(skb->data, ring + offset, left);
-		memcpy(skb->data+left, ring, size - left);
+		skb_copy_to_linear_data(skb, ring + offset, left);
+		skb_copy_to_linear_data_offset(skb, left, ring, size - left);
 	} else
-		memcpy(skb->data, ring + offset, size);
+		skb_copy_to_linear_data(skb, ring + offset, size);
 }
 #endif
 
@@ -2013,7 +2013,6 @@ no_early_rx:
 
 		skb = dev_alloc_skb (pkt_size + 2);
 		if (likely(skb)) {
-			skb->dev = dev;
 			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
 #if RX_BUF_IDX == 3
 			wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 640d7ca..3ff1155 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -830,7 +830,6 @@ memory_squeeze:
 				lp->stats.rx_dropped++;
 			}
 			else {
-				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
 					skb_reserve(skb, 2);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a3d46ea..b86ccd2 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -311,7 +311,7 @@ config MAC8390
 
 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
@@ -337,8 +337,8 @@ config MACSONIC
 	  be called macsonic.
 
 config MACMACE
-	bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)"
-	depends on NET_ETHERNET && MAC && EXPERIMENTAL
+	bool "Macintosh (AV) onboard MACE ethernet"
+	depends on NET_ETHERNET && MAC
 	select CRC32
 	help
 	  Support for the onboard AMD 79C940 MACE Ethernet controller used in
@@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM
 	  enables offloading for checksums on transmit.  If unsure, say Y.
 
 config MIPS_SIM_NET
-	tristate "MIPS simulator Network device (EXPERIMENTAL)"
-	depends on MIPS_SIM && EXPERIMENTAL
+	tristate "MIPS simulator Network device"
+	depends on NET_ETHERNET && MIPS_SIM
 	help
 	  The MIPSNET device is a simple Ethernet network device which is
 	  emulated by the MIPS Simulator.
@@ -822,7 +822,7 @@ config SMC91X
 	tristate "SMC 91C9x/91C1xxx support"
 	select CRC32
 	select MII
-	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00)
+	depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN)
 	help
 	  This is a driver for SMC's 91x series of Ethernet chipsets,
 	  including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -833,8 +833,8 @@ config SMC91X
 	  This driver is also available as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want).
 	  The module will be called smc91x.  If you want to compile it as a
-	  module, say M here and read <file:Documentation/modules.txt> as well
-	  as <file:Documentation/networking/net-modules.txt>.
+	  module, say M here and read <file:Documentation/kbuild/modules.txt>
+	  as well as <file:Documentation/networking/net-modules.txt>.
 
 config SMC9194
 	tristate "SMC 9194 support"
@@ -889,7 +889,7 @@ config SMC911X
 
 	  This driver is also available as a module. The module will be 
 	  called smc911x.  If you want to compile it as a module, say M 
-	  here and read <file:Documentation/modules.txt>
+	  here and read <file:Documentation/kbuild/modules.txt>
 
 config NET_VENDOR_RACAL
 	bool "Racal-Interlan (Micom) NI cards"
@@ -1104,7 +1104,7 @@ config ETH16I
 
 config NE2000
 	tristate "NE2000/NE1000 support"
-	depends on NET_ISA || (Q40 && m) || M32R
+	depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938
 	select CRC32
 	---help---
 	  If you have a network (Ethernet) card of this type, say Y and read
@@ -1444,7 +1444,8 @@ config CS89x0
 
 config TC35815
 	tristate "TOSHIBA TC35815 Ethernet support"
-	depends on NET_PCI && PCI && TOSHIBA_JMR3927
+	depends on NET_PCI && PCI && MIPS
+	select MII
 
 config DGRS
 	tristate "Digi Intl. RightSwitch SE-X support"
@@ -2273,11 +2274,12 @@ config GFAR_NAPI
 	depends on GIANFAR
 
 config UCC_GETH
-	tristate "Freescale QE UCC GETH"
-	depends on QUICC_ENGINE && UCC_FAST
+	tristate "Freescale QE Gigabit Ethernet"
+	depends on QUICC_ENGINE
+	select UCC_FAST
 	help
-	  This driver supports the Gigabit Ethernet mode of QE UCC.
-	  QE can be found on MPC836x CPUs.
+	  This driver supports the Gigabit Ethernet mode of the QUICC Engine,
+	  which is available on some Freescale SOCs.
 
 config UGETH_NAPI
 	bool "NAPI Support"
@@ -2291,14 +2293,10 @@ config UGETH_FILTERING
 	bool "Mac address filtering support"
 	depends on UCC_GETH
 
-config UGETH_TX_ON_DEMOND
-	bool "Transmit on Demond support"
+config UGETH_TX_ON_DEMAND
+	bool "Transmit on Demand support"
 	depends on UCC_GETH
 
-config UGETH_HAS_GIGA
-	bool
-	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 && PPC32)
@@ -2490,6 +2488,7 @@ config NETXEN_NIC
 config PASEMI_MAC
 	tristate "PA Semi 1/10Gbit MAC"
 	depends on PPC64 && PCI
+	select PHYLIB
 	help
 	  This driver supports the on-chip 1/10Gbit Ethernet controller on
 	  PA Semi's PWRficient line of chips.
@@ -2929,11 +2928,6 @@ endif #NETDEVICES
 config NETPOLL
 	def_bool NETCONSOLE
 
-config NETPOLL_RX
-	bool "Netpoll support for trapping incoming packets"
-	default n
-	depends on NETPOLL
-
 config NETPOLL_TRAP
 	bool "Netpoll traffic trapping"
 	default n
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 33af833..59c0459 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \
 		gianfar_sysfs.o
 
 obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
 
 #
 # link order important here
@@ -206,7 +206,7 @@ obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
 obj-$(CONFIG_NET_PCMCIA) += pcmcia/
-obj-$(CONFIG_NET_RADIO) += wireless/
+obj-y += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index dd8ed45..1c3e293 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -83,7 +83,6 @@ extern struct net_device *bagetlance_pro
 extern struct net_device *mvme147lance_probe(int unit);
 extern struct net_device *tc515_probe(int unit);
 extern struct net_device *lance_probe(int unit);
-extern struct net_device *mace_probe(int unit);
 extern struct net_device *mac8390_probe(int unit);
 extern struct net_device *mac89x0_probe(int unit);
 extern struct net_device *mc32_probe(int unit);
@@ -274,9 +273,6 @@ #endif
 #ifdef CONFIG_MVME147_NET	/* MVME147 internal Ethernet */
 	{mvme147lance_probe, 0},
 #endif
-#ifdef CONFIG_MACMACE		/* Mac 68k Quadra AV builtin Ethernet */
-	{mace_probe, 0},
-#endif
 #ifdef CONFIG_MAC8390           /* NuBus NS8390-based cards */
 	{mac8390_probe, 0},
 #endif
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index d76548e..81d5a37 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -320,7 +320,6 @@ #endif
 				return 0;
 			}
 
-			skb->dev = dev;
 			skb_reserve (skb, 2);		/* 16 byte align */
 			skb_put (skb, len);		/* make room */
 			eth_copy_and_sum(skb,
@@ -563,7 +562,6 @@ static int lance_start_xmit (struct sk_b
 	volatile struct lance_init_block *ib = lp->init_block;
 	int entry, skblen, len;
 	int status = 0;
-	static int outs;
 	unsigned long flags;
 
 	skblen = skb->len;
@@ -599,17 +597,16 @@ #endif
 	ib->btx_ring [entry].length = (-len) | 0xf000;
 	ib->btx_ring [entry].misc = 0;
 
-	memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+	skb_copy_from_linear_data(skb, (void *)&ib->tx_buf [entry][0], skblen);
 
 	/* Clear the slack of the packet, do I need this? */
 	if (len != skblen)
-		memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
+		memset ((void *) &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;
-
-	outs++;
+	lp->stats.tx_bytes += skblen;
 
 	if (TX_BUFFS_AVAIL <= 0)
 		netif_stop_queue(dev);
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 7138e0e..7122b7b 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2027,7 +2027,6 @@ static void ace_rx_int(struct net_device
 		 */
 		csum = retdesc->tcp_udp_csum;
 
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 
 		/*
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 962c954..675fe91 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -798,9 +798,7 @@ #endif
 			pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
 					 lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
 			skb_put(skb, pkt_len);
-			skb->dev = dev;
 			lp->rx_skbuff[rx_index] = new_skb;
-			new_skb->dev = dev;
 			lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
 								   new_skb->data,
 								   lp->rx_buff_len-2,
@@ -926,9 +924,7 @@ #endif
 		pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
 			lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
 		skb_put(skb, pkt_len);
-		skb->dev = dev;
 		lp->rx_skbuff[rx_index] = new_skb;
-		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);
 
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index dba5e51..da6ffa8 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -853,9 +853,9 @@ static void cops_rx(struct net_device *d
                 return;
         }
 
-        skb->mac.raw    = skb->data;    /* Point to entire packet. */
+        skb_reset_mac_header(skb);    /* Point to entire packet. */
         skb_pull(skb,3);
-        skb->h.raw      = skb->data;    /* Point to data (Skip header). */
+        skb_reset_transport_header(skb);    /* Point to data (Skip header). */
 
         /* Update the counters. */
         lp->stats.rx_packets++;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 2ea44ce..6a6cbd3 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -770,13 +770,13 @@ static int sendup_buffer (struct net_dev
 	skb->data[0] = dnode;
 	skb->data[1] = snode;
 	skb->data[2] = llaptype;
-	skb->mac.raw = skb->data;	/* save pointer to llap header */
+	skb_reset_mac_header(skb);	/* save pointer to llap header */
 	skb_pull(skb,3);
 
 	/* copy ddp(s,e)hdr + contents */
-	memcpy(skb->data,(void*)ltdmabuf,len);
+	skb_copy_to_linear_data(skb, ltdmabuf, len);
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	stats->rx_packets++;
 	stats->rx_bytes+=skb->len;
@@ -917,13 +917,14 @@ static int ltpc_xmit(struct sk_buff *skb
 
 	int i;
 	struct lt_sendlap cbuf;
+	unsigned char *hdr;
 
 	cbuf.command = LT_SENDLAP;
 	cbuf.dnode = skb->data[0];
 	cbuf.laptype = skb->data[2];
 	skb_pull(skb,3);	/* skip past LLAP header */
 	cbuf.length = skb->len;	/* this is host order */
-	skb->h.raw=skb->data;
+	skb_reset_transport_header(skb);
 
 	if(debug & DEBUG_UPPER) {
 		printk("command ");
@@ -932,11 +933,13 @@ static int ltpc_xmit(struct sk_buff *skb
 		printk("\n");
 	}
 
-	do_write(dev,&cbuf,sizeof(cbuf),skb->h.raw,skb->len);
+	hdr = skb_transport_header(skb);
+	do_write(dev, &cbuf, sizeof(cbuf), hdr, skb->len);
 
 	if(debug & DEBUG_UPPER) {
 		printk("sent %d ddp bytes\n",skb->len);
-		for(i=0;i<skb->len;i++) printk("%02x ",skb->h.raw[i]);
+		for (i = 0; i < skb->len; i++)
+			printk("%02x ", hdr[i]);
 		printk("\n");
 	}
 
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
index 6318814..e0a18e7 100644
--- a/drivers/net/arcnet/arc-rawmode.c
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -110,7 +110,7 @@ static void rx(struct net_device *dev, i
 
 	pkt = (struct archdr *) skb->data;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ARC_HDR_SIZE);
 
 	/* up to sizeof(pkt->soft) has already been copied from the card */
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 83004fd..681e20b 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -519,9 +519,12 @@ static int arcnet_header(struct sk_buff 
 		 * real header when we do rebuild_header.
 		 */
 		*(uint16_t *) skb_push(skb, 2) = type;
-		if (skb->nh.raw - skb->mac.raw != 2)
+		/*
+		 * XXX: Why not use skb->mac_len?
+		 */
+		if (skb->network_header - skb->mac_header != 2)
 			BUGMSG(D_NORMAL, "arcnet_header: Yikes!  diff (%d) is not 2!\n",
-			       (int)(skb->nh.raw - skb->mac.raw));
+			       (int)(skb->network_header - skb->mac_header));
 		return -2;	/* return error -- can't transmit yet! */
 	}
 	else {
@@ -554,11 +557,13 @@ static int arcnet_rebuild_header(struct 
 	unsigned short type;
 	uint8_t daddr=0;
 	struct ArcProto *proto;
-
-	if (skb->nh.raw - skb->mac.raw != 2) {
+	/*
+	 * XXX: Why not use skb->mac_len?
+	 */
+	if (skb->network_header - skb->mac_header != 2) {
 		BUGMSG(D_NORMAL,
-		     "rebuild_header: shouldn't be here! (hdrsize=%d)\n",
-		     (int)(skb->nh.raw - skb->mac.raw));
+		       "rebuild_header: shouldn't be here! (hdrsize=%d)\n",
+		       (int)(skb->network_header - skb->mac_header));
 		return 0;
 	}
 	type = *(uint16_t *) skb_pull(skb, 2);
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index 6648558..cc4610d 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -122,10 +122,8 @@ static void rx(struct net_device *dev, i
 	}
 	skb_put(skb, length + ARC_HDR_SIZE + sizeof(int));
 	skb->dev = dev;
-
-	pkt = (struct archdr *) skb->data;
-
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
+	pkt = (struct archdr *)skb_mac_header(skb);
 	skb_pull(skb, ARC_HDR_SIZE);
 
 	/* up to sizeof(pkt->soft) has already been copied from the card */
@@ -270,13 +268,13 @@ static int ack_tx(struct net_device *dev
   skb_put(ackskb, length + ARC_HDR_SIZE );
   ackskb->dev = dev;
 
-  ackpkt = (struct archdr *) ackskb->data;
-
-  ackskb->mac.raw = ackskb->data;
+  skb_reset_mac_header(ackskb);
+  ackpkt = (struct archdr *)skb_mac_header(ackskb);
   /* skb_pull(ackskb, ARC_HDR_SIZE); */
 
 
-  memcpy(ackpkt, lp->outgoing.skb->data, ARC_HDR_SIZE+sizeof(struct arc_cap));
+  skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
+		ARC_HDR_SIZE + sizeof(struct arc_cap));
   ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */
   ackpkt->soft.cap.mes.ack=acked;
 
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index 6d6c69f..2de8877 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -94,7 +94,7 @@ static unsigned short type_trans(struct 
 	int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE;
 
 	/* Pull off the arcnet header. */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, hdr_size);
 
 	if (pkt->hard.dest == 0)
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index bee3422..460a095 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -96,7 +96,7 @@ static unsigned short type_trans(struct 
 	int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE;
 
 	/* Pull off the arcnet header. */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, hdr_size);
 
 	if (pkt->hard.dest == 0)
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 9dfc09b..a241ae7 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -677,6 +677,7 @@ #endif
 	priv->cur_tx -= TX_RING_SIZE;
 	priv->dirty_tx -= TX_RING_SIZE;
     }
+    priv->stats.tx_bytes += len;
 
     /* Trigger an immediate send poll. */
     lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
@@ -743,7 +744,6 @@ static int ariadne_rx(struct net_device 
 	    }
 
 
-	    skb->dev = dev;
 	    skb_reserve(skb,2);		/* 16 byte align */
 	    skb_put(skb,pkt_len);	/* Make room */
 	    eth_copy_and_sum(skb, (char *)priv->rx_buff[entry], pkt_len,0);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index ddd12d4..8f0d7ce 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -526,7 +526,6 @@ am79c961_rx(struct net_device *dev, stru
 		skb = dev_alloc_skb(len + 2);
 
 		if (skb) {
-			skb->dev = dev;
 			skb_reserve(skb, 2);
 
 			am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 1621b8f..ef2cc80 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -225,6 +225,16 @@ static irqreturn_t at91ether_phy_interru
 		if (!(phy & ((1 << 2) | 1)))
 			goto done;
 	}
+	else if (lp->phy_type == MII_T78Q21x3_ID) {			/* ack interrupt in Teridian PHY */
+		read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
+		if (!(phy & ((1 << 2) | 1)))
+			goto done;
+	}
+	else if (lp->phy_type == MII_DP83848_ID) {
+		read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
+		if (!(phy & (1 << 7)))
+			goto done;
+	}
 
 	update_linkspeed(dev, 0);
 
@@ -280,6 +290,19 @@ static void enable_phyirq(struct net_dev
 		dsintr = (1 << 10) | ( 1 << 8);
 		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
 	}
+	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
+		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+		dsintr = dsintr | 0x500;		/* set bits 8, 10 */
+		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
+		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+		dsintr = dsintr | 0x3c;			/* set bits 2..5 */
+		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+		dsintr = dsintr | 0x3;			/* set bits 0,1 */
+		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+	}
 
 	disable_mdi();
 	spin_unlock_irq(&lp->lock);
@@ -323,6 +346,19 @@ static void disable_phyirq(struct net_de
 		dsintr = ~((1 << 10) | (1 << 8));
 		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
 	}
+	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
+		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+		dsintr = dsintr & ~0x500;			/* clear bits 8, 10 */
+		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+	}
+	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
+		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+		dsintr = dsintr & ~0x3;				/* clear bits 0, 1 */
+		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+		dsintr = dsintr & ~0x3c;			/* clear bits 2..5 */
+		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+	}
 
 	disable_mdi();
 	spin_unlock_irq(&lp->lock);
@@ -535,8 +571,8 @@ static void at91ether_sethashtable(struc
 		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
 	}
 
-	at91_emac_write(AT91_EMAC_HSH, mc_filter[0]);
-	at91_emac_write(AT91_EMAC_HSL, mc_filter[1]);
+	at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
+	at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
 }
 
 /*
@@ -858,7 +894,6 @@ static void at91ether_rx(struct net_devi
 			skb_reserve(skb, 2);
 			memcpy(skb_put(skb, pktlen), p_recv, pktlen);
 
-			skb->dev = dev;
 			skb->protocol = eth_type_trans(skb, dev);
 			dev->last_rx = jiffies;
 			lp->stats.rx_bytes += pktlen;
@@ -1063,10 +1098,16 @@ #endif
 		printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
 	else if (phy_type == MII_DP83847_ID)
 		printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+	else if (phy_type == MII_DP83848_ID)
+		printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
 	else if (phy_type == MII_AC101L_ID)
 		printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
 	else if (phy_type == MII_KS8721_ID)
 		printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+	else if (phy_type == MII_T78Q21x3_ID)
+		printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
+	else if (phy_type == MII_LAN83C185_ID)
+		printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
 
 	return 0;
 }
@@ -1104,8 +1145,11 @@ static int __init at91ether_probe(struct
 			case MII_RTL8201_ID:		/* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
 			case MII_BCM5221_ID:		/* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
 			case MII_DP83847_ID:		/* National Semiconductor DP83847:  */
+			case MII_DP83848_ID:		/* National Semiconductor DP83848:  */
 			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
 			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
+			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
 				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
 				break;
 		}
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
index b6b665d..a38fd2d 100644
--- a/drivers/net/arm/at91_ether.h
+++ b/drivers/net/arm/at91_ether.h
@@ -17,39 +17,46 @@ #define AT91_ETHERNET
 
 
 /* Davicom 9161 PHY */
-#define MII_DM9161_ID	0x0181b880
-#define MII_DM9161A_ID	0x0181b8a0
-
-/* Davicom specific registers */
-#define MII_DSCR_REG	16
-#define MII_DSCSR_REG	17
-#define MII_DSINTR_REG	21
+#define MII_DM9161_ID		0x0181b880
+#define MII_DM9161A_ID		0x0181b8a0
+#define MII_DSCR_REG		16
+#define MII_DSCSR_REG		17
+#define MII_DSINTR_REG		21
 
 /* Intel LXT971A PHY */
-#define MII_LXT971A_ID	0x001378E0
-
-/* Intel specific registers */
-#define MII_ISINTE_REG	18
-#define MII_ISINTS_REG	19
-#define MII_LEDCTRL_REG	20
+#define MII_LXT971A_ID		0x001378E0
+#define MII_ISINTE_REG		18
+#define MII_ISINTS_REG		19
+#define MII_LEDCTRL_REG		20
 
 /* Realtek RTL8201 PHY */
-#define MII_RTL8201_ID	0x00008200
+#define MII_RTL8201_ID		0x00008200
 
 /* Broadcom BCM5221 PHY */
-#define MII_BCM5221_ID	0x004061e0
-
-/* Broadcom specific registers */
-#define MII_BCMINTR_REG	26
+#define MII_BCM5221_ID		0x004061e0
+#define MII_BCMINTR_REG		26
 
 /* National Semiconductor DP83847 */
-#define MII_DP83847_ID	0x20005c30
+#define MII_DP83847_ID		0x20005c30
+
+/* National Semiconductor DP83848 */
+#define MII_DP83848_ID		0x20005c90
+#define MII_DPPHYSTS_REG	16
+#define MII_DPMICR_REG		17
+#define MII_DPMISR_REG		18
 
 /* Altima AC101L PHY */
-#define MII_AC101L_ID	0x00225520
+#define MII_AC101L_ID		0x00225520
 
 /* Micrel KS8721 PHY */
-#define MII_KS8721_ID	0x00221610
+#define MII_KS8721_ID		0x00221610
+
+/* Teridian 78Q2123/78Q2133 */
+#define MII_T78Q21x3_ID		0x000e7230
+#define MII_T78Q21INT_REG	17
+
+/* SMSC LAN83C185 */
+#define MII_LAN83C185_ID	0x0007C0A0
 
 /* ........................................................................ */
 
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index dd698b0..2438c5b 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -255,7 +255,6 @@ static int ep93xx_rx(struct net_device *
 
 		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);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index a292188..f075ceb 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -875,7 +875,6 @@ ether1_recv_done (struct net_device *dev
 			skb = dev_alloc_skb (length + 2);
 
 			if (skb) {
-				skb->dev = dev;
 				skb_reserve (skb, 2);
 
 				ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 8411783..32da2eb 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -661,7 +661,6 @@ if (next_ptr < RX_START || next_ptr >= R
 			if (skb) {
 				unsigned char *buf;
 
-				skb->dev = dev;
 				skb_reserve(skb, 2);
 				buf = skb_put(skb, length);
 				ether3_readbuffer(dev, buf + 12, length - 12);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 56ae8ba..bed8e0e 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -768,7 +768,6 @@ #endif
 				lp->stats.rx_dropped++;
 				break;
 			}
-			skb->dev = dev;
 			skb_reserve(skb,2);
 
 			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 4e3bf6a..3d87bd2 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -453,7 +453,8 @@ bionet_send_packet(struct sk_buff *skb, 
 		stdma_lock(bionet_intr, NULL);
 		local_irq_restore(flags);
 		if( !STRAM_ADDR(buf+length-1) ) {
-			memcpy(nic_packet->buffer, skb->data, length);
+			skb_copy_from_linear_data(skb, nic_packet->buffer,
+						  length);
 			buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
 		}
 
@@ -544,13 +545,13 @@ bionet_poll_rx(struct net_device *dev) {
 				break;
 			}
 
-			skb->dev = dev;
 			skb_reserve( skb, 2 );		/* 16 Byte align  */
 			skb_put( skb, pkt_len );	/* make room */
 
 			/* 'skb->data' points to the start of sk_buff data area.
 			 */
-			memcpy(skb->data, nic_packet->buffer, pkt_len);
+			skb_copy_to_linear_data(skb, nic_packet->buffer,
+						pkt_len);
 			skb->protocol = eth_type_trans( skb, dev );
 			netif_rx(skb);
 			dev->last_rx = jiffies;
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index 3b54361..5471440 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -717,7 +717,8 @@ pamsnet_send_packet(struct sk_buff *skb,
 
 		local_irq_restore(flags);
 		if( !STRAM_ADDR(buf+length-1) ) {
-			memcpy(nic_packet->buffer, skb->data, length);
+			skb_copy_from_linear_data(skb, nic_packet->buffer,
+						  length);
 			buf = (unsigned long)phys_nic_packet;
 		}
 
@@ -792,7 +793,8 @@ pamsnet_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_copy_to_linear_data(skb, nic_packet->buffer,
+						pkt_len);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 7e37ac8..dfa8b9b 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -1047,7 +1047,6 @@ static int lance_rx( struct net_device *
 						   pkt_len );
 				}
 
-				skb->dev = dev;
 				skb_reserve( skb, 2 );	/* 16 byte align */
 				skb_put( skb, pkt_len );	/* Make room */
 				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
index c11c277..1f616c5 100644
--- a/drivers/net/atl1/atl1_ethtool.c
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -156,8 +156,7 @@ static int atl1_set_settings(struct net_
 	u16 old_media_type = hw->media_type;
 
 	if (netif_running(adapter->netdev)) {
-		printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
-			atl1_driver_name);
+		dev_dbg(&adapter->pdev->dev, "ethtool shutting down adapter\n");
 		atl1_down(adapter);
 	}
 
@@ -166,9 +165,8 @@ static int atl1_set_settings(struct net_
 	else {
 		if (ecmd->speed == SPEED_1000) {
 			if (ecmd->duplex != DUPLEX_FULL) {
-				printk(KERN_WARNING
-				       "%s: can't force to 1000M half duplex\n",
-					atl1_driver_name);
+				dev_warn(&adapter->pdev->dev,
+					"can't force to 1000M half duplex\n");
 				ret_val = -EINVAL;
 				goto exit_sset;
 			}
@@ -206,9 +204,8 @@ static int atl1_set_settings(struct net_
 	}
 	if (atl1_phy_setup_autoneg_adv(hw)) {
 		ret_val = -EINVAL;
-		printk(KERN_WARNING
-			"%s: invalid ethtool speed/duplex setting\n",
-			atl1_driver_name);
+		dev_warn(&adapter->pdev->dev,
+			"invalid ethtool speed/duplex setting\n");
 		goto exit_sset;
 	}
 	if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
@@ -239,12 +236,10 @@ exit_sset:
 		hw->media_type = old_media_type;
 
 	if (netif_running(adapter->netdev)) {
-		printk(KERN_DEBUG "%s: ethtool starting adapter\n",
-			atl1_driver_name);
+		dev_dbg(&adapter->pdev->dev, "ethtool starting adapter\n");
 		atl1_up(adapter);
 	} else if (!ret_val) {
-		printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
-			atl1_driver_name);
+		dev_dbg(&adapter->pdev->dev, "ethtool resetting adapter\n");
 		atl1_reset(adapter);
 	}
 	return ret_val;
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
index 69482e0..ef886bd 100644
--- a/drivers/net/atl1/atl1_hw.c
+++ b/drivers/net/atl1/atl1_hw.c
@@ -2,20 +2,20 @@
  * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
  * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
  * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
- * 
+ *
  * Derived from Intel e1000 driver
  * Copyright(c) 1999 - 2005 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
  * more details.
- * 
+ *
  * You 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.
@@ -38,12 +38,13 @@ #include "atl1.h"
  */
 s32 atl1_reset_hw(struct atl1_hw *hw)
 {
+	struct pci_dev *pdev = hw->back->pdev;
 	u32 icr;
 	int i;
 
-	/* 
+	/*
 	 * Clear Interrupt mask to stop board from generating
-	 * interrupts & Clear any pending interrupt events 
+	 * interrupts & Clear any pending interrupt events
 	 */
 	/*
 	 * iowrite32(0, hw->hw_addr + REG_IMR);
@@ -74,7 +75,7 @@ s32 atl1_reset_hw(struct atl1_hw *hw)
 	}
 
 	if (icr) {
-		printk (KERN_DEBUG "icr = %x\n", icr); 
+		dev_dbg(&pdev->dev, "ICR = 0x%x\n", icr);
 		return icr;
 	}
 
@@ -136,8 +137,8 @@ s32 atl1_read_phy_reg(struct atl1_hw *hw
 	int i;
 
 	val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
-	    	MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
- 		MDIO_CLK_SEL_SHIFT;
+		MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+		MDIO_CLK_SEL_SHIFT;
 	iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
 	ioread32(hw->hw_addr + REG_MDIO_CTRL);
 
@@ -204,7 +205,7 @@ static bool atl1_spi_read(struct atl1_hw
 
 /*
  * get_permanent_address
- * return 0 if get valid mac address, 
+ * return 0 if get valid mac address,
  */
 static int atl1_get_permanent_address(struct atl1_hw *hw)
 {
@@ -301,7 +302,7 @@ static int atl1_get_permanent_address(st
 }
 
 /*
- * Reads the adapter's MAC address from the EEPROM 
+ * Reads the adapter's MAC address from the EEPROM
  * hw - Struct containing variables accessed by shared code
  */
 s32 atl1_read_mac_addr(struct atl1_hw *hw)
@@ -437,6 +438,7 @@ s32 atl1_phy_enter_power_saving(struct a
  */
 static s32 atl1_phy_reset(struct atl1_hw *hw)
 {
+	struct pci_dev *pdev = hw->back->pdev;
 	s32 ret_val;
 	u16 phy_data;
 
@@ -468,8 +470,7 @@ static s32 atl1_phy_reset(struct atl1_hw
 		u32 val;
 		int i;
 		/* pcie serdes link may be down! */
-		printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", 
-			atl1_driver_name);
+		dev_dbg(&pdev->dev, "pcie phy link down\n");
 
 		for (i = 0; i < 25; i++) {
 			msleep(1);
@@ -479,9 +480,7 @@ static s32 atl1_phy_reset(struct atl1_hw
 		}
 
 		if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
-			printk(KERN_WARNING 
-				"%s: pcie link down at least for 25ms\n", 
-				atl1_driver_name);
+			dev_warn(&pdev->dev, "pcie link down at least 25ms\n");
 			return ret_val;
 		}
 	}
@@ -571,6 +570,7 @@ s32 atl1_phy_setup_autoneg_adv(struct at
  */
 static s32 atl1_setup_link(struct atl1_hw *hw)
 {
+	struct pci_dev *pdev = hw->back->pdev;
 	s32 ret_val;
 
 	/*
@@ -581,15 +581,13 @@ static s32 atl1_setup_link(struct atl1_h
 	 */
 	ret_val = atl1_phy_setup_autoneg_adv(hw);
 	if (ret_val) {
-		printk(KERN_DEBUG "%s: error setting up autonegotiation\n", 
-			atl1_driver_name);
+		dev_dbg(&pdev->dev, "error setting up autonegotiation\n");
 		return ret_val;
 	}
 	/* SW.Reset , En-Auto-Neg if needed */
 	ret_val = atl1_phy_reset(hw);
 	if (ret_val) {
-		printk(KERN_DEBUG "%s: error resetting the phy\n", 
-			atl1_driver_name);
+		dev_dbg(&pdev->dev, "error resetting phy\n");
 		return ret_val;
 	}
 	hw->phy_configured = true;
@@ -631,7 +629,7 @@ static void atl1_init_flash_opcode(struc
  * Performs basic configuration of the adapter.
  * hw - Struct containing variables accessed by shared code
  * Assumes that the controller has previously been reset and is in a
- * post-reset uninitialized state. Initializes multicast table, 
+ * post-reset uninitialized state. Initializes multicast table,
  * and  Calls routines to setup link
  * Leaves the transmit and receive units disabled and uninitialized.
  */
@@ -669,6 +667,7 @@ s32 atl1_init_hw(struct atl1_hw *hw)
  */
 s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
 {
+	struct pci_dev *pdev = hw->back->pdev;
 	s32 ret_val;
 	u16 phy_data;
 
@@ -691,8 +690,7 @@ s32 atl1_get_speed_and_duplex(struct atl
 		*speed = SPEED_10;
 		break;
 	default:
-		printk(KERN_DEBUG "%s: error getting speed\n", 
-			atl1_driver_name);
+		dev_dbg(&pdev->dev, "error getting speed\n");
 		return ATL1_ERR_PHY_SPEED;
 		break;
 	}
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index 8606eac..d28f88b 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -188,8 +188,7 @@ s32 atl1_setup_ring_resources(struct atl
 	size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
 	tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
 	if (unlikely(!tpd_ring->buffer_info)) {
-		printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
-			atl1_driver_name, size);
+		dev_err(&pdev->dev, "kzalloc failed , size = D%d\n", size);
 		goto err_nomem;
 	}
 	rfd_ring->buffer_info =
@@ -207,9 +206,7 @@ s32 atl1_setup_ring_resources(struct atl
 	ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
 						&ring_header->dma);
 	if (unlikely(!ring_header->desc)) {
-		printk(KERN_WARNING
-			"%s: pci_alloc_consistent failed, size = D%d\n",
-			atl1_driver_name, size);
+		dev_err(&pdev->dev, "pci_alloc_consistent failed\n");
 		goto err_nomem;
 	}
 
@@ -373,8 +370,7 @@ static void atl1_rx_checksum(struct atl1
 		if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
 					ERR_FLAG_CODE | ERR_FLAG_OV)) {
 			adapter->hw_csum_err++;
-			printk(KERN_DEBUG "%s: rx checksum error\n",
-				atl1_driver_name);
+			dev_dbg(&adapter->pdev->dev, "rx checksum error\n");
 			return;
 		}
 	}
@@ -393,8 +389,9 @@ static void atl1_rx_checksum(struct atl1
 	}
 
 	/* IPv4, but hardware thinks its checksum is wrong */
-	printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
-		atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+	dev_dbg(&adapter->pdev->dev,
+		"hw csum wrong, pkt_flag:%x, err_flag:%x\n",
+		rrd->pkt_flg, rrd->err_flg);
 	skb->ip_summed = CHECKSUM_COMPLETE;
 	skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
 	adapter->hw_csum_err++;
@@ -408,7 +405,6 @@ static void atl1_rx_checksum(struct atl1
 static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
 {
 	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
-	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 	struct page *page;
 	unsigned long offset;
@@ -444,7 +440,6 @@ static u16 atl1_alloc_rx_buffers(struct 
 		 * the 14 byte MAC header is removed
 		 */
 		skb_reserve(skb, NET_IP_ALIGN);
-		skb->dev = netdev;
 
 		buffer_info->alloced = 1;
 		buffer_info->skb = skb;
@@ -509,14 +504,13 @@ chk_rrd:
 			/* rrd seems to be bad */
 			if (unlikely(i-- > 0)) {
 				/* rrd may not be DMAed completely */
-				printk(KERN_DEBUG
-					"%s: RRD may not be DMAed completely\n",
-					atl1_driver_name);
+				dev_dbg(&adapter->pdev->dev,
+					"incomplete RRD DMA transfer\n");
 				udelay(1);
 				goto chk_rrd;
 			}
 			/* bad rrd */
-			printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+			dev_dbg(&adapter->pdev->dev, "bad RRD\n");
 			/* see if update RFD index */
 			if (rrd->num_buf > 1) {
 				u16 num_buf;
@@ -687,8 +681,8 @@ static void atl1_check_for_link(struct a
 	/* notify upper layer link down ASAP */
 	if (!(phy_data & BMSR_LSTATUS)) {	/* Link Down */
 		if (netif_carrier_ok(netdev)) {	/* old link state: Up */
-			printk(KERN_INFO "%s: %s link is down\n",
-			       atl1_driver_name, netdev->name);
+			dev_info(&adapter->pdev->dev, "%s link is down\n",
+				netdev->name);
 			adapter->link_speed = SPEED_0;
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
@@ -733,8 +727,8 @@ static irqreturn_t atl1_intr(int irq, vo
 
 		/* check if PCIE PHY Link down */
 		if (status & ISR_PHY_LINKDOWN) {
-			printk(KERN_DEBUG "%s: pcie phy link down %x\n",
-				atl1_driver_name, status);
+			dev_dbg(&adapter->pdev->dev, "pcie phy link down %x\n",
+				status);
 			if (netif_running(adapter->netdev)) {	/* reset MAC */
 				iowrite32(0, adapter->hw.hw_addr + REG_IMR);
 				schedule_work(&adapter->pcie_dma_to_rst_task);
@@ -744,9 +738,9 @@ static irqreturn_t atl1_intr(int irq, vo
 
 		/* check if DMA read/write error ? */
 		if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
-			printk(KERN_DEBUG
-				"%s: pcie DMA r/w error (status = 0x%x)\n",
-				atl1_driver_name, status);
+			dev_dbg(&adapter->pdev->dev,
+				"pcie DMA r/w error (status = 0x%x)\n",
+				status);
 			iowrite32(0, adapter->hw.hw_addr + REG_IMR);
 			schedule_work(&adapter->pcie_dma_to_rst_task);
 			return IRQ_HANDLED;
@@ -764,14 +758,13 @@ static irqreturn_t atl1_intr(int irq, vo
 
 		/* rx exception */
 		if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+			ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+			ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+			if (status & (ISR_RXF_OV | ISR_RFD_UNRUN |
 				ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
-				ISR_HOST_RRD_OV | ISR_CMB_RX))) {
-			if (status &
-			    (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
-			     ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
-				printk(KERN_INFO
-					"%s: rx exception: status = 0x%x\n",
-					atl1_driver_name, status);
+				ISR_HOST_RRD_OV))
+				dev_dbg(&adapter->pdev->dev,
+					"rx exception, ISR = 0x%x\n", status);
 			atl1_intr_rx(adapter);
 		}
 
@@ -876,8 +869,7 @@ static u32 atl1_check_link(struct atl1_a
 	atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
 	if (!(phy_data & BMSR_LSTATUS)) {	/* link down */
 		if (netif_carrier_ok(netdev)) {	/* old link state: Up */
-			printk(KERN_INFO "%s: link is down\n",
-				atl1_driver_name);
+			dev_info(&adapter->pdev->dev, "link is down\n");
 			adapter->link_speed = SPEED_0;
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
@@ -920,11 +912,11 @@ static u32 atl1_check_link(struct atl1_a
 			adapter->link_speed = speed;
 			adapter->link_duplex = duplex;
 			atl1_setup_mac_ctrl(adapter);
-			printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
-			       atl1_driver_name, netdev->name,
-			       adapter->link_speed,
-			       adapter->link_duplex ==
-			       FULL_DUPLEX ? "full duplex" : "half duplex");
+			dev_info(&adapter->pdev->dev,
+				"%s link is up %d Mbps %s\n",
+				netdev->name, adapter->link_speed,
+				adapter->link_duplex == FULL_DUPLEX ?
+				"full duplex" : "half duplex");
 		}
 		if (!netif_carrier_ok(netdev)) {	/* Link down -> Up */
 			netif_carrier_on(netdev);
@@ -1296,19 +1288,21 @@ static int atl1_tso(struct atl1_adapter 
 		}
 
 		if (skb->protocol == ntohs(ETH_P_IP)) {
-			skb->nh.iph->tot_len = 0;
-			skb->nh.iph->check = 0;
-			skb->h.th->check =
-			    ~csum_tcpudp_magic(skb->nh.iph->saddr,
-					       skb->nh.iph->daddr, 0,
-					       IPPROTO_TCP, 0);
-			ipofst = skb->nh.raw - skb->data;
+			struct iphdr *iph = ip_hdr(skb);
+
+			iph->tot_len = 0;
+			iph->check = 0;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
+			ipofst = skb_network_offset(skb);
 			if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
 				tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
 
-			tso->tsopl |= (skb->nh.iph->ihl &
+			tso->tsopl |= (iph->ihl &
 				CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
-			tso->tsopl |= ((skb->h.th->doff << 2) &
+			tso->tsopl |= (tcp_hdrlen(skb) &
 				TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
 			tso->tsopl |= (skb_shinfo(skb)->gso_size &
 				TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
@@ -1327,11 +1321,11 @@ static int atl1_tx_csum(struct atl1_adap
 	u8 css, cso;
 
 	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
-		cso = skb->h.raw - skb->data;
-		css = (skb->h.raw + skb->csum_offset) - skb->data;
+		cso = skb_transport_offset(skb);
+		css = cso + skb->csum_offset;
 		if (unlikely(cso & 0x1)) {
-			printk(KERN_DEBUG "%s: payload offset != even number\n",
-				atl1_driver_name);
+			dev_dbg(&adapter->pdev->dev,
+				"payload offset not an even number\n");
 			return -1;
 		}
 		csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
@@ -1370,8 +1364,7 @@ static void atl1_tx_map(struct atl1_adap
 
 	if (tcp_seg) {
 		/* TSO/GSO */
-		proto_hdr_len =
-		    ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 		buffer_info->length = proto_hdr_len;
 		page = virt_to_page(skb->data);
 		offset = (unsigned long)skb->data & ~PAGE_MASK;
@@ -1563,8 +1556,8 @@ static int atl1_xmit_frame(struct sk_buf
 	mss = skb_shinfo(skb)->gso_size;
 	if (mss) {
 		if (skb->protocol == htons(ETH_P_IP)) {
-			proto_hdr_len = ((skb->h.raw - skb->data) +
-					 (skb->h.th->doff << 2));
+			proto_hdr_len = (skb_transport_offset(skb) +
+					 tcp_hdrlen(skb));
 			if (unlikely(proto_hdr_len > len)) {
 				dev_kfree_skb_any(skb);
 				return NETDEV_TX_OK;
@@ -1580,7 +1573,7 @@ static int atl1_xmit_frame(struct sk_buf
 	if (!spin_trylock(&adapter->lock)) {
 		/* Can't get lock - tell upper layer to requeue */
 		local_irq_restore(flags);
-		printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+		dev_dbg(&adapter->pdev->dev, "tx locked\n");
 		return NETDEV_TX_LOCKED;
 	}
 
@@ -1588,7 +1581,7 @@ static int atl1_xmit_frame(struct sk_buf
 		/* not enough descriptors */
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&adapter->lock, flags);
-		printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+		dev_dbg(&adapter->pdev->dev, "tx busy\n");
 		return NETDEV_TX_BUSY;
 	}
 
@@ -1842,8 +1835,7 @@ static int atl1_change_mtu(struct net_de
 
 	if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
 	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-		printk(KERN_WARNING "%s: invalid MTU setting\n",
-			atl1_driver_name);
+		dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
 		return -EINVAL;
 	}
 
@@ -2137,9 +2129,7 @@ static int __devinit atl1_probe(struct p
 	if (err) {
 		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (err) {
-			printk(KERN_DEBUG
-				"%s: no usable DMA configuration, aborting\n",
-				atl1_driver_name);
+			dev_err(&pdev->dev, "no usable DMA configuration\n");
 			goto err_dma;
 		}
 		pci_using_64 = false;
@@ -2176,7 +2166,9 @@ static int __devinit atl1_probe(struct p
 		goto err_pci_iomap;
 	}
 	/* get device revision number */
-	adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+	adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr +
+					(REG_MASTER_CTRL + 2));
+	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 
 	/* set default ring resource counts */
 	adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
@@ -2467,8 +2459,6 @@ static void __exit atl1_exit_module(void
  */
 static int __init atl1_init_module(void)
 {
-	printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
-	printk(KERN_INFO "%s\n", atl1_copyright);
 	return pci_register_driver(&atl1_driver);
 }
 
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
index c407214..4246bb9 100644
--- a/drivers/net/atl1/atl1_param.c
+++ b/drivers/net/atl1/atl1_param.c
@@ -22,8 +22,8 @@
  */
 
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/pci.h>
 #include "atl1.h"
 
 /*
@@ -94,7 +94,7 @@ struct atl1_option {
 	} arg;
 };
 
-static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, struct pci_dev *pdev)
 {
 	if (*value == OPTION_UNSET) {
 		*value = opt->def;
@@ -105,19 +105,17 @@ static int __devinit atl1_validate_optio
 	case enable_option:
 		switch (*value) {
 		case OPTION_ENABLED:
-			printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
-				opt->name);
+			dev_info(&pdev->dev, "%s enabled\n", opt->name);
 			return 0;
 		case OPTION_DISABLED:
-			printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
-				opt->name);
+			dev_info(&pdev->dev, "%s disabled\n", opt->name);
 			return 0;
 		}
 		break;
 	case range_option:
 		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
-			printk(KERN_INFO "%s: %s set to %i\n",
-				atl1_driver_name, opt->name, *value);
+			dev_info(&pdev->dev, "%s set to %i\n", opt->name,
+				*value);
 			return 0;
 		}
 		break;
@@ -129,8 +127,8 @@ static int __devinit atl1_validate_optio
 				ent = &opt->arg.l.p[i];
 				if (*value == ent->i) {
 					if (ent->str[0] != '\0')
-						printk(KERN_INFO "%s: %s\n",
-						       atl1_driver_name, ent->str);
+						dev_info(&pdev->dev, "%s\n",
+							ent->str);
 					return 0;
 				}
 			}
@@ -141,8 +139,8 @@ static int __devinit atl1_validate_optio
 		break;
 	}
 
-	printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
-	       atl1_driver_name, opt->name, *value, opt->err);
+	dev_info(&pdev->dev, "invalid %s specified (%i) %s\n",
+		opt->name, *value, opt->err);
 	*value = opt->def;
 	return -1;
 }
@@ -158,12 +156,11 @@ static int __devinit atl1_validate_optio
  */
 void __devinit atl1_check_options(struct atl1_adapter *adapter)
 {
+	struct pci_dev *pdev = adapter->pdev;
 	int bd = adapter->bd_number;
 	if (bd >= ATL1_MAX_NIC) {
-		printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
-			atl1_driver_name, bd);
-		printk(KERN_NOTICE "%s: using defaults for all values\n",
-			atl1_driver_name);
+		dev_notice(&pdev->dev, "no configuration for board#%i\n", bd);
+		dev_notice(&pdev->dev, "using defaults for all values\n");
 	}
 	{			/* Interrupt Moderate Timer */
 		struct atl1_option opt = {
@@ -178,7 +175,7 @@ void __devinit atl1_check_options(struct
 		int val;
 		if (num_int_mod_timer > bd) {
 			val = int_mod_timer[bd];
-			atl1_validate_option(&val, &opt);
+			atl1_validate_option(&val, &opt, pdev);
 			adapter->imt = (u16) val;
 		} else
 			adapter->imt = (u16) (opt.def);
@@ -198,7 +195,7 @@ void __devinit atl1_check_options(struct
 		int val;
 		if (num_flash_vendor > bd) {
 			val = flash_vendor[bd];
-			atl1_validate_option(&val, &opt);
+			atl1_validate_option(&val, &opt, pdev);
 			adapter->hw.flash_vendor = (u8) val;
 		} else
 			adapter->hw.flash_vendor = (u8) (opt.def);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 2d306fc..18aba83 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -793,7 +793,6 @@ static void net_rx(struct net_device *de
 			lp->stats.rx_dropped++;
 			goto done;
 		}
-		skb->dev = dev;
 
 		skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 		read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 69ae229..c39ab80 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -45,7 +45,6 @@ #include <linux/ioport.h>
 #include <linux/bitops.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>
@@ -1125,7 +1124,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);
+	skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
 	if (skb->len < ETH_ZLEN) {
 		for (i=skb->len; i<ETH_ZLEN; i++) {
 			((char *)pDB->vaddr)[i] = 0;
@@ -1205,7 +1204,6 @@ static int au1000_rx(struct net_device *
 				aup->stats.rx_dropped++;
 				continue;
 			}
-			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte IP header align */
 			eth_copy_and_sum(skb,
 				(unsigned char *)pDB->vaddr, frmlen, 0);
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index d742bfe..879a2ff 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -825,12 +825,11 @@ static int b44_rx(struct b44 *bp, int bu
 			if (copy_skb == NULL)
 				goto drop_it_no_recycle;
 
-			copy_skb->dev = bp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			/* DMA sync done above, copy just the actual packet */
-			memcpy(copy_skb->data, skb->data+bp->rx_offset, len);
-
+			skb_copy_from_linear_data_offset(skb, bp->rx_offset,
+							 copy_skb->data, len);
 			skb = copy_skb;
 		}
 		skb->ip_summed = CHECKSUM_NONE;
@@ -1007,7 +1006,8 @@ static int b44_start_xmit(struct sk_buff
 			goto err_out;
 		}
 
-		memcpy(skb_put(bounce_skb, len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(bounce_skb, len),
+					  skb->len);
 		dev_kfree_skb_any(skb);
 		skb = bounce_skb;
 	}
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index c143304..9b8d7d9 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -715,7 +715,6 @@ static irqreturn_t bmac_rxdma_intr(int i
 		if (skb != NULL) {
 			nb -= ETHERCRC;
 			skb_put(skb, nb);
-			skb->dev = dev;
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
@@ -1261,9 +1260,10 @@ static int __devinit bmac_probe(struct m
 		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
 		return -ENODEV;
 	}
-	prop_addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
+	prop_addr = of_get_property(macio_get_of_node(mdev),
+			"mac-address", NULL);
 	if (prop_addr == NULL) {
-		prop_addr = get_property(macio_get_of_node(mdev),
+		prop_addr = of_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");
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index e85f5ec..88b33c6 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1,6 +1,6 @@
 /* bnx2.c: Broadcom NX2 network driver.
  *
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004-2007 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
@@ -54,8 +54,8 @@ #include "bnx2_fw2.h"
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.5.8"
-#define DRV_MODULE_RELDATE	"April 24, 2007"
+#define DRV_MODULE_VERSION	"1.5.10"
+#define DRV_MODULE_RELDATE	"May 1, 2007"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -84,6 +84,7 @@ typedef enum {
 	BCM5708,
 	BCM5708S,
 	BCM5709,
+	BCM5709S,
 } board_t;
 
 /* indexed by board_t, above */
@@ -98,6 +99,7 @@ static const struct {
 	{ "Broadcom NetXtreme II BCM5708 1000Base-T" },
 	{ "Broadcom NetXtreme II BCM5708 1000Base-SX" },
 	{ "Broadcom NetXtreme II BCM5709 1000Base-T" },
+	{ "Broadcom NetXtreme II BCM5709 1000Base-SX" },
 	};
 
 static struct pci_device_id bnx2_pci_tbl[] = {
@@ -117,6 +119,8 @@ static struct pci_device_id bnx2_pci_tbl
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
 	{ 0, }
 };
 
@@ -230,21 +234,29 @@ static inline u32 bnx2_tx_avail(struct b
 static u32
 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
 {
+	u32 val;
+
+	spin_lock_bh(&bp->indirect_lock);
 	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
-	return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
+	val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
+	spin_unlock_bh(&bp->indirect_lock);
+	return val;
 }
 
 static void
 bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
 {
+	spin_lock_bh(&bp->indirect_lock);
 	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
 	REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
+	spin_unlock_bh(&bp->indirect_lock);
 }
 
 static void
 bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
 {
 	offset += cid_addr;
+	spin_lock_bh(&bp->indirect_lock);
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 		int i;
 
@@ -262,6 +274,7 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_add
 		REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
 		REG_WR(bp, BNX2_CTX_DATA, val);
 	}
+	spin_unlock_bh(&bp->indirect_lock);
 }
 
 static int
@@ -572,8 +585,8 @@ bnx2_report_fw_link(struct bnx2 *bp)
 		if (bp->autoneg) {
 			fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
 
-			bnx2_read_phy(bp, MII_BMSR, &bmsr);
-			bnx2_read_phy(bp, MII_BMSR, &bmsr);
+			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
 
 			if (!(bmsr & BMSR_ANEGCOMPLETE) ||
 			    bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
@@ -654,8 +667,8 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
 		return;
 	}
 
-	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
-	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
 
 	if (bp->phy_flags & PHY_SERDES_FLAG) {
 		u32 new_local_adv = 0;
@@ -700,6 +713,45 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
 }
 
 static int
+bnx2_5709s_linkup(struct bnx2 *bp)
+{
+	u32 val, speed;
+
+	bp->link_up = 1;
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
+	bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+	if ((bp->autoneg & AUTONEG_SPEED) == 0) {
+		bp->line_speed = bp->req_line_speed;
+		bp->duplex = bp->req_duplex;
+		return 0;
+	}
+	speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
+	switch (speed) {
+		case MII_BNX2_GP_TOP_AN_SPEED_10:
+			bp->line_speed = SPEED_10;
+			break;
+		case MII_BNX2_GP_TOP_AN_SPEED_100:
+			bp->line_speed = SPEED_100;
+			break;
+		case MII_BNX2_GP_TOP_AN_SPEED_1G:
+		case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
+			bp->line_speed = SPEED_1000;
+			break;
+		case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
+			bp->line_speed = SPEED_2500;
+			break;
+	}
+	if (val & MII_BNX2_GP_TOP_AN_FD)
+		bp->duplex = DUPLEX_FULL;
+	else
+		bp->duplex = DUPLEX_HALF;
+	return 0;
+}
+
+static int
 bnx2_5708s_linkup(struct bnx2 *bp)
 {
 	u32 val;
@@ -736,7 +788,7 @@ bnx2_5706s_linkup(struct bnx2 *bp)
 	bp->link_up = 1;
 	bp->line_speed = SPEED_1000;
 
-	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 	if (bmcr & BMCR_FULLDPLX) {
 		bp->duplex = DUPLEX_FULL;
 	}
@@ -748,8 +800,8 @@ bnx2_5706s_linkup(struct bnx2 *bp)
 		return 0;
 	}
 
-	bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
-	bnx2_read_phy(bp, MII_LPA, &remote_adv);
+	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
 
 	common = local_adv & remote_adv;
 	if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
@@ -770,7 +822,7 @@ bnx2_copper_linkup(struct bnx2 *bp)
 {
 	u32 bmcr;
 
-	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 	if (bmcr & BMCR_ANENABLE) {
 		u32 local_adv, remote_adv, common;
 
@@ -787,8 +839,8 @@ bnx2_copper_linkup(struct bnx2 *bp)
 			bp->duplex = DUPLEX_HALF;
 		}
 		else {
-			bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
-			bnx2_read_phy(bp, MII_LPA, &remote_adv);
+			bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+			bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
 
 			common = local_adv & remote_adv;
 			if (common & ADVERTISE_100FULL) {
@@ -898,6 +950,145 @@ bnx2_set_mac_link(struct bnx2 *bp)
 	return 0;
 }
 
+static void
+bnx2_enable_bmsr1(struct bnx2 *bp)
+{
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5709))
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_GP_STATUS);
+}
+
+static void
+bnx2_disable_bmsr1(struct bnx2 *bp)
+{
+	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	    (CHIP_NUM(bp) == CHIP_NUM_5709))
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+}
+
+static int
+bnx2_test_and_enable_2g5(struct bnx2 *bp)
+{
+	u32 up1;
+	int ret = 1;
+
+	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+		return 0;
+
+	if (bp->autoneg & AUTONEG_SPEED)
+		bp->advertising |= ADVERTISED_2500baseX_Full;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
+	bnx2_read_phy(bp, bp->mii_up1, &up1);
+	if (!(up1 & BCM5708S_UP1_2G5)) {
+		up1 |= BCM5708S_UP1_2G5;
+		bnx2_write_phy(bp, bp->mii_up1, up1);
+		ret = 0;
+	}
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+	return ret;
+}
+
+static int
+bnx2_test_and_disable_2g5(struct bnx2 *bp)
+{
+	u32 up1;
+	int ret = 0;
+
+	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+		return 0;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
+	bnx2_read_phy(bp, bp->mii_up1, &up1);
+	if (up1 & BCM5708S_UP1_2G5) {
+		up1 &= ~BCM5708S_UP1_2G5;
+		bnx2_write_phy(bp, bp->mii_up1, up1);
+		ret = 1;
+	}
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+	return ret;
+}
+
+static void
+bnx2_enable_forced_2g5(struct bnx2 *bp)
+{
+	u32 bmcr;
+
+	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+		return;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		u32 val;
+
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_SERDES_DIG);
+		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+		val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
+		val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
+		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		bmcr |= BCM5708S_BMCR_FORCE_2500;
+	}
+
+	if (bp->autoneg & AUTONEG_SPEED) {
+		bmcr &= ~BMCR_ANENABLE;
+		if (bp->req_duplex == DUPLEX_FULL)
+			bmcr |= BMCR_FULLDPLX;
+	}
+	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
+}
+
+static void
+bnx2_disable_forced_2g5(struct bnx2 *bp)
+{
+	u32 bmcr;
+
+	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+		return;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		u32 val;
+
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_SERDES_DIG);
+		bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+		val &= ~MII_BNX2_SD_MISC1_FORCE;
+		bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		bmcr &= ~BCM5708S_BMCR_FORCE_2500;
+	}
+
+	if (bp->autoneg & AUTONEG_SPEED)
+		bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
+	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
+}
+
 static int
 bnx2_set_link(struct bnx2 *bp)
 {
@@ -911,8 +1102,10 @@ bnx2_set_link(struct bnx2 *bp)
 
 	link_up = bp->link_up;
 
-	bnx2_read_phy(bp, MII_BMSR, &bmsr);
-	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	bnx2_enable_bmsr1(bp);
+	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+	bnx2_disable_bmsr1(bp);
 
 	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
 	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
@@ -933,6 +1126,8 @@ bnx2_set_link(struct bnx2 *bp)
 				bnx2_5706s_linkup(bp);
 			else if (CHIP_NUM(bp) == CHIP_NUM_5708)
 				bnx2_5708s_linkup(bp);
+			else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+				bnx2_5709s_linkup(bp);
 		}
 		else {
 			bnx2_copper_linkup(bp);
@@ -941,17 +1136,9 @@ bnx2_set_link(struct bnx2 *bp)
 	}
 	else {
 		if ((bp->phy_flags & PHY_SERDES_FLAG) &&
-			(bp->autoneg & AUTONEG_SPEED)) {
+		    (bp->autoneg & AUTONEG_SPEED))
+			bnx2_disable_forced_2g5(bp);
 
-			u32 bmcr;
-
-			bnx2_read_phy(bp, MII_BMCR, &bmcr);
-			bmcr &= ~BCM5708S_BMCR_FORCE_2500;
-			if (!(bmcr & BMCR_ANENABLE)) {
-				bnx2_write_phy(bp, MII_BMCR, bmcr |
-					BMCR_ANENABLE);
-			}
-		}
 		bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
 		bp->link_up = 0;
 	}
@@ -971,13 +1158,13 @@ bnx2_reset_phy(struct bnx2 *bp)
 	int i;
 	u32 reg;
 
-        bnx2_write_phy(bp, MII_BMCR, BMCR_RESET);
+        bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
 
 #define PHY_RESET_MAX_WAIT 100
 	for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
 		udelay(10);
 
-		bnx2_read_phy(bp, MII_BMCR, &reg);
+		bnx2_read_phy(bp, bp->mii_bmcr, &reg);
 		if (!(reg & BMCR_RESET)) {
 			udelay(20);
 			break;
@@ -1026,34 +1213,40 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
 static int
 bnx2_setup_serdes_phy(struct bnx2 *bp)
 {
-	u32 adv, bmcr, up1;
+	u32 adv, bmcr;
 	u32 new_adv = 0;
 
 	if (!(bp->autoneg & AUTONEG_SPEED)) {
 		u32 new_bmcr;
 		int force_link_down = 0;
 
-		bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+		if (bp->req_line_speed == SPEED_2500) {
+			if (!bnx2_test_and_enable_2g5(bp))
+				force_link_down = 1;
+		} else if (bp->req_line_speed == SPEED_1000) {
+			if (bnx2_test_and_disable_2g5(bp))
+				force_link_down = 1;
+		}
+		bnx2_read_phy(bp, bp->mii_adv, &adv);
 		adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
 
-		bnx2_read_phy(bp, MII_BMCR, &bmcr);
-		new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500);
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+		new_bmcr = bmcr & ~BMCR_ANENABLE;
 		new_bmcr |= BMCR_SPEED1000;
-		if (bp->req_line_speed == SPEED_2500) {
-			new_bmcr |= BCM5708S_BMCR_FORCE_2500;
-			bnx2_read_phy(bp, BCM5708S_UP1, &up1);
-			if (!(up1 & BCM5708S_UP1_2G5)) {
-				up1 |= BCM5708S_UP1_2G5;
-				bnx2_write_phy(bp, BCM5708S_UP1, up1);
-				force_link_down = 1;
+
+		if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+			if (bp->req_line_speed == SPEED_2500)
+				bnx2_enable_forced_2g5(bp);
+			else if (bp->req_line_speed == SPEED_1000) {
+				bnx2_disable_forced_2g5(bp);
+				new_bmcr &= ~0x2000;
 			}
+
 		} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
-			bnx2_read_phy(bp, BCM5708S_UP1, &up1);
-			if (up1 & BCM5708S_UP1_2G5) {
-				up1 &= ~BCM5708S_UP1_2G5;
-				bnx2_write_phy(bp, BCM5708S_UP1, up1);
-				force_link_down = 1;
-			}
+			if (bp->req_line_speed == SPEED_2500)
+				new_bmcr |= BCM5708S_BMCR_FORCE_2500;
+			else
+				new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
 		}
 
 		if (bp->req_duplex == DUPLEX_FULL) {
@@ -1067,49 +1260,48 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
 		if ((new_bmcr != bmcr) || (force_link_down)) {
 			/* Force a link down visible on the other side */
 			if (bp->link_up) {
-				bnx2_write_phy(bp, MII_ADVERTISE, adv &
+				bnx2_write_phy(bp, bp->mii_adv, adv &
 					       ~(ADVERTISE_1000XFULL |
 						 ADVERTISE_1000XHALF));
-				bnx2_write_phy(bp, MII_BMCR, bmcr |
+				bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
 					BMCR_ANRESTART | BMCR_ANENABLE);
 
 				bp->link_up = 0;
 				netif_carrier_off(bp->dev);
-				bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+				bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
 				bnx2_report_link(bp);
 			}
-			bnx2_write_phy(bp, MII_ADVERTISE, adv);
-			bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+			bnx2_write_phy(bp, bp->mii_adv, adv);
+			bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
+		} else {
+			bnx2_resolve_flow_ctrl(bp);
+			bnx2_set_mac_link(bp);
 		}
 		return 0;
 	}
 
-	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
-		bnx2_read_phy(bp, BCM5708S_UP1, &up1);
-		up1 |= BCM5708S_UP1_2G5;
-		bnx2_write_phy(bp, BCM5708S_UP1, up1);
-	}
+	bnx2_test_and_enable_2g5(bp);
 
 	if (bp->advertising & ADVERTISED_1000baseT_Full)
 		new_adv |= ADVERTISE_1000XFULL;
 
 	new_adv |= bnx2_phy_get_pause_adv(bp);
 
-	bnx2_read_phy(bp, MII_ADVERTISE, &adv);
-	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bnx2_read_phy(bp, bp->mii_adv, &adv);
+	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 	bp->serdes_an_pending = 0;
 	if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
 		/* Force a link down visible on the other side */
 		if (bp->link_up) {
-			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
 			spin_unlock_bh(&bp->phy_lock);
 			msleep(20);
 			spin_lock_bh(&bp->phy_lock);
 		}
 
-		bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
-		bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
+		bnx2_write_phy(bp, bp->mii_adv, new_adv);
+		bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
 			BMCR_ANENABLE);
 		/* Speed up link-up time when the link partner
 		 * does not autonegotiate which is very common
@@ -1122,6 +1314,9 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
 		bp->current_interval = SERDES_AN_TIMEOUT;
 		bp->serdes_an_pending = 1;
 		mod_timer(&bp->timer, jiffies + bp->current_interval);
+	} else {
+		bnx2_resolve_flow_ctrl(bp);
+		bnx2_set_mac_link(bp);
 	}
 
 	return 0;
@@ -1146,14 +1341,14 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
 	u32 bmcr;
 	u32 new_bmcr;
 
-	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 	if (bp->autoneg & AUTONEG_SPEED) {
 		u32 adv_reg, adv1000_reg;
 		u32 new_adv_reg = 0;
 		u32 new_adv1000_reg = 0;
 
-		bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg);
+		bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
 		adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
 			ADVERTISE_PAUSE_ASYM);
 
@@ -1179,9 +1374,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
 			(adv_reg != new_adv_reg) ||
 			((bmcr & BMCR_ANENABLE) == 0)) {
 
-			bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg);
+			bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
 			bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
-			bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART |
+			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
 				BMCR_ANENABLE);
 		}
 		else if (bp->link_up) {
@@ -1204,21 +1399,21 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
 	if (new_bmcr != bmcr) {
 		u32 bmsr;
 
-		bnx2_read_phy(bp, MII_BMSR, &bmsr);
-		bnx2_read_phy(bp, MII_BMSR, &bmsr);
+		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+		bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
 
 		if (bmsr & BMSR_LSTATUS) {
 			/* Force link down */
-			bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+			bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
 			spin_unlock_bh(&bp->phy_lock);
 			msleep(50);
 			spin_lock_bh(&bp->phy_lock);
 
-			bnx2_read_phy(bp, MII_BMSR, &bmsr);
-			bnx2_read_phy(bp, MII_BMSR, &bmsr);
+			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
 		}
 
-		bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+		bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
 
 		/* Normally, the new speed is setup after the link has
 		 * gone down and up again. In some cases, link will not go
@@ -1230,6 +1425,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
 			bnx2_resolve_flow_ctrl(bp);
 			bnx2_set_mac_link(bp);
 		}
+	} else {
+		bnx2_resolve_flow_ctrl(bp);
+		bnx2_set_mac_link(bp);
 	}
 	return 0;
 }
@@ -1249,10 +1447,63 @@ bnx2_setup_phy(struct bnx2 *bp)
 }
 
 static int
+bnx2_init_5709s_phy(struct bnx2 *bp)
+{
+	u32 val;
+
+	bp->mii_bmcr = MII_BMCR + 0x10;
+	bp->mii_bmsr = MII_BMSR + 0x10;
+	bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
+	bp->mii_adv = MII_ADVERTISE + 0x10;
+	bp->mii_lpa = MII_LPA + 0x10;
+	bp->mii_up1 = MII_BNX2_OVER1G_UP1;
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
+	bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+	bnx2_reset_phy(bp);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
+
+	bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
+	val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
+	val |= MII_BNX2_SD_1000XCTL1_FIBER;
+	bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+	bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
+	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+		val |= BCM5708S_UP1_2G5;
+	else
+		val &= ~BCM5708S_UP1_2G5;
+	bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
+	bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
+	val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
+	bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
+
+	val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
+	      MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
+	bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
+
+	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+	return 0;
+}
+
+static int
 bnx2_init_5708s_phy(struct bnx2 *bp)
 {
 	u32 val;
 
+	bnx2_reset_phy(bp);
+
+	bp->mii_up1 = BCM5708S_UP1;
+
 	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
 	bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
 	bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
@@ -1305,6 +1556,8 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
 static int
 bnx2_init_5706s_phy(struct bnx2 *bp)
 {
+	bnx2_reset_phy(bp);
+
 	bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5706)
@@ -1342,6 +1595,8 @@ bnx2_init_copper_phy(struct bnx2 *bp)
 {
 	u32 val;
 
+	bnx2_reset_phy(bp);
+
 	if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
 		bnx2_write_phy(bp, 0x18, 0x0c00);
 		bnx2_write_phy(bp, 0x17, 0x000a);
@@ -1396,9 +1651,13 @@ bnx2_init_phy(struct bnx2 *bp)
 	bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
 	bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
 
-        REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+	bp->mii_bmcr = MII_BMCR;
+	bp->mii_bmsr = MII_BMSR;
+	bp->mii_bmsr1 = MII_BMSR;
+	bp->mii_adv = MII_ADVERTISE;
+	bp->mii_lpa = MII_LPA;
 
-	bnx2_reset_phy(bp);
+        REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
 
 	bnx2_read_phy(bp, MII_PHYSID1, &val);
 	bp->phy_id = val << 16;
@@ -1410,6 +1669,8 @@ bnx2_init_phy(struct bnx2 *bp)
 			rc = bnx2_init_5706s_phy(bp);
 		else if (CHIP_NUM(bp) == CHIP_NUM_5708)
 			rc = bnx2_init_5708s_phy(bp);
+		else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+			rc = bnx2_init_5709s_phy(bp);
 	}
 	else {
 		rc = bnx2_init_copper_phy(bp);
@@ -1442,7 +1703,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp)
 	int rc, i;
 
 	spin_lock_bh(&bp->phy_lock);
-	rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+	rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
 			    BMCR_SPEED1000);
 	spin_unlock_bh(&bp->phy_lock);
 	if (rc)
@@ -1681,25 +1942,33 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 i
 	return 0;
 }
 
-static void
-bnx2_phy_int(struct bnx2 *bp)
+static int
+bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
 {
+	struct status_block *sblk = bp->status_blk;
 	u32 new_link_state, old_link_state;
+	int is_set = 1;
 
-	new_link_state = bp->status_blk->status_attn_bits &
-		STATUS_ATTN_BITS_LINK_STATE;
-	old_link_state = bp->status_blk->status_attn_bits_ack &
-		STATUS_ATTN_BITS_LINK_STATE;
+	new_link_state = sblk->status_attn_bits & event;
+	old_link_state = sblk->status_attn_bits_ack & event;
 	if (new_link_state != old_link_state) {
-		if (new_link_state) {
-			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
-				STATUS_ATTN_BITS_LINK_STATE);
-		}
-		else {
-			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
-				STATUS_ATTN_BITS_LINK_STATE);
-		}
+		if (new_link_state)
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
+		else
+			REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
+	} else
+		is_set = 0;
+
+	return is_set;
+}
+
+static void
+bnx2_phy_int(struct bnx2 *bp)
+{
+	if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
+		spin_lock(&bp->phy_lock);
 		bnx2_set_link(bp);
+		spin_unlock(&bp->phy_lock);
 	}
 }
 
@@ -1884,10 +2153,8 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
 				goto reuse_rx;
 
 			/* aligned copy */
-			memcpy(new_skb->data,
-				skb->data + bp->rx_offset - 2,
-				len + 2);
-
+			skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
+				      new_skb->data, len + 2);
 			skb_reserve(new_skb, 2);
 			skb_put(new_skb, len);
 
@@ -1995,6 +2262,23 @@ bnx2_msi(int irq, void *dev_instance)
 }
 
 static irqreturn_t
+bnx2_msi_1shot(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2 *bp = netdev_priv(dev);
+
+	prefetch(bp->status_blk);
+
+	/* Return here if interrupt is disabled. */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0))
+		return IRQ_HANDLED;
+
+	netif_rx_schedule(dev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
 bnx2_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
@@ -2024,6 +2308,8 @@ bnx2_interrupt(int irq, void *dev_instan
 	return IRQ_HANDLED;
 }
 
+#define STATUS_ATTN_EVENTS	STATUS_ATTN_BITS_LINK_STATE
+
 static inline int
 bnx2_has_work(struct bnx2 *bp)
 {
@@ -2033,8 +2319,8 @@ bnx2_has_work(struct bnx2 *bp)
 	    (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
 		return 1;
 
-	if ((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
-	    (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
+	if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
+	    (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
 		return 1;
 
 	return 0;
@@ -2044,15 +2330,14 @@ static int
 bnx2_poll(struct net_device *dev, int *budget)
 {
 	struct bnx2 *bp = netdev_priv(dev);
+	struct status_block *sblk = bp->status_blk;
+	u32 status_attn_bits = sblk->status_attn_bits;
+	u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
 
-	if ((bp->status_blk->status_attn_bits &
-		STATUS_ATTN_BITS_LINK_STATE) !=
-		(bp->status_blk->status_attn_bits_ack &
-		STATUS_ATTN_BITS_LINK_STATE)) {
+	if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
+	    (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
 
-		spin_lock(&bp->phy_lock);
 		bnx2_phy_int(bp);
-		spin_unlock(&bp->phy_lock);
 
 		/* This is needed to take care of transient status
 		 * during link changes.
@@ -3491,17 +3776,21 @@ #endif
 	REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
 
 	if (CHIP_ID(bp) == CHIP_ID_5706_A1)
-		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
+		val = BNX2_HC_CONFIG_COLLECT_STATS;
 	else {
-		REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
-		       BNX2_HC_CONFIG_TX_TMR_MODE |
-		       BNX2_HC_CONFIG_COLLECT_STATS);
+		val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
+		      BNX2_HC_CONFIG_COLLECT_STATS;
 	}
 
+	if (bp->flags & ONE_SHOT_MSI_FLAG)
+		val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+	REG_WR(bp, BNX2_HC_CONFIG, val);
+
 	/* Clear internal stats counters. */
 	REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
 
-	REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
+	REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
 
 	if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
 	    BNX2_PORT_FEATURE_ASF_ENABLED)
@@ -3765,10 +4054,11 @@ static int
 bnx2_test_registers(struct bnx2 *bp)
 {
 	int ret;
-	int i;
+	int i, is_5709;
 	static const struct {
 		u16   offset;
 		u16   flags;
+#define BNX2_FL_NOT_5709	1
 		u32   rw_mask;
 		u32   ro_mask;
 	} reg_tbl[] = {
@@ -3776,26 +4066,26 @@ bnx2_test_registers(struct bnx2 *bp)
 		{ 0x0090, 0, 0xffffffff, 0x00000000 },
 		{ 0x0094, 0, 0x00000000, 0x00000000 },
 
-		{ 0x0404, 0, 0x00003f00, 0x00000000 },
-		{ 0x0418, 0, 0x00000000, 0xffffffff },
-		{ 0x041c, 0, 0x00000000, 0xffffffff },
-		{ 0x0420, 0, 0x00000000, 0x80ffffff },
-		{ 0x0424, 0, 0x00000000, 0x00000000 },
-		{ 0x0428, 0, 0x00000000, 0x00000001 },
-		{ 0x0450, 0, 0x00000000, 0x0000ffff },
-		{ 0x0454, 0, 0x00000000, 0xffffffff },
-		{ 0x0458, 0, 0x00000000, 0xffffffff },
-
-		{ 0x0808, 0, 0x00000000, 0xffffffff },
-		{ 0x0854, 0, 0x00000000, 0xffffffff },
-		{ 0x0868, 0, 0x00000000, 0x77777777 },
-		{ 0x086c, 0, 0x00000000, 0x77777777 },
-		{ 0x0870, 0, 0x00000000, 0x77777777 },
-		{ 0x0874, 0, 0x00000000, 0x77777777 },
-
-		{ 0x0c00, 0, 0x00000000, 0x00000001 },
-		{ 0x0c04, 0, 0x00000000, 0x03ff0001 },
-		{ 0x0c08, 0, 0x0f0ff073, 0x00000000 },
+		{ 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
+		{ 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+		{ 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+		{ 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
+		{ 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
+		{ 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
+		{ 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
+		{ 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+		{ 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+
+		{ 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+		{ 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+		{ 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+		{ 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+		{ 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+		{ 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+
+		{ 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
+		{ 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
+		{ 0x0c08, BNX2_FL_NOT_5709,  0x0f0ff073, 0x00000000 },
 
 		{ 0x1000, 0, 0x00000000, 0x00000001 },
 		{ 0x1004, 0, 0x00000000, 0x000f0001 },
@@ -3842,7 +4132,6 @@ bnx2_test_registers(struct bnx2 *bp)
 
 		{ 0x5004, 0, 0x00000000, 0x0000007f },
 		{ 0x5008, 0, 0x0f0007ff, 0x00000000 },
-		{ 0x500c, 0, 0xf800f800, 0x07ff07ff },
 
 		{ 0x5c00, 0, 0x00000000, 0x00000001 },
 		{ 0x5c04, 0, 0x00000000, 0x0003000f },
@@ -3882,8 +4171,16 @@ bnx2_test_registers(struct bnx2 *bp)
 	};
 
 	ret = 0;
+	is_5709 = 0;
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		is_5709 = 1;
+
 	for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
 		u32 offset, rw_mask, ro_mask, save_val, val;
+		u16 flags = reg_tbl[i].flags;
+
+		if (is_5709 && (flags & BNX2_FL_NOT_5709))
+			continue;
 
 		offset = (u32) reg_tbl[i].offset;
 		rw_mask = reg_tbl[i].rw_mask;
@@ -3952,10 +4249,10 @@ bnx2_test_memory(struct bnx2 *bp)
 {
 	int ret = 0;
 	int i;
-	static const struct {
+	static struct mem_entry {
 		u32   offset;
 		u32   len;
-	} mem_tbl[] = {
+	} mem_tbl_5706[] = {
 		{ 0x60000,  0x4000 },
 		{ 0xa0000,  0x3000 },
 		{ 0xe0000,  0x4000 },
@@ -3963,7 +4260,21 @@ bnx2_test_memory(struct bnx2 *bp)
 		{ 0x1a0000, 0x4000 },
 		{ 0x160000, 0x4000 },
 		{ 0xffffffff, 0    },
+	},
+	mem_tbl_5709[] = {
+		{ 0x60000,  0x4000 },
+		{ 0xa0000,  0x3000 },
+		{ 0xe0000,  0x4000 },
+		{ 0x120000, 0x4000 },
+		{ 0x1a0000, 0x4000 },
+		{ 0xffffffff, 0    },
 	};
+	struct mem_entry *mem_tbl;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		mem_tbl = mem_tbl_5709;
+	else
+		mem_tbl = mem_tbl_5706;
 
 	for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
 		if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
@@ -4165,8 +4476,10 @@ bnx2_test_link(struct bnx2 *bp)
 	u32 bmsr;
 
 	spin_lock_bh(&bp->phy_lock);
-	bnx2_read_phy(bp, MII_BMSR, &bmsr);
-	bnx2_read_phy(bp, MII_BMSR, &bmsr);
+	bnx2_enable_bmsr1(bp);
+	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+	bnx2_disable_bmsr1(bp);
 	spin_unlock_bh(&bp->phy_lock);
 
 	if (bmsr & BMSR_LSTATUS) {
@@ -4216,7 +4529,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
 
 		bp->current_interval = bp->timer_interval;
 
-		bnx2_read_phy(bp, MII_BMCR, &bmcr);
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 		if (bmcr & BMCR_ANENABLE) {
 			u32 phy1, phy2;
@@ -4234,7 +4547,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
 
 				bmcr &= ~BMCR_ANENABLE;
 				bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
-				bnx2_write_phy(bp, MII_BMCR, bmcr);
+				bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
 				bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
 			}
 		}
@@ -4248,9 +4561,9 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
 		if (phy2 & 0x20) {
 			u32 bmcr;
 
-			bnx2_read_phy(bp, MII_BMCR, &bmcr);
+			bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 			bmcr |= BMCR_ANENABLE;
-			bnx2_write_phy(bp, MII_BMCR, bmcr);
+			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
 
 			bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
 		}
@@ -4274,17 +4587,12 @@ bnx2_5708_serdes_timer(struct bnx2 *bp)
 	else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
 		u32 bmcr;
 
-		bnx2_read_phy(bp, MII_BMCR, &bmcr);
-
+		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 		if (bmcr & BMCR_ANENABLE) {
-			bmcr &= ~BMCR_ANENABLE;
-			bmcr |= BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500;
-			bnx2_write_phy(bp, MII_BMCR, bmcr);
+			bnx2_enable_forced_2g5(bp);
 			bp->current_interval = SERDES_FORCED_TIMEOUT;
 		} else {
-			bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500);
-			bmcr |= BMCR_ANENABLE;
-			bnx2_write_phy(bp, MII_BMCR, bmcr);
+			bnx2_disable_forced_2g5(bp);
 			bp->serdes_an_pending = 2;
 			bp->current_interval = bp->timer_interval;
 		}
@@ -4315,7 +4623,7 @@ bnx2_timer(unsigned long data)
 	if (bp->phy_flags & PHY_SERDES_FLAG) {
 		if (CHIP_NUM(bp) == CHIP_NUM_5706)
 			bnx2_5706_serdes_timer(bp);
-		else if (CHIP_NUM(bp) == CHIP_NUM_5708)
+		else
 			bnx2_5708_serdes_timer(bp);
 	}
 
@@ -4323,6 +4631,38 @@ bnx2_restart_timer:
 	mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
+static int
+bnx2_request_irq(struct bnx2 *bp)
+{
+	struct net_device *dev = bp->dev;
+	int rc = 0;
+
+	if (bp->flags & USING_MSI_FLAG) {
+		irq_handler_t	fn = bnx2_msi;
+
+		if (bp->flags & ONE_SHOT_MSI_FLAG)
+			fn = bnx2_msi_1shot;
+
+		rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
+	} else
+		rc = request_irq(bp->pdev->irq, bnx2_interrupt,
+				 IRQF_SHARED, dev->name, dev);
+	return rc;
+}
+
+static void
+bnx2_free_irq(struct bnx2 *bp)
+{
+	struct net_device *dev = bp->dev;
+
+	if (bp->flags & USING_MSI_FLAG) {
+		free_irq(bp->pdev->irq, dev);
+		pci_disable_msi(bp->pdev);
+		bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
+	} else
+		free_irq(bp->pdev->irq, dev);
+}
+
 /* Called with rtnl_lock */
 static int
 bnx2_open(struct net_device *dev)
@@ -4330,6 +4670,8 @@ bnx2_open(struct net_device *dev)
 	struct bnx2 *bp = netdev_priv(dev);
 	int rc;
 
+	netif_carrier_off(dev);
+
 	bnx2_set_power_state(bp, PCI_D0);
 	bnx2_disable_int(bp);
 
@@ -4337,24 +4679,15 @@ bnx2_open(struct net_device *dev)
 	if (rc)
 		return rc;
 
-	if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
-		(CHIP_ID(bp) != CHIP_ID_5706_A1) &&
-		!disable_msi) {
-
+	if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
 		if (pci_enable_msi(bp->pdev) == 0) {
 			bp->flags |= USING_MSI_FLAG;
-			rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name,
-					dev);
-		}
-		else {
-			rc = request_irq(bp->pdev->irq, bnx2_interrupt,
-					IRQF_SHARED, dev->name, dev);
+			if (CHIP_NUM(bp) == CHIP_NUM_5709)
+				bp->flags |= ONE_SHOT_MSI_FLAG;
 		}
 	}
-	else {
-		rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
-				dev->name, dev);
-	}
+	rc = bnx2_request_irq(bp);
+
 	if (rc) {
 		bnx2_free_mem(bp);
 		return rc;
@@ -4363,11 +4696,7 @@ bnx2_open(struct net_device *dev)
 	rc = bnx2_init_nic(bp);
 
 	if (rc) {
-		free_irq(bp->pdev->irq, dev);
-		if (bp->flags & USING_MSI_FLAG) {
-			pci_disable_msi(bp->pdev);
-			bp->flags &= ~USING_MSI_FLAG;
-		}
+		bnx2_free_irq(bp);
 		bnx2_free_skbs(bp);
 		bnx2_free_mem(bp);
 		return rc;
@@ -4391,16 +4720,13 @@ bnx2_open(struct net_device *dev)
 			       bp->dev->name);
 
 			bnx2_disable_int(bp);
-			free_irq(bp->pdev->irq, dev);
-			pci_disable_msi(bp->pdev);
-			bp->flags &= ~USING_MSI_FLAG;
+			bnx2_free_irq(bp);
 
 			rc = bnx2_init_nic(bp);
 
-			if (!rc) {
-				rc = request_irq(bp->pdev->irq, bnx2_interrupt,
-					IRQF_SHARED, dev->name, dev);
-			}
+			if (!rc)
+				rc = bnx2_request_irq(bp);
+
 			if (rc) {
 				bnx2_free_skbs(bp);
 				bnx2_free_mem(bp);
@@ -4510,41 +4836,53 @@ bnx2_start_xmit(struct sk_buff *skb, str
 		vlan_tag_flags |=
 			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
 	}
-	if ((mss = skb_shinfo(skb)->gso_size) &&
-		(skb->len > (bp->dev->mtu + ETH_HLEN))) {
+	if ((mss = skb_shinfo(skb)->gso_size)) {
 		u32 tcp_opt_len, ip_tcp_len;
+		struct iphdr *iph;
 
-		if (skb_header_cloned(skb) &&
-		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
-			dev_kfree_skb(skb);
-			return NETDEV_TX_OK;
-		}
-
-		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
 		vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
 
-		tcp_opt_len = 0;
-		if (skb->h.th->doff > 5) {
-			tcp_opt_len = (skb->h.th->doff - 5) << 2;
-		}
-		ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
+		tcp_opt_len = tcp_optlen(skb);
 
-		skb->nh.iph->check = 0;
-		skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
-		skb->h.th->check =
-			~csum_tcpudp_magic(skb->nh.iph->saddr,
-					    skb->nh.iph->daddr,
-					    0, IPPROTO_TCP, 0);
+		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
+			u32 tcp_off = skb_transport_offset(skb) -
+				      sizeof(struct ipv6hdr) - ETH_HLEN;
+
+			vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
+					  TX_BD_FLAGS_SW_FLAGS;
+			if (likely(tcp_off == 0))
+				vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
+			else {
+				tcp_off >>= 3;
+				vlan_tag_flags |= ((tcp_off & 0x3) <<
+						   TX_BD_FLAGS_TCP6_OFF0_SHL) |
+						  ((tcp_off & 0x10) <<
+						   TX_BD_FLAGS_TCP6_OFF4_SHL);
+				mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
+			}
+		} else {
+			if (skb_header_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+				dev_kfree_skb(skb);
+				return NETDEV_TX_OK;
+			}
 
-		if (tcp_opt_len || (skb->nh.iph->ihl > 5)) {
-			vlan_tag_flags |= ((skb->nh.iph->ihl - 5) +
-				(tcp_opt_len >> 2)) << 8;
+			ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
+
+			iph = ip_hdr(skb);
+			iph->check = 0;
+			iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
+			if (tcp_opt_len || (iph->ihl > 5)) {
+				vlan_tag_flags |= ((iph->ihl - 5) +
+						   (tcp_opt_len >> 2)) << 8;
+			}
 		}
-	}
-	else
-	{
+	} else
 		mss = 0;
-	}
 
 	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
@@ -4625,11 +4963,7 @@ bnx2_close(struct net_device *dev)
 	else
 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
 	bnx2_reset_chip(bp, reset_code);
-	free_irq(bp->pdev->irq, dev);
-	if (bp->flags & USING_MSI_FLAG) {
-		pci_disable_msi(bp->pdev);
-		bp->flags &= ~USING_MSI_FLAG;
-	}
+	bnx2_free_irq(bp);
 	bnx2_free_skbs(bp);
 	bnx2_free_mem(bp);
 	bp->link_up = 0;
@@ -4738,6 +5072,8 @@ bnx2_get_settings(struct net_device *dev
 	if (bp->phy_flags & PHY_SERDES_FLAG) {
 		cmd->supported |= SUPPORTED_1000baseT_Full |
 			SUPPORTED_FIBRE;
+		if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+			cmd->supported |= SUPPORTED_2500baseX_Full;
 
 		cmd->port = PORT_FIBRE;
 	}
@@ -4801,8 +5137,10 @@ bnx2_set_settings(struct net_device *dev
 
 			advertising = cmd->advertising;
 
-		}
-		else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+		} else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
+			if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+				return -EINVAL;
+		} else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
 			advertising = cmd->advertising;
 		}
 		else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
@@ -4978,7 +5316,7 @@ bnx2_nway_reset(struct net_device *dev)
 
 	/* Force a link down visible on the other side */
 	if (bp->phy_flags & PHY_SERDES_FLAG) {
-		bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+		bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
 		spin_unlock_bh(&bp->phy_lock);
 
 		msleep(20);
@@ -4990,9 +5328,9 @@ bnx2_nway_reset(struct net_device *dev)
 		mod_timer(&bp->timer, jiffies + bp->current_interval);
 	}
 
-	bnx2_read_phy(bp, MII_BMCR, &bmcr);
+	bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 	bmcr &= ~BMCR_LOOPBACK;
-	bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
+	bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
 
 	spin_unlock_bh(&bp->phy_lock);
 
@@ -5212,10 +5550,15 @@ bnx2_set_rx_csum(struct net_device *dev,
 static int
 bnx2_set_tso(struct net_device *dev, u32 data)
 {
-	if (data)
+	struct bnx2 *bp = netdev_priv(dev);
+
+	if (data) {
 		dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-	else
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+		if (CHIP_NUM(bp) == CHIP_NUM_5709)
+			dev->features |= NETIF_F_TSO6;
+	} else
+		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
+				   NETIF_F_TSO_ECN);
 	return 0;
 }
 
@@ -5513,6 +5856,17 @@ bnx2_phys_id(struct net_device *dev, u32
 	return 0;
 }
 
+static int
+bnx2_set_tx_csum(struct net_device *dev, u32 data)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		return (ethtool_op_set_tx_hw_csum(dev, data));
+	else
+		return (ethtool_op_set_tx_csum(dev, data));
+}
+
 static const struct ethtool_ops bnx2_ethtool_ops = {
 	.get_settings		= bnx2_get_settings,
 	.set_settings		= bnx2_set_settings,
@@ -5535,7 +5889,7 @@ static const struct ethtool_ops bnx2_eth
 	.get_rx_csum		= bnx2_get_rx_csum,
 	.set_rx_csum		= bnx2_set_rx_csum,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.set_tx_csum		= ethtool_op_set_tx_csum,
+	.set_tx_csum		= bnx2_set_tx_csum,
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
 	.get_tso		= ethtool_op_get_tso,
@@ -5565,6 +5919,9 @@ bnx2_ioctl(struct net_device *dev, struc
 	case SIOCGMIIREG: {
 		u32 mii_regval;
 
+		if (!netif_running(dev))
+			return -EAGAIN;
+
 		spin_lock_bh(&bp->phy_lock);
 		err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
 		spin_unlock_bh(&bp->phy_lock);
@@ -5578,6 +5935,9 @@ bnx2_ioctl(struct net_device *dev, struc
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
+		if (!netif_running(dev))
+			return -EAGAIN;
+
 		spin_lock_bh(&bp->phy_lock);
 		err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
 		spin_unlock_bh(&bp->phy_lock);
@@ -5679,6 +6039,58 @@ bnx2_get_5709_media(struct bnx2 *bp)
 	}
 }
 
+static void __devinit
+bnx2_get_pci_speed(struct bnx2 *bp)
+{
+	u32 reg;
+
+	reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
+	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
+		u32 clkreg;
+
+		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:
+			bp->bus_speed_mhz = 133;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
+			bp->bus_speed_mhz = 100;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
+			bp->bus_speed_mhz = 66;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
+			bp->bus_speed_mhz = 50;
+			break;
+
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
+		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
+			bp->bus_speed_mhz = 33;
+			break;
+		}
+	}
+	else {
+		if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
+			bp->bus_speed_mhz = 66;
+		else
+			bp->bus_speed_mhz = 33;
+	}
+
+	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
+		bp->flags |= PCI_32BIT_FLAG;
+
+}
+
 static int __devinit
 bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 {
@@ -5686,6 +6098,7 @@ bnx2_init_board(struct pci_dev *pdev, st
 	unsigned long mem_len;
 	int rc;
 	u32 reg;
+	u64 dma_mask, persist_dma_mask;
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
@@ -5724,25 +6137,11 @@ bnx2_init_board(struct pci_dev *pdev, st
 		goto err_out_release;
 	}
 
-	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
-		bp->flags |= USING_DAC_FLAG;
-		if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-			dev_err(&pdev->dev,
-				"pci_set_consistent_dma_mask failed, aborting.\n");
-			rc = -EIO;
-			goto err_out_release;
-		}
-	}
-	else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
-		dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
-		rc = -EIO;
-		goto err_out_release;
-	}
-
 	bp->dev = dev;
 	bp->pdev = pdev;
 
 	spin_lock_init(&bp->phy_lock);
+	spin_lock_init(&bp->indirect_lock);
 	INIT_WORK(&bp->reset_task, bnx2_reset_task);
 
 	dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
@@ -5770,7 +6169,15 @@ bnx2_init_board(struct pci_dev *pdev, st
 
 	bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
 
-	if (CHIP_NUM(bp) != CHIP_NUM_5709) {
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
+			dev_err(&pdev->dev,
+				"Cannot find PCIE capability, aborting.\n");
+			rc = -EIO;
+			goto err_out_unmap;
+		}
+		bp->flags |= PCIE_FLAG;
+	} else {
 		bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
 		if (bp->pcix_cap == 0) {
 			dev_err(&pdev->dev,
@@ -5780,51 +6187,33 @@ bnx2_init_board(struct pci_dev *pdev, st
 		}
 	}
 
-	/* Get bus information. */
-	reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
-	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
-		u32 clkreg;
-
-		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:
-			bp->bus_speed_mhz = 133;
-			break;
-
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
-			bp->bus_speed_mhz = 100;
-			break;
-
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
-			bp->bus_speed_mhz = 66;
-			break;
+	if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
+		if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
+			bp->flags |= MSI_CAP_FLAG;
+	}
 
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
-			bp->bus_speed_mhz = 50;
-			break;
+	/* 5708 cannot support DMA addresses > 40-bit.  */
+	if (CHIP_NUM(bp) == CHIP_NUM_5708)
+		persist_dma_mask = dma_mask = DMA_40BIT_MASK;
+	else
+		persist_dma_mask = dma_mask = DMA_64BIT_MASK;
 
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
-		case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
-			bp->bus_speed_mhz = 33;
-			break;
+	/* Configure DMA attributes. */
+	if (pci_set_dma_mask(pdev, dma_mask) == 0) {
+		dev->features |= NETIF_F_HIGHDMA;
+		rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
+		if (rc) {
+			dev_err(&pdev->dev,
+				"pci_set_consistent_dma_mask failed, aborting.\n");
+			goto err_out_unmap;
 		}
-	}
-	else {
-		if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
-			bp->bus_speed_mhz = 66;
-		else
-			bp->bus_speed_mhz = 33;
+	} else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+		dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
+		goto err_out_unmap;
 	}
 
-	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
-		bp->flags |= PCI_32BIT_FLAG;
+	if (!(bp->flags & PCIE_FLAG))
+		bnx2_get_pci_speed(bp);
 
 	/* 5706A0 may falsely detect SERR and PERR. */
 	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
@@ -6008,6 +6397,26 @@ err_out:
 	return rc;
 }
 
+static char * __devinit
+bnx2_bus_string(struct bnx2 *bp, char *str)
+{
+	char *s = str;
+
+	if (bp->flags & PCIE_FLAG) {
+		s += sprintf(s, "PCI Express");
+	} else {
+		s += sprintf(s, "PCI");
+		if (bp->flags & PCIX_FLAG)
+			s += sprintf(s, "-X");
+		if (bp->flags & PCI_32BIT_FLAG)
+			s += sprintf(s, " 32-bit");
+		else
+			s += sprintf(s, " 64-bit");
+		s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
+	}
+	return str;
+}
+
 static int __devinit
 bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -6015,6 +6424,7 @@ bnx2_init_one(struct pci_dev *pdev, cons
 	struct net_device *dev = NULL;
 	struct bnx2 *bp;
 	int rc, i;
+	char str[40];
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -6055,6 +6465,23 @@ #if defined(HAVE_POLL_CONTROLLER) || def
 	dev->poll_controller = poll_bnx2;
 #endif
 
+	pci_set_drvdata(pdev, dev);
+
+	memcpy(dev->dev_addr, bp->mac_addr, 6);
+	memcpy(dev->perm_addr, bp->mac_addr, 6);
+	bp->name = board_info[ent->driver_data].name;
+
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+	else
+		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+#ifdef BCM_VLAN
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+#endif
+	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
+		dev->features |= NETIF_F_TSO6;
+
 	if ((rc = register_netdev(dev))) {
 		dev_err(&pdev->dev, "Cannot register net device\n");
 		if (bp->regview)
@@ -6066,20 +6493,13 @@ #endif
 		return rc;
 	}
 
-	pci_set_drvdata(pdev, dev);
-
-	memcpy(dev->dev_addr, bp->mac_addr, 6);
-	memcpy(dev->perm_addr, bp->mac_addr, 6);
-	bp->name = board_info[ent->driver_data].name,
-	printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
+	printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
 		"IRQ %d, ",
 		dev->name,
 		bp->name,
 		((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
 		((CHIP_ID(bp) & 0x0ff0) >> 4),
-		((bp->flags & PCIX_FLAG) ? "-X" : ""),
-		((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
-		bp->bus_speed_mhz,
+		bnx2_bus_string(bp, str),
 		dev->base_addr,
 		bp->pdev->irq);
 
@@ -6088,17 +6508,6 @@ #endif
 		printk("%2.2x", dev->dev_addr[i]);
 	printk("\n");
 
-	dev->features |= NETIF_F_SG;
-	if (bp->flags & USING_DAC_FLAG)
-		dev->features |= NETIF_F_HIGHDMA;
-	dev->features |= NETIF_F_IP_CSUM;
-#ifdef BCM_VLAN
-	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif
-	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-
-	netif_carrier_off(bp->dev);
-
 	return 0;
 }
 
@@ -6143,6 +6552,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_me
 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
 	bnx2_reset_chip(bp, reset_code);
 	bnx2_free_skbs(bp);
+	pci_save_state(pdev);
 	bnx2_set_power_state(bp, pci_choose_state(pdev, state));
 	return 0;
 }
@@ -6156,6 +6566,7 @@ bnx2_resume(struct pci_dev *pdev)
 	if (!netif_running(dev))
 		return 0;
 
+	pci_restore_state(pdev);
 	bnx2_set_power_state(bp, PCI_D0);
 	netif_device_attach(dev);
 	bnx2_init_nic(bp);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 878eee5..bd6288d 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -1,6 +1,6 @@
 /* bnx2.h: Broadcom NX2 network driver.
  *
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004-2007 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
@@ -24,8 +24,11 @@ struct tx_bd {
 	u32 tx_bd_haddr_hi;
 	u32 tx_bd_haddr_lo;
 	u32 tx_bd_mss_nbytes;
+		#define TX_BD_TCP6_OFF2_SHL		(14)
 	u32 tx_bd_vlan_tag_flags;
 		#define TX_BD_FLAGS_CONN_FAULT		(1<<0)
+		#define TX_BD_FLAGS_TCP6_OFF0_MSK	(3<<1)
+		#define TX_BD_FLAGS_TCP6_OFF0_SHL	(1)
 		#define TX_BD_FLAGS_TCP_UDP_CKSUM	(1<<1)
 		#define TX_BD_FLAGS_IP_CKSUM		(1<<2)
 		#define TX_BD_FLAGS_VLAN_TAG		(1<<3)
@@ -34,6 +37,7 @@ struct tx_bd {
 		#define TX_BD_FLAGS_END			(1<<6)
 		#define TX_BD_FLAGS_START		(1<<7)
 		#define TX_BD_FLAGS_SW_OPTION_WORD	(0x1f<<8)
+		#define TX_BD_FLAGS_TCP6_OFF4_SHL	(12)
 		#define TX_BD_FLAGS_SW_FLAGS		(1<<13)
 		#define TX_BD_FLAGS_SW_SNAP		(1<<14)
 		#define TX_BD_FLAGS_SW_LSO		(1<<15)
@@ -6292,6 +6296,41 @@ #define MII_BNX2_DSP_RW_PORT			0x15
 #define MII_BNX2_DSP_ADDRESS			0x17
 #define MII_BNX2_DSP_EXPAND_REG			 0x0f00
 
+#define MII_BNX2_BLK_ADDR			0x1f
+#define MII_BNX2_BLK_ADDR_IEEE0			 0x0000
+#define MII_BNX2_BLK_ADDR_GP_STATUS		 0x8120
+#define MII_BNX2_GP_TOP_AN_STATUS1		  0x1b
+#define MII_BNX2_GP_TOP_AN_SPEED_MSK		   0x3f00
+#define MII_BNX2_GP_TOP_AN_SPEED_10		   0x0000
+#define MII_BNX2_GP_TOP_AN_SPEED_100		   0x0100
+#define MII_BNX2_GP_TOP_AN_SPEED_1G		   0x0200
+#define MII_BNX2_GP_TOP_AN_SPEED_2_5G		   0x0300
+#define MII_BNX2_GP_TOP_AN_SPEED_1GKV		   0x0d00
+#define MII_BNX2_GP_TOP_AN_FD			   0x8
+#define MII_BNX2_BLK_ADDR_SERDES_DIG		 0x8300
+#define MII_BNX2_SERDES_DIG_1000XCTL1		  0x10
+#define MII_BNX2_SD_1000XCTL1_FIBER		   0x01
+#define MII_BNX2_SD_1000XCTL1_AUTODET		   0x10
+#define MII_BNX2_SERDES_DIG_MISC1		  0x18
+#define MII_BNX2_SD_MISC1_FORCE_MSK		   0xf
+#define MII_BNX2_SD_MISC1_FORCE_2_5G		   0x0
+#define MII_BNX2_SD_MISC1_FORCE			   0x10
+#define MII_BNX2_BLK_ADDR_OVER1G		 0x8320
+#define MII_BNX2_OVER1G_UP1			  0x19
+#define MII_BNX2_BLK_ADDR_BAM_NXTPG		 0x8350
+#define MII_BNX2_BAM_NXTPG_CTL			  0x10
+#define MII_BNX2_NXTPG_CTL_BAM			   0x1
+#define MII_BNX2_NXTPG_CTL_T2			   0x2
+#define MII_BNX2_BLK_ADDR_CL73_USERB0		 0x8370
+#define MII_BNX2_CL73_BAM_CTL1			  0x12
+#define MII_BNX2_CL73_BAM_EN			   0x8000
+#define MII_BNX2_CL73_BAM_STA_MGR_EN		   0x4000
+#define MII_BNX2_CL73_BAM_NP_AFT_BP_EN		   0x2000
+#define MII_BNX2_BLK_ADDR_AER			 0xffd0
+#define MII_BNX2_AER_AER			  0x1e
+#define MII_BNX2_AER_AER_AN_MMD			   0x3800
+#define MII_BNX2_BLK_ADDR_COMBO_IEEEB0		 0xffe0
+
 #define MIN_ETHERNET_PACKET_SIZE	60
 #define MAX_ETHERNET_PACKET_SIZE	1514
 #define MAX_ETHERNET_JUMBO_PACKET_SIZE	9014
@@ -6429,13 +6468,15 @@ struct bnx2 {
 	u32 			last_status_idx;
 
 	u32			flags;
-#define PCIX_FLAG			1
-#define PCI_32BIT_FLAG			2
-#define ONE_TDMA_FLAG			4	/* no longer used */
-#define NO_WOL_FLAG			8
-#define USING_DAC_FLAG			0x10
-#define USING_MSI_FLAG			0x20
-#define ASF_ENABLE_FLAG			0x40
+#define PCIX_FLAG			0x00000001
+#define PCI_32BIT_FLAG			0x00000002
+#define ONE_TDMA_FLAG			0x00000004	/* no longer used */
+#define NO_WOL_FLAG			0x00000008
+#define USING_MSI_FLAG			0x00000020
+#define ASF_ENABLE_FLAG			0x00000040
+#define MSI_CAP_FLAG			0x00000080
+#define ONE_SHOT_MSI_FLAG		0x00000100
+#define PCIE_FLAG			0x00000200
 
 	/* Put tx producer and consumer fields in separate cache lines. */
 
@@ -6484,6 +6525,7 @@ #endif
 
 	/* Used to synchronize phy accesses. */
 	spinlock_t		phy_lock;
+	spinlock_t		indirect_lock;
 
 	u32			phy_flags;
 #define PHY_SERDES_FLAG			1
@@ -6495,6 +6537,13 @@ #define PHY_INT_MODE_AUTO_POLLING_FLAG	0
 #define PHY_INT_MODE_LINK_READY_FLAG	0x200
 #define PHY_DIS_EARLY_DAC_FLAG		0x400
 
+	u32			mii_bmcr;
+	u32			mii_bmsr;
+	u32			mii_bmsr1;
+	u32			mii_adv;
+	u32			mii_lpa;
+	u32			mii_up1;
+
 	u32			chip_id;
 	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
 #define CHIP_NUM(bp)			(((bp)->chip_id) & 0xffff0000)
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index 21d368f..b49f439 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,680 +15,1071 @@
  */
 
 static u8 bnx2_COM_b06FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x09, 0x83, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5b, 0x7d, 0x6c,
-	0x5b, 0xd7, 0x75, 0x3f, 0xef, 0xf1, 0x51, 0x7a, 0x96, 0x68, 0xf9, 0x99,
-	0x7e, 0x96, 0x59, 0x4f, 0xb1, 0x49, 0xf1, 0xc9, 0xd2, 0x62, 0x2d, 0x63,
-	0x34, 0x35, 0xd1, 0x3a, 0x26, 0x66, 0x48, 0xda, 0x71, 0x36, 0x67, 0xa0,
-	0x1d, 0x05, 0x51, 0x51, 0xaf, 0xd0, 0x48, 0xd9, 0xcd, 0xb2, 0x0c, 0x73,
-	0x96, 0xb4, 0x70, 0xbc, 0xb4, 0xa1, 0x25, 0x79, 0xf5, 0x06, 0x45, 0xcf,
-	0xb3, 0x34, 0x39, 0xc0, 0x82, 0x41, 0x10, 0x9d, 0x3a, 0x7f, 0x30, 0xa5,
-	0xed, 0x7c, 0x19, 0xe8, 0x12, 0x29, 0xb2, 0x93, 0xb5, 0x43, 0xd0, 0xa6,
-	0x68, 0xff, 0xe8, 0x8a, 0x6e, 0x30, 0x52, 0x0c, 0xf3, 0x3a, 0xa0, 0x30,
-	0xfa, 0xc7, 0xe6, 0x2d, 0x1f, 0xdc, 0xef, 0xdc, 0x77, 0x1f, 0xf9, 0x48,
-	0x51, 0x96, 0x1c, 0x34, 0x5d, 0xb7, 0x99, 0x80, 0xf0, 0xde, 0xbd, 0xf7,
-	0xbc, 0x7b, 0xcf, 0x3d, 0xdf, 0xe7, 0xdc, 0xab, 0x5f, 0x53, 0xa9, 0x85,
-	0xe4, 0x6f, 0x2d, 0xfe, 0xc2, 0x7f, 0xf4, 0xc7, 0xb9, 0xdb, 0x3e, 0x7d,
-	0x5b, 0x1f, 0x5e, 0x07, 0x54, 0xdd, 0xaf, 0x72, 0xbf, 0x0f, 0x7f, 0x26,
-	0xfe, 0xfa, 0xe4, 0x7b, 0xa3, 0x9f, 0x81, 0xbf, 0x2b, 0x18, 0x1c, 0xfe,
-	0x09, 0x91, 0xb2, 0x0c, 0x8c, 0xf7, 0x57, 0x2e, 0x5f, 0x7f, 0x9c, 0x17,
-	0x0e, 0xaf, 0x62, 0x9e, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf,
-	0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0xff, 0x3f, 0x3f, 0x9f, 0x13, 0x72,
-	0x88, 0x98, 0x85, 0xff, 0x48, 0x57, 0xe3, 0x89, 0xa1, 0xa4, 0x45, 0xba,
-	0x2f, 0x7e, 0x65, 0x28, 0x67, 0x11, 0x25, 0x8a, 0xdb, 0xc3, 0x29, 0xfa,
-	0xb0, 0x9c, 0x37, 0x35, 0xe2, 0xfe, 0x5b, 0xe2, 0x1f, 0x3c, 0xfd, 0xfa,
-	0x9d, 0x91, 0xab, 0xb3, 0x3e, 0xd2, 0x8d, 0xf8, 0xcb, 0xba, 0xb1, 0x8d,
-	0xf4, 0x0e, 0x7c, 0xf3, 0x5c, 0xf7, 0x7f, 0xa8, 0xd4, 0xe6, 0xce, 0x75,
-	0xa5, 0xfc, 0x7a, 0x37, 0xe5, 0x37, 0xc7, 0x75, 0x52, 0xe3, 0x5d, 0x3f,
-	0x48, 0xfa, 0x8c, 0x61, 0x5f, 0xdc, 0xa0, 0xf9, 0x12, 0x65, 0x0e, 0x4c,
-	0xf0, 0x1a, 0xb1, 0x75, 0xf7, 0x62, 0x2e, 0x2d, 0x3e, 0x3c, 0xf4, 0x67,
-	0xd6, 0xd3, 0x65, 0xd5, 0xb2, 0x7a, 0xe6, 0x28, 0x30, 0xf0, 0x7c, 0x3f,
-	0xc6, 0x8b, 0x91, 0x1e, 0xa2, 0x3b, 0x49, 0xb5, 0xf2, 0x01, 0x9f, 0xa5,
-	0x53, 0xb2, 0x64, 0x51, 0xaa, 0x44, 0xf4, 0x77, 0x45, 0x85, 0x9e, 0xb7,
-	0xda, 0x69, 0xae, 0xf7, 0x83, 0x72, 0x02, 0xb8, 0xbc, 0x6d, 0x0d, 0x0f,
-	0x8d, 0x5b, 0x3c, 0x57, 0x7c, 0x9d, 0x83, 0x6f, 0x6f, 0x5b, 0xce, 0xd2,
-	0x68, 0xb4, 0xc8, 0x7d, 0xbd, 0x2d, 0xdc, 0xe7, 0x8f, 0x3f, 0x1c, 0x7c,
-	0xde, 0x0a, 0xc8, 0xbe, 0x1f, 0xa5, 0x92, 0x98, 0x6f, 0xac, 0xc8, 0xb0,
-	0xcf, 0xde, 0x91, 0xb3, 0x4c, 0xd9, 0x6f, 0xc5, 0x93, 0x56, 0x08, 0xfd,
-	0x1d, 0x72, 0x2c, 0xbd, 0x2e, 0x67, 0x59, 0x72, 0xac, 0x88, 0x6f, 0x7a,
-	0x65, 0xff, 0x3b, 0xa9, 0x9c, 0x15, 0x93, 0xfd, 0x57, 0x93, 0x49, 0xab,
-	0x5f, 0xf6, 0x1f, 0xbe, 0x2b, 0x67, 0xc5, 0x65, 0xff, 0xf7, 0x81, 0x8b,
-	0x41, 0xc7, 0x8a, 0x61, 0xfc, 0x25, 0x30, 0xfe, 0x9a, 0x41, 0x6d, 0x19,
-	0x8c, 0x61, 0xef, 0xb6, 0x4e, 0x97, 0x7d, 0x21, 0x7a, 0xbd, 0xfb, 0x32,
-	0x68, 0x63, 0xd0, 0xd9, 0x12, 0x29, 0x99, 0xee, 0x10, 0x68, 0x62, 0xd2,
-	0xb9, 0x52, 0x2b, 0xf9, 0x4e, 0xfa, 0xb0, 0xe7, 0xcf, 0x51, 0xd6, 0xd4,
-	0x69, 0xfd, 0x8c, 0x42, 0x9d, 0x7d, 0x6b, 0x28, 0x61, 0xe4, 0x29, 0xd5,
-	0x8d, 0x28, 0x6e, 0xd2, 0x24, 0x6d, 0x66, 0x71, 0xbd, 0x8a, 0x1e, 0x95,
-	0x22, 0xa1, 0x2c, 0x28, 0x3c, 0x72, 0xfa, 0x5d, 0x8e, 0x39, 0xb1, 0x26,
-	0xff, 0x85, 0x29, 0x35, 0x71, 0x2b, 0x0d, 0x1b, 0x8c, 0x0f, 0x80, 0x05,
-	0x1f, 0x74, 0x25, 0x79, 0x2a, 0x44, 0xc7, 0xec, 0x80, 0x92, 0x3a, 0x75,
-	0x37, 0x25, 0x63, 0x64, 0xaa, 0xd4, 0x25, 0xbe, 0x2d, 0x14, 0x43, 0x34,
-	0x6e, 0x93, 0x92, 0xb4, 0x99, 0x5e, 0xed, 0x18, 0x6f, 0x13, 0xb0, 0xe8,
-	0xeb, 0xf0, 0x51, 0x97, 0x91, 0x22, 0x9d, 0x71, 0x46, 0x7f, 0x50, 0x49,
-	0x8b, 0x39, 0x44, 0x7f, 0x78, 0x8c, 0x02, 0x74, 0xba, 0x68, 0x4a, 0xd8,
-	0x72, 0x39, 0x19, 0x33, 0x00, 0x07, 0xda, 0xd9, 0x26, 0x0d, 0xe3, 0x39,
-	0x6a, 0xf3, 0xfa, 0x21, 0xc8, 0xcc, 0xb7, 0x87, 0xb2, 0xd3, 0x62, 0xbe,
-	0xb0, 0x2f, 0xce, 0xf3, 0x75, 0x00, 0xee, 0x1d, 0xe0, 0xa5, 0x90, 0x26,
-	0x78, 0x95, 0xa0, 0xec, 0x84, 0x02, 0x79, 0xc2, 0x53, 0xd0, 0x2d, 0x0d,
-	0xfc, 0x35, 0xb2, 0xfa, 0x14, 0xca, 0x59, 0x9b, 0x28, 0x6f, 0xa0, 0x5d,
-	0xbc, 0xa0, 0x26, 0xed, 0x66, 0x4a, 0x69, 0x61, 0xec, 0x5f, 0xc8, 0x0a,
-	0x8d, 0xe1, 0x1b, 0xd5, 0x62, 0x98, 0x9f, 0x61, 0xef, 0xc3, 0x82, 0xfe,
-	0x4d, 0xf1, 0xfd, 0x74, 0x69, 0x22, 0xaf, 0x26, 0x4b, 0xed, 0xe4, 0x9b,
-	0x89, 0x40, 0x9a, 0xc7, 0xd5, 0xd4, 0x19, 0x8d, 0xfc, 0x93, 0x0a, 0x41,
-	0x3e, 0x0c, 0x5f, 0xfc, 0xb8, 0xba, 0xb3, 0x74, 0x41, 0x4d, 0x95, 0xf8,
-	0x1b, 0xc0, 0x16, 0x55, 0xd0, 0x96, 0xdf, 0xb7, 0x83, 0x96, 0x34, 0xac,
-	0xc6, 0x75, 0x3d, 0x51, 0x64, 0x99, 0xe5, 0x6f, 0xc1, 0x0f, 0xec, 0xe5,
-	0x9c, 0x0d, 0xfe, 0x08, 0x7e, 0x85, 0xc1, 0xaf, 0x6f, 0x82, 0x5f, 0xfd,
-	0xe0, 0x53, 0x8c, 0xde, 0x28, 0xf5, 0xd2, 0x6b, 0xa5, 0x1e, 0x7a, 0x15,
-	0x32, 0xf9, 0x4a, 0x29, 0x4c, 0x2f, 0x97, 0x3a, 0xe8, 0xa5, 0x52, 0x88,
-	0xce, 0x0b, 0x1e, 0xa6, 0x21, 0xff, 0x82, 0xaf, 0xfa, 0x26, 0xf0, 0xa4,
-	0x1d, 0x3c, 0x59, 0x0f, 0x79, 0xd9, 0x08, 0xf9, 0x9b, 0xee, 0xd6, 0x69,
-	0xaa, 0x9b, 0x12, 0x41, 0xf4, 0x6f, 0x89, 0x6b, 0x82, 0x4e, 0x1a, 0xc6,
-	0xc7, 0x26, 0xfc, 0x94, 0x32, 0x4e, 0xd3, 0x7b, 0x93, 0x1a, 0x8d, 0x95,
-	0xa6, 0x36, 0x3a, 0x7c, 0xe3, 0xf6, 0x2c, 0x5d, 0x44, 0x5f, 0xca, 0x98,
-	0xa5, 0x4b, 0xdb, 0x54, 0x1a, 0x9d, 0xfe, 0x1b, 0x4a, 0x9e, 0x39, 0x4d,
-	0x3f, 0xfe, 0x3a, 0x51, 0x06, 0x34, 0x51, 0xfb, 0x7e, 0x5a, 0x4e, 0x18,
-	0xa0, 0x45, 0x5f, 0xaf, 0x90, 0x08, 0xb5, 0x8f, 0x79, 0x19, 0x86, 0xae,
-	0x68, 0x4a, 0xca, 0x7e, 0x01, 0xfa, 0xd2, 0xaa, 0x24, 0xa7, 0x88, 0x72,
-	0x53, 0x65, 0xca, 0xc5, 0xfc, 0xf4, 0x98, 0x51, 0xa6, 0x74, 0xac, 0x89,
-	0xbe, 0x68, 0xb4, 0xd3, 0x68, 0xef, 0x6f, 0xf8, 0xdc, 0x5c, 0x65, 0xba,
-	0xd4, 0x8f, 0x77, 0xee, 0x23, 0x9a, 0x12, 0xef, 0x4e, 0x7f, 0xbe, 0xe4,
-	0xa7, 0x84, 0x99, 0x0f, 0x69, 0xf4, 0x8e, 0xcf, 0xc1, 0x29, 0xe1, 0x8e,
-	0x81, 0x57, 0xc3, 0xb0, 0x0f, 0x8e, 0x0c, 0x66, 0x27, 0xd6, 0x5c, 0x4b,
-	0x88, 0x6e, 0xc0, 0x0b, 0xd9, 0xd3, 0x18, 0x8f, 0x61, 0x25, 0x6e, 0x52,
-	0xa7, 0xd0, 0x8d, 0x7e, 0xc0, 0x0c, 0x28, 0xfb, 0x4a, 0xcc, 0x6b, 0xbc,
-	0x17, 0x19, 0xd7, 0xcd, 0x80, 0xd5, 0xf0, 0x4c, 0x48, 0x9c, 0xbd, 0x78,
-	0xf2, 0x5c, 0x8c, 0x27, 0x3f, 0x7f, 0xcf, 0x83, 0xe7, 0xe7, 0x2b, 0xef,
-	0x53, 0x9e, 0xf7, 0x7c, 0xe9, 0x4f, 0x03, 0x0e, 0x7e, 0x4c, 0xcf, 0x01,
-	0x1a, 0x9d, 0x38, 0x2c, 0xd7, 0xc2, 0x7b, 0x91, 0xd7, 0x38, 0x0d, 0x3a,
-	0x09, 0xc8, 0x15, 0xd6, 0x3a, 0xec, 0x59, 0xeb, 0x49, 0xcf, 0x5a, 0x4f,
-	0x7a, 0xd6, 0xca, 0x83, 0xb6, 0xb4, 0x4e, 0xb5, 0xfc, 0xd0, 0x51, 0xee,
-	0x39, 0x8e, 0x39, 0x9f, 0x03, 0x5f, 0xbe, 0x0a, 0x98, 0x38, 0x2d, 0xda,
-	0xa0, 0xc7, 0x94, 0x46, 0x7b, 0x4d, 0x7e, 0x7f, 0xb1, 0xd5, 0xc1, 0x8b,
-	0xdf, 0x2f, 0x48, 0x9c, 0x5a, 0x1d, 0xb8, 0xd2, 0x15, 0xa1, 0xff, 0xf3,
-	0x25, 0xd6, 0x4f, 0x8a, 0xf9, 0x2c, 0x3a, 0x94, 0x8e, 0xb5, 0xd3, 0x98,
-	0xa1, 0xc4, 0x46, 0x7b, 0x9a, 0x99, 0x8e, 0x09, 0xd5, 0x6a, 0x85, 0x0e,
-	0x50, 0x58, 0x65, 0xdb, 0x25, 0xf0, 0x7b, 0x49, 0xe2, 0x61, 0x70, 0x3b,
-	0xa3, 0x5a, 0xc1, 0xba, 0x7e, 0x96, 0xdf, 0x57, 0xf0, 0xce, 0x32, 0x9c,
-	0xd4, 0x9c, 0xb5, 0x5f, 0x45, 0x9b, 0xed, 0xce, 0x66, 0xd9, 0x76, 0xc7,
-	0xff, 0xa0, 0xa9, 0xb6, 0xfd, 0x05, 0xb3, 0xb6, 0xed, 0xea, 0x82, 0xd7,
-	0x66, 0xf1, 0xde, 0xc2, 0xe4, 0xb3, 0x58, 0x8e, 0xfc, 0xc0, 0x35, 0x06,
-	0x3d, 0x6c, 0x96, 0x38, 0x7c, 0x4b, 0xe2, 0x00, 0x5c, 0x01, 0x37, 0x5a,
-	0xe2, 0x6f, 0x04, 0x4b, 0xea, 0xda, 0x4c, 0x43, 0xf7, 0x7d, 0xad, 0x18,
-	0xbf, 0xec, 0xe3, 0x75, 0xdc, 0x27, 0x29, 0x69, 0xe8, 0xc9, 0xd8, 0xb4,
-	0x46, 0xd9, 0xd8, 0x26, 0x21, 0xd7, 0xd9, 0x58, 0xd5, 0x06, 0x8c, 0x4e,
-	0xd4, 0xdb, 0x00, 0xfe, 0x8e, 0x6d, 0x80, 0xa3, 0xfb, 0x63, 0xd3, 0x6c,
-	0x0b, 0x1c, 0xdd, 0x3f, 0x36, 0xc1, 0x36, 0x41, 0xcc, 0x09, 0xfd, 0x67,
-	0x3b, 0xe0, 0xda, 0x00, 0xfe, 0x86, 0x6d, 0x80, 0x0f, 0xf2, 0xcd, 0xf3,
-	0xb9, 0x6b, 0x8f, 0xd7, 0xcd, 0x3b, 0xce, 0xb6, 0x45, 0xd9, 0xd9, 0xcd,
-	0x30, 0xc7, 0xb1, 0x76, 0x80, 0x0a, 0xd3, 0xcc, 0xc3, 0x48, 0xe8, 0x08,
-	0x1d, 0x17, 0x36, 0xef, 0xf4, 0x04, 0x25, 0x0e, 0x9e, 0x18, 0xa0, 0x34,
-	0x6c, 0xc0, 0xdc, 0xc4, 0xb5, 0x32, 0xf8, 0x78, 0x47, 0x13, 0x59, 0xb0,
-	0x75, 0xf0, 0x93, 0xfd, 0x7e, 0xf2, 0xc5, 0xe3, 0x90, 0xb7, 0x98, 0xf0,
-	0x5d, 0xd5, 0x9f, 0xa6, 0xed, 0xaa, 0x69, 0x37, 0xc1, 0x3f, 0x62, 0xde,
-	0xfe, 0x98, 0x90, 0x4d, 0xef, 0x2f, 0x09, 0x1b, 0x94, 0x8c, 0x7d, 0x08,
-	0xf9, 0x75, 0x69, 0xe4, 0xea, 0x1f, 0xdb, 0xfa, 0x2b, 0x1e, 0x1f, 0xb2,
-	0x05, 0x76, 0xdf, 0x84, 0x3c, 0xb9, 0x76, 0x9f, 0xed, 0x71, 0x88, 0x6d,
-	0x26, 0xf4, 0x8d, 0x6d, 0x70, 0x80, 0xd4, 0x19, 0x4d, 0xda, 0x69, 0x5d,
-	0xda, 0xe9, 0x00, 0x6c, 0x34, 0xb7, 0x0d, 0xd9, 0x36, 0x45, 0x1b, 0xf6,
-	0x1a, 0xf6, 0x70, 0x77, 0x3a, 0x35, 0xc1, 0xfe, 0x10, 0xbe, 0x7b, 0x86,
-	0x75, 0xf8, 0xdb, 0x43, 0x23, 0xd3, 0xc2, 0x07, 0xb0, 0xff, 0x80, 0x65,
-	0x66, 0x1b, 0xce, 0xb6, 0x1c, 0xfb, 0x2e, 0x62, 0xdd, 0x8a, 0xad, 0x64,
-	0x39, 0xf1, 0xe2, 0xc5, 0x38, 0xad, 0x21, 0xf5, 0xa4, 0x43, 0x6b, 0x35,
-	0xfe, 0xa8, 0x46, 0x2d, 0x4c, 0x63, 0xc6, 0x7f, 0x2b, 0x70, 0xe6, 0x7d,
-	0xfd, 0x4f, 0xe0, 0xcc, 0xeb, 0xd6, 0xe3, 0x4d, 0x7a, 0x6b, 0xfc, 0xac,
-	0xfe, 0xf0, 0x33, 0xa4, 0x37, 0xc7, 0xcf, 0xd2, 0xbf, 0x58, 0x74, 0x9f,
-	0x0e, 0x3f, 0xdb, 0xad, 0xc0, 0xcf, 0x16, 0xa1, 0xef, 0x53, 0x3a, 0x1d,
-	0x3c, 0x15, 0xc9, 0xfc, 0x2b, 0x45, 0x61, 0x3f, 0x76, 0xd0, 0xc8, 0x94,
-	0x42, 0x7a, 0x17, 0xb5, 0xc3, 0x7f, 0xf4, 0x37, 0x61, 0xfe, 0x5d, 0x44,
-	0x9b, 0x1d, 0xbf, 0xd9, 0x15, 0x1e, 0x05, 0xff, 0xd3, 0x2f, 0x7e, 0x05,
-	0xdf, 0x3c, 0x4d, 0x07, 0xa7, 0x0e, 0x2b, 0x39, 0xfb, 0x08, 0xe0, 0x97,
-	0x83, 0xd5, 0x01, 0x9b, 0x07, 0xec, 0x97, 0x31, 0xef, 0xd3, 0xa4, 0xdf,
-	0x1e, 0x19, 0x48, 0x28, 0xc0, 0xe3, 0x45, 0x01, 0x2f, 0x7d, 0x71, 0x97,
-	0xb1, 0x53, 0xf0, 0x3f, 0x40, 0xef, 0x15, 0x2f, 0x80, 0xbe, 0xbd, 0xf0,
-	0x39, 0x91, 0x67, 0x61, 0x93, 0xe1, 0x8f, 0x22, 0x57, 0x31, 0x2d, 0x7c,
-	0x11, 0x29, 0x0f, 0x76, 0xa7, 0x41, 0xef, 0x38, 0xfc, 0xd3, 0x00, 0xfc,
-	0x53, 0x0c, 0xbe, 0xa9, 0x07, 0x7e, 0xc9, 0x82, 0x5f, 0x0a, 0x83, 0x1f,
-	0x06, 0xcd, 0xc2, 0x47, 0xcd, 0x42, 0xfe, 0xe7, 0x66, 0x48, 0x19, 0x04,
-	0xad, 0xcf, 0xc1, 0x3f, 0x26, 0x63, 0x77, 0x42, 0xcf, 0x22, 0x17, 0x66,
-	0xd5, 0x41, 0xca, 0xc1, 0x9f, 0x77, 0x6e, 0x8b, 0x62, 0xbd, 0x26, 0x4a,
-	0x84, 0x5c, 0x1d, 0xe5, 0xdf, 0x7e, 0x85, 0xac, 0x7f, 0x06, 0xef, 0x22,
-	0x61, 0xa2, 0x3d, 0x94, 0xb5, 0xa3, 0x46, 0xa7, 0xda, 0x03, 0x18, 0x6e,
-	0x87, 0x95, 0x03, 0x53, 0x11, 0x05, 0xfb, 0x03, 0xcd, 0x27, 0x60, 0xeb,
-	0xcb, 0x34, 0x1e, 0x63, 0x3d, 0x29, 0xd3, 0xf3, 0xb1, 0xc8, 0x40, 0x9e,
-	0x5a, 0xe9, 0x98, 0x39, 0x21, 0x7c, 0xbc, 0x16, 0x3f, 0x21, 0x74, 0x2c,
-	0x67, 0xe1, 0x59, 0xec, 0x54, 0xb2, 0x53, 0xbc, 0x7e, 0x14, 0x5a, 0xee,
-	0xc7, 0x93, 0xe7, 0x07, 0xdd, 0xfa, 0x49, 0x39, 0xd8, 0x9d, 0x87, 0x77,
-	0x88, 0x18, 0x8b, 0x58, 0x39, 0x35, 0x11, 0x0d, 0x45, 0x55, 0x8d, 0x86,
-	0x35, 0x85, 0x46, 0x61, 0x6f, 0xd2, 0xb1, 0xff, 0x2c, 0x1f, 0x33, 0x79,
-	0xbc, 0x99, 0xbe, 0x2a, 0xfc, 0x0d, 0xd6, 0x2e, 0x4c, 0x63, 0x5d, 0x3f,
-	0xf8, 0xcb, 0xeb, 0xf2, 0x3c, 0x68, 0xc3, 0xf6, 0x6b, 0x56, 0xe4, 0xd9,
-	0x3c, 0xed, 0x00, 0x6d, 0xd9, 0x66, 0xc1, 0x3e, 0x0c, 0x60, 0xed, 0x5e,
-	0xd8, 0x4f, 0x3c, 0x93, 0xbd, 0x1c, 0x07, 0x05, 0x68, 0xd8, 0x64, 0x79,
-	0xd4, 0xe5, 0x98, 0xe9, 0x19, 0xf3, 0xcb, 0xb1, 0x20, 0xfe, 0xe0, 0x7f,
-	0x4d, 0x96, 0x19, 0x6e, 0x73, 0x4c, 0xc6, 0x34, 0x09, 0xd3, 0xdc, 0x64,
-	0x02, 0x34, 0x8b, 0x9c, 0x4d, 0x10, 0xd3, 0x0c, 0x46, 0x7b, 0x7f, 0x82,
-	0xbe, 0x64, 0xaf, 0xf7, 0x3b, 0xb6, 0xb0, 0x55, 0x49, 0xc1, 0x17, 0xa8,
-	0x56, 0x0b, 0x7c, 0x45, 0x98, 0x5e, 0x15, 0xb0, 0x64, 0xa8, 0xf1, 0x68,
-	0xe8, 0x4b, 0x74, 0xab, 0xb0, 0x11, 0x09, 0xc3, 0x4b, 0xe3, 0xff, 0x52,
-	0xc9, 0x72, 0xbf, 0x69, 0xa5, 0xec, 0x20, 0xf3, 0x89, 0xd7, 0x33, 0x68,
-	0xae, 0xe4, 0xbc, 0xfb, 0x10, 0xa3, 0x16, 0x60, 0x6b, 0xce, 0x4f, 0xaa,
-	0xf4, 0xf8, 0x1d, 0xf0, 0x65, 0xb1, 0x6d, 0x58, 0xcb, 0xc4, 0x78, 0x1e,
-	0x6d, 0x15, 0x6d, 0xe8, 0x99, 0x11, 0x02, 0x8f, 0xb9, 0x9f, 0xe1, 0x4c,
-	0xfc, 0xbd, 0xcf, 0xb1, 0x75, 0x3e, 0xab, 0xde, 0x4a, 0x14, 0x64, 0x7a,
-	0xc5, 0x40, 0x2b, 0xcb, 0x50, 0xd5, 0x6d, 0xc2, 0x5f, 0x3b, 0xb6, 0xc4,
-	0x82, 0x2e, 0xc2, 0xe6, 0xf6, 0x79, 0x75, 0x91, 0xe3, 0x09, 0x57, 0x17,
-	0x23, 0xa1, 0x84, 0x0a, 0x5b, 0xdc, 0xa7, 0xd1, 0x09, 0xd1, 0x56, 0x28,
-	0x31, 0x18, 0x09, 0x2d, 0xa8, 0x1c, 0x4b, 0x33, 0x6c, 0x18, 0xf1, 0x4a,
-	0x40, 0xc2, 0x22, 0x9e, 0xb3, 0xdd, 0x98, 0x30, 0x84, 0x7e, 0x53, 0xf4,
-	0x1f, 0xab, 0xe8, 0xa8, 0x13, 0xff, 0xa9, 0x88, 0x11, 0x0b, 0x88, 0x11,
-	0x53, 0x42, 0x47, 0x8d, 0x04, 0x72, 0x04, 0xd0, 0xdc, 0xd1, 0xcf, 0x42,
-	0x91, 0x71, 0xc9, 0xb1, 0x5c, 0x0e, 0x00, 0x99, 0x13, 0x8e, 0x7d, 0xa4,
-	0x3c, 0xc7, 0x91, 0xa3, 0xea, 0x53, 0x34, 0x5c, 0x60, 0x3f, 0x8e, 0x3f,
-	0x9b, 0x6d, 0x2d, 0xec, 0xa3, 0xf0, 0xc5, 0x51, 0xf0, 0x39, 0x0f, 0x1a,
-	0xac, 0x97, 0x74, 0xdd, 0x4f, 0x07, 0xec, 0x3d, 0xa0, 0x79, 0x9c, 0x46,
-	0x4e, 0x8d, 0xb0, 0xcc, 0xf6, 0x14, 0x28, 0xd2, 0x73, 0x8c, 0xb6, 0x1b,
-	0x73, 0x2c, 0xdf, 0x83, 0xe5, 0x1d, 0xe0, 0x85, 0xd0, 0x51, 0xc8, 0x20,
-	0x65, 0x0b, 0x23, 0xf4, 0x58, 0x89, 0xfb, 0xf2, 0xa0, 0x1d, 0xe2, 0xda,
-	0xfe, 0xfd, 0x52, 0xce, 0x31, 0x9f, 0xe6, 0xce, 0x37, 0x22, 0xe7, 0x63,
-	0x38, 0x86, 0xe1, 0x6f, 0xaa, 0xf3, 0xee, 0x14, 0x3c, 0x8d, 0x18, 0x5d,
-	0x6a, 0x79, 0x87, 0x1f, 0xe3, 0xcf, 0xf7, 0xf3, 0x3b, 0xe6, 0x81, 0xef,
-	0x6f, 0xb6, 0xf6, 0x00, 0x76, 0x10, 0x73, 0xfa, 0xa9, 0xb3, 0xdd, 0xc5,
-	0x37, 0x81, 0xb5, 0xd9, 0xcf, 0x31, 0x9f, 0x1f, 0xa1, 0xec, 0xa9, 0x7c,
-	0x8f, 0x0a, 0x19, 0x9b, 0xcd, 0x28, 0xe4, 0xb7, 0x1e, 0xa6, 0xdc, 0xa9,
-	0xa3, 0x6c, 0x37, 0x40, 0xab, 0x3d, 0xb4, 0x6b, 0x22, 0xd2, 0x73, 0x80,
-	0x34, 0xb1, 0xce, 0x5b, 0x24, 0xe8, 0x1f, 0x9b, 0x15, 0xbe, 0x20, 0x43,
-	0xe9, 0x89, 0xed, 0xa1, 0x4b, 0xe8, 0x1b, 0x1e, 0x8c, 0x84, 0x17, 0xe8,
-	0x09, 0xd0, 0xe5, 0x23, 0xf8, 0x22, 0xab, 0x67, 0x0c, 0x3a, 0x84, 0x9c,
-	0x0a, 0xeb, 0x8f, 0x4a, 0xda, 0xe0, 0xbb, 0xcc, 0x51, 0xd0, 0x8f, 0xf2,
-	0x0e, 0x4d, 0x99, 0x9e, 0x4c, 0xcb, 0xaf, 0xc0, 0xf6, 0x1c, 0x11, 0xb1,
-	0x4b, 0x56, 0xd0, 0xee, 0xd2, 0x06, 0x47, 0x0e, 0x60, 0x8b, 0x30, 0xef,
-	0xe5, 0x41, 0x85, 0xb6, 0x20, 0x4e, 0x3f, 0x24, 0x78, 0xeb, 0xa3, 0x7d,
-	0x66, 0xd4, 0xd8, 0x47, 0xf3, 0x7e, 0x27, 0x56, 0xc0, 0x3c, 0x3d, 0xf7,
-	0x60, 0x0f, 0x90, 0x53, 0xfb, 0xeb, 0xeb, 0xa8, 0x2d, 0x12, 0x4e, 0xa8,
-	0x09, 0xfa, 0x93, 0xd2, 0xdd, 0xe4, 0xe8, 0x77, 0x2b, 0xdb, 0x7e, 0xf0,
-	0xb0, 0xd3, 0x69, 0x5b, 0x78, 0x16, 0x3a, 0xb1, 0x1e, 0xe3, 0xfe, 0xac,
-	0xc0, 0x7d, 0x84, 0xba, 0xa1, 0x6b, 0x22, 0x8f, 0x39, 0x51, 0x8b, 0x17,
-	0xf3, 0xbc, 0x9e, 0xcf, 0x5f, 0xc6, 0x3c, 0xdc, 0xcf, 0x70, 0x78, 0x2f,
-	0x3c, 0x41, 0x23, 0x90, 0xc7, 0x5c, 0x7f, 0x57, 0x68, 0x0c, 0xdf, 0xa4,
-	0x4a, 0x4d, 0x74, 0x54, 0xe3, 0xf1, 0x48, 0x38, 0xaf, 0x1e, 0x42, 0xdc,
-	0xf3, 0xb8, 0xea, 0xb7, 0x7e, 0xe6, 0x67, 0xbf, 0xe3, 0xb7, 0xae, 0x29,
-	0xd5, 0xb9, 0x10, 0x87, 0x8a, 0xdc, 0x60, 0x41, 0x19, 0x2c, 0x5d, 0x52,
-	0x92, 0x85, 0x6b, 0x4a, 0xaa, 0xc4, 0x30, 0x8e, 0xce, 0x67, 0xcf, 0x74,
-	0x82, 0x4e, 0x1f, 0x89, 0xef, 0xe6, 0x7a, 0x8f, 0x50, 0xea, 0xd4, 0xad,
-	0x94, 0x9e, 0xe6, 0xbc, 0x34, 0x02, 0x7c, 0x3f, 0x2a, 0xe7, 0x62, 0x41,
-	0xca, 0x9d, 0xe1, 0x31, 0xb6, 0x5f, 0xd6, 0xd5, 0x45, 0x1f, 0xef, 0x9f,
-	0xf9, 0x6f, 0x52, 0xc1, 0x7e, 0x53, 0xd2, 0x8f, 0xdf, 0x7d, 0x9c, 0x93,
-	0xe1, 0xf7, 0x6f, 0x86, 0xd3, 0xb7, 0x95, 0x16, 0x36, 0xdc, 0xc8, 0x3e,
-	0x57, 0xb3, 0xc7, 0x47, 0x7d, 0x7e, 0x6b, 0x7b, 0x13, 0xb5, 0x84, 0x80,
-	0xc3, 0x4a, 0x7b, 0x64, 0x98, 0x5f, 0x87, 0x1c, 0xb0, 0x4d, 0xd9, 0x0d,
-	0x7e, 0x5a, 0x6c, 0xc3, 0x60, 0x93, 0x76, 0x53, 0xae, 0xc4, 0xb2, 0x1d,
-	0x35, 0x32, 0x90, 0xb1, 0x34, 0x75, 0xb1, 0x1e, 0xb9, 0xba, 0x07, 0xdb,
-	0x9d, 0x87, 0xed, 0x46, 0x3c, 0x64, 0x53, 0xbe, 0x29, 0xce, 0x36, 0xbc,
-	0x0b, 0xb2, 0x85, 0xbe, 0x62, 0x55, 0x17, 0x77, 0x2d, 0xc1, 0x5d, 0x5b,
-	0xc2, 0xa3, 0x02, 0xd5, 0xe2, 0x3f, 0x4b, 0x8c, 0xff, 0x5f, 0x00, 0xff,
-	0xcf, 0x01, 0x7f, 0xc6, 0xa9, 0x31, 0xfe, 0x3b, 0x2b, 0xf8, 0x33, 0x0c,
-	0xfc, 0x1c, 0x64, 0xf1, 0x0d, 0xe8, 0xe2, 0x6b, 0x36, 0x7c, 0x9d, 0x0d,
-	0xff, 0x67, 0xc3, 0xdf, 0xd9, 0xf0, 0x8b, 0x36, 0x7c, 0x1e, 0xf6, 0x74,
-	0x0e, 0x36, 0xe9, 0xac, 0x9d, 0x34, 0x58, 0x9f, 0x92, 0x31, 0xf6, 0x9d,
-	0xbb, 0x65, 0xde, 0x1d, 0x92, 0x71, 0xf7, 0xa7, 0x64, 0x2c, 0x7b, 0x00,
-	0xb1, 0xec, 0x66, 0x1a, 0xed, 0xe1, 0x9c, 0xa4, 0x05, 0xcf, 0x75, 0x78,
-	0x22, 0x6e, 0xed, 0x49, 0x48, 0xbd, 0xfc, 0x0c, 0x62, 0x5c, 0xd8, 0xff,
-	0x1e, 0xe4, 0x37, 0x19, 0xc4, 0x6a, 0x56, 0x1f, 0xc7, 0xe5, 0xb0, 0x65,
-	0xef, 0x37, 0x39, 0x76, 0xfe, 0x2e, 0x19, 0x03, 0xbb, 0xed, 0x56, 0xc0,
-	0xa4, 0xd1, 0xd7, 0x8a, 0x6f, 0x7e, 0x07, 0xb2, 0xdf, 0x86, 0xf6, 0xce,
-	0x3a, 0x18, 0xe4, 0xb3, 0x56, 0x16, 0x7d, 0x11, 0xc0, 0xb4, 0x61, 0x9d,
-	0x0e, 0xb4, 0xf7, 0xa0, 0x7d, 0x8b, 0xb3, 0x8e, 0xf1, 0x2b, 0x68, 0xa7,
-	0xea, 0xbe, 0xd9, 0x8a, 0xbe, 0x4c, 0x5d, 0xdf, 0x9b, 0xe8, 0x4b, 0xa2,
-	0x6f, 0x51, 0x7e, 0x97, 0x47, 0x3b, 0x52, 0x07, 0xb3, 0x88, 0x3e, 0xc6,
-	0xf1, 0x5b, 0x78, 0xde, 0x47, 0xa3, 0x19, 0x8e, 0x03, 0xdc, 0xb1, 0xdc,
-	0x7a, 0x6a, 0xe3, 0xdc, 0xf7, 0x43, 0x21, 0x3b, 0xf3, 0xd2, 0x46, 0xa7,
-	0x27, 0xd8, 0x4f, 0x8c, 0x20, 0xee, 0xe1, 0x71, 0xe1, 0x9c, 0x3c, 0xfd,
-	0x1f, 0x00, 0xf6, 0x61, 0x8c, 0x21, 0x56, 0xb7, 0xcb, 0x4d, 0x8d, 0xc7,
-	0x1f, 0xc5, 0xf8, 0x5f, 0xca, 0x6f, 0x2b, 0x73, 0x03, 0xfe, 0x1b, 0x75,
-	0x7d, 0x6a, 0xb0, 0xb6, 0xbd, 0xd6, 0xf3, 0xbe, 0x4d, 0x5f, 0xfa, 0xfd,
-	0x48, 0x1d, 0xfc, 0xef, 0x6e, 0xa8, 0x6d, 0x3f, 0xc5, 0xdf, 0x20, 0x87,
-	0x70, 0xdb, 0x09, 0xc8, 0x1d, 0xdb, 0xa4, 0xfa, 0x79, 0x3e, 0x6b, 0xd4,
-	0xf6, 0x6d, 0x32, 0x6b, 0xdb, 0x1c, 0x27, 0x31, 0x5c, 0x08, 0xf2, 0xde,
-	0xa1, 0xec, 0xb2, 0x7f, 0x13, 0xe3, 0x61, 0xe5, 0x5e, 0xdb, 0x8b, 0x67,
-	0x48, 0xe6, 0x46, 0xe1, 0x4a, 0xcc, 0x3b, 0x5f, 0x0a, 0x40, 0xae, 0x3e,
-	0x0f, 0x9e, 0x73, 0xdc, 0x53, 0xd5, 0xf1, 0xf7, 0x68, 0x39, 0x1d, 0x67,
-	0x1f, 0xc0, 0x31, 0xfe, 0x36, 0x11, 0x1f, 0xfb, 0xe2, 0x4f, 0x70, 0x0c,
-	0xf6, 0xb4, 0xe3, 0x5b, 0x2c, 0xf8, 0x43, 0xb4, 0x4b, 0x7e, 0xc7, 0x6e,
-	0x22, 0x9f, 0xc8, 0x16, 0xd8, 0x9f, 0xb1, 0x0f, 0x89, 0xc0, 0x4e, 0xb3,
-	0x1f, 0xfd, 0x24, 0x7d, 0xc6, 0x5d, 0xcd, 0x6c, 0xfb, 0x34, 0xeb, 0x05,
-	0xc4, 0x0b, 0x1c, 0xe7, 0xb1, 0xed, 0xc6, 0x7b, 0xd1, 0x8d, 0x57, 0xee,
-	0xd7, 0xc8, 0xaa, 0xfa, 0x11, 0x67, 0x8f, 0x5b, 0x59, 0x37, 0x56, 0xb1,
-	0xef, 0xc6, 0xb6, 0xed, 0xc7, 0x75, 0xb6, 0xe1, 0xb2, 0xb0, 0x0d, 0x0f,
-	0x6a, 0x7e, 0xeb, 0xf7, 0x9b, 0x1d, 0x79, 0x6d, 0x6c, 0x1b, 0xee, 0xad,
-	0xd8, 0x06, 0x57, 0x5e, 0xbd, 0x79, 0xeb, 0x0f, 0xc0, 0x1b, 0x0b, 0xbc,
-	0xa9, 0xaf, 0xd5, 0x70, 0x8e, 0xe2, 0x87, 0x1f, 0xe2, 0x18, 0x91, 0x73,
-	0xd9, 0x18, 0xe5, 0x62, 0x45, 0xc4, 0x6a, 0x91, 0xd9, 0xd9, 0x4a, 0x8e,
-	0xf5, 0x35, 0x69, 0xbb, 0x6b, 0xe2, 0x22, 0x7a, 0xbc, 0x78, 0x09, 0xf8,
-	0x73, 0xbc, 0xa5, 0x49, 0x1b, 0xc1, 0xfd, 0xe3, 0x12, 0x47, 0x7e, 0xe7,
-	0x3a, 0x1e, 0x7c, 0x69, 0xf1, 0x47, 0xe0, 0x15, 0xc7, 0x7d, 0x51, 0x27,
-	0xde, 0xab, 0x89, 0xa9, 0xd7, 0xf8, 0xc9, 0xe2, 0x78, 0x89, 0x61, 0x74,
-	0x19, 0x2f, 0x05, 0x64, 0x5e, 0x63, 0xc8, 0x3c, 0x87, 0x63, 0x6d, 0xae,
-	0xb1, 0xd6, 0xc7, 0x50, 0x0b, 0x43, 0xc1, 0x6d, 0xcc, 0x13, 0x8e, 0xa1,
-	0xda, 0x28, 0x39, 0xe3, 0xc4, 0x50, 0x4e, 0x9d, 0xcd, 0xcd, 0x71, 0x5c,
-	0x5c, 0xd9, 0x0f, 0xef, 0xc0, 0x3e, 0x45, 0x9e, 0x14, 0x74, 0xea, 0x7f,
-	0x1a, 0xec, 0xf6, 0x51, 0xf4, 0x8f, 0xba, 0xfd, 0x9e, 0x5c, 0xc3, 0xc5,
-	0x85, 0x7d, 0xbd, 0x1b, 0xd3, 0xed, 0x96, 0x31, 0x1d, 0x62, 0x18, 0xdb,
-	0xc9, 0xbb, 0xf6, 0x16, 0x33, 0xe8, 0xe3, 0x75, 0x11, 0x1b, 0x12, 0xc7,
-	0x49, 0x90, 0xaf, 0xfd, 0x91, 0x50, 0x58, 0xad, 0xc7, 0xab, 0x75, 0xa1,
-	0x16, 0xaf, 0x41, 0xf1, 0xdd, 0xf8, 0x92, 0xef, 0x48, 0xc4, 0x92, 0xe3,
-	0xf6, 0x10, 0xe8, 0xc5, 0xf8, 0xb9, 0xba, 0xe1, 0xc6, 0xc9, 0x8c, 0xd3,
-	0x3f, 0x82, 0xc6, 0xbb, 0x15, 0xfe, 0x7e, 0xcc, 0xde, 0x2f, 0xe8, 0x96,
-	0x15, 0xb8, 0x0e, 0x7b, 0x70, 0x1d, 0x91, 0xb8, 0xb2, 0x2e, 0xb0, 0x7e,
-	0x78, 0x6b, 0x9a, 0xa6, 0xd8, 0x1b, 0x70, 0x0e, 0xf3, 0xb9, 0xb9, 0x6a,
-	0x2d, 0x0c, 0xf9, 0xb6, 0xc1, 0x1f, 0x02, 0xd7, 0xac, 0x88, 0x43, 0x03,
-	0x0b, 0xf5, 0x34, 0x1c, 0xc7, 0x5a, 0x88, 0xdb, 0x81, 0x8f, 0xcb, 0xf3,
-	0x26, 0x89, 0xcf, 0x37, 0xc5, 0xdc, 0x63, 0xa2, 0x06, 0xea, 0xd3, 0x39,
-	0x77, 0xc9, 0x0a, 0xde, 0x69, 0x92, 0x77, 0x8f, 0x56, 0xf0, 0x73, 0x78,
-	0x1c, 0x90, 0x74, 0xe5, 0xdc, 0x95, 0x75, 0x5a, 0xf0, 0xa7, 0x9d, 0x73,
-	0xd3, 0x41, 0x6a, 0x14, 0x23, 0x2f, 0x0c, 0xa9, 0xdb, 0x1c, 0x3a, 0x3a,
-	0x31, 0xf2, 0xda, 0xba, 0x18, 0xf9, 0xb6, 0x20, 0xc7, 0x5a, 0xc3, 0x50,
-	0x82, 0x79, 0xf8, 0xba, 0x97, 0x6d, 0xc8, 0x36, 0x70, 0x3d, 0x5f, 0x53,
-	0xbb, 0xec, 0x59, 0xa6, 0xd6, 0x1c, 0x20, 0xdf, 0x0c, 0xfb, 0x0e, 0x0b,
-	0x79, 0x06, 0x91, 0x36, 0xc9, 0x3a, 0xcb, 0xbe, 0xbd, 0x1a, 0x67, 0xcf,
-	0x51, 0xa3, 0x18, 0xfb, 0x46, 0xfd, 0xfa, 0x79, 0xbf, 0xdf, 0x3a, 0xac,
-	0x3b, 0x36, 0x73, 0x25, 0xbf, 0xee, 0xc2, 0xed, 0x41, 0x9c, 0xad, 0x50,
-	0x93, 0x55, 0xc0, 0xfe, 0xde, 0xf0, 0x37, 0x5b, 0xae, 0x2e, 0x06, 0x68,
-	0xfd, 0xcc, 0x2d, 0x42, 0x1f, 0x8d, 0xc9, 0xaa, 0x3e, 0x8e, 0x82, 0x37,
-	0x19, 0xa7, 0x06, 0x60, 0xae, 0xa7, 0xeb, 0xd7, 0x0b, 0xc6, 0xed, 0x37,
-	0xfd, 0xaa, 0xe5, 0xca, 0xc0, 0xf5, 0xf2, 0x91, 0x4f, 0xd5, 0xd1, 0xba,
-	0x51, 0x4d, 0xf8, 0x2c, 0xe8, 0x1a, 0x47, 0xde, 0x1d, 0x79, 0x81, 0x10,
-	0x3b, 0x39, 0x79, 0x78, 0x1a, 0xb9, 0x77, 0xe4, 0x02, 0xe7, 0xe3, 0x6e,
-	0x7e, 0xfe, 0x6a, 0x29, 0x72, 0x36, 0x8f, 0x9c, 0x79, 0x1e, 0x39, 0xf9,
-	0xcb, 0xc8, 0xc9, 0xcf, 0x97, 0x7a, 0x41, 0xff, 0x1e, 0x99, 0x8f, 0xb3,
-	0x8e, 0x99, 0x74, 0x11, 0xb9, 0xd3, 0x77, 0x67, 0xd8, 0x46, 0x74, 0xd1,
-	0x3d, 0xc8, 0x35, 0xbe, 0x3f, 0xa9, 0x68, 0x9d, 0x7d, 0x01, 0x5f, 0xc2,
-	0xb8, 0x91, 0x38, 0x71, 0x29, 0x4f, 0x1a, 0xc7, 0x8a, 0x23, 0x4d, 0x7e,
-	0x6b, 0xae, 0x95, 0x5a, 0xf6, 0x2c, 0xcb, 0x93, 0x6a, 0xac, 0xe8, 0xc2,
-	0x19, 0xd4, 0xd9, 0xf7, 0x87, 0x9c, 0xdb, 0xc4, 0x48, 0xe4, 0xd3, 0xeb,
-	0xe8, 0xed, 0x93, 0x65, 0xda, 0x19, 0xbb, 0x56, 0xbe, 0x68, 0xad, 0xa3,
-	0x6c, 0xef, 0x43, 0x32, 0x97, 0x5c, 0x78, 0x28, 0x69, 0xe5, 0x43, 0x3e,
-	0xf7, 0x7c, 0x62, 0x42, 0x47, 0x84, 0xc8, 0xbf, 0x20, 0xcd, 0x0d, 0x20,
-	0x71, 0x6e, 0xd9, 0xfe, 0x02, 0x1f, 0x10, 0xb1, 0x6d, 0x9c, 0x33, 0x03,
-	0xa2, 0xd6, 0xb6, 0xd1, 0xe2, 0x7e, 0x03, 0xfc, 0xbe, 0x8f, 0xe6, 0x90,
-	0x43, 0x14, 0x44, 0x1e, 0xde, 0x0e, 0x78, 0x37, 0x0f, 0xbf, 0x1f, 0xb9,
-	0x01, 0xd3, 0xd8, 0x04, 0xfc, 0x6f, 0x03, 0xc6, 0x6b, 0x43, 0x9f, 0x6b,
-	0x22, 0xf1, 0x3d, 0x8f, 0xb7, 0x13, 0xd7, 0x65, 0xab, 0xf3, 0xf2, 0x9c,
-	0x3c, 0xf6, 0x61, 0xf9, 0xf6, 0xbe, 0x3e, 0xcf, 0xdc, 0x6d, 0x9e, 0xb9,
-	0xef, 0xf0, 0xcc, 0xed, 0xc3, 0xb7, 0x2e, 0x3e, 0x41, 0x7c, 0xeb, 0xae,
-	0xf1, 0xb7, 0x9e, 0x35, 0x5c, 0xdc, 0xdb, 0x3d, 0xb8, 0xbf, 0x8f, 0xf9,
-	0xb9, 0xcf, 0xf4, 0xf4, 0xf1, 0x9a, 0x1b, 0x68, 0x6e, 0xb0, 0x8d, 0x16,
-	0x4f, 0x72, 0x5f, 0xd0, 0x83, 0x0b, 0xe3, 0x17, 0x90, 0x63, 0x6d, 0x74,
-	0xf1, 0x64, 0x8b, 0xc0, 0x9b, 0xfd, 0xf9, 0xc6, 0xca, 0x9a, 0x57, 0xb0,
-	0xa6, 0x3b, 0x97, 0x89, 0x6f, 0x19, 0x96, 0xf1, 0xe3, 0x31, 0xee, 0xe3,
-	0xb1, 0x37, 0xcb, 0x5f, 0x33, 0x82, 0xce, 0x9e, 0x0d, 0xc6, 0xcd, 0xfd,
-	0x56, 0x6b, 0x26, 0x8b, 0xdb, 0x9d, 0x34, 0x1b, 0xd4, 0xc0, 0x37, 0x55,
-	0xfa, 0x28, 0xae, 0x23, 0xa8, 0x4a, 0xb4, 0x8f, 0xf9, 0xbc, 0x4e, 0xd6,
-	0xaf, 0x5b, 0x30, 0x6f, 0xd8, 0xcd, 0xd1, 0x88, 0xe5, 0x38, 0x27, 0xec,
-	0xbe, 0x26, 0xc7, 0xd9, 0xee, 0xb3, 0xdf, 0xc7, 0x53, 0xc8, 0xaa, 0x3c,
-	0xaf, 0x29, 0xed, 0xa0, 0x83, 0x50, 0xcf, 0x8b, 0xb2, 0x9e, 0xb2, 0xe8,
-	0xad, 0x99, 0x18, 0x4e, 0x1c, 0xe3, 0x9c, 0xed, 0xac, 0x85, 0xfe, 0xe0,
-	0xbd, 0x98, 0x00, 0x1e, 0x61, 0x8a, 0xe2, 0xaf, 0x50, 0xca, 0xe3, 0x69,
-	0xe1, 0xa9, 0xe0, 0xc9, 0xf5, 0x0c, 0x1d, 0x4f, 0xe8, 0x18, 0xec, 0x53,
-	0xb4, 0xef, 0x92, 0x93, 0x3f, 0x41, 0x37, 0xde, 0x9e, 0x74, 0xea, 0x51,
-	0x8b, 0xd6, 0x72, 0xf5, 0xa8, 0x3f, 0x67, 0x9e, 0x9c, 0x70, 0xeb, 0x51,
-	0x8b, 0x24, 0xea, 0x51, 0x27, 0x56, 0xa8, 0x47, 0x25, 0x56, 0x5f, 0x8f,
-	0xe2, 0xf9, 0x35, 0xda, 0xd7, 0x4f, 0xca, 0x17, 0x64, 0x3d, 0xea, 0x3d,
-	0x72, 0xea, 0x51, 0x17, 0xa9, 0x71, 0x3d, 0xea, 0x78, 0x5d, 0x3d, 0x2a,
-	0x28, 0xea, 0x51, 0x3c, 0x8f, 0x53, 0x8f, 0x12, 0xed, 0xbe, 0x88, 0xa7,
-	0xee, 0x42, 0xf4, 0xee, 0x64, 0x07, 0x68, 0x66, 0xd0, 0xf7, 0x1a, 0xda,
-	0x34, 0x45, 0xc8, 0xdb, 0x4a, 0x35, 0xd0, 0x07, 0x6e, 0xb8, 0xbe, 0xa2,
-	0xd0, 0x06, 0xcc, 0x9b, 0xec, 0x7b, 0xd8, 0x53, 0x63, 0x61, 0x9a, 0xff,
-	0x62, 0xea, 0x2c, 0x07, 0x45, 0x9d, 0xe5, 0x87, 0x6b, 0xbc, 0x75, 0x96,
-	0x45, 0xba, 0x7e, 0x9d, 0xe5, 0x60, 0x83, 0x3a, 0xcb, 0x5b, 0x54, 0xad,
-	0xb3, 0xbc, 0x45, 0xd5, 0x3a, 0xcb, 0xc1, 0x12, 0xe7, 0xe2, 0x3e, 0x89,
-	0x5f, 0x06, 0xed, 0x41, 0xf1, 0xc7, 0xb5, 0x97, 0xc5, 0xca, 0x1e, 0x7e,
-	0xd9, 0x6a, 0x2f, 0x6c, 0x03, 0x22, 0x17, 0x2e, 0xd7, 0xd4, 0x5e, 0xb8,
-	0x0d, 0x9d, 0xb1, 0xd7, 0x08, 0x19, 0x99, 0x83, 0x7f, 0x5f, 0x9c, 0x0c,
-	0x61, 0xce, 0x0e, 0xf8, 0x8c, 0x0e, 0xe4, 0x06, 0x61, 0xb4, 0x15, 0xda,
-	0x64, 0x0d, 0xa1, 0x8f, 0xc7, 0xd9, 0x0e, 0x43, 0xb7, 0x6c, 0x77, 0x7f,
-	0x0f, 0x48, 0x1a, 0x44, 0x68, 0xb8, 0x9d, 0xf4, 0x20, 0xfb, 0x8e, 0xc9,
-	0x3d, 0x74, 0xc8, 0xde, 0x22, 0xf6, 0xbd, 0xc1, 0xaa, 0x95, 0xb9, 0xc1,
-	0x1b, 0x90, 0xb9, 0xcc, 0xaa, 0x65, 0x8e, 0xe5, 0xcd, 0x39, 0xf7, 0xdd,
-	0x60, 0xf1, 0xfa, 0x1d, 0x02, 0xa7, 0x77, 0x1b, 0xc8, 0xfb, 0x18, 0xec,
-	0x8e, 0x33, 0xbf, 0x2e, 0xd7, 0xab, 0x8f, 0x87, 0x9f, 0x6d, 0x66, 0xff,
-	0xbd, 0x72, 0x3d, 0xb1, 0xde, 0x7f, 0xaf, 0xe4, 0x47, 0x15, 0x61, 0x93,
-	0xb3, 0x25, 0xae, 0xed, 0x7b, 0xf9, 0x33, 0x8f, 0x9c, 0x00, 0x7d, 0x42,
-	0x0f, 0x98, 0xae, 0x41, 0xf0, 0x01, 0xeb, 0xd8, 0x4f, 0xc9, 0x5a, 0x16,
-	0x9e, 0x05, 0x97, 0x7f, 0xad, 0xb0, 0x99, 0xee, 0x18, 0xdb, 0x01, 0x0b,
-	0xfe, 0x8f, 0xeb, 0x28, 0x7c, 0x8e, 0xca, 0xfd, 0x2e, 0x5f, 0xbb, 0x2e,
-	0xbc, 0xa7, 0x72, 0xbb, 0x5c, 0xce, 0x8a, 0x7a, 0x2d, 0xa9, 0x9d, 0x7d,
-	0xd3, 0x2d, 0x6c, 0x6b, 0xb6, 0x58, 0xae, 0xcc, 0x26, 0xf0, 0xce, 0x7c,
-	0x7d, 0x17, 0x36, 0x9c, 0xcf, 0xaa, 0xbf, 0x23, 0x6a, 0x04, 0x73, 0x36,
-	0xdb, 0x6b, 0x8e, 0x41, 0x7f, 0x0b, 0xb2, 0xc4, 0xef, 0x51, 0x71, 0x2e,
-	0x21, 0x6a, 0xf8, 0x83, 0xdc, 0x76, 0xed, 0x4a, 0x94, 0xed, 0x30, 0xf6,
-	0x5c, 0xa5, 0x31, 0xe2, 0x23, 0xc8, 0x0c, 0xc7, 0xb1, 0x0c, 0xe7, 0xc6,
-	0x9e, 0x9a, 0xa7, 0x66, 0xab, 0xcb, 0xb8, 0x88, 0x75, 0x39, 0x00, 0x9a,
-	0xed, 0x10, 0x31, 0xea, 0xb8, 0x5d, 0xa6, 0xea, 0x19, 0x3f, 0xd3, 0xdc,
-	0x39, 0xe7, 0x3f, 0x66, 0x2f, 0x47, 0xfb, 0xcd, 0x37, 0x48, 0x7b, 0x47,
-	0x1f, 0x6b, 0xe9, 0xae, 0x23, 0x7e, 0x71, 0xe9, 0xee, 0xfa, 0xa8, 0x49,
-	0x49, 0x83, 0xa8, 0xac, 0x2b, 0x7e, 0x5a, 0x9e, 0x29, 0xfd, 0x5f, 0xd8,
-	0xaf, 0xe2, 0xd9, 0xaf, 0xab, 0xbb, 0xfb, 0xe4, 0x7e, 0xc3, 0x75, 0xba,
-	0x1b, 0x97, 0x75, 0xb9, 0x5f, 0x84, 0xee, 0xba, 0x7b, 0xe2, 0xb5, 0xb7,
-	0x5c, 0x67, 0xdd, 0x67, 0x48, 0x8d, 0xaf, 0x14, 0x7b, 0xff, 0xb4, 0xf9,
-	0xe3, 0xc5, 0xde, 0x1f, 0x87, 0x9e, 0x5e, 0xbd, 0x65, 0x1a, 0xb6, 0x89,
-	0xb8, 0xc2, 0xd1, 0x1f, 0xd8, 0xe3, 0x82, 0x9f, 0x16, 0x1e, 0xd2, 0xe9,
-	0x9f, 0xee, 0xe4, 0xfa, 0xac, 0x26, 0x73, 0x7c, 0x6e, 0x7f, 0xb1, 0x95,
-	0x63, 0xab, 0x4d, 0xd6, 0x77, 0x44, 0x6e, 0x95, 0x57, 0x4d, 0x8f, 0x1f,
-	0x31, 0x30, 0xce, 0x63, 0x61, 0xba, 0x1c, 0xbc, 0x91, 0xb8, 0xbc, 0xcb,
-	0x58, 0xf4, 0xad, 0x26, 0x2e, 0xbf, 0x55, 0xf7, 0x5b, 0x7f, 0xdd, 0x7a,
-	0xbd, 0x3a, 0x47, 0x35, 0x2e, 0xe7, 0x7c, 0x3e, 0xe8, 0xd4, 0x18, 0x4c,
-	0x8e, 0xcf, 0xd7, 0x4a, 0x9e, 0xf0, 0x3b, 0x72, 0x11, 0x1b, 0x79, 0x08,
-	0x64, 0xfc, 0x55, 0xc8, 0xca, 0x2b, 0x36, 0xf2, 0x0e, 0x1b, 0xf9, 0x88,
-	0x8d, 0xdc, 0xc3, 0x46, 0xee, 0x61, 0xf7, 0xc8, 0x1c, 0x26, 0x23, 0xeb,
-	0x56, 0x7c, 0x46, 0xcb, 0xf9, 0x61, 0x5e, 0xc9, 0xd8, 0xe3, 0x7c, 0x1f,
-	0x41, 0x4d, 0xc6, 0x36, 0xca, 0x78, 0xf0, 0x38, 0xdf, 0x77, 0x28, 0xab,
-	0x71, 0xae, 0x45, 0x91, 0xaa, 0xc6, 0x6f, 0x87, 0x8f, 0xda, 0x0e, 0xbc,
-	0x9a, 0x79, 0xdc, 0xa7, 0xc6, 0x5b, 0x99, 0x76, 0x8a, 0x1a, 0x5f, 0x2b,
-	0xcf, 0x0d, 0x7a, 0x03, 0x0e, 0xfe, 0xdd, 0xdc, 0xd6, 0xd4, 0xf8, 0xdd,
-	0xec, 0xd3, 0xc2, 0xa4, 0xba, 0xfd, 0xb7, 0x07, 0x98, 0xae, 0xa4, 0xde,
-	0x16, 0xe0, 0xb8, 0x76, 0xde, 0xf6, 0x8b, 0x3b, 0x05, 0xc9, 0x18, 0xd7,
-	0xcc, 0xb8, 0x5d, 0xa5, 0xab, 0xba, 0x2c, 0x5d, 0xfd, 0x95, 0xfa, 0x3f,
-	0xd3, 0xd2, 0xc7, 0x70, 0xa2, 0x36, 0xc6, 0x34, 0x75, 0xe7, 0xe3, 0xf3,
-	0x66, 0x5e, 0x47, 0xdc, 0x63, 0xc0, 0xf3, 0x60, 0x33, 0xb5, 0x0d, 0x0e,
-	0xf9, 0x2d, 0xef, 0xba, 0x6c, 0x43, 0x76, 0x90, 0x37, 0xc7, 0x5a, 0x7e,
-	0xcd, 0xa8, 0x38, 0x1b, 0x49, 0xf6, 0x47, 0x85, 0xec, 0xb0, 0xac, 0x69,
-	0xe2, 0xce, 0xd5, 0x47, 0xe2, 0x1e, 0x09, 0xcb, 0x19, 0xcb, 0xf2, 0x78,
-	0x7f, 0x57, 0x58, 0x53, 0x5b, 0xb0, 0x46, 0x98, 0xd2, 0x25, 0x71, 0x56,
-	0x80, 0x7c, 0xe9, 0xdc, 0x3a, 0x6a, 0xfb, 0x07, 0xbd, 0x9a, 0xc7, 0x46,
-	0x9d, 0xb3, 0x7a, 0xbb, 0xde, 0xff, 0x8d, 0x8a, 0x73, 0x65, 0xc7, 0x06,
-	0xb9, 0xe7, 0xc3, 0xab, 0x3b, 0xff, 0xbe, 0xbe, 0x3e, 0xb5, 0xd4, 0xd7,
-	0x0d, 0x24, 0x0d, 0x98, 0x36, 0x8d, 0xcf, 0xee, 0xe7, 0x4b, 0x7c, 0xaf,
-	0x25, 0x12, 0xe3, 0xdc, 0x6d, 0x44, 0xdc, 0xf9, 0x50, 0x21, 0x85, 0x3a,
-	0x8d, 0x19, 0x9c, 0xf3, 0x85, 0x86, 0x7d, 0x71, 0xca, 0x64, 0x27, 0x48,
-	0x43, 0xac, 0x98, 0xa9, 0xd6, 0x03, 0x1f, 0x5c, 0x43, 0x96, 0x2b, 0x97,
-	0x51, 0xce, 0x1f, 0x6a, 0xce, 0xed, 0x16, 0xe9, 0xb0, 0x72, 0xa0, 0x74,
-	0x84, 0x0e, 0x34, 0x8c, 0x29, 0x1b, 0xd7, 0x03, 0x2f, 0xd6, 0xd5, 0x14,
-	0x16, 0x44, 0x4d, 0x21, 0xb7, 0xc6, 0x6f, 0x3d, 0x19, 0x70, 0xee, 0xb5,
-	0x34, 0xd6, 0x93, 0x5d, 0x15, 0x3d, 0x71, 0xe1, 0xf8, 0x2c, 0xbe, 0x8d,
-	0x76, 0x8a, 0xb5, 0x0e, 0x2b, 0x59, 0xbb, 0x95, 0x76, 0x1a, 0x0e, 0xd6,
-	0xa3, 0x36, 0xe3, 0x75, 0x58, 0x39, 0x68, 0xe7, 0x95, 0xb4, 0xa8, 0x3d,
-	0x70, 0x8c, 0xbf, 0xe6, 0xda, 0x30, 0x95, 0xe9, 0xed, 0x98, 0xfb, 0x3d,
-	0xc3, 0x78, 0x6b, 0x8a, 0x2e, 0x9d, 0xf8, 0x2e, 0x51, 0x58, 0xe6, 0x6f,
-	0xce, 0x7c, 0xb9, 0x29, 0xae, 0x25, 0xde, 0x8f, 0xfd, 0x33, 0xfc, 0x6e,
-	0x25, 0x39, 0x55, 0x2e, 0xa7, 0x31, 0x3e, 0xd6, 0x7b, 0xaf, 0xc8, 0x8d,
-	0xd4, 0x38, 0x0d, 0x71, 0x8e, 0xac, 0x2d, 0xc9, 0x91, 0xd3, 0xd0, 0x35,
-	0xc4, 0x20, 0x76, 0x13, 0xbe, 0x75, 0xe3, 0x91, 0xcf, 0xae, 0x75, 0x64,
-	0xe4, 0xbb, 0x12, 0x0f, 0x1e, 0xff, 0xfb, 0x80, 0x7b, 0x0f, 0x28, 0x77,
-	0x2a, 0x8d, 0xfd, 0x37, 0x51, 0xca, 0x74, 0xf2, 0xbb, 0xec, 0x99, 0x23,
-	0x1b, 0x6a, 0xe1, 0xd1, 0x77, 0xca, 0x85, 0x0f, 0xd6, 0xc1, 0xf3, 0x19,
-	0xd7, 0x5f, 0xd5, 0xc1, 0x07, 0x3d, 0xf0, 0x66, 0x1d, 0x3c, 0xe2, 0xae,
-	0x33, 0xdf, 0xa8, 0x83, 0x37, 0x3d, 0xf0, 0xed, 0x75, 0xf0, 0xed, 0x80,
-	0x7f, 0xa3, 0x0e, 0x1e, 0x7d, 0xa7, 0x90, 0x13, 0x08, 0xda, 0x70, 0x8c,
-	0x74, 0x48, 0xe6, 0x89, 0x78, 0x2e, 0xb9, 0x1f, 0xc9, 0xf2, 0xd3, 0x01,
-	0x1a, 0x7b, 0xeb, 0xb5, 0x09, 0xd8, 0xa8, 0xaa, 0x4c, 0x39, 0xfa, 0xea,
-	0x95, 0x25, 0x96, 0xbd, 0x3c, 0xe4, 0x15, 0x7a, 0x54, 0x80, 0x3e, 0x15,
-	0x5c, 0x5f, 0xca, 0x77, 0xaa, 0x22, 0xc7, 0x1d, 0x3d, 0x56, 0x68, 0xbd,
-	0x35, 0x2f, 0x73, 0x91, 0xab, 0x8c, 0x3b, 0xfc, 0x86, 0xeb, 0x3b, 0xe8,
-	0x84, 0x63, 0x57, 0x58, 0xbf, 0x79, 0x7e, 0x69, 0x5f, 0x4a, 0x2c, 0x87,
-	0xce, 0x3a, 0xe9, 0x25, 0x32, 0x1b, 0x5e, 0x52, 0x77, 0xf1, 0xd5, 0xd9,
-	0x77, 0x12, 0xf6, 0x3d, 0xd7, 0xe2, 0xb7, 0x36, 0xac, 0xbd, 0x9e, 0x7d,
-	0xcf, 0x78, 0xec, 0x7b, 0x38, 0x58, 0xf5, 0xf9, 0x8f, 0x09, 0x9f, 0xdf,
-	0xd1, 0xc0, 0x66, 0xac, 0xde, 0xe7, 0xef, 0xfd, 0xd8, 0x3e, 0x7f, 0xb9,
-	0x75, 0x57, 0xe3, 0xf3, 0x1f, 0x69, 0xf9, 0x78, 0x3e, 0x9f, 0xd7, 0xac,
-	0xaf, 0x65, 0x7a, 0xcf, 0x59, 0x8e, 0xca, 0x18, 0x7b, 0xb7, 0x27, 0xc6,
-	0x66, 0xfc, 0xbe, 0x27, 0xef, 0x02, 0x9e, 0x5e, 0xeb, 0xc8, 0xdb, 0x51,
-	0x19, 0xa7, 0x73, 0xec, 0x8d, 0xf7, 0xc2, 0x23, 0x90, 0xd1, 0x7c, 0x8f,
-	0x8f, 0x54, 0x9a, 0x35, 0x9d, 0xb3, 0xed, 0x9f, 0x6f, 0xae, 0x17, 0xa1,
-	0xcb, 0xc2, 0x9f, 0x24, 0x3e, 0x81, 0x5a, 0xea, 0x49, 0xc8, 0x8f, 0xbb,
-	0xaf, 0x95, 0x6a, 0xa9, 0xf5, 0xe7, 0x1f, 0x7c, 0xee, 0x41, 0xca, 0x03,
-	0x95, 0x73, 0x10, 0xaf, 0x4e, 0xe9, 0x94, 0x9d, 0x21, 0xdd, 0x8c, 0x93,
-	0xb2, 0x8f, 0x71, 0x8e, 0xfd, 0xb0, 0x52, 0x6f, 0x3f, 0x24, 0x6b, 0x30,
-	0xea, 0xb2, 0x77, 0x82, 0x7e, 0x02, 0x7c, 0x58, 0xaf, 0x9c, 0x1a, 0x8c,
-	0xea, 0xdc, 0x09, 0x3a, 0xfe, 0xf3, 0xbb, 0x13, 0xc4, 0xf3, 0x6b, 0xb4,
-	0xb7, 0xc1, 0x9d, 0x20, 0xdf, 0x2a, 0xef, 0x04, 0xad, 0x17, 0x35, 0x18,
-	0x9e, 0xc7, 0xa9, 0xc1, 0x70, 0xbb, 0xb3, 0x8f, 0xe5, 0x3a, 0x4c, 0xa3,
-	0x93, 0xb7, 0x88, 0x7b, 0xa8, 0x9d, 0x7d, 0xb5, 0xf2, 0xbd, 0xef, 0x13,
-	0x8d, 0xa5, 0x79, 0xbd, 0xa3, 0x0d, 0xef, 0xb6, 0x24, 0x3f, 0xc1, 0x9a,
-	0xcb, 0x21, 0x51, 0x73, 0xb9, 0xb3, 0xcd, 0x5b, 0x73, 0x51, 0x57, 0xb8,
-	0xdb, 0x72, 0xa8, 0x41, 0xcd, 0xc5, 0xef, 0xb9, 0xdb, 0xe2, 0xf7, 0xdc,
-	0x6d, 0x39, 0x24, 0xeb, 0x2b, 0xea, 0x2f, 0xd1, 0xdd, 0x96, 0xe4, 0x8a,
-	0x77, 0x5b, 0xb6, 0x4a, 0x7d, 0xf5, 0xc2, 0xaf, 0xfe, 0xbc, 0x32, 0x55,
-	0x67, 0xe7, 0x13, 0xc2, 0xce, 0xdf, 0xd5, 0xea, 0xb7, 0x9e, 0x69, 0xbb,
-	0x9e, 0x9d, 0xdf, 0x57, 0xd1, 0x53, 0xbe, 0xa3, 0xcd, 0x77, 0xbe, 0x58,
-	0x16, 0xf9, 0x7c, 0xa6, 0x89, 0x72, 0x03, 0xbf, 0x2a, 0x68, 0xf6, 0x58,
-	0x6f, 0xed, 0x99, 0x63, 0xf5, 0x5e, 0xa4, 0xee, 0xb9, 0x17, 0x69, 0xa2,
-	0x5f, 0xaf, 0xab, 0x87, 0x04, 0xe4, 0xdd, 0x7e, 0xf8, 0xc2, 0x19, 0x43,
-	0xda, 0x5e, 0xc4, 0x70, 0x98, 0xae, 0x50, 0xe4, 0x3b, 0x95, 0x6d, 0xe4,
-	0x9b, 0x71, 0xce, 0x4b, 0x54, 0x11, 0x63, 0x42, 0x8e, 0x8b, 0x7e, 0xe1,
-	0x6f, 0xd4, 0xb8, 0x23, 0xb3, 0xe3, 0xf6, 0x05, 0xe0, 0xbf, 0x21, 0x51,
-	0x6d, 0x9b, 0x95, 0x5a, 0xce, 0x58, 0xe5, 0x0e, 0xbf, 0x09, 0xfb, 0xe0,
-	0xdc, 0x07, 0xca, 0x98, 0x7c, 0x67, 0xe4, 0x62, 0x5b, 0xf5, 0x3e, 0xd0,
-	0x67, 0xa4, 0x9c, 0x3a, 0xf7, 0x81, 0x48, 0x4d, 0x40, 0x3e, 0x6e, 0xe4,
-	0x3e, 0x50, 0xd7, 0x92, 0xfb, 0x40, 0x2b, 0xf3, 0x66, 0xe9, 0x7d, 0xa0,
-	0xc6, 0xfc, 0xe1, 0xfb, 0x40, 0xff, 0xde, 0xe6, 0xdc, 0x43, 0x5d, 0x89,
-	0x3f, 0x6e, 0x9c, 0xf4, 0x11, 0xe0, 0xf9, 0x3e, 0x50, 0xe5, 0x1e, 0x90,
-	0xe7, 0x0e, 0x10, 0xdf, 0x25, 0x59, 0xee, 0x0c, 0xce, 0x7b, 0xff, 0xa4,
-	0xa7, 0x72, 0xff, 0xe4, 0x7c, 0xc9, 0xf5, 0xed, 0xee, 0xb9, 0x1c, 0xc7,
-	0x39, 0xbb, 0x44, 0x8e, 0x7a, 0xae, 0x54, 0x5b, 0xc3, 0x60, 0xbe, 0x8f,
-	0x16, 0xcf, 0x81, 0x3e, 0x6f, 0x89, 0xdc, 0x00, 0x7c, 0xde, 0xe2, 0x23,
-	0xe6, 0x1d, 0x29, 0xa0, 0x8b, 0x38, 0xcb, 0x75, 0xf8, 0xdd, 0x21, 0x64,
-	0xc1, 0x91, 0x8b, 0xdd, 0x9e, 0xf3, 0xd0, 0xaa, 0x1c, 0x38, 0x67, 0xba,
-	0x0e, 0xef, 0x6a, 0x65, 0x46, 0x9c, 0xdd, 0x0c, 0xed, 0xb5, 0x9c, 0xf3,
-	0xc6, 0xa8, 0x38, 0xb7, 0x6d, 0xaf, 0xb3, 0x5b, 0x3a, 0xe4, 0x06, 0x31,
-	0x67, 0x8c, 0xeb, 0xd5, 0x8c, 0xfb, 0x66, 0xc1, 0xe3, 0x46, 0x67, 0x71,
-	0x2b, 0xd7, 0xf1, 0xdc, 0x9a, 0x0a, 0x21, 0x97, 0xd8, 0x9d, 0xce, 0x09,
-	0xbb, 0xe9, 0xac, 0xdd, 0x29, 0xd6, 0xde, 0x58, 0x77, 0x96, 0xcd, 0x72,
-	0xb5, 0x5c, 0x4c, 0x70, 0x3d, 0x9a, 0xde, 0xb3, 0x84, 0xa6, 0xb5, 0xba,
-	0x84, 0xdc, 0xb5, 0x62, 0xe3, 0x3b, 0x2a, 0xba, 0x34, 0x2e, 0xee, 0x21,
-	0xbb, 0xe7, 0xb5, 0x0e, 0xfd, 0xaa, 0xba, 0xb7, 0x5c, 0x3c, 0x53, 0x4f,
-	0xbf, 0x4d, 0xff, 0x4b, 0xe8, 0x77, 0x15, 0xf4, 0xe3, 0x77, 0x03, 0xef,
-	0xef, 0x8a, 0x7a, 0xc0, 0xb9, 0x52, 0xe4, 0x78, 0x9e, 0x38, 0x4e, 0x88,
-	0xcc, 0x2e, 0x50, 0x0f, 0xe8, 0xc8, 0xff, 0xeb, 0xe2, 0xde, 0x9d, 0x60,
-	0xfa, 0xb2, 0x7d, 0x8f, 0xbc, 0x70, 0x99, 0xd8, 0xc6, 0xdf, 0x8d, 0x7d,
-	0x94, 0xcb, 0x2f, 0xc5, 0x5c, 0xfa, 0xb3, 0xee, 0x73, 0x9d, 0xaa, 0x76,
-	0x5f, 0x7b, 0x57, 0xed, 0x53, 0x1d, 0xf9, 0xcc, 0x34, 0x90, 0xcf, 0x8c,
-	0xdc, 0xa3, 0x6f, 0xa6, 0x71, 0xbc, 0x9a, 0x9a, 0xfc, 0xef, 0x5e, 0xae,
-	0x26, 0xb6, 0x8d, 0x22, 0x0a, 0xbf, 0xac, 0xd7, 0x4e, 0xe3, 0xa4, 0x61,
-	0x93, 0x3a, 0xad, 0x69, 0xd2, 0x60, 0xc7, 0x4b, 0x12, 0x29, 0xa5, 0xa4,
-	0x52, 0x55, 0x45, 0x60, 0xa9, 0x21, 0x4e, 0xda, 0x0a, 0x71, 0x70, 0x0b,
-	0x48, 0x51, 0xc5, 0x21, 0x4d, 0xd3, 0x7b, 0x85, 0x84, 0x54, 0xa1, 0x8a,
-	0x46, 0x4e, 0x02, 0x15, 0x4a, 0xe5, 0x0a, 0x96, 0x72, 0x41, 0xa2, 0xd8,
-	0x8e, 0x02, 0x52, 0x2a, 0xf7, 0xca, 0x85, 0xba, 0xbf, 0x08, 0x89, 0x03,
-	0x70, 0x06, 0x29, 0x2a, 0x3f, 0xe2, 0xc0, 0x8d, 0x1b, 0x54, 0x5d, 0xde,
-	0x37, 0xb3, 0x63, 0xaf, 0x77, 0xd7, 0x8e, 0x03, 0x11, 0x07, 0x27, 0xbb,
-	0xf6, 0xcc, 0xce, 0xec, 0xcc, 0x37, 0x6f, 0xbe, 0xf7, 0x37, 0xfd, 0xbe,
-	0x78, 0x8d, 0x5a, 0xdb, 0x5b, 0xf3, 0x55, 0xec, 0xe7, 0xaf, 0x37, 0x18,
-	0x57, 0xed, 0xba, 0xe4, 0xa9, 0xf5, 0xe3, 0x9a, 0x72, 0xd9, 0x1b, 0xf0,
-	0xfe, 0xc7, 0x68, 0x51, 0xd8, 0x86, 0x94, 0xad, 0xee, 0xc5, 0x40, 0x9b,
-	0xd9, 0xff, 0x33, 0x16, 0x03, 0x3e, 0x9b, 0x68, 0xad, 0x6d, 0x8a, 0xed,
-	0x71, 0xd9, 0x16, 0xde, 0xda, 0xc2, 0xb6, 0x10, 0x3c, 0x16, 0xfd, 0x9e,
-	0xb1, 0xa8, 0xc9, 0xea, 0xa1, 0x16, 0xed, 0x74, 0x88, 0x21, 0xbf, 0x9d,
-	0x67, 0x6c, 0x05, 0xca, 0xce, 0x4f, 0x5d, 0x36, 0x3c, 0xe0, 0x73, 0xdc,
-	0x59, 0xeb, 0xc0, 0x27, 0xb5, 0x9d, 0x1a, 0x51, 0xed, 0x01, 0x8f, 0xc9,
-	0xc5, 0x45, 0x82, 0xbe, 0x86, 0x36, 0xe3, 0x82, 0xe3, 0xfa, 0x39, 0x14,
-	0x8f, 0xf1, 0xfa, 0x1b, 0x88, 0xe5, 0x70, 0xda, 0x3f, 0xd9, 0x76, 0xae,
-	0x9c, 0xe5, 0xbd, 0x42, 0xd4, 0x63, 0xbd, 0xef, 0x52, 0xdb, 0x82, 0xa8,
-	0x27, 0xe3, 0x20, 0x1c, 0x1d, 0xd0, 0xe1, 0xe2, 0x8d, 0x74, 0x3f, 0xff,
-	0x9e, 0x13, 0xcc, 0xdd, 0x7f, 0xdd, 0x1d, 0x36, 0x3f, 0x34, 0x64, 0xae,
-	0xde, 0x56, 0xdc, 0x5d, 0xd9, 0x89, 0x06, 0x85, 0xaf, 0xc1, 0xad, 0x7b,
-	0x41, 0x76, 0x5d, 0xe0, 0x3d, 0x7c, 0xa8, 0xba, 0x7f, 0xef, 0x84, 0x7d,
-	0xe8, 0x99, 0x16, 0x62, 0x1d, 0x44, 0x8e, 0xe5, 0x2b, 0x53, 0xc8, 0x45,
-	0xaa, 0xe6, 0xef, 0x78, 0xf3, 0x3c, 0x20, 0x3f, 0x55, 0x9e, 0x87, 0xca,
-	0x23, 0xc5, 0x7b, 0x24, 0x02, 0xf2, 0x3c, 0xdc, 0x32, 0x18, 0xf5, 0xea,
-	0xdf, 0xc3, 0x2d, 0x7f, 0x57, 0x1c, 0xf9, 0x5b, 0xf0, 0xd8, 0xe3, 0x97,
-	0xf3, 0x6a, 0x2d, 0x20, 0xe7, 0x43, 0xf1, 0x94, 0xde, 0x00, 0x9e, 0x12,
-	0x9c, 0xeb, 0xa1, 0xa5, 0x2f, 0xf2, 0x5e, 0x7e, 0x08, 0x7b, 0xb9, 0x51,
-	0x8b, 0xe9, 0x95, 0x72, 0xf0, 0xdc, 0x3a, 0x64, 0xa2, 0xca, 0xb9, 0x81,
-	0x5c, 0x44, 0x2c, 0x3c, 0xe6, 0xba, 0xe4, 0x60, 0x11, 0xbf, 0xa9, 0x58,
-	0x52, 0xa5, 0x47, 0xbd, 0x23, 0xf2, 0x0c, 0xbe, 0x1b, 0x3f, 0xcc, 0x1c,
-	0x18, 0xf2, 0x13, 0x76, 0xa6, 0x43, 0x0e, 0x1f, 0xbe, 0xcc, 0xbf, 0x8d,
-	0x39, 0xd7, 0x92, 0x8b, 0xca, 0x6b, 0xa5, 0x4b, 0xfd, 0xd0, 0x41, 0xe6,
-	0x6f, 0x0e, 0x2f, 0xad, 0xb3, 0x41, 0xc4, 0x53, 0xda, 0xdb, 0x74, 0xa1,
-	0xd8, 0x0c, 0x83, 0xf5, 0xf8, 0x4b, 0x79, 0x38, 0x4f, 0x42, 0x70, 0x9e,
-	0x9f, 0x3a, 0xc2, 0xe6, 0x44, 0x4f, 0xb3, 0x38, 0x9c, 0x53, 0x55, 0xfc,
-	0xa9, 0x72, 0xaa, 0x6f, 0x8f, 0x3a, 0x10, 0xa7, 0xe6, 0xc7, 0x04, 0xe6,
-	0x1f, 0xfa, 0x9c, 0x5a, 0x87, 0xd0, 0xeb, 0x10, 0xf3, 0x87, 0x76, 0x8d,
-	0x06, 0x6b, 0xb0, 0x66, 0x13, 0x2f, 0x50, 0x2b, 0xb1, 0x7f, 0xc9, 0xd1,
-	0x0a, 0x9d, 0xed, 0x69, 0xa6, 0xf3, 0x9e, 0x08, 0xd4, 0x79, 0x83, 0x72,
-	0xa4, 0xcc, 0x80, 0x1c, 0x29, 0x37, 0x0e, 0x75, 0x17, 0x0e, 0xe3, 0x2e,
-	0x2e, 0x30, 0xc0, 0xdc, 0xb9, 0x8b, 0xf1, 0x04, 0xee, 0x1c, 0xa5, 0xd0,
-	0x07, 0x6e, 0xee, 0xec, 0xf7, 0x13, 0x49, 0x5c, 0xfe, 0xdb, 0xdc, 0xa9,
-	0xa0, 0x7e, 0x27, 0x7c, 0xfd, 0x86, 0x1c, 0x9f, 0x6c, 0xc8, 0x13, 0x82,
-	0x38, 0xfe, 0x4e, 0xf7, 0xd3, 0xbb, 0xf6, 0xd1, 0xa6, 0x09, 0xfd, 0x70,
-	0x74, 0xb1, 0xba, 0xee, 0x5f, 0xf0, 0xd9, 0xb9, 0xc1, 0x67, 0x43, 0xc2,
-	0x27, 0xd7, 0x25, 0xf6, 0x90, 0x9d, 0x93, 0x61, 0x9d, 0x1e, 0x19, 0x66,
-	0xf7, 0xd4, 0xec, 0xfc, 0x88, 0x21, 0xec, 0x73, 0x74, 0x0e, 0xb9, 0xef,
-	0x14, 0x1a, 0xc6, 0xa5, 0xe2, 0x3b, 0xe9, 0x1b, 0x38, 0x77, 0x04, 0xb2,
-	0x1b, 0xf2, 0xfc, 0xf4, 0x6c, 0xd8, 0x34, 0x1c, 0x1f, 0x03, 0xfc, 0x08,
-	0xc0, 0xa9, 0x7a, 0x7e, 0x90, 0x0d, 0x3d, 0x68, 0x0e, 0x87, 0x7c, 0x73,
-	0x28, 0xf1, 0x06, 0x6e, 0x8f, 0x58, 0xbc, 0x83, 0x9e, 0x38, 0xc5, 0x9d,
-	0x18, 0x93, 0xee, 0x80, 0x78, 0x41, 0xc4, 0xfa, 0xf9, 0xfa, 0xcb, 0xef,
-	0x7c, 0x51, 0xf3, 0xaf, 0xad, 0x49, 0x6d, 0xba, 0x3c, 0xad, 0x4d, 0x15,
-	0x51, 0xee, 0xa2, 0x56, 0xdb, 0x97, 0x36, 0x5d, 0x1c, 0x11, 0x7c, 0x30,
-	0x79, 0xad, 0x42, 0x78, 0x4f, 0xdb, 0xbe, 0x25, 0xb8, 0xed, 0x80, 0x0f,
-	0xab, 0x8a, 0x73, 0x18, 0x2d, 0xbc, 0x97, 0xb4, 0xbd, 0xb8, 0xb9, 0x8e,
-	0x5b, 0xbe, 0x3f, 0x1d, 0x20, 0xdf, 0x9b, 0xd9, 0x0a, 0x91, 0xbf, 0x29,
-	0xe2, 0xb2, 0xa9, 0x68, 0x21, 0xde, 0xf1, 0x30, 0xe2, 0x7b, 0xe1, 0xd7,
-	0xa8, 0x62, 0xe1, 0x6e, 0x30, 0x16, 0xaa, 0xf6, 0x60, 0x1d, 0xb9, 0xa3,
-	0x2c, 0x8b, 0xc3, 0xe9, 0x5e, 0x0a, 0x99, 0x28, 0xff, 0x6c, 0xe2, 0x3e,
-	0x1d, 0x73, 0x78, 0x09, 0xfc, 0x3c, 0xb2, 0xde, 0x4c, 0x0b, 0x76, 0xe1,
-	0x60, 0x7f, 0x46, 0x84, 0x65, 0xf3, 0x67, 0xbd, 0xad, 0xf9, 0x33, 0x54,
-	0x39, 0xd4, 0xed, 0xa2, 0x35, 0x0b, 0x71, 0x92, 0xf0, 0x2f, 0x75, 0x77,
-	0xb4, 0x9b, 0x41, 0xf2, 0x4f, 0xc5, 0x7e, 0x82, 0x1f, 0xc9, 0xb9, 0xba,
-	0x41, 0x98, 0x3b, 0x9b, 0xbe, 0x6f, 0x30, 0x57, 0xdb, 0xb1, 0x29, 0x37,
-	0x9f, 0x2b, 0xc3, 0x33, 0x57, 0xd8, 0x8b, 0x9a, 0xcd, 0x95, 0xf2, 0x43,
-	0x2a, 0xdf, 0xdc, 0x51, 0xc8, 0x93, 0x45, 0xf7, 0x5c, 0xed, 0x8c, 0x7f,
-	0x4e, 0xce, 0xd9, 0x4e, 0xfb, 0xe0, 0x1a, 0x8f, 0x43, 0x34, 0xd0, 0x76,
-	0x12, 0x2c, 0x33, 0xfc, 0x6b, 0xeb, 0x86, 0x5c, 0x5b, 0xcc, 0x2b, 0x9e,
-	0x6f, 0xb8, 0xb6, 0xb0, 0x0f, 0x5c, 0x70, 0xf6, 0x81, 0xd3, 0x3e, 0x7d,
-	0x51, 0xd9, 0xbc, 0xff, 0xab, 0xed, 0x0d, 0xcf, 0x7d, 0x22, 0xce, 0xe9,
-	0xc8, 0x91, 0xdc, 0x47, 0xce, 0x37, 0xe4, 0x61, 0x3d, 0xdb, 0x5c, 0xa7,
-	0x6a, 0xee, 0x91, 0x73, 0x01, 0x79, 0x99, 0xa5, 0xf3, 0xf9, 0xc7, 0x06,
-	0x75, 0xf7, 0x53, 0xa4, 0x1a, 0xd3, 0x72, 0x40, 0xf0, 0x61, 0xb7, 0xbe,
-	0xbc, 0xec, 0xe4, 0x28, 0xe6, 0x5c, 0x63, 0xb0, 0x9c, 0xcf, 0x36, 0x89,
-	0xa7, 0x6f, 0x25, 0x9e, 0x63, 0xc0, 0x23, 0x37, 0xbd, 0x73, 0x35, 0xa1,
-	0x65, 0xf2, 0xa8, 0xb3, 0x87, 0xce, 0xea, 0x9f, 0xf0, 0x18, 0x3d, 0xb1,
-	0x23, 0xe2, 0x9c, 0x11, 0xe0, 0xd2, 0xb6, 0x97, 0xcd, 0x0e, 0x5a, 0x94,
-	0x7e, 0x46, 0x9a, 0xfa, 0xf8, 0x12, 0x15, 0x85, 0x7f, 0x0b, 0xb9, 0x51,
-	0xb0, 0x71, 0xc3, 0x47, 0x87, 0xe7, 0xf0, 0xf7, 0x1b, 0x13, 0x8e, 0xcc,
-	0xfd, 0x93, 0x31, 0x8c, 0x7a, 0x38, 0x0b, 0x01, 0xeb, 0x9d, 0x34, 0xc9,
-	0x31, 0xb9, 0x1d, 0x71, 0x4e, 0x80, 0x8c, 0xcd, 0xbb, 0x5d, 0xde, 0x8e,
-	0x4f, 0xa1, 0x55, 0xbd, 0xe4, 0xeb, 0x68, 0xd8, 0xfc, 0x72, 0xcf, 0xf6,
-	0x7d, 0x0a, 0x2a, 0x77, 0x5f, 0x71, 0x58, 0x75, 0x2d, 0x73, 0x69, 0xc1,
-	0x99, 0xe7, 0xd7, 0x55, 0xde, 0x6d, 0x77, 0x40, 0xde, 0x6d, 0x88, 0xe6,
-	0x84, 0xaf, 0x2e, 0x44, 0x39, 0x47, 0x37, 0x93, 0x9c, 0x5a, 0xd9, 0x6a,
-	0x23, 0x4e, 0xfc, 0x29, 0xee, 0xdd, 0x39, 0xf9, 0x7c, 0x5f, 0x04, 0xcf,
-	0x46, 0x4e, 0xb5, 0x2d, 0x62, 0xf1, 0x33, 0xa2, 0x5c, 0xa7, 0xa7, 0x1c,
-	0xdf, 0x17, 0xd5, 0x33, 0x3b, 0xb9, 0x7c, 0x8a, 0x64, 0x0e, 0x7d, 0x27,
-	0xcd, 0x15, 0x9b, 0xf5, 0x6b, 0x1f, 0xe2, 0x81, 0xe3, 0xf0, 0x95, 0x0a,
-	0xbf, 0x95, 0xa1, 0xfa, 0x80, 0x3e, 0xb5, 0x57, 0xfb, 0x04, 0xf9, 0x14,
-	0x12, 0x7e, 0x05, 0xbe, 0x76, 0xda, 0x99, 0x23, 0x77, 0xbf, 0xc2, 0xdc,
-	0x2f, 0x3c, 0xa7, 0xd3, 0x55, 0xb6, 0xd3, 0x55, 0xb6, 0x36, 0x5e, 0x3a,
-	0xeb, 0x54, 0x0b, 0xe5, 0x1f, 0x59, 0x2f, 0xfd, 0x56, 0xd8, 0xe6, 0xe6,
-	0xb3, 0x06, 0x2d, 0xac, 0xf7, 0xf2, 0x27, 0xc6, 0x1f, 0x94, 0xdb, 0xcb,
-	0xff, 0xdd, 0x9c, 0xa2, 0x5f, 0xc4, 0x02, 0xb6, 0xce, 0x07, 0x83, 0xf1,
-	0x1f, 0xbc, 0x6e, 0x13, 0x01, 0xeb, 0xb6, 0xf9, 0xbe, 0x22, 0xf7, 0x93,
-	0xe4, 0x95, 0x8a, 0x23, 0xaf, 0x36, 0x69, 0xd0, 0x27, 0xa7, 0x82, 0xd6,
-	0x29, 0xfa, 0x78, 0xca, 0xe9, 0xe3, 0x9b, 0xa2, 0x3f, 0xe3, 0x54, 0xa8,
-	0xe6, 0x0d, 0x1f, 0xe1, 0xeb, 0x98, 0xb2, 0xd1, 0x35, 0x90, 0xab, 0xdf,
-	0x6c, 0x43, 0xc6, 0x04, 0x71, 0xb2, 0x03, 0x01, 0xfa, 0x80, 0xee, 0xd2,
-	0x07, 0xe2, 0x55, 0x7d, 0x60, 0x45, 0xe8, 0x09, 0xbb, 0x1c, 0x1d, 0x34,
-	0xd8, 0x16, 0x97, 0xcb, 0xe3, 0xcc, 0x1b, 0xd8, 0xf8, 0xa4, 0x1d, 0x7d,
-	0xda, 0xaa, 0x9e, 0x99, 0xc3, 0xba, 0x65, 0x8d, 0x4b, 0xfb, 0xe5, 0x09,
-	0xce, 0xac, 0xa8, 0xcc, 0x3e, 0x30, 0xa3, 0xa4, 0xa5, 0x93, 0xf1, 0xa9,
-	0x50, 0x84, 0x16, 0xac, 0x28, 0x15, 0xac, 0x14, 0x73, 0x70, 0xf0, 0xe3,
-	0xd0, 0x80, 0x46, 0x11, 0x96, 0x35, 0x11, 0x2a, 0x95, 0x94, 0x4e, 0x76,
-	0x86, 0xc8, 0x2c, 0xc6, 0xa4, 0x0d, 0x9b, 0x71, 0x9a, 0x1f, 0x33, 0xe6,
-	0x49, 0x43, 0xcc, 0x8b, 0x93, 0xa3, 0x0e, 0x0c, 0x8a, 0x38, 0x4b, 0xfd,
-	0xe5, 0x91, 0x28, 0xb5, 0xa7, 0xa5, 0xcd, 0x68, 0x86, 0xdb, 0xf8, 0xc2,
-	0x8a, 0xd1, 0x95, 0x7c, 0xd2, 0x38, 0xc1, 0xed, 0x64, 0xac, 0x64, 0x62,
-	0x92, 0x9f, 0x5d, 0x2c, 0x45, 0x28, 0x67, 0x45, 0xa8, 0x50, 0x4a, 0x19,
-	0x43, 0x6d, 0xa2, 0xcd, 0x18, 0xda, 0x7c, 0x49, 0x1f, 0x33, 0x4e, 0x92,
-	0xbb, 0xcd, 0xaf, 0x9c, 0x36, 0xbd, 0x6d, 0xfd, 0x61, 0xe3, 0xfe, 0x44,
-	0xa8, 0x32, 0x7b, 0x9f, 0xf1, 0x92, 0x5b, 0x9d, 0x60, 0xd9, 0x14, 0x13,
-	0x67, 0xdb, 0x68, 0xe9, 0x34, 0xcb, 0x1d, 0x9c, 0x6d, 0x61, 0xd0, 0x62,
-	0x39, 0x4e, 0xef, 0x57, 0xed, 0x07, 0x12, 0x43, 0x39, 0x91, 0x43, 0x84,
-	0x33, 0x17, 0x2a, 0xb3, 0xbf, 0x9b, 0x5e, 0x7f, 0x3f, 0xeb, 0x5b, 0x1f,
-	0xc5, 0x28, 0x72, 0x15, 0x71, 0xdd, 0x36, 0x5d, 0x1b, 0x4f, 0x5e, 0xd9,
-	0x14, 0x79, 0x68, 0x09, 0x5a, 0x33, 0xa5, 0x3c, 0xcd, 0x71, 0xf9, 0x15,
-	0x94, 0x5b, 0x4b, 0xd0, 0x3d, 0x91, 0x8f, 0xd6, 0x4e, 0x77, 0xf4, 0x18,
-	0x85, 0x6e, 0x9a, 0xc6, 0xbc, 0xf0, 0x0b, 0x57, 0x66, 0x87, 0x86, 0x0d,
-	0xd2, 0xae, 0xa2, 0x1e, 0xff, 0xbf, 0x89, 0xfb, 0x28, 0x61, 0x7e, 0x66,
-	0xac, 0x31, 0x5e, 0x49, 0xc3, 0xf1, 0x12, 0x64, 0xf3, 0x41, 0x89, 0xa5,
-	0x39, 0x23, 0x42, 0xd0, 0x5f, 0x61, 0x7b, 0xeb, 0x35, 0x27, 0x7b, 0xa4,
-	0xfe, 0xe4, 0x3b, 0x9b, 0x43, 0x9f, 0x19, 0x71, 0x9f, 0xcf, 0x51, 0x7b,
-	0x66, 0xc6, 0x92, 0xef, 0xb9, 0x52, 0xee, 0xa5, 0x25, 0x6e, 0x7b, 0x64,
-	0xf8, 0x8c, 0x73, 0xa6, 0x0f, 0xff, 0xd9, 0x8b, 0x7b, 0x85, 0xb7, 0x7d,
-	0x7d, 0x14, 0xc5, 0x3d, 0x0d, 0xe8, 0x3c, 0xc7, 0xb0, 0xe9, 0x87, 0xc5,
-	0xb8, 0xa7, 0xe2, 0x98, 0xcb, 0xb9, 0xb8, 0x3a, 0x97, 0x08, 0x65, 0xba,
-	0xe9, 0x91, 0xd5, 0x45, 0x3f, 0x8b, 0xf3, 0x47, 0xf8, 0xba, 0x84, 0x9c,
-	0xa3, 0x36, 0xca, 0x64, 0xbb, 0x69, 0xb3, 0x14, 0x66, 0x71, 0x05, 0xec,
-	0x44, 0xb9, 0x4c, 0x81, 0xa6, 0xd6, 0x5f, 0xeb, 0x83, 0x1f, 0x66, 0x52,
-	0xab, 0x61, 0xe9, 0x51, 0x00, 0x96, 0x7e, 0xa9, 0xc3, 0xd2, 0xd1, 0xbe,
-	0xe6, 0x58, 0xea, 0x77, 0x62, 0xd6, 0xa3, 0x14, 0x71, 0x70, 0xf4, 0x39,
-	0xe3, 0xe8, 0x3d, 0xc6, 0xd1, 0xf1, 0x06, 0x38, 0xd2, 0x3c, 0x38, 0x3a,
-	0x51, 0x87, 0xa3, 0x6c, 0x5f, 0x33, 0x1c, 0x1d, 0x0f, 0xa1, 0xff, 0xcd,
-	0xd6, 0x32, 0xfa, 0xb0, 0x9f, 0x39, 0xbd, 0x49, 0xa5, 0xd5, 0xe4, 0xf8,
-	0x24, 0x55, 0x90, 0x73, 0x92, 0x58, 0xa2, 0xb4, 0xe0, 0x76, 0x05, 0x81,
-	0xbf, 0x2c, 0x8f, 0xc9, 0xae, 0x06, 0xe7, 0xaa, 0x24, 0x9c, 0x79, 0x93,
-	0x73, 0x99, 0xc9, 0x57, 0x66, 0x1f, 0x32, 0x36, 0xee, 0x6d, 0xe8, 0x3a,
-	0x7e, 0x0b, 0xb1, 0x8c, 0xbc, 0xbb, 0x81, 0x73, 0x5b, 0xe2, 0x74, 0xdf,
-	0x1a, 0xa0, 0x7b, 0xd6, 0x7e, 0xba, 0x6b, 0x0d, 0xd2, 0x03, 0x0b, 0x6d,
-	0x60, 0x0e, 0xf8, 0x5e, 0xcc, 0x81, 0x46, 0x33, 0x31, 0x2e, 0x53, 0xda,
-	0x4f, 0x95, 0x92, 0xc2, 0x35, 0xb0, 0x03, 0x0c, 0x35, 0xc6, 0x4e, 0xa6,
-	0x0e, 0x3b, 0xb2, 0x0e, 0x30, 0xb3, 0xe4, 0xb7, 0xad, 0xed, 0x32, 0xf8,
-	0x5d, 0x0d, 0xc6, 0x56, 0x58, 0xc4, 0x91, 0x24, 0x47, 0x67, 0x42, 0x90,
-	0x59, 0xb7, 0x18, 0x53, 0x3c, 0x17, 0x3c, 0x7e, 0xda, 0xf5, 0x41, 0x96,
-	0x39, 0x4f, 0x09, 0x1b, 0xf4, 0x94, 0xa9, 0xc7, 0x33, 0x64, 0x5f, 0xd6,
-	0xcc, 0x31, 0x91, 0xeb, 0xb6, 0x54, 0xf6, 0x9e, 0x31, 0x91, 0xe1, 0xb1,
-	0x57, 0x78, 0xf4, 0xca, 0xa1, 0x76, 0xaa, 0x38, 0x31, 0x4c, 0x85, 0x55,
-	0xdb, 0x7e, 0xc8, 0xfc, 0x7f, 0xcd, 0x84, 0xcc, 0xfe, 0xdb, 0xae, 0xc4,
-	0x74, 0x5a, 0x36, 0x55, 0xdf, 0xee, 0x08, 0x7c, 0x31, 0x47, 0xa4, 0x77,
-	0x37, 0xaa, 0xaf, 0xc4, 0xbf, 0xe3, 0xbb, 0xbf, 0x04, 0x97, 0x59, 0xab,
-	0x96, 0x85, 0xed, 0xf8, 0xd2, 0xd8, 0xc2, 0x2a, 0xce, 0x7e, 0x7b, 0xfc,
-	0xea, 0xf9, 0xd5, 0x5c, 0x1f, 0x4b, 0xd8, 0x94, 0x4e, 0x76, 0x68, 0x79,
-	0x3c, 0xf7, 0x5c, 0x98, 0x86, 0x19, 0x97, 0x38, 0x83, 0x6b, 0x6c, 0x34,
-	0x2c, 0xce, 0x38, 0xd9, 0xcd, 0x78, 0xc8, 0x0a, 0x3b, 0xfd, 0xd4, 0x91,
-	0x09, 0x9a, 0x2c, 0xa7, 0xf9, 0x53, 0x3f, 0x7e, 0xb5, 0xb9, 0xe3, 0xe1,
-	0x48, 0xe3, 0x37, 0x37, 0xff, 0xa8, 0xd5, 0x9d, 0xe6, 0xba, 0x33, 0x5b,
-	0xd6, 0x55, 0xe7, 0x12, 0xfd, 0x03, 0x69, 0xae, 0x1b, 0xa3, 0xbc, 0x57,
-	0x00, 0x00, 0x00 };
+	0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a,
+	0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
+	0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
+	0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
+	0x65, 0x6b, 0x4a, 0xa2, 0x6d, 0x05, 0x11, 0x02, 0x62, 0x49, 0xa9, 0x46,
+	0x50, 0xb7, 0x92, 0xab, 0xb6, 0x81, 0x6b, 0x4b, 0x6b, 0x92, 0x6a, 0x09,
+	0x84, 0xe6, 0x08, 0x11, 0x43, 0x19, 0xa9, 0x11, 0x10, 0xa4, 0x1c, 0xbb,
+	0xc0, 0xb6, 0x2b, 0xbf, 0x05, 0x34, 0x2e, 0x15, 0x4a, 0x6e, 0xd4, 0x34,
+	0x30, 0xfc, 0xa7, 0xa8, 0x51, 0x38, 0xad, 0xe1, 0x04, 0xa8, 0x9b, 0x16,
+	0x45, 0xd0, 0xfc, 0x88, 0x0a, 0xdb, 0xd9, 0x7e, 0xdf, 0x9d, 0x3b, 0xcb,
+	0xe1, 0x92, 0xd4, 0xc3, 0x8f, 0xfe, 0x28, 0x81, 0xe5, 0xcc, 0xbd, 0x73,
+	0xe7, 0xde, 0x73, 0xcf, 0xe3, 0x3b, 0x8f, 0xb9, 0x77, 0x8a, 0x34, 0x88,
+	0xfe, 0x5b, 0x8f, 0x5f, 0xf2, 0xd1, 0x3f, 0x18, 0xbe, 0xab, 0xe7, 0xae,
+	0xbb, 0x71, 0x7b, 0xb7, 0x19, 0xb1, 0x22, 0xec, 0xe7, 0x3f, 0x07, 0xbf,
+	0x6e, 0x7d, 0xbf, 0xda, 0x9f, 0x8d, 0xdf, 0x65, 0xfc, 0x86, 0x7e, 0x2e,
+	0x62, 0xac, 0x31, 0x26, 0xfc, 0x57, 0xa9, 0x5c, 0xfd, 0xb9, 0x49, 0x5a,
+	0xae, 0xf2, 0x3c, 0xe2, 0x2f, 0xa9, 0x68, 0xe6, 0x4f, 0x62, 0x66, 0x46,
+	0x8e, 0xe7, 0x5c, 0x89, 0x45, 0x32, 0x1f, 0x1c, 0x1f, 0x76, 0x45, 0xb2,
+	0xa5, 0x6d, 0xc9, 0xbc, 0x7c, 0x5c, 0x29, 0x3a, 0x96, 0xb0, 0xff, 0xd6,
+	0xcc, 0x47, 0x27, 0xde, 0xd8, 0x91, 0xfa, 0xc5, 0x6c, 0x44, 0x62, 0x76,
+	0xe6, 0x15, 0xb1, 0xb7, 0x4a, 0xac, 0x15, 0xef, 0x3c, 0xdb, 0x99, 0x33,
+	0xa4, 0x29, 0x98, 0xeb, 0x83, 0xca, 0x1b, 0x9d, 0x52, 0xdc, 0x9c, 0x89,
+	0x89, 0x99, 0xe9, 0x78, 0x27, 0x17, 0xb1, 0x87, 0x22, 0x19, 0x5b, 0x16,
+	0xca, 0x32, 0x30, 0x32, 0x29, 0xb1, 0x58, 0x66, 0x22, 0x56, 0xdf, 0x21,
+	0xb1, 0x68, 0x66, 0xe8, 0xf8, 0xf7, 0xdc, 0x13, 0x15, 0xd3, 0x75, 0x93,
+	0xa3, 0x12, 0xef, 0x1d, 0xef, 0xc1, 0xf3, 0x52, 0x0a, 0x04, 0xef, 0x10,
+	0xd3, 0x2d, 0xc6, 0x23, 0x6e, 0x4c, 0x72, 0x65, 0x57, 0xf2, 0x65, 0x91,
+	0x1f, 0x96, 0x0c, 0x19, 0x77, 0x5b, 0x64, 0x74, 0xfb, 0x47, 0x95, 0x2c,
+	0x68, 0xf9, 0x3b, 0x77, 0xe8, 0xf8, 0x73, 0x2e, 0xe9, 0x9d, 0x8e, 0xf9,
+	0xf4, 0x8e, 0xd7, 0x0f, 0xbb, 0x96, 0xcc, 0x95, 0xd8, 0x77, 0xd0, 0x64,
+	0x9f, 0x95, 0xf9, 0x7e, 0xc3, 0xb8, 0x1b, 0xd7, 0x7d, 0x13, 0xd9, 0x1c,
+	0xe6, 0x9b, 0x2f, 0x71, 0xec, 0xbb, 0x5f, 0x18, 0x76, 0x1d, 0xdd, 0x9f,
+	0xdd, 0x91, 0x73, 0x13, 0xe8, 0x6f, 0xd5, 0xcf, 0x9e, 0x79, 0x74, 0xd8,
+	0x75, 0xf5, 0x33, 0xcb, 0xca, 0xb9, 0x5d, 0xba, 0xbf, 0xb4, 0x6b, 0xd8,
+	0xdd, 0xae, 0xfb, 0x7f, 0xbc, 0x2b, 0xe7, 0xa6, 0x75, 0x7f, 0xef, 0x57,
+	0x86, 0xdd, 0x1e, 0xdd, 0xff, 0xf6, 0xce, 0x9c, 0xdb, 0xab, 0xfb, 0x4f,
+	0xf5, 0x0e, 0xbb, 0xb6, 0x9c, 0x2d, 0x25, 0xf1, 0x9b, 0x88, 0x59, 0x1d,
+	0x19, 0x3d, 0xe6, 0x59, 0xd0, 0x9b, 0xc5, 0x98, 0x3e, 0xf4, 0xef, 0xc1,
+	0xaf, 0x1f, 0xbf, 0xf2, 0x06, 0x69, 0x1a, 0xc0, 0xf3, 0x0f, 0xb7, 0xf8,
+	0x3c, 0x04, 0xaf, 0xbc, 0x98, 0xbc, 0x17, 0x49, 0xc8, 0x1b, 0x9d, 0xef,
+	0x81, 0x97, 0xb6, 0x9c, 0x2b, 0x8b, 0x31, 0xd0, 0x99, 0x00, 0x0f, 0x1d,
+	0x79, 0xb1, 0xdc, 0x28, 0x91, 0x6f, 0x45, 0xc0, 0xa3, 0xaf, 0x4a, 0xc1,
+	0x89, 0xc9, 0xc6, 0x19, 0x43, 0xda, 0xba, 0xd7, 0x49, 0xd6, 0x2e, 0x4a,
+	0xbe, 0x13, 0x52, 0x9f, 0x72, 0xc4, 0x9a, 0x59, 0xdc, 0x68, 0xa2, 0xc7,
+	0x94, 0x54, 0xa2, 0x80, 0x19, 0x47, 0xce, 0xbe, 0x4b, 0x1d, 0xa5, 0x7c,
+	0xf1, 0x4b, 0x4a, 0x7e, 0xf2, 0x0e, 0x19, 0xb2, 0x49, 0xe7, 0x9f, 0xdd,
+	0xea, 0xaf, 0x19, 0x33, 0x72, 0x67, 0x06, 0xe5, 0xa4, 0x17, 0x37, 0xf2,
+	0x67, 0x76, 0x4a, 0x2e, 0x2d, 0x8e, 0x29, 0x1d, 0xea, 0xdd, 0xf9, 0xd2,
+	0xa0, 0x8c, 0x7b, 0x62, 0xe4, 0x3c, 0x4b, 0x46, 0x4b, 0x2d, 0x78, 0xde,
+	0xa4, 0xc6, 0xa2, 0xaf, 0x35, 0x22, 0x1d, 0x76, 0x5e, 0x62, 0xe8, 0xb7,
+	0xd1, 0xdf, 0x6c, 0xf4, 0xa9, 0x39, 0x54, 0x7f, 0x72, 0x4c, 0xe2, 0xd8,
+	0x9b, 0xa3, 0xc7, 0x56, 0x2a, 0xb9, 0xb4, 0x8d, 0x71, 0x83, 0x32, 0xe6,
+	0x39, 0x32, 0x84, 0xeb, 0xa8, 0xc7, 0xf5, 0x13, 0xd0, 0xb1, 0xb7, 0x8e,
+	0x17, 0xa6, 0xd5, 0x7c, 0xc9, 0x48, 0x86, 0xf3, 0xb5, 0x62, 0xdc, 0x05,
+	0xd0, 0x65, 0x88, 0xa5, 0x64, 0x9b, 0x95, 0xc2, 0xa4, 0x21, 0xe4, 0x5b,
+	0x41, 0xf1, 0xb0, 0x0f, 0xf4, 0x5b, 0xe2, 0x76, 0x1b, 0x32, 0xec, 0xde,
+	0x2c, 0x45, 0x1b, 0xed, 0xd2, 0x79, 0x33, 0xe7, 0xd5, 0x4b, 0xde, 0x4a,
+	0x62, 0xff, 0x94, 0xfd, 0x90, 0x8c, 0xe1, 0x1d, 0xd3, 0xe5, 0x98, 0x8f,
+	0xb0, 0x77, 0xb4, 0xf1, 0x6e, 0x5d, 0xe6, 0xa0, 0x5c, 0x9a, 0x2c, 0x9a,
+	0xb9, 0x72, 0x8b, 0x44, 0x66, 0x52, 0xd0, 0xfe, 0x71, 0x33, 0xff, 0xbc,
+	0x25, 0xd1, 0x29, 0xea, 0x97, 0xd8, 0x91, 0xcc, 0x84, 0xb9, 0xbb, 0x7c,
+	0xde, 0xcc, 0x97, 0xf9, 0x0e, 0xc6, 0x96, 0x4c, 0xf0, 0x96, 0xf7, 0xdb,
+	0xc0, 0x4b, 0xea, 0x36, 0xdf, 0x81, 0x1c, 0xb0, 0x87, 0x17, 0x3d, 0xc8,
+	0x45, 0xc9, 0x29, 0x09, 0x39, 0x89, 0xd1, 0xd7, 0x19, 0x93, 0xb1, 0x69,
+	0x4b, 0x0a, 0xe9, 0x9b, 0x15, 0xe7, 0x0b, 0xe9, 0x25, 0x9a, 0x46, 0x27,
+	0x6b, 0x69, 0xe2, 0x7b, 0xa4, 0xc9, 0xa7, 0x65, 0x6c, 0x9a, 0xb4, 0xf9,
+	0xb4, 0x9c, 0x9c, 0x24, 0x8d, 0x5c, 0x87, 0xf4, 0x90, 0xae, 0x80, 0x26,
+	0xbe, 0x43, 0x9a, 0x36, 0x61, 0x7e, 0x65, 0xc0, 0x46, 0x1f, 0x68, 0x18,
+	0xf3, 0x2c, 0xc8, 0x26, 0x2e, 0x05, 0xbb, 0x68, 0x8c, 0xf5, 0x6e, 0x4b,
+	0xc0, 0xaa, 0x8d, 0xd1, 0x5e, 0xd2, 0xeb, 0x42, 0x7e, 0x75, 0x4a, 0xce,
+	0x66, 0x66, 0x9c, 0x3c, 0xc3, 0x78, 0xae, 0x8d, 0xfb, 0x92, 0x2d, 0xe3,
+	0x6a, 0x3e, 0xd2, 0xf3, 0x59, 0xcc, 0x43, 0x7a, 0x2f, 0x43, 0x57, 0x7b,
+	0xa0, 0xa3, 0x69, 0xf9, 0xdb, 0xf2, 0x76, 0x79, 0xbd, 0xdc, 0x25, 0xaf,
+	0xc1, 0x7e, 0x5f, 0x2d, 0x27, 0xe5, 0x95, 0x72, 0xab, 0xbc, 0x5c, 0x4e,
+	0xc8, 0x4b, 0x4a, 0x7f, 0xfb, 0x44, 0x9a, 0x94, 0x4e, 0xc7, 0x6e, 0x86,
+	0x3e, 0xb6, 0x40, 0x1f, 0x9b, 0x61, 0x4f, 0x1b, 0x61, 0xab, 0xdf, 0x06,
+	0x0f, 0xa7, 0x3b, 0x25, 0xbb, 0x09, 0xfd, 0xb7, 0x65, 0x2c, 0xa5, 0x23,
+	0x16, 0x9e, 0x8f, 0x4d, 0x46, 0x25, 0x6f, 0x9f, 0x95, 0xf7, 0xa7, 0x2c,
+	0x19, 0x2b, 0x3f, 0x79, 0x9b, 0xaf, 0xb3, 0x6c, 0xcf, 0xca, 0x45, 0xf4,
+	0xe5, 0xed, 0x59, 0xb9, 0xb4, 0xd5, 0x94, 0xd1, 0xe9, 0xef, 0x4a, 0xee,
+	0xf9, 0xb3, 0xf2, 0xd3, 0xbf, 0x16, 0x19, 0x00, 0xef, 0xcd, 0xee, 0xff,
+	0xaa, 0x64, 0x6d, 0xec, 0xb1, 0x7b, 0xbb, 0x92, 0x89, 0xd9, 0x4d, 0x3d,
+	0x4e, 0x02, 0x57, 0x2c, 0x23, 0xef, 0xbd, 0x00, 0x6c, 0x69, 0x34, 0x72,
+	0xa7, 0x45, 0x86, 0x4f, 0x57, 0x64, 0x38, 0x1d, 0x95, 0xc7, 0xec, 0x8a,
+	0xf4, 0xa5, 0xeb, 0xe4, 0xa8, 0x4d, 0xac, 0x39, 0x6e, 0x04, 0xb8, 0xfe,
+	0xed, 0xf2, 0x09, 0xdc, 0xb3, 0x4f, 0x64, 0x5a, 0xdd, 0xfb, 0xfd, 0xc5,
+	0x72, 0x54, 0xb2, 0x4e, 0x31, 0x61, 0x49, 0x9b, 0xe9, 0xd3, 0xf4, 0xcd,
+	0xe0, 0x19, 0x78, 0x35, 0x04, 0x2c, 0xf5, 0xed, 0xaf, 0x30, 0xb9, 0xee,
+	0x4a, 0x56, 0x75, 0x47, 0x29, 0x3b, 0xe8, 0x34, 0x79, 0x9d, 0x1c, 0x32,
+	0x32, 0x8e, 0xb4, 0x29, 0xbc, 0xe8, 0xc1, 0x98, 0x5e, 0x63, 0x7f, 0x99,
+	0x7a, 0x8e, 0xfb, 0x12, 0x69, 0xdd, 0x8c, 0xb1, 0x16, 0xae, 0x59, 0x4d,
+	0x73, 0x98, 0x4e, 0xce, 0x45, 0x3a, 0x79, 0x7d, 0x21, 0x44, 0xe7, 0x5f,
+	0x56, 0xef, 0xa7, 0x43, 0xf7, 0xc5, 0xf2, 0x0f, 0x1a, 0x7c, 0xfa, 0xc8,
+	0xcf, 0x5e, 0xe8, 0xe3, 0x37, 0xf4, 0x5a, 0xb8, 0x2f, 0x71, 0x8d, 0xb3,
+	0x15, 0x5f, 0xa7, 0x8a, 0xd7, 0x58, 0xeb, 0x62, 0x68, 0xad, 0x4b, 0xa1,
+	0xb5, 0x2e, 0x85, 0xd6, 0x2a, 0x82, 0xb7, 0xb2, 0xc1, 0x74, 0xa3, 0xc0,
+	0x27, 0xf6, 0x4c, 0x60, 0xce, 0x67, 0x21, 0x97, 0x9f, 0x60, 0x4c, 0x46,
+	0x16, 0x3d, 0xf0, 0xe3, 0x74, 0x54, 0xf6, 0xa9, 0x67, 0xbd, 0x9a, 0xae,
+	0xf0, 0xb3, 0x98, 0xec, 0x75, 0x78, 0x1f, 0x3c, 0xb3, 0xc0, 0x63, 0xb6,
+	0xff, 0xe1, 0x16, 0xbf, 0xcd, 0xfb, 0xf3, 0x9a, 0xfe, 0x87, 0xfc, 0xf7,
+	0xca, 0x1f, 0x28, 0x9c, 0x5c, 0x28, 0x13, 0xc7, 0x24, 0x1d, 0x71, 0xe5,
+	0x48, 0x5f, 0x1a, 0x76, 0x65, 0x1b, 0xe9, 0xd1, 0xae, 0x7a, 0xf2, 0x3c,
+	0x6b, 0xba, 0x8d, 0xc0, 0x0a, 0x49, 0x9a, 0xd0, 0xb3, 0x51, 0xb5, 0x97,
+	0x75, 0xa6, 0x4f, 0xb3, 0xcd, 0xf6, 0x80, 0xe9, 0x36, 0xd7, 0xf4, 0xd3,
+	0xde, 0x1b, 0x71, 0x4f, 0xdd, 0x7e, 0x4c, 0xcb, 0x37, 0x8e, 0x36, 0xf1,
+	0xb9, 0x5f, 0xb7, 0x83, 0xe7, 0x39, 0x6b, 0x79, 0xfb, 0xed, 0x2d, 0xcb,
+	0xdb, 0x01, 0x76, 0x84, 0xb1, 0x9d, 0x7b, 0x4d, 0x4a, 0xc4, 0xa5, 0xce,
+	0x45, 0x41, 0x6b, 0x1a, 0xb6, 0x58, 0xaf, 0x69, 0xb8, 0x5d, 0xd3, 0x00,
+	0x5a, 0x31, 0x6e, 0x54, 0xd9, 0x98, 0x12, 0x5f, 0x4d, 0x9b, 0xfc, 0x0e,
+	0xee, 0xd7, 0xab, 0xe7, 0xbe, 0x2d, 0x06, 0x57, 0x31, 0x76, 0x77, 0x52,
+	0xe6, 0x13, 0x90, 0x79, 0x5c, 0xe6, 0xa7, 0xc9, 0xb3, 0x54, 0xe2, 0x71,
+	0x41, 0xbb, 0x94, 0x90, 0xb3, 0x93, 0x92, 0x3d, 0x7c, 0xaa, 0x57, 0xfa,
+	0x60, 0x9f, 0x73, 0x93, 0x57, 0x2a, 0xe0, 0xdb, 0xbd, 0x75, 0xe2, 0x02,
+	0x83, 0xe1, 0xef, 0x7b, 0xa2, 0x12, 0xc9, 0x64, 0xa0, 0x0b, 0x69, 0xe5,
+	0x83, 0x97, 0xfe, 0x2c, 0xeb, 0xfe, 0x65, 0xed, 0x3a, 0xf8, 0x79, 0xcc,
+	0xdb, 0x93, 0x56, 0x7a, 0x13, 0xfe, 0xcb, 0x01, 0x57, 0x72, 0xe9, 0x8f,
+	0xa1, 0x5b, 0x01, 0x4d, 0x81, 0x6d, 0xd0, 0x07, 0x7d, 0x10, 0xf2, 0x6d,
+	0xad, 0xc0, 0x17, 0x07, 0xf2, 0x0b, 0xfc, 0x11, 0xfd, 0x44, 0x82, 0x58,
+	0x0e, 0x5b, 0xa0, 0x6f, 0x88, 0x8b, 0x39, 0x63, 0x69, 0xff, 0x11, 0xd3,
+	0xfe, 0x23, 0x0e, 0xdf, 0xc1, 0xb6, 0xad, 0xdb, 0x8e, 0x6e, 0x27, 0xd0,
+	0x46, 0xec, 0x31, 0x43, 0xbb, 0x7a, 0xeb, 0xf8, 0xc8, 0xb4, 0xf2, 0x49,
+	0xf4, 0x67, 0xf0, 0x14, 0xf4, 0x29, 0xf4, 0x2d, 0xd8, 0x6f, 0x09, 0xeb,
+	0x55, 0x31, 0x9c, 0xf2, 0x08, 0xd3, 0x43, 0x5a, 0xd6, 0x89, 0x09, 0x3f,
+	0x9b, 0x75, 0x48, 0xef, 0x77, 0x20, 0x0f, 0x62, 0x25, 0xe9, 0xbe, 0x15,
+	0xb4, 0x72, 0x3f, 0xff, 0x97, 0xb4, 0x72, 0xbd, 0x5a, 0x7a, 0x3f, 0x2d,
+	0x66, 0x2b, 0xec, 0xc0, 0x9e, 0x33, 0xc0, 0x66, 0x31, 0xf6, 0x77, 0x0e,
+	0x62, 0xcf, 0x03, 0xc0, 0xee, 0x7e, 0x60, 0xf7, 0x1e, 0x60, 0x77, 0x1f,
+	0xb0, 0x3b, 0x0b, 0xec, 0xee, 0x05, 0x6e, 0xf7, 0x00, 0xb7, 0xd3, 0xe0,
+	0x8d, 0x23, 0xb3, 0xc0, 0xf1, 0x59, 0xe8, 0xcb, 0x2c, 0xe6, 0x28, 0xcc,
+	0x88, 0xf1, 0x35, 0xec, 0xe1, 0xe8, 0x54, 0x6a, 0x16, 0xfa, 0x9d, 0x18,
+	0x32, 0xa1, 0x07, 0xe9, 0xbb, 0x61, 0x6f, 0x88, 0x9b, 0xca, 0x83, 0x32,
+	0x0c, 0xbf, 0xdf, 0xb6, 0xb5, 0x1d, 0xfa, 0x84, 0x68, 0x24, 0x11, 0xe8,
+	0x68, 0xbf, 0x14, 0xbc, 0x76, 0xbb, 0xcd, 0xec, 0x42, 0x5f, 0x2a, 0x89,
+	0x18, 0xd5, 0x38, 0x74, 0x3a, 0x65, 0x8c, 0x9c, 0x26, 0x0f, 0x26, 0x81,
+	0x83, 0x15, 0x19, 0x4f, 0x53, 0x4f, 0x2b, 0xf2, 0x5c, 0x3a, 0xd5, 0x5b,
+	0x94, 0x46, 0x39, 0xe9, 0x4c, 0x2a, 0xdf, 0x6f, 0x65, 0x4e, 0x29, 0x1f,
+	0x3a, 0xec, 0xe2, 0x5a, 0x6a, 0x33, 0x0a, 0xa7, 0xb9, 0xd7, 0x76, 0xfc,
+	0xa2, 0x58, 0xf7, 0x57, 0x90, 0x91, 0x25, 0x7d, 0x3d, 0x62, 0x1c, 0xee,
+	0x2c, 0x02, 0x39, 0x53, 0xf6, 0x22, 0x56, 0xcb, 0x4f, 0xb6, 0x27, 0xda,
+	0x4d, 0x4b, 0x86, 0x2c, 0x43, 0x46, 0x61, 0x5f, 0x7d, 0xe9, 0xff, 0xa9,
+	0x9c, 0x74, 0xf8, 0xbc, 0x5e, 0xfe, 0x5c, 0x61, 0x31, 0xd6, 0x9e, 0x9f,
+	0xc6, 0xba, 0x51, 0xf0, 0x9b, 0xeb, 0x72, 0x1e, 0xb4, 0x81, 0x8b, 0x96,
+	0x9b, 0x9a, 0x2d, 0xca, 0x2e, 0xd8, 0xe9, 0x06, 0xc9, 0x6d, 0xaf, 0x93,
+	0xec, 0x40, 0x52, 0x0a, 0x53, 0xbb, 0x80, 0x8d, 0x31, 0x65, 0xab, 0x85,
+	0xc1, 0xa4, 0x3c, 0x36, 0xc5, 0xbe, 0x2c, 0xf6, 0x9a, 0x3a, 0x95, 0x15,
+	0xee, 0xd5, 0x90, 0xec, 0xc1, 0xac, 0x3c, 0xe6, 0x65, 0x65, 0x04, 0xf2,
+	0x3a, 0x0b, 0x5e, 0x1e, 0xf2, 0x5c, 0x79, 0x0e, 0xbe, 0x26, 0x7f, 0x1a,
+	0x58, 0xeb, 0xae, 0x07, 0x2e, 0xa6, 0xce, 0x31, 0xc6, 0x37, 0x19, 0x87,
+	0x82, 0x97, 0x7f, 0x34, 0x45, 0x5e, 0x9a, 0x32, 0x7d, 0xaf, 0x01, 0x3c,
+	0x48, 0x82, 0x77, 0xae, 0xfc, 0xb1, 0x97, 0x3a, 0x9f, 0x35, 0x81, 0xc5,
+	0xe9, 0xde, 0x88, 0x34, 0x24, 0x30, 0xce, 0x1f, 0x93, 0x4f, 0x47, 0x20,
+	0xd7, 0x22, 0xc6, 0xa6, 0xd0, 0xcf, 0x77, 0x1d, 0xfc, 0xb2, 0x18, 0x07,
+	0x5d, 0xb5, 0x53, 0xe7, 0x67, 0x4d, 0x8e, 0x4f, 0x42, 0x3e, 0x36, 0xc6,
+	0x03, 0xf8, 0x6c, 0xde, 0xa7, 0x8d, 0x02, 0x69, 0xf0, 0xa8, 0x53, 0x88,
+	0x49, 0xcb, 0xc4, 0xd4, 0xf6, 0x73, 0xaf, 0x0b, 0xd7, 0xf9, 0x22, 0xc6,
+	0x7f, 0x88, 0x38, 0xdc, 0x96, 0x79, 0xc8, 0xe5, 0xa7, 0xe0, 0x55, 0x36,
+	0xe1, 0xb7, 0x0b, 0x33, 0xa9, 0x73, 0x8b, 0x26, 0xef, 0xdd, 0xe2, 0xa8,
+	0xd9, 0x23, 0xd2, 0x4c, 0x7e, 0xa5, 0xc1, 0x2b, 0xd7, 0x36, 0xcd, 0xb4,
+	0xf2, 0x65, 0xbe, 0x2d, 0xdf, 0x05, 0x9a, 0xa0, 0xf3, 0xdd, 0x61, 0x9b,
+	0xa0, 0xaf, 0x0d, 0x6c, 0x22, 0x95, 0x98, 0x35, 0xe1, 0x9f, 0xbb, 0x2d,
+	0x39, 0xa5, 0xda, 0xe0, 0xd1, 0x60, 0x2a, 0x91, 0x35, 0x11, 0x33, 0x95,
+	0xba, 0xe4, 0xac, 0xc7, 0xf1, 0x49, 0x85, 0x51, 0xfe, 0x78, 0xc4, 0x7a,
+	0x1e, 0xe3, 0xc5, 0x2e, 0xd0, 0xec, 0xdb, 0xc9, 0xdc, 0xa4, 0xa3, 0x9e,
+	0x9d, 0xf4, 0xfc, 0xb8, 0xd0, 0x44, 0xec, 0x38, 0x8b, 0xd8, 0x31, 0xaf,
+	0x6c, 0xc6, 0xce, 0x22, 0xd7, 0x80, 0xce, 0xfb, 0xf6, 0x32, 0x5f, 0xba,
+	0x4f, 0x86, 0xcf, 0x7c, 0x3f, 0x6e, 0x22, 0xce, 0x2a, 0x38, 0xa4, 0x8b,
+	0xe3, 0xcf, 0x81, 0x4e, 0xf2, 0x4e, 0x86, 0x18, 0x57, 0x21, 0x16, 0x7e,
+	0x84, 0x32, 0x1e, 0xed, 0x7e, 0x88, 0x7c, 0x2b, 0x82, 0xe8, 0x53, 0x3e,
+	0x8e, 0x49, 0x91, 0x71, 0xe8, 0x62, 0xe4, 0x09, 0x19, 0x9a, 0xa7, 0x2f,
+	0xc4, 0xcf, 0x23, 0x26, 0x02, 0xc7, 0x94, 0xcf, 0x6a, 0x87, 0x3e, 0x14,
+	0xc1, 0xef, 0x8d, 0x3a, 0x0e, 0x3b, 0x08, 0xf9, 0xf6, 0x43, 0xfe, 0x19,
+	0x19, 0x39, 0x33, 0x42, 0xdd, 0xee, 0x9a, 0x97, 0x54, 0xd7, 0x49, 0xd9,
+	0x66, 0xcf, 0xc1, 0x06, 0xb3, 0x83, 0x95, 0x5d, 0x66, 0x86, 0xef, 0x9c,
+	0xc0, 0x3b, 0xb8, 0xce, 0x8f, 0xc8, 0xd1, 0x32, 0xfb, 0x9e, 0x05, 0xdf,
+	0x11, 0x17, 0xf7, 0x1c, 0xd4, 0xf6, 0x80, 0xf9, 0xac, 0x60, 0xbe, 0x11,
+	0x3d, 0x1f, 0xc7, 0x71, 0x0c, 0xdf, 0x59, 0x9a, 0x77, 0x37, 0x7d, 0x22,
+	0x30, 0xa8, 0xc3, 0xac, 0xec, 0x8a, 0xe2, 0xf9, 0x73, 0x3d, 0xbc, 0xc7,
+	0x3c, 0xf0, 0x89, 0xb6, 0xdb, 0x8f, 0xb1, 0x83, 0x98, 0x73, 0x9d, 0xb4,
+	0xb5, 0x04, 0xf4, 0x52, 0x3f, 0x18, 0xab, 0xb0, 0x3d, 0xb2, 0xc9, 0x97,
+	0xd1, 0xab, 0x11, 0xdf, 0xc7, 0xcc, 0xa2, 0x4d, 0x3b, 0x3c, 0x26, 0x79,
+	0x2f, 0x85, 0x7d, 0x42, 0x06, 0xe5, 0x51, 0xbd, 0x47, 0xc8, 0x69, 0xe0,
+	0x29, 0xf0, 0x41, 0x8a, 0x3e, 0x6f, 0xc8, 0x17, 0xf2, 0xe4, 0x38, 0x6c,
+	0xe0, 0x71, 0x8c, 0x41, 0xbc, 0xab, 0x78, 0x60, 0x6f, 0xf2, 0xe3, 0xf5,
+	0x54, 0x31, 0xcb, 0xbc, 0xb3, 0x99, 0xba, 0x0d, 0xdc, 0x2a, 0x0f, 0xd8,
+	0x9c, 0x7b, 0xd6, 0x64, 0x7e, 0x92, 0x4a, 0x5e, 0x88, 0xec, 0x67, 0xbb,
+	0x6b, 0xd6, 0x84, 0x8c, 0x20, 0xc7, 0xdc, 0xf6, 0x76, 0x8d, 0x55, 0xef,
+	0x28, 0x5d, 0xa6, 0xde, 0x17, 0xbc, 0x6d, 0xf6, 0x43, 0x42, 0x5d, 0x76,
+	0xa0, 0x17, 0xc4, 0x0b, 0x5e, 0x2d, 0xf8, 0xee, 0x04, 0x74, 0x61, 0xbd,
+	0xa6, 0x9d, 0xf7, 0x96, 0xcc, 0xda, 0x58, 0xc3, 0xfb, 0x8f, 0x0d, 0x7e,
+	0x1f, 0xef, 0x19, 0x33, 0x05, 0x72, 0x0c, 0x68, 0xa5, 0x3c, 0x6b, 0x65,
+	0xf8, 0x24, 0x68, 0x67, 0x3f, 0xae, 0xf3, 0xc7, 0x60, 0xa7, 0xc0, 0x94,
+	0x9e, 0x8e, 0xc4, 0x45, 0x8c, 0xcf, 0x03, 0xf7, 0x8b, 0x16, 0x9f, 0x5d,
+	0x31, 0x96, 0xde, 0x31, 0x19, 0x27, 0x23, 0x1e, 0xbf, 0x60, 0x7c, 0x0d,
+	0xb1, 0x4e, 0x6e, 0xfe, 0x8a, 0x91, 0x87, 0x5e, 0xcc, 0x7b, 0x77, 0x43,
+	0x9f, 0x68, 0x57, 0x36, 0xd6, 0x4e, 0x25, 0xfe, 0xc9, 0x6c, 0x4f, 0xce,
+	0x01, 0x03, 0x0e, 0x81, 0xb1, 0xbe, 0x2c, 0x5d, 0x25, 0xdb, 0x45, 0x33,
+	0xaa, 0xf1, 0x8f, 0xed, 0x94, 0xfd, 0xb0, 0xc0, 0x58, 0x1a, 0xf6, 0x80,
+	0xcf, 0x7b, 0x64, 0xb8, 0x9c, 0x91, 0xc2, 0x99, 0x6d, 0xf6, 0x28, 0x72,
+	0xf5, 0x25, 0xda, 0x89, 0x75, 0x45, 0x60, 0x1d, 0xfc, 0xb7, 0x27, 0xc5,
+	0xba, 0x0c, 0x31, 0xaf, 0x03, 0xfa, 0x84, 0xbe, 0xd2, 0x92, 0x4e, 0xde,
+	0xbf, 0x62, 0x3f, 0xf4, 0xdb, 0xcb, 0xf7, 0x34, 0x2f, 0xd7, 0xde, 0xd3,
+	0xee, 0xea, 0x9e, 0x88, 0x31, 0xf0, 0x03, 0x1e, 0xfc, 0x00, 0x74, 0xfa,
+	0x75, 0x0f, 0x7e, 0xc0, 0x83, 0x1f, 0x80, 0x3d, 0xbe, 0x02, 0x7d, 0x7c,
+	0xd9, 0x83, 0x2f, 0xf0, 0xe0, 0x0b, 0x3c, 0xf8, 0x02, 0x2f, 0x07, 0xd9,
+	0x11, 0xef, 0xe9, 0x4b, 0x0e, 0x54, 0xfd, 0xa7, 0x1f, 0x83, 0xdd, 0xa2,
+	0xe3, 0x1a, 0xd8, 0xae, 0xbd, 0x59, 0x46, 0xbb, 0x98, 0x13, 0x35, 0xe0,
+	0xda, 0x88, 0x2b, 0x62, 0x98, 0xae, 0x2f, 0x69, 0xdb, 0x79, 0x1c, 0x74,
+	0x01, 0x17, 0xba, 0xbe, 0x08, 0xdd, 0x44, 0x1c, 0xe1, 0xfe, 0x86, 0x8e,
+	0x7f, 0x7e, 0x64, 0xf9, 0xba, 0xd9, 0x88, 0xbe, 0xfb, 0xd0, 0xd7, 0x88,
+	0x31, 0x47, 0x31, 0x86, 0xf1, 0x53, 0x93, 0xee, 0x0b, 0x8f, 0x63, 0x1c,
+	0xf5, 0x00, 0xd6, 0x4a, 0x61, 0x5c, 0x13, 0xe6, 0x6e, 0xc5, 0x98, 0x9d,
+	0x18, 0x73, 0x2b, 0xda, 0x8c, 0xb9, 0xb7, 0xa0, 0x7d, 0x4f, 0xcd, 0x3b,
+	0xb7, 0xa3, 0xef, 0x4b, 0x35, 0x7d, 0x8b, 0xe8, 0xeb, 0x41, 0xdf, 0x45,
+	0xfd, 0x5e, 0x11, 0xed, 0x96, 0x9a, 0x31, 0x97, 0xd1, 0x87, 0xb8, 0xd9,
+	0xfe, 0x7b, 0x5c, 0xfb, 0x71, 0x25, 0x4d, 0xc1, 0x33, 0xc6, 0xcd, 0xc8,
+	0x41, 0xab, 0xb1, 0xef, 0x5b, 0x8c, 0x0b, 0xe1, 0x7b, 0x7f, 0x6c, 0xf9,
+	0x71, 0xe3, 0x77, 0x6d, 0x5f, 0x57, 0x83, 0xf6, 0x8f, 0x6a, 0xda, 0x1c,
+	0xfb, 0xdf, 0x35, 0x7d, 0x3b, 0x36, 0x2e, 0x6f, 0xdf, 0x59, 0xb7, 0xf2,
+	0x9d, 0x89, 0x9a, 0x31, 0x2f, 0x37, 0x2f, 0x6f, 0xff, 0xe9, 0x2a, 0xef,
+	0xec, 0xd9, 0xb0, 0xbc, 0xef, 0xd1, 0x4d, 0x35, 0x63, 0xa0, 0x53, 0x0e,
+	0x72, 0xab, 0x60, 0xfc, 0x03, 0x37, 0xf9, 0xcf, 0xc9, 0xdf, 0x5a, 0x5d,
+	0x52, 0x5b, 0x47, 0xdb, 0x84, 0x1c, 0x2e, 0x18, 0xb0, 0x39, 0xdb, 0xcc,
+	0x5c, 0x32, 0xf2, 0xd0, 0xa9, 0x5c, 0x39, 0x98, 0x8f, 0xb6, 0x5c, 0x5b,
+	0xdb, 0x08, 0x6a, 0x1a, 0x8c, 0xbb, 0xe2, 0xd0, 0x9b, 0xfd, 0x90, 0x71,
+	0x6a, 0xa2, 0x28, 0x4b, 0x36, 0xdc, 0x66, 0xae, 0x65, 0xc3, 0x4f, 0x6b,
+	0xdc, 0x7a, 0x0a, 0x74, 0x56, 0x64, 0x20, 0x5d, 0x4f, 0xff, 0xa4, 0xf1,
+	0x8c, 0x58, 0x54, 0xa9, 0x44, 0xb6, 0x56, 0xe4, 0x48, 0xfa, 0xc3, 0x8a,
+	0x28, 0x1c, 0x9c, 0x50, 0x58, 0x94, 0x34, 0xdb, 0x21, 0x23, 0x1b, 0xb9,
+	0x8d, 0x23, 0x43, 0x0e, 0xfd, 0xd9, 0x31, 0xc6, 0x29, 0x27, 0x7c, 0x9c,
+	0x25, 0x16, 0xa1, 0x8d, 0xbc, 0xae, 0x70, 0xda, 0x50, 0x31, 0x70, 0x61,
+	0x9e, 0xd8, 0x4e, 0x3c, 0x85, 0xdf, 0xb6, 0x39, 0xef, 0x6a, 0x78, 0x19,
+	0x8b, 0x32, 0x3e, 0xb4, 0xdc, 0x17, 0xe0, 0x1b, 0xf9, 0x8c, 0x71, 0x04,
+	0xee, 0x4b, 0xaa, 0xae, 0x56, 0x5c, 0xbe, 0x97, 0xcd, 0xcc, 0x43, 0xae,
+	0x63, 0x7f, 0xab, 0x63, 0x54, 0xbb, 0x79, 0x6d, 0x7b, 0xde, 0x5b, 0xb5,
+	0xe7, 0x40, 0xdf, 0x56, 0xab, 0x59, 0xbc, 0xa3, 0xf8, 0xff, 0x52, 0x39,
+	0x75, 0xaa, 0x08, 0xfb, 0x59, 0x50, 0x39, 0x7a, 0x20, 0x0b, 0xc6, 0x3c,
+	0xa9, 0x67, 0x66, 0xe9, 0x2d, 0x54, 0x8e, 0xc2, 0xfc, 0xa4, 0x22, 0xbb,
+	0xd3, 0xff, 0xa6, 0xf6, 0x9e, 0x35, 0x3b, 0xeb, 0x18, 0x63, 0x2c, 0x78,
+	0xe4, 0x53, 0x1a, 0xcf, 0x11, 0xfb, 0xa7, 0x7f, 0x26, 0x79, 0x87, 0x7d,
+	0xbf, 0xac, 0xcc, 0x21, 0x36, 0x52, 0xf1, 0x92, 0x8a, 0x0f, 0x18, 0xef,
+	0x1d, 0x01, 0x8f, 0xc8, 0xc7, 0x01, 0xf0, 0x36, 0x88, 0x19, 0xfe, 0x91,
+	0xbe, 0x58, 0x96, 0xc7, 0xd1, 0xc8, 0xb4, 0x4a, 0x97, 0x30, 0xa7, 0x89,
+	0xf9, 0xe8, 0xe3, 0xe8, 0x47, 0xd8, 0x5f, 0x88, 0x32, 0xb6, 0xf3, 0x63,
+	0x83, 0x08, 0xd6, 0xb3, 0x80, 0x83, 0xef, 0x0a, 0x63, 0x9a, 0x61, 0x25,
+	0x03, 0x62, 0x29, 0x9f, 0xb1, 0x2f, 0xa6, 0x63, 0xef, 0xb8, 0x8e, 0xb5,
+	0x6d, 0x1d, 0x6b, 0x93, 0x0e, 0xd6, 0x2d, 0x83, 0x38, 0x82, 0x72, 0xba,
+	0x70, 0xdc, 0xdc, 0xca, 0x38, 0xa2, 0x49, 0x56, 0x8f, 0x23, 0x02, 0x9a,
+	0x76, 0x82, 0x26, 0xc6, 0x7d, 0xaa, 0x4e, 0xd5, 0xec, 0xd7, 0xc6, 0x48,
+	0x43, 0xe0, 0x27, 0x95, 0x3f, 0x9e, 0x80, 0xeb, 0xc3, 0xde, 0x10, 0x48,
+	0x02, 0xdb, 0x73, 0x93, 0x3b, 0xb5, 0xdf, 0x65, 0x0e, 0xc1, 0xf8, 0xdd,
+	0xd7, 0xd3, 0x5c, 0x7a, 0x34, 0x98, 0xa7, 0x05, 0x9e, 0x32, 0x54, 0x43,
+	0xe3, 0x5a, 0x8c, 0x7b, 0x82, 0x18, 0x68, 0x8f, 0x8e, 0x81, 0xfa, 0xe5,
+	0x88, 0xe7, 0xe7, 0x0c, 0x03, 0xa5, 0x01, 0xf4, 0x29, 0xda, 0x13, 0x8c,
+	0x35, 0x4d, 0x93, 0xb1, 0x66, 0x0a, 0xc9, 0x87, 0xbf, 0x97, 0xb6, 0xad,
+	0xac, 0x65, 0x06, 0x7b, 0x69, 0xbc, 0xb0, 0x7c, 0x2f, 0xbb, 0x94, 0xde,
+	0x9b, 0xe0, 0x9d, 0x8f, 0x4d, 0x9c, 0xf3, 0x7c, 0x94, 0xb8, 0x35, 0x50,
+	0x1a, 0x54, 0xf3, 0x8e, 0xaf, 0x98, 0x57, 0xb0, 0xc7, 0x03, 0x6b, 0x3c,
+	0xe3, 0xfe, 0x19, 0x5b, 0xd8, 0x7a, 0xff, 0x81, 0x0c, 0x2f, 0x63, 0xce,
+	0x2e, 0xa3, 0xa0, 0xe2, 0xb6, 0x83, 0x4a, 0x1e, 0x85, 0xd2, 0x10, 0xae,
+	0xb4, 0x17, 0x35, 0x8f, 0xb2, 0x99, 0x51, 0x25, 0x83, 0x11, 0xb5, 0xc7,
+	0xb9, 0xd2, 0x23, 0x88, 0xd7, 0xbe, 0x0e, 0x3f, 0x18, 0xae, 0x2b, 0x3a,
+	0x18, 0x43, 0x5e, 0x15, 0x43, 0x78, 0x4a, 0x9a, 0x59, 0x33, 0xbc, 0x82,
+	0x35, 0xb8, 0xe7, 0x38, 0xe4, 0x6f, 0xf8, 0xcf, 0xd5, 0xfa, 0x01, 0xcf,
+	0xeb, 0x42, 0xf4, 0x54, 0x10, 0xbf, 0x26, 0x40, 0x43, 0xf8, 0x9d, 0x63,
+	0xd2, 0xe7, 0x51, 0x56, 0xed, 0x89, 0x11, 0xe4, 0xbb, 0x05, 0x09, 0x62,
+	0x11, 0xae, 0x4f, 0x0c, 0xc8, 0x23, 0x97, 0x4a, 0x60, 0x7f, 0x01, 0x5f,
+	0x03, 0x9e, 0xc6, 0x2f, 0xd4, 0xea, 0xc7, 0x38, 0xe8, 0x19, 0xf6, 0xc8,
+	0xa7, 0x40, 0x6f, 0x83, 0xb5, 0x2f, 0xab, 0xfd, 0x8c, 0xa9, 0xda, 0xe7,
+	0xfa, 0xba, 0x40, 0x7f, 0x47, 0x11, 0xb7, 0xf8, 0xfa, 0xf8, 0x7b, 0x9a,
+	0x37, 0x81, 0xde, 0xc6, 0xb5, 0x0e, 0x30, 0x47, 0xa4, 0x5d, 0x05, 0x3a,
+	0xd2, 0x61, 0xef, 0x57, 0xbc, 0xe0, 0x33, 0x95, 0x13, 0x2a, 0x39, 0x0f,
+	0x55, 0xe5, 0xbc, 0xbe, 0x46, 0x67, 0x3b, 0x6d, 0xdf, 0x46, 0x69, 0x8b,
+	0xb0, 0x69, 0xd0, 0xf7, 0xd2, 0x32, 0xdb, 0xef, 0x5a, 0xa3, 0xae, 0x1c,
+	0x97, 0xc8, 0xcc, 0x0f, 0xc0, 0xcb, 0xdb, 0x91, 0xd7, 0x20, 0xcb, 0x9f,
+	0x22, 0x46, 0x31, 0xfe, 0x58, 0x8a, 0x89, 0xe7, 0x64, 0xb5, 0x78, 0xf8,
+	0x5a, 0xb1, 0xc7, 0x9d, 0xd7, 0x19, 0x7b, 0xfc, 0x49, 0x1d, 0xf3, 0x9c,
+	0x05, 0xd8, 0xe9, 0x21, 0xbc, 0x5f, 0xe7, 0xfe, 0x10, 0x3e, 0xed, 0xaf,
+	0xac, 0x7a, 0x37, 0xc0, 0x8b, 0xb8, 0x6c, 0x9c, 0xd9, 0xac, 0x30, 0xc3,
+	0x9e, 0x5a, 0xc2, 0x8c, 0x51, 0xcf, 0xd7, 0x5f, 0xf0, 0xca, 0xd9, 0x28,
+	0xd7, 0x9b, 0x77, 0x2f, 0xe5, 0x10, 0x43, 0xd5, 0x1c, 0xe2, 0x96, 0x1a,
+	0x3e, 0xae, 0x86, 0x99, 0xe7, 0x54, 0xbe, 0xfc, 0x6a, 0x39, 0xf5, 0x82,
+	0x48, 0x1f, 0xf2, 0xe4, 0xd4, 0x79, 0x91, 0x2c, 0x72, 0x65, 0xe6, 0x73,
+	0x7b, 0x90, 0x3b, 0xa7, 0x7e, 0x21, 0xd2, 0x8b, 0x9c, 0x99, 0xf9, 0x70,
+	0x3f, 0xf8, 0xda, 0x03, 0x4c, 0x4d, 0x03, 0x63, 0xb7, 0x83, 0xbf, 0x5d,
+	0x0a, 0x57, 0x0f, 0x9d, 0x46, 0xae, 0xad, 0xea, 0xec, 0xb4, 0x75, 0x07,
+	0x7e, 0xb5, 0x52, 0x79, 0x2c, 0xdd, 0x8e, 0x7c, 0x3f, 0x29, 0x5f, 0xb6,
+	0x98, 0xf3, 0x1a, 0x56, 0xae, 0x7b, 0x26, 0x12, 0x8e, 0x63, 0x0b, 0xd7,
+	0xf4, 0x11, 0x2b, 0x79, 0x3f, 0xac, 0xfc, 0xc4, 0x78, 0xe4, 0x6a, 0xbc,
+	0xdf, 0x5f, 0xe5, 0xfd, 0x9d, 0x0d, 0xd2, 0xd0, 0xaf, 0xea, 0x0b, 0xb9,
+	0xee, 0xaf, 0x13, 0xcb, 0xd2, 0xf0, 0xf3, 0xf0, 0xc7, 0x15, 0xb9, 0x3f,
+	0x7d, 0xa5, 0x72, 0xd1, 0xdd, 0x20, 0x85, 0xed, 0x07, 0x34, 0x9e, 0x1f,
+	0x78, 0x32, 0xe7, 0x16, 0x61, 0x1f, 0xfa, 0xdb, 0xc2, 0x64, 0x0c, 0x51,
+	0x29, 0xff, 0x9a, 0x65, 0xae, 0xf7, 0xf6, 0x7a, 0x69, 0xd8, 0xf6, 0x02,
+	0x8b, 0x63, 0xc4, 0x99, 0x39, 0x27, 0xae, 0xea, 0xdd, 0x37, 0xb9, 0xec,
+	0xb7, 0x21, 0xd3, 0xdf, 0x92, 0x39, 0xc4, 0x13, 0xf3, 0xbd, 0xa0, 0x71,
+	0x7b, 0x0b, 0xc6, 0xd3, 0xee, 0xc8, 0xf3, 0xdf, 0x96, 0xa1, 0x41, 0xf2,
+	0xd4, 0xc1, 0xf8, 0xfb, 0x31, 0xa6, 0x19, 0xd7, 0x07, 0x23, 0x73, 0x76,
+	0xcc, 0x6f, 0x0f, 0x70, 0x0e, 0xfa, 0x52, 0xce, 0xc3, 0xb5, 0x5a, 0x94,
+	0xcd, 0x2f, 0xcd, 0xcf, 0xb9, 0xf9, 0xec, 0xe3, 0xca, 0xbe, 0xee, 0xee,
+	0xd0, 0x1a, 0x4d, 0xa1, 0x35, 0x7a, 0x42, 0x6b, 0x90, 0xb6, 0xe6, 0x10,
+	0x6d, 0xcd, 0x78, 0xff, 0x3e, 0xac, 0xd7, 0xaf, 0xe3, 0x94, 0x60, 0x9d,
+	0x60, 0x1f, 0x2d, 0xa1, 0xb1, 0x1f, 0x62, 0x0d, 0xf6, 0x39, 0xa1, 0x3e,
+	0xae, 0x0b, 0x1c, 0x73, 0xd8, 0x6e, 0x0e, 0xd1, 0x42, 0xfa, 0x1a, 0xd0,
+	0xaf, 0xe6, 0x02, 0x3f, 0x1b, 0xe0, 0xbb, 0x4c, 0xf8, 0x8f, 0x08, 0xe2,
+	0xaa, 0x60, 0x4f, 0xc1, 0x1c, 0x0e, 0xde, 0xe3, 0x18, 0xff, 0xb9, 0xff,
+	0x0e, 0xfb, 0xf9, 0x3c, 0x22, 0xdf, 0x53, 0xf4, 0xb2, 0xcd, 0x3d, 0x34,
+	0x81, 0x56, 0x5e, 0x53, 0x32, 0xdb, 0x0c, 0xd9, 0x77, 0x33, 0x9f, 0x36,
+	0xe4, 0x36, 0xd7, 0x34, 0xf2, 0xdd, 0x94, 0xef, 0x06, 0x8d, 0x97, 0x0d,
+	0x46, 0xee, 0x34, 0x6b, 0x08, 0x8d, 0x3a, 0xf7, 0x43, 0xbe, 0xa1, 0x7c,
+	0x4c, 0xe0, 0x03, 0xe8, 0x63, 0x18, 0xab, 0xd0, 0x7f, 0x66, 0xf5, 0x3d,
+	0xae, 0xd0, 0xd3, 0xc3, 0xf3, 0xcd, 0x72, 0x51, 0xf1, 0xd0, 0x96, 0xc5,
+	0x2a, 0x0f, 0xa3, 0xfa, 0xbb, 0xd1, 0x31, 0xfd, 0x4d, 0x66, 0x3f, 0xe2,
+	0x01, 0xdc, 0x97, 0x80, 0xb9, 0xdd, 0xd0, 0xb7, 0x6e, 0xe6, 0x70, 0x45,
+	0x5c, 0x59, 0xc3, 0x30, 0x70, 0x75, 0x70, 0x8d, 0xe1, 0x0a, 0xbf, 0x04,
+	0xac, 0xc9, 0x77, 0xbf, 0x0d, 0x1d, 0x82, 0x6c, 0xca, 0xb6, 0x71, 0xbf,
+	0xe7, 0xd7, 0x87, 0x16, 0xdd, 0xd5, 0xeb, 0x43, 0x8b, 0xa2, 0xea, 0x43,
+	0x13, 0xd7, 0xa8, 0x0f, 0x65, 0xaf, 0xbf, 0x3e, 0x74, 0xa2, 0x9e, 0x18,
+	0xbc, 0xb7, 0x47, 0x8c, 0xdf, 0xd5, 0xf5, 0xa1, 0xf7, 0xc5, 0xaf, 0x0f,
+	0x5d, 0x94, 0xd5, 0xeb, 0x43, 0x13, 0x35, 0xf5, 0xa1, 0x8d, 0xaa, 0x3e,
+	0xc4, 0x79, 0xfc, 0xfa, 0x10, 0xdb, 0x6d, 0xdd, 0xbd, 0xa1, 0x3a, 0x08,
+	0xf0, 0x54, 0xe5, 0x84, 0xb6, 0x31, 0xe8, 0x05, 0x18, 0x45, 0x2c, 0xbf,
+	0xb9, 0xea, 0x8f, 0x96, 0xf0, 0xca, 0x50, 0xba, 0x75, 0x2d, 0xbc, 0x1a,
+	0xf4, 0x63, 0x90, 0x65, 0x58, 0x35, 0x5e, 0x8d, 0x53, 0x5e, 0xab, 0x67,
+	0xde, 0x3c, 0x56, 0x5a, 0x9a, 0x77, 0x0c, 0xb2, 0x1d, 0xaa, 0xd6, 0x50,
+	0xd6, 0x8a, 0x85, 0x1c, 0x39, 0xb6, 0xea, 0x37, 0xb8, 0x44, 0x76, 0xe5,
+	0x37, 0x38, 0x43, 0x1c, 0xd0, 0xd9, 0xd6, 0x5d, 0x50, 0x79, 0xd5, 0x9c,
+	0xf7, 0x55, 0xb9, 0xf0, 0xb0, 0x0d, 0x3c, 0x09, 0x6a, 0x26, 0x94, 0xe5,
+	0x92, 0x8f, 0x28, 0x98, 0x9f, 0x5f, 0xdd, 0xe4, 0xb0, 0xaa, 0x9b, 0xfc,
+	0xbc, 0x3e, 0x5c, 0x37, 0x59, 0x94, 0xab, 0xd7, 0x4d, 0x0e, 0xaf, 0x52,
+	0x37, 0x79, 0x53, 0x96, 0xea, 0x26, 0x6f, 0x4a, 0x50, 0x37, 0x89, 0xc8,
+	0x85, 0x4d, 0x9c, 0xe7, 0x08, 0xde, 0x19, 0xc0, 0xaf, 0x1f, 0x3f, 0xbf,
+	0x8e, 0xb2, 0x58, 0xa5, 0x7f, 0xb5, 0x3a, 0x4a, 0x7d, 0xec, 0x93, 0xd4,
+	0x51, 0x7c, 0x4c, 0x0f, 0xea, 0x28, 0x0d, 0x88, 0x5f, 0xe0, 0x43, 0xcc,
+	0x70, 0x1d, 0xa5, 0x15, 0xf3, 0xb2, 0x8f, 0x6d, 0xf6, 0xc3, 0x2e, 0xe0,
+	0x67, 0xb2, 0xaa, 0xce, 0xf1, 0x9b, 0x9a, 0x87, 0x07, 0xb0, 0xe7, 0x24,
+	0x64, 0x41, 0x3e, 0xb6, 0xab, 0x38, 0x32, 0x6b, 0x25, 0x8c, 0x5c, 0x27,
+	0xbc, 0xd3, 0x24, 0xbf, 0xd9, 0x27, 0x64, 0xa4, 0x4c, 0x1d, 0x6f, 0x45,
+	0xdc, 0x6d, 0xa1, 0xef, 0x00, 0xda, 0x41, 0x8c, 0xd4, 0x5d, 0x9d, 0x83,
+	0x76, 0x38, 0xc7, 0x7a, 0x9f, 0x73, 0x3d, 0x3e, 0x67, 0x27, 0x68, 0x0e,
+	0xef, 0xa3, 0x08, 0x7f, 0x83, 0x3e, 0x25, 0x73, 0xc6, 0x8a, 0x01, 0x2d,
+	0x49, 0xda, 0xf4, 0x75, 0xcc, 0xc7, 0xbe, 0x9d, 0x2a, 0xdf, 0x1a, 0xee,
+	0xe1, 0x5e, 0xe9, 0xbb, 0x16, 0x40, 0x1f, 0xfa, 0xe6, 0x99, 0xe3, 0xd1,
+	0x8f, 0x05, 0x39, 0x58, 0x5c, 0xe5, 0x60, 0x2d, 0x8a, 0x1f, 0xe4, 0xf5,
+	0x23, 0x31, 0xe2, 0x63, 0x8b, 0xcb, 0x3d, 0xf4, 0x6b, 0x5c, 0x63, 0xdb,
+	0xcf, 0xf5, 0x58, 0x8f, 0x6e, 0x71, 0x9f, 0x80, 0x5c, 0x59, 0xab, 0x09,
+	0xe4, 0xf7, 0x0d, 0xbd, 0xef, 0x5e, 0x29, 0xb6, 0x48, 0x6c, 0x23, 0xe8,
+	0x69, 0x9b, 0x62, 0x8c, 0x7d, 0x8f, 0xca, 0x37, 0x1c, 0x77, 0x6d, 0xbb,
+	0xdd, 0x7f, 0x03, 0x76, 0x3b, 0x70, 0x55, 0xbb, 0x3d, 0x1b, 0x0b, 0xdb,
+	0xed, 0xfe, 0x1b, 0xb0, 0xdb, 0x23, 0x37, 0x64, 0xb7, 0xdc, 0x1b, 0x31,
+	0x29, 0xa8, 0x8b, 0xad, 0x8c, 0x9b, 0x82, 0x75, 0x47, 0xb1, 0x66, 0x76,
+	0x8d, 0x35, 0x87, 0xd6, 0xac, 0xbb, 0xd6, 0xc6, 0x4c, 0xd7, 0x23, 0x6f,
+	0xe6, 0x21, 0xf4, 0xab, 0x71, 0xed, 0x83, 0x9e, 0xd6, 0x3a, 0x1f, 0xe4,
+	0xed, 0x61, 0xfb, 0xa1, 0x5e, 0x50, 0x17, 0x7e, 0x02, 0x7e, 0x51, 0x1f,
+	0x02, 0x9b, 0x6b, 0xaf, 0xd1, 0xc1, 0x05, 0xe4, 0xf3, 0xed, 0x5a, 0x07,
+	0x29, 0xeb, 0x4e, 0xf5, 0x3d, 0x69, 0xde, 0x7b, 0xc2, 0xcf, 0xe3, 0xa1,
+	0x03, 0x85, 0xf9, 0xc0, 0xd6, 0x92, 0x58, 0x37, 0x78, 0x46, 0x3e, 0xba,
+	0x88, 0x61, 0xb6, 0x21, 0xfe, 0x02, 0x8f, 0x54, 0xff, 0xf2, 0x3a, 0xf0,
+	0xd5, 0xf1, 0x4c, 0x8a, 0x51, 0x8c, 0x7d, 0xae, 0x07, 0x36, 0xde, 0x43,
+	0x8c, 0xca, 0x20, 0x8f, 0xa1, 0x1e, 0x52, 0x37, 0x3b, 0xba, 0x0e, 0x99,
+	0x8c, 0x91, 0x0e, 0xc2, 0xf6, 0x6c, 0xa5, 0xc7, 0xbb, 0xcb, 0x1d, 0xe7,
+	0x16, 0x4d, 0xae, 0x51, 0xa9, 0x14, 0x54, 0xbd, 0x5e, 0xcc, 0x5c, 0xf7,
+	0x4d, 0xeb, 0xe8, 0x97, 0x6e, 0x76, 0x23, 0x5a, 0xd7, 0xb2, 0xb8, 0xa7,
+	0xde, 0xfe, 0x2b, 0x7c, 0x3b, 0xf2, 0x89, 0xee, 0x7f, 0x41, 0x7f, 0x02,
+	0x36, 0x4f, 0x5f, 0xce, 0xfc, 0x62, 0x87, 0x1e, 0xd7, 0xae, 0xbe, 0x95,
+	0xaa, 0xef, 0x2d, 0x4e, 0xe0, 0x7f, 0x52, 0xf4, 0xcf, 0xcb, 0xe4, 0xcc,
+	0xb3, 0x1b, 0x79, 0x95, 0x9f, 0xf0, 0x7d, 0xa5, 0x93, 0xc8, 0x29, 0xac,
+	0x50, 0x9d, 0x3d, 0xa6, 0x73, 0x31, 0xda, 0x58, 0x5c, 0xe5, 0x89, 0x7e,
+	0xee, 0xc1, 0x5c, 0x75, 0xf9, 0x99, 0x8d, 0xd5, 0x75, 0x60, 0xf3, 0x27,
+	0xd0, 0x81, 0x5a, 0xf9, 0xc5, 0x60, 0xfb, 0x81, 0xfc, 0x82, 0x98, 0x65,
+	0x56, 0xef, 0xbb, 0xdd, 0x97, 0xe1, 0xff, 0x8b, 0x7d, 0x1a, 0xa1, 0x7d,
+	0x06, 0x78, 0x74, 0x58, 0xef, 0x73, 0x47, 0x0d, 0x1e, 0x0d, 0xd4, 0xd8,
+	0xec, 0xe7, 0x89, 0x47, 0x97, 0xd7, 0x7d, 0xfe, 0x78, 0xc4, 0x7d, 0x6d,
+	0x59, 0x15, 0x87, 0xfc, 0x7d, 0x3c, 0x2d, 0x66, 0xe6, 0xb3, 0xcc, 0xdf,
+	0x3e, 0x89, 0x7c, 0xc2, 0x38, 0x42, 0x99, 0x34, 0xa9, 0x78, 0xd5, 0xb7,
+	0x3d, 0xf8, 0xf2, 0xf9, 0xa8, 0xbc, 0xf7, 0x50, 0x4c, 0x7e, 0x75, 0x2f,
+	0xbf, 0x95, 0x59, 0xba, 0x7e, 0xc5, 0x76, 0xb4, 0xc1, 0xf7, 0x43, 0x48,
+	0x24, 0x94, 0xdf, 0xe1, 0x3b, 0x81, 0x3d, 0xdb, 0x78, 0xce, 0x67, 0x5b,
+	0xe4, 0x42, 0xf3, 0x8d, 0xe4, 0x74, 0x1d, 0xf6, 0xfb, 0xe6, 0x6a, 0x39,
+	0xdd, 0xd5, 0x6b, 0x7f, 0x4b, 0x39, 0x1d, 0x71, 0xb6, 0x59, 0xd7, 0x7b,
+	0x98, 0xd7, 0xec, 0xd7, 0xd8, 0xc9, 0x7b, 0xe4, 0xaa, 0x1e, 0xf2, 0x57,
+	0xc8, 0xf6, 0x35, 0xc4, 0x4b, 0xaf, 0x7a, 0xc8, 0x59, 0x3d, 0xe4, 0xaa,
+	0x1e, 0x72, 0x55, 0x0f, 0xb9, 0xaa, 0xd7, 0xa5, 0x73, 0xde, 0x01, 0x5d,
+	0xd7, 0xe7, 0xf7, 0x70, 0xd6, 0x0b, 0x8a, 0xf0, 0x25, 0xe3, 0x3c, 0x63,
+	0x61, 0xe6, 0xd2, 0xeb, 0x82, 0x73, 0x48, 0xba, 0xe6, 0xdd, 0xaa, 0x6b,
+	0x30, 0x75, 0x37, 0x29, 0xdf, 0x6c, 0xbe, 0xd1, 0xe0, 0x7f, 0x33, 0xe7,
+	0xf9, 0x8f, 0x3f, 0x44, 0x5c, 0xc2, 0x1a, 0xd8, 0x04, 0x6d, 0xb4, 0x62,
+	0x66, 0x58, 0x63, 0x11, 0xd3, 0xcc, 0x7c, 0x01, 0xef, 0x6c, 0xc3, 0x1e,
+	0xea, 0x69, 0xdb, 0x11, 0x33, 0xd3, 0x48, 0x9e, 0x1a, 0x66, 0x66, 0xbd,
+	0x9e, 0xeb, 0x6f, 0x1a, 0xfc, 0xd8, 0xaa, 0x93, 0x6d, 0xcb, 0x64, 0x9c,
+	0xa0, 0x62, 0xed, 0xa0, 0x7f, 0x4f, 0xf3, 0xf2, 0xb5, 0xa2, 0x0a, 0xdf,
+	0x73, 0xe9, 0x87, 0x31, 0x9f, 0x3a, 0xdb, 0x54, 0xe5, 0xb7, 0xb9, 0x26,
+	0xbf, 0xa3, 0x9a, 0xdf, 0x3e, 0x8f, 0x23, 0x1c, 0xa7, 0xea, 0xbe, 0xe4,
+	0x75, 0x30, 0x9f, 0xaa, 0xe1, 0x61, 0x1d, 0x75, 0x8e, 0x03, 0xd7, 0xbb,
+	0xa2, 0xd2, 0x34, 0x78, 0x20, 0xea, 0x86, 0xd7, 0x25, 0x46, 0xf5, 0x2e,
+	0xfb, 0xfe, 0xb4, 0xf6, 0x9a, 0xed, 0xea, 0xdb, 0x99, 0xef, 0x33, 0xa2,
+	0x4a, 0x07, 0x2d, 0x75, 0x36, 0xef, 0xd7, 0xea, 0xcc, 0x0d, 0xf5, 0x2f,
+	0x8f, 0x3c, 0x66, 0xbc, 0xa7, 0x23, 0x69, 0x99, 0x7f, 0xd1, 0xc0, 0x5a,
+	0x6b, 0x5f, 0x39, 0xc0, 0x3d, 0xae, 0x57, 0xeb, 0xc7, 0x59, 0x27, 0x0b,
+	0xf0, 0x4c, 0x36, 0xfb, 0xf5, 0xb3, 0x4f, 0x63, 0x4b, 0x0d, 0x35, 0xb6,
+	0x14, 0xec, 0xd3, 0xcf, 0x57, 0xf9, 0xdd, 0x7a, 0xb5, 0xb3, 0x13, 0x0b,
+	0xe5, 0xd0, 0xf7, 0x8f, 0xaa, 0x6e, 0xf0, 0x5c, 0xcb, 0x83, 0xd0, 0x41,
+	0xd6, 0xfe, 0xf7, 0xc0, 0x8e, 0x2a, 0x95, 0x3e, 0xd6, 0x93, 0xb7, 0x3f,
+	0xa0, 0xcf, 0x27, 0x3c, 0xa3, 0xea, 0x09, 0xd6, 0x8a, 0x7a, 0x42, 0x1f,
+	0x74, 0x05, 0x31, 0x00, 0x6c, 0xb0, 0xa0, 0x64, 0xc9, 0x78, 0xa0, 0xf6,
+	0xfb, 0xca, 0xf9, 0x46, 0x9f, 0x0f, 0xb7, 0x37, 0xfa, 0xdf, 0x18, 0x7e,
+	0xe9, 0x2c, 0x6f, 0xf3, 0xfd, 0x44, 0x63, 0x70, 0xce, 0x67, 0xf8, 0x4c,
+	0x1f, 0x74, 0xb1, 0x4e, 0xf2, 0x6a, 0x3e, 0xc4, 0xbb, 0xcf, 0xff, 0xac,
+	0x79, 0xf9, 0x78, 0xf4, 0x9d, 0x09, 0xc6, 0x37, 0xd7, 0x8c, 0x6f, 0xc6,
+	0xf8, 0x7f, 0xaf, 0x19, 0xdf, 0x1c, 0x1a, 0xef, 0xd4, 0x8c, 0x77, 0x30,
+	0xbe, 0x7e, 0xd3, 0xf2, 0xf1, 0x4e, 0x68, 0x7c, 0x4b, 0xcd, 0xf8, 0x16,
+	0x8c, 0x6f, 0xa8, 0x19, 0x8f, 0xbe, 0x33, 0x75, 0xfa, 0xbb, 0x17, 0x31,
+	0xf6, 0x88, 0xce, 0xbb, 0x71, 0x2d, 0xd5, 0x7e, 0x4b, 0xa1, 0xde, 0xb5,
+	0x42, 0x06, 0xc1, 0x39, 0x3b, 0xda, 0x6b, 0x16, 0xf6, 0xba, 0x14, 0xcb,
+	0xf8, 0xfa, 0x18, 0xd6, 0x45, 0xe2, 0x43, 0x51, 0x22, 0x2e, 0x74, 0x67,
+	0x1e, 0x3a, 0x34, 0x1f, 0xf8, 0x24, 0x9e, 0x99, 0x4a, 0x75, 0xf9, 0x7a,
+	0x6a, 0x48, 0xd4, 0x5d, 0xd0, 0x39, 0xd8, 0x4e, 0xd2, 0x0e, 0xbc, 0x0c,
+	0x30, 0x53, 0x4e, 0xf9, 0x76, 0x43, 0xfd, 0xe5, 0xfc, 0xda, 0x7e, 0xa8,
+	0xab, 0x7a, 0x9d, 0xbe, 0x15, 0xb8, 0x96, 0x5c, 0x51, 0xab, 0x8a, 0x5c,
+	0x07, 0xae, 0x0d, 0x54, 0x71, 0xed, 0x41, 0x99, 0xad, 0xe6, 0xdb, 0xfd,
+	0x72, 0xd4, 0xdb, 0xcb, 0xf3, 0x38, 0xa7, 0xb2, 0xf2, 0xd9, 0xe4, 0xdb,
+	0x7b, 0xab, 0x7e, 0x32, 0x35, 0x91, 0x95, 0x0b, 0xc7, 0x99, 0x43, 0x05,
+	0xb5, 0xd6, 0x71, 0xef, 0x5b, 0x94, 0x0b, 0x6c, 0xe3, 0x46, 0xf3, 0x6d,
+	0xce, 0xe7, 0xc8, 0x51, 0xff, 0x2c, 0x44, 0x75, 0xde, 0x62, 0x75, 0xde,
+	0x84, 0xb6, 0x37, 0xfa, 0xe0, 0x25, 0x7f, 0x99, 0x87, 0xbf, 0x1c, 0x42,
+	0xce, 0xbd, 0xe0, 0xad, 0x56, 0xef, 0xbc, 0x51, 0x7f, 0x59, 0x5b, 0x37,
+	0xae, 0xf5, 0x97, 0x5c, 0xa7, 0xb6, 0x56, 0x9c, 0xac, 0xc1, 0x7f, 0xea,
+	0xd3, 0x53, 0x3a, 0xa6, 0xc6, 0x75, 0xfe, 0x29, 0xd8, 0xa3, 0x29, 0x43,
+	0x4a, 0x7f, 0xd9, 0x0e, 0x72, 0xcb, 0x03, 0xd5, 0xdc, 0x72, 0x29, 0x1f,
+	0x44, 0xec, 0xda, 0x75, 0x9f, 0xc6, 0x47, 0xc6, 0xc8, 0xe3, 0xe8, 0x3f,
+	0x05, 0x1d, 0xe0, 0x33, 0xd6, 0x3f, 0xef, 0x90, 0x2f, 0x5b, 0xbe, 0x7f,
+	0xf2, 0xeb, 0x50, 0x07, 0x54, 0xfc, 0xcf, 0xfa, 0xff, 0x70, 0x7a, 0xa3,
+	0x8e, 0xf7, 0xae, 0x85, 0xab, 0xcb, 0x73, 0x53, 0xd3, 0x3c, 0x81, 0x77,
+	0x99, 0x9b, 0x3e, 0x10, 0x27, 0x86, 0xe6, 0xca, 0x57, 0x7d, 0xbf, 0x48,
+	0xff, 0x32, 0xac, 0xbe, 0xfb, 0xa9, 0x3c, 0x14, 0xe3, 0x16, 0xf4, 0xfb,
+	0x7e, 0x1e, 0x9a, 0x2b, 0x6f, 0x89, 0xfb, 0x38, 0x78, 0xb5, 0x9c, 0xe5,
+	0x58, 0x9c, 0xb5, 0xbc, 0x05, 0xef, 0x5a, 0xb4, 0xae, 0xcc, 0x7b, 0x23,
+	0x2b, 0xf2, 0xde, 0x41, 0x9d, 0xd7, 0x7e, 0x45, 0xe5, 0xbd, 0x3e, 0x8f,
+	0xb9, 0x97, 0x70, 0x1e, 0xe5, 0x02, 0x0b, 0xf9, 0x8d, 0x84, 0xf8, 0x30,
+	0xaa, 0xfc, 0x56, 0x61, 0xf2, 0x77, 0xd4, 0xf9, 0x89, 0x95, 0x7a, 0xf3,
+	0x79, 0xfb, 0x89, 0x60, 0xef, 0x4f, 0x89, 0x5f, 0xaf, 0xdb, 0x03, 0x5a,
+	0x98, 0x5b, 0x45, 0xb5, 0x3e, 0xa4, 0x34, 0x5e, 0x07, 0xe3, 0x82, 0x3c,
+	0xbe, 0xfa, 0x5d, 0xb5, 0x98, 0x5d, 0x56, 0x3f, 0xd9, 0x42, 0x18, 0x86,
+	0xdc, 0xb3, 0x37, 0xf0, 0x1d, 0xe2, 0xd3, 0x9c, 0x7f, 0xa8, 0xf5, 0x6b,
+	0xfc, 0x46, 0xda, 0xaa, 0xcf, 0xc7, 0xb9, 0xb0, 0x01, 0x9e, 0x65, 0x0e,
+	0xe3, 0xab, 0x3a, 0x03, 0x17, 0x73, 0x32, 0x62, 0xec, 0x23, 0x7d, 0xe9,
+	0x7f, 0xd6, 0xfb, 0x4c, 0xc8, 0x91, 0x29, 0xbf, 0xbe, 0x69, 0xae, 0x71,
+	0xfe, 0xcd, 0x34, 0xaf, 0xab, 0xbe, 0x79, 0x03, 0xe7, 0xdf, 0x5e, 0x8f,
+	0x07, 0xf5, 0xcd, 0xda, 0xf3, 0x6f, 0x91, 0xeb, 0x3c, 0xff, 0xe6, 0xd7,
+	0x37, 0x39, 0x4f, 0xb8, 0xbe, 0x79, 0x8f, 0x3a, 0x43, 0x36, 0x3a, 0xd5,
+	0xa3, 0xce, 0x23, 0xb7, 0x75, 0xaf, 0x8d, 0xb3, 0xfb, 0x3e, 0xb3, 0x7c,
+	0xe4, 0x3f, 0xe3, 0xe1, 0x7c, 0x64, 0xdf, 0xe7, 0x92, 0x8f, 0x70, 0x2f,
+	0xbf, 0xef, 0x7f, 0xb7, 0xad, 0x39, 0xfb, 0x95, 0xfb, 0x1c, 0x6b, 0x98,
+	0x47, 0x54, 0x0d, 0x73, 0xcb, 0xfa, 0x70, 0x0d, 0xd3, 0xbc, 0xc6, 0xd9,
+	0xaf, 0x23, 0xab, 0xd4, 0x30, 0xa3, 0xa1, 0xb3, 0x5f, 0x51, 0x7d, 0xf6,
+	0x6b, 0xa3, 0x8b, 0xbc, 0x51, 0xd7, 0x2c, 0xcd, 0xab, 0x9e, 0xfd, 0xea,
+	0x59, 0xff, 0x49, 0x6a, 0x96, 0xb9, 0x65, 0x35, 0xcb, 0x15, 0x67, 0xbf,
+	0xe0, 0xd7, 0x36, 0x4b, 0x32, 0x94, 0xe3, 0xe4, 0x6e, 0xf0, 0x6c, 0x43,
+	0xfe, 0x3a, 0xe2, 0x80, 0x7d, 0x55, 0x5b, 0xe5, 0xd9, 0xfd, 0x3a, 0xec,
+	0x39, 0x2a, 0x7b, 0x1d, 0xea, 0x27, 0xcf, 0x38, 0x76, 0xc2, 0x16, 0x70,
+	0x2d, 0xb3, 0xdd, 0x45, 0x19, 0x19, 0x03, 0x9d, 0xcb, 0xcf, 0x17, 0x2c,
+	0x9d, 0xd3, 0x8d, 0x55, 0xcf, 0xe9, 0x9e, 0x84, 0xde, 0x98, 0x53, 0x31,
+	0x99, 0x0b, 0xe9, 0xd4, 0x38, 0x62, 0x3b, 0x73, 0xc6, 0xd6, 0xcf, 0x93,
+	0x12, 0x99, 0x72, 0x80, 0x6f, 0x3c, 0xdb, 0xdb, 0x24, 0x91, 0x19, 0xff,
+	0x7b, 0xa3, 0xa9, 0xf0, 0x33, 0x81, 0x31, 0x3c, 0xdb, 0x19, 0x95, 0xa3,
+	0xaa, 0x3e, 0x11, 0xe8, 0xf2, 0x37, 0xc1, 0xe3, 0x4d, 0xd9, 0xa5, 0xb6,
+	0xb3, 0x8a, 0x8f, 0x47, 0xcc, 0x38, 0x45, 0x7d, 0xbe, 0x5b, 0xf2, 0xba,
+	0xf6, 0x33, 0x5c, 0xde, 0xa9, 0x73, 0x09, 0xf5, 0xcd, 0x06, 0xbc, 0x6c,
+	0xd3, 0xfe, 0x16, 0xd7, 0xf9, 0x36, 0xfa, 0x37, 0xc6, 0xcc, 0xd2, 0x37,
+	0xb9, 0x2d, 0x31, 0x02, 0x6c, 0x1b, 0x52, 0x6b, 0xde, 0x08, 0xcf, 0x8d,
+	0x15, 0xf1, 0xd7, 0x8d, 0xf1, 0x3d, 0x88, 0x85, 0xdf, 0xc4, 0xfe, 0xda,
+	0xa0, 0x1f, 0x8f, 0x4b, 0xfe, 0xcc, 0x1d, 0xd2, 0x37, 0x9d, 0x02, 0x3d,
+	0xbf, 0xae, 0x0c, 0xa7, 0x11, 0x37, 0x3f, 0xcf, 0x33, 0x60, 0xc0, 0x4b,
+	0xf0, 0xed, 0x95, 0x15, 0xdf, 0xa0, 0xc3, 0xe7, 0xc6, 0xba, 0xaa, 0xe7,
+	0x80, 0x5e, 0x2a, 0x4b, 0xac, 0x99, 0x34, 0x4f, 0x2d, 0x9d, 0x09, 0x5f,
+	0x28, 0xef, 0x56, 0x7e, 0xec, 0xc5, 0xf2, 0xff, 0x52, 0x77, 0x6d, 0xb1,
+	0x6d, 0x9d, 0xf7, 0xfd, 0xcf, 0x43, 0xea, 0x12, 0xdd, 0x7c, 0x24, 0xd3,
+	0x32, 0x2d, 0xd1, 0xf2, 0x39, 0xd2, 0xb1, 0xc5, 0xd8, 0x5a, 0xc7, 0x6a,
+	0xca, 0x26, 0xac, 0x5a, 0xc2, 0x52, 0xf4, 0x65, 0x59, 0x36, 0xd0, 0x97,
+	0x76, 0x1e, 0x16, 0xa0, 0x0e, 0x65, 0x3b, 0x1d, 0xd0, 0x07, 0xb7, 0xd9,
+	0x80, 0xa4, 0x03, 0x6c, 0x96, 0xb2, 0x1c, 0xaf, 0x53, 0x4d, 0x36, 0x66,
+	0xd5, 0xac, 0x1b, 0x50, 0x4e, 0x92, 0x9d, 0xb4, 0x50, 0xc0, 0x64, 0xbd,
+	0x60, 0xd8, 0x43, 0xad, 0xc9, 0xf6, 0xf6, 0xb2, 0x87, 0x6c, 0xd8, 0x83,
+	0x81, 0x0d, 0x98, 0x63, 0x05, 0x68, 0x96, 0x02, 0x49, 0x87, 0x15, 0x43,
+	0x1e, 0x36, 0x70, 0xff, 0xdf, 0x77, 0x21, 0x0f, 0x0f, 0x0f, 0x75, 0x89,
+	0x9d, 0x01, 0x33, 0x60, 0x88, 0xe7, 0x9c, 0xef, 0x9c, 0xf3, 0x7d, 0xff,
+	0xef, 0x7f, 0xbf, 0x9d, 0x3a, 0x3f, 0x8f, 0xd8, 0xc3, 0xdc, 0xca, 0x5b,
+	0x0c, 0x8b, 0xbb, 0x42, 0x96, 0xcd, 0xe5, 0x69, 0x28, 0x48, 0xd8, 0x0f,
+	0x0a, 0x30, 0x0c, 0x44, 0x6e, 0x86, 0x8c, 0xcd, 0x47, 0xc5, 0xbe, 0x4a,
+	0x5e, 0x71, 0xcc, 0x95, 0x5b, 0x51, 0xdb, 0x5b, 0x99, 0x73, 0x21, 0xf7,
+	0x42, 0xe6, 0x85, 0x00, 0x9e, 0xab, 0x17, 0x8f, 0x3b, 0x32, 0x2f, 0x64,
+	0x64, 0x01, 0xe7, 0xfa, 0x3d, 0x72, 0xae, 0x9d, 0x71, 0x00, 0x39, 0x44,
+	0xc8, 0x05, 0xc7, 0x9c, 0x85, 0x5f, 0xc3, 0x37, 0x2e, 0xbd, 0x3d, 0xff,
+	0xaa, 0x7c, 0xe7, 0xb0, 0x78, 0xe7, 0x2e, 0xc5, 0xb3, 0x74, 0x0e, 0x78,
+	0x3c, 0x30, 0x93, 0x1f, 0x8d, 0x04, 0x19, 0xbf, 0x67, 0xca, 0xb0, 0xa5,
+	0x9b, 0xe9, 0x6b, 0x1b, 0xc1, 0x33, 0xd1, 0x00, 0xcf, 0x7a, 0x9a, 0x60,
+	0xdb, 0xbb, 0xca, 0xbb, 0x25, 0xec, 0xe4, 0x79, 0xe4, 0xb7, 0xeb, 0xfc,
+	0x04, 0x09, 0xbb, 0x2a, 0x0d, 0x5d, 0x73, 0xe7, 0x26, 0xd4, 0x60, 0x77,
+	0xa6, 0x0a, 0xbb, 0xdd, 0xff, 0x8f, 0x60, 0x77, 0x4f, 0xe8, 0xba, 0x6f,
+	0x95, 0x91, 0x83, 0xa6, 0xe5, 0xbd, 0xae, 0x5d, 0x02, 0x1c, 0xc1, 0x4f,
+	0xed, 0xd2, 0x2a, 0x81, 0xa7, 0x22, 0x6f, 0xb8, 0x52, 0xf9, 0x41, 0xbc,
+	0xea, 0x93, 0x64, 0x1b, 0x04, 0xb6, 0x08, 0x7c, 0x77, 0xcd, 0x65, 0xe4,
+	0xf1, 0x8f, 0x25, 0x23, 0xa1, 0x17, 0x79, 0x6d, 0x91, 0x1f, 0xf5, 0xb8,
+	0x6d, 0x91, 0xe3, 0xdb, 0xb4, 0x45, 0x2e, 0x48, 0x5b, 0x24, 0xbb, 0x75,
+	0x5b, 0x64, 0xa0, 0x21, 0x5f, 0xab, 0xb6, 0x9e, 0xed, 0xdb, 0x22, 0xc6,
+	0x86, 0xb6, 0xc8, 0x88, 0xcb, 0xef, 0x82, 0xf9, 0xfe, 0x2e, 0x65, 0x4f,
+	0x80, 0xc7, 0x69, 0x38, 0x03, 0xc6, 0x27, 0x3c, 0x3e, 0xe0, 0x4f, 0x12,
+	0xd6, 0xe6, 0x8e, 0xff, 0x5b, 0x58, 0x0f, 0x36, 0xf8, 0xb7, 0x6b, 0xeb,
+	0xa1, 0xf0, 0xce, 0x6d, 0xe9, 0xec, 0x5e, 0x58, 0x0f, 0x36, 0xf5, 0x93,
+	0x36, 0xcf, 0x45, 0xac, 0xf7, 0x93, 0x0e, 0x1b, 0xcd, 0x78, 0xfb, 0x77,
+	0x5d, 0xfe, 0x53, 0x37, 0x7f, 0x07, 0x4d, 0x51, 0xe0, 0xf8, 0xa8, 0x7e,
+	0x17, 0x68, 0xc9, 0xce, 0x66, 0x09, 0xf6, 0x11, 0xde, 0x17, 0x11, 0xb4,
+	0xe6, 0xd1, 0xb7, 0xf8, 0x7d, 0xbc, 0xbe, 0xd7, 0x9e, 0x15, 0x72, 0x4a,
+	0xfa, 0x1a, 0x30, 0x3e, 0x16, 0x38, 0x2b, 0xc6, 0xca, 0xdc, 0x24, 0xe5,
+	0x7b, 0x50, 0x7a, 0x7e, 0x33, 0x9f, 0x43, 0xa3, 0xcc, 0xdb, 0x9e, 0x5d,
+	0xa0, 0x69, 0x7c, 0x1f, 0xef, 0x4b, 0xa4, 0xce, 0xae, 0x02, 0xff, 0xbc,
+	0xc0, 0x7a, 0xc1, 0x70, 0x55, 0x27, 0xa8, 0xdf, 0x9b, 0xcb, 0xc2, 0x7e,
+	0xd3, 0xbc, 0x33, 0x2d, 0xf2, 0xdd, 0x24, 0xef, 0x84, 0x9e, 0xa6, 0x79,
+	0xa7, 0x57, 0x0f, 0xde, 0xe7, 0x83, 0x17, 0xbe, 0x75, 0xa7, 0x7a, 0xef,
+	0x2c, 0xe4, 0x8f, 0xa7, 0x7c, 0xf7, 0xae, 0x5a, 0x77, 0x95, 0xad, 0x8d,
+	0x95, 0xf7, 0xa7, 0xc4, 0xba, 0xa2, 0x4f, 0x27, 0x51, 0x13, 0x57, 0xad,
+	0x09, 0xf2, 0xd6, 0x41, 0x41, 0x0e, 0x68, 0x3a, 0xd4, 0x75, 0xe2, 0x80,
+	0x45, 0xcc, 0xa7, 0x0e, 0xca, 0x2d, 0x4b, 0x70, 0x9f, 0x17, 0x16, 0x35,
+	0x39, 0x32, 0xa7, 0xe4, 0xc8, 0xa2, 0x8b, 0x8f, 0x37, 0xea, 0xed, 0x7d,
+	0x3e, 0x7a, 0xbb, 0xbb, 0xb6, 0x43, 0xd4, 0xb8, 0x35, 0xa9, 0xed, 0xf0,
+	0xab, 0x99, 0xc2, 0xd8, 0x17, 0x59, 0x5f, 0xf9, 0x14, 0xf4, 0x15, 0x13,
+	0x35, 0x4b, 0x52, 0x67, 0xc1, 0x75, 0x96, 0x49, 0xaf, 0x45, 0x18, 0xa7,
+	0x8e, 0xd1, 0x79, 0xd6, 0xc9, 0x6f, 0xd2, 0xe3, 0xca, 0x66, 0x4b, 0xb8,
+	0xf2, 0x4c, 0x91, 0xdf, 0x1f, 0xa0, 0xec, 0xb3, 0x76, 0x2c, 0x41, 0xc7,
+	0xe8, 0x9c, 0xc8, 0x99, 0x41, 0xcc, 0x0f, 0x79, 0x08, 0x07, 0xc5, 0x3c,
+	0xa5, 0x7f, 0xe3, 0x51, 0xe4, 0xcd, 0x6d, 0x3d, 0x67, 0x5f, 0xd7, 0xfa,
+	0x25, 0xc5, 0x3b, 0x97, 0x15, 0xed, 0x89, 0x73, 0x7c, 0xff, 0x8b, 0x46,
+	0xe3, 0xfd, 0x09, 0x23, 0x55, 0x4e, 0x19, 0xc9, 0x25, 0x8c, 0x7b, 0xd1,
+	0x98, 0x2e, 0xc3, 0xd6, 0xd4, 0xb8, 0x64, 0xc7, 0x41, 0x97, 0x6b, 0xb4,
+	0x79, 0x7c, 0x62, 0x91, 0x3c, 0xf5, 0x13, 0x5b, 0x98, 0xf7, 0x91, 0xba,
+	0x79, 0x6b, 0xf8, 0xe2, 0x37, 0x7c, 0x40, 0x09, 0x86, 0xa9, 0xd6, 0x7f,
+	0x3b, 0xe0, 0x73, 0x8f, 0x65, 0x69, 0x23, 0xfd, 0xd7, 0x6e, 0xd0, 0x7f,
+	0x17, 0x37, 0x9d, 0xf7, 0xc3, 0xf2, 0x02, 0x59, 0xc3, 0x1d, 0x74, 0x84,
+	0x9e, 0xcb, 0xf3, 0xae, 0xd3, 0x81, 0x3d, 0x38, 0x85, 0x31, 0xda, 0x37,
+	0xae, 0x7d, 0x63, 0x3d, 0x2a, 0x1f, 0x58, 0xe7, 0x2c, 0x74, 0x28, 0x3c,
+	0xc6, 0x75, 0xd8, 0x62, 0xab, 0x3c, 0x3f, 0xd8, 0x65, 0x4f, 0x8a, 0x39,
+	0xb2, 0x5d, 0x66, 0x4d, 0x93, 0xf4, 0x7f, 0x9f, 0x2d, 0xd7, 0xd5, 0x8f,
+	0xfa, 0xd4, 0x51, 0x0e, 0xfb, 0xd4, 0x51, 0xba, 0x69, 0x32, 0xe4, 0xa2,
+	0xc9, 0x88, 0x4b, 0xbf, 0x8b, 0xb2, 0x7d, 0xd3, 0xc5, 0xbc, 0x06, 0xf6,
+	0x4d, 0x07, 0x05, 0x5f, 0x71, 0xdb, 0x37, 0xde, 0xba, 0x7d, 0xd0, 0x27,
+	0x74, 0x38, 0x69, 0xeb, 0xa4, 0x8a, 0xd5, 0x9a, 0x7f, 0x5e, 0x77, 0xad,
+	0x66, 0x71, 0xa9, 0xa1, 0xbe, 0xd2, 0x6f, 0xbe, 0x43, 0x0d, 0xf3, 0x85,
+	0x9c, 0x4b, 0x34, 0xd5, 0xfd, 0xfc, 0xec, 0xaf, 0x47, 0x35, 0x3f, 0x2f,
+	0xdf, 0xc3, 0xbb, 0x86, 0x85, 0x1f, 0x3c, 0x5b, 0xe5, 0x79, 0x93, 0x72,
+	0xbe, 0xf9, 0x7a, 0x7b, 0x24, 0x78, 0x8d, 0x14, 0xec, 0xfc, 0x65, 0xc0,
+	0xf6, 0x7c, 0x6a, 0x9d, 0x1e, 0xf9, 0x3c, 0xd1, 0x2b, 0x7d, 0x65, 0x2d,
+	0x2a, 0xd7, 0x7a, 0x97, 0xb2, 0x0b, 0x37, 0xc3, 0x77, 0x9c, 0x6b, 0x51,
+	0xfe, 0x45, 0xdb, 0x2a, 0x11, 0xf0, 0xfc, 0xc4, 0xe9, 0x16, 0xc7, 0x54,
+	0xf1, 0x2d, 0xc4, 0xb0, 0x80, 0xf7, 0xfa, 0xf9, 0xb2, 0xd6, 0x6a, 0xf3,
+	0x3d, 0xb3, 0x1a, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x32, 0xe4, 0x10, 0x8f,
+	0x79, 0xf2, 0xb8, 0x1f, 0x06, 0x16, 0x3d, 0x3e, 0xb9, 0xcd, 0xc8, 0x4d,
+	0x6e, 0x36, 0xcf, 0xfb, 0x2e, 0xfd, 0x1d, 0xf3, 0xad, 0x54, 0xde, 0x8c,
+	0x0f, 0x48, 0x99, 0x5d, 0xf6, 0xd7, 0xa5, 0xcc, 0x2d, 0xcf, 0xcf, 0x2b,
+	0xa3, 0xf7, 0x6c, 0x51, 0x46, 0x8b, 0x7e, 0x28, 0x81, 0xc3, 0x82, 0x07,
+	0xa0, 0x06, 0x1b, 0x39, 0xd6, 0x9f, 0x06, 0xcd, 0x33, 0x9f, 0x75, 0xd5,
+	0xaa, 0xf9, 0xef, 0x63, 0x35, 0xce, 0x12, 0x42, 0x2f, 0x88, 0x09, 0xe4,
+	0x9b, 0xf4, 0x31, 0xef, 0xc1, 0xf8, 0xfd, 0xd6, 0x1d, 0xf8, 0x80, 0x95,
+	0x9f, 0x2a, 0xa5, 0xe4, 0xcb, 0xe1, 0x2d, 0xc4, 0x5b, 0xb6, 0xc7, 0xa7,
+	0x6d, 0x6b, 0x95, 0x10, 0x0b, 0x42, 0x4e, 0xf0, 0x0b, 0x3d, 0xd4, 0x73,
+	0xaa, 0xad, 0xcd, 0xb9, 0xdb, 0x2b, 0xe3, 0x53, 0xb8, 0xd6, 0x45, 0x37,
+	0x8a, 0xc8, 0xd7, 0xc6, 0xb5, 0xdf, 0xe3, 0x6b, 0x7e, 0x3c, 0x4a, 0xe7,
+	0x9b, 0x43, 0xe7, 0x93, 0xfb, 0x53, 0x22, 0xd8, 0x54, 0x15, 0xfa, 0xa7,
+	0xf8, 0xaf, 0xc8, 0x18, 0x47, 0xf9, 0x51, 0xc7, 0x6f, 0xfc, 0xfc, 0x8a,
+	0x46, 0xdf, 0xc7, 0xcd, 0x97, 0xfc, 0xf2, 0x96, 0xfc, 0x8a, 0xc8, 0xbb,
+	0xdf, 0x4a, 0x1c, 0x45, 0xc7, 0x8b, 0x27, 0x44, 0xed, 0xa9, 0x1b, 0x0f,
+	0x1e, 0x4d, 0xcc, 0x18, 0xf8, 0x30, 0xd4, 0xc0, 0xab, 0x1e, 0x3e, 0x06,
+	0xe0, 0x85, 0x6b, 0x87, 0xaf, 0x4f, 0xcb, 0x3f, 0x36, 0x8c, 0x3c, 0x00,
+	0xf8, 0xb3, 0x9f, 0xa2, 0xb3, 0xd7, 0x81, 0xc3, 0x06, 0x63, 0xdb, 0x08,
+	0xcd, 0x86, 0x51, 0x57, 0x24, 0x6a, 0x73, 0x54, 0x2c, 0x51, 0xd6, 0x0a,
+	0x9d, 0x15, 0x75, 0x8f, 0xfb, 0x23, 0xeb, 0x94, 0x66, 0xb9, 0x97, 0xa5,
+	0x73, 0x2c, 0x63, 0xcf, 0x2d, 0xd5, 0x74, 0xfc, 0xc6, 0xda, 0xc7, 0x7a,
+	0x1c, 0x5f, 0x17, 0x38, 0x1e, 0xdd, 0x10, 0xc7, 0x8f, 0x56, 0x71, 0x7c,
+	0xae, 0x4f, 0xe2, 0xf3, 0x45, 0x7e, 0x56, 0x0f, 0x1d, 0x16, 0xcf, 0xcd,
+	0xf2, 0xef, 0x4e, 0x3a, 0x2c, 0xfb, 0x62, 0xf0, 0xbb, 0x99, 0xc7, 0xe7,
+	0xb3, 0x74, 0xfe, 0x7a, 0x36, 0x90, 0x12, 0x35, 0x0a, 0xee, 0xbe, 0x1e,
+	0xfa, 0x7e, 0x8c, 0x6b, 0x86, 0xff, 0x9a, 0x2f, 0xc9, 0x9a, 0xab, 0x92,
+	0xe4, 0x4f, 0xf4, 0x76, 0x7c, 0xd0, 0x83, 0xff, 0xf5, 0x36, 0xe6, 0x05,
+	0x25, 0x03, 0x4f, 0x6c, 0xe0, 0xff, 0x68, 0xc4, 0xcb, 0x5e, 0x1f, 0xbd,
+	0xf9, 0x8d, 0x3e, 0x19, 0xbb, 0xda, 0xc8, 0xff, 0xe1, 0xc6, 0xd1, 0xba,
+	0x58, 0x3e, 0xf3, 0xfd, 0x84, 0xaa, 0xff, 0x7b, 0xa7, 0x4f, 0xca, 0x0b,
+	0xd4, 0x04, 0xa6, 0x19, 0x0e, 0x6f, 0xb2, 0xae, 0x32, 0x48, 0xad, 0xaf,
+	0xe8, 0xb5, 0x0e, 0x0a, 0x7e, 0xeb, 0xf6, 0xe7, 0x5c, 0x56, 0xb5, 0xe0,
+	0x39, 0xd7, 0x9a, 0x2e, 0x0b, 0x5b, 0xa8, 0x39, 0xbd, 0x35, 0xcf, 0xc3,
+	0x8a, 0x7a, 0x64, 0x82, 0x17, 0xdf, 0xd0, 0x2f, 0x05, 0xfb, 0x4b, 0x86,
+	0xd4, 0x83, 0x27, 0x59, 0xbf, 0xdd, 0x6e, 0x0c, 0xe9, 0x61, 0x75, 0x44,
+	0x6f, 0x4f, 0x0e, 0xef, 0x6f, 0xec, 0x83, 0xb4, 0x39, 0x32, 0xaf, 0x3d,
+	0x25, 0x78, 0xc1, 0xe5, 0xb1, 0x0a, 0x4d, 0xc7, 0xbb, 0x29, 0x33, 0xc6,
+	0xef, 0x9e, 0x44, 0x4f, 0xac, 0x20, 0x65, 0x99, 0x7e, 0x33, 0x63, 0x8f,
+	0x29, 0x7d, 0x51, 0xfb, 0xdd, 0xdb, 0x54, 0xee, 0xc3, 0x45, 0x11, 0xab,
+	0x94, 0xfd, 0x84, 0xf8, 0xf7, 0x92, 0x7e, 0xf6, 0x45, 0x11, 0x33, 0xcd,
+	0x5c, 0x6f, 0x55, 0xe3, 0x3a, 0x5d, 0xe3, 0x30, 0xa6, 0x53, 0x8d, 0xc5,
+	0x33, 0xb5, 0x4e, 0xd1, 0xae, 0xf8, 0x2d, 0xe8, 0x30, 0xad, 0x6a, 0xf5,
+	0x70, 0xfd, 0x02, 0xcd, 0x54, 0xd7, 0xd2, 0xc9, 0x63, 0xff, 0x5b, 0xf5,
+	0xf2, 0xe8, 0x64, 0x9d, 0x17, 0xf3, 0x6e, 0x9c, 0x13, 0xd6, 0x12, 0x14,
+	0x71, 0x24, 0xfe, 0xad, 0xde, 0x73, 0xa6, 0x3a, 0x27, 0xe4, 0x6d, 0xd8,
+	0x11, 0xf9, 0x2c, 0x3d, 0xae, 0xd3, 0x35, 0x4e, 0xf3, 0x0a, 0x1d, 0xa7,
+	0xf8, 0x57, 0x9e, 0xc7, 0x3f, 0xa8, 0xbc, 0x5e, 0x53, 0xc4, 0x54, 0x65,
+	0xde, 0x86, 0xfe, 0x0d, 0x3f, 0x34, 0xf2, 0x2c, 0x90, 0x3b, 0xe1, 0xe6,
+	0x37, 0x72, 0xbd, 0x21, 0xc8, 0xa2, 0x32, 0x62, 0xa9, 0x88, 0x6b, 0x34,
+	0xd3, 0x9d, 0xf7, 0x20, 0x5f, 0x7f, 0x1b, 0x3a, 0xe8, 0x56, 0xe8, 0xcf,
+	0xf2, 0xa1, 0x3f, 0xf7, 0xfb, 0x51, 0xeb, 0x86, 0x9a, 0xb7, 0x6c, 0xcc,
+	0xa0, 0x0a, 0xdb, 0x0a, 0x06, 0x95, 0xcc, 0x00, 0x9d, 0x77, 0xec, 0xf8,
+	0x12, 0xc9, 0x9a, 0xc9, 0xe9, 0x79, 0x3b, 0xb6, 0x4a, 0x87, 0xcc, 0x73,
+	0x24, 0x7b, 0x25, 0x94, 0x58, 0x06, 0x9f, 0xa1, 0x18, 0xdb, 0x47, 0x6c,
+	0x7f, 0x9e, 0x42, 0x5c, 0x46, 0xef, 0x0b, 0x6a, 0xe3, 0xf1, 0x37, 0xc6,
+	0x70, 0xba, 0xb9, 0x93, 0x3a, 0x12, 0xfc, 0xcc, 0x18, 0xf8, 0x13, 0x3f,
+	0x27, 0x4d, 0x49, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x39, 0x65, 0x9b, 0x25,
+	0x32, 0x78, 0x2c, 0x6c, 0x57, 0x3c, 0x07, 0xf7, 0x27, 0xcc, 0x16, 0xf2,
+	0xd6, 0xe1, 0x5e, 0x14, 0x75, 0x8a, 0x6f, 0xc7, 0x0f, 0x92, 0xd1, 0x0f,
+	0x7e, 0x85, 0x7d, 0x1b, 0x55, 0xf1, 0xa4, 0x4b, 0xfc, 0xdb, 0x51, 0xbf,
+	0xbf, 0x2a, 0xea, 0xdd, 0xe4, 0x6f, 0xe0, 0xf6, 0x2f, 0xab, 0x3d, 0xab,
+	0xcb, 0x09, 0x89, 0x8c, 0x18, 0x5f, 0xa5, 0x0b, 0x4b, 0x1b, 0xf9, 0x66,
+	0xfc, 0xea, 0x5b, 0xbb, 0xb6, 0x58, 0xdf, 0xba, 0xbe, 0x53, 0xd6, 0x8c,
+	0xe1, 0xfd, 0x7e, 0xba, 0x97, 0x77, 0x6d, 0xee, 0x7a, 0xd5, 0xef, 0xd0,
+	0xb4, 0xac, 0x35, 0x56, 0xb8, 0x70, 0xbd, 0x89, 0x7f, 0xf3, 0x49, 0x21,
+	0x2f, 0xcf, 0xca, 0x38, 0xc3, 0x80, 0xec, 0x6d, 0x16, 0xa2, 0xe5, 0x6a,
+	0xed, 0x67, 0x50, 0xd5, 0x7f, 0x30, 0x53, 0x7c, 0xa4, 0x75, 0x9f, 0x3a,
+	0x57, 0x15, 0x71, 0xa7, 0xb4, 0x2b, 0x8f, 0x22, 0xa4, 0xf2, 0x24, 0x70,
+	0xdf, 0x48, 0x18, 0x75, 0x5b, 0xb2, 0xd6, 0x12, 0x63, 0x50, 0xe7, 0x08,
+	0x1b, 0x12, 0x75, 0xae, 0xf0, 0xfb, 0x35, 0xab, 0x05, 0xc5, 0x78, 0xf8,
+	0x9f, 0xb4, 0x5d, 0x78, 0x5a, 0xd0, 0x98, 0x7c, 0xa7, 0xac, 0xd9, 0x5c,
+	0x5c, 0x39, 0x23, 0xea, 0x24, 0x93, 0xaa, 0xf6, 0x33, 0x43, 0x5d, 0x42,
+	0x6f, 0xfa, 0xf8, 0x35, 0x9b, 0xe7, 0xc2, 0xdb, 0xaf, 0xd9, 0x74, 0xdf,
+	0xb3, 0xbd, 0x9a, 0x4d, 0x93, 0xd7, 0x6e, 0x2c, 0xc8, 0x9a, 0xcd, 0xfa,
+	0x58, 0x80, 0xf4, 0x43, 0x65, 0x5c, 0xf2, 0x48, 0xea, 0x7f, 0x5f, 0x72,
+	0xe5, 0x08, 0xcb, 0x7a, 0xcc, 0xc5, 0xaa, 0x0e, 0x24, 0xeb, 0x31, 0x65,
+	0x4e, 0xb1, 0xbb, 0x0f, 0x89, 0x8c, 0x39, 0xc8, 0xf7, 0x74, 0x7b, 0x62,
+	0x0e, 0x2d, 0x4c, 0xa3, 0xa3, 0xaa, 0xe6, 0xbc, 0x19, 0x6e, 0xd6, 0xd9,
+	0x2a, 0x4c, 0x73, 0x15, 0xfa, 0x69, 0xfc, 0xd3, 0x74, 0x3f, 0x1c, 0x51,
+	0xb9, 0x74, 0xc8, 0x9d, 0x3b, 0xa8, 0xe0, 0xa8, 0xf5, 0x0f, 0xf2, 0xd1,
+	0x3f, 0x7e, 0x5b, 0xe4, 0x10, 0x4b, 0xfd, 0x65, 0x50, 0xd1, 0x24, 0xe8,
+	0x36, 0xe2, 0xa2, 0xdb, 0x5d, 0x4d, 0xe8, 0x16, 0xf4, 0xf9, 0xdd, 0x1d,
+	0xb2, 0x4f, 0x01, 0xe2, 0xde, 0xdf, 0x57, 0xbf, 0x37, 0xa3, 0xbf, 0xf7,
+	0x78, 0x6f, 0x40, 0x83, 0x78, 0xc6, 0x87, 0xe1, 0x1a, 0x1d, 0xea, 0xdf,
+	0x98, 0xcb, 0x7e, 0xd7, 0x5c, 0x86, 0x5d, 0x73, 0xd9, 0xd7, 0x64, 0x2e,
+	0xac, 0x4f, 0x94, 0x2f, 0xf0, 0xff, 0x8f, 0x3b, 0x27, 0xe1, 0xab, 0x65,
+	0x5a, 0x8d, 0x0b, 0xf9, 0x9a, 0x03, 0x1c, 0x85, 0x9e, 0x32, 0xaa, 0xea,
+	0xe0, 0xdd, 0xf3, 0x6c, 0x66, 0xab, 0x41, 0x16, 0xa0, 0xd7, 0x41, 0x82,
+	0xef, 0xeb, 0x6c, 0xd2, 0xeb, 0x00, 0x3a, 0x86, 0x5f, 0xaf, 0x03, 0x37,
+	0x8f, 0x77, 0xeb, 0x52, 0xd0, 0x7d, 0x21, 0x03, 0xa1, 0xf3, 0xa2, 0x57,
+	0xc1, 0x2f, 0xd1, 0x85, 0xaa, 0x8e, 0x79, 0x90, 0xd2, 0x4a, 0xc7, 0xbc,
+	0xb0, 0xa4, 0xf7, 0x7c, 0xd8, 0xb3, 0xe7, 0x7e, 0x3a, 0xe7, 0x90, 0xca,
+	0xf1, 0xd1, 0xb0, 0xca, 0xba, 0x60, 0x95, 0xf5, 0x81, 0x95, 0x78, 0x47,
+	0x93, 0x79, 0x03, 0x3e, 0xb8, 0x07, 0xff, 0xbf, 0x13, 0x41, 0x8f, 0x16,
+	0xa2, 0xdf, 0xd8, 0x55, 0xf3, 0x0b, 0xe8, 0xdf, 0x98, 0x63, 0xd3, 0xdc,
+	0x4f, 0xa5, 0x0f, 0x0e, 0x06, 0x8e, 0x5c, 0x67, 0x03, 0x9d, 0x65, 0x5e,
+	0xbd, 0x2d, 0xa8, 0x75, 0x85, 0x03, 0x82, 0xef, 0xdd, 0x0f, 0x22, 0x77,
+	0x45, 0x9f, 0xeb, 0xd6, 0xbe, 0x5c, 0xb5, 0xfe, 0xd6, 0x3a, 0x7d, 0xa2,
+	0xa6, 0x4b, 0xe8, 0x1c, 0x54, 0xfd, 0x5b, 0xcb, 0xc0, 0x7b, 0x75, 0xfe,
+	0x89, 0x5b, 0x75, 0xfd, 0x06, 0xe1, 0x0b, 0xea, 0x4e, 0x1b, 0x4e, 0x4a,
+	0xe4, 0x91, 0xf6, 0x3a, 0xf0, 0x7b, 0x25, 0x99, 0x37, 0xf7, 0xa6, 0x91,
+	0xb3, 0xdc, 0x7b, 0xcd, 0xa2, 0x93, 0xf9, 0x2f, 0xed, 0x95, 0x74, 0x7a,
+	0x89, 0x86, 0xc7, 0x79, 0xfc, 0x14, 0x7c, 0xbd, 0x76, 0x2c, 0xc9, 0x4a,
+	0xe4, 0x5c, 0xb9, 0x8d, 0x16, 0x59, 0x5b, 0x0f, 0x3a, 0x25, 0xe1, 0xbb,
+	0x63, 0x99, 0x51, 0x40, 0x6f, 0x55, 0x63, 0xa1, 0x95, 0x9f, 0xdb, 0x4f,
+	0xcb, 0x45, 0xd0, 0x7c, 0x8b, 0xea, 0x11, 0x82, 0xb1, 0x01, 0xea, 0x73,
+	0xfe, 0x84, 0xe1, 0xf5, 0x05, 0x91, 0x47, 0xb9, 0x58, 0xb8, 0x24, 0xff,
+	0x96, 0x5e, 0x52, 0xef, 0xe0, 0xf7, 0x95, 0xff, 0x86, 0x12, 0x7d, 0x96,
+	0xcb, 0x36, 0x73, 0xff, 0xf3, 0xd7, 0x3f, 0x8e, 0x6f, 0x4b, 0xff, 0xc8,
+	0xa6, 0x6b, 0xfa, 0x87, 0xfb, 0xd9, 0x5a, 0x17, 0x39, 0xd6, 0x2f, 0xfb,
+	0x37, 0x00, 0x06, 0x9d, 0xd0, 0xad, 0xd2, 0x80, 0xa5, 0x31, 0x65, 0x47,
+	0x92, 0xc1, 0x49, 0x9a, 0x2d, 0x47, 0x8d, 0x4c, 0x01, 0x3a, 0x30, 0xff,
+	0x2d, 0x5d, 0xd9, 0x2d, 0x7d, 0x2e, 0xfa, 0x1e, 0xf0, 0xf5, 0x9d, 0x3c,
+	0xfe, 0x3f, 0xfa, 0x65, 0xee, 0xb5, 0xfb, 0x7c, 0x0f, 0x9f, 0x7f, 0x2e,
+	0x52, 0x7f, 0xfe, 0x31, 0x3e, 0xdf, 0xc7, 0xe7, 0xe1, 0x87, 0x84, 0x9f,
+	0x31, 0x46, 0x39, 0xde, 0x9f, 0xd9, 0x32, 0xf3, 0xa9, 0x57, 0x58, 0x5e,
+	0x2c, 0xe9, 0x71, 0xbb, 0x50, 0x97, 0x23, 0xf6, 0xc4, 0xe0, 0x31, 0x97,
+	0xf3, 0x63, 0x3c, 0x6e, 0x90, 0x82, 0xaf, 0x58, 0x34, 0xbb, 0xa4, 0x71,
+	0x52, 0xe7, 0xd4, 0xbf, 0xc3, 0xf0, 0x45, 0xde, 0xce, 0x47, 0xbb, 0x25,
+	0xfc, 0x62, 0xc2, 0x87, 0x89, 0x3c, 0x8e, 0x2b, 0x02, 0xf7, 0xec, 0x49,
+	0xab, 0xfa, 0x7e, 0xe0, 0x96, 0x88, 0x73, 0xf0, 0x1a, 0x58, 0x2e, 0x4d,
+	0x39, 0x66, 0xae, 0x9a, 0x8f, 0xf6, 0xe7, 0x03, 0xf2, 0xfe, 0xff, 0xda,
+	0x25, 0xfb, 0xa3, 0xbe, 0x3f, 0xa0, 0xfb, 0x24, 0x4a, 0x9d, 0x00, 0x39,
+	0xca, 0x01, 0x01, 0x9b, 0xe0, 0x02, 0xe4, 0x95, 0xc1, 0xbf, 0x79, 0x3d,
+	0x69, 0xcc, 0xb1, 0xad, 0x5f, 0xf7, 0x7c, 0x91, 0xeb, 0x3a, 0xc6, 0xf3,
+	0x4d, 0xf1, 0xba, 0xf4, 0xf9, 0x04, 0x1f, 0xfb, 0xed, 0x2f, 0x9e, 0xd5,
+	0x91, 0x46, 0x5d, 0x70, 0xe6, 0x54, 0x47, 0x3a, 0x13, 0x93, 0xfb, 0x5c,
+	0xf3, 0xd1, 0x46, 0xaa, 0x3e, 0xda, 0xb9, 0xfc, 0x78, 0x3f, 0xfc, 0x15,
+	0xc6, 0x35, 0xde, 0xef, 0xf0, 0x15, 0x1e, 0x8b, 0x7a, 0x84, 0x1c, 0xff,
+	0xed, 0x52, 0xf9, 0x3c, 0x8d, 0xb8, 0x22, 0xf3, 0x23, 0xb4, 0x5e, 0x81,
+	0x7b, 0x9f, 0xe0, 0x67, 0x48, 0xdd, 0xa2, 0xf9, 0x7b, 0xa8, 0x21, 0xff,
+	0xa5, 0x11, 0xc7, 0x36, 0xf2, 0xab, 0x8a, 0x38, 0xa2, 0x0f, 0x9e, 0x6d,
+	0xd4, 0x83, 0xe0, 0x9e, 0xf0, 0x8b, 0x4d, 0x37, 0xd0, 0x2b, 0xe8, 0x38,
+	0x44, 0x2f, 0xcc, 0x67, 0xe9, 0x31, 0xde, 0xab, 0x3f, 0x30, 0x3e, 0x83,
+	0x38, 0x3b, 0xc9, 0x5c, 0x27, 0x86, 0x71, 0xde, 0x89, 0x9d, 0x33, 0x52,
+	0xe0, 0x8b, 0x95, 0x90, 0xd3, 0x45, 0xad, 0x4c, 0xab, 0xbf, 0x49, 0x23,
+	0x6c, 0xcf, 0x81, 0x66, 0x9d, 0x48, 0x8a, 0x40, 0x6f, 0xb6, 0x79, 0x84,
+	0x71, 0x62, 0xba, 0x0c, 0x7c, 0x36, 0xe8, 0x8b, 0x45, 0xa2, 0xe7, 0x8b,
+	0x23, 0xe6, 0xf7, 0xc8, 0xb1, 0x6a, 0xd7, 0x6d, 0x33, 0xc9, 0xf3, 0x48,
+	0x95, 0x5f, 0xa2, 0xf7, 0x44, 0xdf, 0x12, 0xc0, 0x51, 0xef, 0xfb, 0x1f,
+	0xd1, 0x99, 0x34, 0xe6, 0xbd, 0x75, 0xfa, 0x3c, 0xb9, 0x2d, 0xfa, 0xec,
+	0xf0, 0xa1, 0xcf, 0x7f, 0x54, 0x78, 0x53, 0x61, 0x1c, 0xed, 0xa0, 0x99,
+	0x02, 0x72, 0xbf, 0x3e, 0x8b, 0xfe, 0x52, 0x85, 0x0c, 0xf3, 0xa5, 0x4c,
+	0x8d, 0x2f, 0x5d, 0x4d, 0x06, 0x13, 0xa0, 0x71, 0xf4, 0x65, 0x53, 0xf9,
+	0x3e, 0x58, 0xc7, 0x00, 0x8d, 0x2c, 0x74, 0x22, 0xf6, 0xb5, 0x9a, 0x9c,
+	0x48, 0xa8, 0xfa, 0x7c, 0xdb, 0x9a, 0x66, 0xfe, 0x38, 0xc7, 0xb4, 0x9c,
+	0x2b, 0x1c, 0xa4, 0xc5, 0x70, 0x94, 0x86, 0x17, 0x74, 0xbf, 0x12, 0x11,
+	0x37, 0x89, 0x4a, 0x9e, 0xa4, 0xd7, 0xfd, 0x84, 0xf0, 0x45, 0x58, 0x37,
+	0x3f, 0xa9, 0x75, 0x77, 0x6e, 0xc2, 0x97, 0xde, 0x57, 0x34, 0x5b, 0xb9,
+	0x95, 0x8c, 0x53, 0x36, 0x39, 0xf1, 0xef, 0x02, 0xff, 0x87, 0x6f, 0xc2,
+	0xaf, 0x06, 0x1e, 0x6d, 0x51, 0x3a, 0xef, 0x85, 0x45, 0x94, 0xd7, 0x8d,
+	0xeb, 0x95, 0x0f, 0x67, 0xe2, 0x2f, 0x09, 0xdd, 0x6b, 0xe4, 0x26, 0x8f,
+	0x13, 0xf2, 0x48, 0xf3, 0x0d, 0x3f, 0x3c, 0xd4, 0x3d, 0x29, 0x35, 0x2e,
+	0xca, 0x7c, 0x4e, 0x93, 0x9f, 0x9b, 0x0e, 0x7a, 0x71, 0xf2, 0x5e, 0xe0,
+	0xf8, 0xbc, 0x45, 0x27, 0xf2, 0xf6, 0xab, 0x59, 0x9a, 0x64, 0xba, 0x76,
+	0xcb, 0x0b, 0x1e, 0x4f, 0xc0, 0xb3, 0x29, 0xd0, 0x3e, 0x65, 0x0a, 0x96,
+	0xcc, 0xb7, 0x13, 0x3d, 0xe5, 0x70, 0x8c, 0xda, 0xe2, 0xee, 0xdd, 0x5a,
+	0x1e, 0x64, 0x0a, 0xa8, 0x15, 0xe4, 0xbf, 0x25, 0x1e, 0x8f, 0xfc, 0xfe,
+	0x22, 0x9e, 0x03, 0x19, 0x87, 0xb9, 0xf3, 0xf1, 0xb2, 0xdc, 0xd7, 0x61,
+	0x7e, 0xf6, 0xc8, 0x38, 0xbf, 0xb3, 0x3c, 0xc6, 0xfb, 0xdb, 0x23, 0x78,
+	0xb3, 0xdc, 0xcf, 0x29, 0xba, 0xec, 0xcb, 0x57, 0xe4, 0xbe, 0x64, 0x5c,
+	0xf4, 0x9d, 0x11, 0xf4, 0x3d, 0x25, 0xf6, 0x23, 0x53, 0x34, 0x58, 0x5f,
+	0xd6, 0xbe, 0x04, 0xb6, 0x9b, 0x8b, 0x21, 0xc5, 0x43, 0x70, 0xed, 0x89,
+	0xdd, 0x22, 0x1f, 0x11, 0xf6, 0x74, 0x11, 0x7f, 0xa7, 0xe8, 0x0a, 0xeb,
+	0xfd, 0x2f, 0xe7, 0xdb, 0xe8, 0x4e, 0xa1, 0x8d, 0xee, 0x16, 0xa2, 0x74,
+	0x7b, 0x7e, 0x07, 0x5d, 0x66, 0x9b, 0xe6, 0xb2, 0x13, 0xb2, 0x72, 0xb4,
+	0x03, 0xf1, 0x42, 0xe4, 0x0a, 0x31, 0xdd, 0x61, 0x3c, 0xf4, 0xef, 0xe4,
+	0x1e, 0xc6, 0x39, 0xb6, 0x8d, 0xda, 0xe9, 0x5d, 0x7e, 0x67, 0x2e, 0xaf,
+	0x73, 0x1c, 0xe0, 0x63, 0xdf, 0x5f, 0xb5, 0x1f, 0x36, 0xc7, 0x11, 0x73,
+	0x13, 0x1c, 0x99, 0x12, 0xbc, 0x7e, 0x76, 0x3e, 0x8a, 0xbe, 0xca, 0xd9,
+	0x16, 0xf8, 0x49, 0x99, 0x3f, 0x3f, 0x17, 0xc2, 0x78, 0x9c, 0x73, 0x64,
+	0x8e, 0xa4, 0x58, 0x5b, 0x84, 0x8f, 0x03, 0xa2, 0x0e, 0x5a, 0xc2, 0xa1,
+	0x9d, 0xd7, 0x17, 0x10, 0xe3, 0x33, 0xcb, 0xed, 0x74, 0xb6, 0x68, 0xf2,
+	0x71, 0x90, 0xf5, 0x44, 0x8c, 0xed, 0xdd, 0xa7, 0xfb, 0xcb, 0x5e, 0xe6,
+	0xb9, 0xe7, 0xc4, 0x38, 0xfe, 0xbb, 0xdc, 0x43, 0xb3, 0xc5, 0x2e, 0x75,
+	0x7c, 0x50, 0xe6, 0xf2, 0x8a, 0x5c, 0x6c, 0x5c, 0xdb, 0x88, 0xbf, 0xbd,
+	0xcd, 0x38, 0x05, 0x99, 0x2a, 0x75, 0x7c, 0xf0, 0x9a, 0x5b, 0x0d, 0xfd,
+	0x90, 0x81, 0x73, 0x93, 0xf4, 0x4d, 0x96, 0xb7, 0xc3, 0xaf, 0xc0, 0x1f,
+	0xfc, 0xfb, 0xc0, 0x9b, 0x52, 0x96, 0x06, 0xf9, 0x18, 0x7d, 0x8e, 0x82,
+	0xa2, 0x96, 0x69, 0x3a, 0x1c, 0x13, 0xf5, 0x1f, 0x92, 0x46, 0x4f, 0x89,
+	0x9e, 0x73, 0x3f, 0x12, 0xbc, 0xc9, 0xce, 0x5a, 0x06, 0xf4, 0x11, 0xf8,
+	0x54, 0x64, 0xee, 0xd5, 0x49, 0xa7, 0xf7, 0xed, 0x5d, 0x53, 0xa3, 0x94,
+	0xe8, 0x07, 0xde, 0x4b, 0x9a, 0x55, 0x3d, 0x04, 0x04, 0xbf, 0x37, 0x0f,
+	0xe8, 0x9a, 0x48, 0x7d, 0xac, 0x65, 0x85, 0x3e, 0xee, 0xf2, 0x5c, 0x37,
+	0x3d, 0xd7, 0xab, 0x79, 0x72, 0x2c, 0xf3, 0x58, 0xce, 0x93, 0xec, 0x39,
+	0x84, 0xbe, 0x71, 0xc0, 0x3f, 0xf3, 0xc0, 0x7e, 0xf3, 0x73, 0xca, 0x06,
+	0xca, 0xac, 0x8c, 0x44, 0x7a, 0x8d, 0x98, 0x91, 0x19, 0xfb, 0x97, 0x4a,
+	0x22, 0x0d, 0xbd, 0xe8, 0xc6, 0x6e, 0xc9, 0xe3, 0x30, 0xaf, 0x6c, 0x1c,
+	0xaa, 0xdb, 0xa9, 0x95, 0x2e, 0x5a, 0x15, 0x7d, 0xb5, 0xa0, 0x63, 0xe0,
+	0x7e, 0x3c, 0x27, 0x6b, 0xb6, 0xb0, 0x7d, 0x77, 0xc3, 0x01, 0x8d, 0x1f,
+	0x8a, 0xdc, 0xe4, 0xfd, 0x4c, 0xad, 0x7c, 0x54, 0x39, 0x23, 0xfa, 0xd2,
+	0x60, 0x6c, 0x0f, 0xcd, 0x08, 0x9b, 0x8b, 0xf5, 0x97, 0x3a, 0xbb, 0x76,
+	0x12, 0xf3, 0xcc, 0x22, 0x56, 0x62, 0x38, 0xdf, 0x0e, 0x64, 0x4a, 0x32,
+	0xf6, 0x9d, 0xf2, 0xc4, 0xbe, 0x4f, 0x89, 0xd8, 0x37, 0xe2, 0xde, 0x80,
+	0x2b, 0x60, 0xe9, 0x97, 0xcb, 0x82, 0x7d, 0x8c, 0xf3, 0x3e, 0x5a, 0x34,
+	0x77, 0x5d, 0xf0, 0x9b, 0xc9, 0xe9, 0x60, 0xa2, 0xb7, 0x85, 0xac, 0x40,
+	0xd2, 0xb1, 0xe3, 0x0f, 0x58, 0x87, 0xb8, 0x5d, 0xc0, 0x3c, 0x5f, 0xa2,
+	0xf5, 0x52, 0x0b, 0xd3, 0x89, 0xcd, 0x78, 0xb7, 0xca, 0x3a, 0xed, 0x2c,
+	0xbd, 0x5b, 0x22, 0xba, 0x5d, 0xbc, 0x8a, 0x5e, 0xbb, 0xb1, 0x07, 0x4c,
+	0x2b, 0x88, 0x05, 0x67, 0x62, 0xf0, 0xb1, 0xb1, 0x5e, 0x1b, 0x6b, 0x55,
+	0xb8, 0xd9, 0xc5, 0xb6, 0xa3, 0xc9, 0xff, 0x1d, 0xfe, 0x1f, 0x89, 0x00,
+	0x2e, 0x6b, 0xc5, 0x31, 0xc1, 0x4b, 0x97, 0xf8, 0xfc, 0x12, 0x9f, 0x87,
+	0x4c, 0x5d, 0x2b, 0x56, 0xde, 0x49, 0xc6, 0x13, 0x56, 0x72, 0xe2, 0xa4,
+	0x1c, 0xc3, 0x38, 0x77, 0xf9, 0x7a, 0x62, 0x4f, 0x88, 0xe7, 0x31, 0xc3,
+	0xf3, 0x58, 0x27, 0x99, 0xeb, 0x9d, 0x12, 0xef, 0x26, 0xba, 0x23, 0xde,
+	0xcb, 0x3a, 0x53, 0xfc, 0x71, 0x3a, 0x13, 0x96, 0xef, 0xcf, 0xc5, 0x51,
+	0x73, 0xd5, 0x49, 0xb3, 0x63, 0xa3, 0xaa, 0xe6, 0xea, 0xcd, 0x26, 0x35,
+	0x57, 0xed, 0xb4, 0x36, 0x0f, 0xbb, 0xb7, 0x9d, 0xe9, 0xdd, 0x14, 0xb9,
+	0x7a, 0x6b, 0xf3, 0xa2, 0x1f, 0x3e, 0xaf, 0xa7, 0xb2, 0x3e, 0xc3, 0xaa,
+	0x79, 0x26, 0xde, 0x2d, 0x74, 0xa7, 0xdb, 0xcb, 0xbf, 0xc5, 0xf3, 0x49,
+	0x58, 0x99, 0x09, 0xf7, 0x3a, 0xc4, 0x7c, 0xd7, 0xa7, 0xc5, 0xb8, 0xa0,
+	0x67, 0x5c, 0x82, 0x32, 0x13, 0x98, 0xbf, 0x18, 0xf3, 0x3f, 0xc9, 0xb8,
+	0x5e, 0x8f, 0xfb, 0x7e, 0x8b, 0x72, 0x42, 0xdf, 0xe7, 0xbf, 0x4b, 0x3d,
+	0x81, 0xf5, 0x02, 0xfc, 0x26, 0x06, 0xe3, 0x3f, 0xe6, 0x66, 0x51, 0x76,
+	0x89, 0xd7, 0x75, 0xbd, 0x2b, 0xf0, 0xa0, 0xf0, 0x93, 0x4a, 0xa6, 0x2e,
+	0xb7, 0xa5, 0xde, 0xbf, 0x2e, 0x6d, 0xae, 0x28, 0x39, 0xd7, 0x20, 0x4b,
+	0x21, 0x47, 0xb3, 0x95, 0xa0, 0x03, 0xbd, 0x0f, 0xb6, 0xd0, 0x25, 0xe6,
+	0x63, 0x32, 0x3f, 0x89, 0x79, 0x2a, 0xf3, 0x32, 0x49, 0x47, 0xa9, 0xba,
+	0xcf, 0x32, 0x48, 0x5c, 0x1e, 0xae, 0xe5, 0x45, 0xba, 0xe2, 0xe6, 0x21,
+	0x57, 0xdc, 0xdc, 0x74, 0xe5, 0x45, 0x86, 0x85, 0x9e, 0x56, 0xd3, 0xad,
+	0xc2, 0x4a, 0xb7, 0x8a, 0x8a, 0x9e, 0xf4, 0xe0, 0x71, 0x8b, 0x55, 0x1e,
+	0xb7, 0x73, 0x13, 0x1e, 0xe7, 0x67, 0x9b, 0xae, 0x2a, 0x7e, 0x62, 0xc7,
+	0x21, 0x6b, 0x6e, 0x31, 0xdf, 0xf8, 0x71, 0x79, 0x82, 0xf9, 0x49, 0x9c,
+	0xf9, 0xc9, 0x18, 0xf3, 0x93, 0x18, 0xf3, 0x13, 0x87, 0x61, 0x60, 0xf1,
+	0xda, 0xef, 0x05, 0x6e, 0xcf, 0x43, 0x8e, 0x4c, 0xd2, 0x95, 0x32, 0x78,
+	0xf3, 0x18, 0xeb, 0x42, 0xf7, 0x02, 0x6b, 0xf3, 0x3d, 0x8c, 0xc7, 0x52,
+	0xff, 0xa9, 0xb7, 0x6f, 0xec, 0x57, 0x51, 0x1f, 0x97, 0x8c, 0xaf, 0x81,
+	0xff, 0xbc, 0x99, 0xa5, 0xee, 0xc0, 0xed, 0x42, 0x57, 0x60, 0xad, 0xf0,
+	0x13, 0xf4, 0xa5, 0x78, 0x1d, 0x34, 0x8e, 0xbe, 0xbf, 0x3f, 0x1c, 0x9d,
+	0xe4, 0xb9, 0x77, 0x07, 0x66, 0x79, 0x5f, 0xbe, 0x12, 0x4f, 0xf4, 0xf6,
+	0x49, 0x5a, 0xc8, 0xe6, 0xc0, 0x3d, 0x17, 0x76, 0xd0, 0xfe, 0xf1, 0xe4,
+	0x9e, 0x5e, 0xa6, 0x5b, 0xe0, 0x7b, 0xad, 0xef, 0x4e, 0x90, 0xf1, 0xb0,
+	0x43, 0xf5, 0xeb, 0xb1, 0x58, 0x5e, 0x7e, 0xc8, 0xf7, 0x7f, 0x10, 0xc8,
+	0x15, 0x5e, 0xe3, 0x67, 0xe3, 0xf8, 0x4f, 0xe1, 0xdf, 0x64, 0x7b, 0x01,
+	0xbd, 0x7e, 0x3a, 0x79, 0x0c, 0xc6, 0xe2, 0xd8, 0x8e, 0x31, 0x6f, 0x8b,
+	0xaf, 0x1a, 0xf6, 0x64, 0xc2, 0x78, 0x3e, 0x8a, 0x9e, 0xf1, 0x3f, 0x2c,
+	0x3f, 0x15, 0x95, 0x31, 0xb6, 0xe7, 0xf6, 0x48, 0x3e, 0xc2, 0xb8, 0x19,
+	0x4e, 0x08, 0x9b, 0xad, 0xe5, 0x9a, 0x94, 0x9b, 0x8b, 0xbc, 0xbf, 0x4b,
+	0xf1, 0x18, 0xef, 0x6f, 0x97, 0x92, 0x99, 0x59, 0xbe, 0x2e, 0xe4, 0x31,
+	0xcb, 0x4e, 0x86, 0x77, 0x91, 0x4c, 0xd1, 0x03, 0xe2, 0x14, 0xfa, 0xea,
+	0x3c, 0x83, 0xe7, 0x31, 0xb6, 0x82, 0x6f, 0x7c, 0x18, 0xc8, 0x14, 0xf0,
+	0x5e, 0xe0, 0x1f, 0xff, 0x2e, 0x4d, 0xd2, 0xd5, 0xbc, 0x9e, 0xc3, 0x80,
+	0x61, 0x7c, 0x13, 0xf3, 0x08, 0xd0, 0x4e, 0xe7, 0xdf, 0x18, 0x4e, 0x7c,
+	0xfc, 0x97, 0xde, 0x39, 0x9d, 0x57, 0x73, 0x42, 0x9f, 0xca, 0x36, 0x5e,
+	0xc3, 0x4e, 0x42, 0xff, 0xa2, 0x45, 0xd1, 0x47, 0xb2, 0x55, 0xd8, 0xaa,
+	0x8b, 0xc2, 0xe6, 0x38, 0xba, 0xa7, 0xd6, 0xdb, 0xf2, 0x71, 0xcf, 0xb9,
+	0x9f, 0x07, 0x72, 0xf3, 0x87, 0x85, 0x6e, 0x36, 0x3c, 0xbe, 0x47, 0xd5,
+	0x9c, 0x7e, 0x5e, 0x5c, 0x33, 0x16, 0x70, 0xed, 0x49, 0x75, 0xed, 0xd7,
+	0x84, 0x4e, 0x8c, 0xfc, 0xb8, 0xd0, 0x35, 0x81, 0xdf, 0xbc, 0xaf, 0x4e,
+	0x8c, 0xf1, 0x3b, 0xb2, 0x04, 0xdf, 0xbc, 0x80, 0xa7, 0x86, 0x07, 0x60,
+	0x01, 0x9c, 0xef, 0x52, 0xf8, 0x6e, 0x5b, 0xa9, 0xa0, 0x5e, 0x77, 0x33,
+	0x38, 0xb3, 0x8e, 0x93, 0xc7, 0x5a, 0xb1, 0xa6, 0xdd, 0x81, 0x44, 0xc9,
+	0x32, 0x72, 0xf3, 0xb0, 0x71, 0xe0, 0x7f, 0xdc, 0x8b, 0xbc, 0x28, 0x9e,
+	0xc3, 0x6e, 0x4a, 0xa4, 0x31, 0x2f, 0x8c, 0xd3, 0x30, 0x18, 0xf7, 0xc0,
+	0xc2, 0x7d, 0xdf, 0x0e, 0x75, 0x5f, 0xbb, 0xd8, 0x0b, 0x32, 0xf0, 0x1e,
+	0xfd, 0x6e, 0xbc, 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x2e,
+	0xe6, 0xd7, 0xc9, 0x09, 0xf9, 0x2c, 0xe3, 0xa6, 0xbc, 0xb6, 0xcb, 0xf1,
+	0x9f, 0xaf, 0xdc, 0x3f, 0xdc, 0xab, 0xf7, 0x6f, 0x07, 0x95, 0x84, 0x5f,
+	0x09, 0xd7, 0xba, 0xc5, 0xb5, 0xa4, 0xd3, 0x2d, 0xf6, 0x75, 0x8e, 0x8f,
+	0xcf, 0x16, 0x7a, 0x02, 0xb0, 0xd5, 0x73, 0xe9, 0xee, 0x40, 0xa9, 0x84,
+	0xf5, 0x76, 0x07, 0x52, 0x8c, 0xf3, 0xd3, 0x85, 0x23, 0x95, 0x59, 0xc1,
+	0x5b, 0x58, 0xc7, 0xed, 0xb3, 0xcd, 0x33, 0xc6, 0xcf, 0xc4, 0x9a, 0xf8,
+	0x7d, 0xfc, 0x9b, 0xe9, 0x2e, 0xcf, 0x74, 0x97, 0x67, 0xba, 0xcb, 0x33,
+	0xdd, 0xb1, 0x8d, 0xfa, 0x83, 0x3c, 0xd3, 0x1d, 0xcb, 0x90, 0xb7, 0x58,
+	0x86, 0x48, 0x5a, 0x4d, 0x28, 0xdf, 0x9e, 0xa6, 0x55, 0x6f, 0x4d, 0xa6,
+	0xa6, 0x4d, 0xc8, 0x6d, 0x0a, 0x1c, 0x1d, 0xad, 0xa7, 0xd1, 0x3b, 0x4c,
+	0xa3, 0x2d, 0x53, 0xfd, 0xf4, 0xa0, 0x88, 0x3d, 0xb3, 0xad, 0x39, 0xe6,
+	0xd1, 0xa9, 0x20, 0x74, 0xac, 0x10, 0xd3, 0x13, 0x74, 0x4c, 0x9b, 0xe1,
+	0xde, 0x4f, 0xeb, 0xc5, 0x76, 0x1e, 0x03, 0x9a, 0xdd, 0xab, 0x8e, 0xf3,
+	0x4c, 0xb3, 0x90, 0x7b, 0xd7, 0x02, 0x77, 0x0a, 0x06, 0xeb, 0x62, 0x21,
+	0x33, 0x43, 0xe0, 0x9f, 0x42, 0x3f, 0xe3, 0x7d, 0x5f, 0x65, 0x7e, 0x0f,
+	0xdf, 0x29, 0x7a, 0x77, 0x95, 0x20, 0x3b, 0x22, 0xb7, 0x99, 0x7f, 0x5e,
+	0x28, 0x5e, 0x63, 0x3a, 0xef, 0xa3, 0x2f, 0x17, 0x21, 0x9f, 0x01, 0x23,
+	0x3e, 0x2e, 0x91, 0xf0, 0x7d, 0x19, 0x53, 0x58, 0xfb, 0xfe, 0xac, 0x21,
+	0xf0, 0xe4, 0xaf, 0x01, 0x07, 0x86, 0xfd, 0xdd, 0x3d, 0xe8, 0x69, 0x9f,
+	0x30, 0x5a, 0x95, 0x8f, 0x17, 0xbf, 0x31, 0x1e, 0x63, 0x01, 0x37, 0x1c,
+	0x37, 0x8b, 0x2f, 0xe2, 0x1b, 0x11, 0x71, 0x86, 0x87, 0x97, 0x5f, 0x5d,
+	0xe5, 0xfb, 0x05, 0xbc, 0x26, 0x93, 0x41, 0xd4, 0x87, 0xd3, 0xd7, 0x82,
+	0x53, 0x93, 0xf4, 0x72, 0x19, 0xf3, 0xbe, 0x42, 0xb3, 0x61, 0xf0, 0x1f,
+	0x3b, 0x7e, 0x9f, 0x24, 0xec, 0xda, 0x59, 0xdf, 0xfc, 0xa2, 0x3f, 0x4f,
+	0xb3, 0x92, 0x42, 0x3f, 0x6e, 0x63, 0x7b, 0x07, 0xb0, 0x79, 0x83, 0x71,
+	0x2d, 0x0e, 0x1f, 0x80, 0xe2, 0x67, 0xdf, 0x67, 0x9e, 0x83, 0x3d, 0xc3,
+	0x71, 0x3d, 0x0f, 0x5b, 0x53, 0x3c, 0xcc, 0x71, 0xf1, 0xb0, 0x5c, 0x95,
+	0x87, 0x31, 0x2e, 0x08, 0xde, 0x05, 0xde, 0x74, 0x82, 0xf5, 0x45, 0xf9,
+	0x1b, 0x7a, 0xe0, 0x4e, 0xc1, 0xab, 0x98, 0xb7, 0xb3, 0xfd, 0xb0, 0x58,
+	0xce, 0x06, 0x8e, 0x08, 0x9e, 0xa1, 0xf1, 0xf9, 0xa9, 0x01, 0x49, 0x07,
+	0xed, 0xd2, 0x1f, 0x79, 0x0a, 0x7c, 0xca, 0x6f, 0xfc, 0x67, 0x78, 0x1c,
+	0xc6, 0x3b, 0x91, 0xd7, 0x99, 0x7f, 0x2d, 0xc6, 0x63, 0x22, 0x06, 0x22,
+	0x6d, 0x9c, 0x2c, 0xdb, 0x01, 0xbb, 0x90, 0x6b, 0x69, 0x25, 0xab, 0xfc,
+	0x4b, 0xd7, 0x1f, 0xc1, 0xaf, 0x88, 0x3d, 0x4e, 0xf4, 0x1a, 0x72, 0x1d,
+	0x16, 0xd6, 0x31, 0x5b, 0xa4, 0xd0, 0x4c, 0x1c, 0xb9, 0x71, 0xe0, 0xeb,
+	0x1f, 0xf0, 0xba, 0xb1, 0xaf, 0x1f, 0x60, 0x5f, 0xe5, 0xb5, 0x89, 0x63,
+	0x62, 0x5e, 0xb3, 0xcb, 0x35, 0xfe, 0x37, 0x97, 0x1f, 0x30, 0x16, 0x0b,
+	0x72, 0x6e, 0x4b, 0xa3, 0x92, 0xc7, 0x2d, 0x96, 0xd0, 0xab, 0x4b, 0xcc,
+	0x91, 0xe7, 0xa6, 0xd7, 0x85, 0xf7, 0x6a, 0x7a, 0xdf, 0x0a, 0x6d, 0x3d,
+	0xc3, 0x74, 0x84, 0x3d, 0xc8, 0xba, 0x70, 0xe4, 0x5b, 0xfc, 0x7e, 0x9c,
+	0x6b, 0x9c, 0xff, 0x83, 0xea, 0xfc, 0x9f, 0xe4, 0xf9, 0x63, 0xcc, 0x07,
+	0x2c, 0xef, 0xe5, 0xfc, 0x1f, 0x54, 0xe7, 0x5f, 0x54, 0xf3, 0xa7, 0x9c,
+	0x31, 0xd5, 0xab, 0xf4, 0xf7, 0xa6, 0xcf, 0x6a, 0x9f, 0x99, 0x10, 0x63,
+	0xcd, 0x19, 0xe8, 0x44, 0xa6, 0x9e, 0x8b, 0xb6, 0x0d, 0xdd, 0x73, 0xb1,
+	0x63, 0xf7, 0xe9, 0x8f, 0x49, 0xea, 0x1d, 0x43, 0xac, 0x77, 0xe0, 0x3c,
+	0xcd, 0x82, 0xcf, 0xe6, 0xc2, 0xe8, 0x11, 0x3b, 0xc8, 0x30, 0x62, 0x3b,
+	0x6a, 0x82, 0xff, 0x0a, 0xbf, 0x18, 0x9e, 0xa3, 0xef, 0xff, 0x43, 0x5a,
+	0x9f, 0x07, 0x2f, 0x86, 0xfe, 0x29, 0xfb, 0xc8, 0xae, 0xaf, 0x48, 0xff,
+	0x6b, 0xca, 0xd7, 0xff, 0x0a, 0xdf, 0xeb, 0x04, 0xf4, 0x73, 0x13, 0x7e,
+	0xda, 0x69, 0xf5, 0xed, 0x8f, 0x5c, 0x19, 0xcf, 0xf2, 0xe3, 0x2b, 0x93,
+	0xae, 0x1c, 0x35, 0xe4, 0x8c, 0x64, 0x99, 0x4f, 0x38, 0x66, 0x8b, 0x21,
+	0x6b, 0x64, 0x6e, 0x95, 0xb5, 0xae, 0x73, 0x8c, 0xf7, 0xc4, 0x89, 0x1b,
+	0x46, 0x4a, 0xf8, 0x08, 0xda, 0x9d, 0x2e, 0x6a, 0x63, 0x39, 0x78, 0x8e,
+	0xd0, 0xe7, 0xcc, 0xb6, 0x10, 0x3b, 0xb9, 0xca, 0x38, 0x36, 0x1b, 0xb7,
+	0x23, 0xcf, 0x0b, 0x7b, 0x12, 0xf2, 0x01, 0xdf, 0x4e, 0x01, 0xac, 0x30,
+	0x07, 0xfe, 0xbd, 0x8c, 0x9e, 0x95, 0x71, 0x5e, 0x3f, 0x7c, 0xbd, 0x23,
+	0xd6, 0x5d, 0x96, 0x2b, 0x57, 0x85, 0x3f, 0xe5, 0x12, 0xeb, 0x92, 0xb6,
+	0x79, 0x54, 0xd0, 0x99, 0x31, 0xc4, 0x54, 0xc1, 0x74, 0x82, 0x1c, 0x81,
+	0xfd, 0xa2, 0xa7, 0x8e, 0xb4, 0x51, 0x78, 0x95, 0x2b, 0xaa, 0x57, 0x41,
+	0x1a, 0xb4, 0xbf, 0x75, 0x5f, 0x42, 0xfa, 0xa1, 0x7d, 0x28, 0x6e, 0x1d,
+	0xca, 0xeb, 0xa7, 0x86, 0x3d, 0x66, 0x89, 0xde, 0x8c, 0x80, 0x9d, 0xf0,
+	0x03, 0x1a, 0x63, 0x0c, 0x37, 0xfd, 0x9d, 0x1a, 0xb7, 0xbd, 0x7f, 0x5e,
+	0xd4, 0xdc, 0xbf, 0x59, 0x96, 0x32, 0x34, 0xc7, 0xb6, 0xf8, 0xec, 0xb8,
+	0x5b, 0xa7, 0xb0, 0x0b, 0xd3, 0xc2, 0x07, 0x33, 0x40, 0xc9, 0x85, 0x31,
+	0xfa, 0x7c, 0x1e, 0x3c, 0x88, 0xee, 0x27, 0x1d, 0xf1, 0xcd, 0x25, 0x9e,
+	0xd3, 0x18, 0xa5, 0xca, 0x80, 0x51, 0x80, 0x66, 0x99, 0xcb, 0xe7, 0x0a,
+	0x88, 0xbd, 0xf3, 0xef, 0x12, 0xbe, 0xa9, 0xf2, 0x3b, 0xca, 0xb7, 0x1d,
+	0xa5, 0xe9, 0x05, 0xca, 0x66, 0xe2, 0x4f, 0x8b, 0x3e, 0xd3, 0x99, 0xf8,
+	0xa8, 0xf2, 0xc9, 0x44, 0xf8, 0x3c, 0xfc, 0x5c, 0x16, 0x7d, 0x2e, 0x6f,
+	0x67, 0x33, 0x24, 0x7d, 0x0d, 0xc4, 0x73, 0x30, 0x58, 0x76, 0xee, 0x64,
+	0x9e, 0x70, 0x52, 0xf8, 0x1b, 0x58, 0xd3, 0x98, 0xc7, 0x78, 0xf8, 0x0a,
+	0xfa, 0x08, 0xf6, 0x55, 0xa6, 0xf0, 0x92, 0x1a, 0x5b, 0x21, 0x93, 0x71,
+	0xc1, 0xfc, 0x55, 0x27, 0x1b, 0x37, 0x6a, 0xf7, 0xc3, 0x57, 0x71, 0x52,
+	0xe8, 0x7d, 0x43, 0xb4, 0x24, 0x68, 0xbd, 0x52, 0x99, 0x11, 0x7e, 0x07,
+	0x3e, 0x2e, 0x4d, 0x0e, 0x4a, 0x5e, 0x25, 0xcf, 0x4b, 0x7f, 0x04, 0x3f,
+	0xb3, 0xc4, 0xf3, 0xa8, 0xcb, 0x7f, 0x8f, 0x52, 0x62, 0x1b, 0xfe, 0xa1,
+	0x53, 0x8f, 0xd4, 0x3f, 0xc4, 0xb0, 0x66, 0xd9, 0x71, 0x8b, 0x69, 0xe3,
+	0xc7, 0x9b, 0xda, 0x6d, 0xef, 0x69, 0x19, 0xcc, 0xb0, 0x32, 0xc5, 0xb7,
+	0x2b, 0xa0, 0x33, 0xcf, 0x96, 0xe7, 0xf0, 0x1d, 0x99, 0x40, 0x5a, 0xe8,
+	0xb2, 0x11, 0xd6, 0x4d, 0xa0, 0xa3, 0x8c, 0x88, 0x78, 0x62, 0xe2, 0x59,
+	0xcb, 0x98, 0x5d, 0xc1, 0xb7, 0xa1, 0xa0, 0x9b, 0xe9, 0x9c, 0x86, 0x76,
+	0x91, 0xa7, 0x2e, 0xe3, 0xbc, 0x90, 0xaf, 0xe0, 0x79, 0x3f, 0x0f, 0x64,
+	0x56, 0x9e, 0xde, 0xa5, 0xf3, 0xd5, 0x12, 0x61, 0x9d, 0x0f, 0xa3, 0x79,
+	0x8a, 0xc6, 0x3d, 0x1d, 0xa3, 0x70, 0x7f, 0xcb, 0x0b, 0xb4, 0xeb, 0xd6,
+	0x09, 0xe0, 0x57, 0x12, 0x7b, 0x74, 0x15, 0xb1, 0x31, 0xa3, 0x2e, 0xfe,
+	0xd0, 0xc6, 0xfb, 0x64, 0x31, 0x6e, 0xc0, 0x5f, 0xf7, 0x05, 0xfe, 0x8b,
+	0x38, 0x42, 0x69, 0x10, 0x7a, 0x50, 0xaf, 0xc3, 0x38, 0x33, 0x81, 0xe3,
+	0x7e, 0x5a, 0x2c, 0x6a, 0xbd, 0x55, 0xfa, 0x90, 0x16, 0x97, 0xf5, 0x7e,
+	0xc1, 0x7f, 0x34, 0xac, 0x7a, 0x08, 0xd8, 0x64, 0xf5, 0x01, 0x4e, 0x9f,
+	0x14, 0x3d, 0x6e, 0x16, 0x73, 0xd8, 0x4a, 0xce, 0x11, 0xbe, 0x2f, 0x86,
+	0x9e, 0x99, 0xfb, 0x00, 0x7b, 0xde, 0x23, 0x77, 0x4c, 0x62, 0x4e, 0x7d,
+	0xff, 0xe7, 0x51, 0xed, 0xdb, 0x63, 0x3e, 0xfb, 0xf6, 0xd1, 0xa0, 0x8c,
+	0x73, 0x3d, 0xa7, 0xc6, 0xf8, 0xe5, 0x99, 0xfe, 0xf3, 0x0b, 0xf0, 0x1f,
+	0xd5, 0xea, 0x25, 0xee, 0x09, 0xbe, 0xd2, 0xe8, 0xc3, 0x8e, 0x30, 0x3f,
+	0x95, 0x74, 0x7c, 0xd2, 0x87, 0x8e, 0xfb, 0x78, 0x8f, 0x4f, 0x3c, 0x04,
+	0x1d, 0x9f, 0x68, 0x4a, 0xc7, 0x87, 0xa2, 0xd2, 0x87, 0xda, 0x48, 0xc7,
+	0xa8, 0xd9, 0x39, 0x59, 0x6e, 0xe6, 0xaf, 0xc2, 0x3e, 0xa0, 0xf6, 0x1c,
+	0xfe, 0x04, 0xc0, 0x4a, 0xfb, 0x14, 0x10, 0xdb, 0x03, 0x3e, 0x22, 0x56,
+	0xf2, 0x17, 0x94, 0x9a, 0xf7, 0xc6, 0x38, 0x37, 0xba, 0xe7, 0x7d, 0x9f,
+	0x7b, 0xa0, 0x6b, 0x83, 0x16, 0xec, 0x88, 0xb4, 0xd5, 0x35, 0xbc, 0xde,
+	0x0d, 0x1c, 0x29, 0xda, 0xd9, 0x12, 0x18, 0x63, 0x4f, 0x98, 0xce, 0x23,
+	0x8e, 0xaf, 0x7c, 0xbe, 0xc7, 0xf3, 0x72, 0xdd, 0xe6, 0xb8, 0xc0, 0x07,
+	0xe8, 0xa3, 0x91, 0x74, 0x30, 0xcd, 0x7b, 0x2a, 0xfd, 0xbd, 0x99, 0xe5,
+	0x88, 0xda, 0x27, 0x1e, 0x8b, 0xe7, 0xf9, 0xd6, 0xf3, 0x61, 0x7f, 0xec,
+	0x57, 0x57, 0xab, 0x79, 0xc1, 0x90, 0x05, 0x15, 0xfa, 0x05, 0xcb, 0xb9,
+	0xe0, 0xb8, 0x29, 0xfa, 0x28, 0xdc, 0x2a, 0x8f, 0xb3, 0x7e, 0x88, 0x3d,
+	0x84, 0xaf, 0x50, 0xfb, 0x72, 0x7f, 0x31, 0x44, 0x3d, 0x87, 0x58, 0xea,
+	0x1b, 0xe4, 0xb0, 0x7e, 0x68, 0x8c, 0x23, 0xbf, 0xdb, 0xe2, 0x7b, 0xd0,
+	0xff, 0x69, 0xbf, 0x95, 0xa2, 0x2e, 0xf8, 0x09, 0xd0, 0xa7, 0xd9, 0xca,
+	0xd5, 0xd1, 0xd4, 0x69, 0x41, 0x53, 0xa9, 0x95, 0xd3, 0x8a, 0xa6, 0x4e,
+	0x2b, 0x7f, 0xf9, 0x69, 0x45, 0x53, 0xa7, 0x15, 0x4d, 0x9d, 0x56, 0x34,
+	0x75, 0x9a, 0xf1, 0x7a, 0xc4, 0xec, 0x13, 0x3a, 0xbb, 0xf6, 0x57, 0xf6,
+	0x50, 0xa6, 0x88, 0xf3, 0x90, 0xc7, 0x5e, 0xba, 0x7a, 0x75, 0x48, 0xd2,
+	0xd5, 0x24, 0x2d, 0xca, 0x3c, 0x39, 0x7e, 0x17, 0xf6, 0xe0, 0xeb, 0x83,
+	0xd4, 0x73, 0x2f, 0x70, 0x76, 0x1e, 0x73, 0x0d, 0xd0, 0xb4, 0xe8, 0xe1,
+	0xda, 0x42, 0x49, 0xb7, 0x2e, 0x6b, 0xa2, 0x7e, 0x4b, 0xda, 0x6a, 0xd9,
+	0xa6, 0xb5, 0x5c, 0x1a, 0x2f, 0xa6, 0xd4, 0x7e, 0x79, 0xed, 0x98, 0x36,
+	0x4a, 0x17, 0x00, 0x57, 0xe4, 0x32, 0x5a, 0xbc, 0x37, 0x02, 0x4e, 0x59,
+	0xd3, 0x07, 0x06, 0xc7, 0x15, 0x0c, 0xbe, 0x22, 0xd6, 0x88, 0x5c, 0x40,
+	0xf8, 0x1c, 0x9b, 0xc3, 0x21, 0x97, 0x1f, 0xe1, 0xe7, 0x30, 0xee, 0x8f,
+	0x47, 0x98, 0x07, 0x6d, 0x1d, 0x0e, 0xb5, 0xb5, 0x37, 0xe3, 0x35, 0x5b,
+	0xad, 0x87, 0xb9, 0xef, 0x92, 0x1d, 0x11, 0x25, 0x37, 0xa4, 0x9e, 0xfb,
+	0x98, 0x63, 0xa7, 0xb3, 0x3c, 0xb7, 0xbf, 0x8f, 0xb7, 0xef, 0xa5, 0x8e,
+	0x0a, 0x1d, 0x8b, 0x03, 0x9f, 0x7b, 0xd8, 0x6e, 0xe4, 0x39, 0xec, 0xaf,
+	0xd0, 0xd5, 0xf8, 0x01, 0xb6, 0x4d, 0xf0, 0x2d, 0xa6, 0x11, 0xfe, 0xef,
+	0x24, 0x82, 0x01, 0xcc, 0xab, 0x8b, 0xef, 0x0d, 0x93, 0xd1, 0x9b, 0xe8,
+	0x6d, 0x57, 0xba, 0x29, 0xfc, 0x6e, 0xac, 0x9b, 0x1a, 0x33, 0xf1, 0x1d,
+	0xaa, 0xa6, 0x0c, 0xbe, 0x6a, 0xc4, 0xb1, 0x7e, 0x56, 0x91, 0xbd, 0x00,
+	0xa2, 0xea, 0xf8, 0xa7, 0x95, 0x44, 0x14, 0xc7, 0x26, 0xdd, 0x60, 0x7b,
+	0x39, 0x11, 0x18, 0xd9, 0x2b, 0x74, 0xf6, 0x80, 0x7d, 0x4c, 0xe6, 0x30,
+	0xd8, 0xa6, 0x15, 0xf0, 0xc3, 0x77, 0xa9, 0xeb, 0xd4, 0xf2, 0x4c, 0x81,
+	0xff, 0x15, 0xfa, 0x4f, 0xa6, 0x55, 0x93, 0x10, 0xb3, 0x98, 0x14, 0xb5,
+	0xce, 0xc8, 0x33, 0x3e, 0x3b, 0x0f, 0x9a, 0x85, 0xdf, 0xd0, 0x51, 0x7b,
+	0xfc, 0x29, 0xe4, 0x89, 0x15, 0x16, 0x69, 0x63, 0x59, 0x01, 0xbf, 0xd8,
+	0xc8, 0xc2, 0x5a, 0x6f, 0x58, 0xd4, 0x5e, 0xc3, 0xcf, 0xa9, 0xf3, 0x89,
+	0xf7, 0xf3, 0xf3, 0x43, 0xe2, 0xdb, 0x72, 0xd3, 0xd7, 0x30, 0xae, 0x95,
+	0x86, 0x17, 0x2a, 0x4f, 0xf1, 0x75, 0x11, 0x2f, 0xcc, 0x50, 0xbb, 0x8a,
+	0x05, 0x74, 0xa9, 0xf8, 0x51, 0x84, 0x69, 0xa8, 0x56, 0x53, 0x3c, 0x5c,
+	0xf5, 0x9d, 0x01, 0xb7, 0xbd, 0xbe, 0xb3, 0xaf, 0x6d, 0x22, 0x67, 0x36,
+	0xc3, 0x67, 0xe4, 0x82, 0xb6, 0x91, 0xf2, 0x09, 0x5a, 0xb3, 0xb4, 0xd5,
+	0xda, 0xb9, 0x6d, 0xdf, 0xd3, 0xde, 0x3a, 0xb5, 0x7a, 0xf1, 0xae, 0xd3,
+	0xa1, 0xf0, 0xa8, 0x95, 0xce, 0x16, 0x3b, 0x58, 0x56, 0xa3, 0xce, 0x09,
+	0xf0, 0x0a, 0x46, 0x51, 0x27, 0xf2, 0x5c, 0xa8, 0x95, 0x96, 0x97, 0x91,
+	0xd3, 0xf0, 0x67, 0x7b, 0x65, 0x7e, 0x6e, 0x9a, 0xe1, 0x72, 0x88, 0xe5,
+	0x9a, 0xa1, 0x62, 0x35, 0x38, 0x07, 0x9e, 0x20, 0x7a, 0x78, 0x86, 0x9e,
+	0x1e, 0xed, 0x60, 0x7d, 0x5e, 0xfa, 0xfa, 0x0f, 0xf3, 0xb3, 0xbf, 0x57,
+	0x4c, 0xc3, 0x4f, 0x65, 0x1e, 0xe5, 0xe7, 0x4f, 0xb3, 0x1e, 0x90, 0xa0,
+	0x56, 0x5a, 0x5a, 0x6e, 0x65, 0x7d, 0xbe, 0x95, 0xf5, 0x80, 0x11, 0x73,
+	0x38, 0x20, 0xde, 0x25, 0x6a, 0x52, 0x3e, 0x1b, 0x3a, 0x64, 0x1e, 0x13,
+	0x79, 0x36, 0x7f, 0xa5, 0xde, 0xe5, 0x7d, 0xc7, 0x07, 0x15, 0x1c, 0x1f,
+	0x0d, 0xae, 0x5e, 0xbc, 0xe3, 0x98, 0x8c, 0x7f, 0x93, 0xac, 0xf3, 0x86,
+	0xc5, 0xf7, 0x17, 0x8d, 0xa9, 0x29, 0xd6, 0xff, 0xf1, 0x8d, 0xb7, 0x67,
+	0x28, 0x5b, 0x3e, 0x45, 0x5f, 0x2f, 0xbb, 0x7d, 0xaf, 0xcf, 0xf0, 0x9c,
+	0x65, 0xed, 0x7c, 0x1b, 0xcf, 0xeb, 0x3d, 0xc7, 0xcb, 0x2b, 0x3a, 0x28,
+	0xf8, 0xad, 0x30, 0xb5, 0x7e, 0x03, 0x3e, 0x8f, 0x0a, 0x15, 0xe2, 0xf6,
+	0xd5, 0xfb, 0x24, 0xfd, 0xbc, 0x37, 0x44, 0x5e, 0x2a, 0xdf, 0xcf, 0xcf,
+	0x9c, 0xc3, 0xb8, 0x1b, 0x16, 0xdd, 0x76, 0x24, 0xbc, 0xff, 0x36, 0x14,
+	0xa6, 0xe0, 0x1b, 0xc8, 0xf5, 0x82, 0x8e, 0xb5, 0x7a, 0xd1, 0x39, 0xc0,
+	0x7c, 0xfa, 0x1b, 0xb8, 0x8f, 0xff, 0xbe, 0x81, 0xe3, 0x0e, 0x5e, 0x27,
+	0xe4, 0x2c, 0x72, 0x4a, 0xc0, 0xdf, 0x0e, 0x45, 0x4c, 0x81, 0x7f, 0xcf,
+	0x30, 0x4e, 0xb5, 0x08, 0x1f, 0x5f, 0x1f, 0xc6, 0x3a, 0x83, 0xac, 0x13,
+	0xac, 0x5e, 0x1c, 0x3d, 0x80, 0xe3, 0x44, 0x6f, 0x90, 0x61, 0x24, 0x71,
+	0xa8, 0xe1, 0x9b, 0x75, 0xa1, 0xc3, 0xa3, 0xe4, 0xfa, 0x6e, 0x1d, 0x7a,
+	0x26, 0x75, 0x50, 0x8a, 0xdf, 0x31, 0x5d, 0x94, 0xeb, 0x9e, 0x2b, 0x07,
+	0x49, 0xfa, 0x87, 0x52, 0x43, 0xfa, 0xfb, 0x84, 0xd4, 0x8f, 0x67, 0x6b,
+	0x5a, 0xc1, 0xef, 0x1e, 0x7a, 0x50, 0xec, 0xa2, 0x75, 0x15, 0x43, 0x7a,
+	0x20, 0xec, 0x29, 0xe6, 0xc5, 0xe9, 0x1e, 0xba, 0xbf, 0xdc, 0x42, 0xd4,
+	0xd7, 0x21, 0x62, 0xbc, 0x0f, 0x8a, 0x8b, 0x94, 0x7c, 0xed, 0xc9, 0x21,
+	0xe9, 0x4f, 0xa9, 0xe1, 0xc8, 0x03, 0x1f, 0x1c, 0x79, 0x57, 0xe0, 0xc8,
+	0xf0, 0xd0, 0xc6, 0x38, 0xb2, 0x47, 0xe7, 0x22, 0x52, 0xab, 0xc2, 0x8f,
+	0xd7, 0x19, 0x3f, 0x5e, 0x66, 0xfc, 0x38, 0xd2, 0x04, 0x3f, 0x0c, 0x0f,
+	0x7e, 0x1c, 0x15, 0xf8, 0xf1, 0xeb, 0x43, 0x1b, 0xe1, 0xc7, 0x91, 0xe0,
+	0x46, 0x3e, 0x1e, 0x8d, 0x9b, 0x03, 0xb4, 0x54, 0x74, 0x68, 0x79, 0xde,
+	0x8e, 0x27, 0x68, 0x35, 0x22, 0x63, 0x83, 0x53, 0xa2, 0x4e, 0x65, 0x51,
+	0xe0, 0x55, 0x5a, 0xf8, 0x2f, 0xfd, 0xbf, 0x1b, 0x68, 0x29, 0xf8, 0xcb,
+	0x3d, 0x99, 0xce, 0xaf, 0x5e, 0xfc, 0x3b, 0xde, 0xc7, 0xdb, 0x2b, 0xa1,
+	0x10, 0xae, 0x05, 0xa7, 0xc2, 0xb4, 0xb6, 0x82, 0xef, 0x12, 0x46, 0xe8,
+	0x4e, 0x31, 0x4a, 0xb7, 0x8b, 0x03, 0xb4, 0x56, 0x1c, 0xa2, 0xbb, 0x45,
+	0xbc, 0x03, 0x30, 0xe7, 0x63, 0x01, 0x73, 0x83, 0x0e, 0x87, 0x79, 0xcc,
+	0xf2, 0x00, 0xad, 0x2e, 0x6b, 0x7c, 0x05, 0xae, 0x62, 0xff, 0xe1, 0x27,
+	0xf0, 0xc7, 0x81, 0xe9, 0x3a, 0x1c, 0x90, 0xf7, 0x60, 0xef, 0x67, 0x1b,
+	0x6b, 0x64, 0x45, 0x9e, 0xa5, 0xc9, 0x38, 0xd2, 0x32, 0x65, 0x0b, 0x5f,
+	0xea, 0xe1, 0x20, 0x74, 0xd9, 0xc4, 0x3e, 0xea, 0xe1, 0x3d, 0x70, 0x90,
+	0x27, 0x34, 0xc4, 0x7a, 0xe9, 0x0e, 0xa1, 0x87, 0x26, 0x9d, 0x50, 0x64,
+	0x9a, 0x2a, 0x97, 0x0c, 0x07, 0x3d, 0x0f, 0xd3, 0xfc, 0x3c, 0x43, 0xf9,
+	0x71, 0xba, 0x5d, 0xf8, 0xe4, 0xd5, 0x39, 0x11, 0x8b, 0x7d, 0x96, 0xe7,
+	0x0c, 0xf9, 0x58, 0x8b, 0x73, 0x50, 0x35, 0xce, 0xd1, 0xce, 0xeb, 0x96,
+	0xb4, 0x34, 0xe3, 0xf0, 0xb8, 0x32, 0x8f, 0x2b, 0x23, 0x76, 0xc6, 0xe7,
+	0x97, 0x11, 0xb7, 0x8d, 0xd2, 0xda, 0x3c, 0x68, 0x0e, 0x7e, 0x89, 0x5a,
+	0xac, 0x74, 0x6d, 0x05, 0xe7, 0xe1, 0x9b, 0xa8, 0xc5, 0x4a, 0xd7, 0x54,
+	0xac, 0x74, 0x6d, 0x65, 0x4a, 0xf0, 0xe1, 0xd9, 0xff, 0xdd, 0x14, 0x60,
+	0x19, 0x30, 0x85, 0x19, 0xba, 0x4e, 0x53, 0x0d, 0x7a, 0xbf, 0x4e, 0x0c,
+	0x78, 0x6c, 0x58, 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d,
+	0xb8, 0xfd, 0xe3, 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23,
+	0x80, 0x79, 0x49, 0x18, 0x9a, 0x97, 0x60, 0x73, 0xaf, 0xfc, 0x0c, 0x90,
+	0xbb, 0x7a, 0x6c, 0xc0, 0x6d, 0x7c, 0x48, 0xf9, 0x23, 0x83, 0x56, 0xfe,
+	0x30, 0xb0, 0x38, 0xa9, 0x43, 0xf4, 0x37, 0xad, 0x7f, 0x2c, 0x07, 0x1b,
+	0x5f, 0x6b, 0x02, 0x9a, 0xdb, 0x3c, 0x85, 0x94, 0xb9, 0x5b, 0x60, 0xbd,
+	0x89, 0x75, 0x5d, 0x26, 0xb1, 0x76, 0xc3, 0xd2, 0x42, 0x0c, 0x19, 0xe9,
+	0x09, 0x62, 0x06, 0x22, 0x3d, 0xd9, 0x00, 0xcb, 0x4e, 0x16, 0x60, 0x5e,
+	0x11, 0x02, 0xd6, 0x0f, 0x0c, 0xd0, 0x3a, 0xe6, 0x00, 0x78, 0x2c, 0xa1,
+	0x89, 0x01, 0x74, 0x07, 0x27, 0xd0, 0xfe, 0x7e, 0x65, 0xf0, 0xba, 0xe3,
+	0x06, 0x09, 0x88, 0xa1, 0x8b, 0x7a, 0x14, 0xe5, 0x41, 0x79, 0xd4, 0x49,
+	0x85, 0x81, 0xc4, 0xfc, 0x04, 0xf2, 0x1f, 0xd0, 0x1f, 0x20, 0x3f, 0x02,
+	0xf3, 0x93, 0x33, 0x50, 0x0e, 0xb4, 0x36, 0xaa, 0x79, 0x0d, 0x48, 0x1f,
+	0x28, 0x0c, 0x41, 0x65, 0x2a, 0x68, 0x8c, 0x03, 0xc8, 0x5e, 0x22, 0x04,
+	0x0d, 0x3b, 0x20, 0x0d, 0x64, 0x37, 0x4f, 0x11, 0x01, 0xf3, 0x93, 0x02,
+	0x84, 0x18, 0x1a, 0xe0, 0xf9, 0x89, 0x1d, 0xe8, 0x52, 0x98, 0x9b, 0xfe,
+	0xff, 0x3f, 0xa6, 0xc2, 0x02, 0x4c, 0x7b, 0xa0, 0xb5, 0xb5, 0xbf, 0xff,
+	0x1f, 0x10, 0x61, 0x61, 0x68, 0x81, 0xaf, 0xd1, 0x0b, 0x94, 0x07, 0x95,
+	0x73, 0x0b, 0x80, 0xac, 0x36, 0x78, 0xbd, 0x0d, 0x92, 0x07, 0x89, 0xfd,
+	0x02, 0x96, 0x2b, 0xff, 0xff, 0x2f, 0x85, 0xab, 0x05, 0x01, 0x00, 0xb3,
+	0x28, 0x79, 0xae, 0x58, 0x7d, 0x00, 0x00, 0x00 };
 
-static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = {
-	0x08002428, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c,
-	0x08002380, 0x0800245c, 0x080023e4, 0x0800245c, 0x0800231c, 0x0800245c,
-	0x0800245c, 0x0800245c, 0x08002328, 0x00000000, 0x08003240, 0x08003270,
-	0x080032a0, 0x080032d0, 0x08003300, 0x00000000, 0x00000000 };
-static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = {
+	0x08001c1c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c,
+	0x08001b74, 0x08001c4c, 0x08001bdc, 0x08001c4c, 0x08001b08, 0x08001c4c,
+	0x08001c4c, 0x08001c4c, 0x08001b14, 0x00000000, 0x08002b58, 0x08002ba8,
+	0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
+	0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
+	0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_com_fw_06 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
-	.start_addr			= 0x080008b4,
+	.start_addr			= 0x080000b4,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x57bc,
+	.text_len			= 0x7d54,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_COM_b06FwText,
 	.gz_text_len			= sizeof(bnx2_COM_b06FwText),
 
-	.data_addr			= 0x08005840,
+	.data_addr			= 0x08007e00,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_COM_b06FwData,
 
-	.sbss_addr			= 0x08005840,
-	.sbss_len			= 0x1c,
+	.sbss_addr			= 0x08007e00,
+	.sbss_len			= 0x60,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_COM_b06FwSbss,
 
-	.bss_addr			= 0x08005860,
+	.bss_addr			= 0x08007e60,
 	.bss_len			= 0x88,
 	.bss_index			= 0x0,
 	.bss				= bnx2_COM_b06FwBss,
 
-	.rodata_addr			= 0x080057c0,
-	.rodata_len			= 0x58,
+	.rodata_addr			= 0x08007d58,
+	.rodata_len			= 0x88,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_COM_b06FwRodata,
 };
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 680c769..2c06753 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -1,13 +1,13 @@
 /* bnx2_fw2.h: Broadcom NX2 network driver.
  *
- * Copyright (c) 2006 Broadcom Corporation
+ * Copyright (c) 2004, 2005, 2006, 2007 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, except as noted below.
  *
  * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2006 Broadcom Corporation.
+ * source code, Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation.
  *
  * Permission is hereby granted for the distribution of this firmware data
  * in hexadecimal or equivalent format, provided this copyright notice is
@@ -15,3289 +15,3260 @@
  */
 
 static u8 bnx2_COM_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0xac, 0xfb, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xdc, 0x5b, 0x6b, 0x70,
-	0x1b, 0xd7, 0x75, 0x3e, 0xfb, 0x00, 0x09, 0x91, 0x10, 0xb5, 0xa4, 0x60,
-	0x1a, 0x96, 0x68, 0x07, 0x20, 0x57, 0x22, 0x6a, 0xb1, 0x29, 0x4c, 0x33,
-	0x16, 0x9b, 0xc2, 0x12, 0x02, 0x50, 0xae, 0x26, 0xc3, 0x3a, 0x94, 0xcd,
-	0xd8, 0x4a, 0xaa, 0xc9, 0x30, 0x00, 0xa5, 0xf4, 0x61, 0xb7, 0x92, 0xab,
-	0xa9, 0x5d, 0xd7, 0xaa, 0x21, 0x92, 0x6a, 0xf5, 0x83, 0xe5, 0x2a, 0x16,
-	0x43, 0xa9, 0xd3, 0x74, 0xc2, 0x12, 0x56, 0xac, 0x4e, 0x31, 0x85, 0xfc,
-	0xd6, 0x38, 0xb1, 0xc9, 0x4a, 0x76, 0xeb, 0xf4, 0xe1, 0xa6, 0x33, 0xcd,
-	0xa3, 0x9d, 0x36, 0xf6, 0xa8, 0x3f, 0xea, 0xe9, 0xd3, 0x33, 0x6e, 0xa7,
-	0xea, 0xd8, 0x0e, 0xfa, 0x7d, 0x77, 0x77, 0x81, 0x25, 0x48, 0xbd, 0xfc,
-	0xc8, 0x8f, 0x70, 0x06, 0xb3, 0x7b, 0xef, 0xde, 0xbd, 0xf7, 0xdc, 0xf3,
-	0xf8, 0xce, 0x63, 0x2f, 0xfb, 0x44, 0x5a, 0xc4, 0xfb, 0x5b, 0x8b, 0x5f,
-	0xfc, 0xfe, 0x5f, 0x2d, 0x7c, 0x7c, 0xf0, 0xe3, 0xfd, 0x22, 0xb7, 0xdc,
-	0xa2, 0xb7, 0x86, 0x75, 0xf6, 0x1b, 0xf8, 0x45, 0xf1, 0xeb, 0xf7, 0xee,
-	0x57, 0xfb, 0xb3, 0xf0, 0x7b, 0x13, 0x0f, 0xc7, 0xfe, 0x55, 0x44, 0xbb,
-	0xc4, 0x98, 0xe0, 0x5f, 0xb5, 0x7a, 0xf9, 0xe7, 0x5c, 0x38, 0x7e, 0x89,
-	0x67, 0x86, 0xbb, 0x9c, 0xa2, 0x97, 0x3f, 0x09, 0xeb, 0x69, 0x39, 0x94,
-	0xb5, 0x25, 0x6c, 0xa4, 0xdf, 0x3c, 0x54, 0xb0, 0x45, 0x32, 0xe5, 0x2d,
-	0xf1, 0x9c, 0xbc, 0x57, 0x2d, 0x46, 0x4d, 0x61, 0xff, 0x8d, 0xe9, 0x77,
-	0xbf, 0xf6, 0xe2, 0xd6, 0xc4, 0x5b, 0xf3, 0x86, 0x84, 0xad, 0xf4, 0x19,
-	0xb1, 0x36, 0x4b, 0xb8, 0x0b, 0xef, 0x7c, 0xb5, 0xf7, 0x3d, 0x91, 0x36,
-	0x7f, 0xae, 0x37, 0xab, 0x2f, 0xf6, 0x4a, 0x71, 0x43, 0x3a, 0x2c, 0x7a,
-	0x7a, 0xd3, 0xf7, 0xb3, 0x86, 0x35, 0x66, 0xa4, 0x2d, 0x59, 0xac, 0xc8,
-	0xc8, 0xde, 0x69, 0x09, 0x87, 0xd3, 0x47, 0x9b, 0x9b, 0x37, 0x49, 0xd8,
-	0x4c, 0x8f, 0x1d, 0xfa, 0x6d, 0xfb, 0xd1, 0xaa, 0x6e, 0xdb, 0xc9, 0x05,
-	0x89, 0x0c, 0x9e, 0x1a, 0xc0, 0xf3, 0x72, 0x22, 0x29, 0xb2, 0x55, 0x74,
-	0xbb, 0x18, 0x31, 0xec, 0xb0, 0x64, 0x2b, 0xb6, 0xe4, 0x2a, 0x22, 0x7f,
-	0x5e, 0xd6, 0xe4, 0x94, 0xdd, 0x29, 0x0b, 0x7d, 0xef, 0x56, 0x33, 0xa0,
-	0xe5, 0xcf, 0xec, 0xb1, 0x43, 0x53, 0x36, 0xe9, 0x9d, 0x6d, 0x76, 0xe9,
-	0x9d, 0x6a, 0x2a, 0xd8, 0xa6, 0x4c, 0x94, 0xd9, 0x37, 0xa2, 0xb3, 0x2f,
-	0x94, 0x7e, 0x68, 0xcd, 0x29, 0x3b, 0xe2, 0xf5, 0xed, 0xdc, 0x9e, 0xc5,
-	0x7c, 0x93, 0x65, 0x8e, 0x3d, 0x93, 0x2a, 0xd8, 0x51, 0xaf, 0x3f, 0x79,
-	0x5b, 0xd6, 0x8e, 0xa1, 0xbf, 0xcb, 0x7b, 0x76, 0xf2, 0xbe, 0x82, 0x6d,
-	0x7b, 0xcf, 0xbe, 0x8a, 0xb9, 0x93, 0x5e, 0xff, 0x7d, 0xdb, 0x0a, 0x76,
-	0x9f, 0xd7, 0x3f, 0xbd, 0x2d, 0x6b, 0xa7, 0xbc, 0xfe, 0xe4, 0xee, 0x82,
-	0x3d, 0xe0, 0xf5, 0x9f, 0xbd, 0x3d, 0x6b, 0x0f, 0x7a, 0xfd, 0x0f, 0x6d,
-	0x2d, 0xd8, 0x69, 0xf4, 0x1f, 0x6d, 0xd6, 0x37, 0x59, 0x72, 0xa4, 0x1c,
-	0xc7, 0x2f, 0x83, 0x67, 0x43, 0xe8, 0xdb, 0x89, 0xdf, 0x30, 0x7e, 0xbf,
-	0xb8, 0x4e, 0xda, 0x46, 0x70, 0xfd, 0xc6, 0x46, 0x97, 0x77, 0xe0, 0x91,
-	0x13, 0x96, 0x37, 0x8c, 0x98, 0xbc, 0xd8, 0xfb, 0x06, 0x78, 0x68, 0xc9,
-	0x99, 0x8a, 0x68, 0x23, 0xbd, 0x31, 0xf0, 0x2e, 0x2a, 0x4f, 0x56, 0x5a,
-	0xc5, 0x78, 0xcc, 0x00, 0x6f, 0x3e, 0x2f, 0xf9, 0x68, 0x58, 0xda, 0xe7,
-	0x34, 0xe9, 0xee, 0x0f, 0x4b, 0xc6, 0x52, 0x72, 0x13, 0x7d, 0x26, 0x2a,
-	0xc6, 0x5c, 0x66, 0xbd, 0x2e, 0x9b, 0xac, 0x9c, 0x14, 0xc1, 0xbb, 0xef,
-	0x51, 0x27, 0xf1, 0x2c, 0x2e, 0xb9, 0xe9, 0x9b, 0x65, 0xcc, 0x22, 0x5d,
-	0x3b, 0x6f, 0x74, 0xd7, 0x0a, 0x6b, 0xd9, 0x13, 0x23, 0x72, 0xc4, 0x89,
-	0x68, 0xb9, 0x13, 0xdb, 0x24, 0x9b, 0x92, 0x28, 0xde, 0x8b, 0xe5, 0xf1,
-	0xa4, 0x54, 0x1e, 0x91, 0x29, 0x47, 0xb4, 0xac, 0x43, 0x7e, 0x76, 0xe2,
-	0x79, 0x9b, 0x1a, 0x8b, 0xbe, 0x2e, 0x43, 0xcd, 0x1d, 0x46, 0xbf, 0x85,
-	0xfe, 0x0e, 0x6d, 0x48, 0xcd, 0xa1, 0xfa, 0xe3, 0x93, 0x12, 0x91, 0xc7,
-	0xcb, 0x51, 0x6f, 0x6c, 0xb5, 0x9a, 0x4d, 0x59, 0x18, 0x37, 0x22, 0x93,
-	0x4e, 0x54, 0xc6, 0x70, 0x9d, 0x70, 0xb8, 0x7e, 0x0c, 0x3a, 0xf5, 0xda,
-	0xa1, 0xfc, 0xac, 0x9a, 0x2f, 0x6e, 0xa4, 0x39, 0x5f, 0x17, 0xc6, 0x4d,
-	0x80, 0x2e, 0x4d, 0x4c, 0x25, 0xcb, 0x8c, 0xe4, 0xa7, 0x35, 0xe8, 0x1b,
-	0xae, 0x8a, 0xaf, 0x43, 0xa0, 0xdf, 0x14, 0xbb, 0x5f, 0x93, 0x02, 0x64,
-	0x55, 0xb4, 0xd0, 0x2e, 0x9f, 0xd5, 0xb3, 0x4e, 0xb3, 0xe4, 0xcc, 0xb8,
-	0x18, 0x33, 0x4a, 0x97, 0x64, 0x12, 0xef, 0xe8, 0x36, 0xc7, 0x5c, 0xc4,
-	0xbe, 0xc7, 0x94, 0x1c, 0x9a, 0xd2, 0x45, 0x3d, 0x57, 0xe9, 0x14, 0x7d,
-	0x6e, 0x8f, 0xbc, 0x3c, 0x2d, 0x96, 0x91, 0x7e, 0xb7, 0x9a, 0xb5, 0xa7,
-	0xf4, 0xec, 0x13, 0xa6, 0x84, 0x66, 0x34, 0x99, 0xb2, 0x13, 0xb0, 0x80,
-	0xa3, 0xfa, 0x8e, 0xca, 0x59, 0x8c, 0xe3, 0x7b, 0x18, 0x57, 0xd6, 0xc1,
-	0x57, 0xde, 0x6f, 0xb1, 0x74, 0xa5, 0xcf, 0x1c, 0x03, 0x19, 0x60, 0x1f,
-	0x4f, 0x3a, 0x90, 0x89, 0x92, 0x51, 0x1c, 0x32, 0x7a, 0x15, 0x32, 0x1a,
-	0x80, 0x6c, 0x52, 0xf2, 0x52, 0xa5, 0x4f, 0x9e, 0xaf, 0x24, 0xe5, 0x39,
-	0xe8, 0xeb, 0xb3, 0x95, 0xb8, 0x3c, 0x53, 0xe9, 0x92, 0xa7, 0x2b, 0x31,
-	0x79, 0x4a, 0xc9, 0x2d, 0x07, 0xdb, 0x50, 0xb2, 0x0c, 0x5f, 0x9f, 0x96,
-	0x70, 0x27, 0xe4, 0xd1, 0x01, 0xfd, 0x69, 0x87, 0x6e, 0x7e, 0xa5, 0x37,
-	0x2c, 0xb3, 0xbd, 0x92, 0x59, 0x8f, 0xfe, 0x9b, 0xd2, 0xa6, 0xe2, 0x91,
-	0x89, 0xe7, 0x93, 0xd3, 0x21, 0xc9, 0x59, 0x8f, 0xcb, 0x85, 0x19, 0x53,
-	0x26, 0x2b, 0xdb, 0x6f, 0x72, 0x65, 0xc6, 0xf6, 0xbc, 0x9c, 0x9f, 0x69,
-	0xc2, 0xb3, 0x79, 0x79, 0x79, 0xb3, 0x2e, 0x13, 0xb3, 0x6f, 0x89, 0x09,
-	0x1e, 0x0e, 0x29, 0x79, 0x3f, 0x2e, 0xff, 0xfc, 0x27, 0x22, 0x23, 0xe0,
-	0x8b, 0xde, 0xff, 0xef, 0xd5, 0x8c, 0x05, 0x7e, 0xf4, 0xf7, 0x41, 0x3f,
-	0x74, 0x5c, 0x29, 0xcf, 0x38, 0xc6, 0x98, 0x5a, 0xce, 0x39, 0x0d, 0x9b,
-	0x6a, 0xd5, 0xb2, 0xc7, 0x45, 0x0a, 0xc7, 0xab, 0x52, 0x48, 0x85, 0xe4,
-	0x01, 0xab, 0x2a, 0x43, 0xa9, 0x26, 0x39, 0x60, 0x75, 0xca, 0x44, 0xdf,
-	0xcf, 0x68, 0x3e, 0x96, 0x7d, 0xa5, 0x92, 0xc6, 0x3d, 0xfb, 0x44, 0x66,
-	0xd5, 0xbd, 0xdb, 0x5f, 0xac, 0x84, 0x24, 0x13, 0x2d, 0xc6, 0x4c, 0xb9,
-	0xa0, 0xb9, 0xb4, 0xed, 0xf4, 0x9f, 0x41, 0x5e, 0x63, 0xc0, 0x90, 0x84,
-	0xd2, 0xa5, 0xfc, 0xf4, 0x9a, 0x8b, 0x19, 0xd5, 0x1d, 0x52, 0x7a, 0x6a,
-	0xa4, 0x4d, 0xd2, 0x31, 0xa6, 0xa5, 0xa3, 0xd2, 0xad, 0xec, 0x64, 0x00,
-	0x63, 0x06, 0xb5, 0xbb, 0x2b, 0x94, 0x37, 0xee, 0xcb, 0xa4, 0x75, 0x03,
-	0xc6, 0x9a, 0xb8, 0x66, 0x3c, 0x9a, 0x83, 0x74, 0x72, 0x2e, 0xd2, 0xc9,
-	0xeb, 0xde, 0x00, 0x9d, 0xfb, 0x6a, 0xf7, 0xb3, 0x81, 0xfb, 0x62, 0xe5,
-	0xd7, 0x5b, 0x5c, 0xfa, 0xc8, 0xd7, 0x41, 0x99, 0x98, 0x7e, 0xc8, 0x5b,
-	0x0b, 0xf7, 0x65, 0xae, 0xb1, 0x00, 0x3e, 0xa9, 0x91, 0x57, 0x58, 0xab,
-	0x18, 0x58, 0xeb, 0x70, 0x60, 0xad, 0xc3, 0x81, 0xb5, 0x8a, 0xe0, 0xad,
-	0xac, 0xd3, 0x81, 0x33, 0x79, 0xc2, 0xbc, 0x1c, 0xc5, 0x9c, 0x6f, 0x88,
-	0x91, 0xa6, 0x2d, 0xf8, 0x36, 0xf9, 0x07, 0x18, 0x9f, 0x96, 0x73, 0x0e,
-	0x78, 0x73, 0x3c, 0x24, 0x77, 0xa9, 0x71, 0xff, 0xb1, 0xc6, 0xa5, 0x31,
-	0xf8, 0x2c, 0x2c, 0xbb, 0xa2, 0xbc, 0xf7, 0x9f, 0x99, 0xe0, 0x37, 0xdb,
-	0x93, 0x37, 0xb8, 0x6d, 0xde, 0x9f, 0xf5, 0xf6, 0xd2, 0xee, 0xbe, 0x57,
-	0x79, 0x53, 0x61, 0xc6, 0x62, 0x85, 0xb6, 0x2d, 0x29, 0xc3, 0x96, 0xfd,
-	0x43, 0xa9, 0x4e, 0x99, 0xb4, 0xb4, 0xd4, 0x44, 0xb2, 0x99, 0xfc, 0xcf,
-	0xe8, 0x76, 0x2b, 0xec, 0x47, 0xe2, 0x3a, 0x71, 0x51, 0xed, 0xeb, 0x5b,
-	0x1e, 0xfd, 0x16, 0xdb, 0x23, 0xba, 0xdd, 0xd1, 0xd0, 0x4f, 0xfd, 0xff,
-	0x4b, 0xdc, 0xd3, 0x06, 0xfa, 0x75, 0x77, 0xed, 0xbf, 0x42, 0x9b, 0x58,
-	0x15, 0xf1, 0xda, 0xfe, 0xf3, 0xff, 0x32, 0x96, 0xb7, 0x8f, 0x6d, 0x5c,
-	0xde, 0xf6, 0x6d, 0x29, 0x88, 0x73, 0xdc, 0x2b, 0x6c, 0xd8, 0xa6, 0xfe,
-	0x85, 0x40, 0x6b, 0x0a, 0x36, 0xdc, 0xec, 0xd1, 0xf0, 0xba, 0x47, 0x03,
-	0x68, 0xc5, 0xb8, 0x89, 0x0a, 0xdf, 0x51, 0xa2, 0x6c, 0x68, 0x93, 0xf7,
-	0xfe, 0xfd, 0x5a, 0xf5, 0xfc, 0x0d, 0x83, 0xeb, 0xf8, 0x57, 0xd1, 0x86,
-	0x60, 0x67, 0x93, 0xb3, 0xa6, 0xe4, 0x53, 0x31, 0x65, 0x0f, 0xf9, 0x54,
-	0x1d, 0x3f, 0x26, 0xa7, 0x1b, 0xf1, 0x83, 0xef, 0x11, 0x3f, 0x5c, 0xec,
-	0x98, 0x98, 0x25, 0x8e, 0xd4, 0x71, 0xe3, 0xc8, 0xb4, 0x8f, 0x25, 0x9c,
-	0x9b, 0x18, 0xe2, 0xe3, 0x07, 0xdf, 0x23, 0x7e, 0x18, 0x90, 0x15, 0xe7,
-	0xf4, 0xd7, 0x9f, 0x6a, 0x98, 0x7b, 0x4a, 0x61, 0x93, 0x8b, 0xcb, 0x6f,
-	0x06, 0x70, 0xbe, 0x0b, 0x18, 0x1d, 0x85, 0xfc, 0x7c, 0x8c, 0x26, 0x76,
-	0xc6, 0x80, 0xeb, 0xe0, 0x91, 0xc2, 0xe4, 0x08, 0x70, 0xcc, 0xf4, 0x30,
-	0x35, 0xec, 0x61, 0x6a, 0x04, 0x78, 0xca, 0xb6, 0xe5, 0xb5, 0xa3, 0x5e,
-	0x3b, 0x86, 0x36, 0xfc, 0xef, 0x1c, 0x6d, 0xec, 0xb5, 0x43, 0xe3, 0xb3,
-	0x0a, 0xa7, 0x89, 0xf1, 0xc0, 0x0a, 0xe2, 0x2c, 0xf1, 0xb6, 0x4b, 0x16,
-	0xca, 0x58, 0xaf, 0x86, 0x69, 0x94, 0x47, 0x90, 0x1e, 0xd2, 0xb2, 0x46,
-	0xf4, 0xc7, 0xdc, 0xfd, 0xe8, 0xe9, 0xcf, 0xeb, 0xd2, 0xc2, 0x7d, 0x90,
-	0xee, 0x1b, 0x41, 0x2b, 0xf7, 0xf6, 0xa3, 0xa4, 0x95, 0xeb, 0x35, 0xd2,
-	0x7b, 0x1a, 0xf4, 0x66, 0x80, 0xb7, 0xa2, 0x8d, 0xf6, 0x8e, 0x82, 0xde,
-	0x11, 0x60, 0xf1, 0x30, 0xb0, 0x78, 0x27, 0xb0, 0x78, 0x08, 0x58, 0x9c,
-	0x06, 0x0e, 0x0f, 0x02, 0x87, 0x07, 0x80, 0xc3, 0x29, 0xec, 0x2b, 0x2a,
-	0xf3, 0xc0, 0xe5, 0x79, 0xe0, 0xf3, 0x3c, 0xe4, 0x35, 0x31, 0x27, 0xda,
-	0x17, 0xb0, 0xfe, 0x63, 0x33, 0x89, 0xd3, 0xd0, 0xcd, 0x58, 0x51, 0x87,
-	0x3d, 0xa5, 0x06, 0xa1, 0x23, 0x49, 0x29, 0x55, 0x46, 0xa5, 0x40, 0x3f,
-	0xb6, 0xb9, 0x07, 0xb6, 0x0b, 0xfb, 0x89, 0xf9, 0x71, 0xd3, 0x5a, 0xef,
-	0xfa, 0xf7, 0x22, 0xf6, 0x1f, 0x83, 0x27, 0x89, 0xb8, 0xc8, 0xb0, 0xe4,
-	0x9d, 0x1e, 0x2b, 0xab, 0x27, 0x31, 0x8e, 0xed, 0xb8, 0xb6, 0xf7, 0x78,
-	0x42, 0x1b, 0x3f, 0xce, 0x3d, 0x4d, 0x03, 0xe3, 0xaa, 0x32, 0x95, 0xa2,
-	0xad, 0x56, 0xe5, 0x54, 0x2a, 0x31, 0x58, 0x94, 0x56, 0x39, 0x12, 0x9d,
-	0x56, 0xfe, 0xcd, 0x4c, 0x1f, 0x53, 0xfa, 0x51, 0xb0, 0x71, 0x2d, 0x77,
-	0x6b, 0xf9, 0xe3, 0xf4, 0x3b, 0x3d, 0xf8, 0x85, 0x40, 0x0b, 0xe7, 0x37,
-	0x65, 0x68, 0x40, 0xb4, 0x7d, 0xbd, 0x45, 0xa0, 0x62, 0xc2, 0x3a, 0x87,
-	0x95, 0x73, 0xd3, 0x3d, 0xb1, 0x9c, 0x6e, 0xca, 0x98, 0xa9, 0xc9, 0x04,
-	0xec, 0x65, 0x28, 0xf5, 0x7f, 0xd5, 0x23, 0x51, 0x3e, 0x6f, 0x96, 0xdf,
-	0x51, 0x38, 0x8b, 0xb5, 0x4b, 0xb3, 0x58, 0x37, 0x04, 0xfe, 0x71, 0x5d,
-	0xce, 0x83, 0x36, 0x30, 0xcf, 0xb4, 0x13, 0xa7, 0x8b, 0xb2, 0x1d, 0x76,
-	0xb7, 0x4e, 0xb2, 0x7d, 0x4d, 0x92, 0x19, 0x89, 0xcb, 0xc4, 0xcc, 0x76,
-	0xe0, 0x1e, 0x64, 0x60, 0xb7, 0x48, 0x7e, 0x34, 0x2e, 0x5f, 0x9e, 0x61,
-	0x5f, 0x06, 0xfb, 0x4f, 0x1c, 0xcd, 0x08, 0xf7, 0x1f, 0x52, 0xfb, 0x8a,
-	0xeb, 0x19, 0x39, 0xe0, 0xbc, 0xa4, 0xbb, 0x76, 0xe9, 0xb6, 0xf7, 0x42,
-	0x1e, 0xa7, 0xc0, 0xef, 0xbc, 0x63, 0xcb, 0x02, 0xfc, 0x4a, 0xee, 0x38,
-	0x70, 0xd5, 0x6e, 0x03, 0x06, 0x26, 0xce, 0xd2, 0x3e, 0x0c, 0xc4, 0x5a,
-	0x25, 0xc5, 0xeb, 0x2e, 0x39, 0x3e, 0xa3, 0xcb, 0xb3, 0xb7, 0xc5, 0xd1,
-	0x06, 0xd6, 0xa6, 0x12, 0x67, 0xc6, 0xf4, 0x2e, 0xb9, 0xb5, 0x23, 0x86,
-	0xf7, 0x52, 0x5a, 0xde, 0xf9, 0x37, 0xf2, 0xf2, 0x64, 0x5c, 0xe7, 0x58,
-	0x5d, 0x72, 0x29, 0x03, 0x3a, 0x56, 0xc4, 0xf8, 0x7f, 0x40, 0x7f, 0x97,
-	0xcc, 0x21, 0xbe, 0x99, 0x03, 0x4d, 0xd9, 0x14, 0xb1, 0x30, 0x71, 0x72,
-	0x49, 0x07, 0x66, 0xcd, 0x41, 0x37, 0x47, 0x11, 0x3f, 0xcc, 0xfc, 0x37,
-	0xc6, 0xc4, 0x21, 0xd3, 0x1e, 0x6b, 0x02, 0xf8, 0x92, 0xe9, 0xe2, 0x3d,
-	0xe7, 0xb4, 0xe5, 0x94, 0x43, 0x1d, 0x8a, 0xcb, 0xe3, 0x15, 0xbe, 0xd7,
-	0x73, 0xf6, 0x69, 0xb1, 0xe5, 0x41, 0xe7, 0x7f, 0x30, 0xfe, 0x1d, 0xc4,
-	0x9e, 0x96, 0x94, 0x20, 0xb7, 0x02, 0x78, 0x99, 0x89, 0xb9, 0xed, 0x89,
-	0xb9, 0xc4, 0xd9, 0x0b, 0x3a, 0xef, 0xed, 0xe2, 0x82, 0x7e, 0xb3, 0x48,
-	0x07, 0xf9, 0x99, 0x02, 0x2f, 0x6d, 0x4b, 0xd7, 0x37, 0x7b, 0xf1, 0x16,
-	0x6d, 0xc0, 0x06, 0x7d, 0xa6, 0x2c, 0xf4, 0x07, 0x6d, 0x80, 0x7e, 0xd6,
-	0xb7, 0x81, 0x44, 0x6c, 0x49, 0xd7, 0xf1, 0xdc, 0x94, 0x63, 0xaa, 0xad,
-	0x81, 0xd6, 0x44, 0x8c, 0xfb, 0x9b, 0x2c, 0x27, 0xe5, 0x71, 0x87, 0xe3,
-	0xc1, 0xe7, 0xe9, 0x88, 0x37, 0x1e, 0xf1, 0x8e, 0xc3, 0x98, 0x29, 0x09,
-	0x9a, 0x5d, 0xbb, 0x58, 0x98, 0x8e, 0xaa, 0x67, 0x47, 0x1c, 0x37, 0x36,
-	0xd2, 0x11, 0x3f, 0xcd, 0x23, 0x7e, 0xca, 0x29, 0x1b, 0xb1, 0x32, 0x88,
-	0xaf, 0xe1, 0x67, 0x5d, 0xfb, 0x28, 0x95, 0x49, 0xcb, 0x3d, 0xa0, 0x2f,
-	0x51, 0x04, 0x31, 0xc7, 0x74, 0xb8, 0xeb, 0xec, 0x80, 0x14, 0x19, 0x63,
-	0x9d, 0x33, 0x1e, 0x91, 0xb1, 0x12, 0xfd, 0x1b, 0x7e, 0x8e, 0x6d, 0x31,
-	0xa6, 0xcf, 0x28, 0xdf, 0xd3, 0x03, 0x3d, 0x80, 0x5f, 0x4a, 0xb5, 0x8b,
-	0xeb, 0x07, 0xf7, 0x40, 0x9e, 0xc3, 0x90, 0x7b, 0x5a, 0xc6, 0x4f, 0x8c,
-	0x53, 0xa7, 0x93, 0x25, 0x49, 0x24, 0x8f, 0xc8, 0x16, 0x6b, 0x01, 0xbe,
-	0x30, 0x33, 0x5a, 0xdd, 0xae, 0xa7, 0xf9, 0xce, 0xa3, 0x78, 0x07, 0xd7,
-	0xd2, 0xb8, 0x3c, 0x50, 0x61, 0xdf, 0x9d, 0x86, 0xb4, 0xc0, 0x56, 0x06,
-	0xf6, 0x78, 0x76, 0x80, 0xf9, 0x4c, 0x7f, 0xbe, 0x71, 0x6f, 0x3e, 0x8e,
-	0xe3, 0x18, 0xbe, 0x53, 0x9f, 0x77, 0x07, 0x7d, 0x1b, 0xb0, 0x64, 0x87,
-	0x5e, 0xdd, 0x1e, 0xc2, 0xf3, 0x53, 0x03, 0xbc, 0xc7, 0x3c, 0xf0, 0x6d,
-	0x96, 0x3d, 0x8c, 0xb1, 0xa3, 0x98, 0x73, 0x8d, 0x64, 0x3b, 0x7d, 0x7a,
-	0xa9, 0x03, 0x8c, 0x3f, 0xd8, 0x8e, 0xae, 0x77, 0x79, 0xff, 0x25, 0xc3,
-	0xd5, 0xc9, 0x11, 0xb4, 0x69, 0x7f, 0x07, 0x25, 0xe7, 0x24, 0xb0, 0x4f,
-	0xf0, 0xb6, 0x32, 0xe1, 0xed, 0x11, 0xfc, 0x1f, 0x39, 0x0c, 0x3e, 0x48,
-	0xd1, 0xe5, 0x0d, 0xf9, 0x42, 0x9e, 0xfc, 0x16, 0x74, 0xff, 0x61, 0x8c,
-	0x81, 0x7f, 0x50, 0x3c, 0x58, 0xea, 0x70, 0x63, 0xd1, 0x44, 0x31, 0xc3,
-	0xfc, 0xa9, 0x83, 0x98, 0x07, 0xfc, 0xa9, 0x40, 0xb1, 0x30, 0xf7, 0x92,
-	0xbe, 0x86, 0xf4, 0xc6, 0x97, 0x0c, 0x83, 0xed, 0xe4, 0x12, 0x74, 0xb8,
-	0x04, 0xf9, 0x64, 0xfb, 0x68, 0xb3, 0x36, 0xe4, 0x31, 0x63, 0x50, 0x5f,
-	0x4b, 0x88, 0x05, 0xf3, 0xce, 0x16, 0xeb, 0x5e, 0xf2, 0xcd, 0xb2, 0xe4,
-	0x69, 0x27, 0x88, 0x1d, 0x3b, 0x30, 0x94, 0x7a, 0x18, 0x85, 0x1e, 0x98,
-	0xf0, 0xc9, 0x31, 0xc8, 0xfc, 0xc5, 0x0e, 0x77, 0x2f, 0xbc, 0x37, 0x65,
-	0xde, 0xc2, 0x9a, 0xce, 0xef, 0xaf, 0x73, 0xfb, 0x78, 0xcf, 0xb8, 0xc8,
-	0x97, 0xab, 0x4f, 0x3b, 0xe5, 0xdb, 0x28, 0xd3, 0x43, 0xd8, 0x0b, 0xfb,
-	0x71, 0x2d, 0x1d, 0x94, 0x71, 0xd0, 0x56, 0x18, 0xd8, 0x14, 0x3b, 0x8f,
-	0xf1, 0x39, 0xe0, 0x79, 0xd1, 0xe4, 0xb3, 0x8b, 0x5a, 0xfd, 0x1d, 0xc4,
-	0x5c, 0x36, 0xfd, 0xd9, 0x92, 0xf6, 0x85, 0xca, 0xcb, 0x5a, 0xb6, 0x74,
-	0x51, 0xcb, 0x41, 0x4f, 0x4a, 0x0e, 0x73, 0x06, 0xda, 0x8f, 0x85, 0xb5,
-	0x13, 0xb1, 0xb7, 0xf5, 0x9e, 0xf8, 0x02, 0xb0, 0x60, 0x2f, 0x6c, 0x3a,
-	0x67, 0xee, 0x94, 0x02, 0xb0, 0x35, 0x7f, 0x62, 0x0b, 0xec, 0x2d, 0x1e,
-	0xa0, 0x8b, 0x78, 0x56, 0xa4, 0x4f, 0xd5, 0x76, 0x38, 0x52, 0x6c, 0x4a,
-	0x13, 0xd7, 0x36, 0x41, 0x77, 0xd0, 0x57, 0xae, 0xeb, 0xdf, 0x1d, 0x2b,
-	0x68, 0x45, 0x7e, 0x39, 0xb0, 0x9c, 0xde, 0x92, 0x5c, 0x99, 0xde, 0x1d,
-	0x35, 0x7a, 0x89, 0x19, 0xc0, 0x7f, 0xd8, 0xcd, 0x4b, 0xd0, 0xdf, 0xe7,
-	0x1d, 0xe0, 0xbf, 0x03, 0xfc, 0x87, 0x4d, 0x3d, 0x03, 0xdd, 0x7b, 0xda,
-	0x81, 0x0f, 0x70, 0xe0, 0x03, 0x1c, 0xf8, 0x00, 0x27, 0x0b, 0x39, 0x11,
-	0xe7, 0xe9, 0x43, 0x76, 0xd7, 0x7c, 0x9e, 0x1b, 0x37, 0xdd, 0xe0, 0xc5,
-	0x22, 0xa3, 0x88, 0x45, 0x36, 0xc8, 0x44, 0xf2, 0x7a, 0xec, 0xad, 0x05,
-	0xd7, 0x56, 0x5c, 0xb1, 0x46, 0xf2, 0x76, 0xcf, 0x4e, 0x1e, 0x06, 0x5d,
-	0x88, 0xbf, 0x93, 0x3f, 0x0d, 0x3d, 0x6c, 0x02, 0x3d, 0x3f, 0xe5, 0xc5,
-	0x2c, 0x0f, 0x9a, 0xae, 0x1e, 0xb6, 0xa2, 0xef, 0x93, 0xe8, 0x6b, 0xc5,
-	0x98, 0x03, 0x18, 0xc3, 0x98, 0xa7, 0xcd, 0xeb, 0x0b, 0x8e, 0x63, 0xec,
-	0xf3, 0x19, 0xac, 0x95, 0xc0, 0xb8, 0x36, 0xcc, 0xdd, 0x85, 0x31, 0xdb,
-	0x30, 0xe6, 0x46, 0xb4, 0x19, 0x33, 0x6f, 0x44, 0xfb, 0x13, 0x0d, 0xef,
-	0x7c, 0x0c, 0x7d, 0xb7, 0x37, 0xf4, 0x9d, 0x43, 0x1f, 0xf2, 0x50, 0xeb,
-	0xbc, 0xf7, 0x5e, 0x11, 0xed, 0xce, 0x86, 0x31, 0xaf, 0xa2, 0x0f, 0x71,
-	0xaf, 0xf5, 0x2d, 0x5c, 0x91, 0x7f, 0x5a, 0xa4, 0xc9, 0x7f, 0xc6, 0xb8,
-	0x37, 0x8e, 0xfe, 0x90, 0x17, 0xbb, 0xfe, 0xa6, 0x09, 0xbd, 0xd3, 0x86,
-	0x9c, 0xdf, 0x30, 0xdd, 0x58, 0xef, 0x4e, 0xcb, 0xd5, 0x43, 0xbf, 0xfd,
-	0x70, 0x43, 0x9b, 0x63, 0x17, 0x1a, 0xfa, 0xfe, 0xa5, 0xa1, 0xfd, 0xdd,
-	0xd0, 0xca, 0x77, 0x06, 0xdb, 0x97, 0xf7, 0x15, 0x3a, 0x96, 0xb7, 0xed,
-	0xa6, 0x95, 0xef, 0xe8, 0xeb, 0x96, 0xf7, 0xdd, 0xb8, 0xbe, 0x61, 0x0c,
-	0x74, 0x2a, 0x8a, 0x1c, 0xc9, 0x1f, 0x1f, 0xbe, 0xce, 0x7d, 0x4e, 0xfe,
-	0x36, 0xea, 0x92, 0xda, 0x3a, 0xda, 0x3a, 0xe4, 0xb0, 0xa4, 0xc1, 0x9e,
-	0x2c, 0x3d, 0xfd, 0xb2, 0x96, 0x83, 0x4e, 0x65, 0x2b, 0xfe, 0x7c, 0xb4,
-	0xd9, 0xc6, 0xdc, 0xdc, 0xcf, 0xc9, 0x19, 0x2b, 0x45, 0xa0, 0x37, 0xf7,
-	0xd0, 0x27, 0x1d, 0x2d, 0x4a, 0xdd, 0x3e, 0xbb, 0xf5, 0x4b, 0xd9, 0xe7,
-	0xed, 0x1e, 0x46, 0x1d, 0x06, 0x9d, 0x55, 0x19, 0x49, 0x35, 0xd3, 0xc7,
-	0x78, 0xd8, 0x45, 0xdc, 0xa9, 0x56, 0x8d, 0xcd, 0x55, 0xd9, 0x9f, 0x7a,
-	0xa7, 0x2a, 0x0a, 0xf3, 0x06, 0x15, 0xee, 0xc4, 0xf5, 0x1e, 0xc8, 0xc8,
-	0x42, 0x6e, 0x82, 0x7c, 0x3a, 0x4a, 0x9f, 0x74, 0x90, 0xf1, 0xc9, 0xa3,
-	0x2e, 0xa6, 0x12, 0x77, 0xd0, 0x46, 0x5e, 0x96, 0x3f, 0xce, 0xf5, 0x71,
-	0x2d, 0x11, 0xc7, 0x47, 0x95, 0x4f, 0xc9, 0x5b, 0x9c, 0x77, 0x35, 0x6c,
-	0x3c, 0x6b, 0x32, 0xa6, 0x33, 0xed, 0xd3, 0xf0, 0x6f, 0x7c, 0xc6, 0x58,
-	0xe1, 0x34, 0xe3, 0x92, 0x00, 0x56, 0x6d, 0x35, 0xe0, 0x32, 0x8b, 0xcb,
-	0xf7, 0xb5, 0x81, 0x79, 0xc4, 0x55, 0xec, 0x75, 0x75, 0x2c, 0xea, 0xd1,
-	0xaf, 0x6c, 0xdb, 0xbb, 0x6a, 0xb6, 0xed, 0xeb, 0xde, 0x6a, 0x39, 0xf8,
-	0xf7, 0x95, 0x2c, 0x9e, 0xaa, 0x24, 0x8e, 0x15, 0x61, 0x4b, 0x8b, 0x2a,
-	0xef, 0xf6, 0xe5, 0xc2, 0x18, 0x27, 0x71, 0x72, 0x1e, 0x6f, 0x8e, 0xab,
-	0x1c, 0x83, 0xf9, 0x45, 0x55, 0x76, 0xa4, 0x5a, 0xa3, 0xe4, 0x43, 0x46,
-	0xff, 0x76, 0x88, 0x31, 0xc3, 0xa2, 0x43, 0x9e, 0xa5, 0xf0, 0x3c, 0x05,
-	0x4c, 0xf8, 0x27, 0xc9, 0x45, 0xd9, 0xf7, 0x76, 0x75, 0x01, 0x71, 0x95,
-	0x8a, 0x8f, 0x94, 0xbf, 0x67, 0x7c, 0xb7, 0x1f, 0xfc, 0x22, 0x4f, 0x47,
-	0xc0, 0x67, 0x3f, 0x06, 0x78, 0x8d, 0x75, 0x15, 0x59, 0x1e, 0x07, 0x8b,
-	0x3c, 0x50, 0x7e, 0x19, 0x73, 0xea, 0x6e, 0xac, 0xc2, 0x3c, 0xdc, 0x66,
-	0x7f, 0x47, 0x88, 0xb1, 0x9c, 0xeb, 0xeb, 0x0d, 0xac, 0x87, 0xdc, 0xbe,
-	0xfc, 0x8f, 0x2a, 0x6e, 0x2a, 0x28, 0x79, 0x20, 0x86, 0xaa, 0xf0, 0x19,
-	0xfb, 0xc2, 0x5e, 0xec, 0x1c, 0xf1, 0x62, 0x65, 0xcb, 0x8b, 0x95, 0x49,
-	0x07, 0x6b, 0x6f, 0x7e, 0x5c, 0x40, 0x99, 0x2d, 0x1d, 0xd2, 0x37, 0x33,
-	0x2e, 0x68, 0x93, 0xd5, 0xe3, 0x02, 0x9f, 0xa6, 0x6d, 0xa0, 0x89, 0x71,
-	0x9e, 0xaa, 0xbd, 0x74, 0xb8, 0xf5, 0x1e, 0xd2, 0xe0, 0xfb, 0x47, 0xe5,
-	0x87, 0x8f, 0xc2, 0xe5, 0x61, 0x6f, 0x69, 0xd0, 0xba, 0x53, 0xb2, 0xd3,
-	0xdb, 0x3c, 0x7f, 0xcb, 0x1c, 0x80, 0xf1, 0xb7, 0xab, 0xb3, 0xd9, 0xd4,
-	0x84, 0x3f, 0x4f, 0x27, 0x3c, 0x64, 0xa0, 0x2e, 0xc4, 0xb5, 0x18, 0xc7,
-	0xf8, 0x31, 0xcd, 0x4e, 0x2f, 0xa6, 0x19, 0x96, 0xfd, 0x8e, 0x1b, 0xf3,
-	0x8f, 0xa0, 0x3f, 0xef, 0x28, 0xda, 0x63, 0x8c, 0x2d, 0x75, 0xc4, 0xdc,
-	0x99, 0x3d, 0x09, 0x24, 0x0f, 0xee, 0x5e, 0xba, 0xb1, 0x97, 0x52, 0x6d,
-	0x2f, 0xad, 0x4b, 0xcb, 0xf7, 0x32, 0xaa, 0xde, 0x9d, 0x5a, 0xf1, 0xae,
-	0x60, 0x1f, 0xbb, 0x2f, 0xf1, 0x8c, 0x7b, 0x64, 0xdc, 0x60, 0x79, 0x7b,
-	0xf4, 0xe5, 0x74, 0x00, 0x7b, 0x4c, 0x6a, 0x79, 0x15, 0x6b, 0xed, 0x51,
-	0x3c, 0xcf, 0x97, 0xc7, 0x70, 0xa5, 0x7d, 0xa8, 0x79, 0x94, 0x8d, 0x4c,
-	0x28, 0x3e, 0x8f, 0xab, 0x7d, 0x2c, 0x94, 0x7f, 0x41, 0x0a, 0x27, 0x7e,
-	0x09, 0x7e, 0x2f, 0x58, 0x0f, 0x63, 0x2d, 0x91, 0xfc, 0x28, 0x06, 0xf0,
-	0x93, 0x7b, 0x65, 0xad, 0xeb, 0x0f, 0x43, 0x6e, 0x7e, 0x10, 0x81, 0x8c,
-	0x35, 0xf7, 0xb9, 0x5a, 0xdf, 0xe7, 0x6b, 0x53, 0x80, 0x9e, 0x2a, 0x62,
-	0xce, 0x18, 0x68, 0x08, 0xbe, 0x73, 0x50, 0x86, 0x1c, 0xca, 0xa3, 0x27,
-	0x36, 0x2e, 0xb6, 0x95, 0x17, 0x3f, 0xce, 0xe0, 0xfa, 0xb4, 0xf9, 0x5c,
-	0xcc, 0x10, 0xd6, 0x2f, 0x7d, 0xde, 0xf9, 0x7c, 0x8b, 0x2c, 0x35, 0xea,
-	0xc0, 0x14, 0xe8, 0x29, 0x38, 0xe4, 0x93, 0xaf, 0x9b, 0xfe, 0xda, 0xaf,
-	0xaa, 0xfd, 0x4c, 0xaa, 0x9a, 0xdd, 0x73, 0x35, 0x1d, 0x9d, 0x40, 0x0c,
-	0xe2, 0xea, 0xdc, 0x7d, 0x1e, 0x6f, 0x7c, 0xdd, 0x8c, 0x78, 0x72, 0x66,
-	0x1e, 0x47, 0xdb, 0xf1, 0xf5, 0x60, 0x93, 0x75, 0xb7, 0xe2, 0x05, 0x9f,
-	0x11, 0x53, 0x5c, 0x59, 0x8e, 0xd5, 0x64, 0xb9, 0xb6, 0x41, 0x2f, 0xbf,
-	0xb7, 0xce, 0xb5, 0x43, 0xda, 0x1b, 0xec, 0x16, 0xf4, 0x3d, 0xb5, 0xcc,
-	0xbe, 0x93, 0x97, 0xa8, 0x83, 0x46, 0xc4, 0x98, 0xfb, 0x53, 0xf0, 0xf2,
-	0x63, 0xc8, 0x55, 0x44, 0xcc, 0x19, 0xe2, 0x10, 0xe3, 0x8d, 0x7a, 0xbc,
-	0xbb, 0x20, 0xab, 0xc5, 0xba, 0x57, 0x8a, 0x35, 0x7e, 0xf2, 0x2a, 0x63,
-	0x8d, 0x78, 0x93, 0xb4, 0x10, 0x8b, 0x86, 0x11, 0xdb, 0x6a, 0xd2, 0x64,
-	0x3f, 0x08, 0x1f, 0x76, 0xc6, 0x6c, 0xb6, 0x7d, 0x4c, 0x88, 0x48, 0xfb,
-	0xdc, 0x06, 0x85, 0x0b, 0xd6, 0x4c, 0x1d, 0x17, 0x26, 0xc0, 0xfb, 0x11,
-	0xb7, 0xb6, 0x1a, 0x6d, 0x97, 0xab, 0xcd, 0x8d, 0xeb, 0x71, 0xff, 0x58,
-	0x2d, 0xee, 0xbf, 0xa1, 0x81, 0x8f, 0xab, 0xe1, 0xe2, 0x19, 0xf0, 0x2d,
-	0x8d, 0xfc, 0x97, 0x79, 0xed, 0x10, 0xf2, 0x61, 0xe6, 0x62, 0x19, 0xe4,
-	0xc4, 0x89, 0x33, 0xc0, 0x2a, 0xe4, 0xc8, 0x89, 0xb7, 0xe0, 0x57, 0x90,
-	0x37, 0x27, 0xe6, 0x99, 0xbb, 0x2e, 0x22, 0x3f, 0x7e, 0x1a, 0xf9, 0xf1,
-	0x53, 0x95, 0x3e, 0xf0, 0x37, 0xa9, 0xb0, 0x73, 0xef, 0x71, 0xd1, 0xee,
-	0x52, 0xf5, 0x61, 0xda, 0x73, 0x14, 0x7e, 0xb4, 0x5a, 0x3d, 0x90, 0xea,
-	0x41, 0x4e, 0x1e, 0x97, 0x4f, 0x99, 0xcc, 0x63, 0x35, 0xb3, 0xbb, 0x7f,
-	0xc1, 0x08, 0xc6, 0xa4, 0xd9, 0x2b, 0xfa, 0x81, 0x95, 0xbc, 0xcf, 0x29,
-	0x5f, 0x70, 0xcc, 0xb8, 0x1c, 0xef, 0xef, 0xaa, 0xf1, 0xfe, 0xc2, 0x1a,
-	0x69, 0x19, 0x56, 0x35, 0x80, 0xee, 0xfe, 0x03, 0xc4, 0xab, 0x14, 0xfc,
-	0x3a, 0xfc, 0x6f, 0x55, 0xee, 0x48, 0x5d, 0xac, 0x9e, 0xb7, 0xd7, 0x49,
-	0xbe, 0xef, 0x8b, 0x1e, 0x66, 0x8f, 0x3d, 0x92, 0xb5, 0x8b, 0xb0, 0x0f,
-	0xb7, 0x16, 0x39, 0x3e, 0x1d, 0x46, 0x14, 0xca, 0xbf, 0x0e, 0x59, 0x18,
-	0xfc, 0x1b, 0xc8, 0x70, 0xcb, 0x69, 0x16, 0xb0, 0x74, 0xe0, 0xf0, 0x42,
-	0x34, 0xa2, 0xea, 0x33, 0xd7, 0xd9, 0xec, 0xb7, 0x20, 0xd3, 0x51, 0x59,
-	0x40, 0xfc, 0x50, 0x1a, 0x04, 0x8d, 0x7d, 0x9d, 0x18, 0x4f, 0xbb, 0x23,
-	0xcf, 0x47, 0xe1, 0x7b, 0xc9, 0xd3, 0x28, 0xc6, 0xef, 0xc2, 0x98, 0x0e,
-	0x5c, 0xbf, 0x68, 0x2c, 0x58, 0xcc, 0x9d, 0x7f, 0x0e, 0x6d, 0xce, 0x11,
-	0xf4, 0x9d, 0x9f, 0x0e, 0x89, 0x9a, 0x93, 0xef, 0x74, 0x2a, 0xfb, 0xaf,
-	0xaf, 0xc5, 0x75, 0xf8, 0xec, 0xbd, 0xea, 0x2d, 0xfd, 0x83, 0x81, 0xf5,
-	0xda, 0x02, 0xeb, 0x0d, 0x06, 0xd6, 0x23, 0x9d, 0x1d, 0x01, 0x3a, 0x3b,
-	0xf0, 0x7e, 0x0e, 0x6b, 0x0f, 0xab, 0x98, 0xa7, 0xbe, 0xe6, 0xfd, 0x81,
-	0x35, 0xfd, 0xfd, 0x75, 0x06, 0xde, 0x7b, 0x07, 0xeb, 0xb1, 0x2f, 0x1a,
-	0xe8, 0x23, 0x0d, 0xeb, 0xd1, 0xc7, 0x76, 0x47, 0x80, 0x2e, 0xd2, 0xba,
-	0x16, 0xfd, 0x2a, 0x7e, 0x02, 0x9f, 0x5b, 0xe0, 0xb7, 0x74, 0xf8, 0x0e,
-	0xd6, 0xa0, 0x1b, 0xf7, 0xfa, 0x65, 0xac, 0xeb, 0xcf, 0x17, 0xc5, 0x1c,
-	0x1c, 0xcf, 0xb1, 0x86, 0xf7, 0x3e, 0xfb, 0xf9, 0xfc, 0x1b, 0xd5, 0xaf,
-	0x2b, 0xbe, 0xad, 0x07, 0xed, 0xaa, 0xee, 0x22, 0xf3, 0x1d, 0x26, 0xe4,
-	0xc9, 0xfc, 0x58, 0x93, 0x9b, 0x6c, 0x5d, 0xeb, 0xe9, 0xa7, 0xec, 0xd7,
-	0x79, 0x58, 0xda, 0xa2, 0x65, 0x8f, 0xb3, 0x5e, 0xd0, 0xea, 0xe5, 0x7c,
-	0xc8, 0x3d, 0x94, 0x8f, 0x31, 0xbd, 0xe7, 0xf4, 0x31, 0x8c, 0x5b, 0xe8,
-	0x3f, 0x33, 0xde, 0x3d, 0xae, 0xd0, 0xe1, 0x7d, 0xa5, 0x0e, 0x39, 0xaf,
-	0x78, 0x6a, 0xc9, 0xb9, 0x1a, 0x4f, 0x43, 0xde, 0xb7, 0x90, 0x83, 0xde,
-	0x77, 0x06, 0x03, 0x71, 0x11, 0xee, 0xcb, 0x19, 0xd0, 0x10, 0x97, 0x9e,
-	0x7e, 0xe6, 0x6e, 0x45, 0x5c, 0x59, 0xa7, 0xd0, 0x70, 0x75, 0xeb, 0x17,
-	0x3d, 0xfd, 0xf0, 0x4b, 0xc0, 0xa1, 0x9e, 0xfe, 0xef, 0xa8, 0x7c, 0xae,
-	0x54, 0xb1, 0xb4, 0x3b, 0x1c, 0xb7, 0x46, 0x74, 0xce, 0xbe, 0x5c, 0x8d,
-	0x68, 0xa0, 0x99, 0x75, 0x0d, 0xbf, 0x46, 0x74, 0x4e, 0x54, 0x8d, 0xe8,
-	0xe4, 0x15, 0x6a, 0x44, 0x99, 0xab, 0xaf, 0x11, 0x71, 0x7e, 0x53, 0xee,
-	0x1e, 0x10, 0xed, 0x4b, 0x5e, 0x8d, 0xe8, 0x82, 0xb8, 0x35, 0xa2, 0xf3,
-	0xb2, 0x7a, 0x8d, 0xe8, 0x68, 0x43, 0x8d, 0x68, 0xbd, 0xaa, 0x11, 0x71,
-	0x1e, 0xb7, 0x46, 0xc4, 0x76, 0xbe, 0x7f, 0x30, 0x50, 0xeb, 0x00, 0xfe,
-	0x3a, 0xb7, 0x82, 0x6f, 0x96, 0x36, 0xea, 0xf8, 0x98, 0x46, 0xec, 0xbf,
-	0xbe, 0xe6, 0xbf, 0xea, 0xf8, 0xa6, 0x29, 0x9d, 0xbb, 0x12, 0xbe, 0x8d,
-	0xba, 0x71, 0xc9, 0x32, 0x6c, 0x9b, 0xaa, 0xc5, 0x2e, 0xbf, 0xdc, 0xcc,
-	0x1c, 0x7a, 0xb2, 0x5c, 0x9f, 0x77, 0x12, 0xf2, 0x1e, 0xab, 0xd5, 0x49,
-	0x2e, 0x15, 0x1f, 0x45, 0xe5, 0xe0, 0xaa, 0xdf, 0x9a, 0x62, 0x99, 0x95,
-	0xdf, 0x9a, 0x34, 0x89, 0x82, 0xce, 0x7c, 0x7f, 0x5e, 0xe5, 0x5d, 0x0b,
-	0xce, 0xcf, 0xcb, 0xd2, 0xbd, 0x16, 0xf0, 0xc7, 0xaf, 0x9f, 0x50, 0xbe,
-	0x75, 0x9f, 0x92, 0xd5, 0x3f, 0xba, 0x1a, 0xca, 0x3e, 0x55, 0x43, 0xf9,
-	0x5a, 0x73, 0xb0, 0x86, 0x72, 0x4e, 0x2e, 0x5f, 0x43, 0xd9, 0xb7, 0x4a,
-	0x0d, 0xe5, 0x15, 0xa9, 0xd7, 0x50, 0x5e, 0x11, 0xbf, 0x86, 0x62, 0xc8,
-	0xd2, 0x7a, 0xce, 0xb3, 0x1f, 0xef, 0x8c, 0xe0, 0x37, 0x8c, 0x9f, 0x5b,
-	0x53, 0x39, 0x57, 0xa3, 0x7f, 0xb5, 0x9a, 0xca, 0x37, 0x9b, 0xdf, 0x4f,
-	0x4d, 0xc5, 0xf5, 0x01, 0x7e, 0x4d, 0xa5, 0x05, 0xf1, 0x0e, 0x7c, 0x8e,
-	0x1e, 0xac, 0xa9, 0xfc, 0x2d, 0xed, 0x01, 0x7d, 0x2a, 0x46, 0x40, 0x3f,
-	0xec, 0x02, 0x7e, 0x29, 0xa3, 0x6a, 0x1c, 0x9f, 0xf6, 0x78, 0xb8, 0x1b,
-	0x7b, 0x8e, 0x43, 0x16, 0xe4, 0x63, 0x8f, 0x8a, 0x2d, 0x33, 0x66, 0x4c,
-	0xcb, 0xf6, 0xc2, 0x9b, 0x4d, 0xf3, 0x5b, 0x74, 0x4c, 0xc6, 0x2b, 0xd4,
-	0xf1, 0x2e, 0xc4, 0xe2, 0x26, 0xfa, 0x76, 0xa3, 0xed, 0xc7, 0x54, 0xfd,
-	0xb5, 0x39, 0x68, 0x9b, 0x0b, 0xc0, 0x59, 0xe0, 0xc4, 0x55, 0xf8, 0xa8,
-	0x6d, 0xa0, 0x39, 0xb8, 0x8f, 0x22, 0xfc, 0x13, 0xfa, 0x94, 0xcc, 0x19,
-	0x5b, 0xfa, 0xb4, 0xc4, 0x69, 0xe7, 0x57, 0x31, 0x1f, 0xfb, 0xb6, 0xa9,
-	0x7c, 0xac, 0x30, 0xc0, 0xbd, 0xd2, 0xd7, 0x2d, 0x82, 0x3e, 0xf4, 0x95,
-	0x98, 0x03, 0xd2, 0xef, 0xf9, 0x39, 0x5a, 0x44, 0xe5, 0x68, 0x9d, 0x8a,
-	0x1f, 0xe4, 0xf5, 0x8d, 0x61, 0x62, 0x65, 0xa7, 0xcd, 0x3d, 0x0c, 0x7b,
-	0x58, 0xc7, 0xb6, 0x9b, 0x0b, 0x66, 0x74, 0xde, 0x3f, 0x02, 0xb9, 0xb2,
-	0x4e, 0xe3, 0xcb, 0xef, 0x21, 0x6f, 0xdf, 0x83, 0x52, 0xec, 0x94, 0xf0,
-	0x7a, 0xd0, 0x93, 0x9f, 0x61, 0xdc, 0xfd, 0x09, 0x95, 0x83, 0x44, 0xed,
-	0x4b, 0xdb, 0xed, 0x5d, 0xd7, 0x60, 0xb7, 0x23, 0x97, 0xb5, 0xdb, 0xcf,
-	0x85, 0x83, 0x76, 0x7b, 0xd7, 0x35, 0xd8, 0xed, 0xfe, 0x6b, 0xb2, 0x5b,
-	0xee, 0x8d, 0x98, 0xe4, 0xd7, 0xc4, 0x56, 0xc6, 0x59, 0xfe, 0xba, 0x13,
-	0x58, 0x33, 0x73, 0x89, 0x35, 0xc7, 0x2e, 0x59, 0x5b, 0x6d, 0x8c, 0xb1,
-	0xae, 0x46, 0xde, 0xcc, 0xad, 0xe8, 0x6f, 0x23, 0x9e, 0x5f, 0xba, 0xdd,
-	0xcb, 0xe7, 0xfd, 0xbc, 0x3e, 0x68, 0x3f, 0xd4, 0x0b, 0xea, 0xc2, 0x63,
-	0xe0, 0x17, 0xf5, 0xc1, 0xb7, 0xb9, 0x9e, 0x06, 0x1d, 0x5c, 0x44, 0xbe,
-	0xdf, 0xe3, 0xe9, 0x20, 0x65, 0xdd, 0xab, 0xbe, 0x11, 0x95, 0x9c, 0x47,
-	0xdc, 0x3c, 0x1f, 0x3a, 0x90, 0x2f, 0xf9, 0xb6, 0x06, 0x9e, 0x44, 0xfd,
-	0x67, 0xe4, 0xa3, 0x8d, 0x98, 0x67, 0x0b, 0xe2, 0x35, 0xf0, 0x48, 0xf5,
-	0x2f, 0xaf, 0x09, 0x5f, 0x1e, 0xcf, 0xa4, 0x18, 0xc2, 0xd8, 0x53, 0x03,
-	0xb0, 0xf1, 0x01, 0x62, 0x54, 0x1a, 0x79, 0x0f, 0xf5, 0x90, 0xba, 0xb9,
-	0x29, 0xb9, 0x43, 0x67, 0x4c, 0xb5, 0x07, 0xb6, 0x47, 0x7d, 0x8d, 0xcb,
-	0x8e, 0xca, 0xa6, 0x33, 0xe7, 0x74, 0xae, 0x51, 0xad, 0xe6, 0x99, 0x2b,
-	0x5a, 0xa2, 0x77, 0xf7, 0xff, 0x45, 0x98, 0x7e, 0xe9, 0x7a, 0xdb, 0xf0,
-	0x74, 0x2d, 0x83, 0x7b, 0xea, 0xed, 0xeb, 0xf0, 0xf7, 0xfc, 0xc6, 0xfe,
-	0x03, 0xf4, 0xc7, 0x60, 0xf3, 0xf4, 0xef, 0xcc, 0x47, 0xb6, 0x7a, 0xe3,
-	0x7a, 0xd4, 0xf7, 0xcf, 0x6c, 0xea, 0x56, 0xef, 0xbb, 0x13, 0xfd, 0x4f,
-	0x82, 0x3e, 0x7b, 0x99, 0x9c, 0x79, 0x46, 0x21, 0xa7, 0xf2, 0x19, 0xbe,
-	0xaf, 0x74, 0x12, 0x39, 0x88, 0x19, 0xa8, 0xa5, 0x87, 0xbd, 0xdc, 0x8d,
-	0x36, 0x16, 0x81, 0x0c, 0xb7, 0x7b, 0xb9, 0x0a, 0xf3, 0xd7, 0xe5, 0x67,
-	0x13, 0x56, 0xd7, 0x81, 0x0d, 0xef, 0x43, 0x07, 0x1a, 0xe5, 0x17, 0x86,
-	0xed, 0xfb, 0xf2, 0xf3, 0xe3, 0x98, 0x79, 0x6f, 0xdf, 0x3d, 0xae, 0x0c,
-	0x7f, 0x2c, 0xf6, 0xa9, 0x05, 0xf6, 0xe9, 0xe3, 0xd1, 0x3e, 0x6f, 0x9f,
-	0x5b, 0x1b, 0xf0, 0x68, 0xa4, 0xc1, 0x66, 0x3f, 0x4a, 0x3c, 0x3a, 0xb4,
-	0xe6, 0xa3, 0xc7, 0x23, 0xee, 0x6b, 0xe3, 0xaa, 0x38, 0xe4, 0xee, 0xe3,
-	0x77, 0x45, 0x4f, 0x7f, 0x98, 0xf9, 0xde, 0xfb, 0x91, 0x4f, 0x10, 0x47,
-	0x28, 0x93, 0x36, 0x15, 0xc3, 0xba, 0xb6, 0x07, 0x5f, 0x5e, 0x0a, 0xc9,
-	0x1b, 0xf7, 0x84, 0xe5, 0x7f, 0x6f, 0xe3, 0xf7, 0x30, 0xd3, 0xab, 0x69,
-	0xb1, 0xfd, 0xc2, 0x1a, 0xd7, 0x0f, 0xbd, 0xd0, 0xee, 0xfa, 0x1d, 0xbe,
-	0xe3, 0xdb, 0xb3, 0x85, 0xe7, 0x7c, 0xb6, 0x91, 0x5f, 0x4c, 0xae, 0x21,
-	0x07, 0xdc, 0x64, 0x5d, 0xd0, 0x57, 0xcb, 0x01, 0x2f, 0x5f, 0x0f, 0xac,
-	0xe7, 0x80, 0xc4, 0xd9, 0x0e, 0xa5, 0x1b, 0xf9, 0x28, 0x73, 0x1f, 0xc3,
-	0xc3, 0x4e, 0xde, 0x23, 0xb7, 0x75, 0x90, 0xef, 0x42, 0xb6, 0xcf, 0x21,
-	0x5e, 0x7a, 0xd6, 0x41, 0x8e, 0xeb, 0x20, 0xb7, 0x75, 0x90, 0xdb, 0x3a,
-	0xc8, 0x6d, 0x9d, 0xa4, 0x97, 0x23, 0x8f, 0x78, 0x75, 0x7f, 0x7e, 0xe3,
-	0x66, 0x7d, 0xa1, 0x08, 0x5f, 0x32, 0xc5, 0x73, 0x13, 0x7a, 0x36, 0xb5,
-	0xc6, 0xdb, 0x9f, 0x5f, 0x13, 0xef, 0xf2, 0x6a, 0x36, 0xdf, 0x54, 0x75,
-	0x43, 0xd1, 0x1f, 0x68, 0x71, 0xbf, 0x83, 0xf3, 0x7c, 0xc7, 0xaf, 0x21,
-	0x2e, 0x51, 0x67, 0x88, 0x68, 0xa3, 0x55, 0x3d, 0xcd, 0x9a, 0x8c, 0xe8,
-	0x7a, 0xfa, 0x16, 0xbc, 0xb3, 0xc5, 0xcd, 0x09, 0xa2, 0x62, 0xe8, 0xe9,
-	0x56, 0xf2, 0x54, 0xd3, 0xd3, 0x6b, 0xbd, 0xb9, 0xf6, 0xb7, 0xb8, 0xb1,
-	0x55, 0x2f, 0xdb, 0xa6, 0xce, 0x38, 0x41, 0xc5, 0xda, 0x7e, 0xff, 0xc5,
-	0xf6, 0xe5, 0x6b, 0x85, 0x14, 0xbe, 0x67, 0x53, 0xf7, 0x62, 0x3e, 0xb6,
-	0xeb, 0xfc, 0xd6, 0x2f, 0xc9, 0xef, 0x90, 0xc7, 0x6f, 0x97, 0xc7, 0x06,
-	0xc7, 0xa9, 0xba, 0x30, 0x79, 0xed, 0xcf, 0xa7, 0xea, 0x7a, 0x58, 0x47,
-	0x9d, 0xcd, 0xc0, 0xf5, 0x07, 0xa6, 0xb4, 0x8d, 0xee, 0x0e, 0xd9, 0xc1,
-	0x75, 0xfd, 0x6f, 0xe2, 0x57, 0xb3, 0x66, 0x8f, 0xfa, 0x8e, 0xe6, 0xfa,
-	0x8c, 0x90, 0xd2, 0x41, 0x33, 0xcd, 0x7d, 0xfd, 0x50, 0x9d, 0xa9, 0xa1,
-	0xfe, 0xe5, 0x90, 0xc7, 0x4c, 0x0d, 0x6c, 0x8a, 0x9b, 0xfa, 0x48, 0x0b,
-	0xeb, 0xaf, 0x43, 0x15, 0x1f, 0xf7, 0xb8, 0x5e, 0xa3, 0x1f, 0x67, 0x5d,
-	0xcd, 0xc7, 0x33, 0xd9, 0xe0, 0xd6, 0xdb, 0x3e, 0x88, 0x2d, 0xb5, 0x34,
-	0xd8, 0x92, 0xbf, 0x4f, 0xee, 0x9f, 0xd7, 0xd5, 0xcf, 0x43, 0x2c, 0x56,
-	0x02, 0xdf, 0x47, 0x6a, 0xba, 0xc1, 0xb3, 0x2a, 0x9f, 0x85, 0x0e, 0xf2,
-	0xdb, 0xc0, 0x4e, 0xd8, 0x51, 0xb5, 0x3a, 0xc4, 0x1a, 0x73, 0xdf, 0x67,
-	0x54, 0x7e, 0xa9, 0xa7, 0xe7, 0x55, 0xfd, 0xc1, 0x5c, 0x51, 0x7f, 0x18,
-	0x82, 0xae, 0x20, 0x06, 0x70, 0xda, 0x54, 0x4c, 0xa7, 0xe2, 0x85, 0x4a,
-	0xe3, 0xf7, 0x97, 0xfb, 0x5b, 0x5d, 0x3e, 0xfc, 0x5d, 0x8b, 0xfb, 0x0d,
-	0xe2, 0x8f, 0xa2, 0xcb, 0xdb, 0x7c, 0xff, 0xaf, 0x5b, 0xfc, 0xb3, 0x3b,
-	0x85, 0x13, 0x43, 0xd0, 0x45, 0xe4, 0xe4, 0x6a, 0x3e, 0xc4, 0xbb, 0x4f,
-	0xcc, 0x76, 0x2c, 0x1f, 0x8f, 0xbe, 0x13, 0xfe, 0xf8, 0x8e, 0x86, 0xf1,
-	0x1d, 0x18, 0xff, 0x7b, 0x0d, 0xe3, 0x3b, 0x02, 0xe3, 0xa3, 0x0d, 0xe3,
-	0xa3, 0x18, 0xff, 0x7c, 0xc3, 0xf8, 0x68, 0x60, 0x7c, 0x67, 0xc3, 0xf8,
-	0x4e, 0x8c, 0x7f, 0xa1, 0x61, 0x3c, 0xfa, 0x4e, 0x34, 0x79, 0xdf, 0xc5,
-	0x88, 0xb1, 0xfb, 0xbd, 0x5c, 0x1c, 0xd7, 0x72, 0xe3, 0xb7, 0x16, 0xea,
-	0x5d, 0x17, 0x64, 0xe0, 0x9f, 0xa7, 0xa3, 0xbd, 0x66, 0x60, 0xaf, 0xf5,
-	0x58, 0xc6, 0xd5, 0xc7, 0xa0, 0x2e, 0x12, 0x1f, 0x8a, 0x62, 0xd8, 0xd0,
-	0x9d, 0x12, 0x74, 0xa8, 0xe4, 0xfb, 0x24, 0x9e, 0x83, 0xe2, 0x19, 0x53,
-	0xd7, 0xf7, 0x86, 0xec, 0x45, 0x2f, 0x07, 0x7b, 0x9b, 0xb4, 0x03, 0x2f,
-	0x7d, 0xcc, 0x94, 0x63, 0xae, 0xdd, 0x50, 0x7f, 0x39, 0xbf, 0x67, 0x3f,
-	0xd4, 0x55, 0x6f, 0x9d, 0xa1, 0x15, 0xb8, 0x16, 0x5f, 0x51, 0xdb, 0x32,
-	0xae, 0x02, 0xd7, 0x46, 0x6a, 0xb8, 0xf6, 0x59, 0x99, 0xaf, 0xe5, 0xdb,
-	0xc3, 0x72, 0xc0, 0xd9, 0xc5, 0x33, 0x36, 0xc7, 0x32, 0xf2, 0xe1, 0xe4,
-	0xdb, 0xbb, 0x6a, 0x7e, 0x92, 0x67, 0x3a, 0x96, 0x0e, 0x31, 0x87, 0xf2,
-	0x6b, 0xb3, 0x53, 0xce, 0xcf, 0xb6, 0x42, 0x2e, 0xb0, 0x8d, 0x6b, 0xcd,
-	0xb7, 0x39, 0x5f, 0x54, 0x0e, 0xb8, 0xe7, 0x1d, 0x6a, 0xf3, 0x16, 0x6b,
-	0xf3, 0xc6, 0x3c, 0x7b, 0xa3, 0x0f, 0xae, 0xfb, 0xcb, 0x1c, 0xfc, 0xe5,
-	0x18, 0x72, 0xee, 0x45, 0x67, 0xb5, 0xfa, 0xe8, 0xb5, 0xfa, 0xcb, 0xc6,
-	0x3a, 0x73, 0xa3, 0xbf, 0xe4, 0x3a, 0x8d, 0xb5, 0xe5, 0x78, 0x03, 0xfe,
-	0x53, 0x9f, 0x0e, 0x7b, 0x31, 0x35, 0xae, 0xa5, 0xc3, 0xb0, 0x47, 0x5d,
-	0xc6, 0x94, 0xfe, 0xb2, 0xed, 0xe7, 0x96, 0xbb, 0x6b, 0xb9, 0x65, 0x3d,
-	0x1f, 0x44, 0xec, 0x9a, 0xfc, 0xa4, 0x87, 0x8f, 0x8c, 0x91, 0xa7, 0xd0,
-	0x7f, 0x0c, 0x3a, 0xc0, 0x67, 0xac, 0x97, 0xde, 0x2c, 0x9f, 0x32, 0x5d,
-	0xff, 0xe4, 0xd6, 0xa6, 0x76, 0xab, 0xf8, 0x9f, 0xdf, 0x0b, 0x0a, 0xa9,
-	0x76, 0x2f, 0xde, 0xbb, 0x12, 0xae, 0x2e, 0xcf, 0x4d, 0x75, 0xfd, 0x51,
-	0xbc, 0xcb, 0xdc, 0xd4, 0x8c, 0x10, 0x43, 0xb3, 0x95, 0xcb, 0xbe, 0x5f,
-	0xa4, 0x7f, 0x29, 0xa8, 0xef, 0x82, 0x2a, 0x0f, 0xc5, 0xb8, 0x45, 0xef,
-	0x7d, 0x37, 0x0f, 0xcd, 0x56, 0xbe, 0xdd, 0xea, 0xe2, 0xe0, 0xe5, 0x72,
-	0x96, 0x9f, 0x88, 0xb0, 0xae, 0xb7, 0xe8, 0x5c, 0x89, 0xd6, 0x95, 0x79,
-	0xaf, 0xb1, 0x22, 0xef, 0x1d, 0xf5, 0xf2, 0xda, 0xcf, 0xa9, 0xbc, 0xd7,
-	0xe5, 0x31, 0xf7, 0x12, 0xcc, 0xa3, 0x6c, 0x60, 0x21, 0xbf, 0xa9, 0x10,
-	0x1f, 0x26, 0x94, 0xdf, 0xca, 0x4f, 0xdf, 0x09, 0x3e, 0x47, 0x57, 0xd1,
-	0x9b, 0x8f, 0xda, 0x4f, 0xf8, 0x7b, 0x3f, 0x2c, 0x6e, 0xbd, 0x6e, 0x27,
-	0x68, 0x61, 0x6e, 0x15, 0xf2, 0xf4, 0xe1, 0xbb, 0xde, 0x39, 0x53, 0x7f,
-	0x9c, 0x9f, 0xc7, 0xd7, 0xbe, 0xbb, 0x16, 0x33, 0xcb, 0xea, 0x27, 0x1b,
-	0x09, 0xc3, 0x90, 0x7b, 0xe6, 0x1a, 0xbe, 0x5b, 0x7c, 0x90, 0xf3, 0x11,
-	0x8d, 0x7e, 0x8d, 0xdf, 0x4d, 0xf9, 0xad, 0x54, 0xb4, 0xbb, 0x7b, 0x6d,
-	0xd8, 0x00, 0xcf, 0x2c, 0x07, 0xf1, 0x35, 0x2c, 0xf9, 0x39, 0x09, 0x47,
-	0xd3, 0xfc, 0x06, 0x40, 0xff, 0xff, 0xba, 0xb7, 0xcf, 0x98, 0xec, 0x9f,
-	0x71, 0x6b, 0x9e, 0xfa, 0x65, 0xcf, 0xc5, 0x1d, 0x00, 0x1f, 0x12, 0x47,
-	0xfd, 0x9a, 0xa7, 0xee, 0x9e, 0x8b, 0x3b, 0xfa, 0xe1, 0x9d, 0x8b, 0xe3,
-	0xfc, 0xa6, 0xec, 0x5a, 0xe5, 0x5c, 0x9c, 0x71, 0x95, 0xe7, 0xe2, 0xda,
-	0x55, 0xcd, 0x93, 0xf3, 0xb8, 0x35, 0x4f, 0xb6, 0xbb, 0xfb, 0x59, 0x2b,
-	0xe1, 0xd9, 0xb7, 0x01, 0x75, 0x06, 0xb9, 0xbb, 0xff, 0x47, 0x91, 0xa3,
-	0x7c, 0x3d, 0xf2, 0xd1, 0xe7, 0x28, 0xdc, 0xcb, 0xaf, 0xb8, 0xdf, 0x77,
-	0xe5, 0x5a, 0xea, 0x00, 0x1f, 0xac, 0xae, 0xb9, 0x5f, 0xd5, 0x35, 0xbf,
-	0x13, 0x09, 0xd6, 0x35, 0xf5, 0x2b, 0x9c, 0x0d, 0xdb, 0xbf, 0x4a, 0x5d,
-	0x33, 0x14, 0x38, 0x1b, 0x16, 0xf2, 0xce, 0x86, 0xb5, 0xdb, 0xc8, 0x25,
-	0xbd, 0x3a, 0xa6, 0x7e, 0xd9, 0xb3, 0x61, 0xff, 0x19, 0xf9, 0xe0, 0x75,
-	0xcc, 0x15, 0x67, 0xc3, 0xe0, 0xeb, 0x36, 0x48, 0xfc, 0x9a, 0xf2, 0x9e,
-	0x0f, 0x92, 0xf3, 0xf0, 0xbc, 0x7e, 0x13, 0xf6, 0x1c, 0x92, 0x5d, 0x51,
-	0xea, 0x27, 0xcf, 0x36, 0xf6, 0xc2, 0x16, 0x70, 0xad, 0xb0, 0x9d, 0xa4,
-	0x8c, 0xb4, 0x91, 0xde, 0xe5, 0xe7, 0x10, 0xea, 0xe7, 0x71, 0xc3, 0xb5,
-	0xf3, 0xb8, 0x47, 0xa0, 0x37, 0xfa, 0x4c, 0x58, 0x16, 0x02, 0x3a, 0x35,
-	0x85, 0x78, 0x4f, 0x9f, 0xb3, 0xbc, 0xe7, 0xfc, 0x9f, 0x8a, 0x28, 0x30,
-	0x8f, 0x67, 0x78, 0xdb, 0xc4, 0x98, 0x73, 0xbf, 0x59, 0xba, 0xff, 0x57,
-	0x12, 0xc3, 0x18, 0x9e, 0xf1, 0x0c, 0xc9, 0x01, 0x55, 0xb3, 0xf0, 0x75,
-	0x79, 0xc7, 0x5a, 0x69, 0x59, 0x9f, 0xa9, 0xb7, 0xa3, 0xab, 0xf8, 0x7d,
-	0xc4, 0x91, 0x33, 0xd4, 0xe7, 0x5b, 0x25, 0xe7, 0xd5, 0x83, 0x0a, 0x95,
-	0x6d, 0x5e, 0x7e, 0xa1, 0xbe, 0xed, 0x80, 0x97, 0xdd, 0x9e, 0x0f, 0xc6,
-	0xb5, 0xd4, 0x4d, 0x9f, 0x87, 0x35, 0x4e, 0xca, 0xd0, 0xf4, 0x96, 0xd8,
-	0x38, 0xf0, 0x6e, 0x4c, 0xad, 0x79, 0x2d, 0x3c, 0xd7, 0x2e, 0xf1, 0xbd,
-	0xf1, 0x6a, 0xf9, 0xee, 0xc7, 0xc7, 0x8f, 0x62, 0x7f, 0xdd, 0xd0, 0x8f,
-	0x87, 0x25, 0x77, 0xe2, 0x66, 0x19, 0x9a, 0x4d, 0x80, 0x9e, 0x1f, 0x56,
-	0x0b, 0x29, 0xc4, 0xd2, 0x4f, 0xf0, 0xdc, 0x18, 0x30, 0x14, 0x7c, 0x7b,
-	0x66, 0xc5, 0x77, 0xec, 0xe0, 0x59, 0xb3, 0x64, 0xed, 0xec, 0xd0, 0x53,
-	0x15, 0x09, 0x77, 0x90, 0xe6, 0x99, 0xfa, 0xd9, 0xef, 0xc5, 0xca, 0x0e,
-	0xe5, 0xdb, 0x9e, 0xac, 0x2c, 0xab, 0xfd, 0x28, 0x19, 0x4e, 0x94, 0x9f,
-	0x04, 0x2f, 0x5e, 0x51, 0xfe, 0xed, 0x88, 0x23, 0x37, 0x19, 0x42, 0x79,
-	0x88, 0x06, 0x1e, 0xa8, 0x33, 0x1c, 0xee, 0xf7, 0xfd, 0x2e, 0x25, 0x57,
-	0x17, 0x2b, 0x76, 0x06, 0xce, 0x60, 0xd4, 0x65, 0xeb, 0x9e, 0xcd, 0x70,
-	0x65, 0xe1, 0x9e, 0x1f, 0x21, 0x3f, 0x97, 0x0e, 0xed, 0xb2, 0xdd, 0xf3,
-	0x23, 0x3d, 0x73, 0xec, 0xeb, 0x6c, 0xf0, 0x7d, 0x61, 0xe8, 0x00, 0xcf,
-	0x1d, 0xf1, 0xcc, 0x37, 0x69, 0x56, 0xb5, 0x8e, 0x55, 0xbf, 0x6d, 0x5f,
-	0x5b, 0xcd, 0xd5, 0x5d, 0xb3, 0x5b, 0xad, 0x79, 0x9d, 0x87, 0x59, 0xfe,
-	0x59, 0xef, 0x94, 0xf6, 0xff, 0xd4, 0x5d, 0x7b, 0x6c, 0x1b, 0xf7, 0x7d,
-	0xff, 0xf2, 0x48, 0x3d, 0xac, 0xe7, 0x49, 0xa6, 0x64, 0x5a, 0x52, 0x94,
-	0x3b, 0xe9, 0x64, 0x29, 0xb1, 0x12, 0x70, 0x9e, 0xba, 0x0a, 0x88, 0x9a,
-	0xb0, 0x24, 0xfd, 0x58, 0x10, 0x0c, 0xb4, 0xad, 0x64, 0xee, 0x92, 0xad,
-	0x0e, 0x25, 0xa7, 0x1d, 0x30, 0x60, 0x6e, 0xd6, 0x02, 0x69, 0x07, 0xc7,
-	0x0c, 0x65, 0x27, 0xc6, 0xaa, 0x88, 0x4c, 0xcc, 0x6a, 0x1d, 0xb0, 0x62,
-	0x1c, 0xa5, 0x38, 0x69, 0xa7, 0x80, 0x69, 0xda, 0x04, 0xc5, 0xfe, 0xb1,
-	0x26, 0x3b, 0x7b, 0x61, 0x7f, 0x04, 0xdb, 0x80, 0x1a, 0x5b, 0x81, 0xba,
-	0x76, 0x8a, 0x65, 0x1b, 0xe0, 0x34, 0xdb, 0xb0, 0x75, 0x58, 0x0b, 0xee,
-	0xfb, 0xf9, 0x3d, 0xc8, 0x23, 0x79, 0xd4, 0xc3, 0x71, 0x06, 0x4c, 0x80,
-	0x40, 0xde, 0xf1, 0x77, 0x77, 0xbf, 0xdf, 0xf7, 0xf7, 0x7d, 0xbf, 0x6e,
-	0x2e, 0x33, 0x1e, 0xf2, 0x33, 0x7e, 0xcf, 0x15, 0x61, 0x5f, 0x37, 0xd2,
-	0xe1, 0x36, 0x83, 0x67, 0xa4, 0x0e, 0x9e, 0xd5, 0x34, 0xc1, 0xf6, 0x78,
-	0x99, 0x77, 0x4b, 0xd8, 0xc9, 0xf3, 0xc8, 0x63, 0xd7, 0x39, 0x0e, 0x12,
-	0x76, 0x65, 0x1a, 0x5a, 0x72, 0xe7, 0x37, 0x54, 0x60, 0x77, 0xb2, 0x0c,
-	0xbb, 0x3d, 0xff, 0x8f, 0x60, 0x77, 0x4d, 0xe8, 0xbf, 0xdf, 0x2e, 0x22,
-	0x6f, 0x4d, 0xeb, 0x00, 0xba, 0x6e, 0x09, 0x70, 0x04, 0x3f, 0xb5, 0xf3,
-	0xeb, 0x04, 0x9e, 0x8a, 0xbc, 0xe2, 0x52, 0xe9, 0x3b, 0xe1, 0xb2, 0x9f,
-	0x92, 0xed, 0x12, 0xd8, 0x27, 0xf0, 0xe7, 0x35, 0x96, 0x91, 0x47, 0x6f,
-	0x4b, 0x46, 0x42, 0x57, 0xaa, 0xb5, 0x4f, 0x7e, 0xbb, 0xcb, 0x6d, 0x9f,
-	0x1c, 0xdd, 0xa1, 0x7d, 0x72, 0x5a, 0xda, 0x27, 0xa9, 0xed, 0xdb, 0x27,
-	0x03, 0x75, 0x79, 0x5d, 0x95, 0xf5, 0xec, 0xdc, 0x3e, 0x31, 0x36, 0xb5,
-	0x4f, 0x46, 0x5d, 0xbe, 0x18, 0xcc, 0xf7, 0x57, 0x29, 0x75, 0x0c, 0x3c,
-	0x4e, 0xc3, 0x19, 0x30, 0x3e, 0x56, 0xe3, 0x17, 0xfe, 0x38, 0x61, 0xfd,
-	0xd7, 0xff, 0xc7, 0xb0, 0x1e, 0xac, 0xf3, 0x79, 0x57, 0xd6, 0x03, 0x21,
-	0xfe, 0x51, 0x60, 0x3d, 0xd8, 0xd0, 0x77, 0xda, 0x38, 0x67, 0xb1, 0xda,
-	0x77, 0x3a, 0x62, 0x34, 0xe2, 0xed, 0x7f, 0xe4, 0xf2, 0xa9, 0xba, 0xf9,
-	0x3b, 0x68, 0x8a, 0x7c, 0x47, 0xc7, 0xf5, 0xb3, 0x40, 0x4b, 0x76, 0x2a,
-	0x45, 0xb0, 0x99, 0xf0, 0xbc, 0x90, 0xa0, 0xb5, 0x1a, 0x7d, 0x8b, 0x9f,
-	0xc7, 0xeb, 0x7b, 0xf5, 0x09, 0x21, 0xa7, 0xa4, 0xff, 0x01, 0xe3, 0x27,
-	0x7c, 0xf3, 0x62, 0xac, 0xcc, 0x6f, 0x52, 0xfe, 0x08, 0xa5, 0xfb, 0x37,
-	0xf2, 0x43, 0xd4, 0xcb, 0xbc, 0x9d, 0xd9, 0x0a, 0x9a, 0xc6, 0xef, 0xe6,
-	0x7d, 0x09, 0x55, 0xd9, 0x5a, 0xe0, 0x9f, 0xa7, 0x59, 0x2f, 0x18, 0x29,
-	0xeb, 0x04, 0xd5, 0x7b, 0x73, 0x4e, 0xd8, 0x74, 0x9a, 0x77, 0x26, 0x64,
-	0xee, 0xa9, 0x38, 0x0f, 0x3d, 0x4d, 0xf3, 0xce, 0x5a, 0x3d, 0xf8, 0x6e,
-	0x0f, 0xbc, 0xf0, 0xca, 0x69, 0x2a, 0xef, 0x9d, 0x85, 0x9c, 0xf3, 0xb8,
-	0xe7, 0xde, 0x95, 0x6b, 0xc2, 0x52, 0x95, 0xb1, 0xf2, 0xfa, 0xb8, 0x58,
-	0xd7, 0x0f, 0x8e, 0x44, 0x51, 0xfb, 0x56, 0xae, 0x17, 0xab, 0xad, 0x77,
-	0x82, 0x1c, 0xd0, 0x74, 0xa8, 0x6b, 0xa2, 0x01, 0x8b, 0x61, 0x8f, 0x7a,
-	0x27, 0xb7, 0x2c, 0xc1, 0x75, 0xb5, 0xb0, 0xa8, 0xc8, 0x91, 0xf3, 0x4a,
-	0x8e, 0x14, 0x5c, 0x7c, 0xbc, 0x5e, 0x6f, 0xef, 0xf5, 0xd0, 0xdb, 0xbd,
-	0x6a, 0x9e, 0x30, 0xa7, 0x67, 0x58, 0x0f, 0xb9, 0x1f, 0x7a, 0x88, 0x89,
-	0xba, 0x25, 0xa9, 0x8b, 0xe0, 0x77, 0x96, 0x35, 0xaf, 0x86, 0x18, 0x57,
-	0x8e, 0xd0, 0x53, 0xac, 0x6b, 0x5f, 0xa2, 0x7b, 0x94, 0x7d, 0x16, 0x71,
-	0xe5, 0x99, 0x22, 0x8f, 0xdf, 0x47, 0xa9, 0x27, 0xec, 0x89, 0x08, 0x1d,
-	0xa1, 0x53, 0x22, 0x67, 0x06, 0xf1, 0x3d, 0xe4, 0x1c, 0xdc, 0x2b, 0x9e,
-	0x2f, 0x7d, 0x19, 0x77, 0x22, 0xa7, 0x6e, 0xfb, 0xf9, 0xfb, 0xba, 0x56,
-	0x2f, 0x2a, 0x9e, 0xb9, 0xaa, 0x68, 0x4a, 0x9c, 0xe3, 0xeb, 0x9f, 0x31,
-	0xea, 0xaf, 0x8f, 0x18, 0xf1, 0x62, 0xdc, 0x88, 0xae, 0x60, 0xdc, 0x33,
-	0x46, 0xac, 0x08, 0x1b, 0x52, 0xe3, 0x88, 0x1d, 0x06, 0xbd, 0x6d, 0xd0,
-	0xd6, 0xb1, 0x88, 0x02, 0xd5, 0xd4, 0x49, 0x6c, 0x63, 0xde, 0x87, 0xaa,
-	0xe6, 0xad, 0xe1, 0x8b, 0xef, 0xf0, 0xf7, 0x44, 0x18, 0xa6, 0x5a, 0xaf,
-	0x6d, 0x83, 0x7f, 0x7d, 0x22, 0x45, 0x9b, 0xe9, 0xb5, 0x76, 0x9d, 0x5e,
-	0x5b, 0xd8, 0x72, 0xde, 0x1f, 0x95, 0xc6, 0x65, 0x3d, 0xa2, 0xdf, 0x11,
-	0xfa, 0x2b, 0xcf, 0xbb, 0x4a, 0xb7, 0xad, 0xc1, 0x29, 0x8c, 0xd1, 0x7e,
-	0x70, 0xed, 0x07, 0xeb, 0x52, 0xf9, 0xc0, 0x3a, 0x3f, 0xa1, 0x0d, 0xf5,
-	0x5e, 0xa6, 0xcc, 0x6b, 0x85, 0x8d, 0xb5, 0xce, 0xf3, 0x83, 0xbd, 0xf5,
-	0xa0, 0x98, 0x23, 0xdb, 0x5b, 0x56, 0x8c, 0xa4, 0xaf, 0x7b, 0xbe, 0x58,
-	0x55, 0xff, 0xe9, 0x51, 0x07, 0x39, 0xe2, 0x51, 0x07, 0xe9, 0xa6, 0xb5,
-	0x80, 0x8b, 0xd6, 0x42, 0x2e, 0xbd, 0x6d, 0x88, 0xed, 0x96, 0x0e, 0xe6,
-	0x21, 0xb0, 0x5b, 0xda, 0xc8, 0xff, 0xb2, 0xdb, 0x6e, 0xa9, 0xad, 0x45,
-	0x07, 0xdd, 0x41, 0x37, 0x93, 0x36, 0x4c, 0x3c, 0x57, 0xae, 0x63, 0xe7,
-	0x75, 0x57, 0x6a, 0x0e, 0x57, 0xea, 0xea, 0x23, 0xbd, 0xe6, 0x3b, 0x5c,
-	0x37, 0x5f, 0xc8, 0xaf, 0x48, 0x43, 0x9d, 0xce, 0xcb, 0xae, 0xba, 0x53,
-	0xf3, 0xab, 0xe5, 0x67, 0x78, 0xd6, 0x88, 0xf0, 0x79, 0xa7, 0xca, 0xbc,
-	0x6c, 0x5a, 0xce, 0x37, 0x53, 0x6d, 0x67, 0xf8, 0x97, 0x48, 0xc1, 0xce,
-	0x9b, 0xb7, 0xef, 0xcc, 0x7f, 0xd6, 0x5e, 0x23, 0x77, 0xdf, 0x33, 0xa5,
-	0x5f, 0xac, 0x49, 0xe5, 0x61, 0xf7, 0x29, 0x7b, 0x6f, 0x2b, 0x7c, 0xc7,
-	0xb9, 0x26, 0xe5, 0x4b, 0xb4, 0xad, 0x3c, 0x01, 0xcf, 0x8f, 0x9d, 0x68,
-	0x72, 0x4c, 0x15, 0xcb, 0x42, 0xbc, 0x0a, 0x78, 0xaf, 0xef, 0x0f, 0x9e,
-	0xbd, 0x9d, 0x3d, 0xb3, 0xea, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x2d, 0xe4,
-	0x17, 0x4f, 0xd6, 0xe4, 0x78, 0x7f, 0x14, 0x58, 0x74, 0x79, 0xe4, 0x3d,
-	0x23, 0x6f, 0xb9, 0xd1, 0x3c, 0xaf, 0xbb, 0xf4, 0x72, 0xcc, 0xb7, 0x54,
-	0x7a, 0x23, 0x3c, 0x20, 0x65, 0x71, 0xd1, 0x5b, 0x47, 0x32, 0xb7, 0x3d,
-	0xbf, 0x5a, 0xd9, 0xbb, 0x77, 0x9b, 0xb2, 0x57, 0xf4, 0xf4, 0xf0, 0x1d,
-	0x14, 0x3c, 0xa0, 0x83, 0x56, 0x72, 0xc8, 0xbf, 0xfe, 0x05, 0xd0, 0x3c,
-	0xf3, 0x59, 0x57, 0x4d, 0x9a, 0xf7, 0x3e, 0x96, 0x63, 0x2a, 0x81, 0x19,
-	0xc4, 0xfe, 0x90, 0x5b, 0xd2, 0xcb, 0xbc, 0x07, 0xe3, 0xc7, 0xac, 0xab,
-	0xf0, 0xf7, 0x2a, 0xff, 0x53, 0x5c, 0xc9, 0x97, 0x83, 0xdb, 0x88, 0xad,
-	0xec, 0x8c, 0x4f, 0xdb, 0xd6, 0x3a, 0x21, 0xee, 0x83, 0x7c, 0xe1, 0xfb,
-	0xba, 0xa8, 0xeb, 0x33, 0x2d, 0x2d, 0xce, 0x97, 0x7a, 0x64, 0x2c, 0x0a,
-	0xbf, 0x75, 0xd0, 0x2b, 0x39, 0xe4, 0x72, 0xe3, 0xb7, 0xdf, 0xe0, 0xdf,
-	0xbc, 0x78, 0x94, 0xce, 0x45, 0x87, 0x2e, 0x27, 0xf7, 0x27, 0x4f, 0xb0,
-	0x95, 0x4a, 0xf4, 0xb7, 0xe1, 0x5f, 0x94, 0xf1, 0x8c, 0xe2, 0x9d, 0x8e,
-	0xd5, 0x78, 0xf9, 0x0b, 0xdf, 0xec, 0xb9, 0xdd, 0xdc, 0xc8, 0x2f, 0x6c,
-	0xcb, 0x5f, 0x88, 0x38, 0xff, 0x76, 0x62, 0x26, 0x3a, 0x36, 0x3c, 0x25,
-	0x6a, 0x4e, 0xdd, 0x78, 0x70, 0x67, 0xe2, 0xc3, 0xc0, 0x87, 0xe1, 0x3a,
-	0x5e, 0xf5, 0xd1, 0xfd, 0xfd, 0xb5, 0x70, 0x6d, 0xf3, 0xf4, 0x55, 0x79,
-	0xc7, 0x81, 0x11, 0xf3, 0x87, 0x9f, 0xfa, 0x21, 0x9a, 0xbf, 0x08, 0x1c,
-	0x36, 0x18, 0xdb, 0x46, 0x69, 0x21, 0x88, 0xba, 0x22, 0x51, 0x9b, 0xa3,
-	0xe2, 0x86, 0xb2, 0x56, 0x68, 0x5e, 0xd4, 0x40, 0x8e, 0x85, 0x6e, 0xf2,
-	0xbc, 0xe7, 0x8b, 0x29, 0x3a, 0xc5, 0x32, 0xf6, 0xd4, 0x4a, 0x45, 0x77,
-	0xaf, 0xaf, 0x83, 0xac, 0xc6, 0xf1, 0x9b, 0x02, 0xc7, 0x87, 0x36, 0xc5,
-	0xf1, 0xc3, 0x65, 0x1c, 0xff, 0x44, 0xaf, 0xc4, 0xe7, 0x67, 0xf9, 0x5e,
-	0x5d, 0x74, 0x50, 0xdc, 0x37, 0xc5, 0xdf, 0xdb, 0xe9, 0xa0, 0xec, 0x61,
-	0xc1, 0xcf, 0x66, 0x1e, 0x9f, 0x49, 0xd1, 0x53, 0x17, 0x53, 0xbe, 0xb8,
-	0xa8, 0x5f, 0x70, 0xf7, 0xe8, 0xd0, 0xd7, 0x63, 0x5c, 0x23, 0xfc, 0xd7,
-	0x7c, 0x49, 0xd6, 0x5c, 0xe5, 0x25, 0x7f, 0xa2, 0x77, 0xc3, 0x83, 0x35,
-	0xf8, 0x5f, 0x6d, 0x3b, 0x9e, 0x56, 0x32, 0xf0, 0xd8, 0x26, 0x7e, 0x8d,
-	0x7a, 0xbc, 0xec, 0xf1, 0xd0, 0x87, 0x7f, 0xbd, 0x57, 0xc6, 0xa9, 0x36,
-	0xf3, 0x6b, 0xb8, 0x71, 0xb4, 0x2a, 0x6e, 0xcf, 0x7c, 0xff, 0xbf, 0x55,
-	0x1c, 0xfd, 0xa5, 0x5e, 0x29, 0x2f, 0x50, 0x1f, 0x98, 0x60, 0x38, 0x9c,
-	0x64, 0x5d, 0x65, 0x90, 0x9a, 0x5f, 0xd6, 0x6b, 0x1d, 0x14, 0xfc, 0xd6,
-	0xed, 0xa7, 0x39, 0xa7, 0x6a, 0xbb, 0xd3, 0xae, 0x35, 0x9d, 0x13, 0x36,
-	0x4e, 0x63, 0x7a, 0x6b, 0x9c, 0x73, 0x35, 0x54, 0x23, 0x13, 0x6a, 0xf1,
-	0x0d, 0xbd, 0x4f, 0xb0, 0xbf, 0x64, 0x48, 0x3d, 0x78, 0x9a, 0xf5, 0xdb,
-	0x9d, 0xc6, 0x8b, 0x3e, 0xaa, 0x8e, 0x58, 0xdb, 0x53, 0xa3, 0xf6, 0x3b,
-	0xf6, 0x41, 0xda, 0x1c, 0xc9, 0x57, 0x1f, 0x12, 0xbc, 0xe0, 0xdc, 0x64,
-	0x89, 0x62, 0xe1, 0x4e, 0x4a, 0x4e, 0xf2, 0xb3, 0xa7, 0x1d, 0xb6, 0xbd,
-	0xfc, 0x94, 0x62, 0xfa, 0x4d, 0x4e, 0xee, 0x52, 0xfa, 0xa2, 0xf6, 0xa7,
-	0xb7, 0xa8, 0x3c, 0x87, 0x67, 0x45, 0x5c, 0x52, 0xf6, 0xc6, 0xe0, 0xef,
-	0x2b, 0xfa, 0xde, 0xcf, 0x8a, 0xf8, 0x68, 0xf2, 0x62, 0xb3, 0x1a, 0xd7,
-	0xee, 0x1a, 0x87, 0x31, 0xed, 0x6a, 0x2c, 0xee, 0xa9, 0x75, 0x8a, 0x56,
-	0xc5, 0x6f, 0x1f, 0x11, 0x75, 0x60, 0xb2, 0x56, 0x0f, 0xbf, 0x9f, 0xa6,
-	0xb9, 0xf2, 0x5a, 0xda, 0x79, 0xec, 0xcf, 0x4a, 0x11, 0x61, 0xcb, 0xb5,
-	0xb3, 0xce, 0x8b, 0x79, 0xd7, 0xcf, 0x09, 0x6b, 0xf1, 0x8b, 0xf8, 0x10,
-	0x7f, 0x57, 0xcf, 0x39, 0x59, 0x9e, 0x13, 0x72, 0x34, 0xec, 0x90, 0xbc,
-	0x97, 0x1e, 0xd7, 0xee, 0x1a, 0xa7, 0x79, 0x85, 0x8e, 0x3f, 0xfc, 0x80,
-	0xe7, 0xf1, 0x37, 0x2a, 0x87, 0xd7, 0x14, 0xf1, 0x53, 0x99, 0xa3, 0xa1,
-	0xbf, 0xc3, 0xbf, 0x8c, 0x9c, 0x0a, 0xe4, 0x49, 0xb8, 0xf9, 0x8d, 0x5c,
-	0x6f, 0x00, 0xb2, 0xa8, 0x88, 0xb8, 0x29, 0xe2, 0x15, 0x8d, 0x74, 0xe7,
-	0xbd, 0xc8, 0xcd, 0xdf, 0x81, 0x0e, 0xba, 0x1d, 0xfa, 0xb3, 0x3c, 0xe8,
-	0xcf, 0xfd, 0x7c, 0xd4, 0xc1, 0xa1, 0x1e, 0x2e, 0x35, 0x61, 0x50, 0x89,
-	0x6d, 0x05, 0x83, 0xf2, 0xa6, 0x8f, 0x9e, 0x72, 0xec, 0xf0, 0x0a, 0xc9,
-	0x9a, 0xc9, 0xd8, 0xa2, 0x3d, 0xb1, 0x4e, 0xfb, 0x45, 0xcd, 0x38, 0x7a,
-	0x1f, 0xe4, 0x59, 0x06, 0x9f, 0xa4, 0x09, 0xb6, 0x8f, 0xd8, 0xfe, 0x9c,
-	0x45, 0xbc, 0x45, 0xef, 0x0b, 0x6a, 0xe0, 0xf1, 0x39, 0xc1, 0x70, 0x7a,
-	0x6c, 0x37, 0xb5, 0x45, 0xf8, 0x9e, 0x13, 0xe0, 0x4f, 0xe8, 0xe7, 0x45,
-	0x51, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x9c, 0xb5, 0xcd, 0x3c, 0x19, 0x3c,
-	0x16, 0xb6, 0x2b, 0xee, 0x83, 0xeb, 0x23, 0x66, 0x13, 0xd5, 0xd6, 0xe4,
-	0x3e, 0x2b, 0xea, 0x14, 0xdf, 0x0d, 0xdf, 0x47, 0x46, 0x3f, 0xf8, 0x15,
-	0xf6, 0xed, 0x5e, 0x15, 0x27, 0x3a, 0xcb, 0xdf, 0xc7, 0xd5, 0xf7, 0xaf,
-	0x88, 0xfd, 0x94, 0xdf, 0x35, 0x7e, 0xe3, 0xef, 0x5f, 0x5a, 0xc8, 0xf9,
-	0xa1, 0xca, 0x59, 0xa9, 0xca, 0x05, 0x09, 0x8d, 0x1a, 0x5f, 0xa1, 0xd3,
-	0x2b, 0x9b, 0xf9, 0x5f, 0xbc, 0x6a, 0x5d, 0xbb, 0xb7, 0x59, 0xeb, 0xfa,
-	0x07, 0xbb, 0x65, 0x6d, 0x99, 0x7b, 0x2e, 0xff, 0xc9, 0x73, 0xf1, 0xd2,
-	0xc9, 0xea, 0xf4, 0x44, 0x5e, 0x6f, 0x89, 0xfe, 0x29, 0xfc, 0x49, 0xba,
-	0x1e, 0x0c, 0xa9, 0x9c, 0x25, 0xe4, 0x28, 0xdd, 0xa7, 0xf0, 0x5a, 0xf3,
-	0x7e, 0xf2, 0xe0, 0xfd, 0x8f, 0x89, 0x5c, 0x4d, 0x29, 0x3b, 0x06, 0x15,
-	0x3c, 0x00, 0xb3, 0x90, 0x0b, 0x66, 0x7d, 0x2e, 0x98, 0x19, 0xea, 0x7b,
-	0xa7, 0x38, 0x3e, 0xbd, 0xf2, 0x99, 0x6e, 0x59, 0x2f, 0x8e, 0x58, 0xe2,
-	0xbc, 0xfa, 0xbe, 0xd5, 0x7a, 0x7f, 0xce, 0x6b, 0x15, 0xfe, 0x26, 0xd7,
-	0x5a, 0x5f, 0x27, 0x72, 0x5a, 0x82, 0xf5, 0x30, 0xf8, 0x8e, 0xeb, 0x3c,
-	0xe6, 0x38, 0xe6, 0x9a, 0xe3, 0x88, 0x6b, 0x8e, 0x77, 0x37, 0x98, 0x23,
-	0xf3, 0xf8, 0xe2, 0x69, 0xfe, 0xbf, 0xdd, 0xb9, 0xca, 0x79, 0xce, 0x0b,
-	0x78, 0xb6, 0x53, 0x3a, 0x18, 0x52, 0xb2, 0xe3, 0xfb, 0xaa, 0x16, 0xdd,
-	0x6b, 0xce, 0xff, 0x40, 0x8d, 0xf7, 0xcd, 0x8d, 0xab, 0xee, 0xfa, 0xe3,
-	0x97, 0x28, 0x26, 0xeb, 0xc8, 0x15, 0x6d, 0x7f, 0xb5, 0x81, 0x1f, 0xfa,
-	0x41, 0xa1, 0xff, 0xcc, 0xcb, 0x78, 0xd0, 0x80, 0xec, 0xbf, 0x16, 0xa0,
-	0xd5, 0x72, 0x2d, 0xaf, 0x5f, 0xd5, 0xee, 0xdc, 0x1f, 0xbc, 0xb3, 0x75,
-	0xbc, 0x38, 0xff, 0x88, 0xf0, 0xe5, 0xc9, 0xf8, 0x51, 0x42, 0xd5, 0x23,
-	0xdb, 0x16, 0x72, 0x03, 0x0a, 0x6b, 0xf0, 0xbf, 0x36, 0xaa, 0xdd, 0xc5,
-	0xb5, 0xf0, 0x03, 0x6a, 0x3b, 0xfe, 0x84, 0xe0, 0x89, 0xd2, 0x3f, 0x26,
-	0xeb, 0x6f, 0x0b, 0x6b, 0x27, 0x45, 0xcd, 0x6b, 0x54, 0xd5, 0xf1, 0x26,
-	0xa9, 0x43, 0xe8, 0xb9, 0xb7, 0x5f, 0x7f, 0xfb, 0x5c, 0x70, 0xe7, 0xf5,
-	0xb7, 0xee, 0x6b, 0x76, 0x56, 0x7f, 0x6b, 0xf2, 0xda, 0x8d, 0x65, 0x59,
-	0x7f, 0x5b, 0x1d, 0x93, 0x91, 0xfe, 0xc0, 0xa4, 0x4b, 0x7f, 0x90, 0xfa,
-	0xfa, 0x6f, 0xb9, 0xf2, 0xb7, 0x65, 0x6d, 0x6d, 0xa1, 0xac, 0xb3, 0xca,
-	0xda, 0x5a, 0x99, 0xef, 0xed, 0xee, 0x03, 0x23, 0x63, 0x3f, 0xf2, 0x39,
-	0x9d, 0x35, 0xb1, 0x1f, 0x59, 0x53, 0x6b, 0x19, 0x8d, 0x6c, 0x38, 0xd1,
-	0xe7, 0xa2, 0x8f, 0xba, 0x22, 0x8c, 0xbb, 0xed, 0x0d, 0xfa, 0x21, 0x44,
-	0x1a, 0xf4, 0x43, 0x70, 0xf3, 0x7e, 0xb7, 0x8e, 0x05, 0x9d, 0x18, 0xb2,
-	0x11, 0xba, 0x30, 0xfa, 0x19, 0x84, 0xe9, 0x74, 0x59, 0xf7, 0xbc, 0x8f,
-	0x12, 0x4a, 0xf7, 0x3c, 0xbd, 0xa2, 0xf9, 0xd1, 0x48, 0x0d, 0x3f, 0xf2,
-	0xd2, 0x45, 0x6d, 0x95, 0xe7, 0xa3, 0xe9, 0x35, 0xe5, 0xa2, 0xd7, 0x94,
-	0x07, 0xbd, 0x8a, 0x67, 0x34, 0x98, 0xf7, 0xf7, 0xd5, 0x35, 0xf8, 0x4f,
-	0x84, 0xd0, 0xb3, 0x85, 0x79, 0x6a, 0x50, 0xe9, 0x7f, 0x2e, 0x7a, 0x3d,
-	0xc5, 0xf4, 0xaa, 0xcf, 0x63, 0xbe, 0x0d, 0x73, 0x41, 0x95, 0xce, 0x38,
-	0xe8, 0x3b, 0x74, 0xf1, 0x1b, 0x22, 0x4f, 0xaa, 0xda, 0x5e, 0xd4, 0xfa,
-	0xc4, 0x3e, 0x41, 0x4b, 0xd7, 0xfd, 0xc8, 0x5b, 0xd1, 0xe7, 0x4c, 0xe5,
-	0x27, 0xd3, 0xb0, 0x68, 0xae, 0xd2, 0x39, 0x2a, 0xfa, 0x86, 0xc8, 0xf1,
-	0x75, 0xcd, 0xed, 0x43, 0x9e, 0x9b, 0x3e, 0xaf, 0x65, 0xe6, 0xb5, 0x2a,
-	0x7f, 0xc6, 0xe5, 0xaa, 0x9e, 0x83, 0xf0, 0x1d, 0x75, 0x26, 0x0c, 0x27,
-	0x2e, 0x72, 0x4c, 0x7b, 0x1c, 0xf8, 0xc9, 0xa2, 0x4c, 0xfb, 0x3d, 0x09,
-	0xe4, 0x33, 0xf7, 0x2c, 0x59, 0x74, 0x3c, 0x73, 0xff, 0x5d, 0x12, 0x57,
-	0xce, 0x8a, 0x3e, 0x92, 0xe8, 0x67, 0x16, 0x63, 0xf9, 0x1c, 0xf5, 0x4f,
-	0xd3, 0xf9, 0x62, 0x0b, 0x15, 0x58, 0xbb, 0xf7, 0x3b, 0x79, 0xe1, 0xeb,
-	0x63, 0x9e, 0x94, 0x45, 0x2f, 0x51, 0x63, 0xb9, 0x99, 0xef, 0xdb, 0x4f,
-	0xab, 0xb9, 0x31, 0xd1, 0x13, 0x4a, 0xf6, 0x17, 0xc1, 0x58, 0x1f, 0xf5,
-	0x3a, 0x07, 0xfb, 0xa8, 0xed, 0xb3, 0x22, 0xc7, 0xb2, 0x90, 0x3d, 0x2b,
-	0x3f, 0xf3, 0x0f, 0xa8, 0x67, 0xf0, 0xf3, 0x8a, 0x7f, 0x4a, 0x91, 0x5e,
-	0xcb, 0x65, 0xcb, 0xb9, 0xff, 0xbc, 0xf5, 0x95, 0xa3, 0x3b, 0xd2, 0x57,
-	0x52, 0x89, 0x8a, 0xbe, 0xe2, 0xbe, 0x77, 0x39, 0x07, 0xa6, 0x5f, 0xf6,
-	0x7b, 0x00, 0x0c, 0xda, 0xa1, 0x8b, 0x25, 0x00, 0x4b, 0x63, 0xc6, 0x0e,
-	0x45, 0xfd, 0x53, 0xb4, 0x50, 0x1c, 0x32, 0x92, 0x59, 0xe8, 0xcc, 0xfc,
-	0x99, 0x8f, 0xee, 0x91, 0x3e, 0x1a, 0x7d, 0x0d, 0xf8, 0xca, 0x6e, 0x1e,
-	0xff, 0x7a, 0xbf, 0xcc, 0xcb, 0x76, 0x9f, 0xef, 0xe2, 0xf3, 0x7b, 0x42,
-	0xd5, 0xe7, 0x77, 0xf1, 0xf9, 0xde, 0x04, 0xf6, 0xd0, 0x58, 0x82, 0x5f,
-	0xd2, 0xa1, 0x34, 0xef, 0xcd, 0x42, 0x91, 0x65, 0xeb, 0xcb, 0xcc, 0x47,
-	0x57, 0xf4, 0xb8, 0x3e, 0xd4, 0xec, 0x88, 0x3d, 0x31, 0x78, 0xcc, 0xb9,
-	0xcc, 0x04, 0x8f, 0x1b, 0x24, 0xff, 0xcb, 0x6c, 0x8b, 0xae, 0x68, 0x5c,
-	0xd5, 0xf9, 0xf6, 0xdf, 0xe8, 0x93, 0x39, 0x55, 0xdf, 0xdd, 0x23, 0xe1,
-	0xe7, 0x08, 0x9e, 0x72, 0x9e, 0xe1, 0xf2, 0xbc, 0xc0, 0x43, 0x7b, 0xda,
-	0x2a, 0x3f, 0xbf, 0x13, 0x78, 0xd5, 0x8a, 0xbc, 0xd9, 0xc0, 0x12, 0xf3,
-	0xc5, 0x19, 0xc7, 0x4c, 0x97, 0x73, 0xd5, 0x1e, 0x1f, 0x90, 0xd7, 0xbf,
-	0xd9, 0x27, 0xfb, 0x83, 0x7e, 0x6b, 0x40, 0xf7, 0x48, 0x94, 0x32, 0x07,
-	0xf9, 0xcb, 0x3e, 0x01, 0x1b, 0xff, 0x32, 0xf8, 0xa5, 0xc1, 0xdf, 0x79,
-	0x3d, 0x09, 0xcc, 0xf1, 0x4a, 0x9f, 0xee, 0x17, 0x23, 0xd7, 0x15, 0xe7,
-	0xf9, 0x46, 0x78, 0x5d, 0xfa, 0xfc, 0x0c, 0x1f, 0x7b, 0xed, 0x2f, 0xee,
-	0xd5, 0x96, 0x90, 0xfd, 0xc5, 0xda, 0x12, 0xc9, 0x09, 0xb9, 0xcf, 0x15,
-	0x9f, 0x6e, 0xa8, 0xec, 0xd3, 0x3d, 0x9f, 0xb9, 0xd5, 0x07, 0xff, 0x86,
-	0xb1, 0xc4, 0xfb, 0x1d, 0x7c, 0x9e, 0xc7, 0xa2, 0x56, 0x21, 0xcd, 0x9f,
-	0x1d, 0x2a, 0xaf, 0xa7, 0x1e, 0x57, 0x64, 0x9e, 0x84, 0x96, 0x5b, 0xb8,
-	0xf6, 0x43, 0xbe, 0x87, 0x94, 0x5d, 0x8d, 0x9f, 0x43, 0x75, 0x79, 0x30,
-	0xf5, 0x38, 0xb6, 0x99, 0x1f, 0x56, 0xc4, 0x13, 0x3d, 0xf0, 0x6c, 0xb3,
-	0x7e, 0x06, 0xd7, 0x84, 0x1f, 0x2d, 0x56, 0x47, 0xaf, 0xa0, 0xe3, 0x00,
-	0xfd, 0xce, 0x62, 0x8a, 0x76, 0xf1, 0x5e, 0xfd, 0xa6, 0xf1, 0x00, 0xe2,
-	0xed, 0x24, 0x73, 0x9e, 0x18, 0xc6, 0x19, 0x67, 0xe2, 0x94, 0x11, 0x01,
-	0xbf, 0x2c, 0x05, 0x9c, 0x0e, 0x6a, 0x66, 0x5a, 0xfd, 0x65, 0x1a, 0x65,
-	0xfb, 0x0f, 0x34, 0xeb, 0x84, 0xe2, 0x04, 0x7a, 0xb3, 0xcd, 0x43, 0xac,
-	0x13, 0xc7, 0x8a, 0xc0, 0x67, 0x83, 0x3e, 0x9f, 0x23, 0xfa, 0x5c, 0x6e,
-	0xd4, 0xfc, 0x26, 0x39, 0x56, 0xe5, 0x77, 0xdb, 0x8c, 0xf2, 0x3c, 0xe2,
-	0xc5, 0x2f, 0xd3, 0xfb, 0xa2, 0xcf, 0x09, 0xe0, 0xa8, 0xf7, 0xfd, 0x4b,
-	0x74, 0x32, 0x81, 0x79, 0x6f, 0x9f, 0x3e, 0x8f, 0xef, 0x88, 0x3e, 0xdb,
-	0x3c, 0xe8, 0xf3, 0xc5, 0x7e, 0x89, 0x37, 0x25, 0xc6, 0xd1, 0x36, 0x9a,
-	0xcb, 0x22, 0x07, 0xec, 0xd3, 0xe8, 0x3b, 0x95, 0x4d, 0x32, 0x5f, 0x4a,
-	0x56, 0xf8, 0xd2, 0x85, 0x28, 0x1b, 0xc3, 0x4c, 0xe3, 0xe8, 0xcb, 0xa6,
-	0xf2, 0x7e, 0xb0, 0x8e, 0x01, 0x1a, 0x5d, 0x6e, 0xe7, 0x6b, 0x69, 0x3d,
-	0x3a, 0x15, 0x51, 0xb5, 0xfe, 0xb6, 0x15, 0x63, 0xfe, 0x78, 0x9e, 0x69,
-	0x39, 0x9d, 0xbd, 0x97, 0x0a, 0xc1, 0x21, 0x1a, 0x59, 0xd6, 0xfd, 0x4d,
-	0x44, 0xce, 0xc6, 0xa0, 0xe4, 0x49, 0x7a, 0xdd, 0x9f, 0x10, 0xbe, 0x0b,
-	0xeb, 0xd2, 0xc7, 0xb5, 0xee, 0xf6, 0x2d, 0xf8, 0xd2, 0x25, 0x45, 0xb3,
-	0xa5, 0xcb, 0xd1, 0x30, 0xa5, 0xa2, 0x53, 0xaf, 0xf4, 0x03, 0xff, 0x47,
-	0x2e, 0xc1, 0x0f, 0x07, 0x1e, 0x6d, 0x51, 0x22, 0x53, 0x0b, 0x8b, 0x21,
-	0x5e, 0x37, 0x7e, 0x2f, 0x7d, 0x30, 0x17, 0x7e, 0x40, 0xc8, 0xfe, 0xd1,
-	0x4b, 0x3c, 0x4e, 0xca, 0x26, 0xc5, 0x37, 0xbc, 0xf0, 0x50, 0xf7, 0xc5,
-	0xd4, 0xb8, 0x28, 0x73, 0x3d, 0x59, 0x7f, 0x33, 0x13, 0xfe, 0x5a, 0x9c,
-	0xbc, 0xe6, 0x3b, 0xba, 0x68, 0xd1, 0xb1, 0x8c, 0xfd, 0xf5, 0x14, 0x4d,
-	0x31, 0x5d, 0xbb, 0xe5, 0x05, 0x8f, 0x27, 0xe0, 0xd9, 0x34, 0xd3, 0x3e,
-	0xdb, 0xcd, 0x59, 0x4b, 0xe6, 0xdd, 0x89, 0xde, 0x73, 0x38, 0x46, 0xdd,
-	0xf1, 0x5f, 0xf5, 0x6b, 0x79, 0x90, 0xcc, 0xa2, 0x8e, 0x90, 0x3f, 0xf3,
-	0x3c, 0x1e, 0xb9, 0xff, 0x39, 0xdc, 0x07, 0xf2, 0x0e, 0x73, 0xe7, 0xe3,
-	0x55, 0xb9, 0xaf, 0x23, 0x7c, 0x6f, 0xd4, 0xdd, 0x1f, 0x2b, 0x4e, 0xf2,
-	0xfe, 0x76, 0x09, 0xde, 0x2c, 0xf7, 0x73, 0x9a, 0xce, 0x79, 0xf2, 0x15,
-	0xb9, 0x2f, 0x49, 0x17, 0x7d, 0x27, 0x05, 0x7d, 0x4f, 0x8b, 0xfd, 0x48,
-	0xe6, 0x0c, 0xd6, 0xd7, 0xb4, 0xef, 0x81, 0xed, 0xec, 0x5c, 0x40, 0xe7,
-	0x06, 0xf2, 0xf7, 0x0f, 0xfb, 0x45, 0x5e, 0x22, 0xec, 0xef, 0x1c, 0x3e,
-	0xa7, 0xe9, 0x79, 0x96, 0xeb, 0x2f, 0x64, 0x5a, 0xe8, 0x6a, 0xb6, 0x85,
-	0xde, 0xc9, 0x0e, 0xd1, 0x95, 0xc5, 0x6e, 0x3a, 0xc7, 0x3a, 0xf3, 0x39,
-	0x27, 0x60, 0xa5, 0xa9, 0x1b, 0xf1, 0x45, 0xe4, 0x0c, 0x31, 0xdd, 0x61,
-	0x3c, 0xf4, 0xbf, 0xe8, 0x5e, 0xc6, 0x39, 0xd6, 0xbd, 0x5b, 0xe9, 0x3d,
-	0x7e, 0x66, 0x3a, 0xa3, 0x73, 0x1d, 0xe0, 0x93, 0x1f, 0x2b, 0xeb, 0xaf,
-	0x5b, 0xe3, 0x88, 0xb9, 0x05, 0x8e, 0x4c, 0x8b, 0xf8, 0xd6, 0xc2, 0x22,
-	0xff, 0xbe, 0x08, 0xff, 0x39, 0xc3, 0x9b, 0xf9, 0xf3, 0x93, 0x01, 0x8c,
-	0xc7, 0x39, 0x47, 0xe6, 0x4a, 0x8a, 0xb5, 0x85, 0xf8, 0xd8, 0x27, 0x6a,
-	0xa4, 0x25, 0x1c, 0x5a, 0x79, 0x7d, 0x3e, 0x31, 0x3e, 0xb9, 0xda, 0x4a,
-	0xf3, 0x39, 0xd6, 0x41, 0x72, 0x7e, 0xb6, 0x61, 0x30, 0xf6, 0xef, 0x54,
-	0x6f, 0x61, 0xdc, 0xbf, 0x8b, 0xd2, 0x62, 0x1c, 0x7f, 0xae, 0x76, 0xd1,
-	0x42, 0xae, 0x43, 0x1d, 0xdf, 0x2b, 0x72, 0xdc, 0x65, 0x1f, 0x23, 0xfc,
-	0xb6, 0x19, 0x7f, 0x7b, 0x97, 0x71, 0x0a, 0x32, 0x55, 0xda, 0xa5, 0xe0,
-	0x35, 0x97, 0xeb, 0x7a, 0x22, 0x03, 0xe7, 0xa6, 0xe8, 0x25, 0x96, 0xb7,
-	0x23, 0x2f, 0xc3, 0x7f, 0xfc, 0x38, 0xf0, 0x26, 0x9f, 0xa2, 0x41, 0x3e,
-	0x46, 0x5f, 0x24, 0xbf, 0xa8, 0x73, 0x8a, 0x05, 0x27, 0x44, 0x6d, 0x88,
-	0xa4, 0xd1, 0x59, 0xd1, 0x8b, 0xee, 0x2d, 0xc1, 0x9b, 0xec, 0x94, 0x65,
-	0x40, 0x1f, 0x81, 0x0f, 0x46, 0xe6, 0x60, 0x1d, 0x77, 0x7a, 0xde, 0xed,
-	0x9b, 0x19, 0xa7, 0x48, 0x3f, 0xf0, 0x5e, 0xd2, 0xac, 0xea, 0x2f, 0x20,
-	0xf8, 0xbd, 0xb9, 0x4f, 0xd7, 0x4b, 0xea, 0x63, 0x2d, 0x2b, 0xf4, 0x71,
-	0x47, 0xcd, 0xef, 0x66, 0xcd, 0xef, 0xe5, 0x7c, 0x39, 0x96, 0x79, 0x2c,
-	0xe7, 0x49, 0xf6, 0x28, 0x4a, 0x2e, 0x4b, 0xfc, 0x33, 0xf7, 0x8d, 0x99,
-	0x8f, 0x2a, 0x1d, 0x3c, 0xb9, 0x36, 0x1a, 0xea, 0x31, 0x26, 0x8c, 0xe4,
-	0xe4, 0x3f, 0x96, 0x22, 0x09, 0xe8, 0x45, 0x4f, 0xee, 0x51, 0xf9, 0xa7,
-	0x3c, 0xaf, 0x54, 0x18, 0xaa, 0xdb, 0xec, 0x5a, 0x07, 0xad, 0x8b, 0x9e,
-	0x5c, 0x42, 0xc7, 0xe0, 0xeb, 0x71, 0x9f, 0x94, 0xd9, 0x44, 0xe8, 0x73,
-	0x0e, 0x1a, 0xdf, 0x1f, 0xba, 0xc4, 0xfb, 0x19, 0x5f, 0xfb, 0x69, 0xe9,
-	0xa4, 0xe8, 0x71, 0x83, 0xb1, 0x5d, 0x34, 0x27, 0x74, 0x7e, 0xd6, 0x5f,
-	0xaa, 0xec, 0xaa, 0x29, 0xcc, 0x33, 0x85, 0xd8, 0x8a, 0xe1, 0xfc, 0xbe,
-	0x2f, 0x99, 0x97, 0xb1, 0xf2, 0x78, 0x4d, 0xac, 0x7c, 0x56, 0xc4, 0xca,
-	0x11, 0x27, 0x07, 0x5c, 0x01, 0x4b, 0xaf, 0x9c, 0x16, 0xec, 0x63, 0x98,
-	0x90, 0x1b, 0x7e, 0xee, 0xa2, 0xe0, 0x37, 0xe1, 0x98, 0x5f, 0xe6, 0x57,
-	0xc7, 0x79, 0xc6, 0x06, 0x5d, 0x60, 0x7c, 0xb0, 0x27, 0x36, 0x58, 0x97,
-	0x58, 0xc9, 0x7e, 0x99, 0xae, 0xe4, 0x9b, 0x58, 0xd7, 0x5b, 0xa0, 0x8d,
-	0x3c, 0xb1, 0x4e, 0xd8, 0x4d, 0x0b, 0x61, 0xc6, 0xb1, 0x89, 0x36, 0xde,
-	0x4f, 0xd6, 0x6b, 0x27, 0x98, 0xee, 0x78, 0xee, 0x2b, 0xb9, 0xd2, 0x8f,
-	0xd2, 0xe1, 0x88, 0x15, 0x9d, 0xea, 0x60, 0xbb, 0xc5, 0xe4, 0x7f, 0x87,
-	0xff, 0x77, 0x85, 0x00, 0x93, 0xc2, 0x2a, 0x7e, 0x67, 0x9d, 0x27, 0x53,
-	0xfa, 0xd1, 0x1c, 0x8f, 0x99, 0x9b, 0x82, 0xfd, 0x03, 0x3b, 0xcf, 0xe1,
-	0x7f, 0x39, 0x66, 0x65, 0x95, 0xf1, 0xfb, 0x62, 0x2a, 0x64, 0x08, 0xde,
-	0xbe, 0xce, 0x3c, 0xfe, 0x02, 0xcd, 0xf1, 0x1c, 0xae, 0x10, 0xae, 0xb5,
-	0x28, 0x19, 0xde, 0xc7, 0x78, 0xdf, 0xcd, 0x9f, 0xa8, 0xbf, 0x6a, 0xa7,
-	0x85, 0xc9, 0x31, 0x55, 0x7f, 0xf5, 0xbd, 0x06, 0xf5, 0x57, 0xb8, 0x8e,
-	0xe5, 0xfe, 0x62, 0xe9, 0xe6, 0x5c, 0xd8, 0xfd, 0x3c, 0x32, 0x92, 0xe1,
-	0x4e, 0xa1, 0x23, 0xad, 0xac, 0xfa, 0xf8, 0xd9, 0x11, 0x2b, 0x39, 0xc5,
-	0x73, 0xcc, 0xb9, 0xe7, 0x5d, 0xba, 0x19, 0x0b, 0x63, 0x9c, 0xbf, 0x66,
-	0x1c, 0xdb, 0xca, 0x53, 0x72, 0x3d, 0x85, 0x5c, 0xe9, 0xe7, 0xd1, 0xb0,
-	0x5e, 0x9f, 0xfb, 0x5a, 0xac, 0x03, 0xf4, 0xc4, 0x9f, 0x2b, 0x5d, 0xbe,
-	0x2b, 0x59, 0xd8, 0xdf, 0x06, 0xe3, 0x39, 0x66, 0x34, 0x44, 0xa9, 0x15,
-	0xa6, 0xef, 0x8b, 0x1d, 0xbe, 0x8d, 0xec, 0x95, 0x52, 0xb2, 0x2a, 0x97,
-	0xa5, 0xda, 0xef, 0x2e, 0x6d, 0xae, 0x21, 0x72, 0x96, 0x20, 0x33, 0x21,
-	0x2f, 0x53, 0x25, 0xbf, 0x03, 0xfd, 0x0e, 0xb6, 0xd0, 0x59, 0xe6, 0x57,
-	0x32, 0x1f, 0x89, 0x79, 0x27, 0xf3, 0x2c, 0x49, 0x2f, 0xf1, 0xaa, 0xd7,
-	0x0d, 0x48, 0x9c, 0x1d, 0xa9, 0xe4, 0x41, 0xba, 0xe2, 0xe9, 0x01, 0x57,
-	0x3c, 0xdd, 0x74, 0xe5, 0x41, 0x06, 0x85, 0x3e, 0x56, 0xd1, 0xa1, 0x82,
-	0x4a, 0x87, 0x82, 0xae, 0x25, 0x79, 0x59, 0xa1, 0xcc, 0xcb, 0x76, 0x6f,
-	0xc1, 0xcb, 0xbc, 0x6c, 0xd3, 0x75, 0xc5, 0x37, 0xec, 0x30, 0xe4, 0xfc,
-	0xe5, 0xe2, 0x34, 0xbd, 0xcd, 0x3c, 0xe2, 0xad, 0x62, 0x98, 0xf9, 0xc6,
-	0x24, 0xf3, 0x8d, 0x09, 0xe6, 0x1b, 0x0e, 0xc3, 0xc0, 0xe2, 0xb5, 0x5f,
-	0xf3, 0x5d, 0x59, 0x84, 0xbc, 0x98, 0xa2, 0xe7, 0x8b, 0xe0, 0xc1, 0x93,
-	0xac, 0xf3, 0x5c, 0xf3, 0x6d, 0x2c, 0x76, 0x31, 0xbe, 0x4a, 0x3d, 0xa7,
-	0xda, 0x8e, 0x41, 0xaf, 0x15, 0xf8, 0x87, 0xaf, 0x82, 0xcf, 0xbc, 0x91,
-	0xa2, 0x4e, 0x86, 0x3d, 0xe0, 0xbc, 0x8e, 0xde, 0x14, 0xaf, 0x81, 0x96,
-	0xd1, 0x13, 0xf8, 0xbb, 0xe3, 0x53, 0x3c, 0xf7, 0x4e, 0xdf, 0x02, 0xef,
-	0xcb, 0xd3, 0xe1, 0x94, 0xd9, 0xcb, 0x38, 0x7f, 0xac, 0x82, 0xf3, 0xa9,
-	0x34, 0xaf, 0xa0, 0x67, 0xb9, 0x9b, 0xc6, 0x0e, 0x44, 0xf7, 0xf6, 0x30,
-	0x9d, 0x22, 0x37, 0xa2, 0xd2, 0xa7, 0xc7, 0x4f, 0x27, 0x83, 0x6d, 0xaa,
-	0xbf, 0x8f, 0xc5, 0xf2, 0xf1, 0x03, 0xbe, 0xcf, 0x2d, 0x5f, 0x3a, 0xfb,
-	0x2a, 0x3f, 0x03, 0xc7, 0x5f, 0x85, 0xff, 0x93, 0xed, 0x83, 0x56, 0xe1,
-	0x3f, 0x2a, 0x88, 0xb1, 0x38, 0xb6, 0x27, 0x98, 0x97, 0x85, 0xd7, 0x0d,
-	0x7b, 0x3a, 0x62, 0x30, 0xd1, 0x75, 0x99, 0xbc, 0xde, 0xd2, 0xa0, 0x8c,
-	0xc1, 0xed, 0xdd, 0x2b, 0xf9, 0x06, 0xe3, 0x66, 0x30, 0x22, 0x6c, 0xb4,
-	0xa6, 0x25, 0x29, 0x27, 0x0b, 0xbc, 0xcf, 0x2b, 0xe1, 0x09, 0xde, 0xe7,
-	0x0e, 0x25, 0x23, 0x53, 0xfc, 0xbb, 0x90, 0xbf, 0x2c, 0x2b, 0x87, 0xd0,
-	0xb3, 0xda, 0x14, 0xfd, 0x20, 0x66, 0xd1, 0x6f, 0xa7, 0x83, 0xef, 0x6b,
-	0x33, 0xd6, 0x82, 0x4f, 0x7c, 0xe0, 0x4b, 0x66, 0xf1, 0x5c, 0xe0, 0x21,
-	0x7f, 0xcf, 0x4f, 0xd1, 0x85, 0x8c, 0x9e, 0xc3, 0x80, 0x61, 0xbc, 0x84,
-	0x79, 0xf8, 0x68, 0xb7, 0xf3, 0x43, 0x86, 0x17, 0x1f, 0xff, 0x71, 0xed,
-	0x9c, 0x86, 0xd5, 0x9c, 0xd0, 0xd3, 0xb2, 0x05, 0x3d, 0x7c, 0x08, 0xbd,
-	0x8f, 0x0a, 0xa2, 0xe7, 0x64, 0xb3, 0xb0, 0x4d, 0x0b, 0xc2, 0xc6, 0x28,
-	0x85, 0x2a, 0x7d, 0x30, 0xef, 0xa9, 0x39, 0xf7, 0x13, 0x5f, 0x7a, 0xf1,
-	0xa0, 0xd0, 0xc5, 0x46, 0x0e, 0xec, 0x55, 0xf5, 0xa7, 0x5d, 0xe2, 0xbe,
-	0xc6, 0x32, 0x7e, 0x7b, 0x50, 0xfd, 0xf6, 0x49, 0xa1, 0x03, 0x23, 0x2f,
-	0x2e, 0xb0, 0x24, 0xf0, 0x9c, 0xf7, 0xd7, 0x99, 0x60, 0x3c, 0x0f, 0xad,
-	0xc0, 0x77, 0x2f, 0xe0, 0xa9, 0xe1, 0x01, 0x58, 0x00, 0xf7, 0x3b, 0x14,
-	0xde, 0xdb, 0x56, 0xdc, 0xaf, 0xd7, 0xdd, 0x08, 0xce, 0xac, 0xd3, 0x64,
-	0xb0, 0x56, 0xac, 0x69, 0x8f, 0x2f, 0x92, 0xb7, 0x8c, 0xf4, 0x22, 0x6c,
-	0x1a, 0xd4, 0xb5, 0xdc, 0x85, 0xbc, 0x29, 0x9e, 0xc3, 0x1e, 0x8a, 0x24,
-	0x30, 0x2f, 0x8c, 0xd3, 0x30, 0xf8, 0xb7, 0x1a, 0x58, 0xb8, 0xaf, 0xeb,
-	0x56, 0xd7, 0xb5, 0x8a, 0xbd, 0x20, 0x03, 0xcf, 0xd1, 0xcf, 0xc6, 0x73,
-	0xf1, 0x7c, 0x5c, 0x87, 0xfb, 0xc9, 0xfb, 0xf6, 0x31, 0x7f, 0x8e, 0x4e,
-	0xc9, 0x7b, 0x19, 0x97, 0xe4, 0x6f, 0x7d, 0x8e, 0xf7, 0x7c, 0xe5, 0xfe,
-	0xf9, 0x54, 0xbf, 0x1e, 0xec, 0x5f, 0x37, 0xe5, 0x85, 0x8f, 0x13, 0xbf,
-	0x75, 0x8a, 0xdf, 0xa2, 0x4e, 0xa7, 0xd8, 0xd7, 0xf3, 0x7c, 0x3c, 0x9f,
-	0xed, 0xf2, 0xc1, 0x36, 0x4f, 0x27, 0x3a, 0x7d, 0xf9, 0x3c, 0xd6, 0xdb,
-	0xe9, 0x8b, 0x33, 0xee, 0xc7, 0xb2, 0xf1, 0xd2, 0x82, 0xe0, 0x31, 0xac,
-	0xd3, 0xf6, 0xda, 0xe6, 0x49, 0xe3, 0x4f, 0x86, 0x64, 0x6f, 0x5b, 0x7c,
-	0x67, 0xfa, 0xcb, 0x30, 0xfd, 0x65, 0x98, 0xfe, 0x32, 0x4c, 0x7f, 0x19,
-	0xa6, 0x3f, 0xb6, 0x4b, 0xdf, 0x64, 0x99, 0xf1, 0x6d, 0x96, 0x19, 0x92,
-	0x66, 0x23, 0xca, 0x8f, 0xa9, 0x69, 0xb6, 0xb6, 0x3e, 0x53, 0xd3, 0x28,
-	0xe4, 0x34, 0xf9, 0x0e, 0x8f, 0x57, 0xd3, 0xea, 0x55, 0xa6, 0xd5, 0xa6,
-	0x99, 0x7e, 0xba, 0x91, 0xc3, 0x9e, 0xd9, 0xd6, 0x79, 0xe6, 0xd1, 0x71,
-	0x3f, 0x74, 0xaa, 0x00, 0xd3, 0x13, 0x74, 0x4a, 0x9b, 0xe1, 0xde, 0x4f,
-	0x37, 0x99, 0x4f, 0xdf, 0xc8, 0x81, 0x76, 0xef, 0x52, 0xc7, 0x19, 0xa6,
-	0x5d, 0xc8, 0xb9, 0x25, 0xdf, 0xd5, 0xac, 0xc1, 0xba, 0x57, 0xc0, 0x4c,
-	0x12, 0xf8, 0xa8, 0xd0, 0xc7, 0x78, 0xdf, 0xd7, 0x99, 0xdf, 0xc3, 0x57,
-	0x87, 0xbe, 0x5f, 0x79, 0x1f, 0xcb, 0x89, 0xd0, 0x15, 0xe6, 0xa3, 0xa7,
-	0x73, 0x4b, 0x4c, 0xef, 0xbd, 0xf4, 0x85, 0x1c, 0xe4, 0x31, 0x60, 0xc4,
-	0xc7, 0x79, 0x12, 0x3e, 0x30, 0x63, 0x06, 0x6b, 0x1f, 0x4b, 0x19, 0x02,
-	0x4f, 0x9e, 0x01, 0x1c, 0x18, 0xf6, 0x67, 0xf6, 0xa2, 0x67, 0x7d, 0xc4,
-	0x68, 0x56, 0x3e, 0x45, 0x7c, 0xc7, 0x78, 0x8c, 0x05, 0xdc, 0x70, 0xdc,
-	0x28, 0xfe, 0x88, 0xf7, 0x42, 0x84, 0x19, 0x1e, 0xb5, 0x7c, 0xeb, 0x02,
-	0x7a, 0x91, 0x02, 0x5e, 0xd3, 0x51, 0x3f, 0x6a, 0xc5, 0xe9, 0x39, 0xbc,
-	0xff, 0xe0, 0x85, 0x22, 0xe6, 0xbd, 0x48, 0x0b, 0x41, 0xf0, 0x21, 0x3b,
-	0x7c, 0x9d, 0x24, 0xec, 0x5a, 0x59, 0xbf, 0xfc, 0xbc, 0x37, 0x6f, 0xb3,
-	0xa2, 0x42, 0x1f, 0x6e, 0x61, 0xfb, 0x06, 0xb0, 0x79, 0x8b, 0x71, 0x2d,
-	0x0c, 0x9b, 0x5f, 0xf1, 0xb5, 0x37, 0x99, 0xe7, 0x60, 0xcf, 0x3a, 0x85,
-	0x8c, 0xf1, 0xe2, 0x65, 0x1b, 0x8a, 0x97, 0x39, 0x2e, 0x5e, 0x96, 0x2e,
-	0xf3, 0x32, 0xc6, 0x09, 0xc1, 0xc3, 0xc0, 0xa3, 0x66, 0x59, 0x4f, 0x94,
-	0xdf, 0xa1, 0xff, 0xed, 0x16, 0x3c, 0x8b, 0x79, 0x3d, 0xdb, 0x0d, 0x85,
-	0x62, 0xca, 0x77, 0x48, 0xf0, 0x0e, 0x8d, 0xd7, 0xff, 0xa3, 0xe8, 0xa1,
-	0x55, 0xf0, 0x81, 0xf4, 0x2c, 0xf8, 0x95, 0xd7, 0xf8, 0xff, 0x02, 0x6c,
-	0x79, 0xbc, 0x13, 0x7a, 0x8d, 0xf9, 0x58, 0x21, 0x0c, 0x9b, 0xb5, 0x43,
-	0xd9, 0x36, 0xe8, 0xbb, 0xb5, 0x07, 0xb9, 0x96, 0x56, 0xb4, 0xcc, 0xc7,
-	0x76, 0x2b, 0xbf, 0x05, 0xfc, 0x8c, 0xd8, 0xeb, 0x3a, 0x5d, 0xc0, 0x82,
-	0x2e, 0xc0, 0x63, 0x03, 0x0c, 0x1f, 0xd1, 0x1b, 0x9c, 0xe8, 0x16, 0xc3,
-	0x01, 0xfb, 0x7c, 0x0b, 0xfb, 0xcc, 0xba, 0x2c, 0x05, 0xe6, 0xa6, 0x02,
-	0x03, 0x98, 0xdf, 0xc2, 0x6a, 0x85, 0x1f, 0x9e, 0xcf, 0x0c, 0x18, 0x85,
-	0xac, 0x9c, 0xe3, 0xca, 0xb8, 0xe4, 0x79, 0x85, 0x3c, 0x7a, 0x7b, 0x89,
-	0xb9, 0xf2, 0x1c, 0xf5, 0xfa, 0x04, 0xff, 0x52, 0x74, 0xbf, 0x1d, 0x5a,
-	0x4b, 0x30, 0x5d, 0x61, 0x4f, 0x52, 0x2e, 0x9c, 0x79, 0x94, 0x9f, 0x8f,
-	0x73, 0x8d, 0xd7, 0x71, 0xb3, 0xbc, 0x8e, 0x08, 0xaf, 0x03, 0x63, 0x6f,
-	0xf9, 0x6e, 0xa8, 0x75, 0xdc, 0x28, 0xaf, 0x63, 0x56, 0xad, 0x83, 0xd2,
-	0xc6, 0xcc, 0x6e, 0xa5, 0xc7, 0x6f, 0x79, 0xcf, 0xd6, 0x28, 0xeb, 0x27,
-	0xe9, 0x55, 0xc0, 0xf3, 0x1e, 0x85, 0x2f, 0x6e, 0x7f, 0xa8, 0x7b, 0x6e,
-	0xf6, 0xc4, 0x75, 0xfa, 0x5d, 0xba, 0x29, 0xf4, 0x93, 0x61, 0xd6, 0x4f,
-	0x70, 0x9e, 0x16, 0xc0, 0x87, 0xd3, 0x41, 0xf4, 0x9b, 0x1d, 0x64, 0x98,
-	0xb1, 0x5d, 0x35, 0xc5, 0x9f, 0xc2, 0x4f, 0x86, 0xfb, 0xe8, 0xeb, 0xbf,
-	0x48, 0x37, 0x17, 0xc1, 0xab, 0xa1, 0x8f, 0xca, 0x9e, 0xb4, 0x37, 0xd7,
-	0xa4, 0x9f, 0x36, 0xee, 0xe9, 0xa7, 0x85, 0x8f, 0x36, 0x0c, 0x7d, 0xdd,
-	0x84, 0x3f, 0x37, 0x26, 0xde, 0x67, 0xc1, 0xc7, 0x45, 0xdc, 0xcb, 0x8b,
-	0xef, 0x4c, 0xbb, 0x72, 0xdc, 0x90, 0x73, 0x92, 0x62, 0x3e, 0xe2, 0x98,
-	0x4d, 0x86, 0xac, 0x9d, 0xb9, 0x5c, 0xd4, 0x3a, 0x51, 0x9c, 0xf7, 0xc8,
-	0x09, 0x1b, 0x46, 0x44, 0xf8, 0x0c, 0x5a, 0x9d, 0x0e, 0x6a, 0x61, 0x39,
-	0x79, 0x8a, 0xd0, 0x13, 0xcd, 0xb6, 0xe0, 0xcb, 0xbf, 0xc0, 0xb8, 0xb7,
-	0x10, 0xb6, 0x43, 0x9f, 0x13, 0xf6, 0x25, 0xe4, 0x07, 0xde, 0xa7, 0x02,
-	0x18, 0x63, 0x0e, 0xfc, 0x7d, 0x15, 0xfd, 0x30, 0xc3, 0xbc, 0x7e, 0xf8,
-	0x81, 0x47, 0xad, 0x77, 0x58, 0xee, 0x5c, 0x10, 0xfe, 0x95, 0xb3, 0x94,
-	0x66, 0x3a, 0x3c, 0x2c, 0xe8, 0xd0, 0x18, 0x66, 0x6a, 0x61, 0xfa, 0x41,
-	0x8e, 0xc1, 0x98, 0xe8, 0xbf, 0x23, 0x6d, 0x16, 0x5e, 0xe5, 0x9a, 0xea,
-	0x6b, 0x90, 0x00, 0x6f, 0xd8, 0xbe, 0x6f, 0x21, 0xf1, 0x91, 0x7d, 0x2a,
-	0x6e, 0x5d, 0xab, 0xd6, 0x87, 0x0d, 0xfb, 0xcc, 0x12, 0x7d, 0x1f, 0x01,
-	0x3b, 0xe1, 0x17, 0x34, 0x26, 0x19, 0x6e, 0xfa, 0xdd, 0x35, 0x6e, 0xfb,
-	0xff, 0x29, 0x51, 0x9f, 0xff, 0x46, 0x51, 0xca, 0xd8, 0x34, 0xdb, 0xe6,
-	0x0b, 0x07, 0xdc, 0x3a, 0x87, 0x9d, 0x8d, 0x09, 0x9f, 0xcc, 0x00, 0x45,
-	0x97, 0x27, 0xe9, 0xb1, 0x0c, 0x78, 0x14, 0x5d, 0x8f, 0x3a, 0x78, 0xc3,
-	0x06, 0x68, 0x79, 0x92, 0xe2, 0x45, 0xc0, 0xc8, 0x47, 0x0b, 0x2c, 0x05,
-	0xd2, 0x59, 0xc4, 0xee, 0xf9, 0x7b, 0x1e, 0xef, 0x57, 0xf9, 0x15, 0xe5,
-	0xf7, 0x1e, 0xa2, 0xd8, 0x32, 0xa5, 0x92, 0xe1, 0x87, 0x45, 0xcf, 0xea,
-	0x64, 0x78, 0x5c, 0xf9, 0x68, 0x42, 0x7c, 0x1e, 0x7e, 0x2f, 0x8b, 0x1e,
-	0xcd, 0xd8, 0xa9, 0x24, 0x49, 0xdf, 0x03, 0xf1, 0x1c, 0x0c, 0x96, 0xad,
-	0xbb, 0x99, 0x57, 0x1c, 0x17, 0xfe, 0x07, 0xd6, 0x44, 0x16, 0x31, 0x1e,
-	0xbe, 0x83, 0x5e, 0x82, 0xbd, 0x95, 0xcc, 0x3e, 0xa0, 0xc6, 0x96, 0xc8,
-	0x64, 0x5c, 0x30, 0x7f, 0xc9, 0x49, 0x85, 0x8d, 0xca, 0xf5, 0xf0, 0x5d,
-	0x1c, 0x17, 0xfa, 0xe1, 0x30, 0xdb, 0x30, 0x62, 0x5c, 0x69, 0x4e, 0xf8,
-	0x21, 0xf8, 0x38, 0xff, 0xd3, 0x01, 0xfd, 0x6e, 0x03, 0x9c, 0x97, 0xfe,
-	0x09, 0xbe, 0x67, 0x9e, 0xe7, 0x51, 0x95, 0x17, 0x3f, 0x44, 0x91, 0x1d,
-	0xf8, 0x8b, 0x66, 0xef, 0xa8, 0xbf, 0x88, 0x61, 0xcd, 0xb2, 0xe5, 0x32,
-	0xd3, 0xc6, 0xdb, 0x5b, 0xda, 0x71, 0xef, 0x6b, 0x19, 0xcd, 0xb0, 0x32,
-	0xc5, 0xfb, 0x2f, 0xd0, 0xeb, 0x73, 0xa1, 0xf8, 0x29, 0xbc, 0x47, 0xc6,
-	0x97, 0x10, 0x3a, 0x6f, 0x88, 0x75, 0x17, 0xe8, 0x30, 0xa3, 0x22, 0xbe,
-	0x15, 0x79, 0xc2, 0x32, 0x16, 0xd6, 0xfa, 0xc9, 0x0f, 0xbf, 0x9a, 0xa3,
-	0x73, 0x22, 0x5a, 0x45, 0xfe, 0xba, 0x8c, 0x2b, 0x42, 0xfe, 0x82, 0x07,
-	0xfe, 0xc4, 0x97, 0x5c, 0xf3, 0xf7, 0xe9, 0x7c, 0xb7, 0x48, 0xb0, 0x9c,
-	0x4f, 0xa3, 0x78, 0x8a, 0xc6, 0x3d, 0x1d, 0xb3, 0x70, 0xbf, 0xd7, 0x0a,
-	0xb4, 0xeb, 0xd6, 0x19, 0xe0, 0x67, 0x12, 0x7b, 0x74, 0x01, 0x71, 0x5c,
-	0xa3, 0x2a, 0x1e, 0xd1, 0xc2, 0xfb, 0x04, 0x3b, 0x0f, 0xfe, 0xbb, 0xcf,
-	0xf2, 0x27, 0xe2, 0x0a, 0x27, 0x07, 0xa1, 0x27, 0xf5, 0x38, 0x8c, 0x33,
-	0x53, 0x38, 0xee, 0x67, 0xbb, 0x4b, 0xeb, 0xb5, 0xd2, 0xa7, 0xc4, 0xb6,
-	0x98, 0xda, 0x2f, 0xf8, 0x93, 0x46, 0x54, 0xbf, 0x01, 0x9b, 0xac, 0x5e,
-	0xc0, 0xe9, 0xe3, 0xa2, 0xc7, 0xad, 0x62, 0x10, 0xdb, 0xc9, 0x59, 0xc2,
-	0x3b, 0xb7, 0xd0, 0x77, 0xf3, 0x6e, 0xc0, 0x9e, 0xf7, 0xc8, 0x1d, 0xa3,
-	0xf8, 0x94, 0x7a, 0xff, 0xcf, 0x9d, 0xda, 0xb7, 0x5d, 0x1e, 0xfb, 0xf6,
-	0xbd, 0x41, 0x19, 0x03, 0xbb, 0x4b, 0x8d, 0xf1, 0xca, 0x53, 0xfd, 0xfb,
-	0xa7, 0xe1, 0x4f, 0xaa, 0xd4, 0x51, 0x5c, 0x13, 0x7c, 0xa5, 0xde, 0xa7,
-	0x1d, 0x62, 0x7e, 0x2a, 0xe9, 0xf8, 0xb8, 0x07, 0x1d, 0xf7, 0xce, 0x40,
-	0x2f, 0xb9, 0x7d, 0x3a, 0x3e, 0xd6, 0x90, 0x8e, 0xff, 0x75, 0x50, 0xfa,
-	0x54, 0xeb, 0xe9, 0x18, 0xb5, 0x3c, 0xc7, 0x8b, 0x8d, 0xfc, 0x57, 0xd8,
-	0x07, 0xd4, 0xa4, 0xc3, 0xe7, 0x01, 0x58, 0x69, 0xbf, 0x07, 0xe2, 0x7e,
-	0xc0, 0x47, 0xc4, 0x4e, 0xfe, 0x90, 0xe2, 0x8b, 0xb5, 0xb1, 0xd0, 0xcd,
-	0xae, 0xf9, 0x96, 0xc7, 0x35, 0xd0, 0xc5, 0x41, 0x0b, 0x76, 0x48, 0xda,
-	0xf4, 0x1a, 0x5e, 0xef, 0xf9, 0x0e, 0xe5, 0xec, 0x54, 0x9e, 0xe0, 0xa3,
-	0x0e, 0xd2, 0x53, 0x88, 0x2b, 0x2b, 0x1f, 0xf0, 0xd1, 0x8c, 0x5c, 0xb7,
-	0x79, 0x40, 0xe0, 0x03, 0xf4, 0xd5, 0x50, 0xc2, 0x9f, 0xe0, 0x3d, 0x95,
-	0xfe, 0xdf, 0xe4, 0x6a, 0x48, 0xed, 0x13, 0x8f, 0xc5, 0xfd, 0x3c, 0xeb,
-	0xfc, 0xb0, 0x3f, 0xf6, 0xd7, 0xd7, 0xcb, 0x79, 0xc5, 0x90, 0x05, 0x25,
-	0xfa, 0x0f, 0x96, 0x73, 0xfe, 0x03, 0xa6, 0xe8, 0xb9, 0x70, 0xb9, 0x78,
-	0x80, 0xf5, 0x47, 0xec, 0x21, 0x7c, 0x87, 0xda, 0xb7, 0xfb, 0xf6, 0x30,
-	0x75, 0xed, 0x67, 0xa9, 0x6f, 0x90, 0xc3, 0x7a, 0xa3, 0x71, 0x00, 0xf9,
-	0xe1, 0x16, 0x5f, 0x83, 0x5e, 0x51, 0x63, 0x56, 0x9c, 0x3a, 0xe0, 0x4f,
-	0x40, 0x0f, 0x68, 0x2b, 0x5d, 0x45, 0x53, 0xb3, 0x82, 0xa6, 0xe2, 0x6b,
-	0xb3, 0x8a, 0xa6, 0x66, 0x95, 0xff, 0x7c, 0x56, 0xd1, 0xd4, 0xac, 0xa2,
-	0xa9, 0x59, 0x45, 0x53, 0xb3, 0x8c, 0xd7, 0xa3, 0xac, 0xaf, 0x42, 0xf7,
-	0xd0, 0xfe, 0xcb, 0x2e, 0x4a, 0xe6, 0x70, 0x1e, 0xf2, 0xb8, 0x96, 0xae,
-	0x7e, 0x6d, 0x58, 0xfb, 0x47, 0x0b, 0x32, 0xcf, 0x8e, 0x9f, 0x85, 0x3d,
-	0x78, 0x98, 0xe1, 0x77, 0xcd, 0x37, 0xbf, 0x88, 0xb9, 0xfa, 0x28, 0x26,
-	0x7a, 0xc0, 0x36, 0x51, 0xd4, 0xad, 0xe3, 0x9a, 0xa8, 0xeb, 0x92, 0xb6,
-	0x5c, 0xaa, 0x61, 0x8d, 0x97, 0xc6, 0x8b, 0x69, 0xb5, 0x5f, 0xb5, 0x76,
-	0x4e, 0x0b, 0x25, 0xb2, 0x80, 0x2b, 0x72, 0x21, 0x2d, 0xde, 0x1b, 0x01,
-	0xa7, 0x94, 0xe9, 0x01, 0x83, 0xa3, 0x0a, 0x06, 0x4f, 0x8b, 0x35, 0x22,
-	0x97, 0x10, 0x3e, 0xc8, 0xc6, 0x70, 0x48, 0x67, 0x46, 0xf9, 0x3e, 0x8c,
-	0xfb, 0x07, 0x42, 0xcc, 0x83, 0xb6, 0x0b, 0x07, 0xf7, 0xda, 0x1b, 0xf1,
-	0x9a, 0xed, 0xd6, 0xd3, 0x5c, 0x77, 0xc9, 0x8e, 0x90, 0x92, 0x1b, 0x52,
-	0xef, 0xdd, 0xe5, 0xd8, 0x89, 0x14, 0xcf, 0xed, 0x2f, 0xc2, 0x7f, 0x39,
-	0x44, 0x6d, 0x25, 0x3a, 0x12, 0x06, 0x3e, 0x77, 0xb1, 0x5d, 0xc9, 0x73,
-	0x18, 0x2b, 0xd1, 0x85, 0xf0, 0x3e, 0xb6, 0x5d, 0xf6, 0xb3, 0x0e, 0x3a,
-	0xca, 0xff, 0x4e, 0xc4, 0xef, 0xc3, 0xbc, 0x3a, 0xf8, 0xda, 0x7e, 0x32,
-	0x7a, 0x52, 0x66, 0x2b, 0xeb, 0x07, 0x47, 0x2a, 0xf6, 0x88, 0x05, 0xff,
-	0x1c, 0xeb, 0xb6, 0xc6, 0x5c, 0xb8, 0x5b, 0xd5, 0x9c, 0xc1, 0x87, 0x8d,
-	0xf8, 0xd6, 0x3f, 0x97, 0x64, 0xaf, 0x80, 0x21, 0x75, 0xfc, 0xe3, 0x52,
-	0x64, 0x08, 0xc7, 0x78, 0xe7, 0x90, 0x3d, 0x11, 0xf1, 0xfd, 0x58, 0xea,
-	0xf2, 0x3e, 0xfb, 0x88, 0x7c, 0x3f, 0x80, 0x6d, 0x5a, 0x3e, 0x2f, 0xbc,
-	0x97, 0x3a, 0x4f, 0x25, 0x5f, 0x15, 0x74, 0x50, 0xa2, 0x7f, 0x67, 0x9a,
-	0x35, 0x09, 0xb1, 0x8c, 0x29, 0x51, 0x0b, 0x8d, 0x7c, 0xe5, 0xf9, 0x45,
-	0x3d, 0x2f, 0x47, 0xed, 0xf5, 0xfd, 0xc8, 0x37, 0xcb, 0x16, 0x68, 0x73,
-	0x99, 0x01, 0x3f, 0xda, 0xe8, 0xf2, 0x46, 0x4f, 0x50, 0xd4, 0x66, 0x77,
-	0xb3, 0x8e, 0xa3, 0xf3, 0x92, 0xc7, 0xf8, 0xfe, 0x01, 0xf1, 0xbe, 0xb9,
-	0xd8, 0x12, 0xc6, 0x35, 0xd3, 0xc8, 0x72, 0xe9, 0x21, 0xfe, 0x5d, 0xc4,
-	0x11, 0x93, 0xd4, 0xaa, 0x62, 0x04, 0x1d, 0x2a, 0xae, 0x14, 0x62, 0x5a,
-	0xaa, 0xd4, 0x1c, 0x8f, 0x94, 0x7d, 0x6d, 0xc0, 0xf1, 0x5a, 0x5f, 0xdb,
-	0x73, 0x5b, 0xc8, 0x9b, 0xad, 0xf0, 0x1a, 0x39, 0xa5, 0x2d, 0xa4, 0x7c,
-	0x88, 0xd6, 0x02, 0x6d, 0xb7, 0xb6, 0x6e, 0xc7, 0xd7, 0xb4, 0x36, 0xcf,
-	0xac, 0x9f, 0x79, 0xc7, 0x69, 0x53, 0xf8, 0xd4, 0x4c, 0xf3, 0xb9, 0x36,
-	0x96, 0xd9, 0xa8, 0x97, 0x02, 0xbc, 0xfc, 0x43, 0xa8, 0x37, 0x79, 0x32,
-	0xd0, 0x4c, 0xab, 0xab, 0xc8, 0x79, 0x78, 0xfc, 0x2e, 0x99, 0xe7, 0xfb,
-	0x08, 0xc3, 0x65, 0x3f, 0xcb, 0x37, 0x43, 0xc5, 0x70, 0x70, 0x0e, 0xbc,
-	0x41, 0xf4, 0xfd, 0x0c, 0x3c, 0x3c, 0xde, 0xc6, 0x7a, 0xbd, 0x8c, 0x01,
-	0x1c, 0xe4, 0x7b, 0x7f, 0x33, 0xf7, 0x08, 0xfc, 0x59, 0xe6, 0x61, 0xbe,
-	0x7f, 0x8c, 0xf5, 0x81, 0x08, 0x35, 0xd3, 0xca, 0x6a, 0x33, 0xeb, 0xf5,
-	0xcd, 0xac, 0x0f, 0x8c, 0x9a, 0x23, 0x3e, 0xf1, 0x2c, 0x51, 0xdb, 0xf2,
-	0xe9, 0xc0, 0x7e, 0xc6, 0x41, 0x3c, 0xeb, 0x8b, 0xea, 0x59, 0xb5, 0xcf,
-	0xb8, 0x55, 0xc2, 0xf1, 0x61, 0xff, 0xfa, 0x99, 0xab, 0x78, 0x2f, 0xd4,
-	0xe2, 0x34, 0xeb, 0xbe, 0x41, 0xf1, 0x6e, 0x46, 0x63, 0x66, 0x86, 0xed,
-	0x80, 0x30, 0x1f, 0x1f, 0xa1, 0x54, 0x31, 0x41, 0xbf, 0x57, 0x74, 0xfb,
-	0x6a, 0x8f, 0xf0, 0x9c, 0x65, 0x6d, 0x7d, 0x0b, 0xcf, 0xeb, 0x7d, 0xa7,
-	0x96, 0x67, 0xb4, 0x91, 0xff, 0x6b, 0x41, 0x6a, 0x7e, 0x11, 0xbe, 0x91,
-	0x12, 0x65, 0xc3, 0xf6, 0x85, 0xeb, 0xe2, 0xbd, 0x1b, 0x16, 0xbd, 0x22,
-	0xf2, 0x5b, 0xf9, 0x7a, 0xbe, 0xe7, 0x79, 0x8c, 0x7b, 0xc5, 0xa2, 0x2b,
-	0x8e, 0x84, 0xf7, 0x9f, 0x05, 0x82, 0xe4, 0x7f, 0x1d, 0x39, 0x48, 0xd0,
-	0xb5, 0xd6, 0xcf, 0x38, 0xfb, 0x98, 0x5f, 0xbf, 0x88, 0xeb, 0xf8, 0xf3,
-	0x75, 0x1c, 0xb7, 0xf1, 0x3a, 0x21, 0x6f, 0x91, 0x77, 0x02, 0x3e, 0xb7,
-	0x3f, 0x64, 0x0a, 0xfc, 0x3b, 0xc2, 0x38, 0xd5, 0x24, 0x7c, 0x81, 0xbd,
-	0x18, 0xeb, 0x0c, 0xb2, 0x6e, 0xb0, 0x7e, 0x66, 0x7c, 0x1f, 0x8e, 0x23,
-	0x3d, 0x7e, 0x86, 0x91, 0xc4, 0xa1, 0xb0, 0x78, 0xff, 0xa1, 0xeb, 0x2f,
-	0x70, 0x70, 0x9c, 0x78, 0x3f, 0xa1, 0x3f, 0xf0, 0x7e, 0x9a, 0xe8, 0xb3,
-	0xd4, 0x46, 0x71, 0x7e, 0x46, 0x2c, 0x27, 0xd7, 0x7d, 0xbe, 0xe8, 0x27,
-	0xe9, 0x47, 0x6a, 0x1e, 0xd6, 0xef, 0x29, 0xa4, 0x7e, 0xdc, 0x5b, 0xd3,
-	0x0a, 0xbe, 0x77, 0xd1, 0x8d, 0x5c, 0x07, 0xdd, 0x54, 0xb1, 0xa5, 0x1b,
-	0xc2, 0xae, 0x62, 0x9e, 0x9c, 0xe8, 0xa2, 0xeb, 0xab, 0x4d, 0x44, 0xbd,
-	0x6d, 0x22, 0xf6, 0x7b, 0x23, 0x97, 0xc7, 0xf3, 0x87, 0xa5, 0xdf, 0xa5,
-	0x82, 0x23, 0x37, 0x3c, 0x70, 0xe4, 0x3d, 0x81, 0x23, 0xef, 0x6d, 0x81,
-	0x23, 0x7b, 0x95, 0x2d, 0xd1, 0x46, 0xcd, 0x0a, 0x3f, 0x5e, 0x63, 0xfc,
-	0x78, 0x81, 0xf1, 0xe3, 0x50, 0x03, 0xfc, 0x30, 0x6a, 0xf0, 0xe3, 0xb0,
-	0xc0, 0x8f, 0x9f, 0x6d, 0x8a, 0x1f, 0x87, 0xfc, 0x9b, 0xf9, 0x82, 0x34,
-	0x6e, 0x0e, 0xd0, 0x4a, 0xce, 0xa1, 0xd5, 0x45, 0x9b, 0x2d, 0x7b, 0xd8,
-	0xe6, 0x88, 0x19, 0xce, 0x88, 0x7a, 0x97, 0x82, 0xc0, 0x2b, 0x96, 0xe3,
-	0x33, 0xa8, 0x69, 0xaa, 0xdb, 0x03, 0x12, 0xef, 0xa5, 0x14, 0xf0, 0x97,
-	0x7b, 0x12, 0xcb, 0xac, 0x9f, 0xf9, 0x73, 0xde, 0xc7, 0x2b, 0x6b, 0x81,
-	0x00, 0x7e, 0xf3, 0xcf, 0x04, 0x69, 0x63, 0x8d, 0xed, 0x54, 0xc6, 0xb1,
-	0xab, 0xb9, 0x21, 0xba, 0x92, 0x1b, 0xa0, 0x8d, 0xdc, 0x30, 0xbd, 0x93,
-	0xc3, 0x33, 0x00, 0x73, 0x3e, 0x16, 0x30, 0x37, 0xe8, 0x60, 0x90, 0xc7,
-	0xac, 0x0e, 0xd0, 0xfa, 0xaa, 0xc6, 0x57, 0xe0, 0x2a, 0xf6, 0x3f, 0xd2,
-	0x23, 0xeb, 0xd0, 0xea, 0x71, 0x20, 0x56, 0x85, 0x03, 0xf2, 0x1a, 0xec,
-	0xfd, 0x42, 0x7d, 0x0d, 0x6d, 0xab, 0x39, 0x83, 0x1c, 0xb8, 0x36, 0xb6,
-	0xc9, 0x6d, 0xe1, 0x73, 0x3d, 0xe8, 0x87, 0x4e, 0x6b, 0xdc, 0x4d, 0x5d,
-	0xbc, 0x07, 0x0e, 0xf2, 0x87, 0x86, 0x59, 0x3f, 0xed, 0x16, 0xfa, 0x68,
-	0xd4, 0x09, 0x84, 0x62, 0x54, 0x3a, 0x6b, 0x38, 0xe8, 0x93, 0xf8, 0x08,
-	0xdf, 0xcf, 0x50, 0x7e, 0x9e, 0x4e, 0x17, 0x3e, 0xd5, 0xea, 0x9e, 0x88,
-	0xd1, 0x9e, 0xe0, 0x39, 0x43, 0x4e, 0x56, 0xe2, 0x22, 0x54, 0x8e, 0x8b,
-	0xb4, 0xf2, 0xba, 0x25, 0x2d, 0xcd, 0x39, 0x3c, 0xae, 0xc8, 0xe3, 0x8a,
-	0x88, 0xa9, 0xf1, 0xf9, 0x55, 0xc4, 0x73, 0x87, 0x68, 0x63, 0x11, 0x34,
-	0x07, 0xff, 0x44, 0x25, 0x86, 0xba, 0xb1, 0x86, 0xf3, 0xf0, 0x51, 0x54,
-	0x62, 0xa8, 0x1b, 0x2a, 0x86, 0xba, 0xb1, 0x36, 0x2d, 0xf8, 0xf0, 0x42,
-	0x8e, 0x79, 0x40, 0xce, 0xaf, 0xf2, 0x07, 0xf7, 0xa9, 0x77, 0xf6, 0x9c,
-	0x10, 0x3e, 0xe4, 0x1e, 0x67, 0x73, 0x18, 0x1e, 0xac, 0x83, 0xe1, 0xb4,
-	0xd0, 0x83, 0xe2, 0x7c, 0xcf, 0x58, 0xee, 0x04, 0xc3, 0x73, 0x96, 0x69,
-	0x69, 0xb7, 0xa2, 0x25, 0x1d, 0x93, 0xed, 0x26, 0xf5, 0xfe, 0x1f, 0xa1,
-	0xeb, 0x4b, 0xfe, 0x33, 0x54, 0xc3, 0x7f, 0x28, 0x10, 0x1d, 0x97, 0xd7,
-	0xa7, 0x8b, 0xaf, 0x0c, 0x6b, 0xff, 0x5b, 0x9a, 0xef, 0xbb, 0x90, 0xdb,
-	0x49, 0x4c, 0x97, 0xe5, 0xa6, 0x67, 0xce, 0xe0, 0x76, 0x9f, 0xad, 0x71,
-	0xe1, 0xc4, 0x6d, 0xe0, 0x93, 0xbc, 0x47, 0x05, 0x9f, 0xfe, 0x77, 0x16,
-	0xc0, 0xb2, 0x93, 0x05, 0x98, 0x57, 0x84, 0x80, 0xf5, 0x03, 0x03, 0xb4,
-	0x8e, 0x39, 0x00, 0x1e, 0x53, 0x68, 0x02, 0xe6, 0x19, 0xa7, 0xf5, 0x40,
-	0xfb, 0xfb, 0x95, 0xc1, 0xeb, 0x5d, 0x1b, 0xa0, 0x67, 0x4f, 0x2d, 0xea,
-	0x79, 0x2c, 0x07, 0xca, 0xa3, 0x4e, 0x2a, 0x0c, 0x24, 0xe6, 0x27, 0x90,
-	0xff, 0x80, 0xfe, 0x00, 0xf9, 0x11, 0x98, 0x9f, 0x9c, 0x81, 0x72, 0xa0,
-	0x35, 0x53, 0xcd, 0x6b, 0x40, 0xfa, 0x40, 0x61, 0x08, 0x2a, 0x53, 0x41,
-	0x63, 0x1d, 0x40, 0xf6, 0x12, 0x21, 0x68, 0xd8, 0x01, 0x69, 0x20, 0xbb,
-	0x79, 0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x4f,
-	0xec, 0x40, 0x97, 0xc2, 0xdc, 0xf4, 0xff, 0xff, 0x31, 0x15, 0x16, 0x60,
-	0xda, 0x03, 0xad, 0xf9, 0xfc, 0xfd, 0xff, 0x80, 0x08, 0x0b, 0x43, 0x0b,
-	0x7c, 0xed, 0x9e, 0xb0, 0x3c, 0xa8, 0x9c, 0x5b, 0x00, 0x64, 0xb5, 0xc1,
-	0xeb, 0x6d, 0x16, 0xf0, 0x7d, 0xc4, 0x0b, 0x18, 0x7e, 0x01, 0xcb, 0x95,
-	0xff, 0xff, 0x97, 0xc2, 0xd5, 0x82, 0x00, 0x00, 0xd4, 0xc2, 0xcb, 0x42,
-	0x60, 0x7c, 0x00, 0x00, 0x00 };
-static u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
-	0x08001ad8, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14,
-	0x08001a24, 0x08001b14, 0x08001a98, 0x08001b14, 0x080019ac, 0x08001b14,
-	0x08001b14, 0x08001b14, 0x080019b8, 0x0, 0x08002a2c, 0x08002a7c,
-	0x08002aac, 0x08002adc, 0x08002b0c, 0x0, 0x08005fac, 0x08005fac,
-	0x08005fac, 0x08005fac, 0x08005fac, 0x08005fd8, 0x08005fd8, 0x08006018,
-	0x08006024, 0x08006024, 0x08005fac, 0x0, 0x0 };
-static u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b09FwSbss[(0x5c/4) + 1] = { 0x0 };
+	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b,
+	0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92,
+	0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0,
+	0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c,
+	0x69, 0x64, 0x50, 0x80, 0xb6, 0x4c, 0x46, 0xec, 0x1a, 0x9a, 0x4e, 0x87,
+	0xd6, 0xa6, 0x6e, 0x9b, 0xc9, 0x34, 0x78, 0x47, 0x1f, 0x8d, 0xa7, 0x15,
+	0xba, 0x06, 0x1b, 0xd9, 0xd3, 0xd0, 0xa0, 0x6a, 0x71, 0xf1, 0x8f, 0x8d,
+	0xaf, 0xf9, 0x48, 0xaa, 0x4c, 0x4d, 0xa5, 0x18, 0x48, 0x69, 0xa7, 0x4d,
+	0xfb, 0xa3, 0x9e, 0xa1, 0x5f, 0x84, 0x32, 0xfd, 0xc1, 0x74, 0xda, 0x4e,
+	0x3a, 0x24, 0x53, 0x08, 0x84, 0xed, 0xf3, 0x9c, 0x7b, 0xee, 0xea, 0x6a,
+	0x25, 0x7f, 0xf1, 0x91, 0x1f, 0xd5, 0xcc, 0xfa, 0xde, 0xf3, 0xfd, 0x9e,
+	0xf7, 0xbc, 0xef, 0xf3, 0x7e, 0xdc, 0xe3, 0x4f, 0x8a, 0xb4, 0x8a, 0xf9,
+	0xdb, 0x80, 0x5f, 0xfa, 0xc1, 0xdf, 0x2c, 0x5f, 0x37, 0x78, 0xdd, 0x0d,
+	0x78, 0xbd, 0x41, 0xc5, 0xec, 0x18, 0xeb, 0xf9, 0x4f, 0x12, 0xbf, 0x01,
+	0xf3, 0xbe, 0xd6, 0x9f, 0x83, 0xdf, 0x9b, 0x68, 0x1c, 0xfb, 0x0f, 0x11,
+	0xeb, 0x3c, 0x7d, 0xa2, 0x7f, 0xf5, 0xfa, 0x85, 0xdb, 0x15, 0x69, 0xb9,
+	0x40, 0x7b, 0x2c, 0x58, 0x52, 0xd3, 0xcc, 0x9f, 0x24, 0x54, 0x6e, 0xec,
+	0xe1, 0x82, 0x2b, 0x89, 0x58, 0x6e, 0xf7, 0xc1, 0xb2, 0x2b, 0x92, 0xaf,
+	0xed, 0x48, 0x17, 0xe5, 0x67, 0xf5, 0x4a, 0xd2, 0x16, 0xd6, 0x5f, 0x95,
+	0x7b, 0xef, 0xc9, 0x17, 0x6e, 0xca, 0xfc, 0x68, 0x2e, 0x26, 0x09, 0x27,
+	0xf7, 0xbc, 0x38, 0xdb, 0x25, 0xd1, 0x83, 0x31, 0x4f, 0xf4, 0xe5, 0x2d,
+	0xe9, 0x08, 0xe7, 0x7a, 0xb3, 0xfe, 0x42, 0x9f, 0x54, 0xb6, 0xe4, 0x12,
+	0xa2, 0x72, 0xdb, 0x5e, 0x2d, 0xc4, 0x9c, 0xb1, 0x58, 0xce, 0x91, 0x45,
+	0x5f, 0x46, 0xee, 0x9f, 0x96, 0x44, 0x22, 0xf7, 0xe5, 0xc4, 0xba, 0x6d,
+	0x92, 0xb0, 0x73, 0x4b, 0x0f, 0xff, 0xbe, 0x7b, 0xb0, 0xae, 0x5c, 0xb7,
+	0x7f, 0x5e, 0xda, 0x87, 0x4e, 0x0c, 0xa2, 0xbd, 0x96, 0xe9, 0x17, 0xb9,
+	0x49, 0x94, 0x5b, 0x69, 0x8f, 0xb9, 0x09, 0x29, 0xf8, 0xae, 0x14, 0x7d,
+	0x91, 0xbf, 0xac, 0x59, 0x72, 0xc2, 0xed, 0x92, 0xf9, 0x9d, 0xef, 0xd5,
+	0xf3, 0xa0, 0xe5, 0xfb, 0xee, 0xd2, 0xc3, 0x93, 0x2e, 0xe9, 0x3d, 0x90,
+	0x08, 0xe8, 0xdd, 0xbb, 0xae, 0xec, 0xda, 0x32, 0x5e, 0x63, 0xdd, 0xa8,
+	0x62, 0x5d, 0x3c, 0x97, 0x68, 0x3d, 0xe1, 0xb6, 0x9b, 0xba, 0x57, 0x6f,
+	0x29, 0x60, 0xbe, 0x89, 0x1a, 0xfb, 0xe6, 0xaf, 0x2f, 0xbb, 0x49, 0x53,
+	0xbf, 0x70, 0x63, 0xc1, 0x4d, 0xa1, 0xbe, 0xc7, 0xb4, 0x8d, 0x3d, 0x58,
+	0x76, 0x5d, 0xd3, 0xf6, 0x76, 0xac, 0xe0, 0xf6, 0x9b, 0xfa, 0xf7, 0x6e,
+	0x2e, 0xbb, 0x3b, 0x4d, 0x7d, 0x0f, 0xe6, 0xca, 0x9a, 0xfa, 0x85, 0x7b,
+	0xca, 0xee, 0xa0, 0xa9, 0xdf, 0x7d, 0x73, 0xc1, 0x1d, 0x32, 0xf5, 0x89,
+	0xa1, 0xb2, 0x9b, 0x43, 0xfd, 0x97, 0x13, 0x6a, 0x9b, 0x23, 0x53, 0xb5,
+	0x34, 0x7e, 0x79, 0xb4, 0x0d, 0xa3, 0x6e, 0x37, 0x7e, 0xb7, 0xe3, 0xf7,
+	0xc8, 0x46, 0xe9, 0x18, 0xc1, 0xf3, 0xbf, 0xba, 0x03, 0xde, 0x81, 0x47,
+	0x5e, 0x42, 0x5e, 0x8f, 0xa5, 0xe4, 0x85, 0xbe, 0xd7, 0xc1, 0x43, 0x47,
+	0x4e, 0xfb, 0x62, 0x8d, 0xf4, 0xa5, 0xc0, 0xbb, 0xa4, 0x3c, 0xe3, 0xb7,
+	0x49, 0xec, 0xb1, 0x18, 0x78, 0xf3, 0xcb, 0x52, 0x4a, 0x26, 0x64, 0xd3,
+	0xac, 0x25, 0x5b, 0x07, 0x12, 0x92, 0x77, 0xb8, 0x36, 0x4e, 0x7b, 0x26,
+	0x29, 0xb1, 0xd9, 0xfc, 0x66, 0x25, 0xdb, 0x9c, 0xa2, 0x54, 0xc0, 0xbb,
+	0x57, 0x29, 0x97, 0x68, 0x4b, 0x4b, 0x71, 0xfa, 0x5a, 0x19, 0x73, 0x48,
+	0xd7, 0x1f, 0x5c, 0x15, 0xac, 0x95, 0xb0, 0x0a, 0xc7, 0x46, 0x65, 0xca,
+	0x6b, 0xb7, 0x8a, 0xc7, 0x6e, 0x96, 0x42, 0x56, 0x92, 0x18, 0x97, 0x2a,
+	0xa1, 0xa5, 0x5a, 0x1b, 0x95, 0x49, 0x4f, 0xac, 0x82, 0x47, 0x7e, 0x76,
+	0xa1, 0xbd, 0x43, 0xf7, 0x45, 0x5d, 0x4f, 0x4c, 0xcf, 0x9d, 0x40, 0xbd,
+	0x83, 0xfa, 0x4e, 0x6b, 0x58, 0xcf, 0xa1, 0xeb, 0xd3, 0x13, 0xd2, 0x2e,
+	0x4f, 0xd5, 0x92, 0xa6, 0x6f, 0xbd, 0x5e, 0xc8, 0x3a, 0xe8, 0x37, 0x2a,
+	0x13, 0x5e, 0x52, 0xc6, 0xf0, 0x1c, 0xf7, 0xb8, 0x7e, 0x0a, 0x32, 0x75,
+	0xdd, 0xc1, 0xd2, 0x51, 0x3d, 0x5f, 0x3a, 0x96, 0xe3, 0x7c, 0x3d, 0xe8,
+	0xf7, 0x12, 0xe8, 0xb2, 0xc4, 0xd6, 0x67, 0x99, 0x97, 0xd2, 0xb4, 0x05,
+	0x79, 0xc3, 0x53, 0xf3, 0x75, 0x18, 0xf4, 0xdb, 0xe2, 0x0e, 0x58, 0x52,
+	0xc6, 0x59, 0x55, 0x1c, 0x94, 0x6b, 0x0b, 0xaa, 0xe0, 0xad, 0x93, 0xa2,
+	0x9d, 0x96, 0xd8, 0x0c, 0x65, 0x69, 0x4c, 0x26, 0x30, 0x46, 0xb9, 0xec,
+	0xf3, 0x0e, 0xf6, 0x3d, 0xa6, 0xcf, 0xa1, 0x25, 0x57, 0x51, 0x45, 0xbf,
+	0x4b, 0xd4, 0xec, 0xbd, 0xf2, 0xd2, 0xb4, 0x38, 0x38, 0xc7, 0x7a, 0xc1,
+	0x9d, 0x54, 0x85, 0xa7, 0x6d, 0x89, 0xcf, 0x58, 0x32, 0xe9, 0x66, 0xa0,
+	0x01, 0x87, 0xd4, 0x2e, 0x7f, 0x01, 0xfd, 0x38, 0x0e, 0xfd, 0x6a, 0x0a,
+	0x7c, 0xe5, 0xfb, 0x0e, 0x47, 0x69, 0x79, 0x66, 0x1f, 0x9c, 0x01, 0xf6,
+	0xf1, 0x8c, 0x87, 0x33, 0xd1, 0x67, 0x94, 0xc6, 0x19, 0x89, 0x35, 0xdc,
+	0x07, 0x99, 0x3a, 0x6a, 0x4b, 0x29, 0x8b, 0x7d, 0xa1, 0x77, 0x29, 0xbb,
+	0x4c, 0xd7, 0xc4, 0x74, 0x33, 0x5d, 0x1c, 0x47, 0xba, 0x02, 0x9a, 0xc6,
+	0x8f, 0x92, 0xbe, 0x65, 0x7a, 0xa6, 0xa6, 0x43, 0x1a, 0xb9, 0x1e, 0x69,
+	0x0b, 0xe9, 0xe2, 0x38, 0xd2, 0xb5, 0x99, 0x67, 0xcd, 0x3f, 0x6b, 0x18,
+	0x74, 0x4c, 0x78, 0x36, 0xce, 0xa8, 0x5d, 0x4a, 0x4e, 0xc5, 0x9a, 0x18,
+	0xda, 0x91, 0x82, 0x36, 0x5b, 0xe3, 0x43, 0xa4, 0xd9, 0xc5, 0x39, 0xb6,
+	0xe8, 0xf3, 0x56, 0xb9, 0x49, 0xf2, 0x0e, 0xfd, 0xb9, 0x3e, 0xde, 0x6b,
+	0x8e, 0x4c, 0xea, 0xf9, 0x48, 0xd3, 0x47, 0x31, 0x0f, 0x69, 0x7d, 0x05,
+	0xb2, 0x3a, 0x08, 0x19, 0xcd, 0xca, 0x5f, 0xf8, 0x3b, 0xe5, 0xcf, 0xfc,
+	0x7e, 0xf9, 0x0e, 0xf4, 0xf6, 0xdb, 0x7e, 0x5a, 0x9e, 0xf7, 0x7b, 0xe4,
+	0x39, 0x3f, 0x25, 0xcf, 0x6a, 0xf9, 0x1d, 0x16, 0xe9, 0xa0, 0x4c, 0xa7,
+	0xa5, 0x13, 0xfa, 0xb3, 0x09, 0xba, 0xf9, 0x38, 0xf8, 0x77, 0xb4, 0x4f,
+	0xf2, 0x9b, 0x73, 0x92, 0xb8, 0x1a, 0xbf, 0x2b, 0xf0, 0xeb, 0xca, 0xd9,
+	0x5a, 0x56, 0xec, 0x1c, 0x79, 0x68, 0x4b, 0x51, 0xef, 0xd9, 0x96, 0x09,
+	0xff, 0x91, 0xab, 0x03, 0xd9, 0x15, 0x19, 0x01, 0x8f, 0xd5, 0xc0, 0x4f,
+	0xea, 0x79, 0x07, 0xfb, 0x18, 0xd8, 0xa1, 0x79, 0xaf, 0x06, 0x28, 0xb3,
+	0x69, 0xc8, 0xbd, 0x6d, 0x15, 0xbd, 0x93, 0xc0, 0x8d, 0x36, 0xab, 0x70,
+	0xa4, 0x22, 0xe5, 0x23, 0x75, 0x29, 0x67, 0xe3, 0xf2, 0x90, 0x53, 0x97,
+	0xe1, 0x6c, 0x8b, 0xec, 0x77, 0xc0, 0xfb, 0x9d, 0xbf, 0x6d, 0x85, 0x98,
+	0xfd, 0xb8, 0xff, 0x3b, 0x78, 0x67, 0x9d, 0xc8, 0x51, 0xfd, 0x1e, 0xd4,
+	0x57, 0xfc, 0xb8, 0xe4, 0x93, 0x95, 0x94, 0x2d, 0x5b, 0x54, 0xb0, 0xee,
+	0x78, 0xd8, 0x06, 0x7e, 0x2c, 0x01, 0x27, 0x33, 0x5a, 0x5f, 0x4a, 0xd3,
+	0xeb, 0xdf, 0xce, 0xeb, 0x6a, 0xf4, 0x77, 0x06, 0xe5, 0xac, 0xe6, 0x67,
+	0x7a, 0xcc, 0xca, 0x25, 0x65, 0x6b, 0x8d, 0xe5, 0x21, 0xeb, 0x4e, 0x9f,
+	0xf2, 0x8c, 0x77, 0x9f, 0x74, 0x5e, 0x89, 0x7e, 0x36, 0x9e, 0x79, 0x43,
+	0x6f, 0x94, 0x46, 0xce, 0x43, 0x1a, 0xf9, 0xfc, 0x66, 0x84, 0xc6, 0x27,
+	0x1b, 0xef, 0x47, 0x23, 0xef, 0x15, 0xff, 0x8f, 0x5a, 0x03, 0xda, 0x86,
+	0xe4, 0x8d, 0x99, 0xaf, 0x98, 0x75, 0xf0, 0x7e, 0x8a, 0xf3, 0x7f, 0xab,
+	0x1e, 0xc8, 0x4b, 0xe5, 0x22, 0xeb, 0x2c, 0x44, 0xd6, 0xf9, 0x6e, 0x64,
+	0x9d, 0xef, 0x46, 0xd6, 0xa9, 0x80, 0xa7, 0xb2, 0x51, 0x41, 0x86, 0x4b,
+	0x34, 0x63, 0x72, 0x08, 0x73, 0xbe, 0x2e, 0xb1, 0x1c, 0xf5, 0x3c, 0xc4,
+	0x9b, 0x73, 0xe8, 0x9f, 0x93, 0xb3, 0x33, 0x15, 0x29, 0x1d, 0x89, 0xcb,
+	0x1d, 0xba, 0xdf, 0x26, 0x43, 0x5f, 0xb4, 0x2d, 0x21, 0x7b, 0x92, 0x7c,
+	0x0f, 0xdb, 0x6c, 0xf0, 0x99, 0xe5, 0x6f, 0x5d, 0x19, 0x94, 0xf9, 0xbe,
+	0x60, 0xf6, 0x32, 0x1a, 0x8c, 0x3b, 0xf5, 0xa6, 0xc6, 0xc3, 0x45, 0x9f,
+	0xb8, 0x25, 0xd9, 0x98, 0x2b, 0xfb, 0x86, 0xb3, 0x5d, 0x32, 0xe1, 0x58,
+	0xd9, 0xf1, 0xfe, 0x75, 0xd4, 0x8b, 0xbc, 0x72, 0xdb, 0x80, 0x0d, 0x92,
+	0x56, 0xc4, 0x7c, 0xbd, 0x2f, 0x4b, 0x05, 0xf4, 0x3b, 0x2c, 0x8f, 0x28,
+	0xb7, 0xb3, 0xa9, 0x9e, 0xba, 0x1d, 0xc3, 0x3b, 0x65, 0x78, 0x97, 0x39,
+	0x63, 0x1b, 0x65, 0xe2, 0xf0, 0x35, 0xa6, 0x1c, 0xb6, 0x6f, 0xb6, 0x57,
+	0x96, 0xcf, 0x76, 0xaf, 0x2c, 0x87, 0x38, 0x11, 0xc5, 0x70, 0xee, 0x15,
+	0xf8, 0xe4, 0x52, 0xee, 0xe2, 0xa0, 0x35, 0x0b, 0x9d, 0x5b, 0x67, 0x68,
+	0xb8, 0xc2, 0xd0, 0x00, 0x5a, 0xfb, 0x20, 0x59, 0x5a, 0x97, 0xb4, 0x68,
+	0x35, 0x95, 0xc9, 0xfb, 0xf0, 0x7d, 0x83, 0x6e, 0x0f, 0x74, 0x2e, 0x7c,
+	0x86, 0xf8, 0xfe, 0x66, 0xc4, 0x5e, 0xf4, 0x40, 0x67, 0x93, 0xe0, 0x55,
+	0x88, 0xf5, 0xc4, 0xe0, 0x14, 0xec, 0x03, 0x64, 0x55, 0x63, 0x7b, 0x3b,
+	0xf0, 0xd0, 0x36, 0xd8, 0x9c, 0x30, 0xd8, 0xdc, 0x0e, 0x5c, 0x66, 0xd9,
+	0x31, 0xe5, 0xa4, 0x29, 0xa7, 0x50, 0x86, 0x1d, 0x9f, 0x25, 0x2e, 0x5f,
+	0x77, 0x70, 0xef, 0x51, 0x8d, 0xf7, 0xb4, 0x15, 0x40, 0x61, 0xe2, 0x35,
+	0x71, 0xbb, 0x47, 0xe6, 0x6b, 0x58, 0xaf, 0x81, 0x8d, 0xdc, 0x7b, 0x94,
+	0x1e, 0xd2, 0xb2, 0x5e, 0x14, 0x6c, 0x57, 0x3e, 0x49, 0x7a, 0x1f, 0xc4,
+	0xde, 0x89, 0x3f, 0xa4, 0xfb, 0x2a, 0xd0, 0xca, 0x7d, 0xfc, 0x3c, 0x69,
+	0xe5, 0x7a, 0xcd, 0xf4, 0x7e, 0x58, 0x1c, 0x24, 0xed, 0x27, 0xb1, 0xe7,
+	0x3c, 0x30, 0x4f, 0xac, 0xd1, 0xbe, 0x51, 0xec, 0x79, 0x04, 0x78, 0x78,
+	0x3b, 0xf0, 0x70, 0x37, 0xf0, 0x70, 0x18, 0x78, 0x98, 0x03, 0x16, 0x0e,
+	0x01, 0x0b, 0x07, 0x81, 0x85, 0x59, 0xf0, 0x26, 0x29, 0x73, 0xc0, 0xc6,
+	0x39, 0x60, 0xe4, 0x1c, 0xe6, 0x18, 0x9f, 0x15, 0xeb, 0x4b, 0xd8, 0xc3,
+	0x63, 0x33, 0x99, 0x93, 0x90, 0xa5, 0x54, 0x45, 0x41, 0xfe, 0xb3, 0x43,
+	0x90, 0xed, 0x7e, 0xa9, 0xfa, 0xb6, 0x94, 0x69, 0x53, 0xb7, 0xf7, 0x42,
+	0xd7, 0x20, 0xef, 0x29, 0x31, 0x7f, 0x1b, 0xcc, 0xf3, 0x1f, 0x45, 0xdc,
+	0xbf, 0xa3, 0x2c, 0xa6, 0x45, 0xce, 0x48, 0xc9, 0xeb, 0x75, 0x0a, 0xaa,
+	0x1f, 0xfd, 0x58, 0xce, 0xaa, 0xfb, 0x8f, 0x5c, 0xaf, 0xf6, 0x1e, 0x21,
+	0x5f, 0xa6, 0x81, 0x57, 0x75, 0x99, 0xcc, 0x52, 0xb7, 0xea, 0x72, 0x22,
+	0x9b, 0x19, 0xaa, 0x48, 0x9b, 0x4c, 0x25, 0xa7, 0xb5, 0xad, 0xb5, 0x73,
+	0x87, 0xb5, 0xbd, 0x2a, 0xbb, 0x78, 0xd6, 0x06, 0x54, 0xe9, 0x08, 0xf7,
+	0xdf, 0x8b, 0x5f, 0x1c, 0xb4, 0x70, 0x7e, 0x5b, 0x86, 0x07, 0x1d, 0xf5,
+	0x40, 0x5f, 0x05, 0x08, 0x96, 0x71, 0xce, 0x62, 0xe5, 0xe2, 0x74, 0x6f,
+	0xaa, 0xa8, 0x6c, 0x19, 0xb3, 0x2d, 0x19, 0x87, 0x7c, 0x0f, 0x67, 0xdf,
+	0xa9, 0x4f, 0x25, 0xd9, 0xbe, 0x4e, 0xbe, 0xae, 0x7d, 0x0e, 0xac, 0x5d,
+	0x3d, 0x8a, 0x75, 0xe3, 0x38, 0x03, 0xae, 0xcb, 0x79, 0x50, 0xae, 0xd9,
+	0x28, 0x67, 0x4e, 0x56, 0xc4, 0x87, 0x9e, 0x6c, 0x94, 0xc2, 0xce, 0x16,
+	0xc9, 0x8f, 0xa4, 0x65, 0x7c, 0xc6, 0x07, 0x4e, 0xe1, 0x1c, 0xdd, 0x56,
+	0x29, 0x8d, 0xa6, 0xe5, 0xd1, 0x19, 0xd6, 0x9d, 0xc6, 0xfe, 0x33, 0x87,
+	0xf2, 0xc2, 0xfd, 0xc7, 0xf5, 0xbe, 0xd2, 0xea, 0xb4, 0xec, 0xf7, 0xde,
+	0x30, 0x7a, 0x14, 0x94, 0xef, 0xc7, 0x99, 0x9e, 0xf0, 0x17, 0xb0, 0x7f,
+	0x57, 0xe6, 0x81, 0xff, 0xc5, 0x23, 0xc0, 0x41, 0xb7, 0x03, 0x98, 0x95,
+	0x59, 0xa0, 0x4d, 0x8d, 0xc1, 0xef, 0xab, 0x6a, 0x5e, 0xf7, 0xc8, 0x91,
+	0x19, 0x25, 0xdf, 0xbe, 0x31, 0x8d, 0x32, 0xb0, 0x31, 0x9b, 0x39, 0x3d,
+	0xa6, 0x7a, 0xe4, 0x86, 0xce, 0x14, 0xc6, 0xe5, 0x54, 0xc9, 0xdb, 0x18,
+	0x03, 0x2f, 0x8f, 0xa7, 0x15, 0xfb, 0x2a, 0x29, 0x66, 0x63, 0x38, 0xff,
+	0x0a, 0xfa, 0xbf, 0x8f, 0xf5, 0x7a, 0x64, 0x16, 0xbe, 0xd6, 0xec, 0x4c,
+	0x1e, 0xe3, 0x88, 0x5d, 0x99, 0xe3, 0x4b, 0x0a, 0x18, 0x33, 0x0b, 0xf9,
+	0x1e, 0x85, 0x2f, 0x33, 0x03, 0xd1, 0x69, 0x4d, 0xe3, 0x4c, 0x7b, 0x9d,
+	0x71, 0xe0, 0x41, 0xbe, 0x87, 0xef, 0x9c, 0xd3, 0x95, 0x13, 0x1e, 0xe5,
+	0x30, 0x2d, 0x4f, 0xf9, 0x1c, 0xd7, 0xbb, 0xf0, 0x1c, 0x7c, 0x9f, 0xdf,
+	0xf5, 0xae, 0x44, 0xff, 0x77, 0xe1, 0x07, 0x3b, 0x52, 0xc5, 0xb9, 0x95,
+	0xc1, 0xcb, 0x7c, 0x2a, 0x28, 0x8f, 0xcf, 0x66, 0x16, 0xde, 0x50, 0x7c,
+	0x77, 0x2b, 0xf3, 0xea, 0x5a, 0x91, 0x4e, 0xf2, 0x33, 0x0b, 0x5e, 0xba,
+	0x8e, 0x52, 0xdb, 0x8d, 0xef, 0x47, 0x3d, 0x72, 0x41, 0x9f, 0x2d, 0xf3,
+	0x03, 0x51, 0x3d, 0xa2, 0x3d, 0x0c, 0xf5, 0x28, 0x93, 0x5a, 0x52, 0x0a,
+	0xed, 0xb6, 0x1c, 0xd6, 0x65, 0x0b, 0xb4, 0x66, 0x52, 0xdc, 0xdf, 0x44,
+	0xad, 0x5f, 0x9e, 0xf2, 0xd8, 0x1f, 0x7c, 0x9e, 0x6e, 0x37, 0xfd, 0x4f,
+	0x83, 0x87, 0xf4, 0xdf, 0xfa, 0x41, 0x73, 0xa0, 0x5b, 0xf3, 0xd3, 0x49,
+	0xdd, 0x36, 0xe5, 0x05, 0x7e, 0x9a, 0x82, 0x2f, 0x37, 0x07, 0x5f, 0xae,
+	0xa8, 0xf5, 0xcc, 0xc9, 0xc3, 0xd7, 0x87, 0x9e, 0x04, 0x3a, 0x56, 0xad,
+	0x91, 0x96, 0xbb, 0x40, 0x5f, 0xa6, 0x02, 0x62, 0x0e, 0xab, 0x1c, 0xce,
+	0x7d, 0x50, 0x2a, 0xf4, 0xf7, 0xce, 0xc6, 0x9e, 0x92, 0xb1, 0x2a, 0xed,
+	0x11, 0x7e, 0x9e, 0xeb, 0x30, 0xbe, 0xc8, 0x6b, 0x5b, 0xd1, 0x0d, 0x39,
+	0x80, 0x1d, 0xc9, 0x6e, 0x32, 0x7e, 0xce, 0x13, 0x38, 0xcf, 0x33, 0x38,
+	0xf7, 0x9a, 0xec, 0x3d, 0xf6, 0x0a, 0x65, 0xba, 0xbf, 0x2a, 0x99, 0xfe,
+	0x29, 0xd9, 0xe1, 0xcc, 0x43, 0x1f, 0xf3, 0xa3, 0xf5, 0x5b, 0x54, 0x8e,
+	0x63, 0x0e, 0x62, 0x0c, 0x9e, 0xd5, 0x57, 0xe4, 0x21, 0x9f, 0x75, 0x0f,
+	0x81, 0x9f, 0xd0, 0x95, 0xc1, 0x27, 0x8c, 0x1e, 0x60, 0x3e, 0x3b, 0x9c,
+	0xef, 0x15, 0x33, 0x1f, 0xfb, 0xb1, 0x0f, 0xc7, 0x2c, 0xcf, 0xbb, 0x8b,
+	0xb6, 0x08, 0x78, 0xb4, 0x4b, 0xd5, 0x6f, 0x89, 0xa3, 0xfd, 0xc4, 0x20,
+	0xdf, 0x31, 0x0f, 0x6c, 0x91, 0xe3, 0x9e, 0x41, 0x5f, 0xf8, 0x7a, 0xde,
+	0x7a, 0x29, 0x74, 0x85, 0xf4, 0x52, 0x06, 0xe8, 0x27, 0x68, 0x1b, 0xbc,
+	0x39, 0xe0, 0xfd, 0x1f, 0xc6, 0x02, 0x99, 0x3c, 0x80, 0x32, 0xf5, 0xef,
+	0x80, 0x14, 0xbd, 0x0c, 0xf6, 0x09, 0x1d, 0xf3, 0x3b, 0xac, 0x60, 0x8f,
+	0xe0, 0xff, 0xc8, 0x39, 0xf0, 0x41, 0x2a, 0x01, 0x6f, 0xc8, 0x17, 0xf2,
+	0xa4, 0x03, 0xb2, 0x0f, 0xb9, 0x87, 0xdc, 0x96, 0x34, 0x0f, 0xfe, 0xbd,
+	0x33, 0xf0, 0x8b, 0x33, 0x95, 0x3c, 0xe3, 0xb9, 0x4e, 0xe2, 0x26, 0x30,
+	0xcc, 0x87, 0x70, 0x60, 0xee, 0x25, 0xb5, 0x9e, 0xf4, 0xa6, 0x97, 0x62,
+	0x7d, 0x2c, 0xf7, 0x2f, 0x41, 0x86, 0xab, 0x38, 0x9f, 0xc2, 0xce, 0x5e,
+	0x83, 0x5b, 0xcf, 0xc6, 0x28, 0xaf, 0x55, 0x60, 0x4c, 0xc9, 0xdb, 0xe1,
+	0xdc, 0x4d, 0xbe, 0x39, 0x8e, 0x3c, 0xe7, 0x45, 0xb1, 0x03, 0xb6, 0xcf,
+	0xa5, 0x1c, 0x26, 0x21, 0x07, 0x36, 0x6c, 0x68, 0x0a, 0x67, 0xfe, 0x6f,
+	0x9d, 0xc1, 0x5e, 0xf8, 0x6e, 0xcb, 0x9c, 0x83, 0x35, 0xbd, 0xc5, 0x8d,
+	0x41, 0x1d, 0xdf, 0xb7, 0xf0, 0x8c, 0x0e, 0xaf, 0xa4, 0x9d, 0xe7, 0xdb,
+	0x7c, 0xa6, 0x27, 0xb0, 0x17, 0xd6, 0xe3, 0x59, 0x3d, 0x2e, 0x7b, 0x89,
+	0x9b, 0x83, 0xdb, 0x52, 0x2f, 0xa2, 0x7f, 0x11, 0x36, 0xa1, 0x62, 0xb3,
+	0xed, 0x6d, 0x6b, 0x79, 0x8c, 0xa2, 0x5f, 0x0a, 0x1f, 0x78, 0xc9, 0xfa,
+	0x92, 0xff, 0x92, 0x55, 0xa8, 0xbe, 0x6d, 0x15, 0x21, 0x27, 0x55, 0x8f,
+	0xf1, 0x0b, 0xf5, 0xc7, 0xc1, 0xda, 0x99, 0xd4, 0x5b, 0xaa, 0x37, 0x3d,
+	0x0f, 0x2c, 0xb8, 0x1f, 0x3a, 0x5d, 0xb4, 0x17, 0xa4, 0xec, 0xd7, 0xa4,
+	0x74, 0x6c, 0x07, 0xf4, 0x2d, 0x1d, 0xa1, 0x8b, 0x78, 0x56, 0xa1, 0x1f,
+	0x6e, 0xed, 0xf2, 0xa4, 0xd2, 0x92, 0x23, 0xae, 0x6d, 0x83, 0xec, 0xa0,
+	0xae, 0xb6, 0x2c, 0x7f, 0xb7, 0xad, 0xa2, 0x15, 0xb1, 0xee, 0xe0, 0x4a,
+	0x7a, 0xab, 0x72, 0x71, 0x7a, 0x77, 0x35, 0xe8, 0x25, 0x66, 0x00, 0xff,
+	0x3d, 0xe0, 0xbf, 0x07, 0xfc, 0xf7, 0x80, 0xff, 0x1e, 0xf0, 0xdf, 0x83,
+	0x6d, 0xf0, 0x60, 0x03, 0x3c, 0xd8, 0x00, 0x0f, 0x36, 0xc0, 0x83, 0x0d,
+	0xf0, 0x0a, 0x38, 0x27, 0xe2, 0x3c, 0x6d, 0xc8, 0x3d, 0x0d, 0xbb, 0x19,
+	0xf8, 0x39, 0x57, 0x1a, 0xdf, 0x01, 0xfa, 0xe7, 0x6c, 0x91, 0xf1, 0xfe,
+	0x2b, 0xb0, 0xb7, 0x56, 0x3c, 0xdb, 0xf0, 0xc4, 0x1a, 0xfd, 0x9f, 0x35,
+	0x7a, 0xf2, 0x55, 0xd0, 0xa5, 0x50, 0xfe, 0x05, 0xc8, 0x61, 0x0b, 0xe8,
+	0xf9, 0x94, 0xf1, 0x31, 0xbe, 0x61, 0x07, 0x72, 0xd8, 0x86, 0xba, 0xcf,
+	0xa0, 0xae, 0x0d, 0x7d, 0xf6, 0xa3, 0x0f, 0x7d, 0x94, 0x0e, 0x53, 0x17,
+	0xed, 0x47, 0x5f, 0xe5, 0x0b, 0x58, 0x2b, 0x83, 0x7e, 0x1d, 0x98, 0xbb,
+	0x07, 0x7d, 0x6e, 0x46, 0x9f, 0xab, 0x50, 0xa6, 0x6f, 0xdb, 0x8d, 0xf2,
+	0xa7, 0x9b, 0xc6, 0x5c, 0x83, 0xba, 0xcf, 0x36, 0xd5, 0x9d, 0x45, 0x1d,
+	0x62, 0x62, 0xe7, 0x45, 0x33, 0xae, 0x82, 0x72, 0x57, 0x53, 0x9f, 0x57,
+	0x50, 0x37, 0x84, 0xba, 0xbf, 0xc2, 0x13, 0xb1, 0xb0, 0x43, 0x9a, 0xc2,
+	0x36, 0xfa, 0xa9, 0x69, 0xd4, 0xc7, 0x8d, 0xaf, 0xf9, 0x24, 0x7d, 0x2f,
+	0xd8, 0xdc, 0x3f, 0xb6, 0x03, 0xdf, 0x0c, 0xde, 0xab, 0x96, 0xc3, 0xb0,
+	0xfc, 0xcd, 0xa6, 0x32, 0xfb, 0x7e, 0xbf, 0xa9, 0xae, 0x6d, 0xd3, 0xca,
+	0xf2, 0x4f, 0xe3, 0xab, 0xc7, 0xdc, 0xdb, 0xd4, 0xe7, 0xeb, 0x9d, 0x2b,
+	0xcb, 0xbb, 0x5b, 0x56, 0x8f, 0xd9, 0xbe, 0x71, 0x65, 0xdd, 0xad, 0x9b,
+	0x57, 0x96, 0xe9, 0x03, 0x26, 0x11, 0xc3, 0x84, 0xfd, 0x77, 0x7e, 0x22,
+	0x68, 0x27, 0x7f, 0x9b, 0x65, 0x49, 0x2b, 0x23, 0xca, 0x0a, 0xe7, 0xb0,
+	0x64, 0x41, 0x9f, 0x1c, 0x95, 0x7b, 0xc9, 0x2a, 0x42, 0xa6, 0x0a, 0x7e,
+	0x38, 0x1f, 0x75, 0xb6, 0x39, 0x4f, 0x10, 0xe6, 0x07, 0xe8, 0x6f, 0xb5,
+	0x43, 0x6e, 0xee, 0xa2, 0x4d, 0x3a, 0x54, 0x91, 0x65, 0xfd, 0xdc, 0xaa,
+	0xce, 0xa7, 0x9f, 0xf7, 0x19, 0x8c, 0x3a, 0x07, 0x3a, 0xeb, 0x32, 0x92,
+	0x5d, 0x47, 0x1b, 0x63, 0xb0, 0x8b, 0xb8, 0x53, 0xaf, 0xc7, 0xb6, 0xd7,
+	0x65, 0x5f, 0xf6, 0xdd, 0xba, 0x68, 0xcc, 0xbb, 0x57, 0xe3, 0x4e, 0x5a,
+	0x75, 0xe3, 0x8c, 0x1c, 0xc4, 0x12, 0x88, 0xed, 0x93, 0xb4, 0x49, 0xc7,
+	0xe9, 0x9f, 0x1c, 0x0c, 0x30, 0x95, 0xb8, 0x83, 0xb2, 0x3f, 0x85, 0x39,
+	0xb9, 0x3e, 0x9e, 0x55, 0xe2, 0xb8, 0xad, 0x6d, 0x4a, 0xc9, 0xe1, 0xbc,
+	0x6b, 0x61, 0xe3, 0xbf, 0xd8, 0xf4, 0x0b, 0x6d, 0xf7, 0x24, 0xec, 0x1b,
+	0xdb, 0xe8, 0x2b, 0x9c, 0xa4, 0x5f, 0x12, 0xc1, 0xaa, 0x9b, 0x62, 0xe2,
+	0x2e, 0x63, 0x66, 0xb0, 0xaf, 0x2d, 0xf4, 0xfb, 0x2f, 0x61, 0xaf, 0x6b,
+	0x63, 0x51, 0xaf, 0xba, 0xb8, 0x6e, 0xef, 0x69, 0xe8, 0x76, 0x28, 0x7b,
+	0x6b, 0xe5, 0x03, 0x5e, 0xd5, 0x67, 0xf1, 0xac, 0x9f, 0x39, 0x5c, 0x81,
+	0x2e, 0x2d, 0xea, 0xd8, 0x37, 0x3c, 0x17, 0xfa, 0x38, 0x99, 0xe3, 0x73,
+	0x90, 0xed, 0xbd, 0x3a, 0x26, 0x60, 0x3c, 0x50, 0x97, 0x5d, 0xd9, 0x4f,
+	0x25, 0xc9, 0x87, 0xbc, 0xfa, 0x71, 0x9c, 0x3e, 0xc3, 0xa2, 0x47, 0x9e,
+	0x65, 0xd1, 0x9e, 0x05, 0x26, 0xfc, 0xab, 0x14, 0x93, 0xac, 0x7b, 0xab,
+	0x3e, 0x0f, 0xbf, 0x4a, 0xfb, 0x47, 0xda, 0xde, 0xd3, 0xbf, 0x83, 0x5d,
+	0xf7, 0xc9, 0xd3, 0x25, 0xf0, 0x39, 0xf4, 0x01, 0x7e, 0x40, 0x1f, 0x55,
+	0x56, 0xfa, 0xd2, 0x22, 0x0f, 0xd5, 0xfe, 0x01, 0x36, 0x47, 0x05, 0xbe,
+	0x0a, 0xe3, 0x65, 0x97, 0xf5, 0x37, 0xc6, 0xe9, 0xcb, 0x05, 0xb6, 0x3e,
+	0x86, 0xf5, 0x10, 0x5f, 0xd7, 0xfe, 0xd3, 0x2a, 0x79, 0x3d, 0xf4, 0xb3,
+	0xb0, 0x7f, 0xf8, 0x50, 0x3e, 0xdb, 0x58, 0x97, 0x30, 0xfe, 0x77, 0xbb,
+	0xf1, 0xb7, 0x1d, 0xe3, 0x6f, 0x6b, 0x3a, 0x12, 0x4e, 0x2e, 0xf4, 0x0b,
+	0x78, 0x66, 0xe9, 0x83, 0x6a, 0x3b, 0xfd, 0x82, 0x0e, 0x59, 0xdb, 0x2f,
+	0x08, 0x69, 0x3a, 0x85, 0x7d, 0xd2, 0xcf, 0xd3, 0x79, 0xa0, 0xce, 0x20,
+	0xf7, 0x44, 0x1a, 0x42, 0xfb, 0xa8, 0xed, 0xf0, 0x21, 0x98, 0x3c, 0xe6,
+	0x24, 0x41, 0xeb, 0x6e, 0x29, 0x4c, 0x9f, 0x32, 0xf6, 0x96, 0x71, 0x04,
+	0x7d, 0xf8, 0x40, 0x66, 0x0b, 0xd9, 0x0e, 0xcb, 0xcc, 0xd3, 0x05, 0x0b,
+	0x19, 0xc9, 0x51, 0x71, 0x2d, 0xfa, 0x31, 0xa1, 0x4f, 0xb3, 0x60, 0x7c,
+	0x9a, 0x33, 0xb2, 0xcf, 0x0b, 0xe2, 0x86, 0x91, 0xda, 0x12, 0xea, 0x34,
+	0xed, 0x29, 0xfa, 0x96, 0x0a, 0x3e, 0x77, 0xfe, 0xde, 0x0c, 0x02, 0x90,
+	0x60, 0x2f, 0x5b, 0xb1, 0x97, 0x6a, 0x63, 0x2f, 0x6d, 0x4b, 0xcd, 0x3e,
+	0x0e, 0xc7, 0x4e, 0xae, 0x1a, 0x2b, 0xd8, 0xc7, 0xdc, 0x79, 0xda, 0xb8,
+	0x47, 0xfa, 0x0d, 0x8e, 0xd9, 0x63, 0x78, 0x4e, 0x8f, 0x63, 0x8f, 0x49,
+	0xab, 0xa4, 0x7d, 0x2d, 0xfa, 0x2d, 0x88, 0xb3, 0x6b, 0x2f, 0xe1, 0x49,
+	0xfd, 0xd0, 0xf3, 0x60, 0x4f, 0xed, 0x7a, 0x4f, 0x53, 0xde, 0x2b, 0x7a,
+	0x1f, 0xf3, 0xb5, 0xbf, 0x91, 0xf2, 0xb1, 0x1f, 0xc0, 0xee, 0x45, 0x73,
+	0x73, 0xcc, 0x6b, 0x92, 0x1f, 0x95, 0x08, 0x7e, 0x72, 0xaf, 0xcc, 0xbb,
+	0xbd, 0x1c, 0x0f, 0xe2, 0x83, 0x69, 0x9c, 0xb1, 0x15, 0xb4, 0xeb, 0xf5,
+	0x43, 0xbe, 0xb6, 0x44, 0xe8, 0xa9, 0xc3, 0xe7, 0x4c, 0x81, 0x86, 0xe8,
+	0x98, 0x03, 0x32, 0xec, 0xf1, 0x3c, 0x7a, 0x53, 0x7b, 0xc5, 0x75, 0x4a,
+	0x12, 0xfa, 0x19, 0x5c, 0x9f, 0x3a, 0x5f, 0x84, 0xe3, 0xcb, 0x5c, 0x6a,
+	0xc8, 0xbb, 0x90, 0x6f, 0xed, 0x4b, 0xcd, 0x32, 0x30, 0x89, 0x58, 0xab,
+	0xec, 0x91, 0x4f, 0xa1, 0x6c, 0x86, 0x6b, 0xbf, 0x6a, 0x71, 0x3f, 0x13,
+	0x3a, 0x7f, 0xf8, 0x4f, 0x0d, 0x19, 0x1d, 0x07, 0x76, 0x04, 0x32, 0xf7,
+	0xf7, 0x86, 0x37, 0xa1, 0x6c, 0xb6, 0x9b, 0x73, 0x66, 0x2c, 0x48, 0xdd,
+	0x09, 0xe5, 0x60, 0x9b, 0x73, 0xa7, 0xe6, 0x05, 0xdb, 0xb4, 0xcf, 0xad,
+	0xcf, 0x72, 0xac, 0x71, 0x96, 0x1b, 0x9a, 0xe4, 0xf2, 0xdd, 0x8d, 0x81,
+	0x1e, 0x52, 0xdf, 0xa0, 0xb7, 0xe0, 0xd7, 0xb3, 0x2b, 0xf4, 0xbb, 0xff,
+	0x3c, 0x39, 0xd9, 0x76, 0x89, 0xcd, 0x7e, 0x0f, 0xbc, 0xbc, 0x06, 0xb1,
+	0x8a, 0x88, 0x3d, 0x43, 0x1c, 0xa2, 0xbf, 0xb1, 0xec, 0xef, 0xce, 0xcb,
+	0x5a, 0xbe, 0xee, 0xc5, 0x7c, 0x8d, 0x4f, 0x5e, 0xa2, 0xaf, 0x31, 0xdc,
+	0x22, 0xad, 0xc4, 0xa2, 0x33, 0xf0, 0x6d, 0x2d, 0x69, 0x71, 0xbf, 0x01,
+	0x1b, 0x76, 0xda, 0x5e, 0xe7, 0x86, 0x98, 0xd0, 0x2e, 0x9b, 0x66, 0xb7,
+	0x68, 0x5c, 0x70, 0x66, 0x96, 0x71, 0x61, 0x1c, 0xbc, 0x1f, 0x09, 0xf2,
+	0xbc, 0xc9, 0x4d, 0x72, 0xa9, 0xf1, 0xf5, 0xb2, 0xdf, 0x3f, 0xd6, 0xf0,
+	0xfb, 0xaf, 0x6c, 0xe2, 0xe3, 0x5a, 0xb8, 0x78, 0x1a, 0x7c, 0xcb, 0x21,
+	0xfe, 0x65, 0x5c, 0x3b, 0x8c, 0x78, 0x98, 0xb1, 0x58, 0x1e, 0x31, 0x71,
+	0xe6, 0xb4, 0xc8, 0x6e, 0xc4, 0xc8, 0x99, 0x1f, 0x31, 0x7f, 0xf5, 0xbc,
+	0x9f, 0x99, 0x13, 0xb9, 0x1d, 0x7c, 0x1d, 0x04, 0x6e, 0x66, 0x81, 0xa3,
+	0x3b, 0xc1, 0xdf, 0x7e, 0x8d, 0x9d, 0xf7, 0x1f, 0x11, 0xeb, 0x0e, 0x9d,
+	0xab, 0xa6, 0x3e, 0x27, 0x61, 0x47, 0xeb, 0xf5, 0xfd, 0xd9, 0x5e, 0xc4,
+	0xf5, 0x69, 0xb9, 0xd5, 0x66, 0x1c, 0x6b, 0xd9, 0x5b, 0x07, 0xe6, 0x63,
+	0x51, 0x9f, 0xb4, 0x70, 0x51, 0x3b, 0xb0, 0x9a, 0xf7, 0x45, 0x6d, 0x0b,
+	0x0e, 0xc7, 0x2e, 0xc4, 0xfb, 0x3b, 0x1a, 0xbc, 0x6f, 0x69, 0x95, 0xd6,
+	0xdb, 0x75, 0x1e, 0x61, 0xeb, 0xc0, 0x7e, 0xe2, 0x55, 0x16, 0x76, 0x1d,
+	0xf6, 0xb7, 0x2e, 0xb7, 0x65, 0xdf, 0xae, 0xbf, 0xe8, 0x6e, 0x94, 0xd2,
+	0xce, 0xfb, 0x0c, 0x66, 0x2f, 0x7d, 0xad, 0xe0, 0x56, 0xa0, 0x1f, 0x41,
+	0xce, 0x70, 0xef, 0x74, 0x02, 0x96, 0x80, 0x7f, 0x9d, 0x32, 0x3f, 0xf4,
+	0x16, 0xce, 0x70, 0xc7, 0x49, 0x26, 0x9c, 0x14, 0x70, 0x78, 0x3e, 0xd9,
+	0xae, 0xf3, 0xc5, 0x9f, 0x70, 0x59, 0xef, 0xe0, 0x4c, 0x47, 0x65, 0x1e,
+	0xfe, 0x43, 0x75, 0x08, 0x34, 0xee, 0xec, 0x42, 0x7f, 0xea, 0x1d, 0x79,
+	0x3e, 0x0a, 0xdb, 0x4b, 0x9e, 0x26, 0xd1, 0x7f, 0x0f, 0xfa, 0x74, 0xe2,
+	0x79, 0x5f, 0x6c, 0xde, 0x61, 0xec, 0xfc, 0x79, 0x94, 0x39, 0x47, 0xd4,
+	0x76, 0x7e, 0x2e, 0x2e, 0x7a, 0x4e, 0x8e, 0xe9, 0xd2, 0xfa, 0xbf, 0xbc,
+	0x16, 0xd7, 0x61, 0xdb, 0xcf, 0xea, 0xd7, 0x0f, 0x0c, 0x45, 0xd6, 0xeb,
+	0x88, 0xac, 0x37, 0x14, 0x59, 0x8f, 0x74, 0x76, 0x46, 0xe8, 0xec, 0xc4,
+	0xf8, 0x22, 0xd6, 0x26, 0x3f, 0xa2, 0x6b, 0x3e, 0x18, 0x59, 0x33, 0xdc,
+	0x5f, 0x57, 0x64, 0xdc, 0xbb, 0x58, 0x8f, 0x75, 0xc9, 0x48, 0x1d, 0x69,
+	0xd8, 0x8c, 0x3a, 0x96, 0x3b, 0x23, 0x74, 0x91, 0xd6, 0x0d, 0xa8, 0xd7,
+	0xfe, 0x13, 0xf8, 0xdc, 0x0a, 0xbb, 0xa5, 0x60, 0x3b, 0x5a, 0xe0, 0x5f,
+	0x35, 0xef, 0xf5, 0x51, 0xac, 0x1b, 0xce, 0x97, 0xc4, 0x1c, 0xec, 0xcf,
+	0xbe, 0x31, 0x33, 0x9e, 0xf5, 0x6c, 0xff, 0xf3, 0xfa, 0x9f, 0x6a, 0xbe,
+	0x6d, 0x06, 0xed, 0x3a, 0xef, 0x22, 0x73, 0x9d, 0x36, 0xce, 0x93, 0xf1,
+	0xb1, 0x25, 0x57, 0xbb, 0xca, 0xea, 0x1d, 0xe0, 0xd9, 0x6f, 0x34, 0x58,
+	0xda, 0x6a, 0x15, 0x8e, 0x30, 0x5f, 0xd0, 0x66, 0x62, 0x3e, 0xc4, 0x1e,
+	0xda, 0xc6, 0xd8, 0xa6, 0x9d, 0x36, 0x86, 0x7e, 0x0b, 0xed, 0xe7, 0x69,
+	0xf3, 0x8e, 0x27, 0x64, 0xf8, 0x81, 0x6a, 0xa7, 0xbc, 0xa8, 0x79, 0xea,
+	0xc8, 0xd9, 0x06, 0x4f, 0xe3, 0xe6, 0xbb, 0xcc, 0x01, 0xf3, 0xcd, 0xa3,
+	0x0f, 0x7e, 0x11, 0xde, 0x6b, 0x79, 0xd0, 0x90, 0x96, 0xde, 0x01, 0xc6,
+	0x6e, 0x15, 0x3c, 0x99, 0xa7, 0xb0, 0xf0, 0x0c, 0xf2, 0x17, 0xbd, 0x03,
+	0xb0, 0x4b, 0xc0, 0xa1, 0xde, 0x81, 0x73, 0x3a, 0x9e, 0xab, 0xfa, 0x8e,
+	0x75, 0x9b, 0x17, 0xe4, 0x88, 0xce, 0xba, 0x17, 0xca, 0x11, 0xdd, 0xb3,
+	0x8e, 0x79, 0x8d, 0x30, 0x47, 0x74, 0x56, 0x74, 0x8e, 0xe8, 0xf8, 0x45,
+	0x72, 0x44, 0xf9, 0x4b, 0xcf, 0x11, 0x71, 0x7e, 0x5b, 0xee, 0x1c, 0x74,
+	0xd4, 0xaf, 0x9a, 0x1c, 0xd1, 0x1b, 0x12, 0xe4, 0x88, 0x5e, 0x94, 0xb5,
+	0x73, 0x44, 0x87, 0x9a, 0x72, 0x44, 0x9b, 0x75, 0x8e, 0x88, 0xf3, 0x04,
+	0x39, 0x22, 0x96, 0x4b, 0x03, 0x43, 0x91, 0x5c, 0x07, 0xf0, 0xd7, 0xbb,
+	0x01, 0x7c, 0x73, 0xac, 0x51, 0x2f, 0xc4, 0x34, 0x62, 0xff, 0x15, 0x0d,
+	0xfb, 0xb5, 0x8c, 0x6f, 0x96, 0x96, 0xb9, 0x8b, 0xe1, 0xdb, 0x68, 0xe0,
+	0x97, 0xac, 0xc0, 0xb6, 0xc9, 0x86, 0xef, 0xe2, 0xad, 0x63, 0x0c, 0x3d,
+	0x51, 0x5b, 0x9e, 0x77, 0x02, 0xbc, 0x1e, 0x6b, 0xe4, 0x49, 0xce, 0xe7,
+	0x1f, 0x25, 0xe5, 0xc0, 0x9a, 0xdf, 0xbd, 0x52, 0xf9, 0xd5, 0xdf, 0xbd,
+	0x2c, 0x49, 0x82, 0xce, 0xd2, 0x40, 0x49, 0xc7, 0x5d, 0xf3, 0xde, 0xaf,
+	0xc8, 0xd2, 0xdd, 0x0e, 0xf0, 0x27, 0xcc, 0x9f, 0xf0, 0x7c, 0x97, 0x6d,
+	0x4a, 0x41, 0x7d, 0x7c, 0x39, 0x94, 0x07, 0x74, 0x0e, 0xe5, 0xc5, 0x75,
+	0xd1, 0x1c, 0xca, 0x59, 0xb9, 0x70, 0x0e, 0xe5, 0x81, 0x35, 0x72, 0x28,
+	0x2f, 0xcb, 0x72, 0x0e, 0xe5, 0x65, 0x09, 0x73, 0x28, 0x31, 0x59, 0xda,
+	0x1c, 0x48, 0xe3, 0x03, 0xfe, 0x12, 0x7e, 0x67, 0xf0, 0x0b, 0x72, 0x2a,
+	0x67, 0x1b, 0xf4, 0xaf, 0x95, 0x53, 0x79, 0x7d, 0xdd, 0x07, 0xc9, 0xa9,
+	0x04, 0x36, 0x20, 0xcc, 0xa9, 0xe0, 0xe7, 0xc0, 0xe6, 0xa8, 0x68, 0x4e,
+	0xe5, 0x27, 0xd4, 0x07, 0xd4, 0xb1, 0xcc, 0x7a, 0xe8, 0x05, 0xec, 0x52,
+	0x5e, 0xe7, 0x38, 0x3e, 0x67, 0x78, 0x38, 0x87, 0x3d, 0xa7, 0x71, 0x16,
+	0xe4, 0x63, 0xaf, 0xf6, 0x2d, 0xf3, 0x76, 0xca, 0x2a, 0xf4, 0xc1, 0x9a,
+	0x4d, 0xf3, 0xbb, 0xb8, 0x6d, 0xed, 0xf5, 0x29, 0xe3, 0x09, 0xab, 0x8c,
+	0xbd, 0x0c, 0x4f, 0xcf, 0xc9, 0x5e, 0x3f, 0xf4, 0xa9, 0x06, 0x1a, 0x73,
+	0x50, 0x37, 0xe7, 0x81, 0xb3, 0xc0, 0x89, 0x4b, 0xb0, 0x51, 0xa7, 0x40,
+	0x73, 0x74, 0x1f, 0x88, 0x89, 0x07, 0x51, 0xa7, 0xcf, 0x9c, 0xbe, 0x65,
+	0x48, 0x4b, 0x9a, 0x7a, 0x7e, 0x09, 0xf3, 0xb1, 0xee, 0x94, 0x8e, 0xc7,
+	0xca, 0x83, 0xdc, 0x2b, 0x6d, 0xdd, 0x22, 0xe8, 0x43, 0x5d, 0x95, 0x31,
+	0x20, 0xed, 0x5e, 0x18, 0xa3, 0xb5, 0xeb, 0x18, 0xad, 0x4b, 0xf3, 0x83,
+	0xbc, 0xbe, 0x35, 0x41, 0xac, 0xec, 0x72, 0xb9, 0x87, 0x33, 0x06, 0xeb,
+	0x58, 0x0e, 0x62, 0xc1, 0xbc, 0xe2, 0xfb, 0xef, 0xe1, 0x5c, 0x99, 0xa7,
+	0x09, 0xcf, 0xef, 0x2b, 0x66, 0xdf, 0x43, 0x52, 0xe9, 0x92, 0xc4, 0x66,
+	0xd0, 0x53, 0x9a, 0xa1, 0xdf, 0xfd, 0x69, 0x1d, 0x83, 0x24, 0xdd, 0xf3,
+	0xeb, 0xed, 0x1d, 0x97, 0xa1, 0xb7, 0x23, 0x17, 0xd4, 0xdb, 0xaf, 0x25,
+	0xa2, 0x7a, 0x7b, 0xc7, 0x65, 0xe8, 0xed, 0xbe, 0xcb, 0xd2, 0x5b, 0xee,
+	0x8d, 0x98, 0x14, 0xe6, 0xc4, 0x56, 0xfb, 0x59, 0xe1, 0xba, 0xe3, 0x58,
+	0x33, 0x7f, 0x9e, 0x35, 0xc7, 0xce, 0x9b, 0x5b, 0x6d, 0xf6, 0xb1, 0x2e,
+	0xe5, 0xbc, 0x19, 0x5b, 0xd1, 0xde, 0xb6, 0x1b, 0xbb, 0x74, 0x9f, 0x89,
+	0xe7, 0xc3, 0xb8, 0x3e, 0xaa, 0x3f, 0x94, 0x0b, 0xca, 0xc2, 0x77, 0xc0,
+	0x2f, 0xca, 0x43, 0xa8, 0x73, 0xdd, 0x4d, 0x32, 0xb8, 0x88, 0x78, 0xbf,
+	0xdb, 0xc8, 0x20, 0xcf, 0xba, 0x4f, 0x7f, 0x67, 0xaa, 0x7a, 0x4f, 0x05,
+	0x71, 0xbe, 0x8b, 0x67, 0x35, 0xd4, 0x35, 0xf0, 0x24, 0x19, 0xb6, 0x91,
+	0x8f, 0x2e, 0x7c, 0x9e, 0x1d, 0xf0, 0xd7, 0xc0, 0x23, 0x5d, 0xbf, 0x32,
+	0x27, 0x7c, 0x61, 0x3c, 0x93, 0x4a, 0x1c, 0x7d, 0x4f, 0x0c, 0x42, 0xc7,
+	0x07, 0x89, 0x51, 0x35, 0xc4, 0x3d, 0x94, 0x43, 0xca, 0xe6, 0xb6, 0xfe,
+	0x5d, 0x8a, 0x3e, 0xd5, 0x13, 0x88, 0x83, 0x29, 0xaf, 0x69, 0xd9, 0xe5,
+	0x6f, 0x3b, 0x7d, 0x56, 0x71, 0x8d, 0x7a, 0xbd, 0xc4, 0x58, 0xd1, 0x11,
+	0xb5, 0x75, 0xe0, 0xbf, 0x13, 0xb4, 0x4b, 0x57, 0xb8, 0x31, 0x23, 0x6b,
+	0x79, 0xbc, 0x53, 0x6e, 0x7f, 0x08, 0x7b, 0xcf, 0xef, 0xfd, 0xaf, 0xa1,
+	0x3e, 0x05, 0x9d, 0xa7, 0x7d, 0x67, 0x3c, 0x72, 0x93, 0xe9, 0xd7, 0xad,
+	0xbf, 0x57, 0x16, 0xb2, 0x37, 0x98, 0x6f, 0x57, 0xb4, 0x3f, 0x19, 0xda,
+	0xec, 0x15, 0xe7, 0xcc, 0xfb, 0x12, 0x45, 0x1d, 0xcf, 0x70, 0xbc, 0x96,
+	0x49, 0xc4, 0x20, 0x76, 0x24, 0x97, 0x9e, 0x30, 0xb1, 0x1b, 0x75, 0xac,
+	0x1d, 0x67, 0xe8, 0x9b, 0x58, 0x85, 0xf1, 0xeb, 0xca, 0x7b, 0x12, 0x6b,
+	0xcb, 0xc0, 0x96, 0x0f, 0x20, 0x03, 0xcd, 0xe7, 0x97, 0x80, 0xee, 0x87,
+	0xe7, 0x17, 0xfa, 0x31, 0x73, 0x66, 0xdf, 0xdd, 0xc1, 0x19, 0xfe, 0xbf,
+	0xd8, 0xa7, 0x15, 0xd9, 0x67, 0x88, 0x47, 0x0f, 0x98, 0x7d, 0xde, 0xd4,
+	0x84, 0x47, 0x23, 0x4d, 0x3a, 0xfb, 0x71, 0xe2, 0xd1, 0x9f, 0xac, 0xff,
+	0xf8, 0xf1, 0x88, 0xfb, 0xea, 0x5e, 0x13, 0x87, 0x82, 0x7d, 0x3c, 0x22,
+	0x2a, 0xf7, 0x51, 0xc6, 0x7b, 0x1f, 0xe4, 0x7c, 0xa2, 0x38, 0xc2, 0x33,
+	0xe9, 0xd0, 0x3e, 0x6c, 0xa0, 0x7b, 0xb0, 0xe5, 0xd5, 0xb8, 0xbc, 0x7e,
+	0x57, 0x42, 0xfe, 0xf7, 0x46, 0x7e, 0x0f, 0xb3, 0x4d, 0x4e, 0x8b, 0xe5,
+	0xd7, 0xd6, 0x07, 0x76, 0xe8, 0xb5, 0x4d, 0x81, 0xdd, 0xe1, 0x98, 0x50,
+	0x9f, 0x1d, 0xb4, 0xb3, 0xad, 0x5b, 0x96, 0x3a, 0x2f, 0x27, 0x06, 0xdc,
+	0xe6, 0xbc, 0xa1, 0xd6, 0x8a, 0x01, 0x2f, 0x9c, 0x0f, 0x5c, 0x8e, 0x01,
+	0x89, 0xb3, 0x9d, 0x5a, 0x36, 0x4a, 0x49, 0xc6, 0x3e, 0x7d, 0x06, 0x3b,
+	0xf9, 0x8e, 0xd8, 0xd6, 0x43, 0xbc, 0xeb, 0x21, 0xd6, 0xf5, 0x10, 0xff,
+	0x7a, 0x88, 0x71, 0x3d, 0xc4, 0xb6, 0x1e, 0x62, 0x5b, 0x0f, 0xb1, 0xad,
+	0xd7, 0x6f, 0x62, 0xe4, 0x11, 0x93, 0xf7, 0xe7, 0x77, 0x72, 0xe6, 0x17,
+	0x2a, 0xb0, 0x25, 0x93, 0xbc, 0xe7, 0xa0, 0x0a, 0xd9, 0xf5, 0x66, 0x7f,
+	0x61, 0x4e, 0xbc, 0xc7, 0xe4, 0x6c, 0x5e, 0xd7, 0x79, 0x43, 0x51, 0xb3,
+	0xad, 0xc1, 0xb7, 0x74, 0xde, 0xc7, 0xf8, 0x2d, 0xf8, 0x25, 0xfa, 0x3e,
+	0x13, 0x75, 0xb4, 0xae, 0x72, 0xcc, 0xc9, 0x88, 0x52, 0xb9, 0xeb, 0x31,
+	0x66, 0x47, 0x10, 0x13, 0x24, 0x25, 0xa6, 0x72, 0x6d, 0xe4, 0xa9, 0xa5,
+	0x72, 0x1b, 0xcc, 0x5c, 0x47, 0x5b, 0x03, 0xdf, 0xaa, 0x8f, 0x65, 0x5b,
+	0xe5, 0x6e, 0xe6, 0x13, 0xe7, 0x1e, 0xd6, 0xf7, 0x74, 0xae, 0x5c, 0x6b,
+	0x4a, 0xe3, 0x7b, 0x21, 0x7b, 0x37, 0xe6, 0xd3, 0xf7, 0x88, 0x1a, 0xfc,
+	0x56, 0xe7, 0xe5, 0xf7, 0x94, 0xe1, 0x77, 0xc0, 0xe3, 0x18, 0xfb, 0xe9,
+	0xbc, 0x30, 0x79, 0x1d, 0xce, 0xa7, 0xf3, 0x7a, 0x58, 0x47, 0xdf, 0xa5,
+	0xc0, 0x53, 0xc5, 0xa5, 0x63, 0xf4, 0x9e, 0xb8, 0x1b, 0x5d, 0x37, 0xfc,
+	0x26, 0x7e, 0x29, 0x6b, 0x76, 0xeb, 0xef, 0x68, 0x81, 0xcd, 0x98, 0xd2,
+	0x32, 0x68, 0xe7, 0xb8, 0xaf, 0xf7, 0x21, 0x7f, 0x53, 0x5a, 0xfe, 0x8a,
+	0x88, 0x63, 0x26, 0x07, 0xb7, 0xa5, 0x6d, 0x75, 0xa0, 0x95, 0xf9, 0xd7,
+	0x61, 0x3f, 0xc4, 0x3d, 0xae, 0xd7, 0x6c, 0xc7, 0x99, 0x57, 0x0b, 0xf1,
+	0x4c, 0xb6, 0x04, 0xf9, 0xb6, 0x0f, 0xa3, 0x4b, 0xad, 0x4d, 0xba, 0x14,
+	0xee, 0x93, 0xfb, 0xe7, 0x73, 0xed, 0x3b, 0x15, 0x8b, 0x7e, 0xe4, 0xfb,
+	0x48, 0x43, 0x36, 0x78, 0xb7, 0xe4, 0x8b, 0x90, 0x41, 0xfd, 0x9d, 0x02,
+	0x7a, 0x54, 0xaf, 0x0f, 0x33, 0xc7, 0xbc, 0xf3, 0x0b, 0xe6, 0xde, 0x82,
+	0x3c, 0xcc, 0xfc, 0x83, 0xbd, 0x2a, 0xff, 0x30, 0x0c, 0x59, 0x81, 0x0f,
+	0xe0, 0x75, 0x68, 0x9f, 0x4e, 0xb9, 0xf4, 0x07, 0x9a, 0xbf, 0xbf, 0x3c,
+	0xda, 0x16, 0xf0, 0xe1, 0xed, 0xd6, 0xe0, 0x1b, 0xc4, 0xdf, 0x26, 0x57,
+	0x96, 0x39, 0xfe, 0x7f, 0x8c, 0xac, 0x1c, 0x86, 0x6d, 0x1e, 0x86, 0x2c,
+	0x22, 0x26, 0xd7, 0xf3, 0x1d, 0x96, 0xd2, 0xd3, 0x0b, 0x9d, 0x2b, 0xfb,
+	0xa3, 0xee, 0x58, 0xd8, 0xff, 0xb1, 0xa6, 0xfe, 0x8f, 0xa1, 0xff, 0x0b,
+	0x4d, 0xfd, 0x1f, 0x8b, 0xf4, 0x3f, 0xda, 0xd4, 0x1f, 0x31, 0xe2, 0xd3,
+	0xff, 0xdc, 0xd4, 0xff, 0x68, 0xa4, 0xff, 0x6c, 0x53, 0xff, 0x59, 0xf4,
+	0x7f, 0xad, 0xa9, 0x3f, 0xea, 0x8e, 0xb5, 0x98, 0xef, 0x62, 0xc4, 0xd8,
+	0x7d, 0x26, 0x16, 0xc7, 0xb3, 0xd6, 0xfc, 0xad, 0x85, 0x72, 0xd7, 0x83,
+	0x33, 0x08, 0xef, 0xb4, 0x51, 0x5f, 0xf3, 0xd0, 0xd7, 0x65, 0x5f, 0x26,
+	0x90, 0xc7, 0xa8, 0x2c, 0x12, 0x1f, 0x2a, 0x12, 0x73, 0x7d, 0xfa, 0x47,
+	0x56, 0xb9, 0x1a, 0xda, 0x24, 0xde, 0x5b, 0xe2, 0x7d, 0xd7, 0xc0, 0xf6,
+	0xc6, 0xdd, 0x45, 0x13, 0x83, 0x5d, 0xd1, 0x06, 0xda, 0x81, 0x97, 0x21,
+	0x66, 0xca, 0xe1, 0x40, 0x6f, 0x28, 0xbf, 0x9c, 0xdf, 0xe8, 0x0f, 0x65,
+	0xd5, 0xac, 0x33, 0xbc, 0x0a, 0xd7, 0xd2, 0xab, 0x72, 0x5b, 0xb1, 0x4b,
+	0xc0, 0xb5, 0x91, 0x06, 0xae, 0x7d, 0x51, 0xe6, 0x1a, 0xf1, 0xf6, 0x19,
+	0xd9, 0xef, 0xed, 0xe1, 0x3d, 0x9d, 0xc3, 0x79, 0xf9, 0x68, 0xe2, 0xed,
+	0x3d, 0x0d, 0x3b, 0xc9, 0x3b, 0x1d, 0xe9, 0x83, 0xbc, 0x83, 0x1b, 0xe6,
+	0x66, 0x27, 0xbd, 0x5f, 0xc7, 0xfe, 0x69, 0x33, 0x2f, 0x37, 0xde, 0xe6,
+	0x7c, 0x49, 0xd9, 0x1f, 0xdc, 0x77, 0x68, 0xcc, 0x5b, 0x69, 0xcc, 0x9b,
+	0x32, 0xfa, 0x46, 0x1b, 0xbc, 0x6c, 0x2f, 0x8b, 0xb0, 0x97, 0x63, 0x88,
+	0xb9, 0x17, 0xbd, 0xb5, 0xf2, 0xa3, 0x97, 0x6b, 0x2f, 0x9b, 0xf3, 0xcc,
+	0xcd, 0xf6, 0x92, 0xeb, 0x34, 0xe7, 0x96, 0xd3, 0x4d, 0xf8, 0x4f, 0x79,
+	0x3a, 0x67, 0x7c, 0x6a, 0x3c, 0xab, 0xe7, 0xa0, 0x8f, 0x4a, 0xc6, 0xb4,
+	0xfc, 0xb2, 0x1c, 0xc6, 0x96, 0xf7, 0x34, 0x62, 0xcb, 0xe5, 0x78, 0x10,
+	0xbe, 0x6b, 0xff, 0x67, 0x0c, 0x3e, 0xd2, 0x47, 0x76, 0xac, 0xb2, 0xb7,
+	0x5b, 0xed, 0xd5, 0x6d, 0xcc, 0x97, 0x5e, 0x2b, 0xb7, 0xea, 0x38, 0xfe,
+	0x8c, 0xc9, 0x4d, 0xcd, 0x69, 0xff, 0x9f, 0xdf, 0x0b, 0xca, 0xd9, 0x4d,
+	0xc6, 0xdf, 0xbb, 0x18, 0xae, 0xae, 0x8c, 0x4d, 0x95, 0x3a, 0x88, 0xb1,
+	0x8c, 0x4d, 0xfb, 0xdb, 0x89, 0xa1, 0x05, 0xff, 0x82, 0xe3, 0x31, 0x8e,
+	0xe3, 0xd9, 0x47, 0xc7, 0xa1, 0xe8, 0xb7, 0x68, 0xc6, 0x07, 0x71, 0x68,
+	0xc1, 0xff, 0x71, 0x5b, 0x80, 0x83, 0x17, 0x8a, 0x59, 0x3e, 0xdf, 0xce,
+	0xbc, 0xde, 0xa2, 0x77, 0x31, 0x5a, 0x57, 0xc7, 0xbd, 0xb1, 0x55, 0x71,
+	0xaf, 0x6d, 0xe2, 0xda, 0x5f, 0xd2, 0x71, 0x6f, 0xc0, 0x63, 0xee, 0x25,
+	0x1a, 0x47, 0xb9, 0xc0, 0x42, 0x7e, 0x53, 0x21, 0x3e, 0xd0, 0x47, 0x81,
+	0x9f, 0x35, 0xfd, 0x8b, 0xe0, 0x73, 0x72, 0x0d, 0xb9, 0xf9, 0xb8, 0xed,
+	0x44, 0xb8, 0xf7, 0x73, 0x12, 0xe4, 0xeb, 0x76, 0x83, 0x16, 0xc6, 0x56,
+	0x71, 0x23, 0x0f, 0x3f, 0x35, 0xf7, 0x2a, 0xc3, 0x7e, 0x61, 0x1c, 0xdf,
+	0xf8, 0xee, 0x5a, 0xc9, 0xaf, 0xc8, 0x9f, 0x74, 0x33, 0x0d, 0x8d, 0x73,
+	0xcf, 0x5f, 0xc6, 0x77, 0x8b, 0x0f, 0x73, 0x3f, 0xa2, 0xd9, 0xae, 0xf1,
+	0xbb, 0x29, 0xbf, 0x95, 0x8a, 0x75, 0x67, 0x9f, 0x0b, 0x1d, 0xe0, 0xbd,
+	0xe1, 0x28, 0xbe, 0x26, 0xa4, 0x34, 0x2b, 0x89, 0x64, 0x8e, 0xdf, 0x00,
+	0x68, 0xff, 0x7f, 0x68, 0xf6, 0x99, 0x92, 0x7d, 0x33, 0x41, 0xce, 0x53,
+	0x5d, 0xf0, 0x5e, 0xdc, 0xe3, 0xe0, 0x43, 0xe6, 0x50, 0x98, 0xf3, 0x54,
+	0xc1, 0xbd, 0xb8, 0x43, 0x1f, 0xdd, 0xbd, 0x38, 0xce, 0x6f, 0xcb, 0x9e,
+	0x35, 0xee, 0xc5, 0xc5, 0x2e, 0xf1, 0x5e, 0xdc, 0x26, 0x9d, 0xf3, 0xe4,
+	0x3c, 0x41, 0xce, 0x93, 0xe5, 0xad, 0x03, 0xcc, 0x95, 0xf0, 0xee, 0xdb,
+	0xa0, 0xbe, 0x2f, 0xbc, 0x75, 0xe0, 0xe7, 0x11, 0xa3, 0xfc, 0x75, 0xfb,
+	0xc7, 0x1f, 0xa3, 0x70, 0x2f, 0xbf, 0x11, 0x7c, 0xdf, 0x95, 0xcb, 0xc9,
+	0x03, 0x7c, 0xb8, 0xbc, 0xe6, 0x3e, 0x9d, 0xd7, 0x7c, 0xa7, 0x3d, 0x9a,
+	0xd7, 0x54, 0x17, 0xb9, 0x1b, 0xb6, 0x6f, 0x8d, 0xbc, 0x66, 0x3c, 0x72,
+	0x37, 0x2c, 0x6e, 0xee, 0x86, 0x6d, 0x72, 0x11, 0x4b, 0x9a, 0x3c, 0xa6,
+	0xba, 0xe0, 0xdd, 0xb0, 0xce, 0x0d, 0x1f, 0x3e, 0x8f, 0xb9, 0xea, 0x6e,
+	0x18, 0x6c, 0xdd, 0x16, 0x49, 0x5f, 0x56, 0xdc, 0xf3, 0x61, 0x62, 0x1e,
+	0xde, 0xab, 0x6f, 0xc1, 0x9e, 0xe3, 0xb2, 0x27, 0x49, 0xf9, 0xe4, 0xdd,
+	0xc6, 0x3e, 0xe8, 0x02, 0x9e, 0x3e, 0xcb, 0xfd, 0x3c, 0x23, 0x6b, 0xa4,
+	0x6f, 0xe5, 0x3d, 0x84, 0xe5, 0x3b, 0xbd, 0x89, 0xc6, 0x9d, 0xde, 0x29,
+	0xc8, 0x8d, 0x9a, 0x49, 0xc8, 0x7c, 0x44, 0xa6, 0x26, 0x3d, 0xf8, 0x4b,
+	0xb3, 0x8e, 0x69, 0xe7, 0xff, 0xef, 0x48, 0x02, 0xf3, 0x78, 0x0f, 0xb8,
+	0x43, 0x62, 0xb3, 0xc1, 0x37, 0xcb, 0xe0, 0xff, 0xb8, 0xa4, 0xd0, 0x87,
+	0x77, 0x3c, 0xe3, 0xb2, 0x5f, 0xe7, 0x2c, 0x42, 0x59, 0xfe, 0x35, 0xf0,
+	0x78, 0x73, 0x7e, 0xb9, 0x9c, 0x5c, 0xc3, 0xee, 0x27, 0xa5, 0x3c, 0x43,
+	0x79, 0xbe, 0xc1, 0xfc, 0xff, 0x82, 0xd3, 0x52, 0xf6, 0x4f, 0x99, 0xf8,
+	0x42, 0x7f, 0xdb, 0x01, 0x2f, 0xb7, 0x18, 0x1b, 0x8c, 0x67, 0x75, 0x0b,
+	0x6d, 0x1e, 0xd6, 0x38, 0x2e, 0xc3, 0xd3, 0x3b, 0x52, 0x7b, 0x81, 0x77,
+	0x63, 0x7a, 0xcd, 0xcb, 0xe1, 0xb9, 0x75, 0x9e, 0xef, 0x8d, 0x97, 0xca,
+	0xf7, 0xd0, 0x3f, 0xae, 0x62, 0x7f, 0x5b, 0x20, 0x1f, 0x5f, 0x95, 0xe2,
+	0xb1, 0x6b, 0x65, 0xf8, 0x68, 0x06, 0xf4, 0xbc, 0x5f, 0x2f, 0x67, 0xe1,
+	0x4b, 0x3f, 0xcd, 0x7b, 0x63, 0xc0, 0x50, 0xf0, 0xed, 0xf9, 0x55, 0xdf,
+	0xb1, 0xa3, 0x77, 0xcd, 0xfa, 0x1b, 0x77, 0x87, 0x9e, 0xf5, 0x25, 0xd1,
+	0x49, 0x9a, 0x67, 0x96, 0xef, 0x8f, 0x2f, 0xfa, 0xbb, 0xb4, 0x6d, 0x7b,
+	0xc6, 0x5f, 0x91, 0xfb, 0xd1, 0x67, 0x38, 0x5e, 0xfb, 0x1e, 0xec, 0xdb,
+	0x39, 0x8b, 0xf6, 0x6d, 0xca, 0x93, 0xab, 0x63, 0xc2, 0xf3, 0x10, 0x0b,
+	0x3c, 0xd0, 0x77, 0x38, 0x82, 0xef, 0xfb, 0x3d, 0xfa, 0x5c, 0x03, 0xac,
+	0x58, 0x88, 0xdc, 0xc1, 0x58, 0x3e, 0xdb, 0xe0, 0x6e, 0x46, 0x70, 0x16,
+	0xc1, 0xfd, 0x11, 0xed, 0x6f, 0x1e, 0xdc, 0xe3, 0x06, 0xf7, 0x47, 0x7a,
+	0x67, 0x59, 0xd7, 0xd5, 0x64, 0xfb, 0x12, 0x90, 0x01, 0xde, 0x3b, 0xe2,
+	0xbd, 0x71, 0xd2, 0xac, 0x73, 0x1d, 0xff, 0x47, 0xdd, 0xd5, 0xc7, 0xb6,
+	0x75, 0x5d, 0xf7, 0xc3, 0x47, 0xea, 0xc3, 0xb4, 0x2c, 0x53, 0x32, 0x25,
+	0xd3, 0x96, 0x2c, 0xbf, 0x27, 0x3d, 0x59, 0x72, 0xac, 0x14, 0xac, 0xab,
+	0xad, 0x02, 0x46, 0xa4, 0x0c, 0x49, 0x7f, 0xb4, 0x08, 0x06, 0xfa, 0xa3,
+	0x99, 0x8b, 0x66, 0xab, 0x4b, 0xd9, 0x4e, 0x0a, 0xf4, 0x0f, 0xb7, 0xc5,
+	0x80, 0x6c, 0x58, 0x60, 0x86, 0xb4, 0x12, 0x63, 0x56, 0x4c, 0xd6, 0x66,
+	0x85, 0x0c, 0xd8, 0x30, 0x4e, 0x54, 0x9c, 0x14, 0x50, 0xc6, 0x04, 0x69,
+	0x83, 0xa2, 0x58, 0x61, 0x45, 0x76, 0x36, 0x6c, 0x7f, 0x65, 0x43, 0xd0,
+	0x05, 0x9b, 0xb3, 0x38, 0x76, 0xb0, 0x06, 0x45, 0xd6, 0x7d, 0x62, 0x18,
+	0xd0, 0x0d, 0xdc, 0xf9, 0xdd, 0x0f, 0xf2, 0xf1, 0xf1, 0x51, 0x1f, 0x89,
+	0x33, 0x60, 0x02, 0x04, 0xbe, 0xf7, 0x78, 0xdf, 0x7b, 0xf7, 0x9e, 0x7b,
+	0xce, 0xb9, 0xbf, 0x73, 0xee, 0x39, 0x87, 0x9e, 0x7b, 0xdb, 0x9b, 0xf3,
+	0xb9, 0xca, 0x77, 0x8e, 0x8a, 0x77, 0x0e, 0x28, 0x9d, 0xa5, 0xe3, 0xc5,
+	0x63, 0xc6, 0x6c, 0x61, 0x22, 0xe2, 0x67, 0xfe, 0x9e, 0xad, 0xc2, 0xbe,
+	0x6e, 0x87, 0xe1, 0xd6, 0xa2, 0x67, 0xbc, 0x85, 0x9e, 0xcd, 0x32, 0xc1,
+	0xf6, 0x78, 0x5d, 0x77, 0x4b, 0xda, 0xc9, 0xeb, 0x88, 0x85, 0xd7, 0x31,
+	0x0e, 0x92, 0x76, 0x75, 0x19, 0xba, 0xe2, 0x8c, 0x6f, 0x68, 0xd0, 0xee,
+	0x74, 0x9d, 0x76, 0x3b, 0xff, 0x1f, 0xd1, 0xee, 0x1d, 0x81, 0x7f, 0x5f,
+	0xad, 0x22, 0x6e, 0x4d, 0x63, 0x00, 0x9d, 0x3b, 0x04, 0x3a, 0x42, 0x9f,
+	0x5a, 0xe5, 0x15, 0x82, 0x4e, 0x45, 0x5c, 0x71, 0xad, 0xf6, 0x5a, 0xb4,
+	0xee, 0xa7, 0x64, 0xbb, 0x04, 0xf6, 0x09, 0xfc, 0x79, 0xed, 0xd7, 0xc8,
+	0x63, 0x1f, 0x6b, 0x8d, 0x04, 0x56, 0x72, 0xdb, 0x27, 0x0c, 0x08, 0x1d,
+	0xf6, 0xc9, 0xb1, 0x4d, 0xda, 0x27, 0xe7, 0xa5, 0x7d, 0x92, 0xdd, 0xb8,
+	0x7d, 0xb2, 0xbb, 0x25, 0xae, 0xab, 0x31, 0x9e, 0xcd, 0xdb, 0x27, 0xc6,
+	0x9a, 0xf6, 0xc9, 0x90, 0xc3, 0x17, 0x83, 0xfe, 0xfe, 0x06, 0x65, 0x8f,
+	0x43, 0xc7, 0x69, 0x3a, 0x83, 0xc6, 0xc7, 0x5d, 0x7e, 0xe1, 0x4f, 0x93,
+	0xd6, 0xbf, 0xf8, 0x3f, 0xa6, 0xf5, 0x50, 0x8b, 0xcf, 0xbb, 0x31, 0x1e,
+	0x0a, 0xef, 0xd8, 0x14, 0x8e, 0x77, 0xd3, 0x7a, 0xa8, 0xad, 0xef, 0xb4,
+	0x7d, 0xcc, 0x62, 0xb3, 0xef, 0x74, 0xd4, 0x68, 0xa7, 0xdb, 0xff, 0xd8,
+	0xe1, 0x53, 0x75, 0xea, 0x77, 0xc8, 0x14, 0xf9, 0x8e, 0x4d, 0xe8, 0x77,
+	0x41, 0x96, 0xac, 0x6c, 0x96, 0x60, 0x33, 0xe1, 0x7d, 0x11, 0x21, 0x6b,
+	0x2e, 0xbc, 0xc5, 0xef, 0x63, 0x7a, 0xbe, 0xf8, 0x87, 0x62, 0x9d, 0x92,
+	0xfe, 0x07, 0xb4, 0x0f, 0xfb, 0xce, 0x88, 0xb6, 0x32, 0xbe, 0x49, 0xf9,
+	0x23, 0x14, 0xf6, 0x6f, 0xe7, 0x87, 0x68, 0x5d, 0xf3, 0x36, 0x67, 0x2b,
+	0x68, 0x19, 0xdf, 0xcb, 0xf3, 0x12, 0x69, 0xb2, 0xb5, 0xa0, 0x3f, 0xcf,
+	0x33, 0x2e, 0x18, 0xad, 0x63, 0x82, 0xe6, 0xb9, 0xb9, 0x28, 0x6c, 0x3a,
+	0xad, 0x3b, 0x57, 0x64, 0xec, 0xa9, 0xb8, 0x0e, 0x9c, 0xa6, 0x75, 0xa7,
+	0x1b, 0x07, 0xef, 0xf5, 0xe0, 0x0b, 0xcf, 0xdc, 0x4f, 0x3d, 0x77, 0x26,
+	0x62, 0xce, 0x53, 0x9e, 0x73, 0x57, 0xcf, 0xe1, 0xca, 0x36, 0xda, 0xca,
+	0xfb, 0x53, 0x62, 0x5c, 0xdf, 0xfc, 0x62, 0x02, 0xb9, 0x6a, 0xf5, 0xfc,
+	0x21, 0x77, 0xce, 0x14, 0xd6, 0x01, 0x2d, 0x87, 0x3a, 0x3f, 0x1b, 0xb4,
+	0x18, 0xf1, 0xc8, 0x99, 0x72, 0xae, 0x25, 0xb8, 0xcf, 0x4d, 0x8b, 0xc6,
+	0x3a, 0x32, 0xa7, 0xd6, 0x91, 0x45, 0x87, 0x1e, 0x6f, 0xc5, 0xed, 0xfd,
+	0x1e, 0xb8, 0xdd, 0x2b, 0x6f, 0x0a, 0x7d, 0x7a, 0x92, 0x71, 0xc8, 0x67,
+	0x80, 0x43, 0x42, 0xc8, 0x5b, 0x92, 0x58, 0x04, 0xdf, 0x17, 0x19, 0x8f,
+	0x44, 0x98, 0x57, 0x7e, 0x44, 0xe7, 0x18, 0x6b, 0x5f, 0xa7, 0xfd, 0xca,
+	0x3e, 0x83, 0xdc, 0xea, 0x38, 0x53, 0xc4, 0xf1, 0xfb, 0x28, 0xfb, 0x98,
+	0x35, 0x19, 0xa7, 0x1f, 0xd1, 0x59, 0x11, 0x33, 0x83, 0xfd, 0x3d, 0xc4,
+	0x1c, 0x3c, 0x20, 0xde, 0x2f, 0x7d, 0x19, 0xf7, 0x23, 0xa6, 0x6e, 0xe3,
+	0xf1, 0xfb, 0x2a, 0xb7, 0x8e, 0xdb, 0xe1, 0x9d, 0x4b, 0x4a, 0xa6, 0xc4,
+	0x35, 0xbe, 0xff, 0x49, 0xa3, 0xf5, 0xfe, 0xb8, 0x91, 0xaa, 0xa6, 0x8c,
+	0x44, 0x05, 0xed, 0x9e, 0x34, 0x92, 0x55, 0xd8, 0x90, 0x9a, 0x47, 0xac,
+	0x28, 0xe4, 0x6d, 0x95, 0xd6, 0xdf, 0x8b, 0x58, 0x24, 0x57, 0x9e, 0xc4,
+	0x06, 0xfa, 0x7d, 0xb8, 0xa9, 0xdf, 0x9a, 0xbe, 0x38, 0x86, 0xbf, 0xe7,
+	0x15, 0xa6, 0xa9, 0xc6, 0xb5, 0x41, 0xf8, 0xd7, 0x27, 0xb3, 0xb4, 0x16,
+	0xae, 0xb5, 0x5a, 0x70, 0xed, 0xe2, 0xba, 0xfd, 0xfe, 0xa4, 0x32, 0x2e,
+	0xf3, 0xa3, 0xfd, 0xb6, 0xc0, 0xaf, 0xdc, 0xef, 0x26, 0x6c, 0xeb, 0xe2,
+	0x29, 0xb4, 0xd1, 0x7e, 0x70, 0xed, 0x07, 0xeb, 0x55, 0xf1, 0xc0, 0x3a,
+	0x3e, 0x21, 0x88, 0x7c, 0xaf, 0x90, 0x8c, 0x6b, 0x85, 0x8d, 0xb5, 0xc2,
+	0xfd, 0x83, 0xbd, 0x05, 0x9f, 0x8f, 0xb0, 0xb7, 0xcc, 0x24, 0x49, 0x5f,
+	0xf7, 0x99, 0xaa, 0xd3, 0xbf, 0xeb, 0x95, 0x4b, 0x39, 0xea, 0x91, 0x4b,
+	0xe9, 0x94, 0xb5, 0x80, 0x43, 0xd6, 0x22, 0x0e, 0xdc, 0x36, 0xcc, 0x76,
+	0x4b, 0x0f, 0xeb, 0x90, 0x1e, 0xb1, 0x6d, 0xe2, 0xbf, 0xea, 0xb4, 0x5b,
+	0xdc, 0x79, 0xf1, 0x90, 0x3b, 0x60, 0x33, 0x69, 0xc3, 0xa4, 0x4a, 0xf5,
+	0x9c, 0x7a, 0x1e, 0x77, 0x23, 0x6f, 0xb1, 0xd2, 0x92, 0x63, 0xe9, 0xd5,
+	0xdf, 0x91, 0x96, 0xfe, 0x62, 0xfd, 0x8a, 0xb7, 0xc5, 0x74, 0x5e, 0x76,
+	0xd5, 0xfd, 0xea, 0x9f, 0x5b, 0x9f, 0xe1, 0x5d, 0xa3, 0xc2, 0xe7, 0x9d,
+	0xad, 0xeb, 0xb2, 0x19, 0xd9, 0xdf, 0x42, 0xb3, 0x9d, 0xe1, 0xbf, 0x42,
+	0x8a, 0x76, 0xde, 0xba, 0x7d, 0x73, 0xfe, 0xb3, 0xad, 0x6e, 0x1c, 0xdc,
+	0x27, 0xfd, 0x62, 0x73, 0x2a, 0x0e, 0x7b, 0x40, 0xd9, 0x7b, 0xeb, 0xf1,
+	0x3b, 0xae, 0xcd, 0x29, 0x5f, 0xa2, 0x65, 0x96, 0x09, 0x7c, 0x7e, 0xfc,
+	0x54, 0x87, 0x1d, 0x52, 0x7b, 0x59, 0xd8, 0xaf, 0x02, 0xdf, 0xeb, 0xe7,
+	0x43, 0x67, 0x6f, 0x64, 0xce, 0xcc, 0x96, 0x39, 0x93, 0x7c, 0x05, 0x5b,
+	0x0b, 0xf1, 0xc5, 0x53, 0xae, 0x18, 0xef, 0x4f, 0x42, 0x8b, 0x5e, 0x8f,
+	0xb8, 0x67, 0xc4, 0x2d, 0xb7, 0xeb, 0xe7, 0x1d, 0x07, 0x2e, 0x47, 0x7f,
+	0x6b, 0xb5, 0x57, 0xa2, 0xbb, 0xe5, 0x5a, 0x5c, 0xf5, 0xc6, 0x48, 0xa1,
+	0x0d, 0xf7, 0xcf, 0xbd, 0xf6, 0xee, 0xda, 0xe0, 0xda, 0x2b, 0xea, 0x8b,
+	0xf8, 0x0e, 0x09, 0x1d, 0xd0, 0x43, 0x95, 0x12, 0xe2, 0xaf, 0x3f, 0x0b,
+	0x99, 0x67, 0x3d, 0xeb, 0xc8, 0x49, 0xf3, 0x9e, 0xc7, 0xfa, 0x9e, 0x4a,
+	0x20, 0x86, 0xbd, 0x3f, 0xc4, 0x96, 0xf4, 0xb3, 0xee, 0x41, 0xfb, 0x71,
+	0xf3, 0x16, 0xfc, 0xbd, 0xca, 0xff, 0x94, 0x52, 0xeb, 0xcb, 0xa1, 0x0d,
+	0xec, 0xad, 0x6c, 0x4e, 0x4f, 0x5b, 0xe6, 0x0a, 0x61, 0xdf, 0x07, 0xf1,
+	0xc2, 0xc7, 0x7a, 0xa9, 0xf7, 0x2b, 0x5d, 0x5d, 0xf6, 0x1f, 0xf4, 0xc9,
+	0xbd, 0x28, 0x7c, 0xd7, 0x43, 0x2f, 0x94, 0x10, 0xcb, 0x8d, 0xef, 0x7e,
+	0x8b, 0xbf, 0xf3, 0xd2, 0x51, 0x3a, 0x16, 0x1d, 0x58, 0x4e, 0xce, 0x4f,
+	0x99, 0x60, 0x2b, 0xd5, 0xe8, 0x6f, 0xa2, 0x9f, 0x93, 0xfb, 0x19, 0xd5,
+	0xfb, 0xbd, 0x57, 0xe3, 0xe5, 0x2f, 0xfc, 0x69, 0xdf, 0xc7, 0x8d, 0x8d,
+	0xfc, 0xd6, 0x86, 0xfc, 0x85, 0xd8, 0xe7, 0xdf, 0xc8, 0x9e, 0x89, 0xde,
+	0x1b, 0x9e, 0x16, 0x39, 0xa7, 0x4e, 0x3e, 0xb8, 0x3f, 0xfb, 0xc3, 0xe0,
+	0x87, 0x91, 0x16, 0x5d, 0xf5, 0xc9, 0xfd, 0xfd, 0x6e, 0xba, 0x06, 0x3d,
+	0x7d, 0x55, 0xde, 0xfb, 0xc0, 0xd8, 0xf3, 0x87, 0x9f, 0xba, 0x4a, 0x67,
+	0xae, 0x81, 0x87, 0x0d, 0xe6, 0xb6, 0x31, 0xca, 0x87, 0x91, 0x57, 0x24,
+	0x72, 0x73, 0xf4, 0xbe, 0xa1, 0xc8, 0x15, 0x3a, 0x23, 0x72, 0x20, 0xc7,
+	0x23, 0xf7, 0x78, 0x3d, 0x3c, 0x53, 0x7d, 0x9b, 0xce, 0x56, 0x82, 0xfc,
+	0xdf, 0xc0, 0xee, 0xad, 0x79, 0x90, 0xcd, 0x3c, 0x7e, 0x4f, 0xf0, 0xf8,
+	0xf0, 0x9a, 0x3c, 0x7e, 0xa4, 0xce, 0xe3, 0x5f, 0xe9, 0x97, 0xfc, 0xdc,
+	0xcb, 0xcf, 0xea, 0xa5, 0x43, 0xe2, 0xb9, 0x6f, 0xf3, 0xf1, 0x56, 0x3a,
+	0x14, 0x92, 0xc7, 0x67, 0x2b, 0xac, 0xe3, 0x0b, 0x6f, 0xd3, 0xb9, 0x6b,
+	0x59, 0x5f, 0x4a, 0xe4, 0x2f, 0x38, 0x6b, 0x69, 0xe8, 0xfb, 0xd1, 0xae,
+	0x1d, 0xff, 0x6b, 0xbd, 0x24, 0x73, 0xae, 0xca, 0x52, 0x3f, 0xd1, 0x5b,
+	0xd1, 0x21, 0x17, 0xff, 0x37, 0xdb, 0x8e, 0xe7, 0xd5, 0x1a, 0x78, 0x7c,
+	0x0d, 0xbf, 0x46, 0x2b, 0x5f, 0xf6, 0x79, 0xe0, 0xe1, 0xa7, 0xfb, 0xe5,
+	0x3e, 0xd5, 0x5a, 0x7e, 0x8d, 0xa6, 0xb8, 0x0e, 0xe7, 0xbe, 0x3d, 0xeb,
+	0xfd, 0x3d, 0x2a, 0x17, 0xf0, 0x87, 0xfd, 0x72, 0xbd, 0x40, 0x7e, 0xe0,
+	0x0a, 0xd3, 0xe1, 0x22, 0x63, 0x95, 0x21, 0xea, 0xbc, 0xaa, 0xc7, 0x3a,
+	0x24, 0xf4, 0xad, 0xd3, 0x4f, 0x73, 0x51, 0xe5, 0x76, 0xe7, 0x1c, 0x63,
+	0xba, 0x28, 0x6c, 0x9c, 0xf6, 0xf2, 0xd6, 0x3e, 0xe6, 0x6a, 0xd8, 0xb5,
+	0x26, 0xb8, 0xf9, 0x0d, 0x75, 0x4a, 0x30, 0xbf, 0x64, 0x48, 0x1c, 0x3c,
+	0xc3, 0xf8, 0x76, 0xb3, 0xfb, 0x45, 0x9f, 0x14, 0x23, 0xba, 0x6b, 0x60,
+	0xb8, 0x8f, 0x31, 0x0f, 0xd2, 0xe6, 0xc8, 0xbc, 0x58, 0x15, 0xba, 0xe0,
+	0xe2, 0x54, 0x8d, 0x92, 0xd1, 0x6d, 0x94, 0x99, 0xe2, 0x77, 0xcf, 0xd8,
+	0x6c, 0x7b, 0xf9, 0x29, 0xcb, 0xf2, 0x9b, 0x99, 0xda, 0xa2, 0xf0, 0xa2,
+	0xf6, 0xa7, 0x77, 0xa9, 0x38, 0x87, 0x5e, 0xb1, 0x2f, 0x29, 0x6b, 0xf5,
+	0xf0, 0x71, 0x45, 0x3f, 0x1b, 0xd7, 0xc1, 0xbb, 0x9d, 0xaa, 0xdd, 0x65,
+	0x47, 0x3b, 0xb4, 0xb9, 0xac, 0xda, 0xe2, 0x99, 0x1a, 0x53, 0x74, 0x2b,
+	0x7d, 0x0b, 0x39, 0x5c, 0x51, 0xb9, 0x7a, 0xc2, 0x7e, 0xa0, 0xd9, 0xfa,
+	0x58, 0x2e, 0x73, 0xdb, 0xff, 0xae, 0xc5, 0x85, 0x2d, 0x77, 0x99, 0x31,
+	0x6f, 0x55, 0xc8, 0x8a, 0xbb, 0x4f, 0x18, 0x8b, 0x5f, 0xec, 0x0f, 0xf1,
+	0xb1, 0x7a, 0xcf, 0xe9, 0x7a, 0x9f, 0x10, 0xa3, 0x61, 0x45, 0xe4, 0xb3,
+	0x74, 0xbb, 0xcb, 0x8e, 0x76, 0x5a, 0x57, 0xe8, 0xfd, 0x87, 0x8f, 0x7c,
+	0xb3, 0x85, 0xdb, 0x3e, 0x19, 0xc3, 0x1b, 0x12, 0xfb, 0xa7, 0x32, 0x46,
+	0x43, 0x1f, 0xc3, 0xbf, 0x8c, 0x98, 0x0a, 0xc4, 0x49, 0x38, 0xf5, 0x8d,
+	0x1c, 0x6f, 0x00, 0x6b, 0x51, 0x15, 0xfb, 0xa6, 0xd8, 0xaf, 0x68, 0x87,
+	0x9d, 0x77, 0x21, 0x36, 0x7f, 0x13, 0x18, 0x74, 0x23, 0xf2, 0x67, 0x7a,
+	0xc8, 0x9f, 0xf3, 0xfd, 0xc8, 0x83, 0x43, 0x3e, 0x5c, 0x76, 0xd2, 0xa0,
+	0x1a, 0xdb, 0x0a, 0x06, 0x95, 0x43, 0x3e, 0x3a, 0x67, 0x5b, 0xd1, 0x8a,
+	0xc0, 0x9a, 0x8f, 0xc0, 0x7f, 0x35, 0xb9, 0x42, 0x07, 0x44, 0xce, 0x38,
+	0x6a, 0x1f, 0x94, 0x79, 0x0d, 0x3e, 0xcd, 0x3c, 0x78, 0x96, 0xed, 0x8f,
+	0xec, 0x49, 0xec, 0xb7, 0xe8, 0x79, 0x41, 0x0e, 0x3c, 0x3e, 0x4d, 0x9e,
+	0xbb, 0xdf, 0xdd, 0x41, 0xc1, 0x38, 0x3f, 0xd3, 0x84, 0x7e, 0xe2, 0xe7,
+	0xa4, 0x29, 0xc1, 0x76, 0x12, 0x6c, 0xd6, 0xd3, 0x27, 0xad, 0x50, 0x99,
+	0x0c, 0x6e, 0x0b, 0xdb, 0x15, 0xcf, 0xc1, 0xfd, 0xf1, 0x50, 0x07, 0xb9,
+	0x73, 0x72, 0x7b, 0x45, 0x9e, 0xe2, 0x5b, 0xd1, 0x07, 0xc9, 0x18, 0x84,
+	0xbe, 0xc2, 0xbc, 0x3d, 0xa0, 0xf6, 0x89, 0xb6, 0xf3, 0xf1, 0x84, 0x3a,
+	0x0e, 0x8a, 0xf9, 0x94, 0xc7, 0x9a, 0xbf, 0xf1, 0xf7, 0xf3, 0x2e, 0xb2,
+	0xfd, 0x6a, 0xfe, 0x9a, 0x62, 0x41, 0x22, 0x63, 0x46, 0x90, 0xce, 0x57,
+	0xd6, 0xf2, 0xbf, 0x78, 0xe5, 0xba, 0x6e, 0xdf, 0x60, 0xae, 0xeb, 0x4f,
+	0x76, 0xc8, 0xdc, 0x32, 0x67, 0x5f, 0xfe, 0x93, 0xfb, 0xe2, 0x85, 0xc9,
+	0x5a, 0x70, 0x22, 0x8f, 0xb7, 0x46, 0x3f, 0x8b, 0x7e, 0x9e, 0xee, 0x84,
+	0x23, 0x2a, 0x66, 0x09, 0x31, 0x4a, 0x0f, 0x2a, 0xbe, 0xd6, 0xba, 0x9f,
+	0x3c, 0x74, 0xff, 0xa3, 0x22, 0x56, 0x53, 0xae, 0x1d, 0x43, 0x8a, 0x1e,
+	0xa0, 0x59, 0xc4, 0x41, 0xb3, 0x01, 0x07, 0xcd, 0x0c, 0x75, 0xbc, 0x4d,
+	0x9c, 0x9f, 0xaf, 0x3c, 0xb5, 0x5d, 0xe6, 0x8b, 0x63, 0x2f, 0xf1, 0x92,
+	0x3a, 0x5e, 0x6f, 0xbc, 0x56, 0x98, 0x82, 0xc2, 0xdf, 0xe4, 0x18, 0xeb,
+	0xcb, 0x44, 0xf6, 0x81, 0x70, 0x2b, 0x0d, 0x5e, 0x73, 0x5c, 0x47, 0x1f,
+	0xc7, 0x1d, 0x7d, 0x1c, 0x75, 0xf4, 0x71, 0x6f, 0x9b, 0x3e, 0xb2, 0x8e,
+	0xe7, 0xf7, 0x9c, 0xad, 0x7e, 0xdc, 0xbe, 0xa2, 0x9f, 0xc8, 0x23, 0x06,
+	0x3d, 0xb7, 0x52, 0x2e, 0x1c, 0x51, 0x6b, 0xc7, 0x2f, 0x55, 0x2e, 0xba,
+	0x57, 0x9f, 0xff, 0x8e, 0xda, 0xcf, 0x9b, 0x93, 0x57, 0x9d, 0xf9, 0xc7,
+	0xdf, 0xa5, 0xa4, 0xcc, 0x23, 0x57, 0xb2, 0x7d, 0xb9, 0x8d, 0x1f, 0x1a,
+	0xf1, 0x1c, 0xc0, 0x20, 0xc2, 0x2e, 0xdc, 0x2d, 0x6b, 0xc1, 0x05, 0x68,
+	0xa9, 0x9e, 0xcb, 0xeb, 0x57, 0xb9, 0x3b, 0xc7, 0xc3, 0xf7, 0x37, 0x8f,
+	0x17, 0xd7, 0xff, 0x4c, 0xf8, 0xf2, 0xe4, 0xfe, 0xd1, 0x8a, 0xca, 0x47,
+	0xb6, 0x4c, 0xc4, 0x06, 0x2c, 0x2e, 0xc3, 0xff, 0xda, 0x2e, 0x77, 0x57,
+	0xea, 0xa2, 0x4c, 0xbd, 0x3e, 0x4a, 0x59, 0xe4, 0x35, 0x48, 0xff, 0x98,
+	0xcc, 0xbf, 0x5d, 0x5c, 0xbe, 0x25, 0x72, 0x5e, 0x13, 0x2a, 0x8f, 0x37,
+	0x43, 0x3d, 0x02, 0xe7, 0x7e, 0xfc, 0xfc, 0xdb, 0x17, 0xc2, 0x9b, 0xcf,
+	0xbf, 0x75, 0xde, 0xb3, 0xb9, 0xfc, 0xdb, 0x10, 0x8f, 0xdd, 0x58, 0x90,
+	0xf9, 0xb7, 0xcd, 0x7b, 0x32, 0x32, 0xff, 0x36, 0xe3, 0xc0, 0x0f, 0x12,
+	0xaf, 0xbf, 0xe5, 0x88, 0xdf, 0x96, 0xb9, 0xb5, 0x8b, 0x75, 0xcc, 0x2a,
+	0x73, 0x6b, 0x65, 0xbc, 0xb7, 0xb3, 0x0e, 0x8c, 0xdc, 0xfb, 0x91, 0xef,
+	0xd9, 0xe6, 0xda, 0xfb, 0x91, 0x39, 0xb5, 0xa6, 0xd1, 0xce, 0x86, 0xc3,
+	0x1a, 0x81, 0x7a, 0x08, 0x71, 0xe6, 0xdd, 0xad, 0x6d, 0xea, 0x21, 0xc4,
+	0xdb, 0xd4, 0x43, 0x70, 0xea, 0x7e, 0x27, 0xc6, 0x02, 0x26, 0xc6, 0xda,
+	0x08, 0x2c, 0x8c, 0x7a, 0x06, 0x51, 0x3a, 0x5f, 0xc7, 0x9e, 0x0f, 0x52,
+	0x5a, 0x61, 0xcf, 0xf3, 0x15, 0xad, 0x8f, 0x46, 0x5d, 0xfa, 0xc8, 0x0b,
+	0x8b, 0x5a, 0x2a, 0xce, 0x47, 0xcb, 0x6b, 0xd6, 0x21, 0xaf, 0x59, 0x0f,
+	0x79, 0xc5, 0x3d, 0xd9, 0x36, 0xfd, 0xfe, 0xa5, 0xba, 0x07, 0xff, 0x4f,
+	0x46, 0x50, 0xb3, 0x85, 0x68, 0xf7, 0x80, 0xc2, 0x7f, 0x0e, 0x79, 0x3d,
+	0xcb, 0xf2, 0xaa, 0xaf, 0xa3, 0xbf, 0xed, 0x6c, 0x00, 0x8d, 0x19, 0x87,
+	0x7c, 0x87, 0xaf, 0xbd, 0x21, 0xe2, 0xa4, 0x9a, 0xed, 0x45, 0x8d, 0x27,
+	0xf6, 0x09, 0x59, 0xba, 0xe3, 0x47, 0xdc, 0x8a, 0xbe, 0x16, 0x52, 0x7e,
+	0x32, 0x4d, 0x8b, 0xce, 0x26, 0xcc, 0xd1, 0xc0, 0x1b, 0x22, 0xc6, 0xd7,
+	0xd1, 0xb7, 0x7f, 0xe5, 0xbe, 0xe9, 0xeb, 0x7a, 0xcd, 0x7c, 0xa7, 0xc9,
+	0x9f, 0x71, 0xa3, 0xa9, 0xee, 0x1f, 0x7c, 0x47, 0xdb, 0xd2, 0x86, 0x9d,
+	0x12, 0x31, 0xa6, 0x7d, 0x36, 0xfc, 0x64, 0x09, 0x96, 0xfd, 0xbe, 0x34,
+	0xe2, 0x99, 0xfb, 0xae, 0x98, 0x74, 0xa2, 0x70, 0x7e, 0x8f, 0xe4, 0x95,
+	0x0b, 0xa2, 0xa6, 0x25, 0x6a, 0x20, 0x26, 0x79, 0x7d, 0x4e, 0x30, 0xe8,
+	0x9c, 0xab, 0x76, 0xd1, 0x22, 0xa3, 0x7b, 0xbf, 0x5d, 0x16, 0xbe, 0x3e,
+	0xd6, 0x49, 0x45, 0xd4, 0x36, 0x35, 0x16, 0x3a, 0xf9, 0xb9, 0x83, 0xb4,
+	0x54, 0x1a, 0x17, 0x35, 0xa1, 0x64, 0x7d, 0x11, 0xb4, 0xf5, 0x51, 0xbf,
+	0xfd, 0x0d, 0xa6, 0xdd, 0xd7, 0x44, 0x8c, 0xe5, 0x62, 0xf1, 0x82, 0xfc,
+	0x2c, 0x3f, 0xa5, 0xde, 0xc1, 0xef, 0xab, 0xfe, 0x98, 0xe2, 0xfd, 0xa6,
+	0xc3, 0x96, 0x73, 0xfe, 0x79, 0xe3, 0x95, 0x63, 0x9b, 0xc2, 0x2b, 0xd9,
+	0x74, 0x03, 0xaf, 0x38, 0x9f, 0xad, 0xb1, 0xcb, 0xe4, 0xa0, 0xac, 0xf7,
+	0x00, 0x1a, 0x6c, 0x05, 0x16, 0x4b, 0x83, 0x96, 0x46, 0xcc, 0x8a, 0x24,
+	0xfc, 0x33, 0x94, 0xaf, 0x5e, 0xa7, 0x4c, 0x11, 0x98, 0x99, 0x3f, 0xcb,
+	0xe7, 0x76, 0x4a, 0x1f, 0x8d, 0xbe, 0x07, 0x7a, 0x65, 0x07, 0xb7, 0xff,
+	0xeb, 0x41, 0x19, 0x97, 0xed, 0xbc, 0xde, 0xcb, 0xd7, 0xbf, 0x10, 0x69,
+	0xbe, 0xbe, 0x85, 0xaf, 0xf7, 0xa7, 0x31, 0x87, 0xc6, 0x15, 0xf8, 0x25,
+	0x27, 0x29, 0xc7, 0xf3, 0x93, 0xaf, 0xf2, 0xda, 0x7a, 0x95, 0xf5, 0x55,
+	0x45, 0xb7, 0x1b, 0x40, 0xce, 0x8e, 0x98, 0x13, 0x83, 0xdb, 0x5c, 0x2c,
+	0x4c, 0x71, 0xbb, 0x21, 0xf2, 0x5f, 0x35, 0x29, 0x5f, 0xd1, 0xbc, 0xaa,
+	0xe3, 0xed, 0xdf, 0x18, 0x90, 0x31, 0x55, 0xef, 0xec, 0x94, 0xf4, 0x9b,
+	0x14, 0x3e, 0x4f, 0xc4, 0x73, 0x3c, 0x23, 0xf8, 0xd0, 0x9a, 0x31, 0xeb,
+	0xef, 0xdf, 0x06, 0xbe, 0x42, 0xdd, 0x54, 0x1e, 0x03, 0xeb, 0xc5, 0x98,
+	0x1d, 0xca, 0xd5, 0x63, 0xd5, 0x9e, 0xdb, 0x2d, 0xef, 0xff, 0xe9, 0x80,
+	0xac, 0x55, 0x7a, 0x5b, 0x9d, 0xeb, 0x35, 0x07, 0xf1, 0xcb, 0x3e, 0x41,
+	0x1b, 0xff, 0x02, 0xf4, 0xa5, 0xc1, 0xc7, 0x3c, 0x9e, 0x34, 0xfa, 0xf8,
+	0xb3, 0x01, 0x5d, 0x9f, 0x50, 0x8e, 0xeb, 0x28, 0xf7, 0x37, 0xc5, 0xe3,
+	0xd2, 0xd7, 0xe3, 0x7c, 0xee, 0x35, 0xbf, 0x78, 0x56, 0x30, 0x2d, 0xeb,
+	0x8b, 0x05, 0xd3, 0x99, 0x49, 0x39, 0xcf, 0x0d, 0x9f, 0x6e, 0xa4, 0xee,
+	0xd3, 0x9d, 0x2b, 0xf4, 0x0f, 0xc2, 0xbf, 0x61, 0x5c, 0xe1, 0xf9, 0x0e,
+	0x3f, 0xc3, 0x6d, 0x91, 0xab, 0x90, 0xe3, 0xcf, 0x1e, 0x15, 0xd7, 0xd3,
+	0xca, 0x2b, 0x32, 0x4e, 0x42, 0xaf, 0x5b, 0xb8, 0x77, 0x80, 0x9f, 0x21,
+	0xd7, 0xae, 0xf6, 0xef, 0xa1, 0x96, 0x38, 0x98, 0x56, 0x1e, 0x5b, 0xcb,
+	0x0f, 0x2b, 0xf6, 0x13, 0x3d, 0xf8, 0x6c, 0xad, 0x7a, 0x06, 0xef, 0x08,
+	0x3f, 0x5a, 0xb2, 0x45, 0x5e, 0x21, 0xc7, 0x01, 0xfa, 0xce, 0x7c, 0x96,
+	0xb6, 0xf0, 0x5c, 0x7d, 0xc3, 0xf8, 0x35, 0xec, 0xb7, 0x93, 0x8c, 0x79,
+	0x62, 0x1a, 0x17, 0xec, 0xc9, 0xb3, 0x06, 0xd3, 0xb9, 0x90, 0xad, 0x05,
+	0xec, 0x1e, 0xea, 0x64, 0x59, 0xfd, 0x22, 0x8d, 0xb1, 0xfd, 0x07, 0x99,
+	0xb5, 0x23, 0x29, 0x82, 0xbc, 0x59, 0xa1, 0xc3, 0xcc, 0x13, 0xc9, 0x2a,
+	0xf8, 0xd9, 0xa0, 0x27, 0x4a, 0x44, 0x8f, 0x97, 0xc6, 0x42, 0xdf, 0x27,
+	0xdb, 0x6c, 0x7c, 0x6f, 0x85, 0x12, 0xdc, 0x8f, 0x54, 0xf5, 0x77, 0xe8,
+	0x43, 0x51, 0xe7, 0x04, 0x74, 0xd4, 0xf3, 0xfe, 0xdb, 0x74, 0x3a, 0x8d,
+	0x7e, 0x6f, 0x5c, 0x3e, 0x4f, 0x6c, 0x4a, 0x3e, 0x83, 0x1e, 0xf2, 0xf9,
+	0xea, 0xa0, 0xe4, 0x9b, 0x1a, 0xf3, 0x68, 0x90, 0x66, 0x8b, 0x88, 0x01,
+	0x7b, 0x18, 0x75, 0xa7, 0x8a, 0x19, 0xd6, 0x4b, 0x99, 0x86, 0x5e, 0xba,
+	0x94, 0xf0, 0xc7, 0x21, 0xe3, 0xa8, 0xcb, 0xa6, 0xe2, 0x7e, 0x30, 0x8e,
+	0xdd, 0x34, 0xb6, 0xb0, 0x95, 0xef, 0xa5, 0x95, 0xc4, 0x74, 0x5c, 0xe5,
+	0xfa, 0x5b, 0x66, 0x92, 0xf5, 0xe3, 0x1c, 0xcb, 0x72, 0xae, 0xf8, 0x00,
+	0x2d, 0x86, 0x87, 0x69, 0x74, 0x41, 0xd7, 0x37, 0xc1, 0x58, 0xff, 0x6d,
+	0x48, 0xea, 0x24, 0x3d, 0xee, 0x5f, 0x11, 0xbe, 0x0b, 0xf3, 0xfa, 0xa7,
+	0x35, 0xee, 0xad, 0xeb, 0xe8, 0xa5, 0xbf, 0x52, 0x32, 0x5b, 0xbb, 0x91,
+	0x88, 0x52, 0x36, 0x31, 0xfd, 0x97, 0x82, 0xff, 0x47, 0xaf, 0xc3, 0x0f,
+	0x07, 0x1d, 0x6d, 0x52, 0xba, 0xe0, 0xa6, 0xc5, 0x30, 0x8f, 0x1b, 0xdf,
+	0xd7, 0xfe, 0x79, 0x36, 0xfa, 0x94, 0x58, 0xfb, 0xc7, 0xae, 0x73, 0x3b,
+	0xb1, 0x36, 0x69, 0xbd, 0xe1, 0xc5, 0x87, 0xba, 0x8e, 0xa5, 0xe6, 0x45,
+	0x19, 0xeb, 0xc9, 0xf8, 0x2d, 0x94, 0xf6, 0xbb, 0x79, 0xf2, 0x23, 0x3a,
+	0x36, 0x6f, 0xd2, 0xf1, 0x82, 0xf5, 0x7c, 0x96, 0x66, 0x58, 0xae, 0x9d,
+	0xeb, 0x05, 0xb7, 0x27, 0xf0, 0x59, 0x8c, 0x65, 0x9f, 0xed, 0xe6, 0xa2,
+	0x29, 0xe3, 0xee, 0x44, 0xed, 0xb9, 0x2e, 0xa1, 0x47, 0x43, 0xf6, 0x3f,
+	0x0d, 0xea, 0xf5, 0x20, 0x53, 0x44, 0x1e, 0x21, 0x7f, 0x96, 0xb9, 0x7d,
+	0x61, 0x90, 0x32, 0x25, 0x3c, 0x07, 0xeb, 0x1d, 0xfa, 0xce, 0xe7, 0x4b,
+	0x72, 0x5e, 0x47, 0xf9, 0xd9, 0xc8, 0xbb, 0x3f, 0x5e, 0x9d, 0x12, 0xb1,
+	0x77, 0xd0, 0xcd, 0x72, 0x3e, 0x63, 0x74, 0xd1, 0x53, 0xaf, 0x28, 0x4c,
+	0xe9, 0x90, 0xef, 0x8c, 0x90, 0xef, 0x98, 0x98, 0x8f, 0x4c, 0xc9, 0x60,
+	0xbc, 0xa6, 0x7d, 0x0f, 0xfd, 0x7c, 0x1e, 0x50, 0x3a, 0x04, 0xdf, 0x0d,
+	0xec, 0x14, 0x71, 0x89, 0x36, 0xae, 0xe3, 0x33, 0x46, 0xcf, 0x30, 0xee,
+	0x7c, 0xb6, 0xd0, 0x45, 0xb7, 0x8a, 0x5d, 0xf4, 0x66, 0x71, 0x98, 0x6e,
+	0xce, 0x6f, 0xa7, 0x8b, 0x8c, 0x99, 0x2f, 0xda, 0x01, 0x33, 0xc7, 0xf6,
+	0xc5, 0x0b, 0x51, 0x11, 0x33, 0xc4, 0x72, 0x87, 0xf6, 0xc0, 0x7f, 0x89,
+	0x5d, 0xcc, 0x73, 0x8c, 0xbd, 0xbb, 0xe9, 0x03, 0x7e, 0x67, 0xae, 0xa0,
+	0x63, 0x1d, 0xe0, 0x93, 0x1f, 0xaf, 0xe3, 0xd7, 0xf5, 0x79, 0x24, 0xb4,
+	0x0e, 0x8f, 0xc4, 0x84, 0xae, 0xcf, 0xcf, 0xf3, 0xf7, 0xf3, 0xf0, 0x9f,
+	0x33, 0xbd, 0x59, 0x3f, 0x7f, 0x3d, 0x80, 0xf6, 0xb8, 0x66, 0xcb, 0x58,
+	0x49, 0x31, 0xb6, 0x08, 0x9f, 0x83, 0xb6, 0x11, 0x45, 0x87, 0x6e, 0x1e,
+	0x9f, 0x4f, 0xb4, 0xcf, 0x2c, 0x75, 0xd3, 0x99, 0x12, 0x63, 0x90, 0x92,
+	0x9f, 0x6d, 0x18, 0xb4, 0x0d, 0xec, 0xd5, 0xf5, 0x5f, 0x2f, 0x72, 0xdf,
+	0x73, 0x25, 0x89, 0x41, 0x72, 0x4b, 0xbd, 0x94, 0x2f, 0xf5, 0xa8, 0xf3,
+	0x07, 0x44, 0x8c, 0xbb, 0xac, 0x63, 0x84, 0xef, 0xd6, 0xd2, 0x6f, 0x6f,
+	0x31, 0x4f, 0x61, 0x4d, 0x95, 0x76, 0x29, 0x74, 0xcd, 0x8d, 0x96, 0xba,
+	0xc4, 0xe0, 0xb9, 0x19, 0xfa, 0x2e, 0xaf, 0xb7, 0xa3, 0x57, 0xe1, 0x3f,
+	0xfe, 0x2a, 0xf8, 0xa6, 0x0c, 0x1e, 0x1b, 0xbd, 0x8a, 0xba, 0x48, 0x7e,
+	0x91, 0xe7, 0x94, 0x0c, 0x4f, 0x8a, 0xdc, 0x10, 0x29, 0xa3, 0x27, 0x45,
+	0x2d, 0xba, 0x1f, 0x0a, 0xdd, 0x64, 0x65, 0x4d, 0x03, 0x78, 0x04, 0x3e,
+	0x18, 0x19, 0x83, 0x75, 0xc2, 0xee, 0x7b, 0x6b, 0x20, 0x36, 0x41, 0xf1,
+	0x41, 0xf0, 0xbd, 0x94, 0x59, 0x55, 0x5f, 0x40, 0xe8, 0xfb, 0xd0, 0x3e,
+	0x9d, 0x2f, 0xa9, 0xcf, 0xf5, 0x5a, 0xa1, 0xcf, 0x7b, 0x5c, 0xdf, 0x87,
+	0x5c, 0xdf, 0xd7, 0xe3, 0xe5, 0x78, 0xcd, 0xe3, 0x75, 0x9e, 0x64, 0x8d,
+	0xa2, 0xcc, 0x82, 0xe4, 0xbf, 0xd0, 0xbe, 0xf1, 0xd0, 0x97, 0x15, 0x06,
+	0xcf, 0x2c, 0x8f, 0x45, 0xfa, 0x8c, 0x1e, 0x7f, 0x66, 0xea, 0xef, 0x6b,
+	0xf1, 0x34, 0x70, 0xd1, 0xdc, 0x4e, 0xa9, 0xe3, 0xd0, 0xaf, 0x6c, 0x14,
+	0xd0, 0xed, 0xe4, 0x72, 0x0f, 0xad, 0x88, 0x9a, 0x5c, 0xc0, 0x18, 0xb8,
+	0x1f, 0xcf, 0xc9, 0x86, 0x3a, 0x08, 0x35, 0xd7, 0x21, 0xe3, 0x07, 0x22,
+	0xd7, 0x79, 0x3e, 0x53, 0xcb, 0xff, 0x55, 0x3b, 0x2d, 0x6a, 0xdc, 0xa0,
+	0x2d, 0x63, 0x48, 0x81, 0xf9, 0x19, 0xbf, 0x34, 0xd9, 0x55, 0x33, 0xe8,
+	0x67, 0x16, 0x7b, 0x2b, 0x86, 0xfd, 0x22, 0xcb, 0x98, 0xdc, 0x2b, 0x4f,
+	0xb9, 0xf6, 0xca, 0x4f, 0x8a, 0xbd, 0x72, 0xec, 0x93, 0x83, 0xae, 0xa0,
+	0xa5, 0x57, 0x4c, 0x0b, 0xe6, 0x31, 0xca, 0xf3, 0x68, 0xd2, 0xc5, 0x6b,
+	0x42, 0xdf, 0x44, 0x93, 0x7e, 0x19, 0x5f, 0x9d, 0xa2, 0xac, 0x88, 0xbf,
+	0x96, 0x9f, 0x71, 0x23, 0x61, 0x5b, 0x93, 0xab, 0x8c, 0x29, 0x2a, 0xc5,
+	0x2d, 0x74, 0xb3, 0xdc, 0xc1, 0x98, 0xef, 0x6f, 0x69, 0xb5, 0x4c, 0x8c,
+	0x0d, 0xb7, 0x53, 0x3e, 0xca, 0xbc, 0x36, 0x19, 0xe4, 0x79, 0x65, 0x7c,
+	0x3b, 0xc9, 0xf2, 0xc7, 0x63, 0xa8, 0x94, 0x6a, 0xef, 0xe7, 0xa2, 0x71,
+	0x33, 0x31, 0xdd, 0xc3, 0xf6, 0x4b, 0x88, 0xff, 0x6d, 0xfe, 0xff, 0x6c,
+	0x04, 0xb4, 0x59, 0x5c, 0xc2, 0xf7, 0x8c, 0x7d, 0x0a, 0xb5, 0xf7, 0x67,
+	0xb9, 0xcd, 0xec, 0x34, 0xec, 0x20, 0xd8, 0x7b, 0x36, 0xff, 0xcb, 0x36,
+	0x15, 0xe6, 0xbb, 0xdc, 0xb5, 0x6c, 0xc4, 0x10, 0x3a, 0x1e, 0x75, 0x5d,
+	0xc6, 0xd4, 0x67, 0xdc, 0x98, 0xe5, 0xbe, 0xdc, 0x24, 0x3c, 0xc3, 0xa4,
+	0x4c, 0x74, 0x1f, 0xcb, 0xc1, 0x76, 0xfe, 0x44, 0x3e, 0xd6, 0x56, 0xca,
+	0x4f, 0x8d, 0xab, 0x7c, 0xac, 0x48, 0x9b, 0x7c, 0x2c, 0xdc, 0xc7, 0x38,
+	0x60, 0xbe, 0x76, 0x6f, 0x36, 0xea, 0x7c, 0x2f, 0x19, 0x99, 0xe8, 0x36,
+	0x81, 0x99, 0x2a, 0x4b, 0xfb, 0xb9, 0x0f, 0x71, 0x33, 0x33, 0xcd, 0x7d,
+	0x2d, 0x39, 0xfb, 0x5f, 0xbb, 0x97, 0x8c, 0xa2, 0x9d, 0xdf, 0xd5, 0x2e,
+	0x4e, 0xa2, 0xed, 0x12, 0xda, 0xd7, 0xfe, 0x27, 0x11, 0xd5, 0xe3, 0x74,
+	0xde, 0x8b, 0xf1, 0x40, 0xbe, 0xf8, 0xb3, 0x72, 0x9b, 0x6e, 0x16, 0x61,
+	0x8f, 0x1b, 0xcc, 0xf7, 0xe8, 0x91, 0x49, 0xd9, 0x0a, 0x63, 0xc0, 0x6b,
+	0x7b, 0x7d, 0xab, 0xc5, 0x37, 0x6a, 0x99, 0xa6, 0xd8, 0x96, 0x66, 0x3f,
+	0xbc, 0xb4, 0xc1, 0x86, 0xc9, 0xbe, 0x82, 0x35, 0x14, 0xeb, 0x67, 0xb6,
+	0xe6, 0xb7, 0x81, 0xf7, 0x60, 0x1b, 0x5d, 0x60, 0xfd, 0x25, 0xe3, 0x93,
+	0x58, 0x97, 0xb2, 0x0e, 0x93, 0xf2, 0x93, 0x6a, 0xfa, 0x39, 0x04, 0xc9,
+	0xc3, 0xa3, 0x8d, 0xb8, 0x48, 0xc7, 0xfe, 0x7a, 0xc0, 0xb1, 0xbf, 0x1e,
+	0x72, 0xc4, 0x45, 0x86, 0x05, 0x3e, 0x6b, 0x60, 0xaa, 0xb0, 0xc2, 0x54,
+	0xc0, 0x5e, 0x52, 0xb7, 0x2d, 0xd6, 0x75, 0xdb, 0x8e, 0x75, 0x74, 0x9b,
+	0x97, 0xad, 0xba, 0xa2, 0xf4, 0x88, 0x15, 0xc5, 0x1a, 0x73, 0x83, 0xf5,
+	0xc5, 0xeb, 0xd5, 0x69, 0xd6, 0x23, 0x51, 0xd6, 0x23, 0x53, 0xac, 0x47,
+	0x26, 0x59, 0x8f, 0xd8, 0x4c, 0x03, 0x93, 0xc7, 0xfe, 0x11, 0xeb, 0x69,
+	0xac, 0x1f, 0x33, 0xf4, 0x4c, 0x15, 0x3a, 0x79, 0x8a, 0x31, 0xd0, 0x47,
+	0xb4, 0x3a, 0xdf, 0xcb, 0xfc, 0x2b, 0x71, 0x4f, 0xb3, 0x5d, 0x83, 0xda,
+	0x2b, 0xf0, 0x17, 0xff, 0x39, 0xf4, 0xce, 0x2b, 0x59, 0x1a, 0xf1, 0xdd,
+	0x2c, 0x82, 0xce, 0xab, 0xa8, 0x55, 0xf1, 0x12, 0x64, 0x1b, 0x35, 0x82,
+	0x7f, 0x30, 0x31, 0xc3, 0x7d, 0x1f, 0xf1, 0xe5, 0x79, 0x5e, 0xbe, 0x1d,
+	0xcd, 0x86, 0xfa, 0x59, 0x06, 0x8e, 0x2b, 0x19, 0x38, 0xde, 0x90, 0x81,
+	0x6c, 0x8e, 0x47, 0xd2, 0xb7, 0xb0, 0x9d, 0xc6, 0x0f, 0x26, 0x76, 0xf5,
+	0xb1, 0xfc, 0x22, 0x66, 0xa2, 0x51, 0xbf, 0xc7, 0x4f, 0xa7, 0xc3, 0x41,
+	0x55, 0xf7, 0xc7, 0x14, 0x39, 0xef, 0xf9, 0xe2, 0xbb, 0x8c, 0x4b, 0x58,
+	0x4e, 0x43, 0x38, 0xbf, 0x0c, 0xbf, 0x28, 0xdb, 0x0d, 0xdd, 0xc2, 0xaf,
+	0xb4, 0x28, 0xda, 0xe2, 0xdc, 0x9a, 0x64, 0x1d, 0x17, 0x5d, 0x31, 0xac,
+	0x99, 0xb8, 0xf1, 0x9b, 0xc3, 0xa8, 0xe1, 0xfe, 0x83, 0xea, 0xe7, 0x86,
+	0xe5, 0xde, 0x5c, 0x72, 0x97, 0xd4, 0x27, 0xcc, 0xa3, 0xe1, 0xb8, 0xb0,
+	0xdd, 0x3a, 0xae, 0xc8, 0xf5, 0x73, 0x91, 0xe7, 0xbb, 0x12, 0x9d, 0xe4,
+	0xf9, 0xee, 0x51, 0x6b, 0x67, 0x96, 0xbf, 0x17, 0xeb, 0x32, 0xaf, 0xa1,
+	0xc3, 0xa8, 0x7f, 0x1f, 0x12, 0x75, 0x22, 0x4e, 0xa2, 0x0e, 0x4f, 0x02,
+	0xcf, 0x63, 0xee, 0x85, 0xfe, 0xf8, 0x07, 0x5e, 0xa3, 0xf1, 0x5e, 0xf0,
+	0x23, 0x1f, 0x97, 0x67, 0xe8, 0x52, 0x41, 0xf7, 0xe1, 0x3d, 0x32, 0xbe,
+	0x8b, 0x7e, 0xf8, 0x68, 0x87, 0xfd, 0x9e, 0xc8, 0x05, 0x31, 0xfe, 0xc4,
+	0xdd, 0xa7, 0xa3, 0xaa, 0x4f, 0xa8, 0x75, 0xd9, 0x85, 0xda, 0x3e, 0x84,
+	0x9a, 0x48, 0x8b, 0xa2, 0x16, 0x65, 0xa7, 0xb0, 0x59, 0x17, 0x85, 0xed,
+	0xb1, 0x7f, 0x57, 0xa3, 0x3e, 0xe6, 0x7e, 0xd7, 0xb5, 0x3b, 0xbc, 0x6e,
+	0x1d, 0x12, 0x18, 0x6d, 0x14, 0xf5, 0xda, 0x45, 0x5e, 0xea, 0x8c, 0xf8,
+	0xce, 0x58, 0xc0, 0x77, 0x0f, 0xa9, 0xef, 0x3e, 0x2f, 0xb0, 0xb1, 0x11,
+	0xeb, 0x66, 0xbd, 0x28, 0xf8, 0x9d, 0xe7, 0xd9, 0x9e, 0x64, 0x7e, 0x8f,
+	0x54, 0xf8, 0xb9, 0xa7, 0x05, 0x3d, 0x35, 0x3d, 0x40, 0x0b, 0xc8, 0x40,
+	0x8f, 0xe2, 0x7f, 0xcb, 0x4c, 0xf9, 0xf5, 0xb8, 0xdb, 0xd1, 0x99, 0xb1,
+	0x4e, 0x01, 0x63, 0xc5, 0x98, 0x4c, 0x5f, 0xbc, 0x1c, 0xf1, 0xe5, 0xe6,
+	0x61, 0xeb, 0x20, 0xdf, 0x65, 0x0f, 0xe2, 0xa9, 0xb8, 0x0f, 0x3b, 0x29,
+	0x9e, 0x46, 0xbf, 0xd0, 0x4e, 0xd3, 0xc0, 0x76, 0xd1, 0xc2, 0x79, 0xdf,
+	0x76, 0x75, 0x5f, 0xb7, 0x98, 0x0b, 0x32, 0xf0, 0x1e, 0xfd, 0x6e, 0xbc,
+	0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x00, 0xeb, 0xed, 0xc4,
+	0xb4, 0x7c, 0x96, 0x71, 0x5d, 0x7e, 0x37, 0x60, 0x7b, 0xf7, 0x57, 0xce,
+	0x9f, 0x4f, 0xd5, 0xf1, 0xc1, 0xfc, 0x6d, 0xa7, 0xb2, 0xf0, 0x7d, 0xe2,
+	0xbb, 0x11, 0x9f, 0xb0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xf3,
+	0x33, 0xc5, 0xdb, 0xc2, 0x66, 0xcf, 0xa5, 0x47, 0x7c, 0xe5, 0x32, 0xc6,
+	0x3b, 0xe2, 0x4b, 0xb1, 0x0c, 0x24, 0x8b, 0x89, 0x5a, 0x5e, 0xe2, 0x02,
+	0x3a, 0xdd, 0x6f, 0x85, 0x4e, 0x1b, 0xef, 0x0f, 0xcb, 0x9a, 0xb7, 0x38,
+	0x66, 0x39, 0x2c, 0xb0, 0x1c, 0x16, 0x58, 0x0e, 0x0b, 0x2c, 0x87, 0x6c,
+	0xab, 0xbe, 0x56, 0x60, 0x39, 0xe4, 0xb5, 0xe4, 0x55, 0x5e, 0x4b, 0xa4,
+	0xec, 0xc6, 0x95, 0x7f, 0x53, 0xcb, 0xae, 0x3b, 0x6f, 0x53, 0xcb, 0x2a,
+	0xd6, 0x6f, 0xf2, 0x1d, 0x99, 0x68, 0x96, 0xd9, 0x5b, 0x2c, 0xb3, 0x1d,
+	0xb1, 0x41, 0xba, 0x5b, 0xc2, 0x9c, 0x59, 0xe6, 0x1c, 0xeb, 0xea, 0x94,
+	0x1f, 0x58, 0x2b, 0xc0, 0xf2, 0x04, 0xac, 0x69, 0x31, 0xdd, 0x07, 0xe9,
+	0x1e, 0xeb, 0xeb, 0xbb, 0x25, 0xc8, 0xf0, 0x1e, 0x75, 0x6e, 0xb1, 0x0c,
+	0x63, 0xfd, 0xb3, 0x7d, 0xb7, 0x8a, 0x06, 0x63, 0xb2, 0x40, 0x28, 0x43,
+	0xd0, 0xa7, 0x02, 0xa7, 0xf1, 0xbc, 0xaf, 0xb0, 0xde, 0x87, 0x0f, 0x0f,
+	0xeb, 0xc5, 0x19, 0x1f, 0xaf, 0x17, 0x91, 0x9b, 0xac, 0x4f, 0xcf, 0x97,
+	0x6c, 0x96, 0xfb, 0x7e, 0xfa, 0x56, 0x09, 0xeb, 0x34, 0x68, 0xc4, 0xe7,
+	0x65, 0x12, 0xbe, 0x31, 0x23, 0x86, 0xb1, 0x8f, 0x67, 0x0d, 0xc1, 0x27,
+	0x7f, 0x0a, 0x3a, 0x30, 0xed, 0x5f, 0xdc, 0x85, 0xda, 0xf3, 0x71, 0xa3,
+	0x53, 0xf9, 0x1a, 0x71, 0x8c, 0xf6, 0x68, 0x0b, 0xba, 0xe1, 0xbc, 0xdd,
+	0xbe, 0x24, 0x7e, 0xb3, 0x21, 0x0a, 0xff, 0x9b, 0x4b, 0x7f, 0x5d, 0xe2,
+	0xfb, 0x05, 0xbd, 0x66, 0x12, 0x7e, 0xe4, 0x90, 0xd3, 0xd3, 0xfe, 0xd8,
+	0x0c, 0x3d, 0x5b, 0x45, 0xbf, 0xaf, 0x52, 0x3e, 0x0c, 0x7d, 0x64, 0x45,
+	0xef, 0x90, 0xa4, 0x5d, 0x37, 0xe3, 0xce, 0x27, 0xbc, 0x75, 0x9c, 0x99,
+	0x10, 0x38, 0xb9, 0x8b, 0xf5, 0x0b, 0x68, 0xf3, 0x13, 0xe6, 0x35, 0x7e,
+	0x5f, 0x41, 0xeb, 0xb7, 0x1f, 0xb3, 0xce, 0xc1, 0x9c, 0xe1, 0x7c, 0x6d,
+	0x9d, 0xb6, 0xaa, 0x74, 0x9a, 0xed, 0xd0, 0x69, 0xb9, 0xba, 0x4e, 0x63,
+	0xde, 0x10, 0xba, 0x0c, 0xba, 0xea, 0x51, 0xc6, 0x91, 0xf2, 0x18, 0xf8,
+	0x70, 0x87, 0xd0, 0x5d, 0xac, 0xfb, 0xd9, 0xae, 0x58, 0xac, 0x66, 0x7d,
+	0x87, 0x85, 0x0e, 0xd1, 0xfc, 0xbd, 0x7f, 0xb7, 0x94, 0x8b, 0x6e, 0xa1,
+	0x0f, 0x72, 0x27, 0xa1, 0xb7, 0xbc, 0xda, 0x8f, 0x73, 0x3b, 0xb4, 0xb7,
+	0x23, 0x2f, 0xb1, 0x3e, 0x5b, 0x8c, 0xc2, 0xa6, 0xed, 0x51, 0xb6, 0x0f,
+	0xea, 0x72, 0x61, 0xaf, 0x0b, 0x63, 0xd5, 0xfa, 0x6c, 0x40, 0xf9, 0x35,
+	0xe0, 0x87, 0xc4, 0x9c, 0xb7, 0xc5, 0x08, 0x26, 0x30, 0x02, 0xdf, 0x13,
+	0x60, 0x7a, 0x89, 0x1a, 0xe2, 0x44, 0xef, 0xd2, 0xaa, 0x90, 0x8d, 0x77,
+	0x05, 0x76, 0xc9, 0xf3, 0x77, 0xb3, 0xd3, 0x07, 0x45, 0x3f, 0xf3, 0x4b,
+	0x0d, 0xfd, 0x38, 0x57, 0x78, 0x0f, 0xeb, 0x86, 0xe8, 0x6b, 0x65, 0x42,
+	0xea, 0xc0, 0xc5, 0x32, 0x6a, 0x80, 0x89, 0x3e, 0x73, 0x5f, 0xf5, 0x38,
+	0xd1, 0x0f, 0xad, 0x0f, 0x36, 0x22, 0x7b, 0x8c, 0x6b, 0xfb, 0x31, 0x47,
+	0x59, 0x07, 0x0f, 0x3d, 0xcb, 0xef, 0xc7, 0xb5, 0xf5, 0xc7, 0x73, 0xaf,
+	0x3e, 0x1e, 0xf8, 0xf6, 0x70, 0xcf, 0xbb, 0x74, 0x57, 0x8d, 0xe7, 0x6e,
+	0x7d, 0x3c, 0xcf, 0xa8, 0xf1, 0x50, 0xce, 0x88, 0x0d, 0x28, 0xdc, 0xbf,
+	0xe1, 0x67, 0x77, 0x27, 0x18, 0xc7, 0xe4, 0x96, 0x40, 0xe7, 0xfd, 0x8a,
+	0x9f, 0x9c, 0x7e, 0x54, 0x67, 0x5f, 0xad, 0xc9, 0x3b, 0xac, 0x7f, 0xef,
+	0x09, 0x1c, 0x33, 0xc2, 0x38, 0x06, 0xd7, 0x29, 0x0f, 0x3d, 0x9d, 0x0b,
+	0xa3, 0x4e, 0xed, 0x0c, 0x8f, 0x9b, 0xed, 0xb1, 0x69, 0xfe, 0x14, 0xfe,
+	0x35, 0x3c, 0x47, 0xdf, 0xff, 0x3c, 0xdd, 0x9b, 0x87, 0x2e, 0x07, 0x8e,
+	0x95, 0xb5, 0x6c, 0xef, 0x2d, 0x4b, 0xff, 0x6e, 0xca, 0xd3, 0xbf, 0x0b,
+	0xdf, 0xee, 0x34, 0x70, 0x7e, 0x08, 0x7e, 0xe0, 0xa4, 0xfa, 0xad, 0x8f,
+	0x5c, 0x15, 0xcf, 0xf2, 0xd2, 0x4b, 0x33, 0x8e, 0xd8, 0x38, 0xc4, 0xaa,
+	0x64, 0x59, 0xcf, 0xd8, 0xa1, 0x0e, 0x43, 0xe6, 0xdc, 0xdc, 0xa8, 0x6a,
+	0xec, 0x74, 0x94, 0xe7, 0xcc, 0x8e, 0x1a, 0x46, 0x4a, 0xf8, 0x1a, 0xba,
+	0xed, 0x1e, 0xea, 0xe2, 0x75, 0xf4, 0x2c, 0xa1, 0x96, 0x9a, 0x65, 0x62,
+	0x0f, 0xe0, 0x12, 0xf3, 0x64, 0x3e, 0x6a, 0x45, 0x1e, 0x17, 0x76, 0x29,
+	0xd6, 0x17, 0x03, 0x74, 0x62, 0x5a, 0xa3, 0x0f, 0x7c, 0xbc, 0x84, 0x3a,
+	0x9a, 0x51, 0x1e, 0x3f, 0xfc, 0xc7, 0x63, 0xe6, 0x9b, 0xbc, 0x2e, 0x5d,
+	0x12, 0x7e, 0x99, 0x0b, 0x94, 0x63, 0x39, 0x3d, 0x22, 0xe4, 0xd4, 0x18,
+	0x61, 0x29, 0x62, 0xb9, 0x42, 0x6c, 0xc2, 0xb8, 0xa8, 0xdb, 0x23, 0x6d,
+	0x1d, 0x1e, 0xe5, 0xb2, 0xaa, 0x87, 0x90, 0x86, 0xee, 0xd8, 0xb8, 0x4f,
+	0x22, 0xfd, 0x89, 0x7d, 0x31, 0x4e, 0x4c, 0xe6, 0xf6, 0x7d, 0xc3, 0xae,
+	0x33, 0x45, 0xbd, 0x48, 0xd0, 0x4e, 0xf8, 0x13, 0x8d, 0x29, 0xa6, 0x9b,
+	0xfe, 0xdd, 0x19, 0xa7, 0xdf, 0xe0, 0x9c, 0xc8, 0xeb, 0x7f, 0xa5, 0x2a,
+	0xd7, 0xe0, 0x1c, 0xdb, 0xf4, 0xf9, 0x83, 0x4e, 0x4c, 0x62, 0x15, 0x93,
+	0xc2, 0x97, 0xb3, 0x9b, 0x12, 0x0b, 0x53, 0xf4, 0x68, 0x01, 0x3a, 0x8c,
+	0xee, 0x24, 0x6c, 0xfc, 0xa2, 0x0c, 0x64, 0x7c, 0x8a, 0x52, 0x55, 0xd0,
+	0xc8, 0xc7, 0x58, 0x89, 0x79, 0xaf, 0x88, 0x3d, 0x7f, 0x3e, 0x2e, 0xe3,
+	0x77, 0x54, 0x7e, 0x5d, 0xf9, 0xcb, 0x87, 0x29, 0xb9, 0x40, 0xd9, 0x4c,
+	0xf4, 0x4b, 0xa2, 0xd6, 0x75, 0x26, 0x3a, 0xa1, 0x7c, 0x3b, 0x11, 0xbe,
+	0x0e, 0x7f, 0x99, 0x49, 0x5f, 0x2e, 0x58, 0xd9, 0x0c, 0x49, 0x9f, 0x05,
+	0x71, 0x1f, 0x0c, 0x5e, 0x7b, 0x77, 0xb0, 0x0e, 0x39, 0x21, 0xfc, 0x16,
+	0x8c, 0x54, 0xe6, 0xd1, 0x1e, 0x3e, 0x87, 0x7e, 0x82, 0x9d, 0x96, 0x29,
+	0x3e, 0xa5, 0xda, 0xd6, 0x28, 0xc4, 0xbc, 0x10, 0xfa, 0x55, 0x3b, 0x1b,
+	0x35, 0x1a, 0xf7, 0xc3, 0xe7, 0x71, 0x42, 0xe0, 0xc8, 0x11, 0xb6, 0x79,
+	0x44, 0xbb, 0xda, 0xac, 0xf0, 0x5f, 0xf0, 0x79, 0xf9, 0x81, 0x21, 0xfd,
+	0x9b, 0x08, 0xb8, 0x2e, 0xfd, 0x1a, 0xfc, 0xcc, 0x32, 0xf7, 0xa3, 0x29,
+	0x9e, 0x7e, 0x98, 0xe2, 0x9b, 0xf0, 0x33, 0x9d, 0xbc, 0xaf, 0x7e, 0x26,
+	0xa6, 0x35, 0xaf, 0x3d, 0x37, 0x58, 0x36, 0x5e, 0x5f, 0xd7, 0xfe, 0xfb,
+	0x50, 0xaf, 0xe1, 0x4c, 0xab, 0x90, 0xf8, 0xdd, 0x0c, 0x60, 0xf0, 0x7c,
+	0xf5, 0x71, 0xfc, 0x5e, 0x8c, 0x2f, 0x2d, 0xb0, 0x71, 0x84, 0xb1, 0x0d,
+	0x30, 0xce, 0x98, 0xd8, 0x17, 0x8b, 0x3f, 0x16, 0xf1, 0xe5, 0x97, 0x07,
+	0xc9, 0x0f, 0x7f, 0x9c, 0xad, 0x63, 0x29, 0xba, 0x45, 0xdc, 0xbb, 0xdc,
+	0x8f, 0xc4, 0xfa, 0x0c, 0x9d, 0x78, 0x87, 0xed, 0x86, 0x09, 0x15, 0x87,
+	0xd3, 0x21, 0x6a, 0x53, 0xc9, 0xbd, 0x54, 0xad, 0x53, 0x34, 0xef, 0xe9,
+	0xbd, 0x0e, 0xe7, 0x6f, 0x73, 0x41, 0x76, 0x9d, 0x98, 0x02, 0xfe, 0x29,
+	0x31, 0x47, 0x97, 0x88, 0xe4, 0x1c, 0x37, 0xf6, 0x31, 0xba, 0x78, 0x9e,
+	0x60, 0x0f, 0xc2, 0xef, 0xf7, 0x35, 0xfe, 0xc4, 0x7e, 0xc4, 0xd5, 0x21,
+	0xe0, 0xa8, 0x3e, 0x9b, 0x79, 0x66, 0x1a, 0xe7, 0x83, 0x6c, 0x9f, 0x69,
+	0xdc, 0x2b, 0x7d, 0x51, 0x6c, 0xb3, 0xa9, 0xf9, 0x82, 0x1f, 0x6a, 0x54,
+	0xd5, 0x29, 0xb0, 0xc8, 0xec, 0x07, 0x9d, 0x3e, 0x2d, 0x79, 0x5c, 0x6f,
+	0xef, 0x62, 0x23, 0xb1, 0x4e, 0xf8, 0xdd, 0x30, 0xd4, 0xeb, 0xdc, 0x0b,
+	0xda, 0xf3, 0x1c, 0x39, 0xf7, 0x36, 0x1e, 0xdf, 0xa5, 0x7f, 0xb3, 0xe8,
+	0xfe, 0xcc, 0xdb, 0x16, 0x8f, 0x79, 0xfb, 0xf9, 0x90, 0xdc, 0x3b, 0x7b,
+	0x58, 0xb5, 0xf1, 0x8a, 0x6f, 0x5d, 0xfe, 0x0e, 0xfc, 0x50, 0x8d, 0xfc,
+	0x8b, 0x77, 0x84, 0x5e, 0x69, 0xf5, 0x85, 0x47, 0x58, 0x9f, 0x4a, 0x39,
+	0x3e, 0xe1, 0x21, 0xc7, 0xfd, 0x31, 0xe0, 0x96, 0x8f, 0x2f, 0xc7, 0xc7,
+	0xdb, 0xca, 0xf1, 0x9e, 0x61, 0xe9, 0x8b, 0x6d, 0x95, 0x63, 0xe4, 0x00,
+	0x9d, 0xa8, 0xb6, 0xf3, 0x7b, 0x61, 0x1e, 0x90, 0xcb, 0xee, 0xf4, 0x95,
+	0x80, 0x66, 0xda, 0x5f, 0x82, 0x7d, 0x43, 0xf0, 0x25, 0xf6, 0x5e, 0x4e,
+	0x1a, 0xa9, 0x79, 0xf7, 0x5e, 0xea, 0x46, 0xee, 0xbd, 0xed, 0x71, 0x2f,
+	0xb0, 0x3b, 0x64, 0xc3, 0x8a, 0x48, 0x5f, 0x80, 0xa6, 0xdf, 0xb0, 0xef,
+	0x70, 0xc9, 0xca, 0x96, 0x09, 0xbe, 0xee, 0x30, 0x9d, 0xc3, 0xfe, 0xb4,
+	0xf2, 0x25, 0x1f, 0x2b, 0x48, 0x3a, 0x84, 0x0e, 0x0a, 0xfe, 0x00, 0xbe,
+	0x8d, 0xa4, 0xfd, 0x69, 0x9e, 0x63, 0xe9, 0x47, 0xce, 0x2c, 0x45, 0xd4,
+	0xbc, 0x71, 0x5b, 0x3c, 0xcf, 0x33, 0x5f, 0x10, 0xf3, 0x65, 0x3d, 0xbf,
+	0x52, 0x8f, 0x4f, 0xc6, 0xda, 0x50, 0xa3, 0xff, 0xe0, 0x75, 0xcf, 0x7f,
+	0x30, 0x24, 0x6a, 0x37, 0xdc, 0xa8, 0x1e, 0x64, 0xbc, 0x89, 0x39, 0x85,
+	0x0f, 0x52, 0xfb, 0x88, 0x1f, 0xda, 0x4b, 0xbd, 0x07, 0x18, 0x05, 0x18,
+	0x64, 0x33, 0xbe, 0x34, 0x0e, 0x22, 0xce, 0xdc, 0xe4, 0x7b, 0x50, 0x73,
+	0x6a, 0xdc, 0x4c, 0x51, 0x0f, 0xfc, 0x10, 0xa8, 0x25, 0x6d, 0xe6, 0x9a,
+	0x64, 0xec, 0x94, 0x90, 0xb1, 0xd4, 0xf2, 0x29, 0x25, 0x63, 0xa7, 0x94,
+	0x1f, 0xfe, 0x94, 0x92, 0xb1, 0x53, 0x4a, 0xc6, 0x4e, 0x29, 0x19, 0x3b,
+	0xc5, 0x7c, 0x3e, 0xc6, 0xf8, 0x16, 0x58, 0x44, 0xfb, 0x41, 0x7b, 0x29,
+	0x53, 0xc2, 0x75, 0xac, 0xcf, 0x6e, 0x39, 0x7b, 0x69, 0x44, 0xca, 0x19,
+	0x63, 0x13, 0x19, 0xaf, 0xc7, 0xef, 0xc2, 0x1c, 0xfc, 0x1e, 0xd3, 0xef,
+	0x23, 0x3a, 0x33, 0x8f, 0xbe, 0xfa, 0x28, 0x29, 0x6a, 0xc9, 0x76, 0x50,
+	0xc2, 0x89, 0x85, 0x43, 0xc8, 0x0f, 0x93, 0xb6, 0x5f, 0xb6, 0x6d, 0xae,
+	0x98, 0xe6, 0x93, 0x98, 0x9a, 0x2f, 0xb7, 0x5d, 0xd4, 0x45, 0xe9, 0x22,
+	0xe8, 0x8a, 0x98, 0x4a, 0x93, 0xe7, 0x46, 0xd0, 0x49, 0x86, 0x44, 0xb9,
+	0x68, 0x70, 0x4c, 0xd1, 0xe0, 0xdb, 0x62, 0x8c, 0x88, 0x49, 0x84, 0x2f,
+	0xb3, 0x3d, 0x1d, 0x72, 0x85, 0x31, 0x7e, 0x0e, 0xcb, 0xc2, 0xc1, 0x08,
+	0xeb, 0xa4, 0x8d, 0xd3, 0xa1, 0x31, 0xf6, 0x76, 0xba, 0x67, 0xa3, 0x79,
+	0x39, 0x77, 0x1c, 0x6b, 0x49, 0x44, 0xad, 0x23, 0x12, 0x17, 0x6f, 0xb1,
+	0x6b, 0x74, 0x34, 0xba, 0x97, 0x8f, 0xad, 0x74, 0x96, 0x0e, 0x90, 0xd1,
+	0x57, 0xa3, 0xbf, 0x60, 0x39, 0xe8, 0x66, 0x39, 0x38, 0xaa, 0xec, 0x92,
+	0xa3, 0x75, 0xbb, 0x64, 0xcf, 0x1e, 0xc4, 0x65, 0x64, 0xc4, 0xbe, 0xd7,
+	0x56, 0x55, 0x43, 0x00, 0xbe, 0x6f, 0x9c, 0x77, 0x51, 0x7c, 0x18, 0xe7,
+	0xf8, 0x2d, 0x22, 0x6b, 0x32, 0xee, 0x1b, 0xdf, 0x23, 0xb0, 0xbb, 0xcf,
+	0xc2, 0x3d, 0x47, 0xa5, 0xde, 0xf3, 0x91, 0x7f, 0xfc, 0x36, 0xe3, 0x89,
+	0x1a, 0x3d, 0xc1, 0xef, 0xcc, 0x17, 0xf7, 0xf1, 0xb3, 0x75, 0x4d, 0x09,
+	0x3b, 0x6e, 0xf8, 0xb6, 0x92, 0xbf, 0xaf, 0xdd, 0xbb, 0x2d, 0xc1, 0x8f,
+	0x8c, 0xa7, 0x8d, 0xd9, 0xe8, 0x7b, 0xb5, 0xd3, 0x27, 0xe1, 0x63, 0x87,
+	0x9c, 0x58, 0x21, 0xd3, 0xe7, 0x25, 0x1f, 0x12, 0x2b, 0x35, 0xe2, 0x63,
+	0x21, 0x2f, 0x35, 0xfa, 0x77, 0x1e, 0x5b, 0x88, 0xb0, 0x77, 0x22, 0x9f,
+	0x9f, 0xa6, 0x19, 0x91, 0x83, 0x8d, 0x38, 0xe9, 0x33, 0xf3, 0xfa, 0x5d,
+	0xb6, 0xe2, 0x8d, 0xcf, 0x20, 0xce, 0xad, 0xb8, 0x48, 0x6b, 0xaf, 0x39,
+	0xf0, 0xd7, 0x8d, 0x2d, 0xac, 0xf6, 0x85, 0x45, 0x4e, 0xf8, 0x76, 0xc6,
+	0x48, 0x3a, 0x1e, 0x7a, 0x9c, 0x9f, 0x0f, 0x3f, 0x5e, 0x80, 0x92, 0x57,
+	0xd0, 0xae, 0x93, 0x46, 0x17, 0x6a, 0x5f, 0xe0, 0xef, 0xc5, 0xfe, 0x65,
+	0x86, 0xba, 0xd5, 0xde, 0x44, 0x8f, 0xda, 0xcf, 0x8a, 0xb0, 0xec, 0x35,
+	0x72, 0x9d, 0x47, 0xeb, 0x3e, 0x3d, 0xc8, 0x84, 0xdb, 0xa7, 0xf7, 0xf4,
+	0x3a, 0xeb, 0xd5, 0x7a, 0x72, 0x80, 0x58, 0xd6, 0x2e, 0x52, 0xbe, 0x4a,
+	0x33, 0x4f, 0x1b, 0xcd, 0xe9, 0xdb, 0xf4, 0x3d, 0xdd, 0x9d, 0x31, 0xf3,
+	0xc2, 0x9b, 0x76, 0x50, 0xf1, 0x5f, 0x27, 0x9d, 0x29, 0x05, 0x79, 0xcd,
+	0x87, 0x6e, 0x05, 0xbd, 0xfc, 0xc3, 0xc8, 0x73, 0xf9, 0x7a, 0xa0, 0x93,
+	0x96, 0x96, 0x10, 0x6b, 0xf1, 0x47, 0x7b, 0x64, 0x7c, 0x71, 0x9a, 0xe9,
+	0x72, 0x80, 0xd7, 0x47, 0x43, 0xed, 0x1d, 0xe1, 0x1a, 0x74, 0x89, 0xa8,
+	0x37, 0x1a, 0xf8, 0xd2, 0x44, 0x90, 0xed, 0x02, 0xb9, 0xf7, 0x70, 0x88,
+	0x9f, 0xfd, 0xfd, 0x52, 0x1a, 0xfe, 0xb2, 0xd0, 0x11, 0x7e, 0x7e, 0x92,
+	0xf1, 0x44, 0x9c, 0x3a, 0xa9, 0xb2, 0xd4, 0xc9, 0x76, 0x41, 0x27, 0xe3,
+	0x89, 0xb1, 0xd0, 0xa8, 0x4f, 0xbc, 0x4b, 0xe4, 0xd4, 0x3c, 0x1c, 0x38,
+	0xc0, 0x7c, 0x85, 0x77, 0xbd, 0xae, 0xde, 0xe5, 0x7e, 0xc7, 0x2f, 0x6a,
+	0x38, 0x3f, 0xe2, 0x37, 0x2f, 0xdc, 0xc2, 0xef, 0x51, 0xcd, 0xcf, 0x30,
+	0x76, 0x0e, 0x53, 0x7e, 0xbe, 0x83, 0xc7, 0x10, 0x63, 0x3b, 0x22, 0xca,
+	0xe7, 0x8f, 0x50, 0xb6, 0x7a, 0x92, 0x7e, 0xbf, 0xea, 0xf4, 0x09, 0x3f,
+	0xc2, 0x7d, 0x96, 0x39, 0xfd, 0x5d, 0xdc, 0xaf, 0x0f, 0x6d, 0xb7, 0x8e,
+	0x09, 0x92, 0xff, 0x7b, 0x61, 0xea, 0x7c, 0x0e, 0xbe, 0x97, 0x1a, 0x15,
+	0xa3, 0xd6, 0xa5, 0x3b, 0x24, 0xfd, 0xcf, 0x2f, 0x88, 0xb8, 0x5a, 0xbe,
+	0x9f, 0x9f, 0x39, 0x87, 0x76, 0x2f, 0x98, 0x74, 0xd3, 0x96, 0xf4, 0x7e,
+	0x23, 0x10, 0x26, 0xff, 0xcb, 0x88, 0x7d, 0x02, 0x56, 0x33, 0x2f, 0xd8,
+	0xfb, 0x58, 0xbf, 0x3f, 0x87, 0xfb, 0xf8, 0xf3, 0x65, 0x9c, 0x07, 0x79,
+	0x9c, 0x58, 0xaf, 0x11, 0xef, 0x02, 0xbd, 0x78, 0x20, 0x12, 0x12, 0xfc,
+	0xf7, 0x08, 0xf3, 0x54, 0x87, 0xf0, 0x35, 0xf6, 0xa3, 0xad, 0x3d, 0xc4,
+	0xd8, 0xc2, 0xbc, 0x30, 0xb1, 0x0f, 0xe7, 0xf1, 0x3e, 0x3f, 0xd3, 0x48,
+	0xf2, 0x10, 0xc6, 0xd3, 0xc4, 0xdc, 0x81, 0x43, 0x13, 0xc4, 0xf3, 0x09,
+	0xfc, 0xc1, 0xf3, 0x19, 0x42, 0x7d, 0xa7, 0x20, 0xa5, 0xf8, 0x1d, 0xc9,
+	0x92, 0x1c, 0xf7, 0x5c, 0xd5, 0x4f, 0xd2, 0x4f, 0x75, 0x74, 0x44, 0xff,
+	0x9e, 0x21, 0x0d, 0xe2, 0xd9, 0x5a, 0x56, 0x70, 0xdc, 0x4b, 0x77, 0x4b,
+	0x3d, 0x74, 0x4f, 0xed, 0x69, 0xdd, 0x15, 0x76, 0x19, 0xeb, 0xf0, 0x74,
+	0x2f, 0xdd, 0x59, 0xea, 0x20, 0xea, 0x0f, 0x8a, 0x3d, 0xe7, 0xbb, 0xa5,
+	0x32, 0xbf, 0x3f, 0x31, 0x22, 0xfd, 0x3a, 0x0d, 0x1e, 0xb9, 0xeb, 0xc1,
+	0x23, 0x1f, 0x08, 0x1e, 0xd9, 0x37, 0xb2, 0x36, 0x8f, 0xec, 0x52, 0xb6,
+	0x48, 0x90, 0x3a, 0x15, 0x7f, 0xbc, 0xc4, 0xfc, 0xf1, 0x2c, 0xf3, 0xc7,
+	0xe1, 0x36, 0xfc, 0x61, 0xb8, 0xf8, 0xe3, 0x88, 0xe0, 0x8f, 0x87, 0x46,
+	0xd6, 0xe2, 0x8f, 0xc3, 0xfe, 0xb5, 0x7c, 0x4d, 0xe2, 0xb7, 0x3c, 0x2f,
+	0xcc, 0xd9, 0xbb, 0x99, 0xd7, 0x6d, 0xaa, 0xcc, 0x23, 0x67, 0x61, 0x25,
+	0x6a, 0xd0, 0xbf, 0x08, 0x9b, 0x6c, 0x55, 0xd8, 0xfc, 0x31, 0x11, 0xc3,
+	0xba, 0x28, 0xf8, 0x8b, 0xd7, 0xff, 0x18, 0x72, 0xaa, 0xdc, 0x73, 0xd1,
+	0x4d, 0x37, 0xa3, 0x98, 0x0b, 0x53, 0xcd, 0x05, 0xae, 0x75, 0xe9, 0xfa,
+	0x90, 0x01, 0xbe, 0x7e, 0xe1, 0x03, 0xf0, 0xe8, 0x72, 0x4f, 0x20, 0x59,
+	0xf8, 0xe6, 0x08, 0xf0, 0x5f, 0x7e, 0x99, 0x1c, 0xd7, 0x03, 0x7c, 0x3d,
+	0x2c, 0x7e, 0xfb, 0x09, 0xb2, 0xf2, 0x8f, 0x88, 0x71, 0x64, 0x9e, 0xbc,
+	0x59, 0x1a, 0xa6, 0x5b, 0xa5, 0xdd, 0xb4, 0x5a, 0x1a, 0xa1, 0x37, 0x45,
+	0x2d, 0x0d, 0x99, 0x1b, 0xb9, 0x2a, 0xe6, 0xc8, 0xa0, 0x43, 0x61, 0x6e,
+	0xb3, 0xb4, 0x9b, 0x56, 0x96, 0x34, 0x7f, 0x83, 0xb7, 0xc1, 0x2f, 0xf1,
+	0x3e, 0x99, 0x2f, 0xd7, 0xca, 0x33, 0xc9, 0x26, 0x9e, 0x91, 0xf7, 0x80,
+	0x57, 0xf2, 0xad, 0xb9, 0xbe, 0xdd, 0xa1, 0x18, 0x62, 0xf5, 0x82, 0xd4,
+	0x81, 0xb8, 0x45, 0xc3, 0x9a, 0x3c, 0xe4, 0x07, 0x86, 0xfe, 0x2a, 0xaf,
+	0xb9, 0x3c, 0x67, 0x36, 0xe2, 0x9c, 0x46, 0x18, 0x0f, 0x6f, 0x17, 0xf8,
+	0x37, 0x61, 0x07, 0x22, 0x49, 0xaa, 0x5d, 0x30, 0x6c, 0xd4, 0x73, 0x4c,
+	0xf3, 0xf3, 0x0c, 0xe5, 0x6f, 0xda, 0xe6, 0xe0, 0x3f, 0x37, 0xd6, 0xc5,
+	0x5e, 0xf2, 0x63, 0xdc, 0x67, 0xac, 0xc3, 0x8d, 0xfd, 0x1a, 0xaa, 0xef,
+	0xd7, 0x74, 0xf3, 0xb8, 0xa5, 0xec, 0xcd, 0xda, 0xdc, 0xae, 0xca, 0xed,
+	0xaa, 0xd8, 0xfb, 0xe3, 0xeb, 0x4b, 0xd8, 0x77, 0x1e, 0xa6, 0xd5, 0x79,
+	0xc8, 0x28, 0xfc, 0x21, 0x8d, 0xbd, 0xde, 0xd5, 0x65, 0x5c, 0x87, 0x4f,
+	0xa4, 0xb1, 0xd7, 0xbb, 0xaa, 0xf6, 0x7a, 0x57, 0x97, 0x63, 0x42, 0x6f,
+	0xe7, 0x4b, 0x4c, 0xf7, 0x92, 0x5f, 0xc5, 0x39, 0xee, 0x53, 0xbf, 0x2d,
+	0xf4, 0x98, 0xf0, 0x69, 0xf7, 0xd9, 0x6b, 0xd3, 0xf0, 0x50, 0x0b, 0x0d,
+	0x63, 0x02, 0x67, 0xa5, 0xf8, 0x99, 0xc9, 0xd2, 0x63, 0xff, 0x3b, 0x60,
+	0x78, 0x46, 0x00, 0xf3, 0x9e, 0x30, 0x34, 0xef, 0xc1, 0xe6, 0x8e, 0xf9,
+	0x19, 0x20, 0xf7, 0x14, 0xd9, 0x80, 0xfb, 0x16, 0x90, 0xf2, 0x4a, 0x06,
+	0xad, 0xbc, 0x02, 0xa6, 0x09, 0x75, 0x88, 0xfe, 0xa6, 0xf5, 0x9f, 0xe5,
+	0x60, 0xe3, 0x80, 0x4d, 0x40, 0x73, 0x9b, 0xa7, 0x90, 0x32, 0xf7, 0x0c,
+	0xac, 0x6f, 0xb1, 0xae, 0x6d, 0xb4, 0x01, 0xef, 0xb1, 0x5e, 0x34, 0x85,
+	0x85, 0x61, 0x49, 0x0f, 0x03, 0xb0, 0x7e, 0x00, 0xa5, 0x75, 0x50, 0x1d,
+	0x01, 0x4f, 0xef, 0x02, 0x4d, 0x40, 0xf7, 0x39, 0x01, 0xdb, 0xa2, 0xce,
+	0xfd, 0xca, 0xe0, 0xb5, 0xb2, 0x0d, 0xd0, 0x73, 0xab, 0x16, 0xf5, 0x88,
+	0xc9, 0x83, 0xf2, 0x99, 0x93, 0x0a, 0x03, 0x19, 0x79, 0x81, 0x0d, 0x9a,
+	0x17, 0xc0, 0xe1, 0x04, 0x4c, 0xeb, 0xc0, 0x32, 0x6a, 0x8d, 0x2e, 0xd0,
+	0x3c, 0x1e, 0x16, 0x97, 0x7e, 0x90, 0x18, 0x03, 0x54, 0x8c, 0x05, 0xc8,
+	0x97, 0x01, 0xb6, 0x29, 0x41, 0x7e, 0x05, 0xe5, 0x05, 0x90, 0xd9, 0x20,
+	0xbf, 0x83, 0xca, 0x4e, 0x50, 0x5e, 0x04, 0xb2, 0x97, 0x08, 0x41, 0xfd,
+	0x0c, 0xa4, 0x81, 0xec, 0xe6, 0x29, 0x22, 0x60, 0x7e, 0x52, 0x80, 0x10,
+	0x43, 0x03, 0x3c, 0x1f, 0x10, 0x1b, 0xc6, 0x30, 0xf5, 0x31, 0x64, 0xe4,
+	0x1b, 0x88, 0x19, 0x88, 0x7c, 0xc3, 0xce, 0x70, 0x40, 0x00, 0x16, 0x56,
+	0xff, 0xff, 0x1f, 0x53, 0x61, 0x01, 0xa6, 0x53, 0xd0, 0x3a, 0xd6, 0xdf,
+	0xff, 0x0f, 0x88, 0xb0, 0x30, 0xb4, 0xc0, 0xd7, 0x23, 0xe6, 0xc8, 0x83,
+	0xca, 0xd0, 0x05, 0x40, 0x56, 0x1b, 0xbc, 0x4d, 0xc0, 0x02, 0xbe, 0xef,
+	0x79, 0x01, 0xc3, 0x2f, 0x60, 0x99, 0xf5, 0xff, 0xff, 0x52, 0xb8, 0x5a,
+	0x10, 0x00, 0x00, 0x19, 0x3f, 0x16, 0x21, 0xc4, 0x7d, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
+	0x08001b68, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4,
+	0x08001ab4, 0x08001ba4, 0x08001b28, 0x08001ba4, 0x08001a3c, 0x08001ba4,
+	0x08001ba4, 0x08001ba4, 0x08001a48, 0x00000000, 0x08002abc, 0x08002b0c,
+	0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c,
+	0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8,
+	0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_com_fw_09 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
-	.start_addr			= 0x080000b0,
+	.start_addr			= 0x080000b4,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x7c5c,
+	.text_len			= 0x7dc0,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_COM_b09FwText,
 	.gz_text_len			= sizeof(bnx2_COM_b09FwText),
 
-	.data_addr			= 0x08007d00,
+	.data_addr			= 0x08007e60,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_COM_b09FwData,
 
-	.sbss_addr			= 0x08007d00,
-	.sbss_len			= 0x5c,
+	.sbss_addr			= 0x08007e60,
+	.sbss_len			= 0x60,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_COM_b09FwSbss,
 
-	.bss_addr			= 0x08007d60,
+	.bss_addr			= 0x08007ec0,
 	.bss_len			= 0x88,
 	.bss_index			= 0x0,
 	.bss				= bnx2_COM_b09FwBss,
 
-	.rodata_addr			= 0x08007c60,
+	.rodata_addr			= 0x08007dc0,
 	.rodata_len			= 0x88,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_COM_b09FwRodata,
 };
 
 static u8 bnx2_CP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x8e, 0xfc, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xbd, 0x7d, 0x0d, 0x74,
-	0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x79, 0x92, 0xc6, 0xb2, 0x2c, 0x3f,
-	0xcb, 0x63, 0x65, 0x22, 0x0b, 0x7b, 0x46, 0x7a, 0xb2, 0x95, 0x58, 0x64,
-	0xc7, 0xae, 0x00, 0x6d, 0x3b, 0x85, 0xe9, 0x48, 0xb2, 0x9d, 0x0f, 0x8a,
-	0x4c, 0x44, 0x4f, 0x5a, 0xe8, 0x22, 0xc6, 0x76, 0x48, 0x80, 0xb2, 0x4e,
-	0x09, 0x69, 0x80, 0x04, 0x0f, 0x23, 0xf9, 0x83, 0x74, 0xec, 0x51, 0x12,
-	0xc5, 0x76, 0x4f, 0x73, 0x58, 0x55, 0x92, 0x1d, 0x43, 0xa7, 0x1e, 0x27,
-	0x71, 0x68, 0xf6, 0x6c, 0x68, 0xb4, 0x4a, 0xe2, 0xa6, 0x3d, 0xd9, 0xd6,
-	0xf4, 0x84, 0x6e, 0xda, 0x43, 0x77, 0x85, 0x71, 0x88, 0x4b, 0xb3, 0x4b,
-	0xf8, 0x68, 0x61, 0xa1, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d, 0xd2, 0xe8,
-	0xc3, 0x09, 0xa1, 0xbb, 0xf5, 0x39, 0xcf, 0x6f, 0xde, 0xfd, 0xfc, 0xdf,
-	0xff, 0xfd, 0x7f, 0xdf, 0x0f, 0xad, 0x17, 0xa9, 0x17, 0xfb, 0x6f, 0x15,
-	0x9e, 0x6d, 0x89, 0x7d, 0xbb, 0xb7, 0x5e, 0xd7, 0x73, 0x1d, 0x7e, 0x6e,
-	0x75, 0x57, 0x46, 0x95, 0xbc, 0x89, 0x7f, 0x89, 0x9f, 0xa1, 0x4c, 0x44,
-	0xc4, 0x0b, 0xfb, 0xe2, 0x23, 0x51, 0x95, 0x1e, 0xfc, 0x64, 0xd6, 0x97,
-	0x68, 0x24, 0x7d, 0xf6, 0xb3, 0xbb, 0x7d, 0x91, 0x4c, 0x79, 0x4b, 0xa2,
-	0x57, 0xfe, 0x25, 0xc8, 0xc7, 0x5c, 0x61, 0xfa, 0x5b, 0xd2, 0xff, 0xfc,
-	0x9f, 0xbe, 0xf2, 0x8e, 0xe4, 0x6b, 0xe3, 0x11, 0x89, 0x7a, 0xe9, 0x8f,
-	0x89, 0xb7, 0x49, 0xa2, 0xad, 0xe9, 0x81, 0x4f, 0x3e, 0xbc, 0xf9, 0x6f,
-	0x44, 0x1a, 0xc3, 0xb6, 0x2e, 0x07, 0x5f, 0xd9, 0x2c, 0xf9, 0x96, 0x74,
-	0x7c, 0xc8, 0x4d, 0x7b, 0xf2, 0x74, 0x45, 0x06, 0x0a, 0xc5, 0xa8, 0x44,
-	0xd2, 0x1d, 0x2f, 0xf5, 0x46, 0xf6, 0x07, 0x11, 0xdf, 0xf7, 0x7a, 0xa5,
-	0xa1, 0x27, 0xdb, 0x8d, 0xf4, 0xf2, 0x56, 0x51, 0x7e, 0x54, 0xb2, 0x15,
-	0x69, 0x50, 0xbe, 0x8f, 0x77, 0xbd, 0xa8, 0x74, 0xd2, 0xcb, 0x46, 0x5c,
-	0x29, 0x54, 0x2e, 0xac, 0x30, 0x6d, 0x96, 0xec, 0xfb, 0x6f, 0xa2, 0xe6,
-	0x8d, 0x36, 0x4b, 0x51, 0x99, 0x8d, 0xc4, 0x05, 0xfd, 0x00, 0xe6, 0x06,
-	0x19, 0x2e, 0x25, 0x24, 0x5b, 0x64, 0xbf, 0xae, 0xe4, 0x3c, 0xf6, 0xd9,
-	0x80, 0xfa, 0x2b, 0x9d, 0xe5, 0xcb, 0xb3, 0xec, 0x4b, 0x28, 0x9b, 0x40,
-	0xb9, 0x56, 0x79, 0xbc, 0x12, 0x97, 0xc7, 0x2a, 0x31, 0x79, 0xb4, 0x72,
-	0x87, 0x64, 0x50, 0xf7, 0x6c, 0x05, 0x7d, 0x97, 0x6a, 0xa5, 0x77, 0xac,
-	0x5e, 0xb2, 0x63, 0xed, 0xf1, 0x9c, 0x04, 0xc1, 0x27, 0x52, 0x1f, 0x95,
-	0xa1, 0x26, 0x94, 0x2f, 0x31, 0x2f, 0xbe, 0x20, 0x2f, 0x97, 0xda, 0xe2,
-	0xe5, 0x94, 0x23, 0x99, 0xc1, 0x64, 0x7c, 0x48, 0xf1, 0xbb, 0x46, 0xb2,
-	0x5d, 0xf8, 0x1e, 0x70, 0x25, 0xe2, 0x07, 0xc1, 0x1d, 0xa9, 0x26, 0xc0,
-	0x91, 0x4c, 0x24, 0x14, 0xeb, 0xb2, 0x5e, 0x32, 0x9f, 0x50, 0x51, 0xc9,
-	0x57, 0xae, 0x93, 0x44, 0x53, 0x10, 0xbc, 0x37, 0xe5, 0x21, 0x5d, 0xa4,
-	0xb7, 0x28, 0xfb, 0x54, 0xda, 0x47, 0x9b, 0x92, 0x52, 0xe9, 0xb5, 0x18,
-	0xc7, 0x16, 0xe0, 0xa9, 0x56, 0x32, 0x31, 0xc9, 0xa8, 0xb4, 0x24, 0x54,
-	0x7a, 0x05, 0xd2, 0x1c, 0xa9, 0xf1, 0xa7, 0x2c, 0x9d, 0xac, 0xc6, 0xb7,
-	0x0c, 0xa8, 0x74, 0xd3, 0xa2, 0xf4, 0x64, 0x42, 0xd4, 0x8f, 0xea, 0xd0,
-	0x67, 0x67, 0x46, 0x31, 0x0d, 0x6f, 0x9d, 0x76, 0xfd, 0x32, 0x69, 0x1f,
-	0x74, 0x16, 0xa6, 0x3d, 0xb5, 0x8a, 0xb0, 0x8a, 0xe2, 0xef, 0x28, 0xe0,
-	0x6a, 0x41, 0xff, 0xed, 0x5e, 0x0d, 0xc6, 0x35, 0x90, 0x4a, 0x7a, 0xfd,
-	0xea, 0xc5, 0x40, 0x9a, 0x09, 0x33, 0xf3, 0x14, 0xf2, 0x50, 0x34, 0x9d,
-	0xc2, 0xbc, 0xb9, 0x72, 0x08, 0x63, 0xbb, 0x38, 0x96, 0xf4, 0xda, 0x14,
-	0xde, 0x53, 0xfc, 0xdd, 0x34, 0x14, 0x49, 0x07, 0x41, 0x36, 0x35, 0x2e,
-	0xb9, 0x72, 0xd2, 0x9b, 0x05, 0x70, 0xbd, 0x63, 0x71, 0x8c, 0x1f, 0xe3,
-	0x88, 0x65, 0x92, 0x6b, 0xa4, 0xcb, 0xce, 0xcf, 0x5f, 0xa2, 0xef, 0x76,
-	0xef, 0x0e, 0xd5, 0xee, 0xa5, 0x54, 0xd2, 0x9b, 0x90, 0x3f, 0xc4, 0x77,
-	0x10, 0xec, 0x4a, 0x25, 0xe3, 0x79, 0xcc, 0xdd, 0xa5, 0x62, 0x4c, 0x5e,
-	0x2e, 0x26, 0x41, 0xa9, 0xc9, 0xce, 0x49, 0xd9, 0x92, 0x9a, 0x04, 0xdc,
-	0x05, 0x3c, 0x07, 0x99, 0x57, 0x46, 0x5e, 0x99, 0x75, 0x83, 0xe0, 0xe6,
-	0xd4, 0x89, 0x60, 0xa8, 0xd9, 0xd0, 0xfe, 0xd3, 0x25, 0xcc, 0x2b, 0xe6,
-	0xe9, 0xb1, 0x12, 0xe6, 0xb5, 0x84, 0x39, 0xd5, 0xf3, 0xdf, 0x89, 0xf9,
-	0x27, 0x8d, 0x90, 0x3e, 0xb6, 0x59, 0x7a, 0x7d, 0xb7, 0x7d, 0x8b, 0x64,
-	0x4b, 0x8e, 0x64, 0x53, 0x3f, 0x09, 0x32, 0x9a, 0x27, 0xc4, 0xe9, 0x2d,
-	0x91, 0x26, 0x6b, 0x00, 0x2b, 0x3f, 0x7f, 0xdd, 0x96, 0x8b, 0x3a, 0x18,
-	0x06, 0xe7, 0x83, 0xf9, 0x51, 0xe5, 0xd7, 0xd9, 0xfc, 0x90, 0xf6, 0xf9,
-	0x0f, 0x74, 0xe7, 0xcf, 0x97, 0xcb, 0x92, 0x36, 0x2b, 0x22, 0xb9, 0x07,
-	0x03, 0xe9, 0x4d, 0x01, 0x5f, 0x6c, 0xd3, 0x4b, 0x89, 0xae, 0xeb, 0xb1,
-	0x8c, 0x2e, 0x8b, 0x7f, 0x3f, 0xae, 0x41, 0x1f, 0x4e, 0x5f, 0x69, 0xbe,
-	0x6e, 0x5f, 0xe9, 0x85, 0x98, 0x85, 0x0f, 0xdf, 0x3d, 0x4e, 0xb6, 0xf2,
-	0x77, 0x76, 0x8e, 0xc3, 0x71, 0x74, 0x2d, 0x43, 0xe3, 0x2e, 0xf8, 0xc1,
-	0x93, 0x5c, 0xb1, 0x07, 0xfd, 0xc6, 0xf0, 0x0e, 0x82, 0x91, 0x54, 0x26,
-	0xe9, 0x4a, 0x1a, 0xdf, 0x03, 0x98, 0xaf, 0x0e, 0xe0, 0x4f, 0xdc, 0xec,
-	0xe6, 0x94, 0xf4, 0x55, 0x40, 0x7b, 0x95, 0x37, 0x96, 0x14, 0x7a, 0x0c,
-	0xa9, 0x7f, 0xb1, 0xb8, 0x61, 0x3f, 0x7c, 0xbb, 0x32, 0x02, 0xfa, 0x28,
-	0x8c, 0xf9, 0x32, 0x5c, 0x9c, 0xf6, 0x94, 0x24, 0x41, 0xbb, 0x69, 0xe9,
-	0xad, 0xf8, 0x52, 0x28, 0xe2, 0x5d, 0x6a, 0x07, 0xfd, 0xba, 0x92, 0x89,
-	0x9b, 0x39, 0x29, 0x14, 0x7f, 0x09, 0xe3, 0x02, 0x8e, 0x7d, 0xfe, 0xee,
-	0xb1, 0xb0, 0x80, 0xf7, 0xbb, 0x53, 0x1a, 0x3f, 0x6f, 0x0e, 0x06, 0xf6,
-	0x8d, 0x31, 0x60, 0x9c, 0x85, 0xb2, 0x8b, 0x77, 0x0c, 0xef, 0x90, 0x16,
-	0xe3, 0x80, 0xa9, 0x55, 0x86, 0x41, 0x8b, 0xbd, 0x82, 0xdf, 0x53, 0x84,
-	0x91, 0xfd, 0xb6, 0xe8, 0xdf, 0xc3, 0x63, 0x1b, 0xf4, 0x77, 0x6e, 0xa0,
-	0x45, 0xf2, 0x53, 0xe1, 0x58, 0x28, 0x0f, 0x28, 0x03, 0x92, 0x87, 0x45,
-	0x28, 0x13, 0x82, 0xe0, 0xc1, 0x14, 0xe5, 0x42, 0x10, 0x3c, 0x96, 0xa2,
-	0x9c, 0x38, 0x07, 0xfe, 0xa7, 0x6c, 0x20, 0xaf, 0xae, 0x55, 0x9c, 0x83,
-	0x6c, 0x11, 0x7d, 0x40, 0x4e, 0xe4, 0xba, 0x4e, 0x40, 0x6e, 0x50, 0xae,
-	0x5c, 0xf8, 0x44, 0xd6, 0xcf, 0xc7, 0x23, 0x1a, 0x0f, 0x98, 0x6f, 0xc8,
-	0xbc, 0x8c, 0x86, 0xbc, 0x4d, 0x0a, 0x5d, 0xa3, 0xb6, 0xcc, 0x65, 0x5d,
-	0xc6, 0x5d, 0x52, 0xe6, 0x76, 0x65, 0xf8, 0xae, 0x15, 0xf3, 0xb1, 0x42,
-	0x11, 0x4f, 0x6d, 0x9b, 0xf8, 0x2d, 0xd1, 0x9a, 0xf4, 0x97, 0x90, 0x37,
-	0x7d, 0xd7, 0x49, 0x7f, 0xb9, 0xbc, 0x59, 0x77, 0x69, 0xde, 0x88, 0xb8,
-	0x7e, 0xb2, 0x73, 0x97, 0x9a, 0x01, 0x3d, 0x05, 0xc1, 0xc9, 0x54, 0x98,
-	0xfe, 0x8f, 0xee, 0xd2, 0x3e, 0x12, 0x35, 0x4b, 0xd3, 0xee, 0x5d, 0x26,
-	0xed, 0xc4, 0x32, 0x69, 0x1b, 0x6a, 0x97, 0xa6, 0xbd, 0x7f, 0x99, 0xb4,
-	0xfb, 0x97, 0x49, 0xfb, 0x5f, 0xcb, 0xa4, 0x7d, 0x67, 0x99, 0xb4, 0xef,
-	0x2d, 0x93, 0xd6, 0x52, 0xb7, 0x34, 0xcd, 0x05, 0x3f, 0x6d, 0x92, 0x42,
-	0xec, 0x73, 0x1c, 0xbb, 0xc5, 0xcd, 0xfe, 0xc8, 0x52, 0xdc, 0xd4, 0xa0,
-	0x5c, 0xeb, 0xa2, 0x72, 0x53, 0xcb, 0x94, 0xab, 0x45, 0xb9, 0xa6, 0x45,
-	0xe5, 0x92, 0xcb, 0xe0, 0xba, 0x4e, 0xeb, 0xaf, 0x85, 0xe5, 0x0a, 0xcb,
-	0x94, 0x63, 0xfa, 0x1e, 0xdb, 0xcf, 0x16, 0x68, 0x99, 0xd7, 0x9b, 0xaf,
-	0x5a, 0x91, 0x66, 0xa6, 0xb7, 0x42, 0x47, 0xac, 0x50, 0x86, 0xdf, 0x29,
-	0x5b, 0x98, 0xe6, 0x81, 0xee, 0xa3, 0xa0, 0x3b, 0xca, 0x47, 0xf0, 0x91,
-	0x4f, 0xfe, 0x5d, 0x25, 0x43, 0xb1, 0x2d, 0xde, 0x2f, 0xa8, 0x06, 0xd0,
-	0x58, 0xd2, 0x4b, 0x28, 0xf2, 0x97, 0xe4, 0x23, 0x69, 0x3f, 0xdf, 0x2b,
-	0x2a, 0xa6, 0x24, 0x90, 0xbe, 0x94, 0x6a, 0x52, 0xb2, 0x1f, 0xfc, 0x93,
-	0x81, 0x4e, 0xda, 0x15, 0xf4, 0x6a, 0x1e, 0x32, 0x65, 0xaf, 0x2c, 0x2b,
-	0x7d, 0x39, 0x48, 0x19, 0x97, 0xce, 0xdc, 0x95, 0xf5, 0xa7, 0x7b, 0x6a,
-	0x41, 0xb3, 0x17, 0x51, 0x67, 0x07, 0x6a, 0xee, 0x2d, 0xbb, 0xd2, 0x57,
-	0xee, 0x04, 0x2f, 0x38, 0x72, 0xde, 0x5f, 0x2d, 0xe7, 0x53, 0x28, 0x5b,
-	0x89, 0xc8, 0x4c, 0xcc, 0x91, 0x19, 0x7c, 0x67, 0x53, 0xc8, 0xab, 0x84,
-	0xbc, 0xd5, 0x29, 0x07, 0x4a, 0xbe, 0x1c, 0x2e, 0xfd, 0x92, 0x0a, 0xf5,
-	0x56, 0x7f, 0x6a, 0xa5, 0x9c, 0xf6, 0x4c, 0xdb, 0x3b, 0xfc, 0x69, 0x68,
-	0x4c, 0x57, 0x2e, 0xfa, 0xc9, 0xf8, 0x8c, 0xe6, 0x89, 0x1f, 0x06, 0x7d,
-	0x68, 0x67, 0xc2, 0x4f, 0x7a, 0x7f, 0x8a, 0xef, 0xa1, 0x32, 0xed, 0x90,
-	0xf9, 0xb6, 0x86, 0xd1, 0xd6, 0xa1, 0xd2, 0x2a, 0xf9, 0xb0, 0xad, 0xbf,
-	0xdd, 0x9f, 0xee, 0x04, 0xcf, 0x79, 0xa7, 0x28, 0x23, 0x8a, 0x80, 0x6b,
-	0x10, 0xbc, 0x8d, 0xba, 0xcf, 0x69, 0x39, 0x05, 0xbb, 0xa5, 0xb8, 0x1a,
-	0x72, 0xf7, 0x1f, 0x83, 0x0f, 0xc7, 0x58, 0x9e, 0x69, 0xd4, 0x25, 0x32,
-	0xaa, 0xd2, 0x90, 0x09, 0xdd, 0x94, 0x85, 0x09, 0xc8, 0x41, 0xc8, 0x96,
-	0xd2, 0x4f, 0x83, 0x8c, 0x5b, 0x2d, 0xdf, 0x24, 0x3f, 0x5f, 0x86, 0x69,
-	0x09, 0x23, 0x2f, 0x4b, 0xb3, 0x73, 0xb2, 0x22, 0x0f, 0xf9, 0xf2, 0x74,
-	0x85, 0x72, 0xe1, 0x7a, 0xf0, 0x68, 0xab, 0xf4, 0x15, 0x93, 0xf9, 0x8c,
-	0x6c, 0xc2, 0xfc, 0x7d, 0x1e, 0x73, 0xea, 0xe2, 0xb9, 0xaf, 0x5e, 0x1a,
-	0x53, 0xd0, 0xcd, 0x4c, 0x47, 0xa3, 0xcd, 0x51, 0xc8, 0xa8, 0xdf, 0x03,
-	0x1e, 0x86, 0x39, 0xe7, 0xf1, 0x6c, 0xc4, 0x19, 0xa0, 0x3d, 0x32, 0x40,
-	0xfd, 0x50, 0x66, 0xdb, 0x84, 0x37, 0x6e, 0x7f, 0x47, 0xb5, 0x8c, 0x31,
-	0xbf, 0x1b, 0xf0, 0x3b, 0x61, 0x7f, 0x7b, 0xf8, 0xed, 0xdb, 0xdf, 0x31,
-	0xfc, 0xee, 0xb4, 0xbf, 0xa1, 0x5b, 0x8b, 0x5d, 0xfa, 0xf7, 0x48, 0x69,
-	0xfb, 0x76, 0xe5, 0x5f, 0x27, 0xb9, 0xa9, 0x56, 0x39, 0x50, 0xf4, 0xad,
-	0x6c, 0xc1, 0x23, 0x4f, 0x3a, 0x66, 0x9c, 0x80, 0x9b, 0xb2, 0xb3, 0x94,
-	0x77, 0x06, 0x08, 0x3f, 0x68, 0xa0, 0xb7, 0xb8, 0xc5, 0x5b, 0x23, 0xa4,
-	0x81, 0x11, 0xa7, 0xb7, 0xe2, 0x64, 0x60, 0xaf, 0xc5, 0x87, 0xe5, 0x30,
-	0x7e, 0x8b, 0x17, 0x49, 0x3f, 0x89, 0xb7, 0xc1, 0x01, 0xf5, 0xce, 0x70,
-	0x89, 0xf2, 0xd2, 0xc7, 0xd8, 0x13, 0x72, 0x6e, 0x81, 0x0d, 0x45, 0x5c,
-	0x28, 0xc9, 0x8d, 0x25, 0x4f, 0xe4, 0x25, 0x99, 0x1f, 0x07, 0x43, 0xec,
-	0x4a, 0xb9, 0xf2, 0xde, 0x14, 0x68, 0xf7, 0x3a, 0x47, 0xb6, 0x5f, 0xe7,
-	0xc2, 0xe6, 0xf1, 0xc7, 0xb7, 0x83, 0xfe, 0x31, 0xcf, 0x9a, 0x1e, 0xd4,
-	0x19, 0x81, 0x9d, 0x08, 0x6c, 0x9f, 0xe9, 0xea, 0x1b, 0x2e, 0xe6, 0x3e,
-	0xa6, 0xd2, 0xfb, 0x3e, 0x95, 0xed, 0xbe, 0x46, 0x72, 0x83, 0x0a, 0x38,
-	0x6a, 0x1e, 0x82, 0x1e, 0xc4, 0xb8, 0x82, 0x00, 0xf4, 0x0c, 0x79, 0x7e,
-	0xf3, 0xcd, 0x91, 0x74, 0x8d, 0xf4, 0x0e, 0x36, 0xa3, 0x0e, 0xf3, 0x88,
-	0xaf, 0xaf, 0xa2, 0x9d, 0x64, 0xa2, 0x4f, 0xe4, 0x9e, 0x91, 0xee, 0x59,
-	0x67, 0x78, 0xf4, 0x37, 0xc0, 0x93, 0x5b, 0x51, 0xff, 0x01, 0xd4, 0x7f,
-	0xcd, 0x29, 0x8c, 0xfd, 0xc8, 0x19, 0x1e, 0xfb, 0x9e, 0x33, 0x32, 0xb6,
-	0x61, 0x43, 0x7f, 0xcf, 0x86, 0x0d, 0xbb, 0x7b, 0x5c, 0x99, 0x00, 0x8f,
-	0x65, 0xbc, 0x0d, 0x1b, 0x46, 0x7a, 0xba, 0x80, 0x83, 0x2d, 0x5e, 0x9f,
-	0xf8, 0xde, 0x76, 0x01, 0xff, 0xc4, 0xd8, 0x67, 0x14, 0xf9, 0x49, 0xe4,
-	0xb3, 0x7e, 0x5c, 0xe7, 0xf7, 0xca, 0x96, 0x78, 0x93, 0xb0, 0xff, 0x88,
-	0x2d, 0x53, 0x13, 0x91, 0xfa, 0x07, 0xec, 0xfc, 0x66, 0x9c, 0x1a, 0x9f,
-	0xe9, 0x1c, 0x0b, 0xd3, 0x39, 0xb7, 0x7f, 0x67, 0x6d, 0xd5, 0xd5, 0x48,
-	0xe7, 0x37, 0x71, 0x46, 0xbc, 0xd0, 0xc6, 0xa8, 0xd1, 0xb6, 0x61, 0xae,
-	0x48, 0x9a, 0x71, 0x65, 0x4f, 0xd1, 0x41, 0x1d, 0xd0, 0xc5, 0x19, 0xfb,
-	0x1c, 0x05, 0x6c, 0x83, 0x68, 0xeb, 0xe8, 0x21, 0xd4, 0xa3, 0xcc, 0x48,
-	0x76, 0x8a, 0xfa, 0x00, 0xca, 0x6c, 0xf1, 0xd6, 0x0a, 0x6d, 0x89, 0x3b,
-	0x25, 0x57, 0x22, 0x7f, 0x77, 0x00, 0x9e, 0xa8, 0x24, 0x9a, 0xf1, 0x5d,
-	0x81, 0x4d, 0xf1, 0x60, 0x8d, 0x58, 0xdb, 0x45, 0xe6, 0x6d, 0x91, 0x3b,
-	0x94, 0xc0, 0xde, 0x18, 0x9a, 0x5c, 0x8f, 0x72, 0x0e, 0xf0, 0x42, 0xfb,
-	0x03, 0xb4, 0x36, 0x99, 0x91, 0xec, 0x26, 0xf0, 0xc9, 0xa4, 0x87, 0x6f,
-	0xc0, 0x35, 0xf9, 0x16, 0xbc, 0x23, 0xfa, 0xdb, 0xc0, 0x09, 0xbc, 0xa6,
-	0x22, 0x56, 0x67, 0x75, 0xa1, 0xef, 0xf7, 0x48, 0x76, 0x34, 0x4e, 0x5b,
-	0x62, 0x75, 0xd6, 0xcf, 0x40, 0xd7, 0x2b, 0x28, 0x41, 0x8c, 0x61, 0xd2,
-	0x81, 0x3c, 0xa9, 0x95, 0xdd, 0x8f, 0xe0, 0xf7, 0x83, 0xc6, 0xe6, 0xdd,
-	0x3d, 0xc9, 0x7e, 0x1a, 0x00, 0x13, 0x6c, 0x90, 0x47, 0x60, 0x9b, 0x3e,
-	0x02, 0x1b, 0xe4, 0x91, 0x66, 0x3c, 0x1c, 0x1b, 0xdb, 0x9f, 0x59, 0x03,
-	0x31, 0xa9, 0xbf, 0x73, 0xa4, 0x57, 0xd8, 0xea, 0xb9, 0x62, 0xca, 0x94,
-	0x2f, 0x76, 0xeb, 0xb7, 0xa1, 0xeb, 0x1e, 0xfb, 0x3b, 0xae, 0xf9, 0x3a,
-	0xdf, 0x04, 0x9a, 0xaf, 0x74, 0x69, 0x99, 0x93, 0xf5, 0xf1, 0x86, 0xcd,
-	0x99, 0x69, 0xe2, 0x18, 0xe3, 0x36, 0x2d, 0xae, 0xd3, 0x12, 0x4d, 0xd6,
-	0xde, 0x28, 0x59, 0x5b, 0x03, 0xb8, 0x19, 0x6a, 0x06, 0xc4, 0x94, 0xcf,
-	0x12, 0xe2, 0x93, 0x32, 0x00, 0xf4, 0x0b, 0x9b, 0xe2, 0xdc, 0x15, 0xe5,
-	0xdf, 0xac, 0xb6, 0xb1, 0xce, 0x56, 0x48, 0xc7, 0xa4, 0xed, 0x20, 0xb8,
-	0x3f, 0x55, 0x87, 0xf6, 0xc9, 0xf3, 0xb0, 0x40, 0x8e, 0x02, 0x26, 0x60,
-	0xa2, 0xc6, 0x3f, 0xab, 0x69, 0xa0, 0xd6, 0x27, 0x0d, 0x57, 0xf3, 0x97,
-	0xe8, 0xf1, 0x9e, 0x05, 0x8f, 0xc1, 0xbe, 0x81, 0xfd, 0xd6, 0x01, 0xdb,
-	0x98, 0x7d, 0x1c, 0xe6, 0xb7, 0xa7, 0xc0, 0x53, 0xd9, 0x39, 0x9e, 0x12,
-	0x99, 0x28, 0x12, 0x37, 0xa1, 0x5d, 0xc7, 0x79, 0x26, 0x7e, 0x32, 0x18,
-	0x33, 0xdf, 0x7d, 0x16, 0x4f, 0x3b, 0x2d, 0x9e, 0x6e, 0xb2, 0xef, 0x11,
-	0xbc, 0x69, 0xe3, 0x0d, 0xe0, 0xcd, 0xf9, 0x19, 0xc4, 0x9b, 0xbc, 0x75,
-	0x0b, 0xde, 0x28, 0x5b, 0xca, 0xc8, 0x6e, 0x6d, 0x87, 0x45, 0xe4, 0x57,
-	0xb4, 0x6c, 0xfb, 0x02, 0xe6, 0xb2, 0x48, 0xfa, 0x95, 0x7c, 0x2c, 0x02,
-	0x9c, 0x14, 0xf0, 0xfb, 0x4e, 0xd7, 0xd0, 0x2a, 0x71, 0xb2, 0xc0, 0x57,
-	0xaa, 0x82, 0x29, 0x66, 0xe5, 0x5c, 0x42, 0xdb, 0xfa, 0xb9, 0xe2, 0x07,
-	0x34, 0x5c, 0xb7, 0x42, 0xde, 0xe5, 0x45, 0x35, 0x43, 0x37, 0x80, 0x16,
-	0x54, 0x0c, 0x9a, 0x2b, 0x78, 0x06, 0x7a, 0x29, 0x37, 0x49, 0xdb, 0xb8,
-	0x8d, 0x7e, 0x49, 0x34, 0xd7, 0xd5, 0x48, 0x3a, 0x52, 0x0a, 0xf6, 0x17,
-	0xbe, 0x55, 0xae, 0x4b, 0xd3, 0xa9, 0xa3, 0xfc, 0x98, 0xb6, 0x7f, 0x5d,
-	0x1f, 0xd2, 0xd6, 0xf8, 0xbd, 0xae, 0xf2, 0xd7, 0x2e, 0x4e, 0x4b, 0x50,
-	0x0f, 0xa3, 0x5e, 0x22, 0xd7, 0xd5, 0x4c, 0x1e, 0xf3, 0x40, 0xbf, 0x19,
-	0xe5, 0x6b, 0xdf, 0x27, 0xaf, 0xba, 0x57, 0x2f, 0x2a, 0xaf, 0xdf, 0x8e,
-	0xfd, 0x76, 0xed, 0xdb, 0xb3, 0xef, 0x84, 0x7d, 0xe7, 0xdd, 0x6e, 0xbe,
-	0x1d, 0x71, 0xd3, 0x7c, 0x83, 0x92, 0xd3, 0x6c, 0x43, 0xf3, 0x95, 0x95,
-	0x33, 0x1d, 0x5e, 0x41, 0xc8, 0x57, 0x9f, 0x93, 0x5b, 0x27, 0x8d, 0xfc,
-	0xdd, 0x0e, 0x19, 0x04, 0xff, 0xcc, 0x9b, 0x11, 0xc0, 0x3f, 0x98, 0x96,
-	0x5b, 0x2b, 0xc4, 0xdb, 0xef, 0x02, 0x7f, 0x60, 0xe2, 0x7a, 0xea, 0x74,
-	0xca, 0xdd, 0x3b, 0x61, 0xf7, 0xa2, 0x7c, 0x91, 0x38, 0x1f, 0xd2, 0x73,
-	0x53, 0x28, 0xee, 0xd1, 0x73, 0x73, 0xb0, 0x38, 0x03, 0xfc, 0xdc, 0x06,
-	0xba, 0x0f, 0x82, 0x99, 0x54, 0x01, 0x94, 0xf3, 0x11, 0xfc, 0x86, 0x1d,
-	0x50, 0xfc, 0x18, 0xf2, 0x1b, 0xa5, 0x30, 0x4a, 0x9e, 0x73, 0x2d, 0x0f,
-	0xbf, 0x13, 0xfc, 0x14, 0x45, 0xbb, 0x48, 0xeb, 0xe6, 0xef, 0x9f, 0x20,
-	0x0f, 0xef, 0x49, 0x4c, 0x62, 0x33, 0x6d, 0x1d, 0xf6, 0xcd, 0xb9, 0xe3,
-	0x9c, 0xc5, 0xb4, 0x2c, 0x3f, 0x3b, 0x37, 0x6f, 0x97, 0xe7, 0xe8, 0x36,
-	0x4f, 0x1f, 0x8f, 0xf9, 0x1a, 0x56, 0xd2, 0xfd, 0xb7, 0xb4, 0x5c, 0x72,
-	0x8f, 0xce, 0xac, 0x30, 0xef, 0xc5, 0x75, 0x39, 0xe7, 0xd5, 0x34, 0x48,
-	0xbf, 0x25, 0xd9, 0x93, 0x07, 0x3f, 0x61, 0x9c, 0xd2, 0xa7, 0x7d, 0x1d,
-	0xd2, 0x04, 0x69, 0x60, 0xdc, 0xd2, 0xe6, 0x94, 0xa5, 0xcd, 0x27, 0xf1,
-	0xc6, 0x53, 0xba, 0x60, 0x69, 0xf3, 0x29, 0xbc, 0xf1, 0x94, 0x5e, 0x9c,
-	0xe3, 0xe3, 0x5e, 0xf8, 0x72, 0xdb, 0xa1, 0xdf, 0x76, 0x57, 0x40, 0xbf,
-	0xe0, 0xbb, 0x1c, 0x7c, 0x80, 0x5c, 0x69, 0x1f, 0xde, 0xec, 0x67, 0xa3,
-	0x6d, 0x3f, 0x23, 0x7b, 0x4a, 0x01, 0xc6, 0x78, 0x37, 0xc6, 0xfb, 0x39,
-	0xbc, 0x3f, 0xa3, 0xe5, 0x8c, 0xf2, 0x0f, 0x5b, 0x79, 0xf5, 0x79, 0xbc,
-	0xdb, 0xe3, 0x07, 0xa5, 0xdd, 0x8b, 0xc8, 0x34, 0xda, 0xfa, 0xba, 0xec,
-	0xa9, 0xcc, 0xe2, 0xb9, 0x84, 0xe7, 0x55, 0x3c, 0x97, 0xd1, 0xde, 0x0b,
-	0x48, 0x5f, 0x29, 0xd3, 0x5e, 0x3d, 0xca, 0xbf, 0x86, 0xdf, 0xcf, 0xcb,
-	0xd0, 0x23, 0x2f, 0xe1, 0xf9, 0x01, 0xf2, 0x9f, 0x45, 0xfd, 0x60, 0xf5,
-	0x8c, 0x4f, 0x19, 0xf6, 0x9c, 0x6d, 0x3b, 0xe5, 0xe4, 0x2a, 0xa0, 0xe9,
-	0xd2, 0x00, 0xfa, 0xde, 0xa3, 0x79, 0xa6, 0x0f, 0x32, 0x3f, 0x07, 0x19,
-	0x37, 0xa4, 0x61, 0x6a, 0x07, 0x7c, 0x79, 0xcc, 0x05, 0xde, 0x93, 0xb5,
-	0x32, 0x1b, 0xa3, 0x1d, 0x79, 0x93, 0x2e, 0x9f, 0x2b, 0x35, 0x69, 0xbb,
-	0x7a, 0x7c, 0x09, 0xff, 0xd0, 0xef, 0x0a, 0xe5, 0x81, 0x91, 0xc6, 0x13,
-	0x45, 0xca, 0x02, 0xe8, 0x9f, 0xe2, 0x08, 0xde, 0xb5, 0x5a, 0x26, 0x14,
-	0x24, 0x94, 0x07, 0xac, 0x47, 0x99, 0x50, 0x2d, 0x77, 0x28, 0x6b, 0x28,
-	0x7b, 0x28, 0x4b, 0xcc, 0x7c, 0xec, 0x7e, 0x90, 0x32, 0x1c, 0xb4, 0x10,
-	0xa3, 0xfd, 0xe1, 0x19, 0x1f, 0x64, 0xec, 0x3e, 0x2b, 0x4f, 0x47, 0xf5,
-	0x5c, 0xec, 0x29, 0xaa, 0x98, 0x2b, 0xa7, 0x91, 0x86, 0xe7, 0xf8, 0xc3,
-	0x78, 0x7f, 0x49, 0xf6, 0xe0, 0xc9, 0x1d, 0xff, 0x02, 0x7e, 0x73, 0x6e,
-	0xca, 0x28, 0x87, 0xa7, 0x74, 0x02, 0x6f, 0x3c, 0xa5, 0x31, 0x2b, 0x47,
-	0xc6, 0xad, 0x1c, 0xe1, 0x9c, 0xde, 0x04, 0x3c, 0x70, 0x7c, 0x4a, 0xc7,
-	0x17, 0xc0, 0xcf, 0x4e, 0x6e, 0xf2, 0x5d, 0xd6, 0x8f, 0x6d, 0x14, 0xc3,
-	0x83, 0x78, 0x3a, 0xc9, 0xcf, 0x0d, 0xda, 0x0e, 0xce, 0x69, 0xda, 0xfd,
-	0x2b, 0xd7, 0xf0, 0x62, 0xcc, 0xe8, 0x14, 0xaf, 0x59, 0x34, 0xef, 0xcf,
-	0xe1, 0x31, 0x63, 0xf1, 0xc8, 0xdf, 0xca, 0xfe, 0x86, 0xdc, 0x82, 0x4d,
-	0x9b, 0xf5, 0x7d, 0xcc, 0x03, 0xc6, 0x72, 0x7c, 0x14, 0x7d, 0x3b, 0xb2,
-	0xdb, 0xa7, 0x0c, 0x67, 0x0c, 0x81, 0xe3, 0x63, 0xbb, 0x48, 0xd7, 0x38,
-	0x48, 0xc9, 0xbc, 0x6f, 0x7e, 0x13, 0xe6, 0x2c, 0x23, 0x7b, 0x4b, 0xf7,
-	0x6a, 0x5f, 0xb9, 0xf6, 0x68, 0x93, 0xf5, 0x73, 0xc2, 0x72, 0xa0, 0xd5,
-	0x18, 0x6d, 0x9b, 0x2f, 0xc5, 0x0c, 0xcd, 0xf3, 0x37, 0xe5, 0x73, 0xb5,
-	0xbc, 0x37, 0x76, 0x4d, 0x61, 0x81, 0xac, 0xa3, 0x6d, 0x81, 0x39, 0x2b,
-	0x57, 0xe3, 0x9d, 0xbe, 0x3b, 0xf9, 0x8a, 0xfc, 0x74, 0x10, 0x3c, 0xf1,
-	0x5d, 0xcb, 0xfb, 0xf4, 0x35, 0xd8, 0xe7, 0x62, 0x7e, 0xf2, 0x60, 0xfb,
-	0xba, 0x72, 0x0a, 0xb6, 0xdb, 0xf6, 0xb9, 0x36, 0xae, 0x06, 0x3c, 0x51,
-	0x79, 0xa4, 0xd8, 0x20, 0x93, 0x45, 0xd5, 0x1c, 0xb1, 0xb2, 0x33, 0x22,
-	0x09, 0x4d, 0xdf, 0xb4, 0xef, 0x7a, 0xc7, 0x22, 0x96, 0xee, 0xd6, 0xd5,
-	0x48, 0xfd, 0xef, 0x42, 0xc7, 0xa6, 0xa1, 0x63, 0x1b, 0xa1, 0x83, 0x17,
-	0xcb, 0x88, 0x35, 0x35, 0x4b, 0x65, 0x04, 0xeb, 0x24, 0xe1, 0x75, 0x1f,
-	0x44, 0xbd, 0x90, 0xfe, 0xa2, 0x9a, 0xd6, 0x72, 0x92, 0x77, 0xb6, 0x57,
-	0x46, 0x9c, 0x1d, 0x95, 0xc5, 0x3a, 0x68, 0x8b, 0xe7, 0x8a, 0x81, 0xf5,
-	0x91, 0x22, 0x6d, 0xd4, 0x64, 0x2a, 0x0b, 0x9c, 0xec, 0x00, 0xcc, 0xcf,
-	0x8c, 0xc2, 0x4f, 0xa7, 0x5c, 0x06, 0xcc, 0xa7, 0x01, 0xf3, 0xc4, 0xa8,
-	0x13, 0xda, 0x06, 0xc2, 0xa0, 0xc8, 0xc4, 0x58, 0x97, 0xcc, 0x4c, 0x91,
-	0x0e, 0x21, 0x03, 0x46, 0x31, 0x9f, 0xa9, 0x15, 0xb0, 0x03, 0xd8, 0x3f,
-	0xe4, 0xf6, 0x58, 0x8b, 0xce, 0x33, 0xfa, 0xbc, 0x55, 0x66, 0xca, 0x69,
-	0x0b, 0xdb, 0xe1, 0x2a, 0xd8, 0x56, 0xcc, 0xc1, 0xb6, 0x03, 0xb0, 0xed,
-	0x5c, 0x16, 0xb6, 0xe5, 0x74, 0x71, 0x1b, 0x6c, 0x1a, 0xa3, 0x8b, 0x0d,
-	0x5e, 0x9b, 0x2d, 0x3d, 0xbc, 0xdf, 0xda, 0xbb, 0xb4, 0x89, 0x7e, 0x0a,
-	0x78, 0x48, 0x63, 0xf8, 0x3d, 0x79, 0x2f, 0x65, 0x19, 0xd2, 0xf9, 0xbd,
-	0x07, 0x65, 0xf0, 0x3d, 0xf9, 0x67, 0x2b, 0x4c, 0xd9, 0xbb, 0x2d, 0x2c,
-	0xb4, 0x13, 0x32, 0xb0, 0x89, 0xfb, 0x9c, 0xec, 0x24, 0x61, 0xf8, 0x8f,
-	0x80, 0x17, 0x79, 0x95, 0xea, 0x36, 0xf9, 0x66, 0xbb, 0xd7, 0xda, 0x76,
-	0xd8, 0x76, 0x38, 0x96, 0x95, 0x56, 0xcf, 0x87, 0xf4, 0x15, 0xda, 0xd7,
-	0x23, 0x4e, 0x66, 0xc9, 0xb8, 0xaa, 0x69, 0x8e, 0xf2, 0xd6, 0x95, 0x7e,
-	0xd0, 0x49, 0xff, 0x02, 0x5a, 0x33, 0x72, 0xc3, 0xd0, 0xf1, 0x0a, 0x3b,
-	0xbe, 0x1a, 0xc3, 0x37, 0xa9, 0x28, 0xf4, 0x21, 0xe5, 0xcd, 0x0e, 0xe3,
-	0x9b, 0xcb, 0x43, 0x80, 0x35, 0xfc, 0x3e, 0xa8, 0x6d, 0xce, 0xa7, 0x4b,
-	0x94, 0x49, 0xf3, 0xb4, 0x68, 0x7c, 0x97, 0x56, 0xf4, 0x55, 0x6d, 0xaf,
-	0xbb, 0x32, 0x60, 0xe6, 0xfc, 0x30, 0xe7, 0x9c, 0xbe, 0x48, 0xfb, 0x03,
-	0x03, 0x96, 0xbf, 0x92, 0xa3, 0x79, 0x79, 0xbb, 0x1d, 0xfb, 0x1f, 0x2e,
-	0x33, 0x77, 0x8d, 0x73, 0x73, 0x37, 0x50, 0x59, 0x3c, 0x46, 0x91, 0xb6,
-	0x07, 0x58, 0xcf, 0x85, 0x8d, 0x94, 0x92, 0x5a, 0x9f, 0xf2, 0x93, 0xb6,
-	0x12, 0xd2, 0x27, 0xb6, 0x78, 0x4d, 0xf0, 0x01, 0x9e, 0x5e, 0x62, 0x77,
-	0x25, 0xac, 0xdc, 0xa4, 0x1f, 0x1c, 0xf6, 0x91, 0xb7, 0x72, 0x32, 0x8f,
-	0xf6, 0x47, 0x9c, 0xfe, 0xca, 0x72, 0xf2, 0x32, 0x94, 0x93, 0x1c, 0x8f,
-	0x23, 0x77, 0x3c, 0x48, 0x1e, 0x7d, 0xbf, 0xb6, 0xaf, 0xb7, 0x6e, 0xab,
-	0x01, 0xfe, 0x08, 0xc7, 0xcc, 0x1a, 0xa2, 0x33, 0xf7, 0x08, 0x6c, 0x22,
-	0x3b, 0x6f, 0xbb, 0xe7, 0xe6, 0x5f, 0xd3, 0x05, 0x7e, 0x33, 0x8e, 0x6a,
-	0x68, 0xa4, 0xc6, 0x77, 0x34, 0x2d, 0xd4, 0x2e, 0xb1, 0x65, 0x39, 0x06,
-	0xda, 0xb3, 0xb5, 0xc6, 0x16, 0x2c, 0xd1, 0xfe, 0xa4, 0xec, 0xa2, 0xfd,
-	0xf9, 0x43, 0xe0, 0x88, 0xe3, 0xe9, 0xb2, 0x69, 0xb4, 0x53, 0x17, 0x8f,
-	0x6f, 0xb1, 0xff, 0x48, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x84, 0x22, 0x6c,
-	0x81, 0x0c, 0x80, 0x97, 0x39, 0x07, 0x8a, 0xb6, 0xeb, 0xb6, 0xbf, 0xa8,
-	0x31, 0x31, 0xe4, 0xd5, 0xb5, 0x52, 0xcf, 0x3e, 0xc9, 0x7f, 0x7c, 0xaf,
-	0xd2, 0xf6, 0xef, 0x52, 0x59, 0x56, 0xad, 0x7b, 0xae, 0x9e, 0xc3, 0x5f,
-	0xff, 0x82, 0x39, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x35, 0x0e, 0x49, 0x13,
-	0x86, 0x16, 0x0c, 0x2d, 0x6e, 0xb4, 0xfa, 0x26, 0xa4, 0xbd, 0xab, 0x40,
-	0x7b, 0xf7, 0x81, 0xc6, 0x28, 0xc3, 0x19, 0x97, 0x5b, 0x8b, 0xef, 0x23,
-	0xf8, 0x0e, 0xf9, 0xe4, 0x4a, 0x32, 0x9c, 0xf2, 0x9b, 0x75, 0xb2, 0x56,
-	0xee, 0x87, 0x7e, 0x2e, 0xeb, 0x70, 0xdc, 0x94, 0xff, 0xff, 0x15, 0xed,
-	0xac, 0xad, 0x35, 0xf6, 0xca, 0x8d, 0xb5, 0x94, 0xaf, 0x6b, 0xe4, 0x60,
-	0x55, 0xda, 0x95, 0xe4, 0x77, 0xf5, 0x98, 0xd7, 0xff, 0x3f, 0x18, 0x73,
-	0x7c, 0xd1, 0x98, 0x3d, 0x3b, 0xe6, 0x77, 0x21, 0xbf, 0xc9, 0xf8, 0x38,
-	0x1e, 0xf9, 0x2e, 0x1c, 0xb3, 0xc5, 0x85, 0x1e, 0x57, 0xb5, 0x9c, 0x08,
-	0x65, 0x04, 0xc7, 0x35, 0x60, 0xc7, 0xf0, 0xb9, 0xaa, 0x71, 0x0d, 0xbc,
-	0x89, 0x71, 0xb5, 0x2e, 0x18, 0xd7, 0xf6, 0x2b, 0x8e, 0x6b, 0x39, 0x1e,
-	0x27, 0x2f, 0x87, 0xe3, 0x8b, 0xca, 0xae, 0x22, 0xc7, 0xd8, 0x8f, 0x31,
-	0x1e, 0xd4, 0xfe, 0x80, 0x19, 0x63, 0xda, 0x8e, 0x51, 0x54, 0xdb, 0xb6,
-	0x7f, 0x8f, 0xdf, 0xd5, 0xe3, 0xa3, 0xee, 0xff, 0x3e, 0x68, 0xba, 0x4e,
-	0xb2, 0x5d, 0x75, 0x56, 0xfe, 0xdf, 0x24, 0x1f, 0x2e, 0x71, 0xae, 0x93,
-	0x19, 0x91, 0x51, 0xe8, 0xe0, 0xff, 0x5c, 0xcb, 0xd8, 0xfd, 0xf6, 0x94,
-	0xd5, 0x63, 0xd0, 0x17, 0x3b, 0x60, 0xf3, 0xf5, 0x17, 0x55, 0x77, 0x44,
-	0x82, 0xe0, 0xb6, 0xd4, 0xa7, 0xd1, 0xf7, 0x7e, 0xed, 0xab, 0x2e, 0x8d,
-	0x9b, 0x3f, 0x57, 0x2b, 0x3e, 0xed, 0x0d, 0xea, 0x73, 0xe8, 0xbb, 0xe3,
-	0xb4, 0xc1, 0xb2, 0xb0, 0x93, 0x33, 0xf1, 0x88, 0xb6, 0xc5, 0xa8, 0x13,
-	0x93, 0xf1, 0x8c, 0xa4, 0xd1, 0x5f, 0x26, 0xae, 0x84, 0x7d, 0xc0, 0x56,
-	0x83, 0x0d, 0xf9, 0xe1, 0xca, 0x3e, 0x3c, 0x0f, 0xcb, 0xad, 0xb0, 0x77,
-	0x6e, 0x7d, 0xe4, 0x0b, 0x72, 0x1b, 0x6c, 0x9d, 0xdb, 0x1e, 0x19, 0x93,
-	0xbd, 0xb0, 0x6d, 0xf6, 0xc2, 0xce, 0xd9, 0x5b, 0xa1, 0xed, 0x39, 0x8e,
-	0xb2, 0xad, 0x55, 0xb4, 0x46, 0x1b, 0x87, 0xe3, 0x23, 0xee, 0x0f, 0x72,
-	0x0e, 0x52, 0x09, 0xf5, 0x8a, 0x9e, 0x97, 0xa6, 0x05, 0x69, 0xaf, 0x27,
-	0xab, 0x42, 0xfd, 0xb4, 0xca, 0xc6, 0x8d, 0x8c, 0x0d, 0x78, 0x65, 0xda,
-	0x22, 0x8d, 0x78, 0xc0, 0x33, 0xf1, 0x47, 0xda, 0xaa, 0x1e, 0x7f, 0x63,
-	0x9d, 0xf8, 0x2b, 0xeb, 0xa4, 0xfe, 0x73, 0x90, 0xaf, 0xd5, 0x34, 0xc5,
-	0xb7, 0x67, 0x75, 0x0d, 0x69, 0x8b, 0x32, 0x38, 0xa4, 0x87, 0x8d, 0xaf,
-	0x23, 0x7f, 0xaf, 0x48, 0x4f, 0xfb, 0xb9, 0x2e, 0xb3, 0xbb, 0x5b, 0x56,
-	0x33, 0x1e, 0x90, 0xad, 0xcc, 0xc7, 0x04, 0x94, 0x5f, 0x1d, 0x13, 0xa0,
-	0x9f, 0xf5, 0x01, 0xe0, 0xec, 0x16, 0x3c, 0xfb, 0x64, 0x88, 0x71, 0x87,
-	0x4a, 0x68, 0x97, 0x7f, 0xd5, 0xda, 0xe5, 0x21, 0x1c, 0x09, 0xc0, 0x61,
-	0xe4, 0xf3, 0x52, 0x3d, 0xb7, 0x50, 0x7f, 0xe7, 0xe7, 0x6c, 0xda, 0x84,
-	0xec, 0x2a, 0x71, 0xdc, 0x94, 0xc1, 0xc4, 0x4d, 0xb5, 0x0c, 0x8e, 0x5b,
-	0x3b, 0x0a, 0x65, 0xb4, 0xfc, 0x5c, 0x2a, 0x3b, 0x29, 0xf7, 0x18, 0x9f,
-	0x7f, 0x20, 0x45, 0x5a, 0x7f, 0xb7, 0x64, 0xe6, 0xe2, 0xf3, 0x02, 0x7a,
-	0x93, 0x54, 0x24, 0xad, 0xd7, 0xd3, 0xbc, 0x09, 0xd9, 0x21, 0xbd, 0x31,
-	0xc6, 0x3a, 0x19, 0xcf, 0xf3, 0xf3, 0x13, 0xb0, 0x1f, 0x86, 0x4b, 0x0a,
-	0x16, 0x7c, 0xad, 0x0c, 0x79, 0x81, 0x6c, 0x4f, 0x39, 0x3a, 0x76, 0x6c,
-	0x74, 0x6d, 0xa9, 0xce, 0xd8, 0xae, 0x8e, 0x8e, 0xff, 0xce, 0x80, 0xfa,
-	0x66, 0xb4, 0x7d, 0xab, 0xb4, 0xfe, 0x9d, 0xd6, 0x65, 0x46, 0xeb, 0xc2,
-	0x38, 0xe6, 0x8c, 0x17, 0xb1, 0xe5, 0xaa, 0xd3, 0xa7, 0xea, 0x42, 0x5b,
-	0xb0, 0x50, 0x09, 0xd3, 0x9e, 0x5c, 0x26, 0xed, 0x85, 0x65, 0xd2, 0xfe,
-	0x76, 0x99, 0x34, 0x13, 0x17, 0xec, 0x2f, 0x5e, 0x46, 0xde, 0x88, 0xe6,
-	0x55, 0x69, 0x36, 0xf6, 0x75, 0x7e, 0xae, 0xcc, 0x2a, 0xeb, 0x97, 0x31,
-	0x46, 0x6c, 0x62, 0xc3, 0x39, 0x1d, 0x1b, 0xde, 0xe2, 0x6d, 0x53, 0x8c,
-	0x75, 0x11, 0x17, 0x09, 0xd9, 0xab, 0xf1, 0x42, 0x9c, 0x7c, 0x85, 0x31,
-	0xe0, 0x3c, 0xd7, 0x5a, 0x13, 0xea, 0x4a, 0xb4, 0x3d, 0x6f, 0x9b, 0x98,
-	0x79, 0x8b, 0xe9, 0x75, 0xd5, 0x3e, 0xd8, 0x0a, 0xfd, 0xc5, 0x26, 0xd9,
-	0x3e, 0x96, 0x58, 0x41, 0xbd, 0xb5, 0x63, 0xcc, 0xf8, 0x83, 0x7b, 0xc1,
-	0x57, 0x19, 0x21, 0x8c, 0xc9, 0x94, 0x08, 0x6d, 0xe2, 0xa5, 0xb6, 0xf0,
-	0xeb, 0xb7, 0xd7, 0x7b, 0x85, 0xf6, 0x1c, 0xd8, 0x0e, 0x3f, 0x6b, 0x7b,
-	0xf5, 0xd2, 0x37, 0x16, 0xe2, 0x4a, 0xfd, 0x9c, 0xf5, 0x22, 0x57, 0xa8,
-	0xa7, 0xed, 0x12, 0x79, 0x66, 0x4e, 0x16, 0x6f, 0x84, 0xcd, 0x24, 0x41,
-	0xb6, 0x5b, 0x5a, 0x23, 0xa2, 0x63, 0x3c, 0x29, 0x23, 0x9b, 0x3b, 0xb8,
-	0xb6, 0x03, 0xfa, 0x37, 0xb6, 0x8a, 0x89, 0x9b, 0x86, 0x76, 0xca, 0x72,
-	0xb4, 0x7b, 0xbd, 0xa5, 0x5d, 0xae, 0xa9, 0xee, 0xa0, 0xcc, 0xc5, 0x9c,
-	0x18, 0x3a, 0xde, 0x5e, 0x94, 0x44, 0x48, 0xc7, 0x33, 0xf0, 0x8b, 0xab,
-	0xe9, 0x78, 0x46, 0x52, 0x9a, 0x8e, 0x6b, 0x17, 0xd0, 0x71, 0xab, 0xa5,
-	0xe3, 0x77, 0x44, 0x0d, 0x5d, 0x28, 0xad, 0xa7, 0x48, 0xa7, 0x86, 0x8e,
-	0x1d, 0x4d, 0xc7, 0x33, 0x78, 0xbb, 0x7e, 0x8f, 0x2d, 0x13, 0xb1, 0x69,
-	0xfc, 0x1d, 0xa6, 0x51, 0x2e, 0xfe, 0x66, 0xd4, 0xe8, 0xa5, 0x14, 0xe8,
-	0x28, 0x4c, 0xff, 0x60, 0xd4, 0xd0, 0x67, 0x75, 0x9a, 0x89, 0x8f, 0xf4,
-	0x17, 0xdf, 0x13, 0x5d, 0x48, 0x9f, 0x29, 0xd0, 0x67, 0x58, 0xe6, 0xf5,
-	0xe8, 0xb3, 0xde, 0xae, 0x5b, 0x44, 0xf5, 0xba, 0x7b, 0x26, 0x66, 0x68,
-	0xf5, 0x56, 0x3d, 0x76, 0x8e, 0xfb, 0xd9, 0x9f, 0x81, 0x56, 0xcd, 0xdc,
-	0x9c, 0x9f, 0xf7, 0xb7, 0x19, 0x8b, 0x4a, 0x98, 0x18, 0x36, 0xe3, 0xa4,
-	0x57, 0xb2, 0x1d, 0x8d, 0x7c, 0xaa, 0xd1, 0xf2, 0xa9, 0x71, 0x48, 0xa5,
-	0xab, 0x65, 0x76, 0x37, 0x74, 0x05, 0x6d, 0x6c, 0x2d, 0xa7, 0x91, 0xd7,
-	0x9a, 0xc8, 0x16, 0xff, 0xd9, 0xee, 0x5f, 0xe0, 0xba, 0x80, 0x0c, 0x39,
-	0x48, 0x6b, 0x2b, 0x9b, 0x71, 0x29, 0xbf, 0x11, 0xdf, 0xdd, 0xd2, 0x56,
-	0x56, 0x72, 0xfb, 0x58, 0x83, 0xec, 0x2b, 0xba, 0xf2, 0x51, 0xd4, 0xff,
-	0x48, 0xd1, 0x83, 0x3f, 0x3e, 0x1e, 0xa5, 0x5d, 0xb8, 0xb7, 0xc8, 0xf5,
-	0x49, 0xc7, 0xac, 0x19, 0x2d, 0x58, 0xf3, 0x8c, 0x48, 0x5b, 0x47, 0x01,
-	0x9e, 0x8a, 0xb8, 0x3b, 0x01, 0x47, 0x5d, 0x3a, 0x2d, 0xaf, 0x74, 0x0f,
-	0x38, 0xda, 0x97, 0x70, 0x7a, 0xe4, 0xc6, 0x4a, 0x5a, 0x6e, 0xa8, 0x98,
-	0x75, 0xd2, 0xf9, 0x75, 0xd0, 0xa4, 0x37, 0x0d, 0x9d, 0x93, 0xf1, 0x82,
-	0xe0, 0x3c, 0xe4, 0xb7, 0x3a, 0xe2, 0x4a, 0xb4, 0x23, 0x19, 0x9f, 0x16,
-	0xf3, 0x7d, 0xb1, 0xfc, 0xe3, 0x60, 0x28, 0xe6, 0xca, 0x2b, 0x3e, 0xc7,
-	0xd5, 0x23, 0xd7, 0x97, 0xab, 0xfb, 0xe3, 0x5a, 0xe9, 0x13, 0x51, 0xae,
-	0x4d, 0x64, 0x2b, 0xe5, 0x28, 0xe3, 0xe7, 0x22, 0x79, 0x69, 0x7b, 0x2b,
-	0x7c, 0x37, 0x48, 0xeb, 0xb6, 0xb7, 0x82, 0x56, 0x62, 0xd0, 0xf3, 0x5b,
-	0x01, 0xd7, 0x56, 0xc6, 0xbb, 0x18, 0xe7, 0xe2, 0xf7, 0x5f, 0xa2, 0x5f,
-	0xd6, 0xfd, 0x5d, 0xbd, 0x66, 0x25, 0x8a, 0x73, 0x6e, 0xf8, 0x65, 0x79,
-	0x5d, 0xd3, 0x38, 0x14, 0x4d, 0x8b, 0x13, 0x7d, 0x5b, 0x5c, 0x56, 0xf8,
-	0xd5, 0xfd, 0x73, 0xed, 0x57, 0x14, 0x70, 0xe8, 0xee, 0xd8, 0xdc, 0x23,
-	0x7d, 0x18, 0x5f, 0xff, 0x92, 0xf1, 0xed, 0x17, 0xc6, 0x54, 0x2f, 0x16,
-	0x39, 0x86, 0xf9, 0x71, 0xa9, 0x3f, 0x32, 0xe3, 0x8a, 0x76, 0x2c, 0x1e,
-	0x8f, 0xae, 0xaf, 0x4e, 0x01, 0x96, 0xe7, 0xf4, 0x1e, 0x81, 0x20, 0xb8,
-	0xa6, 0xe3, 0x62, 0x90, 0x58, 0x97, 0xec, 0x9c, 0x9e, 0x5f, 0xd3, 0x19,
-	0x8a, 0xa4, 0x33, 0x1a, 0xff, 0xf8, 0x4e, 0xe4, 0xca, 0xdd, 0x98, 0x3b,
-	0x71, 0x73, 0x5d, 0xae, 0xe6, 0x8d, 0x9c, 0xdf, 0x6d, 0xd7, 0xad, 0x42,
-	0xbf, 0x29, 0x08, 0x94, 0xbf, 0x58, 0x56, 0x50, 0x47, 0x61, 0xec, 0xb2,
-	0xdb, 0xee, 0x4b, 0x49, 0x31, 0x6e, 0x38, 0xe4, 0xa6, 0xa3, 0x89, 0x42,
-	0xb9, 0x0b, 0xbf, 0x1b, 0xf0, 0xfe, 0x45, 0xd8, 0x28, 0x3d, 0xb0, 0x61,
-	0x24, 0xa6, 0x8c, 0x3c, 0x00, 0xfd, 0x76, 0xe4, 0x95, 0x22, 0x3f, 0x7a,
-	0x89, 0xe1, 0x72, 0x2c, 0x31, 0x5a, 0xde, 0xcb, 0xfa, 0x28, 0x7b, 0xa5,
-	0xf8, 0x1d, 0xfb, 0x62, 0x1f, 0xf4, 0x79, 0x7f, 0x96, 0x3e, 0x5c, 0xdb,
-	0x36, 0xdb, 0x0c, 0xf1, 0xe2, 0xd2, 0x0d, 0xc7, 0xbf, 0x6e, 0xeb, 0x8f,
-	0x70, 0x7c, 0x7b, 0x2d, 0xdc, 0x8b, 0xfb, 0x7d, 0x49, 0xdb, 0x2c, 0x8f,
-	0x55, 0x68, 0x27, 0x72, 0x4d, 0x27, 0x79, 0x62, 0x5c, 0x08, 0x47, 0x10,
-	0x5c, 0x48, 0x19, 0x7d, 0xfd, 0x74, 0x85, 0xeb, 0x1a, 0x41, 0xf0, 0x5d,
-	0xda, 0xc2, 0x83, 0x25, 0xf4, 0x17, 0xe2, 0x60, 0x63, 0xde, 0x85, 0x2c,
-	0x1c, 0xe9, 0x26, 0x7e, 0x05, 0x5e, 0x69, 0x87, 0xb7, 0x4b, 0xa2, 0x89,
-	0xdf, 0x2e, 0x37, 0x24, 0x3e, 0x51, 0xf6, 0x80, 0x67, 0x8e, 0x3b, 0x96,
-	0xd8, 0x63, 0xc7, 0xcc, 0xfd, 0x20, 0xaf, 0xbf, 0x4f, 0xe3, 0xa5, 0x05,
-	0x3e, 0x12, 0x61, 0x9a, 0x87, 0x85, 0xb0, 0x25, 0x2c, 0x6e, 0x82, 0xe0,
-	0xfb, 0x29, 0xf6, 0xd9, 0xcd, 0xfd, 0x00, 0x23, 0xe8, 0x37, 0xbf, 0x56,
-	0x11, 0x0f, 0xd1, 0xc4, 0x1d, 0xe8, 0xfb, 0xb7, 0xd1, 0xf7, 0xbe, 0x32,
-	0xfb, 0x83, 0x7c, 0xc0, 0xd8, 0x47, 0x2a, 0x21, 0xbc, 0xcb, 0xf5, 0x1d,
-	0xce, 0x79, 0xa7, 0xb5, 0xeb, 0xc2, 0x6f, 0x8d, 0x48, 0x4f, 0xc1, 0x97,
-	0xcb, 0x56, 0x66, 0xd6, 0xb8, 0xf2, 0x2e, 0xc8, 0xda, 0x40, 0x4e, 0x42,
-	0x86, 0xcd, 0x68, 0xba, 0xc9, 0xae, 0xe7, 0xff, 0x11, 0xf9, 0xe4, 0x0a,
-	0xc6, 0x94, 0x7b, 0x7d, 0xda, 0xab, 0xb3, 0xc1, 0x8c, 0x4f, 0x99, 0xbc,
-	0x4a, 0xc6, 0xbd, 0x7c, 0x27, 0xf4, 0x03, 0xd2, 0x1a, 0xe9, 0x63, 0x27,
-	0xb2, 0x91, 0x64, 0x62, 0x58, 0xb8, 0xc7, 0x89, 0xfb, 0x13, 0xb8, 0xef,
-	0x87, 0xf2, 0xc0, 0x85, 0x9c, 0xe3, 0x1c, 0x9a, 0xfe, 0x86, 0xcb, 0xf3,
-	0x65, 0x0f, 0x08, 0xd7, 0x09, 0x93, 0xf1, 0xbd, 0xda, 0x26, 0x01, 0xd5,
-	0x15, 0x59, 0x76, 0x33, 0x2c, 0x12, 0xbf, 0xaa, 0xbc, 0xde, 0x73, 0x05,
-	0x3e, 0x67, 0x1c, 0x21, 0x1a, 0xcd, 0x16, 0xe5, 0xb5, 0x48, 0xb7, 0xbc,
-	0x96, 0x4d, 0xd5, 0x4b, 0xaf, 0x96, 0xf9, 0xcc, 0xd3, 0xe9, 0xb3, 0x26,
-	0xdd, 0x85, 0x2e, 0xe1, 0x9c, 0xf4, 0x40, 0x46, 0x4f, 0x00, 0x6e, 0xe2,
-	0xb0, 0x87, 0x32, 0x89, 0xf3, 0xa7, 0x54, 0x3a, 0x16, 0xcd, 0x95, 0xa5,
-	0x2f, 0x57, 0xb4, 0xb1, 0x9e, 0x01, 0x8e, 0x7f, 0x95, 0xc5, 0x43, 0xa3,
-	0xb8, 0x80, 0xad, 0x2f, 0x92, 0x70, 0xe0, 0x2b, 0x43, 0xd7, 0x3f, 0xba,
-	0x4a, 0x1a, 0x89, 0x9b, 0x1e, 0xf0, 0x52, 0x0d, 0x74, 0xd1, 0xfd, 0xcd,
-	0x5c, 0x37, 0xd5, 0x36, 0x64, 0xec, 0x63, 0xbf, 0xac, 0xd2, 0x7f, 0x1b,
-	0x57, 0xe9, 0x51, 0x2b, 0x2f, 0xa3, 0x7d, 0x94, 0x97, 0x4f, 0x97, 0x08,
-	0x8f, 0x78, 0x11, 0x3f, 0xd1, 0xd7, 0x5b, 0x16, 0x15, 0x49, 0x7b, 0xd1,
-	0xde, 0xf2, 0x42, 0xfa, 0x7f, 0xba, 0xf2, 0x61, 0x6b, 0x0b, 0x56, 0xc7,
-	0x54, 0xab, 0xf3, 0xc8, 0x83, 0xcb, 0xe5, 0x11, 0x26, 0x89, 0xae, 0x48,
-	0x5f, 0xf8, 0x54, 0x7b, 0x47, 0xde, 0xab, 0x15, 0xe2, 0x39, 0x80, 0xdc,
-	0x06, 0xae, 0xcb, 0x5c, 0xaf, 0xde, 0x8f, 0x79, 0xfb, 0x3f, 0x41, 0x26,
-	0xc6, 0x7c, 0x4f, 0xea, 0xe0, 0xdb, 0xbe, 0x0c, 0xdd, 0xf9, 0x8a, 0x7f,
-	0xe1, 0x53, 0x9d, 0x1d, 0x41, 0xf0, 0xac, 0x9f, 0x4f, 0xb8, 0x90, 0x1f,
-	0x87, 0x2d, 0xbe, 0x87, 0x81, 0xef, 0x89, 0x39, 0x7c, 0x27, 0xe4, 0x62,
-	0xd7, 0xf7, 0x03, 0xae, 0xf5, 0x0d, 0x97, 0x6f, 0xbd, 0x55, 0xa5, 0x3f,
-	0xfe, 0xa1, 0x6c, 0x37, 0xfb, 0x1b, 0x91, 0xc3, 0x95, 0x9b, 0x88, 0xbf,
-	0x28, 0xc6, 0x7a, 0x4f, 0x9f, 0x6f, 0xfa, 0xed, 0x5b, 0xd0, 0x2f, 0xe9,
-	0xe5, 0x47, 0xac, 0x8b, 0x32, 0xd5, 0x75, 0x33, 0xa0, 0xcb, 0xbc, 0xad,
-	0x3b, 0x70, 0x85, 0xba, 0xde, 0x15, 0xea, 0x1e, 0x46, 0xdd, 0x3d, 0xb6,
-	0xee, 0x85, 0xcf, 0xbc, 0xb9, 0x7e, 0x07, 0xb8, 0xc7, 0x0e, 0x3e, 0x80,
-	0xb8, 0x11, 0xff, 0x36, 0xfc, 0xbe, 0x85, 0xed, 0x28, 0xda, 0xf7, 0x23,
-	0x95, 0x21, 0x19, 0xae, 0xec, 0xc4, 0x33, 0x88, 0xb4, 0x3e, 0x3c, 0xfb,
-	0xf0, 0x3b, 0x8d, 0x47, 0xa2, 0x6e, 0xfa, 0xc2, 0x5d, 0xc3, 0x7e, 0x88,
-	0x57, 0xae, 0xcd, 0xb3, 0x0f, 0xd8, 0x17, 0x5d, 0x3f, 0x41, 0x1f, 0x61,
-	0xfa, 0x07, 0x50, 0x67, 0x1a, 0x69, 0x2b, 0x69, 0x7b, 0x62, 0xae, 0xab,
-	0xeb, 0x54, 0xc3, 0x36, 0x1d, 0xce, 0x05, 0xf2, 0x0d, 0x8d, 0xf6, 0x16,
-	0x43, 0x18, 0xef, 0x44, 0x1b, 0xe3, 0x57, 0x29, 0xff, 0x1e, 0xc2, 0x15,
-	0x57, 0xfe, 0xc7, 0xf0, 0x7e, 0x2d, 0xd8, 0x9d, 0x62, 0x4c, 0x9e, 0xf3,
-	0x7e, 0xdd, 0xaa, 0xa5, 0x7b, 0x9f, 0x42, 0x1a, 0xe8, 0x84, 0x4e, 0x69,
-	0xb0, 0x74, 0x5a, 0x80, 0xe5, 0x43, 0x1a, 0xe5, 0x98, 0x17, 0x97, 0x4d,
-	0x76, 0xe6, 0xa5, 0x07, 0xba, 0x8c, 0xb2, 0xf6, 0xd3, 0xf5, 0x26, 0x0e,
-	0x03, 0xcb, 0xd1, 0xef, 0x04, 0x3d, 0x37, 0x88, 0x87, 0xfa, 0x03, 0x11,
-	0x0f, 0x34, 0x18, 0xd6, 0x4f, 0x7a, 0x03, 0x11, 0x8e, 0x19, 0x1c, 0x5f,
-	0xe6, 0xba, 0x34, 0x6d, 0x6b, 0xd6, 0x0f, 0x6d, 0x1c, 0xfe, 0x7b, 0x59,
-	0xc4, 0x67, 0x1a, 0xdb, 0x0b, 0xde, 0x55, 0xe3, 0x2f, 0x59, 0x63, 0xc1,
-	0x38, 0xf3, 0x49, 0x68, 0x30, 0xaf, 0x4f, 0xcb, 0xe9, 0xfc, 0x35, 0x35,
-	0xd2, 0xe0, 0xf5, 0xeb, 0xdf, 0x2c, 0xd3, 0xe0, 0x81, 0x4f, 0x17, 0x95,
-	0x61, 0x1a, 0xf3, 0x0a, 0x6b, 0x94, 0xde, 0xab, 0xa4, 0xf7, 0x28, 0xc9,
-	0x83, 0xa9, 0x64, 0x62, 0x48, 0x25, 0xbd, 0x71, 0xd9, 0x0f, 0xb9, 0x43,
-	0x39, 0x39, 0x73, 0x7f, 0x44, 0xb8, 0x9f, 0xef, 0x5d, 0x92, 0xf5, 0x29,
-	0x3f, 0x0b, 0x9f, 0x57, 0x94, 0x75, 0x95, 0x97, 0x1a, 0xcc, 0xd8, 0xb8,
-	0x0f, 0x01, 0x70, 0x36, 0xd1, 0x86, 0xbb, 0xb5, 0x81, 0x3c, 0x94, 0x50,
-	0x11, 0xd9, 0x45, 0x3f, 0x5f, 0x7d, 0xb1, 0x5e, 0xea, 0xa7, 0xd7, 0x78,
-	0x52, 0xd1, 0xe9, 0x66, 0x7f, 0x60, 0xb2, 0x73, 0x48, 0x89, 0x1e, 0x7b,
-	0x46, 0xbd, 0x91, 0xcc, 0x9e, 0xb5, 0xfa, 0x23, 0x90, 0xc7, 0xb4, 0xbe,
-	0x98, 0xf9, 0xbc, 0x2b, 0x17, 0x82, 0xb6, 0x4d, 0x17, 0xda, 0xb3, 0x5d,
-	0xb4, 0x73, 0x57, 0xd9, 0xfd, 0x95, 0x8c, 0x63, 0xbd, 0x4b, 0x9e, 0xf3,
-	0x0b, 0x18, 0xf7, 0x7e, 0xb9, 0xe0, 0xb3, 0xbf, 0x99, 0xcf, 0x79, 0xc2,
-	0x74, 0xc2, 0x6e, 0xfa, 0x13, 0xf5, 0xa7, 0x80, 0x87, 0x7d, 0x52, 0x07,
-	0x5f, 0xc9, 0xee, 0x4b, 0x0e, 0xe4, 0x45, 0xcf, 0x4b, 0x8f, 0xa0, 0xad,
-	0x15, 0x3e, 0xf8, 0x10, 0x76, 0x73, 0xcd, 0x91, 0xab, 0x21, 0x77, 0x1d,
-	0xbd, 0xc7, 0x02, 0x93, 0xe1, 0x4d, 0x61, 0xde, 0x33, 0x03, 0x2c, 0x57,
-	0x2f, 0xd3, 0x31, 0xf2, 0xba, 0xe6, 0x97, 0x4f, 0x65, 0xfd, 0x76, 0x4f,
-	0x39, 0xc3, 0x8c, 0x31, 0x00, 0xaf, 0xa4, 0xcd, 0x54, 0x6c, 0xbb, 0xcf,
-	0xb6, 0x58, 0xe6, 0x2a, 0xf9, 0xf6, 0xc0, 0x85, 0x7f, 0x78, 0xd6, 0xff,
-	0x7b, 0xc0, 0x91, 0x81, 0x4c, 0xe0, 0xf3, 0x6a, 0x90, 0x8f, 0x31, 0xa6,
-	0xf5, 0xbf, 0xeb, 0xad, 0x9d, 0xac, 0x79, 0x7f, 0x58, 0xef, 0x93, 0x79,
-	0xfe, 0x33, 0x59, 0xae, 0x77, 0xc0, 0x36, 0xc9, 0x69, 0xb9, 0x18, 0xfd,
-	0x69, 0x0e, 0xf0, 0x14, 0x2a, 0xb4, 0x43, 0xfe, 0x06, 0x76, 0x88, 0xd6,
-	0x93, 0xf2, 0xed, 0x41, 0xe6, 0xb1, 0xdd, 0xec, 0xd5, 0xae, 0xd6, 0x0b,
-	0x21, 0x2c, 0xc9, 0xce, 0x1c, 0xf2, 0x47, 0xb4, 0x1d, 0xef, 0xc9, 0xac,
-	0xe7, 0xea, 0x7d, 0x27, 0xf9, 0xc1, 0x20, 0x78, 0xc5, 0x77, 0xe5, 0xa4,
-	0x86, 0xf9, 0x05, 0xf4, 0xe1, 0xc8, 0xc4, 0x80, 0xfb, 0xd3, 0x93, 0x3e,
-	0xc7, 0xc7, 0x3c, 0xae, 0x2b, 0x6d, 0x8e, 0x1b, 0xf8, 0x68, 0x9b, 0x7e,
-	0x2f, 0x98, 0x8d, 0x71, 0xdd, 0x02, 0x3c, 0x5d, 0x6a, 0xf7, 0x6e, 0x90,
-	0xdb, 0xe6, 0x6c, 0x9a, 0x69, 0x31, 0x36, 0xa3, 0xd1, 0x69, 0x17, 0xfe,
-	0x61, 0xc4, 0xbf, 0xb0, 0xba, 0x80, 0xb9, 0x81, 0x0e, 0x5b, 0x0c, 0x4b,
-	0x8a, 0xb0, 0x0c, 0x6b, 0x58, 0x62, 0xc0, 0xa5, 0x0b, 0xd9, 0x77, 0x9b,
-	0x1c, 0x02, 0xde, 0x87, 0x06, 0x45, 0x9e, 0x85, 0x4d, 0x76, 0xbe, 0x0a,
-	0x9e, 0x19, 0xc0, 0x73, 0xde, 0xe7, 0x5e, 0x00, 0xe6, 0xf9, 0xde, 0xb0,
-	0x70, 0x2f, 0x00, 0x71, 0xd8, 0x81, 0xdf, 0x22, 0x33, 0xd0, 0xbf, 0x27,
-	0xfd, 0xd7, 0x82, 0xf1, 0x18, 0x75, 0x23, 0xda, 0x99, 0xdb, 0x1b, 0x14,
-	0xc8, 0xe7, 0x53, 0xd4, 0x43, 0xb5, 0xd2, 0xb6, 0x8e, 0x7e, 0x88, 0x91,
-	0x9f, 0x37, 0xf8, 0x19, 0xf4, 0xf5, 0x5b, 0x2b, 0xa5, 0x3e, 0x2f, 0xfd,
-	0x1d, 0x75, 0xc8, 0x73, 0x6d, 0xde, 0x80, 0xce, 0xeb, 0xef, 0x38, 0x8c,
-	0xfc, 0x8f, 0xaf, 0x64, 0xbc, 0xdb, 0xf5, 0xd7, 0x4b, 0xdb, 0x1a, 0xe6,
-	0x55, 0xf3, 0xe0, 0xab, 0xdc, 0x83, 0x69, 0x75, 0x38, 0x64, 0x59, 0x29,
-	0xef, 0x71, 0xa7, 0xdd, 0x21, 0xcc, 0xc5, 0x6e, 0x9f, 0xb2, 0xed, 0xbf,
-	0xa3, 0x6e, 0x4a, 0x6e, 0xf4, 0x07, 0x91, 0x37, 0x8d, 0xbc, 0xc3, 0x36,
-	0x6f, 0xd0, 0xe6, 0x6d, 0x43, 0xde, 0x3e, 0xe0, 0xef, 0x6e, 0x9d, 0x9e,
-	0xe5, 0x6f, 0x53, 0xc7, 0x5b, 0xd9, 0x71, 0xe1, 0x33, 0x37, 0xf8, 0x84,
-	0x0b, 0x79, 0x25, 0xae, 0x8b, 0xde, 0x26, 0x79, 0x2f, 0x79, 0x0b, 0x7b,
-	0xfd, 0x66, 0xb1, 0x0e, 0xb2, 0x89, 0x7b, 0x80, 0x69, 0xb3, 0x6e, 0xf1,
-	0x5e, 0x96, 0xff, 0x40, 0xba, 0xeb, 0xc9, 0x38, 0x5f, 0x5b, 0xc9, 0xb8,
-	0xd8, 0x88, 0x4f, 0xfb, 0x3a, 0x90, 0x9c, 0x5e, 0x3f, 0xa1, 0x7f, 0x5b,
-	0x44, 0x3a, 0xe9, 0x41, 0x35, 0x45, 0xf4, 0x3e, 0x2d, 0x7e, 0x47, 0x61,
-	0xf7, 0x06, 0x42, 0x9f, 0x8f, 0x36, 0x5d, 0xc6, 0xe3, 0xda, 0x50, 0x98,
-	0xe7, 0x21, 0x4f, 0x6d, 0x8a, 0xc0, 0x26, 0xaa, 0xf5, 0x1d, 0x1d, 0xa3,
-	0x2e, 0xe8, 0x75, 0x00, 0xc6, 0xdf, 0x32, 0xf0, 0x63, 0x02, 0xe9, 0x47,
-	0xdf, 0xa4, 0xfd, 0x68, 0x87, 0xef, 0x1d, 0x10, 0xee, 0x67, 0x65, 0x7a,
-	0xbb, 0xf7, 0x6d, 0x99, 0xa7, 0xf3, 0x19, 0x49, 0x66, 0x94, 0x03, 0xff,
-	0x75, 0xab, 0x23, 0xf5, 0xb0, 0x3d, 0x6e, 0x30, 0xfa, 0xcd, 0xe3, 0x9e,
-	0xc4, 0x8b, 0xda, 0x56, 0x6b, 0xb4, 0xf3, 0x91, 0x05, 0x6e, 0xb8, 0x1f,
-	0x7c, 0xe0, 0x9e, 0xdd, 0x7e, 0x21, 0x09, 0x6a, 0xd4, 0xba, 0x71, 0x18,
-	0xb4, 0x91, 0x4d, 0x19, 0xdd, 0x78, 0xc3, 0x9c, 0x6e, 0xfc, 0xf3, 0x95,
-	0xe4, 0x89, 0xe1, 0x72, 0x1c, 0x75, 0xf5, 0x3a, 0x4a, 0x82, 0x75, 0x6b,
-	0x31, 0x9f, 0xe7, 0xfd, 0xec, 0x35, 0xa0, 0x2f, 0xc8, 0xe1, 0x64, 0xe7,
-	0x29, 0xd4, 0x2d, 0xa0, 0xee, 0xe4, 0x5c, 0x5d, 0x47, 0x46, 0x7c, 0xbd,
-	0xef, 0x59, 0x26, 0xcb, 0x21, 0x1d, 0x26, 0xe3, 0xb7, 0x6a, 0x5e, 0xe0,
-	0x7e, 0x30, 0x37, 0x71, 0x9f, 0x6c, 0xd6, 0xb4, 0xdd, 0x27, 0xdc, 0x27,
-	0xc5, 0xb6, 0xef, 0x0b, 0xda, 0xd6, 0x10, 0xbe, 0x12, 0xde, 0xa4, 0x8d,
-	0x31, 0xbc, 0xc3, 0xf9, 0x37, 0xf3, 0x3e, 0xe4, 0x10, 0xdf, 0xbf, 0x1f,
-	0xe4, 0x07, 0x39, 0x2f, 0xfc, 0x9e, 0xa7, 0xb9, 0x11, 0xd0, 0x5c, 0xc4,
-	0x7f, 0xbb, 0x0c, 0xeb, 0x3d, 0x10, 0x29, 0x99, 0xd0, 0xf1, 0xcc, 0x0b,
-	0xc1, 0x23, 0x0b, 0xe4, 0xf8, 0x47, 0x94, 0xa1, 0x21, 0xfe, 0x2e, 0x24,
-	0xea, 0x64, 0x66, 0x4d, 0x9d, 0xde, 0xf1, 0x41, 0x7c, 0x8c, 0xde, 0x73,
-	0x3b, 0xf8, 0xf5, 0xfa, 0xb9, 0xb1, 0x00, 0xdf, 0xc0, 0xe3, 0x4e, 0x63,
-	0xeb, 0x63, 0x1c, 0x19, 0xed, 0xbf, 0x67, 0x8b, 0x4a, 0xef, 0x0b, 0xa2,
-	0x8e, 0x3f, 0x00, 0x9d, 0x6a, 0xf6, 0xa4, 0xe0, 0x5d, 0xe1, 0xbc, 0x29,
-	0xed, 0x73, 0x1c, 0x04, 0x0f, 0x1f, 0xf4, 0xb3, 0x6b, 0x6a, 0x75, 0xdb,
-	0x49, 0xef, 0x7a, 0x6d, 0x13, 0x6e, 0x94, 0x99, 0x14, 0xdb, 0x23, 0x5e,
-	0xfe, 0x47, 0x30, 0xe4, 0xcd, 0xa0, 0x7f, 0x43, 0xff, 0x59, 0x5f, 0xb5,
-	0xd4, 0x49, 0xf5, 0x3e, 0x53, 0xe2, 0xc9, 0x85, 0xbd, 0xd2, 0x01, 0xfc,
-	0x18, 0x78, 0x73, 0xe5, 0xb7, 0x49, 0x21, 0xe6, 0xda, 0xb1, 0x45, 0xb4,
-	0x2f, 0x37, 0x91, 0xaa, 0x83, 0x2d, 0xf8, 0x17, 0xc1, 0xe4, 0x82, 0x31,
-	0x1e, 0xac, 0x1a, 0xe3, 0x4c, 0x02, 0xd8, 0x68, 0x89, 0xcc, 0xc9, 0x01,
-	0xf6, 0x65, 0x64, 0x52, 0x38, 0xc6, 0x3a, 0x8c, 0x71, 0xc7, 0xdc, 0x18,
-	0x0f, 0x2f, 0x1a, 0xe3, 0x61, 0x8c, 0x11, 0xf6, 0x42, 0x29, 0xd3, 0xe9,
-	0xce, 0xcf, 0xfb, 0xd5, 0x35, 0x73, 0xf3, 0x29, 0xdc, 0xeb, 0x84, 0xf1,
-	0xd3, 0xa6, 0xd8, 0x08, 0x78, 0x74, 0x5b, 0x90, 0x71, 0x0e, 0x64, 0x5b,
-	0x76, 0x4d, 0x8d, 0x1d, 0xff, 0x76, 0x96, 0x2b, 0x1b, 0x1c, 0x9c, 0x4c,
-	0xb9, 0x9d, 0x8f, 0xa0, 0xbf, 0xbd, 0x76, 0x5c, 0xbd, 0xe5, 0xab, 0x31,
-	0xae, 0x0b, 0xdf, 0xc1, 0x18, 0xe0, 0xb3, 0x9d, 0xa0, 0x0f, 0x9c, 0x18,
-	0x92, 0x05, 0xb2, 0xeb, 0x33, 0xf3, 0x72, 0xd4, 0xc0, 0x4c, 0xdb, 0xba,
-	0x30, 0x07, 0xf3, 0xdd, 0x8b, 0x60, 0xbe, 0x1b, 0x30, 0xef, 0xb3, 0xf3,
-	0xb2, 0xaf, 0x6a, 0xcf, 0x62, 0x48, 0x47, 0xfc, 0xfd, 0xbc, 0xf5, 0x45,
-	0x3e, 0x20, 0xf7, 0x97, 0x3a, 0xe5, 0xcb, 0x95, 0xe4, 0x59, 0xc6, 0xd1,
-	0xcf, 0x55, 0x92, 0xe3, 0x22, 0x5d, 0xf2, 0xc7, 0xb0, 0x73, 0xae, 0x82,
-	0x6f, 0xf1, 0x34, 0xfc, 0xd7, 0x3f, 0xa9, 0xf8, 0xf2, 0xc4, 0xdc, 0x7e,
-	0x38, 0xea, 0xba, 0xb4, 0x9c, 0x84, 0x4f, 0xbb, 0xed, 0x68, 0x1b, 0xf7,
-	0x2a, 0x11, 0xbe, 0xbb, 0xa8, 0x73, 0xda, 0x94, 0xe6, 0xc5, 0xef, 0x62,
-	0xbc, 0xa7, 0xa9, 0x6b, 0xd6, 0xfa, 0xbe, 0x77, 0xb3, 0x5a, 0x47, 0x99,
-	0x90, 0xff, 0x5a, 0xe4, 0x03, 0xf5, 0x26, 0xc6, 0x92, 0xf1, 0x9a, 0xc9,
-	0x1b, 0xdb, 0x3a, 0x12, 0x7d, 0x42, 0x5b, 0x82, 0xfe, 0x36, 0x6c, 0xa1,
-	0xd2, 0xe6, 0xf8, 0x5a, 0xa1, 0x4c, 0xa2, 0x5d, 0x94, 0x96, 0x09, 0xc0,
-	0x3e, 0x06, 0x89, 0x50, 0x68, 0xf6, 0x47, 0x7b, 0xd5, 0x44, 0x03, 0x79,
-	0x70, 0xdb, 0x19, 0xd0, 0xd7, 0x36, 0x8c, 0xa9, 0x2b, 0x79, 0x76, 0x46,
-	0x65, 0x4e, 0xac, 0x95, 0x57, 0x82, 0xa1, 0x66, 0x47, 0x9e, 0xd8, 0xc4,
-	0x3c, 0x2d, 0xb7, 0x3f, 0xd5, 0x0b, 0xf9, 0xd4, 0xce, 0x73, 0x0b, 0x03,
-	0xf2, 0x2f, 0x77, 0x80, 0x06, 0x7f, 0xb8, 0xe9, 0x6b, 0xc1, 0x6c, 0xb3,
-	0x2b, 0x5b, 0x37, 0x25, 0xbd, 0xbc, 0xc2, 0x78, 0x4a, 0x18, 0x4f, 0x09,
-	0xe3, 0xe3, 0x98, 0x4b, 0x18, 0xd7, 0x15, 0xf7, 0x4a, 0xf5, 0x2c, 0x88,
-	0xcb, 0x1a, 0x3f, 0x2d, 0x93, 0x77, 0x65, 0x83, 0xdd, 0x2b, 0x35, 0x5c,
-	0x1f, 0xae, 0xb1, 0x65, 0x64, 0x3c, 0x28, 0xf8, 0x7f, 0x70, 0x55, 0xb6,
-	0x2b, 0xb6, 0x58, 0xe7, 0xdc, 0x35, 0xaf, 0x73, 0x44, 0x9e, 0x33, 0xf3,
-	0x86, 0x39, 0xf3, 0xbd, 0x49, 0x6e, 0x86, 0x87, 0x0e, 0xdc, 0xaa, 0xf7,
-	0x3c, 0x77, 0xe0, 0x9b, 0x36, 0xd5, 0xa7, 0xf5, 0x3a, 0xe2, 0x4c, 0xf9,
-	0x1e, 0x3b, 0x77, 0xf7, 0x68, 0x3d, 0xbb, 0x75, 0xd3, 0xa5, 0x80, 0xfb,
-	0xdc, 0xbc, 0x4d, 0xcb, 0xc5, 0x22, 0x68, 0xef, 0xd5, 0x69, 0xde, 0xe7,
-	0x7a, 0x76, 0x41, 0x9f, 0x13, 0x01, 0xde, 0xe6, 0xe2, 0x62, 0xf5, 0x48,
-	0xa3, 0xbe, 0xf8, 0x69, 0x83, 0x59, 0x47, 0xa5, 0x6c, 0x58, 0x83, 0x34,
-	0xd7, 0xec, 0x05, 0x5e, 0x90, 0xf7, 0xdf, 0xea, 0xcd, 0x9e, 0x8f, 0xea,
-	0xb2, 0xe0, 0x31, 0xbd, 0x2f, 0x84, 0xfb, 0x03, 0x7f, 0x79, 0xa5, 0xb1,
-	0x4d, 0xc3, 0x7c, 0xa6, 0xff, 0x38, 0x98, 0xd0, 0x31, 0x36, 0xf6, 0xf5,
-	0x43, 0xfc, 0x5e, 0xbc, 0x5f, 0x24, 0xb4, 0x5d, 0xeb, 0x40, 0xf7, 0xda,
-	0x5f, 0x16, 0x94, 0x89, 0xe7, 0x25, 0x22, 0x13, 0x55, 0x30, 0x4e, 0x10,
-	0xee, 0x52, 0xd7, 0xaa, 0xf9, 0xd8, 0xdd, 0x6a, 0xa4, 0x11, 0xc6, 0x75,
-	0x8b, 0xf2, 0xc8, 0x1b, 0xad, 0x2b, 0x49, 0x37, 0xd3, 0xc2, 0xb4, 0xf9,
-	0x31, 0xcd, 0x68, 0xfb, 0xb9, 0x6d, 0x95, 0xde, 0xfb, 0xc4, 0x35, 0x46,
-	0xc6, 0x08, 0x63, 0x26, 0xdf, 0xf5, 0xff, 0x56, 0xd7, 0x19, 0x9a, 0xab,
-	0xa3, 0xe7, 0x02, 0xf9, 0x6e, 0x55, 0x5e, 0x35, 0xdc, 0xd4, 0x5f, 0x43,
-	0x9d, 0x75, 0xd0, 0x89, 0x17, 0x53, 0xab, 0xc3, 0xbd, 0xf0, 0xb0, 0x21,
-	0xb2, 0xd7, 0xd4, 0x5a, 0x99, 0x3f, 0x81, 0x79, 0x7d, 0x26, 0x65, 0x78,
-	0x51, 0xf3, 0x61, 0xf1, 0x36, 0xf8, 0xeb, 0xa1, 0xde, 0xa0, 0x9c, 0x26,
-	0x6f, 0x22, 0xad, 0x42, 0x9f, 0xe0, 0xc2, 0xea, 0x99, 0xae, 0x57, 0x03,
-	0xee, 0xb3, 0x7c, 0x45, 0xdb, 0x51, 0x43, 0xb2, 0xb0, 0xed, 0xd1, 0x7b,
-	0x5e, 0xbf, 0xed, 0xa1, 0x65, 0xda, 0x1e, 0xb2, 0x6d, 0x8b, 0x6b, 0xda,
-	0x8e, 0x5e, 0xa1, 0xed, 0x81, 0x37, 0x68, 0x7b, 0x70, 0x99, 0xb6, 0x07,
-	0xc3, 0xb6, 0x95, 0x69, 0xdb, 0x0b, 0xdb, 0x4e, 0x2c, 0xc2, 0xc9, 0x67,
-	0x5e, 0xbf, 0xed, 0x7d, 0xcb, 0xb4, 0xbd, 0x6f, 0x11, 0xdc, 0xc4, 0x49,
-	0x2d, 0x74, 0xff, 0x3d, 0xda, 0xe6, 0xac, 0x03, 0xdf, 0x5c, 0x84, 0xfc,
-	0x36, 0xfe, 0xc8, 0x85, 0xbb, 0x66, 0xcb, 0xe0, 0x2b, 0xf8, 0xd7, 0x99,
-	0x72, 0x03, 0x9e, 0x71, 0xd8, 0x33, 0x28, 0x07, 0x7b, 0xbc, 0x26, 0x1d,
-	0xc8, 0xc9, 0x6e, 0x96, 0xcd, 0xc7, 0x6b, 0xe7, 0xf4, 0xc6, 0x3d, 0xe8,
-	0x8f, 0x6d, 0xfb, 0x5e, 0xbf, 0xbc, 0xa6, 0xfb, 0xcb, 0x95, 0xe9, 0x8f,
-	0x21, 0xbd, 0x42, 0x1f, 0x97, 0xf5, 0x42, 0x19, 0x58, 0x67, 0xd7, 0x3e,
-	0x68, 0x6b, 0x32, 0x0e, 0xa7, 0xed, 0x51, 0x29, 0x94, 0x7f, 0x12, 0x4c,
-	0x83, 0x2e, 0x46, 0xe6, 0x74, 0xc8, 0x93, 0xab, 0x68, 0xb3, 0x8f, 0x53,
-	0xb3, 0x54, 0xc5, 0xa0, 0x46, 0x7c, 0xa6, 0xfd, 0x98, 0x6d, 0xc2, 0x0e,
-	0x0c, 0xcb, 0x32, 0x6e, 0x6c, 0x62, 0x4e, 0x67, 0x21, 0x33, 0xcd, 0x9e,
-	0x0e, 0xfa, 0x2a, 0x4f, 0x81, 0x97, 0xf7, 0x43, 0x76, 0x24, 0xf3, 0x22,
-	0x3d, 0x8d, 0xe6, 0xac, 0x45, 0x4c, 0x72, 0x5d, 0xbf, 0x69, 0xf1, 0xb8,
-	0xef, 0xce, 0xe5, 0xcf, 0x59, 0x40, 0x3e, 0x38, 0x94, 0x91, 0xd7, 0x37,
-	0x9a, 0x75, 0xbb, 0xb7, 0x36, 0x32, 0x1e, 0xa3, 0x36, 0x75, 0xaf, 0xd6,
-	0xf2, 0xc7, 0x09, 0xbf, 0xbf, 0xb2, 0xe8, 0x3b, 0xac, 0xf7, 0x93, 0xd5,
-	0x0b, 0xeb, 0x85, 0xe9, 0x70, 0x4d, 0x16, 0xa4, 0x1f, 0x58, 0xb3, 0xb0,
-	0x7e, 0xac, 0x69, 0xe1, 0xf7, 0xe0, 0xa2, 0xef, 0xcf, 0x2c, 0xfa, 0x7e,
-	0x61, 0xd1, 0xf7, 0x75, 0x6b, 0x17, 0x95, 0x5f, 0xf4, 0xfd, 0xe5, 0xb5,
-	0xcb, 0xc3, 0xfb, 0x57, 0x6b, 0x17, 0xc2, 0xf5, 0x94, 0x5e, 0x73, 0x1d,
-	0xaf, 0xb8, 0xb2, 0xbd, 0x88, 0x7c, 0xe7, 0xd6, 0x18, 0xf2, 0xe1, 0xcb,
-	0x54, 0xe7, 0x73, 0x8d, 0xe3, 0x1d, 0xb1, 0x85, 0xed, 0xcd, 0xd7, 0xdb,
-	0x31, 0x5f, 0x2f, 0x35, 0x5f, 0xcf, 0xf8, 0x23, 0x13, 0x15, 0xe6, 0x31,
-	0x3d, 0x6c, 0xd7, 0xd4, 0x1d, 0x29, 0x79, 0xfa, 0x3c, 0xc2, 0x80, 0x3e,
-	0x8f, 0x90, 0x80, 0x6f, 0xf4, 0x94, 0x8e, 0xeb, 0xaf, 0x51, 0x48, 0xaf,
-	0x34, 0xea, 0xd8, 0xbe, 0xe8, 0x33, 0x09, 0x03, 0xb0, 0xb9, 0x78, 0x0e,
-	0x21, 0x90, 0x9d, 0x29, 0xf3, 0x36, 0xe7, 0x12, 0x0e, 0x07, 0xbd, 0x5e,
-	0x10, 0x0c, 0xfb, 0x67, 0xad, 0x2c, 0xc7, 0xbb, 0x62, 0xea, 0xd0, 0xd7,
-	0x7c, 0x14, 0xfa, 0x66, 0xde, 0xc7, 0x7c, 0x8a, 0xf6, 0x3a, 0x68, 0xa6,
-	0x1b, 0x7a, 0x37, 0xf9, 0xa4, 0x68, 0xdd, 0xd1, 0x05, 0x9d, 0xeb, 0xdd,
-	0xfb, 0x3e, 0xd8, 0x3a, 0x5f, 0x06, 0xad, 0x1f, 0x4b, 0xf5, 0x68, 0xff,
-	0xff, 0x1c, 0x74, 0x31, 0xe3, 0x84, 0x8f, 0x69, 0xda, 0x22, 0x8d, 0x35,
-	0xe8, 0xb3, 0x50, 0x27, 0x53, 0x4e, 0x34, 0xdb, 0x75, 0xde, 0xc4, 0xcd,
-	0x53, 0xed, 0xde, 0x73, 0xe0, 0xb5, 0x7e, 0x7f, 0x03, 0x6c, 0x66, 0xd1,
-	0x3a, 0xbf, 0x50, 0x5a, 0x6f, 0x6d, 0x83, 0x66, 0x19, 0x77, 0xb9, 0x56,
-	0x93, 0xec, 0x19, 0x32, 0x3e, 0x66, 0x3c, 0xa1, 0x18, 0x23, 0xe6, 0xfa,
-	0x05, 0xcf, 0x39, 0x70, 0x9d, 0x9b, 0xf1, 0x90, 0xf1, 0x7b, 0x47, 0xfc,
-	0xbc, 0x17, 0xb1, 0x67, 0x23, 0xb2, 0x45, 0x43, 0x9b, 0x7b, 0xb4, 0xad,
-	0x1a, 0x05, 0x3f, 0x7d, 0x0f, 0x74, 0xcf, 0xba, 0xa4, 0xfd, 0xef, 0x04,
-	0x93, 0xae, 0x89, 0x4f, 0x29, 0xd4, 0xcb, 0x6a, 0x5c, 0x3d, 0x25, 0x07,
-	0x4a, 0xe4, 0xff, 0xa8, 0x96, 0xe5, 0xbb, 0x53, 0x94, 0x07, 0x51, 0xe0,
-	0x71, 0x0a, 0xf8, 0x6b, 0x90, 0xdd, 0x5d, 0x45, 0x94, 0x89, 0xc8, 0xd0,
-	0x40, 0x03, 0x78, 0x8f, 0x76, 0x09, 0xdf, 0x2e, 0xca, 0x7b, 0x32, 0x55,
-	0x1c, 0xd7, 0x7b, 0x9e, 0x1f, 0x43, 0xdd, 0xc7, 0xf1, 0x4c, 0x14, 0xcb,
-	0xa8, 0xf3, 0xb0, 0x2e, 0x3f, 0x31, 0xca, 0x73, 0x22, 0x02, 0x7b, 0xff,
-	0x49, 0x29, 0x4c, 0xb6, 0xc1, 0x2f, 0x99, 0x1e, 0x77, 0xe7, 0xe2, 0xe4,
-	0xff, 0xa5, 0x91, 0xeb, 0xcc, 0x85, 0xeb, 0xb8, 0x27, 0x47, 0xdc, 0x81,
-	0xcd, 0xaa, 0xb3, 0x49, 0xaf, 0xf9, 0xf4, 0x48, 0x3f, 0x6c, 0x8a, 0x9b,
-	0x2b, 0xcf, 0xc4, 0xcc, 0xda, 0xc0, 0x82, 0xf5, 0x86, 0xc3, 0xc4, 0x8a,
-	0x3a, 0xea, 0xf2, 0xdc, 0xa7, 0x4c, 0x9c, 0x81, 0xf6, 0x39, 0x1a, 0xae,
-	0xe7, 0x30, 0xcd, 0x93, 0xb6, 0xeb, 0x00, 0xd7, 0x99, 0x7f, 0xd2, 0xf2,
-	0xf5, 0x89, 0x4d, 0x61, 0x5f, 0xf9, 0x60, 0x6c, 0x53, 0x5e, 0x3e, 0x81,
-	0x27, 0x77, 0x5d, 0x72, 0x34, 0xab, 0xd8, 0xef, 0x37, 0x02, 0xc6, 0x02,
-	0x54, 0xba, 0x55, 0xf2, 0x4d, 0xd5, 0xfd, 0x33, 0xad, 0xc3, 0x2b, 0xa8,
-	0xd7, 0x83, 0x63, 0x26, 0x11, 0x03, 0x0e, 0xf2, 0x6f, 0x08, 0xcf, 0x16,
-	0xcf, 0x57, 0xcb, 0xc1, 0x73, 0xc2, 0xae, 0xd7, 0x70, 0x0d, 0x66, 0x05,
-	0xf0, 0xd2, 0x80, 0xf4, 0x09, 0x19, 0x39, 0xfe, 0x3b, 0x31, 0xee, 0x17,
-	0xaa, 0xd1, 0x7e, 0xf5, 0x7d, 0xf5, 0x26, 0x06, 0xf2, 0x2c, 0xca, 0x30,
-	0x7f, 0x1c, 0x75, 0x92, 0xf9, 0x6c, 0x64, 0xad, 0x0c, 0xe9, 0x7e, 0x83,
-	0x48, 0xdb, 0xb6, 0x7a, 0xbd, 0x4f, 0x5f, 0xce, 0x30, 0x6e, 0x11, 0xd6,
-	0x7d, 0x56, 0xef, 0x83, 0x73, 0xd3, 0xc9, 0x7c, 0x5f, 0x84, 0xf2, 0xa9,
-	0x53, 0x7a, 0xb9, 0xce, 0x73, 0x66, 0x5c, 0xd3, 0x76, 0xfb, 0x26, 0x9e,
-	0x07, 0xdd, 0x02, 0xfb, 0xef, 0x3b, 0x80, 0x89, 0x30, 0x9e, 0x40, 0x3a,
-	0x7c, 0xc2, 0xd7, 0x85, 0x61, 0xfa, 0x4d, 0xc2, 0x30, 0xfd, 0x26, 0x61,
-	0x20, 0x2e, 0x00, 0x47, 0xa5, 0x7d, 0x75, 0x68, 0x53, 0x5c, 0x85, 0x71,
-	0x1c, 0x2c, 0x4d, 0xc3, 0xbf, 0xd5, 0x31, 0x94, 0xce, 0x69, 0x45, 0x9e,
-	0xf7, 0xc0, 0x73, 0xe0, 0xad, 0x12, 0x78, 0x0f, 0xb6, 0xe1, 0x97, 0x61,
-	0x1b, 0x3e, 0x01, 0xdb, 0xf0, 0x1c, 0x6c, 0xc3, 0xc7, 0x31, 0x37, 0x8f,
-	0x2d, 0xe0, 0xd5, 0x8c, 0xe6, 0xd5, 0x42, 0xe9, 0x02, 0x78, 0xb5, 0xeb,
-	0x0a, 0xfc, 0xe8, 0xc2, 0xc6, 0xa7, 0x0d, 0xed, 0xc0, 0x96, 0xff, 0xb8,
-	0xf6, 0x8b, 0x1f, 0x4c, 0x8d, 0xb1, 0x0e, 0x68, 0x38, 0x49, 0x9f, 0x16,
-	0xf2, 0x3f, 0x99, 0x07, 0xef, 0x61, 0xac, 0x8e, 0xa3, 0xae, 0x5b, 0x23,
-	0xd4, 0x1f, 0xee, 0x36, 0xee, 0xef, 0xe6, 0x58, 0x13, 0x8b, 0xf0, 0x64,
-	0xf8, 0x73, 0x8f, 0x4f, 0x3d, 0x42, 0xbe, 0x4c, 0x7c, 0x76, 0xc4, 0xaf,
-	0xe6, 0xc5, 0x1d, 0x1c, 0x5f, 0xe0, 0x6d, 0x5a, 0xae, 0xee, 0x7c, 0xf9,
-	0x35, 0x73, 0xe5, 0x75, 0xff, 0xa3, 0xe4, 0x37, 0xe8, 0x6e, 0xe2, 0x3e,
-	0x91, 0x8d, 0x6c, 0xb0, 0xb8, 0xdf, 0x2f, 0x6d, 0xdb, 0x60, 0xaf, 0x0f,
-	0x82, 0x7e, 0xa7, 0x02, 0xf1, 0xb7, 0x85, 0x6d, 0xce, 0xb7, 0xe3, 0xd9,
-	0x76, 0x76, 0xc3, 0x96, 0xed, 0xdb, 0xc4, 0xb5, 0x5e, 0xd8, 0xf2, 0xa9,
-	0x70, 0x3e, 0x60, 0xf9, 0xea, 0x39, 0xa7, 0x0c, 0xa5, 0xec, 0x6c, 0xb0,
-	0xf1, 0x7e, 0xb6, 0x77, 0x61, 0xd1, 0x3c, 0x5d, 0x0a, 0x78, 0xce, 0x76,
-	0xc4, 0x1f, 0xab, 0xa2, 0x95, 0xbf, 0xb2, 0xb4, 0xa2, 0x16, 0x8d, 0xe3,
-	0x9c, 0xa5, 0x95, 0x10, 0xde, 0x58, 0x48, 0x2b, 0x75, 0x21, 0xad, 0xe4,
-	0xc7, 0x43, 0x5a, 0x61, 0xdd, 0x73, 0x21, 0xad, 0x24, 0xaa, 0x69, 0x25,
-	0x3f, 0xee, 0xe0, 0x59, 0x0c, 0x07, 0xe9, 0x85, 0xed, 0x90, 0x5e, 0x00,
-	0x4b, 0xa5, 0x32, 0x47, 0x2f, 0x31, 0xb4, 0x73, 0xa8, 0xa4, 0x34, 0xad,
-	0x0c, 0xa9, 0x50, 0x47, 0x78, 0x98, 0x73, 0xcc, 0xfd, 0x15, 0x69, 0x24,
-	0x65, 0x69, 0x64, 0xfe, 0x2c, 0xd1, 0x22, 0xda, 0x00, 0xee, 0x79, 0x5e,
-	0x60, 0xb3, 0xa6, 0x8d, 0xfb, 0x53, 0x2f, 0xa0, 0xec, 0x28, 0x68, 0x23,
-	0xc4, 0xc1, 0x03, 0x16, 0x07, 0x8b, 0xe7, 0xf2, 0xb4, 0xc5, 0xc1, 0xa8,
-	0xc5, 0x81, 0xe6, 0x97, 0x3c, 0xe7, 0x4c, 0x69, 0x1c, 0xd4, 0x69, 0x1c,
-	0x88, 0x0a, 0xeb, 0x9e, 0x5e, 0x06, 0x07, 0x2c, 0x33, 0xaa, 0xc7, 0x1f,
-	0xc1, 0xf8, 0xf7, 0x61, 0xfc, 0x4a, 0x8f, 0x9f, 0xf3, 0xc0, 0xf1, 0x03,
-	0x96, 0xca, 0x77, 0xe6, 0xc6, 0xdf, 0x84, 0x36, 0x0e, 0x6a, 0xdb, 0x99,
-	0xf1, 0x54, 0xea, 0x46, 0x33, 0xfe, 0xc7, 0x2a, 0xe6, 0x8c, 0xc9, 0x63,
-	0x4b, 0xf4, 0xd8, 0x0b, 0x96, 0x37, 0x7c, 0xbd, 0xce, 0xc6, 0x73, 0x6d,
-	0xe7, 0xa0, 0xbb, 0xc6, 0x52, 0x09, 0x7b, 0xe6, 0xd4, 0xd8, 0x43, 0x5f,
-	0x4d, 0x91, 0x77, 0x3e, 0xaa, 0xf7, 0xfa, 0x9d, 0xa5, 0x5d, 0x54, 0x6a,
-	0x92, 0xbe, 0xb1, 0x6a, 0xb8, 0x09, 0x6f, 0x3e, 0x50, 0x3e, 0x63, 0x37,
-	0xfb, 0xa1, 0x3b, 0x4c, 0xdc, 0x1a, 0xb4, 0x84, 0xf4, 0x64, 0xbe, 0x37,
-	0x52, 0x27, 0xea, 0x81, 0x0f, 0x60, 0xcc, 0x2e, 0x7c, 0xcc, 0x76, 0x6f,
-	0x9b, 0xa2, 0xae, 0xbb, 0xba, 0x4a, 0xd7, 0x35, 0x5b, 0x5d, 0xb7, 0x86,
-	0xba, 0x0e, 0x70, 0x3f, 0x25, 0x87, 0x4b, 0x9c, 0xbf, 0x7c, 0xa2, 0x4e,
-	0xc7, 0x40, 0x1d, 0x1b, 0xe7, 0x4b, 0xc6, 0x0f, 0x6b, 0x5a, 0xa6, 0xce,
-	0x4a, 0xea, 0xb8, 0xe4, 0x4c, 0xd7, 0x3f, 0xd9, 0x75, 0x10, 0xea, 0xb5,
-	0xef, 0x07, 0x7f, 0xb0, 0x8c, 0x5e, 0x83, 0xfe, 0xd1, 0xf6, 0x59, 0x0d,
-	0x64, 0xad, 0x9c, 0x6a, 0xc6, 0xb3, 0x9a, 0xe7, 0xc1, 0x3a, 0x3b, 0x54,
-	0xbd, 0xd4, 0x9c, 0x6a, 0x94, 0x3d, 0x63, 0x7a, 0xdd, 0x5c, 0xd4, 0x29,
-	0xe0, 0xff, 0x14, 0xcf, 0x14, 0x88, 0x3e, 0x03, 0x95, 0x1b, 0x85, 0x3f,
-	0x33, 0xf1, 0x94, 0xd9, 0x1b, 0x38, 0x56, 0xa3, 0x7f, 0xd3, 0xc6, 0x28,
-	0xa4, 0x32, 0xfa, 0xec, 0xd0, 0x1e, 0xb4, 0xd9, 0xbe, 0xa9, 0x16, 0x63,
-	0x8e, 0xa1, 0x2e, 0xf7, 0x16, 0xaa, 0x36, 0x57, 0x6a, 0xc5, 0x9d, 0x88,
-	0xea, 0xf3, 0x4b, 0x3c, 0x7f, 0x9f, 0xed, 0x69, 0x42, 0x5e, 0x44, 0xaf,
-	0x15, 0xd4, 0x9c, 0x9a, 0x3f, 0xa7, 0xae, 0x8e, 0x8a, 0x5d, 0xc3, 0x4f,
-	0x6b, 0xbd, 0x12, 0x39, 0x4a, 0x9d, 0xc3, 0xfd, 0x55, 0x3d, 0x98, 0xf7,
-	0xe5, 0xf4, 0x8d, 0x31, 0x62, 0xb3, 0x98, 0x3f, 0x75, 0x86, 0x67, 0x8d,
-	0x5b, 0xf1, 0x0e, 0xdb, 0x0b, 0xf5, 0x08, 0x74, 0xdf, 0xdb, 0x3f, 0xe1,
-	0x49, 0x3d, 0xf0, 0x3d, 0xa1, 0x80, 0x6b, 0x57, 0xd3, 0x42, 0x5e, 0x85,
-	0xb1, 0x69, 0x43, 0x0f, 0x8f, 0xbf, 0x21, 0x3f, 0x90, 0x26, 0x3a, 0x6d,
-	0x6c, 0xc1, 0xb7, 0x31, 0x7e, 0xd2, 0xb6, 0xa1, 0x87, 0x47, 0x53, 0x19,
-	0xc5, 0xbd, 0x51, 0x66, 0x1d, 0x94, 0xb4, 0x41, 0x9a, 0x4f, 0xe8, 0xf5,
-	0xd1, 0x8c, 0xbc, 0x2c, 0x99, 0xa6, 0x76, 0xd8, 0x5d, 0xff, 0xb6, 0x73,
-	0x6c, 0xee, 0x2e, 0xd0, 0x34, 0x07, 0xdd, 0xc4, 0x7d, 0xca, 0x9d, 0xf2,
-	0x5e, 0x9e, 0x57, 0x98, 0x70, 0xa0, 0x94, 0x9f, 0xd2, 0x7b, 0xbf, 0x77,
-	0x14, 0x57, 0xcb, 0xad, 0xa9, 0xa8, 0x5d, 0xe7, 0xac, 0x05, 0x1d, 0x40,
-	0x50, 0x9f, 0xaa, 0xc5, 0x13, 0x75, 0x38, 0x7f, 0x17, 0x53, 0x99, 0xa4,
-	0x22, 0xb3, 0xc3, 0xe7, 0x9f, 0x91, 0x2d, 0xde, 0x1e, 0x7d, 0xce, 0x4e,
-	0x9c, 0xba, 0x53, 0x7f, 0xe9, 0xd1, 0x06, 0x25, 0xfd, 0xcc, 0xf8, 0xb5,
-	0x7a, 0x5d, 0xab, 0x3f, 0x15, 0x04, 0x39, 0xcc, 0x5f, 0x41, 0x4c, 0xfc,
-	0x6c, 0xc2, 0x67, 0x1a, 0xfd, 0xda, 0x06, 0xa7, 0xf6, 0x4c, 0xa3, 0x63,
-	0x68, 0x45, 0x22, 0x2a, 0x5d, 0xef, 0xd4, 0x9c, 0xba, 0x93, 0x73, 0x06,
-	0xba, 0xf2, 0x1c, 0x43, 0x57, 0x31, 0x67, 0x9e, 0xae, 0xd6, 0xd9, 0xdf,
-	0x2a, 0x5d, 0x27, 0x99, 0x64, 0x1d, 0xc6, 0xdb, 0x5b, 0x0c, 0x61, 0x3c,
-	0x0c, 0xb8, 0x08, 0xcf, 0xdd, 0x18, 0xc3, 0x30, 0x9e, 0x3c, 0x60, 0x01,
-	0xb3, 0x9f, 0x2a, 0x00, 0xe6, 0x83, 0x78, 0x18, 0x27, 0x6b, 0x76, 0x22,
-	0x13, 0xd5, 0xf0, 0x12, 0xc6, 0x1f, 0x5b, 0x78, 0x5f, 0x0f, 0x56, 0x4f,
-	0x66, 0xba, 0x8b, 0x80, 0x87, 0x70, 0xde, 0x07, 0x18, 0x69, 0x97, 0x8e,
-	0xe2, 0xdb, 0x03, 0x7c, 0x63, 0x16, 0x26, 0xd0, 0xe3, 0xd8, 0x43, 0xf3,
-	0xbf, 0x8b, 0xb4, 0x93, 0x8f, 0xd9, 0xef, 0xd6, 0x45, 0x32, 0xe0, 0x15,
-	0x87, 0x78, 0x1e, 0x29, 0xbd, 0xe6, 0xc0, 0x0e, 0x00, 0xdf, 0xbf, 0xe4,
-	0x44, 0xce, 0xc4, 0xe5, 0x50, 0x91, 0x31, 0x84, 0xe3, 0x0e, 0xe7, 0x41,
-	0xf9, 0x57, 0xa1, 0x4c, 0x5c, 0xc9, 0xc4, 0xd5, 0x78, 0xde, 0x82, 0x67,
-	0x03, 0x9e, 0x8d, 0x78, 0xd6, 0xe3, 0x69, 0xc5, 0xf3, 0x2d, 0x94, 0x53,
-	0xb1, 0x3a, 0xe1, 0x7e, 0xd5, 0x16, 0xa5, 0x34, 0x1f, 0x71, 0xcf, 0xc2,
-	0x65, 0xc0, 0xe5, 0x2b, 0xd0, 0x3b, 0x1e, 0x9e, 0xf1, 0xf8, 0x3a, 0xfa,
-	0x98, 0xc5, 0xd3, 0xa9, 0xe4, 0x4c, 0x17, 0x9e, 0x14, 0x9e, 0x6e, 0x3c,
-	0x3d, 0x78, 0xd2, 0x78, 0x5e, 0x75, 0x0c, 0xcf, 0x5d, 0x02, 0xbe, 0x42,
-	0x1e, 0x01, 0xce, 0x17, 0xf0, 0x9c, 0xe7, 0xbc, 0x09, 0x9e, 0x73, 0x2c,
-	0xcf, 0x39, 0xf3, 0x3c, 0x57, 0xeb, 0xa8, 0x63, 0xf5, 0x4e, 0xe4, 0x18,
-	0x7d, 0x85, 0x5a, 0xc7, 0xf0, 0x7f, 0x44, 0x7a, 0x07, 0x41, 0x4b, 0xc7,
-	0x30, 0x67, 0xc7, 0x48, 0x57, 0x2e, 0xd2, 0xc7, 0x16, 0xf5, 0x3b, 0xfa,
-	0x26, 0xfa, 0x3d, 0x61, 0xfb, 0x7d, 0xb8, 0xaa, 0xdf, 0x83, 0x68, 0xfb,
-	0x3e, 0xdb, 0xef, 0xc1, 0xaa, 0x7e, 0x41, 0x2b, 0xc7, 0xf2, 0x78, 0x48,
-	0x17, 0x23, 0x48, 0x0f, 0x65, 0xc2, 0xdd, 0x6b, 0xa4, 0xbe, 0x46, 0x9f,
-	0x27, 0x8d, 0xf9, 0x35, 0x73, 0xba, 0x31, 0x53, 0xa5, 0x1f, 0x7e, 0x16,
-	0xfd, 0x38, 0x5c, 0xa2, 0x8d, 0x38, 0x5d, 0x25, 0x17, 0xe8, 0xfb, 0x04,
-	0x72, 0x5c, 0xfb, 0x39, 0xf4, 0x79, 0xe8, 0xff, 0x2c, 0xb6, 0xad, 0x3e,
-	0xae, 0xf7, 0xe7, 0xde, 0x55, 0x6c, 0x95, 0x4f, 0x14, 0x69, 0x13, 0x92,
-	0x5e, 0x82, 0x60, 0xcf, 0x36, 0xda, 0xa7, 0xf9, 0x60, 0x9d, 0x9f, 0xd4,
-	0xb1, 0xb5, 0x4f, 0x2e, 0xd5, 0x19, 0xa3, 0xbd, 0xf0, 0xcd, 0xb3, 0x47,
-	0x3f, 0x08, 0x9d, 0x51, 0x03, 0xb8, 0x9f, 0xd2, 0x77, 0x80, 0xec, 0x1a,
-	0x55, 0x23, 0x6b, 0x25, 0x2e, 0x37, 0x17, 0x6b, 0x61, 0xf7, 0x30, 0x56,
-	0x5e, 0x2f, 0xed, 0xdb, 0xa2, 0xe6, 0x6c, 0x8d, 0x17, 0xc3, 0x6f, 0xcf,
-	0x9c, 0xf5, 0x89, 0xc5, 0x91, 0x1f, 0x69, 0xa2, 0x1c, 0x8c, 0xf9, 0xef,
-	0xd4, 0xfb, 0x26, 0xdb, 0xb6, 0xd1, 0x6e, 0xb9, 0x41, 0xeb, 0x70, 0x77,
-	0x89, 0x9d, 0xa4, 0x5a, 0x3c, 0x99, 0xb7, 0xd1, 0x76, 0x17, 0x93, 0x09,
-	0xc2, 0xf5, 0x90, 0x70, 0x3f, 0xc1, 0x7e, 0x29, 0xa4, 0x1a, 0x25, 0x92,
-	0xe6, 0xba, 0x5c, 0xb2, 0x93, 0xb6, 0xd1, 0xc4, 0x98, 0x67, 0xcf, 0x9e,
-	0xac, 0x96, 0x0b, 0xba, 0x9f, 0x5a, 0x0d, 0xa3, 0x39, 0x8f, 0xc6, 0x35,
-	0x2f, 0x9e, 0x81, 0x72, 0xf1, 0x6e, 0xd0, 0x7a, 0x67, 0xa2, 0xcc, 0xb3,
-	0x4e, 0xf0, 0x97, 0xca, 0x31, 0x7d, 0xc6, 0xd4, 0x7b, 0x3b, 0xfc, 0xd8,
-	0xf2, 0x06, 0xd9, 0x3d, 0xb6, 0x82, 0xeb, 0x28, 0xb1, 0xb5, 0xd0, 0x1f,
-	0xac, 0xd3, 0xb6, 0x0d, 0xfe, 0xdf, 0xf8, 0x46, 0x79, 0x7c, 0x9c, 0x6d,
-	0xb7, 0xc8, 0xe4, 0x94, 0x38, 0xde, 0xdb, 0x57, 0xa2, 0x8c, 0xc7, 0xf1,
-	0x08, 0xf7, 0x3c, 0xb5, 0x6d, 0x13, 0xe5, 0xbd, 0xdd, 0x95, 0xf3, 0xdd,
-	0x11, 0xbd, 0x26, 0xe3, 0x82, 0x4e, 0xd8, 0xde, 0xf9, 0xee, 0x56, 0x39,
-	0x3b, 0x05, 0x9a, 0x80, 0xdc, 0xef, 0x3b, 0x45, 0x98, 0x44, 0xb6, 0x4f,
-	0xc0, 0x5e, 0x90, 0x76, 0x3c, 0xa0, 0x0f, 0xc8, 0xef, 0x5b, 0xbb, 0xd9,
-	0x17, 0xf4, 0x12, 0x74, 0x5c, 0xdb, 0x36, 0x23, 0x0b, 0x32, 0x13, 0x35,
-	0x48, 0x67, 0xbb, 0xf0, 0x0f, 0x07, 0xd9, 0x4e, 0x58, 0x57, 0x61, 0x4c,
-	0xb5, 0x9a, 0x5e, 0x66, 0x17, 0xe9, 0x8f, 0x73, 0x3f, 0x97, 0xfd, 0xcd,
-	0x36, 0x3a, 0x41, 0x2b, 0xbe, 0xde, 0xc3, 0x63, 0x6c, 0x2b, 0xce, 0x09,
-	0x6d, 0x22, 0xda, 0x55, 0xd7, 0x6a, 0xfb, 0x62, 0xb2, 0xc2, 0x19, 0xe4,
-	0xda, 0x48, 0x38, 0x47, 0x71, 0x39, 0x59, 0x9a, 0x9b, 0xa7, 0x0d, 0x35,
-	0x0b, 0xe7, 0x89, 0xb4, 0x92, 0x1a, 0xb2, 0xb6, 0xc7, 0x8c, 0x3c, 0x0f,
-	0xbb, 0xac, 0x53, 0xcf, 0xd9, 0x0c, 0x6c, 0x59, 0x3b, 0x67, 0xda, 0x9e,
-	0x2d, 0x84, 0x73, 0x36, 0x00, 0x8d, 0x53, 0xbe, 0x41, 0xcf, 0x99, 0x07,
-	0xba, 0xc9, 0x03, 0xef, 0x79, 0xcc, 0x53, 0x1e, 0x73, 0x94, 0x2f, 0xb7,
-	0xc8, 0xc4, 0x71, 0xd5, 0x5a, 0x23, 0x92, 0xd8, 0xed, 0xb7, 0xc8, 0xf0,
-	0x14, 0x63, 0x05, 0x1b, 0x60, 0x83, 0x6d, 0xc4, 0xd3, 0x8a, 0x6f, 0xd6,
-	0xe3, 0x1d, 0x1f, 0x0a, 0x75, 0xeb, 0x96, 0xd8, 0x59, 0x67, 0xd1, 0xf7,
-	0xd3, 0xc0, 0xc3, 0xa3, 0xc0, 0xc3, 0x3c, 0xef, 0xbc, 0x50, 0x15, 0x5f,
-	0xe2, 0x58, 0xb5, 0x0e, 0xc5, 0x78, 0x63, 0x7a, 0x3e, 0x75, 0x9c, 0xa9,
-	0x54, 0xfb, 0x66, 0xec, 0xa9, 0x38, 0xed, 0xa9, 0xdc, 0xa8, 0x67, 0xce,
-	0x60, 0x0d, 0xc0, 0x77, 0xf2, 0xf7, 0x69, 0x5a, 0x1f, 0x1a, 0x27, 0x5c,
-	0xd1, 0x10, 0xae, 0x05, 0x73, 0xc6, 0x33, 0xb3, 0x4b, 0xe3, 0x18, 0x2f,
-	0xcc, 0xed, 0x11, 0x87, 0x2e, 0x97, 0xd1, 0x14, 0xe3, 0x24, 0xad, 0xcb,
-	0xc0, 0xf4, 0x94, 0xb6, 0x61, 0x45, 0x9d, 0x96, 0x03, 0x25, 0x9e, 0xb7,
-	0xe5, 0x1a, 0xcc, 0xef, 0x31, 0x7e, 0xd4, 0x39, 0x21, 0xc7, 0xd0, 0x37,
-	0xd7, 0xc5, 0x95, 0x8d, 0xcf, 0xac, 0xb2, 0x7b, 0xf2, 0xaa, 0x63, 0x34,
-	0x66, 0xdd, 0x7c, 0xe1, 0xd9, 0x93, 0xe4, 0xc0, 0xac, 0x5e, 0x77, 0xe5,
-	0x9a, 0xa1, 0x8c, 0x46, 0xa0, 0xfd, 0x76, 0x77, 0x27, 0x7b, 0xcc, 0x59,
-	0xc3, 0x84, 0xf4, 0x97, 0xcc, 0xf8, 0x2f, 0xea, 0x7d, 0x93, 0x66, 0x7f,
-	0xb8, 0xd9, 0x53, 0xb9, 0x5f, 0x2e, 0xa6, 0xa2, 0x55, 0x73, 0x5b, 0x27,
-	0xc3, 0xc0, 0x85, 0x5e, 0xcb, 0x84, 0x5d, 0x9c, 0xeb, 0x7e, 0xbc, 0x89,
-	0x67, 0xd1, 0xa2, 0x98, 0x9f, 0xc2, 0x38, 0xcf, 0xa7, 0xb3, 0xdd, 0x2b,
-	0xb5, 0x45, 0x31, 0xcb, 0xb3, 0x4e, 0x90, 0x95, 0x6f, 0xdd, 0x12, 0xaf,
-	0xd7, 0xf9, 0x2b, 0xec, 0x99, 0x16, 0xd8, 0x0d, 0xbb, 0x02, 0xf9, 0x33,
-	0xe8, 0xc9, 0xd3, 0x76, 0x4c, 0x09, 0x1d, 0x93, 0x92, 0xe0, 0x7c, 0x2a,
-	0x6e, 0xe3, 0xce, 0x1c, 0xcb, 0x98, 0xa5, 0x6f, 0x63, 0xff, 0xcc, 0xdb,
-	0xd0, 0x5d, 0x9a, 0xd6, 0x1f, 0xd7, 0xb2, 0xb0, 0xcb, 0xda, 0xce, 0x3a,
-	0x8e, 0x73, 0x42, 0xf4, 0x1e, 0xac, 0xd0, 0x37, 0xea, 0xa8, 0xf2, 0x0b,
-	0x8c, 0x2f, 0x57, 0x18, 0x5b, 0x4e, 0x46, 0xcd, 0xfb, 0x84, 0xf4, 0xe5,
-	0xf6, 0x6c, 0xe2, 0xdd, 0x30, 0xa1, 0x2f, 0xd7, 0x65, 0x7d, 0xb9, 0x46,
-	0xed, 0xcb, 0x99, 0xd8, 0x43, 0xe3, 0x9c, 0x2f, 0x57, 0x18, 0xcb, 0x83,
-	0x56, 0x6a, 0xed, 0x59, 0x09, 0x63, 0x0b, 0x0d, 0x17, 0x5d, 0xbd, 0x6f,
-	0x24, 0x37, 0xa0, 0xe0, 0x37, 0x18, 0x1f, 0x8b, 0xb1, 0x0a, 0xa5, 0xfe,
-	0xce, 0xfa, 0x17, 0x1b, 0x24, 0xd3, 0xbc, 0x02, 0xe3, 0x7e, 0x4a, 0xcf,
-	0xb9, 0x59, 0xc3, 0x82, 0x5c, 0x1b, 0x64, 0xcc, 0x87, 0x67, 0x47, 0x35,
-	0x7f, 0x25, 0x7a, 0x23, 0x9d, 0xc6, 0x9e, 0xf5, 0x13, 0x6b, 0xa5, 0xfe,
-	0xb8, 0x53, 0x18, 0x8f, 0xda, 0x7e, 0x13, 0x80, 0xa9, 0x06, 0x73, 0xf3,
-	0x4e, 0x2b, 0x93, 0xd9, 0xf7, 0x3b, 0xea, 0x18, 0x1b, 0x98, 0x2a, 0x9a,
-	0x18, 0x60, 0x5f, 0x31, 0x12, 0x9e, 0x5b, 0x57, 0x5c, 0x47, 0xce, 0x0c,
-	0xae, 0x00, 0x2c, 0x2b, 0x96, 0xb5, 0x59, 0x1f, 0x7b, 0x43, 0x1d, 0x45,
-	0x9a, 0x7a, 0x4a, 0xef, 0x2f, 0x5c, 0xd9, 0x9d, 0xdc, 0xa9, 0xcf, 0x23,
-	0xe9, 0x58, 0x62, 0x5e, 0xb8, 0x7f, 0xf7, 0x9b, 0xf2, 0x36, 0x2d, 0xfb,
-	0x0f, 0xa4, 0xa8, 0xc7, 0xb6, 0xe9, 0xdf, 0xb5, 0xe9, 0x20, 0x38, 0xdf,
-	0xfd, 0x2c, 0x6c, 0x16, 0xdf, 0xfb, 0x96, 0xb4, 0xc7, 0x7b, 0xb5, 0x0d,
-	0x85, 0xb9, 0x1a, 0xac, 0x97, 0x15, 0xfe, 0xb8, 0xdd, 0xab, 0x68, 0xd6,
-	0x03, 0x0b, 0xc2, 0xfb, 0x17, 0x3a, 0x6c, 0x5e, 0x3e, 0xa8, 0x07, 0x3d,
-	0x7d, 0x44, 0x8c, 0xac, 0xc9, 0xcd, 0xcb, 0x1a, 0xee, 0xa7, 0xcb, 0x90,
-	0xa0, 0xdd, 0x23, 0x92, 0xe4, 0xdd, 0x49, 0xec, 0xbb, 0x20, 0x57, 0x41,
-	0x3f, 0xb3, 0x1e, 0x6d, 0x56, 0x7e, 0x73, 0x0f, 0x8a, 0xef, 0x1d, 0x84,
-	0x8e, 0xb9, 0x61, 0xa9, 0x8e, 0x89, 0xd3, 0xbf, 0xcf, 0x8d, 0xd2, 0x47,
-	0x5c, 0x89, 0x3a, 0x2d, 0xf2, 0xd1, 0xb1, 0xdf, 0x5a, 0x4b, 0x1e, 0x1b,
-	0x82, 0x7c, 0x57, 0xf7, 0x87, 0xe7, 0x2e, 0x99, 0xc6, 0x7c, 0xb6, 0x5b,
-	0x27, 0x89, 0xf7, 0x79, 0xf2, 0xc5, 0x4a, 0x32, 0x31, 0x0b, 0x1d, 0x35,
-	0xe4, 0x0c, 0xb7, 0x9a, 0xd8, 0xe9, 0xa7, 0xd6, 0x9a, 0x73, 0x5a, 0xf5,
-	0xc0, 0x69, 0x18, 0x4f, 0xad, 0xa6, 0xdd, 0x59, 0x2b, 0x97, 0x83, 0xa0,
-	0xbe, 0x5b, 0xcb, 0xe2, 0x9d, 0x94, 0xc5, 0x07, 0x52, 0x1d, 0x86, 0x07,
-	0xb4, 0xef, 0xc4, 0x3d, 0x00, 0xc0, 0x43, 0xb7, 0xcb, 0xbd, 0xd0, 0x96,
-	0x4f, 0xfd, 0xcc, 0x8c, 0x95, 0x4f, 0xca, 0x59, 0xca, 0x9f, 0x6a, 0x6b,
-	0x74, 0x81, 0xec, 0x3d, 0x34, 0x46, 0xbd, 0x9c, 0x9a, 0xfe, 0x26, 0xe4,
-	0x55, 0x4e, 0xe3, 0xa1, 0x45, 0xee, 0x1b, 0x93, 0xcc, 0x45, 0xe8, 0xac,
-	0xc2, 0xd4, 0x42, 0x1e, 0x5d, 0xda, 0x1e, 0xc7, 0x7a, 0x7a, 0xad, 0xf1,
-	0x71, 0x17, 0x8e, 0x75, 0x9a, 0x7b, 0x8c, 0xf4, 0x58, 0xb9, 0x37, 0xff,
-	0x9c, 0x1d, 0xeb, 0xca, 0x70, 0xac, 0x3d, 0x0b, 0xc7, 0x1a, 0xfa, 0xf8,
-	0xa1, 0xfc, 0x4d, 0xe8, 0xb3, 0x49, 0xfa, 0x4c, 0xcc, 0xd8, 0x4a, 0xe9,
-	0x1d, 0x6d, 0xb4, 0x72, 0xd3, 0x83, 0x0e, 0xe2, 0x79, 0xa1, 0xe9, 0xcf,
-	0x79, 0x62, 0x71, 0xa6, 0x88, 0x07, 0xca, 0xdc, 0x26, 0x7d, 0x9e, 0x71,
-	0x02, 0x7e, 0xd6, 0x87, 0x8b, 0x2c, 0x1b, 0xe6, 0x5f, 0x29, 0x46, 0x1c,
-	0xfa, 0xd6, 0xf4, 0x9f, 0x3a, 0x97, 0xc4, 0x16, 0x4c, 0x1c, 0x98, 0xf1,
-	0x5f, 0x73, 0xcf, 0x02, 0xf7, 0x7d, 0xdf, 0x01, 0xde, 0xfa, 0xed, 0x62,
-	0xb2, 0x27, 0x1b, 0xa1, 0x3c, 0x9d, 0x95, 0x43, 0x95, 0x3e, 0x69, 0xd3,
-	0x67, 0xed, 0xdf, 0x30, 0x46, 0x9c, 0xa9, 0x8e, 0x11, 0x8b, 0x63, 0x62,
-	0xc4, 0x3b, 0x7f, 0x8e, 0x18, 0xb1, 0x38, 0x26, 0x46, 0xbc, 0x9c, 0x9f,
-	0x35, 0x52, 0x9a, 0xc5, 0xb8, 0xea, 0x21, 0x53, 0x94, 0x93, 0x9b, 0x6a,
-	0xc0, 0xbb, 0x16, 0x6f, 0xc0, 0x32, 0x56, 0xc0, 0xdb, 0xc3, 0xfb, 0x20,
-	0xde, 0x31, 0x19, 0x99, 0xd3, 0x1d, 0xb3, 0x90, 0x1f, 0xd4, 0x69, 0xac,
-	0x6b, 0xfc, 0x82, 0xc9, 0x72, 0x33, 0xca, 0x5d, 0x72, 0x26, 0x58, 0xaf,
-	0xd4, 0x28, 0xc3, 0x63, 0x94, 0xdd, 0x4d, 0x32, 0x3a, 0x16, 0xda, 0xb8,
-	0x9f, 0x5d, 0xcf, 0xb5, 0x81, 0x21, 0x09, 0x6d, 0xd8, 0x67, 0xd6, 0x9b,
-	0xb5, 0xdb, 0x2d, 0x31, 0xa9, 0x5f, 0x8d, 0x39, 0x38, 0xee, 0x5c, 0x1c,
-	0x5f, 0xbd, 0xc0, 0x96, 0x4d, 0xd8, 0xd8, 0xe0, 0xb8, 0xd5, 0xc1, 0xcb,
-	0xcb, 0x88, 0xea, 0xf9, 0x8f, 0xdb, 0x73, 0xbc, 0x51, 0x7b, 0xd7, 0x5f,
-	0x42, 0xcf, 0xcf, 0x40, 0x65, 0x16, 0xfd, 0xad, 0x57, 0x99, 0x71, 0x8e,
-	0x73, 0xee, 0x7e, 0x1e, 0xc8, 0xc5, 0x56, 0x35, 0x34, 0xbe, 0x80, 0x2e,
-	0x41, 0xb7, 0x1c, 0x9b, 0x03, 0xda, 0xbd, 0x57, 0x26, 0x46, 0x09, 0x5f,
-	0x47, 0x3c, 0xa2, 0xcf, 0xf5, 0xe2, 0x7b, 0xdc, 0x9c, 0x27, 0xea, 0xad,
-	0x84, 0x67, 0x7a, 0xd7, 0x00, 0xde, 0xc5, 0xe7, 0x7a, 0xad, 0x9e, 0xd6,
-	0x36, 0x04, 0xcf, 0xf7, 0x86, 0x63, 0x58, 0x8e, 0x9e, 0x02, 0x19, 0xd6,
-	0xfb, 0x7d, 0xd7, 0xca, 0xe9, 0x07, 0xe7, 0xce, 0x17, 0x34, 0xc1, 0x56,
-	0x69, 0x85, 0xa9, 0x3c, 0xe0, 0xa6, 0xb9, 0xef, 0x82, 0xfb, 0x0b, 0x3a,
-	0xe2, 0xb7, 0xe9, 0x73, 0x1f, 0xf3, 0x67, 0xac, 0xe7, 0xcf, 0x7e, 0x84,
-	0x67, 0x5a, 0xe3, 0xd2, 0x07, 0x3a, 0xec, 0xd7, 0xe9, 0x31, 0x8c, 0x87,
-	0x6b, 0xbe, 0x1a, 0x0f, 0x90, 0x3d, 0x5c, 0xfb, 0xc5, 0xd8, 0x2b, 0x2d,
-	0x2a, 0xa7, 0xcf, 0x58, 0x47, 0x2d, 0x8d, 0x5d, 0x76, 0xf6, 0x94, 0x13,
-	0x6a, 0x4f, 0xd9, 0x57, 0x7b, 0xcb, 0x36, 0xaf, 0xfb, 0x01, 0xcc, 0x07,
-	0x7e, 0x8f, 0x17, 0x9d, 0x21, 0xe0, 0xab, 0x50, 0x3a, 0xe2, 0x64, 0xf4,
-	0xfb, 0xa8, 0x7d, 0x43, 0x0e, 0x60, 0xae, 0x7a, 0xc7, 0xa3, 0x5a, 0xde,
-	0xcf, 0xdf, 0xd3, 0x17, 0xce, 0xeb, 0x0b, 0x7a, 0x0d, 0x68, 0x5a, 0x88,
-	0x6b, 0xcf, 0xda, 0x10, 0xc7, 0x9d, 0x9c, 0xc6, 0x3d, 0xcb, 0x7c, 0x4b,
-	0xff, 0x06, 0x9d, 0x2b, 0xd3, 0x5e, 0x2b, 0xde, 0x8b, 0xf7, 0x4d, 0x86,
-	0xfa, 0x86, 0x70, 0xdf, 0x09, 0xbd, 0x16, 0xec, 0x37, 0xf2, 0x6a, 0x56,
-	0x46, 0x2a, 0x5c, 0xc3, 0x64, 0x3b, 0x48, 0x2f, 0xd7, 0xc0, 0x1e, 0x58,
-	0x78, 0xbe, 0xba, 0x7f, 0x7e, 0x1e, 0x12, 0xe3, 0x42, 0x58, 0xee, 0xd6,
-	0x67, 0x17, 0xab, 0xef, 0x1e, 0xb9, 0xf2, 0xbf, 0x70, 0xfd, 0xd0, 0xc8,
-	0x50, 0x0b, 0x47, 0x86, 0xf2, 0xce, 0xc8, 0x95, 0xaf, 0xcb, 0x41, 0xe0,
-	0xf1, 0x30, 0x60, 0x52, 0xf7, 0xf3, 0xce, 0xab, 0x57, 0xa5, 0x30, 0x59,
-	0x2f, 0xea, 0xa1, 0x82, 0xe3, 0x3e, 0x54, 0x2b, 0x91, 0x87, 0x94, 0x53,
-	0xf3, 0x50, 0xbb, 0xf6, 0xcf, 0x77, 0xa4, 0xda, 0xe3, 0x7b, 0xe5, 0xb8,
-	0xe3, 0xde, 0xaf, 0xf4, 0x59, 0xdb, 0x82, 0xc7, 0x58, 0xdf, 0x71, 0x27,
-	0x72, 0x7f, 0xd4, 0x9e, 0xd3, 0x37, 0xf1, 0xbd, 0x59, 0xcd, 0xf7, 0xdf,
-	0x58, 0x47, 0x9c, 0xcd, 0x0a, 0xf1, 0xf1, 0x59, 0xc8, 0xad, 0x4f, 0x4b,
-	0x76, 0x34, 0x31, 0x57, 0xc6, 0xec, 0xb3, 0xdf, 0xb0, 0xce, 0xf0, 0x0b,
-	0xcb, 0xbc, 0xe2, 0xf0, 0xce, 0x1c, 0xa3, 0x33, 0x3e, 0xdf, 0x12, 0xee,
-	0xb9, 0x37, 0x73, 0xca, 0xfc, 0xc6, 0x75, 0x52, 0xff, 0x0a, 0xe6, 0x8b,
-	0xfd, 0x11, 0x57, 0xab, 0xf4, 0x3d, 0x05, 0x9e, 0x6c, 0x89, 0xd7, 0xcd,
-	0xd9, 0x43, 0x46, 0xf6, 0xd6, 0x01, 0x6e, 0xc0, 0x6f, 0xec, 0x3b, 0x21,
-	0x9d, 0x0a, 0x24, 0x37, 0x69, 0xb6, 0xa3, 0x67, 0x87, 0x98, 0x39, 0x33,
-	0x34, 0xb3, 0xc2, 0xd8, 0x91, 0xf8, 0x36, 0x74, 0xa1, 0x64, 0xfb, 0xd8,
-	0x4b, 0x4e, 0x3f, 0xcf, 0x3c, 0x8a, 0xb6, 0x1b, 0x97, 0xb3, 0x09, 0xc1,
-	0x4b, 0xcf, 0x5b, 0xff, 0x32, 0x08, 0xc6, 0x52, 0x29, 0xde, 0x2b, 0xb8,
-	0x8c, 0x4f, 0xb9, 0xca, 0x99, 0x1c, 0x6d, 0x70, 0x26, 0x46, 0x03, 0xd9,
-	0x93, 0xe2, 0x9d, 0x49, 0xdc, 0x93, 0xa0, 0xe3, 0xe3, 0x48, 0x6b, 0x87,
-	0x6e, 0x7d, 0xc7, 0x3a, 0xee, 0x71, 0xbb, 0xd9, 0x6f, 0xb4, 0xe5, 0x88,
-	0x63, 0xfa, 0xca, 0xed, 0x27, 0x72, 0xc2, 0xbb, 0x8b, 0xb6, 0xc4, 0x63,
-	0x7a, 0x7f, 0xe2, 0x17, 0x50, 0x0f, 0x7d, 0x94, 0xd8, 0xaf, 0xeb, 0x4c,
-	0x40, 0x9e, 0x4d, 0x8e, 0xf1, 0xbe, 0x14, 0x9e, 0x63, 0x88, 0xb4, 0x2a,
-	0xb9, 0xd6, 0x1b, 0xb6, 0xf7, 0x69, 0xe6, 0xe1, 0x0a, 0x45, 0x74, 0xda,
-	0x16, 0x6f, 0xf7, 0xdc, 0x1d, 0x9b, 0x61, 0x5a, 0x78, 0xd7, 0xa6, 0xd2,
-	0x67, 0x56, 0xe0, 0xd3, 0x9e, 0x1e, 0x92, 0xb8, 0x33, 0x55, 0x6c, 0x75,
-	0x4e, 0x16, 0x33, 0x5b, 0xd7, 0x81, 0x3e, 0xce, 0xa7, 0x3e, 0x46, 0xf9,
-	0x05, 0xdb, 0xef, 0x45, 0xc9, 0x57, 0x3e, 0x24, 0xe3, 0x2d, 0xed, 0xde,
-	0xfd, 0x7a, 0x6e, 0x2e, 0x03, 0x67, 0x2d, 0x2a, 0x3b, 0xfa, 0xc4, 0x3a,
-	0xea, 0xb7, 0xdd, 0x45, 0x05, 0x5e, 0x56, 0xbf, 0x88, 0x07, 0x36, 0x6e,
-	0xad, 0xb6, 0x51, 0xf6, 0xa6, 0x58, 0xae, 0xc1, 0xe9, 0x1d, 0x5d, 0x85,
-	0x79, 0xdc, 0x05, 0xfd, 0xe9, 0xc0, 0x46, 0x22, 0xae, 0x1b, 0x9c, 0x3d,
-	0xa3, 0x79, 0xf4, 0xc8, 0x7d, 0xd6, 0xbc, 0xf7, 0xf0, 0x30, 0xc6, 0xa8,
-	0xe5, 0x2b, 0x78, 0xf7, 0x12, 0xd7, 0xdb, 0x83, 0x49, 0xd8, 0x06, 0xb9,
-	0xae, 0x7f, 0x67, 0xd7, 0xab, 0xa7, 0xaf, 0xb0, 0x5e, 0xed, 0xc9, 0x23,
-	0x15, 0x7d, 0x6f, 0x48, 0xe7, 0xb8, 0xe2, 0x3a, 0x6e, 0xf3, 0x55, 0x7a,
-	0x7e, 0x54, 0x87, 0xdd, 0x1b, 0x78, 0x72, 0x9d, 0xbd, 0xd3, 0x06, 0x70,
-	0x5c, 0x05, 0x18, 0x36, 0x62, 0xfc, 0x84, 0xc1, 0xd4, 0x11, 0x75, 0x4b,
-	0x9c, 0x3a, 0x70, 0x56, 0x4e, 0xaf, 0x0b, 0xf7, 0x7b, 0xa0, 0x1d, 0xc8,
-	0xb5, 0x47, 0xe3, 0x46, 0x37, 0xae, 0x5d, 0xa6, 0x9d, 0x70, 0x3c, 0x8e,
-	0x1d, 0x0f, 0x69, 0x75, 0x43, 0x0b, 0xfd, 0x89, 0x59, 0xa9, 0x5b, 0x54,
-	0x9e, 0xf1, 0xfc, 0x5d, 0xad, 0x66, 0xdf, 0x11, 0xcb, 0x7a, 0xb0, 0x4b,
-	0x69, 0xe3, 0x12, 0x77, 0x7a, 0xae, 0x8a, 0xdc, 0x5b, 0x9c, 0xf3, 0x2f,
-	0x43, 0x9e, 0x5c, 0xeb, 0xbd, 0x4d, 0x91, 0xf6, 0x42, 0xfc, 0x12, 0xb7,
-	0x09, 0xe0, 0x95, 0x71, 0x95, 0xd3, 0x41, 0x66, 0x80, 0x7c, 0xc5, 0x36,
-	0x98, 0xff, 0xa2, 0x8e, 0xe5, 0x0e, 0xa6, 0x18, 0x27, 0x6a, 0x3f, 0x71,
-	0x87, 0x0a, 0x65, 0xd3, 0x2c, 0xd7, 0x10, 0x1c, 0xde, 0x21, 0xba, 0x0b,
-	0x1d, 0x5e, 0x9c, 0x52, 0xce, 0x37, 0xc7, 0x5c, 0x7c, 0xd7, 0xd8, 0xfb,
-	0x42, 0x8d, 0x6e, 0x12, 0xf9, 0xeb, 0x70, 0xbc, 0xf1, 0x3c, 0xe6, 0xfb,
-	0x12, 0xe6, 0x7b, 0xf9, 0xfb, 0x41, 0x91, 0x57, 0x46, 0x5e, 0xf9, 0x43,
-	0x41, 0xa6, 0x89, 0xf4, 0x47, 0x9a, 0x7b, 0x3d, 0x9f, 0x59, 0xef, 0x63,
-	0x02, 0x6c, 0x67, 0xc1, 0x0b, 0x19, 0xae, 0x25, 0x07, 0xc7, 0x52, 0x37,
-	0x81, 0x17, 0x76, 0xca, 0x9f, 0xc0, 0x16, 0xf8, 0xe3, 0x4a, 0x1a, 0x3c,
-	0xd1, 0x03, 0x1e, 0xe9, 0x06, 0x5f, 0xa4, 0xb4, 0x5d, 0xfc, 0x28, 0x74,
-	0xde, 0xd9, 0x4a, 0xc9, 0xd9, 0x3b, 0x5a, 0x74, 0x72, 0xa3, 0x47, 0x41,
-	0x17, 0xdc, 0x03, 0xab, 0xae, 0xa9, 0x11, 0x37, 0x3e, 0x29, 0xa4, 0xff,
-	0x76, 0xee, 0xed, 0x68, 0x06, 0xae, 0xce, 0x10, 0x57, 0x93, 0x95, 0x2d,
-	0xde, 0x3a, 0xf0, 0x41, 0xb3, 0xe6, 0x83, 0x46, 0x27, 0xe3, 0xdd, 0x64,
-	0xf9, 0x60, 0x04, 0x7c, 0x50, 0x58, 0xc2, 0x07, 0xcf, 0x58, 0x9a, 0x9f,
-	0xae, 0xe2, 0x83, 0x49, 0x9b, 0x36, 0x7e, 0x05, 0x3e, 0xb8, 0xca, 0x4f,
-	0x3e, 0x39, 0x24, 0x27, 0xc0, 0x07, 0x0f, 0x6b, 0x3e, 0xb8, 0x4a, 0xf3,
-	0x01, 0xe3, 0x46, 0xe4, 0x85, 0x56, 0xc8, 0x0e, 0xf2, 0xc2, 0xb3, 0x32,
-	0x0b, 0x5e, 0x78, 0x51, 0xb1, 0xef, 0xcb, 0xb4, 0x0f, 0x46, 0xe9, 0x8f,
-	0x9d, 0x2a, 0x15, 0xc1, 0xbb, 0x4a, 0xbe, 0x30, 0x16, 0x04, 0x33, 0xf0,
-	0xd1, 0x1f, 0x84, 0x0d, 0xef, 0xea, 0x3b, 0x69, 0xa7, 0x61, 0xbb, 0x10,
-	0x36, 0xda, 0xe4, 0xe3, 0x0e, 0xe8, 0xfd, 0xf0, 0x04, 0xc6, 0xb0, 0x47,
-	0xfd, 0x3e, 0xfc, 0x60, 0x0f, 0xf3, 0x4a, 0xdb, 0xfe, 0xb8, 0xe6, 0x9b,
-	0x1a, 0xe8, 0x80, 0x93, 0xdd, 0x8c, 0x33, 0xf9, 0xde, 0x5e, 0xd5, 0x9e,
-	0xef, 0x03, 0xcc, 0x11, 0x75, 0xbf, 0x30, 0xc6, 0xd1, 0xb4, 0xc8, 0xb6,
-	0xa7, 0x5c, 0x18, 0x90, 0xfb, 0x6c, 0x5e, 0x3e, 0xa8, 0x83, 0x1d, 0x5a,
-	0xa7, 0x8c, 0x5d, 0xae, 0xb6, 0x25, 0xbd, 0xdf, 0x80, 0xd0, 0xac, 0x4d,
-	0x9b, 0x3d, 0x81, 0x7d, 0xc5, 0x6a, 0xbb, 0xfe, 0x5e, 0xd8, 0xf5, 0xac,
-	0x23, 0xae, 0xb1, 0xeb, 0xef, 0xb2, 0xbc, 0xc6, 0xdf, 0x9e, 0xb6, 0xf1,
-	0x0f, 0x00, 0xbe, 0x1d, 0x73, 0x36, 0x3e, 0xdb, 0xa0, 0xad, 0x21, 0x72,
-	0x03, 0xec, 0xbc, 0x1b, 0xc1, 0x83, 0x37, 0xc1, 0x8f, 0x7a, 0x77, 0xd1,
-	0x93, 0x9d, 0xc5, 0x66, 0xf8, 0xdb, 0xad, 0xf2, 0xab, 0x63, 0x1b, 0xa5,
-	0x7f, 0xf4, 0x77, 0x9a, 0xa1, 0x57, 0x61, 0x97, 0xbe, 0x08, 0x38, 0x23,
-	0x56, 0x56, 0x47, 0xc1, 0x03, 0xed, 0x89, 0x1f, 0xa8, 0x44, 0xab, 0x91,
-	0xed, 0x3c, 0x4b, 0xbe, 0x5c, 0x3b, 0x31, 0xd4, 0x67, 0x1c, 0xa5, 0x45,
-	0xce, 0x1c, 0xa7, 0xe7, 0x95, 0x80, 0x2d, 0x9e, 0x82, 0x1d, 0xb2, 0x01,
-	0xed, 0x31, 0x96, 0xbc, 0x5a, 0x9e, 0xd9, 0xea, 0xde, 0x9d, 0xd3, 0x7c,
-	0x78, 0xc9, 0xc9, 0x8e, 0xdd, 0x24, 0x85, 0xc1, 0x28, 0xc6, 0xa0, 0x9a,
-	0xd7, 0xca, 0xf5, 0xd2, 0xaf, 0xc7, 0x73, 0x59, 0x0e, 0x42, 0x1f, 0xff,
-	0x69, 0xb1, 0x5f, 0x66, 0x07, 0x9a, 0xf0, 0x1d, 0x95, 0x67, 0x8a, 0x5b,
-	0xe0, 0xef, 0xfc, 0x0a, 0x70, 0x54, 0x8b, 0xef, 0x5a, 0xe9, 0x5d, 0x47,
-	0x5e, 0x6d, 0x90, 0x19, 0xa4, 0xdf, 0x28, 0xbf, 0x64, 0xd3, 0x99, 0x46,
-	0xde, 0x68, 0x40, 0xdd, 0xa8, 0x9c, 0x2f, 0xd2, 0x96, 0xd4, 0x3c, 0xd1,
-	0xf3, 0xb2, 0x6c, 0xc9, 0xbc, 0x0c, 0xdb, 0xf4, 0x59, 0x3c, 0xcf, 0x4b,
-	0x72, 0xe7, 0x6e, 0x67, 0x4b, 0xa2, 0xdd, 0x81, 0xbe, 0xc4, 0xe3, 0x3a,
-	0x5b, 0xbc, 0x5a, 0xe7, 0x5a, 0xdb, 0x46, 0x8d, 0x3c, 0x3f, 0xa8, 0xe2,
-	0x0d, 0x98, 0x93, 0xcd, 0x4e, 0x87, 0x4d, 0xe3, 0xb7, 0xbe, 0x2f, 0x51,
-	0xda, 0xcf, 0xa8, 0x0d, 0xab, 0x44, 0xda, 0x1a, 0x60, 0xe7, 0xec, 0x11,
-	0xd5, 0xdc, 0x20, 0xae, 0xb4, 0x4f, 0xa8, 0x56, 0xa4, 0xf9, 0x36, 0x2d,
-	0xd6, 0x00, 0x9d, 0x80, 0xb4, 0x16, 0xa4, 0x6d, 0xb2, 0x69, 0x4d, 0x0d,
-	0x52, 0x8b, 0xb4, 0xcb, 0x9a, 0xe7, 0x2f, 0x76, 0xf8, 0x5e, 0xce, 0xa9,
-	0x97, 0xb6, 0x53, 0x0d, 0x90, 0x0d, 0xab, 0x65, 0x66, 0x6b, 0x9d, 0xb4,
-	0x21, 0x8f, 0x31, 0xee, 0xd4, 0xa9, 0xa8, 0xbc, 0xf3, 0x54, 0x7b, 0xfc,
-	0xa3, 0x18, 0x43, 0xfb, 0x19, 0xc6, 0xbc, 0xff, 0xac, 0x99, 0x31, 0x9f,
-	0xb6, 0x33, 0x7c, 0xd7, 0x69, 0xf9, 0x43, 0x7c, 0x98, 0x3b, 0xdf, 0x60,
-	0x63, 0x94, 0x8e, 0x3b, 0xc3, 0xa3, 0xd4, 0xdb, 0xed, 0xf6, 0x7e, 0xa2,
-	0xff, 0xd9, 0x4c, 0x5f, 0x6d, 0x82, 0x36, 0x54, 0x89, 0xfc, 0x48, 0xdd,
-	0x83, 0xf7, 0xb8, 0x23, 0x85, 0x79, 0x99, 0x35, 0x45, 0xbe, 0x3a, 0xae,
-	0xb8, 0x4f, 0x05, 0x69, 0x95, 0x77, 0x05, 0x66, 0x8e, 0xc9, 0x0b, 0x46,
-	0x2e, 0xfd, 0x9a, 0x91, 0x4b, 0xa7, 0xcf, 0x2d, 0x90, 0x4b, 0x05, 0x2d,
-	0x97, 0x06, 0x05, 0xef, 0xa9, 0x02, 0xe4, 0xd2, 0x08, 0xbe, 0x3d, 0x2d,
-	0x97, 0x62, 0x62, 0x6d, 0x64, 0x89, 0x5e, 0xc5, 0xfe, 0x27, 0x4b, 0xae,
-	0xb6, 0xa5, 0x0a, 0xe3, 0xb0, 0x43, 0x4a, 0x23, 0x56, 0x67, 0x4b, 0xba,
-	0x49, 0x3a, 0x7a, 0x7e, 0x2a, 0xa1, 0x9d, 0x39, 0xdb, 0xcc, 0x3b, 0x8f,
-	0x5f, 0x54, 0x94, 0x61, 0x27, 0x20, 0xc3, 0x1e, 0xbe, 0x82, 0x0c, 0x43,
-	0x5e, 0x19, 0x79, 0x65, 0xb6, 0xfb, 0xdd, 0x9f, 0x0e, 0x79, 0x94, 0x1f,
-	0x94, 0x19, 0x90, 0x49, 0x25, 0xc8, 0xa4, 0x12, 0xe4, 0x54, 0x09, 0x72,
-	0xa9, 0x04, 0xb9, 0x54, 0x82, 0x5c, 0x2a, 0x41, 0x2e, 0x41, 0xc6, 0x3d,
-	0x0a, 0x19, 0x67, 0x64, 0xda, 0x00, 0xed, 0x35, 0xb9, 0xcf, 0xea, 0x77,
-	0x13, 0x27, 0xe9, 0xb2, 0x7e, 0x91, 0xd9, 0xb3, 0x7a, 0xae, 0x2a, 0x2e,
-	0xb8, 0xeb, 0x88, 0xe6, 0x77, 0xcf, 0x57, 0xd7, 0x3a, 0xdc, 0x1f, 0xf3,
-	0x03, 0xed, 0xb3, 0x6f, 0xe6, 0x6f, 0xa9, 0x03, 0x5f, 0xbf, 0x62, 0xf9,
-	0x7a, 0xf3, 0x1c, 0x5f, 0x27, 0x1d, 0xc6, 0x89, 0x97, 0xe7, 0xeb, 0x16,
-	0x9b, 0x97, 0x0f, 0x56, 0x80, 0xaf, 0x57, 0x2c, 0xe2, 0xeb, 0x28, 0xf8,
-	0x7a, 0xe7, 0x12, 0xbe, 0x5e, 0xe5, 0xf4, 0xea, 0x3a, 0x3c, 0x83, 0xc6,
-	0xef, 0x5a, 0x67, 0x9e, 0xaf, 0xf7, 0x6b, 0xbe, 0x3e, 0x04, 0xbe, 0xbe,
-	0xbe, 0x8a, 0xaf, 0x77, 0x4a, 0xf2, 0x96, 0x6c, 0x64, 0xa3, 0xec, 0xbe,
-	0x5f, 0x35, 0xaf, 0x91, 0x7f, 0x11, 0x53, 0xdf, 0xf0, 0x58, 0xef, 0x58,
-	0xb3, 0xe4, 0x1e, 0xfa, 0x11, 0xd7, 0x06, 0xc8, 0x23, 0x43, 0x19, 0xc7,
-	0x93, 0x83, 0x47, 0x7e, 0x20, 0xd3, 0x9a, 0xb7, 0x44, 0xf6, 0x1c, 0x89,
-	0xca, 0xf0, 0x11, 0xc6, 0x1e, 0xbe, 0x63, 0xe9, 0xbd, 0x4e, 0x86, 0x07,
-	0xb9, 0x5f, 0xd2, 0x95, 0xdd, 0x47, 0xe0, 0x63, 0x1d, 0x61, 0xec, 0xe1,
-	0xf2, 0x1c, 0x8f, 0x4d, 0x43, 0xb6, 0xec, 0x3e, 0xa2, 0xe7, 0x1a, 0xed,
-	0x34, 0xc8, 0xa1, 0x23, 0x22, 0xb7, 0x1d, 0x71, 0xe5, 0xf6, 0x23, 0x73,
-	0xbc, 0x36, 0x10, 0xf2, 0xda, 0x9f, 0x83, 0xd7, 0xda, 0x2d, 0xaf, 0xa9,
-	0x39, 0x5e, 0xfb, 0x5a, 0x15, 0xaf, 0xb1, 0x3e, 0x79, 0xed, 0x82, 0x4d,
-	0xe3, 0xb7, 0x2b, 0x7b, 0x8f, 0xb4, 0xca, 0xee, 0x87, 0xde, 0x22, 0x7b,
-	0xee, 0x27, 0xac, 0xe6, 0x9e, 0x3c, 0xda, 0x5f, 0xe3, 0x95, 0x76, 0xb4,
-	0x1f, 0xee, 0x0f, 0xd2, 0x77, 0x65, 0x75, 0x4e, 0x48, 0x32, 0xcf, 0xfe,
-	0x6a, 0xe1, 0x3b, 0x9f, 0x82, 0x4f, 0xb1, 0x17, 0x30, 0xdd, 0x7a, 0x44,
-	0x92, 0xae, 0xbc, 0x26, 0x23, 0xa9, 0x47, 0x5b, 0x8d, 0x3d, 0x71, 0x09,
-	0xbc, 0x42, 0xfa, 0xcf, 0x48, 0xee, 0xed, 0x81, 0xf6, 0x2b, 0x46, 0xcb,
-	0x42, 0xff, 0x9f, 0x31, 0x73, 0xc7, 0xdc, 0x77, 0xc7, 0xf3, 0xbe, 0x35,
-	0xfa, 0xbc, 0x9b, 0x8e, 0xd7, 0x76, 0x33, 0xbf, 0x46, 0xef, 0x37, 0xcd,
-	0xe9, 0xb3, 0xdc, 0xac, 0xcf, 0x76, 0x62, 0x3a, 0x9e, 0x5e, 0x28, 0xf3,
-	0x8e, 0x30, 0xde, 0xbd, 0xcc, 0xbb, 0x06, 0xff, 0xf8, 0x2a, 0x13, 0x9b,
-	0x25, 0xdf, 0x7d, 0xdd, 0xc9, 0x15, 0x2f, 0xe9, 0x7d, 0x85, 0x59, 0x1f,
-	0xbf, 0xcb, 0xfc, 0x66, 0xf9, 0x4b, 0x8c, 0x71, 0x24, 0x12, 0xea, 0x81,
-	0x56, 0xee, 0x3b, 0x18, 0x9c, 0x32, 0x76, 0x94, 0xe1, 0xd1, 0x06, 0xed,
-	0x6b, 0x8c, 0xe0, 0x7b, 0xf7, 0x68, 0xa3, 0x53, 0xa0, 0x6d, 0x32, 0xd0,
-	0xe0, 0xe4, 0xc7, 0xf7, 0xb4, 0x1a, 0x9b, 0x79, 0x20, 0xce, 0x3d, 0x85,
-	0x19, 0xb5, 0x54, 0x26, 0x9f, 0x92, 0x50, 0x26, 0x27, 0x6f, 0xc9, 0xc0,
-	0xb6, 0xce, 0x1d, 0xd1, 0xf7, 0xf7, 0x25, 0xda, 0x15, 0xc7, 0xf4, 0x09,
-	0xc8, 0xd7, 0x90, 0x16, 0xe2, 0xf2, 0xf1, 0x23, 0xa4, 0x07, 0x15, 0x6b,
-	0x94, 0xdf, 0xb2, 0xf4, 0x70, 0x59, 0x8a, 0x90, 0x3b, 0x47, 0x8e, 0xdc,
-	0x2e, 0xe3, 0xbb, 0x16, 0xd3, 0xc3, 0x9e, 0x79, 0x7a, 0x88, 0xc1, 0x3e,
-	0x73, 0xaa, 0xe9, 0xe1, 0x37, 0xe7, 0xe8, 0x61, 0xdc, 0xf9, 0xd7, 0xd2,
-	0xc3, 0x0d, 0x0b, 0xe8, 0x61, 0x44, 0xd3, 0x43, 0xff, 0x1c, 0x3d, 0x8c,
-	0x1c, 0x61, 0xbf, 0x7a, 0x5d, 0xd4, 0x9b, 0x71, 0x38, 0xe7, 0x73, 0xb4,
-	0x90, 0x18, 0xd6, 0xfb, 0x44, 0x93, 0x79, 0x9e, 0x25, 0x5d, 0xa5, 0x18,
-	0x1b, 0x99, 0x9f, 0xff, 0xc6, 0x7f, 0xd3, 0xf9, 0x7f, 0x47, 0xfc, 0xff,
-	0xef, 0xfc, 0x5f, 0x8f, 0xf6, 0x29, 0x8b, 0x43, 0x79, 0x1c, 0xd2, 0xc3,
-	0x7b, 0xe2, 0x46, 0x2f, 0x70, 0x8e, 0xf9, 0x6d, 0xf6, 0xac, 0x9f, 0x83,
-	0xfc, 0x7b, 0x1c, 0xf2, 0xef, 0xb1, 0x05, 0xeb, 0x01, 0x3d, 0x36, 0x06,
-	0x11, 0xc8, 0xc1, 0xd4, 0x3c, 0x3e, 0x66, 0xba, 0x89, 0x0f, 0xb3, 0xf7,
-	0xe4, 0x6c, 0x65, 0x31, 0x4e, 0x5c, 0xbd, 0xdf, 0xe8, 0x64, 0xaa, 0x1a,
-	0x27, 0x84, 0x7b, 0xb6, 0x6a, 0x8c, 0xf8, 0x5d, 0xe6, 0xf7, 0x65, 0xbd,
-	0x87, 0xa4, 0xa0, 0xd7, 0x9f, 0x88, 0x17, 0xae, 0x3f, 0x11, 0x27, 0xae,
-	0xb6, 0xf7, 0x0b, 0xe5, 0x3a, 0xbd, 0x2f, 0xfc, 0xc0, 0x54, 0x4c, 0x66,
-	0x62, 0x8c, 0xeb, 0xf1, 0xde, 0x57, 0xfa, 0xca, 0x7e, 0xbc, 0x20, 0x79,
-	0x7b, 0xd6, 0x67, 0x95, 0xa5, 0x6d, 0xc6, 0x03, 0x79, 0x27, 0x42, 0xb8,
-	0x0e, 0xd1, 0x69, 0x65, 0x5d, 0x43, 0x55, 0x9c, 0x12, 0x78, 0x1f, 0x93,
-	0x44, 0xb6, 0x1b, 0xef, 0x29, 0xf6, 0xfd, 0xa4, 0x8c, 0x3c, 0x58, 0x86,
-	0x2d, 0xf7, 0x30, 0x74, 0x8e, 0x23, 0x10, 0x93, 0xfa, 0x2e, 0x14, 0xc2,
-	0x30, 0xa1, 0xef, 0xf5, 0xa3, 0xdf, 0x47, 0x7a, 0x88, 0xe3, 0xfb, 0xb2,
-	0x8d, 0x25, 0xc5, 0xa5, 0x50, 0xfc, 0x01, 0xe0, 0xe7, 0x1d, 0x94, 0x3f,
-	0xc2, 0xfb, 0x8d, 0xe6, 0xc3, 0xf8, 0x21, 0x03, 0xfa, 0xcd, 0xb9, 0x79,
-	0xcd, 0xc9, 0x94, 0xcd, 0xfe, 0x96, 0xaa, 0xfb, 0xf5, 0xe5, 0xb0, 0xb6,
-	0x9f, 0xd3, 0x76, 0x5f, 0x0b, 0xcf, 0xe7, 0x19, 0x1b, 0xfa, 0xcb, 0xb0,
-	0xa1, 0x9f, 0xa8, 0x64, 0xf4, 0x1a, 0xd6, 0x63, 0xb0, 0xa1, 0x1f, 0x85,
-	0xee, 0xa1, 0xce, 0x89, 0x59, 0x9d, 0x33, 0xa2, 0x76, 0x69, 0x9d, 0xf3,
-	0xd7, 0x5a, 0xe7, 0xfc, 0xea, 0x12, 0x9d, 0x73, 0x48, 0xb5, 0x8f, 0x52,
-	0xe7, 0xf4, 0xaa, 0x9d, 0x0e, 0xed, 0xc5, 0xb5, 0xcb, 0xe8, 0x9c, 0xf7,
-	0xca, 0xaf, 0xd8, 0xbc, 0xfd, 0xf2, 0xbe, 0x6d, 0x7a, 0xdd, 0xc6, 0x9b,
-	0x50, 0xbc, 0xcb, 0xce, 0xe8, 0xa0, 0xeb, 0x55, 0xa7, 0x5e, 0xef, 0xfd,
-	0x6a, 0x95, 0xce, 0x69, 0x53, 0xdd, 0x4e, 0xaf, 0xae, 0xc3, 0x78, 0x04,
-	0xbf, 0x53, 0x4e, 0x66, 0xa0, 0x0e, 0xdf, 0x71, 0x89, 0x1c, 0xc1, 0xd8,
-	0xcd, 0x7d, 0x7b, 0xca, 0xe4, 0x5d, 0x63, 0xf3, 0x54, 0x98, 0xee, 0x9a,
-	0xf4, 0x76, 0x9b, 0x6e, 0x74, 0x55, 0x9b, 0x6a, 0xd5, 0xba, 0x6a, 0x33,
-	0x18, 0x6a, 0x02, 0xfa, 0x75, 0xa2, 0x14, 0xea, 0x2c, 0xfe, 0x66, 0xbc,
-	0x99, 0x71, 0x89, 0x30, 0x6e, 0x9d, 0x40, 0x19, 0x3c, 0xa5, 0xd0, 0xa6,
-	0xe4, 0x6f, 0xf8, 0x0a, 0x78, 0xa6, 0x80, 0xd7, 0x5b, 0xc0, 0x3f, 0xbf,
-	0x5e, 0x64, 0xdc, 0xb3, 0x59, 0x8e, 0x8e, 0x55, 0xe7, 0xb5, 0xca, 0xbb,
-	0xc7, 0x36, 0xc8, 0xbe, 0x51, 0xff, 0x6a, 0xa9, 0xdf, 0x28, 0x23, 0xa3,
-	0x2f, 0xea, 0xfb, 0x40, 0xd6, 0xe8, 0x7b, 0x92, 0x78, 0x7f, 0x98, 0x91,
-	0x91, 0xfd, 0x8e, 0x91, 0x91, 0x19, 0x35, 0x6f, 0xb3, 0x86, 0x6d, 0xf2,
-	0x6e, 0xa6, 0xbe, 0xd1, 0xb8, 0xbe, 0x43, 0x7a, 0xa2, 0x72, 0xad, 0xfc,
-	0xd1, 0x71, 0x75, 0xa7, 0x9a, 0xbf, 0x4b, 0x41, 0xdb, 0xac, 0x93, 0x0b,
-	0x6c, 0xd6, 0xbf, 0x97, 0x99, 0xf7, 0x45, 0x31, 0x4e, 0xd0, 0xf0, 0x75,
-	0x2f, 0x73, 0x1d, 0xb4, 0x39, 0x26, 0x97, 0xa4, 0x4f, 0xe3, 0x8f, 0xf2,
-	0xb4, 0x01, 0x72, 0x70, 0x56, 0xeb, 0xd7, 0xb5, 0xbc, 0xf3, 0xf8, 0x08,
-	0x6d, 0xd7, 0xaf, 0x6b, 0x79, 0xb6, 0xd6, 0xda, 0xae, 0xd3, 0x90, 0xd3,
-	0x94, 0xa3, 0x37, 0xca, 0x5f, 0xdb, 0x74, 0xa6, 0x25, 0xe3, 0xb3, 0x42,
-	0x7d, 0x17, 0x83, 0x0c, 0xa5, 0x3c, 0xfd, 0x59, 0x6d, 0xd7, 0xe7, 0x6c,
-	0x1b, 0x94, 0x9f, 0x46, 0x76, 0x6f, 0x76, 0xa6, 0x6d, 0x1a, 0xbf, 0xc3,
-	0x18, 0xba, 0x9f, 0xc9, 0x59, 0x3e, 0x53, 0xce, 0x93, 0xc8, 0x5f, 0x83,
-	0x7c, 0xf2, 0xd9, 0x63, 0x9a, 0xcf, 0xb4, 0x7d, 0xe2, 0x74, 0xd9, 0x35,
-	0x85, 0xb9, 0xf5, 0x80, 0x3c, 0xf9, 0x4c, 0x1d, 0xf5, 0xa6, 0x8d, 0x3c,
-	0xf0, 0x90, 0xfe, 0x45, 0xe8, 0x0e, 0xd6, 0x45, 0xfa, 0xb1, 0x0c, 0xe6,
-	0xf0, 0x24, 0xfc, 0x9f, 0x46, 0x7c, 0x37, 0xe3, 0x7b, 0x42, 0x7e, 0x75,
-	0x30, 0xaa, 0xc7, 0x3d, 0x82, 0x71, 0x1c, 0x38, 0x82, 0x31, 0x39, 0xc6,
-	0x76, 0x76, 0xcf, 0xb8, 0x52, 0x73, 0x86, 0x7c, 0xc7, 0x33, 0x86, 0x41,
-	0xb0, 0xb7, 0x8b, 0x74, 0x9b, 0xf4, 0xfa, 0xf5, 0xf9, 0xb7, 0xcd, 0xf1,
-	0x08, 0x70, 0x72, 0x00, 0xf3, 0x31, 0x52, 0xf4, 0xbd, 0xac, 0xe3, 0xc7,
-	0x31, 0x4e, 0xd8, 0x80, 0xed, 0xb0, 0x05, 0xdb, 0x61, 0x07, 0xb6, 0xc3,
-	0x0e, 0x5c, 0x2d, 0xa7, 0xb6, 0x72, 0x7f, 0x49, 0xfe, 0x9d, 0xbc, 0x77,
-	0xf9, 0x1b, 0x3a, 0x36, 0x5f, 0x7b, 0x4b, 0x1f, 0x7c, 0x76, 0xf1, 0x92,
-	0x03, 0xdc, 0x63, 0x3f, 0xeb, 0xd5, 0xde, 0xd2, 0x2f, 0xed, 0x3d, 0xc8,
-	0xef, 0xb9, 0x24, 0x1d, 0xb7, 0x7c, 0xd8, 0xa9, 0x1d, 0xe8, 0x03, 0x1e,
-	0x33, 0x4e, 0x32, 0x3e, 0xe4, 0x30, 0x4e, 0x91, 0xdd, 0x1c, 0xd1, 0x67,
-	0xc4, 0xa6, 0x19, 0x8b, 0xb8, 0xa5, 0x3d, 0xb2, 0x25, 0xb1, 0xdb, 0x49,
-	0x0e, 0xa8, 0x48, 0x72, 0xa0, 0xcf, 0x09, 0xcb, 0xf1, 0x0e, 0x6a, 0xc8,
-	0x19, 0xc0, 0x7a, 0xa0, 0xf4, 0x75, 0xd0, 0xd3, 0x79, 0x29, 0x1c, 0x6f,
-	0x90, 0xa9, 0x62, 0xbb, 0x97, 0x55, 0x31, 0xe1, 0xbe, 0x12, 0x75, 0x0a,
-	0x44, 0x7f, 0x26, 0x2a, 0x13, 0xa3, 0x1b, 0x45, 0x69, 0xdb, 0xbd, 0x45,
-	0xb2, 0x63, 0xa3, 0x72, 0xbe, 0x5b, 0x9a, 0x14, 0xda, 0xe7, 0xdd, 0xde,
-	0xea, 0x14, 0xd7, 0x11, 0x43, 0x5e, 0x58, 0x4f, 0x3e, 0x19, 0x05, 0x0e,
-	0x41, 0xb7, 0x8c, 0xeb, 0xd6, 0x09, 0xe5, 0xde, 0xed, 0x3a, 0x66, 0xca,
-	0x38, 0x6d, 0xf5, 0x7a, 0x03, 0xf9, 0x23, 0xba, 0x2c, 0x7f, 0x4c, 0x96,
-	0xb8, 0x36, 0x23, 0x79, 0x97, 0x71, 0x61, 0x1f, 0xbf, 0xc7, 0x59, 0xb6,
-	0x4e, 0x46, 0xba, 0xf3, 0x76, 0x8f, 0xc7, 0x37, 0xc1, 0x07, 0x1c, 0x9f,
-	0x5e, 0x27, 0x01, 0xaf, 0x2f, 0x5e, 0xcf, 0x88, 0x56, 0xc9, 0x03, 0x47,
-	0x66, 0x46, 0xc3, 0xf5, 0x0f, 0xb6, 0x87, 0xef, 0x71, 0x23, 0x6f, 0xb3,
-	0x4b, 0xea, 0x11, 0x2e, 0xae, 0x55, 0x2e, 0x94, 0xb1, 0x4a, 0x9f, 0x13,
-	0xf6, 0xb4, 0x7c, 0x3d, 0x5d, 0x31, 0xb2, 0x75, 0xbc, 0x12, 0xea, 0x96,
-	0xa8, 0xd1, 0xa5, 0x4b, 0xf4, 0x89, 0x89, 0x60, 0xce, 0xeb, 0x93, 0x4b,
-	0x3a, 0x46, 0xf7, 0x6b, 0x53, 0x2d, 0xe2, 0x1e, 0x93, 0xd9, 0x11, 0xff,
-	0x54, 0x2b, 0xf7, 0x69, 0x8c, 0xa4, 0xde, 0x8c, 0x7e, 0x8c, 0xb5, 0x50,
-	0x1f, 0x0e, 0xa9, 0xb5, 0x78, 0xaf, 0xd1, 0xf4, 0x07, 0x9e, 0xc2, 0xb7,
-	0xf1, 0x13, 0xbe, 0x0c, 0x3f, 0xe1, 0x09, 0xe8, 0xba, 0x73, 0xf0, 0x13,
-	0x1e, 0x87, 0x9f, 0xf0, 0x18, 0xfc, 0x84, 0x47, 0xa1, 0x27, 0xab, 0xfd,
-	0x83, 0xe1, 0x05, 0xfe, 0x41, 0xa0, 0xf9, 0x9f, 0x31, 0xc0, 0xc7, 0xab,
-	0x7c, 0x83, 0xbd, 0x46, 0x5f, 0xc1, 0xef, 0x37, 0x7c, 0xd4, 0xa6, 0x6e,
-	0xd6, 0xfa, 0xd1, 0xec, 0xd9, 0x1d, 0x98, 0xd3, 0x57, 0x6d, 0xca, 0xe8,
-	0xab, 0x89, 0x79, 0x7d, 0x65, 0xf8, 0xe8, 0xd8, 0xa8, 0x44, 0xfc, 0xd1,
-	0xe9, 0x6c, 0x6a, 0xbb, 0xe6, 0xa1, 0x26, 0x7f, 0xa3, 0x44, 0x1e, 0x50,
-	0xcd, 0x35, 0x92, 0xb5, 0xdf, 0xa0, 0xaf, 0xa3, 0x5f, 0x47, 0x5b, 0xef,
-	0x94, 0x9c, 0xb6, 0xcf, 0xae, 0x8c, 0xef, 0x47, 0x17, 0xe1, 0xbb, 0x50,
-	0x7a, 0x56, 0xe3, 0xfc, 0x7e, 0x7d, 0x26, 0xbf, 0x41, 0x86, 0xcb, 0x21,
-	0xce, 0x79, 0x06, 0x8e, 0xfb, 0x30, 0x5a, 0x25, 0x72, 0xac, 0x45, 0xfa,
-	0x53, 0xa2, 0x72, 0xa9, 0x95, 0x7a, 0xff, 0xca, 0xa9, 0x6e, 0x89, 0xe7,
-	0xba, 0x49, 0xab, 0xf7, 0xc9, 0x84, 0x9e, 0x8b, 0x16, 0xa9, 0x39, 0x46,
-	0x1b, 0x25, 0x5c, 0xc3, 0xbb, 0xbd, 0xc5, 0xde, 0x41, 0x1d, 0x35, 0xe5,
-	0x44, 0x0e, 0xea, 0xf9, 0x9a, 0xd5, 0x7b, 0x0c, 0x6f, 0x9e, 0x62, 0x2c,
-	0x9e, 0xf7, 0xfd, 0x31, 0x0e, 0xff, 0xaf, 0x99, 0xbf, 0x42, 0x8b, 0xb1,
-	0x67, 0xd6, 0x58, 0x3b, 0xc6, 0xc4, 0xa9, 0x96, 0xb7, 0x61, 0xd8, 0x4e,
-	0xf5, 0x1d, 0xb5, 0xab, 0xe0, 0x03, 0x37, 0xa0, 0x4d, 0xae, 0x63, 0xdb,
-	0xbf, 0x17, 0xe4, 0xfd, 0xb3, 0x73, 0xc0, 0x5f, 0x85, 0xb4, 0x06, 0xe4,
-	0x31, 0x66, 0xf3, 0x85, 0x16, 0xc6, 0x65, 0xb3, 0x7e, 0xa3, 0x4d, 0x5b,
-	0xe5, 0x8c, 0x8c, 0xb6, 0xc3, 0x37, 0xe7, 0x39, 0x76, 0xe6, 0xf7, 0x73,
-	0xee, 0x84, 0x7f, 0xab, 0x69, 0x12, 0xf2, 0x67, 0x8f, 0x5c, 0x6b, 0xe3,
-	0xce, 0xd4, 0xc3, 0xbf, 0xb8, 0x60, 0xbd, 0xf6, 0x10, 0xf4, 0xd8, 0xad,
-	0x90, 0x47, 0xd4, 0xc3, 0x87, 0xe4, 0x17, 0x2c, 0x3d, 0x2f, 0xd4, 0xc3,
-	0x17, 0x85, 0xb1, 0xe1, 0x2e, 0xe4, 0xe5, 0x83, 0x28, 0xe8, 0xe1, 0x70,
-	0x95, 0xaf, 0x46, 0xbf, 0xaf, 0x2e, 0x6d, 0xd6, 0xc0, 0x16, 0xfa, 0x7d,
-	0x90, 0x03, 0xb1, 0xd0, 0xcf, 0xab, 0x9d, 0x5b, 0xa3, 0xdd, 0x69, 0xeb,
-	0x8e, 0xa4, 0x5e, 0x22, 0x8e, 0x12, 0x87, 0xe4, 0xf6, 0xf5, 0xbc, 0x26,
-	0xcf, 0xf5, 0xbf, 0xa5, 0x71, 0x26, 0x8a, 0xb4, 0xb7, 0x46, 0xc3, 0x68,
-	0xe5, 0x7c, 0x22, 0xdc, 0xbf, 0x51, 0xb0, 0x75, 0xf7, 0xd8, 0xf5, 0xf8,
-	0x82, 0x7c, 0x9b, 0x71, 0xce, 0x44, 0x5f, 0x64, 0x25, 0xcf, 0x64, 0xa3,
-	0xee, 0xed, 0xda, 0x6f, 0xcf, 0x48, 0xd8, 0x16, 0xbf, 0x6b, 0xaa, 0xda,
-	0xa6, 0x1d, 0xc5, 0xf7, 0xe2, 0xfb, 0x1b, 0x9e, 0xd7, 0x6b, 0x8b, 0xe6,
-	0x6e, 0x9a, 0x90, 0x4f, 0xc8, 0x3b, 0x09, 0x7d, 0x8e, 0xc9, 0x3f, 0x46,
-	0xbb, 0x87, 0xeb, 0xae, 0xde, 0xf4, 0x70, 0xea, 0x23, 0xfa, 0x0e, 0xd5,
-	0x71, 0x11, 0xa7, 0x90, 0xda, 0xab, 0xf7, 0x9d, 0x14, 0x74, 0x7c, 0x39,
-	0x8f, 0xf7, 0xbc, 0x8f, 0xda, 0x76, 0x8c, 0x7f, 0x0b, 0x88, 0x69, 0x1f,
-	0x04, 0x6c, 0xd4, 0x21, 0x94, 0xbd, 0x31, 0x69, 0x3b, 0xfa, 0x7e, 0xcd,
-	0x0b, 0x6b, 0xe1, 0x0b, 0xf4, 0x1e, 0x85, 0xae, 0x3e, 0x1a, 0x97, 0xfe,
-	0xa3, 0x5a, 0x37, 0x66, 0x96, 0xc6, 0x0a, 0xb6, 0x78, 0x2e, 0xfd, 0x89,
-	0x98, 0x27, 0xd7, 0x1c, 0x8d, 0xc8, 0xe1, 0xd8, 0x16, 0xaf, 0xc3, 0xb9,
-	0xd1, 0xea, 0x42, 0x43, 0x7f, 0xa0, 0x15, 0xd4, 0x37, 0xeb, 0x90, 0xbd,
-	0xf3, 0xb1, 0x6b, 0xd4, 0x7f, 0x49, 0x46, 0xc8, 0x4b, 0x95, 0x88, 0x8c,
-	0x0f, 0xb6, 0x02, 0x9e, 0xb7, 0xae, 0x07, 0x0e, 0x40, 0x53, 0x98, 0x1f,
-	0xfd, 0xf7, 0x3c, 0xdc, 0x38, 0xe5, 0x57, 0x1b, 0xfa, 0xef, 0x3b, 0x4a,
-	0x1d, 0xe6, 0x6b, 0xbe, 0x46, 0xbf, 0x5e, 0x8d, 0xf6, 0x3d, 0xc8, 0x8b,
-	0x6f, 0x11, 0xff, 0x01, 0xc8, 0xb5, 0xa3, 0x51, 0xe9, 0x38, 0xda, 0x20,
-	0x9b, 0x8e, 0xd2, 0xf7, 0xa8, 0xf6, 0x45, 0x69, 0x8b, 0x5e, 0xc2, 0xb8,
-	0x6e, 0x34, 0xf7, 0x0d, 0x4e, 0x45, 0x65, 0x1f, 0xf9, 0x15, 0x65, 0x73,
-	0xb0, 0x93, 0xb3, 0x47, 0x3d, 0xbd, 0x16, 0x9a, 0xc5, 0x38, 0xf9, 0x37,
-	0x2c, 0xfa, 0x8e, 0x1a, 0x39, 0x53, 0xa0, 0x6f, 0x32, 0xd0, 0x02, 0xbc,
-	0x3e, 0x60, 0xf9, 0xe5, 0x3d, 0xeb, 0x2d, 0x5f, 0xfe, 0x9c, 0xfc, 0x96,
-	0x5b, 0x6f, 0xe4, 0xe5, 0x87, 0xd6, 0x73, 0x2f, 0xd2, 0x5a, 0x9f, 0xef,
-	0x3a, 0x6d, 0x43, 0x18, 0xb9, 0xf9, 0x7a, 0xfc, 0x27, 0xc0, 0x51, 0xb8,
-	0xfe, 0x44, 0x3e, 0xe4, 0x1a, 0xb2, 0x3e, 0xb3, 0x92, 0x9a, 0xd1, 0x7f,
-	0x53, 0x89, 0x6b, 0x61, 0xf3, 0xf7, 0x59, 0x6d, 0xaf, 0x30, 0x36, 0xfe,
-	0x4c, 0xf8, 0x37, 0x9c, 0xaa, 0xf6, 0x19, 0x56, 0xaf, 0x75, 0x31, 0xbe,
-	0x34, 0xb7, 0x17, 0x28, 0x18, 0xd5, 0x77, 0xc2, 0xc5, 0x9c, 0x8b, 0xc5,
-	0x5a, 0xe7, 0x9b, 0x63, 0x12, 0xb8, 0x7e, 0xdc, 0xf9, 0x96, 0xcf, 0xb5,
-	0x71, 0xcf, 0x79, 0xb9, 0xe8, 0x83, 0xf7, 0xfe, 0x02, 0xe3, 0x68, 0x75,
-	0x5e, 0xc1, 0x9c, 0x1e, 0x2c, 0x65, 0x92, 0x9e, 0x8d, 0x83, 0x3f, 0x5b,
-	0x6c, 0x75, 0x9e, 0x9b, 0x8f, 0x21, 0xf5, 0x84, 0x74, 0x71, 0x88, 0x79,
-	0x65, 0xe4, 0x95, 0x19, 0xeb, 0xad, 0x77, 0x26, 0xc7, 0xec, 0x7e, 0x12,
-	0xa3, 0x8b, 0xe6, 0xd6, 0x5f, 0x06, 0xf4, 0xfa, 0x84, 0xeb, 0x4c, 0x4e,
-	0x4d, 0xaf, 0x37, 0xfb, 0x8a, 0x6a, 0x91, 0x67, 0xf6, 0x58, 0x4e, 0x4c,
-	0xd5, 0xa2, 0x4c, 0xbd, 0x33, 0xa1, 0x63, 0x5e, 0xda, 0xf6, 0x70, 0xc6,
-	0xa7, 0xea, 0x9d, 0x29, 0xbd, 0xd6, 0x1c, 0x75, 0x4e, 0x8e, 0xb1, 0xed,
-	0x28, 0xca, 0x88, 0x73, 0x0a, 0xed, 0x4d, 0x8d, 0xb5, 0xc7, 0xf7, 0x49,
-	0x3b, 0x6c, 0x01, 0xfe, 0x8d, 0x34, 0xde, 0x17, 0xe0, 0x3a, 0x53, 0x73,
-	0xed, 0x2a, 0xb4, 0xc3, 0xb2, 0xa4, 0x41, 0xf6, 0xeb, 0xa2, 0xfd, 0xa5,
-	0x6b, 0x52, 0x4b, 0x71, 0x32, 0x06, 0x9c, 0x1c, 0xb4, 0x38, 0x39, 0x61,
-	0x71, 0x32, 0x5a, 0x85, 0x93, 0x87, 0x17, 0xe1, 0xe4, 0x04, 0x70, 0xf2,
-	0xf0, 0x15, 0x70, 0x82, 0xbc, 0xf2, 0xc3, 0x16, 0x27, 0xf7, 0x2d, 0xc2,
-	0x49, 0x7e, 0x2e, 0x16, 0x6f, 0x70, 0x32, 0x02, 0x9c, 0xd4, 0xb4, 0x1a,
-	0xd8, 0x0f, 0x5a, 0x9c, 0xe0, 0x3d, 0x75, 0x10, 0x65, 0xee, 0xab, 0xc2,
-	0xc9, 0x41, 0xe0, 0xe4, 0x3e, 0x8b, 0x93, 0xc3, 0x16, 0x27, 0x87, 0x51,
-	0x26, 0x0f, 0x9c, 0x14, 0x96, 0xc1, 0xc9, 0x08, 0x70, 0x12, 0xb6, 0x5b,
-	0x40, 0x3b, 0x87, 0xab, 0x70, 0x32, 0xb2, 0x0c, 0x4e, 0xb8, 0xe6, 0x1a,
-	0xee, 0xe1, 0xbe, 0xfc, 0x06, 0x7b, 0xb8, 0x53, 0x9f, 0x7d, 0xe3, 0x3d,
-	0xdc, 0x2c, 0x73, 0xb9, 0xea, 0xcc, 0xfb, 0xb3, 0x76, 0x4f, 0x9a, 0xd9,
-	0xfb, 0x37, 0x7f, 0x0f, 0x5e, 0x3b, 0xf8, 0xbc, 0x90, 0xf7, 0xc4, 0xec,
-	0x21, 0x75, 0xb7, 0x4d, 0x81, 0xd7, 0x8e, 0xca, 0x81, 0xe3, 0xb5, 0x87,
-	0x73, 0x36, 0xcd, 0xdf, 0xd6, 0x9e, 0x57, 0x8a, 0x79, 0xe1, 0xde, 0x83,
-	0x17, 0xcd, 0x5d, 0x50, 0x31, 0x9e, 0xc7, 0xa8, 0x5e, 0x7b, 0x7e, 0xd1,
-	0xde, 0x55, 0xe4, 0xdd, 0x9b, 0xf5, 0xa7, 0x13, 0xdc, 0x57, 0x55, 0xd0,
-	0xf0, 0x72, 0x2d, 0xad, 0x47, 0xef, 0xa5, 0xca, 0x16, 0x69, 0x67, 0x27,
-	0xb8, 0x27, 0x0d, 0xf6, 0x31, 0xf7, 0xed, 0x9a, 0x7d, 0xba, 0xbd, 0x0b,
-	0xf6, 0xe9, 0x56, 0x9f, 0xef, 0x26, 0xdf, 0xcd, 0xd3, 0xcd, 0xc1, 0xb9,
-	0xbb, 0x57, 0x8f, 0x3b, 0xcf, 0xe8, 0xf8, 0x70, 0x3d, 0xe6, 0x27, 0x08,
-	0x4e, 0xa7, 0x4c, 0x5c, 0x76, 0x46, 0xc7, 0x65, 0x05, 0x1e, 0xf8, 0xb0,
-	0x8d, 0xcd, 0x76, 0xf4, 0x5c, 0x9e, 0x8b, 0xcb, 0x2e, 0xd8, 0xa3, 0xa3,
-	0xef, 0xff, 0xc8, 0x8e, 0x5e, 0xd2, 0x7b, 0x71, 0xfa, 0x52, 0x8e, 0x14,
-	0x20, 0x23, 0xf6, 0x8c, 0xbf, 0x2a, 0xc3, 0x0f, 0xf2, 0x9b, 0x3a, 0x2d,
-	0x02, 0xbd, 0x45, 0xb9, 0x9d, 0x97, 0x6c, 0x0f, 0xd3, 0x4c, 0x9d, 0x3e,
-	0xed, 0x23, 0x1f, 0x77, 0x7a, 0xe7, 0xfa, 0x27, 0x7e, 0xc3, 0x35, 0x70,
-	0xfe, 0xa6, 0x9d, 0x93, 0x71, 0xb2, 0x15, 0xe6, 0x87, 0x6b, 0xe1, 0x77,
-	0xdb, 0xfb, 0x08, 0x99, 0x5f, 0x7d, 0xff, 0xb5, 0xe1, 0xd3, 0xac, 0xfe,
-	0x3b, 0x22, 0x23, 0x4e, 0x1f, 0xea, 0x4c, 0x7b, 0x0d, 0x03, 0x2a, 0x7d,
-	0xd3, 0x00, 0xcf, 0xca, 0x4d, 0x2c, 0xf9, 0xfb, 0x01, 0xf3, 0xba, 0xb0,
-	0xa0, 0xe7, 0x94, 0xfb, 0xb0, 0xa6, 0x41, 0x8b, 0x9a, 0xb6, 0x34, 0xfd,
-	0x1f, 0x98, 0xd3, 0x91, 0xd4, 0xad, 0xd4, 0x93, 0xa1, 0x8e, 0x4c, 0xc6,
-	0xfb, 0x78, 0x7f, 0x84, 0xa6, 0x71, 0x7b, 0x97, 0xc4, 0xd4, 0x39, 0xad,
-	0xdf, 0x47, 0x52, 0xbc, 0x5f, 0x66, 0x99, 0xb2, 0xa3, 0x55, 0x65, 0xf5,
-	0xb8, 0x3d, 0xf9, 0x43, 0xcc, 0xcd, 0x17, 0x61, 0x6f, 0xf6, 0x8e, 0xbd,
-	0x0a, 0x9f, 0x31, 0x2e, 0x5f, 0x2a, 0xbd, 0x04, 0x7a, 0xcd, 0xaf, 0xb5,
-	0x77, 0xe1, 0x65, 0x01, 0x37, 0xcf, 0x38, 0xeb, 0xfd, 0xc3, 0x91, 0x3f,
-	0x02, 0x5d, 0xfc, 0xc1, 0x4b, 0xec, 0x03, 0xb0, 0x44, 0x60, 0xcf, 0xc3,
-	0x36, 0x18, 0x7f, 0x49, 0xef, 0x95, 0xbb, 0xbe, 0xfc, 0x92, 0x8e, 0x53,
-	0xf4, 0x97, 0x5b, 0x65, 0x7b, 0xb9, 0x41, 0x76, 0x40, 0x2f, 0xec, 0x28,
-	0xfb, 0x78, 0xa2, 0x72, 0x63, 0xd9, 0xcc, 0xd3, 0x47, 0xca, 0x9c, 0xef,
-	0x6d, 0x32, 0x71, 0xbc, 0x9a, 0x66, 0xa7, 0xed, 0xde, 0x31, 0xd2, 0x0f,
-	0x9e, 0x52, 0x32, 0x3f, 0xad, 0xc7, 0xce, 0x5d, 0xac, 0xc9, 0xc3, 0xb3,
-	0xc2, 0xbd, 0xf8, 0xfc, 0x1b, 0x74, 0xdf, 0x68, 0xe5, 0x19, 0x77, 0xde,
-	0x8f, 0xd8, 0x5f, 0x09, 0xf7, 0x86, 0xbf, 0xfe, 0x19, 0x10, 0xfd, 0x77,
-	0x5d, 0xf4, 0xde, 0x70, 0x4d, 0x7b, 0xd2, 0x76, 0x26, 0xa6, 0x75, 0x84,
-	0xa1, 0xf1, 0xf9, 0xbf, 0xe7, 0x22, 0xf2, 0x7f, 0x01, 0x95, 0xf6, 0x2d,
-	0x58, 0xd0, 0x73, 0x00, 0x00, 0x00 };
-static u32 bnx2_CP_b09FwData[(0x50/4) + 1] = {
-	0x00010030, 0x00000030, 0x00000000, 0x00000001, 0x00010fd0, 0x00000fd0,
-	0x00001430, 0x0000007f, 0x00030400, 0x00001000, 0x00000030, 0x00000020,
-	0x00050200, 0x00001000, 0x00000030, 0x00000010, 0x00010400, 0x00000400,
-	0x00001030, 0x00000020, 0x00000000 };
-static u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
-	0x080005d8, 0x080007f8, 0x0800073c, 0x08000764, 0x0800078c, 0x080007b4,
-	0x08000610, 0x080005fc, 0x08000820, 0x08000820, 0x0800062c, 0x08000648,
-	0x08000648, 0x08000820, 0x08000660, 0x08000674, 0x08000820, 0x08000688,
-	0x08000820, 0x08000820, 0x0800069c, 0x08000820, 0x08000820, 0x08000820,
-	0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820,
-	0x08000820, 0x080006b0, 0x08000820, 0x080006c4, 0x080006d8, 0x080006ec,
-	0x08000820, 0x08000700, 0x08000714, 0x08000728, 0x08003740, 0x08003758,
-	0x08003768, 0x08003778, 0x08003790, 0x080037a8, 0x080037b8, 0x080037c8,
-	0x080037e8, 0x080037f8, 0x08003808, 0x08003898, 0x080037d8, 0x08003818,
-	0x08003828, 0x08003840, 0x08003860, 0x08003898, 0x08003878, 0x08003878,
-	0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x08005618,
-	0x08005618, 0x08005640, 0x08005690, 0x08005660, 0x00000000 };
-static u32 bnx2_CP_b09FwBss[(0x870/4) + 1] = { 0x0 };
-static u32 bnx2_CP_b09FwSbss[(0xe9/4) + 1] = { 0x0 };
+	0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d,
+	0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59,
+	0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22,
+	0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12,
+	0x02, 0xab, 0x10, 0x43, 0xb3, 0x1c, 0x4a, 0xc5, 0x48, 0x4e, 0x02, 0x04,
+	0xea, 0x40, 0xe8, 0x86, 0xdd, 0xec, 0x66, 0x32, 0x92, 0x3f, 0x9a, 0x8e,
+	0x3d, 0x93, 0x44, 0x89, 0xbd, 0xdd, 0x9c, 0xad, 0x90, 0x14, 0x3b, 0x74,
+	0x07, 0x4f, 0xe2, 0x98, 0x96, 0x73, 0x0a, 0x8d, 0x50, 0x8c, 0x9b, 0xe6,
+	0xb0, 0xdd, 0xd0, 0xa6, 0x34, 0xdb, 0x86, 0x22, 0x8c, 0x81, 0xf4, 0x2c,
+	0xdd, 0x86, 0x42, 0x77, 0xd3, 0x36, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d,
+	0x9a, 0x91, 0x34, 0xce, 0x07, 0xdd, 0xad, 0xcf, 0x79, 0x7e, 0xf3, 0xee,
+	0xbb, 0x1f, 0xff, 0xfb, 0xbf, 0xff, 0xef, 0xfb, 0xbf, 0x4f, 0x97, 0x8b,
+	0x34, 0x8b, 0xfd, 0xb7, 0x01, 0xd7, 0xd5, 0xc9, 0xfd, 0xe3, 0x57, 0x5f,
+	0x39, 0x70, 0x25, 0x9f, 0xa3, 0x91, 0x68, 0x44, 0xde, 0xc4, 0xbf, 0xe4,
+	0x1b, 0xa8, 0x83, 0x0e, 0xdd, 0x70, 0x2c, 0x5e, 0x12, 0x53, 0x43, 0xde,
+	0xfe, 0x8c, 0x27, 0xb1, 0xc8, 0x50, 0xee, 0xce, 0x71, 0x4f, 0x24, 0x5d,
+	0xee, 0x4b, 0x0e, 0xcb, 0x3f, 0x05, 0xb9, 0x78, 0x54, 0x58, 0xfe, 0x96,
+	0xa1, 0x57, 0x7f, 0xeb, 0x2b, 0xff, 0x2a, 0xf5, 0xf2, 0x4c, 0x44, 0x62,
+	0xee, 0xd0, 0xed, 0xe2, 0x6e, 0x93, 0x58, 0xe7, 0x50, 0x72, 0xff, 0x23,
+	0xdb, 0x97, 0x44, 0x5a, 0xc3, 0xbe, 0x5e, 0x0a, 0xbe, 0xb2, 0x5d, 0x72,
+	0x1d, 0x43, 0x89, 0xb1, 0x86, 0x21, 0x57, 0x9e, 0xaa, 0xc8, 0xe8, 0x89,
+	0xc2, 0xcb, 0x41, 0x74, 0x28, 0x88, 0x4c, 0x0d, 0x38, 0x12, 0x19, 0x92,
+	0xb3, 0xe3, 0x03, 0xf7, 0x04, 0xca, 0xf3, 0xfc, 0x45, 0x69, 0x19, 0x3c,
+	0x37, 0x80, 0xf7, 0x65, 0x41, 0xdd, 0xbd, 0xd7, 0x9c, 0x28, 0xc4, 0x44,
+	0x0d, 0xf5, 0xbc, 0x90, 0x89, 0x5c, 0x25, 0x7c, 0x7f, 0x56, 0x7a, 0xfc,
+	0xa7, 0x05, 0xe5, 0xe5, 0x98, 0x64, 0x2a, 0xd2, 0x82, 0x32, 0xdc, 0x9b,
+	0x51, 0x27, 0xe5, 0x66, 0x22, 0xae, 0xe4, 0x2b, 0x3f, 0x5e, 0x67, 0xc6,
+	0x9d, 0xb3, 0xf7, 0xbf, 0x8e, 0x99, 0x3b, 0xc6, 0x2d, 0xc6, 0x64, 0x29,
+	0x92, 0x10, 0xc0, 0x82, 0x79, 0x25, 0x64, 0xb2, 0x98, 0x94, 0x4c, 0x81,
+	0xb0, 0x45, 0x25, 0xeb, 0x12, 0xae, 0x04, 0xda, 0xb7, 0x39, 0xf5, 0xeb,
+	0xb3, 0xee, 0x0b, 0xa8, 0x9b, 0x44, 0xbd, 0x4e, 0x79, 0x12, 0x75, 0x4f,
+	0x57, 0xe2, 0xf2, 0x44, 0xe5, 0x57, 0x25, 0x8d, 0xb6, 0x8f, 0x57, 0x30,
+	0x76, 0xb1, 0x51, 0x86, 0xa7, 0x9b, 0x25, 0x33, 0xdd, 0x9d, 0xc8, 0x4a,
+	0x10, 0x7c, 0xda, 0xff, 0xa8, 0x8c, 0xb5, 0xa1, 0x7e, 0x91, 0xef, 0x12,
+	0x2b, 0xde, 0x65, 0xfd, 0x3e, 0x37, 0xab, 0x1c, 0x49, 0xef, 0x4d, 0x25,
+	0xc6, 0x14, 0x9f, 0x1b, 0x24, 0xd3, 0x8f, 0xe7, 0xd1, 0xa8, 0x44, 0xbc,
+	0x20, 0xb8, 0xc3, 0xbf, 0x0c, 0x70, 0xa4, 0x92, 0x49, 0xc5, 0xb6, 0x6c,
+	0x97, 0xca, 0x25, 0x55, 0x5c, 0x72, 0x95, 0x2b, 0x25, 0xd9, 0x16, 0x04,
+	0xef, 0xf3, 0x3b, 0x51, 0x2e, 0x32, 0x5c, 0x90, 0xfd, 0x58, 0x23, 0xf4,
+	0x29, 0xbe, 0x1a, 0xda, 0x8c, 0x79, 0xf4, 0xb9, 0xc3, 0xd2, 0x28, 0xe9,
+	0xb8, 0xa4, 0xd5, 0x90, 0x24, 0xd5, 0xd0, 0x3a, 0x94, 0x39, 0xd2, 0xe0,
+	0x7d, 0xc1, 0xd2, 0xd2, 0x46, 0x3c, 0xcb, 0xa8, 0x1a, 0x6a, 0x5b, 0x55,
+	0x9e, 0x4a, 0x8a, 0x5a, 0x07, 0x5c, 0xa5, 0x7a, 0xd3, 0x8a, 0x65, 0xb8,
+	0xeb, 0xb2, 0x0f, 0x36, 0xad, 0x2d, 0xdb, 0xef, 0xac, 0x2c, 0xbb, 0xbd,
+	0x85, 0xb0, 0x8a, 0xe2, 0xef, 0xb8, 0x9e, 0x6b, 0x3a, 0xde, 0xed, 0x36,
+	0x60, 0x5e, 0xa3, 0x7e, 0xca, 0xdd, 0xa9, 0x9e, 0x0f, 0xa4, 0x9d, 0x30,
+	0xf3, 0x9d, 0xc2, 0x3b, 0x54, 0x1d, 0xf2, 0xb1, 0x6e, 0xae, 0x1c, 0xc2,
+	0xdc, 0xce, 0x4f, 0xa7, 0xdc, 0x2e, 0x85, 0xfb, 0x3c, 0x7f, 0x07, 0x41,
+	0xc6, 0xcf, 0xe9, 0x35, 0xfd, 0xee, 0x74, 0x02, 0xcf, 0x80, 0x3f, 0x9e,
+	0x4e, 0x6d, 0x92, 0xab, 0xed, 0xba, 0x7c, 0x13, 0x63, 0x76, 0xbb, 0x77,
+	0xa8, 0x6e, 0xd7, 0x57, 0x29, 0x77, 0x56, 0xce, 0xe0, 0x39, 0x08, 0x6e,
+	0xf4, 0x53, 0x89, 0x1c, 0xd6, 0xec, 0x42, 0x21, 0x2e, 0xdf, 0x2b, 0xa4,
+	0x40, 0xc5, 0xa9, 0xde, 0x39, 0xe9, 0xf3, 0xe7, 0x00, 0x6f, 0x1e, 0xd7,
+	0x41, 0xbe, 0x2b, 0xe3, 0x5d, 0x99, 0x6d, 0x83, 0xe0, 0x26, 0xff, 0x37,
+	0x83, 0xb1, 0x76, 0xc3, 0x17, 0x4f, 0x15, 0xb1, 0x9e, 0x80, 0xf9, 0x74,
+	0x11, 0xeb, 0x89, 0xb5, 0x7a, 0x5c, 0xaf, 0x7b, 0x2f, 0xd6, 0x9d, 0xb4,
+	0x41, 0xba, 0xd8, 0x61, 0x69, 0xf9, 0x03, 0xf6, 0x2e, 0x92, 0x29, 0x3a,
+	0x92, 0xf1, 0xff, 0x31, 0x48, 0x6b, 0x7e, 0x11, 0x67, 0xb8, 0x48, 0x5a,
+	0x6c, 0x00, 0xac, 0x7c, 0xcc, 0xda, 0x7a, 0x1b, 0x1d, 0xe0, 0x96, 0xeb,
+	0xc0, 0xf7, 0x31, 0xe5, 0x35, 0xd9, 0xf7, 0x21, 0x5f, 0xf0, 0xdf, 0x26,
+	0x47, 0xbc, 0x6a, 0xbd, 0x0c, 0x69, 0xb2, 0x92, 0x93, 0xec, 0x83, 0x81,
+	0x0c, 0xfb, 0xc0, 0x13, 0xfb, 0x74, 0x7d, 0xd1, 0x6d, 0x5d, 0xd6, 0xd1,
+	0x75, 0xf1, 0x6f, 0x7d, 0x23, 0xc6, 0x70, 0x46, 0x8a, 0xd5, 0xb6, 0x23,
+	0xc5, 0xfc, 0x66, 0x0b, 0x1f, 0x9e, 0x07, 0x9d, 0x4c, 0xe5, 0x82, 0x5d,
+	0xdb, 0x70, 0x1e, 0x57, 0xd7, 0xa1, 0x6d, 0x17, 0x7c, 0xe0, 0x4a, 0xb6,
+	0x30, 0x88, 0x71, 0xe3, 0xb8, 0x07, 0xc1, 0x94, 0x9f, 0x4e, 0x45, 0x65,
+	0x08, 0xcf, 0xa3, 0xe4, 0x3d, 0xe0, 0x4f, 0xa2, 0x99, 0xed, 0xbe, 0x8c,
+	0x80, 0xee, 0xf3, 0x95, 0xd7, 0x97, 0x22, 0x7a, 0x0e, 0xfe, 0x3f, 0x59,
+	0xdc, 0x70, 0x1c, 0x33, 0xe6, 0x54, 0xb1, 0x43, 0xf2, 0xd3, 0x9e, 0x4c,
+	0x16, 0x16, 0x7a, 0x95, 0xbc, 0x4c, 0x7e, 0xc7, 0xfa, 0xa5, 0x40, 0xbb,
+	0x43, 0x32, 0x5c, 0xf1, 0x24, 0x5f, 0xc0, 0xbd, 0xd8, 0x0d, 0xfa, 0x8d,
+	0x4a, 0x3a, 0x61, 0xd6, 0x26, 0x5f, 0x18, 0xc1, 0xfc, 0x80, 0x6b, 0x8f,
+	0xbf, 0x07, 0x2d, 0x4c, 0xae, 0x64, 0x06, 0x48, 0x3f, 0x6f, 0x06, 0x96,
+	0x98, 0xcc, 0xfa, 0xe0, 0x0b, 0xd7, 0xc0, 0x92, 0x2f, 0xc6, 0xa2, 0xc3,
+	0x98, 0xf7, 0x70, 0xf9, 0x57, 0xd0, 0x7f, 0x8b, 0xfe, 0x0d, 0x7e, 0xb2,
+	0x65, 0x51, 0xdc, 0xe3, 0xb8, 0x13, 0xe6, 0x90, 0x56, 0x21, 0x1b, 0xa6,
+	0x3b, 0x65, 0x12, 0xb4, 0x3a, 0x2c, 0xf8, 0x3d, 0xcf, 0xb9, 0x10, 0xae,
+	0x0e, 0xfd, 0x7b, 0x72, 0x7a, 0x8b, 0x7e, 0xce, 0x8e, 0x76, 0x48, 0x6e,
+	0x3e, 0x9c, 0x33, 0xe5, 0x05, 0x65, 0x44, 0xea, 0xb0, 0x08, 0x65, 0x46,
+	0x10, 0x3c, 0xe8, 0x53, 0x6e, 0x04, 0xc1, 0x69, 0x9f, 0x72, 0xe4, 0x0c,
+	0xe4, 0x03, 0x65, 0x07, 0x79, 0xd9, 0x53, 0x5c, 0xab, 0x4c, 0xa1, 0x17,
+	0xeb, 0xd1, 0x28, 0xd9, 0xfe, 0xe3, 0x84, 0x15, 0x72, 0xe7, 0xa5, 0x4f,
+	0x66, 0xbc, 0x5c, 0x22, 0xa2, 0xf1, 0x04, 0xca, 0x82, 0x3c, 0x4c, 0xeb,
+	0x99, 0x75, 0x49, 0xbe, 0xbf, 0x64, 0xeb, 0xc8, 0xaf, 0xb2, 0x4e, 0x74,
+	0x4d, 0x9d, 0x7f, 0xa7, 0x0c, 0x5f, 0xf6, 0x62, 0xdd, 0x3a, 0x14, 0xf1,
+	0xd8, 0xb5, 0x8d, 0xcf, 0x12, 0x6b, 0x18, 0xfa, 0x3d, 0xbc, 0x7b, 0xee,
+	0x53, 0x8f, 0x7a, 0xf5, 0xde, 0xfd, 0x28, 0xba, 0xf6, 0xdd, 0x94, 0x44,
+	0xbd, 0x54, 0xef, 0x8d, 0xea, 0x4f, 0x1a, 0xa4, 0x35, 0x08, 0x1e, 0xf5,
+	0xc3, 0xf2, 0xc6, 0x86, 0xb5, 0x63, 0x5c, 0x55, 0xa7, 0xec, 0x68, 0x9d,
+	0xb2, 0xcf, 0xd7, 0x29, 0x7b, 0x7b, 0xe3, 0xda, 0xb2, 0xdb, 0xeb, 0x94,
+	0xcd, 0xd6, 0x29, 0xfb, 0x69, 0x9d, 0x32, 0x69, 0x5a, 0x5b, 0x16, 0xa9,
+	0x53, 0xd6, 0x57, 0xa7, 0x2c, 0x0a, 0xbe, 0xdb, 0x26, 0xf9, 0xf8, 0xbd,
+	0x9c, 0xbb, 0xc5, 0x4d, 0x29, 0xb2, 0x16, 0x37, 0x0d, 0xa8, 0xd7, 0xb9,
+	0xaa, 0xde, 0x17, 0xeb, 0xd4, 0x6b, 0x44, 0xbd, 0xb6, 0x55, 0xf5, 0x76,
+	0xd4, 0xc1, 0x75, 0x13, 0xea, 0xc5, 0x56, 0xd5, 0x7b, 0xb0, 0x4e, 0x3d,
+	0x96, 0x7f, 0xc6, 0x8e, 0xd3, 0x07, 0x2d, 0xf4, 0x5a, 0xeb, 0xd5, 0x28,
+	0xd2, 0xce, 0xf2, 0x5e, 0xe8, 0x90, 0x0e, 0x65, 0xe4, 0x02, 0x65, 0x10,
+	0xcb, 0x3a, 0x41, 0xe7, 0x71, 0xd0, 0x1d, 0xe5, 0x28, 0xf8, 0x8c, 0x73,
+	0xa9, 0x6c, 0x90, 0xb1, 0x78, 0x9f, 0x7b, 0xb5, 0x6a, 0x01, 0x8d, 0xa5,
+	0xdc, 0xa4, 0x22, 0xff, 0x49, 0x2e, 0x32, 0xe4, 0xe5, 0x86, 0x45, 0xc5,
+	0x95, 0x04, 0x32, 0xe2, 0xab, 0x36, 0x25, 0xf7, 0x80, 0xbf, 0xd2, 0xd0,
+	0x59, 0x37, 0x06, 0xc3, 0x9a, 0xb7, 0x4c, 0xdd, 0x8b, 0xcb, 0x54, 0x5f,
+	0x0e, 0x52, 0x16, 0x0e, 0x8d, 0x7e, 0x2a, 0xe3, 0x2d, 0x0c, 0x36, 0x82,
+	0x66, 0xcf, 0xa3, 0xcd, 0x6e, 0xb4, 0xdc, 0x57, 0x8e, 0xca, 0x48, 0x79,
+	0x00, 0xbc, 0xe0, 0xc8, 0x39, 0x6f, 0xa3, 0x9c, 0xf3, 0x51, 0xb7, 0x12,
+	0x91, 0xc5, 0xb8, 0x23, 0x8b, 0x78, 0xce, 0xf8, 0x78, 0x57, 0x09, 0x79,
+	0x6b, 0x40, 0x0e, 0x14, 0x7d, 0x39, 0x5c, 0xbc, 0x41, 0x85, 0x7a, 0x6d,
+	0xa7, 0xbf, 0x5e, 0x1e, 0x73, 0x4d, 0xdf, 0xbb, 0xbd, 0x05, 0x68, 0xd4,
+	0xa8, 0x9c, 0xf7, 0x52, 0x89, 0x45, 0xcd, 0x13, 0xff, 0x27, 0x18, 0x41,
+	0x3f, 0xb3, 0x5e, 0xca, 0xfd, 0x03, 0x3c, 0x8f, 0x95, 0x69, 0xcb, 0x54,
+	0xfb, 0x9a, 0x44, 0x5f, 0x87, 0x8a, 0x1b, 0xe4, 0x56, 0xdb, 0x7e, 0x97,
+	0xb7, 0xd0, 0x0b, 0x9e, 0x73, 0x4f, 0x50, 0x86, 0x14, 0x00, 0xd7, 0x5e,
+	0xf0, 0x36, 0xda, 0x7e, 0x4d, 0xcb, 0x33, 0xd8, 0x3e, 0x85, 0x8d, 0x90,
+	0xcf, 0x7f, 0x17, 0xdc, 0x1a, 0x67, 0x7d, 0x96, 0x51, 0xe7, 0x48, 0x49,
+	0x0d, 0x41, 0x26, 0x0c, 0x50, 0x66, 0x26, 0x21, 0x2f, 0x21, 0x7b, 0x8a,
+	0x3f, 0x0d, 0xd2, 0xd1, 0x5a, 0x39, 0x28, 0xb9, 0x6a, 0x1d, 0x96, 0x25,
+	0x8d, 0x5c, 0x2d, 0x2e, 0x2d, 0xcb, 0x8a, 0x1c, 0xe4, 0xcb, 0x53, 0x15,
+	0xca, 0x85, 0x0f, 0x82, 0x47, 0x3b, 0x65, 0xa4, 0x90, 0xca, 0xa5, 0x65,
+	0x1b, 0xd6, 0xef, 0xd7, 0xb1, 0xa6, 0x51, 0x5c, 0x0f, 0xad, 0x97, 0x56,
+	0x1f, 0xba, 0x9b, 0xe5, 0xe8, 0xb4, 0x9d, 0x36, 0xd2, 0x6f, 0x03, 0x0f,
+	0x93, 0x5c, 0xf3, 0x44, 0x26, 0xe2, 0x8c, 0xd2, 0x5e, 0x19, 0x85, 0x7c,
+	0xcc, 0x96, 0xd9, 0x37, 0xe1, 0x4d, 0xd8, 0xdf, 0xb0, 0x9b, 0x0a, 0x9d,
+	0xf6, 0x77, 0x0b, 0x7e, 0x27, 0xed, 0x6f, 0xc8, 0xd4, 0x82, 0x67, 0x7f,
+	0xc7, 0xb5, 0x1c, 0x32, 0xbf, 0x13, 0xf8, 0xdd, 0xaf, 0x7f, 0x4f, 0x15,
+	0x77, 0xed, 0x52, 0xde, 0x95, 0x92, 0x9d, 0xef, 0x94, 0x03, 0x85, 0x77,
+	0x58, 0xd9, 0x82, 0x4b, 0xbe, 0xe4, 0x98, 0x79, 0x26, 0xf4, 0xba, 0xe7,
+	0x8b, 0x39, 0x67, 0x94, 0xf0, 0xe3, 0xf7, 0x70, 0xa1, 0xcf, 0xdd, 0x24,
+	0xa4, 0x81, 0x29, 0x67, 0xb8, 0xe2, 0xa4, 0x23, 0x43, 0x3d, 0x89, 0x49,
+	0x39, 0x8c, 0xdf, 0xe2, 0x46, 0x86, 0xbe, 0x84, 0xbb, 0xc1, 0xc1, 0x57,
+	0xb6, 0x43, 0xb6, 0x16, 0x29, 0x2f, 0x3d, 0xcc, 0x3d, 0x29, 0x67, 0x56,
+	0xd8, 0x58, 0xc4, 0x85, 0x92, 0xec, 0x74, 0xea, 0x78, 0x4e, 0x52, 0xb9,
+	0x19, 0x30, 0xc4, 0x8d, 0x7e, 0x54, 0xde, 0xe7, 0x83, 0x76, 0xaf, 0x74,
+	0x64, 0xd7, 0x95, 0x51, 0xd8, 0x44, 0xde, 0xcc, 0x2e, 0xc8, 0x58, 0xc8,
+	0xbe, 0x08, 0xe9, 0x41, 0x9d, 0x92, 0xb1, 0xe8, 0x10, 0xb0, 0x7d, 0xaa,
+	0x7f, 0x64, 0xb2, 0x90, 0xbd, 0x5d, 0x0d, 0xed, 0xff, 0x6c, 0x66, 0xe0,
+	0xad, 0x92, 0xdd, 0xab, 0x80, 0xa3, 0xf6, 0x31, 0xc8, 0x4c, 0xcc, 0x2b,
+	0x08, 0x40, 0xcf, 0x90, 0xe7, 0x37, 0xdd, 0x14, 0x19, 0x6a, 0x90, 0xe1,
+	0xbd, 0xed, 0x68, 0xc3, 0x77, 0xc4, 0xd7, 0x79, 0xe0, 0x33, 0x95, 0x1c,
+	0x11, 0xb9, 0x7b, 0x6a, 0x60, 0xc9, 0x99, 0x2c, 0x7d, 0x10, 0x3c, 0x79,
+	0x15, 0xda, 0x3f, 0x80, 0xf6, 0x2f, 0x3b, 0xf9, 0xe9, 0x57, 0x9c, 0xc9,
+	0xe9, 0xbf, 0x75, 0xa6, 0xa6, 0xb7, 0x6c, 0xd9, 0x39, 0xb8, 0x65, 0xcb,
+	0xf8, 0x60, 0xd4, 0xea, 0x97, 0x2d, 0x5b, 0xa6, 0x06, 0x07, 0x81, 0x83,
+	0x3e, 0x77, 0x44, 0x3c, 0x77, 0x97, 0x80, 0x7f, 0xe2, 0x1c, 0x93, 0xfa,
+	0x27, 0x85, 0xf7, 0x6c, 0xef, 0xe9, 0xf7, 0xc3, 0xd2, 0x97, 0x68, 0x13,
+	0x8e, 0x1f, 0xb1, 0x75, 0xda, 0x01, 0xfb, 0x03, 0x76, 0x7d, 0x0b, 0xaa,
+	0xc1, 0x63, 0x39, 0xe7, 0xc2, 0x72, 0xae, 0xed, 0x8f, 0xac, 0x2d, 0xbb,
+	0x11, 0xe5, 0x7c, 0x26, 0xce, 0x88, 0x17, 0xda, 0x22, 0x0d, 0xda, 0x76,
+	0xcc, 0x16, 0x48, 0x33, 0x51, 0x99, 0x28, 0xb4, 0xa1, 0x0d, 0xe8, 0xe2,
+	0x94, 0xbd, 0x8e, 0x02, 0xb6, 0xbd, 0xe8, 0xeb, 0xe8, 0x21, 0xb4, 0xa3,
+	0xcc, 0x48, 0xf5, 0x8a, 0xfa, 0x04, 0xea, 0xf4, 0xb9, 0x9b, 0x85, 0x36,
+	0xc7, 0x71, 0xc9, 0x16, 0xc9, 0xdf, 0x3d, 0x80, 0x27, 0x26, 0xc9, 0x76,
+	0x3c, 0x57, 0x0e, 0xc0, 0x0e, 0x69, 0xb0, 0x3a, 0x33, 0x94, 0x17, 0xfc,
+	0x77, 0x87, 0x12, 0xef, 0x80, 0x8c, 0xcd, 0x5d, 0x8e, 0x7a, 0x0e, 0xf0,
+	0x42, 0x3b, 0x05, 0x36, 0xcb, 0x5c, 0x5a, 0x32, 0xdb, 0xee, 0xc5, 0xdd,
+	0xc5, 0x73, 0x1e, 0xf7, 0xb7, 0xe0, 0x3e, 0x89, 0x7b, 0x08, 0x27, 0xf0,
+	0xea, 0x47, 0xac, 0xce, 0xba, 0x06, 0x63, 0xff, 0x6b, 0xc9, 0x94, 0x12,
+	0xb4, 0x39, 0x36, 0x66, 0xbc, 0xb4, 0xab, 0x44, 0x6d, 0x56, 0x32, 0x85,
+	0xfa, 0xf0, 0x09, 0xbc, 0x83, 0x32, 0x7e, 0x12, 0xbf, 0x1f, 0xa4, 0x4d,
+	0x3c, 0x25, 0xe3, 0x73, 0x1c, 0xa7, 0x00, 0x98, 0x4a, 0x92, 0x3d, 0xf9,
+	0x00, 0xae, 0x69, 0x5c, 0x0f, 0xe3, 0xe2, 0xdc, 0xd8, 0xff, 0xe2, 0x26,
+	0x05, 0x5c, 0xf3, 0x39, 0x4b, 0x3a, 0xae, 0xe0, 0x37, 0x69, 0xb8, 0x42,
+	0xdb, 0x06, 0xf4, 0x5b, 0x09, 0xe9, 0xda, 0xb7, 0xbf, 0x13, 0x9a, 0xaf,
+	0x73, 0x6d, 0xa0, 0x99, 0xca, 0xa0, 0x96, 0x39, 0x19, 0x0f, 0xf7, 0x0a,
+	0x6c, 0x8f, 0x36, 0xce, 0xd1, 0xb3, 0x65, 0x9e, 0x2e, 0x4b, 0xea, 0xb2,
+	0x7e, 0x5b, 0x86, 0x7b, 0xa5, 0x41, 0xc6, 0xda, 0x01, 0x31, 0xe5, 0xb3,
+	0x84, 0xf8, 0xa4, 0x0c, 0x00, 0xfd, 0xc2, 0x66, 0x38, 0x73, 0x51, 0xf9,
+	0xb7, 0xa4, 0x6d, 0xb1, 0xc7, 0x2b, 0xa4, 0x63, 0xd2, 0x76, 0x10, 0xdc,
+	0xef, 0x37, 0xa1, 0x7f, 0xf2, 0xbc, 0x48, 0xc3, 0xd1, 0xa8, 0xcc, 0xb8,
+	0xa4, 0x85, 0x77, 0xb4, 0x90, 0x06, 0x1a, 0x3d, 0xd2, 0x70, 0x2d, 0x7f,
+	0x71, 0x0d, 0xd9, 0x5f, 0x0e, 0xf6, 0x1d, 0xed, 0xbc, 0x1e, 0xd8, 0xce,
+	0x1c, 0xe3, 0x30, 0x9f, 0x5d, 0x05, 0x9e, 0xca, 0x2c, 0xf3, 0x94, 0xc8,
+	0x6c, 0x81, 0xb8, 0x09, 0xed, 0x3f, 0xae, 0x33, 0xf1, 0xf3, 0x38, 0xe6,
+	0xcc, 0xfb, 0x19, 0x8b, 0xa7, 0x2f, 0x59, 0x3c, 0x7d, 0xd9, 0xde, 0x5d,
+	0x27, 0xab, 0x6d, 0xc1, 0x05, 0x3c, 0x73, 0x7d, 0xa2, 0x1a, 0x67, 0xd9,
+	0xc2, 0x0c, 0xee, 0xa8, 0x5b, 0x7c, 0x5c, 0xc6, 0xb5, 0x9d, 0x16, 0x91,
+	0x77, 0x69, 0xd9, 0x06, 0x21, 0xdd, 0x5c, 0x00, 0xcc, 0x0d, 0x92, 0x8b,
+	0x47, 0xf4, 0xda, 0x47, 0xbd, 0x03, 0x51, 0x43, 0xab, 0xc4, 0xc9, 0x0a,
+	0x5f, 0xaa, 0x06, 0xa6, 0xb8, 0x95, 0x73, 0x84, 0x8b, 0xb4, 0xfb, 0x88,
+	0x86, 0xeb, 0x16, 0xc8, 0xbb, 0x9c, 0xa8, 0xf6, 0x46, 0xb9, 0x0c, 0xb4,
+	0xa0, 0xe2, 0xd0, 0x5c, 0xc1, 0xd3, 0xb0, 0x9b, 0xb2, 0x73, 0xb4, 0xa1,
+	0xbb, 0xe8, 0xb7, 0xc4, 0xb2, 0xfd, 0xad, 0xa4, 0x23, 0xa5, 0x60, 0x7f,
+	0xe1, 0x59, 0x65, 0xfb, 0x35, 0x9d, 0x3a, 0xca, 0x8b, 0x6b, 0x3b, 0x19,
+	0xbc, 0x12, 0xb1, 0xbe, 0x73, 0x54, 0x79, 0x9b, 0x57, 0x97, 0x25, 0xa9,
+	0x87, 0xd1, 0x2e, 0x99, 0xed, 0x6f, 0x27, 0x8f, 0xb9, 0xca, 0x03, 0x2e,
+	0x3d, 0xed, 0x1b, 0xe5, 0xd4, 0xc0, 0xc6, 0x55, 0xf5, 0xf5, 0xdd, 0xb1,
+	0xcf, 0x51, 0x7b, 0x77, 0xed, 0x3d, 0x69, 0xef, 0xb9, 0xe8, 0x00, 0xef,
+	0x8e, 0x44, 0x87, 0x78, 0xc7, 0x1a, 0x0e, 0xb1, 0x0f, 0xcd, 0x57, 0x56,
+	0xce, 0xf4, 0xb8, 0x79, 0x21, 0x5f, 0xfd, 0xa9, 0xdc, 0x32, 0x67, 0xe4,
+	0xef, 0x2e, 0xc8, 0x20, 0xf8, 0x6f, 0xee, 0xa2, 0x00, 0xfe, 0xbd, 0x65,
+	0xb9, 0xa5, 0x42, 0xbc, 0xfd, 0x06, 0xf0, 0xb7, 0x35, 0x4a, 0xde, 0x74,
+	0x85, 0x72, 0xf7, 0x4e, 0xd1, 0xf6, 0x69, 0x81, 0x38, 0x3f, 0x2b, 0x5c,
+	0x9b, 0x7c, 0xe1, 0x19, 0xbd, 0x36, 0x07, 0x0b, 0x8b, 0xc0, 0xcf, 0xd7,
+	0x41, 0xf7, 0x41, 0xb0, 0xe8, 0xe7, 0x41, 0x39, 0x7f, 0x84, 0xdf, 0xe8,
+	0xbb, 0xf0, 0x1c, 0xde, 0xb7, 0x4a, 0xbe, 0x44, 0x9e, 0x8b, 0x5a, 0x1e,
+	0x3e, 0x05, 0x7e, 0xba, 0x0c, 0xfd, 0xa2, 0x6c, 0x80, 0xbf, 0xff, 0x11,
+	0xef, 0x70, 0x9f, 0xc3, 0x22, 0xb6, 0xd3, 0xd6, 0xe1, 0xd8, 0x5c, 0x3b,
+	0xae, 0x59, 0x5c, 0xfb, 0xad, 0x8f, 0x2f, 0xaf, 0x1b, 0xd7, 0x2b, 0xd5,
+	0x9b, 0x93, 0x70, 0xcd, 0x44, 0x1e, 0x2f, 0xb0, 0x3e, 0xe9, 0xff, 0x1f,
+	0x62, 0x46, 0x17, 0xfc, 0xc9, 0x3a, 0x73, 0x5f, 0xdd, 0x96, 0x6b, 0x5e,
+	0x4b, 0x83, 0xf4, 0x6f, 0x52, 0x83, 0x39, 0xc8, 0x9d, 0xa8, 0xd7, 0x2a,
+	0x23, 0xda, 0x27, 0x22, 0x4d, 0x90, 0x06, 0x6e, 0x56, 0x86, 0x36, 0x3f,
+	0xa4, 0x0c, 0x6d, 0x3e, 0x03, 0x5a, 0xc4, 0x55, 0x5c, 0x72, 0x0c, 0x6d,
+	0x7e, 0x1d, 0x77, 0x5c, 0xc5, 0x0b, 0x4e, 0xc8, 0xc7, 0xc3, 0xf0, 0xf9,
+	0x76, 0x15, 0xa2, 0xce, 0x78, 0x05, 0xf4, 0x5b, 0x8c, 0xa1, 0x7c, 0x81,
+	0x38, 0xc7, 0xfc, 0x39, 0xce, 0x56, 0xdb, 0xff, 0xe3, 0x32, 0x51, 0x0c,
+	0xb4, 0x5d, 0x95, 0x9d, 0xbb, 0x17, 0xf7, 0xf5, 0x5a, 0xce, 0x28, 0x2f,
+	0xad, 0x8c, 0xbc, 0x7a, 0x17, 0xee, 0xdd, 0x89, 0x83, 0xd2, 0xed, 0x46,
+	0xe4, 0x39, 0xf4, 0xf5, 0x43, 0x67, 0xa2, 0xf2, 0x32, 0xae, 0x9f, 0xe0,
+	0x7a, 0x15, 0xd7, 0x2b, 0xe8, 0xf7, 0x45, 0x94, 0xaf, 0x97, 0x05, 0xb7,
+	0x19, 0xf5, 0x45, 0x8d, 0x57, 0x5e, 0x70, 0xc6, 0x4e, 0xbe, 0x84, 0x2b,
+	0xaa, 0x26, 0x2a, 0xcf, 0x3b, 0xd9, 0xb9, 0x60, 0xe3, 0xa2, 0x47, 0x19,
+	0xf6, 0xa7, 0x8e, 0xe9, 0x7b, 0x08, 0x73, 0x00, 0x4d, 0x17, 0x17, 0x30,
+	0xf6, 0x33, 0x9a, 0x67, 0x46, 0x20, 0xf3, 0xb3, 0xb0, 0x4b, 0xc6, 0x34,
+	0x4c, 0x97, 0x03, 0x3e, 0xf8, 0xba, 0x03, 0xb8, 0xcf, 0x35, 0xca, 0x52,
+	0x9c, 0x76, 0xe4, 0x97, 0x75, 0xfd, 0x6c, 0xb1, 0x5b, 0xe3, 0x76, 0x66,
+	0x0d, 0xff, 0xd0, 0x3f, 0x0b, 0xe5, 0x81, 0x91, 0xc6, 0xb3, 0x05, 0xca,
+	0x02, 0xe8, 0x9f, 0xc2, 0x14, 0xee, 0x8d, 0x5a, 0x26, 0xe4, 0x25, 0x94,
+	0x07, 0x6c, 0x47, 0x99, 0x50, 0x2b, 0x77, 0x28, 0x6b, 0x28, 0x7b, 0x28,
+	0x4b, 0xcc, 0x7a, 0x8c, 0x3f, 0x48, 0x19, 0x7e, 0x2d, 0xfc, 0x53, 0xda,
+	0x1f, 0x9d, 0xc6, 0x07, 0x99, 0xce, 0x28, 0x23, 0x4f, 0xf7, 0xe8, 0xb5,
+	0x98, 0x28, 0xa8, 0x38, 0x20, 0x47, 0x19, 0xae, 0x63, 0x7b, 0x71, 0xcf,
+	0xaa, 0x09, 0x5c, 0xd9, 0x63, 0x1f, 0xc0, 0x6f, 0xae, 0xcd, 0x04, 0xea,
+	0xe1, 0x2a, 0x8e, 0xe2, 0x8e, 0x0b, 0xb6, 0x99, 0x91, 0x23, 0x5c, 0xd3,
+	0x84, 0x5d, 0xd3, 0x2f, 0x03, 0x0f, 0x9c, 0x9f, 0xd2, 0xf1, 0x07, 0xe5,
+	0xed, 0x00, 0xde, 0x2b, 0xd6, 0xdf, 0x6d, 0x15, 0xc3, 0x83, 0xb8, 0x7a,
+	0xc9, 0xcf, 0x2d, 0x66, 0xbd, 0x34, 0xed, 0x7e, 0x37, 0x6a, 0x78, 0x31,
+	0x8e, 0xb2, 0x08, 0xca, 0xda, 0x45, 0xf3, 0xfe, 0x32, 0x1e, 0xd3, 0x16,
+	0x8f, 0xfc, 0xad, 0xec, 0x6f, 0xd0, 0x13, 0x6c, 0xda, 0x8c, 0x37, 0x80,
+	0x71, 0x31, 0x97, 0x63, 0x7b, 0xd4, 0x38, 0xe4, 0xf7, 0xb8, 0x47, 0x19,
+	0xce, 0x38, 0x03, 0xe7, 0xc7, 0x7e, 0x51, 0xae, 0x71, 0xe0, 0x4b, 0xd5,
+	0x87, 0xff, 0x32, 0xd6, 0xec, 0x71, 0xd9, 0x57, 0xbc, 0x5a, 0xfb, 0xd4,
+	0x8d, 0x47, 0xcd, 0x7a, 0x88, 0x0a, 0xeb, 0xa1, 0xef, 0x38, 0x6d, 0x9b,
+	0x31, 0xfd, 0x3e, 0x7a, 0x94, 0xbf, 0x29, 0x9f, 0x6b, 0xe5, 0xbd, 0xb1,
+	0x6b, 0xf2, 0x2b, 0x64, 0x1d, 0x6d, 0x0b, 0xac, 0x59, 0xb9, 0x16, 0xef,
+	0xf4, 0xf1, 0x29, 0xf3, 0xc8, 0x4f, 0x07, 0xc1, 0x13, 0xaa, 0xc1, 0xf0,
+	0x3e, 0x7d, 0x8d, 0x7a, 0xfc, 0x04, 0xfb, 0x0b, 0xbc, 0x72, 0x02, 0xb6,
+	0xdb, 0xae, 0xe5, 0x3e, 0x20, 0x2b, 0xe3, 0x31, 0x39, 0x59, 0x68, 0x91,
+	0xb9, 0x82, 0x82, 0xc1, 0x60, 0x64, 0x67, 0x44, 0x12, 0x5a, 0xff, 0xd2,
+	0xbe, 0x1b, 0x9e, 0x8e, 0x58, 0xba, 0x83, 0xc3, 0xd2, 0xfc, 0x1b, 0xd0,
+	0xb1, 0x65, 0xe8, 0xd8, 0x56, 0xe8, 0xe0, 0xd5, 0x32, 0xa2, 0xab, 0x61,
+	0xad, 0x8c, 0x60, 0x9b, 0x14, 0xbc, 0xf2, 0x83, 0x68, 0x17, 0xd2, 0x5f,
+	0x4c, 0xd3, 0x5a, 0x56, 0x72, 0xce, 0xae, 0xca, 0x94, 0xb3, 0xbb, 0xb2,
+	0x5a, 0x07, 0xf5, 0xb9, 0x51, 0x31, 0xb0, 0x9e, 0xd4, 0x71, 0xbc, 0x94,
+	0x9f, 0x01, 0x4e, 0x76, 0x83, 0xee, 0x9e, 0x2e, 0xc1, 0x8f, 0xa7, 0x5c,
+	0x06, 0xcc, 0x8f, 0x01, 0xe6, 0xd9, 0x92, 0x13, 0xda, 0x06, 0xc2, 0xe0,
+	0xc9, 0xec, 0x74, 0xbf, 0x2c, 0xce, 0x93, 0x0e, 0x21, 0x03, 0x4a, 0x58,
+	0x4f, 0x7f, 0x1d, 0xec, 0x00, 0x8e, 0x0f, 0xb9, 0x3d, 0xdd, 0xa1, 0xdf,
+	0x19, 0x7d, 0xde, 0x29, 0x8b, 0xe5, 0xf7, 0x58, 0xd8, 0x0e, 0xd7, 0xc0,
+	0xb6, 0x6e, 0x19, 0xb6, 0xdd, 0x80, 0x6d, 0x4f, 0x5d, 0xd8, 0xea, 0xe9,
+	0xe2, 0x2e, 0xd8, 0x34, 0xe4, 0x8f, 0x10, 0xaf, 0xed, 0x96, 0x1e, 0x6e,
+	0xb7, 0xf6, 0x2e, 0x6d, 0xa2, 0x9f, 0x02, 0x1e, 0xd2, 0x18, 0x7e, 0xcf,
+	0x3d, 0x4a, 0x59, 0x86, 0x72, 0x3e, 0x7f, 0x06, 0x75, 0xf0, 0x3c, 0xf7,
+	0xe7, 0x56, 0x0e, 0xde, 0x65, 0x61, 0xa1, 0x9d, 0x90, 0x86, 0x4d, 0x3c,
+	0xe2, 0x64, 0xe6, 0x08, 0x43, 0x0e, 0xf0, 0xe2, 0x5d, 0xa5, 0xb6, 0x4f,
+	0xde, 0xd9, 0xef, 0x15, 0xb6, 0x1f, 0xf6, 0x1d, 0xce, 0x65, 0xbd, 0xd5,
+	0xf3, 0x21, 0x7d, 0x85, 0xf6, 0xf5, 0x94, 0x93, 0x5e, 0x33, 0xaf, 0x5a,
+	0x9a, 0xa3, 0xbc, 0x8d, 0xca, 0x4e, 0xd0, 0xc9, 0xce, 0x15, 0xb4, 0xa6,
+	0xdd, 0x10, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x18, 0xbe, 0xf1, 0x63,
+	0xd0, 0x87, 0x94, 0x37, 0x37, 0x1b, 0xdf, 0x5c, 0x4e, 0x00, 0xd6, 0xf0,
+	0x99, 0xb4, 0xc9, 0xdf, 0x94, 0x49, 0x55, 0x5a, 0x34, 0xbe, 0x4b, 0xa7,
+	0x8e, 0x9f, 0x56, 0xed, 0xf5, 0xa8, 0x8c, 0x9a, 0x35, 0x3f, 0xcc, 0x35,
+	0xa7, 0x2f, 0xd2, 0xfd, 0xc0, 0xa8, 0xe5, 0xaf, 0x54, 0x29, 0x27, 0xbb,
+	0xed, 0xdc, 0xbf, 0x5c, 0x67, 0xed, 0x5a, 0x97, 0xd7, 0x6e, 0xb4, 0xb2,
+	0x7a, 0x8e, 0x22, 0x5d, 0x0f, 0x44, 0xb5, 0x6f, 0x2b, 0xca, 0x97, 0x46,
+	0x8f, 0xf2, 0x93, 0xb6, 0x12, 0xca, 0x67, 0xfb, 0xdc, 0x36, 0xd0, 0xdb,
+	0x53, 0x6b, 0xec, 0xae, 0xa4, 0x95, 0x9b, 0xf4, 0x83, 0xc3, 0x31, 0x72,
+	0x56, 0x4e, 0xe6, 0xd0, 0xff, 0x94, 0xb3, 0xb3, 0x52, 0x4f, 0x5e, 0x86,
+	0x72, 0x92, 0xf3, 0xb9, 0x57, 0xee, 0x78, 0x90, 0x3c, 0x7a, 0xbb, 0xb6,
+	0xaf, 0xaf, 0xda, 0x71, 0x00, 0xf8, 0x23, 0xfc, 0x8b, 0x9b, 0x60, 0x32,
+	0x40, 0xe7, 0xa6, 0x65, 0xdc, 0xae, 0xdb, 0xf8, 0xf2, 0xfa, 0xf3, 0x6a,
+	0xc7, 0x6f, 0xc6, 0x59, 0x95, 0x85, 0x59, 0xdb, 0xb1, 0xb0, 0xeb, 0x56,
+	0xdb, 0xb2, 0x9c, 0x03, 0xed, 0xd9, 0x46, 0x63, 0x0b, 0x16, 0x69, 0x7f,
+	0x52, 0x76, 0xd1, 0xfe, 0x8c, 0x35, 0x4a, 0x33, 0xe7, 0x33, 0x68, 0xcb,
+	0x68, 0xa7, 0xae, 0x9e, 0xdf, 0x6a, 0xff, 0x91, 0x70, 0x12, 0x6e, 0x43,
+	0x5b, 0x49, 0x45, 0xd8, 0x02, 0x19, 0xf5, 0xaf, 0xd5, 0x6b, 0xa0, 0x68,
+	0xbb, 0xee, 0xf8, 0x76, 0x83, 0x89, 0x31, 0x27, 0xd1, 0x3f, 0xc7, 0x24,
+	0xff, 0xf1, 0x4e, 0x3b, 0xbf, 0x9e, 0x2c, 0xab, 0xd5, 0x3d, 0x97, 0x2d,
+	0xe3, 0x6f, 0xe7, 0x8a, 0x35, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x2d, 0x0e,
+	0x49, 0x13, 0xa4, 0x85, 0x90, 0x16, 0xb7, 0x5a, 0x7d, 0x13, 0xd2, 0xde,
+	0xa5, 0xa0, 0xbd, 0xfb, 0x80, 0x27, 0xca, 0x70, 0xc6, 0xed, 0x36, 0xe3,
+	0xf9, 0x08, 0x9e, 0x43, 0x3e, 0xb9, 0x98, 0x0c, 0xa7, 0xfc, 0x66, 0x9b,
+	0x8c, 0x95, 0xfb, 0xa1, 0x9f, 0xcb, 0x36, 0x9c, 0x37, 0xe5, 0xff, 0x57,
+	0xe9, 0x77, 0x35, 0x1a, 0x3b, 0xfd, 0x43, 0x8d, 0x94, 0xaf, 0x9b, 0xe4,
+	0x60, 0x4d, 0xd9, 0xc5, 0xe4, 0x77, 0xed, 0x9c, 0x2f, 0xff, 0x7f, 0x30,
+	0xe7, 0xc4, 0xaa, 0x39, 0xbb, 0x76, 0xce, 0x15, 0xbc, 0x6f, 0xc3, 0xfb,
+	0x16, 0xea, 0x82, 0x64, 0x55, 0xde, 0x58, 0x5c, 0xe8, 0x79, 0xd5, 0xca,
+	0x89, 0x50, 0x46, 0x70, 0x5e, 0x1f, 0xb1, 0x73, 0x78, 0xa0, 0x66, 0x5e,
+	0x1f, 0x79, 0x13, 0xf3, 0xea, 0x5c, 0x31, 0xaf, 0x5d, 0x17, 0x9d, 0x57,
+	0x3d, 0x1e, 0x27, 0x2f, 0x87, 0xf3, 0x8b, 0xc9, 0x8d, 0x05, 0xce, 0x71,
+	0x27, 0xe6, 0x48, 0x18, 0xc2, 0x39, 0x0e, 0xd9, 0x39, 0x8a, 0xea, 0xda,
+	0xf1, 0x73, 0xf8, 0x5d, 0x3b, 0x3f, 0xea, 0xfe, 0x1f, 0x83, 0xa6, 0x9b,
+	0x24, 0xd3, 0xdf, 0x64, 0xe5, 0xff, 0x97, 0xe5, 0xd6, 0x22, 0xd7, 0x3a,
+	0x95, 0x16, 0xd9, 0xa3, 0xf6, 0x15, 0x9f, 0x6d, 0x64, 0x8c, 0x7f, 0x97,
+	0x6f, 0xf5, 0x18, 0xf4, 0xc5, 0x6e, 0xd8, 0x7c, 0x3b, 0x0b, 0x6a, 0x20,
+	0x22, 0x41, 0x70, 0x9b, 0xdf, 0x8c, 0xb1, 0x37, 0x6a, 0x5f, 0x75, 0x6d,
+	0x7c, 0xfd, 0x99, 0x46, 0xf1, 0x68, 0x6f, 0x50, 0x9f, 0x43, 0xdf, 0x1d,
+	0xa3, 0x0d, 0x96, 0x81, 0x9d, 0x9c, 0x4e, 0x44, 0xb4, 0x2d, 0x46, 0x9d,
+	0x98, 0x4a, 0xa4, 0xa5, 0x2c, 0xd9, 0x63, 0xe9, 0x84, 0x12, 0x8e, 0x01,
+	0x5b, 0x0d, 0x36, 0xe4, 0xad, 0x90, 0x35, 0xb7, 0x56, 0xf6, 0xaa, 0x5b,
+	0x60, 0xef, 0xdc, 0x72, 0xf2, 0x03, 0xea, 0x36, 0xd8, 0x3a, 0xb7, 0x9d,
+	0xbc, 0x41, 0xed, 0x83, 0x6d, 0xb3, 0x0f, 0x76, 0xce, 0xbe, 0x0a, 0x6d,
+	0xcf, 0x9b, 0x41, 0x7b, 0x9d, 0x35, 0xb4, 0x46, 0x1b, 0x87, 0xf3, 0x23,
+	0xee, 0x8f, 0x71, 0x0d, 0xfc, 0xa4, 0x7a, 0x45, 0xaf, 0x4b, 0xdb, 0x8a,
+	0xb2, 0xd7, 0x92, 0x55, 0xa1, 0x7e, 0xda, 0x60, 0xe3, 0x46, 0x94, 0xb7,
+	0xaf, 0x45, 0x5b, 0xa4, 0x11, 0x17, 0x78, 0x26, 0xfe, 0x48, 0x5b, 0xb5,
+	0xf3, 0xdf, 0xd4, 0x24, 0x5e, 0x67, 0x93, 0x34, 0xdf, 0x0b, 0xf9, 0x5a,
+	0x4b, 0x53, 0xbc, 0xbb, 0x56, 0xd7, 0x90, 0xb6, 0x28, 0x83, 0x43, 0x7a,
+	0xd8, 0xfa, 0x1a, 0xf2, 0xf7, 0xa2, 0xf4, 0x74, 0x4f, 0x64, 0x28, 0x08,
+	0xc6, 0x07, 0x64, 0x23, 0xe3, 0x01, 0x99, 0x4a, 0x35, 0x26, 0xa0, 0xbc,
+	0xda, 0x98, 0x00, 0xfd, 0xac, 0x47, 0x80, 0xdf, 0x19, 0x5c, 0x22, 0x63,
+	0x8c, 0x3b, 0x54, 0x42, 0xbb, 0xfc, 0x1b, 0xd6, 0x2e, 0x0f, 0xe1, 0x48,
+	0x02, 0x0e, 0x23, 0x9f, 0xd7, 0xea, 0xb9, 0x95, 0xfa, 0x3b, 0xb7, 0x6c,
+	0xd3, 0x26, 0xe5, 0xc6, 0x22, 0xe7, 0x4d, 0x19, 0x4c, 0xdc, 0xd4, 0xca,
+	0xe0, 0x84, 0xb5, 0xa3, 0x50, 0x47, 0xcb, 0xcf, 0xb5, 0xb2, 0x93, 0x72,
+	0x8f, 0xf1, 0xf9, 0x07, 0x7c, 0xd2, 0xfa, 0x7b, 0x24, 0xbd, 0x1c, 0x9f,
+	0x17, 0xd0, 0x9b, 0xf8, 0x91, 0x21, 0xbd, 0xdf, 0xe6, 0xce, 0xca, 0x6e,
+	0x19, 0x8e, 0x33, 0xd6, 0xc9, 0x78, 0x9e, 0x97, 0x9b, 0x05, 0x0f, 0x4c,
+	0x16, 0x15, 0x2c, 0xf8, 0x46, 0x19, 0x73, 0x03, 0xd9, 0xe5, 0x3b, 0x3a,
+	0x76, 0x6c, 0x74, 0xed, 0x4c, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0xff, 0x5d,
+	0x04, 0xf5, 0x2d, 0x6a, 0xfb, 0x56, 0x69, 0xfd, 0xbb, 0xa0, 0xeb, 0x7c,
+	0xae, 0x29, 0x8c, 0x63, 0x2e, 0xba, 0x11, 0x5b, 0xaf, 0xb6, 0xfc, 0x8b,
+	0x36, 0x3e, 0x9d, 0x84, 0xec, 0x0f, 0xcb, 0xfe, 0xb0, 0x4e, 0xd9, 0xb7,
+	0xea, 0x94, 0xfd, 0xcf, 0x3a, 0x65, 0x26, 0x2e, 0xb8, 0xb3, 0xf0, 0xf7,
+	0x78, 0x37, 0xa5, 0x7d, 0x77, 0xb1, 0xfb, 0x61, 0xb9, 0xe5, 0x3a, 0x1b,
+	0xac, 0x5f, 0xc6, 0x18, 0xb1, 0x89, 0x0d, 0x67, 0x75, 0x6c, 0xb8, 0xcf,
+	0xdd, 0xa1, 0xf4, 0x5e, 0xca, 0x7e, 0xc6, 0x19, 0xf7, 0x69, 0xbc, 0x10,
+	0x27, 0x5f, 0x61, 0x0c, 0x38, 0xc7, 0xbd, 0xd8, 0xa4, 0xba, 0x18, 0x6d,
+	0x57, 0x6d, 0x13, 0xb3, 0x6e, 0xb4, 0x8b, 0x5b, 0x64, 0x04, 0xb6, 0xc2,
+	0xce, 0x42, 0x9b, 0xec, 0x9a, 0x1e, 0x58, 0x47, 0xbd, 0xb5, 0x7b, 0xda,
+	0xf8, 0x83, 0xfb, 0xc0, 0x57, 0x69, 0x21, 0x8c, 0x29, 0x5f, 0x84, 0x36,
+	0xf1, 0x5a, 0x5b, 0xf8, 0xb5, 0xfb, 0xfb, 0xa5, 0x8b, 0xf4, 0xe7, 0xc0,
+	0x76, 0x78, 0xa3, 0xfd, 0x35, 0xcb, 0xc8, 0x74, 0x88, 0x2b, 0xf5, 0x33,
+	0xb6, 0x8b, 0x5c, 0xa4, 0x9d, 0xb6, 0x4b, 0xe4, 0xe9, 0x65, 0x59, 0xbc,
+	0x15, 0x36, 0x93, 0x04, 0x99, 0x01, 0xe9, 0x8c, 0x88, 0x8e, 0xf1, 0xf8,
+	0x46, 0x36, 0xf7, 0x70, 0x6f, 0x07, 0xf4, 0x6f, 0x6c, 0x15, 0x13, 0x37,
+	0x0d, 0xed, 0x94, 0x7a, 0xb4, 0x7b, 0x9d, 0xa5, 0x5d, 0xee, 0xb9, 0xee,
+	0xa6, 0xcc, 0xd5, 0x6b, 0x42, 0x3a, 0xde, 0x55, 0x90, 0x64, 0x48, 0xc7,
+	0x8b, 0x92, 0x5e, 0x41, 0xc7, 0x8b, 0x32, 0xa4, 0xe9, 0xb8, 0x71, 0x05,
+	0x1d, 0x77, 0x5a, 0x3a, 0xde, 0x13, 0x33, 0x74, 0xa1, 0xb4, 0x9e, 0x22,
+	0x9d, 0x1a, 0x3a, 0x76, 0x34, 0x1d, 0x2f, 0xe2, 0x1e, 0xf5, 0xae, 0xb3,
+	0x75, 0x22, 0xb6, 0x8c, 0xbf, 0xc3, 0x32, 0xca, 0xc5, 0x4f, 0xc6, 0x8c,
+	0x5e, 0x1a, 0x02, 0x1d, 0x85, 0xe5, 0xfb, 0x6d, 0xfc, 0xa0, 0xb6, 0xcc,
+	0xc4, 0x47, 0x76, 0x16, 0xc6, 0x62, 0x2b, 0xe9, 0x73, 0x08, 0xf4, 0x19,
+	0xd6, 0x79, 0x2d, 0xfa, 0x6c, 0xb6, 0xfb, 0x16, 0x71, 0xbd, 0x2f, 0x9f,
+	0x8e, 0x1b, 0x5a, 0xbd, 0x45, 0xcf, 0x9d, 0xf3, 0x3e, 0xfb, 0x06, 0x68,
+	0xd5, 0xac, 0xcd, 0xb9, 0xaa, 0xbf, 0xcd, 0x58, 0x54, 0xd2, 0xc4, 0xb0,
+	0x19, 0x27, 0xbd, 0x98, 0xed, 0x68, 0xe4, 0x53, 0x83, 0x96, 0x4f, 0xad,
+	0x63, 0xcc, 0x35, 0xa8, 0xca, 0xec, 0x01, 0xe8, 0x0a, 0xda, 0xd8, 0x5a,
+	0x4e, 0xe3, 0x5d, 0x67, 0x32, 0x53, 0x78, 0x35, 0x88, 0x78, 0x8c, 0x0f,
+	0x71, 0x5f, 0x40, 0xc6, 0x1c, 0x94, 0x75, 0x95, 0xcd, 0xbc, 0x94, 0xd7,
+	0x8a, 0xe7, 0x01, 0xe9, 0x2a, 0x2b, 0xf9, 0xe8, 0x74, 0x8b, 0xec, 0x2f,
+	0x44, 0xe5, 0xe3, 0x68, 0xff, 0xb1, 0x82, 0x0b, 0x7f, 0xfc, 0x4c, 0x8c,
+	0x76, 0xe1, 0xbe, 0x02, 0xf7, 0x27, 0x59, 0x37, 0xbe, 0x6a, 0x7f, 0x36,
+	0x22, 0x5d, 0x3d, 0x79, 0x78, 0x2a, 0x12, 0xdd, 0x03, 0x38, 0x9a, 0x86,
+	0x86, 0xe4, 0x07, 0x03, 0x1b, 0x51, 0xf6, 0xb2, 0x1d, 0x6f, 0xd4, 0x31,
+	0xf1, 0xde, 0x41, 0x79, 0x77, 0x65, 0x48, 0xae, 0xaf, 0x98, 0x3d, 0xd5,
+	0xea, 0x9e, 0x69, 0xca, 0x5d, 0x80, 0xfe, 0x49, 0xbb, 0x41, 0x70, 0xce,
+	0xc3, 0xaa, 0x1f, 0x89, 0x4a, 0xac, 0x27, 0x95, 0x58, 0x10, 0xf3, 0x7c,
+	0xbe, 0xfc, 0x0f, 0xc1, 0x58, 0x3c, 0x2a, 0x3f, 0xf0, 0x38, 0xc7, 0x41,
+	0xb9, 0xae, 0x5c, 0x3b, 0x36, 0x97, 0xf3, 0x0f, 0x63, 0xdc, 0xa7, 0xc8,
+	0x54, 0x16, 0x62, 0x8c, 0xa5, 0xd3, 0xe7, 0xe8, 0x7a, 0x1b, 0xfc, 0x38,
+	0x48, 0xee, 0xae, 0xb7, 0x81, 0x6e, 0xe2, 0xd0, 0xf9, 0x57, 0x01, 0xc6,
+	0xab, 0x18, 0xfb, 0x62, 0xcc, 0x8b, 0xcf, 0x5f, 0xc7, 0xb8, 0x6c, 0xfb,
+	0x1b, 0xd6, 0x5e, 0xe6, 0xfa, 0x1b, 0xde, 0xa9, 0xaf, 0x77, 0x5a, 0xc7,
+	0x62, 0x43, 0xe2, 0xc4, 0xde, 0x91, 0x90, 0x75, 0x5e, 0xed, 0xf8, 0xdc,
+	0x27, 0x86, 0xc5, 0x38, 0x20, 0xd1, 0xdd, 0xdb, 0x07, 0x65, 0x04, 0xf3,
+	0xdb, 0xb9, 0x66, 0x7e, 0xf7, 0x08, 0xe3, 0xab, 0xe7, 0x0b, 0x9c, 0x43,
+	0x75, 0x5e, 0xea, 0x0b, 0x66, 0x5e, 0xb1, 0x9e, 0xd5, 0xf3, 0xd1, 0xed,
+	0xd5, 0x09, 0xc0, 0xf2, 0x35, 0x9d, 0x57, 0x10, 0x04, 0x6f, 0xed, 0x39,
+	0x1f, 0x24, 0x2f, 0x49, 0xf5, 0x2e, 0x54, 0xf7, 0x77, 0xc6, 0x22, 0x43,
+	0x69, 0xad, 0xcf, 0xf0, 0x9c, 0xcc, 0x96, 0xd3, 0x58, 0x47, 0x89, 0x66,
+	0xfb, 0xa3, 0x9a, 0x4f, 0xb2, 0x5e, 0xda, 0xee, 0x61, 0x85, 0x3e, 0x54,
+	0x10, 0x28, 0x6f, 0xb5, 0xdc, 0xa0, 0xbe, 0xc2, 0xdc, 0xe5, 0xdf, 0xda,
+	0x1c, 0x96, 0x5e, 0xc6, 0xb3, 0xc6, 0xa2, 0x43, 0xb1, 0x64, 0xbe, 0xec,
+	0xe1, 0x77, 0x0b, 0xee, 0x3b, 0x60, 0xaf, 0xf8, 0xb0, 0x67, 0x24, 0xae,
+	0x8c, 0x6c, 0x00, 0x2d, 0xf7, 0xe4, 0x94, 0x22, 0x6f, 0xba, 0xc9, 0xc9,
+	0x72, 0x3c, 0x59, 0x2a, 0x7f, 0x96, 0xed, 0x51, 0xb7, 0x5e, 0x2c, 0xcf,
+	0xc8, 0x86, 0xa7, 0x2a, 0x1c, 0x83, 0xfe, 0xef, 0x1b, 0x19, 0x23, 0x6a,
+	0xfb, 0x66, 0x9f, 0x21, 0x5e, 0xa2, 0x74, 0xc9, 0xf1, 0x2f, 0x6d, 0x7d,
+	0x13, 0xce, 0xef, 0xb3, 0x16, 0xee, 0xd5, 0xe3, 0xbe, 0xa0, 0xed, 0x97,
+	0xd3, 0x15, 0xda, 0x8c, 0xdc, 0xdf, 0x49, 0x1d, 0x9f, 0x11, 0xc2, 0x11,
+	0x04, 0xcf, 0xf9, 0x46, 0x77, 0x3f, 0x55, 0xe1, 0x1e, 0x47, 0x10, 0xfc,
+	0x88, 0x76, 0xf1, 0xde, 0x22, 0xc6, 0x0b, 0x71, 0xb0, 0x35, 0x17, 0x85,
+	0x5c, 0x9c, 0x1a, 0x20, 0x7e, 0x05, 0x1e, 0x6a, 0x8f, 0x7b, 0xa3, 0xc4,
+	0x92, 0x9f, 0x2a, 0xb7, 0x24, 0x3f, 0x5d, 0x76, 0x81, 0x67, 0xce, 0x3b,
+	0x9e, 0x9c, 0xb0, 0x73, 0xce, 0x96, 0x89, 0xdf, 0xd7, 0xda, 0x87, 0x7c,
+	0x61, 0x85, 0xbf, 0x44, 0x98, 0xaa, 0xb0, 0x10, 0xb6, 0xa4, 0xc5, 0x4d,
+	0x10, 0xfc, 0xd8, 0x37, 0x6b, 0x3a, 0x55, 0x94, 0x29, 0x8c, 0x9b, 0xdb,
+	0xac, 0x88, 0x87, 0x58, 0xf2, 0x0e, 0x8c, 0xfd, 0x29, 0x8c, 0xbd, 0xbf,
+	0xcc, 0xf1, 0x20, 0x2b, 0x30, 0xf7, 0xa9, 0x4a, 0x08, 0x6f, 0xbd, 0xb1,
+	0xc3, 0x35, 0xef, 0xb5, 0x36, 0x5e, 0xf8, 0xac, 0x11, 0xd9, 0xae, 0xbc,
+	0x7e, 0xd0, 0xd7, 0xe2, 0xa6, 0xa8, 0xfc, 0x22, 0xe4, 0x6e, 0x20, 0x8f,
+	0x42, 0x9e, 0x2d, 0x6a, 0xba, 0xc9, 0x5c, 0xce, 0xff, 0x23, 0xf2, 0xeb,
+	0xeb, 0x18, 0x5f, 0x1e, 0xf6, 0x68, 0xbb, 0x2e, 0x05, 0x8b, 0x1e, 0xe5,
+	0xf3, 0x06, 0x99, 0x71, 0x73, 0xbd, 0xd0, 0x15, 0x28, 0x6b, 0xa5, 0xbf,
+	0x9d, 0xcc, 0x44, 0x52, 0xc9, 0x49, 0x61, 0x3e, 0x14, 0x73, 0x15, 0x98,
+	0x23, 0x44, 0xd9, 0x10, 0x85, 0xcc, 0xe3, 0x1a, 0x9a, 0xf1, 0x26, 0xcb,
+	0xd5, 0xba, 0x07, 0x84, 0x7b, 0x86, 0xa9, 0xc4, 0x3e, 0x6d, 0x9f, 0x88,
+	0x8c, 0x17, 0x58, 0x77, 0x3b, 0xac, 0x13, 0xaf, 0xa6, 0xbe, 0xce, 0xe1,
+	0x02, 0x9f, 0x87, 0x71, 0xac, 0x58, 0x2c, 0x53, 0x90, 0x97, 0x23, 0x03,
+	0xf2, 0x32, 0xed, 0xce, 0x61, 0xd0, 0xb6, 0xeb, 0xf1, 0xbd, 0x29, 0xcf,
+	0xf8, 0xb2, 0x94, 0x19, 0xec, 0xa3, 0x9d, 0x9d, 0x53, 0x9a, 0x27, 0x44,
+	0xa1, 0x6d, 0x2c, 0x5b, 0x96, 0x91, 0x6c, 0xc1, 0xc6, 0x7a, 0x46, 0x39,
+	0xe7, 0x0d, 0x35, 0x73, 0x6f, 0x95, 0x28, 0x60, 0x1a, 0x89, 0x24, 0x9d,
+	0x06, 0xef, 0x23, 0x2d, 0x46, 0xe7, 0x43, 0xee, 0xb7, 0xdd, 0xdf, 0xce,
+	0x3d, 0x53, 0x05, 0x1f, 0x5a, 0xb5, 0xdf, 0x7e, 0x8d, 0x1a, 0xfa, 0xf3,
+	0x04, 0xf4, 0xa0, 0x95, 0x95, 0xb1, 0x91, 0xae, 0x65, 0xfa, 0xe6, 0xf8,
+	0xd2, 0x1e, 0xf1, 0x92, 0x23, 0xc3, 0x65, 0x51, 0x91, 0x21, 0x37, 0x36,
+	0x5c, 0x5e, 0x49, 0xf3, 0x4f, 0x55, 0xfe, 0xbd, 0xb5, 0x05, 0x6b, 0x63,
+	0xaa, 0xb5, 0xef, 0xc8, 0x77, 0x2b, 0xf6, 0x2b, 0x92, 0x26, 0x07, 0x86,
+	0xfb, 0xb4, 0x5c, 0x93, 0xf4, 0x5b, 0x1b, 0xa0, 0x7c, 0x66, 0xb4, 0x8f,
+	0xc6, 0x9c, 0x8b, 0x98, 0xcd, 0x3d, 0x33, 0xb8, 0x4e, 0x97, 0x1d, 0x99,
+	0x82, 0x7c, 0x38, 0x20, 0x7f, 0x1f, 0xa4, 0xe3, 0xe6, 0xbd, 0x59, 0x5f,
+	0xd6, 0xe7, 0x5e, 0x44, 0xb3, 0xe4, 0x4f, 0x46, 0x25, 0x77, 0x92, 0x7b,
+	0x60, 0xcf, 0xed, 0xaf, 0xe6, 0x6d, 0x50, 0x0e, 0x70, 0xbf, 0xd6, 0x91,
+	0x3c, 0xfc, 0xda, 0x11, 0xee, 0xc3, 0xf7, 0xff, 0x1f, 0xf4, 0xc1, 0x7a,
+	0x61, 0xdb, 0x16, 0xb4, 0x6d, 0xb4, 0x6d, 0x47, 0xef, 0x78, 0x73, 0x6d,
+	0x5b, 0xd1, 0x36, 0x16, 0x8e, 0xfb, 0x06, 0xdb, 0x6a, 0x7c, 0x5e, 0x33,
+	0x5c, 0x28, 0x2e, 0xc1, 0x4f, 0x4e, 0x4c, 0x48, 0xda, 0x19, 0x1f, 0xd0,
+	0xf3, 0xb9, 0x66, 0xb8, 0x0c, 0x38, 0xe2, 0x41, 0x90, 0xf7, 0x43, 0x3d,
+	0xcc, 0x7f, 0xc7, 0x44, 0x3c, 0x96, 0x71, 0xdf, 0x92, 0xfe, 0x04, 0xa3,
+	0xa4, 0x2e, 0xf3, 0xd9, 0x24, 0xcf, 0xfd, 0xc9, 0xf8, 0x46, 0xdc, 0x55,
+	0x17, 0x71, 0x92, 0xf5, 0x18, 0xef, 0xdd, 0x68, 0xcb, 0x23, 0x2c, 0x4f,
+	0x45, 0x21, 0x4b, 0x4c, 0x79, 0xc4, 0x96, 0x03, 0x26, 0x3f, 0x9f, 0x04,
+	0xb7, 0xd9, 0x72, 0x3e, 0x2b, 0x5d, 0x6e, 0x9e, 0x0d, 0x0f, 0x8d, 0x09,
+	0xe3, 0x3a, 0x99, 0xeb, 0x1a, 0x64, 0x2b, 0xd6, 0x87, 0x3e, 0xa3, 0x23,
+	0xcd, 0x80, 0xe3, 0x9c, 0xff, 0x76, 0xd8, 0xd6, 0x81, 0xfc, 0xc0, 0x37,
+	0xf4, 0x3f, 0x2b, 0x3d, 0x69, 0xe5, 0x30, 0x07, 0x20, 0x90, 0x9d, 0xfe,
+	0xb6, 0xc4, 0x2e, 0xfc, 0x1e, 0xef, 0x4f, 0xca, 0xec, 0x20, 0xe8, 0xb1,
+	0x9f, 0xbc, 0xb1, 0x15, 0x36, 0x0f, 0x7e, 0xf7, 0xb4, 0xc8, 0x92, 0x9b,
+	0x73, 0xd7, 0xc1, 0x5f, 0x1b, 0xc1, 0xac, 0xe6, 0x0a, 0x9e, 0x7b, 0x1b,
+	0x84, 0x5c, 0xda, 0xed, 0xc1, 0xbd, 0x76, 0xbe, 0xdf, 0xc2, 0x7c, 0x7f,
+	0xad, 0x59, 0x9a, 0x59, 0x5e, 0x5b, 0xb7, 0x51, 0xf6, 0xb8, 0xdb, 0xdd,
+	0xd8, 0x8a, 0xba, 0xe7, 0x51, 0x97, 0x65, 0x9e, 0xcb, 0x1c, 0x9d, 0xd9,
+	0x32, 0xe9, 0xcc, 0xc0, 0xda, 0xd5, 0x13, 0x04, 0xd7, 0xf9, 0x1c, 0x37,
+	0x08, 0xae, 0xf7, 0xfb, 0xdc, 0x67, 0xe5, 0xf9, 0xc0, 0xd8, 0x54, 0x21,
+	0xed, 0x3c, 0x67, 0xe5, 0x75, 0x10, 0xbc, 0xec, 0xf7, 0xca, 0xef, 0x54,
+	0x52, 0x8f, 0xd3, 0xe7, 0x3e, 0x83, 0xe7, 0x33, 0xbe, 0xc9, 0x2b, 0xfa,
+	0x13, 0xb4, 0x8b, 0xab, 0x7e, 0xd0, 0xb0, 0x27, 0x5f, 0xd4, 0x3e, 0x3a,
+	0xf1, 0x67, 0x62, 0xfc, 0x55, 0x18, 0x30, 0x61, 0x2f, 0xb3, 0xc9, 0x65,
+	0x7e, 0xa0, 0xa6, 0xdf, 0xda, 0x77, 0x0a, 0xef, 0x58, 0x16, 0x04, 0x97,
+	0x0c, 0xfc, 0x31, 0xe6, 0x94, 0x2a, 0x71, 0xef, 0xee, 0x03, 0x9a, 0xff,
+	0x04, 0x7e, 0x3d, 0xe9, 0x24, 0xea, 0x2a, 0xe5, 0x1d, 0xee, 0x52, 0xa9,
+	0x9c, 0xc8, 0x5b, 0xb0, 0xfe, 0x5c, 0x63, 0x30, 0x48, 0x1b, 0x60, 0xdf,
+	0xb6, 0xbd, 0xd9, 0xc4, 0x92, 0xe8, 0x4b, 0xa7, 0x37, 0xc1, 0xd7, 0xd5,
+	0xf6, 0x4c, 0x14, 0x7c, 0x3d, 0xd1, 0x16, 0x04, 0xef, 0xf7, 0xc3, 0x35,
+	0xb3, 0xb1, 0x6a, 0xe8, 0xf8, 0x6c, 0xff, 0xb9, 0x66, 0x63, 0xc7, 0x31,
+	0x4f, 0x30, 0xa9, 0xe3, 0xfa, 0xaa, 0x1d, 0x3a, 0x64, 0xdb, 0x57, 0x39,
+	0x7e, 0x8e, 0xe5, 0xef, 0xf3, 0x43, 0x98, 0xaa, 0xed, 0xb3, 0xfd, 0xeb,
+	0xac, 0xcd, 0x19, 0x05, 0x2e, 0x3d, 0xb7, 0x4b, 0xfd, 0x4d, 0x60, 0x74,
+	0x6b, 0x48, 0xc3, 0x7f, 0x17, 0x3c, 0x18, 0x37, 0xcf, 0x99, 0x6d, 0xec,
+	0x63, 0xab, 0x4c, 0x6e, 0xc3, 0x73, 0xf4, 0x5a, 0xdc, 0x87, 0x2f, 0x8b,
+	0xc8, 0x15, 0x89, 0x61, 0xb5, 0xcd, 0x7d, 0x50, 0xfa, 0xac, 0x8c, 0xfb,
+	0x1a, 0xf4, 0x7d, 0x0e, 0xfe, 0x78, 0x93, 0x3c, 0x08, 0x9a, 0x56, 0x03,
+	0xa9, 0xe4, 0x82, 0x4a, 0xf5, 0xce, 0xa8, 0x94, 0x3f, 0xa6, 0xae, 0xe7,
+	0xbc, 0x06, 0x89, 0x8b, 0x19, 0xe2, 0xb7, 0x08, 0xfc, 0x17, 0x81, 0xe3,
+	0x8b, 0xee, 0xf1, 0xfa, 0x56, 0xb7, 0x18, 0xfd, 0x96, 0xd3, 0xb4, 0x69,
+	0xec, 0xf2, 0x3f, 0xf6, 0xc3, 0x35, 0x84, 0x6d, 0xc8, 0x1c, 0x99, 0xba,
+	0x6b, 0x94, 0xe5, 0x1a, 0x41, 0x31, 0xe4, 0x40, 0xf7, 0xa9, 0xe4, 0x84,
+	0x5a, 0x0a, 0x36, 0xed, 0xe8, 0xee, 0x7d, 0x42, 0xf7, 0x93, 0xf2, 0xd3,
+	0x2a, 0x0f, 0x78, 0xb6, 0x4a, 0xd3, 0x0e, 0xe2, 0x99, 0xb0, 0xc6, 0x18,
+	0x4f, 0x72, 0xef, 0x40, 0xdd, 0x31, 0xa5, 0xf7, 0xa0, 0x6d, 0x1d, 0xc2,
+	0x1c, 0x5f, 0x2f, 0xcd, 0xd4, 0x43, 0x8c, 0x93, 0xbd, 0x96, 0x2e, 0x84,
+	0x4c, 0x3a, 0x46, 0x19, 0x18, 0x31, 0xb1, 0xdf, 0xca, 0xcf, 0xa1, 0x9d,
+	0xce, 0x67, 0x89, 0x45, 0x21, 0xa3, 0xa6, 0xc0, 0xc5, 0x87, 0x8e, 0x49,
+	0xb4, 0xc1, 0xfb, 0x5f, 0xcd, 0xc6, 0x6f, 0xa2, 0x0f, 0xc5, 0xb1, 0x1b,
+	0x24, 0xbf, 0x26, 0xde, 0x52, 0x02, 0xfc, 0xcd, 0x32, 0x79, 0x8c, 0x6b,
+	0x11, 0x85, 0xcc, 0xe1, 0xd8, 0x12, 0xcd, 0xf4, 0x07, 0xc1, 0x38, 0xcb,
+	0x4f, 0x92, 0x7f, 0x25, 0xc5, 0x77, 0xb9, 0x93, 0x0b, 0x9b, 0xd4, 0x0a,
+	0x59, 0xdb, 0x62, 0xe1, 0xd0, 0x78, 0x92, 0x92, 0x96, 0x23, 0xd4, 0x37,
+	0xb7, 0xd5, 0xc0, 0x33, 0x7a, 0xc7, 0x94, 0xd7, 0xf8, 0x26, 0xe0, 0xf9,
+	0x3d, 0xc0, 0xd3, 0x62, 0xe1, 0x69, 0x5c, 0x05, 0x4f, 0x4b, 0x08, 0x0f,
+	0xe4, 0x1c, 0xe5, 0x6a, 0xec, 0x9a, 0x74, 0x59, 0x9c, 0xbc, 0x27, 0x9d,
+	0x4a, 0xfb, 0x2f, 0xd4, 0x37, 0x8d, 0xee, 0xf8, 0x80, 0x2b, 0xe3, 0x5a,
+	0xd7, 0x44, 0xaf, 0xe9, 0x2e, 0x2f, 0xc0, 0x7a, 0x15, 0x27, 0xe3, 0x11,
+	0xf6, 0x7a, 0x76, 0xd5, 0x3d, 0x90, 0xff, 0x8b, 0xa9, 0xa8, 0xb5, 0x25,
+	0x4a, 0x3e, 0xfd, 0x96, 0xb8, 0xde, 0xdb, 0xaf, 0xc2, 0xf4, 0x12, 0x60,
+	0x82, 0x3c, 0x3e, 0xd6, 0xe7, 0x8e, 0xca, 0xa5, 0xda, 0x37, 0xb3, 0xb8,
+	0xc6, 0xdc, 0x62, 0x35, 0x73, 0x83, 0xfe, 0x53, 0xe1, 0xdc, 0x20, 0x13,
+	0x51, 0xaf, 0x24, 0xf7, 0x5b, 0x5c, 0xb4, 0x62, 0x4e, 0xb1, 0x9a, 0xf9,
+	0x74, 0x27, 0xf6, 0xb3, 0xcc, 0xcc, 0xa7, 0x27, 0xef, 0xc5, 0x2c, 0x7e,
+	0x57, 0xc3, 0x58, 0xf5, 0x17, 0x67, 0x24, 0x90, 0x29, 0x1f, 0x6b, 0xd4,
+	0x4b, 0xff, 0x24, 0x66, 0xf3, 0x98, 0x15, 0x9e, 0x37, 0x58, 0xfe, 0x72,
+	0x25, 0xaf, 0xfd, 0xb7, 0x2f, 0xad, 0x37, 0x7c, 0x1a, 0xb5, 0xf9, 0x6b,
+	0xfc, 0xdd, 0xb1, 0xde, 0xee, 0xef, 0xe7, 0xd2, 0xf2, 0xfb, 0xeb, 0x69,
+	0x97, 0x34, 0x78, 0x43, 0xab, 0xca, 0x62, 0x28, 0xbb, 0x7d, 0xbd, 0x95,
+	0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1a, 0xf3, 0x34, 0xf8, 0x8e, 0x32, 0xb8,
+	0x16, 0x27, 0x7d, 0x60, 0x45, 0xf2, 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc,
+	0x51, 0x7d, 0x27, 0x8c, 0xa3, 0xe3, 0x77, 0x3d, 0xdb, 0x9f, 0xf8, 0x26,
+	0xae, 0xe5, 0xdb, 0x53, 0xe0, 0xfb, 0x03, 0xbe, 0x13, 0x9d, 0x65, 0x1e,
+	0x80, 0xa6, 0xe1, 0xda, 0xbe, 0xaf, 0x47, 0xdf, 0x21, 0x2d, 0x93, 0x5e,
+	0xae, 0xd7, 0x74, 0xd3, 0x44, 0x5d, 0x7c, 0x8c, 0xf4, 0xc7, 0x58, 0x72,
+	0xb3, 0xd6, 0x8f, 0xd5, 0x75, 0x6c, 0x82, 0xae, 0x89, 0x1b, 0x1e, 0x75,
+	0xcd, 0x7e, 0x77, 0xb5, 0xbf, 0x31, 0xf4, 0x47, 0x3b, 0x0d, 0x7e, 0xba,
+	0xc7, 0x68, 0x0e, 0xe5, 0x97, 0x13, 0x55, 0x57, 0x6a, 0x3f, 0x33, 0xa6,
+	0xf3, 0x8e, 0x96, 0xeb, 0x4e, 0xd8, 0xb1, 0x49, 0xb7, 0x26, 0xfe, 0x5f,
+	0x1d, 0x5f, 0x1c, 0xb5, 0x4d, 0x40, 0x65, 0x8d, 0x32, 0x35, 0x40, 0x1a,
+	0xe5, 0xdc, 0xb5, 0x0d, 0x75, 0x0d, 0xed, 0x08, 0x43, 0x9f, 0xb4, 0x9d,
+	0xa2, 0xd7, 0x64, 0x0b, 0x8d, 0xc6, 0x67, 0x89, 0xcb, 0xe6, 0x06, 0x9d,
+	0x47, 0x80, 0xb2, 0x72, 0xa8, 0xcb, 0xa2, 0x32, 0xdb, 0xff, 0xbf, 0x83,
+	0xf4, 0x5e, 0xd6, 0xad, 0xbb, 0x6f, 0x9f, 0x98, 0x11, 0x8d, 0xa7, 0xbf,
+	0xa8, 0xe2, 0xc9, 0xce, 0x2d, 0xbe, 0x7a, 0x6e, 0x05, 0xc0, 0x7b, 0x0f,
+	0x64, 0x27, 0xd7, 0xc9, 0xe4, 0x6f, 0x3f, 0x2e, 0x4e, 0x34, 0xd3, 0x5b,
+	0x6f, 0x6e, 0xa5, 0x10, 0xaf, 0x9c, 0x1b, 0x68, 0x35, 0x9c, 0x17, 0x69,
+	0x3b, 0xae, 0xf7, 0x89, 0x94, 0x22, 0x2c, 0xad, 0xab, 0x70, 0x1b, 0xd2,
+	0x9d, 0xa1, 0xb9, 0xa7, 0x34, 0xcd, 0xb5, 0x58, 0x9a, 0x43, 0x5d, 0x97,
+	0xfb, 0xde, 0xa3, 0x2d, 0x55, 0x9a, 0xdb, 0x60, 0x69, 0xee, 0x99, 0xf5,
+	0x66, 0x4f, 0xfc, 0xfd, 0x2d, 0x66, 0x4f, 0xea, 0x2f, 0x57, 0x3d, 0x6f,
+	0xa2, 0xcd, 0x08, 0x5f, 0x2c, 0x7c, 0xae, 0x85, 0xf5, 0x0c, 0x60, 0xad,
+	0x95, 0x35, 0x4d, 0x36, 0xee, 0xc6, 0xfd, 0x73, 0xfa, 0x7d, 0x51, 0x79,
+	0x14, 0x76, 0x50, 0xbe, 0xfc, 0x8f, 0xc1, 0x02, 0x7c, 0xbf, 0xa9, 0x65,
+	0xdd, 0x7b, 0x5b, 0x0b, 0xf9, 0x6d, 0x06, 0xbf, 0x0e, 0xd6, 0xf8, 0x3c,
+	0x98, 0x2f, 0xca, 0xfe, 0x01, 0xeb, 0x01, 0xb9, 0xbc, 0x5c, 0x97, 0x31,
+	0x0b, 0xe3, 0xe3, 0x30, 0x66, 0x68, 0xf6, 0x13, 0x29, 0xe7, 0xef, 0x84,
+	0x4f, 0x74, 0x0f, 0xf4, 0x24, 0xe9, 0xfb, 0xa5, 0x16, 0x93, 0xe7, 0x1b,
+	0x87, 0x1e, 0xfb, 0x65, 0x9b, 0x0b, 0x75, 0xf8, 0x57, 0xeb, 0xe7, 0xf8,
+	0x82, 0xf6, 0x1d, 0xd2, 0xcc, 0xdf, 0xb7, 0x98, 0x98, 0xf1, 0xb7, 0x5a,
+	0xc8, 0x67, 0x6a, 0xdb, 0x0f, 0x37, 0x68, 0xbe, 0x70, 0xc2, 0xe7, 0xcf,
+	0xb4, 0xae, 0x7c, 0x0e, 0xdb, 0x3d, 0xd9, 0xba, 0xb2, 0x5d, 0x58, 0xfe,
+	0x73, 0x1b, 0x57, 0x96, 0x5f, 0xe3, 0xae, 0x6c, 0xff, 0xf5, 0x55, 0xcf,
+	0x2d, 0x9b, 0x56, 0x3e, 0x5f, 0xbd, 0xea, 0x79, 0x6a, 0xd5, 0xf3, 0x85,
+	0x55, 0xcf, 0x57, 0xb5, 0xad, 0x7c, 0xbe, 0xbd, 0xad, 0x3e, 0xbc, 0x87,
+	0xdb, 0x56, 0xc2, 0x75, 0xa7, 0x8e, 0xf7, 0xcf, 0x54, 0xa2, 0xb2, 0xab,
+	0x80, 0xf7, 0x4e, 0xe7, 0x66, 0xa3, 0xd7, 0x6a, 0xdf, 0x33, 0xbe, 0xf6,
+	0xd7, 0xab, 0xfa, 0xab, 0xb6, 0xdb, 0x5d, 0x6d, 0xe7, 0x57, 0xdb, 0x19,
+	0xd9, 0x36, 0x5b, 0xe1, 0x3b, 0x96, 0x87, 0xfd, 0x9a, 0xb6, 0x53, 0xc5,
+	0x4e, 0x9d, 0x0b, 0x3b, 0xaa, 0x73, 0x61, 0x93, 0xe0, 0xc3, 0x3b, 0x75,
+	0x4c, 0x69, 0x93, 0x42, 0x79, 0xa5, 0x55, 0xc7, 0x95, 0x74, 0x2c, 0xb5,
+	0x30, 0x0a, 0xdb, 0x96, 0x39, 0xb0, 0x81, 0xec, 0xf1, 0xcd, 0xdd, 0xe4,
+	0xc4, 0x1e, 0x0e, 0x86, 0xdd, 0x20, 0x98, 0xf4, 0x6e, 0xb3, 0xf9, 0x62,
+	0xb8, 0x57, 0x4c, 0x1b, 0xea, 0xe0, 0x27, 0xa0, 0x83, 0xab, 0xba, 0xf7,
+	0x4e, 0x8c, 0xb5, 0x00, 0x9a, 0x19, 0x90, 0xdf, 0xad, 0xa4, 0xbe, 0x24,
+	0xfa, 0xcc, 0x4d, 0x3f, 0x6c, 0xb8, 0xa5, 0x4f, 0xbd, 0xdf, 0xf3, 0x61,
+	0xeb, 0x05, 0xf2, 0xb0, 0x3f, 0x08, 0x1a, 0xea, 0x85, 0xbd, 0xe7, 0x69,
+	0xbf, 0xf4, 0xb4, 0xa6, 0x2d, 0xd2, 0x58, 0x8b, 0xce, 0xd7, 0x7f, 0xd4,
+	0x77, 0x62, 0x99, 0xfe, 0x3f, 0x32, 0x71, 0x1a, 0xbf, 0xdb, 0xfd, 0x1a,
+	0xf8, 0x76, 0xa7, 0xb7, 0x05, 0x3e, 0x0a, 0x69, 0x88, 0xf1, 0xaf, 0xcb,
+	0x75, 0x1e, 0x21, 0x03, 0x68, 0x33, 0x51, 0xc6, 0x09, 0x53, 0x83, 0x63,
+	0xc2, 0x79, 0xa7, 0x12, 0x49, 0xa5, 0xed, 0xaa, 0xe0, 0x46, 0x9f, 0x39,
+	0xb6, 0xdc, 0x63, 0x21, 0x3f, 0xef, 0xff, 0xf4, 0x94, 0x97, 0x73, 0x23,
+	0x36, 0x2f, 0x37, 0x53, 0x30, 0xb4, 0x39, 0x41, 0xda, 0x84, 0x3f, 0xb5,
+	0xd8, 0xff, 0xb7, 0x01, 0xed, 0xfb, 0xa4, 0x22, 0xed, 0xff, 0x4d, 0x30,
+	0x17, 0x65, 0x5f, 0x84, 0x7b, 0xff, 0xa7, 0x33, 0x1a, 0x57, 0x77, 0xca,
+	0x81, 0x22, 0x6d, 0xe1, 0x98, 0xce, 0xe7, 0x18, 0xf7, 0x69, 0xa7, 0xc5,
+	0x80, 0xc7, 0x0f, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x47, 0x50, 0x27, 0x22,
+	0x63, 0x60, 0xf1, 0xd9, 0x02, 0xf9, 0x93, 0xf7, 0x28, 0xea, 0xbb, 0x32,
+	0x5f, 0xb8, 0x59, 0xe7, 0xdb, 0x9d, 0x46, 0xdb, 0x27, 0x71, 0xcd, 0x16,
+	0x26, 0xd0, 0x66, 0xaf, 0xae, 0x3f, 0x5b, 0x62, 0x8e, 0xb2, 0x40, 0x2e,
+	0xed, 0x97, 0xfc, 0x5c, 0x97, 0x8c, 0xc5, 0x17, 0x66, 0xa2, 0xcb, 0x71,
+	0x99, 0x8f, 0x6f, 0xe0, 0x1e, 0x47, 0xfe, 0x4a, 0xee, 0x07, 0x4b, 0x74,
+	0x74, 0xbb, 0xea, 0x6d, 0xd3, 0x3e, 0xd7, 0xa0, 0xec, 0xac, 0x0c, 0xc9,
+	0x4d, 0x95, 0xcf, 0x6e, 0x36, 0xb1, 0xa8, 0x15, 0xf1, 0xad, 0xc3, 0xc4,
+	0x8a, 0x3a, 0x1a, 0xe5, 0xb9, 0x25, 0x99, 0x3d, 0x25, 0x12, 0x39, 0x1a,
+	0xc6, 0x12, 0x59, 0xe6, 0x4a, 0xd7, 0x95, 0x80, 0xeb, 0x14, 0x64, 0x6b,
+	0x3c, 0x26, 0x5f, 0xdc, 0x16, 0x8e, 0x95, 0x0b, 0xa6, 0xb7, 0xe5, 0xe4,
+	0xd3, 0xb8, 0xb2, 0x57, 0xa6, 0x4a, 0x19, 0xc5, 0x71, 0xbf, 0x13, 0x50,
+	0x96, 0xa9, 0x21, 0x4f, 0x72, 0x6d, 0xe1, 0xd8, 0xf0, 0x6f, 0x76, 0x84,
+	0xe3, 0xd3, 0xe6, 0x36, 0x67, 0x1e, 0xf2, 0xdc, 0x77, 0x01, 0xfd, 0x45,
+	0x86, 0xee, 0xde, 0x40, 0xdf, 0x61, 0x58, 0xd8, 0x0e, 0x32, 0x5d, 0xb1,
+	0x6f, 0xc2, 0x49, 0xf8, 0x6b, 0xe1, 0x5c, 0x4c, 0xc6, 0x81, 0xa3, 0xdc,
+	0xeb, 0xc2, 0xdb, 0xe7, 0x7a, 0xaa, 0x1e, 0xbc, 0xa3, 0x36, 0x96, 0xc8,
+	0xf8, 0xe0, 0x3a, 0xe0, 0xad, 0x05, 0xe5, 0x1f, 0x94, 0xa9, 0x63, 0x6f,
+	0xdb, 0xcc, 0xbd, 0xec, 0x06, 0xcf, 0xb1, 0x39, 0xa7, 0x3c, 0xbf, 0x73,
+	0x37, 0xea, 0xf0, 0xfd, 0xcd, 0x68, 0x93, 0xca, 0x65, 0x22, 0x9b, 0xe1,
+	0x13, 0x71, 0xdc, 0x20, 0xd2, 0xb5, 0xa3, 0x59, 0xe7, 0x90, 0xca, 0x29,
+	0xea, 0xf3, 0xb0, 0xed, 0xdd, 0x3a, 0x47, 0x03, 0x7e, 0x7b, 0x6e, 0x24,
+	0x42, 0xf9, 0xd5, 0x2b, 0xc3, 0xd4, 0x27, 0xa7, 0x6e, 0xd6, 0xb4, 0xdf,
+	0xbd, 0x8d, 0x67, 0x99, 0xfa, 0x8c, 0x8d, 0x1e, 0x27, 0x8c, 0xa3, 0x28,
+	0x87, 0xfd, 0xfe, 0x9a, 0x30, 0xdc, 0xf5, 0x26, 0x61, 0xb8, 0xeb, 0x4d,
+	0xc2, 0x40, 0x5c, 0x00, 0x8e, 0xca, 0x5f, 0x6c, 0x08, 0x63, 0xd5, 0x97,
+	0x62, 0x1e, 0x07, 0x8b, 0x77, 0xc9, 0xa1, 0xa2, 0xa3, 0xe3, 0x8e, 0x0b,
+	0x8a, 0x32, 0xc1, 0x05, 0x4f, 0x82, 0xf7, 0x8a, 0xe0, 0xcd, 0x22, 0x78,
+	0xb1, 0x08, 0xbe, 0x84, 0xfd, 0x7f, 0x06, 0xf6, 0xff, 0x93, 0x58, 0x9b,
+	0xd3, 0x2b, 0x78, 0x39, 0xad, 0x79, 0x39, 0x5f, 0xa4, 0xaf, 0xd6, 0x7f,
+	0x11, 0x7e, 0x8d, 0xca, 0x70, 0x21, 0x05, 0x55, 0xe2, 0x44, 0xb3, 0xfd,
+	0x9f, 0x24, 0xbf, 0xca, 0x83, 0xfe, 0x0d, 0x68, 0x73, 0x18, 0x34, 0x9e,
+	0xa2, 0x1d, 0x48, 0xfb, 0x27, 0x07, 0xde, 0x3c, 0x4c, 0x5f, 0x4d, 0x5d,
+	0xb9, 0x49, 0xa8, 0x5f, 0xa2, 0x3b, 0x98, 0x7b, 0xc8, 0xb9, 0x26, 0x57,
+	0xe1, 0xc9, 0xf0, 0xef, 0x84, 0x47, 0x3d, 0x43, 0xbe, 0x7d, 0x99, 0x7c,
+	0x5b, 0xc3, 0xab, 0x01, 0xe7, 0x17, 0xb8, 0xdb, 0xea, 0xb5, 0xad, 0xd6,
+	0xdf, 0xb4, 0x5c, 0x5f, 0x8f, 0x5f, 0x22, 0x3f, 0x42, 0x27, 0x11, 0xf7,
+	0xc9, 0x4c, 0x64, 0x8b, 0xc5, 0x3d, 0x6c, 0xb7, 0x1d, 0x97, 0x00, 0xf7,
+	0x9d, 0x92, 0x9b, 0x0f, 0xc4, 0xdb, 0x11, 0xf6, 0x59, 0xed, 0xc7, 0xb5,
+	0xfd, 0x8c, 0x17, 0x1c, 0x19, 0xd9, 0xc6, 0x7d, 0x08, 0x07, 0x7a, 0x3e,
+	0x5c, 0x0f, 0xd8, 0xfb, 0x7a, 0xcd, 0x29, 0x63, 0x29, 0x5b, 0x5b, 0x6c,
+	0xfc, 0x89, 0xfd, 0x1d, 0x5e, 0xb5, 0x4e, 0x17, 0x02, 0x9e, 0x11, 0x9b,
+	0xf2, 0x6e, 0xa8, 0xa1, 0x95, 0xfb, 0x2c, 0xad, 0xa8, 0x55, 0xf3, 0xb8,
+	0xdd, 0xd2, 0x4a, 0x08, 0x6f, 0x3c, 0xa4, 0x95, 0xa6, 0x90, 0x56, 0x72,
+	0x33, 0x21, 0xad, 0xb0, 0xed, 0xed, 0x21, 0xad, 0x24, 0x6b, 0x69, 0x25,
+	0x37, 0xe3, 0xe0, 0x5a, 0x0d, 0x07, 0xe9, 0x85, 0xfd, 0x90, 0x5e, 0x00,
+	0x4b, 0xe5, 0xd6, 0xd6, 0x90, 0x5e, 0xe2, 0xe8, 0xe7, 0x50, 0xd1, 0xe4,
+	0x74, 0xc0, 0xef, 0xb2, 0x3a, 0xc4, 0xc5, 0x9a, 0x1b, 0x1f, 0xb1, 0x3e,
+	0x8d, 0xf8, 0x96, 0x46, 0xaa, 0x79, 0xee, 0xab, 0x68, 0x03, 0xb8, 0x67,
+	0x2e, 0xeb, 0x76, 0x4d, 0x1b, 0xf7, 0xfb, 0x53, 0xa8, 0xbb, 0x07, 0xb4,
+	0x11, 0xe2, 0xe0, 0x7a, 0x8b, 0x83, 0xd5, 0x6b, 0x39, 0x66, 0x71, 0xb0,
+	0xc7, 0xe2, 0x40, 0xf3, 0x4b, 0x8e, 0x6b, 0xa6, 0x34, 0x0e, 0x9a, 0x34,
+	0x0e, 0x44, 0x85, 0x6d, 0xc7, 0xea, 0xe0, 0x80, 0x75, 0xf6, 0xe8, 0xf9,
+	0x47, 0x30, 0xff, 0xfd, 0x98, 0xbf, 0xd2, 0xf3, 0xe7, 0x3a, 0x70, 0xfe,
+	0x80, 0xa5, 0x72, 0x72, 0x79, 0xfe, 0x6d, 0xe8, 0xe3, 0x60, 0x31, 0xa2,
+	0xe7, 0x0f, 0xdb, 0x7e, 0x30, 0x9c, 0xff, 0xe9, 0x8a, 0xc9, 0x7f, 0x3e,
+	0xbd, 0x46, 0xcf, 0x4d, 0x59, 0xde, 0xf0, 0xb4, 0x5f, 0xcc, 0x98, 0xf6,
+	0x19, 0xe8, 0xb6, 0x69, 0x3f, 0x69, 0xcf, 0x43, 0x19, 0x7b, 0xe9, 0x1b,
+	0x3e, 0x79, 0xe7, 0xe3, 0x3a, 0x0f, 0xe5, 0x71, 0xda, 0x4d, 0xc5, 0x36,
+	0x19, 0x99, 0xae, 0x85, 0x9b, 0xf0, 0xe6, 0xb4, 0x1c, 0xcd, 0x62, 0x7e,
+	0xe3, 0x7e, 0x2f, 0xe4, 0x9b, 0xa6, 0x25, 0x94, 0xa7, 0x72, 0xc3, 0x91,
+	0x26, 0x51, 0x0f, 0x7c, 0x08, 0x73, 0x8e, 0xca, 0x66, 0xaf, 0xdb, 0xdd,
+	0xa1, 0xa8, 0x0b, 0x2f, 0xab, 0xd1, 0x85, 0xed, 0x56, 0x17, 0x6e, 0xa2,
+	0x2e, 0x04, 0xdc, 0x77, 0xca, 0xe1, 0x22, 0xd7, 0x2f, 0x97, 0x6c, 0x82,
+	0xfe, 0xff, 0x81, 0xc7, 0xb3, 0x27, 0x3a, 0x6e, 0x96, 0x38, 0xac, 0x69,
+	0x99, 0x3a, 0x2d, 0xa5, 0xcf, 0x6a, 0x2c, 0xd2, 0xc6, 0x8e, 0x33, 0x16,
+	0x4a, 0xbd, 0xf7, 0xe3, 0xe0, 0x73, 0x75, 0xf4, 0xde, 0x64, 0xd1, 0xd8,
+	0x6f, 0x0d, 0xb0, 0x09, 0xe5, 0x44, 0x3b, 0xae, 0x8d, 0x3c, 0xab, 0xd0,
+	0xdb, 0xa3, 0x9a, 0xa5, 0xe1, 0x44, 0xab, 0x4c, 0x4c, 0x1b, 0x1b, 0x57,
+	0x9d, 0x00, 0xfe, 0x4f, 0x30, 0xdf, 0x55, 0x74, 0x7e, 0x7e, 0xb6, 0x04,
+	0x3b, 0x77, 0xf6, 0x4e, 0x93, 0xb7, 0x32, 0xdd, 0xa0, 0x7f, 0xd3, 0x06,
+	0xc9, 0xfb, 0x69, 0xe8, 0xbb, 0x98, 0x4c, 0xa0, 0xcf, 0xee, 0x6d, 0x8d,
+	0x98, 0x73, 0x1c, 0x6d, 0xe9, 0xf3, 0x31, 0x8e, 0xd6, 0x28, 0xd1, 0xd9,
+	0xb8, 0xce, 0xad, 0xe7, 0xd9, 0xd1, 0xcc, 0x60, 0x1b, 0xde, 0x31, 0x9f,
+	0xc1, 0xc5, 0x58, 0xa1, 0xec, 0x47, 0xbf, 0x47, 0xc5, 0xee, 0xf7, 0x0c,
+	0x69, 0xfd, 0x17, 0x39, 0xea, 0xda, 0x33, 0x74, 0x83, 0x58, 0xf7, 0x7a,
+	0x7a, 0xd1, 0x18, 0xb9, 0x19, 0xac, 0x9f, 0x3a, 0x15, 0xc5, 0xbd, 0x13,
+	0xf7, 0xb0, 0xbf, 0x50, 0x8f, 0x40, 0x37, 0xbe, 0xb3, 0x6f, 0xa3, 0x34,
+	0x03, 0xdf, 0xb3, 0x0a, 0xb8, 0x36, 0x39, 0x59, 0x39, 0xcd, 0x0b, 0x55,
+	0x7a, 0x78, 0xf2, 0x75, 0xf9, 0x81, 0x34, 0x41, 0x5a, 0xa0, 0x5c, 0x24,
+	0x6d, 0x50, 0x26, 0x3a, 0xfa, 0x6c, 0x03, 0xe9, 0xe1, 0x09, 0xdf, 0x8b,
+	0x70, 0xdf, 0xde, 0xc4, 0xe5, 0x49, 0x1b, 0xa4, 0xf9, 0xa4, 0x8e, 0xd7,
+	0xa7, 0xe5, 0x7b, 0x92, 0x6e, 0xeb, 0x86, 0x5d, 0xf6, 0x2f, 0xbb, 0xc6,
+	0xe6, 0xdc, 0xad, 0xa6, 0x39, 0xe8, 0x26, 0xe6, 0xd0, 0xf5, 0xca, 0xfb,
+	0x2a, 0x39, 0xe0, 0xe1, 0x5e, 0x28, 0xe5, 0x3b, 0x75, 0x5e, 0xe2, 0xee,
+	0xc2, 0x46, 0xb9, 0xc5, 0x8f, 0xd9, 0xb8, 0xfb, 0x41, 0xd0, 0xc1, 0xa2,
+	0x23, 0x27, 0xce, 0xe2, 0x3a, 0xe7, 0x70, 0xfd, 0xce, 0xfb, 0xe9, 0x94,
+	0x22, 0xb3, 0x7b, 0xd1, 0xc4, 0xa2, 0xf4, 0xb9, 0x13, 0xfa, 0x0c, 0xc8,
+	0x82, 0xd3, 0x74, 0xe2, 0xd0, 0x46, 0xe3, 0x4b, 0x03, 0x16, 0xaf, 0xd1,
+	0x1d, 0xa1, 0x2d, 0xe7, 0x07, 0x41, 0x96, 0x76, 0x83, 0x28, 0xed, 0x23,
+	0xc1, 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x5b, 0x9d, 0xc6, 0x53, 0x2f, 0x5a,
+	0x5a, 0x91, 0x88, 0x1a, 0x7a, 0xc6, 0x69, 0x38, 0x71, 0x9c, 0x6b, 0xa6,
+	0xf3, 0xa4, 0x0d, 0x5d, 0x3d, 0xe7, 0x54, 0xe9, 0xea, 0x1b, 0xf6, 0xb7,
+	0x1a, 0x6a, 0x92, 0x74, 0xaa, 0x09, 0xf3, 0x1d, 0x2e, 0x84, 0x30, 0x7e,
+	0x1f, 0x70, 0x11, 0x1e, 0xd0, 0xed, 0xec, 0x9f, 0xe1, 0x5a, 0x02, 0x2c,
+	0xf7, 0x01, 0xee, 0xf3, 0x80, 0xf9, 0x02, 0x2e, 0xd5, 0x11, 0x91, 0x3f,
+	0x76, 0x22, 0xb3, 0xb5, 0xf0, 0x12, 0xc6, 0xd3, 0x16, 0xde, 0xd7, 0x82,
+	0xd5, 0x95, 0xc5, 0x81, 0x2e, 0xc0, 0x43, 0x38, 0x5f, 0x02, 0x8c, 0xb4,
+	0x5b, 0x9f, 0xc7, 0xb3, 0x0b, 0xf8, 0x5e, 0xb0, 0x30, 0x81, 0x1e, 0xa7,
+	0xff, 0x47, 0xf5, 0x77, 0x81, 0x76, 0xf4, 0x9f, 0xdb, 0xe7, 0xce, 0x55,
+	0x32, 0xa0, 0xc7, 0x21, 0x9e, 0xa7, 0x8a, 0x4b, 0xb4, 0x03, 0xc0, 0xf7,
+	0x3f, 0x94, 0xc8, 0xa9, 0x84, 0x1c, 0x2a, 0x70, 0x0f, 0xe8, 0x24, 0xf0,
+	0xa1, 0xcf, 0xa4, 0xa0, 0xce, 0x15, 0xb8, 0xa0, 0xec, 0x67, 0xb7, 0xe3,
+	0xea, 0xc5, 0xf5, 0x56, 0x5c, 0x20, 0x87, 0xd9, 0x13, 0xb8, 0xfa, 0xd0,
+	0xb7, 0x8a, 0x37, 0x09, 0x73, 0xa9, 0xbe, 0x8d, 0x36, 0xda, 0xb6, 0xcc,
+	0xa9, 0xa1, 0x01, 0xe0, 0x6f, 0x00, 0xb0, 0x25, 0x70, 0x31, 0xff, 0xf8,
+	0x87, 0x8e, 0x9c, 0x7a, 0x19, 0x17, 0x18, 0xec, 0x14, 0x08, 0xf3, 0xd4,
+	0x20, 0x2e, 0x28, 0xb1, 0x53, 0x69, 0x5c, 0x23, 0xb8, 0xfe, 0xd2, 0x31,
+	0x3c, 0xd7, 0x09, 0x7c, 0x85, 0x3c, 0x02, 0x9c, 0xaf, 0xe0, 0xb9, 0xaf,
+	0x3b, 0x6f, 0x9c, 0xe7, 0x7e, 0xe2, 0x18, 0x9e, 0x7b, 0xc5, 0xa9, 0xf2,
+	0xdc, 0x59, 0x47, 0x3d, 0xfc, 0x8c, 0x13, 0x79, 0x98, 0xbe, 0xc4, 0x59,
+	0xc7, 0xf0, 0x7f, 0x44, 0x86, 0xf7, 0x82, 0x96, 0x1e, 0x5e, 0xc0, 0x45,
+	0xba, 0x7a, 0x16, 0xe5, 0x2f, 0xac, 0x1a, 0xf7, 0xf9, 0x37, 0x31, 0xee,
+	0xab, 0x76, 0x5c, 0x51, 0xd5, 0x71, 0x2f, 0xa0, 0xef, 0x97, 0xec, 0xb8,
+	0x17, 0x6a, 0xc6, 0x05, 0xad, 0x3c, 0xbc, 0x84, 0x8b, 0x74, 0xf1, 0x22,
+	0xca, 0x43, 0x99, 0x80, 0x85, 0x6e, 0x6e, 0xd0, 0x67, 0x9d, 0xe2, 0x5e,
+	0xc3, 0xb2, 0x6e, 0x4c, 0xd7, 0xe8, 0x87, 0x37, 0xa2, 0x1f, 0x27, 0x8b,
+	0xb4, 0x11, 0x17, 0x6a, 0xe4, 0x02, 0x7d, 0xa3, 0x40, 0x8e, 0x69, 0x3f,
+	0x88, 0x3e, 0x11, 0xfd, 0xa3, 0xd5, 0xb6, 0xd5, 0x27, 0x75, 0xee, 0xd8,
+	0xaf, 0x15, 0x3a, 0xe5, 0xd3, 0x05, 0xda, 0x84, 0xa4, 0x97, 0x20, 0x98,
+	0xd8, 0x41, 0xfb, 0x34, 0x17, 0x5c, 0xe2, 0x91, 0x4e, 0x3c, 0xf7, 0x33,
+	0x6b, 0x75, 0x46, 0x69, 0x18, 0xbe, 0x7b, 0xe6, 0xe8, 0xaf, 0x40, 0x67,
+	0x34, 0x00, 0x6e, 0xd2, 0x5b, 0x87, 0xdc, 0x58, 0x52, 0x53, 0x9b, 0x25,
+	0x21, 0x37, 0x15, 0x1a, 0x61, 0xf7, 0x30, 0xaf, 0xaa, 0x59, 0xba, 0x77,
+	0xc4, 0x4c, 0xde, 0xb7, 0x1b, 0xc7, 0x6f, 0xd7, 0xe4, 0xa1, 0xc7, 0x13,
+	0x78, 0xff, 0x7b, 0x2e, 0xe5, 0x60, 0xdc, 0xbb, 0x56, 0xe7, 0xf4, 0x74,
+	0xed, 0xa0, 0xdd, 0x72, 0xbd, 0xd6, 0xe1, 0xd1, 0x35, 0x76, 0x92, 0xea,
+	0x70, 0xa5, 0x6a, 0xa3, 0x8d, 0x17, 0x52, 0x49, 0xc2, 0xf5, 0x90, 0x70,
+	0xff, 0xeb, 0x1e, 0xc9, 0xfb, 0xad, 0xf0, 0x0b, 0x18, 0x3b, 0x4f, 0xf5,
+	0xd2, 0x36, 0x9a, 0x9d, 0x76, 0x6d, 0x5e, 0xf4, 0x46, 0x79, 0x4e, 0x8f,
+	0xd3, 0xa8, 0x61, 0x34, 0x67, 0x25, 0xb8, 0x8f, 0x10, 0xd3, 0xe7, 0x73,
+	0x66, 0xcb, 0x2d, 0x5a, 0xef, 0xcc, 0x96, 0x99, 0x87, 0x0f, 0x7f, 0xaa,
+	0xcc, 0xbc, 0x7b, 0x5f, 0xdc, 0x77, 0xc2, 0xcf, 0x2d, 0x6f, 0x91, 0xf1,
+	0xe9, 0x75, 0xd2, 0xe8, 0xa9, 0xf8, 0x66, 0xc8, 0x47, 0xb6, 0xe9, 0xda,
+	0x01, 0xff, 0x70, 0x66, 0xab, 0x3c, 0x39, 0xc3, 0xbe, 0x3b, 0x64, 0x6e,
+	0x5e, 0x1c, 0xf7, 0x9d, 0xeb, 0x51, 0x07, 0x72, 0x7d, 0x07, 0xcb, 0x92,
+	0xb8, 0x8b, 0x72, 0xdf, 0x19, 0x95, 0x73, 0x03, 0x7c, 0x66, 0xee, 0xbf,
+	0x44, 0xd9, 0xdf, 0xb9, 0x81, 0x4e, 0x79, 0x7c, 0x1e, 0x34, 0x01, 0xb9,
+	0x3f, 0x72, 0x82, 0x30, 0x89, 0xec, 0x9a, 0x65, 0x2c, 0xbd, 0xdb, 0x65,
+	0xdc, 0x94, 0xfb, 0x34, 0xb7, 0x0c, 0x70, 0x2c, 0xe8, 0x25, 0xe8, 0xb8,
+	0xae, 0x1d, 0x46, 0x16, 0xa4, 0x67, 0x1b, 0x50, 0xce, 0x7e, 0xe1, 0x3f,
+	0xee, 0x65, 0x3f, 0x61, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59, 0x5a,
+	0xa5, 0x3f, 0xce, 0xfc, 0x4c, 0xf6, 0x37, 0xfb, 0xe8, 0xd5, 0x7b, 0x21,
+	0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae, 0xba,
+	0x42, 0xdb, 0x17, 0x73, 0x15, 0xae, 0x20, 0x63, 0x51, 0xe1, 0x1a, 0x25,
+	0xe4, 0xd1, 0xe2, 0xf2, 0x3a, 0x6d, 0x69, 0x58, 0xb9, 0x4e, 0xa4, 0x15,
+	0x7f, 0xcc, 0xda, 0x1e, 0x8b, 0x92, 0x83, 0x5d, 0xd6, 0xab, 0xd7, 0x6c,
+	0x11, 0xb6, 0xac, 0x5d, 0x33, 0x6d, 0xcf, 0xe6, 0xc3, 0x35, 0x1b, 0x85,
+	0xc6, 0x29, 0xab, 0x4d, 0x5c, 0x33, 0x97, 0xf1, 0x6e, 0xe0, 0x3d, 0x87,
+	0x75, 0xca, 0x61, 0x8d, 0x72, 0xe5, 0x0e, 0x99, 0x3d, 0xa6, 0x3a, 0x1b,
+	0x44, 0x92, 0xe3, 0x5e, 0x87, 0x4c, 0xce, 0x33, 0x96, 0xb0, 0x05, 0x36,
+	0xd8, 0x56, 0x5c, 0x9d, 0x78, 0x66, 0x3b, 0xf0, 0x54, 0x59, 0xa1, 0x6d,
+	0xd3, 0x1a, 0x3b, 0xeb, 0x71, 0x8c, 0xcd, 0x1c, 0xe1, 0x27, 0x80, 0x87,
+	0x2a, 0xef, 0x4c, 0xd5, 0xc4, 0x9f, 0x38, 0x57, 0xad, 0x43, 0x31, 0xdf,
+	0xb8, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x36, 0xbe, 0x19, 0x7b, 0x2a, 0x41,
+	0x7b, 0x2a, 0x5b, 0x72, 0xcd, 0xf9, 0x80, 0x51, 0xf8, 0x4e, 0x5e, 0xef,
+	0x26, 0xd2, 0xfa, 0xd8, 0x0c, 0xe1, 0x8a, 0x85, 0x70, 0xad, 0x58, 0x33,
+	0x9e, 0xe7, 0x5a, 0x1b, 0xe7, 0x98, 0x5a, 0xce, 0x5f, 0x34, 0xb1, 0x7d,
+	0xc6, 0x51, 0x3a, 0xeb, 0xc0, 0x74, 0xa7, 0xb6, 0x61, 0x45, 0x8d, 0xc9,
+	0x81, 0x22, 0xcf, 0x82, 0x31, 0x9e, 0x78, 0x23, 0xe3, 0x49, 0xbd, 0xb3,
+	0xf2, 0x5e, 0x8c, 0xcd, 0x5c, 0x1d, 0x65, 0xe3, 0x37, 0x1b, 0x6c, 0x8e,
+	0x48, 0x6d, 0x0c, 0xc7, 0xe4, 0xf2, 0xac, 0xcc, 0x8b, 0x4e, 0x8d, 0x2e,
+	0x61, 0x9d, 0x7f, 0x5d, 0xef, 0x0d, 0x4a, 0x29, 0x02, 0xed, 0x37, 0x3e,
+	0x90, 0x1a, 0x34, 0xe7, 0x60, 0x92, 0xb2, 0xb3, 0x68, 0xe6, 0x7f, 0x5e,
+	0xe7, 0xf4, 0x98, 0xdc, 0x45, 0x93, 0xef, 0x73, 0x8f, 0x9c, 0x87, 0x0e,
+	0xaf, 0xae, 0x6d, 0x93, 0x4c, 0x02, 0x17, 0x59, 0xbd, 0x2f, 0x91, 0x94,
+	0xec, 0xc0, 0xc7, 0x37, 0xf1, 0x9c, 0x44, 0x0c, 0xeb, 0x93, 0x9f, 0xe1,
+	0xd9, 0x49, 0xf6, 0x7b, 0xb1, 0xbe, 0x28, 0x66, 0x99, 0x87, 0x0f, 0x59,
+	0xf9, 0xb6, 0xbe, 0x44, 0xb3, 0x7e, 0xbf, 0xce, 0xe6, 0x5b, 0x3b, 0x22,
+	0x37, 0x06, 0xf2, 0x87, 0x10, 0x9f, 0x8f, 0xd9, 0x39, 0x25, 0x75, 0xcc,
+	0x4a, 0x82, 0x73, 0x7e, 0xc2, 0xc6, 0x2c, 0x39, 0x97, 0x1b, 0x2c, 0x7d,
+	0x1b, 0xfb, 0xa7, 0x6a, 0x43, 0x9b, 0x7d, 0xbf, 0x27, 0xb5, 0x2c, 0xec,
+	0xb7, 0xb6, 0xb3, 0x8e, 0xf3, 0x1c, 0x17, 0x9d, 0x13, 0x10, 0xfa, 0x46,
+	0x3d, 0x35, 0x7e, 0x81, 0xf1, 0xe5, 0xf2, 0xd3, 0xf5, 0x64, 0x54, 0xd5,
+	0x27, 0xa4, 0x2f, 0x37, 0xb1, 0x8d, 0xdf, 0x2d, 0x08, 0x7d, 0xb9, 0x7e,
+	0xeb, 0xcb, 0xb5, 0x6a, 0x5f, 0xce, 0xc4, 0x1e, 0x5a, 0x97, 0x7d, 0xb9,
+	0xfc, 0x74, 0x0e, 0xb4, 0x12, 0x7e, 0x67, 0xc1, 0xd8, 0x42, 0x93, 0x05,
+	0x9e, 0x79, 0x69, 0x94, 0xec, 0xa8, 0x82, 0xdf, 0x60, 0x7c, 0x2c, 0xc6,
+	0x2a, 0x94, 0xfa, 0x96, 0xf5, 0x2f, 0x3a, 0x25, 0xdd, 0xbe, 0x0e, 0xf3,
+	0xbe, 0x53, 0xaf, 0xf9, 0x5c, 0xc1, 0xec, 0x7d, 0x66, 0xf7, 0x32, 0x26,
+	0xc4, 0x73, 0x4d, 0x9a, 0xbf, 0x92, 0xc3, 0x91, 0x5e, 0x63, 0xcf, 0x7a,
+	0xdf, 0x04, 0xde, 0x4f, 0x02, 0xe7, 0x31, 0x3b, 0x6e, 0x12, 0x30, 0x1d,
+	0xc0, 0xda, 0x5c, 0x6b, 0x65, 0x32, 0xc7, 0xde, 0xd3, 0xc4, 0xd8, 0xc0,
+	0x7c, 0x21, 0x8c, 0x11, 0x46, 0xec, 0x99, 0x4a, 0x2f, 0xd2, 0xe8, 0xad,
+	0xab, 0x6b, 0xab, 0x9e, 0x7e, 0x5d, 0xdd, 0x44, 0x5a, 0xba, 0x53, 0xe7,
+	0xb9, 0xac, 0x1f, 0x48, 0xed, 0xd1, 0x39, 0xf2, 0x3a, 0xc6, 0x98, 0x13,
+	0xe6, 0x94, 0x7d, 0x57, 0xde, 0xa1, 0x65, 0xfe, 0x01, 0x9f, 0xfa, 0x6b,
+	0x87, 0xfe, 0xdd, 0x38, 0x14, 0x04, 0xe7, 0x06, 0xee, 0x86, 0xad, 0xe2,
+	0xb9, 0xdf, 0x97, 0xee, 0xc4, 0xb0, 0xb6, 0x9d, 0xb0, 0x46, 0x7b, 0x9b,
+	0x65, 0x9d, 0x77, 0xb3, 0xcd, 0x99, 0xc9, 0x41, 0x6e, 0xa6, 0x60, 0x33,
+	0xf1, 0x4c, 0x70, 0x8f, 0x7d, 0x97, 0x0b, 0x9a, 0x41, 0x47, 0x1f, 0x13,
+	0x23, 0x63, 0xb2, 0x55, 0x19, 0xc3, 0x5c, 0x83, 0x34, 0x09, 0x39, 0x7a,
+	0x44, 0x52, 0xfc, 0xee, 0x07, 0xc7, 0xce, 0xcb, 0xa5, 0xd0, 0xcb, 0x6c,
+	0xa7, 0xbf, 0xd9, 0x83, 0x67, 0xee, 0xe1, 0x78, 0xee, 0x41, 0xe8, 0x96,
+	0xeb, 0xd7, 0xea, 0x96, 0x04, 0xfd, 0xfa, 0x6c, 0x89, 0xbe, 0xe1, 0x7a,
+	0xb4, 0xe9, 0x90, 0x8f, 0x4f, 0x77, 0xb7, 0x91, 0xb7, 0xc6, 0x20, 0xd7,
+	0xd5, 0xfd, 0xe1, 0x59, 0x20, 0x96, 0xf1, 0x3d, 0xfb, 0x6d, 0x92, 0xe4,
+	0xfb, 0x5d, 0xf9, 0x7c, 0x25, 0x95, 0x5c, 0x82, 0x6e, 0x1a, 0x73, 0x7e,
+	0xf1, 0x72, 0x13, 0x53, 0x7d, 0x7b, 0x9b, 0x39, 0x3b, 0xd0, 0x4c, 0x9b,
+	0xdd, 0xc6, 0x59, 0x6b, 0x69, 0x76, 0xc9, 0xca, 0xe3, 0x20, 0x68, 0x1e,
+	0xd0, 0x32, 0x78, 0x0f, 0x65, 0xf0, 0x01, 0xbf, 0xc7, 0xd0, 0xbe, 0xf6,
+	0x99, 0x02, 0xac, 0x23, 0xf0, 0x30, 0x10, 0x65, 0x7e, 0x9e, 0xe5, 0x4f,
+	0x2f, 0xbd, 0x68, 0xe5, 0x92, 0x72, 0xd6, 0xf2, 0xa5, 0xba, 0x2a, 0xb6,
+	0x42, 0xe6, 0x1e, 0x9a, 0xa6, 0x3e, 0xf6, 0x17, 0xbe, 0x0b, 0x39, 0x95,
+	0xd5, 0x78, 0xe8, 0x90, 0xfb, 0xa6, 0x25, 0x7d, 0x1e, 0xba, 0x2a, 0x3f,
+	0xbf, 0x92, 0x37, 0xd7, 0xf6, 0xc7, 0xb9, 0x7e, 0xb8, 0xcd, 0xf8, 0xb6,
+	0x2b, 0xe7, 0xba, 0x80, 0xb9, 0xa6, 0xf5, 0x5c, 0xb9, 0x6f, 0xf3, 0x31,
+	0x3b, 0xd7, 0xf5, 0xe1, 0x5c, 0x07, 0x57, 0xce, 0x35, 0xf4, 0xed, 0x43,
+	0xb9, 0x9b, 0xd4, 0xf9, 0xf2, 0x3a, 0x4f, 0x7b, 0x7a, 0xbd, 0x0c, 0x97,
+	0x5a, 0xad, 0xbc, 0x74, 0xa1, 0x7b, 0x98, 0xc3, 0xbe, 0x70, 0xaf, 0x2b,
+	0x16, 0x67, 0x8a, 0x78, 0xa0, 0xac, 0x6d, 0xd3, 0x67, 0x6c, 0x66, 0xe1,
+	0x5f, 0xdd, 0x5a, 0x60, 0xdd, 0xf0, 0xfd, 0xc5, 0x62, 0xc7, 0xa1, 0x4f,
+	0x4d, 0xbf, 0xa9, 0x77, 0x4d, 0x4c, 0xc1, 0xc4, 0x87, 0x19, 0x17, 0x36,
+	0x67, 0x7f, 0x99, 0x8b, 0x78, 0x07, 0x78, 0xea, 0x53, 0x85, 0xd4, 0x60,
+	0x26, 0x42, 0x39, 0x7a, 0x5c, 0x0e, 0x55, 0x46, 0xa4, 0x4b, 0x9f, 0xff,
+	0x7c, 0xdd, 0xd8, 0x71, 0xba, 0x36, 0x76, 0xcc, 0x74, 0x02, 0xc6, 0x8e,
+	0xf7, 0xfc, 0x0c, 0xb1, 0x63, 0x71, 0x4c, 0xec, 0xb8, 0x9e, 0x7f, 0x35,
+	0x55, 0x3c, 0x8e, 0x79, 0x35, 0x43, 0x96, 0x2c, 0x3a, 0xd9, 0xf9, 0x16,
+	0xdc, 0xcf, 0xe2, 0x1e, 0xc3, 0xfd, 0x3c, 0xee, 0x2e, 0xee, 0x17, 0x70,
+	0x8f, 0xcb, 0xd4, 0xb2, 0xce, 0x38, 0x0e, 0xb9, 0x41, 0x5d, 0xc6, 0xb6,
+	0xc6, 0x1f, 0x98, 0x2b, 0xb7, 0xf3, 0x7b, 0x2d, 0xce, 0xec, 0x3c, 0xe7,
+	0xd0, 0x2a, 0x93, 0xd3, 0x94, 0xd9, 0x6d, 0x52, 0x9a, 0x0e, 0x6d, 0xdb,
+	0x9f, 0xef, 0xe0, 0x9e, 0xc1, 0x98, 0x84, 0xb6, 0xeb, 0x3d, 0x1d, 0x66,
+	0xaf, 0xf1, 0x3b, 0x58, 0xe3, 0x8d, 0x58, 0x83, 0x93, 0x72, 0x7e, 0x66,
+	0xe3, 0x0a, 0x1b, 0x36, 0x69, 0x63, 0x82, 0x33, 0x56, 0xf7, 0xd6, 0x97,
+	0x11, 0xb5, 0xeb, 0x9f, 0xb0, 0x67, 0xcb, 0xc2, 0x1c, 0xa1, 0xa4, 0x5e,
+	0x9f, 0xd1, 0xca, 0x71, 0x8c, 0x37, 0x28, 0xe9, 0x19, 0xce, 0x73, 0xf9,
+	0x9b, 0x11, 0x90, 0x87, 0x27, 0xa0, 0x57, 0x57, 0xd0, 0x25, 0xe8, 0x96,
+	0x73, 0x73, 0x40, 0xbb, 0x8f, 0xca, 0x6c, 0x89, 0xf0, 0xf5, 0x24, 0x22,
+	0xfa, 0xac, 0x19, 0x9e, 0x67, 0x4c, 0x8e, 0xfb, 0x70, 0x25, 0x3c, 0x67,
+	0xb6, 0x89, 0x67, 0x07, 0x57, 0x9d, 0x35, 0xb3, 0xfa, 0x59, 0xdb, 0x0e,
+	0x3c, 0x73, 0x16, 0xce, 0xa1, 0x1e, 0x3d, 0x05, 0x32, 0xa9, 0xf3, 0xce,
+	0x36, 0xcb, 0x63, 0x0f, 0x2e, 0xe7, 0xbc, 0xb6, 0xc1, 0x46, 0xe9, 0x84,
+	0x89, 0x3c, 0x1a, 0x1d, 0xea, 0x81, 0x8f, 0xc7, 0x3c, 0x99, 0x9e, 0xc4,
+	0x6d, 0x3a, 0x17, 0xb9, 0x7a, 0xee, 0xaf, 0x9a, 0x8f, 0x1c, 0x9e, 0xb3,
+	0x4a, 0xe8, 0xef, 0x5a, 0xec, 0xd4, 0xe5, 0x71, 0xcc, 0x87, 0xfb, 0x7e,
+	0x1a, 0x0f, 0x09, 0x7e, 0xa7, 0xeb, 0x29, 0xe0, 0x60, 0xb2, 0xf2, 0x6d,
+	0xd0, 0xbb, 0x63, 0xcf, 0x9c, 0x91, 0xc6, 0x06, 0x64, 0xa2, 0x9c, 0x70,
+	0x26, 0xca, 0x03, 0xce, 0xbe, 0xb2, 0x7d, 0x37, 0xb0, 0x67, 0xb3, 0x34,
+	0xe3, 0xf7, 0x4c, 0x97, 0x33, 0x06, 0x7c, 0xe5, 0x8b, 0xdd, 0x4e, 0x5a,
+	0xdf, 0x3d, 0x7b, 0x87, 0x1c, 0xc0, 0x5a, 0x0d, 0xcf, 0xc4, 0xb5, 0x9c,
+	0xaf, 0x7e, 0x5b, 0x2a, 0x5c, 0x57, 0x7e, 0x13, 0x89, 0x7c, 0x7c, 0x5c,
+	0x7f, 0xe7, 0xc8, 0xd8, 0x0e, 0x27, 0xd1, 0xdf, 0x71, 0x1b, 0x13, 0xef,
+	0x73, 0xb2, 0xba, 0x1f, 0xb3, 0x1e, 0xf9, 0xe2, 0x09, 0xdc, 0x57, 0x9f,
+	0x79, 0x0e, 0xf5, 0x8c, 0x85, 0xbb, 0x10, 0xdc, 0x63, 0xe4, 0xd5, 0x71,
+	0x99, 0xaa, 0x30, 0x7f, 0xc4, 0xd1, 0x7c, 0x34, 0x59, 0x3e, 0x00, 0x9d,
+	0xb4, 0xf2, 0xcc, 0xdf, 0xce, 0xea, 0x3a, 0x24, 0x67, 0x84, 0xb0, 0x70,
+	0x0d, 0x56, 0x9e, 0x87, 0xbf, 0xf8, 0xbf, 0x70, 0x5f, 0xd1, 0xc8, 0x50,
+	0x0b, 0x47, 0x9a, 0xf2, 0xce, 0xc8, 0x95, 0x69, 0x39, 0x08, 0x78, 0x0e,
+	0xe3, 0x52, 0xf7, 0xf3, 0x3b, 0x2c, 0xf3, 0x92, 0x9f, 0xbb, 0x4f, 0xd4,
+	0x43, 0xe7, 0x9d, 0xe8, 0x43, 0x07, 0x25, 0xf2, 0xd0, 0xa2, 0xd3, 0xf0,
+	0x50, 0xb7, 0xf6, 0xcb, 0x77, 0xfb, 0xdd, 0x89, 0x7d, 0x72, 0x52, 0xa2,
+	0xf7, 0x2b, 0x7d, 0xfe, 0x2b, 0xef, 0x32, 0xc6, 0x77, 0x52, 0x22, 0xf7,
+	0xc7, 0xec, 0xd9, 0x51, 0x13, 0xd7, 0x5b, 0xd2, 0x7c, 0xff, 0x9b, 0x71,
+	0xe2, 0x6c, 0x49, 0x8e, 0x6b, 0xde, 0x19, 0x86, 0x9e, 0xc8, 0x94, 0x92,
+	0xcb, 0x75, 0x4c, 0xbe, 0xe7, 0xf3, 0x9b, 0x0d, 0xbf, 0xb0, 0x4e, 0x8f,
+	0xc3, 0xef, 0x38, 0x18, 0x9d, 0x91, 0xb9, 0x2c, 0xcc, 0xfd, 0x34, 0x6b,
+	0xca, 0xf7, 0x67, 0xb1, 0x86, 0x3d, 0x58, 0x2f, 0x8e, 0xe7, 0xe8, 0xfd,
+	0x5c, 0x9e, 0x9d, 0x75, 0xa5, 0x2f, 0xd1, 0xb4, 0x6c, 0x07, 0xb1, 0xee,
+	0x7d, 0xd2, 0x04, 0xb8, 0xd5, 0x43, 0x79, 0x63, 0xd7, 0x09, 0xe9, 0x54,
+	0x20, 0xb9, 0x49, 0xb3, 0x3d, 0x83, 0xbb, 0xf5, 0x1a, 0xde, 0x6b, 0x69,
+	0x66, 0x9d, 0xb1, 0x1f, 0xf1, 0x6c, 0xe8, 0x22, 0x2f, 0xbb, 0xa6, 0x7f,
+	0x08, 0x3d, 0xcf, 0x7d, 0x17, 0x6d, 0x2f, 0xd6, 0xb1, 0x05, 0xc9, 0x4b,
+	0xcf, 0x58, 0xbf, 0x32, 0x08, 0xa6, 0x7d, 0x1f, 0x78, 0xac, 0xe7, 0x4b,
+	0x6e, 0x71, 0xe6, 0x4a, 0x5b, 0x9d, 0xd9, 0x52, 0x20, 0x13, 0x3e, 0xbf,
+	0xe3, 0xc1, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x86, 0x6e, 0xfd, 0xeb,
+	0xcd, 0x3c, 0x8f, 0x74, 0x93, 0xf7, 0xa2, 0x98, 0x7a, 0xc4, 0x31, 0x7d,
+	0xe4, 0xee, 0xe3, 0x59, 0xe1, 0xf7, 0x34, 0xfa, 0x12, 0x71, 0xfd, 0x5d,
+	0x8f, 0xcf, 0xa1, 0x1d, 0xc6, 0x28, 0x72, 0xdc, 0x67, 0x9d, 0x59, 0xc8,
+	0xb3, 0xb9, 0x69, 0x9e, 0xe1, 0x67, 0x3e, 0x6d, 0xa4, 0x53, 0xc9, 0x15,
+	0xee, 0xa4, 0xfd, 0x06, 0x5c, 0x0e, 0x2e, 0x50, 0x44, 0x97, 0xf5, 0xb9,
+	0xe3, 0xcb, 0xdf, 0x85, 0x0b, 0xcb, 0xc2, 0xef, 0xc3, 0x29, 0x9d, 0x3b,
+	0x0d, 0x5f, 0xf6, 0xb1, 0x31, 0xf9, 0x89, 0x33, 0x5f, 0x78, 0xc5, 0x79,
+	0xb4, 0x90, 0xbe, 0xea, 0x12, 0xd0, 0xc7, 0x39, 0xbf, 0x97, 0xf2, 0x0b,
+	0x36, 0x5f, 0x41, 0x72, 0x95, 0x09, 0x99, 0xe9, 0xe8, 0x76, 0xef, 0xd7,
+	0x6b, 0x33, 0x03, 0x9c, 0x7d, 0x1b, 0xeb, 0xf7, 0xc9, 0x38, 0xf5, 0xdb,
+	0x78, 0x41, 0x81, 0x97, 0xd5, 0xcf, 0xe3, 0x82, 0x6d, 0xdb, 0xa8, 0x6d,
+	0x94, 0x7d, 0x3e, 0xeb, 0x6d, 0x75, 0x86, 0x4b, 0x5b, 0xb0, 0x8e, 0x7b,
+	0xa1, 0x3f, 0x1d, 0xd8, 0x69, 0xa0, 0x6d, 0x94, 0x4d, 0x02, 0x07, 0xe3,
+	0xbe, 0x91, 0xe7, 0xc3, 0x92, 0xd3, 0x3e, 0x9e, 0xb9, 0xa7, 0x95, 0x89,
+	0x99, 0x05, 0xc1, 0x1c, 0xec, 0x83, 0x6c, 0x7f, 0x09, 0xbc, 0xf0, 0x08,
+	0xae, 0xb7, 0xdb, 0x3d, 0xed, 0x17, 0x2e, 0xb2, 0xa7, 0xed, 0xca, 0xc9,
+	0x8a, 0x3e, 0xd7, 0xae, 0xf3, 0xab, 0x92, 0xea, 0xbf, 0x5f, 0xa2, 0xd7,
+	0x4a, 0xf5, 0xe8, 0x9c, 0xb4, 0xb4, 0x7c, 0x38, 0x6e, 0xf4, 0x30, 0x61,
+	0x4a, 0x02, 0x9e, 0xad, 0xc0, 0x05, 0xe1, 0x31, 0x6d, 0x44, 0x6d, 0xba,
+	0x94, 0xfa, 0x70, 0x49, 0x3e, 0x12, 0x0f, 0xcf, 0x14, 0xa0, 0x1f, 0xc8,
+	0xb8, 0x8f, 0x5d, 0x6a, 0xf4, 0xe4, 0xe6, 0x3a, 0xfd, 0x84, 0x73, 0x73,
+	0xec, 0xdc, 0x48, 0xb7, 0x7f, 0x96, 0xa0, 0x4f, 0xb1, 0x24, 0x4d, 0xab,
+	0xea, 0x33, 0xa6, 0xbf, 0xe1, 0x72, 0x73, 0x46, 0x81, 0x75, 0x5d, 0xd8,
+	0xa6, 0xb4, 0x73, 0x89, 0x47, 0xbd, 0x6e, 0x05, 0x25, 0x3c, 0x67, 0x00,
+	0x6e, 0xae, 0x5c, 0xe1, 0xbe, 0x43, 0x91, 0x0e, 0x43, 0x5c, 0x7f, 0x5b,
+	0xf3, 0xc9, 0x78, 0x81, 0xb1, 0x95, 0x47, 0x83, 0xf4, 0x28, 0x79, 0x8c,
+	0x7d, 0xf0, 0x7d, 0x41, 0xc7, 0x73, 0xf7, 0xfa, 0x8c, 0x15, 0x75, 0x1f,
+	0xbf, 0x43, 0x85, 0x72, 0x0a, 0xfa, 0xb7, 0xb8, 0xe8, 0xf0, 0x1b, 0x78,
+	0x37, 0x0a, 0xee, 0xf3, 0x8b, 0xce, 0x77, 0xa7, 0x9f, 0xc5, 0x73, 0x83,
+	0xfd, 0xee, 0x9d, 0xd1, 0x53, 0x22, 0xc5, 0x70, 0xbe, 0x89, 0x1c, 0xd6,
+	0xfe, 0x02, 0xd6, 0xbe, 0xfe, 0x77, 0xee, 0xf0, 0xae, 0x8c, 0x77, 0xe5,
+	0x0f, 0x07, 0xe9, 0x36, 0xd2, 0x22, 0xe9, 0xef, 0xb5, 0xfc, 0xe6, 0x41,
+	0xcd, 0x17, 0x93, 0xc5, 0xc7, 0xc1, 0x17, 0x69, 0xee, 0x37, 0x07, 0x0f,
+	0xfb, 0x37, 0x80, 0x2f, 0xf6, 0xc8, 0xef, 0xc3, 0x2e, 0xf8, 0xdd, 0xca,
+	0x10, 0xf8, 0x63, 0x10, 0xfc, 0x32, 0x00, 0x1e, 0xf1, 0xb5, 0x8d, 0xfc,
+	0x04, 0xf4, 0x1f, 0xf4, 0x9a, 0xb3, 0xaf, 0xd4, 0xe5, 0x64, 0x4b, 0x9e,
+	0x33, 0x51, 0xe2, 0xf7, 0x5a, 0xd4, 0x5b, 0x1b, 0x24, 0x9a, 0x98, 0x13,
+	0xf2, 0x42, 0x37, 0x73, 0x1c, 0xdb, 0x81, 0xab, 0x53, 0xc4, 0xd5, 0x5c,
+	0xa5, 0xcf, 0xbd, 0x04, 0x3c, 0xd1, 0xae, 0x79, 0xa2, 0xd5, 0x49, 0xbb,
+	0x37, 0x58, 0x9e, 0x78, 0x11, 0x3c, 0x71, 0x7e, 0x0d, 0x4f, 0x3c, 0x6d,
+	0xe9, 0x7f, 0xa1, 0x86, 0x27, 0xe6, 0x6c, 0xd9, 0xcc, 0x45, 0x78, 0xe2,
+	0x52, 0x2f, 0xf5, 0xa5, 0x31, 0x79, 0x15, 0x3c, 0x21, 0x8a, 0x3c, 0x71,
+	0xa9, 0xe6, 0x09, 0xc6, 0x8e, 0xc8, 0x17, 0x9d, 0x90, 0x23, 0xe4, 0x8b,
+	0xb3, 0xb2, 0x04, 0xbe, 0x78, 0x5e, 0x71, 0xec, 0x19, 0xda, 0x0a, 0x25,
+	0xfa, 0x64, 0x27, 0x8a, 0x5d, 0xe0, 0x77, 0x25, 0xff, 0x65, 0x3a, 0x08,
+	0x16, 0xe1, 0xa7, 0x3f, 0x08, 0x7b, 0x3e, 0xaa, 0xbf, 0xa9, 0xb8, 0x00,
+	0xba, 0x0f, 0xe9, 0x7d, 0xc2, 0x01, 0xbd, 0x1f, 0x9e, 0xc5, 0x1c, 0x26,
+	0xd4, 0x7f, 0x86, 0x2f, 0xec, 0x62, 0x5d, 0x69, 0xe7, 0x1f, 0xd3, 0x3c,
+	0xd4, 0x00, 0x7d, 0xf0, 0xe8, 0x00, 0x63, 0x4d, 0x9e, 0xbb, 0x4f, 0x75,
+	0xe7, 0x46, 0x00, 0x73, 0x44, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xad, 0xb2,
+	0xf3, 0x29, 0x23, 0x46, 0x21, 0xeb, 0xcc, 0xbb, 0x5c, 0xd0, 0x04, 0x9b,
+	0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x48, 0xb9, 0x1f, 0x84, 0x00, 0x6d,
+	0x84, 0xbd, 0xb0, 0x0b, 0xab, 0x3d, 0x52, 0xa8, 0xb5, 0xf1, 0xff, 0x03,
+	0x6c, 0x7c, 0xb6, 0x91, 0xa8, 0xb1, 0xf1, 0x7f, 0xcd, 0xf2, 0x1a, 0x7f,
+	0xbb, 0xda, 0xde, 0x3f, 0x00, 0xf8, 0x76, 0x2f, 0xdb, 0xfb, 0xec, 0x83,
+	0x76, 0x87, 0xc8, 0xf5, 0xb0, 0xf9, 0xde, 0x0d, 0x1e, 0xbc, 0x01, 0xbe,
+	0xd4, 0x7b, 0x0a, 0xae, 0xec, 0x29, 0xb4, 0xc3, 0xe7, 0xee, 0x94, 0xf7,
+	0x4e, 0x6f, 0x95, 0x9d, 0x25, 0xff, 0x12, 0x69, 0xee, 0x80, 0x8d, 0x5a,
+	0x00, 0x9c, 0x11, 0x2b, 0xb7, 0xcf, 0x02, 0x6f, 0xdd, 0xc9, 0x9f, 0xa8,
+	0x17, 0xad, 0x5d, 0xc4, 0xb3, 0x8e, 0xf5, 0xfa, 0x89, 0xa3, 0x3d, 0x63,
+	0x29, 0x1d, 0x72, 0xea, 0x18, 0xbd, 0xaf, 0x24, 0xec, 0x72, 0x1f, 0x36,
+	0xc9, 0x16, 0xf4, 0xc7, 0x78, 0xf2, 0x46, 0x79, 0xfa, 0xaa, 0xe8, 0x5d,
+	0x59, 0xcd, 0x87, 0x9d, 0x4e, 0x66, 0x1a, 0x3e, 0xc0, 0xde, 0x18, 0xe6,
+	0xa0, 0xda, 0x37, 0xcb, 0x75, 0xb2, 0x53, 0xcf, 0x67, 0x46, 0x0e, 0x42,
+	0x37, 0xff, 0x41, 0x61, 0xa7, 0x2c, 0x8d, 0xb6, 0xe1, 0x39, 0x26, 0x4f,
+	0x17, 0xfa, 0xe0, 0xfb, 0xbc, 0x0b, 0x38, 0x6a, 0xc4, 0x73, 0xa3, 0x0c,
+	0x5f, 0x42, 0x5e, 0x6d, 0x91, 0x45, 0x94, 0xbf, 0x5b, 0x7e, 0xc1, 0x96,
+	0xb3, 0x8c, 0xbc, 0xd1, 0x82, 0xb6, 0x31, 0x39, 0x57, 0xa0, 0x5d, 0xa9,
+	0x79, 0x62, 0xf0, 0x7b, 0xd2, 0x97, 0xfe, 0x1e, 0xec, 0xd4, 0xb3, 0xb8,
+	0x9e, 0x91, 0xd4, 0x9e, 0x71, 0xa7, 0x2f, 0xd9, 0xed, 0x40, 0x77, 0xe2,
+	0x8a, 0x3a, 0x7d, 0x6e, 0xa3, 0x73, 0x85, 0xed, 0xa3, 0x41, 0x9e, 0xd9,
+	0xab, 0x12, 0x2d, 0x58, 0x93, 0xed, 0x4e, 0x8f, 0x2d, 0xe3, 0x73, 0xca,
+	0x78, 0x40, 0xa7, 0xd4, 0x96, 0x0d, 0x22, 0x5d, 0x2d, 0xb0, 0x79, 0x26,
+	0x44, 0xb5, 0xb7, 0x48, 0x54, 0xba, 0x67, 0x55, 0x27, 0xca, 0x3c, 0x5b,
+	0x16, 0x6f, 0x81, 0x7e, 0x40, 0x59, 0x07, 0xca, 0xb6, 0xd9, 0xb2, 0xb6,
+	0x16, 0x69, 0x44, 0xd9, 0x8c, 0xe6, 0xf9, 0xf3, 0x3d, 0x9e, 0x9b, 0x75,
+	0x9a, 0xa5, 0xeb, 0x44, 0x0b, 0x64, 0xc3, 0x46, 0x59, 0xbc, 0xaa, 0x49,
+	0xba, 0xf0, 0x8e, 0x71, 0x6e, 0xff, 0x44, 0x4c, 0xae, 0x3d, 0xd1, 0x9d,
+	0xf8, 0x38, 0xe6, 0xd0, 0x7d, 0x8a, 0x71, 0xef, 0xfc, 0x25, 0x8c, 0xfb,
+	0x74, 0x9d, 0xe2, 0xbd, 0x49, 0xcb, 0x1f, 0xe2, 0xc3, 0x7c, 0x93, 0x88,
+	0x32, 0xf9, 0x24, 0xfc, 0x5c, 0xea, 0xf0, 0x6e, 0xfb, 0xfd, 0x8c, 0xe3,
+	0x97, 0xd0, 0x6f, 0x9b, 0xa5, 0x5d, 0x52, 0x24, 0x3f, 0x52, 0x0f, 0xe1,
+	0x3e, 0xe3, 0x48, 0xbe, 0x2a, 0xb3, 0xe6, 0xc9, 0x57, 0xc7, 0x14, 0x73,
+	0x59, 0x50, 0x56, 0xf9, 0xc5, 0xc0, 0xac, 0x31, 0x79, 0xc1, 0xc8, 0xa5,
+	0x0f, 0x18, 0xb9, 0xf4, 0xd8, 0x99, 0x15, 0x72, 0xe9, 0xbc, 0x96, 0x4b,
+	0x7b, 0x05, 0xf7, 0xf9, 0xf3, 0x90, 0x4b, 0x2f, 0xe2, 0xd9, 0xd5, 0x72,
+	0x29, 0x2e, 0xd6, 0x5e, 0x96, 0xaf, 0xea, 0xf1, 0xe7, 0x8a, 0x51, 0x6d,
+	0x57, 0xe5, 0x67, 0x60, 0x93, 0x14, 0xa7, 0xac, 0xfe, 0x96, 0xa1, 0x36,
+	0xe9, 0x19, 0xfc, 0xa9, 0x84, 0x36, 0xe7, 0x7f, 0xba, 0x84, 0xdf, 0xee,
+	0x7c, 0x5e, 0x51, 0x86, 0xbd, 0x0a, 0x19, 0x26, 0xaa, 0xbe, 0x0c, 0xc3,
+	0xbb, 0x32, 0xde, 0x95, 0xd9, 0xef, 0x8f, 0x7e, 0x3a, 0xe6, 0x52, 0x7e,
+	0x50, 0x66, 0x40, 0x26, 0x15, 0x21, 0x93, 0x8a, 0x90, 0x53, 0x45, 0xc8,
+	0x25, 0xd8, 0x6c, 0x67, 0x8a, 0x90, 0x4b, 0x45, 0xc8, 0x25, 0xc8, 0xb8,
+	0x27, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x85, 0x4c, 0x9b, 0x91, 0xfb, 0xac,
+	0xae, 0x37, 0xb1, 0x92, 0x7e, 0xeb, 0x23, 0x0d, 0xe8, 0x18, 0xf2, 0x99,
+	0x9a, 0xd8, 0xe0, 0x8d, 0x47, 0x34, 0xbf, 0xbb, 0x9e, 0xba, 0xc2, 0x61,
+	0x0e, 0xcd, 0x4f, 0xb4, 0xff, 0xbe, 0x9d, 0xbf, 0xa5, 0x09, 0x7c, 0xfd,
+	0x03, 0xcb, 0xd7, 0xdb, 0x97, 0xf9, 0x3a, 0xe5, 0x30, 0x56, 0x5c, 0x9f,
+	0xaf, 0x3b, 0xec, 0xbb, 0x5c, 0xb0, 0x0e, 0x7c, 0xbd, 0x6e, 0x15, 0x5f,
+	0xc7, 0xc0, 0xd7, 0x7b, 0xd6, 0xf0, 0xf5, 0x06, 0x67, 0x58, 0xb7, 0xe1,
+	0x19, 0x09, 0x3e, 0x37, 0x3a, 0x55, 0xbe, 0xbe, 0x47, 0xf3, 0xf5, 0x21,
+	0xf0, 0xf5, 0x75, 0x35, 0x7c, 0xbd, 0x47, 0x52, 0x37, 0x67, 0x22, 0x5b,
+	0x65, 0xfc, 0x7e, 0xd5, 0xbe, 0x49, 0xfe, 0x49, 0x4c, 0x7b, 0xc3, 0x63,
+	0xc3, 0xd3, 0xed, 0x92, 0x7d, 0xe8, 0x15, 0x94, 0x91, 0xcf, 0x52, 0x63,
+	0x69, 0xc7, 0x95, 0x83, 0x47, 0x7e, 0x22, 0x0b, 0x9a, 0xb7, 0x44, 0x26,
+	0x8e, 0xc4, 0x64, 0xf2, 0x08, 0xe3, 0x10, 0x7f, 0x63, 0xe9, 0xbd, 0x49,
+	0x26, 0xf7, 0x32, 0x6f, 0x2e, 0x2a, 0xe3, 0x47, 0xe0, 0x6f, 0x1d, 0x61,
+	0x1c, 0xe2, 0xa5, 0x65, 0x1e, 0x5b, 0x80, 0x6c, 0x19, 0x3f, 0xc2, 0xb5,
+	0x8e, 0xa1, 0x9f, 0x16, 0x39, 0x74, 0x44, 0xe4, 0xb6, 0x23, 0x51, 0xf9,
+	0xe8, 0x91, 0x65, 0x5e, 0x1b, 0x0d, 0x79, 0xed, 0x59, 0xf0, 0x5a, 0xb7,
+	0xe5, 0x35, 0xb5, 0xcc, 0x6b, 0x7f, 0x5a, 0xc3, 0x6b, 0x6c, 0x4f, 0x5e,
+	0x7b, 0xce, 0x96, 0xf1, 0x39, 0x2a, 0xfb, 0x8e, 0x74, 0xca, 0xf8, 0x43,
+	0x6f, 0x91, 0x89, 0xfb, 0x09, 0xab, 0xf9, 0x8e, 0x13, 0x6d, 0xb1, 0x99,
+	0x4a, 0x37, 0xfa, 0x0f, 0x73, 0x88, 0xf4, 0xf7, 0x10, 0x7a, 0x67, 0x25,
+	0x95, 0xe3, 0x78, 0x8d, 0xf0, 0xa3, 0x4f, 0xc0, 0xbf, 0xd8, 0x07, 0x98,
+	0x6e, 0x39, 0x22, 0xa9, 0xa8, 0xbc, 0x2c, 0x53, 0xfe, 0x27, 0x2e, 0x37,
+	0xf6, 0x04, 0x6c, 0x11, 0x6d, 0xfb, 0xa4, 0x25, 0xfb, 0xce, 0x40, 0xfb,
+	0x18, 0xa5, 0xb2, 0x30, 0x16, 0xc0, 0xb8, 0xb9, 0x63, 0xbe, 0xc7, 0xc4,
+	0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0x07, 0xf8, 0x9e, 0xcf,
+	0xb0, 0x67, 0xf4, 0x59, 0x43, 0xb6, 0x7f, 0x44, 0x7f, 0x1b, 0x91, 0x31,
+	0xf5, 0x7c, 0x99, 0xdf, 0xb0, 0x81, 0xff, 0x59, 0xe6, 0xb7, 0xb0, 0xf6,
+	0xb7, 0x9b, 0xf8, 0x2c, 0xf9, 0xee, 0x87, 0x0e, 0xbf, 0x5d, 0x35, 0xa5,
+	0x73, 0xbd, 0xf0, 0xbb, 0xcc, 0x67, 0xd6, 0x7f, 0x84, 0xf1, 0x8e, 0x64,
+	0x52, 0xbd, 0xf7, 0x72, 0xe6, 0x1e, 0xec, 0x9d, 0x67, 0xdd, 0xad, 0x96,
+	0x47, 0xb7, 0x6a, 0xbf, 0x83, 0x36, 0xd6, 0x78, 0xe9, 0x45, 0xc9, 0xd3,
+	0x36, 0x19, 0xdd, 0xea, 0xe4, 0x66, 0x92, 0x97, 0x1b, 0xfb, 0x79, 0xdd,
+	0xa5, 0xcc, 0x3b, 0x4c, 0xab, 0xb5, 0x32, 0xf9, 0x84, 0x84, 0x32, 0x39,
+	0x75, 0x33, 0xbf, 0xb7, 0x9b, 0x3d, 0xa2, 0xbf, 0x2f, 0x95, 0xec, 0x56,
+	0x9c, 0xd3, 0xa7, 0x21, 0x5f, 0x43, 0x5a, 0x48, 0xc8, 0x27, 0x8f, 0x90,
+	0x1e, 0x54, 0xbc, 0x55, 0x3e, 0x61, 0xe9, 0x61, 0x46, 0x0a, 0x90, 0x3b,
+	0x47, 0x8e, 0x7c, 0x54, 0x66, 0x6e, 0x5c, 0x4d, 0x0f, 0x13, 0x55, 0x7a,
+	0x88, 0xc3, 0x3e, 0x73, 0x6a, 0xe9, 0xe1, 0x97, 0x97, 0xe9, 0x61, 0xc6,
+	0xf9, 0xe7, 0xd2, 0xc3, 0xf5, 0x2b, 0xe8, 0x61, 0x4a, 0xd3, 0xc3, 0xce,
+	0x65, 0x7a, 0x98, 0x3a, 0xc2, 0x71, 0xf5, 0xde, 0xa8, 0xbb, 0xe8, 0x70,
+	0xcd, 0x97, 0x69, 0x21, 0x39, 0xa9, 0xf3, 0xf5, 0x53, 0x39, 0x9e, 0x6f,
+	0xda, 0xa0, 0x18, 0x27, 0xa9, 0xae, 0x7f, 0xeb, 0xbf, 0xe8, 0xfa, 0xbf,
+	0xfc, 0xff, 0x79, 0xfd, 0xd5, 0xa5, 0xcc, 0xdd, 0xe7, 0x99, 0x55, 0x23,
+	0x8f, 0x43, 0x7a, 0x88, 0x5d, 0x6a, 0xf4, 0x02, 0xd7, 0x98, 0xcf, 0x90,
+	0x67, 0x90, 0x7f, 0x67, 0x20, 0xff, 0x9e, 0x84, 0xfc, 0x3b, 0xbd, 0x62,
+	0x4f, 0x60, 0xd0, 0xc6, 0x23, 0x02, 0x39, 0xe8, 0x57, 0xf1, 0xb1, 0x38,
+	0x40, 0x7c, 0x98, 0xfc, 0x13, 0xe6, 0xfe, 0xae, 0xc4, 0x49, 0x54, 0xe7,
+	0x1c, 0x3d, 0xea, 0xd7, 0xe2, 0x84, 0x70, 0xbf, 0x5c, 0x33, 0x47, 0xfc,
+	0x2e, 0xf3, 0x79, 0x46, 0xe7, 0x91, 0xe4, 0xf5, 0x1e, 0x14, 0xf1, 0xc2,
+	0x3d, 0x28, 0xe2, 0x24, 0xaa, 0xed, 0xfd, 0x7c, 0xb9, 0x49, 0xe7, 0xd0,
+	0x1f, 0x98, 0x8f, 0xcb, 0x62, 0x9c, 0x31, 0x3e, 0x7e, 0x97, 0x90, 0x7e,
+	0xb3, 0x97, 0xc8, 0x4b, 0x8e, 0xb9, 0x72, 0xe0, 0xe9, 0x0d, 0x96, 0xb6,
+	0x19, 0x1b, 0xe4, 0x99, 0xdd, 0x70, 0x2f, 0xa2, 0xd7, 0xca, 0xba, 0x96,
+	0x9a, 0x98, 0x25, 0xf0, 0x3e, 0x2d, 0xc9, 0xcc, 0x00, 0xee, 0xf3, 0x1c,
+	0x7b, 0xbf, 0x4c, 0x3d, 0x38, 0x01, 0x5b, 0x6e, 0x2f, 0x74, 0x0e, 0xcf,
+	0x9f, 0x99, 0xef, 0x70, 0x13, 0x86, 0x59, 0xfd, 0xdd, 0x29, 0xfa, 0x80,
+	0xa4, 0x87, 0x04, 0x9e, 0x67, 0x6c, 0x5c, 0x29, 0x21, 0xf9, 0xc2, 0x05,
+	0xf3, 0x6d, 0xcb, 0xc2, 0x4b, 0xb8, 0xbf, 0xde, 0x7a, 0x18, 0x3f, 0x64,
+	0xd4, 0xdc, 0xd1, 0xd7, 0x92, 0xa4, 0xcb, 0x26, 0xc7, 0xa5, 0x1a, 0x37,
+	0x99, 0x91, 0xc3, 0xda, 0x7e, 0x1e, 0xb2, 0xb9, 0x2d, 0xa9, 0xd1, 0x9c,
+	0x18, 0x1b, 0xfa, 0x77, 0x60, 0x43, 0x7f, 0xb1, 0x92, 0xd6, 0xfb, 0x58,
+	0xa7, 0x61, 0x43, 0x3f, 0x01, 0xdd, 0x43, 0x9d, 0x13, 0xb7, 0x3a, 0x67,
+	0x4a, 0xdd, 0xa8, 0x75, 0xce, 0x37, 0xb5, 0xce, 0x79, 0xef, 0x1a, 0x9d,
+	0x73, 0x48, 0x75, 0x97, 0xa8, 0x73, 0x86, 0xd5, 0x1e, 0x87, 0xf6, 0xe2,
+	0xe6, 0x3a, 0x3a, 0xe7, 0x7d, 0xf2, 0x2e, 0xfb, 0xee, 0x1e, 0x79, 0xff,
+	0x0e, 0xbd, 0x77, 0xe3, 0xce, 0x2a, 0x7e, 0x6b, 0xc9, 0xe8, 0xa0, 0xeb,
+	0x54, 0xaf, 0xde, 0xf3, 0xfd, 0x46, 0x8d, 0xce, 0xe9, 0x52, 0x03, 0xce,
+	0xb0, 0x6e, 0xc3, 0xd8, 0x04, 0x9f, 0x7d, 0x27, 0x3d, 0xda, 0x84, 0xe7,
+	0x84, 0x44, 0x8e, 0x60, 0xee, 0xe6, 0x7b, 0x50, 0xca, 0xbc, 0x7b, 0xab,
+	0x7d, 0xa7, 0xc2, 0xf2, 0xa8, 0x29, 0xef, 0xb6, 0xe5, 0x46, 0x57, 0x75,
+	0xa9, 0x4e, 0xad, 0xab, 0xb6, 0x83, 0xa1, 0x66, 0xa1, 0x5f, 0x67, 0x8b,
+	0xa1, 0xce, 0xe2, 0x6f, 0xc6, 0x9e, 0x19, 0xa3, 0x08, 0x63, 0xd8, 0x49,
+	0xd4, 0xc1, 0x55, 0x0c, 0x6d, 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x1e,
+	0x78, 0xbd, 0x19, 0xfc, 0xf3, 0x6f, 0x0a, 0x8c, 0x81, 0xb6, 0xcb, 0xd1,
+	0xe9, 0xda, 0x77, 0x9d, 0xf2, 0x9e, 0xe9, 0x2d, 0xb2, 0xbf, 0xf4, 0x2d,
+	0xf0, 0xc1, 0x56, 0x99, 0x2a, 0x15, 0xf4, 0x79, 0xf5, 0x4d, 0xfa, 0x3b,
+	0x1e, 0xfc, 0xbe, 0x8d, 0x91, 0x91, 0x3b, 0x1d, 0x23, 0x23, 0xd3, 0xaa,
+	0x6a, 0xb3, 0x86, 0x7d, 0xf2, 0xdb, 0x21, 0x23, 0xa5, 0x84, 0xfe, 0xc6,
+	0xe9, 0x6c, 0xe5, 0x0a, 0xf9, 0xc2, 0x31, 0x75, 0xa7, 0xaa, 0x9e, 0xef,
+	0xd5, 0x36, 0xeb, 0xdc, 0x0a, 0x9b, 0xf5, 0xaf, 0x64, 0xf1, 0xfd, 0x31,
+	0xcc, 0x13, 0x34, 0x7c, 0xe5, 0xf7, 0xb8, 0x17, 0xda, 0x1e, 0x97, 0x0b,
+	0x32, 0xa2, 0xf1, 0x47, 0x79, 0xda, 0x02, 0x39, 0xb8, 0xa4, 0xf5, 0xeb,
+	0x66, 0xd0, 0x20, 0x65, 0xe9, 0xc7, 0xe4, 0x45, 0x2d, 0xcf, 0x36, 0x5b,
+	0xdb, 0x75, 0x81, 0xb1, 0xd4, 0x23, 0xb4, 0x5d, 0xbf, 0x69, 0xcb, 0x59,
+	0x96, 0x4a, 0x2c, 0x09, 0xf5, 0x5d, 0x1c, 0x32, 0x94, 0xf2, 0xf4, 0x8d,
+	0xda, 0xae, 0x5f, 0xb3, 0x7d, 0x50, 0x7e, 0x1a, 0xd9, 0xbd, 0xdd, 0x59,
+	0xb0, 0x65, 0x7c, 0x0e, 0xe3, 0xe9, 0x5e, 0x3a, 0x6b, 0xf9, 0x4c, 0x39,
+	0x5f, 0xc2, 0xfb, 0x4d, 0x78, 0x4f, 0x3e, 0x3b, 0xad, 0xf9, 0x4c, 0xdb,
+	0x27, 0x4e, 0xbf, 0xdd, 0x5f, 0x58, 0xde, 0x1b, 0xc8, 0x91, 0xcf, 0xd4,
+	0x51, 0x77, 0xc1, 0xc8, 0x03, 0xe6, 0xa9, 0x7e, 0x1e, 0xba, 0x83, 0x6d,
+	0x51, 0xfe, 0x70, 0x9a, 0xbe, 0x2d, 0xfc, 0x9f, 0x56, 0x3c, 0xb7, 0xe3,
+	0x79, 0x56, 0xde, 0xbb, 0x37, 0xa6, 0xe7, 0x3d, 0x85, 0x79, 0x1c, 0x38,
+	0x82, 0x39, 0x39, 0xc6, 0x76, 0x8e, 0x9e, 0x8a, 0x4a, 0xc3, 0x29, 0xf2,
+	0x1d, 0xcf, 0xda, 0x04, 0xc1, 0xbe, 0x7e, 0xd2, 0x6d, 0xca, 0xdd, 0xa9,
+	0xcf, 0x96, 0x6e, 0x4f, 0x44, 0x80, 0x93, 0x03, 0x58, 0x8f, 0xa9, 0x82,
+	0xe7, 0x66, 0x1c, 0x2f, 0x81, 0x79, 0xc2, 0x06, 0xec, 0x86, 0x2d, 0xd8,
+	0x0d, 0x3b, 0xb0, 0x1b, 0x76, 0xe0, 0x46, 0x39, 0x71, 0x15, 0x73, 0x4c,
+	0x72, 0xd7, 0xc2, 0x2b, 0x97, 0xef, 0xe8, 0x38, 0x7d, 0xe3, 0xcd, 0x23,
+	0xf0, 0xd9, 0xc5, 0x4d, 0x8d, 0x32, 0x0f, 0x7f, 0xc9, 0x6d, 0xbc, 0x79,
+	0xa7, 0x74, 0x0f, 0xe2, 0xfd, 0xe0, 0x05, 0xe9, 0xb9, 0xf9, 0x56, 0xa7,
+	0x71, 0x74, 0x04, 0x78, 0x4c, 0x3b, 0xa9, 0xc4, 0x98, 0xb3, 0x80, 0x71,
+	0x32, 0xdb, 0x23, 0xc2, 0xb8, 0xe5, 0x02, 0x63, 0x11, 0x37, 0x77, 0x47,
+	0xfa, 0x92, 0xe3, 0x4e, 0x6a, 0x54, 0x45, 0x52, 0xa3, 0x23, 0x4e, 0x58,
+	0x8f, 0xdf, 0x48, 0x85, 0x9c, 0x01, 0xac, 0x07, 0x8a, 0xd3, 0xa0, 0xa7,
+	0xff, 0x28, 0xf9, 0x63, 0x2d, 0x32, 0x5f, 0xe8, 0x76, 0x33, 0x2a, 0xae,
+	0x73, 0x4b, 0xd4, 0x09, 0x10, 0xfd, 0xa9, 0x98, 0xcc, 0x96, 0xb6, 0x8a,
+	0xd2, 0xb6, 0x7b, 0x87, 0x64, 0xa6, 0x4b, 0x72, 0x6e, 0x40, 0xda, 0x14,
+	0xfa, 0xe7, 0xb7, 0x67, 0xd5, 0x09, 0xee, 0x25, 0x86, 0xbc, 0x70, 0x39,
+	0xf9, 0xa4, 0x04, 0x1c, 0x82, 0x6e, 0x19, 0xe3, 0x6d, 0x12, 0xca, 0xbd,
+	0x8f, 0xea, 0xf8, 0x29, 0x63, 0xb6, 0xb5, 0x7b, 0x0f, 0xe4, 0x8f, 0x58,
+	0x5d, 0xfe, 0x98, 0x2b, 0x72, 0x9f, 0x46, 0x72, 0x51, 0xc6, 0x88, 0x3d,
+	0xfc, 0x9e, 0x61, 0xdd, 0x26, 0x99, 0x1a, 0xc8, 0xd9, 0x3c, 0x8f, 0x47,
+	0x12, 0xcc, 0x21, 0x26, 0x4e, 0xc6, 0x07, 0xc8, 0xeb, 0xab, 0xf7, 0x36,
+	0x62, 0x35, 0xf2, 0xc0, 0x91, 0xc5, 0x52, 0xb8, 0x17, 0xc2, 0xfe, 0xf0,
+	0x3c, 0x63, 0xe4, 0x6d, 0x66, 0x4d, 0x3b, 0xc2, 0xc5, 0xfd, 0xca, 0x95,
+	0x32, 0x56, 0x79, 0x94, 0xa9, 0xae, 0x96, 0xaf, 0x8f, 0x55, 0x8c, 0x6c,
+	0x9d, 0xa9, 0x84, 0xba, 0x25, 0x66, 0x74, 0xe9, 0x1a, 0x7d, 0x62, 0xa2,
+	0x99, 0x55, 0x7d, 0x42, 0xbd, 0xa8, 0xe4, 0x03, 0xf3, 0x1d, 0x12, 0x7d,
+	0x58, 0x96, 0xa6, 0xbc, 0xec, 0xe5, 0xcc, 0xd5, 0x98, 0xf2, 0xdf, 0x8c,
+	0x7e, 0xfc, 0x6f, 0x09, 0xea, 0xc3, 0x31, 0xf5, 0x75, 0xdc, 0x37, 0x69,
+	0xfa, 0x03, 0x4f, 0xe1, 0xd9, 0xf8, 0x09, 0xbf, 0x03, 0x3f, 0xe1, 0x8b,
+	0xd0, 0x75, 0x67, 0xe0, 0x27, 0x3c, 0x09, 0x3f, 0xe1, 0x34, 0xfc, 0x84,
+	0x27, 0xa0, 0x27, 0x6b, 0xfd, 0x83, 0xc9, 0x15, 0xfe, 0x41, 0xa0, 0xf9,
+	0x9f, 0xf1, 0xc0, 0x27, 0x6b, 0x7c, 0x83, 0x7d, 0x46, 0x5f, 0xc1, 0xef,
+	0x37, 0x7c, 0xd4, 0xa5, 0x6e, 0xd2, 0xfa, 0xd1, 0xe4, 0xed, 0x8e, 0x2e,
+	0xeb, 0xab, 0x2e, 0x65, 0xf4, 0xd5, 0x6c, 0x55, 0x5f, 0x19, 0x3e, 0x7a,
+	0xb8, 0x24, 0x11, 0xaf, 0xb4, 0x90, 0xf1, 0x77, 0x69, 0x1e, 0x6a, 0xf3,
+	0xb6, 0x4a, 0xe4, 0x01, 0xd5, 0xde, 0x20, 0x19, 0xfb, 0x0c, 0xfa, 0x3a,
+	0x3a, 0x8d, 0xbe, 0xae, 0x95, 0xac, 0xb6, 0xcf, 0x2e, 0x8e, 0xef, 0x27,
+	0x56, 0xe1, 0x3b, 0x5f, 0xbc, 0x5b, 0xe3, 0xfc, 0xfe, 0x32, 0xf7, 0x59,
+	0x5a, 0x64, 0xb2, 0x1c, 0xe2, 0x9c, 0xe7, 0x59, 0x99, 0x8b, 0xd1, 0x29,
+	0x91, 0x87, 0x3b, 0x78, 0xce, 0x4a, 0x65, 0xfd, 0xf5, 0x3a, 0x87, 0xe5,
+	0xc4, 0x80, 0x24, 0xb2, 0x03, 0xa4, 0xd5, 0xfb, 0x64, 0x56, 0xaf, 0x45,
+	0x87, 0x34, 0x3c, 0x4c, 0x1b, 0x25, 0xdc, 0xcf, 0xeb, 0xba, 0xcc, 0x7e,
+	0x23, 0x35, 0x66, 0xea, 0x89, 0x1c, 0xd4, 0xeb, 0x75, 0x5c, 0xe7, 0x19,
+	0xde, 0x34, 0xcf, 0xb8, 0x3c, 0xbf, 0x47, 0xc5, 0x98, 0xfc, 0x3f, 0x67,
+	0xfd, 0x7e, 0xe1, 0x32, 0x63, 0xcf, 0x6c, 0xb2, 0x76, 0x8c, 0x89, 0x53,
+	0xd5, 0xb7, 0x61, 0xd8, 0x4f, 0xed, 0x37, 0x14, 0xb7, 0x38, 0x93, 0xa5,
+	0xad, 0x4e, 0xbe, 0xc4, 0xbd, 0x6c, 0xfb, 0xf7, 0x2e, 0xdc, 0x3d, 0xce,
+	0x01, 0x6f, 0x0b, 0xca, 0x18, 0xb3, 0x64, 0xcc, 0xe6, 0x97, 0x2e, 0x63,
+	0x8c, 0x36, 0xe3, 0x71, 0x6c, 0x96, 0x6d, 0x71, 0xa6, 0x4a, 0xdd, 0xf0,
+	0xcd, 0x79, 0xae, 0x8a, 0xef, 0x77, 0x72, 0xed, 0xa0, 0x83, 0x5d, 0x7d,
+	0x66, 0x77, 0x42, 0xae, 0xb0, 0x31, 0x68, 0xea, 0xe1, 0x9f, 0x5f, 0xb1,
+	0x77, 0x7b, 0x08, 0x7a, 0xec, 0x16, 0xc8, 0x23, 0xea, 0xe1, 0x43, 0x72,
+	0xb5, 0xa5, 0xe7, 0x95, 0x7a, 0xf8, 0xbc, 0x30, 0x4e, 0xdc, 0x8f, 0x77,
+	0xb9, 0x20, 0x06, 0x7a, 0x38, 0x5c, 0xe3, 0xab, 0xd1, 0xef, 0x6b, 0x1a,
+	0x32, 0xfb, 0x61, 0x2b, 0xfd, 0x3e, 0xc8, 0x81, 0x78, 0xe8, 0xe7, 0x35,
+	0x2e, 0xef, 0xd7, 0xee, 0xb1, 0x6d, 0xa7, 0xfc, 0xfb, 0x89, 0xa3, 0xe4,
+	0x21, 0xe9, 0x81, 0x2e, 0x63, 0x0e, 0xc8, 0x6f, 0x69, 0x9c, 0x89, 0x22,
+	0xed, 0x6d, 0xd2, 0x30, 0x5a, 0x39, 0x9f, 0x0c, 0x73, 0x38, 0xf2, 0xb6,
+	0xed, 0x84, 0xdd, 0x93, 0xcf, 0xcb, 0xdc, 0x65, 0xd4, 0x83, 0x23, 0x91,
+	0xf5, 0xfc, 0x7e, 0x22, 0xda, 0xf6, 0x18, 0xbd, 0x28, 0x61, 0x5f, 0x7c,
+	0x6e, 0xa8, 0xe9, 0x9b, 0x76, 0x14, 0xef, 0xab, 0xcf, 0x91, 0x3d, 0xa3,
+	0xf7, 0x19, 0xcd, 0xf7, 0x12, 0x42, 0x3e, 0x21, 0xef, 0x24, 0xf5, 0x59,
+	0x27, 0xef, 0x61, 0xda, 0x3d, 0xdc, 0x83, 0x75, 0x17, 0x26, 0xfd, 0x4f,
+	0xe8, 0x6f, 0xfc, 0xcd, 0x88, 0x38, 0x79, 0xff, 0x36, 0x9d, 0x7b, 0x92,
+	0xd7, 0xb1, 0xe6, 0x1c, 0xee, 0x55, 0x1f, 0xb5, 0xeb, 0x61, 0xfe, 0x4d,
+	0x0b, 0x96, 0x65, 0x01, 0x1b, 0x75, 0x08, 0x65, 0x6f, 0x5c, 0xba, 0x8e,
+	0x7e, 0x58, 0xf3, 0xc2, 0x66, 0xf8, 0x02, 0xc3, 0x47, 0xa1, 0xab, 0x8f,
+	0x26, 0x64, 0xe7, 0x51, 0xad, 0x1b, 0xd3, 0x6b, 0x63, 0x05, 0x7d, 0x6e,
+	0xd4, 0x79, 0x8f, 0x3e, 0xc7, 0xf6, 0xd6, 0xa3, 0x11, 0x39, 0x1c, 0xef,
+	0x73, 0x7b, 0x9c, 0xf7, 0x5a, 0x5d, 0x18, 0xc6, 0xb0, 0x5b, 0xd0, 0xfe,
+	0xf5, 0xe2, 0xd8, 0x61, 0xfc, 0x3a, 0x22, 0x33, 0x7b, 0x3b, 0x01, 0xdb,
+	0x5f, 0x5d, 0x66, 0xce, 0x20, 0x63, 0xad, 0xf4, 0xb7, 0xe7, 0xa3, 0x09,
+	0xca, 0xb2, 0x2e, 0xc0, 0x32, 0x72, 0x94, 0xfa, 0xcc, 0xd3, 0x3c, 0x0e,
+	0x18, 0xdc, 0x06, 0xed, 0x87, 0x90, 0x2f, 0xdf, 0x22, 0xde, 0x03, 0x90,
+	0x71, 0x47, 0x63, 0xd2, 0x73, 0xb4, 0x45, 0xb6, 0x1d, 0xa5, 0x1f, 0x52,
+	0xeb, 0x97, 0xd2, 0x2e, 0x7d, 0x04, 0x73, 0x7c, 0xb7, 0x96, 0x93, 0xdc,
+	0xd3, 0xdc, 0x4f, 0xde, 0x45, 0xdd, 0x2c, 0x6c, 0xe6, 0xcc, 0x51, 0x57,
+	0xef, 0x91, 0x66, 0x30, 0xe7, 0x6c, 0xd9, 0xc5, 0x38, 0x46, 0xe6, 0xe4,
+	0xe9, 0xa7, 0x8c, 0x76, 0x00, 0xc7, 0xef, 0xb5, 0xbc, 0xb3, 0xbe, 0xc3,
+	0xf2, 0xe8, 0xcf, 0xc8, 0x7b, 0x5b, 0x3a, 0x8c, 0xec, 0x7c, 0x4b, 0x07,
+	0x73, 0x93, 0x36, 0x7b, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7,
+	0xe2, 0x45, 0x01, 0x8e, 0xc2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0x38, 0xe7,
+	0xeb, 0xf3, 0x2b, 0xfe, 0xa2, 0xfe, 0x3b, 0x21, 0xdc, 0x23, 0xab, 0x7e,
+	0x6f, 0x65, 0x57, 0x85, 0x71, 0xf2, 0xcf, 0x86, 0x7f, 0x97, 0xa4, 0x26,
+	0xef, 0xb0, 0x76, 0x0f, 0x8c, 0xb1, 0xa6, 0xe5, 0xdc, 0xa0, 0xa0, 0xa4,
+	0xbf, 0x5f, 0xf4, 0x9c, 0x73, 0xbe, 0x70, 0xd6, 0xf9, 0xee, 0xb4, 0x04,
+	0x51, 0xef, 0x27, 0xce, 0xf7, 0x3d, 0xee, 0x99, 0x7f, 0xdd, 0xf9, 0x5e,
+	0xc1, 0x03, 0x1f, 0xde, 0x87, 0x79, 0xbc, 0xe2, 0xfc, 0x00, 0xeb, 0x7b,
+	0xb0, 0x98, 0x4e, 0xb9, 0x36, 0x26, 0x7e, 0xb6, 0xf0, 0x8a, 0xf3, 0xb5,
+	0x6a, 0x3c, 0x69, 0x30, 0xa4, 0x91, 0x43, 0x7c, 0x57, 0xc6, 0xbb, 0xb2,
+	0xde, 0xff, 0x71, 0xe6, 0xa6, 0x6d, 0x7e, 0x89, 0xe6, 0xe3, 0x85, 0xe5,
+	0x7d, 0x99, 0x51, 0xbd, 0x57, 0xf1, 0xac, 0x33, 0x37, 0x7f, 0x77, 0x87,
+	0xc9, 0x33, 0x3a, 0x8b, 0x77, 0x26, 0xe7, 0x72, 0x76, 0xfe, 0x2c, 0xea,
+	0x3c, 0xe3, 0xcc, 0xea, 0xf8, 0x97, 0xf6, 0xc5, 0x9d, 0x99, 0xf9, 0x67,
+	0x9c, 0x79, 0xbd, 0x07, 0x7d, 0xce, 0x79, 0x74, 0x9a, 0x7d, 0x9f, 0x43,
+	0x9d, 0x05, 0xe7, 0x04, 0xfa, 0x9b, 0x9f, 0xe6, 0x79, 0xdc, 0x6e, 0xd8,
+	0x05, 0xfc, 0x7b, 0x3f, 0xfc, 0x1e, 0xc7, 0xb3, 0xce, 0xfc, 0x72, 0xbf,
+	0x8b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x59, 0xf4, 0xbf, 0x76,
+	0xaf, 0x6a, 0x2d, 0x4e, 0x5e, 0x00, 0x4e, 0x2e, 0x58, 0x9c, 0xbc, 0x6a,
+	0x71, 0xf2, 0x7c, 0x0d, 0x4e, 0x44, 0xad, 0xc4, 0xc9, 0xab, 0xc0, 0x89,
+	0xa8, 0xfa, 0x38, 0xc1, 0xbb, 0x32, 0xde, 0x69, 0x9c, 0xbc, 0xb4, 0x0a,
+	0x27, 0x4b, 0xcb, 0x71, 0x79, 0x83, 0x93, 0x17, 0x81, 0x93, 0xaf, 0x5a,
+	0xd8, 0x2f, 0x58, 0x9c, 0xe0, 0x3e, 0x7f, 0x01, 0x75, 0x5e, 0xaa, 0xc1,
+	0xc9, 0x05, 0xe0, 0xe4, 0x25, 0x8b, 0x93, 0xef, 0x5b, 0x9c, 0x7c, 0x1f,
+	0x75, 0x96, 0x80, 0x93, 0xf3, 0x75, 0x70, 0xf2, 0x22, 0x70, 0x12, 0xf6,
+	0x7b, 0x1e, 0xfd, 0x7c, 0xbf, 0x06, 0x27, 0x2f, 0xd6, 0xc1, 0x09, 0xf7,
+	0x62, 0xc3, 0x9c, 0xee, 0x99, 0xd7, 0xc9, 0xe9, 0x96, 0x3b, 0x5f, 0x3f,
+	0xa7, 0x9b, 0x75, 0x66, 0xa4, 0xfa, 0x37, 0x25, 0xee, 0xb6, 0x39, 0x6a,
+	0x26, 0x17, 0xb0, 0xfa, 0xcd, 0xa6, 0x6e, 0xf0, 0x79, 0x3e, 0xe7, 0x8a,
+	0xc9, 0x29, 0x8d, 0xee, 0xf8, 0x10, 0x78, 0x6d, 0x97, 0x1c, 0x38, 0xd6,
+	0x78, 0x38, 0x6b, 0xcb, 0xbc, 0x1d, 0xdd, 0x39, 0xa5, 0xf8, 0x2e, 0xcc,
+	0x49, 0xa0, 0x5f, 0xd2, 0xc0, 0x6f, 0x0b, 0xf6, 0xa6, 0xa5, 0x76, 0x4f,
+	0xba, 0xc0, 0x6f, 0x34, 0x61, 0xec, 0x25, 0xfe, 0xfd, 0x8b, 0x24, 0xf3,
+	0xac, 0xf2, 0x1a, 0xde, 0x14, 0xf4, 0xc7, 0xa0, 0xce, 0xad, 0xca, 0x14,
+	0x68, 0x73, 0x27, 0x99, 0xa3, 0x06, 0x5b, 0x79, 0xc8, 0x9e, 0x09, 0xf3,
+	0xf5, 0x39, 0x95, 0x2a, 0xff, 0xd4, 0x9e, 0x87, 0x26, 0xdf, 0x55, 0xe9,
+	0xe6, 0xe0, 0xf2, 0x77, 0x02, 0x4f, 0xca, 0xd3, 0x3a, 0x56, 0xdc, 0x8c,
+	0xf5, 0x09, 0x82, 0xc7, 0x7c, 0x13, 0xa3, 0x5d, 0xd4, 0x31, 0x5a, 0x81,
+	0x37, 0x3e, 0x69, 0xe3, 0xb4, 0x3d, 0x83, 0x2f, 0x2d, 0xc7, 0x68, 0x6b,
+	0xf3, 0x59, 0xcc, 0xfe, 0x7a, 0xa6, 0xf4, 0x88, 0xce, 0xd1, 0x19, 0xe1,
+	0xf7, 0x37, 0x20, 0x23, 0x26, 0x66, 0xe6, 0x65, 0xf2, 0x41, 0x3e, 0x53,
+	0xbf, 0x45, 0xa0, 0xc3, 0x28, 0xc3, 0x73, 0x92, 0x19, 0x64, 0x99, 0x69,
+	0x33, 0xa2, 0xfd, 0xe5, 0x93, 0x32, 0xbc, 0x3c, 0x3e, 0xf1, 0x7b, 0x57,
+	0xcd, 0x77, 0xab, 0x69, 0xf3, 0xa4, 0x9d, 0x4c, 0x85, 0xef, 0xc3, 0x3d,
+	0xf2, 0xbb, 0xec, 0xb7, 0xb3, 0xf8, 0xbe, 0xf6, 0x5b, 0xad, 0x5a, 0x74,
+	0xe0, 0x37, 0xbf, 0x87, 0x36, 0xe5, 0x8c, 0xa0, 0xcd, 0x82, 0xdb, 0x32,
+	0xaa, 0x86, 0x6e, 0x18, 0xe5, 0xb9, 0xb9, 0xd9, 0x35, 0xdf, 0xba, 0xae,
+	0xea, 0xc5, 0xbc, 0x5e, 0x53, 0xe6, 0x67, 0xdd, 0x05, 0x5a, 0xd4, 0xb4,
+	0xa5, 0xe9, 0xff, 0xc0, 0xb2, 0xbe, 0xa4, 0x9e, 0x35, 0xdf, 0x9e, 0x31,
+	0xfa, 0x32, 0x95, 0x18, 0xc1, 0xf8, 0xfa, 0x6f, 0x2a, 0xd8, 0x73, 0xbd,
+	0xd9, 0xf9, 0xdb, 0xb5, 0xae, 0x9f, 0xf2, 0xd3, 0xc9, 0xa8, 0xd4, 0xa9,
+	0x5b, 0xaa, 0xa9, 0xab, 0xe7, 0xed, 0xca, 0x7f, 0xc5, 0xda, 0x7c, 0xbe,
+	0x58, 0x96, 0xe1, 0xe9, 0xbf, 0x84, 0xff, 0x98, 0x90, 0xdf, 0x2e, 0x96,
+	0x40, 0xaf, 0xb9, 0xcd, 0xf6, 0x5b, 0x4d, 0x19, 0xc0, 0xcd, 0x6f, 0xaf,
+	0xe8, 0x7c, 0xe2, 0xc8, 0x17, 0x40, 0x17, 0x9f, 0x2b, 0x71, 0x0c, 0xc0,
+	0x12, 0x81, 0x6d, 0x0f, 0x3b, 0x61, 0xa6, 0xa4, 0x73, 0xe7, 0xae, 0x2b,
+	0x97, 0x74, 0xcc, 0x62, 0x67, 0xb9, 0x53, 0x76, 0x95, 0x5b, 0x64, 0x37,
+	0xf4, 0xc2, 0xee, 0xb2, 0x87, 0x2b, 0x26, 0xef, 0x2e, 0x9b, 0x75, 0xfa,
+	0x58, 0x99, 0xeb, 0xbd, 0x43, 0x66, 0x8f, 0xad, 0xfe, 0x3e, 0xe7, 0x42,
+	0x2e, 0xfc, 0x3b, 0x4b, 0x4a, 0x31, 0xbf, 0x8c, 0xb4, 0x84, 0xab, 0x98,
+	0x3a, 0xbc, 0xa0, 0xf1, 0xc0, 0x0c, 0xd7, 0x54, 0x69, 0x49, 0x98, 0xa7,
+	0xcf, 0xbf, 0xad, 0x34, 0x73, 0x39, 0xcf, 0x4d, 0xf3, 0x5b, 0x5e, 0x3b,
+	0x2b, 0x61, 0xde, 0x78, 0xbd, 0x9c, 0x71, 0xd8, 0xf9, 0x3b, 0xc2, 0x1c,
+	0xbf, 0x18, 0x73, 0xc6, 0xa5, 0xeb, 0x54, 0x0b, 0xee, 0xa7, 0x2f, 0xd7,
+	0x67, 0x9b, 0x4f, 0x89, 0x2d, 0xd3, 0xf9, 0xe4, 0x78, 0x5e, 0xfd, 0x7d,
+	0xb5, 0x90, 0x1f, 0xaa, 0x7f, 0xa7, 0x40, 0xe4, 0xff, 0x02, 0xfb, 0x2e,
+	0x88, 0x71, 0xec, 0x6e, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
+	0x0800061c, 0x0800083c, 0x08000780, 0x080007a8, 0x080007d0, 0x080007f8,
+	0x08000654, 0x08000640, 0x08000864, 0x08000864, 0x08000670, 0x0800068c,
+	0x0800068c, 0x08000864, 0x080006a4, 0x080006b8, 0x08000864, 0x080006cc,
+	0x08000864, 0x08000864, 0x080006e0, 0x08000864, 0x08000864, 0x08000864,
+	0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864,
+	0x08000864, 0x080006f4, 0x08000864, 0x08000708, 0x0800071c, 0x08000730,
+	0x08000864, 0x08000744, 0x08000758, 0x0800076c, 0x08003200, 0x08003218,
+	0x08003228, 0x08003238, 0x08003250, 0x08003268, 0x08003278, 0x08003288,
+	0x080032a8, 0x080032b8, 0x080032c8, 0x08003358, 0x08003298, 0x080032d8,
+	0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338,
+	0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc,
+	0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 };
+static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 };
+static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_cp_fw_09 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
 	.start_addr			= 0x0800006c,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x73cc,
+	.text_len			= 0x6ee8,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_CP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_CP_b09FwText),
 
-	.data_addr			= 0x08007500,
-	.data_len			= 0x50,
+	.data_addr			= 0x08007020,
+	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_CP_b09FwData,
 
-	.sbss_addr			= 0x08007554,
-	.sbss_len			= 0xe9,
+	.sbss_addr			= 0x08007024,
+	.sbss_len			= 0xa1,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_CP_b09FwSbss,
 
-	.bss_addr			= 0x08007640,
-	.bss_len			= 0x870,
+	.bss_addr			= 0x080070d0,
+	.bss_len			= 0x3b0,
 	.bss_index			= 0x0,
 	.bss				= bnx2_CP_b09FwBss,
 
-	.rodata_addr			= 0x080073d0,
+	.rodata_addr			= 0x08006ee8,
 	.rodata_len			= 0x118,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_CP_b09FwRodata,
 };
 
 static u8 bnx2_RXP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x19, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6b, 0x6c,
-	0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x20, 0xb5, 0xa2, 0xf8, 0x18, 0x2e, 0x57,
-	0xcc, 0x4a, 0x66, 0xec, 0x5d, 0x71, 0x24, 0xb2, 0x16, 0x6b, 0x8c, 0xd8,
-	0xad, 0x4d, 0x04, 0x6b, 0x7b, 0x33, 0xbb, 0x92, 0x98, 0x54, 0x85, 0x29,
-	0x87, 0x75, 0x0c, 0xc3, 0x75, 0xd9, 0xa5, 0x1a, 0xbb, 0xae, 0x51, 0xc8,
-	0x8f, 0xc4, 0x06, 0x6a, 0xd6, 0x9b, 0x25, 0xdd, 0xa8, 0xe9, 0x82, 0x43,
-	0x4b, 0xaa, 0xe9, 0x02, 0x69, 0xbb, 0x20, 0xa9, 0xc7, 0x8f, 0x85, 0x56,
-	0x76, 0x52, 0xc7, 0xf9, 0xe1, 0x48, 0x50, 0x95, 0x20, 0x28, 0x0c, 0x43,
-	0x48, 0x8d, 0xd6, 0x3f, 0xda, 0x40, 0x95, 0x9f, 0x68, 0x92, 0x42, 0x41,
-	0x0b, 0xc7, 0x68, 0x6c, 0x4f, 0xbf, 0xef, 0xce, 0x0c, 0xb9, 0xa4, 0x5f,
-	0x40, 0x7f, 0xf4, 0x4f, 0xe7, 0x02, 0x8b, 0xb9, 0xf7, 0xce, 0x3d, 0xe7,
-	0x9e, 0x7b, 0xde, 0xe7, 0x0e, 0xa5, 0xdf, 0xef, 0x94, 0x0e, 0x09, 0x5b,
-	0x17, 0x7e, 0x99, 0xc3, 0x8f, 0x3d, 0x74, 0xc3, 0xd8, 0x0d, 0xa3, 0x22,
-	0x7b, 0xf6, 0x18, 0x5b, 0x12, 0x7a, 0x34, 0x1f, 0xb7, 0xb8, 0xc5, 0x2d,
-	0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e,
-	0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71,
-	0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b,
-	0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b,
-	0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc,
-	0xe2, 0xf6, 0xff, 0xbd, 0x19, 0x22, 0x16, 0x9f, 0x5d, 0xe1, 0x4f, 0x12,
-	0x7a, 0xfe, 0xf2, 0x1f, 0xba, 0xb6, 0x24, 0x8c, 0xfc, 0xcf, 0x66, 0xa6,
-	0x6d, 0x91, 0x42, 0x63, 0x77, 0xa6, 0x28, 0xef, 0xfb, 0x95, 0x94, 0x29,
-	0x9c, 0xff, 0x6c, 0xfe, 0xbd, 0xbf, 0x7d, 0xf1, 0xa6, 0xec, 0xd5, 0xba,
-	0x21, 0x09, 0x2b, 0x3f, 0xb7, 0xc7, 0xda, 0x25, 0x89, 0x01, 0xc0, 0x7c,
-	0x6b, 0xe8, 0xc7, 0xdd, 0xd2, 0x2d, 0x6b, 0x78, 0xec, 0x84, 0x5c, 0x36,
-	0x5e, 0xd0, 0xdc, 0xa6, 0xef, 0x9f, 0x70, 0x7c, 0xff, 0x87, 0xf8, 0xbd,
-	0xe5, 0x60, 0xec, 0x7d, 0xe0, 0x17, 0x4c, 0x43, 0x74, 0xfb, 0x2f, 0x34,
-	0x77, 0xb9, 0x43, 0xaa, 0x8b, 0xa6, 0xcc, 0x7a, 0x29, 0x39, 0xe2, 0x55,
-	0xb4, 0x52, 0xb3, 0xa6, 0xed, 0x3d, 0x35, 0xaf, 0xed, 0x3b, 0x75, 0x44,
-	0xdb, 0x7f, 0x6a, 0x41, 0x73, 0x4f, 0x49, 0x45, 0xdf, 0xd3, 0x29, 0x05,
-	0xeb, 0xb4, 0x56, 0x6c, 0xf6, 0x6b, 0xee, 0xe2, 0x7b, 0xbe, 0xeb, 0x64,
-	0xad, 0xbb, 0xc4, 0x2c, 0x80, 0x16, 0x71, 0x6b, 0x3e, 0xc6, 0xa6, 0x14,
-	0x52, 0xbe, 0xaf, 0xe7, 0xfd, 0x27, 0xdc, 0x9c, 0x6d, 0xe9, 0x5a, 0x4a,
-	0xaa, 0xcd, 0x7e, 0xe0, 0xed, 0xd4, 0x8a, 0x8b, 0xa6, 0x56, 0xf2, 0xfc,
-	0x73, 0xae, 0x23, 0x03, 0x86, 0xf8, 0xfe, 0x9c, 0xb3, 0x33, 0x7d, 0x48,
-	0x4e, 0x02, 0x6f, 0x03, 0xf8, 0xc4, 0xd2, 0xf3, 0xa4, 0x8f, 0x74, 0x92,
-	0xe4, 0x8a, 0x56, 0x1c, 0x8a, 0xe8, 0x93, 0x0c, 0xe9, 0x2f, 0xaf, 0xe8,
-	0xa0, 0x73, 0x8b, 0x94, 0xeb, 0x96, 0x4c, 0xad, 0x6c, 0x5c, 0x7f, 0xd9,
-	0x7f, 0x71, 0x28, 0x25, 0xcf, 0x36, 0xb3, 0x47, 0x2a, 0x92, 0x90, 0x39,
-	0x2f, 0x23, 0x7a, 0x5e, 0x0a, 0x6e, 0x6e, 0x40, 0xce, 0x35, 0xd3, 0xf2,
-	0x5c, 0xd3, 0x4e, 0x57, 0x65, 0x93, 0x94, 0x53, 0x96, 0x9c, 0x6d, 0xa6,
-	0x70, 0x46, 0xff, 0x9c, 0x6e, 0xdb, 0x56, 0x15, 0x6b, 0xab, 0xcd, 0x97,
-	0xf8, 0xef, 0x5f, 0xac, 0xe9, 0x9c, 0x82, 0xa9, 0x80, 0xee, 0x70, 0x2d,
-	0xcf, 0xa1, 0xd6, 0xaa, 0xb3, 0x04, 0x6b, 0xa5, 0x32, 0x9d, 0xc3, 0x5c,
-	0x73, 0x34, 0xe4, 0xef, 0x16, 0x9c, 0x97, 0x4f, 0x4b, 0xaa, 0x9e, 0x01,
-	0xde, 0xb0, 0xff, 0xcf, 0xc0, 0x37, 0x80, 0xf3, 0x5e, 0xab, 0x7e, 0xee,
-	0xa2, 0xa4, 0x74, 0xd9, 0x99, 0x2e, 0x0b, 0x78, 0xdb, 0xec, 0xc4, 0x98,
-	0xf4, 0xf9, 0xfe, 0x7e, 0x47, 0xac, 0xaa, 0xd3, 0x03, 0x98, 0x8c, 0x54,
-	0x9d, 0x6e, 0xe0, 0x69, 0x13, 0xcb, 0xe6, 0xb9, 0xb8, 0xd7, 0x66, 0xcc,
-	0xfb, 0x5d, 0x46, 0xde, 0xf7, 0xa7, 0x73, 0xd2, 0x1d, 0xcc, 0xed, 0x56,
-	0x38, 0xa6, 0x26, 0x34, 0xac, 0xfb, 0x05, 0x69, 0x4e, 0x24, 0xf3, 0xec,
-	0xf3, 0x99, 0x13, 0x77, 0xfe, 0xda, 0x90, 0x96, 0x34, 0x68, 0xb9, 0x26,
-	0xec, 0x83, 0xff, 0x1e, 0xf8, 0xe0, 0x7c, 0x06, 0x63, 0xed, 0x3a, 0xe0,
-	0x19, 0xae, 0x0a, 0xf7, 0xe8, 0x93, 0xa5, 0x94, 0xe8, 0x57, 0x9c, 0xde,
-	0x70, 0x5d, 0x37, 0x68, 0x8d, 0xf4, 0xa0, 0x5f, 0xe6, 0x16, 0xc9, 0xeb,
-	0x1a, 0x64, 0x83, 0xe7, 0x8d, 0x15, 0xad, 0xd0, 0x3c, 0x82, 0xbe, 0x29,
-	0xd3, 0xb6, 0x7f, 0x6e, 0xce, 0x99, 0xd7, 0x8a, 0xa7, 0x4e, 0x6a, 0xa5,
-	0x53, 0x2f, 0x68, 0x7b, 0x9b, 0x2f, 0x74, 0x49, 0x47, 0x16, 0xa7, 0x4e,
-	0xc8, 0x93, 0x9e, 0x26, 0xa4, 0x73, 0x09, 0xbc, 0x2b, 0x58, 0x15, 0x31,
-	0xed, 0x6e, 0x6d, 0x1f, 0xf0, 0xb4, 0xd9, 0x7f, 0xd2, 0x29, 0xdd, 0x86,
-	0x6c, 0xb2, 0xa3, 0xb5, 0x29, 0xf9, 0x33, 0xd0, 0x74, 0xc1, 0x49, 0x91,
-	0x5f, 0x3d, 0x01, 0x4c, 0x44, 0x07, 0xf5, 0x8a, 0x3a, 0xa5, 0x17, 0x4a,
-	0xc7, 0xff, 0xbc, 0xaf, 0x3a, 0xb2, 0x85, 0x6b, 0xa0, 0xff, 0xd6, 0xfd,
-	0xd3, 0xb6, 0xdb, 0x6b, 0x4a, 0xc5, 0xd2, 0x25, 0x6b, 0x15, 0xe5, 0x3a,
-	0x99, 0x73, 0x44, 0x8a, 0x35, 0xec, 0x69, 0x9b, 0xe0, 0x8d, 0x0d, 0xde,
-	0xec, 0x3c, 0x32, 0xa8, 0xff, 0x96, 0x64, 0xfa, 0x2b, 0x9a, 0x19, 0xf2,
-	0x71, 0x49, 0x6e, 0x51, 0xf0, 0x7a, 0xde, 0x81, 0x7e, 0x76, 0xb0, 0x8f,
-	0x7d, 0x13, 0x6a, 0x5f, 0x23, 0x6f, 0xa7, 0x97, 0x45, 0x34, 0x3d, 0xbf,
-	0x1b, 0xf8, 0xa8, 0xb7, 0x5c, 0xf7, 0x04, 0x68, 0x24, 0xed, 0xec, 0xdb,
-	0x80, 0x49, 0x88, 0xeb, 0x74, 0xb5, 0xd0, 0x49, 0x79, 0x93, 0xd7, 0xe4,
-	0x9d, 0x3a, 0xa7, 0xb6, 0x76, 0xce, 0x5f, 0xf9, 0x9b, 0x46, 0x4d, 0xf9,
-	0xa1, 0x3a, 0x2f, 0x6d, 0x8c, 0xeb, 0x52, 0xa1, 0x4e, 0x24, 0xa0, 0x47,
-	0xa2, 0x95, 0x1d, 0x6b, 0x15, 0x57, 0x59, 0x44, 0x37, 0xf2, 0x9d, 0x52,
-	0x54, 0xf4, 0x8d, 0x61, 0x2f, 0xda, 0x1e, 0x6c, 0xc8, 0xe6, 0x59, 0x38,
-	0x97, 0x87, 0x8d, 0x67, 0xd9, 0x97, 0xf2, 0x02, 0xed, 0x9d, 0xb4, 0x9d,
-	0xcf, 0xaa, 0x7f, 0x8e, 0x45, 0x5d, 0x3c, 0xd6, 0x03, 0xda, 0x38, 0x86,
-	0x1d, 0xda, 0x78, 0x3f, 0xa2, 0x89, 0x3b, 0x36, 0x08, 0xfe, 0x70, 0x9d,
-	0x9d, 0x81, 0x9c, 0x0b, 0x2e, 0xf6, 0x74, 0x9d, 0xdf, 0x50, 0x3c, 0xe8,
-	0xc5, 0x79, 0x06, 0xe7, 0xc9, 0xaf, 0x0e, 0xe8, 0xb6, 0x26, 0x65, 0x27,
-	0x9b, 0xa1, 0xdc, 0x03, 0xda, 0x75, 0xd9, 0x74, 0x63, 0x2b, 0xed, 0x91,
-	0xac, 0xa8, 0x87, 0xa6, 0x24, 0x47, 0xb9, 0x96, 0xeb, 0xb8, 0x3e, 0x3b,
-	0x26, 0xfa, 0xaf, 0x7c, 0x6b, 0xdd, 0x59, 0x6d, 0xd9, 0x31, 0x0f, 0x1a,
-	0x02, 0xde, 0x82, 0x27, 0x9f, 0xb6, 0x96, 0x7c, 0xdd, 0xc8, 0x3f, 0xae,
-	0x6d, 0x5d, 0x07, 0x9d, 0xe8, 0x27, 0x0d, 0x27, 0x3a, 0x03, 0x5b, 0x8b,
-	0x68, 0x8a, 0x64, 0xa3, 0x85, 0x38, 0x3e, 0xe9, 0x1c, 0x5c, 0x0f, 0x1f,
-	0xe0, 0xc1, 0x07, 0xc0, 0xaf, 0x3d, 0xeb, 0xc1, 0xfe, 0x3d, 0xfa, 0x8c,
-	0x8c, 0xbc, 0x38, 0x04, 0x1f, 0xb7, 0xe6, 0x63, 0xd0, 0xc6, 0xd1, 0xd7,
-	0xc5, 0x80, 0x8f, 0x99, 0xad, 0xeb, 0xb0, 0x59, 0xf0, 0x78, 0x85, 0x73,
-	0xb0, 0xed, 0x95, 0x12, 0x9e, 0xb6, 0x54, 0x1b, 0xd4, 0xab, 0xc8, 0x97,
-	0xd2, 0xe7, 0xa4, 0xe1, 0x5f, 0xe8, 0x77, 0xe8, 0x57, 0xb8, 0xd6, 0xf7,
-	0x4b, 0x0e, 0x61, 0x7d, 0x99, 0x70, 0x68, 0x43, 0x9d, 0xa2, 0x27, 0x2b,
-	0xda, 0xc1, 0x21, 0xd8, 0xd6, 0xf5, 0x6d, 0xa0, 0x95, 0x36, 0x76, 0x8d,
-	0x48, 0x3b, 0xf7, 0xfb, 0x69, 0x57, 0xf0, 0xef, 0xee, 0x36, 0x61, 0x0d,
-	0x9f, 0xef, 0x86, 0x63, 0x2d, 0xf4, 0x2d, 0x7c, 0x9f, 0xcd, 0x14, 0xa4,
-	0x3f, 0x1c, 0xb3, 0xbf, 0x4a, 0xaf, 0xa3, 0xdf, 0x98, 0x90, 0x1d, 0x27,
-	0x03, 0x9f, 0xb8, 0x63, 0xc9, 0x12, 0xfb, 0x64, 0x40, 0xe3, 0x8e, 0x33,
-	0x91, 0x6f, 0x7c, 0x1f, 0xf0, 0xa0, 0xcf, 0x5b, 0x8d, 0x03, 0x68, 0x3f,
-	0xd3, 0x60, 0x2a, 0x98, 0xdb, 0xc8, 0x0b, 0xfa, 0x63, 0xda, 0x9b, 0xd5,
-	0x6a, 0x6f, 0x7b, 0x60, 0x6f, 0x4e, 0xbb, 0x64, 0x9d, 0xbf, 0x87, 0xbd,
-	0x7d, 0xc3, 0xd1, 0xc0, 0x1b, 0x91, 0x8b, 0xb5, 0x34, 0x6c, 0xdd, 0x4c,
-	0xbf, 0x26, 0x3b, 0x33, 0xb3, 0xa2, 0xc9, 0x09, 0xce, 0x35, 0x30, 0xa7,
-	0x7c, 0x71, 0xe0, 0x0b, 0x2e, 0x1b, 0x4f, 0x81, 0x2e, 0xdf, 0x9f, 0x05,
-	0xce, 0xf2, 0x88, 0x11, 0xda, 0x56, 0x34, 0x6f, 0xdd, 0xef, 0xda, 0xee,
-	0xaf, 0x19, 0x52, 0x19, 0x6e, 0x93, 0xec, 0xf0, 0x12, 0x70, 0x4f, 0x3b,
-	0x81, 0x1d, 0x53, 0xd7, 0x97, 0x81, 0x7f, 0xce, 0x1b, 0x82, 0x1e, 0xd3,
-	0x0e, 0x40, 0x17, 0xf0, 0x2f, 0x03, 0xff, 0x5c, 0xb3, 0x4d, 0xbe, 0x6e,
-	0x46, 0xb1, 0x32, 0x3a, 0x4f, 0x37, 0x96, 0x45, 0xfb, 0x1e, 0x96, 0x2f,
-	0x7a, 0x49, 0xcd, 0x3d, 0x46, 0xff, 0x5a, 0x1d, 0x86, 0x9d, 0x68, 0x55,
-	0x87, 0x7b, 0x1b, 0xb2, 0xbc, 0xba, 0x46, 0x0a, 0xd5, 0xc0, 0x06, 0x0b,
-	0xee, 0x50, 0x25, 0x6d, 0x28, 0x5f, 0x22, 0xb2, 0x0f, 0xb6, 0xb7, 0x6c,
-	0x73, 0xcc, 0xf9, 0x60, 0x6e, 0xbc, 0xd6, 0x0f, 0x9f, 0xc8, 0xf1, 0x7b,
-	0xfe, 0xb4, 0x13, 0xcc, 0x7d, 0xa1, 0x76, 0x57, 0x37, 0xfd, 0x2e, 0xe2,
-	0x44, 0xa6, 0xea, 0xfc, 0xbb, 0x0f, 0xfd, 0x5d, 0x07, 0xf3, 0xd1, 0x78,
-	0xb2, 0xe3, 0x81, 0xce, 0x8a, 0xb6, 0xdf, 0xd6, 0xfb, 0xdb, 0x43, 0x1f,
-	0xb6, 0x1f, 0x93, 0x7b, 0x6b, 0xd5, 0xbe, 0x76, 0x79, 0xcf, 0x60, 0x1c,
-	0xbd, 0x22, 0x62, 0xba, 0xb5, 0x5d, 0xe0, 0x47, 0xb5, 0xb7, 0x65, 0x2e,
-	0x51, 0xaa, 0xf9, 0x72, 0xc1, 0x09, 0x60, 0x30, 0xee, 0x2c, 0xd6, 0xf4,
-	0xfe, 0x84, 0xac, 0x8e, 0x2d, 0xc2, 0xac, 0xc8, 0xae, 0xe1, 0x65, 0x51,
-	0xb0, 0x7d, 0x89, 0x35, 0xd8, 0x54, 0xa9, 0x56, 0xed, 0x6d, 0x19, 0xa7,
-	0x8b, 0xc0, 0xa5, 0xef, 0x59, 0x85, 0x1d, 0x58, 0x83, 0xdd, 0x2a, 0x99,
-	0x5e, 0xc2, 0xeb, 0xfd, 0x9b, 0xd7, 0x70, 0x67, 0x42, 0x7a, 0xfa, 0x36,
-	0xaf, 0xe1, 0xb0, 0x89, 0xb3, 0x65, 0x3c, 0x4c, 0x9c, 0x3b, 0xd6, 0x70,
-	0x8e, 0xac, 0xa7, 0xe7, 0xb0, 0xc0, 0x07, 0x25, 0xda, 0xf3, 0xb2, 0xe7,
-	0x62, 0x6d, 0x70, 0xe2, 0x8b, 0x82, 0x58, 0x37, 0xb2, 0x29, 0xf4, 0xc9,
-	0xe6, 0x1e, 0x17, 0xbc, 0x32, 0x85, 0x3e, 0x4e, 0x93, 0x2a, 0xe4, 0x7c,
-	0x7f, 0x43, 0xf6, 0x5c, 0x68, 0x98, 0xa1, 0x2e, 0x51, 0x27, 0xde, 0x86,
-	0x8d, 0x75, 0x4e, 0x99, 0x88, 0xc3, 0xe7, 0x94, 0x8d, 0xc9, 0x44, 0xb5,
-	0x26, 0x95, 0xed, 0xf9, 0x27, 0x7c, 0xe8, 0xe2, 0x94, 0x05, 0x3f, 0x5a,
-	0x94, 0xce, 0x31, 0x37, 0x87, 0xf9, 0x06, 0x6d, 0x0b, 0x7e, 0x05, 0xb0,
-	0xd0, 0xb5, 0x84, 0x31, 0xbf, 0xf3, 0x55, 0xd7, 0xe0, 0x3e, 0x19, 0xe4,
-	0x4d, 0x89, 0x84, 0x3e, 0x7f, 0xd5, 0xa7, 0x9e, 0x4d, 0x8f, 0x5c, 0x45,
-	0x9e, 0x62, 0xc1, 0x57, 0xc2, 0x7f, 0x40, 0xdf, 0x67, 0x9b, 0x82, 0xb8,
-	0xfe, 0x40, 0x4f, 0x60, 0x63, 0x47, 0xb7, 0x06, 0x4f, 0x31, 0xe9, 0x9b,
-	0xa7, 0x73, 0xcc, 0x01, 0xda, 0x13, 0x6e, 0x6e, 0x7c, 0x9b, 0x71, 0xe6,
-	0xc0, 0x36, 0xfd, 0x4c, 0x65, 0x9b, 0x0e, 0x9f, 0x0e, 0x9b, 0xd2, 0xdd,
-	0x1c, 0xfa, 0x67, 0x22, 0x1b, 0x4a, 0xc3, 0x86, 0xde, 0x56, 0x39, 0xc8,
-	0xb9, 0xe6, 0x29, 0xd8, 0xab, 0xa2, 0x55, 0x26, 0x90, 0x13, 0xe8, 0xa3,
-	0xef, 0x43, 0x4f, 0x70, 0x16, 0xf8, 0xc0, 0x02, 0xb8, 0xa4, 0x8f, 0xbe,
-	0x11, 0xda, 0x33, 0xfb, 0xef, 0xf8, 0x41, 0x7c, 0xf8, 0x7c, 0xb8, 0xff,
-	0x3f, 0x75, 0x07, 0x3e, 0x20, 0xc2, 0x45, 0x3c, 0xc3, 0xda, 0x04, 0xf2,
-	0x99, 0x89, 0xa6, 0xa9, 0xd1, 0x9f, 0x17, 0x3d, 0xe6, 0x21, 0xcc, 0x41,
-	0x1e, 0x0b, 0xfd, 0x22, 0x73, 0x8f, 0xce, 0x90, 0xa7, 0xb9, 0x28, 0xce,
-	0x29, 0x7b, 0x43, 0xcc, 0xc9, 0x94, 0x9d, 0x36, 0xe5, 0x93, 0xa7, 0x73,
-	0x9d, 0x58, 0x87, 0xb9, 0x26, 0xce, 0x0d, 0xbf, 0x84, 0x5c, 0x06, 0x6b,
-	0xce, 0x63, 0x7d, 0x7b, 0x68, 0xf3, 0x17, 0xa5, 0x0c, 0x9f, 0x6a, 0xda,
-	0x7c, 0x9f, 0xeb, 0x91, 0x0e, 0x8c, 0x1b, 0xd8, 0x0b, 0x7e, 0xc2, 0x50,
-	0x7c, 0x46, 0x2c, 0x48, 0x5d, 0xc7, 0x1c, 0x09, 0x6b, 0x33, 0x58, 0x4b,
-	0xbf, 0xcb, 0xb5, 0xcf, 0x82, 0x0e, 0x8c, 0x1b, 0x84, 0xa1, 0x8f, 0x12,
-	0xdf, 0xcd, 0x6d, 0x86, 0x26, 0xf9, 0xe7, 0x0c, 0x3b, 0x5a, 0x1b, 0xe1,
-	0xdd, 0xb8, 0x96, 0xf9, 0x09, 0x71, 0xf7, 0x84, 0xf1, 0x7f, 0x5c, 0x0a,
-	0xcd, 0x02, 0x7e, 0x22, 0xd3, 0xc7, 0x90, 0x8f, 0xd9, 0x6d, 0x88, 0x55,
-	0x9c, 0xdf, 0x6a, 0x05, 0x67, 0x8d, 0xe0, 0xee, 0xef, 0x5b, 0x3f, 0xfe,
-	0x42, 0x72, 0xcd, 0x47, 0xd2, 0xc2, 0xa4, 0x80, 0x18, 0x01, 0x5e, 0x65,
-	0xa6, 0x98, 0xc3, 0x15, 0x1b, 0x4a, 0xa6, 0x98, 0x1b, 0x83, 0x5f, 0x0c,
-	0xf2, 0xa2, 0x73, 0xde, 0x46, 0xd9, 0x59, 0xe0, 0x77, 0x01, 0x3c, 0xce,
-	0x40, 0x87, 0xc6, 0x01, 0x2b, 0x87, 0x81, 0x83, 0xf1, 0xd7, 0xd1, 0xf3,
-	0x49, 0x29, 0x5b, 0xcc, 0x13, 0xda, 0x49, 0x67, 0x81, 0xf6, 0xaf, 0xe7,
-	0x37, 0x63, 0x8e, 0xfd, 0x7b, 0x7b, 0x02, 0x99, 0x75, 0x71, 0x3c, 0xa1,
-	0xe7, 0x7b, 0x36, 0xcc, 0x7f, 0xbf, 0x2b, 0xa0, 0x4d, 0x8d, 0x31, 0xff,
-	0xf2, 0x86, 0xf1, 0xef, 0x25, 0xd7, 0x8f, 0xef, 0xda, 0x16, 0xea, 0x20,
-	0xfa, 0x8f, 0x85, 0xf4, 0x82, 0xb6, 0x55, 0x5a, 0xa3, 0x9c, 0x57, 0x16,
-	0x74, 0xe4, 0x7f, 0x6e, 0x6e, 0x27, 0x62, 0x7d, 0x46, 0x4a, 0x4d, 0xd0,
-	0xbd, 0x1a, 0xcb, 0x56, 0xd7, 0x54, 0xd6, 0xd6, 0x04, 0xbe, 0xbe, 0xd4,
-	0xf4, 0x91, 0x3b, 0xb5, 0xc6, 0xbd, 0x61, 0xf4, 0x2b, 0xd8, 0xa7, 0x20,
-	0xd3, 0xde, 0x85, 0x82, 0x6e, 0x1f, 0x09, 0xf2, 0x3e, 0xfb, 0x9b, 0x5a,
-	0x69, 0x99, 0xf9, 0x20, 0xec, 0xc9, 0x56, 0xf9, 0x3f, 0xe2, 0xca, 0x51,
-	0xad, 0x70, 0xea, 0x38, 0xf2, 0xc1, 0x15, 0xfc, 0x4e, 0xe3, 0xd7, 0xc0,
-	0x2f, 0xca, 0xc3, 0x9f, 0x41, 0x1e, 0xaf, 0x7c, 0x2c, 0xe2, 0x41, 0xb0,
-	0xff, 0x1b, 0x2b, 0xd0, 0xb3, 0xe3, 0x29, 0xf9, 0x86, 0xad, 0xf7, 0xe9,
-	0x81, 0x5f, 0x29, 0x20, 0x8f, 0xb5, 0xde, 0x96, 0xdf, 0x0e, 0xf3, 0x22,
-	0x91, 0xd7, 0x16, 0xc0, 0xc7, 0x91, 0xfd, 0xa1, 0xce, 0x16, 0xee, 0x75,
-	0x95, 0xff, 0x0c, 0xf3, 0x1e, 0xe4, 0x5f, 0x05, 0xb5, 0xea, 0x5b, 0xe0,
-	0x8d, 0x26, 0x6f, 0x41, 0x87, 0x5e, 0x5b, 0xe8, 0x00, 0x3d, 0xb6, 0x94,
-	0x27, 0x91, 0x2f, 0x68, 0x83, 0xd6, 0x26, 0xad, 0x03, 0x76, 0x0c, 0x1b,
-	0x57, 0x63, 0x49, 0xb4, 0xe5, 0x2f, 0xcd, 0x2c, 0xd5, 0x74, 0xac, 0x45,
-	0xee, 0x93, 0x43, 0x1f, 0xb2, 0xbf, 0xb2, 0x40, 0x38, 0x5d, 0x5e, 0x5f,
-	0x30, 0xe4, 0x4d, 0xe4, 0x52, 0x6f, 0xd9, 0x97, 0x66, 0x10, 0xb7, 0xfa,
-	0x11, 0x23, 0x50, 0x8b, 0xec, 0xa4, 0x9f, 0xde, 0x61, 0xe2, 0x59, 0xc2,
-	0x6f, 0x1f, 0x72, 0xc1, 0x8f, 0x86, 0xf9, 0xb8, 0xf5, 0xa4, 0x2d, 0x01,
-	0x18, 0xae, 0x37, 0x41, 0x5b, 0x37, 0xe4, 0x9f, 0xb5, 0xa6, 0xe4, 0xf5,
-	0x1e, 0x95, 0xaf, 0x68, 0x9c, 0x0f, 0x7c, 0xd3, 0x87, 0xe7, 0xc9, 0x67,
-	0x03, 0x3a, 0xce, 0x31, 0xdf, 0xd1, 0x87, 0x12, 0x5f, 0x76, 0xac, 0x80,
-	0xc3, 0x5c, 0x59, 0x08, 0xfa, 0xd1, 0x9c, 0x68, 0x51, 0x1c, 0xa3, 0x6f,
-	0x2c, 0xc1, 0x4e, 0x38, 0x9e, 0x10, 0x25, 0x83, 0x75, 0xf2, 0x94, 0x84,
-	0x99, 0x3f, 0x3b, 0x33, 0x67, 0x53, 0xae, 0xf0, 0x71, 0xb5, 0x48, 0xae,
-	0x94, 0x51, 0xbb, 0x54, 0x17, 0xbe, 0x09, 0xb9, 0xea, 0x61, 0xbe, 0x0f,
-	0x1b, 0x3f, 0x4e, 0xf9, 0xa2, 0xfe, 0x5b, 0x40, 0xee, 0xb3, 0x20, 0xc9,
-	0xa0, 0x5e, 0x39, 0x8a, 0x3c, 0x1f, 0xf2, 0xab, 0x1d, 0x07, 0x0e, 0xd8,
-	0x69, 0x6d, 0x05, 0x4f, 0xd4, 0x16, 0xb5, 0xd3, 0x78, 0x0e, 0xe0, 0xd9,
-	0xa0, 0x6e, 0x86, 0xb9, 0xc6, 0x87, 0xe8, 0x81, 0x3d, 0x95, 0x68, 0x4f,
-	0xf2, 0xfd, 0x66, 0x5e, 0xbe, 0xdb, 0x1c, 0x93, 0xe7, 0x9b, 0x39, 0xf9,
-	0xbb, 0xa6, 0x23, 0xdf, 0x69, 0x8e, 0xc8, 0xb7, 0x9b, 0xc3, 0xac, 0xc9,
-	0x90, 0x37, 0x65, 0x98, 0x37, 0xc9, 0xbd, 0xde, 0xad, 0xb0, 0x77, 0xca,
-	0xff, 0xd2, 0x4c, 0xa1, 0x31, 0x28, 0xe5, 0x63, 0xf0, 0xcf, 0xce, 0xcd,
-	0xac, 0x25, 0xe5, 0x11, 0x87, 0x35, 0x41, 0x1b, 0xdf, 0xa3, 0xce, 0x84,
-	0xff, 0x86, 0x3f, 0x9b, 0x4a, 0x65, 0x4f, 0xbb, 0x46, 0x47, 0xe8, 0x03,
-	0x6e, 0x49, 0x4a, 0x07, 0xf6, 0x82, 0x0f, 0x5c, 0x7a, 0x1a, 0x36, 0xa0,
-	0x6a, 0x9a, 0x04, 0xfc, 0x0d, 0x73, 0x01, 0x93, 0x76, 0x8c, 0x3a, 0x30,
-	0x9b, 0x71, 0x0d, 0xd6, 0x77, 0xb4, 0x67, 0x03, 0x81, 0x83, 0x70, 0xfb,
-	0x2c, 0xca, 0xcd, 0xb4, 0xe9, 0x57, 0x0b, 0xa1, 0x8f, 0x4b, 0x84, 0x7a,
-	0x69, 0x61, 0xfe, 0xf1, 0xd0, 0x27, 0x6f, 0xdc, 0x07, 0xf1, 0x02, 0xf9,
-	0x64, 0xb0, 0x8e, 0xb0, 0x5a, 0x08, 0xdb, 0x17, 0xce, 0x75, 0x82, 0xdf,
-	0x8e, 0x94, 0xbd, 0x37, 0x35, 0xe6, 0xd9, 0xc8, 0x77, 0x30, 0x1e, 0xc1,
-	0xf8, 0x4a, 0x38, 0xfe, 0x9c, 0x4c, 0x2f, 0x0a, 0x68, 0xfd, 0x89, 0x56,
-	0x54, 0xe3, 0x31, 0x8c, 0x75, 0x8c, 0x0d, 0xd6, 0x02, 0x68, 0x37, 0x27,
-	0xa9, 0xeb, 0xba, 0x4d, 0x5f, 0x38, 0x19, 0xfa, 0xc3, 0x82, 0x1c, 0xf6,
-	0x06, 0x0b, 0x57, 0x11, 0x33, 0xb4, 0xb6, 0x28, 0xff, 0xd9, 0x0e, 0xbe,
-	0xf8, 0xfe, 0xed, 0xac, 0xb9, 0x93, 0xa6, 0x7c, 0x7b, 0x3e, 0x6b, 0x3d,
-	0xa4, 0x7f, 0x0d, 0x67, 0xf2, 0xfd, 0x83, 0x76, 0xf6, 0xc8, 0x94, 0xde,
-	0x25, 0xdf, 0x3d, 0xca, 0xd8, 0x7b, 0x76, 0xe6, 0x07, 0xd0, 0xbd, 0xfa,
-	0x4a, 0xbb, 0xd4, 0xeb, 0xa6, 0x5c, 0x19, 0x1d, 0x04, 0x9d, 0x96, 0xd4,
-	0x1b, 0x49, 0xe4, 0x73, 0x9b, 0x65, 0xb6, 0x5f, 0x19, 0x18, 0xfc, 0xf4,
-	0xb0, 0xf2, 0xd3, 0xae, 0x8d, 0x67, 0xe3, 0xe7, 0x3d, 0xeb, 0xcf, 0x5c,
-	0x02, 0xfd, 0xd0, 0xeb, 0xe4, 0x76, 0x25, 0xe7, 0xb2, 0x37, 0x68, 0x95,
-	0x75, 0xc4, 0x2e, 0x73, 0xd0, 0xba, 0x57, 0xff, 0x2f, 0xff, 0xf3, 0x26,
-	0x65, 0xf7, 0xaa, 0xaa, 0x61, 0x54, 0xac, 0xc3, 0x7e, 0x4b, 0x2b, 0x2f,
-	0x83, 0x16, 0xf8, 0xd8, 0xc6, 0xf6, 0x70, 0x9c, 0x51, 0xbc, 0x38, 0xdb,
-	0xe8, 0x90, 0xef, 0xd4, 0xb7, 0xc8, 0x72, 0x9d, 0xef, 0xdb, 0x65, 0xa9,
-	0x3e, 0x78, 0xb5, 0x4f, 0xef, 0x97, 0xf3, 0xd7, 0x5c, 0x6f, 0xdd, 0xa3,
-	0x23, 0x37, 0x98, 0xfc, 0x40, 0x7e, 0x39, 0xda, 0x23, 0x3f, 0xfe, 0x72,
-	0xf6, 0x99, 0x3f, 0xd5, 0x61, 0x03, 0xa3, 0x9d, 0xb4, 0x6d, 0xf4, 0x39,
-	0x9f, 0xbd, 0x5a, 0xd0, 0xa9, 0xdb, 0x3f, 0x02, 0x4f, 0xb3, 0x0b, 0x81,
-	0x1d, 0x10, 0x37, 0xf1, 0x42, 0x37, 0xec, 0xef, 0x01, 0x27, 0xde, 0x35,
-	0x06, 0x81, 0xeb, 0x7b, 0x8a, 0x17, 0xb7, 0x3b, 0xd9, 0xab, 0x08, 0x49,
-	0xfe, 0x15, 0x7b, 0x70, 0x78, 0x87, 0xbe, 0x5d, 0xea, 0xe9, 0xeb, 0xad,
-	0xe7, 0xe0, 0xff, 0x0b, 0xa9, 0xec, 0x91, 0xcb, 0x72, 0x76, 0xe6, 0xa2,
-	0x4d, 0xfd, 0xa7, 0xdf, 0x78, 0x09, 0xb9, 0xa7, 0x25, 0x0b, 0x0d, 0xfa,
-	0x4b, 0xe2, 0x62, 0xfe, 0xbf, 0xcb, 0x3a, 0xac, 0x33, 0x4f, 0xc0, 0x3b,
-	0xcc, 0x1b, 0xbf, 0x4e, 0x39, 0xb7, 0x11, 0x76, 0xb8, 0xa0, 0xff, 0x62,
-	0x03, 0x8f, 0x06, 0xad, 0xbd, 0x3a, 0xf7, 0xfb, 0x37, 0xec, 0xfb, 0x0e,
-	0x68, 0x1d, 0x04, 0x2c, 0x62, 0x66, 0xba, 0x75, 0x8f, 0x57, 0xd4, 0x1e,
-	0xc7, 0x1a, 0xc8, 0xf5, 0x56, 0xf7, 0xc0, 0x5c, 0x43, 0xc7, 0x39, 0x4d,
-	0x25, 0x97, 0x2b, 0xa3, 0xe4, 0xef, 0x9e, 0x5e, 0xe6, 0x99, 0x46, 0xfe,
-	0xaf, 0xfd, 0xa8, 0x7e, 0x7c, 0x7e, 0x7e, 0x12, 0xfe, 0xd9, 0xf7, 0x2f,
-	0xec, 0x1a, 0x04, 0x0d, 0xa8, 0x43, 0xd3, 0xe4, 0xf9, 0xd9, 0x19, 0x17,
-	0x38, 0x8a, 0x0a, 0xf7, 0x25, 0x59, 0x01, 0xee, 0x09, 0xf2, 0x01, 0xb8,
-	0xe7, 0x38, 0xaf, 0x64, 0x80, 0xf9, 0x46, 0x06, 0x78, 0x23, 0xfd, 0x4c,
-	0x42, 0xd7, 0x76, 0x5b, 0xb7, 0x07, 0xba, 0x9e, 0x60, 0x6c, 0x7b, 0x0e,
-	0xba, 0x57, 0x48, 0x52, 0x7f, 0xda, 0x7b, 0xd7, 0xf4, 0xa7, 0x15, 0x7f,
-	0xbb, 0x94, 0x16, 0x12, 0xc0, 0x6b, 0xca, 0x5c, 0x8e, 0x78, 0x31, 0xae,
-	0x53, 0xf7, 0x2b, 0xa1, 0xee, 0x77, 0x86, 0xb8, 0x17, 0xc1, 0x93, 0x6c,
-	0xa6, 0xae, 0xb3, 0x8e, 0xda, 0xa6, 0x6a, 0x5b, 0x03, 0x36, 0x5d, 0xae,
-	0xb1, 0x0e, 0xe5, 0xfd, 0xc8, 0xa5, 0x99, 0x69, 0xd4, 0xaa, 0xe5, 0xda,
-	0x88, 0x56, 0x6e, 0xda, 0x5a, 0xd9, 0xa3, 0xbe, 0xed, 0xb2, 0x2e, 0x28,
-	0x1e, 0xa7, 0x65, 0xa9, 0xf9, 0x4b, 0xbf, 0xba, 0x6b, 0x13, 0xfa, 0xd0,
-	0xfd, 0x09, 0xca, 0xf7, 0xb3, 0xa4, 0x0b, 0x41, 0x9c, 0xfc, 0x4e, 0xc9,
-	0xc9, 0x21, 0x14, 0xbd, 0xc8, 0xad, 0x4e, 0x0d, 0x11, 0x3f, 0xe8, 0x48,
-	0xa5, 0x64, 0xd9, 0xe3, 0x1e, 0x67, 0x67, 0xc8, 0xcb, 0xf2, 0x71, 0x4b,
-	0x0e, 0x2b, 0xf9, 0xbd, 0xac, 0x6c, 0xbb, 0xbc, 0x62, 0xc8, 0x74, 0x72,
-	0xd0, 0x7a, 0x58, 0xb2, 0x57, 0x2f, 0x18, 0xd9, 0x67, 0xa6, 0x60, 0xd7,
-	0x4b, 0x8b, 0x86, 0xb8, 0xaa, 0xde, 0xa2, 0x8c, 0xb2, 0x0b, 0xb0, 0xfc,
-	0xf0, 0xec, 0x7b, 0x5b, 0xce, 0xde, 0x2d, 0x2b, 0x4f, 0xff, 0x26, 0x7c,
-	0xce, 0x01, 0xc8, 0xc2, 0xcc, 0x1c, 0x42, 0x5e, 0xf1, 0xb4, 0x0c, 0x5a,
-	0x55, 0xe4, 0xc9, 0xe0, 0x3b, 0xda, 0x01, 0x65, 0x03, 0x17, 0x74, 0x8c,
-	0x07, 0xc8, 0x27, 0x8e, 0xaf, 0x95, 0x0b, 0xca, 0x96, 0xd2, 0xea, 0xdd,
-	0x0e, 0xe0, 0x08, 0xde, 0x71, 0xfc, 0x19, 0xd9, 0xa1, 0xde, 0xdd, 0xa9,
-	0xde, 0x55, 0xe9, 0x2b, 0x94, 0xfc, 0xbe, 0x82, 0x3d, 0xc9, 0xe3, 0x68,
-	0xbe, 0x4b, 0x02, 0x5b, 0x8a, 0xf8, 0x6e, 0xc9, 0xc1, 0x46, 0x4a, 0xbe,
-	0x84, 0xfa, 0xe7, 0x8e, 0xc6, 0x80, 0x94, 0x20, 0xc7, 0xe9, 0xdc, 0x83,
-	0xbd, 0x3c, 0x5b, 0x71, 0x25, 0xfb, 0x8c, 0xe8, 0xa4, 0xf5, 0x4e, 0x39,
-	0xe4, 0x45, 0xf4, 0x74, 0x86, 0xf4, 0x4d, 0x86, 0xe3, 0x44, 0x48, 0x43,
-	0x2b, 0xbe, 0x4e, 0xe0, 0x42, 0xac, 0xcf, 0x79, 0x21, 0x1e, 0xfa, 0x11,
-	0xd0, 0x3a, 0x99, 0x96, 0x15, 0x8f, 0x74, 0x6c, 0x91, 0x6a, 0x8a, 0xfd,
-	0x03, 0xd0, 0x37, 0xe2, 0xd9, 0xc4, 0x7c, 0x66, 0x1d, 0x8f, 0x1f, 0x6c,
-	0x54, 0xc0, 0x63, 0xf2, 0x97, 0xeb, 0x10, 0x23, 0x3e, 0x47, 0xf9, 0xed,
-	0x46, 0x2e, 0x6f, 0x07, 0xba, 0x69, 0xad, 0xed, 0x59, 0x3a, 0xde, 0x0d,
-	0x59, 0x71, 0xdf, 0x0e, 0x99, 0x84, 0xdd, 0x17, 0xeb, 0xdc, 0x7f, 0x12,
-	0x7a, 0x74, 0x51, 0xed, 0x5f, 0x5a, 0xe9, 0x0f, 0xe1, 0x09, 0xdb, 0xbd,
-	0x01, 0xb6, 0x5d, 0xf6, 0x2e, 0x58, 0x1f, 0x01, 0xff, 0xbb, 0x80, 0xd7,
-	0xe5, 0x44, 0x8e, 0xf0, 0xc4, 0x83, 0x75, 0xf5, 0xd4, 0x27, 0xe0, 0x49,
-	0xaa, 0xba, 0xbe, 0x58, 0x6f, 0x97, 0xe2, 0x42, 0x84, 0x8b, 0x78, 0x3e,
-	0x40, 0xdd, 0x7b, 0xb7, 0xc2, 0x35, 0xad, 0x70, 0xe1, 0x7d, 0x9d, 0x3e,
-	0xe7, 0x26, 0xc0, 0xa3, 0x76, 0xb7, 0x41, 0x5b, 0xb2, 0x4b, 0xaa, 0xaa,
-	0x76, 0xef, 0x50, 0xbe, 0xa6, 0x9a, 0xdc, 0x8c, 0xf7, 0x3e, 0xf6, 0xdc,
-	0x8d, 0x7c, 0xa6, 0x1b, 0x73, 0x99, 0x0d, 0x73, 0x1b, 0xe9, 0x4f, 0x6c,
-	0xa0, 0xff, 0xbf, 0x7b, 0x19, 0x52, 0xe6, 0x72, 0xc1, 0xba, 0x12, 0xd6,
-	0xcd, 0x1e, 0x87, 0x4d, 0x30, 0x4f, 0x4f, 0x31, 0x36, 0x5f, 0xa3, 0x68,
-	0x99, 0x5d, 0xf9, 0x29, 0xd6, 0xf5, 0x03, 0x36, 0x1a, 0x07, 0x7c, 0x78,
-	0x0a, 0x78, 0x8e, 0xd7, 0xd5, 0x1d, 0x05, 0x64, 0xf0, 0xbe, 0x3a, 0x7b,
-	0xb5, 0xfe, 0x69, 0x3c, 0xbb, 0xa6, 0x85, 0x5f, 0xe4, 0x15, 0xe9, 0x25,
-	0xad, 0xbc, 0x2f, 0x82, 0xbd, 0x39, 0xd0, 0xe3, 0xa4, 0x21, 0xa5, 0x1c,
-	0xe2, 0xba, 0xc7, 0xbb, 0x57, 0xda, 0xe5, 0x40, 0x50, 0x23, 0xd8, 0x8c,
-	0xef, 0xa6, 0x3a, 0xfb, 0xa1, 0x15, 0xde, 0xbf, 0x66, 0x78, 0x47, 0x37,
-	0x8c, 0xda, 0x5b, 0x1e, 0x5a, 0xb1, 0xe5, 0x6b, 0x8d, 0x61, 0x79, 0xb8,
-	0x91, 0xb5, 0xee, 0x81, 0x0f, 0x28, 0xaf, 0xde, 0xcb, 0x6e, 0x4b, 0xd2,
-	0x7f, 0x99, 0xc8, 0x3d, 0xdb, 0xec, 0x20, 0x17, 0xa9, 0xb2, 0x36, 0x3b,
-	0x9e, 0xe5, 0x7d, 0x8d, 0x55, 0x97, 0x8d, 0xf9, 0xca, 0xff, 0x65, 0xae,
-	0xc2, 0xfd, 0xe9, 0xaf, 0x91, 0x9b, 0x78, 0xc8, 0x4d, 0x3c, 0xe4, 0x26,
-	0x1e, 0x72, 0x13, 0x0f, 0xb9, 0x89, 0x87, 0xdc, 0xc4, 0x43, 0x6e, 0xe2,
-	0x21, 0x37, 0x41, 0x1d, 0x10, 0xd4, 0x07, 0xe3, 0xc8, 0xb9, 0xe1, 0xbf,
-	0xbc, 0x5b, 0xc2, 0xdc, 0x22, 0x8a, 0xcd, 0x9c, 0x3b, 0xbf, 0xc9, 0x0d,
-	0xea, 0x2b, 0xe5, 0x13, 0x0a, 0xcd, 0x89, 0x30, 0x07, 0xe2, 0x9a, 0x28,
-	0x76, 0x73, 0x9d, 0x8c, 0xb9, 0xa8, 0x3d, 0x0b, 0x93, 0xcc, 0x91, 0x82,
-	0x98, 0x15, 0xe4, 0xe7, 0xaf, 0x22, 0x4f, 0xca, 0x20, 0x4f, 0x1a, 0x40,
-	0x4e, 0xc4, 0x7b, 0xea, 0xe8, 0x2e, 0xa9, 0xa0, 0x1d, 0xf4, 0xc6, 0xb5,
-	0x2f, 0x79, 0xcc, 0xdf, 0xed, 0x4c, 0x59, 0xd7, 0x8f, 0xf7, 0x89, 0x2f,
-	0xc5, 0xd1, 0xaf, 0x23, 0x57, 0xfe, 0x4b, 0x75, 0x6f, 0x36, 0x31, 0x44,
-	0x99, 0xdf, 0xf7, 0x31, 0xf9, 0x72, 0xc4, 0xdf, 0xe0, 0xbe, 0x4f, 0x5f,
-	0x22, 0xff, 0x44, 0x7a, 0xcf, 0x80, 0xe1, 0x67, 0x12, 0x92, 0x3c, 0xb9,
-	0x05, 0x73, 0x96, 0xf4, 0xa9, 0x3b, 0x23, 0x88, 0xf2, 0xcc, 0x7f, 0x40,
-	0x5e, 0xb6, 0xe8, 0x67, 0x78, 0xb3, 0x40, 0xbc, 0xf4, 0xaf, 0xf5, 0x99,
-	0x62, 0xbd, 0xae, 0x74, 0xea, 0x60, 0xa3, 0x84, 0x3c, 0xca, 0xe8, 0x93,
-	0x0e, 0x13, 0xb5, 0x54, 0x84, 0x9b, 0x38, 0xdf, 0x4c, 0xaa, 0x1a, 0xe7,
-	0xcc, 0xaa, 0x3c, 0x21, 0x6b, 0xee, 0x53, 0x9f, 0xa9, 0x2e, 0x64, 0xd3,
-	0xac, 0x71, 0x0b, 0x56, 0x7d, 0xe6, 0x49, 0xe0, 0x58, 0x46, 0x6e, 0x60,
-	0xa8, 0xbd, 0xeb, 0x33, 0xb3, 0x0b, 0xc1, 0xbd, 0x55, 0x40, 0x03, 0xe3,
-	0x55, 0x87, 0x18, 0x4b, 0xc1, 0xfd, 0x95, 0xae, 0x60, 0x09, 0x47, 0x78,
-	0x13, 0x70, 0x94, 0xdb, 0x30, 0x60, 0x29, 0x3b, 0xd2, 0x50, 0x9f, 0xa9,
-	0xd4, 0x5b, 0x69, 0x20, 0x1e, 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0x24, 0x45,
-	0x3f, 0xe9, 0xfb, 0xe5, 0xd1, 0x81, 0xb0, 0xae, 0x44, 0x1d, 0x79, 0xcc,
-	0x0c, 0xf4, 0x5c, 0x8d, 0xff, 0x58, 0xc5, 0xa9, 0x8c, 0xce, 0x79, 0x3e,
-	0xf1, 0x2e, 0xf7, 0x28, 0xe6, 0x30, 0x5e, 0x8e, 0xd6, 0xea, 0xe1, 0xda,
-	0xae, 0x16, 0x7e, 0xb6, 0x85, 0xfb, 0x91, 0x26, 0x9e, 0xf3, 0x15, 0xec,
-	0x45, 0xba, 0xb8, 0xc6, 0x04, 0x6d, 0x90, 0xa5, 0xf7, 0xbf, 0xe5, 0x7d,
-	0xeb, 0x99, 0xc8, 0x53, 0x13, 0x30, 0x5c, 0x4f, 0x1c, 0x11, 0x0c, 0x5e,
-	0x9c, 0x09, 0xe0, 0xf4, 0xd5, 0x7b, 0xbe, 0x4f, 0xda, 0xb7, 0x95, 0xd6,
-	0x68, 0xff, 0x08, 0xcf, 0x70, 0x20, 0xb7, 0x55, 0x78, 0xf5, 0x7f, 0x7f,
-	0xe1, 0x09, 0x5d, 0xfc, 0xd0, 0x7d, 0xe9, 0x70, 0x4b, 0x8d, 0x1c, 0xdd,
-	0x3b, 0xb0, 0xfe, 0x67, 0x3d, 0xcf, 0xef, 0x03, 0xad, 0xf5, 0x69, 0x29,
-	0x8c, 0x65, 0xdb, 0xa4, 0x60, 0xb2, 0x56, 0x19, 0x0f, 0xc7, 0x5b, 0x11,
-	0xdb, 0x38, 0xbe, 0x15, 0xfc, 0x85, 0x2e, 0x3b, 0x1d, 0x61, 0xad, 0x94,
-	0x0c, 0xbe, 0xeb, 0x0c, 0xd3, 0x8e, 0x58, 0x6b, 0x6e, 0x0e, 0xe7, 0x22,
-	0x3b, 0xa2, 0x1f, 0x36, 0xc3, 0x39, 0xfa, 0x5b, 0x1d, 0xf5, 0x12, 0xfb,
-	0xc0, 0xb3, 0xdc, 0x6a, 0x4b, 0xd1, 0x33, 0x29, 0xa7, 0x17, 0x23, 0xbf,
-	0x05, 0x9f, 0x32, 0x64, 0x86, 0xbe, 0xbf, 0x13, 0xbe, 0xaf, 0x5b, 0xf6,
-	0xc2, 0x67, 0xed, 0x83, 0xcf, 0xda, 0x8f, 0x1a, 0x75, 0x7c, 0xa5, 0xf5,
-	0x3e, 0x97, 0x75, 0x71, 0x55, 0x0e, 0x29, 0xf9, 0x57, 0x7c, 0xc3, 0xfe,
-	0x00, 0x3a, 0xb0, 0x53, 0xe5, 0x7b, 0x81, 0x4e, 0xc0, 0xdf, 0x3a, 0x49,
-	0xe8, 0xc4, 0xc6, 0x7b, 0xe3, 0x61, 0xd8, 0x46, 0x47, 0x41, 0xc5, 0x86,
-	0x95, 0x80, 0xf7, 0xd5, 0x7a, 0xc0, 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5,
-	0xd2, 0xb0, 0xa4, 0x82, 0x7d, 0x2b, 0xd8, 0xb7, 0x82, 0xda, 0x72, 0xb6,
-	0xd1, 0xfa, 0xed, 0xaa, 0x2b, 0xa4, 0x9d, 0xb0, 0x51, 0xdf, 0x6a, 0x39,
-	0x7f, 0xf4, 0x3c, 0x02, 0xfe, 0x3f, 0x02, 0xfe, 0x1f, 0x46, 0x4d, 0xf5,
-	0x00, 0x6a, 0xaa, 0xfb, 0x50, 0x53, 0x1d, 0x42, 0x4d, 0x35, 0x85, 0x9a,
-	0xea, 0x6e, 0xf8, 0x8f, 0x3b, 0xe1, 0x3f, 0x26, 0xe1, 0x3f, 0x26, 0xd4,
-	0x9d, 0xd1, 0x41, 0x6f, 0xe3, 0x1d, 0x4a, 0xb4, 0x17, 0xdb, 0x1b, 0x22,
-	0x50, 0x81, 0xf2, 0xb1, 0x71, 0xa9, 0x37, 0x59, 0x5b, 0x39, 0xea, 0x3e,
-	0x6c, 0xda, 0x99, 0xd4, 0xa6, 0x90, 0xbf, 0xdf, 0x33, 0xc2, 0x9a, 0x2b,
-	0xa9, 0x15, 0x55, 0xcd, 0x95, 0x7d, 0xc1, 0x45, 0x8a, 0x84, 0xdc, 0x0f,
-	0x67, 0xce, 0x9e, 0x2e, 0x1a, 0x51, 0xbd, 0xd3, 0xbb, 0x5a, 0xef, 0x2c,
-	0xcf, 0xb3, 0xde, 0x79, 0x75, 0xb5, 0xde, 0x59, 0x9e, 0x67, 0xbd, 0xf3,
-	0xca, 0xba, 0x7a, 0xe7, 0xca, 0xd3, 0x97, 0xd6, 0xd5, 0x3b, 0x57, 0x9e,
-	0x7e, 0x29, 0x1c, 0x4b, 0xa8, 0x0f, 0x21, 0xad, 0x96, 0x83, 0x67, 0x4f,
-	0x98, 0x73, 0x34, 0xfb, 0xd6, 0xff, 0xdf, 0x74, 0xca, 0x96, 0x35, 0xb1,
-	0xff, 0x68, 0x6b, 0x50, 0x23, 0xb5, 0xce, 0x77, 0xb7, 0xcc, 0x5f, 0x56,
-	0xdf, 0x4b, 0xcb, 0xb5, 0xcd, 0xef, 0xc2, 0x03, 0xcb, 0xca, 0x10, 0xf3,
-	0xbc, 0x0f, 0x7c, 0x7e, 0xf3, 0x73, 0xf5, 0x0e, 0xf5, 0xcd, 0xcd, 0x55,
-	0xf9, 0x36, 0xec, 0x7c, 0xf4, 0xd1, 0xad, 0x81, 0x2f, 0x60, 0x3f, 0xa5,
-	0x05, 0xfe, 0xfd, 0x01, 0xe0, 0x01, 0xaf, 0x3d, 0x53, 0xdd, 0x07, 0x05,
-	0xe7, 0x0d, 0xee, 0xc6, 0xcd, 0xfc, 0xe5, 0x19, 0xe6, 0xd6, 0x55, 0x85,
-	0x9b, 0xf5, 0x23, 0x6b, 0xce, 0x28, 0x06, 0x44, 0xb8, 0x5e, 0x4d, 0x05,
-	0x74, 0xbb, 0xa8, 0x1d, 0xb9, 0x26, 0x1a, 0xb7, 0xd6, 0x9a, 0x9d, 0xe1,
-	0xbd, 0xdb, 0xe5, 0x20, 0xaf, 0x52, 0xf8, 0xcc, 0x10, 0xdf, 0xcf, 0xfd,
-	0xc0, 0xf7, 0x10, 0xde, 0x6a, 0x81, 0x1f, 0x47, 0xae, 0xc7, 0x7b, 0x1a,
-	0xe6, 0x6c, 0xa6, 0xbc, 0x33, 0xdf, 0x25, 0xff, 0x79, 0xd4, 0xf7, 0x27,
-	0x9c, 0xec, 0xf0, 0x25, 0xd4, 0x1e, 0x27, 0x69, 0x27, 0xa3, 0xa4, 0x73,
-	0x30, 0x33, 0x2b, 0xa9, 0x3e, 0xd2, 0x72, 0x5e, 0x3f, 0xac, 0x7d, 0x98,
-	0x6e, 0x3d, 0xdc, 0xe7, 0x1f, 0x5b, 0xf6, 0xc9, 0xb4, 0xec, 0x53, 0xa0,
-	0xcd, 0xd6, 0xef, 0xc0, 0x99, 0x2b, 0xdb, 0xaf, 0xb7, 0x52, 0x61, 0x5d,
-	0xf6, 0xf0, 0xe8, 0x66, 0x59, 0xe8, 0xcf, 0x9e, 0x7d, 0x05, 0xf9, 0x7a,
-	0x79, 0x14, 0x73, 0xa9, 0x41, 0xbc, 0xe3, 0x7c, 0xb6, 0x8e, 0x5c, 0xf4,
-	0x6c, 0x5d, 0xb6, 0x01, 0x3e, 0x5b, 0x11, 0xe1, 0x3c, 0xfb, 0x8a, 0xb6,
-	0x7a, 0xe8, 0x03, 0xd2, 0x17, 0x70, 0xe6, 0x29, 0xd4, 0x5f, 0x87, 0x83,
-	0x7b, 0xb4, 0x70, 0x9f, 0x1b, 0xb5, 0x20, 0x6f, 0xce, 0x69, 0x95, 0xf0,
-	0x0e, 0xf0, 0x2b, 0xf0, 0x17, 0x86, 0x4e, 0xd8, 0x77, 0x80, 0x5b, 0x93,
-	0xa5, 0xa3, 0x86, 0xba, 0x3b, 0x2d, 0x8f, 0x52, 0xd6, 0x7c, 0x7e, 0x14,
-	0xef, 0xa2, 0x33, 0xfd, 0x4d, 0x78, 0xa6, 0xd1, 0xb0, 0x6e, 0x8f, 0xce,
-	0x94, 0x90, 0xd7, 0xe7, 0x2d, 0xc0, 0x8e, 0x80, 0x1f, 0x25, 0x59, 0x69,
-	0x66, 0x3e, 0x05, 0x4f, 0xad, 0x85, 0x37, 0xe6, 0x06, 0x19, 0x46, 0x75,
-	0x0f, 0x78, 0x30, 0x91, 0x86, 0x1d, 0xde, 0xd7, 0x17, 0xdd, 0xe9, 0x1a,
-	0xb6, 0xae, 0x05, 0x75, 0x3c, 0xe7, 0x07, 0x60, 0x8b, 0x19, 0xd8, 0x27,
-	0x73, 0xa6, 0x12, 0x6b, 0x15, 0xda, 0x93, 0xe5, 0x1a, 0x59, 0x6b, 0x52,
-	0x86, 0x51, 0xef, 0xf0, 0xfc, 0x79, 0x59, 0x6e, 0x46, 0x34, 0xe4, 0x60,
-	0x8f, 0x63, 0xf8, 0x8d, 0xe0, 0x9d, 0x83, 0x1f, 0x6b, 0xa5, 0x82, 0x7c,
-	0x55, 0xe5, 0xe2, 0xc8, 0xb5, 0x87, 0x48, 0xdf, 0x01, 0xac, 0xa7, 0x3e,
-	0x53, 0x4f, 0x0f, 0x88, 0xdb, 0x4f, 0x5f, 0x91, 0x06, 0x6e, 0xc0, 0x78,
-	0xaf, 0xc1, 0xd6, 0x07, 0xf0, 0xcc, 0x5a, 0x65, 0xf2, 0x56, 0xe1, 0xf7,
-	0x7d, 0x23, 0xc7, 0x6f, 0x11, 0xe3, 0xe1, 0x78, 0xd0, 0xfa, 0x1d, 0xea,
-	0x5e, 0xfa, 0x5a, 0x39, 0xbb, 0x18, 0xc5, 0xc1, 0x19, 0xd8, 0x20, 0xef,
-	0x68, 0xc7, 0xc1, 0x17, 0x8e, 0xb5, 0x30, 0x1e, 0x62, 0x7e, 0xf9, 0xaf,
-	0x70, 0xee, 0xbc, 0x9c, 0x44, 0xfd, 0x2f, 0xfd, 0x7c, 0x66, 0x80, 0x7f,
-	0x4b, 0xa8, 0xef, 0xeb, 0xe1, 0x0d, 0x9b, 0xfd, 0x71, 0xd0, 0x67, 0xb6,
-	0xc0, 0x13, 0x26, 0xac, 0x4f, 0x04, 0xf1, 0x38, 0xed, 0xdf, 0xaa, 0xe7,
-	0xef, 0x96, 0x3f, 0x50, 0x67, 0xca, 0xcb, 0xa1, 0x45, 0xdf, 0x77, 0x73,
-	0x83, 0xc3, 0xcb, 0x92, 0x1d, 0x7e, 0x52, 0x76, 0x5b, 0x7b, 0x59, 0x8f,
-	0x59, 0xc4, 0xe3, 0xdf, 0xda, 0x96, 0xf7, 0xfd, 0x13, 0xa0, 0xfd, 0x07,
-	0x6a, 0x9f, 0xbb, 0x41, 0x3f, 0x78, 0xa5, 0x6a, 0x12, 0xd2, 0x0a, 0xde,
-	0xa4, 0x48, 0x6f, 0xa7, 0x1c, 0x6a, 0x3e, 0x1f, 0xca, 0xe6, 0x11, 0x71,
-	0xbd, 0xb7, 0x0d, 0xde, 0x6f, 0x97, 0x9b, 0x8f, 0x86, 0xb4, 0xe5, 0x41,
-	0x2f, 0xf6, 0x6f, 0xfe, 0x43, 0x8a, 0xbe, 0x81, 0x32, 0x77, 0x91, 0x35,
-	0xba, 0xa3, 0xcf, 0x40, 0x07, 0x3f, 0xce, 0x0f, 0x24, 0x65, 0xbd, 0x1f,
-	0x20, 0x5c, 0xf2, 0x23, 0x74, 0x85, 0x74, 0x88, 0xf2, 0x9f, 0x2a, 0x6e,
-	0x29, 0x7c, 0xc6, 0x06, 0x5f, 0xf0, 0xa4, 0x7a, 0x9e, 0x37, 0xe8, 0x9b,
-	0x18, 0xff, 0xa8, 0xc3, 0xdd, 0xf0, 0x7f, 0xd0, 0x41, 0xd8, 0x71, 0x71,
-	0x91, 0xf7, 0x13, 0x43, 0xea, 0x4e, 0xab, 0x04, 0xd9, 0x2e, 0xf1, 0x3b,
-	0x63, 0x2a, 0xc8, 0x27, 0x83, 0xfa, 0x2b, 0x43, 0x5f, 0x88, 0xf6, 0xb8,
-	0xf2, 0x93, 0x25, 0xf5, 0x5d, 0x31, 0x89, 0x35, 0x3e, 0x9e, 0xad, 0x7f,
-	0x27, 0xf1, 0xa3, 0x42, 0xf0, 0x77, 0x12, 0xe1, 0x37, 0xde, 0x7a, 0x90,
-	0x47, 0x3c, 0xd8, 0x30, 0x65, 0xaa, 0x11, 0xfd, 0xdd, 0x04, 0xe5, 0x60,
-	0x4b, 0xb9, 0x11, 0xe5, 0x0e, 0x7e, 0x50, 0xd3, 0xac, 0x93, 0xe5, 0xe3,
-	0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4, 0x78, 0x39, 0x90, 0xdf, 0x92,
-	0xbe, 0x03, 0xf2, 0x03, 0xcf, 0x3d, 0x13, 0xb6, 0x94, 0x0e, 0xe3, 0xba,
-	0xc5, 0x1a, 0x33, 0xac, 0x7b, 0xb7, 0x4b, 0x75, 0x92, 0xef, 0x13, 0xf2,
-	0xda, 0xfc, 0x40, 0x70, 0x4f, 0x24, 0x89, 0xf0, 0x3d, 0xc7, 0x49, 0x29,
-	0xab, 0xf7, 0x77, 0x86, 0xf8, 0x50, 0xa7, 0xdd, 0x19, 0x8d, 0xd3, 0x90,
-	0x63, 0x00, 0x37, 0x8d, 0x58, 0xf6, 0x55, 0xc4, 0xb1, 0x69, 0xf0, 0xbd,
-	0x38, 0x51, 0x91, 0x6b, 0x6d, 0x4b, 0xc5, 0x7d, 0x37, 0x49, 0x1d, 0xa3,
-	0x7e, 0x11, 0xa6, 0x07, 0xb9, 0x2a, 0xce, 0x3b, 0x2a, 0x53, 0x46, 0xfe,
-	0xdd, 0xdb, 0xca, 0xb5, 0xac, 0x55, 0x90, 0xf7, 0x7d, 0xd7, 0xe4, 0xf8,
-	0xfc, 0x6d, 0x0f, 0x06, 0x77, 0xfe, 0xba, 0x9e, 0xbf, 0x78, 0x5b, 0x39,
-	0xe8, 0xe3, 0xcc, 0xef, 0x86, 0x7d, 0xc2, 0x19, 0xea, 0x7b, 0xec, 0x4f,
-	0x6e, 0x32, 0xe5, 0xc2, 0x4d, 0xbe, 0x7f, 0x0f, 0xbf, 0x09, 0x85, 0x75,
-	0xac, 0xa5, 0xea, 0xd8, 0x0e, 0x95, 0x8f, 0xb8, 0xa3, 0x19, 0xad, 0x04,
-	0xdb, 0x3d, 0xe9, 0xa1, 0xe6, 0xd1, 0xb3, 0x63, 0xe7, 0x75, 0x0b, 0xf1,
-	0x37, 0x9b, 0x39, 0x2e, 0xb9, 0x3e, 0x7e, 0x63, 0x9e, 0x73, 0xb8, 0x66,
-	0x5b, 0x70, 0xef, 0x75, 0x83, 0xab, 0x7c, 0xae, 0x48, 0x18, 0x87, 0x6e,
-	0x68, 0xb5, 0x8f, 0xd6, 0x3c, 0x93, 0x76, 0x21, 0x53, 0x26, 0xe8, 0xa9,
-	0xd6, 0xa2, 0x9c, 0x8d, 0x7f, 0x0f, 0x70, 0xfe, 0xb6, 0xa7, 0x1a, 0x17,
-	0x6f, 0x9b, 0x85, 0x7c, 0x78, 0xa6, 0xd9, 0x46, 0xa4, 0x7f, 0x51, 0xdd,
-	0xc0, 0x3e, 0xe2, 0xbf, 0x87, 0xf8, 0xef, 0x21, 0xfe, 0x7b, 0x88, 0xff,
-	0x1e, 0xe2, 0xbf, 0x87, 0xf8, 0x0f, 0x1e, 0x3e, 0x07, 0x7d, 0x79, 0xd6,
-	0x9b, 0x08, 0x73, 0xb6, 0xc7, 0x56, 0x73, 0x36, 0xfe, 0xcd, 0xcb, 0xb9,
-	0xa6, 0xa2, 0xa5, 0x52, 0x91, 0x20, 0xe7, 0x15, 0x9d, 0xf9, 0x4d, 0x94,
-	0xf3, 0x7e, 0xf4, 0xf7, 0x90, 0x00, 0x8e, 0xf9, 0x1e, 0xe1, 0x2a, 0x9a,
-	0x6e, 0x13, 0x2e, 0xc8, 0xf9, 0x58, 0x67, 0xad, 0x87, 0xe1, 0x77, 0x37,
-	0xfa, 0xb6, 0xe0, 0x9b, 0x4f, 0xf0, 0x7d, 0xa9, 0x76, 0x87, 0x8b, 0x58,
-	0x5c, 0x6e, 0xa8, 0x78, 0x8c, 0x71, 0xe3, 0x0e, 0xfe, 0xad, 0x02, 0x64,
-	0xc0, 0x77, 0x5f, 0x66, 0x6d, 0x51, 0x6e, 0x20, 0x2f, 0x5a, 0x8e, 0x72,
-	0x21, 0xc0, 0x79, 0x6f, 0x6a, 0xa5, 0x05, 0xca, 0x59, 0x97, 0xd9, 0x14,
-	0x98, 0x62, 0xb7, 0xe6, 0x78, 0x97, 0x54, 0xbd, 0x74, 0xb6, 0x49, 0x7a,
-	0x46, 0x40, 0x5b, 0x74, 0x8f, 0x2c, 0x62, 0xcc, 0xa7, 0x44, 0x9f, 0x47,
-	0x7e, 0x6b, 0x0f, 0xa9, 0xbf, 0x6f, 0xe8, 0xc5, 0x3e, 0xfa, 0xfc, 0x8e,
-	0x96, 0x7b, 0x5a, 0x29, 0x04, 0x3e, 0x9b, 0xb1, 0x87, 0xe7, 0x48, 0xc1,
-	0x76, 0xdd, 0x6d, 0x38, 0x1b, 0xe4, 0xfa, 0xaf, 0x5b, 0x55, 0x0e, 0x0e,
-	0x3f, 0x7a, 0x62, 0xa8, 0xbf, 0x5f, 0xba, 0xb7, 0xcb, 0xc9, 0x21, 0xd6,
-	0x6b, 0x9b, 0x81, 0x8f, 0x6b, 0x79, 0xff, 0xb4, 0x5d, 0x4e, 0x2d, 0xc2,
-	0xcf, 0x2e, 0x66, 0x1d, 0xea, 0xf2, 0xd2, 0x50, 0x0a, 0xfe, 0xf9, 0xe6,
-	0x7e, 0xc6, 0xe7, 0xe5, 0x26, 0x75, 0xa5, 0x17, 0xf0, 0x03, 0xd0, 0xcb,
-	0x4d, 0xb0, 0x27, 0x1d, 0xfb, 0x47, 0xb8, 0xff, 0x45, 0xe1, 0xee, 0xb5,
-	0x9d, 0x6d, 0x4a, 0x37, 0xf4, 0xac, 0x95, 0xd1, 0x41, 0xfb, 0xff, 0x14,
-	0x6e, 0x6d, 0x31, 0x71, 0x5c, 0x67, 0xf8, 0x3f, 0xb3, 0xdc, 0x8c, 0xd7,
-	0x30, 0x86, 0xf5, 0xb2, 0x58, 0xae, 0xba, 0x03, 0x63, 0x33, 0xd1, 0x62,
-	0x65, 0xb0, 0xec, 0x16, 0x55, 0x96, 0xba, 0xda, 0x05, 0x42, 0xe2, 0x3a,
-	0xdd, 0x24, 0xb4, 0x72, 0xd5, 0x2a, 0x42, 0x60, 0x37, 0x8e, 0xfa, 0xd2,
-	0x46, 0x55, 0xdb, 0x37, 0xaf, 0x16, 0xec, 0x38, 0xcd, 0xac, 0x17, 0x37,
-	0x38, 0xf4, 0x71, 0xb3, 0x2c, 0x0e, 0x90, 0x75, 0x56, 0x6e, 0xf2, 0x90,
-	0x3e, 0x19, 0x6d, 0xa2, 0x24, 0x55, 0xa5, 0xbc, 0x54, 0x7d, 0xab, 0x5a,
-	0x0b, 0x27, 0xc4, 0x0f, 0xa9, 0xad, 0xf6, 0xa5, 0x77, 0x4d, 0xbf, 0xef,
-	0xcc, 0x2c, 0xc6, 0xa4, 0x51, 0x91, 0x56, 0x73, 0xe6, 0xcc, 0xb9, 0x9f,
-	0xff, 0xf2, 0xfd, 0x17, 0x3e, 0x67, 0x67, 0xba, 0xc2, 0xbd, 0xcd, 0x95,
-	0x76, 0xc6, 0xfe, 0xb6, 0xd4, 0xcc, 0x02, 0xf3, 0x1a, 0x86, 0x64, 0xdc,
-	0x64, 0xae, 0xcf, 0x96, 0x3a, 0x57, 0x66, 0x1b, 0x1b, 0x65, 0xda, 0xe4,
-	0x4b, 0x6a, 0xa6, 0xdc, 0x23, 0x17, 0x41, 0xc7, 0x85, 0xe1, 0xd6, 0xd0,
-	0xf7, 0xda, 0x19, 0xf2, 0x73, 0x77, 0x3c, 0xd4, 0x57, 0x1a, 0x57, 0x16,
-	0x34, 0xb6, 0xee, 0xde, 0xf5, 0xed, 0x49, 0xac, 0x29, 0x41, 0x5f, 0x79,
-	0x5c, 0xcb, 0x26, 0x83, 0xef, 0x7d, 0xbb, 0xde, 0xe3, 0xbb, 0xde, 0x0f,
-	0xfc, 0x8f, 0xf6, 0x2c, 0xef, 0xa6, 0x07, 0xae, 0xd3, 0x1a, 0xe5, 0x2c,
-	0x05, 0xcf, 0x36, 0x66, 0x3d, 0x2b, 0x4d, 0x5c, 0x90, 0x15, 0x5f, 0x65,
-	0xdd, 0x36, 0xc8, 0xbb, 0x36, 0x99, 0x5f, 0x04, 0xcd, 0x63, 0x1f, 0xed,
-	0x36, 0x63, 0xe4, 0x43, 0x71, 0xf2, 0x4c, 0x07, 0xae, 0xc1, 0xb0, 0x07,
-	0x13, 0x68, 0xe7, 0x3f, 0xef, 0xa6, 0xcc, 0xb3, 0xda, 0x97, 0x43, 0x3c,
-	0xe3, 0xab, 0x82, 0xce, 0xf7, 0x60, 0x9b, 0x16, 0xb9, 0x63, 0x67, 0x7a,
-	0xc2, 0x7c, 0x20, 0xd8, 0xbe, 0x5f, 0x8d, 0x13, 0x6b, 0x3c, 0xe7, 0x6e,
-	0xd7, 0x99, 0x9b, 0xc2, 0x1c, 0x2b, 0x10, 0xcd, 0x53, 0x22, 0xe5, 0xaa,
-	0xc8, 0xeb, 0xf8, 0xfd, 0xa6, 0x1a, 0xc6, 0x4f, 0x14, 0xed, 0xee, 0x93,
-	0xb2, 0x5e, 0xfa, 0x9a, 0xd4, 0xa0, 0x7f, 0xd6, 0x5c, 0xdf, 0xbf, 0xeb,
-	0x26, 0xf5, 0x99, 0xbf, 0xe8, 0x29, 0x19, 0x18, 0xa1, 0x7e, 0x6b, 0x93,
-	0x97, 0x17, 0x5b, 0x64, 0xc3, 0xb4, 0xcc, 0xbb, 0x44, 0x01, 0x5e, 0x42,
-	0x26, 0x63, 0x11, 0x8d, 0x51, 0xe5, 0x5b, 0x22, 0x5b, 0xf8, 0xb6, 0xb5,
-	0xf8, 0x4c, 0x9c, 0xfe, 0x97, 0x4f, 0x16, 0xf9, 0x6e, 0xe0, 0x69, 0x48,
-	0xc3, 0x8e, 0x00, 0xcb, 0x42, 0x08, 0x99, 0x3c, 0x77, 0xee, 0xf7, 0xbb,
-	0x5c, 0x1b, 0xea, 0x68, 0xcf, 0xb6, 0x49, 0xe1, 0x30, 0x64, 0xa2, 0x1a,
-	0xd4, 0x39, 0x47, 0x8d, 0x98, 0x96, 0xd1, 0x91, 0x0a, 0x7d, 0xf8, 0xe6,
-	0x5e, 0x2d, 0xaf, 0x33, 0x37, 0x7e, 0xa4, 0xf7, 0x82, 0x72, 0xbe, 0xe2,
-	0x92, 0x56, 0x4d, 0x59, 0x03, 0xaf, 0xad, 0xd6, 0x5f, 0xed, 0xe3, 0x5d,
-	0xad, 0xd7, 0x5f, 0x88, 0x07, 0xf6, 0x1a, 0xeb, 0x7e, 0x1c, 0x0f, 0xea,
-	0x92, 0xa1, 0xfd, 0x45, 0x3b, 0xad, 0x8c, 0xbd, 0xbd, 0x20, 0xf5, 0xa5,
-	0x9f, 0xc9, 0x3b, 0xa5, 0x9f, 0xc8, 0xaf, 0x97, 0xce, 0x00, 0x7f, 0x58,
-	0xe5, 0x3c, 0xf4, 0xc9, 0xcd, 0xba, 0xef, 0xdf, 0x74, 0xa7, 0x60, 0x2b,
-	0xf8, 0xfe, 0xef, 0xdc, 0x0d, 0x19, 0x38, 0xf6, 0x3d, 0xec, 0x39, 0x07,
-	0x1e, 0xa2, 0x2c, 0x9c, 0x04, 0xbd, 0xb9, 0x7d, 0xd2, 0x19, 0xd5, 0x74,
-	0x32, 0x78, 0xac, 0x15, 0x7b, 0x30, 0x42, 0x4c, 0xce, 0xbd, 0x8c, 0xf4,
-	0x91, 0x66, 0x8c, 0x7a, 0x09, 0xf3, 0xb7, 0x82, 0x2f, 0xf6, 0xe2, 0xa7,
-	0xe4, 0xee, 0x08, 0xd6, 0x3a, 0x42, 0xda, 0x6b, 0x95, 0x81, 0x47, 0xb1,
-	0x8f, 0x5c, 0x8b, 0xdc, 0xf3, 0x7e, 0x19, 0xa7, 0x6f, 0xef, 0x9e, 0xc7,
-	0xb2, 0xf1, 0x95, 0x2e, 0xf1, 0xa5, 0x05, 0xba, 0x7c, 0xfe, 0x78, 0x80,
-	0x9b, 0xde, 0x55, 0x43, 0x68, 0x6f, 0xe7, 0xdf, 0x53, 0xc4, 0x79, 0x79,
-	0xbf, 0x15, 0xb8, 0x7c, 0x1c, 0x78, 0x28, 0x53, 0xbf, 0x20, 0x8d, 0x91,
-	0x28, 0xda, 0x10, 0xaf, 0x68, 0x59, 0x22, 0x59, 0x8f, 0x39, 0x5a, 0xcc,
-	0x97, 0xc2, 0x1a, 0xa7, 0x74, 0x2e, 0x57, 0x1f, 0xcf, 0x9c, 0x58, 0x3e,
-	0xa8, 0xb3, 0x41, 0x23, 0xac, 0x23, 0x7d, 0xa7, 0x35, 0xa6, 0x82, 0x0e,
-	0xc5, 0x78, 0xc3, 0x92, 0xd1, 0xe5, 0x2e, 0x8c, 0x77, 0x41, 0x32, 0x6e,
-	0x73, 0xcc, 0x51, 0xb4, 0xa1, 0x9c, 0x19, 0x05, 0x96, 0xf8, 0x58, 0x8d,
-	0x2d, 0xc6, 0xa0, 0xcb, 0xe3, 0x32, 0x66, 0xee, 0xd9, 0xb1, 0xc7, 0xbc,
-	0xb6, 0x15, 0x0c, 0x63, 0x38, 0x5c, 0x53, 0xd7, 0x8e, 0x35, 0xb1, 0x3f,
-	0x7e, 0xb0, 0x93, 0x33, 0x8b, 0x0b, 0x90, 0x53, 0x0b, 0x1f, 0x66, 0xdc,
-	0x67, 0x25, 0x1b, 0x6b, 0xd3, 0xb6, 0x4d, 0x05, 0xf7, 0x92, 0xf5, 0xe8,
-	0xd3, 0xfa, 0x0e, 0xe4, 0xd0, 0x9e, 0xb0, 0x8e, 0x6d, 0xc5, 0xc8, 0xe0,
-	0xec, 0x03, 0x1b, 0x97, 0x75, 0x5f, 0x96, 0xcc, 0x42, 0x4e, 0x26, 0x74,
-	0x3f, 0x9e, 0xe1, 0x41, 0x8d, 0x43, 0xc8, 0xab, 0x03, 0xbd, 0x38, 0xcb,
-	0xd4, 0x03, 0x7b, 0x38, 0xd9, 0x4b, 0x2e, 0xfa, 0x4f, 0xc8, 0xb3, 0xf8,
-	0xd6, 0xcb, 0x3b, 0x6a, 0x93, 0x81, 0x67, 0xa0, 0x2f, 0xbd, 0x66, 0x7d,
-	0x54, 0x3e, 0xf3, 0xfc, 0x38, 0x63, 0x2e, 0x7f, 0xf6, 0x4c, 0xf9, 0xc4,
-	0xd3, 0xb1, 0xd8, 0xe9, 0x88, 0x58, 0xe7, 0x03, 0x5b, 0xfd, 0xf0, 0xf4,
-	0xbc, 0xe2, 0xf7, 0xc3, 0xe7, 0x57, 0x54, 0x07, 0xda, 0x46, 0xd1, 0x8e,
-	0xeb, 0x30, 0x65, 0xdc, 0xfb, 0xab, 0x3f, 0x73, 0xc4, 0xf7, 0x27, 0x74,
-	0x4e, 0x58, 0xca, 0x9c, 0x57, 0x4d, 0x7c, 0xee, 0x88, 0x17, 0x6b, 0xc7,
-	0x5c, 0x29, 0x73, 0x45, 0x1d, 0xc6, 0x7a, 0x58, 0xee, 0x25, 0x4f, 0x24,
-	0x36, 0x84, 0xe3, 0x5b, 0x93, 0xcb, 0x2a, 0x95, 0x1c, 0x54, 0x56, 0xba,
-	0x80, 0x5f, 0x8b, 0xd2, 0x71, 0xcc, 0x44, 0x52, 0x81, 0x77, 0xb1, 0x27,
-	0xfb, 0xa8, 0xef, 0x4f, 0xda, 0xac, 0x4f, 0x99, 0x51, 0x45, 0xdf, 0x4b,
-	0xa7, 0x8e, 0x77, 0x5e, 0x3e, 0x90, 0x32, 0x8f, 0xaa, 0xfd, 0xe1, 0xfb,
-	0x28, 0x64, 0xe6, 0xf6, 0x78, 0x67, 0x96, 0x95, 0x29, 0x2f, 0x79, 0xa9,
-	0xe4, 0xac, 0xb2, 0x72, 0x18, 0x33, 0x37, 0xa6, 0x28, 0x37, 0x52, 0x66,
-	0xa7, 0xa2, 0x7f, 0xb4, 0x5d, 0xef, 0x7b, 0x12, 0xfd, 0x53, 0xaa, 0x25,
-	0x5c, 0x0f, 0xef, 0xeb, 0x4a, 0x5f, 0xc0, 0x33, 0x94, 0x39, 0xfd, 0xc6,
-	0xcc, 0x02, 0xf3, 0xcb, 0x74, 0x5e, 0x43, 0x7a, 0xe0, 0x18, 0xdf, 0x0d,
-	0xb9, 0x7f, 0xe2, 0x6f, 0xa8, 0x43, 0xb9, 0xcc, 0x3a, 0x27, 0xe4, 0xb7,
-	0x23, 0x1a, 0x3f, 0xdf, 0x3f, 0x91, 0xd7, 0xb9, 0x8b, 0x0d, 0x35, 0x10,
-	0xee, 0x7b, 0xfb, 0xce, 0x92, 0x19, 0xf7, 0x4b, 0x1c, 0x67, 0x21, 0x72,
-	0xb2, 0x5d, 0x98, 0x23, 0x3a, 0x5e, 0x6a, 0xd2, 0x06, 0x7d, 0x03, 0xcc,
-	0x15, 0x68, 0xc6, 0xdd, 0x2f, 0x88, 0x71, 0xac, 0x63, 0x07, 0x9d, 0x00,
-	0x77, 0x02, 0xaf, 0x56, 0x31, 0x4e, 0x61, 0x51, 0xf2, 0x41, 0x7f, 0xe9,
-	0x60, 0x4e, 0x6a, 0xa1, 0xfa, 0x45, 0x63, 0x04, 0x3a, 0x70, 0x1c, 0xef,
-	0xf7, 0x4f, 0x90, 0x3e, 0x79, 0x36, 0x49, 0x35, 0xbe, 0xc4, 0xf5, 0x1c,
-	0x94, 0x89, 0x45, 0x60, 0x23, 0xfc, 0xe6, 0x17, 0x83, 0x7b, 0xbb, 0x0e,
-	0x9c, 0x3d, 0xe1, 0x99, 0x9a, 0x5f, 0x67, 0x5d, 0xc6, 0x4f, 0xc0, 0x2b,
-	0x3a, 0x8f, 0x8a, 0x7d, 0x99, 0x4b, 0x78, 0x88, 0xfa, 0xd1, 0x6d, 0x48,
-	0x0c, 0x6d, 0x89, 0x59, 0x59, 0x6f, 0x8d, 0x26, 0x23, 0xdd, 0x32, 0x0f,
-	0x79, 0x57, 0x81, 0xee, 0x2c, 0x5c, 0x89, 0xca, 0xac, 0xa7, 0xe3, 0xd9,
-	0xc9, 0x8f, 0x95, 0x2b, 0xb5, 0xfa, 0x71, 0xb9, 0x51, 0x77, 0xf4, 0x37,
-	0xea, 0xb5, 0xc2, 0xab, 0x86, 0x7c, 0xff, 0x88, 0xce, 0xa5, 0x73, 0x2a,
-	0xd2, 0xd9, 0x4f, 0xcc, 0xb3, 0xa2, 0xf3, 0xea, 0x20, 0x3b, 0x80, 0x39,
-	0xde, 0x06, 0xe6, 0x78, 0x0b, 0x98, 0xe3, 0x57, 0xc0, 0xd8, 0x37, 0x4b,
-	0x93, 0xa1, 0xfc, 0x9f, 0x86, 0x1c, 0xa2, 0xae, 0xb6, 0xce, 0xe0, 0x4e,
-	0xa7, 0xf3, 0xa0, 0xc1, 0xdb, 0xb0, 0x3f, 0xd6, 0x4b, 0x19, 0x59, 0x5d,
-	0x9a, 0x90, 0xb5, 0xa5, 0x20, 0x0f, 0xf9, 0x03, 0xe6, 0x7d, 0x8d, 0xf0,
-	0x9e, 0x1c, 0xc8, 0xa1, 0x3d, 0x32, 0x70, 0x94, 0xf2, 0xa3, 0x43, 0x96,
-	0x8b, 0xab, 0x5a, 0x0e, 0x2d, 0x17, 0x59, 0x8e, 0x88, 0xce, 0x21, 0x9b,
-	0xda, 0x90, 0x8a, 0x5b, 0x47, 0xfd, 0x3e, 0xed, 0x0f, 0x0a, 0xfc, 0xf3,
-	0x94, 0x97, 0x7f, 0x0a, 0xef, 0x5e, 0xe9, 0xdc, 0xba, 0x19, 0xb3, 0x1b,
-	0xed, 0x9a, 0xb2, 0x6b, 0x30, 0x88, 0xb9, 0xab, 0xdb, 0x68, 0x83, 0x39,
-	0x80, 0x19, 0xaf, 0x43, 0x87, 0x34, 0x9c, 0x6e, 0x8d, 0xfd, 0x1a, 0xce,
-	0x21, 0x9d, 0x77, 0xcb, 0x71, 0x0a, 0x45, 0x5b, 0xe6, 0x8a, 0x56, 0x32,
-	0x0f, 0xfa, 0xbb, 0x01, 0xbb, 0x6d, 0x15, 0x77, 0xb0, 0x86, 0x33, 0x58,
-	0xaf, 0x53, 0xcf, 0x6f, 0x6a, 0xd9, 0xbb, 0x5c, 0xff, 0x23, 0xc6, 0xb1,
-	0xce, 0xa4, 0xe5, 0x0f, 0x7d, 0x94, 0x81, 0xf4, 0x4d, 0x65, 0x75, 0xff,
-	0xa0, 0xdf, 0x2a, 0xda, 0xae, 0xd5, 0x29, 0x8f, 0x45, 0x2e, 0x79, 0x36,
-	0x74, 0xc9, 0xcb, 0x09, 0x62, 0x80, 0xb2, 0x6a, 0xf6, 0xf3, 0xc3, 0x35,
-	0xfb, 0xfe, 0x5e, 0x9b, 0xeb, 0x72, 0x42, 0xb9, 0x4d, 0xdd, 0xbf, 0xa1,
-	0xb1, 0x8d, 0x57, 0x7a, 0x56, 0xde, 0xc4, 0x7d, 0x07, 0x18, 0x27, 0x27,
-	0x6f, 0x00, 0xe3, 0xd5, 0x4b, 0xcd, 0xbc, 0xed, 0x93, 0x38, 0xa7, 0x92,
-	0x9a, 0xbb, 0xda, 0x29, 0x97, 0xaf, 0x15, 0xd4, 0x4b, 0xd7, 0x3c, 0xf5,
-	0xf3, 0xab, 0x45, 0x55, 0xb8, 0xea, 0xfb, 0xff, 0x70, 0x67, 0xe4, 0x9d,
-	0x25, 0x5f, 0x4e, 0xbb, 0x46, 0x7f, 0x44, 0x9a, 0xf9, 0x74, 0xbe, 0xdf,
-	0x01, 0xd9, 0xbc, 0x7e, 0xc0, 0xf7, 0x1f, 0x19, 0x19, 0x11, 0xe7, 0x00,
-	0x31, 0xca, 0x70, 0x82, 0x39, 0xae, 0x94, 0x39, 0x19, 0xdb, 0x3e, 0x5f,
-	0x51, 0x0a, 0xf2, 0xad, 0x3b, 0xc0, 0x2f, 0x8f, 0xee, 0x0b, 0xe3, 0x26,
-	0x3f, 0x7c, 0x9e, 0x7e, 0xe5, 0xc4, 0xe7, 0xfc, 0xca, 0xa6, 0x9c, 0x2d,
-	0xf6, 0xa2, 0x7f, 0x4c, 0x7e, 0x50, 0x8c, 0xee, 0x2a, 0x9b, 0x78, 0x3a,
-	0x46, 0xa1, 0x78, 0xcf, 0x1f, 0xd4, 0xf1, 0x03, 0x60, 0x12, 0xd3, 0xf7,
-	0x67, 0x5d, 0xce, 0xd7, 0x8d, 0xf9, 0x36, 0xcc, 0x7d, 0xd0, 0xff, 0xa7,
-	0xb5, 0x7e, 0x2e, 0x2b, 0xd8, 0xc1, 0xe0, 0xef, 0x98, 0x8c, 0x15, 0xa1,
-	0xe3, 0x15, 0xf3, 0x4c, 0x89, 0x15, 0xac, 0xc4, 0x2c, 0x64, 0xc7, 0x0c,
-	0xe4, 0xcd, 0x29, 0x1d, 0x67, 0xed, 0xd5, 0xb2, 0x67, 0x8e, 0xe5, 0x9c,
-	0xa4, 0x2b, 0x6e, 0x8f, 0x3e, 0xbf, 0xcd, 0x1b, 0x2f, 0x26, 0x82, 0x3b,
-	0x07, 0x1f, 0xe7, 0x94, 0xb4, 0xc1, 0x1e, 0xca, 0xae, 0x4c, 0x81, 0x27,
-	0x12, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xe8, 0xef, 0x86, 0xf6, 0x29,
-	0x06, 0xb1, 0x8b, 0x86, 0xc9, 0x76, 0xa7, 0xd0, 0xaf, 0x5d, 0x32, 0x57,
-	0xdb, 0xb4, 0x5c, 0x7d, 0xb8, 0x2e, 0x0d, 0x1c, 0xf2, 0x04, 0xca, 0x11,
-	0xd4, 0x25, 0xc3, 0xb2, 0x81, 0xf2, 0x34, 0xca, 0x2d, 0x78, 0xb2, 0xcd,
-	0x61, 0xe0, 0x0a, 0x3c, 0x5f, 0xc3, 0x78, 0x23, 0x58, 0x73, 0xce, 0x94,
-	0x8f, 0x4e, 0x50, 0x97, 0x38, 0x06, 0x73, 0x91, 0x67, 0x6d, 0x3c, 0x6b,
-	0x45, 0x95, 0x5d, 0x60, 0x19, 0xcf, 0x72, 0xf0, 0xfd, 0x21, 0x99, 0x84,
-	0x3e, 0x99, 0x6b, 0x81, 0x4c, 0xfa, 0x68, 0x5b, 0x26, 0xb1, 0xae, 0x5d,
-	0xc6, 0xae, 0x92, 0xd7, 0x4d, 0xd0, 0x5b, 0xa7, 0x64, 0xaf, 0xc5, 0x34,
-	0x1e, 0xad, 0x80, 0x16, 0xaf, 0x83, 0xae, 0x96, 0x41, 0x53, 0x99, 0xa2,
-	0x35, 0x3a, 0xad, 0x92, 0xda, 0x2f, 0xf0, 0x38, 0xe8, 0xb5, 0xe3, 0x0a,
-	0xb1, 0x28, 0x79, 0xd9, 0x01, 0xed, 0x89, 0xdf, 0x61, 0xdb, 0x93, 0x8e,
-	0xb2, 0x41, 0x83, 0xa0, 0xcb, 0x62, 0xc0, 0xd3, 0xef, 0x29, 0x2d, 0x57,
-	0x47, 0xef, 0x48, 0x2a, 0x7d, 0x47, 0x2c, 0xc8, 0x02, 0xcb, 0xfd, 0x50,
-	0x5c, 0x8c, 0x79, 0x5c, 0x5e, 0xc7, 0x3c, 0x06, 0xf8, 0xfb, 0xc8, 0x90,
-	0xe6, 0xef, 0x51, 0x89, 0xec, 0xe6, 0x71, 0xd0, 0x1b, 0x64, 0x50, 0xc0,
-	0xd3, 0xe9, 0x90, 0x46, 0x9f, 0x06, 0xff, 0x5a, 0xb0, 0xca, 0x92, 0x32,
-	0x0f, 0xfe, 0xbf, 0x8e, 0xef, 0xb7, 0xea, 0x9f, 0xaa, 0xb9, 0x05, 0x15,
-	0xe6, 0xb2, 0x7c, 0x1b, 0x38, 0xf9, 0xf7, 0x38, 0xbb, 0x2e, 0x8d, 0xdd,
-	0x07, 0x46, 0x18, 0x4b, 0xfb, 0xb7, 0xba, 0x6c, 0x1f, 0x95, 0xcd, 0xe1,
-	0xe3, 0x28, 0xef, 0xc3, 0xd3, 0xc0, 0x39, 0x44, 0x75, 0x2c, 0x7c, 0xd9,
-	0x1b, 0x36, 0x0a, 0x3a, 0xef, 0xe0, 0x98, 0xce, 0xcf, 0x37, 0xec, 0x03,
-	0xf8, 0x4e, 0xbf, 0x0c, 0xf7, 0x06, 0xcc, 0xa4, 0x12, 0x3a, 0xc7, 0xb4,
-	0x02, 0x2c, 0xb1, 0x82, 0xf1, 0xde, 0xa7, 0x5f, 0xaf, 0x06, 0x1e, 0x1e,
-	0xfe, 0xa7, 0x9f, 0x8e, 0x31, 0x27, 0x7d, 0x33, 0x11, 0xe8, 0xbf, 0xcf,
-	0xfc, 0x4d, 0x7b, 0x6e, 0xd4, 0xc0, 0xcb, 0x6d, 0x33, 0x86, 0xb6, 0xd0,
-	0x65, 0xd0, 0x45, 0x65, 0x4d, 0xbf, 0x6c, 0x17, 0xf4, 0x2d, 0xd4, 0x52,
-	0xe6, 0x07, 0x12, 0xf4, 0x9d, 0xb7, 0xa9, 0x77, 0xda, 0x21, 0x5f, 0x92,
-	0x1a, 0x57, 0xbe, 0x6f, 0xe7, 0x21, 0x15, 0xac, 0xe4, 0x24, 0x68, 0xb4,
-	0x4d, 0x2c, 0x67, 0x5c, 0x1e, 0xcc, 0x3b, 0xab, 0xfb, 0xb2, 0x6d, 0xb3,
-	0x6f, 0x73, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0xa7, 0x36, 0x35,
-	0x8d, 0x36, 0x6a, 0xed, 0xfd, 0x01, 0x8d, 0x36, 0xf7, 0x11, 0xfb, 0x3f,
-	0xfb, 0x20, 0x9d, 0x0c, 0x1b, 0x41, 0x0e, 0x06, 0x9e, 0x35, 0x9e, 0xe7,
-	0xa7, 0xc0, 0xf7, 0x3b, 0xe9, 0xa7, 0xe9, 0x67, 0x0c, 0xe8, 0xe7, 0x91,
-	0x6d, 0xfa, 0x21, 0xdd, 0x74, 0xca, 0xd8, 0x35, 0x5b, 0x26, 0x8a, 0xfa,
-	0xbe, 0x81, 0x35, 0xe9, 0x3f, 0x3a, 0x0e, 0xba, 0x21, 0xad, 0x93, 0xb7,
-	0x4c, 0x29, 0x83, 0x8e, 0xca, 0x90, 0x4f, 0x65, 0xd0, 0x14, 0x31, 0x50,
-	0x19, 0xf2, 0xad, 0x5c, 0xb7, 0x9c, 0x2a, 0xf6, 0x4c, 0x9d, 0xbd, 0x02,
-	0x3a, 0xba, 0x5e, 0xe7, 0xfd, 0xeb, 0x35, 0x9b, 0xd4, 0x83, 0xb7, 0xb6,
-	0xef, 0xfe, 0xef, 0xb8, 0xfb, 0x43, 0x72, 0x03, 0x76, 0xcb, 0x9b, 0xa5,
-	0x61, 0xc8, 0x24, 0x21, 0x5e, 0x04, 0x6d, 0x8c, 0xca, 0x6a, 0xe9, 0xa4,
-	0xac, 0x41, 0x3f, 0xad, 0x2f, 0x0d, 0x00, 0x4f, 0x43, 0x8e, 0xbe, 0x72,
-	0x44, 0xde, 0x58, 0x52, 0x32, 0x63, 0x43, 0xbf, 0x2c, 0xd3, 0x07, 0x0f,
-	0x7a, 0x2e, 0x77, 0xea, 0x98, 0xfd, 0x58, 0x35, 0xf0, 0xc5, 0x8f, 0x57,
-	0xbb, 0x64, 0xa2, 0x6a, 0xca, 0x63, 0xd5, 0x1e, 0x79, 0xa2, 0x1a, 0x93,
-	0xd3, 0xb5, 0x84, 0x7c, 0xa3, 0x7a, 0x50, 0x4e, 0x55, 0x0f, 0xc9, 0x93,
-	0xb5, 0xa4, 0x7c, 0x13, 0x76, 0x61, 0xae, 0xe6, 0xc8, 0x64, 0x6d, 0x58,
-	0x1e, 0xaf, 0xd1, 0xc7, 0x8e, 0xf9, 0xf0, 0xcb, 0x6e, 0xfb, 0x2e, 0xb8,
-	0xae, 0x0e, 0xac, 0xcb, 0x51, 0xe3, 0x3a, 0x66, 0x29, 0xb9, 0xc0, 0xff,
-	0x21, 0x72, 0x0e, 0x7d, 0x2f, 0xbe, 0xa2, 0xa4, 0xa2, 0xe7, 0x6f, 0xfe,
-	0xdf, 0x48, 0x54, 0xdb, 0x46, 0xe7, 0xca, 0x07, 0xd1, 0xc6, 0xa6, 0x4d,
-	0x12, 0xfa, 0x41, 0x9a, 0xfe, 0xff, 0xa6, 0xed, 0x65, 0x68, 0x1f, 0xf6,
-	0x2d, 0xda, 0x5e, 0xfa, 0xec, 0x29, 0x3f, 0x68, 0xe7, 0xd0, 0xd6, 0xda,
-	0x19, 0xe7, 0x68, 0xce, 0x7b, 0x31, 0xf7, 0xf0, 0xff, 0xa7, 0x04, 0xf1,
-	0xaa, 0xb3, 0xb5, 0x83, 0xfc, 0x3f, 0x15, 0xac, 0xe5, 0x8b, 0xf3, 0xc5,
-	0x27, 0x4a, 0x63, 0xea, 0xb1, 0x12, 0x11, 0x8d, 0x2f, 0x17, 0xb7, 0x73,
-	0xf2, 0xbe, 0x2e, 0xcb, 0x6e, 0x54, 0xaf, 0x21, 0xf0, 0xdb, 0xa7, 0x75,
-	0x7e, 0xde, 0xd8, 0x10, 0xe9, 0x8f, 0x71, 0xb8, 0xae, 0x30, 0xb6, 0x00,
-	0x6c, 0xeb, 0x9a, 0x72, 0xa9, 0x1a, 0xf8, 0xaf, 0xe6, 0x34, 0xbd, 0xbc,
-	0x05, 0x9a, 0x63, 0xfc, 0x21, 0x78, 0xe6, 0xcb, 0x41, 0xdf, 0xec, 0x90,
-	0x43, 0x7b, 0x1c, 0xfb, 0x35, 0x7a, 0x38, 0x17, 0xff, 0x4f, 0x07, 0xe5,
-	0x70, 0xbd, 0xcc, 0x2f, 0xb6, 0x35, 0x2d, 0x06, 0x31, 0x5e, 0x47, 0x9e,
-	0xc3, 0x5d, 0x54, 0x4c, 0xae, 0xbf, 0x43, 0x2a, 0x0e, 0x6d, 0x5b, 0xca,
-	0xef, 0x21, 0x29, 0x63, 0x9e, 0x8a, 0xd3, 0xf4, 0x8d, 0x05, 0x72, 0xb6,
-	0x62, 0x3e, 0x98, 0x77, 0xba, 0xbc, 0x1f, 0xef, 0xa8, 0x73, 0x80, 0x99,
-	0xa6, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0xe6, 0xf0, 0x4c, 0x84, 0x75,
-	0xaf, 0xf5, 0x6b, 0xac, 0x7e, 0xf2, 0x41, 0xbf, 0x99, 0xb2, 0x95, 0xcf,
-	0x44, 0xb6, 0x94, 0xf1, 0x8b, 0xf5, 0x7e, 0xca, 0xdc, 0xfd, 0x36, 0x7f,
-	0x51, 0xf9, 0x8b, 0xa9, 0x7d, 0x0a, 0xe1, 0xb7, 0x3d, 0xf2, 0x94, 0xc9,
-	0xdc, 0xf5, 0xb4, 0x1a, 0x2b, 0xfd, 0x34, 0xcc, 0xd3, 0xdd, 0x52, 0xfb,
-	0x2b, 0x6f, 0xf7, 0x07, 0x79, 0xee, 0x1c, 0x7b, 0x67, 0x6e, 0xfb, 0x4e,
-	0x3a, 0x61, 0x8e, 0x7b, 0x3b, 0x70, 0xab, 0x56, 0x62, 0xe0, 0x41, 0xc8,
-	0x3b, 0xbb, 0x45, 0xf3, 0x63, 0xa1, 0xf6, 0x2f, 0x7f, 0x43, 0xf3, 0x73,
-	0xd3, 0xc7, 0xf0, 0xdb, 0x7e, 0xda, 0xb6, 0x94, 0x1b, 0x97, 0x02, 0xbf,
-	0x91, 0xb6, 0xa1, 0x21, 0x2b, 0x50, 0x47, 0x5e, 0x05, 0x9f, 0x6c, 0xb7,
-	0xe5, 0xdf, 0x7f, 0x01, 0x99, 0xe7, 0xd3, 0x46, 0x40, 0x67, 0x00, 0x00,
-	0x00 };
-static u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
-	0x08003fa4, 0x08003ea4, 0x08003f48, 0x08003f60, 0x08003f78, 0x08003f98,
-	0x08003fa4, 0x08003fa4, 0x08003eac, 0x00000000, 0x080049d4, 0x08004a0c,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004a44, 0x08004c08,
-	0x08004b50, 0x08004b88, 0x08004c08, 0x08004ad8, 0x08004c08, 0x08004c08,
-	0x08004b88, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004bc8,
-	0x08004c08, 0x08004bc8, 0x08004b50, 0x08004c08, 0x08004c08, 0x08004bc8,
-	0x08004bc8, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
-	0x08004ab4, 0x00000000, 0x0800602c, 0x08006044, 0x08006044, 0x08006044,
-	0x0800602c, 0x08006044, 0x08006044, 0x08006044, 0x0800602c, 0x08006044,
-	0x08006044, 0x08006044, 0x0800602c, 0x08006044, 0x08006044, 0x08006044,
-	0x08006038, 0x00000000, 0x00000000 };
-static u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
+	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c,
+	0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67,
+	0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a,
+	0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1,
+	0x03, 0x53, 0xb6, 0x62, 0x07, 0x45, 0x6a, 0xb0, 0x4b, 0xb9, 0x0e, 0x8c,
+	0x06, 0x90, 0xff, 0x52, 0xbf, 0xb0, 0xde, 0x2c, 0xa9, 0x58, 0x4d, 0x17,
+	0x9c, 0xb5, 0x4d, 0x9b, 0x0e, 0x60, 0xb7, 0x0b, 0x92, 0x12, 0xf5, 0xb0,
+	0xd0, 0xb2, 0xa9, 0xdb, 0xea, 0xc1, 0x8e, 0x09, 0x56, 0xb1, 0x53, 0xa0,
+	0x2d, 0x5c, 0x27, 0x69, 0xfc, 0x10, 0x14, 0xaa, 0xec, 0xc4, 0x42, 0xd1,
+	0xa2, 0x02, 0x12, 0xd8, 0x29, 0x22, 0x7b, 0xfa, 0x7d, 0x77, 0x66, 0xc8,
+	0x25, 0x2d, 0xdb, 0x41, 0x1f, 0xfa, 0xd2, 0xbd, 0xc0, 0x62, 0xee, 0xbd,
+	0x73, 0xee, 0xb9, 0xe7, 0x9e, 0xff, 0x73, 0x87, 0xd2, 0x1f, 0x74, 0x48,
+	0xbb, 0x84, 0xad, 0x13, 0xbf, 0xd4, 0x89, 0x27, 0x1e, 0xb9, 0x69, 0xf4,
+	0xa6, 0x9b, 0xd1, 0xbd, 0xd9, 0x30, 0x4c, 0x23, 0x9a, 0x6f, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+	0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0xfb, 0xff, 0xde,
+	0x0c, 0x11, 0x8b, 0xcf, 0xce, 0xf0, 0x27, 0x31, 0x3d, 0x23, 0x0f, 0xb9,
+	0xb6, 0xc4, 0x8c, 0xcc, 0xd5, 0xa9, 0x49, 0x5b, 0x24, 0x5b, 0xdb, 0x97,
+	0xca, 0xc9, 0x87, 0x7e, 0x31, 0x61, 0x0a, 0xe7, 0xaf, 0xcf, 0x5c, 0xfd,
+	0x8b, 0x57, 0x6f, 0x4d, 0x5f, 0xa9, 0x1a, 0x12, 0xb3, 0x32, 0x33, 0x07,
+	0xac, 0xbd, 0x12, 0xeb, 0xc7, 0x9a, 0x17, 0x87, 0xfe, 0xa9, 0x4b, 0xba,
+	0x22, 0x5c, 0x22, 0x0b, 0xe5, 0xb4, 0x73, 0x18, 0xcf, 0x33, 0xb5, 0x7d,
+	0xce, 0x9a, 0x98, 0xb2, 0x6a, 0x05, 0x3b, 0x96, 0xca, 0x1a, 0xf1, 0x48,
+	0xa9, 0x16, 0x93, 0x8b, 0xea, 0xdf, 0x79, 0x60, 0x4f, 0x9b, 0xfd, 0xf3,
+	0x9a, 0x5b, 0xf7, 0xfd, 0xd3, 0x8e, 0xef, 0xbf, 0x8e, 0xdf, 0x7b, 0x0e,
+	0xc6, 0xde, 0x47, 0x7e, 0xd6, 0x34, 0x44, 0xb7, 0xff, 0x4c, 0x73, 0x17,
+	0x5b, 0xa5, 0x34, 0x2f, 0x32, 0xed, 0xc5, 0xe4, 0x94, 0x57, 0xd4, 0xf2,
+	0xf5, 0xb2, 0x76, 0x68, 0x79, 0x56, 0x3b, 0xbc, 0x7c, 0x4a, 0x3b, 0xb2,
+	0x5c, 0xd1, 0xdc, 0x65, 0x29, 0xea, 0x07, 0x3a, 0x24, 0x6b, 0x9d, 0xd5,
+	0x72, 0xf5, 0x3e, 0xcd, 0x9d, 0xbf, 0xea, 0xbb, 0x4e, 0xda, 0xfa, 0x3d,
+	0x31, 0xb3, 0xdc, 0xcf, 0x2d, 0xfb, 0x18, 0x9b, 0x92, 0x4d, 0xf8, 0xbe,
+	0x9e, 0xf1, 0x9f, 0x74, 0x47, 0x6d, 0x4b, 0xd7, 0x62, 0x52, 0xaa, 0xb7,
+	0x03, 0x6f, 0x87, 0x96, 0x9b, 0x37, 0xb5, 0xbc, 0xe7, 0xbf, 0xe6, 0x3a,
+	0xd2, 0x6f, 0x88, 0xef, 0xcf, 0x38, 0x7b, 0x92, 0xc7, 0xe5, 0x0c, 0xf0,
+	0xd6, 0x80, 0x4f, 0x2c, 0x3d, 0x43, 0xfa, 0x22, 0x9a, 0x8b, 0x5a, 0x6e,
+	0x28, 0xa2, 0x4f, 0x52, 0xa4, 0xbf, 0xb0, 0xa4, 0x83, 0xce, 0xed, 0x52,
+	0xa8, 0x5a, 0x32, 0xb1, 0xb4, 0x15, 0xfe, 0xa2, 0xff, 0xea, 0x50, 0x42,
+	0xfe, 0xb2, 0x9e, 0x3e, 0x55, 0x04, 0x2f, 0x66, 0xbc, 0x94, 0x80, 0xcf,
+	0x59, 0x77, 0xb4, 0x5f, 0x5e, 0xab, 0x27, 0xe5, 0xbb, 0x75, 0x3b, 0x59,
+	0x92, 0x6d, 0x52, 0x48, 0x58, 0xb2, 0x82, 0x35, 0xd3, 0xa0, 0x43, 0xb7,
+	0x6d, 0xab, 0x04, 0xd8, 0x52, 0xfd, 0x27, 0xfc, 0xb7, 0x32, 0xd6, 0xe4,
+	0xa8, 0x5a, 0x53, 0x04, 0xdd, 0x21, 0x2c, 0xcf, 0xa1, 0x60, 0xd5, 0x59,
+	0x02, 0x58, 0x29, 0x4e, 0x8e, 0x62, 0xae, 0xfe, 0x85, 0x50, 0x16, 0xad,
+	0x38, 0x2f, 0x9f, 0xbb, 0x71, 0xbe, 0xdd, 0xe0, 0x89, 0x24, 0x74, 0xd9,
+	0x93, 0x2c, 0x60, 0x66, 0xba, 0xde, 0x81, 0x31, 0x69, 0xf1, 0xfd, 0x23,
+	0x8e, 0x58, 0x25, 0xa7, 0x1b, 0xbc, 0x4b, 0x49, 0xc9, 0xe9, 0xc2, 0x9a,
+	0x16, 0xb1, 0x6c, 0x9e, 0x81, 0x78, 0xdb, 0x30, 0xef, 0x77, 0x1a, 0x19,
+	0xdf, 0x9f, 0x1c, 0x95, 0xae, 0x60, 0x6e, 0x1f, 0x70, 0x98, 0x32, 0x31,
+	0xae, 0x01, 0xee, 0x03, 0xd2, 0x17, 0x8b, 0x67, 0xd8, 0xe7, 0x73, 0x54,
+	0xdc, 0xd9, 0x54, 0xb8, 0x6f, 0x87, 0x94, 0xbc, 0xeb, 0xc3, 0x3e, 0x78,
+	0xed, 0xe1, 0xcc, 0xce, 0x4e, 0x8c, 0xb5, 0x1b, 0x80, 0xc7, 0x29, 0x09,
+	0xf7, 0xd8, 0x21, 0x6b, 0x09, 0xd1, 0x2f, 0x39, 0xbd, 0x21, 0x5c, 0x17,
+	0x68, 0x8d, 0x64, 0xde, 0x2e, 0x33, 0xf3, 0xad, 0x72, 0x72, 0x9e, 0xbc,
+	0x2d, 0x43, 0x16, 0x78, 0xde, 0x52, 0xd4, 0xb2, 0xf5, 0x53, 0xe8, 0x9b,
+	0x32, 0x69, 0xfb, 0xaf, 0xcd, 0x38, 0xb3, 0x5a, 0x6e, 0xf9, 0x8c, 0x96,
+	0x87, 0x0e, 0x1c, 0x5a, 0x3e, 0xaf, 0x1d, 0xae, 0xaf, 0x76, 0x4a, 0x7b,
+	0x1a, 0xda, 0x66, 0xca, 0x49, 0x4f, 0x13, 0xd2, 0xbb, 0x00, 0x7e, 0x65,
+	0x2d, 0x70, 0xde, 0xee, 0xd2, 0x0e, 0x03, 0x57, 0x8b, 0xfd, 0xad, 0x0e,
+	0xe9, 0x32, 0x64, 0x9b, 0x1d, 0xc1, 0xc6, 0xe4, 0x5b, 0xa0, 0x6d, 0xcd,
+	0x49, 0x00, 0x4e, 0xba, 0x83, 0x35, 0x3d, 0x21, 0x3d, 0xd4, 0x25, 0xea,
+	0x91, 0x9e, 0xcd, 0xcf, 0xfd, 0x69, 0x6f, 0x69, 0xff, 0x76, 0xc2, 0xc0,
+	0x3e, 0x52, 0x0f, 0x4d, 0xda, 0x6e, 0x8f, 0x29, 0x45, 0x4b, 0x97, 0xb4,
+	0x95, 0x93, 0x1b, 0x64, 0xc6, 0x11, 0xc9, 0x41, 0xbf, 0x75, 0xdb, 0x04,
+	0x8f, 0x6c, 0xf0, 0x68, 0xcf, 0xa9, 0x41, 0xfd, 0x0e, 0x49, 0xf5, 0x15,
+	0x35, 0x33, 0xe4, 0xe7, 0x82, 0xdc, 0xa6, 0xd6, 0xeb, 0x19, 0x07, 0x3a,
+	0xd9, 0xce, 0x3e, 0xf6, 0x8d, 0xa9, 0x7d, 0x8d, 0x8c, 0x9d, 0x5c, 0x14,
+	0xd1, 0xf4, 0xcc, 0x3e, 0xe0, 0xa3, 0xae, 0x12, 0xee, 0x29, 0xd0, 0x48,
+	0xda, 0xd9, 0xb7, 0xb1, 0x26, 0x26, 0xae, 0xd3, 0xd9, 0x40, 0x27, 0xe8,
+	0x49, 0x90, 0xe7, 0xe4, 0xa1, 0x3a, 0xa7, 0xb6, 0x71, 0xce, 0x5f, 0xfb,
+	0xdb, 0x46, 0x4c, 0x79, 0x5d, 0x9d, 0x97, 0x76, 0x45, 0x38, 0x75, 0x46,
+	0x21, 0x7f, 0xa6, 0x3d, 0xd1, 0x0a, 0x8e, 0xb5, 0x8e, 0x0b, 0x7a, 0xa1,
+	0x1b, 0x99, 0x0e, 0xc9, 0x29, 0xfa, 0x0e, 0x62, 0x2f, 0xda, 0x1b, 0xec,
+	0xc6, 0xe6, 0x59, 0x38, 0x97, 0x81, 0xed, 0xa6, 0x95, 0xfe, 0x14, 0x2a,
+	0xf4, 0x07, 0xa4, 0x6d, 0x35, 0xad, 0x4b, 0x80, 0xaf, 0xf4, 0x6c, 0x37,
+	0x68, 0xe3, 0x18, 0xb6, 0x67, 0xe3, 0xfd, 0x7e, 0xd8, 0xfa, 0xc1, 0x41,
+	0xf0, 0x87, 0x70, 0x76, 0x0a, 0xf2, 0xce, 0xba, 0xd8, 0xd3, 0x75, 0x6e,
+	0x56, 0x3c, 0xe8, 0xc1, 0x79, 0x06, 0x67, 0xc9, 0xaf, 0x76, 0xe8, 0xb3,
+	0x26, 0x05, 0x27, 0x9d, 0xa2, 0xfc, 0x03, 0xda, 0x75, 0xd9, 0x76, 0x4b,
+	0x23, 0xed, 0x91, 0xac, 0xa8, 0x8f, 0xa6, 0xc4, 0x47, 0x08, 0x4b, 0x38,
+	0xc2, 0xa7, 0x0f, 0x8a, 0xfe, 0x6b, 0xdf, 0xda, 0x74, 0x56, 0x5b, 0x06,
+	0x66, 0x41, 0x43, 0xc0, 0x5b, 0xf0, 0xe4, 0xb3, 0x60, 0xc9, 0xd7, 0xad,
+	0xfc, 0x23, 0x6c, 0x23, 0x1c, 0x74, 0xa2, 0x8f, 0x34, 0xac, 0x74, 0x04,
+	0xf6, 0x15, 0xd1, 0x14, 0xc9, 0x46, 0x0b, 0x71, 0x7c, 0xda, 0x39, 0x08,
+	0x0f, 0xbb, 0xf7, 0x60, 0xf7, 0x1e, 0x7c, 0x82, 0x07, 0x9b, 0xf7, 0xe8,
+	0x27, 0x52, 0xf2, 0xea, 0x10, 0xfc, 0xda, 0x86, 0x5f, 0x41, 0x1b, 0x43,
+	0x5f, 0x17, 0x03, 0x7e, 0x65, 0xba, 0xaa, 0xc3, 0x76, 0x61, 0x43, 0x4b,
+	0x9c, 0xb3, 0xf0, 0xcc, 0xe3, 0x69, 0xc3, 0x8f, 0x52, 0xaf, 0x22, 0xff,
+	0x49, 0x3f, 0x93, 0x84, 0x4f, 0xa1, 0xaf, 0xa1, 0x2f, 0x21, 0xac, 0xef,
+	0xe7, 0x1d, 0xae, 0xf5, 0x65, 0xdc, 0xa1, 0x1d, 0x75, 0x88, 0x1e, 0x2f,
+	0x6a, 0x47, 0x87, 0x60, 0x63, 0x37, 0xb6, 0x80, 0x56, 0xda, 0xda, 0x75,
+	0x74, 0x15, 0x68, 0xbf, 0xe8, 0x0c, 0xfe, 0x5d, 0xde, 0x36, 0xc0, 0x28,
+	0xa1, 0x76, 0x05, 0xe3, 0xb6, 0xd0, 0x9f, 0xf0, 0x7d, 0x3a, 0x95, 0x95,
+	0xdd, 0xe1, 0x98, 0xfd, 0x75, 0x7a, 0x1d, 0xfd, 0x96, 0x98, 0x0c, 0x9c,
+	0x09, 0xfc, 0xe0, 0xc0, 0x82, 0x25, 0xf6, 0x99, 0x80, 0xc6, 0x81, 0x73,
+	0x91, 0x3f, 0x6c, 0x01, 0x3e, 0xd0, 0xe7, 0x6d, 0xc4, 0x09, 0x91, 0xf7,
+	0x34, 0x98, 0x0a, 0xe6, 0xb6, 0xf2, 0x82, 0x3e, 0x98, 0xf6, 0x66, 0x35,
+	0xda, 0xdb, 0x01, 0xd8, 0x9b, 0xd3, 0x2a, 0x69, 0xe7, 0xef, 0x60, 0x6f,
+	0x4f, 0x39, 0x1a, 0x78, 0x23, 0x72, 0xa1, 0xdc, 0x01, 0x5b, 0x37, 0x93,
+	0xef, 0xc8, 0x9e, 0xd4, 0xb4, 0x68, 0x72, 0x9a, 0x73, 0x35, 0xcc, 0x29,
+	0xff, 0x1b, 0xd8, 0xf7, 0x45, 0xe3, 0x69, 0xd0, 0xe5, 0xfb, 0xd3, 0xc0,
+	0x59, 0xd8, 0x6f, 0x84, 0xb6, 0x15, 0xcd, 0xa7, 0x10, 0xf3, 0xdc, 0xcf,
+	0x19, 0x52, 0x1c, 0x6e, 0x91, 0xf4, 0xf0, 0x02, 0x70, 0x4f, 0x3a, 0x81,
+	0x1d, 0x53, 0xd7, 0x17, 0x81, 0x7f, 0xc6, 0x1b, 0x82, 0x1e, 0xd3, 0x0e,
+	0x40, 0x17, 0xf0, 0x2f, 0x02, 0xff, 0x4c, 0xbd, 0x45, 0xbe, 0x69, 0x46,
+	0xb1, 0x34, 0x3a, 0x4f, 0x1b, 0xc0, 0xa2, 0x7d, 0x4f, 0xc8, 0x17, 0xbd,
+	0xb8, 0xe6, 0x3e, 0x4b, 0x3f, 0x5b, 0x1a, 0x86, 0x9d, 0x68, 0x25, 0x87,
+	0x7b, 0x1b, 0xb2, 0xb8, 0x0e, 0x23, 0xd9, 0x52, 0x60, 0x83, 0x59, 0x77,
+	0xa8, 0x98, 0x34, 0x94, 0x2f, 0x11, 0x39, 0x5c, 0x36, 0x01, 0xc3, 0x31,
+	0xe7, 0x83, 0xb9, 0xb1, 0x72, 0x1f, 0x7c, 0x23, 0xc7, 0x57, 0xfd, 0x49,
+	0x27, 0x98, 0xfb, 0xdd, 0x72, 0x81, 0x32, 0x62, 0xdc, 0x4e, 0x95, 0x9c,
+	0x7f, 0xf7, 0xa1, 0xbf, 0x9b, 0xd6, 0x5c, 0x1b, 0x4f, 0x7a, 0x2c, 0x8c,
+	0xf5, 0xda, 0x11, 0x5b, 0xef, 0x6b, 0x0d, 0x7d, 0xd8, 0x11, 0x4c, 0x1e,
+	0x2a, 0x97, 0x7a, 0x5b, 0xe5, 0xaa, 0xc1, 0xd8, 0x79, 0x09, 0x46, 0xed,
+	0x96, 0xf7, 0x82, 0x1f, 0xa5, 0x9e, 0x86, 0xb9, 0x58, 0xbe, 0xec, 0xcb,
+	0x9a, 0x13, 0xac, 0xc1, 0xb8, 0x23, 0x57, 0xd6, 0xfb, 0x62, 0xb2, 0x3e,
+	0xb6, 0xb8, 0x66, 0x49, 0xf6, 0x0e, 0x2f, 0x8a, 0x5a, 0xdb, 0x1b, 0xdb,
+	0x58, 0x9b, 0xc8, 0x97, 0x4b, 0x3d, 0x0d, 0xe3, 0x64, 0x0e, 0xb8, 0xf4,
+	0x03, 0xeb, 0x6b, 0xfb, 0x37, 0xd6, 0xee, 0x90, 0x54, 0x0f, 0xd7, 0xeb,
+	0x7d, 0x6d, 0x1b, 0xb8, 0x53, 0x21, 0x3d, 0xbd, 0x6d, 0x1b, 0x38, 0x6c,
+	0xe2, 0x6c, 0x18, 0x0f, 0x13, 0xe7, 0xc0, 0x06, 0xce, 0xfd, 0x9b, 0xe9,
+	0x39, 0x21, 0xf0, 0x41, 0xb1, 0xd6, 0x8c, 0x1c, 0xb8, 0x50, 0x1e, 0x1c,
+	0xff, 0xa2, 0x20, 0xe6, 0xed, 0xdf, 0x16, 0xfa, 0x64, 0xf3, 0x80, 0x0b,
+	0x5e, 0x99, 0x42, 0x1f, 0xa7, 0x49, 0x09, 0x72, 0x7e, 0xa8, 0x26, 0x07,
+	0xd6, 0x6a, 0x12, 0xea, 0x12, 0x75, 0xe2, 0x32, 0x6c, 0x4c, 0x8a, 0xbb,
+	0x32, 0x1d, 0x13, 0x66, 0xc6, 0x82, 0xad, 0xc9, 0x78, 0x09, 0x3e, 0xd9,
+	0xc8, 0xec, 0x79, 0x3b, 0x67, 0x3c, 0xe9, 0x1b, 0x88, 0xdb, 0x39, 0xe9,
+	0x38, 0xe8, 0x8e, 0x62, 0xbe, 0x46, 0xdb, 0x82, 0x5f, 0xa9, 0x13, 0xf7,
+	0x7c, 0xb7, 0x74, 0x21, 0x2e, 0xd6, 0x5e, 0xda, 0x11, 0xd8, 0x8e, 0x98,
+	0x26, 0x7c, 0xed, 0xcc, 0x28, 0xe3, 0x78, 0x6b, 0x0c, 0xf0, 0x13, 0x46,
+	0x66, 0x6c, 0xe7, 0xf1, 0xda, 0x9d, 0x3b, 0x0b, 0xb5, 0xe2, 0xce, 0x42,
+	0xd9, 0xa2, 0x9d, 0xe8, 0xee, 0x28, 0xfa, 0x2a, 0x57, 0x4a, 0xc2, 0x26,
+	0x2e, 0xab, 0x3c, 0xe2, 0xb5, 0x7a, 0x1d, 0xf6, 0x47, 0xfb, 0x16, 0x19,
+	0xf7, 0xb0, 0xc7, 0xc8, 0x87, 0x90, 0x3b, 0x68, 0x83, 0x4f, 0xcb, 0xe2,
+	0xd4, 0xfa, 0xc8, 0xbf, 0x85, 0xf6, 0xc9, 0xfe, 0xfb, 0x7e, 0xe0, 0xef,
+	0xef, 0xe8, 0x0e, 0xe6, 0xde, 0x0a, 0x6d, 0x3a, 0xc2, 0x45, 0x3c, 0xc3,
+	0xda, 0x38, 0x72, 0x92, 0xf1, 0xba, 0xa9, 0xd1, 0x3f, 0xe7, 0x3c, 0xe6,
+	0x12, 0xcc, 0x23, 0xa6, 0x43, 0x3f, 0x27, 0xd9, 0x1c, 0xfc, 0x88, 0x8e,
+	0xdc, 0xa2, 0x00, 0xbb, 0x31, 0x33, 0x57, 0x64, 0x46, 0xf9, 0x48, 0x89,
+	0xb5, 0x64, 0x9e, 0x00, 0xcc, 0x7f, 0xc0, 0xe6, 0xda, 0xba, 0x43, 0x3d,
+	0x0c, 0x7d, 0xbc, 0xf2, 0xbb, 0x80, 0xbd, 0xbc, 0x05, 0xf6, 0xdd, 0x46,
+	0x58, 0xbc, 0xbf, 0xb8, 0xe5, 0xfd, 0x4f, 0x69, 0xbf, 0x78, 0xb7, 0x0a,
+	0x7f, 0xda, 0x1a, 0xda, 0xfe, 0x05, 0x29, 0xc0, 0xb7, 0x9a, 0x36, 0x73,
+	0xc7, 0xdb, 0xb0, 0x16, 0xe3, 0x1a, 0x68, 0x84, 0xbf, 0x40, 0xcc, 0x04,
+	0xbf, 0x11, 0x13, 0x12, 0x37, 0x30, 0x3f, 0xa2, 0x9f, 0x00, 0x2c, 0xfd,
+	0x2f, 0x61, 0x5f, 0xe9, 0x20, 0xcf, 0x0b, 0x35, 0xae, 0xa1, 0xaf, 0x12,
+	0xdf, 0x1d, 0x6d, 0x83, 0x46, 0xf9, 0xaf, 0x19, 0x76, 0x04, 0x1b, 0xe1,
+	0xdd, 0x0a, 0xcb, 0x7c, 0x85, 0xb8, 0xbb, 0xc3, 0x3c, 0x60, 0x4c, 0xb2,
+	0xf5, 0x2c, 0x7e, 0x45, 0x99, 0x7c, 0x16, 0xb9, 0x98, 0xdd, 0x42, 0x5e,
+	0x90, 0x35, 0x56, 0xc0, 0xa3, 0x68, 0xdd, 0x13, 0xbd, 0x9b, 0xc7, 0xf7,
+	0xc5, 0x37, 0x7c, 0x25, 0x2d, 0x4d, 0xb2, 0x88, 0x15, 0xe0, 0x71, 0x6a,
+	0x42, 0xcf, 0x24, 0x24, 0x57, 0x0b, 0xf8, 0x8b, 0x78, 0x0b, 0xff, 0xc8,
+	0x2e, 0x64, 0xb2, 0xee, 0x07, 0x23, 0x99, 0x53, 0xcf, 0xb2, 0x90, 0x4d,
+	0x0a, 0xba, 0x34, 0x86, 0xb5, 0x72, 0x02, 0x38, 0x18, 0x87, 0x1d, 0x3d,
+	0x13, 0x97, 0x82, 0xc5, 0x7c, 0x41, 0xe5, 0x7a, 0x59, 0xfa, 0x01, 0x3d,
+	0xd3, 0x86, 0x39, 0xf6, 0x1f, 0xee, 0x0e, 0x64, 0xdd, 0xc9, 0xf1, 0xb8,
+	0x9e, 0xe9, 0xde, 0x32, 0xff, 0x7a, 0x67, 0x40, 0x9b, 0x1a, 0x63, 0xfe,
+	0x5f, 0xb6, 0x8c, 0xbf, 0x1e, 0xdf, 0x3c, 0x7e, 0x60, 0x67, 0xa4, 0x0f,
+	0x7a, 0xe6, 0x89, 0x90, 0x5e, 0xea, 0xe9, 0x56, 0x5a, 0x7f, 0x13, 0x7d,
+	0x79, 0x0e, 0x38, 0x95, 0x8e, 0xff, 0x06, 0xfa, 0xb2, 0x0e, 0xfb, 0x09,
+	0xfa, 0xd2, 0x48, 0xc3, 0x7a, 0x5d, 0x51, 0xd1, 0x91, 0x93, 0xba, 0xa3,
+	0x7b, 0x90, 0x77, 0xa4, 0x24, 0x5f, 0x07, 0xef, 0xd6, 0xe3, 0xea, 0x3a,
+	0x4c, 0x71, 0x03, 0x26, 0x88, 0x3b, 0xf9, 0xba, 0x8f, 0x3c, 0xae, 0x31,
+	0x06, 0x0f, 0xa3, 0x5f, 0xc4, 0x59, 0x57, 0x64, 0xd2, 0x5b, 0xcb, 0xea,
+	0xf6, 0xa9, 0x20, 0x0f, 0xb5, 0xbf, 0xad, 0xe5, 0x17, 0x99, 0xa3, 0xc6,
+	0xd0, 0x57, 0xf5, 0x07, 0x62, 0xdc, 0x33, 0x5a, 0x76, 0x79, 0x0e, 0xf9,
+	0xe9, 0x12, 0x7e, 0x67, 0xf1, 0xab, 0xe1, 0x17, 0xd5, 0x01, 0x2f, 0xa0,
+	0x8e, 0x50, 0xfe, 0x1e, 0xb1, 0x29, 0xd8, 0xff, 0x67, 0x4b, 0xc8, 0x8f,
+	0xe7, 0x12, 0xf2, 0x94, 0xad, 0xf7, 0xea, 0x81, 0x8f, 0xcb, 0x22, 0xb7,
+	0xb6, 0x2e, 0xcb, 0x97, 0xc2, 0x1c, 0x4d, 0xe4, 0x9d, 0x0a, 0x64, 0xb9,
+	0xff, 0x48, 0xe8, 0x9f, 0xbe, 0xf6, 0xa0, 0xab, 0x7c, 0x79, 0x98, 0x83,
+	0xc1, 0xef, 0x64, 0x15, 0xd4, 0x1b, 0xe0, 0x8f, 0x26, 0xef, 0x41, 0x8f,
+	0xdf, 0xa9, 0xb4, 0x83, 0x1e, 0x5b, 0x0a, 0xc7, 0x90, 0xbb, 0x68, 0x83,
+	0xd6, 0x36, 0xad, 0x1d, 0x79, 0x18, 0xfc, 0x8e, 0x1a, 0x93, 0x67, 0x17,
+	0xa7, 0x16, 0xca, 0x3a, 0x60, 0xc1, 0xf3, 0x51, 0xf4, 0xa1, 0x7f, 0x97,
+	0x2a, 0x5c, 0xa7, 0xcb, 0xbb, 0x15, 0x43, 0x7e, 0x8e, 0xbc, 0xee, 0x3d,
+	0xfb, 0xe2, 0x14, 0x6c, 0xb0, 0x0f, 0xf1, 0x0a, 0xb5, 0xd0, 0x1e, 0xc6,
+	0x8c, 0x01, 0x13, 0xcf, 0x3c, 0x7e, 0x87, 0x91, 0xe7, 0x5d, 0x7b, 0xcd,
+	0x27, 0xc1, 0x93, 0xb6, 0x18, 0xd6, 0x10, 0xde, 0x04, 0x6d, 0x5d, 0xd0,
+	0xc1, 0xb4, 0x35, 0x21, 0xdd, 0x96, 0xca, 0x9d, 0x34, 0xce, 0x07, 0x7e,
+	0xf2, 0xe3, 0xf3, 0xe4, 0xb3, 0x01, 0x1d, 0xe2, 0x98, 0xef, 0xe8, 0xcf,
+	0x89, 0x2f, 0x7d, 0x30, 0x8b, 0xc3, 0x5c, 0xaa, 0x04, 0xfd, 0x68, 0x4e,
+	0xb4, 0x28, 0xa6, 0xd2, 0x4f, 0xe7, 0x61, 0xab, 0x1c, 0x8f, 0x8b, 0x92,
+	0xc1, 0x26, 0x79, 0x52, 0x8f, 0x56, 0xa7, 0x66, 0x6c, 0xca, 0xd5, 0x92,
+	0xe9, 0x72, 0x24, 0x57, 0xca, 0x08, 0x75, 0x66, 0xe5, 0xdb, 0x90, 0xab,
+	0x1e, 0xd6, 0x20, 0xf0, 0x03, 0x73, 0x94, 0x2f, 0xea, 0xc4, 0x0a, 0xf2,
+	0xb0, 0x8a, 0xc4, 0x83, 0x1a, 0xea, 0x19, 0xd4, 0x1d, 0x90, 0x5f, 0x79,
+	0x0e, 0x38, 0x12, 0x78, 0x2e, 0xe1, 0x99, 0xc4, 0xf3, 0x2c, 0x9e, 0xfd,
+	0x78, 0xd6, 0x68, 0x1f, 0x61, 0xde, 0xf3, 0x31, 0x7a, 0x60, 0x27, 0x79,
+	0xda, 0xb4, 0x7c, 0xaf, 0x9e, 0x91, 0xbf, 0xad, 0x1f, 0x94, 0xbf, 0xa9,
+	0x8f, 0xca, 0x5f, 0xd7, 0x1d, 0x79, 0xb9, 0xbe, 0x5f, 0xfe, 0xaa, 0x3e,
+	0xcc, 0x9a, 0x10, 0x39, 0x5c, 0x0a, 0xbe, 0xf9, 0xbc, 0x3c, 0xe8, 0xd5,
+	0xe1, 0x73, 0x28, 0xff, 0x8b, 0x53, 0xd9, 0xda, 0x75, 0x52, 0x78, 0xd6,
+	0x42, 0x9e, 0x69, 0xb0, 0x2e, 0x93, 0xc7, 0x9c, 0x3b, 0xe2, 0x94, 0xbd,
+	0x6e, 0xb3, 0x4e, 0x39, 0x49, 0x38, 0xd4, 0xbb, 0x1a, 0xf2, 0x97, 0x16,
+	0x99, 0x48, 0xa4, 0x57, 0x5c, 0x23, 0x19, 0xfa, 0xa3, 0x3b, 0x01, 0x87,
+	0x3d, 0xbd, 0x0e, 0x59, 0x7b, 0x1e, 0xb6, 0xe0, 0xa0, 0x56, 0x4e, 0xc4,
+	0xe0, 0xfb, 0x54, 0x7e, 0xa2, 0x7c, 0x4b, 0xe0, 0x4b, 0xa3, 0x9a, 0x91,
+	0x73, 0xd9, 0x70, 0x8e, 0xf1, 0xd1, 0x02, 0xec, 0x72, 0x18, 0x43, 0xb6,
+	0xe2, 0xa4, 0x6f, 0x3c, 0x16, 0xfa, 0xc7, 0x15, 0x39, 0xe1, 0x0d, 0x66,
+	0xaf, 0x20, 0xf6, 0x68, 0x2d, 0x51, 0x5e, 0xb4, 0x0b, 0xb4, 0xf9, 0xfe,
+	0xdd, 0xac, 0xbf, 0xe3, 0xa6, 0xfc, 0x70, 0x36, 0x6d, 0x3d, 0xa2, 0xcf,
+	0x40, 0xce, 0xbe, 0x7f, 0xd4, 0x4e, 0x9f, 0x9a, 0xd0, 0x3b, 0xe5, 0x27,
+	0xcf, 0x30, 0x26, 0xaf, 0x4e, 0x7d, 0x1f, 0x7a, 0x50, 0x5d, 0x6a, 0x95,
+	0x6a, 0xd5, 0x94, 0x4b, 0x23, 0x83, 0x6a, 0xdf, 0x6a, 0x2d, 0x8e, 0x3c,
+	0xaf, 0x4d, 0xa6, 0xfb, 0x94, 0xb2, 0xc3, 0x6f, 0x0f, 0x2b, 0xbf, 0xed,
+	0xda, 0x78, 0xd6, 0x92, 0xd6, 0x66, 0x5a, 0x5e, 0x96, 0x82, 0x07, 0x1d,
+	0x8b, 0xef, 0x02, 0x4f, 0xd8, 0x1f, 0xb4, 0x0a, 0x3a, 0x62, 0xa0, 0x39,
+	0x68, 0x3d, 0xa8, 0xff, 0xd2, 0xff, 0x1d, 0x93, 0x7c, 0x7c, 0x1b, 0xb1,
+	0x85, 0xb1, 0x52, 0x53, 0x7a, 0xb7, 0xb0, 0xf4, 0x53, 0x8b, 0xfe, 0x65,
+	0xa5, 0xb6, 0x2b, 0x1c, 0xd3, 0xbf, 0x73, 0xdc, 0x2e, 0x2f, 0x57, 0xb7,
+	0xcb, 0x62, 0x95, 0xef, 0x5b, 0x65, 0xa1, 0x3a, 0x78, 0xa5, 0x57, 0xef,
+	0x93, 0xd5, 0xeb, 0x6e, 0xb4, 0xee, 0xd7, 0xc1, 0x93, 0x63, 0x1f, 0xc9,
+	0x07, 0x23, 0xdd, 0xf2, 0xd6, 0x7d, 0xe9, 0x17, 0xfe, 0x44, 0x87, 0x3e,
+	0x8e, 0x74, 0xd0, 0xce, 0xd0, 0xe7, 0x7c, 0xfa, 0x4a, 0x56, 0xa7, 0x9e,
+	0xfd, 0x00, 0xfa, 0x95, 0xae, 0x04, 0x3a, 0x49, 0xdc, 0xc4, 0x0b, 0xf9,
+	0xd8, 0x6f, 0x00, 0x27, 0xde, 0xd5, 0x06, 0x81, 0xeb, 0x0d, 0xc5, 0x8b,
+	0xbb, 0x9d, 0xf4, 0x15, 0x84, 0x28, 0xff, 0x92, 0x3d, 0x38, 0x3c, 0xa0,
+	0xef, 0x92, 0x6a, 0xf2, 0x46, 0xeb, 0xbb, 0x88, 0x07, 0xd9, 0x44, 0xfa,
+	0xd4, 0x45, 0x59, 0x9d, 0xba, 0x60, 0x53, 0x17, 0x69, 0xc3, 0xff, 0x80,
+	0x9c, 0xd4, 0x92, 0x4a, 0x8d, 0xbe, 0x8b, 0xb8, 0x58, 0x17, 0xec, 0xb5,
+	0x4e, 0x80, 0x06, 0x77, 0x3f, 0xde, 0x61, 0xde, 0xf8, 0x3c, 0xe5, 0xd6,
+	0xc2, 0xb5, 0xc3, 0x59, 0xbd, 0x7f, 0x0b, 0x8f, 0x06, 0xad, 0x43, 0x3a,
+	0xf7, 0xfb, 0x2f, 0xec, 0xfb, 0x3e, 0x68, 0x1d, 0xc4, 0x5a, 0xc4, 0xd0,
+	0x64, 0xe3, 0x1e, 0x3f, 0x52, 0x7b, 0x3c, 0x5b, 0x43, 0x0e, 0xb8, 0xbe,
+	0x07, 0xe6, 0x6a, 0x3a, 0xce, 0x69, 0x2a, 0xb9, 0x5c, 0x1a, 0x21, 0x7f,
+	0x6f, 0xef, 0x61, 0x2c, 0x37, 0x32, 0x2f, 0x85, 0x79, 0x46, 0x4c, 0x7e,
+	0x8c, 0xba, 0x6b, 0x12, 0xfe, 0x7f, 0x61, 0xef, 0x20, 0x68, 0x40, 0x7d,
+	0x9a, 0x54, 0xf1, 0x7c, 0xca, 0x05, 0x8e, 0x9c, 0xc2, 0xfd, 0xa6, 0x2c,
+	0x01, 0xf7, 0x38, 0xf9, 0x00, 0xdc, 0x33, 0x9c, 0x57, 0x32, 0xc0, 0x7c,
+	0x2d, 0x05, 0xbc, 0xbd, 0xa1, 0xff, 0x8b, 0x43, 0x57, 0xf7, 0x59, 0x77,
+	0x4b, 0x2c, 0xf4, 0x7f, 0x71, 0x79, 0xeb, 0x79, 0xe8, 0x7d, 0x9c, 0xfa,
+	0x93, 0xe8, 0xd9, 0xd0, 0x9f, 0x46, 0xfc, 0xad, 0x92, 0xaf, 0xc4, 0x80,
+	0x17, 0x39, 0xf7, 0x28, 0xf1, 0x62, 0x5c, 0xa5, 0x2e, 0x17, 0x43, 0x5d,
+	0xee, 0x08, 0x71, 0xaf, 0x41, 0x97, 0xd3, 0xa9, 0x55, 0x9d, 0xf5, 0xd5,
+	0x4e, 0x55, 0xf3, 0x1a, 0xb0, 0xaf, 0x42, 0x99, 0xb1, 0x88, 0xb6, 0x75,
+	0x71, 0x6a, 0x12, 0x35, 0x6c, 0xa1, 0x7c, 0x50, 0x2f, 0xd4, 0x47, 0xf5,
+	0x82, 0x47, 0x7d, 0xdb, 0x6b, 0x2d, 0x28, 0x1e, 0x27, 0x65, 0xa1, 0xfe,
+	0x81, 0x5f, 0xda, 0xbb, 0x0d, 0x7d, 0xe8, 0xfe, 0x38, 0xe5, 0x7b, 0x3d,
+	0xe9, 0x42, 0x50, 0x27, 0xbf, 0x13, 0x72, 0x66, 0xe8, 0x7b, 0xdd, 0xcc,
+	0xd1, 0x96, 0x87, 0x88, 0x1f, 0x74, 0x24, 0x12, 0xb2, 0xe8, 0x71, 0x8f,
+	0xd5, 0x29, 0xf2, 0xb2, 0x30, 0x67, 0xc9, 0x09, 0x25, 0x3f, 0x9e, 0x9b,
+	0xf7, 0x47, 0x86, 0x4c, 0xc6, 0x07, 0xad, 0x47, 0x25, 0x7d, 0x65, 0xcd,
+	0x48, 0xbf, 0x30, 0x81, 0xb8, 0xba, 0x30, 0x6f, 0x88, 0xab, 0xea, 0x30,
+	0xca, 0x28, 0x5d, 0x81, 0x35, 0x86, 0x67, 0xbf, 0xa7, 0xe1, 0xec, 0x5d,
+	0x72, 0xe1, 0xf9, 0xcf, 0xc3, 0xee, 0x5f, 0x81, 0x2c, 0xcc, 0xd4, 0x71,
+	0xe4, 0x19, 0xcf, 0xc9, 0xa0, 0x55, 0x42, 0xfe, 0x0c, 0xbe, 0xa3, 0xbd,
+	0xa2, 0x6c, 0x60, 0x41, 0xc7, 0xb8, 0x9f, 0x7c, 0xe2, 0x78, 0xb7, 0x2c,
+	0xf4, 0x05, 0x36, 0xce, 0x77, 0x03, 0xc0, 0x11, 0xbc, 0xe3, 0xf8, 0xb7,
+	0x64, 0x40, 0xbd, 0xab, 0xaa, 0x75, 0x25, 0xe9, 0x0d, 0xe5, 0xf7, 0x18,
+	0xf6, 0x24, 0x8f, 0xa3, 0xf9, 0x4e, 0x09, 0x6c, 0x29, 0xe2, 0xbb, 0x25,
+	0x47, 0x6b, 0x09, 0xb9, 0xa7, 0x96, 0x94, 0x2f, 0xd7, 0xfa, 0x25, 0x0f,
+	0x39, 0x4e, 0x8e, 0x3e, 0xd9, 0xc3, 0xb3, 0xe5, 0x96, 0xd2, 0x2f, 0x88,
+	0x4e, 0x5a, 0xab, 0x72, 0xdc, 0x8b, 0xe8, 0xe9, 0x08, 0xe9, 0x33, 0xc3,
+	0x71, 0x2c, 0xa4, 0xa1, 0x11, 0x5f, 0x07, 0x70, 0x65, 0x81, 0xe7, 0xa5,
+	0x10, 0x0f, 0xfd, 0x08, 0x68, 0x3d, 0x96, 0x94, 0x25, 0x8f, 0x74, 0x6c,
+	0x97, 0x52, 0x82, 0xfd, 0x57, 0xa0, 0x6f, 0xc4, 0xb3, 0x8d, 0xf9, 0xcd,
+	0x26, 0x1e, 0x3f, 0x5c, 0x2b, 0x82, 0xc7, 0xe4, 0x2f, 0xe1, 0xe0, 0xaf,
+	0xbf, 0x40, 0xf9, 0xed, 0x43, 0x8e, 0x6f, 0x07, 0xba, 0x69, 0x6d, 0xec,
+	0x99, 0x9f, 0xeb, 0x82, 0xac, 0xb8, 0x6f, 0xbb, 0x1c, 0x83, 0xdd, 0xe7,
+	0xaa, 0xdc, 0xff, 0x18, 0xf4, 0xe8, 0x2d, 0xb5, 0x7f, 0x7e, 0xa9, 0x2f,
+	0x5c, 0xcf, 0xb5, 0x5d, 0x5b, 0xd6, 0xb6, 0xca, 0xa1, 0x8a, 0x75, 0x8d,
+	0xf5, 0xbf, 0x8f, 0xf5, 0xba, 0x9c, 0x1e, 0xe5, 0x7a, 0xe2, 0x01, 0x5c,
+	0x35, 0xf1, 0x29, 0x78, 0xe2, 0xaa, 0xde, 0xcf, 0x55, 0x5b, 0x25, 0x57,
+	0x89, 0x70, 0x11, 0xcf, 0x47, 0xa8, 0x87, 0xbf, 0xaa, 0x70, 0x4d, 0x2a,
+	0x5c, 0x78, 0x5f, 0xa5, 0xcf, 0xb9, 0x15, 0xeb, 0x3b, 0xe8, 0xff, 0xa5,
+	0x14, 0xef, 0x94, 0x92, 0xaa, 0xe9, 0xdb, 0x95, 0xaf, 0x29, 0xc5, 0xdb,
+	0xf0, 0xbe, 0x13, 0x36, 0xbf, 0x0f, 0xb9, 0x45, 0x17, 0xeb, 0xdc, 0x2d,
+	0x73, 0x5b, 0xe9, 0x8f, 0x6d, 0xa1, 0x3f, 0x06, 0xb8, 0x5e, 0xec, 0x19,
+	0xc0, 0xe5, 0x01, 0x37, 0x3d, 0x07, 0x3e, 0x3b, 0xf4, 0x2b, 0x8c, 0x93,
+	0xd7, 0x29, 0x5a, 0xa6, 0x97, 0xfe, 0x1b, 0xe7, 0xea, 0xc3, 0xda, 0x68,
+	0x1c, 0xf0, 0xe1, 0x69, 0xe0, 0x99, 0xab, 0xaa, 0xbb, 0x0b, 0xc8, 0x60,
+	0x7b, 0x9c, 0x67, 0x2f, 0x55, 0x3f, 0x8b, 0x67, 0xd7, 0x35, 0xf0, 0x8b,
+	0xbc, 0x22, 0xbd, 0xa4, 0x95, 0xf7, 0x48, 0xb0, 0x37, 0x07, 0x7a, 0x1c,
+	0x37, 0x24, 0x3f, 0x6a, 0x21, 0x3f, 0xe7, 0x3d, 0x2c, 0xed, 0xd2, 0xe2,
+	0xdd, 0x67, 0x4c, 0xb7, 0x19, 0x6b, 0x4d, 0x75, 0xf6, 0xe3, 0x4b, 0xbc,
+	0x8b, 0x4d, 0xf1, 0xee, 0x6e, 0x98, 0xd7, 0x18, 0x8f, 0x2c, 0xd9, 0xf2,
+	0x78, 0x6d, 0x58, 0x1e, 0xad, 0xa5, 0xad, 0xfb, 0xe1, 0x03, 0x0a, 0xeb,
+	0x77, 0xb4, 0x43, 0x71, 0xfa, 0x2f, 0x13, 0x79, 0x60, 0x8b, 0x1d, 0xe4,
+	0x05, 0x25, 0xd6, 0x6c, 0x73, 0x69, 0xde, 0xe3, 0x58, 0x55, 0xd9, 0x9a,
+	0x3b, 0xfc, 0x5f, 0xe6, 0x0d, 0xdc, 0x9f, 0xfe, 0x1a, 0x79, 0x82, 0x87,
+	0x3c, 0xc1, 0x43, 0x9e, 0xe0, 0x21, 0x4f, 0xf0, 0x90, 0x27, 0x78, 0xc8,
+	0x13, 0x3c, 0xe4, 0x09, 0x1e, 0xf2, 0x04, 0xc4, 0xee, 0xa0, 0x5e, 0x18,
+	0x43, 0xfe, 0x0b, 0xff, 0xe5, 0xdd, 0x06, 0x3e, 0xf1, 0xfe, 0x92, 0x31,
+	0x87, 0xb1, 0x99, 0x73, 0xab, 0xdb, 0x5c, 0xca, 0x4d, 0xf9, 0xbe, 0x3b,
+	0x31, 0x37, 0x1e, 0xe6, 0x23, 0x84, 0x89, 0x62, 0x37, 0xe1, 0xe4, 0xa0,
+	0xeb, 0x68, 0xb0, 0x31, 0xe6, 0x2b, 0x41, 0xcc, 0x0a, 0x72, 0xe5, 0xb7,
+	0x91, 0xb3, 0xa4, 0x90, 0xb3, 0xf4, 0x23, 0x3f, 0xe1, 0x9d, 0x75, 0x74,
+	0xc7, 0x94, 0xd5, 0x8e, 0x7a, 0x63, 0xda, 0x3d, 0x1e, 0x73, 0x69, 0x3b,
+	0x55, 0xd0, 0xf5, 0xb9, 0x5e, 0xf1, 0x25, 0x37, 0xf2, 0x4d, 0xe4, 0xad,
+	0xcf, 0xa9, 0xfb, 0xb4, 0xf1, 0x21, 0xca, 0xbc, 0xf2, 0x09, 0xb9, 0x6b,
+	0xc4, 0xdf, 0xe0, 0x1e, 0x50, 0x5f, 0x20, 0xff, 0x44, 0x7a, 0xce, 0x81,
+	0xe1, 0xe7, 0x62, 0x12, 0x3f, 0xb3, 0x1d, 0x73, 0x96, 0xf4, 0xaa, 0xbb,
+	0x24, 0x88, 0xf2, 0xdc, 0x55, 0xc8, 0xcb, 0x16, 0xfd, 0x1c, 0x6f, 0x1c,
+	0x88, 0x97, 0xfe, 0x75, 0x65, 0x2a, 0x57, 0x5d, 0x51, 0x3a, 0x75, 0xb4,
+	0x96, 0x47, 0x7d, 0xd4, 0xd3, 0x2b, 0xed, 0x26, 0x6a, 0xab, 0x08, 0x37,
+	0x71, 0xfe, 0x32, 0xae, 0x6a, 0x9e, 0x73, 0xeb, 0xf2, 0x84, 0xac, 0xb9,
+	0xcf, 0xca, 0x54, 0xa9, 0x92, 0x4e, 0xb2, 0x56, 0xce, 0x5a, 0x2b, 0x53,
+	0x27, 0x81, 0x63, 0x11, 0xb9, 0x81, 0xa1, 0xf6, 0x5e, 0x99, 0x9a, 0xae,
+	0x04, 0xf7, 0x59, 0x01, 0x0d, 0x8c, 0x57, 0xed, 0x62, 0x2c, 0x04, 0xf7,
+	0x5a, 0xba, 0x5a, 0xcb, 0x75, 0x5c, 0x6f, 0x62, 0x1d, 0xe5, 0x36, 0x8c,
+	0xb5, 0x94, 0x1d, 0x69, 0x58, 0x99, 0x2a, 0x56, 0x1b, 0x69, 0x20, 0x1e,
+	0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0xc4, 0x45, 0x3f, 0xe3, 0xfb, 0x85, 0x91,
+	0xfe, 0x30, 0xef, 0x3a, 0x89, 0xfc, 0xce, 0x0c, 0xf4, 0x5c, 0x8d, 0xbf,
+	0xa3, 0xe2, 0x54, 0x4a, 0xe7, 0x3c, 0x9f, 0x78, 0x37, 0xba, 0x80, 0x39,
+	0x8c, 0x17, 0x23, 0x58, 0x3d, 0x84, 0xed, 0x6c, 0xe0, 0x67, 0x4b, 0xb8,
+	0x1f, 0x69, 0xe2, 0x39, 0x2f, 0x61, 0x2f, 0xd2, 0x45, 0x98, 0x38, 0x68,
+	0x83, 0x2c, 0xbd, 0xff, 0x2d, 0xef, 0x1b, 0xcf, 0x44, 0x9e, 0x9a, 0x58,
+	0x43, 0x78, 0xe2, 0x88, 0xd6, 0xe0, 0xc5, 0xb9, 0x60, 0x9d, 0xbe, 0x7e,
+	0xff, 0xf7, 0x69, 0xfb, 0x36, 0xd2, 0x1a, 0xed, 0x1f, 0xe1, 0x19, 0x0e,
+	0xe4, 0xb6, 0xbe, 0x5e, 0xfd, 0x9f, 0x61, 0x78, 0x42, 0x17, 0x3f, 0x76,
+	0x8f, 0x3a, 0xdc, 0x50, 0x87, 0x46, 0xf7, 0x17, 0xbc, 0x0f, 0x60, 0x7d,
+	0xcf, 0x6f, 0x07, 0x8d, 0xb5, 0xe2, 0xcb, 0x61, 0x2c, 0xdb, 0x29, 0x59,
+	0x93, 0x75, 0xc3, 0xf9, 0x70, 0xbc, 0x03, 0xb1, 0x8d, 0xe3, 0x3a, 0xf8,
+	0x0b, 0x5d, 0x76, 0xda, 0xc3, 0xba, 0x25, 0x1e, 0x7c, 0xe3, 0x19, 0xa6,
+	0x1d, 0xb1, 0xee, 0x6b, 0x0b, 0xe7, 0x22, 0x3b, 0xa2, 0x1f, 0x36, 0xc3,
+	0x39, 0xfa, 0x5b, 0x1d, 0xb5, 0x0b, 0xfb, 0xc0, 0xb3, 0xd8, 0x68, 0x4b,
+	0xd1, 0x33, 0x2e, 0x67, 0xe7, 0x23, 0xbf, 0x05, 0x9f, 0x32, 0x64, 0x86,
+	0xbe, 0xbf, 0x03, 0xbe, 0xaf, 0x4b, 0x0e, 0xc1, 0x67, 0x1d, 0x86, 0xcf,
+	0x3a, 0x82, 0x7a, 0x71, 0x6c, 0xa9, 0xf1, 0x9e, 0x97, 0x35, 0x6a, 0x97,
+	0x76, 0x5c, 0xc9, 0xbf, 0xe8, 0x1b, 0xf6, 0x47, 0xd0, 0x01, 0xd6, 0x5d,
+	0x91, 0x4e, 0xc0, 0xdf, 0x3a, 0x71, 0xe8, 0xc4, 0xd6, 0xfb, 0xe4, 0x61,
+	0xd8, 0x46, 0x7b, 0x56, 0xc5, 0x86, 0xa5, 0x80, 0xf7, 0xa5, 0x6a, 0xc0,
+	0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5, 0x58, 0xb3, 0xa4, 0x88, 0x7d, 0x8b,
+	0xd8, 0xb7, 0x88, 0x3a, 0x6f, 0xba, 0xd6, 0xf8, 0x1d, 0xab, 0x33, 0xa4,
+	0x9d, 0x6b, 0xa3, 0xbe, 0xd5, 0x70, 0xfe, 0xe8, 0x79, 0x0a, 0xfc, 0x7f,
+	0x0c, 0xfc, 0x3f, 0x81, 0xfa, 0xe6, 0x8f, 0x50, 0xdf, 0x7c, 0x0d, 0xf5,
+	0xcd, 0x71, 0xd4, 0x37, 0x13, 0xa8, 0x6f, 0xbe, 0x0a, 0xff, 0xf1, 0x15,
+	0xf8, 0x8f, 0x63, 0xf0, 0x1f, 0xe3, 0xea, 0xee, 0xe9, 0xa8, 0xb7, 0xf5,
+	0x4e, 0x25, 0xda, 0x8b, 0xed, 0x67, 0x22, 0x76, 0x11, 0x67, 0x1a, 0x93,
+	0x6a, 0x9d, 0xf5, 0x8d, 0x23, 0xee, 0x41, 0xd6, 0x37, 0xc7, 0xb4, 0x09,
+	0xe4, 0xef, 0xf7, 0xef, 0x67, 0xdd, 0x13, 0xd7, 0x72, 0xaa, 0xee, 0x49,
+	0x9f, 0x77, 0x91, 0x22, 0x21, 0xf7, 0xc3, 0x99, 0xd3, 0x67, 0x73, 0xa0,
+	0x25, 0xc8, 0xf9, 0x7a, 0x42, 0xbf, 0xd7, 0x21, 0x8b, 0xb3, 0xa8, 0x19,
+	0xbc, 0x1f, 0x6b, 0x05, 0xe5, 0x1b, 0x2d, 0x8c, 0x51, 0x2b, 0x7b, 0xff,
+	0x1c, 0x8e, 0x47, 0x64, 0x72, 0x1e, 0xb5, 0xed, 0xf3, 0xff, 0xa8, 0xe5,
+	0xd4, 0xd8, 0xc1, 0x18, 0xf9, 0xee, 0xf3, 0x7f, 0x1f, 0x8e, 0x8b, 0xa1,
+	0x3e, 0x84, 0xb4, 0x5a, 0x0e, 0x9e, 0xdd, 0x61, 0xce, 0xf1, 0x6a, 0xef,
+	0xe6, 0xff, 0xd3, 0x8e, 0xad, 0x45, 0x13, 0xfb, 0x1b, 0x3b, 0x82, 0xfa,
+	0xac, 0x71, 0xbe, 0xab, 0x61, 0xfe, 0x8a, 0xfa, 0xce, 0x5a, 0x28, 0xb7,
+	0xfd, 0x0a, 0x1e, 0x58, 0x96, 0x86, 0x98, 0xe7, 0x7d, 0xe4, 0xf3, 0xfb,
+	0x9f, 0xab, 0xb7, 0xab, 0x6f, 0x72, 0xae, 0xca, 0xb7, 0x61, 0xe7, 0x23,
+	0xa5, 0x1d, 0x81, 0x2f, 0x60, 0x3f, 0xa1, 0x05, 0xfe, 0xfd, 0x8f, 0x81,
+	0x07, 0xbc, 0xf6, 0x1a, 0x6b, 0x38, 0x2b, 0xbc, 0x4b, 0xb9, 0x32, 0xc5,
+	0xdc, 0xba, 0xa4, 0x70, 0xb3, 0xd6, 0x63, 0xdd, 0x17, 0xc5, 0x80, 0x08,
+	0xd7, 0xcf, 0x13, 0x01, 0xdd, 0xe3, 0xa8, 0xe9, 0x08, 0x13, 0x8d, 0x1b,
+	0xeb, 0xbf, 0x8e, 0xf0, 0x1e, 0xee, 0x4a, 0x90, 0x57, 0x29, 0x7c, 0x66,
+	0x88, 0xef, 0x3f, 0xfd, 0xc0, 0xf7, 0x70, 0xbd, 0xd5, 0xb0, 0xfe, 0x3c,
+	0x72, 0x3d, 0xde, 0x99, 0xec, 0x52, 0xdf, 0x19, 0xdf, 0x9f, 0xed, 0x94,
+	0x5f, 0x3c, 0xe3, 0xfb, 0xe3, 0x4e, 0x7a, 0xf8, 0x4d, 0xd4, 0x1e, 0x67,
+	0x68, 0x27, 0x23, 0xa4, 0x73, 0x30, 0x35, 0x2d, 0x03, 0xbd, 0x41, 0x2e,
+	0xfe, 0x75, 0xed, 0xe3, 0x74, 0xeb, 0xe1, 0x3e, 0x3f, 0x6c, 0xd8, 0x27,
+	0xd5, 0xb0, 0xcf, 0x0a, 0x6d, 0xb6, 0x7a, 0x2f, 0xce, 0x5c, 0xdc, 0x75,
+	0xa3, 0x95, 0x08, 0xeb, 0xb2, 0x47, 0x47, 0xda, 0xa4, 0xd2, 0x97, 0x5e,
+	0xf9, 0x11, 0xf2, 0xf5, 0xc2, 0x08, 0xe6, 0x12, 0x83, 0x78, 0xc7, 0xf9,
+	0x74, 0x15, 0xb9, 0xe8, 0x4a, 0x55, 0x86, 0xb0, 0x3e, 0x5d, 0x14, 0xe1,
+	0x3c, 0xfb, 0x8a, 0xb6, 0x6a, 0xe8, 0x03, 0x92, 0x6b, 0x38, 0xf3, 0x04,
+	0xea, 0xaf, 0x13, 0xeb, 0xf5, 0x30, 0xf7, 0xb9, 0x59, 0x5b, 0x53, 0xb9,
+	0xf1, 0x01, 0xad, 0x98, 0x08, 0xce, 0xf8, 0x87, 0xf0, 0x17, 0x86, 0xce,
+	0xb5, 0xef, 0x03, 0xb7, 0x26, 0x0b, 0xcf, 0x18, 0xea, 0x0e, 0xb6, 0x30,
+	0x42, 0x59, 0xf3, 0x79, 0x2d, 0xde, 0x45, 0x67, 0xfa, 0xf3, 0xf0, 0x4c,
+	0xd9, 0xb0, 0x9e, 0x8e, 0xce, 0x14, 0x93, 0x77, 0x67, 0x2d, 0xac, 0xfd,
+	0x1c, 0xf8, 0x91, 0x97, 0xa5, 0x7a, 0xea, 0x33, 0xf0, 0x94, 0x1b, 0x78,
+	0x63, 0x6e, 0x91, 0x61, 0x71, 0xa3, 0x86, 0x1f, 0x4f, 0xc2, 0x0e, 0xbf,
+	0xd1, 0x1b, 0xdd, 0x0d, 0x1b, 0xb6, 0xcf, 0xba, 0x07, 0x8d, 0xf3, 0xfd,
+	0xb0, 0xc5, 0x14, 0xec, 0x93, 0x39, 0x53, 0x9e, 0xb5, 0x0a, 0xed, 0xc9,
+	0x72, 0x8d, 0xb4, 0x75, 0x4c, 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x19, 0x59,
+	0xac, 0x47, 0x34, 0x8c, 0xc2, 0x1e, 0x0f, 0xe2, 0xb7, 0x1f, 0xef, 0x1c,
+	0xfc, 0x58, 0x2b, 0xad, 0xc8, 0xe3, 0x2a, 0x17, 0x47, 0xae, 0x3d, 0x44,
+	0xfa, 0xee, 0x04, 0x3c, 0xf5, 0x99, 0x7a, 0x7a, 0xa7, 0xb8, 0x7d, 0xf4,
+	0x15, 0x49, 0xe0, 0xc6, 0x1a, 0xef, 0x22, 0x6c, 0xbd, 0x1f, 0xcf, 0xb4,
+	0x55, 0x20, 0x6f, 0x15, 0x7e, 0xdf, 0x37, 0x46, 0xf9, 0x8d, 0xe2, 0x7c,
+	0x38, 0x1e, 0xb4, 0xbe, 0x4c, 0xdd, 0x4b, 0xee, 0x96, 0x95, 0xf9, 0x28,
+	0x0e, 0x9e, 0x86, 0x0d, 0xf2, 0xce, 0x76, 0x0c, 0x7c, 0xe1, 0x58, 0x0b,
+	0xe3, 0x21, 0xe6, 0x17, 0x97, 0x71, 0xee, 0x8c, 0x9c, 0x41, 0xfd, 0x2f,
+	0x7d, 0x7c, 0xa6, 0x80, 0x7f, 0x7b, 0xa8, 0xef, 0x9b, 0xd7, 0x1b, 0x36,
+	0xfb, 0x63, 0xa0, 0xcf, 0x6c, 0x58, 0xcf, 0x35, 0x41, 0x7d, 0xb2, 0x26,
+	0x88, 0xc7, 0x49, 0xff, 0x76, 0x3d, 0xf3, 0xa2, 0x3c, 0xa0, 0xce, 0x54,
+	0x93, 0xe3, 0xf3, 0xbe, 0xef, 0x8e, 0x0e, 0x0e, 0x2f, 0x4a, 0x7a, 0xf8,
+	0xa4, 0xec, 0xb3, 0x0e, 0xb1, 0x1e, 0xb3, 0x88, 0xc7, 0xbf, 0xbd, 0x25,
+	0xe3, 0xfb, 0xa7, 0x41, 0xfb, 0xf7, 0xd5, 0x3e, 0x2f, 0x82, 0x7e, 0xf0,
+	0x4a, 0xd5, 0x24, 0xa4, 0x15, 0xcf, 0x04, 0xe9, 0x2d, 0xcb, 0xf1, 0xfa,
+	0x85, 0x50, 0x36, 0x8f, 0x89, 0xeb, 0x5d, 0x36, 0x5c, 0xbb, 0x0c, 0xd8,
+	0x85, 0x90, 0xb6, 0x0c, 0xe8, 0xc5, 0xfe, 0xf5, 0xb7, 0x13, 0xf4, 0x0d,
+	0x94, 0xb9, 0x8b, 0xac, 0xd1, 0x1d, 0x41, 0x1e, 0x95, 0xf8, 0x24, 0x3f,
+	0x10, 0x97, 0xcd, 0x7e, 0x80, 0xeb, 0xe2, 0xd7, 0xd0, 0x15, 0xd2, 0x51,
+	0x54, 0xfe, 0x53, 0xc5, 0x2d, 0x85, 0xcf, 0xd8, 0xe2, 0x0b, 0x2a, 0xea,
+	0xb9, 0x6a, 0xd0, 0x37, 0x31, 0xfe, 0x51, 0x87, 0xbb, 0xe0, 0xff, 0xa0,
+	0x83, 0xb0, 0xe3, 0xdc, 0x3c, 0xef, 0x27, 0x86, 0x78, 0xaf, 0x74, 0x36,
+	0x0f, 0xd9, 0x2e, 0xf0, 0xfb, 0x63, 0x22, 0xa8, 0x31, 0x83, 0xfa, 0x2b,
+	0x45, 0x5f, 0x88, 0xb6, 0xa4, 0xfc, 0x64, 0x5e, 0x7d, 0x6f, 0x8c, 0x03,
+	0xc6, 0xa7, 0xef, 0x6c, 0xf8, 0x9b, 0x89, 0x1f, 0x64, 0x83, 0xbf, 0x99,
+	0x08, 0xbf, 0xfd, 0x56, 0x83, 0x3c, 0xe2, 0xe1, 0x9a, 0x29, 0x13, 0xb5,
+	0xe8, 0x6f, 0x28, 0x28, 0x07, 0xf8, 0xe6, 0x5a, 0x94, 0x3b, 0xf8, 0x41,
+	0x4d, 0xb3, 0x49, 0x96, 0x4b, 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4,
+	0x78, 0x31, 0xaa, 0x2f, 0x07, 0x20, 0x3f, 0xf0, 0x1c, 0x74, 0xbd, 0x3b,
+	0x1b, 0xd4, 0xb9, 0x25, 0xfa, 0xc5, 0xfe, 0xa8, 0xee, 0xdd, 0x25, 0xa5,
+	0x63, 0x7c, 0x1f, 0x93, 0x77, 0x66, 0x63, 0xea, 0x7d, 0x41, 0x62, 0xe1,
+	0x7b, 0x8e, 0xe3, 0x52, 0x50, 0xef, 0xab, 0x21, 0x3e, 0xd4, 0x69, 0x5f,
+	0x89, 0xc6, 0xa6, 0x76, 0xbc, 0x1e, 0xac, 0x9b, 0xac, 0x57, 0xe5, 0xf1,
+	0xfa, 0x2a, 0xce, 0xaf, 0x49, 0x6e, 0xbc, 0x28, 0xbb, 0x6d, 0x4b, 0xc5,
+	0x7d, 0x37, 0x4e, 0x1d, 0xa3, 0x7e, 0x8d, 0xa9, 0xba, 0xb3, 0x88, 0x7c,
+	0xa1, 0x30, 0xc2, 0x6f, 0x3c, 0xbf, 0xba, 0xab, 0x50, 0x4e, 0x5b, 0x59,
+	0xf9, 0xd0, 0x77, 0x4d, 0x8e, 0x45, 0x47, 0x3d, 0x74, 0xd7, 0xc3, 0xb5,
+	0x0b, 0x77, 0x05, 0x67, 0xc5, 0xfb, 0x1a, 0x61, 0x0d, 0xf5, 0x6d, 0xf6,
+	0x5f, 0x6f, 0x35, 0x65, 0xed, 0x56, 0xdf, 0xbf, 0xdf, 0xb1, 0xc4, 0x0d,
+	0x6b, 0x57, 0x4b, 0xd5, 0xae, 0xed, 0x2a, 0x07, 0x71, 0x47, 0x52, 0x5a,
+	0x1e, 0xf6, 0x7a, 0xc6, 0x43, 0x9d, 0xa3, 0xa7, 0x0f, 0xae, 0xea, 0x16,
+	0x62, 0x6e, 0x3a, 0x35, 0x27, 0x6e, 0x2f, 0xbf, 0x37, 0xcf, 0x38, 0x84,
+	0xd9, 0x19, 0xdc, 0x75, 0xdd, 0x34, 0xae, 0xfc, 0xac, 0x48, 0x18, 0x7b,
+	0x6e, 0x6a, 0xb4, 0x89, 0xc6, 0xdc, 0x92, 0xb6, 0x20, 0x13, 0x26, 0x68,
+	0x29, 0x95, 0xa3, 0x3c, 0x8d, 0x7f, 0x1b, 0xb0, 0x7a, 0xd7, 0xd3, 0xa0,
+	0x73, 0x1a, 0x74, 0xf2, 0x1c, 0xd3, 0xb5, 0x48, 0xe7, 0xa2, 0x5a, 0x81,
+	0x7d, 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0x3d,
+	0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0xbd, 0xf1,
+	0x30, 0x4f, 0x7b, 0x62, 0x3d, 0x4f, 0x5b, 0xa9, 0xf3, 0x3b, 0x94, 0xa2,
+	0xa5, 0x58, 0x94, 0x20, 0xcf, 0x15, 0x9d, 0x39, 0x4d, 0x94, 0xe7, 0x5e,
+	0xfb, 0x9b, 0x48, 0xb0, 0x8e, 0x39, 0x1e, 0xd7, 0x15, 0x35, 0xdd, 0xe6,
+	0xba, 0x20, 0xcf, 0x63, 0x6d, 0xb5, 0x79, 0x0d, 0xf2, 0xb5, 0x0c, 0xfd,
+	0x19, 0xed, 0x22, 0x11, 0xd4, 0x8b, 0x99, 0xf3, 0xf7, 0xba, 0x88, 0xbf,
+	0x85, 0x9a, 0x8a, 0xc1, 0xbc, 0x17, 0xbc, 0x97, 0x7f, 0xb7, 0x00, 0x39,
+	0xf0, 0xdd, 0x7d, 0xac, 0x27, 0x0a, 0xb5, 0xa4, 0x14, 0x17, 0xa3, 0xfc,
+	0x07, 0xeb, 0xbc, 0x7d, 0x5a, 0xbe, 0x42, 0xd9, 0xea, 0x32, 0x9d, 0x00,
+	0x53, 0xec, 0xc6, 0xbc, 0xee, 0x4d, 0x55, 0x23, 0xad, 0xd4, 0x49, 0xcf,
+	0x7e, 0xd0, 0x16, 0xdd, 0xe3, 0x8a, 0x18, 0xb3, 0x09, 0xd1, 0x67, 0x91,
+	0xd3, 0xda, 0x43, 0xea, 0x6f, 0x1d, 0x7a, 0xb0, 0x8f, 0x3e, 0x3b, 0x10,
+	0xfd, 0x2d, 0x06, 0xeb, 0xae, 0xec, 0xc6, 0xfd, 0x2b, 0xcf, 0x91, 0x80,
+	0xbd, 0x7e, 0x69, 0x27, 0xce, 0x06, 0xb9, 0x5e, 0xde, 0xa1, 0xf2, 0x6e,
+	0xf8, 0xce, 0xd3, 0x43, 0xe9, 0x3e, 0xe9, 0xda, 0x25, 0x67, 0x86, 0x58,
+	0xa3, 0xb5, 0x01, 0x1f, 0x61, 0x79, 0xe7, 0xb4, 0x4b, 0x96, 0xe7, 0xe1,
+	0x5b, 0xe7, 0xd3, 0x0e, 0xff, 0xbe, 0x60, 0x01, 0x21, 0x6d, 0xa1, 0x3e,
+	0xd6, 0xc7, 0x98, 0xbc, 0x58, 0xa7, 0xae, 0xf4, 0x60, 0x7d, 0x3f, 0x74,
+	0x71, 0x1b, 0x6c, 0x48, 0xc7, 0xfe, 0x11, 0xee, 0xf7, 0x14, 0xee, 0x1e,
+	0xfb, 0xb7, 0x77, 0x2a, 0xdd, 0xd0, 0xd3, 0x56, 0x4a, 0x07, 0xed, 0x1f,
+	0xab, 0x2d, 0x1d, 0xe1, 0xf7, 0xc2, 0x69, 0xaf, 0xf1, 0xbb, 0xe1, 0x3e,
+	0xad, 0x50, 0xe1, 0xdf, 0x38, 0x0c, 0xc9, 0x21, 0x8b, 0x7f, 0xff, 0xb3,
+	0x4f, 0x7b, 0xa0, 0x4a, 0x18, 0x1b, 0x7d, 0xd6, 0xe1, 0xcb, 0xb0, 0xe5,
+	0xff, 0x29, 0xdc, 0xea, 0x62, 0xdb, 0x3a, 0xcb, 0xf0, 0xfb, 0x1d, 0xe7,
+	0xc7, 0x4d, 0xdd, 0xe4, 0x34, 0x71, 0x12, 0x27, 0xca, 0xc0, 0xc7, 0x39,
+	0x49, 0x3d, 0x39, 0xd5, 0x4e, 0xa2, 0x14, 0x22, 0x88, 0x84, 0xe5, 0xfc,
+	0xcc, 0x63, 0x14, 0x3c, 0xc8, 0xa6, 0x4e, 0x42, 0x55, 0x94, 0x74, 0x5b,
+	0x27, 0xee, 0xb8, 0x40, 0x5c, 0x80, 0x6a, 0x39, 0x69, 0xe9, 0x86, 0x3d,
+	0xa7, 0x5b, 0xba, 0x00, 0x57, 0x9e, 0xe3, 0xa4, 0x4d, 0xe7, 0xcc, 0x1a,
+	0x03, 0x69, 0x70, 0x41, 0x23, 0x33, 0x6d, 0xe3, 0x66, 0x37, 0x48, 0x5c,
+	0x57, 0x29, 0x83, 0x02, 0x6b, 0x2b, 0xb8, 0xe1, 0xef, 0xe2, 0xf0, 0x3c,
+	0xdf, 0x39, 0x76, 0xd3, 0xc0, 0x44, 0x24, 0xeb, 0x7c, 0xe7, 0x3b, 0xdf,
+	0xff, 0xf7, 0xbe, 0xcf, 0xfb, 0x9b, 0x6e, 0xb9, 0x08, 0x3a, 0xce, 0x8d,
+	0xb5, 0xfa, 0xfe, 0xd6, 0x0e, 0x9f, 0x87, 0x07, 0xfb, 0x7c, 0x19, 0xa5,
+	0x75, 0xc9, 0x9c, 0xd6, 0xa7, 0xbb, 0x0e, 0x7d, 0x7b, 0x16, 0x6b, 0x8a,
+	0xe0, 0x1c, 0x1e, 0xe9, 0xd3, 0x78, 0x64, 0xf0, 0xbd, 0xff, 0xd0, 0x7b,
+	0xdf, 0xa1, 0xf7, 0xde, 0xff, 0xd1, 0x9e, 0xe5, 0xc3, 0xf4, 0xc0, 0x75,
+	0x5a, 0x53, 0x1a, 0xfd, 0xf2, 0x93, 0x6a, 0x39, 0x6f, 0x25, 0xa9, 0x0b,
+	0xcc, 0x88, 0xab, 0x66, 0x9c, 0x36, 0x60, 0x5c, 0x9b, 0xac, 0xae, 0x83,
+	0xe6, 0xb1, 0x8f, 0x76, 0x9b, 0xf1, 0xf2, 0x89, 0x3e, 0xf2, 0x4c, 0x10,
+	0xd7, 0x60, 0xd8, 0xc3, 0x11, 0xb4, 0x73, 0x5f, 0x74, 0x12, 0xe6, 0x39,
+	0xed, 0xbf, 0xa1, 0x0e, 0xe3, 0xaa, 0x9c, 0xce, 0xfd, 0x60, 0x9b, 0x16,
+	0xb9, 0x6d, 0xa7, 0xba, 0xfd, 0xdc, 0x20, 0xd8, 0xbb, 0xa9, 0x3e, 0xea,
+	0x17, 0x2f, 0x38, 0xcd, 0x3a, 0x73, 0x5f, 0x98, 0x77, 0x05, 0xa2, 0x79,
+	0x4a, 0xa4, 0x54, 0x11, 0xb9, 0x86, 0xdf, 0x6f, 0x2a, 0x7e, 0xfc, 0x42,
+	0xd1, 0xd6, 0x9e, 0x96, 0x1b, 0xc5, 0x2f, 0x48, 0x15, 0x32, 0x67, 0xc7,
+	0x71, 0xdd, 0x3b, 0x4e, 0x54, 0x9f, 0xf9, 0x0f, 0xf2, 0x4a, 0x62, 0xe3,
+	0x94, 0x69, 0x6d, 0xf2, 0xc3, 0x75, 0xe6, 0xd5, 0x59, 0xe6, 0x1d, 0x61,
+	0x7e, 0x5b, 0x44, 0xd2, 0xe1, 0x80, 0xd6, 0x4b, 0xe5, 0x69, 0x68, 0x12,
+	0xf8, 0xf6, 0x87, 0xf5, 0xb3, 0x7d, 0xf4, 0xb9, 0x7c, 0xbc, 0xce, 0x77,
+	0x03, 0x4f, 0x43, 0xea, 0x76, 0x00, 0xfa, 0x2b, 0x80, 0xc7, 0xe4, 0xb9,
+	0x73, 0xbf, 0xcf, 0x73, 0x6d, 0xa8, 0xa3, 0x0d, 0xdb, 0x26, 0xb9, 0x11,
+	0xe0, 0xa0, 0x1a, 0xd6, 0xf9, 0x47, 0xf5, 0xb0, 0xc6, 0xe5, 0x40, 0x99,
+	0x7e, 0x7b, 0xf3, 0xa8, 0xc6, 0xe8, 0xd4, 0xee, 0xf7, 0xf4, 0x5e, 0x50,
+	0xce, 0x96, 0x1d, 0xd2, 0xaa, 0x29, 0x3b, 0xe0, 0xb5, 0xeb, 0xb5, 0x37,
+	0xfa, 0x79, 0x57, 0x37, 0x6a, 0xdf, 0xef, 0xf3, 0x6c, 0x34, 0xd6, 0x5d,
+	0xe8, 0xf3, 0xea, 0xa2, 0xbe, 0xcd, 0x45, 0xdb, 0xac, 0x84, 0xbd, 0x7d,
+	0x5b, 0x6a, 0x1b, 0xdf, 0x95, 0x77, 0x8b, 0xdf, 0x91, 0x5f, 0x6c, 0x9c,
+	0x81, 0xce, 0x61, 0x95, 0xb2, 0x90, 0x27, 0x6f, 0xd7, 0x5c, 0xf7, 0x6d,
+	0x67, 0x01, 0xf6, 0x81, 0xeb, 0xfe, 0xd6, 0xd9, 0x93, 0xd8, 0xc4, 0x37,
+	0xb1, 0xe7, 0x0c, 0x78, 0x88, 0x58, 0x98, 0x06, 0xbd, 0x7d, 0xb1, 0x5f,
+	0x3a, 0x42, 0x9a, 0x4e, 0x86, 0x27, 0x5a, 0xb1, 0x07, 0xc3, 0xd7, 0xc3,
+	0xb9, 0x97, 0xe9, 0x7e, 0xd2, 0x8c, 0x51, 0xfb, 0x09, 0xe6, 0x6f, 0x05,
+	0x5f, 0x1c, 0xc5, 0x4f, 0xc9, 0x9d, 0x71, 0xac, 0x75, 0x9c, 0xb4, 0xd7,
+	0x2a, 0xb1, 0xc7, 0xb0, 0x8f, 0x4c, 0x8b, 0xdc, 0xcb, 0x6f, 0xf6, 0xd1,
+	0x9f, 0x77, 0x2f, 0xcf, 0xb2, 0xf1, 0xb9, 0x4e, 0x71, 0xa5, 0x05, 0xf2,
+	0x7b, 0x75, 0xd2, 0xd3, 0x95, 0x7e, 0xad, 0x4e, 0xa0, 0xbd, 0x9d, 0x7d,
+	0x4f, 0x51, 0xb7, 0xcb, 0xba, 0xad, 0xd0, 0xc5, 0xe7, 0xa0, 0x03, 0xa5,
+	0x6a, 0x17, 0xa4, 0x3e, 0x1e, 0x42, 0x1b, 0xea, 0x28, 0x1a, 0x4b, 0x64,
+	0x26, 0xcf, 0x7c, 0x2d, 0xe6, 0x4e, 0x61, 0x8d, 0x0b, 0xc4, 0x0d, 0xae,
+	0xb1, 0x8d, 0x31, 0x38, 0xbf, 0xce, 0x06, 0x8d, 0xb0, 0x8e, 0xf4, 0x9d,
+	0x04, 0x4f, 0x26, 0x29, 0x37, 0x31, 0xde, 0x18, 0xc6, 0x63, 0xb9, 0x13,
+	0xe3, 0x5d, 0x90, 0x94, 0xd3, 0x18, 0x73, 0x0a, 0x6d, 0x88, 0x33, 0x53,
+	0xd0, 0x1f, 0x86, 0xd4, 0xec, 0x7a, 0x18, 0xf2, 0xbb, 0x4f, 0x66, 0xcd,
+	0x23, 0x07, 0xf6, 0x98, 0xd5, 0xf6, 0x81, 0x61, 0x8c, 0xf9, 0x6b, 0xea,
+	0x3c, 0xb0, 0x26, 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x6a, 0x7d, 0x0d, 0x38,
+	0xb5, 0xf6, 0x61, 0xca, 0x39, 0x2b, 0x33, 0x61, 0xae, 0x89, 0xf5, 0x61,
+	0xac, 0x99, 0x7e, 0xac, 0x67, 0x81, 0x43, 0x47, 0xfc, 0x3a, 0xb6, 0x15,
+	0x23, 0x85, 0xb3, 0xf7, 0xec, 0x5a, 0xd6, 0x7d, 0x56, 0x52, 0x6b, 0x19,
+	0x99, 0xd7, 0xfd, 0x78, 0x86, 0x83, 0x5a, 0xf7, 0x20, 0xaf, 0xc6, 0x7a,
+	0x70, 0x96, 0x89, 0x07, 0x36, 0x70, 0xb4, 0x47, 0xcb, 0xcc, 0x7e, 0x8f,
+	0x67, 0xf1, 0xad, 0x87, 0x77, 0xd4, 0x26, 0xb1, 0x6f, 0x40, 0x46, 0xe6,
+	0x1b, 0xf5, 0x21, 0xf9, 0x24, 0xdf, 0xd1, 0xcf, 0x38, 0xcb, 0xdd, 0xbc,
+	0x29, 0x1f, 0xe7, 0x75, 0x2c, 0x74, 0x31, 0x20, 0xd6, 0x79, 0xcf, 0x3e,
+	0x1f, 0x59, 0x5c, 0x55, 0xfc, 0x3e, 0x72, 0x7e, 0x4b, 0x05, 0xd1, 0x36,
+	0x84, 0x76, 0x5c, 0x87, 0x29, 0x73, 0xf9, 0xbf, 0xb9, 0x4b, 0xa3, 0xae,
+	0x3b, 0xaf, 0xf3, 0xc3, 0x12, 0xe6, 0xaa, 0x6a, 0xe8, 0xe4, 0x71, 0xc9,
+	0x87, 0xdb, 0x31, 0x57, 0xc2, 0xdc, 0x52, 0x23, 0x58, 0x0f, 0xcb, 0x3d,
+	0xe4, 0x89, 0xc8, 0x9e, 0x70, 0x7c, 0x2b, 0xbd, 0xa9, 0x12, 0xd1, 0x61,
+	0x65, 0x25, 0x73, 0xf8, 0xb5, 0x28, 0x1d, 0x47, 0x8c, 0x44, 0x15, 0x78,
+	0x17, 0x7b, 0xb2, 0x4f, 0xba, 0x6e, 0xda, 0x66, 0x7d, 0xc2, 0x0c, 0x29,
+	0xfa, 0x5b, 0x3a, 0x74, 0xbc, 0xf1, 0x72, 0x6f, 0xc2, 0x3c, 0xa9, 0x8e,
+	0xfb, 0xef, 0x53, 0xc0, 0xcc, 0xe6, 0x78, 0x67, 0x36, 0x95, 0x29, 0x2f,
+	0xe5, 0x13, 0xd1, 0x65, 0x65, 0x65, 0x30, 0x66, 0x66, 0x56, 0x11, 0x37,
+	0x12, 0x66, 0x87, 0xa2, 0x4f, 0xb4, 0x5d, 0xef, 0x3b, 0x8d, 0xfe, 0x09,
+	0xd5, 0xe2, 0xaf, 0x87, 0xf7, 0xf5, 0xe3, 0x7e, 0x8f, 0x67, 0x88, 0x39,
+	0xa3, 0xc0, 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x64, 0x6c, 0x62, 0x54,
+	0x63, 0xe8, 0xfd, 0x53, 0x7f, 0x47, 0x1d, 0xca, 0x25, 0xd6, 0xc5, 0x7d,
+	0x7e, 0x1b, 0xd5, 0x3a, 0xf3, 0xfd, 0x53, 0x59, 0x9d, 0xc7, 0x58, 0x57,
+	0x31, 0x7f, 0xdf, 0xcd, 0x3b, 0x8b, 0xa6, 0x9c, 0x47, 0x38, 0xce, 0x5a,
+	0x60, 0xba, 0x5d, 0x98, 0x23, 0x3a, 0x57, 0x6c, 0xd0, 0x06, 0xfd, 0x01,
+	0xcc, 0x17, 0x68, 0xc4, 0xbd, 0x2f, 0x88, 0x31, 0x11, 0x3c, 0x40, 0x27,
+	0xd0, 0x35, 0xa1, 0xa3, 0x56, 0x30, 0x4e, 0x6e, 0x5d, 0xb2, 0x5e, 0x7f,
+	0x09, 0x32, 0x27, 0x35, 0x57, 0xf9, 0xb4, 0x31, 0x38, 0x37, 0xe6, 0xc0,
+	0xfb, 0xfd, 0x53, 0xa4, 0x4f, 0x9e, 0x4d, 0x54, 0xcd, 0x6d, 0x70, 0x3d,
+	0x83, 0x32, 0xbf, 0x3e, 0x24, 0xcb, 0xf8, 0xad, 0xae, 0x7b, 0xf7, 0xb6,
+	0x0d, 0xdd, 0x7a, 0x3e, 0x6f, 0x6a, 0x7e, 0x5d, 0x76, 0x18, 0x33, 0x01,
+	0xaf, 0xe8, 0x9c, 0x2a, 0xf6, 0x65, 0x5e, 0xe1, 0x10, 0xe5, 0xa3, 0x53,
+	0x87, 0x5c, 0xdd, 0xae, 0x51, 0x4f, 0x65, 0xbd, 0x35, 0x15, 0x0d, 0x74,
+	0xc9, 0x2a, 0xf0, 0xae, 0x0c, 0xd9, 0x99, 0x7b, 0x25, 0x24, 0xcb, 0x79,
+	0x1d, 0x4f, 0x8e, 0xfe, 0x5e, 0x39, 0x52, 0xad, 0x4d, 0xca, 0x6e, 0x2d,
+	0xae, 0xbf, 0x51, 0xae, 0xe5, 0x5e, 0x37, 0xe4, 0xf9, 0x51, 0x9d, 0x57,
+	0x17, 0x2f, 0x4b, 0xef, 0x00, 0x75, 0x9e, 0x2d, 0x9d, 0x63, 0x07, 0xec,
+	0x80, 0xce, 0xf1, 0x33, 0xe8, 0x1c, 0xef, 0x40, 0xe7, 0xf8, 0x69, 0x11,
+	0xf8, 0x52, 0x4c, 0xfb, 0xf8, 0xbf, 0x08, 0x1c, 0xa2, 0xac, 0xb6, 0xce,
+	0xe0, 0x4e, 0x17, 0xb3, 0xa0, 0xc1, 0x5b, 0x92, 0x06, 0xde, 0xa6, 0xe4,
+	0xfa, 0xc6, 0xbc, 0xec, 0x6c, 0x78, 0x79, 0xc8, 0x1f, 0x30, 0x07, 0x6c,
+	0x9c, 0xf7, 0x14, 0x07, 0x0e, 0x1d, 0x91, 0xd8, 0x49, 0xe2, 0x47, 0x50,
+	0x36, 0x0b, 0xef, 0x68, 0x1c, 0xda, 0x2c, 0xb0, 0x1c, 0x10, 0x9d, 0x4f,
+	0xb6, 0xb0, 0x27, 0x65, 0xe7, 0x97, 0xa8, 0x3f, 0xa6, 0x7d, 0x40, 0x9e,
+	0x4f, 0x9e, 0x78, 0xf9, 0x67, 0xff, 0xee, 0x95, 0xce, 0xb3, 0x5b, 0x32,
+	0xbb, 0xd0, 0xae, 0x81, 0x5d, 0xc3, 0x5e, 0xcc, 0x5b, 0xfd, 0x05, 0x6d,
+	0x30, 0x47, 0xb1, 0x4b, 0xb6, 0x21, 0x43, 0xea, 0xf1, 0x2e, 0xad, 0xfb,
+	0xd5, 0xe3, 0x43, 0x3a, 0x17, 0x97, 0xe3, 0xe4, 0x0a, 0xb6, 0xac, 0x14,
+	0xac, 0x68, 0x16, 0xf4, 0xb7, 0x0b, 0x5b, 0xed, 0x3a, 0xee, 0x60, 0x07,
+	0x67, 0x70, 0xa3, 0x46, 0x39, 0x7f, 0x57, 0x63, 0xef, 0x66, 0xed, 0x4f,
+	0x18, 0xc7, 0x3a, 0x93, 0x94, 0x3f, 0xf6, 0x13, 0x03, 0xe9, 0x8f, 0x9a,
+	0xd1, 0xfd, 0xbd, 0x7e, 0xd7, 0xd1, 0x76, 0xa7, 0x46, 0x3c, 0x16, 0xb9,
+	0x94, 0xb7, 0x21, 0x4b, 0x5e, 0x8f, 0x50, 0x07, 0x28, 0xa9, 0x46, 0x3f,
+	0xd7, 0x5f, 0xb3, 0xeb, 0x1e, 0xb5, 0xb9, 0xae, 0xb8, 0x8f, 0xdb, 0x94,
+	0xfd, 0x7b, 0x5a, 0xee, 0xe7, 0x8b, 0x67, 0xe5, 0x2d, 0xdc, 0xb7, 0xa7,
+	0xe3, 0x64, 0xe4, 0x4d, 0xe8, 0x78, 0xb5, 0x62, 0x23, 0x6f, 0x7b, 0x1a,
+	0xe7, 0x64, 0xa9, 0x95, 0x2b, 0x2f, 0xcb, 0xe5, 0xab, 0xfb, 0xea, 0xa5,
+	0xab, 0x31, 0xf5, 0xf2, 0x95, 0x61, 0x95, 0xbb, 0xe2, 0xba, 0xff, 0x74,
+	0x96, 0xe4, 0xdd, 0x0d, 0x57, 0x4e, 0x3b, 0xc6, 0x40, 0x40, 0x1a, 0xb9,
+	0x75, 0xae, 0x1b, 0x04, 0x36, 0xdf, 0xe8, 0x75, 0xdd, 0x47, 0xc7, 0xc7,
+	0x25, 0xde, 0x4b, 0x1d, 0xe5, 0xf3, 0x11, 0xe6, 0xbb, 0x12, 0x73, 0x52,
+	0xb6, 0x7d, 0xbe, 0xac, 0x14, 0xf0, 0xad, 0xcb, 0xd3, 0x5f, 0x1e, 0x3b,
+	0xe6, 0xc7, 0x4a, 0x7e, 0xf4, 0x22, 0x7d, 0xc9, 0x91, 0xff, 0xf2, 0x25,
+	0x9b, 0x72, 0xae, 0xf0, 0x19, 0xf4, 0x0f, 0xcb, 0xb7, 0x0a, 0xa1, 0x43,
+	0x65, 0x13, 0xcf, 0x31, 0x95, 0x2b, 0xdc, 0x73, 0x87, 0x75, 0xcc, 0x00,
+	0x3a, 0x89, 0xe9, 0xba, 0xcb, 0x0e, 0xe7, 0xeb, 0xc2, 0x7c, 0x7b, 0xe6,
+	0x31, 0xc8, 0xff, 0xd3, 0x5a, 0x3e, 0x9f, 0x53, 0xb0, 0x7d, 0xc1, 0xdf,
+	0x61, 0x99, 0x2d, 0x40, 0xc6, 0x2b, 0xe6, 0x9c, 0x52, 0x57, 0xb0, 0x22,
+	0xcb, 0xc0, 0x8e, 0x25, 0xe0, 0xcd, 0x93, 0x3a, 0xb6, 0xda, 0xa3, 0xb1,
+	0x67, 0x85, 0xe5, 0x8c, 0x24, 0xcb, 0x4e, 0xb7, 0x3e, 0xbf, 0xfd, 0xdd,
+	0x57, 0x23, 0xde, 0x9d, 0x83, 0x8f, 0x33, 0x4a, 0xda, 0x60, 0x03, 0xcd,
+	0x6c, 0x2d, 0x80, 0x27, 0x22, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x75, 0xc8,
+	0xef, 0xba, 0xf6, 0x23, 0x7a, 0xf1, 0x8a, 0xba, 0xc9, 0x76, 0xcf, 0xa0,
+	0x5f, 0xbb, 0xa4, 0xae, 0xb4, 0x69, 0x5c, 0x7d, 0xb8, 0x2e, 0x09, 0x3d,
+	0xe4, 0x69, 0x94, 0x03, 0xa8, 0x8b, 0xfa, 0x65, 0x03, 0xe5, 0x45, 0x94,
+	0x5b, 0xf0, 0x64, 0x9b, 0x11, 0xe8, 0x15, 0x78, 0xbe, 0x81, 0xf1, 0xc6,
+	0xb1, 0xe6, 0x8c, 0x29, 0x1f, 0x9d, 0xa2, 0x2c, 0x19, 0x53, 0xcc, 0x4b,
+	0x5e, 0xb6, 0xf1, 0xac, 0x0e, 0xab, 0x99, 0x35, 0x96, 0xf1, 0x2c, 0x79,
+	0xdf, 0x1f, 0xc2, 0x24, 0xf4, 0x49, 0x5d, 0xf5, 0x30, 0xe9, 0xa3, 0x26,
+	0x26, 0xb1, 0xae, 0x5d, 0x66, 0xaf, 0x90, 0xd7, 0x4d, 0xd0, 0x5b, 0x87,
+	0xcc, 0x5c, 0x0d, 0x6b, 0x7d, 0xb4, 0x0c, 0x5a, 0xdc, 0x06, 0x5d, 0x6d,
+	0x82, 0xa6, 0x52, 0x05, 0x6b, 0x6a, 0x51, 0x45, 0xb5, 0x2f, 0xe0, 0x09,
+	0xd0, 0x6b, 0xf0, 0x15, 0xea, 0xa2, 0xe4, 0xe5, 0x38, 0x68, 0x4f, 0xdc,
+	0xa0, 0x6d, 0xa7, 0xe3, 0xca, 0x06, 0x0d, 0x82, 0x2e, 0x0b, 0x1e, 0x4f,
+	0xbf, 0xa7, 0x34, 0xae, 0x4e, 0xdd, 0x96, 0x44, 0xf2, 0xb6, 0x58, 0xc0,
+	0x02, 0xcb, 0xf9, 0x50, 0x1c, 0x8c, 0x39, 0x29, 0xd7, 0x30, 0x8f, 0x01,
+	0xfe, 0x1e, 0x3d, 0xa1, 0xf9, 0x7b, 0x4a, 0x02, 0x87, 0x79, 0x1c, 0xf4,
+	0x06, 0x0c, 0xf2, 0x78, 0x3a, 0xe9, 0xd3, 0xe8, 0xd7, 0xc1, 0xbf, 0x16,
+	0x2c, 0xb1, 0xb0, 0xac, 0x82, 0xff, 0xb7, 0xf1, 0xfd, 0x66, 0x6d, 0x44,
+	0xad, 0xac, 0x29, 0x3f, 0x97, 0xe4, 0x19, 0xe8, 0xc9, 0xb7, 0x70, 0x76,
+	0x9d, 0x5a, 0x77, 0x8f, 0x8d, 0x33, 0x7e, 0x96, 0x56, 0x97, 0xed, 0x93,
+	0xb2, 0x3f, 0x36, 0x89, 0xf2, 0x31, 0x3c, 0x0d, 0x9c, 0x43, 0x48, 0xc7,
+	0xbf, 0x37, 0xf3, 0x8e, 0xf2, 0xfe, 0x67, 0x61, 0x42, 0xe7, 0xe7, 0x1b,
+	0x76, 0x2f, 0xbe, 0xd3, 0x17, 0xc3, 0xbd, 0x41, 0x67, 0x52, 0x11, 0x9d,
+	0x6f, 0x5a, 0x86, 0x2e, 0xb1, 0x85, 0xf1, 0xde, 0xa7, 0x2f, 0xaf, 0x0a,
+	0x1e, 0x1e, 0xfb, 0x97, 0x9b, 0x0c, 0x33, 0x47, 0xfd, 0x6e, 0xc4, 0x93,
+	0x7f, 0x9f, 0xb8, 0xfb, 0xf6, 0xca, 0x94, 0x81, 0x97, 0x5b, 0x66, 0x18,
+	0x6d, 0x21, 0xcb, 0x20, 0x8b, 0x4a, 0x9a, 0x7e, 0xd9, 0xce, 0xeb, 0x9b,
+	0xab, 0x26, 0xcc, 0x0f, 0xc4, 0xeb, 0xbb, 0x6a, 0x53, 0xee, 0xb4, 0x03,
+	0x5f, 0xa2, 0x5a, 0xaf, 0x7c, 0xdf, 0xce, 0x02, 0x15, 0xac, 0x68, 0x1a,
+	0x34, 0xda, 0x26, 0x56, 0x7c, 0x4e, 0x1e, 0xcc, 0xbb, 0xac, 0xfb, 0xb2,
+	0x6d, 0xa3, 0x6f, 0x63, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b,
+	0x36, 0x35, 0x8d, 0xd6, 0xab, 0xdd, 0x03, 0x1e, 0x8d, 0x36, 0xf6, 0x11,
+	0xfe, 0x3f, 0xfb, 0x20, 0x9d, 0x38, 0xca, 0xcb, 0xbb, 0xc0, 0xb3, 0xca,
+	0xf3, 0x1c, 0x01, 0x6d, 0x1c, 0xa4, 0x9f, 0x86, 0x6f, 0xd1, 0xa3, 0x9f,
+	0x47, 0x9b, 0xf4, 0x43, 0xba, 0xe9, 0x90, 0xd9, 0xab, 0xb6, 0xcc, 0x17,
+	0xf4, 0x7d, 0x43, 0xd7, 0xa4, 0xcf, 0x68, 0x12, 0x74, 0x43, 0x5a, 0x27,
+	0x6f, 0x99, 0x52, 0x02, 0x1d, 0x95, 0x80, 0x4f, 0x25, 0xd0, 0x54, 0x19,
+	0xf8, 0x56, 0x02, 0xbe, 0x95, 0x6a, 0x56, 0xbc, 0x82, 0x3d, 0x53, 0x66,
+	0x6f, 0x81, 0x8e, 0xb6, 0x6b, 0xbc, 0x7f, 0xbd, 0x66, 0x93, 0x72, 0xf0,
+	0x66, 0xf3, 0xee, 0xff, 0x81, 0xbb, 0x1f, 0x92, 0x5d, 0xd8, 0x2d, 0x6f,
+	0x15, 0xc7, 0x80, 0x49, 0x02, 0x8c, 0x72, 0x40, 0x1b, 0x53, 0x72, 0xbd,
+	0x38, 0x2d, 0x3b, 0x90, 0x4f, 0x37, 0x36, 0x62, 0xd0, 0xa7, 0x23, 0xb2,
+	0xf2, 0xda, 0xa8, 0xbc, 0xb9, 0xa1, 0x64, 0x09, 0xf4, 0x9b, 0xdb, 0xa4,
+	0xdf, 0x1d, 0xf4, 0x5c, 0xea, 0xd0, 0x71, 0xfa, 0xd9, 0x8a, 0xe7, 0x7f,
+	0x9f, 0xab, 0x74, 0xca, 0x7c, 0xc5, 0x94, 0xc7, 0x2b, 0xdd, 0xf2, 0xe5,
+	0x4a, 0x58, 0x4e, 0xc3, 0x0e, 0xfc, 0x4a, 0x65, 0x50, 0x9e, 0xac, 0x0c,
+	0xc9, 0x57, 0xab, 0x51, 0xf9, 0x5a, 0xd5, 0x96, 0x4c, 0x35, 0x2e, 0xe9,
+	0xea, 0x98, 0x3c, 0x51, 0xa5, 0x5f, 0x1d, 0xf3, 0xe1, 0x37, 0xd3, 0xf4,
+	0x57, 0x70, 0x5d, 0x41, 0xac, 0x2b, 0xae, 0xe6, 0x74, 0x9c, 0x52, 0x32,
+	0x9e, 0xcf, 0x43, 0xe4, 0x39, 0x8c, 0x75, 0xf1, 0x35, 0x25, 0x65, 0x3d,
+	0x7f, 0xe3, 0xff, 0x46, 0x42, 0xda, 0x36, 0x7a, 0xae, 0x34, 0x88, 0x36,
+	0x90, 0x7b, 0xf9, 0x86, 0xef, 0xa3, 0xe1, 0xf3, 0x6f, 0xd8, 0x5e, 0x86,
+	0xf6, 0x5b, 0xdf, 0xa4, 0xed, 0xa5, 0xcf, 0x9e, 0xf8, 0x41, 0x3b, 0xe7,
+	0x9a, 0xf6, 0x9b, 0x3c, 0x88, 0x6d, 0x34, 0xe6, 0xbd, 0x98, 0x79, 0xf8,
+	0xff, 0x53, 0xbc, 0x18, 0xd5, 0xb9, 0xea, 0x20, 0xff, 0x4f, 0x05, 0x6b,
+	0xf9, 0xf4, 0xdc, 0xf1, 0xf9, 0xe2, 0xac, 0x7a, 0xbc, 0x48, 0x8d, 0xc6,
+	0x95, 0x8b, 0xcd, 0x9c, 0xb8, 0x2f, 0xc9, 0xa6, 0x13, 0xd2, 0x6b, 0xf0,
+	0xf3, 0x1f, 0x75, 0x7e, 0xdc, 0xec, 0x09, 0xd2, 0x1f, 0x63, 0x6f, 0x9d,
+	0x7e, 0x3c, 0x01, 0xba, 0xad, 0x63, 0xca, 0xa5, 0x8a, 0xe7, 0xb3, 0x5a,
+	0xd1, 0xf4, 0xf2, 0x2b, 0xd0, 0x1c, 0x63, 0x0e, 0xde, 0x33, 0x5b, 0xf2,
+	0xfa, 0xce, 0xe0, 0xde, 0x60, 0x8f, 0x63, 0xbf, 0x46, 0x37, 0xe7, 0xe2,
+	0xff, 0xe9, 0xa0, 0xec, 0xaf, 0x97, 0xb9, 0xc6, 0xb6, 0xa6, 0x45, 0x2f,
+	0xae, 0x1b, 0x97, 0x17, 0x70, 0x7e, 0x65, 0x93, 0xeb, 0x0f, 0x4a, 0x39,
+	0x4e, 0xdb, 0x96, 0xf8, 0x7d, 0x42, 0x4a, 0x98, 0xa7, 0x1c, 0x6f, 0xf8,
+	0xc3, 0x3c, 0x9c, 0x2d, 0x9b, 0x0f, 0xe6, 0x5d, 0x2c, 0x1d, 0xc7, 0x3b,
+	0xea, 0xe2, 0xd0, 0x99, 0x16, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0x56,
+	0xf0, 0x8c, 0xf8, 0x75, 0xd5, 0x01, 0xad, 0xab, 0x4f, 0x3f, 0xe8, 0xb7,
+	0x54, 0xb2, 0xb2, 0xa9, 0x40, 0x42, 0x19, 0xaf, 0xfe, 0x7c, 0x80, 0x98,
+	0x7b, 0xdc, 0xe6, 0x2f, 0x24, 0x7f, 0x35, 0xb5, 0x4f, 0xc1, 0xff, 0x76,
+	0x44, 0x9e, 0x32, 0x99, 0xc7, 0x9e, 0x54, 0xb3, 0xc5, 0x9c, 0x9f, 0xe3,
+	0x9b, 0x50, 0xc7, 0xcb, 0x37, 0x07, 0xbc, 0x9c, 0x77, 0x8e, 0x7d, 0x30,
+	0xcf, 0xfd, 0x20, 0x9d, 0x30, 0xdf, 0xbd, 0xbd, 0xf9, 0x3f, 0x52, 0xe5,
+	0x3c, 0xf0, 0xce, 0x6e, 0xd1, 0xfc, 0x98, 0xab, 0xfe, 0xdb, 0xdd, 0xd3,
+	0xfc, 0xdc, 0xf0, 0x31, 0xfc, 0x6e, 0x80, 0xb6, 0x2d, 0x71, 0xe3, 0x92,
+	0x97, 0x3b, 0xaa, 0x6d, 0x68, 0x60, 0x05, 0xea, 0xc8, 0xab, 0xe0, 0x93,
+	0x66, 0x5b, 0xfe, 0xfd, 0x07, 0x69, 0x3f, 0x51, 0x42, 0x6c, 0x67, 0x00,
+	0x00, 0x00 };
+
+static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
+	0x08004050, 0x08003f50, 0x08003ff4, 0x0800400c, 0x08004024, 0x08004044,
+	0x08004050, 0x08004050, 0x08003f58, 0x00000000, 0x08004a0c, 0x08004a44,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004a7c, 0x08004c40,
+	0x08004b88, 0x08004bc0, 0x08004c40, 0x08004b10, 0x08004c40, 0x08004c40,
+	0x08004bc0, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c00,
+	0x08004c40, 0x08004c00, 0x08004b88, 0x08004c40, 0x08004c40, 0x08004c00,
+	0x08004c00, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+	0x08004aec, 0x00000000, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
+	0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070,
+	0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
+	0x08006064, 0x00000000, 0x00000000 };
+static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
+static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_rxp_fw_09 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
 	.start_addr			= 0x08003184,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x673c,
+	.text_len			= 0x6768,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_RXP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_RXP_b09FwText),
 
-	.data_addr			= 0x080069e0,
+	.data_addr			= 0x08006a00,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_RXP_b09FwData,
 
-	.sbss_addr			= 0x080069e0,
-	.sbss_len			= 0x2c,
+	.sbss_addr			= 0x08006a00,
+	.sbss_len			= 0x20,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_RXP_b09FwSbss,
 
-	.bss_addr			= 0x08006a10,
+	.bss_addr			= 0x08006a20,
 	.bss_len			= 0x13dc,
 	.bss_index			= 0x0,
 	.bss				= bnx2_RXP_b09FwBss,
 
-	.rodata_addr			= 0x08006740,
+	.rodata_addr			= 0x08006768,
 	.rodata_len			= 0x278,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_RXP_b09FwRodata,
 };
 
 static u8 bnx2_TPAT_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0xdb, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x58, 0x5d, 0x6c,
-	0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xbb, 0x13, 0x77, 0xed, 0xbd, 0x49, 0x97,
-	0x6a, 0x13, 0xb9, 0x74, 0xc6, 0x1e, 0x3b, 0x8b, 0x1c, 0x35, 0x93, 0xb0,
-	0x24, 0x16, 0x5a, 0xd1, 0xc9, 0xcc, 0xae, 0x6b, 0xe5, 0x29, 0x86, 0xbc,
-	0xf1, 0xb2, 0xac, 0xed, 0x46, 0x54, 0x48, 0x4d, 0x51, 0x84, 0x22, 0x81,
-	0x94, 0x65, 0x76, 0x53, 0x40, 0x5a, 0x65, 0xc1, 0xa0, 0x04, 0x21, 0x84,
-	0x22, 0x9b, 0x66, 0x91, 0x58, 0x3c, 0x4d, 0xe9, 0x6b, 0x94, 0xbc, 0x90,
-	0x96, 0x17, 0x9e, 0x4b, 0x9e, 0xac, 0x02, 0x12, 0x0f, 0xa8, 0x8a, 0x78,
-	0x40, 0x15, 0x0d, 0x1e, 0xbe, 0x33, 0x3f, 0x9b, 0x5d, 0xd7, 0x29, 0x79,
-	0xa8, 0x84, 0xa5, 0xf1, 0xcc, 0xfd, 0x39, 0xf7, 0xe7, 0x7c, 0xdf, 0x77,
-	0xee, 0xb9, 0x5b, 0x92, 0x69, 0x82, 0xd2, 0xbf, 0x49, 0x3c, 0x97, 0xbe,
-	0x71, 0xf1, 0xd2, 0xe2, 0x8b, 0x27, 0x4d, 0x3a, 0x71, 0xe2, 0x45, 0xe9,
-	0x19, 0x43, 0xa6, 0xcf, 0xe0, 0x4f, 0x21, 0x12, 0xd9, 0xf8, 0xfc, 0x90,
-	0x21, 0x57, 0x6f, 0x4e, 0x7b, 0x36, 0x19, 0x4a, 0xd5, 0x79, 0x61, 0xd5,
-	0x26, 0x72, 0x07, 0x0b, 0xa6, 0x4f, 0xff, 0x89, 0x5a, 0x45, 0x95, 0xb8,
-	0xfe, 0xf9, 0xea, 0xa3, 0xe3, 0x77, 0x4e, 0x5b, 0x0f, 0x6f, 0x2a, 0x64,
-	0x88, 0x6a, 0xc3, 0x10, 0xf3, 0x64, 0x4c, 0xc3, 0xe6, 0x97, 0x47, 0x57,
-	0x34, 0x9a, 0xca, 0xc6, 0x12, 0x14, 0xf4, 0x0c, 0xaa, 0x77, 0x31, 0x8e,
-	0x7d, 0x59, 0xf2, 0x43, 0x55, 0xf2, 0x6f, 0x18, 0x24, 0x57, 0x5d, 0xc9,
-	0x0b, 0x6d, 0xb4, 0x49, 0xe4, 0x39, 0x39, 0x72, 0x45, 0x14, 0x7d, 0xd3,
-	0x91, 0x49, 0xb6, 0x77, 0xa3, 0xd9, 0xb9, 0x25, 0xc9, 0xeb, 0x2f, 0x4b,
-	0x7e, 0xdf, 0xe3, 0x7d, 0x63, 0x1d, 0x4b, 0x92, 0xdb, 0xe7, 0x77, 0xd5,
-	0xf0, 0xbb, 0x53, 0xd4, 0x28, 0x52, 0x41, 0xb6, 0xd9, 0xd6, 0x24, 0xdf,
-	0x59, 0x28, 0x29, 0x34, 0x8b, 0xe7, 0x00, 0xad, 0x3b, 0x94, 0xf7, 0x1c,
-	0x52, 0x15, 0x5b, 0x26, 0xbf, 0x28, 0xd1, 0xaf, 0x2b, 0x1a, 0x9e, 0xb3,
-	0x52, 0xad, 0xbf, 0x96, 0x8e, 0x53, 0xa4, 0x36, 0xd6, 0xd2, 0x2c, 0xf2,
-	0xda, 0x12, 0x7b, 0xcf, 0x59, 0x10, 0x32, 0xcd, 0xe2, 0x99, 0xc4, 0x77,
-	0x13, 0xfd, 0x34, 0xf2, 0x2a, 0x7b, 0xdb, 0x0e, 0xe0, 0x1b, 0xeb, 0xc4,
-	0x58, 0x5e, 0xbc, 0x0e, 0x13, 0xeb, 0xb0, 0xa9, 0xd3, 0x5b, 0xc6, 0x3e,
-	0xe6, 0x4a, 0x4d, 0xd2, 0xa9, 0x13, 0xaf, 0x7d, 0x92, 0x02, 0xa1, 0x50,
-	0x70, 0x4c, 0x23, 0xf7, 0x9c, 0x8a, 0xf2, 0x21, 0x6a, 0x09, 0x09, 0x7d,
-	0x3a, 0x29, 0x7e, 0x39, 0xb4, 0xeb, 0xa8, 0x2f, 0x50, 0x50, 0x3c, 0x28,
-	0xc9, 0xd5, 0xef, 0xa1, 0x7e, 0x4e, 0x34, 0xe9, 0xbb, 0x78, 0x4b, 0x28,
-	0x1f, 0xe4, 0xf1, 0x50, 0x96, 0x48, 0xb1, 0x49, 0x78, 0xa1, 0x49, 0xed,
-	0x30, 0xb3, 0xe5, 0xfa, 0xa4, 0xae, 0x15, 0xee, 0xc5, 0x0e, 0xfd, 0x7a,
-	0x75, 0x6a, 0x08, 0x6a, 0xa9, 0x55, 0xf4, 0xe9, 0xd9, 0xa2, 0x06, 0x9c,
-	0xdc, 0x18, 0xcf, 0x97, 0xb8, 0x9e, 0xff, 0x50, 0x6f, 0x92, 0x52, 0xb5,
-	0x85, 0x4f, 0x5f, 0xa6, 0xa4, 0x8d, 0xf7, 0x29, 0x63, 0x6f, 0xa7, 0xd2,
-	0x72, 0x51, 0x78, 0x37, 0xbe, 0x48, 0x6e, 0xec, 0x1f, 0x03, 0xdf, 0x02,
-	0x7b, 0xd4, 0x81, 0x75, 0xe0, 0xca, 0xd4, 0x2a, 0x19, 0x64, 0x2d, 0xae,
-	0xa1, 0xe5, 0x6f, 0x5d, 0x05, 0x7e, 0x67, 0xdc, 0xd4, 0xd4, 0x8e, 0x71,
-	0xfe, 0x23, 0xd6, 0xd9, 0x12, 0x06, 0xf0, 0x6e, 0x9c, 0x8f, 0xa2, 0x37,
-	0x9d, 0x28, 0xd2, 0xab, 0x76, 0xf9, 0x16, 0x2d, 0x94, 0x34, 0x9a, 0x17,
-	0x78, 0xc3, 0x8f, 0x36, 0x7c, 0xa5, 0x65, 0xeb, 0xc9, 0x78, 0x86, 0xbf,
-	0xcb, 0x12, 0x96, 0x42, 0x1f, 0x74, 0xdf, 0x63, 0x7f, 0x94, 0x97, 0x62,
-	0x9b, 0x28, 0xda, 0x5c, 0xfc, 0x34, 0x9b, 0xef, 0xa7, 0x36, 0x51, 0x54,
-	0xaf, 0xf0, 0xbc, 0x16, 0xf6, 0xcc, 0x5c, 0x25, 0xaa, 0x0f, 0x1c, 0xa3,
-	0xd9, 0xc5, 0xfa, 0x6c, 0xbc, 0x07, 0x25, 0xec, 0xc1, 0x2a, 0x9b, 0x92,
-	0x41, 0x81, 0x1d, 0xbd, 0x00, 0x7e, 0xb8, 0xbe, 0x6d, 0xbd, 0xef, 0x2b,
-	0x05, 0xda, 0x72, 0xf2, 0xd4, 0x09, 0x4b, 0x14, 0x84, 0x1d, 0xf2, 0x42,
-	0x19, 0x73, 0x14, 0x68, 0xd3, 0x7e, 0x18, 0xd5, 0x1d, 0x07, 0x7e, 0x21,
-	0xb6, 0x2b, 0xd5, 0x69, 0x1a, 0xed, 0x0b, 0x62, 0x8d, 0x1c, 0x60, 0x21,
-	0xc3, 0x37, 0xb3, 0xf1, 0x77, 0x10, 0x3a, 0x68, 0xa7, 0x96, 0x5c, 0xb1,
-	0x44, 0x40, 0x56, 0xc9, 0x53, 0x48, 0xc8, 0x55, 0x81, 0x3e, 0x2d, 0xaa,
-	0x85, 0x06, 0xed, 0x28, 0x97, 0x63, 0x7e, 0xb7, 0x7b, 0x3b, 0xd1, 0x9d,
-	0xa3, 0x25, 0xba, 0x1b, 0x16, 0xe9, 0x76, 0x48, 0x72, 0xd3, 0x01, 0x37,
-	0x8a, 0x82, 0xde, 0x0a, 0x47, 0xf7, 0xf2, 0x1b, 0xec, 0x25, 0x38, 0xa2,
-	0x40, 0x83, 0xab, 0xce, 0x3d, 0x30, 0xc8, 0x02, 0x46, 0x2d, 0xec, 0x3d,
-	0x7b, 0xf3, 0xbe, 0x76, 0xa6, 0x57, 0x6d, 0xeb, 0x87, 0x3e, 0xa3, 0x76,
-	0x4d, 0x43, 0xed, 0x5e, 0x7f, 0x0c, 0x30, 0x86, 0xa0, 0xab, 0xd0, 0x93,
-	0x0c, 0xbf, 0xcc, 0x6c, 0x1b, 0xd4, 0xef, 0xe6, 0xc8, 0xdc, 0x54, 0xa9,
-	0xd9, 0x2b, 0x92, 0x33, 0x6f, 0x99, 0x24, 0xcb, 0x45, 0x99, 0x54, 0x9a,
-	0xd9, 0x8c, 0x68, 0x09, 0xeb, 0xb8, 0x6f, 0xff, 0x48, 0xa7, 0xa9, 0xc0,
-	0xd1, 0x89, 0xfb, 0x18, 0x34, 0x73, 0xcb, 0x90, 0xfc, 0x1e, 0xef, 0x83,
-	0x7d, 0x6e, 0xa4, 0x3e, 0x57, 0x25, 0xef, 0x46, 0x8e, 0x66, 0x37, 0xfe,
-	0x11, 0x79, 0x36, 0x7c, 0x0d, 0x9e, 0xaf, 0x56, 0xbe, 0xa0, 0xd0, 0x04,
-	0xea, 0x36, 0xb9, 0xed, 0x61, 0x5a, 0xcf, 0x63, 0x44, 0x91, 0xe7, 0x3c,
-	0x4b, 0x1e, 0xf3, 0xff, 0x3c, 0xdb, 0xe4, 0x68, 0x66, 0x83, 0x75, 0x83,
-	0xf7, 0x26, 0x97, 0x79, 0x6d, 0x07, 0xa8, 0x89, 0x1d, 0x35, 0xcb, 0x45,
-	0xf8, 0x41, 0x8e, 0x35, 0xd2, 0xc4, 0x8e, 0x65, 0x7b, 0x02, 0x6f, 0x9e,
-	0xef, 0xac, 0x92, 0xf0, 0x9d, 0xe3, 0x46, 0x9e, 0x7c, 0xe0, 0xab, 0x62,
-	0x3d, 0x6b, 0x34, 0x57, 0x5a, 0x8f, 0xdb, 0x50, 0x37, 0xe0, 0x36, 0xb1,
-	0xa7, 0x0d, 0xe5, 0x41, 0xb6, 0x06, 0x70, 0xda, 0x6e, 0x63, 0x16, 0x2d,
-	0xde, 0x6b, 0xdd, 0xe1, 0xfe, 0xdc, 0xb7, 0x55, 0xd6, 0xc8, 0x2a, 0x6f,
-	0x62, 0xf4, 0x7e, 0x17, 0xfb, 0xbd, 0xce, 0xb1, 0xc8, 0x36, 0xff, 0x4a,
-	0xdc, 0x7f, 0x16, 0x7b, 0x9e, 0x5b, 0x6c, 0x73, 0xdb, 0x40, 0x23, 0x7b,
-	0xa3, 0x25, 0x54, 0xf8, 0x5f, 0x86, 0xf3, 0xfd, 0x1f, 0xff, 0x2b, 0xd2,
-	0xaa, 0xe0, 0x74, 0xa5, 0x00, 0x7c, 0x2c, 0xb3, 0x0d, 0xbd, 0xdb, 0x18,
-	0x37, 0x70, 0x14, 0xd8, 0x25, 0x38, 0x71, 0xbf, 0xa5, 0x6e, 0x44, 0xed,
-	0x78, 0xae, 0x2b, 0x3c, 0x17, 0x62, 0x92, 0xbd, 0xf8, 0x07, 0x70, 0xa3,
-	0x49, 0x79, 0x9a, 0xdf, 0xce, 0xd3, 0x85, 0x41, 0x9e, 0x66, 0xae, 0xe9,
-	0xf0, 0x43, 0x14, 0x75, 0x2a, 0xac, 0x51, 0xe0, 0x6d, 0x73, 0x3f, 0xab,
-	0xa4, 0xc8, 0xbc, 0x0e, 0xb4, 0x6f, 0x13, 0xad, 0x0d, 0x74, 0xf8, 0x4d,
-	0x1d, 0x19, 0x5b, 0xa6, 0x97, 0x7f, 0x46, 0xf4, 0xf2, 0x80, 0x6d, 0x79,
-	0xfc, 0xc4, 0xa6, 0x89, 0x3d, 0xcb, 0xc0, 0xfc, 0xc2, 0x40, 0x46, 0xbc,
-	0x40, 0x3c, 0xed, 0x7b, 0x88, 0x93, 0x35, 0x3c, 0x4b, 0x88, 0x9d, 0x8c,
-	0x0d, 0xc7, 0x91, 0x5d, 0xe0, 0xb3, 0x8c, 0xb6, 0xb3, 0xa8, 0x4b, 0xf4,
-	0xae, 0xd8, 0x3a, 0xd5, 0x9c, 0x49, 0x6a, 0x67, 0xb1, 0x4a, 0x70, 0xac,
-	0x3a, 0x08, 0x4e, 0x1d, 0x40, 0xfc, 0xf9, 0x9d, 0x32, 0x1e, 0xab, 0x10,
-	0xd3, 0x8a, 0x87, 0x11, 0x9b, 0xfa, 0xa8, 0xe7, 0xf1, 0x6e, 0xe1, 0x7d,
-	0x00, 0xe5, 0xc3, 0xe8, 0x3b, 0x1a, 0xa7, 0x32, 0xbb, 0x27, 0xc5, 0x28,
-	0xf0, 0x6e, 0xc3, 0x40, 0x7f, 0x13, 0xba, 0x61, 0x7f, 0xe7, 0x10, 0x3f,
-	0xd8, 0xe7, 0x39, 0xf8, 0x54, 0xc7, 0xdc, 0x82, 0x66, 0xb7, 0xa9, 0xa5,
-	0xa4, 0xf1, 0xcb, 0x1f, 0xc6, 0xaf, 0x52, 0xcc, 0x83, 0x20, 0x14, 0xb0,
-	0x61, 0xfd, 0x66, 0x7a, 0x65, 0xec, 0xc8, 0xf5, 0xa0, 0x65, 0x4f, 0x89,
-	0xa2, 0x55, 0xa7, 0x40, 0x4d, 0xe0, 0xee, 0x42, 0xc3, 0x4d, 0x68, 0xd8,
-	0x1f, 0xd1, 0xb0, 0xff, 0x3f, 0x35, 0x0c, 0x7d, 0x42, 0x23, 0xb7, 0xc1,
-	0xa9, 0xb7, 0x7a, 0xfb, 0xe9, 0x99, 0xb5, 0xcc, 0x9a, 0x36, 0xe9, 0xce,
-	0xd1, 0xa7, 0xd5, 0x74, 0x49, 0x7e, 0x4a, 0x4d, 0xb7, 0x58, 0xd3, 0x2a,
-	0x6b, 0xba, 0xb8, 0x57, 0xd3, 0xd3, 0x18, 0x23, 0xd1, 0xe6, 0x19, 0xb5,
-	0x48, 0xda, 0x3c, 0xf0, 0xd8, 0xc8, 0x93, 0x72, 0xed, 0x31, 0xef, 0x98,
-	0xcb, 0xfe, 0x00, 0xff, 0xb6, 0x35, 0xb4, 0x49, 0xe3, 0xf5, 0x88, 0x81,
-	0x6a, 0xd5, 0x2a, 0xad, 0xc5, 0x7d, 0x54, 0xd2, 0xe1, 0xff, 0xd7, 0x8f,
-	0x5a, 0xa6, 0x29, 0x8f, 0x6a, 0x1f, 0xea, 0xdf, 0x88, 0xae, 0x68, 0x55,
-	0x9e, 0xa7, 0x65, 0x82, 0xf3, 0xe6, 0x4f, 0x80, 0x55, 0xbb, 0xcb, 0x7c,
-	0xb7, 0x45, 0x3d, 0xe6, 0x19, 0xca, 0xd0, 0x84, 0x06, 0xde, 0xe6, 0xd0,
-	0x4f, 0xdd, 0x48, 0x74, 0x74, 0x1b, 0xe3, 0x6e, 0x75, 0x99, 0x67, 0x06,
-	0xe9, 0xd7, 0xed, 0xd2, 0x85, 0x38, 0x06, 0xcf, 0x8a, 0x25, 0x62, 0x0d,
-	0xf2, 0xb9, 0x88, 0xf6, 0x41, 0x8e, 0x94, 0x58, 0xf7, 0x13, 0xa9, 0xee,
-	0x9f, 0x87, 0xaf, 0x26, 0x50, 0x66, 0xed, 0x1f, 0x4e, 0xb5, 0x3f, 0x85,
-	0x37, 0xd7, 0xad, 0xa8, 0x09, 0x87, 0xc0, 0xc7, 0x0d, 0xc6, 0x37, 0x8f,
-	0x58, 0xc7, 0xf3, 0xff, 0x33, 0x5a, 0xb5, 0x19, 0x63, 0xdb, 0xfc, 0x01,
-	0xcd, 0x41, 0x7f, 0xa8, 0xdf, 0xe6, 0xbe, 0x6c, 0x93, 0xf5, 0x15, 0x69,
-	0xdf, 0x0f, 0xf7, 0xf4, 0x45, 0xfd, 0x36, 0xf7, 0x63, 0x7d, 0x1c, 0x22,
-	0xe5, 0x3a, 0x9f, 0xdb, 0x1e, 0xeb, 0x03, 0x76, 0x35, 0xd4, 0x71, 0x6e,
-	0xc1, 0xf6, 0x7c, 0x86, 0xf3, 0x3a, 0x39, 0xef, 0xe0, 0x73, 0x7e, 0xcf,
-	0x79, 0x3e, 0xd4, 0xc8, 0x19, 0xf0, 0xfe, 0x3b, 0xea, 0x27, 0x35, 0xb2,
-	0x02, 0x4d, 0x5c, 0x54, 0x13, 0x8d, 0xbc, 0x86, 0xf7, 0x19, 0x94, 0x57,
-	0xf6, 0x68, 0x24, 0xb3, 0x7b, 0xf2, 0x39, 0x1e, 0xf4, 0x4a, 0xf1, 0x99,
-	0xcb, 0xf3, 0x29, 0x1b, 0xd4, 0xd2, 0x52, 0x3d, 0xd4, 0x87, 0x7a, 0x98,
-	0x40, 0xcc, 0xc8, 0xa5, 0x5c, 0xc7, 0xdb, 0xfe, 0x48, 0xf1, 0x1d, 0x4b,
-	0xb4, 0x89, 0xb5, 0x31, 0x7a, 0x9e, 0xfd, 0xbf, 0xf4, 0x41, 0xe0, 0x51,
-	0x3c, 0x37, 0x72, 0x11, 0x3e, 0x17, 0xa2, 0xe8, 0x15, 0x07, 0xed, 0x59,
-	0x4e, 0x12, 0x63, 0x9f, 0xc3, 0xd9, 0xcb, 0x78, 0x20, 0x0f, 0xb4, 0x67,
-	0xa1, 0x07, 0x8e, 0x05, 0xbb, 0xd1, 0x96, 0xed, 0xa1, 0xae, 0x06, 0xff,
-	0x33, 0x26, 0xcb, 0xd2, 0x52, 0xdf, 0x60, 0x3b, 0xe8, 0x6d, 0xbf, 0x5c,
-	0x4c, 0x87, 0xae, 0x1e, 0xe3, 0xc4, 0x3c, 0x6a, 0x8e, 0xe0, 0xd4, 0x88,
-	0x71, 0xda, 0x19, 0xe2, 0xd4, 0x4c, 0x71, 0x6a, 0xc6, 0x38, 0x3d, 0x48,
-	0x71, 0xfa, 0xf3, 0x13, 0x70, 0xda, 0x79, 0x0a, 0x9c, 0x0c, 0xda, 0xb2,
-	0x4b, 0x38, 0x6f, 0xf5, 0x38, 0x77, 0xbd, 0xef, 0xec, 0x97, 0x7b, 0xb1,
-	0xdf, 0xc7, 0xb0, 0x8a, 0x18, 0xab, 0x2d, 0x1a, 0xcd, 0x43, 0x2c, 0xf3,
-	0x1e, 0x15, 0x70, 0x6e, 0xe4, 0xe9, 0xea, 0x9e, 0x5c, 0x24, 0x00, 0x4e,
-	0xb5, 0x14, 0xa7, 0xab, 0xc0, 0xa9, 0x96, 0xe2, 0xb4, 0x3e, 0x82, 0xd3,
-	0xfa, 0x18, 0x4e, 0x1c, 0x53, 0x2a, 0xc6, 0x7a, 0x37, 0xc3, 0x28, 0xc3,
-	0x47, 0xa7, 0x9b, 0x62, 0x0a, 0xfb, 0x3f, 0x4e, 0xed, 0x9f, 0xaa, 0x9c,
-	0xff, 0x02, 0xbb, 0x97, 0x54, 0x39, 0x3e, 0x17, 0xf8, 0xfb, 0x71, 0xbe,
-	0x82, 0xb9, 0x5c, 0xcf, 0xe1, 0x3d, 0x21, 0xcf, 0xb5, 0x47, 0x63, 0xd1,
-	0x07, 0x88, 0x45, 0x5c, 0xc7, 0xfd, 0x54, 0xa9, 0x06, 0xcd, 0x2b, 0xc8,
-	0xe1, 0xfd, 0x61, 0x0e, 0x9f, 0xf8, 0xe1, 0x6a, 0x9a, 0xc3, 0x6f, 0xd9,
-	0x9c, 0xc3, 0x9f, 0xd0, 0x68, 0x62, 0x39, 0xc5, 0x93, 0x79, 0x3d, 0x89,
-	0xb6, 0xb3, 0x31, 0xee, 0x6d, 0xc4, 0xf2, 0x55, 0xf8, 0xa0, 0x19, 0xf3,
-	0x13, 0x79, 0x57, 0xca, 0x5d, 0xe4, 0xbb, 0xe4, 0x87, 0x09, 0x4f, 0x3f,
-	0xdb, 0x5c, 0xec, 0xef, 0x88, 0xd9, 0x46, 0x43, 0xc5, 0x1d, 0xe0, 0x6e,
-	0x18, 0xc7, 0xea, 0x73, 0x41, 0x97, 0x5a, 0x47, 0xaa, 0x57, 0x22, 0xe0,
-	0xee, 0x7e, 0xfd, 0x34, 0x9f, 0x39, 0xf9, 0x45, 0xaf, 0x82, 0xfa, 0x81,
-	0x41, 0xc8, 0x83, 0x70, 0xa7, 0xa1, 0x96, 0x77, 0x5a, 0x42, 0xbe, 0x83,
-	0x32, 0x6c, 0x82, 0x70, 0xba, 0x21, 0x57, 0x4b, 0xe0, 0x43, 0x8b, 0x5c,
-	0xac, 0xd3, 0x0d, 0xe3, 0x7b, 0x4d, 0x43, 0xa9, 0x1a, 0xc8, 0x37, 0xc9,
-	0xc0, 0x99, 0x0f, 0x9f, 0x98, 0x46, 0x7b, 0x80, 0x9c, 0x08, 0x79, 0x80,
-	0xb7, 0x08, 0xbf, 0x1c, 0x03, 0x76, 0xa1, 0x0a, 0xdb, 0x6f, 0xe9, 0xc9,
-	0x9d, 0x88, 0xc8, 0x8b, 0xfd, 0xf5, 0x71, 0xca, 0x91, 0x38, 0xe7, 0x92,
-	0x6a, 0x3d, 0x32, 0x9b, 0x0e, 0xb8, 0x8e, 0x33, 0xa5, 0x13, 0x72, 0x5e,
-	0x7d, 0xcc, 0x90, 0xaf, 0x71, 0x3c, 0x7f, 0x00, 0x1f, 0xe2, 0x7b, 0x9b,
-	0xcf, 0x19, 0x85, 0x73, 0x73, 0xdc, 0x7d, 0xca, 0x88, 0x37, 0x34, 0x89,
-	0xd8, 0x87, 0xd8, 0x3b, 0xcd, 0x58, 0xb9, 0xc9, 0x19, 0xc4, 0xe3, 0x1d,
-	0x97, 0x93, 0x79, 0xfe, 0xa4, 0x25, 0x1c, 0xc6, 0x7d, 0x07, 0xfe, 0x5b,
-	0xed, 0x39, 0x1c, 0x73, 0x3f, 0xaf, 0xd0, 0x43, 0x8a, 0x39, 0x29, 0x4e,
-	0x20, 0x16, 0x9f, 0x86, 0x8d, 0x1b, 0xeb, 0x31, 0xc9, 0xbd, 0x32, 0x9b,
-	0x0f, 0xf7, 0x8c, 0xf1, 0x17, 0x65, 0xbc, 0xec, 0x82, 0xd3, 0x95, 0x74,
-	0xbe, 0x51, 0x8e, 0x2c, 0x20, 0xe5, 0x79, 0xa0, 0x0d, 0xf3, 0xb7, 0xa2,
-	0x8e, 0x7e, 0xbc, 0x46, 0xd6, 0x25, 0xdb, 0x1c, 0xd1, 0xc6, 0xc7, 0x99,
-	0xdd, 0x67, 0x8c, 0xea, 0xc8, 0x18, 0x45, 0xde, 0x9b, 0x68, 0x3a, 0xcf,
-	0xa4, 0xf7, 0x0c, 0x8e, 0x2d, 0x02, 0x3a, 0x95, 0x9f, 0x93, 0xb1, 0x0f,
-	0x0f, 0x7b, 0xf6, 0xe3, 0xfa, 0x5f, 0xe9, 0xe3, 0xe3, 0xfe, 0x56, 0x4d,
-	0xca, 0xc7, 0x12, 0x6e, 0xda, 0x78, 0x87, 0x0f, 0x46, 0xd6, 0xae, 0xed,
-	0x33, 0xef, 0xd7, 0x38, 0x5d, 0x43, 0xbc, 0x21, 0x57, 0xc1, 0x1d, 0xcc,
-	0x27, 0x7c, 0x87, 0xaf, 0x67, 0x3e, 0x04, 0x6f, 0xe8, 0x5c, 0x3b, 0xe5,
-	0x8b, 0x9c, 0xf0, 0x85, 0xf3, 0xba, 0xc5, 0x55, 0xf0, 0xa5, 0x0d, 0xbe,
-	0xc0, 0xae, 0xa1, 0x55, 0xa7, 0xc1, 0x05, 0x8e, 0x4d, 0x28, 0x87, 0xcc,
-	0x1d, 0xe6, 0x0a, 0xf3, 0xe6, 0x31, 0x5f, 0x5e, 0xe9, 0x1a, 0xc6, 0xe6,
-	0xa7, 0x70, 0xe5, 0x8d, 0x98, 0x2b, 0xcc, 0xd9, 0x24, 0x7e, 0x74, 0x80,
-	0x55, 0x90, 0xc6, 0x8f, 0x00, 0xf1, 0xa3, 0xc6, 0xf9, 0x4f, 0x1c, 0x0b,
-	0x12, 0xfd, 0xac, 0x41, 0x3f, 0x35, 0x85, 0xf3, 0x23, 0xd6, 0x0e, 0xdb,
-	0xb1, 0x7e, 0xd8, 0xae, 0x90, 0xda, 0x8d, 0xc7, 0x91, 0x76, 0xcf, 0x32,
-	0xb3, 0x38, 0xd2, 0x86, 0x76, 0x3a, 0xa9, 0x8e, 0xda, 0xa9, 0x8e, 0xd0,
-	0xa7, 0xa5, 0x54, 0xf8, 0x4c, 0xb0, 0x4c, 0x1f, 0xf1, 0xa3, 0x13, 0x8f,
-	0xd9, 0xa2, 0xe4, 0x2e, 0xc3, 0xda, 0xe6, 0xb8, 0x3b, 0x12, 0x6f, 0xd3,
-	0x7b, 0x6e, 0x23, 0xbe, 0xe7, 0x7e, 0x45, 0x1f, 0x8f, 0xb7, 0x38, 0x6b,
-	0xe2, 0x7b, 0xee, 0x29, 0x9d, 0xef, 0xb9, 0x01, 0x7d, 0x49, 0x1f, 0xbd,
-	0xe7, 0x06, 0x63, 0xf7, 0xdc, 0xcc, 0x96, 0xeb, 0xf7, 0x8b, 0xbb, 0x99,
-	0x4f, 0x38, 0xf6, 0x32, 0x9f, 0xf6, 0xcb, 0x15, 0xb3, 0x3e, 0x1c, 0x93,
-	0x58, 0xef, 0x1c, 0xcb, 0x92, 0xdc, 0xec, 0x6e, 0x98, 0xe9, 0xe2, 0x55,
-	0xcc, 0x83, 0x72, 0x6f, 0x3f, 0x5d, 0x18, 0xa9, 0x2e, 0x26, 0x13, 0x9b,
-	0xde, 0xa8, 0x36, 0x5e, 0xd5, 0xc7, 0xb5, 0x91, 0x8d, 0x93, 0x69, 0x23,
-	0x19, 0x73, 0x47, 0x29, 0xe1, 0x0c, 0x2c, 0x23, 0x1e, 0x09, 0xbe, 0xa3,
-	0x21, 0x5e, 0x54, 0xf3, 0xb8, 0xa7, 0x14, 0x78, 0xec, 0x76, 0xf8, 0x2c,
-	0x35, 0x8a, 0x8c, 0x0b, 0xaf, 0xff, 0x61, 0x7c, 0x7f, 0xc0, 0xba, 0x0b,
-	0x01, 0xff, 0xfe, 0xf1, 0x09, 0x3e, 0xbe, 0x06, 0x3e, 0x66, 0xfb, 0x19,
-	0xad, 0xbf, 0x34, 0x52, 0x5f, 0x4e, 0x31, 0x4f, 0x7c, 0x7e, 0x2f, 0xd5,
-	0xc8, 0x26, 0x72, 0xb7, 0xfb, 0xc8, 0x8b, 0xde, 0x44, 0xfc, 0x0e, 0x06,
-	0x1f, 0x47, 0xf7, 0x8a, 0x2a, 0x75, 0x86, 0x36, 0xbf, 0xc0, 0xba, 0x2d,
-	0x71, 0x13, 0x5f, 0x6f, 0x0c, 0xb2, 0xb1, 0xb9, 0x9d, 0xeb, 0xfe, 0x8d,
-	0xf3, 0x19, 0x79, 0xdf, 0xb0, 0xef, 0xfb, 0x11, 0xe7, 0xbb, 0x77, 0x81,
-	0xc5, 0x3b, 0xe1, 0x34, 0xfd, 0x1e, 0x1c, 0x7b, 0x3b, 0xce, 0x79, 0x93,
-	0x5c, 0x17, 0xfe, 0xc3, 0x99, 0xc7, 0x67, 0xbd, 0xf7, 0x39, 0x99, 0x2e,
-	0xd3, 0x57, 0x1d, 0xae, 0x93, 0xa9, 0x7e, 0x2a, 0x8a, 0x2e, 0xe2, 0xdc,
-	0x5f, 0x19, 0x3b, 0xf7, 0x71, 0x07, 0x3c, 0xc9, 0xf9, 0x7f, 0x96, 0xf3,
-	0xef, 0x46, 0x33, 0xf3, 0xd6, 0x4d, 0x97, 0x5c, 0xa9, 0xde, 0xe7, 0x7c,
-	0x6c, 0x98, 0x8b, 0x11, 0x1d, 0x7a, 0x14, 0xc9, 0xf3, 0x7c, 0x36, 0xbd,
-	0x9b, 0xfa, 0x1c, 0x6d, 0x37, 0x1e, 0xe1, 0x1e, 0x53, 0x8b, 0x7f, 0x17,
-	0x72, 0xfb, 0x3c, 0x0f, 0x97, 0xf1, 0x0e, 0x39, 0x47, 0x78, 0xd2, 0x6f,
-	0x35, 0x2a, 0xf0, 0xb5, 0xcc, 0x75, 0x85, 0xe2, 0x7b, 0x21, 0xee, 0x6e,
-	0x3f, 0x6f, 0x53, 0x12, 0x3b, 0x6a, 0xce, 0x39, 0xac, 0x05, 0x98, 0x88,
-	0x06, 0x30, 0x9e, 0x47, 0xac, 0xb2, 0xcc, 0x93, 0x72, 0xf2, 0x5b, 0xd5,
-	0x1a, 0xc6, 0x56, 0x4e, 0x72, 0x2e, 0xf9, 0x51, 0xb4, 0x36, 0x88, 0xcf,
-	0x44, 0x87, 0xb9, 0xe6, 0x87, 0x07, 0x65, 0x7e, 0xbb, 0x21, 0x7f, 0xeb,
-	0x98, 0xc7, 0x7c, 0x02, 0x0f, 0x8b, 0xa2, 0x76, 0xc3, 0x14, 0xf5, 0x9e,
-	0x29, 0x96, 0x7a, 0x32, 0x54, 0x52, 0xc8, 0xd1, 0x14, 0xe7, 0x08, 0x3a,
-	0xd1, 0x73, 0x58, 0xcb, 0x2d, 0x53, 0xf8, 0xc8, 0xa3, 0xbe, 0xad, 0x58,
-	0x62, 0x85, 0x76, 0xb1, 0xc7, 0x47, 0x51, 0x72, 0xa7, 0x35, 0x45, 0x6d,
-	0x38, 0xf7, 0x23, 0xcc, 0xcd, 0x6b, 0x62, 0x2d, 0xf3, 0x79, 0xb6, 0x2c,
-	0x9d, 0x83, 0x8f, 0xce, 0xf7, 0x77, 0x11, 0x43, 0xf9, 0x3c, 0xcb, 0x23,
-	0xe6, 0x59, 0x26, 0x5f, 0xf6, 0xef, 0x62, 0xff, 0xef, 0xf4, 0x80, 0x0f,
-	0x72, 0xc7, 0xb7, 0x87, 0x79, 0x1a, 0x63, 0x58, 0x06, 0x17, 0xd9, 0x3e,
-	0x8a, 0x82, 0xc5, 0x38, 0x47, 0xc1, 0x5a, 0xe6, 0xca, 0xb7, 0x90, 0xa7,
-	0xd7, 0x69, 0xa1, 0x5c, 0x8f, 0xdf, 0x11, 0x72, 0x12, 0xfe, 0x5d, 0xc0,
-	0x12, 0x4d, 0x7c, 0xd7, 0xd2, 0xef, 0x80, 0x73, 0xf8, 0x45, 0x1e, 0x83,
-	0x73, 0x79, 0xd6, 0xe1, 0x7f, 0x01, 0x17, 0xc6, 0xf1, 0xb2, 0x84, 0x14,
-	0x00, 0x00, 0x00 };
-static u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwBss[(0x250/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwSbss[(0x34/4) + 1] = { 0x0 };
+	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58,
+	0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb,
+	0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13,
+	0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c,
+	0x28, 0xc5, 0x90, 0x87, 0x52, 0x50, 0x57, 0x32, 0x09, 0x79, 0x69, 0xda,
+	0xc6, 0x90, 0x3e, 0x79, 0x3b, 0x2b, 0xc7, 0x0e, 0x6c, 0xbc, 0x8d, 0x52,
+	0xe4, 0x52, 0xfa, 0x60, 0xd6, 0xb1, 0x05, 0xcd, 0x46, 0x93, 0xd4, 0x7e,
+	0x35, 0x36, 0x4e, 0x93, 0xa7, 0x42, 0x9f, 0x52, 0xf4, 0x18, 0xd2, 0x12,
+	0xda, 0x52, 0x8a, 0x69, 0xa1, 0x09, 0x8d, 0xeb, 0xdb, 0xef, 0xdc, 0x99,
+	0x91, 0x57, 0xb6, 0xec, 0xa4, 0x25, 0x85, 0x0a, 0x56, 0x77, 0xe6, 0xce,
+	0x3d, 0xe7, 0x9e, 0x7b, 0xee, 0x77, 0xbe, 0x73, 0xee, 0x2d, 0xeb, 0x34,
+	0x48, 0xd9, 0xdf, 0x30, 0x7e, 0x2f, 0x7e, 0xf7, 0x85, 0x17, 0xab, 0x8f,
+	0x3c, 0xea, 0x10, 0x3d, 0xfa, 0x88, 0x66, 0x98, 0x06, 0x7d, 0x09, 0x7f,
+	0x50, 0x22, 0x72, 0xfd, 0xfc, 0x23, 0x5b, 0xaf, 0x9d, 0x72, 0x42, 0x8f,
+	0x6c, 0xa3, 0x26, 0xbe, 0xbe, 0xe4, 0x11, 0x05, 0xbd, 0x69, 0xa7, 0x4e,
+	0xff, 0x92, 0xcd, 0x92, 0x49, 0xdc, 0xff, 0x50, 0xed, 0xc6, 0xfe, 0xcb,
+	0x07, 0xdd, 0xeb, 0x67, 0x0d, 0xb2, 0x45, 0x6d, 0xd1, 0x16, 0x93, 0x64,
+	0x8f, 0xd5, 0x9a, 0xce, 0x2f, 0xf6, 0x1e, 0x28, 0xd0, 0xae, 0x5c, 0x97,
+	0xa0, 0xb8, 0x43, 0x4d, 0xab, 0x66, 0x53, 0xd4, 0x7e, 0x49, 0x0b, 0x3b,
+	0x9e, 0x98, 0x85, 0x8e, 0xa0, 0x04, 0xfd, 0x1e, 0xde, 0x13, 0x53, 0x8b,
+	0xce, 0xd8, 0xa4, 0xd7, 0x02, 0x3c, 0x4f, 0x51, 0xab, 0x23, 0xe5, 0x2b,
+	0xbe, 0x46, 0x4b, 0xbe, 0x4d, 0x8b, 0xc2, 0x0d, 0x1c, 0xed, 0xa6, 0xac,
+	0x4c, 0x48, 0xf9, 0x9c, 0xaf, 0x93, 0xee, 0xcd, 0x69, 0xe1, 0xfa, 0xbc,
+	0x56, 0x5f, 0x9f, 0x67, 0x7f, 0xc0, 0xbe, 0x39, 0x2d, 0x58, 0xe7, 0xb6,
+	0x66, 0xd7, 0xdb, 0xbb, 0x68, 0xb1, 0x44, 0x23, 0xba, 0x37, 0x85, 0xf9,
+	0x4a, 0xd0, 0xe3, 0x50, 0xe8, 0x4f, 0x0b, 0x9d, 0x2a, 0xf8, 0x0d, 0xd0,
+	0xac, 0x4f, 0x03, 0xba, 0xa7, 0x53, 0xa3, 0xa4, 0xd1, 0x1b, 0x55, 0x0b,
+	0xbf, 0xc3, 0x5a, 0xb4, 0xfe, 0x7c, 0xa6, 0x87, 0xc7, 0xdb, 0xf8, 0xc6,
+	0x36, 0xb3, 0x7c, 0xbf, 0xec, 0x30, 0x9e, 0x9f, 0xc3, 0x38, 0x8b, 0xc2,
+	0xea, 0xed, 0xdf, 0x06, 0xf0, 0xac, 0xa1, 0xff, 0x30, 0xec, 0x62, 0x3d,
+	0x0e, 0xec, 0x28, 0xd3, 0x4a, 0x67, 0x1e, 0xeb, 0x29, 0x50, 0x53, 0x4c,
+	0x4c, 0x35, 0xc8, 0x84, 0x8c, 0x41, 0x41, 0xe9, 0x8a, 0xd4, 0x6b, 0x52,
+	0x86, 0x55, 0x6f, 0xaa, 0xab, 0xe6, 0xd0, 0xc9, 0xf0, 0x0a, 0x14, 0xf9,
+	0xc3, 0xd4, 0x12, 0x06, 0xc5, 0xfb, 0x2c, 0x0a, 0x16, 0x4c, 0xac, 0x71,
+	0x14, 0x72, 0x1a, 0xe4, 0x5f, 0xcb, 0xf6, 0xbc, 0x48, 0xb1, 0x28, 0xa0,
+	0x7f, 0x84, 0xe2, 0xd2, 0x6e, 0x4d, 0xaf, 0xbd, 0x82, 0xfe, 0x09, 0xd1,
+	0xa5, 0x53, 0x68, 0x35, 0xbc, 0xef, 0xc6, 0x58, 0x7e, 0xd7, 0xa0, 0x8f,
+	0x44, 0x98, 0x78, 0xd4, 0x4a, 0x72, 0x59, 0xee, 0x4f, 0xfb, 0x9a, 0xc9,
+	0xed, 0xfb, 0xed, 0xc1, 0x4e, 0x41, 0x27, 0x3a, 0xb3, 0x98, 0x8f, 0x9a,
+	0x46, 0x0d, 0xe3, 0xb0, 0x37, 0xbc, 0xbf, 0x81, 0xc2, 0xc1, 0xe3, 0xdc,
+	0xcf, 0x7f, 0xe8, 0x77, 0xc8, 0xa8, 0xf1, 0xb7, 0x6f, 0x52, 0xfa, 0x2d,
+	0xb5, 0x3f, 0xf4, 0x1f, 0xcb, 0xde, 0x4b, 0x22, 0x3c, 0xf3, 0x28, 0xd6,
+	0xa8, 0x60, 0x83, 0xe7, 0x02, 0xf0, 0x11, 0xcf, 0xe8, 0xd4, 0x2c, 0x17,
+	0xc9, 0xf5, 0x8f, 0xa2, 0xf7, 0xd7, 0x6d, 0x83, 0xea, 0xec, 0x2b, 0xdf,
+	0xcc, 0x64, 0x18, 0x1b, 0x1f, 0x64, 0x76, 0x0a, 0x5a, 0x3c, 0x22, 0xe5,
+	0x8a, 0x2f, 0xa5, 0x55, 0xf3, 0x9c, 0x13, 0x34, 0x5d, 0x36, 0x69, 0x52,
+	0xa0, 0x85, 0x8f, 0xbd, 0x72, 0x83, 0x2c, 0x60, 0xa1, 0x1f, 0xff, 0xfc,
+	0xf7, 0xa6, 0x86, 0x25, 0xd0, 0xb5, 0x36, 0xeb, 0x98, 0x70, 0x66, 0x95,
+	0x8c, 0x94, 0xf1, 0xcc, 0xbd, 0x64, 0x2e, 0x65, 0x32, 0x52, 0x46, 0x55,
+	0x81, 0x3d, 0x6f, 0x0a, 0xd8, 0x87, 0x75, 0x31, 0xc6, 0x89, 0xa2, 0x9e,
+	0x6f, 0x37, 0xda, 0xb0, 0xd1, 0x43, 0xdb, 0x13, 0xf0, 0x0f, 0x51, 0x0b,
+	0x63, 0xf5, 0xea, 0x7d, 0x8c, 0x0d, 0xec, 0xef, 0x82, 0x1d, 0xb5, 0xdd,
+	0xf2, 0x29, 0x5a, 0xb0, 0xeb, 0xbd, 0xe9, 0xf2, 0x32, 0x3d, 0xc4, 0x73,
+	0xd8, 0x56, 0xed, 0x88, 0xdd, 0x55, 0x72, 0x88, 0xc4, 0x41, 0x3c, 0xf7,
+	0x88, 0xe2, 0x36, 0x69, 0xa1, 0x7f, 0x1f, 0xaf, 0x15, 0x72, 0xf3, 0x99,
+	0xdc, 0x7c, 0x26, 0x37, 0x92, 0xc9, 0x3d, 0xd5, 0x27, 0xf7, 0x14, 0xcb,
+	0x61, 0x6c, 0x90, 0x8d, 0x0d, 0xb2, 0xb1, 0x66, 0x36, 0x36, 0xca, 0xc6,
+	0xa2, 0xed, 0x8d, 0xc1, 0x36, 0x77, 0xca, 0xd1, 0x6c, 0x8a, 0x3d, 0xf9,
+	0x70, 0xe8, 0x53, 0x50, 0xf7, 0xdc, 0xcd, 0xba, 0x31, 0x42, 0xe7, 0xfc,
+	0x21, 0x5a, 0x49, 0xc6, 0x28, 0x4e, 0x56, 0x28, 0x4c, 0x74, 0xc8, 0x8e,
+	0x50, 0xd7, 0xbb, 0x2e, 0x67, 0x7d, 0x1f, 0x7b, 0x66, 0xb3, 0x5c, 0x79,
+	0x96, 0x1c, 0x7c, 0x9f, 0x16, 0xcb, 0xe4, 0x03, 0x2b, 0x3a, 0xf6, 0xad,
+	0xa2, 0x9e, 0xe3, 0xc4, 0xe7, 0x35, 0x37, 0xf5, 0xaa, 0x2b, 0x62, 0x72,
+	0xcb, 0xa1, 0x41, 0x42, 0xaf, 0xc1, 0x4f, 0x49, 0x93, 0xa2, 0xc4, 0xa6,
+	0x0f, 0x8d, 0x97, 0x54, 0x8c, 0xc6, 0x9d, 0x4d, 0x79, 0x79, 0xaf, 0x43,
+	0x57, 0x30, 0xcf, 0xc5, 0xa4, 0x4c, 0xbf, 0x4a, 0x4a, 0xf4, 0x4e, 0x42,
+	0x7a, 0xe8, 0x03, 0xc3, 0x25, 0x41, 0x6f, 0x27, 0xfd, 0x3e, 0xff, 0x88,
+	0x7d, 0x6e, 0xdf, 0x5f, 0x23, 0x7b, 0xb4, 0xc6, 0x38, 0x4b, 0x39, 0xa0,
+	0x9e, 0x72, 0x80, 0xc2, 0x52, 0xab, 0x13, 0x3f, 0x68, 0x80, 0x7f, 0x96,
+	0xfc, 0x60, 0xb7, 0xa1, 0xf6, 0xa3, 0x89, 0x3d, 0xcc, 0x5b, 0xde, 0x9b,
+	0xab, 0xce, 0x92, 0xe7, 0x9e, 0xaa, 0x33, 0x6a, 0x4f, 0x5b, 0x39, 0x2e,
+	0xfb, 0xe6, 0xf8, 0x33, 0xe6, 0x18, 0xa2, 0x06, 0xe2, 0xec, 0x09, 0x13,
+	0xb1, 0xe3, 0xfd, 0xdd, 0x60, 0x5c, 0x39, 0x1b, 0x8c, 0x6f, 0xa2, 0xf1,
+	0x0d, 0x9b, 0xd6, 0xdb, 0x45, 0x72, 0xba, 0x43, 0xb4, 0xd4, 0x19, 0xa4,
+	0xca, 0x05, 0x13, 0x63, 0xef, 0xa3, 0xca, 0xaa, 0x5e, 0xe2, 0x38, 0xae,
+	0xc3, 0xc7, 0xe3, 0x5d, 0x09, 0x7c, 0x0e, 0xd2, 0xf8, 0x9a, 0xab, 0xb0,
+	0xb3, 0xe4, 0xb5, 0x7c, 0x83, 0x7e, 0x4c, 0xd7, 0xf6, 0x15, 0xb0, 0xa6,
+	0x12, 0xf9, 0x93, 0xfd, 0xf3, 0xe9, 0x80, 0x18, 0xf7, 0xc5, 0x45, 0xda,
+	0xe5, 0x3a, 0xa4, 0xb3, 0x3e, 0x9b, 0xc6, 0x2f, 0xd8, 0x5a, 0xbd, 0xc3,
+	0x3e, 0x63, 0xfc, 0xd9, 0x19, 0xfe, 0x4c, 0x2d, 0x3c, 0x53, 0xc4, 0x5c,
+	0x7f, 0x91, 0xa1, 0x27, 0xb1, 0x0f, 0x3a, 0x2d, 0x55, 0x7f, 0x04, 0xfb,
+	0xd0, 0xd7, 0xe5, 0x6f, 0xd7, 0xb3, 0x7e, 0xd6, 0x01, 0x7e, 0xf0, 0xef,
+	0xa7, 0x90, 0xb9, 0xe0, 0x08, 0xcb, 0x14, 0x69, 0x7c, 0x95, 0xf9, 0x05,
+	0x6d, 0x97, 0xdf, 0x79, 0x6d, 0x03, 0xd4, 0x80, 0x57, 0x1a, 0x53, 0x25,
+	0xd8, 0xa5, 0x2b, 0xbe, 0x68, 0x80, 0x3f, 0x74, 0x6f, 0x10, 0x2d, 0xcf,
+	0xf7, 0x73, 0x23, 0x8f, 0xa9, 0xb8, 0x33, 0x44, 0x75, 0xe0, 0xd7, 0x84,
+	0x3d, 0xcb, 0x34, 0x51, 0x3e, 0xaa, 0xbe, 0xa1, 0xaf, 0xc7, 0xdf, 0xc4,
+	0x6d, 0xdf, 0xf0, 0xde, 0xcb, 0x6d, 0x40, 0x6c, 0x7b, 0x2d, 0xcc, 0x62,
+	0x65, 0x7e, 0xe1, 0xf1, 0xcd, 0x32, 0xf6, 0x06, 0x7c, 0x46, 0xf0, 0x25,
+	0x51, 0xb7, 0x6d, 0x82, 0x6f, 0xf4, 0xaf, 0xea, 0x2c, 0x57, 0x62, 0x3d,
+	0x58, 0xff, 0x9a, 0xa9, 0xd5, 0xcf, 0x78, 0xce, 0x1f, 0x88, 0xe5, 0x2b,
+	0xf0, 0xc1, 0xc4, 0x4c, 0x8b, 0xc7, 0xf7, 0x2c, 0xf2, 0x56, 0x9b, 0xc2,
+	0xc4, 0x9e, 0xc2, 0x73, 0x54, 0xff, 0xc9, 0x08, 0xf6, 0xda, 0x75, 0x5a,
+	0xf4, 0x5b, 0xd8, 0x53, 0x20, 0xaf, 0x6b, 0xd2, 0x1b, 0x6d, 0xf6, 0x85,
+	0x4d, 0x95, 0x35, 0x29, 0x4f, 0xfa, 0xbc, 0x27, 0xbf, 0x83, 0x5f, 0x08,
+	0x2b, 0x9c, 0x98, 0xf9, 0x08, 0xfb, 0xb3, 0xde, 0xe3, 0xbd, 0xb1, 0x94,
+	0x4f, 0xbc, 0xd5, 0x29, 0xec, 0xeb, 0x54, 0x66, 0x23, 0xef, 0x97, 0x49,
+	0x2b, 0x55, 0x9d, 0xce, 0x57, 0x3f, 0x93, 0xba, 0xc7, 0xfc, 0x5a, 0x80,
+	0x6f, 0x31, 0xae, 0x8b, 0x71, 0x49, 0x01, 0x3e, 0xfc, 0x07, 0x78, 0x45,
+	0xca, 0xf3, 0x55, 0xf4, 0xaf, 0x1e, 0x87, 0xad, 0x06, 0x64, 0x53, 0x8c,
+	0xb1, 0x3d, 0x73, 0xed, 0x7c, 0x7d, 0xde, 0xcc, 0x7b, 0x4a, 0xdf, 0x10,
+	0x4d, 0x6e, 0x0c, 0xd1, 0xb3, 0xbd, 0x21, 0x1a, 0x3f, 0xcd, 0x32, 0xe0,
+	0xa6, 0xaa, 0x27, 0x22, 0xc6, 0xa8, 0xa7, 0xfc, 0x50, 0x36, 0x74, 0x5e,
+	0x27, 0xbe, 0x6f, 0x10, 0x2d, 0xf7, 0x78, 0x0e, 0xb3, 0x4f, 0xa7, 0x4e,
+	0x87, 0x7e, 0x4a, 0x74, 0xa8, 0xc7, 0xb2, 0x5b, 0xbe, 0x83, 0x5e, 0x01,
+	0x9d, 0x82, 0x38, 0x0f, 0x19, 0x1e, 0xf2, 0xdd, 0x7a, 0x88, 0xfc, 0x15,
+	0xe1, 0x37, 0x87, 0x9c, 0xc6, 0xeb, 0x9f, 0x42, 0xfc, 0x31, 0x8f, 0xdf,
+	0xc4, 0xda, 0x0b, 0xb4, 0xe2, 0xcf, 0x63, 0x0c, 0xef, 0xf1, 0x61, 0x7c,
+	0x1f, 0x46, 0x1e, 0xc8, 0xf2, 0x84, 0xe0, 0x3c, 0xb1, 0x1b, 0x71, 0x30,
+	0x00, 0xee, 0xdf, 0x63, 0x6e, 0xcf, 0x13, 0x18, 0x57, 0xda, 0x83, 0xbc,
+	0x70, 0x3f, 0xfa, 0x59, 0xd7, 0x28, 0xda, 0x01, 0xbc, 0xef, 0xc1, 0xd8,
+	0xfe, 0x1c, 0x91, 0xcb, 0xdd, 0x2d, 0x3f, 0x20, 0x26, 0x56, 0x11, 0x2b,
+	0x6b, 0x9c, 0x27, 0x38, 0x16, 0x79, 0x4f, 0x8b, 0xe0, 0x6f, 0x1b, 0x3a,
+	0x78, 0x6f, 0x8b, 0xd8, 0x43, 0xce, 0x71, 0x82, 0x2a, 0x1b, 0x3b, 0xe5,
+	0x0f, 0x5e, 0x0f, 0x38, 0xec, 0x34, 0xaf, 0xc5, 0x15, 0x0d, 0xf0, 0x59,
+	0xb8, 0x31, 0x8d, 0xef, 0xc8, 0x85, 0x22, 0xb2, 0x1b, 0xa7, 0x53, 0x2e,
+	0x6b, 0x6c, 0x8c, 0x29, 0x9c, 0xc6, 0x89, 0xc0, 0x3b, 0x73, 0x59, 0xce,
+	0x5d, 0x8c, 0x25, 0x0a, 0x20, 0xbb, 0x19, 0x1a, 0x52, 0x2e, 0xf9, 0x23,
+	0xd4, 0x00, 0x2e, 0x03, 0xf0, 0x59, 0x03, 0x7c, 0x56, 0xef, 0xe3, 0xb3,
+	0xfa, 0xe7, 0xf2, 0x19, 0xb8, 0xaa, 0x03, 0xae, 0xea, 0x80, 0xab, 0x50,
+	0x1b, 0xbc, 0x03, 0xec, 0xbf, 0xdd, 0xd9, 0x89, 0xe3, 0x98, 0xdf, 0x98,
+	0xe7, 0xa6, 0xe8, 0xf2, 0xde, 0xff, 0x94, 0xe7, 0x8e, 0x83, 0x13, 0x6c,
+	0xfa, 0xfe, 0xde, 0x7b, 0x73, 0xdd, 0x09, 0x70, 0x9d, 0xf5, 0xf9, 0x5c,
+	0xd7, 0x64, 0xae, 0x33, 0x81, 0xbd, 0x26, 0x78, 0x40, 0x5f, 0xed, 0x9f,
+	0xe7, 0x24, 0xe6, 0xe1, 0x3e, 0x33, 0xcb, 0xa5, 0x3a, 0x75, 0x81, 0x7b,
+	0xc3, 0xe3, 0x79, 0x60, 0x73, 0x92, 0x72, 0xd1, 0x13, 0x66, 0x89, 0xac,
+	0x49, 0xe0, 0x61, 0x75, 0x88, 0x8c, 0xd3, 0xb7, 0xf0, 0x8e, 0x7a, 0x00,
+	0x71, 0x8e, 0x7f, 0x1b, 0xb9, 0x8e, 0x41, 0x70, 0x8d, 0x49, 0x85, 0x55,
+	0x0b, 0xef, 0xda, 0xb6, 0x71, 0x87, 0x90, 0x6f, 0x8c, 0x9a, 0x3b, 0xf3,
+	0x7b, 0x7e, 0xee, 0xf1, 0x98, 0x41, 0xd2, 0xd7, 0x5c, 0xc7, 0xd1, 0x5d,
+	0xff, 0x1a, 0xb8, 0xe1, 0x7d, 0x8f, 0xf9, 0x2f, 0x06, 0x0a, 0x0a, 0x64,
+	0xae, 0xca, 0xe3, 0x56, 0x8d, 0xe7, 0x6e, 0x3a, 0x88, 0x73, 0xe7, 0x35,
+	0xe0, 0x87, 0x73, 0xe7, 0xf9, 0x2a, 0xd7, 0x7b, 0x69, 0x8c, 0xb6, 0x7a,
+	0xf9, 0x9c, 0xa3, 0xb0, 0xdb, 0x82, 0x4c, 0xff, 0x58, 0xc6, 0x8b, 0x94,
+	0xcf, 0x62, 0x4d, 0x06, 0xe6, 0xb1, 0xd6, 0x6c, 0x2a, 0xac, 0xb1, 0x5f,
+	0x5c, 0xc8, 0x57, 0xc4, 0x1c, 0x6d, 0x6e, 0xe3, 0x83, 0x93, 0xbd, 0x0f,
+	0x4c, 0xe6, 0x50, 0x03, 0xb1, 0x59, 0xc4, 0xbc, 0xd6, 0x96, 0x2e, 0xca,
+	0x74, 0xb1, 0xbc, 0x57, 0x7e, 0x76, 0x4b, 0x9e, 0x79, 0x6d, 0xa2, 0xcc,
+	0xfc, 0xc5, 0x76, 0x18, 0x8a, 0x4b, 0x07, 0x33, 0x2e, 0xad, 0x60, 0x3f,
+	0x07, 0x55, 0x5c, 0xea, 0xde, 0xc3, 0x19, 0x9f, 0xee, 0x46, 0xcb, 0x7d,
+	0x37, 0xb2, 0x38, 0x31, 0x61, 0x2f, 0xeb, 0x1d, 0x24, 0x03, 0x76, 0x45,
+	0x6a, 0x4d, 0x7f, 0x93, 0x4b, 0x1e, 0x73, 0x04, 0xe3, 0x53, 0x71, 0x29,
+	0xfa, 0x27, 0x60, 0x33, 0xf3, 0x02, 0xcb, 0xb1, 0xfc, 0x4e, 0x72, 0x7f,
+	0x85, 0x9c, 0xd8, 0x41, 0x0e, 0x7d, 0x1b, 0x2c, 0xc3, 0xdc, 0x30, 0x8a,
+	0xf1, 0x21, 0xf3, 0x02, 0x7c, 0xc6, 0xb2, 0xe5, 0x2c, 0x0e, 0x23, 0x7c,
+	0xe3, 0xba, 0x97, 0xe3, 0x23, 0x20, 0xab, 0xc6, 0xeb, 0xe0, 0x9a, 0x98,
+	0xf3, 0x22, 0xd7, 0xa1, 0x5c, 0x6f, 0xe6, 0xf5, 0xa9, 0x37, 0x35, 0x7b,
+	0xb7, 0x5a, 0x53, 0xf4, 0xd7, 0x9a, 0xe8, 0xd8, 0xb1, 0xd6, 0xf4, 0xac,
+	0xb4, 0xd6, 0xac, 0x58, 0x77, 0xaf, 0x35, 0x73, 0xd9, 0x7b, 0xd7, 0x9a,
+	0x71, 0x87, 0xf7, 0x08, 0xb9, 0x54, 0xf0, 0x5a, 0xa8, 0x69, 0x66, 0x7c,
+	0x11, 0xdd, 0xc6, 0x17, 0xd1, 0x69, 0xb7, 0x7c, 0x8e, 0x38, 0xa6, 0xdd,
+	0x72, 0x8b, 0x6b, 0xa0, 0x0d, 0xae, 0x81, 0x0c, 0xe4, 0xd2, 0x7e, 0xce,
+	0xc8, 0x7d, 0xc2, 0xbe, 0x1c, 0x04, 0x27, 0xb3, 0x1f, 0x8b, 0x19, 0x3f,
+	0xa0, 0xf5, 0x3e, 0x05, 0x3f, 0xe4, 0xbc, 0xc2, 0x3e, 0xfb, 0x7f, 0xe2,
+	0x15, 0xb2, 0x07, 0xc0, 0x0f, 0x36, 0xea, 0xcd, 0x46, 0x47, 0xd9, 0x02,
+	0x5f, 0x48, 0x39, 0xe7, 0x33, 0xf6, 0x53, 0xbe, 0x50, 0x3e, 0x51, 0x78,
+	0x2c, 0xd2, 0xbb, 0x3e, 0x63, 0x01, 0xe7, 0x23, 0x8f, 0x73, 0x22, 0xf3,
+	0xef, 0x4d, 0xf9, 0xae, 0x17, 0xa2, 0x2f, 0xc2, 0x9e, 0x33, 0x0e, 0xe6,
+	0xb5, 0x43, 0xeb, 0x36, 0xe4, 0x18, 0x0b, 0xe5, 0x3b, 0xce, 0x3d, 0xe9,
+	0xf9, 0x84, 0x6b, 0xe1, 0xff, 0x16, 0x1b, 0x17, 0xef, 0x82, 0x8d, 0x37,
+	0x33, 0x6c, 0xfc, 0xf2, 0x1e, 0xd8, 0xb8, 0xf8, 0x05, 0xb1, 0xe1, 0x3a,
+	0x1f, 0xa3, 0x5e, 0x7a, 0xcf, 0x63, 0x7c, 0x48, 0xf9, 0xb1, 0xbf, 0x53,
+	0x3e, 0x09, 0x6c, 0xe3, 0xd5, 0x9b, 0x32, 0xce, 0x72, 0x89, 0xfe, 0xd6,
+	0xad, 0x5c, 0x32, 0xfe, 0x6a, 0x8a, 0x8b, 0xf1, 0xb7, 0xa4, 0x3c, 0xb7,
+	0x03, 0x0e, 0xb8, 0x56, 0xbe, 0x0a, 0x1e, 0x68, 0xd1, 0xff, 0xa2, 0x56,
+	0x66, 0xce, 0xae, 0xda, 0x47, 0xdb, 0xf9, 0xbe, 0xe7, 0x7b, 0x5e, 0xa0,
+	0xb3, 0x62, 0x17, 0xfc, 0xb5, 0x9f, 0x5a, 0xaf, 0x9b, 0x7c, 0x7e, 0x00,
+	0x1e, 0x1e, 0x37, 0x39, 0x56, 0x71, 0x56, 0xc4, 0x73, 0x7f, 0x3d, 0x0d,
+	0x3c, 0xfa, 0xbc, 0x76, 0xb5, 0xee, 0x3e, 0xae, 0xff, 0x1e, 0x4a, 0x92,
+	0x3b, 0xf2, 0xc8, 0xb6, 0x73, 0xb3, 0x81, 0x73, 0x73, 0x5d, 0xe9, 0xe0,
+	0xb3, 0x55, 0xea, 0xbf, 0x13, 0xea, 0xac, 0x7c, 0x53, 0x9e, 0x53, 0xe7,
+	0xe5, 0xd1, 0x02, 0x0d, 0xce, 0x67, 0x58, 0x61, 0x5f, 0x0c, 0xab, 0x7a,
+	0x82, 0x31, 0xd5, 0x42, 0xbe, 0x5d, 0x82, 0x3f, 0x1a, 0x2a, 0x16, 0xb0,
+	0xf6, 0xcc, 0x1f, 0x2d, 0xf8, 0xa3, 0x9e, 0xa4, 0x31, 0xf1, 0xe5, 0x9e,
+	0x1d, 0xfe, 0x88, 0x7c, 0x6a, 0x2f, 0x9a, 0x38, 0x6f, 0x5f, 0x49, 0x54,
+	0xfe, 0x5c, 0x68, 0xb5, 0xa9, 0xf9, 0x60, 0xed, 0x38, 0xd7, 0x6d, 0x5c,
+	0x77, 0xcd, 0x2c, 0x55, 0xd1, 0xd7, 0xb3, 0x29, 0x84, 0x4f, 0xbe, 0x7d,
+	0x90, 0x16, 0x8d, 0x1a, 0xe3, 0x17, 0xef, 0x09, 0x35, 0xc3, 0x83, 0xa8,
+	0xa5, 0x92, 0xb1, 0x45, 0xbd, 0x36, 0x06, 0x1c, 0x35, 0x29, 0x80, 0x9d,
+	0x01, 0x74, 0xcf, 0xb5, 0x6d, 0x7b, 0xb9, 0xcd, 0x67, 0xa4, 0x26, 0xf1,
+	0x19, 0xbc, 0xdb, 0xbb, 0x0e, 0x7d, 0x03, 0xcf, 0xe0, 0xcc, 0xea, 0xc4,
+	0xc0, 0xd5, 0xcb, 0x89, 0x45, 0xad, 0x12, 0xdf, 0x51, 0x30, 0x57, 0x96,
+	0xa1, 0xe3, 0x99, 0x42, 0x8a, 0xcb, 0x32, 0xf4, 0x70, 0xcc, 0x10, 0xe6,
+	0x63, 0xff, 0xe5, 0x58, 0x2b, 0xf7, 0xd5, 0xee, 0x85, 0xec, 0xbc, 0x4a,
+	0xca, 0x07, 0xec, 0xdf, 0xd0, 0x7b, 0xbe, 0x90, 0xdf, 0xc7, 0xb4, 0x10,
+	0xf3, 0x8d, 0x7d, 0x8c, 0x43, 0x0d, 0x78, 0xc3, 0x98, 0x84, 0xfb, 0x90,
+	0x57, 0xf6, 0x21, 0x37, 0x97, 0x8a, 0xaa, 0x6d, 0x26, 0xc7, 0xb2, 0xf1,
+	0xba, 0x1a, 0xc7, 0x39, 0x21, 0x4e, 0xd4, 0x59, 0x41, 0x8b, 0x3a, 0xe4,
+	0x34, 0x7c, 0x9c, 0x81, 0x50, 0x5b, 0xac, 0x24, 0x9c, 0xcf, 0xf7, 0xd9,
+	0xba, 0xe2, 0xb9, 0x4d, 0xc8, 0xe0, 0x79, 0x83, 0xf4, 0x86, 0xcf, 0xf7,
+	0x07, 0xd9, 0xdd, 0x46, 0x89, 0x86, 0x21, 0x0f, 0xbb, 0xc6, 0xd8, 0xae,
+	0xa0, 0xa1, 0x6a, 0x11, 0xd6, 0xbd, 0x5f, 0x4f, 0xef, 0x5c, 0x7e, 0x93,
+	0xcd, 0x65, 0x83, 0x5f, 0x08, 0xe7, 0x1d, 0x9f, 0xf3, 0xda, 0xd7, 0x0c,
+	0xba, 0x4e, 0x8a, 0x23, 0xc5, 0x37, 0x90, 0xef, 0x0e, 0x42, 0x26, 0x50,
+	0xfc, 0x92, 0x9e, 0x19, 0x72, 0x99, 0x8a, 0xb1, 0x5d, 0xc7, 0x77, 0xcc,
+	0xed, 0xef, 0x01, 0x62, 0xab, 0x9a, 0xcd, 0xd7, 0x8f, 0xd3, 0x4d, 0xe0,
+	0x74, 0xb3, 0xb0, 0x75, 0xee, 0x28, 0x15, 0x30, 0x8e, 0x6d, 0x64, 0x2e,
+	0x61, 0x99, 0x4f, 0xac, 0xed, 0x7a, 0x2a, 0x3b, 0xe8, 0xf8, 0x53, 0x9f,
+	0x8e, 0x12, 0xaf, 0x4d, 0x34, 0xd2, 0xf3, 0xb3, 0xfa, 0x6b, 0xc0, 0xcf,
+	0x38, 0x6f, 0x3c, 0xa0, 0x63, 0x1d, 0x5c, 0x7f, 0xd5, 0x55, 0x3f, 0x0e,
+	0x56, 0xdb, 0xf4, 0xfe, 0x30, 0x9b, 0x67, 0x5f, 0x1a, 0x0f, 0x1e, 0xda,
+	0x64, 0xb3, 0xcf, 0x76, 0x6b, 0x87, 0x79, 0x91, 0xd8, 0xbd, 0x19, 0x8d,
+	0xf1, 0x66, 0xd4, 0x38, 0x07, 0xe3, 0x79, 0x0b, 0x1f, 0x8c, 0xd5, 0xcf,
+	0xc7, 0xa8, 0xf5, 0x05, 0x31, 0xfa, 0x46, 0x9b, 0xb9, 0x22, 0xc5, 0x68,
+	0xe3, 0x0e, 0x8c, 0xa2, 0x06, 0x2a, 0xe5, 0xf8, 0xe4, 0x78, 0xc9, 0xf1,
+	0x99, 0x3f, 0xf3, 0xfd, 0x08, 0x38, 0x38, 0xe3, 0xb6, 0x18, 0xdc, 0x16,
+	0xa9, 0x1c, 0xe7, 0x96, 0x23, 0x4a, 0xe3, 0x78, 0x19, 0x71, 0x1c, 0x19,
+	0x9c, 0xf3, 0x38, 0x86, 0x59, 0x8e, 0xe3, 0x98, 0xe5, 0x46, 0x32, 0x39,
+	0xb4, 0x88, 0xe7, 0x28, 0x8b, 0xe7, 0x16, 0x78, 0x37, 0xca, 0xe2, 0xb9,
+	0x85, 0x18, 0x5e, 0xc9, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0xdf, 0xdb, 0x19,
+	0x55, 0x95, 0x8b, 0x9d, 0x3a, 0x78, 0x6d, 0x45, 0xe9, 0x6c, 0x62, 0x9d,
+	0xb0, 0xb1, 0x93, 0xc7, 0xc5, 0x1d, 0xf7, 0x5b, 0x58, 0xcf, 0xad, 0xbc,
+	0x32, 0x8b, 0xbc, 0x72, 0x0e, 0x79, 0xa5, 0xdb, 0x77, 0xbf, 0x75, 0x56,
+	0xe5, 0x95, 0x27, 0x8b, 0x79, 0x5e, 0xe9, 0x66, 0x79, 0xa5, 0xab, 0xf2,
+	0xca, 0x13, 0x45, 0xce, 0x2b, 0x31, 0x05, 0xc5, 0xfe, 0xbc, 0x12, 0x6f,
+	0xcb, 0x2b, 0xb9, 0x2c, 0xf7, 0xef, 0x94, 0x57, 0x72, 0x9f, 0x71, 0x6e,
+	0xb1, 0x72, 0x5e, 0xbd, 0x2d, 0x9f, 0xe4, 0x63, 0xd8, 0x56, 0xe6, 0x25,
+	0xe6, 0xe0, 0xb4, 0xae, 0xbf, 0x92, 0xe4, 0xb1, 0x74, 0x0c, 0xf3, 0xe0,
+	0xbd, 0xb3, 0x53, 0x2c, 0xd9, 0x59, 0x2c, 0x0d, 0xa7, 0x32, 0x9d, 0xfe,
+	0x78, 0x3a, 0x56, 0xdc, 0x1e, 0x4f, 0xb9, 0x9e, 0x3c, 0x9e, 0x52, 0x9d,
+	0x1f, 0x1a, 0x65, 0xae, 0x07, 0x70, 0x96, 0x76, 0xfd, 0x39, 0xf4, 0x5e,
+	0xe8, 0x4d, 0xa3, 0xae, 0x36, 0xe9, 0x6a, 0xce, 0x37, 0xea, 0xbe, 0x07,
+	0x6d, 0x2f, 0xb7, 0xb5, 0xb8, 0xf5, 0xad, 0x8b, 0xda, 0xfa, 0x7d, 0xf0,
+	0xc8, 0x79, 0xf5, 0xfd, 0x33, 0x79, 0xb5, 0x84, 0x33, 0xb0, 0x97, 0x8f,
+	0x7b, 0x1d, 0xf3, 0xb9, 0xe2, 0x2c, 0x9e, 0x5e, 0xee, 0xdd, 0x82, 0xf9,
+	0x8a, 0xc7, 0x7d, 0xff, 0x44, 0x0e, 0x41, 0x5d, 0xbe, 0x35, 0x96, 0xcf,
+	0x38, 0x1e, 0xd6, 0xec, 0xd0, 0xa5, 0x6d, 0xe7, 0x9c, 0xf4, 0x7c, 0x83,
+	0x75, 0xa3, 0x3e, 0xe1, 0x3a, 0x25, 0xfc, 0x8a, 0x4e, 0x2f, 0xd1, 0xb7,
+	0x7c, 0xee, 0xd3, 0x69, 0xf6, 0x31, 0x29, 0x5f, 0x40, 0xcd, 0xf2, 0xf4,
+	0xb6, 0x9a, 0xa5, 0x48, 0xe3, 0x07, 0xfa, 0xcf, 0x87, 0x37, 0xe5, 0xf8,
+	0xa4, 0x7b, 0x36, 0xa0, 0x40, 0x9b, 0x5d, 0xe7, 0x5a, 0x76, 0xab, 0x76,
+	0x25, 0x1a, 0xbd, 0x21, 0xf5, 0x49, 0xce, 0x85, 0x57, 0x33, 0x5f, 0xe1,
+	0xdb, 0x99, 0x1b, 0xe0, 0xd6, 0x48, 0xdd, 0xf1, 0x06, 0xeb, 0x3c, 0x0f,
+	0xbf, 0xa3, 0x4d, 0xb8, 0xbe, 0xb9, 0xdb, 0xbd, 0xab, 0x89, 0x7d, 0x71,
+	0x9d, 0xa3, 0x06, 0xa9, 0xbb, 0x8b, 0x25, 0xdf, 0xfd, 0x59, 0x8b, 0x52,
+	0x9e, 0x88, 0xfc, 0x05, 0xd8, 0x02, 0x9c, 0x8b, 0x45, 0xec, 0xcd, 0x24,
+	0x78, 0xc9, 0x75, 0x0e, 0xe8, 0x42, 0x61, 0x7f, 0x19, 0xba, 0x8d, 0x03,
+	0x5c, 0x3f, 0x7e, 0x2a, 0x97, 0x7b, 0x2a, 0x07, 0xfb, 0x8c, 0x91, 0x7a,
+	0xb2, 0x5b, 0xe7, 0x36, 0x48, 0xf8, 0xb9, 0x80, 0x79, 0x9c, 0xbb, 0xe0,
+	0xa7, 0x24, 0xa2, 0x33, 0x8e, 0x98, 0xed, 0x38, 0x62, 0xae, 0xa3, 0x03,
+	0xdd, 0xb6, 0x4d, 0xbb, 0xb0, 0x27, 0xc8, 0xc1, 0xf4, 0x00, 0x6c, 0xb9,
+	0xe0, 0x88, 0x3a, 0x6a, 0xc1, 0x1f, 0x18, 0xae, 0x78, 0x9a, 0x3e, 0xc1,
+	0x1a, 0x6f, 0xc8, 0xf4, 0xde, 0xc5, 0x11, 0xd1, 0xd6, 0xdc, 0x37, 0x30,
+	0x37, 0xdb, 0xc4, 0x31, 0xca, 0xf9, 0x72, 0x5e, 0x5b, 0x80, 0x8f, 0x8e,
+	0xac, 0x6b, 0xe0, 0x35, 0xce, 0x97, 0x23, 0xd9, 0xfd, 0x12, 0xf6, 0x07,
+	0xeb, 0xbf, 0x74, 0x47, 0xad, 0x99, 0xd7, 0x94, 0xe9, 0xdd, 0x69, 0x3c,
+	0xc3, 0xf3, 0x13, 0x6c, 0x99, 0x98, 0xba, 0xa0, 0xce, 0x3d, 0xd3, 0xa8,
+	0xf1, 0xb8, 0x95, 0xa8, 0x83, 0xf8, 0xae, 0x8b, 0x6b, 0x27, 0x89, 0xf8,
+	0x4f, 0x9f, 0x63, 0x3e, 0x13, 0xcd, 0xb0, 0x0e, 0x3e, 0x1b, 0x71, 0xfc,
+	0xfc, 0x1b, 0x2f, 0xf3, 0x0a, 0xbd, 0x68, 0x18, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_tpat_fw_09 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
 	.start_addr			= 0x08000860,
 
 	.text_addr			= 0x08000800,
-	.text_len			= 0x1480,
+	.text_len			= 0x1864,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TPAT_b09FwText,
 	.gz_text_len			= sizeof(bnx2_TPAT_b09FwText),
 
-	.data_addr			= 0x08001ca0,
+	.data_addr			= 0x08002080,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_TPAT_b09FwData,
 
-	.sbss_addr			= 0x08001ca0,
-	.sbss_len			= 0x34,
+	.sbss_addr			= 0x08002088,
+	.sbss_len			= 0x2c,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_TPAT_b09FwSbss,
 
-	.bss_addr			= 0x08001ce0,
-	.bss_len			= 0x250,
+	.bss_addr			= 0x080020c0,
+	.bss_len			= 0x850,
 	.bss_index			= 0x0,
 	.bss				= bnx2_TPAT_b09FwBss,
 
@@ -3308,732 +3279,769 @@ static struct fw_info bnx2_tpat_fw_09 = 
 };
 
 static u8 bnx2_TXP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x51, 0xfe, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x7b, 0x7f, 0x70,
-	0x1b, 0xe7, 0x99, 0xde, 0xbb, 0x0b, 0x80, 0x04, 0x29, 0x8a, 0x5a, 0x31,
-	0x30, 0x83, 0x38, 0xb4, 0x8d, 0x15, 0x17, 0x34, 0x6d, 0xf2, 0x1c, 0x58,
-	0xe5, 0xf9, 0xd8, 0x06, 0xb5, 0xd7, 0xc0, 0x92, 0xa2, 0x63, 0x26, 0x47,
-	0xbb, 0xcc, 0x9d, 0x92, 0x51, 0x7d, 0x28, 0x48, 0x29, 0x6e, 0xe3, 0xb4,
-	0xaa, 0xe3, 0x3f, 0x34, 0x4d, 0x5b, 0xc3, 0x00, 0x25, 0xcb, 0x2e, 0x44,
-	0xd0, 0x16, 0x63, 0xa5, 0x33, 0x37, 0x53, 0x18, 0x80, 0x28, 0xe7, 0xba,
-	0x24, 0xdc, 0xe4, 0x2e, 0xe9, 0x1f, 0xc9, 0x99, 0xa5, 0x6c, 0xc5, 0x6d,
-	0xae, 0x33, 0xbe, 0x3f, 0xda, 0xa6, 0x37, 0xd7, 0x19, 0x8d, 0xfc, 0x23,
-	0xce, 0x8f, 0xb9, 0xb8, 0x69, 0x7a, 0x56, 0x5b, 0xd9, 0xe8, 0xf3, 0x7c,
-	0xbb, 0x4b, 0x82, 0x32, 0x15, 0x5b, 0xd7, 0x76, 0xa6, 0x9c, 0xc1, 0x10,
-	0xfb, 0xed, 0xb7, 0xdf, 0xf7, 0xfe, 0x7e, 0xdf, 0xe7, 0xfd, 0x16, 0x71,
-	0x91, 0x6e, 0xf1, 0xff, 0x76, 0xe3, 0x93, 0x38, 0x7a, 0xec, 0xb1, 0x3b,
-	0xc6, 0xef, 0xd8, 0x2f, 0x72, 0xe7, 0x9d, 0xb2, 0x2b, 0xaa, 0xf3, 0xe6,
-	0xdb, 0x21, 0x91, 0xdc, 0x4f, 0xe5, 0xaf, 0xfc, 0x87, 0xc7, 0x8d, 0x60,
-	0x7d, 0x7e, 0x24, 0xaa, 0xa7, 0x5f, 0xcc, 0x64, 0x2c, 0x89, 0x86, 0xd2,
-	0x33, 0x9f, 0x9d, 0xb3, 0x44, 0x6c, 0x77, 0x24, 0x91, 0x95, 0xf7, 0x5a,
-	0x85, 0x58, 0x58, 0x38, 0x7e, 0x53, 0xfa, 0xca, 0xe3, 0xdf, 0xff, 0x2d,
-	0xf3, 0x9d, 0x6a, 0x48, 0xa2, 0x46, 0x3a, 0x27, 0xc6, 0x90, 0x44, 0x07,
-	0xf0, 0xcc, 0xef, 0xdf, 0x3a, 0xa5, 0x4b, 0x6f, 0xb0, 0x56, 0x5c, 0x16,
-	0x2a, 0x6f, 0xb7, 0xbe, 0x7f, 0x6b, 0x4c, 0xfe, 0x55, 0xd3, 0x90, 0x17,
-	0x9b, 0x61, 0x6d, 0xb2, 0xd2, 0x23, 0xa5, 0x8a, 0x2b, 0xc7, 0xcb, 0x05,
-	0xc9, 0x36, 0x5f, 0x90, 0xe2, 0xb2, 0xd1, 0x9b, 0x39, 0xf7, 0x07, 0x52,
-	0x5a, 0xee, 0xeb, 0xcd, 0x9e, 0x73, 0xa5, 0x58, 0x8e, 0xf7, 0x66, 0x9a,
-	0x46, 0x6f, 0xf6, 0x4c, 0x0c, 0xd7, 0x7d, 0xbd, 0x99, 0x33, 0x66, 0x41,
-	0xa4, 0x1f, 0x73, 0xe2, 0xbd, 0xd9, 0x8a, 0x99, 0x13, 0x19, 0x4c, 0xbd,
-	0x22, 0x03, 0xbd, 0xd9, 0x66, 0x4d, 0x5b, 0x37, 0x34, 0x29, 0xfe, 0x86,
-	0x18, 0xbd, 0xe9, 0xcb, 0xad, 0x4f, 0x58, 0x86, 0xec, 0xb5, 0x64, 0xcf,
-	0x1e, 0x4b, 0x9e, 0x88, 0xa7, 0xa3, 0x92, 0x3f, 0xdd, 0x25, 0xb6, 0xe2,
-	0xc9, 0x90, 0xfc, 0x99, 0x11, 0x63, 0x43, 0x22, 0x62, 0xc7, 0x82, 0xeb,
-	0x56, 0x2b, 0x93, 0xfa, 0x02, 0xe5, 0x8a, 0xbd, 0xa4, 0x77, 0xb2, 0x29,
-	0x92, 0xa9, 0x44, 0x25, 0x93, 0x7a, 0xaf, 0xe5, 0x3d, 0x13, 0xc5, 0xbe,
-	0xe1, 0xde, 0x89, 0x4a, 0xab, 0xe5, 0xa4, 0xb0, 0x47, 0x2a, 0x78, 0x36,
-	0x22, 0xd5, 0x98, 0x5d, 0x2d, 0xa5, 0x4c, 0xdd, 0xd3, 0x09, 0x79, 0xe4,
-	0xb5, 0x2d, 0xba, 0xf5, 0xdb, 0x92, 0x8f, 0x49, 0xb5, 0x98, 0xba, 0x4b,
-	0x9e, 0x4e, 0x19, 0x72, 0x12, 0xeb, 0x3d, 0x95, 0x82, 0x1c, 0xad, 0x63,
-	0x5a, 0xa6, 0x69, 0xc6, 0x45, 0x7b, 0x5a, 0x32, 0x67, 0x06, 0x8d, 0xac,
-	0x60, 0x6f, 0xab, 0x75, 0x4b, 0x26, 0x85, 0xfd, 0x46, 0xff, 0x67, 0xcb,
-	0x8e, 0x99, 0xb9, 0xaa, 0x0c, 0x48, 0xb1, 0x32, 0x98, 0xfa, 0x13, 0xd1,
-	0xa4, 0xd3, 0xa2, 0x7c, 0x5a, 0x72, 0x3f, 0xf6, 0xcd, 0x58, 0x18, 0x6f,
-	0x8a, 0xad, 0x27, 0x23, 0xf2, 0x0f, 0x0c, 0x33, 0x91, 0x09, 0xf5, 0x4b,
-	0xf1, 0x74, 0x27, 0xe8, 0xb4, 0xfb, 0x74, 0xcc, 0x3d, 0x30, 0x26, 0xb1,
-	0x5d, 0x22, 0x5a, 0x28, 0x9d, 0xc4, 0xba, 0x22, 0x45, 0x77, 0x00, 0xcf,
-	0x26, 0xc7, 0x7f, 0x2a, 0x7b, 0x24, 0xb1, 0x37, 0x2c, 0x25, 0xb7, 0x1b,
-	0x72, 0x34, 0xa0, 0x83, 0xe4, 0xf8, 0x5f, 0x40, 0x29, 0xba, 0x95, 0x8c,
-	0x1f, 0x93, 0x9c, 0x96, 0x6d, 0x76, 0x48, 0x29, 0x19, 0x95, 0x05, 0xd0,
-	0xb1, 0x90, 0xfa, 0xa2, 0x96, 0x39, 0x77, 0x50, 0xcb, 0x9e, 0xc3, 0xbc,
-	0x66, 0xdd, 0xb7, 0x35, 0x03, 0xeb, 0xe8, 0x52, 0x4c, 0x1e, 0xc4, 0xbd,
-	0xa8, 0xcc, 0x61, 0xde, 0x1c, 0x78, 0x2a, 0x35, 0xf7, 0xc8, 0xfa, 0x6c,
-	0xac, 0x37, 0x03, 0x1d, 0x16, 0x71, 0xff, 0xb7, 0x67, 0x34, 0x31, 0x2c,
-	0x5b, 0x7e, 0x3c, 0x06, 0x1d, 0x9e, 0x81, 0xfe, 0xce, 0xc4, 0xe5, 0x78,
-	0x45, 0x62, 0xba, 0x24, 0xe3, 0x79, 0x79, 0x41, 0xea, 0x2e, 0xf5, 0x0f,
-	0x7d, 0x42, 0xdf, 0x45, 0x97, 0xcf, 0x41, 0x6f, 0x15, 0x07, 0xf2, 0x98,
-	0x02, 0x0d, 0x0f, 0x6a, 0xf7, 0xd7, 0x67, 0xb5, 0x03, 0xcd, 0x1f, 0x6b,
-	0xd2, 0x7d, 0x4c, 0xfb, 0x5c, 0xf3, 0x88, 0xe6, 0xcb, 0x1e, 0xba, 0x8b,
-	0x8a, 0x3d, 0x13, 0x95, 0x95, 0xa6, 0xa7, 0xbb, 0x1a, 0xec, 0xd3, 0x36,
-	0x6c, 0xe8, 0xe1, 0x6f, 0x6f, 0xce, 0x59, 0x69, 0xc6, 0x64, 0x01, 0xb4,
-	0x1d, 0x6f, 0x72, 0xfe, 0xef, 0x41, 0x3f, 0x51, 0x71, 0x6f, 0xed, 0x91,
-	0x1c, 0xc6, 0x8b, 0x67, 0xc4, 0xce, 0xa4, 0x74, 0x3c, 0xd3, 0x2b, 0x21,
-	0xab, 0x1f, 0x9f, 0x6e, 0x99, 0xab, 0x77, 0xda, 0x21, 0x2b, 0x26, 0x73,
-	0x4d, 0xca, 0x10, 0xff, 0x2b, 0x81, 0x1c, 0x49, 0x2b, 0xc7, 0xf9, 0x1c,
-	0xc7, 0x0d, 0x8c, 0xb7, 0x8f, 0xd1, 0x2e, 0x7a, 0x41, 0x8f, 0x39, 0x2c,
-	0x18, 0xcb, 0x57, 0x92, 0xc6, 0xe7, 0xf8, 0xbf, 0x49, 0xd9, 0x06, 0x32,
-	0x0d, 0x63, 0xae, 0x2e, 0xf9, 0x3a, 0xf6, 0x39, 0x7d, 0xa5, 0x15, 0x19,
-	0xc3, 0xb5, 0xf5, 0x4b, 0xc8, 0x92, 0xfb, 0x86, 0x41, 0x93, 0x2e, 0xb9,
-	0x3a, 0xd7, 0xe2, 0x7d, 0x81, 0xee, 0x8b, 0x7b, 0x75, 0x19, 0x86, 0x7e,
-	0x4d, 0xec, 0xd3, 0x85, 0x39, 0x3d, 0x90, 0x1f, 0x78, 0x3d, 0x87, 0xef,
-	0xe0, 0x5d, 0xb7, 0x74, 0x3c, 0xdf, 0x29, 0x73, 0x29, 0xda, 0x0b, 0xe9,
-	0xdc, 0x85, 0xb5, 0xbb, 0x64, 0xfe, 0x34, 0xe5, 0x01, 0xbb, 0xaa, 0xc4,
-	0xa4, 0x74, 0xc6, 0x34, 0x1c, 0x31, 0x21, 0x1b, 0x1b, 0xf3, 0x3a, 0x25,
-	0x67, 0xb4, 0x5a, 0x13, 0xa9, 0x11, 0xe3, 0x9b, 0xca, 0xce, 0x47, 0x8c,
-	0xa4, 0x26, 0x85, 0x8e, 0xf4, 0x10, 0x64, 0x6b, 0x1e, 0x14, 0xe1, 0xf5,
-	0x0f, 0xc4, 0x9e, 0xa5, 0xff, 0xc4, 0xb8, 0x17, 0xfc, 0xa9, 0x1f, 0xf4,
-	0xd3, 0xe7, 0x06, 0xa0, 0x97, 0xb8, 0xf2, 0x83, 0x89, 0x1d, 0xfd, 0xc0,
-	0x9c, 0xaa, 0x82, 0xdf, 0xe2, 0xb9, 0x30, 0xfd, 0x2f, 0x05, 0x73, 0x93,
-	0x5d, 0x56, 0x14, 0xb6, 0x40, 0x5a, 0xc6, 0xb1, 0x7e, 0xab, 0xf5, 0xd9,
-	0x94, 0x47, 0x53, 0xf1, 0x8c, 0x8d, 0x67, 0xc3, 0x90, 0xbb, 0xf9, 0x70,
-	0x42, 0xed, 0x3f, 0xee, 0xef, 0x6f, 0xc8, 0x1c, 0xe8, 0x2e, 0x56, 0x42,
-	0x92, 0x35, 0xb8, 0xc6, 0x9f, 0x71, 0x3c, 0xe7, 0xad, 0x05, 0xbb, 0x3d,
-	0x35, 0x68, 0xdc, 0x07, 0x5f, 0xa2, 0x8f, 0x15, 0x57, 0x29, 0x63, 0xac,
-	0x33, 0x46, 0x19, 0x1b, 0x8a, 0xc6, 0xcc, 0x19, 0xda, 0x91, 0x0c, 0x84,
-	0x84, 0x76, 0x8e, 0x98, 0x01, 0xbb, 0x2a, 0xf9, 0x76, 0x95, 0x77, 0xa9,
-	0xff, 0xbb, 0x7d, 0xff, 0xd4, 0x65, 0x28, 0x49, 0x7b, 0x7f, 0x5a, 0xb2,
-	0xf0, 0xf1, 0x39, 0xec, 0x54, 0x07, 0x4f, 0xb5, 0xca, 0x20, 0x64, 0x15,
-	0xf8, 0x1d, 0xf4, 0x3b, 0xfa, 0x6e, 0x2b, 0x88, 0x05, 0xc5, 0x0a, 0x7d,
-	0xa6, 0x68, 0xe8, 0x52, 0xc0, 0x07, 0x76, 0x63, 0x99, 0xc3, 0x99, 0x90,
-	0x39, 0x93, 0x03, 0x6d, 0xb0, 0x7b, 0xc9, 0xdc, 0x49, 0x7b, 0xc6, 0x9c,
-	0xa6, 0xec, 0x0f, 0xfc, 0xac, 0xe6, 0x52, 0x4f, 0xdd, 0xd8, 0x37, 0xa0,
-	0x29, 0x8c, 0x31, 0xae, 0x13, 0x85, 0xcd, 0x07, 0x36, 0x43, 0xfb, 0x33,
-	0xed, 0x75, 0xe9, 0x90, 0xe1, 0x24, 0x62, 0xd9, 0x19, 0x1d, 0xfa, 0x1b,
-	0x40, 0x4c, 0x09, 0xcb, 0x11, 0xc8, 0xea, 0x4b, 0x15, 0xd2, 0xe7, 0xc0,
-	0xef, 0x10, 0xdb, 0xce, 0x4c, 0xc2, 0xcf, 0xa6, 0xb4, 0x09, 0xf8, 0xc4,
-	0x67, 0xea, 0xa4, 0xa9, 0x25, 0xf4, 0x4b, 0xe7, 0x5c, 0x4e, 0x9b, 0x6c,
-	0x1e, 0xd4, 0xa6, 0xce, 0xd1, 0x4f, 0xe8, 0x23, 0xa6, 0xf1, 0x80, 0x78,
-	0x3c, 0x14, 0x9b, 0xaf, 0x68, 0xf4, 0xd5, 0xe2, 0xa9, 0x2e, 0xd0, 0xb1,
-	0x0b, 0xf4, 0x18, 0xf0, 0x3d, 0xd8, 0x97, 0x65, 0xce, 0xd0, 0x66, 0x9c,
-	0xa4, 0x95, 0xf8, 0xe7, 0xf2, 0x41, 0x39, 0x4c, 0x6c, 0xca, 0x61, 0x04,
-	0x32, 0xd9, 0x2e, 0x87, 0x85, 0x0f, 0xca, 0xc1, 0x2e, 0x40, 0x0e, 0x0b,
-	0x88, 0x43, 0x0b, 0x4d, 0xf2, 0xdc, 0x12, 0xfd, 0x4e, 0x81, 0x75, 0xca,
-	0xbd, 0x7a, 0x9a, 0x36, 0x4a, 0x3f, 0x49, 0x26, 0x4a, 0x58, 0xa1, 0xe1,
-	0xf6, 0x28, 0xdf, 0x98, 0x54, 0xb2, 0xf8, 0x30, 0x7e, 0xc9, 0xdf, 0x16,
-	0xcf, 0x53, 0x75, 0xc6, 0x1b, 0xd8, 0x79, 0xd2, 0x32, 0xbe, 0x20, 0x5b,
-	0x7c, 0xdf, 0xb7, 0xc5, 0x37, 0xf6, 0x09, 0x62, 0x10, 0x79, 0x0e, 0xe2,
-	0x31, 0x6d, 0xe5, 0xa5, 0x56, 0xc8, 0xb2, 0xa0, 0x03, 0xda, 0x0b, 0x69,
-	0x30, 0x8d, 0xcf, 0x0a, 0xfe, 0x23, 0x2e, 0xd0, 0x97, 0x72, 0x6a, 0x5e,
-	0x87, 0xe4, 0xf6, 0x7a, 0xf3, 0xe7, 0x2a, 0xad, 0x5f, 0xe8, 0xe9, 0xf7,
-	0x5b, 0x99, 0x31, 0xcb, 0xf7, 0xf1, 0xa8, 0x7c, 0xb9, 0x6e, 0xe6, 0x12,
-	0x5a, 0x8f, 0x14, 0x6e, 0x40, 0x5c, 0xa9, 0xd0, 0x3f, 0xfa, 0xaf, 0x11,
-	0xcb, 0x06, 0xfc, 0x58, 0xf6, 0x13, 0xc8, 0x9e, 0xb9, 0xe7, 0xf0, 0xfb,
-	0xeb, 0x31, 0xfe, 0x4f, 0x1a, 0x33, 0xf2, 0x05, 0xe6, 0x9b, 0x3d, 0xba,
-	0x8a, 0xdf, 0x16, 0x73, 0x41, 0x21, 0x9c, 0xee, 0x96, 0xc2, 0x5e, 0x29,
-	0x84, 0xd2, 0xf4, 0x23, 0xfa, 0x46, 0x87, 0x4f, 0x77, 0x90, 0x3b, 0xf8,
-	0x77, 0x4c, 0x17, 0x8b, 0x73, 0x90, 0x27, 0x2a, 0xe4, 0xe3, 0xbd, 0x40,
-	0x27, 0x78, 0x46, 0x22, 0x9e, 0xcd, 0x4d, 0x23, 0x66, 0x52, 0xa6, 0xed,
-	0xf6, 0xc2, 0x58, 0x2a, 0x09, 0xdd, 0x62, 0x2c, 0x15, 0x23, 0x94, 0x7e,
-	0x50, 0xb3, 0xeb, 0x5f, 0xd4, 0x6c, 0xc8, 0xce, 0x86, 0xec, 0x6c, 0xc8,
-	0x2e, 0x03, 0xd9, 0x65, 0x9b, 0xa4, 0x87, 0xb4, 0x78, 0xeb, 0x3b, 0xde,
-	0xfa, 0xa0, 0xb3, 0x5f, 0xf2, 0xca, 0xc7, 0xc9, 0x2f, 0x62, 0xb2, 0x8a,
-	0x07, 0x93, 0x9a, 0x17, 0x0f, 0xb8, 0xde, 0x14, 0x9e, 0xbf, 0x1b, 0x79,
-	0xce, 0xd6, 0x75, 0x6b, 0x4b, 0x26, 0x0b, 0x6d, 0x32, 0x29, 0xb9, 0x94,
-	0x11, 0xe7, 0xd3, 0x97, 0x5d, 0xe8, 0x3d, 0x90, 0xcb, 0x34, 0x68, 0xe8,
-	0x24, 0xef, 0x3e, 0x1f, 0x5c, 0xbf, 0xcf, 0x5f, 0xff, 0xd3, 0x58, 0x93,
-	0xbe, 0xbb, 0xd3, 0xbe, 0xdc, 0x93, 0xb9, 0xf4, 0xd7, 0xf1, 0x83, 0x5a,
-	0x02, 0x31, 0xfa, 0x45, 0xf8, 0xda, 0xc5, 0x50, 0x5c, 0xbe, 0x7f, 0xeb,
-	0x6b, 0xa8, 0x2f, 0xa4, 0x70, 0x63, 0xba, 0x95, 0x08, 0xa7, 0xdf, 0x6b,
-	0x2d, 0x8c, 0x21, 0x7e, 0xa6, 0xcd, 0x78, 0x26, 0x34, 0x2a, 0x2f, 0x35,
-	0x87, 0xe5, 0x3b, 0x4d, 0x4b, 0xfe, 0xa8, 0x99, 0x90, 0x3f, 0x6c, 0x0e,
-	0xc8, 0xb7, 0x9b, 0x71, 0xf9, 0x56, 0x33, 0xa8, 0x45, 0xe2, 0xb4, 0xa5,
-	0x5e, 0xa7, 0xb9, 0x53, 0x3d, 0x04, 0x3b, 0xc7, 0x5a, 0x99, 0xb1, 0x70,
-	0x2e, 0x94, 0x56, 0x35, 0xc2, 0xcc, 0xd1, 0xf2, 0xe3, 0x2d, 0xdd, 0xb2,
-	0x0a, 0xba, 0xde, 0x33, 0x6e, 0xdc, 0x25, 0x39, 0x3d, 0x8d, 0x31, 0x77,
-	0x3c, 0xec, 0x94, 0xbb, 0x90, 0x5f, 0xa2, 0xa8, 0x65, 0x06, 0xa4, 0x80,
-	0x75, 0x0b, 0xcd, 0x56, 0x6b, 0x29, 0xf5, 0x0f, 0x3f, 0x65, 0xfc, 0x8d,
-	0x7f, 0xd9, 0x29, 0xbd, 0xdf, 0x5e, 0x37, 0x86, 0xfe, 0xbb, 0x5f, 0x0f,
-	0xa1, 0xc6, 0xea, 0x57, 0x8b, 0xe7, 0xb4, 0xf4, 0xa8, 0x93, 0x70, 0x37,
-	0x70, 0x5f, 0xa2, 0xfd, 0xd6, 0xcf, 0x51, 0x85, 0xc8, 0xee, 0x98, 0xc5,
-	0x9a, 0x6b, 0x26, 0xfb, 0x79, 0xfc, 0xff, 0x58, 0x5a, 0xf6, 0xf4, 0xe1,
-	0xff, 0xde, 0x34, 0x4c, 0x2a, 0xcd, 0x98, 0xac, 0xb5, 0xc5, 0x64, 0xd1,
-	0x1c, 0xe4, 0xdf, 0x05, 0xf0, 0xe4, 0x40, 0x1e, 0xbf, 0xd3, 0x8c, 0x6a,
-	0xd9, 0xd3, 0xfd, 0x52, 0xaa, 0x33, 0xaf, 0x71, 0x5e, 0xd4, 0xaf, 0x7b,
-	0x78, 0xdd, 0x81, 0x6b, 0x41, 0xae, 0xf9, 0x94, 0x48, 0xaf, 0xf9, 0xa3,
-	0xcf, 0x4b, 0xdd, 0xaf, 0x5b, 0x22, 0xb2, 0xac, 0x6c, 0x8c, 0xe3, 0xaf,
-	0x65, 0xbf, 0x36, 0xb4, 0x35, 0xfe, 0xec, 0xe6, 0xf8, 0x3b, 0xd9, 0x4f,
-	0x6f, 0x8e, 0x77, 0x87, 0x3d, 0x1e, 0xc6, 0xb5, 0x99, 0x66, 0xc1, 0x1f,
-	0xbb, 0x0c, 0xb9, 0xb7, 0x5a, 0x0b, 0xc8, 0x3d, 0x45, 0xeb, 0x32, 0xea,
-	0x24, 0xc6, 0x9f, 0xeb, 0x89, 0x37, 0xdb, 0x62, 0x8d, 0x91, 0x09, 0x51,
-	0x9f, 0x51, 0xf1, 0xd6, 0xe4, 0xfd, 0x4e, 0xc4, 0x9d, 0xcb, 0xf8, 0xce,
-	0x3c, 0x17, 0xc4, 0x3c, 0xce, 0xe1, 0xf3, 0x6f, 0x5f, 0x43, 0xe7, 0x31,
-	0xe8, 0xfc, 0xff, 0x1b, 0xdd, 0xe2, 0x4f, 0xe9, 0x56, 0xc5, 0x9d, 0x97,
-	0xb6, 0xd9, 0x2c, 0xe9, 0xef, 0xf6, 0x69, 0x96, 0x68, 0x38, 0x6d, 0x38,
-	0x0b, 0xd6, 0x8d, 0x12, 0x41, 0x0d, 0x4b, 0x9b, 0x2d, 0x35, 0xbf, 0x8b,
-	0xe7, 0x99, 0x27, 0x25, 0x1a, 0x49, 0xd3, 0x2e, 0xd6, 0x07, 0x32, 0xd6,
-	0x31, 0xa7, 0xe6, 0x1e, 0x73, 0xce, 0x2a, 0x3b, 0x59, 0xbf, 0xc9, 0xab,
-	0xcd, 0x7f, 0x74, 0x13, 0x6a, 0x73, 0x3c, 0xcf, 0x98, 0xcb, 0xf1, 0x46,
-	0x4f, 0xc6, 0x62, 0x0e, 0x5a, 0x72, 0x8a, 0xf8, 0x2c, 0xa8, 0xb9, 0xaf,
-	0x0e, 0x70, 0x6e, 0x67, 0x3a, 0x76, 0xd3, 0x8f, 0xf1, 0xbf, 0x23, 0xfd,
-	0xce, 0x4d, 0x17, 0x2c, 0xae, 0x3b, 0x75, 0xd3, 0x59, 0xb5, 0x46, 0x18,
-	0xf1, 0x8c, 0xf3, 0x2e, 0xdf, 0xc4, 0x67, 0x9f, 0x44, 0x1c, 0x3f, 0xe1,
-	0x42, 0x97, 0xee, 0x8b, 0x4e, 0x1e, 0x9f, 0x39, 0xd2, 0x54, 0xe1, 0x7d,
-	0xe3, 0xe6, 0x8c, 0x15, 0x56, 0xf9, 0xf6, 0x4b, 0x98, 0x73, 0x04, 0x73,
-	0x0e, 0xbb, 0x01, 0x3f, 0xea, 0xbe, 0x93, 0xc5, 0xfd, 0xc3, 0x65, 0xc3,
-	0x71, 0xca, 0xe6, 0x38, 0x6a, 0x8e, 0xf8, 0x71, 0xe4, 0xe3, 0x1c, 0x72,
-	0xa0, 0x2d, 0xe6, 0x70, 0x41, 0xd2, 0x5d, 0x93, 0xa8, 0xe5, 0x56, 0x90,
-	0x4f, 0x50, 0x87, 0xa4, 0xaa, 0x32, 0xd8, 0x95, 0x39, 0xad, 0xc3, 0x3e,
-	0xef, 0x80, 0xbd, 0x1a, 0x8e, 0x9e, 0x44, 0x5c, 0x47, 0xdc, 0x5c, 0xa8,
-	0x58, 0x5a, 0xb6, 0x3c, 0x68, 0x94, 0xe4, 0x56, 0x59, 0x37, 0xcc, 0xf8,
-	0xa4, 0xec, 0x92, 0x6c, 0x18, 0xf3, 0x86, 0x3f, 0x2e, 0xb9, 0xb8, 0x86,
-	0xd8, 0x70, 0x03, 0xe2, 0x16, 0xeb, 0xe4, 0xf6, 0x18, 0xfa, 0x0b, 0x11,
-	0xeb, 0x8b, 0x21, 0xc6, 0x9e, 0x4e, 0x8b, 0x75, 0x3f, 0xe7, 0xed, 0x92,
-	0x8d, 0x0f, 0xcc, 0x7b, 0xb7, 0x6d, 0x5e, 0xfb, 0xf8, 0x7b, 0x18, 0xdf,
-	0x25, 0x17, 0x41, 0x47, 0x38, 0x39, 0x26, 0x25, 0xf0, 0x10, 0x39, 0xd5,
-	0x6a, 0x5d, 0x00, 0x3f, 0x3a, 0xf8, 0x2f, 0x56, 0x59, 0x0b, 0x84, 0xa4,
-	0x6a, 0xe0, 0x9e, 0xdb, 0x6a, 0xd5, 0x10, 0x46, 0xf5, 0x55, 0xd2, 0x1c,
-	0x95, 0x49, 0x77, 0x48, 0xec, 0x06, 0xe5, 0x60, 0xc2, 0xeb, 0xfe, 0xac,
-	0x2b, 0x7b, 0x86, 0x39, 0x13, 0x16, 0xb1, 0xfa, 0xe7, 0x5d, 0x19, 0xe4,
-	0x3e, 0x7d, 0xf5, 0x62, 0x57, 0x16, 0x7a, 0x0f, 0xad, 0xfe, 0xe7, 0x2e,
-	0xe7, 0x34, 0xe9, 0x0a, 0x21, 0xf7, 0xdd, 0x22, 0x45, 0xa3, 0x25, 0xdf,
-	0x44, 0x8d, 0x50, 0x1c, 0x46, 0x2e, 0x83, 0x17, 0xe8, 0xa0, 0xbb, 0x60,
-	0x48, 0xb4, 0x3b, 0xfd, 0x7d, 0xd0, 0x37, 0x06, 0xd9, 0xec, 0xc2, 0x9c,
-	0x10, 0xc6, 0x87, 0xf0, 0xbf, 0x7d, 0xfc, 0x8d, 0x2e, 0xe4, 0x05, 0xc4,
-	0x60, 0x89, 0x66, 0xc6, 0x7a, 0xb0, 0xfe, 0xf7, 0x30, 0x8e, 0x09, 0xc9,
-	0xcd, 0xf1, 0x27, 0xbc, 0xf1, 0xb7, 0x41, 0x0b, 0x9f, 0x63, 0x8d, 0x22,
-	0xd1, 0xb9, 0x31, 0x03, 0x34, 0x70, 0x6e, 0x4c, 0xcd, 0x75, 0xce, 0xd0,
-	0x06, 0x0c, 0xa7, 0x66, 0xdd, 0x2c, 0xd9, 0xe5, 0x7e, 0x99, 0x5c, 0xee,
-	0x93, 0x03, 0xcb, 0xe6, 0x4c, 0x95, 0xd8, 0x0f, 0x3c, 0x0b, 0xea, 0x30,
-	0x7d, 0x55, 0x20, 0x01, 0x33, 0x7e, 0x44, 0x06, 0xe3, 0x5f, 0x92, 0x5f,
-	0xb6, 0x90, 0xef, 0x91, 0xeb, 0x7b, 0x24, 0xac, 0xd6, 0x89, 0x07, 0x7b,
-	0xd2, 0x46, 0xb7, 0xed, 0xeb, 0x9c, 0xb9, 0xd6, 0xba, 0x70, 0xfe, 0xd5,
-	0xf8, 0x55, 0xeb, 0xfe, 0x85, 0xbf, 0xae, 0x81, 0x75, 0x07, 0xb0, 0x26,
-	0x79, 0x34, 0xbb, 0x26, 0x4e, 0x8b, 0xdd, 0x09, 0xfa, 0x9c, 0xe4, 0x8d,
-	0xc0, 0x86, 0xfd, 0x72, 0x62, 0x99, 0xf1, 0x42, 0xfa, 0xf1, 0x19, 0x8d,
-	0x48, 0x72, 0xf8, 0x1c, 0xea, 0xae, 0x09, 0xb5, 0x86, 0x57, 0x93, 0xe9,
-	0xab, 0x29, 0xd4, 0xc4, 0x3f, 0x05, 0x3d, 0xac, 0x15, 0xc8, 0x73, 0x18,
-	0xfc, 0xa6, 0x50, 0x8b, 0x11, 0x47, 0xb5, 0x1e, 0xcf, 0xa4, 0xf0, 0xfd,
-	0x5c, 0xa2, 0x2b, 0x8b, 0x98, 0x08, 0xff, 0xbe, 0x39, 0xa4, 0x72, 0x18,
-	0xf5, 0x32, 0xda, 0x45, 0x3c, 0x83, 0xe7, 0xa1, 0x27, 0xca, 0x68, 0xbc,
-	0xcb, 0xa9, 0x50, 0x46, 0x02, 0x7a, 0x2c, 0xd8, 0x64, 0x58, 0x61, 0x29,
-	0x7d, 0xd5, 0xc6, 0xbc, 0xb7, 0x42, 0xac, 0x77, 0x33, 0x16, 0xbf, 0x23,
-	0xe6, 0xac, 0x4e, 0x61, 0x2e, 0xbf, 0xdf, 0x85, 0x75, 0x07, 0x87, 0x8b,
-	0xd2, 0x31, 0x7c, 0x18, 0xf1, 0x4e, 0x1f, 0x1b, 0x01, 0x6d, 0xb4, 0xf3,
-	0x16, 0xb0, 0xc0, 0x6f, 0x81, 0x1f, 0xf8, 0x46, 0xd2, 0x92, 0xf9, 0x25,
-	0xca, 0x55, 0x3e, 0x0e, 0x1e, 0xc0, 0x7f, 0x12, 0x71, 0x8d, 0x3c, 0x70,
-	0x6f, 0x41, 0x8e, 0xbe, 0x5b, 0xf2, 0x4b, 0x51, 0x55, 0xeb, 0xdb, 0x06,
-	0xf7, 0xd7, 0x34, 0x3d, 0xdd, 0x0d, 0x1d, 0x93, 0xb7, 0x1c, 0x68, 0x7b,
-	0x0c, 0x79, 0x80, 0xbc, 0x91, 0x2f, 0xfa, 0xca, 0x28, 0xfc, 0x84, 0xf4,
-	0xfb, 0xb6, 0xa7, 0xad, 0x23, 0xa6, 0xa8, 0x38, 0x98, 0xca, 0x20, 0xb0,
-	0xbd, 0xd4, 0x1c, 0x97, 0x3f, 0x6e, 0x8e, 0xc9, 0x77, 0x9b, 0x29, 0xe4,
-	0xc0, 0x51, 0xe4, 0xc0, 0x61, 0xe4, 0x40, 0x0b, 0x39, 0x30, 0x81, 0x1c,
-	0x38, 0x80, 0x1c, 0x18, 0x47, 0x9c, 0x14, 0x39, 0xa1, 0xf2, 0x6d, 0x2c,
-	0x0a, 0xcc, 0x1d, 0xb5, 0x9b, 0x0e, 0x78, 0x99, 0xc1, 0x5e, 0xb3, 0xe0,
-	0xeb, 0x50, 0xd7, 0x44, 0x65, 0x1c, 0x31, 0xd7, 0x42, 0x3c, 0x4a, 0x20,
-	0xdf, 0x8c, 0x01, 0x6b, 0x89, 0x6c, 0x2c, 0x25, 0x10, 0x13, 0x5b, 0xe2,
-	0x00, 0x13, 0x97, 0x8c, 0x14, 0x9e, 0xdd, 0xab, 0xec, 0x33, 0x94, 0xbe,
-	0x3b, 0x2c, 0xdd, 0xa3, 0x92, 0x2f, 0x9f, 0xc4, 0x58, 0x1c, 0xeb, 0x75,
-	0x21, 0x2f, 0x31, 0x2e, 0x30, 0x06, 0x2c, 0x39, 0xbf, 0x6b, 0xd1, 0xd7,
-	0xba, 0xb5, 0xcc, 0xe9, 0x82, 0x30, 0x96, 0x23, 0x0f, 0xc0, 0x1e, 0x38,
-	0x36, 0x89, 0xe7, 0xf8, 0xfd, 0x2f, 0xfd, 0x98, 0xf9, 0xb1, 0x4e, 0x81,
-	0xd1, 0xbe, 0xc4, 0x9c, 0x67, 0x61, 0x3d, 0xb7, 0xdd, 0x4f, 0x9f, 0x47,
-	0xad, 0x14, 0xdc, 0x27, 0xae, 0x66, 0x3f, 0xe1, 0x24, 0x68, 0x1e, 0x04,
-	0xbe, 0x47, 0x6d, 0x75, 0xb0, 0x8a, 0xef, 0xed, 0xf3, 0x5d, 0xcc, 0x57,
-	0x63, 0x51, 0x23, 0x6d, 0xb1, 0x9e, 0x43, 0xac, 0x3c, 0x86, 0xb8, 0x68,
-	0x3b, 0xfa, 0x5a, 0x03, 0x7c, 0x42, 0x8e, 0x65, 0xdb, 0x09, 0x0f, 0xbd,
-	0xd6, 0x7a, 0xd6, 0x1a, 0x96, 0x89, 0xb5, 0x31, 0xc9, 0xae, 0x0d, 0xc6,
-	0xcf, 0x4b, 0xd7, 0x65, 0x5b, 0x5e, 0x6b, 0x95, 0x5c, 0xf3, 0xa4, 0x0d,
-	0xbb, 0xdc, 0xb7, 0xdf, 0x90, 0x1a, 0x30, 0xdc, 0xbe, 0xfd, 0x9d, 0xac,
-	0xe9, 0x5f, 0x14, 0x3d, 0x21, 0x99, 0x45, 0x5b, 0xc6, 0xf6, 0x07, 0xb5,
-	0xe7, 0x2f, 0x3b, 0xa4, 0x1b, 0x63, 0x6b, 0x09, 0xcc, 0x61, 0xdd, 0xaf,
-	0xfa, 0x27, 0xe0, 0x59, 0xf3, 0x9e, 0x51, 0x39, 0x8f, 0x98, 0x19, 0xbc,
-	0x37, 0x6d, 0xe7, 0xfc, 0x22, 0x70, 0x0d, 0xe4, 0x99, 0x59, 0x24, 0xee,
-	0xda, 0x05, 0x39, 0x45, 0x60, 0x23, 0xd4, 0xfd, 0x20, 0x9e, 0x6d, 0xc9,
-	0x57, 0x53, 0xb4, 0x87, 0xc7, 0x20, 0x4b, 0xac, 0x15, 0x0e, 0xf8, 0xf9,
-	0x9a, 0xcc, 0x2d, 0x51, 0x7e, 0x71, 0xd4, 0x96, 0xdc, 0x5b, 0xa2, 0x5d,
-	0xe9, 0xab, 0xeb, 0x46, 0xdb, 0xd9, 0x58, 0xc4, 0xfa, 0x43, 0xc4, 0xd8,
-	0x88, 0xd5, 0x65, 0xf6, 0x06, 0x58, 0x53, 0x1d, 0x80, 0x4e, 0xa6, 0x15,
-	0xe6, 0xce, 0xd4, 0x53, 0x62, 0x9d, 0x62, 0xac, 0x92, 0x44, 0xc8, 0x22,
-	0xbe, 0x17, 0x43, 0x4f, 0xcf, 0xe2, 0x1e, 0xe5, 0xc9, 0x5a, 0x1f, 0xf7,
-	0x57, 0xff, 0xa3, 0xd2, 0x49, 0x08, 0xba, 0xcb, 0xef, 0x67, 0x11, 0x22,
-	0x4b, 0xa1, 0x34, 0x62, 0xe0, 0x18, 0x79, 0x50, 0x7b, 0xa3, 0x9e, 0xa4,
-	0xdf, 0x81, 0x67, 0xd8, 0x46, 0x5b, 0x5d, 0xa9, 0xfe, 0x4a, 0x95, 0x08,
-	0x6c, 0x59, 0x0a, 0x91, 0x34, 0x78, 0x1a, 0xc3, 0x77, 0x38, 0xff, 0x09,
-	0xe8, 0xf3, 0x2c, 0x9e, 0x5f, 0x00, 0x5f, 0x1b, 0x65, 0xd2, 0x9d, 0x4c,
-	0x1c, 0x57, 0xbe, 0x8b, 0x6b, 0x97, 0xb5, 0xcc, 0xd7, 0xe4, 0xbc, 0xe2,
-	0xef, 0x13, 0xac, 0x9d, 0xa1, 0xa7, 0xeb, 0xe1, 0x6f, 0xf2, 0x3a, 0xf9,
-	0xf3, 0xd6, 0x67, 0xce, 0xca, 0x58, 0x09, 0xc9, 0x96, 0x5f, 0x6a, 0x85,
-	0x2d, 0x2b, 0x3e, 0xef, 0xeb, 0x31, 0xeb, 0x46, 0x41, 0x07, 0xfb, 0x00,
-	0xfb, 0x95, 0x2e, 0x41, 0x07, 0x6d, 0xa7, 0x10, 0x4d, 0x3f, 0x2e, 0x2b,
-	0x4b, 0xff, 0x54, 0x6a, 0x4b, 0x05, 0xa9, 0x2f, 0xfd, 0x23, 0x39, 0xb7,
-	0xd4, 0x92, 0x0b, 0x29, 0x15, 0x93, 0xac, 0x0e, 0xe5, 0xcf, 0x72, 0xa3,
-	0x87, 0x07, 0x93, 0xe3, 0x97, 0x20, 0xc0, 0x95, 0xaa, 0x47, 0xfb, 0x54,
-	0x1b, 0xed, 0x17, 0x60, 0x6b, 0xaf, 0x58, 0xa4, 0x7f, 0x4c, 0x6a, 0x65,
-	0xd2, 0xfe, 0xa0, 0xa2, 0xfd, 0xc0, 0x26, 0xed, 0x92, 0x0b, 0x59, 0xa4,
-	0x7f, 0x27, 0xda, 0x81, 0xf3, 0xfb, 0x49, 0x7f, 0x02, 0xcf, 0x7e, 0xd0,
-	0xfe, 0x6a, 0xee, 0x6b, 0xad, 0x8d, 0x72, 0x44, 0xd1, 0x1c, 0x4a, 0x8f,
-	0x41, 0x3e, 0xaf, 0xb5, 0xd6, 0x5d, 0xfa, 0x11, 0xbe, 0xbb, 0xf7, 0x20,
-	0x46, 0xf5, 0x61, 0xaf, 0x5e, 0xc9, 0xcf, 0x46, 0x11, 0x27, 0xc7, 0xa1,
-	0xdb, 0x2e, 0xe5, 0x87, 0x08, 0x17, 0xd0, 0xd9, 0x34, 0xe6, 0x1f, 0xa2,
-	0xbf, 0x29, 0xb9, 0x38, 0x90, 0x4b, 0xb1, 0x9c, 0x8e, 0xa0, 0xfe, 0xc7,
-	0x3e, 0x86, 0x93, 0x73, 0xf9, 0xcc, 0x00, 0x62, 0x1a, 0xff, 0x7f, 0x64,
-	0x7b, 0x28, 0x20, 0xd6, 0x42, 0xe7, 0x3d, 0x90, 0x1f, 0xe8, 0x18, 0x9b,
-	0x41, 0x6e, 0x4d, 0x0e, 0xd7, 0x54, 0x7f, 0x91, 0x71, 0xe5, 0x28, 0xf2,
-	0xe9, 0x21, 0x7c, 0xbc, 0xfd, 0x26, 0x9a, 0xdc, 0x73, 0x3b, 0x4f, 0x45,
-	0x77, 0x7d, 0x2f, 0x01, 0x52, 0xa6, 0xc9, 0x7d, 0x0b, 0x12, 0x4a, 0x87,
-	0xb0, 0x2f, 0xc7, 0x7a, 0x10, 0x63, 0x06, 0xa2, 0xd9, 0xe6, 0xcf, 0x31,
-	0x4e, 0x5f, 0x66, 0x7c, 0x0f, 0x68, 0x1f, 0xc5, 0x9a, 0x8c, 0xbb, 0x63,
-	0xe0, 0x99, 0x35, 0x26, 0xe3, 0x26, 0xf2, 0x48, 0xe3, 0x47, 0xcc, 0x2d,
-	0xf8, 0x3e, 0xe0, 0x7f, 0xe7, 0x7d, 0x89, 0xde, 0x9c, 0x36, 0xab, 0x05,
-	0x31, 0xb1, 0x27, 0x74, 0x6e, 0xc5, 0xa5, 0xd8, 0x30, 0x5f, 0x20, 0x66,
-	0xd4, 0x29, 0x83, 0x35, 0xca, 0x89, 0xfd, 0x27, 0xd4, 0x7f, 0xb5, 0xe7,
-	0x21, 0x8f, 0xa8, 0xec, 0xb5, 0x0e, 0x22, 0xa6, 0x80, 0xfe, 0xca, 0x18,
-	0x78, 0x63, 0x8f, 0x66, 0x10, 0xf9, 0x2b, 0x04, 0x21, 0xa0, 0x96, 0x5a,
-	0x0b, 0xc9, 0xbd, 0xe1, 0x11, 0xa3, 0x28, 0x8f, 0x46, 0x58, 0x36, 0x17,
-	0xd6, 0x98, 0x07, 0xc2, 0xb2, 0xb0, 0x26, 0x72, 0x69, 0x91, 0x71, 0x45,
-	0xfd, 0x41, 0xe6, 0x86, 0x33, 0x8f, 0x3c, 0x5b, 0x5a, 0x62, 0x8c, 0x61,
-	0x9c, 0xb8, 0x01, 0xba, 0x48, 0x7e, 0xe3, 0xab, 0xc8, 0x49, 0xa5, 0xf2,
-	0x20, 0x62, 0xa6, 0xac, 0xeb, 0x90, 0x29, 0x72, 0x19, 0x6b, 0xd4, 0x1d,
-	0xfa, 0x32, 0x41, 0x4f, 0x26, 0x2a, 0xc5, 0x45, 0xf6, 0x63, 0xa2, 0xa0,
-	0x85, 0x35, 0x76, 0x48, 0xd5, 0x3f, 0x37, 0xa8, 0xd8, 0xca, 0xff, 0xe1,
-	0xb6, 0x7d, 0x93, 0x27, 0xf7, 0xe9, 0x8c, 0x63, 0x37, 0x8b, 0x3d, 0x63,
-	0x77, 0x1d, 0xa8, 0x74, 0x48, 0xb5, 0x8f, 0x76, 0x49, 0xfd, 0xbf, 0xa0,
-	0x62, 0xed, 0x02, 0x78, 0x2a, 0x2e, 0x12, 0xe3, 0x86, 0x31, 0x2f, 0xe6,
-	0xcf, 0xa3, 0x5c, 0xff, 0x89, 0xcc, 0xed, 0x7f, 0x17, 0x74, 0x79, 0x71,
-	0x2d, 0xbf, 0x1f, 0xf1, 0x76, 0x46, 0x97, 0x3b, 0xef, 0x1a, 0xc7, 0xb3,
-	0xcc, 0x81, 0xef, 0xf8, 0x78, 0x92, 0x63, 0xec, 0x61, 0x81, 0xbe, 0x15,
-	0x03, 0xff, 0xfb, 0xa4, 0xb0, 0x12, 0x85, 0x1c, 0x90, 0x4b, 0x6b, 0xde,
-	0x5a, 0xac, 0x77, 0x4f, 0x42, 0x47, 0xfa, 0xa9, 0xa8, 0x44, 0x4e, 0xf5,
-	0x49, 0xf8, 0xeb, 0xdd, 0xd2, 0xf1, 0xf5, 0x21, 0x09, 0x7d, 0xdd, 0x64,
-	0x4e, 0x4f, 0x9c, 0x80, 0xbe, 0xe6, 0x65, 0x5c, 0x9e, 0x44, 0xde, 0x62,
-	0x5e, 0x57, 0x76, 0x6a, 0xf4, 0x4b, 0x08, 0x05, 0xab, 0xfe, 0x8c, 0x2d,
-	0x8f, 0xee, 0xff, 0x85, 0xea, 0x33, 0x01, 0xc3, 0x8b, 0xfe, 0xfc, 0x94,
-	0xd8, 0xcd, 0x77, 0x21, 0x6b, 0xc3, 0x79, 0xed, 0xd6, 0xa0, 0xa6, 0x1c,
-	0x56, 0xfd, 0xc2, 0x47, 0xf7, 0x7b, 0x35, 0x25, 0xf0, 0xb8, 0xe6, 0xa8,
-	0x9a, 0x12, 0xf1, 0x35, 0xcc, 0x79, 0xfd, 0xa2, 0x63, 0xaf, 0xbc, 0x0c,
-	0x42, 0x4f, 0xb7, 0x88, 0x7d, 0x08, 0x7e, 0xf1, 0x9c, 0x2c, 0xe9, 0x69,
-	0x4d, 0xad, 0x19, 0x7a, 0x86, 0x71, 0x8a, 0xf1, 0x8b, 0x36, 0x9e, 0x4c,
-	0x14, 0x61, 0x7f, 0xa1, 0xe7, 0x19, 0xa3, 0x3c, 0xdb, 0x9e, 0x68, 0x8b,
-	0x75, 0x0b, 0x95, 0x7b, 0xa0, 0x43, 0xd4, 0xf2, 0x16, 0xe2, 0x9c, 0x81,
-	0x5c, 0x6e, 0xf1, 0xda, 0xeb, 0xe1, 0xe5, 0x63, 0x31, 0x75, 0x5d, 0xac,
-	0x7a, 0x18, 0xdc, 0x5b, 0x9f, 0x75, 0x07, 0x62, 0x4c, 0x93, 0x74, 0x70,
-	0xdf, 0x01, 0x09, 0x3d, 0x17, 0x93, 0xf0, 0x73, 0xb4, 0x3f, 0x33, 0xe1,
-	0x40, 0x7e, 0x0b, 0x16, 0x31, 0xd0, 0x0a, 0xb0, 0xc5, 0xcd, 0xa2, 0xaf,
-	0x0c, 0xc0, 0x77, 0xcc, 0x78, 0x55, 0x92, 0x12, 0xaa, 0x45, 0xe5, 0xad,
-	0x45, 0x33, 0x41, 0x7b, 0x39, 0x6b, 0x61, 0xbc, 0xd9, 0x75, 0x79, 0x5d,
-	0x51, 0xc1, 0xb1, 0x2f, 0x87, 0x80, 0x19, 0x86, 0x6d, 0xbd, 0x47, 0x5e,
-	0x87, 0xbe, 0x73, 0x6a, 0xec, 0x66, 0xac, 0x0b, 0x1a, 0x9e, 0x33, 0xc1,
-	0x03, 0xd7, 0xfd, 0x1e, 0xd6, 0x54, 0xf8, 0xca, 0xd9, 0x60, 0x4d, 0xba,
-	0x48, 0xdb, 0xed, 0x83, 0xdd, 0xe1, 0xba, 0xd9, 0x21, 0xb9, 0xd9, 0x84,
-	0xe8, 0x8b, 0x9f, 0x91, 0xc1, 0xfd, 0xba, 0xc7, 0x8f, 0xe2, 0x91, 0x63,
-	0xec, 0xc7, 0xdd, 0xae, 0xfc, 0x51, 0x5f, 0x83, 0xcd, 0x3c, 0x48, 0x1d,
-	0x23, 0xf7, 0x23, 0x8f, 0x31, 0x8e, 0x85, 0x90, 0xc7, 0xb2, 0x4d, 0x4f,
-	0xef, 0xd5, 0x07, 0xfb, 0xe5, 0xc9, 0xe7, 0x68, 0x4f, 0xb8, 0xb7, 0x69,
-	0x53, 0x41, 0x0f, 0x98, 0xf7, 0x2c, 0x39, 0xf9, 0x6c, 0x50, 0x73, 0xb0,
-	0xbe, 0x32, 0xe3, 0x07, 0xc0, 0x8f, 0x7e, 0x27, 0xe3, 0x81, 0xae, 0x6c,
-	0x37, 0x6f, 0x59, 0x5e, 0xdd, 0x51, 0x49, 0xb0, 0x2f, 0x6e, 0xb0, 0x4e,
-	0xb3, 0xe3, 0x9e, 0xbc, 0x8b, 0x18, 0x2b, 0x35, 0x67, 0x11, 0xa3, 0x23,
-	0x72, 0x71, 0xd6, 0x86, 0xee, 0x3f, 0x0b, 0xba, 0x0e, 0x75, 0x11, 0x23,
-	0x5f, 0x9c, 0x75, 0x70, 0x7d, 0x48, 0xd5, 0x66, 0xa1, 0x3b, 0x61, 0xc7,
-	0xcd, 0x7e, 0xfa, 0x91, 0xaf, 0xa7, 0x84, 0x56, 0x5c, 0x32, 0xb5, 0x12,
-	0x62, 0xf6, 0x64, 0x8a, 0x39, 0xbe, 0x53, 0xf5, 0x4d, 0xd9, 0xaf, 0xc9,
-	0x2b, 0xbc, 0xb0, 0x4f, 0x2b, 0x56, 0x19, 0xe7, 0x0b, 0xf1, 0x0e, 0x21,
-	0x0e, 0x11, 0xad, 0x66, 0x51, 0x27, 0x9a, 0x9c, 0x57, 0xbd, 0x58, 0x11,
-	0xc7, 0x3d, 0x42, 0x19, 0x68, 0xf5, 0xea, 0x3e, 0xad, 0x50, 0x0d, 0xc9,
-	0xc5, 0x18, 0xe9, 0x4e, 0xa8, 0xfa, 0x7d, 0xbf, 0xb2, 0xb5, 0x1e, 0xe4,
-	0x12, 0xd8, 0x4c, 0xea, 0x93, 0xd8, 0x57, 0x8d, 0xc1, 0xa6, 0xa8, 0x7b,
-	0xea, 0x5d, 0xc5, 0x48, 0x5f, 0xf7, 0x3b, 0xe5, 0x4c, 0xd0, 0x51, 0x26,
-	0x7e, 0xef, 0xf4, 0xf1, 0xfb, 0xa2, 0x5f, 0x0f, 0x3d, 0x26, 0xac, 0x53,
-	0x16, 0x2a, 0xa4, 0x05, 0xf1, 0xd6, 0xdd, 0xc9, 0x96, 0x28, 0x47, 0x2f,
-	0xa6, 0x1c, 0x45, 0x1d, 0xa3, 0xaf, 0x19, 0xbe, 0x0d, 0xf0, 0x6f, 0x14,
-	0xf7, 0xbc, 0x5a, 0xaa, 0xd8, 0x8c, 0xc0, 0xdf, 0xa7, 0x21, 0x23, 0xea,
-	0x06, 0xfa, 0x5b, 0xe3, 0x99, 0x0a, 0xf4, 0xb7, 0xf6, 0xf2, 0xfb, 0x76,
-	0x1f, 0x63, 0xde, 0xb0, 0x3c, 0x89, 0xf1, 0x13, 0x67, 0x48, 0xcf, 0xb8,
-	0x8f, 0xc7, 0x12, 0x90, 0x09, 0x63, 0xfc, 0xa8, 0xbc, 0xd5, 0x70, 0x14,
-	0xfe, 0xdb, 0xb7, 0x7f, 0x46, 0xe6, 0xdd, 0x59, 0xe0, 0x3f, 0xc8, 0xdf,
-	0x48, 0xc0, 0x3f, 0xe3, 0x2a, 0x3e, 0x1e, 0xfe, 0x68, 0x35, 0x49, 0xd8,
-	0xcb, 0xd9, 0xf7, 0x5e, 0x67, 0xce, 0xde, 0x0d, 0xfc, 0xf5, 0x91, 0xd6,
-	0x0f, 0x79, 0xeb, 0xff, 0x17, 0xe8, 0xea, 0x73, 0xd8, 0x23, 0x0a, 0xfa,
-	0xfa, 0x29, 0xd3, 0x0f, 0x7b, 0x4e, 0xf7, 0x9e, 0xbb, 0xff, 0x3a, 0xe9,
-	0x32, 0xa4, 0x01, 0x8c, 0x50, 0x50, 0x79, 0x94, 0xb5, 0x62, 0xc4, 0xd7,
-	0xdf, 0x31, 0x60, 0x67, 0xae, 0x1b, 0xc4, 0xde, 0x4e, 0x29, 0xf4, 0x05,
-	0xf5, 0x27, 0x62, 0xf6, 0xe6, 0x78, 0x50, 0xcf, 0xf2, 0xf9, 0x94, 0x93,
-	0x2f, 0xb3, 0x4f, 0xc8, 0x5c, 0xc0, 0x31, 0x65, 0x87, 0x1f, 0x42, 0xb7,
-	0x09, 0xcf, 0x20, 0xdd, 0xf7, 0x29, 0xba, 0x1d, 0x45, 0x37, 0xfd, 0x8b,
-	0x67, 0x3a, 0xec, 0xa3, 0x05, 0x7d, 0x33, 0xae, 0x07, 0x4c, 0x00, 0x7d,
-	0x7f, 0x17, 0x3a, 0xfe, 0x4e, 0x05, 0x98, 0xa0, 0x02, 0x4c, 0x80, 0x3d,
-	0xbe, 0x0d, 0x1d, 0x7f, 0xab, 0x02, 0x4c, 0x50, 0x89, 0xfb, 0x3d, 0x0a,
-	0x9b, 0x98, 0xfe, 0x23, 0xda, 0x6e, 0xd0, 0x93, 0xb9, 0xda, 0x2e, 0x39,
-	0xce, 0xf9, 0x01, 0x36, 0x8e, 0xc2, 0x8e, 0x78, 0x6e, 0x11, 0xf4, 0x3b,
-	0xfc, 0x1c, 0xd1, 0xe0, 0xb9, 0x00, 0x72, 0x44, 0x83, 0xe7, 0x18, 0x23,
-	0xf1, 0x10, 0x30, 0x61, 0x48, 0xe2, 0xc2, 0x5e, 0xef, 0xdc, 0x18, 0xd6,
-	0x1a, 0x1d, 0x84, 0x27, 0x75, 0xa8, 0xbe, 0xd6, 0x71, 0xd5, 0x6f, 0x40,
-	0x5c, 0xa8, 0x06, 0xb5, 0x5b, 0x52, 0x26, 0x96, 0x88, 0x33, 0x65, 0xaf,
-	0x9e, 0x86, 0x0e, 0x5c, 0x62, 0xc3, 0xcd, 0xbe, 0xf4, 0x70, 0x1d, 0x7b,
-	0x16, 0x2d, 0x8f, 0xbe, 0xe3, 0xee, 0xd6, 0x33, 0x07, 0x10, 0x9f, 0xa7,
-	0xca, 0x09, 0x99, 0x2c, 0x7b, 0x98, 0x00, 0xf5, 0xcf, 0x55, 0xfd, 0x51,
-	0x9b, 0x7a, 0x80, 0xfe, 0x36, 0x6d, 0x23, 0x71, 0x3e, 0x45, 0x19, 0x53,
-	0xff, 0xd3, 0xaa, 0x67, 0x7d, 0xa0, 0xee, 0xf5, 0xe5, 0x27, 0x95, 0x2d,
-	0x84, 0x19, 0x67, 0xa8, 0x3f, 0xcf, 0x87, 0x61, 0x17, 0x79, 0x37, 0x90,
-	0x4b, 0x3b, 0x1e, 0xf9, 0xbc, 0x26, 0xd6, 0x4e, 0xe3, 0xb9, 0xb6, 0xf1,
-	0xcd, 0xfb, 0x3e, 0xbd, 0x88, 0x7d, 0x9b, 0x3d, 0x06, 0xc6, 0xa9, 0xad,
-	0xf1, 0x10, 0xea, 0x87, 0xb0, 0xba, 0x8f, 0x18, 0xde, 0x88, 0x49, 0xb6,
-	0x61, 0x89, 0x53, 0xe5, 0x3c, 0xf6, 0x2d, 0x18, 0x8f, 0x9e, 0x90, 0xec,
-	0x52, 0xaf, 0xe4, 0x62, 0x66, 0xca, 0x96, 0xbf, 0x27, 0x1b, 0xcb, 0x85,
-	0x04, 0xcf, 0x0d, 0x0b, 0x33, 0x1a, 0x9e, 0x7b, 0x18, 0xd7, 0xa4, 0xd9,
-	0x92, 0xc3, 0x65, 0xe6, 0x9d, 0x91, 0x78, 0x03, 0xf7, 0x72, 0xb3, 0xec,
-	0xd5, 0x54, 0x61, 0x93, 0x66, 0xa2, 0x8a, 0x78, 0xf0, 0x72, 0x99, 0xfb,
-	0x01, 0x1b, 0x95, 0xd9, 0xcf, 0x09, 0xee, 0x3f, 0x01, 0x1c, 0x88, 0x58,
-	0x1d, 0xf3, 0xe7, 0x28, 0x5e, 0x6d, 0x23, 0x2c, 0x81, 0xae, 0x3b, 0x65,
-	0xdd, 0x8f, 0xbb, 0xb5, 0xb2, 0xd7, 0x47, 0x39, 0x4b, 0x7a, 0xdc, 0xff,
-	0xd5, 0x5a, 0x8f, 0xa1, 0x16, 0xda, 0xe4, 0xf5, 0x8f, 0xb9, 0x8f, 0x81,
-	0xb0, 0x2b, 0x27, 0xdc, 0x40, 0x26, 0xbc, 0xcf, 0x31, 0x9e, 0x8d, 0xb6,
-	0x5a, 0x67, 0xad, 0xf6, 0x9e, 0xdf, 0xf5, 0xf4, 0xcc, 0xde, 0xb8, 0x2d,
-	0x63, 0xbd, 0xe6, 0xa0, 0x26, 0xf6, 0x7b, 0x66, 0x87, 0x46, 0xbc, 0x9e,
-	0xd9, 0xfc, 0xc8, 0xf6, 0x9e, 0xd9, 0xcf, 0x6f, 0xf3, 0x7a, 0x66, 0x17,
-	0x9d, 0x22, 0x3e, 0x5e, 0xcf, 0x6c, 0xf8, 0x76, 0xaf, 0x67, 0xf6, 0xf0,
-	0xed, 0x5e, 0xcf, 0xec, 0x91, 0x11, 0xaf, 0x67, 0xf6, 0xfb, 0xb7, 0x6f,
-	0xef, 0x99, 0x3d, 0x36, 0xb2, 0xbd, 0x67, 0x26, 0x13, 0xc8, 0x77, 0x13,
-	0x5b, 0x3d, 0xb3, 0xf2, 0xc8, 0xb5, 0x7b, 0x66, 0xaf, 0x06, 0x78, 0x1d,
-	0xfc, 0x8c, 0x81, 0x87, 0x14, 0xf0, 0xfa, 0x28, 0xf0, 0xfa, 0xaf, 0xeb,
-	0x59, 0x87, 0xc1, 0xe7, 0xcd, 0x7e, 0x5e, 0xb8, 0x1e, 0xdc, 0x7e, 0xbb,
-	0xff, 0x8c, 0xa0, 0xde, 0x4d, 0xf8, 0xb5, 0x0a, 0xb1, 0xfb, 0x1e, 0xbf,
-	0x66, 0xfb, 0x6b, 0xd1, 0xad, 0xf3, 0xec, 0xf6, 0xff, 0x37, 0xa0, 0xf4,
-	0x0e, 0xf0, 0x3c, 0xf9, 0x79, 0x0d, 0xb5, 0x1f, 0xf9, 0x47, 0xa2, 0xef,
-	0xbe, 0xe8, 0x7c, 0xd5, 0x22, 0xc6, 0x7f, 0x1c, 0xbe, 0x6a, 0xef, 0x0d,
-	0xc9, 0x3a, 0xfc, 0x96, 0x39, 0xea, 0xa4, 0x64, 0x31, 0x3f, 0xab, 0xe6,
-	0x27, 0x26, 0xb6, 0xe6, 0xa7, 0x26, 0xbe, 0xaa, 0x6a, 0x52, 0xf3, 0x5f,
-	0xe3, 0xf3, 0x0d, 0x65, 0xdf, 0x96, 0x87, 0xe1, 0x9d, 0x4a, 0x80, 0xb7,
-	0xc2, 0x3e, 0x76, 0x36, 0x1c, 0xdb, 0x9d, 0xc0, 0x33, 0xe6, 0x8b, 0xb6,
-	0x34, 0x14, 0x7e, 0x0f, 0xa5, 0xcd, 0x17, 0x73, 0xaa, 0x5e, 0x33, 0x9c,
-	0xbc, 0x1b, 0xd4, 0xdf, 0xa8, 0xa1, 0x86, 0x06, 0xd5, 0xf9, 0x9b, 0xbe,
-	0x36, 0x8c, 0x3c, 0xd6, 0x5e, 0x63, 0xb3, 0xae, 0xd6, 0xfd, 0xba, 0xda,
-	0x90, 0xbb, 0xf7, 0xb7, 0x63, 0x73, 0x99, 0xf8, 0x5b, 0x0a, 0x9b, 0xef,
-	0x42, 0x6d, 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7e,
-	0x01, 0xeb, 0x19, 0xe6, 0x46, 0xd6, 0x37, 0x31, 0x7c, 0xf8, 0xbe, 0x41,
-	0x80, 0xd1, 0x3b, 0xfc, 0xf8, 0xce, 0xba, 0x28, 0xc0, 0x2a, 0x77, 0x75,
-	0x7b, 0xb5, 0xd1, 0x2e, 0xcd, 0xab, 0x3f, 0x13, 0xfe, 0x9c, 0xf0, 0x26,
-	0x16, 0x0e, 0x6f, 0x62, 0xe1, 0x6d, 0xe7, 0x30, 0xa2, 0xde, 0x6d, 0x50,
-	0xe7, 0x39, 0x3c, 0xdf, 0x11, 0x4d, 0x4f, 0xf3, 0x8c, 0x07, 0x38, 0xc7,
-	0xe2, 0x99, 0x0f, 0x7d, 0xe9, 0x41, 0x2d, 0x5b, 0x37, 0x10, 0xef, 0x99,
-	0x7f, 0x90, 0x6b, 0xcb, 0xc1, 0xd9, 0x62, 0xa0, 0x27, 0xca, 0x8e, 0x63,
-	0x7f, 0xaa, 0xa1, 0xe6, 0x4d, 0x45, 0xac, 0x43, 0xa0, 0x65, 0x0a, 0xff,
-	0x03, 0x99, 0xde, 0xa3, 0x72, 0x5f, 0x27, 0x6c, 0xf6, 0x78, 0x85, 0xd8,
-	0xf5, 0x71, 0x69, 0xf8, 0xf8, 0x75, 0x65, 0xc9, 0xc3, 0xae, 0xe1, 0xed,
-	0xd8, 0x35, 0xb5, 0x21, 0x1e, 0x8d, 0x07, 0x76, 0xa4, 0xd1, 0x70, 0x5e,
-	0x19, 0x22, 0x66, 0x25, 0x9d, 0xcc, 0x3d, 0xd3, 0x88, 0x81, 0xcc, 0x39,
-	0xcc, 0x37, 0xc4, 0xa5, 0xd7, 0xa2, 0x4f, 0x8d, 0x1d, 0xed, 0xb0, 0xa2,
-	0xf8, 0xcc, 0x83, 0x8e, 0x19, 0x3c, 0x93, 0x96, 0x85, 0xd3, 0x5f, 0xd1,
-	0x9c, 0xfa, 0x3c, 0xe8, 0x99, 0x42, 0xae, 0xa3, 0x2d, 0x15, 0x0c, 0xcf,
-	0x8e, 0xd6, 0x11, 0xf7, 0x5d, 0xc6, 0x02, 0xd4, 0xae, 0xa8, 0x47, 0xca,
-	0x8c, 0xbd, 0x3c, 0xeb, 0x0a, 0x62, 0x2e, 0xfb, 0x26, 0xa8, 0x59, 0x59,
-	0xbb, 0x2e, 0x72, 0xdf, 0xed, 0xba, 0xa8, 0xb9, 0xc4, 0x5d, 0x86, 0xb3,
-	0xbe, 0x46, 0xdc, 0xf8, 0x51, 0x31, 0xa4, 0xe1, 0xbc, 0x3c, 0x44, 0x1c,
-	0x79, 0x3d, 0xf8, 0xd1, 0x84, 0x34, 0xcd, 0x17, 0xd6, 0xf5, 0x76, 0xfc,
-	0xe8, 0x61, 0xc7, 0xcc, 0xda, 0x41, 0xac, 0xc9, 0xda, 0x8c, 0x38, 0xd1,
-	0x44, 0x98, 0x1b, 0xc4, 0xb3, 0x83, 0xe0, 0xc7, 0xc3, 0x8a, 0x59, 0x60,
-	0xc5, 0xbf, 0x03, 0xac, 0x58, 0x92, 0xf7, 0xa2, 0xc4, 0x8a, 0xb6, 0x8f,
-	0x15, 0x1d, 0xd8, 0x71, 0x7e, 0x9b, 0x1d, 0x6b, 0xaa, 0x07, 0xc5, 0x7b,
-	0x79, 0x60, 0xbd, 0xec, 0xa2, 0x79, 0x1d, 0xf8, 0x50, 0x93, 0x98, 0x3a,
-	0xaf, 0x0f, 0xb7, 0xad, 0x19, 0xe0, 0xc0, 0x7d, 0x0a, 0xdf, 0xdd, 0x57,
-	0xd9, 0x85, 0xda, 0x44, 0xe1, 0x3d, 0xff, 0x9c, 0x2f, 0x7c, 0xd5, 0xd9,
-	0x67, 0xb8, 0xed, 0xec, 0x73, 0x0b, 0x17, 0xe2, 0x39, 0xbf, 0xc7, 0x17,
-	0x81, 0xde, 0xfe, 0x07, 0x69, 0x82, 0x5f, 0xd1, 0x07, 0x34, 0xcf, 0x4f,
-	0xb6, 0xe1, 0xc3, 0xff, 0x7a, 0x15, 0x3e, 0x44, 0xce, 0x5a, 0x89, 0x49,
-	0x06, 0xd8, 0xd0, 0x5e, 0xe3, 0x5a, 0xf4, 0xe5, 0x51, 0xe9, 0x00, 0x7f,
-	0x9d, 0x8b, 0x7d, 0xc0, 0x44, 0xdd, 0x12, 0x05, 0x36, 0x8a, 0x28, 0x6c,
-	0x34, 0x44, 0x0c, 0x33, 0x7c, 0x18, 0x98, 0xa6, 0xb1, 0x89, 0x8f, 0xcc,
-	0xd4, 0x0f, 0xa0, 0x97, 0x87, 0x95, 0xad, 0x8c, 0xcb, 0x53, 0x88, 0x9d,
-	0x1d, 0x6b, 0xc0, 0x75, 0x2b, 0x1e, 0x6e, 0x8a, 0x5c, 0x85, 0x9b, 0x8e,
-	0xec, 0x88, 0x9b, 0x54, 0xbf, 0x7e, 0x9c, 0x32, 0x79, 0xdd, 0xf5, 0xfa,
-	0xf5, 0x97, 0x5c, 0xaf, 0x5f, 0xff, 0xba, 0xdb, 0xde, 0xaf, 0xbf, 0x49,
-	0x8a, 0x86, 0x69, 0x5f, 0x94, 0xab, 0xfa, 0xf5, 0x33, 0xec, 0x7f, 0x57,
-	0xbb, 0xbc, 0xbe, 0x7c, 0xb7, 0xdf, 0xaf, 0x37, 0xa5, 0xb8, 0x6d, 0xdc,
-	0x90, 0xb7, 0xad, 0xa0, 0x5f, 0xff, 0x2f, 0x30, 0xd6, 0x83, 0x3d, 0xb6,
-	0xf7, 0xea, 0x2f, 0xb9, 0xec, 0xd5, 0xc7, 0x38, 0xcf, 0xef, 0xd5, 0x73,
-	0x1e, 0x6a, 0x78, 0x97, 0x7d, 0xfa, 0x9b, 0x21, 0x8b, 0x7e, 0xc8, 0xa1,
-	0x4f, 0x3a, 0x9e, 0x8b, 0x73, 0x8e, 0xea, 0xcf, 0x5f, 0x74, 0x63, 0x78,
-	0xce, 0xeb, 0xa3, 0x1f, 0x86, 0x5d, 0x1d, 0xd9, 0xec, 0xcf, 0x7b, 0x7b,
-	0xbc, 0xe1, 0x6e, 0x5f, 0x7f, 0xfb, 0x3a, 0x03, 0xfe, 0x3a, 0x31, 0xac,
-	0x13, 0xbf, 0x6a, 0x9d, 0xad, 0x7e, 0xfc, 0x1b, 0xae, 0xd7, 0x8b, 0x77,
-	0x4e, 0x8b, 0xdd, 0x81, 0x98, 0xfc, 0xe2, 0xd0, 0x8d, 0xfe, 0x1a, 0x9b,
-	0xbd, 0x78, 0xc6, 0x0e, 0xe0, 0x75, 0xc6, 0x0f, 0x3e, 0xff, 0xff, 0xbe,
-	0x17, 0xcf, 0x3e, 0xbc, 0x77, 0x9e, 0x42, 0xff, 0x04, 0x2e, 0x7f, 0xd6,
-	0xeb, 0xc1, 0x4f, 0x54, 0x82, 0xde, 0x3a, 0xeb, 0xc6, 0xe0, 0xbd, 0x8c,
-	0xc1, 0xc4, 0x71, 0xa1, 0xad, 0x90, 0x3e, 0xae, 0xdb, 0x23, 0x73, 0x0a,
-	0x17, 0xc1, 0xa6, 0x92, 0xd7, 0xc6, 0xc6, 0xb5, 0xc5, 0x00, 0x1b, 0xc7,
-	0x14, 0x36, 0xae, 0xad, 0x05, 0xd8, 0x38, 0x73, 0x0d, 0x6c, 0xfc, 0xdf,
-	0xba, 0xbc, 0xf8, 0x1f, 0x95, 0x82, 0xc2, 0xc6, 0xd7, 0x7a, 0xc7, 0x86,
-	0xf7, 0xba, 0x89, 0x03, 0xc4, 0x3b, 0x17, 0xef, 0xbb, 0x86, 0xaf, 0x05,
-	0x78, 0x99, 0xb9, 0xbe, 0x5f, 0x66, 0x9e, 0xdb, 0xc2, 0xcb, 0x1e, 0x26,
-	0x36, 0x13, 0x47, 0x55, 0x2e, 0x04, 0x3e, 0x68, 0xb2, 0xef, 0x7d, 0x48,
-	0xd9, 0x6e, 0xa9, 0x32, 0xab, 0x70, 0x59, 0x1e, 0xb5, 0x6d, 0x51, 0xe1,
-	0x60, 0x62, 0xe0, 0x2e, 0x91, 0xbe, 0x20, 0x17, 0x05, 0x18, 0x33, 0xec,
-	0xc7, 0x67, 0x9e, 0x29, 0xbc, 0x1d, 0xca, 0x10, 0x03, 0xbb, 0x41, 0x8d,
-	0x40, 0x39, 0x0f, 0x23, 0x76, 0x19, 0xbe, 0xac, 0x3c, 0x9f, 0xdd, 0xb7,
-	0xff, 0x87, 0xef, 0xdb, 0x06, 0xe3, 0x5a, 0x80, 0x11, 0x51, 0x03, 0x55,
-	0xc6, 0xd5, 0xbb, 0x0e, 0x1e, 0x46, 0xf4, 0xf0, 0x61, 0xd6, 0x9d, 0x01,
-	0x4e, 0x9e, 0x95, 0x09, 0xe0, 0xf3, 0xf5, 0xdf, 0x65, 0xef, 0x29, 0xc0,
-	0x44, 0x36, 0xfe, 0xb7, 0xf7, 0xa2, 0x78, 0xdd, 0xa1, 0xce, 0xfe, 0xce,
-	0x0f, 0x45, 0xdb, 0xc6, 0xff, 0x3e, 0xe2, 0x37, 0xea, 0xa1, 0x0a, 0x73,
-	0x1d, 0xb1, 0xd0, 0x6f, 0x40, 0x07, 0x63, 0xd7, 0xc0, 0x42, 0x57, 0xe7,
-	0x26, 0xe6, 0xcb, 0xad, 0xbc, 0xe4, 0x6c, 0xe6, 0x25, 0xee, 0xf1, 0xeb,
-	0x72, 0x27, 0xc7, 0x6c, 0x23, 0x62, 0x4d, 0xe1, 0x33, 0x8f, 0x7c, 0xbd,
-	0x3d, 0x37, 0xcd, 0x5d, 0x47, 0x6e, 0x9a, 0x50, 0xb9, 0x89, 0xf4, 0xa2,
-	0x9e, 0x83, 0x4c, 0xbe, 0x0b, 0x59, 0x7e, 0x07, 0xb4, 0xff, 0x11, 0xf8,
-	0xf9, 0x43, 0x60, 0xac, 0x6f, 0x03, 0x63, 0x7d, 0xab, 0xd2, 0xfe, 0x0e,
-	0xc3, 0xb8, 0xb0, 0x0e, 0xf4, 0xea, 0x66, 0x0f, 0xc3, 0x1f, 0x86, 0x57,
-	0x35, 0xca, 0x86, 0x33, 0x57, 0x1e, 0x31, 0xe6, 0xbd, 0xf3, 0xd2, 0x44,
-	0x4e, 0xd2, 0x88, 0x11, 0xcc, 0x15, 0xea, 0x3a, 0xce, 0x7e, 0x25, 0xb1,
-	0x42, 0x5d, 0xd5, 0x93, 0x43, 0x52, 0x6d, 0x78, 0xf8, 0x6a, 0xe1, 0x8c,
-	0xb7, 0xc6, 0x9c, 0x8f, 0xaf, 0xf2, 0x3e, 0xbe, 0xca, 0x35, 0x36, 0x12,
-	0xac, 0xcf, 0x17, 0x52, 0xdb, 0x31, 0xd5, 0x61, 0x1f, 0x53, 0xcd, 0xff,
-	0x15, 0x31, 0x15, 0xf7, 0xca, 0xe3, 0x99, 0xc9, 0xa5, 0x84, 0x1c, 0x80,
-	0x7c, 0x27, 0xca, 0xd4, 0x93, 0x69, 0xc3, 0x6e, 0x3e, 0x44, 0x57, 0x8e,
-	0xd2, 0x4b, 0x28, 0xe9, 0xe9, 0x69, 0x12, 0x7a, 0x9a, 0xf8, 0xb5, 0xf5,
-	0x8d, 0x1a, 0x33, 0xde, 0x1c, 0x8b, 0xe2, 0xf3, 0x7f, 0xaa, 0x23, 0xd2,
-	0x4f, 0x3d, 0x5d, 0x8d, 0xb9, 0xae, 0x07, 0x7b, 0x6d, 0xc7, 0x5d, 0xb6,
-	0xc2, 0x5d, 0x1d, 0xfe, 0x9c, 0x99, 0x89, 0x49, 0xe8, 0xf0, 0xdf, 0x63,
-	0xce, 0x9f, 0xc0, 0xb7, 0x7e, 0x88, 0x78, 0xfd, 0xef, 0xa0, 0x8b, 0x7f,
-	0x8b, 0xda, 0xe0, 0x55, 0xe4, 0x9f, 0x1f, 0x60, 0x6c, 0x0b, 0xc7, 0xa8,
-	0x33, 0xfa, 0xd1, 0x8c, 0x95, 0x98, 0x28, 0xba, 0x89, 0x09, 0x0f, 0x7f,
-	0xfc, 0xea, 0x6f, 0x66, 0xac, 0x29, 0xbe, 0xc3, 0x00, 0xf9, 0xfe, 0xf9,
-	0xdd, 0x73, 0x0a, 0x7b, 0x04, 0x98, 0x23, 0x67, 0x73, 0xff, 0x92, 0x9b,
-	0x9a, 0xa8, 0xe1, 0xe3, 0x61, 0x9b, 0xef, 0xd9, 0x1e, 0xb6, 0x59, 0xfa,
-	0xeb, 0xd4, 0xbb, 0x87, 0x6b, 0x1e, 0x4e, 0xd3, 0xaf, 0xeb, 0xc0, 0x1c,
-	0x35, 0xf8, 0x64, 0xa1, 0x69, 0xab, 0xcf, 0xf1, 0x8a, 0x6d, 0x46, 0x20,
-	0x1f, 0xf6, 0x58, 0x4f, 0xd1, 0x0b, 0x5d, 0xd3, 0x28, 0x13, 0x81, 0xba,
-	0x66, 0xfc, 0x9f, 0xf9, 0xd7, 0x4f, 0xfb, 0xd7, 0x4f, 0xf9, 0xd7, 0x27,
-	0x91, 0x77, 0x9f, 0x54, 0xb9, 0x93, 0xe3, 0x1c, 0x83, 0x72, 0x5d, 0xac,
-	0x85, 0xf5, 0xce, 0x8e, 0xfe, 0xb4, 0x55, 0x8d, 0x79, 0xfe, 0x5c, 0x68,
-	0x3a, 0xf8, 0xfc, 0x63, 0x7c, 0x0e, 0xe2, 0x33, 0x8d, 0xcf, 0x63, 0xf8,
-	0x6c, 0xca, 0x54, 0xcb, 0x56, 0xa8, 0xa3, 0x61, 0xc9, 0x62, 0xbc, 0x88,
-	0x3a, 0x34, 0x93, 0x7a, 0x44, 0x8a, 0xf5, 0x92, 0x94, 0x96, 0x34, 0xe9,
-	0xb6, 0xd2, 0x52, 0xaa, 0x1f, 0x93, 0xe3, 0x4b, 0xde, 0xb9, 0x61, 0x57,
-	0xda, 0xc6, 0xdc, 0x96, 0x3c, 0x9c, 0x7a, 0x5c, 0xf4, 0x3b, 0x8f, 0x61,
-	0x9e, 0xe8, 0xc5, 0xd1, 0xdb, 0xd4, 0xf9, 0x58, 0x3d, 0xe5, 0xc9, 0xf8,
-	0x80, 0x65, 0x9b, 0xc8, 0x5b, 0xc3, 0x4f, 0x62, 0xed, 0x8c, 0x7a, 0x3f,
-	0x30, 0x2d, 0x27, 0x4e, 0x6f, 0xec, 0xf5, 0x62, 0xa9, 0x69, 0xbc, 0x81,
-	0x4d, 0xeb, 0xe0, 0xc3, 0x46, 0xec, 0x9b, 0x82, 0x9d, 0x1f, 0x71, 0xc3,
-	0xda, 0x04, 0x62, 0xe0, 0x84, 0xab, 0x6a, 0x3d, 0xc4, 0x2a, 0xc3, 0x49,
-	0x9e, 0x8a, 0xe1, 0x9a, 0xef, 0xd0, 0x20, 0x0f, 0x2a, 0x5b, 0xd9, 0x00,
-	0x8e, 0xd1, 0x54, 0xbf, 0xaf, 0xb4, 0x79, 0x0e, 0xa4, 0xfa, 0xff, 0x4e,
-	0x32, 0xa9, 0x4b, 0x7e, 0x8c, 0x38, 0xd6, 0x56, 0xb9, 0xa8, 0x51, 0xb6,
-	0x3f, 0xc1, 0xda, 0xf0, 0x75, 0x61, 0x5e, 0xbb, 0x07, 0xf3, 0x06, 0x10,
-	0x7f, 0x71, 0xaf, 0x09, 0x5e, 0x4e, 0x93, 0x57, 0x3e, 0x83, 0xda, 0xb6,
-	0xfa, 0x49, 0xbd, 0xb8, 0xe4, 0xd7, 0x44, 0xaa, 0x76, 0x48, 0x48, 0x7d,
-	0xf3, 0xcc, 0xc9, 0xeb, 0x93, 0xd4, 0xdd, 0x00, 0x3b, 0xf4, 0x60, 0x0e,
-	0xeb, 0x08, 0xc8, 0xc8, 0x3b, 0x27, 0x53, 0x67, 0x64, 0x45, 0xf7, 0x93,
-	0x7a, 0x69, 0x29, 0x83, 0x71, 0xf6, 0xa4, 0xf1, 0xbd, 0xaa, 0x2b, 0xec,
-	0x7f, 0x31, 0x74, 0x58, 0x1a, 0xd5, 0x16, 0xe8, 0x45, 0x8e, 0xdd, 0x7b,
-	0x58, 0x6a, 0xd5, 0x79, 0x79, 0xa1, 0xba, 0xb1, 0x0b, 0xd8, 0x09, 0x32,
-	0x25, 0xfd, 0x3d, 0x3e, 0xfd, 0x54, 0x41, 0x30, 0x0e, 0x79, 0x9e, 0x2e,
-	0xc4, 0xbd, 0xba, 0x96, 0xb8, 0xed, 0x24, 0xdf, 0x1b, 0x8c, 0xf3, 0x3d,
-	0xbe, 0x23, 0xcb, 0xb4, 0xc9, 0x8b, 0xf7, 0x2e, 0x58, 0x9f, 0x92, 0x0b,
-	0xa9, 0x3d, 0xb2, 0x91, 0x52, 0xf5, 0x2f, 0xf1, 0x01, 0x7c, 0xdb, 0x34,
-	0xd6, 0xe5, 0x6e, 0x39, 0x01, 0x3f, 0xbd, 0x90, 0xca, 0xa9, 0xf3, 0x9b,
-	0xe3, 0x4d, 0x62, 0xfb, 0x79, 0xd6, 0x54, 0xb2, 0xae, 0x7a, 0x60, 0xad,
-	0xd6, 0x64, 0x8a, 0xb1, 0xa7, 0x43, 0x36, 0x14, 0xd6, 0xf2, 0x7a, 0xe3,
-	0x1b, 0xb3, 0x9e, 0x6f, 0x84, 0x94, 0xbd, 0xff, 0x1b, 0xd0, 0x71, 0x0c,
-	0x36, 0x1b, 0x51, 0x73, 0x42, 0xe9, 0x4e, 0x7f, 0x8e, 0xc2, 0x66, 0x6d,
-	0x73, 0xc6, 0xc7, 0x33, 0x96, 0xf1, 0xa9, 0x8c, 0x35, 0x36, 0xe1, 0xf5,
-	0x53, 0x4c, 0xc3, 0xd6, 0x2e, 0xb6, 0x82, 0xf7, 0x4d, 0xa6, 0xe0, 0x4f,
-	0x2f, 0x6d, 0x62, 0x63, 0x18, 0xe7, 0xf3, 0x0b, 0xd0, 0x6b, 0x58, 0x3a,
-	0x4e, 0xb5, 0xee, 0x99, 0x4b, 0x8d, 0x24, 0x8e, 0x08, 0xdf, 0x30, 0x62,
-	0xfd, 0x6c, 0x82, 0xda, 0x05, 0xe4, 0xc3, 0x2b, 0xc4, 0x08, 0xc3, 0xe7,
-	0xe5, 0xca, 0x3d, 0x99, 0xd4, 0x7e, 0xad, 0x36, 0x8b, 0xea, 0xe4, 0xf9,
-	0x29, 0xe6, 0xd3, 0xa3, 0xec, 0x7d, 0x86, 0x4e, 0xbd, 0xad, 0x39, 0x65,
-	0xf5, 0x8e, 0x39, 0xf4, 0xd2, 0xd2, 0xe6, 0x21, 0x37, 0x3c, 0x3f, 0xc3,
-	0x04, 0xa8, 0x5b, 0x83, 0x09, 0x47, 0x72, 0xec, 0x71, 0x49, 0x7e, 0x59,
-	0xf6, 0x65, 0x10, 0x47, 0xed, 0x99, 0x0e, 0x99, 0x6f, 0x18, 0xce, 0xe0,
-	0xe2, 0x51, 0xac, 0x31, 0x87, 0xb5, 0xa6, 0x51, 0x83, 0xcc, 0x22, 0x27,
-	0x53, 0xae, 0x8c, 0xd5, 0x0f, 0x43, 0x46, 0x37, 0xf1, 0xcc, 0x78, 0x3c,
-	0x27, 0xe6, 0x4c, 0x41, 0xad, 0xfb, 0x9e, 0x96, 0x1f, 0xfd, 0x18, 0x72,
-	0x5a, 0x58, 0x0e, 0x24, 0x45, 0x9f, 0x4e, 0x86, 0xdf, 0x9f, 0xb3, 0x38,
-	0x16, 0xe5, 0x98, 0x8e, 0xb1, 0xf0, 0xe7, 0x92, 0x51, 0x3d, 0x93, 0x34,
-	0xc7, 0xd9, 0xef, 0x0d, 0x59, 0x73, 0x12, 0x7a, 0xbe, 0xb7, 0x47, 0xba,
-	0xa7, 0xa5, 0x77, 0xd5, 0x1c, 0x7f, 0x1d, 0xb4, 0x84, 0x55, 0x6c, 0x9f,
-	0x13, 0xdd, 0x1f, 0xef, 0xd9, 0x1c, 0x0f, 0xfb, 0xe3, 0xd3, 0xd2, 0xbd,
-	0x3a, 0x62, 0xbc, 0x29, 0x87, 0xb1, 0x66, 0x48, 0x2e, 0xa1, 0xa6, 0xb1,
-	0x86, 0xe6, 0xe0, 0x73, 0x0f, 0x91, 0x96, 0x83, 0xc0, 0x14, 0xf0, 0x09,
-	0xd4, 0xd9, 0xd6, 0x27, 0xe5, 0x4b, 0x46, 0x97, 0xe4, 0x55, 0x4d, 0x1b,
-	0xf6, 0x7a, 0xa5, 0xb0, 0xf3, 0x5b, 0x87, 0xa6, 0x77, 0x7b, 0xfd, 0x00,
-	0x9e, 0x67, 0x8c, 0x62, 0xec, 0x4a, 0x6b, 0xc5, 0xe2, 0x18, 0xef, 0x5d,
-	0x69, 0xd5, 0xad, 0x11, 0x23, 0xab, 0x45, 0xfd, 0x73, 0xed, 0x79, 0xc5,
-	0x7b, 0xa1, 0x3a, 0x68, 0xd4, 0xe4, 0x16, 0x2d, 0x7b, 0x03, 0xf2, 0x83,
-	0xfb, 0x19, 0xcc, 0xbd, 0xd2, 0xca, 0x58, 0xf3, 0xaa, 0x7f, 0x5f, 0x93,
-	0xe0, 0x9a, 0xeb, 0x8c, 0x18, 0x93, 0xea, 0xd9, 0x11, 0xe3, 0x84, 0xd6,
-	0xfe, 0xac, 0xa1, 0x4d, 0x6e, 0x7b, 0xb6, 0x5b, 0xc9, 0x28, 0x64, 0x79,
-	0x73, 0x4a, 0xd5, 0x69, 0x79, 0xda, 0xe5, 0xbc, 0x2b, 0xad, 0xac, 0x15,
-	0xd1, 0x4e, 0xdc, 0xc0, 0x18, 0xc8, 0xb9, 0x97, 0xaf, 0xda, 0x87, 0xd7,
-	0xd7, 0xda, 0xe3, 0x5d, 0xd9, 0xbe, 0xc7, 0x2e, 0x35, 0xe7, 0x82, 0x9a,
-	0x13, 0x56, 0xb2, 0xde, 0xbe, 0xcf, 0xcf, 0x64, 0xfb, 0x3e, 0xdd, 0x9b,
-	0x3c, 0x97, 0xb0, 0xe6, 0x93, 0x98, 0x5b, 0x76, 0x07, 0xe3, 0x75, 0xb9,
-	0xdc, 0xca, 0x5b, 0x17, 0xe5, 0xc2, 0xe6, 0xda, 0xbf, 0xc2, 0x75, 0x3b,
-	0x4d, 0xbf, 0xf2, 0x69, 0xe4, 0x77, 0x8e, 0x3d, 0xaa, 0xe4, 0xbd, 0xdb,
-	0x1a, 0x3c, 0x58, 0xd3, 0xcc, 0xf1, 0x9f, 0x09, 0x75, 0x75, 0x44, 0xc5,
-	0x98, 0xdb, 0xa0, 0xa7, 0x7d, 0xcf, 0xc0, 0x67, 0x47, 0x6d, 0x35, 0xe7,
-	0x92, 0x35, 0x2d, 0xfb, 0x4e, 0x0d, 0x1a, 0x97, 0x10, 0xdb, 0x9c, 0x18,
-	0xaf, 0x51, 0x2b, 0x59, 0x7c, 0x27, 0xfe, 0x4e, 0xd6, 0x01, 0xd0, 0xe5,
-	0xe0, 0xf0, 0xcf, 0xe4, 0xa8, 0x9c, 0xa8, 0x1c, 0x43, 0x2e, 0x9c, 0x93,
-	0xe1, 0x67, 0x90, 0x37, 0x2a, 0x05, 0x3c, 0x49, 0x9f, 0xf5, 0x72, 0xe0,
-	0x9c, 0x7a, 0xcf, 0xfc, 0x24, 0xea, 0x64, 0xd8, 0x6e, 0x79, 0x70, 0x78,
-	0x05, 0xcf, 0xbc, 0xa0, 0x70, 0xa8, 0x2b, 0x0d, 0xf8, 0x40, 0xe2, 0xf9,
-	0x3d, 0xb2, 0xfb, 0x01, 0xda, 0x22, 0x32, 0xfd, 0x6d, 0x11, 0xf5, 0xee,
-	0xbd, 0x6e, 0x75, 0x8a, 0xec, 0xa5, 0xdd, 0x34, 0x61, 0x63, 0x73, 0xde,
-	0x99, 0xd6, 0xb6, 0x6b, 0x73, 0xe6, 0xa2, 0xac, 0x2a, 0xfb, 0xbb, 0x7d,
-	0xd5, 0xfb, 0x3f, 0xba, 0x8a, 0x72, 0x38, 0x39, 0x2d, 0x77, 0xac, 0x7a,
-	0xf6, 0x56, 0x5a, 0x3a, 0xaa, 0xe4, 0x3a, 0xa7, 0xe4, 0xda, 0x92, 0xc3,
-	0x29, 0xca, 0x9c, 0xbc, 0xf0, 0xbd, 0x40, 0x4f, 0x16, 0xf7, 0xfb, 0xf6,
-	0x33, 0xf8, 0x0c, 0x7f, 0x57, 0x42, 0xd9, 0xb0, 0xee, 0xbe, 0x7f, 0x37,
-	0xcf, 0x59, 0xf7, 0xad, 0x92, 0xcf, 0x1b, 0xb7, 0xf1, 0xf9, 0x14, 0x62,
-	0xea, 0xd0, 0x90, 0xc7, 0xeb, 0xab, 0x4b, 0x1f, 0xce, 0xeb, 0x37, 0x37,
-	0x79, 0x0d, 0x49, 0x43, 0xd5, 0xaf, 0x5d, 0xbd, 0xd2, 0x8d, 0xa8, 0x07,
-	0x7b, 0xf8, 0x09, 0xf6, 0x9a, 0x12, 0xd2, 0xe0, 0xed, 0xb7, 0xe1, 0x92,
-	0x96, 0x80, 0x76, 0xd2, 0x73, 0x9f, 0xaf, 0x2f, 0xee, 0x7f, 0x74, 0xc7,
-	0x7b, 0x97, 0xc4, 0x70, 0x86, 0x31, 0xa6, 0x2b, 0x9d, 0x65, 0x7d, 0xff,
-	0x9a, 0x16, 0x5d, 0xe9, 0xcc, 0xde, 0xd4, 0xd9, 0xeb, 0xd0, 0x59, 0x5d,
-	0x7e, 0x13, 0xbc, 0xc0, 0x9f, 0x9f, 0x19, 0x31, 0x0e, 0x13, 0x5b, 0x18,
-	0x5c, 0x0f, 0x31, 0xd4, 0xd7, 0x5d, 0xc7, 0x47, 0xd0, 0xdd, 0x9b, 0xa2,
-	0xf4, 0x07, 0x7e, 0x90, 0x7f, 0xd4, 0xf3, 0x8c, 0x61, 0xe4, 0xa9, 0x43,
-	0xf9, 0x3e, 0x69, 0x53, 0x67, 0xfc, 0x33, 0x9e, 0x3e, 0x95, 0x6f, 0xfb,
-	0xfa, 0xcc, 0xcd, 0x50, 0x67, 0xe6, 0x6e, 0x4f, 0x7f, 0x9d, 0x6a, 0xce,
-	0x62, 0x32, 0xa1, 0xfc, 0xda, 0x1a, 0xba, 0x65, 0x37, 0x75, 0xf8, 0xb4,
-	0xeb, 0xfd, 0x2f, 0xbb, 0xd3, 0xb2, 0xe8, 0x7e, 0x98, 0x1e, 0x3d, 0x1d,
-	0x4e, 0x88, 0xe7, 0x3f, 0x57, 0xeb, 0x4f, 0x5f, 0x0d, 0x2b, 0x5b, 0x9d,
-	0x80, 0xec, 0x4e, 0x56, 0x3e, 0xe6, 0xdb, 0xb7, 0xc7, 0xeb, 0xd0, 0x87,
-	0xf0, 0x7a, 0xb8, 0x3c, 0x68, 0xbc, 0x8d, 0xb5, 0x26, 0x15, 0x86, 0x8b,
-	0x88, 0xe3, 0xf3, 0x9a, 0xd8, 0xe4, 0x35, 0xa0, 0xcd, 0x9b, 0x97, 0x65,
-	0x5d, 0xea, 0x32, 0x3e, 0x3d, 0xaa, 0xde, 0xbf, 0x7f, 0xa3, 0xcc, 0xb8,
-	0x0c, 0xcc, 0x13, 0xeb, 0x93, 0x4b, 0x8d, 0x84, 0x5c, 0x22, 0x96, 0x18,
-	0xc3, 0x7f, 0xf7, 0x98, 0x9f, 0x9b, 0xa3, 0xf2, 0x66, 0xb9, 0xbd, 0x56,
-	0x1c, 0x95, 0xd7, 0xcb, 0x41, 0xbd, 0x48, 0x2c, 0xcb, 0xfc, 0x3f, 0x27,
-	0x6f, 0x2d, 0x0d, 0xca, 0xfa, 0x0c, 0xf2, 0xf8, 0x10, 0x65, 0x30, 0x62,
-	0x7c, 0x46, 0xfd, 0xbe, 0xe2, 0x4a, 0xeb, 0xbc, 0x85, 0x75, 0x97, 0x5b,
-	0x72, 0x84, 0xe7, 0xd0, 0xfc, 0xde, 0xf8, 0x04, 0x56, 0xe1, 0xbc, 0x3e,
-	0xa9, 0x2d, 0xa3, 0x2e, 0x2f, 0x73, 0x5d, 0xca, 0x69, 0x5a, 0x7d, 0x9f,
-	0xc4, 0x3e, 0xf7, 0xf3, 0xbd, 0xf4, 0x18, 0x75, 0x71, 0xa5, 0xb5, 0x61,
-	0xf1, 0x1c, 0x72, 0x4e, 0x1a, 0xd0, 0xd7, 0x97, 0x93, 0x3c, 0x27, 0xcf,
-	0x0b, 0x7f, 0x9f, 0x52, 0x6b, 0xcc, 0xa0, 0x16, 0xb8, 0xd2, 0x5a, 0xb0,
-	0x9e, 0x52, 0x7a, 0x6a, 0x54, 0x1f, 0xf0, 0xc7, 0x79, 0xcd, 0x7b, 0x86,
-	0xb3, 0x6f, 0x88, 0xf5, 0xe7, 0x03, 0xc8, 0xff, 0xac, 0x3d, 0x89, 0xb7,
-	0x28, 0x8b, 0x04, 0x6a, 0x5c, 0xae, 0xc5, 0xdf, 0x04, 0x25, 0x87, 0xf3,
-	0x32, 0x09, 0x7a, 0x80, 0xcb, 0x5c, 0xc6, 0xfd, 0x5b, 0x65, 0x23, 0xe6,
-	0xc5, 0x77, 0xbe, 0xaf, 0xb5, 0x81, 0x98, 0xbf, 0xb1, 0x19, 0xf3, 0xfb,
-	0x71, 0x6d, 0x38, 0xa9, 0xa1, 0xff, 0x84, 0xf5, 0xd9, 0x77, 0x61, 0xcc,
-	0x1f, 0xc7, 0x7c, 0x8e, 0xf5, 0x49, 0x69, 0x59, 0x6c, 0xf6, 0x99, 0x6a,
-	0xc2, 0x77, 0x31, 0x72, 0xb2, 0xd8, 0x18, 0x8c, 0x9f, 0xd7, 0x1c, 0xf5,
-	0xce, 0x46, 0x72, 0x88, 0x7d, 0xb7, 0x3e, 0x69, 0x2c, 0x4b, 0x22, 0x94,
-	0x7e, 0x48, 0xdc, 0x86, 0x87, 0xb9, 0x17, 0x34, 0xf6, 0xdf, 0x6c, 0x69,
-	0x6c, 0x9f, 0x63, 0x84, 0xd2, 0x87, 0xe4, 0x0f, 0xfc, 0x39, 0x8e, 0x9a,
-	0xf3, 0x1f, 0x76, 0xf3, 0xec, 0xab, 0xe1, 0xf6, 0x82, 0x06, 0xd2, 0x76,
-	0x63, 0xfb, 0xbe, 0x89, 0xad, 0x7d, 0xb9, 0x27, 0x6a, 0x98, 0xbd, 0x36,
-	0xf6, 0x7d, 0x15, 0xcf, 0x3c, 0x04, 0x3a, 0xae, 0x84, 0x74, 0xeb, 0x21,
-	0x29, 0x36, 0xae, 0xde, 0xa3, 0x9d, 0x06, 0x3e, 0xc3, 0xf5, 0xb9, 0xcf,
-	0x21, 0xd0, 0x77, 0x45, 0xd3, 0xad, 0x43, 0x90, 0xa5, 0xb7, 0x47, 0xe8,
-	0x39, 0xd3, 0xf8, 0xa1, 0x0c, 0x89, 0xbe, 0xa2, 0x29, 0xf9, 0xeb, 0xb5,
-	0x51, 0x38, 0xc4, 0x94, 0x74, 0xaf, 0xcd, 0x4a, 0x68, 0x8d, 0x3d, 0x00,
-	0xda, 0x22, 0xf5, 0xb8, 0x0b, 0x7e, 0x2c, 0x76, 0xd8, 0x22, 0xde, 0x67,
-	0x1f, 0x77, 0xb5, 0x57, 0x7a, 0x89, 0xf7, 0x59, 0x0f, 0x1c, 0xc4, 0x7f,
-	0xd6, 0x04, 0x2f, 0xb5, 0x32, 0xa9, 0x77, 0x54, 0xde, 0xcc, 0x37, 0x78,
-	0xdf, 0x4c, 0x88, 0xf0, 0x1e, 0xe3, 0x43, 0x9f, 0x44, 0xbe, 0x3e, 0x8c,
-	0x98, 0x90, 0x03, 0x76, 0xc6, 0xba, 0xa7, 0x86, 0x24, 0xec, 0xbd, 0xeb,
-	0xa0, 0xfa, 0x25, 0x6f, 0x2d, 0x9b, 0xfe, 0xef, 0x53, 0x64, 0xdf, 0xf9,
-	0x14, 0x7b, 0x9a, 0x03, 0xb0, 0x53, 0xd6, 0x23, 0xa2, 0x6f, 0xa0, 0xde,
-	0xbc, 0xd4, 0x88, 0xf6, 0xf2, 0x7d, 0xcb, 0xd7, 0x5d, 0x5c, 0x13, 0xbb,
-	0xc7, 0x14, 0x56, 0xf4, 0xef, 0xf1, 0x3b, 0xea, 0xa0, 0x6d, 0x98, 0x32,
-	0x01, 0x4c, 0xc9, 0x3a, 0x69, 0xca, 0x7f, 0xe7, 0xcd, 0x70, 0x4e, 0x6c,
-	0xab, 0x95, 0x86, 0x65, 0x03, 0x38, 0x6b, 0xdd, 0xb5, 0x10, 0x07, 0xdf,
-	0xd6, 0xea, 0x65, 0xf5, 0xbb, 0x34, 0xed, 0x01, 0x60, 0xac, 0x44, 0x9f,
-	0xaa, 0x75, 0x4e, 0x3e, 0x20, 0x9e, 0xbd, 0xc3, 0xca, 0x54, 0xcc, 0x5a,
-	0xaf, 0x7a, 0xb5, 0xc5, 0x46, 0x75, 0x4a, 0xfe, 0xd4, 0x5d, 0x50, 0xbd,
-	0xd2, 0x25, 0xd4, 0x1b, 0xe1, 0x45, 0x55, 0x6b, 0xb5, 0xe1, 0x54, 0xc4,
-	0xb7, 0x67, 0x8f, 0xc0, 0x07, 0x4d, 0xf5, 0x6e, 0x81, 0xbe, 0xd2, 0x6a,
-	0x65, 0x11, 0x2f, 0x74, 0xcb, 0x32, 0x8a, 0xc8, 0x73, 0x59, 0xf5, 0x7e,
-	0x0a, 0xfd, 0xf7, 0xf7, 0x54, 0x1c, 0x96, 0x1a, 0x64, 0xf3, 0x5c, 0x02,
-	0xeb, 0x68, 0xca, 0x3e, 0x43, 0x4a, 0x0f, 0x0f, 0x28, 0xec, 0x1a, 0x5a,
-	0x41, 0x80, 0x5a, 0x1b, 0x12, 0x59, 0x81, 0xbf, 0xc2, 0x77, 0xc3, 0x6b,
-	0xd4, 0x01, 0x65, 0x3b, 0x2b, 0x11, 0xc8, 0x9e, 0x58, 0x22, 0xb4, 0x48,
-	0x19, 0xc7, 0x61, 0x17, 0x5c, 0x07, 0x32, 0xe6, 0xbb, 0x2c, 0xcb, 0x1d,
-	0xf2, 0x4c, 0xc3, 0xf4, 0xdf, 0x3d, 0x7f, 0x89, 0xef, 0xa3, 0xeb, 0x73,
-	0x63, 0x03, 0xc4, 0x4f, 0x52, 0x6a, 0x00, 0x63, 0x9c, 0x66, 0x0d, 0xce,
-	0x18, 0x50, 0x88, 0x47, 0x94, 0xaf, 0xb3, 0x06, 0xf6, 0x7c, 0x9f, 0xf8,
-	0x3a, 0x62, 0x11, 0xdb, 0x8e, 0x62, 0x8f, 0x9d, 0xe4, 0xea, 0xd5, 0x9e,
-	0x93, 0xa0, 0xf3, 0xfc, 0x92, 0x39, 0x55, 0x90, 0x14, 0xdf, 0x71, 0x9e,
-	0xb1, 0xc1, 0xf7, 0x06, 0xe2, 0xe4, 0x42, 0x85, 0xef, 0x33, 0x17, 0xe1,
-	0x59, 0x53, 0x72, 0xbe, 0xcc, 0x1a, 0xf0, 0x76, 0xe8, 0x8b, 0xd7, 0xc5,
-	0xf1, 0x10, 0xfc, 0xff, 0xa2, 0xc1, 0xdf, 0x91, 0xf1, 0x77, 0x41, 0x66,
-	0x2a, 0xa1, 0x1d, 0x84, 0x8e, 0x0b, 0x46, 0xc4, 0xb7, 0x03, 0xa7, 0x4c,
-	0x8c, 0x35, 0x62, 0x9c, 0xc3, 0xf7, 0x97, 0xdd, 0xcb, 0x2d, 0xd6, 0x3f,
-	0x17, 0x10, 0xe7, 0xa6, 0x92, 0x53, 0xb0, 0x9d, 0x42, 0xbc, 0x13, 0xb4,
-	0xfe, 0x5d, 0xdc, 0xcb, 0xbb, 0xdc, 0xc7, 0x4c, 0x5d, 0x94, 0x22, 0x30,
-	0xfd, 0x48, 0xe2, 0x65, 0xd9, 0x83, 0x3a, 0x55, 0x93, 0x37, 0x2d, 0x73,
-	0x5c, 0x34, 0xb5, 0xde, 0xf0, 0x7d, 0xb0, 0xbd, 0x37, 0x10, 0xdf, 0x3a,
-	0xfc, 0xda, 0x3d, 0x5b, 0x26, 0x16, 0x3a, 0xaa, 0xde, 0x05, 0xb8, 0x60,
-	0xb1, 0x7f, 0xc7, 0xdf, 0x44, 0xfe, 0xa5, 0xda, 0x63, 0xeb, 0x8c, 0x8d,
-	0xfd, 0x63, 0xd2, 0xe7, 0xf1, 0x78, 0xc0, 0xf2, 0x68, 0xe4, 0x3a, 0x91,
-	0xb6, 0x75, 0xce, 0xfb, 0xeb, 0x9c, 0xf5, 0xd7, 0xa9, 0xf9, 0xeb, 0x5c,
-	0xd8, 0x5c, 0xe7, 0x6e, 0xe8, 0xbf, 0xd5, 0x7a, 0x0a, 0xf8, 0x21, 0x93,
-	0x6a, 0xb5, 0x1c, 0xd4, 0x59, 0xa5, 0xd1, 0x79, 0x75, 0x46, 0xaa, 0xa7,
-	0xbf, 0x71, 0x6f, 0xc6, 0x2a, 0xc4, 0xc3, 0x0a, 0x7b, 0xa0, 0x92, 0x82,
-	0x1d, 0x16, 0xc4, 0xc3, 0xdc, 0x3c, 0xb7, 0xf3, 0xce, 0xf5, 0xba, 0xa1,
-	0xc3, 0x1c, 0x72, 0x86, 0x91, 0x39, 0x67, 0x49, 0x61, 0xdf, 0x6f, 0xea,
-	0xb0, 0xf3, 0x5e, 0xe4, 0x87, 0x9f, 0xc0, 0x66, 0x8c, 0x4c, 0xbd, 0x91,
-	0x43, 0xbd, 0xc3, 0xf9, 0x77, 0x40, 0x8f, 0x85, 0x4c, 0xad, 0x51, 0xc8,
-	0x9c, 0xe5, 0x79, 0x0e, 0xe6, 0xd5, 0x1a, 0x3d, 0x90, 0x7b, 0x8f, 0xea,
-	0x8b, 0xbc, 0x5c, 0x8e, 0x31, 0x06, 0xc1, 0xd6, 0x63, 0x18, 0x8b, 0xab,
-	0xdf, 0x68, 0xd5, 0xdd, 0x65, 0xf8, 0x74, 0x02, 0xe3, 0xd5, 0xae, 0x49,
-	0x85, 0x47, 0x2d, 0x59, 0x71, 0x7f, 0xa5, 0x15, 0xcb, 0x97, 0xb5, 0x52,
-	0x79, 0x18, 0x73, 0x46, 0xf9, 0x5b, 0x9f, 0x3d, 0xc0, 0x49, 0x53, 0xd5,
-	0x1d, 0x69, 0x4a, 0x80, 0x26, 0xbd, 0x8d, 0xa6, 0x04, 0xe8, 0x41, 0xcc,
-	0x3c, 0xc5, 0xde, 0xf1, 0xa8, 0x9c, 0x28, 0xf3, 0x9d, 0x26, 0xfe, 0x46,
-	0xd5, 0x90, 0x30, 0xb0, 0x65, 0xe4, 0x94, 0x19, 0x5f, 0x57, 0xbd, 0x1a,
-	0x73, 0xb8, 0x2e, 0x23, 0xa9, 0xba, 0xa8, 0xfc, 0x92, 0x38, 0x81, 0x7c,
-	0xf5, 0x86, 0xdb, 0x23, 0x6f, 0xfa, 0x7b, 0x5d, 0x14, 0x9e, 0x33, 0x6e,
-	0xdf, 0xeb, 0xc9, 0x4a, 0x2a, 0xf3, 0x8a, 0x15, 0xf2, 0xf9, 0xea, 0xc3,
-	0x5e, 0x7b, 0x30, 0x37, 0x95, 0x39, 0xdf, 0xd8, 0x69, 0xae, 0x83, 0xb9,
-	0x91, 0xb6, 0xb9, 0x0e, 0xe6, 0xf5, 0x20, 0xef, 0xf5, 0x28, 0x9e, 0x4a,
-	0xa0, 0xeb, 0x52, 0x99, 0x3c, 0xf1, 0x0c, 0x82, 0x7b, 0x1a, 0xc4, 0xc6,
-	0x53, 0xe2, 0x9f, 0xd9, 0xf2, 0xf7, 0x7a, 0x57, 0xf5, 0x6b, 0x94, 0x0d,
-	0x4c, 0x58, 0x3c, 0x9b, 0x99, 0xd1, 0xb2, 0xf5, 0x3c, 0x72, 0xd5, 0x8d,
-	0xc4, 0x43, 0x29, 0x1b, 0xb9, 0x92, 0xe7, 0x3c, 0x8d, 0x72, 0x81, 0xef,
-	0x3d, 0xc3, 0x2e, 0xde, 0x21, 0x5e, 0xbe, 0x31, 0xa4, 0xde, 0x43, 0x70,
-	0xfc, 0x73, 0x20, 0x31, 0x32, 0x63, 0x7c, 0xf7, 0xe0, 0x6e, 0xa9, 0x2f,
-	0x7f, 0x11, 0x63, 0x19, 0xe4, 0xc5, 0x43, 0x5a, 0xe6, 0xdc, 0x24, 0xae,
-	0x1f, 0xc2, 0x35, 0xe2, 0xf0, 0x72, 0x0e, 0xf7, 0x1f, 0xc2, 0xf5, 0xbc,
-	0x96, 0x6d, 0xe6, 0x70, 0xfd, 0x30, 0xae, 0x27, 0x48, 0x9b, 0xf3, 0x8a,
-	0x35, 0xa5, 0xd9, 0x58, 0xcb, 0x3e, 0x37, 0x89, 0x4f, 0xfb, 0x7a, 0xbc,
-	0x07, 0x3d, 0x95, 0x79, 0x3e, 0x96, 0x04, 0x4d, 0x0f, 0x6a, 0x4e, 0xbd,
-	0x1b, 0x6b, 0x0c, 0xe1, 0x79, 0xda, 0x54, 0xfb, 0x39, 0xd4, 0x6d, 0xaa,
-	0x67, 0x14, 0x4a, 0xa7, 0x81, 0x77, 0x1f, 0x41, 0xde, 0xd7, 0xc4, 0xb1,
-	0x1e, 0x97, 0x62, 0x2a, 0x2d, 0x0b, 0xf5, 0x90, 0x64, 0x63, 0x05, 0x7c,
-	0x2f, 0x48, 0x66, 0x1c, 0xf7, 0xeb, 0xb4, 0x05, 0xce, 0x2b, 0x49, 0xb1,
-	0x4a, 0xfc, 0xce, 0x7e, 0xd1, 0x57, 0xc0, 0x37, 0xfb, 0x44, 0x79, 0xc8,
-	0x20, 0x46, 0xfb, 0xdd, 0xa1, 0xa7, 0xe5, 0xbd, 0xd3, 0x8c, 0x7c, 0xac,
-	0x65, 0xea, 0xfe, 0x59, 0x9d, 0xc5, 0xdf, 0x2b, 0xb1, 0x47, 0x25, 0xc5,
-	0x50, 0x9a, 0x7d, 0x0e, 0xd5, 0x17, 0x4f, 0x79, 0x67, 0x7a, 0xed, 0xef,
-	0x90, 0x04, 0xfe, 0xc2, 0x7d, 0xbf, 0x82, 0xe7, 0xbd, 0xbe, 0x54, 0xb6,
-	0xf9, 0x41, 0x5d, 0xf0, 0x5d, 0xfd, 0x15, 0xe8, 0xe2, 0xfc, 0x87, 0xf6,
-	0xb9, 0xd8, 0xe3, 0x9a, 0x47, 0x2c, 0x62, 0x7f, 0x2c, 0x90, 0xdf, 0xd5,
-	0x34, 0x92, 0xbe, 0xc3, 0x58, 0x4b, 0x52, 0x8c, 0xb3, 0xb9, 0x58, 0x42,
-	0xd5, 0xbe, 0x1b, 0x4b, 0xf2, 0xc4, 0x16, 0xbd, 0xa4, 0x95, 0x72, 0x78,
-	0x04, 0xf5, 0x1a, 0x7f, 0xff, 0xf0, 0xb8, 0xe4, 0x53, 0xec, 0xd1, 0x84,
-	0x90, 0x0b, 0x0b, 0xf8, 0xbe, 0x25, 0xb7, 0x92, 0x2f, 0xb7, 0x7c, 0xf5,
-	0x5b, 0x4a, 0x77, 0x35, 0x8b, 0xfb, 0x05, 0xbd, 0x8b, 0x69, 0xa5, 0xb3,
-	0x9a, 0x7a, 0xcf, 0x36, 0xe0, 0x3d, 0xe8, 0xbf, 0xed, 0x6c, 0x73, 0x93,
-	0x16, 0x69, 0xfb, 0x38, 0xdf, 0x5b, 0x18, 0xb6, 0x85, 0xf4, 0x93, 0x0f,
-	0xe6, 0xac, 0xe0, 0x5c, 0x34, 0xe0, 0x21, 0xe0, 0xf3, 0xa3, 0xca, 0x85,
-	0x74, 0xee, 0x31, 0xa4, 0x7b, 0xca, 0x08, 0x59, 0xcc, 0x01, 0x9f, 0xf6,
-	0xfb, 0xf8, 0xff, 0x37, 0xe5, 0xea, 0xf1, 0x1e, 0x86, 0xa8, 0xfc, 0xdf,
-	0x8b, 0xee, 0xa0, 0xf7, 0xab, 0xcf, 0x80, 0x0d, 0xe7, 0xac, 0xb5, 0xc5,
-	0x67, 0x6d, 0x07, 0x3e, 0x6b, 0x3e, 0x9f, 0x1f, 0x7e, 0x4e, 0xea, 0xd1,
-	0x59, 0x5b, 0xb2, 0xc1, 0x23, 0x6d, 0x6a, 0x27, 0x7b, 0xe3, 0x6f, 0x9c,
-	0xd4, 0xef, 0xad, 0xa2, 0xb6, 0x7b, 0xad, 0x5e, 0x27, 0xeb, 0x64, 0xcf,
-	0xee, 0xce, 0x22, 0xd7, 0x55, 0xab, 0x5e, 0xcd, 0x5c, 0x75, 0xd9, 0x6b,
-	0xde, 0x69, 0x6f, 0x0d, 0x34, 0xff, 0x8e, 0x7a, 0xef, 0xa4, 0xe4, 0x7a,
-	0x7d, 0xa9, 0x6a, 0xb5, 0x3d, 0x57, 0xde, 0xc0, 0x3c, 0x39, 0x5c, 0x90,
-	0x19, 0xe8, 0x31, 0x89, 0xeb, 0x9b, 0xe5, 0xe5, 0x65, 0x75, 0x86, 0xe4,
-	0x9f, 0xd5, 0xf0, 0x0c, 0x46, 0x9d, 0x43, 0x23, 0x5e, 0xcd, 0xaa, 0x78,
-	0xbd, 0xb1, 0xac, 0xee, 0xa9, 0xdf, 0x3c, 0xd4, 0xdd, 0x19, 0xc4, 0x73,
-	0xd4, 0x06, 0xd6, 0x6e, 0x29, 0xa2, 0x86, 0x3e, 0x6b, 0xcd, 0x18, 0xc4,
-	0x29, 0x5c, 0x6b, 0x03, 0x6b, 0x9d, 0x5f, 0x96, 0xbd, 0x7c, 0xa7, 0xa3,
-	0xaa, 0xce, 0xbd, 0xbc, 0x7e, 0xf5, 0xbc, 0x04, 0xbf, 0xd7, 0x8d, 0xfa,
-	0x39, 0x8e, 0xef, 0x95, 0xf0, 0xb7, 0xa7, 0x8c, 0x01, 0xa8, 0x6b, 0x66,
-	0x0a, 0x58, 0xaf, 0xd5, 0xf2, 0xfa, 0xd9, 0x2d, 0xd8, 0x7d, 0x84, 0xbf,
-	0x65, 0xc0, 0xdf, 0x23, 0xb0, 0x13, 0xf8, 0xc1, 0xe6, 0x38, 0xaf, 0x59,
-	0x4b, 0x04, 0xd7, 0x4c, 0x58, 0xff, 0x1b, 0xed, 0xcc, 0xfa, 0xa1, 0x98,
-	0x41, 0x00, 0x00, 0x00 };
-static u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
+	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c,
+	0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1,
+	0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42,
+	0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48,
+	0xd1, 0x6c, 0x68, 0x95, 0x49, 0x94, 0x54, 0xe3, 0x62, 0x41, 0x52, 0xf1,
+	0xb6, 0xce, 0x54, 0x9b, 0x78, 0x5a, 0x4d, 0xeb, 0xad, 0x11, 0x90, 0xfa,
+	0xe7, 0x85, 0x04, 0xda, 0x62, 0x44, 0x7f, 0xc8, 0x07, 0x18, 0x80, 0x24,
+	0x6f, 0xf2, 0x44, 0x28, 0x9b, 0x7f, 0xfd, 0xd0, 0xac, 0x50, 0x4a, 0xd6,
+	0xba, 0x9b, 0xb4, 0xa3, 0xed, 0x66, 0x67, 0x3b, 0xd3, 0x2f, 0x1c, 0x49,
+	0xf6, 0x7a, 0x77, 0x67, 0x36, 0xda, 0x6e, 0xb6, 0xab, 0xb6, 0xb2, 0xd1,
+	0xdf, 0xef, 0xbe, 0xf7, 0x28, 0x90, 0xa6, 0x6c, 0xcb, 0xb3, 0xed, 0x94,
+	0x33, 0x18, 0xe0, 0xdd, 0x77, 0xdf, 0xb9, 0xe7, 0x9e, 0x73, 0xee, 0x39,
+	0xe7, 0x77, 0xee, 0x7d, 0x0c, 0x8b, 0x74, 0x89, 0xf7, 0xf7, 0x00, 0x3e,
+	0x91, 0x43, 0x87, 0x9f, 0xd9, 0x3e, 0xb2, 0xfd, 0x13, 0xf8, 0xf9, 0x09,
+	0x31, 0x02, 0x06, 0x6f, 0xbe, 0x69, 0x88, 0x64, 0xff, 0x42, 0x3e, 0xf0,
+	0x1f, 0x1e, 0x37, 0x7d, 0xfa, 0xfc, 0x48, 0x50, 0x4f, 0x4c, 0xec, 0x4a,
+	0x5a, 0x12, 0x34, 0x12, 0xb2, 0x6f, 0xca, 0x12, 0xb1, 0x9d, 0xa1, 0x48,
+	0x4a, 0xde, 0x6a, 0xe6, 0x43, 0x01, 0x61, 0xfb, 0x47, 0x12, 0x77, 0x9e,
+	0xfb, 0xc9, 0xa7, 0xa3, 0xb7, 0xca, 0x86, 0x04, 0xcd, 0x44, 0x56, 0xcc,
+	0x01, 0x09, 0xf6, 0xe1, 0x99, 0x6f, 0x3f, 0x6a, 0x18, 0xd2, 0xb3, 0xca,
+	0xab, 0xcc, 0x95, 0x56, 0x9a, 0x3f, 0x79, 0x34, 0x2c, 0xbf, 0x57, 0x0f,
+	0xc9, 0xf7, 0xea, 0xa6, 0x5c, 0xac, 0x07, 0xb4, 0xf1, 0x92, 0x29, 0xb3,
+	0xa5, 0x69, 0xfd, 0x48, 0x31, 0x2f, 0xa9, 0x7a, 0x56, 0x2f, 0x2c, 0x98,
+	0x3d, 0xc9, 0xf3, 0x39, 0x7d, 0x76, 0xa1, 0xb7, 0x27, 0x75, 0x7e, 0x5a,
+	0x2f, 0x14, 0xc3, 0x3d, 0xc9, 0xba, 0xd9, 0x93, 0x5a, 0x0c, 0xe1, 0xba,
+	0xb7, 0x27, 0xb9, 0x18, 0x9d, 0x17, 0xd9, 0x8a, 0x3e, 0xe1, 0x9e, 0x54,
+	0x29, 0x9a, 0x15, 0xe9, 0x8f, 0xbf, 0x2a, 0x7d, 0x3d, 0xa9, 0xfa, 0x3f,
+	0xd1, 0x1b, 0xa6, 0x26, 0x85, 0x5f, 0x15, 0x33, 0x9c, 0xb8, 0xd5, 0x7c,
+	0xc8, 0xd2, 0xc4, 0xb4, 0x6e, 0x37, 0xb7, 0x58, 0x41, 0xc9, 0x9d, 0xee,
+	0x14, 0x5b, 0xcd, 0xc9, 0x94, 0xdc, 0xe2, 0x90, 0xb9, 0x2c, 0x6d, 0x62,
+	0x87, 0xfc, 0xeb, 0x66, 0x33, 0x19, 0xff, 0x32, 0xe5, 0x8a, 0x71, 0xa4,
+	0x67, 0xbc, 0x2e, 0x92, 0x2c, 0x05, 0x25, 0x19, 0x7f, 0xab, 0xe9, 0x3e,
+	0x13, 0xc4, 0x98, 0x81, 0x9e, 0xb1, 0x52, 0xb3, 0x99, 0x8e, 0x83, 0x7e,
+	0xdc, 0x7f, 0xb6, 0x4d, 0xca, 0x21, 0xbb, 0x3c, 0x1b, 0xff, 0x6f, 0xba,
+	0xab, 0x13, 0xce, 0x91, 0xd7, 0xb6, 0xe8, 0x56, 0x5e, 0x72, 0x21, 0x29,
+	0x17, 0xe2, 0x9f, 0x92, 0x13, 0xf1, 0x30, 0xe6, 0x17, 0x94, 0x63, 0x71,
+	0xc8, 0xd1, 0x3a, 0xac, 0x25, 0xeb, 0xd1, 0x48, 0x56, 0x9e, 0x97, 0xe4,
+	0x62, 0xbf, 0x99, 0x16, 0x8c, 0x6d, 0x35, 0x3f, 0x9a, 0x8c, 0x63, 0xbc,
+	0xe1, 0xff, 0xd5, 0xb4, 0x43, 0xd1, 0x6c, 0x59, 0x06, 0xa5, 0x50, 0xea,
+	0x8f, 0xff, 0x4c, 0x34, 0x09, 0x5a, 0x62, 0x4f, 0x59, 0x26, 0xe4, 0x16,
+	0x1d, 0x4c, 0x19, 0x4d, 0xd9, 0x83, 0xf1, 0x93, 0x16, 0xee, 0xd7, 0x65,
+	0xb3, 0x6e, 0xb5, 0x4b, 0xc1, 0x94, 0x50, 0x97, 0x3c, 0x22, 0x85, 0xd3,
+	0x68, 0x8f, 0xdb, 0xbd, 0x3a, 0x9e, 0xc9, 0x8c, 0xb0, 0x4d, 0x34, 0x23,
+	0x11, 0x33, 0x53, 0xe0, 0xa8, 0xe2, 0x0c, 0x62, 0xfc, 0x98, 0xdd, 0xa9,
+	0x99, 0xb2, 0x62, 0x06, 0xa4, 0xea, 0xc4, 0xec, 0xb0, 0xd6, 0x2e, 0xc7,
+	0x62, 0x5d, 0x90, 0x69, 0x18, 0xb4, 0xe5, 0x9b, 0x7a, 0x22, 0x16, 0xce,
+	0x41, 0x51, 0x3a, 0x64, 0x35, 0x07, 0x7e, 0xe6, 0xe2, 0x59, 0x2d, 0x55,
+	0xff, 0x8a, 0x96, 0x3c, 0xbf, 0x5f, 0xdb, 0x75, 0x1e, 0x7d, 0xea, 0xe7,
+	0x3c, 0xbb, 0x0b, 0x83, 0x37, 0x1d, 0xcf, 0xb2, 0x1d, 0x3c, 0x2b, 0xde,
+	0xd1, 0x06, 0x5d, 0x36, 0x26, 0x43, 0x3d, 0x49, 0xa5, 0x4b, 0xf2, 0xa6,
+	0x4b, 0x6e, 0x42, 0x93, 0x5e, 0xcb, 0x96, 0xe0, 0x27, 0xa1, 0xcf, 0x45,
+	0xe8, 0x72, 0x31, 0x22, 0x47, 0x4a, 0x12, 0xd2, 0x85, 0x63, 0x65, 0xf5,
+	0xaa, 0x43, 0x7b, 0x80, 0x6e, 0xa1, 0xfb, 0x82, 0xc3, 0x67, 0xa1, 0xc3,
+	0x52, 0x1a, 0xf2, 0xc9, 0x60, 0xec, 0x7d, 0xda, 0x9e, 0xea, 0xa4, 0x96,
+	0x81, 0x9d, 0x14, 0x4e, 0x0f, 0x41, 0x77, 0xd1, 0xc8, 0x8a, 0x6c, 0x96,
+	0x82, 0x65, 0x45, 0xbe, 0x2c, 0xdd, 0x72, 0x6c, 0xd1, 0x92, 0x23, 0x8b,
+	0x21, 0xc9, 0x9b, 0x51, 0xb3, 0x26, 0x7d, 0xd9, 0x4d, 0x89, 0x1e, 0x79,
+	0xfe, 0x74, 0x34, 0x53, 0x96, 0x7e, 0xfb, 0x75, 0xdc, 0xcf, 0x9d, 0xa4,
+	0x4e, 0x25, 0x9f, 0x8a, 0x1b, 0x92, 0x85, 0x4d, 0x18, 0xd6, 0x1f, 0x81,
+	0xff, 0xe6, 0x73, 0xc9, 0x78, 0x34, 0x2c, 0xa2, 0x4b, 0xea, 0x0b, 0xfd,
+	0xe6, 0x6e, 0x89, 0x9a, 0x19, 0xca, 0x3f, 0x3e, 0x04, 0x3d, 0xfc, 0x77,
+	0xca, 0x1e, 0xb4, 0xa8, 0xe3, 0xa1, 0xf0, 0x31, 0xe8, 0x32, 0xab, 0x74,
+	0xdc, 0x83, 0xf1, 0x03, 0x9e, 0xed, 0xf4, 0x48, 0xbe, 0x7a, 0xc3, 0x93,
+	0x43, 0x8f, 0xcc, 0x57, 0xbb, 0xa5, 0x00, 0x1d, 0x16, 0xc4, 0x92, 0xc2,
+	0xf9, 0x3f, 0xf7, 0xda, 0x2d, 0x99, 0x3b, 0xff, 0x32, 0xec, 0xe1, 0xb0,
+	0xb6, 0xbf, 0xfe, 0x0b, 0xcd, 0xb3, 0x1f, 0xd8, 0x5f, 0x50, 0xec, 0x89,
+	0xa0, 0x9c, 0xab, 0xbb, 0xf6, 0x57, 0xc1, 0x1a, 0xb3, 0x4d, 0x1b, 0xb6,
+	0xf4, 0xc6, 0x6a, 0x9f, 0x73, 0xf5, 0x3e, 0x3c, 0x1b, 0x94, 0x23, 0x75,
+	0xf6, 0xcf, 0xc3, 0xc6, 0x82, 0xb2, 0xf4, 0x68, 0xb7, 0x64, 0xd1, 0x5e,
+	0x58, 0x14, 0x3b, 0x19, 0xd7, 0xf1, 0x4c, 0x0f, 0xe6, 0xb2, 0x15, 0x9f,
+	0x2e, 0x99, 0xaa, 0x76, 0xd8, 0x86, 0x15, 0x92, 0xa9, 0x3a, 0xf5, 0x8f,
+	0xef, 0x92, 0x6f, 0x03, 0x94, 0x2f, 0xdb, 0xf9, 0x1c, 0xdb, 0x4d, 0xb4,
+	0xb7, 0xb6, 0xd1, 0xb6, 0x37, 0x53, 0xa6, 0x83, 0x82, 0xb6, 0x5c, 0x29,
+	0x66, 0xee, 0xe7, 0x77, 0x9d, 0xf6, 0xd0, 0x6a, 0x0b, 0x01, 0xf4, 0x87,
+	0x1e, 0xab, 0x18, 0xeb, 0xf4, 0x9d, 0x66, 0xdb, 0x08, 0xae, 0x2d, 0x2c,
+	0xaa, 0x2e, 0x8e, 0x1d, 0x00, 0x5f, 0xba, 0x64, 0xab, 0x8a, 0xb7, 0x08,
+	0x6d, 0xc0, 0x9d, 0x47, 0x9f, 0xcc, 0x2e, 0x76, 0xf7, 0xa4, 0x17, 0xd9,
+	0x9e, 0x0c, 0x1b, 0x98, 0xe7, 0x54, 0x5c, 0x1a, 0x73, 0x71, 0xbd, 0x3f,
+	0x00, 0xbe, 0xa6, 0xb1, 0xe0, 0x30, 0x0f, 0x8f, 0xc7, 0x06, 0xee, 0xf7,
+	0xca, 0xd4, 0x79, 0xf6, 0xe5, 0x18, 0x85, 0x2d, 0xba, 0x24, 0xc0, 0x1b,
+	0x3e, 0x56, 0x14, 0xf7, 0x3b, 0x31, 0x4e, 0x37, 0x6c, 0x27, 0x83, 0x31,
+	0x9b, 0x8f, 0x27, 0xe3, 0xbd, 0x92, 0x5d, 0xed, 0x2b, 0xb0, 0x3b, 0xf6,
+	0x1f, 0x5c, 0xd7, 0x17, 0xf2, 0x3d, 0x0f, 0x9a, 0x8b, 0x9d, 0x90, 0x21,
+	0xdb, 0x75, 0xf0, 0xdc, 0x01, 0x1e, 0x82, 0x98, 0x4f, 0x3f, 0xd6, 0x43,
+	0x07, 0xe8, 0x6f, 0xc2, 0x9c, 0x3a, 0x65, 0xfa, 0x74, 0x2f, 0x74, 0x61,
+	0xa2, 0x6f, 0x50, 0x9e, 0x2f, 0x45, 0x61, 0x03, 0xec, 0x0f, 0x1d, 0x2c,
+	0x46, 0xc3, 0x55, 0xb1, 0x65, 0x2e, 0xde, 0x01, 0xfb, 0x6a, 0x36, 0x67,
+	0x60, 0x1f, 0xdf, 0x51, 0xfe, 0x62, 0xc8, 0x1c, 0xd3, 0x24, 0xdf, 0x91,
+	0x38, 0x0c, 0x7e, 0xa2, 0x4f, 0x89, 0xf0, 0x7a, 0x87, 0xc6, 0x35, 0x0b,
+	0x39, 0x72, 0x6c, 0xf8, 0xa4, 0xad, 0x90, 0x21, 0xfd, 0x56, 0x1f, 0xec,
+	0x39, 0xac, 0xfc, 0xc9, 0xd8, 0x86, 0xfe, 0x24, 0x3a, 0x51, 0xc6, 0x58,
+	0x85, 0xf3, 0x01, 0xfa, 0xb0, 0x51, 0x2c, 0x57, 0x79, 0x00, 0x6b, 0x6f,
+	0x56, 0xd9, 0xc7, 0x09, 0xce, 0xb7, 0xf9, 0xf9, 0x38, 0xf9, 0xe2, 0x7c,
+	0x6d, 0x3c, 0x4b, 0x1b, 0x8c, 0x1e, 0xb6, 0xd5, 0xf8, 0x27, 0xbc, 0xf1,
+	0x5d, 0xde, 0x0b, 0xa5, 0x1e, 0x2d, 0xa5, 0x78, 0xf0, 0xe9, 0x88, 0x2c,
+	0x9f, 0xec, 0x37, 0xf7, 0xc0, 0x86, 0xe9, 0xa7, 0x96, 0x2f, 0x50, 0xc7,
+	0xa0, 0x31, 0x42, 0x1d, 0x9b, 0x8a, 0xbf, 0xe4, 0x22, 0xd7, 0x9e, 0xf4,
+	0x19, 0x42, 0x1f, 0x01, 0x9f, 0x8b, 0xb5, 0x38, 0xeb, 0xad, 0xc5, 0x9c,
+	0x43, 0xfb, 0x7b, 0x06, 0xcf, 0xea, 0x32, 0x16, 0xa3, 0x7f, 0x78, 0x5e,
+	0x52, 0xf0, 0x91, 0xd0, 0xa3, 0x54, 0x31, 0x97, 0x4a, 0xa9, 0xd5, 0x6f,
+	0xc1, 0xb6, 0x86, 0xff, 0xae, 0xe9, 0xfa, 0x43, 0xfa, 0x06, 0xfa, 0x9a,
+	0x82, 0xa9, 0x43, 0x72, 0x3a, 0x9c, 0x21, 0x74, 0x13, 0x4f, 0x1a, 0xd1,
+	0x4c, 0x16, 0x7c, 0x4d, 0x59, 0x4d, 0xb1, 0x1e, 0x13, 0x44, 0x0c, 0xf4,
+	0xa9, 0xcb, 0x4e, 0xdf, 0x3f, 0x2d, 0x3b, 0xbe, 0x2e, 0xa8, 0x57, 0xea,
+	0xc1, 0xf7, 0x11, 0x01, 0xb9, 0x0c, 0xdf, 0x35, 0x57, 0xea, 0x96, 0x06,
+	0x78, 0xba, 0xe2, 0xf8, 0xb6, 0x66, 0x78, 0xb6, 0xc6, 0x67, 0xba, 0xf1,
+	0x7c, 0x00, 0x7e, 0x4d, 0xf2, 0x46, 0x02, 0xbf, 0x8b, 0xa4, 0xc9, 0x36,
+	0xdf, 0xce, 0xb9, 0x66, 0xa2, 0x76, 0x59, 0xda, 0x25, 0x13, 0x43, 0xfc,
+	0x58, 0xd4, 0x31, 0x56, 0x1f, 0x7c, 0x79, 0x40, 0x0e, 0x96, 0x42, 0xf2,
+	0xd5, 0x12, 0xe7, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xb1, 0x09, 0x9d,
+	0x8f, 0xc3, 0xe7, 0x65, 0xb4, 0x31, 0xf8, 0x9f, 0xdd, 0xd5, 0xaf, 0x68,
+	0xe9, 0xf3, 0x59, 0x6d, 0xbc, 0xbe, 0x5f, 0xcb, 0x9c, 0x9f, 0xd4, 0x76,
+	0xb5, 0xf8, 0x22, 0xd1, 0xde, 0xdd, 0x17, 0x9d, 0x38, 0xcd, 0x31, 0xfb,
+	0xe3, 0x1b, 0xfb, 0xa2, 0x5f, 0x6a, 0xad, 0xbe, 0xa8, 0x1f, 0xbe, 0x28,
+	0x03, 0x5f, 0x34, 0x7e, 0xdf, 0xbe, 0xa8, 0x5d, 0xdf, 0xd8, 0x17, 0x75,
+	0xeb, 0x77, 0x7d, 0x11, 0x63, 0xcf, 0xbf, 0xc6, 0xb5, 0x29, 0xdb, 0x76,
+	0xfa, 0x72, 0x0e, 0xc3, 0x0f, 0x6f, 0x82, 0xac, 0xbb, 0xb8, 0x76, 0x22,
+	0x05, 0xd8, 0xfd, 0x34, 0xc6, 0xfa, 0x4d, 0xd8, 0xfb, 0xb6, 0x98, 0x65,
+	0x3e, 0xa1, 0xc6, 0x7d, 0xa7, 0xce, 0xc7, 0x56, 0x75, 0x4e, 0x1e, 0xdf,
+	0x53, 0xe7, 0xb6, 0xab, 0x73, 0xea, 0xba, 0x53, 0x66, 0xd4, 0xb8, 0x4d,
+	0x09, 0x3c, 0x26, 0xf0, 0x2a, 0xf2, 0x59, 0x23, 0x11, 0x05, 0x3d, 0x1d,
+	0xe3, 0x53, 0x5f, 0x31, 0xf0, 0x20, 0xd0, 0x6f, 0xb7, 0xf2, 0x45, 0xbb,
+	0xa0, 0xf7, 0x65, 0xe7, 0xfe, 0x74, 0x95, 0x69, 0xd1, 0xd5, 0x9e, 0x35,
+	0xba, 0xea, 0x90, 0xe1, 0x98, 0xaf, 0xa3, 0xcd, 0x92, 0x8c, 0x51, 0x67,
+	0xf7, 0xa3, 0xab, 0x7f, 0xaa, 0xff, 0xfd, 0xe8, 0xea, 0xb7, 0xee, 0xa1,
+	0xab, 0x7f, 0xb5, 0x4e, 0x57, 0x96, 0xf9, 0x82, 0x46, 0xda, 0x8c, 0x1f,
+	0xf4, 0x47, 0xcd, 0x8f, 0x4e, 0x31, 0x7f, 0xa8, 0x73, 0x4d, 0xfb, 0x79,
+	0x07, 0xd7, 0xf3, 0xa5, 0xa6, 0x61, 0x59, 0x90, 0x1d, 0xd7, 0x34, 0xe5,
+	0x16, 0x35, 0x3f, 0x4f, 0xfe, 0x11, 0x3b, 0xa6, 0x10, 0x6b, 0x5c, 0x1e,
+	0xda, 0xa5, 0xbc, 0xc5, 0xed, 0x3f, 0x55, 0x6a, 0xfe, 0x42, 0x4f, 0xbc,
+	0xdd, 0x4c, 0x8e, 0x58, 0x5e, 0x1c, 0x08, 0xca, 0xd7, 0xaa, 0xd1, 0xac,
+	0xad, 0x75, 0x4b, 0xfe, 0x41, 0xc4, 0x9e, 0x12, 0xfd, 0xd7, 0xd6, 0x7b,
+	0xc4, 0xe8, 0x3e, 0x2f, 0x46, 0x57, 0xc1, 0x2b, 0xf3, 0xab, 0xef, 0xbe,
+	0xd5, 0x08, 0xf1, 0x3b, 0x66, 0xee, 0x93, 0x2f, 0x73, 0x8e, 0x88, 0xf7,
+	0x8c, 0xfb, 0x16, 0x73, 0x9e, 0x7c, 0x20, 0xd1, 0x25, 0xf9, 0x2d, 0x5c,
+	0x8f, 0xf4, 0x73, 0xf4, 0x5d, 0xed, 0x1e, 0xdf, 0x7e, 0x8e, 0xa4, 0x78,
+	0x33, 0x30, 0x65, 0xf4, 0x41, 0x3e, 0x54, 0xe2, 0x3c, 0xde, 0xf2, 0xec,
+	0x89, 0xb9, 0x82, 0xb4, 0xb9, 0xbe, 0x61, 0x2f, 0x72, 0x01, 0xda, 0x81,
+	0xaf, 0x73, 0xea, 0x9b, 0x39, 0x82, 0x44, 0x74, 0x8b, 0x39, 0x82, 0x98,
+	0x46, 0x62, 0x9f, 0x66, 0x43, 0xf7, 0x36, 0x74, 0x6f, 0x43, 0xf7, 0x36,
+	0x74, 0x9f, 0xac, 0x1f, 0xc6, 0x3d, 0x95, 0x87, 0x80, 0x17, 0x97, 0x7e,
+	0xda, 0xa5, 0x0f, 0x3e, 0xb7, 0x4a, 0x4e, 0xe9, 0x84, 0xf3, 0x45, 0xae,
+	0xa1, 0xfc, 0xf5, 0xb8, 0xe6, 0xfa, 0x6b, 0xd2, 0xcb, 0xe0, 0xf9, 0xdb,
+	0x98, 0xa7, 0xad, 0xeb, 0xd6, 0x5d, 0x99, 0xcc, 0xb5, 0xc8, 0x64, 0xd6,
+	0xa1, 0x8c, 0xd8, 0x9f, 0x3e, 0x77, 0x5a, 0xaf, 0xac, 0xca, 0x65, 0x2f,
+	0x78, 0xe8, 0xe0, 0xdc, 0xbd, 0x79, 0x90, 0x7e, 0xaf, 0x47, 0xff, 0x6f,
+	0xd1, 0x87, 0xfe, 0x75, 0xa3, 0x71, 0x39, 0x26, 0x73, 0xc6, 0x77, 0x9b,
+	0x0f, 0x72, 0x66, 0xac, 0x81, 0xef, 0x21, 0x96, 0x5f, 0x44, 0x2c, 0x59,
+	0x31, 0x22, 0xf2, 0x93, 0x47, 0xaf, 0x21, 0x97, 0x96, 0xfc, 0xc3, 0x89,
+	0x66, 0x24, 0x90, 0x78, 0xab, 0x39, 0x37, 0x82, 0x18, 0x97, 0x88, 0x86,
+	0x93, 0xc6, 0xb0, 0x5c, 0xaa, 0x0f, 0xca, 0x8f, 0xea, 0x96, 0xfc, 0xb0,
+	0x1e, 0x91, 0x1f, 0x20, 0xe6, 0x7f, 0xbf, 0xde, 0x9a, 0x73, 0x47, 0x68,
+	0x4f, 0x3d, 0xe9, 0xfa, 0x46, 0xb9, 0x7f, 0x13, 0x34, 0xde, 0x82, 0x9d,
+	0x04, 0xb2, 0xc8, 0xf5, 0x19, 0xbf, 0x26, 0x0e, 0x15, 0x9f, 0x6b, 0x82,
+	0xb7, 0x6c, 0x5b, 0xc2, 0xca, 0xeb, 0x7a, 0xf7, 0xa8, 0xf9, 0x29, 0xb4,
+	0x39, 0xa3, 0x81, 0x6a, 0xb1, 0x53, 0xe5, 0x8b, 0xd0, 0x91, 0xd8, 0xf5,
+	0x60, 0xb0, 0x56, 0xbc, 0x85, 0x7e, 0xcd, 0xe6, 0xa1, 0xf8, 0x6f, 0xed,
+	0x30, 0xff, 0x81, 0x85, 0x35, 0xdd, 0xf9, 0x25, 0x23, 0xb1, 0x49, 0x66,
+	0x43, 0xdf, 0x6f, 0x98, 0x03, 0x7d, 0x59, 0x3d, 0x11, 0x94, 0x74, 0x91,
+	0x6b, 0x2a, 0x24, 0xb3, 0x55, 0x28, 0xff, 0x3c, 0xd7, 0x85, 0x3c, 0x3b,
+	0x17, 0xef, 0x86, 0xed, 0xff, 0x9a, 0xe1, 0xae, 0x03, 0x18, 0x50, 0x75,
+	0x50, 0xf2, 0xe0, 0x37, 0x5f, 0x7f, 0xcb, 0xc3, 0x0e, 0xf0, 0x2a, 0x5b,
+	0x21, 0xf8, 0xc4, 0x70, 0xda, 0x76, 0xfe, 0x30, 0x88, 0xb6, 0xe0, 0x56,
+	0xeb, 0xce, 0x26, 0x7c, 0x3f, 0x10, 0xb2, 0x88, 0x4d, 0x24, 0xf3, 0x05,
+	0x7c, 0xff, 0x4a, 0x42, 0x36, 0xf7, 0xe2, 0x7b, 0x4b, 0x02, 0x26, 0x99,
+	0x60, 0xcc, 0xd5, 0x5a, 0x62, 0xae, 0x68, 0x69, 0xc8, 0x6e, 0x0e, 0x73,
+	0x4f, 0x43, 0x9e, 0x5f, 0xac, 0x07, 0xb5, 0xd4, 0xe9, 0x47, 0xc0, 0x87,
+	0x9f, 0x3b, 0x23, 0x3f, 0x33, 0x97, 0xb7, 0x04, 0xe4, 0x16, 0x7c, 0x5c,
+	0x12, 0x7e, 0xcc, 0x46, 0x6e, 0xb1, 0x03, 0xcb, 0x35, 0xfa, 0x5f, 0xbf,
+	0x20, 0x5f, 0xf3, 0x78, 0x6b, 0x93, 0x05, 0x65, 0xa3, 0x6c, 0xcf, 0x67,
+	0xfe, 0xcd, 0xc0, 0xdd, 0xf6, 0x17, 0x57, 0xdb, 0xcb, 0x99, 0x7f, 0xb8,
+	0xda, 0xde, 0xdb, 0xe6, 0xf2, 0x3f, 0xaa, 0x4d, 0xd4, 0xf7, 0x78, 0x6d,
+	0xb7, 0xa1, 0xb3, 0x66, 0x93, 0xb9, 0x45, 0x01, 0xd8, 0x24, 0x1d, 0xa7,
+	0x2f, 0xbe, 0x1f, 0x5f, 0xbb, 0xc6, 0xcf, 0x9a, 0x49, 0x83, 0xb6, 0x10,
+	0x14, 0x97, 0x26, 0xef, 0x77, 0x20, 0x7f, 0xbf, 0x8d, 0xdf, 0x8c, 0xa3,
+	0x7e, 0x6e, 0xce, 0x3e, 0x7c, 0xfe, 0xcd, 0x7b, 0xd8, 0x4b, 0x08, 0xf6,
+	0xf2, 0xff, 0xab, 0x5d, 0x5c, 0xba, 0x1f, 0xbb, 0xc0, 0x9f, 0xb2, 0x0b,
+	0xd5, 0xff, 0xd2, 0xea, 0x5a, 0x09, 0x43, 0x3e, 0x8c, 0x07, 0x83, 0xd0,
+	0xf1, 0x66, 0x99, 0xb5, 0xc8, 0x8f, 0x15, 0xc9, 0xc1, 0x5f, 0x9e, 0x58,
+	0x17, 0xbb, 0xbb, 0x10, 0x0f, 0x8e, 0x9f, 0x8e, 0x8e, 0x32, 0x1e, 0xc4,
+	0xe0, 0x1b, 0x93, 0xef, 0x88, 0x07, 0x37, 0x8c, 0xd6, 0x78, 0x60, 0x20,
+	0x1e, 0xec, 0x7a, 0x97, 0x78, 0x70, 0xe2, 0x1d, 0xf1, 0x40, 0x83, 0x6c,
+	0x38, 0xbf, 0xbf, 0x35, 0xfc, 0x78, 0x50, 0x58, 0x13, 0x0f, 0x7c, 0x5d,
+	0x59, 0x0a, 0x0b, 0xdc, 0xd5, 0x5b, 0x97, 0xa7, 0x2b, 0x09, 0x06, 0x12,
+	0x8d, 0xcc, 0x9c, 0xf5, 0xb0, 0xb4, 0xc1, 0xe7, 0x5e, 0xaa, 0x8f, 0x40,
+	0x67, 0x97, 0x30, 0xf7, 0x68, 0x9c, 0x89, 0x65, 0x5b, 0x82, 0xeb, 0xe1,
+	0xcd, 0x08, 0x30, 0xe2, 0x6e, 0xe0, 0xbe, 0xdd, 0x67, 0xd5, 0xfa, 0x78,
+	0x33, 0xea, 0x61, 0xf7, 0x6d, 0xc0, 0xee, 0x78, 0x3e, 0x00, 0x4c, 0xc8,
+	0xf6, 0x2b, 0x66, 0x12, 0x7a, 0xaa, 0x3a, 0xf6, 0xee, 0x02, 0x3e, 0x73,
+	0xaa, 0xef, 0xad, 0x08, 0xfb, 0x76, 0x24, 0x12, 0xd1, 0x3f, 0xc3, 0x77,
+	0x7b, 0x22, 0xbc, 0xed, 0xaa, 0x45, 0xba, 0x87, 0xa2, 0x67, 0x15, 0x8d,
+	0x80, 0x14, 0xd4, 0xb3, 0x91, 0x6d, 0x7c, 0xf6, 0x18, 0x62, 0xf6, 0x51,
+	0xc7, 0x94, 0x23, 0x4e, 0x76, 0x77, 0x0e, 0x1f, 0x62, 0xd5, 0x4b, 0x25,
+	0xde, 0x1f, 0xc5, 0xfd, 0x80, 0x30, 0x97, 0xfc, 0x2a, 0xfa, 0x1c, 0x44,
+	0x9f, 0x19, 0xc7, 0xd7, 0x05, 0xef, 0x37, 0x32, 0x29, 0xdc, 0x9f, 0x29,
+	0x36, 0x32, 0xe9, 0x22, 0xf3, 0xd6, 0xa1, 0xf0, 0x11, 0xc8, 0x33, 0x8b,
+	0x5c, 0xcd, 0x96, 0xe8, 0x60, 0x5e, 0x9e, 0xee, 0x1c, 0x07, 0x4e, 0x3a,
+	0x87, 0x1c, 0xc2, 0x9e, 0x8c, 0xc6, 0xcb, 0xf2, 0xe1, 0xce, 0xe4, 0x69,
+	0xe4, 0x0b, 0xf1, 0xed, 0x90, 0x61, 0x23, 0xa3, 0xc7, 0x04, 0xb6, 0x1e,
+	0x87, 0x5f, 0x1e, 0xd1, 0x53, 0xc5, 0x7e, 0x73, 0x56, 0x1e, 0x95, 0x86,
+	0x19, 0x0d, 0x8f, 0xcb, 0x26, 0x49, 0x05, 0xd0, 0x6f, 0xf0, 0x43, 0x92,
+	0x0d, 0x53, 0xd6, 0x0f, 0xc2, 0xdf, 0x6b, 0xd2, 0x61, 0xb5, 0xc6, 0x9e,
+	0x5b, 0x10, 0x6f, 0x2e, 0x40, 0x9f, 0xdd, 0x61, 0x75, 0x7a, 0x3a, 0xd9,
+	0x24, 0xcb, 0xef, 0xe8, 0x77, 0xbb, 0xa5, 0x5f, 0x6b, 0xfb, 0xdb, 0x68,
+	0xdf, 0x84, 0x9c, 0xb3, 0x91, 0x09, 0xc4, 0x20, 0x7f, 0xcc, 0xa1, 0x0d,
+	0x76, 0x72, 0x15, 0xf3, 0x61, 0x1c, 0x2c, 0x94, 0x99, 0xf7, 0x18, 0x52,
+	0x36, 0x71, 0xcf, 0x69, 0x36, 0x2b, 0x16, 0xf8, 0xbd, 0x40, 0x9e, 0x83,
+	0x32, 0xee, 0x0c, 0x88, 0x5d, 0xa3, 0x1c, 0xa2, 0xf0, 0x4a, 0x0f, 0x77,
+	0xa5, 0x16, 0xa3, 0x76, 0x1e, 0x14, 0x8d, 0x0b, 0x7d, 0x5d, 0x49, 0xe4,
+	0x39, 0xfa, 0x85, 0x48, 0x57, 0x0a, 0x36, 0x6b, 0x5c, 0x78, 0xa8, 0x2b,
+	0x7d, 0x9a, 0x7c, 0x19, 0xc8, 0x73, 0x3e, 0x0a, 0x9c, 0xdf, 0x94, 0xdf,
+	0x45, 0x2e, 0x5b, 0x18, 0x44, 0x0e, 0x80, 0xd5, 0xaf, 0x83, 0xef, 0xbc,
+	0x29, 0xc1, 0xae, 0xc4, 0xab, 0xe0, 0x6f, 0x18, 0xb2, 0xd9, 0x84, 0x3e,
+	0x06, 0xda, 0x07, 0x58, 0x13, 0x68, 0x69, 0xb7, 0xba, 0x10, 0x4f, 0x11,
+	0xbb, 0x24, 0x98, 0x1c, 0xe9, 0x06, 0xfd, 0x2b, 0x01, 0xe6, 0x82, 0xc1,
+	0xd8, 0x6a, 0xfb, 0x37, 0xdd, 0xf6, 0x41, 0xf0, 0xc2, 0xe7, 0x88, 0x09,
+	0x24, 0x38, 0x35, 0x62, 0x82, 0x07, 0xf6, 0x0d, 0xa9, 0xbe, 0xe9, 0x45,
+	0xda, 0x40, 0x23, 0x53, 0xb1, 0x1e, 0x91, 0xd4, 0xc2, 0x56, 0x19, 0x5f,
+	0xe8, 0x95, 0x5d, 0x0b, 0xc4, 0x30, 0xac, 0x69, 0x60, 0x2a, 0xc0, 0x18,
+	0xfa, 0x05, 0xe6, 0x76, 0xd1, 0xf0, 0x41, 0xe9, 0x0f, 0x7f, 0x15, 0xeb,
+	0x60, 0xca, 0x8a, 0x45, 0x66, 0xb1, 0xc6, 0x02, 0x8a, 0x4e, 0xd8, 0x1f,
+	0x93, 0x36, 0xba, 0x66, 0xdc, 0xf4, 0xe2, 0xbd, 0xe8, 0x62, 0xe1, 0x5c,
+	0x08, 0xaf, 0xa3, 0xfb, 0x57, 0x1e, 0x5d, 0x13, 0x74, 0xfb, 0x40, 0x93,
+	0x73, 0x7c, 0xa8, 0x73, 0xec, 0xb4, 0xd8, 0x1d, 0xe0, 0x2f, 0x1d, 0x7b,
+	0x58, 0x66, 0x41, 0xe7, 0xe8, 0x02, 0xfd, 0xa4, 0x6c, 0xc5, 0x67, 0xb8,
+	0x4d, 0x62, 0x83, 0xe7, 0x81, 0x73, 0xc6, 0x14, 0x0d, 0x17, 0x73, 0xe8,
+	0x17, 0x12, 0xc0, 0xa9, 0x1f, 0x07, 0x3f, 0xcc, 0xb1, 0x38, 0xe7, 0x00,
+	0xe6, 0x9b, 0xc0, 0x3a, 0x64, 0x7d, 0x85, 0xeb, 0x1b, 0xbf, 0xcf, 0x87,
+	0x3b, 0x53, 0xa7, 0xdb, 0xb1, 0xee, 0xe4, 0x11, 0x43, 0xc5, 0x7e, 0xea,
+	0xc5, 0xea, 0x4c, 0x96, 0x14, 0xdf, 0x9d, 0xa9, 0x12, 0x65, 0x14, 0xef,
+	0x4c, 0x97, 0x28, 0x23, 0x01, 0x3f, 0x71, 0xd8, 0x64, 0x40, 0x22, 0x5b,
+	0xa8, 0xc7, 0x43, 0xe8, 0xf7, 0x57, 0x01, 0xe2, 0xb8, 0xa4, 0xc5, 0xdf,
+	0xf0, 0xb5, 0x17, 0x0e, 0xa3, 0x2f, 0x7f, 0x6f, 0x07, 0xdd, 0xfe, 0xc1,
+	0x82, 0xb4, 0x0f, 0xce, 0xc0, 0x4f, 0xe8, 0x23, 0xc0, 0x91, 0xca, 0xce,
+	0x9b, 0xc0, 0xd8, 0x3b, 0x30, 0x1f, 0xac, 0x8d, 0x98, 0x25, 0xd3, 0xf3,
+	0x94, 0xab, 0x7c, 0x08, 0x73, 0xc0, 0xfc, 0x63, 0xf0, 0x2d, 0x9c, 0x03,
+	0xc7, 0x16, 0xe4, 0x36, 0x4b, 0x92, 0x9b, 0x0f, 0x2a, 0x2c, 0x6b, 0x9b,
+	0x1c, 0x5f, 0xd3, 0xf4, 0x44, 0x17, 0x74, 0xcc, 0xb9, 0xcd, 0x81, 0xb7,
+	0x67, 0x10, 0xff, 0xa2, 0x0a, 0x43, 0x19, 0x17, 0xb8, 0x56, 0x46, 0xb1,
+	0x4e, 0xc8, 0xbf, 0x67, 0x7b, 0x5a, 0x03, 0x3e, 0x45, 0xf9, 0x7f, 0xe4,
+	0xea, 0x09, 0xf8, 0x91, 0x51, 0xf9, 0x7d, 0xf8, 0x92, 0x1f, 0xd7, 0xe3,
+	0xc8, 0x1b, 0x86, 0x91, 0x37, 0x0c, 0x22, 0x6f, 0xb0, 0x90, 0x37, 0x44,
+	0x90, 0x37, 0xf4, 0x21, 0x6f, 0x08, 0x23, 0x3e, 0x88, 0x1c, 0xad, 0xe7,
+	0x61, 0x63, 0x0d, 0xf8, 0x41, 0x33, 0x68, 0xd7, 0x43, 0xc1, 0x64, 0x3d,
+	0x1c, 0x4c, 0xd5, 0x03, 0x98, 0xd3, 0x01, 0x8e, 0x89, 0xf9, 0xe5, 0x3b,
+	0xc7, 0x4a, 0xc3, 0x88, 0x39, 0x36, 0xfc, 0x52, 0x1a, 0xf1, 0x36, 0x2e,
+	0x47, 0xf0, 0xcc, 0xf2, 0x7c, 0x04, 0xcf, 0x34, 0x25, 0x1d, 0x6f, 0x93,
+	0x59, 0x33, 0x0e, 0x1a, 0x5b, 0x94, 0x9d, 0x22, 0xdf, 0x6a, 0x83, 0x9d,
+	0x4a, 0xae, 0xc8, 0x7c, 0xab, 0x0f, 0xf4, 0x3a, 0x11, 0x97, 0xe9, 0x1f,
+	0xe8, 0x0b, 0xec, 0xdd, 0x5f, 0xb2, 0xb8, 0xe6, 0xba, 0xb4, 0xe4, 0xe9,
+	0xbc, 0x10, 0x6b, 0x22, 0x0e, 0xc2, 0x2e, 0xd8, 0x36, 0x81, 0xe7, 0xf8,
+	0xfb, 0x6d, 0xcf, 0xef, 0x7f, 0x24, 0x28, 0x30, 0xde, 0x4b, 0x8c, 0xf9,
+	0x16, 0xe8, 0x39, 0xad, 0xeb, 0xb5, 0xa6, 0x8b, 0xe5, 0xdf, 0x67, 0xfd,
+	0x8d, 0x35, 0xc7, 0xd7, 0xc0, 0x73, 0xbf, 0xb9, 0x8c, 0x1c, 0xd9, 0xde,
+	0xbf, 0x82, 0xdf, 0xad, 0xfd, 0xeb, 0xe8, 0xaf, 0xda, 0x82, 0x66, 0x22,
+	0xce, 0x7c, 0x18, 0x3e, 0x73, 0x10, 0xfe, 0xf1, 0x56, 0x46, 0x5f, 0xba,
+	0x89, 0x79, 0x42, 0x9e, 0xc5, 0x5b, 0x99, 0xc0, 0xc0, 0xb5, 0xe6, 0x8b,
+	0xc0, 0x37, 0x63, 0x4b, 0x23, 0x92, 0x5a, 0xea, 0x0f, 0x5f, 0x96, 0xce,
+	0xdb, 0xb6, 0x5c, 0x6b, 0xce, 0x3a, 0xd1, 0xe3, 0xb6, 0x10, 0x6f, 0x99,
+	0x52, 0x01, 0xa9, 0x6d, 0x3b, 0x3b, 0x88, 0x19, 0x2f, 0x8a, 0x1e, 0x91,
+	0xe4, 0x29, 0x5b, 0x46, 0x76, 0xfa, 0xb9, 0xfb, 0x9d, 0x0e, 0xe9, 0x42,
+	0xdb, 0x52, 0x04, 0x7d, 0x88, 0x53, 0x39, 0xef, 0x2c, 0xe6, 0xac, 0xb9,
+	0xcf, 0x78, 0xf5, 0xc9, 0x42, 0x09, 0x73, 0xaf, 0xdf, 0xca, 0x5c, 0x3e,
+	0x05, 0xec, 0x0e, 0x1d, 0x25, 0x4f, 0xb1, 0xae, 0xb0, 0x09, 0x72, 0x1a,
+	0x83, 0xad, 0xd0, 0x06, 0xfa, 0xf1, 0x6c, 0x53, 0xbe, 0x11, 0xa7, 0x5d,
+	0xbc, 0x04, 0x59, 0x82, 0x56, 0xc0, 0x9f, 0x0f, 0x70, 0xde, 0x3c, 0xe5,
+	0x17, 0x46, 0x6e, 0xce, 0xb1, 0x25, 0xd8, 0x99, 0x58, 0x9f, 0x77, 0xdf,
+	0xca, 0x2c, 0x9f, 0x02, 0xfd, 0x01, 0xd6, 0xde, 0xe0, 0xb3, 0x8b, 0xac,
+	0x1d, 0x32, 0x27, 0xdd, 0x05, 0x3d, 0xed, 0x55, 0xb5, 0xb8, 0x64, 0x35,
+	0x2e, 0xd6, 0x49, 0xfa, 0x2c, 0x89, 0x18, 0xd6, 0x7e, 0xe4, 0xaf, 0x62,
+	0xea, 0x89, 0x49, 0xdc, 0xa3, 0x3c, 0x35, 0xe4, 0x1c, 0xb8, 0x7f, 0x61,
+	0x45, 0xe9, 0xc4, 0x80, 0xee, 0x72, 0x3b, 0x99, 0x84, 0xc9, 0xbc, 0x91,
+	0x80, 0x2f, 0x1c, 0xe1, 0x1c, 0xd4, 0xd8, 0xc8, 0xc7, 0xb9, 0xfe, 0x30,
+	0x67, 0xd8, 0x55, 0x4b, 0x5e, 0xae, 0xfe, 0x66, 0x4b, 0x47, 0x60, 0xd3,
+	0x92, 0x6f, 0x43, 0x3e, 0x90, 0x1c, 0xc1, 0x6f, 0x38, 0x81, 0xa3, 0xd0,
+	0xe7, 0xd9, 0x11, 0xd6, 0x3f, 0x5f, 0x02, 0xb6, 0x27, 0xdf, 0xb1, 0xc8,
+	0x11, 0xb5, 0x86, 0x71, 0xed, 0x30, 0x97, 0xdb, 0x24, 0x97, 0xd5, 0xfc,
+	0x1e, 0x22, 0xf6, 0x80, 0x9e, 0xee, 0x67, 0x7e, 0xe3, 0xf7, 0x39, 0x3f,
+	0x97, 0x3e, 0x63, 0x57, 0xd2, 0x8a, 0x48, 0xaa, 0x78, 0xa9, 0x19, 0xb0,
+	0x2c, 0x60, 0x67, 0x57, 0x8f, 0x29, 0x27, 0x08, 0x3e, 0x58, 0x6b, 0xdb,
+	0xa9, 0x74, 0x09, 0x3e, 0x68, 0x3b, 0xf9, 0x60, 0x62, 0xb3, 0x9c, 0x9b,
+	0xef, 0x91, 0xca, 0xfc, 0xcf, 0xa5, 0x3a, 0xdf, 0x25, 0xe7, 0xe7, 0x9b,
+	0x72, 0x35, 0xae, 0x7c, 0x93, 0xd5, 0xae, 0xd6, 0xb5, 0x3c, 0xec, 0xd6,
+	0x61, 0x62, 0xa3, 0xd7, 0xe5, 0x79, 0x39, 0x57, 0x76, 0x79, 0xcf, 0xb4,
+	0xf0, 0x7e, 0x15, 0xb6, 0xf6, 0xaa, 0x45, 0xfe, 0x47, 0xa4, 0x52, 0x24,
+	0xef, 0xfb, 0x14, 0xef, 0xbb, 0x56, 0x79, 0x97, 0xac, 0x61, 0x91, 0xff,
+	0x8d, 0x78, 0xef, 0x90, 0xec, 0x56, 0xf2, 0x1f, 0xc1, 0xb3, 0xef, 0xb4,
+	0xbf, 0x8a, 0x73, 0xad, 0xb9, 0x5c, 0x6c, 0x53, 0x3c, 0x1b, 0x89, 0x11,
+	0xc8, 0xe7, 0x5a, 0xb3, 0xe1, 0x70, 0x1d, 0xe1, 0xb7, 0xf3, 0x2f, 0xe0,
+	0xab, 0x7a, 0x55, 0xce, 0x92, 0x9b, 0xec, 0xee, 0x4c, 0x2e, 0x8e, 0x42,
+	0xb7, 0x9d, 0x6a, 0x1d, 0xc2, 0x6d, 0x40, 0x67, 0xff, 0x1e, 0xfd, 0xbf,
+	0xcd, 0xf5, 0xa6, 0xe4, 0x92, 0x86, 0x5c, 0x0a, 0xc5, 0xf1, 0x76, 0xe0,
+	0x27, 0x8c, 0xd3, 0xc8, 0x64, 0x1d, 0x3e, 0xd3, 0x07, 0xdf, 0xc6, 0xef,
+	0xf7, 0x6d, 0x0f, 0x79, 0xf8, 0x5c, 0xe8, 0x1c, 0x79, 0x05, 0xd7, 0xf3,
+	0x48, 0x03, 0x31, 0x36, 0x36, 0x58, 0x51, 0xfb, 0x10, 0x71, 0x85, 0x85,
+	0x67, 0x9d, 0x6f, 0xe3, 0xe3, 0x8e, 0x37, 0x56, 0xe7, 0x98, 0x6b, 0xe7,
+	0x54, 0x70, 0x1a, 0xc8, 0xdf, 0x2d, 0xd0, 0xe5, 0xb8, 0x79, 0x31, 0x12,
+	0x06, 0xc6, 0x65, 0x5b, 0x37, 0x7c, 0x4c, 0x04, 0x3e, 0x6b, 0x18, 0xbe,
+	0x9f, 0x6b, 0x99, 0x7e, 0xde, 0xe7, 0x7d, 0x18, 0x34, 0xe9, 0x7f, 0x87,
+	0x31, 0x67, 0xe6, 0xd8, 0xf4, 0x9f, 0x88, 0x27, 0xb5, 0x70, 0x57, 0xf2,
+	0xb4, 0x5b, 0x1b, 0x74, 0x7f, 0xf3, 0xbe, 0x04, 0x1f, 0x49, 0x44, 0xcb,
+	0x79, 0xe4, 0x7e, 0x29, 0xac, 0xd1, 0xa4, 0x85, 0x3c, 0xbb, 0x16, 0x7d,
+	0x85, 0x98, 0x5b, 0xa7, 0x0c, 0x96, 0x28, 0x27, 0xd6, 0xa9, 0x4c, 0xc9,
+	0x57, 0xbe, 0x0b, 0x79, 0x04, 0x65, 0x8b, 0x95, 0x85, 0x4f, 0x01, 0xff,
+	0x98, 0xfb, 0x5c, 0x89, 0xb5, 0xc8, 0x7e, 0xc4, 0x31, 0x03, 0x42, 0x40,
+	0x4e, 0xb5, 0x64, 0xc8, 0x67, 0x03, 0x43, 0xc8, 0x01, 0x9f, 0x45, 0xdf,
+	0x80, 0xe4, 0x97, 0x18, 0x0f, 0x02, 0x32, 0xb7, 0x24, 0x72, 0xfd, 0x14,
+	0xfd, 0x8a, 0xfa, 0x83, 0xcc, 0x1b, 0x99, 0x69, 0x62, 0xed, 0x79, 0xfa,
+	0x18, 0xfa, 0x89, 0x07, 0xa1, 0x8b, 0xd8, 0x4b, 0xdf, 0x40, 0x6c, 0x9a,
+	0x2d, 0xf6, 0xc3, 0x67, 0x4a, 0x43, 0x87, 0x4c, 0x11, 0xd3, 0x98, 0xa3,
+	0x6f, 0x50, 0x77, 0xf4, 0x6b, 0x8e, 0x41, 0x29, 0x9c, 0x62, 0xbd, 0x31,
+	0x08, 0x5e, 0x98, 0xb7, 0x1a, 0x2a, 0x0f, 0x7a, 0x50, 0xf9, 0x56, 0x7e,
+	0x07, 0x5a, 0xc6, 0x8d, 0x1d, 0xdf, 0xa6, 0xd3, 0x8f, 0x3d, 0x22, 0xf6,
+	0xc4, 0xa1, 0xce, 0x5d, 0xa5, 0x76, 0x29, 0xf7, 0xd2, 0x2e, 0xa9, 0xff,
+	0xac, 0x4e, 0x5f, 0x8b, 0x3c, 0x0c, 0xf4, 0x58, 0x23, 0x08, 0xa0, 0x5f,
+	0xc8, 0xeb, 0x47, 0xb9, 0xfe, 0xb6, 0x4c, 0xed, 0xfc, 0x3b, 0xf0, 0xe5,
+	0xfa, 0xb5, 0xdc, 0x4e, 0xf8, 0xdb, 0x09, 0x5d, 0x1e, 0xfb, 0x54, 0x1a,
+	0xcf, 0x32, 0x16, 0xde, 0xf2, 0xf0, 0x38, 0xdb, 0x58, 0xa3, 0x45, 0x9e,
+	0x7e, 0xce, 0xc4, 0x77, 0xaf, 0xe4, 0xcf, 0x05, 0x21, 0x07, 0xe4, 0xc4,
+	0x15, 0x97, 0x16, 0xf3, 0xde, 0xe3, 0xd0, 0x91, 0x7e, 0x32, 0x28, 0x6d,
+	0x27, 0x7b, 0x25, 0xf0, 0xad, 0x2e, 0x69, 0xff, 0xd6, 0x80, 0x18, 0xdf,
+	0x62, 0x2d, 0x29, 0x1a, 0x39, 0xaa, 0xea, 0x58, 0x69, 0x39, 0x86, 0xf8,
+	0xa5, 0x23, 0x16, 0x2b, 0x3b, 0x35, 0xb7, 0x8a, 0x81, 0xc4, 0x55, 0x7f,
+	0xc1, 0x96, 0xaf, 0xef, 0xfc, 0x85, 0xaa, 0xa3, 0x26, 0x47, 0x70, 0xfd,
+	0x72, 0x06, 0xd8, 0x44, 0x83, 0xad, 0x34, 0x32, 0xd7, 0x1e, 0xf5, 0x73,
+	0xcb, 0x41, 0x55, 0x93, 0xff, 0xfa, 0x4e, 0x37, 0xb7, 0x9c, 0x45, 0x6e,
+	0x99, 0x56, 0xb9, 0x25, 0xfc, 0x6b, 0x80, 0xfd, 0xb6, 0x8a, 0x8e, 0xb1,
+	0x72, 0xc2, 0x5c, 0xfd, 0xa3, 0x62, 0x1f, 0xc0, 0xba, 0x38, 0x23, 0xf3,
+	0x7a, 0x42, 0x53, 0x34, 0x8d, 0x17, 0xe8, 0xa7, 0xe8, 0xbf, 0x68, 0xe3,
+	0xac, 0x69, 0xa1, 0xed, 0x65, 0xfa, 0x28, 0xd7, 0xb6, 0xc7, 0x5a, 0x7c,
+	0xdd, 0x5c, 0xa9, 0x0e, 0x1d, 0x22, 0xa7, 0xb7, 0xda, 0x30, 0x7f, 0xc4,
+	0x74, 0x8b, 0xd7, 0x9c, 0x3f, 0x7c, 0x67, 0x28, 0xa4, 0xae, 0x0b, 0x65,
+	0xb7, 0x86, 0xe1, 0xd2, 0x67, 0xfe, 0x01, 0x1f, 0x53, 0x27, 0x1f, 0x1c,
+	0xb7, 0x4f, 0x8c, 0x33, 0x21, 0x09, 0x9c, 0xa1, 0xfd, 0x45, 0x23, 0x69,
+	0xc8, 0x6f, 0xce, 0x22, 0x06, 0x3c, 0x04, 0x6c, 0xf4, 0x88, 0xe8, 0xe7,
+	0x06, 0xb1, 0x76, 0xa2, 0xe1, 0xb2, 0xc4, 0xc4, 0xa8, 0x04, 0xe5, 0x8d,
+	0x53, 0xd1, 0x08, 0xed, 0xe5, 0x2c, 0xe2, 0xd5, 0x91, 0x7a, 0xe7, 0xed,
+	0x86, 0xe2, 0x82, 0x6d, 0xdf, 0x08, 0x00, 0x3b, 0x0c, 0xda, 0x7a, 0xb7,
+	0xdc, 0x80, 0xbe, 0xb3, 0xaa, 0xed, 0x11, 0xd0, 0x05, 0x0f, 0x67, 0x58,
+	0x1b, 0x24, 0xdd, 0xa3, 0xa0, 0x49, 0xda, 0x8d, 0xcc, 0x32, 0x73, 0xd3,
+	0x53, 0xb4, 0xdd, 0x5e, 0xd8, 0x1d, 0xae, 0xeb, 0xed, 0x92, 0x9d, 0x8c,
+	0x88, 0x7e, 0x6a, 0x8f, 0xf4, 0xef, 0xd4, 0xdd, 0xf9, 0xa8, 0x39, 0xb2,
+	0x8d, 0x35, 0xe7, 0x11, 0xb5, 0x1e, 0xf5, 0x25, 0xd8, 0xcc, 0x3e, 0xea,
+	0x18, 0xb1, 0x1f, 0x71, 0x8c, 0x7e, 0xcc, 0x40, 0x1c, 0x4b, 0xd5, 0x5d,
+	0xbd, 0x97, 0xf7, 0x6d, 0x95, 0x63, 0x67, 0x68, 0x4f, 0xb8, 0xb7, 0x6a,
+	0x53, 0xfe, 0xde, 0x10, 0xef, 0x59, 0x72, 0xfc, 0x45, 0xe6, 0x1e, 0xcc,
+	0x39, 0x98, 0x67, 0x45, 0xc3, 0xbb, 0x30, 0x1f, 0xfd, 0x31, 0xfa, 0x03,
+	0x5d, 0xd9, 0x6e, 0x0e, 0x3e, 0xba, 0x50, 0xa7, 0xde, 0x86, 0xb9, 0x7f,
+	0x66, 0x32, 0x5f, 0xb3, 0xc3, 0xae, 0xbc, 0x0b, 0x68, 0x9b, 0x85, 0xef,
+	0x4f, 0x39, 0x6d, 0xb2, 0x32, 0x69, 0x43, 0xf7, 0x5f, 0x02, 0x5f, 0x07,
+	0x3a, 0x59, 0x23, 0x58, 0x99, 0x4c, 0xe3, 0xfa, 0x80, 0xca, 0xd1, 0x8c,
+	0xc7, 0x6c, 0xd0, 0xd8, 0xca, 0x75, 0xe4, 0xe9, 0x29, 0xae, 0x17, 0xe6,
+	0x1f, 0xd3, 0x67, 0xe1, 0xb3, 0xc7, 0xe3, 0x8c, 0xf1, 0xdc, 0x4b, 0xe8,
+	0x00, 0x1f, 0xdd, 0x0a, 0x57, 0xe8, 0xd6, 0x4e, 0xbd, 0x50, 0xa6, 0x9f,
+	0xcf, 0x87, 0xdb, 0x85, 0x78, 0xc4, 0xd4, 0x2b, 0x16, 0x75, 0xa2, 0xc9,
+	0x65, 0xb5, 0xef, 0x20, 0x92, 0x76, 0x0e, 0x61, 0xac, 0xb8, 0x5e, 0x2d,
+	0xef, 0xd4, 0xf3, 0x65, 0x43, 0x56, 0x42, 0xe4, 0x3b, 0xa2, 0xf2, 0xf8,
+	0x9d, 0xca, 0xd6, 0x8a, 0x88, 0x25, 0xb0, 0x99, 0xf8, 0x87, 0x31, 0xae,
+	0x6a, 0x83, 0x4d, 0x51, 0xf7, 0xd4, 0xbb, 0xf2, 0x91, 0x9e, 0xee, 0x37,
+	0x8a, 0x99, 0x45, 0xf8, 0x5f, 0xd6, 0x2f, 0x3a, 0xbc, 0x5a, 0xe3, 0x4b,
+	0x5e, 0x3e, 0xf4, 0x8c, 0x30, 0x4f, 0x99, 0x2b, 0x91, 0x97, 0x22, 0xfc,
+	0xe1, 0x46, 0xb6, 0x44, 0x39, 0xba, 0x3e, 0xe5, 0x10, 0xec, 0x42, 0x5f,
+	0x32, 0x3d, 0x1b, 0xe0, 0xdf, 0x28, 0xee, 0x31, 0x06, 0xe0, 0xbb, 0xde,
+	0x86, 0xf5, 0xbe, 0x17, 0x32, 0xa2, 0x6e, 0xa0, 0xbf, 0x25, 0xee, 0xbb,
+	0x42, 0x7f, 0x4b, 0x57, 0xde, 0xb6, 0x7b, 0xe9, 0xf3, 0x46, 0xe4, 0x18,
+	0xfc, 0xe8, 0xd1, 0x45, 0xf2, 0x93, 0xf6, 0x70, 0xd9, 0x30, 0x64, 0x42,
+	0x1f, 0x3f, 0x2c, 0x6f, 0xd4, 0x7e, 0xa0, 0x70, 0xe0, 0xb6, 0x9d, 0x0d,
+	0x99, 0x86, 0x7f, 0x98, 0x71, 0x20, 0x7f, 0x33, 0x82, 0xf5, 0x19, 0x56,
+	0xfe, 0x71, 0xe6, 0xfd, 0xe5, 0x24, 0x01, 0x37, 0x66, 0x7f, 0xf6, 0x3e,
+	0x63, 0xf6, 0x03, 0xc0, 0x61, 0xef, 0x8b, 0xbe, 0xe1, 0xd2, 0xff, 0x33,
+	0xe8, 0xea, 0xd7, 0x55, 0xfd, 0x22, 0xb7, 0x73, 0x2b, 0x65, 0xfa, 0x5e,
+	0xcf, 0xe9, 0xee, 0x73, 0x9f, 0xbb, 0x4f, 0xbe, 0x4c, 0xa9, 0x01, 0x2b,
+	0xe4, 0x55, 0x1c, 0x65, 0xae, 0xd8, 0xe6, 0xe9, 0x6f, 0x10, 0x18, 0x9a,
+	0x74, 0x7d, 0xdf, 0xdb, 0x21, 0xf9, 0x5e, 0x3f, 0xff, 0x84, 0xcf, 0x5e,
+	0x6d, 0xf7, 0xf3, 0x59, 0x3e, 0xbf, 0x92, 0x41, 0xfe, 0x0c, 0x1b, 0x60,
+	0x2c, 0x60, 0x5b, 0x5c, 0xf9, 0xa1, 0x77, 0xe7, 0x9b, 0xf5, 0x0b, 0xf2,
+	0xbd, 0x5b, 0xf1, 0x9d, 0x56, 0x7c, 0xb3, 0x06, 0xb9, 0x5f, 0x4b, 0x9d,
+	0x67, 0x1d, 0xd2, 0xaf, 0x3b, 0x92, 0x1e, 0xb0, 0x01, 0xf4, 0xfd, 0x63,
+	0xd0, 0xfd, 0x11, 0xf4, 0xfa, 0xc3, 0x12, 0xb0, 0x41, 0x09, 0xd8, 0xa0,
+	0x04, 0x6c, 0x50, 0x02, 0x36, 0x28, 0x85, 0xbd, 0x3a, 0x8b, 0x4d, 0x6c,
+	0xff, 0x3e, 0x6d, 0xd7, 0xaf, 0x6d, 0xac, 0xb7, 0x4b, 0xb7, 0xb6, 0x99,
+	0xaa, 0xfb, 0x18, 0x39, 0xc8, 0x5a, 0x2b, 0xb0, 0x9a, 0x5f, 0xf7, 0xf0,
+	0x62, 0x44, 0x8d, 0xfb, 0x5e, 0x88, 0x11, 0x35, 0x1b, 0xeb, 0x66, 0x28,
+	0x6c, 0x00, 0x1b, 0x1a, 0x12, 0xc6, 0x6f, 0x13, 0xbe, 0x17, 0xb4, 0x86,
+	0xfb, 0xb1, 0x92, 0xda, 0x55, 0x5d, 0xef, 0x88, 0xaa, 0x3b, 0x58, 0x32,
+	0x5b, 0xf6, 0x73, 0xb7, 0x98, 0x8c, 0xcd, 0x13, 0x6f, 0xca, 0x16, 0x3d,
+	0x01, 0x1d, 0x38, 0xc4, 0x88, 0xdc, 0x27, 0xe4, 0xf8, 0xb1, 0xc1, 0x2a,
+	0xc6, 0x2c, 0x58, 0x2e, 0x7f, 0x47, 0x9c, 0xbb, 0xcf, 0xec, 0x82, 0x7f,
+	0xce, 0x14, 0x23, 0x32, 0x5e, 0x74, 0x31, 0x01, 0xf2, 0x9f, 0x75, 0xf5,
+	0xe5, 0x5b, 0xd0, 0xc3, 0xad, 0xcc, 0x94, 0xb5, 0x6a, 0x1b, 0x91, 0xcb,
+	0x71, 0xca, 0x98, 0xfa, 0xdf, 0xab, 0xf6, 0x29, 0x76, 0x55, 0xdd, 0xbd,
+	0xa4, 0x71, 0x65, 0x0b, 0x01, 0xfa, 0x19, 0xd0, 0x89, 0xbb, 0x6b, 0x18,
+	0x76, 0x91, 0x73, 0x7c, 0xb9, 0xb4, 0xe2, 0x91, 0x2f, 0x6a, 0x62, 0x6d,
+	0xd4, 0xfe, 0x1b, 0x2d, 0xed, 0xab, 0xf7, 0x3d, 0x7e, 0xe1, 0xfb, 0x56,
+	0x6b, 0x0d, 0xf4, 0x53, 0x77, 0xdb, 0x81, 0xdd, 0x24, 0xa0, 0xee, 0xc3,
+	0x87, 0xd7, 0x42, 0x92, 0xaa, 0x59, 0x92, 0x2e, 0xb3, 0x1f, 0xeb, 0x17,
+	0xf4, 0x47, 0x7f, 0x22, 0x29, 0xe4, 0xab, 0xd9, 0x50, 0x34, 0x6e, 0xcb,
+	0x7f, 0x96, 0xe5, 0x85, 0x7c, 0x84, 0xe7, 0x0a, 0xf2, 0x13, 0x1a, 0x9e,
+	0xfb, 0x19, 0xae, 0xc9, 0xb3, 0x25, 0x33, 0x45, 0xc6, 0x9d, 0xa1, 0x70,
+	0x0d, 0xf7, 0xb2, 0x93, 0xac, 0xd9, 0x7c, 0x07, 0x36, 0x19, 0x8d, 0x94,
+	0xa1, 0xef, 0x2b, 0x45, 0x8e, 0x07, 0x6c, 0x54, 0x64, 0x5d, 0xc7, 0xbf,
+	0xff, 0x27, 0xc0, 0x81, 0xf0, 0xd5, 0x21, 0xaf, 0x8f, 0x9a, 0xab, 0x6d,
+	0x06, 0x60, 0xe3, 0x0d, 0xcf, 0xdf, 0x56, 0x8a, 0x6e, 0x1d, 0xe5, 0x2c,
+	0xf9, 0x70, 0xfe, 0x77, 0xb3, 0x11, 0x42, 0x0e, 0xb4, 0x3a, 0xc7, 0xab,
+	0xa4, 0x6f, 0xc2, 0xdd, 0xca, 0x51, 0xc7, 0x97, 0x05, 0xef, 0xb3, 0x8d,
+	0x67, 0x27, 0x9a, 0xcd, 0xb3, 0xd6, 0x07, 0xad, 0x99, 0xf5, 0x6d, 0x4f,
+	0x5a, 0xf9, 0xdd, 0x15, 0x27, 0xef, 0xd5, 0xcc, 0xbe, 0xbd, 0xc3, 0xad,
+	0x99, 0xd5, 0x76, 0xac, 0xad, 0x99, 0x59, 0xdb, 0xdd, 0x9a, 0xd9, 0xfc,
+	0xee, 0x02, 0x3e, 0x6e, 0xcd, 0x2c, 0xbb, 0xdd, 0xad, 0x99, 0x95, 0xb7,
+	0xbb, 0x35, 0x33, 0x67, 0x87, 0x5b, 0x33, 0xfb, 0xf9, 0xf6, 0xb5, 0x35,
+	0xb3, 0x1f, 0xec, 0x58, 0x5b, 0x33, 0xbb, 0xb8, 0x3b, 0x87, 0xcf, 0xdd,
+	0x9a, 0xd9, 0xcf, 0x76, 0xdc, 0xbb, 0x66, 0xf6, 0x9a, 0x8f, 0xd7, 0x31,
+	0x9f, 0x11, 0xcc, 0x21, 0x0e, 0xbc, 0x3e, 0x0c, 0xbc, 0xfe, 0x6e, 0x75,
+	0xfe, 0x00, 0xe6, 0x39, 0xe8, 0xc5, 0x83, 0x0f, 0x82, 0xdb, 0x47, 0xbc,
+	0x67, 0x6d, 0xe4, 0xbb, 0x11, 0x2f, 0x57, 0x21, 0x76, 0xdf, 0xec, 0xe5,
+	0x6c, 0xff, 0xa8, 0xf3, 0xee, 0xb9, 0x97, 0xd6, 0xef, 0x0f, 0x21, 0xf5,
+	0xf6, 0xf1, 0x3c, 0xe7, 0x95, 0x47, 0xee, 0x47, 0x39, 0xd8, 0xe8, 0x3f,
+	0xbf, 0xfb, 0x1b, 0x16, 0x31, 0xfe, 0x73, 0x58, 0xab, 0xf6, 0x16, 0x43,
+	0x9d, 0x01, 0x60, 0x8c, 0x3a, 0x2e, 0x29, 0xf4, 0x4f, 0xa9, 0xfe, 0xd7,
+	0x5a, 0xfa, 0xaf, 0xa0, 0x3f, 0xe9, 0x46, 0xff, 0x1d, 0x3e, 0x2f, 0x29,
+	0xfb, 0xb6, 0x5c, 0x0c, 0x9f, 0x2e, 0xf9, 0x78, 0x2b, 0xe0, 0x61, 0xe7,
+	0x46, 0xc6, 0x76, 0x3e, 0x8f, 0x67, 0xa2, 0x17, 0x6d, 0xb9, 0xa9, 0xf0,
+	0xbb, 0x91, 0x88, 0x5e, 0xcc, 0xaa, 0x7c, 0xad, 0x91, 0xc9, 0x39, 0x7e,
+	0xfe, 0x8d, 0x1c, 0x6a, 0x80, 0x39, 0x0c, 0xec, 0x7d, 0x69, 0x10, 0x71,
+	0xac, 0x35, 0xc7, 0x66, 0x5e, 0xad, 0x7b, 0x79, 0xb5, 0x29, 0x9f, 0xd9,
+	0xd9, 0x8a, 0xcd, 0x2f, 0xee, 0xfe, 0xc7, 0x0a, 0x9b, 0x6f, 0x42, 0x6e,
+	0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7a, 0x01, 0xf3,
+	0x19, 0xc6, 0x46, 0xe6, 0x37, 0x21, 0x7c, 0x78, 0x26, 0xc9, 0xc7, 0xe8,
+	0xed, 0x9e, 0x7f, 0x67, 0x5e, 0xe4, 0x63, 0x95, 0xe4, 0x26, 0x37, 0x37,
+	0xda, 0xa4, 0xb9, 0xf9, 0x67, 0xc4, 0xeb, 0x13, 0x58, 0xc5, 0xc2, 0x81,
+	0x55, 0x2c, 0xbc, 0x66, 0x1f, 0x4b, 0xd4, 0xf9, 0x27, 0xb5, 0x1f, 0xc6,
+	0xfd, 0xb1, 0x46, 0xe6, 0xca, 0x80, 0x68, 0x7a, 0x82, 0xfb, 0x64, 0xc0,
+	0x3a, 0x16, 0xf7, 0xcd, 0xe8, 0x3b, 0xf7, 0x69, 0xa9, 0x2a, 0xe3, 0x0f,
+	0xf1, 0x91, 0xbf, 0x17, 0xee, 0xeb, 0x89, 0xb2, 0x63, 0xdb, 0x1f, 0x6b,
+	0xc8, 0x79, 0xe3, 0xed, 0xd6, 0x53, 0xe0, 0x25, 0x83, 0x6f, 0x5f, 0xa6,
+	0x9f, 0x55, 0xb1, 0xaf, 0x03, 0xb6, 0x7b, 0xa4, 0x44, 0xec, 0xba, 0x59,
+	0x6a, 0x1e, 0x7e, 0x3d, 0x37, 0xef, 0x62, 0xd7, 0xc0, 0x5a, 0xec, 0x1a,
+	0x5f, 0x16, 0x97, 0xc7, 0x5d, 0x1b, 0xf2, 0x48, 0xbc, 0x4a, 0xfe, 0x18,
+	0x77, 0xf6, 0xc2, 0xff, 0x35, 0x80, 0x69, 0x19, 0x73, 0x18, 0x6f, 0x22,
+	0xc0, 0xf6, 0xf7, 0xe2, 0x4f, 0xb5, 0x1d, 0xea, 0xb0, 0x82, 0xf8, 0x4c,
+	0xc3, 0x7f, 0x4c, 0xe0, 0x99, 0x8c, 0xcc, 0x9e, 0xfe, 0x1a, 0xe6, 0x36,
+	0x2d, 0x57, 0xe6, 0x27, 0xc1, 0xdf, 0x73, 0x32, 0x17, 0xcf, 0xc3, 0x8f,
+	0x70, 0xcf, 0x83, 0xb8, 0xad, 0xdf, 0xfb, 0x9e, 0xd6, 0xcf, 0x5a, 0x51,
+	0xe2, 0x46, 0xa9, 0x16, 0xe9, 0x83, 0xb9, 0x67, 0xc8, 0xbd, 0x61, 0xda,
+	0x0f, 0xeb, 0x27, 0xc8, 0x5d, 0x99, 0xc3, 0x9e, 0xe2, 0xf8, 0x6b, 0x75,
+	0xb2, 0xec, 0x10, 0x7f, 0x35, 0x32, 0x8d, 0x25, 0xe2, 0xc7, 0xf7, 0x8b,
+	0x25, 0xa9, 0x07, 0xe2, 0xc9, 0xfb, 0xc1, 0x91, 0xd1, 0x79, 0x60, 0xc8,
+	0x57, 0x1a, 0x7a, 0x2b, 0x8e, 0x74, 0x31, 0x64, 0x72, 0x29, 0x0b, 0x9a,
+	0x71, 0x85, 0x95, 0x91, 0xc7, 0xc1, 0xed, 0xf5, 0xe3, 0xd9, 0x7e, 0xe4,
+	0xe4, 0x2e, 0x66, 0x4c, 0x01, 0x33, 0xfe, 0x06, 0x30, 0xe3, 0xac, 0x74,
+	0x76, 0x11, 0x33, 0xda, 0x1e, 0x66, 0x4c, 0xc3, 0x9e, 0x73, 0x6b, 0xec,
+	0x59, 0x53, 0xb5, 0x28, 0xde, 0xcb, 0x01, 0xf3, 0xa5, 0x4e, 0x45, 0xef,
+	0x03, 0x27, 0x6a, 0x12, 0x52, 0xe7, 0x52, 0x02, 0x2d, 0x34, 0x7d, 0x3c,
+	0xb8, 0x4d, 0xe1, 0xbc, 0xdd, 0xa5, 0x4d, 0xc8, 0x51, 0x14, 0xee, 0xf3,
+	0xf6, 0x4b, 0x03, 0xeb, 0xf6, 0x90, 0x03, 0x2d, 0x7b, 0xc8, 0x77, 0xf1,
+	0x21, 0x9e, 0xf3, 0x6a, 0x7d, 0x6d, 0xf0, 0x05, 0xff, 0x13, 0x3c, 0x71,
+	0x7d, 0x71, 0x2d, 0x68, 0xee, 0x7a, 0x59, 0x83, 0x13, 0xff, 0x7a, 0x1d,
+	0x4e, 0x44, 0xec, 0x3a, 0x17, 0x92, 0x24, 0x30, 0xa2, 0xbd, 0x44, 0x5a,
+	0x5c, 0xd3, 0xc3, 0xd2, 0x8e, 0xf9, 0x75, 0x9c, 0xea, 0x05, 0x36, 0xea,
+	0x92, 0x20, 0x30, 0x52, 0x9b, 0xc2, 0x48, 0x03, 0xc4, 0x32, 0x83, 0x33,
+	0xc0, 0x36, 0xb5, 0x55, 0x9c, 0x14, 0x8d, 0xff, 0x01, 0xf4, 0xf2, 0x94,
+	0xf2, 0x3d, 0x69, 0x39, 0x01, 0x5f, 0xda, 0xbe, 0x04, 0x7c, 0x77, 0xce,
+	0xc5, 0x4f, 0x6d, 0xeb, 0xf0, 0xd3, 0xc1, 0x0d, 0xf1, 0x93, 0xaa, 0xdf,
+	0x8f, 0x52, 0x26, 0x37, 0x1c, 0xb7, 0x7e, 0x7f, 0xdd, 0x71, 0xeb, 0xf7,
+	0x37, 0x9c, 0xd6, 0xfa, 0xfd, 0x47, 0xa4, 0x60, 0x46, 0xed, 0x15, 0x59,
+	0x57, 0xbf, 0x9f, 0x60, 0x3d, 0xdc, 0xe9, 0x72, 0xeb, 0xf4, 0x5d, 0x5e,
+	0xfd, 0x3e, 0x2a, 0x85, 0x35, 0xed, 0xa6, 0xbc, 0x69, 0xf9, 0xf5, 0xfb,
+	0xef, 0xa2, 0xad, 0x1b, 0x63, 0xac, 0xad, 0xdd, 0x5f, 0x77, 0x58, 0xbb,
+	0x0f, 0xb1, 0x9f, 0x57, 0xbb, 0x67, 0x3f, 0xe4, 0xf2, 0x0e, 0xeb, 0xf6,
+	0x8f, 0x40, 0x16, 0x5b, 0x21, 0x87, 0x5e, 0x69, 0x3f, 0x13, 0x66, 0x1f,
+	0x55, 0xaf, 0x5f, 0x71, 0x42, 0x78, 0xce, 0xad, 0xab, 0xcf, 0xc0, 0xae,
+	0x0e, 0xae, 0xd6, 0xeb, 0xdd, 0x31, 0x6e, 0x3a, 0x6b, 0xe9, 0xaf, 0xa5,
+	0xd3, 0xe7, 0xd1, 0x09, 0x81, 0x4e, 0x78, 0x1d, 0x9d, 0xbb, 0xf5, 0xf9,
+	0x9b, 0x8e, 0x5b, 0x9b, 0x4f, 0x9f, 0x16, 0xbb, 0x1d, 0xbe, 0xf9, 0xe2,
+	0xc0, 0xc3, 0x1e, 0x8d, 0xd5, 0xda, 0x3c, 0x7d, 0x08, 0x70, 0x7b, 0x4c,
+	0x9d, 0xbd, 0x9a, 0xf9, 0x7f, 0x50, 0x9b, 0x67, 0x5d, 0xde, 0xdd, 0x5f,
+	0xe1, 0xfa, 0x04, 0x3e, 0x7f, 0xd1, 0xad, 0xc9, 0x8f, 0x95, 0xfc, 0x5a,
+	0x3b, 0xf3, 0x47, 0xff, 0x5c, 0x54, 0x7f, 0xe4, 0x88, 0xd0, 0x56, 0xc8,
+	0x1f, 0xe9, 0x76, 0xcb, 0x94, 0xc2, 0x47, 0xb0, 0xa9, 0xd8, 0xbd, 0x31,
+	0x72, 0xe5, 0x94, 0x8f, 0x91, 0x43, 0x0a, 0x23, 0x57, 0x96, 0x7c, 0x8c,
+	0x9c, 0xbc, 0x07, 0x46, 0x6e, 0x76, 0xb9, 0x71, 0x20, 0x28, 0x79, 0x85,
+	0x91, 0xef, 0x75, 0x96, 0x8c, 0xf7, 0xba, 0x88, 0x07, 0xc4, 0x3d, 0x5f,
+	0xd0, 0x7b, 0x8f, 0xb5, 0xe6, 0xe3, 0x66, 0xc6, 0xfe, 0xad, 0x32, 0x71,
+	0xe6, 0x2e, 0x6e, 0x76, 0xb1, 0x71, 0x34, 0x72, 0x48, 0xc5, 0x44, 0xe0,
+	0x84, 0x3a, 0xeb, 0xdf, 0xc4, 0xbe, 0x8c, 0x39, 0x01, 0x85, 0xcf, 0x72,
+	0x45, 0xe6, 0x01, 0x6c, 0x23, 0x16, 0xee, 0xe4, 0x31, 0x2b, 0x2f, 0x26,
+	0xf9, 0x58, 0xd3, 0x3f, 0xd7, 0xc2, 0x3d, 0x86, 0x37, 0x8d, 0xa4, 0x85,
+	0x76, 0xc7, 0xcf, 0x15, 0xe2, 0xea, 0x3c, 0x50, 0x12, 0x58, 0x72, 0x6a,
+	0x15, 0x4b, 0xd2, 0x57, 0xfc, 0xf4, 0x6d, 0xdb, 0xa4, 0x5f, 0xf3, 0xb1,
+	0x22, 0x72, 0xa2, 0x12, 0xd7, 0xb6, 0x8f, 0x15, 0x5d, 0x9c, 0x98, 0x72,
+	0x1a, 0xc0, 0xcb, 0x01, 0x19, 0x03, 0x4e, 0x6f, 0x7c, 0x89, 0x35, 0x28,
+	0x1f, 0x1b, 0xd9, 0xf8, 0x6e, 0xad, 0x49, 0xf1, 0xba, 0x5d, 0xed, 0x05,
+	0x5e, 0x1e, 0x08, 0xb6, 0xb4, 0x3f, 0x0b, 0xff, 0x8d, 0xfc, 0x08, 0xd8,
+	0xc4, 0xc5, 0x44, 0x3b, 0xa0, 0x83, 0x91, 0x7b, 0x60, 0xa2, 0xf5, 0x31,
+	0x8a, 0x31, 0xf3, 0x6e, 0x8c, 0x4a, 0xd7, 0xe9, 0xcf, 0xef, 0xc6, 0xa8,
+	0x7b, 0xc7, 0x50, 0xb6, 0x61, 0x76, 0x56, 0x06, 0x9f, 0x69, 0x29, 0xac,
+	0x8b, 0x51, 0x73, 0x1f, 0x20, 0x46, 0xb9, 0xf8, 0xc0, 0xe5, 0xfb, 0xf7,
+	0x21, 0x9b, 0x1f, 0x43, 0xa6, 0x3f, 0x02, 0xe6, 0xfa, 0x21, 0xe6, 0xf5,
+	0x03, 0xe0, 0xa1, 0xef, 0x97, 0xd6, 0x9f, 0x07, 0x19, 0x15, 0xe6, 0x87,
+	0x2e, 0x66, 0x72, 0x31, 0xfd, 0x0c, 0x56, 0x57, 0xad, 0xd8, 0xc8, 0x4c,
+	0x15, 0x87, 0xcc, 0x69, 0x77, 0x1f, 0x35, 0x92, 0x95, 0xa7, 0x3b, 0x53,
+	0x8b, 0x8c, 0x19, 0xea, 0x3a, 0xcc, 0xfa, 0x25, 0xb1, 0x43, 0x55, 0xe5,
+	0x99, 0x03, 0x52, 0xae, 0xb9, 0x78, 0x6b, 0x6e, 0xd1, 0xa5, 0x31, 0xe5,
+	0xe1, 0xad, 0x9c, 0x87, 0xb7, 0xb2, 0xb5, 0xe5, 0x48, 0x00, 0xfd, 0xe7,
+	0xe2, 0x6b, 0x31, 0xd6, 0x8c, 0x87, 0xb1, 0xa6, 0x3f, 0x20, 0xc6, 0xe2,
+	0x58, 0x39, 0x3c, 0x33, 0x3e, 0x1f, 0x91, 0x5d, 0x90, 0xf3, 0x58, 0x91,
+	0xfa, 0xe2, 0x19, 0xb2, 0xf7, 0xd2, 0x19, 0xf5, 0xe5, 0xea, 0x2a, 0x10,
+	0xdb, 0xa7, 0x8d, 0x43, 0x57, 0x63, 0xef, 0xa9, 0x2b, 0x31, 0xdf, 0x18,
+	0x09, 0xe2, 0xf3, 0xf7, 0xa5, 0x2b, 0xce, 0x83, 0xfa, 0x5a, 0x8f, 0xc5,
+	0xee, 0x07, 0x93, 0xad, 0xc5, 0x63, 0xb6, 0xc2, 0x63, 0xed, 0x5e, 0x1f,
+	0xd9, 0x33, 0x0e, 0x5d, 0xfe, 0x27, 0xf4, 0xf9, 0x99, 0xd5, 0x2d, 0x3f,
+	0x85, 0xff, 0xfe, 0x43, 0xe8, 0xe4, 0x3f, 0x22, 0x57, 0x78, 0xcd, 0xea,
+	0x93, 0x3f, 0x40, 0xdb, 0x5d, 0x9c, 0xc3, 0xfe, 0xc1, 0xc7, 0x92, 0xd6,
+	0x35, 0xe0, 0x93, 0x6b, 0x1e, 0x3e, 0x79, 0x3a, 0x99, 0xb4, 0x26, 0x59,
+	0x37, 0x87, 0x9c, 0x0f, 0xa4, 0xa6, 0x14, 0x36, 0xf1, 0x31, 0xc9, 0xed,
+	0x34, 0xc7, 0x9f, 0x75, 0x56, 0x80, 0x7d, 0x56, 0x3c, 0xec, 0x73, 0x60,
+	0xcc, 0xc5, 0x3e, 0xc1, 0xcf, 0x50, 0xff, 0x2e, 0xee, 0x59, 0xb1, 0x93,
+	0x18, 0xa7, 0x0a, 0x4c, 0x52, 0x71, 0x0e, 0x48, 0xbe, 0xbe, 0x57, 0x7d,
+	0x8e, 0x94, 0xec, 0x68, 0x1b, 0xe4, 0xc4, 0xda, 0xeb, 0x49, 0xae, 0x4a,
+	0x27, 0x6a, 0x16, 0xf1, 0x9d, 0x75, 0xa2, 0xe1, 0xdf, 0xf1, 0xae, 0x9f,
+	0xf7, 0xae, 0x4f, 0x78, 0xd7, 0xc7, 0x11, 0x87, 0x8f, 0xa9, 0x58, 0xca,
+	0x76, 0xb6, 0x41, 0xc9, 0x0e, 0x68, 0x01, 0x7b, 0x9c, 0x1d, 0xfe, 0x8b,
+	0x66, 0x59, 0xe9, 0x98, 0xf4, 0x27, 0xf0, 0x39, 0x8e, 0xcf, 0x34, 0x3e,
+	0xfb, 0xf1, 0xc9, 0xe3, 0xb3, 0x2a, 0x53, 0x2d, 0x55, 0x9a, 0x84, 0x8d,
+	0x0c, 0x4a, 0xaa, 0xfe, 0x12, 0xf4, 0xf8, 0x1c, 0x74, 0x7b, 0x58, 0x0a,
+	0xd5, 0x3f, 0x95, 0xd9, 0x79, 0x4d, 0xba, 0x2c, 0xe8, 0xb4, 0x0a, 0x5b,
+	0x9e, 0x77, 0xf7, 0x13, 0x3b, 0x13, 0x7b, 0xd1, 0xb7, 0x29, 0x4f, 0xc5,
+	0x9f, 0x13, 0xfd, 0xb1, 0x39, 0xf4, 0x13, 0xbd, 0x30, 0xfc, 0x31, 0xb5,
+	0x6f, 0x56, 0x8d, 0xbb, 0x32, 0xde, 0x65, 0xd9, 0x51, 0xe8, 0x7c, 0xf0,
+	0x18, 0x68, 0x27, 0xd5, 0xd9, 0xd8, 0x8c, 0x1c, 0x3d, 0xbd, 0xbc, 0xc5,
+	0xf5, 0xad, 0x51, 0xf3, 0x26, 0xf5, 0x8e, 0x79, 0xd8, 0xf0, 0x85, 0x19,
+	0xd8, 0xfb, 0x41, 0x27, 0xa0, 0x8d, 0x21, 0xde, 0x8c, 0x39, 0x37, 0x55,
+	0xbc, 0x81, 0xef, 0xca, 0xc4, 0x4e, 0x86, 0x70, 0xcd, 0xb3, 0x45, 0x88,
+	0x8b, 0xea, 0x6c, 0xe5, 0x32, 0xf0, 0x8d, 0xa6, 0xea, 0x80, 0xb3, 0xab,
+	0xfb, 0x43, 0x86, 0xf2, 0x5b, 0xb1, 0x98, 0x2e, 0xb9, 0x11, 0xe2, 0xdc,
+	0xbd, 0x2a, 0x36, 0xd5, 0x8a, 0xf6, 0x43, 0xcc, 0x15, 0x6f, 0x08, 0xe3,
+	0xdc, 0xe3, 0xe8, 0xd7, 0x07, 0x7f, 0x8c, 0x7b, 0x75, 0xda, 0x27, 0xe7,
+	0xca, 0x67, 0xa6, 0xa5, 0x5a, 0x1e, 0xc5, 0x7c, 0xbd, 0x1c, 0x49, 0xe5,
+	0x12, 0x11, 0xd8, 0xa3, 0xbf, 0x17, 0xe5, 0xd6, 0x4f, 0xaa, 0x8e, 0x8f,
+	0x29, 0xba, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xee, 0x9f, 0xa9, 0xbd,
+	0xb3, 0x82, 0x33, 0x0a, 0x39, 0x25, 0xd1, 0xce, 0x5a, 0x35, 0x7e, 0x97,
+	0x75, 0x55, 0x13, 0x58, 0x31, 0x66, 0xa4, 0x56, 0x6e, 0x82, 0x5f, 0xc4,
+	0xdc, 0x2d, 0x33, 0x52, 0x29, 0x4f, 0xcb, 0x2b, 0xe5, 0x9f, 0x77, 0x03,
+	0x53, 0x41, 0xa6, 0xe4, 0xbf, 0x5b, 0xee, 0x9e, 0xbf, 0xf5, 0xdb, 0x21,
+	0xcf, 0xd3, 0xf9, 0xb0, 0x9b, 0xe7, 0xe6, 0x55, 0x2d, 0xc6, 0xfd, 0xb6,
+	0xf5, 0x29, 0x2b, 0x1a, 0x9e, 0x45, 0xcf, 0x83, 0x0b, 0xb4, 0xcd, 0xfc,
+	0xf8, 0x9c, 0xb5, 0x43, 0xae, 0xc6, 0x37, 0xcb, 0x72, 0x5c, 0xe5, 0xc5,
+	0xc4, 0x0f, 0x58, 0xeb, 0x51, 0xb3, 0x21, 0x7b, 0xe4, 0x28, 0xd6, 0xed,
+	0xd5, 0xf8, 0xd3, 0xb0, 0xd3, 0x67, 0x61, 0x0b, 0xac, 0x01, 0x1c, 0x62,
+	0xae, 0x25, 0x0d, 0x55, 0x23, 0x6b, 0x36, 0xc7, 0xd5, 0x19, 0xee, 0x76,
+	0x59, 0x56, 0x58, 0xcc, 0xad, 0x9d, 0x2f, 0x4f, 0xba, 0x6b, 0xc4, 0x50,
+	0x76, 0xff, 0xc7, 0xe0, 0xc7, 0x84, 0xed, 0xb6, 0xa9, 0x3e, 0x46, 0xa2,
+	0xc3, 0xeb, 0xa3, 0xf4, 0xdb, 0xd2, 0xe7, 0x95, 0x44, 0xd2, 0xda, 0xff,
+	0x89, 0xa4, 0x75, 0x73, 0xb7, 0x5b, 0x6f, 0x89, 0x9a, 0xb6, 0xc6, 0xf7,
+	0x52, 0xdc, 0xf5, 0x98, 0xc1, 0xba, 0xba, 0xb4, 0x8a, 0xa1, 0x61, 0xa4,
+	0x2f, 0x5f, 0x81, 0x7e, 0x03, 0xd2, 0x7e, 0xb2, 0xf9, 0xf8, 0x54, 0x7c,
+	0x28, 0x72, 0x50, 0x78, 0x02, 0x8b, 0x79, 0x75, 0x34, 0x9e, 0x95, 0x2b,
+	0x88, 0x93, 0x77, 0x88, 0x1d, 0x06, 0x2f, 0xcb, 0x9d, 0xc7, 0x93, 0xf1,
+	0x51, 0xad, 0x32, 0x89, 0xac, 0xe5, 0xe5, 0x49, 0xc6, 0xd9, 0x43, 0x22,
+	0xc0, 0x97, 0x27, 0x47, 0x24, 0x5d, 0x54, 0xef, 0xa9, 0xf0, 0x9c, 0xad,
+	0x36, 0x0d, 0xf9, 0xe1, 0xf9, 0x09, 0x06, 0x46, 0xdd, 0xea, 0x8f, 0xa4,
+	0xe5, 0x69, 0xd6, 0xc0, 0x24, 0xb7, 0x20, 0xdb, 0x92, 0xf0, 0xab, 0xf6,
+	0x44, 0xbb, 0x4c, 0xd7, 0x1a, 0x99, 0xfe, 0x53, 0xcf, 0x82, 0xc6, 0x14,
+	0x68, 0xed, 0x45, 0x6e, 0x92, 0x45, 0xac, 0xa6, 0x7c, 0xe9, 0xbb, 0x9f,
+	0x81, 0x8c, 0x3e, 0xc2, 0x3d, 0xe5, 0xd1, 0xac, 0x44, 0x27, 0xf2, 0x8a,
+	0xee, 0x5b, 0x5a, 0x6e, 0xf8, 0x57, 0x10, 0xeb, 0x02, 0xb2, 0x2b, 0x26,
+	0xfa, 0xde, 0x58, 0xe0, 0xed, 0x29, 0x8b, 0x6d, 0x41, 0xb6, 0xe9, 0x68,
+	0x0b, 0xfc, 0x7a, 0x2c, 0xa8, 0x27, 0x63, 0xd1, 0x51, 0x9e, 0x8f, 0x36,
+	0xac, 0x29, 0xee, 0x4d, 0x3c, 0x20, 0x5d, 0x7b, 0xa5, 0xe7, 0x42, 0x74,
+	0xf4, 0x06, 0x78, 0x09, 0x28, 0x5f, 0x3f, 0x25, 0xba, 0xd7, 0xde, 0xbd,
+	0xda, 0x1e, 0xf0, 0xda, 0xf7, 0x4a, 0xd7, 0x85, 0x21, 0xf3, 0x75, 0x99,
+	0x01, 0x4d, 0x43, 0xae, 0x23, 0xd7, 0xb1, 0x06, 0xa6, 0x60, 0x8b, 0x4f,
+	0x92, 0x97, 0xfd, 0xc0, 0x1a, 0x58, 0x1b, 0xc8, 0xbf, 0xad, 0x0f, 0xcb,
+	0x57, 0xcd, 0x4e, 0xc9, 0xa9, 0x5c, 0x37, 0xe0, 0xd6, 0x52, 0x61, 0xef,
+	0x8f, 0x0e, 0x1c, 0xec, 0x71, 0xeb, 0x05, 0xdc, 0xef, 0x18, 0x46, 0xdb,
+	0x9d, 0xe6, 0x39, 0x8b, 0x6d, 0xbc, 0x77, 0xa7, 0x59, 0xb5, 0x86, 0xcc,
+	0x94, 0x16, 0xf4, 0xf6, 0xbd, 0x0f, 0xa9, 0xb9, 0xe7, 0xcb, 0xfd, 0x66,
+	0x45, 0x1e, 0xd5, 0x52, 0x0f, 0x22, 0x5e, 0x38, 0xd3, 0xe8, 0x7b, 0x87,
+	0xe7, 0x29, 0x54, 0x7d, 0xbf, 0x22, 0xfe, 0x35, 0xe9, 0x0c, 0x99, 0xe3,
+	0xea, 0xd9, 0x21, 0xf3, 0xa8, 0xd6, 0xfa, 0x6c, 0x58, 0x1b, 0x5f, 0xf3,
+	0x6c, 0x97, 0x92, 0x91, 0x61, 0xb9, 0x7d, 0x66, 0xcb, 0x7b, 0xe5, 0x79,
+	0x87, 0xfd, 0xee, 0x34, 0x53, 0xd6, 0x03, 0xda, 0xd1, 0x07, 0xe9, 0x0b,
+	0xd9, 0xf7, 0xf6, 0xba, 0x71, 0x78, 0x7d, 0xaf, 0x31, 0x9a, 0xb2, 0x76,
+	0x8c, 0x4d, 0xaa, 0xcf, 0x55, 0xd5, 0x27, 0xa0, 0x64, 0xbd, 0x76, 0x9c,
+	0xbf, 0x91, 0xb5, 0xe3, 0x74, 0xad, 0xce, 0x79, 0x16, 0x34, 0x8f, 0xa1,
+	0x6f, 0xd1, 0xe9, 0x0f, 0x57, 0xe5, 0x76, 0x33, 0x67, 0xbd, 0x29, 0x57,
+	0x57, 0x69, 0xff, 0x12, 0xd7, 0xad, 0x3c, 0xfd, 0xd2, 0xe3, 0x91, 0xbf,
+	0xd9, 0xf6, 0x2f, 0x95, 0xbc, 0x1f, 0xb0, 0xfa, 0xf7, 0x57, 0xb4, 0xe8,
+	0xe8, 0x5f, 0x0a, 0x75, 0xf5, 0xcf, 0x94, 0xaf, 0xf9, 0x18, 0xf4, 0xb4,
+	0xed, 0x05, 0xac, 0xdd, 0xe1, 0xa4, 0xea, 0x73, 0xdd, 0xda, 0x2b, 0xdb,
+	0x4e, 0xf6, 0x9b, 0xd7, 0xe5, 0x33, 0x92, 0x0e, 0xf1, 0x1a, 0x39, 0x94,
+	0xc5, 0xf7, 0x52, 0x3e, 0xc1, 0xbc, 0x00, 0xba, 0xec, 0x1f, 0xfc, 0x4b,
+	0x79, 0x56, 0x8e, 0x96, 0xe6, 0xe0, 0x7b, 0xa6, 0x64, 0xf0, 0x05, 0xfa,
+	0x9f, 0xbc, 0xe9, 0xd6, 0x6a, 0xdc, 0x98, 0x98, 0xf2, 0x62, 0xe2, 0x9c,
+	0xf2, 0x73, 0xaf, 0x79, 0xe7, 0x22, 0xfa, 0x07, 0xcf, 0xe1, 0xd9, 0x57,
+	0x94, 0x0f, 0xf8, 0x3d, 0xa9, 0x62, 0x2d, 0x44, 0x5e, 0xde, 0x2c, 0x0f,
+	0x3c, 0x41, 0x9b, 0x44, 0x06, 0xf0, 0xb1, 0x36, 0xf5, 0x1e, 0x8c, 0x6e,
+	0x75, 0x88, 0x6c, 0xa1, 0xfd, 0x5c, 0x86, 0xad, 0x4d, 0xb9, 0x7b, 0x5f,
+	0x6b, 0xae, 0xa3, 0x13, 0x2b, 0xf2, 0x1f, 0x94, 0x1d, 0x7e, 0xfc, 0x82,
+	0xfb, 0x3d, 0x7c, 0x01, 0xe9, 0x72, 0x6c, 0xaf, 0x6c, 0xbf, 0xe0, 0xda,
+	0xdd, 0xec, 0xfc, 0xb3, 0x4a, 0xbe, 0x53, 0x4a, 0xbe, 0x4d, 0x99, 0x89,
+	0x53, 0xf6, 0x9c, 0x13, 0xcf, 0x4f, 0xba, 0x32, 0xf9, 0x9c, 0x67, 0x47,
+	0xfd, 0x2f, 0xf0, 0x3d, 0x35, 0xca, 0x88, 0x7c, 0xcf, 0xf4, 0x70, 0x3f,
+	0x76, 0xdb, 0x05, 0xce, 0xb7, 0x6f, 0xcd, 0x7c, 0x4f, 0xc0, 0xc7, 0x0e,
+	0x0c, 0xb8, 0x73, 0x7e, 0x6d, 0xfe, 0xfd, 0xcf, 0xf9, 0x77, 0x57, 0xe7,
+	0x6c, 0x48, 0x55, 0xe5, 0xb9, 0xb1, 0xcd, 0xd2, 0x95, 0x93, 0x06, 0xec,
+	0xe3, 0xcf, 0x85, 0x67, 0xc6, 0xc9, 0x8b, 0x3b, 0xee, 0xb2, 0x43, 0x9e,
+	0xfc, 0x39, 0x90, 0xaf, 0x29, 0x4f, 0x7f, 0xe4, 0xe3, 0xd9, 0x0d, 0xef,
+	0x5d, 0x97, 0x46, 0x66, 0x10, 0x6d, 0xba, 0xd2, 0xe1, 0x98, 0xb7, 0xde,
+	0xf6, 0x8a, 0xae, 0x74, 0x98, 0x5c, 0xd5, 0xe1, 0x0d, 0xe8, 0xb0, 0x2a,
+	0x9f, 0xc6, 0x9c, 0xb0, 0xbe, 0x5f, 0x18, 0x32, 0x67, 0x64, 0xab, 0xd2,
+	0xbf, 0x35, 0x00, 0x9f, 0xea, 0xe9, 0xb2, 0xfd, 0x3e, 0x74, 0xf9, 0xba,
+	0x28, 0x7d, 0xaa, 0x73, 0x44, 0x55, 0x45, 0x87, 0xbe, 0x8d, 0x73, 0x6b,
+	0x57, 0x3e, 0x81, 0x3c, 0xaa, 0xb3, 0x01, 0x13, 0xae, 0x7e, 0xd5, 0x9a,
+	0xf7, 0xf4, 0x9b, 0x9d, 0xa0, 0x0e, 0x7f, 0xad, 0xc7, 0xd5, 0x67, 0x87,
+	0xea, 0x73, 0x2a, 0x36, 0xaa, 0xd6, 0xbb, 0x35, 0xf0, 0xe9, 0x1e, 0xea,
+	0xf4, 0x79, 0xc7, 0xfd, 0x2e, 0x22, 0xce, 0x9d, 0x72, 0xde, 0x4b, 0xaf,
+	0xae, 0x4e, 0xc7, 0xc4, 0x5d, 0x57, 0xeb, 0xf5, 0xa9, 0x5f, 0x08, 0x28,
+	0x1b, 0x1e, 0x83, 0x0c, 0x8f, 0x97, 0x1e, 0xf4, 0xec, 0xde, 0x9d, 0xf3,
+	0xc0, 0xfb, 0x9c, 0xf3, 0x91, 0x62, 0xbf, 0xf9, 0x26, 0xee, 0x8d, 0x63,
+	0xce, 0x33, 0xd2, 0x26, 0x29, 0x6f, 0xce, 0x91, 0xd5, 0x39, 0xfb, 0x3c,
+	0xba, 0xfd, 0x52, 0xcc, 0x63, 0x1d, 0xfa, 0xaf, 0x7f, 0xab, 0xde, 0x37,
+	0xb9, 0x59, 0xa4, 0xdf, 0x06, 0x56, 0x0a, 0xf5, 0xca, 0xf5, 0x5a, 0x44,
+	0xae, 0x13, 0x83, 0x8c, 0xe0, 0xdb, 0x99, 0xf3, 0x62, 0x78, 0x50, 0x5e,
+	0x2f, 0x6e, 0xc4, 0xc7, 0xb0, 0xdc, 0x28, 0xfa, 0xbc, 0x10, 0x0b, 0x33,
+	0x5f, 0x98, 0x92, 0x37, 0xe6, 0xfb, 0xa5, 0x31, 0x81, 0xb8, 0x3f, 0x40,
+	0x99, 0x0c, 0x99, 0x7b, 0xd4, 0x7b, 0x48, 0x77, 0x9a, 0x97, 0x2d, 0xd0,
+	0x5f, 0x68, 0xca, 0x41, 0xee, 0x67, 0xf3, 0x77, 0xed, 0x21, 0x69, 0x30,
+	0xa7, 0x18, 0xe8, 0x95, 0xca, 0x02, 0xf2, 0xf9, 0x22, 0xe9, 0x53, 0x6e,
+	0x7b, 0xd5, 0xef, 0x71, 0x8c, 0xf7, 0x39, 0xbe, 0x1f, 0x10, 0xa2, 0x6e,
+	0xee, 0x34, 0x97, 0x2d, 0xee, 0x67, 0x4e, 0x49, 0x0d, 0xfa, 0xfb, 0xe7,
+	0x31, 0xee, 0xb7, 0xe7, 0xd4, 0xf9, 0xdb, 0x4a, 0x6d, 0x02, 0xb9, 0xc3,
+	0x9d, 0xe6, 0x9c, 0x75, 0x56, 0xe9, 0xad, 0x56, 0x7e, 0xc2, 0x6b, 0xe7,
+	0x35, 0xef, 0x35, 0x32, 0xdb, 0x06, 0x98, 0xaf, 0x3e, 0x81, 0x7c, 0x81,
+	0xb9, 0xea, 0x04, 0xf0, 0x1a, 0x65, 0x12, 0x91, 0xd9, 0x22, 0x69, 0x49,
+	0x68, 0x13, 0xf2, 0xfb, 0x9c, 0x8c, 0x83, 0x9f, 0x08, 0x72, 0x7b, 0xc6,
+	0x87, 0x47, 0x65, 0x39, 0xe4, 0xc6, 0x01, 0x9e, 0xfb, 0x5a, 0x46, 0x6c,
+	0x58, 0x5e, 0x8d, 0x0d, 0x5b, 0x71, 0xdd, 0xc8, 0xc4, 0x07, 0xfe, 0x06,
+	0xf4, 0x59, 0xb7, 0x61, 0x6c, 0x18, 0x45, 0x7f, 0xb6, 0xf5, 0xca, 0xec,
+	0x02, 0x92, 0x08, 0xe4, 0x2c, 0x15, 0xe1, 0x99, 0x8e, 0xac, 0x9c, 0xaa,
+	0xf5, 0x87, 0x2f, 0x6b, 0x69, 0x75, 0xf6, 0x23, 0x36, 0xc0, 0xf3, 0x2c,
+	0xbd, 0x52, 0x5b, 0x90, 0x88, 0x91, 0x78, 0x52, 0x9c, 0x9a, 0x8b, 0xd9,
+	0xe7, 0x34, 0x9e, 0x69, 0xb1, 0xa5, 0xb6, 0xb6, 0x8f, 0x89, 0xdc, 0x57,
+	0xbe, 0xe3, 0xf5, 0x49, 0xab, 0x3e, 0x7f, 0xdd, 0xc3, 0x3d, 0xb4, 0x9a,
+	0xd3, 0x03, 0x1e, 0xc8, 0xdb, 0xc3, 0xad, 0xe3, 0x46, 0xee, 0x8e, 0xcb,
+	0x31, 0x91, 0xcd, 0x6c, 0xb1, 0x31, 0xee, 0x4d, 0x3c, 0xf3, 0x24, 0xf8,
+	0xb8, 0x63, 0xe8, 0xd6, 0x93, 0x52, 0xa8, 0xad, 0x1f, 0xa3, 0x95, 0x07,
+	0x3e, 0x43, 0xfa, 0x1c, 0xe7, 0x00, 0xf8, 0xbb, 0xa3, 0xe9, 0xd6, 0x01,
+	0xc8, 0xd2, 0x1d, 0xc3, 0x38, 0x13, 0x35, 0x7f, 0x2a, 0x03, 0xa2, 0x9f,
+	0xd3, 0x94, 0xfc, 0xf5, 0xca, 0x30, 0x16, 0x48, 0x46, 0xba, 0x96, 0x26,
+	0xc5, 0x58, 0x62, 0x0d, 0xe1, 0xb5, 0xce, 0xb4, 0xda, 0xbf, 0xdd, 0x84,
+	0xf5, 0x2d, 0x76, 0xc0, 0x62, 0xbd, 0x80, 0xf5, 0xe0, 0x9f, 0x6e, 0x96,
+	0x1e, 0xd6, 0x0b, 0x98, 0x37, 0xec, 0xc7, 0x37, 0x73, 0x87, 0x4b, 0x4d,
+	0xe4, 0x7a, 0x9b, 0x19, 0x5f, 0x73, 0x35, 0xde, 0x8f, 0x46, 0x44, 0x78,
+	0x8f, 0x7e, 0xa3, 0x57, 0xda, 0xbe, 0x35, 0x08, 0x5f, 0xf1, 0x34, 0xb0,
+	0x37, 0xe8, 0x9e, 0x1c, 0x90, 0x80, 0x7b, 0x66, 0x42, 0xd5, 0x5b, 0xde,
+	0x58, 0x88, 0x7a, 0xef, 0x73, 0xc9, 0xb6, 0xcb, 0x71, 0xd6, 0x44, 0xfb,
+	0x58, 0xf3, 0x41, 0x3f, 0xd1, 0x97, 0x91, 0x9f, 0x5e, 0xaf, 0x59, 0x9b,
+	0x79, 0x7e, 0xf3, 0x86, 0x83, 0x6b, 0x62, 0xff, 0x90, 0xc2, 0x98, 0xde,
+	0x3d, 0xfe, 0x46, 0xbe, 0xf4, 0x8e, 0x77, 0x13, 0x98, 0x4f, 0x4d, 0x7a,
+	0x67, 0xe7, 0x1a, 0x99, 0xa3, 0x6b, 0x72, 0xaa, 0x41, 0x55, 0xef, 0x6d,
+	0x38, 0x16, 0xfc, 0xe3, 0x08, 0xec, 0x93, 0x6b, 0xa0, 0xa9, 0x3d, 0x01,
+	0x6c, 0x16, 0xe9, 0x55, 0x39, 0xd1, 0xf1, 0x27, 0xc4, 0xb5, 0x77, 0x58,
+	0x99, 0xf2, 0x65, 0x8d, 0xb2, 0x9b, 0x83, 0x2c, 0x97, 0x33, 0xf2, 0x47,
+	0xce, 0x15, 0x55, 0x6b, 0x9d, 0x47, 0x5e, 0x12, 0x38, 0xa5, 0x72, 0xb2,
+	0x16, 0x7c, 0x0b, 0xbf, 0xf7, 0xe2, 0xd7, 0xb1, 0x16, 0xa3, 0xea, 0x8c,
+	0x82, 0x7e, 0xae, 0xd9, 0x4c, 0xc1, 0x7f, 0xe8, 0x96, 0x65, 0x16, 0x10,
+	0x0f, 0x53, 0xea, 0x9c, 0x0b, 0xd7, 0xf1, 0x6f, 0x2b, 0xff, 0x2c, 0x15,
+	0xc8, 0xe6, 0x4c, 0x04, 0x74, 0x34, 0x65, 0x9f, 0x86, 0xd2, 0xc3, 0x13,
+	0x0a, 0xf3, 0x1a, 0xe7, 0xe0, 0xb0, 0x96, 0x06, 0x44, 0xce, 0x65, 0x64,
+	0x0e, 0x6b, 0x38, 0xb0, 0x44, 0x1d, 0x50, 0xb6, 0x93, 0xd2, 0x06, 0xd9,
+	0x1f, 0x01, 0xf6, 0x30, 0x4e, 0x51, 0xc6, 0x61, 0xac, 0x8b, 0x5e, 0x09,
+	0x9c, 0x81, 0x8c, 0x4f, 0x01, 0x23, 0x2c, 0xb4, 0xcb, 0xf7, 0x6a, 0xbe,
+	0x4c, 0x2f, 0xf1, 0x5c, 0xbf, 0x3e, 0x35, 0xd2, 0x47, 0x1c, 0x25, 0xd5,
+	0xda, 0x9c, 0xcc, 0x9d, 0x66, 0xce, 0x3e, 0xa9, 0xce, 0x0c, 0x04, 0xd4,
+	0x99, 0x15, 0x37, 0x67, 0x76, 0xbf, 0x5d, 0x8c, 0x59, 0x15, 0xee, 0xb5,
+	0x09, 0x6c, 0x67, 0x18, 0xe3, 0x6e, 0x24, 0x5f, 0x37, 0x57, 0x1d, 0x07,
+	0xbf, 0x97, 0xe7, 0xa3, 0x99, 0xbc, 0xc4, 0x79, 0x76, 0x7a, 0xc2, 0xc6,
+	0xfc, 0x97, 0xe1, 0x3f, 0xe7, 0x4a, 0x3c, 0x27, 0x5d, 0xc0, 0x0a, 0xcb,
+	0xc8, 0xe5, 0x22, 0x73, 0xc6, 0x8f, 0x43, 0x6f, 0xbc, 0x2e, 0x8c, 0x1a,
+	0xf0, 0x03, 0x2b, 0xea, 0xdd, 0xcf, 0xa8, 0xdd, 0x40, 0x0e, 0x1b, 0xd1,
+	0xf6, 0x43, 0xd7, 0x79, 0xb3, 0xcd, 0xb3, 0x07, 0x9e, 0xc5, 0x3f, 0x0b,
+	0x3f, 0x7a, 0x5e, 0xf8, 0x4e, 0xd6, 0xed, 0x26, 0xf3, 0xa5, 0xab, 0xf0,
+	0x7b, 0x99, 0x58, 0x06, 0x36, 0x94, 0x0f, 0x77, 0x80, 0xe7, 0xdf, 0xc4,
+	0xbd, 0x9c, 0xc3, 0x71, 0xa2, 0xf1, 0x15, 0x29, 0x44, 0x02, 0x32, 0x14,
+	0xb9, 0x22, 0x9b, 0xe1, 0xc9, 0x34, 0x79, 0xdd, 0x8a, 0x8e, 0x8a, 0xa6,
+	0xe8, 0x0d, 0xee, 0x86, 0x0d, 0xde, 0x84, 0xbf, 0x6b, 0xf7, 0x72, 0xfd,
+	0x54, 0x91, 0x18, 0xea, 0x59, 0x75, 0xb6, 0xe0, 0xaa, 0xc5, 0x3a, 0x20,
+	0xdf, 0xc5, 0xfe, 0x1f, 0x6a, 0x8c, 0xbb, 0x7b, 0x77, 0xac, 0x43, 0x93,
+	0x3f, 0x77, 0x8e, 0xbb, 0x2c, 0x97, 0x47, 0xd2, 0x69, 0x6b, 0xa1, 0x73,
+	0xd9, 0xa3, 0x73, 0xd6, 0xa3, 0x53, 0xf1, 0xe8, 0x5c, 0x5d, 0xa5, 0xb3,
+	0x07, 0x76, 0xd0, 0x6c, 0x9e, 0x00, 0xde, 0x48, 0xc6, 0x9b, 0xcd, 0x34,
+	0xf2, 0xb2, 0xd9, 0xe1, 0x69, 0xb5, 0xe7, 0xaa, 0x27, 0x46, 0xc7, 0x93,
+	0x96, 0x2b, 0x7f, 0x58, 0x81, 0x4c, 0xc3, 0x1e, 0xf3, 0xe2, 0x62, 0x75,
+	0xee, 0x07, 0xba, 0xfb, 0x85, 0x5d, 0xf0, 0x03, 0x4f, 0x23, 0x96, 0x5c,
+	0x1c, 0x3f, 0x6f, 0x49, 0x7e, 0xdb, 0x27, 0x75, 0xd8, 0x7b, 0x0f, 0xdf,
+	0x27, 0x35, 0xa5, 0xeb, 0xe2, 0x78, 0xb5, 0xf6, 0x34, 0xf2, 0x23, 0xf6,
+	0xdf, 0x4e, 0x0c, 0xb6, 0xab, 0x52, 0x8b, 0xec, 0x3a, 0xcb, 0xfd, 0x21,
+	0xf4, 0xab, 0xd4, 0xba, 0x21, 0xf7, 0x6e, 0x55, 0x57, 0xb9, 0x52, 0x0c,
+	0x41, 0x8f, 0x26, 0x6c, 0x3e, 0x84, 0xb6, 0x30, 0xec, 0xa0, 0x0f, 0xed,
+	0x3f, 0xc7, 0xda, 0x8e, 0xa0, 0x7d, 0xa5, 0x73, 0x5c, 0xe1, 0x58, 0x4b,
+	0xce, 0x39, 0x37, 0x11, 0x73, 0xdf, 0x84, 0x1f, 0x1d, 0x44, 0x9f, 0x61,
+	0xf4, 0xf9, 0x14, 0xc6, 0xe1, 0x3b, 0xcd, 0x1b, 0xf1, 0xd4, 0x00, 0x4f,
+	0x7a, 0x0b, 0x4f, 0x0d, 0xf0, 0x03, 0xdf, 0x79, 0x92, 0x35, 0xe8, 0x61,
+	0x39, 0x5a, 0xe4, 0x19, 0x29, 0xbe, 0x17, 0x6f, 0x4a, 0x00, 0x98, 0xb4,
+	0xed, 0x64, 0x34, 0xdc, 0x50, 0xb5, 0x1e, 0xda, 0xd6, 0x50, 0xbc, 0x2a,
+	0x2a, 0xce, 0x44, 0x8e, 0x22, 0x7e, 0xdd, 0x74, 0xba, 0xe5, 0x75, 0x6f,
+	0xac, 0x15, 0xe1, 0xfe, 0xe5, 0xda, 0xb1, 0x8e, 0x95, 0xae, 0x8d, 0xbf,
+	0x6a, 0x19, 0xde, 0xbc, 0x7a, 0x31, 0xd6, 0xaf, 0xa2, 0xef, 0xb5, 0xf1,
+	0xcb, 0xb5, 0x8d, 0xfa, 0xde, 0x44, 0xdf, 0xb6, 0x96, 0xbe, 0x37, 0xd1,
+	0xaf, 0x1b, 0x71, 0xb0, 0x5b, 0xcd, 0x69, 0x16, 0x7c, 0x5d, 0x2f, 0xaa,
+	0xf7, 0xb4, 0x21, 0x77, 0x8e, 0x69, 0x12, 0x53, 0x67, 0xdc, 0x5a, 0x49,
+	0xd4, 0x8c, 0x68, 0xef, 0xa8, 0xf7, 0x28, 0x1b, 0x18, 0xb3, 0x80, 0x7b,
+	0xe7, 0x27, 0xb4, 0x54, 0x35, 0x87, 0x98, 0xf5, 0x30, 0xf1, 0x53, 0xdc,
+	0x46, 0xcc, 0xac, 0x80, 0x5e, 0xad, 0xd8, 0xe0, 0x79, 0x6a, 0xd8, 0xc5,
+	0x2d, 0xe2, 0xec, 0x87, 0x0d, 0x75, 0xae, 0x21, 0xad, 0x6a, 0x76, 0x95,
+	0xa2, 0x98, 0xc9, 0x11, 0x9e, 0x65, 0xf8, 0x0c, 0xd6, 0xe5, 0x57, 0xd0,
+	0x96, 0x44, 0x7c, 0x3c, 0xa0, 0x25, 0xcf, 0x8f, 0xe3, 0xfa, 0x49, 0x5c,
+	0xc3, 0x1f, 0x2f, 0x64, 0x71, 0xff, 0x49, 0x5c, 0x4f, 0x6b, 0xa9, 0x7a,
+	0x16, 0xd7, 0x4f, 0xe1, 0x7a, 0xca, 0x64, 0x9e, 0xf2, 0xaa, 0x95, 0xd1,
+	0x6c, 0xd0, 0xb2, 0xcf, 0x8f, 0xe3, 0xd3, 0x4a, 0x8f, 0xf7, 0xa0, 0xa7,
+	0x22, 0xf7, 0xda, 0x62, 0xe0, 0x69, 0x9f, 0x96, 0xae, 0x76, 0x81, 0xc6,
+	0x00, 0x9e, 0xa7, 0x4d, 0xed, 0xf7, 0xc6, 0x67, 0xcd, 0xe9, 0x63, 0xaa,
+	0xe6, 0x64, 0x24, 0x32, 0xc0, 0xc9, 0x87, 0x91, 0x07, 0x68, 0x92, 0xb6,
+	0x9e, 0x93, 0x42, 0x1c, 0x7e, 0xa5, 0x6a, 0x48, 0x2a, 0x94, 0xc7, 0xef,
+	0xbc, 0x24, 0x47, 0x71, 0xbf, 0x4a, 0x5b, 0x60, 0xbf, 0x3f, 0x95, 0x42,
+	0x99, 0xb8, 0x9f, 0x75, 0x26, 0xd6, 0xa6, 0x58, 0x5f, 0xca, 0x41, 0x06,
+	0x21, 0xda, 0xef, 0x06, 0x35, 0x31, 0xf7, 0x8c, 0x34, 0xe2, 0xb2, 0x96,
+	0xac, 0x72, 0xdf, 0xaf, 0x91, 0xb9, 0x6c, 0xf1, 0xfd, 0xb1, 0x69, 0xee,
+	0x23, 0x16, 0x8c, 0x04, 0xeb, 0x23, 0xaa, 0xbe, 0x1e, 0x77, 0xf7, 0x07,
+	0x5b, 0xcf, 0xa4, 0xf8, 0xeb, 0x85, 0xe3, 0x7e, 0x0d, 0xcf, 0xbb, 0xf5,
+	0xac, 0x54, 0xfd, 0x9d, 0xba, 0xe0, 0x3b, 0x00, 0xe7, 0xa0, 0x8b, 0xcb,
+	0x2a, 0x37, 0xe6, 0x1e, 0xee, 0xbb, 0xe5, 0x54, 0xc8, 0x61, 0x8a, 0xac,
+	0x91, 0xf9, 0xfb, 0x76, 0xbe, 0x1c, 0xd7, 0xf3, 0x4a, 0x3e, 0x67, 0x40,
+	0x53, 0xe2, 0xf4, 0xbb, 0xd9, 0x10, 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf3,
+	0x2e, 0xdf, 0xe4, 0x99, 0xf2, 0x38, 0x0c, 0xff, 0xc9, 0xf7, 0x2b, 0x9e,
+	0x93, 0x5c, 0x9c, 0x35, 0x1e, 0x03, 0xb1, 0x31, 0x8f, 0xdf, 0x77, 0xe5,
+	0x37, 0xeb, 0xc9, 0x2f, 0x57, 0xfe, 0x2f, 0x4a, 0x87, 0x15, 0x8b, 0xe3,
+	0xf9, 0xb5, 0x8f, 0xbd, 0x4a, 0x77, 0x15, 0x75, 0x7e, 0xd7, 0x97, 0x81,
+	0x5f, 0xbf, 0xdb, 0xd8, 0xf6, 0xc6, 0x2d, 0xf2, 0xf6, 0x10, 0xcf, 0x43,
+	0x0c, 0xda, 0x42, 0xfe, 0x39, 0x0f, 0xc6, 0x30, 0x7f, 0xaf, 0xd5, 0x9f,
+	0x83, 0x3f, 0xcf, 0xfb, 0x95, 0x0f, 0xf9, 0xfd, 0xe4, 0x16, 0xe9, 0xca,
+	0x98, 0x86, 0xc5, 0xd8, 0xf0, 0xb8, 0xb7, 0x3f, 0xf0, 0x7f, 0x43, 0xce,
+	0xae, 0x2c, 0x02, 0x09, 0x99, 0xf5, 0xde, 0xbf, 0xde, 0xc0, 0x1e, 0xd6,
+	0xef, 0x35, 0x37, 0x32, 0x67, 0xad, 0xbb, 0xf3, 0xae, 0x6c, 0x30, 0xef,
+	0x8a, 0x37, 0xef, 0xea, 0x7d, 0xf2, 0x5b, 0x99, 0xb7, 0x31, 0x67, 0xda,
+	0xdc, 0x46, 0xf6, 0x28, 0xea, 0xdd, 0xb0, 0x15, 0x23, 0x18, 0xb4, 0x9d,
+	0x7b, 0xd5, 0x50, 0x99, 0x57, 0xbb, 0x76, 0x79, 0x16, 0xb1, 0xb0, 0x5c,
+	0x76, 0x73, 0xec, 0xb2, 0xc3, 0x5a, 0xf6, 0xbb, 0xf1, 0xc0, 0x77, 0xb9,
+	0xbe, 0xa8, 0xce, 0xbb, 0xcc, 0x3a, 0x6e, 0xdd, 0xab, 0x5c, 0x6e, 0x8d,
+	0xa9, 0x0f, 0x32, 0x9e, 0x0e, 0xe6, 0x65, 0x82, 0xef, 0x94, 0xe3, 0xfa,
+	0x11, 0xb9, 0xb2, 0xa0, 0xf6, 0xac, 0xbc, 0xbd, 0x21, 0xee, 0xf9, 0xa8,
+	0xfd, 0x6f, 0xf8, 0xb5, 0x49, 0xe5, 0xd7, 0x97, 0x17, 0xd4, 0x3d, 0x17,
+	0x2b, 0x39, 0x13, 0xf0, 0xfb, 0xc8, 0x25, 0xac, 0x07, 0xa4, 0x80, 0x9c,
+	0xfb, 0xac, 0x75, 0x78, 0x0b, 0x71, 0x0e, 0x69, 0x2d, 0x83, 0xd6, 0xe5,
+	0x05, 0xd9, 0xc2, 0x33, 0x25, 0x65, 0xb5, 0xcf, 0xe6, 0xd6, 0xc5, 0xa7,
+	0xc5, 0xff, 0x7f, 0x1d, 0x41, 0x2f, 0x16, 0xf2, 0x5c, 0x0b, 0xdf, 0x73,
+	0xa6, 0xaf, 0x40, 0x1e, 0x34, 0xc1, 0x7d, 0x9c, 0x66, 0xd3, 0xad, 0x9b,
+	0x37, 0xb1, 0x2e, 0xda, 0xf8, 0x0e, 0x05, 0xfe, 0x0e, 0xc3, 0x7e, 0xb0,
+	0x4e, 0x56, 0xdb, 0x79, 0xcd, 0xdc, 0xc3, 0xbf, 0x66, 0x60, 0xfb, 0x3f,
+	0xe8, 0xf3, 0x49, 0x14, 0x38, 0x46, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
 	0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010,
 	0x00000030, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x00000010,
 	0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00008002, 0x00000000,
@@ -4043,42 +4051,42 @@ static u32 bnx2_TXP_b09FwData[(0xd0/4) +
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
 	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
-static u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
-	0x08003be8, 0x08003c14, 0x08003c5c, 0x08003c5c, 0x08003ae8, 0x08003b14,
-	0x08003b14, 0x08003c5c, 0x08003c5c, 0x08003c5c, 0x08003b7c, 0x00000000,
+static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
+	0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c,
+	0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000,
 	0x00000000 };
-static u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b09FwSbss[(0x80/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_txp_fw_09 = {
-	.ver_major			= 0x1,
-	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_major			= 0x3,
+	.ver_minor			= 0x4,
+	.ver_fix			= 0x3,
 
 	.start_addr			= 0x08000060,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x4194,
+	.text_len			= 0x4634,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TXP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_TXP_b09FwText),
 
-	.data_addr			= 0x080041e0,
+	.data_addr			= 0x08004680,
 	.data_len			= 0xd0,
 	.data_index			= 0x0,
 	.data				= bnx2_TXP_b09FwData,
 
-	.sbss_addr			= 0x080042b0,
-	.sbss_len			= 0x80,
+	.sbss_addr			= 0x08004750,
+	.sbss_len			= 0x8c,
 	.sbss_index			= 0x0,
 	.sbss				= bnx2_TXP_b09FwSbss,
 
-	.bss_addr			= 0x08004330,
+	.bss_addr			= 0x080047e0,
 	.bss_len			= 0xa20,
 	.bss_index			= 0x0,
 	.bss				= bnx2_TXP_b09FwBss,
 
-	.rodata_addr			= 0x08004198,
+	.rodata_addr			= 0x08004638,
 	.rodata_len			= 0x30,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_TXP_b09FwRodata,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 3fb354d..7e03f41 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -884,8 +884,8 @@ static int ad_lacpdu_send(struct port *p
 	}
 
 	skb->dev = slave->dev;
-	skb->mac.raw = skb->data;
-	skb->nh.raw = skb->data + ETH_HLEN;
+	skb_reset_mac_header(skb);
+	skb->network_header = skb->mac_header + ETH_HLEN;
 	skb->protocol = PKT_TYPE_LACPDU;
 	skb->priority = TC_PRIO_CONTROL;
 
@@ -928,8 +928,8 @@ static int ad_marker_send(struct port *p
 	skb_reserve(skb, 16);
 
 	skb->dev = slave->dev;
-	skb->mac.raw = skb->data;
-	skb->nh.raw = skb->data + ETH_HLEN;
+	skb_reset_mac_header(skb);
+	skb->network_header = skb->mac_header + ETH_HLEN;
 	skb->protocol = PKT_TYPE_LACPDU;
 
 	marker_header = (struct marker_header *)skb_put(skb, length);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 217a2ee..92c3b6f 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -104,10 +104,15 @@ struct arp_pkt {
 };
 #pragma pack()
 
+static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
+{
+	return (struct arp_pkt *)skb_network_header(skb);
+}
+
 /* Forward declaration */
 static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
 
-static inline u8 _simple_hash(u8 *hash_start, int hash_size)
+static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
 {
 	int i;
 	u8 hash = 0;
@@ -613,7 +618,7 @@ static void rlb_req_update_subnet_client
 static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
-	struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
+	struct arp_pkt *arp = arp_pkt(skb);
 	struct slave *assigned_slave;
 	struct rlb_client_info *client_info;
 	u32 hash_index = 0;
@@ -701,7 +706,7 @@ static struct slave *rlb_choose_channel(
  */
 static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
 {
-	struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
+	struct arp_pkt *arp = arp_pkt(skb);
 	struct slave *tx_slave = NULL;
 
 	if (arp->op_code == __constant_htons(ARPOP_REPLY)) {
@@ -890,8 +895,8 @@ static void alb_send_learning_packets(st
 		data = skb_put(skb, size);
 		memcpy(data, &pkt, size);
 
-		skb->mac.raw = data;
-		skb->nh.raw = data + ETH_HLEN;
+		skb_reset_mac_header(skb);
+		skb->network_header = skb->mac_header + ETH_HLEN;
 		skb->protocol = pkt.type;
 		skb->priority = TC_PRIO_CONTROL;
 		skb->dev = slave->dev;
@@ -1263,10 +1268,10 @@ int bond_alb_xmit(struct sk_buff *skb, s
 	int hash_size = 0;
 	int do_tx_balance = 1;
 	u32 hash_index = 0;
-	u8 *hash_start = NULL;
+	const u8 *hash_start = NULL;
 	int res = 1;
 
-	skb->mac.raw = (unsigned char *)skb->data;
+	skb_reset_mac_header(skb);
 	eth_data = eth_hdr(skb);
 
 	/* make sure that the curr_active_slave and the slaves list do
@@ -1280,15 +1285,18 @@ int bond_alb_xmit(struct sk_buff *skb, s
 	}
 
 	switch (ntohs(skb->protocol)) {
-	case ETH_P_IP:
+	case ETH_P_IP: {
+		const struct iphdr *iph = ip_hdr(skb);
+
 		if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) ||
-		    (skb->nh.iph->daddr == ip_bcast) ||
-		    (skb->nh.iph->protocol == IPPROTO_IGMP)) {
+		    (iph->daddr == ip_bcast) ||
+		    (iph->protocol == IPPROTO_IGMP)) {
 			do_tx_balance = 0;
 			break;
 		}
-		hash_start = (char*)&(skb->nh.iph->daddr);
-		hash_size = sizeof(skb->nh.iph->daddr);
+		hash_start = (char *)&(iph->daddr);
+		hash_size = sizeof(iph->daddr);
+	}
 		break;
 	case ETH_P_IPV6:
 		if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) {
@@ -1296,8 +1304,8 @@ int bond_alb_xmit(struct sk_buff *skb, s
 			break;
 		}
 
-		hash_start = (char*)&(skb->nh.ipv6h->daddr);
-		hash_size = sizeof(skb->nh.ipv6h->daddr);
+		hash_start = (char *)&(ipv6_hdr(skb)->daddr);
+		hash_size = sizeof(ipv6_hdr(skb)->daddr);
 		break;
 	case ETH_P_IPX:
 		if (ipx_hdr(skb)->ipx_checksum !=
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index e4724d8..724bce5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1360,13 +1360,6 @@ int bond_enslave(struct net_device *bond
 		goto err_undo_flags;
 	}
 
-	if (slave_dev->get_stats == NULL) {
-		printk(KERN_NOTICE DRV_NAME
-			": %s: the driver for slave device %s does not provide "
-			"get_stats function, network statistics will be "
-			"inaccurate.\n", bond_dev->name, slave_dev->name);
-	}
-
 	new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
 	if (!new_slave) {
 		res = -ENOMEM;
@@ -2524,7 +2517,7 @@ static int bond_arp_rcv(struct sk_buff *
 				 (2 * sizeof(u32)))))
 		goto out_unlock;
 
-	arp = skb->nh.arph;
+	arp = arp_hdr(skb);
 	if (arp->ar_hln != dev->addr_len ||
 	    skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->pkt_type == PACKET_LOOPBACK ||
@@ -3476,7 +3469,7 @@ static int bond_xmit_hash_policy_l34(str
 				    struct net_device *bond_dev, int count)
 {
 	struct ethhdr *data = (struct ethhdr *)skb->data;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
 	int layer4_xor = 0;
 
@@ -3640,35 +3633,32 @@ static struct net_device_stats *bond_get
 	read_lock_bh(&bond->lock);
 
 	bond_for_each_slave(bond, slave, i) {
-		if (slave->dev->get_stats) {
-			sstats = slave->dev->get_stats(slave->dev);
-
-			stats->rx_packets += sstats->rx_packets;
-			stats->rx_bytes += sstats->rx_bytes;
-			stats->rx_errors += sstats->rx_errors;
-			stats->rx_dropped += sstats->rx_dropped;
-
-			stats->tx_packets += sstats->tx_packets;
-			stats->tx_bytes += sstats->tx_bytes;
-			stats->tx_errors += sstats->tx_errors;
-			stats->tx_dropped += sstats->tx_dropped;
-
-			stats->multicast += sstats->multicast;
-			stats->collisions += sstats->collisions;
-
-			stats->rx_length_errors += sstats->rx_length_errors;
-			stats->rx_over_errors += sstats->rx_over_errors;
-			stats->rx_crc_errors += sstats->rx_crc_errors;
-			stats->rx_frame_errors += sstats->rx_frame_errors;
-			stats->rx_fifo_errors += sstats->rx_fifo_errors;
-			stats->rx_missed_errors += sstats->rx_missed_errors;
-
-			stats->tx_aborted_errors += sstats->tx_aborted_errors;
-			stats->tx_carrier_errors += sstats->tx_carrier_errors;
-			stats->tx_fifo_errors += sstats->tx_fifo_errors;
-			stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
-			stats->tx_window_errors += sstats->tx_window_errors;
-		}
+		sstats = slave->dev->get_stats(slave->dev);
+		stats->rx_packets += sstats->rx_packets;
+		stats->rx_bytes += sstats->rx_bytes;
+		stats->rx_errors += sstats->rx_errors;
+		stats->rx_dropped += sstats->rx_dropped;
+
+		stats->tx_packets += sstats->tx_packets;
+		stats->tx_bytes += sstats->tx_bytes;
+		stats->tx_errors += sstats->tx_errors;
+		stats->tx_dropped += sstats->tx_dropped;
+
+		stats->multicast += sstats->multicast;
+		stats->collisions += sstats->collisions;
+
+		stats->rx_length_errors += sstats->rx_length_errors;
+		stats->rx_over_errors += sstats->rx_over_errors;
+		stats->rx_crc_errors += sstats->rx_crc_errors;
+		stats->rx_frame_errors += sstats->rx_frame_errors;
+		stats->rx_fifo_errors += sstats->rx_fifo_errors;
+		stats->rx_missed_errors += sstats->rx_missed_errors;
+
+		stats->tx_aborted_errors += sstats->tx_aborted_errors;
+		stats->tx_carrier_errors += sstats->tx_carrier_errors;
+		stats->tx_fifo_errors += sstats->tx_fifo_errors;
+		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+		stats->tx_window_errors += sstats->tx_window_errors;
 	}
 
 	read_unlock_bh(&bond->lock);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index c812648..4aec747 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -1995,7 +1995,6 @@ static int cas_rx_process_pkt(struct cas
 		return -1;
 
 	*skbref = skb;
-	skb->dev = cp->dev;
 	skb_reserve(skb, swivel);
 
 	p = skb->data;
@@ -2822,10 +2821,8 @@ static inline int cas_xmit_tx_ringN(stru
 
 	ctrl = 0;
 	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 = csum_start_off + skb->csum_offset;
+		const u64 csum_start_off = skb_transport_offset(skb);
+		const u64 csum_stuff_off = csum_start_off + skb->csum_offset;
 
 		ctrl =  TX_DESC_CSUM_EN |
 			CAS_BASE(TX_DESC_CSUM_START, csum_start_off) |
@@ -2849,8 +2846,8 @@ static inline int cas_xmit_tx_ringN(stru
 			      ctrl | TX_DESC_SOF, 0);
 		entry = TX_DESC_NEXT(ring, entry);
 
-		memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
-		       len - tabort, tabort);
+		skb_copy_from_linear_data_offset(skb, len - tabort,
+			      tx_tiny_buf(cp, ring, entry), tabort);
 		mapping = tx_tiny_map(cp, ring, entry, tentry);
 		cas_write_txd(cp, ring, entry, mapping, tabort, ctrl,
 			      (nr_frags == 0));
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 382d23f..743ad8b 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,8 +4,6 @@ #
 
 obj-$(CONFIG_CHELSIO_T1) += cxgb.o
 
-cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
 cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
 	     mv88x201x.o my3126.o $(cxgb-y)
-
-
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 787f2f2..8ba702c 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -322,9 +322,9 @@ struct board_info {
 	unsigned char           mdio_mdiinv;
 	unsigned char           mdio_mdc;
 	unsigned char           mdio_phybaseaddr;
-	struct gmac            *gmac;
-	struct gphy            *gphy;
-	struct mdio_ops        *mdio_ops;
+	const struct gmac      *gmac;
+	const struct gphy      *gphy;
+	const struct mdio_ops  *mdio_ops;
 	const char             *desc;
 };
 
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h
index cf91434..79d855e 100644
--- a/drivers/net/chelsio/cphy.h
+++ b/drivers/net/chelsio/cphy.h
@@ -100,7 +100,7 @@ struct cphy {
 
 	u32 elmer_gpo;
 
-	struct cphy_ops *ops;                /* PHY operations */
+	const struct cphy_ops *ops;            /* PHY operations */
 	int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr,
 			 int reg_addr, unsigned int *val);
 	int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr,
@@ -136,7 +136,7 @@ static inline int simple_mdio_write(stru
 /* Convenience initializer */
 static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
 			     int phy_addr, struct cphy_ops *phy_ops,
-			     struct mdio_ops *mdio_ops)
+			     const struct mdio_ops *mdio_ops)
 {
 	phy->adapter = adapter;
 	phy->addr    = phy_addr;
@@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy
 struct gphy {
 	/* Construct a PHY instance with the given PHY address */
 	struct cphy *(*create)(adapter_t *adapter, int phy_addr,
-			       struct mdio_ops *mdio_ops);
+			       const struct mdio_ops *mdio_ops);
 
 	/*
 	 * Reset the PHY chip.  This resets the whole PHY chip, not individual
@@ -160,11 +160,9 @@ struct gphy {
 	int (*reset)(adapter_t *adapter);
 };
 
-extern struct gphy t1_my3126_ops;
-extern struct gphy t1_mv88e1xxx_ops;
-extern struct gphy t1_vsc8244_ops;
-extern struct gphy t1_xpak_ops;
-extern struct gphy t1_mv88x201x_ops;
-extern struct gphy t1_dummy_phy_ops;
+extern const struct gphy t1_my3126_ops;
+extern const struct gphy t1_mv88e1xxx_ops;
+extern const struct gphy t1_vsc8244_ops;
+extern const struct gphy t1_mv88x201x_ops;
 
 #endif /* _CXGB_CPHY_H_ */
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index 006a2eb..d423374 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_insta
 struct cmac {
 	struct cmac_statistics stats;
 	adapter_t *adapter;
-	struct cmac_ops *ops;
+	const struct cmac_ops *ops;
 	cmac_instance *instance;
 };
 
@@ -136,11 +136,7 @@ struct gmac {
 	int (*reset)(adapter_t *);
 };
 
-extern struct gmac t1_pm3393_ops;
-extern struct gmac t1_chelsio_mac_ops;
-extern struct gmac t1_vsc7321_ops;
-extern struct gmac t1_vsc7326_ops;
-extern struct gmac t1_ixf1010_ops;
-extern struct gmac t1_dummy_mac_ops;
+extern const struct gmac t1_pm3393_ops;
+extern const struct gmac t1_vsc7326_ops;
 
 #endif /* _CXGB_GMAC_H_ */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
deleted file mode 100644
index 10b2a9a..0000000
--- a/drivers/net/chelsio/ixf1010.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */
-#include "gmac.h"
-#include "elmer0.h"
-
-/* Update fast changing statistics every 15 seconds */
-#define STATS_TICK_SECS 15
-/* 30 minutes for full statistics update */
-#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
-
-/*
- * The IXF1010 can handle frames up to 16383 bytes but it's optimized for
- * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this.
- * This length includes ethernet header and FCS.
- */
-#define MAX_FRAME_SIZE 0x2667
-
-/* MAC registers */
-enum {
-	/* Per-port registers */
-	REG_MACADDR_LOW = 0,
-	REG_MACADDR_HIGH = 0x4,
-	REG_FDFC_TYPE = 0xC,
-	REG_FC_TX_TIMER_VALUE = 0x1c,
-	REG_IPG_RX_TIME1 = 0x28,
-	REG_IPG_RX_TIME2 = 0x2c,
-	REG_IPG_TX_TIME = 0x30,
-	REG_PAUSE_THRES = 0x38,
-	REG_MAX_FRAME_SIZE = 0x3c,
-	REG_RGMII_SPEED = 0x40,
-	REG_FC_ENABLE = 0x48,
-	REG_DISCARD_CTRL_FRAMES = 0x54,
-	REG_DIVERSE_CONFIG = 0x60,
-	REG_RX_FILTER = 0x64,
-	REG_MC_ADDR_LOW = 0x68,
-	REG_MC_ADDR_HIGH = 0x6c,
-
-	REG_RX_OCTETS_OK = 0x80,
-	REG_RX_OCTETS_BAD = 0x84,
-	REG_RX_UC_PKTS = 0x88,
-	REG_RX_MC_PKTS = 0x8c,
-	REG_RX_BC_PKTS = 0x90,
-	REG_RX_FCS_ERR = 0xb0,
-	REG_RX_TAGGED = 0xb4,
-	REG_RX_DATA_ERR = 0xb8,
-	REG_RX_ALIGN_ERR = 0xbc,
-	REG_RX_LONG_ERR = 0xc0,
-	REG_RX_JABBER_ERR = 0xc4,
-	REG_RX_PAUSE_FRAMES = 0xc8,
-	REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc,
-	REG_RX_VERY_LONG_ERR = 0xd0,
-	REG_RX_RUNT_ERR = 0xd4,
-	REG_RX_SHORT_ERR = 0xd8,
-	REG_RX_SYMBOL_ERR = 0xe4,
-
-	REG_TX_OCTETS_OK = 0x100,
-	REG_TX_OCTETS_BAD = 0x104,
-	REG_TX_UC_PKTS = 0x108,
-	REG_TX_MC_PKTS = 0x10c,
-	REG_TX_BC_PKTS = 0x110,
-	REG_TX_EXCESSIVE_LEN_DROP = 0x14c,
-	REG_TX_UNDERRUN = 0x150,
-	REG_TX_TAGGED = 0x154,
-	REG_TX_PAUSE_FRAMES = 0x15C,
-
-	/* Global registers */
-	REG_PORT_ENABLE = 0x1400,
-
-	REG_JTAG_ID = 0x1430,
-
-	RX_FIFO_HIGH_WATERMARK_BASE = 0x1600,
-	RX_FIFO_LOW_WATERMARK_BASE = 0x1628,
-	RX_FIFO_FRAMES_REMOVED_BASE = 0x1650,
-
-	REG_RX_ERR_DROP = 0x167c,
-	REG_RX_FIFO_OVERFLOW_EVENT = 0x1680,
-
-	TX_FIFO_HIGH_WATERMARK_BASE = 0x1800,
-	TX_FIFO_LOW_WATERMARK_BASE = 0x1828,
-	TX_FIFO_XFER_THRES_BASE = 0x1850,
-
-	REG_TX_FIFO_OVERFLOW_EVENT = 0x1878,
-	REG_TX_FIFO_OOS_EVENT = 0x1884,
-
-	TX_FIFO_FRAMES_REMOVED_BASE = 0x1888,
-
-	REG_SPI_RX_BURST = 0x1c00,
-	REG_SPI_RX_TRAINING = 0x1c04,
-	REG_SPI_RX_CALENDAR = 0x1c08,
-	REG_SPI_TX_SYNC = 0x1c0c
-};
-
-enum {                     /* RMON registers */
-	REG_RxOctetsTotalOK = 0x80,
-	REG_RxOctetsBad = 0x84,
-	REG_RxUCPkts = 0x88,
-	REG_RxMCPkts = 0x8c,
-	REG_RxBCPkts = 0x90,
-	REG_RxJumboPkts = 0xac,
-	REG_RxFCSErrors = 0xb0,
-	REG_RxDataErrors = 0xb8,
-	REG_RxAlignErrors = 0xbc,
-	REG_RxLongErrors = 0xc0,
-	REG_RxJabberErrors = 0xc4,
-	REG_RxPauseMacControlCounter = 0xc8,
-	REG_RxVeryLongErrors = 0xd0,
-	REG_RxRuntErrors = 0xd4,
-	REG_RxShortErrors = 0xd8,
-	REG_RxSequenceErrors = 0xe0,
-	REG_RxSymbolErrors = 0xe4,
-
-	REG_TxOctetsTotalOK = 0x100,
-	REG_TxOctetsBad = 0x104,
-	REG_TxUCPkts = 0x108,
-	REG_TxMCPkts = 0x10c,
-	REG_TxBCPkts = 0x110,
-	REG_TxJumboPkts = 0x12C,
-	REG_TxTotalCollisions = 0x134,
-	REG_TxExcessiveLengthDrop = 0x14c,
-	REG_TxUnderrun = 0x150,
-	REG_TxCRCErrors = 0x158,
-	REG_TxPauseFrames = 0x15c
-};
-
-enum {
-	DIVERSE_CONFIG_PAD_ENABLE = 0x80,
-	DIVERSE_CONFIG_CRC_ADD = 0x40
-};
-
-#define MACREG_BASE            0
-#define MACREG(mac, mac_reg)   ((mac)->instance->mac_base + (mac_reg))
-
-struct _cmac_instance {
-	u32 mac_base;
-	u32 index;
-	u32 version;
-	u32 ticks;
-};
-
-static void disable_port(struct cmac *mac)
-{
-	u32 val;
-
-	t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val);
-	val &= ~(1 << mac->instance->index);
-	t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
-}
-
-/*
- * Read the current values of the RMON counters and add them to the cumulative
- * port statistics.  The HW RMON counters are cleared by this operation.
- */
-static void port_stats_update(struct cmac *mac)
-{
-	static struct {
-		unsigned int reg;
-		unsigned int offset;
-	} hw_stats[] = {
-
-#define HW_STAT(name, stat_name) \
-	{ REG_##name, \
-	  (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
-
-		/* Rx stats */
-		HW_STAT(RxOctetsTotalOK, RxOctetsOK),
-		HW_STAT(RxOctetsBad, RxOctetsBad),
-		HW_STAT(RxUCPkts, RxUnicastFramesOK),
-		HW_STAT(RxMCPkts, RxMulticastFramesOK),
-		HW_STAT(RxBCPkts, RxBroadcastFramesOK),
-		HW_STAT(RxJumboPkts, RxJumboFramesOK),
-		HW_STAT(RxFCSErrors, RxFCSErrors),
-		HW_STAT(RxAlignErrors, RxAlignErrors),
-		HW_STAT(RxLongErrors, RxFrameTooLongErrors),
-		HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
-		HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
-		HW_STAT(RxDataErrors, RxDataErrors),
-		HW_STAT(RxJabberErrors, RxJabberErrors),
-		HW_STAT(RxRuntErrors, RxRuntErrors),
-		HW_STAT(RxShortErrors, RxRuntErrors),
-		HW_STAT(RxSequenceErrors, RxSequenceErrors),
-		HW_STAT(RxSymbolErrors, RxSymbolErrors),
-
-		/* Tx stats (skip collision stats as we are full-duplex only) */
-		HW_STAT(TxOctetsTotalOK, TxOctetsOK),
-		HW_STAT(TxOctetsBad, TxOctetsBad),
-		HW_STAT(TxUCPkts, TxUnicastFramesOK),
-		HW_STAT(TxMCPkts, TxMulticastFramesOK),
-		HW_STAT(TxBCPkts, TxBroadcastFramesOK),
-		HW_STAT(TxJumboPkts, TxJumboFramesOK),
-		HW_STAT(TxPauseFrames, TxPauseFrames),
-		HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
-		HW_STAT(TxUnderrun, TxUnderrun),
-		HW_STAT(TxCRCErrors, TxFCSErrors)
-	}, *p = hw_stats;
-	u64 *stats = (u64 *) &mac->stats;
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
-		u32 val;
-
-		t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
-		stats[p->offset] += val;
-	}
-}
-
-/* No-op interrupt operation as this MAC does not support interrupts */
-static int mac_intr_op(struct cmac *mac)
-{
-	return 0;
-}
-
-/* Expect MAC address to be in network byte order. */
-static int mac_set_address(struct cmac *mac, u8 addr[6])
-{
-	u32 addr_lo, addr_hi;
-
-	addr_lo = addr[2];
-	addr_lo = (addr_lo << 8) | addr[3];
-	addr_lo = (addr_lo << 8) | addr[4];
-	addr_lo = (addr_lo << 8) | addr[5];
-
-	addr_hi = addr[0];
-	addr_hi = (addr_hi << 8) | addr[1];
-
-	t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo);
-	t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi);
-	return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
-	u32 addr_lo, addr_hi;
-
-	t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo);
-	t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi);
-
-	addr[0] = (u8) (addr_hi >> 8);
-	addr[1] = (u8) addr_hi;
-	addr[2] = (u8) (addr_lo >> 24);
-	addr[3] = (u8) (addr_lo >> 16);
-	addr[4] = (u8) (addr_lo >> 8);
-	addr[5] = (u8) addr_lo;
-	return 0;
-}
-
-/* This is intended to reset a port, not the whole MAC */
-static int mac_reset(struct cmac *mac)
-{
-	return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
-	u32 val, new_mode;
-	adapter_t *adapter = mac->adapter;
-	u32 addr_lo, addr_hi;
-	u8 *addr;
-
-	t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val);
-	new_mode = val & ~7;
-	if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0)
-		new_mode |= 1;     /* only set if version > 0 due to erratum */
-	if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm)
-	     && t1_rx_mode_mc_cnt(rm) <= 1)
-		new_mode |= 2;
-	if (new_mode != val)
-		t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode);
-	switch (t1_rx_mode_mc_cnt(rm)) {
-	case 0:
-		t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0);
-		t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0);
-		break;
-	case 1:
-		addr = t1_get_next_mcaddr(rm);
-		addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
-			addr[5];
-		addr_hi = (addr[0] << 8) | addr[1];
-		t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo);
-		t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi);
-		break;
-	default:
-		break;
-	}
-	return 0;
-}
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
-	/* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
-	if (mtu > (MAX_FRAME_SIZE - 14 - 4))
-		return -EINVAL;
-	t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
-		     mtu + 14 + 4);
-	return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
-				   int fc)
-{
-	u32 val;
-
-	if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000)
-		return -1;
-	if (duplex >= 0 && duplex != DUPLEX_FULL)
-		return -1;
-
-	if (speed >= 0) {
-		val = speed == SPEED_100 ? 1 : 2;
-		t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val);
-	}
-
-	t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
-	val &= ~3;
-	if (fc & PAUSE_RX)
-		val |= 1;
-	if (fc & PAUSE_TX)
-		val |= 2;
-	t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val);
-	return 0;
-}
-
-static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex,
-				   int *fc)
-{
-	u32 val;
-
-	if (duplex)
-		*duplex = DUPLEX_FULL;
-	if (speed) {
-		t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED),
-			 &val);
-		*speed = (val & 2) ? SPEED_1000 : SPEED_100;
-	}
-	if (fc) {
-		t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
-		*fc = 0;
-		if (val & 1)
-			*fc |= PAUSE_RX;
-		if (val & 2)
-			*fc |= PAUSE_TX;
-	}
-	return 0;
-}
-
-static void enable_port(struct cmac *mac)
-{
-	u32 val;
-	u32 index = mac->instance->index;
-	adapter_t *adapter = mac->adapter;
-
-	t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val);
-	val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE;
-	t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val);
-	if (mac->instance->version > 0)
-		t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3);
-	else /* Don't enable unicast address filtering due to IXF1010 bug */
-		t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2);
-
-	t1_tpi_read(adapter, REG_RX_ERR_DROP, &val);
-	val |= (1 << index);
-	t1_tpi_write(adapter, REG_RX_ERR_DROP, val);
-
-	/*
-	 * Clear the port RMON registers by adding their current values to the
-	 * cumulatice port stats and then clearing the stats.  Really.
-	 */
-	port_stats_update(mac);
-	memset(&mac->stats, 0, sizeof(struct cmac_statistics));
-	mac->instance->ticks = 0;
-
-	t1_tpi_read(adapter, REG_PORT_ENABLE, &val);
-	val |= (1 << index);
-	t1_tpi_write(adapter, REG_PORT_ENABLE, val);
-
-	index <<= 2;
-	if (is_T2(adapter)) {
-		/* T204: set the Fifo water level & threshold */
-		t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
-		t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
-		t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600);
-		t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0);
-		t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100);
-	} else {
-	/*
-	 * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around
-	 * Underrun problem. Intel has blessed this solution.
-	 */
-		t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400);
-	}
-}
-
-/* IXF1010 ports do not have separate enables for TX and RX */
-static int mac_enable(struct cmac *mac, int which)
-{
-	if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
-		enable_port(mac);
-	return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
-	if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
-		disable_port(mac);
-	return 0;
-}
-
-#define RMON_UPDATE(mac, name, stat_name) \
-	t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
-	(mac)->stats.stat_name += val;
-
-/*
- * This function is called periodically to accumulate the current values of the
- * RMON counters into the port statistics.  Since the counters are only 32 bits
- * some of them can overflow in less than a minute at GigE speeds, so this
- * function should be called every 30 seconds or so.
- *
- * To cut down on reading costs we update only the octet counters at each tick
- * and do a full update at major ticks, which can be every 30 minutes or more.
- */
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
-							   int flag)
-{
-	if (flag == MAC_STATS_UPDATE_FULL ||
-	    MAJOR_UPDATE_TICKS <= mac->instance->ticks) {
-		port_stats_update(mac);
-		mac->instance->ticks = 0;
-	} else {
-		u32 val;
-
-		RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
-		RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
-		mac->instance->ticks++;
-	}
-	return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
-	kfree(mac);
-}
-
-static struct cmac_ops ixf1010_ops = {
-	.destroy                  = mac_destroy,
-	.reset                    = mac_reset,
-	.interrupt_enable         = mac_intr_op,
-	.interrupt_disable        = mac_intr_op,
-	.interrupt_clear          = mac_intr_op,
-	.enable                   = mac_enable,
-	.disable                  = mac_disable,
-	.set_mtu                  = mac_set_mtu,
-	.set_rx_mode              = mac_set_rx_mode,
-	.set_speed_duplex_fc      = mac_set_speed_duplex_fc,
-	.get_speed_duplex_fc      = mac_get_speed_duplex_fc,
-	.statistics_update        = mac_update_statistics,
-	.macaddress_get           = mac_get_address,
-	.macaddress_set           = mac_set_address,
-};
-
-static int ixf1010_mac_reset(adapter_t *adapter)
-{
-	u32 val;
-
-	t1_tpi_read(adapter, A_ELMER0_GPO, &val);
-	if ((val & 1) != 0) {
-		val &= ~1;
-		t1_tpi_write(adapter, A_ELMER0_GPO, val);
-		udelay(2);
-	}
-	val |= 1;
-	t1_tpi_write(adapter, A_ELMER0_GPO, val);
-	udelay(2);
-
-	t1_tpi_write(adapter, REG_PORT_ENABLE, 0);
-	return 0;
-}
-
-static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
-{
-	struct cmac *mac;
-	u32 val;
-
-	if (index > 9)
-		return NULL;
-
-	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-	if (!mac)
-		return NULL;
-
-	mac->ops = &ixf1010_ops;
-	mac->instance = (cmac_instance *)(mac + 1);
-
-	mac->instance->mac_base = MACREG_BASE + (index * 0x200);
-	mac->instance->index    = index;
-	mac->adapter  = adapter;
-	mac->instance->ticks    = 0;
-
-	t1_tpi_read(adapter, REG_JTAG_ID, &val);
-	mac->instance->version = val >> 28;
-	return mac;
-}
-
-struct gmac t1_ixf1010_ops = {
-	STATS_TICK_SECS,
-	ixf1010_mac_create,
-	ixf1010_mac_reset
-};
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
index 6af39dc..1d97282 100644
--- a/drivers/net/chelsio/mac.c
+++ b/drivers/net/chelsio/mac.c
@@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t
 	return mac;
 }
 
-struct gmac t1_chelsio_mac_ops = {
+const struct gmac t1_chelsio_mac_ops = {
 	.create = mac_create
 };
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 5867e3b..0632be0 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = {
 };
 
 static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
-					 struct mdio_ops *mdio_ops)
+					 const struct mdio_ops *mdio_ops)
 {
 	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
@@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t
 	return 0;
 }
 
-struct gphy t1_mv88e1xxx_ops = {
-	mv88e1xxx_phy_create,
-	mv88e1xxx_phy_reset
+const struct gphy t1_mv88e1xxx_ops = {
+	.create = mv88e1xxx_phy_create,
+	.reset =  mv88e1xxx_phy_reset
 };
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c
index c8e8948..cd85604 100644
--- a/drivers/net/chelsio/mv88x201x.c
+++ b/drivers/net/chelsio/mv88x201x.c
@@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = {
 };
 
 static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr,
-					 struct mdio_ops *mdio_ops)
+					 const struct mdio_ops *mdio_ops)
 {
 	u32 val;
 	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t
 	return 0;
 }
 
-struct gphy t1_mv88x201x_ops = {
-	mv88x201x_phy_create,
-	mv88x201x_phy_reset
+const struct gphy t1_mv88x201x_ops = {
+	.create = mv88x201x_phy_create,
+	.reset = mv88x201x_phy_reset
 };
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 87dde3e..040acd2 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = {
 };
 
 static struct cphy *my3126_phy_create(adapter_t *adapter,
-			int phy_addr, struct mdio_ops *mdio_ops)
+			int phy_addr, const struct mdio_ops *mdio_ops)
 {
 	struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
 
@@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * 
 	return 0;
 }
 
-struct gphy t1_my3126_ops = {
-	my3126_phy_create,
-	my3126_phy_reset
+const struct gphy t1_my3126_ops = {
+	.create = my3126_phy_create,
+	.reset = my3126_phy_reset
 };
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 69129ed..678778a 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * 
 	return successful_reset ? 0 : 1;
 }
 
-struct gmac t1_pm3393_ops = {
-	STATS_TICK_SECS,
-	pm3393_mac_create,
-	pm3393_mac_reset
+const struct gmac t1_pm3393_ops = {
+	.stats_update_period = STATS_TICK_SECS,
+	.create              = pm3393_mac_create,
+	.reset               = pm3393_mac_reset,
 };
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 326d4a6..e4f874a 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1062,7 +1062,7 @@ static inline struct sk_buff *get_packet
 					    pci_unmap_addr(ce, dma_addr),
 					    pci_unmap_len(ce, dma_len),
 					    PCI_DMA_FROMDEVICE);
-		memcpy(skb->data, ce->skb->data, len);
+		skb_copy_from_linear_data(ce->skb, skb->data, len);
 		pci_dma_sync_single_for_device(pdev,
 					       pci_unmap_addr(ce, dma_addr),
 					       pci_unmap_len(ce, dma_len),
@@ -1379,12 +1379,11 @@ static void sge_rx(struct sge *sge, stru
 	}
 	__skb_pull(skb, sizeof(*p));
 
-	skb->dev = adapter->port[p->iff].dev;
 	skb->dev->last_rx = jiffies;
 	st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
 	st->rx_packets++;
 
-	skb->protocol = eth_type_trans(skb, skb->dev);
+	skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
 	if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
 	    skb->protocol == htons(ETH_P_IP) &&
 	    (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
@@ -1866,14 +1865,14 @@ int t1_start_xmit(struct sk_buff *skb, s
 
 		++st->tx_tso;
 
-		eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+		eth_type = skb_network_offset(skb) == ETH_HLEN ?
 			CPL_ETH_II : CPL_ETH_II_VLAN;
 
 		hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr));
 		hdr->opcode = CPL_TX_PKT_LSO;
 		hdr->ip_csum_dis = hdr->l4_csum_dis = 0;
-		hdr->ip_hdr_words = skb->nh.iph->ihl;
-		hdr->tcp_hdr_words = skb->h.th->doff;
+		hdr->ip_hdr_words = ip_hdr(skb)->ihl;
+		hdr->tcp_hdr_words = tcp_hdr(skb)->doff;
 		hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
 							  skb_shinfo(skb)->gso_size));
 		hdr->len = htonl(skb->len - sizeof(*hdr));
@@ -1913,7 +1912,7 @@ int t1_start_xmit(struct sk_buff *skb, s
 
 		if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
 		    skb->ip_summed == CHECKSUM_PARTIAL &&
-		    skb->nh.iph->protocol == IPPROTO_UDP) {
+		    ip_hdr(skb)->protocol == IPPROTO_UDP) {
 			if (unlikely(skb_checksum_help(skb))) {
 				pr_debug("%s: unable to do udp checksum\n", dev->name);
 				dev_kfree_skb_any(skb);
@@ -1926,7 +1925,7 @@ int t1_start_xmit(struct sk_buff *skb, s
 		 */
 		if ((unlikely(!adapter->sge->espibug_skb[dev->if_port]))) {
 			if (skb->protocol == htons(ETH_P_ARP) &&
-			    skb->nh.arph->ar_op == htons(ARPOP_REQUEST)) {
+			    arp_hdr(skb)->ar_op == htons(ARPOP_REQUEST)) {
 				adapter->sge->espibug_skb[dev->if_port] = skb;
 				/* We want to re-use this skb later. We
 				 * simply bump the reference count and it
@@ -2096,10 +2095,14 @@ static void espibug_workaround_t204(unsi
 					0x0, 0x7, 0x43, 0x0, 0x0, 0x0
 				};
 
-				memcpy(skb->data + sizeof(struct cpl_tx_pkt),
-					ch_mac_addr, ETH_ALEN);
-				memcpy(skb->data + skb->len - 10,
-					ch_mac_addr, ETH_ALEN);
+				skb_copy_to_linear_data_offset(skb,
+						    sizeof(struct cpl_tx_pkt),
+							       ch_mac_addr,
+							       ETH_ALEN);
+				skb_copy_to_linear_data_offset(skb,
+							       skb->len - 10,
+							       ch_mac_addr,
+							       ETH_ALEN);
 				skb->cb[0] = 0xff;
 			}
 
@@ -2126,10 +2129,14 @@ static void espibug_workaround(unsigned 
 	                if (!skb->cb[0]) {
 	                        u8 ch_mac_addr[ETH_ALEN] =
 	                            {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
-	                        memcpy(skb->data + sizeof(struct cpl_tx_pkt),
-	                               ch_mac_addr, ETH_ALEN);
-	                        memcpy(skb->data + skb->len - 10, ch_mac_addr,
-	                               ETH_ALEN);
+	                        skb_copy_to_linear_data_offset(skb,
+						     sizeof(struct cpl_tx_pkt),
+							       ch_mac_addr,
+							       ETH_ALEN);
+	                        skb_copy_to_linear_data_offset(skb,
+							       skb->len - 10,
+							       ch_mac_addr,
+							       ETH_ALEN);
 	                        skb->cb[0] = 0xff;
 	                }
 
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index c2522cd..7de9a61 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *ada
 }
 
 #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
-static struct mdio_ops mi1_mdio_ops = {
-	mi1_mdio_init,
-	mi1_mdio_read,
-	mi1_mdio_write
+static const struct mdio_ops mi1_mdio_ops = {
+	.init = mi1_mdio_init,
+	.read = mi1_mdio_read,
+	.write = mi1_mdio_write
 };
 #endif
 
@@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t 
 	return 0;
 }
 
-static struct mdio_ops mi1_mdio_ext_ops = {
-	mi1_mdio_init,
-	mi1_mdio_ext_read,
-	mi1_mdio_ext_write
+static const struct mdio_ops mi1_mdio_ext_ops = {
+	.init = mi1_mdio_init,
+	.read = mi1_mdio_ext_read,
+	.write = mi1_mdio_ext_write
 };
 
 enum {
@@ -392,63 +392,136 @@ enum {
 	CH_BRD_N204_4CU,
 };
 
-static struct board_info t1_board[] = {
-
-{ CHBT_BOARD_CHT110, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
-  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
-  125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
-  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_my3126_ops, &mi1_mdio_ext_ops,
-  "Chelsio T110 1x10GBase-CX4 TOE" },
-
-{ CHBT_BOARD_N110, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio N110 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_N210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio N210 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_88X2010,
-  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
-  "Chelsio T210 1x10GBaseX TOE" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
-  SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
-  CHBT_MAC_PM3393, CHBT_PHY_MY3126,
-  125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
-  1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
-  1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
-  &t1_my3126_ops, &mi1_mdio_ext_ops,
-  "Chelsio T210 1x10GBase-CX4 TOE" },
+static const struct board_info t1_board[] = {
+	{
+		.board		= CHBT_BOARD_CHT110,
+		.port_number	= 1,
+		.caps		= SUPPORTED_10000baseT_Full,
+		.chip_term	= CHBT_TERM_T1,
+		.chip_mac	= CHBT_MAC_PM3393,
+		.chip_phy	= CHBT_PHY_MY3126,
+		.clock_core	= 125000000,
+		.clock_mc3	= 150000000,
+		.clock_mc4	= 125000000,
+		.espi_nports	= 1,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 1,
+		.mdio_mdiinv	= 1,
+		.mdio_mdc	= 1,
+		.mdio_phybaseaddr = 1,
+		.gmac		= &t1_pm3393_ops,
+		.gphy		= &t1_my3126_ops,
+		.mdio_ops	= &mi1_mdio_ext_ops,
+		.desc		= "Chelsio T110 1x10GBase-CX4 TOE",
+	},
+
+	{
+		.board		= CHBT_BOARD_N110,
+		.port_number	= 1,
+		.caps		= SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+		.chip_term	= CHBT_TERM_T1,
+		.chip_mac	= CHBT_MAC_PM3393,
+		.chip_phy	= CHBT_PHY_88X2010,
+		.clock_core	= 125000000,
+		.espi_nports	= 1,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 0,
+		.mdio_mdiinv	= 0,
+		.mdio_mdc	= 1,
+		.mdio_phybaseaddr = 0,
+		.gmac		= &t1_pm3393_ops,
+		.gphy		= &t1_mv88x201x_ops,
+		.mdio_ops	= &mi1_mdio_ext_ops,
+		.desc		= "Chelsio N110 1x10GBaseX NIC",
+	},
+
+	{
+		.board		= CHBT_BOARD_N210,
+		.port_number	= 1,
+		.caps		= SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+		.chip_term	= CHBT_TERM_T2,
+		.chip_mac	= CHBT_MAC_PM3393,
+		.chip_phy	= CHBT_PHY_88X2010,
+		.clock_core	= 125000000,
+		.espi_nports	= 1,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 0,
+		.mdio_mdiinv	= 0,
+		.mdio_mdc	= 1,
+		.mdio_phybaseaddr = 0,
+		.gmac		= &t1_pm3393_ops,
+		.gphy		= &t1_mv88x201x_ops,
+		.mdio_ops	= &mi1_mdio_ext_ops,
+		.desc		= "Chelsio N210 1x10GBaseX NIC",
+	},
+
+	{
+		.board		= CHBT_BOARD_CHT210,
+		.port_number	= 1,
+		.caps		= SUPPORTED_10000baseT_Full,
+		.chip_term	= CHBT_TERM_T2,
+		.chip_mac	= CHBT_MAC_PM3393,
+		.chip_phy	= CHBT_PHY_88X2010,
+		.clock_core	= 125000000,
+		.clock_mc3	= 133000000,
+		.clock_mc4	= 125000000,
+		.espi_nports	= 1,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 0,
+		.mdio_mdiinv	= 0,
+		.mdio_mdc	= 1,
+		.mdio_phybaseaddr = 0,
+		.gmac		= &t1_pm3393_ops,
+		.gphy		= &t1_mv88x201x_ops,
+		.mdio_ops	= &mi1_mdio_ext_ops,
+		.desc		= "Chelsio T210 1x10GBaseX TOE",
+	},
+
+	{
+		.board		= CHBT_BOARD_CHT210,
+		.port_number	= 1,
+		.caps		= SUPPORTED_10000baseT_Full,
+		.chip_term	= CHBT_TERM_T2,
+		.chip_mac	= CHBT_MAC_PM3393,
+		.chip_phy	= CHBT_PHY_MY3126,
+		.clock_core	= 125000000,
+		.clock_mc3	= 133000000,
+		.clock_mc4	= 125000000,
+		.espi_nports	= 1,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 1,
+		.mdio_mdiinv	= 1,
+		.mdio_mdc	= 1,
+		.mdio_phybaseaddr = 1,
+		.gmac		= &t1_pm3393_ops,
+		.gphy		= &t1_my3126_ops,
+		.mdio_ops	= &mi1_mdio_ext_ops,
+		.desc		= "Chelsio T210 1x10GBase-CX4 TOE",
+	},
 
 #ifdef CONFIG_CHELSIO_T1_1G
-{ CHBT_BOARD_CHN204, 4/*ports#*/,
-  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
-  SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
-  SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
-  100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
-  4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
-  0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
-  &t1_mv88e1xxx_ops, &mi1_mdio_ops,
-  "Chelsio N204 4x100/1000BaseT NIC" },
+	{
+		.board		= CHBT_BOARD_CHN204,
+		.port_number	= 4,
+		.caps		= SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+				| SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+				| SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+				  SUPPORTED_PAUSE | SUPPORTED_TP,
+		.chip_term	= CHBT_TERM_T2,
+		.chip_mac	= CHBT_MAC_VSC7321,
+		.chip_phy	= CHBT_PHY_88E1111,
+		.clock_core	= 100000000,
+		.espi_nports	= 4,
+		.clock_elmer0	= 44,
+		.mdio_mdien	= 0,
+		.mdio_mdiinv	= 0,
+		.mdio_mdc	= 0,
+		.mdio_phybaseaddr = 4,
+		.gmac		= &t1_vsc7326_ops,
+		.gphy		= &t1_mv88e1xxx_ops,
+		.mdio_ops	= &mi1_mdio_ops,
+		.desc		= "Chelsio N204 4x100/1000BaseT NIC",
+	},
 #endif
 
 };
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 534ffa0..99b51f6 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *
 	return 0;
 }
 
-struct gmac t1_vsc7326_ops = {
+const struct gmac t1_vsc7326_ops = {
 	.stats_update_period = STATS_TICK_SECS,
 	.create              = vsc7326_mac_create,
 	.reset               = vsc7326_mac_reset,
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
deleted file mode 100644
index 251d485..0000000
--- a/drivers/net/chelsio/vsc8244.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file is part of the Chelsio T2 Ethernet driver.
- *
- * Copyright (C) 2005 Chelsio Communications.  All rights reserved.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
- * release for licensing terms and conditions.
- */
-
-#include "common.h"
-#include "cphy.h"
-#include "elmer0.h"
-
-#ifndef ADVERTISE_PAUSE_CAP
-# define ADVERTISE_PAUSE_CAP 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#ifndef MII_CTRL1000
-# define MII_CTRL1000 9
-#endif
-
-#ifndef ADVERTISE_1000FULL
-# define ADVERTISE_1000FULL 0x200
-# define ADVERTISE_1000HALF 0x100
-#endif
-
-/* VSC8244 PHY specific registers. */
-enum {
-	VSC8244_INTR_ENABLE   = 25,
-	VSC8244_INTR_STATUS   = 26,
-	VSC8244_AUX_CTRL_STAT = 28,
-};
-
-enum {
-	VSC_INTR_RX_ERR     = 1 << 0,
-	VSC_INTR_MS_ERR     = 1 << 1,  /* master/slave resolution error */
-	VSC_INTR_CABLE      = 1 << 2,  /* cable impairment */
-	VSC_INTR_FALSE_CARR = 1 << 3,  /* false carrier */
-	VSC_INTR_MEDIA_CHG  = 1 << 4,  /* AMS media change */
-	VSC_INTR_RX_FIFO    = 1 << 5,  /* Rx FIFO over/underflow */
-	VSC_INTR_TX_FIFO    = 1 << 6,  /* Tx FIFO over/underflow */
-	VSC_INTR_DESCRAMBL  = 1 << 7,  /* descrambler lock-lost */
-	VSC_INTR_SYMBOL_ERR = 1 << 8,  /* symbol error */
-	VSC_INTR_NEG_DONE   = 1 << 10, /* autoneg done */
-	VSC_INTR_NEG_ERR    = 1 << 11, /* autoneg error */
-	VSC_INTR_LINK_CHG   = 1 << 13, /* link change */
-	VSC_INTR_ENABLE     = 1 << 15, /* interrupt enable */
-};
-
-#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
-			   VSC_INTR_NEG_DONE)
-#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
-		   VSC_INTR_ENABLE)
-
-/* PHY specific auxiliary control & status register fields */
-#define S_ACSR_ACTIPHY_TMR    0
-#define M_ACSR_ACTIPHY_TMR    0x3
-#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
-
-#define S_ACSR_SPEED    3
-#define M_ACSR_SPEED    0x3
-#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
-
-#define S_ACSR_DUPLEX 5
-#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
-
-#define S_ACSR_ACTIPHY 6
-#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
-
-/*
- * Reset the PHY.  This PHY completes reset immediately so we never wait.
- */
-static int vsc8244_reset(struct cphy *cphy, int wait)
-{
-	int err;
-	unsigned int ctl;
-
-	err = simple_mdio_read(cphy, MII_BMCR, &ctl);
-	if (err)
-		return err;
-
-	ctl &= ~BMCR_PDOWN;
-	ctl |= BMCR_RESET;
-	return simple_mdio_write(cphy, MII_BMCR, ctl);
-}
-
-static int vsc8244_intr_enable(struct cphy *cphy)
-{
-	simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
-
-	/* Enable interrupts through Elmer */
-	if (t1_is_asic(cphy->adapter)) {
-		u32 elmer;
-
-		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
-		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter))
-		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
-	}
-
-	return 0;
-}
-
-static int vsc8244_intr_disable(struct cphy *cphy)
-{
-	simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0);
-
-	if (t1_is_asic(cphy->adapter)) {
-		u32 elmer;
-
-		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
-		elmer &= ~ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter))
-		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
-	}
-
-	return 0;
-}
-
-static int vsc8244_intr_clear(struct cphy *cphy)
-{
-	u32 val;
-	u32 elmer;
-
-	/* Clear PHY interrupts by reading the register. */
-	simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
-
-	if (t1_is_asic(cphy->adapter)) {
-		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
-		elmer |= ELMER0_GP_BIT1;
-		if (is_T2(cphy->adapter))
-		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
-	}
-
-	return 0;
-}
-
-/*
- * Force the PHY speed and duplex.  This also disables auto-negotiation, except
- * for 1Gb/s, where auto-negotiation is mandatory.
- */
-static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
-{
-	int err;
-	unsigned int ctl;
-
-	err = simple_mdio_read(phy, MII_BMCR, &ctl);
-	if (err)
-		return err;
-
-	if (speed >= 0) {
-		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
-		if (speed == SPEED_100)
-			ctl |= BMCR_SPEED100;
-		else if (speed == SPEED_1000)
-			ctl |= BMCR_SPEED1000;
-	}
-	if (duplex >= 0) {
-		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
-		if (duplex == DUPLEX_FULL)
-			ctl |= BMCR_FULLDPLX;
-	}
-	if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for 1Gb/s */
-		ctl |= BMCR_ANENABLE;
-	return simple_mdio_write(phy, MII_BMCR, ctl);
-}
-
-int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
-{
-	int ret;
-	unsigned int val;
-
-	ret = mdio_read(phy, mmd, reg, &val);
-	if (!ret)
-		ret = mdio_write(phy, mmd, reg, val | bits);
-	return ret;
-}
-
-static int vsc8244_autoneg_enable(struct cphy *cphy)
-{
-	return t1_mdio_set_bits(cphy, 0, MII_BMCR,
-				BMCR_ANENABLE | BMCR_ANRESTART);
-}
-
-static int vsc8244_autoneg_restart(struct cphy *cphy)
-{
-	return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART);
-}
-
-static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
-{
-	int err;
-	unsigned int val = 0;
-
-	err = simple_mdio_read(phy, MII_CTRL1000, &val);
-	if (err)
-		return err;
-
-	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-	if (advertise_map & ADVERTISED_1000baseT_Half)
-		val |= ADVERTISE_1000HALF;
-	if (advertise_map & ADVERTISED_1000baseT_Full)
-		val |= ADVERTISE_1000FULL;
-
-	err = simple_mdio_write(phy, MII_CTRL1000, val);
-	if (err)
-		return err;
-
-	val = 1;
-	if (advertise_map & ADVERTISED_10baseT_Half)
-		val |= ADVERTISE_10HALF;
-	if (advertise_map & ADVERTISED_10baseT_Full)
-		val |= ADVERTISE_10FULL;
-	if (advertise_map & ADVERTISED_100baseT_Half)
-		val |= ADVERTISE_100HALF;
-	if (advertise_map & ADVERTISED_100baseT_Full)
-		val |= ADVERTISE_100FULL;
-	if (advertise_map & ADVERTISED_PAUSE)
-		val |= ADVERTISE_PAUSE_CAP;
-	if (advertise_map & ADVERTISED_ASYM_PAUSE)
-		val |= ADVERTISE_PAUSE_ASYM;
-	return simple_mdio_write(phy, MII_ADVERTISE, val);
-}
-
-static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
-				   int *speed, int *duplex, int *fc)
-{
-	unsigned int bmcr, status, lpa, adv;
-	int err, sp = -1, dplx = -1, pause = 0;
-
-	err = simple_mdio_read(cphy, MII_BMCR, &bmcr);
-	if (!err)
-		err = simple_mdio_read(cphy, MII_BMSR, &status);
-	if (err)
-		return err;
-
-	if (link_ok) {
-		/*
-		 * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
-		 * once more to get the current link state.
-		 */
-		if (!(status & BMSR_LSTATUS))
-			err = simple_mdio_read(cphy, MII_BMSR, &status);
-		if (err)
-			return err;
-		*link_ok = (status & BMSR_LSTATUS) != 0;
-	}
-	if (!(bmcr & BMCR_ANENABLE)) {
-		dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-		if (bmcr & BMCR_SPEED1000)
-			sp = SPEED_1000;
-		else if (bmcr & BMCR_SPEED100)
-			sp = SPEED_100;
-		else
-			sp = SPEED_10;
-	} else if (status & BMSR_ANEGCOMPLETE) {
-		err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status);
-		if (err)
-			return err;
-
-		dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
-		sp = G_ACSR_SPEED(status);
-		if (sp == 0)
-			sp = SPEED_10;
-		else if (sp == 1)
-			sp = SPEED_100;
-		else
-			sp = SPEED_1000;
-
-		if (fc && dplx == DUPLEX_FULL) {
-			err = simple_mdio_read(cphy, MII_LPA, &lpa);
-			if (!err)
-				err = simple_mdio_read(cphy, MII_ADVERTISE,
-						       &adv);
-			if (err)
-				return err;
-
-			if (lpa & adv & ADVERTISE_PAUSE_CAP)
-				pause = PAUSE_RX | PAUSE_TX;
-			else if ((lpa & ADVERTISE_PAUSE_CAP) &&
-				 (lpa & ADVERTISE_PAUSE_ASYM) &&
-				 (adv & ADVERTISE_PAUSE_ASYM))
-				pause = PAUSE_TX;
-			else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
-				 (adv & ADVERTISE_PAUSE_CAP))
-				pause = PAUSE_RX;
-		}
-	}
-	if (speed)
-		*speed = sp;
-	if (duplex)
-		*duplex = dplx;
-	if (fc)
-		*fc = pause;
-	return 0;
-}
-
-static int vsc8244_intr_handler(struct cphy *cphy)
-{
-	unsigned int cause;
-	int err, cphy_cause = 0;
-
-	err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause);
-	if (err)
-		return err;
-
-	cause &= INTR_MASK;
-	if (cause & CFG_CHG_INTR_MASK)
-		cphy_cause |= cphy_cause_link_change;
-	if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
-		cphy_cause |= cphy_cause_fifo_error;
-	return cphy_cause;
-}
-
-static void vsc8244_destroy(struct cphy *cphy)
-{
-	kfree(cphy);
-}
-
-static struct cphy_ops vsc8244_ops = {
-	.destroy              = vsc8244_destroy,
-	.reset                = vsc8244_reset,
-	.interrupt_enable     = vsc8244_intr_enable,
-	.interrupt_disable    = vsc8244_intr_disable,
-	.interrupt_clear      = vsc8244_intr_clear,
-	.interrupt_handler    = vsc8244_intr_handler,
-	.autoneg_enable       = vsc8244_autoneg_enable,
-	.autoneg_restart      = vsc8244_autoneg_restart,
-	.advertise            = vsc8244_advertise,
-	.set_speed_duplex     = vsc8244_set_speed_duplex,
-	.get_link_status      = vsc8244_get_link_status
-};
-
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
-				       struct mdio_ops *mdio_ops)
-{
-	struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
-
-	if (!cphy)
-		return NULL;
-
-	cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
-
-	return cphy;
-}
-
-
-static int vsc8244_phy_reset(adapter_t* adapter)
-{
-	return 0;
-}
-
-struct gphy t1_vsc8244_ops = {
-	vsc8244_phy_create,
-	vsc8244_phy_reset
-};
-
-
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h
deleted file mode 100644
index d3c1829..0000000
--- a/drivers/net/chelsio/vsc8244_reg.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */
-#ifndef CHELSIO_MV8E1XXX_H
-#define CHELSIO_MV8E1XXX_H
-
-#ifndef BMCR_SPEED1000
-# define BMCR_SPEED1000 0x40
-#endif
-
-#ifndef ADVERTISE_PAUSE
-# define ADVERTISE_PAUSE 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#define MII_GBMR 1       /* 1000Base-T mode register */
-#define MII_GBCR 9       /* 1000Base-T control register */
-#define MII_GBSR 10      /* 1000Base-T status register */
-
-/* 1000Base-T control register fields */
-#define GBCR_ADV_1000HALF         0x100
-#define GBCR_ADV_1000FULL         0x200
-#define GBCR_PREFER_MASTER        0x400
-#define GBCR_MANUAL_AS_MASTER     0x800
-#define GBCR_MANUAL_CONFIG_ENABLE 0x1000
-
-/* 1000Base-T status register fields */
-#define GBSR_LP_1000HALF  0x400
-#define GBSR_LP_1000FULL  0x800
-#define GBSR_REMOTE_OK    0x1000
-#define GBSR_LOCAL_OK     0x2000
-#define GBSR_LOCAL_MASTER 0x4000
-#define GBSR_MASTER_FAULT 0x8000
-
-/* Vitesse PHY interrupt status bits. */
-#if 0
-#define VSC8244_INTR_JABBER          0x0001
-#define VSC8244_INTR_POLARITY_CHNG   0x0002
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-#define VSC8244_INTR_DOWNSHIFT       0x0020
-#define VSC8244_INTR_MDI_XOVER_CHNG  0x0040
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_FALSE_CARRIER   0x0100
-#define VSC8244_INTR_SYMBOL_ERROR    0x0200
-#define VSC8244_INTR_LINK_CHNG       0x0400
-#define VSC8244_INTR_AUTONEG_DONE    0x0800
-#define VSC8244_INTR_PAGE_RECV       0x1000
-#define VSC8244_INTR_DUPLEX_CHNG     0x2000
-#define VSC8244_INTR_SPEED_CHNG      0x4000
-#define VSC8244_INTR_AUTONEG_ERR     0x8000
-#else
-//#define VSC8244_INTR_JABBER          0x0001
-//#define VSC8244_INTR_POLARITY_CHNG   0x0002
-//#define VSC8244_INTR_BIT2            0x0004
-//#define VSC8244_INTR_BIT3            0x0008
-#define VSC8244_INTR_RX_ERR          0x0001
-#define VSC8244_INTR_MASTER_SLAVE    0x0002
-#define VSC8244_INTR_CABLE_IMPAIRED  0x0004
-#define VSC8244_INTR_FALSE_CARRIER   0x0008
-//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-//#define VSC8244_INTR_DOWNSHIFT       0x0020
-//#define VSC8244_INTR_MDI_XOVER_CHNG  0x0040
-//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_BIT4            0x0010
-#define VSC8244_INTR_FIFO_RX         0x0020
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040
-#define VSC8244_INTR_LOCK_LOST       0x0080
-//#define VSC8244_INTR_FALSE_CARRIER   0x0100
-//#define VSC8244_INTR_SYMBOL_ERROR    0x0200
-//#define VSC8244_INTR_LINK_CHNG       0x0400
-//#define VSC8244_INTR_AUTONEG_DONE    0x0800
-#define VSC8244_INTR_SYMBOL_ERROR    0x0100
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200
-#define VSC8244_INTR_AUTONEG_DONE    0x0400
-#define VSC8244_INTR_AUTONEG_ERR     0x0800
-//#define VSC8244_INTR_PAGE_RECV       0x1000
-//#define VSC8244_INTR_DUPLEX_CHNG     0x2000
-//#define VSC8244_INTR_SPEED_CHNG      0x4000
-//#define VSC8244_INTR_AUTONEG_ERR     0x8000
-#define VSC8244_INTR_DUPLEX_CHNG     0x1000
-#define VSC8244_INTR_LINK_CHNG       0x2000
-#define VSC8244_INTR_SPEED_CHNG      0x4000
-#define VSC8244_INTR_STATUS          0x8000
-#endif
-
-
-/* Vitesse PHY specific registers. */
-#define VSC8244_SPECIFIC_CNTRL_REGISTER               16
-#define VSC8244_SPECIFIC_STATUS_REGISTER              0x1c
-#define VSC8244_INTERRUPT_ENABLE_REGISTER             0x19
-#define VSC8244_INTERRUPT_STATUS_REGISTER             0x1a
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER       20
-#define VSC8244_RECV_ERR_CNTR_REGISTER                21
-#define VSC8244_RES_REGISTER                          22
-#define VSC8244_GLOBAL_STATUS_REGISTER                23
-#define VSC8244_LED_CONTROL_REGISTER                  24
-#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER          25
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER     26
-#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER      27
-#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER         28
-#define VSC8244_EXTENDED_ADDR_REGISTER                29
-#define VSC8244_EXTENDED_REGISTER                     30
-
-/* PHY specific control register fields */
-#define S_PSCR_MDI_XOVER_MODE    5
-#define M_PSCR_MDI_XOVER_MODE    0x3
-#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
-#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE)
-
-/* Extended PHY specific control register fields */
-#define S_DOWNSHIFT_ENABLE 8
-#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
-
-#define S_DOWNSHIFT_CNT    9
-#define M_DOWNSHIFT_CNT    0x7
-#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
-#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT)
-
-/* PHY specific status register fields */
-#define S_PSSR_JABBER 0
-#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
-
-#define S_PSSR_POLARITY 1
-#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
-
-#define S_PSSR_RX_PAUSE 2
-#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
-
-#define S_PSSR_TX_PAUSE 3
-#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
-
-#define S_PSSR_ENERGY_DETECT 4
-#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
-
-#define S_PSSR_DOWNSHIFT_STATUS 5
-#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
-
-#define S_PSSR_MDI 6
-#define V_PSSR_MDI (1 << S_PSSR_MDI)
-
-#define S_PSSR_CABLE_LEN    7
-#define M_PSSR_CABLE_LEN    0x7
-#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
-#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
-
-//#define S_PSSR_LINK 10
-//#define S_PSSR_LINK 13
-#define S_PSSR_LINK 2
-#define V_PSSR_LINK (1 << S_PSSR_LINK)
-
-//#define S_PSSR_STATUS_RESOLVED 11
-//#define S_PSSR_STATUS_RESOLVED 10
-#define S_PSSR_STATUS_RESOLVED 15
-#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
-
-#define S_PSSR_PAGE_RECEIVED 12
-#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
-
-//#define S_PSSR_DUPLEX 13
-//#define S_PSSR_DUPLEX 12
-#define S_PSSR_DUPLEX 5
-#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
-
-//#define S_PSSR_SPEED    14
-//#define S_PSSR_SPEED    14
-#define S_PSSR_SPEED    3
-#define M_PSSR_SPEED    0x3
-#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
-#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
-
-#endif
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 8eb5712..5bdf5ca 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1348,7 +1348,8 @@ #endif
 
 #ifdef ETHDEBUG
 		printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
-		  skb->head, skb->data, skb->tail, skb->end);
+		       skb->head, skb->data, skb_tail_pointer(skb),
+		       skb_end_pointer(skb));
 		printk("copying packet to 0x%x.\n", skb_data_ptr);
 #endif
 
@@ -1375,7 +1376,6 @@ #endif
 		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
 	}
 
-	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 
 	/* Send the packet to the upper layers */
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 4612f71..9774bb1 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1004,7 +1004,6 @@ skip_this_frame:
 		return;
 	}
 	skb_reserve(skb, 2);	/* longword align L3 header */
-	skb->dev = dev;
 
 	if (bp + length > lp->end_dma_buff) {
 		int semi_cnt = lp->end_dma_buff - bp;
@@ -1702,7 +1701,6 @@ #endif
 		return;
 	}
 	skb_reserve(skb, 2);	/* longword align L3 header */
-	skb->dev = dev;
 
 	readwords(ioaddr, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
 	if (length & 1)
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 199e506..ebcf35e 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -783,7 +783,7 @@ static int do_trace(struct t3cdev *dev, 
 	skb->protocol = htons(0xffff);
 	skb->dev = dev->lldev;
 	skb_pull(skb, sizeof(*p));
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	netif_receive_skb(skb);
 	return 0;
 }
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 027ab2c..3666586 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -661,7 +661,7 @@ static inline struct sk_buff *get_imm_pa
 
 	if (skb) {
 		__skb_put(skb, IMMED_PKT_SIZE);
-		memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+		skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE);
 	}
 	return skb;
 }
@@ -897,11 +897,11 @@ static void write_tx_pkt_wr(struct adapt
 		d->flit[2] = 0;
 		cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
 		hdr->cntrl = htonl(cntrl);
-		eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+		eth_type = skb_network_offset(skb) == ETH_HLEN ?
 		    CPL_ETH_II : CPL_ETH_II_VLAN;
 		tso_info |= V_LSO_ETH_TYPE(eth_type) |
-		    V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
-		    V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+		    V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) |
+		    V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff);
 		hdr->lso_info = htonl(tso_info);
 		flits = 3;
 	} else {
@@ -913,7 +913,8 @@ static void write_tx_pkt_wr(struct adapt
 		if (skb->len <= WR_LEN - sizeof(*cpl)) {
 			q->sdesc[pidx].skb = NULL;
 			if (!skb->data_len)
-				memcpy(&d->flit[2], skb->data, skb->len);
+				skb_copy_from_linear_data(skb, &d->flit[2],
+							  skb->len);
 			else
 				skb_copy_bits(skb, 0, &d->flit[2], skb->len);
 
@@ -1319,16 +1320,19 @@ static void write_ofld_wr(struct adapter
 	/* Only TX_DATA builds SGLs */
 
 	from = (struct work_request_hdr *)skb->data;
-	memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+	memcpy(&d->flit[1], &from[1],
+	       skb_transport_offset(skb) - sizeof(*from));
 
-	flits = (skb->h.raw - skb->data) / 8;
+	flits = skb_transport_offset(skb) / 8;
 	sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
-	sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+	sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
+			     skb->tail - skb->transport_header,
 			     adap->pdev);
 	if (need_skb_unmap()) {
 		setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
 		skb->destructor = deferred_unmap_destructor;
-		((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+		((struct unmap_info *)skb->cb)->len = (skb->tail -
+						       skb->transport_header);
 	}
 
 	write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
@@ -1349,8 +1353,8 @@ static inline unsigned int calc_tx_descs
 	if (skb->len <= WR_LEN && cnt == 0)
 		return 1;	/* packet fits as immediate data */
 
-	flits = (skb->h.raw - skb->data) / 8;	/* headers */
-	if (skb->tail != skb->h.raw)
+	flits = skb_transport_offset(skb) / 8;	/* headers */
+	if (skb->tail != skb->transport_header)
 		cnt++;
 	return flits_to_desc(flits + sgl_len(cnt));
 }
@@ -1620,7 +1624,9 @@ static inline int rx_offload(struct t3cd
 			     unsigned int gather_idx)
 {
 	rq->offload_pkts++;
-	skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
 
 	if (rq->polling) {
 		rx_gather[gather_idx++] = skb;
@@ -1684,9 +1690,8 @@ static void rx_eth(struct adapter *adap,
 	struct port_info *pi;
 
 	skb_pull(skb, sizeof(*p) + pad);
-	skb->dev = adap->port[p->iff];
 	skb->dev->last_rx = jiffies;
-	skb->protocol = eth_type_trans(skb, skb->dev);
+	skb->protocol = eth_type_trans(skb, adap->port[p->iff]);
 	pi = netdev_priv(skb->dev);
 	if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
 	    !p->fragment) {
@@ -1717,11 +1722,11 @@ static void skb_data_init(struct sk_buff
 {
 	skb->len = len;
 	if (len <= SKB_DATA_SIZE) {
-		memcpy(skb->data, p->va, len);
+		skb_copy_to_linear_data(skb, p->va, len);
 		skb->tail += len;
 		put_page(p->frag.page);
 	} else {
-		memcpy(skb->data, p->va, SKB_DATA_SIZE);
+		skb_copy_to_linear_data(skb, p->va, SKB_DATA_SIZE);
 		skb_shinfo(skb)->frags[0].page = p->frag.page;
 		skb_shinfo(skb)->frags[0].page_offset =
 		    p->frag.page_offset + SKB_DATA_SIZE;
@@ -1767,7 +1772,7 @@ static struct sk_buff *get_packet(struct
 			__skb_put(skb, len);
 			pci_dma_sync_single_for_cpu(adap->pdev, mapping, len,
 						    PCI_DMA_FROMDEVICE);
-			memcpy(skb->data, sd->t.skb->data, len);
+			skb_copy_from_linear_data(sd->t.skb, skb->data, len);
 			pci_dma_sync_single_for_device(adap->pdev, mapping, len,
 						       PCI_DMA_FROMDEVICE);
 		} else if (!drop_thres)
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 042e27e..b112317 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -38,7 +38,7 @@ #define DRV_NAME "cxgb3"
 #define DRV_VERSION "1.0-ko"
 
 /* Firmware version */
-#define FW_VERSION_MAJOR 3
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MAJOR 4
+#define FW_VERSION_MINOR 0
 #define FW_VERSION_MICRO 0
 #endif				/* __CHELSIO_VERSION_H */
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index e547ce1..dae97b8 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -359,7 +359,6 @@ static void de600_rx_intr(struct net_dev
 	}
 	/* else */
 
-	skb->dev = dev;
 	skb_reserve(skb,2);	/* Align */
 
 	/* 'skb->data' points to the start of sk_buff data area. */
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index b6ad0cb..dc48924 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -697,7 +697,6 @@ static int de620_rx_intr(struct net_devi
 		}
 		else { /* Yep! Go get it! */
 			skb_reserve(skb,2);	/* Align */
-			skb->dev = dev;
 			/* skb->data points to the start of sk_buff data area */
 			buffer = skb_put(skb,size);
 			/* copy the packet into the buffer */
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 9f7e1db..95d854e 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -616,7 +616,6 @@ #endif
 			}
 			lp->stats.rx_bytes += len;
 
-			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte align */
 			skb_put(skb, len);	/* make room */
 
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 07d2731..571d82f 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3091,13 +3091,13 @@ #endif
 					{
 						/* Receive buffer allocated, pass receive packet up */
 
-						memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
+						skb_copy_to_linear_data(skb,
+							       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 */
-
 					skb->protocol = fddi_type_trans(skb, bp->dev);
 					bp->rcv_total_bytes += skb->len;
 					netif_rx(skb);
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index f3807aa..1834970 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1044,7 +1044,6 @@ static int depca_rx(struct net_device *d
 					unsigned char *buf;
 					skb_reserve(skb, 2);	/* 16 byte align the IP header */
 					buf = skb_put(skb, pkt_len);
-					skb->dev = dev;
 					if (entry < lp->rx_old) {	/* Wrapped buffer */
 						len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
 						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index a795202..df62c02 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -503,7 +503,6 @@ dgrs_rcv_frame(
 		/* discarding the frame */
 		goto out;
 	}
-	skb->dev = devN;
 	skb_reserve(skb, 2);	/* Align IP header */
 
 again:
@@ -742,7 +741,7 @@ static int dgrs_start_xmit(struct sk_buf
 		}
 
 		amt = min_t(unsigned int, len, rbdp->size - count);
-		memcpy( (char *) S2H(rbdp->buf) + count, skb->data + i, amt);
+		skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt);
 		i += amt;
 		count += amt;
 		len -= amt;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 9d446a0..74ec64a 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -504,7 +504,6 @@ rio_timer (unsigned long data)
 					break;
 				}
 				np->rx_skbuff[entry] = skb;
-				skb->dev = dev;
 				/* 16 byte align the IP header */
 				skb_reserve (skb, 2);
 				np->rx_ring[entry].fraginfo =
@@ -575,7 +574,6 @@ alloc_list (struct net_device *dev)
 				dev->name);
 			break;
 		}
-		skb->dev = dev;	/* Mark as being used by this device. */
 		skb_reserve (skb, 2);	/* 16 byte align the IP header. */
 		/* Rubicon now supports 40 bits of addressing space. */
 		np->rx_ring[i].fraginfo =
@@ -866,7 +864,6 @@ receive_packet (struct net_device *dev)
 							    	DMA_48BIT_MASK,
 							    np->rx_buf_sz,
 							    PCI_DMA_FROMDEVICE);
-				skb->dev = dev;
 				/* 16 byte align the IP header */
 				skb_reserve (skb, 2);
 				eth_copy_and_sum (skb,
@@ -910,7 +907,6 @@ #endif
 				break;
 			}
 			np->rx_skbuff[entry] = skb;
-			skb->dev = dev;
 			/* 16 byte align the IP header */
 			skb_reserve (skb, 2);
 			np->rx_ring[entry].fraginfo =
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 615d2b1..264fa0e 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -77,9 +77,6 @@ #include "dm9000.h"
 
 #define DM9000_PHY		0x40	/* PHY address 0x01 */
 
-#define TRUE			1
-#define FALSE			0
-
 #define CARDNAME "dm9000"
 #define PFX CARDNAME ": "
 
@@ -601,7 +598,7 @@ #endif
 	printk("%s: not found (%d).\n", CARDNAME, ret);
 
 	dm9000_release_board(pdev, db);
-	kfree(ndev);
+	free_netdev(ndev);
 
 	return ret;
 }
@@ -896,7 +893,7 @@ dm9000_rx(struct net_device *dev)
 	struct dm9000_rxhdr rxhdr;
 	struct sk_buff *skb;
 	u8 rxbyte, *rdptr;
-	int GoodPacket;
+	bool GoodPacket;
 	int RxLen;
 
 	/* Check packet ready or not */
@@ -918,7 +915,7 @@ dm9000_rx(struct net_device *dev)
 			return;
 
 		/* A packet ready now  & Get status/length */
-		GoodPacket = TRUE;
+		GoodPacket = true;
 		writeb(DM9000_MRCMD, db->io_addr);
 
 		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
@@ -927,7 +924,7 @@ dm9000_rx(struct net_device *dev)
 
 		/* Packet Status check */
 		if (RxLen < 0x40) {
-			GoodPacket = FALSE;
+			GoodPacket = false;
 			PRINTK1("Bad Packet received (runt)\n");
 		}
 
@@ -936,7 +933,7 @@ dm9000_rx(struct net_device *dev)
 		}
 
 		if (rxhdr.RxStatus & 0xbf00) {
-			GoodPacket = FALSE;
+			GoodPacket = false;
 			if (rxhdr.RxStatus & 0x100) {
 				PRINTK1("fifo error\n");
 				db->stats.rx_fifo_errors++;
@@ -954,7 +951,6 @@ dm9000_rx(struct net_device *dev)
 		/* Move data from DM9000 */
 		if (GoodPacket
 		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
-			skb->dev = dev;
 			skb_reserve(skb, 2);
 			rdptr = (u8 *) skb_put(skb, RxLen - 4);
 
@@ -1194,7 +1190,7 @@ dm9000_drv_remove(struct platform_device
 
 	unregister_netdev(ndev);
 	dm9000_release_board(pdev, (board_info_t *) ndev->priv);
-	kfree(ndev);		/* free device structure */
+	free_netdev(ndev);		/* free device structure */
 
 	PRINTK1("clean_module() exit\n");
 
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 0cefef5..6169663 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -159,7 +159,7 @@ #include <asm/unaligned.h>
 
 #define DRV_NAME		"e100"
 #define DRV_EXT			"-NAPI"
-#define DRV_VERSION		"3.5.17-k2"DRV_EXT
+#define DRV_VERSION		"3.5.17-k4"DRV_EXT
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel Corporation"
 #define PFX			DRV_NAME ": "
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION);
 
 static int debug = 3;
 static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
 module_param(debug, int, 0);
 module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
 #define DPRINTK(nlevel, klevel, fmt, args...) \
 	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -282,12 +285,6 @@ enum scb_status {
 	rus_mask         = 0x3C,
 };
 
-enum ru_state  {
-	RU_SUSPENDED = 0,
-	RU_RUNNING	 = 1,
-	RU_UNINITIALIZED = -1,
-};
-
 enum scb_stat_ack {
 	stat_ack_not_ours    = 0x00,
 	stat_ack_sw_gen      = 0x04,
@@ -529,7 +526,6 @@ struct nic {
 	struct rx *rx_to_use;
 	struct rx *rx_to_clean;
 	struct rfd blank_rfd;
-	enum ru_state ru_running;
 
 	spinlock_t cb_lock			____cacheline_aligned;
 	spinlock_t cmd_lock;
@@ -591,7 +587,7 @@ static inline void e100_write_flush(stru
 {
 	/* Flush previous PCI writes through intermediate bridges
 	 * by doing a benign read */
-	(void)readb(&nic->csr->scb.status);
+	(void)ioread8(&nic->csr->scb.status);
 }
 
 static void e100_enable_irq(struct nic *nic)
@@ -599,7 +595,7 @@ static void e100_enable_irq(struct nic *
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->cmd_lock, flags);
-	writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+	iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -609,7 +605,7 @@ static void e100_disable_irq(struct nic 
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->cmd_lock, flags);
-	writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+	iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -618,11 +614,11 @@ static void e100_hw_reset(struct nic *ni
 {
 	/* Put CU and RU into idle with a selective reset to get
 	 * device off of PCI bus */
-	writel(selective_reset, &nic->csr->port);
+	iowrite32(selective_reset, &nic->csr->port);
 	e100_write_flush(nic); udelay(20);
 
 	/* Now fully reset device */
-	writel(software_reset, &nic->csr->port);
+	iowrite32(software_reset, &nic->csr->port);
 	e100_write_flush(nic); udelay(20);
 
 	/* Mask off our interrupt line - it's unmasked after reset */
@@ -639,7 +635,7 @@ static int e100_self_test(struct nic *ni
 	nic->mem->selftest.signature = 0;
 	nic->mem->selftest.result = 0xFFFFFFFF;
 
-	writel(selftest | dma_addr, &nic->csr->port);
+	iowrite32(selftest | dma_addr, &nic->csr->port);
 	e100_write_flush(nic);
 	/* Wait 10 msec for self-test to complete */
 	msleep(10);
@@ -677,23 +673,23 @@ static void e100_eeprom_write(struct nic
 	for(j = 0; j < 3; j++) {
 
 		/* Chip select */
-		writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
 		for(i = 31; i >= 0; i--) {
 			ctrl = (cmd_addr_data[j] & (1 << i)) ?
 				eecs | eedi : eecs;
-			writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+			iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
 			e100_write_flush(nic); udelay(4);
 
-			writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+			iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
 			e100_write_flush(nic); udelay(4);
 		}
 		/* Wait 10 msec for cmd to complete */
 		msleep(10);
 
 		/* Chip deselect */
-		writeb(0, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(0, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 	}
 };
@@ -709,21 +705,21 @@ static u16 e100_eeprom_read(struct nic *
 	cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
 
 	/* Chip select */
-	writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+	iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
 	e100_write_flush(nic); udelay(4);
 
 	/* Bit-bang to read word from eeprom */
 	for(i = 31; i >= 0; i--) {
 		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
-		writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
-		writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
 		/* Eeprom drives a dummy zero to EEDO after receiving
 		 * complete address.  Use this to adjust addr_len. */
-		ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+		ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
 		if(!(ctrl & eedo) && i > 16) {
 			*addr_len -= (i - 16);
 			i = 17;
@@ -733,7 +729,7 @@ static u16 e100_eeprom_read(struct nic *
 	}
 
 	/* Chip deselect */
-	writeb(0, &nic->csr->eeprom_ctrl_lo);
+	iowrite8(0, &nic->csr->eeprom_ctrl_lo);
 	e100_write_flush(nic); udelay(4);
 
 	return le16_to_cpu(data);
@@ -804,7 +800,7 @@ static int e100_exec_cmd(struct nic *nic
 
 	/* Previous command is accepted when SCB clears */
 	for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
-		if(likely(!readb(&nic->csr->scb.cmd_lo)))
+		if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
 			break;
 		cpu_relax();
 		if(unlikely(i > E100_WAIT_SCB_FAST))
@@ -816,8 +812,8 @@ static int e100_exec_cmd(struct nic *nic
 	}
 
 	if(unlikely(cmd != cuc_resume))
-		writel(dma_addr, &nic->csr->scb.gen_ptr);
-	writeb(cmd, &nic->csr->scb.cmd_lo);
+		iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+	iowrite8(cmd, &nic->csr->scb.cmd_lo);
 
 err_unlock:
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
@@ -895,7 +891,7 @@ static u16 mdio_ctrl(struct nic *nic, u3
 	 */
 	spin_lock_irqsave(&nic->mdio_lock, flags);
 	for (i = 100; i; --i) {
-		if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+		if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
 			break;
 		udelay(20);
 	}
@@ -905,11 +901,11 @@ static u16 mdio_ctrl(struct nic *nic, u3
 		spin_unlock_irqrestore(&nic->mdio_lock, flags);
 		return 0;		/* No way to indicate timeout error */
 	}
-	writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+	iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
 
 	for (i = 0; i < 100; i++) {
 		udelay(20);
-		if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+		if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready)
 			break;
 	}
 	spin_unlock_irqrestore(&nic->mdio_lock, flags);
@@ -951,7 +947,7 @@ static void e100_get_defaults(struct nic
 		((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
 	/* Template for a freshly allocated RFD */
-	nic->blank_rfd.command = cpu_to_le16(cb_el);
+	nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s);
 	nic->blank_rfd.rbd = 0xFFFFFFFF;
 	nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
 
@@ -1318,7 +1314,7 @@ static inline int e100_exec_cb_wait(stru
 	}
 
 	/* ack any interupts, something could have been set */
-	writeb(~0, &nic->csr->scb.stat_ack);
+	iowrite8(~0, &nic->csr->scb.stat_ack);
 
 	/* if the command failed, or is not OK, notify and return */
 	if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
@@ -1580,7 +1576,7 @@ static void e100_watchdog(unsigned long 
 	 * accidentally, due to hardware that shares a register between the
 	 * interrupt mask bit and the SW Interrupt generation bit */
 	spin_lock_irq(&nic->cmd_lock);
-	writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+	iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irq(&nic->cmd_lock);
 
@@ -1746,19 +1742,11 @@ static int e100_alloc_cbs(struct nic *ni
 	return 0;
 }
 
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static inline void e100_start_receiver(struct nic *nic)
 {
-	if(!nic->rxs) return;
-	if(RU_SUSPENDED != nic->ru_running) return;
-
-	/* handle init time starts */
-	if(!rx) rx = nic->rxs;
-
-	/* (Re)start RU if suspended or idle and RFA is non-NULL */
-	if(rx->skb) {
-		e100_exec_cmd(nic, ruc_start, rx->dma_addr);
-		nic->ru_running = RU_RUNNING;
-	}
+	/* Start if RFA is non-NULL */
+	if(nic->rx_to_clean->skb)
+		e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
@@ -1769,7 +1757,7 @@ static int e100_rx_alloc_skb(struct nic 
 
 	/* Align, init, and map the RFD. */
 	skb_reserve(rx->skb, NET_IP_ALIGN);
-	memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
+	skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd));
 	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
 		RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
 
@@ -1787,7 +1775,7 @@ static int e100_rx_alloc_skb(struct nic 
 		put_unaligned(cpu_to_le32(rx->dma_addr),
 			(u32 *)&prev_rfd->link);
 		wmb();
-		prev_rfd->command &= ~cpu_to_le16(cb_el);
+		prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s);
 		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
 			sizeof(struct rfd), PCI_DMA_TODEVICE);
 	}
@@ -1825,10 +1813,6 @@ static int e100_rx_indicate(struct nic *
 	pci_unmap_single(nic->pdev, rx->dma_addr,
 		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
-	/* this allows for a fast restart without re-enabling interrupts */
-	if(le16_to_cpu(rfd->command) & cb_el)
-		nic->ru_running = RU_SUSPENDED;
-
 	/* Pull off the RFD and put the actual data (minus eth hdr) */
 	skb_reserve(skb, sizeof(struct rfd));
 	skb_put(skb, actual_size);
@@ -1859,45 +1843,18 @@ static void e100_rx_clean(struct nic *ni
 	unsigned int work_to_do)
 {
 	struct rx *rx;
-	int restart_required = 0;
-	struct rx *rx_to_start = NULL;
-
-	/* are we already rnr? then pay attention!!! this ensures that
-	 * the state machine progression never allows a start with a
-	 * partially cleaned list, avoiding a race between hardware
-	 * and rx_to_clean when in NAPI mode */
-	if(RU_SUSPENDED == nic->ru_running)
-		restart_required = 1;
 
 	/* Indicate newly arrived packets */
 	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
-		if(-EAGAIN == err) {
-			/* hit quota so have more work to do, restart once
-			 * cleanup is complete */
-			restart_required = 0;
-			break;
-		} else if(-ENODATA == err)
+		if(e100_rx_indicate(nic, rx, work_done, work_to_do))
 			break; /* No more to clean */
 	}
 
-	/* save our starting point as the place we'll restart the receiver */
-	if(restart_required)
-		rx_to_start = nic->rx_to_clean;
-
 	/* Alloc new skbs to refill list */
 	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
 		if(unlikely(e100_rx_alloc_skb(nic, rx)))
 			break; /* Better luck next time (see watchdog) */
 	}
-
-	if(restart_required) {
-		// ack the rnr?
-		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
-		e100_start_receiver(nic, rx_to_start);
-		if(work_done)
-			(*work_done)++;
-	}
 }
 
 static void e100_rx_clean_list(struct nic *nic)
@@ -1905,8 +1862,6 @@ static void e100_rx_clean_list(struct ni
 	struct rx *rx;
 	unsigned int i, count = nic->params.rfds.count;
 
-	nic->ru_running = RU_UNINITIALIZED;
-
 	if(nic->rxs) {
 		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
 			if(rx->skb) {
@@ -1928,7 +1883,6 @@ static int e100_rx_alloc_list(struct nic
 	unsigned int i, count = nic->params.rfds.count;
 
 	nic->rx_to_use = nic->rx_to_clean = NULL;
-	nic->ru_running = RU_UNINITIALIZED;
 
 	if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
 		return -ENOMEM;
@@ -1943,7 +1897,6 @@ static int e100_rx_alloc_list(struct nic
 	}
 
 	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
-	nic->ru_running = RU_SUSPENDED;
 
 	return 0;
 }
@@ -1952,7 +1905,7 @@ static irqreturn_t e100_intr(int irq, vo
 {
 	struct net_device *netdev = dev_id;
 	struct nic *nic = netdev_priv(netdev);
-	u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+	u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
 
 	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
 
@@ -1961,11 +1914,7 @@ static irqreturn_t e100_intr(int irq, vo
 		return IRQ_NONE;
 
 	/* Ack interrupt(s) */
-	writeb(stat_ack, &nic->csr->scb.stat_ack);
-
-	/* We hit Receive No Resource (RNR); restart RU after cleaning */
-	if(stat_ack & stat_ack_rnr)
-		nic->ru_running = RU_SUSPENDED;
+	iowrite8(stat_ack, &nic->csr->scb.stat_ack);
 
 	if(likely(netif_rx_schedule_prep(netdev))) {
 		e100_disable_irq(nic);
@@ -2058,7 +2007,7 @@ static int e100_up(struct nic *nic)
 	if((err = e100_hw_init(nic)))
 		goto err_clean_cbs;
 	e100_set_multicast_list(nic->netdev);
-	e100_start_receiver(nic, NULL);
+	e100_start_receiver(nic);
 	mod_timer(&nic->watchdog, jiffies);
 	if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
 		nic->netdev->name, nic->netdev)))
@@ -2107,7 +2056,7 @@ static void e100_tx_timeout_task(struct 
 	struct net_device *netdev = nic->netdev;
 
 	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
-		readb(&nic->csr->scb.status));
+		ioread8(&nic->csr->scb.status));
 	e100_down(netdev_priv(netdev));
 	e100_up(netdev_priv(netdev));
 }
@@ -2139,7 +2088,7 @@ static int e100_loopback_test(struct nic
 		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
 			BMCR_LOOPBACK);
 
-	e100_start_receiver(nic, NULL);
+	e100_start_receiver(nic);
 
 	if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
 		err = -ENOMEM;
@@ -2230,9 +2179,9 @@ static void e100_get_regs(struct net_dev
 	int i;
 
 	regs->version = (1 << 24) | nic->rev_id;
-	buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
-		readb(&nic->csr->scb.cmd_lo) << 16 |
-		readw(&nic->csr->scb.status);
+	buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+		ioread8(&nic->csr->scb.cmd_lo) << 16 |
+		ioread16(&nic->csr->scb.status);
 	for(i = E100_PHY_REGS; i >= 0; i--)
 		buff[1 + E100_PHY_REGS - i] =
 			mdio_read(netdev, nic->mii.phy_id, i);
@@ -2604,7 +2553,10 @@ #endif
 	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
-	nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
+	if (use_io)
+		DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+	nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
 	if(!nic->csr) {
 		DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
 		err = -ENOMEM;
@@ -2651,11 +2603,16 @@ #endif
 
 	memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
 	memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
-	if(!is_valid_ether_addr(netdev->perm_addr)) {
-		DPRINTK(PROBE, ERR, "Invalid MAC address from "
-			"EEPROM, aborting.\n");
-		err = -EAGAIN;
-		goto err_out_free;
+	if (!is_valid_ether_addr(netdev->perm_addr)) {
+		if (!eeprom_bad_csum_allow) {
+			DPRINTK(PROBE, ERR, "Invalid MAC address from "
+			        "EEPROM, aborting.\n");
+			err = -EAGAIN;
+			goto err_out_free;
+		} else {
+			DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
+			        "you MUST configure one.\n");
+		}
 	}
 
 	/* Wol magic packet can be enabled from eeprom */
@@ -2676,7 +2633,7 @@ #endif
 
 	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
 		"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-		(unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
 		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
 		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
 
@@ -2685,7 +2642,7 @@ #endif
 err_out_free:
 	e100_free(nic);
 err_out_iounmap:
-	iounmap(nic->csr);
+	pci_iounmap(pdev, nic->csr);
 err_out_free_res:
 	pci_release_regions(pdev);
 err_out_disable_pdev:
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index dd4b728..a9ea67e 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -155,9 +155,6 @@ #define E1000_MNG_VLAN_NONE -1
 /* Number of packet split data buffers (not including the header buffer) */
 #define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1
 
-/* only works for sizes that are powers of 2 */
-#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct e1000_buffer {
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 6777887..bb08375 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *n
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_tx_ring *txdr, *tx_old;
 	struct e1000_rx_ring *rxdr, *rx_old;
-	int i, err, tx_ring_size, rx_ring_size;
+	int i, err;
 
 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
 		return -EINVAL;
 
-	tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
-	rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-
 	while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
 		msleep(1);
 
@@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *n
 	rx_old = adapter->rx_ring;
 
 	err = -ENOMEM;
-	txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+	txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
 	if (!txdr)
 		goto err_alloc_tx;
 
-	rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+	rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
 	if (!rxdr)
 		goto err_alloc_rx;
 
@@ -686,12 +683,12 @@ e1000_set_ringparam(struct net_device *n
 	rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
 	rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
 		E1000_MAX_RXD : E1000_MAX_82544_RXD));
-	E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+	rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
 
 	txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD);
 	txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ?
 		E1000_MAX_TXD : E1000_MAX_82544_TXD));
-	E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+	txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
 	for (i = 0; i < adapter->num_tx_queues; i++)
 		txdr[i].count = txdr->count;
@@ -742,7 +739,7 @@ #define REG_PATTERN_TEST(R, M, W)       
 	uint32_t pat, value;                                                   \
 	uint32_t test[] =                                                      \
 		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};              \
-	for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) {              \
+	for (pat = 0; pat < ARRAY_SIZE(test); pat++) {              \
 		E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
 		value = E1000_READ_REG(&adapter->hw, R);                       \
 		if (value != (test[pat] & W & M)) {                             \
@@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adap
 	struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
 	struct pci_dev *pdev = adapter->pdev;
 	uint32_t rctl;
-	int size, i, ret_val;
+	int i, ret_val;
 
 	/* Setup Tx descriptor ring and Tx buffers */
 
 	if (!txdr->count)
 		txdr->count = E1000_DEFAULT_TXD;
 
-	size = txdr->count * sizeof(struct e1000_buffer);
-	if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+	if (!(txdr->buffer_info = kcalloc(txdr->count,
+	                                  sizeof(struct e1000_buffer),
+		                          GFP_KERNEL))) {
 		ret_val = 1;
 		goto err_nomem;
 	}
-	memset(txdr->buffer_info, 0, size);
 
 	txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
-	E1000_ROUNDUP(txdr->size, 4096);
-	if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+	txdr->size = ALIGN(txdr->size, 4096);
+	if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size,
+	                                        &txdr->dma))) {
 		ret_val = 2;
 		goto err_nomem;
 	}
@@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adap
 	if (!rxdr->count)
 		rxdr->count = E1000_DEFAULT_RXD;
 
-	size = rxdr->count * sizeof(struct e1000_buffer);
-	if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+	if (!(rxdr->buffer_info = kcalloc(rxdr->count,
+	                                  sizeof(struct e1000_buffer),
+	                                  GFP_KERNEL))) {
 		ret_val = 4;
 		goto err_nomem;
 	}
-	memset(rxdr->buffer_info, 0, size);
 
 	rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
 	if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index b28a915..3a03a74 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -409,25 +409,21 @@ e1000_release_hw_control(struct e1000_ad
 {
 	uint32_t ctrl_ext;
 	uint32_t swsm;
-	uint32_t extcnf;
 
 	/* Let firmware taken over control of h/w */
 	switch (adapter->hw.mac_type) {
-	case e1000_82571:
-	case e1000_82572:
-	case e1000_80003es2lan:
-		ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
-		E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
-				ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
-		break;
 	case e1000_82573:
 		swsm = E1000_READ_REG(&adapter->hw, SWSM);
 		E1000_WRITE_REG(&adapter->hw, SWSM,
 				swsm & ~E1000_SWSM_DRV_LOAD);
+		break;
+	case e1000_82571:
+	case e1000_82572:
+	case e1000_80003es2lan:
 	case e1000_ich8lan:
-		extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+		ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
 		E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
-				extcnf & ~E1000_CTRL_EXT_DRV_LOAD);
+				ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
 		break;
 	default:
 		break;
@@ -450,26 +446,21 @@ e1000_get_hw_control(struct e1000_adapte
 {
 	uint32_t ctrl_ext;
 	uint32_t swsm;
-	uint32_t extcnf;
 
 	/* Let firmware know the driver has taken over */
 	switch (adapter->hw.mac_type) {
-	case e1000_82571:
-	case e1000_82572:
-	case e1000_80003es2lan:
-		ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
-		E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
-				ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
-		break;
 	case e1000_82573:
 		swsm = E1000_READ_REG(&adapter->hw, SWSM);
 		E1000_WRITE_REG(&adapter->hw, SWSM,
 				swsm | E1000_SWSM_DRV_LOAD);
 		break;
+	case e1000_82571:
+	case e1000_82572:
+	case e1000_80003es2lan:
 	case e1000_ich8lan:
-		extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL);
-		E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL,
-				extcnf | E1000_EXTCNF_CTRL_SWFLAG);
+		ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+		E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+				ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
 		break;
 	default:
 		break;
@@ -522,14 +513,15 @@ e1000_release_manageability(struct e1000
 	}
 }
 
-int
-e1000_up(struct e1000_adapter *adapter)
+/**
+ * e1000_configure - configure the hardware for RX and TX
+ * @adapter = private board structure
+ **/
+static void e1000_configure(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 	int i;
 
-	/* hardware has been reset, we need to reload some things */
-
 	e1000_set_multi(netdev);
 
 	e1000_restore_vlan(adapter);
@@ -548,14 +540,20 @@ e1000_up(struct e1000_adapter *adapter)
 	}
 
 	adapter->tx_queue_len = netdev->tx_queue_len;
+}
+
+int e1000_up(struct e1000_adapter *adapter)
+{
+	/* hardware has been reset, we need to reload some things */
+	e1000_configure(adapter);
+
+	clear_bit(__E1000_DOWN, &adapter->flags);
 
 #ifdef CONFIG_E1000_NAPI
-	netif_poll_enable(netdev);
+	netif_poll_enable(adapter->netdev);
 #endif
 	e1000_irq_enable(adapter);
 
-	clear_bit(__E1000_DOWN, &adapter->flags);
-
 	/* fire a link change interrupt to start the watchdog */
 	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC);
 	return 0;
@@ -640,15 +638,15 @@ e1000_down(struct e1000_adapter *adapter
 	 * reschedule our watchdog timer */
 	set_bit(__E1000_DOWN, &adapter->flags);
 
+#ifdef CONFIG_E1000_NAPI
+	netif_poll_disable(netdev);
+#endif
 	e1000_irq_disable(adapter);
 
 	del_timer_sync(&adapter->tx_fifo_stall_timer);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
 
-#ifdef CONFIG_E1000_NAPI
-	netif_poll_disable(netdev);
-#endif
 	netdev->tx_queue_len = adapter->tx_queue_len;
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
@@ -750,9 +748,9 @@ e1000_reset(struct e1000_adapter *adapte
 		               VLAN_TAG_SIZE;
 		min_tx_space = min_rx_space;
 		min_tx_space *= 2;
-		E1000_ROUNDUP(min_tx_space, 1024);
+		min_tx_space = ALIGN(min_tx_space, 1024);
 		min_tx_space >>= 10;
-		E1000_ROUNDUP(min_rx_space, 1024);
+		min_rx_space = ALIGN(min_rx_space, 1024);
 		min_rx_space >>= 10;
 
 		/* If current Tx allocation is less than the min Tx FIFO size,
@@ -1356,31 +1354,27 @@ #endif
 static int __devinit
 e1000_alloc_queues(struct e1000_adapter *adapter)
 {
-	int size;
-
-	size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
-	adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+	                           sizeof(struct e1000_tx_ring), GFP_KERNEL);
 	if (!adapter->tx_ring)
 		return -ENOMEM;
-	memset(adapter->tx_ring, 0, size);
 
-	size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-	adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+	adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+	                           sizeof(struct e1000_rx_ring), GFP_KERNEL);
 	if (!adapter->rx_ring) {
 		kfree(adapter->tx_ring);
 		return -ENOMEM;
 	}
-	memset(adapter->rx_ring, 0, size);
 
 #ifdef CONFIG_E1000_NAPI
-	size = sizeof(struct net_device) * adapter->num_rx_queues;
-	adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+	adapter->polling_netdev = kcalloc(adapter->num_rx_queues,
+	                                  sizeof(struct net_device),
+	                                  GFP_KERNEL);
 	if (!adapter->polling_netdev) {
 		kfree(adapter->tx_ring);
 		kfree(adapter->rx_ring);
 		return -ENOMEM;
 	}
-	memset(adapter->polling_netdev, 0, size);
 #endif
 
 	return E1000_SUCCESS;
@@ -1410,21 +1404,17 @@ e1000_open(struct net_device *netdev)
 		return -EBUSY;
 
 	/* allocate transmit descriptors */
-	if ((err = e1000_setup_all_tx_resources(adapter)))
+	err = e1000_setup_all_tx_resources(adapter);
+	if (err)
 		goto err_setup_tx;
 
 	/* allocate receive descriptors */
-	if ((err = e1000_setup_all_rx_resources(adapter)))
-		goto err_setup_rx;
-
-	err = e1000_request_irq(adapter);
+	err = e1000_setup_all_rx_resources(adapter);
 	if (err)
-		goto err_req_irq;
+		goto err_setup_rx;
 
 	e1000_power_up_phy(adapter);
 
-	if ((err = e1000_up(adapter)))
-		goto err_up;
 	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
 	if ((adapter->hw.mng_cookie.status &
 			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
@@ -1437,12 +1427,33 @@ e1000_open(struct net_device *netdev)
 	    e1000_check_mng_mode(&adapter->hw))
 		e1000_get_hw_control(adapter);
 
+	/* before we allocate an interrupt, we must be ready to handle it.
+	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+	 * as soon as we call pci_request_irq, so we have to setup our
+	 * clean_rx handler before we do so.  */
+	e1000_configure(adapter);
+
+	err = e1000_request_irq(adapter);
+	if (err)
+		goto err_req_irq;
+
+	/* From here on the code is the same as e1000_up() */
+	clear_bit(__E1000_DOWN, &adapter->flags);
+
+#ifdef CONFIG_E1000_NAPI
+	netif_poll_enable(netdev);
+#endif
+
+	e1000_irq_enable(adapter);
+
+	/* fire a link status change interrupt to start the watchdog */
+	E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_LSC);
+
 	return E1000_SUCCESS;
 
-err_up:
-	e1000_power_down_phy(adapter);
-	e1000_free_irq(adapter);
 err_req_irq:
+	e1000_release_hw_control(adapter);
+	e1000_power_down_phy(adapter);
 	e1000_free_all_rx_resources(adapter);
 err_setup_rx:
 	e1000_free_all_tx_resources(adapter);
@@ -1545,7 +1556,7 @@ e1000_setup_tx_resources(struct e1000_ad
 	/* round up to nearest 4K */
 
 	txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
-	E1000_ROUNDUP(txdr->size, 4096);
+	txdr->size = ALIGN(txdr->size, 4096);
 
 	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
 	if (!txdr->desc) {
@@ -1759,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_ad
 	}
 	memset(rxdr->buffer_info, 0, size);
 
-	size = sizeof(struct e1000_ps_page) * rxdr->count;
-	rxdr->ps_page = kmalloc(size, GFP_KERNEL);
+	rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
+	                        GFP_KERNEL);
 	if (!rxdr->ps_page) {
 		vfree(rxdr->buffer_info);
 		DPRINTK(PROBE, ERR,
 		"Unable to allocate memory for the receive descriptor ring\n");
 		return -ENOMEM;
 	}
-	memset(rxdr->ps_page, 0, size);
 
-	size = sizeof(struct e1000_ps_page_dma) * rxdr->count;
-	rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL);
+	rxdr->ps_page_dma = kcalloc(rxdr->count,
+	                            sizeof(struct e1000_ps_page_dma),
+	                            GFP_KERNEL);
 	if (!rxdr->ps_page_dma) {
 		vfree(rxdr->buffer_info);
 		kfree(rxdr->ps_page);
@@ -1778,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_ad
 		"Unable to allocate memory for the receive descriptor ring\n");
 		return -ENOMEM;
 	}
-	memset(rxdr->ps_page_dma, 0, size);
 
 	if (adapter->hw.mac_type <= e1000_82547_rev_2)
 		desc_len = sizeof(struct e1000_rx_desc);
@@ -1788,7 +1798,7 @@ e1000_setup_rx_resources(struct e1000_ad
 	/* Round up to nearest 4K */
 
 	rxdr->size = rxdr->count * desc_len;
-	E1000_ROUNDUP(rxdr->size, 4096);
+	rxdr->size = ALIGN(rxdr->size, 4096);
 
 	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
@@ -2652,7 +2662,7 @@ e1000_watchdog(unsigned long data)
 
 			netif_carrier_on(netdev);
 			netif_wake_queue(netdev);
-			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+			mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
 			adapter->smartspeed = 0;
 		} else {
 			/* make sure the receive unit is started */
@@ -2669,7 +2679,7 @@ e1000_watchdog(unsigned long data)
 			DPRINTK(LINK, INFO, "NIC Link is Down\n");
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
-			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+			mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
 
 			/* 80003ES2LAN workaround--
 			 * For packet buffer work-around on link down event;
@@ -2721,7 +2731,7 @@ e1000_watchdog(unsigned long data)
 		e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
 
 	/* Reset the timer */
-	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+	mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
 }
 
 enum latency_range {
@@ -2887,33 +2897,30 @@ e1000_tso(struct e1000_adapter *adapter,
 				return err;
 		}
 
-		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 		mss = skb_shinfo(skb)->gso_size;
 		if (skb->protocol == htons(ETH_P_IP)) {
-			skb->nh.iph->tot_len = 0;
-			skb->nh.iph->check = 0;
-			skb->h.th->check =
-				~csum_tcpudp_magic(skb->nh.iph->saddr,
-						   skb->nh.iph->daddr,
-						   0,
-						   IPPROTO_TCP,
-						   0);
+			struct iphdr *iph = ip_hdr(skb);
+			iph->tot_len = 0;
+			iph->check = 0;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
 			cmd_length = E1000_TXD_CMD_IP;
-			ipcse = skb->h.raw - skb->data - 1;
+			ipcse = skb_transport_offset(skb) - 1;
 		} 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,
-						 &skb->nh.ipv6h->daddr,
-						 0,
-						 IPPROTO_TCP,
-						 0);
+			ipv6_hdr(skb)->payload_len = 0;
+			tcp_hdr(skb)->check =
+				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						 &ipv6_hdr(skb)->daddr,
+						 0, IPPROTO_TCP, 0);
 			ipcse = 0;
 		}
-		ipcss = skb->nh.raw - skb->data;
-		ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
-		tucss = skb->h.raw - skb->data;
-		tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
+		ipcss = skb_network_offset(skb);
+		ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
+		tucss = skb_transport_offset(skb);
+		tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
 		tucse = 0;
 
 		cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
@@ -2954,7 +2961,7 @@ e1000_tx_csum(struct e1000_adapter *adap
 	uint8_t css;
 
 	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
-		css = skb->h.raw - skb->data;
+		css = skb_transport_offset(skb);
 
 		i = tx_ring->next_to_use;
 		buffer_info = &tx_ring->buffer_info[i];
@@ -2962,7 +2969,8 @@ e1000_tx_csum(struct e1000_adapter *adap
 
 		context_desc->lower_setup.ip_config = 0;
 		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
+		context_desc->upper_setup.tcp_fields.tucso =
+			css + skb->csum_offset;
 		context_desc->upper_setup.tcp_fields.tucse = 0;
 		context_desc->tcp_seg_setup.data = 0;
 		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -3162,7 +3170,7 @@ e1000_82547_fifo_workaround(struct e1000
 	uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
 	uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
 
-	E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+	skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR);
 
 	if (adapter->link_duplex != HALF_DUPLEX)
 		goto no_fifo_stall_required;
@@ -3296,7 +3304,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 		/* TSO Workaround for 82571/2/3 Controllers -- if skb->data
 		* points to just header, pull a few bytes of payload from
 		* frags into skb->data */
-		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 		if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) {
 			switch (adapter->hw.mac_type) {
 				unsigned int pull_size;
@@ -3307,7 +3315,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
 				 * NOTE: this is a TSO only workaround
 				 * if end byte alignment not correct move us
 				 * into the next dword */
-				if ((unsigned long)(skb->tail - 1) & 4)
+				if ((unsigned long)(skb_tail_pointer(skb) - 1) & 4)
 					break;
 				/* fall through */
 			case e1000_82571:
@@ -3363,12 +3371,9 @@ e1000_xmit_frame(struct sk_buff *skb, st
 	    (adapter->hw.mac_type == e1000_82573))
 		e1000_transfer_dhcp_info(adapter, skb);
 
-	local_irq_save(flags);
-	if (!spin_trylock(&tx_ring->tx_lock)) {
+	if (!spin_trylock_irqsave(&tx_ring->tx_lock, flags))
 		/* Collision - tell upper layer to requeue */
-		local_irq_restore(flags);
 		return NETDEV_TX_LOCKED;
-	}
 
 	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
@@ -4227,9 +4232,12 @@ #endif
 			    netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
 			if (new_skb) {
 				skb_reserve(new_skb, NET_IP_ALIGN);
-				memcpy(new_skb->data - NET_IP_ALIGN,
-				       skb->data - NET_IP_ALIGN,
-				       length + NET_IP_ALIGN);
+				skb_copy_to_linear_data_offset(new_skb,
+							       -NET_IP_ALIGN,
+							       (skb->data -
+							        NET_IP_ALIGN),
+							       (length +
+							        NET_IP_ALIGN));
 				/* save the skb in buffer_info as good */
 				buffer_info->skb = skb;
 				skb = new_skb;
@@ -4391,7 +4399,7 @@ #endif
 				PCI_DMA_FROMDEVICE);
 			vaddr = kmap_atomic(ps_page->ps_page[0],
 			                    KM_SKB_DATA_SOFTIRQ);
-			memcpy(skb->tail, vaddr, l1);
+			memcpy(skb_tail_pointer(skb), vaddr, l1);
 			kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
 			pci_dma_sync_single_for_device(pdev,
 				ps_page_dma->ps_page_dma[0],
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index f8862e2..f485874 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter
 		if (num_TxDescriptors > bd) {
 			tx_ring->count = TxDescriptors[bd];
 			e1000_validate_option(&tx_ring->count, &opt, adapter);
-			E1000_ROUNDUP(tx_ring->count,
+			tx_ring->count = ALIGN(tx_ring->count,
 						REQ_TX_DESCRIPTOR_MULTIPLE);
 		} else {
 			tx_ring->count = opt.def;
@@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter
 		if (num_RxDescriptors > bd) {
 			rx_ring->count = RxDescriptors[bd];
 			e1000_validate_option(&rx_ring->count, &opt, adapter);
-			E1000_ROUNDUP(rx_ring->count,
+			rx_ring->count = ALIGN(rx_ring->count,
 						REQ_RX_DESCRIPTOR_MULTIPLE);
 		} else {
 			rx_ring->count = opt.def;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index b446309..39654e1 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1591,7 +1591,6 @@ eepro_rx(struct net_device *dev)
 
 				break;
 			}
-			skb->dev = dev;
 			skb_reserve(skb,2);
 
 			if (lp->version == LAN595)
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index e28bb1e..6c267c3 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1793,7 +1793,6 @@ speedo_rx(struct net_device *dev)
 			   copying to a properly sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
@@ -1805,8 +1804,9 @@ #if 1 || USE_IP_CSUM
 				eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data,
-					   pkt_len);
+				skb_copy_from_linear_data(sp->rx_skbuff[entry],
+							  skb_put(skb, pkt_len),
+							  pkt_len);
 #endif
 				pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
 											   sizeof(struct RxFD) + pkt_len,
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 3868b80..7934ea3 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -115,6 +115,7 @@ #include <linux/slab.h>
 #include <linux/mca-legacy.h>
 #include <linux/spinlock.h>
 #include <linux/bitops.h>
+#include <linux/jiffies.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -556,7 +557,7 @@ static void unstick_cu(struct net_device
 
 	if (lp->started)
 	{
-		if ((jiffies - dev->trans_start)>50)
+		if (time_after(jiffies, dev->trans_start + 50))
 		{
 			if (lp->tx_link==lp->last_tx_restart)
 			{
@@ -612,7 +613,7 @@ static void unstick_cu(struct net_device
 	}
 	else
 	{
-		if ((jiffies-lp->init_time)>10)
+		if (time_after(jiffies, lp->init_time + 10))
 		{
 			unsigned short status = scb_status(dev);
 			printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
@@ -776,7 +777,7 @@ #endif
 static void eexp_cmd_clear(struct net_device *dev)
 {
 	unsigned long int oldtime = jiffies;
-	while (scb_rdcmd(dev) && ((jiffies-oldtime)<10));
+	while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
 	if (scb_rdcmd(dev)) {
 		printk("%s: command didn't clear\n", dev->name);
 	}
@@ -976,7 +977,6 @@ #endif
 					lp->stats.rx_dropped++;
 					break;
 				}
-				skb->dev = dev;
 				skb_reserve(skb, 2);
 				outw(pbuf+10, ioaddr+READ_PTR);
 			        insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);
@@ -1650,7 +1650,7 @@ #if 0
 #endif
                 oj = jiffies;
                 while ((SCB_CUstat(scb_status(dev)) == 2) &&
-                       ((jiffies-oj) < 2000));
+                       (time_before(jiffies, oj + 2000)));
 		if (SCB_CUstat(scb_status(dev)) == 2)
 			printk("%s: warning, CU didn't stop\n", dev->name);
                 lp->started &= ~(STARTED_CU);
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 42295d6..602872d 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@ #include <asm/abs_addr.h>
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0046"
+#define DRV_VERSION	"EHEA_0058"
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
 	| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -78,10 +78,7 @@ #define EHEA_MAX_PACKET_SIZE    9022	/* 
 #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
@@ -108,11 +105,7 @@ #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
 
@@ -311,6 +304,7 @@ struct ehea_cq {
  * Memory Region
  */
 struct ehea_mr {
+	struct ehea_adapter *adapter;
 	u64 handle;
 	u64 vaddr;
 	u32 lkey;
@@ -319,17 +313,12 @@ struct ehea_mr {
 /*
  * Port state information
  */
-struct port_state {
-	int poll_max_processed;
+struct port_stats {
 	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;
+	int err_tcp_cksum;
+	int err_ip_cksum;
+	int err_frame_crc;
 };
 
 #define EHEA_IRQ_NAME_SIZE 20
@@ -348,6 +337,7 @@ struct ehea_q_skb_arr {
  * Port resources
  */
 struct ehea_port_res {
+	struct port_stats p_stats;
 	struct ehea_mr send_mr;       	/* send memory region */
 	struct ehea_mr recv_mr;       	/* receive memory region */
 	spinlock_t xmit_lock;
@@ -357,9 +347,8 @@ struct ehea_port_res {
 	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_eq *eq;
+	struct net_device *d_netdev;
 	struct ehea_q_skb_arr rq1_skba;
 	struct ehea_q_skb_arr rq2_skba;
 	struct ehea_q_skb_arr rq3_skba;
@@ -369,21 +358,18 @@ struct ehea_port_res {
 	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;
 };
 
 
+#define EHEA_MAX_PORTS 16
 struct ehea_adapter {
 	u64 handle;
-	u8 num_ports;
-	struct ehea_port *port[16];
+	struct ibmebus_dev *ebus_dev;
+	struct ehea_port *port[EHEA_MAX_PORTS];
 	struct ehea_eq *neq;       /* notification event queue */
 	struct workqueue_struct *ehea_wq;
 	struct tasklet_struct neq_tasklet;
@@ -406,7 +392,7 @@ struct ehea_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 of_device  ofdev; /* Open Firmware Device */
 	struct ehea_mc_list *mc_list;	 /* Multicast MAC addresses */
 	struct vlan_group *vgrp;
 	struct ehea_eq *qp_eq;
@@ -415,7 +401,9 @@ struct ehea_port {
 	char int_aff_name[EHEA_IRQ_NAME_SIZE];
 	int allmulti;			 /* Indicates IFF_ALLMULTI state */
 	int promisc;		 	 /* Indicates IFF_PROMISC state */
+	int num_tx_qps;
 	int num_add_tx_qps;
+	int num_mcs;
 	int resets;
 	u64 mac_addr;
 	u32 logical_port_id;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 9f57c2e..decec8c 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_de
 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);
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static u32 ehea_get_msglevel(struct net_device *dev)
@@ -166,33 +166,23 @@ static u32 ehea_get_rx_csum(struct net_d
 }
 
 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"},
+	{"Receive errors"},
+	{"TCP cksum errors"},
+	{"IP cksum errors"},
+	{"Frame cksum errors"},
+	{"num SQ stopped"},
+	{"SQ stopped"},
+	{"PR0 free_swqes"},
+	{"PR1 free_swqes"},
+	{"PR2 free_swqes"},
+	{"PR3 free_swqes"},
+	{"PR4 free_swqes"},
+	{"PR5 free_swqes"},
+	{"PR6 free_swqes"},
+	{"PR7 free_swqes"},
 };
 
 static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -211,63 +201,44 @@ static int ehea_get_stats_count(struct n
 static void ehea_get_ethtool_stats(struct net_device *dev,
 				     struct ethtool_stats *stats, u64 *data)
 {
-	u64 hret;
-	int i;
+	int i, k, tmp;
 	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;
-	}
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp += port->port_res[k].p_stats.poll_receive_errors;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp += port->port_res[k].p_stats.err_tcp_cksum;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp += port->port_res[k].p_stats.err_ip_cksum;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp += port->port_res[k].p_stats.err_frame_crc;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp += port->port_res[k].p_stats.queue_stopped;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp |= port->port_res[k].queue_stopped;
+	data[i++] = tmp;
+
+	for (k = 0; k < 8; k++)
+		data[i++] = atomic_read(&port->port_res[k].swqe_avail);
 
-	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 = {
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 0e4042b..f6e0cb1 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIE
 static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
 static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
 static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+static int use_mcs = 0;
+static int num_tx_qps = EHEA_NUM_TX_QP;
 
 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_param(use_mcs, int, 0);
+module_param(num_tx_qps, int, 0);
 
+MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
 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 = "
@@ -71,6 +76,29 @@ MODULE_PARM_DESC(rq1_entries, "Number of
 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) ")");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+
+static int port_name_cnt = 0;
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+                                        const struct of_device_id *id);
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev);
+
+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_adapter,
+	.remove = ehea_remove,
+};
 
 void ehea_dump(void *adr, int len, char *msg) {
 	int x;
@@ -197,7 +225,7 @@ static int ehea_refill_rq_def(struct ehe
 		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);
+				   pr->port->netdev->name, i);
 			q_skba->os_skbs = fill_wqes - i;
 			ret = -ENOMEM;
 			break;
@@ -321,6 +349,13 @@ static int ehea_treat_poll_error(struct 
 {
 	struct sk_buff *skb;
 
+	if (cqe->status & EHEA_CQE_STAT_ERR_TCP)
+		pr->p_stats.err_tcp_cksum++;
+	if (cqe->status & EHEA_CQE_STAT_ERR_IP)
+		pr->p_stats.err_ip_cksum++;
+	if (cqe->status & EHEA_CQE_STAT_ERR_CRC)
+		pr->p_stats.err_frame_crc++;
+
 	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");
@@ -345,10 +380,11 @@ static int ehea_treat_poll_error(struct 
 	return 0;
 }
 
-static int ehea_poll(struct net_device *dev, int *budget)
+static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
+					struct ehea_port_res *pr,
+					int *budget)
 {
-	struct ehea_port *port = netdev_priv(dev);
-	struct ehea_port_res *pr = &port->port_res[0];
+	struct ehea_port *port = pr->port;
 	struct ehea_qp *qp = pr->qp;
 	struct ehea_cqe *cqe;
 	struct sk_buff *skb;
@@ -359,14 +395,12 @@ static int ehea_poll(struct net_device *
 	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;
+	int wqe_index, last_wqe_index, rq, 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);
@@ -386,13 +420,14 @@ static int ehea_poll(struct net_device *
 				if (unlikely(!skb)) {
 					if (netif_msg_rx_err(port))
 						ehea_error("LL rq1: skb=NULL");
-					skb = netdev_alloc_skb(dev,
+
+					skb = netdev_alloc_skb(port->netdev,
 							       EHEA_L_PKT_SIZE);
 					if (!skb)
 						break;
 				}
-				memcpy(skb->data, ((char*)cqe) + 64,
-				       cqe->num_bytes_transfered - 4);
+				skb_copy_to_linear_data(skb, ((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,
@@ -402,7 +437,7 @@ static int ehea_poll(struct net_device *
 						ehea_error("rq2: skb=NULL");
 					break;
 				}
-				ehea_fill_skb(dev, skb, cqe);
+				ehea_fill_skb(port->netdev, skb, cqe);
 				processed_rq2++;
 			} else {  /* RQ3 */
 				skb = get_skb_by_index(skb_arr_rq3,
@@ -412,7 +447,7 @@ static int ehea_poll(struct net_device *
 						ehea_error("rq3: skb=NULL");
 					break;
 				}
-				ehea_fill_skb(dev, skb, cqe);
+				ehea_fill_skb(port->netdev, skb, cqe);
 				processed_rq3++;
 			}
 
@@ -421,9 +456,8 @@ static int ehea_poll(struct net_device *
 							 cqe->vlan_tag);
 			else
 				netif_receive_skb(skb);
-
-		} else { /* Error occured */
-			pr->p_state.poll_receive_errors++;
+		} else {
+			pr->p_stats.poll_receive_errors++;
 			port_reset = ehea_treat_poll_error(pr, rq, cqe,
 							   &processed_rq2,
 							   &processed_rq3);
@@ -433,72 +467,32 @@ static int ehea_poll(struct net_device *
 		cqe = ehea_poll_rq1(qp, &wqe_index);
 	}
 
-	dev->quota -= processed;
-	*budget -= processed;
-
-	pr->p_state.ehea_poll += 1;
 	pr->rx_packets += processed;
+	*budget -= 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;
+	cqe = ehea_poll_rq1(qp, &wqe_index);
+	return cqe;
 }
 
-void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 {
 	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 quota = my_quota;
 	int cqe_counter = 0;
 	int swqe_av = 0;
+	int index;
 	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 = ehea_poll_cq(send_cq);
+	while(cqe && (quota > 0)) {
+		ehea_inc_cq(send_cq);
+
 		cqe_counter++;
 		rmb();
 		if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
@@ -514,17 +508,25 @@ void ehea_send_irq_tasklet(unsigned long
 			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);
+			   == EHEA_SWQE2_TYPE)) {
+
+			index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+			skb = pr->sq_skba.arr[index];
+			dev_kfree_skb(skb);
+			pr->sq_skba.arr[index] = NULL;
+		}
 
 		swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
 		quota--;
-	} while (quota > 0);
+
+		cqe = ehea_poll_cq(send_cq);
+	};
 
 	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);
@@ -532,22 +534,55 @@ void ehea_send_irq_tasklet(unsigned long
 	}
 	spin_unlock_irqrestore(&pr->netif_queue, flags);
 
-	if (unlikely(cqe))
-		tasklet_hi_schedule(&pr->send_comp_task);
+	return cqe;
 }
 
-static irqreturn_t ehea_send_irq_handler(int irq, void *param)
+#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+
+static int ehea_poll(struct net_device *dev, int *budget)
 {
-	struct ehea_port_res *pr = param;
-	tasklet_hi_schedule(&pr->send_comp_task);
-	return IRQ_HANDLED;
+	struct ehea_port_res *pr = dev->priv;
+	struct ehea_cqe *cqe;
+	struct ehea_cqe *cqe_skb = NULL;
+	int force_irq, wqe_index;
+
+	cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+	cqe_skb = ehea_poll_cq(pr->send_cq);
+
+	force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+
+	if ((!cqe && !cqe_skb) || force_irq) {
+		pr->poll_counter = 0;
+		netif_rx_complete(dev);
+		ehea_reset_cq_ep(pr->recv_cq);
+		ehea_reset_cq_ep(pr->send_cq);
+		ehea_reset_cq_n1(pr->recv_cq);
+		ehea_reset_cq_n1(pr->send_cq);
+		cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+		cqe_skb = ehea_poll_cq(pr->send_cq);
+
+		if (!cqe && !cqe_skb)
+			return 0;
+
+		if (!netif_rx_reschedule(dev, dev->quota))
+			return 0;
+	}
+
+	cqe = ehea_proc_rwqes(dev, pr, budget);
+	cqe_skb = ehea_proc_cqes(pr, 300);
+
+	if (cqe || cqe_skb)
+		pr->poll_counter++;
+
+	return 1;
 }
 
 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);
+
+	netif_rx_schedule(pr->d_netdev);
+
 	return IRQ_HANDLED;
 }
 
@@ -580,7 +615,7 @@ static struct ehea_port *ehea_get_port(s
 {
 	int i;
 
-	for (i = 0; i < adapter->num_ports; i++)
+	for (i = 0; i < EHEA_MAX_PORTS; i++)
 		if (adapter->port[i])
 	                if (adapter->port[i]->logical_port_id == logical_port)
 				return adapter->port[i];
@@ -650,19 +685,25 @@ int ehea_sense_port_attr(struct ehea_por
 	}
 
 	port->autoneg = 1;
+	port->num_mcs = cb0->num_default_qps;
 
 	/* Number of default QPs */
-	port->num_def_qps = cb0->num_default_qps;
+	if (use_mcs)
+		port->num_def_qps = cb0->num_default_qps;
+	else
+		port->num_def_qps = 1;
 
 	if (!port->num_def_qps) {
 		ret = -EINVAL;
 		goto out_free;
 	}
 
-	if (port->num_def_qps >= EHEA_NUM_TX_QP)
+	port->num_tx_qps = num_tx_qps;
+
+	if (port->num_def_qps >= port->num_tx_qps)
 		port->num_add_tx_qps = 0;
 	else
-		port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+		port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
 
 	ret = 0;
 out_free:
@@ -882,23 +923,6 @@ static int ehea_reg_interrupts(struct ne
 	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,
-					  IRQF_DISABLED, 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);
@@ -916,41 +940,41 @@ static int ehea_reg_interrupts(struct ne
 		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,
+			 "%s-queue%d", dev->name, i);
+		ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1,
+					  ehea_recv_irq_handler,
 					  IRQF_DISABLED, pr->int_send_name,
 					  pr);
 		if (ret) {
-			ehea_error("failed registering irq for ehea_send "
+			ehea_error("failed registering irq for ehea_queue "
 				   "port_res_nr:%d, ist=%X", i,
-				   pr->send_eq->attr.ist1);
+				   pr->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);
+			ehea_info("irq_handle 0x%X for function ehea_queue_int "
+				  "%d registered", pr->eq->attr.ist1, i);
 	}
 out:
 	return ret;
 
+
 out_free_req:
 	while (--i >= 0) {
-		u32 ist = port->port_res[i].send_eq->attr.ist1;
+		u32 ist = port->port_res[i].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)
@@ -960,21 +984,13 @@ static void ehea_free_interrupts(struct 
 	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);
+		ibmebus_free_irq(NULL, pr->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);
+				  i, pr->eq->attr.ist1);
 	}
 
 	/* associated events */
@@ -1003,8 +1019,13 @@ static int ehea_configure_port(struct eh
 				      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[0].qp->init_attr.qp_nr;
+	for (i = 0; i < port->num_mcs; i++)
+		if (use_mcs)
+			cb0->default_qpn_arr[i] =
+				port->port_res[i].qp->init_attr.qp_nr;
+		else
+			cb0->default_qpn_arr[i] =
+				port->port_res[0].qp->init_attr.qp_nr;
 
 	if (netif_msg_ifup(port))
 		ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
@@ -1027,52 +1048,35 @@ out:
 	return ret;
 }
 
-static int ehea_gen_smrs(struct ehea_port_res *pr)
+int ehea_gen_smrs(struct ehea_port_res *pr)
 {
-	u64 hret;
+	int ret;
 	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)
+	ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr);
+	if (ret)
 		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;
+	ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr);
+	if (ret)
+		goto out_free;
 
 	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_free:
+	ehea_rem_mr(&pr->send_mr);
 out:
+	ehea_error("Generating SMRS failed\n");
 	return -EIO;
 }
 
-static int ehea_rem_smrs(struct ehea_port_res *pr)
+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;
+	if ((ehea_rem_mr(&pr->send_mr))
+	    || (ehea_rem_mr(&pr->recv_mr)))
+		return -EIO;
+	else
+		return 0;
 }
 
 static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
@@ -1103,25 +1107,17 @@ static int ehea_init_port_res(struct ehe
 	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)");
+	pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+	if (!pr->eq) {
+		ehea_error("create_eq failed (eq)");
 		goto out_free;
 	}
 
 	pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
-				     pr->recv_eq->fw_handle,
+				     pr->eq->fw_handle,
 				     port->logical_port_id);
 	if (!pr->recv_cq) {
 		ehea_error("create_cq failed (cq_recv)");
@@ -1129,7 +1125,7 @@ static int ehea_init_port_res(struct ehe
 	}
 
 	pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
-				     pr->send_eq->fw_handle,
+				     pr->eq->fw_handle,
 				     port->logical_port_id);
 	if (!pr->send_cq) {
 		ehea_error("create_cq failed (cq_send)");
@@ -1194,11 +1190,20 @@ static int ehea_init_port_res(struct ehe
 		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);
+
+	pr->d_netdev = alloc_netdev(0, "", ether_setup);
+	if (!pr->d_netdev)
+		goto out_free;
+	pr->d_netdev->priv = pr;
+	pr->d_netdev->weight = 64;
+	pr->d_netdev->poll = ehea_poll;
+	set_bit(__LINK_STATE_START, &pr->d_netdev->state);
+	strcpy(pr->d_netdev->name, port->netdev->name);
+
 	ret = 0;
 	goto out;
 
@@ -1211,8 +1216,7 @@ out_free:
 	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);
+	ehea_destroy_eq(pr->eq);
 out:
 	return ret;
 }
@@ -1221,13 +1225,14 @@ static int ehea_clean_portres(struct ehe
 {
 	int ret, i;
 
+	free_netdev(pr->d_netdev);
+
 	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);
+		ehea_destroy_eq(pr->eq);
 
 		for (i = 0; i < pr->rq1_skba.len; i++)
 			if (pr->rq1_skba.arr[i])
@@ -1262,8 +1267,8 @@ static int ehea_clean_portres(struct ehe
 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);
+	swqe->ip_start = skb_network_offset(skb);
+	swqe->ip_end = (u8)(swqe->ip_start + ip_hdrlen(skb) - 1);
 }
 
 static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
@@ -1300,13 +1305,13 @@ static void write_swqe2_TSO(struct sk_bu
 	/* 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);
+	headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
 
 	skb_data_size = skb->len - skb->data_len;
 
 	if (skb_data_size >= headersize) {
 		/* copy immediate data */
-		memcpy(imm_data, skb->data, headersize);
+		skb_copy_from_linear_data(skb, imm_data, headersize);
 		swqe->immediate_data_length = headersize;
 
 		if (skb_data_size > headersize) {
@@ -1337,7 +1342,7 @@ static void write_swqe2_nonTSO(struct sk
 	 */
 	if (skb_data_size >= SWQE2_MAX_IMM) {
 		/* copy immediate data */
-		memcpy(imm_data, skb->data, SWQE2_MAX_IMM);
+		skb_copy_from_linear_data(skb, imm_data, SWQE2_MAX_IMM);
 
 		swqe->immediate_data_length = SWQE2_MAX_IMM;
 
@@ -1350,7 +1355,7 @@ static void write_swqe2_nonTSO(struct sk
 			swqe->descriptors++;
 		}
 	} else {
-		memcpy(imm_data, skb->data, skb_data_size);
+		skb_copy_from_linear_data(skb, imm_data, skb_data_size);
 		swqe->immediate_data_length = skb_data_size;
 	}
 }
@@ -1688,6 +1693,7 @@ static void ehea_xmit2(struct sk_buff *s
 		       struct ehea_swqe *swqe, u32 lkey)
 {
 	if (skb->protocol == htons(ETH_P_IP)) {
+		const struct iphdr *iph = ip_hdr(skb);
 		/* IPv4 */
 		swqe->tx_control |= EHEA_SWQE_CRC
 				 | EHEA_SWQE_IP_CHECKSUM
@@ -1697,15 +1703,15 @@ static void ehea_xmit2(struct sk_buff *s
 
 		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))
+		if (iph->protocol == IPPROTO_UDP) {
+			if ((iph->frag_off & IP_MF) ||
+			    (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) {
+		} else if (iph->protocol == IPPROTO_TCP) {
 			write_tcp_offset_end(swqe, skb);
 		}
 
@@ -1731,10 +1737,11 @@ static void ehea_xmit3(struct sk_buff *s
 	int i;
 
 	if (skb->protocol == htons(ETH_P_IP)) {
+		const struct iphdr *iph = ip_hdr(skb);
 		/* IPv4 */
 		write_ip_start_end(swqe, skb);
 
-		if (skb->nh.iph->protocol == IPPROTO_TCP) {
+		if (iph->protocol == IPPROTO_TCP) {
 			swqe->tx_control |= EHEA_SWQE_CRC
 					 | EHEA_SWQE_IP_CHECKSUM
 					 | EHEA_SWQE_TCP_CHECKSUM
@@ -1742,9 +1749,9 @@ static void ehea_xmit3(struct sk_buff *s
 
 			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))
+		} else if (iph->protocol == IPPROTO_UDP) {
+			if ((iph->frag_off & IP_MF) ||
+			    (iph->frag_off & IP_OFFSET))
 				/* IP fragment, so don't change cs */
 				swqe->tx_control |= EHEA_SWQE_CRC
 						 | EHEA_SWQE_IMM_DATA_PRESENT;
@@ -1770,10 +1777,11 @@ static void ehea_xmit3(struct sk_buff *s
 	/* copy (immediate) data */
 	if (nfrags == 0) {
 		/* data is in a single piece */
-		memcpy(imm_data, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, imm_data, skb->len);
 	} else {
 		/* first copy data from the skb->data buffer ... */
-		memcpy(imm_data, skb->data, skb->len - skb->data_len);
+		skb_copy_from_linear_data(skb, imm_data,
+					  skb->len - skb->data_len);
 		imm_data += skb->len - skb->data_len;
 
 		/* ... then copy data from the fragments */
@@ -1789,6 +1797,22 @@ static void ehea_xmit3(struct sk_buff *s
 	dev_kfree_skb(skb);
 }
 
+static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
+{
+	struct tcphdr *tcp;
+	u32 tmp;
+
+	if ((skb->protocol == htons(ETH_P_IP)) &&
+	    (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
+		tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4));
+		tmp = (tcp->source + (tcp->dest << 16)) % 31;
+		tmp += ip_hdr(skb)->daddr % 31;
+		return tmp % num_qps;
+	}
+	else
+		return 0;
+}
+
 static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ehea_port *port = netdev_priv(dev);
@@ -1796,9 +1820,17 @@ static int ehea_start_xmit(struct sk_buf
 	unsigned long flags;
 	u32 lkey;
 	int swqe_index;
-	struct ehea_port_res *pr = &port->port_res[0];
+	struct ehea_port_res *pr;
+
+	pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)];
 
-	spin_lock(&pr->xmit_lock);
+	if (!spin_trylock(&pr->xmit_lock))
+		return NETDEV_TX_BUSY;
+
+	if (pr->queue_stopped) {
+		spin_unlock(&pr->xmit_lock);
+		return NETDEV_TX_BUSY;
+	}
 
 	swqe = ehea_get_swqe(pr->qp, &swqe_index);
 	memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -1821,6 +1853,7 @@ static int ehea_start_xmit(struct sk_buf
 		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_REFILL, 1)
 		      | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
 		pr->sq_skba.arr[pr->sq_skba.index] = skb;
 
@@ -1829,14 +1862,7 @@ static int ehea_start_xmit(struct sk_buf
 
 		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;
+		swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
 	}
 	pr->swqe_id_counter += 1;
 
@@ -1856,6 +1882,7 @@ static int ehea_start_xmit(struct sk_buf
 	if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
 		spin_lock_irqsave(&pr->netif_queue, flags);
 		if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+			pr->p_stats.queue_stopped++;
 			netif_stop_queue(dev);
 			pr->queue_stopped = 1;
 		}
@@ -2057,7 +2084,7 @@ static int ehea_port_res_setup(struct eh
 	}
 
 	pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
-	pr_cfg.max_entries_scq = sq_entries;
+	pr_cfg.max_entries_scq = sq_entries * 2;
 	pr_cfg.max_entries_sq = sq_entries;
 	pr_cfg.max_entries_rq1 = rq1_entries;
 	pr_cfg.max_entries_rq2 = rq2_entries;
@@ -2106,6 +2133,28 @@ static int ehea_clean_all_portres(struct
 	return ret;
 }
 
+static void ehea_remove_adapter_mr (struct ehea_adapter *adapter)
+{
+	int i;
+
+	for (i=0; i < EHEA_MAX_PORTS; i++)
+		if (adapter->port[i])
+			return;
+
+	ehea_rem_mr(&adapter->mr);
+}
+
+static int ehea_add_adapter_mr (struct ehea_adapter *adapter)
+{
+	int i;
+
+	for (i=0; i < EHEA_MAX_PORTS; i++)
+		if (adapter->port[i])
+			return 0;
+
+	return ehea_reg_kernel_mr(adapter, &adapter->mr);
+}
+
 static int ehea_up(struct net_device *dev)
 {
 	int ret, i;
@@ -2205,8 +2254,10 @@ static int ehea_down(struct net_device *
 	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);
+	for (i = 0; i < port->num_def_qps; i++)
+		while (test_bit(__LINK_STATE_RX_SCHED,
+				&port->port_res[i].d_netdev->state))
+			msleep(1);
 
 	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 	ret = ehea_clean_all_portres(port);
@@ -2273,8 +2324,6 @@ static void ehea_tx_watchdog(struct net_
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
 {
 	struct hcp_query_ehea *cb;
-	struct device_node *lhea_dn = NULL;
-	struct device_node *eth_dn = NULL;
 	u64 hret;
 	int ret;
 
@@ -2291,18 +2340,6 @@ int ehea_sense_adapter_attr(struct ehea_
 		goto out_herr;
 	}
 
-	/* Determine the number of available logical ports
-	 * by counting the child nodes of the lhea OFDT entry
-	 */
-	adapter->num_ports = 0;
-	lhea_dn = of_find_node_by_name(lhea_dn, "lhea");
-	do {
-		eth_dn = of_get_next_child(lhea_dn, eth_dn);
-		if (eth_dn)
-			adapter->num_ports++;
-	} while ( eth_dn );
-	of_node_put(lhea_dn);
-
 	adapter->max_mc_mac = cb->max_mc_mac - 1;
 	ret = 0;
 
@@ -2312,79 +2349,188 @@ out:
 	return ret;
 }
 
-static int ehea_setup_single_port(struct ehea_port *port,
-				  struct device_node *dn)
+int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
 {
-	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;
-	int jumbo = 0;
-
-	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);
+	u64 hret;
+	int ret = 0;
 
-	ret = ehea_sense_port_attr(port);
-	if (ret)
-		goto out;
+	*jumbo = 0;
 
-	/* Enable Jumbo frames */
+	/* (Try to) enable *jumbo frames */
 	cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!cb4) {
 		ehea_error("no mem for cb4");
+		ret = -ENOMEM;
+		goto out;
 	} else {
-		hret = ehea_h_query_ehea_port(adapter->handle,
+		hret = ehea_h_query_ehea_port(port->adapter->handle,
 					      port->logical_port_id,
 					      H_PORT_CB4,
 					      H_PORT_CB4_JUMBO, cb4);
-
 		if (hret == H_SUCCESS) {
 			if (cb4->jumbo_frame)
-				jumbo = 1;
+				*jumbo = 1;
 			else {
 				cb4->jumbo_frame = 1;
-				hret = ehea_h_modify_ehea_port(adapter->handle,
+				hret = ehea_h_modify_ehea_port(port->adapter->
+							       handle,
 							       port->
-							        logical_port_id,
+							       logical_port_id,
 							       H_PORT_CB4,
 							       H_PORT_CB4_JUMBO,
 							       cb4);
 				if (hret == H_SUCCESS)
-					jumbo = 1;
+					*jumbo = 1;
 			}
-		}
+		} else
+			ret = -EINVAL;
+
 		kfree(cb4);
 	}
+out:
+	return ret;
+}
+
+static ssize_t ehea_show_port_id(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+	return sprintf(buf, "0x%X", port->logical_port_id);
+}
+
+static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
+		   NULL);
+
+static void __devinit logical_port_release(struct device *dev)
+{
+	struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+	of_node_put(port->ofdev.node);
+}
+
+static int ehea_driver_sysfs_add(struct device *dev,
+                                 struct device_driver *driver)
+{
+	int ret;
+
+	ret = sysfs_create_link(&driver->kobj, &dev->kobj,
+				kobject_name(&dev->kobj));
+	if (ret == 0) {
+		ret = sysfs_create_link(&dev->kobj, &driver->kobj,
+					"driver");
+		if (ret)
+			sysfs_remove_link(&driver->kobj,
+					  kobject_name(&dev->kobj));
+	}
+	return ret;
+}
+
+static void ehea_driver_sysfs_remove(struct device *dev,
+                                     struct device_driver *driver)
+{
+	struct device_driver *drv = driver;
+
+	if (drv) {
+		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+		sysfs_remove_link(&dev->kobj, "driver");
+	}
+}
+
+static struct device *ehea_register_port(struct ehea_port *port,
+					 struct device_node *dn)
+{
+	int ret;
+
+	port->ofdev.node = of_node_get(dn);
+	port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev;
+	port->ofdev.dev.bus = &ibmebus_bus_type;
+
+	sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++);
+	port->ofdev.dev.release = logical_port_release;
+
+	ret = of_device_register(&port->ofdev);
+	if (ret) {
+		ehea_error("failed to register device. ret=%d", ret);
+		goto out;
+	}
+
+	ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
+        if (ret) {
+		ehea_error("failed to register attributes, ret=%d", ret);
+		goto out_unreg_of_dev;
+	}
+
+	ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver);
+	if (ret) {
+		ehea_error("failed to register sysfs driver link");
+		goto out_rem_dev_file;
+	}
+
+	return &port->ofdev.dev;
+
+out_rem_dev_file:
+	device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+out_unreg_of_dev:
+	of_device_unregister(&port->ofdev);
+out:
+	return NULL;
+}
+
+static void ehea_unregister_port(struct ehea_port *port)
+{
+	ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver);
+	device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+	of_device_unregister(&port->ofdev);
+}
+
+struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
+					 u32 logical_port_id,
+					 struct device_node *dn)
+{
+	int ret;
+	struct net_device *dev;
+	struct ehea_port *port;
+	struct device *port_dev;
+	int jumbo;
+
+	/* allocate memory for the port structures */
+	dev = alloc_etherdev(sizeof(struct ehea_port));
+
+	if (!dev) {
+		ehea_error("no mem for net_device");
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	port = netdev_priv(dev);
+
+	sema_init(&port->port_lock, 1);
+	port->state = EHEA_PORT_DOWN;
+	port->sig_comp_iv = sq_entries / 10;
+
+	port->adapter = adapter;
+	port->netdev = dev;
+	port->logical_port_id = logical_port_id;
+
+	port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+	port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+	if (!port->mc_list) {
+		ret = -ENOMEM;
+		goto out_free_ethdev;
+	}
+
+	INIT_LIST_HEAD(&port->mc_list->list);
+
+	ret = ehea_sense_port_attr(port);
+	if (ret)
+		goto out_free_mc_list;
+
+	port_dev = ehea_register_port(port, dn);
+	if (!port_dev)
+		goto out_free_mc_list;
+
+	SET_NETDEV_DEV(dev, port_dev);
 
 	/* initialize net_device structure */
 	SET_MODULE_OWNER(dev);
@@ -2417,84 +2563,224 @@ static int ehea_setup_single_port(struct
 	ret = register_netdev(dev);
 	if (ret) {
 		ehea_error("register_netdev failed. ret=%d", ret);
-		goto out_free;
+		goto out_unreg_port;
 	}
 
+	ret = ehea_get_jumboframe_status(port, &jumbo);
+	if (ret)
+		ehea_error("failed determining jumbo frame status for %s",
+			   port->netdev->name);
+
 	ehea_info("%s: Jumbo frames are %sabled", dev->name,
 		  jumbo == 1 ? "en" : "dis");
 
-	port->netdev = dev;
-	ret = 0;
-	goto out;
+	return port;
 
-out_free:
+out_unreg_port:
+	ehea_unregister_port(port);
+
+out_free_mc_list:
 	kfree(port->mc_list);
-out:
-	return ret;
+
+out_free_ethdev:
+	free_netdev(dev);
+
+out_err:
+	ehea_error("setting up logical port with id=%d failed, ret=%d",
+		   logical_port_id, ret);
+	return NULL;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+	unregister_netdev(port->netdev);
+	ehea_unregister_port(port);
+	kfree(port->mc_list);
+	free_netdev(port->netdev);
 }
 
 static int ehea_setup_ports(struct ehea_adapter *adapter)
 {
-	int ret;
-	int port_setup_ok = 0;
+	struct device_node *lhea_dn;
+	struct device_node *eth_dn = NULL;
+	const u32 *dn_log_port_id;
+	int i = 0;
+
+	lhea_dn = adapter->ebus_dev->ofdev.node;
+	while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+		dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
+						    NULL);
+		if (!dn_log_port_id) {
+			ehea_error("bad device node: eth_dn name=%s",
+				   eth_dn->full_name);
+			continue;
+		}
+
+		if (ehea_add_adapter_mr(adapter)) {
+			ehea_error("creating MR failed");
+			of_node_put(eth_dn);
+			return -EIO;
+		}
+
+		adapter->port[i] = ehea_setup_single_port(adapter,
+							  *dn_log_port_id,
+							  eth_dn);
+		if (adapter->port[i])
+			ehea_info("%s -> logical port id #%d",
+				  adapter->port[i]->netdev->name,
+				  *dn_log_port_id);
+		else
+			ehea_remove_adapter_mr(adapter);
+
+		i++;
+	};
+
+	return 0;
+}
+
+static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
+					   u32 logical_port_id)
+{
+	struct device_node *lhea_dn;
+	struct device_node *eth_dn = NULL;
+	const u32 *dn_log_port_id;
+
+	lhea_dn = adapter->ebus_dev->ofdev.node;
+	while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+		dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
+						    NULL);
+		if (dn_log_port_id)
+			if (*dn_log_port_id == logical_port_id)
+				return eth_dn;
+	};
+
+	return NULL;
+}
+
+static ssize_t ehea_probe_port(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ehea_adapter *adapter = dev->driver_data;
 	struct ehea_port *port;
-	struct device_node *dn = NULL;
-	struct net_device *dev;
+	struct device_node *eth_dn = NULL;
 	int i;
 
-	/* get port properties for all ports */
-	for (i = 0; i < adapter->num_ports; i++) {
+	u32 logical_port_id;
 
-		if (adapter->port[i])
-			continue;	/* port already up and running */
+	sscanf(buf, "%X", &logical_port_id);
 
-		/* allocate memory for the port structures */
-		dev = alloc_etherdev(sizeof(struct ehea_port));
+	port = ehea_get_port(adapter, logical_port_id);
 
-		if (!dev) {
-			ehea_error("no mem for net_device");
-			break;
-		}
+	if (port) {
+		ehea_info("adding port with logical port id=%d failed. port "
+			  "already configured as %s.", logical_port_id,
+			  port->netdev->name);
+		return -EINVAL;
+	}
 
-		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);
+	eth_dn = ehea_get_eth_dn(adapter, logical_port_id);
 
-		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);
-		}
+	if (!eth_dn) {
+		ehea_info("no logical port with id %d found", logical_port_id);
+		return -EINVAL;
 	}
 
-	of_node_put(dn);
+	if (ehea_add_adapter_mr(adapter)) {
+		ehea_error("creating MR failed");
+		return -EIO;
+	}
 
-	/* Check for succesfully set up ports */
-	for (i = 0; i < adapter->num_ports; i++)
-		if (adapter->port[i])
-			port_setup_ok++;
+	port = ehea_setup_single_port(adapter, logical_port_id, eth_dn);
 
-	if (port_setup_ok)
-		ret = 0;	/* At least some ports are setup correctly */
-	else
-		ret = -EINVAL;
+	of_node_put(eth_dn);
+
+	if (port) {
+		for (i=0; i < EHEA_MAX_PORTS; i++)
+			if (!adapter->port[i]) {
+				adapter->port[i] = port;
+				break;
+			}
+
+		ehea_info("added %s (logical port id=%d)", port->netdev->name,
+			  logical_port_id);
+	} else {
+		ehea_remove_adapter_mr(adapter);
+		return -EIO;
+	}
+
+	return (ssize_t) count;
+}
+
+static ssize_t ehea_remove_port(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct ehea_adapter *adapter = dev->driver_data;
+	struct ehea_port *port;
+	int i;
+	u32 logical_port_id;
+
+	sscanf(buf, "%X", &logical_port_id);
+
+	port = ehea_get_port(adapter, logical_port_id);
 
+	if (port) {
+		ehea_info("removed %s (logical port id=%d)", port->netdev->name,
+			  logical_port_id);
+
+		ehea_shutdown_single_port(port);
+
+		for (i=0; i < EHEA_MAX_PORTS; i++)
+			if (adapter->port[i] == port) {
+				adapter->port[i] = NULL;
+				break;
+			}
+	} else {
+		ehea_error("removing port with logical port id=%d failed. port "
+			   "not configured.", logical_port_id);
+		return -EINVAL;
+	}
+
+	ehea_remove_adapter_mr(adapter);
+
+	return (ssize_t) count;
+}
+
+static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
+static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
+
+int ehea_create_device_sysfs(struct ibmebus_dev *dev)
+{
+	int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port);
+	if (ret)
+		goto out;
+
+	ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port);
+out:
 	return ret;
 }
 
-static int __devinit ehea_probe(struct ibmebus_dev *dev,
-				const struct of_device_id *id)
+void ehea_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+	device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port);
+	device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port);
+}
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+					const struct of_device_id *id)
 {
 	struct ehea_adapter *adapter;
-	u64 *adapter_handle;
+	const u64 *adapter_handle;
 	int ret;
 
+	if (!dev || !dev->ofdev.node) {
+		ehea_error("Invalid ibmebus device probed");
+		return -EINVAL;
+	}
+
 	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 	if (!adapter) {
 		ret = -ENOMEM;
@@ -2502,7 +2788,9 @@ static int __devinit ehea_probe(struct i
 		goto out;
 	}
 
-	adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
+	adapter->ebus_dev = dev;
+
+	adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
 					    NULL);
 	if (adapter_handle)
 		adapter->handle = *adapter_handle;
@@ -2518,26 +2806,21 @@ static int __devinit ehea_probe(struct i
 
 	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;
+		goto out_free_ad;
 	}
-	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) {
+		ret = -EIO;
 		dev_err(&dev->ofdev.dev, "NEQ creation failed");
-		goto out_free_res;
+		goto out_free_ad;
 	}
 
 	tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
@@ -2552,18 +2835,27 @@ static int __devinit ehea_probe(struct i
 	}
 
 	adapter->ehea_wq = create_workqueue("ehea_wq");
-	if (!adapter->ehea_wq)
+	if (!adapter->ehea_wq) {
+		ret = -EIO;
 		goto out_free_irq;
+	}
+
+	ret = ehea_create_device_sysfs(dev);
+	if (ret)
+		goto out_kill_wq;
 
 	ret = ehea_setup_ports(adapter);
 	if (ret) {
 		dev_err(&dev->ofdev.dev, "setup_ports failed");
-		goto out_kill_wq;
+		goto out_rem_dev_sysfs;
 	}
 
 	ret = 0;
 	goto out;
 
+out_rem_dev_sysfs:
+	ehea_remove_device_sysfs(dev);
+
 out_kill_wq:
 	destroy_workqueue(adapter->ehea_wq);
 
@@ -2573,45 +2865,32 @@ out_free_irq:
 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++)
+	for (i = 0; i < EHEA_MAX_PORTS; i++)
 		if (adapter->port[i]) {
 			ehea_shutdown_single_port(adapter->port[i]);
 			adapter->port[i] = NULL;
 		}
+
+	ehea_remove_device_sysfs(dev);
+
 	destroy_workqueue(adapter->ehea_wq);
 
 	ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
 	tasklet_kill(&adapter->neq_tasklet);
 
 	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;
-	}
+	ehea_remove_adapter_mr(adapter);
 	kfree(adapter);
 	return 0;
 }
@@ -2644,21 +2923,6 @@ static int check_module_parm(void)
 	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;
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index bc3c005..95c4a7f 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64
 				 0, 0, 0, 0, 0, 0);             /* R7-R12 */
 }
 
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+			 u64 force_bit)
 {
 	return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
 				       adapter_handle,	   /* R4 */
 				       res_handle,         /* R5 */
-				       0, 0, 0, 0, 0);     /* R6-R10 */
+				       force_bit,
+				       0, 0, 0, 0);        /* R7-R10 */
 }
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 90acddb..d17a45a 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -414,7 +414,11 @@ #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);
+#define FORCE_FREE 1
+#define NORMAL_FREE 0
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+			 u64 force_bit);
 
 u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
 			     const u64 length, const u32 access_ctrl,
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 96ff3b6..f24a886 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -197,7 +197,7 @@ out_kill_hwq:
 	hw_queue_dtor(&cq->hw_queue);
 
 out_freeres:
-	ehea_h_free_resource(adapter->handle, cq->fw_handle);
+	ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
 
 out_freemem:
 	kfree(cq);
@@ -206,25 +206,38 @@ out_nomem:
 	return NULL;
 }
 
-int ehea_destroy_cq(struct ehea_cq *cq)
+u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
 {
-	u64 adapter_handle, hret;
+	u64 hret;
+	u64 adapter_handle = cq->adapter->handle;
+
+        /* deregister all previous registered pages */
+	hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
+	if (hret != H_SUCCESS)
+		return hret;
+
+	hw_queue_dtor(&cq->hw_queue);
+	kfree(cq);
+
+	return hret;
+}
 
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+	u64 hret;
 	if (!cq)
 		return 0;
 
-	adapter_handle = cq->adapter->handle;
+	if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+		ehea_error_data(cq->adapter, cq->fw_handle);
+		hret = ehea_destroy_cq_res(cq, FORCE_FREE);
+	}
 
-	/* 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;
 }
 
@@ -297,7 +310,7 @@ out_kill_hwq:
 	hw_queue_dtor(&eq->hw_queue);
 
 out_freeres:
-	ehea_h_free_resource(adapter->handle, eq->fw_handle);
+	ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
 
 out_freemem:
 	kfree(eq);
@@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehe
 	return eqe;
 }
 
-int ehea_destroy_eq(struct ehea_eq *eq)
+u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
 {
 	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);
+	hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
 	spin_unlock_irqrestore(&eq->spinlock, flags);
 
-	if (hret != H_SUCCESS) {
-		ehea_error("destroy_eq failed");
-		return -EIO;
-	}
+	if (hret != H_SUCCESS)
+		return hret;
 
 	hw_queue_dtor(&eq->hw_queue);
 	kfree(eq);
 
+	return hret;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+	u64 hret;
+	if (!eq)
+		return 0;
+
+	if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+		ehea_error_data(eq->adapter, eq->fw_handle);
+		hret = ehea_destroy_eq_res(eq, FORCE_FREE);
+	}
+
+	if (hret != H_SUCCESS) {
+		ehea_error("destroy EQ failed");
+		return -EIO;
+        }
+
 	return 0;
 }
 
@@ -471,41 +498,56 @@ out_kill_hwsq:
 
 out_freeres:
 	ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
-	ehea_h_free_resource(adapter->handle, qp->fw_handle);
+	ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
 
 out_freemem:
 	kfree(qp);
 	return NULL;
 }
 
-int ehea_destroy_qp(struct ehea_qp *qp)
+u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
 {
-	u64 hret;
-	struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+        u64 hret;
+        struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
 
-	if (!qp)
-		return 0;
 
-	ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
-	hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
-	if (hret != H_SUCCESS) {
-		ehea_error("destroy_qp failed");
-		return -EIO;
-	}
+        ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+        hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+        if (hret != H_SUCCESS)
+                return hret;
 
-	hw_queue_dtor(&qp->hw_squeue);
-	hw_queue_dtor(&qp->hw_rqueue1);
+        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);
+        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;
+        return hret;
 }
 
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+        u64 hret;
+        if (!qp)
+                return 0;
+
+        if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+                ehea_error_data(qp->adapter, qp->fw_handle);
+                hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+        }
+
+        if (hret != H_SUCCESS) {
+                ehea_error("destroy QP failed");
+                return -EIO;
+        }
+
+        return 0;
+}
+
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
 {
 	int i, k, ret;
 	u64 hret, pt_abs, start, end, nr_pages;
@@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adap
 
 	hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
 					acc_ctrl, adapter->pd,
-					&adapter->mr.handle, &adapter->mr.lkey);
+					&mr->handle, &mr->lkey);
 	if (hret != H_SUCCESS) {
 		ehea_error("alloc_resource_mr failed");
 		ret = -EIO;
 		goto out;
 	}
 
-	adapter->mr.vaddr = KERNELBASE;
+	mr->vaddr = KERNELBASE;
 	k = 0;
 
 	while (nr_pages > 0) {
@@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adap
 							     EHEA_PAGESIZE)));
 
 			hret = ehea_h_register_rpage_mr(adapter->handle,
-							adapter->mr.handle, 0,
+							mr->handle, 0,
 							0, (u64)pt_abs,
 							num_pages);
 			nr_pages -= num_pages;
@@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adap
 							  (k * EHEA_PAGESIZE)));
 
 			hret = ehea_h_register_rpage_mr(adapter->handle,
-							adapter->mr.handle, 0,
+							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);
+					     mr->handle, FORCE_FREE);
+			ehea_error("register_rpage_mr failed");
 			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);
+		ehea_h_free_resource(adapter->handle, mr->handle,
+				     FORCE_FREE);
+		ehea_error("register_rpage failed for last page");
 		ret = -EIO;
 		goto out;
 	}
+
+	mr->adapter = adapter;
 	ret = 0;
 out:
 	kfree(pt);
 	return ret;
 }
 
+int ehea_rem_mr(struct ehea_mr *mr)
+{
+	u64 hret;
+
+	if (!mr || !mr->adapter)
+		return -EINVAL;
+
+	hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
+				    FORCE_FREE);
+	if (hret != H_SUCCESS) {
+		ehea_error("destroy MR failed");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+		 struct ehea_mr *shared_mr)
+{
+	u64 hret;
+
+	hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
+				   old_mr->vaddr, EHEA_MR_ACC_CTRL,
+				   adapter->pd, shared_mr);
+	if (hret != H_SUCCESS)
+		return -EIO;
+
+	shared_mr->adapter = adapter;
+
+	return 0;
+}
+
 void print_error_data(u64 *data)
 {
 	int length;
@@ -597,6 +673,14 @@ void print_error_data(u64 *data)
 		ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
 			   "port=%lX", resource, data[6], data[12], data[22]);
 
+	if (type == 0x4) /* Completion Queue */
+		ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource,
+			   data[6]);
+
+	if (type == 0x3) /* Event Queue */
+		ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource,
+			   data[6]);
+
 	ehea_dump(data, length, "error data");
 }
 
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 1ff6098..c0eb3e0 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -142,6 +142,8 @@ #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
+#define EHEA_CQE_STAT_ERR_IP       0x2000
+#define EHEA_CQE_STAT_ERR_CRC      0x1000
 
 struct ehea_cqe {
 	u64 wr_id;		/* work request ID from WQE */
@@ -320,6 +322,11 @@ static inline struct ehea_cqe *ehea_poll
 	return hw_qeit_get_valid(queue);
 }
 
+static inline void ehea_inc_cq(struct ehea_cq *cq)
+{
+	hw_qeit_inc(&cq->hw_queue);
+}
+
 static inline void ehea_inc_rq1(struct ehea_qp *qp)
 {
 	hw_qeit_inc(&qp->hw_rqueue1);
@@ -327,7 +334,7 @@ static inline void ehea_inc_rq1(struct e
 
 static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
 {
-	return hw_qeit_get_inc_valid(&my_cq->hw_queue);
+	return hw_qeit_get_valid(&my_cq->hw_queue);
 }
 
 #define EHEA_CQ_REGISTER_ORIG 0
@@ -356,7 +363,12 @@ struct ehea_qp *ehea_create_qp(struct eh
 
 int ehea_destroy_qp(struct ehea_qp *qp);
 
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr);
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+		 struct ehea_mr *shared_mr);
+
+int ehea_rem_mr(struct ehea_mr *mr);
 
 void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
 
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 3a6a83d..4e3f14c 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -934,7 +934,6 @@ static void epic_init_ring(struct net_de
 		ep->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
-		skb->dev = dev;			/* Mark as being used by this device. */
 		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
 		ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
 			skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
@@ -1199,7 +1198,6 @@ static int epic_rx(struct net_device *de
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(ep->pci_dev,
 							    ep->rx_ring[entry].bufaddr,
@@ -1236,7 +1234,6 @@ static int epic_rx(struct net_device *de
 			skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz);
 			if (skb == NULL)
 				break;
-			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
 				skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 93283e3..04abf59 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1175,7 +1175,6 @@ static void eth16i_rx(struct net_device 
 				break;
 			}
 
-			skb->dev = dev;
 			skb_reserve(skb,2);
 
 			/*
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 714ea11..cb0792c 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -993,7 +993,6 @@ static int ewrk3_rx(struct net_device *d
 
 					if ((skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 						unsigned char *p;
-						skb->dev = dev;
 						skb_reserve(skb, 2);	/* Align to 16 bytes */
 						p = skb_put(skb, pkt_len);
 
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 38a13f4..abe9b08 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1719,7 +1719,6 @@ #endif
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak &&
 			    (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(np->pci_dev,
 							    np->cur_rx->buffer,
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 6764281..255b091 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -647,7 +647,6 @@ #endif
 		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
 		fep->stats.rx_dropped++;
 	} else {
-		skb->dev = dev;
 		skb_put(skb,pkt_len-4);	/* Make room */
 		eth_copy_and_sum(skb, data, pkt_len-4, 0);
 		skb->protocol=eth_type_trans(skb,dev);
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index 77f747a..88efe97 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -19,7 +19,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -551,7 +550,9 @@ static int fec_enet_rx_common(struct net
 				skbn = dev_alloc_skb(pkt_len + 2);
 				if (skbn != NULL) {
 					skb_reserve(skbn, 2);	/* align IP header */
-					memcpy(skbn->data, skb->data, pkt_len);
+					skb_copy_from_linear_data(skb
+								  skbn->data,
+								  pkt_len);
 					/* swap */
 					skbt = skb;
 					skb = skbn;
@@ -561,7 +562,6 @@ static int fec_enet_rx_common(struct net
 				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
 
 			if (skbn != NULL) {
-				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				skb->protocol = eth_type_trans(skb, dev);
 				received++;
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index e79700a..b3fa0d6 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -19,7 +19,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index d04214e..7a01802 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -1385,11 +1385,12 @@ static int nv_alloc_rx(struct net_device
 	while (np->put_rx.orig != less_rx) {
 		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
 		if (skb) {
-			skb->dev = dev;
 			np->put_rx_ctx->skb = skb;
-			np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
-							     skb->end-skb->data, PCI_DMA_FROMDEVICE);
-			np->put_rx_ctx->dma_len = skb->end-skb->data;
+			np->put_rx_ctx->dma = pci_map_single(np->pci_dev,
+							     skb->data,
+							     skb_tailroom(skb),
+							     PCI_DMA_FROMDEVICE);
+			np->put_rx_ctx->dma_len = skb_tailroom(skb);
 			np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
 			wmb();
 			np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
@@ -1416,11 +1417,12 @@ static int nv_alloc_rx_optimized(struct 
 	while (np->put_rx.ex != less_rx) {
 		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
 		if (skb) {
-			skb->dev = dev;
 			np->put_rx_ctx->skb = skb;
-			np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
-							     skb->end-skb->data, PCI_DMA_FROMDEVICE);
-			np->put_rx_ctx->dma_len = skb->end-skb->data;
+			np->put_rx_ctx->dma = pci_map_single(np->pci_dev,
+							     skb->data,
+							     skb_tailroom(skb),
+							     PCI_DMA_FROMDEVICE);
+			np->put_rx_ctx->dma_len = skb_tailroom(skb);
 			np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
 			np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
 			wmb();
@@ -1604,8 +1606,9 @@ static void nv_drain_rx(struct net_devic
 		wmb();
 		if (np->rx_skb[i].skb) {
 			pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
-						np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
-						PCI_DMA_FROMDEVICE);
+					 (skb_end_pointer(np->rx_skb[i].skb) -
+					  np->rx_skb[i].skb->data),
+					 PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(np->rx_skb[i].skb);
 			np->rx_skb[i].skb = NULL;
 		}
@@ -4376,11 +4379,12 @@ static int nv_loopback_test(struct net_d
 		ret = 0;
 		goto out;
 	}
+	test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data,
+				       skb_tailroom(tx_skb),
+				       PCI_DMA_FROMDEVICE);
 	pkt_data = skb_put(tx_skb, pkt_len);
 	for (i = 0; i < pkt_len; i++)
 		pkt_data[i] = (u8)(i & 0xff);
-	test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data,
-				       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].buf = cpu_to_le32(test_dma_addr);
@@ -4437,7 +4441,7 @@ static int nv_loopback_test(struct net_d
 	}
 
 	pci_unmap_page(np->pci_dev, test_dma_addr,
-		       tx_skb->end-tx_skb->data,
+		       (skb_end_pointer(tx_skb) - tx_skb->data),
 		       PCI_DMA_TODEVICE);
 	dev_kfree_skb_any(tx_skb);
  out:
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4a05c14..a4a2a0e 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -24,7 +24,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -160,7 +159,8 @@ static int fs_enet_rx_napi(struct net_de
 				skbn = dev_alloc_skb(pkt_len + 2);
 				if (skbn != NULL) {
 					skb_reserve(skbn, 2);	/* align IP header */
-					memcpy(skbn->data, skb->data, pkt_len);
+					skb_copy_from_linear_data(skb,
+						      skbn->data, pkt_len);
 					/* swap */
 					skbt = skb;
 					skb = skbn;
@@ -170,7 +170,6 @@ static int fs_enet_rx_napi(struct net_de
 				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
 
 			if (skbn != NULL) {
-				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				skb->protocol = eth_type_trans(skb, dev);
 				received++;
@@ -294,7 +293,8 @@ static int fs_enet_rx_non_napi(struct ne
 				skbn = dev_alloc_skb(pkt_len + 2);
 				if (skbn != NULL) {
 					skb_reserve(skbn, 2);	/* align IP header */
-					memcpy(skbn->data, skb->data, pkt_len);
+					skb_copy_from_linear_data(skb,
+						      skbn->data, pkt_len);
 					/* swap */
 					skbt = skb;
 					skb = skbn;
@@ -304,7 +304,6 @@ static int fs_enet_rx_non_napi(struct ne
 				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
 
 			if (skbn != NULL) {
-				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				skb->protocol = eth_type_trans(skb, dev);
 				received++;
@@ -516,7 +515,6 @@ void fs_init_bds(struct net_device *dev)
 			break;
 		}
 		fep->rx_skbuff[i] = skb;
-		skb->dev = dev;
 		CBDW_BUFADDR(bdp,
 			dma_map_single(fep->dev, skb->data,
 				L1_CACHE_ALIGN(PKT_MAXBUF_SIZE),
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 8545e84..5603121 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -21,7 +21,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index cdcfb96..04b4f80 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -21,7 +21,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 65925b5..d0f2898 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -21,7 +21,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index f914478..d384010 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -22,7 +22,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 235b177..0a563a8 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -21,7 +21,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index d981d4c..b666a0c 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -942,18 +942,18 @@ static inline void gfar_tx_checksum(stru
 
 	/* Tell the controller what the protocol is */
 	/* And provide the already calculated phcs */
-	if (skb->nh.iph->protocol == IPPROTO_UDP) {
+	if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
 		flags |= TXFCB_UDP;
-		fcb->phcs = skb->h.uh->check;
+		fcb->phcs = udp_hdr(skb)->check;
 	} else
-		fcb->phcs = skb->h.th->check;
+		fcb->phcs = udp_hdr(skb)->check;
 
 	/* l3os is the distance between the start of the
 	 * frame (skb->data) and the start of the IP hdr.
 	 * l4os is the distance between the start of the
 	 * l3 hdr and the l4 hdr */
-	fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
-	fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+	fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN);
+	fcb->l4os = skb_network_header_len(skb);
 
 	fcb->flags = flags;
 }
@@ -1295,8 +1295,6 @@ struct sk_buff * gfar_new_skb(struct net
 	 */
 	skb_reserve(skb, alignamount);
 
-	skb->dev = dev;
-
 	bdp->bufPtr = dma_map_single(NULL, skb->data,
 			priv->rx_buffer_size, DMA_FROM_DEVICE);
 
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index c3c0d67..2521b11 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1568,7 +1568,6 @@ #ifdef RX_CHECKSUM
 				printk(KERN_ERR "%s: rx_copybreak non-zero "
 				  "not good with RX_CHECKSUM\n", dev->name);
 #endif
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(hmp->pci_dev,
 							    hmp->rx_ring[entry].addr,
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 30baf6e..17ac697 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -415,11 +415,18 @@ static int ser12_open(struct net_device 
 
 	if (!dev || !bc)
 		return -ENXIO;
-	if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
-	    dev->irq < 2 || dev->irq > 15)
+	if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
+	    dev->irq < 2 || dev->irq > NR_IRQS) {
+		printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
+				"or irq (2 <= irq <= %d)\n",
+				0xffff-SER12_EXTENT, NR_IRQS);
 		return -ENXIO;
-	if (bc->baud < 300 || bc->baud > 4800)
+	}
+	if (bc->baud < 300 || bc->baud > 4800) {
+		printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
+				"(300...4800)\n");
 		return -EINVAL;
+	}
 	if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
 		printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", 
 		       dev->base_addr);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index d254269..656f278 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -282,7 +282,7 @@ static int bpq_xmit(struct sk_buff *skb,
 	}
 
 	skb->protocol = ax25_type_trans(skb, dev);
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 	dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
 	bpq->stats.tx_packets++;
 	bpq->stats.tx_bytes+=skb->len;
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 0fbb414..3be8c50 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -930,7 +930,7 @@ static int scc_send_packet(struct sk_buf
 
 	/* Transfer data to DMA buffer */
 	i = priv->tx_head;
-	memcpy(priv->tx_buf[i], skb->data + 1, skb->len - 1);
+	skb_copy_from_linear_data_offset(skb, 1, priv->tx_buf[i], skb->len - 1);
 	priv->tx_len[i] = skb->len - 1;
 
 	/* Clear interrupts while we touch our circular buffers */
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index f5a17ad..b33adc6 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -317,7 +317,9 @@ void hdlcdrv_transmitter(struct net_devi
 				dev_kfree_skb_irq(skb);
 				break;
 			}
-			memcpy(s->hdlctx.buffer, skb->data+1, pkt_len);
+			skb_copy_from_linear_data_offset(skb, 1,
+							 s->hdlctx.buffer,
+							 pkt_len);
 			dev_kfree_skb_irq(skb);
 			s->hdlctx.bp = s->hdlctx.buffer;
 			append_crc_ccitt(s->hdlctx.buffer, pkt_len);
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index ee3ea4f..467559d 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -638,7 +638,9 @@ static void yam_tx_byte(struct net_devic
         			dev_kfree_skb_any(skb);
 				break;
 			}
-			memcpy(yp->tx_buf, skb->data + 1, yp->tx_len);
+			skb_copy_from_linear_data_offset(skb, 1,
+							 yp->tx_buf,
+							 yp->tx_len);
 			dev_kfree_skb_any(skb);
 			yp->tx_count = 0;
 			yp->tx_crcl = 0x21;
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 7dc5185..8118a67 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1816,7 +1816,6 @@ #endif
 			u_char *ptr;
 
 			skb_reserve(skb,2);
-			skb->dev = dev;
 
 			/* ptr to start of the sk_buff data area */
 			skb_put(skb, pkt_len);
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index dd8ad87..50035eb 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -27,7 +27,6 @@ #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
@@ -1338,7 +1337,7 @@ static inline int emac_rx_sg_append(stru
 			dev_kfree_skb(dev->rx_sg_skb);
 			dev->rx_sg_skb = NULL;
 		} else {
-			cacheable_memcpy(dev->rx_sg_skb->tail,
+			cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
 					 dev->rx_skb[slot]->data, len);
 			skb_put(dev->rx_sg_skb, len);
 			emac_recycle_rx_skb(dev, slot, len);
@@ -1398,7 +1397,6 @@ static int emac_poll_rx(void *param, int
 
 		skb_put(skb, len);
 	      push_packet:
-		skb->dev = dev->ndev;
 		skb->protocol = eth_type_trans(skb, dev->ndev);
 		emac_rx_csum(dev, skb, ctrl);
 
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 3f946c8..fe85d6f 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -601,7 +601,6 @@ static void irqrx_handler(struct net_dev
 
 				/* set up skb fields */
 
-				skb->dev = dev;
 				skb->protocol = eth_type_trans(skb, dev);
 				skb->ip_summed = CHECKSUM_NONE;
 
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 458db05..3bec0f7 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driv
 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);
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
 static struct kobj_type ktype_veth_pool;
 
 #ifdef CONFIG_PROC_FS
@@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(s
 	}
 }
 
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
 {
 	ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
 
@@ -798,7 +798,6 @@ static int ibmveth_poll(struct net_devic
 
 				skb_reserve(skb, offset);
 				skb_put(skb, length);
-				skb->dev = netdev;
 				skb->protocol = eth_type_trans(skb, netdev);
 
 				netif_receive_skb(skb);	/* send it up */
@@ -954,14 +953,16 @@ static int __devinit ibmveth_probe(struc
 	ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
 					dev->unit_address);
 
-	mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
+	mac_addr_p = (unsigned char *) vio_get_attribute(dev,
+						VETH_MAC_ADDR, NULL);
 	if(!mac_addr_p) {
 		printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
 				"attribute\n", __FILE__, __LINE__);
 		return 0;
 	}
 
-	mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
+	mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+						VETH_MCAST_FILTER_SIZE, NULL);
 	if(!mcastFilterSize_p) {
 		printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
 				"VETH_MCAST_FILTER_SIZE attribute\n",
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 4ad7807..f749e07 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -633,8 +633,6 @@ #endif
 
 			ip->rx_skbs[rx_entry] = NULL;	/* Poison  */
 
-			new_skb->dev = priv_netdev(ip);
-
 			/* Because we reserve afterwards. */
 			skb_put(new_skb, (1664 + RX_OFFSET));
 			rxb = (struct ioc3_erxbuf *) new_skb->data;
@@ -940,7 +938,6 @@ static void ioc3_alloc_rings(struct net_
 			}
 
 			ip->rx_skbs[i] = skb;
-			skb->dev = dev;
 
 			/* Because we reserve afterwards. */
 			skb_put(skb, (1664 + RX_OFFSET));
@@ -1396,9 +1393,9 @@ #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 	 * manually.
 	 */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		int proto = ntohs(skb->nh.iph->protocol);
+		const struct iphdr *ih = ip_hdr(skb);
+		const int proto = ntohs(ih->protocol);
 		unsigned int csoff;
-		struct iphdr *ih = skb->nh.iph;
 		uint32_t csum, ehsum;
 		uint16_t *eh;
 
@@ -1425,11 +1422,11 @@ #ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 		csoff = ETH_HLEN + (ih->ihl << 2);
 		if (proto == IPPROTO_UDP) {
 			csoff += offsetof(struct udphdr, check);
-			skb->h.uh->check = csum;
+			udp_hdr(skb)->check = csum;
 		}
 		if (proto == IPPROTO_TCP) {
 			csoff += offsetof(struct tcphdr, check);
-			skb->h.th->check = csum;
+			tcp_hdr(skb)->check = csum;
 		}
 
 		w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
@@ -1446,7 +1443,7 @@ #endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 
 	if (len <= 104) {
 		/* Short packet, let's copy it directly into the ring.  */
-		memcpy(desc->data, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, desc->data, skb->len);
 		if (len < ETH_ZLEN) {
 			/* Very short packet, pad with zeros at the end. */
 			memset(desc->data + len, 0, ETH_ZLEN - len);
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index cebf8c3..f9c889c 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1472,9 +1472,8 @@ static int ali_ircc_fir_hard_xmit(struct
 
 	self->stats.tx_bytes += skb->len;
 
-	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
-	       skb->len);
-	
+	skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
+		      skb->len);
 	self->tx_fifo.len++;
 	self->tx_fifo.free++;
 
@@ -1924,7 +1923,7 @@ static int  ali_ircc_dma_receive_complet
 			
 			/* Copy frame without CRC, CRC is removed by hardware*/
 			skb_put(skb, len);
-			memcpy(skb->data, self->rx_buff.data, len);
+			skb_copy_to_linear_data(skb, self->rx_buff.data, len);
 
 			/* Move to next frame */
 			self->rx_buff.data += len;
@@ -1932,7 +1931,7 @@ static int  ali_ircc_dma_receive_complet
 			self->stats.rx_packets++;
 
 			skb->dev = self->netdev;
-			skb->mac.raw  = skb->data;
+			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
 			self->netdev->last_rx = jiffies;
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 37914dc..4dbdfaa 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -526,7 +526,7 @@ #endif
 	
 	if (aup->speed == 4000000) {
 		/* FIR */
-		memcpy((void *)pDB->vaddr, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, pDB->vaddr, skb->len);
 		ptxd->count_0 = skb->len & 0xff;
 		ptxd->count_1 = (skb->len >> 8) & 0xff;
 
@@ -604,9 +604,9 @@ static int au1k_irda_rx(struct net_devic
 				skb_put(skb, count);
 			else
 				skb_put(skb, count-2);
-			memcpy(skb->data, (void *)pDB->vaddr, count-2);
+			skb_copy_to_linear_data(skb, pDB->vaddr, count - 2);
 			skb->dev = dev;
-			skb->mac.raw = skb->data;
+			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
 			prxd->count_0 = 0;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 11af0ae..3ca47bf 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1119,7 +1119,7 @@ #endif
   else
     {
       len = skb->len;
-      memcpy (self->tx_bufs[self->txs], skb->data, len);
+      skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len);
     }
   self->ring->tx[self->txs].len = len & 0x0fff;
 
@@ -1282,11 +1282,11 @@ #endif
                       skb_reserve (skb, 1);
 
                       skb_put (skb, len);
-                      memcpy (skb->data, self->rx_bufs[self->rxs], len);
-
+                      skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs],
+					      len);
                       self->stats.rx_packets++;
                       skb->dev = self->netdev;
-                      skb->mac.raw = skb->data;
+                      skb_reset_mac_header(skb);
                       skb->protocol = htons (ETH_P_IRDA);
                     }
                   else
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 1d510bd..0ac240c 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -441,7 +441,7 @@ static int irda_usb_hard_xmit(struct sk_
 		goto drop;
 	}
 
-	memcpy(self->tx_buff + self->header_length, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, self->tx_buff + self->header_length, skb->len);
 
 	/* Change setting for next frame */
 	if (self->capability & IUC_STIR421X) {
@@ -902,7 +902,7 @@ static void irda_usb_receive(struct urb 
 
 	if(docopy) {
 		/* Copy packet, so we can recycle the original */
-		memcpy(newskb->data, skb->data, urb->actual_length);
+		skb_copy_from_linear_data(skb, newskb->data, urb->actual_length);
 		/* Deliver this new skb */
 		dataskb = newskb;
 		/* And hook the old skb to the URB
@@ -921,7 +921,7 @@ static void irda_usb_receive(struct urb 
 
 	/* Ask the networking layer to queue the packet for the IrDA stack */
 	dataskb->dev = self->netdev;
-	dataskb->mac.raw  = dataskb->data;
+	skb_reset_mac_header(dataskb);
 	dataskb->protocol = htons(ETH_P_IRDA);
 	len = dataskb->len;
 	netif_rx(dataskb);
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index f0c61f3..0de8672 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -200,14 +200,14 @@ static inline int mcs_setup_transceiver_
 /* Setup a communication between mcs7780 and agilent chip. */
 static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs)
 {
-	IRDA_WARNING("This transceiver type is not supported yet.");
+	IRDA_WARNING("This transceiver type is not supported yet.\n");
 	return 1;
 }
 
 /* Setup a communication between mcs7780 and sharp chip. */
 static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs)
 {
-	IRDA_WARNING("This transceiver type is not supported yet.");
+	IRDA_WARNING("This transceiver type is not supported yet.\n");
 	return 1;
 }
 
@@ -279,7 +279,7 @@ static inline int mcs_setup_transceiver(
 		break;
 
 	default:
-		IRDA_WARNING("Unknown transceiver type: %d",
+		IRDA_WARNING("Unknown transceiver type: %d\n",
 			     mcs->transceiver_type);
 		ret = 1;
 	}
@@ -318,7 +318,7 @@ static inline int mcs_setup_transceiver(
 		return ret;
 
 error:
-	IRDA_ERROR("%s", msg);
+	IRDA_ERROR("%s\n", msg);
 	return ret;
 }
 
@@ -353,7 +353,7 @@ static unsigned mcs_wrap_fir_skb(const s
 	buf[0] = len & 0xff;
 	buf[1] = (len >> 8) & 0xff;
 	/* copy the data into the tx buffer. */
-	memcpy(buf+2, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, buf + 2, skb->len);
 	/* put the fcs in the last four bytes in little endian order. */
 	buf[len - 4] = fcs & 0xff;
 	buf[len - 3] = (fcs >> 8) & 0xff;
@@ -377,7 +377,7 @@ static unsigned mcs_wrap_mir_skb(const s
 	buf[0] = len & 0xff;
 	buf[1] = (len >> 8) & 0xff;
 	/* copy the data */
-	memcpy(buf+2, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, buf + 2, skb->len);
 	/* put the fcs in last two bytes in little endian order. */
 	buf[len - 2] = fcs & 0xff;
 	buf[len - 1] = (fcs >> 8) & 0xff;
@@ -426,9 +426,9 @@ static void mcs_unwrap_mir(struct mcs_cb
 	}
 
 	skb_reserve(skb, 1);
-	memcpy(skb->data, buf, new_len);
+	skb_copy_to_linear_data(skb, buf, new_len);
 	skb_put(skb, new_len);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	skb->dev = mcs->netdev;
 
@@ -479,9 +479,9 @@ static void mcs_unwrap_fir(struct mcs_cb
 	}
 
 	skb_reserve(skb, 1);
-	memcpy(skb->data, buf, new_len);
+	skb_copy_to_linear_data(skb, buf, new_len);
 	skb_put(skb, new_len);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	skb->dev = mcs->netdev;
 
@@ -587,7 +587,7 @@ static int mcs_speed_change(struct mcs_c
 	} while(cnt++ < 100 && (rval & MCS_IRINTX));
 
 	if(cnt >= 100) {
-		IRDA_ERROR("unable to change speed");
+		IRDA_ERROR("unable to change speed\n");
 		ret = -EIO;
 		goto error;
 	}
@@ -638,7 +638,7 @@ static int mcs_speed_change(struct mcs_c
 
 		default:
 			ret = 1;
-			IRDA_WARNING("Unknown transceiver type: %d",
+			IRDA_WARNING("Unknown transceiver type: %d\n",
 				     mcs->transceiver_type);
 		}
 	if (unlikely(ret))
@@ -733,7 +733,7 @@ static int mcs_net_open(struct net_devic
 	sprintf(hwname, "usb#%d", mcs->usbdev->devnum);
 	mcs->irlap = irlap_open(netdev, &mcs->qos, hwname);
 	if (!mcs->irlap) {
-		IRDA_ERROR("mcs7780: irlap_open failed");
+		IRDA_ERROR("mcs7780: irlap_open failed\n");
 		goto error2;
 	}
 
@@ -862,7 +862,7 @@ static int mcs_hard_xmit(struct sk_buff 
 			  mcs->out_buf, wraplen, mcs_send_irq, mcs);
 
 	if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) {
-		IRDA_ERROR("failed tx_urb: %d", ret);
+		IRDA_ERROR("failed tx_urb: %d\n", ret);
 		switch (ret) {
 		case -ENODEV:
 		case -EPIPE:
@@ -897,7 +897,7 @@ static int mcs_probe(struct usb_interfac
 	if (!ndev)
 		goto error1;
 
-	IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.", udev->devnum);
+	IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
 
 	/* what is it realy for? */
 	SET_MODULE_OWNER(ndev);
@@ -905,7 +905,7 @@ static int mcs_probe(struct usb_interfac
 
 	ret = usb_reset_configuration(udev);
 	if (ret != 0) {
-		IRDA_ERROR("mcs7780: usb reset configuration failed");
+		IRDA_ERROR("mcs7780: usb reset configuration failed\n");
 		goto error2;
 	}
 
@@ -950,7 +950,7 @@ static int mcs_probe(struct usb_interfac
 	if (ret != 0)
 		goto error2;
 
-	IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s",
+	IRDA_DEBUG(1, "IrDA: Registered MosChip MCS7780 device as %s\n",
 		   ndev->name);
 
 	mcs->transceiver_type = transceiver_type;
@@ -981,7 +981,7 @@ static void mcs_disconnect(struct usb_in
 	free_netdev(mcs->netdev);
 
 	usb_set_intfdata(intf, NULL);
-	IRDA_DEBUG(0, "MCS7780 now disconnected.");
+	IRDA_DEBUG(0, "MCS7780 now disconnected.\n");
 }
 
 /* Module insertion */
@@ -992,7 +992,7 @@ static int __init mcs_init(void)
 	/* register this driver with the USB subsystem */
 	result = usb_register(&mcs_driver);
 	if (result)
-		IRDA_ERROR("usb_register failed. Error number %d", result);
+		IRDA_ERROR("usb_register failed. Error number %d\n", result);
 
 	return result;
 }
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 29b5ccd..d96c897 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1466,9 +1466,8 @@ static int nsc_ircc_hard_xmit_fir(struct
 
 	self->stats.tx_bytes += skb->len;
 
-	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
-	       skb->len);
-	
+	skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
+		      skb->len);
 	self->tx_fifo.len++;
 	self->tx_fifo.free++;
 
@@ -1869,10 +1868,14 @@ static int nsc_ircc_dma_receive_complete
 			/* Copy frame without CRC */
 			if (self->io.speed < 4000000) {
 				skb_put(skb, len-2);
-				memcpy(skb->data, self->rx_buff.data, len-2);
+				skb_copy_to_linear_data(skb,
+							self->rx_buff.data,
+							len - 2);
 			} else {
 				skb_put(skb, len-4);
-				memcpy(skb->data, self->rx_buff.data, len-4);
+				skb_copy_to_linear_data(skb,
+							self->rx_buff.data,
+							len - 4);
 			}
 
 			/* Move to next frame */
@@ -1881,7 +1884,7 @@ static int nsc_ircc_dma_receive_complete
 			self->stats.rx_packets++;
 
 			skb->dev = self->netdev;
-			skb->mac.raw  = skb->data;
+			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
 			self->netdev->last_rx = jiffies;
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 2272156..55ff0fb 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -134,7 +134,7 @@ static int pxa_irda_set_speed(struct pxa
 			DCSR(si->rxdma) &= ~DCSR_RUN;
 			/* disable FICP */
 			ICCR0 = 0;
-			pxa_set_cken(CKEN13_FICP, 0);
+			pxa_set_cken(CKEN_FICP, 0);
 
 			/* set board transceiver to SIR mode */
 			si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
@@ -144,7 +144,7 @@ static int pxa_irda_set_speed(struct pxa
 			pxa_gpio_mode(GPIO47_STTXD_MD);
 
 			/* enable the STUART clock */
-			pxa_set_cken(CKEN5_STUART, 1);
+			pxa_set_cken(CKEN_STUART, 1);
 		}
 
 		/* disable STUART first */
@@ -169,7 +169,7 @@ static int pxa_irda_set_speed(struct pxa
 		/* disable STUART */
 		STIER = 0;
 		STISR = 0;
-		pxa_set_cken(CKEN5_STUART, 0);
+		pxa_set_cken(CKEN_STUART, 0);
 
 		/* disable FICP first */
 		ICCR0 = 0;
@@ -182,7 +182,7 @@ static int pxa_irda_set_speed(struct pxa
 		pxa_gpio_mode(GPIO47_ICPTXD_MD);
 
 		/* enable the FICP clock */
-		pxa_set_cken(CKEN13_FICP, 1);
+		pxa_set_cken(CKEN_FICP, 1);
 
 		si->speed = speed;
 		pxa_irda_fir_dma_rx_start(si);
@@ -386,12 +386,12 @@ static void pxa_irda_fir_irq_eif(struct 
 
 		/* Align IP header to 20 bytes  */
 		skb_reserve(skb, 1);
-		memcpy(skb->data, si->dma_rx_buff, len);
+		skb_copy_to_linear_data(skb, si->dma_rx_buff, len);
 		skb_put(skb, len);
 
 		/* Feed it to IrLAP  */
 		skb->dev = dev;
-		skb->mac.raw  = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = htons(ETH_P_IRDA);
 		netif_rx(skb);
 
@@ -484,7 +484,7 @@ static int pxa_irda_hard_xmit(struct sk_
 		unsigned long mtt = irda_get_mtt(skb);
 
 		si->dma_tx_buff_len = skb->len;
-		memcpy(si->dma_tx_buff, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len);
 
 		if (mtt)
 			while ((unsigned)(OSCR - si->last_oscr)/4 < mtt)
@@ -593,7 +593,7 @@ static void pxa_irda_shutdown(struct pxa
 	/* disable STUART SIR mode */
 	STISR = 0;
 	/* disable the STUART clock */
-	pxa_set_cken(CKEN5_STUART, 0);
+	pxa_set_cken(CKEN_STUART, 0);
 
 	/* disable DMA */
 	DCSR(si->txdma) &= ~DCSR_RUN;
@@ -601,7 +601,7 @@ static void pxa_irda_shutdown(struct pxa
 	/* disable FICP */
 	ICCR0 = 0;
 	/* disable the FICP clock */
-	pxa_set_cken(CKEN13_FICP, 0);
+	pxa_set_cken(CKEN_FICP, 0);
 
 	DRCMR17 = 0;
 	DRCMR18 = 0;
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 937372d..056639f 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -504,7 +504,7 @@ static void sa1100_irda_fir_error(struct
 
 		skb_put(skb, len);
 		skb->dev = dev;
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = htons(ETH_P_IRDA);
 		si->stats.rx_packets++;
 		si->stats.rx_bytes += len;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 17b0c3a..9d6c8f3 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 
 #include <net/irda/irda.h>
diff --git a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c
index d7e32d9..25d5b8a 100644
--- a/drivers/net/irda/sir_dongle.c
+++ b/drivers/net/irda/sir_dongle.c
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/kmod.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 31c6233..9043bf4 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -79,11 +79,17 @@ MODULE_AUTHOR("Daniele Peri <peri@csai.u
 MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
 MODULE_LICENSE("GPL");
 
-static int ircc_dma = 255;
+static int smsc_nopnp;
+module_param_named(nopnp, smsc_nopnp, bool, 0);
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
+
+#define DMA_INVAL 255
+static int ircc_dma = DMA_INVAL;
 module_param(ircc_dma, int, 0);
 MODULE_PARM_DESC(ircc_dma, "DMA channel");
 
-static int ircc_irq = 255;
+#define IRQ_INVAL 255
+static int ircc_irq = IRQ_INVAL;
 module_param(ircc_irq, int, 0);
 MODULE_PARM_DESC(ircc_irq, "IRQ line");
 
@@ -315,6 +321,7 @@ static struct smsc_chip __initdata lpc_c
 {
 	/* Base address 0x2E or 0x4E */
 	{ "47N227",	KEY55_1|FIR|SERx4,	0x5a, 0x00 },
+	{ "47N227",	KEY55_1|FIR|SERx4,	0x7a, 0x00 },
 	{ "47N267",	KEY55_1|FIR|SERx4,	0x5e, 0x00 },
 	{ NULL }
 };
@@ -359,7 +366,6 @@ static inline void register_bank(int iob
                iobase + IRCC_MASTER);
 }
 
-#ifdef	CONFIG_PNP
 /* PNP hotplug support */
 static const struct pnp_device_id smsc_ircc_pnp_table[] = {
 	{ .id = "SMCf010", .driver_data = 0 },
@@ -367,7 +373,35 @@ static const struct pnp_device_id smsc_i
 	{ }
 };
 MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
-#endif
+
+static int pnp_driver_registered;
+
+static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev,
+				      const struct pnp_device_id *dev_id)
+{
+	unsigned int firbase, sirbase;
+	u8 dma, irq;
+
+	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
+	      pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0)))
+		return -EINVAL;
+
+	sirbase = pnp_port_start(dev, 0);
+	firbase = pnp_port_start(dev, 1);
+	dma = pnp_dma(dev, 0);
+	irq = pnp_irq(dev, 0);
+
+	if (smsc_ircc_open(firbase, sirbase, dma, irq))
+		return -ENODEV;
+
+	return 0;
+}
+
+static struct pnp_driver smsc_ircc_pnp_driver = {
+	.name		= "smsc-ircc2",
+	.id_table	= smsc_ircc_pnp_table,
+	.probe		= smsc_ircc_pnp_probe,
+};
 
 
 /*******************************************************************************
@@ -378,6 +412,35 @@ #endif
  *
  *******************************************************************************/
 
+static int __init smsc_ircc_legacy_probe(void)
+{
+	int ret = 0;
+
+	if (ircc_fir > 0 && ircc_sir > 0) {
+		IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
+		IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+
+		if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
+			ret = -ENODEV;
+	} else {
+		ret = -ENODEV;
+
+		/* try user provided configuration register base address */
+		if (ircc_cfg > 0) {
+			IRDA_MESSAGE(" Overriding configuration address "
+				     "0x%04x\n", ircc_cfg);
+			if (!smsc_superio_fdc(ircc_cfg))
+				ret = 0;
+			if (!smsc_superio_lpc(ircc_cfg))
+				ret = 0;
+		}
+
+		if (smsc_ircc_look_for_chips() > 0)
+			ret = 0;
+	}
+	return ret;
+}
+
 /*
  * Function smsc_ircc_init ()
  *
@@ -405,31 +468,20 @@ #endif
 
 	dev_count = 0;
 
-	if (ircc_fir > 0 && ircc_sir > 0) {
-		IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
-		IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
-
-		if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
-			ret = -ENODEV;
+	if (smsc_nopnp || !pnp_platform_devices ||
+	    ircc_cfg || ircc_fir || ircc_sir ||
+	    ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) {
+		ret = smsc_ircc_legacy_probe();
 	} else {
-		ret = -ENODEV;
-
-		/* try user provided configuration register base address */
-		if (ircc_cfg > 0) {
-			IRDA_MESSAGE(" Overriding configuration address "
-				     "0x%04x\n", ircc_cfg);
-			if (!smsc_superio_fdc(ircc_cfg))
-				ret = 0;
-			if (!smsc_superio_lpc(ircc_cfg))
-				ret = 0;
-		}
-
-		if (smsc_ircc_look_for_chips() > 0)
-			ret = 0;
+		if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0)
+			pnp_driver_registered = 1;
 	}
 
-	if (ret)
+	if (ret) {
+		if (pnp_driver_registered)
+			pnp_unregister_driver(&smsc_ircc_pnp_driver);
 		platform_driver_unregister(&smsc_ircc_driver);
+	}
 
 	return ret;
 }
@@ -645,7 +697,7 @@ static void smsc_ircc_setup_io(struct sm
 	self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;
 	self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;
 
-	if (irq < 255) {
+	if (irq != IRQ_INVAL) {
 		if (irq != chip_irq)
 			IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
 				     driver_name, chip_irq, irq);
@@ -653,7 +705,7 @@ static void smsc_ircc_setup_io(struct sm
 	} else
 		self->io.irq = chip_irq;
 
-	if (dma < 255) {
+	if (dma != DMA_INVAL) {
 		if (dma != chip_dma)
 			IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
 				     driver_name, chip_dma, dma);
@@ -1161,7 +1213,7 @@ static int smsc_ircc_hard_xmit_fir(struc
 		self->new_speed = speed;
 	}
 
-	memcpy(self->tx_buff.head, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, self->tx_buff.head, skb->len);
 
 	self->tx_buff.len = skb->len;
 	self->tx_buff.data = self->tx_buff.head;
@@ -1412,7 +1464,7 @@ #endif
 	self->stats.rx_bytes += len;
 
 	skb->dev = self->netdev;
-	skb->mac.raw  = skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	netif_rx(skb);
 }
@@ -1839,6 +1891,9 @@ static void __exit smsc_ircc_cleanup(voi
 			smsc_ircc_close(dev_self[i]);
 	}
 
+	if (pnp_driver_registered)
+		pnp_unregister_driver(&smsc_ircc_pnp_driver);
+
 	platform_driver_unregister(&smsc_ircc_driver);
 }
 
@@ -2835,9 +2890,9 @@ static int __init smsc_ircc_preconfigure
 					tmpconf.fir_io = ircc_fir;
 				if (ircc_sir != 0)
 					tmpconf.sir_io = ircc_sir;
-				if (ircc_dma != 0xff)
+				if (ircc_dma != DMA_INVAL)
 					tmpconf.fir_dma = ircc_dma;
-				if (ircc_irq != 0xff)
+				if (ircc_irq != IRQ_INVAL)
 					tmpconf.fir_irq = ircc_irq;
 
 				IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name);
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 20d306f..755aa44 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -52,7 +52,6 @@ #include <linux/crc32.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 #include <net/irda/irda.h>
-#include <net/irda/irlap.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/wrapper.h>
 #include <net/irda/crc.h>
@@ -349,7 +348,7 @@ static void fir_eof(struct stir_cb *stir
 		}
 		skb_reserve(nskb, 1);
 		skb = nskb;
-		memcpy(nskb->data, rx_buff->data, len);
+		skb_copy_to_linear_data(nskb, rx_buff->data, len);
 	} else {
 		nskb = dev_alloc_skb(rx_buff->truesize);
 		if (unlikely(!nskb)) {
@@ -364,7 +363,7 @@ static void fir_eof(struct stir_cb *stir
 
 	skb_put(skb, len);
 
-	skb->mac.raw  = skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	skb->dev = stir->netdev;
 
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index c3ed9b3..ff53585 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -925,8 +925,8 @@ static int via_ircc_hard_xmit_fir(struct
 
 	self->tx_fifo.tail += skb->len;
 	self->stats.tx_bytes += skb->len;
-	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data,
-	       skb->len);
+	skb_copy_from_linear_data(skb,
+		      self->tx_fifo.queue[self->tx_fifo.free].start, skb->len);
 	self->tx_fifo.len++;
 	self->tx_fifo.free++;
 //F01   if (self->tx_fifo.len == 1) {
@@ -1125,7 +1125,7 @@ static int via_ircc_dma_receive_complete
 		self->stats.rx_bytes += len;
 		self->stats.rx_packets++;
 		skb->dev = self->netdev;
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = htons(ETH_P_IRDA);
 		netif_rx(skb);
 		return TRUE;
@@ -1189,7 +1189,7 @@ F01_E */
 		skb_reserve(skb, 1);
 		skb_put(skb, len - 4);
 
-		memcpy(skb->data, self->rx_buff.data, len - 4);
+		skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
 		IRDA_DEBUG(2, "%s(): len=%x.rx_buff=%p\n", __FUNCTION__,
 			   len - 4, self->rx_buff.data);
 
@@ -1198,7 +1198,7 @@ F01_E */
 		self->stats.rx_bytes += len;
 		self->stats.rx_packets++;
 		skb->dev = self->netdev;
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = htons(ETH_P_IRDA);
 		netif_rx(skb);
 
@@ -1234,7 +1234,7 @@ static int upload_rxdata(struct via_ircc
 	}
 	skb_reserve(skb, 1);
 	skb_put(skb, len - 4 + 1);
-	memcpy(skb->data, self->rx_buff.data, len - 4 + 1);
+	skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4 + 1);
 	st_fifo->tail++;
 	st_fifo->len++;
 	if (st_fifo->tail > MAX_RX_WINDOW)
@@ -1244,7 +1244,7 @@ static int upload_rxdata(struct via_ircc
 	self->stats.rx_bytes += len;
 	self->stats.rx_packets++;
 	skb->dev = self->netdev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	netif_rx(skb);
 	if (st_fifo->len < (MAX_RX_WINDOW + 2)) {
@@ -1303,7 +1303,7 @@ static int RxTimerHandler(struct via_irc
 			}
 			skb_reserve(skb, 1);
 			skb_put(skb, len - 4);
-			memcpy(skb->data, self->rx_buff.data, len - 4);
+			skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4);
 
 			IRDA_DEBUG(2, "%s(): len=%x.head=%x\n", __FUNCTION__,
 				   len - 4, st_fifo->head);
@@ -1313,7 +1313,7 @@ static int RxTimerHandler(struct via_irc
 			self->stats.rx_bytes += len;
 			self->stats.rx_packets++;
 			skb->dev = self->netdev;
-			skb->mac.raw = skb->data;
+			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
 		}		//while
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 3457e9d..bf78ef1 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -44,7 +44,6 @@ #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
@@ -595,7 +594,7 @@ static int vlsi_process_rx(struct vlsi_r
 	rd->skb = NULL;
 	skb->dev = ndev;
 	memcpy(skb_put(skb,len), rd->buf, len);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	if (in_interrupt())
 		netif_rx(skb);
 	else
@@ -993,7 +992,7 @@ static int vlsi_hard_start_xmit(struct s
 			goto drop;
 		}
 		else
-			memcpy(rd->buf, skb->data, len);
+			skb_copy_from_linear_data(skb, rd->buf, len);
 	}
 
 	rd->skb = skb;			/* remember skb for tx-complete stats */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 4212657..5182e80 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -529,7 +529,7 @@ int w83977af_hard_xmit(struct sk_buff *s
 	/* Decide if we should use PIO or DMA transfer */
 	if (self->io.speed > PIO_MAX_SPEED) {
 		self->tx_buff.data = self->tx_buff.head;
-		memcpy(self->tx_buff.data, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, self->tx_buff.data, skb->len);
 		self->tx_buff.len = skb->len;
 		
 		mtt = irda_get_mtt(skb);
@@ -908,10 +908,14 @@ #endif
 			/* Copy frame without CRC */
 			if (self->io.speed < 4000000) {
 				skb_put(skb, len-2);
-				memcpy(skb->data, self->rx_buff.data, len-2);
+				skb_copy_to_linear_data(skb,
+							self->rx_buff.data,
+							len - 2);
 			} else {
 				skb_put(skb, len-4);
-				memcpy(skb->data, self->rx_buff.data, len-4);
+				skb_copy_to_linear_data(skb,
+							self->rx_buff.data,
+							len - 4);
 			}
 
 			/* Move to next frame */
@@ -919,7 +923,7 @@ #endif
 			self->stats.rx_packets++;
 			
 			skb->dev = self->netdev;
-			skb->mac.raw  = skb->data;
+			skb_reset_mac_header(skb);
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
 			self->netdev->last_rx = jiffies;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 0e9ba3c..347d50c 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1540,7 +1540,6 @@ static void veth_receive(struct veth_lpa
 		}
 
 		skb_put(skb, length);
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 		skb->ip_summed = CHECKSUM_NONE;
 		netif_rx(skb);	/* send it up */
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index cf30a10..c8e9086 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -111,9 +111,6 @@ #define IXGB_RXBUFFER_16384 16384
 /* How many Rx Buffers do we bundle into one write to the hardware ? */
 #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)))
-
 /* wrapper around a pointer to a socket buffer,
  * so a DMA handle can be stored along with the buffer */
 struct ixgb_buffer {
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index d6628bd..afde848 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *ne
 
 	rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD);
 	rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD);
-	IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); 
+	rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
 
 	txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD);
 	txdr->count = min(txdr->count,(uint32_t)MAX_TXD);
-	IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); 
+	txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
 
 	if(netif_running(adapter->netdev)) {
 		/* Try to get new resources before deleting old */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index afc2ec7..6d2b059 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adap
 	/* round up to nearest 4K */
 
 	txdr->size = txdr->count * sizeof(struct ixgb_tx_desc);
-	IXGB_ROUNDUP(txdr->size, 4096);
+	txdr->size = ALIGN(txdr->size, 4096);
 
 	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
 	if(!txdr->desc) {
@@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adap
 	/* Round up to nearest 4K */
 
 	rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc);
-	IXGB_ROUNDUP(rxdr->size, 4096);
+	rxdr->size = ALIGN(rxdr->size, 4096);
 
 	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
@@ -1182,24 +1182,27 @@ ixgb_tso(struct ixgb_adapter *adapter, s
 
 	if (likely(skb_is_gso(skb))) {
 		struct ixgb_buffer *buffer_info;
+		struct iphdr *iph;
+
 		if (skb_header_cloned(skb)) {
 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
 			if (err)
 				return err;
 		}
 
-		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 		mss = skb_shinfo(skb)->gso_size;
-		skb->nh.iph->tot_len = 0;
-		skb->nh.iph->check = 0;
-		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
-						      skb->nh.iph->daddr,
-						      0, IPPROTO_TCP, 0);
-		ipcss = skb->nh.raw - skb->data;
-		ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
-		ipcse = skb->h.raw - skb->data - 1;
-		tucss = skb->h.raw - skb->data;
-		tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
+		iph = ip_hdr(skb);
+		iph->tot_len = 0;
+		iph->check = 0;
+		tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+							 iph->daddr, 0,
+							 IPPROTO_TCP, 0);
+		ipcss = skb_network_offset(skb);
+		ipcso = (void *)&(iph->check) - (void *)skb->data;
+		ipcse = skb_transport_offset(skb) - 1;
+		tucss = skb_transport_offset(skb);
+		tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
 		tucse = 0;
 
 		i = adapter->tx_ring.next_to_use;
@@ -1243,7 +1246,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapte
 
 	if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
 		struct ixgb_buffer *buffer_info;
-		css = skb->h.raw - skb->data;
+		css = skb_transport_offset(skb);
 		cso = css + skb->csum_offset;
 
 		i = adapter->tx_ring.next_to_use;
@@ -2014,9 +2017,12 @@ #define IXGB_CB_LENGTH 256
 			    netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
 			if (new_skb) {
 				skb_reserve(new_skb, NET_IP_ALIGN);
-				memcpy(new_skb->data - NET_IP_ALIGN,
-				       skb->data - NET_IP_ALIGN,
-				       length + NET_IP_ALIGN);
+				skb_copy_to_linear_data_offset(new_skb,
+							       -NET_IP_ALIGN,
+							       (skb->data -
+							        NET_IP_ALIGN),
+							       (length +
+							        NET_IP_ALIGN));
 				/* save the skb in buffer_info as good */
 				buffer_info->skb = skb;
 				skb = new_skb;
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
index 8434d75..9e04a6b 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -34,7 +34,6 @@ #ifndef _IXGB_OSDEP_H_
 #define _IXGB_OSDEP_H_
 
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <asm/io.h>
 #include <linux/interrupt.h>
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index b27442a..5d5ddab 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct 
 	return -1;
 }
 
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
 /**
  * ixgb_check_options - Range Checking for Command Line Parameters
  * @adapter: board private structure
@@ -284,7 +282,7 @@ ixgb_check_options(struct ixgb_adapter *
 		} else {
 			tx_ring->count = opt.def;
 		}
-		IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+		tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
 	}
 	{ /* Receive Descriptor Count */
 		struct ixgb_option opt = {
@@ -303,7 +301,7 @@ ixgb_check_options(struct ixgb_adapter *
 		} else {
 			rx_ring->count = opt.def;
 		}
-		IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+		rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
 	}
 	{ /* Receive Checksum Offload Enable */
 		struct ixgb_option opt = {
@@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter *
 			.name = "Flow Control",
 			.err  = "reading default settings from EEPROM",
 			.def  = ixgb_fc_tx_pause,
-			.arg  = { .l = { .nr = LIST_LEN(fc_list),
+			.arg  = { .l = { .nr = ARRAY_SIZE(fc_list),
 					 .p = fc_list }}
 		};
 
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index a4eccb1..6683afc 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -110,11 +110,10 @@ static int ixpdev_rx(struct net_device *
 
 		skb = dev_alloc_skb(desc->pkt_length + 2);
 		if (likely(skb != NULL)) {
-			skb->dev = nds[desc->channel];
 			skb_reserve(skb, 2);
 			eth_copy_and_sum(skb, buf, desc->pkt_length, 0);
 			skb_put(skb, desc->pkt_length);
-			skb->protocol = eth_type_trans(skb, skb->dev);
+			skb->protocol = eth_type_trans(skb, nds[desc->channel]);
 
 			skb->dev->last_rx = jiffies;
 
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index d34afb5..75f6f44 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -88,6 +88,23 @@ static unsigned short known_revisions[] 
 	0xffff			/* end of list */
 };
 
+static int jazzsonic_open(struct net_device* dev)
+{
+	if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	return sonic_open(dev);
+}
+
+static int jazzsonic_close(struct net_device* dev)
+{
+	int err;
+	err = sonic_close(dev);
+	free_irq(dev->irq, dev);
+	return err;
+}
+
 static int __init sonic_probe1(struct net_device *dev)
 {
 	static unsigned version_printed;
@@ -169,8 +186,8 @@ static int __init sonic_probe1(struct ne
 	lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
 	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
 
-	dev->open = sonic_open;
-	dev->stop = sonic_close;
+	dev->open = jazzsonic_open;
+	dev->stop = jazzsonic_close;
 	dev->hard_start_xmit = sonic_send_packet;
 	dev->get_stats = sonic_get_stats;
 	dev->set_multicast_list = &sonic_multicast_list;
@@ -260,8 +277,6 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet 
 module_param(sonic_debug, int, 0);
 MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
 
-#define SONIC_IRQ_FLAG IRQF_DISABLED
-
 #include "sonic.c"
 
 static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
@@ -269,11 +284,11 @@ static int __devexit jazz_sonic_device_r
 	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sonic_local* lp = netdev_priv(dev);
 
-	unregister_netdev (dev);
+	unregister_netdev(dev);
 	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
 	                  lp->descriptors, lp->descriptors_laddr);
 	release_region (dev->base_addr, SONIC_MEM_SIZE);
-	free_netdev (dev);
+	free_netdev(dev);
 
 	return 0;
 }
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index a384332..0fe96c8 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -988,7 +988,7 @@ static int lance_start_xmit(struct sk_bu
 		if (lance_debug > 5)
 			printk("%s: bouncing a high-memory packet (%#x).\n",
 				   dev->name, (u32)isa_virt_to_bus(skb->data));
-		memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
+		skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len);
 		lp->tx_ring[entry].base =
 			((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
 		dev_kfree_skb(skb);
@@ -1184,7 +1184,6 @@ lance_rx(struct net_device *dev)
 					}
 					break;
 				}
-				skb->dev = dev;
 				skb_reserve(skb,2);	/* 16 byte align */
 				skb_put(skb,pkt_len);	/* Make room */
 				eth_copy_and_sum(skb,
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 452863d..6b49fc4 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -81,7 +81,6 @@ #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/types.h>
 #include <linux/bitops.h>
 
@@ -801,7 +800,6 @@ memory_squeeze:
 				lp->stats.rx_dropped++;
 			}
 			else {
-				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
 					dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index e726c06..5c86e73 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -722,7 +722,6 @@ static void ei_receive(struct net_device
 			else
 			{
 				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
-				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
 				skb->protocol=eth_type_trans(skb,dev);
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 2b739fd..6ba6ed2 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -75,8 +75,9 @@ #define LOOPBACK_OVERHEAD (128 + MAX_HEA
 #ifdef LOOPBACK_TSO
 static void emulate_large_send_offload(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = (struct tcphdr *)(skb_network_header(skb) +
+					      (iph->ihl * 4));
 	unsigned int doffset = (iph->ihl + th->doff) * 4;
 	unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
 	unsigned int offset = 0;
@@ -90,10 +91,11 @@ static void emulate_large_send_offload(s
 		if (!nskb)
 			break;
 		skb_reserve(nskb, 32);
-		nskb->mac.raw = nskb->data - 14;
-		nskb->nh.raw = nskb->data;
-		iph = nskb->nh.iph;
-		memcpy(nskb->data, skb->nh.raw, doffset);
+		skb_set_mac_header(nskb, -ETH_HLEN);
+		skb_reset_network_header(nskb);
+		iph = ip_hdr(nskb);
+		skb_copy_to_linear_data(nskb, skb_network_header(skb),
+					doffset);
 		if (skb_copy_bits(skb,
 				  doffset + offset,
 				  nskb->data + doffset,
@@ -108,7 +110,7 @@ static void emulate_large_send_offload(s
 		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 		nskb->pkt_type = skb->pkt_type;
 
-		th = (struct tcphdr*)(nskb->nh.raw + iph->ihl*4);
+		th = (struct tcphdr *)(skb_network_header(nskb) + iph->ihl * 4);
 		iph->tot_len = htons(frag_size + doffset);
 		iph->id = htons(id);
 		iph->check = 0;
@@ -137,7 +139,6 @@ static int loopback_xmit(struct sk_buff 
 	skb_orphan(skb);
 
 	skb->protocol = eth_type_trans(skb,dev);
-	skb->dev = dev;
 #ifndef LOOPBACK_MUST_CHECKSUM
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 #endif
@@ -145,7 +146,7 @@ #endif
 #ifdef LOOPBACK_TSO
 	if (skb_is_gso(skb)) {
 		BUG_ON(skb->protocol != htons(ETH_P_IP));
-		BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
+		BUG_ON(ip_hdr(skb)->protocol != IPPROTO_TCP);
 
 		emulate_large_send_offload(skb);
 		return 0;
@@ -163,11 +164,9 @@ #endif
 	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 = &loopback_stats;
+	struct net_device_stats *stats = &dev->stats;
 	unsigned long bytes = 0;
 	unsigned long packets = 0;
 	int i;
@@ -207,7 +206,6 @@ static const struct ethtool_ops loopback
 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,
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 177c502..5fc18da 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -676,7 +676,6 @@ i596_rx_one(struct net_device *dev, stru
 			return 1;
 		}
 
-		skb->dev = dev;
 		memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
 
 		skb->protocol = eth_type_trans(skb,dev);
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index a12bb64..90b0c3e 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -14,6 +14,8 @@
 /* 2001-05-15: support for Cabletron ported from old daynaport driver
  * and fixed access to Sonic Sys card which masquerades as a Farallon
  * by rayk@knightsmanor.org */
+/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
+/* 2003-12-26: Make sure Asante cards always work. */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -61,25 +63,21 @@ #define CABLETRON_TX_START_PG		CABLETRON
 #define DAYNA_8390_BASE		0x80000
 #define DAYNA_8390_MEM		0x00000
 
-#define KINETICS_8390_BASE	0x80000
-#define KINETICS_8390_MEM	0x00000
-
 #define CABLETRON_8390_BASE	0x90000
 #define CABLETRON_8390_MEM	0x00000
 
+#define INTERLAN_8390_BASE	0xE0000
+#define INTERLAN_8390_MEM	0xD0000
+
 enum mac8390_type {
 	MAC8390_NONE = -1,
 	MAC8390_APPLE,
 	MAC8390_ASANTE,
-	MAC8390_FARALLON,  /* Apple, Asante, and Farallon are all compatible */
+	MAC8390_FARALLON,
 	MAC8390_CABLETRON,
 	MAC8390_DAYNA,
 	MAC8390_INTERLAN,
 	MAC8390_KINETICS,
-	MAC8390_FOCUS,
-	MAC8390_SONICSYS,
-	MAC8390_DAYNA2,
-	MAC8390_DAYNA3,
 };
 
 static const char * cardname[] = {
@@ -90,10 +88,6 @@ static const char * cardname[] = {
 	"dayna",
 	"interlan",
 	"kinetics",
-	"focus",
-	"sonic systems",
-	"dayna2",
-	"dayna_lc",
 };
 
 static int word16[] = {
@@ -104,10 +98,6 @@ static int word16[] = {
 	0, /* dayna */
 	1, /* interlan */
 	0, /* kinetics */
-	1, /* focus (??) */
-	1, /* sonic systems  */
-	1, /* dayna2 */
-	1, /* dayna-lc */
 };
 
 /* on which cards do we use NuBus resources? */
@@ -119,10 +109,12 @@ static int useresources[] = {
 	0, /* dayna */
 	0, /* interlan */
 	0, /* kinetics */
-	0, /* focus (??) */
-	1, /* sonic systems */
-	1, /* dayna2 */
-	1, /* dayna-lc */
+};
+
+enum mac8390_access {
+	ACCESS_UNKNOWN = 0,
+	ACCESS_32,
+	ACCESS_16,
 };
 
 extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
@@ -134,8 +126,9 @@ static int mac8390_initdev(struct net_de
 static int mac8390_open(struct net_device * dev);
 static int mac8390_close(struct net_device * dev);
 static void mac8390_no_reset(struct net_device *dev);
+static void interlan_reset(struct net_device *dev);
 
-/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
+/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
 static void sane_get_8390_hdr(struct net_device *dev,
 			      struct e8390_pkt_hdr *hdr, int ring_page);
 static void sane_block_input(struct net_device * dev, int count,
@@ -172,23 +165,93 @@ static void word_memcpy_fromcard(void *t
 
 enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
 {
-	if (dev->dr_sw == NUBUS_DRSW_ASANTE)
-		return MAC8390_ASANTE;
-	if (dev->dr_sw == NUBUS_DRSW_FARALLON)
-		return MAC8390_FARALLON;
-	if (dev->dr_sw == NUBUS_DRSW_KINETICS)
-		return MAC8390_KINETICS;
-	if (dev->dr_sw == NUBUS_DRSW_DAYNA)
-		return MAC8390_DAYNA;
-	if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
-		return MAC8390_DAYNA2;
-	if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
-		return MAC8390_DAYNA3;
-	if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
-		return MAC8390_CABLETRON;
+	switch (dev->dr_sw) {
+		case NUBUS_DRSW_3COM:
+			switch (dev->dr_hw) {
+				case NUBUS_DRHW_APPLE_SONIC_NB:
+				case NUBUS_DRHW_APPLE_SONIC_LC:
+				case NUBUS_DRHW_SONNET:
+					return MAC8390_NONE;
+					break;
+				default:
+					return MAC8390_APPLE;
+					break;
+			}
+			break;
+
+		case NUBUS_DRSW_APPLE:
+			switch (dev->dr_hw) {
+				case NUBUS_DRHW_ASANTE_LC:
+					return MAC8390_NONE;
+					break;
+				case NUBUS_DRHW_CABLETRON:
+					return MAC8390_CABLETRON;
+					break;
+				default:
+					return MAC8390_APPLE;
+					break;
+			}
+			break;
+
+		case NUBUS_DRSW_ASANTE:
+			return MAC8390_ASANTE;
+			break;
+
+		case NUBUS_DRSW_TECHWORKS:
+		case NUBUS_DRSW_DAYNA2:
+		case NUBUS_DRSW_DAYNA_LC:
+			if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+				return MAC8390_CABLETRON;
+			else
+				return MAC8390_APPLE;
+			break;
+
+		case NUBUS_DRSW_FARALLON:
+			return MAC8390_FARALLON;
+			break;
+
+		case NUBUS_DRSW_KINETICS:
+			switch (dev->dr_hw) {
+				case NUBUS_DRHW_INTERLAN:
+					return MAC8390_INTERLAN;
+					break;
+				default:
+					return MAC8390_KINETICS;
+					break;
+			}
+			break;
+
+		case NUBUS_DRSW_DAYNA:
+			// These correspond to Dayna Sonic cards
+			// which use the macsonic driver
+			if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
+				dev->dr_hw == NUBUS_DRHW_INTERLAN )
+				return MAC8390_NONE;
+			else
+				return MAC8390_DAYNA;
+			break;
+	}
 	return MAC8390_NONE;
 }
 
+enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
+{
+	unsigned long outdata = 0xA5A0B5B0;
+	unsigned long indata =  0x00000000;
+	/* Try writing 32 bits */
+	memcpy((char *)membase, (char *)&outdata, 4);
+	/* Now compare them */
+	if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+		return ACCESS_32;
+	/* Write 16 bit output */
+	word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
+	/* Now read it back */
+	word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
+	if (outdata == indata)
+		return ACCESS_16;
+	return ACCESS_UNKNOWN;
+}
+
 int __init mac8390_memsize(unsigned long membase)
 {
 	unsigned long flags;
@@ -287,14 +350,6 @@ struct net_device * __init mac8390_probe
 			continue;
 		} else {
 			nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
-			/* Some Sonic Sys cards masquerade as Farallon */
-			if (cardtype == MAC8390_FARALLON &&
-					dev->dev_addr[0] == 0x0 &&
-					dev->dev_addr[1] == 0x40 &&
-					dev->dev_addr[2] == 0x10) {
-				/* This is really Sonic Sys card */
-				cardtype = MAC8390_SONICSYS;
-			}
 		}
 
 		if (useresources[cardtype] == 1) {
@@ -334,6 +389,17 @@ struct net_device * __init mac8390_probe
 						dev->mem_start +
 						mac8390_memsize(dev->mem_start);
 					break;
+				case MAC8390_INTERLAN:
+					dev->base_addr =
+						(int)(ndev->board->slot_addr +
+						INTERLAN_8390_BASE);
+					dev->mem_start =
+						(int)(ndev->board->slot_addr +
+						INTERLAN_8390_MEM);
+					dev->mem_end =
+						dev->mem_start +
+						mac8390_memsize(dev->mem_start);
+					break;
 				case MAC8390_CABLETRON:
 					dev->base_addr =
 						(int)(ndev->board->slot_addr +
@@ -356,8 +422,8 @@ struct net_device * __init mac8390_probe
 
 				default:
 					printk(KERN_ERR "Card type %s is"
-							" unsupported, sorry\n",
-					       cardname[cardtype]);
+					       " unsupported, sorry\n",
+					       ndev->board->name);
 					continue;
 			}
 		}
@@ -438,7 +504,7 @@ static int __init mac8390_initdev(struct
 		24,    26,     28,     30
 	};
 
-	int access_bitmode;
+	int access_bitmode = 0;
 
 	/* Now fill in our stuff */
 	dev->open = &mac8390_open;
@@ -468,29 +534,47 @@ #endif
 
 	/* Fill in model-specific information and functions */
 	switch(type) {
-	case MAC8390_SONICSYS:
-		/* 16 bit card, register map is reversed */
-		ei_status.reset_8390 = &mac8390_no_reset;
-		ei_status.block_input = &slow_sane_block_input;
-		ei_status.block_output = &slow_sane_block_output;
-		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
-		ei_status.reg_offset = back4_offsets;
-		access_bitmode = 0;
-		break;
 	case MAC8390_FARALLON:
 	case MAC8390_APPLE:
+		switch(mac8390_testio(dev->mem_start)) {
+			case ACCESS_UNKNOWN:
+				printk("Don't know how to access card memory!\n");
+				return -ENODEV;
+				break;
+
+			case ACCESS_16:
+				/* 16 bit card, register map is reversed */
+				ei_status.reset_8390 = &mac8390_no_reset;
+				ei_status.block_input = &slow_sane_block_input;
+				ei_status.block_output = &slow_sane_block_output;
+				ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+				ei_status.reg_offset = back4_offsets;
+				break;
+
+			case ACCESS_32:
+				/* 32 bit card, register map is reversed */
+				ei_status.reset_8390 = &mac8390_no_reset;
+				ei_status.block_input = &sane_block_input;
+				ei_status.block_output = &sane_block_output;
+				ei_status.get_8390_hdr = &sane_get_8390_hdr;
+				ei_status.reg_offset = back4_offsets;
+				access_bitmode = 1;
+				break;
+		}
+		break;
+
 	case MAC8390_ASANTE:
-	case MAC8390_DAYNA2:
-	case MAC8390_DAYNA3:
-		/* 32 bit card, register map is reversed */
-		/* sane */
+		/* Some Asante cards pass the 32 bit test
+		 * but overwrite system memory when run at 32 bit.
+		 * so we run them all at 16 bit.
+		 */
 		ei_status.reset_8390 = &mac8390_no_reset;
-		ei_status.block_input = &sane_block_input;
-		ei_status.block_output = &sane_block_output;
-		ei_status.get_8390_hdr = &sane_get_8390_hdr;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
 		ei_status.reg_offset = back4_offsets;
-		access_bitmode = 1;
 		break;
+
 	case MAC8390_CABLETRON:
 		/* 16 bit card, register map is short forward */
 		ei_status.reset_8390 = &mac8390_no_reset;
@@ -498,21 +582,30 @@ #endif
 		ei_status.block_output = &slow_sane_block_output;
 		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
 		ei_status.reg_offset = fwrd2_offsets;
-		access_bitmode = 0;
 		break;
+
 	case MAC8390_DAYNA:
 	case MAC8390_KINETICS:
-		/* 16 bit memory */
+		/* 16 bit memory, register map is forward */
 		/* dayna and similar */
 		ei_status.reset_8390 = &mac8390_no_reset;
 		ei_status.block_input = &dayna_block_input;
 		ei_status.block_output = &dayna_block_output;
 		ei_status.get_8390_hdr = &dayna_get_8390_hdr;
 		ei_status.reg_offset = fwrd4_offsets;
-		access_bitmode = 0;
 		break;
+
+	case MAC8390_INTERLAN:
+		/* 16 bit memory, register map is forward */
+		ei_status.reset_8390 = &interlan_reset;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+	        ei_status.reg_offset = fwrd4_offsets;
+	        break;
+
 	default:
-		printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+		printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
 		return -ENODEV;
 	}
 
@@ -530,9 +623,9 @@ #endif
 				printk(":");
 		}
 	}
-	printk(" IRQ %d, shared memory at %#lx-%#lx,  %d-bit access.\n",
-		   dev->irq, dev->mem_start, dev->mem_end-1,
-		   access_bitmode?32:16);
+	printk(" IRQ %d, %d KB shared memory at %#lx,  %d-bit access.\n",
+		   dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4,
+		   dev->mem_start, access_bitmode?32:16);
 	return 0;
 }
 
@@ -561,6 +654,18 @@ static void mac8390_no_reset(struct net_
 	return;
 }
 
+static void interlan_reset(struct net_device *dev)
+{
+	unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
+	if (ei_debug > 1)
+		printk("Need to reset the NS8390 t=%lu...", jiffies);
+	ei_status.txing = 0;
+	target[0xC0000] = 0;
+	if (ei_debug > 1)
+		printk("reset complete\n");
+	return;
+}
+
 /* dayna_memcpy_fromio/dayna_memcpy_toio */
 /* directly from daynaport.c by Alan Cox */
 static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index e960138..26a3b45 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -128,7 +128,7 @@ #if 0
 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);
 static void set_multicast_list(struct net_device *dev);
 static void net_rx(struct net_device *dev);
@@ -374,56 +374,39 @@ net_open(struct net_device *dev)
 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);
+	struct net_local *lp = netdev_priv(dev);
+	unsigned long flags;
 
-		/* initiate a transmit sequence */
-		writereg(dev, PP_TxCMD, lp->send_cmd);
-		writereg(dev, PP_TxLength, skb->len);
+	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]);
 
-		/* 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;
-		}
+	/* 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);
+	netif_stop_queue(dev);
 
-		/* Write the contents of the packet */
-		memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
+	/* 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 */
+	skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
+				  skb->len+1);
+
+	local_irq_restore(flags);
+	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
 
 	return 0;
@@ -441,9 +424,6 @@ static irqreturn_t net_interrupt(int irq
 		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 +444,7 @@ static irqreturn_t net_interrupt(int irq
 			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 +458,7 @@ static irqreturn_t net_interrupt(int irq
                                    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 +475,6 @@ static irqreturn_t net_interrupt(int irq
 			break;
 		}
 	}
-	dev->interrupt = 0;
 	return IRQ_HANDLED;
 }
 
@@ -530,9 +507,9 @@ net_rx(struct net_device *dev)
 		return;
 	}
 	skb_put(skb, length);
-	skb->dev = dev;
 
-	memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
+	skb_copy_to_linear_data(skb, (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 +588,6 @@ static void set_multicast_list(struct ne
 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 --git a/drivers/net/macb.c b/drivers/net/macb.c
index 2e9571b..0e04f7a 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -357,7 +357,6 @@ static int macb_rx_frame(struct macb *bp
 	}
 
 	skb_reserve(skb, RX_OFFSET);
-	skb->dev = bp->dev;
 	skb->ip_summed = CHECKSUM_NONE;
 	skb_put(skb, len);
 
@@ -368,9 +367,10 @@ static int macb_rx_frame(struct macb *bp
 			BUG_ON(frag != last_frag);
 			frag_len = len - offset;
 		}
-		memcpy(skb->data + offset,
-		       bp->rx_buffers + (RX_BUFFER_SIZE * frag),
-		       frag_len);
+		skb_copy_to_linear_data_offset(skb, offset,
+					       (bp->rx_buffers +
+					        (RX_BUFFER_SIZE * frag)),
+					       frag_len);
 		offset += RX_BUFFER_SIZE;
 		bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
 		wmb();
@@ -576,7 +576,8 @@ #ifdef DEBUG
 	int i;
 	dev_dbg(&bp->pdev->dev,
 		"start_xmit: len %u head %p data %p tail %p end %p\n",
-		skb->len, skb->head, skb->data, skb->tail, skb->end);
+		skb->len, skb->head, skb->data,
+		skb_tail_pointer(skb), skb_end_pointer(skb));
 	dev_dbg(&bp->pdev->dev,
 		"data:");
 	for (i = 0; i < 16; i++)
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 9ec24f0..52b9332 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -110,9 +110,9 @@ static int __devinit mace_probe(struct m
 		return -ENODEV;
 	}
 
-	addr = get_property(mace, "mac-address", NULL);
+	addr = of_get_property(mace, "mac-address", NULL);
 	if (addr == NULL) {
-		addr = get_property(mace, "local-mac-address", NULL);
+		addr = of_get_property(mace, "local-mac-address", NULL);
 		if (addr == NULL) {
 			printk(KERN_ERR "Can't get mac-address for MACE %s\n",
 			       mace->full_name);
@@ -939,7 +939,6 @@ static irqreturn_t mace_rxdma_intr(int i
 		else	/* Ethernet header; mace includes FCS */
 		    nb -= 8;
 		skb_put(skb, nb);
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 		mp->stats.rx_bytes += skb->len;
 		netif_rx(skb);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 5d541e8..fef3193 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -12,6 +12,11 @@
  *	Copyright (C) 1998 Alan Cox <alan@redhat.com>
  *
  *	Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
+ *
+ *	Copyright (C) 2007 Finn Thain
+ *
+ *	Converted to DMA API, converted to unified driver model,
+ *	sync'd some routines with mace.c and fixed various bugs.
  */
 
 
@@ -23,8 +28,9 @@ #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/crc32.h>
 #include <linux/bitrev.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/macintosh.h>
 #include <asm/macints.h>
@@ -32,13 +38,20 @@ #include <asm/mac_psc.h>
 #include <asm/page.h>
 #include "mace.h"
 
-#define N_TX_RING	1
-#define N_RX_RING	8
-#define N_RX_PAGES	((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE)
+static char mac_mace_string[] = "macmace";
+static struct platform_device *mac_mace_device;
+
+#define N_TX_BUFF_ORDER	0
+#define N_TX_RING	(1 << N_TX_BUFF_ORDER)
+#define N_RX_BUFF_ORDER	3
+#define N_RX_RING	(1 << N_RX_BUFF_ORDER)
+
 #define TX_TIMEOUT	HZ
 
-/* Bits in transmit DMA status */
-#define TX_DMA_ERR	0x80
+#define MACE_BUFF_SIZE	0x800
+
+/* Chip rev needs workaround on HW & multicast addr change */
+#define BROKEN_ADDRCHG_REV	0x0941
 
 /* The MACE is simply wired down on a Mac68K box */
 
@@ -47,40 +60,46 @@ #define MACE_PROM	(void *)(0x50F08001)
 
 struct mace_data {
 	volatile struct mace *mace;
-	volatile unsigned char *tx_ring;
-	volatile unsigned char *tx_ring_phys;
-	volatile unsigned char *rx_ring;
-	volatile unsigned char *rx_ring_phys;
+	unsigned char *tx_ring;
+	dma_addr_t tx_ring_phys;
+	unsigned char *rx_ring;
+	dma_addr_t rx_ring_phys;
 	int dma_intr;
 	struct net_device_stats stats;
 	int rx_slot, rx_tail;
 	int tx_slot, tx_sloti, tx_count;
+	int chipid;
+	struct device *device;
 };
 
 struct mace_frame {
-	u16	len;
-	u16	status;
-	u16	rntpc;
-	u16	rcvcc;
-	u32	pad1;
-	u32	pad2;
+	u8	rcvcnt;
+	u8	pad1;
+	u8	rcvsts;
+	u8	pad2;
+	u8	rntpc;
+	u8	pad3;
+	u8	rcvcc;
+	u8	pad4;
+	u32	pad5;
+	u32	pad6;
 	u8	data[1];
 	/* And frame continues.. */
 };
 
 #define PRIV_BYTES	sizeof(struct mace_data)
 
-extern void psc_debug_dump(void);
-
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
 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 void mace_reset(struct net_device *dev);
 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);
+static void __mace_set_address(struct net_device *dev, void *addr);
 
 /*
  * Load a receive DMA channel with a base address and ring length
@@ -88,7 +107,7 @@ static void mace_tx_timeout(struct net_d
 
 static void mace_load_rxdma_base(struct net_device *dev, int set)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 
 	psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
 	psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys);
@@ -103,7 +122,7 @@ static void mace_load_rxdma_base(struct 
 
 static void mace_rxdma_reset(struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mace = mp->mace;
 	u8 maccc = mace->maccc;
 
@@ -130,7 +149,7 @@ static void mace_rxdma_reset(struct net_
 
 static void mace_txdma_reset(struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mace = mp->mace;
 	u8 maccc;
 
@@ -168,7 +187,7 @@ static void mace_dma_off(struct net_devi
  * model of Macintrash has a MACE (AV macintoshes)
  */
 
-struct net_device *mace_probe(int unit)
+static int __devinit mace_probe(struct platform_device *pdev)
 {
 	int j;
 	struct mace_data *mp;
@@ -179,24 +198,28 @@ struct net_device *mace_probe(int unit)
 	int err;
 
 	if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 
 	found = 1;	/* prevent 'finding' one on every device probe */
 
 	dev = alloc_etherdev(PRIV_BYTES);
 	if (!dev)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
-	if (unit >= 0)
-		sprintf(dev->name, "eth%d", unit);
+	mp = netdev_priv(dev);
+
+	mp->device = &pdev->dev;
+	SET_NETDEV_DEV(dev, &pdev->dev);
+ 	SET_MODULE_OWNER(dev);
 
-	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;
 
+	mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo;
+
 	/*
 	 * The PROM contains 8 bytes which total 0xFF when XOR'd
 	 * together. Due to the usual peculiar apple brain damage
@@ -217,7 +240,7 @@ struct net_device *mace_probe(int unit)
 
 	if (checksum != 0xFF) {
 		free_netdev(dev);
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 	}
 
 	memset(&mp->stats, 0, sizeof(mp->stats));
@@ -237,22 +260,98 @@ struct net_device *mace_probe(int unit)
 
 	err = register_netdev(dev);
 	if (!err)
-		return dev;
+		return 0;
 
 	free_netdev(dev);
-	return ERR_PTR(err);
+	return err;
+}
+
+/*
+ * Reset the chip.
+ */
+
+static void mace_reset(struct net_device *dev)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
+	int i;
+
+	/* soft-reset the chip */
+	i = 200;
+	while (--i) {
+		mb->biucc = SWRST;
+		if (mb->biucc & SWRST) {
+			udelay(10);
+			continue;
+		}
+		break;
+	}
+	if (!i) {
+		printk(KERN_ERR "macmace: cannot reset chip!\n");
+		return;
+	}
+
+	mb->maccc = 0;	/* turn off tx, rx */
+	mb->imr = 0xFF;	/* disable all intrs for now */
+	i = mb->ir;
+
+	mb->biucc = XMTSP_64;
+	mb->utr = RTRD;
+	mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU;
+
+	mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+	mb->rcvfc = 0;
+
+	/* load up the hardware address */
+	__mace_set_address(dev, dev->dev_addr);
+
+	/* clear the multicast filter */
+	if (mp->chipid == BROKEN_ADDRCHG_REV)
+		mb->iac = LOGADDR;
+	else {
+		mb->iac = ADDRCHG | LOGADDR;
+		while ((mb->iac & ADDRCHG) != 0)
+			;
+	}
+	for (i = 0; i < 8; ++i)
+		mb->ladrf = 0;
+
+	/* done changing address */
+	if (mp->chipid != BROKEN_ADDRCHG_REV)
+		mb->iac = 0;
+
+	mb->plscc = PORTSEL_AUI;
 }
 
 /*
  * Load the address on a mace controller.
  */
 
-static int mace_set_address(struct net_device *dev, void *addr)
+static void __mace_set_address(struct net_device *dev, void *addr)
 {
-	unsigned char *p = addr;
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
+	unsigned char *p = addr;
 	int i;
+
+	/* load up the hardware address */
+	if (mp->chipid == BROKEN_ADDRCHG_REV)
+		mb->iac = PHYADDR;
+	else {
+		mb->iac = ADDRCHG | PHYADDR;
+		while ((mb->iac & ADDRCHG) != 0)
+			;
+	}
+	for (i = 0; i < 6; ++i)
+		mb->padr = dev->dev_addr[i] = p[i];
+	if (mp->chipid != BROKEN_ADDRCHG_REV)
+		mb->iac = 0;
+}
+
+static int mace_set_address(struct net_device *dev, void *addr)
+{
+	struct mace_data *mp = netdev_priv(dev);
+	volatile struct mace *mb = mp->mace;
 	unsigned long flags;
 	u8 maccc;
 
@@ -260,15 +359,10 @@ static int mace_set_address(struct net_d
 
 	maccc = mb->maccc;
 
-	/* 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];
-	}
+	__mace_set_address(dev, addr);
 
 	mb->maccc = maccc;
+
 	local_irq_restore(flags);
 
 	return 0;
@@ -281,31 +375,11 @@ static int mace_set_address(struct net_d
 
 static int mace_open(struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
-#if 0
-	int i;
 
-	i = 200;
-	while (--i) {
-		mb->biucc = SWRST;
-		if (mb->biucc & SWRST) {
-			udelay(10);
-			continue;
-		}
-		break;
-	}
-	if (!i) {
-		printk(KERN_ERR "%s: software reset failed!!\n", dev->name);
-		return -EAGAIN;
-	}
-#endif
-
-	mb->biucc = XMTSP_64;
-	mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST;
-	mb->xmtfc = AUTO_PAD_XMIT;
-	mb->plscc = PORTSEL_AUI;
-	/* mb->utr = RTRD; */
+	/* reset the chip */
+	mace_reset(dev);
 
 	if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) {
 		printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq);
@@ -319,25 +393,21 @@ #endif
 
 	/* Allocate the DMA ring buffers */
 
-	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);
-		free_irq(dev->irq, dev);
-		free_irq(mp->dma_intr, dev);
-		printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name);
-		return -ENOMEM;
+	mp->tx_ring = dma_alloc_coherent(mp->device,
+			N_TX_RING * MACE_BUFF_SIZE,
+			&mp->tx_ring_phys, GFP_KERNEL);
+	if (mp->tx_ring == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name);
+		goto out1;
 	}
 
-	mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
-	mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
-
-	/* 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->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH);
+	mp->rx_ring = dma_alloc_coherent(mp->device,
+			N_RX_RING * MACE_BUFF_SIZE,
+			&mp->rx_ring_phys, GFP_KERNEL);
+	if (mp->rx_ring == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name);
+		goto out2;
+	}
 
 	mace_dma_off(dev);
 
@@ -348,34 +418,22 @@ #endif
 	psc_write_word(PSC_ENETWR_CTL, 0x0400);
 	psc_write_word(PSC_ENETRD_CTL, 0x0400);
 
-#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];
-
-	/* clear the multicast filter */
-	mb->iac = ADDRCHG | LOGADDR;
-
-	while ((mb->iac & ADDRCHG) != 0);
-
-	for (i = 0; i < 8; ++i)
-		mb->ladrf = 0;
-
-	mb->plscc = PORTSEL_GPSI + ENPLSIO;
-
-	mb->maccc = ENXMT | ENRCV;
-	mb->imr = RCVINT;
-#endif
-
 	mace_rxdma_reset(dev);
 	mace_txdma_reset(dev);
 
+	/* turn it on! */
+	mb->maccc = ENXMT | ENRCV;
+	/* enable all interrupts except receive interrupts */
+	mb->imr = RCVINT;
 	return 0;
+
+out2:
+	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+	                  mp->tx_ring, mp->tx_ring_phys);
+out1:
+	free_irq(dev->irq, dev);
+	free_irq(mp->dma_intr, dev);
+	return -ENOMEM;
 }
 
 /*
@@ -384,19 +442,13 @@ #endif
 
 static int mace_close(struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
 
 	mb->maccc = 0;		/* disable rx and tx	 */
 	mb->imr = 0xFF;		/* disable all irqs	 */
 	mace_dma_off(dev);	/* disable rx and tx dma */
 
-	free_irq(dev->irq, dev);
-	free_irq(IRQ_MAC_MACE_DMA, dev);
-
-	free_pages((u32) mp->rx_ring, N_RX_PAGES);
-	free_pages((u32) mp->tx_ring, 0);
-
 	return 0;
 }
 
@@ -406,22 +458,26 @@ static int mace_close(struct net_device 
 
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
+	unsigned long flags;
 
-	/* Stop the queue if the buffer is full */
+	/* Stop the queue since there's only the one buffer */
 
+	local_irq_save(flags);
+	netif_stop_queue(dev);
 	if (!mp->tx_count) {
-		netif_stop_queue(dev);
-		return 1;
+		printk(KERN_ERR "macmace: tx queue running but no free buffers.\n");
+		local_irq_restore(flags);
+		return NETDEV_TX_BUSY;
 	}
 	mp->tx_count--;
+	local_irq_restore(flags);
 
 	mp->stats.tx_packets++;
 	mp->stats.tx_bytes += skb->len;
 
 	/* We need to copy into our xmit buffer to take care of alignment and caching issues */
-
-	memcpy((void *) mp->tx_ring, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
 
 	/* load the Tx DMA and fire it off */
 
@@ -433,23 +489,26 @@ static int mace_xmit_start(struct sk_buf
 
 	dev_kfree_skb(skb);
 
-	return 0;
+	dev->trans_start = jiffies;
+	return NETDEV_TX_OK;
 }
 
 static struct net_device_stats *mace_stats(struct net_device *dev)
 {
-	struct mace_data *p = (struct mace_data *) dev->priv;
-	return &p->stats;
+	struct mace_data *mp = netdev_priv(dev);
+	return &mp->stats;
 }
 
 static void mace_set_multicast(struct net_device *dev)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
 	int i, j;
 	u32 crc;
 	u8 maccc;
+	unsigned long flags;
 
+	local_irq_save(flags);
 	maccc = mb->maccc;
 	mb->maccc &= ~PROM;
 
@@ -474,116 +533,122 @@ 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];
+		if (mp->chipid == BROKEN_ADDRCHG_REV)
+			mb->iac = LOGADDR;
+		else {
+			mb->iac = ADDRCHG | LOGADDR;
+			while ((mb->iac & ADDRCHG) != 0)
+				;
 		}
+		for (i = 0; i < 8; ++i)
+			mb->ladrf = multicast_filter[i];
+		if (mp->chipid != BROKEN_ADDRCHG_REV)
+			mb->iac = 0;
 	}
 
 	mb->maccc = maccc;
+	local_irq_restore(flags);
 }
 
-/*
- * 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;
 	static int mace_babbles, mace_jabbers;
 
-	if (intr & MPCO) {
+	if (intr & MPCO)
 		mp->stats.rx_missed_errors += 256;
-	}
-	mp->stats.rx_missed_errors += mb->mpc;	/* reading clears it */
-
-	if (intr & RNTPCO) {
+	mp->stats.rx_missed_errors += mb->mpc;   /* reading clears it */
+	if (intr & RNTPCO)
 		mp->stats.rx_length_errors += 256;
-	}
-	mp->stats.rx_length_errors += mb->rntpc;	/* reading clears it */
-
-	if (intr & CERR) {
+	mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+	if (intr & CERR)
 		++mp->stats.tx_heartbeat_errors;
-	}
-	if (intr & BABBLE) {
-		if (mace_babbles++ < 4) {
-			printk(KERN_DEBUG "mace: babbling transmitter\n");
-		}
-	}
-	if (intr & JABBER) {
-		if (mace_jabbers++ < 4) {
-			printk(KERN_DEBUG "mace: jabbering transceiver\n");
-		}
-	}
+	if (intr & BABBLE)
+		if (mace_babbles++ < 4)
+			printk(KERN_DEBUG "macmace: babbling transmitter\n");
+	if (intr & JABBER)
+		if (mace_jabbers++ < 4)
+			printk(KERN_DEBUG "macmace: jabbering transceiver\n");
 }
 
-/*
- *	A transmit error has occurred. (We kick the transmit side from
- *	the DMA completion)
- */
-
-static void mace_xmit_error(struct net_device *dev)
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
-	u8 xmtfs, xmtrc;
+	int intr, fs;
+	unsigned int flags;
 
-	xmtfs = mb->xmtfs;
-	xmtrc = mb->xmtrc;
+	/* don't want the dma interrupt handler to fire */
+	local_irq_save(flags);
 
-	if (xmtfs & XMTSV) {
-		if (xmtfs & UFLO) {
-			printk("%s: DMA underrun.\n", dev->name);
-			mp->stats.tx_errors++;
-			mp->stats.tx_fifo_errors++;
-			mace_txdma_reset(dev);
+	intr = mb->ir; /* read interrupt register */
+	mace_handle_misc_intrs(mp, intr);
+
+	if (intr & XMTINT) {
+		fs = mb->xmtfs;
+		if ((fs & XMTSV) == 0) {
+			printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs);
+			mace_reset(dev);
+			/*
+			 * XXX mace likes to hang the machine after a xmtfs error.
+			 * This is hard to reproduce, reseting *may* help
+			 */
 		}
-		if (xmtfs & RTRY) {
-			mp->stats.collisions++;
+		/* dma should have finished */
+		if (!mp->tx_count) {
+			printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs);
+		}
+		/* Update stats */
+		if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+			++mp->stats.tx_errors;
+			if (fs & LCAR)
+				++mp->stats.tx_carrier_errors;
+			else if (fs & (UFLO|LCOL|RTRY)) {
+				++mp->stats.tx_aborted_errors;
+				if (mb->xmtfs & UFLO) {
+					printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
+					mp->stats.tx_fifo_errors++;
+					mace_txdma_reset(dev);
+				}
+			}
 		}
 	}
-}
 
-/*
- *	A receive interrupt occurred.
- */
+	if (mp->tx_count)
+		netif_wake_queue(dev);
 
-static void mace_recv_interrupt(struct net_device *dev)
-{
-/*	struct mace_data *mp = (struct mace_data *) dev->priv; */
-//	volatile struct mace *mb = mp->mace;
-}
+	local_irq_restore(flags);
 
-/*
- * Process the chip interrupt
- */
+	return IRQ_HANDLED;
+}
 
-static irqreturn_t mace_interrupt(int irq, void *dev_id)
+static void mace_tx_timeout(struct net_device *dev)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	volatile struct mace *mb = mp->mace;
-	u8 ir;
+	unsigned long flags;
 
-	ir = mb->ir;
-	mace_handle_misc_intrs(mp, ir);
+	local_irq_save(flags);
 
-	if (ir & XMTINT) {
-		mace_xmit_error(dev);
-	}
-	if (ir & RCVINT) {
-		mace_recv_interrupt(dev);
-	}
-	return IRQ_HANDLED;
-}
+	/* turn off both tx and rx and reset the chip */
+	mb->maccc = 0;
+	printk(KERN_ERR "macmace: transmit timeout - resetting\n");
+	mace_txdma_reset(dev);
+	mace_reset(dev);
 
-static void mace_tx_timeout(struct net_device *dev)
-{
-/*	struct mace_data *mp = (struct mace_data *) dev->priv; */
-//	volatile struct mace *mb = mp->mace;
+	/* restart rx dma */
+	mace_rxdma_reset(dev);
+
+	mp->tx_count = N_TX_RING;
+	netif_wake_queue(dev);
+
+	/* turn it on! */
+	mb->maccc = ENXMT | ENRCV;
+	/* enable all interrupts except receive interrupts */
+	mb->imr = RCVINT;
+
+	local_irq_restore(flags);
 }
 
 /*
@@ -592,41 +657,39 @@ static void mace_tx_timeout(struct net_d
 
 static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
 {
-	struct mace_data *mp = (struct mace_data *) dev->priv;
+	struct mace_data *mp = netdev_priv(dev);
 	struct sk_buff *skb;
+	unsigned int frame_status = mf->rcvsts;
 
-	if (mf->status & RS_OFLO) {
-		printk("%s: fifo overflow.\n", dev->name);
-		mp->stats.rx_errors++;
-		mp->stats.rx_fifo_errors++;
-	}
-	if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
+	if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
 		mp->stats.rx_errors++;
+		if (frame_status & RS_OFLO) {
+			printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
+			mp->stats.rx_fifo_errors++;
+		}
+		if (frame_status & RS_CLSN)
+			mp->stats.collisions++;
+		if (frame_status & RS_FRAMERR)
+			mp->stats.rx_frame_errors++;
+		if (frame_status & RS_FCSERR)
+			mp->stats.rx_crc_errors++;
+	} else {
+		unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
 
-	if (mf->status&RS_CLSN) {
-		mp->stats.collisions++;
-	}
-	if (mf->status&RS_FRAMERR) {
-		mp->stats.rx_frame_errors++;
-	}
-	if (mf->status&RS_FCSERR) {
-		mp->stats.rx_crc_errors++;
-	}
-
-	skb = dev_alloc_skb(mf->len+2);
-	if (!skb) {
-		mp->stats.rx_dropped++;
-		return;
+		skb = dev_alloc_skb(frame_length + 2);
+		if (!skb) {
+			mp->stats.rx_dropped++;
+			return;
+		}
+		skb_reserve(skb, 2);
+		memcpy(skb_put(skb, frame_length), mf->data, frame_length);
+
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+		dev->last_rx = jiffies;
+		mp->stats.rx_packets++;
+		mp->stats.rx_bytes += frame_length;
 	}
-	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);
-	dev->last_rx = jiffies;
-	mp->stats.rx_packets++;
-	mp->stats.rx_bytes += mf->len;
 }
 
 /*
@@ -636,7 +699,7 @@ static void mace_dma_rx_frame(struct net
 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;
+	struct mace_data *mp = netdev_priv(dev);
 	int left, head;
 	u16 status;
 	u32 baka;
@@ -663,7 +726,8 @@ static irqreturn_t mace_dma_intr(int irq
 		/* Loop through the ring buffer and process new packages */
 
 		while (mp->rx_tail < head) {
-			mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800)));
+			mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring
+				+ (mp->rx_tail * MACE_BUFF_SIZE)));
 			mp->rx_tail++;
 		}
 
@@ -690,9 +754,76 @@ static irqreturn_t mace_dma_intr(int irq
 		psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100);
 		mp->tx_sloti ^= 0x10;
 		mp->tx_count++;
-		netif_wake_queue(dev);
 	}
 	return IRQ_HANDLED;
 }
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Macintosh MACE ethernet driver");
+
+static int __devexit mac_mace_device_remove (struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct mace_data *mp = netdev_priv(dev);
+
+	unregister_netdev(dev);
+
+	free_irq(dev->irq, dev);
+	free_irq(IRQ_MAC_MACE_DMA, dev);
+
+	dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE,
+	                  mp->rx_ring, mp->rx_ring_phys);
+	dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+	                  mp->tx_ring, mp->tx_ring_phys);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+static struct platform_driver mac_mace_driver = {
+	.probe  = mace_probe,
+	.remove = __devexit_p(mac_mace_device_remove),
+	.driver	= {
+		.name = mac_mace_string,
+	},
+};
+
+static int __init mac_mace_init_module(void)
+{
+	int err;
+
+	if ((err = platform_driver_register(&mac_mace_driver))) {
+		printk(KERN_ERR "Driver registration failed\n");
+		return err;
+	}
+
+	mac_mace_device = platform_device_alloc(mac_mace_string, 0);
+	if (!mac_mace_device)
+		goto out_unregister;
+
+	if (platform_device_add(mac_mace_device)) {
+		platform_device_put(mac_mace_device);
+		mac_mace_device = NULL;
+	}
+
+	return 0;
+
+out_unregister:
+	platform_driver_unregister(&mac_mace_driver);
+
+	return -ENOMEM;
+}
+
+static void __exit mac_mace_cleanup_module(void)
+{
+	platform_driver_unregister(&mac_mace_driver);
+
+	if (mac_mace_device) {
+		platform_device_unregister(mac_mace_device);
+		mac_mace_device = NULL;
+	}
+}
+
+module_init(mac_mace_init_module);
+module_exit(mac_mace_cleanup_module);
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 8ca57a0..e9ecdbf 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -130,6 +130,46 @@ static inline void bit_reverse_addr(unsi
 		addr[i] = bitrev8(addr[i]);
 }
 
+static irqreturn_t macsonic_interrupt(int irq, void *dev_id)
+{
+	irqreturn_t result;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	result = sonic_interrupt(irq, dev_id);
+	local_irq_restore(flags);
+	return result;
+}
+
+static int macsonic_open(struct net_device* dev)
+{
+	if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+	/* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
+	 * in at priority level 3. However, we sometimes get the level 2 inter-
+	 * rupt as well, which must prevent re-entrance of the sonic handler.
+	 */
+	if (dev->irq == IRQ_AUTO_3)
+		if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
+			printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9);
+			free_irq(dev->irq, dev);
+			return -EAGAIN;
+		}
+	return sonic_open(dev);
+}
+
+static int macsonic_close(struct net_device* dev)
+{
+	int err;
+	err = sonic_close(dev);
+	free_irq(dev->irq, dev);
+	if (dev->irq == IRQ_AUTO_3)
+		free_irq(IRQ_NUBUS_9, dev);
+	return err;
+}
+
 int __init macsonic_init(struct net_device* dev)
 {
 	struct sonic_local* lp = netdev_priv(dev);
@@ -160,8 +200,8 @@ int __init macsonic_init(struct net_devi
 	lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
 	                     * SONIC_BUS_SCALE(lp->dma_bitmode));
 
-	dev->open = sonic_open;
-	dev->stop = sonic_close;
+	dev->open = macsonic_open;
+	dev->stop = macsonic_close;
 	dev->hard_start_xmit = sonic_send_packet;
 	dev->get_stats = sonic_get_stats;
 	dev->set_multicast_list = &sonic_multicast_list;
@@ -402,7 +442,7 @@ int __init macsonic_ident(struct nubus_d
 	    ndev->dr_sw == NUBUS_DRSW_DAYNA)
 		return MACSONIC_DAYNA;
 
-	if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
+	if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC &&
 	    ndev->dr_sw == 0) { /* huh? */
 		return MACSONIC_APPLE16;
 	}
@@ -522,7 +562,7 @@ #endif
 	return macsonic_init(dev);
 }
 
-static int __init mac_sonic_probe(struct platform_device *device)
+static int __init mac_sonic_probe(struct platform_device *pdev)
 {
 	struct net_device *dev;
 	struct sonic_local *lp;
@@ -534,8 +574,8 @@ static int __init mac_sonic_probe(struct
 		return -ENOMEM;
 
 	lp = netdev_priv(dev);
-	lp->device = &device->dev;
-	SET_NETDEV_DEV(dev, &device->dev);
+	lp->device = &pdev->dev;
+	SET_NETDEV_DEV(dev, &pdev->dev);
  	SET_MODULE_OWNER(dev);
 
 	/* This will catch fatal stuff like -ENOMEM as well as success */
@@ -572,19 +612,17 @@ MODULE_DESCRIPTION("Macintosh SONIC ethe
 module_param(sonic_debug, int, 0);
 MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
 
-#define SONIC_IRQ_FLAG IRQ_FLG_FAST
-
 #include "sonic.c"
 
-static int __devexit mac_sonic_device_remove (struct platform_device *device)
+static int __devexit mac_sonic_device_remove (struct platform_device *pdev)
 {
-	struct net_device *dev = platform_get_drvdata(device);
+	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sonic_local* lp = netdev_priv(dev);
 
-	unregister_netdev (dev);
+	unregister_netdev(dev);
 	dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
 	                  lp->descriptors, lp->descriptors_laddr);
-	free_netdev (dev);
+	free_netdev(dev);
 
 	return 0;
 }
@@ -607,9 +645,8 @@ static int __init mac_sonic_init_module(
 	}
 
 	mac_sonic_device = platform_device_alloc(mac_sonic_string, 0);
-	if (!mac_sonic_device) {
+	if (!mac_sonic_device)
 		goto out_unregister;
-	}
 
 	if (platform_device_add(mac_sonic_device)) {
 		platform_device_put(mac_sonic_device);
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 7e69ca6..0343ea1 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -421,7 +421,6 @@ #endif
 					/* Write metadata, and then pass to the receive level */
 					skb_put(skb_c, len);
 					priv->rx_skbs[priv->rx_write] = skb;
-					skb_c->dev = dev;
 					skb_c->protocol = eth_type_trans(skb_c, dev);
 					dev->last_rx = jiffies;
 					priv->stats.rx_packets++;
@@ -609,7 +608,7 @@ static void meth_tx_short_prepare(struct
 
 	desc->header.raw = METH_TX_CMD_INT_EN | (len-1) | ((128-len) << 16);
 	/* maybe I should set whole thing to 0 first... */
-	memcpy(desc->data.dt + (120 - len), skb->data, skb->len);
+	skb_copy_from_linear_data(skb, desc->data.dt + (120 - len), skb->len);
 	if (skb->len < len)
 		memset(desc->data.dt + 120 - len + skb->len, 0, len-skb->len);
 }
@@ -627,8 +626,8 @@ static void meth_tx_1page_prepare(struct
 
 	/* unaligned part */
 	if (unaligned_len) {
-		memcpy(desc->data.dt + (120 - unaligned_len),
-		       skb->data, unaligned_len);
+		skb_copy_from_linear_data(skb, desc->data.dt + (120 - unaligned_len),
+			      unaligned_len);
 		desc->header.raw |= (128 - unaligned_len) << 16;
 	}
 
@@ -653,8 +652,8 @@ static void meth_tx_2page_prepare(struct
 	desc->header.raw = METH_TX_CMD_INT_EN | TX_CATBUF1 | TX_CATBUF2| (skb->len - 1);
 	/* unaligned part */
 	if (unaligned_len){
-		memcpy(desc->data.dt + (120 - unaligned_len),
-		       skb->data, unaligned_len);
+		skb_copy_from_linear_data(skb, desc->data.dt + (120 - unaligned_len),
+			      unaligned_len);
 		desc->header.raw |= (128 - unaligned_len) << 16;
 	}
 
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 2912a34..9205605 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -33,6 +33,13 @@ #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 
+/**
+ * mii_ethtool_gset - get settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 {
 	struct net_device *dev = mii->dev;
@@ -114,6 +121,13 @@ int mii_ethtool_gset(struct mii_if_info 
 	return 0;
 }
 
+/**
+ * mii_ethtool_sset - set settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 {
 	struct net_device *dev = mii->dev;
@@ -207,6 +221,10 @@ int mii_ethtool_sset(struct mii_if_info 
 	return 0;
 }
 
+/**
+ * mii_check_gmii_support - check if the MII supports Gb interfaces
+ * @mii: the MII interface
+ */
 int mii_check_gmii_support(struct mii_if_info *mii)
 {
 	int reg;
@@ -221,6 +239,12 @@ int mii_check_gmii_support(struct mii_if
 	return 0;
 }
 
+/**
+ * mii_link_ok - is link status up/ok
+ * @mii: the MII interface
+ *
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
+ */
 int mii_link_ok (struct mii_if_info *mii)
 {
 	/* first, a dummy read, needed to latch some MII phys */
@@ -230,6 +254,12 @@ int mii_link_ok (struct mii_if_info *mii
 	return 0;
 }
 
+/**
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ * @mii: the MII interface
+ *
+ * Returns 0 on success, negative on error.
+ */
 int mii_nway_restart (struct mii_if_info *mii)
 {
 	int bmcr;
@@ -247,6 +277,14 @@ int mii_nway_restart (struct mii_if_info
 	return r;
 }
 
+/**
+ * mii_check_link - check MII link status
+ * @mii: MII interface
+ *
+ * If the link status changed (previous != current), call
+ * netif_carrier_on() if current link status is Up or call
+ * netif_carrier_off() if current link status is Down.
+ */
 void mii_check_link (struct mii_if_info *mii)
 {
 	int cur_link = mii_link_ok(mii);
@@ -258,6 +296,15 @@ void mii_check_link (struct mii_if_info 
 		netif_carrier_off(mii->dev);
 }
 
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
 unsigned int mii_check_media (struct mii_if_info *mii,
 			      unsigned int ok_to_print,
 			      unsigned int init_media)
@@ -326,6 +373,16 @@ unsigned int mii_check_media (struct mii
 	return 0; /* duplex did not change */
 }
 
+/**
+ * generic_mii_ioctl - main MII ioctl interface
+ * @mii_if: the MII interface
+ * @mii_data: MII ioctl data structure
+ * @cmd: MII ioctl command
+ * @duplex_chg_out: pointer to @duplex_changed status if there was no
+ *	ioctl error
+ *
+ * Returns 0 on success, negative on error.
+ */
 int generic_mii_ioctl(struct mii_if_info *mii_if,
 		      struct mii_ioctl_data *mii_data, int cmd,
 		      unsigned int *duplex_chg_out)
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index f42b9e2..638a279 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -26,8 +26,6 @@ struct mipsnet_priv {
 	struct net_device_stats stats;
 };
 
-static struct platform_device *mips_plat_dev;
-
 static char mipsnet_string[] = "mipsnet";
 
 /*
@@ -101,7 +99,6 @@ static inline ssize_t mipsnet_get_fromde
 	if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
 		return -EFAULT;
 
-	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
 
@@ -298,64 +295,17 @@ static struct device_driver mipsnet_driv
 	.remove	= __devexit_p(mipsnet_device_remove),
 };
 
-static void mipsnet_platform_release(struct device *device)
-{
-	struct platform_device *pldev;
-
-	/* free device */
-	pldev = to_platform_device(device);
-	kfree(pldev);
-}
-
 static int __init mipsnet_init_module(void)
 {
-	struct platform_device *pldev;
 	int err;
 
 	printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
 	       "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
 
-	if (driver_register(&mipsnet_driver)) {
+	err = driver_register(&mipsnet_driver);
+	if (err)
 		printk(KERN_ERR "Driver registration failed\n");
-		err = -ENODEV;
-		goto out;
-	}
-
-        if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto out_unregister_driver;
-	}
-
-	memset (pldev, 0, sizeof (*pldev));
-	pldev->name		= mipsnet_string;
-	pldev->id		= 0;
-	pldev->dev.release	= mipsnet_platform_release;
 
-	if (platform_device_register(pldev)) {
-		err = -ENODEV;
-		goto out_free_pldev;
-	}
-
-        if (!pldev->dev.driver) {
-		/*
-		 * The driver was not bound to this device, there was
-                 * no hardware at this address. Unregister it, as the
-		 * release fuction will take care of freeing the
-		 * allocated structure
-		 */
-		platform_device_unregister (pldev);
-	}
-
-	mips_plat_dev		= pldev;
-
-	return 0;
-
-out_free_pldev:
-	kfree(pldev);
-
-out_unregister_driver:
-	driver_unregister(&mipsnet_driver);
-out:
 	return err;
 }
 
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 8015a7c..1799eee 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -51,8 +51,8 @@ #include <asm/delay.h>
 #include "mv643xx_eth.h"
 
 /* Static function declarations */
-static void eth_port_uc_addr_get(struct net_device *dev,
-						unsigned char *MacAddr);
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);
 static void eth_port_set_multicast_list(struct net_device *);
 static void mv643xx_eth_port_enable_tx(unsigned int port_num,
 						unsigned int queues);
@@ -434,7 +434,6 @@ static int mv643xx_eth_receive_queue(str
 			 * received packet
 			 */
 			skb_put(skb, pkt_info.byte_cnt - 4);
-			skb->dev = dev;
 
 			if (pkt_info.cmd_sts & ETH_LAYER_4_CHECKSUM_OK) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1162,15 +1161,15 @@ static void eth_tx_submit_descs_for_skb(
 
 		cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
 			   ETH_GEN_IP_V_4_CHECKSUM  |
-			   skb->nh.iph->ihl << ETH_TX_IHL_SHIFT;
+			   ip_hdr(skb)->ihl << ETH_TX_IHL_SHIFT;
 
-		switch (skb->nh.iph->protocol) {
+		switch (ip_hdr(skb)->protocol) {
 		case IPPROTO_UDP:
 			cmd_sts |= ETH_UDP_FRAME;
-			desc->l4i_chk = skb->h.uh->check;
+			desc->l4i_chk = udp_hdr(skb)->check;
 			break;
 		case IPPROTO_TCP:
-			desc->l4i_chk = skb->h.th->check;
+			desc->l4i_chk = tcp_hdr(skb)->check;
 			break;
 		default:
 			BUG();
@@ -1382,7 +1381,7 @@ #endif
 	port_num = mp->port_num = pd->port_number;
 
 	/* set default config values */
-	eth_port_uc_addr_get(dev, dev->dev_addr);
+	eth_port_uc_addr_get(port_num, dev->dev_addr);
 	mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
 	mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
 
@@ -1840,26 +1839,9 @@ static void eth_port_start(struct net_de
 }
 
 /*
- * eth_port_uc_addr_set - This function Set the port Unicast address.
- *
- * DESCRIPTION:
- *		This function Set the port Ethernet MAC address.
- *
- * INPUT:
- *	unsigned int	eth_port_num	Port number.
- *	char *		p_addr		Address to be set
- *
- * OUTPUT:
- *	Set MAC address low and high registers. also calls
- *	eth_port_set_filter_table_entry() to set the unicast
- *	table with the proper information.
- *
- * RETURN:
- *	N/A.
- *
+ * eth_port_uc_addr_set - Write a MAC address into the port's hw registers
  */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
-							unsigned char *p_addr)
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr)
 {
 	unsigned int mac_h;
 	unsigned int mac_l;
@@ -1869,40 +1851,24 @@ static void eth_port_uc_addr_set(unsigne
 	mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
 							(p_addr[3] << 0);
 
-	mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
-	mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+	mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l);
+	mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h);
 
-	/* Accept frames of this address */
-	table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num);
+	/* Accept frames with this address */
+	table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num);
 	eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
 }
 
 /*
- * eth_port_uc_addr_get - This function retrieves the port Unicast address
- * (MAC address) from the ethernet hw registers.
- *
- * DESCRIPTION:
- *		This function retrieves the port Ethernet MAC address.
- *
- * INPUT:
- *	unsigned int	eth_port_num	Port number.
- *	char		*MacAddr	pointer where the MAC address is stored
- *
- * OUTPUT:
- *	Copy the MAC address to the location pointed to by MacAddr
- *
- * RETURN:
- *	N/A.
- *
+ * eth_port_uc_addr_get - Read the MAC address from the port's hw registers
  */
-static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr)
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr)
 {
-	struct mv643xx_private *mp = netdev_priv(dev);
 	unsigned int mac_h;
 	unsigned int mac_l;
 
-	mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num));
-	mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num));
+	mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num));
+	mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num));
 
 	p_addr[0] = (mac_h >> 24) & 0xff;
 	p_addr[1] = (mac_h >> 16) & 0xff;
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 7d4e90c..82f8c0c 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -346,10 +346,6 @@ static void eth_port_init(struct mv643xx
 static void eth_port_reset(unsigned int eth_port_num);
 static void eth_port_start(struct net_device *dev);
 
-/* Port MAC address routines */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
-				 unsigned char *p_addr);
-
 /* PHY and MIB routines */
 static void ethernet_phy_reset(unsigned int eth_port_num);
 
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index f8efe0e..5d14be7 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -290,6 +290,8 @@ #define MYRI10GE_LOWPART_TO_U32(X) ((u32
 
 #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
 
+static void myri10ge_set_multicast_list(struct net_device *dev);
+
 static inline void put_be32(__be32 val, __be32 __iomem * p)
 {
 	__raw_writel((__force __u32) val, (__force void __iomem *)p);
@@ -353,6 +355,8 @@ myri10ge_send_cmd(struct myri10ge_priv *
 			return 0;
 		} else if (result == MXGEFW_CMD_UNKNOWN) {
 			return -ENOSYS;
+		} else if (result == MXGEFW_CMD_ERROR_UNALIGNED) {
+			return -E2BIG;
 		} else {
 			dev_err(&mgp->pdev->dev,
 				"command %d failed, result = %d\n",
@@ -712,14 +716,78 @@ myri10ge_change_promisc(struct myri10ge_
 		       mgp->dev->name);
 }
 
-static int myri10ge_reset(struct myri10ge_priv *mgp)
+static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type)
 {
 	struct myri10ge_cmd cmd;
 	int status;
-	size_t bytes;
 	u32 len;
 	struct page *dmatest_page;
 	dma_addr_t dmatest_bus;
+	char *test = " ";
+
+	dmatest_page = alloc_page(GFP_KERNEL);
+	if (!dmatest_page)
+		return -ENOMEM;
+	dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
+				   DMA_BIDIRECTIONAL);
+
+	/* Run a small DMA test.
+	 * The magic multipliers to the length tell the firmware
+	 * to do DMA read, write, or read+write tests.  The
+	 * results are returned in cmd.data0.  The upper 16
+	 * bits or the return is the number of transfers completed.
+	 * The lower 16 bits is the time in 0.5us ticks that the
+	 * transfers took to complete.
+	 */
+
+	len = mgp->tx.boundary;
+
+	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+	cmd.data2 = len * 0x10000;
+	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+	if (status != 0) {
+		test = "read";
+		goto abort;
+	}
+	mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);
+	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+	cmd.data2 = len * 0x1;
+	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+	if (status != 0) {
+		test = "write";
+		goto abort;
+	}
+	mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);
+
+	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+	cmd.data2 = len * 0x10001;
+	status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+	if (status != 0) {
+		test = "read/write";
+		goto abort;
+	}
+	mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /
+	    (cmd.data0 & 0xffff);
+
+abort:
+	pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+	put_page(dmatest_page);
+
+	if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST)
+		dev_warn(&mgp->pdev->dev, "DMA %s benchmark failed: %d\n",
+			 test, status);
+
+	return status;
+}
+
+static int myri10ge_reset(struct myri10ge_priv *mgp)
+{
+	struct myri10ge_cmd cmd;
+	int status;
+	size_t bytes;
 
 	/* try to send a reset command to the card to see if it
 	 * is alive */
@@ -729,11 +797,8 @@ static int myri10ge_reset(struct myri10g
 		dev_err(&mgp->pdev->dev, "failed reset\n");
 		return -ENXIO;
 	}
-	dmatest_page = alloc_page(GFP_KERNEL);
-	if (!dmatest_page)
-		return -ENOMEM;
-	dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
-				   DMA_BIDIRECTIONAL);
+
+	(void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST);
 
 	/* Now exchange information about interrupts  */
 
@@ -761,52 +826,6 @@ static int myri10ge_reset(struct myri10g
 	}
 	put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
 
-	/* Run a small DMA test.
-	 * The magic multipliers to the length tell the firmware
-	 * to do DMA read, write, or read+write tests.  The
-	 * results are returned in cmd.data0.  The upper 16
-	 * bits or the return is the number of transfers completed.
-	 * The lower 16 bits is the time in 0.5us ticks that the
-	 * transfers took to complete.
-	 */
-
-	len = mgp->tx.boundary;
-
-	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
-	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
-	cmd.data2 = len * 0x10000;
-	status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
-	if (status == 0)
-		mgp->read_dma = ((cmd.data0 >> 16) * len * 2) /
-		    (cmd.data0 & 0xffff);
-	else
-		dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n",
-			 status);
-	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
-	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
-	cmd.data2 = len * 0x1;
-	status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
-	if (status == 0)
-		mgp->write_dma = ((cmd.data0 >> 16) * len * 2) /
-		    (cmd.data0 & 0xffff);
-	else
-		dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n",
-			 status);
-
-	cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
-	cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
-	cmd.data2 = len * 0x10001;
-	status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
-	if (status == 0)
-		mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /
-		    (cmd.data0 & 0xffff);
-	else
-		dev_warn(&mgp->pdev->dev,
-			 "DMA read/write benchmark failed: %d\n", status);
-
-	pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
-	put_page(dmatest_page);
-
 	memset(mgp->rx_done.entry, 0, bytes);
 
 	/* reset mcp/driver shared state back to 0 */
@@ -820,10 +839,8 @@ static int myri10ge_reset(struct myri10g
 	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);
-	if (mgp->adopted_rx_filter_bug)
-		(void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
+	myri10ge_set_multicast_list(mgp->dev);
 	return status;
 }
 
@@ -879,7 +896,7 @@ myri10ge_rx_skb_build(struct sk_buff *sk
 	 * skb_pull() (for ether_pad and eth_type_trans()) requires
 	 * the beginning of the packet in skb_headlen(), move it
 	 * manually */
-	memcpy(skb->data, va, hlen);
+	skb_copy_to_linear_data(skb, va, hlen);
 	skb_shinfo(skb)->frags[0].page_offset += hlen;
 	skb_shinfo(skb)->frags[0].size -= hlen;
 	skb->data_len -= hlen;
@@ -1020,7 +1037,6 @@ myri10ge_rx_done(struct myri10ge_priv *m
 		skb_shinfo(skb)->nr_frags = 0;
 	}
 	skb->protocol = eth_type_trans(skb, dev);
-	skb->dev = dev;
 
 	if (mgp->csum_flag) {
 		if ((skb->protocol == htons(ETH_P_IP)) ||
@@ -1356,7 +1372,9 @@ static const char myri10ge_gstrings_stat
 	"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
 	"wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
 	"link_changes", "link_up", "dropped_link_overflow",
-	"dropped_link_error_or_filtered", "dropped_multicast_filtered",
+	"dropped_link_error_or_filtered",
+	"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
+	"dropped_unicast_filtered", "dropped_multicast_filtered",
 	"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
 	"dropped_no_big_buffer"
 };
@@ -1413,6 +1431,11 @@ myri10ge_get_ethtool_stats(struct net_de
 	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_pause);
+	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_phy);
+	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_crc32);
+	data[i++] =
+	    (unsigned int)ntohl(mgp->fw_stats->dropped_unicast_filtered);
 	data[i++] =
 	    (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
 	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
@@ -2030,7 +2053,7 @@ again:
 	odd_flag = 0;
 	flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST);
 	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
-		cksum_offset = (skb->h.raw - skb->data);
+		cksum_offset = skb_transport_offset(skb);
 		pseudo_hdr_offset = cksum_offset + skb->csum_offset;
 		/* If the headers are excessively large, then we must
 		 * fall back to a software checksum */
@@ -2055,7 +2078,7 @@ again:
 		 * send loop that we are still in the
 		 * header portion of the TSO packet.
 		 * TSO header must be at most 134 bytes long */
-		cum_len = -((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+		cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
 
 		/* for TSO, pseudo_hdr_offset holds mss.
 		 * The firmware figures out where to put
@@ -2277,7 +2300,7 @@ static void myri10ge_set_multicast_list(
 	myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
 
 	/* This firmware is known to not support multicast */
-	if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug)
+	if (!mgp->fw_multicast_support)
 		return;
 
 	/* Disable multicast filtering */
@@ -2289,7 +2312,7 @@ static void myri10ge_set_multicast_list(
 		goto abort;
 	}
 
-	if (dev->flags & IFF_ALLMULTI) {
+	if ((dev->flags & IFF_ALLMULTI) || mgp->adopted_rx_filter_bug) {
 		/* request to disable multicast filtering, so quit here */
 		return;
 	}
@@ -2462,8 +2485,6 @@ static void myri10ge_enable_ecrc(struct 
 	err_cap |= PCI_ERR_CAP_ECRC_GENE;
 	pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap);
 	dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge));
-	mgp->tx.boundary = 4096;
-	mgp->fw_name = myri10ge_fw_aligned;
 }
 
 /*
@@ -2485,22 +2506,70 @@ static void myri10ge_enable_ecrc(struct 
  * firmware image, and set tx.boundary to 4KB.
  */
 
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1 0x3510
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4 0x351b
-#define PCI_DEVICE_ID_INTEL_E3000_PCIE	0x2779
-#define PCI_DEVICE_ID_INTEL_E3010_PCIE	0x277a
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST 0x140
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST 0x142
-
-static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
 {
-	struct pci_dev *bridge = mgp->pdev->bus->self;
+	struct pci_dev *pdev = mgp->pdev;
+	struct device *dev = &pdev->dev;
+	int cap, status;
+	u16 val;
+
+	mgp->tx.boundary = 4096;
+	/*
+	 * Verify the max read request size was set to 4KB
+	 * before trying the test with 4KB.
+	 */
+	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (cap < 64) {
+		dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
+		goto abort;
+	}
+	status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
+	if (status != 0) {
+		dev_err(dev, "Couldn't read max read req size: %d\n", status);
+		goto abort;
+	}
+	if ((val & (5 << 12)) != (5 << 12)) {
+		dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val);
+		mgp->tx.boundary = 2048;
+	}
+	/*
+	 * load the optimized firmware (which assumes aligned PCIe
+	 * completions) in order to see if it works on this host.
+	 */
+	mgp->fw_name = myri10ge_fw_aligned;
+	status = myri10ge_load_firmware(mgp);
+	if (status != 0) {
+		goto abort;
+	}
+
+	/*
+	 * Enable ECRC if possible
+	 */
+	myri10ge_enable_ecrc(mgp);
+
+	/*
+	 * Run a DMA test which watches for unaligned completions and
+	 * aborts on the first one seen.
+	 */
 
+	status = myri10ge_dma_test(mgp, MXGEFW_CMD_UNALIGNED_TEST);
+	if (status == 0)
+		return;		/* keep the aligned firmware */
+
+	if (status != -E2BIG)
+		dev_warn(dev, "DMA test failed: %d\n", status);
+	if (status == -ENOSYS)
+		dev_warn(dev, "Falling back to ethp! "
+			 "Please install up to date fw\n");
+abort:
+	/* fall back to using the unaligned firmware */
 	mgp->tx.boundary = 2048;
 	mgp->fw_name = myri10ge_fw_unaligned;
 
+}
+
+static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+{
 	if (myri10ge_force_firmware == 0) {
 		int link_width, exp_cap;
 		u16 lnk;
@@ -2509,8 +2578,6 @@ static void myri10ge_select_firmware(str
 		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 Link is less than 8 or if the
 		 * upstream bridge is known to provide aligned
 		 * completions */
@@ -2519,46 +2586,8 @@ static void myri10ge_select_firmware(str
 				 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)
-			    /* ServerWorks HT2100 */
-			    || (bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
-				&& bridge->device >=
-				PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST
-				&& bridge->device <=
-				PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST)
-			    /* All Intel E3000/E3010 PCIE ports */
-			    || (bridge->vendor == PCI_VENDOR_ID_INTEL
-				&& (bridge->device ==
-				    PCI_DEVICE_ID_INTEL_E3000_PCIE
-				    || bridge->device ==
-				    PCI_DEVICE_ID_INTEL_E3010_PCIE))
-			    /* All Intel 6310/6311/6321ESB PCIE ports */
-			    || (bridge->vendor == PCI_VENDOR_ID_INTEL
-				&& bridge->device >=
-				PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1
-				&& bridge->device <=
-				PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4)
-			    /* 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);
-			mgp->tx.boundary = 4096;
-			mgp->fw_name = myri10ge_fw_aligned;
-		} else if (bridge &&
-			   bridge->vendor == PCI_VENDOR_ID_SGI &&
-			   bridge->device == 0x4002 /* TIOCE pcie-port */ ) {
-			/* this pcie bridge does not support 4K rdma request */
-			mgp->tx.boundary = 2048;
-			mgp->fw_name = myri10ge_fw_aligned;
+		} else {
+			myri10ge_firmware_probe(mgp);
 		}
 	} else {
 		if (myri10ge_force_firmware == 1) {
@@ -2826,7 +2855,6 @@ static int myri10ge_probe(struct pci_dev
 		status = -ENODEV;
 		goto abort_with_netdev;
 	}
-	myri10ge_select_firmware(mgp);
 
 	/* Find the vendor-specific cap so we can check
 	 * the reboot register later on */
@@ -2920,6 +2948,8 @@ #endif
 		goto abort_with_ioremap;
 	memset(mgp->rx_done.entry, 0, bytes);
 
+	myri10ge_select_firmware(mgp);
+
 	status = myri10ge_load_firmware(mgp);
 	if (status != 0) {
 		dev_err(&pdev->dev, "failed to load firmware\n");
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 29463b3..a1d2a22 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -200,6 +200,13 @@ enum myri10ge_mcp_cmd_type {
 	/* 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 */
+
+	MXGEFW_CMD_UNALIGNED_TEST,
+	/* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
+	 * chipset */
+
+	MXGEFW_CMD_UNALIGNED_STATUS
+	    /* return data = boolean, true if the chipset is known to be unaligned */
 };
 
 enum myri10ge_mcp_cmd_status {
@@ -212,18 +219,27 @@ enum myri10ge_mcp_cmd_status {
 	MXGEFW_CMD_ERROR_HASH_ERROR,
 	MXGEFW_CMD_ERROR_BAD_PORT,
 	MXGEFW_CMD_ERROR_RESOURCES,
-	MXGEFW_CMD_ERROR_MULTICAST
+	MXGEFW_CMD_ERROR_MULTICAST,
+	MXGEFW_CMD_ERROR_UNALIGNED
 };
 
 #define MXGEFW_OLD_IRQ_DATA_LEN 40
 
 struct mcp_irq_data {
 	/* add new counters at the beginning */
-	__be32 future_use[5];
+	__be32 future_use[1];
+	__be32 dropped_pause;
+	__be32 dropped_unicast_filtered;
+	__be32 dropped_bad_crc32;
+	__be32 dropped_bad_phy;
 	__be32 dropped_multicast_filtered;
 	/* 40 Bytes */
 	__be32 send_done_count;
 
+#define MXGEFW_LINK_DOWN 0
+#define MXGEFW_LINK_UP 1
+#define MXGEFW_LINK_MYRINET 2
+#define MXGEFW_LINK_UNKNOWN 3
 	__be32 link_up;
 	__be32 dropped_link_overflow;
 	__be32 dropped_link_error_or_filtered;
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index ee26ef5..13444da 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -368,7 +368,7 @@ static __be16 myri_type_trans(struct sk_
 	struct ethhdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);
+	skb_set_mac_header(skb, MYRI_PAD_LEN);
 	skb_pull(skb, dev->hard_header_len);
 	eth = eth_hdr(skb);
 
@@ -502,7 +502,7 @@ static void myri_rx(struct myri_eth *mp,
 			copy_skb->dev = dev;
 			DRX(("resv_and_put "));
 			skb_put(copy_skb, len);
-			memcpy(copy_skb->data, skb->data, len);
+			skb_copy_from_linear_data(skb, copy_skb->data, len);
 
 			/* Reuse original ring buffer. */
 			DRX(("reuse "));
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 349b96a..223e0e6 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -81,6 +81,8 @@ static const int multicast_filter_limit 
    Setting to > 1518 effectively disables this feature. */
 static int rx_copybreak;
 
+static int dspcfg_workaround = 1;
+
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' should exist for driver
    interoperability.
@@ -139,12 +141,14 @@ MODULE_LICENSE("GPL");
 module_param(mtu, int, 0);
 module_param(debug, int, 0);
 module_param(rx_copybreak, int, 0);
+module_param(dspcfg_workaround, int, 1);
 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,
 	"DP8381x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(dspcfg_workaround, "DP8381x: control DspCfg workaround");
 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)");
@@ -590,6 +594,7 @@ struct netdev_private {
 	u32 srr;
 	/* expected DSPCFG value */
 	u16 dspcfg;
+	int dspcfg_workaround;
 	/* parms saved in ethtool format */
 	u16	speed;		/* The forced speed, 10Mb, 100Mb, gigabit */
 	u8	duplex;		/* Duplex, half or full */
@@ -656,6 +661,56 @@ static int netdev_get_regs(struct net_de
 static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
 static const struct ethtool_ops ethtool_ops;
 
+#define NATSEMI_ATTR(_name) \
+static ssize_t natsemi_show_##_name(struct device *dev, \
+         struct device_attribute *attr, char *buf); \
+	 static ssize_t natsemi_set_##_name(struct device *dev, \
+		struct device_attribute *attr, \
+	        const char *buf, size_t count); \
+	 static DEVICE_ATTR(_name, 0644, natsemi_show_##_name, natsemi_set_##_name)
+
+#define NATSEMI_CREATE_FILE(_dev, _name) \
+         device_create_file(&_dev->dev, &dev_attr_##_name)
+#define NATSEMI_REMOVE_FILE(_dev, _name) \
+         device_create_file(&_dev->dev, &dev_attr_##_name)
+
+NATSEMI_ATTR(dspcfg_workaround);
+
+static ssize_t natsemi_show_dspcfg_workaround(struct device *dev,
+				  	      struct device_attribute *attr, 
+					      char *buf)
+{
+	struct netdev_private *np = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "%s\n", np->dspcfg_workaround ? "on" : "off");
+}
+
+static ssize_t natsemi_set_dspcfg_workaround(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	struct netdev_private *np = netdev_priv(to_net_dev(dev));
+	int new_setting;
+	u32 flags;
+
+        /* Find out the new setting */
+        if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
+                new_setting = 1;
+        else if (!strncmp("off", buf, count - 1)
+                 || !strncmp("0", buf, count - 1))
+		new_setting = 0;
+	else
+                 return count; 
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	np->dspcfg_workaround = new_setting;
+
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	return count;
+}
+
 static inline void __iomem *ns_ioaddr(struct net_device *dev)
 {
 	return (void __iomem *) dev->base_addr;
@@ -820,6 +875,7 @@ #endif
 		np->ignore_phy = 1;
 	else
 		np->ignore_phy = 0;
+	np->dspcfg_workaround = dspcfg_workaround;
 
 	/* Initial port:
 	 * - If configured to ignore the PHY set up for external.
@@ -899,6 +955,9 @@ #endif
 	if (i)
 		goto err_register_netdev;
 
+	if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround))
+		goto err_create_file;
+
 	if (netif_msg_drv(np)) {
 		printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
 			dev->name, natsemi_pci_info[chip_idx].name, iostart,
@@ -915,6 +974,9 @@ #endif
 	}
 	return 0;
 
+ err_create_file:
+ 	unregister_netdev(dev);
+
  err_register_netdev:
 	iounmap(ioaddr);
 
@@ -1727,7 +1789,8 @@ static void init_registers(struct net_de
  *    It seems that a reference set for this chip went out with incorrect info,
  *    and there exist boards that aren't quite right.  An unexpected voltage
  *    drop can cause the PHY to get itself in a weird state (basically reset).
- *    NOTE: this only seems to affect revC chips.
+ *    NOTE: this only seems to affect revC chips.  The user can disable
+ *    this check via dspcfg_workaround sysfs option.
  * 3) check of death of the RX path due to OOM
  */
 static void netdev_timer(unsigned long data)
@@ -1753,10 +1816,10 @@ static void netdev_timer(unsigned long d
 		writew(1, ioaddr+PGSEL);
 		dspcfg = readw(ioaddr+DSPCFG);
 		writew(0, ioaddr+PGSEL);
-		if (dspcfg != np->dspcfg) {
+		if (np->dspcfg_workaround && dspcfg != np->dspcfg) {
 			if (!netif_queue_stopped(dev)) {
 				spin_unlock_irq(&np->lock);
-				if (netif_msg_hw(np))
+				if (netif_msg_drv(np))
 					printk(KERN_NOTICE "%s: possible phy reset: "
 						"re-initializing\n", dev->name);
 				disable_irq(dev->irq);
@@ -2289,7 +2352,6 @@ static void netdev_rx(struct net_device 
 			 * without copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 			    && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) {
-				skb->dev = dev;
 				/* 16 byte align the IP header */
 				skb_reserve(skb, RX_OFFSET);
 				pci_dma_sync_single_for_cpu(np->pci_dev,
@@ -3158,6 +3220,7 @@ static void __devexit natsemi_remove1 (s
 	struct net_device *dev = pci_get_drvdata(pdev);
 	void __iomem * ioaddr = ns_ioaddr(dev);
 
+	NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround);
 	unregister_netdev (dev);
 	pci_release_regions (pdev);
 	iounmap(ioaddr);
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index a5c4199..c9f74bf 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -51,14 +51,11 @@ #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/jiffies.h>
+#include <linux/platform_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 
-#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
-#include <asm/tx4938/rbtx4938.h>
-#endif
-
 #include "8390.h"
 
 #define DRV_NAME "ne"
@@ -77,8 +74,13 @@ #define SUPPORT_NE_BAD_CLONES
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
+#if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R))
+/* Do we need a portlist for the ISA auto-probe ? */
+#define NEEDS_PORTLIST
+#endif
+
 /* A zero-terminated list of I/O addresses to be probed at boot. */
-#ifndef MODULE
+#ifdef NEEDS_PORTLIST
 static unsigned int netcard_portlist[] __initdata = {
 	0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
 };
@@ -146,7 +148,7 @@ #else
 #  define DCR_VAL 0x49
 #endif
 
-static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_probe1(struct net_device *dev, unsigned long ioaddr);
 static int ne_probe_isapnp(struct net_device *dev);
 
 static int ne_open(struct net_device *dev);
@@ -184,8 +186,8 @@ static void ne_block_output(struct net_d
 
 static int __init do_ne_probe(struct net_device *dev)
 {
-	unsigned int base_addr = dev->base_addr;
-#ifndef MODULE
+	unsigned long base_addr = dev->base_addr;
+#ifdef NEEDS_PORTLIST
 	int orig_irq = dev->irq;
 #endif
 
@@ -201,7 +203,7 @@ #endif
 	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
 		return 0;
 
-#ifndef MODULE
+#ifdef NEEDS_PORTLIST
 	/* Last resort. The semi-risky ISA auto-probe. */
 	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
 		int ioaddr = netcard_portlist[base_addr];
@@ -226,10 +228,6 @@ struct net_device * __init ne_probe(int 
 	sprintf(dev->name, "eth%d", unit);
 	netdev_boot_setup_check(dev);
 
-#ifdef CONFIG_TOSHIBA_RBTX4938
-	dev->base_addr = RBTX4938_RTL_8019_BASE;
-	dev->irq = RBTX4938_RTL_8019_IRQ;
-#endif
 	err = do_ne_probe(dev);
 	if (err)
 		goto out;
@@ -285,7 +283,7 @@ static int __init ne_probe_isapnp(struct
 	return -ENODEV;
 }
 
-static int __init ne_probe1(struct net_device *dev, int ioaddr)
+static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
 {
 	int i;
 	unsigned char SA_prom[32];
@@ -324,7 +322,7 @@ static int __init ne_probe1(struct net_d
 	if (ei_debug  &&  version_printed++ == 0)
 		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
 
-	printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+	printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr);
 
 	/* A user with a poor card that fails to ack the reset, or that
 	   does not have a valid 0x57,0x57 signature can still use this
@@ -516,8 +514,7 @@ #else
 	}
 #endif
 
-	printk("\n%s: %s found at %#x, using IRQ %d.\n",
-		dev->name, name, ioaddr, dev->irq);
+	printk("\n");
 
 	ei_status.name = name;
 	ei_status.tx_start_page = start_page;
@@ -547,6 +544,8 @@ #endif
 	ret = register_netdev(dev);
 	if (ret)
 		goto out_irq;
+	printk(KERN_INFO "%s: %s found at %#lx, using IRQ %d.\n",
+	       dev->name, name, ioaddr, dev->irq);
 	return 0;
 
 out_irq:
@@ -807,6 +806,87 @@ #endif
 	return;
 }
 
+static int __init ne_drv_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct resource *res;
+	int err, irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!res || irq < 0)
+		return -ENODEV;
+
+	dev = alloc_ei_netdev();
+	if (!dev)
+		return -ENOMEM;
+	dev->irq = irq;
+	dev->base_addr = res->start;
+	err = do_ne_probe(dev);
+	if (err) {
+		free_netdev(dev);
+		return err;
+	}
+	platform_set_drvdata(pdev, dev);
+	return 0;
+}
+
+static int __exit ne_drv_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	unregister_netdev(dev);
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, NE_IO_EXTENT);
+	free_netdev(dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	if (netif_running(dev))
+		netif_device_detach(dev);
+	return 0;
+}
+
+static int ne_drv_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	if (netif_running(dev)) {
+		ne_reset_8390(dev);
+		NS8390_init(dev, 1);
+		netif_device_attach(dev);
+	}
+	return 0;
+}
+#else
+#define ne_drv_suspend NULL
+#define ne_drv_resume NULL
+#endif
+
+static struct platform_driver ne_driver = {
+	.remove		= __exit_p(ne_drv_remove),
+	.suspend	= ne_drv_suspend,
+	.resume		= ne_drv_resume,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ne_init(void)
+{
+	return platform_driver_probe(&ne_driver, ne_drv_probe);
+}
+
+static void __exit ne_exit(void)
+{
+	platform_driver_unregister(&ne_driver);
+}
 
 #ifdef MODULE
 #define MAX_NE_CARDS	4	/* Max number of NE cards per module */
@@ -832,6 +912,7 @@ ISA device autoprobes on a running machi
 int __init init_module(void)
 {
 	int this_dev, found = 0;
+	int plat_found = !ne_init();
 
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
 		struct net_device *dev = alloc_ei_netdev();
@@ -845,7 +926,7 @@ int __init init_module(void)
 			continue;
 		}
 		free_netdev(dev);
-		if (found)
+		if (found || plat_found)
 			break;
 		if (io[this_dev] != 0)
 			printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
@@ -853,7 +934,7 @@ int __init init_module(void)
 			printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
 		return -ENXIO;
 	}
-	if (found)
+	if (found || plat_found)
 		return 0;
 	return -ENODEV;
 }
@@ -871,6 +952,7 @@ void __exit cleanup_module(void)
 {
 	int this_dev;
 
+	ne_exit();
 	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
 		struct net_device *dev = dev_ne[this_dev];
 		if (dev) {
@@ -880,4 +962,7 @@ void __exit cleanup_module(void)
 		}
 	}
 }
+#else /* MODULE */
+module_init(ne_init);
+module_exit(ne_exit);
 #endif /* MODULE */
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index a53644f..2b8da0a 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -168,7 +168,6 @@ static void netx_eth_receive(struct net_
 		FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno));
 
 	ndev->last_rx = jiffies;
-	skb->dev = ndev;
 	skb->protocol = eth_type_trans(skb, ndev);
 	netif_rx(skb);
 	priv->stats.rx_packets++;
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index dd8ce35..ad6688e 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -64,9 +64,9 @@ #include <asm/pgtable.h>
 #include "netxen_nic_hw.h"
 
 #define _NETXEN_NIC_LINUX_MAJOR 3
-#define _NETXEN_NIC_LINUX_MINOR 3
-#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3"
+#define _NETXEN_NIC_LINUX_MINOR 4
+#define _NETXEN_NIC_LINUX_SUBVERSION 2
+#define NETXEN_NIC_LINUX_VERSIONID  "3.4.2"
 
 #define NUM_FLASH_SECTORS (64)
 #define FLASH_SECTOR_SIZE (64 * 1024)
@@ -131,8 +131,8 @@ #define NX_P2_C1		0x25
 #define FIRST_PAGE_GROUP_START	0
 #define FIRST_PAGE_GROUP_END	0x100000
 
-#define SECOND_PAGE_GROUP_START	0x4000000
-#define SECOND_PAGE_GROUP_END	0x66BC000
+#define SECOND_PAGE_GROUP_START	0x6000000
+#define SECOND_PAGE_GROUP_END	0x68BC000
 
 #define THIRD_PAGE_GROUP_START	0x70E4000
 #define THIRD_PAGE_GROUP_END	0x8000000
@@ -205,6 +205,8 @@ #define RCV_DESC_TYPE(ID) \
 
 #define MAX_CMD_DESCRIPTORS		1024
 #define MAX_RCV_DESCRIPTORS		16384
+#define MAX_CMD_DESCRIPTORS_HOST	(MAX_CMD_DESCRIPTORS / 4)
+#define MAX_RCV_DESCRIPTORS_1G		(MAX_RCV_DESCRIPTORS / 4)
 #define MAX_JUMBO_RCV_DESCRIPTORS	1024
 #define MAX_LRO_RCV_DESCRIPTORS		64
 #define MAX_RCVSTATUS_DESCRIPTORS	MAX_RCV_DESCRIPTORS
@@ -230,7 +232,9 @@ #define get_index_range(index,length,cou
 	(((index) + (count)) & ((length) - 1))
 
 #define MPORT_SINGLE_FUNCTION_MODE 0x1111
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
 
+#include "netxen_nic_phan_reg.h"
 extern unsigned long long netxen_dma_mask;
 extern unsigned long last_schedule_time;
 
@@ -300,6 +304,8 @@ #define FLAGS_VLAN_TAGGED	0x10
 
 #define netxen_set_cmd_desc_port(cmd_desc, var)	\
 	((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define netxen_set_cmd_desc_ctxid(cmd_desc, var)	\
+	((cmd_desc)->port_ctxid |= ((var) & 0xF0))
 
 #define netxen_set_cmd_desc_flags(cmd_desc, val)	\
 	((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
@@ -442,7 +448,7 @@ struct status_desc {
 	/* Bit pattern: 0-6 lro_count indicates frag sequence,
 	   7 last_frag indicates last frag */
 	u8 lro;
-} __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(16)));
 
 enum {
 	NETXEN_RCV_PEG_0 = 0,
@@ -703,10 +709,8 @@ #define DPRINTK(klevel, fmt, args...)	do
 #else
 #define DPRINTK(klevel, fmt, args...)	do { \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\
-		(adapter != NULL && \
-		adapter->port[0] != NULL && \
-		adapter->port[0]->netdev != NULL) ? \
-		adapter->port[0]->netdev->name : NULL, \
+		(adapter != NULL && adapter->netdev != NULL) ? \
+		adapter->netdev->name : NULL, \
 		## args); } while(0)
 #endif
 
@@ -722,6 +726,18 @@ struct netxen_skb_frag {
 	u32 length;
 };
 
+#define _netxen_set_bits(config_word, start, bits, val)	{\
+	unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\
+	unsigned long long __tvalue = (val);    \
+	(config_word) &= ~__tmask;      \
+	(config_word) |= (((__tvalue) << (start)) & __tmask); \
+}
+	
+#define _netxen_clear_bits(config_word, start, bits) {\
+	unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));  \
+	(config_word) &= ~__tmask; \
+}		
+
 /*    Following defines are for the state of the buffers    */
 #define	NETXEN_BUFFER_FREE	0
 #define	NETXEN_BUFFER_BUSY	1
@@ -766,6 +782,8 @@ struct netxen_hardware_context {
 	void __iomem *pci_base0;
 	void __iomem *pci_base1;
 	void __iomem *pci_base2;
+	unsigned long first_page_group_end;
+	unsigned long first_page_group_start;
 	void __iomem *db_base;
 	unsigned long db_len;
 
@@ -780,6 +798,7 @@ struct netxen_hardware_context {
 	struct pci_dev *cmd_desc_pdev;
 	dma_addr_t cmd_desc_phys_addr;
 	struct netxen_adapter *adapter;
+	int pci_func;
 };
 
 #define RCV_RING_LRO	RCV_DESC_LRO
@@ -788,17 +807,27 @@ #define MINIMUM_ETHERNET_FRAME_SIZE	64	/
 #define ETHERNET_FCS_SIZE		4
 
 struct netxen_adapter_stats {
-	u64 ints;
-	u64 hostints;
-	u64 otherints;
-	u64 process_rcv;
-	u64 process_xmit;
-	u64 noxmitdone;
-	u64 xmitcsummed;
-	u64 post_called;
-	u64 posted;
-	u64 lastposted;
-	u64 goodskbposts;
+	u64  rcvdbadskb;
+	u64  xmitcalled;
+	u64  xmitedframes;
+	u64  xmitfinished;
+	u64  badskblen;
+	u64  nocmddescriptor;
+	u64  polled;
+	u64  uphappy;
+	u64  updropped;
+	u64  uplcong;
+	u64  uphcong;
+	u64  upmcong;
+	u64  updunno;
+	u64  skbfreed;
+	u64  txdropped;
+	u64  txnullskb;
+	u64  csummed;
+	u64  no_rcv;
+	u64  rxbytes;
+	u64  txbytes;
+	u64  ints;
 };
 
 /*
@@ -846,13 +875,20 @@ struct netxen_dummy_dma {
 
 struct netxen_adapter {
 	struct netxen_hardware_context ahw;
-	int port_count;		/* Number of configured ports  */
-	int active_ports;	/* Number of open ports */
-	struct netxen_port *port[NETXEN_MAX_PORTS];	/* ptr to each port  */
+	
+	struct netxen_adapter *master;
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+	unsigned char mac_addr[ETH_ALEN];
+	int mtu;
+	int portnum;
+
 	spinlock_t tx_lock;
 	spinlock_t lock;
 	struct work_struct watchdog_task;
 	struct timer_list watchdog_timer;
+	struct work_struct  tx_timeout_task;
 
 	u32 curr_window;
 
@@ -875,6 +911,15 @@ struct netxen_adapter {
 	u32 temp;
 
 	struct netxen_adapter_stats stats;
+	
+	u16 portno;
+	u16 link_speed;
+	u16 link_duplex;
+	u16 state;
+	u16 link_autoneg;
+	int rcsum;
+	int status;
+	spinlock_t stats_lock;
 
 	struct netxen_cmd_buffer *cmd_buf_arr;	/* Command buffers for xmit */
 
@@ -891,65 +936,23 @@ struct netxen_adapter {
 	struct netxen_ring_ctx *ctx_desc;
 	struct pci_dev *ctx_desc_pdev;
 	dma_addr_t ctx_desc_phys_addr;
-	int (*enable_phy_interrupts) (struct netxen_adapter *, int);
-	int (*disable_phy_interrupts) (struct netxen_adapter *, int);
+	int (*enable_phy_interrupts) (struct netxen_adapter *);
+	int (*disable_phy_interrupts) (struct netxen_adapter *);
 	void (*handle_phy_intr) (struct netxen_adapter *);
-	int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t);
-	int (*set_mtu) (struct netxen_port *, int);
-	int (*set_promisc) (struct netxen_adapter *, int,
-			    netxen_niu_prom_mode_t);
-	int (*unset_promisc) (struct netxen_adapter *, int,
-			      netxen_niu_prom_mode_t);
-	int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *);
-	int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val);
+	int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t);
+	int (*set_mtu) (struct netxen_adapter *, int);
+	int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+	int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+	int (*phy_read) (struct netxen_adapter *, long reg, u32 *);
+	int (*phy_write) (struct netxen_adapter *, long reg, u32 val);
 	int (*init_port) (struct netxen_adapter *, int);
 	void (*init_niu) (struct netxen_adapter *);
-	int (*stop_port) (struct netxen_adapter *, int);
+	int (*stop_port) (struct netxen_adapter *);
 };				/* netxen_adapter structure */
 
 /* Max number of xmit producer threads that can run simultaneously */
 #define	MAX_XMIT_PRODUCERS		16
 
-struct netxen_port_stats {
-	u64 rcvdbadskb;
-	u64 xmitcalled;
-	u64 xmitedframes;
-	u64 xmitfinished;
-	u64 badskblen;
-	u64 nocmddescriptor;
-	u64 polled;
-	u64 uphappy;
-	u64 updropped;
-	u64 uplcong;
-	u64 uphcong;
-	u64 upmcong;
-	u64 updunno;
-	u64 skbfreed;
-	u64 txdropped;
-	u64 txnullskb;
-	u64 csummed;
-	u64 no_rcv;
-	u64 rxbytes;
-	u64 txbytes;
-};
-
-struct netxen_port {
-	struct netxen_adapter *adapter;
-
-	u16 portnum;		/* GBE port number */
-	u16 link_speed;
-	u16 link_duplex;
-	u16 link_autoneg;
-
-	int flags;
-
-	struct net_device *netdev;
-	struct pci_dev *pdev;
-	struct net_device_stats net_stats;
-	struct netxen_port_stats stats;
-	struct work_struct tx_timeout_task;
-};
-
 #define PCI_OFFSET_FIRST_RANGE(adapter, off)    \
 	((adapter)->ahw.pci_base0 + (off))
 #define PCI_OFFSET_SECOND_RANGE(adapter, off)   \
@@ -987,32 +990,26 @@ static inline void __iomem *pci_base(str
 	return NULL;
 }
 
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-					  int port);
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-					 int port);
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-					   int port);
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-					  int port);
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-					 int port);
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-					int port);
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter);
 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter);
 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter);
 void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
 				 long enable);
 void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
 				  long enable);
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg,
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
 			    __u32 * readval);
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy,
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
 			     long reg, __u32 val);
 
 /* Functions available from netxen_nic_hw.c */
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu);
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu);
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu);
 void netxen_nic_init_niu_gb(struct netxen_adapter *adapter);
 void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw);
 void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val);
@@ -1027,6 +1024,7 @@ int netxen_nic_hw_write_wx(struct netxen
 			   int len);
 void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
 				 unsigned long off, int data);
+int netxen_nic_erase_pxe(struct netxen_adapter *adapter);
 
 /* Functions from netxen_nic_init.c */
 void netxen_free_adapter_offload(struct netxen_adapter *adapter);
@@ -1051,11 +1049,8 @@ int netxen_do_rom_se(struct netxen_adapt
 
 /* Functions from netxen_nic_isr.c */
 void netxen_nic_isr_other(struct netxen_adapter *adapter);
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port,
-				 u32 link);
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port,
-			    u32 enable);
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter);
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link);
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable);
 void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
 void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
 void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
@@ -1110,6 +1105,7 @@ static inline void netxen_nic_enable_int
 
 	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
 		mask = 0xbff;
+		writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
 		writel(mask, PCI_OFFSET_SECOND_RANGE(adapter,
 						     ISR_INT_TARGET_MASK));
 	}
@@ -1174,4 +1170,5 @@ extern int netxen_rom_fast_read(struct n
 
 extern struct ethtool_ops netxen_nic_ethtool_ops;
 
+extern int physical_port[];	/* physical port # from virtual port.*/
 #endif				/* __NETXEN_NIC_H_ */
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index ee1b5a2..16fabb3 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -40,8 +40,8 @@ #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/version.h>
 
-#include "netxen_nic_hw.h"
 #include "netxen_nic.h"
+#include "netxen_nic_hw.h"
 #include "netxen_nic_phan_reg.h"
 
 struct netxen_nic_stats {
@@ -50,8 +50,8 @@ struct netxen_nic_stats {
 	int stat_offset;
 };
 
-#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \
-			offsetof(struct netxen_port, m)
+#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \
+			offsetof(struct netxen_adapter, m)
 
 #define NETXEN_NIC_PORT_WINDOW 0x10000
 #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF
@@ -100,8 +100,7 @@ static int netxen_nic_get_eeprom_len(str
 static void
 netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	u32 fw_major = 0;
 	u32 fw_minor = 0;
 	u32 fw_build = 0;
@@ -115,7 +114,7 @@ netxen_nic_get_drvinfo(struct net_device
 	fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
 	sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
 
-	strncpy(drvinfo->bus_info, pci_name(port->pdev), 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
 	drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
 	drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
 	drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
@@ -125,8 +124,7 @@ netxen_nic_get_drvinfo(struct net_device
 static int
 netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg;
 
 	/* read which mode */
@@ -146,8 +144,8 @@ netxen_nic_get_settings(struct net_devic
 		ecmd->port = PORT_TP;
 
 		if (netif_running(dev)) {
-			ecmd->speed = port->link_speed;
-			ecmd->duplex = port->link_duplex;
+			ecmd->speed = adapter->link_speed;
+			ecmd->duplex = adapter->link_duplex;
 		} else
 			return -EIO;	/* link absent */
 	} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
@@ -165,7 +163,7 @@ netxen_nic_get_settings(struct net_devic
 	} else
 		return -EIO;
 
-	ecmd->phy_address = port->portnum;
+	ecmd->phy_address = adapter->portnum;
 	ecmd->transceiver = XCVR_EXTERNAL;
 
 	switch ((netxen_brdtype_t) boardinfo->board_type) {
@@ -179,7 +177,7 @@ netxen_nic_get_settings(struct net_devic
 		ecmd->port = PORT_TP;
 		ecmd->autoneg = (boardinfo->board_type ==
 				 NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
-		    (AUTONEG_DISABLE) : (port->link_autoneg);
+		    (AUTONEG_DISABLE) : (adapter->link_autoneg);
 		break;
 	case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
 	case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -206,23 +204,22 @@ netxen_nic_get_settings(struct net_devic
 static int
 netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	__u32 status;
 
 	/* read which mode */
 	if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
 		/* autonegotiation */
 		if (adapter->phy_write
-		    && adapter->phy_write(adapter, port->portnum,
+		    && adapter->phy_write(adapter,
 					  NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
 					  ecmd->autoneg) != 0)
 			return -EIO;
 		else
-			port->link_autoneg = ecmd->autoneg;
+			adapter->link_autoneg = ecmd->autoneg;
 
 		if (adapter->phy_read
-		    && adapter->phy_read(adapter, port->portnum,
+		    && adapter->phy_read(adapter,
 					 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 					 &status) != 0)
 			return -EIO;
@@ -245,13 +242,13 @@ netxen_nic_set_settings(struct net_devic
 		if (ecmd->duplex == DUPLEX_FULL)
 			netxen_set_phy_duplex(status);
 		if (adapter->phy_write
-		    && adapter->phy_write(adapter, port->portnum,
+		    && adapter->phy_write(adapter,
 					  NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 					  *((int *)&status)) != 0)
 			return -EIO;
 		else {
-			port->link_speed = ecmd->speed;
-			port->link_duplex = ecmd->duplex;
+			adapter->link_speed = ecmd->speed;
+			adapter->link_duplex = ecmd->duplex;
 		}
 	} else
 		return -EOPNOTSUPP;
@@ -360,15 +357,14 @@ static struct netxen_niu_regs niu_regist
 static void
 netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	__u32 mode, *regs_buff = p;
 	void __iomem *addr;
 	int i, window;
 
 	memset(p, 0, NETXEN_NIC_REGS_LEN);
 	regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
-	    (port->pdev)->device;
+	    (adapter->pdev)->device;
 	/* which mode */
 	NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, &regs_buff[0]);
 	mode = regs_buff[0];
@@ -383,7 +379,8 @@ netxen_nic_get_regs(struct net_device *d
 		for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
 			/* GB: port specific registers */
 			if (mode == 0 && i >= 19)
-				window = port->portnum * NETXEN_NIC_PORT_WINDOW;
+				window = physical_port[adapter->portnum] *
+					NETXEN_NIC_PORT_WINDOW;
 
 			NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode].
 						   reg[i - 3] + window,
@@ -395,15 +392,14 @@ netxen_nic_get_regs(struct net_device *d
 
 static u32 netxen_nic_test_link(struct net_device *dev)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	__u32 status;
 	int val;
 
 	/* read which mode */
 	if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
 		if (adapter->phy_read
-		    && adapter->phy_read(adapter, port->portnum,
+		    && adapter->phy_read(adapter,
 					 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 					 &status) != 0)
 			return -EIO;
@@ -422,15 +418,15 @@ static int
 netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 		      u8 * bytes)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	int offset;
 	int ret;
 
 	if (eeprom->len == 0)
 		return -EINVAL;
 
-	eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
+	eeprom->magic = (adapter->pdev)->vendor | 
+			((adapter->pdev)->device << 16);
 	offset = eeprom->offset;
 
 	ret = netxen_rom_fast_read_words(adapter, offset, bytes, 
@@ -445,8 +441,7 @@ static int
 netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 			u8 * bytes)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	int offset = eeprom->offset;
 	static int flash_start;
 	static int ready_to_flash;
@@ -516,8 +511,7 @@ netxen_nic_set_eeprom(struct net_device 
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	int i;
 
 	ring->rx_pending = 0;
@@ -541,19 +535,45 @@ static void
 netxen_nic_get_pauseparam(struct net_device *dev,
 			  struct ethtool_pauseparam *pause)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	__u32 val;
+	int port = physical_port[adapter->portnum];
 
 	if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+		if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+			return;
 		/* get flow control settings */
-		netxen_nic_read_w0(adapter,
-				   NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-				   &val);
+		netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port),
+				&val);
 		pause->rx_pause = netxen_gb_get_rx_flowctl(val);
-		pause->tx_pause = netxen_gb_get_tx_flowctl(val);
-		/* get autoneg settings */
-		pause->autoneg = port->link_autoneg;
+		netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+		switch (port) {
+			case 0:
+				pause->tx_pause = !(netxen_gb_get_gb0_mask(val));
+				break;
+			case 1:
+				pause->tx_pause = !(netxen_gb_get_gb1_mask(val));
+				break;
+			case 2:
+				pause->tx_pause = !(netxen_gb_get_gb2_mask(val));
+				break;
+			case 3:
+			default:
+				pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
+				break;
+		}
+	} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+		if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+			return;
+		pause->rx_pause = 1;
+		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+		if (port == 0)
+			pause->tx_pause = !(netxen_xg_get_xg0_mask(val));
+		else
+			pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
+	} else {
+		printk(KERN_ERR"%s: Unknown board type: %x\n", 
+				netxen_nic_driver_name, adapter->ahw.board_type);
 	}
 }
 
@@ -561,42 +581,76 @@ static int
 netxen_nic_set_pauseparam(struct net_device *dev,
 			  struct ethtool_pauseparam *pause)
 {
-	struct netxen_port *port = netdev_priv(dev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	__u32 val;
-	unsigned int autoneg;
-
+	int port = physical_port[adapter->portnum];
 	/* read mode */
 	if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+		if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+			return -EIO;
 		/* set flow control */
 		netxen_nic_read_w0(adapter,
-				   NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-				   (u32 *) & val);
-		if (pause->tx_pause)
-			netxen_gb_tx_flowctl(val);
-		else
-			netxen_gb_unset_tx_flowctl(val);
+					NETXEN_NIU_GB_MAC_CONFIG_0(port), &val);
+		
 		if (pause->rx_pause)
 			netxen_gb_rx_flowctl(val);
 		else
 			netxen_gb_unset_rx_flowctl(val);
 
-		netxen_nic_write_w0(adapter,
-				    NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
-				    *&val);
+		netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+				val);
 		/* set autoneg */
-		autoneg = pause->autoneg;
-		if (adapter->phy_write
-		    && adapter->phy_write(adapter, port->portnum,
-					  NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
-					  autoneg) != 0)
+		netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+		switch (port) {
+			case 0:
+				if (pause->tx_pause)
+					netxen_gb_unset_gb0_mask(val);
+				else
+					netxen_gb_set_gb0_mask(val);
+				break;
+			case 1:
+				if (pause->tx_pause)
+					netxen_gb_unset_gb1_mask(val);
+				else
+					netxen_gb_set_gb1_mask(val);
+				break;
+			case 2:
+				if (pause->tx_pause)
+					netxen_gb_unset_gb2_mask(val);
+				else
+					netxen_gb_set_gb2_mask(val);
+				break;
+			case 3:
+			default:
+				if (pause->tx_pause)
+					netxen_gb_unset_gb3_mask(val);
+				else
+					netxen_gb_set_gb3_mask(val);
+				break;
+		}
+		netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
+	} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+		if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
 			return -EIO;
-		else {
-			port->link_autoneg = pause->autoneg;
-			return 0;
+		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+		if (port == 0) {
+			if (pause->tx_pause)
+				netxen_xg_unset_xg0_mask(val);
+			else
+				netxen_xg_set_xg0_mask(val);
+		} else {
+			if (pause->tx_pause)
+				netxen_xg_unset_xg1_mask(val);
+			else
+				netxen_xg_set_xg1_mask(val);
 		}
-	} else
-		return -EOPNOTSUPP;
+		netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);			
+	} else {
+		printk(KERN_ERR "%s: Unknown board type: %x\n",
+				netxen_nic_driver_name, 
+				adapter->ahw.board_type);
+	}
+	return 0;
 }
 
 static int netxen_nic_reg_test(struct net_device *dev)
@@ -627,23 +681,12 @@ static void
 netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
 		     u64 * data)
 {
-	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {	/* offline tests */
-		/* link test */
-		if ((data[1] = (u64) netxen_nic_test_link(dev)))
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-
-		/* register tests */
-		if ((data[0] = netxen_nic_reg_test(dev)))
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-	} else {		/* online tests */
-		/* register tests */
-		if((data[0] = netxen_nic_reg_test(dev)))
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-
-		/* link test */
-		if ((data[1] = (u64) netxen_nic_test_link(dev)))
-			eth_test->flags |= ETH_TEST_FL_FAILED;
-	}
+	memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN);
+	if ((data[0] = netxen_nic_reg_test(dev)))
+		eth_test->flags |= ETH_TEST_FL_FAILED;
+	/* link test */
+	if ((data[1] = (u64) netxen_nic_test_link(dev)))
+		eth_test->flags |= ETH_TEST_FL_FAILED;
 }
 
 static void
@@ -675,12 +718,13 @@ static void
 netxen_nic_get_ethtool_stats(struct net_device *dev,
 			     struct ethtool_stats *stats, u64 * data)
 {
-	struct netxen_port *port = netdev_priv(dev);
+	struct netxen_adapter *adapter = netdev_priv(dev);
 	int index;
 
 	for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
 		char *p =
-		    (char *)port + netxen_nic_gstrings_stats[index].stat_offset;
+		    (char *)adapter +
+		    netxen_nic_gstrings_stats[index].stat_offset;
 		data[index] =
 		    (netxen_nic_gstrings_stats[index].sizeof_stat ==
 		     sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index fe8b675..608e37b 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -467,6 +467,8 @@ #define NETXEN_PCI_OCM0_MAX	(0x050fffffU
 #define NETXEN_PCI_OCM1		(0x05100000UL)
 #define NETXEN_PCI_OCM1_MAX	(0x051fffffUL)
 #define NETXEN_PCI_CRBSPACE	(0x06000000UL)
+#define NETXEN_PCI_128MB_SIZE	(0x08000000UL)
+#define NETXEN_PCI_32MB_SIZE	(0x02000000UL)
 
 #define NETXEN_CRB_CAM	NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM)
 
@@ -484,6 +486,7 @@ #define	NETXEN_NIU_PHY_WAITLEN		200000
 	/* 10 seconds before we give up */
 #define	NETXEN_NIU_PHY_WAITMAX		50
 #define	NETXEN_NIU_MAX_GBE_PORTS	4
+#define	NETXEN_NIU_MAX_XG_PORTS		2
 
 #define	NETXEN_NIU_MODE			(NETXEN_CRB_NIU + 0x00000)
 
@@ -527,6 +530,7 @@ #define	NETXEN_NIU_TEST_MUX_CTL		(NETXEN
 #define	NETXEN_NIU_XG_PAUSE_CTL		(NETXEN_CRB_NIU + 0x00098)
 #define	NETXEN_NIU_XG_PAUSE_LEVEL	(NETXEN_CRB_NIU + 0x000dc)
 #define	NETXEN_NIU_XG_SEL		(NETXEN_CRB_NIU + 0x00128)
+#define NETXEN_NIU_GB_PAUSE_CTL		(NETXEN_CRB_NIU + 0x0030c)
 
 #define NETXEN_NIU_FULL_LEVEL_XG	(NETXEN_CRB_NIU + 0x00450)
 
@@ -649,11 +653,19 @@ #define PCIX_MN_WINDOW		(0x10200)
 #define PCIX_MS_WINDOW		(0x10204)
 #define PCIX_SN_WINDOW		(0x10208)
 #define PCIX_CRB_WINDOW		(0x10210)
+#define PCIX_CRB_WINDOW_F0	(0x10210)
+#define PCIX_CRB_WINDOW_F1	(0x10230)
+#define PCIX_CRB_WINDOW_F2	(0x10250)
+#define PCIX_CRB_WINDOW_F3	(0x10270)
 
 #define PCIX_TARGET_STATUS	(0x10118)
 #define PCIX_TARGET_MASK	(0x10128)
 
 #define PCIX_MSI_F0		(0x13000)
+#define PCIX_MSI_F1		(0x13004)
+#define PCIX_MSI_F2		(0x13008)
+#define PCIX_MSI_F3		(0x1300c)
+#define PCIX_MSI_F(i)		(0x13000+((i)*4))
 
 #define PCIX_PS_MEM_SPACE	(0x90000)
 
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 6537574..baff17a 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -33,8 +33,225 @@
 
 #include "netxen_nic.h"
 #include "netxen_nic_hw.h"
+#define DEFINE_GLOBAL_RECV_CRB
 #include "netxen_nic_phan_reg.h"
 
+
+#include <net/ip.h>
+
+struct netxen_recv_crb recv_crb_registers[] = {
+	/*
+	 * Instance 0.
+	 */
+	{
+	 /* rcv_desc_crb: */
+	 {
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x100),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x104),
+	   /* crb_gloablrcv_ring: */
+	   NETXEN_NIC_REG(0x108),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x10c),
+
+	   },
+	  /* Jumbo frames */
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x110),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x114),
+	   /* crb_gloablrcv_ring: */
+	   NETXEN_NIC_REG(0x118),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x11c),
+	   },
+	  /* LRO */
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x120),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x124),
+	   /* crb_gloablrcv_ring: */
+	   NETXEN_NIC_REG(0x128),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x12c),
+	   }
+	  },
+	 /* crb_rcvstatus_ring: */
+	 NETXEN_NIC_REG(0x130),
+	 /* crb_rcv_status_producer: */
+	 NETXEN_NIC_REG(0x134),
+	 /* crb_rcv_status_consumer: */
+	 NETXEN_NIC_REG(0x138),
+	 /* crb_rcvpeg_state: */
+	 NETXEN_NIC_REG(0x13c),
+	 /* crb_status_ring_size */
+	 NETXEN_NIC_REG(0x140),
+
+	 },
+	/*
+	 * Instance 1,
+	 */
+	{
+	 /* rcv_desc_crb: */
+	 {
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x144),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x148),
+	   /* crb_globalrcv_ring: */
+	   NETXEN_NIC_REG(0x14c),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x150),
+
+	   },
+	  /* Jumbo frames */
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x154),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x158),
+	   /* crb_globalrcv_ring: */
+	   NETXEN_NIC_REG(0x15c),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x160),
+	   },
+	  /* LRO */
+	  {
+	   /* crb_rcv_producer_offset: */
+	   NETXEN_NIC_REG(0x164),
+	   /* crb_rcv_consumer_offset: */
+	   NETXEN_NIC_REG(0x168),
+	   /* crb_globalrcv_ring: */
+	   NETXEN_NIC_REG(0x16c),
+	   /* crb_rcv_ring_size */
+	   NETXEN_NIC_REG(0x170),
+	   }
+
+	  },
+	 /* crb_rcvstatus_ring: */
+	 NETXEN_NIC_REG(0x174),
+	 /* crb_rcv_status_producer: */
+	 NETXEN_NIC_REG(0x178),
+	 /* crb_rcv_status_consumer: */
+	 NETXEN_NIC_REG(0x17c),
+	 /* crb_rcvpeg_state: */
+	 NETXEN_NIC_REG(0x180),
+	 /* crb_status_ring_size */
+	 NETXEN_NIC_REG(0x184),
+	 },
+	/*
+	 * Instance 2,
+	 */
+	{
+	  {
+	    {
+	    /* crb_rcv_producer_offset: */
+	    NETXEN_NIC_REG(0x1d8),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x1dc),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x1f0),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x1f4),
+	    },
+	    /* Jumbo frames */
+	    {
+	    /* crb_rcv_producer_offset: */		    
+	    NETXEN_NIC_REG(0x1f8),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x1fc),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x200),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x204),
+	    },
+	    /* LRO */
+	    {
+	    /* crb_rcv_producer_offset: */
+	    NETXEN_NIC_REG(0x208),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x20c),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x210),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x214),
+	    }
+	  },
+	  /* crb_rcvstatus_ring: */
+	  NETXEN_NIC_REG(0x218),
+	  /* crb_rcv_status_producer: */
+	  NETXEN_NIC_REG(0x21c),
+	  /* crb_rcv_status_consumer: */
+	  NETXEN_NIC_REG(0x220),
+	  /* crb_rcvpeg_state: */
+	  NETXEN_NIC_REG(0x224),
+	  /* crb_status_ring_size */
+	  NETXEN_NIC_REG(0x228),
+	},
+	/*
+	 * Instance 3,
+	 */
+	{
+	  {
+	    {
+	    /* crb_rcv_producer_offset: */
+	    NETXEN_NIC_REG(0x22c),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x230),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x234),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x238),
+	    },
+	    /* Jumbo frames */
+	    {
+	    /* crb_rcv_producer_offset: */ 
+	    NETXEN_NIC_REG(0x23c),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x240),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x244),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x248),
+	    },
+	    /* LRO */
+	    {
+	    /* crb_rcv_producer_offset: */
+	    NETXEN_NIC_REG(0x24c),
+	    /* crb_rcv_consumer_offset: */
+	    NETXEN_NIC_REG(0x250),
+	    /* crb_gloablrcv_ring: */
+	    NETXEN_NIC_REG(0x254),
+	    /* crb_rcv_ring_size */
+	    NETXEN_NIC_REG(0x258),
+	    }
+	  },
+	  /* crb_rcvstatus_ring: */
+	  NETXEN_NIC_REG(0x25c),
+	  /* crb_rcv_status_producer: */
+	  NETXEN_NIC_REG(0x260),
+	  /* crb_rcv_status_consumer: */
+	  NETXEN_NIC_REG(0x264),
+	  /* crb_rcvpeg_state: */
+	  NETXEN_NIC_REG(0x268),
+	  /* crb_status_ring_size */
+	  NETXEN_NIC_REG(0x26c),
+	},
+};
+
+u64 ctx_addr_sig_regs[][3] = {
+	{NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
+	{NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
+	{NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
+	{NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
+};
+
+
 /*  PCI Windowing for DDR regions.  */
 
 #define ADDR_IN_RANGE(addr, low, high)	\
@@ -68,8 +285,7 @@ void netxen_free_hw_resources(struct net
 
 int netxen_nic_set_mac(struct net_device *netdev, void *p)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	struct sockaddr *addr = p;
 
 	if (netif_running(netdev))
@@ -82,7 +298,7 @@ int netxen_nic_set_mac(struct net_device
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
 	if (adapter->macaddr_set)
-		adapter->macaddr_set(port, addr->sa_data);
+		adapter->macaddr_set(adapter, addr->sa_data);
 
 	return 0;
 }
@@ -92,56 +308,19 @@ int netxen_nic_set_mac(struct net_device
  */
 void netxen_nic_set_multi(struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	struct dev_mc_list *mc_ptr;
-	__u32 netxen_mac_addr_cntl_data = 0;
 
 	mc_ptr = netdev->mc_list;
 	if (netdev->flags & IFF_PROMISC) {
 		if (adapter->set_promisc)
 			adapter->set_promisc(adapter,
-					     port->portnum,
 					     NETXEN_NIU_PROMISC_MODE);
 	} else {
-		if (adapter->unset_promisc &&
-		    adapter->ahw.boardcfg.board_type
-		    != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+		if (adapter->unset_promisc)
 			adapter->unset_promisc(adapter,
-					       port->portnum,
 					       NETXEN_NIU_NON_PROMISC_MODE);
 	}
-	if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
-		netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03);
-		netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data);
-		netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data);
-		netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data);
-		netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data);
-	} else {
-		netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
-		netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01);
-		netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02);
-		netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03);
-	}
-	writel(netxen_mac_addr_cntl_data,
-	       NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG));
-	if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
-		writel(netxen_mac_addr_cntl_data,
-		       NETXEN_CRB_NORMALIZE(adapter,
-					    NETXEN_MULTICAST_ADDR_HI_0));
-	} else {
-		writel(netxen_mac_addr_cntl_data,
-		       NETXEN_CRB_NORMALIZE(adapter,
-					    NETXEN_MULTICAST_ADDR_HI_1));
-	}
-	netxen_mac_addr_cntl_data = 0;
-	writel(netxen_mac_addr_cntl_data,
-	       NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR));
 }
 
 /*
@@ -150,8 +329,7 @@ void netxen_nic_set_multi(struct net_dev
  */
 int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE;
 
 	if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) {
@@ -161,7 +339,7 @@ int netxen_nic_change_mtu(struct net_dev
 	}
 
 	if (adapter->set_mtu)
-		adapter->set_mtu(port, mtu);
+		adapter->set_mtu(adapter, mtu);
 	netdev->mtu = mtu;
 
 	return 0;
@@ -178,9 +356,9 @@ int netxen_nic_hw_resources(struct netxe
 	void *addr;
 	int loops = 0, err = 0;
 	int ctx, ring;
-	u32 card_cmdring = 0;
 	struct netxen_recv_context *recv_ctx;
 	struct netxen_rcv_desc_ctx *rcv_desc;
+	int func_id = adapter->portnum;
 
 	DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE,
 		PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE));
@@ -189,11 +367,6 @@ int netxen_nic_hw_resources(struct netxe
 	DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE,
 		pci_base_offset(adapter, NETXEN_CAM_RAM_BASE));
 
-	/* Window 1 call */
-	card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING));
-
-	DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n",
-		card_cmdring);
 
 	for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
 		DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n");
@@ -227,7 +400,7 @@ int netxen_nic_hw_resources(struct netxe
 			    (dma_addr_t *) & adapter->ctx_desc_phys_addr,
 			    &adapter->ctx_desc_pdev);
 
-	printk("ctx_desc_phys_addr: 0x%llx\n",
+	printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n",
 	       (unsigned long long) adapter->ctx_desc_phys_addr);
 	if (addr == NULL) {
 		DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
@@ -236,6 +409,7 @@ int netxen_nic_hw_resources(struct netxe
 	}
 	memset(addr, 0, sizeof(struct netxen_ring_ctx));
 	adapter->ctx_desc = (struct netxen_ring_ctx *)addr;
+	adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum);
 	adapter->ctx_desc->cmd_consumer_offset =
 	    cpu_to_le64(adapter->ctx_desc_phys_addr +
 			sizeof(struct netxen_ring_ctx));
@@ -247,7 +421,7 @@ int netxen_nic_hw_resources(struct netxe
 			    adapter->max_tx_desc_count,
 			    (dma_addr_t *) & hw->cmd_desc_phys_addr,
 			    &adapter->ahw.cmd_desc_pdev);
-	printk("cmd_desc_phys_addr: 0x%llx\n",
+	printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n",
 	       (unsigned long long) hw->cmd_desc_phys_addr);
 
 	if (addr == NULL) {
@@ -306,11 +480,11 @@ int netxen_nic_hw_resources(struct netxe
 	/* Window = 1 */
 
 	writel(lower32(adapter->ctx_desc_phys_addr),
-	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO));
+	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id)));
 	writel(upper32(adapter->ctx_desc_phys_addr),
-	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI));
-	writel(NETXEN_CTX_SIGNATURE,
-	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG));
+	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id)));
+	writel(NETXEN_CTX_SIGNATURE | func_id,
+	       NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id)));
 	return err;
 }
 
@@ -337,10 +511,6 @@ void netxen_free_hw_resources(struct net
 				    adapter->ahw.cmd_desc_phys_addr);
 		adapter->ahw.cmd_desc_head = NULL;
 	}
-	/* Special handling: there are 2 ports on this board */
-	if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
-		adapter->ahw.max_ports = 2;
-	}
 
 	for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
 		recv_ctx = &adapter->recv_ctx[ctx];
@@ -371,22 +541,20 @@ void netxen_tso_check(struct netxen_adap
 		      struct cmd_desc_type0 *desc, struct sk_buff *skb)
 {
 	if (desc->mss) {
-		desc->total_hdr_length = sizeof(struct ethhdr) +
-		    ((skb->nh.iph)->ihl * sizeof(u32)) +
-		    ((skb->h.th)->doff * sizeof(u32));
+		desc->total_hdr_length = (sizeof(struct ethhdr) +
+					  ip_hdrlen(skb) + tcp_hdrlen(skb));
 		netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO);
 	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		if (skb->nh.iph->protocol == IPPROTO_TCP) {
+		if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
 			netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT);
-		} else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+		} else if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
 			netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT);
 		} else {
 			return;
 		}
 	}
-	adapter->stats.xmitcsummed++;
-	desc->tcp_hdr_offset = skb->h.raw - skb->data;
-	desc->ip_hdr_offset = skb->nh.raw - skb->data;
+	desc->tcp_hdr_offset = skb_transport_offset(skb);
+	desc->ip_hdr_offset = skb_network_offset(skb);
 }
 
 int netxen_is_flash_supported(struct netxen_adapter *adapter)
@@ -474,7 +642,30 @@ void netxen_nic_pci_change_crbwindow(str
 
 	if (adapter->curr_window == wndw)
 		return;
-
+	switch(adapter->ahw.pci_func) {
+		case 0:
+			offset = PCI_OFFSET_SECOND_RANGE(adapter,
+					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+			break;
+		case 1:
+			offset = PCI_OFFSET_SECOND_RANGE(adapter,
+					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1));
+			break;
+		case 2:
+			offset = PCI_OFFSET_SECOND_RANGE(adapter,
+					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2));
+			break;
+		case 3:
+			offset = PCI_OFFSET_SECOND_RANGE(adapter,
+					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3));
+			break;
+		default:
+			printk(KERN_INFO "Changing the window for PCI function"
+					"%d\n",	adapter->ahw.pci_func);
+			offset = PCI_OFFSET_SECOND_RANGE(adapter,
+					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+			break;
+	}
 	/*
 	 * Move the CRB window.
 	 * We need to write to the "direct access" region of PCI
@@ -483,9 +674,6 @@ void netxen_nic_pci_change_crbwindow(str
 	 * register address is received by PCI. The direct region bypasses
 	 * the CRB bus.
 	 */
-	offset =
-	    PCI_OFFSET_SECOND_RANGE(adapter,
-				    NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
 
 	if (wndw & 0x1)
 		wndw = NETXEN_WINDOW_ONE;
@@ -503,7 +691,10 @@ void netxen_nic_pci_change_crbwindow(str
 		count++;
 	}
 
-	adapter->curr_window = wndw;
+	if (wndw == NETXEN_WINDOW_ONE)
+		adapter->curr_window = 1;
+	else
+		adapter->curr_window = 0;
 }
 
 void netxen_load_firmware(struct netxen_adapter *adapter)
@@ -748,6 +939,17 @@ netxen_nic_pci_set_window(struct netxen_
 	return addr;
 }
 
+int
+netxen_nic_erase_pxe(struct netxen_adapter *adapter)
+{
+	if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) {
+		printk(KERN_ERR "%s: erase pxe failed\n", 
+			netxen_nic_driver_name);
+		return -1;
+	}
+	return 0;
+}
+
 int netxen_nic_get_board_info(struct netxen_adapter *adapter)
 {
 	int rv = 0;
@@ -809,43 +1011,29 @@ int netxen_nic_get_board_info(struct net
 
 /* NIU access sections */
 
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
 {
-	struct netxen_adapter *adapter = port->adapter;
 	netxen_nic_write_w0(adapter,
-			    NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum),
-			    new_mtu);
+			NETXEN_NIU_GB_MAX_FRAME_SIZE(
+				physical_port[adapter->portnum]), new_mtu);
 	return 0;
 }
 
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
 {
-	struct netxen_adapter *adapter = port->adapter;
 	new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
-	if (port->portnum == 0)
-	    netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu);
-	else if (port->portnum == 1)
-	    netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu);
+	if (physical_port[adapter->portnum] == 0)
+		netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, 
+				new_mtu);
+	else 
+		netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE,
+				new_mtu);
 	return 0;
 }
 
 void netxen_nic_init_niu_gb(struct netxen_adapter *adapter)
 {
-	int portno;
-	for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++)
-		netxen_niu_gbe_init_port(adapter, portno);
-}
-
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter)
-{
-	int port_nr;
-	struct netxen_port *port;
-
-	for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) {
-		port = adapter->port[port_nr];
-		if (adapter->stop_port)
-			adapter->stop_port(adapter, port->portnum);
-	}
+	netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]);
 }
 
 void
@@ -864,9 +1052,8 @@ netxen_crb_writelit_adapter(struct netxe
 	}
 }
 
-void netxen_nic_set_link_parameters(struct netxen_port *port)
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
 {
-	struct netxen_adapter *adapter = port->adapter;
 	__u32 status;
 	__u32 autoneg;
 	__u32 mode;
@@ -875,47 +1062,47 @@ void netxen_nic_set_link_parameters(stru
 	if (netxen_get_niu_enable_ge(mode)) {	/* Gb 10/100/1000 Mbps mode */
 		if (adapter->phy_read
 		    && adapter->
-		    phy_read(adapter, port->portnum,
+		    phy_read(adapter,
 			     NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 			     &status) == 0) {
 			if (netxen_get_phy_link(status)) {
 				switch (netxen_get_phy_speed(status)) {
 				case 0:
-					port->link_speed = SPEED_10;
+					adapter->link_speed = SPEED_10;
 					break;
 				case 1:
-					port->link_speed = SPEED_100;
+					adapter->link_speed = SPEED_100;
 					break;
 				case 2:
-					port->link_speed = SPEED_1000;
+					adapter->link_speed = SPEED_1000;
 					break;
 				default:
-					port->link_speed = -1;
+					adapter->link_speed = -1;
 					break;
 				}
 				switch (netxen_get_phy_duplex(status)) {
 				case 0:
-					port->link_duplex = DUPLEX_HALF;
+					adapter->link_duplex = DUPLEX_HALF;
 					break;
 				case 1:
-					port->link_duplex = DUPLEX_FULL;
+					adapter->link_duplex = DUPLEX_FULL;
 					break;
 				default:
-					port->link_duplex = -1;
+					adapter->link_duplex = -1;
 					break;
 				}
 				if (adapter->phy_read
 				    && adapter->
-				    phy_read(adapter, port->portnum,
+				    phy_read(adapter,
 					     NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
 					     &autoneg) != 0)
-					port->link_autoneg = autoneg;
+					adapter->link_autoneg = autoneg;
 			} else
 				goto link_down;
 		} else {
 		      link_down:
-			port->link_speed = -1;
-			port->link_duplex = -1;
+			adapter->link_speed = -1;
+			adapter->link_duplex = -1;
 		}
 	}
 }
@@ -929,7 +1116,7 @@ void netxen_nic_flash_print(struct netxe
 	char brd_name[NETXEN_MAX_SHORT_NAME];
 	struct netxen_new_user_info user_info;
 	int i, addr = USER_START;
-	u32 *ptr32;
+	__le32 *ptr32;
 
 	struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
 	if (board_info->magic != NETXEN_BDINFO_MAGIC) {
@@ -955,7 +1142,6 @@ void netxen_nic_flash_print(struct netxe
 				       netxen_nic_driver_name);
 				return;
 			}
-			*ptr32 = le32_to_cpu(*ptr32);
 			ptr32++;
 			addr += sizeof(u32);
 		}
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index ab1112e..245bf13 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -6,12 +6,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.
- *                            
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *                                   
+ *
  * You 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,
@@ -87,7 +87,7 @@ #define NETXEN_NIC_LOCKED_READ_REG(X, Y)
 	*(u32 *)Y = readl((void __iomem*) addr);
 
 struct netxen_port;
-void netxen_nic_set_link_parameters(struct netxen_port *port);
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
 void netxen_nic_flash_print(struct netxen_adapter *adapter);
 int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off,
 			   void *data, int len);
@@ -220,6 +220,69 @@ #define netxen_get_gb_mii_mgmt_scanning(
 		_netxen_crb_get_bit(config_word, 1)
 #define netxen_get_gb_mii_mgmt_notvalid(config_word)	\
 		_netxen_crb_get_bit(config_word, 2)
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define netxen_xg_set_xg0_mask(config_word)    \
+	((config_word) |= 1 << 0)
+#define netxen_xg_set_xg1_mask(config_word)    \
+	((config_word) |= 1 << 3)
+		
+#define netxen_xg_get_xg0_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 0)
+#define netxen_xg_get_xg1_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 3)
+
+#define netxen_xg_unset_xg0_mask(config_word)  \
+	((config_word) &= ~(1 << 0))
+#define netxen_xg_unset_xg1_mask(config_word)  \
+	((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ *      Bit 0       : xg0_mask => 1:disable tx pause frames
+ *      Bit 1       : xg0_request => 1:request single pause frame
+ *      Bit 2       : xg0_on_off => 1:request is pause on, 0:off
+ *      Bit 3       : xg1_mask => 1:disable tx pause frames
+ *      Bit 4       : xg1_request => 1:request single pause frame
+ *      Bit 5       : xg1_on_off => 1:request is pause on, 0:off
+ */
+#define netxen_gb_set_gb0_mask(config_word)    \
+	((config_word) |= 1 << 0)
+#define netxen_gb_set_gb1_mask(config_word)    \
+	((config_word) |= 1 << 2)
+#define netxen_gb_set_gb2_mask(config_word)    \
+	((config_word) |= 1 << 4)
+#define netxen_gb_set_gb3_mask(config_word)    \
+	((config_word) |= 1 << 6)
+
+#define netxen_gb_get_gb0_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 0)
+#define netxen_gb_get_gb1_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 2)
+#define netxen_gb_get_gb2_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 4)
+#define netxen_gb_get_gb3_mask(config_word)    \
+	_netxen_crb_get_bit((config_word), 6)
+	
+#define netxen_gb_unset_gb0_mask(config_word)  \
+	((config_word) &= ~(1 << 0))
+#define netxen_gb_unset_gb1_mask(config_word)  \
+	((config_word) &= ~(1 << 2))
+#define netxen_gb_unset_gb2_mask(config_word)  \
+	((config_word) &= ~(1 << 4))
+#define netxen_gb_unset_gb3_mask(config_word)  \
+	((config_word) &= ~(1 << 6))
+
 
 /*
  * PHY-Specific MII control/status registers.
@@ -452,21 +515,21 @@ #define netxen_nic_mcr_set_enable_pool(c
 		((config) |= (((val) & 0x0f) << 28))
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
 				    netxen_niu_prom_mode_t mode);
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
-				       int port, netxen_niu_prom_mode_t mode);
+				       netxen_niu_prom_mode_t mode);
 
 /* get/set the MAC address for a given MAC */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
 			   netxen_ethernet_macaddr_t * addr);
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
 			   netxen_ethernet_macaddr_t addr);
 
 /* XG versons */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
 			      netxen_ethernet_macaddr_t * addr);
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
 			      netxen_ethernet_macaddr_t addr);
 
 /* Generic enable for GbE ports. Will detect the speed of the link. */
@@ -475,8 +538,8 @@ int netxen_niu_gbe_init_port(struct netx
 int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port);
 
 /* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter);
 
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter);
 
 #endif				/* __NETXEN_NIC_HW_H_ */
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index eff965d..cf0e96a 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_a
 		return err;
 	}
 	/* Window 1 call */
-	writel(MPORT_SINGLE_FUNCTION_MODE,
+	writel(MPORT_MULTI_FUNCTION_MODE,
 	       NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE));
 	writel(PHAN_INITIALIZE_ACK,
 	       NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
@@ -226,7 +226,6 @@ void netxen_initialize_adapter_ops(struc
 		adapter->unset_promisc = netxen_niu_set_promiscuous_mode;
 		adapter->phy_read = netxen_niu_gbe_phy_read;
 		adapter->phy_write = netxen_niu_gbe_phy_write;
-		adapter->init_port = netxen_niu_gbe_init_port;
 		adapter->init_niu = netxen_nic_init_niu_gb;
 		adapter->stop_port = netxen_niu_disable_gbe_port;
 		break;
@@ -277,8 +276,8 @@ u32 netxen_decode_crb_addr(u32 addr)
 		return (pci_base + offset);
 }
 
-static long rom_max_timeout = 10000;
-static long rom_lock_timeout = 1000000;
+static long rom_max_timeout = 100;
+static long rom_lock_timeout = 10000;
 static long rom_write_timeout = 700;
 
 static inline int rom_lock(struct netxen_adapter *adapter)
@@ -438,9 +437,9 @@ do_rom_fast_read_words(struct netxen_ada
 
 	for (addridx = addr; addridx < (addr + size); addridx += 4) {
 		ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
-		*(int *)bytes = cpu_to_le32(*(int *)bytes);
 		if (ret != 0)
 			break;
+		*(int *)bytes = cpu_to_le32(*(int *)bytes);
 		bytes += 4;
 	}
 
@@ -499,7 +498,6 @@ static inline int do_rom_fast_write_word
 		int data;
 
 		data = le32_to_cpu((*(u32*)bytes));
-
 		ret = do_rom_fast_write(adapter, addridx, data);
 		if (ret < 0)
 			return ret;
@@ -953,7 +951,8 @@ void netxen_phantom_init(struct netxen_a
 
 	if (!pegtune_val) {
 		val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-		while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
+		while (val != PHAN_INITIALIZE_COMPLETE && 
+			val != PHAN_INITIALIZE_ACK && loops < 200000) {
 			udelay(100);
 			schedule();
 			val =
@@ -990,9 +989,7 @@ int netxen_nic_rx_has_work(struct netxen
 
 static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
 {
-	int port_num;
-	struct netxen_port *port;
-	struct net_device *netdev;
+	struct net_device *netdev = adapter->netdev;
 	uint32_t temp, temp_state, temp_val;
 	int rv = 0;
 
@@ -1006,14 +1003,9 @@ static inline int netxen_nic_check_temp(
 		       "%s: Device temperature %d degrees C exceeds"
 		       " maximum allowed. Hardware has been shut down.\n",
 		       netxen_nic_driver_name, temp_val);
-		for (port_num = 0; port_num < adapter->ahw.max_ports;
-		     port_num++) {
-			port = adapter->port[port_num];
-			netdev = port->netdev;
 
-			netif_carrier_off(netdev);
-			netif_stop_queue(netdev);
-		}
+		netif_carrier_off(netdev);
+		netif_stop_queue(netdev);
 		rv = 1;
 	} else if (temp_state == NX_TEMP_WARN) {
 		if (adapter->temp == NX_TEMP_NORMAL) {
@@ -1037,29 +1029,23 @@ static inline int netxen_nic_check_temp(
 
 void netxen_watchdog_task(struct work_struct *work)
 {
-	int port_num;
-	struct netxen_port *port;
 	struct net_device *netdev;
 	struct netxen_adapter *adapter =
 		container_of(work, struct netxen_adapter, watchdog_task);
 
-	if (netxen_nic_check_temp(adapter))
+	if ((adapter->portnum  == 0) && netxen_nic_check_temp(adapter))
 		return;
 
-	for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
-		port = adapter->port[port_num];
-		netdev = port->netdev;
-
-		if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
-			printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
-			       netxen_nic_driver_name, port_num, netdev->name);
-			netif_carrier_on(netdev);
-		}
-
-		if (netif_queue_stopped(netdev))
-			netif_wake_queue(netdev);
+	netdev = adapter->netdev;
+	if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
+		printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
+		       netxen_nic_driver_name, adapter->portnum, netdev->name);
+		netif_carrier_on(netdev);
 	}
 
+	if (netif_queue_stopped(netdev))
+		netif_wake_queue(netdev);
+
 	if (adapter->handle_phy_intr)
 		adapter->handle_phy_intr(adapter);
 	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -1074,9 +1060,8 @@ void
 netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
 		   struct status_desc *desc)
 {
-	struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)];
-	struct pci_dev *pdev = port->pdev;
-	struct net_device *netdev = port->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct net_device *netdev = adapter->netdev;
 	int index = netxen_get_sts_refhandle(desc);
 	struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
 	struct netxen_rx_buffer *buffer;
@@ -1126,10 +1111,9 @@ netxen_process_rcv(struct netxen_adapter
 	skb = (struct sk_buff *)buffer->skb;
 
 	if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
-		port->stats.csummed++;
+		adapter->stats.csummed++;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
-	skb->dev = netdev;
 	if (desc_ctx == RCV_DESC_LRO_CTXID) {
 		/* True length was only available on the last pkt */
 		skb_put(skb, buffer->lro_length);
@@ -1147,27 +1131,27 @@ netxen_process_rcv(struct netxen_adapter
 	 */
 	switch (ret) {
 	case NET_RX_SUCCESS:
-		port->stats.uphappy++;
+		adapter->stats.uphappy++;
 		break;
 
 	case NET_RX_CN_LOW:
-		port->stats.uplcong++;
+		adapter->stats.uplcong++;
 		break;
 
 	case NET_RX_CN_MOD:
-		port->stats.upmcong++;
+		adapter->stats.upmcong++;
 		break;
 
 	case NET_RX_CN_HIGH:
-		port->stats.uphcong++;
+		adapter->stats.uphcong++;
 		break;
 
 	case NET_RX_DROP:
-		port->stats.updropped++;
+		adapter->stats.updropped++;
 		break;
 
 	default:
-		port->stats.updunno++;
+		adapter->stats.updunno++;
 		break;
 	}
 
@@ -1179,14 +1163,13 @@ netxen_process_rcv(struct netxen_adapter
 	/*
 	 * We just consumed one buffer so post a buffer.
 	 */
-	adapter->stats.post_called++;
 	buffer->skb = NULL;
 	buffer->state = NETXEN_BUFFER_FREE;
 	buffer->lro_current_frags = 0;
 	buffer->lro_expected_frags = 0;
 
-	port->stats.no_rcv++;
-	port->stats.rxbytes += length;
+	adapter->stats.no_rcv++;
+	adapter->stats.rxbytes += length;
 }
 
 /* Process Receive status ring */
@@ -1227,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxe
 
 	/* update the consumer index in phantom */
 	if (count) {
-		adapter->stats.process_rcv++;
 		recv_ctx->status_rx_consumer = consumer;
 		recv_ctx->status_rx_producer = producer;
 
@@ -1250,13 +1232,10 @@ int netxen_process_cmd_ring(unsigned lon
 	int count1 = 0;
 	int count2 = 0;
 	struct netxen_cmd_buffer *buffer;
-	struct netxen_port *port;	/* port #1 */
-	struct netxen_port *nport;
 	struct pci_dev *pdev;
 	struct netxen_skb_frag *frag;
 	u32 i;
 	struct sk_buff *skb = NULL;
-	int p;
 	int done;
 
 	spin_lock(&adapter->tx_lock);
@@ -1277,7 +1256,6 @@ int netxen_process_cmd_ring(unsigned lon
 	}
 
 	adapter->proc_cmd_buf_counter++;
-	adapter->stats.process_xmit++;
 	/*
 	 * Not needed - does not seem to be used anywhere.
 	 * adapter->cmd_consumer = consumer;
@@ -1286,8 +1264,7 @@ int netxen_process_cmd_ring(unsigned lon
 
 	while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) {
 		buffer = &adapter->cmd_buf_arr[last_consumer];
-		port = adapter->port[buffer->port];
-		pdev = port->pdev;
+		pdev = adapter->pdev;
 		frag = &buffer->frag_array[0];
 		skb = buffer->skb;
 		if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) {
@@ -1300,24 +1277,23 @@ int netxen_process_cmd_ring(unsigned lon
 					       PCI_DMA_TODEVICE);
 			}
 
-			port->stats.skbfreed++;
+			adapter->stats.skbfreed++;
 			dev_kfree_skb_any(skb);
 			skb = NULL;
 		} else if (adapter->proc_cmd_buf_counter == 1) {
-			port->stats.txnullskb++;
+			adapter->stats.txnullskb++;
 		}
-		if (unlikely(netif_queue_stopped(port->netdev)
-			     && netif_carrier_ok(port->netdev))
-		    && ((jiffies - port->netdev->trans_start) >
-			port->netdev->watchdog_timeo)) {
-			SCHEDULE_WORK(&port->tx_timeout_task);
+		if (unlikely(netif_queue_stopped(adapter->netdev)
+			     && netif_carrier_ok(adapter->netdev))
+		    && ((jiffies - adapter->netdev->trans_start) >
+			adapter->netdev->watchdog_timeo)) {
+			SCHEDULE_WORK(&adapter->tx_timeout_task);
 		}
 
 		last_consumer = get_next_index(last_consumer,
 					       adapter->max_tx_desc_count);
 		count1++;
 	}
-	adapter->stats.noxmitdone += count1;
 
 	count2 = 0;
 	spin_lock(&adapter->tx_lock);
@@ -1337,13 +1313,10 @@ int netxen_process_cmd_ring(unsigned lon
 		}
 	}
 	if (count1 || count2) {
-		for (p = 0; p < adapter->ahw.max_ports; p++) {
-			nport = adapter->port[p];
-			if (netif_queue_stopped(nport->netdev)
-			    && (nport->flags & NETXEN_NETDEV_STATUS)) {
-				netif_wake_queue(nport->netdev);
-				nport->flags &= ~NETXEN_NETDEV_STATUS;
-			}
+		if (netif_queue_stopped(adapter->netdev)
+		    && (adapter->flags & NETXEN_NETDEV_STATUS)) {
+			netif_wake_queue(adapter->netdev);
+			adapter->flags &= ~NETXEN_NETDEV_STATUS;
 		}
 	}
 	/*
@@ -1389,7 +1362,6 @@ void netxen_post_rx_buffers(struct netxe
 	netxen_ctx_msg msg = 0;
 	dma_addr_t dma;
 
-	adapter->stats.post_called++;
 	rcv_desc = &recv_ctx->rcv_desc[ringid];
 
 	producer = rcv_desc->producer;
@@ -1442,8 +1414,6 @@ #endif
 	if (count) {
 		rcv_desc->begin_alloc = index;
 		rcv_desc->rcv_pending += count;
-		adapter->stats.lastposted = count;
-		adapter->stats.posted += count;
 		rcv_desc->producer = producer;
 		if (rcv_desc->rcv_free >= 32) {
 			rcv_desc->rcv_free = 0;
@@ -1451,7 +1421,8 @@ #endif
 			writel((producer - 1) &
 			       (rcv_desc->max_rx_desc_count - 1),
 			       NETXEN_CRB_NORMALIZE(adapter,
-						    recv_crb_registers[0].
+						    recv_crb_registers[
+						    adapter->portnum].
 						    rcv_desc_crb[ringid].
 						    crb_rcv_producer_offset));
 			/*
@@ -1464,7 +1435,7 @@ #endif
 					     ((producer -
 					       1) & (rcv_desc->
 						     max_rx_desc_count - 1)));
-			netxen_set_msg_ctxid(msg, 0);
+			netxen_set_msg_ctxid(msg, adapter->portnum);
 			netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
 			writel(msg,
 			       DB_NORMALIZE(adapter,
@@ -1486,7 +1457,6 @@ void netxen_post_rx_buffers_nodb(struct 
 	int count = 0;
 	int index = 0;
 
-	adapter->stats.post_called++;
 	rcv_desc = &recv_ctx->rcv_desc[ringid];
 
 	producer = rcv_desc->producer;
@@ -1533,8 +1503,6 @@ void netxen_post_rx_buffers_nodb(struct 
 	if (count) {
 		rcv_desc->begin_alloc = index;
 		rcv_desc->rcv_pending += count;
-		adapter->stats.lastposted = count;
-		adapter->stats.posted += count;
 		rcv_desc->producer = producer;
 		if (rcv_desc->rcv_free >= 32) {
 			rcv_desc->rcv_free = 0;
@@ -1542,7 +1510,8 @@ void netxen_post_rx_buffers_nodb(struct 
 			writel((producer - 1) &
 			       (rcv_desc->max_rx_desc_count - 1),
 			       NETXEN_CRB_NORMALIZE(adapter,
-						    recv_crb_registers[0].
+						    recv_crb_registers[
+						    adapter->portnum].
 						    rcv_desc_crb[ringid].
 						    crb_rcv_producer_offset));
 			wmb();
@@ -1563,13 +1532,7 @@ int netxen_nic_tx_has_work(struct netxen
 
 void netxen_nic_clear_stats(struct netxen_adapter *adapter)
 {
-	struct netxen_port *port;
-	int port_num;
-
 	memset(&adapter->stats, 0, sizeof(adapter->stats));
-	for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
-		port = adapter->port[port_num];
-		memset(&port->stats, 0, sizeof(port->stats));
-	}
+	return;
 }
 
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index be366e4..b213b06 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -6,12 +6,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.
- *                            
+ *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *                                   
+ *
  * You 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,
@@ -40,35 +40,35 @@ #include "netxen_nic_phan_reg.h"
  */
 struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct net_device_stats *stats = &port->net_stats;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
+	struct net_device_stats *stats = &adapter->net_stats;
 
 	memset(stats, 0, sizeof(*stats));
 
 	/* total packets received   */
-	stats->rx_packets = port->stats.no_rcv;
+	stats->rx_packets = adapter->stats.no_rcv;
 	/* total packets transmitted    */
-	stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
+	stats->tx_packets = adapter->stats.xmitedframes + 
+		adapter->stats.xmitfinished;
 	/* total bytes received     */
-	stats->rx_bytes = port->stats.rxbytes;
+	stats->rx_bytes = adapter->stats.rxbytes;
 	/* total bytes transmitted  */
-	stats->tx_bytes = port->stats.txbytes;
+	stats->tx_bytes = adapter->stats.txbytes;
 	/* bad packets received     */
-	stats->rx_errors = port->stats.rcvdbadskb;
+	stats->rx_errors = adapter->stats.rcvdbadskb;
 	/* packet transmit problems */
-	stats->tx_errors = port->stats.nocmddescriptor;
+	stats->tx_errors = adapter->stats.nocmddescriptor;
 	/* no space in linux buffers    */
-	stats->rx_dropped = port->stats.updropped;
+	stats->rx_dropped = adapter->stats.updropped;
 	/* no space available in linux  */
-	stats->tx_dropped = port->stats.txdropped;
+	stats->tx_dropped = adapter->stats.txdropped;
 
 	return stats;
 }
 
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
-				 u32 link)
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
 {
-	struct net_device *netdev = (adapter->port[portno])->netdev;
+	struct net_device *netdev = adapter->netdev;
 
 	if (link)
 		netif_carrier_on(netdev);
@@ -76,15 +76,13 @@ void netxen_indicate_link_status(struct 
 		netif_carrier_off(netdev);
 }
 
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
-			    u32 enable)
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 {
 	__u32 int_src;
-	struct netxen_port *port;
 
 	/*  This should clear the interrupt source */
 	if (adapter->phy_read)
-		adapter->phy_read(adapter, portno,
+		adapter->phy_read(adapter, 
 				  NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
 				  &int_src);
 	if (int_src == 0) {
@@ -92,9 +90,7 @@ void netxen_handle_port_int(struct netxe
 		return;
 	}
 	if (adapter->disable_phy_interrupts)
-		adapter->disable_phy_interrupts(adapter, portno);
-
-	port = adapter->port[portno];
+		adapter->disable_phy_interrupts(adapter);
 
 	if (netxen_get_phy_int_jabber(int_src))
 		DPRINTK(INFO, "Jabber interrupt \n");
@@ -115,64 +111,57 @@ void netxen_handle_port_int(struct netxe
 		DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
 
 		if (adapter->phy_read
-		    && adapter->phy_read(adapter, portno,
+		    && adapter->phy_read(adapter, 
 					 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 					 &status) == 0) {
 			if (netxen_get_phy_int_link_status_changed(int_src)) {
 				if (netxen_get_phy_link(status)) {
-					netxen_niu_gbe_init_port(adapter,
-								 portno);
-					printk("%s: %s Link UP\n",
+					printk(KERN_INFO "%s: %s Link UP\n",
 					       netxen_nic_driver_name,
-					       port->netdev->name);
+					       adapter->netdev->name);
 
 				} else {
-					printk("%s: %s Link DOWN\n",
+					printk(KERN_INFO "%s: %s Link DOWN\n",
 					       netxen_nic_driver_name,
-					       port->netdev->name);
+					       adapter->netdev->name);
 				}
-				netxen_indicate_link_status(adapter, portno,
+				netxen_indicate_link_status(adapter, 
 							    netxen_get_phy_link
 							    (status));
 			}
 		}
 	}
 	if (adapter->enable_phy_interrupts)
-		adapter->enable_phy_interrupts(adapter, portno);
+		adapter->enable_phy_interrupts(adapter);
 }
 
 void netxen_nic_isr_other(struct netxen_adapter *adapter)
 {
-	u32 portno;
+	int portno = adapter->portnum;
 	u32 val, linkup, qg_linksup;
 
 	/* verify the offset */
 	val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+	val = val >> physical_port[adapter->portnum];
 	if (val == adapter->ahw.qg_linksup)
 		return;
 
 	qg_linksup = adapter->ahw.qg_linksup;
 	adapter->ahw.qg_linksup = val;
 	DPRINTK(INFO, "link update 0x%08x\n", val);
-	for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
-		linkup = val & 1;
-		if (linkup != (qg_linksup & 1)) {
-			printk(KERN_INFO "%s: %s PORT %d link %s\n",
-			       adapter->port[portno]->netdev->name,
-			       netxen_nic_driver_name, portno,
-			       ((linkup == 0) ? "down" : "up"));
-			netxen_indicate_link_status(adapter, portno, linkup);
-			if (linkup)
-				netxen_nic_set_link_parameters(adapter->
-							       port[portno]);
 
-		}
-		val = val >> 1;
-		qg_linksup = qg_linksup >> 1;
-	}
+	linkup = val & 1;
 
-	adapter->stats.otherints++;
+	if (linkup != (qg_linksup & 1)) {
+		printk(KERN_INFO "%s: %s PORT %d link %s\n",
+		       adapter->netdev->name,
+		       netxen_nic_driver_name, portno,
+		       ((linkup == 0) ? "down" : "up"));
+		netxen_indicate_link_status(adapter, linkup);
+		if (linkup)
+			netxen_nic_set_link_parameters(adapter);
 
+	}
 }
 
 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
@@ -182,26 +171,28 @@ void netxen_nic_gbe_handle_phy_intr(stru
 
 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
 {
-	struct net_device *netdev = adapter->port[0]->netdev;
-	u32 val;
+	struct net_device *netdev = adapter->netdev;
+	u32 val, val1;
 
 	/* WINDOW = 1 */
 	val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+	val >>= (physical_port[adapter->portnum] * 8);
+	val1 = val & 0xff;
 
-	if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
+	if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
 		printk(KERN_INFO "%s: %s NIC Link is down\n",
 		       netxen_nic_driver_name, netdev->name);
 		adapter->ahw.xg_linkup = 0;
 		/* read twice to clear sticky bits */
 		/* WINDOW = 0 */
-		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
-		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
+		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
+		netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
 
 		if ((val & 0xffb) != 0xffb) {
 			printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
-			       netxen_nic_driver_name, val);
+			       netxen_nic_driver_name, val1);
 		}
-	} else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
+	} else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
 		printk(KERN_INFO "%s: %s NIC Link is up\n",
 		       netxen_nic_driver_name, netdev->name);
 		adapter->ahw.xg_linkup = 1;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 7d2525e..4e32bb6 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -36,11 +36,11 @@ #include <linux/highmem.h>
 #include "netxen_nic_hw.h"
 
 #include "netxen_nic.h"
-#define DEFINE_GLOBAL_RECV_CRB
 #include "netxen_nic_phan_reg.h"
 
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
+#include <net/ip.h>
 
 MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
 MODULE_LICENSE("GPL");
@@ -76,6 +76,8 @@ static void netxen_nic_poll_controller(s
 #endif
 static irqreturn_t netxen_intr(int irq, void *data);
 
+int physical_port[] = {0, 1, 2, 3};
+
 /*  PCI Device ID Table  */
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
 	{PCI_DEVICE(0x4040, 0x0001)},
@@ -93,6 +95,67 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl)
 struct workqueue_struct *netxen_workq;
 static void netxen_watchdog(unsigned long);
 
+static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+							uint32_t crb_producer)
+{
+	switch (adapter->portnum) {
+		case 0:
+			writel(crb_producer, NETXEN_CRB_NORMALIZE
+					(adapter, CRB_CMD_PRODUCER_OFFSET));
+			return;
+		case 1:
+			writel(crb_producer, NETXEN_CRB_NORMALIZE
+					(adapter, CRB_CMD_PRODUCER_OFFSET_1));
+			return;
+		case 2:
+			writel(crb_producer, NETXEN_CRB_NORMALIZE
+					(adapter, CRB_CMD_PRODUCER_OFFSET_2));
+			return;
+		case 3:
+			writel(crb_producer, NETXEN_CRB_NORMALIZE
+					(adapter, CRB_CMD_PRODUCER_OFFSET_3));
+			return;
+		default:
+			printk(KERN_WARNING "We tried to update "
+					"CRB_CMD_PRODUCER_OFFSET for invalid "
+					"PCI function id %d\n",
+					adapter->portnum);
+			return;
+	}
+}
+
+static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+							u32 crb_consumer)
+{
+	switch (adapter->portnum) {
+		case 0:
+			writel(crb_consumer, NETXEN_CRB_NORMALIZE
+				(adapter, CRB_CMD_CONSUMER_OFFSET));
+			return;
+		case 1:
+			writel(crb_consumer, NETXEN_CRB_NORMALIZE
+				(adapter, CRB_CMD_CONSUMER_OFFSET_1));
+			return;
+		case 2:
+			writel(crb_consumer, NETXEN_CRB_NORMALIZE
+				(adapter, CRB_CMD_CONSUMER_OFFSET_2));
+			return;
+		case 3:
+			writel(crb_consumer, NETXEN_CRB_NORMALIZE
+				(adapter, CRB_CMD_CONSUMER_OFFSET_3));
+			return;
+		default:
+			printk(KERN_WARNING "We tried to update "
+					"CRB_CMD_PRODUCER_OFFSET for invalid "
+					"PCI function id %d\n",
+					adapter->portnum);
+			return;
+	}
+}
+
+#define	ADAPTER_LIST_SIZE 12
+int netxen_cards_found;
+
 /*
  * netxen_nic_probe()
  *
@@ -110,26 +173,30 @@ netxen_nic_probe(struct pci_dev *pdev, c
 {
 	struct net_device *netdev = NULL;
 	struct netxen_adapter *adapter = NULL;
-	struct netxen_port *port = NULL;
 	void __iomem *mem_ptr0 = NULL;
 	void __iomem *mem_ptr1 = NULL;
 	void __iomem *mem_ptr2 = NULL;
+	unsigned long first_page_group_end;
+	unsigned long first_page_group_start;
+
 
 	u8 __iomem *db_ptr = NULL;
 	unsigned long mem_base, mem_len, db_base, db_len;
-	int pci_using_dac, i, err;
+	int pci_using_dac, i = 0, err;
 	int ring;
 	struct netxen_recv_context *recv_ctx = NULL;
 	struct netxen_rcv_desc_ctx *rcv_desc = NULL;
 	struct netxen_cmd_buffer *cmd_buf_arr = NULL;
 	u64 mac_addr[FLASH_NUM_PORTS + 1];
 	int valid_mac = 0;
+	u32 val;
+	int pci_func_id = PCI_FUNC(pdev->devfn);
 
 	printk(KERN_INFO "%s \n", netxen_nic_driver_string);
-	/* In current scheme, we use only PCI function 0 */
-	if (PCI_FUNC(pdev->devfn) != 0) {
-		DPRINTK(ERR, "NetXen function %d will not be enabled.\n",
-			PCI_FUNC(pdev->devfn));
+
+	if (pdev->class != 0x020000) {
+		printk(KERN_ERR"NetXen function %d, class %x will not"
+				"be enabled.\n",pci_func_id, pdev->class);
 		return -ENODEV;
 	}
 	if ((err = pci_enable_device(pdev)))
@@ -156,18 +223,52 @@ netxen_nic_probe(struct pci_dev *pdev, c
 		pci_using_dac = 0;
 	}
 
+
+	netdev = alloc_etherdev(sizeof(struct netxen_adapter));
+	if(!netdev) {
+		printk(KERN_ERR"%s: Failed to allocate memory for the "
+				"device block.Check system memory resource"
+				" usage.\n", netxen_nic_driver_name);
+		goto err_out_free_res;
+	}
+
+	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	adapter = netdev->priv;
+	memset(adapter, 0 , sizeof(struct netxen_adapter));
+
+	adapter->ahw.pdev = pdev;
+	adapter->ahw.pci_func  = pci_func_id;
+	spin_lock_init(&adapter->tx_lock);
+	spin_lock_init(&adapter->lock);
+
 	/* remap phys address */
 	mem_base = pci_resource_start(pdev, 0);	/* 0 is for BAR 0 */
 	mem_len = pci_resource_len(pdev, 0);
 
 	/* 128 Meg of memory */
-	mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
-	mem_ptr1 =
-	    ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE);
-	mem_ptr2 =
-	    ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+	if (mem_len == NETXEN_PCI_128MB_SIZE) {
+		mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
+		mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,
+				SECOND_PAGE_GROUP_SIZE);
+		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
+				THIRD_PAGE_GROUP_SIZE);
+		first_page_group_start = FIRST_PAGE_GROUP_START;
+		first_page_group_end   = FIRST_PAGE_GROUP_END;
+	} else if (mem_len == NETXEN_PCI_32MB_SIZE) {
+		mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
+		mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
+			SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+		first_page_group_start = 0;
+		first_page_group_end   = 0;
+	} else {
+		err = -EIO; 
+		goto err_out_free_netdev;
+	}
 
-	if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+	if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
+			(mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
 		DPRINTK(ERR,
 			"Cannot remap adapter memory aborting.:"
 			"0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -197,30 +298,87 @@ netxen_nic_probe(struct pci_dev *pdev, c
 	}
 	DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
 
-/*
- *      Allocate a adapter structure which will manage all the initialization
- *      as well as the common resources for all ports...
- *      all the ports will have pointer to this adapter as well as Adapter
- *      will have pointers of all the ports structures.
- */
+	adapter->ahw.pci_base0 = mem_ptr0;
+	adapter->ahw.first_page_group_start = first_page_group_start;
+	adapter->ahw.first_page_group_end   = first_page_group_end;
+	adapter->ahw.pci_base1 = mem_ptr1;
+	adapter->ahw.pci_base2 = mem_ptr2;
+	adapter->ahw.db_base = db_ptr;
+	adapter->ahw.db_len = db_len;
 
-	/* One adapter structure for all 4 ports....   */
-	adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL);
-	if (adapter == NULL) {
-		printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n",
-		       netxen_nic_driver_name,
-		       (int)sizeof(struct netxen_adapter));
-		err = -ENOMEM;
-		goto err_out_dbunmap;
-	}
+	adapter->netdev  = netdev;
+	adapter->pdev    = pdev;
+	adapter->portnum = pci_func_id;
+
+	netdev->open		   = netxen_nic_open;
+	netdev->stop		   = netxen_nic_close;
+	netdev->hard_start_xmit    = netxen_nic_xmit_frame;
+	netdev->get_stats	   = netxen_nic_get_stats;	
+	netdev->set_multicast_list = netxen_nic_set_multi;
+	netdev->set_mac_address    = netxen_nic_set_mac;
+	netdev->change_mtu	   = netxen_nic_change_mtu;
+	netdev->tx_timeout	   = netxen_tx_timeout;
+	netdev->watchdog_timeo     = HZ;
+
+	netxen_nic_change_mtu(netdev, netdev->mtu);
+
+	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+	netdev->poll = netxen_nic_poll;
+	netdev->weight = NETXEN_NETDEV_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = netxen_nic_poll_controller;
+#endif
+	/* ScatterGather support */
+	netdev->features = NETIF_F_SG;
+	netdev->features |= NETIF_F_IP_CSUM;
+	netdev->features |= NETIF_F_TSO;
+
+	if (pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	if (pci_enable_msi(pdev)) {
+		adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
+		printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
+		       " error\n", netxen_nic_driver_name);
+	} else
+		adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+
+	netdev->irq = pdev->irq;
+	INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
 
-	adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
-	adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
+	/*
+	 * Set the CRB window to invalid. If any register in window 0 is
+	 * accessed it should set the window to 0 and then reset it to 1.
+	 */
+	adapter->curr_window = 255;
+
+	/* initialize the adapter */
+	netxen_initialize_adapter_hw(adapter);
+
+#ifdef CONFIG_PPC
+	if ((adapter->ahw.boardcfg.board_type ==
+		NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) &&
+			(pci_func_id == 2))
+		    goto err_out_free_adapter;
+#endif /* CONFIG_PPC */
+
+	/*
+	 *  Adapter in our case is quad port so initialize it before
+	 *  initializing the ports
+	 */
+
+	netxen_initialize_adapter_ops(adapter);
+
+	adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
+	if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
+			(adapter->ahw.boardcfg.board_type == 
+			 NETXEN_BRDTYPE_P2_SB31_2G)) 
+		adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+	else
+		adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
 	adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
 	adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
 
-	pci_set_drvdata(pdev, adapter);
-
 	cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
 	if (cmd_buf_arr == NULL) {
 		printk(KERN_ERR
@@ -230,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, c
 		goto err_out_free_adapter;
 	}
 	memset(cmd_buf_arr, 0, TX_RINGSIZE);
+	adapter->cmd_buf_arr = cmd_buf_arr;
 
 	for (i = 0; i < MAX_RCV_CTX; ++i) {
 		recv_ctx = &adapter->recv_ctx[i];
@@ -277,33 +436,20 @@ netxen_nic_probe(struct pci_dev *pdev, c
 
 	}
 
-	adapter->cmd_buf_arr = cmd_buf_arr;
-	adapter->ahw.pci_base0 = mem_ptr0;
-	adapter->ahw.pci_base1 = mem_ptr1;
-	adapter->ahw.pci_base2 = mem_ptr2;
-	adapter->ahw.db_base = db_ptr;
-	adapter->ahw.db_len = db_len;
-	spin_lock_init(&adapter->tx_lock);
-	spin_lock_init(&adapter->lock);
 	netxen_initialize_adapter_sw(adapter);	/* initialize the buffers in adapter */
-#ifdef CONFIG_IA64
-	netxen_pinit_from_rom(adapter, 0);
-	udelay(500);
-	netxen_load_firmware(adapter);
-#endif
 
-	/*
-	 * Set the CRB window to invalid. If any register in window 0 is
-	 * accessed it should set the window to 0 and then reset it to 1.
-	 */
-	adapter->curr_window = 255;
-	/*
-	 *  Adapter in our case is quad port so initialize it before
-	 *  initializing the ports
-	 */
-	netxen_initialize_adapter_hw(adapter);	/* initialize the adapter */
+	/* Mezz cards have PCI function 0,2,3 enabled */
+	if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+		&& (pci_func_id >= 2))
+			adapter->portnum = pci_func_id - 2;
 
-	netxen_initialize_adapter_ops(adapter);
+#ifdef CONFIG_IA64
+	if(adapter->portnum == 0) {
+		netxen_pinit_from_rom(adapter, 0);
+		udelay(500);
+		netxen_load_firmware(adapter);
+	}
+#endif
 
 	init_timer(&adapter->watchdog_timer);
 	adapter->ahw.xg_linkup = 0;
@@ -314,12 +460,12 @@ #endif
 	adapter->proc_cmd_buf_counter = 0;
 	adapter->ahw.revision_id = nx_p2_id;
 
-	if (pci_enable_msi(pdev)) {
-		adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
-		printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
-		       " error\n", netxen_nic_driver_name);
-	} else
-		adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+	/* make sure Window == 1 */
+	netxen_nic_pci_change_crbwindow(adapter, 1);
+
+	netxen_nic_update_cmd_producer(adapter, 0);
+	netxen_nic_update_cmd_consumer(adapter, 0);
+	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
 
 	if (netxen_is_flash_supported(adapter) == 0 &&
 	    netxen_get_flash_mac_addr(adapter, mac_addr) == 0)
@@ -327,153 +473,118 @@ #endif
 	else
 		valid_mac = 0;
 
-	/*
-	 * Initialize all the CRB registers here.
-	 */
-	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
-	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET));
-	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
-
-	/* do this before waking up pegs so that we have valid dummy dma addr */
-	err = netxen_initialize_adapter_offload(adapter);
-	if (err) {
-		goto err_out_free_dev;
+	if (valid_mac) {
+		unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum];
+		netdev->dev_addr[0] = *(p + 5);
+		netdev->dev_addr[1] = *(p + 4);
+		netdev->dev_addr[2] = *(p + 3);
+		netdev->dev_addr[3] = *(p + 2);
+		netdev->dev_addr[4] = *(p + 1);
+		netdev->dev_addr[5] = *(p + 0);
+
+		memcpy(netdev->perm_addr, netdev->dev_addr,
+			netdev->addr_len);
+		if (!is_valid_ether_addr(netdev->perm_addr)) {
+			printk(KERN_ERR "%s: Bad MAC address "
+				"%02x:%02x:%02x:%02x:%02x:%02x.\n",
+				netxen_nic_driver_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]);
+		} else {
+			if (adapter->macaddr_set)
+				adapter->macaddr_set(adapter,
+							netdev->dev_addr);
+		}
 	}
 
-	/* Unlock the HW, prompting the boot sequence */
-	writel(1,
-	       NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
-
-	/* Handshake with the card before we register the devices. */
-	netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-
-	/* initialize the all the ports */
-	adapter->active_ports = 0;
-
-	for (i = 0; i < adapter->ahw.max_ports; i++) {
-		netdev = alloc_etherdev(sizeof(struct netxen_port));
-		if (!netdev) {
-			printk(KERN_ERR "%s: could not allocate netdev for port"
-			       " %d\n", netxen_nic_driver_name, i + 1);
+	if (adapter->portnum == 0) {
+		err = netxen_initialize_adapter_offload(adapter);
+		if (err) 
+			goto err_out_free_rx_buffer;
+		val = readl(NETXEN_CRB_NORMALIZE(adapter, 
+					NETXEN_CAM_RAM(0x1fc)));
+		if (val == 0x55555555) {
+		    /* This is the first boot after power up */
+		    val = readl(NETXEN_CRB_NORMALIZE(adapter,
+					NETXEN_ROMUSB_GLB_SW_RESET));
+		    printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val);
+		    if (val != 0x80000f) {
+			/* clear the register for future unloads/loads */
+			writel(0, NETXEN_CRB_NORMALIZE(adapter,
+						NETXEN_CAM_RAM(0x1fc)));
+			printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
+			err = -ENODEV;
 			goto err_out_free_dev;
-		}
+		    }
 
-		SET_MODULE_OWNER(netdev);
-		SET_NETDEV_DEV(netdev, &pdev->dev);
-
-		port = netdev_priv(netdev);
-		port->netdev = netdev;
-		port->pdev = pdev;
-		port->adapter = adapter;
-		port->portnum = i;	/* Gigabit port number from 0-3 */
-
-		netdev->open = netxen_nic_open;
-		netdev->stop = netxen_nic_close;
-		netdev->hard_start_xmit = netxen_nic_xmit_frame;
-		netdev->get_stats = netxen_nic_get_stats;
-		netdev->set_multicast_list = netxen_nic_set_multi;
-		netdev->set_mac_address = netxen_nic_set_mac;
-		netdev->change_mtu = netxen_nic_change_mtu;
-		netdev->tx_timeout = netxen_tx_timeout;
-		netdev->watchdog_timeo = HZ;
-
-		netxen_nic_change_mtu(netdev, netdev->mtu);
-
-		SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-		netdev->poll = netxen_nic_poll;
-		netdev->weight = NETXEN_NETDEV_WEIGHT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-		netdev->poll_controller = netxen_nic_poll_controller;
-#endif
-		/* ScatterGather support */
-		netdev->features = NETIF_F_SG;
-		netdev->features |= NETIF_F_IP_CSUM;
-		netdev->features |= NETIF_F_TSO;
-
-		if (pci_using_dac)
-			netdev->features |= NETIF_F_HIGHDMA;
-
-		if (valid_mac) {
-			unsigned char *p = (unsigned char *)&mac_addr[i];
-			netdev->dev_addr[0] = *(p + 5);
-			netdev->dev_addr[1] = *(p + 4);
-			netdev->dev_addr[2] = *(p + 3);
-			netdev->dev_addr[3] = *(p + 2);
-			netdev->dev_addr[4] = *(p + 1);
-			netdev->dev_addr[5] = *(p + 0);
-
-			memcpy(netdev->perm_addr, netdev->dev_addr,
-			       netdev->addr_len);
-			if (!is_valid_ether_addr(netdev->perm_addr)) {
-				printk(KERN_ERR "%s: Bad MAC address "
-				       "%02x:%02x:%02x:%02x:%02x:%02x.\n",
-				       netxen_nic_driver_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]);
-			} else {
-				if (adapter->macaddr_set)
-					adapter->macaddr_set(port,
-							     netdev->dev_addr);
-			}
+		    /* clear the register for future unloads/loads */
+		    writel(0, NETXEN_CRB_NORMALIZE(adapter, 
+					    NETXEN_CAM_RAM(0x1fc)));
 		}
-		INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task);
-		netif_carrier_off(netdev);
-		netif_stop_queue(netdev);
+		printk(KERN_INFO "State: 0x%0x\n",
+			readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
 
-		if ((err = register_netdev(netdev))) {
-			printk(KERN_ERR "%s: register_netdev failed port #%d"
-			       " aborting\n", netxen_nic_driver_name, i + 1);
-			err = -EIO;
-			free_netdev(netdev);
-			goto err_out_free_dev;
-		}
-		adapter->port_count++;
-		adapter->port[i] = port;
+		/*
+		 * Tell the hardware our version number.
+		 */
+		i = (_NETXEN_NIC_LINUX_MAJOR << 16) 
+			| ((_NETXEN_NIC_LINUX_MINOR << 8))
+			| (_NETXEN_NIC_LINUX_SUBVERSION);
+		writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
+
+		/* Unlock the HW, prompting the boot sequence */
+		writel(1,
+			NETXEN_CRB_NORMALIZE(adapter,
+				NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
+		/* Handshake with the card before we register the devices. */
+		netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
 	}
-	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-	netxen_pinit_from_rom(adapter, 0);
-	udelay(500);
-	netxen_load_firmware(adapter);
-	netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+
 	/*
-	 * delay a while to ensure that the Pegs are up & running.
-	 * Otherwise, we might see some flaky behaviour.
+	 * See if the firmware gave us a virtual-physical port mapping.
 	 */
-	udelay(100);
+	i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum)));
+	if (i != 0x55555555)
+		physical_port[adapter->portnum] = i;
+
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	if ((err = register_netdev(netdev))) {
+		printk(KERN_ERR "%s: register_netdev failed port #%d"
+			       " aborting\n", netxen_nic_driver_name,
+			       adapter->portnum);
+		err = -EIO;
+		goto err_out_free_dev;
+	}
+
+	pci_set_drvdata(pdev, adapter);
 
 	switch (adapter->ahw.board_type) {
-	case NETXEN_NIC_GBE:
-		printk("%s: QUAD GbE board initialized\n",
-		       netxen_nic_driver_name);
-		break;
+		case NETXEN_NIC_GBE:
+			printk(KERN_INFO "%s: QUAD GbE board initialized\n",
+			       netxen_nic_driver_name);
+			break;
 
-	case NETXEN_NIC_XGBE:
-		printk("%s: XGbE board initialized\n", netxen_nic_driver_name);
-		break;
+		case NETXEN_NIC_XGBE:
+			printk(KERN_INFO "%s: XGbE board initialized\n", 
+					netxen_nic_driver_name);
+			break;
 	}
 
 	adapter->driver_mismatch = 0;
 
 	return 0;
 
-      err_out_free_dev:
-	if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-		pci_disable_msi(pdev);
-	for (i = 0; i < adapter->port_count; i++) {
-		port = adapter->port[i];
-		if ((port) && (port->netdev)) {
-			unregister_netdev(port->netdev);
-			free_netdev(port->netdev);
-		}
-	}
+err_out_free_dev:
+	if (adapter->portnum == 0)
+		netxen_free_adapter_offload(adapter);
 
-	netxen_free_adapter_offload(adapter);
-
-      err_out_free_rx_buffer:
+err_out_free_rx_buffer:
 	for (i = 0; i < MAX_RCV_CTX; ++i) {
 		recv_ctx = &adapter->recv_ctx[i];
 		for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
@@ -486,15 +597,16 @@ #endif
 	}
 	vfree(cmd_buf_arr);
 
-      err_out_free_adapter:
+err_out_free_adapter:
+	if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+		pci_disable_msi(pdev);
+
 	pci_set_drvdata(pdev, NULL);
-	kfree(adapter);
 
-      err_out_dbunmap:
 	if (db_ptr)
 		iounmap(db_ptr);
 
-      err_out_iounmap:
+err_out_iounmap:
 	if (mem_ptr0)
 		iounmap(mem_ptr0);
 	if (mem_ptr1)
@@ -502,9 +614,13 @@ #endif
 	if (mem_ptr2)
 		iounmap(mem_ptr2);
 
-      err_out_free_res:
+err_out_free_netdev:
+	free_netdev(netdev);
+
+err_out_free_res:
 	pci_release_regions(pdev);
-      err_out_disable_pdev:
+
+err_out_disable_pdev:
 	pci_disable_device(pdev);
 	return err;
 }
@@ -512,7 +628,7 @@ #endif
 static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 {
 	struct netxen_adapter *adapter;
-	struct netxen_port *port;
+	struct net_device *netdev;
 	struct netxen_rx_buffer *buffer;
 	struct netxen_recv_context *recv_ctx;
 	struct netxen_rcv_desc_ctx *rcv_desc;
@@ -523,38 +639,34 @@ static void __devexit netxen_nic_remove(
 	if (adapter == NULL)
 		return;
 
+	netdev = adapter->netdev;
+
+	netxen_nic_disable_int(adapter);
 	if (adapter->irq)
 		free_irq(adapter->irq, adapter);
-	netxen_nic_stop_all_ports(adapter);
-	/* leave the hw in the same state as reboot */
-	writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-	netxen_pinit_from_rom(adapter, 0);
-	udelay(500);
-	netxen_load_firmware(adapter);
-	netxen_free_adapter_offload(adapter);
-
-	mdelay(1000);		/* Delay for a while to drain the DMA engines */
-	for (i = 0; i < adapter->port_count; i++) {
-		port = adapter->port[i];
-		if ((port) && (port->netdev)) {
-			unregister_netdev(port->netdev);
-			free_netdev(port->netdev);
-		}
-	}
+	
+	if (adapter->stop_port)
+		adapter->stop_port(adapter);
 
 	if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
 		pci_disable_msi(pdev);
-	if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
-		netxen_free_hw_resources(adapter);
 
-	iounmap(adapter->ahw.db_base);
-	iounmap(adapter->ahw.pci_base0);
-	iounmap(adapter->ahw.pci_base1);
-	iounmap(adapter->ahw.pci_base2);
+	if (adapter->portnum == 0)
+		netxen_free_adapter_offload(adapter);
 
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
+	if (adapter->irq)
+		free_irq(adapter->irq, adapter);
+	if(adapter->portnum == 0) {
+		/* leave the hw in the same state as reboot */
+		writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+		netxen_pinit_from_rom(adapter, 0);
+		udelay(500);
+		netxen_load_firmware(adapter);
+		netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+	}
+
+	if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+		netxen_free_hw_resources(adapter);
 
 	for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
 		recv_ctx = &adapter->recv_ctx[ctxid];
@@ -574,8 +686,20 @@ static void __devexit netxen_nic_remove(
 		}
 	}
 
+	unregister_netdev(netdev);
+
 	vfree(adapter->cmd_buf_arr);
-	kfree(adapter);
+
+	iounmap(adapter->ahw.db_base);
+	iounmap(adapter->ahw.pci_base0);
+	iounmap(adapter->ahw.pci_base1);
+	iounmap(adapter->ahw.pci_base2);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	free_netdev(netdev);
 }
 
 /*
@@ -584,8 +708,7 @@ static void __devexit netxen_nic_remove(
  */
 static int netxen_nic_open(struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv;
 	int err = 0;
 	int ctx, ring;
 
@@ -596,8 +719,6 @@ static int netxen_nic_open(struct net_de
 			return -EIO;
 		}
 		netxen_nic_flash_print(adapter);
-		if (adapter->init_niu)
-			adapter->init_niu(adapter);
 
 		/* setup all the resources for the Phantom... */
 		/* this include the descriptors for rcv, tx, and status */
@@ -608,21 +729,14 @@ static int netxen_nic_open(struct net_de
 			       err);
 			return err;
 		}
-		if (adapter->init_port
-		    && adapter->init_port(adapter, port->portnum) != 0) {
-			printk(KERN_ERR "%s: Failed to initialize port %d\n",
-			       netxen_nic_driver_name, port->portnum);
-			netxen_free_hw_resources(adapter);
-			return -EIO;
-		}
 		for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
 			for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++)
 				netxen_post_rx_buffers(adapter, ctx, ring);
 		}
 		adapter->irq = adapter->ahw.pdev->irq;
-		err = request_irq(adapter->ahw.pdev->irq, &netxen_intr,
-				  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
-				  netdev->name, adapter);
+		err = request_irq(adapter->ahw.pdev->irq, netxen_intr,
+				  SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
+				  adapter);
 		if (err) {
 			printk(KERN_ERR "request_irq failed with: %d\n", err);
 			netxen_free_hw_resources(adapter);
@@ -631,23 +745,28 @@ static int netxen_nic_open(struct net_de
 
 		adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
 	}
-	adapter->active_ports++;
-	if (adapter->active_ports == 1) {
-		if (!adapter->driver_mismatch)
-			mod_timer(&adapter->watchdog_timer, jiffies);
+	if (!adapter->driver_mismatch)
+		mod_timer(&adapter->watchdog_timer, jiffies);
 
-		netxen_nic_enable_int(adapter);
-	}
+	netxen_nic_enable_int(adapter);
 
 	/* Done here again so that even if phantom sw overwrote it,
 	 * we set it */
 	if (adapter->macaddr_set)
-		adapter->macaddr_set(port, netdev->dev_addr);
-	netxen_nic_set_link_parameters(port);
+		adapter->macaddr_set(adapter, netdev->dev_addr);
+	if (adapter->init_port
+	    && adapter->init_port(adapter, adapter->portnum) != 0) {
+	    del_timer_sync(&adapter->watchdog_timer);
+		printk(KERN_ERR "%s: Failed to initialize port %d\n",
+				netxen_nic_driver_name, adapter->portnum);
+		return -EIO;
+	}
+
+	netxen_nic_set_link_parameters(adapter);
 
 	netxen_nic_set_multi(netdev);
 	if (adapter->set_mtu)
-		adapter->set_mtu(port, netdev->mtu);
+		adapter->set_mtu(adapter, netdev->mtu);
 
 	if (!adapter->driver_mismatch)
 		netif_start_queue(netdev);
@@ -660,8 +779,7 @@ static int netxen_nic_open(struct net_de
  */
 static int netxen_nic_close(struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	int i, j;
 	struct netxen_cmd_buffer *cmd_buff;
 	struct netxen_skb_frag *buffrag;
@@ -669,47 +787,39 @@ static int netxen_nic_close(struct net_d
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	adapter->active_ports--;
-
-	if (!adapter->active_ports) {
-		netxen_nic_disable_int(adapter);
-		cmd_buff = adapter->cmd_buf_arr;
-		for (i = 0; i < adapter->max_tx_desc_count; i++) {
-			buffrag = cmd_buff->frag_array;
+	cmd_buff = adapter->cmd_buf_arr;
+	for (i = 0; i < adapter->max_tx_desc_count; i++) {
+		buffrag = cmd_buff->frag_array;
+		if (buffrag->dma) {
+			pci_unmap_single(adapter->pdev, buffrag->dma,
+					 buffrag->length, PCI_DMA_TODEVICE);
+			buffrag->dma = (u64) NULL;
+		}
+		for (j = 0; j < cmd_buff->frag_count; j++) {
+			buffrag++;
 			if (buffrag->dma) {
-				pci_unmap_single(port->pdev, buffrag->dma,
-						 buffrag->length,
-						 PCI_DMA_TODEVICE);
+				pci_unmap_page(adapter->pdev, buffrag->dma,
+					       buffrag->length, 
+					       PCI_DMA_TODEVICE);
 				buffrag->dma = (u64) NULL;
 			}
-			for (j = 0; j < cmd_buff->frag_count; j++) {
-				buffrag++;
-				if (buffrag->dma) {
-					pci_unmap_page(port->pdev,
-						       buffrag->dma,
-						       buffrag->length,
-						       PCI_DMA_TODEVICE);
-					buffrag->dma = (u64) NULL;
-				}
-			}
-			/* Free the skb we received in netxen_nic_xmit_frame */
-			if (cmd_buff->skb) {
-				dev_kfree_skb_any(cmd_buff->skb);
-				cmd_buff->skb = NULL;
-			}
-			cmd_buff++;
 		}
-		FLUSH_SCHEDULED_WORK();
-		del_timer_sync(&adapter->watchdog_timer);
+		/* Free the skb we received in netxen_nic_xmit_frame */
+		if (cmd_buff->skb) {
+			dev_kfree_skb_any(cmd_buff->skb);
+			cmd_buff->skb = NULL;
+		}
+		cmd_buff++;
 	}
+	FLUSH_SCHEDULED_WORK();
+	del_timer_sync(&adapter->watchdog_timer);
 
 	return 0;
 }
 
 static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	struct netxen_hardware_context *hw = &adapter->ahw;
 	unsigned int first_seg_len = skb->len - skb->data_len;
 	struct netxen_skb_frag *buffrag;
@@ -727,12 +837,12 @@ static int netxen_nic_xmit_frame(struct 
 	u32 last_cmd_consumer = 0;
 	int no_of_desc;
 
-	port->stats.xmitcalled++;
+	adapter->stats.xmitcalled++;
 	frag_count = skb_shinfo(skb)->nr_frags + 1;
 
 	if (unlikely(skb->len <= 0)) {
 		dev_kfree_skb_any(skb);
-		port->stats.badskblen++;
+		adapter->stats.badskblen++;
 		return NETDEV_TX_OK;
 	}
 
@@ -741,7 +851,7 @@ static int netxen_nic_xmit_frame(struct 
 		       "too large, can handle only %d frags\n",
 		       netxen_nic_driver_name, netdev->name,
 		       frag_count, MAX_BUFFERS_PER_CMD);
-		port->stats.txdropped++;
+		adapter->stats.txdropped++;
 		if ((++dropped_packet & 0xff) == 0xff)
 			printk("%s: %s droppped packets = %d\n",
 			       netxen_nic_driver_name, netdev->name,
@@ -758,7 +868,7 @@ static int netxen_nic_xmit_frame(struct 
 	 */
       retry_getting_window:
 	spin_lock_bh(&adapter->tx_lock);
-	if (adapter->total_threads == MAX_XMIT_PRODUCERS) {
+	if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
 		spin_unlock_bh(&adapter->tx_lock);
 		/*
 		 * Yield CPU
@@ -778,9 +888,8 @@ static int netxen_nic_xmit_frame(struct 
 		if (skb_shinfo(skb)->gso_size > 0) {
 
 			no_of_desc++;
-			if (((skb->nh.iph)->ihl * sizeof(u32)) +
-			    ((skb->h.th)->doff * sizeof(u32)) +
-			    sizeof(struct ethhdr) >
+			if ((ip_hdrlen(skb) + tcp_hdrlen(skb) +
+			     sizeof(struct ethhdr)) >
 			    (sizeof(struct cmd_desc_type0) - 2)) {
 				no_of_desc++;
 			}
@@ -792,15 +901,8 @@ static int netxen_nic_xmit_frame(struct 
 	if ((k + no_of_desc) >=
 	    ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
 	     last_cmd_consumer)) {
-		port->stats.nocmddescriptor++;
-		DPRINTK(ERR, "No command descriptors available,"
-			" producer = %d, consumer = %d count=%llu,"
-			" dropping packet\n", producer,
-			adapter->last_cmd_consumer,
-			port->stats.nocmddescriptor);
-
 		netif_stop_queue(netdev);
-		port->flags |= NETXEN_NETDEV_STATUS;
+		adapter->flags |= NETXEN_NETDEV_STATUS;
 		spin_unlock_bh(&adapter->tx_lock);
 		return NETDEV_TX_BUSY;
 	}
@@ -828,16 +930,17 @@ static int netxen_nic_xmit_frame(struct 
 	pbuf->skb = skb;
 	pbuf->cmd = TX_ETHER_PKT;
 	pbuf->frag_count = frag_count;
-	pbuf->port = port->portnum;
+	pbuf->port = adapter->portnum;
 	buffrag = &pbuf->frag_array[0];
-	buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len,
+	buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
 				      PCI_DMA_TODEVICE);
 	buffrag->length = first_seg_len;
 	netxen_set_cmd_desc_totallength(hwdesc, skb->len);
 	netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count);
 	netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
 
-	netxen_set_cmd_desc_port(hwdesc, port->portnum);
+	netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
+	netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
 	hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
 	hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
 
@@ -860,7 +963,7 @@ static int netxen_nic_xmit_frame(struct 
 		offset = frag->page_offset;
 
 		temp_len = len;
-		temp_dma = pci_map_page(port->pdev, frag->page, offset,
+		temp_dma = pci_map_page(adapter->pdev, frag->page, offset,
 					len, PCI_DMA_TODEVICE);
 
 		buffrag++;
@@ -920,26 +1023,36 @@ static int netxen_nic_xmit_frame(struct 
 			/* copy the next 64 bytes - should be enough except
 			 * for pathological case
 			 */
-			memcpy((void *)hwdesc, (void *)(skb->data) +
-			       first_hdr_len, hdr_len - first_hdr_len);
+			skb_copy_from_linear_data_offset(skb, first_hdr_len,
+							 hwdesc,
+							 (hdr_len -
+							  first_hdr_len));
 			producer = get_next_index(producer, max_tx_desc_count);
 		}
 	}
+
+	i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+
+	hw->cmd_desc_head[saved_producer].flags_opcode =
+		cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
+	hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
+	  cpu_to_le32(hw->cmd_desc_head[saved_producer].
+			  num_of_buffers_total_length);
+
 	spin_lock_bh(&adapter->tx_lock);
-	port->stats.txbytes +=
-	    netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+	adapter->stats.txbytes += i;
+
 	/* Code to update the adapter considering how many producer threads
 	   are currently working */
 	if ((--adapter->num_threads) == 0) {
 		/* This is the last thread */
 		u32 crb_producer = adapter->cmd_producer;
-		writel(crb_producer,
-		       NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+		netxen_nic_update_cmd_producer(adapter, crb_producer);
 		wmb();
 		adapter->total_threads = 0;
 	}
 
-	port->stats.xmitfinished++;
+	adapter->stats.xmitfinished++;
 	spin_unlock_bh(&adapter->tx_lock);
 
 	netdev->trans_start = jiffies;
@@ -959,27 +1072,26 @@ static void netxen_watchdog(unsigned lon
 
 static void netxen_tx_timeout(struct net_device *netdev)
 {
-	struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-
-	SCHEDULE_WORK(&port->tx_timeout_task);
+	struct netxen_adapter *adapter = (struct netxen_adapter *)
+						netdev_priv(netdev);
+	SCHEDULE_WORK(&adapter->tx_timeout_task);
 }
 
 static void netxen_tx_timeout_task(struct work_struct *work)
 {
-	struct netxen_port *port =
-		container_of(work, struct netxen_port, tx_timeout_task);
-	struct net_device *netdev = port->netdev;
+	struct netxen_adapter *adapter = 
+		container_of(work, struct netxen_adapter, tx_timeout_task);
 	unsigned long flags;
 
 	printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
-	       netxen_nic_driver_name, netdev->name);
-
-	spin_lock_irqsave(&port->adapter->lock, flags);
-	netxen_nic_close(netdev);
-	netxen_nic_open(netdev);
-	spin_unlock_irqrestore(&port->adapter->lock, flags);
-	netdev->trans_start = jiffies;
-	netif_wake_queue(netdev);
+	       netxen_nic_driver_name, adapter->netdev->name);
+
+	spin_lock_irqsave(&adapter->lock, flags);
+	netxen_nic_close(adapter->netdev);
+	netxen_nic_open(adapter->netdev);
+	spin_unlock_irqrestore(&adapter->lock, flags);
+	adapter->netdev->trans_start = jiffies;
+	netif_wake_queue(adapter->netdev);
 }
 
 static int
@@ -988,17 +1100,16 @@ netxen_handle_int(struct netxen_adapter 
 	u32 ret = 0;
 
 	DPRINTK(INFO, "Entered handle ISR\n");
-
 	adapter->stats.ints++;
 
 	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
 		int count = 0;
 		u32 mask;
-		mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
-		if ((mask & 0x80) == 0) {
-			/* not our interrupt */
+		u32 our_int = 0;
+		our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+		/* not our interrupt */
+		if ((our_int & (0x80 << adapter->portnum)) == 0)
 			return ret;
-		}
 		netxen_nic_disable_int(adapter);
 		/* Window = 0 or 1 */
 		do {
@@ -1010,7 +1121,6 @@ netxen_handle_int(struct netxen_adapter 
 			printk("Could not disable interrupt completely\n");
 
 	}
-	adapter->stats.hostints++;
 
 	if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
 		if (netif_rx_schedule_prep(netdev)) {
@@ -1044,33 +1154,24 @@ netxen_handle_int(struct netxen_adapter 
 irqreturn_t netxen_intr(int irq, void *data)
 {
 	struct netxen_adapter *adapter;
-	struct netxen_port *port;
 	struct net_device *netdev;
-	int i;
 
 	if (unlikely(!irq)) {
 		return IRQ_NONE;	/* Not our interrupt */
 	}
 
 	adapter = (struct netxen_adapter *)data;
-	for (i = 0; i < adapter->ahw.max_ports; i++) {
-		port = adapter->port[i];
-		netdev = port->netdev;
-
-		/* process our status queue (for all 4 ports) */
-		if (netif_running(netdev)) {
-			netxen_handle_int(adapter, netdev);
-			break;
-		}
-	}
+	netdev  = adapter->netdev;
+	/* process our status queue (for all 4 ports) */
+	if (netif_running(netdev))
+		netxen_handle_int(adapter, netdev);
 
 	return IRQ_HANDLED;
 }
 
 static int netxen_nic_poll(struct net_device *netdev, int *budget)
 {
-	struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	int work_to_do = min(*budget, netdev->quota);
 	int done = 1;
 	int ctx;
@@ -1078,7 +1179,6 @@ static int netxen_nic_poll(struct net_de
 	int work_done = 0;
 
 	DPRINTK(INFO, "polling for %d descriptors\n", *budget);
-	port->stats.polled++;
 
 	work_done = 0;
 	for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
@@ -1122,8 +1222,7 @@ static int netxen_nic_poll(struct net_de
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void netxen_nic_poll_controller(struct net_device *netdev)
 {
-	struct netxen_port *port = netdev_priv(netdev);
-	struct netxen_adapter *adapter = port->adapter;
+	struct netxen_adapter *adapter = netdev_priv(netdev);
 	disable_irq(adapter->irq);
 	netxen_intr(adapter->irq, adapter);
 	enable_irq(adapter->irq);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index d5d9507..cef90a7 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -88,12 +88,13 @@ static inline int phy_unlock(struct netx
  *	  -1 on error
  *
  */
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
-			    long reg, __u32 * readval)
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, 
+				__u32 * readval)
 {
 	long timeout = 0;
 	long result = 0;
 	long restore = 0;
+	long phy = physical_port[adapter->portnum];
 	__u32 address;
 	__u32 command;
 	__u32 status;
@@ -183,12 +184,13 @@ int netxen_niu_gbe_phy_read(struct netxe
  *	  -1 on error
  *
  */
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
-			     long phy, long reg, __u32 val)
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, 
+				__u32 val)
 {
 	long timeout = 0;
 	long result = 0;
 	long restore = 0;
+	long phy = physical_port[adapter->portnum];
 	__u32 address;
 	__u32 command;
 	__u32 status;
@@ -258,15 +260,13 @@ int netxen_niu_gbe_phy_write(struct netx
 	return result;
 }
 
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-					  int port)
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f);
 	return 0;
 }
 
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
-					 int port)
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter)
 {
 	int result = 0;
 	__u32 enable = 0;
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts
 	netxen_set_phy_int_speed_changed(enable);
 
 	if (0 !=
-	    netxen_niu_gbe_phy_write(adapter, port,
+	    netxen_niu_gbe_phy_write(adapter, 
 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
 				     enable))
 		result = -EIO;
@@ -283,38 +283,34 @@ int netxen_niu_gbe_enable_phy_interrupts
 	return result;
 }
 
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-					   int port)
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f);
 	return 0;
 }
 
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
-					  int port)
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
 {
 	int result = 0;
 	if (0 !=
-	    netxen_niu_gbe_phy_write(adapter, port,
+	    netxen_niu_gbe_phy_write(adapter,
 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))
 		result = -EIO;
 
 	return result;
 }
 
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-					 int port)
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
 	return 0;
 }
 
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
-					int port)
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
 	int result = 0;
 	if (0 !=
-	    netxen_niu_gbe_phy_write(adapter, port,
+	    netxen_niu_gbe_phy_write(adapter, 
 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
 				     -EIO))
 		result = -EIO;
@@ -355,9 +351,9 @@ void netxen_niu_gbe_set_mii_mode(struct 
 					    0x5);
 	}
 
-	if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+	if (netxen_niu_gbe_enable_phy_interrupts(adapter))
 		printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
-	if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+	if (netxen_niu_gbe_clear_phy_interrupts(adapter))
 		printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
 }
 
@@ -393,9 +389,9 @@ void netxen_niu_gbe_set_gmii_mode(struct
 					    0x5);
 	}
 
-	if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+	if (netxen_niu_gbe_enable_phy_interrupts(adapter))
 		printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
-	if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+	if (netxen_niu_gbe_clear_phy_interrupts(adapter))
 		printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
 }
 
@@ -404,11 +400,11 @@ int netxen_niu_gbe_init_port(struct netx
 	int result = 0;
 	__u32 status;
 	if (adapter->disable_phy_interrupts)
-		adapter->disable_phy_interrupts(adapter, port);
+		adapter->disable_phy_interrupts(adapter);
 	mdelay(2);
 
 	if (0 ==
-	    netxen_niu_gbe_phy_read(adapter, port,
+	    netxen_niu_gbe_phy_read(adapter,
 				    NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 				    &status)) {
 		if (netxen_get_phy_link(status)) {
@@ -439,13 +435,13 @@ int netxen_niu_gbe_init_port(struct netx
 						    | NETXEN_GB_MAC_ENABLE_TX_RX
 						    |
 						    NETXEN_GB_MAC_PAUSED_FRMS);
-			if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+			if (netxen_niu_gbe_clear_phy_interrupts(adapter))
 				printk(KERN_ERR PFX
 				       "ERROR clearing PHY interrupts\n");
-			if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+			if (netxen_niu_gbe_enable_phy_interrupts(adapter))
 				printk(KERN_ERR PFX
 				       "ERROR enabling PHY interrupts\n");
-			if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+			if (netxen_niu_gbe_clear_phy_interrupts(adapter))
 				printk(KERN_ERR PFX
 				       "ERROR clearing PHY interrupts\n");
 			result = -1;
@@ -458,26 +454,18 @@ int netxen_niu_gbe_init_port(struct netx
 
 int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
 {
-	u32 reg = 0, ret = 0;
+	u32 reg;
+	u32 portnum = physical_port[adapter->portnum];
 
-	if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
-		netxen_crb_writelit_adapter(adapter,
-					    NETXEN_NIU_XG1_CONFIG_0, 0x5);
-		/* XXX hack for Mez cards: both ports in promisc mode */
-		netxen_nic_hw_read_wx(adapter,
-				      NETXEN_NIU_XGE_CONFIG_1, &reg, 4);
-		reg = (reg | 0x2000UL);
-		netxen_crb_writelit_adapter(adapter,
-					    NETXEN_NIU_XGE_CONFIG_1, reg);
-		reg = 0;
-		netxen_nic_hw_read_wx(adapter,
-				      NETXEN_NIU_XG1_CONFIG_1, &reg, 4);
-		reg = (reg | 0x2000UL);
-		netxen_crb_writelit_adapter(adapter,
-					    NETXEN_NIU_XG1_CONFIG_1, reg);
-	}
+	netxen_crb_writelit_adapter(adapter,
+		NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5);
+	netxen_nic_hw_read_wx(adapter,
+		NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), &reg, 4);
+	reg = (reg & ~0x2000UL);
+	netxen_crb_writelit_adapter(adapter,
+		NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg);
 
-	return ret;
+	return 0;
 }
 
 /* 
@@ -498,7 +486,7 @@ int netxen_niu_gbe_handle_phy_interrupt(
 	 * The read of the PHY INT status will clear the pending
 	 * interrupt status
 	 */
-	if (netxen_niu_gbe_phy_read(adapter, port,
+	if (netxen_niu_gbe_phy_read(adapter,
 				    NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
 				    &int_src) != 0)
 		result = -EINVAL;
@@ -535,7 +523,7 @@ int netxen_niu_gbe_handle_phy_interrupt(
 			printk(KERN_INFO PFX
 			       "speed_changed or link status changed");
 			if (netxen_niu_gbe_phy_read
-			    (adapter, port,
+			    (adapter,
 			     NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 			     &status) == 0) {
 				if (netxen_get_phy_speed(status) == 2) {
@@ -581,10 +569,11 @@ int netxen_niu_gbe_handle_phy_interrupt(
  * Note that the passed-in value must already be in network byte order.
  */
 int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
-			   int phy, netxen_ethernet_macaddr_t * addr)
+			   netxen_ethernet_macaddr_t * addr)
 {
 	u32 stationhigh;
 	u32 stationlow;
+	int phy = physical_port[adapter->portnum];
 	u8 val[8];
 
 	if (addr == NULL)
@@ -610,13 +599,12 @@ int netxen_niu_macaddr_get(struct netxen
  * Set the station MAC address.
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
 			   netxen_ethernet_macaddr_t addr)
 {
 	u8 temp[4];
 	u32 val;
-	struct netxen_adapter *adapter = port->adapter;
-	int phy = port->portnum;
+	int phy = physical_port[adapter->portnum];
 	unsigned char mac_addr[6];
 	int i;
 
@@ -634,7 +622,7 @@ int netxen_niu_macaddr_set(struct netxen
 		    (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
 			return -2;
 
-		netxen_niu_macaddr_get(adapter, phy,
+		netxen_niu_macaddr_get(adapter, 
 				       (netxen_ethernet_macaddr_t *) mac_addr);
 		if (memcmp(mac_addr, addr, 6) == 0)
 			break;
@@ -642,7 +630,7 @@ int netxen_niu_macaddr_set(struct netxen
 
 	if (i == 10) {
 		printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
-		       netxen_nic_driver_name, port->netdev->name);
+		       netxen_nic_driver_name, adapter->netdev->name);
 		printk(KERN_ERR "MAC address set: "
 		       "%02x:%02x:%02x:%02x:%02x:%02x.\n",
 		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -735,13 +723,13 @@ int netxen_niu_enable_gbe_port(struct ne
 }
 
 /* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
 {
 	__u32 mac_cfg0;
+	u32 port = physical_port[adapter->portnum];
 
 	if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
 		return -EINVAL;
-
 	mac_cfg0 = 0;
 	netxen_gb_soft_reset(mac_cfg0);
 	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -751,13 +739,13 @@ int netxen_niu_disable_gbe_port(struct n
 }
 
 /* Disable an XG interface */
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
 {
 	__u32 mac_cfg;
+	u32 port = physical_port[adapter->portnum];
 
 	if (port != 0)
 		return -EINVAL;
-
 	mac_cfg = 0;
 	netxen_xg_soft_reset(mac_cfg);
 	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
@@ -767,10 +755,11 @@ int netxen_niu_disable_xg_port(struct ne
 }
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
 				    netxen_niu_prom_mode_t mode)
 {
 	__u32 reg;
+	u32 port = physical_port[adapter->portnum];
 
 	if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
 		return -EINVAL;
@@ -824,25 +813,50 @@ int netxen_niu_set_promiscuous_mode(stru
  * Set the MAC address for an XG port
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
 			      netxen_ethernet_macaddr_t addr)
 {
+	int phy = physical_port[adapter->portnum];
 	u8 temp[4];
 	u32 val;
-	struct netxen_adapter *adapter = port->adapter;
+
+	if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS))
+		return -EIO;
 
 	temp[0] = temp[1] = 0;
-	memcpy(temp + 2, addr, 2);
-	val = le32_to_cpu(*(__le32 *)temp);
-	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
-				   &val, 4))
+	switch (phy) {
+	case 0:
+	    memcpy(temp + 2, addr, 2);
+	    val = le32_to_cpu(*(__le32 *)temp);
+	    if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+				&val, 4))
 		return -EIO;
 
-	memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
-	val = le32_to_cpu(*(__le32 *)temp);
-	if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
-				   &val, 4))
+	    memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+	    val = le32_to_cpu(*(__le32 *)temp);
+	    if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+				&val, 4))
+		return -EIO;
+	    break;
+
+	case 1:
+	    memcpy(temp + 2, addr, 2);
+	    val = le32_to_cpu(*(__le32 *)temp);
+	    if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1,
+				&val, 4))
+		return -EIO;
+
+	    memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+	    val = le32_to_cpu(*(__le32 *)temp);
+	    if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI,
+				&val, 4))
 		return -EIO;
+	    break;
+
+	default:
+	    printk(KERN_ERR "Unknown port %d\n", phy);
+	    break;
+	}
 
 	return 0;
 }
@@ -851,9 +865,10 @@ int netxen_niu_xg_macaddr_set(struct net
  * Return the current station MAC address.
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
 			      netxen_ethernet_macaddr_t * addr)
 {
+	int phy = physical_port[adapter->portnum];
 	u32 stationhigh;
 	u32 stationlow;
 	u8 val[8];
@@ -878,21 +893,24 @@ int netxen_niu_xg_macaddr_get(struct net
 }
 
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
-				       int port, netxen_niu_prom_mode_t mode)
+				       netxen_niu_prom_mode_t mode)
 {
 	__u32 reg;
+	u32 port = physical_port[adapter->portnum];
 
-	if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+	if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
 		return -EINVAL;
 
-	if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, &reg, 4))
-		return -EIO;
+	if (netxen_nic_hw_read_wx(adapter,
+		NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), &reg, 4))
+			return -EIO;
 	if (mode == NETXEN_NIU_PROMISC_MODE)
 		reg = (reg | 0x2000UL);
 	else
 		reg = (reg & ~0x2000UL);
 
-	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg);
+	netxen_crb_writelit_adapter(adapter,
+		NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg);
 
 	return 0;
 }
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 0c7c943..9457fc7 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -100,8 +100,21 @@ #define CRB_JUMBO_BUFFER_CONS       NETX
 
 #define CRB_CMD_PRODUCER_OFFSET_1   NETXEN_NIC_REG(0x1ac)
 #define CRB_CMD_CONSUMER_OFFSET_1   NETXEN_NIC_REG(0x1b0)
+#define CRB_CMD_PRODUCER_OFFSET_2   NETXEN_NIC_REG(0x1b8)
+#define CRB_CMD_CONSUMER_OFFSET_2   NETXEN_NIC_REG(0x1bc)
+
+// 1c0 to 1cc used for signature reg
+#define CRB_CMD_PRODUCER_OFFSET_3   NETXEN_NIC_REG(0x1d0)
+#define CRB_CMD_CONSUMER_OFFSET_3   NETXEN_NIC_REG(0x1d4)
 #define CRB_TEMP_STATE              NETXEN_NIC_REG(0x1b4)
 
+#define CRB_V2P_0		    NETXEN_NIC_REG(0x290)
+#define CRB_V2P_1		    NETXEN_NIC_REG(0x294)
+#define CRB_V2P_2		    NETXEN_NIC_REG(0x298)
+#define CRB_V2P_3		    NETXEN_NIC_REG(0x29c)
+#define CRB_V2P(port)		    (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION	    NETXEN_NIC_REG(0x2a0)
+
 /* used for ethtool tests */
 #define CRB_SCRATCHPAD_TEST	    NETXEN_NIC_REG(0x280)
 
@@ -139,128 +152,13 @@ struct netxen_recv_crb {
 };
 
 #if defined(DEFINE_GLOBAL_RECV_CRB)
-struct netxen_recv_crb recv_crb_registers[] = {
-	/*
-	 * Instance 0.
-	 */
-	{
-	 /* rcv_desc_crb: */
-	 {
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x100),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x104),
-	   /* crb_gloablrcv_ring: */
-	   NETXEN_NIC_REG(0x108),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x10c),
-
-	   },
-	  /* Jumbo frames */
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x110),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x114),
-	   /* crb_gloablrcv_ring: */
-	   NETXEN_NIC_REG(0x118),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x11c),
-	   },
-	  /* LRO */
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x120),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x124),
-	   /* crb_gloablrcv_ring: */
-	   NETXEN_NIC_REG(0x128),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x12c),
-	   }
-	  },
-	 /* crb_rcvstatus_ring: */
-	 NETXEN_NIC_REG(0x130),
-	 /* crb_rcv_status_producer: */
-	 NETXEN_NIC_REG(0x134),
-	 /* crb_rcv_status_consumer: */
-	 NETXEN_NIC_REG(0x138),
-	 /* crb_rcvpeg_state: */
-	 NETXEN_NIC_REG(0x13c),
-	 /* crb_status_ring_size */
-	 NETXEN_NIC_REG(0x140),
-
-	 },
-	/*
-	 * Instance 1,
-	 */
-	{
-	 /* rcv_desc_crb: */
-	 {
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x144),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x148),
-	   /* crb_globalrcv_ring: */
-	   NETXEN_NIC_REG(0x14c),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x150),
-
-	   },
-	  /* Jumbo frames */
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x154),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x158),
-	   /* crb_globalrcv_ring: */
-	   NETXEN_NIC_REG(0x15c),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x160),
-	   },
-	  /* LRO */
-	  {
-	   /* crb_rcv_producer_offset: */
-	   NETXEN_NIC_REG(0x164),
-	   /* crb_rcv_consumer_offset: */
-	   NETXEN_NIC_REG(0x168),
-	   /* crb_globalrcv_ring: */
-	   NETXEN_NIC_REG(0x16c),
-	   /* crb_rcv_ring_size */
-	   NETXEN_NIC_REG(0x170),
-	   }
-
-	  },
-	 /* crb_rcvstatus_ring: */
-	 NETXEN_NIC_REG(0x174),
-	 /* crb_rcv_status_producer: */
-	 NETXEN_NIC_REG(0x178),
-	 /* crb_rcv_status_consumer: */
-	 NETXEN_NIC_REG(0x17c),
-	 /* crb_rcvpeg_state: */
-	 NETXEN_NIC_REG(0x180),
-	 /* crb_status_ring_size */
-	 NETXEN_NIC_REG(0x184),
-
-	 },
-};
-
-u64 ctx_addr_sig_regs[][3] = {
-	{NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
-	{NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
-	{NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
-	{NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
-};
-
 #else
 extern struct netxen_recv_crb recv_crb_registers[];
 extern u64 ctx_addr_sig_regs[][3];
-#define CRB_CTX_ADDR_REG_LO            (ctx_addr_sig_regs[0][0])
-#define CRB_CTX_ADDR_REG_HI            (ctx_addr_sig_regs[0][2])
-#define CRB_CTX_SIGNATURE_REG       (ctx_addr_sig_regs[0][1])
 #endif				/* DEFINE_GLOBAL_RECEIVE_CRB */
+#define CRB_CTX_ADDR_REG_LO(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][0])
+#define CRB_CTX_ADDR_REG_HI(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][2])
+#define CRB_CTX_SIGNATURE_REG(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][1])
 
 /*
  * Temperature control.
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 8be0d03..3d5b423 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -562,7 +562,6 @@ static void ni5010_rx(struct net_device 
 		return;
 	}
 
-	skb->dev = dev;
 	skb_reserve(skb, 2);
 
 	/* Read packet into buffer */
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index a6f4b24..8dbd6d1 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -934,7 +934,6 @@ static void ni52_rcv_int(struct net_devi
 					skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
 					if(skb != NULL)
 					{
-						skb->dev = dev;
 						skb_reserve(skb,2);
 						skb_put(skb,totlen);
 						eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
@@ -1183,7 +1182,7 @@ #if(NUM_XMIT_BUFFS > 1)
 	else
 #endif
 	{
-		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+		skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len);
 		len = skb->len;
 		if (len < ETH_ZLEN) {
 			len = ETH_ZLEN;
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 1578f4d..3818edf 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -610,7 +610,6 @@ static void *ni65_alloc_mem(struct net_d
 			printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what);
 			return NULL;
 		}
-		skb->dev = dev;
 		skb_reserve(skb,2+16);
 		skb_put(skb,R_BUF_SIZE);	 /* grab the whole space .. (not necessary) */
 		ptr = skb->data;
@@ -1094,7 +1093,6 @@ #endif
 			if(skb)
 			{
 				skb_reserve(skb,2);
-	skb->dev = dev;
 #ifdef RCV_VIA_SKB
 				if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
 					skb_put(skb,len);
@@ -1178,8 +1176,9 @@ #ifdef XMT_VIA_SKB
 		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
 #endif
 
-			memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
-							 (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
+			skb_copy_from_linear_data(skb, p->tmdbounce[p->tmdbouncenum],
+				      skb->len > T_BUF_SIZE ? T_BUF_SIZE :
+							      skb->len);
 			if (len > skb->len)
 				memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len);
 			dev_kfree_skb (skb);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 9ec6e9e..3439f8c 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -104,7 +104,6 @@ #include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
 #include <linux/workqueue.h>
 #include <linux/init.h>
 #include <linux/ip.h>	/* for iph */
@@ -607,7 +606,6 @@ static inline int rx_refill(struct net_d
 		res &= 0xf;
 		skb_reserve(skb, res);
 
-		skb->dev = ndev;
 		if (gfp != GFP_ATOMIC)
 			spin_lock_irqsave(&dev->rx_info.lock, flags);
 		res = ns83820_add_rx_skb(dev, skb);
@@ -1157,9 +1155,9 @@ again:
 	extsts = 0;
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		extsts |= EXTSTS_IPPKT;
-		if (IPPROTO_TCP == skb->nh.iph->protocol)
+		if (IPPROTO_TCP == ip_hdr(skb)->protocol)
 			extsts |= EXTSTS_TCPPKT;
-		else if (IPPROTO_UDP == skb->nh.iph->protocol)
+		else if (IPPROTO_UDP == ip_hdr(skb)->protocol)
 			extsts |= EXTSTS_UDPPKT;
 	}
 
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index d670ac7..bc7f3de 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -33,6 +33,8 @@ #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
 
+#include <asm/irq.h>
+
 #include "pasemi_mac.h"
 
 
@@ -51,6 +53,16 @@ #include "pasemi_mac.h"
 #define RX_RING_SIZE 512
 #define TX_RING_SIZE 512
 
+#define DEFAULT_MSG_ENABLE	  \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_PROBE	| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_TIMER	| \
+	 NETIF_MSG_IFDOWN	| \
+	 NETIF_MSG_IFUP		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
+
 #define TX_DESC(mac, num)	((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
 #define TX_DESC_INFO(mac, num)	((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
 #define RX_DESC(mac, num)	((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
@@ -59,11 +71,13 @@ #define RX_BUFF(mac, num)	((mac)->rx->bu
 
 #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
 
-/* XXXOJN these should come out of the device tree some day */
-#define PAS_DMA_CAP_BASE   0xe00d0040
-#define PAS_DMA_CAP_SIZE   0x100
-#define PAS_DMA_COM_BASE   0xe00d0100
-#define PAS_DMA_COM_SIZE   0x100
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+static int debug = -1;	/* -1 == use DEFAULT_MSG_ENABLE as value */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
 
 static struct pasdma_status *dma_status;
 
@@ -80,7 +94,12 @@ static int pasemi_get_mac_addr(struct pa
 		return -ENOENT;
 	}
 
-	maddr = get_property(dn, "mac-address", NULL);
+	maddr = of_get_property(dn, "local-mac-address", NULL);
+
+	/* Fall back to mac-address for older firmware */
+	if (maddr == NULL)
+		maddr = of_get_property(dn, "mac-address", NULL);
+
 	if (maddr == NULL) {
 		dev_warn(&pdev->dev,
 			 "no mac address in device tree, not configuring\n");
@@ -277,8 +296,8 @@ static void pasemi_mac_free_rx_resources
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		info = &RX_DESC_INFO(mac, i);
 		dp = &RX_DESC(mac, i);
-		if (info->dma) {
-			if (info->skb) {
+		if (info->skb) {
+			if (info->dma) {
 				pci_unmap_single(mac->dma_pdev,
 						 info->dma,
 						 info->skb->len,
@@ -309,84 +328,120 @@ static void pasemi_mac_replenish_rx_ring
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int i;
 	int start = mac->rx->next_to_fill;
-	unsigned int count;
+	unsigned int limit, count;
 
-	count = (mac->rx->next_to_clean + RX_RING_SIZE -
+	limit = (mac->rx->next_to_clean + RX_RING_SIZE -
 		 mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
 
 	/* Check to see if we're doing first-time setup */
 	if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
-		count = RX_RING_SIZE;
+		limit = RX_RING_SIZE;
 
-	if (count <= 0)
+	if (limit <= 0)
 		return;
 
-	for (i = start; i < start + count; i++) {
+	i = start;
+	for (count = limit; count; count--) {
 		struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
 		u64 *buff = &RX_BUFF(mac, i);
 		struct sk_buff *skb;
 		dma_addr_t dma;
 
-		skb = dev_alloc_skb(BUF_SIZE);
+		/* skb might still be in there for recycle on short receives */
+		if (info->skb)
+			skb = info->skb;
+		else
+			skb = dev_alloc_skb(BUF_SIZE);
 
-		if (!skb) {
-			count = i - start;
+		if (unlikely(!skb))
 			break;
-		}
-
-		skb->dev = dev;
 
 		dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
 				     PCI_DMA_FROMDEVICE);
 
-		if (dma_mapping_error(dma)) {
+		if (unlikely(dma_mapping_error(dma))) {
 			dev_kfree_skb_irq(info->skb);
-			count = i - start;
 			break;
 		}
 
 		info->skb = skb;
 		info->dma = dma;
 		*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+		i++;
 	}
 
 	wmb();
 
 	pci_write_config_dword(mac->dma_pdev,
 			       PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
-			       count);
+			       limit - count);
 	pci_write_config_dword(mac->dma_pdev,
 			       PAS_DMA_RXINT_INCR(mac->dma_if),
-			       count);
+			       limit - count);
+
+	mac->rx->next_to_fill += limit - count;
+}
+
+static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
+{
+	unsigned int reg, stat;
+	/* Re-enable packet count interrupts: finally
+	 * ack the packet count interrupt we got in rx_intr.
+	 */
+
+	pci_read_config_dword(mac->iob_pdev,
+			      PAS_IOB_DMA_RXCH_STAT(mac->dma_rxch),
+			      &stat);
+
+	reg = PAS_IOB_DMA_RXCH_RESET_PCNT(stat & PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+		| PAS_IOB_DMA_RXCH_RESET_PINTC;
+
+	pci_write_config_dword(mac->iob_pdev,
+			       PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch),
+			       reg);
+}
+
+static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
+{
+	unsigned int reg, stat;
+
+	/* Re-enable packet count interrupts */
+	pci_read_config_dword(mac->iob_pdev,
+			      PAS_IOB_DMA_TXCH_STAT(mac->dma_txch), &stat);
 
-	mac->rx->next_to_fill += count;
+	reg = PAS_IOB_DMA_TXCH_RESET_PCNT(stat & PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+		| PAS_IOB_DMA_TXCH_RESET_PINTC;
+
+	pci_write_config_dword(mac->iob_pdev,
+			       PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
 }
 
+
 static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 {
-	unsigned int i;
-	int start, count;
+	unsigned int n;
+	int count;
+	struct pas_dma_xct_descr *dp;
+	struct pasemi_mac_buffer *info;
+	struct sk_buff *skb;
+	unsigned int i, len;
+	u64 macrx;
+	dma_addr_t dma;
 
 	spin_lock(&mac->rx->lock);
 
-	start = mac->rx->next_to_clean;
-	count = 0;
+	n = mac->rx->next_to_clean;
 
-	for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
-		struct pas_dma_xct_descr *dp;
-		struct pasemi_mac_buffer *info;
-		struct sk_buff *skb;
-		unsigned int j, len;
-		dma_addr_t dma;
+	for (count = limit; count; count--) {
 
 		rmb();
 
-		dp = &RX_DESC(mac, i);
+		dp = &RX_DESC(mac, n);
+		macrx = dp->macrx;
 
-		if (!(dp->macrx & XCT_MACRX_O))
+		if (!(macrx & XCT_MACRX_O))
 			break;
 
-		count++;
 
 		info = NULL;
 
@@ -398,29 +453,42 @@ static int pasemi_mac_clean_rx(struct pa
 		 */
 
 		dma = (dp->ptr & XCT_PTR_ADDR_M);
-		for (j = start; j < (start + RX_RING_SIZE); j++) {
-			info = &RX_DESC_INFO(mac, j);
+		for (i = n; i < (n + RX_RING_SIZE); i++) {
+			info = &RX_DESC_INFO(mac, i);
 			if (info->dma == dma)
 				break;
 		}
 
-		BUG_ON(!info);
-		BUG_ON(info->dma != dma);
+		skb = info->skb;
+		info->dma = 0;
 
-		pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+		pci_unmap_single(mac->dma_pdev, dma, skb->len,
 				 PCI_DMA_FROMDEVICE);
 
-		skb = info->skb;
-
-		len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+		if (len < 256) {
+			struct sk_buff *new_skb =
+			    netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+			if (new_skb) {
+				skb_reserve(new_skb, NET_IP_ALIGN);
+				memcpy(new_skb->data - NET_IP_ALIGN,
+					skb->data - NET_IP_ALIGN,
+					len + NET_IP_ALIGN);
+				/* save the skb in buffer_info as good */
+				skb = new_skb;
+			}
+			/* else just continue with the old one */
+		} else
+			info->skb = NULL;
 
 		skb_put(skb, len);
 
 		skb->protocol = eth_type_trans(skb, mac->netdev);
 
-		if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+		if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
 			skb->ip_summed = CHECKSUM_COMPLETE;
-			skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+			skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
 					   XCT_MACRX_CSUM_S;
 		} else
 			skb->ip_summed = CHECKSUM_NONE;
@@ -430,13 +498,13 @@ static int pasemi_mac_clean_rx(struct pa
 
 		netif_receive_skb(skb);
 
-		info->dma = 0;
-		info->skb = NULL;
 		dp->ptr = 0;
 		dp->macrx = 0;
+
+		n++;
 	}
 
-	mac->rx->next_to_clean += count;
+	mac->rx->next_to_clean += limit - count;
 	pasemi_mac_replenish_rx_ring(mac->netdev);
 
 	spin_unlock(&mac->rx->lock);
@@ -478,6 +546,8 @@ static int pasemi_mac_clean_tx(struct pa
 	mac->tx->next_to_clean += count;
 	spin_unlock_irqrestore(&mac->tx->lock, flags);
 
+	netif_wake_queue(mac->netdev);
+
 	return count;
 }
 
@@ -488,18 +558,28 @@ static irqreturn_t pasemi_mac_rx_intr(in
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int reg;
 
-	if (!(*mac->rx_status & PAS_STATUS_INT))
+	if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
 		return IRQ_NONE;
 
-	netif_rx_schedule(dev);
-	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
-			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+	if (*mac->rx_status & PAS_STATUS_ERROR)
+		printk("rx_status reported error\n");
+
+	/* Don't reset packet count so it won't fire again but clear
+	 * all others.
+	 */
+
+	pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &reg);
 
-	reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
-	      PAS_IOB_DMA_RXCH_RESET_DINTC;
+	reg = 0;
+	if (*mac->rx_status & PAS_STATUS_SOFT)
+		reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
+	if (*mac->rx_status & PAS_STATUS_ERROR)
+		reg |= PAS_IOB_DMA_RXCH_RESET_DINTC;
 	if (*mac->rx_status & PAS_STATUS_TIMER)
 		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
 
+	netif_rx_schedule(dev);
+
 	pci_write_config_dword(mac->iob_pdev,
 			       PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
 
@@ -512,31 +592,137 @@ static irqreturn_t pasemi_mac_tx_intr(in
 	struct net_device *dev = data;
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int reg;
-	int was_full;
 
-	was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
-
-	if (!(*mac->tx_status & PAS_STATUS_INT))
+	if (!(*mac->tx_status & PAS_STATUS_CAUSE_M))
 		return IRQ_NONE;
 
 	pasemi_mac_clean_tx(mac);
 
-	reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
-	if (*mac->tx_status & PAS_STATUS_TIMER)
-		reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+	reg = PAS_IOB_DMA_TXCH_RESET_PINTC;
+
+	if (*mac->tx_status & PAS_STATUS_SOFT)
+		reg |= PAS_IOB_DMA_TXCH_RESET_SINTC;
+	if (*mac->tx_status & PAS_STATUS_ERROR)
+		reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
 
 	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
 			       reg);
 
-	if (was_full)
-		netif_wake_queue(dev);
-
 	return IRQ_HANDLED;
 }
 
+static void pasemi_adjust_link(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	int msg;
+	unsigned int flags;
+	unsigned int new_flags;
+
+	if (!mac->phydev->link) {
+		/* If no link, MAC speed settings don't matter. Just report
+		 * link down and return.
+		 */
+		if (mac->link && netif_msg_link(mac))
+			printk(KERN_INFO "%s: Link is down.\n", dev->name);
+
+		netif_carrier_off(dev);
+		mac->link = 0;
+
+		return;
+	} else
+		netif_carrier_on(dev);
+
+	pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+	new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
+			      PAS_MAC_CFG_PCFG_TSR_M);
+
+	if (!mac->phydev->duplex)
+		new_flags |= PAS_MAC_CFG_PCFG_HD;
+
+	switch (mac->phydev->speed) {
+	case 1000:
+		new_flags |= PAS_MAC_CFG_PCFG_SPD_1G |
+			     PAS_MAC_CFG_PCFG_TSR_1G;
+		break;
+	case 100:
+		new_flags |= PAS_MAC_CFG_PCFG_SPD_100M |
+			     PAS_MAC_CFG_PCFG_TSR_100M;
+		break;
+	case 10:
+		new_flags |= PAS_MAC_CFG_PCFG_SPD_10M |
+			     PAS_MAC_CFG_PCFG_TSR_10M;
+		break;
+	default:
+		printk("Unsupported speed %d\n", mac->phydev->speed);
+	}
+
+	/* Print on link or speed/duplex change */
+	msg = mac->link != mac->phydev->link || flags != new_flags;
+
+	mac->duplex = mac->phydev->duplex;
+	mac->speed = mac->phydev->speed;
+	mac->link = mac->phydev->link;
+
+	if (new_flags != flags)
+		pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags);
+
+	if (msg && netif_msg_link(mac))
+		printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
+		       dev->name, mac->speed, mac->duplex ? "full" : "half");
+}
+
+static int pasemi_mac_phy_init(struct net_device *dev)
+{
+	struct pasemi_mac *mac = netdev_priv(dev);
+	struct device_node *dn, *phy_dn;
+	struct phy_device *phydev;
+	unsigned int phy_id;
+	const phandle *ph;
+	const unsigned int *prop;
+	struct resource r;
+	int ret;
+
+	dn = pci_device_to_OF_node(mac->pdev);
+	ph = of_get_property(dn, "phy-handle", NULL);
+	if (!ph)
+		return -ENODEV;
+	phy_dn = of_find_node_by_phandle(*ph);
+
+	prop = of_get_property(phy_dn, "reg", NULL);
+	ret = of_address_to_resource(phy_dn->parent, 0, &r);
+	if (ret)
+		goto err;
+
+	phy_id = *prop;
+	snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id);
+
+	of_node_put(phy_dn);
+
+	mac->link = 0;
+	mac->speed = 0;
+	mac->duplex = -1;
+
+	phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII);
+
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	mac->phydev = phydev;
+
+	return 0;
+
+err:
+	of_node_put(phy_dn);
+	return -ENODEV;
+}
+
+
 static int pasemi_mac_open(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
+	int base_irq;
 	unsigned int flags;
 	int ret;
 
@@ -560,10 +746,18 @@ static int pasemi_mac_open(struct net_de
 	flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
 
 	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
-			       PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+			       PAS_IOB_DMA_RXCH_CFG_CNTTH(1));
 
+	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
+			       PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
+
+	/* Clear out any residual packet count state from firmware */
+	pasemi_mac_restart_rx_intr(mac);
+	pasemi_mac_restart_tx_intr(mac);
+
+	/* 0xffffff is max value, about 16ms */
 	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
-			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
 
 	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
 
@@ -597,31 +791,50 @@ static int pasemi_mac_open(struct net_de
 
 	pasemi_mac_replenish_rx_ring(dev);
 
+	ret = pasemi_mac_phy_init(dev);
+	/* Some configs don't have PHYs (XAUI etc), so don't complain about
+	 * failed init due to -ENODEV.
+	 */
+	if (ret && ret != -ENODEV)
+		dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
+
 	netif_start_queue(dev);
 	netif_poll_enable(dev);
 
-	ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
-			  &pasemi_mac_tx_intr, IRQF_DISABLED,
+	/* Interrupts are a bit different for our DMA controller: While
+	 * it's got one a regular PCI device header, the interrupt there
+	 * is really the base of the range it's using. Each tx and rx
+	 * channel has it's own interrupt source.
+	 */
+
+	base_irq = virq_to_hw(mac->dma_pdev->irq);
+
+	mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch);
+	mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch);
+
+	ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED,
 			  mac->tx->irq_name, dev);
 	if (ret) {
 		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
-		       mac->dma_pdev->irq + mac->dma_txch, ret);
+			base_irq + mac->dma_txch, ret);
 		goto out_tx_int;
 	}
 
-	ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
-			  &pasemi_mac_rx_intr, IRQF_DISABLED,
+	ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED,
 			  mac->rx->irq_name, dev);
 	if (ret) {
 		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
-		       mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+			base_irq + 20 + mac->dma_rxch, ret);
 		goto out_rx_int;
 	}
 
+	if (mac->phydev)
+		phy_start(mac->phydev);
+
 	return 0;
 
 out_rx_int:
-	free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+	free_irq(mac->tx_irq, dev);
 out_tx_int:
 	netif_poll_disable(dev);
 	netif_stop_queue(dev);
@@ -641,6 +854,11 @@ static int pasemi_mac_close(struct net_d
 	unsigned int stat;
 	int retries;
 
+	if (mac->phydev) {
+		phy_stop(mac->phydev);
+		phy_disconnect(mac->phydev);
+	}
+
 	netif_stop_queue(dev);
 
 	/* Clean out any pending buffers */
@@ -662,40 +880,37 @@ static int pasemi_mac_close(struct net_d
 		pci_read_config_dword(mac->dma_pdev,
 				      PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
 				      &stat);
-		if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+		if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+	if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
-	}
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
 		pci_read_config_dword(mac->dma_pdev,
 				      PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
 				      &stat);
-		if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+		if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+	if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
-	}
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
 		pci_read_config_dword(mac->dma_pdev,
 				      PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
 				      &stat);
-		if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+		if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+	if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
-	}
 
 	/* Then, disable the channel. This must be done separately from
 	 * stopping, since you can't disable when active.
@@ -708,8 +923,8 @@ static int pasemi_mac_close(struct net_d
 	pci_write_config_dword(mac->dma_pdev,
 			       PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
 
-	free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
-	free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+	free_irq(mac->tx_irq, dev);
+	free_irq(mac->rx_irq, dev);
 
 	/* Free resources */
 	pasemi_mac_free_rx_resources(dev);
@@ -731,16 +946,18 @@ static int pasemi_mac_start_tx(struct sk
 	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		switch (skb->nh.iph->protocol) {
+		const unsigned char *nh = skb_network_header(skb);
+
+		switch (ip_hdr(skb)->protocol) {
 		case IPPROTO_TCP:
 			dflags |= XCT_MACTX_CSUM_TCP;
-			dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
-			dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+			dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2);
+			dflags |= XCT_MACTX_IPO(nh - skb->data);
 			break;
 		case IPPROTO_UDP:
 			dflags |= XCT_MACTX_CSUM_UDP;
-			dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
-			dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+			dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2);
+			dflags |= XCT_MACTX_IPO(nh - skb->data);
 			break;
 		}
 	}
@@ -802,6 +1019,7 @@ static struct net_device_stats *pasemi_m
 	return &mac->stats;
 }
 
+
 static void pasemi_mac_set_rx_mode(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
@@ -826,18 +1044,17 @@ static int pasemi_mac_poll(struct net_de
 
 	pkts = pasemi_mac_clean_rx(mac, limit);
 
+	dev->quota -= pkts;
+	*budget -= pkts;
+
 	if (pkts < limit) {
 		/* all done, no more packets present */
 		netif_rx_complete(dev);
 
-		/* re-enable receive interrupts */
-		pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
-				       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+		pasemi_mac_restart_rx_intr(mac);
 		return 0;
 	} else {
 		/* used up our quantum, so reschedule */
-		dev->quota -= pkts;
-		*budget -= pkts;
 		return 1;
 	}
 }
@@ -937,6 +1154,11 @@ pasemi_mac_probe(struct pci_dev *pdev, c
 	mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
 	mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
 
+	mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+
+	/* Enable most messages by default */
+	mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
 	err = register_netdev(dev);
 
 	if (err) {
@@ -1011,9 +1233,5 @@ int pasemi_mac_init_module(void)
 	return pci_register_driver(&pasemi_mac_driver);
 }
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
-MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
-
 module_init(pasemi_mac_init_module);
 module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index c3e37e4..8bc0cea 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -24,6 +24,7 @@ #define PASEMI_MAC_H
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
+#include <linux/phy.h>
 
 struct pasemi_mac_txring {
 	spinlock_t	 lock;
@@ -54,6 +55,7 @@ struct pasemi_mac {
 	struct pci_dev *pdev;
 	struct pci_dev *dma_pdev;
 	struct pci_dev *iob_pdev;
+	struct phy_device *phydev;
 	struct net_device_stats stats;
 
 	/* Pointer to the cacheable per-channel status registers */
@@ -73,6 +75,14 @@ #define MAC_TYPE_XAUI	2
 
 	struct pasemi_mac_txring *tx;
 	struct pasemi_mac_rxring *rx;
+	unsigned long	tx_irq;
+	unsigned long	rx_irq;
+	int	link;
+	int	speed;
+	int	duplex;
+
+	unsigned int	msg_enable;
+	char	phy_id[BUS_ID_SIZE];
 };
 
 /* Software status descriptor (desc_info) */
@@ -193,11 +203,15 @@ #define _PAS_DMA_RXINT_STRIDE		0x20
 #define PAS_DMA_RXINT_RCMDSTA(i)	(0x200+(i)*_PAS_DMA_RXINT_STRIDE)
 #define    PAS_DMA_RXINT_RCMDSTA_EN	0x00000001
 #define    PAS_DMA_RXINT_RCMDSTA_ST	0x00000002
-#define    PAS_DMA_RXINT_RCMDSTA_OO	0x00000100
-#define    PAS_DMA_RXINT_RCMDSTA_BP	0x00000200
-#define    PAS_DMA_RXINT_RCMDSTA_DR	0x00000400
+#define    PAS_DMA_RXINT_RCMDSTA_MBT	0x00000008
+#define    PAS_DMA_RXINT_RCMDSTA_MDR	0x00000010
+#define    PAS_DMA_RXINT_RCMDSTA_MOO	0x00000020
+#define    PAS_DMA_RXINT_RCMDSTA_MBP	0x00000040
 #define    PAS_DMA_RXINT_RCMDSTA_BT	0x00000800
-#define    PAS_DMA_RXINT_RCMDSTA_TB	0x00001000
+#define    PAS_DMA_RXINT_RCMDSTA_DR	0x00001000
+#define    PAS_DMA_RXINT_RCMDSTA_OO	0x00002000
+#define    PAS_DMA_RXINT_RCMDSTA_BP	0x00004000
+#define    PAS_DMA_RXINT_RCMDSTA_TB	0x00008000
 #define    PAS_DMA_RXINT_RCMDSTA_ACT	0x00010000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
@@ -297,6 +311,7 @@ #define    PAS_STATUS_DCNT_M		0x00000000
 #define    PAS_STATUS_DCNT_S		16
 #define    PAS_STATUS_BPCNT_M		0x0000ffff00000000ull
 #define    PAS_STATUS_BPCNT_S		32
+#define    PAS_STATUS_CAUSE_M		0xf000000000000000ull
 #define    PAS_STATUS_TIMER		0x1000000000000000ull
 #define    PAS_STATUS_ERROR		0x2000000000000000ull
 #define    PAS_STATUS_SOFT		0x4000000000000000ull
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 6ca4e4f..df8998b 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1344,7 +1344,7 @@ static int netdrv_start_xmit (struct sk_
 
 	tp->tx_info[entry].skb = skb;
 	/* tp->tx_info[entry].mapping = 0; */
-	memcpy (tp->tx_buf[entry], skb->data, skb->len);
+	skb_copy_from_linear_data(skb, tp->tx_buf[entry], skb->len);
 
 	/* Note: the chip doesn't have auto-pad! */
 	NETDRV_W32 (TxStatus0 + (entry * sizeof(u32)),
@@ -1565,7 +1565,6 @@ #endif
 
 		skb = dev_alloc_skb (pkt_size + 2);
 		if (skb) {
-			skb->dev = dev;
 			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
 
 			eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index c7bd9c1..2b395ee 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -1056,7 +1056,6 @@ static int el3_rx(struct net_device *dev
 			DEBUG(3, "  Receiving packet size %d status %4.4x.\n",
 				  pkt_len, rx_status);
 			if (skb != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);
 				insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
 						((pkt_len+3)>>2));
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 461e827..143ae2f 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -883,7 +883,6 @@ static int el3_rx(struct net_device *dev
 	    DEBUG(3, "    Receiving packet size %d status %4.4x.\n",
 		  pkt_len, rx_status);
 	    if (skb != NULL) {
-		skb->dev = dev;
 		skb_reserve(skb, 2);
 		insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
 			(pkt_len+3)>>2);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 6139048..808fae1 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1136,7 +1136,7 @@ static int ei_start_xmit(struct sk_buff 
 		ei_block_output(dev, length, skb->data, output_page);
 	else {
 		memset(packet, 0, ETH_ZLEN);
-		memcpy(packet, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, packet, skb->len);
 		ei_block_output(dev, length, packet, output_page);
 	}
 	
@@ -1496,7 +1496,6 @@ static void ei_receive(struct net_device
 			else
 			{
 				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
-				skb->dev = dev;
 				skb_put(skb, pkt_len);	/* Make room */
 				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
 				skb->protocol=eth_type_trans(skb,dev);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 0d7de61..3f93d49 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -999,7 +999,6 @@ #endif
 		lp->stats.rx_dropped++;
 		break;
 	    }
-	    skb->dev = dev;
 
 	    skb_reserve(skb, 2);
 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 3b70774..73da611 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1182,12 +1182,10 @@ static int mace_rx(struct net_device *de
       skb = dev_alloc_skb(pkt_len+2);
 
       if (skb != NULL) {
-	skb->dev = dev;
-
 	skb_reserve(skb, 2);
 	insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1);
 	if (pkt_len & 1)
-	    *(skb->tail-1) = inb(ioaddr + AM2150_RCV);
+	    *(skb_tail_pointer(skb) - 1) = inb(ioaddr + AM2150_RCV);
 	skb->protocol = eth_type_trans(skb, dev);
 	
 	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 2561f76..7912dbd 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1669,7 +1669,6 @@ static void smc_rx(struct net_device *de
 	     (packet_length+1)>>1);
 	skb->protocol = eth_type_trans(skb, dev);
 	
-	skb->dev = dev;
 	netif_rx(skb);
 	dev->last_rx = jiffies;
 	smc->stats.rx_packets++;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 5879e7c..258d6f3 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1226,7 +1226,6 @@ xirc2ps_interrupt(int irq, void *dev_id)
 			    (pktlen+1)>>1);
 		}
 		skb->protocol = eth_type_trans(skb, dev);
-		skb->dev = dev;
 		netif_rx(skb);
 		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
@@ -1421,7 +1420,7 @@ set_addresses(struct net_device *dev)
     kio_addr_t ioaddr = dev->base_addr;
     local_info_t *lp = netdev_priv(dev);
     struct dev_mc_list *dmi = dev->mc_list;
-    char *addr;
+    unsigned char *addr;
     int i,j,k,n;
 
     SelectPage(k=0x50);
@@ -1430,6 +1429,9 @@ set_addresses(struct net_device *dev)
 	    if (++n > 9)
 		break;
 	    i = 0;
+	    if (n > 1 && n <= dev->mc_count && dmi) {
+	   	 dmi = dmi->next;
+	    }
 	}
 	if (j > 15) {
 	    j = 8;
@@ -1437,10 +1439,9 @@ set_addresses(struct net_device *dev)
 	    SelectPage(k);
 	}
 
-	if (n && n <= dev->mc_count && dmi) {
+	if (n && n <= dev->mc_count && dmi)
 	    addr = dmi->dmi_addr;
-	    dmi = dmi->next;
-	} else
+	else
 	    addr = dev->dev_addr;
 
 	if (lp->mohawk)
@@ -1466,10 +1467,10 @@ set_multicast_list(struct net_device *de
     if (dev->flags & IFF_PROMISC) { /* snoop */
 	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */
     } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) {
-	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */
+	PutByte(XIRCREG42_SWC1, 0x02); /* set MPE */
     } else if (dev->mc_count) {
 	/* the chip can filter 9 addresses perfectly */
-	PutByte(XIRCREG42_SWC1, 0x00);
+	PutByte(XIRCREG42_SWC1, 0x01);
 	SelectPage(0x40);
 	PutByte(XIRCREG40_CMD0, Offline);
 	set_addresses(dev);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 4d94ba7..9c171a7 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -253,12 +253,12 @@ struct pcnet32_access {
  * so the structure should be allocated using pci_alloc_consistent().
  */
 struct pcnet32_private {
-	struct pcnet32_init_block init_block;
+	struct pcnet32_init_block *init_block;
 	/* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
 	struct pcnet32_rx_head	*rx_ring;
 	struct pcnet32_tx_head	*tx_ring;
-	dma_addr_t		dma_addr;/* DMA address of beginning of this
-				   object, returned by pci_alloc_consistent */
+	dma_addr_t		init_dma_addr;/* DMA address of beginning of the init block,
+				   returned by pci_alloc_consistent */
 	struct pci_dev		*pci_dev;
 	const char		*name;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(stru
 
 static void pcnet32_purge_rx_ring(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int i;
 
 	/* free all allocated skbuffs */
@@ -681,7 +681,7 @@ #endif
 
 static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int r = -EOPNOTSUPP;
 
@@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct n
 
 static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int r = -EOPNOTSUPP;
 
@@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct n
 static void pcnet32_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct n
 
 static u32 pcnet32_get_link(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int r;
 
@@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_d
 
 static u32 pcnet32_get_msglevel(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	return lp->msg_enable;
 }
 
 static void pcnet32_set_msglevel(struct net_device *dev, u32 value)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	lp->msg_enable = value;
 }
 
 static int pcnet32_nway_reset(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	int r = -EOPNOTSUPP;
 
@@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net
 static void pcnet32_get_ringparam(struct net_device *dev,
 				  struct ethtool_ringparam *ering)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 
 	ering->tx_max_pending = TX_MAX_RING_SIZE;
 	ering->tx_pending = lp->tx_ring_size;
@@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct
 static int pcnet32_set_ringparam(struct net_device *dev,
 				 struct ethtool_ringparam *ering)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 	unsigned int size;
 	ulong ioaddr = dev->base_addr;
@@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struc
 static void pcnet32_ethtool_test(struct net_device *dev,
 				 struct ethtool_test *test, u64 * data)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int rc;
 
 	if (test->flags == ETH_TEST_FL_OFFLINE) {
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct 
 
 static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct pcnet32_access *a = &lp->a;	/* access to registers */
 	ulong ioaddr = dev->base_addr;	/* card base I/O address */
 	struct sk_buff *skb;	/* sk buff */
@@ -1047,7 +1047,7 @@ #endif
 
 static void pcnet32_led_blink_callback(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct pcnet32_access *a = &lp->a;
 	ulong ioaddr = dev->base_addr;
 	unsigned long flags;
@@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(s
 
 static int pcnet32_phys_id(struct net_device *dev, u32 data)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct pcnet32_access *a = &lp->a;
 	ulong ioaddr = dev->base_addr;
 	unsigned long flags;
@@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_de
 		int can_sleep)
 {
 	int csr5;
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct pcnet32_access *a = &lp->a;
 	ulong ioaddr = dev->base_addr;
 	int ticks;
@@ -1206,7 +1206,6 @@ static void pcnet32_rx_entry(struct net_
 					 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,
@@ -1258,7 +1257,7 @@ #endif
 
 static int pcnet32_rx(struct net_device *dev, int quota)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int entry = lp->cur_rx & lp->rx_mod_mask;
 	struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
 	int npackets = 0;
@@ -1283,7 +1282,7 @@ static int pcnet32_rx(struct net_device 
 
 static int pcnet32_tx(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned int dirty_tx = lp->dirty_tx;
 	int delta;
 	int must_restart = 0;
@@ -1382,7 +1381,7 @@ #endif
 #ifdef CONFIG_PCNET32_NAPI
 static int pcnet32_poll(struct net_device *dev, int *budget)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int quota = min(dev->quota, *budget);
 	unsigned long ioaddr = dev->base_addr;
 	unsigned long flags;
@@ -1429,7 +1428,7 @@ #define PCNET32_REGS_PER_PHY	32
 #define PCNET32_MAX_PHYS	32
 static int pcnet32_get_regs_len(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int j = lp->phycount * PCNET32_REGS_PER_PHY;
 
 	return ((PCNET32_NUM_REGS + j) * sizeof(u16));
@@ -1440,7 +1439,7 @@ static void pcnet32_get_regs(struct net_
 {
 	int i, csr0;
 	u16 *buff = ptr;
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct pcnet32_access *a = &lp->a;
 	ulong ioaddr = dev->base_addr;
 	unsigned long flags;
@@ -1593,7 +1592,6 @@ static int __devinit
 pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
 	struct pcnet32_private *lp;
-	dma_addr_t lp_dma_addr;
 	int i, media;
 	int fdx, mii, fset, dxsuflo;
 	int chip_version;
@@ -1715,7 +1713,7 @@ pcnet32_probe1(unsigned long ioaddr, int
 		dxsuflo = 1;
 	}
 
-	dev = alloc_etherdev(0);
+	dev = alloc_etherdev(sizeof(*lp));
 	if (!dev) {
 		if (pcnet32_debug & NETIF_MSG_PROBE)
 			printk(KERN_ERR PFX "Memory allocation failed.\n");
@@ -1806,25 +1804,22 @@ pcnet32_probe1(unsigned long ioaddr, int
 	}
 
 	dev->base_addr = ioaddr;
+	lp = netdev_priv(dev);
 	/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
-	if ((lp =
-	     pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+	if ((lp->init_block =
+	     pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {
 		if (pcnet32_debug & NETIF_MSG_PROBE)
 			printk(KERN_ERR PFX
 			       "Consistent memory allocation failed.\n");
 		ret = -ENOMEM;
 		goto err_free_netdev;
 	}
-
-	memset(lp, 0, sizeof(*lp));
-	lp->dma_addr = lp_dma_addr;
 	lp->pci_dev = pdev;
 
 	spin_lock_init(&lp->lock);
 
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
-	dev->priv = lp;
 	lp->name = chipname;
 	lp->shared_irq = shared;
 	lp->tx_ring_size = TX_RING_SIZE;	/* default tx ring size */
@@ -1871,23 +1866,21 @@ pcnet32_probe1(unsigned long ioaddr, int
 	    && dev->dev_addr[2] == 0x75)
 		lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
 
-	lp->init_block.mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
-	lp->init_block.tlen_rlen =
+	lp->init_block->mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
+	lp->init_block->tlen_rlen =
 	    le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
 	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-	lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+		lp->init_block->phys_addr[i] = dev->dev_addr[i];
+	lp->init_block->filter[0] = 0x00000000;
+	lp->init_block->filter[1] = 0x00000000;
+	lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+	lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
 
 	/* switch pcnet32 to 32bit mode */
 	a->write_bcr(ioaddr, 20, 2);
 
-	a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private,
-							 init_block)) & 0xffff);
-	a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
-							 init_block)) >> 16);
+	a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+	a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
 
 	if (pdev) {		/* use the IRQ provided by PCI */
 		dev->irq = pdev->irq;
@@ -1993,7 +1986,8 @@ #endif
       err_free_ring:
 	pcnet32_free_ring(dev);
       err_free_consistent:
-	pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+	pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+			    lp->init_block, lp->init_dma_addr);
       err_free_netdev:
 	free_netdev(dev);
       err_release_region:
@@ -2004,7 +1998,7 @@ #endif
 /* if any allocation fails, caller must also call pcnet32_free_ring */
 static int pcnet32_alloc_ring(struct net_device *dev, char *name)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 
 	lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
 					   sizeof(struct pcnet32_tx_head) *
@@ -2071,7 +2065,7 @@ static int pcnet32_alloc_ring(struct net
 
 static void pcnet32_free_ring(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 
 	kfree(lp->tx_skbuff);
 	lp->tx_skbuff = NULL;
@@ -2104,7 +2098,7 @@ static void pcnet32_free_ring(struct net
 
 static int pcnet32_open(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 val;
 	int i;
@@ -2135,8 +2129,7 @@ static int pcnet32_open(struct net_devic
 		       "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
 		       dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr),
 		       (u32) (lp->rx_ring_dma_addr),
-		       (u32) (lp->dma_addr +
-			      offsetof(struct pcnet32_private, init_block)));
+		       (u32) (lp->init_dma_addr));
 
 	/* set/reset autoselect bit */
 	val = lp->a.read_bcr(ioaddr, 2) & ~2;
@@ -2275,7 +2268,7 @@ #ifdef DO_DXSUFLO
 	}
 #endif
 
-	lp->init_block.mode =
+	lp->init_block->mode =
 	    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
 	pcnet32_load_multicast(dev);
 
@@ -2285,12 +2278,8 @@ #endif
 	}
 
 	/* Re-initialize the PCNET32, and start it when done. */
-	lp->a.write_csr(ioaddr, 1, (lp->dma_addr +
-				    offsetof(struct pcnet32_private,
-					     init_block)) & 0xffff);
-	lp->a.write_csr(ioaddr, 2,
-			(lp->dma_addr +
-			 offsetof(struct pcnet32_private, init_block)) >> 16);
+	lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+	lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
 
 	lp->a.write_csr(ioaddr, CSR4, 0x0915);	/* auto tx pad */
 	lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
@@ -2317,8 +2306,7 @@ #endif
 		printk(KERN_DEBUG
 		       "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
 		       dev->name, i,
-		       (u32) (lp->dma_addr +
-			      offsetof(struct pcnet32_private, init_block)),
+		       (u32) (lp->init_dma_addr),
 		       lp->a.read_csr(ioaddr, CSR0));
 
 	spin_unlock_irqrestore(&lp->lock, flags);
@@ -2356,7 +2344,7 @@ #endif
 
 static void pcnet32_purge_tx_ring(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int i;
 
 	for (i = 0; i < lp->tx_ring_size; i++) {
@@ -2376,7 +2364,7 @@ static void pcnet32_purge_tx_ring(struct
 /* Initialize the PCNET32 Rx and Tx rings. */
 static int pcnet32_init_ring(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int i;
 
 	lp->tx_full = 0;
@@ -2418,12 +2406,12 @@ static int pcnet32_init_ring(struct net_
 		lp->tx_dma_addr[i] = 0;
 	}
 
-	lp->init_block.tlen_rlen =
+	lp->init_block->tlen_rlen =
 	    le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
 	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-	lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+		lp->init_block->phys_addr[i] = dev->dev_addr[i];
+	lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+	lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
 	wmb();			/* Make sure all changes are visible */
 	return 0;
 }
@@ -2434,7 +2422,7 @@ static int pcnet32_init_ring(struct net_
  */
 static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	int i;
 
@@ -2464,7 +2452,7 @@ static void pcnet32_restart(struct net_d
 
 static void pcnet32_tx_timeout(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr, flags;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -2505,7 +2493,7 @@ static void pcnet32_tx_timeout(struct ne
 
 static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 status;
 	int entry;
@@ -2570,7 +2558,7 @@ pcnet32_interrupt(int irq, void *dev_id)
 	int boguscnt = max_interrupt_work;
 
 	ioaddr = dev->base_addr;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	spin_lock(&lp->lock);
 
@@ -2652,7 +2640,7 @@ #endif
 static int pcnet32_close(struct net_device *dev)
 {
 	unsigned long ioaddr = dev->base_addr;
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	del_timer_sync(&lp->watchdog_timer);
@@ -2693,7 +2681,7 @@ static int pcnet32_close(struct net_devi
 
 static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -2707,8 +2695,8 @@ static struct net_device_stats *pcnet32_
 /* taken from the sunlance driver, which it took from the depca driver */
 static void pcnet32_load_multicast(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
-	volatile struct pcnet32_init_block *ib = &lp->init_block;
+	struct pcnet32_private *lp = netdev_priv(dev);
+	volatile struct pcnet32_init_block *ib = lp->init_block;
 	volatile u16 *mcast_table = (u16 *) & ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	unsigned long ioaddr = dev->base_addr;
@@ -2757,7 +2745,7 @@ static void pcnet32_load_multicast(struc
 static void pcnet32_set_multicast_list(struct net_device *dev)
 {
 	unsigned long ioaddr = dev->base_addr, flags;
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int csr15, suspended;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -2768,12 +2756,12 @@ static void pcnet32_set_multicast_list(s
 		if (netif_msg_hw(lp))
 			printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
 			       dev->name);
-		lp->init_block.mode =
+		lp->init_block->mode =
 		    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
 				7);
 		lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
 	} else {
-		lp->init_block.mode =
+		lp->init_block->mode =
 		    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
 		lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
 		pcnet32_load_multicast(dev);
@@ -2796,7 +2784,7 @@ static void pcnet32_set_multicast_list(s
 /* This routine assumes that the lp->lock is held */
 static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 	u16 val_out;
 
@@ -2812,7 +2800,7 @@ static int mdio_read(struct net_device *
 /* This routine assumes that the lp->lock is held */
 static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long ioaddr = dev->base_addr;
 
 	if (!lp->mii)
@@ -2824,7 +2812,7 @@ static void mdio_write(struct net_device
 
 static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int rc;
 	unsigned long flags;
 
@@ -2842,7 +2830,7 @@ static int pcnet32_ioctl(struct net_devi
 
 static int pcnet32_check_otherphy(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	struct mii_if_info mii = lp->mii_if;
 	u16 bmcr;
 	int i;
@@ -2889,7 +2877,7 @@ static int pcnet32_check_otherphy(struct
 
 static void pcnet32_check_media(struct net_device *dev, int verbose)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	int curr_link;
 	int prev_link = netif_carrier_ok(dev) ? 1 : 0;
 	u32 bcr9;
@@ -2945,7 +2933,7 @@ static void pcnet32_check_media(struct n
 
 static void pcnet32_watchdog(struct net_device *dev)
 {
-	struct pcnet32_private *lp = dev->priv;
+	struct pcnet32_private *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Print the link status if it has changed */
@@ -2961,12 +2949,13 @@ static void __devexit pcnet32_remove_one
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct pcnet32_private *lp = dev->priv;
+		struct pcnet32_private *lp = netdev_priv(dev);
 
 		unregister_netdev(dev);
 		pcnet32_free_ring(dev);
 		release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
-		pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+		pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+				    lp->init_block, lp->init_dma_addr);
 		free_netdev(dev);
 		pci_disable_device(pdev);
 		pci_set_drvdata(pdev, NULL);
@@ -3041,12 +3030,13 @@ static void __exit pcnet32_cleanup_modul
 	struct net_device *next_dev;
 
 	while (pcnet32_dev) {
-		struct pcnet32_private *lp = pcnet32_dev->priv;
+		struct pcnet32_private *lp = netdev_priv(pcnet32_dev);
 		next_dev = lp->next;
 		unregister_netdev(pcnet32_dev);
 		pcnet32_free_ring(pcnet32_dev);
 		release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-		pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+		pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+				    lp->init_block, lp->init_dma_addr);
 		free_netdev(pcnet32_dev);
 		pcnet32_dev = next_dev;
 	}
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 66da91b..68c99b4 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -276,21 +276,15 @@ static int fixed_mdio_register_device(in
 	   artificially, we are binding the driver here by hand;
 	   it will be the same for all the fixed phys anyway.
 	 */
-	down_write(&phydev->dev.bus->subsys.rwsem);
-
 	phydev->dev.driver = &fixed_mdio_driver.driver;
 
 	err = phydev->dev.driver->probe(&phydev->dev);
 	if(err < 0) {
 		printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
-		up_write(&phydev->dev.bus->subsys.rwsem);
 		goto probe_fail;
 	}
 
 	err = device_bind_driver(&phydev->dev);
-
-	up_write(&phydev->dev.bus->subsys.rwsem);
-
 	if (err)
 		goto probe_fail;
 
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index b31ce27..fc4aee9 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -35,10 +35,14 @@ #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-/* mdiobus_register 
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
  *
- * description: Called by a bus driver to bring up all the PHYs
- *   on a given bus, and attach them to the bus
+ * Description: Called by a bus driver to bring up all the PHYs
+ *   on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
  */
 int mdiobus_register(struct mii_bus *bus)
 {
@@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus *
 }
 EXPORT_SYMBOL(mdiobus_unregister);
 
-/* mdio_bus_match
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
  *
- * description: Given a PHY device, and a PHY driver, return 1 if
- *   the driver supports the device.  Otherwise, return 0
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ *   the driver supports the device.  Otherwise, return 0.
  */
 static int mdio_bus_match(struct device *dev, struct device_driver *drv)
 {
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c94a1fb..eed433d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -39,7 +39,9 @@ #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-/* Convenience function to print out the current phy status
+/**
+ * phy_print_status - Convenience function to print out the current phy status
+ * @phydev: the phy_device struct
  */
 void phy_print_status(struct phy_device *phydev)
 {
@@ -55,10 +57,15 @@ void phy_print_status(struct phy_device 
 EXPORT_SYMBOL(phy_print_status);
 
 
-/* Convenience functions for reading/writing a given PHY
- * register. They MUST NOT be called from interrupt context,
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
  * because the bus read/write functions may wait for an interrupt
- * to conclude the operation. */
+ * to conclude the operation.
+ */
 int phy_read(struct phy_device *phydev, u16 regnum)
 {
 	int retval;
@@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, 
 }
 EXPORT_SYMBOL(phy_read);
 
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
 int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
 {
 	int err;
@@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev,
 }
 EXPORT_SYMBOL(phy_write);
 
-
+/**
+ * phy_clear_interrupt - Ack the phy device's interrupt
+ * @phydev: the phy_device struct
+ *
+ * If the @phydev driver has an ack_interrupt function, call it to
+ * ack and clear the phy device's interrupt.
+ *
+ * Returns 0 on success on < 0 on error.
+ */
 int phy_clear_interrupt(struct phy_device *phydev)
 {
 	int err = 0;
@@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_devic
 	return err;
 }
 
-
+/**
+ * phy_config_interrupt - configure the PHY device for the requested interrupts
+ * @phydev: the phy_device struct
+ * @interrupts: interrupt flags to configure for this @phydev
+ *
+ * Returns 0 on success on < 0 on error.
+ */
 int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
 {
 	int err = 0;
@@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_devi
 }
 
 
-/* phy_aneg_done
+/**
+ * phy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
  *
- * description: Reads the status register and returns 0 either if
+ * Description: Reads the status register and returns 0 either if
  *   auto-negotiation is incomplete, or if there was an error.
  *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
  */
@@ -173,9 +206,12 @@ static const struct phy_setting settings
 
 #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
 
-/* phy_find_setting
+/**
+ * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * @speed: speed to match
+ * @duplex: duplex to match
  *
- * description: Searches the settings array for the setting which
+ * Description: Searches the settings array for the setting which
  *   matches the desired speed and duplex, and returns the index
  *   of that setting.  Returns the index of the last setting if
  *   none of the others match.
@@ -192,11 +228,12 @@ static inline int phy_find_setting(int s
 	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
-/* phy_find_valid
- * idx: The first index in settings[] to search
- * features: A mask of the valid settings
+/**
+ * phy_find_valid - find a PHY setting that matches the requested features mask
+ * @idx: The first index in settings[] to search
+ * @features: A mask of the valid settings
  *
- * description: Returns the index of the first valid setting less
+ * Description: Returns the index of the first valid setting less
  *   than or equal to the one pointed to by idx, as determined by
  *   the mask in features.  Returns the index of the last setting
  *   if nothing else matches.
@@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx
 	return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
 }
 
-/* phy_sanitize_settings
+/**
+ * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
+ * @phydev: the target phy_device struct
  *
- * description: Make sure the PHY is set to supported speeds and
+ * Description: Make sure the PHY is set to supported speeds and
  *   duplexes.  Drop down by one in this order:  1000/FULL,
- *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
+ *   1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
  */
 void phy_sanitize_settings(struct phy_device *phydev)
 {
@@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_de
 }
 EXPORT_SYMBOL(phy_sanitize_settings);
 
-/* phy_ethtool_sset:
- * A generic ethtool sset function.  Handles all the details
+/**
+ * phy_ethtool_sset - generic ethtool sset function, handles all the details
+ * @phydev: target phy_device struct
+ * @cmd: ethtool_cmd
  *
  * A few notes about parameter checking:
  * - We don't set port or transceiver, so we don't care what they
  *   were set to.
  * - phy_start_aneg() will make sure forced settings are sane, and
  *   choose the next best ones from the ones selected, so we don't
- *   care if ethtool tries to give us bad values
- *
+ *   care if ethtool tries to give us bad values.
  */
 int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
 {
@@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device *
 }
 EXPORT_SYMBOL(phy_ethtool_gset);
 
-/* Note that this function is currently incompatible with the
+/**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+ * @mii_data: MII ioctl data
+ * @cmd: ioctl cmd to execute
+ *
+ * Note that this function is currently incompatible with the
  * PHYCONTROL layer.  It changes registers without regard to
- * current state.  Use at own risk
+ * current state.  Use at own risk.
  */
 int phy_mii_ioctl(struct phy_device *phydev,
 		struct mii_ioctl_data *mii_data, int cmd)
@@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phy
 					phydev->duplex = DUPLEX_FULL;
 				else
 					phydev->duplex = DUPLEX_HALF;
+				if ((!phydev->autoneg) &&
+						(val & BMCR_SPEED1000))
+					phydev->speed = SPEED_1000;
+				else if ((!phydev->autoneg) &&
+						(val & BMCR_SPEED100))
+					phydev->speed = SPEED_100;
 				break;
 			case MII_ADVERTISE:
 				phydev->advertising = val;
@@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phy
 	return 0;
 }
 
-/* phy_start_aneg
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
  *
- * description: Sanitizes the settings (if we're not
- *   autonegotiating them), and then calls the driver's
- *   config_aneg function.  If the PHYCONTROL Layer is operating,
- *   we change the state to reflect the beginning of
- *   Auto-negotiation or forcing.
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ *   them), and then calls the driver's config_aneg function.
+ *   If the PHYCONTROL Layer is operating, we change the state to
+ *   reflect the beginning of Auto-negotiation or forcing.
  */
 int phy_start_aneg(struct phy_device *phydev)
 {
@@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg);
 static void phy_change(struct work_struct *work);
 static void phy_timer(unsigned long data);
 
-/* phy_start_machine:
+/**
+ * phy_start_machine - start PHY state machine tracking
+ * @phydev: the phy_device struct
+ * @handler: callback function for state change notifications
  *
- * description: The PHY infrastructure can run a state machine
+ * Description: The PHY infrastructure can run a state machine
  *   which tracks whether the PHY is starting up, negotiating,
  *   etc.  This function starts the timer which tracks the state
- *   of the PHY.  If you want to be notified when the state
- *   changes, pass in the callback, otherwise, pass NULL.  If you
+ *   of the PHY.  If you want to be notified when the state changes,
+ *   pass in the callback @handler, otherwise, pass NULL.  If you
  *   want to maintain your own state machine, do not call this
- *   function. */
+ *   function.
+ */
 void phy_start_machine(struct phy_device *phydev,
 		void (*handler)(struct net_device *))
 {
@@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device
 	mod_timer(&phydev->phy_timer, jiffies + HZ);
 }
 
-/* phy_stop_machine
+/**
+ * phy_stop_machine - stop the PHY state machine tracking
+ * @phydev: target phy_device struct
  *
- * description: Stops the state machine timer, sets the state to UP
+ * Description: Stops the state machine timer, sets the state to UP
  *   (unless it wasn't up yet). This function must be called BEFORE
  *   phy_detach.
  */
@@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device 
 	phydev->adjust_state = NULL;
 }
 
-/* phy_force_reduction
+/**
+ * phy_force_reduction - reduce PHY speed/duplex settings by one step
+ * @phydev: target phy_device struct
  *
- * description: Reduces the speed/duplex settings by
- *   one notch.  The order is so:
- *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
- *   10/FULL, 10/HALF.  The function bottoms out at 10/HALF.
+ * Description: Reduces the speed/duplex settings by one notch,
+ *   in this order--
+ *   1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ *   The function bottoms out at 10/HALF.
  */
 static void phy_force_reduction(struct phy_device *phydev)
 {
@@ -464,7 +525,9 @@ static void phy_force_reduction(struct p
 }
 
 
-/* phy_error:
+/**
+ * phy_error - enter HALTED state for this PHY device
+ * @phydev: target phy_device struct
  *
  * Moves the PHY to the HALTED state in response to a read
  * or write error, and tells the controller the link is down.
@@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev
 	spin_unlock(&phydev->lock);
 }
 
-/* phy_interrupt
+/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
  *
- * description: When a PHY interrupt occurs, the handler disables
+ * 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)
@@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq
 	return IRQ_HANDLED;
 }
 
-/* Enable the interrupts from the PHY side */
+/**
+ * phy_enable_interrupts - Enable the interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
 int phy_enable_interrupts(struct phy_device *phydev)
 {
 	int err;
@@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_dev
 }
 EXPORT_SYMBOL(phy_enable_interrupts);
 
-/* Disable the PHY interrupts from the PHY side */
+/**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
 int phy_disable_interrupts(struct phy_device *phydev)
 {
 	int err;
@@ -543,13 +615,15 @@ phy_err:
 }
 EXPORT_SYMBOL(phy_disable_interrupts);
 
-/* phy_start_interrupts
+/**
+ * phy_start_interrupts - request and enable interrupts for a PHY device
+ * @phydev: target phy_device struct
  *
- * description: Request the interrupt for the given PHY.  If
- *   this fails, then we set irq to PHY_POLL.
+ * Description: Request the interrupt for the given PHY.
+ *   If this fails, then we set irq to PHY_POLL.
  *   Otherwise, we enable the interrupts in the PHY.
- *   Returns 0 on success.
  *   This should only be called with a valid IRQ number.
+ *   Returns 0 on success or < 0 on error.
  */
 int phy_start_interrupts(struct phy_device *phydev)
 {
@@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_devi
 }
 EXPORT_SYMBOL(phy_start_interrupts);
 
+/**
+ * phy_stop_interrupts - disable interrupts from a PHY device
+ * @phydev: target phy_device struct
+ */
 int phy_stop_interrupts(struct phy_device *phydev)
 {
 	int err;
@@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_devic
 EXPORT_SYMBOL(phy_stop_interrupts);
 
 
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+/**
+ * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
 static void phy_change(struct work_struct *work)
 {
 	int err;
@@ -630,7 +711,10 @@ phy_err:
 	phy_error(phydev);
 }
 
-/* Bring down the PHY link, and stop checking the status. */
+/**
+ * phy_stop - Bring down the PHY link, and stop checking the status
+ * @phydev: target phy_device struct
+ */
 void phy_stop(struct phy_device *phydev)
 {
 	spin_lock(&phydev->lock);
@@ -659,9 +743,11 @@ out_unlock:
 }
 
 
-/* phy_start
+/**
+ * phy_start - start or restart a PHY device
+ * @phydev: target phy_device struct
  *
- * description: Indicates the attached device's readiness to
+ * Description: Indicates the attached device's readiness to
  *   handle PHY-related work.  Used during startup to start the
  *   PHY, and after a call to phy_stop() to resume operation.
  *   Also used to indicate the MDIO bus has cleared an error
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 7d5b6d1..a8b74cd 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -74,11 +74,13 @@ struct phy_device* phy_device_create(str
 }
 EXPORT_SYMBOL(phy_device_create);
 
-/* get_phy_device
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
  *
- * description: Reads the ID registers of the PHY at addr on the
- *   bus, then allocates and returns the phy_device to
- *   represent it.
+ * Description: Reads the ID registers of the PHY at @addr on the
+ *   @bus, then allocates and returns the phy_device to represent it.
  */
 struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
 {
@@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struc
 	return dev;
 }
 
-/* phy_prepare_link:
+/**
+ * phy_prepare_link - prepares the PHY layer to monitor link status
+ * @phydev: target phy_device struct
+ * @handler: callback function for link status change notifications
  *
- * description: Tells the PHY infrastructure to handle the
+ * Description: Tells the PHY infrastructure to handle the
  *   gory details on monitoring link status (whether through
  *   polling or an interrupt), and to call back to the
  *   connected device driver when the link status changes.
  *   If you want to monitor your own link state, don't call
- *   this function */
+ *   this function.
+ */
 void phy_prepare_link(struct phy_device *phydev,
 		void (*handler)(struct net_device *))
 {
 	phydev->adjust_link = handler;
 }
 
-/* phy_connect:
+/**
+ * phy_connect - connect an ethernet device to a PHY device
+ * @dev: the network device to connect
+ * @phy_id: the PHY device to connect
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
  *
- * description: Convenience function for connecting ethernet
+ * Description: Convenience function for connecting ethernet
  *   devices to PHY devices.  The default behavior is for
  *   the PHY infrastructure to handle everything, and only notify
  *   the connected driver when the link status changes.  If you
@@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct n
 }
 EXPORT_SYMBOL(phy_connect);
 
+/**
+ * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device
+ * @phydev: target phy_device struct
+ */
 void phy_disconnect(struct phy_device *phydev)
 {
 	if (phydev->irq > 0)
@@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *p
 }
 EXPORT_SYMBOL(phy_disconnect);
 
-/* phy_attach:
+static int phy_compare_id(struct device *dev, void *data)
+{
+	return strcmp((char *)data, dev->bus_id) ? 0 : 1;
+}
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @phy_id: PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
  *
- *   description: Called by drivers to attach to a particular PHY
+ * Description: Called by drivers to attach to a particular PHY
  *     device. The phy_device is found, and properly hooked up
  *     to the phy_driver.  If no driver is attached, then the
  *     genphy_driver is used.  The phy_device is given a ptr to
  *     the attaching device, and given a callback for link status
- *     change.  The phy_device is returned to the attaching
- *     driver.
+ *     change.  The phy_device is returned to the attaching driver.
  */
-static int phy_compare_id(struct device *dev, void *data)
-{
-	return strcmp((char *)data, dev->bus_id) ? 0 : 1;
-}
-
 struct phy_device *phy_attach(struct net_device *dev,
 		const char *phy_id, u32 flags, phy_interface_t interface)
 {
@@ -208,16 +228,12 @@ struct phy_device *phy_attach(struct net
 	 * exist, and we should use the genphy driver. */
 	if (NULL == d->driver) {
 		int err;
-		down_write(&d->bus->subsys.rwsem);
 		d->driver = &genphy_driver.driver;
 
 		err = d->driver->probe(d);
-
 		if (err >= 0)
 			err = device_bind_driver(d);
 
-		up_write(&d->bus->subsys.rwsem);
-
 		if (err)
 			return ERR_PTR(err);
 	}
@@ -250,6 +266,10 @@ struct phy_device *phy_attach(struct net
 }
 EXPORT_SYMBOL(phy_attach);
 
+/**
+ * phy_detach - detach a PHY device from its network device
+ * @phydev: target phy_device struct
+ */
 void phy_detach(struct phy_device *phydev)
 {
 	phydev->attached_dev = NULL;
@@ -258,22 +278,21 @@ void phy_detach(struct phy_device *phyde
 	 * was using the generic driver), we unbind the device
 	 * from the generic driver so that there's a chance a
 	 * real driver could be loaded */
-	if (phydev->dev.driver == &genphy_driver.driver) {
-		down_write(&phydev->dev.bus->subsys.rwsem);
+	if (phydev->dev.driver == &genphy_driver.driver)
 		device_release_driver(&phydev->dev);
-		up_write(&phydev->dev.bus->subsys.rwsem);
-	}
 }
 EXPORT_SYMBOL(phy_detach);
 
 
 /* Generic PHY support and helper functions */
 
-/* genphy_config_advert
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
  *
- * description: Writes MII_ADVERTISE with the appropriate values,
+ * Description: Writes MII_ADVERTISE with the appropriate values,
  *   after sanitizing the values to make sure we only advertise
- *   what is supported
+ *   what is supported.
  */
 int genphy_config_advert(struct phy_device *phydev)
 {
@@ -335,11 +354,14 @@ int genphy_config_advert(struct phy_devi
 }
 EXPORT_SYMBOL(genphy_config_advert);
 
-/* genphy_setup_forced
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
  *
- * description: Configures MII_BMCR to force speed/duplex
+ * Description: Configures MII_BMCR to force speed/duplex
  *   to the values in phydev. Assumes that the values are valid.
- *   Please see phy_sanitize_settings() */
+ *   Please see phy_sanitize_settings().
+ */
 int genphy_setup_forced(struct phy_device *phydev)
 {
 	int ctl = BMCR_RESET;
@@ -368,7 +390,10 @@ int genphy_setup_forced(struct phy_devic
 }
 
 
-/* Enable and Restart Autonegotiation */
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
 int genphy_restart_aneg(struct phy_device *phydev)
 {
 	int ctl;
@@ -389,11 +414,13 @@ int genphy_restart_aneg(struct phy_devic
 }
 
 
-/* genphy_config_aneg
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
  *
- * description: If auto-negotiation is enabled, we configure the
+ * Description: If auto-negotiation is enabled, we configure the
  *   advertising, and then restart auto-negotiation.  If it is not
- *   enabled, then we write the BMCR
+ *   enabled, then we write the BMCR.
  */
 int genphy_config_aneg(struct phy_device *phydev)
 {
@@ -413,11 +440,13 @@ int genphy_config_aneg(struct phy_device
 }
 EXPORT_SYMBOL(genphy_config_aneg);
 
-/* genphy_update_link
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
  *
- * description: Update the value in phydev->link to reflect the
+ * Description: Update the value in phydev->link to reflect the
  *   current link value.  In order to do this, we need to read
- *   the status register twice, keeping the second value
+ *   the status register twice, keeping the second value.
  */
 int genphy_update_link(struct phy_device *phydev)
 {
@@ -444,9 +473,11 @@ int genphy_update_link(struct phy_device
 }
 EXPORT_SYMBOL(genphy_update_link);
 
-/* genphy_read_status
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
  *
- * description: Check the link, then figure out the current state
+ * Description: Check the link, then figure out the current state
  *   by comparing what we advertise with what the link partner
  *   advertises.  Start by checking the gigabit possibilities,
  *   then move on to 10/100.
@@ -586,9 +617,11 @@ static int genphy_config_init(struct phy
 }
 
 
-/* phy_probe
+/**
+ * phy_probe - probe and init a PHY device
+ * @dev: device to probe and init
  *
- * description: Take care of setting up the phy_device structure,
+ * Description: Take care of setting up the phy_device structure,
  *   set the state to READY (the driver's init function should
  *   set it to STARTING if needed).
  */
@@ -650,6 +683,10 @@ static int phy_remove(struct device *dev
 	return 0;
 }
 
+/**
+ * phy_driver_register - register a phy_driver with the PHY layer
+ * @new_driver: new phy_driver to register
+ */
 int phy_driver_register(struct phy_driver *new_driver)
 {
 	int retval;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 6bb085f..8754cf3 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -546,7 +546,7 @@ static __be16 plip_type_trans(struct sk_
 	struct ethhdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb,dev->hard_header_len);
 	eth = eth_hdr(skb);
 
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index ef58e41..5411687 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -40,7 +40,6 @@ #include <linux/if_arp.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/device.h>
@@ -88,8 +87,6 @@ #define PF_TO_X(pf, X)		container_of(pf,
 #define PF_TO_PPP(pf)		PF_TO_X(pf, struct ppp)
 #define PF_TO_CHANNEL(pf)	PF_TO_X(pf, struct channel)
 
-#define ROUNDUP(n, x)		(((n) + (x) - 1) / (x))
-
 /*
  * Data structure describing one ppp unit.
  * A ppp unit corresponds to a ppp network interface device
@@ -1297,7 +1294,7 @@ static int ppp_mp_explode(struct ppp *pp
 	 */
 	fragsize = len;
 	if (nfree > 1)
-		fragsize = ROUNDUP(fragsize, nfree);
+		fragsize = DIV_ROUND_UP(fragsize, nfree);
 	/* nbigger channels get fragsize bytes, the rest get fragsize-1,
 	   except if nbigger==0, then they all get fragsize. */
 	nbigger = len % nfree;
@@ -1685,7 +1682,7 @@ #endif /* CONFIG_PPP_FILTER */
 			skb_pull_rcsum(skb, 2);
 			skb->dev = ppp->dev;
 			skb->protocol = htons(npindex_to_ethertype[npi]);
-			skb->mac.raw = skb->data;
+			skb_reset_mac_header(skb);
 			netif_rx(skb);
 			ppp->dev->last_rx = jiffies;
 		}
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index b6f0e9a..5918fab 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -594,7 +594,8 @@ ppp_sync_txmunge(struct syncppp *ap, str
 				return NULL;
 			}
 			skb_reserve(npkt,2);
-			memcpy(skb_put(npkt,skb->len), skb->data, skb->len);
+			skb_copy_from_linear_data(skb,
+				      skb_put(npkt, skb->len), skb->len);
 			kfree_skb(skb);
 			skb = npkt;
 		}
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index ebfa296..6f98834 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -207,7 +207,7 @@ static inline struct pppox_sock *get_ite
 
 static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
 {
-	struct net_device *dev = NULL;
+	struct net_device *dev;
 	int ifindex;
 
 	dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
@@ -218,20 +218,6 @@ static inline struct pppox_sock *get_ite
 	return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
 }
 
-static inline int set_item(struct pppox_sock *po)
-{
-	int i;
-
-	if (!po)
-		return -EINVAL;
-
-	write_lock_bh(&pppoe_hash_lock);
-	i = __set_item(po);
-	write_unlock_bh(&pppoe_hash_lock);
-
-	return i;
-}
-
 static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
 {
 	struct pppox_sock *ret;
@@ -255,54 +241,53 @@ static inline struct pppox_sock *delete_
 static void pppoe_flush_dev(struct net_device *dev)
 {
 	int hash;
-
 	BUG_ON(dev == NULL);
 
-	read_lock_bh(&pppoe_hash_lock);
+	write_lock_bh(&pppoe_hash_lock);
 	for (hash = 0; hash < PPPOE_HASH_SIZE; hash++) {
 		struct pppox_sock *po = item_hash_table[hash];
 
 		while (po != NULL) {
-			if (po->pppoe_dev == dev) {
-				struct sock *sk = sk_pppox(po);
-
-				sock_hold(sk);
-				po->pppoe_dev = NULL;
+			struct sock *sk = sk_pppox(po);
+			if (po->pppoe_dev != dev) {
+				po = po->next;
+				continue;
+			}
+			po->pppoe_dev = NULL;
+			dev_put(dev);
 
-				/* We hold a reference to SK, now drop the
-				 * hash table lock so that we may attempt
-				 * to lock the socket (which can sleep).
-				 */
-				read_unlock_bh(&pppoe_hash_lock);
 
-				lock_sock(sk);
+			/* We always grab the socket lock, followed by the
+			 * pppoe_hash_lock, in that order.  Since we should
+			 * hold the sock lock while doing any unbinding,
+			 * we need to release the lock we're holding.
+			 * Hold a reference to the sock so it doesn't disappear
+			 * as we're jumping between locks.
+			 */
 
-				if (sk->sk_state &
-				    (PPPOX_CONNECTED | PPPOX_BOUND)) {
-					pppox_unbind_sock(sk);
-					dev_put(dev);
-					sk->sk_state = PPPOX_ZOMBIE;
-					sk->sk_state_change(sk);
-				}
+			sock_hold(sk);
 
-				release_sock(sk);
+			write_unlock_bh(&pppoe_hash_lock);
+			lock_sock(sk);
 
-				sock_put(sk);
+			if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+				pppox_unbind_sock(sk);
+				sk->sk_state = PPPOX_ZOMBIE;
+				sk->sk_state_change(sk);
+			}
 
-				read_lock_bh(&pppoe_hash_lock);
+			release_sock(sk);
+			sock_put(sk);
 
-				/* Now restart from the beginning of this
-				 * hash chain.  We always NULL out pppoe_dev
-				 * so we are guaranteed to make forward
-				 * progress.
-				 */
-				po = item_hash_table[hash];
-				continue;
-			}
-			po = po->next;
+			/* Restart scan at the beginning of this hash chain.
+			 * While the lock was dropped the chain contents may
+			 * have changed.
+			 */
+			write_lock_bh(&pppoe_hash_lock);
+			po = item_hash_table[hash];
 		}
 	}
-	read_unlock_bh(&pppoe_hash_lock);
+	write_unlock_bh(&pppoe_hash_lock);
 }
 
 static int pppoe_device_event(struct notifier_block *this,
@@ -344,10 +329,10 @@ static struct notifier_block pppoe_notif
 static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
 {
 	struct pppox_sock *po = pppox_sk(sk);
-	struct pppox_sock *relay_po = NULL;
+	struct pppox_sock *relay_po;
 
 	if (sk->sk_state & PPPOX_BOUND) {
-		struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
+		struct pppoe_hdr *ph = pppoe_hdr(skb);
 		int len = ntohs(ph->length);
 		skb_pull_rcsum(skb, sizeof(struct pppoe_hdr));
 		if (pskb_trim_rcsum(skb, len))
@@ -401,7 +386,7 @@ static int pppoe_rcv(struct sk_buff *skb
 	if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
 		goto out;
 
-	ph = (struct pppoe_hdr *) skb->nh.raw;
+	ph = pppoe_hdr(skb);
 
 	po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
 	if (po != NULL)
@@ -433,7 +418,7 @@ static int pppoe_disc_rcv(struct sk_buff
 	if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
 		goto out;
 
-	ph = (struct pppoe_hdr *) skb->nh.raw;
+	ph = pppoe_hdr(skb);
 	if (ph->code != PADT_CODE)
 		goto abort;
 
@@ -514,36 +499,49 @@ static int pppoe_release(struct socket *
 {
 	struct sock *sk = sock->sk;
 	struct pppox_sock *po;
-	int error = 0;
 
 	if (!sk)
 		return 0;
 
-	if (sock_flag(sk, SOCK_DEAD))
+	lock_sock(sk);
+	if (sock_flag(sk, SOCK_DEAD)){
+		release_sock(sk);
 		return -EBADF;
+	}
 
 	pppox_unbind_sock(sk);
 
 	/* Signal the death of the socket. */
 	sk->sk_state = PPPOX_DEAD;
 
+
+	/* Write lock on hash lock protects the entire "po" struct from
+	 * concurrent updates via pppoe_flush_dev. The "po" struct should
+	 * be considered part of the hash table contents, thus protected
+	 * by the hash table lock */
+	write_lock_bh(&pppoe_hash_lock);
+
 	po = pppox_sk(sk);
 	if (po->pppoe_pa.sid) {
-		delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex);
+		__delete_item(po->pppoe_pa.sid,
+			      po->pppoe_pa.remote, po->pppoe_ifindex);
 	}
 
-	if (po->pppoe_dev)
+	if (po->pppoe_dev) {
 		dev_put(po->pppoe_dev);
+		po->pppoe_dev = NULL;
+	}
 
-	po->pppoe_dev = NULL;
+	write_unlock_bh(&pppoe_hash_lock);
 
 	sock_orphan(sk);
 	sock->sk = NULL;
 
 	skb_queue_purge(&sk->sk_receive_queue);
+	release_sock(sk);
 	sock_put(sk);
 
-	return error;
+	return 0;
 }
 
 
@@ -599,14 +597,18 @@ static int pppoe_connect(struct socket *
 		po->pppoe_dev = dev;
 		po->pppoe_ifindex = dev->ifindex;
 
-		if (!(dev->flags & IFF_UP))
+		write_lock_bh(&pppoe_hash_lock);
+		if (!(dev->flags & IFF_UP)){
+			write_unlock_bh(&pppoe_hash_lock);
 			goto err_put;
+		}
 
 		memcpy(&po->pppoe_pa,
 		       &sp->sa_addr.pppoe,
 		       sizeof(struct pppoe_addr));
 
-		error = set_item(po);
+		error = __set_item(po);
+		write_unlock_bh(&pppoe_hash_lock);
 		if (error < 0)
 			goto err_put;
 
@@ -762,10 +764,10 @@ static int pppoe_ioctl(struct socket *so
 static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
 		  struct msghdr *m, size_t total_len)
 {
-	struct sk_buff *skb = NULL;
+	struct sk_buff *skb;
 	struct sock *sk = sock->sk;
 	struct pppox_sock *po = pppox_sk(sk);
-	int error = 0;
+	int error;
 	struct pppoe_hdr hdr;
 	struct pppoe_hdr *ph;
 	struct net_device *dev;
@@ -799,7 +801,7 @@ static int pppoe_sendmsg(struct kiocb *i
 
 	/* Reserve space for headers. */
 	skb_reserve(skb, dev->hard_header_len);
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	skb->dev = dev;
 
@@ -869,7 +871,8 @@ static int __pppoe_xmit(struct sock *sk,
 			goto abort;
 
 		skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
-		memcpy(skb_put(skb2, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
+					  skb->len);
 	} else {
 		/* Make a clone so as to not disturb the original skb,
 		 * give dev_queue_xmit something it can free.
@@ -884,7 +887,7 @@ static int __pppoe_xmit(struct sock *sk,
 	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
 	skb2->protocol = __constant_htons(ETH_P_PPP_SES);
 
-	skb2->nh.raw = skb2->data;
+	skb_reset_network_header(skb2);
 
 	skb2->dev = dev;
 
@@ -929,10 +932,8 @@ static int pppoe_recvmsg(struct kiocb *i
 		  struct msghdr *m, size_t total_len, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct sk_buff *skb = NULL;
+	struct sk_buff *skb;
 	int error = 0;
-	int len;
-	struct pppoe_hdr *ph = NULL;
 
 	if (sk->sk_state & PPPOX_BOUND) {
 		error = -EIO;
@@ -942,26 +943,21 @@ static int pppoe_recvmsg(struct kiocb *i
 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 				flags & MSG_DONTWAIT, &error);
 
-	if (error < 0) {
+	if (error < 0)
 		goto end;
-	}
 
 	m->msg_namelen = 0;
 
 	if (skb) {
-		error = 0;
-		ph = (struct pppoe_hdr *) skb->nh.raw;
-		len = ntohs(ph->length);
+		struct pppoe_hdr *ph = pppoe_hdr(skb);
+		const int len = ntohs(ph->length);
 
 		error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);
-		if (error < 0)
-			goto do_skb_free;
-		error = len;
+		if (error == 0)
+			error = len;
 	}
 
-do_skb_free:
-	if (skb)
-		kfree_skb(skb);
+	kfree_skb(skb);
 end:
 	return error;
 }
@@ -991,7 +987,7 @@ out:
 
 static __inline__ struct pppox_sock *pppoe_get_idx(loff_t pos)
 {
-	struct pppox_sock *po = NULL;
+	struct pppox_sock *po;
 	int i = 0;
 
 	for (; i < PPPOE_HASH_SIZE; i++) {
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index 9315046..f3e47d0 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -31,6 +31,7 @@ #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
+#include <linux/kmod.h>
 
 #include <net/sock.h>
 
@@ -58,7 +59,7 @@ void pppox_unbind_sock(struct sock *sk)
 {
 	/* Clear connection to ppp device, if attached. */
 
-	if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE)) {
+	if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) {
 		ppp_unregister_channel(&pppox_sk(sk)->chan);
 		sk->sk_state = PPPOX_DEAD;
 	}
@@ -114,6 +115,13 @@ static int pppox_create(struct socket *s
 		goto out;
 
 	rc = -EPROTONOSUPPORT;
+#ifdef CONFIG_KMOD
+	if (!pppox_protos[protocol]) {
+		char buffer[32];
+		sprintf(buffer, "pppox-proto-%d", protocol);
+		request_module(buffer);
+	}
+#endif
 	if (!pppox_protos[protocol] ||
 	    !try_module_get(pppox_protos[protocol]->owner))
 		goto out;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index a8246eb..d8766c0 100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -39,7 +39,7 @@ #include "qla3xxx.h"
 
 #define DRV_NAME  	"qla3xxx"
 #define DRV_STRING 	"QLogic ISP3XXX Network Driver"
-#define DRV_VERSION	"v2.03.00-k3"
+#define DRV_VERSION	"v2.03.00-k4"
 #define PFX		DRV_NAME " "
 
 static const char ql3xxx_driver_name[] = DRV_NAME;
@@ -72,6 +72,30 @@ static struct pci_device_id ql3xxx_pci_t
 MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
 
 /*
+ *  These are the known PHY's which are used
+ */
+typedef enum {
+   PHY_TYPE_UNKNOWN   = 0,
+   PHY_VITESSE_VSC8211,
+   PHY_AGERE_ET1011C,
+   MAX_PHY_DEV_TYPES
+} PHY_DEVICE_et;
+
+typedef struct {
+	PHY_DEVICE_et phyDevice; 
+	u32		phyIdOUI;
+	u16		phyIdModel;
+	char 		*name;
+} PHY_DEVICE_INFO_t;
+
+static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
+	{{PHY_TYPE_UNKNOWN,    0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+	 {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+	 {PHY_AGERE_ET1011C,   0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+};
+
+
+/*
  * Caller must take hw_lock.
  */
 static int ql_sem_spinlock(struct ql3_adapter *qdev,
@@ -662,7 +686,7 @@ static u8 ql_mii_disable_scan_mode(struc
 }
 
 static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
-			       u16 regAddr, u16 value, u32 mac_index)
+			       u16 regAddr, u16 value, u32 phyAddr)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
 	    		qdev->mem_map_registers;
@@ -680,7 +704,7 @@ static int ql_mii_write_reg_ex(struct ql
 	}
 
 	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
-			   PHYAddr[mac_index] | regAddr);
+			   phyAddr | regAddr);
 
 	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
 
@@ -701,7 +725,7 @@ static int ql_mii_write_reg_ex(struct ql
 }
 
 static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
-			      u16 * value, u32 mac_index)
+			      u16 * value, u32 phyAddr)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
 	    		qdev->mem_map_registers;
@@ -720,7 +744,7 @@ static int ql_mii_read_reg_ex(struct ql3
 	}
 
 	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
-			   PHYAddr[mac_index] | regAddr);
+			   phyAddr | regAddr);
 
 	ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
 			   (MAC_MII_CONTROL_RC << 16));
@@ -850,28 +874,31 @@ static void ql_petbi_start_neg(struct ql
 
 }
 
-static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev)
 {
 	ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
-			    mac_index);
+			    PHYAddr[qdev->mac_index]);
 }
 
-static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
 {
 	u16 reg;
 
 	/* Enable Auto-negotiation sense */
-	ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+	ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, 
+			   PHYAddr[qdev->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_TBI_CTRL, reg, 
+			    PHYAddr[qdev->mac_index]);
 
 	ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
-			    PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+			    PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, 
+			    PHYAddr[qdev->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);
+			    PHYAddr[qdev->mac_index]);
 }
 
 static void ql_petbi_init(struct ql3_adapter *qdev)
@@ -880,10 +907,10 @@ static void ql_petbi_init(struct ql3_ada
 	ql_petbi_start_neg(qdev);
 }
 
-static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_init_ex(struct ql3_adapter *qdev)
 {
-	ql_petbi_reset_ex(qdev, mac_index);
-	ql_petbi_start_neg_ex(qdev, mac_index);
+	ql_petbi_reset_ex(qdev);
+	ql_petbi_start_neg_ex(qdev);
 }
 
 static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
@@ -896,33 +923,128 @@ static int ql_is_petbi_neg_pause(struct 
 	return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
 }
 
+static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
+{
+	printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+	/* power down device bit 11 = 1 */
+	ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
+	/* enable diagnostic mode bit 2 = 1 */
+	ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr);
+	/* 1000MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr);
+	/* 1000MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr);
+	/* 100MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr);
+	/* 100MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr);
+	/* 10MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr);
+	/* 10MB amplitude adjust (see Agere errata) */
+	ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr);
+	/* point to hidden reg 0x2806 */
+	ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
+	/* Write new PHYAD w/bit 5 set */
+	ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+	/* 
+	 * Disable diagnostic mode bit 2 = 0
+	 * Power up device bit 11 = 0
+	 * Link up (on) and activity (blink)
+	 */
+	ql_mii_write_reg(qdev, 0x12, 0x840a);
+	ql_mii_write_reg(qdev, 0x00, 0x1140);
+	ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
+}
+
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, 
+				 u16 phyIdReg0, u16 phyIdReg1)
+{
+	PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+	u32   oui;     
+	u16   model;
+	int i;   
+
+	if (phyIdReg0 == 0xffff) {
+		return result;
+	}
+   
+	if (phyIdReg1 == 0xffff) {
+		return result;
+	}
+
+	/* oui is split between two registers */
+	oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
+
+	model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
+
+	/* Scan table for this PHY */
+	for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+		if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
+		{
+			result = PHY_DEVICES[i].phyDevice;
+
+			printk(KERN_INFO "%s: Phy: %s\n",
+				qdev->ndev->name, PHY_DEVICES[i].name);
+			
+		        break;
+		}
+	}
+
+	return result;
+}
+
 static int ql_phy_get_speed(struct ql3_adapter *qdev)
 {
 	u16 reg;
 
+	switch(qdev->phyType) {
+	case PHY_AGERE_ET1011C:
+	{
+		if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
+			return 0;
+
+		reg = (reg >> 8) & 3;
+		break;
+	}
+	default:
 	if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
 		return 0;
 
 	reg = (((reg & 0x18) >> 3) & 3);
+	}
 
-	if (reg == 2)
+	switch(reg) {
+		case 2:
 		return SPEED_1000;
-	else if (reg == 1)
+		case 1:
 		return SPEED_100;
-	else if (reg == 0)
+		case 0:
 		return SPEED_10;
-	else
+		default:
 		return -1;
+	}
 }
 
 static int ql_is_full_dup(struct ql3_adapter *qdev)
 {
 	u16 reg;
 
-	if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
-		return 0;
-
-	return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+	switch(qdev->phyType) {
+	case PHY_AGERE_ET1011C:
+	{
+		if (ql_mii_read_reg(qdev, 0x1A, &reg))
+			return 0;
+			
+		return ((reg & 0x0080) && (reg & 0x1000)) != 0;
+	}
+	case PHY_VITESSE_VSC8211:
+	default:
+	{
+		if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+			return 0;
+		return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+	}
+	}
 }
 
 static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
@@ -935,6 +1057,73 @@ static int ql_is_phy_neg_pause(struct ql
 	return (reg & PHY_NEG_PAUSE) != 0;
 }
 
+static int PHY_Setup(struct ql3_adapter *qdev)
+{
+	u16   reg1;
+	u16   reg2;
+	bool  agereAddrChangeNeeded = false;
+	u32 miiAddr = 0;
+	int err;
+
+	/*  Determine the PHY we are using by reading the ID's */
+	err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
+	if(err != 0) {
+		printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+		       qdev->ndev->name);
+                return err;
+	}
+
+	err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
+	if(err != 0) {
+		printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+		       qdev->ndev->name);
+                return err;
+	}
+
+	/*  Check if we have a Agere PHY */
+	if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
+
+		/* Determine which MII address we should be using 
+		   determined by the index of the card */
+		if (qdev->mac_index == 0) {
+			miiAddr = MII_AGERE_ADDR_1;
+		} else {
+			miiAddr = MII_AGERE_ADDR_2;
+		}
+      
+		err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+		if(err != 0) {
+			printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+		       	       qdev->ndev->name);
+                	return err; 
+		}
+
+		err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
+		if(err != 0) {
+			printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+			       qdev->ndev->name);
+        	        return err;
+		}
+   
+		/*  We need to remember to initialize the Agere PHY */
+         	agereAddrChangeNeeded = true; 
+	}
+
+	/*  Determine the particular PHY we have on board to apply
+	    PHY specific initializations */
+	qdev->phyType = getPhyType(qdev, reg1, reg2);
+
+	if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
+		/* need this here so address gets changed */
+		phyAgereSpecificInit(qdev, miiAddr);  
+	} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
+		printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 /*
  * Caller holds hw_lock.
  */
@@ -1205,15 +1394,14 @@ static int ql_link_down_detect_clear(str
 /*
  * Caller holds hw_lock.
  */
-static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
-					 u32 mac_index)
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
 {
 	struct ql3xxx_port_registers __iomem *port_regs =
 	    		qdev->mem_map_registers;
 	u32 bitToCheck = 0;
 	u32 temp;
 
-	switch (mac_index) {
+	switch (qdev->mac_index) {
 	case 0:
 		bitToCheck = PORT_STATUS_F1_ENABLED;
 		break;
@@ -1238,27 +1426,96 @@ static int ql_this_adapter_controls_port
 	}
 }
 
-static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_reset_ex(struct ql3_adapter *qdev)
 {
-	ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+	ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, 
+			    PHYAddr[qdev->mac_index]);
 }
 
-static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
 {
 	u16 reg;
+	u16 portConfiguration;
+
+	if(qdev->phyType == PHY_AGERE_ET1011C) {
+		/* turn off external loopback */
+		ql_mii_write_reg(qdev, 0x13, 0x0000); 
+	}
+
+	if(qdev->mac_index == 0)
+		portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+	else
+		portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+
+	/*  Some HBA's in the field are set to 0 and they need to
+	    be reinterpreted with a default value */
+	if(portConfiguration == 0)
+		portConfiguration = PORT_CONFIG_DEFAULT;
+
+	/* Set the 1000 advertisements */
+	ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg, 
+			   PHYAddr[qdev->mac_index]);
+	reg &= ~PHY_GIG_ALL_PARAMS;
+
+	if(portConfiguration & 
+	   PORT_CONFIG_FULL_DUPLEX_ENABLED &
+	   PORT_CONFIG_1000MB_SPEED) {
+		reg |= PHY_GIG_ADV_1000F;
+	}
+	 
+	if(portConfiguration & 
+	   PORT_CONFIG_HALF_DUPLEX_ENABLED &
+	   PORT_CONFIG_1000MB_SPEED) {
+		reg |= PHY_GIG_ADV_1000H;
+	}
 
-	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
-			    PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+	ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, 
+			    PHYAddr[qdev->mac_index]);
 
-	ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
-	ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
-			    mac_index);
+	/* Set the 10/100 & pause negotiation advertisements */
+	ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, &reg,
+			   PHYAddr[qdev->mac_index]);
+	reg &= ~PHY_NEG_ALL_PARAMS;
+
+	if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+		reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
+
+	if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+			reg |= PHY_NEG_ADV_100F;
+		
+		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+			reg |= PHY_NEG_ADV_10F;
+	}
+
+	if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+			reg |= PHY_NEG_ADV_100H;
+		
+		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+			reg |= PHY_NEG_ADV_10H;
+	}
+
+	if(portConfiguration &
+	   PORT_CONFIG_1000MB_SPEED) {
+		reg |= 1;	
+	}
+
+	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, 
+			    PHYAddr[qdev->mac_index]);
+
+	ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
+	
+	ql_mii_write_reg_ex(qdev, CONTROL_REG, 
+			    reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
+			    PHYAddr[qdev->mac_index]);
 }
 
-static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_init_ex(struct ql3_adapter *qdev)
 {
-	ql_phy_reset_ex(qdev, mac_index);
-	ql_phy_start_neg_ex(qdev, mac_index);
+	ql_phy_reset_ex(qdev);
+	PHY_Setup(qdev);
+	ql_phy_start_neg_ex(qdev);
 }
 
 /*
@@ -1295,14 +1552,17 @@ static int ql_port_start(struct ql3_adap
 {
 	if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
 		(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
-			 2) << 7))
+			 2) << 7)) {
+		printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
+		       qdev->ndev->name);
 		return -1;
+	}
 
 	if (ql_is_fiber(qdev)) {
 		ql_petbi_init(qdev);
 	} else {
 		/* Copper port */
-		ql_phy_init_ex(qdev, qdev->mac_index);
+		ql_phy_init_ex(qdev);
 	}
 
 	ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1453,7 +1713,7 @@ static void ql_link_state_machine(struct
  */
 static void ql_get_phy_owner(struct ql3_adapter *qdev)
 {
-	if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+	if (ql_this_adapter_controls_port(qdev))
 		set_bit(QL_LINK_MASTER,&qdev->flags);
 	else
 		clear_bit(QL_LINK_MASTER,&qdev->flags);
@@ -1467,11 +1727,11 @@ static void ql_init_scan_mode(struct ql3
 	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);
+		if (ql_this_adapter_controls_port(qdev))
+			ql_petbi_init_ex(qdev);
 	} else {
-		if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
-			ql_phy_init_ex(qdev, qdev->mac_index);
+		if (ql_this_adapter_controls_port(qdev))
+			ql_phy_init_ex(qdev);
 	}
 }
 
@@ -1624,6 +1884,23 @@ static void ql_set_msglevel(struct net_d
 	qdev->msg_enable = value;
 }
 
+static void ql_get_pauseparam(struct net_device *ndev,
+			      struct ethtool_pauseparam *pause)
+{
+	struct ql3_adapter *qdev = netdev_priv(ndev);
+	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+	u32 reg;
+	if(qdev->mac_index == 0)
+		reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
+	else
+		reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
+
+	pause->autoneg  = ql_get_auto_cfg_status(qdev);
+	pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2;
+	pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1;
+}
+
 static const struct ethtool_ops ql3xxx_ethtool_ops = {
 	.get_settings = ql_get_settings,
 	.get_drvinfo = ql_get_drvinfo,
@@ -1631,6 +1908,7 @@ static const struct ethtool_ops ql3xxx_e
 	.get_link = ethtool_op_get_link,
 	.get_msglevel = ql_get_msglevel,
 	.set_msglevel = ql_set_msglevel,
+	.get_pauseparam = ql_get_pauseparam,
 };
 
 static int ql_populate_free_queue(struct ql3_adapter *qdev)
@@ -1815,14 +2093,14 @@ invalid_seg_count:
 	atomic_inc(&qdev->tx_count);
 }
 
-void ql_get_sbuf(struct ql3_adapter *qdev)
+static void ql_get_sbuf(struct ql3_adapter *qdev)
 {
 	if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
 		qdev->small_buf_index = 0;
 	qdev->small_buf_release_cnt++;
 }
 
-struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
+static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
 {
 	struct ql_rcv_buf_cb *lrg_buf_cb = NULL;
 	lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index];
@@ -1873,7 +2151,6 @@ static void ql_process_mac_rx_intr(struc
 			 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);
 
@@ -1928,7 +2205,8 @@ static void ql_process_macip_rx_intr(str
 		 * Copy the ethhdr from first buffer to second. This
 		 * is necessary for 3022 IP completions.
 		 */
-		memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+		skb_copy_from_linear_data_offset(skb1, VLAN_ID_LEN,
+						 skb_push(skb2, size), size);
 	} else {
 		u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
 		if (checksum & 
@@ -1946,7 +2224,6 @@ static void ql_process_macip_rx_intr(str
 			skb2->ip_summed = CHECKSUM_UNNECESSARY;
 		}
 	}
-	skb2->dev = qdev->ndev;
 	skb2->protocol = eth_type_trans(skb2, qdev->ndev);
 
 	netif_receive_skb(skb2);
@@ -3075,6 +3352,7 @@ static int ql_adapter_initialize(struct 
 		goto out;
 	}
 
+	PHY_Setup(qdev);
 	ql_init_scan_mode(qdev);
 	ql_get_phy_owner(qdev);
 
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index 0203f88..4a832c4 100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -293,6 +293,16 @@ #define ETHERNET_CRC_SIZE   4
 
 #define MII_SCAN_REGISTER 0x00000001
 
+#define PHY_ID_0_REG    2
+#define PHY_ID_1_REG    3
+
+#define PHY_OUI_1_MASK       0xfc00
+#define PHY_MODEL_MASK       0x03f0
+
+/*  Address for the Agere Phy */
+#define MII_AGERE_ADDR_1  0x00001000
+#define MII_AGERE_ADDR_2  0x00001100
+
 /* 32-bit ispControlStatus */
 enum {
 	ISP_CONTROL_NP_MASK = 0x0003,
@@ -789,6 +799,7 @@ enum {
 	PHY_CTRL_LOOPBACK = 0x4000,
 
 	PETBI_CONTROL_REG = 0x00,
+	PETBI_CTRL_ALL_PARAMS = 0x7140,
 	PETBI_CTRL_SOFT_RESET = 0x8000,
 	PETBI_CTRL_AUTO_NEG = 0x1000,
 	PETBI_CTRL_RESTART_NEG = 0x0200,
@@ -811,6 +822,23 @@ enum {
 	PETBI_EXPANSION_REG = 0x06,
 	PETBI_EXP_PAGE_RX = 0x0002,
 
+	PHY_GIG_CONTROL = 9,
+	PHY_GIG_ENABLE_MAN = 0x1000,  /* Enable Master/Slave Manual Config*/
+	PHY_GIG_SET_MASTER = 0x0800,  /* Set Master (slave if clear)*/
+	PHY_GIG_ALL_PARAMS = 0x0300,
+	PHY_GIG_ADV_1000F = 0x0200,
+	PHY_GIG_ADV_1000H = 0x0100,
+
+	PHY_NEG_ADVER = 4,
+	PHY_NEG_ALL_PARAMS = 0x0fe0,
+	PHY_NEG_ASY_PAUSE =  0x0800,
+	PHY_NEG_SYM_PAUSE =  0x0400,
+	PHY_NEG_ADV_SPEED =  0x01e0,
+	PHY_NEG_ADV_100F =   0x0100,
+	PHY_NEG_ADV_100H =   0x0080,
+	PHY_NEG_ADV_10F =    0x0040,
+	PHY_NEG_ADV_10H =    0x0020,
+
 	PETBI_TBI_CTRL = 0x11,
 	PETBI_TBI_RESET = 0x8000,
 	PETBI_TBI_AUTO_SENSE = 0x0100,
@@ -826,8 +854,7 @@ enum {
 	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_AUTO_NEG = 0x1000,
 	PHY_CTRL_RESTART_NEG = 0x0200,
 };
 enum {
@@ -892,6 +919,7 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16,
 	u16 pauseThreshold_mac;
 	u16 resumeThreshold_mac;
 	u16 portConfiguration;
+#define PORT_CONFIG_DEFAULT                 0xf700
 #define PORT_CONFIG_AUTO_NEG_ENABLED        0x8000
 #define PORT_CONFIG_SYM_PAUSE_ENABLED       0x4000
 #define PORT_CONFIG_FULL_DUPLEX_ENABLED     0x2000
@@ -1259,6 +1287,7 @@ struct ql3_adapter {
 	struct delayed_work tx_timeout_work;
 	u32 max_frame_size;
 	u32 device_id;
+	u16 phyType;
 };
 
 #endif				/* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 6a77b8a..45876a8 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2284,7 +2284,7 @@ static inline u32 rtl8169_tso_csum(struc
 			return LargeSend | ((mss & MSSMask) << MSSShift);
 	}
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		const struct iphdr *ip = skb->nh.iph;
+		const struct iphdr *ip = ip_hdr(skb);
 
 		if (ip->protocol == IPPROTO_TCP)
 			return IPCS | TCPCS;
@@ -2586,7 +2586,6 @@ rtl8169_rx_interrupt(struct net_device *
 			pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
 				   tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
-			skb->dev = dev;
 			skb_put(skb, pkt_size);
 			skb->protocol = eth_type_trans(skb, dev);
 
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index b7ff484..df6b738 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -115,7 +115,6 @@ static int rionet_rx_clean(struct net_de
 
 		rnet->rx_skb[i]->data = data;
 		skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE);
-		rnet->rx_skb[i]->dev = ndev;
 		rnet->rx_skb[i]->protocol =
 		    eth_type_trans(rnet->rx_skb[i], ndev);
 		error = netif_rx(rnet->rx_skb[i]);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index d81536f..25c73d4 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1029,7 +1029,6 @@ #endif
 					goto defer;
 				}
 			}
-			skb->dev = dev;
 			skb->protocol = hippi_type_trans(skb, dev);
 
 			netif_rx(skb);		/* send it up */
@@ -1452,7 +1451,7 @@ static int rr_start_xmit(struct sk_buff 
 		}
 		skb_reserve(new_skb, 8);
 		skb_put(new_skb, len);
-		memcpy(new_skb->data, skb->data, len);
+		skb_copy_from_linear_data(skb, new_skb->data, len);
 		dev_kfree_skb(skb);
 		skb = new_skb;
 	}
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 33fb7f3..4cb710b 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 46ebf14..290e1c1 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -84,7 +84,7 @@ #include <asm/irq.h>
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.17.1"
+#define DRV_VERSION "2.0.22.1"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct
 }
 
 /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-int vlan_strip_flag;
+static int vlan_strip_flag;
 
 /* Unregister the vlan */
 static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
@@ -394,7 +394,6 @@ static const u64 fix_mac[] = {
 	END_SIGN
 };
 
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
@@ -516,7 +515,7 @@ static int init_shared_mem(struct s2io_n
 		mac_control->fifos[i].list_info = kmalloc(list_holder_size,
 							  GFP_KERNEL);
 		if (!mac_control->fifos[i].list_info) {
-			DBG_PRINT(ERR_DBG,
+			DBG_PRINT(INFO_DBG,
 				  "Malloc failed for list_info\n");
 			return -ENOMEM;
 		}
@@ -542,9 +541,9 @@ static int init_shared_mem(struct s2io_n
 			tmp_v = pci_alloc_consistent(nic->pdev,
 						     PAGE_SIZE, &tmp_p);
 			if (!tmp_v) {
-				DBG_PRINT(ERR_DBG,
+				DBG_PRINT(INFO_DBG,
 					  "pci_alloc_consistent ");
-				DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+				DBG_PRINT(INFO_DBG, "failed for TxDL\n");
 				return -ENOMEM;
 			}
 			/* If we got a zero DMA address(can happen on
@@ -561,9 +560,9 @@ static int init_shared_mem(struct s2io_n
 				tmp_v = pci_alloc_consistent(nic->pdev,
 						     PAGE_SIZE, &tmp_p);
 				if (!tmp_v) {
-					DBG_PRINT(ERR_DBG,
+					DBG_PRINT(INFO_DBG,
 					  "pci_alloc_consistent ");
-					DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+					DBG_PRINT(INFO_DBG, "failed for TxDL\n");
 					return -ENOMEM;
 				}
 			}
@@ -2187,7 +2186,7 @@ static int fill_rxd_3buf(struct s2io_nic
 	/* skb_shinfo(skb)->frag_list will have L4 data payload */
 	skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
 	if (skb_shinfo(skb)->frag_list == NULL) {
-		DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
+		DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
 		return -ENOMEM ;
 	}
 	frag_list = skb_shinfo(skb)->frag_list;
@@ -2195,7 +2194,7 @@ static int fill_rxd_3buf(struct s2io_nic
 	frag_list->next = NULL;
 	tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
 	frag_list->data = tmp;
-	frag_list->tail = tmp;
+	skb_reset_tail_pointer(frag_list);
 
 	/* Buffer-2 receives L4 data payload */
 	((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
@@ -2242,6 +2241,7 @@ static int fill_rx_buffers(struct s2io_n
 	struct buffAdd *ba;
 	unsigned long flags;
 	struct RxD_t *first_rxdp = NULL;
+	u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
 
 	mac_control = &nic->mac_control;
 	config = &nic->config;
@@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_n
 		/* allocate skb */
 		skb = dev_alloc_skb(size);
 		if(!skb) {
-			DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
-			DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+			DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+			DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
 			if (first_rxdp) {
 				wmb();
 				first_rxdp->Control_1 |= RXD_OWN_XENA;
@@ -2342,14 +2342,21 @@ static int fill_rx_buffers(struct s2io_n
 			 * payload
 			 */
 
+			/* save the buffer pointers to avoid frequent dma mapping */
+			Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
+			Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
 			memset(rxdp, 0, sizeof(struct RxD3));
+			/* restore the buffer pointers for dma sync*/
+			((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
+			((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+
 			ba = &mac_control->rings[ring_no].ba[block_no][off];
 			skb_reserve(skb, BUF0_LEN);
 			tmp = (u64)(unsigned long) skb->data;
 			tmp += ALIGN_SIZE;
 			tmp &= ~ALIGN_SIZE;
 			skb->data = (void *) (unsigned long)tmp;
-			skb->tail = (void *) (unsigned long)tmp;
+			skb_reset_tail_pointer(skb);
 
 			if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
 				((struct RxD3*)rxdp)->Buffer0_ptr =
@@ -2573,8 +2580,8 @@ static int s2io_poll(struct net_device *
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		if (fill_rx_buffers(nic, i) == -ENOMEM) {
-			DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-			DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+			DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+			DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
 			break;
 		}
 	}
@@ -2590,8 +2597,8 @@ no_rx:
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		if (fill_rx_buffers(nic, i) == -ENOMEM) {
-			DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-			DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+			DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+			DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
 			break;
 		}
 	}
@@ -2640,8 +2647,8 @@ static void s2io_netpoll(struct net_devi
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		if (fill_rx_buffers(nic, i) == -ENOMEM) {
-			DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
-			DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+			DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+			DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
 			break;
 		}
 	}
@@ -3307,6 +3314,7 @@ static void s2io_reset(struct s2io_nic *
 	u16 subid, pci_cmd;
 	int i;
 	u16 val16;
+	unsigned long long reset_cnt = 0;
 	DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
 			__FUNCTION__, sp->dev->name);
 
@@ -3372,6 +3380,11 @@ new_way:
 
 	/* Reset device statistics maintained by OS */
 	memset(&sp->stats, 0, sizeof (struct net_device_stats));
+	/* save reset count */
+	reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
+	memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
+	/* restore reset count */
+	sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
 
 	/* SXE-002: Configure link and activity LED to turn it off */
 	subid = sp->pdev->subsystem_device;
@@ -3659,7 +3672,7 @@ static int s2io_enable_msi_x(struct s2io
 	nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
 			       GFP_KERNEL);
 	if (nic->entries == NULL) {
-		DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
@@ -3668,7 +3681,7 @@ static int s2io_enable_msi_x(struct s2io
 		kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
 				   GFP_KERNEL);
 	if (nic->s2io_entries == NULL) {
-		DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
 		kfree(nic->entries);
 		return -ENOMEM;
 	}
@@ -4019,7 +4032,7 @@ static int s2io_chk_rx_buffers(struct s2
 			DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
 			DBG_PRINT(INTR_DBG, "PANIC levels\n");
 			if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
-				DBG_PRINT(ERR_DBG, "Out of memory in %s",
+				DBG_PRINT(INFO_DBG, "Out of memory in %s",
 					  __FUNCTION__);
 				clear_bit(0, (&sp->tasklet_status));
 				return -1;
@@ -4029,8 +4042,8 @@ static int s2io_chk_rx_buffers(struct s2
 			tasklet_schedule(&sp->task);
 
 	} else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
-			DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
-			DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+			DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+			DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
 	}
 	return 0;
 }
@@ -4279,9 +4292,7 @@ static void s2io_updt_stats(struct s2io_
 			if (cnt == 5)
 				break; /* Updt failed */
 		} while(1);
-	} else {
-		memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
-	}
+	} 
 }
 
 /**
@@ -5949,12 +5960,12 @@ static void s2io_tasklet(unsigned long d
 		for (i = 0; i < config->rx_ring_num; i++) {
 			ret = fill_rx_buffers(sp, i);
 			if (ret == -ENOMEM) {
-				DBG_PRINT(ERR_DBG, "%s: Out of ",
+				DBG_PRINT(INFO_DBG, "%s: Out of ",
 					  dev->name);
 				DBG_PRINT(ERR_DBG, "memory in tasklet\n");
 				break;
 			} else if (ret == -EFILL) {
-				DBG_PRINT(ERR_DBG,
+				DBG_PRINT(INFO_DBG,
 					  "%s: Rx Ring %d is full\n",
 					  dev->name, i);
 				break;
@@ -6065,8 +6076,8 @@ static int set_rxd_buffer_pointer(struct
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
-				DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
-				DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+				DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+				DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
 				return -ENOMEM ;
 			}
 			/* storing the mapped addr in a temp variable
@@ -6088,7 +6099,7 @@ static int set_rxd_buffer_pointer(struct
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
-				DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+				DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
 					dev->name);
 				return -ENOMEM;
 			}
@@ -6115,7 +6126,7 @@ static int set_rxd_buffer_pointer(struct
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
-				DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+				DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
 					  dev->name);
 				return -ENOMEM;
 			}
@@ -6616,7 +6627,6 @@ static int rx_osm_handler(struct ring_in
 
 	/* Updating statistics */
 	rxdp->Host_Control = 0;
-	sp->rx_pkt_count++;
 	sp->stats.rx_packets++;
 	if (sp->rxd_mode == RXD_MODE_1) {
 		int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -7252,7 +7262,7 @@ #endif
 		goto register_failed;
 	}
 	s2io_vpd_read(sp);
-	DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+	DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
 	DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
 		  sp->product_name, get_xena_rev_id(sp->pdev));
 	DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 803137c..a656d18 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
 /************************************************************************
  * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
  * the GNU General Public License (GPL), incorporated herein by reference.
@@ -760,7 +760,6 @@ #define MAX_MAC_SUPPORTED   16
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
 	struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
-	struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
 
 	struct net_device_stats stats;
 	int high_dma_flag;
@@ -794,11 +793,6 @@ #define MAX_ADDRS_SUPPORTED 64
 	u16 all_multi_pos;
 	u16 promisc_flg;
 
-	u16 tx_pkt_count;
-	u16 rx_pkt_count;
-	u16 tx_err_count;
-	u16 rx_err_count;
-
 	/*  Id timer, used to blink NIC to physically identify NIC. */
 	struct timer_list id_timer;
 
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 143958f..ad94358 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -688,7 +688,6 @@ static int lan_saa9730_rx(struct net_dev
 			} else {
 				lp->stats.rx_bytes += len;
 				lp->stats.rx_packets++;
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align */
 				skb_put(skb, len);	/* make room */
 				eth_copy_and_sum(skb,
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index b9fa4fb..1de3eec 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -834,7 +834,7 @@ #endif /* XXXDEBUG */
 			goto dropped_frame;
 		}
 		skb->dev = dev;
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16];
 		insw(ioaddr, skb_put(skb, NewDatagramDataSize),
 			NewDatagramDataSize / 2);
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 103c317..132e214 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -95,19 +95,28 @@ MODULE_PARM_DESC(full_duplex, "1-" __MOD
 #endif
 
 #ifdef CONFIG_SBMAC_COALESCE
-static int int_pktcnt = 0;
-module_param(int_pktcnt, int, S_IRUGO);
-MODULE_PARM_DESC(int_pktcnt, "Packet count");
+static int int_pktcnt_tx = 255;
+module_param(int_pktcnt_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count");
 
-static int int_timeout = 0;
-module_param(int_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(int_timeout, "Timeout value");
+static int int_timeout_tx = 255;
+module_param(int_timeout_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_tx, "TX timeout value");
+
+static int int_pktcnt_rx = 64;
+module_param(int_pktcnt_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count");
+
+static int int_timeout_rx = 64;
+module_param(int_timeout_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
 #endif
 
 #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>
+#define R_MAC_DMA_OODPKTLOST_RX	R_MAC_DMA_OODPKTLOST
 #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
@@ -155,8 +164,8 @@ #define SBDMA_NEXTBUF(d,f) ((((d)->f+1) 
 
 #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
 
-#define SBMAC_MAX_TXDESCR	32
-#define SBMAC_MAX_RXDESCR	32
+#define SBMAC_MAX_TXDESCR	256
+#define SBMAC_MAX_RXDESCR	256
 
 #define ETHER_ALIGN	2
 #define ETHER_ADDR_LEN	6
@@ -185,10 +194,10 @@ typedef struct sbmacdma_s {
 	 * associated with it.
 	 */
 
-	struct sbmac_softc *sbdma_eth;	        /* back pointer to associated MAC */
-	int              sbdma_channel;	/* channel number */
+	struct sbmac_softc *sbdma_eth;	    /* back pointer to associated MAC */
+	int              sbdma_channel;	    /* channel number */
 	int		 sbdma_txdir;       /* direction (1=transmit) */
-	int		 sbdma_maxdescr;	/* total # of descriptors in ring */
+	int		 sbdma_maxdescr;    /* total # of descriptors in ring */
 #ifdef CONFIG_SBMAC_COALESCE
 	int		 sbdma_int_pktcnt;  /* # descriptors rx/tx before interrupt*/
 	int		 sbdma_int_timeout; /* # usec rx/tx interrupt */
@@ -197,13 +206,16 @@ #endif
 	volatile void __iomem *sbdma_config0;	/* DMA config register 0 */
 	volatile void __iomem *sbdma_config1;	/* DMA config register 1 */
 	volatile void __iomem *sbdma_dscrbase;	/* Descriptor base address */
-	volatile void __iomem *sbdma_dscrcnt;     /* Descriptor count register */
+	volatile void __iomem *sbdma_dscrcnt;   /* Descriptor count register */
 	volatile void __iomem *sbdma_curdscr;	/* current descriptor address */
+	volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
+
 
 	/*
 	 * 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 */
 
@@ -286,8 +298,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 work_to_do, 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);
@@ -308,6 +320,8 @@ 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);
+static int sbmac_poll(struct net_device *poll_dev, int *budget);
+
 static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
 static int sbmac_mii_probe(struct net_device *dev);
 
@@ -679,6 +693,10 @@ static void sbdma_initctx(sbmacdma_t *d,
 			  int txrx,
 			  int maxdescr)
 {
+#ifdef CONFIG_SBMAC_COALESCE
+	int int_pktcnt, int_timeout;
+#endif
+
 	/*
 	 * Save away interesting stuff in the structure
 	 */
@@ -728,6 +746,11 @@ #endif
 		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
 	d->sbdma_curdscr =
 		s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
+	if (d->sbdma_txdir)
+		d->sbdma_oodpktlost = NULL;
+	else
+		d->sbdma_oodpktlost =
+			s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX);
 
 	/*
 	 * Allocate memory for the ring
@@ -735,6 +758,7 @@ #endif
 
 	d->sbdma_maxdescr = maxdescr;
 
+	d->sbdma_dscrtable_unaligned =
 	d->sbdma_dscrtable = (sbdmadscr_t *)
 		kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
 
@@ -765,12 +789,14 @@ #ifdef CONFIG_SBMAC_COALESCE
 	 * Setup Rx/Tx DMA coalescing defaults
 	 */
 
+	int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx;
 	if ( int_pktcnt ) {
 		d->sbdma_int_pktcnt = int_pktcnt;
 	} else {
 		d->sbdma_int_pktcnt = 1;
 	}
 
+	int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx;
 	if ( int_timeout ) {
 		d->sbdma_int_timeout = int_timeout;
 	} else {
@@ -933,9 +959,6 @@ static int sbdma_add_rcvbuffer(sbmacdma_
 		}
 
 		sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN);
-
-		/* mark skbuff owned by our device */
-		sb_new->dev = d->sbdma_eth->sbm_dev;
 	}
 	else {
 		sb_new = sb;
@@ -1128,32 +1151,63 @@ static void sbdma_fillring(sbmacdma_t *d
 	}
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sbmac_netpoll(struct net_device *netdev)
+{
+	struct sbmac_softc *sc = netdev_priv(netdev);
+	int irq = sc->sbm_dev->irq;
+
+	__raw_writeq(0, sc->sbm_imr);
+
+	sbmac_intr(irq, netdev, NULL);
+
+#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
+}
+#endif
 
 /**********************************************************************
- *  SBDMA_RX_PROCESS(sc,d)
+ *  SBDMA_RX_PROCESS(sc,d,work_to_do,poll)
  *
  *  Process "completed" receive buffers on the specified DMA channel.
- *  Note that this isn't really ideal for priority channels, since
- *  it processes all of the packets on a given channel before
- *  returning.
  *
  *  Input parameters:
- *	   sc - softc structure
- *  	   d - DMA channel context
+ *            sc - softc structure
+ *  	       d - DMA channel context
+ *    work_to_do - no. of packets to process before enabling interrupt
+ *                 again (for NAPI)
+ *          poll - 1: using polling (for NAPI)
  *
  *  Return value:
  *  	   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 work_to_do, int poll)
 {
 	int curidx;
 	int hwidx;
 	sbdmadscr_t *dsc;
 	struct sk_buff *sb;
 	int len;
+	int work_done = 0;
+	int dropped = 0;
 
-	for (;;) {
+	prefetch(d);
+
+again:
+	/* Check if the HW dropped any frames */
+	sc->sbm_stats.rx_fifo_errors
+	    += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
+	__raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
+
+	while (work_to_do-- > 0) {
 		/*
 		 * figure out where we are (as an index) and where
 		 * the hardware is (also as an index)
@@ -1165,7 +1219,12 @@ static void sbdma_rx_process(struct sbma
 		 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
 		 */
 
-		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+		dsc = d->sbdma_remptr;
+		curidx = dsc - d->sbdma_dscrtable;
+
+		prefetch(dsc);
+		prefetch(&d->sbdma_ctxtable[curidx]);
+
 		hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
 				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
 
@@ -1176,13 +1235,12 @@ static void sbdma_rx_process(struct sbma
 		 */
 
 		if (curidx == hwidx)
-			break;
+			goto done;
 
 		/*
 		 * Otherwise, get the packet's sk_buff ptr back
 		 */
 
-		dsc = &(d->sbdma_dscrtable[curidx]);
 		sb = d->sbdma_ctxtable[curidx];
 		d->sbdma_ctxtable[curidx] = NULL;
 
@@ -1194,7 +1252,7 @@ static void sbdma_rx_process(struct sbma
 		 * receive ring.
 		 */
 
-		if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+		if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) {
 
 			/*
 			 * Add a new buffer to replace the old one.  If we fail
@@ -1202,9 +1260,14 @@ static void sbdma_rx_process(struct sbma
 			 * packet and put it right back on the receive ring.
 			 */
 
-			if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
-				sc->sbm_stats.rx_dropped++;
+			if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
+				      -ENOBUFS)) {
+ 				sc->sbm_stats.rx_dropped++;
 				sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+				/* No point in continuing at the moment */
+				printk(KERN_ERR "dropped packet (1)\n");
+				d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+				goto done;
 			} else {
 				/*
 				 * Set length into the packet
@@ -1216,8 +1279,6 @@ static void sbdma_rx_process(struct sbma
 				 * receive ring.  Pass the buffer to
 				 * the kernel
 				 */
-				sc->sbm_stats.rx_bytes += len;
-				sc->sbm_stats.rx_packets++;
 				sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
 				/* Check hw IPv4/TCP checksum if supported */
 				if (sc->rx_hw_checksum == ENABLE) {
@@ -1229,8 +1290,22 @@ static void sbdma_rx_process(struct sbma
 						sb->ip_summed = CHECKSUM_NONE;
 					}
 				}
-
-				netif_rx(sb);
+				prefetch(sb->data);
+				prefetch((const void *)(((char *)sb->data)+32));
+				if (poll)
+					dropped = netif_receive_skb(sb);
+				else
+					dropped = netif_rx(sb);
+
+				if (dropped == NET_RX_DROP) {
+					sc->sbm_stats.rx_dropped++;
+					d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+					goto done;
+				}
+				else {
+					sc->sbm_stats.rx_bytes += len;
+					sc->sbm_stats.rx_packets++;
+				}
 			}
 		} else {
 			/*
@@ -1247,12 +1322,16 @@ static void sbdma_rx_process(struct sbma
 		 */
 
 		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+		work_done++;
+	}
+	if (!poll) {
+		work_to_do = 32;
+		goto again; /* collect fifo drop statistics again */
 	}
+done:
+	return work_done;
 }
 
-
-
 /**********************************************************************
  *  SBDMA_TX_PROCESS(sc,d)
  *
@@ -1264,22 +1343,30 @@ static void sbdma_rx_process(struct sbma
  *
  *  Input parameters:
  *      sc - softc structure
- *  	   d - DMA channel context
+ *  	 d - DMA channel context
+ *    poll - 1: using polling (for NAPI)
  *
  *  Return value:
  *  	   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 (;;) {
 		/*
 		 * figure out where we are (as an index) and where
@@ -1293,8 +1380,6 @@ 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
@@ -1332,6 +1417,8 @@ static void sbdma_tx_process(struct sbma
 
 		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
 
+		packets_handled++;
+
 	}
 
 	/*
@@ -1340,8 +1427,10 @@ static void sbdma_tx_process(struct sbma
 	 * watermark on the transmit queue.
 	 */
 
-	netif_wake_queue(d->sbdma_eth->sbm_dev);
+	if (packets_handled)
+		netif_wake_queue(d->sbdma_eth->sbm_dev);
 
+end_unlock:
 	spin_unlock_irqrestore(&(sc->sbm_lock), flags);
 
 }
@@ -1415,9 +1504,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) {
@@ -1615,15 +1704,9 @@ #error invalid SiByte MAC configuation
 #endif
 
 #ifdef CONFIG_SBMAC_COALESCE
-	/*
-	 * 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);
 #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);
 #endif
@@ -2056,57 +2139,46 @@ static irqreturn_t sbmac_intr(int irq,vo
 	uint64_t isr;
 	int handled = 0;
 
-	for (;;) {
-
-		/*
-		 * Read the ISR (this clears the bits in the real
-		 * register, except for counter addr)
-		 */
+	/*
+	 * 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;
+	isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
 
-		if (isr == 0)
-			break;
+	if (isr == 0)
+		return IRQ_RETVAL(0);
+	handled = 1;
 
-		handled = 1;
-
-		/*
-		 * Transmits on channel 0
-		 */
+	/*
+	 * Transmits on channel 0
+	 */
 
-		if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
-			sbdma_tx_process(sc,&(sc->sbm_txdma));
+	if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+		sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
+#ifdef CONFIG_NETPOLL_TRAP
+		if (netpoll_trap()) {
+			if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+				__netif_schedule(dev);
 		}
+#endif
+	}
 
-		/*
-		 * Receives on channel 0
-		 */
-
-		/*
-		 * It's important to test all the bits (or at least the
-		 * EOP_SEEN bit) when deciding to do the RX process
-		 * particularly when coalescing, to make sure we
-		 * take care of the following:
-		 *
-		 * If you have some packets waiting (have been received
-		 * but no interrupt) and get a TX interrupt before
-		 * the RX timer or counter expires, reading the ISR
-		 * above will clear the timer and counter, and you
-		 * won't get another interrupt until a packet shows
-		 * up to start the timer again.  Testing
-		 * EOP_SEEN here takes care of this case.
-		 * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
-		 */
-
-
-		if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
-			sbdma_rx_process(sc,&(sc->sbm_rxdma));
+	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);
+			/* Depend on the exit from poll to reenable intr */
+		}
+		else {
+			/* may leave some packets behind */
+			sbdma_rx_process(sc,&(sc->sbm_rxdma),
+					 SBMAC_MAX_RXDESCR * 2, 0);
 		}
 	}
 	return IRQ_RETVAL(handled);
 }
 
-
 /**********************************************************************
  *  SBMAC_START_TX(skb,dev)
  *
@@ -2236,8 +2308,6 @@ static void sbmac_setmulti(struct sbmac_
 	}
 }
 
-
-
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
 /**********************************************************************
  *  SBMAC_PARSE_XDIGIT(str)
@@ -2400,8 +2470,13 @@ static int sbmac_init(struct net_device 
 	dev->do_ioctl           = sbmac_mii_ioctl;
 	dev->tx_timeout         = sbmac_tx_timeout;
 	dev->watchdog_timeo     = TX_TIMEOUT;
+	dev->poll               = sbmac_poll;
+	dev->weight             = 16;
 
 	dev->change_mtu         = sb1250_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = sbmac_netpoll;
+#endif
 
 	/* This is needed for PASS2 for Rx H/W checksum feature */
 	sbmac_set_iphdr_offset(sc);
@@ -2799,7 +2874,39 @@ static int sbmac_close(struct net_device
 	return 0;
 }
 
+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), work_to_do, 1);
 
+	if (work_done > work_to_do)
+		printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
+		       sc->sbm_dev->name, *budget, dev->quota, work_done);
+
+	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);
+}
 
 #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
 static void
@@ -2886,7 +2993,7 @@ #endif
 
 		/*
 		 * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
-		 * value for us by the firmware if we're going to use this MAC.
+		 * value for us by the firmware if we are going to use this MAC.
 		 * If we find a zero, skip this MAC.
 		 */
 
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index c32c21a..5b7284c 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -814,7 +814,6 @@ static void _sc92031_rx_tasklet(struct n
 			memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
 		}
 
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 		dev->last_rx = jiffies;
 		netif_rx(skb);
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 0d6c95c..4bce7c4 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -550,7 +550,6 @@ static void seeq8005_rx(struct net_devic
 				lp->stats.rx_dropped++;
 				break;
 			}
-			skb->dev = dev;
 			skb_reserve(skb, 2);	/* align data on 16 byte */
 			buf = skb_put(skb,pkt_len);
 
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 52ed522..1fc7730 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -318,7 +318,6 @@ static inline void sgiseeq_rx(struct net
 			skb = dev_alloc_skb(len + 2);
 
 			if (skb) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);
 				skb_put(skb, len);
 
@@ -535,7 +534,7 @@ static int sgiseeq_start_xmit(struct sk_
 	 *    entry and the HPC got to the end of the chain before we
 	 *    added this new entry and restarted it.
 	 */
-	memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
+	skb_copy_from_linear_data(skb, (char *)(long)td->buf_vaddr, skblen);
 	if (len != skblen)
 		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
@@ -625,7 +624,7 @@ static inline void setup_rx_ring(struct 
 
 #define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
 
-static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
 {
 	struct sgiseeq_init_block *sr;
 	struct sgiseeq_private *sp;
@@ -651,7 +650,9 @@ static int sgiseeq_init(struct hpc3_regs
 
 #define EADDR_NVOFS     250
 	for (i = 0; i < 3; i++) {
-		unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+		unsigned short tmp = has_eeprom ?
+			ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
+			ip22_nvram_read(EADDR_NVOFS / 2+i);
 
 		dev->dev_addr[2 * i]     = tmp >> 8;
 		dev->dev_addr[2 * i + 1] = tmp & 0xff;
@@ -684,6 +685,11 @@ #endif
 	sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
 			     HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
 
+	/* Setup PIO and DMA transfer timing */
+	sp->hregs->pconfig = 0x161;
+	sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+			     HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
 	/* Reset the chip. */
 	hpc3_eth_reset(sp->hregs);
 
@@ -730,8 +736,23 @@ err_out:
 
 static int __init sgiseeq_probe(void)
 {
+	unsigned int tmp, ret1, ret2 = 0;
+
 	/* On board adapter on 1st HPC is always present */
-	return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
+	ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
+	/* Let's see if second HPC is there */
+	if (!(ip22_is_fullhouse()) &&
+	    get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
+		sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
+				 SGIMC_GIOPAR_EXP164 |
+				 SGIMC_GIOPAR_HPC264;
+		hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
+		/* interrupt/config register on Challenge S Mezz board */
+		hpc3c1->pbus_extregs[0][0] = 0x30;
+		ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
+	}
+
+	return (ret1 & ret2) ? ret1 : 0;
 }
 
 static void __exit sgiseeq_exit(void)
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 34463ce..bc8de48 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -632,7 +632,6 @@ static int sis190_rx_interrupt(struct ne
 			pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
 				   tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
-			skb->dev = dev;
 			skb_put(skb, pkt_size);
 			skb->protocol = eth_type_trans(skb, dev);
 
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index b2a3b19..2cb2e15 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1160,7 +1160,6 @@ sis900_init_rx_ring(struct net_device *n
 			   buffer */
 			break;
 		}
-		skb->dev = net_dev;
 		sis_priv->rx_skbuff[i] = skb;
 		sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;
                 sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,
@@ -1754,6 +1753,7 @@ #endif
 			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
 		} else {
 			struct sk_buff * skb;
+			struct sk_buff * rx_skb;
 
 			pci_unmap_single(sis_priv->pci_dev,
 				sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
@@ -1787,10 +1787,10 @@ #endif
 			}
 
 			/* give the socket buffer to upper layers */
-			skb = sis_priv->rx_skbuff[entry];
-			skb_put(skb, rx_size);
-			skb->protocol = eth_type_trans(skb, net_dev);
-			netif_rx(skb);
+			rx_skb = sis_priv->rx_skbuff[entry];
+			skb_put(rx_skb, rx_size);
+			rx_skb->protocol = eth_type_trans(rx_skb, net_dev);
+			netif_rx(rx_skb);
 
 			/* some network statistics */
 			if ((rx_status & BCAST) == MCAST)
@@ -1800,7 +1800,6 @@ #endif
 			sis_priv->stats.rx_packets++;
 			sis_priv->dirty_rx++;
 refill_rx_ring:
-			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 =
@@ -1832,7 +1831,6 @@ refill_rx_ring:
 				sis_priv->stats.rx_dropped++;
 				break;
 			}
-			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 =
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index e94ab25..bf21862 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -1562,10 +1562,10 @@ #endif
 	pTxd->pMBuf     = pMessage;
 
 	if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
-		u16 hdrlen = pMessage->h.raw - pMessage->data;
+		u16 hdrlen = skb_transport_offset(pMessage);
 		u16 offset = hdrlen + pMessage->csum_offset;
 
-		if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
+		if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
 			(pAC->GIni.GIChipRev == 0) &&
 			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
 			pTxd->TBControl = BMU_TCP_CHECK;
@@ -1681,7 +1681,7 @@ #endif
 	** Does the HW need to evaluate checksum for TCP or UDP packets? 
 	*/
 	if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
-		u16 hdrlen = pMessage->h.raw - pMessage->data;
+		u16 hdrlen = skb_transport_offset(pMessage);
 		u16 offset = hdrlen + pMessage->csum_offset;
 
 		Control = BMU_STFWD;
@@ -1691,7 +1691,7 @@ #endif
 		** opcode for udp is not working in the hardware yet 
 		** (Revision 2.0)
 		*/
-		if ((pMessage->h.ipiph->protocol == IPPROTO_UDP ) &&
+		if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
 			(pAC->GIni.GIChipRev == 0) &&
 			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
 			Control |= BMU_TCP_CHECK;
@@ -2127,7 +2127,7 @@ #endif
 						    (dma_addr_t) PhysAddr,
 						    FrameLength,
 						    PCI_DMA_FROMDEVICE);
-			memcpy(pNewMsg->data, pMsg, FrameLength);
+			skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength);
 
 			pci_dma_sync_single_for_device(pAC->PciDev,
 						       (dma_addr_t) PhysAddr,
@@ -2193,7 +2193,6 @@ #endif
 				SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
 					FrameLength, pRxPort->PortIndex);
 
-				pMsg->dev = pAC->dev[pRxPort->PortIndex];
 				pMsg->protocol = eth_type_trans(pMsg,
 					pAC->dev[pRxPort->PortIndex]);
 				netif_rx(pMsg);
@@ -2246,7 +2245,6 @@ #endif
 				(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
 				(ForRlmt & SK_RLMT_RX_PROTOCOL) ==
 				SK_RLMT_RX_PROTOCOL) {
-				pMsg->dev = pAC->dev[pRxPort->PortIndex];
 				pMsg->protocol = eth_type_trans(pMsg,
 					pAC->dev[pRxPort->PortIndex]);
 				netif_rx(pMsg);
@@ -5125,7 +5123,12 @@ static int skge_resume(struct pci_dev *p
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
-	pci_enable_device(pdev);
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		printk(KERN_WARNING "sk98lin: unable to enable device %s "
+				"in resume\n", dev->name);
+		goto err_out;
+	}
 	pci_set_master(pdev);
 	if (pAC->GIni.GIMacsFound == 2)
 		ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
@@ -5133,10 +5136,8 @@ static int skge_resume(struct pci_dev *p
 		ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
 	if (ret) {
 		printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
-		pAC->AllocFlag &= ~SK_ALLOC_IRQ;
-		dev->irq = 0;
-		pci_disable_device(pdev);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err_out_disable_pdev;
 	}
 
 	netif_device_attach(dev);
@@ -5153,6 +5154,13 @@ static int skge_resume(struct pci_dev *p
 	}
 
 	return 0;
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+err_out:
+	pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+	dev->irq = 0;
+	return ret;
 }
 #else
 #define skge_suspend NULL
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
deleted file mode 100644
index c73dcd9..0000000
--- a/drivers/net/skfp/h/lnkstat.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/******************************************************************************
- *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme 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.
- *
- *	The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
- * Definition of the Error Log Structure
- * This structure will be copied into the Error Log buffer
- * during the NDIS General Request ReadErrorLog by the MAC Driver
- */
-
-struct	s_error_log {
-
-	/*
-	 * place holder for token ring adapter error log (zeros)
-	 */
-	u_char	reserved_0 ;			/* byte 0 inside Error Log */
-	u_char	reserved_1 ;			/* byte 1 */
-	u_char	reserved_2 ;			/* byte 2 */	
-	u_char	reserved_3 ;			/* byte 3 */
-	u_char	reserved_4 ;			/* byte 4 */
-	u_char	reserved_5 ;			/* byte 5 */
-	u_char	reserved_6 ;			/* byte 6 */
-	u_char	reserved_7 ;			/* byte 7 */
-	u_char	reserved_8 ;			/* byte 8 */
-	u_char	reserved_9 ;			/* byte 9 */
-	u_char	reserved_10 ;			/* byte 10 */
-	u_char	reserved_11 ;			/* byte 11 */
-	u_char	reserved_12 ;			/* byte 12 */
-	u_char	reserved_13 ;			/* byte 13 */
-
-	/*
-	 * FDDI link statistics 
-	 */
-/*
- * smt error low
- */
-#define SMT_ERL_AEB	(1<<15)			/* A elast. buffer */
-#define SMT_ERL_BLC	(1<<14)			/* B link error condition */
-#define SMT_ERL_ALC	(1<<13)			/* A link error condition */
-#define SMT_ERL_NCC	(1<<12)			/* not copied condition */
-#define SMT_ERL_FEC	(1<<11)			/* frame error condition */
-
-/*
- * smt event low
- */
-#define SMT_EVL_NCE	(1<<5)
-
-	u_short	smt_error_low ;			/* byte 14/15 */
-	u_short	smt_error_high ;		/* byte 16/17 */
-	u_short	smt_event_low ;			/* byte 18/19 */
-	u_short	smt_event_high ;		/* byte 20/21 */
-	u_short	connection_policy_violation ;	/* byte 22/23 */
-	u_short port_event ;			/* byte 24/25 */
-	u_short set_count_low ;			/* byte 26/27 */
-	u_short set_count_high ;		/* byte 28/29 */
-	u_short	aci_id_code ;			/* byte 30/31 */
-	u_short	purge_frame_counter ;		/* byte 32/33 */
-
-	/*
-	 * CMT and RMT state machines
-	 */
-	u_short	ecm_state ;			/* byte 34/35 */
-	u_short	pcm_a_state ;			/* byte 36/37 */
-	u_short pcm_b_state ;			/* byte 38/39 */
-	u_short	cfm_state ;			/* byte 40/41 */
-	u_short	rmt_state ;			/* byte 42/43 */
-
-	u_short	not_used[30] ;			/* byte 44-103 */
-
-	u_short	ucode_version_level ;		/* byte 104/105 */
-
-	u_short	not_used_1 ;			/* byte 106/107 */
-	u_short not_used_2 ;			/* byte 108/109 */
-} ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 9733a11..a7ef6c8 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -1680,7 +1680,6 @@ void mac_drv_rx_complete(struct s_smc *s
 	rxd->rxd_os.skb = NULL;
 	skb_trim(skb, len);
 	skb->protocol = fddi_type_trans(skb, bp->dev);
-	skb->dev = bp->dev;	/* pass up device pointer */
 
 	netif_rx(skb);
 	bp->dev->last_rx = jiffies;
@@ -1938,7 +1937,7 @@ int mac_drv_rx_init(struct s_smc *smc, i
 	}
 	skb_reserve(skb, 3);
 	skb_put(skb, len);
-	memcpy(skb->data, look_ahead, len);
+	skb_copy_to_linear_data(skb, look_ahead, len);
 
 	// deliver frame to system
 	skb->protocol = fddi_type_trans(skb, smc->os.dev);
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index d476a3c..b07da10 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@ #include <asm/irq.h>
 #include "skge.h"
 
 #define DRV_NAME		"skge"
-#define DRV_VERSION		"1.10"
+#define DRV_VERSION		"1.11"
 #define PFX			DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE	128
@@ -135,10 +135,13 @@ static void skge_get_regs(struct net_dev
 /* Wake on Lan only supported on Yukon chips with rev 1 or above */
 static u32 wol_supported(const struct skge_hw *hw)
 {
-	if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
-		return WAKE_MAGIC | WAKE_PHY;
-	else
+	if (hw->chip_id == CHIP_ID_GENESIS)
+		return 0;
+
+	if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
 		return 0;
+
+	return WAKE_MAGIC | WAKE_PHY;
 }
 
 static u32 pci_wake_enabled(struct pci_dev *dev)
@@ -2621,6 +2624,7 @@ static int skge_down(struct net_device *
 
 static inline int skge_avail(const struct skge_ring *ring)
 {
+	smp_mb();
 	return ((ring->to_clean > ring->to_use) ? 0 : ring->count)
 		+ (ring->to_clean - ring->to_use) - 1;
 }
@@ -2654,12 +2658,12 @@ static int skge_xmit_frame(struct sk_buf
 	td->dma_hi = map >> 32;
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		int offset = skb->h.raw - skb->data;
+		const int offset = skb_transport_offset(skb);
 
 		/* This seems backwards, but it is what the sk98lin
 		 * does.  Looks like hardware is wrong?
 		 */
-		if (skb->h.ipiph->protocol == IPPROTO_UDP
+		if (ipip_hdr(skb)->protocol == IPPROTO_UDP
 	            && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
 			control = BMU_TCP_CHECK;
 		else
@@ -2709,6 +2713,8 @@ static int skge_xmit_frame(struct sk_buf
 		       dev->name, e - skge->tx_ring.start, skb->len);
 
 	skge->tx_ring.to_use = e->next;
+	smp_wmb();
+
 	if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
 		pr_debug("%s: transmit queue full\n", dev->name);
 		netif_stop_queue(dev);
@@ -2726,8 +2732,6 @@ static void skge_tx_free(struct skge_por
 {
 	struct pci_dev *pdev = skge->hw->pdev;
 
-	BUG_ON(!e->skb);
-
 	/* skb header vs. fragment */
 	if (control & BMU_STF)
 		pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
@@ -2745,7 +2749,6 @@ static void skge_tx_free(struct skge_por
 
 		dev_kfree_skb(e->skb);
 	}
-	e->skb = NULL;
 }
 
 /* Free all buffers in transmit ring */
@@ -2950,7 +2953,7 @@ static struct sk_buff *skge_rx_get(struc
 		pci_dma_sync_single_for_cpu(skge->hw->pdev,
 					    pci_unmap_addr(e, mapaddr),
 					    len, PCI_DMA_FROMDEVICE);
-		memcpy(skb->data, e->skb->data, len);
+		skb_copy_from_linear_data(e->skb, skb->data, len);
 		pci_dma_sync_single_for_device(skge->hw->pdev,
 					       pci_unmap_addr(e, mapaddr),
 					       len, PCI_DMA_FROMDEVICE);
@@ -3017,21 +3020,29 @@ static void skge_tx_done(struct net_devi
 
 	skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
 
-	netif_tx_lock(dev);
 	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
-		struct skge_tx_desc *td = e->desc;
+		u32 control = ((const struct skge_tx_desc *) e->desc)->control;
 
-		if (td->control & BMU_OWN)
+		if (control & BMU_OWN)
 			break;
 
-		skge_tx_free(skge, e, td->control);
+		skge_tx_free(skge, e, control);
 	}
 	skge->tx_ring.to_clean = e;
 
-	if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
-		netif_wake_queue(dev);
+	/* Can run lockless until we need to synchronize to restart queue. */
+	smp_mb();
 
-	netif_tx_unlock(dev);
+	if (unlikely(netif_queue_stopped(dev) &&
+		     skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+		netif_tx_lock(dev);
+		if (unlikely(netif_queue_stopped(dev) &&
+			     skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+			netif_wake_queue(dev);
+
+		}
+		netif_tx_unlock(dev);
+	}
 }
 
 static int skge_poll(struct net_device *dev, int *budget)
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 86467ae..edd7146 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -232,7 +232,6 @@ enum {
 	IS_R2_PAR_ERR	= 1<<0,	/* Queue R2 Parity Error */
 
 	IS_ERR_MSK	= IS_IRQ_MST_ERR | IS_IRQ_STAT
-			| IS_NO_STAT_M1 | IS_NO_STAT_M2
 			| IS_RAM_RD_PAR | IS_RAM_WR_PAR
 			| IS_M1_PAR_ERR | IS_M2_PAR_ERR
 			| IS_R1_PAR_ERR | IS_R2_PAR_ERR,
@@ -2447,15 +2446,15 @@ enum pause_status {
 
 
 struct skge_port {
-	u32		     msg_enable;
 	struct skge_hw	     *hw;
 	struct net_device    *netdev;
 	int		     port;
+	u32		     msg_enable;
 
 	struct skge_ring     tx_ring;
-	struct skge_ring     rx_ring;
 
-	struct net_device_stats net_stats;
+	struct skge_ring     rx_ring ____cacheline_aligned_in_smp;
+	unsigned int	     rx_buf_size;
 
 	struct timer_list    link_timer;
 	enum pause_control   flow_control;
@@ -2471,7 +2470,8 @@ struct skge_port {
 	void		     *mem;	/* PCI memory for rings */
 	dma_addr_t	     dma;
 	unsigned long	     mem_size;
-	unsigned int	     rx_buf_size;
+
+	struct net_device_stats net_stats;
 };
 
 
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index ac36152..a307310 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -32,6 +32,7 @@ #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/tcp.h>
 #include <linux/in.h>
 #include <linux/delay.h>
@@ -123,10 +124,7 @@ static const struct pci_device_id sky2_i
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
-#ifdef broken
-	/* This device causes data corruption problems that are not resolved */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
-#endif
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
@@ -1391,8 +1389,8 @@ static int sky2_xmit_frame(struct sk_buf
 	/* Check for TCP Segmentation Offload */
 	mss = skb_shinfo(skb)->gso_size;
 	if (mss != 0) {
-		mss += ((skb->h.th->doff - 5) * 4);	/* TCP options */
-		mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+		mss += tcp_optlen(skb); /* TCP options */
+		mss += ip_hdrlen(skb) + sizeof(struct tcphdr);
 		mss += ETH_HLEN;
 
 		if (mss != sky2->tx_last_mss) {
@@ -1420,14 +1418,14 @@ #endif
 
 	/* Handle TCP checksum offload */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		unsigned offset = skb->h.raw - skb->data;
+		const unsigned offset = skb_transport_offset(skb);
 		u32 tcpsum;
 
 		tcpsum = offset << 16;		/* sum start */
 		tcpsum |= offset + skb->csum_offset;	/* sum write */
 
 		ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
-		if (skb->nh.iph->protocol == IPPROTO_UDP)
+		if (ip_hdr(skb)->protocol == IPPROTO_UDP)
 			ctrl |= UDPTCP;
 
 		if (tcpsum != sky2->tx_tcpsum) {
@@ -1970,7 +1968,7 @@ static struct sk_buff *receive_copy(stru
 		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_copy_from_linear_data(re->skb, 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,
@@ -3580,10 +3578,21 @@ static int __devinit sky2_probe(struct p
 		goto err_out;
 	}
 
+	/* Some Gigabyte motherboards have 88e8056 but cause problems
+	 * There is some unresolved hardware related problem that causes
+	 * descriptor errors and receive data corruption.
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_MARVELL &&
+	    pdev->device == 0x4364 && pdev->subsystem_vendor == 0x1458) {
+		dev_err(&pdev->dev,
+			"88E8056 on Gigabyte motherboards not supported\n");
+		goto err_out_disable;
+	}
+
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
 		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
-		goto err_out;
+		goto err_out_disable;
 	}
 
 	pci_set_master(pdev);
@@ -3720,6 +3729,7 @@ err_out_free_hw:
 	kfree(hw);
 err_out_free_regions:
 	pci_release_regions(pdev);
+err_out_disable:
 	pci_disable_device(pdev);
 err_out:
 	return err;
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 2f4b1de..65bd20f 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -363,7 +363,7 @@ #endif  /* SL_INCLUDE_CSLIP */
 	}
 	skb->dev = sl->dev;
 	memcpy(skb_put(skb,count), sl->rbuff, count);
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 	skb->protocol=htons(ETH_P_IP);
 	netif_rx(skb);
 	sl->dev->last_rx = jiffies;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index c956141..81f2484 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -499,10 +499,9 @@ #else
 		SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
 		SMC_PULL_DATA(data, pkt_len+2+3);
 
-		DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+		DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
 		PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
 		dev->last_rx = jiffies;
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		lp->stats.rx_packets++;
@@ -1307,7 +1306,6 @@ smc911x_rx_dma_irq(int dma, void *data)
 	lp->current_rx_skb = NULL;
 	PRINT_PKT(skb->data, skb->len);
 	dev->last_rx = jiffies;
-	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 	netif_rx(skb);
 	lp->stats.rx_packets++;
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index bd6e845..36c1eba 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -1262,7 +1262,6 @@ static void smc_rcv(struct net_device *d
 
 		skb_reserve( skb, 2 );   /* 16 bit alignment */
 
-		skb->dev = dev;
 		data = skb_put( skb, packet_length);
 
 #ifdef USE_32_BIT
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 49f4b77..01cc3c7 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -568,7 +568,6 @@ static inline void  smc_rcv(struct net_d
 		PRINT_PKT(data, packet_len - 4);
 
 		dev->last_rx = jiffies;
-		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		lp->stats.rx_packets++;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index d2767e6..111f23d 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -55,6 +55,53 @@ #define SMC_outw(v, a, r)	writew(v, (a) 
 #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
 
+#elif defined(CONFIG_BFIN)
+
+#define SMC_IRQ_FLAGS		IRQF_TRIGGER_HIGH
+
+# if defined (CONFIG_BFIN561_EZKIT)
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	1
+#define SMC_IO_SHIFT		0
+#define SMC_NOWAIT      	1
+#define SMC_USE_BFIN_DMA	0
+
+
+#define SMC_inw(a, r)       	readw((a) + (r))
+#define SMC_outw(v, a, r)   	writew(v, (a) + (r))
+#define SMC_inl(a, r)       	readl((a) + (r))
+#define SMC_outl(v, a, r)   	writel(v, (a) + (r))
+#define SMC_outsl(a, r, p, l)	outsl((unsigned long *)((a) + (r)), p, l)
+#define SMC_insl(a, r, p, l) 	insl ((unsigned long *)((a) + (r)), p, l)
+# else
+#define SMC_CAN_USE_8BIT	0
+#define SMC_CAN_USE_16BIT	1
+#define SMC_CAN_USE_32BIT	0
+#define SMC_IO_SHIFT		0
+#define SMC_NOWAIT      	1
+#define SMC_USE_BFIN_DMA	0
+
+
+#define SMC_inw(a, r)       	readw((a) + (r))
+#define SMC_outw(v, a, r)   	writew(v, (a) + (r))
+#define SMC_outsw(a, r, p, l)	outsw((unsigned long *)((a) + (r)), p, l)
+#define SMC_insw(a, r, p, l) 	insw ((unsigned long *)((a) + (r)), p, l)
+# endif
+/* check if the mac in reg is valid */
+#define SMC_GET_MAC_ADDR(addr)					\
+	do {							\
+		unsigned int __v;				\
+		__v = SMC_inw(ioaddr, ADDR0_REG);		\
+		addr[0] = __v; addr[1] = __v >> 8;		\
+		__v = SMC_inw(ioaddr, ADDR1_REG);		\
+		addr[2] = __v; addr[3] = __v >> 8;		\
+		__v = SMC_inw(ioaddr, ADDR2_REG);		\
+		addr[4] = __v; addr[5] = __v >> 8;		\
+		if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) {		\
+			random_ether_addr(addr);		\
+		}						\
+	} while (0)
 #elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6)
 
 /* We can only do 16-bit reads and writes in the static memory space. */
@@ -232,6 +279,40 @@ #define SMC_outw(v, a, r)	outw(v, (a) + 
 #define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
 
+#elif   defined(CONFIG_SUPERH)
+
+#if defined(CONFIG_SH_7780_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_IO_SHIFT           0
+#define SMC_NOWAIT             1
+
+#define SMC_inb(a, r)          (inw((a) + ((r)&~1)) >> (8*(r%2)))&0xff
+#define SMC_inw(a, r)          inw((a) + (r))
+#define SMC_outb(v, a, r)      outw(((inw((a)+((r)&~1))*(0xff<<8*(r%2)))) | ((v)<<(8*(r&2)))), (a) + ((r)&~1))
+
+#define SMC_outw(v, a, r)      outw(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  outsw((a) + (r), p, l)
+
+#else /* BOARDS */
+
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      1
+
+#define SMC_inb(a, r)          inb((a) + (r))
+#define SMC_inw(a, r)          inw((a) + (r))
+#define SMC_outb(v, a, r)      outb(v, (a) + (r))
+#define SMC_outw(v, a, r)      outw(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  outsw((a) + (r), p, l)
+
+#endif  /* BOARDS */
+
+#define set_irq_type(irq, type) do {} while (0)
+
 #elif   defined(CONFIG_M32R)
 
 #define SMC_CAN_USE_8BIT	0
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index ed7aa0a..8069f3e 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -50,29 +50,6 @@ static int sonic_open(struct net_device 
 	if (sonic_debug > 2)
 		printk("sonic_open: initializing sonic driver.\n");
 
-	/*
-	 * We don't need to deal with auto-irq stuff since we
-	 * hardwire the sonic interrupt.
-	 */
-/*
- * XXX Horrible work around:  We install sonic_interrupt as fast interrupt.
- * This means that during execution of the handler interrupt are disabled
- * covering another bug otherwise corrupting data.  This doesn't mean
- * this glue works ok under all situations.
- *
- * Note (dhd): this also appears to prevent lockups on the Macintrash
- * when more than one Ethernet card is installed (knock on wood)
- *
- * Note (fthain): whether the above is still true is anyones guess. Certainly
- * the buffer handling algorithms will not tolerate re-entrance without some
- * mutual exclusion added. Anyway, the memcpy has now been eliminated from the
- * rx code to make this a faster "fast interrupt".
- */
-	if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) {
-		printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
-		return -EAGAIN;
-	}
-
 	for (i = 0; i < SONIC_NUM_RRS; i++) {
 		struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
 		if (skb == NULL) {
@@ -85,7 +62,6 @@ static int sonic_open(struct net_device 
 			       dev->name);
 			return -ENOMEM;
 		}
-		skb->dev = dev;
 		/* align IP header unless DMA requires otherwise */
 		if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
 			skb_reserve(skb, 2);
@@ -170,8 +146,6 @@ static int sonic_close(struct net_device
 		}
 	}
 
-	free_irq(dev->irq, dev);	/* release the IRQ */
-
 	return 0;
 }
 
@@ -179,8 +153,13 @@ static void sonic_tx_timeout(struct net_
 {
 	struct sonic_local *lp = netdev_priv(dev);
 	int i;
-	/* Stop the interrupts for this */
+	/*
+	 * put the Sonic into software-reset mode and
+	 * disable all interrupts before releasing DMA buffers
+	 */
 	SONIC_WRITE(SONIC_IMR, 0);
+	SONIC_WRITE(SONIC_ISR, 0x7fff);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
 	/* We could resend the original skbs. Easier to re-initialise. */
 	for (i = 0; i < SONIC_NUM_TDS; i++) {
 		if(lp->tx_laddr[i]) {
@@ -451,7 +430,6 @@ static void sonic_rx(struct net_device *
 				lp->stats.rx_dropped++;
 				break;
 			}
-			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);
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index e3019d5..c15e972 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -720,7 +720,7 @@ spider_net_prepare_tx_descr(struct spide
 	spin_unlock_irqrestore(&chain->lock, flags);
 
 	if (skb->protocol == htons(ETH_P_IP) && skb->ip_summed == CHECKSUM_PARTIAL)
-		switch (skb->nh.iph->protocol) {
+		switch (ip_hdr(skb)->protocol) {
 		case IPPROTO_TCP:
 			hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
 			break;
@@ -990,7 +990,6 @@ spider_net_pass_skb_up(struct spider_net
 	netdev = card->netdev;
 
 	skb = descr->skb;
-	skb->dev = netdev;
 	skb_put(skb, hwdescr->valid_size);
 
 	/* the card seems to add 2 bytes of junk in front
@@ -1831,7 +1830,7 @@ try_host_fw:
 	if (!dn)
 		goto out_err;
 
-	fw_prop = get_property(dn, "firmware", &fw_size);
+	fw_prop = of_get_property(dn, "firmware", &fw_size);
 	if (!fw_prop)
 		goto out_err;
 
@@ -2237,7 +2236,7 @@ spider_net_setup_netdev(struct spider_ne
 	if (!dn)
 		return -EIO;
 
-	mac = get_property(dn, "local-mac-address", NULL);
+	mac = of_get_property(dn, "local-mac-address", NULL);
 	if (!mac)
 		return -EIO;
 	memcpy(addr.sa_data, mac, ETH_ALEN);
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 8bba2e3..9d6e454 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1452,7 +1452,6 @@ static int __netdev_rx(struct net_device
 		   to a minimally-sized skbuff. */
 		if (pkt_len < rx_copybreak
 		    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte align the IP header */
 			pci_dma_sync_single_for_cpu(np->pci_dev,
 						    np->rx_info[entry].mapping,
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 4757aa6..a123ea8 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -775,7 +775,6 @@ static void sun3_82586_rcv_int(struct ne
 					skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
 					if(skb != NULL)
 					{
-						skb->dev = dev;
 						skb_reserve(skb,2);
 						skb_put(skb,totlen);
 						eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);
@@ -1024,10 +1023,11 @@ #endif
 	{
 		len = skb->len;
 		if (len < ETH_ZLEN) {
-			memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+			memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
+			       ETH_ZLEN);
 			len = ETH_ZLEN;
 		}
-		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+		skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
 
 #if (NUM_XMIT_BUFFS == 1)
 #	ifdef NO_NOPCOMMANDS
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 7bee45b..791e081 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -629,7 +629,7 @@ #endif
 	head->length = (-len) | 0xf000;
 	head->misc = 0;
 
-	memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+	skb_copy_from_linear_data(skb, PKTBUF_ADDR(head), skb->len);
 	if (len != skb->len)
 		memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
 
@@ -851,10 +851,9 @@ #endif
 				}
 
 
-				skb->dev = dev;
 				skb_reserve( skb, 2 );	/* 16 byte align */
 				skb_put( skb, pkt_len );	/* Make room */
-//			        memcpy( skb->data, PKTBUF_ADDR(head), pkt_len );
+//			        skb_copy_to_linear_data(skb, PKTBUF_ADDR(head), pkt_len);
 				eth_copy_and_sum(skb,
 						 PKTBUF_ADDR(head),
 						 pkt_len, 0);
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 18f8885..2ad8d58 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -855,7 +855,6 @@ static void bigmac_rx(struct bigmac *bp)
 				drops++;
 				goto drop_it;
 			}
-			copy_skb->dev = bp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index c06ecc8..f51ba31 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1308,7 +1308,6 @@ #endif
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(np->pci_dev,
 							    desc->frag[0].addr,
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 08ea61d..4328038 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -64,11 +64,9 @@ #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 #include <asm/idprom.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/pbm.h>
+#include <asm/prom.h>
 #endif
 
 #ifdef CONFIG_PPC_PMAC
@@ -845,11 +843,10 @@ static int gem_rx(struct gem *gp, int wo
 				goto drop_it;
 			}
 
-			copy_skb->dev = gp->dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			pci_dma_sync_single_for_cpu(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
-			memcpy(copy_skb->data, skb->data, len);
+			skb_copy_from_linear_data(skb, copy_skb->data, len);
 			pci_dma_sync_single_for_device(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 
 			/* We'll reuse the original ring buffer. */
@@ -1029,10 +1026,8 @@ static int gem_start_xmit(struct sk_buff
 
 	ctrl = 0;
 	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 = csum_start_off + skb->csum_offset;
+		const u64 csum_start_off = skb_transport_offset(skb);
+		const u64 csum_stuff_off = csum_start_off + skb->csum_offset;
 
 		ctrl = (TXDCTRL_CENAB |
 			(csum_start_off << 15) |
@@ -2849,7 +2844,7 @@ static int gem_ioctl(struct net_device *
 	return rc;
 }
 
-#if (!defined(__sparc__) && !defined(CONFIG_PPC_PMAC))
+#if (!defined(CONFIG_SPARC) && !defined(CONFIG_PPC_PMAC))
 /* Fetch MAC address from vital product data of PCI ROM. */
 static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, unsigned char *dev_addr)
 {
@@ -2904,36 +2899,19 @@ #endif /* not Sparc and not PPC */
 
 static int __devinit gem_get_device_address(struct gem *gp)
 {
-#if defined(__sparc__) || defined(CONFIG_PPC_PMAC)
+#if defined(CONFIG_SPARC) || defined(CONFIG_PPC_PMAC)
 	struct net_device *dev = gp->dev;
-#endif
-
-#if defined(__sparc__)
-	struct pci_dev *pdev = gp->pdev;
-	struct pcidev_cookie *pcp = pdev->sysdata;
-	int use_idprom = 1;
-
-	if (pcp != NULL) {
-		unsigned char *addr;
-		int len;
-
-		addr = of_get_property(pcp->prom_node, "local-mac-address",
-				       &len);
-		if (addr && len == 6) {
-			use_idprom = 0;
-			memcpy(dev->dev_addr, addr, 6);
-		}
-	}
-	if (use_idprom)
-		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#elif defined(CONFIG_PPC_PMAC)
 	const unsigned char *addr;
 
-	addr = get_property(gp->of_node, "local-mac-address", NULL);
+	addr = of_get_property(gp->of_node, "local-mac-address", NULL);
 	if (addr == NULL) {
+#ifdef CONFIG_SPARC
+		addr = idprom->id_ethaddr;
+#else
 		printk("\n");
 		printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
 		return -1;
+#endif
 	}
 	memcpy(dev->dev_addr, addr, 6);
 #else
@@ -3091,7 +3069,7 @@ static int __devinit gem_init_one(struct
 	/* On Apple, we want a reference to the Open Firmware device-tree
 	 * node. We use it for clock control.
 	 */
-#ifdef CONFIG_PPC_PMAC
+#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC)
 	gp->of_node = pci_device_to_OF_node(pdev);
 #endif
 
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index a70067c..58cf87c 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -1025,7 +1025,7 @@ struct gem {
 
 	struct pci_dev		*pdev;
 	struct net_device	*dev;
-#ifdef CONFIG_PPC_PMAC
+#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_SPARC)
 	struct device_node	*of_node;
 #endif
 };
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 56a110c..61843fd 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -451,7 +451,7 @@ #ifdef CONFIG_PPC_PMAC
 	if (phy->platform_data) {
 		struct device_node *np = of_get_parent(phy->platform_data);
 		int can_low_power = 1;
-		if (np == NULL || get_property(np, "no-autolowpower", NULL))
+		if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
 			can_low_power = 0;
 		if (can_low_power) {
 			/* Enable automatic low-power */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 192bbc9..51c3fe2 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -55,9 +55,6 @@ #include <asm/irq.h>
 
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
-#ifdef CONFIG_SPARC
-#include <asm/pbm.h>
-#endif
 #endif
 
 #include "sunhme.h"
@@ -2058,11 +2055,10 @@ static void happy_meal_rx(struct happy_m
 				goto drop_it;
 			}
 
-			copy_skb->dev = dev;
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
-			memcpy(copy_skb->data, skb->data, len);
+			skb_copy_from_linear_data(skb, copy_skb->data, len);
 			hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
 
 			/* Reuse original ring buffer. */
@@ -2270,10 +2266,8 @@ static int happy_meal_start_xmit(struct 
 
 	tx_flags = TXFLAG_OWN;
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
-		u32 csum_start_off, csum_stuff_off;
-
-		csum_start_off = (u32) (skb->h.raw - skb->data);
-		csum_stuff_off = csum_start_off + skb->csum_offset;
+		const u32 csum_start_off = skb_transport_offset(skb);
+		const u32 csum_stuff_off = csum_start_off + skb->csum_offset;
 
 		tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE |
 			    ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) |
@@ -2704,7 +2698,7 @@ static int __devinit happy_meal_sbus_pro
 			dev->dev_addr[i] = macaddr[i];
 		macaddr[5]++;
 	} else {
-		unsigned char *addr;
+		const unsigned char *addr;
 		int len;
 
 		addr = of_get_property(dp, "local-mac-address", &len);
@@ -2986,7 +2980,7 @@ static int __devinit happy_meal_pci_prob
 {
 	struct quattro *qp = NULL;
 #ifdef CONFIG_SPARC
-	struct pcidev_cookie *pcp;
+	struct device_node *dp;
 #endif
 	struct happy_meal *hp;
 	struct net_device *dev;
@@ -2998,13 +2992,8 @@ #endif
 
 	/* Now make sure pci_dev cookie is there. */
 #ifdef CONFIG_SPARC
-	pcp = pdev->sysdata;
-	if (pcp == NULL) {
-		printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
-		return -ENODEV;
-	}
-
-	strcpy(prom_name, pcp->prom_node->name);
+	dp = pci_device_to_OF_node(pdev);
+	strcpy(prom_name, dp->name);
 #else
 	if (is_quattro_p(pdev))
 		strcpy(prom_name, "SUNW,qfe");
@@ -3081,11 +3070,11 @@ #endif
 		macaddr[5]++;
 	} else {
 #ifdef CONFIG_SPARC
-		unsigned char *addr;
+		const unsigned char *addr;
 		int len;
 
 		if (qfe_slot != -1 &&
-		    (addr = of_get_property(pcp->prom_node,
+		    (addr = of_get_property(dp,
 					    "local-mac-address", &len)) != NULL
 		    && len == 6) {
 			memcpy(dev->dev_addr, addr, 6);
@@ -3105,7 +3094,7 @@ #endif
 	hp->tcvregs    = (hpreg_base + 0x7000UL);
 
 #ifdef CONFIG_SPARC
-	hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
+	hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
 	if (hp->hm_revision == 0xff) {
 		unsigned char prev;
 
@@ -3300,7 +3289,7 @@ static int __devinit hme_sbus_probe(stru
 {
 	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
 	struct device_node *dp = dev->node;
-	char *model = of_get_property(dp, "model", NULL);
+	const char *model = of_get_property(dp, "model", NULL);
 	int is_qfe = (match->data != NULL);
 
 	if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index b0929a4..4272253 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -547,7 +547,6 @@ static void lance_rx_dvma(struct net_dev
 
 			lp->stats.rx_bytes += len;
 
-			skb->dev = dev;
 			skb_reserve(skb, 2);		/* 16 byte align */
 			skb_put(skb, len);		/* make room */
 			eth_copy_and_sum(skb,
@@ -721,7 +720,6 @@ static void lance_rx_pio(struct net_devi
 
 			lp->stats.rx_bytes += len;
 
-			skb->dev = dev;
 			skb_reserve (skb, 2);		/* 16 byte align */
 			skb_put(skb, len);		/* make room */
 			lance_piocopy_to_skb(skb, &(ib->rx_buf[entry][0]), len);
@@ -1145,7 +1143,7 @@ static int lance_start_xmit(struct sk_bu
 		struct lance_init_block *ib = lp->init_block_mem;
 		ib->btx_ring [entry].length = (-len) | 0xf000;
 		ib->btx_ring [entry].misc = 0;
-		memcpy((char *)&ib->tx_buf [entry][0], skb->data, skblen);
+		skb_copy_from_linear_data(skb, &ib->tx_buf [entry][0], skblen);
 		if (len != skblen)
 			memset((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
 		ib->btx_ring [entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index f3bad56..fa70e0b 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -437,7 +437,6 @@ static void qe_rx(struct sunqe *qep)
 				drops++;
 				qep->net_stats.rx_dropped++;
 			} else {
-				skb->dev = qep->dev;
 				skb_reserve(skb, 2);
 				skb_put(skb, len);
 				eth_copy_and_sum(skb, (unsigned char *) this_qbuf,
@@ -593,7 +592,7 @@ static int qe_start_xmit(struct sk_buff 
 	/* Avoid a race... */
 	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
 
-	memcpy(txbuf, skb->data, len);
+	skb_copy_from_linear_data(skb, txbuf, len);
 
 	qep->qe_block->qe_txd[entry].tx_addr = txbuf_dvma;
 	qep->qe_block->qe_txd[entry].tx_flags =
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index e3a7e3c..463d600 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,35 +1,34 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *                ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
  *
  * Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba 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 driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ *	-----<snip>-----
+ *	Copyright 2001 MontaVista Software Inc.
+ *	Author: MontaVista Software, Inc.
+ *		ahennessy@mvista.com
+ *	Copyright (C) 2000-2001 Toshiba Corporation
+ *	static const char *version =
+ *		"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ *	-----<snip>-----
  *
- * 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.
+ * 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.
  *
- * You 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 TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
  */
 
-static const char *version =
-	"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#ifdef TC35815_NAPI
+#define DRV_VERSION	"1.35-NAPI"
+#else
+#define DRV_VERSION	"1.35"
+#endif
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME			"tc35815"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -40,6 +39,7 @@ #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -47,36 +47,47 @@ #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
 #include <asm/io.h>
-#include <asm/dma.h>
 #include <asm/byteorder.h>
 
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
 /* First, a few definitions that the brave might change. */
 
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
 #define GATHER_TXINT	/* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
+
+typedef enum {
+	TC35815CF = 0,
+	TC35815_NWU,
+	TC35815_TX4939,
+} board_t;
+
+/* indexed by board_t, above */
+static const struct {
+	const char *name;
+} board_info[] __devinitdata = {
+	{ "TOSHIBA TC35815CF 10/100BaseTX" },
+	{ "TOSHIBA TC35815 with Wake on LAN" },
+	{ "TOSHIBA TC35815/TX4939" },
+};
+
+static const struct pci_device_id tc35815_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+	{PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+	{0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
 
-#define vtonocache(p)	KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+	int speed;
+	int duplex;
+	int doforce;
+} options;
 
 /*
  * Registers
@@ -119,6 +130,11 @@ struct tc35815_regs {
  * Bit assignments
  */
 /* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign            0x00c00000 /* 1:Reception Alignment           */
+#define DMA_RxAlign_1          0x00400000
+#define DMA_RxAlign_2          0x00800000
+#define DMA_RxAlign_3          0x00c00000
+#define DMA_M66EnStat          0x00080000 /* 1:66MHz Enable State            */
 #define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
 #define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
 #define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
@@ -269,42 +285,6 @@ #define MD_CA_Busy             0x0000080
 #define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */
 
 
-/* MII register offsets */
-#define MII_CONTROL             0x0000
-#define MII_STATUS              0x0001
-#define MII_PHY_ID0             0x0002
-#define MII_PHY_ID1             0x0003
-#define MII_ANAR                0x0004
-#define MII_ANLPAR              0x0005
-#define MII_ANER                0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX             0x0100
-#define MIICNTL_RST_AUTO        0x0200
-#define MIICNTL_ISOLATE         0x0400
-#define MIICNTL_PWRDWN          0x0800
-#define MIICNTL_AUTO            0x1000
-#define MIICNTL_SPEED           0x2000
-#define MIICNTL_LPBK            0x4000
-#define MIICNTL_RESET           0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT             0x0001
-#define MIISTAT_JAB             0x0002
-#define MIISTAT_LINK            0x0004
-#define MIISTAT_CAN_AUTO        0x0008
-#define MIISTAT_FAULT           0x0010
-#define MIISTAT_AUTO_DONE       0x0020
-#define MIISTAT_CAN_T           0x0800
-#define MIISTAT_CAN_T_FDX       0x1000
-#define MIISTAT_CAN_TX          0x2000
-#define MIISTAT_CAN_TX_FDX      0x4000
-#define MIISTAT_CAN_T4          0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX           0x0100
-#define MII_AN_TX_HDX           0x0080
-#define MII_AN_10_FDX           0x0040
-#define MII_AN_10_HDX           0x0020
-
-
 /*
  * Descriptors
  */
@@ -352,32 +332,51 @@ #undef NO_CHECK_CARRIER	/* Does not chec
 
 #ifdef NO_CHECK_CARRIER
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7d01 */
+	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #else
 #define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
-	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
-	Tx_En)	/* maybe  0x7f01 */
+	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7b01 */
 #endif
 #define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
 	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
-
 #define INT_EN_CMD  (Int_NRAbtEn | \
-	 Int_DParDEn | Int_DParErrEn | \
+	Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
 	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
 	Int_STargAbtEn | \
 	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD	DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp)	likely((lp)->boardtype != TC35815CF)
 
 /* Tuning parameters */
 #define DMA_BURST_SIZE	32
 #define TX_THRESHOLD	1024
+#define TX_THRESHOLD_MAX 1536       /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10  /* setting threshold max value when overrun error occured this count. */
 
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
 #define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES	8	/* >= 2 */
+#define RX_BUF_NUM	8	/* >= 2 */
 #define RX_FD_NUM	250	/* >= 32 */
 #define TX_FD_NUM	128
+#define RX_BUF_SIZE	PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM	128	/* < 256 */
+#define RX_FD_NUM	256	/* >= 32 */
+#define TX_FD_NUM	128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE	PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE	ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE	(2 / 2)	/* max 2 BD per RxFD */
+#define NAPI_WEIGHT	16
 
 struct TxFD {
 	struct FDesc fd;
@@ -392,18 +391,27 @@ struct RxFD {
 
 struct FrFD {
 	struct FDesc fd;
-	struct BDesc bd[RX_BUF_PAGES];
+	struct BDesc bd[RX_BUF_NUM];
 };
 
 
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr)	readl(addr)
+#define tc_writel(d, addr)	writel(d, addr)
+
+#define TC35815_TX_TIMEOUT  msecs_to_jiffies(400)
 
-dma_addr_t priv_dma_handle;
+/* Timer state engine. */
+enum tc35815_timer_state {
+	arbwait  = 0,	/* Waiting for auto negotiation to complete.          */
+	lupwait  = 1,	/* Auto-neg complete, awaiting link-up status.        */
+	ltrywait = 2,	/* Forcing try of all modes, from fastest to slowest. */
+	asleep   = 3,	/* Time inactive.                                     */
+	lcheck   = 4,	/* Check link status.                                 */
+};
 
 /* Information that need to be kept for each board. */
 struct tc35815_local {
-	struct net_device *next_module;
+	struct pci_dev *pci_dev;
 
 	/* statistics */
 	struct net_device_stats stats;
@@ -411,216 +419,371 @@ struct tc35815_local {
 		int max_tx_qlen;
 		int tx_ints;
 		int rx_ints;
+	        int tx_underrun;
 	} lstats;
 
-	int tbusy;
-	int option;
-#define TC35815_OPT_AUTO	0x00
-#define TC35815_OPT_10M	0x01
-#define TC35815_OPT_100M	0x02
-#define TC35815_OPT_FULLDUP	0x04
-	int linkspeed;	/* 10 or 100 */
+	/* Tx control lock.  This protects the transmit buffer ring
+	 * state along with the "tx full" state of the driver.  This
+	 * means all netif_queue flow control actions are protected
+	 * by this lock as well.
+	 */
+	spinlock_t lock;
+
+	int phy_addr;
 	int fullduplex;
+	unsigned short saved_lpa;
+	struct timer_list timer;
+	enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
+	unsigned int timer_ticks;	/* Number of clicks at each state  */
 
 	/*
 	 * Transmitting: Batch Mode.
 	 *	1 BD in 1 TxFD.
-	 * Receiving: Packing Mode.
+	 * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
 	 *	1 circular FD for Free Buffer List.
-	 *	RX_BUG_PAGES BD in Free Buffer FD.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
 	 *	One Free Buffer BD has PAGE_SIZE data buffer.
+	 * Or Non-Packing Mode.
+	 *	1 circular FD for Free Buffer List.
+	 *	RX_BUF_NUM BD in Free Buffer FD.
+	 *	One Free Buffer BD has ETH_FRAME_LEN data buffer.
 	 */
-        struct pci_dev *pdev;
-	dma_addr_t fd_buf_dma_handle;
-	void * fd_buf;	/* for TxFD, TxFD, FrFD */
+	void * fd_buf;	/* for TxFD, RxFD, FrFD */
+	dma_addr_t fd_buf_dma;
 	struct TxFD *tfd_base;
-	int tfd_start;
-	int tfd_end;
+	unsigned int tfd_start;
+	unsigned int tfd_end;
 	struct RxFD *rfd_base;
 	struct RxFD *rfd_limit;
 	struct RxFD *rfd_cur;
 	struct FrFD *fbl_ptr;
+#ifdef TC35815_USE_PACKEDBUFFER
 	unsigned char fbl_curid;
-	dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
-	void * data_buf[RX_BUF_PAGES];		/* packing */
-	spinlock_t lock;
+	void * data_buf[RX_BUF_NUM];		/* packing */
+	dma_addr_t data_buf_dma[RX_BUF_NUM];
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM];
+#else
+	unsigned int fbl_count;
+	struct {
+		struct sk_buff *skb;
+		dma_addr_t skb_dma;
+	} tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+#endif
+	struct mii_if_info mii;
+	unsigned short mii_id[2];
+	u32 msg_enable;
+	board_t boardtype;
 };
 
-/* Index to functions, as function prototypes. */
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+	return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+#ifdef DEBUG
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+	int i;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+		if (bus >= lp->data_buf_dma[i] &&
+		    bus < lp->data_buf_dma[i] + PAGE_SIZE)
+			return (void *)((u8 *)lp->data_buf[i] +
+					(bus - lp->data_buf_dma[i]));
+	}
+	return NULL;
+}
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	void *buf;
+	/* pci_map + pci_dma_sync will be more effective than
+	 * pci_alloc_consistent on some archs. */
+	if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+		return NULL;
+	*dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		free_page((unsigned long)buf);
+		return NULL;
+	}
+	return buf;
+#else
+	return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+	pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+	free_page((unsigned long)buf);
+#else
+	pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+				       struct pci_dev *hwdev,
+				       dma_addr_t *dma_handle)
+{
+	struct sk_buff *skb;
+	skb = dev_alloc_skb(RX_BUF_SIZE);
+	if (!skb)
+		return NULL;
+	*dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+				     PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(*dma_handle)) {
+		dev_kfree_skb_any(skb);
+		return NULL;
+	}
+	skb_reserve(skb, 2);	/* make IP header 4byte aligned */
+	return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+	pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+			 PCI_DMA_FROMDEVICE);
+	dev_kfree_skb_any(skb);
+}
+#endif /* TC35815_USE_PACKEDBUFFER */
+
+/* Index to functions, as function prototypes. */
 
 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);
+static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int	tc35815_rx(struct net_device *dev, int limit);
+static int	tc35815_poll(struct net_device *dev, int *budget);
+#else
 static void	tc35815_rx(struct net_device *dev);
+#endif
 static void	tc35815_txdone(struct net_device *dev);
 static int	tc35815_close(struct net_device *dev);
 static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
 static void	tc35815_set_multicast_list(struct net_device *dev);
+static void     tc35815_tx_timeout(struct net_device *dev);
+static int	tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void	tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
 
+/* Example routines you must write ;->. */
 static void 	tc35815_chip_reset(struct net_device *dev);
 static void 	tc35815_chip_init(struct net_device *dev);
+static void	tc35815_find_phy(struct net_device *dev);
 static void 	tc35815_phy_chip_init(struct net_device *dev);
 
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+#ifdef DEBUG
+static void	panic_queues(struct net_device *dev);
+#endif
 
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
-    { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-    { 0, }
-};
+static void tc35815_timer(unsigned long data);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val);
 
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int i;
 
-int
-tc35815_probe(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+	/* dev_addr will be overwritten on NETDEV_REGISTER event */
+	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+		;
+	for (i = 0; i < 6; i += 2) {
+		unsigned short data;
+		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+			;
+		data = tc_readl(&tr->PROM_Data);
+		dev->dev_addr[i] = data & 0xff;
+		dev->dev_addr[i+1] = data >> 8;
+	}
+}
+
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
-	int err = 0;
-	int ret;
-	unsigned long pci_memaddr;
-	unsigned int pci_irq_line;
+	void __iomem *ioaddr = NULL;
+	struct net_device *dev;
+	struct tc35815_local *lp;
+	int rc;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+	static int printed_version;
+	if (!printed_version++) {
+		printk(version);
+		dev_printk(KERN_DEBUG, &pdev->dev,
+			   "speed:%d duplex:%d doforce:%d\n",
+			   options.speed, options.duplex, options.doforce);
+	}
 
-	printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+	if (!pdev->irq) {
+		dev_warn(&pdev->dev, "no IRQ assigned.\n");
+		return -ENODEV;
+	}
 
-	err = pci_enable_device(pdev);
-	if (err)
-		return err;
+	/* dev zeroed in alloc_etherdev */
+	dev = alloc_etherdev (sizeof (*lp));
+	if (dev == NULL) {
+		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	lp = dev->priv;
+
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
 
-        pci_memaddr = pci_resource_start (pdev, 1);
+	mmio_start = pci_resource_start (pdev, 1);
+	mmio_end = pci_resource_end (pdev, 1);
+	mmio_flags = pci_resource_flags (pdev, 1);
+	mmio_len = pci_resource_len (pdev, 1);
 
-        printk(KERN_INFO "    pci_memaddr=%#08lx  resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+	/* set this immediately, we need to know before
+	 * we talk to the chip directly */
 
-	if (!pci_memaddr) {
-		printk(KERN_WARNING "no PCI MEM resources, aborting\n");
-		ret = -ENODEV;
+	/* make sure PCI base addr 1 is MMIO */
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
 		goto err_out;
 	}
-	pci_irq_line = pdev->irq;
-	/* irq disabled. */
-	if (pci_irq_line == 0) {
-		printk(KERN_WARNING "no PCI irq, aborting\n");
-		ret = -ENODEV;
+
+	/* check for weird/broken PCI region reporting */
+	if ((mmio_len < sizeof(struct tc35815_regs))) {
+		dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
+		rc = -ENODEV;
 		goto err_out;
 	}
 
-	ret =  tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
-	if (ret)
+	rc = pci_request_regions (pdev, MODNAME);
+	if (rc)
 		goto err_out;
 
-	pci_set_master(pdev);
-
-	return 0;
+	pci_set_master (pdev);
 
-err_out:
-	pci_disable_device(pdev);
-	return ret;
-}
+	/* ioremap MMIO region */
+	ioaddr = ioremap (mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
+	}
 
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
-{
-	static unsigned version_printed = 0;
-	int i, ret;
-	struct tc35815_local *lp;
-	struct tc35815_regs *tr;
-	struct net_device *dev;
+	/* Initialize the device structure. */
+	dev->open = tc35815_open;
+	dev->hard_start_xmit = tc35815_send_packet;
+	dev->stop = tc35815_close;
+	dev->get_stats = tc35815_get_stats;
+	dev->set_multicast_list = tc35815_set_multicast_list;
+	dev->do_ioctl = tc35815_ioctl;
+	dev->ethtool_ops = &tc35815_ethtool_ops;
+	dev->tx_timeout = tc35815_tx_timeout;
+	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+	dev->poll = tc35815_poll;
+	dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = tc35815_poll_controller;
+#endif
 
-	/* Allocate a new 'dev' if needed. */
-	dev = alloc_etherdev(sizeof(struct tc35815_local));
-	if (dev == NULL)
-		return -ENOMEM;
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
 
-	/*
-	 * alloc_etherdev allocs and zeros dev->priv
-	 */
+	/* dev->priv/lp zeroed and aligned in alloc_etherdev */
 	lp = dev->priv;
+	spin_lock_init(&lp->lock);
+	lp->pci_dev = pdev;
+	lp->boardtype = ent->driver_data;
 
-	if (tc35815_debug  &&  version_printed++ == 0)
-		printk(KERN_DEBUG "%s", version);
-
-	/* Fill in the 'dev' fields. */
-	dev->irq = irq;
-	dev->base_addr = (unsigned long)ioremap(base_addr,
-						sizeof(struct tc35815_regs));
-	if (!dev->base_addr) {
-		ret = -ENOMEM;
-		goto err_out;
-	}
-	tr = (struct tc35815_regs*)dev->base_addr;
+	lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+	pci_set_drvdata(pdev, dev);
 
+	/* Soft reset the chip. */
 	tc35815_chip_reset(dev);
 
-	/* Retrieve and print the ethernet address. */
-	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-		;
-	for (i = 0; i < 6; i += 2) {
-		unsigned short data;
-		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
-		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
-			;
-		data = tc_readl(&tr->PROM_Data);
-		dev->dev_addr[i] = data & 0xff;
-		dev->dev_addr[i+1] = data >> 8;
-	}
+	/* Retrieve the ethernet address. */
+	tc35815_init_dev_addr(dev);
+
+	rc = register_netdev (dev);
+	if (rc)
+		goto err_out_unmap;
+
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+	printk(KERN_INFO "%s: %s at 0x%lx, "
+		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+		"IRQ %d\n",
+		dev->name,
+		board_info[ent->driver_data].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);
+
+	setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
+	lp->mii.dev = dev;
+	lp->mii.mdio_read = tc_mdio_read;
+	lp->mii.mdio_write = tc_mdio_write;
+	lp->mii.phy_id_mask = 0x1f;
+	lp->mii.reg_num_mask = 0x1f;
+	tc35815_find_phy(dev);
+	lp->mii.phy_id = lp->phy_addr;
+	lp->mii.full_duplex = 0;
+	lp->mii.force_media = 0;
 
-	/* Initialize the device structure. */
-	lp->pdev = pdev;
-	lp->next_module = root_tc35815_dev;
-	root_tc35815_dev = dev;
+	return 0;
 
-	spin_lock_init(&lp->lock);
+err_out_unmap:
+	iounmap(ioaddr);
+err_out_free_res:
+	pci_release_regions (pdev);
+err_out:
+	free_netdev (dev);
+	return rc;
+}
 
-	if (dev->mem_start > 0) {
-		lp->option = dev->mem_start;
-		if ((lp->option & TC35815_OPT_10M) &&
-		    (lp->option & TC35815_OPT_100M)) {
-			/* if both speed speficied, auto select. */
-			lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
-		}
-	}
-	//XXX fixme
-        lp->option |= TC35815_OPT_10M;
 
-	/* do auto negotiation */
-	tc35815_phy_chip_init(dev);
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	unsigned long mmio_addr;
 
-	dev->open		= tc35815_open;
-	dev->stop		= tc35815_close;
-	dev->tx_timeout         = tc35815_tx_timeout;
-	dev->watchdog_timeo     = TX_TIMEOUT;
-	dev->hard_start_xmit	= tc35815_send_packet;
-	dev->get_stats		= tc35815_get_stats;
-	dev->set_multicast_list = tc35815_set_multicast_list;
-	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, &pdev->dev);
+	mmio_addr = dev->base_addr;
 
-	ret = register_netdev(dev);
-	if (ret)
-		goto err_out_iounmap;
+	unregister_netdev (dev);
 
-	printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
-	       dev->name, cardname, base_addr, irq);
-	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i]);
-	printk("\n");
-	printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
-	       dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+	if (mmio_addr) {
+		iounmap ((void __iomem *)mmio_addr);
+		pci_release_regions (pdev);
+	}
 
-	return 0;
+	free_netdev (dev);
 
-err_out_iounmap:
-	iounmap((void *) dev->base_addr);
-err_out:
-	free_netdev(dev);
-	return ret;
+	pci_set_drvdata (pdev, NULL);
 }
 
-
 static int
 tc35815_init_queues(struct net_device *dev)
 {
@@ -629,44 +792,64 @@ tc35815_init_queues(struct net_device *d
 	unsigned long fd_addr;
 
 	if (!lp->fd_buf) {
-		if (sizeof(struct FDesc) +
-		    sizeof(struct BDesc) * RX_BUF_PAGES +
-		    sizeof(struct FDesc) * RX_FD_NUM +
-		    sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
-			printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
-			return -ENOMEM;
-		}
+		BUG_ON(sizeof(struct FDesc) +
+		       sizeof(struct BDesc) * RX_BUF_NUM +
+		       sizeof(struct FDesc) * RX_FD_NUM +
+		       sizeof(struct TxFD) * TX_FD_NUM >
+		       PAGE_SIZE * FD_PAGE_NUM);
 
-		if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+		if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
 			return -ENOMEM;
-		for (i = 0; i < RX_BUF_PAGES; i++) {
-			if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
+		for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+			if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
 				while (--i >= 0) {
-					free_page((unsigned long)lp->data_buf[i]);
-					lp->data_buf[i] = 0;
+					free_rxbuf_page(lp->pci_dev,
+							lp->data_buf[i],
+							lp->data_buf_dma[i]);
+					lp->data_buf[i] = NULL;
 				}
-				free_page((unsigned long)lp->fd_buf);
-				lp->fd_buf = 0;
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
+				lp->fd_buf = NULL;
+				return -ENOMEM;
+			}
+#else
+			lp->rx_skbs[i].skb =
+				alloc_rxbuf_skb(dev, lp->pci_dev,
+						&lp->rx_skbs[i].skb_dma);
+			if (!lp->rx_skbs[i].skb) {
+				while (--i >= 0) {
+					free_rxbuf_skb(lp->pci_dev,
+						       lp->rx_skbs[i].skb,
+						       lp->rx_skbs[i].skb_dma);
+					lp->rx_skbs[i].skb = NULL;
+				}
+				pci_free_consistent(lp->pci_dev,
+						    PAGE_SIZE * FD_PAGE_NUM,
+						    lp->fd_buf,
+						    lp->fd_buf_dma);
+				lp->fd_buf = NULL;
 				return -ENOMEM;
 			}
-#ifdef __mips__
-			dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
 #endif
 		}
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+		printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+		       dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+		printk(" DataBuf");
+		for (i = 0; i < RX_BUF_NUM; i++)
+			printk(" %p", lp->data_buf[i]);
 #endif
+		printk("\n");
 	} else {
-		memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+		for (i = 0; i < FD_PAGE_NUM; i++) {
+			clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+		}
 	}
-#ifdef __mips__
-	fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
 	fd_addr = (unsigned long)lp->fd_buf;
-#endif
 
 	/* Free Descriptors (for Receive) */
 	lp->rfd_base = (struct RxFD *)fd_addr;
@@ -675,34 +858,66 @@ #endif
 		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
 	}
 	lp->rfd_cur = lp->rfd_base;
-	lp->rfd_limit = (struct RxFD *)(fd_addr -
-					sizeof(struct FDesc) -
-					sizeof(struct BDesc) * 30);
+	lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
 
 	/* Transmit Descriptors */
 	lp->tfd_base = (struct TxFD *)fd_addr;
 	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
 	for (i = 0; i < TX_FD_NUM; i++) {
-		lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
 	}
-	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
 	lp->tfd_start = 0;
 	lp->tfd_end = 0;
 
 	/* Buffer List (for Receive) */
 	lp->fbl_ptr = (struct FrFD *)fd_addr;
-	lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
-	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
-	for (i = 0; i < RX_BUF_PAGES; i++) {
-		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+	lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
+	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+#ifndef TC35815_USE_PACKEDBUFFER
+	/*
+	 * move all allocated skbs to head of rx_skbs[] array.
+	 * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+	 * tc35815_rx() had failed.
+	 */
+	lp->fbl_count = 0;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+		if (lp->rx_skbs[i].skb) {
+			if (i != lp->fbl_count) {
+				lp->rx_skbs[lp->fbl_count].skb =
+					lp->rx_skbs[i].skb;
+				lp->rx_skbs[lp->fbl_count].skb_dma =
+					lp->rx_skbs[i].skb_dma;
+			}
+			lp->fbl_count++;
+		}
+	}
+#endif
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
+#else
+		if (i >= lp->fbl_count) {
+			lp->fbl_ptr->bd[i].BuffData = 0;
+			lp->fbl_ptr->bd[i].BDCtl = 0;
+			continue;
+		}
+		lp->fbl_ptr->bd[i].BuffData =
+			cpu_to_le32(lp->rx_skbs[i].skb_dma);
+#endif
 		/* BDID is index of FrFD.bd[] */
 		lp->fbl_ptr->bd[i].BDCtl =
-			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+				    RX_BUF_SIZE);
 	}
+#ifdef TC35815_USE_PACKEDBUFFER
 	lp->fbl_curid = 0;
+#endif
 
+	printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+	       dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
 	return 0;
 }
 
@@ -713,11 +928,25 @@ tc35815_clear_queues(struct net_device *
 	int i;
 
 	for (i = 0; i < TX_FD_NUM; i++) {
-		struct sk_buff *skb = (struct sk_buff *)
-			le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-		if (skb)
+		u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+		struct sk_buff *skb =
+			fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+		if (lp->tx_skbs[i].skb != skb) {
+			printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+			panic_queues(dev);
+		}
+#else
+		BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+		if (skb) {
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[i].skb = NULL;
+			lp->tx_skbs[i].skb_dma = 0;
 			dev_kfree_skb_any(skb);
-		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		}
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 	}
 
 	tc35815_init_queues(dev);
@@ -731,28 +960,53 @@ tc35815_free_queues(struct net_device *d
 
 	if (lp->tfd_base) {
 		for (i = 0; i < TX_FD_NUM; i++) {
-			struct sk_buff *skb = (struct sk_buff *)
-				le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
-			if (skb)
-				dev_kfree_skb_any(skb);
-			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+			u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+			struct sk_buff *skb =
+				fdsystem != 0xffffffff ?
+				lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+			if (lp->tx_skbs[i].skb != skb) {
+				printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+				panic_queues(dev);
+			}
+#else
+			BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+			if (skb) {
+				dev_kfree_skb(skb);
+				pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+				lp->tx_skbs[i].skb = NULL;
+				lp->tx_skbs[i].skb_dma = 0;
+			}
+			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
 		}
 	}
 
 	lp->rfd_base = NULL;
-	lp->rfd_base = NULL;
 	lp->rfd_limit = NULL;
 	lp->rfd_cur = NULL;
 	lp->fbl_ptr = NULL;
 
-	for (i = 0; i < RX_BUF_PAGES; i++) {
-		if (lp->data_buf[i])
-			free_page((unsigned long)lp->data_buf[i]);
-		lp->data_buf[i] = 0;
+	for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+		if (lp->data_buf[i]) {
+			free_rxbuf_page(lp->pci_dev,
+					lp->data_buf[i], lp->data_buf_dma[i]);
+			lp->data_buf[i] = NULL;
+		}
+#else
+		if (lp->rx_skbs[i].skb) {
+			free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+				       lp->rx_skbs[i].skb_dma);
+			lp->rx_skbs[i].skb = NULL;
+		}
+#endif
+	}
+	if (lp->fd_buf) {
+		pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+				    lp->fd_buf, lp->fd_buf_dma);
+		lp->fd_buf = NULL;
 	}
-	if (lp->fd_buf)
-		__free_pages(lp->fd_buf, FD_PAGE_ORDER);
-	lp->fd_buf = NULL;
 }
 
 static void
@@ -792,6 +1046,7 @@ dump_rxfd(struct RxFD *fd)
 	return bd_count;
 }
 
+#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
 static void
 dump_frfd(struct FrFD *fd)
 {
@@ -802,20 +1057,22 @@ dump_frfd(struct FrFD *fd)
 	       le32_to_cpu(fd->fd.FDStat),
 	       le32_to_cpu(fd->fd.FDCtl));
 	printk("BD: ");
-	for (i = 0; i < RX_BUF_PAGES; i++)
+	for (i = 0; i < RX_BUF_NUM; i++)
 		printk(" %08x %08x",
 		       le32_to_cpu(fd->bd[i].BuffData),
 		       le32_to_cpu(fd->bd[i].BDCtl));
 	printk("\n");
 }
+#endif
 
+#ifdef DEBUG
 static void
 panic_queues(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
 	int i;
 
-	printk("TxFD base %p, start %d, end %d\n",
+	printk("TxFD base %p, start %u, end %u\n",
 	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
 	printk("RxFD base %p limit %p cur %p\n",
 	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
@@ -829,31 +1086,13 @@ panic_queues(struct net_device *dev)
 	dump_frfd(lp->fbl_ptr);
 	panic("%s: Illegal queue state.", dev->name);
 }
-
-#if 0
-static void print_buf(char *add, int length)
-{
-	int i;
-	int len = length;
-
-	printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
-
-	if (len > 100)
-		len = 100;
-	for (i = 0; i < len; i++) {
-		printk(" %2.2X", (unsigned char) add[i]);
-		if (!(i % 16))
-			printk("\n");
-	}
-	printk("\n");
-}
 #endif
 
 static void print_eth(char *add)
 {
 	int i;
 
-	printk("print_eth(%08x)\n", (unsigned int) add);
+	printk("print_eth(%p)\n", add);
 	for (i = 0; i < 6; i++)
 		printk(" %2.2X", (unsigned char) add[i + 6]);
 	printk(" =>");
@@ -862,6 +1101,73 @@ static void print_eth(char *add)
 	printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
 }
 
+static int tc35815_tx_full(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	int do_phy_reset = 1;
+	del_timer(&lp->timer);		/* Kill if running	*/
+
+	if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
+		/* Resetting PHY cause problem on some chip... (SEEQ 80221) */
+		do_phy_reset = 0;
+	}
+	if (do_phy_reset) {
+		int timeout;
+		tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
+		timeout = 100;
+		while (--timeout) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
+				break;
+			udelay(1);
+		}
+		if (!timeout)
+			printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+	}
+
+	tc35815_chip_reset(dev);
+	tc35815_clear_queues(dev);
+	tc35815_chip_init(dev);
+	/* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+	tc35815_set_multicast_list(dev);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+
+	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+	       dev->name, tc_readl(&tr->Tx_Stat));
+
+	/* Try to restart the adaptor. */
+	spin_lock_irq(&lp->lock);
+	tc35815_restart(dev);
+	spin_unlock_irq(&lp->lock);
+
+	lp->stats.tx_errors++;
+
+	/* If we have space available to accept new transmit
+	 * requests, wake up the queueing layer.  This would
+	 * be the case if the chipset_init() call above just
+	 * flushes out the tx queue and empties it.
+	 *
+	 * If instead, the tx queue is retained then the
+	 * netif_wake_queue() call should be placed in the
+	 * TX completion interrupt handler of the driver instead
+	 * of here.
+	 */
+	if (!tc35815_tx_full(dev))
+		netif_wake_queue(dev);
+}
+
 /*
  * Open/initialize the board. This is called (in the current kernel)
  * sometime after booting when the 'ifconfig' program is run.
@@ -874,16 +1180,16 @@ static int
 tc35815_open(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
+
 	/*
 	 * This is used if the interrupt line can turned off (shared).
 	 * See 3c503.c for an example of selecting the IRQ at config-time.
 	 */
-
-	if (dev->irq == 0  ||
-	    request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
+	if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
 		return -EAGAIN;
 	}
 
+	del_timer(&lp->timer);		/* Kill if running	*/
 	tc35815_chip_reset(dev);
 
 	if (tc35815_init_queues(dev) != 0) {
@@ -892,138 +1198,119 @@ tc35815_open(struct net_device *dev)
 	}
 
 	/* Reset the hardware here. Don't forget to set the station address. */
+	spin_lock_irq(&lp->lock);
 	tc35815_chip_init(dev);
+	spin_unlock_irq(&lp->lock);
 
-	lp->tbusy = 0;
+	/* We are now ready to accept transmit requeusts from
+	 * the queueing layer of the networking.
+	 */
 	netif_start_queue(dev);
 
 	return 0;
 }
 
-static void tc35815_tx_timeout(struct net_device *dev)
-{
-	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-	       dev->name, tc_readl(&tr->Tx_Stat));
-	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
-	lp->tbusy=0;
-	spin_unlock_irqrestore(&lp->lock, flags);
-	dev->trans_start = jiffies;
-	netif_wake_queue(dev);
-}
-
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
 static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-
-	if (netif_queue_stopped(dev)) {
-		/*
-		 * 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;
-		printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
-		       dev->name, tc_readl(&tr->Tx_Stat));
-		/* Try to restart the adaptor. */
-		tc35815_chip_reset(dev);
-		tc35815_clear_queues(dev);
-		tc35815_chip_init(dev);
-		lp->tbusy=0;
-		dev->trans_start = jiffies;
-		netif_wake_queue(dev);
-	}
+	struct TxFD *txfd;
+	unsigned long flags;
 
-	/*
-	 * Block a timer-based transmit from overlapping. This could better be
-	 * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+	/* If some error occurs while trying to transmit this
+	 * packet, you should return '1' from this function.
+	 * In such a case you _may not_ do anything to the
+	 * SKB, it is still owned by the network queueing
+	 * layer when an error is returned.  This means you
+	 * may not modify any SKB fields, you may not free
+	 * the SKB, etc.
 	 */
-	if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
-		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
-		dev_kfree_skb_any(skb);
-	} else {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-		unsigned char *buf = skb->data;
-		struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
-		unsigned long flags;
-		lp->stats.tx_bytes += skb->len;
 
+	/* This is the most common case for modern hardware.
+	 * The spinlock protects this code from the TX complete
+	 * hardware interrupt handler.  Queue flow control is
+	 * thus managed under this lock as well.
+	 */
+	spin_lock_irqsave(&lp->lock, flags);
 
-#ifdef __mips__
-		dma_cache_wback_inv((unsigned long)buf, length);
+	/* failsafe... (handle txdone now if half of FDs are used) */
+	if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+	    TX_FD_NUM / 2)
+		tc35815_txdone(dev);
+
+	if (netif_msg_pktdata(lp))
+		print_eth(skb->data);
+#ifdef DEBUG
+	if (lp->tx_skbs[lp->tfd_start].skb) {
+		printk("%s: tx_skbs conflict.\n", dev->name);
+		panic_queues(dev);
+	}
+#else
+	BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
 #endif
-
-		spin_lock_irqsave(&lp->lock, flags);
-
-		/* failsafe... */
-		if (lp->tfd_start != lp->tfd_end)
-			tc35815_txdone(dev);
-
-
-		txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
-
-		txfd->bd.BDCtl = cpu_to_le32(length);
-		txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
-		txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
-		if (lp->tfd_start == lp->tfd_end) {
-			/* Start DMA Transmitter. */
-			txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+	lp->tx_skbs[lp->tfd_start].skb = skb;
+	lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+	/*add to ring */
+	txfd = &lp->tfd_base[lp->tfd_start];
+	txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+	txfd->bd.BDCtl = cpu_to_le32(skb->len);
+	txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+	txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+	if (lp->tfd_start == lp->tfd_end) {
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
+		/* Start DMA Transmitter. */
+		txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
 #ifdef GATHER_TXINT
-			txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+		txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-			if (tc35815_debug > 2) {
-				printk("%s: starting TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
-			tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
-		} else {
-			txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
-			if (tc35815_debug > 2) {
-				printk("%s: queueing TxFD.\n", dev->name);
-				dump_txfd(txfd);
-				if (tc35815_debug > 3)
-					print_eth(buf);
-			}
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: starting TxFD.\n", dev->name);
+			dump_txfd(txfd);
 		}
-		lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+		tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+	} else {
+		txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+		if (netif_msg_tx_queued(lp)) {
+			printk("%s: queueing TxFD.\n", dev->name);
+			dump_txfd(txfd);
+		}
+	}
+	lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
 
-		dev->trans_start = jiffies;
+	dev->trans_start = jiffies;
 
-		if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
-			/* we can send another packet */
-			lp->tbusy = 0;
-			netif_start_queue(dev);
-		} else {
-			netif_stop_queue(dev);
-			if (tc35815_debug > 1)
-				printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
-		}
-		spin_unlock_irqrestore(&lp->lock, flags);
+	/* If we just used up the very last entry in the
+	 * TX ring on this device, tell the queueing
+	 * layer to send no more.
+	 */
+	if (tc35815_tx_full(dev)) {
+		if (netif_msg_tx_queued(lp))
+			printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+		netif_stop_queue(dev);
 	}
 
+	/* When the TX completion hw interrupt arrives, this
+	 * is when the transmit statistics are updated.
+	 */
+
+	spin_unlock_irqrestore(&lp->lock, flags);
 	return 0;
 }
 
 #define FATAL_ERROR_INT \
 	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
 {
 	static int count;
 	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
 	       dev->name, status);
-
 	if (status & Int_IntPCI)
 		printk(" IntPCI");
 	if (status & Int_DmParErr)
@@ -1033,110 +1320,170 @@ static void tc35815_fatal_error_interrup
 	printk("\n");
 	if (count++ > 100)
 		panic("%s: Too many fatal errors.", dev->name);
-	printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+	printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
 	/* Try to restart the adaptor. */
-	tc35815_chip_reset(dev);
-	tc35815_clear_queues(dev);
-	tc35815_chip_init(dev);
+	tc35815_restart(dev);
+}
+
+#ifdef TC35815_NAPI
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+#else
+static int tc35815_do_interrupt(struct net_device *dev, u32 status)
+#endif
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int ret = -1;
+
+	/* Fatal errors... */
+	if (status & FATAL_ERROR_INT) {
+		tc35815_fatal_error_interrupt(dev, status);
+		return 0;
+	}
+	/* recoverable errors */
+	if (status & Int_IntFDAEx) {
+		/* disable FDAEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Free Descriptor Area Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		ret = 0;
+	}
+	if (status & Int_IntBLEx) {
+		/* disable BLEx int. (until we make rooms...) */
+		tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+		printk(KERN_WARNING
+		       "%s: Buffer List Exhausted (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_dropped++;
+		ret = 0;
+	}
+	if (status & Int_IntExBD) {
+		printk(KERN_WARNING
+		       "%s: Excessive Buffer Descriptiors (%#x).\n",
+		       dev->name, status);
+		lp->stats.rx_length_errors++;
+		ret = 0;
+	}
+
+	/* normal notification */
+	if (status & Int_IntMacRx) {
+		/* Got a packet(s). */
+#ifdef TC35815_NAPI
+		ret = tc35815_rx(dev, limit);
+#else
+		tc35815_rx(dev);
+		ret = 0;
+#endif
+		lp->lstats.rx_ints++;
+	}
+	if (status & Int_IntMacTx) {
+		/* Transmit complete. */
+		lp->lstats.tx_ints++;
+		tc35815_txdone(dev);
+		netif_wake_queue(dev);
+		ret = 0;
+	}
+	return ret;
 }
 
 /*
  * The typical workload of the driver:
- *   Handle the network interface interrupts.
+ * Handle the network interface interrupts.
  */
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
-	struct tc35815_regs *tr;
-	struct tc35815_local *lp;
-	int status, boguscount = 0;
-	int handled = 0;
-
-	if (dev == NULL) {
-		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
-		return IRQ_NONE;
-	}
-
-	tr = (struct tc35815_regs*)dev->base_addr;
-	lp = dev->priv;
-
-	do {
-		status = tc_readl(&tr->Int_Src);
-		if (status == 0)
-			break;
-		handled = 1;
-		tc_writel(status, &tr->Int_Src);	/* write to clear */
-
-		/* Fatal errors... */
-		if (status & FATAL_ERROR_INT) {
-			tc35815_fatal_error_interrupt(dev, status);
-			break;
-		}
-		/* recoverable errors */
-		if (status & Int_IntFDAEx) {
-			/* disable FDAEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Free Descriptor Area Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntBLEx) {
-			/* disable BLEx int. (until we make rooms...) */
-			tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
-			printk(KERN_WARNING
-			       "%s: Buffer List Exhausted (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_dropped++;
-		}
-		if (status & Int_IntExBD) {
-			printk(KERN_WARNING
-			       "%s: Excessive Buffer Descriptiors (%#x).\n",
-			       dev->name, status);
-			lp->stats.rx_length_errors++;
-		}
-		/* normal notification */
-		if (status & Int_IntMacRx) {
-			/* Got a packet(s). */
-			lp->lstats.rx_ints++;
-			tc35815_rx(dev);
-		}
-		if (status & Int_IntMacTx) {
-			lp->lstats.tx_ints++;
-			tc35815_txdone(dev);
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+#ifdef TC35815_NAPI
+	u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+	if (!(dmactl & DMA_IntMask)) {
+		/* disable interrupts */
+		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+		if (netif_rx_schedule_prep(dev))
+			__netif_rx_schedule(dev);
+		else {
+			printk(KERN_ERR "%s: interrupt taken in poll\n",
+			       dev->name);
+			BUG();
 		}
-	} while (++boguscount < 20) ;
+		(void)tc_readl(&tr->Int_Src);	/* flush */
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+#else
+	struct tc35815_local *lp = dev->priv;
+	int handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	tc_writel(status, &tr->Int_Src);	/* write to clear */
+	handled = tc35815_do_interrupt(dev, status);
+	(void)tc_readl(&tr->Int_Src);	/* flush */
+	spin_unlock(&lp->lock);
+	return IRQ_RETVAL(handled >= 0);
+#endif /* TC35815_NAPI */
+}
 
-	return IRQ_RETVAL(handled);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	tc35815_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
 }
+#endif
 
 /* We have a good packet(s), get it/them out of the buffers. */
+#ifdef TC35815_NAPI
+static int
+tc35815_rx(struct net_device *dev, int limit)
+#else
 static void
 tc35815_rx(struct net_device *dev)
+#endif
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
 	unsigned int fdctl;
 	int i;
 	int buf_free_count = 0;
 	int fd_free_count = 0;
+#ifdef TC35815_NAPI
+	int received = 0;
+#endif
 
 	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
 		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
 		int pkt_len = fdctl & FD_FDLength_MASK;
-		struct RxFD *next_rfd;
 		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+		struct RxFD *next_rfd;
+#endif
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+		pkt_len -= 4;
+#endif
 
-		if (tc35815_debug > 2)
+		if (netif_msg_rx_status(lp))
 			dump_rxfd(lp->rfd_cur);
 		if (status & Rx_Good) {
-			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 			unsigned char *data;
-			int cur_bd, offset;
-
-			lp->stats.rx_bytes += pkt_len;
+			int cur_bd;
+#ifdef TC35815_USE_PACKEDBUFFER
+			int offset;
+#endif
 
+#ifdef TC35815_NAPI
+			if (--limit < 0)
+				break;
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+			BUG_ON(bd_count > 2);
 			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1145,7 +1492,6 @@ tc35815_rx(struct net_device *dev)
 				break;
 			}
 			skb_reserve(skb, 2);   /* 16 bit alignment */
-			skb->dev = dev;
 
 			data = skb_put(skb, pkt_len);
 
@@ -1155,25 +1501,69 @@ tc35815_rx(struct net_device *dev)
 			while (offset < pkt_len && cur_bd < bd_count) {
 				int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
 					BD_BuffLength_MASK;
-				void *rxbuf =
-					bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
-#ifdef __mips__
-				dma_cache_inv((unsigned long)rxbuf, len);
+				dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
+				void *rxbuf = rxbuf_bus_to_virt(lp, dma);
+				if (offset + len > pkt_len)
+					len = pkt_len - offset;
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+				pci_dma_sync_single_for_cpu(lp->pci_dev,
+							    dma, len,
+							    PCI_DMA_FROMDEVICE);
 #endif
 				memcpy(data + offset, rxbuf, len);
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+				pci_dma_sync_single_for_device(lp->pci_dev,
+							       dma, len,
+							       PCI_DMA_FROMDEVICE);
+#endif
 				offset += len;
 				cur_bd++;
 			}
-#if 0
-			print_buf(data,pkt_len);
+#else /* TC35815_USE_PACKEDBUFFER */
+			BUG_ON(bd_count > 1);
+			cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+				  & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+			if (cur_bd >= RX_BUF_NUM) {
+				printk("%s: invalid BDID.\n", dev->name);
+				panic_queues(dev);
+			}
+			BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+			       (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+			if (!lp->rx_skbs[cur_bd].skb) {
+				printk("%s: NULL skb.\n", dev->name);
+				panic_queues(dev);
+			}
+#else
+			BUG_ON(cur_bd >= RX_BUF_NUM);
 #endif
-			if (tc35815_debug > 3)
+			skb = lp->rx_skbs[cur_bd].skb;
+			prefetch(skb->data);
+			lp->rx_skbs[cur_bd].skb = NULL;
+			lp->fbl_count--;
+			pci_unmap_single(lp->pci_dev,
+					 lp->rx_skbs[cur_bd].skb_dma,
+					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			if (!HAVE_DMA_RXALIGN(lp))
+				memmove(skb->data, skb->data - 2, pkt_len);
+			data = skb_put(skb, pkt_len);
+#endif /* TC35815_USE_PACKEDBUFFER */
+			if (netif_msg_pktdata(lp))
 				print_eth(data);
 			skb->protocol = eth_type_trans(skb, dev);
+#ifdef TC35815_NAPI
+			netif_receive_skb(skb);
+			received++;
+#else
 			netif_rx(skb);
+#endif
+			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
 		} else {
 			lp->stats.rx_errors++;
+			printk(KERN_DEBUG "%s: Rx error (status %x)\n",
+			       dev->name, status & Rx_Stat_Mask);
 			/* WORKAROUND: LongErr and CRCErr means Overflow. */
 			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
 				status &= ~(Rx_LongErr|Rx_CRCErr);
@@ -1190,63 +1580,150 @@ #endif
 			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
 			unsigned char id =
 				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
-			if (id >= RX_BUF_PAGES) {
+#ifdef DEBUG
+			if (id >= RX_BUF_NUM) {
 				printk("%s: invalid BDID.\n", dev->name);
 				panic_queues(dev);
 			}
+#else
+			BUG_ON(id >= RX_BUF_NUM);
+#endif
 			/* free old buffers */
-			while (lp->fbl_curid != id) {
-				bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+#ifdef TC35815_USE_PACKEDBUFFER
+			while (lp->fbl_curid != id)
+#else
+			while (lp->fbl_count < RX_BUF_NUM)
+#endif
+			{
+#ifdef TC35815_USE_PACKEDBUFFER
+				unsigned char curid = lp->fbl_curid;
+#else
+				unsigned char curid =
+					(id + 1 + lp->fbl_count) % RX_BUF_NUM;
+#endif
+				struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+				bdctl = le32_to_cpu(bd->BDCtl);
 				if (bdctl & BD_CownsBD) {
 					printk("%s: Freeing invalid BD.\n",
 					       dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* pass BD to controler */
+#ifndef TC35815_USE_PACKEDBUFFER
+				if (!lp->rx_skbs[curid].skb) {
+					lp->rx_skbs[curid].skb =
+						alloc_rxbuf_skb(dev,
+								lp->pci_dev,
+								&lp->rx_skbs[curid].skb_dma);
+					if (!lp->rx_skbs[curid].skb)
+						break; /* try on next reception */
+					bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+				}
+#endif /* TC35815_USE_PACKEDBUFFER */
 				/* Note: BDLength was modified by chip. */
-				lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
-					cpu_to_le32(BD_CownsBD |
-						    (lp->fbl_curid << BD_RxBDID_SHIFT) |
-						    PAGE_SIZE);
-				lp->fbl_curid =
-					(lp->fbl_curid + 1) % RX_BUF_PAGES;
-				if (tc35815_debug > 2) {
+				bd->BDCtl = cpu_to_le32(BD_CownsBD |
+							(curid << BD_RxBDID_SHIFT) |
+							RX_BUF_SIZE);
+#ifdef TC35815_USE_PACKEDBUFFER
+				lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
+				if (netif_msg_rx_status(lp)) {
 					printk("%s: Entering new FBD %d\n",
 					       dev->name, lp->fbl_curid);
 					dump_frfd(lp->fbl_ptr);
 				}
+#else
+				lp->fbl_count++;
+#endif
 				buf_free_count++;
 			}
 		}
 
 		/* put RxFD back to controller */
-		next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
-#ifdef __mips__
-		next_rfd = (struct RxFD *)vtonocache(next_rfd);
-#endif
+#ifdef DEBUG
+		next_rfd = fd_bus_to_virt(lp,
+					  le32_to_cpu(lp->rfd_cur->fd.FDNext));
 		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
 			printk("%s: RxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
 			/* pass FD to controler */
-			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);	/* for debug */
+#ifdef DEBUG
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
 			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
 			lp->rfd_cur++;
 			fd_free_count++;
 		}
-
-		lp->rfd_cur = next_rfd;
+		if (lp->rfd_cur > lp->rfd_limit)
+			lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+		if (lp->rfd_cur != next_rfd)
+			printk("rfd_cur = %p, next_rfd %p\n",
+			       lp->rfd_cur, next_rfd);
+#endif
 	}
 
 	/* re-enable BL/FDA Exhaust interrupts. */
 	if (fd_free_count) {
-		tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+		struct tc35815_regs __iomem *tr =
+			(struct tc35815_regs __iomem *)dev->base_addr;
+		u32 en, en_old = tc_readl(&tr->Int_En);
+		en = en_old | Int_FDAExEn;
 		if (buf_free_count)
-			tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+			en |= Int_BLExEn;
+		if (en != en_old)
+			tc_writel(en, &tr->Int_En);
 	}
+#ifdef TC35815_NAPI
+	return received;
+#endif
 }
 
+#ifdef TC35815_NAPI
+static int
+tc35815_poll(struct net_device *dev, int *budget)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int limit = min(*budget, dev->quota);
+	int received = 0, handled;
+	u32 status;
+
+	spin_lock(&lp->lock);
+	status = tc_readl(&tr->Int_Src);
+	do {
+		tc_writel(status, &tr->Int_Src);	/* write to clear */
+
+		handled = tc35815_do_interrupt(dev, status, limit);
+		if (handled >= 0) {
+			received += handled;
+			limit -= handled;
+			if (limit <= 0)
+				break;
+		}
+		status = tc_readl(&tr->Int_Src);
+	} while (status);
+	spin_unlock(&lp->lock);
+
+	dev->quota -= received;
+	*budget -= received;
+	if (limit <= 0)
+		return 1;
+
+	netif_rx_complete(dev);
+	/* enable interrupts */
+	tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+	return 0;
+}
+#endif
+
 #ifdef NO_CHECK_CARRIER
 #define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
 #else
@@ -1265,9 +1742,17 @@ tc35815_check_tx_stat(struct net_device 
 	if (status & Tx_TxColl_MASK)
 		lp->stats.collisions += status & Tx_TxColl_MASK;
 
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have NCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		status &= ~Tx_NCarr;
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck)
+	    || lp->fullduplex)
 		status &= ~Tx_NCarr;
+#endif
+#endif
 
 	if (!(status & TX_STA_ERR)) {
 		/* no error. */
@@ -1283,6 +1768,15 @@ tc35815_check_tx_stat(struct net_device 
 	if (status & Tx_Under) {
 		lp->stats.tx_fifo_errors++;
 		msg = "Tx FIFO Underrun.";
+		if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+			lp->lstats.tx_underrun++;
+			if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
+				tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+				msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+			}
+		}
 	}
 	if (status & Tx_Defer) {
 		lp->stats.tx_fifo_errors++;
@@ -1306,18 +1800,19 @@ #endif
 		lp->stats.tx_heartbeat_errors++;
 		msg = "Signal Quality Error.";
 	}
-	if (msg)
+	if (msg && netif_msg_tx_err(lp))
 		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
 }
 
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
 static void
 tc35815_txdone(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
 	struct TxFD *txfd;
 	unsigned int fdctl;
-	int num_done = 0;
 
 	txfd = &lp->tfd_base[lp->tfd_end];
 	while (lp->tfd_start != lp->tfd_end &&
@@ -1325,38 +1820,61 @@ tc35815_txdone(struct net_device *dev)
 		int status = le32_to_cpu(txfd->fd.FDStat);
 		struct sk_buff *skb;
 		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+		u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
 
-		if (tc35815_debug > 2) {
+		if (netif_msg_tx_done(lp)) {
 			printk("%s: complete TxFD.\n", dev->name);
 			dump_txfd(txfd);
 		}
 		tc35815_check_tx_stat(dev, status);
 
-		skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+		skb = fdsystem != 0xffffffff ?
+			lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+		if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+			printk("%s: tx_skbs mismatch.\n", dev->name);
+			panic_queues(dev);
+		}
+#else
+		BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
 		if (skb) {
+			lp->stats.tx_bytes += skb->len;
+			pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+			lp->tx_skbs[lp->tfd_end].skb = NULL;
+			lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+#ifdef TC35815_NAPI
 			dev_kfree_skb_any(skb);
+#else
+			dev_kfree_skb_irq(skb);
+#endif
 		}
-		txfd->fd.FDSystem = cpu_to_le32(0);
+		txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
 
-		num_done++;
 		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
 		txfd = &lp->tfd_base[lp->tfd_end];
-		if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+#ifdef DEBUG
+		if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
 			printk("%s: TxFD FDNext invalid.\n", dev->name);
 			panic_queues(dev);
 		}
+#endif
 		if (fdnext & FD_Next_EOL) {
 			/* DMA Transmitter has been stopping... */
 			if (lp->tfd_end != lp->tfd_start) {
+				struct tc35815_regs __iomem *tr =
+					(struct tc35815_regs __iomem *)dev->base_addr;
 				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
 				struct TxFD* txhead = &lp->tfd_base[head];
 				int qlen = (lp->tfd_start + TX_FD_NUM
 					    - lp->tfd_end) % TX_FD_NUM;
 
+#ifdef DEBUG
 				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
 					printk("%s: TxFD FDCtl invalid.\n", dev->name);
 					panic_queues(dev);
 				}
+#endif
 				/* log max queue length */
 				if (lp->lstats.max_tx_qlen < qlen)
 					lp->lstats.max_tx_qlen = qlen;
@@ -1367,21 +1885,23 @@ tc35815_txdone(struct net_device *dev)
 #ifdef GATHER_TXINT
 				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
 #endif
-				if (tc35815_debug > 2) {
+				if (netif_msg_tx_queued(lp)) {
 					printk("%s: start TxFD on queue.\n",
 					       dev->name);
 					dump_txfd(txfd);
 				}
-				tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+				tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
 			}
 			break;
 		}
 	}
 
-	if (num_done > 0 && lp->tbusy) {
-		lp->tbusy = 0;
-		netif_start_queue(dev);
-	}
+	/* If we had stopped the queue due to a "tx full"
+	 * condition, and space has now been made available,
+	 * wake up the queue.
+	 */
+	if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
+		netif_wake_queue(dev);
 }
 
 /* The inverse routine to tc35815_open(). */
@@ -1389,18 +1909,18 @@ static int
 tc35815_close(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-
-	lp->tbusy = 1;
 	netif_stop_queue(dev);
 
 	/* Flush the Tx and disable Rx here. */
 
+	del_timer(&lp->timer);		/* Kill if running	*/
 	tc35815_chip_reset(dev);
 	free_irq(dev->irq, dev);
 
 	tc35815_free_queues(dev);
 
 	return 0;
+
 }
 
 /*
@@ -1410,29 +1930,29 @@ tc35815_close(struct net_device *dev)
 static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
-
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	if (netif_running(dev)) {
-		spin_lock_irqsave(&lp->lock, flags);
 		/* Update the statistics from the device registers. */
 		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
-		spin_unlock_irqrestore(&lp->lock, flags);
 	}
 
 	return &lp->stats;
 }
 
-static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
 {
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	int cam_index = index * 6;
-	unsigned long cam_data;
-	unsigned long saved_addr;
+	u32 cam_data;
+	u32 saved_addr;
 	saved_addr = tc_readl(&tr->CAM_Adr);
 
-	if (tc35815_debug > 1) {
+	if (netif_msg_hw(lp)) {
 		int i;
-		printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+		printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
 		for (i = 0; i < 6; i++)
 			printk(" %02x", addr[i]);
 		printk("\n");
@@ -1459,14 +1979,6 @@ static void tc35815_set_cam_entry(struct
 		tc_writel(cam_data, &tr->CAM_Data);
 	}
 
-	if (tc35815_debug > 2) {
-		int i;
-		for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
-			tc_writel(i * 4, &tr->CAM_Adr);
-			printk("CAM 0x%x: %08lx",
-			       i * 4, tc_readl(&tr->CAM_Data));
-		}
-	}
 	tc_writel(saved_addr, &tr->CAM_Adr);
 }
 
@@ -1481,10 +1993,19 @@ static void tc35815_set_cam_entry(struct
 static void
 tc35815_set_multicast_list(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 
 	if (dev->flags&IFF_PROMISC)
 	{
+#ifdef WORKAROUND_100HALF_PROMISC
+		/* With some (all?) 100MHalf HUB, controller will hang
+		 * if we enabled promiscuous mode before linkup... */
+		struct tc35815_local *lp = dev->priv;
+		int pid = lp->phy_addr;
+		if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
+			return;
+#endif
 		/* Enable promiscuous mode */
 		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
 	}
@@ -1506,7 +2027,7 @@ tc35815_set_multicast_list(struct net_de
 			if (!cur_addr)
 				break;
 			/* entry 0,1 is reserved. */
-			tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+			tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
 			ena_bits |= CAM_Ena_Bit(i + 2);
 		}
 		tc_writel(ena_bits, &tr->CAM_Ena);
@@ -1518,122 +2039,753 @@ tc35815_set_multicast_list(struct net_de
 	}
 }
 
-static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg)
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long data;
-	unsigned long flags;
+	strcpy(info->driver, MODNAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
 
-	spin_lock_irqsave(&lp->lock, flags);
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	spin_lock_irq(&lp->lock);
+	mii_ethtool_gset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+	return 0;
+}
 
-	tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+#if 1	/* use our negotiation method... */
+	/* Verify the settings we care about. */
+	if (cmd->autoneg != AUTONEG_ENABLE &&
+	    cmd->autoneg != AUTONEG_DISABLE)
+		return -EINVAL;
+	if (cmd->autoneg == AUTONEG_DISABLE &&
+	    ((cmd->speed != SPEED_100 &&
+	      cmd->speed != SPEED_10) ||
+	     (cmd->duplex != DUPLEX_HALF &&
+	      cmd->duplex != DUPLEX_FULL)))
+		return -EINVAL;
+
+	/* Ok, do it to it. */
+	spin_lock_irq(&lp->lock);
+	del_timer(&lp->timer);
+	tc35815_start_auto_negotiation(dev, cmd);
+	spin_unlock_irq(&lp->lock);
+	rc = 0;
+#else
+	spin_lock_irq(&lp->lock);
+	rc = mii_ethtool_sset(&lp->mii, cmd);
+	spin_unlock_irq(&lp->lock);
+#endif
+	return rc;
+}
+
+static int tc35815_nway_reset(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_nway_restart(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
+
+static u32 tc35815_get_link(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+	spin_lock_irq(&lp->lock);
+	rc = mii_link_ok(&lp->mii);
+	spin_unlock_irq(&lp->lock);
+	return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+	struct tc35815_local *lp = dev->priv;
+	lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	return sizeof(lp->lstats) / sizeof(int);
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+	struct tc35815_local *lp = dev->priv;
+	data[0] = lp->lstats.max_tx_qlen;
+	data[1] = lp->lstats.tx_ints;
+	data[2] = lp->lstats.rx_ints;
+	data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+	const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "max_tx_qlen" },
+	{ "tx_ints" },
+	{ "rx_ints" },
+	{ "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+	.get_drvinfo		= tc35815_get_drvinfo,
+	.get_settings		= tc35815_get_settings,
+	.set_settings		= tc35815_set_settings,
+	.nway_reset		= tc35815_nway_reset,
+	.get_link		= tc35815_get_link,
+	.get_msglevel		= tc35815_get_msglevel,
+	.set_msglevel		= tc35815_set_msglevel,
+	.get_strings		= tc35815_get_strings,
+	.get_stats_count	= tc35815_get_stats_count,
+	.get_ethtool_stats	= tc35815_get_ethtool_stats,
+	.get_perm_addr		= ethtool_op_get_perm_addr,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct tc35815_local *lp = dev->priv;
+	int rc;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	spin_lock_irq(&lp->lock);
+	rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+	spin_unlock_irq(&lp->lock);
+
+	return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	u32 data;
+	tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
 	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
 		;
 	data = tc_readl(&tr->MD_Data);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return data;
+	return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+			  int val)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	tc_writel(val, &tr->MD_Data);
+	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+		;
 }
 
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation.  The scheme is very simple.  We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for.  The priority for link configurations, highest first
+ * is:
+ *                 100 Base-T Full Duplex
+ *                 100 Base-T Half Duplex
+ *                 10 Base-T Full Duplex
+ *                 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	unsigned long flags;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
 
-	spin_lock_irqsave(&lp->lock, flags);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
 
-	tc_writel(d, &tr->MD_Data);
-	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
-	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
-		;
-	spin_unlock_irqrestore(&lp->lock, flags);
+	/* Downgrade from full to half duplex.  Only possible via ethtool.  */
+	if (bmcr & BMCR_FULLDPLX) {
+		bmcr &= ~BMCR_FULLDPLX;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* Downgrade from 100 to 10. */
+	if (bmcr & BMCR_SPEED100) {
+		bmcr &= ~BMCR_SPEED100;
+		printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		return 0;
+	}
+
+	/* We've tried everything. */
+	return -1;
 }
 
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	static int first = 1;
-	unsigned short ctl;
-
-	if (first) {
-		unsigned short id0, id1;
-		int count;
-		first = 0;
-
-		/* first data written to the PHY will be an ID number */
-		tc_phy_write(dev, 0, tr, 0, MII_CONTROL);	/* ID:0 */
-#if 0
-		tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
-		printk(KERN_INFO "%s: Resetting PHY...", dev->name);
-		while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
-			;
-		printk("\n");
-		tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
-			     MII_CONTROL);
-#endif
-		id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
-		id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
-		printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
-		       id0, id1);
-		if (lp->option & TC35815_OPT_10M) {
-			lp->linkspeed = 10;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
-		} else if (lp->option & TC35815_OPT_100M) {
-			lp->linkspeed = 100;
-			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+	int pid = lp->phy_addr;
+	unsigned short lpa, bmcr;
+	char *speed = "", *duplex = "";
+
+	lpa = tc_mdio_read(dev, pid, MII_LPA);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+		duplex = "Full Duplex";
+	else
+		duplex = "Half Duplex";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+		       dev->name, speed, duplex);
+	printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+	       dev->name,
+	       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	char *speed = "", *duplex = "";
+
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_SPEED100)
+		speed = "100Mb/s";
+	else
+		speed = "10Mb/s";
+	if (bmcr & BMCR_FULLDPLX)
+		duplex = "Full Duplex.\n";
+	else
+		duplex = "Half Duplex.\n";
+
+	if (netif_msg_link(lp))
+		printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+		       dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int pid = lp->phy_addr;
+	unsigned short bmcr, lpa;
+	int speed;
+
+	if (lp->timer_state == arbwait) {
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+		       dev->name,
+		       bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+		if (!(lpa & (LPA_10HALF | LPA_10FULL |
+			     LPA_100HALF | LPA_100FULL))) {
+			/* fall back to 10HALF */
+			printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+			       dev->name, lpa);
+			lpa = LPA_10HALF;
+		}
+		if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+		if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+			speed = 100;
+		else
+			speed = 10;
+	} else {
+		/* Forcing a link mode. */
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (bmcr & BMCR_FULLDPLX)
+			lp->fullduplex = 1;
+		else
+			lp->fullduplex = 0;
+		if (bmcr & BMCR_SPEED100)
+			speed = 100;
+		else
+			speed = 10;
+	}
+
+	tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+	if (lp->fullduplex) {
+		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+	} else {
+		tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+	}
+	tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+	/* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+		/* WORKAROUND: enable LostCrS only if half duplex operation */
+		if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+			tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+	}
+#endif
+	lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, lpa;
+	int restart_timer = 0;
+
+	spin_lock_irq(&lp->lock);
+
+	lp->timer_ticks++;
+	switch (lp->timer_state) {
+	case arbwait:
+		/*
+		 * Only allow for 5 ticks, thats 10 seconds and much too
+		 * long to wait for arbitration to complete.
+		 */
+		/* TC35815 need more times... */
+		if (lp->timer_ticks >= 10) {
+			/* Enter force mode. */
+			if (!options.doforce) {
+				printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+				       " cable probblem?\n", dev->name);
+				/* Try to restart the adaptor. */
+				tc35815_restart(dev);
+				goto out;
+			}
+			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+			       " trying force link mode\n", dev->name);
+			printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+			       tc_mdio_read(dev, pid, MII_BMCR),
+			       tc_mdio_read(dev, pid, MII_BMSR));
+			bmcr = BMCR_SPEED100;
+			tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+			/*
+			 * OK, seems we need do disable the transceiver
+			 * for the first tick to make sure we get an
+			 * accurate link state at the second tick.
+			 */
+
+			lp->timer_state = ltrywait;
+			lp->timer_ticks = 0;
+			restart_timer = 1;
 		} else {
-			/* auto negotiation */
-			unsigned long neg_result;
-			tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
-			printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
-			count = 0;
-			while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
-				if (count++ > 5000) {
-					printk(" failed. Assume 10Mbps\n");
-					lp->linkspeed = 10;
-					lp->fullduplex = 0;
-					goto done;
+			/* Anything interesting happen? */
+			bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+			if (bmsr & BMSR_ANEGCOMPLETE) {
+				/* Just what we've been waiting for... */
+				tc35815_set_link_modes(dev);
+
+				/*
+				 * Success, at least so far, advance our state
+				 * engine.
+				 */
+				lp->timer_state = lupwait;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lupwait:
+		/*
+		 * Auto negotiation was successful and we are awaiting a
+		 * link up status.  I have decided to let this timer run
+		 * forever until some sort of error is signalled, reporting
+		 * a message to the user at 10 second intervals.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		if (bmsr & BMSR_LSTATUS) {
+			/*
+			 * Wheee, it's up, display the link mode in use and put
+			 * the timer to sleep.
+			 */
+			tc35815_display_link_mode(dev);
+			netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
+#endif
+		} else {
+			if (lp->timer_ticks >= 10) {
+				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+				       "not completely up.\n", dev->name);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case ltrywait:
+		/*
+		 * Making the timeout here too long can make it take
+		 * annoyingly long to attempt all of the link mode
+		 * permutations, but then again this is essentially
+		 * error recovery code for the most part.
+		 */
+		bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		if (lp->timer_ticks == 1) {
+			/*
+			 * Re-enable transceiver, we'll re-enable the
+			 * transceiver next tick, then check link state
+			 * on the following tick.
+			 */
+			restart_timer = 1;
+			break;
+		}
+		if (lp->timer_ticks == 2) {
+			restart_timer = 1;
+			break;
+		}
+		if (bmsr & BMSR_LSTATUS) {
+			/* Force mode selection success. */
+			tc35815_display_forced_link_mode(dev);
+			netif_carrier_on(dev);
+			tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+			/* delayed promiscuous enabling */
+			if (dev->flags & IFF_PROMISC)
+				tc35815_set_multicast_list(dev);
+#endif
+#if 1
+			lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+			lp->timer_state = lcheck;
+			restart_timer = 1;
+#else
+			lp->timer_state = asleep;
+			restart_timer = 0;
+#endif
+		} else {
+			if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+				int ret;
+
+				ret = tc35815_try_next_permutation(dev);
+				if (ret == -1) {
+					/*
+					 * Aieee, tried them all, reset the
+					 * chip and try all over again.
+					 */
+					printk(KERN_NOTICE "%s: Link down, "
+					       "cable problem?\n",
+					       dev->name);
+
+					/* Try to restart the adaptor. */
+					tc35815_restart(dev);
+					goto out;
 				}
-				if (count % 512 == 0)
-					printk(".");
-				mdelay(1);
+				lp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lcheck:
+		bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+		lpa = tc_mdio_read(dev, pid, MII_LPA);
+		if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+			printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+			       bmcr);
+		} else if ((lp->saved_lpa ^ lpa) &
+			   (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+			printk(KERN_NOTICE "%s: link status changed"
+			       " (BMCR %x LPA %x->%x)\n", dev->name,
+			       bmcr, lp->saved_lpa, lpa);
+		} else {
+			/* go on */
+			restart_timer = 1;
+			break;
+		}
+		/* Try to restart the adaptor. */
+		tc35815_restart(dev);
+		goto out;
+
+	case asleep:
+	default:
+		/* Can't happens.... */
+		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+		       "one anyways!\n", dev->name);
+		restart_timer = 0;
+		lp->timer_ticks = 0;
+		lp->timer_state = asleep; /* foo on you */
+		break;
+	}
+
+	if (restart_timer) {
+		lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+		add_timer(&lp->timer);
+	}
+out:
+	spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+					   struct ethtool_cmd *ep)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmsr, bmcr, advertize;
+	int timeout;
+
+	netif_carrier_off(dev);
+	bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+		if (options.speed || options.duplex) {
+			/* Advertise only specified configuration. */
+			advertize &= ~(ADVERTISE_10HALF |
+				       ADVERTISE_10FULL |
+				       ADVERTISE_100HALF |
+				       ADVERTISE_100FULL);
+			if (options.speed != 10) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_100FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_100HALF;
+			}
+			if (options.speed != 100) {
+				if (options.duplex != 1)
+					advertize |= ADVERTISE_10FULL;
+				if (options.duplex != 2)
+					advertize |= ADVERTISE_10HALF;
 			}
-			printk(" done.\n");
-			neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
-				lp->linkspeed = 100;
+			if (options.speed == 100)
+				bmcr |= BMCR_SPEED100;
+			else if (options.speed == 10)
+				bmcr &= ~BMCR_SPEED100;
+			if (options.duplex == 2)
+				bmcr |= BMCR_FULLDPLX;
+			else if (options.duplex == 1)
+				bmcr &= ~BMCR_FULLDPLX;
+		} else {
+			/* Advertise everything we can support. */
+			if (bmsr & BMSR_10HALF)
+				advertize |= ADVERTISE_10HALF;
 			else
-				lp->linkspeed = 10;
-			if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
-				lp->fullduplex = 1;
+				advertize &= ~ADVERTISE_10HALF;
+			if (bmsr & BMSR_10FULL)
+				advertize |= ADVERTISE_10FULL;
 			else
-				lp->fullduplex = 0;
-		done:
-			;
+				advertize &= ~ADVERTISE_10FULL;
+			if (bmsr & BMSR_100HALF)
+				advertize |= ADVERTISE_100HALF;
+			else
+				advertize &= ~ADVERTISE_100HALF;
+			if (bmsr & BMSR_100FULL)
+				advertize |= ADVERTISE_100FULL;
+			else
+				advertize &= ~ADVERTISE_100FULL;
+		}
+
+		tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+		/* Enable Auto-Negotiation, this is usually on already... */
+		bmcr |= BMCR_ANENABLE;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* Restart it to make sure it is going. */
+		bmcr |= BMCR_ANRESTART;
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+		printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+		/* BMCR_ANRESTART self clears when the process has begun. */
+		timeout = 64;  /* More than enough. */
+		while (--timeout) {
+			bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+			if (!(bmcr & BMCR_ANRESTART))
+				break; /* got it. */
+			udelay(10);
 		}
+		if (!timeout) {
+			printk(KERN_ERR "%s: TC35815 would not start auto "
+			       "negotiation BMCR=0x%04x\n",
+			       dev->name, bmcr);
+			printk(KERN_NOTICE "%s: Performing force link "
+			       "detection.\n", dev->name);
+			goto force_link;
+		} else {
+			printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+			lp->timer_state = arbwait;
+		}
+	} else {
+force_link:
+		/* Force the link up, trying first a particular mode.
+		 * Either we are here at the request of ethtool or
+		 * because the Happy Meal would not start to autoneg.
+		 */
+
+		/* Disable auto-negotiation in BMCR, enable the duplex and
+		 * speed setting, init the timer state machine, and fire it off.
+		 */
+		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+			bmcr = BMCR_SPEED100;
+		} else {
+			if (ep->speed == SPEED_100)
+				bmcr = BMCR_SPEED100;
+			else
+				bmcr = 0;
+			if (ep->duplex == DUPLEX_FULL)
+				bmcr |= BMCR_FULLDPLX;
+		}
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+		/* OK, seems we need do disable the transceiver for the first
+		 * tick to make sure we get an accurate link state at the
+		 * second tick.
+		 */
+		lp->timer_state = ltrywait;
 	}
 
-	ctl = 0;
-	if (lp->linkspeed == 100)
-		ctl |= MIICNTL_SPEED;
-	if (lp->fullduplex)
-		ctl |= MIICNTL_FDX;
-	tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+	del_timer(&lp->timer);
+	lp->timer_ticks = 0;
+	lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+	add_timer(&lp->timer);
+}
 
-	if (lp->fullduplex) {
-		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short id0;
+
+	/* find MII phy */
+	for (pid = 31; pid >= 0; pid--) {
+		id0 = tc_mdio_read(dev, pid, MII_BMSR);
+		if (id0 != 0xffff && id0 != 0x0000 &&
+		    (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+			) {
+			lp->phy_addr = pid;
+			break;
+		}
 	}
+	if (pid < 0) {
+		printk(KERN_ERR "%s: No MII Phy found.\n",
+		       dev->name);
+		lp->phy_addr = pid = 0;
+	}
+
+	lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+	lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+	if (netif_msg_hw(lp))
+		printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+		       pid, lp->mii_id[0], lp->mii_id[1]);
 }
 
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
 {
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct tc35815_local *lp = dev->priv;
+	int pid = lp->phy_addr;
+	unsigned short bmcr;
+	struct ethtool_cmd ecmd, *ep;
+
+	/* dis-isolate if needed. */
+	bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+	if (bmcr & BMCR_ISOLATE) {
+		int count = 32;
+		printk(KERN_DEBUG "%s: unisolating...", dev->name);
+		tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+		while (--count) {
+			if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+				break;
+			udelay(20);
+		}
+		printk(" %s.\n", count ? "done" : "failed");
+	}
+
+	if (options.speed && options.duplex) {
+		ecmd.autoneg = AUTONEG_DISABLE;
+		ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+		ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+		ep = &ecmd;
+	} else {
+		ep = NULL;
+	}
+	tc35815_start_auto_negotiation(dev, ep);
+}
 
+static void tc35815_chip_reset(struct net_device *dev)
+{
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
+	int i;
 	/* reset the controller */
 	tc_writel(MAC_Reset, &tr->MAC_Ctl);
-	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
-		;
-
+	udelay(4); /* 3200ns */
+	i = 0;
+	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+		if (i++ > 100) {
+			printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+			break;
+		}
+		mdelay(1);
+	}
 	tc_writel(0, &tr->MAC_Ctl);
 
 	/* initialize registers to default value */
@@ -1651,90 +2803,142 @@ static void tc35815_chip_reset(struct ne
 	tc_writel(0, &tr->CAM_Ena);
 	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */
 
+	/* initialize internal SRAM */
+	tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+	for (i = 0; i < 0x1000; i += 4) {
+		tc_writel(i, &tr->CAM_Adr);
+		tc_writel(0, &tr->CAM_Data);
+	}
+	tc_writel(0, &tr->DMA_Ctl);
 }
 
 static void tc35815_chip_init(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
-	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
-	unsigned long flags;
+	struct tc35815_regs __iomem *tr =
+		(struct tc35815_regs __iomem *)dev->base_addr;
 	unsigned long txctl = TX_CTL_CMD;
 
 	tc35815_phy_chip_init(dev);
 
 	/* load station address to CAM */
-	tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+	tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
 
 	/* Enable CAM (broadcast and unicast) */
 	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
 	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
 
-	spin_lock_irqsave(&lp->lock, flags);
-
-	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-
+	/* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+	if (HAVE_DMA_RXALIGN(lp))
+		tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+	else
+		tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+#ifdef TC35815_USE_PACKEDBUFFER
 	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
+#else
+	tc_writel(ETH_ZLEN, &tr->RxFragSize);
+#endif
 	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
 	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
 	tc_writel(INT_EN_CMD, &tr->Int_En);
 
 	/* set queues */
-	tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+	tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
 	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
 		  &tr->FDA_Lim);
 	/*
 	 * Activation method:
-	 * First, enable eht MAC Transmitter and the DMA Receive circuits.
+	 * First, enable the MAC Transmitter and the DMA Receive circuits.
 	 * Then enable the DMA Transmitter and the MAC Receive circuits.
 	 */
-	tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
+	tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
 	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
+
 	/* start MAC transmitter */
+#ifndef NO_CHECK_CARRIER
+	/* TX4939 does not have EnLCarr */
+	if (lp->boardtype == TC35815_TX4939)
+		txctl &= ~Tx_EnLCarr;
+#ifdef WORKAROUND_LOSTCAR
 	/* WORKAROUND: ignore LostCrS in full duplex operation */
-	if (lp->fullduplex)
-		txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+	if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
+	    lp->fullduplex)
+		txctl &= ~Tx_EnLCarr;
+#endif
+#endif /* !NO_CHECK_CARRIER */
 #ifdef GATHER_TXINT
 	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
 #endif
 	tc_writel(txctl, &tr->Tx_Ctl);
-#if 0	/* No need to polling */
-	tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr);	/* start DMA transmitter */
-#endif
+}
+
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_save_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	netif_device_detach(dev);
+	spin_lock_irqsave(&lp->lock, flags);
+	del_timer(&lp->timer);		/* Kill if running	*/
+	tc35815_chip_reset(dev);
 	spin_unlock_irqrestore(&lp->lock, flags);
+	pci_set_power_state(pdev, PCI_D3hot);
+	return 0;
 }
 
-static struct pci_driver tc35815_driver = {
-	.name = TC35815_MODULE_NAME,
-	.probe = tc35815_probe,
-	.remove = NULL,
-	.id_table = tc35815_pci_tbl,
+static int tc35815_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tc35815_local *lp = dev->priv;
+	unsigned long flags;
+
+	pci_restore_state(pdev);
+	if (!netif_running(dev))
+		return 0;
+	pci_set_power_state(pdev, PCI_D0);
+	spin_lock_irqsave(&lp->lock, flags);
+	tc35815_restart(dev);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	netif_device_attach(dev);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver tc35815_pci_driver = {
+	.name		= MODNAME,
+	.id_table	= tc35815_pci_tbl,
+	.probe		= tc35815_init_one,
+	.remove		= __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+	.suspend	= tc35815_suspend,
+	.resume		= tc35815_resume,
+#endif
 };
 
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+module_param_named(doforce, options.doforce, int, 0);
+MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
+
 static int __init tc35815_init_module(void)
 {
-	return pci_register_driver(&tc35815_driver);
+	return pci_register_driver(&tc35815_pci_driver);
 }
 
 static void __exit tc35815_cleanup_module(void)
 {
-	struct net_device *next_dev;
-
-	/*
-	 * TODO: implement a tc35815_driver.remove hook, and
-	 * move this code into that function.  Then, delete
-	 * all root_tc35815_dev list handling code.
-	 */
-	while (root_tc35815_dev) {
-		struct net_device *dev = root_tc35815_dev;
-		next_dev = ((struct tc35815_local *)dev->priv)->next_module;
-		iounmap((void *)(dev->base_addr));
-		unregister_netdev(dev);
-		free_netdev(dev);
-		root_tc35815_dev = next_dev;
-	}
-
-	pci_unregister_driver(&tc35815_driver);
+	pci_unregister_driver(&tc35815_pci_driver);
 }
 
 module_init(tc35815_init_module);
 module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 256969e..e5e901e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -40,16 +40,16 @@ #include <linux/prefetch.h>
 #include <linux/dma-mapping.h>
 
 #include <net/checksum.h>
+#include <net/ip.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
 #include <asm/idprom.h>
-#include <asm/oplib.h>
-#include <asm/pbm.h>
+#include <asm/prom.h>
 #endif
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -64,8 +64,8 @@ #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.75"
-#define DRV_MODULE_RELDATE	"March 23, 2007"
+#define DRV_MODULE_VERSION	"3.76"
+#define DRV_MODULE_RELDATE	"May 5, 2007"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -1300,9 +1300,11 @@ static int tg3_set_power_state(struct tg
 			msleep(1);
 		}
 	}
-	tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
-					     WOL_DRV_STATE_SHUTDOWN |
-					     WOL_DRV_WOL | WOL_SET_MAGIC_PKT);
+	if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+		tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
+						     WOL_DRV_STATE_SHUTDOWN |
+						     WOL_DRV_WOL |
+						     WOL_SET_MAGIC_PKT);
 
 	pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
 
@@ -2593,10 +2595,8 @@ static int tg3_setup_fiber_by_hand(struc
 {
 	int current_link_up = 0;
 
- 	if (!(mac_status & MAC_STATUS_PCS_SYNCED)) {
-		tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL;
+	if (!(mac_status & MAC_STATUS_PCS_SYNCED))
 		goto out;
-	}
 
 	if (tp->link_config.autoneg == AUTONEG_ENABLE) {
 		u32 flags;
@@ -2614,7 +2614,6 @@ static int tg3_setup_fiber_by_hand(struc
 
 			tg3_setup_flow_control(tp, local_adv, remote_adv);
 
-			tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
 			current_link_up = 1;
 		}
 		for (i = 0; i < 30; i++) {
@@ -2637,7 +2636,6 @@ static int tg3_setup_fiber_by_hand(struc
 	} else {
 		/* Forcing 1000FD link up. */
 		current_link_up = 1;
-		tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
 
 		tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
 		udelay(40);
@@ -3021,6 +3019,16 @@ static int tg3_setup_phy(struct tg3 *tp,
 		}
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) {
+		u32 val = tr32(PCIE_PWR_MGMT_THRESH);
+		if (!netif_carrier_ok(tp->dev))
+			val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) |
+			      tp->pwrmgmt_thresh;
+		else
+			val |= PCIE_PWR_MGMT_L1_THRESH_MSK;
+		tw32(PCIE_PWR_MGMT_THRESH, val);
+	}
+
 	return err;
 }
 
@@ -3349,7 +3357,7 @@ static int tg3_rx(struct tg3 *tp, int bu
 			skb_reserve(copy_skb, 2);
 			skb_put(copy_skb, len);
 			pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
-			memcpy(copy_skb->data, skb->data, len);
+			skb_copy_from_linear_data(skb, copy_skb->data, len);
 			pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
 
 			/* We'll reuse the original ring buffer. */
@@ -3582,8 +3590,12 @@ static irqreturn_t tg3_interrupt(int irq
 	 * Writing non-zero to intr-mbox-0 additional tells the
 	 * NIC to stop sending us irqs, engaging "in-intr-handler"
 	 * event coalescing.
+	 *
+	 * Flush the mailbox to de-assert the IRQ immediately to prevent
+	 * spurious interrupts.  The flush impacts performance but
+	 * excessive spurious interrupts can be worse in some cases.
 	 */
-	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (tg3_irq_sync(tp))
 		goto out;
 	sblk->status &= ~SD_STATUS_UPDATED;
@@ -3627,8 +3639,12 @@ static irqreturn_t tg3_interrupt_tagged(
 	 * writing non-zero to intr-mbox-0 additional tells the
 	 * NIC to stop sending us irqs, engaging "in-intr-handler"
 	 * event coalescing.
+	 *
+	 * Flush the mailbox to de-assert the IRQ immediately to prevent
+	 * spurious interrupts.  The flush impacts performance but
+	 * excessive spurious interrupts can be worse in some cases.
 	 */
-	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (tg3_irq_sync(tp))
 		goto out;
 	if (netif_rx_schedule_prep(dev)) {
@@ -3895,8 +3911,7 @@ static int tg3_start_xmit(struct sk_buff
 	entry = tp->tx_prod;
 	base_flags = 0;
 	mss = 0;
-	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
-	    (mss = skb_shinfo(skb)->gso_size) != 0) {
+	if ((mss = skb_shinfo(skb)->gso_size) != 0) {
 		int tcp_opt_len, ip_tcp_len;
 
 		if (skb_header_cloned(skb) &&
@@ -3908,20 +3923,20 @@ static int tg3_start_xmit(struct sk_buff
 		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
 			mss |= (skb_headlen(skb) - ETH_HLEN) << 9;
 		else {
-			tcp_opt_len = ((skb->h.th->doff - 5) * 4);
-			ip_tcp_len = (skb->nh.iph->ihl * 4) +
-				     sizeof(struct tcphdr);
+			struct iphdr *iph = ip_hdr(skb);
+
+			tcp_opt_len = tcp_optlen(skb);
+			ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
 
-			skb->nh.iph->check = 0;
-			skb->nh.iph->tot_len = htons(mss + ip_tcp_len +
-						     tcp_opt_len);
+			iph->check = 0;
+			iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
 			mss |= (ip_tcp_len + tcp_opt_len) << 9;
 		}
 
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
 
-		skb->h.th->check = 0;
+		tcp_hdr(skb)->check = 0;
 
 	}
 	else if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -4053,8 +4068,8 @@ static int tg3_start_xmit_dma_bug(struct
 	if (skb->ip_summed == CHECKSUM_PARTIAL)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
 	mss = 0;
-	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
-	    (mss = skb_shinfo(skb)->gso_size) != 0) {
+	if ((mss = skb_shinfo(skb)->gso_size) != 0) {
+		struct iphdr *iph;
 		int tcp_opt_len, ip_tcp_len, hdr_len;
 
 		if (skb_header_cloned(skb) &&
@@ -4063,8 +4078,8 @@ static int tg3_start_xmit_dma_bug(struct
 			goto out_unlock;
 		}
 
-		tcp_opt_len = ((skb->h.th->doff - 5) * 4);
-		ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+		tcp_opt_len = tcp_optlen(skb);
+		ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
 
 		hdr_len = ip_tcp_len + tcp_opt_len;
 		if (unlikely((ETH_HLEN + hdr_len) > 80) &&
@@ -4074,34 +4089,31 @@ static int tg3_start_xmit_dma_bug(struct
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
 
-		skb->nh.iph->check = 0;
-		skb->nh.iph->tot_len = htons(mss + hdr_len);
+		iph = ip_hdr(skb);
+		iph->check = 0;
+		iph->tot_len = htons(mss + hdr_len);
 		if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
-			skb->h.th->check = 0;
+			tcp_hdr(skb)->check = 0;
 			base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
-		}
-		else {
-			skb->h.th->check =
-				~csum_tcpudp_magic(skb->nh.iph->saddr,
-						   skb->nh.iph->daddr,
-						   0, IPPROTO_TCP, 0);
-		}
+		} else
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
 
 		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
 		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
-			if (tcp_opt_len || skb->nh.iph->ihl > 5) {
+			if (tcp_opt_len || iph->ihl > 5) {
 				int tsflags;
 
-				tsflags = ((skb->nh.iph->ihl - 5) +
-					   (tcp_opt_len >> 2));
+				tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
 				mss |= (tsflags << 11);
 			}
 		} else {
-			if (tcp_opt_len || skb->nh.iph->ihl > 5) {
+			if (tcp_opt_len || iph->ihl > 5) {
 				int tsflags;
 
-				tsflags = ((skb->nh.iph->ihl - 5) +
-					   (tcp_opt_len >> 2));
+				tsflags = (iph->ihl - 5) + (tcp_opt_len >> 2);
 				base_flags |= tsflags << 12;
 			}
 		}
@@ -5936,7 +5948,7 @@ static int tg3_load_tso_firmware(struct 
 
 
 /* tp->lock is held. */
-static void __tg3_set_mac_addr(struct tg3 *tp)
+static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
 {
 	u32 addr_high, addr_low;
 	int i;
@@ -5948,6 +5960,8 @@ static void __tg3_set_mac_addr(struct tg
 		    (tp->dev->dev_addr[4] <<  8) |
 		    (tp->dev->dev_addr[5] <<  0));
 	for (i = 0; i < 4; i++) {
+		if (i == 1 && skip_mac_1)
+			continue;
 		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
 		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
 	}
@@ -5974,7 +5988,7 @@ static int tg3_set_mac_addr(struct net_d
 {
 	struct tg3 *tp = netdev_priv(dev);
 	struct sockaddr *addr = p;
-	int err = 0;
+	int err = 0, skip_mac_1 = 0;
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EINVAL;
@@ -5985,22 +5999,21 @@ static int tg3_set_mac_addr(struct net_d
 		return 0;
 
 	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
-		/* Reset chip so that ASF can re-init any MAC addresses it
-		 * needs.
-		 */
-		tg3_netif_stop(tp);
-		tg3_full_lock(tp, 1);
+		u32 addr0_high, addr0_low, addr1_high, addr1_low;
 
-		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-		err = tg3_restart_hw(tp, 0);
-		if (!err)
-			tg3_netif_start(tp);
-		tg3_full_unlock(tp);
-	} else {
-		spin_lock_bh(&tp->lock);
-		__tg3_set_mac_addr(tp);
-		spin_unlock_bh(&tp->lock);
+		addr0_high = tr32(MAC_ADDR_0_HIGH);
+		addr0_low = tr32(MAC_ADDR_0_LOW);
+		addr1_high = tr32(MAC_ADDR_1_HIGH);
+		addr1_low = tr32(MAC_ADDR_1_LOW);
+
+		/* Skip MAC addr 1 if ASF is using it. */
+		if ((addr0_high != addr1_high || addr0_low != addr1_low) &&
+		    !(addr1_high == 0 && addr1_low == 0))
+			skip_mac_1 = 1;
 	}
+	spin_lock_bh(&tp->lock);
+	__tg3_set_mac_addr(tp, skip_mac_1);
+	spin_unlock_bh(&tp->lock);
 
 	return err;
 }
@@ -6317,7 +6330,7 @@ static int tg3_reset_hw(struct tg3 *tp, 
 		     tp->rx_jumbo_ptr);
 
 	/* Initialize MAC address and backoff seed. */
-	__tg3_set_mac_addr(tp);
+	__tg3_set_mac_addr(tp, 0);
 
 	/* MTU + ethernet header + FCS + optional VLAN tag */
 	tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8);
@@ -6348,8 +6361,7 @@ static int tg3_reset_hw(struct tg3 *tp, 
 	     tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) {
 		if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE &&
-		    (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 ||
-		     tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) {
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
 			rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
 		} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
 			   !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
@@ -6459,6 +6471,7 @@ static int tg3_reset_hw(struct tg3 *tp, 
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
 			gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
 
+		tp->grc_local_ctrl &= ~gpio_mask;
 		tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask;
 
 		/* GPIO1 must be driven high for eeprom write protect */
@@ -7038,11 +7051,7 @@ static int tg3_open(struct net_device *d
 	if (err)
 		return err;
 
-	if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
-	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
-	    (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) &&
-	    !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) &&
-	      (tp->pdev_peer == tp->pdev))) {
+	if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) {
 		/* All MSI supporting chips should support tagged
 		 * status.  Assert that this is the case.
 		 */
@@ -7401,9 +7410,7 @@ #endif
 
 	tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 	tg3_free_rings(tp);
-	tp->tg3_flags &=
-		~(TG3_FLAG_INIT_COMPLETE |
-		  TG3_FLAG_GOT_SERDES_FLOWCTL);
+	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 
 	tg3_full_unlock(tp);
 
@@ -8038,7 +8045,10 @@ static void tg3_get_wol(struct net_devic
 {
 	struct tg3 *tp = netdev_priv(dev);
 
-	wol->supported = WAKE_MAGIC;
+	if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+		wol->supported = WAKE_MAGIC;
+	else
+		wol->supported = 0;
 	wol->wolopts = 0;
 	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
 		wol->wolopts = WAKE_MAGIC;
@@ -8052,8 +8062,7 @@ static int tg3_set_wol(struct net_device
 	if (wol->wolopts & ~WAKE_MAGIC)
 		return -EINVAL;
 	if ((wol->wolopts & WAKE_MAGIC) &&
-	    tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
-	    !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+	    !(tp->tg3_flags & TG3_FLAG_WOL_CAP))
 		return -EINVAL;
 
 	spin_lock_bh(&tp->lock);
@@ -9291,7 +9300,7 @@ static void __devinit tg3_get_nvram_size
 			return;
 		}
 	}
-	tp->nvram_size = 0x20000;
+	tp->nvram_size = 0x80000;
 }
 
 static void __devinit tg3_get_nvram_info(struct tg3 *tp)
@@ -9410,33 +9419,31 @@ static void __devinit tg3_get_5752_nvram
 
 static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
 {
-	u32 nvcfg1;
+	u32 nvcfg1, protect = 0;
 
 	nvcfg1 = tr32(NVRAM_CFG1);
 
 	/* NVRAM protection for TPM */
-	if (nvcfg1 & (1 << 27))
+	if (nvcfg1 & (1 << 27)) {
 		tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+		protect = 1;
+	}
 
-	switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
-		case FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ:
-		case FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ:
-			tp->nvram_jedecnum = JEDEC_ATMEL;
-			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
-			tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
-
-			nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
-			tw32(NVRAM_CFG1, nvcfg1);
-			break;
-		case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+	nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK;
+	switch (nvcfg1) {
 		case FLASH_5755VENDOR_ATMEL_FLASH_1:
 		case FLASH_5755VENDOR_ATMEL_FLASH_2:
 		case FLASH_5755VENDOR_ATMEL_FLASH_3:
-		case FLASH_5755VENDOR_ATMEL_FLASH_4:
 			tp->nvram_jedecnum = JEDEC_ATMEL;
 			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
 			tp->tg3_flags2 |= TG3_FLG2_FLASH;
 			tp->nvram_pagesize = 264;
+			if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1)
+				tp->nvram_size = (protect ? 0x3e200 : 0x80000);
+			else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2)
+				tp->nvram_size = (protect ? 0x1f200 : 0x40000);
+			else
+				tp->nvram_size = (protect ? 0x1f200 : 0x20000);
 			break;
 		case FLASH_5752VENDOR_ST_M45PE10:
 		case FLASH_5752VENDOR_ST_M45PE20:
@@ -9445,6 +9452,12 @@ static void __devinit tg3_get_5755_nvram
 			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
 			tp->tg3_flags2 |= TG3_FLG2_FLASH;
 			tp->nvram_pagesize = 256;
+			if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10)
+				tp->nvram_size = (protect ? 0x10000 : 0x20000);
+			else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20)
+				tp->nvram_size = (protect ? 0x10000 : 0x40000);
+			else
+				tp->nvram_size = (protect ? 0x20000 : 0x80000);
 			break;
 	}
 }
@@ -9520,6 +9533,8 @@ static void __devinit tg3_nvram_init(str
 		}
 		tg3_enable_nvram_access(tp);
 
+		tp->nvram_size = 0;
+
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
 			tg3_get_5752_nvram_info(tp);
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
@@ -9531,7 +9546,8 @@ static void __devinit tg3_nvram_init(str
 		else
 			tg3_get_nvram_info(tp);
 
-		tg3_get_nvram_size(tp);
+		if (tp->nvram_size == 0)
+			tg3_get_nvram_size(tp);
 
 		tg3_disable_nvram_access(tp);
 		tg3_nvram_unlock(tp);
@@ -9998,14 +10014,16 @@ static void __devinit tg3_get_eeprom_hw_
 	tp->phy_id = PHY_ID_INVALID;
 	tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
-	/* Assume an onboard device by default.  */
-	tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+	/* Assume an onboard device and WOL capable by default.  */
+	tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP;
 
 	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;
 			tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
 		}
+		if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+			tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
 		return;
 	}
 
@@ -10122,8 +10140,9 @@ static void __devinit tg3_get_eeprom_hw_
 			if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 				tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
 		}
-		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
-			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
+		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
+		    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
+			tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
 		if (cfg2 & (1 << 17))
 			tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
@@ -10132,6 +10151,14 @@ static void __devinit tg3_get_eeprom_hw_
 		/* bootcode if bit 18 is set */
 		if (cfg2 & (1 << 18))
 			tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
+
+		if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+			u32 cfg3;
+
+			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
+			if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
+				tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+		}
 	}
 }
 
@@ -10401,6 +10428,8 @@ static void __devinit tg3_read_fw_ver(st
 	}
 }
 
+static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
+
 static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
 	static struct pci_device_id write_reorder_chipsets[] = {
@@ -10556,6 +10585,10 @@ static int __devinit tg3_get_invariants(
 	tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
 	tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
 
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
+		tp->pdev_peer = tg3_find_peer(tp);
+
 	if (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 ||
@@ -10569,6 +10602,14 @@ static int __devinit tg3_get_invariants(
 		tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
 
 	if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+		tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI;
+		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX ||
+		    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX ||
+		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 &&
+		     tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 &&
+		     tp->pdev_peer == tp->pdev))
+			tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI;
+
 		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_5906) {
@@ -10670,17 +10711,6 @@ static int __devinit tg3_get_invariants(
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
 		tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
 
-	/* Back to back register writes can cause problems on this chip,
-	 * the workaround is to read back all reg writes except those to
-	 * mailbox regs.  See tg3_write_indirect_reg32().
-	 *
-	 * PCI Express 5750_A0 rev chips need this workaround too.
-	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
-	    ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
-	     tp->pci_chip_rev_id == CHIPREV_ID_5750_A0))
-		tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG;
-
 	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
 	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
@@ -10704,8 +10734,19 @@ static int __devinit tg3_get_invariants(
 	/* Various workaround register access methods */
 	if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
 		tp->write32 = tg3_write_indirect_reg32;
-	else if (tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG)
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+		 ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+		  tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) {
+		/*
+		 * Back to back register writes can cause problems on these
+		 * chips, the workaround is to read back all reg writes
+		 * except those to mailbox regs.
+		 *
+		 * See tg3_write_indirect_reg32().
+		 */
 		tp->write32 = tg3_write_flush_reg32;
+	}
+
 
 	if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
 	    (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
@@ -10985,27 +11026,27 @@ static int __devinit tg3_get_invariants(
 	 */
 	tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
 
+	if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
+		tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
+				     PCIE_PWR_MGMT_L1_THRESH_MSK;
+
 	return err;
 }
 
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
 static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
 {
 	struct net_device *dev = tp->dev;
 	struct pci_dev *pdev = tp->pdev;
-	struct pcidev_cookie *pcp = pdev->sysdata;
-
-	if (pcp != NULL) {
-		unsigned char *addr;
-		int len;
-
-		addr = of_get_property(pcp->prom_node, "local-mac-address",
-					&len);
-		if (addr && len == 6) {
-			memcpy(dev->dev_addr, addr, 6);
-			memcpy(dev->perm_addr, dev->dev_addr, 6);
-			return 0;
-		}
+	struct device_node *dp = pci_device_to_OF_node(pdev);
+	const unsigned char *addr;
+	int len;
+
+	addr = of_get_property(dp, "local-mac-address", &len);
+	if (addr && len == 6) {
+		memcpy(dev->dev_addr, addr, 6);
+		memcpy(dev->perm_addr, dev->dev_addr, 6);
+		return 0;
 	}
 	return -ENODEV;
 }
@@ -11026,7 +11067,7 @@ static int __devinit tg3_get_device_addr
 	u32 hi, lo, mac_offset;
 	int addr_ok = 0;
 
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
 	if (!tg3_get_macaddr_sparc(tp))
 		return 0;
 #endif
@@ -11898,10 +11939,6 @@ #endif
 		tp->rx_pending = 63;
 	}
 
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
-		tp->pdev_peer = tg3_find_peer(tp);
-
 	err = tg3_get_device_address(tp);
 	if (err) {
 		printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index d515ed2..4d334cf 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -131,6 +131,7 @@ #define  CHIPREV_ID_5750_C2		 0x4202
 #define  CHIPREV_ID_5752_A0_HW		 0x5000
 #define  CHIPREV_ID_5752_A0		 0x6000
 #define  CHIPREV_ID_5752_A1		 0x6001
+#define  CHIPREV_ID_5714_A2		 0x9002
 #define  CHIPREV_ID_5906_A1		 0xc001
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
@@ -1149,6 +1150,9 @@ #define VCPU_STATUS			0x00005100
 #define  VCPU_STATUS_INIT_DONE		 0x04000000
 #define  VCPU_STATUS_DRV_RESET		 0x08000000
 
+#define VCPU_CFGSHDW			0x00005104
+#define  VCPU_CFGSHDW_ASPM_DBNC		 0x00001000
+
 /* Mailboxes */
 #define GRCMBOX_BASE			0x00005600
 #define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
@@ -1506,6 +1510,8 @@ #define PCIE_TRANSACTION_CFG		0x00007c04
 #define PCIE_TRANS_CFG_1SHOT_MSI	 0x20000000
 #define PCIE_TRANS_CFG_LOM		 0x00000020
 
+#define PCIE_PWR_MGMT_THRESH		0x00007d28
+#define PCIE_PWR_MGMT_L1_THRESH_MSK	 0x0000ff00
 
 #define TG3_EEPROM_MAGIC		0x669955aa
 #define TG3_EEPROM_MAGIC_FW		0xa5000000
@@ -1592,6 +1598,9 @@ #define  SHASTA_EXT_LED_SHARED		 0x00008
 #define  SHASTA_EXT_LED_MAC		 0x00010000
 #define  SHASTA_EXT_LED_COMBO		 0x00018000
 
+#define NIC_SRAM_DATA_CFG_3		0x00000d3c
+#define  NIC_SRAM_ASPM_DEBOUNCE		 0x00000002
+
 #define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
 
 #define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
@@ -2199,7 +2208,7 @@ #define TG3_FLAG_RX_CHECKSUMS		0x0000000
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
 #define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
 #define TG3_FLAG_ENABLE_ASF		0x00000020
-#define TG3_FLAG_5701_REG_WRITE_BUG	0x00000040
+#define TG3_FLAG_ASPM_WORKAROUND	0x00000040
 #define TG3_FLAG_POLL_SERDES		0x00000080
 #define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
 #define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
@@ -2215,14 +2224,14 @@ #define TG3_FLAG_PCI_HIGH_SPEED		0x00040
 #define TG3_FLAG_PCI_32BIT		0x00080000
 #define TG3_FLAG_SRAM_USE_CONFIG	0x00100000
 #define TG3_FLAG_TX_RECOVERY_PENDING	0x00200000
-#define TG3_FLAG_SERDES_WOL_CAP		0x00400000
+#define TG3_FLAG_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
 #define TG3_FLAG_IN_RESET_TASK		0x04000000
 #define TG3_FLAG_40BIT_DMA_BUG		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
-#define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
+#define TG3_FLAG_SUPPORT_MSI		0x20000000
 #define TG3_FLAG_CHIP_RESETTING		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 	u32				tg3_flags2;
@@ -2288,6 +2297,7 @@ #define SERDES_AN_TIMEOUT_5714S		1
 	u32				grc_local_ctrl;
 	u32				dma_rwctrl;
 	u32				coalesce_mode;
+	u32				pwrmgmt_thresh;
 
 	/* PCI block */
 	u16				pci_chip_rev_id;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index f85f002..106dc1e 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1112,7 +1112,7 @@ static int TLan_StartTx( struct sk_buff 
 
 	if ( bbuf ) {
 		tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
-		memcpy( tail_buffer, skb->data, skb->len );
+		skb_copy_from_linear_data(skb, tail_buffer, skb->len);
 	} else {
 		tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE);
 		TLan_StoreSKB(tail_list, skb);
@@ -1577,7 +1577,6 @@ u32 TLan_HandleRxEOF( struct net_device 
 				printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n");
 			else {
 				head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
-				skb->dev = dev;
 				skb_reserve(skb, 2);
 				t = (void *) skb_put(skb, frameSize);
 
@@ -1608,7 +1607,6 @@ 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);
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 7580bde..e22a3f5 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -933,20 +933,21 @@ static void xl_rx(struct net_device *dev
 				return ; 				
 			}
 	
-			skb->dev = dev ; 
-
 			while (xl_priv->rx_ring_tail != temp_ring_loc) { 
 				copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; 
 				frame_length -= copy_len ;  
 				pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
-				memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; 
+				skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail],
+							  skb_put(skb, copy_len),
+							  copy_len);
 				pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 				adv_rx_ring(dev) ; 
 			} 
 
 			/* Now we have found the last fragment */
 			pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
-			memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; 
+			skb_copy_from_linear_data(xl_priv->rx_ring_skb[xl_priv->rx_ring_tail],
+				      skb_put(skb,copy_len), frame_length);
 /*			memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */
 			pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
 			adv_rx_ring(dev) ; 
@@ -967,8 +968,6 @@ static void xl_rx(struct net_device *dev
 				return ; 
 			}
 
-			skb->dev = dev ; 
-
 			skb2 = xl_priv->rx_ring_skb[xl_priv->rx_ring_tail] ; 
 			pci_unmap_single(xl_priv->pdev, xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr, xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 			skb_put(skb2, frame_length) ; 
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 01d5531..1e8958e 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -1771,7 +1771,6 @@ #endif
 	/*BMS again, if she comes in with few but leaves with many */
 	skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len);
 	skb_put(skb, length);
-	skb->dev = dev;
 	data = skb->data;
 	rbuffer_len = ntohs(readw(rbuf + offsetof(struct rec_buf, buf_len)));
 	rbufdata = rbuf + offsetof(struct rec_buf, data);
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index e999feb..5d849c0 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -944,8 +944,6 @@ static void streamer_rx(struct net_devic
 				printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",	dev->name);
 				streamer_priv->streamer_stats.rx_dropped++;
 			} else {	/* we allocated an skb OK */
-				skb->dev = dev;
-
 				if (buffer_cnt == 1) {
 					/* release the DMA mapping */
 					pci_unmap_single(streamer_priv->pci_dev, 
@@ -1607,10 +1605,11 @@ #endif
 				      frame_data, buffer_len);
 		} while (next_ptr && (buff_off = next_ptr));
 
+		mac_frame->protocol = tr_type_trans(mac_frame, dev);
 #if STREAMER_NETWORK_MONITOR
 		printk(KERN_WARNING "%s: Received MAC Frame, details: \n",
 		       dev->name);
-		mac_hdr = (struct trh_hdr *) mac_frame->data;
+		mac_hdr = tr_hdr(mac_frame);
 		printk(KERN_WARNING
 		       "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
 		       dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1],
@@ -1622,8 +1621,6 @@ #if STREAMER_NETWORK_MONITOR
 		       mac_hdr->saddr[2], mac_hdr->saddr[3],
 		       mac_hdr->saddr[4], mac_hdr->saddr[5]);
 #endif
-		mac_frame->dev = dev;
-		mac_frame->protocol = tr_type_trans(mac_frame, dev);
 		netif_rx(mac_frame);
 
 		/* Now tell the card we have dealt with the received frame */
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index ed274d6..f8f4d74 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -23,7 +23,6 @@ #include <linux/module.h>
 #include <linux/mca.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/trdevice.h>
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 8f4ecc1..09b3cfb 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -814,8 +814,6 @@ #endif
 					olympic_priv->rx_ring_last_received += i ; 
 					olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ;  
 				} else  {
-					skb->dev = dev ; 
-
 					/* Optimise based upon number of buffers used. 
 			   	   	   If only one buffer is used we can simply swap the buffers around.
 			   	   	   If more than one then we must use the new buffer and copy the information
@@ -847,7 +845,9 @@ #endif
 							pci_dma_sync_single_for_cpu(olympic_priv->pdev,
 								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
-							memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; 
+							skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received],
+								      skb_put(skb,length - 4),
+								      length - 4);
 							pci_dma_sync_single_for_device(olympic_priv->pdev,
 								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
@@ -864,7 +864,9 @@ #endif
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; 
 							rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]);
 							cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); 
-							memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ;
+							skb_copy_from_linear_data(olympic_priv->rx_ring_skb[rx_ring_last_received],
+								      skb_put(skb, cpy_length),
+								      cpy_length);
 							pci_dma_sync_single_for_device(olympic_priv->pdev,
 								le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer),
 								olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ;
@@ -1440,16 +1442,16 @@ #endif 
 			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
 		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
 
+		mac_frame->protocol = tr_type_trans(mac_frame, dev);
+
 		if (olympic_priv->olympic_network_monitor) { 
 			struct trh_hdr *mac_hdr ; 
 			printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
-			mac_hdr = (struct trh_hdr *)mac_frame->data ; 
+			mac_hdr = tr_hdr(mac_frame);
 			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
 			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
 		}
-		mac_frame->dev = dev ; 
-		mac_frame->protocol = tr_type_trans(mac_frame,dev);
-		netif_rx(mac_frame) ; 	
+		netif_rx(mac_frame);
 		dev->last_rx = jiffies;
 
 drop_frame:
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index cec282a..58d7e5d 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -41,7 +41,6 @@ #include <linux/string.h>
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/mca-legacy.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -3889,14 +3888,13 @@ static int smctr_process_rx_packet(MAC_H
 
                 /* Slide data into a sleek skb. */
                 skb_put(skb, skb->len);
-                memcpy(skb->data, rmf, skb->len);
+                skb_copy_to_linear_data(skb, rmf, skb->len);
 
                 /* Update Counters */
                 tp->MacStat.rx_packets++;
                 tp->MacStat.rx_bytes += skb->len;
 
                 /* Kick the packet on up. */
-                skb->dev = dev;
                 skb->protocol = tr_type_trans(skb, dev);
                 netif_rx(skb);
 		dev->last_rx = jiffies;
@@ -4476,14 +4474,13 @@ static int smctr_rx_frame(struct net_dev
 				if (skb) {
                                 	skb_put(skb, rx_size);
 
-                                	memcpy(skb->data, pbuff, rx_size);
+					skb_copy_to_linear_data(skb, pbuff, rx_size);
 
                                 	/* Update Counters */
                                 	tp->MacStat.rx_packets++;
                                 	tp->MacStat.rx_bytes += skb->len;
 
                                 	/* Kick the packet on up. */
-                                	skb->dev = dev;
                                 	skb->protocol = tr_type_trans(skb, dev);
                                 	netif_rx(skb);
 					dev->last_rx = jiffies;
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index ea797ca..12bd294 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -644,7 +644,7 @@ static int tms380tr_hardware_send_packet
 		dmabuf  = 0;
 		i 	= tp->TplFree->TPLIndex;
 		buf 	= tp->LocalTxBuffers[i];
-		memcpy(buf, skb->data, length);
+		skb_copy_from_linear_data(skb, buf, length);
 		newbuf 	= ((char *)buf - (char *)tp) + tp->dmabuffer;
 	}
 	else {
@@ -2168,7 +2168,6 @@ static void tms380tr_rcv_status_irq(stru
 				}
 				else
 				{
-					skb->dev	= dev;
 					skb_put(skb, tp->MaxPacketSize);
 					rpl->SkbStat 	= SKB_DATA_COPY;
 					ReceiveDataPtr 	= rpl->MData;
@@ -2179,7 +2178,8 @@ static void tms380tr_rcv_status_irq(stru
 				|| rpl->SkbStat == SKB_DMA_DIRECT))
 			{
 				if(rpl->SkbStat == SKB_DATA_COPY)
-					memcpy(skb->data, ReceiveDataPtr, Length);
+					skb_copy_to_linear_data(skb, ReceiveDataPtr,
+						       Length);
 
 				/* Deliver frame to system */
 				rpl->Skb = NULL;
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index d92c5c5..1aabc91 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -82,6 +82,7 @@ struct tsi108_prv_data {
 	unsigned int phy;		/* Index of PHY for this interface */
 	unsigned int irq_num;
 	unsigned int id;
+	unsigned int phy_type;
 
 	struct timer_list timer;/* Timer that triggers the check phy function */
 	unsigned int rxtail;	/* Next entry in rxring to read */
@@ -788,7 +789,6 @@ static int tsi108_complete_rx(struct net
 			printk(".\n");
 		}
 
-		skb->dev = dev;
 		skb_put(skb, data->rxring[rx].len);
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_receive_skb(skb);
@@ -1257,11 +1257,11 @@ static void tsi108_init_phy(struct net_d
 	if (i == 0)
 		printk(KERN_ERR "%s function time out \n", __FUNCTION__);
 
-#if (TSI108_PHY_TYPE == PHY_BCM54XX)	/* Broadcom BCM54xx PHY */
-	tsi108_write_mii(data, 0x09, 0x0300);
-	tsi108_write_mii(data, 0x10, 0x1020);
-	tsi108_write_mii(data, 0x1c, 0x8c00);
-#endif
+	if (data->phy_type == TSI108_PHY_BCM54XX) {
+		tsi108_write_mii(data, 0x09, 0x0300);
+		tsi108_write_mii(data, 0x10, 0x1020);
+		tsi108_write_mii(data, 0x1c, 0x8c00);
+	}
 
 	tsi108_write_mii(data,
 			 MII_BMCR,
@@ -1588,6 +1588,7 @@ tsi108_init_one(struct platform_device *
 	data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
 
 	data->phy = einfo->phy;
+	data->phy_type = einfo->phy_type;
 	data->irq_num = einfo->irq_num;
 	data->id = pdev->id;
 	dev->open = tsi108_open;
diff --git a/drivers/net/tsi108_eth.h b/drivers/net/tsi108_eth.h
index 77a769d..5a77ae6 100644
--- a/drivers/net/tsi108_eth.h
+++ b/drivers/net/tsi108_eth.h
@@ -43,15 +43,6 @@ #define TSI_READ_PHY(offset) \
 	in_be32((data->phyregs + (offset)))
 
 /*
- * PHY Configuration Options
- *
- * NOTE: Enable set of definitions corresponding to your board type
- */
-#define PHY_MV88E	1	/* Marvel 88Exxxx PHY */
-#define PHY_BCM54XX	2	/* Broardcom BCM54xx PHY */
-#define TSI108_PHY_TYPE	PHY_MV88E
-
-/*
  * TSI108 GIGE port registers
  */
 
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 942b839..6c400cc 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -14,7 +14,6 @@
 
 */
 
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include "tulip.h"
 
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index c82befa..8617298 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmap
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-        || defined(__sparc__) || defined(__ia64__) \
+        || defined(CONFIG_SPARC) || defined(__ia64__) \
         || defined(__sh__) || defined(__mips__)
 static int rx_copybreak = 1518;
 #else
@@ -435,7 +435,6 @@ static void de_rx (struct de_private *de
 			rx_work = 100;
 			goto rx_next;
 		}
-		copy_skb->dev = de->dev;
 
 		if (!copying_skb) {
 			pci_unmap_single(de->pdev, mapping,
@@ -450,8 +449,8 @@ static void de_rx (struct de_private *de
 		} else {
 			pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
 			skb_reserve(copy_skb, RX_OFFSET);
-			memcpy(skb_put(copy_skb, len), skb->data, len);
-
+			skb_copy_from_linear_data(skb, skb_put(copy_skb, len),
+						  len);
 			pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
 
 			/* We'll reuse the original ring buffer. */
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 4b3cd3d..62143f9 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1160,7 +1160,7 @@ de4x5_hw_init(struct net_device *dev, u_
 	sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id);
 
 	lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
-#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY)
+#if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY)
 	lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN;
 #endif
 	lp->rx_ring = dma_alloc_coherent(gendev, lp->dma_size,
@@ -1175,7 +1175,7 @@ #endif
 	** Set up the RX descriptor ring (Intels)
 	** Allocate contiguous receive buffers, long word aligned (Alphas)
 	*/
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY)
 	for (i=0; i<NUM_RX_DESC; i++) {
 	    lp->rx_ring[i].status = 0;
 	    lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
@@ -1252,11 +1252,7 @@ #endif
 	    mii_get_phy(dev);
 	}
 
-#ifndef __sparc_v9__
 	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
-#else
-	printk("      and requires IRQ%x (provided by %s).\n", dev->irq,
-#endif
 	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
     }
 
@@ -3627,14 +3623,13 @@ de4x5_alloc_rx_buff(struct net_device *d
     struct de4x5_private *lp = netdev_priv(dev);
     struct sk_buff *p;
 
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(CONFIG_SPARC) && !defined(DE4X5_DO_MEMCPY)
     struct sk_buff *ret;
     u_long i=0, tmp;
 
     p = dev_alloc_skb(IEEE802_3_SZ + DE4X5_ALIGN + 2);
     if (!p) return NULL;
 
-    p->dev = dev;
     tmp = virt_to_bus(p->data);
     i = ((tmp + DE4X5_ALIGN) & ~DE4X5_ALIGN) - tmp;
     skb_reserve(p, i);
@@ -3655,7 +3650,6 @@ #else
     p = dev_alloc_skb(len + 2);
     if (!p) return NULL;
 
-    p->dev = dev;
     skb_reserve(p, 2);	                               /* Align */
     if (index < lp->rx_old) {                          /* Wrapped buffer */
 	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 9aeac76..4ed67ff 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -55,9 +55,6 @@
 
     TODO
 
-    Implement pci_driver::suspend() and pci_driver::resume()
-    power management methods.
-
     Check on 64 bit boxes.
     Check and fix on big endian boxes.
 
@@ -125,6 +122,11 @@ #define MAX_CHECK_PACKET 0x8000
 #define DM9801_NOISE_FLOOR 8
 #define DM9802_NOISE_FLOOR 5
 
+#define DMFE_WOL_LINKCHANGE	0x20000000
+#define DMFE_WOL_SAMPLEPACKET	0x10000000
+#define DMFE_WOL_MAGICPACKET	0x08000000
+
+
 #define DMFE_10MHF      0
 #define DMFE_100MHF     1
 #define DMFE_10MFD      4
@@ -251,6 +253,7 @@ struct dmfe_board_info {
 	u8 wait_reset;			/* Hardware failed, need to reset */
 	u8 dm910x_chk_mode;		/* Operating mode check */
 	u8 first_in_callback;		/* Flag to record state */
+	u8 wol_mode;			/* user WOL settings */
 	struct timer_list timer;
 
 	/* System defined statistic counter */
@@ -431,6 +434,7 @@ #endif
 	db->chip_id = ent->driver_data;
 	db->ioaddr = pci_resource_start(pdev, 0);
 	db->chip_revision = dev_rev;
+	db->wol_mode = 0;
 
 	db->pdev = pdev;
 
@@ -682,7 +686,7 @@ static int dmfe_start_xmit(struct sk_buf
 
 	/* transmit this packet */
 	txptr = db->tx_insert_ptr;
-	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len);
 	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
 
 	/* Point to next transmit free descriptor */
@@ -988,14 +992,14 @@ static void dmfe_rx_packet(struct DEVICE
 
 						skb = newskb;
 						/* size less than COPY_SIZE, allocate a rxlen SKB */
-						skb->dev = dev;
 						skb_reserve(skb, 2); /* 16byte align */
-						memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen);
+						skb_copy_from_linear_data(rxptr->rx_skb_ptr,
+							  skb_put(skb, rxlen),
+									  rxlen);
 						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
-					} else {
-						skb->dev = dev;
+					} else
 						skb_put(skb, rxlen);
-					}
+
 					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
 					dev->last_rx = jiffies;
@@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct 
 	spin_unlock_irqrestore(&db->lock, flags);
 }
 
-static void netdev_get_drvinfo(struct net_device *dev,
+/*
+ * 	Ethtool interace
+ */
+
+static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
 			       struct ethtool_drvinfo *info)
 {
 	struct dmfe_board_info *np = netdev_priv(dev);
@@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct ne
 			dev->base_addr, dev->irq);
 }
 
+static int dmfe_ethtool_set_wol(struct net_device *dev,
+				struct ethtool_wolinfo *wolinfo)
+{
+	struct dmfe_board_info *db = netdev_priv(dev);
+
+	if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+		   		WAKE_ARP | WAKE_MAGICSECURE))
+		   return -EOPNOTSUPP;
+
+	db->wol_mode = wolinfo->wolopts;
+	return 0;
+}
+
+static void dmfe_ethtool_get_wol(struct net_device *dev,
+				 struct ethtool_wolinfo *wolinfo)
+{
+	struct dmfe_board_info *db = netdev_priv(dev);
+
+	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+	wolinfo->wolopts = db->wol_mode;
+	return;
+}
+
+
 static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
+	.get_drvinfo		= dmfe_ethtool_get_drvinfo,
 	.get_link               = ethtool_op_get_link,
+	.set_wol		= dmfe_ethtool_set_wol,
+	.get_wol		= dmfe_ethtool_get_wol,
 };
 
 /*
@@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl
 MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
 
 
+#ifdef CONFIG_PM
+static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pci_dev);
+	struct dmfe_board_info *db = netdev_priv(dev);
+	u32 tmp;
+
+	/* Disable upper layer interface */
+	netif_device_detach(dev);
+
+	/* Disable Tx/Rx */
+	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
+	update_cr6(db->cr6_data, dev->base_addr);
+
+	/* Disable Interrupt */
+	outl(0, dev->base_addr + DCR7);
+	outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+	/* Fre RX buffers */
+	dmfe_free_rxbuffer(db);
+
+	/* Enable WOL */
+	pci_read_config_dword(pci_dev, 0x40, &tmp);
+	tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET);
+
+	if (db->wol_mode & WAKE_PHY)
+		tmp |= DMFE_WOL_LINKCHANGE;
+	if (db->wol_mode & WAKE_MAGIC)
+		tmp |= DMFE_WOL_MAGICPACKET;
+
+	pci_write_config_dword(pci_dev, 0x40, tmp);
+
+	pci_enable_wake(pci_dev, PCI_D3hot, 1);
+	pci_enable_wake(pci_dev, PCI_D3cold, 1);
+
+	/* Power down device*/
+	pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state));
+	pci_save_state(pci_dev);
+
+	return 0;
+}
+
+static int dmfe_resume(struct pci_dev *pci_dev)
+{
+	struct net_device *dev = pci_get_drvdata(pci_dev);
+	u32 tmp;
+
+	pci_restore_state(pci_dev);
+	pci_set_power_state(pci_dev, PCI_D0);
+
+	/* Re-initilize DM910X board */
+	dmfe_init_dm910x(dev);
+
+	/* Disable WOL */
+	pci_read_config_dword(pci_dev, 0x40, &tmp);
+
+	tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET);
+	pci_write_config_dword(pci_dev, 0x40, tmp);
+
+	pci_enable_wake(pci_dev, PCI_D3hot, 0);
+	pci_enable_wake(pci_dev, PCI_D3cold, 0);
+
+	/* Restart upper layer interface */
+	netif_device_attach(dev);
+
+	return 0;
+}
+#else
+#define dmfe_suspend NULL
+#define dmfe_resume NULL
+#endif
+
 static struct pci_driver dmfe_driver = {
 	.name		= "dmfe",
 	.id_table	= dmfe_pci_tbl,
 	.probe		= dmfe_init_one,
 	.remove		= __devexit_p(dmfe_remove_one),
+	.suspend        = dmfe_suspend,
+	.resume         = dmfe_resume
 };
 
 MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index e3488d7..9b08afb 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -192,7 +192,6 @@ #endif
                                   to a minimally-sized skbuff. */
                                if (pkt_len < tulip_rx_copybreak
                                    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-                                       skb->dev = dev;
                                        skb_reserve(skb, 2);    /* 16 byte align the IP header */
                                        pci_dma_sync_single_for_cpu(tp->pdev,
 								   tp->rx_buffers[entry].mapping,
@@ -416,7 +415,6 @@ #endif
 			   to a minimally-sized skbuff. */
 			if (pkt_len < tulip_rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(tp->pdev,
 							    tp->rx_buffers[entry].mapping,
@@ -675,7 +673,7 @@ #endif
 				if (tp->link_change)
 					(tp->link_change)(dev, csr5);
 			}
-			if (csr5 & SytemError) {
+			if (csr5 & SystemError) {
 				int error = (csr5 >> 23) & 7;
 				/* oops, we hit a PCI error.  The code produced corresponds
 				 * to the reason:
@@ -745,7 +743,7 @@ #ifdef CONFIG_TULIP_NAPI
 			  TxFIFOUnderflow |
 			  TxJabber |
 			  TPLnkFail |
-			  SytemError )) != 0);
+			  SystemError )) != 0);
 #else
 	} while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
 
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 20bd52b..b562566 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 = 10;	/* max 1 ms */
 					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 = 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;
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index 85a521e..be82a2e 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -15,7 +15,6 @@
 */
 
 #include <linux/kernel.h>
-#include <linux/pci.h>
 #include <linux/jiffies.h>
 #include "tulip.h"
 
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index c31be0e..4e4a879 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -76,7 +76,6 @@
 
 
 
-#include <linux/pci.h>
 #include "tulip.h"
 #include <linux/delay.h>
 
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index df326fe..d2c1f42 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -14,7 +14,6 @@
 
 */
 
-#include <linux/pci.h>
 #include "tulip.h"
 
 
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 25f25da..16f26a8 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -22,6 +22,7 @@ #include <linux/spinlock.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
@@ -132,7 +133,7 @@ #define RxPollInt (RxIntr|RxNoBuf|RxDied
 /* The bits in the CSR5 status registers, mostly interrupt sources. */
 enum status_bits {
 	TimerInt = 0x800,
-	SytemError = 0x2000,
+	SystemError = 0x2000,
 	TPLnkFail = 0x1000,
 	TPLnkPass = 0x10,
 	NormalIntr = 0x10000,
@@ -482,8 +483,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));
 	}
 }
 
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index e3774a5..041af63 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -17,11 +17,11 @@
 
 #define DRV_NAME	"tulip"
 #ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION    "1.1.14-NAPI" /* Keep at least for test */
+#define DRV_VERSION    "1.1.15-NAPI" /* Keep at least for test */
 #else
-#define DRV_VERSION	"1.1.14"
+#define DRV_VERSION	"1.1.15"
 #endif
-#define DRV_RELDATE	"May 11, 2002"
+#define DRV_RELDATE	"Feb 27, 2007"
 
 
 #include <linux/module.h>
@@ -36,8 +36,8 @@ #include <linux/crc32.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
-#ifdef __sparc__
-#include <asm/pbm.h>
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
 #endif
 
 static char version[] __devinitdata =
@@ -67,7 +67,7 @@ const char * const medianame[32] = {
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
 #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-	|| defined(__sparc__) || defined(__ia64__) \
+	|| defined(CONFIG_SPARC) || defined(__ia64__) \
 	|| defined(__sh__) || defined(__mips__)
 static int rx_copybreak = 1518;
 #else
@@ -91,7 +91,7 @@ #if defined(__alpha__) || defined(__ia64
 static int csr0 = 0x01A00000 | 0xE000;
 #elif defined(__i386__) || defined(__powerpc__) || defined(__x86_64__)
 static int csr0 = 0x01A00000 | 0x8000;
-#elif defined(__sparc__) || defined(__hppa__)
+#elif defined(CONFIG_SPARC) || defined(__hppa__)
 /* The UltraSparc PCI controllers will disconnect at every 64-byte
  * crossing anyways so it makes no sense to tell Tulip to burst
  * any more than that.
@@ -1315,7 +1315,7 @@ #endif
 	/* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */
 	if (tulip_uli_dm_quirk(pdev)) {
 		csr0 &= ~0x01f100ff;
-#if defined(__sparc__)
+#if defined(CONFIG_SPARC)
                 csr0 = (csr0 & ~0xff00) | 0xe000;
 #endif
 	}
@@ -1535,23 +1535,19 @@ #endif
 	   Many PCI BIOSes also incorrectly report the IRQ line, so we correct
 	   that here as well. */
 	if (sum == 0  || sum == 6*0xff) {
-#if defined(__sparc__)
-		struct pcidev_cookie *pcp = pdev->sysdata;
+#if defined(CONFIG_SPARC)
+		struct device_node *dp = pci_device_to_OF_node(pdev);
+		const unsigned char *addr;
+		int len;
 #endif
 		eeprom_missing = 1;
 		for (i = 0; i < 5; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__sparc__)
-		if (pcp) {
-			unsigned char *addr;
-			int len;
-
-			addr = of_get_property(pcp->prom_node,
-					       "local-mac-address", &len);
-			if (addr && len == 6)
-				memcpy(dev->dev_addr, addr, 6);
-		}
+#if defined(CONFIG_SPARC)
+		addr = of_get_property(dp, "local-mac-address", &len);
+		if (addr && len == 6)
+			memcpy(dev->dev_addr, addr, 6);
 #endif
 #if defined(__i386__) || defined(__x86_64__)	/* Patch up x86 BIOS bug. */
 		if (last_irq)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 229158e..ca2548e 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -583,7 +583,7 @@ static int uli526x_start_xmit(struct sk_
 
 	/* transmit this packet */
 	txptr = db->tx_insert_ptr;
-	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len);
 	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
 
 	/* Point to next transmit free descriptor */
@@ -828,14 +828,14 @@ static void uli526x_rx_packet(struct net
 					( (skb = dev_alloc_skb(rxlen + 2) )
 					!= NULL) ) {
 					/* size less than COPY_SIZE, allocate a rxlen SKB */
-					skb->dev = dev;
 					skb_reserve(skb, 2); /* 16byte align */
-					memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
+					memcpy(skb_put(skb, rxlen),
+					       skb_tail_pointer(rxptr->rx_skb_ptr),
+					       rxlen);
 					uli526x_reuse_skb(db, rxptr->rx_skb_ptr);
-				} else {
-					skb->dev = dev;
+				} else
 					skb_put(skb, rxlen);
-				}
+
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
 				dev->last_rx = jiffies;
@@ -1177,7 +1177,10 @@ static void uli526x_reuse_skb(struct uli
 
 	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
 		rxptr->rx_skb_ptr = skb;
-		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		rxptr->rdes2 = cpu_to_le32(pci_map_single(db->pdev,
+							  skb_tail_pointer(skb),
+							  RX_ALLOC_SIZE,
+							  PCI_DMA_FROMDEVICE));
 		wmb();
 		rxptr->rdes0 = cpu_to_le32(0x80000000);
 		db->rx_avail_cnt++;
@@ -1341,7 +1344,10 @@ static void allocate_rx_buffer(struct ul
 		if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
 			break;
 		rxptr->rx_skb_ptr = skb; /* FIXME (?) */
-		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		rxptr->rdes2 = cpu_to_le32(pci_map_single(db->pdev,
+							  skb_tail_pointer(skb),
+							  RX_ALLOC_SIZE,
+							  PCI_DMA_FROMDEVICE));
 		wmb();
 		rxptr->rdes0 = cpu_to_le32(0x80000000);
 		rxptr = rxptr->next_rx_desc;
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 002a05e..fa44070 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -813,7 +813,6 @@ static void init_rxtx_rings(struct net_d
 		np->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
-		skb->dev = dev;			/* Mark as being used by this device. */
 		np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data,
 					np->rx_buf_sz,PCI_DMA_FROMDEVICE);
 
@@ -903,7 +902,7 @@ #if defined (__i386__) && !defined(MODUL
 	}
 #elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
 	i |= 0xE000;
-#elif defined(__sparc__) || defined (CONFIG_PARISC)
+#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC)
 	i |= 0x4800;
 #else
 #warning Processor architecture undefined
@@ -1148,7 +1147,7 @@ static irqreturn_t intr_handler(int irq,
 		}
 
 		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
+		if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError |
 						   TimerInt | TxDied))
 			netdev_error(dev, intr_status);
 
@@ -1229,7 +1228,6 @@ #endif
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
 							    np->rx_skbuff[entry]->len,
@@ -1278,7 +1276,6 @@ #endif
 			np->rx_skbuff[entry] = skb;
 			if (skb == NULL)
 				break;			/* Better luck next round. */
-			skb->dev = dev;			/* Mark as being used by this device. */
 			np->rx_addr[entry] = pci_map_single(np->pci_dev,
 							skb->data,
 							np->rx_buf_sz, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 61d3130..985a181 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -411,9 +411,9 @@ static int xircom_start_xmit(struct sk_b
 			   sometimes sends more than you ask it to. */
 
 			memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536);
-			memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len);
-
-
+			skb_copy_from_linear_data(skb,
+				  &(card->tx_buffer[bufferoffsets[desc] / 4]),
+						  skb->len);
 			/* FIXME: The specification tells us that the length we send HAS to be a multiple of
 			   4 bytes. */
 
@@ -1207,7 +1207,6 @@ static void investigate_read_descriptor(
 				card->stats.rx_dropped++;
 				goto out;
 			}
-			skb->dev = dev;
 			skb_reserve(skb, 2);
 			eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0);
 			skb_put(skb, pkt_len);
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index a998c5d..f641729 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -65,7 +65,7 @@ #if defined(__alpha__) || defined(__ia64
 static int csr0 = 0x01A00000 | 0xE000;
 #elif defined(__powerpc__)
 static int csr0 = 0x01B00000 | 0x8000;
-#elif defined(__sparc__)
+#elif defined(CONFIG_SPARC)
 static int csr0 = 0x01B00080 | 0x8000;
 #elif defined(__i386__)
 static int csr0 = 0x01A00000 | 0x8000;
@@ -915,7 +915,9 @@ xircom_start_xmit(struct sk_buff *skb, s
 
 	tp->tx_skbuff[entry] = skb;
 	if (tp->chip_id == X3201_3) {
-		memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
+		skb_copy_from_linear_data(skb,
+					  tp->tx_aligned_skbuff[entry]->data,
+					  skb->len);
 		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
 	} else
 		tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
@@ -1238,7 +1240,6 @@ #endif
 			   to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 #if ! defined(__alpha__)
 				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5643d1e..a2c6caa 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -18,6 +18,10 @@
 /*
  *  Changes:
  *
+ *  Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
+ *    Fixed hw address handling.  Now net_device.dev_addr is kept consistent
+ *    with tun.dev_addr when the address is set by this module.
+ *
  *  Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14
  *    Add TUNSETLINK ioctl to set the link encapsulation
  *
@@ -196,7 +200,10 @@ static void tun_net_init(struct net_devi
 		dev->set_multicast_list = tun_net_mclist;
 
 		ether_setup(dev);
-		random_ether_addr(dev->dev_addr);
+
+		/* random address already created for us by tun_set_iff, use it */
+		memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
+
 		dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
 		break;
 	}
@@ -254,11 +261,11 @@ static __inline__ ssize_t tun_get_user(s
 		return -EFAULT;
 	}
 
-	skb->dev = tun->dev;
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case TUN_TUN_DEV:
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 		skb->protocol = pi.proto;
+		skb->dev = tun->dev;
 		break;
 	case TUN_TAP_DEV:
 		skb->protocol = eth_type_trans(skb, tun->dev);
@@ -386,8 +393,8 @@ static ssize_t tun_chr_aio_read(struct k
 		 *   - we are multicast promiscous.
 		 *   - we belong to the multicast group.
 		 */
-		memcpy(addr, skb->data,
-		       min_t(size_t, sizeof addr, skb->len));
+		skb_copy_from_linear_data(skb, addr, min_t(size_t, sizeof addr,
+								   skb->len));
 		bit_nr = ether_crc(sizeof addr, addr) >> 26;
 		if ((tun->if_flags & IFF_PROMISC) ||
 				memcmp(addr, tun->dev_addr, sizeof addr) == 0 ||
@@ -636,6 +643,7 @@ #endif
 		return 0;
 
 	case SIOCGIFHWADDR:
+		/* Note: the actual net device's address may be different */
 		memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr,
 				min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
 		if (copy_to_user( argp, &ifr, sizeof ifr))
@@ -643,16 +651,24 @@ #endif
 		return 0;
 
 	case SIOCSIFHWADDR:
-		/** Set the character device's hardware address. This is used when
-		 * filtering packets being sent from the network device to the character
-		 * device. */
-		memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
-				min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
-		DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
-				tun->dev->name,
-				tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
-				tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
-		return 0;
+	{
+		/* try to set the actual net device's hw address */
+		int ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
+
+		if (ret == 0) {
+			/** Set the character device's hardware address. This is used when
+			 * filtering packets being sent from the network device to the character
+			 * device. */
+			memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
+					min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
+			DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
+					tun->dev->name,
+					tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
+					tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
+		}
+
+		return  ret;
+	}
 
 	case SIOCADDMULTI:
 		/** Add the specified group to the character device's multicast filter
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 0d91d09..f2dd776 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1708,7 +1708,6 @@ typhoon_rx(struct typhoon *tp, struct ba
 
 		if(pkt_len < rx_copybreak &&
 		   (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-			new_skb->dev = tp->dev;
 			skb_reserve(new_skb, 2);
 			pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
 						    PKT_BUF_SZ,
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 639e1e6..d7aff81 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -29,6 +29,7 @@ #include <linux/dma-mapping.h>
 #include <linux/fsl_devices.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/phy.h>
 #include <linux/workqueue.h>
 
 #include <asm/of_platform.h>
@@ -41,12 +42,13 @@ #include <asm/ucc.h>
 #include <asm/ucc_fast.h>
 
 #include "ucc_geth.h"
-#include "ucc_geth_phy.h"
+#include "ucc_geth_mii.h"
 
 #undef DEBUG
 
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
 #define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
 
 #define ugeth_printk(level, format, arg...)  \
         printk(level format "\n", ## arg)
@@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primar
 		    .bd_mem_part = MEM_PART_SYSTEM,
 		    .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
 		    .max_rx_buf_length = 1536,
-/* FIXME: should be changed in run time for 1G and 100M */
-#ifdef CONFIG_UGETH_HAS_GIGA
-		    .urfs = UCC_GETH_URFS_GIGA_INIT,
-		    .urfet = UCC_GETH_URFET_GIGA_INIT,
-		    .urfset = UCC_GETH_URFSET_GIGA_INIT,
-		    .utfs = UCC_GETH_UTFS_GIGA_INIT,
-		    .utfet = UCC_GETH_UTFET_GIGA_INIT,
-		    .utftt = UCC_GETH_UTFTT_GIGA_INIT,
-#else
+		    /* adjusted at startup if max-speed 1000 */
 		    .urfs = UCC_GETH_URFS_INIT,
 		    .urfet = UCC_GETH_URFET_INIT,
 		    .urfset = UCC_GETH_URFSET_INIT,
 		    .utfs = UCC_GETH_UTFS_INIT,
 		    .utfet = UCC_GETH_UTFET_INIT,
 		    .utftt = UCC_GETH_UTFTT_INIT,
-#endif
 		    .ufpt = 256,
 		    .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
 		    .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
@@ -217,70 +210,6 @@ static struct list_head *dequeue(struct 
 	}
 }
 
-static int get_interface_details(enum enet_interface enet_interface,
-				 enum enet_speed *speed,
-				 int *r10m,
-				 int *rmm,
-				 int *rpm,
-				 int *tbi, int *limited_to_full_duplex)
-{
-	/* Analyze enet_interface according to Interface Mode
-	Configuration table */
-	switch (enet_interface) {
-	case ENET_10_MII:
-		*speed = ENET_SPEED_10BT;
-		break;
-	case ENET_10_RMII:
-		*speed = ENET_SPEED_10BT;
-		*r10m = 1;
-		*rmm = 1;
-		break;
-	case ENET_10_RGMII:
-		*speed = ENET_SPEED_10BT;
-		*rpm = 1;
-		*r10m = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_100_MII:
-		*speed = ENET_SPEED_100BT;
-		break;
-	case ENET_100_RMII:
-		*speed = ENET_SPEED_100BT;
-		*rmm = 1;
-		break;
-	case ENET_100_RGMII:
-		*speed = ENET_SPEED_100BT;
-		*rpm = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_GMII:
-		*speed = ENET_SPEED_1000BT;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_RGMII:
-		*speed = ENET_SPEED_1000BT;
-		*rpm = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_TBI:
-		*speed = ENET_SPEED_1000BT;
-		*tbi = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	case ENET_1000_RTBI:
-		*speed = ENET_SPEED_1000BT;
-		*rpm = 1;
-		*tbi = 1;
-		*limited_to_full_duplex = 1;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-
-	return 0;
-}
-
 static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
 {
 	struct sk_buff *skb = NULL;
@@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_pr
 	ugeth_info("hafdup     : addr - 0x%08x, val - 0x%08x",
 		   (u32) & ugeth->ug_regs->hafdup,
 		   in_be32(&ugeth->ug_regs->hafdup));
-	ugeth_info("miimcfg    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcfg,
-		   in_be32(&ugeth->ug_regs->miimng.miimcfg));
-	ugeth_info("miimcom    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcom,
-		   in_be32(&ugeth->ug_regs->miimng.miimcom));
-	ugeth_info("miimadd    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimadd,
-		   in_be32(&ugeth->ug_regs->miimng.miimadd));
-	ugeth_info("miimcon    : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimcon,
-		   in_be32(&ugeth->ug_regs->miimng.miimcon));
-	ugeth_info("miimstat   : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimstat,
-		   in_be32(&ugeth->ug_regs->miimng.miimstat));
-	ugeth_info("miimmind   : addr - 0x%08x, val - 0x%08x",
-		   (u32) & ugeth->ug_regs->miimng.miimind,
-		   in_be32(&ugeth->ug_regs->miimng.miimind));
 	ugeth_info("ifctl      : addr - 0x%08x, val - 0x%08x",
 		   (u32) & ugeth->ug_regs->ifctl,
 		   in_be32(&ugeth->ug_regs->ifctl));
@@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8
 	return 0;
 }
 
-static int init_mac_duplex_mode(int full_duplex,
-				int limited_to_full_duplex,
-				volatile u32 *maccfg2_register)
-{
-	u32 value = 0;
-
-	/* some interfaces must work in full duplex mode */
-	if ((full_duplex == 0) && (limited_to_full_duplex == 1))
-		return -EINVAL;
-
-	value = in_be32(maccfg2_register);
-
-	if (full_duplex)
-		value |= MACCFG2_FDX;
-	else
-		value &= ~MACCFG2_FDX;
-
-	out_be32(maccfg2_register, value);
-	return 0;
-}
-
 static int init_check_frame_length_mode(int length_check,
 					volatile u32 *maccfg2_register)
 {
@@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 pream
 	return 0;
 }
 
-static int init_mii_management_configuration(int reset_mgmt,
-					     int preamble_supress,
-					     volatile u32 *miimcfg_register,
-					     volatile u32 *miimind_register)
-{
-	unsigned int timeout = PHY_INIT_TIMEOUT;
-	u32 value = 0;
-
-	value = in_be32(miimcfg_register);
-	if (reset_mgmt) {
-		value |= MIIMCFG_RESET_MANAGEMENT;
-		out_be32(miimcfg_register, value);
-	}
-
-	value = 0;
-
-	if (preamble_supress)
-		value |= MIIMCFG_NO_PREAMBLE;
-
-	value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
-	out_be32(miimcfg_register, value);
-
-	/* Wait until the bus is free */
-	while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
-		cpu_relax();
-
-	if (timeout <= 0) {
-		ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 static int init_rx_parameters(int reject_broadcast,
 			      int receive_short_frames,
 			      int promiscuous, volatile u32 *upsmr_register)
@@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct 
 	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;
+	int ret_val;
+	u32 upsmr, maccfg2, tbiBaseAddress;
 	u16 value;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct 
 	ug_regs = ugeth->ug_regs;
 	uf_regs = ugeth->uccf->uf_regs;
 
-	/* Analyze enet_interface according to Interface Mode Configuration
-	table */
-	ret_val =
-	    get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
-				  &rpm, &tbi, &limited_to_full_duplex);
-	if (ret_val != 0) {
-		ugeth_err
-		  ("%s: half duplex not supported in requested configuration.",
-		     __FUNCTION__);
-		return ret_val;
-	}
-
 	/*                    Set MACCFG2                    */
 	maccfg2 = in_be32(&ug_regs->maccfg2);
 	maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
-	if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+	if ((ugeth->max_speed == SPEED_10) ||
+	    (ugeth->max_speed == SPEED_100))
 		maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
-	else if (speed == ENET_SPEED_1000BT)
+	else if (ugeth->max_speed == SPEED_1000)
 		maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
 	maccfg2 |= ug_info->padAndCrc;
 	out_be32(&ug_regs->maccfg2, maccfg2);
@@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct 
 	/*                    Set UPSMR                      */
 	upsmr = in_be32(&uf_regs->upsmr);
 	upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
-	if (rpm)
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		upsmr |= UPSMR_RPM;
-	if (r10m)
-		upsmr |= UPSMR_R10M;
-	if (tbi)
+		switch (ugeth->max_speed) {
+		case SPEED_10:
+			upsmr |= UPSMR_R10M;
+			/* FALLTHROUGH */
+		case SPEED_100:
+			if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
+				upsmr |= UPSMR_RMM;
+		}
+	}
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		upsmr |= UPSMR_TBIM;
-	if (rmm)
-		upsmr |= UPSMR_RMM;
+	}
 	out_be32(&uf_regs->upsmr, upsmr);
 
-	/*                    Set UTBIPAR                    */
-	utbipar = in_be32(&ug_regs->utbipar);
-	utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
-	if (tbi)
-		utbipar |=
-		    (ug_info->phy_address +
-		     ugeth->ug_info->uf_info.
-		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-	else
-		utbipar |=
-		    (0x10 +
-		     ugeth->ug_info->uf_info.
-		     ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
-	out_be32(&ug_regs->utbipar, utbipar);
-
 	/* Disable autonegotiation in tbi mode, because by default it
 	comes up in autonegotiation mode. */
 	/* Note that this depends on proper setting in utbipar register. */
-	if (tbi) {
+	if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+	    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
 		tbiBaseAddress = in_be32(&ug_regs->utbipar);
 		tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
 		tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
-		value =
-		    ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
-					       ENET_TBI_MII_CR);
+		value = ugeth->phydev->bus->read(ugeth->phydev->bus,
+				(u8) tbiBaseAddress, ENET_TBI_MII_CR);
 		value &= ~0x1000;	/* Turn off autonegotiation */
-		ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
-					    ENET_TBI_MII_CR, value);
-	}
-
-	ret_val = init_mac_duplex_mode(1,
-				       limited_to_full_duplex,
-				       &ug_regs->maccfg2);
-	if (ret_val != 0) {
-		ugeth_err
-		("%s: half duplex not supported in requested configuration.",
-		     __FUNCTION__);
-		return ret_val;
+		ugeth->phydev->bus->write(ugeth->phydev->bus,
+				(u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
 	}
 
 	init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct 
  * function converts those variables into the appropriate
  * register values, and can bring down the device if needed.
  */
+
 static void adjust_link(struct net_device *dev)
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
 	struct ucc_geth *ug_regs;
-	u32 tempval;
-	struct ugeth_mii_info *mii_info = ugeth->mii_info;
+	struct ucc_fast *uf_regs;
+	struct phy_device *phydev = ugeth->phydev;
+	unsigned long flags;
+	int new_state = 0;
 
 	ug_regs = ugeth->ug_regs;
+	uf_regs = ugeth->uccf->uf_regs;
 
-	if (mii_info->link) {
+	spin_lock_irqsave(&ugeth->lock, flags);
+
+	if (phydev->link) {
+		u32 tempval = in_be32(&ug_regs->maccfg2);
+		u32 upsmr = in_be32(&uf_regs->upsmr);
 		/* Now we make sure that we can be in full duplex mode.
 		 * If not, we operate in half-duplex mode. */
-		if (mii_info->duplex != ugeth->oldduplex) {
-			if (!(mii_info->duplex)) {
-				tempval = in_be32(&ug_regs->maccfg2);
+		if (phydev->duplex != ugeth->oldduplex) {
+			new_state = 1;
+			if (!(phydev->duplex))
 				tempval &= ~(MACCFG2_FDX);
-				out_be32(&ug_regs->maccfg2, tempval);
-
-				ugeth_info("%s: Half Duplex", dev->name);
-			} else {
-				tempval = in_be32(&ug_regs->maccfg2);
+			else
 				tempval |= MACCFG2_FDX;
-				out_be32(&ug_regs->maccfg2, tempval);
-
-				ugeth_info("%s: Full Duplex", dev->name);
-			}
-
-			ugeth->oldduplex = mii_info->duplex;
+			ugeth->oldduplex = phydev->duplex;
 		}
 
-		if (mii_info->speed != ugeth->oldspeed) {
-			switch (mii_info->speed) {
-			case 1000:
-				ugeth->ug_info->enet_interface = ENET_1000_RGMII;
+		if (phydev->speed != ugeth->oldspeed) {
+			new_state = 1;
+			switch (phydev->speed) {
+			case SPEED_1000:
+				tempval = ((tempval &
+					    ~(MACCFG2_INTERFACE_MODE_MASK)) |
+					    MACCFG2_INTERFACE_MODE_BYTE);
 				break;
-			case 100:
-				ugeth->ug_info->enet_interface = ENET_100_RGMII;
-				break;
-			case 10:
-				ugeth->ug_info->enet_interface = ENET_10_RGMII;
+			case SPEED_100:
+			case SPEED_10:
+				tempval = ((tempval &
+					    ~(MACCFG2_INTERFACE_MODE_MASK)) |
+					    MACCFG2_INTERFACE_MODE_NIBBLE);
+				/* if reduced mode, re-set UPSMR.R10M */
+				if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+				    (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+					if (phydev->speed == SPEED_10)
+						upsmr |= UPSMR_R10M;
+					else
+						upsmr &= ~(UPSMR_R10M);
+				}
 				break;
 			default:
-				ugeth_warn
-				    ("%s: Ack!  Speed (%d) is not 10/100/1000!",
-				     dev->name, mii_info->speed);
+				if (netif_msg_link(ugeth))
+					ugeth_warn(
+						"%s: Ack!  Speed (%d) is not 10/100/1000!",
+						dev->name, phydev->speed);
 				break;
 			}
-			adjust_enet_interface(ugeth);
-
-			ugeth_info("%s: Speed %dBT", dev->name,
-				   mii_info->speed);
-
-			ugeth->oldspeed = mii_info->speed;
+			ugeth->oldspeed = phydev->speed;
 		}
 
+		out_be32(&ug_regs->maccfg2, tempval);
+		out_be32(&uf_regs->upsmr, upsmr);
+
 		if (!ugeth->oldlink) {
-			ugeth_info("%s: Link is up", dev->name);
+			new_state = 1;
 			ugeth->oldlink = 1;
-			netif_carrier_on(dev);
 			netif_schedule(dev);
 		}
-	} else {
-		if (ugeth->oldlink) {
-			ugeth_info("%s: Link is down", dev->name);
+	} else if (ugeth->oldlink) {
+			new_state = 1;
 			ugeth->oldlink = 0;
 			ugeth->oldspeed = 0;
 			ugeth->oldduplex = -1;
-			netif_carrier_off(dev);
-		}
 	}
+
+	if (new_state && netif_msg_link(ugeth))
+		phy_print_status(phydev);
+
+	spin_unlock_irqrestore(&ugeth->lock, flags);
 }
 
 /* Configure the PHY for dev.
@@ -1753,102 +1593,40 @@ static void adjust_link(struct net_devic
  */
 static int init_phy(struct net_device *dev)
 {
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-	struct phy_info *curphy;
-	struct ucc_mii_mng *mii_regs;
-	struct ugeth_mii_info *mii_info;
-	int err;
+	struct ucc_geth_private *priv = netdev_priv(dev);
+	struct phy_device *phydev;
+	char phy_id[BUS_ID_SIZE];
 
-	mii_regs = &ugeth->ug_regs->miimng;
+	priv->oldlink = 0;
+	priv->oldspeed = 0;
+	priv->oldduplex = -1;
 
-	ugeth->oldlink = 0;
-	ugeth->oldspeed = 0;
-	ugeth->oldduplex = -1;
+	snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
+			priv->ug_info->phy_address);
 
-	mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+	phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
 
-	if (NULL == mii_info) {
-		ugeth_err("%s: Could not allocate mii_info", dev->name);
-		return -ENOMEM;
+	if (IS_ERR(phydev)) {
+		printk("%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
 	}
 
-	mii_info->mii_regs = mii_regs;
-	mii_info->speed = SPEED_1000;
-	mii_info->duplex = DUPLEX_FULL;
-	mii_info->pause = 0;
-	mii_info->link = 0;
-
-	mii_info->advertising = (ADVERTISED_10baseT_Half |
+	phydev->supported &= (ADVERTISED_10baseT_Half |
 				 ADVERTISED_10baseT_Full |
 				 ADVERTISED_100baseT_Half |
-				 ADVERTISED_100baseT_Full |
-				 ADVERTISED_1000baseT_Full);
-	mii_info->autoneg = 1;
+				 ADVERTISED_100baseT_Full);
 
-	mii_info->mii_id = ugeth->ug_info->phy_address;
+	if (priv->max_speed == SPEED_1000)
+		phydev->supported |= ADVERTISED_1000baseT_Full;
 
-	mii_info->dev = dev;
+	phydev->advertising = phydev->supported;
 
-	mii_info->mdio_read = &read_phy_reg;
-	mii_info->mdio_write = &write_phy_reg;
-
-	spin_lock_init(&mii_info->mdio_lock);
-
-	ugeth->mii_info = mii_info;
-
-	spin_lock_irq(&ugeth->lock);
-
-	/* Set this UCC to be the master of the MII managment */
-	ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
-	if (init_mii_management_configuration(1,
-					      ugeth->ug_info->
-					      miiPreambleSupress,
-					      &mii_regs->miimcfg,
-					      &mii_regs->miimind)) {
-		ugeth_err("%s: The MII Bus is stuck!", dev->name);
-		err = -1;
-		goto bus_fail;
-	}
-
-	spin_unlock_irq(&ugeth->lock);
-
-	/* get info for this PHY */
-	curphy = get_phy_info(ugeth->mii_info);
-
-	if (curphy == NULL) {
-		ugeth_err("%s: No PHY found", dev->name);
-		err = -1;
-		goto no_phy;
-	}
-
-	mii_info->phyinfo = curphy;
-
-	/* Run the commands which initialize the PHY */
-	if (curphy->init) {
-		err = curphy->init(ugeth->mii_info);
-		if (err)
-			goto phy_init_fail;
-	}
+	priv->phydev = phydev;
 
 	return 0;
-
-      phy_init_fail:
-      no_phy:
-      bus_fail:
-	kfree(mii_info);
-
-	return err;
 }
 
-#ifdef CONFIG_UGETH_TX_ON_DEMOND
-static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
-{
-	struct ucc_fastransmit_on_demand(ugeth->uccf);
 
-	return 0;
-}
-#endif
 
 static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
 {
@@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc
 	}
 	for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
 		bd = ugeth->p_tx_bd_ring[i];
+		if (!bd)
+			continue;
 		for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
 			if (ugeth->tx_skbuff[i][j]) {
 				dma_unmap_single(NULL,
@@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct ne
 static void ucc_geth_stop(struct ucc_geth_private *ugeth)
 {
 	struct ucc_geth *ug_regs = ugeth->ug_regs;
+	struct phy_device *phydev = ugeth->phydev;
 	u32 tempval;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_get
 	ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
 
 	/* Tell the kernel the link is down */
-	ugeth->mii_info->link = 0;
-	adjust_link(ugeth->dev);
+	phy_stop(phydev);
 
 	/* Mask all interrupts */
 	out_be32(ugeth->uccf->p_ucce, 0x00000000);
@@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_get
 	tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
 	out_be32(&ug_regs->maccfg1, tempval);
 
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		/* Clear any pending interrupts */
-		mii_clear_phy_interrupt(ugeth->mii_info);
-
-		/* Disable PHY Interrupts */
-		mii_configure_phy_interrupt(ugeth->mii_info,
-					    MII_INTERRUPT_DISABLED);
-	}
-
 	free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
 
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
-	} else {
-		del_timer_sync(&ugeth->phy_info_timer);
-	}
-
 	ucc_geth_memclean(ugeth);
 }
 
-static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+static int ucc_struct_init(struct ucc_geth_private *ugeth)
 {
-	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;
-	u32 ifstat, i, j, size, l2qt, l3qt, length;
-	u16 temoder = UCC_GETH_TEMODER_INIT;
-	u16 test;
-	u8 function_code = 0;
-	u8 *bd, *endOfRing;
-	u8 numThreadsRxNumerical, numThreadsTxNumerical;
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
+	int i;
 
 	ug_info = ugeth->ug_info;
 	uf_info = &ug_info->uf_info;
 
+	/* Create CQs for hash tables */
+	INIT_LIST_HEAD(&ugeth->group_hash_q);
+	INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
 	if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
 	      (uf_info->bd_mem_part == MEM_PART_MURAM))) {
 		ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
@@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_g
 	for (i = 0; i < ug_info->numQueuesTx; i++)
 		uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
 	/* Initialize the general fast UCC block. */
-	if (ucc_fast_init(uf_info, &uccf)) {
+	if (ucc_fast_init(uf_info, &ugeth->uccf)) {
 		ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
-	ugeth->uccf = uccf;
+
+	ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+
+	return 0;
+}
+
+static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+{
+	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;
+	u32 ifstat, i, j, size, l2qt, l3qt, length;
+	u16 temoder = UCC_GETH_TEMODER_INIT;
+	u16 test;
+	u8 function_code = 0;
+	u8 *bd, *endOfRing;
+	u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+	ugeth_vdbg("%s: IN", __FUNCTION__);
+	uccf = ugeth->uccf;
+	ug_info = ugeth->ug_info;
+	uf_info = &ug_info->uf_info;
+	uf_regs = uccf->uf_regs;
+	ug_regs = ugeth->ug_regs;
 
 	switch (ug_info->numThreadsRx) {
 	case UCC_GETH_NUM_OF_THREADS_1:
@@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_g
 	    || (ug_info->vlanOperationNonTagged !=
 		UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
 
-	uf_regs = uccf->uf_regs;
-	ug_regs = (struct ucc_geth *) (uccf->uf_regs);
-	ugeth->ug_regs = ug_regs;
-
 	init_default_reg_vals(&uf_regs->upsmr,
 			      &ug_regs->maccfg1, &ug_regs->maccfg2);
 
@@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_g
 	/* Size varies with number of Rx queues */
 	ugeth->rx_irq_coalescing_tbl_offset =
 	    qe_muram_alloc(ug_info->numQueuesRx *
-			   sizeof(struct ucc_geth_rx_interrupt_coalescing_entry),
-			   UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+			   sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+			   + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
 	if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
 		ugeth_err
 		    ("%s: Can not allocate DPRAM memory for"
@@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_g
 		for (j = 0; j < NUM_OF_PADDRS; j++)
 			ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
 
-		/* Create CQs for hash tables */
-		if (ug_info->maxGroupAddrInHash > 0) {
-			INIT_LIST_HEAD(&ugeth->group_hash_q);
-		}
-		if (ug_info->maxIndAddrInHash > 0) {
-			INIT_LIST_HEAD(&ugeth->ind_hash_q);
-		}
 		p_82xx_addr_filt =
 		    (struct ucc_geth_82xx_address_filtering_pram *) ugeth->
 		    p_rx_glbl_pram->addressfiltering;
@@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_
 static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+	struct ucc_fast_private *uccf;
+#endif
 	u8 *bd;			/* BD pointer */
 	u32 bd_status;
 	u8 txQ = 0;
@@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk
 		out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
 	}
 
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+	uccf = ugeth->uccf;
+	out_be16(uccf->p_utodr, UCC_FAST_TOD);
+#endif
 	spin_unlock_irq(&ugeth->lock);
 
 	return 0;
@@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_p
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
-	spin_lock(&ugeth->lock);
 	/* collect received buffers */
 	bd = ugeth->rxBd[rxQ];
 
@@ -3683,7 +3462,6 @@ #endif				/* CONFIG_UGETH_NAPI */
 		skb = get_new_skb(ugeth, bd);
 		if (!skb) {
 			ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
-			spin_unlock(&ugeth->lock);
 			ugeth->stats.rx_dropped++;
 			break;
 		}
@@ -3704,7 +3482,6 @@ #endif				/* CONFIG_UGETH_NAPI */
 	}
 
 	ugeth->rxBd[rxQ] = bd;
-	spin_unlock(&ugeth->lock);
 	return howmany;
 }
 
@@ -3756,23 +3533,38 @@ #ifdef CONFIG_UGETH_NAPI
 static int ucc_geth_poll(struct net_device *dev, int *budget)
 {
 	struct ucc_geth_private *ugeth = netdev_priv(dev);
+	struct ucc_geth_info *ug_info;
+	struct ucc_fast_private *uccf;
 	int howmany;
-	int rx_work_limit = *budget;
-	u8 rxQ = 0;
+	u8 i;
+	int rx_work_limit;
+	register u32 uccm;
+
+	ug_info = ugeth->ug_info;
 
+	rx_work_limit = *budget;
 	if (rx_work_limit > dev->quota)
 		rx_work_limit = dev->quota;
 
-	howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+	howmany = 0;
+
+	for (i = 0; i < ug_info->numQueuesRx; i++) {
+		howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
+	}
 
 	dev->quota -= howmany;
 	rx_work_limit -= howmany;
 	*budget -= howmany;
 
-	if (rx_work_limit >= 0)
+	if (rx_work_limit > 0) {
 		netif_rx_complete(dev);
+		uccf = ugeth->uccf;
+		uccm = in_be32(uccf->p_uccm);
+		uccm |= UCCE_RX_EVENTS;
+		out_be32(uccf->p_uccm, uccm);
+	}
 
-	return (rx_work_limit < 0) ? 1 : 0;
+	return (rx_work_limit > 0) ? 0 : 1;
 }
 #endif				/* CONFIG_UGETH_NAPI */
 
@@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(
 	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;
-	register u8 i;
+	register u32 ucce;
+	register u32 uccm;
+#ifndef CONFIG_UGETH_NAPI
+	register u32 rx_mask;
+#endif
+	register u32 tx_mask;
+	u8 i;
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
@@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(
 	uccf = ugeth->uccf;
 	ug_info = ugeth->ug_info;
 
-	do {
-		ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm));
-
-		/* clear event bits for next time */
-		/* Side effect here is to mask ucce variable
-		for future processing below. */
-		out_be32(uccf->p_ucce, ucce);	/* Clear with ones,
-						but only bits in UCCM */
-
-		/* We ignore Tx interrupts because Tx confirmation is
-		done inside Tx routine */
+	/* read and clear events */
+	ucce = (u32) in_be32(uccf->p_ucce);
+	uccm = (u32) in_be32(uccf->p_uccm);
+	ucce &= uccm;
+	out_be32(uccf->p_ucce, ucce);
 
+	/* check for receive events that require processing */
+	if (ucce & UCCE_RX_EVENTS) {
+#ifdef CONFIG_UGETH_NAPI
+		if (netif_rx_schedule_prep(dev)) {
+		uccm &= ~UCCE_RX_EVENTS;
+			out_be32(uccf->p_uccm, uccm);
+			__netif_rx_schedule(dev);
+		}
+#else
+		rx_mask = UCCE_RXBF_SINGLE_MASK;
 		for (i = 0; i < ug_info->numQueuesRx; i++) {
-			if (ucce & bit_mask)
-				ucc_geth_rx(ugeth, i,
-					    (int)ugeth->ug_info->
-					    bdRingLenRx[i]);
-			ucce &= ~bit_mask;
-			bit_mask <<= 1;
+			if (ucce & rx_mask)
+				ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]);
+			ucce &= ~rx_mask;
+			rx_mask <<= 1;
 		}
+#endif /* CONFIG_UGETH_NAPI */
+	}
 
+	/* Tx event processing */
+	if (ucce & UCCE_TX_EVENTS) {
+		spin_lock(&ugeth->lock);
+		tx_mask = UCCE_TXBF_SINGLE_MASK;
 		for (i = 0; i < ug_info->numQueuesTx; i++) {
 			if (ucce & tx_mask)
 				ucc_geth_tx(dev, i);
 			ucce &= ~tx_mask;
 			tx_mask <<= 1;
 		}
+		spin_unlock(&ugeth->lock);
+	}
 
-		/* Exceptions */
+	/* Errors and other events */
+	if (ucce & UCCE_OTHER) {
 		if (ucce & UCCE_BSY) {
-			ugeth_vdbg("Got BUSY irq!!!!");
 			ugeth->stats.rx_errors++;
-			ucce &= ~UCCE_BSY;
 		}
-		if (ucce & UCCE_OTHER) {
-			ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!",
-				   ucce);
-			ugeth->stats.rx_errors++;
-			ucce &= ~ucce;
+		if (ucce & UCCE_TXE) {
+			ugeth->stats.tx_errors++;
 		}
 	}
-	while (ucce);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
-
-	/* Clear the interrupt */
-	mii_clear_phy_interrupt(ugeth->mii_info);
-
-	/* Disable PHY interrupts */
-	mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
-	/* Schedule the phy change */
-	schedule_work(&ugeth->tq);
 
 	return IRQ_HANDLED;
 }
 
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
-	struct ucc_geth_private *ugeth =
-		container_of(work, struct ucc_geth_private, tq);
-	struct net_device *dev = ugeth->dev;
-	struct ucc_geth *ug_regs;
-	int result = 0;
-
-	ugeth_vdbg("%s: IN", __FUNCTION__);
-
-	ug_regs = ugeth->ug_regs;
-
-	/* Delay to give the PHY a chance to change the
-	 * register state */
-	msleep(1);
-
-	/* Update the link, speed, duplex */
-	result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
-	/* Adjust the known status as long as the link
-	 * isn't still coming up */
-	if ((0 == result) || (ugeth->mii_info->link == 0))
-		adjust_link(dev);
-
-	/* Reenable interrupts, if needed */
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
-		mii_configure_phy_interrupt(ugeth->mii_info,
-					    MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	schedule_work(&ugeth->tq);
-
-	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
-	struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
-	struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
-	static int secondary = UGETH_AN_TIMEOUT;
-	int result;
-
-	/* Configure the Auto-negotiation */
-	result = mii_info->phyinfo->config_aneg(mii_info);
-
-	/* If autonegotiation failed to start, and
-	 * we haven't timed out, reset the timer, and return */
-	if (result && secondary--) {
-		mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
-		return;
-	} else if (result) {
-		/* Couldn't start autonegotiation.
-		 * Try switching to forced */
-		mii_info->autoneg = 0;
-		result = mii_info->phyinfo->config_aneg(mii_info);
-
-		/* Forcing failed!  Give up */
-		if (result) {
-			ugeth_err("%s: Forcing failed!", mii_info->dev->name);
-			return;
-		}
-	}
-
-	/* Kill the timer so it can be restarted */
-	del_timer_sync(&ugeth->phy_info_timer);
-
-	/* Grab the PHY interrupt, if necessary/possible */
-	if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
-		if (request_irq(ugeth->ug_info->phy_interrupt,
-				phy_interrupt, IRQF_SHARED,
-				"phy_interrupt", mii_info->dev) < 0) {
-			ugeth_err("%s: Can't get IRQ %d (PHY)",
-				  mii_info->dev->name,
-				  ugeth->ug_info->phy_interrupt);
-		} else {
-			mii_configure_phy_interrupt(ugeth->mii_info,
-						    MII_INTERRUPT_ENABLED);
-			return;
-		}
-	}
-
-	/* Start the timer again, this time in order to
-	 * handle a change in status */
-	init_timer(&ugeth->phy_info_timer);
-	ugeth->phy_info_timer.function = &ugeth_phy_timer;
-	ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
-	mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
 static int ucc_geth_open(struct net_device *dev)
@@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_devi
 		return -EINVAL;
 	}
 
+	err = ucc_struct_init(ugeth);
+	if (err) {
+		ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+		return err;
+	}
+
 	err = ucc_geth_startup(ugeth);
 	if (err) {
 		ugeth_err("%s: Cannot configure net device, aborting.",
@@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_devi
 
 	err = init_phy(dev);
 	if (err) {
-		ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+		ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
 		return err;
 	}
-#ifndef CONFIG_UGETH_NAPI
+
+	phy_start(ugeth->phydev);
+
 	err =
 	    request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
 			"UCC Geth", dev);
@@ -4019,15 +3705,6 @@ #ifndef CONFIG_UGETH_NAPI
 		ucc_geth_stop(ugeth);
 		return err;
 	}
-#endif				/* CONFIG_UGETH_NAPI */
-
-	/* Set up the PHY change work queue */
-	INIT_WORK(&ugeth->tq, ugeth_phy_change);
-
-	init_timer(&ugeth->phy_info_timer);
-	ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
-	ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
-	mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
 
 	err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
 	if (err) {
@@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_dev
 
 	ucc_geth_stop(ugeth);
 
-	/* Shutdown the PHY */
-	if (ugeth->mii_info->phyinfo->close)
-		ugeth->mii_info->phyinfo->close(ugeth->mii_info);
-
-	kfree(ugeth->mii_info);
+	phy_disconnect(ugeth->phydev);
+	ugeth->phydev = NULL;
 
 	netif_stop_queue(dev);
 
@@ -4063,33 +3737,67 @@ static int ucc_geth_close(struct net_dev
 
 const struct ethtool_ops ucc_geth_ethtool_ops = { };
 
+static phy_interface_t to_phy_interface(const char *interface_type)
+{
+	if (strcasecmp(interface_type, "mii") == 0)
+		return PHY_INTERFACE_MODE_MII;
+	if (strcasecmp(interface_type, "gmii") == 0)
+		return PHY_INTERFACE_MODE_GMII;
+	if (strcasecmp(interface_type, "tbi") == 0)
+		return PHY_INTERFACE_MODE_TBI;
+	if (strcasecmp(interface_type, "rmii") == 0)
+		return PHY_INTERFACE_MODE_RMII;
+	if (strcasecmp(interface_type, "rgmii") == 0)
+		return PHY_INTERFACE_MODE_RGMII;
+	if (strcasecmp(interface_type, "rgmii-id") == 0)
+		return PHY_INTERFACE_MODE_RGMII_ID;
+	if (strcasecmp(interface_type, "rtbi") == 0)
+		return PHY_INTERFACE_MODE_RTBI;
+
+	return PHY_INTERFACE_MODE_MII;
+}
+
 static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
 {
 	struct device *device = &ofdev->dev;
 	struct device_node *np = ofdev->node;
+	struct device_node *mdio;
 	struct net_device *dev = NULL;
 	struct ucc_geth_private *ugeth = NULL;
 	struct ucc_geth_info *ug_info;
 	struct resource res;
 	struct device_node *phy;
-	int err, ucc_num, phy_interface;
-	static int mii_mng_configured = 0;
+	int err, ucc_num, max_speed = 0;
 	const phandle *ph;
 	const unsigned int *prop;
 	const void *mac_addr;
+	phy_interface_t phy_interface;
+	static const int enet_to_speed[] = {
+		SPEED_10, SPEED_10, SPEED_10,
+		SPEED_100, SPEED_100, SPEED_100,
+		SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000,
+	};
+	static const phy_interface_t enet_to_phy_interface[] = {
+		PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII,
+		PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII,
+		PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
+		PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
+		PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+	};
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
-	prop = get_property(np, "device-id", NULL);
+	prop = of_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);
+
+	prop = of_get_property(np, "rx-clock", NULL);
 	ug_info->uf_info.rx_clock = *prop;
-	prop = get_property(np, "tx-clock", NULL);
+	prop = of_get_property(np, "tx-clock", NULL);
 	ug_info->uf_info.tx_clock = *prop;
 	err = of_address_to_resource(np, 0, &res);
 	if (err)
@@ -4098,19 +3806,78 @@ static int ucc_geth_probe(struct of_devi
 	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);
+	ph = of_get_property(np, "phy-handle", NULL);
 	phy = of_find_node_by_phandle(*ph);
 
 	if (phy == NULL)
 		return -ENODEV;
 
-	prop = get_property(phy, "reg", NULL);
+	/* set the PHY address */
+	prop = of_get_property(phy, "reg", NULL);
+	if (prop == NULL)
+		return -1;
 	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;
+
+	/* get the phy interface type, or default to MII */
+	prop = of_get_property(np, "interface-type", NULL);
+	if (!prop) {
+		/* handle interface property present in old trees */
+		prop = of_get_property(phy, "interface", NULL);
+		if (prop != NULL)
+			phy_interface = enet_to_phy_interface[*prop];
+		else
+			phy_interface = PHY_INTERFACE_MODE_MII;
+	} else {
+		phy_interface = to_phy_interface((const char *)prop);
+	}
+
+	/* get speed, or derive from interface */
+	prop = of_get_property(np, "max-speed", NULL);
+	if (!prop) {
+		/* handle interface property present in old trees */
+		prop = of_get_property(phy, "interface", NULL);
+		if (prop != NULL)
+			max_speed = enet_to_speed[*prop];
+	} else {
+		max_speed = *prop;
+	}
+	if (!max_speed) {
+		switch (phy_interface) {
+		case PHY_INTERFACE_MODE_GMII:
+		case PHY_INTERFACE_MODE_RGMII:
+		case PHY_INTERFACE_MODE_RGMII_ID:
+		case PHY_INTERFACE_MODE_TBI:
+		case PHY_INTERFACE_MODE_RTBI:
+			max_speed = SPEED_1000;
+			break;
+		default:
+			max_speed = SPEED_100;
+			break;
+		}
+	}
+
+	if (max_speed == SPEED_1000) {
+		ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
+		ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
+		ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
+		ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT;
+		ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
+		ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
+	}
+
+	/* Set the bus id */
+	mdio = of_get_parent(phy);
+
+	if (mdio == NULL)
+		return -1;
+
+	err = of_address_to_resource(mdio, 0, &res);
+	of_node_put(mdio);
+
+	if (err)
+		return -1;
+
+	ug_info->mdio_bus = res.start;
 
 	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,
@@ -4122,43 +3889,6 @@ static int ucc_geth_probe(struct of_devi
 		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(ucc_num);
-		mii_mng_configured = 1;
-	}
-
 	/* Create an ethernet device instance */
 	dev = alloc_etherdev(sizeof(*ugeth));
 
@@ -4192,6 +3922,10 @@ #endif				/* CONFIG_UGETH_NAPI */
 	dev->set_multicast_list = ucc_geth_set_multi;
 	dev->ethtool_ops = &ucc_geth_ethtool_ops;
 
+	ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+	ugeth->phy_interface = phy_interface;
+	ugeth->max_speed = max_speed;
+
 	err = register_netdev(dev);
 	if (err) {
 		ugeth_err("%s: Cannot register net device, aborting.",
@@ -4200,13 +3934,13 @@ #endif				/* CONFIG_UGETH_NAPI */
 		return err;
 	}
 
-	ugeth->ug_info = ug_info;
-	ugeth->dev = dev;
-
 	mac_addr = of_get_mac_address(np);
 	if (mac_addr)
 		memcpy(dev->dev_addr, mac_addr, 6);
 
+	ugeth->ug_info = ug_info;
+	ugeth->dev = dev;
+
 	return 0;
 }
 
@@ -4242,19 +3976,30 @@ static struct of_platform_driver ucc_get
 
 static int __init ucc_geth_init(void)
 {
-	int i;
+	int i, ret;
+
+	ret = uec_mdio_init();
+
+	if (ret)
+		return ret;
 
 	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 of_register_platform_driver(&ucc_geth_driver);
+	ret = of_register_platform_driver(&ucc_geth_driver);
+
+	if (ret)
+		uec_mdio_exit();
+
+	return ret;
 }
 
 static void __exit ucc_geth_exit(void)
 {
 	of_unregister_platform_driver(&ucc_geth_driver);
+	uec_mdio_exit();
 }
 
 module_init(ucc_geth_init);
@@ -4262,4 +4007,5 @@ module_exit(ucc_geth_exit);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index a665612..a29e1c3 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -28,6 +28,8 @@ #include <asm/qe.h>
 #include <asm/ucc.h>
 #include <asm/ucc_fast.h>
 
+#include "ucc_geth_mii.h"
+
 #define NUM_TX_QUEUES                   8
 #define NUM_RX_QUEUES                   8
 #define NUM_BDS_IN_PREFETCHED_BDS       4
@@ -36,15 +38,6 @@ #define NUM_OF_PADDRS                   
 #define ENET_INIT_PARAM_MAX_ENTRIES_RX  9
 #define ENET_INIT_PARAM_MAX_ENTRIES_TX  8
 
-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));
-
 struct ucc_geth {
 	struct ucc_fast uccf;
 
@@ -53,7 +46,7 @@ struct ucc_geth {
 	u32 ipgifg;		/* interframe gap reg.  */
 	u32 hafdup;		/* half-duplex reg.  */
 	u8 res1[0x10];
-	struct ucc_mii_mng miimng;	/* MII management structure */
+	u8 miimng[0x18];	/* MII management structure moved to _mii.h */
 	u32 ifctl;		/* interface control reg */
 	u32 ifstat;		/* interface statux reg */
 	u32 macstnaddr1;	/* mac station address part 1 reg */
@@ -212,6 +205,9 @@ #define UCCE_RXF         (UCCE_RXF7 | UC
 #define UCCE_OTHER       (UCCE_SCAR | UCCE_GRA  | UCCE_CBPR | UCCE_BSY  |\
 			UCCE_RXC  | UCCE_TXC  | UCCE_TXE)
 
+#define UCCE_RX_EVENTS							(UCCE_RXF | UCCE_BSY)
+#define UCCE_TX_EVENTS							(UCCE_TXB | UCCE_TXE)
+
 /* UCC GETH UPSMR (Protocol Specific Mode Register) */
 #define UPSMR_ECM                               0x04000000	/* Enable CAM
 								   Miss or
@@ -381,66 +377,6 @@ #define UCCS_PAU                        
 #define UCCS_MPD                                0x01	/* Magic Packet
 							   Detected */
 
-/* UCC GETH MIIMCFG (MII Management Configuration Register) */
-#define MIIMCFG_RESET_MANAGEMENT                0x80000000	/* Reset
-								   management */
-#define MIIMCFG_NO_PREAMBLE                     0x00000010	/* Preamble
-								   suppress */
-#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)	/* clock divide
-								   << shift */
-#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf	/* clock divide max val
-							 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000	/* divide by 2 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001	/* divide by 4 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002	/* divide by 6 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003	/* divide by 8 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004	/* divide by 10
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005	/* divide by 14
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008	/* divide by 16
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006	/* divide by 20
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007	/* divide by 28
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009	/* divide by 32
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a	/* divide by 48
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b	/* divide by 64
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c	/* divide by 80
-								 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d	/* divide by
-								   112 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e	/* divide by
-								   160 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f	/* divide by
-								   224 */
-
-/* UCC GETH MIIMCOM (MII Management Command Register) */
-#define MIIMCOM_SCAN_CYCLE                      0x00000002	/* Scan cycle */
-#define MIIMCOM_READ_CYCLE                      0x00000001	/* Read cycle */
-
-/* UCC GETH MIIMADD (MII Management Address Register) */
-#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)	/* PHY Address
-								   << shift */
-#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)	/* PHY Register
-								   << shift */
-
-/* UCC GETH MIIMCON (MII Management Control Register) */
-#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)	/* PHY Control
-								   << shift */
-#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)	/* PHY Status
-								   << shift */
-
-/* UCC GETH MIIMIND (MII Management Indicator Register) */
-#define MIIMIND_NOT_VALID                       0x00000004	/* Not valid */
-#define MIIMIND_SCAN                            0x00000002	/* Scan in
-								   progress */
-#define MIIMIND_BUSY                            0x00000001
-
 /* UCC GETH IFSTAT (Interface Status Register) */
 #define IFSTAT_EXCESS_DEFER                     0x00000200	/* Excessive
 								   transmission
@@ -931,8 +867,7 @@ #define UCC_GETH_SEND_QUEUE_QUEUE_DESCRI
 #define UCC_GETH_SCHEDULER_ALIGNMENT		4	/* This is a guess */
 #define UCC_GETH_TX_STATISTICS_ALIGNMENT	4	/* This is a guess */
 #define UCC_GETH_RX_STATISTICS_ALIGNMENT	4	/* This is a guess */
-#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT	4	/* This is a
-								   guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT	64
 #define UCC_GETH_RX_BD_QUEUES_ALIGNMENT		8	/* This is a guess */
 #define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT	128	/* This is a guess */
 #define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4	/* This
@@ -1009,15 +944,6 @@ #define UCC_GETH_UPSMR_INIT             
 								   register */
 #define UCC_GETH_MACCFG1_INIT                   0
 #define UCC_GETH_MACCFG2_INIT                   (MACCFG2_RESERVED_1)
-#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT    \
-				(MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
-
-/* Ethernet speed */
-enum enet_speed {
-	ENET_SPEED_10BT,	/* 10 Base T */
-	ENET_SPEED_100BT,	/* 100 Base T */
-	ENET_SPEED_1000BT	/* 1000 Base T */
-};
 
 /* Ethernet Address Type. */
 enum enet_addr_type {
@@ -1026,22 +952,6 @@ enum enet_addr_type {
 	ENET_ADDR_TYPE_BROADCAST
 };
 
-/* TBI / MII Set Register */
-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 ) */
-	ENET_TBI_MII_ANLPBPA = 0x05,	/* AN link partner base page ability
-					   (ANLPBPA) */
-	ENET_TBI_MII_ANEX = 0x06,	/* AN expansion (ANEX ) */
-	ENET_TBI_MII_ANNPT = 0x07,	/* AN next page transmit (ANNPT ) */
-	ENET_TBI_MII_ANLPANP = 0x08,	/* AN link partner ability next page
-					   (ANLPANP) */
-	ENET_TBI_MII_EXST = 0x0F,	/* Extended status (EXST ) */
-	ENET_TBI_MII_JD = 0x10,	/* Jitter diagnostics (JD ) */
-	ENET_TBI_MII_TBICON = 0x11	/* TBI control (TBICON ) */
-};
-
 /* UCC GETH 82xx Ethernet Address Recognition Location */
 enum ucc_geth_enet_address_recognition_location {
 	UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
@@ -1239,8 +1149,7 @@ struct ucc_geth_info {
 	u16 pausePeriod;
 	u16 extensionField;
 	u8 phy_address;
-	u32 board_flags;
-	u32 phy_interrupt;
+	u32 mdio_bus;
 	u8 weightfactor[NUM_TX_QUEUES];
 	u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
 	u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
@@ -1249,7 +1158,6 @@ struct ucc_geth_info {
 	u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
 	u16 bdRingLenTx[NUM_TX_QUEUES];
 	u16 bdRingLenRx[NUM_RX_QUEUES];
-	enum enet_interface enet_interface;
 	enum ucc_geth_num_of_station_addresses numStationAddresses;
 	enum qe_fltr_largest_external_tbl_lookup_key_size
 	    largestexternallookupkeysize;
@@ -1326,9 +1234,11 @@ struct ucc_geth_private {
 	/* index of the first skb which hasn't been transmitted yet. */
 	u16 skb_dirtytx[NUM_TX_QUEUES];
 
-	struct work_struct tq;
-	struct timer_list phy_info_timer;
 	struct ugeth_mii_info *mii_info;
+	struct phy_device *phydev;
+	phy_interface_t phy_interface;
+	int max_speed;
+	uint32_t msg_enable;
 	int oldspeed;
 	int oldduplex;
 	int oldlink;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
new file mode 100644
index 0000000..27a1ef3
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.c
@@ -0,0 +1,279 @@
+/*
+ * drivers/net/ucc_geth_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Li Yang
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/ocp.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ucc.h>
+
+#include "ucc_geth_mii.h"
+#include "ucc_geth.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg)
+#else
+#define vdbg(format, arg...) do {} while(0)
+#endif
+
+#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define DRV_NAME "fsl-uec_mdio"
+
+/* 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 master UEC MIIM regs */
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+
+	/* Setting up the MII Mangement Address Register */
+	out_be32(&regs->miimadd,
+		 (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+	/* Setting up the MII Mangement Control Register with the value */
+	out_be32(&regs->miimcon, value);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+		cpu_relax();
+
+	return 0;
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value.  Clears miimcom first.  All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+	u16 value;
+
+	/* Setting up the MII Mangement Address Register */
+	out_be32(&regs->miimadd,
+		 (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+	/* Clear miimcom, perform an MII management read cycle */
+	out_be32(&regs->miimcom, 0);
+	out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+	/* Wait till MII management write is complete */
+	while ((in_be32(&regs->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID))
+		cpu_relax();
+
+	/* Read MII management status  */
+	value = in_be32(&regs->miimstat);
+
+	return value;
+}
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int uec_mdio_reset(struct mii_bus *bus)
+{
+	struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+	unsigned int timeout = PHY_INIT_TIMEOUT;
+
+	spin_lock_bh(&bus->mdio_lock);
+
+	/* Reset the management interface */
+	out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
+
+	/* Setup the MII Mgmt clock speed */
+	out_be32(&regs->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112);
+
+	/* Wait until the bus is free */
+	while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
+		cpu_relax();
+
+	spin_unlock_bh(&bus->mdio_lock);
+
+	if (timeout <= 0) {
+		printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+	struct device *device = &ofdev->dev;
+	struct device_node *np = ofdev->node, *tempnp = NULL;
+	struct device_node *child = NULL;
+	struct ucc_mii_mng __iomem *regs;
+	struct mii_bus *new_bus;
+	struct resource res;
+	int k, err = 0;
+
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+	if (NULL == new_bus)
+		return -ENOMEM;
+
+	new_bus->name = "UCC Ethernet Controller MII Bus";
+	new_bus->read = &uec_mdio_read;
+	new_bus->write = &uec_mdio_write;
+	new_bus->reset = &uec_mdio_reset;
+
+	memset(&res, 0, sizeof(res));
+
+	err = of_address_to_resource(np, 0, &res);
+	if (err)
+		goto reg_map_fail;
+
+	new_bus->id = res.start;
+
+	new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL);
+
+	if (NULL == new_bus->irq) {
+		err = -ENOMEM;
+		goto reg_map_fail;
+	}
+
+	for (k = 0; k < 32; k++)
+		new_bus->irq[k] = PHY_POLL;
+
+	while ((child = of_get_next_child(np, child)) != NULL) {
+		int irq = irq_of_parse_and_map(child, 0);
+		if (irq != NO_IRQ) {
+			const u32 *id = of_get_property(child, "reg", NULL);
+			new_bus->irq[*id] = irq;
+		}
+	}
+
+	/* Set the base address */
+	regs = ioremap(res.start, sizeof(struct ucc_mii_mng));
+
+	if (NULL == regs) {
+		err = -ENOMEM;
+		goto ioremap_fail;
+	}
+
+	new_bus->priv = (void __force *)regs;
+
+	new_bus->dev = device;
+	dev_set_drvdata(device, new_bus);
+
+	/* Read MII management master from device tree */
+	while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth"))
+	       != NULL) {
+		struct resource tempres;
+
+		err = of_address_to_resource(tempnp, 0, &tempres);
+		if (err)
+			goto bus_register_fail;
+
+		/* if our mdio regs fall within this UCC regs range */
+		if ((res.start >= tempres.start) &&
+		    (res.end <= tempres.end)) {
+			/* set this UCC to be the MII master */
+			const u32 *id = of_get_property(tempnp, "device-id", NULL);
+			if (id == NULL)
+				goto bus_register_fail;
+
+			ucc_set_qe_mux_mii_mng(*id - 1);
+
+			/* assign the TBI an address which won't
+			 * conflict with the PHYs */
+			out_be32(&regs->utbipar, UTBIPAR_INIT_TBIPA);
+			break;
+		}
+	}
+
+	err = mdiobus_register(new_bus);
+	if (0 != err) {
+		printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
+		       new_bus->name);
+		goto bus_register_fail;
+	}
+
+	return 0;
+
+bus_register_fail:
+	iounmap(regs);
+ioremap_fail:
+	kfree(new_bus->irq);
+reg_map_fail:
+	kfree(new_bus);
+
+	return err;
+}
+
+int uec_mdio_remove(struct of_device *ofdev)
+{
+	struct device *device = &ofdev->dev;
+	struct mii_bus *bus = dev_get_drvdata(device);
+
+	mdiobus_unregister(bus);
+
+	dev_set_drvdata(device, NULL);
+
+	iounmap((void __iomem *)bus->priv);
+	bus->priv = NULL;
+	kfree(bus);
+
+	return 0;
+}
+
+static struct of_device_id uec_mdio_match[] = {
+	{
+		.type = "mdio",
+		.compatible = "ucc_geth_phy",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, uec_mdio_match);
+
+static struct of_platform_driver uec_mdio_driver = {
+	.name	= DRV_NAME,
+	.probe	= uec_mdio_probe,
+	.remove	= uec_mdio_remove,
+	.match_table	= uec_mdio_match,
+};
+
+int __init uec_mdio_init(void)
+{
+	return of_register_platform_driver(&uec_mdio_driver);
+}
+
+void __exit uec_mdio_exit(void)
+{
+	of_unregister_platform_driver(&uec_mdio_driver);
+}
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h
new file mode 100644
index 0000000..98430fe
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.h
@@ -0,0 +1,100 @@
+/*
+ * drivers/net/ucc_geth_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __UEC_MII_H
+#define __UEC_MII_H
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT                0x80000000	/* Reset
+								   management */
+#define MIIMCFG_NO_PREAMBLE                     0x00000010	/* Preamble
+								   suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT              (31 - 31)	/* clock divide
+								   << shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX                0xf	/* max clock divide */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2    0x00000000
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4    0x00000001
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6    0x00000002
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8    0x00000003
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10   0x00000004
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14   0x00000005
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16   0x00000008
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20   0x00000006
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28   0x00000007
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32   0x00000009
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48   0x0000000a
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64   0x0000000b
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80   0x0000000c
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112  0x0000000d
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160  0x0000000e
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224  0x0000000f
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE                      0x00000002	/* Scan cycle */
+#define MIIMCOM_READ_CYCLE                      0x00000001	/* Read cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT               (31 - 23)	/* PHY Address
+								   << shift */
+#define MIIMADD_PHY_REGISTER_SHIFT              (31 - 31)	/* PHY Register
+								   << shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT               (31 - 31)	/* PHY Control
+								   << shift */
+#define MIIMCON_PHY_STATUS_SHIFT                (31 - 31)	/* PHY Status
+								   << shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID                       0x00000004	/* Not valid */
+#define MIIMIND_SCAN                            0x00000002	/* Scan in
+								   progress */
+#define MIIMIND_BUSY                            0x00000001
+
+/* Initial TBI Physical Address */
+#define UTBIPAR_INIT_TBIPA			0x1f
+
+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 */
+	u8 notcare[28];		/* Space holder */
+	u32 utbipar;		/* TBI phy address reg */
+} __attribute__ ((packed));
+
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
+	ENET_TBI_MII_CR = 0x00,	/* Control */
+	ENET_TBI_MII_SR = 0x01,	/* Status */
+	ENET_TBI_MII_ANA = 0x04,	/* AN advertisement */
+	ENET_TBI_MII_ANLPBPA = 0x05,	/* AN link partner base page ability */
+	ENET_TBI_MII_ANEX = 0x06,	/* AN expansion */
+	ENET_TBI_MII_ANNPT = 0x07,	/* AN next page transmit */
+	ENET_TBI_MII_ANLPANP = 0x08,	/* AN link partner ability next page */
+	ENET_TBI_MII_EXST = 0x0F,	/* Extended status */
+	ENET_TBI_MII_JD = 0x10,	/* Jitter diagnostics */
+	ENET_TBI_MII_TBICON = 0x11	/* TBI control */
+};
+
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init uec_mdio_init(void);
+void __exit uec_mdio_exit(void);
+#endif				/* __UEC_MII_H */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
deleted file mode 100644
index 9373d89..0000000
--- a/drivers/net/ucc_geth_phy.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@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
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
-
-#define ugphy_printk(level, format, arg...)  \
-        printk(level format "\n", ## arg)
-
-#define ugphy_dbg(format, arg...)            \
-        ugphy_printk(KERN_DEBUG, format , ## arg)
-#define ugphy_err(format, arg...)            \
-        ugphy_printk(KERN_ERR, format , ## arg)
-#define ugphy_info(format, arg...)           \
-        ugphy_printk(KERN_INFO, format , ## arg)
-#define ugphy_warn(format, arg...)           \
-        ugphy_printk(KERN_WARNING, format , ## arg)
-
-#ifdef UGETH_VERBOSE_DEBUG
-#define ugphy_vdbg ugphy_dbg
-#else
-#define ugphy_vdbg(fmt, args...) do { } while (0)
-#endif				/* UGETH_VERBOSE_DEBUG */
-
-static void config_genmii_advert(struct ugeth_mii_info *mii_info);
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_update_link(struct ugeth_mii_info *mii_info);
-static int genmii_read_status(struct ugeth_mii_info *mii_info);
-
-static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
-{
-	u16 retval;
-	unsigned long flags;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	spin_lock_irqsave(&mii_info->mdio_lock, flags);
-	retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
-	spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
-	return retval;
-}
-
-static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
-{
-	unsigned long flags;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	spin_lock_irqsave(&mii_info->mdio_lock, flags);
-	mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
-	spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* 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)
-{
-	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__);
-
-	spin_lock_irq(&ugeth->lock);
-
-	mii_regs = ugeth->mii_info->mii_regs;
-
-	/* Set this UCC to be the master of the MII managment */
-	ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
-	/* Stop the MII management read cycle */
-	out_be32(&mii_regs->miimcom, 0);
-	/* Setting up the MII Mangement Address Register */
-	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
-	out_be32(&mii_regs->miimadd, tmp_reg);
-
-	/* Setting up the MII Mangement Control Register with the value */
-	out_be32(&mii_regs->miimcon, (u32) value);
-
-	/* Wait till MII management write is complete */
-	while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
-		cpu_relax();
-
-	spin_unlock_irq(&ugeth->lock);
-
-	udelay(10000);
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value.  Clears miimcom first.  All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int 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;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	spin_lock_irq(&ugeth->lock);
-
-	mii_regs = ugeth->mii_info->mii_regs;
-
-	/* Setting up the MII Mangement Address Register */
-	tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
-	out_be32(&mii_regs->miimadd, tmp_reg);
-
-	/* Perform an MII management read cycle */
-	out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
-
-	/* Wait till MII management write is complete */
-	while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
-		cpu_relax();
-
-	udelay(10000);
-
-	/* Read MII management status  */
-	value = (u16) in_be32(&mii_regs->miimstat);
-	out_be32(&mii_regs->miimcom, 0);
-	if (value == 0xffff)
-		ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
-			   mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
-
-	spin_unlock_irq(&ugeth->lock);
-
-	return (value);
-}
-
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->phyinfo->ack_interrupt)
-		mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
-				 u32 interrupts)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	mii_info->interrupts = interrupts;
-	if (mii_info->phyinfo->config_intr)
-		mii_info->phyinfo->config_intr(mii_info);
-}
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct ugeth_mii_info *mii_info)
-{
-	u32 advertise;
-	u16 adv;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Only allow advertising what this PHY supports */
-	mii_info->advertising &= mii_info->phyinfo->features;
-	advertise = mii_info->advertising;
-
-	/* Setup standard advertisement */
-	adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE);
-	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
-	if (advertise & ADVERTISED_10baseT_Half)
-		adv |= ADVERTISE_10HALF;
-	if (advertise & ADVERTISED_10baseT_Full)
-		adv |= ADVERTISE_10FULL;
-	if (advertise & ADVERTISED_100baseT_Half)
-		adv |= ADVERTISE_100HALF;
-	if (advertise & ADVERTISED_100baseT_Full)
-		adv |= ADVERTISE_100FULL;
-	ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
-{
-	u16 ctrl;
-	u32 features = mii_info->phyinfo->features;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	ctrl = ucc_geth_phy_read(mii_info, MII_BMCR);
-
-	ctrl &=
-	    ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
-	ctrl |= BMCR_RESET;
-
-	switch (mii_info->speed) {
-	case SPEED_1000:
-		if (features & (SUPPORTED_1000baseT_Half
-				| SUPPORTED_1000baseT_Full)) {
-			ctrl |= BMCR_SPEED1000;
-			break;
-		}
-		mii_info->speed = SPEED_100;
-	case SPEED_100:
-		if (features & (SUPPORTED_100baseT_Half
-				| SUPPORTED_100baseT_Full)) {
-			ctrl |= BMCR_SPEED100;
-			break;
-		}
-		mii_info->speed = SPEED_10;
-	case SPEED_10:
-		if (features & (SUPPORTED_10baseT_Half
-				| SUPPORTED_10baseT_Full))
-			break;
-	default:		/* Unsupported speed! */
-		ugphy_err("%s: Bad speed!", mii_info->dev->name);
-		break;
-	}
-
-	ucc_geth_phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
-{
-	u16 ctl;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	ctl = ucc_geth_phy_read(mii_info, MII_BMCR);
-	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-	ucc_geth_phy_write(mii_info, MII_BMCR, ctl);
-}
-
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
-{
-	u16 adv;
-	u32 advertise;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->autoneg) {
-		/* Configure the ADVERTISE register */
-		config_genmii_advert(mii_info);
-		advertise = mii_info->advertising;
-
-		adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL);
-		adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
-			 MII_1000BASETCONTROL_HALFDUPLEXCAP);
-		if (advertise & SUPPORTED_1000baseT_Half)
-			adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
-		if (advertise & SUPPORTED_1000baseT_Full)
-			adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-		ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
-		/* Start/Restart aneg */
-		genmii_restart_aneg(mii_info);
-	} else
-		genmii_setup_forced(mii_info);
-
-	return 0;
-}
-
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->autoneg) {
-		config_genmii_advert(mii_info);
-		genmii_restart_aneg(mii_info);
-	} else
-		genmii_setup_forced(mii_info);
-
-	return 0;
-}
-
-static int genmii_update_link(struct ugeth_mii_info *mii_info)
-{
-	u16 status;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Do a fake read */
-	ucc_geth_phy_read(mii_info, MII_BMSR);
-
-	/* Read link and autonegotiation status */
-	status = ucc_geth_phy_read(mii_info, MII_BMSR);
-	if ((status & BMSR_LSTATUS) == 0)
-		mii_info->link = 0;
-	else
-		mii_info->link = 1;
-
-	/* If we are autonegotiating, and not done,
-	 * return an error */
-	if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
-		return -EAGAIN;
-
-	return 0;
-}
-
-static int genmii_read_status(struct ugeth_mii_info *mii_info)
-{
-	u16 status;
-	int err;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Update the link, but return if there
-	 * was an error */
-	err = genmii_update_link(mii_info);
-	if (err)
-		return err;
-
-	if (mii_info->autoneg) {
-		status = ucc_geth_phy_read(mii_info, MII_LPA);
-
-		if (status & (LPA_10FULL | LPA_100FULL))
-			mii_info->duplex = DUPLEX_FULL;
-		else
-			mii_info->duplex = DUPLEX_HALF;
-		if (status & (LPA_100FULL | LPA_100HALF))
-			mii_info->speed = SPEED_100;
-		else
-			mii_info->speed = SPEED_10;
-		mii_info->pause = 0;
-	}
-	/* On non-aneg, we assume what we put in BMCR is the speed,
-	 * though magic-aneg shouldn't prevent this case from occurring
-	 */
-
-	return 0;
-}
-
-static int marvell_init(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
-	ucc_geth_phy_write(mii_info, 0x1b,
-		(ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
-	ucc_geth_phy_write(mii_info, MII_BMCR,
-		  ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-	msleep(4000);
-
-	return 0;
-}
-
-static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* The Marvell PHY has an errata which requires
-	 * that certain registers get written in order
-	 * to restart autonegotiation */
-	ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
-	ucc_geth_phy_write(mii_info, 0x1d, 0x1f);
-	ucc_geth_phy_write(mii_info, 0x1e, 0x200c);
-	ucc_geth_phy_write(mii_info, 0x1d, 0x5);
-	ucc_geth_phy_write(mii_info, 0x1e, 0);
-	ucc_geth_phy_write(mii_info, 0x1e, 0x100);
-
-	gbit_config_aneg(mii_info);
-
-	return 0;
-}
-
-static int marvell_read_status(struct ugeth_mii_info *mii_info)
-{
-	u16 status;
-	int err;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Update the link, but return if there
-	 * was an error */
-	err = genmii_update_link(mii_info);
-	if (err)
-		return err;
-
-	/* If the link is up, read the speed and duplex */
-	/* If we aren't autonegotiating, assume speeds
-	 * are as set */
-	if (mii_info->autoneg && mii_info->link) {
-		int speed;
-		status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
-		/* Get the duplexity */
-		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
-			mii_info->duplex = DUPLEX_FULL;
-		else
-			mii_info->duplex = DUPLEX_HALF;
-
-		/* Get the speed */
-		speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
-		switch (speed) {
-		case MII_M1011_PHY_SPEC_STATUS_1000:
-			mii_info->speed = SPEED_1000;
-			break;
-		case MII_M1011_PHY_SPEC_STATUS_100:
-			mii_info->speed = SPEED_100;
-			break;
-		default:
-			mii_info->speed = SPEED_10;
-			break;
-		}
-		mii_info->pause = 0;
-	}
-
-	return 0;
-}
-
-static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Clear the interrupts by reading the reg */
-	ucc_geth_phy_read(mii_info, MII_M1011_IEVENT);
-
-	return 0;
-}
-
-static int marvell_config_intr(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-		ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
-	else
-		ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
-	return 0;
-}
-
-static int cis820x_init(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
-		  MII_CIS8201_AUXCONSTAT_INIT);
-	ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
-
-	return 0;
-}
-
-static int cis820x_read_status(struct ugeth_mii_info *mii_info)
-{
-	u16 status;
-	int err;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Update the link, but return if there
-	 * was an error */
-	err = genmii_update_link(mii_info);
-	if (err)
-		return err;
-
-	/* If the link is up, read the speed and duplex */
-	/* If we aren't autonegotiating, assume speeds
-	 * are as set */
-	if (mii_info->autoneg && mii_info->link) {
-		int speed;
-
-		status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
-		if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
-			mii_info->duplex = DUPLEX_FULL;
-		else
-			mii_info->duplex = DUPLEX_HALF;
-
-		speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
-		switch (speed) {
-		case MII_CIS8201_AUXCONSTAT_GBIT:
-			mii_info->speed = SPEED_1000;
-			break;
-		case MII_CIS8201_AUXCONSTAT_100:
-			mii_info->speed = SPEED_100;
-			break;
-		default:
-			mii_info->speed = SPEED_10;
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT);
-
-	return 0;
-}
-
-static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-		ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
-	else
-		ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
-	return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct ugeth_mii_info *mii_info)
-{
-	u16 status;
-	int err;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Update the link, but return if there
-	 * was an error */
-	err = genmii_update_link(mii_info);
-	if (err)
-		return err;
-
-	/* If the link is up, read the speed and duplex */
-	/* If we aren't autonegotiating, assume speeds
-	 * are as set */
-	if (mii_info->autoneg && mii_info->link) {
-		status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR);
-		if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
-			mii_info->speed = SPEED_100;
-		else
-			mii_info->speed = SPEED_10;
-
-		if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
-			mii_info->duplex = DUPLEX_FULL;
-		else
-			mii_info->duplex = DUPLEX_HALF;
-	}
-
-	return 0;
-}
-
-static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
-{
-	struct dm9161_private *priv = mii_info->priv;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (0 == priv->resetdone)
-		return -EAGAIN;
-
-	return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
-	struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
-	struct dm9161_private *priv = mii_info->priv;
-	u16 status = ucc_geth_phy_read(mii_info, MII_BMSR);
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (status & BMSR_ANEGCOMPLETE) {
-		priv->resetdone = 1;
-	} else
-		mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct ugeth_mii_info *mii_info)
-{
-	struct dm9161_private *priv;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Allocate the private data structure */
-	priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
-	if (NULL == priv)
-		return -ENOMEM;
-
-	mii_info->priv = priv;
-
-	/* Reset is not done yet */
-	priv->resetdone = 0;
-
-	ucc_geth_phy_write(mii_info, MII_BMCR,
-		  ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-
-	ucc_geth_phy_write(mii_info, MII_BMCR,
-		  ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
-
-	config_genmii_advert(mii_info);
-	/* Start/Restart aneg */
-	genmii_config_aneg(mii_info);
-
-	/* Start a timer for DM9161_DELAY seconds to wait
-	 * for the PHY to be ready */
-	init_timer(&priv->timer);
-	priv->timer.function = &dm9161_timer;
-	priv->timer.data = (unsigned long)mii_info;
-	mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
-	return 0;
-}
-
-static void dm9161_close(struct ugeth_mii_info *mii_info)
-{
-	struct dm9161_private *priv = mii_info->priv;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	del_timer_sync(&priv->timer);
-	kfree(priv);
-}
-
-static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Clear the interrupts by reading the reg */
-	ucc_geth_phy_read(mii_info, MII_DM9161_INTR);
-
-
-	return 0;
-}
-
-static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
-{
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
-		ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
-	else
-		ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
-
-	return 0;
-}
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
-	.phy_id = 0x000fc440,
-	.name = "Cicada Cis8204",
-	.phy_id_mask = 0x000fffc0,
-	.features = MII_GBIT_FEATURES,
-	.init = &cis820x_init,
-	.config_aneg = &gbit_config_aneg,
-	.read_status = &cis820x_read_status,
-	.ack_interrupt = &cis820x_ack_interrupt,
-	.config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
-	.phy_id = 0x0181b880,
-	.phy_id_mask = 0x0ffffff0,
-	.name = "Davicom DM9161E",
-	.init = dm9161_init,
-	.config_aneg = dm9161_config_aneg,
-	.read_status = dm9161_read_status,
-	.close = dm9161_close,
-};
-
-static struct phy_info phy_info_dm9161a = {
-	.phy_id = 0x0181b8a0,
-	.phy_id_mask = 0x0ffffff0,
-	.name = "Davicom DM9161A",
-	.features = MII_BASIC_FEATURES,
-	.init = dm9161_init,
-	.config_aneg = dm9161_config_aneg,
-	.read_status = dm9161_read_status,
-	.ack_interrupt = dm9161_ack_interrupt,
-	.config_intr = dm9161_config_intr,
-	.close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
-	.phy_id = 0x01410c00,
-	.phy_id_mask = 0xffffff00,
-	.name = "Marvell 88E11x1",
-	.features = MII_GBIT_FEATURES,
-	.init = &marvell_init,
-	.config_aneg = &marvell_config_aneg,
-	.read_status = &marvell_read_status,
-	.ack_interrupt = &marvell_ack_interrupt,
-	.config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii = {
-	.phy_id = 0x00000000,
-	.phy_id_mask = 0x00000000,
-	.name = "Generic MII",
-	.features = MII_BASIC_FEATURES,
-	.config_aneg = genmii_config_aneg,
-	.read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
-	&phy_info_cis820x,
-	&phy_info_marvell,
-	&phy_info_dm9161,
-	&phy_info_dm9161a,
-	&phy_info_genmii,
-	NULL
-};
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev.  return a struct phy_info structure describing that PHY
- */
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
-{
-	u16 phy_reg;
-	u32 phy_ID;
-	int i;
-	struct phy_info *theInfo = NULL;
-	struct net_device *dev = mii_info->dev;
-
-	ugphy_vdbg("%s: IN", __FUNCTION__);
-
-	/* Grab the bits from PHYIR1, and put them in the upper half */
-	phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1);
-	phy_ID = (phy_reg & 0xffff) << 16;
-
-	/* Grab the bits from PHYIR2, and put them in the lower half */
-	phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2);
-	phy_ID |= (phy_reg & 0xffff);
-
-	/* loop through all the known PHY types, and find one that */
-	/* matches the ID we read from the PHY. */
-	for (i = 0; phy_info[i]; i++)
-		if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
-			theInfo = phy_info[i];
-			break;
-		}
-
-	/* This shouldn't happen, as we have generic PHY support */
-	if (theInfo == NULL) {
-		ugphy_info("%s: PHY id %x is not supported!", dev->name,
-			   phy_ID);
-		return NULL;
-	} else {
-		ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
-			   phy_ID);
-	}
-
-	return theInfo;
-}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
deleted file mode 100644
index f574078..0000000
--- a/drivers/net/ucc_geth_phy.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@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
- * option) any later version.
- *
- */
-#ifndef __UCC_GETH_PHY_H__
-#define __UCC_GETH_PHY_H__
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY            0x00000001
-#define MIIMIND_NOTVALID        0x00000004
-
-#define UGETH_AN_TIMEOUT        2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL                  0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP    0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP    0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1        0x17
-#define MII_CIS8201_EXTCON1_INIT    0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK           0x19
-#define MII_CIS8201_IMASK_IEN       0x8000
-#define MII_CIS8201_IMASK_SPEED     0x4000
-#define MII_CIS8201_IMASK_LINK      0x2000
-#define MII_CIS8201_IMASK_DUPLEX    0x1000
-#define MII_CIS8201_IMASK_MASK      0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT           0x1a
-#define MII_CIS8201_ISTAT_STATUS    0x8000
-#define MII_CIS8201_ISTAT_SPEED     0x4000
-#define MII_CIS8201_ISTAT_LINK      0x2000
-#define MII_CIS8201_ISTAT_DUPLEX    0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT        0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT    0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010
-#define MII_CIS8201_AUXCONSTAT_100     0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS               0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000          0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100           0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK      0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX    0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED      0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK          0x0400
-
-#define MII_M1011_IEVENT                0x13
-#define MII_M1011_IEVENT_CLEAR          0x0000
-
-#define MII_M1011_IMASK                 0x12
-#define MII_M1011_IMASK_INIT            0x6400
-#define MII_M1011_IMASK_CLEAR           0x0000
-
-#define MII_DM9161_SCR                  0x10
-#define MII_DM9161_SCR_INIT             0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR                 0x11
-#define MII_DM9161_SCSR_100F            0x8000
-#define MII_DM9161_SCSR_100H            0x4000
-#define MII_DM9161_SCSR_10F             0x2000
-#define MII_DM9161_SCSR_10H             0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR                 0x15
-#define MII_DM9161_INTR_PEND            0x8000
-#define MII_DM9161_INTR_DPLX_MASK       0x0800
-#define MII_DM9161_INTR_SPD_MASK        0x0400
-#define MII_DM9161_INTR_LINK_MASK       0x0200
-#define MII_DM9161_INTR_MASK            0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE     0x0010
-#define MII_DM9161_INTR_SPD_CHANGE      0x0008
-#define MII_DM9161_INTR_LINK_CHANGE     0x0004
-#define MII_DM9161_INTR_INIT            0x0000
-#define MII_DM9161_INTR_STOP    \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR              0x12
-#define MII_DM9161_10BTCSR_INIT         0x7800
-
-#define MII_BASIC_FEATURES    (SUPPORTED_10baseT_Half | \
-                 SUPPORTED_10baseT_Full | \
-                 SUPPORTED_100baseT_Half | \
-                 SUPPORTED_100baseT_Full | \
-                 SUPPORTED_Autoneg | \
-                 SUPPORTED_TP | \
-                 SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES    (MII_BASIC_FEATURES | \
-                 SUPPORTED_1000baseT_Half | \
-                 SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND                0x00000001
-
-#define MII_INTERRUPT_DISABLED          0x0
-#define MII_INTERRUPT_ENABLED           0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct ugeth_mii_info {
-	/* Information about the PHY type */
-	/* And management functions */
-	struct phy_info *phyinfo;
-
-	struct ucc_mii_mng *mii_regs;
-
-	/* forced speed & duplex (no autoneg)
-	 * partner speed & duplex & pause (autoneg)
-	 */
-	int speed;
-	int duplex;
-	int pause;
-
-	/* The most recently read link state */
-	int link;
-
-	/* Enabled Interrupts */
-	u32 interrupts;
-
-	u32 advertising;
-	int autoneg;
-	int mii_id;
-
-	/* private data pointer */
-	/* For use by PHYs to maintain extra state */
-	void *priv;
-
-	/* Provided by host chip */
-	struct net_device *dev;
-
-	/* A lock to ensure that only one thing can read/write
-	 * the MDIO bus at a time */
-	spinlock_t mdio_lock;
-
-	/* Provided by ethernet driver */
-	int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
-	void (*mdio_write) (struct net_device * dev, int mii_id, int reg,
-			    int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY.  During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is.  The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a ugeth_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
-	u32 phy_id;
-	char *name;
-	unsigned int phy_id_mask;
-	u32 features;
-
-	/* Called to initialize the PHY */
-	int (*init) (struct ugeth_mii_info * mii_info);
-
-	/* Called to suspend the PHY for power */
-	int (*suspend) (struct ugeth_mii_info * mii_info);
-
-	/* Reconfigures autonegotiation (or disables it) */
-	int (*config_aneg) (struct ugeth_mii_info * mii_info);
-
-	/* Determines the negotiated speed and duplex */
-	int (*read_status) (struct ugeth_mii_info * mii_info);
-
-	/* Clears any pending interrupts */
-	int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
-
-	/* Enables or disables interrupts */
-	int (*config_intr) (struct ugeth_mii_info * mii_info);
-
-	/* Clears up any memory if needed */
-	void (*close) (struct ugeth_mii_info * mii_info);
-};
-
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
-				 u32 interrupts);
-
-struct dm9161_private {
-	struct timer_list timer;
-	int resetdone;
-};
-
-#endif				/* __UCC_GETH_PHY_H__ */
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index f3a972e..adea290 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1486,7 +1486,6 @@ static int rhine_rx(struct net_device *d
 			   copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak &&
 				(skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				pci_dma_sync_single_for_cpu(rp->pdev,
 							    rp->rx_skbuff_dma[entry],
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 8e5d820..25b75b6 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1339,7 +1339,8 @@ static inline int velocity_rx_copy(struc
 			if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
 				skb_reserve(new_skb, 2);
 
-			memcpy(new_skb->data, rx_skb[0]->data, pkt_size);
+			skb_copy_from_linear_data(rx_skb[0], new_skb->data,
+						  pkt_size);
 			*rx_skb = new_skb;
 			ret = 0;
 		}
@@ -1398,7 +1399,6 @@ static int velocity_receive_frame(struct
 		vptr->stats.multicast++;
 
 	skb = rd_info->skb;
-	skb->dev = vptr->dev;
 
 	pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma,
 				    vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
@@ -1428,7 +1428,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, vptr->dev);
 
 	stats->rx_bytes += pkt_len;
 	netif_rx(skb);
@@ -1928,7 +1928,7 @@ #endif
 	if (pktlen < ETH_ZLEN) {
 		/* Cannot occur until ZC support */
 		pktlen = ETH_ZLEN;
-		memcpy(tdinfo->buf, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
 		memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
 		tdinfo->skb = skb;
 		tdinfo->skb_dma[0] = tdinfo->buf_dma;
@@ -1944,7 +1944,7 @@ #ifdef VELOCITY_ZERO_COPY_SUPPORT
 		int nfrags = skb_shinfo(skb)->nr_frags;
 		tdinfo->skb = skb;
 		if (nfrags > 6) {
-			memcpy(tdinfo->buf, skb->data, skb->len);
+			skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
 			tdinfo->skb_dma[0] = tdinfo->buf_dma;
 			td_ptr->tdesc0.pktsize =
 			td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
@@ -2007,7 +2007,7 @@ #endif
 	 */
 	if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
 				 && (skb->ip_summed == CHECKSUM_PARTIAL)) {
-		struct iphdr *ip = skb->nh.iph;
+		const struct iphdr *ip = ip_hdr(skb);
 		if (ip->protocol == IPPROTO_TCP)
 			td_ptr->tdesc1.TCR |= TCR0_TCPCK;
 		else if (ip->protocol == IPPROTO_UDP)
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 5b82e4f..9ef49ce 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -90,7 +90,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 
 #undef COSA_SLOW_IO	/* for testing purposes only */
@@ -773,7 +772,7 @@ static int sppp_rx_done(struct channel_d
 	}
 	chan->rx_skb->protocol = htons(ETH_P_WAN_PPP);
 	chan->rx_skb->dev = chan->pppdev.dev;
-	chan->rx_skb->mac.raw = chan->rx_skb->data;
+	skb_reset_mac_header(chan->rx_skb);
 	chan->stats.rx_packets++;
 	chan->stats.rx_bytes += chan->cosa->rxsize;
 	netif_rx(chan->rx_skb);
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index a631d1c..016b3ff 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -834,7 +834,7 @@ static void cycx_x25_irq_rx(struct cycx_
 	++chan->ifstats.rx_packets;
 	chan->ifstats.rx_bytes += pktlen;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	netif_rx(skb);
 	dev->last_rx = jiffies;		/* timestamp */
 }
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 7369875..66be20c 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -176,7 +176,7 @@ static void dlci_receive(struct sk_buff 
 	if (process)
 	{
 		/* we've set up the protocol, so discard the header */
-		skb->mac.raw = skb->data; 
+		skb_reset_mac_header(skb);
 		skb_pull(skb, header);
 		dlp->stats.rx_bytes += skb->len;
 		netif_rx(skb);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 25021a7..dca0244 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -1904,7 +1904,8 @@ static struct sk_buff *dscc4_init_dummy_
 		struct TxFD *tx_fd = dpriv->tx_fd + last;
 
 		skb->len = DUMMY_SKB_SIZE;
-		memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE);
+		skb_copy_to_linear_data(skb, version,
+					strlen(version) % DUMMY_SKB_SIZE);
 		tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE);
 		tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
 					     DUMMY_SKB_SIZE, PCI_DMA_TODEVICE);
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index c45d6a8..58a53b6 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -864,7 +864,7 @@ fst_tx_dma_complete(struct fst_card_info
 static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	skb->dev = dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_HOST;
 	return htons(ETH_P_CUST);
 }
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index c9664fd..9ec6cf2 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -37,16 +37,16 @@ #define CISCO_KEEPALIVE_REQ	2	/* Cisco k
 struct hdlc_header {
 	u8 address;
 	u8 control;
-	u16 protocol;
+	__be16 protocol;
 }__attribute__ ((packed));
 
 
 struct cisco_packet {
-	u32 type;		/* code */
-	u32 par1;
-	u32 par2;
-	u16 rel;		/* reliability */
-	u32 time;
+	__be32 type;		/* code */
+	__be32 par1;
+	__be32 par2;
+	__be16 rel;		/* reliability */
+	__be32 time;
 }__attribute__ ((packed));
 #define	CISCO_PACKET_LEN	18
 #define	CISCO_BIG_PACKET_LEN	20
@@ -97,7 +97,7 @@ #endif
 
 
 static void cisco_keepalive_send(struct net_device *dev, u32 type,
-				 u32 par1, u32 par2)
+				 __be32 par1, __be32 par2)
 {
 	struct sk_buff *skb;
 	struct cisco_packet *data;
@@ -115,16 +115,16 @@ static void cisco_keepalive_send(struct 
 	data = (struct cisco_packet*)(skb->data + 4);
 
 	data->type = htonl(type);
-	data->par1 = htonl(par1);
-	data->par2 = htonl(par2);
-	data->rel = 0xFFFF;
+	data->par1 = par1;
+	data->par2 = par2;
+	data->rel = __constant_htons(0xFFFF);
 	/* we will need do_div here if 1000 % HZ != 0 */
 	data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
 
 	skb_put(skb, sizeof(struct cisco_packet));
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = dev;
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	dev_queue_xmit(skb);
 }
@@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb)
 		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
 			in_dev = dev->ip_ptr;
 			addr = 0;
-			mask = ~0; /* is the mask correct? */
+			mask = __constant_htonl(~0); /* is the mask correct? */
 
 			if (in_dev != NULL) {
 				struct in_ifaddr **ifap = &in_dev->ifa_list;
@@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb)
 	} /* switch(protocol) */
 
 	printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
-	       data->protocol);
+	       ntohs(data->protocol));
 	dev_kfree_skb_any(skb);
 	return NET_RX_DROP;
 
@@ -270,8 +270,9 @@ static void cisco_timer(unsigned long ar
 		netif_dormant_on(dev);
 	}
 
-	cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
-			     state(hdlc)->rxseq);
+	cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+			     htonl(++state(hdlc)->txseq),
+			     htonl(state(hdlc)->rxseq));
 	state(hdlc)->request_sent = 1;
 	state(hdlc)->timer.expires = jiffies +
 		state(hdlc)->settings.interval * HZ;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index c6c3c75..15b6e07 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff
 	struct sk_buff *skb = *skb_p;
 
 	switch (skb->protocol) {
-	case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
+	case __constant_htons(NLPID_CCITT_ANSI_LMI):
 		head_len = 4;
 		skb_push(skb, head_len);
 		skb->data[3] = NLPID_CCITT_ANSI_LMI;
 		break;
 
-	case __constant_ntohs(NLPID_CISCO_LMI):
+	case __constant_htons(NLPID_CISCO_LMI):
 		head_len = 4;
 		skb_push(skb, head_len);
 		skb->data[3] = NLPID_CISCO_LMI;
 		break;
 
-	case __constant_ntohs(ETH_P_IP):
+	case __constant_htons(ETH_P_IP):
 		head_len = 4;
 		skb_push(skb, head_len);
 		skb->data[3] = NLPID_IP;
 		break;
 
-	case __constant_ntohs(ETH_P_IPV6):
+	case __constant_htons(ETH_P_IPV6):
 		head_len = 4;
 		skb_push(skb, head_len);
 		skb->data[3] = NLPID_IPV6;
 		break;
 
-	case __constant_ntohs(ETH_P_802_3):
+	case __constant_htons(ETH_P_802_3):
 		head_len = 10;
 		if (skb_headroom(skb) < head_len) {
 			struct sk_buff *skb2 = skb_realloc_headroom(skb,
@@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff
 		skb->data[5] = FR_PAD;
 		skb->data[6] = FR_PAD;
 		skb->data[7] = FR_PAD;
-		*(u16*)(skb->data + 8) = skb->protocol;
+		*(__be16*)(skb->data + 8) = skb->protocol;
 	}
 
 	dlci_to_q922(skb->data, dlci);
@@ -533,7 +533,7 @@ static void fr_lmi_send(struct net_devic
 		skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI);
 		fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
 	}
-	data = skb->tail;
+	data = skb_tail_pointer(skb);
 	data[i++] = LMI_CALLREF;
 	data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY;
 	if (lmi == LMI_ANSI)
@@ -590,7 +590,7 @@ static void fr_lmi_send(struct net_devic
 	skb_put(skb, i);
 	skb->priority = TC_PRIO_CONTROL;
 	skb->dev = dev;
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	dev_queue_xmit(skb);
 }
@@ -974,8 +974,8 @@ #endif
 
 	} else if (skb->len > 10 && data[3] == FR_PAD &&
 		   data[4] == NLPID_SNAP && data[5] == FR_PAD) {
-		u16 oui = ntohs(*(u16*)(data + 6));
-		u16 pid = ntohs(*(u16*)(data + 8));
+		u16 oui = ntohs(*(__be16*)(data + 6));
+		u16 pid = ntohs(*(__be16*)(data + 8));
 		skb_pull(skb, 10);
 
 		switch ((((u32)oui) << 16) | pid) {
@@ -1011,7 +1011,6 @@ #endif
 		stats->rx_bytes += skb->len;
 		if (pvc->state.becn)
 			stats->rx_compressed++;
-		skb->dev = dev;
 		netif_rx(skb);
 		return NET_RX_SUCCESS;
 	} else {
@@ -1128,7 +1127,7 @@ static int fr_add_pvc(struct net_device 
 		memcpy(dev->dev_addr, "\x00\x01", 2);
                 get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
 	} else {
-		*(u16*)dev->dev_addr = htons(dlci);
+		*(__be16*)dev->dev_addr = htons(dlci);
 		dlci_to_q922(dev->broadcast, dlci);
 	}
 	dev->hard_start_xmit = pvc_xmit;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index a02c5fb..9ba3e4e 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -59,7 +59,7 @@ static void hostess_input(struct z8530_c
 	/* Drop the CRC - it's not a good idea to try and negotiate it ;) */
 	skb_trim(skb, skb->len-2);
 	skb->protocol=__constant_htons(ETH_P_WAN_PPP);
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 	skb->dev=c->netdevice;
 	/*
 	 *	Send it to the PPP layer. We don't have time to process
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 2b54f1b..ae132c1 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1636,7 +1636,7 @@ static int lmc_rx (struct net_device *de
             if (nsb) {
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
-                sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+                sc->lmc_rxring[i].buffer1 = virt_to_bus(skb_tail_pointer(nsb));
             }
             sc->failed_recv_alloc = 1;
             goto skip_packet;
@@ -1667,8 +1667,8 @@ static int lmc_rx (struct net_device *de
             skb_put (skb, len);
             skb->protocol = lmc_proto_type(sc, skb);
             skb->protocol = htons(ETH_P_WAN_PPP);
-            skb->mac.raw = skb->data;
-//            skb->nh.raw = skb->data;
+            skb_reset_mac_header(skb);
+            /* skb_reset_network_header(skb); */
             skb->dev = dev;
             lmc_proto_netif(sc, skb);
 
@@ -1679,7 +1679,7 @@ static int lmc_rx (struct net_device *de
             if (nsb) {
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
-                sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
+                sc->lmc_rxring[i].buffer1 = virt_to_bus(skb_tail_pointer(nsb));
                 /* Transferred to 21140 below */
             }
             else {
@@ -1702,11 +1702,11 @@ static int lmc_rx (struct net_device *de
             if(!nsb) {
                 goto give_it_anyways;
             }
-            memcpy(skb_put(nsb, len), skb->data, len);
+            skb_copy_from_linear_data(skb, skb_put(nsb, len), len);
             
             nsb->protocol = lmc_proto_type(sc, skb);
-            nsb->mac.raw = nsb->data;
-//            nsb->nh.raw = nsb->data;
+            skb_reset_mac_header(nsb);
+            /* skb_reset_network_header(nsb); */
             nsb->dev = dev;
             lmc_proto_netif(sc, nsb);
         }
@@ -1932,7 +1932,7 @@ static void lmc_softreset (lmc_softc_t *
         sc->lmc_rxring[i].status = 0x80000000;
 
         /* used to be PKT_BUF_SZ now uses skb since we lose some to head room */
-        sc->lmc_rxring[i].length = skb->end - skb->data;
+        sc->lmc_rxring[i].length = skb_tailroom(skb);
 
         /* use to be tail which is dumb since you're thinking why write
          * to the end of the packj,et but since there's nothing there tail == data
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index ae01555..574737b 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -8,7 +8,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 74876c0..31e1799 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -27,7 +27,6 @@ #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 62184de..999bf71 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -1755,17 +1755,17 @@ cpc_trace(struct net_device *dev, struct
 
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_CUST);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_HOST;
 	skb->len = 10 + skb_main->len;
 
-	memcpy(skb->data, dev->name, 5);
+	skb_copy_to_linear_data(skb, dev->name, 5);
 	skb->data[5] = '[';
 	skb->data[6] = rx_tx;
 	skb->data[7] = ']';
 	skb->data[8] = ':';
 	skb->data[9] = ' ';
-	memcpy(&skb->data[10], skb_main->data, skb_main->len);
+	skb_copy_from_linear_data(skb_main, &skb->data[10], skb_main->len);
 
 	netif_rx(skb);
 }
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 5873c34..e24a7b0 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -38,7 +38,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/pci.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
@@ -1003,17 +1002,17 @@ static void cpc_tty_trace(pc300dev_t *de
 	skb_put (skb, 10 + len); 
 	skb->dev = dev->dev; 
 	skb->protocol = htons(ETH_P_CUST); 
-	skb->mac.raw = skb->data; 
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_HOST; 
 	skb->len = 10 + len; 
 
-	memcpy(skb->data,dev->dev->name,5);
+	skb_copy_to_linear_data(skb, dev->dev->name, 5);
 	skb->data[5] = '['; 
 	skb->data[6] = rxtx; 
 	skb->data[7] = ']'; 
 	skb->data[8] = ':'; 
 	skb->data[9] = ' '; 
-	memcpy(&skb->data[10], buf, len); 
+	skb_copy_to_linear_data_offset(skb, 10, buf, len);
 	netif_rx(skb); 
 } 	
 
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index fc5c0c6..35eded7 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -999,11 +999,6 @@ get_rx_buf( struct net_device  *dev )
 	if( !skb )
 		return  NULL;
 
-#ifdef CONFIG_SBNI_MULTILINE
-	skb->dev = ((struct net_local *) dev->priv)->master;
-#else
-	skb->dev = dev;
-#endif
 	skb_reserve( skb, 2 );		/* Align IP on longword boundaries */
 	return  skb;
 }
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 70fb1b9..1313581 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -61,7 +61,7 @@ static void sealevel_input(struct z8530_
 	/* Drop the CRC - it's not a good idea to try and negotiate it ;) */
 	skb_trim(skb, skb->len-2);
 	skb->protocol=htons(ETH_P_WAN_PPP);
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 	skb->dev=c->netdevice;
 	/*
 	 *	Send it to the PPP layer. We don't have time to process
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 218f7b5..67fc67c 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -227,7 +227,7 @@ static void sppp_input (struct net_devic
 	unsigned long flags;
 
 	skb->dev=dev;
-	skb->mac.raw=skb->data;
+	skb_reset_mac_header(skb);
 
 	if (dev->flags & IFF_RUNNING)
 	{
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 8b4540b..98ef400 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -1656,7 +1656,7 @@ static void z8530_rx_done(struct z8530_c
 		else
 		{
 			skb_put(skb, ct);
-			memcpy(skb->data, rxb, ct);
+			skb_copy_to_linear_data(skb, rxb, ct);
 			c->stats.rx_packets++;
 			c->stats.rx_bytes+=ct;
 		}
@@ -1782,7 +1782,7 @@ int z8530_queue_xmit(struct z8530_channe
 		 */
 		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];
 		c->tx_dma_used^=1;	/* Flip temp buffer */
-		memcpy(c->tx_next_ptr, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, c->tx_next_ptr, skb->len);
 	}
 	else
 		c->tx_next_ptr=skb->data;	
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ece3d9c..e273347 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -2,47 +2,21 @@ #
 # Wireless LAN device configuration
 #
 
-menu "Wireless LAN (non-hamradio)"
-	depends on NETDEVICES
-
-config NET_RADIO
-	bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions"
-	select WIRELESS_EXT
-	---help---
-	  Support for wireless LANs and everything having to do with radio,
-	  but not with amateur radio or FM broadcasting.
-
-	  Saying Y here also enables the Wireless Extensions (creates
-	  /proc/net/wireless and enables iwconfig access). The Wireless
-	  Extension is a generic API allowing a driver to expose to the user
-	  space configuration and statistics specific to common Wireless LANs.
-	  The beauty of it is that a single set of tool can support all the
-	  variations of Wireless LANs, regardless of their type (as long as
-	  the driver supports Wireless Extension). Another advantage is that
-	  these parameters may be changed on the fly without restarting the
-	  driver (or Linux). If you wish to use Wireless Extensions with
-	  wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch
-	  the tools from
-	  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
+menu "Wireless LAN"
 
-config NET_WIRELESS_RTNETLINK
-	bool "Wireless Extension API over RtNetlink"
-	depends on NET_RADIO
+config WLAN_PRE80211
+	bool "Wireless LAN (pre-802.11)"
+	depends on NETDEVICES
 	---help---
-	  Support the Wireless Extension API over the RtNetlink socket
-	  in addition to the traditional ioctl interface (selected above).
-
-	  For now, few tools use this facility, but it might grow in the
-	  future. The only downside is that it adds 4.5 kB to your kernel.
+	  Say Y if you have any pre-802.11 wireless LAN hardware.
 
-# Note : the cards are obsolete (can't buy them anymore), but the drivers
-# are not, as people are still using them...
-comment "Obsolete Wireless cards support (pre-802.11)"
-	depends on NET_RADIO && (INET || ISA || PCMCIA)
+	  This option does not affect the kernel build, it only
+	  lets you choose drivers.
 
 config STRIP
 	tristate "STRIP (Metricom starmode radio IP)"
-	depends on NET_RADIO && INET
+	depends on INET && WLAN_PRE80211
+	select WIRELESS_EXT
 	---help---
 	  Say Y if you have a Metricom radio and intend to use Starmode Radio
 	  IP. STRIP is a radio protocol developed for the MosquitoNet project
@@ -65,7 +39,8 @@ config STRIP
 
 config ARLAN
 	tristate "Aironet Arlan 655 & IC2200 DS support"
-	depends on NET_RADIO && ISA && !64BIT
+	depends on ISA && !64BIT && WLAN_PRE80211
+	select WIRELESS_EXT
 	---help---
 	  Aironet makes Arlan, a class of wireless LAN adapters. These use the
 	  www.Telxon.com chip, which is also used on several similar cards.
@@ -80,7 +55,8 @@ config ARLAN
 
 config WAVELAN
 	tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support"
-	depends on NET_RADIO && ISA
+	depends on ISA && WLAN_PRE80211
+	select WIRELESS_EXT
 	---help---
 	  The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is
 	  a Radio LAN (wireless Ethernet-like Local Area Network) using the
@@ -107,7 +83,8 @@ config WAVELAN
 
 config PCMCIA_WAVELAN
 	tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support"
-	depends on NET_RADIO && PCMCIA
+	depends on PCMCIA && WLAN_PRE80211
+	select WIRELESS_EXT
 	help
 	  Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA
 	  (PC-card) wireless Ethernet networking card to your computer.  This
@@ -118,7 +95,8 @@ config PCMCIA_WAVELAN
 
 config PCMCIA_NETWAVE
 	tristate "Xircom Netwave AirSurfer Pcmcia wireless support"
-	depends on NET_RADIO && PCMCIA
+	depends on PCMCIA && WLAN_PRE80211
+	select WIRELESS_EXT
 	help
 	  Say Y here if you intend to attach this type of PCMCIA (PC-card)
 	  wireless Ethernet networking card to your computer.
@@ -126,12 +104,20 @@ config PCMCIA_NETWAVE
 	  To compile this driver as a module, choose M here: the module will be
 	  called netwave_cs.  If unsure, say N.
 
-comment "Wireless 802.11 Frequency Hopping cards support"
-	depends on NET_RADIO && PCMCIA
+
+config WLAN_80211
+	bool "Wireless LAN (IEEE 802.11)"
+	depends on NETDEVICES
+	---help---
+	  Say Y if you have any 802.11 wireless LAN hardware.
+
+	  This option does not affect the kernel build, it only
+	  lets you choose drivers.
 
 config PCMCIA_RAYCS
 	tristate "Aviator/Raytheon 2.4MHz wireless support"
-	depends on NET_RADIO && PCMCIA
+	depends on PCMCIA && WLAN_80211
+	select WIRELESS_EXT
 	---help---
 	  Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
 	  (PC-card) wireless Ethernet networking card to your computer.
@@ -141,12 +127,10 @@ config PCMCIA_RAYCS
 	  To compile this driver as a module, choose M here: the module will be
 	  called ray_cs.  If unsure, say N.
 
-comment "Wireless 802.11b ISA/PCI cards support"
-	depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
-
 config IPW2100
 	tristate "Intel PRO/Wireless 2100 Network Connection"
-	depends on NET_RADIO && PCI
+	depends on PCI && WLAN_80211
+	select WIRELESS_EXT
 	select FW_LOADER
 	select IEEE80211
 	---help---
@@ -169,8 +153,8 @@ config IPW2100
  
           If you want to compile the driver as a module ( = code which can be
           inserted in and removed from the running kernel whenever you want),
-          say M here and read <file:Documentation/modules.txt>.  The module
-          will be called ipw2100.ko.
+          say M here and read <file:Documentation/kbuild/modules.txt>.
+          The module will be called ipw2100.ko.
 	
 config IPW2100_MONITOR
         bool "Enable promiscuous mode"
@@ -200,7 +184,8 @@ config IPW2100_DEBUG
 
 config IPW2200
 	tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-	depends on NET_RADIO && PCI
+	depends on PCI && WLAN_80211
+	select WIRELESS_EXT
 	select FW_LOADER
 	select IEEE80211
 	---help---
@@ -223,8 +208,8 @@ config IPW2200
  
           If you want to compile the driver as a module ( = code which can be
           inserted in and removed from the running kernel whenever you want),
-          say M here and read <file:Documentation/modules.txt>.  The module
-          will be called ipw2200.ko.
+          say M here and read <file:Documentation/kbuild/modules.txt>.
+          The module will be called ipw2200.ko.
 
 config IPW2200_MONITOR
         bool "Enable promiscuous mode"
@@ -280,9 +265,23 @@ config IPW2200_DEBUG
 
 	  If you are not sure, say N here.
 
+config LIBERTAS_USB
+	tristate "Marvell Libertas 8388 802.11a/b/g cards"
+	depends on USB && WLAN_80211
+	select FW_LOADER
+	---help---
+	  A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_USB_DEBUG
+	bool "Enable full debugging output in the Libertas USB module."
+	depends on LIBERTAS_USB
+	---help---
+	  Debugging support.
+
 config AIRO
 	tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
- 	depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN)
+	depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
+	select WIRELESS_EXT
 	select CRYPTO
 	---help---
 	  This is the standard Linux driver to support Cisco/Aironet ISA and
@@ -299,7 +298,8 @@ config AIRO
 
 config HERMES
 	tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
-	depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA)
+	depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+	select WIRELESS_EXT
 	---help---
 	  A driver for 802.11b wireless cards based on the "Hermes" or
 	  Intersil HFA384x (Prism 2) MAC controller.  This includes the vast
@@ -373,7 +373,8 @@ config PCI_HERMES
 
 config ATMEL
       tristate "Atmel at76c50x chipset  802.11b support"
-      depends on NET_RADIO && (PCI || PCMCIA)
+      depends on (PCI || PCMCIA) && WLAN_80211
+      select WIRELESS_EXT
       select FW_LOADER
       select CRC32
        ---help---
@@ -394,13 +395,9 @@ config PCI_ATMEL
         Enable support for PCI and mini-PCI cards containing the
         Atmel at76c506 chip.
 
-# If Pcmcia is compiled in, offer Pcmcia cards...
-comment "Wireless 802.11b Pcmcia/Cardbus cards support"
-	depends on NET_RADIO && PCMCIA
-
 config PCMCIA_HERMES
 	tristate "Hermes PCMCIA card support"
-	depends on NET_RADIO && PCMCIA && HERMES
+	depends on PCMCIA && HERMES
 	---help---
 	  A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
 	  as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -420,7 +417,7 @@ config PCMCIA_HERMES
 
 config PCMCIA_SPECTRUM
 	tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
-	depends on NET_RADIO && PCMCIA && HERMES
+	depends on PCMCIA && HERMES
 	select FW_LOADER
 	---help---
 
@@ -434,7 +431,8 @@ config PCMCIA_SPECTRUM
 
 config AIRO_CS
 	tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
-	depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
+	depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211
+	select WIRELESS_EXT
 	select CRYPTO
 	select CRYPTO_AES
 	---help---
@@ -458,7 +456,8 @@ config AIRO_CS
 
 config PCMCIA_ATMEL
 	tristate "Atmel at76c502/at76c504 PCMCIA cards"
-	depends on NET_RADIO && ATMEL && PCMCIA
+	depends on ATMEL && PCMCIA
+	select WIRELESS_EXT
 	select FW_LOADER
 	select CRC32
 	---help---
@@ -467,17 +466,17 @@ config PCMCIA_ATMEL
 
 config PCMCIA_WL3501
       tristate "Planet WL3501 PCMCIA cards"
-      depends on NET_RADIO && EXPERIMENTAL && PCMCIA
+      depends on EXPERIMENTAL && PCMCIA && WLAN_80211
+      select WIRELESS_EXT
        ---help---
          A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
 	 It has basic support for Linux wireless extensions and initial
 	 micro support for ethtool.
 
-comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support"
-	depends on NET_RADIO && PCI
 config PRISM54
 	tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' 
-	depends on PCI && NET_RADIO && EXPERIMENTAL
+	depends on PCI && EXPERIMENTAL && WLAN_80211
+	select WIRELESS_EXT
 	select FW_LOADER
 	---help---
 	  Enable PCI and Cardbus support for the following chipset based cards:
@@ -518,12 +517,13 @@ config PRISM54
 	  
 	  If you want to compile the driver as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/modules.txt>.  The module
-	  will be called prism54.ko.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.
+	  The module will be called prism54.ko.
 
 config USB_ZD1201
 	tristate "USB ZD1201 based Wireless device support"
-	depends on USB && NET_RADIO
+	depends on USB && WLAN_80211
+	select WIRELESS_EXT
 	select FW_LOADER
 	---help---
 	  Say Y if you want to use wireless LAN adapters based on the ZyDAS
@@ -542,11 +542,4 @@ source "drivers/net/wireless/hostap/Kcon
 source "drivers/net/wireless/bcm43xx/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
 
-# yes, this works even when no drivers are selected
-config NET_WIRELESS
-	bool
-	depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA)
-	default y
-
 endmenu
-
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c613af1..d212460 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
+obj-$(CONFIG_LIBERTAS_USB)     += libertas/
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README
deleted file mode 100644
index 0c274bf..0000000
--- a/drivers/net/wireless/README
+++ /dev/null
@@ -1,25 +0,0 @@
-	README
-	------
-
-	This directory is mostly for Wireless LAN drivers, in their
-various incarnations (ISA, PCI, Pcmcia...).
-	This separate directory is needed because a lot of driver work
-on different bus (typically PCI + Pcmcia) and share 95% of the
-code. This allow the code and the config options to be in one single
-place instead of scattered all over the driver tree, which is never
-100% satisfactory.
-
-	Note : if you want more info on the topic of Wireless LANs,
-you are kindly invited to have a look at the Wireless Howto :
-		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
-	Some Wireless LAN drivers, like orinoco_cs, require the use of
-Wireless Tools to be configured :
-		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
-
-	Special notes for distribution maintainers :
-	1) wvlan_cs will be discontinued soon in favor of orinoco_cs
-	2) Please add Wireless Tools support in your scripts
-
-	Have fun...
-
-	Jean
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 2ada76a..2d3a180 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -25,7 +25,6 @@ #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
@@ -1145,6 +1144,7 @@ static void airo_networks_free(struct ai
 struct airo_info {
 	struct net_device_stats	stats;
 	struct net_device             *dev;
+	struct list_head              dev_list;
 	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
 	   use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
@@ -2360,6 +2360,21 @@ static int airo_change_mtu(struct net_de
 	return 0;
 }
 
+static LIST_HEAD(airo_devices);
+
+static void add_airo_dev(struct airo_info *ai)
+{
+	/* Upper layers already keep track of PCI devices,
+	 * so we only need to remember our non-PCI cards. */
+	if (!ai->pci)
+		list_add_tail(&ai->dev_list, &airo_devices);
+}
+
+static void del_airo_dev(struct airo_info *ai)
+{
+	if (!ai->pci)
+		list_del(&ai->dev_list);
+}
 
 static int airo_close(struct net_device *dev) {
 	struct airo_info *ai = dev->priv;
@@ -2381,8 +2396,6 @@ #endif
 	return 0;
 }
 
-static void del_airo_dev( struct net_device *dev );
-
 void stop_airo_card( struct net_device *dev, int freeres )
 {
 	struct airo_info *ai = dev->priv;
@@ -2434,17 +2447,15 @@ void stop_airo_card( struct net_device *
 		}
         }
 	crypto_free_cipher(ai->tfm);
-	del_airo_dev( dev );
+	del_airo_dev(ai);
 	free_netdev( dev );
 }
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int add_airo_dev( struct net_device *dev );
-
 static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
-	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
+	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
 	return ETH_ALEN;
 }
 
@@ -2740,8 +2751,6 @@ static int airo_networks_allocate(struct
 
 static void airo_networks_free(struct airo_info *ai)
 {
-	if (!ai->networks)
-		return;
 	kfree(ai->networks);
 	ai->networks = NULL;
 }
@@ -2816,12 +2825,10 @@ static struct net_device *_init_airo_car
 	if (IS_ERR(ai->airo_thread_task))
 		goto err_out_free;
 	ai->tfm = NULL;
-	rc = add_airo_dev( dev );
-	if (rc)
-		goto err_out_thr;
+	add_airo_dev(ai);
 
 	if (airo_networks_allocate (ai))
-		goto err_out_unlink;
+		goto err_out_thr;
 	airo_networks_initialize (ai);
 
 	/* The Airo-specific entries in the device structure. */
@@ -2937,9 +2944,8 @@ err_out_irq:
 	free_irq(dev->irq, dev);
 err_out_nets:
 	airo_networks_free(ai);
-err_out_unlink:
-	del_airo_dev(dev);
 err_out_thr:
+	del_airo_dev(ai);
 	set_bit(JOB_DIE, &ai->jobs);
 	kthread_stop(ai->airo_thread_task);
 err_out_free:
@@ -3411,14 +3417,12 @@ #endif /* WIRELESS_SPY */
 			OUT4500( apriv, EVACK, EV_RX);
 
 			if (test_bit(FLAG_802_11, &apriv->flags)) {
-				skb->mac.raw = skb->data;
+				skb_reset_mac_header(skb);
 				skb->pkt_type = PACKET_OTHERHOST;
 				skb->dev = apriv->wifidev;
 				skb->protocol = htons(ETH_P_802_2);
-			} else {
-				skb->dev = dev;
+			} else
 				skb->protocol = eth_type_trans(skb,dev);
-			}
 			skb->dev->last_rx = jiffies;
 			skb->ip_summed = CHECKSUM_NONE;
 
@@ -3641,7 +3645,6 @@ #ifdef WIRELESS_SPY
 		}
 #endif /* WIRELESS_SPY */
 
-		skb->dev = ai->dev;
 		skb->ip_summed = CHECKSUM_NONE;
 		skb->protocol = eth_type_trans(skb, ai->dev);
 		skb->dev->last_rx = jiffies;
@@ -3749,7 +3752,7 @@ #ifdef IW_WIRELESS_SPY	  /* defined in i
 		wireless_spy_update(ai->dev, sa, &wstats);
 	}
 #endif /* IW_WIRELESS_SPY */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->dev = ai->wifidev;
 	skb->protocol = htons(ETH_P_802_2);
@@ -5538,11 +5541,6 @@ static int proc_close( struct inode *ino
 	return 0;
 }
 
-static struct net_device_list {
-	struct net_device *dev;
-	struct net_device_list *next;
-} *airo_devices;
-
 /* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
@@ -5585,26 +5583,6 @@ static void timer_func( struct net_devic
 	apriv->expires = RUN_AT(HZ*3);
 }
 
-static int add_airo_dev( struct net_device *dev ) {
-	struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
-	if ( !node )
-		return -ENOMEM;
-
-	node->dev = dev;
-	node->next = airo_devices;
-	airo_devices = node;
-
-	return 0;
-}
-
-static void del_airo_dev( struct net_device *dev ) {
-	struct net_device_list **p = &airo_devices;
-	while( *p && ( (*p)->dev != dev ) )
-		p = &(*p)->next;
-	if ( *p && (*p)->dev == dev )
-		*p = (*p)->next;
-}
-
 #ifdef CONFIG_PCI
 static int __devinit airo_pci_probe(struct pci_dev *pdev,
 				    const struct pci_device_id *pent)
@@ -5628,6 +5606,10 @@ static int __devinit airo_pci_probe(stru
 
 static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	airo_print_info(dev->name, "Unregistering...");
+	stop_airo_card(dev, 1);
 }
 
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5753,9 +5735,11 @@ #endif
 
 static void __exit airo_cleanup_module( void )
 {
-	while( airo_devices ) {
-		airo_print_info(airo_devices->dev->name, "Unregistering...\n");
-		stop_airo_card( airo_devices->dev, 1 );
+	struct airo_info *ai;
+	while(!list_empty(&airo_devices)) {
+		ai = list_entry(airo_devices.next, struct airo_info, dev_list);
+		airo_print_info(ai->dev->name, "Unregistering...");
+		stop_airo_card(ai->dev, 1);
 	}
 #ifdef CONFIG_PCI
 	pci_unregister_driver(&airo_driver);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 4688e56..498e848 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1500,7 +1500,6 @@ #endif				// ARLAN_MULTICAST
 				break;
 			}
 			skb_reserve(skb, 2);
-			skb->dev = dev;
 			skbtmp = skb_put(skb, pkt_len);
 
 			memcpy_fromio(skbtmp + ARLAN_FAKE_HDR_LEN, ((char __iomem *) arlan) + rxOffset, pkt_len - ARLAN_FAKE_HDR_LEN);
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 23eba69..51a7db5 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -827,14 +827,14 @@ static int start_tx(struct sk_buff *skb,
 	if (priv->wep_is_on)
 		frame_ctl |= IEEE80211_FCTL_PROTECTED;
 	if (priv->operating_mode == IW_MODE_ADHOC) {
-		memcpy(&header.addr1, skb->data, 6);
+		skb_copy_from_linear_data(skb, &header.addr1, 6);
 		memcpy(&header.addr2, dev->dev_addr, 6);
 		memcpy(&header.addr3, priv->BSSID, 6);
 	} else {
 		frame_ctl |= IEEE80211_FCTL_TODS;
 		memcpy(&header.addr1, priv->CurrentBSSID, 6);
 		memcpy(&header.addr2, dev->dev_addr, 6);
-		memcpy(&header.addr3, skb->data, 6);
+		skb_copy_from_linear_data(skb, &header.addr3, 6);
 	}
 
 	if (priv->use_wpa)
@@ -920,7 +920,6 @@ static void fast_rx_path(struct atmel_pr
 		memcpy(&skbp[6], header->addr2, 6); /* source address */
 
 	priv->dev->last_rx = jiffies;
-	skb->dev = priv->dev;
 	skb->protocol = eth_type_trans(skb, priv->dev);
 	skb->ip_summed = CHECKSUM_NONE;
 	netif_rx(skb);
@@ -1028,7 +1027,6 @@ static void frag_rx_path(struct atmel_pr
 				       priv->rx_buf,
 				       priv->frag_len + 12);
 				priv->dev->last_rx = jiffies;
-				skb->dev = priv->dev;
 				skb->protocol = eth_type_trans(skb, priv->dev);
 				skb->ip_summed = CHECKSUM_NONE;
 				netif_rx(skb);
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
index 533993f..ce397e4 100644
--- a/drivers/net/wireless/bcm43xx/Kconfig
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -1,6 +1,7 @@
 config BCM43XX
 	tristate "Broadcom BCM43xx wireless support"
-	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
+	select WIRELESS_EXT
 	select FW_LOADER
 	select HW_RANDOM
 	---help---
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 95ff175..f8483c1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -277,11 +277,14 @@ #define BCM43xx_SBTMSTATELOW_RESET		0x01
 #define BCM43xx_SBTMSTATELOW_REJECT		0x02
 #define BCM43xx_SBTMSTATELOW_CLOCK		0x10000
 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK	0x20000
+#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE	0x20000000
 
 /* sbtmstatehigh state flags */
 #define BCM43xx_SBTMSTATEHIGH_SERROR		0x00000001
 #define BCM43xx_SBTMSTATEHIGH_BUSY		0x00000004
 #define BCM43xx_SBTMSTATEHIGH_TIMEOUT		0x00000020
+#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL	0x00010000
+#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL	0x00020000
 #define BCM43xx_SBTMSTATEHIGH_COREFLAGS		0x1FFF0000
 #define BCM43xx_SBTMSTATEHIGH_DMA64BIT		0x10000000
 #define BCM43xx_SBTMSTATEHIGH_GATEDCLK		0x20000000
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 6e0dc76..e3d2e61 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -998,7 +998,8 @@ static void dma_tx_fragment(struct bcm43
 			assert(0);
 			return;
 		}
-		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(bounce_skb, skb->len),
+					  skb->len);
 		dev_kfree_skb_any(skb);
 		skb = bounce_skb;
 	}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
index c947025..d2df6a0 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -32,7 +32,7 @@ #include "bcm43xx_ethtool.h"
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
 
 
 static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct n
 	struct bcm43xx_private *bcm = bcm43xx_priv(dev);
 
 	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-	strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+	strncpy(info->version, utsname()->release, sizeof(info->version));
 	strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
 }
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index a38e7ee..5e96bca 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1407,7 +1407,7 @@ #endif
 				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
 	} else {
 		if (connect_phy)
-			flags |= 0x20000000;
+			flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_phy_connect(bcm, connect_phy);
 		bcm43xx_core_enable(bcm, flags);
 		bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct 
 		u32 sbtmstatelow;
 
 		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		sbtmstatelow |= 0x20000000;
+		sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
 	}
 	err = wireless_core_up(bcm, 1);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 72529a4..b37f1e3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_p
 
 	flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
 	if (connect) {
-		if (!(flags & 0x00010000))
+		if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
 			return -ENODEV;
 		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		flags |= (0x800 << 18);
+		flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
 	} else {
-		if (!(flags & 0x00020000))
+		if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
 			return -ENODEV;
 		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		flags &= ~(0x800 << 18);
+		flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
 	}
 out:
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct 
 
 	if (phy->rev > 2) {
 		bcm43xx_phy_write(bcm, 0x0422, 0x287A);
-		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); 
+		bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
+				  & 0x0FFF) | 0x3000);
 	}
 		
-	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+	bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
+					| 0x7874);
 	bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
 
 	if (phy->rev == 1) {
-		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+		bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
+				  & 0xF0FF) | 0x0600);
 		bcm43xx_phy_write(bcm, 0x048B, 0x005E);
-		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+		bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
+				  & 0xFF00) | 0x001E);
 		bcm43xx_phy_write(bcm, 0x048D, 0x0002);
 	}
 
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bc
 	if (phy->rev == 1) {
 		bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
 		bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+				  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+				  & 0xFC3F) | 0x0340);
 		bcm43xx_phy_write(bcm, 0x042C, 0x005A);
 		bcm43xx_phy_write(bcm, 0x0427, 0x001A);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
index 1f321ef..7311836 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
@@ -48,6 +48,10 @@ #define bcm43xx_phy_unlock(bcm, flags) \
 		local_irq_restore(flags);	\
 	} while (0)
 
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+        (((phy)->rev > 1) || ((phy)->connected))
+
 u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
 void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 4025dd0..6a109f4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struc
 	return ret;
 }
 
+#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	u16 loop_or = 0;
+	u16 adj_loopback_gain = phy->loopback_gain[0];
+	u8 loop;
+	u16 extern_lna_control;
+
+	if (!phy->connected)
+		return 0;
+	if (!has_loopback_gain(phy)) {
+		if (phy->rev < 7 || !(bcm->sprom.boardflags
+		    & BCM43xx_BFL_EXTLNA)) {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x0FB2;
+			case LPD(0, 0, 1):
+				return 0x00B2;
+			case LPD(1, 0, 1):
+				return 0x30B2;
+			case LPD(1, 0, 0):
+				return 0x30B3;
+			default:
+				assert(0);
+			}
+		} else {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x8FB2;
+			case LPD(0, 0, 1):
+				return 0x80B2;
+			case LPD(1, 0, 1):
+				return 0x20B2;
+			case LPD(1, 0, 0):
+				return 0x20B3;
+			default:
+				assert(0);
+			}
+		}
+	} else {
+		if (radio->revision == 8)
+			adj_loopback_gain += 0x003E;
+		else
+			adj_loopback_gain += 0x0026;
+		if (adj_loopback_gain >= 0x46) {
+			adj_loopback_gain -= 0x46;
+			extern_lna_control = 0x3000;
+		} else if (adj_loopback_gain >= 0x3A) {
+			adj_loopback_gain -= 0x3A;
+			extern_lna_control = 0x2000;
+		} else if (adj_loopback_gain >= 0x2E) {
+			adj_loopback_gain -= 0x2E;
+			extern_lna_control = 0x1000;
+		} else {
+			adj_loopback_gain -= 0x10;
+			extern_lna_control = 0x0000;
+		}
+		for (loop = 0; loop < 16; loop++) {
+			u16 tmp = adj_loopback_gain - 6 * loop;
+			if (tmp < 6)
+				break;
+		}
+
+		loop_or = (loop << 8) | extern_lna_control;
+		if (phy->rev >= 7 && bcm->sprom.boardflags
+		    & BCM43xx_BFL_EXTLNA) {
+			if (extern_lna_control)
+				loop_or |= 0x8000;
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x8F92;
+			case LPD(0, 0, 1):
+				return (0x8092 | loop_or);
+			case LPD(1, 0, 1):
+				return (0x2092 | loop_or);
+			case LPD(1, 0, 0):
+				return (0x2093 | loop_or);
+			default:
+				assert(0);
+			}
+		} else {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x0F92;
+			case LPD(0, 0, 1):
+			case LPD(1, 0, 1):
+				return (0x0092 | loop_or);
+			case LPD(1, 0, 0):
+				return (0x0093 | loop_or);
+			default:
+				assert(0);
+			}
+		}
+	}
+	return 0;
+}
+
 u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
-	u16 backup[19] = { 0 };
+	u16 backup[21] = { 0 };
 	u16 ret;
 	u16 i, j;
 	u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 			backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
 			backup[9] = bcm43xx_phy_read(bcm, 0x0802);
 			bcm43xx_phy_write(bcm, 0x0814,
-			                  (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+			                  (bcm43xx_phy_read(bcm, 0x0814)
+					  | 0x0003));
 			bcm43xx_phy_write(bcm, 0x0815,
-			                  (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));	
+			                  (bcm43xx_phy_read(bcm, 0x0815)
+					  & 0xFFFC));
 			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
-			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+			                  (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+					  & 0x7FFF));
 			bcm43xx_phy_write(bcm, 0x0802,
 			                  (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
-			bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
-			bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+			if (phy->rev > 1) { /* loopback gain enabled */
+				backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+				backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+				if (phy->rev >= 3)
+					bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+				else
+					bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+				bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+			}
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+			if (phy->rev < 7 || !(bcm->sprom.boardflags
+			    & BCM43xx_BFL_EXTLNA))
+				bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+			else
+				bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
 		}
-		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-		                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
 	}
+	bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+	                (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
 	backup[10] = bcm43xx_phy_read(bcm, 0x0035);
 	bcm43xx_phy_write(bcm, 0x0035,
 	                  (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 		bcm43xx_write16(bcm, 0x03E6, 0x0122);
 	} else {
 		if (phy->analog >= 2)
-			bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
-					& 0xFFBF) | 0x0040);
+			bcm43xx_phy_write(bcm, 0x0003,
+					  (bcm43xx_phy_read(bcm, 0x0003)
+					  & 0xFFBF) | 0x0040);
 		bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
-		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+		                (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+				| 0x2000));
 	}
 
 	ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 	if (phy->type == BCM43xx_PHYTYPE_B)
 		bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
 
+	if (phy->connected)
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
 	bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
 	bcm43xx_phy_write(bcm, 0x002B, 0x1403);
 	if (phy->connected)
-		bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+		bcm43xx_phy_write(bcm, 0x0812,
+				  bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
 	bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
 	bcm43xx_radio_write16(bcm, 0x0051,
 	                      (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
-	bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
-	bcm43xx_radio_write16(bcm, 0x0043,
-			      (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+	if (radio->revision == 8)
+		bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+	else {
+		bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+		bcm43xx_radio_write16(bcm, 0x0043,
+				      (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+				      | 0x0009);
+	}
 	bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 
 	for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 		bcm43xx_phy_write(bcm, 0x0059, 0xC810);
 		bcm43xx_phy_write(bcm, 0x0058, 0x000D);
 		if (phy->connected)
-			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
 		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
 		udelay(10);
 		if (phy->connected)
-			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
 		bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
 		udelay(10);
 		if (phy->connected)
-			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
 		bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
-		udelay(10);
+		udelay(20);
 		tmp1 += bcm43xx_phy_read(bcm, 0x002D);
 		bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 		if (phy->connected)
-			bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+			bcm43xx_phy_write(bcm, 0x0812,
+					  bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
 		bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
 	}
 
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 			bcm43xx_phy_write(bcm, 0x0059, 0xC810);
 			bcm43xx_phy_write(bcm, 0x0058, 0x000D);
 			if (phy->connected)
-				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+				bcm43xx_phy_write(bcm, 0x0812,
+						  bcm43xx_get_812_value(bcm,
+						  LPD(1, 0, 1)));
 			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
 			udelay(10);
 			if (phy->connected)
-				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+				bcm43xx_phy_write(bcm, 0x0812,
+						  bcm43xx_get_812_value(bcm,
+						  LPD(1, 0, 1)));
 			bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
 			udelay(10);
 			if (phy->connected)
-				bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+				bcm43xx_phy_write(bcm, 0x0812,
+						  bcm43xx_get_812_value(bcm,
+						  LPD(1, 0, 0)));
 			bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
 			udelay(10);
 			tmp2 += bcm43xx_phy_read(bcm, 0x002D);
 			bcm43xx_phy_write(bcm, 0x0058, 0x0000);
 			if (phy->connected)
-				bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+				bcm43xx_phy_write(bcm, 0x0812,
+						  bcm43xx_get_812_value(bcm,
+						  LPD(1, 0, 1)));
 			bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
 		}
 		tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43x
 		bcm43xx_phy_write(bcm, 0x0030, backup[2]);
 		bcm43xx_write16(bcm, 0x03EC, backup[3]);
 	} else {
-		bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
-				(bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
 		if (phy->connected) {
+			bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+					(bcm43xx_read16(bcm,
+					BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
 			bcm43xx_phy_write(bcm, 0x0811, backup[4]);
 			bcm43xx_phy_write(bcm, 0x0812, backup[5]);
 			bcm43xx_phy_write(bcm, 0x0814, backup[6]);
 			bcm43xx_phy_write(bcm, 0x0815, backup[7]);
 			bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
 			bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+			if (phy->rev > 1) {
+				bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+				bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+			}
 		}
 	}
 	if (i >= 15)
diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig
index 308f773..1fef331 100644
--- a/drivers/net/wireless/hostap/Kconfig
+++ b/drivers/net/wireless/hostap/Kconfig
@@ -1,6 +1,7 @@
 config HOSTAP
 	tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
-	depends on NET_RADIO
+	depends on WLAN_80211
+	select WIRELESS_EXT
 	select IEEE80211
 	select IEEE80211_CRYPT_WEP
 	---help---
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index 7e04dc9..cbedc9e 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -167,7 +167,7 @@ #undef LWNG_SETVAL
 
 	ret = skb->len - phdrlen;
 	skb->dev = dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, hdrlen);
 	if (prism_header)
 		skb_pull(skb, phdrlen);
@@ -933,12 +933,14 @@ #endif
 		if (frag == 0) {
 			/* copy first fragment (including full headers) into
 			 * beginning of the fragment cache skb */
-			memcpy(skb_put(frag_skb, flen), skb->data, flen);
+			skb_copy_from_linear_data(skb, skb_put(frag_skb, flen),
+						  flen);
 		} else {
 			/* append frame payload to the end of the fragment
 			 * cache skb */
-			memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
-			       flen);
+			skb_copy_from_linear_data_offset(skb, hdrlen,
+							 skb_put(frag_skb,
+								 flen), flen);
 		}
 		dev_kfree_skb(skb);
 		skb = NULL;
@@ -1044,8 +1046,9 @@ #endif
 	    skb->len >= ETH_HLEN + ETH_ALEN) {
 		/* Non-standard frame: get addr4 from its bogus location after
 		 * the payload */
-		memcpy(skb->data + ETH_ALEN,
-		       skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+		skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN,
+						 skb->data + ETH_ALEN,
+						 ETH_ALEN);
 		skb_trim(skb, skb->len - ETH_ALEN);
 	}
 
@@ -1073,17 +1076,17 @@ #endif
 
 	if (skb2 != NULL) {
 		/* send to wireless media */
-		skb2->protocol = __constant_htons(ETH_P_802_3);
-		skb2->mac.raw = skb2->nh.raw = skb2->data;
-		/* skb2->nh.raw = skb2->data + ETH_HLEN; */
 		skb2->dev = dev;
+		skb2->protocol = __constant_htons(ETH_P_802_3);
+		skb_reset_mac_header(skb2);
+		skb_reset_network_header(skb2);
+		/* skb2->network_header += ETH_HLEN; */
 		dev_queue_xmit(skb2);
 	}
 
 	if (skb) {
 		skb->protocol = eth_type_trans(skb, dev);
 		memset(skb->cb, 0, sizeof(skb->cb));
-		skb->dev = dev;
 		netif_rx(skb);
 	}
 
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 4a5be70..246fac0 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -146,7 +146,8 @@ int hostap_data_start_xmit(struct sk_buf
 			fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
 			/* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
 			 * Addr4 = SA */
-			memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+			skb_copy_from_linear_data_offset(skb, ETH_ALEN,
+							 &hdr.addr4, ETH_ALEN);
 			hdr_len += ETH_ALEN;
 		} else {
 			/* bogus 4-addr format to workaround Prism2 station
@@ -159,7 +160,8 @@ int hostap_data_start_xmit(struct sk_buf
 			/* SA from skb->data + ETH_ALEN will be added after
 			 * frame payload; use hdr.addr4 as a temporary buffer
 			 */
-			memcpy(&hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+			skb_copy_from_linear_data_offset(skb, ETH_ALEN,
+							 &hdr.addr4, ETH_ALEN);
 			need_tailroom += ETH_ALEN;
 		}
 
@@ -174,24 +176,27 @@ int hostap_data_start_xmit(struct sk_buf
 		else
 			memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
 		memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
-		memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+		skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
 	} else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
 		fc |= IEEE80211_FCTL_FROMDS;
 		/* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
-		memcpy(&hdr.addr1, skb->data, ETH_ALEN);
+		skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
 		memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
-		memcpy(&hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+		skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
+						 ETH_ALEN);
 	} else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
 		fc |= IEEE80211_FCTL_TODS;
 		/* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
 		memcpy(&hdr.addr1, to_assoc_ap ?
 		       local->assoc_ap_addr : local->bssid, ETH_ALEN);
-		memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-		memcpy(&hdr.addr3, skb->data, ETH_ALEN);
+		skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
+						 ETH_ALEN);
+		skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
 	} else if (local->iw_mode == IW_MODE_ADHOC) {
 		/* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
-		memcpy(&hdr.addr1, skb->data, ETH_ALEN);
-		memcpy(&hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+		skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
+		skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
+						 ETH_ALEN);
 		memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
 	}
 
@@ -237,7 +242,7 @@ int hostap_data_start_xmit(struct sk_buf
 	iface->stats.tx_packets++;
 	iface->stats.tx_bytes += skb->len;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	meta = (struct hostap_skb_tx_data *) skb->cb;
 	memset(meta, 0, sizeof(*meta));
 	meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index efb8cf3..5b3abd5 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1,8 +1,8 @@
 /*
  * Intersil Prism2 driver with Host AP (software access point) support
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * This file is to be included into hostap.c when S/W AP functionality is
  * compiled.
@@ -982,7 +982,8 @@ static void prism2_send_mgmt(struct net_
 	meta->tx_cb_idx = tx_cb_idx;
 
 	skb->dev = dev;
-	skb->mac.raw = skb->nh.raw = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
 	dev_queue_xmit(skb);
 }
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -1276,8 +1277,8 @@ static char * ap_auth_make_challenge(str
 		return NULL;
 	}
 
-	memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len,
-	       WLAN_AUTH_CHALLENGE_LEN);
+	skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len,
+					 tmpbuf, WLAN_AUTH_CHALLENGE_LEN);
 	dev_kfree_skb(skb);
 
 	return tmpbuf;
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 0162400..b31e6a0 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -368,9 +368,9 @@ enum {
 
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+offsetof(struct prism2_hostapd_param, u.rid.data)
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+offsetof(struct prism2_hostapd_param, u.generic_elem.data)
 
 /* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
  */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 8d8f4b9..ee1532b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,7 @@ #include <asm/io.h>
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static dev_info_t dev_info = "hostap_cs";
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -838,6 +838,8 @@ static struct pcmcia_device_id hostap_cs
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
 	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
+	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
+					 0x2d858104),
 	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
 					 0x74c5e40d),
 	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
@@ -848,6 +850,11 @@ static struct pcmcia_device_id hostap_cs
 		"Intersil", "PRISM 2_5 PCMCIA ADAPTER",	"ISL37300P",
 		"Eval-RevA",
 		0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+	/* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
+	PCMCIA_DEVICE_PROD_ID1234(
+		"D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
+		"A3",
+		0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
 	PCMCIA_DEVICE_PROD_ID123(
 		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
 		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 3079378..959887b 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.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
@@ -1838,13 +1838,14 @@ static int prism2_tx_80211(struct sk_buf
 
 	/* skb->data starts with txdesc->frame_control */
 	hdr_len = 24;
-	memcpy(&txdesc.frame_control, skb->data, hdr_len);
+	skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len);
  	fc = le16_to_cpu(txdesc.frame_control);
 	if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
 	    (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) &&
 	    skb->len >= 30) {
 		/* Addr4 */
-		memcpy(txdesc.addr4, skb->data + hdr_len, ETH_ALEN);
+		skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4,
+						 ETH_ALEN);
 		hdr_len += ETH_ALEN;
 	}
 
@@ -2217,7 +2218,7 @@ static void hostap_tx_callback(local_inf
 		memcpy(skb_put(skb, len), payload, len);
 
 	skb->dev = local->dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 
 	cb->func(skb, ok, cb->data);
 }
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index cb08bc5..cdea7f7 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1,7 +1,6 @@
 /* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
 
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/ethtool.h>
 #include <net/ieee80211_crypt.h>
 
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 9077e6e..4743426 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.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
@@ -590,20 +590,20 @@ void hostap_dump_tx_header(const char *n
 
 int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
-	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); /* addr2 */
+	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 	return ETH_ALEN;
 }
 
 
 int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
-	if (*(u32 *)skb->mac.raw == LWNG_CAP_DID_BASE) {
-		memcpy(haddr, skb->mac.raw +
-		       sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+	const unsigned char *mac = skb_mac_header(skb);
+
+	if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
+		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
 		       ETH_ALEN); /* addr2 */
-	} else { /* (*(u32 *)skb->mac.raw == htonl(LWNG_CAPHDR_VERSION)) */
-		memcpy(haddr, skb->mac.raw +
-		       sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+	} else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
+		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
 		       ETH_ALEN); /* addr2 */
 	}
 	return ETH_ALEN;
@@ -1063,7 +1063,8 @@ int prism2_sta_send_mgmt(local_info_t *l
 	meta->iface = netdev_priv(dev);
 
 	skb->dev = dev;
-	skb->mac.raw = skb->nh.raw = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
 	dev_queue_xmit(skb);
 
 	return 0;
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index c4f6020..db4899e 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,7 @@ #include <asm/io.h>
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_pci";
 
 
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index e235e06..f0fd5ec 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,7 @@ #include <asm/io.h>
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_plx";
 
 
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index ad6e4a4..d51daf8 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -28,8 +28,8 @@
 
   Portions of this file are based on the Host AP project,
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-    <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+    <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
   ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
@@ -2416,8 +2416,9 @@ static void isr_rx(struct ipw2100_priv *
 #ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
-	memcpy(packet_data, packet->skb->data,
-	       min_t(u32, status->frame_size, IPW_RX_NIC_BUFFER_LENGTH));
+	skb_copy_from_linear_data(packet->skb, packet_data,
+				  min_t(u32, status->frame_size,
+					     IPW_RX_NIC_BUFFER_LENGTH));
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index c878a2f..7cb2052 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct de
 static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
 		   show_net_stats, store_net_stats);
 
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+	int len = 0, i;
+
+	len = sprintf(&buf[len],
+		      "Displaying %d channels in 2.4Ghz band "
+		      "(802.11bg):\n", geo->bg_channels);
+
+	for (i = 0; i < geo->bg_channels; i++) {
+		len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
+			       geo->bg[i].channel,
+			       geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+			       " (radar spectrum)" : "",
+			       ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
+				(geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+			       ? "" : ", IBSS",
+			       geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+			       "passive only" : "active/passive",
+			       geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+			       "B" : "B/G");
+	}
+
+	len += sprintf(&buf[len],
+		       "Displaying %d channels in 5.2Ghz band "
+		       "(802.11a):\n", geo->a_channels);
+	for (i = 0; i < geo->a_channels; i++) {
+		len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
+			       geo->a[i].channel,
+			       geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+			       " (radar spectrum)" : "",
+			       ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
+				(geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+			       ? "" : ", IBSS",
+			       geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+			       "passive only" : "active/passive");
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
 static void notify_wx_assoc_event(struct ipw_priv *priv)
 {
 	union iwreq_data wrqu;
@@ -8133,7 +8179,7 @@ static void ipw_handle_mgmt_packet(struc
 		skb->dev = priv->ieee->dev;
 
 		/* Point raw at the ieee80211_stats */
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 
 		skb->pkt_type = PACKET_OTHERHOST;
 		skb->protocol = __constant_htons(ETH_P_80211_STATS);
@@ -10355,7 +10401,7 @@ static void ipw_handle_promiscuous_tx(st
 
 		rt_hdr->it_len = dst->len;
 
-		memcpy(skb_put(dst, len), src->data, len);
+		skb_copy_from_linear_data(src, skb_put(dst, len), len);
 
 		if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats))
 			dev_kfree_skb_any(dst);
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entri
 	&dev_attr_led.attr,
 	&dev_attr_speed_scan.attr,
 	&dev_attr_net_stats.attr,
+	&dev_attr_channels.attr,
 #ifdef CONFIG_IPW2200_PROMISCUOUS
 	&dev_attr_rtap_iface.attr,
 	&dev_attr_rtap_filter.attr,
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644
index 0000000..e0ecc4d
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.c
@@ -0,0 +1,754 @@
+/**
+  * This file contains functions for 802.11D.
+  */
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+
+#include "host.h"
+#include "decl.h"
+#include "11d.h"
+#include "dev.h"
+#include "wext.h"
+
+#define TX_PWR_DEFAULT	10
+
+static struct region_code_mapping region_code_mapping[] = {
+	{"US ", 0x10},		/* US FCC      */
+	{"CA ", 0x10},		/* IC Canada   */
+	{"SG ", 0x10},		/* Singapore   */
+	{"EU ", 0x30},		/* ETSI        */
+	{"AU ", 0x30},		/* Australia   */
+	{"KR ", 0x30},		/* Republic Of Korea */
+	{"ES ", 0x31},		/* Spain       */
+	{"FR ", 0x32},		/* France      */
+	{"JP ", 0x40},		/* Japan       */
+};
+
+/* Following 2 structure defines the supported channels */
+static struct chan_freq_power channel_freq_power_UN_BG[] = {
+	{1, 2412, TX_PWR_DEFAULT},
+	{2, 2417, TX_PWR_DEFAULT},
+	{3, 2422, TX_PWR_DEFAULT},
+	{4, 2427, TX_PWR_DEFAULT},
+	{5, 2432, TX_PWR_DEFAULT},
+	{6, 2437, TX_PWR_DEFAULT},
+	{7, 2442, TX_PWR_DEFAULT},
+	{8, 2447, TX_PWR_DEFAULT},
+	{9, 2452, TX_PWR_DEFAULT},
+	{10, 2457, TX_PWR_DEFAULT},
+	{11, 2462, TX_PWR_DEFAULT},
+	{12, 2467, TX_PWR_DEFAULT},
+	{13, 2472, TX_PWR_DEFAULT},
+	{14, 2484, TX_PWR_DEFAULT}
+};
+
+static u8 wlan_region_2_code(u8 * region)
+{
+	u8 i;
+	u8 size = sizeof(region_code_mapping)/
+		  sizeof(struct region_code_mapping);
+
+	for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+		region[i] = toupper(region[i]);
+
+	for (i = 0; i < size; i++) {
+		if (!memcmp(region, region_code_mapping[i].region,
+			    COUNTRY_CODE_LEN))
+			return (region_code_mapping[i].code);
+	}
+
+	/* default is US */
+	return (region_code_mapping[0].code);
+}
+
+static u8 *wlan_code_2_region(u8 code)
+{
+	u8 i;
+	u8 size = sizeof(region_code_mapping)
+		  / sizeof(struct region_code_mapping);
+	for (i = 0; i < size; i++) {
+		if (region_code_mapping[i].code == code)
+			return (region_code_mapping[i].region);
+	}
+	/* default is US */
+	return (region_code_mapping[0].region);
+}
+
+/**
+ *  @brief This function finds the nrchan-th chan after the firstchan
+ *  @param band       band
+ *  @param firstchan  first channel number
+ *  @param nrchan   number of channels
+ *  @return 	      the nrchan-th chan number
+*/
+static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+/*find the nrchan-th chan after the firstchan*/
+{
+	u8 i;
+	struct chan_freq_power *cfp;
+	u8 cfp_no;
+
+	cfp = channel_freq_power_UN_BG;
+	cfp_no = sizeof(channel_freq_power_UN_BG) /
+	    sizeof(struct chan_freq_power);
+
+	for (i = 0; i < cfp_no; i++) {
+		if ((cfp + i)->channel == firstchan) {
+			lbs_pr_debug(1, "firstchan found\n");
+			break;
+		}
+	}
+
+	if (i < cfp_no) {
+		/*if beyond the boundary */
+		if (i + nrchan < cfp_no) {
+			*chan = (cfp + i + nrchan)->channel;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  @brief This function Checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return 	                TRUE; FALSE
+*/
+static u8 wlan_channel_known_11d(u8 chan,
+			  struct parsed_region_chan_11d * parsed_region_chan)
+{
+	struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
+	u8 nr_chan = parsed_region_chan->nr_chan;
+	u8 i = 0;
+
+	lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+		sizeof(struct chan_power_11d) * nr_chan);
+
+	for (i = 0; i < nr_chan; i++) {
+		if (chan == chanpwr[i].chan) {
+			lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
+			return 1;
+		}
+	}
+
+	lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
+	return 0;
+}
+
+u32 libertas_chan_2_freq(u8 chan, u8 band)
+{
+	struct chan_freq_power *cf;
+	u16 cnt;
+	u16 i;
+	u32 freq = 0;
+
+	cf = channel_freq_power_UN_BG;
+	cnt =
+	    sizeof(channel_freq_power_UN_BG) /
+	    sizeof(struct chan_freq_power);
+
+	for (i = 0; i < cnt; i++) {
+		if (chan == cf[i].channel)
+			freq = cf[i].freq;
+	}
+
+	return freq;
+}
+
+static int generate_domain_info_11d(struct parsed_region_chan_11d
+				  *parsed_region_chan,
+				  struct wlan_802_11d_domain_reg * domaininfo)
+{
+	u8 nr_subband = 0;
+
+	u8 nr_chan = parsed_region_chan->nr_chan;
+	u8 nr_parsedchan = 0;
+
+	u8 firstchan = 0, nextchan = 0, maxpwr = 0;
+
+	u8 i, flag = 0;
+
+	memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+	       COUNTRY_CODE_LEN);
+
+	lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
+	lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+		sizeof(struct parsed_region_chan_11d));
+
+	for (i = 0; i < nr_chan; i++) {
+		if (!flag) {
+			flag = 1;
+			nextchan = firstchan =
+			    parsed_region_chan->chanpwr[i].chan;
+			maxpwr = parsed_region_chan->chanpwr[i].pwr;
+			nr_parsedchan = 1;
+			continue;
+		}
+
+		if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
+		    parsed_region_chan->chanpwr[i].pwr == maxpwr) {
+			nextchan++;
+			nr_parsedchan++;
+		} else {
+			domaininfo->subband[nr_subband].firstchan = firstchan;
+			domaininfo->subband[nr_subband].nrchan =
+			    nr_parsedchan;
+			domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+			nr_subband++;
+			nextchan = firstchan =
+			    parsed_region_chan->chanpwr[i].chan;
+			maxpwr = parsed_region_chan->chanpwr[i].pwr;
+		}
+	}
+
+	if (flag) {
+		domaininfo->subband[nr_subband].firstchan = firstchan;
+		domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
+		domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+		nr_subband++;
+	}
+	domaininfo->nr_subband = nr_subband;
+
+	lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
+	lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+		COUNTRY_CODE_LEN + 1 +
+		sizeof(struct ieeetypes_subbandset) * nr_subband);
+	return 0;
+}
+
+/**
+ *  @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region_chan          pointer to struct region_channel
+ *  @param *parsed_region_chan  pointer to parsed_region_chan_11d
+ *  @return 	                N/A
+*/
+static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
+					  struct parsed_region_chan_11d *
+					  parsed_region_chan)
+{
+	u8 i;
+	struct chan_freq_power *cfp;
+
+	if (region_chan == NULL) {
+		lbs_pr_debug(1, "11D: region_chan is NULL\n");
+		return;
+	}
+
+	cfp = region_chan->CFP;
+	if (cfp == NULL) {
+		lbs_pr_debug(1, "11D: cfp equal NULL \n");
+		return;
+	}
+
+	parsed_region_chan->band = region_chan->band;
+	parsed_region_chan->region = region_chan->region;
+	memcpy(parsed_region_chan->countrycode,
+	       wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+
+	lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+	       parsed_region_chan->band);
+
+	for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
+		parsed_region_chan->chanpwr[i].chan = cfp->channel;
+		parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
+		lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
+		       parsed_region_chan->chanpwr[i].chan,
+		       parsed_region_chan->chanpwr[i].pwr);
+	}
+	parsed_region_chan->nr_chan = region_chan->nrcfp;
+
+	lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+
+	return;
+}
+
+/**
+ *  @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ *  @param region               region ID
+ *  @param band                 band
+ *  @param chan                 chan
+ *  @return 	                TRUE;FALSE
+*/
+static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+	struct chan_freq_power *cfp;
+	int cfp_no;
+	u8 idx;
+
+	ENTER();
+
+	cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+	if (cfp == NULL)
+		return 0;
+
+	for (idx = 0; idx < cfp_no; idx++) {
+		if (chan == (cfp + idx)->channel) {
+			/* If Mrvl Chip Supported? */
+			if ((cfp + idx)->unsupported) {
+				return 0;
+			} else {
+				return 1;
+			}
+		}
+	}
+
+	/*chan is not in the region table */
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function checks if chan txpwr is learned from AP/IBSS
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return 	                0
+*/
+static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
+				 countryinfo,
+				 u8 band,
+				 struct parsed_region_chan_11d *
+				 parsed_region_chan)
+{
+	u8 nr_subband, nrchan;
+	u8 lastchan, firstchan;
+	u8 region;
+	u8 curchan = 0;
+
+	u8 idx = 0;		/*chan index in parsed_region_chan */
+
+	u8 j, i;
+
+	ENTER();
+
+	/*validation Rules:
+	   1. valid region Code
+	   2. First Chan increment
+	   3. channel range no overlap
+	   4. channel is valid?
+	   5. channel is supported by region?
+	   6. Others
+	 */
+
+	lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+
+	if ((*(countryinfo->countrycode)) == 0
+	    || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+		/* No region Info or Wrong region info: treat as No 11D info */
+		LEAVE();
+		return 0;
+	}
+
+	/*Step1: check region_code */
+	parsed_region_chan->region = region =
+	    wlan_region_2_code(countryinfo->countrycode);
+
+	lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
+	lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+		COUNTRY_CODE_LEN);
+
+	parsed_region_chan->band = band;
+
+	memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
+	       COUNTRY_CODE_LEN);
+
+	nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
+	    sizeof(struct ieeetypes_subbandset);
+
+	for (j = 0, lastchan = 0; j < nr_subband; j++) {
+
+		if (countryinfo->subband[j].firstchan <= lastchan) {
+			/*Step2&3. Check First Chan Num increment and no overlap */
+			lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
+			       countryinfo->subband[j].firstchan, lastchan);
+			continue;
+		}
+
+		firstchan = countryinfo->subband[j].firstchan;
+		nrchan = countryinfo->subband[j].nrchan;
+
+		for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+			/*step4: channel is supported? */
+
+			if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+				/* Chan is not found in UN table */
+				lbs_pr_debug(1, "chan is not supported: %d \n", i);
+				break;
+			}
+
+			lastchan = curchan;
+
+			if (wlan_region_chan_supported_11d
+			    (region, band, curchan)) {
+				/*step5: Check if curchan is supported by mrvl in region */
+				parsed_region_chan->chanpwr[idx].chan = curchan;
+				parsed_region_chan->chanpwr[idx].pwr =
+				    countryinfo->subband[j].maxtxpwr;
+				idx++;
+			} else {
+				/*not supported and ignore the chan */
+				lbs_pr_debug(1,
+				       "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+				       i, curchan, region, band);
+			}
+		}
+
+		/*Step6: Add other checking if any */
+
+	}
+
+	parsed_region_chan->nr_chan = idx;
+
+	lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
+	lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+		2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function calculates the scan type for channels
+ *  @param chan                 chan number
+ *  @param parsed_region_chan   pointer to parsed_region_chan_11d
+ *  @return 	                PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8 libertas_get_scan_type_11d(u8 chan,
+			  struct parsed_region_chan_11d * parsed_region_chan)
+{
+	u8 scan_type = cmd_scan_type_passive;
+
+	ENTER();
+
+	if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+		lbs_pr_debug(1, "11D: Found and do Active Scan\n");
+		scan_type = cmd_scan_type_active;
+	} else {
+		lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
+	}
+
+	LEAVE();
+	return scan_type;
+
+}
+
+void libertas_init_11d(wlan_private * priv)
+{
+	priv->adapter->enable11d = 0;
+	memset(&(priv->adapter->parsed_region_chan), 0,
+	       sizeof(struct parsed_region_chan_11d));
+	return;
+}
+
+static int wlan_enable_11d(wlan_private * priv, u8 flag)
+{
+	int ret;
+
+	priv->adapter->enable11d = flag;
+
+	/* send cmd to FW to enable/disable 11D function in FW */
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    OID_802_11D_ENABLE,
+				    &priv->adapter->enable11d);
+	if (ret)
+		lbs_pr_debug(1, "11D: Fail to enable 11D \n");
+
+	return 0;
+}
+
+/**
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to wlan_private
+ *  @return 	      0; -1
+*/
+static int set_domain_info_11d(wlan_private * priv)
+{
+	int ret;
+
+	if (!priv->adapter->enable11d) {
+		lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
+		return 0;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+	if (ret)
+		lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
+
+	return ret;
+}
+
+/**
+ *  @brief This function setups scan channels
+ *  @param priv       pointer to wlan_private
+ *  @param band       band
+ *  @return 	      0
+*/
+int libertas_set_universaltable(wlan_private * priv, u8 band)
+{
+	wlan_adapter *adapter = priv->adapter;
+	u16 size = sizeof(struct chan_freq_power);
+	u16 i = 0;
+
+	memset(adapter->universal_channel, 0,
+	       sizeof(adapter->universal_channel));
+
+	adapter->universal_channel[i].nrcfp =
+	    sizeof(channel_freq_power_UN_BG) / size;
+	lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
+	       adapter->universal_channel[i].nrcfp);
+
+	adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+	adapter->universal_channel[i].valid = 1;
+	adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+	adapter->universal_channel[i].band = band;
+	i++;
+
+	return 0;
+}
+
+/**
+ *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ *  @param priv       pointer to wlan_private
+ *  @param cmd        pointer to cmd buffer
+ *  @param cmdno      cmd ID
+ *  @param cmdOption  cmd action
+ *  @return 	      0
+*/
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *cmd, u16 cmdno,
+				 u16 cmdoption)
+{
+	struct cmd_ds_802_11d_domain_info *pdomaininfo =
+	    &cmd->params.domaininfo;
+	struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+	wlan_adapter *adapter = priv->adapter;
+	u8 nr_subband = adapter->domainreg.nr_subband;
+
+	ENTER();
+
+	lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
+
+	cmd->command = cpu_to_le16(cmdno);
+	pdomaininfo->action = cpu_to_le16(cmdoption);
+	if (cmdoption == cmd_act_get) {
+		cmd->size =
+		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+		lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+			(int)(cmd->size));
+		LEAVE();
+		return 0;
+	}
+
+	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+	memcpy(domain->countrycode, adapter->domainreg.countrycode,
+	       sizeof(domain->countrycode));
+
+	domain->header.len =
+	    cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+			     sizeof(domain->countrycode));
+
+	if (nr_subband) {
+		memcpy(domain->subband, adapter->domainreg.subband,
+		       nr_subband * sizeof(struct ieeetypes_subbandset));
+
+		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+					     domain->header.len +
+					     sizeof(struct mrvlietypesheader) +
+					     S_DS_GEN);
+	} else {
+		cmd->size =
+		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+	}
+
+	lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
+
+	LEAVE();
+
+	return 0;
+}
+
+/**
+ *  @brief This function implements private cmd: enable/disable 11D
+ *  @param priv    pointer to wlan_private
+ *  @param wrq     pointer to user data
+ *  @return 	   0 or -1
+ */
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+	int data = 0;
+	int *val;
+
+	ENTER();
+	data = SUBCMD_DATA(wrq);
+
+	lbs_pr_debug(1, "enable 11D: %s\n",
+	       (data == 1) ? "enable" : "Disable");
+
+	wlan_enable_11d(priv, data);
+	val = (int *)wrq->u.name;
+	*val = priv->adapter->enable11d;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @param resp    pointer to command response buffer
+ *  @return 	   0; -1
+ */
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11d_domain_info
+	*domaininfo = &resp->params.domaininforesp;
+	struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+	u16 action = le16_to_cpu(domaininfo->action);
+	s16 ret = 0;
+	u8 nr_subband = 0;
+
+	ENTER();
+
+	lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+		(int)le16_to_cpu(resp->size));
+
+	nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
+	/* countrycode 3 bytes */
+
+	lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+
+	if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
+		lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
+		return -1;
+	}
+
+	switch (action) {
+	case cmd_act_set:	/*Proc Set action */
+		break;
+
+	case cmd_act_get:
+		break;
+	default:
+		lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
+		ret = -1;
+		break;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   0; -1
+ */
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+	if (priv->adapter->enable11d) {
+		memset(&adapter->parsed_region_chan, 0,
+		       sizeof(struct parsed_region_chan_11d));
+		ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
+					       countryinfo, 0,
+					       &adapter->parsed_region_chan);
+
+		if (ret == -1) {
+			lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
+			LEAVE();
+			return ret;
+		}
+
+		memset(&adapter->domainreg, 0,
+		       sizeof(struct wlan_802_11d_domain_reg));
+		generate_domain_info_11d(&adapter->parsed_region_chan,
+				      &adapter->domainreg);
+
+		ret = set_domain_info_11d(priv);
+
+		if (ret) {
+			lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+			LEAVE();
+			return ret;
+		}
+	}
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function generates 11D info from user specified regioncode and download to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   0; -1
+ */
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+	struct region_channel *region_chan;
+	u8 j;
+
+	ENTER();
+	lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+
+	if (priv->adapter->enable11d) {
+		/* update parsed_region_chan_11; dnld domaininf to FW */
+
+		for (j = 0; j < sizeof(adapter->region_channel) /
+		     sizeof(adapter->region_channel[0]); j++) {
+			region_chan = &adapter->region_channel[j];
+
+			lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
+			       region_chan->band);
+
+			if (!region_chan || !region_chan->valid
+			    || !region_chan->CFP)
+				continue;
+			if (region_chan->band != adapter->curbssparams.band)
+				continue;
+			break;
+		}
+
+		if (j >= sizeof(adapter->region_channel) /
+		    sizeof(adapter->region_channel[0])) {
+			lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
+			       adapter->curbssparams.band);
+			LEAVE();
+			return -1;
+		}
+
+		memset(&adapter->parsed_region_chan, 0,
+		       sizeof(struct parsed_region_chan_11d));
+		wlan_generate_parsed_region_chan_11d(region_chan,
+						     &adapter->
+						     parsed_region_chan);
+
+		memset(&adapter->domainreg, 0,
+		       sizeof(struct wlan_802_11d_domain_reg));
+		generate_domain_info_11d(&adapter->parsed_region_chan,
+					 &adapter->domainreg);
+
+		ret = set_domain_info_11d(priv);
+
+		if (ret) {
+			lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+			LEAVE();
+			return ret;
+		}
+
+	}
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644
index 0000000..db2ebea
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.h
@@ -0,0 +1,105 @@
+/**
+  * This header file contains data structures and
+  * function declarations of 802.11d
+  */
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#include "types.h"
+#include "defs.h"
+
+#define UNIVERSAL_REGION_CODE			0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
+ */
+#define MRVDRV_MAX_SUBBAND_802_11D		83
+
+#define COUNTRY_CODE_LEN			3
+#define MAX_NO_OF_CHAN 				40
+
+struct cmd_ds_command;
+
+/** Data structure for Country IE*/
+struct ieeetypes_subbandset {
+	u8 firstchan;
+	u8 nrchan;
+	u8 maxtxpwr;
+} __attribute__ ((packed));
+
+struct ieeetypes_countryinfoset {
+	u8 element_id;
+	u8 len;
+	u8 countrycode[COUNTRY_CODE_LEN];
+	struct ieeetypes_subbandset subband[1];
+};
+
+struct ieeetypes_countryinfofullset {
+	u8 element_id;
+	u8 len;
+	u8 countrycode[COUNTRY_CODE_LEN];
+	struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __attribute__ ((packed));
+
+struct mrvlietypes_domainparamset {
+	struct mrvlietypesheader header;
+	u8 countrycode[COUNTRY_CODE_LEN];
+	struct ieeetypes_subbandset subband[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+	u16 action;
+	struct mrvlietypes_domainparamset domain;
+} __attribute__ ((packed));
+
+/** domain regulatory information */
+struct wlan_802_11d_domain_reg {
+	/** country Code*/
+	u8 countrycode[COUNTRY_CODE_LEN];
+	/** No. of subband*/
+	u8 nr_subband;
+	struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+};
+
+struct chan_power_11d {
+	u8 chan;
+	u8 pwr;
+} __attribute__ ((packed));
+
+struct parsed_region_chan_11d {
+	u8 band;
+	u8 region;
+	s8 countrycode[COUNTRY_CODE_LEN];
+	struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
+	u8 nr_chan;
+} __attribute__ ((packed));
+
+struct region_code_mapping {
+	u8 region[COUNTRY_CODE_LEN];
+	u8 code;
+};
+
+u8 libertas_get_scan_type_11d(u8 chan,
+			  struct parsed_region_chan_11d *parsed_region_chan);
+
+u32 libertas_chan_2_freq(u8 chan, u8 band);
+
+enum state_11d libertas_get_state_11d(wlan_private * priv);
+
+void libertas_init_11d(wlan_private * priv);
+
+int libertas_set_universaltable(wlan_private * priv, u8 band);
+
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *cmd, u16 cmdno,
+				 u16 cmdOption);
+
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *resp);
+
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
+
+#endif				/* _WLAN_11D_ */
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644
index 0000000..8862742
--- /dev/null
+++ b/drivers/net/wireless/libertas/LICENSE
@@ -0,0 +1,16 @@
+  Copyright (c) 2003-2006, Marvell International Ltd.
+  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.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You 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.
+
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644
index 0000000..19c9350
--- /dev/null
+++ b/drivers/net/wireless/libertas/Makefile
@@ -0,0 +1,21 @@
+# EXTRA_CFLAGS += -Wpacked
+
+usb8xxx-objs := main.o fw.o wext.o \
+		rx.o tx.o cmd.o 	  \
+		cmdresp.o scan.o	  \
+		join.o 11d.o 		  \
+		ioctl.o debugfs.o	  \
+		ethtool.o assoc.o
+
+ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
+endif
+
+
+# This is needed to support the newer boot2 bootloader (v >= 3104)
+EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
+usb8xxx-objs += if_bootcmd.o
+usb8xxx-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644
index 0000000..688da4c
--- /dev/null
+++ b/drivers/net/wireless/libertas/README
@@ -0,0 +1,1044 @@
+================================================================================
+			README for USB8388
+
+ (c) Copyright © 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License").  You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the license.txt file or by writing to
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ this warranty disclaimer.
+================================================================================
+
+=====================
+DRIVER LOADING
+=====================
+
+	o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
+
+	o. Load driver by using the following command:
+
+		insmod usb8388.ko [fw_name=usb8388.bin]
+
+=====================
+IWPRIV COMMAND
+=====================
+
+NAME
+	This manual describes the usage of private commands used in Marvell WLAN
+	Linux Driver. All the commands available in Wlanconfig will not be available
+	in the iwpriv.
+
+SYNOPSIS
+	iwpriv <ethX> <command> [sub-command] ...
+
+	iwpriv ethX version
+	iwpriv ethX scantype [sub-command]
+	iwpriv ethX getSNR <n>
+	iwpriv ethX getNF <n>
+	iwpriv ethX getRSSI <n>
+	iwpriv ethX setrxant <n>
+	iwpriv ethX getrxant
+	iwpriv ethX settxant <n>
+	iwpriv ethX gettxant
+	iwpriv ethX authalgs <n>
+	iwpriv ethX pre-TBTT <n>
+	iwpriv ethX 8021xauthalgs <n>
+	iwpriv ethX encryptionmode <n>
+	iwpriv ethX setregioncode <n>
+	iwpriv ethX getregioncode
+	iwpriv ethX setbcnavg <n>
+	iwpriv ethX getbcnavg
+	iwpriv ethX setdataavg <n>
+	iwpriv ethX setlisteninter <n>
+	iwpriv ethX getlisteninter
+	iwpriv ethX setmultipledtim <n>
+	iwpriv ethX getmultipledtim
+	iwpriv ethX atimwindow <n>
+	iwpriv ethX deauth
+	iwpriv ethX adhocstop
+	iwpriv ethX radioon
+	iwpriv ethX radiooff
+	iwpriv ethX reasso-on
+	iwpriv ethX reasso-off
+	iwpriv ethX scanmode  [sub-command]
+	iwpriv ethX setwpaie <n>
+	iwpriv ethX wlanidle-off
+	iwpriv ethX wlanidle-on
+	iwpriv ethX getcis
+	iwpriv ethX getlog
+	iwpriv ethX getadhocstatus
+	iwpriv ethX adhocgrate <n>
+
+Version 4 Command:
+	iwpriv ethX inactvityto <n>
+	iwpriv ethX sleeppd <n>
+	iwpriv ethX enable11d <n>
+	iwpriv ethX tpccfg <n>
+	iwpriv ethX powercfg <n>
+	iwpriv ethX setafc <n>
+	iwpriv ethX getafc
+
+Version 5 Command:
+	iwpriv ethX ledgpio <n>
+	iwpriv ethX scanprobes <n>
+	iwpriv ethX lolisteninter <n>
+	iwpriv ethX rateadapt <n> <m>
+	iwpriv ethX txcontrol <n>
+	iwpriv ethX psnullinterval <n>
+	iwpriv ethX prescan <n>
+	iwpriv ethX getrxinfo
+	iwpriv ethX gettxrate
+	iwpriv ethX beaconinterval
+
+BT Commands:
+	The blinding table (BT) contains a list of mac addresses that should be
+	ignored by the firmware.  It is primarily used for debugging and
+	testing networks.  It can be edited and inspected with the following
+	commands:
+
+	iwpriv ethX bt_reset
+	iwpriv ethX bt_add <mac_address>
+	iwpriv ethX bt_del <mac_address>
+	iwpriv ethX bt_list <id>
+
+FWT Commands:
+	The forwarding table (FWT) is a feature used to manage mesh network
+	routing in the firmware.  The FWT is essentially a routing table that
+	associates a destination mac address (da) with a next hop receiver
+	address (ra).  The FWT can be inspected and edited with the following
+	iwpriv commands, which are described in greater detail below.
+	Eventually, the table will be automatically maintained by a custom
+	routing protocol.
+
+	NOTE: FWT commands replace the previous DFT commands.  What were the DFT
+	commands?, you might ask.  They were an earlier API to the firmware that
+	implemented a simple MAC-layer forwarding mechanism.  In the unlikely
+	event that you were using these commands, you must migrate to the new
+	FWT commands which can be used to achieve the same functionality.
+
+	iwpriv ethX fwt_add [parameters]
+	iwpriv ethX fwt_del [parameters]
+	iwpriv ethX fwt_lookup [parameters]
+	iwpriv ethX fwt_list [parameters]
+	iwpriv ethX fwt_list_route [parameters]
+	iwpriv ethX fwt_list_neigh [parameters]
+	iwpriv ethX fwt_reset [parameters]
+	iwpriv ethX fwt_cleanup
+	iwpriv ethX fwt_time
+
+MESH Commands:
+
+	The MESH commands are used to configure various features of the mesh
+	routing protocol.  The following commands are supported:
+
+	iwpriv ethX mesh_get_ttl
+	iwpriv ethX mesh_set_ttl ttl
+
+DESCRIPTION
+	Those commands are used to send additional commands to the Marvell WLAN
+	card via the Linux device driver.
+
+	The ethX parameter specifies the network device that is to be used to
+		perform this command on. it could be eth0, eth1 etc.
+
+version
+	This is used to get the current version of the driver and the firmware.
+
+scantype
+	This command is used to set the scan type to be used by the driver in
+	the scan command. This setting will not be used while performing a scan
+	for a specific SSID, as it is always done with scan type being active.
+
+	where the sub-commands are: -
+			active 	-- to set the scan type to active
+			passive -- to set the scan type to passive
+			get 	-- to get the scan type set in the driver
+
+getSNR
+	This command gets the average and non average value of Signal to Noise
+	Ratio of Beacon and Data.
+
+	where value is:-
+			0 	-- Beacon non-average.
+			1 	-- Beacon average.
+			2 	-- Data non-average.
+			3 	-- Data average.
+
+	If no value is given, all four values are returned in the order mentioned
+	above.
+
+	Note: This command is available only when STA is connected.
+
+getRSSI
+	This command gets the average and non average value os Receive Signal
+	Strength of Beacon and Data.
+
+	where value is:-
+			0 	-- Beacon non-average.
+			1 	-- Beacon average.
+			2 	-- Data non-average.
+			3 	-- Data average.
+
+	Note: This command is available only when STA is connected.
+
+getNF
+	This command gets the average and non average value of Noise Floor of
+	Beacon and Data.
+
+	where value is:-
+			0 	-- Beacon non-average.
+			1 	-- Beacon average.
+			2 	-- Data non-average.
+			3 	-- Data average.
+
+	Note: This command is available only when STA is connected.
+
+setrxant
+	This command is used to set the mode for Rx antenna.
+
+	The options that can be sent are:-
+			1 	-- Antenna 1.
+			2 	-- Antenna 2.
+			0xFFFF 	-- Diversity.
+
+	Usage:
+		iwpriv ethX setrxant 0x01: select Antenna 1.
+
+getrxant
+	This command is used to get the mode for Rx antenna.
+
+
+settxant
+	This command is used to set the mode for Tx antenna.
+		The options that can be sent are:-
+			1 	-- Antenna 1.
+			2 	-- Antenna 2.
+			0xFFFF 	-- Diversity.
+	Usage:
+		iwpriv ethX settxant 0x01: select Antenna 1.
+
+gettxant
+	This command is used to get the mode for Tx antenna.
+
+authalgs
+	This command is used by the WPA supplicant to set the authentication
+	algorithms in the station.
+
+8021xauthalgs
+	This command is used by the WPA supplicant to set the 8021.x authentication algorithm type
+	station.
+
+	where values can be:-
+			1 	-- None
+			2 	-- LEAP
+			4 	-- TLS
+			8 	-- TTLs
+			16	-- MD5
+
+
+encryptionmode
+	This command is used by the WPA supplicant to set the encryption algorithm.
+
+	where values can be:-
+			0 	-- NONE
+			1 	-- WEP40
+			2 	-- TKIP
+			3 	-- CCMP
+			4 	-- WEP104
+
+pre-TBTT
+	This command is used to set pre-TBTT time period where value is in microseconds.
+
+setregioncode
+	This command is used to set the region code in the station.
+	where value is 'region code' for various regions like
+	USA FCC, Canada IC, Spain, France, Europe ETSI,	Japan ...
+
+	Usage:
+		iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode
+	This command is used to get the region code information set in the
+	station.
+
+setbcnavg
+	Set the weighting factor for calculating RSSI.
+
+getbcnavg
+	Get weighting factor for calculating RSSI.
+
+setdataavg
+	Set the weighting factor for calculating SNR.
+
+setlisteninter
+	This command is used to set the listen interval in the
+	station.
+
+	where the value ranges between 1 - 255
+
+getlisteninter
+	This command is used to get the listen interval value set in the
+	station.
+
+setmultipledtim
+	This command is used to set the multiple dtim value in the
+	station.
+		where the value is 1,2,3,4,5,0xfffe
+		0xfffe means the firmware will use listen interval in association
+		command for waking up
+
+getmultipledtim
+	This command is used to get the multiple dtim value set in the station.
+
+atimwindow
+	This command is used to set the atim value in the
+	station.
+
+	where the value ranges between 0 - 50
+
+deauth
+	This command is used to send the de-authentication to the AP with which
+	the station is associated. This command is valid only when
+	station is in Infrastructure mode.
+
+	Note: This command is available only when STA is connected.
+
+adhocstop
+	This command is used to stop beacon transmission from the station and
+	go into idle state in ad-hoc mode.
+
+	Note: This command is available only when STA is connected.
+
+radioon
+	This command is used to turn on the RF antenna.
+
+radiooff
+	This command is sued to turn off the RF antenna.
+
+scanmode
+	This command is used to set the station to scan for either IBSS
+	networks or BSS networks or both BSS and IBSS networks. This
+	command can be used with sub commands,
+
+	where the value for
+			bss 	-- Scan All the BSS networks.
+			ibss 	-- Scan All the IBSS networks.
+			any 	-- Scan both BSS and IBSS networks.
+
+
+
+setwpaie
+	This command is used by WPA supplicant to send the WPA-IE to the driver.
+
+wlanidle-off
+	This command is used to get into idle state.
+
+	Note: This command is available only when STA is connected.
+
+wlanidle-on
+	This command is used to get off the idle state.
+
+	Note: This command is available only when STA is connected.
+
+
+getlog
+	This command is used to get the 802.11 statistics available in the
+		station.
+
+	Note: This command is available only when STA is connected.
+
+getadhocstatus
+	This command is used to get the ad-hoc Network Status.
+
+	The various status codes are:
+		AdhocStarted
+		AdhocJoined
+		AdhocIdle
+		InfraMode
+		AutoUnknownMode
+
+	Note: This command is available only when STA is connected.
+
+adhocgrate
+	This command is used to enable(1) g_rate, Disable(0) g_rate
+	and request(2) the status which g_rate is disabled/enabled,
+	for Ad-hoc creator.
+
+	where value is:-
+		0	-- Disabled
+		1	-- Enabled
+		2	-- Get
+
+ledgpio
+	This command is used to set/get LEDs.
+
+	iwpriv ethX ledgpio <LEDs>
+		will set the corresponding LED for the GPIO Line.
+
+	iwpriv ethX ledgpio
+		will give u which LEDs are Enabled.
+
+	Usage:
+		iwpriv eth1 ledgpio 1 0 2 1 3 4
+			will enable
+			LED 1 -> GPIO 0
+			LED 2 -> GPIO 1
+			LED 3 -> GPIO 4
+
+		iwpriv eth1 ledgpio
+			shows LED information in the format as mentioned above.
+
+	Note: LED0 is invalid
+	Note: Maximum Number of LEDs are 16.
+
+inactivityto
+	This command is used by the host to set/get the inactivity timeout value,
+	which specifies when WLAN device is put to sleep.
+
+	Usage:
+		iwpriv ethX inactivityto [<timeout>]
+
+	where the parameter are:
+		timeout: timeout value in milliseconds.
+
+	Example:
+		iwpriv eth1 inactivityto
+			"get the timeout value"
+
+		iwpriv eth1 inactivityto X
+			"set timeout value to X ms"
+
+
+sleeppd
+	This command is used to configure the sleep period of the WLAN device.
+
+	Usage:
+		iwpriv ethX sleeppd [<sleep period>]
+
+	where the parameter are:
+		Period: sleep period in milliseconds. Range 10~60.
+
+	Example:
+		iwpriv eth1 sleeppd 10
+			"set period as 10 ms"
+		iwpriv eth1 sleeppd
+			"get the sleep period configuration"
+
+enable11d
+	This command is used to control 11d
+	where value is:-
+		1	-- Enabled
+		0	-- Disabled
+		2	-- Get
+
+
+
+
+tpccfg
+	Enables or disables automatic transmit power control.
+
+	The first parameter turns this feature on (1) or off (0).  When turning
+	on, the user must also supply four more parameters in the following
+	order:
+		-UseSNR (Use SNR (in addition to PER) for TPC algorithm),
+		-P0 (P0 power level for TPC),
+		-P1 (P1 power level for TPC),
+		-P2 (P2 power level for TPC).
+
+	Usage:
+		iwpriv ethX tpccfg: Get current configuration
+		iwpriv ethX tpccfg 0: disable auto TPC
+		iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
+							     P0=0x05; P1=0x0a; P2=0x0d;
+		iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
+							     P0=0x05; P1=0x0a; P2=0x0d.
+
+powercfg
+	Enables or disables power adaptation.
+
+	The first parameter turns this feature on (1) or off (0).  When turning
+	on, the user must also supply three more parameters in the following
+	order:
+		-P0 (P0 power level for Power Adaptation),
+		-P1 (P1 power level for Power Adaptation),
+		-P2 (P2 power level for Power Adaptation).
+
+	Usage:
+		iwpriv ethX powercfg: Get current configuration
+		iwpriv ethX powercfg 0: disable power adaptation
+		iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation;
+						       P0=0x0d; P1=0x0f; P2=0x12.
+
+getafc
+	This command returns automatic frequency control parameters.  It returns
+	three integers:
+		-P0: automatic is on (1), or off (0),
+		-P1: current timing offset in PPM (part per million), and
+		-P2: current frequency offset in PPM.
+
+setafc
+	Set automatic frequency control options.
+
+	The first parameter turns automatic on (1) or off (0).
+	The user must supply two more parameters in either case, in the following
+  order:
+
+  When auto is on:
+
+		-P0 (automatic adjustment frequency threshold in PPM),
+		-P1 (automatic adjustment period in beacon period),
+
+  When auto is off:
+
+		-P0 (manual adjustment timing offset in PPM), and
+		-P1 (manual adjustment frequency offset in PPM).
+
+	Usage:
+		iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy
+    offset are 10 PPM.
+
+		iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment,
+    frequency threshold 10 PPM, for every 10 beacon periods.
+
+
+
+scanprobes
+	This command sets number of probe requests per channel.
+
+	Usage:
+		iwpriv ethX scanprobes 3 (set scan probes to 3)
+		iwpriv ethX scanprobes   (get scan probes)
+
+lolisteninter
+	This command sets the value of listen interval.
+
+	Usage:
+	iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
+	iwpriv ethX lolisteninter     (get the lolisteninter value)
+
+rateadapt
+	This command sets the data rates bitmap.
+	Where <n>
+		0: Disable auto rate adapt
+		1: Enable auto rate adapt
+
+	      <m>
+		 data rate bitmap
+			Bit	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			12-15	Reserved
+
+	Usage:
+	iwpriv ethX rateadapt
+			read the currect data rate setting
+	iwpriv ethX rateadapt 1 0x07
+			enable auto data rate adapt and
+			data rates are 1Mbps, 2Mbsp and 5.5Mbps
+
+
+txcontrol
+	This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis.
+
+	Where value <n> is:
+	    if bit[4] == 1:
+		bit[3:0]        -- 0   1   2   3   4   5   6   7   8   9   10   11   12   13-16
+		Data Rate(Mbps) -- 1   2   5.5 11  Rsv 6   9   12  18  24  36   48   54   Rsv
+
+	    bit[12:8]
+		if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
+
+	    bit[14:13] specifies per packet ack policy:
+		bit[14:13]
+		     1  0	use immediate ack policy for this packet
+		     1  1       use no ack policy for this packet
+		     0  x	use the per-packet ack policy setting
+
+	Usage:
+	iwpriv ethX txcontrol 0x7513
+			Use no-ack policy, 5 retires for Tx, 11Mbps rate
+
+
+
+psnullinterval
+	This command is used to set/request NULL package interval for Power Save
+	under infrastructure mode.
+
+	where value is:-
+		-1	-- Disabled
+		n>0	-- Set interval as n (seconds)
+
+prescan
+	This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap
+
+	where value is:-
+		0	-- Disabled
+		1	-- Enabled
+		2       -- Get
+
+getrxinfo
+	This command gets non average value of Signal to Noise Ratio of Data and rate index.
+
+	The following table shows RateIndex and Rate
+
+		     RateIndex	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+
+gettxrate
+	This command gets current Tx rate index of the first packet associated with Rate Adaptation.
+
+	The following table shows RateIndex and Rate
+
+		     RateIndex	Data rate
+			0	1 Mbps
+			1	2 Mbps
+			2	5.5 Mbps
+			3	11 Mbps
+			4	Reserved
+			5	6 Mbps
+			6	9 Mbps
+			7	12 Mbps
+			8	18 Mbps
+			9	24 Mbps
+			10	36 Mbps
+			11	48 Mbps
+			12	54 Mbps
+			13-15	Reserved
+
+bcninterval
+	This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc
+	beacon interval when no argument is given. The valid beacon interval is between 20 - 1000,
+	default beacon interval is 100.
+
+	Usage:
+		iwpriv ethX bcninterval 100  (set adhoc beacon interval to 100)
+		iwpriv ethX bcninterval      (get adhoc beacon interval)
+
+fwt_add
+	This command is used to insert an entry into the FWT table. The list of
+	parameters must follow the following structure:
+
+	iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
+
+	The parameters between brackets are optional, but they must appear in
+	the order specified.  For example, if you want to specify the metric,
+	you must also specify the dir, ssn, and dsn but you need not specify the
+	hopcount, expiration, sleepmode, or snr.  Any unspecified parameters
+	will be assigned the defaults specified below.
+
+	The different parameters are:-
+		da		-- DA MAC address in the form 00:11:22:33:44:55
+		ra		-- RA MAC address in the form 00:11:22:33:44:55
+		metric		-- route metric (cost: smaller-metric routes are
+				   preferred, default is 0)
+		dir		-- direction (1 for direct, 0 for reverse,
+				   default is 1)
+		ssn		-- Source Sequence Number (time at the RA for
+				   reverse routes.  Default is 0)
+		dsn		-- Destination Sequence Number (time at the DA
+				   for direct routes.  Default is 0)
+		hopcount	-- hop count (currently unused, default is 0)
+		ttl		-- TTL (Only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is
+				   1024us, or ~ 1ms. Use 0 for an indefinite
+				   entry, default is 0)
+		sleepmode	-- RA's sleep mode (currently unused, default is
+				   0)
+		snr		-- SNR in the link to RA (currently unused,
+				   default is 0)
+
+	The command does not return anything.
+
+fwt_del
+	This command is used to remove an entry to the FWT table. The list of
+	parameters must follow the following structure:
+
+		iwpriv ethX fwt_del da ra [dir]
+
+	where the different parameters are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		dir		-- direction (1 for direct, 0 for reverse,
+				   default is 1)
+
+	The command does not return anything.
+
+fwt_lookup
+	This command is used to get the best route in the FWT table to a given
+	host. The only parameter is the MAC address of the host that is being
+	looked for.
+
+		iwpriv ethX fwt_lookup da
+
+	where:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+
+	The command returns an output string identical to the one returned by
+	fwt_list described below.
+
+
+fwt_list
+	This command is used to list a route from the FWT table. The only
+	parameter is the index into the table. If you want to list all the
+	routes in a table, start with index=0, and keep listing until you get a
+	"(null)" string.  Note that the indicies may change as the fwt is
+	updated.  It is expected that most users will not use fwt_list directly,
+	but that a utility similar to the traditional route command will be used
+	to invoke fwt_list over and over.
+
+		iwpriv ethX fwt_list index
+
+	The output is a string of the following form:
+
+		da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
+
+	where the different fields are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		metric		-- route metric (cost: smaller-metric routes are preferred)
+		dir		-- direction (1 for direct, 0 for reverse)
+		ssn		-- Source Sequence Number (time at the RA for reverse routes)
+		dsn		-- Destination Sequence Number (time at the DA for direct routes)
+		hopcount	-- hop count (currently unused)
+		ttl		-- TTL (only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+		sleepmode	-- RA's sleep mode (currently unused)
+		snr		-- SNR in the link to RA (currently unused)
+
+fwt_list_route
+	This command is used to list a route from the FWT table. The only
+	parameter is the route ID. If you want to list all the routes in a
+	table, start with rid=0, and keep incrementing rid until you get a
+	"(null)" string. This function is similar to fwt_list. The only
+	difference is the output format.  Also note that this command is meant
+	for debugging.  It is expected that users will use fwt_lookup and
+	fwt_list.  One important reason for this is that the route id may change
+	as the route table is altered.
+
+		iwpriv ethX fwt_list_route rid
+
+	The output is a string of the following form:
+
+		da metric dir nid ssn dsn hopcount ttl expiration
+
+	where the different fields are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		metric		-- route metric (cost: smaller-metric routes are preferred)
+		dir		-- direction (1 for direct, 0 for reverse)
+		nid		-- Next-hop (neighbor) host ID (nid)
+		ssn		-- Source Sequence Number (time at the RA for reverse routes)
+		dsn		-- Destination Sequence Number (time at the DA for direct routes)
+		hopcount	-- hop count (currently unused)
+		ttl		-- TTL count (only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+
+fwt_list_neigh
+	This command is used to list a neighbor from the FWT table. The only
+	parameter is the neighbor ID. If you want to list all the neighbors in a
+	table, start with nid=0, and keep incrementing nid until you get a
+	"(null)" string.  Note that the nid from a fwt_list_route command can be
+	used as an input to this command.  Also note that this command is meant
+	mostly for debugging.  It is expected that users will use fwt_lookup.
+	One important reason for this is that the neighbor id may change as the
+	neighbor table is altered.
+
+		iwpriv ethX fwt_list_neigh nid
+
+	The output is a string of the following form:
+
+		ra sleepmode snr references
+
+	where the different fields are:-
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		sleepmode	-- RA's sleep mode (currently unused)
+		snr		-- SNR in the link to RA (currently unused)
+		references	-- RA's reference counter
+
+fwt_reset
+	This command is used to reset the FWT table, getting rid of all the
+	entries. There are no input parameters.
+
+		iwpriv ethX fwt_reset
+
+	The command does not return anything.
+
+fwt_cleanup
+	This command is used to perform user-based garbage recollection. The
+	FWT table is checked, and all the entries that are expired or invalid
+	are cleaned. Note that this is exported to the driver for debugging
+	purposes, as garbage collection is also fired by the firmware when in
+	space problems. There are no input parameters.
+
+		iwpriv ethX fwt_cleanup
+
+	The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+	This command returns a card's internal time representation.  It is this
+	time that is used to represent the expiration times of FWT entries.  The
+	number is not consistent from card to card; it is simply a timer count.
+	The fwt_time command is used to inspect the timer so that expiration
+	times reported by fwt_list can be properly interpreted.
+
+		iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+	The mesh ttl is the number of hops a mesh packet can traverse before it
+	is dropped.  This parameter is used to prevent infinite loops in the
+	mesh network.  The value returned by this function is the ttl assigned
+	to all mesh packets.  Currently there is no way to control the ttl on a
+	per packet or per socket basis.
+
+	iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+	Set the ttl.  The argument must be between 0 and 255.
+
+	iwpriv ethX mesh_set_ttl <ttl>
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+	Usage:
+	ethtool -e ethX [raw on|off] [offset N] [length N]
+
+       -e     retrieves and prints an EEPROM dump for the  specified  ethernet
+              device.   When raw is enabled, then it dumps the raw EEPROM data
+              to stdout. The length and offset parameters allow  dumping  cer-
+              tain portions of the EEPROM.  Default is to dump the entire EEP-
+              ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset          Values
+------          ------
+0x0000          38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+rdmac
+rdbbp
+rdrf
+	These commands are used to read the MAC, BBP and RF registers from the
+	card.  These commands take one parameter that specifies the offset
+	location that is to be read.  This parameter must be specified in
+	hexadecimal (its possible to preceed preceding the number with a "0x").
+
+	Path: /debugfs/libertas_wireless/ethX/registers/
+
+	Usage:
+		echo "0xa123" > rdmac ; cat rdmac
+		echo "0xa123" > rdbbp ; cat rdbbp
+		echo "0xa123" > rdrf ; cat rdrf
+wrmac
+wrbbp
+wrrf
+	These commands are used to write the MAC, BBP and RF registers in the
+	card.  These commands take two parameters that specify the offset
+	location and the value that is to be written. This parameters must
+	be specified in hexadecimal (its possible to preceed the number
+	with a "0x").
+
+	Usage:
+		echo "0xa123 0xaa" > wrmac
+		echo "0xa123 0xaa" > wrbbp
+		echo "0xa123 0xaa" > wrrf
+
+sleepparams
+	This command is used to set the sleepclock configurations
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage:
+		cat sleepparams: reads the current sleepclock configuration
+
+		echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
+
+		where:
+			p1 is Sleep clock error in ppm (0-65535)
+			p2 is Wakeup offset in usec (0-65535)
+			p3 is Clock stabilization time in usec (0-65535)
+			p4 is Control periodic calibration (0-2)
+			p5 is Control the use of external sleep clock (0-2)
+			p6 is reserved for debug (0-65535)
+
+subscribed_events
+
+	The subscribed_events directory contains the interface for the
+	subscribed events API.
+
+	Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+
+	Each event is represented by a filename. Each filename consists of the
+	following three fields:
+	Value Frequency Subscribed
+
+	To read the current values for a given event, do:
+		cat event
+	To set the current values, do:
+		echo "60 2 1" > event
+
+	Frequency field specifies the reporting frequency for this event.
+	If it is set to 0, then the event is reported only once, and then
+	automatically unsubscribed. If it is set to 1, then the event is
+	reported every time it occurs. If it is set to N, then the event is
+	reported every Nth time it occurs.
+
+	beacon_missed
+	Value field specifies the number of consecutive missing beacons which
+	triggers the LINK_LOSS event. This event is generated only once after
+	which the firmware resets its state. At initialization, the LINK_LOSS
+	event is subscribed by default. The default value of MissedBeacons is
+	60.
+
+	failure_count
+	Value field specifies the consecutive failure count threshold which
+	triggers the generation of the MAX_FAIL event. Once this event is
+	generated, the consecutive failure count is reset to 0.
+	At initialization, the MAX_FAIL event is NOT subscribed by
+	default.
+
+	high_rssi
+	This event is generated when the average received RSSI in beacons goes
+	above a threshold, specified by Value.
+
+	low_rssi
+	This event is generated when the average received RSSI in beacons goes
+	below a threshold, specified by Value.
+
+	high_snr
+	This event is generated when the average received SNR in beacons goes
+	above a threshold, specified by Value.
+
+	low_snr
+	This event is generated when the average received SNR in beacons goes
+	below a threshold, specified by Value.
+
+extscan
+	This command is used to do a specific scan.
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage: echo "SSID" > extscan
+
+	Example:
+		echo "LINKSYS-AP" > extscan
+
+	To see the results of use getscantable command.
+
+getscantable
+
+	Display the current contents of the driver scan table (ie. get the
+	scan results).
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage:
+		cat getscantable
+
+setuserscan
+	Initiate a customized scan and retrieve the results
+
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+    Usage:
+       echo "[ARGS]" > setuserscan
+
+         where [ARGS]:
+
+      chan=[chan#][band][mode] where band is [a,b,g] and mode is
+                               blank for active or 'p' for passive
+      bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
+      ssid="[SSID]"            specify a SSID filter for the scan
+      keep=[0 or 1]            keep the previous scan results (1), discard (0)
+      dur=[scan time]          time to scan for each channel in milliseconds
+      probes=[#]               number of probe requests to send on each chan
+      type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+    Any combination of the above arguments can be supplied on the command line.
+      If the chan token is absent, a full channel scan will be completed by
+      the driver.  If the dur or probes tokens are absent, the driver default
+      setting will be used.  The bssid and ssid fields, if blank,
+      will produce an unfiltered scan. The type field will default to 3 (Any)
+      and the keep field will default to 0 (Discard).
+
+    Examples:
+    1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+            echo "chan=1g,6g,11g" > setuserscan
+
+    2) Perform a passive scan on channel 11 for 20 ms:
+            echo "chan=11gp dur=20" > setuserscan
+
+    3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+       channel 36 in the 'a' band:
+
+            echo "chan=1g,6g,11g,36ap" > setuserscan
+
+    4) Perform an active scan on channel 6 and 36 for a specific SSID:
+            echo "chan=6g,36a ssid="TestAP"" > setuserscan
+
+    5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+       the current scan table intact, update existing or append new scan data:
+            echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+    6) Scan channel 6, for all infrastructure networks, sending two probe
+       requests.  Keep the previous scan table intact. Update any duplicate
+       BSSID/SSID matches with the new scan data:
+            echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+
+    All entries in the scan table (not just the new scan data when keep=1)
+    will be displayed upon completion by use of the getscantable ioctl.
+
+==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644
index 0000000..b55c7f5
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -0,0 +1,588 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#include <linux/bitops.h>
+#include <net/ieee80211.h>
+
+#include "assoc.h"
+#include "join.h"
+#include "decl.h"
+#include "hostcmd.h"
+#include "host.h"
+
+
+static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static int assoc_helper_essid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	int i;
+
+	ENTER();
+
+	lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		if (adapter->prescan) {
+			libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
+		}
+
+		i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
+				NULL, wlan802_11infrastructure);
+		if (i >= 0) {
+			lbs_pr_debug(1,
+			       "SSID found in scan list ... associating...\n");
+
+			ret = wlan_associate(priv, &adapter->scantable[i]);
+			if (ret == 0) {
+				memcpy(&assoc_req->bssid,
+				       &adapter->scantable[i].macaddress,
+				       ETH_ALEN);
+			}
+		} else {
+			lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
+				assoc_req->ssid.ssid);
+		}
+	} else if (assoc_req->mode == wlan802_11ibss) {
+		/* Scan for the network, do not save previous results.  Stale
+		 *   scan data will cause us to join a non-existant adhoc network
+		 */
+		libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
+
+		/* Search for the requested SSID in the scan table */
+		i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+				wlan802_11ibss);
+		if (i >= 0) {
+			lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
+			libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+		} else {
+			/* else send START command */
+			lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
+				" with SSID '%s'\n", assoc_req->ssid.ssid);
+			libertas_start_adhoc_network(priv, &assoc_req->ssid);
+		}
+		memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
+	}
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_bssid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i, ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
+		MAC_ARG(assoc_req->bssid));
+
+	/* Search for index position in list for requested MAC */
+	i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
+			    assoc_req->mode);
+	if (i < 0) {
+		lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
+			"cannot associate.\n", MAC_ARG(assoc_req->bssid));
+		goto out;
+	}
+
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		ret = wlan_associate(priv, &adapter->scantable[i]);
+		lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
+	} else if (assoc_req->mode == wlan802_11ibss) {
+		libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+	}
+	memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
+		sizeof(struct WLAN_802_11_SSID));
+
+out:
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_associate(wlan_private *priv,
+                                  struct assoc_request * assoc_req)
+{
+	int ret = 0, done = 0;
+
+	/* If we're given and 'any' BSSID, try associating based on SSID */
+
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
+		    && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
+			ret = assoc_helper_bssid(priv, assoc_req);
+			done = 1;
+			if (ret) {
+				lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+			}
+		}
+	}
+
+	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		ret = assoc_helper_essid(priv, assoc_req);
+		if (ret) {
+			lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+		}
+	}
+
+	return ret;
+}
+
+
+static int assoc_helper_mode(wlan_private *priv,
+                             struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	if (assoc_req->mode == adapter->inframode) {
+		LEAVE();
+		return 0;
+	}
+
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		if (adapter->psstate != PS_STATE_FULL_POWER)
+			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+		adapter->psmode = wlan802_11powermodecam;
+	}
+
+	adapter->inframode = assoc_req->mode;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    0, cmd_option_waitforrsp,
+				    OID_802_11_INFRASTRUCTURE_MODE,
+				    (void *) assoc_req->mode);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wep_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i;
+	int ret = 0;
+
+	ENTER();
+
+	/* Set or remove WEP keys */
+	if (   assoc_req->wep_keys[0].len
+	    || assoc_req->wep_keys[1].len
+	    || assoc_req->wep_keys[2].len
+	    || assoc_req->wep_keys[3].len) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_set_wep,
+					    cmd_act_add,
+					    cmd_option_waitforrsp,
+					    0, assoc_req);
+	} else {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_set_wep,
+					    cmd_act_remove,
+					    cmd_option_waitforrsp,
+					    0, NULL);
+	}
+
+	if (ret)
+		goto out;
+
+	/* enable/disable the MAC's WEP packet filter */
+	if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
+		adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+	else
+		adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+	ret = libertas_set_mac_packet_filter(priv);
+	if (ret)
+		goto out;
+
+	mutex_lock(&adapter->lock);
+
+	/* Copy WEP keys into adapter wep key fields */
+	for (i = 0; i < 4; i++) {
+		memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+			sizeof(struct WLAN_802_11_KEY));
+	}
+	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+	mutex_unlock(&adapter->lock);
+
+out:
+	LEAVE();
+	return ret;
+}
+
+static int assoc_helper_secinfo(wlan_private *priv,
+                                struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	memcpy(&adapter->secinfo, &assoc_req->secinfo,
+		sizeof(struct wlan_802_11_security));
+
+	ret = libertas_set_mac_packet_filter(priv);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wpa_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+	int ret = 0;
+
+	ENTER();
+
+	/* enable/Disable RSN */
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_enable_rsn,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    0, assoc_req);
+	if (ret)
+		goto out;
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_key_material,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    0, assoc_req);
+
+out:
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wpa_ie(wlan_private *priv,
+                               struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+		memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+		adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+	} else {
+		memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+		adapter->wpa_ie_len = 0;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+
+static int should_deauth_infrastructure(wlan_adapter *adapter,
+                                        struct assoc_request * assoc_req)
+{
+	if (adapter->connect_status != libertas_connected)
+		return 0;
+
+	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		lbs_pr_debug(1, "Deauthenticating due to new SSID in "
+			" configuration request.\n");
+		return 1;
+	}
+
+	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		if (adapter->secinfo.authmode !=
+		    assoc_req->secinfo.authmode) {
+			lbs_pr_debug(1, "Deauthenticating due to updated security "
+				"info in configuration request.\n");
+			return 1;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
+			" configuration request.\n");
+		return 1;
+	}
+
+	/* FIXME: deal with 'auto' mode somehow */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		if (assoc_req->mode != wlan802_11infrastructure)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int should_stop_adhoc(wlan_adapter *adapter,
+                             struct assoc_request * assoc_req)
+{
+	if (adapter->connect_status != libertas_connected)
+		return 0;
+
+	if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
+		return 1;
+	if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
+			sizeof(struct WLAN_802_11_SSID)))
+		return 1;
+
+	/* FIXME: deal with 'auto' mode somehow */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		if (assoc_req->mode != wlan802_11ibss)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void wlan_association_worker(struct work_struct *work)
+{
+	wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req = NULL;
+	int ret = 0;
+	int find_any_ssid = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = adapter->assoc_req;
+	adapter->assoc_req = NULL;
+	mutex_unlock(&adapter->lock);
+
+	if (!assoc_req) {
+		LEAVE();
+		return;
+	}
+
+	lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
+		assoc_req->flags);
+
+	/* If 'any' SSID was specified, find an SSID to associate with */
+	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+	    && !assoc_req->ssid.ssidlength)
+		find_any_ssid = 1;
+
+	/* But don't use 'any' SSID if there's a valid locked BSSID to use */
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
+		    && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
+			find_any_ssid = 0;
+	}
+
+	if (find_any_ssid) {
+		enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+		ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
+				assoc_req->mode, &new_mode);
+		if (ret) {
+			lbs_pr_debug(1, "Could not find best network\n");
+			ret = -ENETUNREACH;
+			goto out;
+		}
+
+		/* Ensure we switch to the mode of the AP */
+		if (assoc_req->mode == wlan802_11autounknown) {
+			set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+			assoc_req->mode = new_mode;
+		}
+	}
+
+	/*
+	 * Check if the attributes being changing require deauthentication
+	 * from the currently associated infrastructure access point.
+	 */
+	if (adapter->inframode == wlan802_11infrastructure) {
+		if (should_deauth_infrastructure(adapter, assoc_req)) {
+			ret = libertas_send_deauthentication(priv);
+			if (ret) {
+				lbs_pr_debug(1, "Deauthentication due to new "
+					"configuration request failed: %d\n",
+					ret);
+			}
+		}
+	} else if (adapter->inframode == wlan802_11ibss) {
+		if (should_stop_adhoc(adapter, assoc_req)) {
+			ret = libertas_stop_adhoc_network(priv);
+			if (ret) {
+				lbs_pr_debug(1, "Teardown of AdHoc network due to "
+					"new configuration request failed: %d\n",
+					ret);
+			}
+
+		}
+	}
+
+	/* Send the various configuration bits to the firmware */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		ret = assoc_helper_mode(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+		ret = assoc_helper_wep_keys(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		ret = assoc_helper_secinfo(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+		ret = assoc_helper_wpa_ie(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+		ret = assoc_helper_wpa_keys(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	/* SSID/BSSID should be the _last_ config option set, because they
+	 * trigger the association attempt.
+	 */
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		int success = 1;
+
+		ret = assoc_helper_associate(priv, assoc_req);
+		if (ret) {
+			lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
+				ret);
+			success = 0;
+		}
+
+		if (adapter->connect_status != libertas_connected) {
+			lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
+				"not connected.\n");
+			success = 0;
+		}
+
+		if (success) {
+			lbs_pr_debug(1, "ASSOC: association attempt successful. "
+				"Associated to '%s' (" MAC_FMT ")\n",
+				assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
+			libertas_prepare_and_send_command(priv,
+				cmd_802_11_rssi,
+				0, cmd_option_waitforrsp, 0, NULL);
+
+			libertas_prepare_and_send_command(priv,
+				cmd_802_11_get_log,
+				0, cmd_option_waitforrsp, 0, NULL);
+		} else {
+
+			ret = -1;
+		}
+	}
+
+out:
+	if (ret) {
+		lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
+			ret);
+	}
+	kfree(assoc_req);
+	LEAVE();
+}
+
+
+/*
+ * Caller MUST hold any necessary locks
+ */
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+{
+	struct assoc_request * assoc_req;
+
+	if (!adapter->assoc_req) {
+		adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
+		if (!adapter->assoc_req) {
+			lbs_pr_info("Not enough memory to allocate association"
+				" request!\n");
+			return NULL;
+		}
+	}
+
+	/* Copy current configuration attributes to the association request,
+	 * but don't overwrite any that are already set.
+	 */
+	assoc_req = adapter->assoc_req;
+	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
+			adapter->curbssparams.ssid.ssidlength);
+	}
+
+	if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+		assoc_req->channel = adapter->curbssparams.channel;
+
+	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+		assoc_req->mode = adapter->inframode;
+
+	if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+			ETH_ALEN);
+	}
+
+	if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+		int i;
+		for (i = 0; i < 4; i++) {
+			memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+				sizeof(struct WLAN_802_11_KEY));
+		}
+	}
+
+	if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+		assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+
+	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+			sizeof(struct WLAN_802_11_KEY));
+	}
+
+	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+			sizeof(struct WLAN_802_11_KEY));
+	}
+
+	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		memcpy(&assoc_req->secinfo, &adapter->secinfo,
+			sizeof(struct wlan_802_11_security));
+	}
+
+	if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+			MAX_WPA_IE_LEN);
+		assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+	}
+
+	return assoc_req;
+}
+
+
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644
index 0000000..2ffd82d
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#ifndef _WLAN_ASSOC_H_
+#define _WLAN_ASSOC_H_
+
+#include "dev.h"
+
+void wlan_association_worker(struct work_struct *work);
+
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+
+#define ASSOC_DELAY (HZ / 2)
+static inline void wlan_postpone_association_work(wlan_private *priv)
+{
+	if (priv->adapter->surpriseremoved)
+		return;
+	cancel_delayed_work(&priv->assoc_work);
+	queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+}
+
+static inline void wlan_cancel_association_work(wlan_private *priv)
+{
+	cancel_delayed_work(&priv->assoc_work);
+	if (priv->adapter->assoc_req) {
+		kfree(priv->adapter->assoc_req);
+		priv->adapter->assoc_req = NULL;
+	}
+}
+
+#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644
index 0000000..bfdac58
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -0,0 +1,1958 @@
+/**
+  * This file contains the handling of command.
+  * It prepares command and sends it to firmware when it is ready.
+  */
+
+#include <net/iw_handler.h>
+#include "host.h"
+#include "hostcmd.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+
+static u16 commands_allowed_in_ps[] = {
+	cmd_802_11_rssi,
+};
+
+/**
+ *  @brief This function checks if the commans is allowed
+ *  in PS mode not.
+ *
+ *  @param command the command ID
+ *  @return 	   TRUE or FALSE
+ */
+static u8 is_command_allowed_in_ps(u16 command)
+{
+	int count = sizeof(commands_allowed_in_ps)
+	    / sizeof(commands_allowed_in_ps[0]);
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (command == cpu_to_le16(commands_allowed_in_ps[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+{
+	struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_get_hw_spec);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+	memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+				   struct cmd_ds_command *cmd,
+				   u16 cmd_action)
+{
+	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+	u16 action = cmd_action;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
+			     S_DS_GEN);
+	psm->action = cpu_to_le16(cmd_action);
+	psm->multipledtim = 0;
+	switch (action) {
+	case cmd_subcmd_enter_ps:
+		lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
+		lbs_pr_debug(1, "locallisteninterval = %d\n",
+		       adapter->locallisteninterval);
+
+		psm->locallisteninterval =
+		    cpu_to_le16(adapter->locallisteninterval);
+		psm->nullpktinterval =
+		    cpu_to_le16(adapter->nullpktinterval);
+		psm->multipledtim =
+		    cpu_to_le16(priv->adapter->multipledtim);
+		break;
+
+	case cmd_subcmd_exit_ps:
+		lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
+		break;
+
+	case cmd_subcmd_sleep_confirmed:
+		lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
+		break;
+
+	default:
+		break;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+					      struct cmd_ds_command *cmd,
+					      u16 cmd_action, void *pdata_buf)
+{
+	u16 *timeout = pdata_buf;
+
+	cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+			     + S_DS_GEN);
+
+	cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+
+	if (cmd_action)
+		cmd->params.inactivity_timeout.timeout =
+		    cpu_to_le16(*timeout);
+	else
+		cmd->params.inactivity_timeout.timeout = 0;
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					u16 cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+
+	if (cmd_action == cmd_act_get) {
+		memset(&adapter->sp, 0, sizeof(struct sleep_params));
+		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+		sp->action = cpu_to_le16(cmd_action);
+	} else if (cmd_action == cmd_act_set) {
+		sp->action = cpu_to_le16(cmd_action);
+		sp->error = cpu_to_le16(adapter->sp.sp_error);
+		sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+		sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+		sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+		sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+		sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_set_wep(wlan_private * priv,
+                                   struct cmd_ds_command *cmd,
+                                   u32 cmd_act,
+                                   void * pdata_buf)
+{
+	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct assoc_request * assoc_req = pdata_buf;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
+	                             + S_DS_GEN);
+
+	if (cmd_act == cmd_act_add) {
+		int i;
+
+		if (!assoc_req) {
+			lbs_pr_debug(1, "Invalid association request!");
+			ret = -1;
+			goto done;
+		}
+
+		wep->action = cpu_to_le16(cmd_act_add);
+
+		/* default tx key index */
+		wep->keyindex = cpu_to_le16((u16)
+				                 (assoc_req->wep_tx_keyidx &
+				                 (u32)cmd_WEP_KEY_INDEX_MASK));
+
+		lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
+
+		/* Copy key types and material to host command structure */
+		for (i = 0; i < 4; i++) {
+			struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+
+			switch (pkey->len) {
+			case KEY_LEN_WEP_40:
+				wep->keytype[i] = cmd_type_wep_40_bit;
+				memmove(&wep->keymaterial[i], pkey->key,
+				        pkey->len);
+				break;
+			case KEY_LEN_WEP_104:
+				wep->keytype[i] = cmd_type_wep_104_bit;
+				memmove(&wep->keymaterial[i], pkey->key,
+				        pkey->len);
+				break;
+			case 0:
+				break;
+			default:
+				lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
+				       i, pkey->len);
+				ret = -1;
+				goto done;
+				break;
+			}
+		}
+	} else if (cmd_act == cmd_act_remove) {
+		/* ACT_REMOVE clears _all_ WEP keys */
+		wep->action = cpu_to_le16(cmd_act_remove);
+
+		/* default tx key index */
+		wep->keyindex = cpu_to_le16((u16)
+				                 (adapter->wep_tx_keyidx &
+				                 (u32)cmd_WEP_KEY_INDEX_MASK));
+	}
+
+	ret = 0;
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action)
+{
+	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+			     S_DS_GEN);
+	penableRSN->action = cpu_to_le16(cmd_action);
+	if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+		penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+	} else {
+		penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+	}
+
+	return 0;
+}
+
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+                            struct WLAN_802_11_KEY * pkey)
+{
+	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+
+	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+		pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
+	} else {
+		pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+	}
+
+	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
+		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+	} else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+	}
+
+	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+	pkeyparamset->keylen = cpu_to_le16(pkey->len);
+	memcpy(pkeyparamset->key, pkey->key, pkey->len);
+	pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
+	                                        + sizeof(pkeyparamset->keyinfo)
+	                                        + sizeof(pkeyparamset->keylen)
+	                                        + sizeof(pkeyparamset->key));
+}
+
+static int wlan_cmd_802_11_key_material(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					u16 cmd_action,
+					u32 cmd_oid, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_key_material *pkeymaterial =
+	    &cmd->params.keymaterial;
+	int ret = 0;
+	int index = 0;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_key_material);
+	pkeymaterial->action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == cmd_act_get) {
+		cmd->size = cpu_to_le16(  S_DS_GEN
+		                             + sizeof (pkeymaterial->action));
+		ret = 0;
+		goto done;
+	}
+
+	memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+
+	if (adapter->wpa_unicast_key.len) {
+		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+		                &adapter->wpa_unicast_key);
+		index++;
+	}
+
+	if (adapter->wpa_mcast_key.len) {
+		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+		                &adapter->wpa_mcast_key);
+		index++;
+	}
+
+	cmd->size = cpu_to_le16(  S_DS_GEN
+	                             + sizeof (pkeymaterial->action)
+	                             + index * sizeof(struct MrvlIEtype_keyParamSet));
+
+	ret = 0;
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_802_11_reset(wlan_private * priv,
+				 struct cmd_ds_command *cmd, int cmd_action)
+{
+	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+	cmd->command = cpu_to_le16(cmd_802_11_reset);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+	reset->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_get_log(wlan_private * priv,
+				   struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_get_log);
+	cmd->size =
+		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+				    struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
+			     S_DS_GEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+				    struct cmd_ds_command *cmd,
+				    int cmd_action,
+				    int cmd_oid, void *pdata_buf)
+{
+	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+	wlan_adapter *adapter = priv->adapter;
+	u8 ucTemp;
+
+	ENTER();
+
+	lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+	cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
+			     S_DS_GEN);
+
+	switch (cmd_oid) {
+	case OID_802_11_INFRASTRUCTURE_MODE:
+	{
+		enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
+			(enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
+		pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+		pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+		pSNMPMIB->bufsize = sizeof(u8);
+		if (mode == wlan802_11infrastructure)
+			ucTemp = SNMP_MIB_VALUE_INFRA;
+		else
+			ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+		memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+
+		break;
+	}
+
+	case OID_802_11D_ENABLE:
+		{
+			u32 ulTemp;
+
+			pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+
+			if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype = cmd_act_set;
+				pSNMPMIB->bufsize = sizeof(u16);
+				ulTemp = *(u32 *)pdata_buf;
+				*((unsigned short *)(pSNMPMIB->value)) =
+				    cpu_to_le16((u16) ulTemp);
+			}
+			break;
+		}
+
+	case OID_802_11_FRAGMENTATION_THRESHOLD:
+		{
+			u32 ulTemp;
+
+			pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+
+			if (cmd_action == cmd_act_get) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_get);
+			} else if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_set);
+				pSNMPMIB->bufsize =
+				    cpu_to_le16(sizeof(u16));
+				ulTemp = *((u32 *) pdata_buf);
+				*((unsigned short *)(pSNMPMIB->value)) =
+				    cpu_to_le16((u16) ulTemp);
+
+			}
+
+			break;
+		}
+
+	case OID_802_11_RTS_THRESHOLD:
+		{
+
+			u32 ulTemp;
+			pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+
+			if (cmd_action == cmd_act_get) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_get);
+			} else if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_set);
+				pSNMPMIB->bufsize =
+				    cpu_to_le16(sizeof(u16));
+				ulTemp = *((u32 *)
+					   pdata_buf);
+				*(unsigned short *)(pSNMPMIB->value) =
+				    cpu_to_le16((u16) ulTemp);
+
+			}
+			break;
+		}
+	case OID_802_11_TX_RETRYCOUNT:
+		pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+
+		if (cmd_action == cmd_act_get) {
+			pSNMPMIB->querytype =
+			    cpu_to_le16(cmd_act_get);
+		} else if (cmd_action == cmd_act_set) {
+			pSNMPMIB->querytype =
+			    cpu_to_le16(cmd_act_set);
+			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+			*((unsigned short *)(pSNMPMIB->value)) =
+			    cpu_to_le16((u16) adapter->txretrycount);
+		}
+
+		break;
+	default:
+		break;
+	}
+
+	lbs_pr_debug(1,
+	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
+	       cmd->command, cmd->size, cmd->seqnum, cmd->result);
+
+	lbs_pr_debug(1,
+	       "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+	       pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize,
+	       *(u16 *) pSNMPMIB->value);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_radio_control(wlan_private * priv,
+					 struct cmd_ds_command *cmd,
+					 int cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_radio_control *pradiocontrol =
+	    &cmd->params.radio;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+
+	pradiocontrol->action = cpu_to_le16(cmd_action);
+
+	switch (adapter->preamble) {
+	case cmd_type_short_preamble:
+		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+		break;
+
+	case cmd_type_long_preamble:
+		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+		break;
+
+	case cmd_type_auto_preamble:
+	default:
+		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+		break;
+	}
+
+	if (adapter->radioon)
+		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+	else
+		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       u16 cmd_action, void *pdata_buf)
+{
+
+	struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+	prtp->action = cmd_action;
+
+	lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
+	       cmd->command, prtp->action);
+
+	switch (cmd_action) {
+	case cmd_act_tx_power_opt_get:
+		prtp->action = cpu_to_le16(cmd_act_get);
+		prtp->currentlevel = 0;
+		break;
+
+	case cmd_act_tx_power_opt_set_high:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel =
+		    cpu_to_le16(cmd_act_tx_power_index_high);
+		break;
+
+	case cmd_act_tx_power_opt_set_mid:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel =
+		    cpu_to_le16(cmd_act_tx_power_index_mid);
+		break;
+
+	case cmd_act_tx_power_opt_set_low:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+		break;
+	}
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+			     S_DS_GEN);
+
+	rant->action = cpu_to_le16(cmd_action);
+	if ((cmd_action == cmd_act_set_rx) ||
+	    (cmd_action == cmd_act_set_tx)) {
+		rant->antennamode =
+		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+					      struct cmd_ds_command *cmd,
+					      u16 cmd_action)
+{
+	struct cmd_ds_802_11_rate_adapt_rateset
+	*rateadapt = &cmd->params.rateset;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+			     + S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+
+	ENTER();
+
+	rateadapt->action = cmd_action;
+	rateadapt->enablehwauto = adapter->enablehwauto;
+	rateadapt->bitmap = adapter->ratebitmap;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+				     struct cmd_ds_command *cmd,
+				     u16 cmd_action)
+{
+	struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = cmd_action;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+			     S_DS_GEN);
+
+	cmd->command = cpu_to_le16(cmd_802_11_data_rate);
+
+	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
+
+	pdatarate->action = cpu_to_le16(cmd_action);
+
+	if (action == cmd_act_set_tx_fix_rate) {
+		pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+		lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
+		       adapter->datarate);
+	} else if (action == cmd_act_set_tx_auto) {
+		lbs_pr_debug(1, "Setting FW for AUTO rate\n");
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action)
+{
+	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+
+	pMCastAdr->action = cpu_to_le16(cmd_action);
+	pMCastAdr->nr_of_adrs =
+	    cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+	memcpy(pMCastAdr->maclist, adapter->multicastlist,
+	       adapter->nr_of_multicastmacaddr * ETH_ALEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      int option, void *pdata_buf)
+{
+	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
+				     + S_DS_GEN);
+
+	if (option == cmd_opt_802_11_rf_channel_set) {
+		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+	}
+
+	rfchan->action = cpu_to_le16(option);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rssi(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rssi);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
+	cmd->params.rssi.N = priv->adapter->bcn_avg_factor;
+
+	/* reset Beacon SNR/NF/RSSI values */
+	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+	adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+	adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+	adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+	return 0;
+}
+
+static int wlan_cmd_reg_access(wlan_private * priv,
+			       struct cmd_ds_command *cmdptr,
+			       u8 cmd_action, void *pdata_buf)
+{
+	struct wlan_offset_value *offval;
+
+	ENTER();
+
+	offval = (struct wlan_offset_value *)pdata_buf;
+
+	switch (cmdptr->command) {
+	case cmd_mac_reg_access:
+		{
+			struct cmd_ds_mac_reg_access *macreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_mac_reg_access)
+					     + S_DS_GEN);
+			macreg =
+			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
+			    macreg;
+
+			macreg->action = cpu_to_le16(cmd_action);
+			macreg->offset = cpu_to_le16((u16) offval->offset);
+			macreg->value = cpu_to_le32(offval->value);
+
+			break;
+		}
+
+	case cmd_bbp_reg_access:
+		{
+			struct cmd_ds_bbp_reg_access *bbpreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_bbp_reg_access)
+					     + S_DS_GEN);
+			bbpreg =
+			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
+			    bbpreg;
+
+			bbpreg->action = cpu_to_le16(cmd_action);
+			bbpreg->offset = cpu_to_le16((u16) offval->offset);
+			bbpreg->value = (u8) offval->value;
+
+			break;
+		}
+
+	case cmd_rf_reg_access:
+		{
+			struct cmd_ds_rf_reg_access *rfreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_rf_reg_access) +
+					     S_DS_GEN);
+			rfreg =
+			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
+			    rfreg;
+
+			rfreg->action = cpu_to_le16(cmd_action);
+			rfreg->offset = cpu_to_le16((u16) offval->offset);
+			rfreg->value = (u8) offval->value;
+
+			break;
+		}
+
+	default:
+		break;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       u16 cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+			     S_DS_GEN);
+	cmd->result = 0;
+
+	cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == cmd_act_set) {
+		memcpy(cmd->params.macadd.macadd,
+		       adapter->current_addr, ETH_ALEN);
+		lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+					 struct cmd_ds_command *cmd,
+					 int cmd_action, void *pdata_buf)
+{
+	struct wlan_ioctl_regrdwr *ea = pdata_buf;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+			     S_DS_GEN);
+	cmd->result = 0;
+
+	cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
+	cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
+	cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+	cmd->params.rdeeprom.value = 0;
+
+	return 0;
+}
+
+static int wlan_cmd_bt_access(wlan_private * priv,
+			       struct cmd_ds_command *cmd,
+			       u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+	lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_bt_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+	bt_access->action = cpu_to_le16(cmd_action);
+
+	switch (cmd_action) {
+	case cmd_act_bt_access_add:
+		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+		lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+		break;
+	case cmd_act_bt_access_del:
+		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+		lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+		break;
+	case cmd_act_bt_access_list:
+		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+		break;
+	case cmd_act_bt_access_reset:
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wlan_cmd_fwt_access(wlan_private * priv,
+			       struct cmd_ds_command *cmd,
+			       u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+	lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_fwt_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+
+	if (pdata_buf)
+		memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+	else
+		memset(fwt_access, 0, sizeof(*fwt_access));
+
+	fwt_access->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+static int wlan_cmd_mesh_access(wlan_private * priv,
+				struct cmd_ds_command *cmd,
+				u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+	lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_mesh_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+
+	if (pdata_buf)
+		memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+	else
+		memset(mesh_access, 0, sizeof(*mesh_access));
+
+	mesh_access->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+{
+	unsigned long flags;
+	struct cmd_ds_command *cmdptr;
+
+	ENTER();
+
+	if (!cmdnode) {
+		lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
+		goto done;
+	}
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+	if (!cmdptr) {
+		lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
+		goto done;
+	}
+
+	/* Exit_PS command needs to be queued in the header always. */
+	if (cmdptr->command == cmd_802_11_ps_mode) {
+		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+		if (psm->action == cmd_subcmd_exit_ps) {
+			if (adapter->psstate != PS_STATE_FULL_POWER)
+				addtail = 0;
+		}
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (addtail)
+		list_add_tail((struct list_head *)cmdnode,
+			      &adapter->cmdpendingq);
+	else
+		list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
+	       (u32) cmdnode,
+	       ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command);
+
+done:
+	LEAVE();
+	return;
+}
+
+/*
+ * TODO: Fix the issue when DownloadcommandToStation is being called the
+ * second time when the command timesout. All the cmdptr->xxx are in little
+ * endian and therefore all the comparissions will fail.
+ * For now - we are not performing the endian conversion the second time - but
+ * for PS and DEEP_SLEEP we need to worry
+ */
+static int DownloadcommandToStation(wlan_private * priv,
+				    struct cmd_ctrl_node *cmdnode)
+{
+	unsigned long flags;
+	struct cmd_ds_command *cmdptr;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u16 cmdsize;
+	u16 command;
+
+	ENTER();
+
+	if (!adapter || !cmdnode) {
+		lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
+		       (int)adapter, (int)cmdnode);
+		if (cmdnode) {
+			spin_lock_irqsave(&adapter->driver_lock, flags);
+			__libertas_cleanup_and_insert_cmd(priv, cmdnode);
+			spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		}
+		ret = -1;
+		goto done;
+	}
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (!cmdptr || !cmdptr->size) {
+		lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+		       "Not sending\n");
+		__libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	adapter->cur_cmd = cmdnode;
+	adapter->cur_cmd_retcode = 0;
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
+	       cmdptr->size);
+
+	cmdsize = cmdptr->size;
+
+	command = cpu_to_le16(cmdptr->command);
+
+	cmdnode->cmdwaitqwoken = 0;
+	cmdsize = cpu_to_le16(cmdsize);
+
+	ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
+
+	if (ret != 0) {
+		lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+	lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+
+	/* Setup the timer after transmit command */
+	if (command == cmd_802_11_scan
+	    || command == cmd_802_11_authenticate
+	    || command == cmd_802_11_associate)
+		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
+	else
+		mod_timer(&adapter->command_timer, jiffies + (5*HZ));
+
+	ret = 0;
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_mac_control(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_mac_control);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+
+	lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
+	       mac->action, cmd->size);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  This function inserts command node to cmdfreeq
+ *  after cleans it. Requires adapter->driver_lock held.
+ */
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	if (!ptempcmd)
+		goto done;
+
+	cleanup_cmdnode(ptempcmd);
+	list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+done:
+	return;
+}
+
+void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+	__libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+int libertas_set_radio_control(wlan_private * priv)
+{
+	int ret = 0;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_radio_control,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+	       priv->adapter->radioon, priv->adapter->preamble);
+
+	LEAVE();
+	return ret;
+}
+
+int libertas_set_mac_packet_filter(wlan_private * priv)
+{
+	int ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
+	       priv->adapter->currentpacketfilter);
+
+	/* Send MAC control command to station */
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_mac_control, 0, 0, 0, NULL);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function prepare the command before send to firmware.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param cmd_no	command number
+ *  @param cmd_action	command action: GET or SET
+ *  @param wait_option	wait option: wait response or not
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		0 or -1
+ */
+int libertas_prepare_and_send_command(wlan_private * priv,
+			  u16 cmd_no,
+			  u16 cmd_action,
+			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmdnode;
+	struct cmd_ds_command *cmdptr;
+	unsigned long flags;
+
+	ENTER();
+
+	if (!adapter) {
+		lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
+		ret = -1;
+		goto done;
+	}
+
+	if (adapter->surpriseremoved) {
+		lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
+		ret = -1;
+		goto done;
+	}
+
+	cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+
+	if (cmdnode == NULL) {
+		lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
+
+		/* Wake up main thread to execute next command */
+		wake_up_interruptible(&priv->mainthread.waitq);
+		ret = -1;
+		goto done;
+	}
+
+	libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+	lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
+	       (u32) cmdptr, cmd_no);
+
+	if (!cmdptr) {
+		lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+		libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		ret = -1;
+		goto done;
+	}
+
+	/* Set sequence number, command and INT option */
+	adapter->seqnum++;
+	cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+
+	cmdptr->command = cmd_no;
+	cmdptr->result = 0;
+
+	switch (cmd_no) {
+	case cmd_get_hw_spec:
+		ret = wlan_cmd_hw_spec(priv, cmdptr);
+		break;
+	case cmd_802_11_ps_mode:
+		ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_scan:
+		ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_mac_control:
+		ret = wlan_cmd_mac_control(priv, cmdptr);
+		break;
+
+	case cmd_802_11_associate:
+	case cmd_802_11_reassociate:
+		ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_deauthenticate:
+		ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
+		break;
+
+	case cmd_802_11_set_wep:
+		ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_ad_hoc_start:
+		ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+		break;
+	case cmd_code_dnld:
+		break;
+
+	case cmd_802_11_reset:
+		ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_get_log:
+		ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+		break;
+
+	case cmd_802_11_authenticate:
+		ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_get_stat:
+		ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+		break;
+
+	case cmd_802_11_snmp_mib:
+		ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+					       cmd_action, cmd_oid, pdata_buf);
+		break;
+
+	case cmd_mac_reg_access:
+	case cmd_bbp_reg_access:
+	case cmd_rf_reg_access:
+		ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_rf_channel:
+		ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+						 cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_rf_tx_power:
+		ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+						  cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_radio_control:
+		ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_rf_antenna:
+		ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+						 cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_data_rate:
+		ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+		break;
+	case cmd_802_11_rate_adapt_rateset:
+		ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+							 cmdptr, cmd_action);
+		break;
+
+	case cmd_mac_multicast_adr:
+		ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_ad_hoc_join:
+		ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_rssi:
+		ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+		break;
+
+	case cmd_802_11_ad_hoc_stop:
+		ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
+		break;
+
+	case cmd_802_11_enable_rsn:
+		ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_key_material:
+		ret = wlan_cmd_802_11_key_material(priv, cmdptr,
+						   cmd_action, cmd_oid,
+						   pdata_buf);
+		break;
+
+	case cmd_802_11_pairwise_tsc:
+		break;
+	case cmd_802_11_group_tsc:
+		break;
+
+	case cmd_802_11_mac_address:
+		ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_eeprom_access:
+		ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+						    cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_set_afc:
+	case cmd_802_11_get_afc:
+
+		cmdptr->command = cpu_to_le16(cmd_no);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+				     S_DS_GEN);
+
+		memmove(&cmdptr->params.afc,
+			pdata_buf, sizeof(struct cmd_ds_802_11_afc));
+
+		ret = 0;
+		goto done;
+
+	case cmd_802_11d_domain_info:
+		ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+						   cmd_no, cmd_action);
+		break;
+
+	case cmd_802_11_sleep_params:
+		ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+		break;
+	case cmd_802_11_inactivity_timeout:
+		ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
+							 cmd_action, pdata_buf);
+		libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
+		break;
+
+	case cmd_802_11_tpc_cfg:
+		cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
+				     S_DS_GEN);
+
+		memmove(&cmdptr->params.tpccfg,
+			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
+
+		ret = 0;
+		break;
+	case cmd_802_11_led_gpio_ctrl:
+		{
+			struct mrvlietypes_ledgpio *gpio =
+			    (struct mrvlietypes_ledgpio*)
+			    cmdptr->params.ledgpio.data;
+
+			memmove(&cmdptr->params.ledgpio,
+				pdata_buf,
+				sizeof(struct cmd_ds_802_11_led_ctrl));
+
+			cmdptr->command =
+			    cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+			cmdptr->size =
+			    cpu_to_le16(gpio->header.len + S_DS_GEN +
+					     ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+			gpio->header.len = cpu_to_le16(gpio->header.len);
+
+			ret = 0;
+			break;
+		}
+	case cmd_802_11_pwr_cfg:
+		cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+				     S_DS_GEN);
+		memmove(&cmdptr->params.pwrcfg, pdata_buf,
+			sizeof(struct cmd_ds_802_11_pwr_cfg));
+
+		ret = 0;
+		break;
+	case cmd_bt_access:
+		ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_fwt_access:
+		ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_mesh_access:
+		ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_get_tsf:
+		cmdptr->command = cpu_to_le16(cmd_get_tsf);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
+				     + S_DS_GEN);
+		ret = 0;
+		break;
+	case cmd_802_11_tx_rate_query:
+		cmdptr->command =
+		    cpu_to_le16(cmd_802_11_tx_rate_query);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+				     S_DS_GEN);
+		adapter->txrate = 0;
+		ret = 0;
+		break;
+	default:
+		lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
+		ret = -1;
+		break;
+	}
+
+	/* return error, since the command preparation failed */
+	if (ret != 0) {
+		lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
+		libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		ret = -1;
+		goto done;
+	}
+
+	cmdnode->cmdwaitqwoken = 0;
+
+	libertas_queue_cmd(adapter, cmdnode, 1);
+	adapter->nr_cmd_pending++;
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	if (wait_option & cmd_option_waitforrsp) {
+		lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
+		might_sleep();
+		wait_event_interruptible(cmdnode->cmdwait_q,
+					 cmdnode->cmdwaitqwoken);
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd_retcode) {
+		lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
+		       adapter->cur_cmd_retcode);
+		adapter->cur_cmd_retcode = 0;
+		ret = -1;
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function allocates the command buffer and link
+ *  it to command free queue.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		0 or -1
+ */
+int libertas_allocate_cmd_buffer(wlan_private * priv)
+{
+	int ret = 0;
+	u32 ulbufsize;
+	u32 i;
+	struct cmd_ctrl_node *tempcmd_array;
+	u8 *ptempvirtualaddr;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* Allocate and initialize cmdCtrlNode */
+	ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+	if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
+		lbs_pr_debug(1,
+		       "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+		ret = -1;
+		goto done;
+	}
+
+	adapter->cmd_array = tempcmd_array;
+	memset(adapter->cmd_array, 0, ulbufsize);
+
+	/* Allocate and initialize command buffers */
+	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+		if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) {
+			lbs_pr_debug(1,
+			       "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+			ret = -1;
+			goto done;
+		}
+
+		memset(ptempvirtualaddr, 0, ulbufsize);
+
+		/* Update command buffer virtual */
+		tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+	}
+
+	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+		init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+		libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+	}
+
+	ret = 0;
+      done:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function frees the command buffer.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		0 or -1
+ */
+int libertas_free_cmd_buffer(wlan_private * priv)
+{
+	u32 ulbufsize;
+	unsigned int i;
+	struct cmd_ctrl_node *tempcmd_array;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* need to check if cmd array is allocated or not */
+	if (adapter->cmd_array == NULL) {
+		lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
+		goto done;
+	}
+
+	tempcmd_array = adapter->cmd_array;
+
+	/* Release shared memory buffers */
+	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+		if (tempcmd_array[i].bufvirtualaddr) {
+			lbs_pr_debug(1, "Free all the array\n");
+			kfree(tempcmd_array[i].bufvirtualaddr);
+			tempcmd_array[i].bufvirtualaddr = NULL;
+		}
+	}
+
+	/* Release cmd_ctrl_node */
+	if (adapter->cmd_array) {
+		lbs_pr_debug(1, "Free cmd_array\n");
+		kfree(adapter->cmd_array);
+		adapter->cmd_array = NULL;
+	}
+
+done:
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function gets a free command node if available in
+ *  command free queue.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+{
+	struct cmd_ctrl_node *tempnode;
+	wlan_adapter *adapter = priv->adapter;
+	unsigned long flags;
+
+	if (!adapter)
+		return NULL;
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (!list_empty(&adapter->cmdfreeq)) {
+		tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+		list_del((struct list_head *)tempnode);
+	} else {
+		lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+		tempnode = NULL;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (tempnode) {
+		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+		       tempnode);
+		cleanup_cmdnode(tempnode);
+	}
+
+	return tempnode;
+}
+
+/**
+ *  @brief This function cleans command node.
+ *
+ *  @param ptempnode	A pointer to cmdCtrlNode structure
+ *  @return 		n/a
+ */
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+{
+	if (!ptempnode)
+		return;
+	ptempnode->cmdwaitqwoken = 1;
+	wake_up_interruptible(&ptempnode->cmdwait_q);
+	ptempnode->status = 0;
+	ptempnode->cmd_oid = (u32) 0;
+	ptempnode->wait_option = 0;
+	ptempnode->pdata_buf = NULL;
+
+	if (ptempnode->bufvirtualaddr != NULL)
+		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+	return;
+}
+
+/**
+ *  @brief This function initializes the command node.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param ptempnode	A pointer to cmd_ctrl_node structure
+ *  @param cmd_oid	cmd oid: treated as sub command
+ *  @param wait_option	wait option: wait response or not
+ *  @param pdata_buf	A pointer to informaion buffer
+ *  @return 		0 or -1
+ */
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+		    struct cmd_ctrl_node *ptempnode,
+		    u32 cmd_oid, u16 wait_option, void *pdata_buf)
+{
+	ENTER();
+
+	if (!ptempnode)
+		return;
+
+	ptempnode->cmd_oid = cmd_oid;
+	ptempnode->wait_option = wait_option;
+	ptempnode->pdata_buf = pdata_buf;
+
+	LEAVE();
+}
+
+/**
+ *  @brief This function executes next command in command
+ *  pending queue. It will put fimware back to PS mode
+ *  if applicable.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @return 	   0 or -1
+ */
+int libertas_execute_next_command(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmdnode = NULL;
+	struct cmd_ds_command *cmdptr;
+	unsigned long flags;
+	int ret = 0;
+
+	lbs_pr_debug(1, "libertas_execute_next_command\n");
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (adapter->cur_cmd) {
+		lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	if (!list_empty(&adapter->cmdpendingq)) {
+		cmdnode = (struct cmd_ctrl_node *)
+		    adapter->cmdpendingq.next;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (cmdnode) {
+		lbs_pr_debug(1,
+		       "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+		cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+		if (is_command_allowed_in_ps(cmdptr->command)) {
+			if ((adapter->psstate == PS_STATE_SLEEP)
+			    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+			    ) {
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+				       cmdptr->command, adapter->psstate);
+				ret = -1;
+				goto done;
+			}
+			lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command "
+			       "0x%x in psstate %d\n",
+			       cmdptr->command, adapter->psstate);
+		} else if (adapter->psstate != PS_STATE_FULL_POWER) {
+			/*
+			 * 1. Non-PS command:
+			 * Queue it. set needtowakeup to TRUE if current state
+			 * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
+			 * 2. PS command but not Exit_PS:
+			 * Ignore it.
+			 * 3. PS command Exit_PS:
+			 * Set needtowakeup to TRUE if current state is SLEEP,
+			 * otherwise send this command down to firmware
+			 * immediately.
+			 */
+			if (cmdptr->command !=
+			    cpu_to_le16(cmd_802_11_ps_mode)) {
+				/*  Prepare to send Exit PS,
+				 *  this non PS command will be sent later */
+				if ((adapter->psstate == PS_STATE_SLEEP)
+				    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+				    ) {
+					/* w/ new scheme, it will not reach here.
+					   since it is blocked in main_thread. */
+					adapter->needtowakeup = 1;
+				} else
+					libertas_ps_wakeup(priv, 0);
+
+				ret = 0;
+				goto done;
+			} else {
+				/*
+				 * PS command. Ignore it if it is not Exit_PS.
+				 * otherwise send it down immediately.
+				 */
+				struct cmd_ds_802_11_ps_mode *psm =
+				    &cmdptr->params.psmode;
+
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+				       psm->action);
+				if (psm->action !=
+				    cpu_to_le16(cmd_subcmd_exit_ps)) {
+					lbs_pr_debug(1,
+					       "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+					list_del((struct list_head *)cmdnode);
+					libertas_cleanup_and_insert_cmd(priv, cmdnode);
+
+					ret = 0;
+					goto done;
+				}
+
+				if ((adapter->psstate == PS_STATE_SLEEP)
+				    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+				    ) {
+					lbs_pr_debug(1,
+					       "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+					list_del((struct list_head *)cmdnode);
+					libertas_cleanup_and_insert_cmd(priv, cmdnode);
+					adapter->needtowakeup = 1;
+
+					ret = 0;
+					goto done;
+				}
+
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+			}
+		}
+		list_del((struct list_head *)cmdnode);
+		lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n",
+		       cmdptr->command);
+		DownloadcommandToStation(priv, cmdnode);
+	} else {
+		/*
+		 * check if in power save mode, if yes, put the device back
+		 * to PS mode
+		 */
+		if ((adapter->psmode != wlan802_11powermodecam) &&
+		    (adapter->psstate == PS_STATE_FULL_POWER) &&
+		    (adapter->connect_status == libertas_connected)) {
+			if (adapter->secinfo.WPAenabled
+			    || adapter->secinfo.WPA2enabled) {
+				/* check for valid WPA group keys */
+				if (adapter->wpa_mcast_key.len
+				    || adapter->wpa_unicast_key.len) {
+					lbs_pr_debug(1,
+					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+					       " go back to PS_SLEEP");
+					libertas_ps_sleep(priv, 0);
+				}
+			} else {
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: command PendQ is empty,"
+				       " go back to PS_SLEEP");
+				libertas_ps_sleep(priv, 0);
+			}
+		}
+	}
+
+	ret = 0;
+done:
+	return ret;
+}
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+	union iwreq_data iwrq;
+	u8 buf[50];
+
+	ENTER();
+
+	memset(&iwrq, 0, sizeof(union iwreq_data));
+	memset(buf, 0, sizeof(buf));
+
+	snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+	iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+	/* Send Event to upper layer */
+	lbs_pr_debug(1, "Event Indication string = %s\n",
+	       (char *)buf);
+	lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
+
+	lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
+	wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+
+	LEAVE();
+	return;
+}
+
+static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+{
+	unsigned long flags;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+	       size);
+
+	lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+
+	ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size);
+	priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->intcounter || adapter->currenttxskb)
+		lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+		       adapter->intcounter, adapter->currenttxskb);
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (ret) {
+		lbs_pr_alert(
+		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+	} else {
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (!adapter->intcounter) {
+			adapter->psstate = PS_STATE_SLEEP;
+		} else {
+			lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+			       adapter->intcounter);
+		}
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+		lbs_pr_debug(1, "+");
+	}
+
+	LEAVE();
+	return ret;
+}
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option)
+{
+
+	ENTER();
+
+	/*
+	 * PS is currently supported only in Infrastructure mode
+	 * Remove this check if it is to be supported in IBSS mode also
+	 */
+
+	libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+			      cmd_subcmd_enter_ps, wait_option, 0, NULL);
+
+	LEAVE();
+	return;
+}
+
+/**
+ *  @brief This function sends Eixt_PS command to firmware.
+ *
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param wait_option	wait response or not
+ *  @return 	   	n/a
+ */
+void libertas_ps_wakeup(wlan_private * priv, int wait_option)
+{
+	enum WLAN_802_11_POWER_MODE Localpsmode;
+
+	ENTER();
+
+	Localpsmode = wlan802_11powermodecam;
+
+	lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
+
+	libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+			      cmd_subcmd_exit_ps,
+			      wait_option, 0, &Localpsmode);
+
+	LEAVE();
+	return;
+}
+
+/**
+ *  @brief This function checks condition and prepares to
+ *  send sleep confirm command to firmware if ok.
+ *
+ *  @param priv    	A pointer to wlan_private structure
+ *  @param psmode  	Power Saving mode
+ *  @return 	   	n/a
+ */
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
+{
+	unsigned long flags =0;
+	wlan_adapter *adapter = priv->adapter;
+	u8 allowed = 1;
+
+	ENTER();
+
+	if (priv->wlan_dev.dnld_sent) {
+		allowed = 0;
+		lbs_pr_debug(1, "D");
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd) {
+		allowed = 0;
+		lbs_pr_debug(1, "C");
+	}
+	if (adapter->intcounter > 0) {
+		allowed = 0;
+		lbs_pr_debug(1, "I%d", adapter->intcounter);
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (allowed) {
+		lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
+		sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+				 sizeof(struct PS_CMD_ConfirmSleep));
+	} else {
+		lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
+	}
+
+	LEAVE();
+}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644
index 0000000..cdb012c
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -0,0 +1,1031 @@
+/**
+  * This file contains the handling of command
+  * responses as well as events generated by firmware.
+  */
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+/**
+ *  @brief This function handles disconnect event. it
+ *  reports disconnect to upper layer, clean tx/rx packets,
+ *  reset link state etc.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+void libertas_mac_event_disconnected(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	union iwreq_data wrqu;
+
+	if (adapter->connect_status != libertas_connected)
+		return;
+
+	lbs_pr_debug(1, "Handles disconnect event.\n");
+
+	memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+	/*
+	 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
+	 * It causes problem in the Supplicant
+	 */
+
+	msleep_interruptible(1000);
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+	/* Free Tx and Rx packets */
+	kfree_skb(priv->adapter->currenttxskb);
+	priv->adapter->currenttxskb = NULL;
+
+	/* report disconnect to upper layer */
+	netif_stop_queue(priv->wlan_dev.netdev);
+	netif_carrier_off(priv->wlan_dev.netdev);
+
+	/* reset SNR/NF/RSSI values */
+	memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
+	memset(adapter->NF, 0x00, sizeof(adapter->NF));
+	memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
+	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+	adapter->nextSNRNF = 0;
+	adapter->numSNRNF = 0;
+	adapter->rxpd_rate = 0;
+	lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
+	       adapter->curbssparams.ssid.ssid,
+	       adapter->curbssparams.ssid.ssidlength);
+	lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
+	       adapter->previousssid.ssid, adapter->previousssid.ssidlength);
+
+	/* reset internal flags */
+	adapter->secinfo.WPAenabled = 0;
+	adapter->secinfo.WPA2enabled = 0;
+	adapter->wpa_ie_len = 0;
+	adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+	adapter->secinfo.Encryptionmode = CIPHER_NONE;
+
+	adapter->connect_status = libertas_disconnected;
+
+	/*
+	 * memorize the previous SSID and BSSID
+	 * it could be used for re-assoc
+	 */
+	memcpy(&adapter->previousssid,
+	       &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
+	memcpy(adapter->previousbssid,
+	       adapter->curbssparams.bssid, ETH_ALEN);
+
+	/* need to erase the current SSID and BSSID info */
+	adapter->pattemptedbssdesc = NULL;
+	memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+	if (adapter->psstate != PS_STATE_FULL_POWER) {
+		/* make firmware to exit PS mode */
+		lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
+		libertas_ps_wakeup(priv, 0);
+	}
+}
+
+/**
+ *  @brief This function handles MIC failure event.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @para  event   the event id
+ *  @return 	   n/a
+ */
+static void handle_mic_failureevent(wlan_private * priv, u32 event)
+{
+	char buf[50];
+
+	memset(buf, 0, sizeof(buf));
+
+	sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+	if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
+		strcat(buf, "unicast ");
+	} else {
+		strcat(buf, "multicast ");
+	}
+
+	libertas_send_iwevcustom_event(priv, buf);
+}
+
+static int wlan_ret_reg_access(wlan_private * priv,
+			       u16 type, struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	switch (type) {
+	case cmd_ret_mac_reg_access:
+		{
+			struct cmd_ds_mac_reg_access *reg;
+
+			reg =
+			    (struct cmd_ds_mac_reg_access *)&resp->params.
+			    macreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	case cmd_ret_bbp_reg_access:
+		{
+			struct cmd_ds_bbp_reg_access *reg;
+			reg =
+			    (struct cmd_ds_bbp_reg_access *)&resp->params.
+			    bbpreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	case cmd_ret_rf_reg_access:
+		{
+			struct cmd_ds_rf_reg_access *reg;
+			reg =
+			    (struct cmd_ds_rf_reg_access *)&resp->params.
+			    rfreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	default:
+		LEAVE();
+		return -1;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_get_hw_spec(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	u32 i;
+	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+
+	adapter->fwreleasenumber = hwspec->fwreleasenumber;
+
+	lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+	       adapter->fwreleasenumber);
+	lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+	       hwspec->permanentaddr[0], hwspec->permanentaddr[1],
+	       hwspec->permanentaddr[2], hwspec->permanentaddr[3],
+	       hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
+	lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X  version=0x%X\n",
+	       hwspec->hwifversion, hwspec->version);
+
+	adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+
+	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+		/* use the region code to search for the index */
+		if (adapter->regioncode == libertas_region_code_to_index[i]) {
+			adapter->regiontableindex = (u16) i;
+			break;
+		}
+	}
+
+	/* if it's unidentified region code, use the default (USA) */
+	if (i >= MRVDRV_MAX_REGION_CODE) {
+		adapter->regioncode = 0x10;
+		adapter->regiontableindex = 0;
+		lbs_pr_info(
+		       "unidentified region code, use the default (USA)\n");
+	}
+
+	if (adapter->current_addr[0] == 0xff) {
+		memmove(adapter->current_addr, hwspec->permanentaddr,
+			ETH_ALEN);
+	}
+
+	memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
+	memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+	if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (libertas_set_universaltable(priv, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_ret_802_11_sleep_params(wlan_private * priv,
+					struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+	       " extsleepclk=%x\n", sp->error, sp->offset,
+	       sp->stabletime, sp->calcontrol, sp->externalsleepclk);
+	adapter->sp.sp_error = le16_to_cpu(sp->error);
+	adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+	adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+	adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
+	adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
+	adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_stat(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+/*	currently adapter->wlan802_11Stat is unused
+
+	struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
+	wlan_adapter *adapter = priv->adapter;
+
+	// TODO Convert it to Big endian befor copy
+	memcpy(&adapter->wlan802_11Stat,
+	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
+*/
+	return 0;
+}
+
+static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+				    struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+	u16 oid = le16_to_cpu(smib->oid);
+	u16 querytype = le16_to_cpu(smib->querytype);
+
+	ENTER();
+
+	lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+	       querytype);
+	lbs_pr_debug(1, "SNMP_RESP: Buf size  = %x\n",
+	       le16_to_cpu(smib->bufsize));
+
+	if (querytype == cmd_act_get) {
+		switch (oid) {
+		case fragthresh_i:
+			priv->adapter->fragthsd =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
+			       priv->adapter->fragthsd);
+			break;
+		case rtsthresh_i:
+			priv->adapter->rtsthsd =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
+			       priv->adapter->rtsthsd);
+			break;
+		case short_retrylim_i:
+			priv->adapter->txretrycount =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
+			       priv->adapter->rtsthsd);
+			break;
+		default:
+			break;
+		}
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_key_material(wlan_private * priv,
+					struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_key_material *pkeymaterial =
+	    &resp->params.keymaterial;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(pkeymaterial->action);
+
+	ENTER();
+
+	/* Copy the returned key to driver private data */
+	if (action == cmd_act_get) {
+		u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+		u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+		while (buf_ptr < resp_end) {
+			struct MrvlIEtype_keyParamSet * pkeyparamset =
+			    (struct MrvlIEtype_keyParamSet *) buf_ptr;
+			struct WLAN_802_11_KEY * pkey;
+			u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+			u8 * end;
+			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+
+			end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+			                          + sizeof (pkeyparamset->length)
+			                          + param_set_len;
+			/* Make sure we don't access past the end of the IEs */
+			if (end > resp_end)
+				break;
+
+			if (key_info & KEY_INFO_WPA_UNICAST)
+				pkey = &adapter->wpa_unicast_key;
+			else if (key_info & KEY_INFO_WPA_MCAST)
+				pkey = &adapter->wpa_mcast_key;
+			else
+				break;
+
+			/* Copy returned key into driver */
+			memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+			if (key_len > sizeof(pkey->key))
+				break;
+			pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+			pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+			pkey->len = le16_to_cpu(pkeyparamset->keylen);
+			memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+			buf_ptr = end + 1;
+		}
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_mac_address(wlan_private * priv,
+				       struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+				       struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+	lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+				      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(pAntenna->action);
+
+	if (action == cmd_act_get_rx)
+		adapter->rxantennamode =
+		    le16_to_cpu(pAntenna->antennamode);
+
+	if (action == cmd_act_get_tx)
+		adapter->txantennamode =
+		    le16_to_cpu(pAntenna->antennamode);
+
+	lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+	       action, le16_to_cpu(pAntenna->antennamode));
+
+	return 0;
+}
+
+static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+					      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rate_adapt_rateset *rates =
+	    &resp->params.rateset;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (rates->action == cmd_act_get) {
+		adapter->enablehwauto = rates->enablehwauto;
+		adapter->ratebitmap = rates->bitmap;
+	}
+
+	LEAVE();
+
+	return 0;
+}
+
+static int wlan_ret_802_11_data_rate(wlan_private * priv,
+				     struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+	wlan_adapter *adapter = priv->adapter;
+	u8 dot11datarate;
+
+	ENTER();
+
+	lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+		(u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+
+	dot11datarate = pdatarate->datarate[0];
+	if (pdatarate->action == cmd_act_get_tx_rate) {
+		memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
+		       sizeof(adapter->libertas_supported_rates));
+	}
+	adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+				      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_channel *rfchannel =
+	    &resp->params.rfchannel;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(rfchannel->action);
+	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+
+	ENTER();
+
+	if (action == cmd_opt_802_11_rf_channel_get
+	    && adapter->curbssparams.channel != newchannel) {
+		lbs_pr_debug(1, "channel Switch: %d to %d\n",
+		       adapter->curbssparams.channel, newchannel);
+
+		/* Update the channel again */
+		adapter->curbssparams.channel = newchannel;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rssi(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+	wlan_adapter *adapter = priv->adapter;
+
+	/* store the non average value */
+	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+	adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+	    le16_to_cpu(rssirsp->noisefloor);
+
+	adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+	adapter->NF[TYPE_BEACON][TYPE_AVG] =
+	    le16_to_cpu(rssirsp->avgnoisefloor);
+
+	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+		     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+	adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+		     adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+	lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
+	       adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+	return 0;
+}
+
+static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+				  struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_ioctl_regrdwr *pbuf;
+	pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+
+	lbs_pr_debug(1, "eeprom read len=%x\n",
+	       le16_to_cpu(resp->params.rdeeprom.bytecount));
+	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+		pbuf->NOB = 0;
+		lbs_pr_debug(1, "eeprom read return length is too big\n");
+		return -1;
+	}
+	pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+	if (pbuf->NOB > 0) {
+
+		memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+		       le16_to_cpu(resp->params.rdeeprom.bytecount));
+		lbs_dbg_hex("adapter", (char *)&pbuf->value,
+			le16_to_cpu(resp->params.rdeeprom.bytecount));
+	}
+	return 0;
+}
+
+static int wlan_ret_get_log(wlan_private * priv,
+			    struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_get_log *logmessage =
+	    (struct cmd_ds_802_11_get_log *)&resp->params.glog;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* TODO Convert it to Big Endian before copy */
+	memcpy(&adapter->logmsg, logmessage,
+	       sizeof(struct cmd_ds_802_11_get_log));
+
+	LEAVE();
+	return 0;
+}
+
+static inline int handle_cmd_response(u16 respcmd,
+				      struct cmd_ds_command *resp,
+				      wlan_private *priv)
+{
+	int ret = 0;
+	unsigned long flags;
+	wlan_adapter *adapter = priv->adapter;
+
+	switch (respcmd) {
+	case cmd_ret_mac_reg_access:
+	case cmd_ret_bbp_reg_access:
+	case cmd_ret_rf_reg_access:
+		ret = wlan_ret_reg_access(priv, respcmd, resp);
+		break;
+
+	case cmd_ret_hw_spec_info:
+		ret = wlan_ret_get_hw_spec(priv, resp);
+		break;
+
+	case cmd_ret_802_11_scan:
+		ret = libertas_ret_80211_scan(priv, resp);
+		break;
+
+	case cmd_ret_802_11_get_log:
+		ret = wlan_ret_get_log(priv, resp);
+		break;
+
+	case cmd_ret_802_11_associate:
+	case cmd_ret_802_11_reassociate:
+		ret = libertas_ret_80211_associate(priv, resp);
+		break;
+
+	case cmd_ret_802_11_disassociate:
+	case cmd_ret_802_11_deauthenticate:
+		ret = libertas_ret_80211_disassociate(priv, resp);
+		break;
+
+	case cmd_ret_802_11_ad_hoc_start:
+	case cmd_ret_802_11_ad_hoc_join:
+		ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+		break;
+
+	case cmd_ret_802_11_stat:
+		ret = wlan_ret_802_11_stat(priv, resp);
+		break;
+
+	case cmd_ret_802_11_snmp_mib:
+		ret = wlan_ret_802_11_snmp_mib(priv, resp);
+		break;
+
+	case cmd_ret_802_11_rf_tx_power:
+		ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+		break;
+
+	case cmd_ret_802_11_set_afc:
+	case cmd_ret_802_11_get_afc:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.afc,
+			sizeof(struct cmd_ds_802_11_afc));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		break;
+	case cmd_ret_802_11_rf_antenna:
+		ret = wlan_ret_802_11_rf_antenna(priv, resp);
+		break;
+
+	case cmd_ret_mac_multicast_adr:
+	case cmd_ret_mac_control:
+	case cmd_ret_802_11_set_wep:
+	case cmd_ret_802_11_reset:
+	case cmd_ret_802_11_authenticate:
+	case cmd_ret_802_11_radio_control:
+	case cmd_ret_802_11_beacon_stop:
+	case cmd_ret_802_11_enable_rsn:
+		break;
+
+	case cmd_ret_802_11_data_rate:
+		ret = wlan_ret_802_11_data_rate(priv, resp);
+		break;
+	case cmd_ret_802_11_rate_adapt_rateset:
+		ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+		break;
+	case cmd_ret_802_11_rf_channel:
+		ret = wlan_ret_802_11_rf_channel(priv, resp);
+		break;
+
+	case cmd_ret_802_11_rssi:
+		ret = wlan_ret_802_11_rssi(priv, resp);
+		break;
+
+	case cmd_ret_802_11_mac_address:
+		ret = wlan_ret_802_11_mac_address(priv, resp);
+		break;
+
+	case cmd_ret_802_11_ad_hoc_stop:
+		ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+		break;
+
+	case cmd_ret_802_11_key_material:
+		lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
+		ret = wlan_ret_802_11_key_material(priv, resp);
+		break;
+
+	case cmd_ret_802_11_eeprom_access:
+		ret = wlan_ret_802_11_eeprom_access(priv, resp);
+		break;
+
+	case cmd_ret_802_11d_domain_info:
+		ret = libertas_ret_802_11d_domain_info(priv, resp);
+		break;
+
+	case cmd_ret_802_11_sleep_params:
+		ret = wlan_ret_802_11_sleep_params(priv, resp);
+		break;
+	case cmd_ret_802_11_inactivity_timeout:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		*((u16 *) adapter->cur_cmd->pdata_buf) =
+		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+
+	case cmd_ret_802_11_tpc_cfg:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.tpccfg,
+			sizeof(struct cmd_ds_802_11_tpc_cfg));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_802_11_led_gpio_ctrl:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.ledgpio,
+			sizeof(struct cmd_ds_802_11_led_ctrl));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_802_11_pwr_cfg:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.pwrcfg,
+			sizeof(struct cmd_ds_802_11_pwr_cfg));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		break;
+
+	case cmd_ret_get_tsf:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memcpy(priv->adapter->cur_cmd->pdata_buf,
+		       &resp->params.gettsf.tsfvalue, sizeof(u64));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_bt_access:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.bt.addr1, 2 * ETH_ALEN);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_fwt_access:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.fwt,
+				sizeof(resp->params.fwt));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_mesh_access:
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.mesh,
+			       sizeof(resp->params.mesh));
+		break;
+	case cmd_rte_802_11_tx_rate_query:
+		priv->adapter->txrate = resp->params.txrate.txrate;
+		break;
+	default:
+		lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
+		       resp->command);
+		break;
+	}
+	return ret;
+}
+
+int libertas_process_rx_command(wlan_private * priv)
+{
+	u16 respcmd;
+	struct cmd_ds_command *resp;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	ulong flags;
+	u16 result;
+
+	ENTER();
+
+	lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
+
+	/* Now we got response from FW, cancel the command timer */
+	del_timer(&adapter->command_timer);
+
+	mutex_lock(&adapter->lock);
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (!adapter->cur_cmd) {
+		lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+		ret = -1;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		goto done;
+	}
+	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+	lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+		priv->wlan_dev.upld_len);
+
+	respcmd = le16_to_cpu(resp->command);
+
+	result = le16_to_cpu(resp->result);
+
+	lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
+	       result, priv->wlan_dev.upld_len);
+
+	if (!(respcmd & 0x8000)) {
+		lbs_pr_debug(1, "Invalid response to command!");
+		adapter->cur_cmd_retcode = -1;
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	/* Store the response code to cur_cmd_retcode. */
+	adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
+
+	if (respcmd == cmd_ret_802_11_ps_mode) {
+		struct cmd_ds_802_11_ps_mode *psmode;
+
+		psmode = &resp->params.psmode;
+		lbs_pr_debug(1,
+		       "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+		       resp->result, psmode->action);
+		psmode->action = cpu_to_le16(psmode->action);
+
+		if (result) {
+			lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
+			       resp->result);
+			if (adapter->inframode == wlan802_11ibss) {
+				/*
+				 * We should not re-try enter-ps command in
+				 * ad-hoc mode. It takes place in
+				 * libertas_execute_next_command().
+				 */
+				if (psmode->action == cmd_subcmd_enter_ps)
+					adapter->psmode =
+					    wlan802_11powermodecam;
+			}
+		} else if (psmode->action == cmd_subcmd_enter_ps) {
+			adapter->needtowakeup = 0;
+			adapter->psstate = PS_STATE_AWAKE;
+
+			lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
+			if (adapter->connect_status != libertas_connected) {
+				/*
+				 * When Deauth Event received before Enter_PS command
+				 * response, We need to wake up the firmware.
+				 */
+				lbs_pr_debug(1,
+				       "Disconnected, Going to invoke libertas_ps_wakeup\n");
+
+				mutex_unlock(&adapter->lock);
+				spin_unlock_irqrestore(&adapter->driver_lock, flags);
+				libertas_ps_wakeup(priv, 0);
+				mutex_lock(&adapter->lock);
+				spin_lock_irqsave(&adapter->driver_lock, flags);
+			}
+		} else if (psmode->action == cmd_subcmd_exit_ps) {
+			adapter->needtowakeup = 0;
+			adapter->psstate = PS_STATE_FULL_POWER;
+			lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
+		} else {
+			lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
+			       psmode->action);
+		}
+
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		ret = 0;
+		goto done;
+	}
+
+	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+		/* Copy the response back to response buffer */
+		memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+
+		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+	}
+
+	/* If the command is not successful, cleanup and return failure */
+	if ((result != 0 || !(respcmd & 0x8000))) {
+		lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
+		       resp->command, resp->result);
+		/*
+		 * Handling errors here
+		 */
+		switch (respcmd) {
+		case cmd_ret_hw_spec_info:
+		case cmd_ret_802_11_reset:
+			lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
+			break;
+
+		}
+
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		ret = -1;
+		goto done;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	ret = handle_cmd_response(respcmd, resp, priv);
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd) {
+		/* Clean up and Put current command back to cmdfreeq */
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		WARN_ON(adapter->nr_cmd_pending > 128);
+		adapter->cur_cmd = NULL;
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+	mutex_unlock(&adapter->lock);
+	LEAVE();
+	return ret;
+}
+
+int libertas_process_event(wlan_private * priv)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	u32 eventcause;
+
+	spin_lock_irq(&adapter->driver_lock);
+	eventcause = adapter->eventcause;
+	spin_unlock_irq(&adapter->driver_lock);
+
+	ENTER();
+
+	lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
+
+	switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+	case MACREG_INT_CODE_LINK_SENSED:
+		lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+		break;
+
+	case MACREG_INT_CODE_DEAUTHENTICATED:
+		lbs_pr_debug(1, "EVENT: Deauthenticated\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_DISASSOCIATED:
+		lbs_pr_debug(1, "EVENT: Disassociated\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+		lbs_pr_debug(1, "EVENT: Link lost\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_PS_SLEEP:
+		lbs_pr_debug(1, "EVENT: SLEEP\n");
+		lbs_pr_debug(1, "_");
+
+		/* handle unexpected PS SLEEP event */
+		if (adapter->psstate == PS_STATE_FULL_POWER) {
+			lbs_pr_debug(1,
+			       "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+			break;
+		}
+		adapter->psstate = PS_STATE_PRE_SLEEP;
+
+		libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
+
+		break;
+
+	case MACREG_INT_CODE_PS_AWAKE:
+		lbs_pr_debug(1, "EVENT: AWAKE \n");
+		lbs_pr_debug(1, "|");
+
+		/* handle unexpected PS AWAKE event */
+		if (adapter->psstate == PS_STATE_FULL_POWER) {
+			lbs_pr_debug(1,
+			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+			break;
+		}
+
+		adapter->psstate = PS_STATE_AWAKE;
+
+		if (adapter->needtowakeup) {
+			/*
+			 * wait for the command processing to finish
+			 * before resuming sending
+			 * adapter->needtowakeup will be set to FALSE
+			 * in libertas_ps_wakeup()
+			 */
+			lbs_pr_debug(1, "Waking up...\n");
+			libertas_ps_wakeup(priv, 0);
+		}
+		break;
+
+	case MACREG_INT_CODE_MIC_ERR_UNICAST:
+		lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
+		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+		break;
+
+	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+		lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
+		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+		break;
+	case MACREG_INT_CODE_MIB_CHANGED:
+	case MACREG_INT_CODE_INIT_DONE:
+		break;
+
+	case MACREG_INT_CODE_ADHOC_BCN_LOST:
+		lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
+		break;
+
+	case MACREG_INT_CODE_RSSI_LOW:
+		lbs_pr_alert( "EVENT: RSSI_LOW\n");
+		break;
+	case MACREG_INT_CODE_SNR_LOW:
+		lbs_pr_alert( "EVENT: SNR_LOW\n");
+		break;
+	case MACREG_INT_CODE_MAX_FAIL:
+		lbs_pr_alert( "EVENT: MAX_FAIL\n");
+		break;
+	case MACREG_INT_CODE_RSSI_HIGH:
+		lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+		break;
+	case MACREG_INT_CODE_SNR_HIGH:
+		lbs_pr_alert( "EVENT: SNR_HIGH\n");
+		break;
+
+	default:
+		lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+		       eventcause >> SBI_EVENT_CAUSE_SHIFT);
+		break;
+	}
+
+	spin_lock_irq(&adapter->driver_lock);
+	adapter->eventcause = 0;
+	spin_unlock_irq(&adapter->driver_lock);
+	LEAVE();
+	return ret;
+}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644
index 0000000..51dfd20
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -0,0 +1,1935 @@
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <net/iw_handler.h>
+#include "dev.h"
+#include "decl.h"
+#include "host.h"
+
+static struct dentry *libertas_dir = NULL;
+static char *szStates[] = {
+	"Connected",
+	"Disconnected"
+};
+
+void libertas_debug_init(wlan_private * priv, struct net_device *dev);
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+        return -EINVAL;
+}
+
+static const size_t len = PAGE_SIZE;
+
+static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	size_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	ssize_t res;
+
+	pos += snprintf(buf+pos, len-pos, "state = %s\n",
+				szStates[priv->adapter->connect_status]);
+	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+				(u32) priv->adapter->regioncode);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return res;
+}
+
+
+static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	size_t pos = 0;
+	int numscansdone = 0, res;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	pos += snprintf(buf+pos, len-pos,
+			"---------------------------------------");
+	pos += snprintf(buf+pos, len-pos,
+			"---------------------------------------\n");
+	pos += snprintf(buf+pos, len-pos,
+		"# | ch  | ss  |       bssid       |   cap    |    TSF   | Qual | SSID \n");
+	pos += snprintf(buf+pos, len-pos,
+		"---------------------------------------");
+	pos += snprintf(buf+pos, len-pos,
+		"---------------------------------------\n");
+
+	while (numscansdone < priv->adapter->numinscantable) {
+		struct bss_descriptor *pbssinfo;
+		u16 cap;
+
+		pbssinfo = &priv->adapter->scantable[numscansdone];
+		memcpy(&cap, &pbssinfo->cap, sizeof(cap));
+		pos += snprintf(buf+pos, len-pos,
+			"%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
+			numscansdone, pbssinfo->channel, pbssinfo->rssi,
+			pbssinfo->macaddress[0], pbssinfo->macaddress[1],
+			pbssinfo->macaddress[2], pbssinfo->macaddress[3],
+			pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
+		pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+				pbssinfo->cap.ibss ? 'A' : 'I',
+				pbssinfo->cap.privacy ? 'P' : ' ',
+				pbssinfo->cap.spectrummgmt ? 'S' : ' ');
+		pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
+		pos += snprintf(buf+pos, len-pos, " %d |",
+			SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
+
+		pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
+
+		numscansdone++;
+	}
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_sleepparams_write(struct file *file,
+				const char __user *user_buf, size_t count,
+				loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t buf_size, res;
+	int p1, p2, p3, p4, p5, p6;
+	struct sleep_params sp;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+	if (res != 6) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	sp.sp_error = p1;
+	sp.sp_offset = p2;
+	sp.sp_stabletime = p3;
+	sp.sp_calcontrol = p4;
+	sp.sp_extsleepclk = p5;
+	sp.sp_reserved = p6;
+
+	memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
+
+        res = libertas_prepare_and_send_command(priv,
+				cmd_802_11_sleep_params,
+				cmd_act_set,
+				cmd_option_waitforrsp, 0, NULL);
+
+	if (!res)
+		res = count;
+	else
+		res = -EINVAL;
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res;
+	size_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+        res = libertas_prepare_and_send_command(priv,
+				cmd_802_11_sleep_params,
+				cmd_act_get,
+				cmd_option_waitforrsp, 0, NULL);
+	if (res) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+			adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+			adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+			adapter->sp.sp_reserved);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	struct WLAN_802_11_SSID extscan_ssid;
+	union iwreq_data wrqu;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
+	extscan_ssid.ssidlength = strlen(buf)-1;
+
+	libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
+
+	memset(&wrqu, 0, sizeof(union iwreq_data));
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+	free_page(addr);
+	return count;
+}
+
+static int libertas_parse_chan(char *buf, size_t count,
+			struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+{
+	char *start, *end, *hold, *str;
+	int i = 0;
+
+	start = strstr(buf, "chan=");
+	if (!start)
+		return -EINVAL;
+	start += 5;
+	end = strstr(start, " ");
+	if (!end)
+		end = buf + count;
+	hold = kzalloc((end - start)+1, GFP_KERNEL);
+	if (!hold)
+		return -ENOMEM;
+	strncpy(hold, start, end - start);
+	hold[(end-start)+1] = '\0';
+	while(hold && (str = strsep(&hold, ","))) {
+		int chan;
+		char band, passive = 0;
+		sscanf(str, "%d%c%c", &chan, &band, &passive);
+		scan_cfg->chanlist[i].channumber = chan;
+		scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+		if (band == 'b' || band == 'g')
+			scan_cfg->chanlist[i].radiotype = 0;
+		else if (band == 'a')
+			scan_cfg->chanlist[i].radiotype = 1;
+
+		scan_cfg->chanlist[i].scantime = dur;
+		i++;
+	}
+
+	kfree(hold);
+	return i;
+}
+
+static void libertas_parse_bssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	unsigned int mac[ETH_ALEN];
+	int i;
+
+	hold = strstr(buf, "bssid=");
+	if (!hold)
+		return;
+	hold += 6;
+	sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
+			mac+4, mac+5);
+	for(i=0;i<ETH_ALEN;i++)
+		scan_cfg->specificBSSID[i] = mac[i];
+}
+
+static void libertas_parse_ssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold, *end;
+	ssize_t size;
+
+	hold = strstr(buf, "ssid=");
+	if (!hold)
+		return;
+	hold += 5;
+	end = strstr(hold, " ");
+	if (!end)
+		end = buf + count - 1;
+
+	size = min(IW_ESSID_MAX_SIZE, end - hold);
+	strncpy(scan_cfg->specificSSID, hold, size);
+
+	return;
+}
+
+static void libertas_parse_keep(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "keep=");
+	if (!hold)
+		return;
+	hold += 5;
+	sscanf(hold, "%d", &val);
+
+	if (val != 0)
+		val = 1;
+
+	scan_cfg->keeppreviousscan = val;
+	return;
+}
+
+static int libertas_parse_dur(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "dur=");
+	if (!hold)
+		return 0;
+	hold += 4;
+	sscanf(hold, "%d", &val);
+
+	return val;
+}
+
+static void libertas_parse_probes(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "probes=");
+	if (!hold)
+		return;
+	hold += 7;
+	sscanf(hold, "%d", &val);
+
+	scan_cfg->numprobes = val;
+
+	return;
+}
+
+static void libertas_parse_type(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "type=");
+	if (!hold)
+		return;
+	hold += 5;
+	sscanf(hold, "%d", &val);
+
+	/* type=1,2 or 3 */
+	if (val < 1 || val > 3)
+		return;
+
+	scan_cfg->bsstype = val;
+
+	return;
+}
+
+static ssize_t libertas_setuserscan(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	struct wlan_ioctl_user_scan_cfg *scan_cfg;
+	union iwreq_data wrqu;
+	int dur;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+	if (!scan_cfg)
+		return -ENOMEM;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+
+	dur = libertas_parse_dur(buf, count, scan_cfg);
+	libertas_parse_chan(buf, count, scan_cfg, dur);
+	libertas_parse_bssid(buf, count, scan_cfg);
+	libertas_parse_ssid(buf, count, scan_cfg);
+	libertas_parse_keep(buf, count, scan_cfg);
+	libertas_parse_probes(buf, count, scan_cfg);
+	libertas_parse_type(buf, count, scan_cfg);
+
+	wlan_scan_networks(priv, scan_cfg);
+	wait_event_interruptible(priv->adapter->cmd_pending,
+				 !priv->adapter->nr_cmd_pending);
+
+	memset(&wrqu, 0x00, sizeof(union iwreq_data));
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+	free_page(addr);
+	kfree(scan_cfg);
+	return count;
+}
+
+static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+			struct cmd_ctrl_node **cmdnode,
+			struct cmd_ds_command **cmd)
+{
+	u16 wait_option = cmd_option_waitforrsp;
+
+	if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+		lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
+		return -ENOMEM;
+	}
+	if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+		lbs_pr_debug(1, "failed to allocate response buffer!\n");
+		return -ENOMEM;
+	}
+	libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+	init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+	(*cmdnode)->pdata_buf = *response_buf;
+	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+	(*cmdnode)->cmdwaitqwoken = 0;
+	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+	(*cmd)->command = cmd_802_11_subscribe_event;
+	(*cmd)->seqnum = ++priv->adapter->seqnum;
+	(*cmd)->result = 0;
+	return 0;
+}
+
+static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_rssithreshold  *Lowrssi;
+		case TLV_TYPE_RSSI_LOW:
+		Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				Lowrssi->rssivalue,
+				Lowrssi->rssifreq,
+				(event->events & 0x0001)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static u16 libertas_get_events_bitmap(wlan_private *priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res;
+	u16 event_bitmap;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		return res;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		return 0;
+	}
+
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	event_bitmap = event->events;
+	kfree(response_buf);
+	return event_bitmap;
+}
+
+static ssize_t libertas_lowrssi_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_rssithreshold *rssi_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_rssithreshold));
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+	rssi_threshold->header.type = cpu_to_le16(0x0104);
+	rssi_threshold->header.len = 2;
+	rssi_threshold->rssivalue = cpu_to_le16(value);
+	rssi_threshold->rssifreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0001 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_snrthreshold *LowSnr;
+		case TLV_TYPE_SNR_LOW:
+		LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				LowSnr->snrvalue,
+				LowSnr->snrfreq,
+				(event->events & 0x0002)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_lowsnr_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_snrthreshold *snr_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_snrthreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+	snr_threshold->header.len = 2;
+	snr_threshold->snrvalue = cpu_to_le16(value);
+	snr_threshold->snrfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0002 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_failurecount *failcount;
+		case TLV_TYPE_FAILCOUNT:
+		failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				failcount->failvalue,
+				failcount->Failfreq,
+				(event->events & 0x0004)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_failurecount);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_failcount_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_failurecount *failcount;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_failurecount));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	failcount = (struct mrvlietypes_failurecount *)(ptr);
+	failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+	failcount->header.len = 2;
+	failcount->failvalue = cpu_to_le16(value);
+	failcount->Failfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0004 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = (struct cmd_ds_command *)response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_beaconsmissed *bcnmiss;
+		case TLV_TYPE_BCNMISS:
+		bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+				bcnmiss->beaconmissed,
+				(event->events & 0x0008)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_bcnmiss_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_beaconsmissed *bcnmiss;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_beaconsmissed));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+	bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+	bcnmiss->header.len = 2;
+	bcnmiss->beaconmissed = cpu_to_le16(value);
+	event_bitmap |= subscribed ? 0x0008 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_rssithreshold  *Highrssi;
+		case TLV_TYPE_RSSI_HIGH:
+		Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				Highrssi->rssivalue,
+				Highrssi->rssifreq,
+				(event->events & 0x0010)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highrssi_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_rssithreshold *rssi_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_rssithreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+	rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+	rssi_threshold->header.len = 2;
+	rssi_threshold->rssivalue = cpu_to_le16(value);
+	rssi_threshold->rssifreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0010 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_snrthreshold *HighSnr;
+		case TLV_TYPE_SNR_HIGH:
+		HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				HighSnr->snrvalue,
+				HighSnr->snrfreq,
+				(event->events & 0x0020)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highsnr_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_snrthreshold *snr_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_snrthreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+	snr_threshold->header.len = 2;
+	snr_threshold->snrvalue = cpu_to_le16(value);
+	snr_threshold->snrfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0020 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->mac_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_mac_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+				priv->mac_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return ret;
+}
+
+static ssize_t libertas_rdmac_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrmac_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_mac_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->bbp_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_bbp_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+				priv->bbp_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+
+	return ret;
+}
+
+static ssize_t libertas_rdbbp_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrbbp_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_bbp_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->rf_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_rf_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+				priv->rf_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+
+	return ret;
+}
+
+static ssize_t libertas_rdrf_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrrf_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_rf_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+#define FOPS(fread, fwrite) { \
+	.owner = THIS_MODULE, \
+	.open = open_file_generic, \
+	.read = (fread), \
+	.write = (fwrite), \
+}
+
+struct libertas_debugfs_files {
+	char *name;
+	int perm;
+	struct file_operations fops;
+};
+
+struct libertas_debugfs_files debugfs_files[] = {
+	{ "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+	{ "getscantable", 0444, FOPS(libertas_getscantable,
+					write_file_dummy), },
+	{ "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+				libertas_sleepparams_write), },
+	{ "extscan", 0600, FOPS(NULL, libertas_extscan), },
+	{ "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+};
+
+struct libertas_debugfs_files debugfs_events_files[] = {
+	{"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+				libertas_lowrssi_write), },
+	{"low_snr", 0644, FOPS(libertas_lowsnr_read,
+				libertas_lowsnr_write), },
+	{"failure_count", 0644, FOPS(libertas_failcount_read,
+				libertas_failcount_write), },
+	{"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+				libertas_bcnmiss_write), },
+	{"high_rssi", 0644, FOPS(libertas_highrssi_read,
+				libertas_highrssi_write), },
+	{"high_snr", 0644, FOPS(libertas_highsnr_read,
+				libertas_highsnr_write), },
+};
+
+struct libertas_debugfs_files debugfs_regs_files[] = {
+	{"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+	{"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+	{"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+	{"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+	{"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+	{"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+};
+
+void libertas_debugfs_init(void)
+{
+	if (!libertas_dir)
+		libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
+
+	return;
+}
+
+void libertas_debugfs_remove(void)
+{
+	if (libertas_dir)
+		 debugfs_remove(libertas_dir);
+	return;
+}
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
+{
+	int i;
+	struct libertas_debugfs_files *files;
+	if (!libertas_dir)
+		goto exit;
+
+	priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+	if (!priv->debugfs_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+		files = &debugfs_files[i];
+		priv->debugfs_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->debugfs_dir,
+							     priv,
+							     &files->fops);
+	}
+
+	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+	if (!priv->events_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+		files = &debugfs_events_files[i];
+		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->events_dir,
+							     priv,
+							     &files->fops);
+	}
+
+	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+	if (!priv->regs_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+		files = &debugfs_regs_files[i];
+		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->regs_dir,
+							     priv,
+							     &files->fops);
+	}
+
+#ifdef PROC_DEBUG
+	libertas_debug_init(priv, dev);
+#endif
+exit:
+	return;
+}
+
+void libertas_debugfs_remove_one(wlan_private *priv)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+		debugfs_remove(priv->debugfs_regs_files[i]);
+
+	debugfs_remove(priv->regs_dir);
+
+	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+		debugfs_remove(priv->debugfs_events_files[i]);
+
+	debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+	debugfs_remove(priv->debugfs_debug);
+#endif
+	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+		debugfs_remove(priv->debugfs_files[i]);
+}
+
+/* debug entry */
+
+#define item_size(n)	(FIELD_SIZEOF(wlan_adapter, n))
+#define item_addr(n)	(offsetof(wlan_adapter, n))
+
+struct debug_data {
+	char name[32];
+	u32 size;
+	u32 addr;
+};
+
+/* To debug any member of wlan_adapter, simply add one line here.
+ */
+static struct debug_data items[] = {
+	{"intcounter", item_size(intcounter), item_addr(intcounter)},
+	{"psmode", item_size(psmode), item_addr(psmode)},
+	{"psstate", item_size(psstate), item_addr(psstate)},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/**
+ *  @brief proc read function
+ *
+ *  @param page	   pointer to buffer
+ *  @param s       read data starting position
+ *  @param off     offset
+ *  @param cnt     counter
+ *  @param eof     end of file flag
+ *  @param data    data to output
+ *  @return 	   number of output data
+ */
+static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
+			size_t count, loff_t *ppos)
+{
+	int val = 0;
+	size_t pos = 0;
+	ssize_t res;
+	char *p;
+	int i;
+	struct debug_data *d;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	p = buf;
+
+	d = (struct debug_data *)file->private_data;
+
+	for (i = 0; i < num_of_items; i++) {
+		if (d[i].size == 1)
+			val = *((u8 *) d[i].addr);
+		else if (d[i].size == 2)
+			val = *((u16 *) d[i].addr);
+		else if (d[i].size == 4)
+			val = *((u32 *) d[i].addr);
+
+		pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
+	}
+
+	res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
+
+	free_page(addr);
+	return res;
+}
+
+/**
+ *  @brief proc write function
+ *
+ *  @param f	   file pointer
+ *  @param buf     pointer to data buffer
+ *  @param cnt     data number to write
+ *  @param data    data to write
+ *  @return 	   number of data
+ */
+static int wlan_debugfs_write(struct file *f, const char __user *buf,
+			    size_t cnt, loff_t *ppos)
+{
+	int r, i;
+	char *pdata;
+	char *p;
+	char *p0;
+	char *p1;
+	char *p2;
+	struct debug_data *d = (struct debug_data *)f->private_data;
+
+	pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+	if (pdata == NULL)
+		return 0;
+
+	if (copy_from_user(pdata, buf, cnt)) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		kfree(pdata);
+		return 0;
+	}
+
+	p0 = pdata;
+	for (i = 0; i < num_of_items; i++) {
+		do {
+			p = strstr(p0, d[i].name);
+			if (p == NULL)
+				break;
+			p1 = strchr(p, '\n');
+			if (p1 == NULL)
+				break;
+			p0 = p1++;
+			p2 = strchr(p, '=');
+			if (!p2)
+				break;
+			p2++;
+			r = simple_strtoul(p2, NULL, 0);
+			if (d[i].size == 1)
+				*((u8 *) d[i].addr) = (u8) r;
+			else if (d[i].size == 2)
+				*((u16 *) d[i].addr) = (u16) r;
+			else if (d[i].size == 4)
+				*((u32 *) d[i].addr) = (u32) r;
+			break;
+		} while (1);
+	}
+	kfree(pdata);
+
+	return cnt;
+}
+
+static struct file_operations libertas_debug_fops = {
+	.owner = THIS_MODULE,
+	.open = open_file_generic,
+	.write = wlan_debugfs_write,
+	.read = wlan_debugfs_read,
+};
+
+/**
+ *  @brief create debug proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @param dev     pointer net_device
+ *  @return 	   N/A
+ */
+void libertas_debug_init(wlan_private * priv, struct net_device *dev)
+{
+	int i;
+
+	if (!priv->debugfs_dir)
+		return;
+
+	for (i = 0; i < num_of_items; i++)
+		items[i].addr += (u32) priv->adapter;
+
+	priv->debugfs_debug = debugfs_create_file("debug", 0644,
+						  priv->debugfs_dir, &items[0],
+						  &libertas_debug_fops);
+}
+
+/**
+ *  @brief remove proc file
+ *
+ *  @param priv	   pointer wlan_private
+ *  @return 	   N/A
+ */
+void libertas_debug_remove(wlan_private * priv)
+{
+	debugfs_remove(priv->debugfs_debug);
+}
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644
index 0000000..880a11b
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -0,0 +1,6 @@
+void libertas_debugfs_init(void);
+void libertas_debugfs_remove(void);
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
+void libertas_debugfs_remove_one(wlan_private *priv);
+
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644
index 0000000..606bdd0
--- /dev/null
+++ b/drivers/net/wireless/libertas/decl.h
@@ -0,0 +1,83 @@
+/**
+  *  This file contains declaration referring to
+  *  functions defined in other source files
+  */
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+#include "defs.h"
+
+/** Function Prototype Declaration */
+struct wlan_private;
+struct sk_buff;
+struct net_device;
+
+extern char *libertas_fw_name;
+
+void libertas_free_adapter(wlan_private * priv);
+int libertas_set_mac_packet_filter(wlan_private * priv);
+
+int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
+void libertas_send_tx_feedback(wlan_private * priv);
+u8 libertas_check_last_packet_indication(wlan_private * priv);
+
+int libertas_free_cmd_buffer(wlan_private * priv);
+struct cmd_ctrl_node;
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+		    struct cmd_ctrl_node *ptempnode,
+		    u32 cmd_oid, u16 wait_option, void *pdata_buf);
+
+int libertas_prepare_and_send_command(wlan_private * priv,
+			  u16 cmd_no,
+			  u16 cmd_action,
+			  u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+
+int libertas_allocate_cmd_buffer(wlan_private * priv);
+int libertas_execute_next_command(wlan_private * priv);
+int libertas_process_event(wlan_private * priv);
+void libertas_interrupt(struct net_device *);
+int libertas_set_radio_control(wlan_private * priv);
+u32 libertas_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_index(u32 rate);
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+
+/** The proc fs interface */
+int libertas_process_rx_command(wlan_private * priv);
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
+void libertas_cleanup_and_insert_cmd(wlan_private * priv,
+					struct cmd_ctrl_node *ptempcmd);
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+					struct cmd_ctrl_node *ptempcmd);
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option);
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
+void libertas_ps_wakeup(wlan_private * priv, int wait_option);
+
+void libertas_tx_runqueue(wlan_private *priv);
+
+extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
+				wlan_adapter * adapter, u8 band, u16 channel);
+
+extern void libertas_mac_event_disconnected(wlan_private * priv);
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+
+int reset_device(wlan_private *priv);
+/* main.c */
+extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
+						             int *cfp_no);
+wlan_private *wlan_add_card(void *card);
+int wlan_remove_card(void *card);
+
+#endif				/* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644
index 0000000..fb1478c
--- /dev/null
+++ b/drivers/net/wireless/libertas/defs.h
@@ -0,0 +1,369 @@
+/**
+  * This header file contains global constant/enum definitions,
+  * global variable declaration.
+  */
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include <linux/spinlock.h>
+
+extern unsigned int libertas_debug;
+
+#define DRV_NAME		"usb8xxx"
+
+#define lbs_pr_info(format, args...) \
+	printk(KERN_INFO DRV_NAME": " format, ## args)
+#define lbs_pr_err(format, args...) \
+	printk(KERN_ERR DRV_NAME": " format, ## args)
+#define lbs_pr_alert(format, args...) \
+	printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+#ifdef DEBUG
+#define lbs_pr_debug(level, format, args...) \
+	do { if (libertas_debug >= level) \
+	printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
+#define lbs_dev_dbg(level, device, format, args...) \
+        lbs_pr_debug(level, "%s: " format, \
+        (device)->bus_id , ## args)
+
+static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+{
+	int i = 0;
+
+	if (!libertas_debug)
+		return;
+
+	printk(KERN_DEBUG "%s: ", prompt);
+	for (i = 1; i <= len; i++) {
+		printk(KERN_DEBUG "%02x ", (u8) * buf);
+		buf++;
+	}
+	printk("\n");
+}
+#else
+#define lbs_pr_debug(level, format, args...)		do {} while (0)
+#define lbs_dev_dbg(level, device, format, args...)	do {} while (0)
+#define lbs_dbg_hex(x,y,z)				do {} while (0)
+#endif
+
+#define	ENTER()			lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
+					__FUNCTION__, __FILE__, __LINE__)
+#define	LEAVE()			lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
+					__FUNCTION__, __FILE__, __LINE__)
+
+/** Buffer Constants */
+
+/*	The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+*	addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+*	driver has more local TxPDs. Each TxPD on the host memory is associated
+*	with a Tx control node. The driver maintains 8 RxPD descriptors for
+*	station firmware to store Rx packet information.
+*
+*	Current version of MAC has a 32x6 multicast address buffer.
+*
+*	802.11b can have up to  14 channels, the driver keeps the
+*	BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
+#define MRVDRV_NUM_OF_CMD_BUFFER        10
+#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE		14
+#define MRVDRV_MAX_BSSID_LIST		64
+#define MRVDRV_ASSOCIATION_TIME_OUT	255
+#define MRVDRV_SNAP_HEADER_LEN          8
+
+#define	WLAN_UPLD_SIZE			2312
+#define DEV_NAME_LEN			32
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_BSS_DESCRIPTS		16
+#define MRVDRV_MAX_REGION_CODE			6
+
+#define MRVDRV_IGNORE_MULTIPLE_DTIM		0xfffe
+#define MRVDRV_MIN_MULTIPLE_DTIM		1
+#define MRVDRV_MAX_MULTIPLE_DTIM		5
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM		1
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL		10
+
+#define	MRVDRV_CHANNELS_PER_SCAN		4
+#define	MRVDRV_MAX_CHANNELS_PER_SCAN		14
+
+#define MRVDRV_DEBUG_RX_PATH		0x00000001
+#define MRVDRV_DEBUG_TX_PATH		0x00000002
+
+#define MRVDRV_MIN_BEACON_INTERVAL		20
+#define MRVDRV_MAX_BEACON_INTERVAL		1000
+#define MRVDRV_BEACON_INTERVAL			100
+
+/** TxPD status */
+
+/*	Station firmware use TxPD status field to report final Tx transmit
+*	result, Bit masks are used to present combined situations.
+*/
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK                0x0001
+
+/** RxPD status - Received packet types */
+/** Rx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/** RSSI-related defines */
+/*	RSSI constants are used to implement 802.11 RSSI threshold
+*	indication. if the Rx packet signal got too weak for 5 consecutive
+*	times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE		(-96)
+
+/** RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE		0
+#define MRVDRV_RTS_MAX_VALUE		2347
+#define MRVDRV_FRAG_MIN_VALUE		256
+#define MRVDRV_FRAG_MAX_VALUE		2346
+
+/* This is for firmware specific length */
+#define EXTRA_LEN	36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+	(ETH_FRAME_LEN + sizeof(struct rxpd) \
+	 + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define	CMD_F_HOSTCMD		(1 << 0)
+#define FW_CAPINFO_WPA  	(1 << 0)
+
+/** WPA key LENGTH*/
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
+
+#define KEY_LEN_WPA_AES			16
+#define KEY_LEN_WPA_TKIP		32
+#define KEY_LEN_WEP_104			13
+#define KEY_LEN_WEP_40			5
+
+#define RF_ANTENNA_1		0x1
+#define RF_ANTENNA_2		0x2
+#define RF_ANTENNA_AUTO		0xFFFF
+
+#define	BAND_B			(0x01)
+#define	BAND_G			(0x02)
+#define ALL_802_11_BANDS	(BAND_B | BAND_G)
+
+/** MACRO DEFINITIONS */
+#define CAL_NF(NF)			((s32)(-(s32)(NF)))
+#define CAL_RSSI(SNR, NF) 		((s32)((s32)(SNR) + CAL_NF(NF)))
+#define SCAN_RSSI(RSSI)			(0x100 - ((u8)(RSSI)))
+
+#define DEFAULT_BCN_AVG_FACTOR		8
+#define DEFAULT_DATA_AVG_FACTOR		8
+#define AVG_SCALE			100
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N)         \
+                        (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+                        ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+                        AVG_SCALE))  / N))
+
+#define B_SUPPORTED_RATES		8
+#define G_SUPPORTED_RATES		14
+
+#define	WLAN_SUPPORTED_RATES		14
+
+#define	MAX_LEDS			8
+
+#define IS_MESH_FRAME(x) (x->cb[6])
+#define SET_MESH_FRAME(x) (x->cb[6]=1)
+#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+
+/** Global Variable Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+extern const char libertas_driver_version[];
+extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES];
+
+extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_b[4];
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+enum SNRNF_TYPE {
+	TYPE_BEACON = 0,
+	TYPE_RXPD,
+	MAX_TYPE_B
+};
+
+/** SNRNF_DATA*/
+enum SNRNF_DATA {
+	TYPE_NOAVG = 0,
+	TYPE_AVG,
+	MAX_TYPE_AVG
+};
+
+/** WLAN_802_11_AUTH_ALG*/
+enum WLAN_802_11_AUTH_ALG {
+	AUTH_ALG_OPEN_SYSTEM = 1,
+	AUTH_ALG_SHARED_KEY = 2,
+	AUTH_ALG_NETWORK_EAP = 8,
+};
+
+/** WLAN_802_1X_AUTH_ALG */
+enum WLAN_802_1X_AUTH_ALG {
+	WLAN_1X_AUTH_ALG_NONE = 1,
+	WLAN_1X_AUTH_ALG_LEAP = 2,
+	WLAN_1X_AUTH_ALG_TLS = 4,
+	WLAN_1X_AUTH_ALG_TTLS = 8,
+	WLAN_1X_AUTH_ALG_MD5 = 16,
+};
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+enum WLAN_802_11_ENCRYPTION_MODE {
+	CIPHER_NONE,
+	CIPHER_WEP40,
+	CIPHER_TKIP,
+	CIPHER_CCMP,
+	CIPHER_WEP104,
+};
+
+/** WLAN_802_11_POWER_MODE */
+enum WLAN_802_11_POWER_MODE {
+	wlan802_11powermodecam,
+	wlan802_11powermodemax_psp,
+	wlan802_11Powermodefast_psp,
+	/*not a real mode, defined as an upper bound */
+	wlan802_11powemodemax
+};
+
+/** PS_STATE */
+enum PS_STATE {
+	PS_STATE_FULL_POWER,
+	PS_STATE_AWAKE,
+	PS_STATE_PRE_SLEEP,
+	PS_STATE_SLEEP
+};
+
+/** DNLD_STATE */
+enum DNLD_STATE {
+	DNLD_RES_RECEIVED,
+	DNLD_DATA_SENT,
+	DNLD_CMD_SENT
+};
+
+/** WLAN_MEDIA_STATE */
+enum WLAN_MEDIA_STATE {
+	libertas_connected,
+	libertas_disconnected
+};
+
+/** WLAN_802_11_PRIVACY_FILTER */
+enum WLAN_802_11_PRIVACY_FILTER {
+	wlan802_11privfilteracceptall,
+	wlan802_11privfilter8021xWEP
+};
+
+/** mv_ms_type */
+enum mv_ms_type {
+	MVMS_DAT = 0,
+	MVMS_CMD = 1,
+	MVMS_TXDONE = 2,
+	MVMS_EVENT
+};
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+enum WLAN_802_11_NETWORK_INFRASTRUCTURE {
+	wlan802_11ibss,
+	wlan802_11infrastructure,
+	wlan802_11autounknown,
+	/*defined as upper bound */
+	wlan802_11infrastructuremax
+};
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+enum WLAN_802_11_AUTHENTICATION_MODE {
+	wlan802_11authmodeopen = 0x00,
+	wlan802_11authmodeshared = 0x01,
+	wlan802_11authmodenetworkEAP = 0x80,
+};
+
+/** WLAN_802_11_WEP_STATUS */
+enum WLAN_802_11_WEP_STATUS {
+	wlan802_11WEPenabled,
+	wlan802_11WEPdisabled,
+};
+
+/** SNMP_MIB_INDEX_e */
+enum SNMP_MIB_INDEX_e {
+	desired_bsstype_i = 0,
+	op_rateset_i,
+	bcnperiod_i,
+	dtimperiod_i,
+	assocrsp_timeout_i,
+	rtsthresh_i,
+	short_retrylim_i,
+	long_retrylim_i,
+	fragthresh_i,
+	dot11d_i,
+	dot11h_i,
+	manufid_i,
+	prodID_i,
+	manuf_oui_i,
+	manuf_name_i,
+	manuf_prodname_i,
+	manuf_prodver_i,
+};
+
+/** KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+	KEY_TYPE_ID_WEP = 0,
+	KEY_TYPE_ID_TKIP,
+	KEY_TYPE_ID_AES
+};
+
+/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+	KEY_INFO_WPA_MCAST = 0x01,
+	KEY_INFO_WPA_UNICAST = 0x02,
+	KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/** SNMP_MIB_VALUE_e */
+enum SNMP_MIB_VALUE_e {
+	SNMP_MIB_VALUE_INFRA = 1,
+	SNMP_MIB_VALUE_ADHOC
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif				/* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644
index 0000000..b1f876f
--- /dev/null
+++ b/drivers/net/wireless/libertas/dev.h
@@ -0,0 +1,403 @@
+/**
+  * This file contains definitions and data structures specific
+  * to Marvell 802.11 NIC. It contains the Device Information
+  * structure wlan_adapter.
+  */
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/debugfs.h>
+
+#include "defs.h"
+#include "scan.h"
+#include "thread.h"
+
+extern struct ethtool_ops libertas_ethtool_ops;
+
+#define	MAX_BSSID_PER_CHANNEL		16
+
+#define NR_TX_QUEUE			3
+
+/* For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST    MAX_BSSID_PER_CHANNEL * \
+						MRVDRV_MAX_CHANNEL_SIZE + 1
+
+#define	MAX_REGION_CHANNEL_NUM	2
+
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+	/** channel Number		*/
+	u16 channel;
+	/** frequency of this channel	*/
+	u32 freq;
+	/** Max allowed Tx power level	*/
+	u16 maxtxpower;
+	/** TRUE:channel unsupported;  FLASE:supported*/
+	u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+	/** TRUE if this entry is valid		     */
+	u8 valid;
+	/** region code for US, Japan ...	     */
+	u8 region;
+	/** band B/G/A, used for BAND_CONFIG cmd	     */
+	u8 band;
+	/** Actual No. of elements in the array below */
+	u8 nrcfp;
+	/** chan-freq-txpower mapping table*/
+	struct chan_freq_power *CFP;
+};
+
+struct wlan_802_11_security {
+	u8 WPAenabled;
+	u8 WPA2enabled;
+	enum WLAN_802_11_WEP_STATUS WEPstatus;
+	enum WLAN_802_11_AUTHENTICATION_MODE authmode;
+	enum WLAN_802_1X_AUTH_ALG auth1xalg;
+	enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+	struct bss_descriptor bssdescriptor;
+	/** bssid */
+	u8 bssid[ETH_ALEN];
+	/** ssid */
+	struct WLAN_802_11_SSID ssid;
+
+	/** band */
+	u8 band;
+	/** channel */
+	u8 channel;
+	/** number of rates supported */
+	int numofrates;
+	/** supported rates*/
+	u8 datarates[WLAN_SUPPORTED_RATES];
+};
+
+/** sleep_params */
+struct sleep_params {
+	u16 sp_error;
+	u16 sp_offset;
+	u16 sp_stabletime;
+	u8 sp_calcontrol;
+	u8 sp_extsleepclk;
+	u16 sp_reserved;
+};
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev {
+	/** device name */
+	char name[DEV_NAME_LEN];
+	/** card pointer */
+	void *card;
+	/** IO port */
+	u32 ioport;
+	/** Upload received */
+	u32 upld_rcv;
+	/** Upload type */
+	u32 upld_typ;
+	/** Upload length */
+	u32 upld_len;
+	/** netdev pointer */
+	struct net_device *netdev;
+	/* Upload buffer */
+	u8 upld_buf[WLAN_UPLD_SIZE];
+	/* Download sent:
+	   bit0 1/0=data_sent/data_tx_done,
+	   bit1 1/0=cmd_sent/cmd_tx_done,
+	   all other bits reserved 0 */
+	u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/* Mesh statistics */
+struct wlan_mesh_stats {
+	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */
+	u32	fwd_unicast_cnt;	/* Fwd: Unicast counter */
+	u32	fwd_drop_ttl;		/* Fwd: TTL zero */
+	u32	fwd_drop_rbt;		/* Fwd: Recently Broadcasted */
+	u32	fwd_drop_noroute; 	/* Fwd: No route to Destination */
+	u32	fwd_drop_nobuf;		/* Fwd: Run out of internal buffers */
+	u32	drop_blind;		/* Rx:  Dropped by blinding table */
+};
+
+/** Private structure for the MV device */
+struct _wlan_private {
+	int open;
+	int mesh_open;
+	int infra_open;
+
+	wlan_adapter *adapter;
+	wlan_dev_t wlan_dev;
+
+	struct net_device_stats stats;
+	struct net_device *mesh_dev ; /* Virtual device */
+
+	struct iw_statistics wstats;
+	struct wlan_mesh_stats mstats;
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_debug;
+	struct dentry *debugfs_files[6];
+
+	struct dentry *events_dir;
+	struct dentry *debugfs_events_files[6];
+
+	struct dentry *regs_dir;
+	struct dentry *debugfs_regs_files[6];
+
+	u32 mac_offset;
+	u32 bbp_offset;
+	u32 rf_offset;
+
+	const struct firmware *firmware;
+	struct device *hotplug_device;
+
+	/** thread to service interrupts */
+	struct wlan_thread mainthread;
+
+	struct delayed_work assoc_work;
+	struct workqueue_struct *assoc_thread;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID			1
+#define ASSOC_FLAG_CHANNEL		2
+#define ASSOC_FLAG_MODE			3
+#define ASSOC_FLAG_BSSID		4
+#define ASSOC_FLAG_WEP_KEYS		5
+#define ASSOC_FLAG_WEP_TX_KEYIDX	6
+#define ASSOC_FLAG_WPA_MCAST_KEY	7
+#define ASSOC_FLAG_WPA_UCAST_KEY	8
+#define ASSOC_FLAG_SECINFO		9
+#define ASSOC_FLAG_WPA_IE		10
+	unsigned long flags;
+
+	struct WLAN_802_11_SSID ssid;
+	u8 channel;
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
+	u8 bssid[ETH_ALEN];
+
+	/** WEP keys */
+	struct WLAN_802_11_KEY wep_keys[4];
+	u16 wep_tx_keyidx;
+
+	/** WPA keys */
+	struct WLAN_802_11_KEY wpa_mcast_key;
+	struct WLAN_802_11_KEY wpa_unicast_key;
+
+	struct wlan_802_11_security secinfo;
+
+	/** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	u8 wpa_ie_len;
+};
+
+/** Wlan adapter data structure*/
+struct _wlan_adapter {
+	/** STATUS variables */
+	u32 fwreleasenumber;
+	u32 fwcapinfo;
+	/* protected with big lock */
+
+	struct mutex lock;
+
+	u8 tmptxbuf[WLAN_UPLD_SIZE];
+	/* protected by hard_start_xmit serialization */
+
+	/** command-related variables */
+	u16 seqnum;
+	/* protected by big lock */
+
+	struct cmd_ctrl_node *cmd_array;
+	/** Current command */
+	struct cmd_ctrl_node *cur_cmd;
+	int cur_cmd_retcode;
+	/** command Queues */
+	/** Free command buffers */
+	struct list_head cmdfreeq;
+	/** Pending command buffers */
+	struct list_head cmdpendingq;
+
+	wait_queue_head_t cmd_pending;
+	u8 nr_cmd_pending;
+	/* command related variables protected by adapter->driver_lock */
+
+	/** Async and Sync Event variables */
+	u32 intcounter;
+	u32 eventcause;
+	u8 nodename[16];	/* nickname */
+
+	/** spin locks */
+	spinlock_t driver_lock;
+
+	/** Timers */
+	struct timer_list command_timer;
+
+	/* TX queue used in PS mode */
+	spinlock_t txqueue_lock;
+	struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+	unsigned int tx_queue_idx;
+
+	u8 hisregcpy;
+
+	/** current ssid/bssid related parameters*/
+	struct current_bss_params curbssparams;
+
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+
+	struct bss_descriptor *pattemptedbssdesc;
+
+	struct WLAN_802_11_SSID previousssid;
+	u8 previousbssid[ETH_ALEN];
+
+	struct bss_descriptor *scantable;
+	u32 numinscantable;
+
+	u8 scantype;
+	u32 scanmode;
+
+	u16 beaconperiod;
+	u8 adhoccreate;
+
+	/** capability Info used in Association, start, join */
+	struct ieeetypes_capinfo capinfo;
+
+	/** MAC address information */
+	u8 current_addr[ETH_ALEN];
+	u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+	u32 nr_of_multicastmacaddr;
+
+	/** 802.11 statistics */
+//	struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+
+	u16 enablehwauto;
+	u16 ratebitmap;
+	/** control G rates */
+	u8 adhoc_grate_enabled;
+
+	u32 txantenna;
+	u32 rxantenna;
+
+	u8 adhocchannel;
+	u32 fragthsd;
+	u32 rtsthsd;
+
+	u32 datarate;
+	u8 is_datarate_auto;
+
+	u16 listeninterval;
+	u16 prescan;
+	u8 txretrycount;
+
+	/** Tx-related variables (for single packet tx) */
+	struct sk_buff *currenttxskb;
+	u16 TxLockFlag;
+
+	/** NIC Operation characteristics */
+	u16 currentpacketfilter;
+	u32 connect_status;
+	u16 regioncode;
+	u16 regiontableindex;
+	u16 txpowerlevel;
+
+	/** POWER MANAGEMENT AND PnP SUPPORT */
+	u8 surpriseremoved;
+	u16 atimwindow;
+
+	u16 psmode;		/* Wlan802_11PowermodeCAM=disable
+				   Wlan802_11PowermodeMAX_PSP=enable */
+	u16 multipledtim;
+	u32 psstate;
+	u8 needtowakeup;
+
+	struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+	u16 locallisteninterval;
+	u16 nullpktinterval;
+
+	struct assoc_request * assoc_req;
+
+	/** Encryption parameter */
+	struct wlan_802_11_security secinfo;
+
+	/** WEP keys */
+	struct WLAN_802_11_KEY wep_keys[4];
+	u16 wep_tx_keyidx;
+
+	/** WPA keys */
+	struct WLAN_802_11_KEY wpa_mcast_key;
+	struct WLAN_802_11_KEY wpa_unicast_key;
+
+	/** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	u8 wpa_ie_len;
+
+	u16 rxantennamode;
+	u16 txantennamode;
+
+	/** Requested Signal Strength*/
+	u16 bcn_avg_factor;
+	u16 data_avg_factor;
+	u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+	u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+	u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+	u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+	u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+	u16 nextSNRNF;
+	u16 numSNRNF;
+	u16 rxpd_rate;
+
+	u8 radioon;
+	u32 preamble;
+
+	/** Multi bands Parameter*/
+	u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+	/** Blue Tooth Co-existence Arbitration */
+
+	/** sleep_params */
+	struct sleep_params sp;
+
+	/** RF calibration data */
+
+#define	MAX_REGION_CHANNEL_NUM	2
+	/** region channel data */
+	struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
+
+	struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
+
+	/** 11D and Domain Regulatory Data */
+	struct wlan_802_11d_domain_reg domainreg;
+	struct parsed_region_chan_11d parsed_region_chan;
+
+	/** FSM variable for 11d support */
+	u32 enable11d;
+
+	/**	MISCELLANEOUS */
+	u8 *prdeeprom;
+	struct wlan_offset_value offsetvalue;
+
+	struct cmd_ds_802_11_get_log logmsg;
+	u16 scanprobes;
+
+	u32 pkttxctrl;
+
+	u16 txrate;
+	u32 linkmode;
+	u32 radiomode;
+	u32 debugmode;
+	u8 fw_ready;
+};
+
+#endif				/* _WLAN_DEV_H_ */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644
index 0000000..0064de5
--- /dev/null
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -0,0 +1,184 @@
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+static const char * mesh_stat_strings[]= {
+			"drop_duplicate_bcast",
+			"drop_ttl_zero",
+			"drop_no_fwd_route",
+			"drop_no_buffers",
+			"fwded_unicast_cnt",
+			"fwded_bcast_cnt",
+			"drop_blind_table"
+};
+
+static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+					 struct ethtool_drvinfo *info)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	char fwver[32];
+
+	libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+
+	strcpy(info->driver, "libertas");
+	strcpy(info->version, libertas_driver_version);
+	strcpy(info->fw_version, fwver);
+}
+
+/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LIBERTAS_EEPROM_LEN 16384
+
+static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+{
+	return LIBERTAS_EEPROM_LEN;
+}
+
+static int libertas_ethtool_get_eeprom(struct net_device *dev,
+                                  struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_ioctl_regrdwr regctrl;
+	char *ptr;
+	int ret;
+
+	regctrl.action = 0;
+	regctrl.offset = eeprom->offset;
+	regctrl.NOB = eeprom->len;
+
+	if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+		return -EINVAL;
+
+//      mutex_lock(&priv->mutex);
+
+	adapter->prdeeprom =
+		    (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+	if (!adapter->prdeeprom)
+		return -ENOMEM;
+	memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+
+	/* +14 is for action, offset, and NOB in
+	 * response */
+	lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
+	       regctrl.action, regctrl.offset, regctrl.NOB);
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_eeprom_access,
+				    regctrl.action,
+				    cmd_option_waitforrsp, 0,
+				    &regctrl);
+
+	if (ret) {
+		if (adapter->prdeeprom)
+			kfree(adapter->prdeeprom);
+		LEAVE();
+			return ret;
+	}
+
+	mdelay(10);
+
+	ptr = (char *)adapter->prdeeprom;
+
+	/* skip the command header, but include the "value" u32 variable */
+	ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+
+	/*
+	 * Return the result back to the user
+	 */
+	memcpy(bytes, ptr, eeprom->len);
+
+	if (adapter->prdeeprom)
+		kfree(adapter->prdeeprom);
+//	mutex_unlock(&priv->mutex);
+
+        return 0;
+}
+
+static void libertas_ethtool_get_stats(struct net_device * dev,
+				struct ethtool_stats * stats, u64 * data)
+{
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	stats->cmd = ETHTOOL_GSTATS;
+	BUG_ON(stats->n_stats != MESH_STATS_NUM);
+
+        data[0] = priv->mstats.fwd_drop_rbt;
+        data[1] = priv->mstats.fwd_drop_ttl;
+        data[2] = priv->mstats.fwd_drop_noroute;
+        data[3] = priv->mstats.fwd_drop_nobuf;
+        data[4] = priv->mstats.fwd_unicast_cnt;
+        data[5] = priv->mstats.fwd_bcast_cnt;
+        data[6] = priv->mstats.drop_blind;
+
+	LEAVE();
+}
+
+static int libertas_ethtool_get_stats_count(struct net_device * dev)
+{
+	int ret;
+	wlan_private *priv = dev->priv;
+	struct cmd_ds_mesh_access mesh_access;
+
+	ENTER();
+	/* Get Mesh Statistics */
+	ret = libertas_prepare_and_send_command(priv,
+			cmd_mesh_access, cmd_act_mesh_get_stats,
+			cmd_option_waitforrsp, 0, &mesh_access);
+
+	if (ret) {
+		LEAVE();
+		return 0;
+	}
+
+        priv->mstats.fwd_drop_rbt = mesh_access.data[0];
+        priv->mstats.fwd_drop_ttl = mesh_access.data[1];
+        priv->mstats.fwd_drop_noroute = mesh_access.data[2];
+        priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
+        priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
+        priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
+        priv->mstats.drop_blind = mesh_access.data[6];
+
+	LEAVE();
+	return MESH_STATS_NUM;
+}
+
+static void libertas_ethtool_get_strings (struct net_device * dev,
+					  u32 stringset,
+					  u8 * s)
+{
+	int i;
+
+	ENTER();
+	switch (stringset) {
+        case ETH_SS_STATS:
+		for (i=0; i < MESH_STATS_NUM; i++) {
+			memcpy(s + i * ETH_GSTRING_LEN,
+					mesh_stat_strings[i],
+					ETH_GSTRING_LEN);
+		}
+		break;
+        }
+	LEAVE();
+}
+
+struct ethtool_ops libertas_ethtool_ops = {
+	.get_drvinfo = libertas_ethtool_get_drvinfo,
+	.get_eeprom =  libertas_ethtool_get_eeprom,
+	.get_eeprom_len = libertas_ethtool_get_eeprom_len,
+	.get_stats_count = libertas_ethtool_get_stats_count,
+	.get_ethtool_stats = libertas_ethtool_get_stats,
+	.get_strings = libertas_ethtool_get_strings,
+};
+
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644
index 0000000..b194a45
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.c
@@ -0,0 +1,361 @@
+/**
+  * This file contains the initialization for FW and HW
+  */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "defs.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "if_usb.h"
+
+char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+unsigned int libertas_debug = 0;
+module_param(libertas_debug, int, 0);
+
+/**
+ *  @brief This function checks the validity of Boot2/FW image.
+ *
+ *  @param data              pointer to image
+ *         len               image length
+ *  @return     0 or -1
+ */
+static int check_fwfile_format(u8 *data, u32 totlen)
+{
+	u8  bincmd, exit;
+	u32 blksize, offset, len;
+	int ret;
+
+	ret = 1;
+	exit = len = 0;
+
+	do {
+		bincmd = *data;
+		blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
+		switch (bincmd) {
+		case FW_HAS_DATA_TO_RECV:
+			offset = sizeof(struct fwheader) + blksize;
+			data += offset;
+			len += offset;
+			if (len >= totlen)
+				exit = 1;
+			break;
+		case FW_HAS_LAST_BLOCK:
+			exit = 1;
+			ret = 0;
+			break;
+		default:
+			exit = 1;
+			break;
+		}
+	} while (!exit);
+
+	if (ret)
+		lbs_pr_err("bin file format check FAIL...\n");
+	else
+		lbs_pr_debug(1, "bin file format check PASS...\n");
+
+	return ret;
+}
+
+/**
+ *  @brief This function downloads firmware image, gets
+ *  HW spec from firmware and set basic parameters to
+ *  firmware.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+	int ret = -1;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
+				    priv->hotplug_device)) < 0) {
+		lbs_pr_err("request_firmware() failed, error code = %#x\n",
+		       ret);
+		lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
+		goto done;
+	}
+
+	if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+		release_firmware(priv->firmware);
+		goto done;
+	}
+
+	ret = libertas_sbi_prog_firmware(priv);
+
+	release_firmware(priv->firmware);
+
+	if (ret) {
+		lbs_pr_debug(1, "Bootloader in invalid state!\n");
+		ret = -1;
+		goto done;
+	}
+
+	/*
+	 * Read MAC address from HW
+	 */
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+				    0, cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	libertas_set_mac_packet_filter(priv);
+
+	/* Get the supported Data rates */
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+				    cmd_act_get_tx_rate,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	LEAVE();
+
+	return (ret);
+}
+
+static int wlan_allocate_adapter(wlan_private * priv)
+{
+	u32 ulbufsize;
+	wlan_adapter *adapter = priv->adapter;
+
+	struct bss_descriptor *ptempscantable;
+
+	/* Allocate buffer to store the BSSID list */
+	ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST;
+	if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) {
+		libertas_free_adapter(priv);
+		return -1;
+	}
+
+	adapter->scantable = ptempscantable;
+	memset(adapter->scantable, 0, ulbufsize);
+
+	/* Allocate the command buffers */
+	libertas_allocate_cmd_buffer(priv);
+
+	memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+	adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+	adapter->libertas_ps_confirm_sleep.command =
+	    cpu_to_le16(cmd_802_11_ps_mode);
+	adapter->libertas_ps_confirm_sleep.size =
+	    cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+	adapter->libertas_ps_confirm_sleep.result = 0;
+	adapter->libertas_ps_confirm_sleep.action =
+	    cpu_to_le16(cmd_subcmd_sleep_confirmed);
+
+	return 0;
+}
+
+static void wlan_init_adapter(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i;
+
+	adapter->scanprobes = 0;
+
+	adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+	adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+	/* ATIM params */
+	adapter->atimwindow = 0;
+
+	adapter->connect_status = libertas_disconnected;
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	/* scan type */
+	adapter->scantype = cmd_scan_type_active;
+
+	/* scan mode */
+	adapter->scanmode = cmd_bss_type_any;
+
+	/* 802.11 specific */
+	adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+	     i++)
+		memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+	adapter->wep_tx_keyidx = 0;
+	adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	adapter->secinfo.authmode = wlan802_11authmodeopen;
+	adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+	adapter->secinfo.Encryptionmode = CIPHER_NONE;
+	adapter->inframode = wlan802_11infrastructure;
+
+	adapter->assoc_req = NULL;
+
+	adapter->numinscantable = 0;
+	adapter->pattemptedbssdesc = NULL;
+	mutex_init(&adapter->lock);
+
+	adapter->prescan = 1;
+
+	memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+	/* PnP and power profile */
+	adapter->surpriseremoved = 0;
+
+	adapter->currentpacketfilter =
+	    cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+
+	adapter->radioon = RADIO_ON;
+	adapter->txantenna = RF_ANTENNA_2;
+	adapter->rxantenna = RF_ANTENNA_AUTO;
+
+	adapter->is_datarate_auto = 1;
+	adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+
+	// set default value of capinfo.
+#define SHORT_PREAMBLE_ALLOWED		1
+	memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
+	adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
+
+	adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+
+	adapter->psmode = wlan802_11powermodecam;
+	adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+	adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+	adapter->psstate = PS_STATE_FULL_POWER;
+	adapter->needtowakeup = 0;
+	adapter->locallisteninterval = 0;	/* default value in firmware will be used */
+
+	adapter->datarate = 0;	// Initially indicate the rate as auto
+
+	adapter->adhoc_grate_enabled = 0;
+
+	adapter->intcounter = 0;
+
+	adapter->currenttxskb = NULL;
+	adapter->pkttxctrl = 0;
+
+	memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+	adapter->tx_queue_idx = 0;
+	spin_lock_init(&adapter->txqueue_lock);
+
+	return;
+}
+
+static void command_timer_fn(unsigned long data);
+
+int libertas_init_fw(wlan_private * priv)
+{
+	int ret = -1;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* Allocate adapter structure */
+	if ((ret = wlan_allocate_adapter(priv)) != 0)
+		goto done;
+
+	/* init adapter structure */
+	wlan_init_adapter(priv);
+
+	/* init timer etc. */
+	setup_timer(&adapter->command_timer, command_timer_fn,
+			(unsigned long)priv);
+
+	/* download fimrware etc. */
+	if ((ret = wlan_setup_station_hw(priv)) != 0) {
+		del_timer_sync(&adapter->command_timer);
+		goto done;
+	}
+
+	/* init 802.11d */
+	libertas_init_11d(priv);
+
+	ret = 0;
+done:
+	LEAVE();
+	return ret;
+}
+
+void libertas_free_adapter(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	if (!adapter) {
+		lbs_pr_debug(1, "Why double free adapter?:)\n");
+		return;
+	}
+
+	lbs_pr_debug(1, "Free command buffer\n");
+	libertas_free_cmd_buffer(priv);
+
+	lbs_pr_debug(1, "Free commandTimer\n");
+	del_timer(&adapter->command_timer);
+
+	lbs_pr_debug(1, "Free scantable\n");
+	if (adapter->scantable) {
+		kfree(adapter->scantable);
+		adapter->scantable = NULL;
+	}
+
+	lbs_pr_debug(1, "Free adapter\n");
+
+	/* Free the adapter object itself */
+	kfree(adapter);
+	priv->adapter = NULL;
+}
+
+/**
+ *  This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+	wlan_private *priv = (wlan_private *)data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *ptempnode;
+	struct cmd_ds_command *cmd;
+	unsigned long flags;
+
+	ptempnode = adapter->cur_cmd;
+	cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+
+	lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
+
+	if (!adapter->fw_ready)
+		return;
+
+	if (ptempnode == NULL) {
+		lbs_pr_debug(1, "PTempnode Empty\n");
+		return;
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	adapter->cur_cmd = NULL;
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
+	libertas_queue_cmd(adapter, ptempnode, 0);
+
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	return;
+}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644
index 0000000..1f9ae26
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.h
@@ -0,0 +1,13 @@
+/**
+  * This header file contains FW interface related definitions.
+  */
+#ifndef _WLAN_FW_H_
+#define _WLAN_FW_H_
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN            32
+#endif
+
+int libertas_init_fw(wlan_private * priv);
+
+#endif				/* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644
index 0000000..c0faaec
--- /dev/null
+++ b/drivers/net/wireless/libertas/host.h
@@ -0,0 +1,338 @@
+/**
+  * This file contains definitions of WLAN commands.
+  */
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL       6
+#define DEFAULT_AD_HOC_CHANNEL_A    36
+
+/** IEEE 802.11 oids */
+#define OID_802_11_SSID                       0x00008002
+#define OID_802_11_INFRASTRUCTURE_MODE        0x00008008
+#define OID_802_11_FRAGMENTATION_THRESHOLD    0x00008009
+#define OID_802_11_RTS_THRESHOLD              0x0000800A
+#define OID_802_11_TX_ANTENNA_SELECTED        0x0000800D
+#define OID_802_11_SUPPORTED_RATES            0x0000800E
+#define OID_802_11_STATISTICS                 0x00008012
+#define OID_802_11_TX_RETRYCOUNT              0x0000801D
+#define OID_802_11D_ENABLE                    0x00008020
+
+#define cmd_option_waitforrsp             0x0002
+
+/** Host command ID */
+#define cmd_code_dnld                 0x0002
+#define cmd_get_hw_spec               0x0003
+#define cmd_eeprom_update             0x0004
+#define cmd_802_11_reset              0x0005
+#define cmd_802_11_scan               0x0006
+#define cmd_802_11_get_log            0x000b
+#define cmd_mac_multicast_adr         0x0010
+#define cmd_802_11_authenticate       0x0011
+#define cmd_802_11_eeprom_access      0x0059
+#define cmd_802_11_associate          0x0050
+#define cmd_802_11_set_wep            0x0013
+#define cmd_802_11_get_stat           0x0014
+#define cmd_802_3_get_stat            0x0015
+#define cmd_802_11_snmp_mib           0x0016
+#define cmd_mac_reg_map               0x0017
+#define cmd_bbp_reg_map               0x0018
+#define cmd_mac_reg_access            0x0019
+#define cmd_bbp_reg_access            0x001a
+#define cmd_rf_reg_access             0x001b
+#define cmd_802_11_radio_control      0x001c
+#define cmd_802_11_rf_channel         0x001d
+#define cmd_802_11_rf_tx_power        0x001e
+#define cmd_802_11_rssi               0x001f
+#define cmd_802_11_rf_antenna         0x0020
+
+#define cmd_802_11_ps_mode	      0x0021
+
+#define cmd_802_11_data_rate          0x0022
+#define cmd_rf_reg_map                0x0023
+#define cmd_802_11_deauthenticate     0x0024
+#define cmd_802_11_reassociate        0x0025
+#define cmd_802_11_disassociate       0x0026
+#define cmd_mac_control               0x0028
+#define cmd_802_11_ad_hoc_start       0x002b
+#define cmd_802_11_ad_hoc_join        0x002c
+
+#define cmd_802_11_query_tkip_reply_cntrs  0x002e
+#define cmd_802_11_enable_rsn              0x002f
+#define cmd_802_11_pairwise_tsc       0x0036
+#define cmd_802_11_group_tsc          0x0037
+#define cmd_802_11_key_material       0x005e
+
+#define cmd_802_11_set_afc            0x003c
+#define cmd_802_11_get_afc            0x003d
+
+#define cmd_802_11_ad_hoc_stop        0x0040
+
+#define cmd_802_11_beacon_stop        0x0049
+
+#define cmd_802_11_mac_address        0x004D
+#define cmd_802_11_eeprom_access      0x0059
+
+#define cmd_802_11_band_config        0x0058
+
+#define cmd_802_11d_domain_info       0x005b
+
+#define cmd_802_11_sleep_params          0x0066
+
+#define cmd_802_11_inactivity_timeout    0x0067
+
+#define cmd_802_11_tpc_cfg               0x0072
+#define cmd_802_11_pwr_cfg               0x0073
+
+#define cmd_802_11_led_gpio_ctrl         0x004e
+
+#define cmd_802_11_subscribe_event       0x0075
+
+#define cmd_802_11_rate_adapt_rateset    0x0076
+
+#define cmd_802_11_tx_rate_query	0x007f
+
+#define cmd_get_tsf                      0x0080
+
+#define cmd_bt_access                 0x0087
+#define cmd_ret_bt_access                 0x8087
+
+#define cmd_fwt_access                0x0088
+#define cmd_ret_fwt_access                0x8088
+
+#define cmd_mesh_access               0x0090
+#define cmd_ret_mesh_access               0x8090
+
+/* For the IEEE Power Save */
+#define cmd_subcmd_enter_ps               0x0030
+#define cmd_subcmd_exit_ps                0x0031
+#define cmd_subcmd_sleep_confirmed        0x0034
+#define cmd_subcmd_full_powerdown         0x0035
+#define cmd_subcmd_full_powerup           0x0036
+
+/* command RET code, MSB is set to 1 */
+#define cmd_ret_hw_spec_info              0x8003
+#define cmd_ret_eeprom_update             0x8004
+#define cmd_ret_802_11_reset              0x8005
+#define cmd_ret_802_11_scan               0x8006
+#define cmd_ret_802_11_get_log            0x800b
+#define cmd_ret_mac_control               0x8028
+#define cmd_ret_mac_multicast_adr         0x8010
+#define cmd_ret_802_11_authenticate       0x8011
+#define cmd_ret_802_11_deauthenticate     0x8024
+#define cmd_ret_802_11_associate          0x8012
+#define cmd_ret_802_11_reassociate        0x8025
+#define cmd_ret_802_11_disassociate       0x8026
+#define cmd_ret_802_11_set_wep            0x8013
+#define cmd_ret_802_11_stat               0x8014
+#define cmd_ret_802_3_stat                0x8015
+#define cmd_ret_802_11_snmp_mib           0x8016
+#define cmd_ret_mac_reg_map               0x8017
+#define cmd_ret_bbp_reg_map               0x8018
+#define cmd_ret_rf_reg_map                0x8023
+#define cmd_ret_mac_reg_access            0x8019
+#define cmd_ret_bbp_reg_access            0x801a
+#define cmd_ret_rf_reg_access             0x801b
+#define cmd_ret_802_11_radio_control      0x801c
+#define cmd_ret_802_11_rf_channel         0x801d
+#define cmd_ret_802_11_rssi               0x801f
+#define cmd_ret_802_11_rf_tx_power        0x801e
+#define cmd_ret_802_11_rf_antenna         0x8020
+#define cmd_ret_802_11_ps_mode            0x8021
+#define cmd_ret_802_11_data_rate          0x8022
+
+#define cmd_ret_802_11_ad_hoc_start       0x802B
+#define cmd_ret_802_11_ad_hoc_join        0x802C
+
+#define cmd_ret_802_11_query_tkip_reply_cntrs  0x802e
+#define cmd_ret_802_11_enable_rsn              0x802f
+#define cmd_ret_802_11_pairwise_tsc       0x8036
+#define cmd_ret_802_11_group_tsc          0x8037
+#define cmd_ret_802_11_key_material       0x805e
+
+#define cmd_enable_rsn                    0x0001
+#define cmd_disable_rsn                   0x0000
+
+#define cmd_act_set                       0x0001
+#define cmd_act_get                       0x0000
+
+#define cmd_act_get_AES                   (cmd_act_get + 2)
+#define cmd_act_set_AES                   (cmd_act_set + 2)
+#define cmd_act_remove_aes                (cmd_act_set + 3)
+
+#define cmd_ret_802_11_set_afc            0x803c
+#define cmd_ret_802_11_get_afc            0x803d
+
+#define cmd_ret_802_11_ad_hoc_stop        0x8040
+
+#define cmd_ret_802_11_beacon_stop        0x8049
+
+#define cmd_ret_802_11_mac_address        0x804D
+#define cmd_ret_802_11_eeprom_access      0x8059
+
+#define cmd_ret_802_11_band_config        0x8058
+
+#define cmd_ret_802_11_sleep_params          0x8066
+
+#define cmd_ret_802_11_inactivity_timeout    0x8067
+
+#define cmd_ret_802_11d_domain_info      (0x8000 |                  \
+                                              cmd_802_11d_domain_info)
+
+#define cmd_ret_802_11_tpc_cfg        (cmd_802_11_tpc_cfg | 0x8000)
+#define cmd_ret_802_11_pwr_cfg        (cmd_802_11_pwr_cfg | 0x8000)
+
+#define cmd_ret_802_11_led_gpio_ctrl     0x804e
+
+#define cmd_ret_802_11_subscribe_event	(cmd_802_11_subscribe_event | 0x8000)
+
+#define cmd_ret_802_11_rate_adapt_rateset	(cmd_802_11_rate_adapt_rateset | 0x8000)
+
+#define cmd_rte_802_11_tx_rate_query 	(cmd_802_11_tx_rate_query | 0x8000)
+
+#define cmd_ret_get_tsf             0x8080
+
+/* Define action or option for cmd_802_11_set_wep */
+#define cmd_act_add                         0x0002
+#define cmd_act_remove                      0x0004
+#define cmd_act_use_default                 0x0008
+
+#define cmd_type_wep_40_bit                 0x0001
+#define cmd_type_wep_104_bit                0x0002
+
+#define cmd_NUM_OF_WEP_KEYS                 4
+
+#define cmd_WEP_KEY_INDEX_MASK              0x3fff
+
+/* Define action or option for cmd_802_11_reset */
+#define cmd_act_halt                        0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_bss_type_bss                    0x0001
+#define cmd_bss_type_ibss                   0x0002
+#define cmd_bss_type_any                    0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_scan_type_active                0x0000
+#define cmd_scan_type_passive               0x0001
+
+#define cmd_scan_radio_type_bg		0
+
+#define cmd_scan_probe_delay_time           0
+
+/* Define action or option for cmd_mac_control */
+#define cmd_act_mac_rx_on                   0x0001
+#define cmd_act_mac_tx_on                   0x0002
+#define cmd_act_mac_loopback_on             0x0004
+#define cmd_act_mac_wep_enable              0x0008
+#define cmd_act_mac_int_enable              0x0010
+#define cmd_act_mac_multicast_enable        0x0020
+#define cmd_act_mac_broadcast_enable        0x0040
+#define cmd_act_mac_promiscuous_enable      0x0080
+#define cmd_act_mac_all_multicast_enable    0x0100
+#define cmd_act_mac_strict_protection_enable  0x0400
+
+/* Define action or option for cmd_802_11_radio_control */
+#define cmd_type_auto_preamble              0x0001
+#define cmd_type_short_preamble             0x0002
+#define cmd_type_long_preamble              0x0003
+
+#define TURN_ON_RF                              0x01
+#define RADIO_ON                                0x01
+#define RADIO_OFF                               0x00
+
+#define SET_AUTO_PREAMBLE                       0x05
+#define SET_SHORT_PREAMBLE                      0x03
+#define SET_LONG_PREAMBLE                       0x01
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define cmd_opt_802_11_rf_channel_get       0x00
+#define cmd_opt_802_11_rf_channel_set       0x01
+
+/* Define action or option for cmd_802_11_rf_tx_power */
+#define cmd_act_tx_power_opt_get            0x0000
+#define cmd_act_tx_power_opt_set_high       0x8007
+#define cmd_act_tx_power_opt_set_mid        0x8004
+#define cmd_act_tx_power_opt_set_low        0x8000
+
+#define cmd_act_tx_power_index_high         0x0007
+#define cmd_act_tx_power_index_mid          0x0004
+#define cmd_act_tx_power_index_low          0x0000
+
+/* Define action or option for cmd_802_11_data_rate */
+#define cmd_act_set_tx_auto                 0x0000
+#define cmd_act_set_tx_fix_rate             0x0001
+#define cmd_act_get_tx_rate                 0x0002
+
+#define cmd_act_set_rx                      0x0001
+#define cmd_act_set_tx                      0x0002
+#define cmd_act_set_both                    0x0003
+#define cmd_act_get_rx                      0x0004
+#define cmd_act_get_tx                      0x0008
+#define cmd_act_get_both                    0x000c
+
+/* Define action or option for cmd_802_11_ps_mode */
+#define cmd_type_cam                        0x0000
+#define cmd_type_max_psp                    0x0001
+#define cmd_type_fast_psp                   0x0002
+
+/* Define action or option for cmd_bt_access */
+enum cmd_bt_access_opts {
+	/* The bt commands start at 5 instead of 1 because the old dft commands
+	 * are mapped to 1-4.  These old commands are no longer maintained and
+	 * should not be called.
+	 */
+	cmd_act_bt_access_add = 5,
+	cmd_act_bt_access_del,
+	cmd_act_bt_access_list,
+	cmd_act_bt_access_reset
+};
+
+/* Define action or option for cmd_fwt_access */
+enum cmd_fwt_access_opts {
+	cmd_act_fwt_access_add = 1,
+	cmd_act_fwt_access_del,
+	cmd_act_fwt_access_lookup,
+	cmd_act_fwt_access_list,
+	cmd_act_fwt_access_list_route,
+	cmd_act_fwt_access_list_neighbor,
+	cmd_act_fwt_access_reset,
+	cmd_act_fwt_access_cleanup,
+	cmd_act_fwt_access_time,
+};
+
+/* Define action or option for cmd_mesh_access */
+enum cmd_mesh_access_opts {
+	cmd_act_mesh_get_ttl = 1,
+	cmd_act_mesh_set_ttl,
+	cmd_act_mesh_get_stats,
+	cmd_act_mesh_get_mpp,
+	cmd_act_mesh_set_mpp,
+};
+
+/** Card Event definition */
+#define MACREG_INT_CODE_TX_PPA_FREE             0x00000000
+#define MACREG_INT_CODE_TX_DMA_DONE             0x00000001
+#define MACREG_INT_CODE_LINK_LOSE_W_SCAN        0x00000002
+#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN       0x00000003
+#define MACREG_INT_CODE_LINK_SENSED             0x00000004
+#define MACREG_INT_CODE_CMD_FINISHED            0x00000005
+#define MACREG_INT_CODE_MIB_CHANGED             0x00000006
+#define MACREG_INT_CODE_INIT_DONE               0x00000007
+#define MACREG_INT_CODE_DEAUTHENTICATED         0x00000008
+#define MACREG_INT_CODE_DISASSOCIATED           0x00000009
+#define MACREG_INT_CODE_PS_AWAKE                0x0000000a
+#define MACREG_INT_CODE_PS_SLEEP                0x0000000b
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST       0x0000000d
+#define MACREG_INT_CODE_MIC_ERR_UNICAST         0x0000000e
+#define MACREG_INT_CODE_WM_AWAKE                0x0000000f
+#define MACREG_INT_CODE_ADHOC_BCN_LOST          0x00000011
+#define MACREG_INT_CODE_RSSI_LOW		0x00000019
+#define MACREG_INT_CODE_SNR_LOW			0x0000001a
+#define MACREG_INT_CODE_MAX_FAIL		0x0000001b
+#define MACREG_INT_CODE_RSSI_HIGH		0x0000001c
+#define MACREG_INT_CODE_SNR_HIGH		0x0000001d
+
+#endif				/* _HOST_H_ */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644
index 0000000..f239e5d
--- /dev/null
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -0,0 +1,693 @@
+/*
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+#include <linux/wireless.h>
+#include "11d.h"
+#include "types.h"
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+	/* Current Tx packet status */
+	u32 tx_status;
+	/* Tx control */
+	u32 tx_control;
+	u32 tx_packet_location;
+	/* Tx packet length */
+	u16 tx_packet_length;
+	/* First 2 byte of destination MAC address */
+	u8 tx_dest_addr_high[2];
+	/* Last 4 byte of destination MAC address */
+	u8 tx_dest_addr_low[4];
+	/* Pkt Priority */
+	u8 priority;
+	/* Pkt Trasnit Power control */
+	u8 powermgmt;
+	/* Amount of time the packet has been queued in the driver (units = 2ms) */
+	u8 pktdelay_2ms;
+	/* reserved */
+	u8 reserved1;
+};
+
+/* RxPD Descriptor */
+struct rxpd {
+	/* Current Rx packet status */
+	u16 status;
+
+	/* SNR */
+	u8 snr;
+
+	/* Tx control */
+	u8 rx_control;
+
+	/* Pkt length */
+	u16 pkt_len;
+
+	/* Noise Floor */
+	u8 nf;
+
+	/* Rx Packet Rate */
+	u8 rx_rate;
+
+	/* Pkt addr */
+	u32 pkt_ptr;
+
+	/* Next Rx RxPD addr */
+	u32 next_rxpd_ptr;
+
+	/* Pkt Priority */
+	u8 priority;
+	u8 reserved[3];
+};
+
+struct cmd_ctrl_node {
+	/* CMD link list */
+	struct list_head list;
+	u32 status;
+	/* CMD ID */
+	u32 cmd_oid;
+	/*CMD wait option: wait for finish or no wait */
+	u16 wait_option;
+	/* command parameter */
+	void *pdata_buf;
+	/*command data */
+	u8 *bufvirtualaddr;
+	u16 cmdflags;
+	/* wait queue */
+	u16 cmdwaitqwoken;
+	wait_queue_head_t cmdwait_q;
+};
+
+/* WLAN_802_11_KEY
+ *
+ * Generic structure to hold all key types.  key type (WEP40, WEP104, TKIP, AES)
+ * is determined from the keylength field.
+ */
+struct WLAN_802_11_KEY {
+	u32 len;
+	u32 flags;  /* KEY_INFO_* from wlan_defs.h */
+	u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+	u16 type; /* KEY_TYPE_* from wlan_defs.h */
+};
+
+struct IE_WPA {
+	u8 elementid;
+	u8 len;
+	u8 oui[4];
+	u16 version;
+};
+
+struct WLAN_802_11_SSID {
+	/* SSID length */
+	u32 ssidlength;
+
+	/* SSID information field */
+	u8 ssid[IW_ESSID_MAX_SIZE];
+};
+
+struct WPA_SUPPLICANT {
+	u8 wpa_ie[256];
+	u8 wpa_ie_len;
+};
+
+/* wlan_offset_value */
+struct wlan_offset_value {
+	u32 offset;
+	u32 value;
+};
+
+struct WLAN_802_11_FIXED_IEs {
+	u8 timestamp[8];
+	u16 beaconinterval;
+	u16 capabilities;
+};
+
+struct WLAN_802_11_VARIABLE_IEs {
+	u8 elementid;
+	u8 length;
+	u8 data[1];
+};
+
+/* Define general data structure */
+/* cmd_DS_GEN */
+struct cmd_ds_gen {
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+};
+
+#define S_DS_GEN sizeof(struct cmd_ds_gen)
+/*
+ * Define data structure for cmd_get_hw_spec
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+	/* HW Interface version number */
+	u16 hwifversion;
+	/* HW version number */
+	u16 version;
+	/* Max number of TxPD FW can handle */
+	u16 nr_txpd;
+	/* Max no of Multicast address */
+	u16 nr_mcast_adr;
+	/* MAC address */
+	u8 permanentaddr[6];
+
+	/* region Code */
+	u16 regioncode;
+
+	/* Number of antenna used */
+	u16 nr_antenna;
+
+	/* FW release number, example 0x1234=1.2.3.4 */
+	u32 fwreleasenumber;
+
+	/* Base Address of TxPD queue */
+	u32 wcb_base;
+	/* Read Pointer of RxPd queue */
+	u32 rxpd_rdptr;
+
+	/* Write Pointer of RxPd queue */
+	u32 rxpd_wrptr;
+
+	/*FW/HW capability */
+	u32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_reset {
+	u16 action;
+};
+
+struct cmd_ds_802_11_subscribe_event {
+	u16 action;
+	u16 events;
+};
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for cmd_802_11_scan
+ */
+struct cmd_ds_802_11_scan {
+	u8 bsstype;
+	u8 BSSID[ETH_ALEN];
+	u8 tlvbuffer[1];
+#if 0
+	mrvlietypes_ssidparamset_t ssidParamSet;
+	mrvlietypes_chanlistparamset_t ChanListParamSet;
+	mrvlietypes_ratesparamset_t OpRateSet;
+#endif
+};
+
+struct cmd_ds_802_11_scan_rsp {
+	u16 bssdescriptsize;
+	u8 nr_sets;
+	u8 bssdesc_and_tlvbuffer[1];
+};
+
+struct cmd_ds_802_11_get_log {
+	u32 mcasttxframe;
+	u32 failed;
+	u32 retry;
+	u32 multiretry;
+	u32 framedup;
+	u32 rtssuccess;
+	u32 rtsfailure;
+	u32 ackfailure;
+	u32 rxfrag;
+	u32 mcastrxframe;
+	u32 fcserror;
+	u32 txframe;
+	u32 wepundecryptable;
+};
+
+struct cmd_ds_mac_control {
+	u16 action;
+	u16 reserved;
+};
+
+struct cmd_ds_mac_multicast_adr {
+	u16 action;
+	u16 nr_of_adrs;
+	u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_802_11_authenticate {
+	u8 macaddr[ETH_ALEN];
+	u8 authtype;
+	u8 reserved[10];
+};
+
+struct cmd_ds_802_11_deauthenticate {
+	u8 macaddr[6];
+	u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate {
+	u8 peerstaaddr[6];
+	struct ieeetypes_capinfo capinfo;
+	u16 listeninterval;
+	u16 bcnperiod;
+	u8 dtimperiod;
+
+#if 0
+	mrvlietypes_ssidparamset_t ssidParamSet;
+	mrvlietypes_phyparamset_t phyparamset;
+	mrvlietypes_ssparamset_t ssparamset;
+	mrvlietypes_ratesparamset_t ratesParamSet;
+#endif
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_disassociate {
+	u8 destmacaddr[6];
+	u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate_rsp {
+	struct ieeetypes_assocrsp assocRsp;
+};
+
+struct cmd_ds_802_11_ad_hoc_result {
+	u8 PAD[3];
+	u8 BSSID[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_set_wep {
+	/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+	u16 action;
+
+	/* key Index selected for Tx */
+	u16 keyindex;
+
+	/* 40, 128bit or TXWEP */
+	u8 keytype[4];
+	u8 keymaterial[4][16];
+};
+
+struct cmd_ds_802_3_get_stat {
+	u32 xmitok;
+	u32 rcvok;
+	u32 xmiterror;
+	u32 rcverror;
+	u32 rcvnobuffer;
+	u32 rcvcrcerror;
+};
+
+struct cmd_ds_802_11_get_stat {
+	u32 txfragmentcnt;
+	u32 mcasttxframecnt;
+	u32 failedcnt;
+	u32 retrycnt;
+	u32 Multipleretrycnt;
+	u32 rtssuccesscnt;
+	u32 rtsfailurecnt;
+	u32 ackfailurecnt;
+	u32 frameduplicatecnt;
+	u32 rxfragmentcnt;
+	u32 mcastrxframecnt;
+	u32 fcserrorcnt;
+	u32 bcasttxframecnt;
+	u32 bcastrxframecnt;
+	u32 txbeacon;
+	u32 rxbeacon;
+	u32 wepundecryptable;
+};
+
+struct cmd_ds_802_11_snmp_mib {
+	u16 querytype;
+	u16 oid;
+	u16 bufsize;
+	u8 value[128];
+};
+
+struct cmd_ds_mac_reg_map {
+	u16 buffersize;
+	u8 regmap[128];
+	u16 reserved;
+};
+
+struct cmd_ds_bbp_reg_map {
+	u16 buffersize;
+	u8 regmap[128];
+	u16 reserved;
+};
+
+struct cmd_ds_rf_reg_map {
+	u16 buffersize;
+	u8 regmap[64];
+	u16 reserved;
+};
+
+struct cmd_ds_mac_reg_access {
+	u16 action;
+	u16 offset;
+	u32 value;
+};
+
+struct cmd_ds_bbp_reg_access {
+	u16 action;
+	u16 offset;
+	u8 value;
+	u8 reserved[3];
+};
+
+struct cmd_ds_rf_reg_access {
+	u16 action;
+	u16 offset;
+	u8 value;
+	u8 reserved[3];
+};
+
+struct cmd_ds_802_11_radio_control {
+	u16 action;
+	u16 control;
+};
+
+struct cmd_ds_802_11_sleep_params {
+	/* ACT_GET/ACT_SET */
+	u16 action;
+
+	/* Sleep clock error in ppm */
+	u16 error;
+
+	/* Wakeup offset in usec */
+	u16 offset;
+
+	/* Clock stabilization time in usec */
+	u16 stabletime;
+
+	/* control periodic calibration */
+	u8 calcontrol;
+
+	/* control the use of external sleep clock */
+	u8 externalsleepclk;
+
+	/* reserved field, should be set to zero */
+	u16 reserved;
+};
+
+struct cmd_ds_802_11_inactivity_timeout {
+	/* ACT_GET/ACT_SET */
+	u16 action;
+
+	/* Inactivity timeout in msec */
+	u16 timeout;
+};
+
+struct cmd_ds_802_11_rf_channel {
+	u16 action;
+	u16 currentchannel;
+	u16 rftype;
+	u16 reserved;
+	u8 channellist[32];
+};
+
+struct cmd_ds_802_11_rssi {
+	/* weighting factor */
+	u16 N;
+
+	u16 reserved_0;
+	u16 reserved_1;
+	u16 reserved_2;
+};
+
+struct cmd_ds_802_11_rssi_rsp {
+	u16 SNR;
+	u16 noisefloor;
+	u16 avgSNR;
+	u16 avgnoisefloor;
+};
+
+struct cmd_ds_802_11_mac_address {
+	u16 action;
+	u8 macadd[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_rf_tx_power {
+	u16 action;
+	u16 currentlevel;
+};
+
+struct cmd_ds_802_11_rf_antenna {
+	u16 action;
+
+	/* Number of antennas or 0xffff(diversity) */
+	u16 antennamode;
+
+};
+
+struct cmd_ds_802_11_ps_mode {
+	u16 action;
+	u16 nullpktinterval;
+	u16 multipledtim;
+	u16 reserved;
+	u16 locallisteninterval;
+};
+
+struct PS_CMD_ConfirmSleep {
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+
+	u16 action;
+	u16 reserved1;
+	u16 multipledtim;
+	u16 reserved;
+	u16 locallisteninterval;
+};
+
+struct cmd_ds_802_11_data_rate {
+	u16 action;
+	u16 reserverd;
+	u8 datarate[G_SUPPORTED_RATES];
+};
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+	u16 action;
+	u16 enablehwauto;
+	u16 bitmap;
+};
+
+struct cmd_ds_802_11_ad_hoc_start {
+	u8 SSID[IW_ESSID_MAX_SIZE];
+	u8 bsstype;
+	u16 beaconperiod;
+	u8 dtimperiod;
+	union IEEEtypes_ssparamset ssparamset;
+	union ieeetypes_phyparamset phyparamset;
+	u16 probedelay;
+	struct ieeetypes_capinfo cap;
+	u8 datarate[G_SUPPORTED_RATES];
+	u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+	u8 BSSID[6];
+	u8 SSID[32];
+	u8 bsstype;
+	u16 beaconperiod;
+	u8 dtimperiod;
+	u8 timestamp[8];
+	u8 localtime[8];
+	union ieeetypes_phyparamset phyparamset;
+	union IEEEtypes_ssparamset ssparamset;
+	struct ieeetypes_capinfo cap;
+	u8 datarates[G_SUPPORTED_RATES];
+
+	/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+	 * Adhoc join command and will cause a binary layout mismatch with
+	 * the firmware
+	 */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+	struct adhoc_bssdesc bssdescriptor;
+	u16 failtimeout;
+	u16 probedelay;
+
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+	u16 action;
+	u16 enable;
+};
+
+struct MrvlIEtype_keyParamSet {
+	/* type ID */
+	u16 type;
+
+	/* length of Payload */
+	u16 length;
+
+	/* type of key: WEP=0, TKIP=1, AES=2 */
+	u16 keytypeid;
+
+	/* key control Info specific to a keytypeid */
+	u16 keyinfo;
+
+	/* length of key */
+	u16 keylen;
+
+	/* key material of size keylen */
+	u8 key[32];
+};
+
+struct cmd_ds_802_11_key_material {
+	u16 action;
+	struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+	u16 action;
+
+	/* multiple 4 */
+	u16 offset;
+	u16 bytecount;
+	u8 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+	u16 action;
+	u8 enable;
+	s8 P0;
+	s8 P1;
+	s8 P2;
+	u8 usesnr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_led_ctrl {
+	u16 action;
+	u16 numled;
+	u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_pwr_cfg {
+	u16 action;
+	u8 enable;
+	s8 PA_P0;
+	s8 PA_P1;
+	s8 PA_P2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+	u16 afc_auto;
+	union {
+		struct {
+			u16 threshold;
+			u16 period;
+		};
+		struct {
+			s16 timing_offset;
+			s16 carrier_offset;
+		};
+	};
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+	u16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+	__le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+	u16 action;
+	u32 id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+	u16 action;
+	u32 id;
+	u8 da[ETH_ALEN];
+	u8 dir;
+	u8 ra[ETH_ALEN];
+	u32 ssn;
+	u32 dsn;
+	u32 metric;
+	u8 hopcount;
+	u8 ttl;
+	u32 expiration;
+	u8 sleepmode;
+	u32 snr;
+	u32 references;
+} __attribute__ ((packed));
+
+#define MESH_STATS_NUM 7
+struct cmd_ds_mesh_access {
+	u16 action;
+	u32 data[MESH_STATS_NUM + 1];	/* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_command {
+	/* command header */
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+
+	/* command Body */
+	union {
+		struct cmd_ds_get_hw_spec hwspec;
+		struct cmd_ds_802_11_ps_mode psmode;
+		struct cmd_ds_802_11_scan scan;
+		struct cmd_ds_802_11_scan_rsp scanresp;
+		struct cmd_ds_mac_control macctrl;
+		struct cmd_ds_802_11_associate associate;
+		struct cmd_ds_802_11_deauthenticate deauth;
+		struct cmd_ds_802_11_set_wep wep;
+		struct cmd_ds_802_11_ad_hoc_start ads;
+		struct cmd_ds_802_11_reset reset;
+		struct cmd_ds_802_11_ad_hoc_result result;
+		struct cmd_ds_802_11_get_log glog;
+		struct cmd_ds_802_11_authenticate auth;
+		struct cmd_ds_802_11_get_stat gstat;
+		struct cmd_ds_802_3_get_stat gstat_8023;
+		struct cmd_ds_802_11_snmp_mib smib;
+		struct cmd_ds_802_11_rf_tx_power txp;
+		struct cmd_ds_802_11_rf_antenna rant;
+		struct cmd_ds_802_11_data_rate drate;
+		struct cmd_ds_802_11_rate_adapt_rateset rateset;
+		struct cmd_ds_mac_multicast_adr madr;
+		struct cmd_ds_802_11_ad_hoc_join adj;
+		struct cmd_ds_802_11_radio_control radio;
+		struct cmd_ds_802_11_rf_channel rfchannel;
+		struct cmd_ds_802_11_rssi rssi;
+		struct cmd_ds_802_11_rssi_rsp rssirsp;
+		struct cmd_ds_802_11_disassociate dassociate;
+		struct cmd_ds_802_11_mac_address macadd;
+		struct cmd_ds_802_11_enable_rsn enbrsn;
+		struct cmd_ds_802_11_key_material keymaterial;
+		struct cmd_ds_mac_reg_access macreg;
+		struct cmd_ds_bbp_reg_access bbpreg;
+		struct cmd_ds_rf_reg_access rfreg;
+		struct cmd_ds_802_11_eeprom_access rdeeprom;
+
+		struct cmd_ds_802_11d_domain_info domaininfo;
+		struct cmd_ds_802_11d_domain_info domaininforesp;
+
+		struct cmd_ds_802_11_sleep_params sleep_params;
+		struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
+		struct cmd_ds_802_11_tpc_cfg tpccfg;
+		struct cmd_ds_802_11_pwr_cfg pwrcfg;
+		struct cmd_ds_802_11_afc afc;
+		struct cmd_ds_802_11_led_ctrl ledgpio;
+
+		struct cmd_tx_rate_query txrate;
+		struct cmd_ds_bt_access bt;
+		struct cmd_ds_fwt_access fwt;
+		struct cmd_ds_mesh_access mesh;
+		struct cmd_ds_get_tsf gettsf;
+		struct cmd_ds_802_11_subscribe_event subscribe_event;
+	} params;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644
index 0000000..567000c
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_bootcmd.c
@@ -0,0 +1,38 @@
+/**
+  * This file contains functions used in USB Boot command
+  * and Boot2/FW update
+  */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+/**
+ *  @brief This function issues Boot command to the Boot2 code
+ *  @param ivalue   1:Boot from FW by USB-Download
+ *                  2:Boot from FW in EEPROM
+ *  @return 	   	0
+ */
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+{
+	struct usb_card_rec	*cardp = priv->wlan_dev.card;
+	struct bootcmdstr	sbootcmd;
+	int i;
+
+	/* Prepare command */
+	sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
+	sbootcmd.u8cmd_tag = ivalue;
+	for (i=0; i<11; i++)
+		sbootcmd.au8dumy[i]=0x00;
+	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+
+	/* Issue command */
+	usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644
index 0000000..695fb6a
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -0,0 +1,952 @@
+/**
+  * This file contains functions used in USB interface module.
+  */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN	4
+
+static const char usbdriver_name[] = "usb8xxx";
+
+static struct usb_device_id if_usb_table[] = {
+	/* Enter the device signature inside */
+	{
+		USB_DEVICE(USB8388_VID_1, USB8388_PID_1),
+	},
+	{
+		USB_DEVICE(USB8388_VID_2, USB8388_PID_2),
+	},
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+
+/**
+ *  @brief  call back function to handle the status of the URB
+ *  @param urb 		pointer to urb structure
+ *  @return 	   	N/A
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+	wlan_private *priv = (wlan_private *) (urb->context);
+	wlan_adapter *adapter = priv->adapter;
+	struct net_device *dev = priv->wlan_dev.netdev;
+
+	/* handle the transmission complete validations */
+
+	if (urb->status != 0) {
+		/* print the failure status number for debug */
+		lbs_pr_info("URB in failure status\n");
+	} else {
+		lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
+		lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
+		       urb->actual_length);
+		priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+		/* Wake main thread if commands are pending */
+		if (!adapter->cur_cmd)
+			wake_up_interruptible(&priv->mainthread.waitq);
+		if ((adapter->connect_status == libertas_connected))
+			netif_wake_queue(dev);
+	}
+
+	return;
+}
+
+/**
+ *  @brief  free tx/rx urb, skb and rx buffer
+ *  @param cardp	pointer usb_card_rec
+ *  @return 	   	N/A
+ */
+void if_usb_free(struct usb_card_rec *cardp)
+{
+	ENTER();
+
+	/* Unlink tx & rx urb */
+	usb_kill_urb(cardp->tx_urb);
+	usb_kill_urb(cardp->rx_urb);
+
+	usb_free_urb(cardp->tx_urb);
+	cardp->tx_urb = NULL;
+
+	usb_free_urb(cardp->rx_urb);
+	cardp->rx_urb = NULL;
+
+	kfree(cardp->bulk_out_buffer);
+	cardp->bulk_out_buffer = NULL;
+
+	LEAVE();
+	return;
+}
+
+/**
+ *  @brief sets the configuration values
+ *  @param ifnum	interface number
+ *  @param id		pointer to usb_device_id
+ *  @return 	   	0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	struct usb_device *udev;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	wlan_private *pwlanpriv;
+	struct usb_card_rec *usb_cardp;
+	int i;
+
+	udev = interface_to_usbdev(intf);
+
+	usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+	if (!usb_cardp) {
+		lbs_pr_err("Out of memory allocating private data.\n");
+		goto error;
+	}
+
+	usb_cardp->udev = udev;
+	iface_desc = intf->cur_altsetting;
+
+	lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+	       " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+	       udev->descriptor.bcdUSB,
+	       udev->descriptor.bDeviceClass,
+	       udev->descriptor.bDeviceSubClass,
+	       udev->descriptor.bDeviceProtocol);
+
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk in endpoint */
+			lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
+			       endpoint->wMaxPacketSize);
+			if (!
+			    (usb_cardp->rx_urb =
+			     usb_alloc_urb(0, GFP_KERNEL))) {
+				lbs_dev_dbg(1, &udev->dev,
+				       "Rx URB allocation failed\n");
+				goto dealloc;
+			}
+			usb_cardp->rx_urb_recall = 0;
+
+			usb_cardp->bulk_in_size =
+			    endpoint->wMaxPacketSize;
+			usb_cardp->bulk_in_endpointAddr =
+			    (endpoint->
+			     bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+			lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
+			       endpoint->bEndpointAddress);
+		}
+
+		if (((endpoint->
+		      bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+		     USB_DIR_OUT)
+		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_BULK)) {
+			/* We found bulk out endpoint */
+			if (!
+			    (usb_cardp->tx_urb =
+			     usb_alloc_urb(0, GFP_KERNEL))) {
+				lbs_dev_dbg(1,&udev->dev,
+				       "Tx URB allocation failed\n");
+				goto dealloc;
+			}
+
+			usb_cardp->bulk_out_size =
+			    endpoint->wMaxPacketSize;
+			lbs_dev_dbg(1, &udev->dev,
+				    "Bulk out size is %d\n",
+				    endpoint->wMaxPacketSize);
+			usb_cardp->bulk_out_endpointAddr =
+			    endpoint->bEndpointAddress;
+			lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
+				    endpoint->bEndpointAddress);
+			usb_cardp->bulk_out_buffer =
+			    kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+				    GFP_KERNEL);
+
+			if (!usb_cardp->bulk_out_buffer) {
+				lbs_dev_dbg(1, &udev->dev,
+				       "Could not allocate buffer\n");
+				goto dealloc;
+			}
+		}
+	}
+
+
+	/* At this point wlan_add_card() will be called.  Don't worry
+	 * about keeping pwlanpriv around since it will be set on our
+	 * usb device data in -> add() -> libertas_sbi_register_dev().
+	 */
+	if (!(pwlanpriv = wlan_add_card(usb_cardp)))
+		goto dealloc;
+
+	usb_get_dev(udev);
+	usb_set_intfdata(intf, usb_cardp);
+
+	/*
+	 * return card structure, which can be got back in the
+	 * diconnect function as the ptr
+	 * argument.
+	 */
+	return 0;
+
+dealloc:
+	if_usb_free(usb_cardp);
+
+error:
+	return -ENOMEM;
+}
+
+/**
+ *  @brief free resource and cleanup
+ *  @param udev		pointer to usb_device
+ *  @param ptr		pointer to usb_cardp
+ *  @return 	   	N/A
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+	struct usb_card_rec *cardp = usb_get_intfdata(intf);
+	wlan_private *priv = (wlan_private *) cardp->priv;
+	wlan_adapter *adapter = NULL;
+
+	adapter = priv->adapter;
+
+	/*
+	 * Update Surprise removed to TRUE
+	 */
+	adapter->surpriseremoved = 1;
+
+	/* card is removed and we can call wlan_remove_card */
+	lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
+	wlan_remove_card(cardp);
+
+	/* Unlink and free urb */
+	if_usb_free(cardp);
+
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(interface_to_usbdev(intf));
+
+	return;
+}
+
+/**
+ *  @brief  This function download FW
+ *  @param priv		pointer to wlan_private
+ *  @return 	   	0
+ */
+static int if_prog_firmware(wlan_private * priv)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	struct FWData *fwdata;
+	struct fwheader *fwheader;
+	u8 *firmware = priv->firmware->data;
+
+	fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+
+	if (!fwdata)
+		return -1;
+
+	fwheader = &fwdata->fwheader;
+
+	if (!cardp->CRC_OK) {
+		cardp->totalbytes = cardp->fwlastblksent;
+		cardp->fwseqnum = cardp->lastseqnum - 1;
+	}
+
+	lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
+		    cardp->totalbytes);
+
+	memcpy(fwheader, &firmware[cardp->totalbytes],
+	       sizeof(struct fwheader));
+
+	cardp->fwlastblksent = cardp->totalbytes;
+	cardp->totalbytes += sizeof(struct fwheader);
+
+	lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
+	memcpy(fwdata->data, &firmware[cardp->totalbytes],
+	       fwdata->fwheader.datalength);
+
+	lbs_dev_dbg(2, &cardp->udev->dev,
+		    "Data length = %d\n", fwdata->fwheader.datalength);
+
+	cardp->fwseqnum = cardp->fwseqnum + 1;
+
+	fwdata->seqnum = cardp->fwseqnum;
+	cardp->lastseqnum = fwdata->seqnum;
+	cardp->totalbytes += fwdata->fwheader.datalength;
+
+	if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) {
+		lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
+			    cardp->totalbytes);
+		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+		usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+
+	} else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) {
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "Host has finished FW downloading\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "Donwloading FW JUMP BLOCK\n");
+		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+		usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+		cardp->fwfinalblk = 1;
+	}
+
+	lbs_dev_dbg(2, &cardp->udev->dev,
+		    "The firmware download is done size is %d\n",
+		    cardp->totalbytes);
+
+	kfree(fwdata);
+
+	return 0;
+}
+
+static int libertas_do_reset(wlan_private *priv)
+{
+	int ret;
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+	ret = usb_reset_device(cardp->udev);
+	if (!ret) {
+		msleep(10);
+		reset_device(priv);
+		msleep(10);
+	}
+	return ret;
+}
+
+/**
+ *  @brief This function transfer the data to the device.
+ *  @param priv 	pointer to wlan_private
+ *  @param payload	pointer to payload data
+ *  @param nb		data length
+ *  @return 	   	0 or -1
+ */
+int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+{
+	/* pointer to card structure */
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	int ret = -1;
+
+	/* check if device is removed */
+	if (priv->adapter->surpriseremoved) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
+		goto tx_ret;
+	}
+
+	usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+			  usb_sndbulkpipe(cardp->udev,
+					  cardp->bulk_out_endpointAddr),
+			  payload, nb, if_usb_write_bulk_callback, priv);
+
+	cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+	if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+		/*  transfer failed */
+		lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
+		ret = -1;
+	} else {
+		lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
+		ret = 0;
+	}
+
+tx_ret:
+	return ret;
+}
+
+static int __if_usb_submit_rx_urb(wlan_private * priv,
+				  void (*callbackfn)
+				  (struct urb *urb))
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	struct sk_buff *skb;
+	struct read_cb_info *rinfo = &cardp->rinfo;
+	int ret = -1;
+
+	if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+		lbs_pr_err("No free skb\n");
+		goto rx_ret;
+	}
+
+	rinfo->skb = skb;
+
+	/* Fill the receive configuration URB and initialise the Rx call back */
+	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+			  usb_rcvbulkpipe(cardp->udev,
+					  cardp->bulk_in_endpointAddr),
+			  skb->tail + IPFIELD_ALIGN_OFFSET,
+			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+			  rinfo);
+
+	cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+	lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+	if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+		/* handle failure conditions */
+		lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
+		ret = -1;
+	} else {
+		lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
+		ret = 0;
+	}
+
+rx_ret:
+	return ret;
+}
+
+static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+{
+	return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+}
+
+static inline int if_usb_submit_rx_urb(wlan_private * priv)
+{
+	return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+	wlan_private *priv = rinfo->priv;
+	struct sk_buff *skb = rinfo->skb;
+	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+	struct fwsyncheader *syncfwheader;
+	struct bootcmdrespStr bootcmdresp;
+
+	if (urb->status) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "URB status is failed during fw load\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	if (cardp->bootcmdresp == 0) {
+		memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+			sizeof(bootcmdresp));
+		if (cardp->udev->descriptor.bcdDevice < 0x3106) {
+			kfree_skb(skb);
+			if_usb_submit_rx_urb_fwload(priv);
+			cardp->bootcmdresp = 1;
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "Received valid boot command response\n");
+			return;
+		}
+		if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
+			lbs_pr_info(
+				"boot cmd response wrong magic number (0x%x)\n",
+				bootcmdresp.u32magicnumber);
+		} else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+			lbs_pr_info(
+				"boot cmd response cmd_tag error (%d)\n",
+				bootcmdresp.u8cmd_tag);
+		} else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+			lbs_pr_info(
+				"boot cmd response result error (%d)\n",
+				bootcmdresp.u8result);
+		} else {
+			cardp->bootcmdresp = 1;
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "Received valid boot command response\n");
+		}
+		kfree_skb(skb);
+		if_usb_submit_rx_urb_fwload(priv);
+		return;
+	}
+
+	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+	if (!syncfwheader) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+			sizeof(struct fwsyncheader));
+
+	if (!syncfwheader->cmd) {
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "FW received Blk with correct CRC\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "FW received Blk seqnum = %d\n",
+		       syncfwheader->seqnum);
+		cardp->CRC_OK = 1;
+	} else {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "FW received Blk with CRC error\n");
+		cardp->CRC_OK = 0;
+	}
+
+	kfree_skb(skb);
+
+	if (cardp->fwfinalblk) {
+		cardp->fwdnldover = 1;
+		goto exit;
+	}
+
+	if_prog_firmware(priv);
+
+	if_usb_submit_rx_urb_fwload(priv);
+exit:
+	kfree(syncfwheader);
+
+	return;
+
+}
+
+#define MRVDRV_MIN_PKT_LEN	30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+				       struct usb_card_rec *cardp,
+				       wlan_private *priv)
+{
+	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+	    MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Packet length is Invalid\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+	skb_put(skb, recvlength);
+	skb_pull(skb, MESSAGE_HEADER_LEN);
+	libertas_process_rxed_packet(priv, skb);
+	priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+}
+
+static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+				      struct sk_buff *skb,
+				      struct usb_card_rec *cardp,
+				      wlan_private *priv)
+{
+	u8 *cmdbuf;
+	if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "The receive buffer is too large\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	if (!in_interrupt())
+		BUG();
+
+	spin_lock(&priv->adapter->driver_lock);
+	/* take care of cur_cmd = NULL case by reading the
+	 * data to clear the interrupt */
+	if (!priv->adapter->cur_cmd) {
+		cmdbuf = priv->wlan_dev.upld_buf;
+		priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+	} else
+		cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+
+	cardp->usb_int_cause |= his_cmdupldrdy;
+	priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+	memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
+	       priv->wlan_dev.upld_len);
+
+	kfree_skb(skb);
+	libertas_interrupt(priv->wlan_dev.netdev);
+	spin_unlock(&priv->adapter->driver_lock);
+
+	lbs_dev_dbg(1, &cardp->udev->dev,
+		    "Wake up main thread to handle cmd response\n");
+
+	return;
+}
+
+/**
+ *  @brief This function reads of the packet into the upload buff,
+ *  wake up the main thread and initialise the Rx callack.
+ *
+ *  @param urb		pointer to struct urb
+ *  @return 	   	N/A
+ */
+static void if_usb_receive(struct urb *urb)
+{
+	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+	wlan_private *priv = rinfo->priv;
+	struct sk_buff *skb = rinfo->skb;
+	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+	int recvlength = urb->actual_length;
+	u8 *recvbuff = NULL;
+	u32 recvtype;
+
+	ENTER();
+
+	if (recvlength) {
+		if (urb->status) {
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "URB status is failed\n");
+			kfree_skb(skb);
+			goto setup_for_next;
+		}
+
+		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+		memcpy(&recvtype, recvbuff, sizeof(u32));
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Recv length = 0x%x\n", recvlength);
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Receive type = 0x%X\n", recvtype);
+		recvtype = le32_to_cpu(recvtype);
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Receive type after = 0x%X\n", recvtype);
+	} else if (urb->status)
+		goto rx_exit;
+
+
+	switch (recvtype) {
+	case CMD_TYPE_DATA:
+		process_cmdtypedata(recvlength, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_REQUEST:
+		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_INDICATION:
+		/* Event cause handling */
+		spin_lock(&priv->adapter->driver_lock);
+		cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
+		lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
+			    cardp->usb_event_cause);
+		if (cardp->usb_event_cause & 0xffff0000) {
+			libertas_send_tx_feedback(priv);
+			break;
+		}
+		cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
+		cardp->usb_int_cause |= his_cardevent;
+		kfree_skb(skb);
+		libertas_interrupt(priv->wlan_dev.netdev);
+		spin_unlock(&priv->adapter->driver_lock);
+		goto rx_exit;
+	default:
+		kfree_skb(skb);
+		break;
+	}
+
+setup_for_next:
+	if_usb_submit_rx_urb(priv);
+rx_exit:
+	LEAVE();
+	return;
+}
+
+/**
+ *  @brief This function downloads data to FW
+ *  @param priv		pointer to wlan_private structure
+ *  @param type		type of data
+ *  @param buf		pointer to data buffer
+ *  @param len		number of bytes
+ *  @return 	   	0 or -1
+ */
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+	int ret = -1;
+	u32 tmp;
+	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+	lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
+	lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
+
+	if (type == MVMS_CMD) {
+		tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+		priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+		       MESSAGE_HEADER_LEN);
+
+	} else {
+		tmp = cpu_to_le32(CMD_TYPE_DATA);
+		priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+		       MESSAGE_HEADER_LEN);
+	}
+
+	memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+
+	ret =
+	    usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
+
+	return ret;
+}
+
+/* called with adapter->driver_lock held */
+int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+	*ireg = cardp->usb_int_cause;
+	cardp->usb_int_cause = 0;
+
+	lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+
+	return 0;
+}
+
+int libertas_sbi_read_event_cause(wlan_private * priv)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	priv->adapter->eventcause = cardp->usb_event_cause;
+	/* Re-submit rx urb here to avoid event lost issue */
+	if_usb_submit_rx_urb(priv);
+	return 0;
+}
+
+int reset_device(wlan_private *priv)
+{
+	int ret;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+				    cmd_act_halt, 0, 0, NULL);
+	msleep_interruptible(10);
+
+	return ret;
+}
+
+int libertas_sbi_unregister_dev(wlan_private * priv)
+{
+	int ret = 0;
+
+	/* Need to send a Reset command to device before USB resources freed
+	 * and wlan_remove_card() called, then device can handle FW download
+	 * again.
+	 */
+	if (priv)
+		reset_device(priv);
+
+	return ret;
+}
+
+
+/**
+ *  @brief  This function register usb device and initialize parameter
+ *  @param		priv pointer to wlan_private
+ *  @return		0 or -1
+ */
+int libertas_sbi_register_dev(wlan_private * priv)
+{
+
+	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+	ENTER();
+
+	cardp->priv = priv;
+	cardp->eth_dev = priv->wlan_dev.netdev;
+	priv->hotplug_device = &(cardp->udev->dev);
+
+	SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev));
+
+	lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
+		    cardp->udev);
+
+	LEAVE();
+	return 0;
+}
+
+
+
+int libertas_sbi_prog_firmware(wlan_private * priv)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	int i = 0;
+	static int reset_count = 10;
+
+	ENTER();
+
+	cardp->rinfo.priv = priv;
+
+restart:
+	if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
+		LEAVE();
+		return -1;
+	}
+
+#ifdef SUPPORT_BOOT_COMMAND
+	cardp->bootcmdresp = 0;
+	do {
+		int j = 0;
+		i++;
+		/* Issue Boot command = 1, Boot from Download-FW */
+		if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+		/* wait for command response */
+		do {
+			j++;
+			msleep_interruptible(100);
+		} while (cardp->bootcmdresp == 0 && j < 10);
+	} while (cardp->bootcmdresp == 0 && i < 5);
+
+	if (cardp->bootcmdresp == 0) {
+		if (--reset_count >= 0) {
+			libertas_do_reset(priv);
+			goto restart;
+		}
+		return -1;
+	}
+#endif
+
+	i = 0;
+	priv->adapter->fw_ready = 0;
+
+	cardp->totalbytes = 0;
+	cardp->fwlastblksent = 0;
+	cardp->CRC_OK = 1;
+	cardp->fwdnldover = 0;
+	cardp->fwseqnum = -1;
+	cardp->totalbytes = 0;
+	cardp->fwfinalblk = 0;
+
+	if_prog_firmware(priv);
+
+	do {
+		lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
+		i++;
+		msleep_interruptible(100);
+		if (priv->adapter->surpriseremoved || i >= 20)
+			break;
+	} while (!cardp->fwdnldover);
+
+	if (!cardp->fwdnldover) {
+		lbs_pr_info("failed to load fw, resetting device!\n");
+		if (--reset_count >= 0) {
+			libertas_do_reset(priv);
+			goto restart;
+		}
+
+		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+		LEAVE();
+		return -1;
+	}
+
+	if_usb_submit_rx_urb(priv);
+
+	/* Delay 200 ms to waiting for the FW ready */
+	msleep_interruptible(200);
+
+	priv->adapter->fw_ready = 1;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Given a usb_card_rec return its wlan_private
+ *  @param card		pointer to a usb_card_rec
+ *  @return 	   	pointer to wlan_private
+ */
+wlan_private *libertas_sbi_get_priv(void *card)
+{
+	struct usb_card_rec *cardp = card;
+	return cardp->priv;
+}
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private * priv)
+{
+	return 0;
+}
+
+int libertas_sbi_resume(wlan_private * priv)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_card_rec *cardp = usb_get_intfdata(intf);
+	wlan_private *priv = cardp->priv;
+
+	ENTER();
+
+	if (priv->adapter->psstate != PS_STATE_FULL_POWER)
+		return -1;
+
+	netif_device_detach(cardp->eth_dev);
+
+	/* Unlink tx & rx urb */
+	usb_kill_urb(cardp->tx_urb);
+	usb_kill_urb(cardp->rx_urb);
+
+	cardp->rx_urb_recall = 1;
+
+	LEAVE();
+	return 0;
+}
+
+static int if_usb_resume(struct usb_interface *intf)
+{
+	struct usb_card_rec *cardp = usb_get_intfdata(intf);
+
+	ENTER();
+
+	cardp->rx_urb_recall = 0;
+
+	if_usb_submit_rx_urb(cardp->priv);
+
+	netif_device_attach(cardp->eth_dev);
+
+	LEAVE();
+	return 0;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+static struct usb_driver if_usb_driver = {
+	/* driver name */
+	.name = usbdriver_name,
+	/* probe function name */
+	.probe = if_usb_probe,
+	/* disconnect function  name */
+	.disconnect = if_usb_disconnect,
+	/* device signature table */
+	.id_table = if_usb_table,
+	.suspend = if_usb_suspend,
+	.resume = if_usb_resume,
+};
+
+/**
+ *  @brief This function registers driver.
+ *  @param add		pointer to add_card callback function
+ *  @param remove	pointer to remove card callback function
+ *  @param arg		pointer to call back function parameter
+ *  @return 	   	dummy success variable
+ */
+int libertas_sbi_register(void)
+{
+	/*
+	 * API registers the Marvell USB driver
+	 * to the USB system
+	 */
+	usb_register(&if_usb_driver);
+
+	/* Return success to wlan layer */
+	return 0;
+}
+
+/**
+ *  @brief This function removes usb driver.
+ *  @return 	   	N/A
+ */
+void libertas_sbi_unregister(void)
+{
+	/* API unregisters the driver from USB subsystem */
+	usb_deregister(&if_usb_driver);
+	return;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644
index 0000000..7851167
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -0,0 +1,109 @@
+/**
+  * This file contains definition for USB interface.
+  */
+#define CMD_TYPE_REQUEST                0xF00DFACE
+#define CMD_TYPE_DATA                   0xBEADC0DE
+#define CMD_TYPE_INDICATION             0xBEEFFACE
+
+#define IPFIELD_ALIGN_OFFSET	2
+
+#define USB8388_VID_1	0x1286
+#define USB8388_PID_1	0x2001
+#define USB8388_VID_2	0x05a3
+#define USB8388_PID_2	0x8388
+
+#ifdef SUPPORT_BOOT_COMMAND
+#define BOOT_CMD_FW_BY_USB     0x01
+#define BOOT_CMD_FW_IN_EEPROM  0x02
+#define BOOT_CMD_UPDATE_BOOT2  0x03
+#define BOOT_CMD_UPDATE_FW     0x04
+#define BOOT_CMD_MAGIC_NUMBER  0x4C56524D   /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+
+struct bootcmdstr
+{
+	u32 u32magicnumber;
+	u8  u8cmd_tag;
+	u8  au8dumy[11];
+};
+
+#define BOOT_CMD_RESP_OK     0x0001
+#define BOOT_CMD_RESP_FAIL   0x0000
+
+struct bootcmdrespStr
+{
+	u32 u32magicnumber;
+	u8  u8cmd_tag;
+	u8  u8result;
+	u8  au8dumy[2];
+};
+#endif /* SUPPORT_BOOT_COMMAND */
+
+/* read callback private data */
+struct read_cb_info {
+        wlan_private *priv;
+        struct sk_buff *skb;
+};
+
+/** USB card description structure*/
+struct usb_card_rec {
+	struct net_device *eth_dev;
+	struct usb_device *udev;
+	struct urb *rx_urb, *tx_urb;
+	void *priv;
+	struct read_cb_info rinfo;
+
+	int bulk_in_size;
+	u8 bulk_in_endpointAddr;
+
+	u8 *bulk_out_buffer;
+	int bulk_out_size;
+	u8 bulk_out_endpointAddr;
+
+	u8 CRC_OK;
+	u32 fwseqnum;
+	u32 lastseqnum;
+	u32 totalbytes;
+	u32 fwlastblksent;
+	u8 fwdnldover;
+	u8 fwfinalblk;
+
+	u32 usb_event_cause;
+	u8 usb_int_cause;
+
+	u8 rx_urb_recall;
+
+	u8 bootcmdresp;
+};
+
+/** fwheader */
+struct fwheader {
+	u32 dnldcmd;
+	u32 baseaddr;
+	u32 datalength;
+	u32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE	600
+/** FWData */
+struct FWData {
+	struct fwheader fwheader;
+	u32 seqnum;
+	u8 data[FW_MAX_DATA_BLK_SIZE];
+};
+
+/** fwsyncheader */
+struct fwsyncheader {
+	u32 cmd;
+	u32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV		0x00000001
+#define FW_HAS_LAST_BLOCK		0x00000004
+
+#define FW_DATA_XMIT_SIZE \
+	sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32)
+
+int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+void if_usb_free(struct usb_card_rec *cardp);
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644
index 0000000..82b3964
--- /dev/null
+++ b/drivers/net/wireless/libertas/ioctl.c
@@ -0,0 +1,2500 @@
+/**
+  * This file contains ioctl functions
+  */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+				IW_ESSID_MAX_SIZE + \
+				IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+				IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+				IW_EV_PARAM_LEN + 40)	/* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int setrxantenna(wlan_private * priv, int mode)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2
+	    && mode != RF_ANTENNA_AUTO) {
+		return -EINVAL;
+	}
+
+	adapter->rxantennamode = mode;
+
+	lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_set_rx,
+				    cmd_option_waitforrsp, 0,
+				    &adapter->rxantennamode);
+	return ret;
+}
+
+static int settxantenna(wlan_private * priv, int mode)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2)
+	    && (mode != RF_ANTENNA_AUTO)) {
+		return -EINVAL;
+	}
+
+	adapter->txantennamode = mode;
+
+	lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_set_tx,
+				    cmd_option_waitforrsp, 0,
+				    &adapter->txantennamode);
+
+	return ret;
+}
+
+static int getrxantenna(wlan_private * priv, char *buf)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	// clear it, so we will know if the value
+	// returned below is correct or not.
+	adapter->rxantennamode = 0;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_get_rx,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
+
+	return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
+}
+
+static int gettxantenna(wlan_private * priv, char *buf)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	// clear it, so we will know if the value
+	// returned below is correct or not.
+	adapter->txantennamode = 0;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_get_tx,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
+
+	return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
+}
+
+static int wlan_set_region(wlan_private * priv, u16 region_code)
+{
+	int i;
+
+	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+		// use the region code to search for the index
+		if (region_code == libertas_region_code_to_index[i]) {
+			priv->adapter->regiontableindex = (u16) i;
+			priv->adapter->regioncode = region_code;
+			break;
+		}
+	}
+
+	// if it's unidentified region code
+	if (i >= MRVDRV_MAX_REGION_CODE) {
+		lbs_pr_debug(1, "region Code not identified\n");
+		LEAVE();
+		return -1;
+	}
+
+	if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *  @brief Get/Set Firmware wakeup method
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	0--success, otherwise fail
+ */
+static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int data;
+	ENTER();
+
+	if ((int)wrq->u.data.length == 0) {
+		if (copy_to_user
+		    (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) {
+			lbs_pr_alert("copy_to_user failed!\n");
+			return -EFAULT;
+		}
+	} else {
+		if ((int)wrq->u.data.length > 1) {
+			lbs_pr_alert("ioctl too many args!\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_alert("Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->pkttxctrl = (u32) data;
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Get/Set NULL Package generation interval
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	0--success, otherwise fail
+ */
+static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int data;
+	ENTER();
+
+	if ((int)wrq->u.data.length == 0) {
+		data = adapter->nullpktinterval;
+
+		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+			lbs_pr_alert( "copy_to_user failed!\n");
+			return -EFAULT;
+		}
+	} else {
+		if ((int)wrq->u.data.length > 1) {
+			lbs_pr_alert( "ioctl too many args!\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->nullpktinterval = data;
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int data[2];
+	ENTER();
+	data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+	data[1] = adapter->rxpd_rate;
+	if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+		lbs_pr_debug(1, "Copy to user failed\n");
+		return -EFAULT;
+	}
+	wrq->u.data.length = 2;
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	int data[4];
+
+	ENTER();
+	memset(data, 0, sizeof(data));
+	if (wrq->u.data.length) {
+		if (copy_from_user(data, wrq->u.data.pointer,
+		     min_t(size_t, wrq->u.data.length, 4) * sizeof(int)))
+			return -EFAULT;
+	}
+	if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+		if (adapter->connect_status == libertas_connected) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_rssi,
+						    0,
+						    cmd_option_waitforrsp,
+						    0, NULL);
+
+			if (ret) {
+				LEAVE();
+				return ret;
+			}
+		}
+	}
+
+	if (wrq->u.data.length == 0) {
+		data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+		data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+		data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+		data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4))
+			return -EFAULT;
+		wrq->u.data.length = 4;
+	} else if (data[0] == 0) {
+		data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+			return -EFAULT;
+		wrq->u.data.length = 1;
+	} else if (data[0] == 1) {
+		data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+			return -EFAULT;
+		wrq->u.data.length = 1;
+	} else if (data[0] == 2) {
+		data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+			return -EFAULT;
+		wrq->u.data.length = 1;
+	} else if (data[0] == 3) {
+		data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+			return -EFAULT;
+		wrq->u.data.length = 1;
+	} else
+		return -ENOTSUPP;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+	int data;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (wrq->u.data.length > 0) {
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
+			return -EFAULT;
+
+		lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data);
+		if ((data > MRVDRV_MAX_BEACON_INTERVAL)
+		    || (data < MRVDRV_MIN_BEACON_INTERVAL))
+			return -ENOTSUPP;
+		adapter->beaconperiod = data;
+	}
+	data = adapter->beaconperiod;
+	if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int)))
+		return -EFAULT;
+
+	wrq->u.data.length = 1;
+
+	return 0;
+}
+
+static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	int temp;
+	int data = 0;
+	int *val;
+
+	ENTER();
+	data = SUBCMD_DATA(wrq);
+	if ((data == 0) || (data == 1)) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rssi,
+					    0, cmd_option_waitforrsp,
+					    0, NULL);
+		if (ret) {
+			LEAVE();
+			return ret;
+		}
+	}
+
+	switch (data) {
+	case 0:
+
+		temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+				adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+		break;
+	case 1:
+		temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG],
+				adapter->NF[TYPE_BEACON][TYPE_AVG]);
+		break;
+	case 2:
+		temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+				adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+		break;
+	case 3:
+		temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+				adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+	val = (int *)wrq->u.name;
+	*val = temp;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	int temp;
+	int data = 0;
+	int *val;
+
+	data = SUBCMD_DATA(wrq);
+	if ((data == 0) || (data == 1)) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rssi,
+					    0, cmd_option_waitforrsp,
+					    0, NULL);
+
+		if (ret) {
+			LEAVE();
+			return ret;
+		}
+	}
+
+	switch (data) {
+	case 0:
+		temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+		break;
+	case 1:
+		temp = adapter->NF[TYPE_BEACON][TYPE_AVG];
+		break;
+	case 2:
+		temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+		break;
+	case 3:
+		temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	temp = CAL_NF(temp);
+
+	lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
+	val = (int *)wrq->u.name;
+	*val = temp;
+	return 0;
+}
+
+static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int *pdata;
+	struct iwreq *wrq = (struct iwreq *)req;
+	int ret = 0;
+	adapter->txrate = 0;
+	lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
+				    cmd_act_get, cmd_option_waitforrsp,
+				    0, NULL);
+	if (ret)
+		return ret;
+
+	pdata = (int *)wrq->u.name;
+	*pdata = (int)adapter->txrate;
+	return 0;
+}
+
+static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	char status[64];
+	wlan_adapter *adapter = priv->adapter;
+
+	memset(status, 0, sizeof(status));
+
+	switch (adapter->inframode) {
+	case wlan802_11ibss:
+		if (adapter->connect_status == libertas_connected) {
+			if (adapter->adhoccreate)
+				memcpy(&status, "AdhocStarted", sizeof(status));
+			else
+				memcpy(&status, "AdhocJoined", sizeof(status));
+		} else {
+			memcpy(&status, "AdhocIdle", sizeof(status));
+		}
+		break;
+	case wlan802_11infrastructure:
+		memcpy(&status, "Inframode", sizeof(status));
+		break;
+	default:
+		memcpy(&status, "AutoUnknownmode", sizeof(status));
+		break;
+	}
+
+	lbs_pr_debug(1, "status = %s\n", status);
+	wrq->u.data.length = strlen(status) + 1;
+
+	if (wrq->u.data.pointer) {
+		if (copy_to_user(wrq->u.data.pointer,
+				 &status, wrq->u.data.length))
+			return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Set/Get WPA IE
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	if (wrq->u.data.length) {
+		if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
+			lbs_pr_debug(1, "failed to copy WPA IE, too big \n");
+			return -EFAULT;
+		}
+		if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer,
+				   wrq->u.data.length)) {
+			lbs_pr_debug(1, "failed to copy WPA IE \n");
+			return -EFAULT;
+		}
+		adapter->wpa_ie_len = wrq->u.data.length;
+		lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
+		       adapter->wpa_ie[0]);
+		lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len);
+		if (adapter->wpa_ie[0] == WPA_IE)
+			adapter->secinfo.WPAenabled = 1;
+		else if (adapter->wpa_ie[0] == WPA2_IE)
+			adapter->secinfo.WPA2enabled = 1;
+		else {
+			adapter->secinfo.WPAenabled = 0;
+			adapter->secinfo.WPA2enabled = 0;
+		}
+	} else {
+		memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie));
+		adapter->wpa_ie_len = wrq->u.data.length;
+		lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n",
+		       adapter->wpa_ie_len, adapter->wpa_ie[0]);
+		adapter->secinfo.WPAenabled = 0;
+		adapter->secinfo.WPA2enabled = 0;
+	}
+
+	// enable/disable RSN in firmware if WPA is enabled/disabled
+	// depending on variable adapter->secinfo.WPAenabled is set or not
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn,
+				    cmd_act_set, cmd_option_waitforrsp,
+				    0, NULL);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set Auto prescan
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	int data;
+	wlan_adapter *adapter = priv->adapter;
+	int *val;
+
+	data = SUBCMD_DATA(wrq);
+	lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
+	adapter->prescan = data;
+
+	val = (int *)wrq->u.name;
+	*val = data;
+	return 0;
+}
+
+static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	u32 mdtim;
+	int idata;
+	int ret = -EINVAL;
+
+	ENTER();
+
+	idata = SUBCMD_DATA(wrq);
+	mdtim = (u32) idata;
+	if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
+	     && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+	    || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+		priv->adapter->multipledtim = mdtim;
+		ret = 0;
+	}
+	if (ret)
+		lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n");
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int alg;
+	struct iwreq *wrq = (struct iwreq *)req;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (wrq->u.data.flags == 0) {
+		//from iwpriv subcmd
+		alg = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+
+	lbs_pr_debug(1, "auth alg is %#x\n", alg);
+
+	switch (alg) {
+	case AUTH_ALG_SHARED_KEY:
+		adapter->secinfo.authmode = wlan802_11authmodeshared;
+		break;
+	case AUTH_ALG_NETWORK_EAP:
+		adapter->secinfo.authmode =
+		    wlan802_11authmodenetworkEAP;
+		break;
+	case AUTH_ALG_OPEN_SYSTEM:
+	default:
+		adapter->secinfo.authmode = wlan802_11authmodeopen;
+		break;
+	}
+	return 0;
+}
+
+/**
+ *  @brief Set 802.1x authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int alg;
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	if (wrq->u.data.flags == 0) {
+		//from iwpriv subcmd
+		alg = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+	lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
+	priv->adapter->secinfo.auth1xalg = alg;
+	return 0;
+}
+
+static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int mode;
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	ENTER();
+
+	if (wrq->u.data.flags == 0) {
+		//from iwpriv subcmd
+		mode = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+	lbs_pr_debug(1, "encryption mode is %#x\n", mode);
+	priv->adapter->secinfo.Encryptionmode = mode;
+
+	LEAVE();
+	return 0;
+}
+
+static void adjust_mtu(wlan_private * priv)
+{
+	int mtu_increment = 0;
+
+	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+		mtu_increment += sizeof(struct ieee80211_hdr_4addr);
+
+	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
+		mtu_increment += max(sizeof(struct tx_radiotap_hdr),
+				     sizeof(struct rx_radiotap_hdr));
+	priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
+	    - sizeof(struct ethhdr)
+	    + mtu_increment;
+}
+
+/**
+ *  @brief Set Link-Layer Layer mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int mode;
+
+	mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+	switch (mode) {
+	case WLAN_LINKMODE_802_3:
+		priv->adapter->linkmode = mode;
+		break;
+	case WLAN_LINKMODE_802_11:
+		priv->adapter->linkmode = mode;
+		break;
+	default:
+		lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
+		       mode);
+		return -EINVAL;
+		break;
+	}
+	lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
+
+	adjust_mtu(priv);
+
+	return 0;
+}
+
+/**
+ *  @brief Set Radio header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int mode;
+
+	mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+	switch (mode) {
+	case WLAN_RADIOMODE_NONE:
+		priv->adapter->radiomode = mode;
+		break;
+	case WLAN_RADIOMODE_RADIOTAP:
+		priv->adapter->radiomode = mode;
+		break;
+	default:
+		lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
+		       mode);
+		return -EINVAL;
+	}
+	lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
+
+	adjust_mtu(priv);
+	return 0;
+}
+
+/**
+ *  @brief Set Debug header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	priv->adapter->debugmode = (int)((struct ifreq *)
+					 ((u8 *) req + 4))->ifr_data;
+	return 0;
+}
+
+static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
+					  struct ifreq *req)
+{
+	int len;
+	char buf[8];
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n");
+	len = getrxantenna(priv, buf);
+
+	wrq->u.data.length = len;
+	if (wrq->u.data.pointer) {
+		if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+			lbs_pr_debug(1, "CopyToUser failed\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
+					  struct ifreq *req)
+{
+	int len;
+	char buf[8];
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n");
+	len = gettxantenna(priv, buf);
+
+	wrq->u.data.length = len;
+	if (wrq->u.data.pointer) {
+		if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+			lbs_pr_debug(1, "CopyToUser failed\n");
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+/**
+ *  @brief Get the MAC TSF value from the firmware
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param wrq          A pointer to iwreq structure containing buffer
+ *                      space to store a TSF value retrieved from the firmware
+ *
+ *  @return             0 if successful; IOCTL error code otherwise
+ */
+static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	u64 tsfval;
+	int ret;
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_get_tsf,
+				    0, cmd_option_waitforrsp, 0, &tsfval);
+
+	lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
+
+	if (ret != 0) {
+		lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n");
+		ret = -EFAULT;
+	} else {
+		if (copy_to_user(wrq->u.data.pointer,
+				 &tsfval,
+				 min_t(size_t, wrq->u.data.length,
+				     sizeof(tsfval))) != 0) {
+
+			lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
+			ret = -EFAULT;
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+/**
+ *  @brief Get/Set adapt rate
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+	int data[2];
+
+	memset(data, 0, sizeof(data));
+	if (!wrq->u.data.length) {
+		lbs_pr_debug(1, "Get ADAPT RATE SET\n");
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rate_adapt_rateset,
+					    cmd_act_get,
+					    cmd_option_waitforrsp, 0, NULL);
+		data[0] = adapter->enablehwauto;
+		data[1] = adapter->ratebitmap;
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+#define GET_TWO_INT	2
+		wrq->u.data.length = GET_TWO_INT;
+	} else {
+		lbs_pr_debug(1, "Set ADAPT RATE SET\n");
+		if (wrq->u.data.length > 2)
+			return -EINVAL;
+		if (copy_from_user
+		    (data, wrq->u.data.pointer,
+		     sizeof(int) * wrq->u.data.length)) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->enablehwauto = data[0];
+		adapter->ratebitmap = data[1];
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rate_adapt_rateset,
+					    cmd_act_set,
+					    cmd_option_waitforrsp, 0, NULL);
+	}
+	return ret;
+}
+
+/**
+ *  @brief Get/Set inactivity timeout
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret;
+	int data = 0;
+	u16 timeout = 0;
+
+	ENTER();
+	if (wrq->u.data.length > 1)
+		return -ENOTSUPP;
+
+	if (wrq->u.data.length == 0) {
+		/* Get */
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_inactivity_timeout,
+					    cmd_act_get,
+					    cmd_option_waitforrsp, 0,
+					    &timeout);
+		data = timeout;
+		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+	} else {
+		/* Set */
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		timeout = data;
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_inactivity_timeout,
+					    cmd_act_set,
+					    cmd_option_waitforrsp, 0,
+					    &timeout);
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret;
+	char buf[GETLOG_BUFSIZE - 1];
+	wlan_adapter *adapter = priv->adapter;
+
+	lbs_pr_debug(1, " GET STATS\n");
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
+				    0, cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		return ret;
+	}
+
+	if (wrq->u.data.pointer) {
+		sprintf(buf, "\n  mcasttxframe %u failed %u retry %u "
+			"multiretry %u framedup %u "
+			"rtssuccess %u rtsfailure %u ackfailure %u\n"
+			"rxfrag %u mcastrxframe %u fcserror %u "
+			"txframe %u wepundecryptable %u ",
+			adapter->logmsg.mcasttxframe,
+			adapter->logmsg.failed,
+			adapter->logmsg.retry,
+			adapter->logmsg.multiretry,
+			adapter->logmsg.framedup,
+			adapter->logmsg.rtssuccess,
+			adapter->logmsg.rtsfailure,
+			adapter->logmsg.ackfailure,
+			adapter->logmsg.rxfrag,
+			adapter->logmsg.mcastrxframe,
+			adapter->logmsg.fcserror,
+			adapter->logmsg.txframe,
+			adapter->logmsg.wepundecryptable);
+		wrq->u.data.length = strlen(buf) + 1;
+		if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	u8 buf[12];
+	u8 *option[] = { "active", "passive", "get", };
+	int i, max_options = (sizeof(option) / sizeof(option[0]));
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (priv->adapter->enable11d) {
+		lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n");
+		return -EFAULT;
+	}
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+							 wrq->u.data.length)))
+		return -EFAULT;
+
+	lbs_pr_debug(1, "Scan type Option = %s\n", buf);
+
+	buf[sizeof(buf) - 1] = '\0';
+
+	for (i = 0; i < max_options; i++) {
+		if (!strcmp(buf, option[i]))
+			break;
+	}
+
+	switch (i) {
+	case 0:
+		adapter->scantype = cmd_scan_type_active;
+		break;
+	case 1:
+		adapter->scantype = cmd_scan_type_passive;
+		break;
+	case 2:
+		wrq->u.data.length = strlen(option[adapter->scantype]) + 1;
+
+		if (copy_to_user(wrq->u.data.pointer,
+				 option[adapter->scantype],
+				 wrq->u.data.length)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			ret = -EFAULT;
+		}
+
+		break;
+	default:
+		lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	wlan_adapter *adapter = priv->adapter;
+	u8 buf[12];
+	u8 *option[] = { "bss", "ibss", "any", "get" };
+	int i, max_options = (sizeof(option) / sizeof(option[0]));
+	int ret = 0;
+
+	ENTER();
+
+	memset(buf, 0, sizeof(buf));
+
+	if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+							 wrq->u.data.length))) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		return -EFAULT;
+	}
+
+	lbs_pr_debug(1, "Scan mode Option = %s\n", buf);
+
+	buf[sizeof(buf) - 1] = '\0';
+
+	for (i = 0; i < max_options; i++) {
+		if (!strcmp(buf, option[i]))
+			break;
+	}
+
+	switch (i) {
+
+	case 0:
+		adapter->scanmode = cmd_bss_type_bss;
+		break;
+	case 1:
+		adapter->scanmode = cmd_bss_type_ibss;
+		break;
+	case 2:
+		adapter->scanmode = cmd_bss_type_any;
+		break;
+	case 3:
+
+		wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
+
+		lbs_pr_debug(1, "Get Scan mode Option = %s\n",
+		       option[adapter->scanmode - 1]);
+
+		lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length);
+
+		if (copy_to_user(wrq->u.data.pointer,
+				 option[adapter->scanmode - 1],
+				 wrq->u.data.length)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			ret = -EFAULT;
+		}
+		lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
+		       (char *)wrq->u.data.pointer);
+
+		break;
+
+	default:
+		lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Get/Set Adhoc G Rate
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	0--success, otherwise fail
+ */
+static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int data, data1;
+	int *val;
+
+	ENTER();
+
+	data1 = SUBCMD_DATA(wrq);
+	switch (data1) {
+	case 0:
+		adapter->adhoc_grate_enabled = 0;
+		break;
+	case 1:
+		adapter->adhoc_grate_enabled = 1;
+		break;
+	case 2:
+		break;
+	default:
+		return -EINVAL;
+	}
+	data = adapter->adhoc_grate_enabled;
+	val = (int *)wrq->u.name;
+	*val = data;
+	LEAVE();
+	return 0;
+}
+
+static inline int hex2int(char c)
+{
+	if (c >= '0' && c <= '9')
+		return (c - '0');
+	if (c >= 'a' && c <= 'f')
+		return (c - 'a' + 10);
+	if (c >= 'A' && c <= 'F')
+		return (c - 'A' + 10);
+	return -1;
+}
+
+/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
+   into binary format (6 bytes).
+
+   This function expects that each byte is represented with 2 characters
+   (e.g., 11:2:11:11:11:11 is invalid)
+
+ */
+static char *eth_str2addr(char *ethstr, u8 * addr)
+{
+	int i, val, val2;
+	char *pos = ethstr;
+
+	/* get rid of initial blanks */
+	while (*pos == ' ' || *pos == '\t')
+		++pos;
+
+	for (i = 0; i < 6; i++) {
+		val = hex2int(*pos++);
+		if (val < 0)
+			return NULL;
+		val2 = hex2int(*pos++);
+		if (val2 < 0)
+			return NULL;
+		addr[i] = (val * 16 + val2) & 0xff;
+
+		if (i < 5 && *pos++ != ':')
+			return NULL;
+	}
+	return pos;
+}
+
+/* this writes xx:xx:xx:xx:xx:xx into ethstr
+   (ethstr must have space for 18 chars) */
+static int eth_addr2str(u8 * addr, char *ethstr)
+{
+	int i;
+	char *pos = ethstr;
+
+	for (i = 0; i < 6; i++) {
+		sprintf(pos, "%02x", addr[i] & 0xff);
+		pos += 2;
+		if (i < 5)
+			*pos++ = ':';
+	}
+	return 17;
+}
+
+/**
+ *  @brief          Add an entry to the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char ethaddrs_str[18];
+	char *pos;
+	u8 ethaddr[ETH_ALEN];
+
+	ENTER();
+	if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+			   sizeof(ethaddrs_str)))
+		return -EFAULT;
+
+	if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+		lbs_pr_info("BT_ADD: Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+	lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv, cmd_bt_access,
+				      cmd_act_bt_access_add,
+				      cmd_option_waitforrsp, 0, ethaddr));
+}
+
+/**
+ *  @brief          Delete an entry from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char ethaddrs_str[18];
+	u8 ethaddr[ETH_ALEN];
+	char *pos;
+
+	ENTER();
+	if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+			   sizeof(ethaddrs_str)))
+		return -EFAULT;
+
+	if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+		lbs_pr_info("Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+	lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_bt_access,
+				      cmd_act_bt_access_del,
+				      cmd_option_waitforrsp, 0, ethaddr));
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_reset_ioctl(wlan_private * priv)
+{
+	ENTER();
+
+	lbs_pr_alert( "BT: resetting\n");
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_bt_access,
+				      cmd_act_bt_access_reset,
+				      cmd_option_waitforrsp, 0, NULL));
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int pos;
+	char *addr1;
+	struct iwreq *wrq = (struct iwreq *)req;
+	/* used to pass id and store the bt entry returned by the FW */
+	union {
+		int id;
+		char addr1addr2[2 * ETH_ALEN];
+	} param;
+	static char outstr[64];
+	char *pbuf = outstr;
+	int ret;
+
+	ENTER();
+
+	if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		return -1;
+	}
+	param.id = simple_strtoul(outstr, NULL, 10);
+	pos = sprintf(pbuf, "%d: ", param.id);
+	pbuf += pos;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
+				    cmd_act_bt_access_list,
+				    cmd_option_waitforrsp, 0,
+				    (char *)&param);
+
+	if (ret == 0) {
+		addr1 = param.addr1addr2;
+
+		pos = sprintf(pbuf, "ignoring traffic from ");
+		pbuf += pos;
+		pos = eth_addr2str(addr1, pbuf);
+		pbuf += pos;
+	} else {
+		sprintf(pbuf, "(null)");
+		pbuf += pos;
+	}
+
+	wrq->u.data.length = strlen(outstr);
+	if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Find the next parameter in an input string
+ *  @param ptr      A pointer to the input parameter string
+ *  @return         A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+	if (!ptr) return NULL;
+	while (*ptr == ' ' || *ptr == '\t') ++ptr;
+	return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ *  @brief          Add an entry to the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[128];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+		lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.metric =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.metric = FWT_DEFAULT_METRIC;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.dir = FWT_DEFAULT_DIR;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.ssn =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.ssn = FWT_DEFAULT_SSN;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dsn =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.dsn = FWT_DEFAULT_DSN;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.ttl = FWT_DEFAULT_TTL;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.expiration =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.snr =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.snr = FWT_DEFAULT_SNR;
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18], ethaddr2_str[18];
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		eth_addr2str(fwt_access.ra, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+		       fwt_access.dir, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+		       fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+		       fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+		       fwt_access.sleepmode, fwt_access.snr);
+	}
+#endif
+
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
+						  cmd_act_fwt_access_add,
+						  cmd_option_waitforrsp, 0,
+						  (void *)&fwt_access));
+}
+
+/**
+ *  @brief          Delete an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+		lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18], ethaddr2_str[18];
+		lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		eth_addr2str(fwt_access.ra, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+		       ethaddr2_str, fwt_access.dir);
+	}
+#endif
+
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv,
+						  cmd_fwt_access,
+						  cmd_act_fwt_access_del,
+						  cmd_option_waitforrsp, 0,
+						  (void *)&fwt_access));
+}
+
+
+/**
+ *  @brief             Print route parameters
+ *  @param fwt_access  struct cmd_ds_fwt_access with route info
+ *  @param buf         destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+	buf += sprintf(buf, " ");
+	buf += eth_addr2str(fwt_access.da, buf);
+	buf += sprintf(buf, " ");
+	buf += eth_addr2str(fwt_access.ra, buf);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+	buf += sprintf(buf, " %u", fwt_access.dir);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+	buf += sprintf(buf, " %u", fwt_access.hopcount);
+	buf += sprintf(buf, " %u", fwt_access.ttl);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+	buf += sprintf(buf, " %u", fwt_access.sleepmode);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
+}
+
+/**
+ *  @brief          Lookup an entry in the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	char *ptr;
+	static struct cmd_ds_fwt_access fwt_access;
+	static char out_str[128];
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18];
+		lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv,
+						cmd_fwt_access,
+						cmd_act_fwt_access_lookup,
+						cmd_option_waitforrsp, 0,
+						(void *)&fwt_access);
+
+	if (ret == 0)
+		print_route(fwt_access, out_str);
+	else
+		sprintf(out_str, "(null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_reset_ioctl(wlan_private * priv)
+{
+	lbs_pr_debug(1, "FWT: resetting\n");
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_fwt_access,
+				      cmd_act_fwt_access_reset,
+				      cmd_option_waitforrsp, 0, NULL));
+}
+
+/**
+ *  @brief          List an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[8];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list,
+				    cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+	if (ret == 0)
+		print_route(fwt_access, pbuf);
+	else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the FRT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list_route,
+				    cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+	if (ret == 0) {
+		pbuf += sprintf(pbuf, " ");
+		pbuf += eth_addr2str(fwt_access.da, pbuf);
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
+		pbuf += sprintf(pbuf, " %u", fwt_access.dir);
+		/* note that the firmware returns the nid in the id field */
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
+		pbuf += sprintf(pbuf, "  hop %u", fwt_access.hopcount);
+		pbuf += sprintf(pbuf, "  ttl %u", fwt_access.ttl);
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
+	} else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the FNT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[8];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list_neighbor,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0) {
+		pbuf += sprintf(pbuf, " ra ");
+		pbuf += eth_addr2str(fwt_access.ra, pbuf);
+		pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
+		pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
+		pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
+	} else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
+ *                  (Garbage Collection)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	static struct cmd_ds_fwt_access fwt_access;
+	int ret;
+
+	ENTER();
+
+	lbs_pr_debug(1, "FWT: cleaning up\n");
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_cleanup,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0)
+		req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets firmware internal time (debug purposes)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	static struct cmd_ds_fwt_access fwt_access;
+	int ret;
+
+	ENTER();
+
+	lbs_pr_debug(1, "FWT: getting time\n");
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_time,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0)
+		req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+
+	ENTER();
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+				    cmd_act_mesh_get_ttl,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&mesh_access);
+
+	if (ret == 0) {
+		req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
+	}
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ttl      New ttl value
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
+{
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+
+	ENTER();
+
+	if( (ttl > 0xff) || (ttl < 0) )
+		return -EINVAL;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	mesh_access.data[0] = ttl;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+						cmd_act_mesh_set_ttl,
+						cmd_option_waitforrsp, 0,
+						(void *)&mesh_access);
+
+	if (ret != 0)
+		ret = -EFAULT;
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief ioctl function - entry point
+ *
+ *  @param dev		A pointer to net_device structure
+ *  @param req	   	A pointer to ifreq structure
+ *  @param cmd 		command
+ *  @return 	   	0--success, otherwise fail
+ */
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+	int subcmd = 0;
+	int idata = 0;
+	int *pdata;
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	ENTER();
+
+	lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+	switch (cmd) {
+	case WLANSCAN_TYPE:
+		lbs_pr_debug(1, "Scan type Ioctl\n");
+		ret = wlan_scan_type_ioctl(priv, wrq);
+		break;
+
+	case WLAN_SETNONE_GETNONE:	/* set WPA mode on/off ioctl #20 */
+		switch (wrq->u.data.flags) {
+		case WLANDEAUTH:
+			lbs_pr_debug(1, "Deauth\n");
+			libertas_send_deauth(priv);
+			break;
+
+		case WLANADHOCSTOP:
+			lbs_pr_debug(1, "Adhoc stop\n");
+			ret = libertas_do_adhocstop_ioctl(priv);
+			break;
+
+		case WLANRADIOON:
+			wlan_radio_ioctl(priv, 1);
+			break;
+
+		case WLANRADIOOFF:
+			wlan_radio_ioctl(priv, 0);
+			break;
+		case WLANWLANIDLEON:
+			libertas_idle_on(priv);
+			break;
+		case WLANWLANIDLEOFF:
+			libertas_idle_off(priv);
+			break;
+		case WLAN_SUBCMD_BT_RESET:	/* bt_reset */
+			wlan_bt_reset_ioctl(priv);
+			break;
+		case WLAN_SUBCMD_FWT_RESET:	/* fwt_reset */
+			wlan_fwt_reset_ioctl(priv);
+			break;
+		}		/* End of switch */
+		break;
+
+	case WLANSETWPAIE:
+		ret = wlan_setwpaie_ioctl(priv, req);
+		break;
+	case WLAN_SETINT_GETINT:
+		/* The first 4 bytes of req->ifr_data is sub-ioctl number
+		 * after 4 bytes sits the payload.
+		 */
+		subcmd = (int)req->ifr_data;	//from iwpriv subcmd
+		switch (subcmd) {
+		case WLANNF:
+			ret = wlan_get_nf(priv, wrq);
+			break;
+		case WLANRSSI:
+			ret = wlan_get_rssi(priv, wrq);
+			break;
+		case WLANENABLE11D:
+			ret = libertas_cmd_enable_11d(priv, wrq);
+			break;
+		case WLANADHOCGRATE:
+			ret = wlan_do_set_grate_ioctl(priv, wrq);
+			break;
+		case WLAN_SUBCMD_SET_PRESCAN:
+			ret = wlan_subcmd_setprescan_ioctl(priv, wrq);
+			break;
+		}
+		break;
+
+	case WLAN_SETONEINT_GETONEINT:
+		switch (wrq->u.data.flags) {
+		case WLAN_BEACON_INTERVAL:
+			ret = wlan_beacon_interval(priv, wrq);
+			break;
+
+		case WLAN_LISTENINTRVL:
+			if (!wrq->u.data.length) {
+				int data;
+				lbs_pr_debug(1, "Get locallisteninterval value\n");
+#define GET_ONE_INT	1
+				data = adapter->locallisteninterval;
+				if (copy_to_user(wrq->u.data.pointer,
+						 &data, sizeof(int))) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = GET_ONE_INT;
+			} else {
+				int data;
+				if (copy_from_user
+				    (&data, wrq->u.data.pointer, sizeof(int))) {
+					lbs_pr_debug(1, "Copy from user failed\n");
+					return -EFAULT;
+				}
+
+				lbs_pr_debug(1, "Set locallisteninterval = %d\n",
+				       data);
+#define MAX_U16_VAL	65535
+				if (data > MAX_U16_VAL) {
+					lbs_pr_debug(1, "Exceeds U16 value\n");
+					return -EINVAL;
+				}
+				adapter->locallisteninterval = data;
+			}
+			break;
+		case WLAN_TXCONTROL:
+			ret = wlan_txcontrol(priv, wrq);	//adds for txcontrol ioctl
+			break;
+
+		case WLAN_NULLPKTINTERVAL:
+			ret = wlan_null_pkt_interval(priv, wrq);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		break;
+
+	case WLAN_SETONEINT_GETNONE:
+		/* The first 4 bytes of req->ifr_data is sub-ioctl number
+		 * after 4 bytes sits the payload.
+		 */
+		subcmd = wrq->u.data.flags;	//from wpa_supplicant subcmd
+
+		if (!subcmd)
+			subcmd = (int)req->ifr_data;	//from iwpriv subcmd
+
+		switch (subcmd) {
+		case WLAN_SUBCMD_SETRXANTENNA:	/* SETRXANTENNA */
+			idata = SUBCMD_DATA(wrq);
+			ret = setrxantenna(priv, idata);
+			break;
+		case WLAN_SUBCMD_SETTXANTENNA:	/* SETTXANTENNA */
+			idata = SUBCMD_DATA(wrq);
+			ret = settxantenna(priv, idata);
+			break;
+		case WLAN_SET_ATIM_WINDOW:
+			adapter->atimwindow = SUBCMD_DATA(wrq);
+			adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
+			break;
+		case WLANSETBCNAVG:
+			adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
+			if (adapter->bcn_avg_factor == 0)
+				adapter->bcn_avg_factor =
+				    DEFAULT_BCN_AVG_FACTOR;
+			if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR)
+				adapter->bcn_avg_factor =
+				    DEFAULT_BCN_AVG_FACTOR;
+			break;
+		case WLANSETDATAAVG:
+			adapter->data_avg_factor = SUBCMD_DATA(wrq);
+			if (adapter->data_avg_factor == 0)
+				adapter->data_avg_factor =
+				    DEFAULT_DATA_AVG_FACTOR;
+			if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR)
+				adapter->data_avg_factor =
+				    DEFAULT_DATA_AVG_FACTOR;
+			break;
+		case WLANSETREGION:
+			idata = SUBCMD_DATA(wrq);
+			ret = wlan_set_region(priv, (u16) idata);
+			break;
+
+		case WLAN_SET_LISTEN_INTERVAL:
+			idata = SUBCMD_DATA(wrq);
+			adapter->listeninterval = (u16) idata;
+			break;
+
+		case WLAN_SET_MULTIPLE_DTIM:
+			ret = wlan_set_multiple_dtim_ioctl(priv, req);
+			break;
+
+		case WLANSETAUTHALG:
+			ret = wlan_setauthalg_ioctl(priv, req);
+			break;
+
+		case WLANSET8021XAUTHALG:
+			ret = wlan_set8021xauthalg_ioctl(priv, req);
+			break;
+
+		case WLANSETENCRYPTIONMODE:
+			ret = wlan_setencryptionmode_ioctl(priv, req);
+			break;
+
+		case WLAN_SET_LINKMODE:
+			ret = wlan_set_linkmode_ioctl(priv, req);
+			break;
+
+		case WLAN_SET_RADIOMODE:
+			ret = wlan_set_radiomode_ioctl(priv, req);
+			break;
+
+		case WLAN_SET_DEBUGMODE:
+			ret = wlan_set_debugmode_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_MESH_SET_TTL:
+			idata = SUBCMD_DATA(wrq);
+			ret = wlan_mesh_set_ttl_ioctl(priv, idata);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		break;
+
+	case WLAN_SETNONE_GETTWELVE_CHAR:	/* Get Antenna settings */
+		/*
+		 * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+		 * in flags of iwreq structure, otherwise it will be in
+		 * mode member of iwreq structure.
+		 */
+		switch ((int)wrq->u.data.flags) {
+		case WLAN_SUBCMD_GETRXANTENNA:	/* Get Rx Antenna */
+			ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_GETTXANTENNA:	/* Get Tx Antenna */
+			ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+			break;
+
+		case WLAN_GET_TSF:
+			ret = wlan_get_tsf_ioctl(priv, wrq);
+			break;
+		}
+		break;
+
+	case WLAN_SET128CHAR_GET128CHAR:
+		switch ((int)wrq->u.data.flags) {
+
+		case WLANSCAN_MODE:
+			lbs_pr_debug(1, "Scan mode Ioctl\n");
+			ret = wlan_scan_mode_ioctl(priv, wrq);
+			break;
+
+		case WLAN_GET_ADHOC_STATUS:
+			ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+			break;
+		case WLAN_SUBCMD_BT_ADD:
+			ret = wlan_bt_add_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_BT_DEL:
+			ret = wlan_bt_del_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_BT_LIST:
+			ret = wlan_bt_list_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_ADD:
+			ret = wlan_fwt_add_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_DEL:
+			ret = wlan_fwt_del_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LOOKUP:
+			ret = wlan_fwt_lookup_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
+			ret = wlan_fwt_list_neighbor_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST:
+			ret = wlan_fwt_list_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST_ROUTE:
+			ret = wlan_fwt_list_route_ioctl(priv, req);
+			break;
+		}
+		break;
+
+	case WLAN_SETNONE_GETONEINT:
+		switch ((int)req->ifr_data) {
+		case WLANGETBCNAVG:
+			pdata = (int *)wrq->u.name;
+			*pdata = (int)adapter->bcn_avg_factor;
+			break;
+
+		case WLANGETREGION:
+			pdata = (int *)wrq->u.name;
+			*pdata = (int)adapter->regioncode;
+			break;
+
+		case WLAN_GET_LISTEN_INTERVAL:
+			pdata = (int *)wrq->u.name;
+			*pdata = (int)adapter->listeninterval;
+			break;
+
+		case WLAN_GET_LINKMODE:
+			req->ifr_data = (char *)((u32) adapter->linkmode);
+			break;
+
+		case WLAN_GET_RADIOMODE:
+			req->ifr_data = (char *)((u32) adapter->radiomode);
+			break;
+
+		case WLAN_GET_DEBUGMODE:
+			req->ifr_data = (char *)((u32) adapter->debugmode);
+			break;
+
+		case WLAN_GET_MULTIPLE_DTIM:
+			pdata = (int *)wrq->u.name;
+			*pdata = (int)adapter->multipledtim;
+			break;
+		case WLAN_GET_TX_RATE:
+			ret = wlan_get_txrate_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_CLEANUP:	/* fwt_cleanup */
+			ret = wlan_fwt_cleanup_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_FWT_TIME:	/* fwt_time */
+			ret = wlan_fwt_time_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_MESH_GET_TTL:
+			ret = wlan_mesh_get_ttl_ioctl(priv, req);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+
+		}
+
+		break;
+
+	case WLANGETLOG:
+		ret = wlan_do_getlog_ioctl(priv, wrq);
+		break;
+
+	case WLAN_SET_GET_SIXTEEN_INT:
+		switch ((int)wrq->u.data.flags) {
+		case WLAN_TPCCFG:
+			{
+				int data[5];
+				struct cmd_ds_802_11_tpc_cfg cfg;
+				memset(&cfg, 0, sizeof(cfg));
+				if ((wrq->u.data.length > 1)
+				    && (wrq->u.data.length != 5))
+					return -1;
+
+				if (wrq->u.data.length == 0) {
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) * 5)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_set);
+					cfg.enable = data[0];
+					cfg.usesnr = data[1];
+					cfg.P0 = data[2];
+					cfg.P1 = data[3];
+					cfg.P2 = data[4];
+				}
+
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_tpc_cfg,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&cfg);
+
+				data[0] = cfg.enable;
+				data[1] = cfg.usesnr;
+				data[2] = cfg.P0;
+				data[3] = cfg.P1;
+				data[4] = cfg.P2;
+				if (copy_to_user
+				    (wrq->u.data.pointer, data,
+				     sizeof(int) * 5)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = 5;
+			}
+			break;
+
+		case WLAN_POWERCFG:
+			{
+				int data[4];
+				struct cmd_ds_802_11_pwr_cfg cfg;
+				memset(&cfg, 0, sizeof(cfg));
+				if ((wrq->u.data.length > 1)
+				    && (wrq->u.data.length != 4))
+					return -1;
+				if (wrq->u.data.length == 0) {
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) * 4)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_set);
+					cfg.enable = data[0];
+					cfg.PA_P0 = data[1];
+					cfg.PA_P1 = data[2];
+					cfg.PA_P2 = data[3];
+				}
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_pwr_cfg,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&cfg);
+				data[0] = cfg.enable;
+				data[1] = cfg.PA_P0;
+				data[2] = cfg.PA_P1;
+				data[3] = cfg.PA_P2;
+				if (copy_to_user
+				    (wrq->u.data.pointer, data,
+				     sizeof(int) * 4)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = 4;
+			}
+			break;
+		case WLAN_AUTO_FREQ_SET:
+			{
+				int data[3];
+				struct cmd_ds_802_11_afc afc;
+				memset(&afc, 0, sizeof(afc));
+				if (wrq->u.data.length != 3)
+					return -1;
+				if (copy_from_user
+				    (data, wrq->u.data.pointer,
+				     sizeof(int) * 3)) {
+					lbs_pr_debug(1, "Copy from user failed\n");
+					return -EFAULT;
+				}
+				afc.afc_auto = data[0];
+
+				if (afc.afc_auto != 0) {
+					afc.threshold = data[1];
+					afc.period = data[2];
+				} else {
+					afc.timing_offset = data[1];
+					afc.carrier_offset = data[2];
+				}
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_set_afc,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&afc);
+			}
+			break;
+		case WLAN_AUTO_FREQ_GET:
+			{
+				int data[3];
+				struct cmd_ds_802_11_afc afc;
+				memset(&afc, 0, sizeof(afc));
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_get_afc,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&afc);
+				data[0] = afc.afc_auto;
+				data[1] = afc.timing_offset;
+				data[2] = afc.carrier_offset;
+				if (copy_to_user
+				    (wrq->u.data.pointer, data,
+				     sizeof(int) * 3)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = 3;
+			}
+			break;
+		case WLAN_SCANPROBES:
+			{
+				int data;
+				if (wrq->u.data.length > 0) {
+					if (copy_from_user
+					    (&data, wrq->u.data.pointer,
+					     sizeof(int))) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					adapter->scanprobes = data;
+				} else {
+					data = adapter->scanprobes;
+					if (copy_to_user
+					    (wrq->u.data.pointer, &data,
+					     sizeof(int))) {
+						lbs_pr_debug(1,
+						       "Copy to user failed\n");
+						return -EFAULT;
+					}
+				}
+				wrq->u.data.length = 1;
+			}
+			break;
+		case WLAN_LED_GPIO_CTRL:
+			{
+				int i;
+				int data[16];
+
+				struct cmd_ds_802_11_led_ctrl ctrl;
+				struct mrvlietypes_ledgpio *gpio =
+				    (struct mrvlietypes_ledgpio *) ctrl.data;
+
+				memset(&ctrl, 0, sizeof(ctrl));
+				if (wrq->u.data.length > MAX_LEDS * 2)
+					return -ENOTSUPP;
+				if ((wrq->u.data.length % 2) != 0)
+					return -ENOTSUPP;
+				if (wrq->u.data.length == 0) {
+					ctrl.action =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) *
+					     wrq->u.data.length)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					ctrl.action =
+					    cpu_to_le16
+					    (cmd_act_set);
+					ctrl.numled = cpu_to_le16(0);
+					gpio->header.type =
+					    cpu_to_le16(TLV_TYPE_LED_GPIO);
+					gpio->header.len = wrq->u.data.length;
+					for (i = 0; i < wrq->u.data.length;
+					     i += 2) {
+						gpio->ledpin[i / 2].led =
+						    data[i];
+						gpio->ledpin[i / 2].pin =
+						    data[i + 1];
+					}
+				}
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_led_gpio_ctrl,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&ctrl);
+				for (i = 0; i < gpio->header.len; i += 2) {
+					data[i] = gpio->ledpin[i / 2].led;
+					data[i + 1] = gpio->ledpin[i / 2].pin;
+				}
+				if (copy_to_user(wrq->u.data.pointer, data,
+						 sizeof(int) *
+						 gpio->header.len)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = gpio->header.len;
+			}
+			break;
+		case WLAN_ADAPT_RATESET:
+			ret = wlan_adapt_rateset(priv, wrq);
+			break;
+		case WLAN_INACTIVITY_TIMEOUT:
+			ret = wlan_inactivity_timeout(priv, wrq);
+			break;
+		case WLANSNR:
+			ret = wlan_get_snr(priv, wrq);
+			break;
+		case WLAN_GET_RXINFO:
+			ret = wlan_get_rxinfo(priv, wrq);
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	LEAVE();
+	return ret;
+}
+
+
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644
index 0000000..11682cb
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.c
@@ -0,0 +1,1055 @@
+/**
+  *  Functions implementing wlan infrastructure and adhoc join routines,
+  *  IOCTL handlers as well as command preperation and response routines
+  *  for sending adhoc start, adhoc join, and association commands
+  *  to the firmware.
+  */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "join.h"
+#include "dev.h"
+
+/**
+ *  @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ *   care, either before or after calling this function
+ *
+ *  @param adapter     A pointer to wlan_adapter structure
+ *  @param rate1       the buffer which keeps input and output
+ *  @param rate1_size  the size of rate1 buffer
+ *  @param rate2       the buffer which keeps rate2
+ *  @param rate2_size  the size of rate2 buffer.
+ *
+ *  @return            0 or -1
+ */
+static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+			    int rate1_size, u8 * rate2, int rate2_size)
+{
+	u8 *ptr = rate1;
+	int ret = 0;
+	u8 tmp[30];
+	int i;
+
+	memset(&tmp, 0, sizeof(tmp));
+	memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
+	memset(rate1, 0, rate1_size);
+
+	/* Mask the top bit of the original values */
+	for (i = 0; tmp[i] && i < sizeof(tmp); i++)
+		tmp[i] &= 0x7F;
+
+	for (i = 0; rate2[i] && i < rate2_size; i++) {
+		/* Check for Card Rate in tmp, excluding the top bit */
+		if (strchr(tmp, rate2[i] & 0x7F)) {
+			/* values match, so copy the Card Rate to rate1 */
+			*rate1++ = rate2[i];
+		}
+	}
+
+	lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+	lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+	lbs_dbg_hex("Common rates:", ptr, rate1_size);
+	lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
+
+	if (!adapter->is_datarate_auto) {
+		while (*ptr) {
+			if ((*ptr & 0x7f) == adapter->datarate) {
+				ret = 0;
+				goto done;
+			}
+			ptr++;
+		}
+		lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+		       "compatible with the network.\n", adapter->datarate);
+
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	return ret;
+}
+
+int libertas_send_deauth(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->inframode == wlan802_11infrastructure &&
+	    adapter->connect_status == libertas_connected)
+		ret = libertas_send_deauthentication(priv);
+	else
+		ret = -ENOTSUPP;
+
+	return ret;
+}
+
+int libertas_do_adhocstop_ioctl(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->inframode == wlan802_11ibss &&
+	    adapter->connect_status == libertas_connected)
+		ret = libertas_stop_adhoc_network(priv);
+	else
+		ret = -ENOTSUPP;
+
+	return ret;
+}
+
+/**
+ *  @brief Associate to a specific BSS discovered in a scan
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
+ *
+ *  @return          0-success, otherwise fail
+ */
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+				    0, cmd_option_waitforrsp,
+				    0, pbssdesc->macaddress);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	/* set preamble to firmware */
+	if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
+		adapter->preamble = cmd_type_short_preamble;
+	else
+		adapter->preamble = cmd_type_long_preamble;
+
+	libertas_set_radio_control(priv);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+				    0, cmd_option_waitforrsp, 0, pbssdesc);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Start an Adhoc Network
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param adhocssid    The ssid of the Adhoc Network
+ *  @return             0--success, -1--fail
+ */
+int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	adapter->adhoccreate = 1;
+
+	if (!adapter->capinfo.shortpreamble) {
+		lbs_pr_debug(1, "AdhocStart: Long preamble\n");
+		adapter->preamble = cmd_type_long_preamble;
+	} else {
+		lbs_pr_debug(1, "AdhocStart: Short preamble\n");
+		adapter->preamble = cmd_type_short_preamble;
+	}
+
+	libertas_set_radio_control(priv);
+
+	lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
+	lbs_pr_debug(1, "curbssparams.channel = %d\n",
+	       adapter->curbssparams.channel);
+	lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+				    0, cmd_option_waitforrsp, 0, adhocssid);
+
+	return ret;
+}
+
+/**
+ *  @brief Join an adhoc network found in a previous scan
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
+ *                      to attempt to join
+ *
+ *  @return             0--success, -1--fail
+ */
+int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
+	       adapter->curbssparams.ssid.ssid);
+	lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
+	       adapter->curbssparams.ssid.ssidlength);
+	lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
+	lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n",
+	       pbssdesc->ssid.ssidlength);
+
+	/* check if the requested SSID is already joined */
+	if (adapter->curbssparams.ssid.ssidlength
+	    && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid)
+	    && (adapter->curbssparams.bssdescriptor.inframode ==
+		wlan802_11ibss)) {
+
+        lbs_pr_debug(1,
+		       "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+		       "not attempting to re-join");
+
+		return -1;
+	}
+
+	/*Use shortpreamble only when both creator and card supports
+	   short preamble */
+	if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+		lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
+		adapter->preamble = cmd_type_long_preamble;
+	} else {
+		lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
+		adapter->preamble = cmd_type_short_preamble;
+	}
+
+	libertas_set_radio_control(priv);
+
+	lbs_pr_debug(1, "curbssparams.channel = %d\n",
+	       adapter->curbssparams.channel);
+	lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
+
+	adapter->adhoccreate = 0;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+				    0, cmd_option_waitforrsp,
+				    OID_802_11_SSID, pbssdesc);
+
+	return ret;
+}
+
+int libertas_stop_adhoc_network(wlan_private * priv)
+{
+	return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+				     0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Send Deauthentication Request
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          0--success, -1--fail
+ */
+int libertas_send_deauthentication(wlan_private * priv)
+{
+	return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+				     0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Set Idle Off
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_off(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
+	int i;
+
+	ENTER();
+
+	if (adapter->connect_status == libertas_disconnected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			if (memcmp(adapter->previousbssid, zeromac,
+				   sizeof(zeromac)) != 0) {
+
+				lbs_pr_debug(1, "Previous SSID = %s\n",
+				       adapter->previousssid.ssid);
+				lbs_pr_debug(1, "Previous BSSID = "
+				       "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+				       adapter->previousbssid[0],
+				       adapter->previousbssid[1],
+				       adapter->previousbssid[2],
+				       adapter->previousbssid[3],
+				       adapter->previousbssid[4],
+				       adapter->previousbssid[5]);
+
+				i = libertas_find_SSID_in_list(adapter,
+						   &adapter->previousssid,
+						   adapter->previousbssid,
+						   adapter->inframode);
+
+				if (i < 0) {
+					libertas_send_specific_BSSID_scan(priv,
+							      adapter->
+							      previousbssid,
+							      1);
+					i = libertas_find_SSID_in_list(adapter,
+							   &adapter->
+							   previousssid,
+							   adapter->
+							   previousbssid,
+							   adapter->
+							   inframode);
+				}
+
+				if (i < 0) {
+					/* If the BSSID could not be found, try just the SSID */
+					i = libertas_find_SSID_in_list(adapter,
+							   &adapter->
+							   previousssid, NULL,
+							   adapter->
+							   inframode);
+				}
+
+				if (i < 0) {
+					libertas_send_specific_SSID_scan(priv,
+							     &adapter->
+							     previousssid,
+							     1);
+					i = libertas_find_SSID_in_list(adapter,
+							   &adapter->
+							   previousssid, NULL,
+							   adapter->
+							   inframode);
+				}
+
+				if (i >= 0) {
+					ret =
+					    wlan_associate(priv,
+							   &adapter->
+							   scantable[i]);
+				}
+			}
+		} else if (adapter->inframode == wlan802_11ibss) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_ad_hoc_start,
+						    0,
+						    cmd_option_waitforrsp,
+						    0, &adapter->previousssid);
+		}
+	}
+	/* else it is connected */
+
+	lbs_pr_debug(1, "\nwlanidle is off");
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set Idle On
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_on(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->connect_status == libertas_connected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			lbs_pr_debug(1, "Previous SSID = %s\n",
+			       adapter->previousssid.ssid);
+			memmove(&adapter->previousssid,
+				&adapter->curbssparams.ssid,
+				sizeof(struct WLAN_802_11_SSID));
+			libertas_send_deauth(priv);
+
+		} else if (adapter->inframode == wlan802_11ibss) {
+			ret = libertas_stop_adhoc_network(priv);
+		}
+
+	}
+
+	lbs_pr_debug(1, "\nwlanidle is on");
+
+	return ret;
+}
+
+/**
+ *  @brief This function prepares command of authenticate.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to cmd_ds_command structure
+ *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ *  @return         0 or -1
+ */
+int libertas_cmd_80211_authenticate(wlan_private * priv,
+				 struct cmd_ds_command *cmd,
+				 void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_authenticate *pauthenticate =
+	    &cmd->params.auth;
+	u8 *bssid = pdata_buf;
+
+	cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+			     + S_DS_GEN);
+
+	pauthenticate->authtype = adapter->secinfo.authmode;
+	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+	lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
+	       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+
+	return 0;
+}
+
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+				   struct cmd_ds_command *cmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+			     S_DS_GEN);
+
+	/* set AP MAC address */
+	memmove(dauth->macaddr, adapter->curbssparams.bssid,
+		ETH_ALEN);
+
+	/* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+	dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+	LEAVE();
+	return 0;
+}
+
+int libertas_cmd_80211_associate(wlan_private * priv,
+			      struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+	int ret = 0;
+	struct bss_descriptor *pbssdesc;
+	u8 *card_rates;
+	u8 *pos;
+	int card_rates_size;
+	u16 tmpcap;
+	struct mrvlietypes_ssidparamset *ssid;
+	struct mrvlietypes_phyparamset *phy;
+	struct mrvlietypes_ssparamset *ss;
+	struct mrvlietypes_ratesparamset *rates;
+	struct mrvlietypes_rsnparamset *rsn;
+
+	ENTER();
+
+	pbssdesc = pdata_buf;
+	pos = (u8 *) passo;
+
+	if (!adapter) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->command = cpu_to_le16(cmd_802_11_associate);
+
+	/* Save so we know which BSS Desc to use in the response handler */
+	adapter->pattemptedbssdesc = pbssdesc;
+
+	memcpy(passo->peerstaaddr,
+	       pbssdesc->macaddress, sizeof(passo->peerstaaddr));
+	pos += sizeof(passo->peerstaaddr);
+
+	/* set the listen interval */
+	passo->listeninterval = adapter->listeninterval;
+
+	pos += sizeof(passo->capinfo);
+	pos += sizeof(passo->listeninterval);
+	pos += sizeof(passo->bcnperiod);
+	pos += sizeof(passo->dtimperiod);
+
+	ssid = (struct mrvlietypes_ssidparamset *) pos;
+	ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+	ssid->header.len = pbssdesc->ssid.ssidlength;
+	memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
+	pos += sizeof(ssid->header) + ssid->header.len;
+	ssid->header.len = cpu_to_le16(ssid->header.len);
+
+	phy = (struct mrvlietypes_phyparamset *) pos;
+	phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+	phy->header.len = sizeof(phy->fh_ds.dsparamset);
+	memcpy(&phy->fh_ds.dsparamset,
+	       &pbssdesc->phyparamset.dsparamset.currentchan,
+	       sizeof(phy->fh_ds.dsparamset));
+	pos += sizeof(phy->header) + phy->header.len;
+	phy->header.len = cpu_to_le16(phy->header.len);
+
+	ss = (struct mrvlietypes_ssparamset *) pos;
+	ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+	ss->header.len = sizeof(ss->cf_ibss.cfparamset);
+	pos += sizeof(ss->header) + ss->header.len;
+	ss->header.len = cpu_to_le16(ss->header.len);
+
+	rates = (struct mrvlietypes_ratesparamset *) pos;
+	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+
+	memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
+
+	card_rates = libertas_supported_rates;
+	card_rates_size = sizeof(libertas_supported_rates);
+
+	if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
+			     card_rates, card_rates_size)) {
+		ret = -1;
+		goto done;
+	}
+
+	rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
+	adapter->curbssparams.numofrates = rates->header.len;
+
+	pos += sizeof(rates->header) + rates->header.len;
+	rates->header.len = cpu_to_le16(rates->header.len);
+
+	if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+		rsn = (struct mrvlietypes_rsnparamset *) pos;
+		rsn->header.type = (u16) adapter->wpa_ie[0];	/* WPA_IE or WPA2_IE */
+		rsn->header.type = cpu_to_le16(rsn->header.type);
+		rsn->header.len = (u16) adapter->wpa_ie[1];
+		memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
+		lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+			sizeof(rsn->header) + rsn->header.len);
+		pos += sizeof(rsn->header) + rsn->header.len;
+		rsn->header.len = cpu_to_le16(rsn->header.len);
+	}
+
+	/* update curbssparams */
+	adapter->curbssparams.channel =
+	    (pbssdesc->phyparamset.dsparamset.currentchan);
+
+	/* Copy the infra. association rates into Current BSS state structure */
+	memcpy(&adapter->curbssparams.datarates, &rates->rates,
+	       min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
+
+	lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
+
+	/* set IBSS field */
+	if (pbssdesc->inframode == wlan802_11infrastructure) {
+#define CAPINFO_ESS_MODE 1
+		passo->capinfo.ess = CAPINFO_ESS_MODE;
+	}
+
+	if (libertas_parse_dnld_countryinfo_11d(priv)) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+	/* set the capability info at last */
+	memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
+	tmpcap &= CAPINFO_MASK;
+	lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+	       tmpcap, CAPINFO_MASK);
+	tmpcap = cpu_to_le16(tmpcap);
+	memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+				 struct cmd_ds_command *cmd, void *pssid)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+	int ret = 0;
+	int cmdappendsize = 0;
+	int i;
+	u16 tmpcap;
+	struct bss_descriptor *pbssdesc;
+	struct WLAN_802_11_SSID *ssid = pssid;
+
+	ENTER();
+
+	if (!adapter) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+
+	pbssdesc = &adapter->curbssparams.bssdescriptor;
+	adapter->pattemptedbssdesc = pbssdesc;
+
+	/*
+	 * Fill in the parameters for 2 data structures:
+	 *   1. cmd_ds_802_11_ad_hoc_start command
+	 *   2. adapter->scantable[i]
+	 *
+	 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+	 *   probe delay, and cap info.
+	 *
+	 * Firmware will fill up beacon period, DTIM, Basic rates
+	 *   and operational rates.
+	 */
+
+	memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
+
+	memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+	memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
+	memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
+
+	pbssdesc->ssid.ssidlength = ssid->ssidlength;
+
+	/* set the BSS type */
+	adhs->bsstype = cmd_bss_type_ibss;
+	pbssdesc->inframode = wlan802_11ibss;
+	adhs->beaconperiod = adapter->beaconperiod;
+
+	/* set Physical param set */
+#define DS_PARA_IE_ID   3
+#define DS_PARA_IE_LEN  1
+
+	adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
+	adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
+
+	WARN_ON(!adapter->adhocchannel);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
+	       adapter->adhocchannel);
+
+	adapter->curbssparams.channel = adapter->adhocchannel;
+
+	pbssdesc->channel = adapter->adhocchannel;
+	adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
+
+	memcpy(&pbssdesc->phyparamset,
+	       &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+	/* set IBSS param set */
+#define IBSS_PARA_IE_ID   6
+#define IBSS_PARA_IE_LEN  2
+
+	adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+	adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+	adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
+	memcpy(&pbssdesc->ssparamset,
+	       &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+	/* set capability info */
+	adhs->cap.ess = 0;
+	adhs->cap.ibss = 1;
+	pbssdesc->cap.ibss = 1;
+
+	/* probedelay */
+	adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
+
+	/* set up privacy in adapter->scantable[i] */
+	if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+		lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
+		pbssdesc->privacy = wlan802_11privfilter8021xWEP;
+		adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+	} else {
+		lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
+		       "privacy to ACCEPT ALL\n");
+		pbssdesc->privacy = wlan802_11privfilteracceptall;
+	}
+
+	memset(adhs->datarate, 0, sizeof(adhs->datarate));
+
+	if (adapter->adhoc_grate_enabled) {
+		memcpy(adhs->datarate, libertas_adhoc_rates_g,
+		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
+	} else {
+		memcpy(adhs->datarate, libertas_adhoc_rates_b,
+		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
+	}
+
+	/* Find the last non zero */
+	for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+
+	adapter->curbssparams.numofrates = i;
+
+	/* Copy the ad-hoc creating rates into Current BSS state structure */
+	memcpy(&adapter->curbssparams.datarates,
+	       &adhs->datarate, adapter->curbssparams.numofrates);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+	       adhs->datarate[0], adhs->datarate[1],
+	       adhs->datarate[2], adhs->datarate[3]);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+	if (libertas_create_dnld_countryinfo_11d(priv)) {
+		lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
+			     + S_DS_GEN + cmdappendsize);
+
+	memcpy(&tmpcap, &adhs->cap, sizeof(u16));
+	tmpcap = cpu_to_le16(tmpcap);
+	memcpy(&adhs->cap, &tmpcap, sizeof(u16));
+
+	ret = 0;
+done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+	cmd->size = cpu_to_le16(S_DS_GEN);
+
+	return 0;
+}
+
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+				struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+	struct bss_descriptor *pbssdesc = pdata_buf;
+	int cmdappendsize = 0;
+	int ret = 0;
+	u8 *card_rates;
+	int card_rates_size;
+	u16 tmpcap;
+	int i;
+
+	ENTER();
+
+	adapter->pattemptedbssdesc = pbssdesc;
+
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+
+	padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+
+	padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
+
+	memcpy(&padhocjoin->bssdescriptor.BSSID,
+	       &pbssdesc->macaddress, ETH_ALEN);
+
+	memcpy(&padhocjoin->bssdescriptor.SSID,
+	       &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
+
+	memcpy(&padhocjoin->bssdescriptor.phyparamset,
+	       &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+	memcpy(&padhocjoin->bssdescriptor.ssparamset,
+	       &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+	memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
+	tmpcap &= CAPINFO_MASK;
+
+	lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+	       tmpcap, CAPINFO_MASK);
+	memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
+	       sizeof(struct ieeetypes_capinfo));
+
+	/* information on BSSID descriptor passed to FW */
+    lbs_pr_debug(1,
+	       "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
+	       padhocjoin->bssdescriptor.BSSID[0],
+	       padhocjoin->bssdescriptor.BSSID[1],
+	       padhocjoin->bssdescriptor.BSSID[2],
+	       padhocjoin->bssdescriptor.BSSID[3],
+	       padhocjoin->bssdescriptor.BSSID[4],
+	       padhocjoin->bssdescriptor.BSSID[5],
+	       padhocjoin->bssdescriptor.SSID);
+
+	lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
+	       (u32) padhocjoin->bssdescriptor.datarates);
+
+	/* failtimeout */
+	padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+	/* probedelay */
+	padhocjoin->probedelay =
+	    cpu_to_le16(cmd_scan_probe_delay_time);
+
+	/* Copy Data rates from the rates recorded in scan response */
+	memset(padhocjoin->bssdescriptor.datarates, 0,
+	       sizeof(padhocjoin->bssdescriptor.datarates));
+	memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
+	       min(sizeof(padhocjoin->bssdescriptor.datarates),
+		   sizeof(pbssdesc->datarates)));
+
+	card_rates = libertas_supported_rates;
+	card_rates_size = sizeof(libertas_supported_rates);
+
+	adapter->curbssparams.channel = pbssdesc->channel;
+
+	if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
+			     sizeof(padhocjoin->bssdescriptor.datarates),
+			     card_rates, card_rates_size)) {
+		lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
+		ret = -1;
+		goto done;
+	}
+
+	/* Find the last non zero */
+	for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
+	     && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+
+	adapter->curbssparams.numofrates = i;
+
+	/*
+	 * Copy the adhoc joining rates to Current BSS State structure
+	 */
+	memcpy(adapter->curbssparams.datarates,
+	       padhocjoin->bssdescriptor.datarates,
+	       adapter->curbssparams.numofrates);
+
+	padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+	    cpu_to_le16(pbssdesc->atimwindow);
+
+	if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+		padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+	}
+
+	if (adapter->psmode == wlan802_11powermodemax_psp) {
+		/* wake up first */
+		enum WLAN_802_11_POWER_MODE Localpsmode;
+
+		Localpsmode = wlan802_11powermodecam;
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_ps_mode,
+					    cmd_act_set,
+					    0, 0, &Localpsmode);
+
+		if (ret) {
+			ret = -1;
+			goto done;
+		}
+	}
+
+	if (libertas_parse_dnld_countryinfo_11d(priv)) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
+			     + S_DS_GEN + cmdappendsize);
+
+	memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
+	       sizeof(struct ieeetypes_capinfo));
+	tmpcap = cpu_to_le16(tmpcap);
+
+	memcpy(&padhocjoin->bssdescriptor.cap,
+	       &tmpcap, sizeof(struct ieeetypes_capinfo));
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_ret_80211_associate(wlan_private * priv,
+			      struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	union iwreq_data wrqu;
+	struct ieeetypes_assocrsp *passocrsp;
+	struct bss_descriptor *pbssdesc;
+
+	ENTER();
+
+	passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+	if (passocrsp->statuscode) {
+
+		libertas_mac_event_disconnected(priv);
+
+        lbs_pr_debug(1,
+		       "ASSOC_RESP: Association failed, status code = %d\n",
+		       passocrsp->statuscode);
+
+		ret = -1;
+		goto done;
+	}
+
+	lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+		le16_to_cpu(resp->size) - S_DS_GEN);
+
+	/* Send a Media Connected event, according to the Spec */
+	adapter->connect_status = libertas_connected;
+
+	/* Set the attempted BSSID Index to current */
+	pbssdesc = adapter->pattemptedbssdesc;
+
+	lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
+
+	/* Set the new SSID to current SSID */
+	memcpy(&adapter->curbssparams.ssid,
+	       &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+	/* Set the new BSSID (AP's MAC address) to current BSSID */
+	memcpy(adapter->curbssparams.bssid,
+	       pbssdesc->macaddress, ETH_ALEN);
+
+	/* Make a copy of current BSSID descriptor */
+	memcpy(&adapter->curbssparams.bssdescriptor,
+	       pbssdesc, sizeof(struct bss_descriptor));
+
+	lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
+	       adapter->currentpacketfilter);
+
+	adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+	adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+	adapter->nextSNRNF = 0;
+	adapter->numSNRNF = 0;
+
+	netif_carrier_on(priv->wlan_dev.netdev);
+	netif_wake_queue(priv->wlan_dev.netdev);
+
+	lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
+
+	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_ret_80211_disassociate(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	ENTER();
+
+	libertas_mac_event_disconnected(priv);
+
+	LEAVE();
+	return 0;
+}
+
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u16 command = le16_to_cpu(resp->command);
+	u16 result = le16_to_cpu(resp->result);
+	struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+	union iwreq_data wrqu;
+	struct bss_descriptor *pbssdesc;
+
+	ENTER();
+
+	padhocresult = &resp->params.result;
+
+	lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
+	lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
+	lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
+
+	pbssdesc = adapter->pattemptedbssdesc;
+
+	/*
+	 * Join result code 0 --> SUCCESS
+	 */
+	if (result) {
+		lbs_pr_debug(1, "ADHOC_RESP failed\n");
+		if (adapter->connect_status == libertas_connected) {
+			libertas_mac_event_disconnected(priv);
+		}
+
+		memset(&adapter->curbssparams.bssdescriptor,
+		       0x00, sizeof(adapter->curbssparams.bssdescriptor));
+
+		LEAVE();
+		return -1;
+	}
+
+	/*
+	 * Now the join cmd should be successful
+	 * If BSSID has changed use SSID to compare instead of BSSID
+	 */
+	lbs_pr_debug(1, "ADHOC_J_RESP  %s\n", pbssdesc->ssid.ssid);
+
+	/* Send a Media Connected event, according to the Spec */
+	adapter->connect_status = libertas_connected;
+
+	if (command == cmd_ret_802_11_ad_hoc_start) {
+		/* Update the created network descriptor with the new BSSID */
+		memcpy(pbssdesc->macaddress,
+		       padhocresult->BSSID, ETH_ALEN);
+	} else {
+
+		/* Make a copy of current BSSID descriptor, only needed for join since
+		 *   the current descriptor is already being used for adhoc start
+		 */
+		memmove(&adapter->curbssparams.bssdescriptor,
+			pbssdesc, sizeof(struct bss_descriptor));
+	}
+
+	/* Set the BSSID from the joined/started descriptor */
+	memcpy(&adapter->curbssparams.bssid,
+	       pbssdesc->macaddress, ETH_ALEN);
+
+	/* Set the new SSID to current SSID */
+	memcpy(&adapter->curbssparams.ssid,
+	       &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+	netif_carrier_on(priv->wlan_dev.netdev);
+	netif_wake_queue(priv->wlan_dev.netdev);
+
+	memset(&wrqu, 0, sizeof(wrqu));
+	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+	lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
+	lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+	lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       padhocresult->BSSID[0], padhocresult->BSSID[1],
+	       padhocresult->BSSID[2], padhocresult->BSSID[3],
+	       padhocresult->BSSID[4], padhocresult->BSSID[5]);
+
+	LEAVE();
+	return ret;
+}
+
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	ENTER();
+
+	libertas_mac_event_disconnected(priv);
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644
index 0000000..8efa245
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Interface for the wlan infrastructure and adhoc join routines
+  *
+  * Driver interface functions and type declarations for the join module
+  *   implemented in wlan_join.c.  Process all start/join requests for
+  *   both adhoc and infrastructure networks
+  */
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+#include "defs.h"
+
+struct cmd_ds_command;
+extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+				       struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					void *pssid);
+extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+					  struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_associate(wlan_private * priv,
+				     struct cmd_ds_command *cmd,
+				     void *pdata_buf);
+
+extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+					struct cmd_ds_command *resp);
+extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+				       struct cmd_ds_command *resp);
+extern int libertas_ret_80211_disassociate(wlan_private * priv,
+					struct cmd_ds_command *resp);
+extern int libertas_ret_80211_associate(wlan_private * priv,
+				     struct cmd_ds_command *resp);
+
+extern int libertas_idle_on(wlan_private * priv);
+extern int libertas_idle_off(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+extern int libertas_reassociation_thread(void *data);
+
+struct WLAN_802_11_SSID;
+struct bss_descriptor;
+
+extern int libertas_start_adhoc_network(wlan_private * priv,
+			     struct WLAN_802_11_SSID *adhocssid);
+extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc);
+extern int libertas_stop_adhoc_network(wlan_private * priv);
+
+extern int libertas_send_deauthentication(wlan_private * priv);
+extern int libertas_send_deauth(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
+
+#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644
index 0000000..dcbf102
--- /dev/null
+++ b/drivers/net/wireless/libertas/main.c
@@ -0,0 +1,1258 @@
+/**
+  * This file contains the major functions in WLAN
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "assoc.h"
+
+#ifdef ENABLE_PM
+static struct pm_dev *wlan_pm_dev = NULL;
+#endif
+
+#define WLAN_TX_PWR_DEFAULT		20	/*100mW */
+#define WLAN_TX_PWR_US_DEFAULT		20	/*100mW */
+#define WLAN_TX_PWR_JP_DEFAULT		16	/*50mW */
+#define WLAN_TX_PWR_FR_DEFAULT		20	/*100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT	20	/*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+	{1, 2412, WLAN_TX_PWR_US_DEFAULT},
+	{2, 2417, WLAN_TX_PWR_US_DEFAULT},
+	{3, 2422, WLAN_TX_PWR_US_DEFAULT},
+	{4, 2427, WLAN_TX_PWR_US_DEFAULT},
+	{5, 2432, WLAN_TX_PWR_US_DEFAULT},
+	{6, 2437, WLAN_TX_PWR_US_DEFAULT},
+	{7, 2442, WLAN_TX_PWR_US_DEFAULT},
+	{8, 2447, WLAN_TX_PWR_US_DEFAULT},
+	{9, 2452, WLAN_TX_PWR_US_DEFAULT},
+	{10, 2457, WLAN_TX_PWR_US_DEFAULT},
+	{11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+	{1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+	{2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+	{3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+	{4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+	{5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+	{6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+	{7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+	{8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+	{9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+	{10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+	{11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+	{12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+	{13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+	{10, 2457, WLAN_TX_PWR_DEFAULT},
+	{11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+	{10, 2457, WLAN_TX_PWR_FR_DEFAULT},
+	{11, 2462, WLAN_TX_PWR_FR_DEFAULT},
+	{12, 2467, WLAN_TX_PWR_FR_DEFAULT},
+	{13, 2472, WLAN_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+	{1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+	{2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+	{3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+	{4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+	{5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+	{6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+	{7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+	{8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+	{9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+	{10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+	{11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+	{12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+	{13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+	{14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+	u8 region;
+	struct chan_freq_power *cfp_BG;
+	int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+	{0x10,			/*US FCC */
+	 channel_freq_power_US_BG,
+	 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+	{0x20,			/*CANADA IC */
+	 channel_freq_power_US_BG,
+	 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+	{0x30, /*EU*/ channel_freq_power_EU_BG,
+	 sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+	{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+	 sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+	{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+	 sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+	{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+	 sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+	 }
+	,
+/*Add new region here */
+};
+
+/**
+ * the rates supported by the card
+ */
+u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+	0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported
+ */
+u8 libertas_supported_rates[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
+    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+static wlan_private *wlanpriv = NULL;
+
+#define MAX_DEVS 5
+static struct net_device *libertas_devs[MAX_DEVS];
+static int libertas_found = 0;
+
+/**
+ * the table to keep region code
+ */
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+    { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+static u8 *default_fw_name = "usb8388.bin";
+
+/**
+ * Attributes exported through sysfs
+ */
+
+/**
+ * @brief Get function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_get(struct device * dev,
+		struct device_attribute *attr, char * buf) {
+	struct cmd_ds_mesh_access mesh_access;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+			cmd_mesh_access,
+			cmd_act_mesh_get_mpp,
+			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+
+	return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
+}
+
+/**
+ * @brief Set function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_set(struct device * dev,
+		struct device_attribute *attr, const char * buf, size_t count) {
+	struct cmd_ds_mesh_access mesh_access;
+
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	sscanf(buf, "%d", &(mesh_access.data[0]));
+	libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+			cmd_mesh_access,
+			cmd_act_mesh_set_mpp,
+			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+	return strlen(buf);
+}
+
+/**
+ * libertas_mpp attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ */
+static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
+		libertas_mpp_set );
+
+/**
+ *  @brief Check if the device can be open and wait if necessary.
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ *
+ * For USB adapter, on some systems the device open handler will be
+ * called before FW ready. Use the following flag check and wait
+ * function to work around the issue.
+ *
+ */
+static int pre_open_check(struct net_device *dev) {
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int i = 0;
+
+	while (!adapter->fw_ready && i < 20) {
+		i++;
+		msleep_interruptible(100);
+	}
+	if (!adapter->fw_ready) {
+		lbs_pr_info("FW not ready, pre_open_check() return failure\n");
+		LEAVE();
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ *  @brief This function opens the device
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_dev_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+
+	priv->open = 1;
+
+	if (adapter->connect_status == libertas_connected) {
+		netif_carrier_on(priv->wlan_dev.netdev);
+	} else
+		netif_carrier_off(priv->wlan_dev.netdev);
+
+	LEAVE();
+	return 0;
+}
+/**
+ *  @brief This function opens the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int mesh_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv ;
+
+	if(pre_open_check(dev) == -1)
+		return -1;
+	priv->mesh_open = 1 ;
+	netif_start_queue(priv->mesh_dev);
+	if (priv->infra_open == 0)
+		return wlan_dev_open(priv->wlan_dev.netdev) ;
+	return 0;
+}
+
+/**
+ *  @brief This function opens the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv ;
+
+	if(pre_open_check(dev) == -1)
+		return -1;
+	priv->infra_open = 1 ;
+	netif_wake_queue(priv->wlan_dev.netdev);
+	if (priv->open == 0)
+		return wlan_dev_open(priv->wlan_dev.netdev) ;
+	return 0;
+}
+
+static int wlan_dev_close(struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	netif_carrier_off(priv->wlan_dev.netdev);
+	priv->open = 0;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function closes the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int mesh_close(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) (dev->priv);
+
+	priv->mesh_open = 0;
+	netif_stop_queue(priv->mesh_dev);
+	if (priv->infra_open == 0)
+		return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+	else
+		return 0;
+}
+
+/**
+ *  @brief This function closes the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_close(struct net_device *dev) {
+	wlan_private *priv = (wlan_private *) dev->priv;
+
+	netif_stop_queue(priv->wlan_dev.netdev);
+	priv->infra_open = 0;
+	if (priv->mesh_open == 0)
+		return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+	else
+		return 0;
+}
+
+
+#ifdef ENABLE_PM
+
+/**
+ *  @brief This function is a callback function. it is called by
+ *  kernel to enter or exit power saving mode.
+ *
+ *  @param pmdev   A pointer to pm_dev
+ *  @param pmreq   pm_request_t
+ *  @param pmdata  A pointer to pmdata
+ *  @return 	   0 or -1
+ */
+static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq,
+			    void *pmdata)
+{
+	wlan_private *priv = wlanpriv;
+	wlan_adapter *adapter = priv->adapter;
+	struct net_device *dev = priv->wlan_dev.netdev;
+
+	lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
+
+	switch (pmreq) {
+	case PM_SUSPEND:
+		lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
+
+		/* in associated mode */
+		if (adapter->connect_status == libertas_connected) {
+			if ((adapter->psstate != PS_STATE_SLEEP)
+			    ) {
+				lbs_pr_debug(1,
+				       "wlan_pm_callback: can't enter sleep mode\n");
+				return -1;
+			} else {
+
+				/*
+				 * Detach the network interface
+				 * if the network is running
+				 */
+				if (netif_running(dev)) {
+					netif_device_detach(dev);
+					lbs_pr_debug(1,
+					       "netif_device_detach().\n");
+				}
+				libertas_sbi_suspend(priv);
+			}
+			break;
+		}
+
+		/* in non associated mode */
+
+		/*
+		 * Detach the network interface
+		 * if the network is running
+		 */
+		if (netif_running(dev))
+			netif_device_detach(dev);
+
+		/*
+		 * Storing and restoring of the regs be taken care
+		 * at the driver rest will be done at wlan driver
+		 * this makes driver independent of the card
+		 */
+
+		libertas_sbi_suspend(priv);
+
+		break;
+
+	case PM_RESUME:
+		/* in associated mode */
+		if (adapter->connect_status == libertas_connected) {
+			{
+				/*
+				 * Bring the inteface up first
+				 * This case should not happen still ...
+				 */
+				libertas_sbi_resume(priv);
+
+				/*
+				 * Attach the network interface
+				 * if the network is running
+				 */
+				if (netif_running(dev)) {
+					netif_device_attach(dev);
+					lbs_pr_debug(1,
+					       "after netif_device_attach().\n");
+				}
+				lbs_pr_debug(1,
+				       "After netif attach, in associated mode.\n");
+			}
+			break;
+		}
+
+		/* in non associated mode */
+
+		/*
+		 * Bring the inteface up first
+		 * This case should not happen still ...
+		 */
+
+		libertas_sbi_resume(priv);
+
+		if (netif_running(dev))
+			netif_device_attach(dev);
+
+		lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
+		break;
+	}
+
+	return 0;
+}
+#endif				/* ENABLE_PM */
+
+static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
+		priv->stats.tx_dropped++;
+		goto done;
+	}
+
+	netif_stop_queue(priv->wlan_dev.netdev);
+
+	if (libertas_process_tx(priv, skb) == 0)
+		dev->trans_start = jiffies;
+done:
+	LEAVE();
+	return ret;
+}
+
+/**
+ * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+	ENTER();
+	SET_MESH_FRAME(skb);
+	LEAVE();
+
+	return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
+}
+
+/**
+ * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	ENTER();
+	UNSET_MESH_FRAME(skb);
+	LEAVE();
+	return wlan_hard_start_xmit(skb, dev);
+}
+
+static void wlan_tx_timeout(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+
+	ENTER();
+
+	lbs_pr_err("tx watch dog timeout!\n");
+
+	priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+	dev->trans_start = jiffies;
+
+	if (priv->adapter->currenttxskb) {
+		if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+			/* If we are here, we have not received feedback from
+			   the previous packet.  Assume TX_FAIL and move on. */
+			priv->adapter->eventcause = 0x01000000;
+			libertas_send_tx_feedback(priv);
+		} else
+			wake_up_interruptible(&priv->mainthread.waitq);
+	} else if (priv->adapter->connect_status == libertas_connected)
+		netif_wake_queue(priv->wlan_dev.netdev);
+
+	LEAVE();
+}
+
+/**
+ *  @brief This function returns the network statistics
+ *
+ *  @param dev     A pointer to wlan_private structure
+ *  @return 	   A pointer to net_device_stats structure
+ */
+static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+
+	return &priv->stats;
+}
+
+static int wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+	int ret = 0;
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct sockaddr *phwaddr = addr;
+
+	ENTER();
+
+	memset(adapter->current_addr, 0, ETH_ALEN);
+
+	/* dev->dev_addr is 8 bytes */
+	lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+	lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+	memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		lbs_pr_debug(1, "set mac address failed.\n");
+		ret = -1;
+		goto done;
+	}
+
+	lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+	memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+	memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_copy_multicast_address(wlan_adapter * adapter,
+				     struct net_device *dev)
+{
+	int i = 0;
+	struct dev_mc_list *mcptr = dev->mc_list;
+
+	for (i = 0; i < dev->mc_count; i++) {
+		memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+		mcptr = mcptr->next;
+	}
+
+	return i;
+
+}
+
+static void wlan_set_multicast_list(struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int oldpacketfilter;
+
+	ENTER();
+
+	oldpacketfilter = adapter->currentpacketfilter;
+
+	if (dev->flags & IFF_PROMISC) {
+		lbs_pr_debug(1, "enable Promiscuous mode\n");
+		adapter->currentpacketfilter |=
+		    cmd_act_mac_promiscuous_enable;
+		adapter->currentpacketfilter &=
+		    ~(cmd_act_mac_all_multicast_enable |
+		      cmd_act_mac_multicast_enable);
+	} else {
+		/* Multicast */
+		adapter->currentpacketfilter &=
+		    ~cmd_act_mac_promiscuous_enable;
+
+		if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+		    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+			lbs_pr_debug(1, "Enabling All Multicast!\n");
+			adapter->currentpacketfilter |=
+			    cmd_act_mac_all_multicast_enable;
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_multicast_enable;
+		} else {
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_all_multicast_enable;
+
+			if (!dev->mc_count) {
+				lbs_pr_debug(1, "No multicast addresses - "
+				       "disabling multicast!\n");
+				adapter->currentpacketfilter &=
+				    ~cmd_act_mac_multicast_enable;
+			} else {
+				int i;
+
+				adapter->currentpacketfilter |=
+				    cmd_act_mac_multicast_enable;
+
+				adapter->nr_of_multicastmacaddr =
+				    wlan_copy_multicast_address(adapter, dev);
+
+				lbs_pr_debug(1, "Multicast addresses: %d\n",
+				       dev->mc_count);
+
+				for (i = 0; i < dev->mc_count; i++) {
+					lbs_pr_debug(1, "Multicast address %d:"
+					       "%x %x %x %x %x %x\n", i,
+					       adapter->multicastlist[i][0],
+					       adapter->multicastlist[i][1],
+					       adapter->multicastlist[i][2],
+					       adapter->multicastlist[i][3],
+					       adapter->multicastlist[i][4],
+					       adapter->multicastlist[i][5]);
+				}
+				/* set multicast addresses to firmware */
+				libertas_prepare_and_send_command(priv,
+						      cmd_mac_multicast_adr,
+						      cmd_act_set, 0, 0,
+						      NULL);
+			}
+		}
+	}
+
+	if (adapter->currentpacketfilter != oldpacketfilter) {
+		libertas_set_mac_packet_filter(priv);
+	}
+
+	LEAVE();
+}
+
+/**
+ *  @brief This function hanldes the major job in WLAN driver.
+ *  it handles the event generated by firmware, rx data received
+ *  from firmware and tx data sent from kernel.
+ *
+ *  @param data    A pointer to wlan_thread structure
+ *  @return 	   0
+ */
+static int wlan_service_main_thread(void *data)
+{
+	struct wlan_thread *thread = data;
+	wlan_private *priv = thread->priv;
+	wlan_adapter *adapter = priv->adapter;
+	wait_queue_t wait;
+	u8 ireg = 0;
+
+	ENTER();
+
+	wlan_activate_thread(thread);
+
+	init_waitqueue_entry(&wait, current);
+
+	for (;;) {
+		lbs_pr_debug(1, "main-thread 111: intcounter=%d "
+		       "currenttxskb=%p dnld_sent=%d\n",
+		       adapter->intcounter,
+		       adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+		add_wait_queue(&thread->waitq, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irq(&adapter->driver_lock);
+		if ((adapter->psstate == PS_STATE_SLEEP) ||
+		    (!adapter->intcounter
+		     && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
+			 list_empty(&adapter->cmdpendingq)))) {
+			lbs_pr_debug(1,
+			       "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+			       adapter->connect_status, adapter->intcounter,
+			       adapter->psmode, adapter->psstate);
+			spin_unlock_irq(&adapter->driver_lock);
+			schedule();
+		} else
+			spin_unlock_irq(&adapter->driver_lock);
+
+
+		lbs_pr_debug(1,
+		       "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
+		       "dnld_sent=%d\n", adapter->intcounter,
+		       adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&thread->waitq, &wait);
+		try_to_freeze();
+
+		lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p "
+		       "dnld_sent=%d\n",
+		       adapter->intcounter,
+		       adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+		if (kthread_should_stop()
+		    || adapter->surpriseremoved) {
+			lbs_pr_debug(1,
+			       "main-thread: break from main thread: surpriseremoved=0x%x\n",
+			       adapter->surpriseremoved);
+			break;
+		}
+
+
+		spin_lock_irq(&adapter->driver_lock);
+		if (adapter->intcounter) {
+			u8 int_status;
+			adapter->intcounter = 0;
+			int_status = libertas_sbi_get_int_status(priv, &ireg);
+
+			if (int_status) {
+				lbs_pr_debug(1,
+				       "main-thread: reading HOST_INT_STATUS_REG failed\n");
+				spin_unlock_irq(&adapter->driver_lock);
+				continue;
+			}
+			adapter->hisregcpy |= ireg;
+		}
+
+		lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p "
+		       "dnld_sent=%d\n",
+		       adapter->intcounter,
+		       adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+		/* command response? */
+		if (adapter->hisregcpy & his_cmdupldrdy) {
+			lbs_pr_debug(1, "main-thread: cmd response ready.\n");
+
+			adapter->hisregcpy &= ~his_cmdupldrdy;
+			spin_unlock_irq(&adapter->driver_lock);
+			libertas_process_rx_command(priv);
+			spin_lock_irq(&adapter->driver_lock);
+		}
+
+		/* Any Card Event */
+		if (adapter->hisregcpy & his_cardevent) {
+			lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
+
+			adapter->hisregcpy &= ~his_cardevent;
+
+			if (libertas_sbi_read_event_cause(priv)) {
+				lbs_pr_alert(
+				       "main-thread: libertas_sbi_read_event_cause failed.\n");
+				spin_unlock_irq(&adapter->driver_lock);
+				continue;
+			}
+			spin_unlock_irq(&adapter->driver_lock);
+			libertas_process_event(priv);
+		} else
+			spin_unlock_irq(&adapter->driver_lock);
+
+		/* Check if we need to confirm Sleep Request received previously */
+		if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+			if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
+				if (adapter->connect_status ==
+				    libertas_connected) {
+					lbs_pr_debug(1,
+					       "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+					       "dnld_sent=%d cur_cmd=%p, confirm now\n",
+					       adapter->intcounter,
+					       adapter->currenttxskb,
+					       priv->wlan_dev.dnld_sent,
+					       adapter->cur_cmd);
+
+					libertas_ps_confirm_sleep(priv,
+						       (u16) adapter->psmode);
+				} else {
+					/* workaround for firmware sending
+					 * deauth/linkloss event immediately
+					 * after sleep request, remove this
+					 * after firmware fixes it
+					 */
+					adapter->psstate = PS_STATE_AWAKE;
+					lbs_pr_alert(
+					       "main-thread: ignore PS_SleepConfirm in non-connected state\n");
+				}
+			}
+		}
+
+		/* The PS state is changed during processing of Sleep Request
+		 * event above
+		 */
+		if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+		    (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
+			continue;
+
+		/* Execute the next command */
+		if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd)
+			libertas_execute_next_command(priv);
+
+		/* Wake-up command waiters which can't sleep in
+		 * libertas_prepare_and_send_command
+		 */
+		if (!adapter->nr_cmd_pending)
+			wake_up_all(&adapter->cmd_pending);
+
+		libertas_tx_runqueue(priv);
+	}
+
+	del_timer(&adapter->command_timer);
+	adapter->nr_cmd_pending = 0;
+	wake_up_all(&adapter->cmd_pending);
+	wlan_deactivate_thread(thread);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device.
+ *
+ *  @param card    A pointer to card
+ *  @return 	   A pointer to wlan_private structure
+ */
+wlan_private *wlan_add_card(void *card)
+{
+	struct net_device *dev = NULL;
+	struct net_device *mesh_dev = NULL;
+	wlan_private *priv = NULL;
+
+	ENTER();
+
+	/* Allocate an Ethernet device and register it */
+	if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+		lbs_pr_alert( "Init ethernet device failed!\n");
+		return NULL;
+	}
+
+	priv = dev->priv;
+
+	/* allocate buffer for wlan_adapter */
+	if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+		lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
+		goto err_kmalloc;
+	}
+
+	/* Allocate a virtual mesh device */
+	if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
+		lbs_pr_debug(1, "Init ethernet device failed!\n");
+		return NULL;
+	}
+
+	/* Both intervaces share the priv structure */
+	mesh_dev->priv = priv;
+
+	/* init wlan_adapter */
+	memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+	priv->wlan_dev.netdev = dev;
+	priv->wlan_dev.card = card;
+	priv->mesh_open = 0;
+	priv->infra_open = 0;
+	priv->mesh_dev = mesh_dev;
+	wlanpriv = priv;
+
+	SET_MODULE_OWNER(dev);
+	SET_MODULE_OWNER(mesh_dev);
+
+	/* Setup the OS Interface to our functions */
+	dev->open = wlan_open;
+	dev->hard_start_xmit = wlan_pre_start_xmit;
+	dev->stop = wlan_close;
+	dev->do_ioctl = libertas_do_ioctl;
+	dev->set_mac_address = wlan_set_mac_address;
+	mesh_dev->open = mesh_open;
+	mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+	mesh_dev->stop = mesh_close;
+	mesh_dev->do_ioctl = libertas_do_ioctl;
+	memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
+			sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
+
+#define	WLAN_WATCHDOG_TIMEOUT	(5 * HZ)
+
+	dev->tx_timeout = wlan_tx_timeout;
+	dev->get_stats = wlan_get_stats;
+	dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
+	dev->ethtool_ops = &libertas_ethtool_ops;
+	mesh_dev->get_stats = wlan_get_stats;
+	mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+
+#ifdef	WIRELESS_EXT
+	dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+	mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+	dev->features |= NETIF_F_DYNALLOC;
+	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+	dev->set_multicast_list = wlan_set_multicast_list;
+
+	INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
+	INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+
+	spin_lock_init(&priv->adapter->driver_lock);
+	init_waitqueue_head(&priv->adapter->cmd_pending);
+	priv->adapter->nr_cmd_pending = 0;
+
+	lbs_pr_debug(1, "Starting kthread...\n");
+	priv->mainthread.priv = priv;
+	wlan_create_thread(wlan_service_main_thread,
+			   &priv->mainthread, "wlan_main_service");
+
+	priv->assoc_thread =
+		create_singlethread_workqueue("libertas_assoc");
+	INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
+
+	/*
+	 * Register the device. Fillup the private data structure with
+	 * relevant information from the card and request for the required
+	 * IRQ.
+	 */
+	if (libertas_sbi_register_dev(priv) < 0) {
+		lbs_pr_info("failed to register wlan device!\n");
+		goto err_registerdev;
+	}
+
+	/* init FW and HW */
+	if (libertas_init_fw(priv)) {
+		lbs_pr_debug(1, "Firmware Init failed\n");
+		goto err_registerdev;
+	}
+
+	if (register_netdev(dev)) {
+		lbs_pr_err("Cannot register network device!\n");
+		goto err_init_fw;
+	}
+
+	/* Register virtual mesh interface */
+	if (register_netdev(mesh_dev)) {
+		lbs_pr_info("Cannot register mesh virtual interface!\n");
+		goto err_init_fw;
+	}
+
+	lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
+
+	libertas_debugfs_init_one(priv, dev);
+
+	if (libertas_found == MAX_DEVS)
+		goto err_init_fw;
+	libertas_devs[libertas_found] = dev;
+	libertas_found++;
+#ifdef ENABLE_PM
+	if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
+		lbs_pr_alert( "failed to register PM callback\n");
+#endif
+	if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp))
+		goto err_create_file;
+
+	LEAVE();
+	return priv;
+
+err_create_file:
+	device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+err_init_fw:
+	libertas_sbi_unregister_dev(priv);
+err_registerdev:
+	destroy_workqueue(priv->assoc_thread);
+	/* Stop the thread servicing the interrupts */
+	wake_up_interruptible(&priv->mainthread.waitq);
+	wlan_terminate_thread(&priv->mainthread);
+	kfree(priv->adapter);
+err_kmalloc:
+	free_netdev(dev);
+	free_netdev(mesh_dev);
+	wlanpriv = NULL;
+
+	LEAVE();
+	return NULL;
+}
+
+static void wake_pending_cmdnodes(wlan_private *priv)
+{
+	struct cmd_ctrl_node *cmdnode;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+	list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+		cmdnode->cmdwaitqwoken = 1;
+		wake_up_interruptible(&cmdnode->cmdwait_q);
+	}
+	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+
+int wlan_remove_card(void *card)
+{
+	wlan_private *priv = libertas_sbi_get_priv(card);
+	wlan_adapter *adapter;
+	struct net_device *dev;
+	struct net_device *mesh_dev;
+	union iwreq_data wrqu;
+	int i;
+
+	ENTER();
+
+	if (!priv) {
+		LEAVE();
+		return 0;
+	}
+
+	adapter = priv->adapter;
+
+	if (!adapter) {
+		LEAVE();
+		return 0;
+	}
+
+	dev = priv->wlan_dev.netdev;
+	mesh_dev = priv->mesh_dev;
+
+	netif_stop_queue(mesh_dev);
+	netif_stop_queue(priv->wlan_dev.netdev);
+	netif_carrier_off(priv->wlan_dev.netdev);
+
+	wake_pending_cmdnodes(priv);
+
+	device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+	unregister_netdev(mesh_dev);
+	unregister_netdev(dev);
+
+	cancel_delayed_work(&priv->assoc_work);
+	destroy_workqueue(priv->assoc_thread);
+
+	if (adapter->psmode == wlan802_11powermodemax_psp) {
+		adapter->psmode = wlan802_11powermodecam;
+		libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+	}
+
+	memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+#ifdef ENABLE_PM
+	pm_unregister(wlan_pm_dev);
+#endif
+
+	adapter->surpriseremoved = 1;
+
+	/* Stop the thread servicing the interrupts */
+	wlan_terminate_thread(&priv->mainthread);
+
+	libertas_debugfs_remove_one(priv);
+
+	lbs_pr_debug(1, "Free adapter\n");
+	libertas_free_adapter(priv);
+
+	for (i = 0; i<libertas_found; i++) {
+		if (libertas_devs[i]==priv->wlan_dev.netdev) {
+			libertas_devs[i] = libertas_devs[--libertas_found];
+			libertas_devs[libertas_found] = NULL ;
+			break ;
+		}
+	}
+
+	lbs_pr_debug(1, "Unregister finish\n");
+
+	priv->wlan_dev.netdev = NULL;
+	priv->mesh_dev = NULL ;
+	free_netdev(mesh_dev);
+	free_netdev(dev);
+	wlanpriv = NULL;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function finds the CFP in
+ *  region_cfp_table based on region and band parameter.
+ *
+ *  @param region  The region code
+ *  @param band	   The band
+ *  @param cfp_no  A pointer to CFP number
+ *  @return 	   A pointer to CFP
+ */
+struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+	int i, end;
+
+	ENTER();
+
+	end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+
+	for (i = 0; i < end ; i++) {
+		lbs_pr_debug(1, "region_cfp_table[i].region=%d\n",
+			region_cfp_table[i].region);
+		if (region_cfp_table[i].region == region) {
+			*cfp_no = region_cfp_table[i].cfp_no_BG;
+			LEAVE();
+			return region_cfp_table[i].cfp_BG;
+		}
+	}
+
+	LEAVE();
+	return NULL;
+}
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i = 0;
+
+	struct chan_freq_power *cfp;
+	int cfp_no;
+
+	ENTER();
+
+	memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
+
+	{
+		cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+		if (cfp != NULL) {
+			adapter->region_channel[i].nrcfp = cfp_no;
+			adapter->region_channel[i].CFP = cfp;
+		} else {
+			lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
+			       region);
+			return -1;
+		}
+		adapter->region_channel[i].valid = 1;
+		adapter->region_channel[i].region = region;
+		adapter->region_channel[i].band = band;
+		i++;
+	}
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function handles the interrupt. it will change PS
+ *  state if applicable. it will wake up main_thread to handle
+ *  the interrupt event as well.
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   n/a
+ */
+void libertas_interrupt(struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n",
+	       priv->adapter->intcounter);
+
+	priv->adapter->intcounter++;
+
+	if (priv->adapter->psstate == PS_STATE_SLEEP) {
+		priv->adapter->psstate = PS_STATE_AWAKE;
+		netif_wake_queue(dev);
+	}
+
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	LEAVE();
+}
+
+static int wlan_init_module(void)
+{
+	int ret = 0;
+
+	ENTER();
+
+	if (libertas_fw_name == NULL) {
+		libertas_fw_name = default_fw_name;
+	}
+
+	libertas_debugfs_init();
+
+	if (libertas_sbi_register()) {
+		ret = -1;
+		libertas_debugfs_remove();
+		goto done;
+	}
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static void wlan_cleanup_module(void)
+{
+	int i;
+
+	ENTER();
+
+	for (i = 0; i<libertas_found; i++) {
+		wlan_private *priv = libertas_devs[i]->priv;
+		reset_device(priv);
+	}
+
+	libertas_sbi_unregister();
+	libertas_debugfs_remove();
+
+	LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644
index 0000000..5d118f4
--- /dev/null
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -0,0 +1,57 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+	struct ieee80211_radiotap_header hdr;
+	u8 rate;
+	u8 txpower;
+	u8 rts_retries;
+	u8 data_retries;
+#if 0
+	u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
+#endif
+} __attribute__ ((packed));
+
+#define TX_RADIOTAP_PRESENT (				\
+	(1 << IEEE80211_RADIOTAP_RATE) |		\
+	(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) |	\
+	(1 << IEEE80211_RADIOTAP_RTS_RETRIES) |		\
+	(1 << IEEE80211_RADIOTAP_DATA_RETRIES)  |	\
+	0)
+
+#define IEEE80211_FC_VERSION_MASK    0x0003
+#define IEEE80211_FC_TYPE_MASK       0x000c
+#define IEEE80211_FC_TYPE_MGT        0x0000
+#define IEEE80211_FC_TYPE_CTL        0x0004
+#define IEEE80211_FC_TYPE_DATA       0x0008
+#define IEEE80211_FC_SUBTYPE_MASK    0x00f0
+#define IEEE80211_FC_TOFROMDS_MASK   0x0300
+#define IEEE80211_FC_TODS_MASK       0x0100
+#define IEEE80211_FC_FROMDS_MASK     0x0200
+#define IEEE80211_FC_NODS            0x0000
+#define IEEE80211_FC_TODS            0x0100
+#define IEEE80211_FC_FROMDS          0x0200
+#define IEEE80211_FC_DSTODS          0x0300
+
+struct rx_radiotap_hdr {
+	struct ieee80211_radiotap_header hdr;
+	u8 flags;
+	u8 rate;
+	u16 chan_freq;
+	u16 chan_flags;
+	u8 antenna;
+	u8 antsignal;
+	u16 rx_flags;
+#if 0
+	u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
+#endif
+} __attribute__ ((packed));
+
+#define RX_RADIOTAP_PRESENT (			\
+	(1 << IEEE80211_RADIOTAP_FLAGS) |	\
+	(1 << IEEE80211_RADIOTAP_RATE) |	\
+	(1 << IEEE80211_RADIOTAP_CHANNEL) |	\
+	(1 << IEEE80211_RADIOTAP_ANTENNA) |	\
+	(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
+	(1 << IEEE80211_RADIOTAP_RX_FLAGS) |	\
+	0)
+
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 0000000..7e3f78f
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
+/**
+  * This file contains the handling of RX in wlan driver.
+  */
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+
+struct eth803hdr {
+	u8 dest_addr[6];
+	u8 src_addr[6];
+	u16 h803_len;
+} __attribute__ ((packed));
+
+struct rfc1042hdr {
+	u8 llc_dsap;
+	u8 llc_ssap;
+	u8 llc_ctrl;
+	u8 snap_oui[3];
+	u16 snap_type;
+} __attribute__ ((packed));
+
+struct rxpackethdr {
+	struct rxpd rx_pd;
+	struct eth803hdr eth803_hdr;
+	struct rfc1042hdr rfc1042_hdr;
+} __attribute__ ((packed));
+
+struct rx80211packethdr {
+	struct rxpd rx_pd;
+	void *eth80211_hdr;
+} __attribute__ ((packed));
+
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
+
+/**
+ *  @brief This function computes the avgSNR .
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   avgSNR
+ */
+static u8 wlan_getavgsnr(wlan_private * priv)
+{
+	u8 i;
+	u16 temp = 0;
+	wlan_adapter *adapter = priv->adapter;
+	if (adapter->numSNRNF == 0)
+		return 0;
+	for (i = 0; i < adapter->numSNRNF; i++)
+		temp += adapter->rawSNR[i];
+	return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ *  @brief This function computes the AvgNF
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   AvgNF
+ */
+static u8 wlan_getavgnf(wlan_private * priv)
+{
+	u8 i;
+	u16 temp = 0;
+	wlan_adapter *adapter = priv->adapter;
+	if (adapter->numSNRNF == 0)
+		return 0;
+	for (i = 0; i < adapter->numSNRNF; i++)
+		temp += adapter->rawNF[i];
+	return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ *  @brief This function save the raw SNR/NF to our internel buffer
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param prxpd   A pointer to rxpd structure of received packet
+ *  @return 	   n/a
+ */
+static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+	wlan_adapter *adapter = priv->adapter;
+	if (adapter->numSNRNF < adapter->data_avg_factor)
+		adapter->numSNRNF++;
+	adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+	adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
+	adapter->nextSNRNF++;
+	if (adapter->nextSNRNF >= adapter->data_avg_factor)
+		adapter->nextSNRNF = 0;
+	return;
+}
+
+/**
+ *  @brief This function computes the RSSI in received packet.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param prxpd   A pointer to rxpd structure of received packet
+ *  @return 	   n/a
+ */
+static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
+	lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
+	       adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+	       adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+	adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+	adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+	wlan_save_rawSNRNF(priv, p_rx_pd);
+
+	adapter->rxpd_rate = p_rx_pd->rx_rate;
+
+	adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+	adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+	lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
+	       adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+	       adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+	adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+	    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+		     adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+	adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+	    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+		     adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+	LEAVE();
+}
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	lbs_pr_debug(1, "skb->data=%p\n", skb->data);
+
+	if(IS_MESH_FRAME(skb))
+		skb->dev = priv->mesh_dev;
+	else
+		skb->dev = priv->wlan_dev.netdev;
+	skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	netif_rx(skb);
+
+	return 0;
+}
+
+/**
+ *  @brief This function processes received packet and forwards it
+ *  to kernel/upper layer
+ *
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return 	   0 or -1
+ */
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	struct rxpackethdr *p_rx_pkt;
+	struct rxpd *p_rx_pd;
+
+	int hdrchop;
+	struct ethhdr *p_ethhdr;
+
+	const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+	ENTER();
+
+	if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+		lbs_dbg_hex("RX packet: ", skb->data,
+			 min_t(unsigned int, skb->len, 100));
+
+	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+		return process_rxed_802_11_packet(priv, skb);
+
+	p_rx_pkt = (struct rxpackethdr *) skb->data;
+	p_rx_pd = &p_rx_pkt->rx_pd;
+	if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+		SET_MESH_FRAME(skb);
+	else
+		UNSET_MESH_FRAME(skb);
+
+	lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+		 min_t(unsigned int, skb->len, 100));
+
+	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+		lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+		priv->stats.rx_length_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	/*
+	 * Check rxpd status and update 802.3 stat,
+	 */
+	if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
+		lbs_pr_debug(1, "RX error: frame received with bad status\n");
+		lbs_pr_alert("rxpd Not OK\n");
+		priv->stats.rx_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+	lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+		sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+	lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+		sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+	if (memcmp(&p_rx_pkt->rfc1042_hdr,
+		   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+		/*
+		 *  Replace the 803 header and rfc1042 header (llc/snap) with an
+		 *    EthernetII header, keep the src/dst and snap_type (ethertype)
+		 *
+		 *  The firmware only passes up SNAP frames converting
+		 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+		 *
+		 *  To create the Ethernet II, just move the src, dst address right
+		 *    before the snap_type.
+		 */
+		p_ethhdr = (struct ethhdr *)
+		    ((u8 *) & p_rx_pkt->eth803_hdr
+		     + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+		     - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+		     - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+		     - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+		memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+		       sizeof(p_ethhdr->h_source));
+		memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+		       sizeof(p_ethhdr->h_dest));
+
+		/* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+		 *   that was removed
+		 */
+		hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+	} else {
+		lbs_dbg_hex("RX Data: LLC/SNAP",
+			(u8 *) & p_rx_pkt->rfc1042_hdr,
+			sizeof(p_rx_pkt->rfc1042_hdr));
+
+		/* Chop off the rxpd */
+		hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+	}
+
+	/* Chop off the leading header bytes so the skb points to the start of
+	 *   either the reconstructed EthII frame or the 802.2/llc/snap frame
+	 */
+	skb_pull(skb, hdrchop);
+
+	/* Take the data rate from the rxpd structure
+	 * only if the rate is auto
+	 */
+	if (adapter->is_datarate_auto)
+		adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+
+	wlan_compute_rssi(priv, p_rx_pd);
+
+	lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+	if (libertas_upload_rx_packet(priv, skb)) {
+		lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
+		       " returns failure\n");
+		ret = -1;
+		goto done;
+	}
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+
+	ret = 0;
+done:
+	LEAVE();
+
+	return ret;
+}
+
+/**
+ *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
+ *  (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ *
+ *  @param rate    Input rate
+ *  @return 	   Output Rate (0 if invalid)
+ */
+static u8 convert_mv_rate_to_radiotap(u8 rate)
+{
+	switch (rate) {
+	case 0:		/*   1 Mbps */
+		return 2;
+	case 1:		/*   2 Mbps */
+		return 4;
+	case 2:		/* 5.5 Mbps */
+		return 11;
+	case 3:		/*  11 Mbps */
+		return 22;
+	case 4:		/*   6 Mbps */
+		return 12;
+	case 5:		/*   9 Mbps */
+		return 18;
+	case 6:		/*  12 Mbps */
+		return 24;
+	case 7:		/*  18 Mbps */
+		return 36;
+	case 8:		/*  24 Mbps */
+		return 48;
+	case 9:		/*  36 Mbps */
+		return 72;
+	case 10:		/*  48 Mbps */
+		return 96;
+	case 11:		/*  54 Mbps */
+		return 108;
+	}
+	lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
+	return 0;
+}
+
+/**
+ *  @brief This function processes a received 802.11 packet and forwards it
+ *  to kernel/upper layer
+ *
+ *  @param priv    A pointer to wlan_private
+ *  @param skb     A pointer to skb which includes the received packet
+ *  @return 	   0 or -1
+ */
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	struct rx80211packethdr *p_rx_pkt;
+	struct rxpd *prxpd;
+	struct rx_radiotap_hdr radiotap_hdr;
+	struct rx_radiotap_hdr *pradiotap_hdr;
+
+	ENTER();
+
+	p_rx_pkt = (struct rx80211packethdr *) skb->data;
+	prxpd = &p_rx_pkt->rx_pd;
+
+	// lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+		lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+		priv->stats.rx_length_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	/*
+	 * Check rxpd status and update 802.3 stat,
+	 */
+	if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
+		//lbs_pr_debug(1, "RX error: frame received with bad status\n");
+		priv->stats.rx_errors++;
+	}
+
+	lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+	/* create the exported radio header */
+	switch (priv->adapter->radiomode) {
+	case WLAN_RADIOMODE_NONE:
+		/* no radio header */
+		/* chop the rxpd */
+		skb_pull(skb, sizeof(struct rxpd));
+		break;
+
+	case WLAN_RADIOMODE_RADIOTAP:
+		/* radiotap header */
+		radiotap_hdr.hdr.it_version = 0;
+		/* XXX must check this value for pad */
+		radiotap_hdr.hdr.it_pad = 0;
+		radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
+		radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+		/* unknown values */
+		radiotap_hdr.flags = 0;
+		radiotap_hdr.chan_freq = 0;
+		radiotap_hdr.chan_flags = 0;
+		radiotap_hdr.antenna = 0;
+		/* known values */
+		radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+		/* XXX must check no carryout */
+		radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+		radiotap_hdr.rx_flags = 0;
+		if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
+			radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+		//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+
+		// lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
+
+		/* chop the rxpd */
+		skb_pull(skb, sizeof(struct rxpd));
+
+		/* add space for the new radio header */
+		if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+		    pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+				     GFP_ATOMIC)) {
+			lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
+			       __func__);
+		}
+
+		pradiotap_hdr =
+		    (struct rx_radiotap_hdr *)skb_push(skb,
+						     sizeof(struct
+							    rx_radiotap_hdr));
+		memcpy(pradiotap_hdr, &radiotap_hdr,
+		       sizeof(struct rx_radiotap_hdr));
+		//lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+		break;
+
+	default:
+		/* unknown header */
+		lbs_pr_alert( "Unknown radiomode (%i)\n",
+		       priv->adapter->radiomode);
+		/* don't export any header */
+		/* chop the rxpd */
+		skb_pull(skb, sizeof(struct rxpd));
+		break;
+	}
+
+	/* Take the data rate from the rxpd structure
+	 * only if the rate is auto
+	 */
+	if (adapter->is_datarate_auto) {
+		adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
+	}
+
+	wlan_compute_rssi(priv, prxpd);
+
+	lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+
+	if (libertas_upload_rx_packet(priv, skb)) {
+		lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
+			"returns failure\n");
+		ret = -1;
+		goto done;
+	}
+
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+
+	ret = 0;
+done:
+	LEAVE();
+
+	skb->protocol = __constant_htons(0x0019);	/* ETH_P_80211_RAW */
+
+	return (ret);
+}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644
index 0000000..59d3a59
--- /dev/null
+++ b/drivers/net/wireless/libertas/sbi.h
@@ -0,0 +1,40 @@
+/**
+  * This file contains IF layer definitions.
+  */
+
+#ifndef	_SBI_H_
+#define	_SBI_H_
+
+#include <linux/interrupt.h>
+
+#include "defs.h"
+
+/** INT status Bit Definition*/
+#define his_cmddnldrdy			0x01
+#define his_cardevent			0x02
+#define his_cmdupldrdy			0x04
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN			32
+#endif
+
+#define SBI_EVENT_CAUSE_SHIFT		3
+
+/* Probe and Check if the card is present*/
+int libertas_sbi_register_dev(wlan_private * priv);
+int libertas_sbi_unregister_dev(wlan_private *);
+int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
+int libertas_sbi_register(void);
+void libertas_sbi_unregister(void);
+int libertas_sbi_prog_firmware(wlan_private *);
+
+int libertas_sbi_read_event_cause(wlan_private *);
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+wlan_private *libertas_sbi_get_priv(void *card);
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private *);
+int libertas_sbi_resume(wlan_private *);
+#endif
+
+#endif				/* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644
index 0000000..e187062
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.c
@@ -0,0 +1,2044 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Functions implementing wlan scan IOCTL and firmware command APIs
+  *
+  * IOCTL handlers as well as command preperation and response routines
+  *  for sending scan commands to the firmware.
+  */
+#include <linux/ctype.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "scan.h"
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                             + IW_ESSID_MAX_SIZE        \
+                             + IW_EV_UINT_LEN           \
+                             + IW_EV_FREQ_LEN           \
+                             + IW_EV_QUAL_LEN           \
+                             + IW_ESSID_MAX_SIZE        \
+                             + IW_EV_PARAM_LEN          \
+                             + 40)	/* 40 for WPAIE */
+
+//! Memory needed to store a max sized channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvlietypesheader)    \
+                            + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
+                               * sizeof(struct chanscanparamset)))
+
+//! Memory needed to store a max number/size SSID TLV for a firmware scan
+#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvlietypes_ssidparamset))
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config)  \
+                            + sizeof(struct mrvlietypes_numprobes)   \
+                            + CHAN_TLV_MAX_SIZE                 \
+                            + SSID_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SCAN   14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ *  Number restricted to prevent hitting the limit on the amount of scan data
+ *  returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD   4
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME  100
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) 1
+#endif
+
+/**
+ *  @brief Check if a scanned network compatible with the driver settings
+ *
+ *   WEP     WPA     WPA2    ad-hoc  encrypt                      Network
+ * enabled enabled  enabled   AES     mode   privacy  WPA  WPA2  Compatible
+ *    0       0        0       0      NONE      0      0    0   yes No security
+ *    1       0        0       0      NONE      1      0    0   yes Static WEP
+ *    0       1        0       0       x        1x     1    x   yes WPA
+ *    0       0        1       0       x        1x     x    1   yes WPA2
+ *    0       0        0       1      NONE      1      0    0   yes Ad-hoc AES
+ *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
+ *
+ *
+ *  @param adapter A pointer to wlan_adapter
+ *  @param index   Index in scantable to check against current driver settings
+ *  @param mode    Network mode: Infrastructure or IBSS
+ *
+ *  @return        Index in scantable, or error code if negative
+ */
+static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
+{
+	ENTER();
+
+	if (adapter->scantable[index].inframode == mode) {
+		if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+		    && !adapter->secinfo.WPAenabled
+		    && !adapter->secinfo.WPA2enabled
+		    && adapter->scantable[index].wpa_supplicant.wpa_ie[0] !=
+		    WPA_IE
+		    && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] !=
+		    WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE
+		    && !adapter->scantable[index].privacy) {
+			/* no security */
+			LEAVE();
+			return index;
+		} else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
+			   && !adapter->secinfo.WPAenabled
+			   && !adapter->secinfo.WPA2enabled
+			   && adapter->scantable[index].privacy) {
+			/* static WEP enabled */
+			LEAVE();
+			return index;
+		} else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+			   && adapter->secinfo.WPAenabled
+			   && !adapter->secinfo.WPA2enabled
+			   && (adapter->scantable[index].wpa_supplicant.
+			       wpa_ie[0]
+			       == WPA_IE)
+			   /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+			      && adapter->scantable[index].privacy */
+		    ) {
+			/* WPA enabled */
+            lbs_pr_debug(1,
+			       "is_network_compatible() WPA: index=%d wpa_ie=%#x "
+			       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+			       "privacy=%#x\n", index,
+			       adapter->scantable[index].wpa_supplicant.
+			       wpa_ie[0],
+			       adapter->scantable[index].wpa2_supplicant.
+			       wpa_ie[0],
+			       (adapter->secinfo.WEPstatus ==
+				wlan802_11WEPenabled) ? "e" : "d",
+			       (adapter->secinfo.WPAenabled) ? "e" : "d",
+			       (adapter->secinfo.WPA2enabled) ? "e" : "d",
+			       adapter->secinfo.Encryptionmode,
+			       adapter->scantable[index].privacy);
+			LEAVE();
+			return index;
+		} else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+			   && !adapter->secinfo.WPAenabled
+			   && adapter->secinfo.WPA2enabled
+			   && (adapter->scantable[index].wpa2_supplicant.
+			       wpa_ie[0]
+			       == WPA2_IE)
+			   /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+			      && adapter->scantable[index].privacy */
+		    ) {
+			/* WPA2 enabled */
+            lbs_pr_debug(1,
+			       "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+			       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+			       "privacy=%#x\n", index,
+			       adapter->scantable[index].wpa_supplicant.
+			       wpa_ie[0],
+			       adapter->scantable[index].wpa2_supplicant.
+			       wpa_ie[0],
+			       (adapter->secinfo.WEPstatus ==
+				wlan802_11WEPenabled) ? "e" : "d",
+			       (adapter->secinfo.WPAenabled) ? "e" : "d",
+			       (adapter->secinfo.WPA2enabled) ? "e" : "d",
+			       adapter->secinfo.Encryptionmode,
+			       adapter->scantable[index].privacy);
+			LEAVE();
+			return index;
+		} else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+			   && !adapter->secinfo.WPAenabled
+			   && !adapter->secinfo.WPA2enabled
+			   && (adapter->scantable[index].wpa_supplicant.
+			       wpa_ie[0]
+			       != WPA_IE)
+			   && (adapter->scantable[index].wpa2_supplicant.
+			       wpa_ie[0]
+			       != WPA2_IE)
+			   && adapter->secinfo.Encryptionmode != CIPHER_NONE
+			   && adapter->scantable[index].privacy) {
+			/* dynamic WEP enabled */
+            lbs_pr_debug(1,
+			       "is_network_compatible() dynamic WEP: index=%d "
+			       "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
+			       index,
+			       adapter->scantable[index].wpa_supplicant.
+			       wpa_ie[0],
+			       adapter->scantable[index].wpa2_supplicant.
+			       wpa_ie[0], adapter->secinfo.Encryptionmode,
+			       adapter->scantable[index].privacy);
+			LEAVE();
+			return index;
+		}
+
+		/* security doesn't match */
+        lbs_pr_debug(1,
+		       "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
+		       index,
+		       adapter->scantable[index].wpa_supplicant.wpa_ie[0],
+		       adapter->scantable[index].wpa2_supplicant.wpa_ie[0],
+		       (adapter->secinfo.WEPstatus ==
+			wlan802_11WEPenabled) ? "e" : "d",
+		       (adapter->secinfo.WPAenabled) ? "e" : "d",
+		       (adapter->secinfo.WPA2enabled) ? "e" : "d",
+		       adapter->secinfo.Encryptionmode,
+		       adapter->scantable[index].privacy);
+		LEAVE();
+		return -ECONNREFUSED;
+	}
+
+	/* mode doesn't match */
+	LEAVE();
+	return -ENETUNREACH;
+}
+
+/**
+ *  @brief This function validates a SSID as being able to be printed
+ *
+ *  @param pssid   SSID structure to validate
+ *
+ *  @return        TRUE or FALSE
+ */
+static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
+{
+	int ssididx;
+
+	for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
+		if (!isprint(pssid->ssid[ssididx])) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/**
+ *  @brief Post process the scan table after a new scan command has completed
+ *
+ *  Inspect each entry of the scan table and try to find an entry that
+ *    matches our current associated/joined network from the scan.  If
+ *    one is found, update the stored copy of the bssdescriptor for our
+ *    current network.
+ *
+ *  Debug dump the current scan table contents if compiled accordingly.
+ *
+ *  @param priv   A pointer to wlan_private structure
+ *
+ *  @return       void
+ */
+static void wlan_scan_process_results(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int foundcurrent;
+	int i;
+
+	foundcurrent = 0;
+
+	if (adapter->connect_status == libertas_connected) {
+		/* try to find the current BSSID in the new scan list */
+		for (i = 0; i < adapter->numinscantable; i++) {
+			if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
+				     &adapter->curbssparams.ssid) &&
+			    !memcmp(adapter->curbssparams.bssid,
+				    adapter->scantable[i].macaddress,
+				    ETH_ALEN)) {
+				foundcurrent = 1;
+			}
+		}
+
+		if (foundcurrent) {
+			/* Make a copy of current BSSID descriptor */
+			memcpy(&adapter->curbssparams.bssdescriptor,
+			       &adapter->scantable[i],
+			       sizeof(adapter->curbssparams.bssdescriptor));
+		}
+	}
+
+	for (i = 0; i < adapter->numinscantable; i++) {
+		lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+		       "RSSI[%03d], SSID[%s]\n",
+		       i,
+		       adapter->scantable[i].macaddress[0],
+		       adapter->scantable[i].macaddress[1],
+		       adapter->scantable[i].macaddress[2],
+		       adapter->scantable[i].macaddress[3],
+		       adapter->scantable[i].macaddress[4],
+		       adapter->scantable[i].macaddress[5],
+		       (s32) adapter->scantable[i].rssi,
+		       adapter->scantable[i].ssid.ssid);
+	}
+}
+
+/**
+ *  @brief Create a channel list for the driver to scan based on region info
+ *
+ *  Use the driver region/band information to construct a comprehensive list
+ *    of channels to scan.  This routine is used for any scan that is not
+ *    provided a specific channel list to scan.
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param scanchanlist  Output parameter: resulting channel list to scan
+ *  @param filteredscan  Flag indicating whether or not a BSSID or SSID filter
+ *                       is being sent in the command to firmware.  Used to
+ *                       increase the number of channels sent in a scan
+ *                       command and to disable the firmware channel scan
+ *                       filter.
+ *
+ *  @return              void
+ */
+static void wlan_scan_create_channel_list(wlan_private * priv,
+					  struct chanscanparamset * scanchanlist,
+					  u8 filteredscan)
+{
+
+	wlan_adapter *adapter = priv->adapter;
+	struct region_channel *scanregion;
+	struct chan_freq_power *cfp;
+	int rgnidx;
+	int chanidx;
+	int nextchan;
+	u8 scantype;
+
+	chanidx = 0;
+
+	/* Set the default scan type to the user specified type, will later
+	 *   be changed to passive on a per channel basis if restricted by
+	 *   regulatory requirements (11d or 11h)
+	 */
+	scantype = adapter->scantype;
+
+	for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+		if (priv->adapter->enable11d &&
+		    adapter->connect_status != libertas_connected) {
+			/* Scan all the supported chan for the first scan */
+			if (!adapter->universal_channel[rgnidx].valid)
+				continue;
+			scanregion = &adapter->universal_channel[rgnidx];
+
+			/* clear the parsed_region_chan for the first scan */
+			memset(&adapter->parsed_region_chan, 0x00,
+			       sizeof(adapter->parsed_region_chan));
+		} else {
+			if (!adapter->region_channel[rgnidx].valid)
+				continue;
+			scanregion = &adapter->region_channel[rgnidx];
+		}
+
+		for (nextchan = 0;
+		     nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+
+			cfp = scanregion->CFP + nextchan;
+
+			if (priv->adapter->enable11d) {
+				scantype =
+				    libertas_get_scan_type_11d(cfp->channel,
+							   &adapter->
+							   parsed_region_chan);
+			}
+
+			switch (scanregion->band) {
+			case BAND_B:
+			case BAND_G:
+			default:
+				scanchanlist[chanidx].radiotype =
+				    cmd_scan_radio_type_bg;
+				break;
+			}
+
+			if (scantype == cmd_scan_type_passive) {
+				scanchanlist[chanidx].maxscantime =
+				    cpu_to_le16
+				    (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+				scanchanlist[chanidx].chanscanmode.passivescan =
+				    1;
+			} else {
+				scanchanlist[chanidx].maxscantime =
+				    cpu_to_le16
+				    (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
+				scanchanlist[chanidx].chanscanmode.passivescan =
+				    0;
+			}
+
+			scanchanlist[chanidx].channumber = cfp->channel;
+
+			if (filteredscan) {
+				scanchanlist[chanidx].chanscanmode.
+				    disablechanfilt = 1;
+			}
+		}
+	}
+}
+
+/**
+ *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ *  Application layer or other functions can invoke wlan_scan_networks
+ *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ *    This structure is used as the basis of one or many wlan_scan_cmd_config
+ *    commands that are sent to the command processing module and sent to
+ *    firmware.
+ *
+ *  Create a wlan_scan_cmd_config based on the following user supplied
+ *    parameters (if present):
+ *             - SSID filter
+ *             - BSSID filter
+ *             - Number of Probes to be sent
+ *             - channel list
+ *
+ *  If the SSID or BSSID filter is not present, disable/clear the filter.
+ *  If the number of probes is not set, use the adapter default setting
+ *  Qualify the channel
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param puserscanin      NULL or pointer to scan configuration parameters
+ *  @param ppchantlvout     Output parameter: Pointer to the start of the
+ *                          channel TLV portion of the output scan config
+ *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
+ *                          list to scan
+ *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
+ *                          each issuance of the firmware scan command
+ *  @param pfilteredscan    Output parameter: Flag indicating whether or not
+ *                          a BSSID or SSID filter is being sent in the
+ *                          command to firmware.  Used to increase the number
+ *                          of channels sent in a scan command and to
+ *                          disable the firmware channel scan filter.
+ *  @param pscancurrentonly Output parameter: Flag indicating whether or not
+ *                          we are only scanning our current active channel
+ *
+ *  @return                 resulting scan configuration
+ */
+static struct wlan_scan_cmd_config *
+wlan_scan_setup_scan_config(wlan_private * priv,
+			    const struct wlan_ioctl_user_scan_cfg * puserscanin,
+			    struct mrvlietypes_chanlistparamset ** ppchantlvout,
+			    struct chanscanparamset * pscanchanlist,
+			    int *pmaxchanperscan,
+			    u8 * pfilteredscan,
+			    u8 * pscancurrentonly)
+{
+	wlan_adapter *adapter = priv->adapter;
+	const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+	struct mrvlietypes_numprobes *pnumprobestlv;
+	struct mrvlietypes_ssidparamset *pssidtlv;
+	struct wlan_scan_cmd_config * pscancfgout = NULL;
+	u8 *ptlvpos;
+	u16 numprobes;
+	u16 ssidlen;
+	int chanidx;
+	int scantype;
+	int scandur;
+	int channel;
+	int radiotype;
+
+	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+	if (pscancfgout == NULL)
+		goto out;
+
+	/* The tlvbufferlen is calculated for each scan command.  The TLVs added
+	 *   in this routine will be preserved since the routine that sends
+	 *   the command will append channelTLVs at *ppchantlvout.  The difference
+	 *   between the *ppchantlvout and the tlvbuffer start will be used
+	 *   to calculate the size of anything we add in this routine.
+	 */
+	pscancfgout->tlvbufferlen = 0;
+
+	/* Running tlv pointer.  Assigned to ppchantlvout at end of function
+	 *  so later routines know where channels can be added to the command buf
+	 */
+	ptlvpos = pscancfgout->tlvbuffer;
+
+	/*
+	 * Set the initial scan paramters for progressive scanning.  If a specific
+	 *   BSSID or SSID is used, the number of channels in the scan command
+	 *   will be increased to the absolute maximum
+	 */
+	*pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+	/* Initialize the scan as un-filtered by firmware, set to TRUE below if
+	 *   a SSID or BSSID filter is sent in the command
+	 */
+	*pfilteredscan = 0;
+
+	/* Initialize the scan as not being only on the current channel.  If
+	 *   the channel list is customized, only contains one channel, and
+	 *   is the active channel, this is set true and data flow is not halted.
+	 */
+	*pscancurrentonly = 0;
+
+	if (puserscanin) {
+
+		/* Set the bss type scan filter, use adapter setting if unset */
+		pscancfgout->bsstype =
+		    (puserscanin->bsstype ? puserscanin->bsstype : adapter->
+		     scanmode);
+
+		/* Set the number of probes to send, use adapter setting if unset */
+		numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
+			     adapter->scanprobes);
+
+		/*
+		 * Set the BSSID filter to the incoming configuration,
+		 *   if non-zero.  If not set, it will remain disabled (all zeros).
+		 */
+		memcpy(pscancfgout->specificBSSID,
+		       puserscanin->specificBSSID,
+		       sizeof(pscancfgout->specificBSSID));
+
+		ssidlen = strlen(puserscanin->specificSSID);
+
+		if (ssidlen) {
+			pssidtlv =
+			    (struct mrvlietypes_ssidparamset *) pscancfgout->
+			    tlvbuffer;
+			pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+			pssidtlv->header.len = cpu_to_le16(ssidlen);
+			memcpy(pssidtlv->ssid, puserscanin->specificSSID,
+			       ssidlen);
+			ptlvpos += sizeof(pssidtlv->header) + ssidlen;
+		}
+
+		/*
+		 *  The default number of channels sent in the command is low to
+		 *    ensure the response buffer from the firmware does not truncate
+		 *    scan results.  That is not an issue with an SSID or BSSID
+		 *    filter applied to the scan results in the firmware.
+		 */
+		if (ssidlen || (memcmp(pscancfgout->specificBSSID,
+				       &zeromac, sizeof(zeromac)) != 0)) {
+			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+			*pfilteredscan = 1;
+		}
+	} else {
+		pscancfgout->bsstype = adapter->scanmode;
+		numprobes = adapter->scanprobes;
+	}
+
+	/* If the input config or adapter has the number of Probes set, add tlv */
+	if (numprobes) {
+		pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
+		pnumprobestlv->header.type =
+		    cpu_to_le16(TLV_TYPE_NUMPROBES);
+		pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
+		pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+
+		ptlvpos +=
+		    sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
+
+		pnumprobestlv->header.len =
+		    cpu_to_le16(pnumprobestlv->header.len);
+	}
+
+	/*
+	 * Set the output for the channel TLV to the address in the tlv buffer
+	 *   past any TLVs that were added in this fuction (SSID, numprobes).
+	 *   channel TLVs will be added past this for each scan command, preserving
+	 *   the TLVs that were previously added.
+	 */
+	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+
+	if (puserscanin && puserscanin->chanlist[0].channumber) {
+
+		lbs_pr_debug(1, "Scan: Using supplied channel list\n");
+
+		for (chanidx = 0;
+		     chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+		     && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+
+			channel = puserscanin->chanlist[chanidx].channumber;
+			(pscanchanlist + chanidx)->channumber = channel;
+
+			radiotype = puserscanin->chanlist[chanidx].radiotype;
+			(pscanchanlist + chanidx)->radiotype = radiotype;
+
+			scantype = puserscanin->chanlist[chanidx].scantype;
+
+			if (scantype == cmd_scan_type_passive) {
+				(pscanchanlist +
+				 chanidx)->chanscanmode.passivescan = 1;
+			} else {
+				(pscanchanlist +
+				 chanidx)->chanscanmode.passivescan = 0;
+			}
+
+			if (puserscanin->chanlist[chanidx].scantime) {
+				scandur =
+				    puserscanin->chanlist[chanidx].scantime;
+			} else {
+				if (scantype == cmd_scan_type_passive) {
+					scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+				} else {
+					scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+				}
+			}
+
+			(pscanchanlist + chanidx)->minscantime =
+			    cpu_to_le16(scandur);
+			(pscanchanlist + chanidx)->maxscantime =
+			    cpu_to_le16(scandur);
+		}
+
+		/* Check if we are only scanning the current channel */
+		if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
+				       ==
+				       priv->adapter->curbssparams.channel)) {
+			*pscancurrentonly = 1;
+			lbs_pr_debug(1, "Scan: Scanning current channel only");
+		}
+
+	} else {
+		lbs_pr_debug(1, "Scan: Creating full region channel list\n");
+		wlan_scan_create_channel_list(priv, pscanchanlist,
+					      *pfilteredscan);
+	}
+
+out:
+	return pscancfgout;
+}
+
+/**
+ *  @brief Construct and send multiple scan config commands to the firmware
+ *
+ *  Previous routines have created a wlan_scan_cmd_config with any requested
+ *   TLVs.  This function splits the channel TLV into maxchanperscan lists
+ *   and sends the portion of the channel TLV along with the other TLVs
+ *   to the wlan_cmd routines for execution in the firmware.
+ *
+ *  @param priv            A pointer to wlan_private structure
+ *  @param maxchanperscan  Maximum number channels to be included in each
+ *                         scan command sent to firmware
+ *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
+ *                         filter is being used for the firmware command
+ *                         scan command sent to firmware
+ *  @param pscancfgout     Scan configuration used for this scan.
+ *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
+ *                         should start.  This is past any other TLVs that
+ *                         must be sent down in each firmware command.
+ *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
+ *
+ *  @return                0 or error return otherwise
+ */
+static int wlan_scan_channel_list(wlan_private * priv,
+				  int maxchanperscan,
+				  u8 filteredscan,
+				  struct wlan_scan_cmd_config * pscancfgout,
+				  struct mrvlietypes_chanlistparamset * pchantlvout,
+				  struct chanscanparamset * pscanchanlist)
+{
+	struct chanscanparamset *ptmpchan;
+	struct chanscanparamset *pstartchan;
+	u8 scanband;
+	int doneearly;
+	int tlvidx;
+	int ret = 0;
+
+	ENTER();
+
+	if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+		lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
+		       pscancfgout, pchantlvout, pscanchanlist);
+		return -1;
+	}
+
+	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+	/* Set the temp channel struct pointer to the start of the desired list */
+	ptmpchan = pscanchanlist;
+
+	/* Loop through the desired channel list, sending a new firmware scan
+	 *   commands for each maxchanperscan channels (or for 1,6,11 individually
+	 *   if configured accordingly)
+	 */
+	while (ptmpchan->channumber) {
+
+		tlvidx = 0;
+		pchantlvout->header.len = 0;
+		scanband = ptmpchan->radiotype;
+		pstartchan = ptmpchan;
+		doneearly = 0;
+
+		/* Construct the channel TLV for the scan command.  Continue to
+		 *  insert channel TLVs until:
+		 *    - the tlvidx hits the maximum configured per scan command
+		 *    - the next channel to insert is 0 (end of desired channel list)
+		 *    - doneearly is set (controlling individual scanning of 1,6,11)
+		 */
+		while (tlvidx < maxchanperscan && ptmpchan->channumber
+		       && !doneearly) {
+
+            lbs_pr_debug(1,
+                    "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
+                ptmpchan->channumber, ptmpchan->radiotype,
+                ptmpchan->chanscanmode.passivescan,
+                ptmpchan->chanscanmode.disablechanfilt,
+                ptmpchan->maxscantime);
+
+			/* Copy the current channel TLV to the command being prepared */
+			memcpy(pchantlvout->chanscanparam + tlvidx,
+			       ptmpchan, sizeof(pchantlvout->chanscanparam));
+
+			/* Increment the TLV header length by the size appended */
+			pchantlvout->header.len +=
+			    sizeof(pchantlvout->chanscanparam);
+
+			/*
+			 *  The tlv buffer length is set to the number of bytes of the
+			 *    between the channel tlv pointer and the start of the
+			 *    tlv buffer.  This compensates for any TLVs that were appended
+			 *    before the channel list.
+			 */
+			pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
+						     - pscancfgout->tlvbuffer);
+
+			/*  Add the size of the channel tlv header and the data length */
+			pscancfgout->tlvbufferlen +=
+			    (sizeof(pchantlvout->header)
+			     + pchantlvout->header.len);
+
+			/* Increment the index to the channel tlv we are constructing */
+			tlvidx++;
+
+			doneearly = 0;
+
+			/* Stop the loop if the *current* channel is in the 1,6,11 set
+			 *   and we are not filtering on a BSSID or SSID.
+			 */
+			if (!filteredscan && (ptmpchan->channumber == 1
+					      || ptmpchan->channumber == 6
+					      || ptmpchan->channumber == 11)) {
+				doneearly = 1;
+			}
+
+			/* Increment the tmp pointer to the next channel to be scanned */
+			ptmpchan++;
+
+			/* Stop the loop if the *next* channel is in the 1,6,11 set.
+			 *  This will cause it to be the only channel scanned on the next
+			 *  interation
+			 */
+			if (!filteredscan && (ptmpchan->channumber == 1
+					      || ptmpchan->channumber == 6
+					      || ptmpchan->channumber == 11)) {
+				doneearly = 1;
+			}
+		}
+
+		/* Send the scan command to the firmware with the specified cfg */
+		ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+					    0, 0, pscancfgout);
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Internal function used to start a scan based on an input config
+ *
+ *  Use the input user scan configuration information when provided in
+ *    order to send the appropriate scan commands to firmware to populate or
+ *    update the internal driver scan table
+ *
+ *  @param priv          A pointer to wlan_private structure
+ *  @param puserscanin   Pointer to the input configuration for the requested
+ *                       scan.
+ *
+ *  @return              0 or < 0 if error
+ */
+int wlan_scan_networks(wlan_private * priv,
+			      const struct wlan_ioctl_user_scan_cfg * puserscanin)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct mrvlietypes_chanlistparamset *pchantlvout;
+	struct chanscanparamset * scan_chan_list = NULL;
+	struct wlan_scan_cmd_config * scan_cfg = NULL;
+	u8 keeppreviousscan;
+	u8 filteredscan;
+	u8 scancurrentchanonly;
+	int maxchanperscan;
+	int ret;
+
+	ENTER();
+
+	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+				WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+	if (scan_chan_list == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	scan_cfg = wlan_scan_setup_scan_config(priv,
+					       puserscanin,
+					       &pchantlvout,
+					       scan_chan_list,
+					       &maxchanperscan,
+					       &filteredscan,
+					       &scancurrentchanonly);
+	if (scan_cfg == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	keeppreviousscan = 0;
+
+	if (puserscanin) {
+		keeppreviousscan = puserscanin->keeppreviousscan;
+	}
+
+	if (!keeppreviousscan) {
+		memset(adapter->scantable, 0x00,
+		       sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
+		adapter->numinscantable = 0;
+	}
+
+	/* Keep the data path active if we are only scanning our current channel */
+	if (!scancurrentchanonly) {
+		netif_stop_queue(priv->wlan_dev.netdev);
+		netif_carrier_off(priv->wlan_dev.netdev);
+	}
+
+	ret = wlan_scan_channel_list(priv,
+				     maxchanperscan,
+				     filteredscan,
+				     scan_cfg,
+				     pchantlvout,
+				     scan_chan_list);
+
+	/*  Process the resulting scan table:
+	 *    - Remove any bad ssids
+	 *    - Update our current BSS information from scan data
+	 */
+	wlan_scan_process_results(priv);
+
+	if (priv->adapter->connect_status == libertas_connected) {
+		netif_carrier_on(priv->wlan_dev.netdev);
+		netif_wake_queue(priv->wlan_dev.netdev);
+	}
+
+out:
+	if (scan_cfg)
+		kfree(scan_cfg);
+
+	if (scan_chan_list)
+		kfree(scan_chan_list);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ *  TLVs can be included at the end of the scan response BSS information.
+ *    Parse the data in the buffer for pointers to TLVs that can potentially
+ *    be passed back in the response
+ *
+ *  @param ptlv        Pointer to the start of the TLV buffer to parse
+ *  @param tlvbufsize  size of the TLV buffer
+ *  @param ptsftlv     Output parameter: Pointer to the TSF TLV if found
+ *
+ *  @return            void
+ */
+static
+void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
+				       int tlvbufsize,
+				       struct mrvlietypes_tsftimestamp ** ptsftlv)
+{
+	struct mrvlietypes_data *pcurrenttlv;
+	int tlvbufleft;
+	u16 tlvtype;
+	u16 tlvlen;
+
+	pcurrenttlv = ptlv;
+	tlvbufleft = tlvbufsize;
+	*ptsftlv = NULL;
+
+	lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+	lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+
+	while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+		tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+		tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+
+		switch (tlvtype) {
+		case TLV_TYPE_TSFTIMESTAMP:
+			*ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+			break;
+
+		default:
+			lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
+			       tlvtype);
+			/* Give up, this seems corrupted */
+			return;
+		}		/* switch */
+
+		tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
+		pcurrenttlv =
+		    (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
+	}			/* while */
+}
+
+/**
+ *  @brief Interpret a BSS scan response returned from the firmware
+ *
+ *  Parse the various fixed fields and IEs passed back for a a BSS probe
+ *   response or beacon from the scan command.  Record information as needed
+ *   in the scan table struct bss_descriptor for that entry.
+ *
+ *  @param pBSSIDEntry  Output parameter: Pointer to the BSS Entry
+ *
+ *  @return             0 or -1
+ */
+static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
+					 u8 ** pbeaconinfo, int *bytesleft)
+{
+	enum ieeetypes_elementid elemID;
+	struct ieeetypes_fhparamset *pFH;
+	struct ieeetypes_dsparamset *pDS;
+	struct ieeetypes_cfparamset *pCF;
+	struct ieeetypes_ibssparamset *pibss;
+	struct ieeetypes_capinfo *pcap;
+	struct WLAN_802_11_FIXED_IEs fixedie;
+	u8 *pcurrentptr;
+	u8 *pRate;
+	u8 elemlen;
+	u8 bytestocopy;
+	u8 ratesize;
+	u16 beaconsize;
+	u8 founddatarateie;
+	int bytesleftforcurrentbeacon;
+
+	struct WPA_SUPPLICANT *pwpa_supplicant;
+	struct WPA_SUPPLICANT *pwpa2_supplicant;
+	struct IE_WPA *pIe;
+	const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+	struct ieeetypes_countryinfoset *pcountryinfo;
+
+	ENTER();
+
+	founddatarateie = 0;
+	ratesize = 0;
+	beaconsize = 0;
+
+	if (*bytesleft >= sizeof(beaconsize)) {
+		/* Extract & convert beacon size from the command buffer */
+		memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
+		beaconsize = le16_to_cpu(beaconsize);
+		*bytesleft -= sizeof(beaconsize);
+		*pbeaconinfo += sizeof(beaconsize);
+	}
+
+	if (beaconsize == 0 || beaconsize > *bytesleft) {
+
+		*pbeaconinfo += *bytesleft;
+		*bytesleft = 0;
+
+		return -1;
+	}
+
+	/* Initialize the current working beacon pointer for this BSS iteration */
+	pcurrentptr = *pbeaconinfo;
+
+	/* Advance the return beacon pointer past the current beacon */
+	*pbeaconinfo += beaconsize;
+	*bytesleft -= beaconsize;
+
+	bytesleftforcurrentbeacon = beaconsize;
+
+	pwpa_supplicant = &pBSSEntry->wpa_supplicant;
+	pwpa2_supplicant = &pBSSEntry->wpa2_supplicant;
+
+	memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
+	lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
+	       pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
+	       pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
+	       pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
+
+	pcurrentptr += ETH_ALEN;
+	bytesleftforcurrentbeacon -= ETH_ALEN;
+
+	if (bytesleftforcurrentbeacon < 12) {
+		lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
+		return -1;
+	}
+
+	/*
+	 * next 4 fields are RSSI, time stamp, beacon interval,
+	 *   and capability information
+	 */
+
+	/* RSSI is 1 byte long */
+	pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
+	lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
+	pcurrentptr += 1;
+	bytesleftforcurrentbeacon -= 1;
+
+	/* time stamp is 8 bytes long */
+	memcpy(fixedie.timestamp, pcurrentptr, 8);
+	memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
+	pcurrentptr += 8;
+	bytesleftforcurrentbeacon -= 8;
+
+	/* beacon interval is 2 bytes long */
+	memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
+	pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
+	pcurrentptr += 2;
+	bytesleftforcurrentbeacon -= 2;
+
+	/* capability information is 2 bytes long */
+	memcpy(&fixedie.capabilities, pcurrentptr, 2);
+	lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
+	       fixedie.capabilities);
+	fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
+	pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
+	memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
+	pcurrentptr += 2;
+	bytesleftforcurrentbeacon -= 2;
+
+	/* rest of the current buffer are IE's */
+	lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
+	       bytesleftforcurrentbeacon);
+
+	lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
+		bytesleftforcurrentbeacon);
+
+	if (pcap->privacy) {
+		lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
+		pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
+	} else {
+		pBSSEntry->privacy = wlan802_11privfilteracceptall;
+	}
+
+	if (pcap->ibss == 1) {
+		pBSSEntry->inframode = wlan802_11ibss;
+	} else {
+		pBSSEntry->inframode = wlan802_11infrastructure;
+	}
+
+	/* process variable IE */
+	while (bytesleftforcurrentbeacon >= 2) {
+		elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+		elemlen = *((u8 *) pcurrentptr + 1);
+
+		if (bytesleftforcurrentbeacon < elemlen) {
+			lbs_pr_debug(1, "InterpretIE: error in processing IE, "
+			       "bytes left < IE length\n");
+			bytesleftforcurrentbeacon = 0;
+			continue;
+		}
+
+		switch (elemID) {
+
+		case SSID:
+			pBSSEntry->ssid.ssidlength = elemlen;
+			memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
+			       elemlen);
+			lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
+			break;
+
+		case SUPPORTED_RATES:
+			memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
+			       elemlen);
+			memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
+				elemlen);
+			ratesize = elemlen;
+			founddatarateie = 1;
+			break;
+
+		case EXTRA_IE:
+			lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
+			pBSSEntry->extra_ie = 1;
+			break;
+
+		case FH_PARAM_SET:
+			pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+			memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
+				sizeof(struct ieeetypes_fhparamset));
+			pBSSEntry->phyparamset.fhparamset.dwelltime
+			    =
+			    le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
+					     dwelltime);
+			break;
+
+		case DS_PARAM_SET:
+			pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+
+			pBSSEntry->channel = pDS->currentchan;
+
+			memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
+			       sizeof(struct ieeetypes_dsparamset));
+			break;
+
+		case CF_PARAM_SET:
+			pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+
+			memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
+			       sizeof(struct ieeetypes_cfparamset));
+			break;
+
+		case IBSS_PARAM_SET:
+			pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+			pBSSEntry->atimwindow =
+			    le32_to_cpu(pibss->atimwindow);
+
+			memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
+				sizeof(struct ieeetypes_ibssparamset));
+
+			pBSSEntry->ssparamset.ibssparamset.atimwindow
+			    =
+			    le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
+					     atimwindow);
+			break;
+
+			/* Handle Country Info IE */
+		case COUNTRY_INFO:
+			pcountryinfo =
+			    (struct ieeetypes_countryinfoset *) pcurrentptr;
+
+			if (pcountryinfo->len <
+			    sizeof(pcountryinfo->countrycode)
+			    || pcountryinfo->len > 254) {
+				lbs_pr_debug(1, "InterpretIE: 11D- Err "
+				       "CountryInfo len =%d min=%d max=254\n",
+				       pcountryinfo->len,
+				       sizeof(pcountryinfo->countrycode));
+				LEAVE();
+				return -1;
+			}
+
+			memcpy(&pBSSEntry->countryinfo,
+			       pcountryinfo, pcountryinfo->len + 2);
+			lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
+				(u8 *) pcountryinfo,
+				(u32) (pcountryinfo->len + 2));
+			break;
+
+		case EXTENDED_SUPPORTED_RATES:
+			/*
+			 * only process extended supported rate
+			 * if data rate is already found.
+			 * data rate IE should come before
+			 * extended supported rate IE
+			 */
+			if (founddatarateie) {
+				if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
+					bytestocopy =
+					    (WLAN_SUPPORTED_RATES - ratesize);
+				} else {
+					bytestocopy = elemlen;
+				}
+
+				pRate = (u8 *) pBSSEntry->datarates;
+				pRate += ratesize;
+				memmove(pRate, (pcurrentptr + 2), bytestocopy);
+
+				pRate = (u8 *) pBSSEntry->libertas_supported_rates;
+
+				pRate += ratesize;
+				memmove(pRate, (pcurrentptr + 2), bytestocopy);
+			}
+			break;
+
+		case VENDOR_SPECIFIC_221:
+#define IE_ID_LEN_FIELDS_BYTES 2
+			pIe = (struct IE_WPA *)pcurrentptr;
+
+			if (!memcmp(pIe->oui, oui01, sizeof(oui01))) {
+				pwpa_supplicant->wpa_ie_len
+				    = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+					  sizeof(pwpa_supplicant->wpa_ie));
+				memcpy(pwpa_supplicant->wpa_ie,
+				       pcurrentptr,
+				       pwpa_supplicant->wpa_ie_len);
+				lbs_dbg_hex("InterpretIE: Resp WPA_IE",
+					pwpa_supplicant->wpa_ie, elemlen);
+			}
+			break;
+		case WPA2_IE:
+			pIe = (struct IE_WPA *)pcurrentptr;
+			pwpa2_supplicant->wpa_ie_len
+			    = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+				  sizeof(pwpa2_supplicant->wpa_ie));
+			memcpy(pwpa2_supplicant->wpa_ie,
+			       pcurrentptr, pwpa2_supplicant->wpa_ie_len);
+
+			lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
+				pwpa2_supplicant->wpa_ie, elemlen);
+			break;
+		case TIM:
+			break;
+
+		case CHALLENGE_TEXT:
+			break;
+		}
+
+		pcurrentptr += elemlen + 2;
+
+		/* need to account for IE ID and IE len */
+		bytesleftforcurrentbeacon -= (elemlen + 2);
+
+	}			/* while (bytesleftforcurrentbeacon > 2) */
+
+	return 0;
+}
+
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0--ssid is same, otherwise is different
+ */
+int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
+{
+	if (!ssid1 || !ssid2)
+		return -1;
+
+	if (ssid1->ssidlength != ssid2->ssidlength)
+		return -1;
+
+	return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
+}
+
+/**
+ *  @brief This function finds a specific compatible BSSID in the scan list
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *  @param bssid    BSSID to find in the scan list
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list, or error return code (< 0)
+ */
+int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
+{
+	int ret = -ENETUNREACH;
+	int i;
+
+	if (!bssid)
+		return -EFAULT;
+
+	lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
+	       adapter->numinscantable);
+
+	/* Look through the scan table for a compatible match. The ret return
+	 *   variable will be equal to the index in the scan table (greater
+	 *   than zero) if the network is compatible.  The loop will continue
+	 *   past a matched bssid that is not compatible in case there is an
+	 *   AP with multiple SSIDs assigned to the same BSSID
+	 */
+	for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
+		if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
+			switch (mode) {
+			case wlan802_11infrastructure:
+			case wlan802_11ibss:
+				ret = is_network_compatible(adapter, i, mode);
+				break;
+			default:
+				ret = i;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+/**
+ *  @brief This function finds ssid in ssid list.
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *  @param ssid     SSID to find in the list
+ *  @param bssid    BSSID to qualify the SSID selection (if provided)
+ *  @param mode     Network mode: Infrastructure or IBSS
+ *
+ *  @return         index in BSSID list
+ */
+int libertas_find_SSID_in_list(wlan_adapter * adapter,
+		   struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
+{
+	int net = -ENETUNREACH;
+	u8 bestrssi = 0;
+	int i;
+	int j;
+
+	lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
+
+	for (i = 0; i < adapter->numinscantable; i++) {
+		if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
+		    (!bssid ||
+		     !memcmp(adapter->scantable[i].
+			     macaddress, bssid, ETH_ALEN))) {
+			switch (mode) {
+			case wlan802_11infrastructure:
+			case wlan802_11ibss:
+				j = is_network_compatible(adapter, i, mode);
+
+				if (j >= 0) {
+					if (bssid) {
+						return i;
+					}
+
+					if (SCAN_RSSI
+					    (adapter->scantable[i].rssi)
+					    > bestrssi) {
+						bestrssi =
+						    SCAN_RSSI(adapter->
+							      scantable[i].
+							      rssi);
+						net = i;
+					}
+				} else {
+					if (net == -ENETUNREACH) {
+						net = j;
+					}
+				}
+				break;
+			case wlan802_11autounknown:
+			default:
+				if (SCAN_RSSI(adapter->scantable[i].rssi)
+				    > bestrssi) {
+					bestrssi =
+					    SCAN_RSSI(adapter->scantable[i].
+						      rssi);
+					net = i;
+				}
+				break;
+			}
+		}
+	}
+
+	return net;
+}
+
+/**
+ *  @brief This function finds the best SSID in the Scan List
+ *
+ *  Search the scan table for the best SSID that also matches the current
+ *   adapter network preference (infrastructure or adhoc)
+ *
+ *  @param adapter  A pointer to wlan_adapter
+ *
+ *  @return         index in BSSID list
+ */
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
+{
+	int bestnet = -ENETUNREACH;
+	u8 bestrssi = 0;
+	int i;
+
+	ENTER();
+
+	lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
+
+	for (i = 0; i < adapter->numinscantable; i++) {
+		switch (mode) {
+		case wlan802_11infrastructure:
+		case wlan802_11ibss:
+			if (is_network_compatible(adapter, i, mode) >= 0) {
+				if (SCAN_RSSI(adapter->scantable[i].rssi) >
+				    bestrssi) {
+					bestrssi =
+					    SCAN_RSSI(adapter->scantable[i].
+						      rssi);
+					bestnet = i;
+				}
+			}
+			break;
+		case wlan802_11autounknown:
+		default:
+			if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
+				bestrssi =
+				    SCAN_RSSI(adapter->scantable[i].rssi);
+				bestnet = i;
+			}
+			break;
+		}
+	}
+
+	LEAVE();
+	return bestnet;
+}
+
+/**
+ *  @brief Find the AP with specific ssid in the scan list
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @param pSSID        A pointer to AP's ssid
+ *
+ *  @return             0--success, otherwise--fail
+ */
+int libertas_find_best_network_SSID(wlan_private * priv,
+                                    struct WLAN_802_11_SSID *pSSID,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct bss_descriptor *preqbssid;
+	int i;
+
+	ENTER();
+
+	memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
+
+	wlan_scan_networks(priv, NULL);
+	if (adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+	i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
+	if (i < 0) {
+		ret = -1;
+		goto out;
+	}
+
+	preqbssid = &adapter->scantable[i];
+	memcpy(pSSID, &preqbssid->ssid,
+	       sizeof(struct WLAN_802_11_SSID));
+	*out_mode = preqbssid->inframode;
+
+	if (!pSSID->ssidlength) {
+		ret = -1;
+	}
+
+out:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Scan Network
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	union iwreq_data wrqu;
+
+	ENTER();
+
+	if (!wlan_scan_networks(priv, NULL)) {
+		memset(&wrqu, 0, sizeof(union iwreq_data));
+		wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+				    NULL);
+	}
+
+	if (adapter->surpriseremoved)
+		return -1;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Send a scan command for all available channels filtered on a spec
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param prequestedssid   A pointer to AP's ssid
+ *  @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ *  @return                0-success, otherwise fail
+ */
+int libertas_send_specific_SSID_scan(wlan_private * priv,
+			 struct WLAN_802_11_SSID *prequestedssid,
+			 u8 keeppreviousscan)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_ioctl_user_scan_cfg scancfg;
+
+	ENTER();
+
+	if (prequestedssid == NULL) {
+		return -1;
+	}
+
+	memset(&scancfg, 0x00, sizeof(scancfg));
+
+	memcpy(scancfg.specificSSID, prequestedssid->ssid,
+	       prequestedssid->ssidlength);
+	scancfg.keeppreviousscan = keeppreviousscan;
+
+	wlan_scan_networks(priv, &scancfg);
+	if (adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief scan an AP with specific BSSID
+ *
+ *  @param priv             A pointer to wlan_private structure
+ *  @param bssid            A pointer to AP's bssid
+ *  @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ *  @return          0-success, otherwise fail
+ */
+int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
+{
+	struct wlan_ioctl_user_scan_cfg scancfg;
+
+	ENTER();
+
+	if (bssid == NULL) {
+		return -1;
+	}
+
+	memset(&scancfg, 0x00, sizeof(scancfg));
+	memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
+	scancfg.keeppreviousscan = keeppreviousscan;
+
+	wlan_scan_networks(priv, &scancfg);
+	if (priv->adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(priv->adapter->cmd_pending,
+		!priv->adapter->nr_cmd_pending);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param dwrq         A pointer to iw_point structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_point *dwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	char *current_ev = extra;
+	char *end_buf = extra + IW_SCAN_MAX_DATA;
+	struct chan_freq_power *cfp;
+	struct bss_descriptor *pscantable;
+	char *current_val;	/* For rates */
+	struct iw_event iwe;	/* Temporary buffer */
+	int i;
+	int j;
+	int rate;
+#define PERFECT_RSSI ((u8)50)
+#define WORST_RSSI   ((u8)0)
+#define RSSI_DIFF    ((u8)(PERFECT_RSSI - WORST_RSSI))
+	u8 rssi;
+
+	u8 buf[16 + 256 * 2];
+	u8 *ptr;
+
+	ENTER();
+
+	/*
+	 * if there's either commands in the queue or one being
+	 * processed return -EAGAIN for iwlist to retry later.
+	 */
+    if (adapter->nr_cmd_pending)
+		return -EAGAIN;
+
+	if (adapter->connect_status == libertas_connected)
+		lbs_pr_debug(1, "Current ssid: %32s\n",
+		       adapter->curbssparams.ssid.ssid);
+
+	lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
+	       adapter->numinscantable);
+
+	/* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+	 * The new API using SIOCGIWSCAN is only limited by buffer size
+	 * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+	 * which is 4096.
+	 */
+	for (i = 0; i < adapter->numinscantable; i++) {
+		if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+			lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
+			       "MAX_SCAN_CELL_SIZE=%d\n",
+			       i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+			break;
+		}
+
+		pscantable = &adapter->scantable[i];
+
+		lbs_pr_debug(1, "i=%d  ssid: %32s\n", i, pscantable->ssid.ssid);
+
+		cfp =
+		    libertas_find_cfp_by_band_and_channel(adapter, 0,
+						 pscantable->channel);
+		if (!cfp) {
+			lbs_pr_debug(1, "Invalid channel number %d\n",
+			       pscantable->channel);
+			continue;
+		}
+
+		if (!ssid_valid(&adapter->scantable[i].ssid)) {
+			continue;
+		}
+
+		/* First entry *MUST* be the AP MAC address */
+		iwe.cmd = SIOCGIWAP;
+		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+		memcpy(iwe.u.ap_addr.sa_data,
+		       &adapter->scantable[i].macaddress, ETH_ALEN);
+
+		iwe.len = IW_EV_ADDR_LEN;
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+		//Add the ESSID
+		iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
+
+		if (iwe.u.data.length > 32) {
+			iwe.u.data.length = 32;
+		}
+
+		iwe.cmd = SIOCGIWESSID;
+		iwe.u.data.flags = 1;
+		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  adapter->scantable[i].ssid.
+						  ssid);
+
+		//Add mode
+		iwe.cmd = SIOCGIWMODE;
+		iwe.u.mode = adapter->scantable[i].inframode + 1;
+		iwe.len = IW_EV_UINT_LEN;
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+		//frequency
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = (long)cfp->freq * 100000;
+		iwe.u.freq.e = 1;
+		iwe.len = IW_EV_FREQ_LEN;
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+		/* Add quality statistics */
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
+		iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
+
+		rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
+		iwe.u.qual.qual =
+		    (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
+		     (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
+		    (RSSI_DIFF * RSSI_DIFF);
+		if (iwe.u.qual.qual > 100)
+			iwe.u.qual.qual = 100;
+		else if (iwe.u.qual.qual < 1)
+			iwe.u.qual.qual = 0;
+
+		if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+			iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+		} else {
+			iwe.u.qual.noise =
+			    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+		}
+		if ((adapter->inframode == wlan802_11ibss) &&
+		    !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+			     &adapter->scantable[i].ssid)
+		    && adapter->adhoccreate) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_rssi,
+						    0,
+						    cmd_option_waitforrsp,
+						    0, NULL);
+
+			if (!ret) {
+				iwe.u.qual.level =
+				    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
+					     AVG_SCALE,
+					     adapter->NF[TYPE_RXPD][TYPE_AVG] /
+					     AVG_SCALE);
+			}
+		}
+		iwe.len = IW_EV_QUAL_LEN;
+		current_ev =
+		    iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+		/* Add encryption capability */
+		iwe.cmd = SIOCGIWENCODE;
+		if (adapter->scantable[i].privacy) {
+			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+		} else {
+			iwe.u.data.flags = IW_ENCODE_DISABLED;
+		}
+		iwe.u.data.length = 0;
+		iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  adapter->scantable->ssid.
+						  ssid);
+
+		current_val = current_ev + IW_EV_LCP_LEN;
+
+		iwe.cmd = SIOCGIWRATE;
+
+		iwe.u.bitrate.fixed = 0;
+		iwe.u.bitrate.disabled = 0;
+		iwe.u.bitrate.value = 0;
+
+		/* Bit rate given in 500 kb/s units (+ 0x80) */
+		for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
+		     j++) {
+			if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
+				break;
+			}
+			rate =
+			    (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
+			    500000;
+			if (rate > iwe.u.bitrate.value) {
+				iwe.u.bitrate.value = rate;
+			}
+
+			iwe.u.bitrate.value =
+			    (adapter->scantable[i].libertas_supported_rates[j]
+			     & 0x7f) * 500000;
+			iwe.len = IW_EV_PARAM_LEN;
+			current_ev =
+			    iwe_stream_add_value(current_ev, current_val,
+						 end_buf, &iwe, iwe.len);
+
+		}
+		if ((adapter->scantable[i].inframode == wlan802_11ibss)
+		    && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+				&adapter->scantable[i].ssid)
+		    && adapter->adhoccreate) {
+			iwe.u.bitrate.value = 22 * 500000;
+		}
+		iwe.len = IW_EV_PARAM_LEN;
+		current_ev =
+		    iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+					 iwe.len);
+
+		/* Add new value to event */
+		current_val = current_ev + IW_EV_LCP_LEN;
+
+		if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) {
+			memset(&iwe, 0, sizeof(iwe));
+			memset(buf, 0, sizeof(buf));
+			memcpy(buf, adapter->scantable[i].
+						wpa2_supplicant.wpa_ie,
+					adapter->scantable[i].wpa2_supplicant.
+						wpa_ie_len);
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = adapter->scantable[i].
+					wpa2_supplicant.wpa_ie_len;
+			iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+					&iwe, buf);
+		}
+		if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) {
+			memset(&iwe, 0, sizeof(iwe));
+			memset(buf, 0, sizeof(buf));
+			memcpy(buf, adapter->scantable[i].
+						wpa_supplicant.wpa_ie,
+					adapter->scantable[i].wpa_supplicant.
+						wpa_ie_len);
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = adapter->scantable[i].
+					wpa_supplicant.wpa_ie_len;
+			iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+					&iwe, buf);
+		}
+
+
+		if (adapter->scantable[i].extra_ie != 0) {
+			memset(&iwe, 0, sizeof(iwe));
+			memset(buf, 0, sizeof(buf));
+			ptr = buf;
+			ptr += sprintf(ptr, "extra_ie");
+			iwe.u.data.length = strlen(buf);
+
+			lbs_pr_debug(1, "iwe.u.data.length %d\n",
+			       iwe.u.data.length);
+			lbs_pr_debug(1, "BUF: %s \n", buf);
+
+			iwe.cmd = IWEVCUSTOM;
+			iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+			current_ev =
+			    iwe_stream_add_point(current_ev, end_buf, &iwe,
+						 buf);
+		}
+
+		current_val = current_ev + IW_EV_LCP_LEN;
+
+		/*
+		 * Check if we added any event
+		 */
+		if ((current_val - current_ev) > IW_EV_LCP_LEN)
+			current_ev = current_val;
+	}
+
+	dwrq->length = (current_ev - extra);
+	dwrq->flags = 0;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Prepare a scan command to be sent to the firmware
+ *
+ *  Use the wlan_scan_cmd_config sent to the command processing module in
+ *   the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
+ *   struct to send to firmware.
+ *
+ *  The fixed fields specifying the BSS type and BSSID filters as well as a
+ *   variable number/length of TLVs are sent in the command to firmware.
+ *
+ *  @param priv       A pointer to wlan_private structure
+ *  @param cmd        A pointer to cmd_ds_command structure to be sent to
+ *                    firmware with the cmd_DS_801_11_SCAN structure
+ *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
+ *                    to set the fields/TLVs for the command sent to firmware
+ *
+ *  @return           0 or -1
+ *
+ *  @sa wlan_scan_create_channel_list
+ */
+int libertas_cmd_80211_scan(wlan_private * priv,
+			 struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+	struct wlan_scan_cmd_config *pscancfg;
+
+	ENTER();
+
+	pscancfg = pdata_buf;
+
+	/* Set fixed field variables in scan command */
+	pscan->bsstype = pscancfg->bsstype;
+	memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
+	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
+
+	cmd->command = cpu_to_le16(cmd_802_11_scan);
+
+	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
+	cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+				     + sizeof(pscan->BSSID)
+				     + pscancfg->tlvbufferlen + S_DS_GEN);
+
+	lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+	       cmd->command, cmd->size, cmd->seqnum);
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function handles the command response of scan
+ *
+ *   The response buffer for the scan command has the following
+ *      memory layout:
+ *
+ *     .-----------------------------------------------------------.
+ *     |  header (4 * sizeof(u16)):  Standard command response hdr |
+ *     .-----------------------------------------------------------.
+ *     |  bufsize (u16) : sizeof the BSS Description data          |
+ *     .-----------------------------------------------------------.
+ *     |  NumOfSet (u8) : Number of BSS Descs returned             |
+ *     .-----------------------------------------------------------.
+ *     |  BSSDescription data (variable, size given in bufsize)    |
+ *     .-----------------------------------------------------------.
+ *     |  TLV data (variable, size calculated using header->size,  |
+ *     |            bufsize and sizeof the fixed fields above)     |
+ *     .-----------------------------------------------------------.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param resp    A pointer to cmd_ds_command
+ *
+ *  @return        0 or -1
+ */
+int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_scan_rsp *pscan;
+	struct bss_descriptor newbssentry;
+	struct mrvlietypes_data *ptlv;
+	struct mrvlietypes_tsftimestamp *ptsftlv;
+	u8 *pbssinfo;
+	u16 scanrespsize;
+	int bytesleft;
+	int numintable;
+	int bssIdx;
+	int idx;
+	int tlvbufsize;
+	u64 tsfval;
+
+	ENTER();
+
+	pscan = &resp->params.scanresp;
+
+	if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
+        lbs_pr_debug(1,
+		       "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+		       pscan->nr_sets);
+		LEAVE();
+		return -1;
+	}
+
+	bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+	lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+	scanrespsize = le16_to_cpu(resp->size);
+	lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
+	       pscan->nr_sets);
+
+	numintable = adapter->numinscantable;
+	pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+	/* The size of the TLV buffer is equal to the entire command response
+	 *   size (scanrespsize) minus the fixed fields (sizeof()'s), the
+	 *   BSS Descriptions (bssdescriptsize as bytesLef) and the command
+	 *   response header (S_DS_GEN)
+	 */
+	tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
+				     + sizeof(pscan->nr_sets)
+				     + S_DS_GEN);
+
+	ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
+
+	/* Search the TLV buffer space in the scan response for any valid TLVs */
+	wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
+
+	/*
+	 *  Process each scan response returned (pscan->nr_sets).  Save
+	 *    the information in the newbssentry and then insert into the
+	 *    driver scan table either as an update to an existing entry
+	 *    or as an addition at the end of the table
+	 */
+	for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
+		/* Zero out the newbssentry we are about to store info in */
+		memset(&newbssentry, 0x00, sizeof(newbssentry));
+
+		/* Process the data fields and IEs returned for this BSS */
+		if ((InterpretBSSDescriptionWithIE(&newbssentry,
+						   &pbssinfo,
+						   &bytesleft) ==
+		     0)
+		    && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
+
+            lbs_pr_debug(1,
+			       "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+			       newbssentry.macaddress[0],
+			       newbssentry.macaddress[1],
+			       newbssentry.macaddress[2],
+			       newbssentry.macaddress[3],
+			       newbssentry.macaddress[4],
+			       newbssentry.macaddress[5]);
+
+			/*
+			 * Search the scan table for the same bssid
+			 */
+			for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
+				if (memcmp(newbssentry.macaddress,
+					   adapter->scantable[bssIdx].
+					   macaddress,
+					   sizeof(newbssentry.macaddress)) ==
+				    0) {
+					/*
+					 * If the SSID matches as well, it is a duplicate of
+					 *   this entry.  Keep the bssIdx set to this
+					 *   entry so we replace the old contents in the table
+					 */
+					if ((newbssentry.ssid.ssidlength ==
+					     adapter->scantable[bssIdx].ssid.
+					     ssidlength)
+					    &&
+					    (memcmp
+					     (newbssentry.ssid.ssid,
+					      adapter->scantable[bssIdx].ssid.
+					      ssid,
+					      newbssentry.ssid.ssidlength) ==
+					     0)) {
+                        lbs_pr_debug(1,
+						       "SCAN_RESP: Duplicate of index: %d\n",
+						       bssIdx);
+						break;
+					}
+				}
+			}
+			/*
+			 * If the bssIdx is equal to the number of entries in the table,
+			 *   the new entry was not a duplicate; append it to the scan
+			 *   table
+			 */
+			if (bssIdx == numintable) {
+				/* Range check the bssIdx, keep it limited to the last entry */
+				if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+					bssIdx--;
+				} else {
+					numintable++;
+				}
+			}
+
+			/*
+			 * If the TSF TLV was appended to the scan results, save the
+			 *   this entries TSF value in the networktsf field.  The
+			 *   networktsf is the firmware's TSF value at the time the
+			 *   beacon or probe response was received.
+			 */
+			if (ptsftlv) {
+				memcpy(&tsfval, &ptsftlv->tsftable[idx],
+				       sizeof(tsfval));
+				tsfval = le64_to_cpu(tsfval);
+
+				memcpy(&newbssentry.networktsf,
+				       &tsfval, sizeof(newbssentry.networktsf));
+			}
+
+			/* Copy the locally created newbssentry to the scan table */
+			memcpy(&adapter->scantable[bssIdx],
+			       &newbssentry,
+			       sizeof(adapter->scantable[bssIdx]));
+
+		} else {
+
+			/* error parsing/interpreting the scan response, skipped */
+			lbs_pr_debug(1, "SCAN_RESP: "
+			       "InterpretBSSDescriptionWithIE returned ERROR\n");
+		}
+	}
+
+	lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+	       pscan->nr_sets, numintable - adapter->numinscantable,
+	       numintable);
+
+	/* Update the total number of BSSIDs in the scan table */
+	adapter->numinscantable = numintable;
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644
index 0000000..d93aa7f
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.h
@@ -0,0 +1,216 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Interface for the wlan network scan routines
+  *
+  * Driver interface functions and type declarations for the scan module
+  *   implemented in wlan_scan.c.
+  */
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+#include "hostcmd.h"
+
+/**
+ *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ *  @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX  50
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS         1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS        2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY         3
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ *   scan command prepared by libertas_cmd_80211_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+struct wlan_scan_cmd_config {
+    /**
+     *  @brief BSS type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+	u8 bsstype;
+
+    /**
+     *  @brief Specific BSSID used to filter scan results in the firmware
+     */
+	u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief length of TLVs sent in command starting at tlvBuffer
+     */
+	int tlvbufferlen;
+
+    /**
+     *  @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+     *
+     *  @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
+     *  @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
+     */
+	u8 tlvbuffer[1];	//!< SSID TLV(s) and ChanList TLVs are stored here
+};
+
+/**
+ *  @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ *  Multiple instances of this structure are included in the IOCTL command
+ *   to configure a instance of a scan on the specific channel.
+ */
+struct wlan_ioctl_user_scan_chan {
+	u8 channumber;		//!< channel Number to scan
+	u8 radiotype;		//!< Radio type: 'B/G' band = 0, 'A' band = 1
+	u8 scantype;		//!< Scan type: Active = 0, Passive = 1
+	u16 scantime;		//!< Scan duration in milliseconds; if 0 default used
+};
+
+/**
+ *  @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ *  Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl.  Specifies
+ *   a number of parameters to be used in general for the scan as well
+ *   as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ *   desired.
+ *
+ *  @sa libertas_set_user_scan_ioctl
+ */
+struct wlan_ioctl_user_scan_cfg {
+
+    /**
+     *  @brief Flag set to keep the previous scan table intact
+     *
+     *  If set, the scan results will accumulate, replacing any previous
+     *   matched entries for a BSS with the new scan data
+     */
+	u8 keeppreviousscan;	//!< Do not erase the existing scan results
+
+    /**
+     *  @brief BSS type to be sent in the firmware command
+     *
+     *  Field can be used to restrict the types of networks returned in the
+     *    scan.  valid settings are:
+     *
+     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     */
+	u8 bsstype;
+
+    /**
+     *  @brief Configure the number of probe requests for active chan scans
+     */
+	u8 numprobes;
+
+    /**
+     *  @brief BSSID filter sent in the firmware command to limit the results
+     */
+	u8 specificBSSID[ETH_ALEN];
+
+    /**
+     *  @brief SSID filter sent in the firmware command to limit the results
+     */
+	char specificSSID[IW_ESSID_MAX_SIZE + 1];
+
+    /**
+     *  @brief Variable number (fixed maximum) of channels to scan up
+     */
+	struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+};
+
+/**
+ *  @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+	u8 macaddress[ETH_ALEN];
+
+	struct WLAN_802_11_SSID ssid;
+
+	/* WEP encryption requirement */
+	u32 privacy;
+
+	/* receive signal strength in dBm */
+	long rssi;
+
+	u32 channel;
+
+	u16 beaconperiod;
+
+	u32 atimwindow;
+
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+	u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
+
+	int extra_ie;
+
+	u8 timestamp[8];	//!< TSF value included in the beacon/probe response
+	union ieeetypes_phyparamset phyparamset;
+	union IEEEtypes_ssparamset ssparamset;
+	struct ieeetypes_capinfo cap;
+	u8 datarates[WLAN_SUPPORTED_RATES];
+
+	__le64 networktsf;		//!< TSF timestamp from the current firmware TSF
+
+	struct ieeetypes_countryinfofullset countryinfo;
+
+	struct WPA_SUPPLICANT wpa_supplicant;
+	struct WPA_SUPPLICANT wpa2_supplicant;
+
+};
+
+extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
+		   struct WLAN_802_11_SSID *ssid2);
+extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
+			  u8 * bssid, int mode);
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
+extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
+
+int libertas_find_best_network_SSID(wlan_private * priv,
+			struct WLAN_802_11_SSID *pSSID,
+			enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+			enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
+
+extern int libertas_send_specific_SSID_scan(wlan_private * priv,
+				struct WLAN_802_11_SSID *prequestedssid,
+				u8 keeppreviousscan);
+extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
+				 u8 * bssid, u8 keeppreviousscan);
+
+extern int libertas_cmd_80211_scan(wlan_private * priv,
+				struct cmd_ds_command *cmd,
+				void *pdata_buf);
+
+extern int libertas_ret_80211_scan(wlan_private * priv,
+				struct cmd_ds_command *resp);
+
+int wlan_scan_networks(wlan_private * priv,
+                const struct wlan_ioctl_user_scan_cfg * puserscanin);
+
+struct ifreq;
+
+struct iw_point;
+struct iw_param;
+struct iw_request_info;
+extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_point *dwrq, char *extra);
+extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_param *vwrq, char *extra);
+
+#endif				/* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644
index 0000000..207b8a6
--- /dev/null
+++ b/drivers/net/wireless/libertas/thread.h
@@ -0,0 +1,52 @@
+#ifndef	__WLAN_THREAD_H_
+#define	__WLAN_THREAD_H_
+
+#include	<linux/kthread.h>
+
+struct wlan_thread {
+	struct task_struct *task;
+	wait_queue_head_t waitq;
+	pid_t pid;
+	void *priv;
+};
+
+static inline void wlan_activate_thread(struct wlan_thread * thr)
+{
+	/** Record the thread pid */
+	thr->pid = current->pid;
+
+	/** Initialize the wait queue */
+	init_waitqueue_head(&thr->waitq);
+}
+
+static inline void wlan_deactivate_thread(struct wlan_thread * thr)
+{
+	ENTER();
+
+	thr->pid = 0;
+
+	LEAVE();
+}
+
+static inline void wlan_create_thread(int (*wlanfunc) (void *),
+				      struct wlan_thread * thr, char *name)
+{
+	thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int wlan_terminate_thread(struct wlan_thread * thr)
+{
+	ENTER();
+
+	/* Check if the thread is active or not */
+	if (!thr->pid) {
+		printk(KERN_ERR "Thread does not exist\n");
+		return -1;
+	}
+	kthread_stop(thr->task);
+
+	LEAVE();
+	return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644
index 0000000..82d0622
--- /dev/null
+++ b/drivers/net/wireless/libertas/tx.c
@@ -0,0 +1,285 @@
+/**
+  * This file contains the handling of TX in wlan driver.
+  */
+#include <linux/netdevice.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "wext.h"
+
+/**
+ *  @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ *  units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ *
+ *  @param rate    Input rate
+ *  @return      Output Rate (0 if invalid)
+ */
+static u32 convert_radiotap_rate_to_mv(u8 rate)
+{
+	switch (rate) {
+	case 2:		/*   1 Mbps */
+		return 0 | (1 << 4);
+	case 4:		/*   2 Mbps */
+		return 1 | (1 << 4);
+	case 11:		/* 5.5 Mbps */
+		return 2 | (1 << 4);
+	case 22:		/*  11 Mbps */
+		return 3 | (1 << 4);
+	case 12:		/*   6 Mbps */
+		return 4 | (1 << 4);
+	case 18:		/*   9 Mbps */
+		return 5 | (1 << 4);
+	case 24:		/*  12 Mbps */
+		return 6 | (1 << 4);
+	case 36:		/*  18 Mbps */
+		return 7 | (1 << 4);
+	case 48:		/*  24 Mbps */
+		return 8 | (1 << 4);
+	case 72:		/*  36 Mbps */
+		return 9 | (1 << 4);
+	case 96:		/*  48 Mbps */
+		return 10 | (1 << 4);
+	case 108:		/*  54 Mbps */
+		return 11 | (1 << 4);
+	}
+	return 0;
+}
+
+/**
+ *  @brief This function processes a single packet and sends
+ *  to IF layer
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @param skb     A pointer to skb which includes TX packet
+ *  @return 	   0 or -1
+ */
+static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct txpd localtxpd;
+	struct txpd *plocaltxpd = &localtxpd;
+	u8 *p802x_hdr;
+	struct tx_radiotap_hdr *pradiotap_hdr;
+	u32 new_rate;
+	u8 *ptr = priv->adapter->tmptxbuf;
+
+	ENTER();
+
+	if (priv->adapter->surpriseremoved)
+		return -1;
+
+	if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+		lbs_dbg_hex("TX packet: ", skb->data,
+			 min_t(unsigned int, skb->len, 100));
+
+	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+		lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
+		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+		ret = -1;
+		goto done;
+	}
+
+	memset(plocaltxpd, 0, sizeof(struct txpd));
+
+	plocaltxpd->tx_packet_length = skb->len;
+
+	/* offset of actual data */
+	plocaltxpd->tx_packet_location = sizeof(struct txpd);
+
+	/* TxCtrl set by user or default */
+	plocaltxpd->tx_control = adapter->pkttxctrl;
+
+	p802x_hdr = skb->data;
+	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+
+		/* locate radiotap header */
+		pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+
+		/* set txpd fields from the radiotap header */
+		new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+		if (new_rate != 0) {
+			/* erase tx_control[4:0] */
+			plocaltxpd->tx_control &= ~0x1f;
+			/* write new tx_control[4:0] */
+			plocaltxpd->tx_control |= new_rate;
+		}
+
+		/* skip the radiotap header */
+		p802x_hdr += sizeof(struct tx_radiotap_hdr);
+		plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
+
+	}
+	/* copy destination address from 802.3 or 802.11 header */
+	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+	else
+		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+	lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+
+	if (IS_MESH_FRAME(skb)) {
+		plocaltxpd->tx_control |= TxPD_MESH_FRAME;
+	}
+
+	memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+
+	ptr += sizeof(struct txpd);
+
+	lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
+	memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
+	ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
+			       priv->adapter->tmptxbuf,
+			       plocaltxpd->tx_packet_length +
+			       sizeof(struct txpd));
+
+	if (ret) {
+		lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
+		goto done;
+	}
+
+	lbs_pr_debug(1, "SendSinglePacket succeeds\n");
+
+      done:
+	if (!ret) {
+		priv->stats.tx_packets++;
+		priv->stats.tx_bytes += skb->len;
+	} else {
+		priv->stats.tx_dropped++;
+		priv->stats.tx_errors++;
+	}
+
+	if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+		/* Keep the skb to echo it back once Tx feedback is
+		   received from FW */
+		skb_orphan(skb);
+		/* stop processing outgoing pkts */
+		netif_stop_queue(priv->wlan_dev.netdev);
+		/* freeze any packets already in our queues */
+		priv->adapter->TxLockFlag = 1;
+	} else {
+		dev_kfree_skb_any(skb);
+		priv->adapter->currenttxskb = NULL;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+
+void libertas_tx_runqueue(wlan_private *priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i;
+
+	spin_lock(&adapter->txqueue_lock);
+	for (i = 0; i < adapter->tx_queue_idx; i++) {
+		struct sk_buff *skb = adapter->tx_queue_ps[i];
+		spin_unlock(&adapter->txqueue_lock);
+		SendSinglePacket(priv, skb);
+		spin_lock(&adapter->txqueue_lock);
+	}
+	adapter->tx_queue_idx = 0;
+	spin_unlock(&adapter->txqueue_lock);
+}
+
+static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	spin_lock(&adapter->txqueue_lock);
+
+	WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
+	adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
+	if (adapter->tx_queue_idx == NR_TX_QUEUE)
+		netif_stop_queue(priv->wlan_dev.netdev);
+	else
+		netif_start_queue(priv->wlan_dev.netdev);
+
+	spin_unlock(&adapter->txqueue_lock);
+}
+
+/**
+ *  @brief This function checks the conditions and sends packet to IF
+ *  layer if everything is ok.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   n/a
+ */
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
+{
+	int ret = -1;
+
+	ENTER();
+
+	lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+	if (priv->wlan_dev.dnld_sent) {
+		lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
+		       priv->wlan_dev.dnld_sent);
+		goto done;
+	}
+
+	if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+	    (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
+		wlan_tx_queue(priv, skb);
+		return ret;
+	}
+
+	priv->adapter->currenttxskb = skb;
+
+	ret = SendSinglePacket(priv, skb);
+done:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function sends to the host the last transmitted packet,
+ *  filling the radiotap headers with transmission information.
+ *
+ *  @param priv     A pointer to wlan_private structure
+ *  @param status   A 32 bit value containing transmission status.
+ *
+ *  @returns void
+ */
+void libertas_send_tx_feedback(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct tx_radiotap_hdr *radiotap_hdr;
+	u32 status = adapter->eventcause;
+	int txfail;
+	int try_count;
+
+	if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+	    adapter->currenttxskb == NULL)
+		return;
+
+	radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+
+	if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+		lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
+			min_t(unsigned int, adapter->currenttxskb->len, 100));
+
+	txfail = (status >> 24);
+
+#if 0
+	/* The version of roofnet that we've tested does not use this yet
+	 * But it may be used in the future.
+	 */
+	if (txfail)
+		radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
+#endif
+	try_count = (status >> 16) & 0xff;
+	radiotap_hdr->data_retries = (try_count) ?
+	    (1 + adapter->txretrycount - try_count) : 0;
+	libertas_upload_rx_packet(priv, adapter->currenttxskb);
+	adapter->currenttxskb = NULL;
+	priv->adapter->TxLockFlag = 0;
+	if (priv->adapter->connect_status == libertas_connected)
+		netif_wake_queue(priv->wlan_dev.netdev);
+}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644
index 0000000..09d62f8
--- /dev/null
+++ b/drivers/net/wireless/libertas/types.h
@@ -0,0 +1,289 @@
+/**
+  * This header file contains definition for global types
+  */
+#ifndef _WLAN_TYPES_
+#define _WLAN_TYPES_
+
+#include <linux/if_ether.h>
+
+/** IEEE type definitions  */
+enum ieeetypes_elementid {
+	SSID = 0,
+	SUPPORTED_RATES,
+	FH_PARAM_SET,
+	DS_PARAM_SET,
+	CF_PARAM_SET,
+	TIM,
+	IBSS_PARAM_SET,
+	COUNTRY_INFO = 7,
+
+	CHALLENGE_TEXT = 16,
+
+	EXTENDED_SUPPORTED_RATES = 50,
+
+	VENDOR_SPECIFIC_221 = 221,
+
+	WPA_IE = 221,
+	WPA2_IE = 48,
+
+	EXTRA_IE = 133,
+} __attribute__ ((packed));
+
+#define CAPINFO_MASK	(~(0xda00))
+
+struct ieeetypes_capinfo {
+	u8 ess:1;
+	u8 ibss:1;
+	u8 cfpollable:1;
+	u8 cfpollrqst:1;
+	u8 privacy:1;
+	u8 shortpreamble:1;
+	u8 pbcc:1;
+	u8 chanagility:1;
+	u8 spectrummgmt:1;
+	u8 rsrvd3:1;
+	u8 shortslottime:1;
+	u8 apsd:1;
+	u8 rsvrd2:1;
+	u8 dsssofdm:1;
+	u8 rsrvd1:2;
+} __attribute__ ((packed));
+
+struct ieeetypes_cfparamset {
+	u8 elementid;
+	u8 len;
+	u8 cfpcnt;
+	u8 cfpperiod;
+	u16 cfpmaxduration;
+	u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+
+struct ieeetypes_ibssparamset {
+	u8 elementid;
+	u8 len;
+	u16 atimwindow;
+} __attribute__ ((packed));
+
+union IEEEtypes_ssparamset {
+	struct ieeetypes_cfparamset cfparamset;
+	struct ieeetypes_ibssparamset ibssparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_fhparamset {
+	u8 elementid;
+	u8 len;
+	u16 dwelltime;
+	u8 hopset;
+	u8 hoppattern;
+	u8 hopindex;
+} __attribute__ ((packed));
+
+struct ieeetypes_dsparamset {
+	u8 elementid;
+	u8 len;
+	u8 currentchan;
+} __attribute__ ((packed));
+
+union ieeetypes_phyparamset {
+	struct ieeetypes_fhparamset fhparamset;
+	struct ieeetypes_dsparamset dsparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_assocrsp {
+	struct ieeetypes_capinfo capability;
+	u16 statuscode;
+	u16 aid;
+	u8 iebuffer[1];
+} __attribute__ ((packed));
+
+/** TLV  type ID definition */
+#define PROPRIETARY_TLV_BASE_ID		0x0100
+
+/* Terminating TLV type */
+#define MRVL_TERMINATE_TLV_ID		0xffff
+
+#define TLV_TYPE_SSID				0x0000
+#define TLV_TYPE_RATES				0x0001
+#define TLV_TYPE_PHY_FH				0x0002
+#define TLV_TYPE_PHY_DS				0x0003
+#define TLV_TYPE_CF				    0x0004
+#define TLV_TYPE_IBSS				0x0006
+
+#define TLV_TYPE_DOMAIN				0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY	0x0021
+
+#define TLV_TYPE_KEY_MATERIAL       (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST           (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES          (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW           (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW            (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT          (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS            (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO           (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR        (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH        (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_REASSOCAP          (PROPRIETARY_TLV_BASE_ID + 11)
+#define TLV_TYPE_POWER_TBL_2_4GHZ   (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ     (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_BCASTPROBE	    (PROPRIETARY_TLV_BASE_ID + 14)
+#define TLV_TYPE_NUMSSID_PROBE	    (PROPRIETARY_TLV_BASE_ID + 15)
+#define TLV_TYPE_WMMQSTATUS   	    (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_CRYPTO_DATA	    (PROPRIETARY_TLV_BASE_ID + 17)
+#define TLV_TYPE_WILDCARDSSID	    (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP	    (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+
+/** TLV related data structures*/
+struct mrvlietypesheader {
+	u16 type;
+	u16 len;
+} __attribute__ ((packed));
+
+struct mrvlietypes_data {
+	struct mrvlietypesheader header;
+	u8 Data[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ratesparamset {
+	struct mrvlietypesheader header;
+	u8 rates[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssidparamset {
+	struct mrvlietypesheader header;
+	u8 ssid[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_wildcardssidparamset {
+	struct mrvlietypesheader header;
+	u8 MaxSsidlength;
+	u8 ssid[1];
+} __attribute__ ((packed));
+
+struct chanscanmode {
+	u8 passivescan:1;
+	u8 disablechanfilt:1;
+	u8 reserved_2_7:6;
+} __attribute__ ((packed));
+
+struct chanscanparamset {
+	u8 radiotype;
+	u8 channumber;
+	struct chanscanmode chanscanmode;
+	u16 minscantime;
+	u16 maxscantime;
+} __attribute__ ((packed));
+
+struct mrvlietypes_chanlistparamset {
+	struct mrvlietypesheader header;
+	struct chanscanparamset chanscanparam[1];
+} __attribute__ ((packed));
+
+struct cfparamset {
+	u8 cfpcnt;
+	u8 cfpperiod;
+	u16 cfpmaxduration;
+	u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+struct ibssparamset {
+	u16 atimwindow;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssparamset {
+	struct mrvlietypesheader header;
+	union {
+		struct cfparamset cfparamset[1];
+		struct ibssparamset ibssparamset[1];
+	} cf_ibss;
+} __attribute__ ((packed));
+
+struct fhparamset {
+	u16 dwelltime;
+	u8 hopset;
+	u8 hoppattern;
+	u8 hopindex;
+} __attribute__ ((packed));
+
+struct dsparamset {
+	u8 currentchan;
+} __attribute__ ((packed));
+
+struct mrvlietypes_phyparamset {
+	struct mrvlietypesheader header;
+	union {
+		struct fhparamset fhparamset[1];
+		struct dsparamset dsparamset[1];
+	} fh_ds;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rsnparamset {
+	struct mrvlietypesheader header;
+	u8 rsnie[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_tsftimestamp {
+	struct mrvlietypesheader header;
+	__le64 tsftable[1];
+} __attribute__ ((packed));
+
+/**  Local Power capability */
+struct mrvlietypes_powercapability {
+	struct mrvlietypesheader header;
+	s8 minpower;
+	s8 maxpower;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rssithreshold {
+	struct mrvlietypesheader header;
+	u8 rssivalue;
+	u8 rssifreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_snrthreshold {
+	struct mrvlietypesheader header;
+	u8 snrvalue;
+	u8 snrfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_failurecount {
+	struct mrvlietypesheader header;
+	u8 failvalue;
+	u8 Failfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_beaconsmissed {
+	struct mrvlietypesheader header;
+	u8 beaconmissed;
+	u8 reserved;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numprobes {
+	struct mrvlietypesheader header;
+	u16 numprobes;
+} __attribute__ ((packed));
+
+struct mrvlietypes_bcastprobe {
+	struct mrvlietypesheader header;
+	u16 bcastprobe;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numssidprobe {
+	struct mrvlietypesheader header;
+	u16 numssidprobe;
+} __attribute__ ((packed));
+
+struct led_pin {
+	u8 led;
+	u8 pin;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ledgpio {
+	struct mrvlietypesheader header;
+	struct led_pin ledpin[1];
+} __attribute__ ((packed));
+
+#endif				/* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644
index 0000000..e86f65a
--- /dev/null
+++ b/drivers/net/wireless/libertas/version.h
@@ -0,0 +1,8 @@
+#define DRIVER_RELEASE_VERSION "320.p0"
+const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef  DEBUG
+    "-dbg"
+#endif
+    "";
+
+
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644
index 0000000..4a52336
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.c
@@ -0,0 +1,2769 @@
+/**
+  * This file contains ioctl functions
+  */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "version.h"
+#include "wext.h"
+#include "assoc.h"
+
+
+/**
+ *  @brief Convert mw value to dbm value
+ *
+ *  @param mw	   the value of mw
+ *  @return 	   the value of dbm
+ */
+static int mw_to_dbm(int mw)
+{
+	if (mw < 2)
+		return 0;
+	else if (mw < 3)
+		return 3;
+	else if (mw < 4)
+		return 5;
+	else if (mw < 6)
+		return 7;
+	else if (mw < 7)
+		return 8;
+	else if (mw < 8)
+		return 9;
+	else if (mw < 10)
+		return 10;
+	else if (mw < 13)
+		return 11;
+	else if (mw < 16)
+		return 12;
+	else if (mw < 20)
+		return 13;
+	else if (mw < 25)
+		return 14;
+	else if (mw < 32)
+		return 15;
+	else if (mw < 40)
+		return 16;
+	else if (mw < 50)
+		return 17;
+	else if (mw < 63)
+		return 18;
+	else if (mw < 79)
+		return 19;
+	else if (mw < 100)
+		return 20;
+	else
+		return 21;
+}
+
+/**
+ *  @brief Find the channel frequency power info with specific channel
+ *
+ *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param band		it can be BAND_A, BAND_G or BAND_B
+ *  @param channel      the channel for looking
+ *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
+						 u8 band, u16 channel)
+{
+	struct chan_freq_power *cfp = NULL;
+	struct region_channel *rc;
+	int count = sizeof(adapter->region_channel) /
+	    sizeof(adapter->region_channel[0]);
+	int i, j;
+
+	for (j = 0; !cfp && (j < count); j++) {
+		rc = &adapter->region_channel[j];
+
+		if (adapter->enable11d)
+			rc = &adapter->universal_channel[j];
+		if (!rc->valid || !rc->CFP)
+			continue;
+		if (rc->band != band)
+			continue;
+		for (i = 0; i < rc->nrcfp; i++) {
+			if (rc->CFP[i].channel == channel) {
+				cfp = &rc->CFP[i];
+				break;
+			}
+		}
+	}
+
+	if (!cfp && channel)
+		lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
+		       "cfp by band %d & channel %d\n", band, channel);
+
+	return cfp;
+}
+
+/**
+ *  @brief Find the channel frequency power info with specific frequency
+ *
+ *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param band		it can be BAND_A, BAND_G or BAND_B
+ *  @param freq	        the frequency for looking
+ *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
+						     u8 band, u32 freq)
+{
+	struct chan_freq_power *cfp = NULL;
+	struct region_channel *rc;
+	int count = sizeof(adapter->region_channel) /
+	    sizeof(adapter->region_channel[0]);
+	int i, j;
+
+	for (j = 0; !cfp && (j < count); j++) {
+		rc = &adapter->region_channel[j];
+
+		if (adapter->enable11d)
+			rc = &adapter->universal_channel[j];
+		if (!rc->valid || !rc->CFP)
+			continue;
+		if (rc->band != band)
+			continue;
+		for (i = 0; i < rc->nrcfp; i++) {
+			if (rc->CFP[i].freq == freq) {
+				cfp = &rc->CFP[i];
+				break;
+			}
+		}
+	}
+
+	if (!cfp && freq)
+		lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
+		       "band %d & freq %d\n", band, freq);
+
+	return cfp;
+}
+
+static int updatecurrentchannel(wlan_private * priv)
+{
+	int ret;
+
+	/*
+	 ** the channel in f/w could be out of sync, get the current channel
+	 */
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+				    cmd_opt_802_11_rf_channel_get,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	lbs_pr_debug(1, "Current channel = %d\n",
+	       priv->adapter->curbssparams.channel);
+
+	return ret;
+}
+
+static int setcurrentchannel(wlan_private * priv, int channel)
+{
+	lbs_pr_debug(1, "Set channel = %d\n", channel);
+
+	/*
+	 **  Current channel is not set to adhocchannel requested, set channel
+	 */
+	return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+				      cmd_opt_802_11_rf_channel_set,
+				      cmd_option_waitforrsp, 0, &channel));
+}
+
+static int changeadhocchannel(wlan_private * priv, int channel)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	adapter->adhocchannel = channel;
+
+	updatecurrentchannel(priv);
+
+	if (adapter->curbssparams.channel == adapter->adhocchannel) {
+		/* adhocchannel is set to the current channel already */
+		LEAVE();
+		return 0;
+	}
+
+	lbs_pr_debug(1, "Updating channel from %d to %d\n",
+	       adapter->curbssparams.channel, adapter->adhocchannel);
+
+	setcurrentchannel(priv, adapter->adhocchannel);
+
+	updatecurrentchannel(priv);
+
+	if (adapter->curbssparams.channel != adapter->adhocchannel) {
+		lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
+		       adapter->adhocchannel, adapter->curbssparams.channel);
+		LEAVE();
+		return -1;
+	}
+
+	if (adapter->connect_status == libertas_connected) {
+		int i;
+		struct WLAN_802_11_SSID curadhocssid;
+
+		lbs_pr_debug(1, "channel Changed while in an IBSS\n");
+
+		/* Copy the current ssid */
+		memcpy(&curadhocssid, &adapter->curbssparams.ssid,
+		       sizeof(struct WLAN_802_11_SSID));
+
+		/* Exit Adhoc mode */
+		lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
+		ret = libertas_stop_adhoc_network(priv);
+
+		if (ret) {
+			LEAVE();
+			return ret;
+		}
+		/* Scan for the network, do not save previous results.  Stale
+		 *   scan data will cause us to join a non-existant adhoc network
+		 */
+		libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
+
+		// find out the BSSID that matches the current SSID
+		i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
+				   wlan802_11ibss);
+
+		if (i >= 0) {
+			lbs_pr_debug(1, "SSID found at %d in List,"
+			       "so join\n", i);
+			libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+		} else {
+			// else send START command
+			lbs_pr_debug(1, "SSID not found in list, "
+			       "so creating adhoc with ssid = %s\n",
+			       curadhocssid.ssid);
+			libertas_start_adhoc_network(priv, &curadhocssid);
+		}		// end of else (START command)
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Set Radio On/OFF
+ *
+ *  @param priv                 A pointer to wlan_private structure
+ *  @option 			Radio Option
+ *  @return 	   		0 --success, otherwise fail
+ */
+int wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (adapter->radioon != option) {
+		lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
+		adapter->radioon = option;
+
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_radio_control,
+					    cmd_act_set,
+					    cmd_option_waitforrsp, 0, NULL);
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Copy rates
+ *
+ *  @param dest                 A pointer to Dest Buf
+ *  @param src		        A pointer to Src Buf
+ *  @param len                  The len of Src Buf
+ *  @return 	   	        Number of rates copyed
+ */
+static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
+{
+	int i;
+
+	for (i = 0; i < len && src[i]; i++, pos++) {
+		if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
+			break;
+		dest[pos] = src[i];
+	}
+
+	return pos;
+}
+
+/**
+ *  @brief Get active data rates
+ *
+ *  @param adapter              A pointer to wlan_adapter structure
+ *  @param rate		        The buf to return the active rates
+ *  @return 	   	        The number of rates
+ */
+static int get_active_data_rates(wlan_adapter * adapter,
+				 u8* rates)
+{
+	int k = 0;
+
+	ENTER();
+
+	if (adapter->connect_status != libertas_connected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			//Infra. mode
+			lbs_pr_debug(1, "Infra\n");
+			k = copyrates(rates, k, libertas_supported_rates,
+				      sizeof(libertas_supported_rates));
+		} else {
+			//ad-hoc mode
+			lbs_pr_debug(1, "Adhoc G\n");
+			k = copyrates(rates, k, libertas_adhoc_rates_g,
+				      sizeof(libertas_adhoc_rates_g));
+		}
+	} else {
+		k = copyrates(rates, 0, adapter->curbssparams.datarates,
+			      adapter->curbssparams.numofrates);
+	}
+
+	LEAVE();
+
+	return k;
+}
+
+static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+			 char *cwrq, char *extra)
+{
+	const char *cp;
+	char comm[6] = { "COMM-" };
+	char mrvl[6] = { "MRVL-" };
+	int cnt;
+
+	ENTER();
+
+	strcpy(cwrq, mrvl);
+
+	cp = strstr(libertas_driver_version, comm);
+	if (cp == libertas_driver_version)	//skip leading "COMM-"
+		cp = libertas_driver_version + strlen(comm);
+	else
+		cp = libertas_driver_version;
+
+	cnt = strlen(mrvl);
+	cwrq += cnt;
+	while (cnt < 16 && (*cp != '-')) {
+		*cwrq++ = toupper(*cp++);
+		cnt++;
+	}
+	*cwrq = '\0';
+
+	LEAVE();
+
+	return 0;
+}
+
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_freq *fwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct chan_freq_power *cfp;
+
+	ENTER();
+
+	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
+					   adapter->curbssparams.channel);
+
+	if (!cfp) {
+		if (adapter->curbssparams.channel)
+			lbs_pr_debug(1, "Invalid channel=%d\n",
+			       adapter->curbssparams.channel);
+		return -EINVAL;
+	}
+
+	fwrq->m = (long)cfp->freq * 100000;
+	fwrq->e = 1;
+
+	lbs_pr_debug(1, "freq=%u\n", fwrq->m);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+			struct sockaddr *awrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (adapter->connect_status == libertas_connected) {
+		memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	} else {
+		memset(awrq->sa_data, 0, ETH_ALEN);
+	}
+	awrq->sa_family = ARPHRD_ETHER;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_point *dwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/*
+	 * Check the size of the string
+	 */
+
+	if (dwrq->length > 16) {
+		return -E2BIG;
+	}
+
+	mutex_lock(&adapter->lock);
+	memset(adapter->nodename, 0, sizeof(adapter->nodename));
+	memcpy(adapter->nodename, extra, dwrq->length);
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_point *dwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/*
+	 * Get the Nick Name saved
+	 */
+
+	mutex_lock(&adapter->lock);
+	strncpy(extra, adapter->nodename, 16);
+	mutex_unlock(&adapter->lock);
+
+	extra[16] = '\0';
+
+	/*
+	 * If none, we may want to get the one that was set
+	 */
+
+	/*
+	 * Push it out !
+	 */
+	dwrq->length = strlen(extra) + 1;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+			struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int rthr = vwrq->value;
+
+	ENTER();
+
+	if (vwrq->disabled) {
+		adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+	} else {
+		if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+			return -EINVAL;
+		adapter->rtsthsd = rthr;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+				    cmd_act_set, cmd_option_waitforrsp,
+				    OID_802_11_RTS_THRESHOLD, &rthr);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+			struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->rtsthsd = 0;
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_option_waitforrsp,
+				    OID_802_11_RTS_THRESHOLD, NULL);
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	vwrq->value = adapter->rtsthsd;
+	vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+			  || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+	vwrq->fixed = 1;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	int fthr = vwrq->value;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (vwrq->disabled) {
+		adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+	} else {
+		if (fthr < MRVDRV_FRAG_MIN_VALUE
+		    || fthr > MRVDRV_FRAG_MAX_VALUE)
+			return -EINVAL;
+		adapter->fragthsd = fthr;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+				    cmd_act_set, cmd_option_waitforrsp,
+				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->fragthsd = 0;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_option_waitforrsp,
+				    OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	vwrq->value = adapter->fragthsd;
+	vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+			  || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+	vwrq->fixed = 1;
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_mode(struct net_device *dev,
+			 struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	switch (adapter->inframode) {
+	case wlan802_11ibss:
+		*uwrq = IW_MODE_ADHOC;
+		break;
+
+	case wlan802_11infrastructure:
+		*uwrq = IW_MODE_INFRA;
+		break;
+
+	default:
+	case wlan802_11autounknown:
+		*uwrq = IW_MODE_AUTO;
+		break;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_txpow(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_rf_tx_power,
+				    cmd_act_tx_power_opt_get,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
+	vwrq->value = adapter->txpowerlevel;
+	vwrq->fixed = 1;
+	if (adapter->radioon) {
+		vwrq->disabled = 0;
+		vwrq->flags = IW_TXPOW_DBM;
+	} else {
+		vwrq->disabled = 1;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (vwrq->flags == IW_RETRY_LIMIT) {
+		/* The MAC has a 4-bit Total_Tx_Count register
+		   Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+		if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+			return -EINVAL;
+
+		/* Adding 1 to convert retry count to try count */
+		adapter->txretrycount = vwrq->value + 1;
+
+		ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+					    cmd_act_set,
+					    cmd_option_waitforrsp,
+					    OID_802_11_TX_RETRYCOUNT, NULL);
+
+		if (ret) {
+			LEAVE();
+			return ret;
+		}
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+	adapter->txretrycount = 0;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_option_waitforrsp,
+				    OID_802_11_TX_RETRYCOUNT, NULL);
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+	vwrq->disabled = 0;
+	if (!vwrq->flags) {
+		vwrq->flags = IW_RETRY_LIMIT;
+		/* Subtract 1 to convert try count to retry count */
+		vwrq->value = adapter->txretrycount - 1;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static inline void sort_channels(struct iw_freq *freq, int num)
+{
+	int i, j;
+	struct iw_freq temp;
+
+	for (i = 0; i < num; i++)
+		for (j = i + 1; j < num; j++)
+			if (freq[i].i > freq[j].i) {
+				temp.i = freq[i].i;
+				temp.m = freq[i].m;
+
+				freq[i].i = freq[j].i;
+				freq[i].m = freq[j].m;
+
+				freq[j].i = temp.i;
+				freq[j].m = temp.m;
+			}
+}
+
+/* data rate listing
+	MULTI_BANDS:
+		abg		a	b	b/g
+   Infra 	G(12)		A(8)	B(4)	G(12)
+   Adhoc 	A+B(12)		A(8)	B(4)	B(4)
+
+	non-MULTI_BANDS:
+					b	b/g
+   Infra 	     		    	B(4)	G(12)
+   Adhoc 	      		    	B(4)	B(4)
+ */
+/**
+ *  @brief Get Range Info
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_point *dwrq, char *extra)
+{
+	int i, j;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iw_range *range = (struct iw_range *)extra;
+	struct chan_freq_power *cfp;
+	u8 rates[WLAN_SUPPORTED_RATES];
+
+	u8 flag = 0;
+
+	ENTER();
+
+	dwrq->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+
+	range->min_nwid = 0;
+	range->max_nwid = 0;
+
+	memset(rates, 0, sizeof(rates));
+	range->num_bitrates = get_active_data_rates(adapter, rates);
+
+	for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+	     i++) {
+		range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+	}
+	range->num_bitrates = i;
+	lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+	       range->num_bitrates);
+
+	range->num_frequency = 0;
+	if (priv->adapter->enable11d &&
+	    adapter->connect_status == libertas_connected) {
+		u8 chan_no;
+		u8 band;
+
+		struct parsed_region_chan_11d *parsed_region_chan =
+		    &adapter->parsed_region_chan;
+
+		if (parsed_region_chan == NULL) {
+			lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
+			LEAVE();
+			return 0;
+		}
+		band = parsed_region_chan->band;
+		lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
+		       parsed_region_chan->nr_chan);
+
+		for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+		     && (i < parsed_region_chan->nr_chan); i++) {
+			chan_no = parsed_region_chan->chanpwr[i].chan;
+			lbs_pr_debug(1, "chan_no=%d\n", chan_no);
+			range->freq[range->num_frequency].i = (long)chan_no;
+			range->freq[range->num_frequency].m =
+			    (long)libertas_chan_2_freq(chan_no, band) * 100000;
+			range->freq[range->num_frequency].e = 1;
+			range->num_frequency++;
+		}
+		flag = 1;
+	}
+	if (!flag) {
+		for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+		     && (j < sizeof(adapter->region_channel)
+			 / sizeof(adapter->region_channel[0])); j++) {
+			cfp = adapter->region_channel[j].CFP;
+			for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+			     && adapter->region_channel[j].valid
+			     && cfp
+			     && (i < adapter->region_channel[j].nrcfp); i++) {
+				range->freq[range->num_frequency].i =
+				    (long)cfp->channel;
+				range->freq[range->num_frequency].m =
+				    (long)cfp->freq * 100000;
+				range->freq[range->num_frequency].e = 1;
+				cfp++;
+				range->num_frequency++;
+			}
+		}
+	}
+
+	lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+	       IW_MAX_FREQUENCIES, range->num_frequency);
+
+	range->num_channels = range->num_frequency;
+
+	sort_channels(&range->freq[0], range->num_frequency);
+
+	/*
+	 * Set an indication of the max TCP throughput in bit/s that we can
+	 * expect using this interface
+	 */
+	if (i > 2)
+		range->throughput = 5000 * 1000;
+	else
+		range->throughput = 1500 * 1000;
+
+	range->min_rts = MRVDRV_RTS_MIN_VALUE;
+	range->max_rts = MRVDRV_RTS_MAX_VALUE;
+	range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+	range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+	range->encoding_size[0] = 5;
+	range->encoding_size[1] = 13;
+	range->num_encoding_sizes = 2;
+	range->max_encoding_tokens = 4;
+
+	range->min_pmp = 1000000;
+	range->max_pmp = 120000000;
+	range->min_pmt = 1000;
+	range->max_pmt = 1000000;
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+	/*
+	 * Minimum version we recommend
+	 */
+	range->we_version_source = 15;
+
+	/*
+	 * Version we are compiled with
+	 */
+	range->we_version_compiled = WIRELESS_EXT;
+
+	range->retry_capa = IW_RETRY_LIMIT;
+	range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+	range->min_retry = TX_RETRY_MIN;
+	range->max_retry = TX_RETRY_MAX;
+
+	/*
+	 * Set the qual, level and noise range values
+	 */
+	range->max_qual.qual = 100;
+	range->max_qual.level = 0;
+	range->max_qual.noise = 0;
+	range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+	range->avg_qual.qual = 70;
+	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
+	range->avg_qual.level = 0;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+	range->sensitivity = 0;
+
+	/*
+	 * Setup the supported power level ranges
+	 */
+	memset(range->txpower, 0, sizeof(range->txpower));
+	range->txpower[0] = 5;
+	range->txpower[1] = 7;
+	range->txpower[2] = 9;
+	range->txpower[3] = 11;
+	range->txpower[4] = 13;
+	range->txpower[5] = 15;
+	range->txpower[6] = 17;
+	range->txpower[7] = 19;
+
+	range->num_txpower = 8;
+	range->txpower_capa = IW_TXPOW_DBM;
+	range->txpower_capa |= IW_TXPOW_RANGE;
+
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+	if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+		range->enc_capa =   IW_ENC_CAPA_WPA
+		                  | IW_ENC_CAPA_WPA2
+		                  | IW_ENC_CAPA_CIPHER_TKIP
+		                  | IW_ENC_CAPA_CIPHER_CCMP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* PS is currently supported only in Infrastructure mode
+	 * Remove this check if it is to be supported in IBSS mode also
+	 */
+
+	if (vwrq->disabled) {
+		adapter->psmode = wlan802_11powermodecam;
+		if (adapter->psstate != PS_STATE_FULL_POWER) {
+			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+		}
+
+		return 0;
+	}
+
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		lbs_pr_debug(1,
+		       "Setting power timeout command is not supported\n");
+		return -EINVAL;
+	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+		lbs_pr_debug(1, "Setting power period command is not supported\n");
+		return -EINVAL;
+	}
+
+	if (adapter->psmode != wlan802_11powermodecam) {
+		return 0;
+	}
+
+	adapter->psmode = wlan802_11powermodemax_psp;
+
+	if (adapter->connect_status == libertas_connected) {
+		libertas_ps_sleep(priv, cmd_option_waitforrsp);
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int mode;
+
+	ENTER();
+
+	mode = adapter->psmode;
+
+	if ((vwrq->disabled = (mode == wlan802_11powermodecam))
+	    || adapter->connect_status == libertas_disconnected) {
+		LEAVE();
+		return 0;
+	}
+
+	vwrq->value = 0;
+
+	LEAVE();
+	return 0;
+}
+
+/*
+ * iwpriv settable callbacks
+ */
+
+static const iw_handler wlan_private_handler[] = {
+	NULL,			/* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+	/*
+	 * { cmd, set_args, get_args, name }
+	 */
+	{
+	 WLANSCAN_TYPE,
+	 IW_PRIV_TYPE_CHAR | 8,
+	 IW_PRIV_TYPE_CHAR | 8,
+	 "scantype"},
+
+	{
+	 WLAN_SETINT_GETINT,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 ""},
+	{
+	 WLANNF,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getNF"},
+	{
+	 WLANRSSI,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getRSSI"},
+	{
+	 WLANENABLE11D,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "enable11d"},
+	{
+	 WLANADHOCGRATE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "adhocgrate"},
+
+	{
+	 WLAN_SUBCMD_SET_PRESCAN,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "prescan"},
+	{
+	 WLAN_SETONEINT_GETONEINT,
+	 IW_PRIV_TYPE_INT | 1,
+	 IW_PRIV_TYPE_INT | 1,
+	 ""},
+	{
+	 WLAN_BEACON_INTERVAL,
+	 IW_PRIV_TYPE_INT | 1,
+	 IW_PRIV_TYPE_INT | 1,
+	 "bcninterval"},
+	{
+	 WLAN_LISTENINTRVL,
+	 IW_PRIV_TYPE_INT | 1,
+	 IW_PRIV_TYPE_INT | 1,
+	 "lolisteninter"},
+	{
+	 WLAN_TXCONTROL,
+	 IW_PRIV_TYPE_INT | 1,
+	 IW_PRIV_TYPE_INT | 1,
+	 "txcontrol"},
+	{
+	 WLAN_NULLPKTINTERVAL,
+	 IW_PRIV_TYPE_INT | 1,
+	 IW_PRIV_TYPE_INT | 1,
+	 "psnullinterval"},
+	/* Using iwpriv sub-command feature */
+	{
+	 WLAN_SETONEINT_GETNONE,	/* IOCTL: 24 */
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 ""},
+
+	{
+	 WLAN_SUBCMD_SETRXANTENNA,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setrxant"},
+	{
+	 WLAN_SUBCMD_SETTXANTENNA,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "settxant"},
+	{
+	 WLANSETAUTHALG,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "authalgs",
+	 },
+	{
+	 WLANSET8021XAUTHALG,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "8021xauthalgs",
+	 },
+	{
+	 WLANSETENCRYPTIONMODE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "encryptionmode",
+	 },
+	{
+	 WLANSETREGION,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setregioncode"},
+	{
+	 WLAN_SET_LISTEN_INTERVAL,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setlisteninter"},
+	{
+	 WLAN_SET_MULTIPLE_DTIM,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setmultipledtim"},
+	{
+	 WLAN_SET_ATIM_WINDOW,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "atimwindow"},
+	{
+	 WLANSETBCNAVG,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setbcnavg"},
+	{
+	 WLANSETDATAAVG,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "setdataavg"},
+	{
+	 WLAN_SET_LINKMODE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "linkmode"},
+	{
+	 WLAN_SET_RADIOMODE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "radiomode"},
+	{
+	 WLAN_SET_DEBUGMODE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "debugmode"},
+	{
+	 WLAN_SUBCMD_MESH_SET_TTL,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "mesh_set_ttl"},
+	{
+	 WLAN_SETNONE_GETONEINT,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 ""},
+	{
+	 WLANGETREGION,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getregioncode"},
+	{
+	 WLAN_GET_LISTEN_INTERVAL,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getlisteninter"},
+	{
+	 WLAN_GET_MULTIPLE_DTIM,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getmultipledtim"},
+	{
+	 WLAN_GET_TX_RATE,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "gettxrate"},
+	{
+	 WLANGETBCNAVG,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "getbcnavg"},
+	{
+	 WLAN_GET_LINKMODE,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_linkmode"},
+	{
+	 WLAN_GET_RADIOMODE,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_radiomode"},
+	{
+	 WLAN_GET_DEBUGMODE,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "get_debugmode"},
+	{
+	 WLAN_SUBCMD_FWT_CLEANUP,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "fwt_cleanup"},
+	{
+	 WLAN_SUBCMD_FWT_TIME,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "fwt_time"},
+	{
+	 WLAN_SUBCMD_MESH_GET_TTL,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "mesh_get_ttl"},
+	{
+	 WLAN_SETNONE_GETTWELVE_CHAR,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 12,
+	 ""},
+	{
+	 WLAN_SUBCMD_GETRXANTENNA,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 12,
+	 "getrxant"},
+	{
+	 WLAN_SUBCMD_GETTXANTENNA,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 12,
+	 "gettxant"},
+	{
+	 WLAN_GET_TSF,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 12,
+	 "gettsf"},
+	{
+	 WLAN_SETNONE_GETNONE,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 ""},
+	{
+	 WLANDEAUTH,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "deauth"},
+	{
+	 WLANADHOCSTOP,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "adhocstop"},
+	{
+	 WLANRADIOON,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "radioon"},
+	{
+	 WLANRADIOOFF,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "radiooff"},
+	{
+	 WLANWLANIDLEON,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "wlanidle-on"},
+	{
+	 WLANWLANIDLEOFF,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "wlanidle-off"},
+	{
+	 WLAN_SUBCMD_FWT_RESET,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "fwt_reset"},
+	{
+	 WLAN_SUBCMD_BT_RESET,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "bt_reset"},
+	{
+	 WLAN_SET128CHAR_GET128CHAR,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 ""},
+	/* BT Management */
+	{
+	 WLAN_SUBCMD_BT_ADD,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_add"},
+	{
+	 WLAN_SUBCMD_BT_DEL,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_del"},
+	{
+	 WLAN_SUBCMD_BT_LIST,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_list"},
+	/* FWT Management */
+	{
+	 WLAN_SUBCMD_FWT_ADD,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_add"},
+	{
+	 WLAN_SUBCMD_FWT_DEL,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_del"},
+	{
+	 WLAN_SUBCMD_FWT_LOOKUP,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_lookup"},
+	{
+	 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list_neigh"},
+	{
+	 WLAN_SUBCMD_FWT_LIST,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list"},
+	{
+	 WLAN_SUBCMD_FWT_LIST_ROUTE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list_route"},
+	{
+	 WLANSCAN_MODE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "scanmode"},
+	{
+	 WLAN_GET_ADHOC_STATUS,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "getadhocstatus"},
+	{
+	 WLAN_SETNONE_GETWORDCHAR,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 ""},
+	{
+	 WLANSETWPAIE,
+	 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+	 IW_PRIV_TYPE_NONE,
+	 "setwpaie"},
+	{
+	 WLANGETLOG,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+	 "getlog"},
+	{
+	 WLAN_SET_GET_SIXTEEN_INT,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 ""},
+	{
+	 WLAN_TPCCFG,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "tpccfg"},
+	{
+	 WLAN_POWERCFG,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "powercfg"},
+	{
+	 WLAN_AUTO_FREQ_SET,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "setafc"},
+	{
+	 WLAN_AUTO_FREQ_GET,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "getafc"},
+	{
+	 WLAN_SCANPROBES,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "scanprobes"},
+	{
+	 WLAN_LED_GPIO_CTRL,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "ledgpio"},
+	{
+	 WLAN_ADAPT_RATESET,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "rateadapt"},
+	{
+	 WLAN_INACTIVITY_TIMEOUT,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "inactivityto"},
+	{
+	 WLANSNR,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "getSNR"},
+	{
+	 WLAN_GET_RATE,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "getrate"},
+	{
+	 WLAN_GET_RXINFO,
+	 IW_PRIV_TYPE_INT | 16,
+	 IW_PRIV_TYPE_INT | 16,
+	 "getrxinfo"},
+};
+
+static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
+{
+	enum {
+		POOR = 30,
+		FAIR = 60,
+		GOOD = 80,
+		VERY_GOOD = 90,
+		EXCELLENT = 95,
+		PERFECT = 100
+	};
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	u32 rssi_qual;
+	u32 tx_qual;
+	u32 quality = 0;
+	int stats_valid = 0;
+	u8 rssi;
+	u32 tx_retries;
+
+	ENTER();
+
+	priv->wstats.status = adapter->inframode;
+
+	/* If we're not associated, all quality values are meaningless */
+	if (adapter->connect_status != libertas_connected)
+		goto out;
+
+	/* Quality by RSSI */
+	priv->wstats.qual.level =
+	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+	     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+	if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+		priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+	} else {
+		priv->wstats.qual.noise =
+		    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+	}
+
+	lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
+	lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
+
+	rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
+	if (rssi < 15)
+		rssi_qual = rssi * POOR / 10;
+	else if (rssi < 20)
+		rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
+	else if (rssi < 30)
+		rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
+	else if (rssi < 40)
+		rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
+		    10 + GOOD;
+	else
+		rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
+		    10 + VERY_GOOD;
+	quality = rssi_qual;
+
+	/* Quality by TX errors */
+	priv->wstats.discard.retries = priv->stats.tx_errors;
+
+	tx_retries = adapter->logmsg.retry;
+
+	if (tx_retries > 75)
+		tx_qual = (90 - tx_retries) * POOR / 15;
+	else if (tx_retries > 70)
+		tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+	else if (tx_retries > 65)
+		tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+	else if (tx_retries > 50)
+		tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+		    15 + GOOD;
+	else
+		tx_qual = (50 - tx_retries) *
+		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+	quality = min(quality, tx_qual);
+
+	priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
+	priv->wstats.discard.fragment = adapter->logmsg.fcserror;
+	priv->wstats.discard.retries = tx_retries;
+	priv->wstats.discard.misc = adapter->logmsg.ackfailure;
+
+	/* Calculate quality */
+	priv->wstats.qual.qual = max(quality, (u32)100);
+	priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+	stats_valid = 1;
+
+	/* update stats asynchronously for future calls */
+	libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+					0, 0, NULL);
+	libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+					0, 0, NULL);
+out:
+	if (!stats_valid) {
+		priv->wstats.miss.beacon = 0;
+		priv->wstats.discard.retries = 0;
+		priv->wstats.qual.qual = 0;
+		priv->wstats.qual.level = 0;
+		priv->wstats.qual.noise = 0;
+		priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
+		priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
+		    IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+	}
+
+	LEAVE ();
+	return &priv->wstats;
+
+
+}
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_freq *fwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int rc = -EINPROGRESS;	/* Call commit handler */
+	struct chan_freq_power *cfp;
+
+	ENTER();
+
+	/*
+	 * If setting by frequency, convert to a channel
+	 */
+	if (fwrq->e == 1) {
+
+		long f = fwrq->m / 100000;
+		int c = 0;
+
+		cfp = find_cfp_by_band_and_freq(adapter, 0, f);
+		if (!cfp) {
+			lbs_pr_debug(1, "Invalid freq=%ld\n", f);
+			return -EINVAL;
+		}
+
+		c = (int)cfp->channel;
+
+		if (c < 0)
+			return -EINVAL;
+
+		fwrq->e = 0;
+		fwrq->m = c;
+	}
+
+	/*
+	 * Setting by channel number
+	 */
+	if (fwrq->m > 1000 || fwrq->e > 0) {
+		rc = -EOPNOTSUPP;
+	} else {
+		int channel = fwrq->m;
+
+		cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
+		if (!cfp) {
+			rc = -EINVAL;
+		} else {
+			if (adapter->inframode == wlan802_11ibss) {
+				rc = changeadhocchannel(priv, channel);
+				/*  If station is WEP enabled, send the
+				 *  command to set WEP in firmware
+				 */
+				if (adapter->secinfo.WEPstatus ==
+				    wlan802_11WEPenabled) {
+					lbs_pr_debug(1, "set_freq: WEP enabled\n");
+					ret = libertas_prepare_and_send_command(priv,
+								    cmd_802_11_set_wep,
+								    cmd_act_add,
+								    cmd_option_waitforrsp,
+								    0,
+								    NULL);
+
+					if (ret) {
+						LEAVE();
+						return ret;
+					}
+
+					adapter->currentpacketfilter |=
+					    cmd_act_mac_wep_enable;
+
+					libertas_set_mac_packet_filter(priv);
+				}
+			} else {
+				rc = -EOPNOTSUPP;
+			}
+		}
+	}
+
+	LEAVE();
+	return rc;
+}
+
+/**
+ *  @brief use index to get the data rate
+ *
+ *  @param index                The index of data rate
+ *  @return 	   		data rate or 0
+ */
+u32 libertas_index_to_data_rate(u8 index)
+{
+	if (index >= sizeof(libertas_wlan_data_rates))
+		index = 0;
+
+	return libertas_wlan_data_rates[index];
+}
+
+/**
+ *  @brief use rate to get the index
+ *
+ *  @param rate                 data rate
+ *  @return 	   		index or 0
+ */
+u8 libertas_data_rate_to_index(u32 rate)
+{
+	u8 *ptr;
+
+	if (rate)
+		if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
+				  sizeof(libertas_wlan_data_rates))))
+			return (ptr - libertas_wlan_data_rates);
+
+	return 0;
+}
+
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	u32 data_rate;
+	u16 action;
+	int ret = 0;
+	u8 rates[WLAN_SUPPORTED_RATES];
+	u8 *rate;
+
+	ENTER();
+
+	lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
+
+	if (vwrq->value == -1) {
+		action = cmd_act_set_tx_auto;	// Auto
+		adapter->is_datarate_auto = 1;
+		adapter->datarate = 0;
+	} else {
+		if (vwrq->value % 100000) {
+			return -EINVAL;
+		}
+
+		data_rate = vwrq->value / 500000;
+
+		memset(rates, 0, sizeof(rates));
+		get_active_data_rates(adapter, rates);
+		rate = rates;
+		while (*rate) {
+			lbs_pr_debug(1, "Rate=0x%X  Wanted=0x%X\n", *rate,
+			       data_rate);
+			if ((*rate & 0x7f) == (data_rate & 0x7f))
+				break;
+			rate++;
+		}
+		if (!*rate) {
+			lbs_pr_alert( "The fixed data rate 0x%X is out "
+			       "of range.\n", data_rate);
+			return -EINVAL;
+		}
+
+		adapter->datarate = data_rate;
+		action = cmd_act_set_tx_fix_rate;
+		adapter->is_datarate_auto = 0;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+				    action, cmd_option_waitforrsp, 0, NULL);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_param *vwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (adapter->is_datarate_auto) {
+		vwrq->fixed = 0;
+	} else {
+		vwrq->fixed = 1;
+	}
+
+	vwrq->value = adapter->datarate * 500000;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_mode(struct net_device *dev,
+		  struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+	ENTER();
+
+	switch (*uwrq) {
+	case IW_MODE_ADHOC:
+		lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
+		       adapter->datarate);
+		new_mode = wlan802_11ibss;
+		adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+		break;
+
+	case IW_MODE_INFRA:
+		lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
+		new_mode = wlan802_11infrastructure;
+		break;
+
+	case IW_MODE_AUTO:
+		lbs_pr_debug(1, "Wanted mode is Auto\n");
+		new_mode = wlan802_11autounknown;
+		break;
+
+	default:
+		lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
+		return -EINVAL;
+	}
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+	} else {
+		assoc_req->mode = new_mode;
+	}
+
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+
+/**
+ *  @brief Get Encryption key
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_get_encode(struct net_device *dev,
+			   struct iw_request_info *info,
+			   struct iw_point *dwrq, u8 * extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+	ENTER();
+
+	lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
+	       dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+
+	dwrq->flags = 0;
+
+	/* Authentication method */
+	switch (adapter->secinfo.authmode) {
+	case wlan802_11authmodeopen:
+		dwrq->flags = IW_ENCODE_OPEN;
+		break;
+
+	case wlan802_11authmodeshared:
+	case wlan802_11authmodenetworkEAP:
+		dwrq->flags = IW_ENCODE_RESTRICTED;
+		break;
+	default:
+		dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+		break;
+	}
+
+	if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+	    || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+		dwrq->flags &= ~IW_ENCODE_DISABLED;
+	} else {
+		dwrq->flags |= IW_ENCODE_DISABLED;
+	}
+
+	memset(extra, 0, 16);
+
+	mutex_lock(&adapter->lock);
+
+	/* Default to returning current transmit key */
+	if (index < 0)
+		index = adapter->wep_tx_keyidx;
+
+	if ((adapter->wep_keys[index].len) &&
+	    (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
+		memcpy(extra, adapter->wep_keys[index].key,
+		       adapter->wep_keys[index].len);
+		dwrq->length = adapter->wep_keys[index].len;
+
+		dwrq->flags |= (index + 1);
+		/* Return WEP enabled */
+		dwrq->flags &= ~IW_ENCODE_DISABLED;
+	} else if ((adapter->secinfo.WPAenabled)
+		   || (adapter->secinfo.WPA2enabled)) {
+		/* return WPA enabled */
+		dwrq->flags &= ~IW_ENCODE_DISABLED;
+	} else {
+		dwrq->flags |= IW_ENCODE_DISABLED;
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	dwrq->flags |= IW_ENCODE_NOKEY;
+
+	lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
+	       extra[0], extra[1], extra[2],
+	       extra[3], extra[4], extra[5], dwrq->length);
+
+	lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Set Encryption key (internal)
+ *
+ *  @param priv			A pointer to private card structure
+ *  @param key_material		A pointer to key material
+ *  @param key_length		length of key material
+ *  @param index		key index to set
+ *  @param set_tx_key		Force set TX key (1 = yes, 0 = no)
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_wep_key(struct assoc_request *assoc_req,
+			    const char *key_material,
+			    u16 key_length,
+			    u16 index,
+			    int set_tx_key)
+{
+	struct WLAN_802_11_KEY *pkey;
+
+	ENTER();
+
+	/* Paranoid validation of key index */
+	if (index > 3) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	/* validate max key length */
+	if (key_length > KEY_LEN_WEP_104) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	pkey = &assoc_req->wep_keys[index];
+
+	if (key_length > 0) {
+		memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+		pkey->type = KEY_TYPE_ID_WEP;
+
+		/* Standardize the key length */
+		pkey->len = (key_length > KEY_LEN_WEP_40) ?
+		                KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
+		memcpy(pkey->key, key_material, key_length);
+	}
+
+	if (set_tx_key) {
+		/* Ensure the chosen key is valid */
+		if (!pkey->len) {
+			lbs_pr_debug(1, "key not set, so cannot enable it\n");
+			LEAVE();
+			return -EINVAL;
+		}
+		assoc_req->wep_tx_keyidx = index;
+	}
+
+	assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
+
+	LEAVE();
+	return 0;
+}
+
+static int validate_key_index(u16 def_index, u16 raw_index,
+			      u16 *out_index, u16 *is_default)
+{
+	if (!out_index || !is_default)
+		return -EINVAL;
+
+	/* Verify index if present, otherwise use default TX key index */
+	if (raw_index > 0) {
+		if (raw_index > 4)
+			return -EINVAL;
+		*out_index = raw_index - 1;
+	} else {
+		*out_index = def_index;
+		*is_default = 1;
+	}
+	return 0;
+}
+
+static void disable_wep(struct assoc_request *assoc_req)
+{
+	int i;
+
+	/* Set Open System auth mode */
+	assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+
+	/* Clear WEP keys and mark WEP as disabled */
+	assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	for (i = 0; i < 4; i++)
+		assoc_req->wep_keys[i].len = 0;
+
+	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+	set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+}
+
+/**
+ *  @brief Set Encryption key
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_encode(struct net_device *dev,
+		    struct iw_request_info *info,
+		    struct iw_point *dwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	u16 is_default = 0, index = 0, set_tx_key = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (dwrq->flags & IW_ENCODE_DISABLED) {
+		disable_wep (assoc_req);
+		goto out;
+	}
+
+	ret = validate_key_index(assoc_req->wep_tx_keyidx,
+	                         (dwrq->flags & IW_ENCODE_INDEX),
+	                         &index, &is_default);
+	if (ret) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* If WEP isn't enabled, or if there is no key data but a valid
+	 * index, set the TX key.
+	 */
+	if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+	    || (dwrq->length == 0 && !is_default))
+		set_tx_key = 1;
+
+	ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+	if (ret)
+		goto out;
+
+	if (dwrq->length)
+		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+	if (set_tx_key)
+		set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+	if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+		assoc_req->secinfo.authmode = wlan802_11authmodeshared;
+	} else if (dwrq->flags & IW_ENCODE_OPEN) {
+		assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+	}
+
+out:
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		0 on success, otherwise failure
+ */
+static int wlan_get_encodeext(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq,
+			      char *extra)
+{
+	int ret = -EINVAL;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int index, max_key_len;
+
+	ENTER();
+
+	max_key_len = dwrq->length - sizeof(*ext);
+	if (max_key_len < 0)
+		goto out;
+
+	index = dwrq->flags & IW_ENCODE_INDEX;
+	if (index) {
+		if (index < 1 || index > 4)
+			goto out;
+		index--;
+	} else {
+		index = adapter->wep_tx_keyidx;
+	}
+
+	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+	    ext->alg != IW_ENCODE_ALG_WEP) {
+		if (index != 0 || adapter->inframode != wlan802_11infrastructure)
+			goto out;
+	}
+
+	dwrq->flags = index + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
+	    && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
+		ext->alg = IW_ENCODE_ALG_NONE;
+		ext->key_len = 0;
+		dwrq->flags |= IW_ENCODE_DISABLED;
+	} else {
+		u8 *key = NULL;
+
+		if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+		    && !adapter->secinfo.WPAenabled
+		    && !adapter->secinfo.WPA2enabled) {
+			ext->alg = IW_ENCODE_ALG_WEP;
+			ext->key_len = adapter->wep_keys[index].len;
+			key = &adapter->wep_keys[index].key[0];
+		} else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
+		           (adapter->secinfo.WPAenabled ||
+		            adapter->secinfo.WPA2enabled)) {
+			/* WPA */
+			ext->alg = IW_ENCODE_ALG_TKIP;
+			ext->key_len = 0;
+		} else {
+			goto out;
+		}
+
+		if (ext->key_len > max_key_len) {
+			ret = -E2BIG;
+			goto out;
+		}
+
+		if (ext->key_len)
+			memcpy(ext->key, key, ext->key_len);
+		else
+			dwrq->flags |= IW_ENCODE_NOKEY;
+		dwrq->flags |= IW_ENCODE_ENABLED;
+	}
+	ret = 0;
+
+out:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
+ *
+ *  @param dev                  A pointer to net_device structure
+ *  @param info			A pointer to iw_request_info structure
+ *  @param vwrq 		A pointer to iw_param structure
+ *  @param extra		A pointer to extra data buf
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_encodeext(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq,
+			      char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int alg = ext->alg;
+	struct assoc_request * assoc_req;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+		disable_wep (assoc_req);
+	} else if (alg == IW_ENCODE_ALG_WEP) {
+		u16 is_default = 0, index, set_tx_key = 0;
+
+		ret = validate_key_index(assoc_req->wep_tx_keyidx,
+		                         (dwrq->flags & IW_ENCODE_INDEX),
+		                         &index, &is_default);
+		if (ret)
+			goto out;
+
+		/* If WEP isn't enabled, or if there is no key data but a valid
+		 * index, or if the set-TX-key flag was passed, set the TX key.
+		 */
+		if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+		    || (dwrq->length == 0 && !is_default)
+		    || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
+			set_tx_key = 1;
+
+		/* Copy key to driver */
+		ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+					set_tx_key);
+		if (ret)
+			goto out;
+
+		if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeshared;
+		} else if (dwrq->flags & IW_ENCODE_OPEN) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+
+		/* Mark the various WEP bits as modified */
+		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		if (dwrq->length)
+			set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+		if (set_tx_key)
+			set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+	} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+		struct WLAN_802_11_KEY * pkey;
+
+		/* validate key length */
+		if (((alg == IW_ENCODE_ALG_TKIP)
+			&& (ext->key_len != KEY_LEN_WPA_TKIP))
+		    || ((alg == IW_ENCODE_ALG_CCMP)
+		        && (ext->key_len != KEY_LEN_WPA_AES))) {
+				lbs_pr_debug(1, "Invalid size %d for key of alg"
+				       "type %d.\n",
+				       ext->key_len,
+				       alg);
+				ret = -EINVAL;
+				goto out;
+		}
+
+		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+			pkey = &assoc_req->wpa_mcast_key;
+		else
+			pkey = &assoc_req->wpa_unicast_key;
+
+		memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+		memcpy(pkey->key, ext->key, ext->key_len);
+		pkey->len = ext->key_len;
+		pkey->flags = KEY_INFO_WPA_ENABLED;
+
+		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+			pkey->flags |= KEY_INFO_WPA_MCAST;
+			set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+		} else {
+			pkey->flags |= KEY_INFO_WPA_UNICAST;
+			set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+		}
+
+		if (alg == IW_ENCODE_ALG_TKIP)
+			pkey->type = KEY_TYPE_ID_TKIP;
+		else if (alg == IW_ENCODE_ALG_CCMP)
+			pkey->type = KEY_TYPE_ID_AES;
+
+		/* If WPA isn't enabled yet, do that now */
+		if (   assoc_req->secinfo.WPAenabled == 0
+		    && assoc_req->secinfo.WPA2enabled == 0) {
+			assoc_req->secinfo.WPAenabled = 1;
+			assoc_req->secinfo.WPA2enabled = 1;
+			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		}
+
+		disable_wep (assoc_req);
+	}
+
+out:
+	if (ret == 0) {
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int wlan_set_genie(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *dwrq,
+			  char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct assoc_request * assoc_req;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (dwrq->length > MAX_WPA_IE_LEN ||
+	    (dwrq->length && extra == NULL)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (dwrq->length) {
+		memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+		assoc_req->wpa_ie_len = dwrq->length;
+	} else {
+		memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+		assoc_req->wpa_ie_len = 0;
+	}
+
+out:
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_genie(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *dwrq,
+			  char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (adapter->wpa_ie_len == 0) {
+		dwrq->length = 0;
+		LEAVE();
+		return 0;
+	}
+
+	if (dwrq->length < adapter->wpa_ie_len) {
+		LEAVE();
+		return -E2BIG;
+	}
+
+	dwrq->length = adapter->wpa_ie_len;
+	memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+
+	LEAVE();
+	return 0;
+}
+
+
+static int wlan_set_auth(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *dwrq,
+			 char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	int ret = 0;
+	int updated = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	switch (dwrq->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * libertas does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+			assoc_req->secinfo.WPAenabled = 0;
+			assoc_req->secinfo.WPA2enabled = 0;
+		}
+		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
+			assoc_req->secinfo.WPAenabled = 1;
+			assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
+			assoc_req->secinfo.WPA2enabled = 1;
+			assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		if (dwrq->value) {
+			adapter->currentpacketfilter |=
+			    cmd_act_mac_strict_protection_enable;
+		} else {
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_strict_protection_enable;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeshared;
+		} else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		} else if (dwrq->value & IW_AUTH_ALG_LEAP) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodenetworkEAP;
+		} else {
+			ret = -EINVAL;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (dwrq->value) {
+			if (!assoc_req->secinfo.WPAenabled &&
+			    !assoc_req->secinfo.WPA2enabled) {
+				assoc_req->secinfo.WPAenabled = 1;
+				assoc_req->secinfo.WPA2enabled = 1;
+				assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+				assoc_req->secinfo.authmode =
+				    wlan802_11authmodeopen;
+			}
+		} else {
+			assoc_req->secinfo.WPAenabled = 0;
+			assoc_req->secinfo.WPA2enabled = 0;
+		}
+		updated = 1;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+out:
+	if (ret == 0) {
+		if (updated)
+			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else if (ret != -EOPNOTSUPP) {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_auth(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *dwrq,
+			 char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	switch (dwrq->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+		dwrq->value = 0;
+		if (adapter->secinfo.WPAenabled)
+			dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+		if (adapter->secinfo.WPA2enabled)
+			dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+		if (!dwrq->value)
+			dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		dwrq->value = 0;
+		if (adapter->currentpacketfilter &
+		    cmd_act_mac_strict_protection_enable)
+			dwrq->value = 1;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		switch (adapter->secinfo.authmode) {
+		case wlan802_11authmodeshared:
+			dwrq->value = IW_AUTH_ALG_SHARED_KEY;
+			break;
+		case wlan802_11authmodeopen:
+			dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+			break;
+		case wlan802_11authmodenetworkEAP:
+			dwrq->value = IW_AUTH_ALG_LEAP;
+			break;
+		default:
+			break;
+		}
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+			dwrq->value = 1;
+		break;
+
+	default:
+		LEAVE();
+		return -EOPNOTSUPP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+
+static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+		   struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	u16 dbm;
+
+	ENTER();
+
+	if (vwrq->disabled) {
+		wlan_radio_ioctl(priv, RADIO_OFF);
+		return 0;
+	}
+
+	adapter->preamble = cmd_type_auto_preamble;
+
+	wlan_radio_ioctl(priv, RADIO_ON);
+
+	if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+		dbm = (u16) mw_to_dbm(vwrq->value);
+	} else
+		dbm = (u16) vwrq->value;
+
+	/* auto tx power control */
+
+	if (vwrq->fixed == 0)
+		dbm = 0xffff;
+
+	lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_rf_tx_power,
+				    cmd_act_tx_power_opt_set_low,
+				    cmd_option_waitforrsp, 0, (void *)&dbm);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+	/*
+	 * Note : if dwrq->flags != 0, we should get the relevant SSID from
+	 * the SSID list...
+	 */
+
+	/*
+	 * Get the current SSID
+	 */
+	if (adapter->connect_status == libertas_connected) {
+		memcpy(extra, adapter->curbssparams.ssid.ssid,
+		       adapter->curbssparams.ssid.ssidlength);
+		extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+	} else {
+		memset(extra, 0, 32);
+		extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+	}
+	/*
+	 * If none, we may want to get the one that was set
+	 */
+
+	/* To make the driver backward compatible with WPA supplicant v0.2.4 */
+	if (dwrq->length == 32)	/* check with WPA supplicant buffer size */
+		dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
+				   IW_ESSID_MAX_SIZE);
+	else
+		dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
+
+	dwrq->flags = 1;	/* active */
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+		   struct iw_point *dwrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct WLAN_802_11_SSID ssid;
+	struct assoc_request * assoc_req;
+	int ssid_len = dwrq->length;
+
+	ENTER();
+
+	/*
+	 * WE-20 and earlier NULL pad the end of the SSID and increment
+	 * SSID length so it can be used like a string.  WE-21 and later don't,
+	 * but some userspace tools aren't able to cope with the change.
+	 */
+	if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
+		ssid_len--;
+
+	/* Check the size of the string */
+	if (ssid_len > IW_ESSID_MAX_SIZE) {
+		ret = -E2BIG;
+		goto out;
+	}
+
+	memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
+
+	if (!dwrq->flags || !ssid_len) {
+		/* "any" SSID requested; leave SSID blank */
+	} else {
+		/* Specific SSID requested */
+		memcpy(&ssid.ssid, extra, ssid_len);
+		ssid.ssidlength = ssid_len;
+	}
+
+	lbs_pr_debug(1, "Requested new SSID = %s\n",
+	       (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
+
+out:
+	mutex_lock(&adapter->lock);
+	if (ret == 0) {
+		/* Get or create the current association request */
+		assoc_req = wlan_get_association_request(adapter);
+		if (!assoc_req) {
+			ret = -ENOMEM;
+		} else {
+			/* Copy the SSID to the association request */
+			memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
+			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+			wlan_postpone_association_work(priv);
+		}
+	}
+
+	/* Cancel the association request if there was an error */
+	if (ret != 0) {
+		wlan_cancel_association_work(priv);
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param awrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *  @return             0 --success, otherwise fail
+ */
+static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+		 struct sockaddr *awrq, char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	int ret = 0;
+
+	ENTER();
+
+	if (awrq->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+
+	lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+
+	mutex_lock(&adapter->lock);
+
+	/* Get or create the current association request */
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		wlan_cancel_association_work(priv);
+		ret = -ENOMEM;
+	} else {
+		/* Copy the BSSID to the association request */
+		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	return ret;
+}
+
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+{
+	union {
+		u32 l;
+		u8 c[4];
+	} ver;
+	char fwver[32];
+
+	mutex_lock(&adapter->lock);
+	ver.l = adapter->fwreleasenumber;
+	mutex_unlock(&adapter->lock);
+
+	if (ver.c[3] == 0)
+		sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+	else
+		sprintf(fwver, "%u.%u.%u.p%u",
+			ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+	snprintf(fwversion, maxlen, fwver);
+}
+
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler wlan_handler[] = {
+	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
+	(iw_handler) wlan_get_name,	/* SIOCGIWNAME */
+	(iw_handler) NULL,	/* SIOCSIWNWID */
+	(iw_handler) NULL,	/* SIOCGIWNWID */
+	(iw_handler) wlan_set_freq,	/* SIOCSIWFREQ */
+	(iw_handler) wlan_get_freq,	/* SIOCGIWFREQ */
+	(iw_handler) wlan_set_mode,	/* SIOCSIWMODE */
+	(iw_handler) wlan_get_mode,	/* SIOCGIWMODE */
+	(iw_handler) NULL,	/* SIOCSIWSENS */
+	(iw_handler) NULL,	/* SIOCGIWSENS */
+	(iw_handler) NULL,	/* SIOCSIWRANGE */
+	(iw_handler) wlan_get_range,	/* SIOCGIWRANGE */
+	(iw_handler) NULL,	/* SIOCSIWPRIV */
+	(iw_handler) NULL,	/* SIOCGIWPRIV */
+	(iw_handler) NULL,	/* SIOCSIWSTATS */
+	(iw_handler) NULL,	/* SIOCGIWSTATS */
+	iw_handler_set_spy,	/* SIOCSIWSPY */
+	iw_handler_get_spy,	/* SIOCGIWSPY */
+	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
+	(iw_handler) wlan_set_wap,	/* SIOCSIWAP */
+	(iw_handler) wlan_get_wap,	/* SIOCGIWAP */
+	(iw_handler) NULL,	/* SIOCSIWMLME */
+	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
+	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) wlan_set_essid,	/* SIOCSIWESSID */
+	(iw_handler) wlan_get_essid,	/* SIOCGIWESSID */
+	(iw_handler) wlan_set_nick,	/* SIOCSIWNICKN */
+	(iw_handler) wlan_get_nick,	/* SIOCGIWNICKN */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) wlan_set_rate,	/* SIOCSIWRATE */
+	(iw_handler) wlan_get_rate,	/* SIOCGIWRATE */
+	(iw_handler) wlan_set_rts,	/* SIOCSIWRTS */
+	(iw_handler) wlan_get_rts,	/* SIOCGIWRTS */
+	(iw_handler) wlan_set_frag,	/* SIOCSIWFRAG */
+	(iw_handler) wlan_get_frag,	/* SIOCGIWFRAG */
+	(iw_handler) wlan_set_txpow,	/* SIOCSIWTXPOW */
+	(iw_handler) wlan_get_txpow,	/* SIOCGIWTXPOW */
+	(iw_handler) wlan_set_retry,	/* SIOCSIWRETRY */
+	(iw_handler) wlan_get_retry,	/* SIOCGIWRETRY */
+	(iw_handler) wlan_set_encode,	/* SIOCSIWENCODE */
+	(iw_handler) wlan_get_encode,	/* SIOCGIWENCODE */
+	(iw_handler) wlan_set_power,	/* SIOCSIWPOWER */
+	(iw_handler) wlan_get_power,	/* SIOCGIWPOWER */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) NULL,	/* -- hole -- */
+	(iw_handler) wlan_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+	(iw_handler) NULL,		/* SIOCSIWPMKSA */
+};
+
+struct iw_handler_def libertas_handler_def = {
+	.num_standard	= sizeof(wlan_handler) / sizeof(iw_handler),
+	.num_private	= sizeof(wlan_private_handler) / sizeof(iw_handler),
+	.num_private_args = sizeof(wlan_private_args) /
+		sizeof(struct iw_priv_args),
+	.standard	= (iw_handler *) wlan_handler,
+	.private	= (iw_handler *) wlan_private_handler,
+	.private_args	= (struct iw_priv_args *)wlan_private_args,
+	.get_wireless_stats = wlan_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644
index 0000000..39f367c
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.h
@@ -0,0 +1,147 @@
+/**
+  * This file contains definition for IOCTL call.
+  */
+#ifndef	_WLAN_WEXT_H_
+#define	_WLAN_WEXT_H_
+
+#define SUBCMD_OFFSET			4
+#define SUBCMD_DATA(x)			*((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** PRIVATE CMD ID */
+#define	WLANIOCTL			SIOCIWFIRSTPRIV
+
+#define WLANSETWPAIE			(WLANIOCTL + 0)
+
+#define WLAN_SETINT_GETINT		(WLANIOCTL + 7)
+#define WLANNF					1
+#define WLANRSSI				2
+#define WLANENABLE11D				5
+#define WLANADHOCGRATE				6
+#define WLAN_SUBCMD_SET_PRESCAN			11
+
+#define WLAN_SETNONE_GETNONE	        (WLANIOCTL + 8)
+#define WLANDEAUTH                  		1
+#define WLANRADIOON                 		2
+#define WLANRADIOOFF                		3
+#define WLANREMOVEADHOCAES          		4
+#define WLANADHOCSTOP               		5
+#define WLANCIPHERTEST              		6
+#define WLANCRYPTOTEST				7
+
+#define WLANWLANIDLEON				10
+#define WLANWLANIDLEOFF				11
+#define WLAN_SUBCMD_BT_RESET			13
+#define WLAN_SUBCMD_FWT_RESET			14
+
+#define WLANGETLOG                  	(WLANIOCTL + 9)
+#define GETLOG_BUFSIZE  300
+
+#define WLANSCAN_TYPE			(WLANIOCTL + 11)
+
+#define WLAN_SETNONE_GETONEINT		(WLANIOCTL + 15)
+#define WLANGETREGION				1
+#define WLAN_GET_LISTEN_INTERVAL		2
+#define WLAN_GET_MULTIPLE_DTIM			3
+#define WLAN_GET_TX_RATE			4
+#define	WLANGETBCNAVG				5
+
+#define WLAN_GET_LINKMODE			6
+#define WLAN_GET_RADIOMODE			7
+#define WLAN_GET_DEBUGMODE			8
+#define WLAN_SUBCMD_FWT_CLEANUP			15
+#define WLAN_SUBCMD_FWT_TIME			16
+#define WLAN_SUBCMD_MESH_GET_TTL		17
+
+#define WLANREGCFRDWR			(WLANIOCTL + 18)
+
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+#define WLAN_SUBCMD_GETRXANTENNA    1
+#define WLAN_SUBCMD_GETTXANTENNA    2
+#define WLAN_GET_TSF                3
+
+#define WLAN_SETNONE_GETWORDCHAR	(WLANIOCTL + 21)
+#define WLANGETADHOCAES				1
+
+#define WLAN_SETONEINT_GETONEINT	(WLANIOCTL + 23)
+#define WLAN_BEACON_INTERVAL			1
+#define	WLAN_LISTENINTRVL			4
+
+#define WLAN_TXCONTROL				6
+#define WLAN_NULLPKTINTERVAL			7
+
+#define WLAN_SETONEINT_GETNONE		(WLANIOCTL + 24)
+#define WLAN_SUBCMD_SETRXANTENNA		1
+#define WLAN_SUBCMD_SETTXANTENNA		2
+#define WLANSETAUTHALG				5
+#define WLANSET8021XAUTHALG			6
+#define WLANSETENCRYPTIONMODE			7
+#define WLANSETREGION				8
+#define WLAN_SET_LISTEN_INTERVAL		9
+
+#define WLAN_SET_MULTIPLE_DTIM			10
+#define WLAN_SET_ATIM_WINDOW			11
+#define WLANSETBCNAVG				13
+#define WLANSETDATAAVG				14
+#define WLAN_SET_LINKMODE			15
+#define WLAN_SET_RADIOMODE			16
+#define WLAN_SET_DEBUGMODE			17
+#define WLAN_SUBCMD_MESH_SET_TTL		18
+
+#define WLAN_SET128CHAR_GET128CHAR	(WLANIOCTL + 25)
+#define WLANSCAN_MODE				6
+
+#define WLAN_GET_ADHOC_STATUS			9
+
+#define WLAN_SUBCMD_BT_ADD			18
+#define WLAN_SUBCMD_BT_DEL   			19
+#define WLAN_SUBCMD_BT_LIST			20
+#define WLAN_SUBCMD_FWT_ADD				21
+#define WLAN_SUBCMD_FWT_DEL   		22
+#define WLAN_SUBCMD_FWT_LOOKUP		23
+#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR			24
+#define WLAN_SUBCMD_FWT_LIST			25
+#define WLAN_SUBCMD_FWT_LIST_ROUTE			26
+
+#define WLAN_SET_GET_SIXTEEN_INT       (WLANIOCTL + 29)
+#define WLAN_TPCCFG                             1
+#define WLAN_POWERCFG                           2
+
+#define WLAN_AUTO_FREQ_SET			3
+#define WLAN_AUTO_FREQ_GET			4
+#define WLAN_LED_GPIO_CTRL			5
+#define WLAN_SCANPROBES 			6
+#define	WLAN_ADAPT_RATESET			8
+#define	WLAN_INACTIVITY_TIMEOUT			9
+#define WLANSNR					10
+#define WLAN_GET_RATE				11
+#define	WLAN_GET_RXINFO				12
+
+#define WLANCMD52RDWR			(WLANIOCTL + 30)
+#define WLANCMD53RDWR			(WLANIOCTL + 31)
+#define CMD53BUFLEN				32
+
+#define	REG_MAC					0x19
+#define	REG_BBP					0x1a
+#define	REG_RF					0x1b
+#define	REG_EEPROM				0x59
+#define WLAN_LINKMODE_802_3			0
+#define WLAN_LINKMODE_802_11			2
+#define WLAN_RADIOMODE_NONE    			0
+#define WLAN_RADIOMODE_RADIOTAP			2
+
+/** wlan_ioctl_regrdwr */
+struct wlan_ioctl_regrdwr {
+	/** Which register to access */
+	u16 whichreg;
+	/** Read or Write */
+	u16 action;
+	u32 offset;
+	u16 NOB;
+	u32 value;
+};
+
+extern struct iw_handler_def libertas_handler_def;
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int wlan_radio_ioctl(wlan_private * priv, u8 option);
+
+#endif				/* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index a009ab5..45b00e1 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -1283,7 +1283,6 @@ static int netwave_rx(struct net_device 
 
 	skb_reserve( skb, 2);  /* Align IP on 16 byte */
 	skb_put( skb, rcvLen);
-	skb->dev = dev;
 
 	/* Copy packet fragments to the skb data area */
 	ptr = (u_char*) skb->data;
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 4e7f6cf..062286d 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -689,7 +689,7 @@ static void orinoco_stat_gather(struct n
 	/* Note : gcc will optimise the whole section away if
 	 * WIRELESS_SPY is not defined... - Jean II */
 	if (SPY_NUMBER(priv)) {
-		orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN,
+		orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
 				   desc->signal, desc->silence);
 	}
 }
@@ -770,7 +770,7 @@ static void orinoco_rx_monitor(struct ne
 
 	/* Copy the 802.11 header to the skb */
 	memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 
 	/* If any, copy the data from the card to the skb */
 	if (datalen > 0) {
@@ -915,7 +915,6 @@ static void __orinoco_ev_rx(struct net_d
 		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
 
 	dev->last_rx = jiffies;
-	skb->dev = dev;
 	skb->protocol = eth_type_trans(skb, dev);
 	skb->ip_summed = CHECKSUM_NONE;
 	if (fc & IEEE80211_FCTL_TODS)
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index b112291..dd070cc 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -136,7 +136,7 @@ #ifdef ISLPCI_ETH_DEBUG
 				printk("islpci_eth_transmit:wds_mac\n");
 #endif
 				memmove(skb->data + 6, src, skb->len);
-				memcpy(skb->data, wds_mac, 6);
+				skb_copy_to_linear_data(skb, wds_mac, 6);
 			} else {
 				memmove(skb->data, src, skb->len);
 			}
@@ -162,13 +162,16 @@ #endif
 
 			skb_put(newskb, init_wds ? skb->len + 6 : skb->len);
 			if (init_wds) {
-				memcpy(newskb->data + 6, skb->data, skb->len);
-				memcpy(newskb->data, wds_mac, 6);
+				skb_copy_from_linear_data(skb,
+							  newskb->data + 6,
+							  skb->len);
+				skb_copy_to_linear_data(newskb, wds_mac, 6);
 #ifdef ISLPCI_ETH_DEBUG
 				printk("islpci_eth_transmit:wds_mac\n");
 #endif
 			} else
-				memcpy(newskb->data, skb->data, skb->len);
+				skb_copy_from_linear_data(skb, newskb->data,
+							  skb->len);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
 			DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n",
@@ -303,7 +306,7 @@ islpci_monitor_rx(islpci_private *priv, 
 		skb_pull(*skb, sizeof (struct rfmon_header));
 
 	(*skb)->protocol = htons(ETH_P_802_2);
-	(*skb)->mac.raw = (*skb)->data;
+	skb_reset_mac_header(*skb);
 	(*skb)->pkt_type = PACKET_OTHERHOST;
 
 	return 0;
@@ -374,10 +377,6 @@ #if VERBOSE > SHOW_ERROR_MESSAGES
 	DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data);
 	display_buffer((char *) skb->data, skb->len);
 #endif
-
-	/* do some additional sk_buff and network layer parameters */
-	skb->dev = ndev;
-
 	/* take care of monitor mode and spy monitoring. */
 	if (unlikely(priv->iw_mode == IW_MODE_MONITOR))
 		discard = islpci_monitor_rx(priv, &skb);
@@ -398,8 +397,10 @@ #endif
 			/* Update spy records */
 			wireless_spy_update(ndev, annex->addr2, &wstats);
 
-			memcpy(skb->data + sizeof (struct rfmon_header),
-			       skb->data, 2 * ETH_ALEN);
+			skb_copy_from_linear_data(skb,
+						  (skb->data +
+						   sizeof(struct rfmon_header)),
+						  2 * ETH_ALEN);
 			skb_pull(skb, sizeof (struct rfmon_header));
 		}
 		skb->protocol = eth_type_trans(skb, ndev);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 47b2ccb..3be6242 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -2232,7 +2232,6 @@ #endif
         return;
     }
     skb_reserve( skb, 2);   /* Align IP on 16 byte (TBD check this)*/
-    skb->dev = dev;
 
     DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len);
 
@@ -2243,7 +2242,8 @@ #endif
     rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
     /* Get source address */
 #ifdef WIRELESS_SPY
-    memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN);
+    skb_copy_from_linear_data_offset(skb, offsetof(struct mac_header, addr_2),
+				     linksrcaddr, ETH_ALEN);
 #endif
     /* Now, deal with encapsulation/translation/sniffer */
     if (!sniffer) {
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index f5ce1c6..ef32a5c 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1971,8 +1971,7 @@ static struct net_device *get_strip_dev(
 		      sizeof(zero_address))) {
 		struct net_device *dev;
 		read_lock_bh(&dev_base_lock);
-		dev = dev_base;
-		while (dev) {
+		for_each_netdev(dev) {
 			if (dev->type == strip_info->dev->type &&
 			    !memcmp(dev->dev_addr,
 				    &strip_info->true_dev_addr,
@@ -1983,7 +1982,6 @@ static struct net_device *get_strip_dev(
 				read_unlock_bh(&dev_base_lock);
 				return (dev);
 			}
-			dev = dev->next;
 		}
 		read_unlock_bh(&dev_base_lock);
 	}
@@ -2009,7 +2007,7 @@ static void deliver_packet(struct strip 
 		       packetlen);
 		skb->dev = get_strip_dev(strip_info);
 		skb->protocol = header->protocol;
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 
 		/* Having put a fake header on the front of the sk_buff for the */
 		/* benefit of tools like tcpdump, skb_pull now 'consumes' that  */
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
deleted file mode 100644
index 3223401..0000000
--- a/drivers/net/wireless/todo.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-	Wireless Todo
-	-------------
-
-1) Bring other kernel Wireless LAN drivers here
-	Completed
-
-2) Bring new Wireless LAN driver not yet in the kernel there
-	See my web page for details
-	In particular : HostAP
-
-3) Misc
-	o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
-	o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
-
-	Jean II
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 2aa3c76..1cf090d 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2512,14 +2512,13 @@ #endif
 		return;
 	}
 
-	skb->dev = dev;
-
 	/* Copy the packet to the buffer. */
 	obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize);
 	skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-	wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+	wv_packet_info(skb_mac_header(skb), sksize, dev->name,
+		       "wv_packet_read");
 #endif				/* DEBUG_RX_INFO */
 
 	/* Statistics-gathering and associated stuff.
@@ -2555,7 +2554,7 @@ #endif
 
 		/* Spying stuff */
 #ifdef IW_WIRELESS_SPY
-		wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
+		wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE,
 			      stats);
 #endif /* IW_WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2939,7 +2938,7 @@ #endif
 	 * need to pad. Jean II */
 	if (skb->len < ETH_ZLEN) {
 		memset(data, 0, ETH_ZLEN);
-		memcpy(data, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, data, skb->len);
 		/* Write packet on the card */
 		if(wv_packet_write(dev, data, ETH_ZLEN))
 			return 1;	/* We failed */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index b042397..67b867f 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -2884,14 +2884,12 @@ #endif
       return;
     }
 
-  skb->dev = dev;
-
   skb_reserve(skb, 2);
   fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize);
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+  wv_packet_info(skb_mac_header(skb), sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
   /* Statistics gathering & stuff associated.
@@ -2925,7 +2923,7 @@ #ifdef WAVELAN_ROAMING
 #endif	/* WAVELAN_ROAMING */
 	  
 #ifdef WIRELESS_SPY
-      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
+      wl_spy_gather(dev, skb_mac_header(skb) + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
       wl_his_gather(dev, stats);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 6cb66a3..935b144 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -327,7 +327,6 @@ static void zd1201_usbrx(struct urb *urb
 			memcpy(skb_put(skb, 6), &data[datalen-8], 6);
 			memcpy(skb_put(skb, 2), &data[datalen-24], 2);
 			memcpy(skb_put(skb, len), data, len);
-			skb->dev = zd->dev;
 			skb->dev->last_rx = jiffies;
 			skb->protocol = eth_type_trans(skb, zd->dev);
 			zd->stats.rx_packets++;
@@ -385,7 +384,6 @@ static void zd1201_usbrx(struct urb *urb
 			memcpy(skb_put(skb, 2), &data[6], 2);
 			memcpy(skb_put(skb, len), data+8, len);
 		}
-		skb->dev = zd->dev;
 		skb->dev->last_rx = jiffies;
 		skb->protocol = eth_type_trans(skb, zd->dev);
 		zd->stats.rx_packets++;
@@ -809,10 +807,10 @@ static int zd1201_hard_start_xmit(struct
 	txbuf[4] = 0x00;
 	txbuf[5] = 0x00;
 
-	memcpy(txbuf+6, skb->data+12, skb->len-12);
+	skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12);
 	if (pad)
 		txbuf[skb->len-12+6]=0;
-	memcpy(txbuf+skb->len-12+6+pad, skb->data, 12);
+	skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12);
 	*(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
 	txbuf[txbuflen-1] = 0;
 
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
index 66ed55b..d1ab24a 100644
--- a/drivers/net/wireless/zd1211rw/Kconfig
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -1,6 +1,7 @@
 config ZD1211RW
 	tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
-	depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+	depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
+	select WIRELESS_EXT
 	select FW_LOADER
 	---help---
 	  This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 87ee3ee..95b4a2a 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -67,11 +67,12 @@ 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%c", chip->pa_type,
+	i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
 		chip->patch_cck_gain ? 'g' : '-',
 		chip->patch_cr157 ? '7' : '-',
 		chip->patch_6m_band_edge ? '6' : '-',
-		chip->new_phy_layout ? 'N' : '-');
+		chip->new_phy_layout ? 'N' : '-',
+		chip->al2230s_bit ? 'S' : '-');
 	return i;
 }
 
@@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip *
 	/* Allocate a single memory block for values and addresses. */
 	count16 = 2*count;
 	a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
-		                   GFP_NOFS);
+		                   GFP_KERNEL);
 	if (!a16) {
 		dev_dbg_f(zd_chip_dev(chip),
 			  "error ENOMEM in allocation of a16\n");
@@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip
 
 	/* Allocate a single memory block for values and addresses. */
 	count16 = 2*count;
-	ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+	ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL);
 	if (!ioreqs16) {
 		r = -ENOMEM;
 		dev_dbg_f(zd_chip_dev(chip),
@@ -614,16 +615,24 @@ static int patch_cr157(struct zd_chip *c
  * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
  * bit (for AL2230, AL2230S)
  */
-static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+static int patch_6m_band_edge(struct zd_chip *chip, u8 channel)
+{
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	if (!chip->patch_6m_band_edge)
+		return 0;
+
+	return zd_rf_patch_6m_band_edge(&chip->rf, channel);
+}
+
+/* Generic implementation of 6M band edge patching, used by most RFs via
+ * zd_rf_generic_patch_6m() */
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
 {
 	struct zd_ioreq16 ioreqs[] = {
 		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
 		{ CR47,  0x1e },
 	};
 
-	if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
-		return 0;
-
 	/* FIXME: Channel 11 is not the edge for all regulatory domains. */
 	if (channel == 1 || channel == 11)
 		ioreqs[0].value = 0x12;
@@ -683,17 +692,17 @@ static int zd1211_hw_reset_phy(struct zd
 		{ CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
 		{ CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
 		{ CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
-		{ CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
-		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
-		{ CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
-		{ CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
-		{ CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
-		{ CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
-		{ CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
-		{ CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
-		{ CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
-		{ CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+		{ CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
+		{ CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
+		{ CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
+		{ CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
+		{ CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
+		{ CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
+		{ CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
+		{ CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+		{ CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+		{ CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+		{ CR170, 0xba }, { CR171, 0xba },
 		/* Note: CR204 must lead the CR203 */
 		{ CR204, 0x7d },
 		{ },
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index e57ed75..ce0a5f6 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -833,6 +833,7 @@ int zd_chip_enable_rx(struct zd_chip *ch
 void zd_chip_disable_rx(struct zd_chip *chip);
 int zd_chip_enable_hwint(struct zd_chip *chip);
 int zd_chip_disable_hwint(struct zd_chip *chip);
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel);
 
 int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
 	u8 rts_rate, int preamble);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 4c5f78e..6753d24 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[] = {
-		{ CR_RX_FILTER, STA_RX_FILTER },
-		{ CR_SNIFFER_ON, 0U },
-	};
-
-	if (ieee->iw_mode == IW_MODE_MONITOR) {
-		ioreqs[0].value = 0xffffffff;
-		ioreqs[1].value = 0x1;
-	}
-
-	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
+	u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
+	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -974,14 +965,14 @@ static int is_data_packet_for_us(struct 
 	switch (ieee->iw_mode) {
 	case IW_MODE_ADHOC:
 		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
-		    memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+		    compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
 			return 0;
 		break;
 	case IW_MODE_AUTO:
 	case IW_MODE_INFRA:
 		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
 		    IEEE80211_FCTL_FROMDS ||
-		    memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+		    compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
 			return 0;
 		break;
 	default:
@@ -989,9 +980,9 @@ static int is_data_packet_for_us(struct 
 		return 0;
 	}
 
-	return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+	return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
 	       (is_multicast_ether_addr(hdr->addr1) &&
-		memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+		compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
 	       (netdev->flags & IFF_PROMISC);
 }
 
@@ -1047,7 +1038,7 @@ static void update_qual_rssi(struct zd_m
 	hdr = (struct ieee80211_hdr_3addr *)buffer;
 	if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
 		return;
-	if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+	if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
 		return;
 
 	spin_lock_irqsave(&mac->lock, flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index f50cff3..549c23b 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@ #include "zd_rf.h"
 #include "zd_ieee80211.h"
 #include "zd_chip.h"
 
-static const char *rfs[] = {
+static const char * const rfs[] = {
 	[0]		= "unknown RF0",
 	[1]		= "unknown RF1",
 	[UW2451_RF]	= "UW2451_RF",
@@ -34,7 +34,7 @@ static const char *rfs[] = {
 	[AL2210_RF]	= "AL2210_RF",
 	[MAXIM_NEW_RF]	= "MAXIM_NEW_RF",
 	[UW2453_RF]	= "UW2453_RF",
-	[AL2230S_RF]	= "AL2230S_RF",
+	[UNKNOWN_A_RF]	= "UNKNOWN_A_RF",
 	[RALINK_RF]	= "RALINK_RF",
 	[INTERSIL_RF]	= "INTERSIL_RF",
 	[RF2959_RF]	= "RF2959_RF",
@@ -154,3 +154,17 @@ int zd_switch_radio_off(struct zd_rf *rf
 		r = t;
 	return r;
 }
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel)
+{
+	if (!rf->patch_6m_band_edge)
+		return 0;
+
+	return rf->patch_6m_band_edge(rf, channel);
+}
+
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel)
+{
+	return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel);
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index a57732e..aa9cc10 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -26,7 +26,7 @@ #define THETA_RF			0x6
 #define AL2210_RF			0x7
 #define MAXIM_NEW_RF			0x8
 #define UW2453_RF			0x9
-#define AL2230S_RF			0xa
+#define UNKNOWN_A_RF			0xa
 #define RALINK_RF			0xb
 #define INTERSIL_RF			0xc
 #define RF2959_RF			0xd
@@ -47,17 +47,13 @@ struct zd_rf {
 	u8 type;
 
 	u8 channel;
-	/*
-	 * Whether this RF should patch the 6M band edge
-	 * (assuming E2P_POD agrees)
-	 */
-	u8 patch_6m_band_edge:1;
 
 	/* RF-specific functions */
 	int (*init_hw)(struct zd_rf *rf);
 	int (*set_channel)(struct zd_rf *rf, u8 channel);
 	int (*switch_radio_on)(struct zd_rf *rf);
 	int (*switch_radio_off)(struct zd_rf *rf);
+	int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
 };
 
 const char *zd_rf_name(u8 type);
@@ -72,6 +68,9 @@ int zd_rf_set_channel(struct zd_rf *rf, 
 int zd_switch_radio_on(struct zd_rf *rf);
 int zd_switch_radio_off(struct zd_rf *rf);
 
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
 /* Functions for individual RF chips */
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 5235a78..511392a 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_i
 	{ CR240, 0x57 }, { CR9,   0xe0 },
 };
 
+static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
+	{ CR47,   0x1e }, /* MARK_002 */
+	{ CR106,  0x22 },
+	{ CR107,  0x2a }, /* MARK_002 */
+	{ CR109,  0x13 }, /* MARK_002 */
+	{ CR118,  0xf8 }, /* MARK_002 */
+	{ CR119,  0x12 }, { CR122,  0xe0 },
+	{ CR128,  0x10 }, /* MARK_001 from 0xe->0x10 */
+	{ CR129,  0x0e }, /* MARK_001 from 0xd->0x0e */
+	{ CR130,  0x10 }, /* MARK_001 from 0xb->0x0d */
+};
+
 static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
 {
 	int r;
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct 
 	int r;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	static const struct zd_ioreq16 ioreqs[] = {
+	static const struct zd_ioreq16 ioreqs_init[] = {
 		{ CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
 		{ CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
 		{ CR44,   0x33 }, { CR106,  0x2a }, { CR107, 0x1a },
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct 
 		{ CR119,  0x10 }, { CR120,  0x4f }, { CR121, 0x77 },
 		{ CR122,  0xe0 }, { CR137,  0x88 }, { CR252, 0xff },
 		{ CR253,  0xff },
+	};
 
-		/* These following happen separately in the vendor driver */
-		{ },
-
+	static const struct zd_ioreq16 ioreqs_pll[] = {
 		/* shdnb(PLL_ON)=0 */
 		{ CR251,  0x2f },
 		/* shdnb(PLL_ON)=1 */
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct 
 		{ CR138,  0x28 }, { CR203,  0x06 },
 	};
 
-	static const u32 rv[] = {
+	static const u32 rv1[] = {
 		/* Channel 1 */
 		0x03f790,
 		0x033331,
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct 
 		0x0b3331,
 		0x03b812,
 		0x00fff3,
+	};
+
+	static const u32 rv2[] = {
 		0x000da4,
 		0x0f4dc5, /* fix freq shift, 0x04edc5 */
 		0x0805b6,
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct 
 		0x0bdffc,
 		0x00000d,
 		0x00500f,
+	};
 
-		/* These writes happen separately in the vendor driver */
+	static const u32 rv3[] = {
 		0x00d00f,
 		0x004c0f,
 		0x00540f,
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct 
 		0x00500f,
 	};
 
-	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init));
 	if (r)
 		return r;
 
-	r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+	if (chip->al2230s_bit) {
+		r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+			ARRAY_SIZE(ioreqs_init_al2230s));
+		if (r)
+			return r;
+	}
+
+	r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+	if (r)
+		return r;
+
+	/* improve band edge for AL2230S */
+	if (chip->al2230s_bit)
+		r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
+	else
+		r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
+	if (r)
+		return r;
+
+	r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+	if (r)
+		return r;
+
+	r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll));
+	if (r)
+		return r;
+
+	r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
 	if (r)
 		return r;
 
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct
 		0x481dc0,
 		0xcfff00,
 		0x25a000,
+	};
 
+	static const u32 rv2[] = {
 		/* To improve AL2230 yield, improve phase noise, 4713 */
 		0x25a000,
 		0xa3b2f0,
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct
 		{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
 	};
 
-	static const u32 rv2[] = {
+	static const u32 rv3[] = {
 		/* To improve AL2230 yield, 4713 */
 		0xf01b00,
 		0xf01e00,
@@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct
 	r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
 	if (r)
 		return r;
+
+	if (chip->al2230s_bit) {
+		r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+			ARRAY_SIZE(ioreqs_init_al2230s));
+		if (r)
+			return r;
+	}
+
 	r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
 	if (r)
 		return r;
 	r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
 	if (r)
 		return r;
-	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+
+	if (chip->al2230s_bit)
+		r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
+	else
+		r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
 	if (r)
 		return r;
+
 	r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
 	if (r)
 		return r;
+	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+	if (r)
+		return r;
+	r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3));
+	if (r)
+		return r;
 	r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
 	if (r)
 		return r;
@@ -358,12 +421,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	if (chip->al2230s_bit) {
-		dev_err(zd_chip_dev(chip), "AL2230S devices are not yet "
-			"supported by this driver.\n");
-		return -ENODEV;
-	}
-
 	rf->switch_radio_off = al2230_switch_radio_off;
 	if (chip->is_zd1211b) {
 		rf->init_hw = zd1211b_al2230_init_hw;
@@ -374,6 +431,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 		rf->set_channel = zd1211_al2230_set_channel;
 		rf->switch_radio_on = zd1211_al2230_switch_radio_on;
 	}
-	rf->patch_6m_band_edge = 1;
+	rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
 	return 0;
 }
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index a289f95..5e5e9dd 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -51,9 +51,52 @@ static const u32 std_rv[] = {
 	0xd8c010,
 };
 
-static int al7230b_init_hw(struct zd_rf *rf)
+static const u32 rv_init1[] = {
+	0x3c9000,
+	0xbfffff,
+	0x700000,
+	0xf15d58,
+};
+
+static const u32 rv_init2[] = {
+	0xf15d59,
+	0xf15d5c,
+	0xf15d58,
+};
+
+static const struct zd_ioreq16 ioreqs_sw[] = {
+	{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+	{ CR38,  0x38 }, { CR136, 0xdf },
+};
+
+static int zd1211b_al7230b_finalize(struct zd_chip *chip)
 {
-	int i, r;
+	int r;
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+		{ CR203, 0x04 },
+		{ },
+		{ CR240, 0x80 },
+	};
+
+	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	if (r)
+		return r;
+
+	if (chip->new_phy_layout) {
+		/* antenna selection? */
+		r = zd_iowrite16_locked(chip, 0xe5, CR9);
+		if (r)
+			return r;
+	}
+
+	return zd_iowrite16_locked(chip, 0x04, CR203);
+}
+
+static int zd1211_al7230b_init_hw(struct zd_rf *rf)
+{
+	int r;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	/* All of these writes are identical to AL2230 unless otherwise
@@ -117,39 +160,136 @@ static int al7230b_init_hw(struct zd_rf 
 	};
 
 	static const struct zd_ioreq16 ioreqs_2[] = {
-		/* PLL_ON */
-		{ CR251, 0x3f },
+		{ CR251, 0x3f }, /* PLL_ON */
 		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
-		{ CR38, 0x38 }, { CR136, 0xdf },
+		{ 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);
+	r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+
+	r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
 	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_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
+	if (r)
+		return r;
 
-	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+	r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+
+	r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0x700000);
+
+	r = zd_iowrite16_locked(chip, 0x06, CR203);
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+	r = zd_iowrite16_locked(chip, 0x80, CR240);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static int zd1211b_al7230b_init_hw(struct zd_rf *rf)
+{
+	int r;
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	static const struct zd_ioreq16 ioreqs_1[] = {
+		{ CR240, 0x57 }, { CR9,   0x9 },
+		{ },
+		{ CR10,  0x8b }, { CR15,  0x20 },
+		{ CR17,  0x2B }, /* for newest (3rd cut) AL2230 */
+		{ CR20,  0x10 }, /* 4N25->Stone Request */
+		{ CR23,  0x40 }, { CR24,  0x20 }, { CR26,  0x93 },
+		{ CR28,  0x3e }, { CR29,  0x00 },
+		{ CR33,  0x28 }, /* 5613 */
+		{ CR34,  0x30 },
+		{ CR35,  0x3e }, /* for newest (3rd cut) AL2230 */
+		{ CR41,  0x24 }, { CR44,  0x32 },
+		{ CR46,  0x99 }, /* for newest (3rd cut) AL2230 */
+		{ CR47,  0x1e },
+
+		/* ZD1215 5610 */
+		{ CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
+		{ CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
+		{ CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
+		{ CR69,  0x28 },
+
+		{ CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
+		{ CR87,  0x0A }, { CR89,  0x04 },
+		{ CR90,  0x58 }, /* 5112 */
+		{ CR91,  0x00 }, /* 5613 */
+		{ CR92,  0x0a },
+		{ CR98,  0x8d }, /* 4804, for 1212 new algorithm */
+		{ CR99,  0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
+		{ CR102, 0x27 },
+		{ CR106, 0x20 }, /* change to 0x24 for AL7230B */
+		{ CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+		{ CR112, 0x1f },
+	};
+
+	static const struct zd_ioreq16 ioreqs_new_phy[] = {
+		{ CR107, 0x28 },
+		{ CR110, 0x1f }, /* 5127, 0x13->0x1f */
+		{ CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+		{ CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
+		{ CR121, 0x6c }, /* 5613 */
+	};
+
+	static const struct zd_ioreq16 ioreqs_old_phy[] = {
+		{ CR107, 0x24 },
+		{ CR110, 0x13 }, /* 5127, 0x13->0x1f */
+		{ CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+		{ CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
+		{ CR121, 0x6a }, /* 5613 */
+	};
+
+	static const struct zd_ioreq16 ioreqs_2[] = {
+		{ CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
+		{ CR117, 0xfa }, { CR120, 0x4f },
+		{ CR122, 0xfc }, /* E0->FCh at 4901 */
+		{ CR123, 0x57 }, /* 5613 */
+		{ CR125, 0xad }, /* 4804, for 1212 new algorithm */
+		{ CR126, 0x6c }, /* 5613 */
+		{ CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+		{ CR130, 0x10 },
+		{ CR131, 0x00 }, /* 5112 */
+		{ CR137, 0x50 }, /* 5613 */
+		{ CR138, 0xa8 }, /* 5112 */
+		{ CR144, 0xac }, /* 5613 */
+		{ CR148, 0x40 }, /* 5112 */
+		{ CR149, 0x40 }, /* 4O07, 50->40 */
+		{ CR150, 0x1a }, /* 5112, 0C->1A */
+		{ CR252, 0x34 }, { CR253, 0x34 },
+		{ CR251, 0x2f }, /* PLL_OFF */
+	};
+
+	static const struct zd_ioreq16 ioreqs_3[] = {
+		{ CR251, 0x7f }, /* PLL_ON */
+		{ 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;
+
+	if (chip->new_phy_layout)
+		r = zd_iowrite16a_locked(chip, ioreqs_new_phy,
+			ARRAY_SIZE(ioreqs_new_phy));
+	else
+		r = zd_iowrite16a_locked(chip, ioreqs_old_phy,
+			ARRAY_SIZE(ioreqs_old_phy));
 	if (r)
 		return r;
 
@@ -157,38 +297,36 @@ static int al7230b_init_hw(struct zd_rf 
 	if (r)
 		return r;
 
-	r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+	r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+
+	r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
 	if (r)
 		return r;
-	r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+
+	r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
 	if (r)
 		return r;
 
-	r = zd_iowrite16_locked(chip, 0x06, CR203);
+	r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3));
 	if (r)
 		return r;
-	r = zd_iowrite16_locked(chip, 0x80, CR240);
+
+	r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
 	if (r)
 		return r;
 
-	return 0;
+	return zd1211b_al7230b_finalize(chip);
 }
 
-static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel)
 {
-	int i, r;
+	int 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[] = {
+	static const struct zd_ioreq16 ioreqs[] = {
 		/* PLL_ON */
 		{ CR251, 0x3f },
 		{ CR203, 0x06 }, { CR240, 0x08 },
@@ -203,11 +341,9 @@ static int al7230b_set_channel(struct zd
 	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_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+	if (r)
+		return r;
 
 	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
 	if (r)
@@ -216,24 +352,69 @@ static int al7230b_set_channel(struct zd
 	if (r)
 		return r;
 
-	r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+	r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
 	if (r)
 		return r;
 
-	for (i = 0; i < 2; i++) {
-		r = zd_rfwrite_cr_locked(chip, rv[i]);
-		if (r)
-			return r;
-	}
+	r = zd_rfwritev_cr_locked(chip, rv, 2);
+	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));
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
-static int al7230b_switch_radio_on(struct zd_rf *rf)
+static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+	int r;
+	const u32 *rv = chan_rv[channel-1];
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	r = zd_iowrite16_locked(chip, 0x57, CR240);
+	if (r)
+		return r;
+	r = zd_iowrite16_locked(chip, 0xe4, CR9);
+	if (r)
+		return r;
+
+	/* PLL_OFF */
+	r = zd_iowrite16_locked(chip, 0x2f, CR251);
+	if (r)
+		return r;
+	r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+	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_sw, ARRAY_SIZE(ioreqs_sw));
+	if (r)
+		return r;
+
+	r = zd_rfwritev_cr_locked(chip, rv, 2);
+	if (r)
+		return r;
+
+	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+	if (r)
+		return r;
+
+	r = zd_iowrite16_locked(chip, 0x7f, CR251);
+	if (r)
+		return r;
+
+	return zd1211b_al7230b_finalize(chip);
+}
+
+static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf)
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
@@ -244,6 +425,17 @@ static int al7230b_switch_radio_on(struc
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+static int zd1211b_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, 0x7f },
+	};
+
+	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);
@@ -255,20 +447,45 @@ static int al7230b_switch_radio_off(stru
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+/* ZD1211B+AL7230B 6m band edge patching differs slightly from other
+ * configurations */
+static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel)
+{
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+	struct zd_ioreq16 ioreqs[] = {
+		{ CR128, 0x14 }, { CR129, 0x12 },
+	};
+
+	/* FIXME: Channel 11 is not the edge for all regulatory domains. */
+	if (channel == 1) {
+		ioreqs[0].value = 0x0e;
+		ioreqs[1].value = 0x10;
+	} else if (channel == 11) {
+		ioreqs[0].value = 0x10;
+		ioreqs[1].value = 0x10;
+	}
+
+	dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+	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 = zd1211b_al7230b_init_hw;
+		rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
+		rf->set_channel = zd1211b_al7230b_set_channel;
+		rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m;
+	} else {
+		rf->init_hw = zd1211_al7230b_init_hw;
+		rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
+		rf->set_channel = zd1211_al7230b_set_channel;
+		rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
 	}
 
-	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_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 5824727..2d736bd 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -21,7 +21,7 @@ #include "zd_rf.h"
 #include "zd_usb.h"
 #include "zd_chip.h"
 
-static u32 rf2959_table[][2] = {
+static const u32 rf2959_table[][2] = {
 	RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
 	RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
 	RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *
 static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
 {
 	int i, r;
-	u32 *rv = rf2959_table[channel-1];
+	const u32 *rv = rf2959_table[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	for (i = 0; i < 2; i++) {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index edaaad2..e04cffc 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -62,7 +63,10 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
@@ -413,7 +417,7 @@ int zd_usb_enable_int(struct zd_usb *usb
 
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
-	urb = usb_alloc_urb(0, GFP_NOFS);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb) {
 		r = -ENOMEM;
 		goto out;
@@ -431,7 +435,7 @@ int zd_usb_enable_int(struct zd_usb *usb
 
 	/* TODO: make it a DMA buffer */
 	r = -ENOMEM;
-	transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+	transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_dbg_f(zd_usb_dev(usb),
 			"couldn't allocate transfer_buffer\n");
@@ -445,7 +449,7 @@ int zd_usb_enable_int(struct zd_usb *usb
 			 intr->interval);
 
 	dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
-	r = usb_submit_urb(urb, GFP_NOFS);
+	r = usb_submit_urb(urb, GFP_KERNEL);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
 			 "Couldn't submit urb. Error number %d\n", r);
@@ -594,10 +598,10 @@ static struct urb *alloc_urb(struct zd_u
 	struct urb *urb;
 	void *buffer;
 
-	urb = usb_alloc_urb(0, GFP_NOFS);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return NULL;
-	buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+	buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
 		                  &urb->transfer_dma);
 	if (!buffer) {
 		usb_free_urb(urb);
@@ -630,7 +634,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
 	r = -ENOMEM;
-	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
 	if (!urbs)
 		goto error;
 	for (i = 0; i < URBS_COUNT; i++) {
@@ -651,7 +655,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 	spin_unlock_irq(&rx->lock);
 
 	for (i = 0; i < URBS_COUNT; i++) {
-		r = usb_submit_urb(urbs[i], GFP_NOFS);
+		r = usb_submit_urb(urbs[i], GFP_KERNEL);
 		if (r)
 			goto error_submit;
 	}
@@ -1157,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb,
 	}
 
 	req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
@@ -1220,7 +1224,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb
 
 	req_len = sizeof(struct usb_req_write_regs) +
 		  count * sizeof(struct reg_data);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
@@ -1300,7 +1304,7 @@ #endif /* DEBUG */
 	bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
 
 	req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 2412ce4..3f4a7cf 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1137,7 +1137,6 @@ #endif
 				skb = dev_alloc_skb(pkt_len + 2);
 				if (skb == NULL)
 					break;
-				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
 				eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0);
 				skb_put(skb, pkt_len);
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index b24b072..4032e9f 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -774,7 +774,6 @@ #endif
 				znet->stats.rx_dropped++;
 				break;
 			}
-			skb->dev = dev;
 
 			if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) {
 				int semi_cnt = (znet->rx_end - znet->rx_cur)<<1;
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 9bb4db5..a68b3b3 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -22,8 +22,6 @@ #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 
-#include <linux/pci.h>
-
 struct hppb_card {
 	unsigned long hpa;
 	struct resource mmio_region;
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 21c4c29..5b86ee5 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -38,7 +38,6 @@ #include <linux/init.h>		/* for __init a
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include <asm/byteorder.h>
 #include <asm/pdc.h>
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index d190c05..98be288 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -365,15 +365,13 @@ #else
 	 * for reading should be OK */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 	    struct net_device_stats *stats;
 	    struct in_device *in_dev = __in_dev_get_rcu(dev);
 	    if (!in_dev || !in_dev->ifa_list)
 		continue;
 	    if (LOOPBACK(in_dev->ifa_list->ifa_local))
 		continue;
-	    if (!dev->get_stats) 
-		continue;
 	    stats = dev->get_stats(dev);
 	    rx_total += stats->rx_packets;
 	    tx_total += stats->tx_packets;
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index ea1b7a6..815e445 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -520,17 +520,17 @@ static struct pdcspath_entry *pdcspath_e
 
 /**
  * pdcs_size_read - Stable Storage size output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
 static ssize_t
-pdcs_size_read(struct subsystem *entry, char *buf)
+pdcs_size_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
-	
-	if (!entry || !buf)
+
+	if (!kset || !buf)
 		return -EINVAL;
-		
+
 	/* show the size of the stable storage */
 	out += sprintf(out, "%ld\n", pdcs_size);
 
@@ -539,17 +539,17 @@ pdcs_size_read(struct subsystem *entry, 
 
 /**
  * pdcs_auto_read - Stable Storage autoboot/search flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
  */
 static ssize_t
-pdcs_auto_read(struct subsystem *entry, char *buf, int knob)
+pdcs_auto_read(struct kset *kset, char *buf, int knob)
 {
 	char *out = buf;
 	struct pdcspath_entry *pathentry;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	/* Current flags are stored in primary boot path entry */
@@ -565,40 +565,40 @@ pdcs_auto_read(struct subsystem *entry, 
 
 /**
  * pdcs_autoboot_read - Stable Storage autoboot flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
 static inline ssize_t
-pdcs_autoboot_read(struct subsystem *entry, char *buf)
+pdcs_autoboot_read(struct kset *kset, char *buf)
 {
-	return pdcs_auto_read(entry, buf, PF_AUTOBOOT);
+	return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_read - Stable Storage autoboot flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
 static inline ssize_t
-pdcs_autosearch_read(struct subsystem *entry, char *buf)
+pdcs_autosearch_read(struct kset *kset, char *buf)
 {
-	return pdcs_auto_read(entry, buf, PF_AUTOSEARCH);
+	return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_timer_read - Stable Storage timer count output (in seconds).
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * The value of the timer field correponds to a number of seconds in powers of 2.
  */
 static ssize_t
-pdcs_timer_read(struct subsystem *entry, char *buf)
+pdcs_timer_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 	struct pdcspath_entry *pathentry;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	/* Current flags are stored in primary boot path entry */
@@ -615,15 +615,15 @@ pdcs_timer_read(struct subsystem *entry,
 
 /**
  * pdcs_osid_read - Stable Storage OS ID register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
 static ssize_t
-pdcs_osid_read(struct subsystem *entry, char *buf)
+pdcs_osid_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	out += sprintf(out, "%s dependent data (0x%.4x)\n",
@@ -634,18 +634,18 @@ pdcs_osid_read(struct subsystem *entry, 
 
 /**
  * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold 16 bytes of OS-Dependent data.
  */
 static ssize_t
-pdcs_osdep1_read(struct subsystem *entry, char *buf)
+pdcs_osdep1_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 	u32 result[4];
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
@@ -661,18 +661,18 @@ pdcs_osdep1_read(struct subsystem *entry
 
 /**
  * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * I have NFC how to interpret the content of that register ;-).
  */
 static ssize_t
-pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+pdcs_diagnostic_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 	u32 result;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	/* get diagnostic */
@@ -686,18 +686,18 @@ pdcs_diagnostic_read(struct subsystem *e
 
 /**
  * pdcs_fastsize_read - Stable Storage FastSize register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This register holds the amount of system RAM to be tested during boot sequence.
  */
 static ssize_t
-pdcs_fastsize_read(struct subsystem *entry, char *buf)
+pdcs_fastsize_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 	u32 result;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	/* get fast-size */
@@ -715,13 +715,13 @@ pdcs_fastsize_read(struct subsystem *ent
 
 /**
  * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
  */
 static ssize_t
-pdcs_osdep2_read(struct subsystem *entry, char *buf)
+pdcs_osdep2_read(struct kset *kset, char *buf)
 {
 	char *out = buf;
 	unsigned long size;
@@ -733,7 +733,7 @@ pdcs_osdep2_read(struct subsystem *entry
 
 	size = pdcs_size - 224;
 
-	if (!entry || !buf)
+	if (!kset || !buf)
 		return -EINVAL;
 
 	for (i=0; i<size; i+=4) {
@@ -748,7 +748,7 @@ pdcs_osdep2_read(struct subsystem *entry
 
 /**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
@@ -758,7 +758,7 @@ pdcs_osdep2_read(struct subsystem *entry
  *	\"n\" (n == 0 or 1) to toggle AutoBoot Off or On
  */
 static ssize_t
-pdcs_auto_write(struct subsystem *entry, const char *buf, size_t count, int knob)
+pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
 {
 	struct pdcspath_entry *pathentry;
 	unsigned char flags;
@@ -768,7 +768,7 @@ pdcs_auto_write(struct subsystem *entry,
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!entry || !buf || !count)
+	if (!kset || !buf || !count)
 		return -EINVAL;
 
 	/* We'll use a local copy of buf */
@@ -823,7 +823,7 @@ parse_error:
 
 /**
  * pdcs_autoboot_write - This function handles autoboot flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -832,14 +832,14 @@ parse_error:
  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
 static inline ssize_t
-pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
 {
-	return pdcs_auto_write(entry, buf, count, PF_AUTOBOOT);
+	return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_write - This function handles autosearch flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -848,14 +848,14 @@ pdcs_autoboot_write(struct subsystem *en
  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
 static inline ssize_t
-pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
 {
-	return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
+	return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -864,14 +864,14 @@ pdcs_autosearch_write(struct subsystem *
  * its input buffer.
  */
 static ssize_t
-pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
 {
 	u8 in[16];
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!entry || !buf || !count)
+	if (!kset || !buf || !count)
 		return -EINVAL;
 
 	if (unlikely(pdcs_osid != OS_ID_LINUX))
@@ -892,7 +892,7 @@ pdcs_osdep1_write(struct subsystem *entr
 
 /**
  * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -901,7 +901,7 @@ pdcs_osdep1_write(struct subsystem *entr
  * constructing its input buffer.
  */
 static ssize_t
-pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
 {
 	unsigned long size;
 	unsigned short i;
@@ -910,7 +910,7 @@ pdcs_osdep2_write(struct subsystem *entr
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!entry || !buf || !count)
+	if (!kset || !buf || !count)
 		return -EINVAL;
 
 	if (unlikely(pdcs_size <= 224))
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 316c06f..8b7d84e 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -201,7 +201,7 @@ static int parport_config(struct pcmcia_
 
     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
-			      NULL);
+			      &link->dev);
     if (p == NULL) {
 	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
 	       "0x%3x, irq %u failed\n", link->io.BasePort1,
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index e5b0a54..77726fc 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -356,6 +356,7 @@ static int __init parport_mfc3_init(void
 				if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops))
 					goto out_irq;
 		}
+		p->dev = &z->dev;
 
 		this_port[pias++] = p;
 		printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 3de2623..02c0d52 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -53,6 +53,7 @@ #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/pnp.h>
+#include <linux/platform_device.h>
 #include <linux/sysctl.h>
 
 #include <asm/io.h>
@@ -620,6 +621,7 @@ static size_t parport_pc_fifo_write_bloc
 	unsigned long dmaflag;
 	size_t left = length;
 	const struct parport_pc_private *priv = port->physport->private_data;
+	struct device *dev = port->physport->dev;
 	dma_addr_t dma_addr, dma_handle;
 	size_t maxlen = 0x10000; /* max 64k per DMA transfer */
 	unsigned long start = (unsigned long) buf;
@@ -631,8 +633,8 @@ dump_parport_state ("enter fifo_write_bl
 		if ((start ^ end) & ~0xffffUL)
 			maxlen = 0x10000 - (start & 0xffff);
 
-		dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
-						       PCI_DMA_TODEVICE);
+		dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length,
+						       DMA_TO_DEVICE);
         } else {
 		/* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
 		maxlen   = PAGE_SIZE;          /* sizeof(priv->dma_buf) */
@@ -728,9 +730,9 @@ dump_parport_state ("enter fifo_write_bl
 
 	/* Turn off DMA mode */
 	frob_econtrol (port, 1<<3, 0);
-	
+
 	if (dma_handle)
-		pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);
+		dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE);
 
 dump_parport_state ("leave fifo_write_block_dma", port);
 	return length - left;
@@ -2146,7 +2148,7 @@ static DEFINE_SPINLOCK(ports_lock);
 struct parport *parport_pc_probe_port (unsigned long int base,
 				       unsigned long int base_hi,
 				       int irq, int dma,
-				       struct pci_dev *dev)
+				       struct device *dev)
 {
 	struct parport_pc_private *priv;
 	struct parport_operations *ops;
@@ -2155,6 +2157,17 @@ struct parport *parport_pc_probe_port (u
 	struct resource *base_res;
 	struct resource	*ECR_res = NULL;
 	struct resource	*EPP_res = NULL;
+	struct platform_device *pdev = NULL;
+
+	if (!dev) {
+		/* We need a physical device to attach to, but none was
+		 * provided. Create our own. */
+		pdev = platform_device_register_simple("parport_pc",
+						       base, NULL, 0);
+		if (IS_ERR(pdev))
+			return NULL;
+		dev = &pdev->dev;
+	}
 
 	ops = kmalloc(sizeof (struct parport_operations), GFP_KERNEL);
 	if (!ops)
@@ -2180,9 +2193,10 @@ struct parport *parport_pc_probe_port (u
 	priv->fifo_depth = 0;
 	priv->dma_buf = NULL;
 	priv->dma_handle = 0;
-	priv->dev = dev;
 	INIT_LIST_HEAD(&priv->list);
 	priv->port = p;
+
+	p->dev = dev;
 	p->base_hi = base_hi;
 	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
 	p->private_data = priv;
@@ -2305,9 +2319,10 @@ #ifdef HAS_DMA
 				p->dma = PARPORT_DMA_NONE;
 			} else {
 				priv->dma_buf =
-				  pci_alloc_consistent(priv->dev,
+				  dma_alloc_coherent(dev,
 						       PAGE_SIZE,
-						       &priv->dma_handle);
+						       &priv->dma_handle,
+						       GFP_KERNEL);
 				if (! priv->dma_buf) {
 					printk (KERN_WARNING "%s: "
 						"cannot get buffer for DMA, "
@@ -2356,6 +2371,8 @@ out3:
 out2:
 	kfree (ops);
 out1:
+	if (pdev)
+		platform_device_unregister(pdev);
 	return NULL;
 }
 
@@ -2383,7 +2400,7 @@ #endif
 		release_region(p->base_hi, 3);
 #if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA)
 	if (priv->dma_buf)
-		pci_free_consistent(priv->dev, PAGE_SIZE,
+		dma_free_coherent(p->physport->dev, PAGE_SIZE,
 				    priv->dma_buf,
 				    priv->dma_handle);
 #endif
@@ -2489,7 +2506,7 @@ static int __devinit sio_ite_8872_probe 
 	 */
 	release_resource(base_res);
 	if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi,
-				   irq, PARPORT_DMA_NONE, NULL)) {
+				   irq, PARPORT_DMA_NONE, &pdev->dev)) {
 		printk (KERN_INFO
 			"parport_pc: ITE 8872 parallel port: io=0x%X",
 			ite8872_lpt);
@@ -2672,7 +2689,7 @@ static int __devinit sio_via_probe (stru
 	}
 
 	/* finally, do the probe with values obtained */
-	if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
+	if (parport_pc_probe_port (port1, port2, irq, dma, &pdev->dev)) {
 		printk (KERN_INFO
 			"parport_pc: VIA parallel port: io=0x%X", port1);
 		if (irq != PARPORT_IRQ_NONE)
@@ -2970,7 +2987,7 @@ static int parport_pc_pci_probe (struct 
 			parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi);
 		data->ports[count] =
 			parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
-					       PARPORT_DMA_NONE, dev);
+					       PARPORT_DMA_NONE, &dev->dev);
 		if (data->ports[count])
 			count++;
 	}
@@ -3077,8 +3094,8 @@ static int parport_pc_pnp_probe(struct p
 	} else
 		dma = PARPORT_DMA_NONE;
 
-	printk(KERN_INFO "parport: PnPBIOS parport detected.\n");
-	if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, NULL)))
+	dev_info(&dev->dev, "reported by %s\n", dev->protocol->name);
+	if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, &dev->dev)))
 		return -ENODEV;
 
 	pnp_set_drvdata(dev,pdata);
@@ -3103,6 +3120,21 @@ static struct pnp_driver parport_pc_pnp_
 };
 
 
+static int __devinit parport_pc_platform_probe(struct platform_device *pdev)
+{
+	/* Always succeed, the actual probing is done in
+	 * parport_pc_probe_port(). */
+	return 0;
+}
+
+static struct platform_driver parport_pc_platform_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "parport_pc",
+	},
+	.probe		= parport_pc_platform_probe,
+};
+
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
 static int __devinit __attribute__((unused))
 parport_pc_find_isa_ports (int autoirq, int autodma)
@@ -3378,9 +3410,15 @@ #endif
 
 static int __init parport_pc_init(void)
 {
+	int err;
+
 	if (parse_parport_params())
 		return -EINVAL;
 
+	err = platform_driver_register(&parport_pc_platform_driver);
+	if (err)
+		return err;
+
 	if (io[0]) {
 		int i;
 		/* Only probe the ports we were given. */
@@ -3405,6 +3443,7 @@ static void __exit parport_pc_exit(void)
 		pci_unregister_driver (&parport_pc_pci_driver);
 	if (pnp_registered_parport)
 		pnp_unregister_driver (&parport_pc_pnp_driver);
+	platform_driver_unregister(&parport_pc_platform_driver);
 
 	spin_lock(&ports_lock);
 	while (!list_empty(&ports_list)) {
@@ -3413,6 +3452,9 @@ static void __exit parport_pc_exit(void)
 		priv = list_entry(ports_list.next,
 				  struct parport_pc_private, list);
 		port = priv->port;
+		if (port->dev && port->dev->bus == &platform_bus_type)
+			platform_device_unregister(
+				to_platform_device(port->dev));
 		spin_unlock(&ports_lock);
 		parport_pc_unregister_port(port);
 		spin_lock(&ports_lock);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 78c0a26..90ea3b8 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -305,7 +305,7 @@ static int __devinit parport_register (s
 		dev_dbg(&dev->dev, "PCI parallel port detected: I/O at "
 			"%#lx(%#lx)\n", io_lo, io_hi);
 		port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
-					      PARPORT_DMA_NONE, dev);
+					      PARPORT_DMA_NONE, &dev->dev);
 		if (port) {
 			priv->port[priv->num_par++] = port;
 			success = 1;
@@ -392,6 +392,7 @@ static int parport_serial_pci_suspend(st
 static int parport_serial_pci_resume(struct pci_dev *dev)
 {
 	struct parport_serial_private *priv = pci_get_drvdata(dev);
+	int err;
 
 	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
@@ -399,7 +400,12 @@ static int parport_serial_pci_resume(str
 	/*
 	 * The device may have been disabled.  Re-enable it.
 	 */
-	pci_enable_device(dev);
+	err = pci_enable_device(dev);
+	if (err) {
+		printk(KERN_ERR "parport_serial: %s: error enabling "
+			"device for resume (%d)\n", pci_name(dev), err);
+		return err;
+	}
 
 	if (priv->serial)
 		pciserial_resume_ports(priv->serial);
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 400bb90..d27019c 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -322,6 +322,7 @@ static int __devinit init_one_port(struc
 		goto out_free_ops;
 
 	p->size = size;
+	p->dev = &sdev->ofdev.dev;
 
 	if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
 			       IRQF_SHARED, p->name, p)) != 0) {
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index fd9129e..cd66442 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -365,6 +365,11 @@ #ifdef CONFIG_PARPORT_1284
 	parport_daisy_init(port);
 #endif
 
+	if (!port->dev)
+		printk(KERN_WARNING "%s: fix this legacy "
+				"no-device port driver!\n",
+				port->name);
+
 	parport_proc_register(port);
 	mutex_lock(&registration_lock);
 	spin_lock_irq(&parportlist_lock);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 5ea5bc7..7a1d6d5 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -1,10 +1,14 @@
 #
 # PCI configuration
 #
+config ARCH_SUPPORTS_MSI
+	bool
+	default n
+
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64
+	depends on ARCH_SUPPORTS_MSI
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
@@ -17,31 +21,6 @@ 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 cannot 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 persistent 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
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index aadaa3c..9e5ea07 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -77,7 +77,7 @@ 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
  */
-int __devinit pci_bus_add_device(struct pci_dev *dev)
+int pci_bus_add_device(struct pci_dev *dev)
 {
 	int retval;
 	retval = device_add(&dev->dev);
@@ -105,7 +105,7 @@ int __devinit pci_bus_add_device(struct 
  *
  * Call hotplug for each new devices.
  */
-void __devinit pci_bus_add_devices(struct pci_bus *bus)
+void pci_bus_add_devices(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 	int retval;
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index be92695..63d6275 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -2,9 +2,7 @@ #
 # PCI Hotplug support
 #
 
-menu "PCI Hotplug Support"
-
-config HOTPLUG_PCI
+menuconfig HOTPLUG_PCI
 	tristate "Support for PCI Hotplug (EXPERIMENTAL)"
 	depends on PCI && EXPERIMENTAL && HOTPLUG
 	---help---
@@ -17,9 +15,10 @@ config HOTPLUG_PCI
 
 	  When in doubt, say N.
 
+if HOTPLUG_PCI
+
 config HOTPLUG_PCI_FAKE
 	tristate "Fake PCI Hotplug driver"
-	depends on HOTPLUG_PCI
 	help
 	  Say Y here if you want to use the fake PCI hotplug driver. It can
 	  be used to simulate PCI hotplug events if even if your system is
@@ -42,7 +41,7 @@ config HOTPLUG_PCI_FAKE
 
 config HOTPLUG_PCI_COMPAQ
 	tristate "Compaq PCI Hotplug driver"
-	depends on HOTPLUG_PCI && X86 && PCI_BIOS
+	depends on X86 && PCI_BIOS
 	help
 	  Say Y here if you have a motherboard with a Compaq PCI Hotplug
 	  controller.
@@ -64,7 +63,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM
 
 config HOTPLUG_PCI_IBM
 	tristate "IBM PCI Hotplug driver"
-	depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS
+	depends on X86_IO_APIC && X86 && PCI_BIOS
 	help
 	  Say Y here if you have a motherboard with a IBM PCI Hotplug
 	  controller.
@@ -76,7 +75,6 @@ config HOTPLUG_PCI_IBM
 
 config HOTPLUG_PCI_ACPI
 	tristate "ACPI PCI Hotplug driver"
-	depends on HOTPLUG_PCI
 	depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
 	help
 	  Say Y here if you have a system that supports PCI Hotplug using
@@ -101,7 +99,6 @@ config HOTPLUG_PCI_ACPI_IBM
 
 config HOTPLUG_PCI_CPCI
 	bool "CompactPCI Hotplug driver"
-	depends on HOTPLUG_PCI
 	help
 	  Say Y here if you have a CompactPCI system card with CompactPCI
 	  hotswap support per the PICMG 2.1 specification.
@@ -110,7 +107,7 @@ config HOTPLUG_PCI_CPCI
 
 config HOTPLUG_PCI_CPCI_ZT5550
 	tristate "Ziatech ZT5550 CompactPCI Hotplug driver"
-	depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+	depends on HOTPLUG_PCI_CPCI && X86
 	help
 	  Say Y here if you have an Performance Technologies (formerly Intel,
           formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
@@ -122,7 +119,7 @@ config HOTPLUG_PCI_CPCI_ZT5550
 
 config HOTPLUG_PCI_CPCI_GENERIC
 	tristate "Generic port I/O CompactPCI Hotplug driver"
-	depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+	depends on HOTPLUG_PCI_CPCI && X86
 	help
 	  Say Y here if you have a CompactPCI system card that exposes the #ENUM
 	  hotswap signal as a bit in a system register that can be read through
@@ -135,7 +132,6 @@ config HOTPLUG_PCI_CPCI_GENERIC
 
 config HOTPLUG_PCI_SHPC
 	tristate "SHPC PCI Hotplug driver"
-	depends on HOTPLUG_PCI
 	help
 	  Say Y here if you have a motherboard with a SHPC PCI Hotplug
 	  controller.
@@ -147,7 +143,7 @@ config HOTPLUG_PCI_SHPC
 
 config HOTPLUG_PCI_RPA
 	tristate "RPA PCI Hotplug driver"
-	depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
+	depends on PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
 	help
 	  Say Y here if you have a RPA system that supports PCI Hotplug.
 
@@ -170,12 +166,11 @@ config HOTPLUG_PCI_RPA_DLPAR
 
 config HOTPLUG_PCI_SGI
 	tristate "SGI PCI Hotplug Support"
-	depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC)
+	depends on IA64_SGI_SN2 || IA64_GENERIC
 	help
 	  Say Y here if you want to use the SGI Altix Hotplug
 	  Driver for PCI devices.
 
 	  When in doubt, say N.
 
-endmenu
-
+endif # HOTPLUG_PCI
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 40c79b0..fa5c019 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -40,7 +40,6 @@ #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.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 fca978f..9ef4e98 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -46,7 +46,6 @@ #include <linux/module.h>
 #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"
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 7f03881..e7322c2 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -424,7 +424,7 @@ static int __init ibm_acpiphp_init(void)
 	int retval = 0;
 	acpi_status status;
 	struct acpi_device *device;
-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
 
 	dbg("%s\n", __FUNCTION__);
 
@@ -471,7 +471,7 @@ init_return:
 static void __exit ibm_acpiphp_exit(void)
 {
 	acpi_status status;
-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
 
 	dbg("%s\n", __FUNCTION__);
 
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c
index 1c12e91..41f6a8d 100644
--- a/drivers/pci/hotplug/cpcihp_zt5550.c
+++ b/drivers/pci/hotplug/cpcihp_zt5550.c
@@ -296,13 +296,17 @@ static struct pci_driver zt5550_hc_drive
 static int __init zt5550_init(void)
 {
 	struct resource* r;
+	int rc;
 
 	info(DRIVER_DESC " version: " DRIVER_VERSION);
 	r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
 	if(!r)
 		return -EBUSY;
 
-	return pci_register_driver(&zt5550_hc_driver);
+	rc = pci_register_driver(&zt5550_hc_driver);
+	if(rc < 0)
+		release_region(ENUM_PORT, 1);
+	return rc;
 }
 
 static void __exit
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index e27907c..027f686 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -238,7 +238,7 @@ static void pci_rescan_bus(const struct 
 {
 	unsigned int devfn;
 	struct pci_dev *dev;
-	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	dev = alloc_pci_dev();
 	if (!dev)
 		return;
 
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 5939294..0316eea 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -34,7 +34,6 @@ #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
-#include <linux/smp_lock.h>
 #include "../pci.h"
 #include "../../../arch/i386/pci/pci.h"	/* for struct irq_routing_table */
 #include "ibmphp.h"
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index f55ac38..46abaa8 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -32,7 +32,6 @@ #include <linux/time.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index f5d632e..bd433ef 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -34,7 +34,6 @@ #include <linux/kobject.h>
 #include <linux/sysfs.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
@@ -62,7 +61,7 @@ #define DRIVER_DESC	"PCI Hot Plug PCI Co
 
 static LIST_HEAD(pci_hotplug_slot_list);
 
-struct subsystem pci_hotplug_slots_subsys;
+struct kset pci_hotplug_slots_subsys;
 
 static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
 		struct attribute *attr, char *buf)
@@ -764,7 +763,7 @@ static int __init pci_hotplug_init (void
 {
 	int result;
 
-	kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
+	kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
 	result = subsystem_register(&pci_hotplug_slots_subsys);
 	if (result) {
 		err("Register subsys with error %d\n", result);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index d19fcae..ccc5762 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode;
 extern int pciehp_poll_time;
 extern int pciehp_debug;
 extern int pciehp_force;
+extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)						\
 	do {								\
@@ -70,14 +71,16 @@ struct slot {
 	struct list_head	slot_list;
 	char name[SLOT_NAME_SIZE];
 	unsigned long last_emi_toggle;
+	struct delayed_work work;	/* work for button event */
+	struct mutex lock;
 };
 
 struct event_info {
 	u32 event_type;
-	u8 hp_slot;
+	struct slot *p_slot;
+	struct work_struct work;
 };
 
-#define MAX_EVENTS		10
 struct controller {
 	struct controller *next;
 	struct mutex crit_sect;		/* critical section mutex */
@@ -86,11 +89,9 @@ struct controller {
 	int slot_num_inc;		/* 1 or -1 */
 	struct pci_dev *pci_dev;
 	struct list_head slot_list;
-	struct event_info event_queue[MAX_EVENTS];
 	struct slot *slot;
 	struct hpc_ops *hpc_ops;
 	wait_queue_head_t queue;	/* sleep & wake process */
-	u8 next_event;
 	u8 bus;
 	u8 device;
 	u8 function;
@@ -149,21 +150,17 @@ #define PWR_LED(cap)		(cap & PWR_LED_PRS
 #define HP_SUPR_RM(cap)		(cap & HP_SUPR_RM_SUP)
 #define EMI(cap)		(cap & EMI_PRSN)
 
-extern int pciehp_event_start_thread(void);
-extern void pciehp_event_stop_thread(void);
-extern int pciehp_enable_slot(struct slot *slot);
-extern int pciehp_disable_slot(struct slot *slot);
+extern int pciehp_sysfs_enable_slot(struct slot *slot);
+extern int pciehp_sysfs_disable_slot(struct slot *slot);
 extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
 extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
 extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
 extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
 extern int pciehp_configure_device(struct slot *p_slot);
 extern int pciehp_unconfigure_device(struct slot *p_slot);
+extern void pciehp_queue_pushbutton_work(struct work_struct *work);
 int pcie_init(struct controller *ctrl, struct pcie_device *dev);
 
-/* Global variables */
-extern struct controller *pciehp_ctrl_list;
-
 static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
 {
 	struct slot *slot;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index a92eda6..e5d3f0b 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -41,7 +41,7 @@ int pciehp_debug;
 int pciehp_poll_mode;
 int pciehp_poll_time;
 int pciehp_force;
-struct controller *pciehp_ctrl_list;
+struct workqueue_struct *pciehp_wq;
 
 #define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -62,7 +62,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pc
 
 #define PCIE_MODULE_NAME "pciehp"
 
-static int pcie_start_thread (void);
 static int set_attention_status (struct hotplug_slot *slot, u8 value);
 static int enable_slot		(struct hotplug_slot *slot);
 static int disable_slot		(struct hotplug_slot *slot);
@@ -229,6 +228,8 @@ static int init_slots(struct controller 
 		slot->device = ctrl->slot_device_offset + i;
 		slot->hpc_ops = ctrl->hpc_ops;
 		slot->number = ctrl->first_slot;
+		mutex_init(&slot->lock);
+		INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
 
 		/* register this slot with the hotplug pci core */
 		hotplug_slot->private = slot;
@@ -286,6 +287,9 @@ static void cleanup_slots(struct control
 		if (EMI(ctrl->ctrlcap))
 			sysfs_remove_file(&slot->hotplug_slot->kobj,
 				&hotplug_slot_attr_lock.attr);
+		cancel_delayed_work(&slot->work);
+		flush_scheduled_work();
+		flush_workqueue(pciehp_wq);
 		pci_hp_deregister(slot->hotplug_slot);
 	}
 }
@@ -314,7 +318,7 @@ static int enable_slot(struct hotplug_sl
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
-	return pciehp_enable_slot(slot);
+	return pciehp_sysfs_enable_slot(slot);
 }
 
 
@@ -324,7 +328,7 @@ static int disable_slot(struct hotplug_s
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
-	return pciehp_disable_slot(slot);
+	return pciehp_sysfs_disable_slot(slot);
 }
 
 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
@@ -466,17 +470,6 @@ static int pciehp_probe(struct pcie_devi
 
 	t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
 
-	/*	Finish setting up the hot plug ctrl device */
-	ctrl->next_event = 0;
-
-	if (!pciehp_ctrl_list) {
-		pciehp_ctrl_list = ctrl;
-		ctrl->next = NULL;
-	} else {
-		ctrl->next = pciehp_ctrl_list;
-		pciehp_ctrl_list = ctrl;
-	}
-
 	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
 	if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
 		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
@@ -496,48 +489,14 @@ err_out_none:
 	return -ENODEV;
 }
 
-
-static int pcie_start_thread(void)
+static void pciehp_remove (struct pcie_device *dev)
 {
-	int retval = 0;
-	
-	dbg("Initialize + Start the notification/polling mechanism \n");
-
-	retval = pciehp_event_start_thread();
-	if (retval) {
-		dbg("pciehp_event_start_thread() failed\n");
-		return retval;
-	}
-
-	return retval;
-}
-
-static void __exit unload_pciehpd(void)
-{
-	struct controller *ctrl;
-	struct controller *tctrl;
-
-	ctrl = pciehp_ctrl_list;
-
-	while (ctrl) {
-		cleanup_slots(ctrl);
+	struct pci_dev *pdev = dev->port;
+	struct controller *ctrl = pci_get_drvdata(pdev);
 
-		ctrl->hpc_ops->release_ctlr(ctrl);
-
-		tctrl = ctrl;
-		ctrl = ctrl->next;
-
-		kfree(tctrl);
-	}
-
-	/* Stop the notification mechanism */
-	pciehp_event_stop_thread();
-
-}
-
-static void pciehp_remove (struct pcie_device *device)
-{
-	/* XXX - Needs to be adapted to device driver model */
+	cleanup_slots(ctrl);
+	ctrl->hpc_ops->release_ctlr(ctrl);
+	kfree(ctrl);
 }
 
 #ifdef CONFIG_PM
@@ -585,31 +544,18 @@ #ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVEN
 	pciehp_poll_mode = 1;
 #endif
 
-	retval = pcie_start_thread();
-	if (retval)
-		goto error_hpc_init;
-
 	retval = pcie_port_service_register(&hpdriver_portdrv);
  	dbg("pcie_port_service_register = %d\n", retval);
   	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
  	if (retval)
 		dbg("%s: Failure to register service\n", __FUNCTION__);
-
-error_hpc_init:
-	if (retval) {
-		pciehp_event_stop_thread();
-	};
-
 	return retval;
 }
 
 static void __exit pcied_cleanup(void)
 {
 	dbg("unload_pciehpd()\n");
-	unload_pciehpd();
-
 	pcie_port_service_unregister(&hpdriver_portdrv);
-
 	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
 }
 
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 4283ef5..7f22caa 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -32,92 +32,61 @@ #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
+#include <linux/workqueue.h>
 #include "../pci.h"
 #include "pciehp.h"
 
-static void interrupt_event_handler(struct controller *ctrl);
+static void interrupt_event_handler(struct work_struct *work);
+static int pciehp_enable_slot(struct slot *p_slot);
+static int pciehp_disable_slot(struct slot *p_slot);
 
-static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
-static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
-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)
+static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
 {
-	return p_slot->hotplug_slot->name;
+	struct event_info *info;
+
+	info = kmalloc(sizeof(*info), GFP_ATOMIC);
+	if (!info)
+		return -ENOMEM;
+
+	info->event_type = event_type;
+	info->p_slot = p_slot;
+	INIT_WORK(&info->work, interrupt_event_handler);
+
+	schedule_work(&info->work);
+
+	return 0;
 }
 
 u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
 {
 	struct slot *p_slot;
-	u8 rc = 0;
-	u8 getstatus;
-	struct event_info *taskInfo;
+	u32 event_type;
 
 	/* Attention Button Change */
 	dbg("pciehp:  Attention button interrupt received.\n");
-	
-	/* This is the structure that tells the worker thread what to do */
-	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
-	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-	
-	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
-	taskInfo->hp_slot = hp_slot;
 
-	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	/*
 	 *  Button pressed - See if need to TAKE ACTION!!!
 	 */
-	info("Button pressed on Slot(%s)\n", slot_name(p_slot));
-	taskInfo->event_type = INT_BUTTON_PRESS;
-
-	if ((p_slot->state == BLINKINGON_STATE)
-	    || (p_slot->state == BLINKINGOFF_STATE)) {
-		/* Cancel if we are still blinking; this means that we press the
-		 * attention again before the 5 sec. limit expires to cancel hot-add
-		 * or hot-remove
-		 */
-		taskInfo->event_type = INT_BUTTON_CANCEL;
-		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 
-		 * means that the previous attention button action to hot-add or
-		 * hot-remove is undergoing
-		 */
-		taskInfo->event_type = INT_BUTTON_IGNORE;
-		info("Button ignore on Slot(%s)\n", slot_name(p_slot));
-	}
+	info("Button pressed on Slot(%s)\n", p_slot->name);
+	event_type = INT_BUTTON_PRESS;
 
-	if (rc)
-		up(&event_semaphore);	/* signal event thread that new event is posted */
+	queue_interrupt_event(p_slot, event_type);
 
 	return 0;
-
 }
 
 u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
 {
 	struct slot *p_slot;
-	u8 rc = 0;
 	u8 getstatus;
-	struct event_info *taskInfo;
+	u32 event_type;
 
 	/* Switch Change */
 	dbg("pciehp:  Switch interrupt received.\n");
 
-	/* This is the structure that tells the worker thread
-	 * what to do
-	 */
-	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
-	taskInfo->hp_slot = hp_slot;
-
-	rc++;
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 
@@ -125,39 +94,30 @@ u8 pciehp_handle_switch_change(u8 hp_slo
 		/*
 		 * Switch opened
 		 */
-		info("Latch open on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_SWITCH_OPEN;
+		info("Latch open on Slot(%s)\n", p_slot->name);
+		event_type = INT_SWITCH_OPEN;
 	} else {
 		/*
 		 *  Switch closed
 		 */
-		info("Latch close on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_SWITCH_CLOSE;
+		info("Latch close on Slot(%s)\n", p_slot->name);
+		event_type = INT_SWITCH_CLOSE;
 	}
 
-	if (rc)
-		up(&event_semaphore);	/* signal event thread that new event is posted */
+	queue_interrupt_event(p_slot, event_type);
 
-	return rc;
+	return 1;
 }
 
 u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
 {
 	struct slot *p_slot;
-	u8 presence_save, rc = 0;
-	struct event_info *taskInfo;
+	u32 event_type;
+	u8 presence_save;
 
 	/* Presence Change */
 	dbg("pciehp:  Presence/Notify input change.\n");
 
-	/* This is the structure that tells the worker thread
-	 * what to do
-	 */
-	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
-	taskInfo->hp_slot = hp_slot;
-
-	rc++;
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	/* Switch is open, assume a presence change
@@ -168,59 +128,49 @@ u8 pciehp_handle_presence_change(u8 hp_s
 		/*
 		 * Card Present
 		 */
-		info("Card present on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_PRESENCE_ON;
+		info("Card present on Slot(%s)\n", p_slot->name);
+		event_type = INT_PRESENCE_ON;
 	} else {
 		/*
 		 * Not Present
 		 */
-		info("Card not present on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_PRESENCE_OFF;
+		info("Card not present on Slot(%s)\n", p_slot->name);
+		event_type = INT_PRESENCE_OFF;
 	}
 
-	if (rc)
-		up(&event_semaphore);	/* signal event thread that new event is posted */
+	queue_interrupt_event(p_slot, event_type);
 
-	return rc;
+	return 1;
 }
 
 u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
 {
 	struct slot *p_slot;
-	u8 rc = 0;
-	struct event_info *taskInfo;
+	u32 event_type;
 
 	/* power fault */
 	dbg("pciehp:  Power fault interrupt received.\n");
 
-	/* this is the structure that tells the worker thread
-	 * what to do
-	 */
-	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
-	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
-	taskInfo->hp_slot = hp_slot;
-
-	rc++;
 	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
 		/*
 		 * power fault Cleared
 		 */
-		info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+		info("Power fault cleared on Slot(%s)\n", p_slot->name);
+		event_type = INT_POWER_FAULT_CLEAR;
 	} else {
 		/*
 		 *   power fault
 		 */
-		info("Power fault on Slot(%s)\n", slot_name(p_slot));
-		taskInfo->event_type = INT_POWER_FAULT;
+		info("Power fault on Slot(%s)\n", p_slot->name);
+		event_type = INT_POWER_FAULT;
 		info("power fault bit %x set\n", hp_slot);
 	}
-	if (rc)
-		up(&event_semaphore);	/* signal event thread that new event is posted */
 
-	return rc;
+	queue_interrupt_event(p_slot, event_type);
+
+	return 1;
 }
 
 /* The following routines constitute the bulk of the 
@@ -357,13 +307,10 @@ static int remove_board(struct slot *p_s
 	return 0;
 }
 
-
-static void pushbutton_helper_thread(unsigned long data)
-{
-	pushbutton_pending = data;
-
-	up(&event_semaphore);
-}
+struct power_work_info {
+	struct slot *p_slot;
+	struct work_struct work;
+};
 
 /**
  * pciehp_pushbutton_thread
@@ -372,276 +319,214 @@ static void pushbutton_helper_thread(uns
  * Handles all pending events and exits.
  *
  */
-static void pciehp_pushbutton_thread(unsigned long slot)
+static void pciehp_power_thread(struct work_struct *work)
 {
-	struct slot *p_slot = (struct slot *) slot;
-	u8 getstatus;
-	
-	pushbutton_pending = 0;
-
-	if (!p_slot) {
-		dbg("%s: Error! slot NULL\n", __FUNCTION__);
-		return;
-	}
-
-	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
-	if (getstatus) {
-		p_slot->state = POWEROFF_STATE;
-		dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
-				p_slot->bus, p_slot->device);
-
+	struct power_work_info *info =
+		container_of(work, struct power_work_info, work);
+	struct slot *p_slot = info->p_slot;
+
+	mutex_lock(&p_slot->lock);
+	switch (p_slot->state) {
+	case POWEROFF_STATE:
+		mutex_unlock(&p_slot->lock);
+		dbg("%s: disabling bus:device(%x:%x)\n",
+		    __FUNCTION__, p_slot->bus, p_slot->device);
 		pciehp_disable_slot(p_slot);
+		mutex_lock(&p_slot->lock);
 		p_slot->state = STATIC_STATE;
-	} else {
-		p_slot->state = POWERON_STATE;
-		dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
-				p_slot->bus, p_slot->device);
-
+		break;
+	case POWERON_STATE:
+		mutex_unlock(&p_slot->lock);
 		if (pciehp_enable_slot(p_slot) &&
 		    PWR_LED(p_slot->ctrl->ctrlcap))
 			p_slot->hpc_ops->green_led_off(p_slot);
-
+		mutex_lock(&p_slot->lock);
 		p_slot->state = STATIC_STATE;
+		break;
+	default:
+		break;
 	}
+	mutex_unlock(&p_slot->lock);
 
-	return;
+	kfree(info);
 }
 
-/**
- * pciehp_surprise_rm_thread
- *
- * Scheduled procedure to handle blocking stuff for the surprise removal
- * Handles all pending events and exits.
- *
- */
-static void pciehp_surprise_rm_thread(unsigned long slot)
+void pciehp_queue_pushbutton_work(struct work_struct *work)
 {
-	struct slot *p_slot = (struct slot *) slot;
-	u8 getstatus;
-	
-	surprise_rm_pending = 0;
+	struct slot *p_slot = container_of(work, struct slot, work.work);
+	struct power_work_info *info;
 
-	if (!p_slot) {
-		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		err("%s: Cannot allocate memory\n", __FUNCTION__);
 		return;
 	}
+	info->p_slot = p_slot;
+	INIT_WORK(&info->work, pciehp_power_thread);
 
-	p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
-	if (!getstatus) {
+	mutex_lock(&p_slot->lock);
+	switch (p_slot->state) {
+	case BLINKINGOFF_STATE:
 		p_slot->state = POWEROFF_STATE;
-		dbg("%s: removing bus:device(%x:%x)\n",
-				__FUNCTION__, p_slot->bus, p_slot->device);
-
-		pciehp_disable_slot(p_slot);
-		p_slot->state = STATIC_STATE;
-	} else {
+		break;
+	case BLINKINGON_STATE:
 		p_slot->state = POWERON_STATE;
-		dbg("%s: adding bus:device(%x:%x)\n",
-				__FUNCTION__, p_slot->bus, p_slot->device);
-
-		if (pciehp_enable_slot(p_slot) &&
-		    PWR_LED(p_slot->ctrl->ctrlcap))
-			p_slot->hpc_ops->green_led_off(p_slot);
-
-		p_slot->state = STATIC_STATE;
+		break;
+	default:
+		goto out;
 	}
-
-	return;
+	queue_work(pciehp_wq, &info->work);
+ out:
+	mutex_unlock(&p_slot->lock);
 }
 
-
-
-/* this is the main worker thread */
-static int event_thread(void* data)
-{
-	struct controller *ctrl;
-	lock_kernel();
-	daemonize("pciehpd_event");
-
-	unlock_kernel();
-
-	while (1) {
-		dbg("!!!!event_thread sleeping\n");
-		down_interruptible (&event_semaphore);
-		dbg("event_thread woken finished = %d\n", event_finished);
-		if (event_finished || signal_pending(current))
-			break;
-		/* Do stuff here */
-		if (pushbutton_pending)
-			pciehp_pushbutton_thread(pushbutton_pending);
-		else if (surprise_rm_pending)
-			pciehp_surprise_rm_thread(surprise_rm_pending);
-		else
-			for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
-				interrupt_event_handler(ctrl);
-	}
-	dbg("event_thread signals exit\n");
-	up(&event_exit);
-	return 0;
-}
-
-int pciehp_event_start_thread(void)
-{
-	int pid;
-
-	/* initialize our semaphores */
-	init_MUTEX_LOCKED(&event_exit);
-	event_finished=0;
-
-	init_MUTEX_LOCKED(&event_semaphore);
-	pid = kernel_thread(event_thread, NULL, 0);
-
-	if (pid < 0) {
-		err ("Can't start up our event thread\n");
-		return -1;
-	}
-	return 0;
-}
-
-
-void pciehp_event_stop_thread(void)
-{
-	event_finished = 1;
-	up(&event_semaphore);
-	down(&event_exit);
-}
-
-
 static int update_slot_info(struct slot *slot)
 {
 	struct hotplug_slot_info *info;
-	/* char buffer[SLOT_NAME_SIZE]; */
 	int result;
 
-	info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
 
-	/* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
-
 	slot->hpc_ops->get_power_status(slot, &(info->power_status));
 	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
 	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
 	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
 
-	/* result = pci_hp_change_slot_info(buffer, info); */
 	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
 	kfree (info);
 	return result;
 }
 
-static void interrupt_event_handler(struct controller *ctrl)
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_button_press_event(struct slot *p_slot)
 {
-	int loop = 0;
-	int change = 1;
-	u8 hp_slot;
+	struct controller *ctrl = p_slot->ctrl;
 	u8 getstatus;
-	struct slot *p_slot;
 
-	while (change) {
-		change = 0;
-
-		for (loop = 0; loop < MAX_EVENTS; loop++) {
-			if (ctrl->event_queue[loop].event_type != 0) {
-				hp_slot = ctrl->event_queue[loop].hp_slot;
-
-				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
-				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
-					dbg("button cancel\n");
-					del_timer(&p_slot->task_event);
-
-					switch (p_slot->state) {
-					case BLINKINGOFF_STATE:
-						if (PWR_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->green_led_on(p_slot);
-
-						if (ATTN_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->set_attention_status(p_slot, 0);
-						break;
-					case BLINKINGON_STATE:
-						if (PWR_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->green_led_off(p_slot);
-
-						if (ATTN_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->set_attention_status(p_slot, 0);
-						break;
-					default:
-						warn("Not a valid state\n");
-						return;
-					}
-					info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
-					p_slot->state = STATIC_STATE;
-				}
-				/* ***********Button Pressed (No action on 1st press...) */
-				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
-					
-					if (ATTN_BUTTN(ctrl->ctrlcap)) {
-						dbg("Button pressed\n");
-						p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
-						if (getstatus) {
-							/* slot is on */
-							dbg("slot is on\n");
-							p_slot->state = BLINKINGOFF_STATE;
-							info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
-						} else {
-							/* slot is off */
-							dbg("slot is off\n");
-							p_slot->state = BLINKINGON_STATE;
-							info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
-						}
-
-						/* blink green LED and turn off amber */
-						if (PWR_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->green_led_blink(p_slot);
-
-						if (ATTN_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
-						init_timer(&p_slot->task_event);
-						p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
-						p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
-						p_slot->task_event.data = (unsigned long) p_slot;
-
-						add_timer(&p_slot->task_event);
-					}
-				}
-				/***********POWER FAULT********************/
-				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
-					if (POWER_CTRL(ctrl->ctrlcap)) {
-						dbg("power fault\n");
-						if (ATTN_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->set_attention_status(p_slot, 1);
-
-						if (PWR_LED(ctrl->ctrlcap))
-							p_slot->hpc_ops->green_led_off(p_slot);
-					}
-				}
-				/***********SURPRISE REMOVAL********************/
-				else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 
-					(ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
-					if (HP_SUPR_RM(ctrl->ctrlcap)) {
-						dbg("Surprise Removal\n");
-						if (p_slot) {
-							surprise_rm_pending = (unsigned long) p_slot;
-							up(&event_semaphore);
-							update_slot_info(p_slot);
-						}
-					}
-				} else {
-					/* refresh notification */
-					if (p_slot)
-						update_slot_info(p_slot);
-				}
-
-				ctrl->event_queue[loop].event_type = 0;
-
-				change = 1;
-			}
-		}		/* End of FOR loop */
+	switch (p_slot->state) {
+	case STATIC_STATE:
+		p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+		if (getstatus) {
+			p_slot->state = BLINKINGOFF_STATE;
+			info("PCI slot #%s - powering off due to button "
+			     "press.\n", p_slot->name);
+		} else {
+			p_slot->state = BLINKINGON_STATE;
+			info("PCI slot #%s - powering on due to button "
+			     "press.\n", p_slot->name);
+		}
+		/* blink green LED and turn off amber */
+		if (PWR_LED(ctrl->ctrlcap))
+			p_slot->hpc_ops->green_led_blink(p_slot);
+		if (ATTN_LED(ctrl->ctrlcap))
+			p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+		schedule_delayed_work(&p_slot->work, 5*HZ);
+		break;
+	case BLINKINGOFF_STATE:
+	case BLINKINGON_STATE:
+		/*
+		 * Cancel if we are still blinking; this means that we
+		 * press the attention again before the 5 sec. limit
+		 * expires to cancel hot-add or hot-remove
+		 */
+		info("Button cancel on Slot(%s)\n", p_slot->name);
+		dbg("%s: button cancel\n", __FUNCTION__);
+		cancel_delayed_work(&p_slot->work);
+		if (p_slot->state == BLINKINGOFF_STATE) {
+			if (PWR_LED(ctrl->ctrlcap))
+				p_slot->hpc_ops->green_led_on(p_slot);
+		} else {
+			if (PWR_LED(ctrl->ctrlcap))
+				p_slot->hpc_ops->green_led_off(p_slot);
+		}
+		if (ATTN_LED(ctrl->ctrlcap))
+			p_slot->hpc_ops->set_attention_status(p_slot, 0);
+		info("PCI slot #%s - action canceled due to button press\n",
+		     p_slot->name);
+		p_slot->state = STATIC_STATE;
+		break;
+	case POWEROFF_STATE:
+	case POWERON_STATE:
+		/*
+		 * Ignore if the slot is on power-on or power-off state;
+		 * this means that the previous attention button action
+		 * to hot-add or hot-remove is undergoing
+		 */
+		info("Button ignore on Slot(%s)\n", p_slot->name);
+		update_slot_info(p_slot);
+		break;
+	default:
+		warn("Not a valid state\n");
+		break;
 	}
 }
 
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_surprise_event(struct slot *p_slot)
+{
+	u8 getstatus;
+	struct power_work_info *info;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		err("%s: Cannot allocate memory\n", __FUNCTION__);
+		return;
+	}
+	info->p_slot = p_slot;
+	INIT_WORK(&info->work, pciehp_power_thread);
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (!getstatus)
+		p_slot->state = POWEROFF_STATE;
+	else
+		p_slot->state = POWERON_STATE;
+
+	queue_work(pciehp_wq, &info->work);
+}
+
+static void interrupt_event_handler(struct work_struct *work)
+{
+	struct event_info *info = container_of(work, struct event_info, work);
+	struct slot *p_slot = info->p_slot;
+	struct controller *ctrl = p_slot->ctrl;
+
+	mutex_lock(&p_slot->lock);
+	switch (info->event_type) {
+	case INT_BUTTON_PRESS:
+		handle_button_press_event(p_slot);
+		break;
+	case INT_POWER_FAULT:
+		if (!POWER_CTRL(ctrl->ctrlcap))
+			break;
+		if (ATTN_LED(ctrl->ctrlcap))
+			p_slot->hpc_ops->set_attention_status(p_slot, 1);
+		if (PWR_LED(ctrl->ctrlcap))
+			p_slot->hpc_ops->green_led_off(p_slot);
+		break;
+	case INT_PRESENCE_ON:
+	case INT_PRESENCE_OFF:
+		if (!HP_SUPR_RM(ctrl->ctrlcap))
+			break;
+		dbg("Surprise Removal\n");
+		update_slot_info(p_slot);
+		handle_surprise_event(p_slot);
+		break;
+	default:
+		update_slot_info(p_slot);
+		break;
+	}
+	mutex_unlock(&p_slot->lock);
+
+	kfree(info);
+}
+
 int pciehp_enable_slot(struct slot *p_slot)
 {
 	u8 getstatus = 0;
@@ -653,7 +538,7 @@ 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(%s)\n", __FUNCTION__,
-		     slot_name(p_slot));
+		     p_slot->name);
 		mutex_unlock(&p_slot->ctrl->crit_sect);
 		return -ENODEV;
 	}
@@ -661,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_sl
 		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: latch open on slot(%s)\n", __FUNCTION__,
-			     slot_name(p_slot));
+			     p_slot->name);
 			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return -ENODEV;
 		}
@@ -671,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_sl
 		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: already enabled on slot(%s)\n", __FUNCTION__,
-			     slot_name(p_slot));
+			     p_slot->name);
 			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return -EINVAL;
 		}
@@ -706,7 +591,7 @@ int pciehp_disable_slot(struct slot *p_s
 		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: no adapter on slot(%s)\n", __FUNCTION__,
-			     slot_name(p_slot));
+			     p_slot->name);
 			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return -ENODEV;
 		}
@@ -716,7 +601,7 @@ int pciehp_disable_slot(struct slot *p_s
 		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (ret || getstatus) {
 			info("%s: latch open on slot(%s)\n", __FUNCTION__,
-			     slot_name(p_slot));
+			     p_slot->name);
 			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return -ENODEV;
 		}
@@ -726,7 +611,7 @@ int pciehp_disable_slot(struct slot *p_s
 		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: already disabled slot(%s)\n", __FUNCTION__,
-			     slot_name(p_slot));
+			     p_slot->name);
 			mutex_unlock(&p_slot->ctrl->crit_sect);
 			return -EINVAL;
 		}
@@ -739,3 +624,66 @@ int pciehp_disable_slot(struct slot *p_s
 	return ret;
 }
 
+int pciehp_sysfs_enable_slot(struct slot *p_slot)
+{
+	int retval = -ENODEV;
+
+	mutex_lock(&p_slot->lock);
+	switch (p_slot->state) {
+	case BLINKINGON_STATE:
+		cancel_delayed_work(&p_slot->work);
+	case STATIC_STATE:
+		p_slot->state = POWERON_STATE;
+		mutex_unlock(&p_slot->lock);
+		retval = pciehp_enable_slot(p_slot);
+		mutex_lock(&p_slot->lock);
+		p_slot->state = STATIC_STATE;
+		break;
+	case POWERON_STATE:
+		info("Slot %s is already in powering on state\n",
+		     p_slot->name);
+		break;
+	case BLINKINGOFF_STATE:
+	case POWEROFF_STATE:
+		info("Already enabled on slot %s\n", p_slot->name);
+		break;
+	default:
+		err("Not a valid state on slot %s\n", p_slot->name);
+		break;
+	}
+	mutex_unlock(&p_slot->lock);
+
+	return retval;
+}
+
+int pciehp_sysfs_disable_slot(struct slot *p_slot)
+{
+	int retval = -ENODEV;
+
+	mutex_lock(&p_slot->lock);
+	switch (p_slot->state) {
+	case BLINKINGOFF_STATE:
+		cancel_delayed_work(&p_slot->work);
+	case STATIC_STATE:
+		p_slot->state = POWEROFF_STATE;
+		mutex_unlock(&p_slot->lock);
+		retval = pciehp_disable_slot(p_slot);
+		mutex_lock(&p_slot->lock);
+		p_slot->state = STATIC_STATE;
+		break;
+	case POWEROFF_STATE:
+		info("Slot %s is already in powering off state\n",
+		     p_slot->name);
+		break;
+	case BLINKINGON_STATE:
+	case POWERON_STATE:
+		info("Already disabled on slot %s\n", p_slot->name);
+		break;
+	default:
+		err("Not a valid state on slot %s\n", p_slot->name);
+		break;
+	}
+	mutex_unlock(&p_slot->lock);
+
+	return retval;
+}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index fbc64aa..9aac6a8 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -71,6 +71,8 @@ #define DBG_ENTER_ROUTINE
 #define DBG_LEAVE_ROUTINE
 #endif				/* DEBUG */
 
+static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
+
 struct ctrl_reg {
 	u8 cap_id;
 	u8 nxt_ptr;
@@ -219,10 +221,7 @@ #define PRSN_STATE		0x0040
 #define EMI_STATE		0x0080
 #define EMI_STATUS_BIT		7
 
-static spinlock_t hpc_event_lock;
-
 DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
-static int ctlr_seq_num = 0;	/* Controller sequence # */
 
 static irqreturn_t pcie_isr(int irq, void *dev_id);
 static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct cont
 	else
 		free_irq(ctrl->pci_dev->irq, ctrl);
 
+	/*
+	 * If this is the last controller to be released, destroy the
+	 * pciehp work queue
+	 */
+	if (atomic_dec_and_test(&pciehp_num_controllers))
+		destroy_workqueue(pciehp_wq);
+
 	DBG_LEAVE_ROUTINE
 }
 
@@ -1152,7 +1158,6 @@ #endif
 int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
 	int rc;
-	static int first = 1;
 	u16 temp_word;
 	u16 cap_reg;
 	u16 intr_enable = 0;
@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, 
 	dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
-	if (first) {
-		spin_lock_init(&hpc_event_lock);
-		first = 0;
-	}
-
 	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
 		if (pci_resource_len(pdev, rc) > 0)
 			dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, 
 		rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
 				 MY_NAME, (void *)ctrl);
 		dbg("%s: request_irq %d for hpc%d (returns %d)\n",
-		    __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
+		    __FUNCTION__, ctrl->pci_dev->irq,
+		    atomic_read(&pciehp_num_controllers), rc);
 		if (rc) {
 			err("Can't get irq %d for the hotplug controller\n",
 			    ctrl->pci_dev->irq);
@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, 
 	dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
 		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
 
+	/*
+	 * If this is the first controller to be initialized,
+	 * initialize the pciehp work queue
+	 */
+	if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
+		pciehp_wq = create_singlethread_workqueue("pciehpd");
+		if (!pciehp_wq) {
+			rc = -ENOMEM;
+			goto abort_free_irq;
+		}
+	}
+
 	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 	if (rc) {
 		err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, 
 			goto abort_disable_intr;
 	}
 
-	ctlr_seq_num++;
 	ctrl->hpc_ops = &pciehp_hpc_ops;
 
 	DBG_LEAVE_ROUTINE
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 7238346..bb3c101 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -98,7 +98,15 @@ static struct device_node *find_dlpar_no
 	return NULL;
 }
 
-static struct slot *find_slot(struct device_node *dn)
+/**
+ * find_php_slot - return hotplug slot structure for device node
+ *
+ * This routine will return the hotplug slot structure
+ * for a given device node. Note that built-in PCI slots
+ * may be dlpar-able, but not hot-pluggable, so this routine
+ * will return NULL for built-in PCI slots.
+ */
+static struct slot *find_php_slot(struct device_node *dn)
 {
 	struct list_head *tmp, *n;
 	struct slot *slot;
@@ -224,9 +232,9 @@ static int dlpar_remove_phb(char *drc_na
 	if (!pcibios_find_pci_bus(dn))
 		return -EINVAL;
 
-	slot = find_slot(dn);
+	/* If pci slot is hotplugable, use hotplug to remove it */
+	slot = find_php_slot(dn);
 	if (slot) {
-		/* Remove hotplug slot */
 		if (rpaphp_deregister_slot(slot)) {
 			printk(KERN_ERR
 				"%s: unable to remove hotplug slot %s\n",
@@ -370,22 +378,17 @@ int dlpar_remove_pci_slot(char *drc_name
 	if (!bus)
 		return -EINVAL;
 
-	slot = find_slot(dn);
+	/* If pci slot is hotplugable, use hotplug to remove it */
+	slot = find_php_slot(dn);
 	if (slot) {
-		/* Remove hotplug slot */
 		if (rpaphp_deregister_slot(slot)) {
 			printk(KERN_ERR
 				"%s: unable to remove hotplug slot %s\n",
 				__FUNCTION__, drc_name);
 			return -EIO;
 		}
-	} else {
-		struct pci_dev *dev, *tmp;
-		list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
-			eeh_remove_bus_device(dev);
-			pci_remove_bus_device(dev);
-		}
-	}
+	} else
+		pcibios_remove_pci_devices(bus);
 
 	if (unmap_bus_range(bus)) {
 		printk(KERN_ERR "%s: failed to unmap bus range\n",
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index 2e7accf..c822a77 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -83,19 +83,15 @@ struct slot {
 
 extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
 extern struct list_head rpaphp_slot_head;
-extern int num_slots;
 
 /* function prototypes */
 
 /* rpaphp_pci.c */
-extern int rpaphp_enable_pci_slot(struct slot *slot);
-extern int rpaphp_register_pci_slot(struct slot *slot);
-extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern int rpaphp_enable_slot(struct slot *slot);
 extern int rpaphp_get_sensor_state(struct slot *slot, int *state);
 
 /* rpaphp_core.c */
 extern int rpaphp_add_slot(struct device_node *dn);
-extern int rpaphp_remove_slot(struct slot *slot);
 extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
 		char **drc_name, char **drc_type, int *drc_power_domain);
 
@@ -104,7 +100,5 @@ extern void dealloc_slot_struct(struct s
 extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
 extern int rpaphp_register_slot(struct slot *slot);
 extern int rpaphp_deregister_slot(struct slot *slot);
-extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
-extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
 	
 #endif				/* _PPC64PHP_H */
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 71a2cb8..458c08e 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -29,7 +29,6 @@ #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <asm/eeh.h>       /* for eeh_add_device() */
 #include <asm/rtas.h>		/* rtas_call */
@@ -39,9 +38,7 @@ #include "../pci.h"		/* for pci_add_new_
 #include "rpaphp.h"
 
 int debug;
-static struct semaphore rpaphp_sem;
 LIST_HEAD(rpaphp_slot_head);
-int num_slots;
 
 #define DRIVER_VERSION	"0.1"
 #define DRIVER_AUTHOR	"Linda Xie <lxie@us.ibm.com>"
@@ -55,11 +52,6 @@ MODULE_LICENSE("GPL");
 
 module_param(debug, bool, 0644);
 
-static int rpaphp_get_attention_status(struct slot *slot)
-{
-	return slot->hotplug_slot->info->attention_status;
-}
-
 /**
  * set_attention_status - set attention LED
  * echo 0 > attention -- set LED OFF
@@ -69,79 +61,75 @@ static int rpaphp_get_attention_status(s
  */
 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
 {
-	int retval = 0;
+	int rc;
 	struct slot *slot = (struct slot *)hotplug_slot->private;
 
-	down(&rpaphp_sem);
 	switch (value) {
 	case 0:
-		retval = rpaphp_set_attention_status(slot, LED_OFF);
-		hotplug_slot->info->attention_status = 0;
-		break;
 	case 1:
-	default:
-		retval = rpaphp_set_attention_status(slot, LED_ON);
-		hotplug_slot->info->attention_status = 1;
-		break;
 	case 2:
-		retval = rpaphp_set_attention_status(slot, LED_ID);
-		hotplug_slot->info->attention_status = 2;
+		break;
+	default:
+		value = 1;
 		break;
 	}
-	up(&rpaphp_sem);
-	return retval;
+
+	rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
+	if (!rc)
+		hotplug_slot->info->attention_status = value;
+
+	return rc;
 }
 
 /**
  * get_power_status - get power status of a slot
  * @hotplug_slot: slot to get status
  * @value: pointer to store status
- *
- *
  */
 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
-	int retval;
+	int retval, level;
 	struct slot *slot = (struct slot *)hotplug_slot->private;
 
-	down(&rpaphp_sem);
-	retval = rpaphp_get_power_status(slot, value);
-	up(&rpaphp_sem);
+	retval = rtas_get_power_level (slot->power_domain, &level);
+	if (!retval)
+		*value = level;
 	return retval;
 }
 
 /**
  * get_attention_status - get attention LED status
- *
- *
  */
 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
-	int retval = 0;
 	struct slot *slot = (struct slot *)hotplug_slot->private;
-
-	down(&rpaphp_sem);
-	*value = rpaphp_get_attention_status(slot);
-	up(&rpaphp_sem);
-	return retval;
+	*value = slot->hotplug_slot->info->attention_status;
+	return 0;
 }
 
 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
 {
 	struct slot *slot = (struct slot *)hotplug_slot->private;
-	int retval = 0;
+	int rc, state;
 
-	down(&rpaphp_sem);
-	retval = rpaphp_get_pci_adapter_status(slot, 0, value);
-	up(&rpaphp_sem);
-	return retval;
+	rc = rpaphp_get_sensor_state(slot, &state);
+
+	*value = NOT_VALID;
+	if (rc)
+		return rc;
+
+	if (state == EMPTY)
+		*value = EMPTY;
+	else if (state == PRESENT)
+		*value = slot->state;
+
+	return 0;
 }
 
 static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	struct slot *slot = (struct slot *)hotplug_slot->private;
 
-	down(&rpaphp_sem);
 	switch (slot->type) {
 	case 1:
 	case 2:
@@ -172,7 +160,6 @@ static int get_max_bus_speed(struct hotp
 		break;
 
 	}
-	up(&rpaphp_sem);
 	return 0;
 }
 
@@ -182,10 +169,10 @@ static int get_children_props(struct dev
 {
 	const int *indexes, *names, *types, *domains;
 
-	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);
+	indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
+	names = of_get_property(dn, "ibm,drc-names", NULL);
+	types = of_get_property(dn, "ibm,drc-types", NULL);
+	domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
 
 	if (!indexes || !names || !types || !domains) {
 		/* Slot does not have dynamically-removable children */
@@ -218,7 +205,7 @@ int rpaphp_get_drc_props(struct device_n
 	char *name_tmp, *type_tmp;
 	int i, rc;
 
-	my_index = get_property(dn, "ibm,my-drc-index", NULL);
+	my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
 	if (!my_index) {
 		/* Node isn't DLPAR/hotplug capable */
 		return -EINVAL;
@@ -265,6 +252,14 @@ static int is_php_type(char *drc_type)
 	return 1;
 }
 
+/**
+ * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
+ *
+ * This routine will return true only if the device node is
+ * a hotpluggable slot. This routine will return false
+ * for built-in pci slots (even when the built-in slots are
+ * dlparable.)
+ */
 static int is_php_dn(struct device_node *dn, const int **indexes,
 		const int **names, const int **types, const int **power_domains)
 {
@@ -272,24 +267,31 @@ static int is_php_dn(struct device_node 
 	int rc;
 
 	rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
-	if (rc >= 0) {
-		if (is_php_type((char *) &drc_types[1])) {
-			*types = drc_types;
-			return 1;
-		}
-	}
+	if (rc < 0)
+		return 0;
 
-	return 0;
+	if (!is_php_type((char *) &drc_types[1]))
+		return 0;
+
+	*types = drc_types;
+	return 1;
 }
 
 /**
- * rpaphp_add_slot -- add hotplug or dlpar slot
+ * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
+ * @dn device node of slot
+ *
+ * This subroutine will register a hotplugable slot with the
+ * PCI hotplug infrastructure. This routine is typicaly called
+ * during boot time, if the hotplug slots are present at boot time,
+ * or is called later, by the dlpar add code, if the slot is
+ * being dynamically added during runtime.
+ *
+ * If the device node points at an embedded (built-in) slot, this
+ * routine will just return without doing anything, since embedded
+ * slots cannot be hotplugged.
  *
- *	rpaphp not only registers PCI hotplug slots(HOTPLUG), 
- *	but also logical DR slots(EMBEDDED).
- *	HOTPLUG slot: An adapter can be physically added/removed. 
- *	EMBEDDED slot: An adapter can be logically removed/added
- *		  from/to a partition with the slot.
+ * To remove a slot, it suffices to call rpaphp_deregister_slot()
  */
 int rpaphp_add_slot(struct device_node *dn)
 {
@@ -299,34 +301,42 @@ int rpaphp_add_slot(struct device_node *
 	const int *indexes, *names, *types, *power_domains;
 	char *name, *type;
 
+	if (!dn->name || strcmp(dn->name, "pci"))
+		return 0;
+
+	/* If this is not a hotplug slot, return without doing anything. */
+	if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
+		return 0;
+
 	dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
 
 	/* register PCI devices */
-	if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
-		if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
-			goto exit;
-
-		name = (char *) &names[1];
-		type = (char *) &types[1];
-		for (i = 0; i < indexes[0]; i++,
-	     		name += (strlen(name) + 1), type += (strlen(type) + 1)) 		{
-
-			if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
-				       power_domains[i + 1]))) {
-				retval = -ENOMEM;
-				goto exit;
-			}
-			slot->type = simple_strtoul(type, NULL, 10);
+	name = (char *) &names[1];
+	type = (char *) &types[1];
+	for (i = 0; i < indexes[0]; i++) {
+
+		slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]);
+		if (!slot)
+			return -ENOMEM;
+
+		slot->type = simple_strtoul(type, NULL, 10);
 				
-			dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
-					indexes[i + 1], name, type);
+		dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+				indexes[i + 1], name, type);
 
-			retval = rpaphp_register_pci_slot(slot);
-		}
+		retval = rpaphp_enable_slot(slot);
+		if (!retval)
+			retval = rpaphp_register_slot(slot);
+
+		if (retval)
+			dealloc_slot_struct(slot);
+
+		name += strlen(name) + 1;
+		type += strlen(type) + 1;
 	}
-exit:
-	dbg("%s - Exit: num_slots=%d rc[%d]\n",
-	    __FUNCTION__, num_slots, retval);
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+
+	/* XXX FIXME: reports a failure only if last entry in loop failed */
 	return retval;
 }
 
@@ -354,7 +364,6 @@ static int __init rpaphp_init(void)
 	struct device_node *dn = NULL;
 
 	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-	init_MUTEX(&rpaphp_sem);
 
 	while ((dn = of_find_node_by_name(dn, "pci")))
 		rpaphp_add_slot(dn);
@@ -367,8 +376,9 @@ static void __exit rpaphp_exit(void)
 	cleanup_slots();
 }
 
-static int __enable_slot(struct slot *slot)
+static int enable_slot(struct hotplug_slot *hotplug_slot)
 {
+	struct slot *slot = (struct slot *)hotplug_slot->private;
 	int state;
 	int retval;
 
@@ -392,46 +402,17 @@ static int __enable_slot(struct slot *sl
 	return 0;
 }
 
-static int enable_slot(struct hotplug_slot *hotplug_slot)
+static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
-	int retval;
 	struct slot *slot = (struct slot *)hotplug_slot->private;
-
-	down(&rpaphp_sem);
-	retval = __enable_slot(slot);
-	up(&rpaphp_sem);
-
-	return retval;
-}
-
-static int __disable_slot(struct slot *slot)
-{
-	struct pci_dev *dev, *tmp;
-
 	if (slot->state == NOT_CONFIGURED)
 		return -EINVAL;
 
-	list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) {
-		eeh_remove_bus_device(dev);
-		pci_remove_bus_device(dev);
-	}
-
+	pcibios_remove_pci_devices(slot->bus);
 	slot->state = NOT_CONFIGURED;
 	return 0;
 }
 
-static int disable_slot(struct hotplug_slot *hotplug_slot)
-{
-	struct slot *slot = (struct slot *)hotplug_slot->private;
-	int retval;
-
-	down(&rpaphp_sem);
-	retval = __disable_slot (slot);
-	up(&rpaphp_sem);
-
-	return retval;
-}
-
 struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
 	.owner = THIS_MODULE,
 	.enable_slot = enable_slot,
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 6f6cbed..54ca865 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -64,75 +64,6 @@ int rpaphp_get_sensor_state(struct slot 
 	return rc;
 }
 
-/**
- * get_pci_adapter_status - get the status of a slot
- * 
- * 0-- slot is empty
- * 1-- adapter is configured
- * 2-- adapter is not configured
- * 3-- not valid
- */
-int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
-{
-	struct pci_bus *bus;
-	int state, rc;
-
-	*value = NOT_VALID;
-	rc = rpaphp_get_sensor_state(slot, &state);
-	if (rc)
-		goto exit;
-
- 	if (state == EMPTY)
- 		*value = EMPTY;
- 	else if (state == PRESENT) {
-		if (!is_init) {
-			/* at run-time slot->state can be changed by */
-			/* config/unconfig adapter */
-			*value = slot->state;
-		} else {
-			bus = pcibios_find_pci_bus(slot->dn);
-			if (bus && !list_empty(&bus->devices))
-				*value = CONFIGURED;
-			else
-				*value = NOT_CONFIGURED;
-		}
-	}
-exit:
-	return rc;
-}
-
-static void print_slot_pci_funcs(struct pci_bus *bus)
-{
-	struct device_node *dn;
-	struct pci_dev *dev;
-
-	dn = pci_bus_to_OF_node(bus);
-	if (!dn)
-		return;
-
-	dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name);
-	list_for_each_entry (dev, &bus->devices, bus_list)
-		dbg("\t%s\n", pci_name(dev));
-	return;
-}
-
-static int setup_pci_hotplug_slot_info(struct slot *slot)
-{
-	struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
-
-	dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
-	    __FUNCTION__);
-	rpaphp_get_power_status(slot, &hotplug_slot_info->power_status);
-	rpaphp_get_pci_adapter_status(slot, 1,
-				      &hotplug_slot_info->adapter_status);
-	if (hotplug_slot_info->adapter_status == NOT_VALID) {
-		err("%s: NOT_VALID: skip dn->full_name=%s\n",
-		    __FUNCTION__, slot->dn->full_name);
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static void set_slot_name(struct slot *slot)
 {
 	struct pci_bus *bus = slot->bus;
@@ -146,69 +77,73 @@ static void set_slot_name(struct slot *s
 			bus->number);
 }
 
-static int setup_pci_slot(struct slot *slot)
+/**
+ * rpaphp_enable_slot - record slot state, config pci device
+ *
+ * Initialize values in the slot, and the hotplug_slot info
+ * structures to indicate if there is a pci card plugged into
+ * the slot. If the slot is not empty, run the pcibios routine
+ * to get pcibios stuff correctly set up.
+ */
+int rpaphp_enable_slot(struct slot *slot)
 {
-	struct device_node *dn = slot->dn;
+	int rc, level, state;
 	struct pci_bus *bus;
+	struct hotplug_slot_info *info = slot->hotplug_slot->info;
+
+	info->adapter_status = NOT_VALID;
+	slot->state = EMPTY;
+
+	/* Find out if the power is turned on for the slot */
+	rc = rtas_get_power_level(slot->power_domain, &level);
+	if (rc)
+		return rc;
+	info->power_status = level;
+
+	/* Figure out if there is an adapter in the slot */
+	rc = rpaphp_get_sensor_state(slot, &state);
+	if (rc)
+		return rc;
 
-	BUG_ON(!dn);
-	bus = pcibios_find_pci_bus(dn);
+	bus = pcibios_find_pci_bus(slot->dn);
 	if (!bus) {
-		err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
-		goto exit_rc;
+		err("%s: no pci_bus for dn %s\n", __FUNCTION__, slot->dn->full_name);
+		return -EINVAL;
 	}
 
+	info->adapter_status = EMPTY;
 	slot->bus = bus;
 	slot->pci_devs = &bus->devices;
 	set_slot_name(slot);
 
-	/* find slot's pci_dev if it's not empty */
-	if (slot->hotplug_slot->info->adapter_status == EMPTY) {
-		slot->state = EMPTY;	/* slot is empty */
-	} else {
-		/* slot is occupied */
-		if (!dn->child) {
-			/* non-empty slot has to have child */
-			err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 
-				__FUNCTION__, slot->name);
-			goto exit_rc;
+	/* if there's an adapter in the slot, go add the pci devices */
+	if (state == PRESENT) {
+		info->adapter_status = NOT_CONFIGURED;
+		slot->state = NOT_CONFIGURED;
+
+		/* non-empty slot has to have child */
+		if (!slot->dn->child) {
+			err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
+			    __FUNCTION__, slot->name);
+			return -EINVAL;
 		}
 
-		if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
-			dbg("%s CONFIGURING pci adapter in slot[%s]\n",  
-				__FUNCTION__, slot->name);
-			pcibios_add_pci_devices(slot->bus);
+		if (list_empty(&bus->devices))
+			pcibios_add_pci_devices(bus);
 
-		} else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
-			err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
-				__FUNCTION__, slot->name);
-			goto exit_rc;
-		}
-		print_slot_pci_funcs(slot->bus);
-		if (!list_empty(slot->pci_devs)) {
+		if (!list_empty(&bus->devices)) {
+			info->adapter_status = CONFIGURED;
 			slot->state = CONFIGURED;
-		} else {
-			/* DLPAR add as opposed to 
-		 	 * boot time */
-			slot->state = NOT_CONFIGURED;
+		}
+
+		if (debug) {
+			struct pci_dev *dev;
+			dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->dn->full_name);
+			list_for_each_entry (dev, &bus->devices, bus_list)
+				dbg("\t%s\n", pci_name(dev));
 		}
 	}
-	return 0;
-exit_rc:
-	dealloc_slot_struct(slot);
-	return -EINVAL;
-}
 
-int rpaphp_register_pci_slot(struct slot *slot)
-{
-	int rc = -EINVAL;
-
-	if (setup_pci_hotplug_slot_info(slot))
-		goto exit_rc;
-	if (setup_pci_slot(slot))
-		goto exit_rc;
-	rc = rpaphp_register_slot(slot);
-exit_rc:
-	return rc;
+	return 0;
 }
 
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index 3009193..d4ee872 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -56,7 +56,6 @@ static struct hotplug_slot_attribute php
 static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = (struct slot *) hotplug_slot->private;
-
 	dealloc_slot_struct(slot);
 }
 
@@ -65,12 +64,12 @@ void dealloc_slot_struct(struct slot *sl
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
+	kfree(slot->location);
 	kfree(slot);
-	return;
 }
 
-struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name,
-		  int power_domain)
+struct slot *alloc_slot_struct(struct device_node *dn,
+                       int drc_index, char *drc_name, int power_domain)
 {
 	struct slot *slot;
 	
@@ -115,7 +114,7 @@ error_nomem:
 
 static int is_registered(struct slot *slot)
 {
-	struct slot             *tmp_slot;
+	struct slot *tmp_slot;
 
 	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
 		if (!strcmp(tmp_slot->name, slot->name))
@@ -140,8 +139,6 @@ int rpaphp_deregister_slot(struct slot *
 	retval = pci_hp_deregister(php_slot);
 	if (retval)
 		err("Problem unregistering a slot %s\n", slot->name);
-	else
-		num_slots--;
 
 	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
@@ -160,14 +157,13 @@ int rpaphp_register_slot(struct slot *sl
 	/* should not try to register the same slot twice */
 	if (is_registered(slot)) {
 		err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
-		retval = -EAGAIN;
-		goto register_fail;
+		return -EAGAIN;
 	}	
 
 	retval = pci_hp_register(php_slot);
 	if (retval) {
 		err("pci_hp_register failed with error %d\n", retval);
-		goto register_fail;
+		return retval;
 	}
 
 	/* create "phy_location" file */
@@ -181,43 +177,10 @@ int rpaphp_register_slot(struct slot *sl
 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
 	info("Slot [%s](PCI location=%s) registered\n", slot->name,
 			slot->location);
-	num_slots++;
 	return 0;
 
 sysfs_fail:
 	pci_hp_deregister(php_slot);
-register_fail:
-	rpaphp_release_slot(php_slot);
 	return retval;
 }
 
-int rpaphp_get_power_status(struct slot *slot, u8 * value)
-{
-	int rc = 0, level;
-	
-	rc = rtas_get_power_level(slot->power_domain, &level);
-	if (rc < 0) {
-		err("failed to get power-level for slot(%s), rc=0x%x\n",
-			slot->location, rc);
-		return rc;
-	}
-
-	dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n",
-		__FUNCTION__, slot->name, slot->power_domain, level);
-	*value = level;
-
-	return rc;
-}
-
-int rpaphp_set_attention_status(struct slot *slot, u8 status)
-{
-	int rc;
-
-	/* status: LED_OFF or LED_ON */
-	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
-	if (rc < 0)
-		err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
-		    slot->name, slot->location, slot->index, status, rc);
-
-	return rc;
-}
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 01d31a1..37ed088 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -166,7 +166,7 @@ extern u8 shpchp_handle_power_fault(u8 h
 extern int shpchp_configure_device(struct slot *p_slot);
 extern int shpchp_unconfigure_device(struct slot *p_slot);
 extern void cleanup_slots(struct controller *ctrl);
-extern void queue_pushbutton_work(struct work_struct *work);
+extern void shpchp_queue_pushbutton_work(struct work_struct *work);
 extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
 
 #ifdef CONFIG_ACPI
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 5f4bc08..80dec97 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -136,7 +136,7 @@ static int init_slots(struct controller 
 		slot->hpc_ops = ctrl->hpc_ops;
 		slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
 		mutex_init(&slot->lock);
-		INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work);
+		INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
 
 		/* register this slot with the hotplug pci core */
 		hotplug_slot->private = slot;
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index b746bd2..d2fc355 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/workqueue.h>
 #include "../pci.h"
@@ -433,7 +432,7 @@ static void shpchp_pushbutton_thread(str
 	kfree(info);
 }
 
-void queue_pushbutton_work(struct work_struct *work)
+void shpchp_queue_pushbutton_work(struct work_struct *work)
 {
 	struct slot *p_slot = container_of(work, struct slot, work.work);
 	struct pushbutton_work_info *info;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 435c195..e6740d1 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -12,7 +12,6 @@ #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/msi.h>
@@ -24,20 +23,8 @@ #include <asm/smp.h>
 #include "pci.h"
 #include "msi.h"
 
-static struct kmem_cache* msi_cachep;
-
 static int pci_msi_enable = 1;
 
-static int msi_cache_init(void)
-{
-	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_enable(struct pci_dev *dev, int enable)
 {
 	int pos;
@@ -68,6 +55,29 @@ static void msix_set_enable(struct pci_d
 	}
 }
 
+static void msix_flush_writes(unsigned int irq)
+{
+	struct msi_desc *entry;
+
+	entry = get_irq_msi(irq);
+	BUG_ON(!entry || !entry->dev);
+	switch (entry->msi_attrib.type) {
+	case PCI_CAP_ID_MSI:
+		/* nothing to do */
+		break;
+	case PCI_CAP_ID_MSIX:
+	{
+		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+		readl(entry->mask_base + offset);
+		break;
+	}
+	default:
+		BUG();
+		break;
+	}
+}
+
 static void msi_set_mask_bit(unsigned int irq, int flag)
 {
 	struct msi_desc *entry;
@@ -187,41 +197,28 @@ void write_msi_msg(unsigned int irq, str
 void mask_msi_irq(unsigned int irq)
 {
 	msi_set_mask_bit(irq, 1);
+	msix_flush_writes(irq);
 }
 
 void unmask_msi_irq(unsigned int irq)
 {
 	msi_set_mask_bit(irq, 0);
+	msix_flush_writes(irq);
 }
 
-static int msi_free_irq(struct pci_dev* dev, int irq);
-
-static int msi_init(void)
-{
-	static int status = -ENOMEM;
-
-	if (!status)
-		return status;
+static int msi_free_irqs(struct pci_dev* dev);
 
-	status = msi_cache_init();
-	if (status < 0) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING "PCI: MSI cache init failed\n");
-		return status;
-	}
-
-	return status;
-}
 
 static struct msi_desc* alloc_msi_entry(void)
 {
 	struct msi_desc *entry;
 
-	entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
+	entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL);
 	if (!entry)
 		return NULL;
 
-	entry->link.tail = entry->link.head = 0;	/* single message */
+	INIT_LIST_HEAD(&entry->list);
+	entry->irq = 0;
 	entry->dev = NULL;
 
 	return entry;
@@ -256,7 +253,6 @@ static void __pci_restore_msi_state(stru
 static void __pci_restore_msix_state(struct pci_dev *dev)
 {
 	int pos;
-	int irq, head, tail = 0;
 	struct msi_desc *entry;
 	u16 control;
 
@@ -266,18 +262,15 @@ static void __pci_restore_msix_state(str
 	/* route the table */
 	pci_intx(dev, 0);		/* disable intx */
 	msix_set_enable(dev, 0);
-	irq = head = dev->first_msi_irq;
-	entry = get_irq_msi(irq);
-	pos = entry->msi_attrib.pos;
-	while (head != tail) {
-		entry = get_irq_msi(irq);
-		write_msi_msg(irq, &entry->msg);
-		msi_set_mask_bit(irq, entry->msi_attrib.masked);
 
-		tail = entry->link.tail;
-		irq = tail;
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		write_msi_msg(entry->irq, &entry->msg);
+		msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
 	}
 
+	BUG_ON(list_empty(&dev->msi_list));
+	entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+	pos = entry->msi_attrib.pos;
 	pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
 	control &= ~PCI_MSIX_FLAGS_MASKALL;
 	control |= PCI_MSIX_FLAGS_ENABLE;
@@ -303,7 +296,7 @@ #endif	/* CONFIG_PM */
 static int msi_capability_init(struct pci_dev *dev)
 {
 	struct msi_desc *entry;
-	int pos, irq;
+	int pos, ret;
 	u16 control;
 
 	msi_set_enable(dev, 0);	/* Ensure msi is disabled as I set it up */
@@ -340,23 +333,21 @@ static int msi_capability_init(struct pc
 			msi_mask_bits_reg(pos, is_64bit_address(control)),
 			maskbits);
 	}
+	list_add(&entry->list, &dev->msi_list);
+
 	/* Configure MSI capability structure */
-	irq = arch_setup_msi_irq(dev, entry);
-	if (irq < 0) {
-		kmem_cache_free(msi_cachep, entry);
-		return irq;
+	ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
+	if (ret) {
+		msi_free_irqs(dev);
+		return ret;
 	}
-	entry->link.head = irq;
-	entry->link.tail = irq;
-	dev->first_msi_irq = irq;
-	set_irq_msi(irq, entry);
 
 	/* Set MSI enabled bits	 */
 	pci_intx(dev, 0);		/* disable intx */
 	msi_set_enable(dev, 1);
 	dev->msi_enabled = 1;
 
-	dev->irq = irq;
+	dev->irq = entry->irq;
 	return 0;
 }
 
@@ -373,8 +364,8 @@ static int msi_capability_init(struct pc
 static int msix_capability_init(struct pci_dev *dev,
 				struct msix_entry *entries, int nvec)
 {
-	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	int irq, pos, i, j, nr_entries, temp = 0;
+	struct msi_desc *entry;
+	int pos, i, j, nr_entries, ret;
 	unsigned long phys_addr;
 	u32 table_offset;
  	u16 control;
@@ -413,44 +404,34 @@ static int msix_capability_init(struct p
 		entry->dev = dev;
 		entry->mask_base = base;
 
-		/* Configure MSI-X capability structure */
-		irq = arch_setup_msi_irq(dev, entry);
-		if (irq < 0) {
-			kmem_cache_free(msi_cachep, entry);
-			break;
-		}
- 		entries[i].vector = irq;
-		if (!head) {
-			entry->link.head = irq;
-			entry->link.tail = irq;
-			head = entry;
-		} else {
-			entry->link.head = temp;
-			entry->link.tail = tail->link.tail;
-			tail->link.tail = irq;
-			head->link.head = irq;
-		}
-		temp = irq;
-		tail = entry;
-
-		set_irq_msi(irq, entry);
+		list_add(&entry->list, &dev->msi_list);
 	}
-	if (i != nvec) {
-		int avail = i - 1;
-		i--;
-		for (; i >= 0; i--) {
-			irq = (entries + i)->vector;
-			msi_free_irq(dev, irq);
-			(entries + i)->vector = 0;
+
+	ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
+	if (ret) {
+		int avail = 0;
+		list_for_each_entry(entry, &dev->msi_list, list) {
+			if (entry->irq != 0) {
+				avail++;
+			}
 		}
+
+		msi_free_irqs(dev);
+
 		/* If we had some success report the number of irqs
 		 * we succeeded in setting up.
 		 */
-		if (avail <= 0)
-			avail = -EBUSY;
+		if (avail == 0)
+			avail = ret;
 		return avail;
 	}
-	dev->first_msi_irq = entries[0].vector;
+
+	i = 0;
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		entries[i].vector = entry->irq;
+		set_irq_msi(entry->irq, entry);
+		i++;
+	}
 	/* Set MSI-X enabled bits */
 	pci_intx(dev, 0);		/* disable intx */
 	msix_set_enable(dev, 1);
@@ -460,21 +441,32 @@ static int msix_capability_init(struct p
 }
 
 /**
- * pci_msi_supported - check whether MSI may be enabled on device
+ * pci_msi_check_device - check whether MSI may be enabled on a device
  * @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: how many MSIs have been requested ?
+ * @type: are we checking for MSI or MSI-X ?
  *
  * Look at global flags, the device itself, and its parent busses
- * to return 0 if MSI are supported for the device.
+ * to determine if MSI/-X are supported for the device. If MSI/-X is
+ * supported return 0, else return an error code.
  **/
-static
-int pci_msi_supported(struct pci_dev * dev)
+static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
 {
 	struct pci_bus *bus;
+	int ret;
 
 	/* MSI must be globally enabled and supported by the device */
 	if (!pci_msi_enable || !dev || dev->no_msi)
 		return -EINVAL;
 
+	/*
+	 * You can't ask to have 0 or less MSIs configured.
+	 *  a) it's stupid ..
+	 *  b) the list manipulation code assumes nvec >= 1.
+	 */
+	if (nvec < 1)
+		return -ERANGE;
+
 	/* 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.
@@ -485,6 +477,13 @@ int pci_msi_supported(struct pci_dev * d
 		if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
 			return -EINVAL;
 
+	ret = arch_msi_check_device(dev, nvec, type);
+	if (ret)
+		return ret;
+
+	if (!pci_find_capability(dev, type))
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -500,19 +499,12 @@ int pci_msi_supported(struct pci_dev * d
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-	int pos, status;
-
-	if (pci_msi_supported(dev) < 0)
-		return -EINVAL;
+	int status;
 
-	status = msi_init();
-	if (status < 0)
+	status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
+	if (status)
 		return status;
 
-	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-	if (!pos)
-		return -EINVAL;
-
 	WARN_ON(!!dev->msi_enabled);
 
 	/* Check whether driver already requested for MSI-X irqs */
@@ -525,69 +517,54 @@ int pci_enable_msi(struct pci_dev* dev)
 	status = msi_capability_init(dev);
 	return status;
 }
+EXPORT_SYMBOL(pci_enable_msi);
 
 void pci_disable_msi(struct pci_dev* dev)
 {
 	struct msi_desc *entry;
 	int default_irq;
 
-	if (!pci_msi_enable)
-		return;
-	if (!dev)
-		return;
-
-	if (!dev->msi_enabled)
+	if (!pci_msi_enable || !dev || !dev->msi_enabled)
 		return;
 
 	msi_set_enable(dev, 0);
 	pci_intx(dev, 1);		/* enable intx */
 	dev->msi_enabled = 0;
 
-	entry = get_irq_msi(dev->first_msi_irq);
-	if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
+	BUG_ON(list_empty(&dev->msi_list));
+	entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+	if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
 		return;
 	}
-	if (irq_has_action(dev->first_msi_irq)) {
-		printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
-		       "free_irq() on MSI irq %d\n",
-		       pci_name(dev), dev->first_msi_irq);
-		BUG_ON(irq_has_action(dev->first_msi_irq));
-	} else {
-		default_irq = entry->msi_attrib.default_irq;
-		msi_free_irq(dev, dev->first_msi_irq);
-
-		/* Restore dev->irq to its default pin-assertion irq */
-		dev->irq = default_irq;
-	}
-	dev->first_msi_irq = 0;
+
+	default_irq = entry->msi_attrib.default_irq;
+	msi_free_irqs(dev);
+
+	/* Restore dev->irq to its default pin-assertion irq */
+	dev->irq = default_irq;
 }
+EXPORT_SYMBOL(pci_disable_msi);
 
-static int msi_free_irq(struct pci_dev* dev, int irq)
+static int msi_free_irqs(struct pci_dev* dev)
 {
-	struct msi_desc *entry;
-	int head, entry_nr, type;
-	void __iomem *base;
+	struct msi_desc *entry, *tmp;
 
-	entry = get_irq_msi(irq);
-	if (!entry || entry->dev != dev) {
-		return -EINVAL;
-	}
-	type = entry->msi_attrib.type;
-	entry_nr = entry->msi_attrib.entry_nr;
-	head = entry->link.head;
-	base = entry->mask_base;
-	get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
-	get_irq_msi(entry->link.tail)->link.head = entry->link.head;
-
-	arch_teardown_msi_irq(irq);
-	kmem_cache_free(msi_cachep, entry);
-
-	if (type == PCI_CAP_ID_MSIX) {
-		writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
-
-		if (head == irq)
-			iounmap(base);
+	list_for_each_entry(entry, &dev->msi_list, list)
+		BUG_ON(irq_has_action(entry->irq));
+
+	arch_teardown_msi_irqs(dev);
+
+	list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
+		if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
+			if (list_is_last(&entry->list, &dev->msi_list))
+				iounmap(entry->mask_base);
+
+			writel(1, entry->mask_base + entry->msi_attrib.entry_nr
+				  * PCI_MSIX_ENTRY_SIZE
+				  + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+		}
+		list_del(&entry->list);
+		kfree(entry);
 	}
 
 	return 0;
@@ -614,17 +591,14 @@ int pci_enable_msix(struct pci_dev* dev,
 	int i, j;
 	u16 control;
 
-	if (!entries || pci_msi_supported(dev) < 0)
+	if (!entries)
  		return -EINVAL;
 
-	status = msi_init();
-	if (status < 0)
+	status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
+	if (status)
 		return status;
 
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (!pos)
- 		return -EINVAL;
-
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
 	nr_entries = multi_msix_capable(control);
 	if (nvec > nr_entries)
@@ -651,41 +625,25 @@ int pci_enable_msix(struct pci_dev* dev,
 	status = msix_capability_init(dev, entries, nvec);
 	return status;
 }
+EXPORT_SYMBOL(pci_enable_msix);
 
-void pci_disable_msix(struct pci_dev* dev)
+static void msix_free_all_irqs(struct pci_dev *dev)
 {
-	int irq, head, tail = 0, warning = 0;
-
-	if (!pci_msi_enable)
-		return;
-	if (!dev)
-		return;
+	msi_free_irqs(dev);
+}
 
-	if (!dev->msix_enabled)
+void pci_disable_msix(struct pci_dev* dev)
+{
+	if (!pci_msi_enable || !dev || !dev->msix_enabled)
 		return;
 
 	msix_set_enable(dev, 0);
 	pci_intx(dev, 1);		/* enable intx */
 	dev->msix_enabled = 0;
 
-	irq = head = dev->first_msi_irq;
-	while (head != tail) {
-		tail = get_irq_msi(irq)->link.tail;
-		if (irq_has_action(irq))
-			warning = 1;
-		else if (irq != head)	/* Release MSI-X irq */
-			msi_free_irq(dev, irq);
-		irq = tail;
-	}
-	msi_free_irq(dev, irq);
-	if (warning) {
-		printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
-			"free_irq() on all MSI-X irqs\n",
-			pci_name(dev));
-		BUG_ON(warning > 0);
-	}
-	dev->first_msi_irq = 0;
+	msix_free_all_irqs(dev);
 }
+EXPORT_SYMBOL(pci_disable_msix);
 
 /**
  * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
@@ -701,38 +659,11 @@ void msi_remove_pci_irq_vectors(struct p
 	if (!pci_msi_enable || !dev)
  		return;
 
-	if (dev->msi_enabled) {
-		if (irq_has_action(dev->first_msi_irq)) {
-			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
-			       "called without free_irq() on MSI irq %d\n",
-			       pci_name(dev), dev->first_msi_irq);
-			BUG_ON(irq_has_action(dev->first_msi_irq));
-		} else /* Release MSI irq assigned to this device */
-			msi_free_irq(dev, dev->first_msi_irq);
-	}
-	if (dev->msix_enabled) {
-		int irq, head, tail = 0, warning = 0;
-		void __iomem *base = NULL;
-
-		irq = head = dev->first_msi_irq;
-		while (head != tail) {
-			tail = get_irq_msi(irq)->link.tail;
-			base = get_irq_msi(irq)->mask_base;
-			if (irq_has_action(irq))
-				warning = 1;
-			else if (irq != head) /* Release MSI-X irq */
-				msi_free_irq(dev, irq);
-			irq = tail;
-		}
-		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 irqs\n",
-			       pci_name(dev));
-			BUG_ON(warning > 0);
-		}
-	}
+	if (dev->msi_enabled)
+		msi_free_irqs(dev);
+
+	if (dev->msix_enabled)
+		msix_free_all_irqs(dev);
 }
 
 void pci_no_msi(void)
@@ -740,7 +671,53 @@ void pci_no_msi(void)
 	pci_msi_enable = 0;
 }
 
-EXPORT_SYMBOL(pci_enable_msi);
-EXPORT_SYMBOL(pci_disable_msi);
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
+void pci_msi_init_pci_dev(struct pci_dev *dev)
+{
+	INIT_LIST_HEAD(&dev->msi_list);
+}
+
+
+/* Arch hooks */
+
+int __attribute__ ((weak))
+arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
+{
+	return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	struct msi_desc *entry;
+	int ret;
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		ret = arch_setup_msi_irq(dev, entry);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
+{
+	return;
+}
+
+void __attribute__ ((weak))
+arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		if (entry->irq != 0)
+			arch_teardown_msi_irq(entry->irq);
+	}
+}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a064f36..b5ac810 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -317,6 +317,10 @@ static int __init acpi_pci_init(void)
 {
 	int ret;
 
+	if (acpi_gbl_FADT.boot_flags & BAF_MSI_NOT_SUPPORTED) {
+		printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
+		pci_no_msi();
+	}
 	ret = register_acpi_bus_type(&acpi_pci_bus);
 	if (ret)
 		return 0;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index a3c1755..3bb7739 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -14,20 +14,6 @@ #include <linux/sched.h>
 #include "pci.h"
 
 /*
- *  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
  */
 
@@ -52,7 +38,7 @@ store_new_id(struct device_driver *drive
 {
 	struct pci_dynid *dynid;
 	struct pci_driver *pdrv = to_pci_driver(driver);
-	__u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
+	__u32 vendor, device, subvendor=PCI_ANY_ID,
 		subdevice=PCI_ANY_ID, class=0, class_mask=0;
 	unsigned long driver_data=0;
 	int fields=0;
@@ -61,7 +47,7 @@ store_new_id(struct device_driver *drive
 	fields = sscanf(buf, "%x %x %x %x %x %x %lux",
 			&vendor, &device, &subvendor, &subdevice,
 			&class, &class_mask, &driver_data);
-	if (fields < 0)
+	if (fields < 2)
 		return -EINVAL;
 
 	dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
@@ -434,11 +420,6 @@ int __pci_register_driver(struct pci_dri
 	drv->driver.mod_name = mod_name;
 	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);
 
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index cd913a2..284e83a 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -620,7 +620,8 @@ int __must_check pci_create_sysfs_dev_fi
 		goto err_bin_file;
 
 	/* If the device has a ROM, try to expose it in sysfs. */
-	if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
+	if (pci_resource_len(pdev, PCI_ROM_RESOURCE) ||
+	    (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
 		rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
 		if (rom_attr) {
 			pdev->rom_attr = rom_attr;
@@ -635,7 +636,7 @@ int __must_check pci_create_sysfs_dev_fi
 				goto err_rom;
 		} else {
 			retval = -ENOMEM;
-			goto err_bin_file;
+			goto err_resource_files;
 		}
 	}
 	/* add platform-specific attributes */
@@ -645,6 +646,8 @@ int __must_check pci_create_sysfs_dev_fi
 
 err_rom:
 	kfree(rom_attr);
+err_resource_files:
+	pci_remove_resource_files(pdev);
 err_bin_file:
 	if (pdev->cfg_size < 4096)
 		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
@@ -695,4 +698,4 @@ static int __init pci_sysfs_init(void)
 	return 0;
 }
 
-__initcall(pci_sysfs_init);
+late_initcall(pci_sysfs_init);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d3eab05..fd47ac0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -13,6 +13,7 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -34,8 +35,7 @@ unsigned long pci_cardbus_mem_size = DEF
  * Given a PCI bus, returns the highest PCI bus number present in the set
  * including the given PCI bus and its list of child PCI buses.
  */
-unsigned char __devinit
-pci_bus_max_busnr(struct pci_bus* bus)
+unsigned char pci_bus_max_busnr(struct pci_bus* bus)
 {
 	struct list_head *tmp;
 	unsigned char max, n;
@@ -891,31 +891,76 @@ pci_disable_device(struct pci_dev *dev)
 }
 
 /**
- * pci_enable_wake - enable device to generate PME# when suspended
- * @dev: - PCI device to operate on
- * @state: - Current state of device.
- * @enable: - Flag to enable or disable generation
- * 
- * Set the bits in the device's PM Capabilities to generate PME# when
- * the system is suspended. 
+ * pcibios_set_pcie_reset_state - set reset state for device dev
+ * @dev: the PCI-E device reset
+ * @state: Reset state to enter into
+ *
+ *
+ * Sets the PCI-E reset state for the device. This is the default
+ * implementation. Architecture implementations can override this.
+ */
+int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev,
+							enum pcie_reset_state state)
+{
+	return -EINVAL;
+}
+
+/**
+ * pci_set_pcie_reset_state - set reset state for device dev
+ * @dev: the PCI-E device reset
+ * @state: Reset state to enter into
  *
- * -EIO is returned if device doesn't have PM Capabilities. 
- * -EINVAL is returned if device supports it, but can't generate wake events.
- * 0 if operation is successful.
- * 
+ *
+ * Sets the PCI reset state for the device.
+ */
+int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+{
+	return pcibios_set_pcie_reset_state(dev, state);
+}
+
+/**
+ * pci_enable_wake - enable PCI device as wakeup event source
+ * @dev: PCI device affected
+ * @state: PCI state from which device will issue wakeup events
+ * @enable: True to enable event generation; false to disable
+ *
+ * This enables the device as a wakeup event source, or disables it.
+ * When such events involves platform-specific hooks, those hooks are
+ * called automatically by this routine.
+ *
+ * Devices with legacy power management (no standard PCI PM capabilities)
+ * always require such platform hooks.  Depending on the platform, devices
+ * supporting the standard PCI PME# signal may require such platform hooks;
+ * they always update bits in config space to allow PME# generation.
+ *
+ * -EIO is returned if the device can't ever be a wakeup event source.
+ * -EINVAL is returned if the device can't generate wakeup events from
+ * the specified PCI state.  Returns zero if the operation is successful.
  */
 int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
 {
 	int pm;
+	int status;
 	u16 value;
 
+	/* Note that drivers should verify device_may_wakeup(&dev->dev)
+	 * before calling this function.  Platform code should report
+	 * errors when drivers try to enable wakeup on devices that
+	 * can't issue wakeups, or on which wakeups were disabled by
+	 * userspace updating the /sys/devices.../power/wakeup file.
+	 */
+
+	status = call_platform_enable_wakeup(&dev->dev, enable);
+
 	/* find PCI PM capability in list */
 	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
 
-	/* If device doesn't support PM Capabilities, but request is to disable
-	 * wake events, it's a nop; otherwise fail */
-	if (!pm) 
-		return enable ? -EIO : 0; 
+	/* If device doesn't support PM Capabilities, but caller wants to
+	 * disable wake events, it's a NOP.  Otherwise fail unless the
+	 * platform hooks handled this legacy device already.
+	 */
+	if (!pm)
+		return enable ? status : 0;
 
 	/* Check device's ability to generate PME# */
 	pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
@@ -924,8 +969,14 @@ int pci_enable_wake(struct pci_dev *dev,
 	value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */
 
 	/* Check if it can generate PME# from requested state. */
-	if (!value || !(value & (1 << state))) 
+	if (!value || !(value & (1 << state))) {
+		/* if it can't, revert what the platform hook changed,
+		 * always reporting the base "EINVAL, can't PME#" error
+		 */
+		if (enable)
+			call_platform_enable_wakeup(&dev->dev, 0);
 		return enable ? -EINVAL : 0;
+	}
 
 	pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
 
@@ -936,7 +987,7 @@ int pci_enable_wake(struct pci_dev *dev,
 		value &= ~PCI_PM_CTRL_PME_ENABLE;
 
 	pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
-	
+
 	return 0;
 }
 
@@ -1271,7 +1322,7 @@ pci_intx(struct pci_dev *pdev, int enabl
 
 /**
  * pci_msi_off - disables any msi or msix capabilities
- * @pdev: the PCI device to operate on
+ * @dev: the PCI device to operate on
  *
  * If you want to use msi see pci_enable_msi and friends.
  * This is a lower level primitive that allows us to disable
@@ -1403,4 +1454,5 @@ EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
 EXPORT_SYMBOL(pci_enable_wake);
+EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 62ea04c..3fec13d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay;
 
 #ifdef CONFIG_PCI_MSI
 void pci_no_msi(void);
+extern void pci_msi_init_pci_dev(struct pci_dev *dev);
 #else
 static inline void pci_no_msi(void) { }
+static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
 #endif
 
 #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2fe1d69..e48fcf0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -364,7 +364,7 @@ #endif
 	}
 }
 
-static struct pci_bus * __devinit pci_alloc_bus(void)
+static struct pci_bus * pci_alloc_bus(void)
 {
 	struct pci_bus *b;
 
@@ -432,7 +432,7 @@ error_register:
 	return NULL;
 }
 
-struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
 	struct pci_bus *child;
 
@@ -461,7 +461,7 @@ static void pci_enable_crs(struct pci_de
 	pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl);
 }
 
-static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
+static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
 {
 	struct pci_bus *parent = child->parent;
 
@@ -477,7 +477,7 @@ static void __devinit pci_fixup_parent_s
 	}
 }
 
-unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
+unsigned int pci_scan_child_bus(struct pci_bus *bus);
 
 /*
  * If it's a bridge, configure it and scan the bus behind it.
@@ -489,7 +489,7 @@ unsigned int __devinit pci_scan_child_bu
  * them, we proceed to assigning numbers to the remaining buses in
  * order to avoid overlaps between old and new bus numbers.
  */
-int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
 {
 	struct pci_bus *child;
 	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
@@ -846,6 +846,23 @@ static void pci_release_bus_bridge_dev(s
 	kfree(dev);
 }
 
+struct pci_dev *alloc_pci_dev(void)
+{
+	struct pci_dev *dev;
+
+	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	INIT_LIST_HEAD(&dev->global_list);
+	INIT_LIST_HEAD(&dev->bus_list);
+
+	pci_msi_init_pci_dev(dev);
+
+	return dev;
+}
+EXPORT_SYMBOL(alloc_pci_dev);
+
 /*
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
@@ -885,7 +902,7 @@ pci_scan_device(struct pci_bus *bus, int
 	if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
 		return NULL;
 
-	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	dev = alloc_pci_dev();
 	if (!dev)
 		return NULL;
 
@@ -912,7 +929,7 @@ pci_scan_device(struct pci_bus *bus, int
 	return dev;
 }
 
-void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
+void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 {
 	device_initialize(&dev->dev);
 	dev->dev.release = pci_release_dev;
@@ -935,8 +952,7 @@ void __devinit pci_device_add(struct pci
 	up_write(&pci_bus_sem);
 }
 
-struct pci_dev * __devinit
-pci_scan_single_device(struct pci_bus *bus, int devfn)
+struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
 {
 	struct pci_dev *dev;
 
@@ -958,7 +974,7 @@ pci_scan_single_device(struct pci_bus *b
  * discovered devices to the @bus->devices list.  New devices
  * will have an empty dev->global_list head.
  */
-int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
+int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
 	int func, nr = 0;
 	int scan_all_fns;
@@ -991,7 +1007,7 @@ int __devinit pci_scan_slot(struct pci_b
 	return nr;
 }
 
-unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
+unsigned int pci_scan_child_bus(struct pci_bus *bus)
 {
 	unsigned int devfn, pass, max = bus->secondary;
 	struct pci_dev *dev;
@@ -1041,7 +1057,7 @@ unsigned int __devinit pci_do_scan_bus(s
 	return max;
 }
 
-struct pci_bus * __devinit pci_create_bus(struct device *parent,
+struct pci_bus * pci_create_bus(struct device *parent,
 		int bus, struct pci_ops *ops, void *sysdata)
 {
 	int error;
@@ -1119,7 +1135,7 @@ err_out:
 }
 EXPORT_SYMBOL_GPL(pci_create_bus);
 
-struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
+struct pci_bus *pci_scan_bus_parented(struct device *parent,
 		int bus, struct pci_ops *ops, void *sysdata)
 {
 	struct pci_bus *b;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index ed87aa5..0425a7b 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -11,7 +11,6 @@ #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 65d6f23..147d86f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1303,119 +1303,6 @@ static void __init quirk_alder_ioapic(st
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic );
 #endif
 
-enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 };
-/* Defaults to combined */
-static enum ide_combined_type combined_mode;
-
-static int __init combined_setup(char *str)
-{
-	if (!strncmp(str, "ide", 3))
-		combined_mode = IDE;
-	else if (!strncmp(str, "libata", 6))
-		combined_mode = LIBATA;
-	else /* "combined" or anything else defaults to old behavior */
-		combined_mode = COMBINED;
-
-	return 1;
-}
-__setup("combined_mode=", combined_setup);
-
-#ifdef CONFIG_SATA_INTEL_COMBINED
-static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
-{
-	u8 prog, comb, tmp;
-	int ich = 0;
-
-	/*
-	 * Narrow down to Intel SATA PCI devices.
-	 */
-	switch (pdev->device) {
-	/* PCI ids taken from drivers/scsi/ata_piix.c */
-	case 0x24d1:
-	case 0x24df:
-	case 0x25a3:
-	case 0x25b0:
-		ich = 5;
-		break;
-	case 0x2651:
-	case 0x2652:
-	case 0x2653:
-	case 0x2680:	/* ESB2 */
-		ich = 6;
-		break;
-	case 0x27c0:
-	case 0x27c4:
-		ich = 7;
-		break;
-	case 0x2828:	/* ICH8M */
-		ich = 8;
-		break;
-	default:
-		/* we do not handle this PCI device */
-		return;
-	}
-
-	/*
-	 * Read combined mode register.
-	 */
-	pci_read_config_byte(pdev, 0x90, &tmp);	/* combined mode reg */
-
-	if (ich == 5) {
-		tmp &= 0x6;  /* interesting bits 2:1, PATA primary/secondary */
-		if (tmp == 0x4)		/* bits 10x */
-			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
-		else if (tmp == 0x6)	/* bits 11x */
-			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
-		else
-			return;			/* not in combined mode */
-	} else {
-		WARN_ON((ich != 6) && (ich != 7) && (ich != 8));
-		tmp &= 0x3;  /* interesting bits 1:0 */
-		if (tmp & (1 << 0))
-			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
-		else if (tmp & (1 << 1))
-			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
-		else
-			return;			/* not in combined mode */
-	}
-
-	/*
-	 * Read programming interface register.
-	 * (Tells us if it's legacy or native mode)
-	 */
-	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
-
-	/* if SATA port is in native mode, we're ok. */
-	if (prog & comb)
-		return;
-
-	/* Don't reserve any so the IDE driver can get them (but only if
-	 * combined_mode=ide).
-	 */
-	if (combined_mode == IDE)
-		return;
-
-	/* Grab them both for libata if combined_mode=libata. */
-	if (combined_mode == LIBATA) {
-		request_region(0x1f0, 8, "libata");	/* port 0 */
-		request_region(0x170, 8, "libata");	/* port 1 */
-		return;
-	}
-
-	/* SATA port is in legacy mode.  Reserve port so that
-	 * IDE driver does not attempt to use it.  If request_region
-	 * fails, it will be obvious at boot time, so we don't bother
-	 * checking return values.
-	 */
-	if (comb == (1 << 0))
-		request_region(0x1f0, 8, "libata");	/* port 0 */
-	else
-		request_region(0x170, 8, "libata");	/* port 1 */
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,	  quirk_intel_ide_combined );
-#endif /* CONFIG_SATA_INTEL_COMBINED */
-
-
 int pcie_mch_quirk;
 EXPORT_SYMBOL(pcie_mch_quirk);
 
@@ -1761,6 +1648,8 @@ static void __devinit quirk_disable_msi(
 	}
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_msi);
 
 /* Go through the list of Hypertransport capabilities and
  * return 1 if a HT MSI capability is found and enabled */
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 2dd8681..b137a27 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -15,8 +15,7 @@ #include "pci.h"
 
 DECLARE_RWSEM(pci_bus_sem);
 
-static struct pci_bus *
-pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
+static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
 {
 	struct pci_bus* child;
 	struct list_head *tmp;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3554f39..5ec297d 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -36,8 +36,7 @@ #endif
 
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 
-static void __devinit
-pbus_assign_resources_sorted(struct pci_bus *bus)
+static void pbus_assign_resources_sorted(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 	struct resource *res;
@@ -220,8 +219,7 @@ pci_setup_bridge(struct pci_bus *bus)
 /* Check whether the bridge supports optional I/O and
    prefetchable memory ranges. If not, the respective
    base/limit registers must be read-only and read as 0. */
-static void __devinit
-pci_bridge_check_ranges(struct pci_bus *bus)
+static void pci_bridge_check_ranges(struct pci_bus *bus)
 {
 	u16 io;
 	u32 pmem;
@@ -259,8 +257,7 @@ pci_bridge_check_ranges(struct pci_bus *
    bus resource of a given type. Note: we intentionally skip
    the bus resources which have already been assigned (that is,
    have non-NULL parent resource). */
-static struct resource * __devinit
-find_free_bus_resource(struct pci_bus *bus, unsigned long type)
+static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
 {
 	int i;
 	struct resource *r;
@@ -281,8 +278,7 @@ find_free_bus_resource(struct pci_bus *b
    since these windows have 4K granularity and the IO ranges
    of non-bridge PCI devices are limited to 256 bytes.
    We must be careful with the ISA aliasing though. */
-static void __devinit
-pbus_size_io(struct pci_bus *bus)
+static void pbus_size_io(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -326,8 +322,7 @@ #endif
 
 /* Calculate the size of the bus and minimal alignment which
    guarantees that all child resources fit in this size. */
-static int __devinit
-pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
 {
 	struct pci_dev *dev;
 	unsigned long min_align, align, size;
@@ -447,8 +442,7 @@ pci_bus_size_cardbus(struct pci_bus *bus
 	}
 }
 
-void __devinit
-pci_bus_size_bridges(struct pci_bus *bus)
+void pci_bus_size_bridges(struct pci_bus *bus)
 {
 	struct pci_dev *dev;
 	unsigned long mask, prefmask;
@@ -498,8 +492,7 @@ pci_bus_size_bridges(struct pci_bus *bus
 }
 EXPORT_SYMBOL(pci_bus_size_bridges);
 
-void __devinit
-pci_bus_assign_resources(struct pci_bus *bus)
+void pci_bus_assign_resources(struct pci_bus *bus)
 {
 	struct pci_bus *b;
 	struct pci_dev *dev;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index cb4ced3..6dfd861 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -101,8 +101,7 @@ pci_update_resource(struct pci_dev *dev,
 		new & ~PCI_REGION_FLAG_MASK);
 }
 
-int __devinit
-pci_claim_resource(struct pci_dev *dev, int resource)
+int pci_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
 	struct resource *root = NULL;
@@ -212,8 +211,7 @@ EXPORT_SYMBOL_GPL(pci_assign_resource_fi
 #endif
 
 /* Sort resources by alignment */
-void __devinit
-pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
+void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 {
 	int i;
 
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 99baabc..948efc7 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -360,7 +360,6 @@ static struct platform_driver at91_cf_dr
 		.name		= (char *) driver_name,
 		.owner		= THIS_MODULE,
 	},
-	.probe		= at91_cf_probe,
 	.remove		= __exit_p(at91_cf_remove),
 	.suspend	= at91_cf_suspend,
 	.resume		= at91_cf_resume,
@@ -370,7 +369,7 @@ static struct platform_driver at91_cf_dr
 
 static int __init at91_cf_init(void)
 {
-	return platform_driver_register(&at91_cf_driver);
+	return platform_driver_probe(&at91_cf_driver, at91_cf_probe);
 }
 module_init(at91_cf_init);
 
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index ac00424..50cad3a 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -26,7 +26,6 @@ #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/pci.h>
 #include <linux/device.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 18e111e..143c6ef 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -234,6 +234,89 @@ static void pcmcia_check_driver(struct p
 /*======================================================================*/
 
 
+struct pcmcia_dynid {
+	struct list_head 		node;
+	struct pcmcia_device_id 	id;
+};
+
+/**
+ * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic PCMCIA device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t
+pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
+{
+	struct pcmcia_dynid *dynid;
+	struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
+	__u16 match_flags, manf_id, card_id;
+	__u8 func_id, function, device_no;
+	__u32 prod_id_hash[4] = {0, 0, 0, 0};
+	int fields=0;
+	int retval = 0;
+
+	fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
+			&match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
+			&prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
+	if (fields < 6)
+		return -EINVAL;
+
+	dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
+	if (!dynid)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dynid->node);
+	dynid->id.match_flags = match_flags;
+	dynid->id.manf_id = manf_id;
+	dynid->id.card_id = card_id;
+	dynid->id.func_id = func_id;
+	dynid->id.function = function;
+	dynid->id.device_no = device_no;
+	memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
+
+	spin_lock(&pdrv->dynids.lock);
+	list_add_tail(&pdrv->dynids.list, &dynid->node);
+	spin_unlock(&pdrv->dynids.lock);
+
+	if (get_driver(&pdrv->drv)) {
+		retval = driver_attach(&pdrv->drv);
+		put_driver(&pdrv->drv);
+	}
+
+	if (retval)
+		return retval;
+	return count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id);
+
+static void
+pcmcia_free_dynids(struct pcmcia_driver *drv)
+{
+	struct pcmcia_dynid *dynid, *n;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	spin_unlock(&drv->dynids.lock);
+}
+
+static int
+pcmcia_create_newid_file(struct pcmcia_driver *drv)
+{
+	int error = 0;
+	if (drv->probe != NULL)
+		error = sysfs_create_file(&drv->drv.kobj,
+					  &driver_attr_new_id.attr);
+	return error;
+}
+
+
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
  *
@@ -241,6 +324,8 @@ static void pcmcia_check_driver(struct p
  */
 int pcmcia_register_driver(struct pcmcia_driver *driver)
 {
+	int error;
+
 	if (!driver)
 		return -EINVAL;
 
@@ -249,10 +334,20 @@ int pcmcia_register_driver(struct pcmcia
 	/* initialize common fields */
 	driver->drv.bus = &pcmcia_bus_type;
 	driver->drv.owner = driver->owner;
+	spin_lock_init(&driver->dynids.lock);
+	INIT_LIST_HEAD(&driver->dynids.list);
 
 	ds_dbg(3, "registering driver %s\n", driver->drv.name);
 
-	return driver_register(&driver->drv);
+	error = driver_register(&driver->drv);
+	if (error < 0)
+		return error;
+
+	error = pcmcia_create_newid_file(driver);
+	if (error)
+		driver_unregister(&driver->drv);
+
+	return error;
 }
 EXPORT_SYMBOL(pcmcia_register_driver);
 
@@ -263,6 +358,7 @@ void pcmcia_unregister_driver(struct pcm
 {
 	ds_dbg(3, "unregistering driver %s\n", driver->drv.name);
 	driver_unregister(&driver->drv);
+	pcmcia_free_dynids(driver);
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
 
@@ -927,6 +1023,21 @@ static int pcmcia_bus_match(struct devic
 	struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
 	struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
 	struct pcmcia_device_id *did = p_drv->id_table;
+	struct pcmcia_dynid *dynid;
+
+	/* match dynamic devices first */
+	spin_lock(&p_drv->dynids.lock);
+	list_for_each_entry(dynid, &p_drv->dynids.list, node) {
+		ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
+		       drv->name);
+		if (pcmcia_devmatch(p_dev, &dynid->id)) {
+			ds_dbg(0, "matched %s to %s\n", dev->bus_id,
+			       drv->name);
+			spin_unlock(&p_drv->dynids.lock);
+			return 1;
+		}
+	}
+	spin_unlock(&p_drv->dynids.lock);
 
 #ifdef CONFIG_PCMCIA_IOCTL
 	/* matching by cardmgr */
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index fda0694..383107b 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,6 +175,7 @@ static int __init mst_pcmcia_init(void)
 	if (!mst_pcmcia_device)
 		return -ENOMEM;
 
+	mst_pcmcia_device->dev.uevent_suppress = 0;
 	mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
 
 	ret = platform_device_add(mst_pcmcia_device);
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index b7b9e14..a2daa3f 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,6 +261,7 @@ static int __init sharpsl_pcmcia_init(vo
 	if (!sharpsl_pcmcia_device)
 		return -ENOMEM;
 
+	sharpsl_pcmcia_device->dev.uevent_suppress = 0;
 	sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
 	sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
 
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index ea5765c..a2bb465 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -22,7 +22,6 @@ #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/pci.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <asm/system.h>
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 91c047a..dd6384b 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -311,7 +311,6 @@ done:
 	return NULL;
 
 found:
-	down_write(&dev->dev.bus->subsys.rwsem);
 	dev->card_link = clink;
 	dev->dev.driver = &drv->link.driver;
 	if (pnp_bus_type.probe(&dev->dev))
@@ -319,14 +318,11 @@ found:
 	if (device_bind_driver(&dev->dev))
 		goto err_out;
 
-	up_write(&dev->dev.bus->subsys.rwsem);
-
 	return dev;
 
 err_out:
 	dev->dev.driver = NULL;
 	dev->card_link = NULL;
-	up_write(&dev->dev.bus->subsys.rwsem);
 	return NULL;
 }
 
@@ -340,11 +336,9 @@ void pnp_release_card_device(struct pnp_
 	struct pnp_card_driver * drv = dev->card_link->driver;
 	if (!drv)
 		return;
-	down_write(&dev->dev.bus->subsys.rwsem);
 	drv->link.remove = &card_remove;
 	device_release_driver(&dev->dev);
 	drv->link.remove = &card_remove_first;
-	up_write(&dev->dev.bus->subsys.rwsem);
 }
 
 /*
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index aec83ec..3e20b1c 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -14,6 +14,7 @@ #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/dma-mapping.h>
 
 #include "base.h"
 
@@ -22,6 +23,14 @@ static LIST_HEAD(pnp_protocols);
 LIST_HEAD(pnp_global);
 DEFINE_SPINLOCK(pnp_lock);
 
+/*
+ * ACPI or PNPBIOS should tell us about all platform devices, so we can
+ * skip some blind probes.  ISAPNP typically enumerates only plug-in ISA
+ * devices, not built-in things like COM ports.
+ */
+int pnp_platform_devices;
+EXPORT_SYMBOL(pnp_platform_devices);
+
 void *pnp_alloc(long size)
 {
 	void *result;
@@ -114,6 +123,8 @@ int __pnp_add_device(struct pnp_dev *dev
 	int ret;
 	pnp_fixup_device(dev);
 	dev->dev.bus = &pnp_bus_type;
+	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK;
 	dev->dev.release = &pnp_release_device;
 	dev->status = PNP_READY;
 	spin_lock(&pnp_lock);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 62eda5d..a005487 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
  * Copyright (c) 2004 Li Shaohua <shaohua.li@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, or (at your option) any
@@ -18,7 +18,7 @@
  * 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/acpi.h>
 #include <linux/pnp.h>
 #include <acpi/acpi_bus.h>
@@ -82,7 +82,7 @@ static void __init pnpidacpi_to_pnpid(ch
 static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
 {
 	acpi_status status;
-	status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data, 
+	status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
 		&dev->res);
 	return ACPI_FAILURE(status) ? -ENODEV : 0;
 }
@@ -112,9 +112,9 @@ static int pnpacpi_set_resources(struct 
 static int pnpacpi_disable_resources(struct pnp_dev *dev)
 {
 	acpi_status status;
-	
+
 	/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
-	status = acpi_evaluate_object((acpi_handle)dev->data, 
+	status = acpi_evaluate_object((acpi_handle)dev->data,
 		"_DIS", NULL, NULL);
 	return ACPI_FAILURE(status) ? -ENODEV : 0;
 }
@@ -167,7 +167,7 @@ static int __init pnpacpi_add_device(str
 		strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
 
 	dev->number = num;
-	
+
 	/* set the initial values for the PnP device */
 	dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
 	if (!dev_id)
@@ -185,14 +185,14 @@ static int __init pnpacpi_add_device(str
 	}
 
 	if(dev->capabilities & PNP_CONFIGURABLE) {
-		status = pnpacpi_parse_resource_option_data(device->handle, 
+		status = pnpacpi_parse_resource_option_data(device->handle,
 			dev);
 		if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
 			pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
 			goto err1;
 		}
 	}
-	
+
 	/* parse compatible ids */
 	if (device->flags.compatible_ids) {
 		struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
@@ -236,6 +236,42 @@ static acpi_status __init pnpacpi_add_de
 	return AE_OK;
 }
 
+static int __init acpi_pnp_match(struct device *dev, void *_pnp)
+{
+	struct acpi_device	*acpi = to_acpi_device(dev);
+	struct pnp_dev		*pnp = _pnp;
+
+	/* true means it matched */
+	return acpi->flags.hardware_id
+		&& !acpi_get_physical_device(acpi->handle)
+		&& compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
+}
+
+static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle)
+{
+	struct device		*adev;
+	struct acpi_device	*acpi;
+
+	adev = bus_find_device(&acpi_bus_type, NULL,
+			to_pnp_dev(dev),
+			acpi_pnp_match);
+	if (!adev)
+		return -ENODEV;
+
+	acpi = to_acpi_device(adev);
+	*handle = acpi->handle;
+	put_device(adev);
+	return 0;
+}
+
+/* complete initialization of a PNPACPI device includes having
+ * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
+ */
+static struct acpi_bus_type __initdata acpi_pnp_bus = {
+	.bus = &pnp_bus_type,
+	.find_device = acpi_pnp_find_device,
+};
+
 int pnpacpi_disabled __initdata;
 static int __init pnpacpi_init(void)
 {
@@ -245,8 +281,11 @@ static int __init pnpacpi_init(void)
 	}
 	pnp_info("PnP ACPI init");
 	pnp_register_protocol(&pnpacpi_protocol);
+	register_acpi_bus_type(&acpi_pnp_bus);
 	acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
 	pnp_info("PnP ACPI: found %d devices", num);
+	unregister_acpi_bus_type(&acpi_pnp_bus);
+	pnp_platform_devices = 1;
 	return 0;
 }
 subsys_initcall(pnpacpi_init);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 95738db..3a201b7 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -62,6 +62,7 @@ #include <linux/dmi.h>
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include <linux/freezer.h>
+#include <linux/kthread.h>
 
 #include <asm/page.h>
 #include <asm/desc.h>
@@ -159,9 +160,7 @@ static int pnp_dock_thread(void * unused
 {
 	static struct pnp_docking_station_info now;
 	int docked = -1, d = 0;
-	daemonize("kpnpbiosd");
-	allow_signal(SIGKILL);
-	while(!unloading && !signal_pending(current))
+	while (!unloading)
 	{
 		int status;
 		
@@ -170,11 +169,8 @@ static int pnp_dock_thread(void * unused
 		 */
 		msleep_interruptible(2000);
 
-		if(signal_pending(current)) {
-			if (try_to_freeze())
-				continue;
-			break;
-		}
+		if (try_to_freeze())
+			continue;
 
 		status = pnp_bios_dock_station_info(&now);
 
@@ -574,6 +570,7 @@ #endif /* CONFIG_ACPI */
 	/* scan for pnpbios devices */
 	build_devlist();
 
+	pnp_platform_devices = 1;
 	return 0;
 }
 
@@ -581,6 +578,7 @@ subsys_initcall(pnpbios_init);
 
 static int __init pnpbios_thread_init(void)
 {
+	struct task_struct *task;
 #if defined(CONFIG_PPC_MERGE)
 	if (check_legacy_ioport(PNPBIOS_BASE))
 		return 0;
@@ -589,7 +587,8 @@ #endif
 		return 0;
 #ifdef CONFIG_HOTPLUG
 	init_completion(&unload_sem);
-	if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0)
+	task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
+	if (!IS_ERR(task))
 		unloading = 0;
 #endif
 	return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e97ecef..277df50 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -16,6 +16,7 @@ #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/pnp.h>
+#include <linux/io.h>
 #include "base.h"
 
 
@@ -106,6 +107,34 @@ static void quirk_sb16audio_resources(st
 	return;
 }
 
+static void quirk_smc_enable(struct pnp_dev *dev)
+{
+	unsigned int firbase;
+
+	if (!dev->active || !pnp_port_valid(dev, 1))
+		return;
+
+	/*
+	 * On the HP/Compaq nw8240 (and probably other similar machines),
+	 * there is an SMCF010 device with two I/O port regions:
+	 *
+	 *	0x3e8-0x3ef SIR
+	 *	0x100-0x10f FIR
+	 *
+	 * _STA reports the device is enabled, but in fact, the BIOS
+	 * neglects to enable the FIR range.  Fortunately, it does fully
+	 * enable the device if we call _SRS.
+	 */
+	firbase = pnp_port_start(dev, 1);
+	if (inb(firbase + 0x7 /* IRCC_MASTER */) == 0xff) {
+		pnp_err("%s (%s) enabled but not responding, disabling and "
+			"re-enabling", dev->dev.bus_id, pnp_dev_name(dev));
+		pnp_disable_dev(dev);
+		pnp_activate_dev(dev);
+	}
+}
+
+
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -126,6 +155,7 @@ static struct pnp_fixup pnp_fixups[] = {
 	{ "CTL0043", quirk_sb16audio_resources },
 	{ "CTL0044", quirk_sb16audio_resources },
 	{ "CTL0045", quirk_sb16audio_resources },
+	{ "SMCf010", quirk_smc_enable },
 	{ "" }
 };
 
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index d21e04c..1393e64 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -38,7 +38,24 @@ #define PS3AV_BUF_SIZE   512	/* max pack
 static int timeout = 5000;	/* in msec ( 5 sec ) */
 module_param(timeout, int, 0644);
 
-static struct ps3av ps3av;
+static struct ps3av {
+	int available;
+	struct mutex mutex;
+	struct work_struct work;
+	struct completion done;
+	struct workqueue_struct *wq;
+	int open_count;
+	struct ps3_vuart_port_device *dev;
+
+	int region;
+	struct ps3av_pkt_av_get_hw_conf av_hw_conf;
+	u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
+	u32 opt_port[PS3AV_OPT_PORT_MAX];
+	u32 head[PS3AV_HEAD_MAX];
+	u32 audio_port;
+	int ps3av_mode;
+	int ps3av_mode_old;
+} ps3av;
 
 static struct ps3_vuart_port_device ps3av_dev = {
 	.match_id = PS3_MATCH_ID_AV_SETTINGS
@@ -159,7 +176,7 @@ static int ps3av_parse_event_packet(cons
 		else
 			printk(KERN_ERR
 			       "%s: failed event packet, cid:%08x size:%d\n",
-			       __FUNCTION__, hdr->cid, hdr->size);
+			       __func__, hdr->cid, hdr->size);
 		return 1;	/* receive event packet */
 	}
 	return 0;
@@ -181,7 +198,7 @@ static int ps3av_send_cmd_pkt(const stru
 	if (res < 0) {
 		dev_dbg(&ps3av_dev.core,
 			"%s: ps3av_vuart_write() failed (result=%d)\n",
-			__FUNCTION__, res);
+			__func__, res);
 		return res;
 	}
 
@@ -194,7 +211,7 @@ static int ps3av_send_cmd_pkt(const stru
 		if (res != PS3AV_HDR_SIZE) {
 			dev_dbg(&ps3av_dev.core,
 				"%s: ps3av_vuart_read() failed (result=%d)\n",
-				__FUNCTION__, res);
+				__func__, res);
 			return res;
 		}
 
@@ -204,7 +221,7 @@ static int ps3av_send_cmd_pkt(const stru
 		if (res < 0) {
 			dev_dbg(&ps3av_dev.core,
 				"%s: ps3av_vuart_read() failed (result=%d)\n",
-				__FUNCTION__, res);
+				__func__, res);
 			return res;
 		}
 		res += PS3AV_HDR_SIZE;	/* total len */
@@ -214,7 +231,7 @@ static int ps3av_send_cmd_pkt(const stru
 
 	if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
 		dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
-			__FUNCTION__, recv_buf->cid);
+			__func__, recv_buf->cid);
 		return -EINVAL;
 	}
 
@@ -250,7 +267,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, 
 		 struct ps3av_send_hdr *buf)
 {
 	int res = 0;
-	union {
+	static union {
 		struct ps3av_reply_hdr reply_hdr;
 		u8 raw[PS3AV_BUF_SIZE];
 	} recv_buf;
@@ -259,8 +276,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, 
 
 	BUG_ON(!ps3av.available);
 
-	if (down_interruptible(&ps3av.sem))
-		return -ERESTARTSYS;
+	mutex_lock(&ps3av.mutex);
 
 	table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
 	BUG_ON(!table);
@@ -277,7 +293,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, 
 	if (res < 0) {
 		printk(KERN_ERR
 		       "%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
-		       __FUNCTION__, res);
+		       __func__, res);
 		goto err;
 	}
 
@@ -286,16 +302,16 @@ int ps3av_do_pkt(u32 cid, u16 send_len, 
 					 usr_buf_size);
 	if (res < 0) {
 		printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
-		       __FUNCTION__, res);
+		       __func__, res);
 		goto err;
 	}
 
-	up(&ps3av.sem);
+	mutex_unlock(&ps3av.mutex);
 	return 0;
 
       err:
-	up(&ps3av.sem);
-	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
+	mutex_unlock(&ps3av.mutex);
+	printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
 	return res;
 }
 
@@ -440,7 +456,7 @@ static int ps3av_set_videomode(void)
 	ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
 
 	/* wake up ps3avd to do the actual video mode setting */
-	up(&ps3av.ping);
+	queue_work(ps3av.wq, &ps3av.work);
 
 	return 0;
 }
@@ -506,7 +522,7 @@ #endif
 	if (res == PS3AV_STATUS_NO_SYNC_HEAD)
 		printk(KERN_WARNING
 		       "%s: Command failed. Please try your request again. \n",
-		       __FUNCTION__);
+		       __func__);
 	else if (res)
 		dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
 
@@ -515,18 +531,10 @@ #endif
 	ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
 }
 
-static int ps3avd(void *p)
+static void ps3avd(struct work_struct *work)
 {
-	struct ps3av *info = p;
-
-	daemonize("ps3avd");
-	while (1) {
-		down(&info->ping);
-		ps3av_set_videomode_cont(info->ps3av_mode,
-					 info->ps3av_mode_old);
-		up(&info->pong);
-	}
-	return 0;
+	ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old);
+	complete(&ps3av.done);
 }
 
 static int ps3av_vid2table_id(int vid)
@@ -707,8 +715,7 @@ int ps3av_set_video_mode(u32 id, int boo
 
 	size = ARRAY_SIZE(video_mode_table);
 	if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
-		dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__,
-			id);
+		dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id);
 		return -EINVAL;
 	}
 
@@ -717,15 +724,14 @@ int ps3av_set_video_mode(u32 id, int boo
 	if ((id & PS3AV_MODE_MASK) == 0) {
 		id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
 		if (id < 1) {
-			printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__,
-			       id);
+			printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
 			return -EINVAL;
 		}
 		id |= option;
 	}
 
 	/* set videomode */
-	down(&ps3av.pong);
+	wait_for_completion(&ps3av.done);
 	ps3av.ps3av_mode_old = ps3av.ps3av_mode;
 	ps3av.ps3av_mode = id;
 	if (ps3av_set_videomode())
@@ -736,6 +742,13 @@ int ps3av_set_video_mode(u32 id, int boo
 
 EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
 
+int ps3av_get_auto_mode(int boot)
+{
+	return ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+}
+
+EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
+
 int ps3av_set_mode(u32 id, int boot)
 {
 	int res;
@@ -771,7 +784,7 @@ int ps3av_get_scanmode(int id)
 	id = id & PS3AV_MODE_MASK;
 	size = ARRAY_SIZE(video_mode_table);
 	if (id > size - 1 || id < 0) {
-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
 		return -EINVAL;
 	}
 	return video_mode_table[id].interlace;
@@ -786,7 +799,7 @@ int ps3av_get_refresh_rate(int id)
 	id = id & PS3AV_MODE_MASK;
 	size = ARRAY_SIZE(video_mode_table);
 	if (id > size - 1 || id < 0) {
-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
 		return -EINVAL;
 	}
 	return video_mode_table[id].freq;
@@ -802,7 +815,7 @@ int ps3av_video_mode2res(u32 id, u32 *xr
 	id = id & PS3AV_MODE_MASK;
 	size = ARRAY_SIZE(video_mode_table);
 	if (id > size - 1 || id < 0) {
-		printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+		printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
 		return -EINVAL;
 	}
 	*xres = video_mode_table[id].x;
@@ -838,7 +851,7 @@ int ps3av_dev_open(void)
 		status = lv1_gpu_open(0);
 		if (status) {
 			printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
-			       __FUNCTION__, status);
+			       __func__, status);
 			ps3av.open_count--;
 		}
 	}
@@ -855,13 +868,13 @@ int ps3av_dev_close(void)
 
 	mutex_lock(&ps3av.mutex);
 	if (ps3av.open_count <= 0) {
-		printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__);
+		printk(KERN_ERR "%s: GPU already closed\n", __func__);
 		status = -1;
 	} else if (!--ps3av.open_count) {
 		status = lv1_gpu_close();
 		if (status)
 			printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
-			       __FUNCTION__, status);
+			       __func__, status);
 	}
 	mutex_unlock(&ps3av.mutex);
 
@@ -880,13 +893,16 @@ static int ps3av_probe(struct ps3_vuart_
 
 	memset(&ps3av, 0, sizeof(ps3av));
 
-	init_MUTEX(&ps3av.sem);
-	init_MUTEX_LOCKED(&ps3av.ping);
-	init_MUTEX(&ps3av.pong);
 	mutex_init(&ps3av.mutex);
 	ps3av.ps3av_mode = 0;
 	ps3av.dev = dev;
-	kernel_thread(ps3avd, &ps3av, CLONE_KERNEL);
+
+	INIT_WORK(&ps3av.work, ps3avd);
+	init_completion(&ps3av.done);
+	complete(&ps3av.done);
+	ps3av.wq = create_singlethread_workqueue("ps3avd");
+	if (!ps3av.wq)
+		return -ENOMEM;
 
 	ps3av.available = 1;
 	switch (ps3_os_area_get_av_multi_out()) {
@@ -908,7 +924,7 @@ static int ps3av_probe(struct ps3_vuart_
 	/* init avsetting modules */
 	res = ps3av_cmd_init();
 	if (res < 0)
-		printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__,
+		printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__,
 		       res);
 
 	ps3av_get_hw_conf(&ps3av);
@@ -926,6 +942,8 @@ static int ps3av_remove(struct ps3_vuart
 {
 	if (ps3av.available) {
 		ps3av_cmd_fin();
+		if (ps3av.wq)
+			destroy_workqueue(ps3av.wq);
 		ps3av.available = 0;
 	}
 
@@ -958,7 +976,7 @@ static int ps3av_module_init(void)
 	if (error) {
 		printk(KERN_ERR
 		       "%s: ps3_vuart_port_driver_register failed %d\n",
-		       __FUNCTION__, error);
+		       __func__, error);
 		return error;
 	}
 
@@ -966,7 +984,7 @@ static int ps3av_module_init(void)
 	if (error)
 		printk(KERN_ERR
 		       "%s: ps3_vuart_port_device_register failed %d\n",
-		       __FUNCTION__, error);
+		       __func__, error);
 
 	return error;
 }
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index bc70e81..0145ea1 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -395,7 +395,7 @@ u32 ps3av_cmd_set_video_mode(void *p, u3
 	video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
 
 	pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
-		__FUNCTION__, video_vid, video_mode->width, video_mode->height,
+		__func__, video_vid, video_mode->width, video_mode->height,
 		video_mode->pitch, video_mode->video_out_format,
 		video_mode->video_format, video_mode->video_order);
 	return sizeof(*video_mode);
@@ -477,7 +477,7 @@ static u8 ps3av_cnv_mclk(u32 fs)
 		if (ps3av_cnv_mclk_table[i].fs == fs)
 			return ps3av_cnv_mclk_table[i].mclk;
 
-	printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+	printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
 	return 0;
 }
 
@@ -526,13 +526,12 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs,
 		d = 4;
 		break;
 	default:
-		printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__,
-		       video_vid);
+		printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid);
 		break;
 	}
 
 	if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)
-		printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+		printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
 	else
 		ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
 
@@ -555,8 +554,7 @@ static u8 ps3av_cnv_enable(u32 source, c
 		ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
 		      0x01;
 	} else
-		printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__,
-		       source);
+		printk(KERN_ERR "%s failed, source:%x\n", __func__, source);
 	return ret;
 }
 
@@ -585,7 +583,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bi
 		ret = PS3AV_CMD_AV_INPUTLEN_24;
 		break;
 	default:
-		printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__,
+		printk(KERN_ERR "%s failed, word_bits:%x\n", __func__,
 		       word_bits);
 		break;
 	}
@@ -595,7 +593,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bi
 static u8 ps3av_cnv_layout(u32 num_of_ch)
 {
 	if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {
-		printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__,
+		printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__,
 		       num_of_ch);
 		return 0;
 	}
@@ -864,7 +862,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt
 
 	res = get_status(avb);
 	if (res)
-		pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__,
+		pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__,
 			 res);
 
       out:
@@ -1013,7 +1011,7 @@ int ps3av_vuart_read(struct ps3_vuart_po
 			return size;
 		if (error != -EAGAIN) {
 			printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
-			       __FUNCTION__, error);
+			       __func__, error);
 			return error;
 		}
 		msleep(POLLING_INTERVAL);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6c12744..ec2d36a 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -82,14 +82,6 @@ struct ports_bmp {
 	u64 unused[3];
 } __attribute__ ((aligned (32)));
 
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-	const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
 #define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
 static void __attribute__ ((unused)) _dump_ports_bmp(
 	const struct ports_bmp* bmp, const char* func, int line)
@@ -894,12 +886,12 @@ static int ps3_vuart_probe(struct device
 
 	if (++vuart_bus_priv.use_count == 1) {
 
-		result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+		result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY,
 			(void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
 
 		if (result) {
 			dev_dbg(&dev->core,
-				"%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+				"%s:%d: ps3_vuart_irq_setup failed (%d)\n",
 				__func__, __LINE__, result);
 			result = -EPERM;
 			goto fail_alloc_irq;
@@ -945,7 +937,7 @@ static int ps3_vuart_probe(struct device
 fail_probe:
 	ps3_vuart_set_interrupt_mask(dev, 0);
 fail_request_irq:
-	ps3_free_vuart_irq(vuart_bus_priv.virq);
+	ps3_vuart_irq_destroy(vuart_bus_priv.virq);
 	vuart_bus_priv.virq = NO_IRQ;
 fail_alloc_irq:
 	--vuart_bus_priv.use_count;
@@ -983,7 +975,7 @@ static int ps3_vuart_remove(struct devic
 	if (--vuart_bus_priv.use_count == 0) {
 		BUG();
 		free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
-		ps3_free_vuart_irq(vuart_bus_priv.virq);
+		ps3_vuart_irq_destroy(vuart_bus_priv.virq);
 		vuart_bus_priv.virq = NO_IRQ;
 	}
 
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 95826b9..5e43983 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -21,21 +21,31 @@ config RTC_CLASS
 	  will be called rtc-class.
 
 config RTC_HCTOSYS
-	bool "Set system time from RTC on startup"
+	bool "Set system time from RTC on startup and resume"
 	depends on RTC_CLASS = y
 	default y
 	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 fsck runs.
+	  If you say yes here, the system time (wall clock) will be set using
+	  the value read from a specified RTC device. This is useful to avoid
+	  unnecessary fsck runs at boot time, and to network better.
 
 config RTC_HCTOSYS_DEVICE
-	string "The RTC to read the time from"
+	string "RTC used to set the system time"
 	depends on RTC_HCTOSYS = y
 	default "rtc0"
 	help
-	  The RTC device that will be used as the source for
-	  the system time, usually rtc0.
+	  The RTC device that will be used to (re)initialize the system
+	  clock, usually rtc0.  Initialization is done when the system
+	  starts up, and when it resumes from a low power state.
+
+	  This clock should be battery-backed, so that it reads the correct
+	  time when the system boots from a power-off state.  Otherwise, your
+	  system will need an external clock source (like an NTP server).
+
+	  If the clock you specify here is not battery backed, it may still
+	  be useful to reinitialize system time when resuming from system
+	  sleep states.  Do not specify an RTC here unless it stays powered
+	  during all this system's supported sleep states.
 
 config RTC_DEBUG
 	bool "RTC debug support"
@@ -48,7 +58,7 @@ comment "RTC interfaces"
 	depends on RTC_CLASS
 
 config RTC_INTF_SYSFS
-	tristate "sysfs"
+	boolean "sysfs"
 	depends on RTC_CLASS && SYSFS
 	default RTC_CLASS
 	help
@@ -59,7 +69,7 @@ config RTC_INTF_SYSFS
 	  will be called rtc-sysfs.
 
 config RTC_INTF_PROC
-	tristate "proc"
+	boolean "proc"
 	depends on RTC_CLASS && PROC_FS
 	default RTC_CLASS
 	help
@@ -71,7 +81,7 @@ config RTC_INTF_PROC
 	  will be called rtc-proc.
 
 config RTC_INTF_DEV
-	tristate "dev"
+	boolean "dev"
 	depends on RTC_CLASS
 	default RTC_CLASS
 	help
@@ -92,44 +102,26 @@ config RTC_INTF_DEV_UIE_EMUL
 	  driver does not expose RTC_UIE ioctls.  Those requests generate
 	  once-per-second update interrupts, used for synchronization.
 
-comment "RTC drivers"
+config RTC_DRV_TEST
+	tristate "Test driver/device"
 	depends on RTC_CLASS
-
-# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
-# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
-# global rtc_lock ... it's not yet just another platform_device.
-
-config RTC_DRV_CMOS
-	tristate "PC-style 'CMOS' real time clock"
-	depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
-		|| M32R || ATARI || POWERPC)
-	help
-	  Say "yes" here to get direct support for the real time clock
-	  found in every PC or ACPI-based system, and some other boards.
-	  Specifically the original MC146818, compatibles like those in
-	  PC south bridges, the DS12887 or M48T86, some multifunction
-	  or LPC bus chips, and so on.
-
-	  Your system will need to define the platform device used by
-	  this driver, otherwise it won't be accessible.  This means
-	  you can safely enable this driver if you don't know whether
-	  or not your board has this kind of hardware.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called rtc-cmos.
-
-config RTC_DRV_X1205
-	tristate "Xicor/Intersil X1205"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
-	  Xicor/Intersil X1205 RTC chip.
+	  RTC test driver. It's a software RTC which can be
+	  used to test the RTC subsystem APIs. It gets
+	  the time from the system clock.
+	  You want this driver only if you are doing development
+	  on the RTC subsystem. Please read the source code
+	  for further details.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-x1205.
+	  will be called rtc-test.
+
+comment "I2C RTC drivers"
+	depends on RTC_CLASS
 
 config RTC_DRV_DS1307
-	tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
 	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for various compatible RTC
@@ -146,53 +138,55 @@ config RTC_DRV_DS1307
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1307.
 
-config RTC_DRV_DS1553
-	tristate "Dallas DS1553"
-	depends on RTC_CLASS
+config RTC_DRV_DS1672
+	tristate "Dallas/Maxim DS1672"
+	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
-	  Dallas DS1553 timekeeping chip.
+	  Dallas/Maxim DS1672 timekeeping chip.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-ds1553.
+	  will be called rtc-ds1672.
 
-config RTC_DRV_ISL1208
-	tristate "Intersil 1208"
+config RTC_DRV_MAX6900
+	tristate "Maxim 6900"
 	depends on RTC_CLASS && I2C
 	help
-	  If you say yes here you get support for the
-	  Intersil 1208 RTC chip.
+	  If you say yes here you will get support for the
+	  Maxim MAX6900 I2C RTC chip.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-isl1208.
+	  will be called rtc-max6900.
 
-config RTC_DRV_DS1672
-	tristate "Dallas/Maxim DS1672"
+config RTC_DRV_RS5C372
+	tristate "Ricoh RS5C372A/B"
 	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
-	  Dallas/Maxim DS1672 timekeeping chip.
+	  Ricoh RS5C372A and RS5C372B RTC chips.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-ds1672.
+	  will be called rtc-rs5c372.
 
-config RTC_DRV_DS1742
-	tristate "Dallas DS1742/1743"
-	depends on RTC_CLASS
+config RTC_DRV_ISL1208
+	tristate "Intersil 1208"
+	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
-	  Dallas DS1742/1743 timekeeping chip.
+	  Intersil 1208 RTC chip.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-ds1742.
+	  will be called rtc-isl1208.
 
-config RTC_DRV_OMAP
-	tristate "TI OMAP1"
-	depends on RTC_CLASS && ( \
-		ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+config RTC_DRV_X1205
+	tristate "Xicor/Intersil X1205"
+	depends on RTC_CLASS && I2C
 	help
-	  Say "yes" here to support the real time clock on TI OMAP1 chips.
-	  This driver can also be built as a module called rtc-omap.
+	  If you say yes here you get support for the
+	  Xicor/Intersil X1205 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-x1205.
 
 config RTC_DRV_PCF8563
 	tristate "Philips PCF8563/Epson RTC8564"
@@ -207,16 +201,20 @@ config RTC_DRV_PCF8563
 
 config RTC_DRV_PCF8583
 	tristate "Philips PCF8583"
-	depends on RTC_CLASS && I2C && ARCH_RPC
+	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the Philips PCF8583
-	  RTC chip found on Acorn RiscPCs.  This driver supports the
+	  RTC chip found on Acorn RiscPCs. This driver supports the
 	  platform specific method of retrieving the current year from
-	  the RTC's SRAM.
+	  the RTC's SRAM. It will work on other platforms with the same
+	  chip, but the year will probably have to be tweaked.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-pcf8583.
 
+comment "SPI RTC drivers"
+	depends on RTC_CLASS
+
 config RTC_DRV_RS5C348
 	tristate "Ricoh RS5C348A/B"
 	depends on RTC_CLASS && SPI
@@ -227,15 +225,92 @@ config RTC_DRV_RS5C348
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-rs5c348.
 
-config RTC_DRV_RS5C372
-	tristate "Ricoh RS5C372A/B"
-	depends on RTC_CLASS && I2C
+config RTC_DRV_MAX6902
+	tristate "Maxim 6902"
+	depends on RTC_CLASS && SPI
+	help
+	  If you say yes here you will get support for the
+	  Maxim MAX6902 SPI RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max6902.
+
+comment "Platform RTC drivers"
+	depends on RTC_CLASS
+
+# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
+# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# global rtc_lock ... it's not yet just another platform_device.
+
+config RTC_DRV_CMOS
+	tristate "PC-style 'CMOS'"
+	depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
+		|| M32R || ATARI || POWERPC)
+	help
+	  Say "yes" here to get direct support for the real time clock
+	  found in every PC or ACPI-based system, and some other boards.
+	  Specifically the original MC146818, compatibles like those in
+	  PC south bridges, the DS12887 or M48T86, some multifunction
+	  or LPC bus chips, and so on.
+
+	  Your system will need to define the platform device used by
+	  this driver, otherwise it won't be accessible.  This means
+	  you can safely enable this driver if you don't know whether
+	  or not your board has this kind of hardware.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-cmos.
+
+config RTC_DRV_DS1553
+	tristate "Dallas DS1553"
+	depends on RTC_CLASS
 	help
 	  If you say yes here you get support for the
-	  Ricoh RS5C372A and RS5C372B RTC chips.
+	  Dallas DS1553 timekeeping chip.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-rs5c372.
+	  will be called rtc-ds1553.
+
+config RTC_DRV_DS1742
+	tristate "Dallas DS1742/1743"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Dallas DS1742/1743 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1742.
+
+config RTC_DRV_M48T86
+	tristate "ST M48T86/Dallas DS12887"
+	depends on RTC_CLASS
+	help
+	  If you say Y here you will get support for the
+	  ST M48T86 and Dallas DS12887 RTC chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-m48t86.
+
+config RTC_DRV_V3020
+	tristate "EM Microelectronic V3020"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you will get support for the
+	  EM Microelectronic v3020 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-v3020.
+
+comment "on-CPU RTC drivers"
+	depends on RTC_CLASS
+
+config RTC_DRV_OMAP
+	tristate "TI OMAP1"
+	depends on RTC_CLASS && ( \
+		ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+	help
+	  Say "yes" here to support the real time clock on TI OMAP1 chips.
+	  This driver can also be built as a module called rtc-omap.
 
 config RTC_DRV_S3C
 	tristate "Samsung S3C series SoC RTC"
@@ -253,16 +328,6 @@ config RTC_DRV_S3C
 	  This driver can also be build as a module. If so, the module
 	  will be called rtc-s3c.
 
-config RTC_DRV_M48T86
-	tristate "ST M48T86/Dallas DS12887"
-	depends on RTC_CLASS
-	help
-	  If you say Y here you will get support for the
-	  ST M48T86 and Dallas DS12887 RTC chips.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called rtc-m48t86.
-
 config RTC_DRV_EP93XX
 	tristate "Cirrus Logic EP93XX"
 	depends on RTC_CLASS && ARCH_EP93XX
@@ -308,7 +373,7 @@ config RTC_DRV_PL031
 	depends on RTC_CLASS && ARM_AMBA
 	help
 	  If you say Y here you will get access to ARM AMBA
-	  PrimeCell PL031 UART found on certain ARM SOCs.
+	  PrimeCell PL031 RTC found on certain ARM SOCs.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called rtc-pl031.
@@ -319,39 +384,20 @@ config RTC_DRV_AT91RM9200
 	help
 	  Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
 
-config RTC_DRV_TEST
-	tristate "Test driver/device"
-	depends on RTC_CLASS
-	help
-	  If you say yes here you get support for the
-	  RTC test driver. It's a software RTC which can be
-	  used to test the RTC subsystem APIs. It gets
-	  the time from the system clock.
-	  You want this driver only if you are doing development
-	  on the RTC subsystem. Please read the source code
-	  for further details.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called rtc-test.
-
-config RTC_DRV_MAX6902
-	tristate "Maxim 6902"
-	depends on RTC_CLASS && SPI
+config RTC_DRV_BFIN
+	tristate "Blackfin On-Chip RTC"
+	depends on RTC_CLASS && BFIN
 	help
 	  If you say yes here you will get support for the
-	  Maxim MAX6902 spi RTC chip.
+	  Blackfin On-Chip Real Time Clock.
 
 	  This driver can also be built as a module. If so, the module
-	  will be called rtc-max6902.
+	  will be called rtc-bfin.
 
-config RTC_DRV_V3020
-	tristate "EM Microelectronic V3020"
-	depends on RTC_CLASS
+config RTC_DRV_RS5C313
+	tristate "Ricoh RS5C313"
+	depends on RTC_CLASS && BROKEN
 	help
-	  If you say yes here you will get support for the
-	  EM Microelectronic v3020 RTC chip.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called rtc-v3020.
+	  If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
 endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 92bfe1b..a1afbc2 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -11,9 +11,9 @@ obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
 obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
 rtc-core-y			:= class.o interface.o
 
-obj-$(CONFIG_RTC_INTF_SYSFS)	+= rtc-sysfs.o
-obj-$(CONFIG_RTC_INTF_PROC)	+= rtc-proc.o
-obj-$(CONFIG_RTC_INTF_DEV)	+= rtc-dev.o
+rtc-core-$(CONFIG_RTC_INTF_DEV)	+= rtc-dev.o
+rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
+rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
@@ -30,11 +30,14 @@ obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o
 obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
 obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
+obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o
+obj-$(CONFIG_RTC_DRV_BFIN)	+= rtc-bfin.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 04aaa63..8b3cd31 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -16,19 +16,94 @@ #include <linux/rtc.h>
 #include <linux/kdev_t.h>
 #include <linux/idr.h>
 
+#include "rtc-core.h"
+
+
 static DEFINE_IDR(rtc_idr);
 static DEFINE_MUTEX(idr_lock);
 struct class *rtc_class;
 
-static void rtc_device_release(struct class_device *class_dev)
+static void rtc_device_release(struct device *dev)
 {
-	struct rtc_device *rtc = to_rtc_device(class_dev);
+	struct rtc_device *rtc = to_rtc_device(dev);
 	mutex_lock(&idr_lock);
 	idr_remove(&rtc_idr, rtc->id);
 	mutex_unlock(&idr_lock);
 	kfree(rtc);
 }
 
+#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
+
+/*
+ * On suspend(), measure the delta between one RTC and the
+ * system's wall clock; restore it on resume().
+ */
+
+static struct timespec	delta;
+static time_t		oldtime;
+
+static int rtc_suspend(struct device *dev, pm_message_t mesg)
+{
+	struct rtc_device	*rtc = to_rtc_device(dev);
+	struct rtc_time		tm;
+
+	if (strncmp(rtc->dev.bus_id,
+				CONFIG_RTC_HCTOSYS_DEVICE,
+				BUS_ID_SIZE) != 0)
+		return 0;
+
+	rtc_read_time(rtc, &tm);
+	rtc_tm_to_time(&tm, &oldtime);
+
+	/* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
+	set_normalized_timespec(&delta,
+				xtime.tv_sec - oldtime,
+				xtime.tv_nsec - (NSEC_PER_SEC >> 1));
+
+	return 0;
+}
+
+static int rtc_resume(struct device *dev)
+{
+	struct rtc_device	*rtc = to_rtc_device(dev);
+	struct rtc_time		tm;
+	time_t			newtime;
+	struct timespec		time;
+
+	if (strncmp(rtc->dev.bus_id,
+				CONFIG_RTC_HCTOSYS_DEVICE,
+				BUS_ID_SIZE) != 0)
+		return 0;
+
+	rtc_read_time(rtc, &tm);
+	if (rtc_valid_tm(&tm) != 0) {
+		pr_debug("%s:  bogus resume time\n", rtc->dev.bus_id);
+		return 0;
+	}
+	rtc_tm_to_time(&tm, &newtime);
+	if (newtime <= oldtime) {
+		if (newtime < oldtime)
+			pr_debug("%s:  time travel!\n", rtc->dev.bus_id);
+		return 0;
+	}
+
+	/* restore wall clock using delta against this RTC;
+	 * adjust again for avg 1/2 second RTC sampling error
+	 */
+	set_normalized_timespec(&time,
+				newtime + delta.tv_sec,
+				(NSEC_PER_SEC >> 1) + delta.tv_nsec);
+	do_settimeofday(&time);
+
+	return 0;
+}
+
+#else
+#define rtc_suspend	NULL
+#define rtc_resume	NULL
+#endif
+
+
 /**
  * rtc_device_register - register w/ RTC class
  * @dev: the device to register
@@ -70,23 +145,29 @@ struct rtc_device *rtc_device_register(c
 	rtc->ops = ops;
 	rtc->owner = owner;
 	rtc->max_user_freq = 64;
-	rtc->class_dev.dev = dev;
-	rtc->class_dev.class = rtc_class;
-	rtc->class_dev.release = rtc_device_release;
+	rtc->dev.parent = dev;
+	rtc->dev.class = rtc_class;
+	rtc->dev.release = rtc_device_release;
 
 	mutex_init(&rtc->ops_lock);
 	spin_lock_init(&rtc->irq_lock);
 	spin_lock_init(&rtc->irq_task_lock);
 
 	strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
-	snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
+	snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);
 
-	err = class_device_register(&rtc->class_dev);
+	rtc_dev_prepare(rtc);
+
+	err = device_register(&rtc->dev);
 	if (err)
 		goto exit_kfree;
 
+	rtc_dev_add_device(rtc);
+	rtc_sysfs_add_device(rtc);
+	rtc_proc_add_device(rtc);
+
 	dev_info(dev, "rtc core: registered %s as %s\n",
-			rtc->name, rtc->class_dev.class_id);
+			rtc->name, rtc->dev.bus_id);
 
 	return rtc;
 
@@ -113,26 +194,22 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
  */
 void rtc_device_unregister(struct rtc_device *rtc)
 {
-	if (class_device_get(&rtc->class_dev) != NULL) {
+	if (get_device(&rtc->dev) != NULL) {
 		mutex_lock(&rtc->ops_lock);
 		/* remove innards of this RTC, then disable it, before
 		 * letting any rtc_class_open() users access it again
 		 */
-		class_device_unregister(&rtc->class_dev);
+		rtc_sysfs_del_device(rtc);
+		rtc_dev_del_device(rtc);
+		rtc_proc_del_device(rtc);
+		device_unregister(&rtc->dev);
 		rtc->ops = NULL;
 		mutex_unlock(&rtc->ops_lock);
-		class_device_put(&rtc->class_dev);
+		put_device(&rtc->dev);
 	}
 }
 EXPORT_SYMBOL_GPL(rtc_device_unregister);
 
-int rtc_interface_register(struct class_interface *intf)
-{
-	intf->class = rtc_class;
-	return class_interface_register(intf);
-}
-EXPORT_SYMBOL_GPL(rtc_interface_register);
-
 static int __init rtc_init(void)
 {
 	rtc_class = class_create(THIS_MODULE, "rtc");
@@ -140,11 +217,16 @@ static int __init rtc_init(void)
 		printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
 		return PTR_ERR(rtc_class);
 	}
+	rtc_class->suspend = rtc_suspend;
+	rtc_class->resume = rtc_resume;
+	rtc_dev_init();
+	rtc_sysfs_init(rtc_class);
 	return 0;
 }
 
 static void __exit rtc_exit(void)
 {
+	rtc_dev_exit();
 	class_destroy(rtc_class);
 }
 
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index d02fe9a..1785272 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -26,15 +26,15 @@ static int __init rtc_hctosys(void)
 {
 	int err;
 	struct rtc_time tm;
-	struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+	struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
 
-	if (class_dev == NULL) {
+	if (rtc == NULL) {
 		printk("%s: unable to open rtc device (%s)\n",
 			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
 		return -ENODEV;
 	}
 
-	err = rtc_read_time(class_dev, &tm);
+	err = rtc_read_time(rtc, &tm);
 	if (err == 0) {
 		err = rtc_valid_tm(&tm);
 		if (err == 0) {
@@ -46,7 +46,7 @@ static int __init rtc_hctosys(void)
 
 			do_settimeofday(&tv);
 
-			dev_info(class_dev->dev,
+			dev_info(rtc->dev.parent,
 				"setting the system clock to "
 				"%d-%02d-%02d %02d:%02d:%02d (%u)\n",
 				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
@@ -54,14 +54,14 @@ static int __init rtc_hctosys(void)
 				(unsigned int) tv.tv_sec);
 		}
 		else
-			dev_err(class_dev->dev,
+			dev_err(rtc->dev.parent,
 				"hctosys: invalid date/time\n");
 	}
 	else
-		dev_err(class_dev->dev,
+		dev_err(rtc->dev.parent,
 			"hctosys: unable to read the hardware clock\n");
 
-	rtc_class_close(class_dev);
+	rtc_class_close(rtc);
 
 	return 0;
 }
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index ef40df0..ad66c6e 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -13,10 +13,9 @@
 
 #include <linux/rtc.h>
 
-int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
+int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 {
 	int err;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
@@ -28,7 +27,7 @@ int rtc_read_time(struct class_device *c
 		err = -EINVAL;
 	else {
 		memset(tm, 0, sizeof(struct rtc_time));
-		err = rtc->ops->read_time(class_dev->dev, tm);
+		err = rtc->ops->read_time(rtc->dev.parent, tm);
 	}
 
 	mutex_unlock(&rtc->ops_lock);
@@ -36,10 +35,9 @@ int rtc_read_time(struct class_device *c
 }
 EXPORT_SYMBOL_GPL(rtc_read_time);
 
-int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
+int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 {
 	int err;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	err = rtc_valid_tm(tm);
 	if (err != 0)
@@ -54,17 +52,16 @@ int rtc_set_time(struct class_device *cl
 	else if (!rtc->ops->set_time)
 		err = -EINVAL;
 	else
-		err = rtc->ops->set_time(class_dev->dev, tm);
+		err = rtc->ops->set_time(rtc->dev.parent, tm);
 
 	mutex_unlock(&rtc->ops_lock);
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_set_time);
 
-int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
+int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
 {
 	int err;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
@@ -73,11 +70,11 @@ int rtc_set_mmss(struct class_device *cl
 	if (!rtc->ops)
 		err = -ENODEV;
 	else if (rtc->ops->set_mmss)
-		err = rtc->ops->set_mmss(class_dev->dev, secs);
+		err = rtc->ops->set_mmss(rtc->dev.parent, secs);
 	else if (rtc->ops->read_time && rtc->ops->set_time) {
 		struct rtc_time new, old;
 
-		err = rtc->ops->read_time(class_dev->dev, &old);
+		err = rtc->ops->read_time(rtc->dev.parent, &old);
 		if (err == 0) {
 			rtc_time_to_tm(secs, &new);
 
@@ -89,7 +86,8 @@ int rtc_set_mmss(struct class_device *cl
 			 */
 			if (!((old.tm_hour == 23 && old.tm_min == 59) ||
 				(new.tm_hour == 23 && new.tm_min == 59)))
-				err = rtc->ops->set_time(class_dev->dev, &new);
+				err = rtc->ops->set_time(rtc->dev.parent,
+						&new);
 		}
 	}
 	else
@@ -101,10 +99,9 @@ int rtc_set_mmss(struct class_device *cl
 }
 EXPORT_SYMBOL_GPL(rtc_set_mmss);
 
-int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 {
 	int err;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
@@ -116,7 +113,7 @@ int rtc_read_alarm(struct class_device *
 		err = -EINVAL;
 	else {
 		memset(alarm, 0, sizeof(struct rtc_wkalrm));
-		err = rtc->ops->read_alarm(class_dev->dev, alarm);
+		err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
 	}
 
 	mutex_unlock(&rtc->ops_lock);
@@ -124,10 +121,13 @@ int rtc_read_alarm(struct class_device *
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
 
-int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 {
 	int err;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = rtc_valid_tm(&alarm->time);
+	if (err != 0)
+		return err;
 
 	err = mutex_lock_interruptible(&rtc->ops_lock);
 	if (err)
@@ -138,7 +138,7 @@ int rtc_set_alarm(struct class_device *c
 	else if (!rtc->ops->set_alarm)
 		err = -EINVAL;
 	else
-		err = rtc->ops->set_alarm(class_dev->dev, alarm);
+		err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
 
 	mutex_unlock(&rtc->ops_lock);
 	return err;
@@ -147,16 +147,14 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm);
 
 /**
  * rtc_update_irq - report RTC periodic, alarm, and/or update irqs
- * @class_dev: the rtc's class device
+ * @rtc: the rtc device
  * @num: how many irqs are being reported (usually one)
  * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
  * Context: in_interrupt(), irqs blocked
  */
-void rtc_update_irq(struct class_device *class_dev,
+void rtc_update_irq(struct rtc_device *rtc,
 		unsigned long num, unsigned long events)
 {
-	struct rtc_device *rtc = to_rtc_device(class_dev);
-
 	spin_lock(&rtc->irq_lock);
 	rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
 	spin_unlock(&rtc->irq_lock);
@@ -171,40 +169,43 @@ void rtc_update_irq(struct class_device 
 }
 EXPORT_SYMBOL_GPL(rtc_update_irq);
 
-struct class_device *rtc_class_open(char *name)
+struct rtc_device *rtc_class_open(char *name)
 {
-	struct class_device *class_dev = NULL,
-				*class_dev_tmp;
+	struct device *dev;
+	struct rtc_device *rtc = NULL;
 
 	down(&rtc_class->sem);
-	list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
-		if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
-			class_dev = class_device_get(class_dev_tmp);
+	list_for_each_entry(dev, &rtc_class->devices, node) {
+		if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
+			dev = get_device(dev);
+			if (dev)
+				rtc = to_rtc_device(dev);
 			break;
 		}
 	}
 
-	if (class_dev) {
-		if (!try_module_get(to_rtc_device(class_dev)->owner))
-			class_dev = NULL;
+	if (rtc) {
+		if (!try_module_get(rtc->owner)) {
+			put_device(dev);
+			rtc = NULL;
+		}
 	}
 	up(&rtc_class->sem);
 
-	return class_dev;
+	return rtc;
 }
 EXPORT_SYMBOL_GPL(rtc_class_open);
 
-void rtc_class_close(struct class_device *class_dev)
+void rtc_class_close(struct rtc_device *rtc)
 {
-	module_put(to_rtc_device(class_dev)->owner);
-	class_device_put(class_dev);
+	module_put(rtc->owner);
+	put_device(&rtc->dev);
 }
 EXPORT_SYMBOL_GPL(rtc_class_close);
 
-int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
 {
 	int retval = -EBUSY;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	if (task == NULL || task->func == NULL)
 		return -EINVAL;
@@ -220,9 +221,8 @@ int rtc_irq_register(struct class_device
 }
 EXPORT_SYMBOL_GPL(rtc_irq_register);
 
-void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
+void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
 {
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	spin_lock_irq(&rtc->irq_task_lock);
 	if (rtc->irq_task == task)
@@ -231,11 +231,10 @@ void rtc_irq_unregister(struct class_dev
 }
 EXPORT_SYMBOL_GPL(rtc_irq_unregister);
 
-int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
+int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
 {
 	int err = 0;
 	unsigned long flags;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	if (rtc->ops->irq_set_state == NULL)
 		return -ENXIO;
@@ -246,17 +245,16 @@ int rtc_irq_set_state(struct class_devic
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
 
 	if (err == 0)
-		err = rtc->ops->irq_set_state(class_dev->dev, enabled);
+		err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
 
 	return err;
 }
 EXPORT_SYMBOL_GPL(rtc_irq_set_state);
 
-int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
+int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
 {
 	int err = 0;
 	unsigned long flags;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
 
 	if (rtc->ops->irq_set_freq == NULL)
 		return -ENXIO;
@@ -267,7 +265,7 @@ int rtc_irq_set_freq(struct class_device
 	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
 
 	if (err == 0) {
-		err = rtc->ops->irq_set_freq(class_dev->dev, freq);
+		err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
 		if (err == 0)
 			rtc->irq_freq = freq;
 	}
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index ac0e68e..33795e5 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -263,7 +263,7 @@ static irqreturn_t at91_rtc_interrupt(in
 
 		at91_sys_write(AT91_RTC_SCCR, rtsr);	/* clear status reg */
 
-		rtc_update_irq(&rtc->class_dev, 1, events);
+		rtc_update_irq(rtc, 1, events);
 
 		pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
 			events >> 8, events & 0x000000FF);
@@ -348,21 +348,10 @@ #ifdef CONFIG_PM
 
 /* 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)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
-	/* calculate time delta for suspend */
-	at91_rtc_readtime(&pdev->dev, &tm);
-	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...
 	 */
@@ -374,36 +363,17 @@ static int at91_rtc_suspend(struct platf
 		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);
-
 	return 0;
 }
 
 static int at91_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
-	at91_rtc_readtime(&pdev->dev, &tm);
-	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);
-
 	return 0;
 }
 #else
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
new file mode 100644
index 0000000..260ead9
--- /dev/null
+++ b/drivers/rtc/rtc-bfin.c
@@ -0,0 +1,445 @@
+/*
+ * Blackfin On-Chip Real Time Clock Driver
+ *  Supports BF531/BF532/BF533/BF534/BF536/BF537
+ *
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* The biggest issue we deal with in this driver is that register writes are
+ * synced to the RTC frequency of 1Hz.  So if you write to a register and
+ * attempt to write again before the first write has completed, the new write
+ * is simply discarded.  This can easily be troublesome if userspace disables
+ * one event (say periodic) and then right after enables an event (say alarm).
+ * Since all events are maintained in the same interrupt mask register, if
+ * we wrote to it to disable the first event and then wrote to it again to
+ * enable the second event, that second event would not be enabled as the
+ * write would be discarded and things quickly fall apart.
+ *
+ * To keep this delay from significantly degrading performance (we, in theory,
+ * would have to sleep for up to 1 second everytime we wanted to write a
+ * register), we only check the write pending status before we start to issue
+ * a new write.  We bank on the idea that it doesnt matter when the sync
+ * happens so long as we don't attempt another write before it does.  The only
+ * time userspace would take this penalty is when they try and do multiple
+ * operations right after another ... but in this case, they need to take the
+ * sync penalty, so we should be OK.
+ *
+ * Also note that the RTC_ISTAT register does not suffer this penalty; its
+ * writes to clear status registers complete immediately.
+ */
+
+#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 <linux/delay.h>
+
+#include <asm/blackfin.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+
+struct bfin_rtc {
+	struct rtc_device *rtc_dev;
+	struct rtc_time rtc_alarm;
+	spinlock_t lock;
+};
+
+/* Bit values for the ISTAT / ICTL registers */
+#define RTC_ISTAT_WRITE_COMPLETE  0x8000
+#define RTC_ISTAT_WRITE_PENDING   0x4000
+#define RTC_ISTAT_ALARM_DAY       0x0040
+#define RTC_ISTAT_24HR            0x0020
+#define RTC_ISTAT_HOUR            0x0010
+#define RTC_ISTAT_MIN             0x0008
+#define RTC_ISTAT_SEC             0x0004
+#define RTC_ISTAT_ALARM           0x0002
+#define RTC_ISTAT_STOPWATCH       0x0001
+
+/* Shift values for RTC_STAT register */
+#define DAY_BITS_OFF    17
+#define HOUR_BITS_OFF   12
+#define MIN_BITS_OFF    6
+#define SEC_BITS_OFF    0
+
+/* Some helper functions to convert between the common RTC notion of time
+ * and the internal Blackfin notion that is stored in 32bits.
+ */
+static inline u32 rtc_time_to_bfin(unsigned long now)
+{
+	u32 sec  = (now % 60);
+	u32 min  = (now % (60 * 60)) / 60;
+	u32 hour = (now % (60 * 60 * 24)) / (60 * 60);
+	u32 days = (now / (60 * 60 * 24));
+	return (sec  << SEC_BITS_OFF) +
+	       (min  << MIN_BITS_OFF) +
+	       (hour << HOUR_BITS_OFF) +
+	       (days << DAY_BITS_OFF);
+}
+static inline unsigned long rtc_bfin_to_time(u32 rtc_bfin)
+{
+	return (((rtc_bfin >> SEC_BITS_OFF)  & 0x003F)) +
+	       (((rtc_bfin >> MIN_BITS_OFF)  & 0x003F) * 60) +
+	       (((rtc_bfin >> HOUR_BITS_OFF) & 0x001F) * 60 * 60) +
+	       (((rtc_bfin >> DAY_BITS_OFF)  & 0x7FFF) * 60 * 60 * 24);
+}
+static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
+{
+	rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
+}
+
+/* Wait for the previous write to a RTC register to complete.
+ * Unfortunately, we can't sleep here as that introduces a race condition when
+ * turning on interrupt events.  Consider this:
+ *  - process sets alarm
+ *  - process enables alarm
+ *  - process sleeps while waiting for rtc write to sync
+ *  - interrupt fires while process is sleeping
+ *  - interrupt acks the event by writing to ISTAT
+ *  - interrupt sets the WRITE PENDING bit
+ *  - interrupt handler finishes
+ *  - process wakes up, sees WRITE PENDING bit set, goes to sleep
+ *  - interrupt fires while process is sleeping
+ * If anyone can point out the obvious solution here, i'm listening :).  This
+ * shouldn't be an issue on an SMP or preempt system as this function should
+ * only be called with the rtc lock held.
+ */
+static void rtc_bfin_sync_pending(void)
+{
+	stampit();
+	while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+		if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
+			break;
+	}
+	bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+}
+
+static void rtc_bfin_reset(struct bfin_rtc *rtc)
+{
+	/* Initialize the RTC. Enable pre-scaler to scale RTC clock
+	 * to 1Hz and clear interrupt/status registers. */
+	spin_lock_irq(&rtc->lock);
+	rtc_bfin_sync_pending();
+	bfin_write_RTC_PREN(0x1);
+	bfin_write_RTC_ICTL(0);
+	bfin_write_RTC_SWCNT(0);
+	bfin_write_RTC_ALARM(0);
+	bfin_write_RTC_ISTAT(0xFFFF);
+	spin_unlock_irq(&rtc->lock);
+}
+
+static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = to_platform_device(dev_id);
+	struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+	unsigned long events = 0;
+	u16 rtc_istat;
+
+	stampit();
+
+	spin_lock_irq(&rtc->lock);
+
+	rtc_istat = bfin_read_RTC_ISTAT();
+
+	if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+		bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+		events |= RTC_AF | RTC_IRQF;
+	}
+
+	if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+		bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+		events |= RTC_PF | RTC_IRQF;
+		bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+	}
+
+	if (rtc_istat & RTC_ISTAT_SEC) {
+		bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+		events |= RTC_UF | RTC_IRQF;
+	}
+
+	rtc_update_irq(rtc->rtc_dev, 1, events);
+
+	spin_unlock_irq(&rtc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int bfin_rtc_open(struct device *dev)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	int ret;
+
+	stampit();
+
+	ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
+	if (unlikely(ret)) {
+		dev_err(dev, "request RTC IRQ failed with %d\n", ret);
+		return ret;
+	}
+
+	rtc_bfin_reset(rtc);
+
+	return ret;
+}
+
+static void bfin_rtc_release(struct device *dev)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	stampit();
+	rtc_bfin_reset(rtc);
+	free_irq(IRQ_RTC, dev);
+}
+
+static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+
+	stampit();
+
+	switch (cmd) {
+	case RTC_PIE_ON:
+		stampit();
+		spin_lock_irq(&rtc->lock);
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+		bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+		bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
+		spin_unlock_irq(&rtc->lock);
+		return 0;
+	case RTC_PIE_OFF:
+		stampit();
+		spin_lock_irq(&rtc->lock);
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_SWCNT(0);
+		bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
+		spin_unlock_irq(&rtc->lock);
+		return 0;
+
+	case RTC_UIE_ON:
+		stampit();
+		spin_lock_irq(&rtc->lock);
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+		bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
+		spin_unlock_irq(&rtc->lock);
+		return 0;
+	case RTC_UIE_OFF:
+		stampit();
+		spin_lock_irq(&rtc->lock);
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
+		spin_unlock_irq(&rtc->lock);
+		return 0;
+
+	case RTC_AIE_ON: {
+		unsigned long rtc_alarm;
+		u16 which_alarm;
+		int ret = 0;
+
+		stampit();
+
+		spin_lock_irq(&rtc->lock);
+
+		rtc_bfin_sync_pending();
+		if (rtc->rtc_alarm.tm_yday == -1) {
+			struct rtc_time now;
+			rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
+			now.tm_sec = rtc->rtc_alarm.tm_sec;
+			now.tm_min = rtc->rtc_alarm.tm_min;
+			now.tm_hour = rtc->rtc_alarm.tm_hour;
+			ret = rtc_tm_to_time(&now, &rtc_alarm);
+			which_alarm = RTC_ISTAT_ALARM;
+		} else {
+			ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
+			which_alarm = RTC_ISTAT_ALARM_DAY;
+		}
+		if (ret == 0) {
+			bfin_write_RTC_ISTAT(which_alarm);
+			bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+			bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
+		}
+
+		spin_unlock_irq(&rtc->lock);
+
+		return ret;
+	}
+	case RTC_AIE_OFF:
+		stampit();
+		spin_lock_irq(&rtc->lock);
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+		spin_unlock_irq(&rtc->lock);
+		return 0;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+
+	stampit();
+
+	spin_lock_irq(&rtc->lock);
+	rtc_bfin_sync_pending();
+	rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
+	spin_unlock_irq(&rtc->lock);
+
+	return 0;
+}
+
+static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	int ret;
+	unsigned long now;
+
+	stampit();
+
+	spin_lock_irq(&rtc->lock);
+
+	ret = rtc_tm_to_time(tm, &now);
+	if (ret == 0) {
+		rtc_bfin_sync_pending();
+		bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+	}
+
+	spin_unlock_irq(&rtc->lock);
+
+	return ret;
+}
+
+static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	stampit();
+	memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
+	alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+	return 0;
+}
+
+static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	stampit();
+	memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+	return 0;
+}
+
+static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+#define yesno(x) (x ? "yes" : "no")
+	u16 ictl = bfin_read_RTC_ICTL();
+	stampit();
+	seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
+	seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
+	seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
+	seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
+#ifdef DEBUG
+	seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
+	seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
+	seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
+	seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
+	seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
+	seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
+#endif
+	return 0;
+}
+
+static int bfin_irq_set_freq(struct device *dev, int freq)
+{
+	struct bfin_rtc *rtc = dev_get_drvdata(dev);
+	stampit();
+	rtc->rtc_dev->irq_freq = freq;
+	return 0;
+}
+
+static struct rtc_class_ops bfin_rtc_ops = {
+	.open          = bfin_rtc_open,
+	.release       = bfin_rtc_release,
+	.ioctl         = bfin_rtc_ioctl,
+	.read_time     = bfin_rtc_read_time,
+	.set_time      = bfin_rtc_set_time,
+	.read_alarm    = bfin_rtc_read_alarm,
+	.set_alarm     = bfin_rtc_set_alarm,
+	.proc          = bfin_rtc_proc,
+	.irq_set_freq  = bfin_irq_set_freq,
+};
+
+static int __devinit bfin_rtc_probe(struct platform_device *pdev)
+{
+	struct bfin_rtc *rtc;
+	int ret = 0;
+
+	stampit();
+
+	rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+	if (unlikely(!rtc))
+		return -ENOMEM;
+
+	spin_lock_init(&rtc->lock);
+
+	rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
+	if (unlikely(IS_ERR(rtc))) {
+		ret = PTR_ERR(rtc->rtc_dev);
+		goto err;
+	}
+	rtc->rtc_dev->irq_freq = 0;
+	rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+
+	platform_set_drvdata(pdev, rtc);
+
+	return 0;
+
+err:
+	kfree(rtc);
+	return ret;
+}
+
+static int __devexit bfin_rtc_remove(struct platform_device *pdev)
+{
+	struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+
+	rtc_device_unregister(rtc->rtc_dev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(rtc);
+
+	return 0;
+}
+
+static struct platform_driver bfin_rtc_driver = {
+	.driver		= {
+		.name	= "rtc-bfin",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= bfin_rtc_probe,
+	.remove		= __devexit_p(bfin_rtc_remove),
+};
+
+static int __init bfin_rtc_init(void)
+{
+	stampit();
+	return platform_driver_register(&bfin_rtc_driver);
+}
+
+static void __exit bfin_rtc_exit(void)
+{
+	platform_driver_unregister(&bfin_rtc_driver);
+}
+
+module_init(bfin_rtc_init);
+module_exit(bfin_rtc_exit);
+
+MODULE_DESCRIPTION("Blackfin On-Chip Real Time Clock Driver");
+MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 7c0d609..6085261 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -46,6 +46,10 @@ struct cmos_rtc {
 	int			irq;
 	struct resource		*iomem;
 
+	void			(*wake_on)(struct device *);
+	void			(*wake_off)(struct device *);
+
+	u8			enabled_wake;
 	u8			suspend_ctrl;
 
 	/* newer hardware extends the original register set */
@@ -203,7 +207,7 @@ static int cmos_set_alarm(struct device 
 	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
 	rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
 	if (is_intr(rtc_intr))
-		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+		rtc_update_irq(cmos->rtc, 1, rtc_intr);
 
 	/* update alarm */
 	CMOS_WRITE(hrs, RTC_HOURS_ALARM);
@@ -223,7 +227,7 @@ static int cmos_set_alarm(struct device 
 		rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
 		rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
 		if (is_intr(rtc_intr))
-			rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+			rtc_update_irq(cmos->rtc, 1, rtc_intr);
 	}
 
 	spin_unlock_irq(&rtc_lock);
@@ -304,7 +308,7 @@ cmos_rtc_ioctl(struct device *dev, unsig
 	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
 	rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
 	if (is_intr(rtc_intr))
-		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+		rtc_update_irq(cmos->rtc, 1, rtc_intr);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 	return 0;
 }
@@ -379,12 +383,12 @@ static irqreturn_t cmos_interrupt(int ir
 		return IRQ_NONE;
 }
 
-#ifdef	CONFIG_PNPACPI
-#define	is_pnpacpi()	1
+#ifdef	CONFIG_PNP
+#define	is_pnp()	1
 #define	INITSECTION
 
 #else
-#define	is_pnpacpi()	0
+#define	is_pnp()	0
 #define	INITSECTION	__init
 #endif
 
@@ -405,13 +409,20 @@ cmos_do_probe(struct device *dev, struct
 	cmos_rtc.irq = rtc_irq;
 	cmos_rtc.iomem = ports;
 
-	/* For ACPI systems the info comes from the FADT.  On others,
-	 * board specific setup provides it as appropriate.
+	/* For ACPI systems extension info comes from the FADT.  On others,
+	 * board specific setup provides it as appropriate.  Systems where
+	 * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
+	 * some almost-clones) can provide hooks to make that behave.
 	 */
 	if (info) {
 		cmos_rtc.day_alrm = info->rtc_day_alarm;
 		cmos_rtc.mon_alrm = info->rtc_mon_alarm;
 		cmos_rtc.century = info->rtc_century;
+
+		if (info->wake_on && info->wake_off) {
+			cmos_rtc.wake_on = info->wake_on;
+			cmos_rtc.wake_off = info->wake_off;
+		}
 	}
 
 	cmos_rtc.rtc = rtc_device_register(driver_name, dev,
@@ -427,14 +438,14 @@ cmos_do_probe(struct device *dev, struct
 	 * REVISIT for non-x86 systems we may need to handle io memory
 	 * resources: ioremap them, and request_mem_region().
 	 */
-	if (is_pnpacpi()) {
+	if (is_pnp()) {
 		retval = request_resource(&ioport_resource, ports);
 		if (retval < 0) {
 			dev_dbg(dev, "i/o registers already in use\n");
 			goto cleanup0;
 		}
 	}
-	rename_region(ports, cmos_rtc.rtc->class_dev.class_id);
+	rename_region(ports, cmos_rtc.rtc->dev.bus_id);
 
 	spin_lock_irq(&rtc_lock);
 
@@ -470,8 +481,8 @@ cmos_do_probe(struct device *dev, struct
 
 	if (is_valid_irq(rtc_irq))
 		retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
-				cmos_rtc.rtc->class_dev.class_id,
-				&cmos_rtc.rtc->class_dev);
+				cmos_rtc.rtc->dev.bus_id,
+				cmos_rtc.rtc);
 	if (retval < 0) {
 		dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
 		goto cleanup1;
@@ -483,7 +494,7 @@ cmos_do_probe(struct device *dev, struct
 	 */
 
 	pr_info("%s: alarms up to one %s%s\n",
-			cmos_rtc.rtc->class_dev.class_id,
+			cmos_rtc.rtc->dev.bus_id,
 			is_valid_irq(rtc_irq)
 				?  (cmos_rtc.mon_alrm
 					? "year"
@@ -520,12 +531,12 @@ static void __exit cmos_do_remove(struct
 
 	cmos_do_shutdown();
 
-	if (is_pnpacpi())
+	if (is_pnp())
 		release_resource(cmos->iomem);
 	rename_region(cmos->iomem, NULL);
 
 	if (is_valid_irq(cmos->irq))
-		free_irq(cmos->irq, &cmos_rtc.rtc->class_dev);
+		free_irq(cmos->irq, cmos_rtc.rtc);
 
 	rtc_device_unregister(cmos_rtc.rtc);
 
@@ -555,16 +566,20 @@ static int cmos_suspend(struct device *d
 		irqstat = CMOS_READ(RTC_INTR_FLAGS);
 		irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;
 		if (is_intr(irqstat))
-			rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
+			rtc_update_irq(cmos->rtc, 1, irqstat);
 	}
 	spin_unlock_irq(&rtc_lock);
 
-	/* ACPI HOOK:  enable ACPI_EVENT_RTC when (tmp & RTC_AIE)
-	 * ... it'd be best if we could do that under rtc_lock.
-	 */
+	if (tmp & RTC_AIE) {
+		cmos->enabled_wake = 1;
+		if (cmos->wake_on)
+			cmos->wake_on(dev);
+		else
+			enable_irq_wake(cmos->irq);
+	}
 
 	pr_debug("%s: suspend%s, ctrl %02x\n",
-			cmos_rtc.rtc->class_dev.class_id,
+			cmos_rtc.rtc->dev.bus_id,
 			(tmp & RTC_AIE) ? ", alarm may wake" : "",
 			tmp);
 
@@ -576,26 +591,28 @@ static int cmos_resume(struct device *de
 	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
 	unsigned char	tmp = cmos->suspend_ctrl;
 
-	/* REVISIT:  a mechanism to resync the system clock (jiffies)
-	 * on resume should be portable between platforms ...
-	 */
-
 	/* re-enable any irqs previously active */
 	if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
 
-		/* ACPI HOOK:  disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */
+		if (cmos->enabled_wake) {
+			if (cmos->wake_off)
+				cmos->wake_off(dev);
+			else
+				disable_irq_wake(cmos->irq);
+			cmos->enabled_wake = 0;
+		}
 
 		spin_lock_irq(&rtc_lock);
 		CMOS_WRITE(tmp, RTC_CONTROL);
 		tmp = CMOS_READ(RTC_INTR_FLAGS);
 		tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
 		if (is_intr(tmp))
-			rtc_update_irq(&cmos->rtc->class_dev, 1, tmp);
+			rtc_update_irq(cmos->rtc, 1, tmp);
 		spin_unlock_irq(&rtc_lock);
 	}
 
 	pr_debug("%s: resume, ctrl %02x\n",
-			cmos_rtc.rtc->class_dev.class_id,
+			cmos_rtc.rtc->dev.bus_id,
 			cmos->suspend_ctrl);
 
 
@@ -613,7 +630,7 @@ #endif
  * the device node will always be created as a PNPACPI device.
  */
 
-#ifdef	CONFIG_PNPACPI
+#ifdef	CONFIG_PNP
 
 #include <linux/pnp.h>
 
@@ -684,11 +701,11 @@ static void __exit cmos_exit(void)
 }
 module_exit(cmos_exit);
 
-#else	/* no PNPACPI */
+#else	/* no PNP */
 
 /*----------------------------------------------------------------*/
 
-/* Platform setup should have set up an RTC device, when PNPACPI is
+/* Platform setup should have set up an RTC device, when PNP is
  * unavailable ... this could happen even on (older) PCs.
  */
 
@@ -734,7 +751,7 @@ static void __exit cmos_exit(void)
 module_exit(cmos_exit);
 
 
-#endif	/* !PNPACPI */
+#endif	/* !PNP */
 
 MODULE_AUTHOR("David Brownell");
 MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h
new file mode 100644
index 0000000..5f9df74
--- /dev/null
+++ b/drivers/rtc/rtc-core.h
@@ -0,0 +1,70 @@
+#ifdef CONFIG_RTC_INTF_DEV
+
+extern void __init rtc_dev_init(void);
+extern void __exit rtc_dev_exit(void);
+extern void rtc_dev_prepare(struct rtc_device *rtc);
+extern void rtc_dev_add_device(struct rtc_device *rtc);
+extern void rtc_dev_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_dev_init(void)
+{
+}
+
+static inline void rtc_dev_exit(void)
+{
+}
+
+static inline void rtc_dev_prepare(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_dev_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_dev_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_RTC_INTF_PROC
+
+extern void rtc_proc_add_device(struct rtc_device *rtc);
+extern void rtc_proc_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_proc_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_proc_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_RTC_INTF_SYSFS
+
+extern void __init rtc_sysfs_init(struct class *);
+extern void rtc_sysfs_add_device(struct rtc_device *rtc);
+extern void rtc_sysfs_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_sysfs_init(struct class *rtc)
+{
+}
+
+static inline void rtc_sysfs_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_sysfs_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 137330b..f4e5f00 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -13,8 +13,8 @@
 
 #include <linux/module.h>
 #include <linux/rtc.h>
+#include "rtc-core.h"
 
-static struct class *rtc_dev_class;
 static dev_t rtc_devt;
 
 #define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
@@ -32,9 +32,9 @@ static int rtc_dev_open(struct inode *in
 	if (!(mutex_trylock(&rtc->char_lock)))
 		return -EBUSY;
 
-	file->private_data = &rtc->class_dev;
+	file->private_data = rtc;
 
-	err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
+	err = ops->open ? ops->open(rtc->dev.parent) : 0;
 	if (err == 0) {
 		spin_lock_irq(&rtc->irq_lock);
 		rtc->irq_data = 0;
@@ -61,7 +61,7 @@ static void rtc_uie_task(struct work_str
 	int num = 0;
 	int err;
 
-	err = rtc_read_time(&rtc->class_dev, &tm);
+	err = rtc_read_time(rtc, &tm);
 
 	local_irq_disable();
 	spin_lock(&rtc->irq_lock);
@@ -79,7 +79,7 @@ static void rtc_uie_task(struct work_str
 	}
 	spin_unlock(&rtc->irq_lock);
 	if (num)
-		rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+		rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
 	local_irq_enable();
 }
 static void rtc_uie_timer(unsigned long data)
@@ -121,7 +121,7 @@ static int set_uie(struct rtc_device *rt
 	struct rtc_time tm;
 	int err;
 
-	err = rtc_read_time(&rtc->class_dev, &tm);
+	err = rtc_read_time(rtc, &tm);
 	if (err)
 		return err;
 	spin_lock_irq(&rtc->irq_lock);
@@ -180,7 +180,7 @@ rtc_dev_read(struct file *file, char __u
 	if (ret == 0) {
 		/* Check for any data updates */
 		if (rtc->ops->read_callback)
-			data = rtc->ops->read_callback(rtc->class_dev.dev,
+			data = rtc->ops->read_callback(rtc->dev.parent,
 						       data);
 
 		if (sizeof(int) != sizeof(long) &&
@@ -210,8 +210,7 @@ static int rtc_dev_ioctl(struct inode *i
 		unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
-	struct class_device *class_dev = file->private_data;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
+	struct rtc_device *rtc = file->private_data;
 	const struct rtc_class_ops *ops = rtc->ops;
 	struct rtc_time tm;
 	struct rtc_wkalrm alarm;
@@ -252,7 +251,7 @@ static int rtc_dev_ioctl(struct inode *i
 
 	/* try the driver's ioctl interface */
 	if (ops->ioctl) {
-		err = ops->ioctl(class_dev->dev, cmd, arg);
+		err = ops->ioctl(rtc->dev.parent, cmd, arg);
 		if (err != -ENOIOCTLCMD)
 			return err;
 	}
@@ -264,7 +263,7 @@ static int rtc_dev_ioctl(struct inode *i
 
 	switch (cmd) {
 	case RTC_ALM_READ:
-		err = rtc_read_alarm(class_dev, &alarm);
+		err = rtc_read_alarm(rtc, &alarm);
 		if (err < 0)
 			return err;
 
@@ -278,17 +277,53 @@ static int rtc_dev_ioctl(struct inode *i
 
 		alarm.enabled = 0;
 		alarm.pending = 0;
-		alarm.time.tm_mday = -1;
-		alarm.time.tm_mon = -1;
-		alarm.time.tm_year = -1;
 		alarm.time.tm_wday = -1;
 		alarm.time.tm_yday = -1;
 		alarm.time.tm_isdst = -1;
-		err = rtc_set_alarm(class_dev, &alarm);
+
+		/* RTC_ALM_SET alarms may be up to 24 hours in the future.
+		 * Rather than expecting every RTC to implement "don't care"
+		 * for day/month/year fields, just force the alarm to have
+		 * the right values for those fields.
+		 *
+		 * RTC_WKALM_SET should be used instead.  Not only does it
+		 * eliminate the need for a separate RTC_AIE_ON call, it
+		 * doesn't have the "alarm 23:59:59 in the future" race.
+		 *
+		 * NOTE:  some legacy code may have used invalid fields as
+		 * wildcards, exposing hardware "periodic alarm" capabilities.
+		 * Not supported here.
+		 */
+		{
+			unsigned long now, then;
+
+			err = rtc_read_time(rtc, &tm);
+			if (err < 0)
+				return err;
+			rtc_tm_to_time(&tm, &now);
+
+			alarm.time.tm_mday = tm.tm_mday;
+			alarm.time.tm_mon = tm.tm_mon;
+			alarm.time.tm_year = tm.tm_year;
+			err  = rtc_valid_tm(&alarm.time);
+			if (err < 0)
+				return err;
+			rtc_tm_to_time(&alarm.time, &then);
+
+			/* alarm may need to wrap into tomorrow */
+			if (then < now) {
+				rtc_time_to_tm(now + 24 * 60 * 60, &tm);
+				alarm.time.tm_mday = tm.tm_mday;
+				alarm.time.tm_mon = tm.tm_mon;
+				alarm.time.tm_year = tm.tm_year;
+			}
+		}
+
+		err = rtc_set_alarm(rtc, &alarm);
 		break;
 
 	case RTC_RD_TIME:
-		err = rtc_read_time(class_dev, &tm);
+		err = rtc_read_time(rtc, &tm);
 		if (err < 0)
 			return err;
 
@@ -300,7 +335,7 @@ static int rtc_dev_ioctl(struct inode *i
 		if (copy_from_user(&tm, uarg, sizeof(tm)))
 			return -EFAULT;
 
-		err = rtc_set_time(class_dev, &tm);
+		err = rtc_set_time(rtc, &tm);
 		break;
 
 	case RTC_IRQP_READ:
@@ -310,7 +345,7 @@ static int rtc_dev_ioctl(struct inode *i
 
 	case RTC_IRQP_SET:
 		if (ops->irq_set_freq)
-			err = rtc_irq_set_freq(class_dev, rtc->irq_task, arg);
+			err = rtc_irq_set_freq(rtc, rtc->irq_task, arg);
 		break;
 
 #if 0
@@ -336,11 +371,11 @@ #endif
 		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
 			return -EFAULT;
 
-		err = rtc_set_alarm(class_dev, &alarm);
+		err = rtc_set_alarm(rtc, &alarm);
 		break;
 
 	case RTC_WKALM_RD:
-		err = rtc_read_alarm(class_dev, &alarm);
+		err = rtc_read_alarm(rtc, &alarm);
 		if (err < 0)
 			return err;
 
@@ -372,7 +407,7 @@ #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 	clear_uie(rtc);
 #endif
 	if (rtc->ops->release)
-		rtc->ops->release(rtc->class_dev.dev);
+		rtc->ops->release(rtc->dev.parent);
 
 	mutex_unlock(&rtc->char_lock);
 	return 0;
@@ -397,17 +432,18 @@ static const struct file_operations rtc_
 
 /* insertion/removal hooks */
 
-static int rtc_dev_add_device(struct class_device *class_dev,
-				struct class_interface *class_intf)
+void rtc_dev_prepare(struct rtc_device *rtc)
 {
-	int err = 0;
-	struct rtc_device *rtc = to_rtc_device(class_dev);
+	if (!rtc_devt)
+		return;
 
 	if (rtc->id >= RTC_DEV_MAX) {
-		dev_err(class_dev->dev, "too many RTCs\n");
-		return -EINVAL;
+		pr_debug("%s: too many RTC devices\n", rtc->name);
+		return;
 	}
 
+	rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
+
 	mutex_init(&rtc->char_lock);
 	spin_lock_init(&rtc->irq_lock);
 	init_waitqueue_head(&rtc->irq_queue);
@@ -418,100 +454,36 @@ #endif
 
 	cdev_init(&rtc->char_dev, &rtc_dev_fops);
 	rtc->char_dev.owner = rtc->owner;
+}
 
-	if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
-		dev_err(class_dev->dev,
-			"failed to add char device %d:%d\n",
+void rtc_dev_add_device(struct rtc_device *rtc)
+{
+	if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
+		printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
+			rtc->name, MAJOR(rtc_devt), rtc->id);
+	else
+		pr_debug("%s: dev (%d:%d)\n", rtc->name,
 			MAJOR(rtc_devt), rtc->id);
-		return -ENODEV;
-	}
-
-	rtc->rtc_dev = class_device_create(rtc_dev_class, NULL,
-						MKDEV(MAJOR(rtc_devt), rtc->id),
-						class_dev->dev, "rtc%d", rtc->id);
-	if (IS_ERR(rtc->rtc_dev)) {
-		dev_err(class_dev->dev, "cannot create rtc_dev device\n");
-		err = PTR_ERR(rtc->rtc_dev);
-		goto err_cdev_del;
-	}
-
-	dev_dbg(class_dev->dev, "rtc intf: dev (%d:%d)\n",
-		MAJOR(rtc->rtc_dev->devt),
-		MINOR(rtc->rtc_dev->devt));
-
-	return 0;
-
-err_cdev_del:
-
-	cdev_del(&rtc->char_dev);
-	return err;
 }
 
-static void rtc_dev_remove_device(struct class_device *class_dev,
-					struct class_interface *class_intf)
+void rtc_dev_del_device(struct rtc_device *rtc)
 {
-	struct rtc_device *rtc = to_rtc_device(class_dev);
-
-	if (rtc->rtc_dev) {
-		dev_dbg(class_dev->dev, "removing char %d:%d\n",
-			MAJOR(rtc->rtc_dev->devt),
-			MINOR(rtc->rtc_dev->devt));
-
-		class_device_unregister(rtc->rtc_dev);
+	if (rtc->dev.devt)
 		cdev_del(&rtc->char_dev);
-	}
 }
 
-/* interface registration */
-
-static struct class_interface rtc_dev_interface = {
-	.add = &rtc_dev_add_device,
-	.remove = &rtc_dev_remove_device,
-};
-
-static int __init rtc_dev_init(void)
+void __init rtc_dev_init(void)
 {
 	int err;
 
-	rtc_dev_class = class_create(THIS_MODULE, "rtc-dev");
-	if (IS_ERR(rtc_dev_class))
-		return PTR_ERR(rtc_dev_class);
-
 	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
-	if (err < 0) {
+	if (err < 0)
 		printk(KERN_ERR "%s: failed to allocate char dev region\n",
 			__FILE__);
-		goto err_destroy_class;
-	}
-
-	err = rtc_interface_register(&rtc_dev_interface);
-	if (err < 0) {
-		printk(KERN_ERR "%s: failed to register the interface\n",
-			__FILE__);
-		goto err_unregister_chrdev;
-	}
-
-	return 0;
-
-err_unregister_chrdev:
-	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
-
-err_destroy_class:
-	class_destroy(rtc_dev_class);
-
-	return err;
 }
 
-static void __exit rtc_dev_exit(void)
+void __exit rtc_dev_exit(void)
 {
-	class_interface_unregister(&rtc_dev_interface);
-	class_destroy(rtc_dev_class);
-	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+	if (rtc_devt)
+		unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
 }
-
-subsys_initcall(rtc_dev_init);
-module_exit(rtc_dev_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class dev interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index e27176c..afa64c7 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -203,7 +203,7 @@ static irqreturn_t ds1553_rtc_interrupt(
 		events |= RTC_UF;
 	else
 		events |= RTC_AF;
-	rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+	rtc_update_irq(pdata->rtc, 1, events);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 7bbc26a..ba795a4 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -117,85 +117,4 @@ int rtc_tm_to_time(struct rtc_time *tm, 
 }
 EXPORT_SYMBOL(rtc_tm_to_time);
 
-
-/* Merge the valid (i.e. non-negative) fields of alarm into the current
- * time.  If the valid alarm fields are earlier than the equivalent
- * fields in the time, carry one into the least significant invalid
- * field, so that the alarm expiry is in the future.  It assumes that the
- * least significant invalid field is more significant than the most
- * significant valid field, and that the seconds field is valid.
- *
- * This is used by alarms that take relative (rather than absolute)
- * times, and/or have a simple binary second counter instead of
- * day/hour/minute/sec registers.
- */
-void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm)
-{
-	int *alarmp = &alarm->tm_sec;
-	int *timep = &now->tm_sec;
-	int carry_into, i;
-
-	/* Ignore everything past the 6th element (tm_year). */
-	for (i = 5; i > 0; i--) {
-		if (alarmp[i] < 0)
-			alarmp[i] = timep[i];
-		else
-			break;
-	}
-
-	/* No carry needed if all fields are valid. */
-	if (i == 5)
-		return;
-
-	for (carry_into = i + 1; i >= 0; i--) {
-		if (alarmp[i] < timep[i])
-			break;
-
-		if (alarmp[i] > timep[i])
-			return;
-	}
-
-	switch (carry_into) {
-		case 1:
-			alarm->tm_min++;
-
-			if (alarm->tm_min < 60)
-				return;
-
-			alarm->tm_min = 0;
-			/* fall-through */
-
-		case 2:
-			alarm->tm_hour++;
-
-			if (alarm->tm_hour < 60)
-				return;
-
-			alarm->tm_hour = 0;
-			/* fall-through */
-
-		case 3:
-			alarm->tm_mday++;
-
-			if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon])
-				return;
-
-			alarm->tm_mday = 1;
-			/* fall-through */
-
-		case 4:
-			alarm->tm_mon++;
-
-			if (alarm->tm_mon <= 12)
-				return;
-
-			alarm->tm_mon = 1;
-			/* fall-through */
-
-		case 5:
-			alarm->tm_year++;
-	}
-}
-EXPORT_SYMBOL(rtc_merge_alarm);
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
new file mode 100644
index 0000000..eee4ee5
--- /dev/null
+++ b/drivers/rtc/rtc-max6900.c
@@ -0,0 +1,311 @@
+/*
+ * rtc class driver for the Maxim MAX6900 chip
+ *
+ * Author: Dale Farnsworth <dale@farnsworth.org>
+ *
+ * based on previously existing rtc class drivers
+ *
+ * 2007 (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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+
+#define DRV_NAME "max6900"
+#define DRV_VERSION "0.1"
+
+/*
+ * register indices
+ */
+#define MAX6900_REG_SC			0	/* seconds	00-59 */
+#define MAX6900_REG_MN			1	/* minutes	00-59 */
+#define MAX6900_REG_HR			2	/* hours	00-23 */
+#define MAX6900_REG_DT			3	/* day of month	00-31 */
+#define MAX6900_REG_MO			4	/* month	01-12 */
+#define MAX6900_REG_DW			5	/* day of week	 1-7  */
+#define MAX6900_REG_YR			6	/* year		00-99 */
+#define MAX6900_REG_CT			7	/* control */
+#define MAX6900_REG_LEN			8
+
+#define MAX6900_REG_CT_WP		(1 << 7)	/* Write Protect */
+
+/*
+ * register read/write commands
+ */
+#define MAX6900_REG_CONTROL_WRITE	0x8e
+#define MAX6900_REG_BURST_READ		0xbf
+#define MAX6900_REG_BURST_WRITE		0xbe
+#define MAX6900_REG_RESERVED_READ	0x96
+
+#define MAX6900_IDLE_TIME_AFTER_WRITE	3	/* specification says 2.5 mS */
+
+#define MAX6900_I2C_ADDR		0xa0
+
+static unsigned short normal_i2c[] = {
+	MAX6900_I2C_ADDR >> 1,
+	I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;			/* defines addr_data */
+
+static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
+
+static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
+{
+	u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
+	struct i2c_msg msgs[2] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= sizeof(reg_addr),
+			.buf	= reg_addr
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= MAX6900_REG_LEN,
+			.buf	= buf
+		}
+	};
+	int rc;
+
+	rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (rc != ARRAY_SIZE(msgs)) {
+		dev_err(&client->dev, "%s: register read failed\n",
+			__FUNCTION__);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
+{
+	u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+	struct i2c_msg msgs[1] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= MAX6900_REG_LEN + 1,
+			.buf	= i2c_buf
+		}
+	};
+	int rc;
+
+	memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
+
+	rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (rc != ARRAY_SIZE(msgs)) {
+		dev_err(&client->dev, "%s: register write failed\n",
+			__FUNCTION__);
+		return -EIO;
+	}
+	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+	return 0;
+}
+
+static int max6900_i2c_validate_client(struct i2c_client *client)
+{
+	u8 regs[MAX6900_REG_LEN];
+	u8 zero_mask[MAX6900_REG_LEN] = {
+		0x80,	/* seconds */
+		0x80,	/* minutes */
+		0x40,	/* hours */
+		0xc0,	/* day of month */
+		0xe0,	/* month */
+		0xf8,	/* day of week */
+		0x00,	/* year */
+		0x7f,	/* control */
+	};
+	int i;
+	int rc;
+	int reserved;
+
+	reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ);
+	if (reserved != 0x07)
+		return -ENODEV;
+
+	rc = max6900_i2c_read_regs(client, regs);
+	if (rc < 0)
+		return rc;
+
+	for (i = 0; i < MAX6900_REG_LEN; ++i) {
+		if (regs[i] & zero_mask[i])
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
+{
+	int rc;
+	u8 regs[MAX6900_REG_LEN];
+
+	rc = max6900_i2c_read_regs(client, regs);
+	if (rc < 0)
+		return rc;
+
+	tm->tm_sec = BCD2BIN(regs[MAX6900_REG_SC]);
+	tm->tm_min = BCD2BIN(regs[MAX6900_REG_MN]);
+	tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
+	tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
+	tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
+	tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+	tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
+
+	return 0;
+}
+
+static int max6900_i2c_clear_write_protect(struct i2c_client *client)
+{
+	int rc;
+	rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
+	if (rc < 0) {
+		dev_err(&client->dev, "%s: control register write failed\n",
+			__FUNCTION__);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int max6900_i2c_set_time(struct i2c_client *client,
+				struct rtc_time const *tm)
+{
+	u8 regs[MAX6900_REG_LEN];
+	int rc;
+
+	rc = max6900_i2c_clear_write_protect(client);
+	if (rc < 0)
+		return rc;
+
+	regs[MAX6900_REG_SC] = BIN2BCD(tm->tm_sec);
+	regs[MAX6900_REG_MN] = BIN2BCD(tm->tm_min);
+	regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
+	regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
+	regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+	regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
+	regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
+	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;	/* set write protect */
+
+	rc = max6900_i2c_write_regs(client, regs);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int max6900_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6900_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6900_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static int max6900_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, max6900_probe);
+}
+
+static int max6900_detach_client(struct i2c_client *client)
+{
+	struct rtc_device *const rtc = i2c_get_clientdata(client);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return i2c_detach_client(client);
+}
+
+static struct i2c_driver max6900_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+	},
+	.id		= I2C_DRIVERID_MAX6900,
+	.attach_adapter = max6900_attach_adapter,
+	.detach_client	= max6900_detach_client,
+};
+
+static const struct rtc_class_ops max6900_rtc_ops = {
+	.read_time	= max6900_rtc_read_time,
+	.set_time	= max6900_rtc_set_time,
+};
+
+static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind)
+{
+	int rc = 0;
+	struct i2c_client *client = NULL;
+	struct rtc_device *rtc = NULL;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		rc = -ENODEV;
+		goto failout;
+	}
+
+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == NULL) {
+		rc = -ENOMEM;
+		goto failout;
+	}
+
+	client->addr = addr;
+	client->adapter = adapter;
+	client->driver = &max6900_driver;
+	strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE);
+
+	if (kind < 0) {
+		rc = max6900_i2c_validate_client(client);
+		if (rc < 0)
+			goto failout;
+	}
+
+	rc = i2c_attach_client(client);
+	if (rc < 0)
+		goto failout;
+
+	dev_info(&client->dev,
+		 "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(max6900_driver.driver.name,
+				  &client->dev,
+				  &max6900_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		rc = PTR_ERR(rtc);
+		goto failout_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	return 0;
+
+failout_detach:
+	i2c_detach_client(client);
+failout:
+	kfree(client);
+	return rc;
+}
+
+static int __init max6900_init(void)
+{
+	return i2c_add_driver(&max6900_driver);
+}
+
+static void __exit max6900_exit(void)
+{
+	i2c_del_driver(&max6900_driver);
+}
+
+MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(max6900_init);
+module_exit(max6900_exit);
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 9de8d67..60a8a4b 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -124,7 +124,7 @@ static void rtc_wait_not_busy(void)
 	/* now we have ~15 usec to read/write various registers */
 }
 
-static irqreturn_t rtc_irq(int irq, void *class_dev)
+static irqreturn_t rtc_irq(int irq, void *rtc)
 {
 	unsigned long		events = 0;
 	u8			irq_data;
@@ -141,7 +141,7 @@ static irqreturn_t rtc_irq(int irq, void
 	if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
 		events |= RTC_IRQF | RTC_UF;
 
-	rtc_update_irq(class_dev, 1, events);
+	rtc_update_irq(rtc, 1, events);
 
 	return IRQ_HANDLED;
 }
@@ -289,34 +289,6 @@ static int omap_rtc_set_alarm(struct dev
 {
 	u8 reg;
 
-	/* Much userspace code uses RTC_ALM_SET, thus "don't care" for
-	 * day/month/year specifies alarms up to 24 hours in the future.
-	 * So we need to handle that ... but let's ignore the "don't care"
-	 * values for hours/minutes/seconds.
-	 */
-	if (alm->time.tm_mday <= 0
-			&& alm->time.tm_mon < 0
-			&& alm->time.tm_year < 0) {
-		struct rtc_time tm;
-		unsigned long now, then;
-
-		omap_rtc_read_time(dev, &tm);
-		rtc_tm_to_time(&tm, &now);
-
-		alm->time.tm_mday = tm.tm_mday;
-		alm->time.tm_mon = tm.tm_mon;
-		alm->time.tm_year = tm.tm_year;
-		rtc_tm_to_time(&alm->time, &then);
-
-		/* sometimes the alarm wraps into tomorrow */
-		if (then < now) {
-			rtc_time_to_tm(now + 24 * 60 * 60, &tm);
-			alm->time.tm_mday = tm.tm_mday;
-			alm->time.tm_mon = tm.tm_mon;
-			alm->time.tm_year = tm.tm_year;
-		}
-	}
-
 	if (tm2bcd(&alm->time) < 0)
 		return -EINVAL;
 
@@ -399,7 +371,7 @@ static int __devinit omap_rtc_probe(stru
 		goto fail;
 	}
 	platform_set_drvdata(pdev, rtc);
-	class_set_devdata(&rtc->class_dev, mem);
+	dev_set_devdata(&rtc->dev, mem);
 
 	/* clear pending irqs, and set 1/second periodic,
 	 * which we'll use instead of update irqs
@@ -418,13 +390,13 @@ static int __devinit omap_rtc_probe(stru
 
 	/* handle periodic and alarm irqs */
 	if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
-			rtc->class_dev.class_id, &rtc->class_dev)) {
+			rtc->dev.bus_id, rtc)) {
 		pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
 			pdev->name, omap_rtc_timer);
 		goto fail0;
 	}
 	if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
-			rtc->class_dev.class_id, &rtc->class_dev)) {
+			rtc->dev.bus_id, rtc)) {
 		pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
 			pdev->name, omap_rtc_alarm);
 		goto fail1;
@@ -481,26 +453,17 @@ static int __devexit omap_rtc_remove(str
 	free_irq(omap_rtc_timer, rtc);
 	free_irq(omap_rtc_alarm, rtc);
 
-	release_resource(class_get_devdata(&rtc->class_dev));
+	release_resource(dev_get_devdata(&rtc->dev));
 	rtc_device_unregister(rtc);
 	return 0;
 }
 
 #ifdef CONFIG_PM
 
-static struct timespec rtc_delta;
 static u8 irqstat;
 
 static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct rtc_time rtc_tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-	omap_rtc_read_time(NULL, &rtc_tm);
-	rtc_tm_to_time(&rtc_tm, &time.tv_sec);
-
-	save_time_delta(&rtc_delta, &time);
 	irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
 
 	/* FIXME the RTC alarm is not currently acting as a wakeup event
@@ -517,14 +480,6 @@ static int omap_rtc_suspend(struct platf
 
 static int omap_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_time rtc_tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-	omap_rtc_read_time(NULL, &rtc_tm);
-	rtc_tm_to_time(&rtc_tm, &time.tv_sec);
-
-	restore_time_delta(&rtc_delta, &time);
 	if (device_may_wakeup(&pdev->dev))
 		disable_irq_wake(omap_rtc_alarm);
 	else
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index f13daa9..e4bf68c 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -51,7 +51,7 @@ static irqreturn_t pl031_interrupt(int i
 {
 	struct rtc_device *rtc = dev_id;
 
-	rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+	rtc_update_irq(rtc, 1, RTC_AF);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index 1bd624f..8d300e6 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -16,18 +16,18 @@ #include <linux/rtc.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
-static struct class_device *rtc_dev = NULL;
-static DEFINE_MUTEX(rtc_lock);
+#include "rtc-core.h"
+
 
 static int rtc_proc_show(struct seq_file *seq, void *offset)
 {
 	int err;
-	struct class_device *class_dev = seq->private;
-	const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+	struct rtc_device *rtc = seq->private;
+	const struct rtc_class_ops *ops = rtc->ops;
 	struct rtc_wkalrm alrm;
 	struct rtc_time tm;
 
-	err = rtc_read_time(class_dev, &tm);
+	err = rtc_read_time(rtc, &tm);
 	if (err == 0) {
 		seq_printf(seq,
 			"rtc_time\t: %02d:%02d:%02d\n"
@@ -36,7 +36,7 @@ static int rtc_proc_show(struct seq_file
 			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
 	}
 
-	err = rtc_read_alarm(class_dev, &alrm);
+	err = rtc_read_alarm(rtc, &alrm);
 	if (err == 0) {
 		seq_printf(seq, "alrm_time\t: ");
 		if ((unsigned int)alrm.time.tm_hour <= 24)
@@ -74,19 +74,19 @@ static int rtc_proc_show(struct seq_file
 	seq_printf(seq, "24hr\t\t: yes\n");
 
 	if (ops->proc)
-		ops->proc(class_dev->dev, seq);
+		ops->proc(rtc->dev.parent, seq);
 
 	return 0;
 }
 
 static int rtc_proc_open(struct inode *inode, struct file *file)
 {
-	struct class_device *class_dev = PDE(inode)->data;
+	struct rtc_device *rtc = PDE(inode)->data;
 
 	if (!try_module_get(THIS_MODULE))
 		return -ENODEV;
 
-	return single_open(file, rtc_proc_show, class_dev);
+	return single_open(file, rtc_proc_show, rtc);
 }
 
 static int rtc_proc_release(struct inode *inode, struct file *file)
@@ -103,62 +103,22 @@ static const struct file_operations rtc_
 	.release	= rtc_proc_release,
 };
 
-static int rtc_proc_add_device(struct class_device *class_dev,
-					struct class_interface *class_intf)
+void rtc_proc_add_device(struct rtc_device *rtc)
 {
-	mutex_lock(&rtc_lock);
-	if (rtc_dev == NULL) {
+	if (rtc->id == 0) {
 		struct proc_dir_entry *ent;
 
-		rtc_dev = class_dev;
-
 		ent = create_proc_entry("driver/rtc", 0, NULL);
 		if (ent) {
-			struct rtc_device *rtc = to_rtc_device(class_dev);
-
 			ent->proc_fops = &rtc_proc_fops;
 			ent->owner = rtc->owner;
-			ent->data = class_dev;
-
-			dev_dbg(class_dev->dev, "rtc intf: proc\n");
+			ent->data = rtc;
 		}
-		else
-			rtc_dev = NULL;
 	}
-	mutex_unlock(&rtc_lock);
-
-	return 0;
 }
 
-static void rtc_proc_remove_device(struct class_device *class_dev,
-					struct class_interface *class_intf)
+void rtc_proc_del_device(struct rtc_device *rtc)
 {
-	mutex_lock(&rtc_lock);
-	if (rtc_dev == class_dev) {
+	if (rtc->id == 0)
 		remove_proc_entry("driver/rtc", NULL);
-		rtc_dev = NULL;
-	}
-	mutex_unlock(&rtc_lock);
-}
-
-static struct class_interface rtc_proc_interface = {
-	.add = &rtc_proc_add_device,
-	.remove = &rtc_proc_remove_device,
-};
-
-static int __init rtc_proc_init(void)
-{
-	return rtc_interface_register(&rtc_proc_interface);
 }
-
-static void __exit rtc_proc_exit(void)
-{
-	class_interface_unregister(&rtc_proc_interface);
-}
-
-subsys_initcall(rtc_proc_init);
-module_exit(rtc_proc_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class proc interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
new file mode 100644
index 0000000..9d6de37
--- /dev/null
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -0,0 +1,405 @@
+/*
+ * Ricoh RS5C313 RTC device/driver
+ *  Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ *  2005-09-19 modifed by kogiidena
+ *
+ * Based on the old drivers/char/rs5c313_rtc.c  by:
+ *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ *
+ * Based on code written by Paul Gortmaker.
+ *  Copyright (C) 1996 Paul Gortmaker
+ *
+ * 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.
+ *
+ * Based on other minimal char device drivers, like Alan's
+ * watchdog, Ted's random, etc. etc.
+ *
+ *	1.07	Paul Gortmaker.
+ *	1.08	Miquel van Smoorenburg: disallow certain things on the
+ *		DEC Alpha as the CMOS clock is also used for other things.
+ *	1.09	Nikita Schmidt: epoch support and some Alpha cleanup.
+ *	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.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
+ *			      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
+ *		CONFIG_HPET_EMULATE_RTC
+ *	1.13	Nobuhiro Iwamatsu: Updata driver.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#define DRV_NAME	"rs5c313"
+#define DRV_VERSION 	"1.13"
+
+#ifdef CONFIG_SH_LANDISK
+/*****************************************************/
+/* LANDISK dependence part of RS5C313                */
+/*****************************************************/
+
+#define SCSMR1		0xFFE00000
+#define SCSCR1		0xFFE00008
+#define SCSMR1_CA	0x80
+#define SCSCR1_CKE	0x03
+#define SCSPTR1		0xFFE0001C
+#define SCSPTR1_EIO	0x80
+#define SCSPTR1_SPB1IO	0x08
+#define SCSPTR1_SPB1DT	0x04
+#define SCSPTR1_SPB0IO	0x02
+#define SCSPTR1_SPB0DT	0x01
+
+#define SDA_OEN		SCSPTR1_SPB1IO
+#define SDA		SCSPTR1_SPB1DT
+#define SCL_OEN		SCSPTR1_SPB0IO
+#define SCL		SCSPTR1_SPB0DT
+
+/* RICOH RS5C313 CE port */
+#define RS5C313_CE	0xB0000003
+
+/* RICOH RS5C313 CE port bit */
+#define RS5C313_CE_RTCCE	0x02
+
+/* SCSPTR1 data */
+unsigned char scsptr1_data;
+
+#define RS5C313_CEENABLE    ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE);
+#define RS5C313_CEDISABLE   ctrl_outb(0x00, RS5C313_CE)
+#define RS5C313_MISCOP      ctrl_outb(0x02, 0xB0000008)
+
+static void rs5c313_init_port(void)
+{
+	/* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
+	ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
+	ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
+
+	/* And Initialize SCL for RS5C313 clock */
+	scsptr1_data = ctrl_inb(SCSPTR1) | SCL;	/* SCL:H */
+	ctrl_outb(scsptr1_data, SCSPTR1);
+	scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN;	/* SCL output enable */
+	ctrl_outb(scsptr1_data, SCSPTR1);
+	RS5C313_CEDISABLE;	/* CE:L */
+}
+
+static void rs5c313_write_data(unsigned char data)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		/* SDA:Write Data */
+		scsptr1_data = (scsptr1_data & ~SDA) |
+				((((0x80 >> i) & data) >> (7 - i)) << 2);
+		ctrl_outb(scsptr1_data, SCSPTR1);
+		if (i == 0) {
+			scsptr1_data |= SDA_OEN;	/* SDA:output enable */
+			ctrl_outb(scsptr1_data, SCSPTR1);
+		}
+		ndelay(700);
+		scsptr1_data &= ~SCL;	/* SCL:L */
+		ctrl_outb(scsptr1_data, SCSPTR1);
+		ndelay(700);
+		scsptr1_data |= SCL;	/* SCL:H */
+		ctrl_outb(scsptr1_data, SCSPTR1);
+	}
+
+	scsptr1_data &= ~SDA_OEN;	/* SDA:output disable */
+	ctrl_outb(scsptr1_data, SCSPTR1);
+}
+
+static unsigned char rs5c313_read_data(void)
+{
+	int i;
+	unsigned char data;
+
+	for (i = 0; i < 8; i++) {
+		ndelay(700);
+		/* SDA:Read Data */
+		data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i);
+		scsptr1_data &= ~SCL;	/* SCL:L */
+		ctrl_outb(scsptr1_data, SCSPTR1);
+		ndelay(700);
+		scsptr1_data |= SCL;	/* SCL:H */
+		ctrl_outb(scsptr1_data, SCSPTR1);
+	}
+	return data & 0x0F;
+}
+
+#endif /* CONFIG_SH_LANDISK */
+
+/*****************************************************/
+/* machine independence part of RS5C313              */
+/*****************************************************/
+
+/* RICOH RS5C313 address */
+#define RS5C313_ADDR_SEC	0x00
+#define RS5C313_ADDR_SEC10	0x01
+#define RS5C313_ADDR_MIN	0x02
+#define RS5C313_ADDR_MIN10	0x03
+#define RS5C313_ADDR_HOUR	0x04
+#define RS5C313_ADDR_HOUR10	0x05
+#define RS5C313_ADDR_WEEK	0x06
+#define RS5C313_ADDR_INTINTVREG	0x07
+#define RS5C313_ADDR_DAY	0x08
+#define RS5C313_ADDR_DAY10	0x09
+#define RS5C313_ADDR_MON	0x0A
+#define RS5C313_ADDR_MON10	0x0B
+#define RS5C313_ADDR_YEAR	0x0C
+#define RS5C313_ADDR_YEAR10	0x0D
+#define RS5C313_ADDR_CNTREG	0x0E
+#define RS5C313_ADDR_TESTREG	0x0F
+
+/* RICOH RS5C313 control register */
+#define RS5C313_CNTREG_ADJ_BSY	0x01
+#define RS5C313_CNTREG_WTEN_XSTP	0x02
+#define RS5C313_CNTREG_12_24	0x04
+#define RS5C313_CNTREG_CTFG	0x08
+
+/* RICOH RS5C313 test register */
+#define RS5C313_TESTREG_TEST	0x01
+
+/* RICOH RS5C313 control bit */
+#define RS5C313_CNTBIT_READ	0x40
+#define RS5C313_CNTBIT_AD	0x20
+#define RS5C313_CNTBIT_DT	0x10
+
+static unsigned char rs5c313_read_reg(unsigned char addr)
+{
+
+	rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD);
+	return rs5c313_read_data();
+}
+
+static void rs5c313_write_reg(unsigned char addr, unsigned char data)
+{
+	data &= 0x0f;
+	rs5c313_write_data(addr | RS5C313_CNTBIT_AD);
+	rs5c313_write_data(data | RS5C313_CNTBIT_DT);
+	return;
+}
+
+static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+{
+	return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
+}
+
+static inline void rs5c313_write_cntreg(unsigned char data)
+{
+	rs5c313_write_reg(RS5C313_ADDR_CNTREG, data);
+}
+
+static inline void rs5c313_write_intintvreg(unsigned char data)
+{
+	rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data);
+}
+
+static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	int data;
+
+	while (1) {
+		RS5C313_CEENABLE;	/* CE:H */
+
+		/* Initialize control reg. 24 hour */
+		rs5c313_write_cntreg(0x04);
+
+		if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+			break;
+
+		RS5C313_CEDISABLE;
+		ndelay(700);	/* CE:L */
+
+	}
+
+	data = rs5c313_read_reg(RS5C313_ADDR_SEC);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
+	tm->tm_sec = BCD2BIN(data);
+
+	data = rs5c313_read_reg(RS5C313_ADDR_MIN);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
+	tm->tm_min = BCD2BIN(data);
+
+	data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
+	tm->tm_hour = BCD2BIN(data);
+
+	data = rs5c313_read_reg(RS5C313_ADDR_DAY);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
+	tm->tm_mday = BCD2BIN(data);
+
+	data = rs5c313_read_reg(RS5C313_ADDR_MON);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
+	tm->tm_mon = BCD2BIN(data) - 1;
+
+	data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
+	data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
+	tm->tm_year = BCD2BIN(data);
+
+	if (tm->tm_year < 70)
+		tm->tm_year += 100;
+
+	data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
+	tm->tm_wday = BCD2BIN(data);
+
+	RS5C313_CEDISABLE;
+	ndelay(700);		/* CE:L */
+
+	return 0;
+}
+
+static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int data;
+
+	/* busy check. */
+	while (1) {
+		RS5C313_CEENABLE;	/* CE:H */
+
+		/* Initiatlize control reg. 24 hour */
+		rs5c313_write_cntreg(0x04);
+
+		if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+			break;
+		RS5C313_MISCOP;
+		RS5C313_CEDISABLE;
+		ndelay(700);	/* CE:L */
+	}
+
+	data = BIN2BCD(tm->tm_sec);
+	rs5c313_write_reg(RS5C313_ADDR_SEC, data);
+	rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
+
+	data = BIN2BCD(tm->tm_min);
+	rs5c313_write_reg(RS5C313_ADDR_MIN, data );
+	rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
+
+	data = BIN2BCD(tm->tm_hour);
+	rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
+	rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
+
+	data = BIN2BCD(tm->tm_mday);
+	rs5c313_write_reg(RS5C313_ADDR_DAY, data);
+	rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4));
+
+	data = BIN2BCD(tm->tm_mon + 1);
+	rs5c313_write_reg(RS5C313_ADDR_MON, data);
+	rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
+
+	data = BIN2BCD(tm->tm_year % 100);
+	rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
+	rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
+
+	data = BIN2BCD(tm->tm_wday);
+	rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
+
+	RS5C313_CEDISABLE;	/* CE:H */
+	ndelay(700);
+
+	return 0;
+}
+
+static void rs5c313_check_xstp_bit(void)
+{
+	struct rtc_time tm;
+
+	RS5C313_CEENABLE;	/* CE:H */
+	if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
+		/* INT interval reg. OFF */
+		rs5c313_write_intintvreg(0x00);
+		/* Initialize control reg. 24 hour & adjust */
+		rs5c313_write_cntreg(0x07);
+
+		/* busy check. */
+		while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+			RS5C313_MISCOP;
+
+		memset(&tm, 0, sizeof(struct rtc_time));
+		tm.tm_mday 	= 1;
+		tm.tm_mon 	= 1;
+
+		rs5c313_rtc_set_time(NULL, &tm);
+		printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
+				"1 Jan 2000\n");
+	}
+	RS5C313_CEDISABLE;
+	ndelay(700);		/* CE:L */
+}
+
+static const struct rtc_class_ops rs5c313_rtc_ops = {
+	.read_time = rs5c313_rtc_read_time,
+	.set_time = rs5c313_rtc_set_time,
+};
+
+static int rs5c313_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = rtc_device_register("rs5c313", &pdev->dev,
+				&rs5c313_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
+
+	platform_set_drvdata(pdev, rtc);
+
+	return err;
+}
+
+static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = platform_get_drvdata( pdev );
+
+	rtc_device_unregister(rtc);
+
+	return 0;
+}
+
+static struct platform_driver rs5c313_rtc_platform_driver = {
+	.driver         = {
+		.name   = DRV_NAME,
+		.owner  = THIS_MODULE,
+	},
+	.probe 	= rs5c313_rtc_probe,
+	.remove = __devexit_p( rs5c313_rtc_remove ),
+};
+
+static int __init rs5c313_rtc_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&rs5c313_rtc_platform_driver);
+	if (err)
+		return err;
+
+	rs5c313_init_port();
+	rs5c313_check_xstp_bit();
+
+	return 0;
+}
+
+static void __exit rs5c313_rtc_exit(void)
+{
+	platform_driver_unregister( &rs5c313_rtc_platform_driver );
+}
+
+module_init(rs5c313_rtc_init);
+module_exit(rs5c313_rtc_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
+MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 9a79a24..54b6130 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -50,7 +50,7 @@ static irqreturn_t s3c_rtc_alarmirq(int 
 {
 	struct rtc_device *rdev = id;
 
-	rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF);
+	rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
 	return IRQ_HANDLED;
 }
 
@@ -58,7 +58,7 @@ static irqreturn_t s3c_rtc_tickirq(int i
 {
 	struct rtc_device *rdev = id;
 
-	rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
+	rtc_update_irq(rdev, tick_count++, RTC_PF | RTC_IRQF);
 	return IRQ_HANDLED;
 }
 
@@ -548,37 +548,15 @@ static int ticnt_save;
 
 static int s3c_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(s3c_rtc_base + S3C2410_TICNT);
-
-	/* calculate time delta for suspend */
-
-	s3c_rtc_gettime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	save_time_delta(&s3c_rtc_delta, &time);
 	s3c_rtc_enable(pdev, 0);
-
 	return 0;
 }
 
 static int s3c_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
 	s3c_rtc_enable(pdev, 1);
-	s3c_rtc_gettime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	restore_time_delta(&s3c_rtc_delta, &time);
-
 	writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
 	return 0;
 }
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 677bae8..0918b78 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -93,7 +93,7 @@ static irqreturn_t sa1100_rtc_interrupt(
 	if (rtsr & RTSR_HZ)
 		events |= RTC_UF | RTC_IRQF;
 
-	rtc_update_irq(&rtc->class_dev, 1, events);
+	rtc_update_irq(rtc, 1, events);
 
 	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
 		rtc_update_alarm(&rtc_alarm);
@@ -119,7 +119,7 @@ static irqreturn_t timer1_interrupt(int 
 	 */
 	OSSR = OSSR_M1;	/* clear match on timer1 */
 
-	rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
+	rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
 
 	if (rtc_timer1_count == 1)
 		rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 198b9f2..6abf481 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int 
 
 	writeb(tmp, rtc->regbase + RCR1);
 
-	rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+	rtc_update_irq(&rtc->rtc_dev, 1, events);
 
 	spin_unlock(&rtc->lock);
 
@@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq,
 
 		rtc->rearm_aie = 1;
 
-		rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+		rtc_update_irq(&rtc->rtc_dev, 1, events);
 	}
 
 	spin_unlock(&rtc->lock);
@@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int i
 
 	spin_lock(&rtc->lock);
 
-	rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
+	rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
 
 	spin_unlock(&rtc->lock);
 
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 899ab8c..69df94b 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -12,20 +12,26 @@
 #include <linux/module.h>
 #include <linux/rtc.h>
 
+#include "rtc-core.h"
+
+
 /* device attributes */
 
-static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
 }
-static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
 
-static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
 
-	retval = rtc_read_time(dev, &tm);
+	retval = rtc_read_time(to_rtc_device(dev), &tm);
 	if (retval == 0) {
 		retval = sprintf(buf, "%04d-%02d-%02d\n",
 			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -33,14 +39,15 @@ static ssize_t rtc_sysfs_show_date(struc
 
 	return retval;
 }
-static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
 
-static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
 
-	retval = rtc_read_time(dev, &tm);
+	retval = rtc_read_time(to_rtc_device(dev), &tm);
 	if (retval == 0) {
 		retval = sprintf(buf, "%02d:%02d:%02d\n",
 			tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -48,14 +55,15 @@ static ssize_t rtc_sysfs_show_time(struc
 
 	return retval;
 }
-static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
 
-static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
 
-	retval = rtc_read_time(dev, &tm);
+	retval = rtc_read_time(to_rtc_device(dev), &tm);
 	if (retval == 0) {
 		unsigned long time;
 		rtc_tm_to_time(&tm, &time);
@@ -64,23 +72,18 @@ static ssize_t rtc_sysfs_show_since_epoc
 
 	return retval;
 }
-static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
-
-static struct attribute *rtc_attrs[] = {
-	&class_device_attr_name.attr,
-	&class_device_attr_date.attr,
-	&class_device_attr_time.attr,
-	&class_device_attr_since_epoch.attr,
-	NULL,
-};
 
-static struct attribute_group rtc_attr_group = {
-	.attrs = rtc_attrs,
+static struct device_attribute rtc_attrs[] = {
+	__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
+	__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
+	__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
+	__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
+	{ },
 };
 
-
 static ssize_t
-rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
+rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	ssize_t retval;
 	unsigned long alarm;
@@ -94,7 +97,7 @@ rtc_sysfs_show_wakealarm(struct class_de
 	 * REVISIT maybe we should require RTC implementations to
 	 * disable the RTC alarm after it triggers, for uniformity.
 	 */
-	retval = rtc_read_alarm(dev, &alm);
+	retval = rtc_read_alarm(to_rtc_device(dev), &alm);
 	if (retval == 0 && alm.enabled) {
 		rtc_tm_to_time(&alm.time, &alarm);
 		retval = sprintf(buf, "%lu\n", alarm);
@@ -104,16 +107,18 @@ rtc_sysfs_show_wakealarm(struct class_de
 }
 
 static ssize_t
-rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
+rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t n)
 {
 	ssize_t retval;
 	unsigned long now, alarm;
 	struct rtc_wkalrm alm;
+	struct rtc_device *rtc = to_rtc_device(dev);
 
 	/* Only request alarms that trigger in the future.  Disable them
 	 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
 	 */
-	retval = rtc_read_time(dev, &alm.time);
+	retval = rtc_read_time(rtc, &alm.time);
 	if (retval < 0)
 		return retval;
 	rtc_tm_to_time(&alm.time, &now);
@@ -124,7 +129,7 @@ rtc_sysfs_set_wakealarm(struct class_dev
 		 * entirely prevent that here, without even the minimal
 		 * locking from the /dev/rtcN api.
 		 */
-		retval = rtc_read_alarm(dev, &alm);
+		retval = rtc_read_alarm(rtc, &alm);
 		if (retval < 0)
 			return retval;
 		if (alm.enabled)
@@ -141,10 +146,10 @@ rtc_sysfs_set_wakealarm(struct class_dev
 	}
 	rtc_time_to_tm(alarm, &alm.time);
 
-	retval = rtc_set_alarm(dev, &alm);
+	retval = rtc_set_alarm(rtc, &alm);
 	return (retval < 0) ? retval : n;
 }
-static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
 		rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
 
 
@@ -153,71 +158,37 @@ static const CLASS_DEVICE_ATTR(wakealarm
  * suspend-to-disk.  So: no attribute unless that side effect is possible.
  * (Userspace may disable that mechanism later.)
  */
-static inline int rtc_does_wakealarm(struct class_device *class_dev)
+static inline int rtc_does_wakealarm(struct rtc_device *rtc)
 {
-	struct rtc_device *rtc;
-
-	if (!device_can_wakeup(class_dev->dev))
+	if (!device_can_wakeup(rtc->dev.parent))
 		return 0;
-	rtc = to_rtc_device(class_dev);
 	return rtc->ops->set_alarm != NULL;
 }
 
 
-static int rtc_sysfs_add_device(struct class_device *class_dev,
-					struct class_interface *class_intf)
+void rtc_sysfs_add_device(struct rtc_device *rtc)
 {
 	int err;
 
-	dev_dbg(class_dev->dev, "rtc intf: sysfs\n");
+	/* not all RTCs support both alarms and wakeup */
+	if (!rtc_does_wakealarm(rtc))
+		return;
 
-	err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
+	err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
 	if (err)
-		dev_err(class_dev->dev, "failed to create %s\n",
-				"sysfs attributes");
-	else if (rtc_does_wakealarm(class_dev)) {
-		/* not all RTCs support both alarms and wakeup */
-		err = class_device_create_file(class_dev,
-					&class_device_attr_wakealarm);
-		if (err) {
-			dev_err(class_dev->dev, "failed to create %s\n",
-					"alarm attribute");
-			sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
-		}
-	}
-
-	return err;
+		dev_err(rtc->dev.parent, "failed to create "
+				"alarm attribute, %d",
+				err);
 }
 
-static void rtc_sysfs_remove_device(struct class_device *class_dev,
-				struct class_interface *class_intf)
+void rtc_sysfs_del_device(struct rtc_device *rtc)
 {
-	if (rtc_does_wakealarm(class_dev))
-		class_device_remove_file(class_dev,
-				&class_device_attr_wakealarm);
-	sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+	/* REVISIT did we add it successfully? */
+	if (rtc_does_wakealarm(rtc))
+		device_remove_file(&rtc->dev, &dev_attr_wakealarm);
 }
 
-/* interface registration */
-
-static struct class_interface rtc_sysfs_interface = {
-	.add = &rtc_sysfs_add_device,
-	.remove = &rtc_sysfs_remove_device,
-};
-
-static int __init rtc_sysfs_init(void)
+void __init rtc_sysfs_init(struct class *rtc_class)
 {
-	return rtc_interface_register(&rtc_sysfs_interface);
+	rtc_class->dev_attrs = rtc_attrs;
 }
-
-static void __exit rtc_sysfs_exit(void)
-{
-	class_interface_unregister(&rtc_sysfs_interface);
-}
-
-subsys_initcall(rtc_sysfs_init);
-module_exit(rtc_sysfs_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class sysfs interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index f50a1b8..254c9fc 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -101,11 +101,11 @@ static ssize_t test_irq_store(struct dev
 	retval = count;
 	local_irq_disable();
 	if (strncmp(buf, "tick", 4) == 0)
-		rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
+		rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
 	else if (strncmp(buf, "alarm", 5) == 0)
-		rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
+		rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
 	else if (strncmp(buf, "update", 6) == 0)
-		rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
+		rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
 	else
 		retval = -EINVAL;
 	local_irq_enable();
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index e40322b..af7596e 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -97,6 +97,7 @@ static DEFINE_SPINLOCK(rtc_lock);
 static char rtc_name[] = "RTC";
 static unsigned long periodic_frequency;
 static unsigned long periodic_count;
+static unsigned int alarm_enabled;
 
 struct resource rtc_resource[2] = {
 	{	.name	= rtc_name,
@@ -188,6 +189,7 @@ static int vr41xx_rtc_read_alarm(struct 
 	low = rtc1_read(ECMPLREG);
 	mid = rtc1_read(ECMPMREG);
 	high = rtc1_read(ECMPHREG);
+	wkalrm->enabled = alarm_enabled;
 
 	spin_unlock_irq(&rtc_lock);
 
@@ -206,10 +208,18 @@ static int vr41xx_rtc_set_alarm(struct d
 
 	spin_lock_irq(&rtc_lock);
 
+	if (alarm_enabled)
+		disable_irq(ELAPSEDTIME_IRQ);
+
 	rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
 	rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
 	rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
 
+	if (wkalrm->enabled)
+		enable_irq(ELAPSEDTIME_IRQ);
+
+	alarm_enabled = wkalrm->enabled;
+
 	spin_unlock_irq(&rtc_lock);
 
 	return 0;
@@ -221,10 +231,24 @@ static int vr41xx_rtc_ioctl(struct devic
 
 	switch (cmd) {
 	case RTC_AIE_ON:
-		enable_irq(ELAPSEDTIME_IRQ);
+		spin_lock_irq(&rtc_lock);
+
+		if (!alarm_enabled) {
+			enable_irq(ELAPSEDTIME_IRQ);
+			alarm_enabled = 1;
+		}
+
+		spin_unlock_irq(&rtc_lock);
 		break;
 	case RTC_AIE_OFF:
-		disable_irq(ELAPSEDTIME_IRQ);
+		spin_lock_irq(&rtc_lock);
+
+		if (alarm_enabled) {
+			disable_irq(ELAPSEDTIME_IRQ);
+			alarm_enabled = 0;
+		}
+
+		spin_unlock_irq(&rtc_lock);
 		break;
 	case RTC_PIE_ON:
 		enable_irq(RTCLONG1_IRQ);
@@ -275,7 +299,7 @@ static irqreturn_t elapsedtime_interrupt
 
 	rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
 
-	rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+	rtc_update_irq(rtc, 1, RTC_AF);
 
 	return IRQ_HANDLED;
 }
@@ -291,7 +315,7 @@ static irqreturn_t rtclong1_interrupt(in
 	rtc1_write(RTCL1LREG, count);
 	rtc1_write(RTCL1HREG, count >> 16);
 
-	rtc_update_irq(&rtc->class_dev, 1, RTC_PF);
+	rtc_update_irq(rtc, 1, RTC_PF);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index eb5dc62..9775210 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -398,6 +398,9 @@ dasd_change_state(struct dasd_device *de
 
 	if (device->state == device->target)
 		wake_up(&dasd_init_waitq);
+
+	/* let user-space know that the device status changed */
+	kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE);
 }
 
 /*
@@ -2171,6 +2174,51 @@ dasd_generic_notify(struct ccw_device *c
 	return ret;
 }
 
+struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device,
+					     void *rdc_buffer,
+					     int rdc_buffer_size, char *magic)
+{
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+
+	cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
+
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Could not allocate RDC request");
+		return cqr;
+	}
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = CCW_CMD_RDC;
+	ccw->cda = (__u32)(addr_t)rdc_buffer;
+	ccw->count = rdc_buffer_size;
+
+	cqr->device = device;
+	cqr->expires = 10*HZ;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 2;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
+}
+
+
+int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
+				void **rdc_buffer, int rdc_buffer_size)
+{
+	int ret;
+	struct dasd_ccw_req *cqr;
+
+	cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size,
+				     magic);
+	if (IS_ERR(cqr))
+		return PTR_ERR(cqr);
+
+	ret = dasd_sleep_on(cqr);
+	dasd_sfree_request(cqr, cqr->device);
+	return ret;
+}
 
 static int __init
 dasd_init(void)
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index ed70852..6a89cef 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -19,6 +19,7 @@ #include <linux/module.h>
 
 #include <asm/debug.h>
 #include <asm/uaccess.h>
+#include <asm/ipl.h>
 
 /* This is ugly... */
 #define PRINTK_HEADER "dasd_devmap:"
@@ -133,6 +134,8 @@ dasd_call_setup(char *str)
 __setup ("dasd=", dasd_call_setup);
 #endif	/* #ifndef MODULE */
 
+#define	DASD_IPLDEV	"ipldev"
+
 /*
  * Read a device busid/devno from a string.
  */
@@ -141,6 +144,20 @@ dasd_busid(char **str, int *id0, int *id
 {
 	int val, old_style;
 
+	/* Interpret ipldev busid */
+	if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {
+		if (ipl_info.type != IPL_TYPE_CCW) {
+			MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw "
+				"device");
+			return -EINVAL;
+		}
+		*id0 = 0;
+		*id1 = ipl_info.data.ccw.dev_id.ssid;
+		*devno = ipl_info.data.ccw.dev_id.devno;
+		*str += strlen(DASD_IPLDEV);
+
+		return 0;
+	}
 	/* check for leading '0x' */
 	old_style = 0;
 	if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -829,6 +846,46 @@ dasd_discipline_show(struct device *dev,
 static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
 
 static ssize_t
+dasd_device_status_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct dasd_device *device;
+	ssize_t len;
+
+	device = dasd_device_from_cdev(to_ccwdev(dev));
+	if (!IS_ERR(device)) {
+		switch (device->state) {
+		case DASD_STATE_NEW:
+			len = snprintf(buf, PAGE_SIZE, "new\n");
+			break;
+		case DASD_STATE_KNOWN:
+			len = snprintf(buf, PAGE_SIZE, "detected\n");
+			break;
+		case DASD_STATE_BASIC:
+			len = snprintf(buf, PAGE_SIZE, "basic\n");
+			break;
+		case DASD_STATE_UNFMT:
+			len = snprintf(buf, PAGE_SIZE, "unformatted\n");
+			break;
+		case DASD_STATE_READY:
+			len = snprintf(buf, PAGE_SIZE, "ready\n");
+			break;
+		case DASD_STATE_ONLINE:
+			len = snprintf(buf, PAGE_SIZE, "online\n");
+			break;
+		default:
+			len = snprintf(buf, PAGE_SIZE, "no stat\n");
+			break;
+		}
+		dasd_put_device(device);
+	} else
+		len = snprintf(buf, PAGE_SIZE, "unknown\n");
+	return len;
+}
+
+static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL);
+
+static ssize_t
 dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct dasd_devmap *devmap;
@@ -939,6 +996,7 @@ static DEVICE_ATTR(eer_enabled, 0644, da
 static struct attribute * dasd_attrs[] = {
 	&dev_attr_readonly.attr,
 	&dev_attr_discipline.attr,
+	&dev_attr_status.attr,
 	&dev_attr_alias.attr,
 	&dev_attr_vendor.attr,
 	&dev_attr_uid.attr,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index cecab22..c9583fb 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -450,6 +450,81 @@ dasd_eckd_generate_uid(struct dasd_devic
 	return 0;
 }
 
+struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+					      void *rcd_buffer,
+					      struct ciw *ciw, __u8 lpm)
+{
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+
+	cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device);
+
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Could not allocate RCD request");
+		return cqr;
+	}
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = ciw->cmd;
+	ccw->cda = (__u32)(addr_t)rcd_buffer;
+	ccw->count = ciw->count;
+
+	cqr->device = device;
+	cqr->expires = 10*HZ;
+	cqr->lpm = lpm;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 2;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
+}
+
+static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
+				   void **rcd_buffer,
+				   int *rcd_buffer_size, __u8 lpm)
+{
+	struct ciw *ciw;
+	char *rcd_buf = NULL;
+	int ret;
+	struct dasd_ccw_req *cqr;
+
+	/*
+	 * scan for RCD command in extended SenseID data
+	 */
+	ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD);
+	if (!ciw || ciw->cmd == 0) {
+		ret = -EOPNOTSUPP;
+		goto out_error;
+	}
+	rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+	if (!rcd_buf) {
+		ret = -ENOMEM;
+		goto out_error;
+	}
+	cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
+	if (IS_ERR(cqr)) {
+		ret =  PTR_ERR(cqr);
+		goto out_error;
+	}
+	ret = dasd_sleep_on(cqr);
+	/*
+	 * on success we update the user input parms
+	 */
+	dasd_sfree_request(cqr, cqr->device);
+	if (ret)
+		goto out_error;
+
+	*rcd_buffer_size = ciw->count;
+	*rcd_buffer = rcd_buf;
+	return 0;
+out_error:
+	kfree(rcd_buf);
+	*rcd_buffer = NULL;
+	*rcd_buffer_size = 0;
+	return ret;
+}
+
 static int
 dasd_eckd_read_conf(struct dasd_device *device)
 {
@@ -469,8 +544,8 @@ dasd_eckd_read_conf(struct dasd_device *
 	/* get configuration data per operational path */
 	for (lpm = 0x80; lpm; lpm>>= 1) {
 		if (lpm & path_data->opm){
-			rc = read_conf_data_lpm(device->cdev, &conf_data,
-						&conf_len, lpm);
+			rc = dasd_eckd_read_conf_lpm(device, &conf_data,
+						     &conf_len, lpm);
 			if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
 				MESSAGE(KERN_WARNING,
 					"Read configuration data returned "
@@ -639,7 +714,7 @@ dasd_eckd_check_characteristics(struct d
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	memset(rdc_data, 0, sizeof(rdc_data));
-	rc = read_dev_chars(device->cdev, &rdc_data, 64);
+	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
 	if (rc)
 		DEV_MESSAGE(KERN_WARNING, device,
 			    "Read device characteristics returned "
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index be0909e..da16ead 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -135,7 +135,7 @@ dasd_fba_check_characteristics(struct da
 	}
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
-	rc = read_dev_chars(device->cdev, &rdc_data, 32);
+	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
 	if (rc) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    "Read device characteristics returned error %d",
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a2cc69e..241294c 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -509,6 +509,8 @@ int dasd_generic_set_online(struct ccw_d
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
 
+int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+
 /* externals in dasd_devmap.c */
 extern int dasd_max_devindex;
 extern int dasd_probeonly;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 293e667..c210784 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@ # S/390 character devices
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-	 sclp_info.o
+	 sclp_info.o sclp_config.o sclp_chp.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -29,3 +29,6 @@ obj-$(CONFIG_S390_TAPE_34XX) += tape_34x
 obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
 obj-$(CONFIG_MONREADER) += monreader.o
 obj-$(CONFIG_MONWRITER) += monwriter.o
+
+zcore_mod-objs := sclp_sdias.o zcore.o
+obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 9a328f1..6000bde 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -813,12 +813,6 @@ con3215_unblank(void)
 	spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 
-static int __init 
-con3215_consetup(struct console *co, char *options)
-{
-	return 0;
-}
-
 /*
  *  The console structure for the 3215 console
  */
@@ -827,7 +821,6 @@ static struct console con3215 = {
 	.write	 = con3215_write,
 	.device	 = con3215_device,
 	.unblank = con3215_unblank,
-	.setup	 = con3215_consetup,
 	.flags	 = CON_PRINTBUFFER,
 };
 
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 8e7f2d7..fd34791 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -555,12 +555,6 @@ con3270_unblank(void)
 	spin_unlock_irqrestore(&cp->view.lock, flags);
 }
 
-static int __init 
-con3270_consetup(struct console *co, char *options)
-{
-	return 0;
-}
-
 /*
  *  The console structure for the 3270 console
  */
@@ -569,7 +563,6 @@ static struct console con3270 = {
 	.write	 = con3270_write,
 	.device	 = con3270_device,
 	.unblank = con3270_unblank,
-	.setup	 = con3270_consetup,
 	.flags	 = CON_PRINTBUFFER,
 };
 
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index f171de3..fa62e69 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -15,6 +15,7 @@ #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/reboot.h>
 #include <linux/jiffies.h>
+#include <linux/init.h>
 #include <asm/types.h>
 #include <asm/s390_ext.h>
 
@@ -510,7 +511,7 @@ sclp_state_change_cb(struct evbuf_header
 }
 
 static struct sclp_register sclp_state_change_event = {
-	.receive_mask = EvTyp_StateChange_Mask,
+	.receive_mask = EVTYP_STATECHANGE_MASK,
 	.receiver_fn = sclp_state_change_cb
 };
 
@@ -930,3 +931,10 @@ sclp_init(void)
 	sclp_init_mask(1);
 	return 0;
 }
+
+static __init int sclp_initcall(void)
+{
+	return sclp_init();
+}
+
+arch_initcall(sclp_initcall);
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 7d29ab4..87ac4a3 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -19,33 +19,37 @@ #include <asm/ebcdic.h>
 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
 #define MAX_CONSOLE_PAGES	4
 
-#define EvTyp_OpCmd		0x01
-#define EvTyp_Msg		0x02
-#define EvTyp_StateChange	0x08
-#define EvTyp_PMsgCmd		0x09
-#define EvTyp_CntlProgOpCmd	0x20
-#define EvTyp_CntlProgIdent	0x0B
-#define EvTyp_SigQuiesce	0x1D
-#define EvTyp_VT220Msg		0x1A
-
-#define EvTyp_OpCmd_Mask	0x80000000
-#define EvTyp_Msg_Mask		0x40000000
-#define EvTyp_StateChange_Mask	0x01000000
-#define EvTyp_PMsgCmd_Mask	0x00800000
-#define EvTyp_CtlProgOpCmd_Mask	0x00000001
-#define EvTyp_CtlProgIdent_Mask	0x00200000
-#define EvTyp_SigQuiesce_Mask	0x00000008
-#define EvTyp_VT220Msg_Mask	0x00000040
-
-#define GnrlMsgFlgs_DOM		0x8000
-#define GnrlMsgFlgs_SndAlrm	0x4000
-#define GnrlMsgFlgs_HoldMsg	0x2000
-
-#define LnTpFlgs_CntlText	0x8000
-#define LnTpFlgs_LabelText	0x4000
-#define LnTpFlgs_DataText	0x2000
-#define LnTpFlgs_EndText	0x1000
-#define LnTpFlgs_PromptText	0x0800
+#define EVTYP_OPCMD		0x01
+#define EVTYP_MSG		0x02
+#define EVTYP_STATECHANGE	0x08
+#define EVTYP_PMSGCMD		0x09
+#define EVTYP_CNTLPROGOPCMD	0x20
+#define EVTYP_CNTLPROGIDENT	0x0B
+#define EVTYP_SIGQUIESCE	0x1D
+#define EVTYP_VT220MSG		0x1A
+#define EVTYP_CONFMGMDATA	0x04
+#define EVTYP_SDIAS		0x1C
+
+#define EVTYP_OPCMD_MASK	0x80000000
+#define EVTYP_MSG_MASK		0x40000000
+#define EVTYP_STATECHANGE_MASK	0x01000000
+#define EVTYP_PMSGCMD_MASK	0x00800000
+#define EVTYP_CTLPROGOPCMD_MASK	0x00000001
+#define EVTYP_CTLPROGIDENT_MASK	0x00200000
+#define EVTYP_SIGQUIESCE_MASK	0x00000008
+#define EVTYP_VT220MSG_MASK	0x00000040
+#define EVTYP_CONFMGMDATA_MASK	0x10000000
+#define EVTYP_SDIAS_MASK	0x00000010
+
+#define GNRLMSGFLGS_DOM		0x8000
+#define GNRLMSGFLGS_SNDALRM	0x4000
+#define GNRLMSGFLGS_HOLDMSG	0x2000
+
+#define LNTPFLGS_CNTLTEXT	0x8000
+#define LNTPFLGS_LABELTEXT	0x4000
+#define LNTPFLGS_DATATEXT	0x2000
+#define LNTPFLGS_ENDTEXT	0x1000
+#define LNTPFLGS_PROMPTTEXT	0x0800
 
 typedef unsigned int sclp_cmdw_t;
 
@@ -56,15 +60,15 @@ #define SCLP_CMDW_READ_SCP_INFO		0x00020
 #define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
 
 #define GDS_ID_MDSMU		0x1310
-#define GDS_ID_MDSRouteInfo	0x1311
-#define GDS_ID_AgUnWrkCorr	0x1549
-#define GDS_ID_SNACondReport	0x1532
+#define GDS_ID_MDSROUTEINFO	0x1311
+#define GDS_ID_AGUNWRKCORR	0x1549
+#define GDS_ID_SNACONDREPORT	0x1532
 #define GDS_ID_CPMSU		0x1212
-#define GDS_ID_RoutTargInstr	0x154D
-#define GDS_ID_OpReq		0x8070
-#define GDS_ID_TextCmd		0x1320
+#define GDS_ID_ROUTTARGINSTR	0x154D
+#define GDS_ID_OPREQ		0x8070
+#define GDS_ID_TEXTCMD		0x1320
 
-#define GDS_KEY_SelfDefTextMsg	0x31
+#define GDS_KEY_SELFDEFTEXTMSG	0x31
 
 typedef u32 sccb_mask_t;	/* ATTENTION: assumes 32bit mask !!! */
 
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
new file mode 100644
index 0000000..a66b914
--- /dev/null
+++ b/drivers/s390/char/sclp_chp.c
@@ -0,0 +1,196 @@
+/*
+ *  drivers/s390/char/sclp_chp.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/errno.h>
+#include <linux/completion.h>
+#include <asm/sclp.h>
+#include <asm/chpid.h>
+
+#include "sclp.h"
+
+#define TAG	"sclp_chp: "
+
+#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH	0x000f0001
+#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH	0x000e0001
+#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION	0x00030001
+
+static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
+{
+	return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
+}
+
+static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
+{
+	return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
+}
+
+static void chp_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+struct chp_cfg_sccb {
+	struct sccb_header header;
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+struct chp_cfg_data {
+	struct chp_cfg_sccb sccb;
+	struct sclp_req req;
+	struct completion completion;
+} __attribute__((packed));
+
+static int do_configure(sclp_cmdw_t cmd)
+{
+	struct chp_cfg_data *data;
+	int rc;
+
+	/* Prepare sccb. */
+	data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+	data->sccb.header.length = sizeof(struct chp_cfg_sccb);
+	data->req.command = cmd;
+	data->req.sccb = &(data->sccb);
+	data->req.status = SCLP_REQ_FILLED;
+	data->req.callback = chp_callback;
+	data->req.callback_data = &(data->completion);
+	init_completion(&data->completion);
+
+	/* Perform sclp request. */
+	rc = sclp_add_request(&(data->req));
+	if (rc)
+		goto out;
+	wait_for_completion(&data->completion);
+
+	/* Check response .*/
+	if (data->req.status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING TAG "configure channel-path request failed "
+		       "(status=0x%02x)\n", data->req.status);
+		rc = -EIO;
+		goto out;
+	}
+	switch (data->sccb.header.response_code) {
+	case 0x0020:
+	case 0x0120:
+	case 0x0440:
+	case 0x0450:
+		break;
+	default:
+		printk(KERN_WARNING TAG "configure channel-path failed "
+		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
+		       data->sccb.header.response_code);
+		rc = -EIO;
+		break;
+	}
+out:
+	free_page((unsigned long) data);
+
+	return rc;
+}
+
+/**
+ * sclp_chp_configure - perform configure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform configure channel-path command sclp command for specified chpid.
+ * Return 0 after command successfully finished, non-zero otherwise.
+ */
+int sclp_chp_configure(struct chp_id chpid)
+{
+	return do_configure(get_configure_cmdw(chpid));
+}
+
+/**
+ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform deconfigure channel-path command sclp command for specified chpid
+ * and wait for completion. On success return 0. Return non-zero otherwise.
+ */
+int sclp_chp_deconfigure(struct chp_id chpid)
+{
+	return do_configure(get_deconfigure_cmdw(chpid));
+}
+
+struct chp_info_sccb {
+	struct sccb_header header;
+	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+struct chp_info_data {
+	struct chp_info_sccb sccb;
+	struct sclp_req req;
+	struct completion completion;
+} __attribute__((packed));
+
+/**
+ * sclp_chp_read_info - perform read channel-path information sclp command
+ * @info: resulting channel-path information data
+ *
+ * Perform read channel-path information sclp command and wait for completion.
+ * On success, store channel-path information in @info and return 0. Return
+ * non-zero otherwise.
+ */
+int sclp_chp_read_info(struct sclp_chp_info *info)
+{
+	struct chp_info_data *data;
+	int rc;
+
+	/* Prepare sccb. */
+	data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!data)
+		return -ENOMEM;
+	data->sccb.header.length = sizeof(struct chp_info_sccb);
+	data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
+	data->req.sccb = &(data->sccb);
+	data->req.status = SCLP_REQ_FILLED;
+	data->req.callback = chp_callback;
+	data->req.callback_data = &(data->completion);
+	init_completion(&data->completion);
+
+	/* Perform sclp request. */
+	rc = sclp_add_request(&(data->req));
+	if (rc)
+		goto out;
+	wait_for_completion(&data->completion);
+
+	/* Check response .*/
+	if (data->req.status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING TAG "read channel-path info request failed "
+		       "(status=0x%02x)\n", data->req.status);
+		rc = -EIO;
+		goto out;
+	}
+	if (data->sccb.header.response_code != 0x0010) {
+		printk(KERN_WARNING TAG "read channel-path info failed "
+		       "(response=0x%04x)\n", data->sccb.header.response_code);
+		rc = -EIO;
+		goto out;
+	}
+	memcpy(info->recognized, data->sccb.recognized,
+	       SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->standby, data->sccb.standby,
+	       SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->configured, data->sccb.configured,
+	       SCLP_CHP_INFO_MASK_SIZE);
+out:
+	free_page((unsigned long) data);
+
+	return rc;
+}
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
new file mode 100644
index 0000000..5322e5e
--- /dev/null
+++ b/drivers/s390/char/sclp_config.c
@@ -0,0 +1,75 @@
+/*
+ *  drivers/s390/char/sclp_config.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/cpu.h>
+#include <linux/sysdev.h>
+#include <linux/workqueue.h>
+#include "sclp.h"
+
+#define TAG	"sclp_config: "
+
+struct conf_mgm_data {
+	u8 reserved;
+	u8 ev_qualifier;
+} __attribute__((packed));
+
+#define EV_QUAL_CAP_CHANGE	3
+
+static struct work_struct sclp_cpu_capability_work;
+
+static void sclp_cpu_capability_notify(struct work_struct *work)
+{
+	int cpu;
+	struct sys_device *sysdev;
+
+	printk(KERN_WARNING TAG "cpu capability changed.\n");
+	lock_cpu_hotplug();
+	for_each_online_cpu(cpu) {
+		sysdev = get_cpu_sysdev(cpu);
+		kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
+	}
+	unlock_cpu_hotplug();
+}
+
+static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
+{
+	struct conf_mgm_data *cdata;
+
+	cdata = (struct conf_mgm_data *)(evbuf + 1);
+	if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE)
+		schedule_work(&sclp_cpu_capability_work);
+}
+
+static struct sclp_register sclp_conf_register =
+{
+	.receive_mask = EVTYP_CONFMGMDATA_MASK,
+	.receiver_fn  = sclp_conf_receiver_fn,
+};
+
+static int __init sclp_conf_init(void)
+{
+	int rc;
+
+	INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
+
+	rc = sclp_register(&sclp_conf_register);
+	if (rc) {
+		printk(KERN_ERR TAG "failed to register (%d).\n", rc);
+		return rc;
+	}
+
+	if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK)) {
+		printk(KERN_WARNING TAG "no configuration management.\n");
+		sclp_unregister(&sclp_conf_register);
+		rc = -ENOSYS;
+	}
+	return rc;
+}
+
+__initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 65aa2c8..29fe2a5 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -46,7 +46,7 @@ struct cpi_sccb {
 /* Event type structure for write message and write priority message */
 static struct sclp_register sclp_cpi_event =
 {
-	.send_mask = EvTyp_CtlProgIdent_Mask
+	.send_mask = EVTYP_CTLPROGIDENT_MASK
 };
 
 MODULE_LICENSE("GPL");
@@ -201,7 +201,7 @@ cpi_module_init(void)
 		       "console.\n");
 		return -EINVAL;
 	}
-	if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) {
+	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
 		printk(KERN_WARNING "cpi: no control program identification "
 		       "support\n");
 		sclp_unregister(&sclp_cpi_event);
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index baa8fe6..45ff25e 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -43,7 +43,7 @@ sclp_quiesce_handler(struct evbuf_header
 }
 
 static struct sclp_register sclp_quiesce_event = {
-	.receive_mask = EvTyp_SigQuiesce_Mask,
+	.receive_mask = EVTYP_SIGQUIESCE_MASK,
 	.receiver_fn = sclp_quiesce_handler
 };
 
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 2486783..bbd5b8b 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -30,7 +30,7 @@ #define MAX_SCCB_ROOM (PAGE_SIZE - sizeo
 
 /* Event type structure for write message and write priority message */
 static struct sclp_register sclp_rw_event = {
-	.send_mask = EvTyp_Msg_Mask | EvTyp_PMsgCmd_Mask
+	.send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK
 };
 
 /*
@@ -64,7 +64,7 @@ sclp_make_buffer(void *page, unsigned sh
 	memset(sccb, 0, sizeof(struct write_sccb));
 	sccb->header.length = sizeof(struct write_sccb);
 	sccb->msg_buf.header.length = sizeof(struct msg_buf);
-	sccb->msg_buf.header.type = EvTyp_Msg;
+	sccb->msg_buf.header.type = EVTYP_MSG;
 	sccb->msg_buf.mdb.header.length = sizeof(struct mdb);
 	sccb->msg_buf.mdb.header.type = 1;
 	sccb->msg_buf.mdb.header.tag = 0xD4C4C240;	/* ebcdic "MDB " */
@@ -114,7 +114,7 @@ sclp_initialize_mto(struct sclp_buffer *
 	memset(mto, 0, sizeof(struct mto));
 	mto->length = sizeof(struct mto);
 	mto->type = 4;	/* message text object */
-	mto->line_type_flags = LnTpFlgs_EndText; /* end text */
+	mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
 
 	/* set pointer to first byte after struct mto. */
 	buffer->current_line = (char *) (mto + 1);
@@ -215,7 +215,7 @@ sclp_write(struct sclp_buffer *buffer, c
 		case '\a':	/* bell, one for several times	*/
 			/* set SCLP sound alarm bit in General Object */
 			buffer->sccb->msg_buf.mdb.go.general_msg_flags |=
-				GnrlMsgFlgs_SndAlrm;
+				GNRLMSGFLGS_SNDALRM;
 			break;
 		case '\t':	/* horizontal tabulator	 */
 			/* check if new mto needs to be created */
@@ -452,12 +452,12 @@ sclp_emit_buffer(struct sclp_buffer *buf
 		return -EIO;
 
 	sccb = buffer->sccb;
-	if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask)
+	if (sclp_rw_event.sclp_send_mask & EVTYP_MSG_MASK)
 		/* Use normal write message */
-		sccb->msg_buf.header.type = EvTyp_Msg;
-	else if (sclp_rw_event.sclp_send_mask & EvTyp_PMsgCmd_Mask)
+		sccb->msg_buf.header.type = EVTYP_MSG;
+	else if (sclp_rw_event.sclp_send_mask & EVTYP_PMSGCMD_MASK)
 		/* Use write priority message */
-		sccb->msg_buf.header.type = EvTyp_PMsgCmd;
+		sccb->msg_buf.header.type = EVTYP_PMSGCMD;
 	else
 		return -ENOSYS;
 	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
new file mode 100644
index 0000000..52283da
--- /dev/null
+++ b/drivers/s390/char/sclp_sdias.c
@@ -0,0 +1,255 @@
+/*
+ * Sclp "store data in absolut storage"
+ *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Michael Holzheu
+ */
+
+#include <linux/sched.h>
+#include <asm/sclp.h>
+#include <asm/debug.h>
+#include <asm/ipl.h>
+#include "sclp.h"
+#include "sclp_rw.h"
+
+#define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
+#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x )
+
+#define SDIAS_RETRIES 300
+#define SDIAS_SLEEP_TICKS 50
+
+#define EQ_STORE_DATA	0x0
+#define EQ_SIZE		0x1
+#define DI_FCP_DUMP	0x0
+#define ASA_SIZE_32	0x0
+#define ASA_SIZE_64	0x1
+#define EVSTATE_ALL_STORED	0x0
+#define EVSTATE_NO_DATA		0x3
+#define EVSTATE_PART_STORED	0x10
+
+static struct debug_info *sdias_dbf;
+
+static struct sclp_register sclp_sdias_register = {
+	.send_mask = EVTYP_SDIAS_MASK,
+};
+
+struct sdias_evbuf {
+	struct	evbuf_header hdr;
+	u8	event_qual;
+	u8	data_id;
+	u64	reserved2;
+	u32	event_id;
+	u16	reserved3;
+	u8	asa_size;
+	u8	event_status;
+	u32	reserved4;
+	u32	blk_cnt;
+	u64	asa;
+	u32	reserved5;
+	u32	fbn;
+	u32	reserved6;
+	u32	lbn;
+	u16	reserved7;
+	u16	dbs;
+} __attribute__((packed));
+
+struct sdias_sccb {
+	struct sccb_header  hdr;
+	struct sdias_evbuf  evbuf;
+} __attribute__((packed));
+
+static struct sdias_sccb sccb __attribute__((aligned(4096)));
+
+static int sclp_req_done;
+static wait_queue_head_t sdias_wq;
+static DEFINE_MUTEX(sdias_mutex);
+
+static void sdias_callback(struct sclp_req *request, void *data)
+{
+	struct sdias_sccb *sccb;
+
+	sccb = (struct sdias_sccb *) request->sccb;
+	sclp_req_done = 1;
+	wake_up(&sdias_wq); /* Inform caller, that request is complete */
+	TRACE("callback done\n");
+}
+
+static int sdias_sclp_send(struct sclp_req *req)
+{
+	int retries;
+	int rc;
+
+	for (retries = SDIAS_RETRIES; retries; retries--) {
+		sclp_req_done = 0;
+		TRACE("add request\n");
+		rc = sclp_add_request(req);
+		if (rc) {
+			/* not initiated, wait some time and retry */
+			set_current_state(TASK_INTERRUPTIBLE);
+			TRACE("add request failed: rc = %i\n",rc);
+			schedule_timeout(SDIAS_SLEEP_TICKS);
+			continue;
+		}
+		/* initiated, wait for completion of service call */
+		wait_event(sdias_wq, (sclp_req_done == 1));
+		if (req->status == SCLP_REQ_FAILED) {
+			TRACE("sclp request failed\n");
+			rc = -EIO;
+			continue;
+		}
+		TRACE("request done\n");
+		break;
+	}
+	return rc;
+}
+
+/*
+ * Get number of blocks (4K) available in the HSA
+ */
+int sclp_sdias_blk_count(void)
+{
+	struct sclp_req request;
+	int rc;
+
+	mutex_lock(&sdias_mutex);
+
+	memset(&sccb, 0, sizeof(sccb));
+	memset(&request, 0, sizeof(request));
+
+	sccb.hdr.length = sizeof(sccb);
+	sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf);
+	sccb.evbuf.hdr.type = EVTYP_SDIAS;
+	sccb.evbuf.event_qual = EQ_SIZE;
+	sccb.evbuf.data_id = DI_FCP_DUMP;
+	sccb.evbuf.event_id = 4712;
+	sccb.evbuf.dbs = 1;
+
+	request.sccb = &sccb;
+	request.command = SCLP_CMDW_WRITE_EVENT_DATA;
+	request.status = SCLP_REQ_FILLED;
+	request.callback = sdias_callback;
+
+	rc = sdias_sclp_send(&request);
+	if (rc) {
+		ERROR_MSG("sclp_send failed for get_nr_blocks\n");
+		goto out;
+	}
+	if (sccb.hdr.response_code != 0x0020) {
+		TRACE("send failed: %x\n", sccb.hdr.response_code);
+		rc = -EIO;
+		goto out;
+	}
+
+	switch (sccb.evbuf.event_status) {
+		case 0:
+			rc = sccb.evbuf.blk_cnt;
+			break;
+		default:
+			ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status);
+			rc = -EIO;
+			goto out;
+	}
+	TRACE("%i blocks\n", rc);
+out:
+	mutex_unlock(&sdias_mutex);
+	return rc;
+}
+
+/*
+ * Copy from HSA to absolute storage (not reentrant):
+ *
+ * @dest     : Address of buffer where data should be copied
+ * @start_blk: Start Block (beginning with 1)
+ * @nr_blks  : Number of 4K blocks to copy
+ *
+ * Return Value: 0 : Requested 'number' of blocks of data copied
+ *		 <0: ERROR - negative event status
+ */
+int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
+{
+	struct sclp_req request;
+	int rc;
+
+	mutex_lock(&sdias_mutex);
+
+	memset(&sccb, 0, sizeof(sccb));
+	memset(&request, 0, sizeof(request));
+
+	sccb.hdr.length = sizeof(sccb);
+	sccb.evbuf.hdr.length = sizeof(struct sdias_evbuf);
+	sccb.evbuf.hdr.type = EVTYP_SDIAS;
+	sccb.evbuf.hdr.flags = 0;
+	sccb.evbuf.event_qual = EQ_STORE_DATA;
+	sccb.evbuf.data_id = DI_FCP_DUMP;
+	sccb.evbuf.event_id = 4712;
+#ifdef __s390x__
+	sccb.evbuf.asa_size = ASA_SIZE_64;
+#else
+	sccb.evbuf.asa_size = ASA_SIZE_32;
+#endif
+	sccb.evbuf.event_status = 0;
+	sccb.evbuf.blk_cnt = nr_blks;
+	sccb.evbuf.asa = (unsigned long)dest;
+	sccb.evbuf.fbn = start_blk;
+	sccb.evbuf.lbn = 0;
+	sccb.evbuf.dbs = 1;
+
+	request.sccb	 = &sccb;
+	request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
+	request.status	 = SCLP_REQ_FILLED;
+	request.callback = sdias_callback;
+
+	rc = sdias_sclp_send(&request);
+	if (rc) {
+		ERROR_MSG("sclp_send failed: %x\n", rc);
+		goto out;
+	}
+	if (sccb.hdr.response_code != 0x0020) {
+		TRACE("copy failed: %x\n", sccb.hdr.response_code);
+		rc = -EIO;
+		goto out;
+	}
+
+	switch (sccb.evbuf.event_status) {
+		case EVSTATE_ALL_STORED:
+			TRACE("all stored\n");
+		case EVSTATE_PART_STORED:
+			TRACE("part stored: %i\n", sccb.evbuf.blk_cnt);
+			break;
+		case EVSTATE_NO_DATA:
+			TRACE("no data\n");
+		default:
+			ERROR_MSG("Error from SCLP while copying hsa. "
+				  "Event status = %x\n",
+				sccb.evbuf.event_status);
+			rc = -EIO;
+	}
+out:
+	mutex_unlock(&sdias_mutex);
+	return rc;
+}
+
+int __init sdias_init(void)
+{
+	int rc;
+
+	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+		return 0;
+	sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
+	debug_register_view(sdias_dbf, &debug_sprintf_view);
+	debug_set_level(sdias_dbf, 6);
+	rc = sclp_register(&sclp_sdias_register);
+	if (rc) {
+		ERROR_MSG("sclp register failed\n");
+		return rc;
+	}
+	init_waitqueue_head(&sdias_wq);
+	TRACE("init done\n");
+	return 0;
+}
+
+void __exit sdias_exit(void)
+{
+	debug_unregister(sdias_dbf);
+	sclp_unregister(&sclp_sdias_register);
+}
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 076816b..e3b3d39 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -648,7 +648,7 @@ sclp_eval_textcmd(struct gds_subvector *
 	subvec = start;
 	while (subvec < end) {
 		subvec = find_gds_subvector(subvec, end,
-					    GDS_KEY_SelfDefTextMsg);
+					    GDS_KEY_SELFDEFTEXTMSG);
 		if (!subvec)
 			break;
 		sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
@@ -664,7 +664,7 @@ sclp_eval_cpmsu(struct gds_vector *start
 
 	vec = start;
 	while (vec < end) {
-		vec = find_gds_vector(vec, end, GDS_ID_TextCmd);
+		vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD);
 		if (!vec)
 			break;
 		sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
@@ -703,7 +703,7 @@ sclp_tty_state_change(struct sclp_regist
 
 static struct sclp_register sclp_input_event =
 {
-	.receive_mask = EvTyp_OpCmd_Mask | EvTyp_PMsgCmd_Mask,
+	.receive_mask = EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK,
 	.state_change_fn = sclp_tty_state_change,
 	.receiver_fn = sclp_tty_receiver
 };
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index f77dc33..7263347 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -99,8 +99,8 @@ static void sclp_vt220_emit_current(void
 
 /* Registration structure for our interest in SCLP event buffers */
 static struct sclp_register sclp_vt220_register = {
-	.send_mask		= EvTyp_VT220Msg_Mask,
-	.receive_mask		= EvTyp_VT220Msg_Mask,
+	.send_mask		= EVTYP_VT220MSG_MASK,
+	.receive_mask		= EVTYP_VT220MSG_MASK,
 	.state_change_fn	= NULL,
 	.receiver_fn		= sclp_vt220_receiver_fn
 };
@@ -202,7 +202,7 @@ sclp_vt220_callback(struct sclp_req *req
 static int
 __sclp_vt220_emit(struct sclp_vt220_request *request)
 {
-	if (!(sclp_vt220_register.sclp_send_mask & EvTyp_VT220Msg_Mask)) {
+	if (!(sclp_vt220_register.sclp_send_mask & EVTYP_VT220MSG_MASK)) {
 		request->sclp_req.status = SCLP_REQ_FAILED;
 		return -EIO;
 	}
@@ -284,7 +284,7 @@ sclp_vt220_initialize_page(void *page)
 	sccb->header.length = sizeof(struct sclp_vt220_sccb);
 	sccb->header.function_code = SCLP_NORMAL_WRITE;
 	sccb->header.response_code = 0x0000;
-	sccb->evbuf.type = EvTyp_VT220Msg;
+	sccb->evbuf.type = EVTYP_VT220MSG;
 	sccb->evbuf.length = sizeof(struct evbuf_header);
 
 	return request;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index bb4ff53..3b52f5c 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -103,6 +103,7 @@ enum tape_op {
 	TO_CRYPT_OFF,	/* Disable encrpytion */
 	TO_KEKL_SET,	/* Set KEK label */
 	TO_KEKL_QUERY,	/* Query KEK label */
+	TO_RDC,		/* Read device characteristics */
 	TO_SIZE,	/* #entries in tape_op_t */
 };
 
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 50f5eda..7e2b2ab 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -788,6 +788,7 @@ tape_3590_done(struct tape_device *devic
 	case TO_SIZE:
 	case TO_KEKL_SET:
 	case TO_KEKL_QUERY:
+	case TO_RDC:
 		break;
 	}
 	return TAPE_IO_SUCCESS;
@@ -1549,6 +1550,26 @@ tape_3590_irq(struct tape_device *device
 	return TAPE_IO_STOP;
 }
 
+
+static int tape_3590_read_dev_chars(struct tape_device *device,
+				    struct tape_3590_rdc_data *rdc_data)
+{
+	int rc;
+	struct tape_request *request;
+
+	request = tape_alloc_request(1, sizeof(*rdc_data));
+	if (IS_ERR(request))
+		return PTR_ERR(request);
+	request->op = TO_RDC;
+	tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data),
+		     request->cpdata);
+	rc = tape_do_io(device, request);
+	if (rc == 0)
+		memcpy(rdc_data, request->cpdata, sizeof(*rdc_data));
+	tape_free_request(request);
+	return rc;
+}
+
 /*
  * Setup device function
  */
@@ -1557,7 +1578,7 @@ tape_3590_setup_device(struct tape_devic
 {
 	int rc;
 	struct tape_3590_disc_data *data;
-	char *rdc_data;
+	struct tape_3590_rdc_data *rdc_data;
 
 	DBF_EVENT(6, "3590 device setup\n");
 	data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
@@ -1566,12 +1587,12 @@ tape_3590_setup_device(struct tape_devic
 	data->read_back_op = READ_PREVIOUS;
 	device->discdata = data;
 
-	rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+	rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA);
 	if (!rdc_data) {
 		rc = -ENOMEM;
 		goto fail_kmalloc;
 	}
-	rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+	rc = tape_3590_read_dev_chars(device, rdc_data);
 	if (rc) {
 		DBF_LH(3, "Read device characteristics failed!\n");
 		goto fail_kmalloc;
@@ -1579,7 +1600,7 @@ tape_3590_setup_device(struct tape_devic
 	rc = tape_std_assign(device);
 	if (rc)
 		goto fail_rdc_data;
-	if (rdc_data[31] == 0x13) {
+	if (rdc_data->data[31] == 0x13) {
 		PRINT_INFO("Device has crypto support\n");
 		data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
 		tape_3592_disable_crypt(device);
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index aa51388..4534055 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -129,6 +129,10 @@ struct tape_3590_med_sense {
 	char pad2[116];
 } __attribute__ ((packed));
 
+struct tape_3590_rdc_data {
+	char data[64];
+} __attribute__ ((packed));
+
 /* Datastructures for 3592 encryption support */
 
 struct tape3592_kekl {
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index e2a8a1a..2fae633 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -73,7 +73,7 @@ const char *tape_op_verbose[TO_SIZE] =
 	[TO_DIS] = "DIS",	[TO_ASSIGN] = "ASS",
 	[TO_UNASSIGN] = "UAS",  [TO_CRYPT_ON] = "CON",
 	[TO_CRYPT_OFF] = "COF",	[TO_KEKL_SET] = "KLS",
-	[TO_KEKL_QUERY] = "KLQ",
+	[TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC",
 };
 
 static int
@@ -911,6 +911,7 @@ __tape_start_request(struct tape_device 
 		case TO_ASSIGN:
 		case TO_UNASSIGN:
 		case TO_READ_ATTMSG:
+		case TO_RDC:
 			if (device->tape_state == TS_INIT)
 				break;
 			if (device->tape_state == TS_UNUSED)
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index b87d3b0..a5a00e9 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -125,7 +125,7 @@ static struct vmlogrdr_priv_t sys_ser[] 
 	  .recording_name = "EREP",
 	  .minor_num      = 0,
 	  .buffer_free    = 1,
-	  .priv_lock      = SPIN_LOCK_UNLOCKED,
+	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[0].priv_lock),
 	  .autorecording  = 1,
 	  .autopurge      = 1,
 	},
@@ -134,7 +134,7 @@ static struct vmlogrdr_priv_t sys_ser[] 
 	  .recording_name = "ACCOUNT",
 	  .minor_num      = 1,
 	  .buffer_free    = 1,
-	  .priv_lock      = SPIN_LOCK_UNLOCKED,
+	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[1].priv_lock),
 	  .autorecording  = 1,
 	  .autopurge      = 1,
 	},
@@ -143,7 +143,7 @@ static struct vmlogrdr_priv_t sys_ser[] 
 	  .recording_name = "SYMPTOM",
 	  .minor_num      = 2,
 	  .buffer_free    = 1,
-	  .priv_lock      = SPIN_LOCK_UNLOCKED,
+	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[2].priv_lock),
 	  .autorecording  = 1,
 	  .autopurge      = 1,
 	}
@@ -385,6 +385,9 @@ static int vmlogrdr_release (struct inod
 
 	struct vmlogrdr_priv_t * logptr = filp->private_data;
 
+	iucv_path_sever(logptr->path, NULL);
+	kfree(logptr->path);
+	logptr->path = NULL;
 	if (logptr->autorecording) {
 		ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
 		if (ret)
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
new file mode 100644
index 0000000..89d4393
--- /dev/null
+++ b/drivers/s390/char/zcore.c
@@ -0,0 +1,651 @@
+/*
+ * zcore module to export memory content and register sets for creating system
+ * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
+ * dump format as s390 standalone dumps.
+ *
+ * For more information please refer to Documentation/s390/zfcpdump.txt
+ *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Michael Holzheu
+ */
+
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/utsname.h>
+#include <linux/debugfs.h>
+#include <asm/ipl.h>
+#include <asm/sclp.h>
+#include <asm/setup.h>
+#include <asm/sigp.h>
+#include <asm/uaccess.h>
+#include <asm/debug.h>
+#include <asm/processor.h>
+#include <asm/irqflags.h>
+
+#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
+#define MSG(x...) printk( KERN_ALERT x )
+#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x )
+
+#define TO_USER		0
+#define TO_KERNEL	1
+
+enum arch_id {
+	ARCH_S390	= 0,
+	ARCH_S390X	= 1,
+};
+
+/* dump system info */
+
+struct sys_info {
+	enum arch_id	arch;
+	unsigned long	sa_base;
+	u32		sa_size;
+	int		cpu_map[NR_CPUS];
+	unsigned long	mem_size;
+	union save_area	lc_mask;
+};
+
+static struct sys_info sys_info;
+static struct debug_info *zcore_dbf;
+static int hsa_available;
+static struct dentry *zcore_dir;
+static struct dentry *zcore_file;
+
+/*
+ * Copy memory from HSA to kernel or user memory (not reentrant):
+ *
+ * @dest:  Kernel or user buffer where memory should be copied to
+ * @src:   Start address within HSA where data should be copied
+ * @count: Size of buffer, which should be copied
+ * @mode:  Either TO_KERNEL or TO_USER
+ */
+static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
+{
+	int offs, blk_num;
+	static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+
+	if (count == 0)
+		return 0;
+
+	/* copy first block */
+	offs = 0;
+	if ((src % PAGE_SIZE) != 0) {
+		blk_num = src / PAGE_SIZE + 2;
+		if (sclp_sdias_copy(buf, blk_num, 1)) {
+			TRACE("sclp_sdias_copy() failed\n");
+			return -EIO;
+		}
+		offs = min((PAGE_SIZE - (src % PAGE_SIZE)), count);
+		if (mode == TO_USER) {
+			if (copy_to_user((__force __user void*) dest,
+					 buf + (src % PAGE_SIZE), offs))
+				return -EFAULT;
+		} else
+			memcpy(dest, buf + (src % PAGE_SIZE), offs);
+	}
+	if (offs == count)
+		goto out;
+
+	/* copy middle */
+	for (; (offs + PAGE_SIZE) <= count; offs += PAGE_SIZE) {
+		blk_num = (src + offs) / PAGE_SIZE + 2;
+		if (sclp_sdias_copy(buf, blk_num, 1)) {
+			TRACE("sclp_sdias_copy() failed\n");
+			return -EIO;
+		}
+		if (mode == TO_USER) {
+			if (copy_to_user((__force __user void*) dest + offs,
+					 buf, PAGE_SIZE))
+				return -EFAULT;
+		} else
+			memcpy(dest + offs, buf, PAGE_SIZE);
+	}
+	if (offs == count)
+		goto out;
+
+	/* copy last block */
+	blk_num = (src + offs) / PAGE_SIZE + 2;
+	if (sclp_sdias_copy(buf, blk_num, 1)) {
+		TRACE("sclp_sdias_copy() failed\n");
+		return -EIO;
+	}
+	if (mode == TO_USER) {
+		if (copy_to_user((__force __user void*) dest + offs, buf,
+				 PAGE_SIZE))
+			return -EFAULT;
+	} else
+		memcpy(dest + offs, buf, count - offs);
+out:
+	return 0;
+}
+
+static int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
+{
+	return memcpy_hsa((void __force *) dest, src, count, TO_USER);
+}
+
+static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
+{
+	return memcpy_hsa(dest, src, count, TO_KERNEL);
+}
+
+static int memcpy_real(void *dest, unsigned long src, size_t count)
+{
+	unsigned long flags;
+	int rc = -EFAULT;
+	register unsigned long _dest asm("2") = (unsigned long) dest;
+	register unsigned long _len1 asm("3") = (unsigned long) count;
+	register unsigned long _src  asm("4") = src;
+	register unsigned long _len2 asm("5") = (unsigned long) count;
+
+	if (count == 0)
+		return 0;
+	flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+	asm volatile (
+		"0:	mvcle	%1,%2,0x0\n"
+		"1:	jo	0b\n"
+		"	lhi	%0,0x0\n"
+		"2:\n"
+		EX_TABLE(1b,2b)
+		: "+d" (rc)
+		: "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+		: "cc", "memory");
+	__raw_local_irq_ssm(flags);
+
+	return rc;
+}
+
+static int memcpy_real_user(__user void *dest, unsigned long src, size_t count)
+{
+	static char buf[4096];
+	int offs = 0, size;
+
+	while (offs < count) {
+		size = min(sizeof(buf), count - offs);
+		if (memcpy_real(buf, src + offs, size))
+			return -EFAULT;
+		if (copy_to_user(dest + offs, buf, size))
+			return -EFAULT;
+		offs += size;
+	}
+	return 0;
+}
+
+#ifdef __s390x__
+/*
+ * Convert s390x (64 bit) cpu info to s390 (32 bit) cpu info
+ */
+static void __init s390x_to_s390_regs(union save_area *out, union save_area *in,
+				      int cpu)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		out->s390.gp_regs[i] = in->s390x.gp_regs[i] & 0x00000000ffffffff;
+		out->s390.acc_regs[i] = in->s390x.acc_regs[i];
+		out->s390.ctrl_regs[i] =
+			in->s390x.ctrl_regs[i] & 0x00000000ffffffff;
+	}
+	/* locore for 31 bit has only space for fpregs 0,2,4,6 */
+	out->s390.fp_regs[0] = in->s390x.fp_regs[0];
+	out->s390.fp_regs[1] = in->s390x.fp_regs[2];
+	out->s390.fp_regs[2] = in->s390x.fp_regs[4];
+	out->s390.fp_regs[3] = in->s390x.fp_regs[6];
+	memcpy(&(out->s390.psw[0]), &(in->s390x.psw[0]), 4);
+	out->s390.psw[1] |= 0x8; /* set bit 12 */
+	memcpy(&(out->s390.psw[4]),&(in->s390x.psw[12]), 4);
+	out->s390.psw[4] |= 0x80; /* set (31bit) addressing bit */
+	out->s390.pref_reg = in->s390x.pref_reg;
+	out->s390.timer = in->s390x.timer;
+	out->s390.clk_cmp = in->s390x.clk_cmp;
+}
+
+static void __init s390x_to_s390_save_areas(void)
+{
+	int i = 1;
+	static union save_area tmp;
+
+	while (zfcpdump_save_areas[i]) {
+		s390x_to_s390_regs(&tmp, zfcpdump_save_areas[i], i);
+		memcpy(zfcpdump_save_areas[i], &tmp, sizeof(tmp));
+		i++;
+	}
+}
+
+#endif /* __s390x__ */
+
+static int __init init_cpu_info(enum arch_id arch)
+{
+	union save_area *sa;
+
+	/* get info for boot cpu from lowcore, stored in the HSA */
+
+	sa = kmalloc(sizeof(*sa), GFP_KERNEL);
+	if (!sa) {
+		ERROR_MSG("kmalloc failed: %s: %i\n",__FUNCTION__, __LINE__);
+		return -ENOMEM;
+	}
+	if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) {
+		ERROR_MSG("could not copy from HSA\n");
+		kfree(sa);
+		return -EIO;
+	}
+	zfcpdump_save_areas[0] = sa;
+
+#ifdef __s390x__
+	/* convert s390x regs to s390, if we are dumping an s390 Linux */
+
+	if (arch == ARCH_S390)
+		s390x_to_s390_save_areas();
+#endif
+
+	return 0;
+}
+
+static DEFINE_MUTEX(zcore_mutex);
+
+#define DUMP_VERSION	0x3
+#define DUMP_MAGIC	0xa8190173618f23fdULL
+#define DUMP_ARCH_S390X	2
+#define DUMP_ARCH_S390	1
+#define HEADER_SIZE	4096
+
+/* dump header dumped according to s390 crash dump format */
+
+struct zcore_header {
+	u64 magic;
+	u32 version;
+	u32 header_size;
+	u32 dump_level;
+	u32 page_size;
+	u64 mem_size;
+	u64 mem_start;
+	u64 mem_end;
+	u32 num_pages;
+	u32 pad1;
+	u64 tod;
+	cpuid_t cpu_id;
+	u32 arch_id;
+	u32 build_arch;
+	char pad2[4016];
+} __attribute__((packed,__aligned__(16)));
+
+static struct zcore_header zcore_header = {
+	.magic		= DUMP_MAGIC,
+	.version	= DUMP_VERSION,
+	.header_size	= 4096,
+	.dump_level	= 0,
+	.page_size	= PAGE_SIZE,
+	.mem_start	= 0,
+#ifdef __s390x__
+	.build_arch	= DUMP_ARCH_S390X,
+#else
+	.build_arch	= DUMP_ARCH_S390,
+#endif
+};
+
+/*
+ * Copy lowcore info to buffer. Use map in order to copy only register parts.
+ *
+ * @buf:    User buffer
+ * @sa:     Pointer to save area
+ * @sa_off: Offset in save area to copy
+ * @len:    Number of bytes to copy
+ */
+static int copy_lc(void __user *buf, void *sa, int sa_off, int len)
+{
+	int i;
+	char *lc_mask = (char*)&sys_info.lc_mask;
+
+	for (i = 0; i < len; i++) {
+		if (!lc_mask[i + sa_off])
+			continue;
+		if (copy_to_user(buf + i, sa + sa_off + i, 1))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+/*
+ * Copy lowcores info to memory, if necessary
+ *
+ * @buf:   User buffer
+ * @addr:  Start address of buffer in dump memory
+ * @count: Size of buffer
+ */
+static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
+{
+	unsigned long end;
+	int i = 0;
+
+	if (count == 0)
+		return 0;
+
+	end = start + count;
+	while (zfcpdump_save_areas[i]) {
+		unsigned long cp_start, cp_end; /* copy range */
+		unsigned long sa_start, sa_end; /* save area range */
+		unsigned long prefix;
+		unsigned long sa_off, len, buf_off;
+
+		if (sys_info.arch == ARCH_S390)
+			prefix = zfcpdump_save_areas[i]->s390.pref_reg;
+		else
+			prefix = zfcpdump_save_areas[i]->s390x.pref_reg;
+
+		sa_start = prefix + sys_info.sa_base;
+		sa_end = prefix + sys_info.sa_base + sys_info.sa_size;
+
+		if ((end < sa_start) || (start > sa_end))
+			goto next;
+		cp_start = max(start, sa_start);
+		cp_end = min(end, sa_end);
+
+		buf_off = cp_start - start;
+		sa_off = cp_start - sa_start;
+		len = cp_end - cp_start;
+
+		TRACE("copy_lc for: %lx\n", start);
+		if (copy_lc(buf + buf_off, zfcpdump_save_areas[i], sa_off, len))
+			return -EFAULT;
+next:
+		i++;
+	}
+	return 0;
+}
+
+/*
+ * Read routine for zcore character device
+ * First 4K are dump header
+ * Next 32MB are HSA Memory
+ * Rest is read from absolute Memory
+ */
+static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
+			  loff_t *ppos)
+{
+	unsigned long mem_start; /* Start address in memory */
+	size_t mem_offs;	 /* Offset in dump memory */
+	size_t hdr_count;	 /* Size of header part of output buffer */
+	size_t size;
+	int rc;
+
+	mutex_lock(&zcore_mutex);
+
+	if (*ppos > (sys_info.mem_size + HEADER_SIZE)) {
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	count = min(count, (size_t) (sys_info.mem_size + HEADER_SIZE - *ppos));
+
+	/* Copy dump header */
+	if (*ppos < HEADER_SIZE) {
+		size = min(count, (size_t) (HEADER_SIZE - *ppos));
+		if (copy_to_user(buf, &zcore_header + *ppos, size)) {
+			rc = -EFAULT;
+			goto fail;
+		}
+		hdr_count = size;
+		mem_start = 0;
+	} else {
+		hdr_count = 0;
+		mem_start = *ppos - HEADER_SIZE;
+	}
+
+	mem_offs = 0;
+
+	/* Copy from HSA data */
+	if (*ppos < (ZFCPDUMP_HSA_SIZE + HEADER_SIZE)) {
+		size = min((count - hdr_count), (size_t) (ZFCPDUMP_HSA_SIZE
+			   - mem_start));
+		rc = memcpy_hsa_user(buf + hdr_count, mem_start, size);
+		if (rc)
+			goto fail;
+
+		mem_offs += size;
+	}
+
+	/* Copy from real mem */
+	size = count - mem_offs - hdr_count;
+	rc = memcpy_real_user(buf + hdr_count + mem_offs, mem_start + mem_offs,
+			      size);
+	if (rc)
+		goto fail;
+
+	/*
+	 * Since s390 dump analysis tools like lcrash or crash
+	 * expect register sets in the prefix pages of the cpus,
+	 * we copy them into the read buffer, if necessary.
+	 * buf + hdr_count: Start of memory part of output buffer
+	 * mem_start: Start memory address to copy from
+	 * count - hdr_count: Size of memory area to copy
+	 */
+	if (zcore_add_lc(buf + hdr_count, mem_start, count - hdr_count)) {
+		rc = -EFAULT;
+		goto fail;
+	}
+	*ppos += count;
+fail:
+	mutex_unlock(&zcore_mutex);
+	return (rc < 0) ? rc : count;
+}
+
+static int zcore_open(struct inode *inode, struct file *filp)
+{
+	if (!hsa_available)
+		return -ENODATA;
+	else
+		return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static int zcore_release(struct inode *inode, struct file *filep)
+{
+	diag308(DIAG308_REL_HSA, NULL);
+	hsa_available = 0;
+	return 0;
+}
+
+static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
+{
+	loff_t rc;
+
+	mutex_lock(&zcore_mutex);
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		rc = file->f_pos;
+		break;
+	case 1:
+		file->f_pos += offset;
+		rc = file->f_pos;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&zcore_mutex);
+	return rc;
+}
+
+static struct file_operations zcore_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= zcore_lseek,
+	.read		= zcore_read,
+	.open		= zcore_open,
+	.release	= zcore_release,
+};
+
+
+static void __init set_s390_lc_mask(union save_area *map)
+{
+	memset(&map->s390.ext_save, 0xff, sizeof(map->s390.ext_save));
+	memset(&map->s390.timer, 0xff, sizeof(map->s390.timer));
+	memset(&map->s390.clk_cmp, 0xff, sizeof(map->s390.clk_cmp));
+	memset(&map->s390.psw, 0xff, sizeof(map->s390.psw));
+	memset(&map->s390.pref_reg, 0xff, sizeof(map->s390.pref_reg));
+	memset(&map->s390.acc_regs, 0xff, sizeof(map->s390.acc_regs));
+	memset(&map->s390.fp_regs, 0xff, sizeof(map->s390.fp_regs));
+	memset(&map->s390.gp_regs, 0xff, sizeof(map->s390.gp_regs));
+	memset(&map->s390.ctrl_regs, 0xff, sizeof(map->s390.ctrl_regs));
+}
+
+static void __init set_s390x_lc_mask(union save_area *map)
+{
+	memset(&map->s390x.fp_regs, 0xff, sizeof(map->s390x.fp_regs));
+	memset(&map->s390x.gp_regs, 0xff, sizeof(map->s390x.gp_regs));
+	memset(&map->s390x.psw, 0xff, sizeof(map->s390x.psw));
+	memset(&map->s390x.pref_reg, 0xff, sizeof(map->s390x.pref_reg));
+	memset(&map->s390x.fp_ctrl_reg, 0xff, sizeof(map->s390x.fp_ctrl_reg));
+	memset(&map->s390x.tod_reg, 0xff, sizeof(map->s390x.tod_reg));
+	memset(&map->s390x.timer, 0xff, sizeof(map->s390x.timer));
+	memset(&map->s390x.clk_cmp, 0xff, sizeof(map->s390x.clk_cmp));
+	memset(&map->s390x.acc_regs, 0xff, sizeof(map->s390x.acc_regs));
+	memset(&map->s390x.ctrl_regs, 0xff, sizeof(map->s390x.ctrl_regs));
+}
+
+/*
+ * Initialize dump globals for a given architecture
+ */
+static int __init sys_info_init(enum arch_id arch)
+{
+	switch (arch) {
+	case ARCH_S390X:
+		MSG("DETECTED 'S390X (64 bit) OS'\n");
+		sys_info.sa_base = SAVE_AREA_BASE_S390X;
+		sys_info.sa_size = sizeof(struct save_area_s390x);
+		set_s390x_lc_mask(&sys_info.lc_mask);
+		break;
+	case ARCH_S390:
+		MSG("DETECTED 'S390 (32 bit) OS'\n");
+		sys_info.sa_base = SAVE_AREA_BASE_S390;
+		sys_info.sa_size = sizeof(struct save_area_s390);
+		set_s390_lc_mask(&sys_info.lc_mask);
+		break;
+	default:
+		ERROR_MSG("unknown architecture 0x%x.\n",arch);
+		return -EINVAL;
+	}
+	sys_info.arch = arch;
+	if (init_cpu_info(arch)) {
+		ERROR_MSG("get cpu info failed\n");
+		return -ENOMEM;
+	}
+	sys_info.mem_size = real_memory_size;
+
+	return 0;
+}
+
+static int __init check_sdias(void)
+{
+	int rc, act_hsa_size;
+
+	rc = sclp_sdias_blk_count();
+	if (rc < 0) {
+		ERROR_MSG("Could not determine HSA size\n");
+		return rc;
+	}
+	act_hsa_size = (rc - 1) * PAGE_SIZE;
+	if (act_hsa_size < ZFCPDUMP_HSA_SIZE) {
+		ERROR_MSG("HSA size too small: %i\n", act_hsa_size);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void __init zcore_header_init(int arch, struct zcore_header *hdr)
+{
+	if (arch == ARCH_S390X)
+		hdr->arch_id = DUMP_ARCH_S390X;
+	else
+		hdr->arch_id = DUMP_ARCH_S390;
+	hdr->mem_size = sys_info.mem_size;
+	hdr->mem_end = sys_info.mem_size;
+	hdr->num_pages = sys_info.mem_size / PAGE_SIZE;
+	hdr->tod = get_clock();
+	get_cpu_id(&hdr->cpu_id);
+}
+
+extern int sdias_init(void);
+
+static int __init zcore_init(void)
+{
+	unsigned char arch;
+	int rc;
+
+	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+		return -ENODATA;
+
+	zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long));
+	debug_register_view(zcore_dbf, &debug_sprintf_view);
+	debug_set_level(zcore_dbf, 6);
+
+	TRACE("devno:  %x\n", ipl_info.data.fcp.dev_id.devno);
+	TRACE("wwpn:   %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
+	TRACE("lun:    %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
+
+	rc = sdias_init();
+	if (rc)
+		goto fail;
+
+	rc = check_sdias();
+	if (rc) {
+		ERROR_MSG("Dump initialization failed\n");
+		goto fail;
+	}
+
+	rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
+	if (rc) {
+		ERROR_MSG("sdial memcpy for arch id failed\n");
+		goto fail;
+	}
+
+#ifndef __s390x__
+	if (arch == ARCH_S390X) {
+		ERROR_MSG("32 bit dumper can't dump 64 bit system!\n");
+		rc = -EINVAL;
+		goto fail;
+	}
+#endif
+
+	rc = sys_info_init(arch);
+	if (rc) {
+		ERROR_MSG("arch init failed\n");
+		goto fail;
+	}
+
+	zcore_header_init(arch, &zcore_header);
+
+	zcore_dir = debugfs_create_dir("zcore" , NULL);
+	if (!zcore_dir) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+	zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL,
+					 &zcore_fops);
+	if (!zcore_file) {
+		debugfs_remove(zcore_dir);
+		rc = -ENOMEM;
+		goto fail;
+	}
+	hsa_available = 1;
+	return 0;
+
+fail:
+	diag308(DIAG308_REL_HSA, NULL);
+	return rc;
+}
+
+extern void sdias_exit(void);
+
+static void __exit zcore_exit(void)
+{
+	debug_unregister(zcore_dbf);
+	sdias_exit();
+	diag308(DIAG308_REL_HSA, NULL);
+}
+
+MODULE_AUTHOR("Copyright IBM Corp. 2003,2007");
+MODULE_DESCRIPTION("zcore module for zfcpdump support");
+MODULE_LICENSE("GPL");
+
+subsys_initcall(zcore_init);
+module_exit(zcore_exit);
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index c490c2a..cfaf77b 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,7 +2,7 @@ #
 # Makefile for the S/390 common i/o drivers
 #
 
-obj-y += airq.o blacklist.o chsc.o cio.o css.o
+obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o
 ccw_device-objs += device.o device_fsm.o device_ops.o
 ccw_device-objs += device_id.o device_pgid.o device_status.o
 obj-y += ccw_device.o cmf.o
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 5aeb68e..e5ccda6 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(st
 {
 	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
 
+	mutex_lock(&gdev->reg_mutex);
 	__ccwgroup_remove_symlinks(gdev);
 	device_unregister(dev);
+	mutex_unlock(&gdev->reg_mutex);
 }
 
 static ssize_t
@@ -173,7 +175,8 @@ ccwgroup_create(struct device *root,
 		return -ENOMEM;
 
 	atomic_set(&gdev->onoff, 0);
-
+	mutex_init(&gdev->reg_mutex);
+	mutex_lock(&gdev->reg_mutex);
 	for (i = 0; i < argc; i++) {
 		gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
 
@@ -183,12 +186,12 @@ ccwgroup_create(struct device *root,
 		    || gdev->cdev[i]->id.driver_info !=
 		    gdev->cdev[0]->id.driver_info) {
 			rc = -EINVAL;
-			goto free_dev;
+			goto error;
 		}
 		/* Don't allow a device to belong to more than one group. */
 		if (gdev->cdev[i]->dev.driver_data) {
 			rc = -EINVAL;
-			goto free_dev;
+			goto error;
 		}
 		gdev->cdev[i]->dev.driver_data = gdev;
 	}
@@ -203,9 +206,8 @@ ccwgroup_create(struct device *root,
 			gdev->cdev[0]->dev.bus_id);
 
 	rc = device_register(&gdev->dev);
-	
 	if (rc)
-		goto free_dev;
+		goto error;
 	get_device(&gdev->dev);
 	rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
 
@@ -216,6 +218,7 @@ ccwgroup_create(struct device *root,
 
 	rc = __ccwgroup_create_symlinks(gdev);
 	if (!rc) {
+		mutex_unlock(&gdev->reg_mutex);
 		put_device(&gdev->dev);
 		return 0;
 	}
@@ -224,19 +227,12 @@ ccwgroup_create(struct device *root,
 error:
 	for (i = 0; i < argc; i++)
 		if (gdev->cdev[i]) {
-			put_device(&gdev->cdev[i]->dev);
-			gdev->cdev[i]->dev.driver_data = NULL;
-		}
-	put_device(&gdev->dev);
-	return rc;
-free_dev:
-	for (i = 0; i < argc; i++)
-		if (gdev->cdev[i]) {
 			if (gdev->cdev[i]->dev.driver_data == gdev)
 				gdev->cdev[i]->dev.driver_data = NULL;
 			put_device(&gdev->cdev[i]->dev);
 		}
-	kfree(gdev);
+	mutex_unlock(&gdev->reg_mutex);
+	put_device(&gdev->dev);
 	return rc;
 }
 
@@ -422,8 +418,12 @@ ccwgroup_driver_unregister (struct ccwgr
 	get_driver(&cdriver->driver);
 	while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
 					 __ccwgroup_match_all))) {
-		__ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+		struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+
+		mutex_lock(&gdev->reg_mutex);
+		__ccwgroup_remove_symlinks(gdev);
 		device_unregister(dev);
+		mutex_unlock(&gdev->reg_mutex);
 		put_device(dev);
 	}
 	put_driver(&cdriver->driver);
@@ -444,8 +444,10 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_d
 	if (cdev->dev.driver_data) {
 		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
 		if (get_device(&gdev->dev)) {
+			mutex_lock(&gdev->reg_mutex);
 			if (device_is_registered(&gdev->dev))
 				return gdev;
+			mutex_unlock(&gdev->reg_mutex);
 			put_device(&gdev->dev);
 		}
 		return NULL;
@@ -465,6 +467,7 @@ ccwgroup_remove_ccwdev(struct ccw_device
 	if (gdev) {
 		__ccwgroup_remove_symlinks(gdev);
 		device_unregister(&gdev->dev);
+		mutex_unlock(&gdev->reg_mutex);
 		put_device(&gdev->dev);
 	}
 }
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
new file mode 100644
index 0000000..ac289e6
--- /dev/null
+++ b/drivers/s390/cio/chp.c
@@ -0,0 +1,683 @@
+/*
+ *  drivers/s390/cio/chp.c
+ *
+ *    Copyright IBM Corp. 1999,2007
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/bug.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <asm/errno.h>
+#include <asm/chpid.h>
+#include <asm/sclp.h>
+
+#include "cio.h"
+#include "css.h"
+#include "ioasm.h"
+#include "cio_debug.h"
+#include "chp.h"
+
+#define to_channelpath(device) container_of(device, struct channel_path, dev)
+#define CHP_INFO_UPDATE_INTERVAL	1*HZ
+
+enum cfg_task_t {
+	cfg_none,
+	cfg_configure,
+	cfg_deconfigure
+};
+
+/* Map for pending configure tasks. */
+static enum cfg_task_t chp_cfg_task[__MAX_CSSID + 1][__MAX_CHPID + 1];
+static DEFINE_MUTEX(cfg_lock);
+static int cfg_busy;
+
+/* Map for channel-path status. */
+static struct sclp_chp_info chp_info;
+static DEFINE_MUTEX(info_lock);
+
+/* Time after which channel-path status may be outdated. */
+static unsigned long chp_info_expires;
+
+/* Workqueue to perform pending configure tasks. */
+static struct workqueue_struct *chp_wq;
+static struct work_struct cfg_work;
+
+/* Wait queue for configure completion events. */
+static wait_queue_head_t cfg_wait_queue;
+
+/* Return channel_path struct for given chpid. */
+static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
+{
+	return css[chpid.cssid]->chps[chpid.id];
+}
+
+/* Set vary state for given chpid. */
+static void set_chp_logically_online(struct chp_id chpid, int onoff)
+{
+	chpid_to_chp(chpid)->state = onoff;
+}
+
+/* On succes return 0 if channel-path is varied offline, 1 if it is varied
+ * online. Return -ENODEV if channel-path is not registered. */
+int chp_get_status(struct chp_id chpid)
+{
+	return (chpid_to_chp(chpid) ? chpid_to_chp(chpid)->state : -ENODEV);
+}
+
+/**
+ * chp_get_sch_opm - return opm for subchannel
+ * @sch: subchannel
+ *
+ * Calculate and return the operational path mask (opm) based on the chpids
+ * used by the subchannel and the status of the associated channel-paths.
+ */
+u8 chp_get_sch_opm(struct subchannel *sch)
+{
+	struct chp_id chpid;
+	int opm;
+	int i;
+
+	opm = 0;
+	chp_id_init(&chpid);
+	for (i=0; i < 8; i++) {
+		opm <<= 1;
+		chpid.id = sch->schib.pmcw.chpid[i];
+		if (chp_get_status(chpid) != 0)
+			opm |= 1;
+	}
+	return opm;
+}
+
+/**
+ * chp_is_registered - check if a channel-path is registered
+ * @chpid: channel-path ID
+ *
+ * Return non-zero if a channel-path with the given chpid is registered,
+ * zero otherwise.
+ */
+int chp_is_registered(struct chp_id chpid)
+{
+	return chpid_to_chp(chpid) != NULL;
+}
+
+/*
+ * Function: s390_vary_chpid
+ * Varies the specified chpid online or offline
+ */
+static int s390_vary_chpid(struct chp_id chpid, int on)
+{
+	char dbf_text[15];
+	int status;
+
+	sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
+		chpid.id);
+	CIO_TRACE_EVENT( 2, dbf_text);
+
+	status = chp_get_status(chpid);
+	if (status < 0) {
+		printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
+		       chpid.cssid, chpid.id);
+		return -EINVAL;
+	}
+
+	if (!on && !status) {
+		printk(KERN_ERR "chpid %x.%02x is already offline\n",
+		       chpid.cssid, chpid.id);
+		return -EINVAL;
+	}
+
+	set_chp_logically_online(chpid, on);
+	chsc_chp_vary(chpid, on);
+	return 0;
+}
+
+/*
+ * Channel measurement related functions
+ */
+static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf,
+					  loff_t off, size_t count)
+{
+	struct channel_path *chp;
+	unsigned int size;
+
+	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	if (!chp->cmg_chars)
+		return 0;
+
+	size = sizeof(struct cmg_chars);
+
+	if (off > size)
+		return 0;
+	if (off + count > size)
+		count = size - off;
+	memcpy(buf, chp->cmg_chars + off, count);
+	return count;
+}
+
+static struct bin_attribute chp_measurement_chars_attr = {
+	.attr = {
+		.name = "measurement_chars",
+		.mode = S_IRUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = sizeof(struct cmg_chars),
+	.read = chp_measurement_chars_read,
+};
+
+static void chp_measurement_copy_block(struct cmg_entry *buf,
+				       struct channel_subsystem *css,
+				       struct chp_id chpid)
+{
+	void *area;
+	struct cmg_entry *entry, reference_buf;
+	int idx;
+
+	if (chpid.id < 128) {
+		area = css->cub_addr1;
+		idx = chpid.id;
+	} else {
+		area = css->cub_addr2;
+		idx = chpid.id - 128;
+	}
+	entry = area + (idx * sizeof(struct cmg_entry));
+	do {
+		memcpy(buf, entry, sizeof(*entry));
+		memcpy(&reference_buf, entry, sizeof(*entry));
+	} while (reference_buf.values[0] != buf->values[0]);
+}
+
+static ssize_t chp_measurement_read(struct kobject *kobj, char *buf,
+				    loff_t off, size_t count)
+{
+	struct channel_path *chp;
+	struct channel_subsystem *css;
+	unsigned int size;
+
+	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	css = to_css(chp->dev.parent);
+
+	size = sizeof(struct cmg_entry);
+
+	/* Only allow single reads. */
+	if (off || count < size)
+		return 0;
+	chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->chpid);
+	count = size;
+	return count;
+}
+
+static struct bin_attribute chp_measurement_attr = {
+	.attr = {
+		.name = "measurement",
+		.mode = S_IRUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = sizeof(struct cmg_entry),
+	.read = chp_measurement_read,
+};
+
+void chp_remove_cmg_attr(struct channel_path *chp)
+{
+	device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+	device_remove_bin_file(&chp->dev, &chp_measurement_attr);
+}
+
+int chp_add_cmg_attr(struct channel_path *chp)
+{
+	int ret;
+
+	ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
+	if (ret)
+		return ret;
+	ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
+	if (ret)
+		device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+	return ret;
+}
+
+/*
+ * Files for the channel path entries.
+ */
+static ssize_t chp_status_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+	if (!chp)
+		return 0;
+	return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") :
+		sprintf(buf, "offline\n"));
+}
+
+static ssize_t chp_status_write(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct channel_path *cp = container_of(dev, struct channel_path, dev);
+	char cmd[10];
+	int num_args;
+	int error;
+
+	num_args = sscanf(buf, "%5s", cmd);
+	if (!num_args)
+		return count;
+
+	if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1"))
+		error = s390_vary_chpid(cp->chpid, 1);
+	else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0"))
+		error = s390_vary_chpid(cp->chpid, 0);
+	else
+		error = -EINVAL;
+
+	return error < 0 ? error : count;
+
+}
+
+static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
+
+static ssize_t chp_configure_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct channel_path *cp;
+	int status;
+
+	cp = container_of(dev, struct channel_path, dev);
+	status = chp_info_get_status(cp->chpid);
+	if (status < 0)
+		return status;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+
+static int cfg_wait_idle(void);
+
+static ssize_t chp_configure_write(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct channel_path *cp;
+	int val;
+	char delim;
+
+	if (sscanf(buf, "%d %c", &val, &delim) != 1)
+		return -EINVAL;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+	cp = container_of(dev, struct channel_path, dev);
+	chp_cfg_schedule(cp->chpid, val);
+	cfg_wait_idle();
+
+	return count;
+}
+
+static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write);
+
+static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct channel_path *chp = container_of(dev, struct channel_path, dev);
+
+	if (!chp)
+		return 0;
+	return sprintf(buf, "%x\n", chp->desc.desc);
+}
+
+static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
+
+static ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct channel_path *chp = to_channelpath(dev);
+
+	if (!chp)
+		return 0;
+	if (chp->cmg == -1) /* channel measurements not available */
+		return sprintf(buf, "unknown\n");
+	return sprintf(buf, "%x\n", chp->cmg);
+}
+
+static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);
+
+static ssize_t chp_shared_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct channel_path *chp = to_channelpath(dev);
+
+	if (!chp)
+		return 0;
+	if (chp->shared == -1) /* channel measurements not available */
+		return sprintf(buf, "unknown\n");
+	return sprintf(buf, "%x\n", chp->shared);
+}
+
+static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
+
+static struct attribute * chp_attrs[] = {
+	&dev_attr_status.attr,
+	&dev_attr_configure.attr,
+	&dev_attr_type.attr,
+	&dev_attr_cmg.attr,
+	&dev_attr_shared.attr,
+	NULL,
+};
+
+static struct attribute_group chp_attr_group = {
+	.attrs = chp_attrs,
+};
+
+static void chp_release(struct device *dev)
+{
+	struct channel_path *cp;
+
+	cp = container_of(dev, struct channel_path, dev);
+	kfree(cp);
+}
+
+/**
+ * chp_new - register a new channel-path
+ * @chpid - channel-path ID
+ *
+ * Create and register data structure representing new channel-path. Return
+ * zero on success, non-zero otherwise.
+ */
+int chp_new(struct chp_id chpid)
+{
+	struct channel_path *chp;
+	int ret;
+
+	if (chp_is_registered(chpid))
+		return 0;
+	chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
+	if (!chp)
+		return -ENOMEM;
+
+	/* fill in status, etc. */
+	chp->chpid = chpid;
+	chp->state = 1;
+	chp->dev.parent = &css[chpid.cssid]->device;
+	chp->dev.release = chp_release;
+	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
+		 chpid.id);
+
+	/* Obtain channel path description and fill it in. */
+	ret = chsc_determine_channel_path_description(chpid, &chp->desc);
+	if (ret)
+		goto out_free;
+	if ((chp->desc.flags & 0x80) == 0) {
+		ret = -ENODEV;
+		goto out_free;
+	}
+	/* Get channel-measurement characteristics. */
+	if (css_characteristics_avail && css_chsc_characteristics.scmc
+	    && css_chsc_characteristics.secm) {
+		ret = chsc_get_channel_measurement_chars(chp);
+		if (ret)
+			goto out_free;
+	} else {
+		static int msg_done;
+
+		if (!msg_done) {
+			printk(KERN_WARNING "cio: Channel measurements not "
+			       "available, continuing.\n");
+			msg_done = 1;
+		}
+		chp->cmg = -1;
+	}
+
+	/* make it known to the system */
+	ret = device_register(&chp->dev);
+	if (ret) {
+		printk(KERN_WARNING "%s: could not register %x.%02x\n",
+		       __func__, chpid.cssid, chpid.id);
+		goto out_free;
+	}
+	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
+	if (ret) {
+		device_unregister(&chp->dev);
+		goto out_free;
+	}
+	mutex_lock(&css[chpid.cssid]->mutex);
+	if (css[chpid.cssid]->cm_enabled) {
+		ret = chp_add_cmg_attr(chp);
+		if (ret) {
+			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
+			device_unregister(&chp->dev);
+			mutex_unlock(&css[chpid.cssid]->mutex);
+			goto out_free;
+		}
+	}
+	css[chpid.cssid]->chps[chpid.id] = chp;
+	mutex_unlock(&css[chpid.cssid]->mutex);
+	return ret;
+out_free:
+	kfree(chp);
+	return ret;
+}
+
+/**
+ * chp_get_chp_desc - return newly allocated channel-path description
+ * @chpid: channel-path ID
+ *
+ * On success return a newly allocated copy of the channel-path description
+ * data associated with the given channel-path ID. Return %NULL on error.
+ */
+void *chp_get_chp_desc(struct chp_id chpid)
+{
+	struct channel_path *chp;
+	struct channel_path_desc *desc;
+
+	chp = chpid_to_chp(chpid);
+	if (!chp)
+		return NULL;
+	desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
+	if (!desc)
+		return NULL;
+	memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
+	return desc;
+}
+
+/**
+ * chp_process_crw - process channel-path status change
+ * @id: channel-path ID number
+ * @status: non-zero if channel-path has become available, zero otherwise
+ *
+ * Handle channel-report-words indicating that the status of a channel-path
+ * has changed.
+ */
+void chp_process_crw(int id, int status)
+{
+	struct chp_id chpid;
+
+	chp_id_init(&chpid);
+	chpid.id = id;
+	if (status) {
+		if (!chp_is_registered(chpid))
+			chp_new(chpid);
+		chsc_chp_online(chpid);
+	} else
+		chsc_chp_offline(chpid);
+}
+
+static inline int info_bit_num(struct chp_id id)
+{
+	return id.id + id.cssid * (__MAX_CHPID + 1);
+}
+
+/* Force chp_info refresh on next call to info_validate(). */
+static void info_expire(void)
+{
+	mutex_lock(&info_lock);
+	chp_info_expires = jiffies - 1;
+	mutex_unlock(&info_lock);
+}
+
+/* Ensure that chp_info is up-to-date. */
+static int info_update(void)
+{
+	int rc;
+
+	mutex_lock(&info_lock);
+	rc = 0;
+	if (time_after(jiffies, chp_info_expires)) {
+		/* Data is too old, update. */
+		rc = sclp_chp_read_info(&chp_info);
+		chp_info_expires = jiffies + CHP_INFO_UPDATE_INTERVAL ;
+	}
+	mutex_unlock(&info_lock);
+
+	return rc;
+}
+
+/**
+ * chp_info_get_status - retrieve configure status of a channel-path
+ * @chpid: channel-path ID
+ *
+ * On success, return 0 for standby, 1 for configured, 2 for reserved,
+ * 3 for not recognized. Return negative error code on error.
+ */
+int chp_info_get_status(struct chp_id chpid)
+{
+	int rc;
+	int bit;
+
+	rc = info_update();
+	if (rc)
+		return rc;
+
+	bit = info_bit_num(chpid);
+	mutex_lock(&info_lock);
+	if (!chp_test_bit(chp_info.recognized, bit))
+		rc = CHP_STATUS_NOT_RECOGNIZED;
+	else if (chp_test_bit(chp_info.configured, bit))
+		rc = CHP_STATUS_CONFIGURED;
+	else if (chp_test_bit(chp_info.standby, bit))
+		rc = CHP_STATUS_STANDBY;
+	else
+		rc = CHP_STATUS_RESERVED;
+	mutex_unlock(&info_lock);
+
+	return rc;
+}
+
+/* Return configure task for chpid. */
+static enum cfg_task_t cfg_get_task(struct chp_id chpid)
+{
+	return chp_cfg_task[chpid.cssid][chpid.id];
+}
+
+/* Set configure task for chpid. */
+static void cfg_set_task(struct chp_id chpid, enum cfg_task_t cfg)
+{
+	chp_cfg_task[chpid.cssid][chpid.id] = cfg;
+}
+
+/* Perform one configure/deconfigure request. Reschedule work function until
+ * last request. */
+static void cfg_func(struct work_struct *work)
+{
+	struct chp_id chpid;
+	enum cfg_task_t t;
+
+	mutex_lock(&cfg_lock);
+	t = cfg_none;
+	chp_id_for_each(&chpid) {
+		t = cfg_get_task(chpid);
+		if (t != cfg_none) {
+			cfg_set_task(chpid, cfg_none);
+			break;
+		}
+	}
+	mutex_unlock(&cfg_lock);
+
+	switch (t) {
+	case cfg_configure:
+		sclp_chp_configure(chpid);
+		info_expire();
+		chsc_chp_online(chpid);
+		break;
+	case cfg_deconfigure:
+		sclp_chp_deconfigure(chpid);
+		info_expire();
+		chsc_chp_offline(chpid);
+		break;
+	case cfg_none:
+		/* Get updated information after last change. */
+		info_update();
+		mutex_lock(&cfg_lock);
+		cfg_busy = 0;
+		mutex_unlock(&cfg_lock);
+		wake_up_interruptible(&cfg_wait_queue);
+		return;
+	}
+	queue_work(chp_wq, &cfg_work);
+}
+
+/**
+ * chp_cfg_schedule - schedule chpid configuration request
+ * @chpid - channel-path ID
+ * @configure - Non-zero for configure, zero for deconfigure
+ *
+ * Schedule a channel-path configuration/deconfiguration request.
+ */
+void chp_cfg_schedule(struct chp_id chpid, int configure)
+{
+	CIO_MSG_EVENT(2, "chp_cfg_sched%x.%02x=%d\n", chpid.cssid, chpid.id,
+		      configure);
+	mutex_lock(&cfg_lock);
+	cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure);
+	cfg_busy = 1;
+	mutex_unlock(&cfg_lock);
+	queue_work(chp_wq, &cfg_work);
+}
+
+/**
+ * chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request
+ * @chpid - channel-path ID
+ *
+ * Cancel an active channel-path deconfiguration request if it has not yet
+ * been performed.
+ */
+void chp_cfg_cancel_deconfigure(struct chp_id chpid)
+{
+	CIO_MSG_EVENT(2, "chp_cfg_cancel:%x.%02x\n", chpid.cssid, chpid.id);
+	mutex_lock(&cfg_lock);
+	if (cfg_get_task(chpid) == cfg_deconfigure)
+		cfg_set_task(chpid, cfg_none);
+	mutex_unlock(&cfg_lock);
+}
+
+static int cfg_wait_idle(void)
+{
+	if (wait_event_interruptible(cfg_wait_queue, !cfg_busy))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+static int __init chp_init(void)
+{
+	struct chp_id chpid;
+
+	chp_wq = create_singlethread_workqueue("cio_chp");
+	if (!chp_wq)
+		return -ENOMEM;
+	INIT_WORK(&cfg_work, cfg_func);
+	init_waitqueue_head(&cfg_wait_queue);
+	if (info_update())
+		return 0;
+	/* Register available channel-paths. */
+	chp_id_for_each(&chpid) {
+		if (chp_info_get_status(chpid) != CHP_STATUS_NOT_RECOGNIZED)
+			chp_new(chpid);
+	}
+
+	return 0;
+}
+
+subsys_initcall(chp_init);
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h
new file mode 100644
index 0000000..6528656
--- /dev/null
+++ b/drivers/s390/cio/chp.h
@@ -0,0 +1,53 @@
+/*
+ *  drivers/s390/cio/chp.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef S390_CHP_H
+#define S390_CHP_H S390_CHP_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <asm/chpid.h>
+#include "chsc.h"
+
+#define CHP_STATUS_STANDBY		0
+#define CHP_STATUS_CONFIGURED		1
+#define CHP_STATUS_RESERVED		2
+#define CHP_STATUS_NOT_RECOGNIZED	3
+
+static inline int chp_test_bit(u8 *bitmap, int num)
+{
+	int byte = num >> 3;
+	int mask = 128 >> (num & 7);
+
+	return (bitmap[byte] & mask) ? 1 : 0;
+}
+
+
+struct channel_path {
+	struct chp_id chpid;
+	int state;
+	struct channel_path_desc desc;
+	/* Channel-measurement related stuff: */
+	int cmg;
+	int shared;
+	void *cmg_chars;
+	struct device dev;
+};
+
+int chp_get_status(struct chp_id chpid);
+u8 chp_get_sch_opm(struct subchannel *sch);
+int chp_is_registered(struct chp_id chpid);
+void *chp_get_chp_desc(struct chp_id chpid);
+void chp_process_crw(int id, int available);
+void chp_remove_cmg_attr(struct channel_path *chp);
+int chp_add_cmg_attr(struct channel_path *chp);
+int chp_new(struct chp_id chpid);
+void chp_cfg_schedule(struct chp_id chpid, int configure);
+void chp_cfg_cancel_deconfigure(struct chp_id chpid);
+int chp_info_get_status(struct chp_id chpid);
+
+#endif /* S390_CHP_H */
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 6f05a44..ea92ac4 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -15,202 +15,124 @@ #include <linux/init.h>
 #include <linux/device.h>
 
 #include <asm/cio.h>
+#include <asm/chpid.h>
 
 #include "css.h"
 #include "cio.h"
 #include "cio_debug.h"
 #include "ioasm.h"
+#include "chp.h"
 #include "chsc.h"
 
 static void *sei_page;
 
-static int new_channel_path(int chpid);
-
-static inline void
-set_chp_logically_online(int chp, int onoff)
-{
-	css[0]->chps[chp]->state = onoff;
-}
-
-static int
-get_chp_status(int chp)
-{
-	return (css[0]->chps[chp] ? css[0]->chps[chp]->state : -ENODEV);
-}
-
-void
-chsc_validate_chpids(struct subchannel *sch)
-{
-	int mask, chp;
-
-	for (chp = 0; chp <= 7; chp++) {
-		mask = 0x80 >> chp;
-		if (!get_chp_status(sch->schib.pmcw.chpid[chp]))
-			/* disable using this path */
-			sch->opm &= ~mask;
-	}
-}
-
-void
-chpid_is_actually_online(int chp)
-{
-	int state;
-
-	state = get_chp_status(chp);
-	if (state < 0) {
-		need_rescan = 1;
-		queue_work(slow_path_wq, &slow_path_work);
-	} else
-		WARN_ON(!state);
-}
+struct chsc_ssd_area {
+	struct chsc_header request;
+	u16 :10;
+	u16 ssid:2;
+	u16 :4;
+	u16 f_sch;	  /* first subchannel */
+	u16 :16;
+	u16 l_sch;	  /* last subchannel */
+	u32 :32;
+	struct chsc_header response;
+	u32 :32;
+	u8 sch_valid : 1;
+	u8 dev_valid : 1;
+	u8 st	     : 3; /* subchannel type */
+	u8 zeroes    : 3;
+	u8  unit_addr;	  /* unit address */
+	u16 devno;	  /* device number */
+	u8 path_mask;
+	u8 fla_valid_mask;
+	u16 sch;	  /* subchannel */
+	u8 chpid[8];	  /* chpids 0-7 */
+	u16 fla[8];	  /* full link addresses 0-7 */
+} __attribute__ ((packed));
 
-/* FIXME: this is _always_ called for every subchannel. shouldn't we
- *	  process more than one at a time? */
-static int
-chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
+int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 {
-	int ccode, j;
-
-	struct {
-		struct chsc_header request;
-		u16 reserved1a:10;
-		u16 ssid:2;
-		u16 reserved1b:4;
-		u16 f_sch;	  /* first subchannel */
-		u16 reserved2;
-		u16 l_sch;	  /* last subchannel */
-		u32 reserved3;
-		struct chsc_header response;
-		u32 reserved4;
-		u8 sch_valid : 1;
-		u8 dev_valid : 1;
-		u8 st	     : 3; /* subchannel type */
-		u8 zeroes    : 3;
-		u8  unit_addr;	  /* unit address */
-		u16 devno;	  /* device number */
-		u8 path_mask;
-		u8 fla_valid_mask;
-		u16 sch;	  /* subchannel */
-		u8 chpid[8];	  /* chpids 0-7 */
-		u16 fla[8];	  /* full link addresses 0-7 */
-	} __attribute__ ((packed)) *ssd_area;
-
-	ssd_area = page;
+	unsigned long page;
+	struct chsc_ssd_area *ssd_area;
+	int ccode;
+	int ret;
+	int i;
+	int mask;
 
+	page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!page)
+		return -ENOMEM;
+	ssd_area = (struct chsc_ssd_area *) page;
 	ssd_area->request.length = 0x0010;
 	ssd_area->request.code = 0x0004;
-
-	ssd_area->ssid = sch->schid.ssid;
-	ssd_area->f_sch = sch->schid.sch_no;
-	ssd_area->l_sch = sch->schid.sch_no;
+	ssd_area->ssid = schid.ssid;
+	ssd_area->f_sch = schid.sch_no;
+	ssd_area->l_sch = schid.sch_no;
 
 	ccode = chsc(ssd_area);
+	/* Check response. */
 	if (ccode > 0) {
-		pr_debug("chsc returned with ccode = %d\n", ccode);
-		return (ccode == 3) ? -ENODEV : -EBUSY;
+		ret = (ccode == 3) ? -ENODEV : -EBUSY;
+		goto out_free;
 	}
-
-	switch (ssd_area->response.code) {
-	case 0x0001: /* everything ok */
-		break;
-	case 0x0002:
-		CIO_CRW_EVENT(2, "Invalid command!\n");
-		return -EINVAL;
-	case 0x0003:
-		CIO_CRW_EVENT(2, "Error in chsc request block!\n");
-		return -EINVAL;
-	case 0x0004:
-		CIO_CRW_EVENT(2, "Model does not provide ssd\n");
-		return -EOPNOTSUPP;
-	default:
-		CIO_CRW_EVENT(2, "Unknown CHSC response %d\n",
+	if (ssd_area->response.code != 0x0001) {
+		CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
+			      schid.ssid, schid.sch_no,
 			      ssd_area->response.code);
-		return -EIO;
+		ret = -EIO;
+		goto out_free;
 	}
-
-	/*
-	 * ssd_area->st stores the type of the detected
-	 * subchannel, with the following definitions:
-	 *
-	 * 0: I/O subchannel:	  All fields have meaning
-	 * 1: CHSC subchannel:	  Only sch_val, st and sch
-	 *			  have meaning
-	 * 2: Message subchannel: All fields except unit_addr
-	 *			  have meaning
-	 * 3: ADM subchannel:	  Only sch_val, st and sch
-	 *			  have meaning
-	 *
-	 * Other types are currently undefined.
-	 */
-	if (ssd_area->st > 3) { /* uhm, that looks strange... */
-		CIO_CRW_EVENT(0, "Strange subchannel type %d"
-			      " for sch 0.%x.%04x\n", ssd_area->st,
-			      sch->schid.ssid, sch->schid.sch_no);
-		/*
-		 * There may have been a new subchannel type defined in the
-		 * time since this code was written; since we don't know which
-		 * fields have meaning and what to do with it we just jump out
-		 */
-		return 0;
-	} else {
-		const char *type[4] = {"I/O", "chsc", "message", "ADM"};
-		CIO_CRW_EVENT(6, "ssd: sch 0.%x.%04x is %s subchannel\n",
-			      sch->schid.ssid, sch->schid.sch_no,
-			      type[ssd_area->st]);
-
-		sch->ssd_info.valid = 1;
-		sch->ssd_info.type = ssd_area->st;
+	if (!ssd_area->sch_valid) {
+		ret = -ENODEV;
+		goto out_free;
 	}
-
-	if (ssd_area->st == 0 || ssd_area->st == 2) {
-		for (j = 0; j < 8; j++) {
-			if (!((0x80 >> j) & ssd_area->path_mask &
-			      ssd_area->fla_valid_mask))
-				continue;
-			sch->ssd_info.chpid[j] = ssd_area->chpid[j];
-			sch->ssd_info.fla[j]   = ssd_area->fla[j];
+	/* Copy data */
+	ret = 0;
+	memset(ssd, 0, sizeof(struct chsc_ssd_info));
+	if ((ssd_area->st != 0) && (ssd_area->st != 2))
+		goto out_free;
+	ssd->path_mask = ssd_area->path_mask;
+	ssd->fla_valid_mask = ssd_area->fla_valid_mask;
+	for (i = 0; i < 8; i++) {
+		mask = 0x80 >> i;
+		if (ssd_area->path_mask & mask) {
+			chp_id_init(&ssd->chpid[i]);
+			ssd->chpid[i].id = ssd_area->chpid[i];
 		}
+		if (ssd_area->fla_valid_mask & mask)
+			ssd->fla[i] = ssd_area->fla[i];
 	}
-	return 0;
+out_free:
+	free_page(page);
+	return ret;
 }
 
-int
-css_get_ssd_info(struct subchannel *sch)
+static int check_for_io_on_path(struct subchannel *sch, int mask)
 {
-	int ret;
-	void *page;
+	int cc;
 
-	page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!page)
-		return -ENOMEM;
-	spin_lock_irq(sch->lock);
-	ret = chsc_get_sch_desc_irq(sch, page);
-	if (ret) {
-		static int cio_chsc_err_msg;
-		
-		if (!cio_chsc_err_msg) {
-			printk(KERN_ERR
-			       "chsc_get_sch_descriptions:"
-			       " Error %d while doing chsc; "
-			       "processing some machine checks may "
-			       "not work\n", ret);
-			cio_chsc_err_msg = 1;
-		}
-	}
-	spin_unlock_irq(sch->lock);
-	free_page((unsigned long)page);
-	if (!ret) {
-		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 ((sch->schib.pmcw.pim & mask) &&
-			    (get_chp_status(chpid) < 0))
-			    new_channel_path(chpid);
-		}
+	cc = stsch(sch->schid, &sch->schib);
+	if (cc)
+		return 0;
+	if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask)
+		return 1;
+	return 0;
+}
+
+static void terminate_internal_io(struct subchannel *sch)
+{
+	if (cio_clear(sch)) {
+		/* Recheck device in case clear failed. */
+		sch->lpm = 0;
+		if (device_trigger_verify(sch) != 0)
+			css_schedule_eval(sch->schid);
+		return;
 	}
-	return ret;
+	/* Request retry of internal operation. */
+	device_set_intretry(sch);
+	/* Call handler. */
+	if (sch->driver && sch->driver->termination)
+		sch->driver->termination(&sch->dev);
 }
 
 static int
@@ -219,7 +141,7 @@ s390_subchannel_remove_chpid(struct devi
 	int j;
 	int mask;
 	struct subchannel *sch;
-	struct channel_path *chpid;
+	struct chp_id *chpid;
 	struct schib schib;
 
 	sch = to_subchannel(dev);
@@ -243,106 +165,50 @@ s390_subchannel_remove_chpid(struct devi
 	if (sch->schib.pmcw.pim == 0x80)
 		goto out_unreg;
 
-	if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
-	    (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
-	    (sch->schib.pmcw.lpum == mask)) {
-		int cc;
-
-		cc = cio_clear(sch);
-		if (cc == -ENODEV)
+	if (check_for_io_on_path(sch, mask)) {
+		if (device_is_online(sch))
+			device_kill_io(sch);
+		else {
+			terminate_internal_io(sch);
+			/* Re-start path verification. */
+			if (sch->driver && sch->driver->verify)
+				sch->driver->verify(&sch->dev);
+		}
+	} else {
+		/* trigger path verification. */
+		if (sch->driver && sch->driver->verify)
+			sch->driver->verify(&sch->dev);
+		else if (sch->lpm == mask)
 			goto out_unreg;
-		/* Request retry of internal operation. */
-		device_set_intretry(sch);
-		/* Call handler. */
-		if (sch->driver && sch->driver->termination)
-			sch->driver->termination(&sch->dev);
-		goto out_unlock;
 	}
 
-	/* trigger path verification. */
-	if (sch->driver && sch->driver->verify)
-		sch->driver->verify(&sch->dev);
-	else if (sch->lpm == mask)
-		goto out_unreg;
-out_unlock:
 	spin_unlock_irq(sch->lock);
 	return 0;
+
 out_unreg:
-	spin_unlock_irq(sch->lock);
 	sch->lpm = 0;
-	if (css_enqueue_subchannel_slow(sch->schid)) {
-		css_clear_subchannel_slow_list();
-		need_rescan = 1;
-	}
+	spin_unlock_irq(sch->lock);
+	css_schedule_eval(sch->schid);
 	return 0;
 }
 
-static void
-s390_set_chpid_offline( __u8 chpid)
+void chsc_chp_offline(struct chp_id chpid)
 {
 	char dbf_txt[15];
-	struct device *dev;
 
-	sprintf(dbf_txt, "chpr%x", chpid);
+	sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
 	CIO_TRACE_EVENT(2, dbf_txt);
 
-	if (get_chp_status(chpid) <= 0)
+	if (chp_get_status(chpid) <= 0)
 		return;
-	dev = get_device(&css[0]->chps[chpid]->dev);
-	bus_for_each_dev(&css_bus_type, NULL, to_channelpath(dev),
+	bus_for_each_dev(&css_bus_type, NULL, &chpid,
 			 s390_subchannel_remove_chpid);
-
-	if (need_rescan || css_slow_subchannels_exist())
-		queue_work(slow_path_wq, &slow_path_work);
-	put_device(dev);
-}
-
-struct res_acc_data {
-	struct channel_path *chp;
-	u32 fla_mask;
-	u16 fla;
-};
-
-static int
-s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
-{
-	int found;
-	int chp;
-	int ccode;
-	
-	found = 0;
-	for (chp = 0; chp <= 7; chp++)
-		/*
-		 * check if chpid is in information updated by ssd
-		 */
-		if (sch->ssd_info.valid &&
-		    sch->ssd_info.chpid[chp] == res_data->chp->id &&
-		    (sch->ssd_info.fla[chp] & res_data->fla_mask)
-		    == res_data->fla) {
-			found = 1;
-			break;
-		}
-	
-	if (found == 0)
-		return 0;
-
-	/*
-	 * Do a stsch to update our subchannel structure with the
-	 * new path information and eventually check for logically
-	 * offline chpids.
-	 */
-	ccode = stsch(sch->schid, &sch->schib);
-	if (ccode > 0)
-		return 0;
-
-	return 0x80 >> chp;
 }
 
 static int
 s390_process_res_acc_new_sch(struct subchannel_id schid)
 {
 	struct schib schib;
-	int ret;
 	/*
 	 * We don't know the device yet, but since a path
 	 * may be available now to the device we'll have
@@ -353,14 +219,35 @@ s390_process_res_acc_new_sch(struct subc
 	 */
 	if (stsch_err(schid, &schib))
 		/* We're through */
-		return need_rescan ? -EAGAIN : -ENXIO;
+		return -ENXIO;
 
 	/* Put it on the slow path. */
-	ret = css_enqueue_subchannel_slow(schid);
-	if (ret) {
-		css_clear_subchannel_slow_list();
-		need_rescan = 1;
-		return -EAGAIN;
+	css_schedule_eval(schid);
+	return 0;
+}
+
+struct res_acc_data {
+	struct chp_id chpid;
+	u32 fla_mask;
+	u16 fla;
+};
+
+static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
+			      struct res_acc_data *data)
+{
+	int i;
+	int mask;
+
+	for (i = 0; i < 8; i++) {
+		mask = 0x80 >> i;
+		if (!(ssd->path_mask & mask))
+			continue;
+		if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid))
+			continue;
+		if ((ssd->fla_valid_mask & mask) &&
+		    ((ssd->fla[i] & data->fla_mask) != data->fla))
+			continue;
+		return mask;
 	}
 	return 0;
 }
@@ -379,14 +266,11 @@ __s390_process_res_acc(struct subchannel
 		return s390_process_res_acc_new_sch(schid);
 
 	spin_lock_irq(sch->lock);
-
-	chp_mask = s390_process_res_acc_sch(res_data, sch);
-
-	if (chp_mask == 0) {
-		spin_unlock_irq(sch->lock);
-		put_device(&sch->dev);
-		return 0;
-	}
+	chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
+	if (chp_mask == 0)
+		goto out;
+	if (stsch(sch->schid, &sch->schib))
+		goto out;
 	old_lpm = sch->lpm;
 	sch->lpm = ((sch->schib.pmcw.pim &
 		     sch->schib.pmcw.pam &
@@ -396,20 +280,18 @@ __s390_process_res_acc(struct subchannel
 		device_trigger_reprobe(sch);
 	else if (sch->driver && sch->driver->verify)
 		sch->driver->verify(&sch->dev);
-
+out:
 	spin_unlock_irq(sch->lock);
 	put_device(&sch->dev);
 	return 0;
 }
 
-
-static int
-s390_process_res_acc (struct res_acc_data *res_data)
+static void s390_process_res_acc (struct res_acc_data *res_data)
 {
-	int rc;
 	char dbf_txt[15];
 
-	sprintf(dbf_txt, "accpr%x", res_data->chp->id);
+	sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid,
+		res_data->chpid.id);
 	CIO_TRACE_EVENT( 2, dbf_txt);
 	if (res_data->fla != 0) {
 		sprintf(dbf_txt, "fla%x", res_data->fla);
@@ -423,12 +305,7 @@ s390_process_res_acc (struct res_acc_dat
 	 * The more information we have (info), the less scanning
 	 * will we have to do.
 	 */
-	rc = for_each_subchannel(__s390_process_res_acc, res_data);
-	if (css_slow_subchannels_exist())
-		rc = -EAGAIN;
-	else if (rc != -EAGAIN)
-		rc = 0;
-	return rc;
+	for_each_subchannel(__s390_process_res_acc, res_data);
 }
 
 static int
@@ -480,43 +357,45 @@ struct chsc_sei_area {
 	/* ccdf has to be big enough for a link-incident record */
 } __attribute__ ((packed));
 
-static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
+static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
 {
-	int chpid;
+	struct chp_id chpid;
+	int id;
 
 	CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
 		      sei_area->rs, sei_area->rsid);
 	if (sei_area->rs != 4)
-		return 0;
-	chpid = __get_chpid_from_lir(sei_area->ccdf);
-	if (chpid < 0)
+		return;
+	id = __get_chpid_from_lir(sei_area->ccdf);
+	if (id < 0)
 		CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
-	else
-		s390_set_chpid_offline(chpid);
-
-	return 0;
+	else {
+		chp_id_init(&chpid);
+		chpid.id = id;
+		chsc_chp_offline(chpid);
+	}
 }
 
-static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
+static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
 {
 	struct res_acc_data res_data;
-	struct device *dev;
+	struct chp_id chpid;
 	int status;
-	int rc;
 
 	CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
 		      "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
 	if (sei_area->rs != 4)
-		return 0;
+		return;
+	chp_id_init(&chpid);
+	chpid.id = sei_area->rsid;
 	/* allocate a new channel path structure, if needed */
-	status = get_chp_status(sei_area->rsid);
+	status = chp_get_status(chpid);
 	if (status < 0)
-		new_channel_path(sei_area->rsid);
+		chp_new(chpid);
 	else if (!status)
-		return 0;
-	dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+		return;
 	memset(&res_data, 0, sizeof(struct res_acc_data));
-	res_data.chp = to_channelpath(dev);
+	res_data.chpid = chpid;
 	if ((sei_area->vf & 0xc0) != 0) {
 		res_data.fla = sei_area->fla;
 		if ((sei_area->vf & 0xc0) == 0xc0)
@@ -526,51 +405,82 @@ static int chsc_process_sei_res_acc(stru
 			/* link address */
 			res_data.fla_mask = 0xff00;
 	}
-	rc = s390_process_res_acc(&res_data);
-	put_device(dev);
-
-	return rc;
+	s390_process_res_acc(&res_data);
 }
 
-static int chsc_process_sei(struct chsc_sei_area *sei_area)
+struct chp_config_data {
+	u8 map[32];
+	u8 op;
+	u8 pc;
+};
+
+static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
 {
-	int rc;
+	struct chp_config_data *data;
+	struct chp_id chpid;
+	int num;
+
+	CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n");
+	if (sei_area->rs != 0)
+		return;
+	data = (struct chp_config_data *) &(sei_area->ccdf);
+	chp_id_init(&chpid);
+	for (num = 0; num <= __MAX_CHPID; num++) {
+		if (!chp_test_bit(data->map, num))
+			continue;
+		chpid.id = num;
+		printk(KERN_WARNING "cio: processing configure event %d for "
+		       "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id);
+		switch (data->op) {
+		case 0:
+			chp_cfg_schedule(chpid, 1);
+			break;
+		case 1:
+			chp_cfg_schedule(chpid, 0);
+			break;
+		case 2:
+			chp_cfg_cancel_deconfigure(chpid);
+			break;
+		}
+	}
+}
 
+static void chsc_process_sei(struct chsc_sei_area *sei_area)
+{
 	/* Check if we might have lost some information. */
-	if (sei_area->flags & 0x40)
+	if (sei_area->flags & 0x40) {
 		CIO_CRW_EVENT(2, "chsc: event overflow\n");
+		css_schedule_eval_all();
+	}
 	/* which kind of information was stored? */
-	rc = 0;
 	switch (sei_area->cc) {
 	case 1: /* link incident*/
-		rc = chsc_process_sei_link_incident(sei_area);
+		chsc_process_sei_link_incident(sei_area);
 		break;
 	case 2: /* i/o resource accessibiliy */
-		rc = chsc_process_sei_res_acc(sei_area);
+		chsc_process_sei_res_acc(sei_area);
+		break;
+	case 8: /* channel-path-configuration notification */
+		chsc_process_sei_chp_config(sei_area);
 		break;
 	default: /* other stuff */
 		CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
 			      sei_area->cc);
 		break;
 	}
-
-	return rc;
 }
 
-int chsc_process_crw(void)
+void chsc_process_crw(void)
 {
 	struct chsc_sei_area *sei_area;
-	int ret;
-	int rc;
 
 	if (!sei_page)
-		return 0;
+		return;
 	/* Access to sei_page is serialized through machine check handler
 	 * thread, so no need for locking. */
 	sei_area = sei_page;
 
 	CIO_TRACE_EVENT( 2, "prcss");
-	ret = 0;
 	do {
 		memset(sei_area, 0, sizeof(*sei_area));
 		sei_area->request.length = 0x0010;
@@ -580,37 +490,26 @@ int chsc_process_crw(void)
 
 		if (sei_area->response.code == 0x0001) {
 			CIO_CRW_EVENT(4, "chsc: sei successful\n");
-			rc = chsc_process_sei(sei_area);
-			if (rc)
-				ret = rc;
+			chsc_process_sei(sei_area);
 		} else {
 			CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
 				      sei_area->response.code);
-			ret = 0;
 			break;
 		}
 	} while (sei_area->flags & 0x80);
-
-	return ret;
 }
 
 static int
 __chp_add_new_sch(struct subchannel_id schid)
 {
 	struct schib schib;
-	int ret;
 
 	if (stsch_err(schid, &schib))
 		/* We're through */
-		return need_rescan ? -EAGAIN : -ENXIO;
+		return -ENXIO;
 
 	/* Put it on the slow path. */
-	ret = css_enqueue_subchannel_slow(schid);
-	if (ret) {
-		css_clear_subchannel_slow_list();
-		need_rescan = 1;
-		return -EAGAIN;
-	}
+	css_schedule_eval(schid);
 	return 0;
 }
 
@@ -619,10 +518,10 @@ static int
 __chp_add(struct subchannel_id schid, void *data)
 {
 	int i, mask;
-	struct channel_path *chp;
+	struct chp_id *chpid;
 	struct subchannel *sch;
 
-	chp = data;
+	chpid = data;
 	sch = get_subchannel_by_schid(schid);
 	if (!sch)
 		/* Check if the subchannel is now available. */
@@ -631,7 +530,7 @@ __chp_add(struct subchannel_id schid, vo
 	for (i=0; i<8; i++) {
 		mask = 0x80 >> i;
 		if ((sch->schib.pmcw.pim & mask) &&
-		    (sch->schib.pmcw.chpid[i] == chp->id)) {
+		    (sch->schib.pmcw.chpid[i] == chpid->id)) {
 			if (stsch(sch->schid, &sch->schib) != 0) {
 				/* Endgame. */
 				spin_unlock_irq(sch->lock);
@@ -657,122 +556,58 @@ __chp_add(struct subchannel_id schid, vo
 	return 0;
 }
 
-static int
-chp_add(int chpid)
+void chsc_chp_online(struct chp_id chpid)
 {
-	int rc;
 	char dbf_txt[15];
-	struct device *dev;
 
-	if (!get_chp_status(chpid))
-		return 0; /* no need to do the rest */
-	
-	sprintf(dbf_txt, "cadd%x", chpid);
+	sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
 	CIO_TRACE_EVENT(2, dbf_txt);
 
-	dev = get_device(&css[0]->chps[chpid]->dev);
-	rc = for_each_subchannel(__chp_add, to_channelpath(dev));
-	if (css_slow_subchannels_exist())
-		rc = -EAGAIN;
-	if (rc != -EAGAIN)
-		rc = 0;
-	put_device(dev);
-	return rc;
+	if (chp_get_status(chpid) != 0)
+		for_each_subchannel(__chp_add, &chpid);
 }
 
-/* 
- * Handling of crw machine checks with channel path source.
- */
-int
-chp_process_crw(int chpid, int on)
-{
-	if (on == 0) {
-		/* Path has gone. We use the link incident routine.*/
-		s390_set_chpid_offline(chpid);
-		return 0; /* De-register is async anyway. */
-	}
-	/*
-	 * Path has come. Allocate a new channel path structure,
-	 * if needed.
-	 */
-	if (get_chp_status(chpid) < 0)
-		new_channel_path(chpid);
-	/* Avoid the extra overhead in process_rec_acc. */
-	return chp_add(chpid);
-}
-
-static int check_for_io_on_path(struct subchannel *sch, int index)
-{
-	int cc;
-
-	cc = stsch(sch->schid, &sch->schib);
-	if (cc)
-		return 0;
-	if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index))
-		return 1;
-	return 0;
-}
-
-static void terminate_internal_io(struct subchannel *sch)
-{
-	if (cio_clear(sch)) {
-		/* Recheck device in case clear failed. */
-		sch->lpm = 0;
-		if (device_trigger_verify(sch) != 0) {
-			if(css_enqueue_subchannel_slow(sch->schid)) {
-				css_clear_subchannel_slow_list();
-				need_rescan = 1;
-			}
-		}
-		return;
-	}
-	/* Request retry of internal operation. */
-	device_set_intretry(sch);
-	/* Call handler. */
-	if (sch->driver && sch->driver->termination)
-		sch->driver->termination(&sch->dev);
-}
-
-static void
-__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
+static void __s390_subchannel_vary_chpid(struct subchannel *sch,
+					 struct chp_id chpid, int on)
 {
 	int chp, old_lpm;
+	int mask;
 	unsigned long flags;
 
-	if (!sch->ssd_info.valid)
-		return;
-	
 	spin_lock_irqsave(sch->lock, flags);
 	old_lpm = sch->lpm;
 	for (chp = 0; chp < 8; chp++) {
-		if (sch->ssd_info.chpid[chp] != chpid)
+		mask = 0x80 >> chp;
+		if (!(sch->ssd_info.path_mask & mask))
+			continue;
+		if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid))
 			continue;
 
 		if (on) {
-			sch->opm |= (0x80 >> chp);
-			sch->lpm |= (0x80 >> chp);
+			sch->opm |= mask;
+			sch->lpm |= mask;
 			if (!old_lpm)
 				device_trigger_reprobe(sch);
 			else if (sch->driver && sch->driver->verify)
 				sch->driver->verify(&sch->dev);
 			break;
 		}
-		sch->opm &= ~(0x80 >> chp);
-		sch->lpm &= ~(0x80 >> chp);
-		if (check_for_io_on_path(sch, chp)) {
+		sch->opm &= ~mask;
+		sch->lpm &= ~mask;
+		if (check_for_io_on_path(sch, mask)) {
 			if (device_is_online(sch))
 				/* Path verification is done after killing. */
 				device_kill_io(sch);
-			else
+			else {
 				/* Kill and retry internal I/O. */
 				terminate_internal_io(sch);
-		} else if (!sch->lpm) {
-			if (device_trigger_verify(sch) != 0) {
-				if (css_enqueue_subchannel_slow(sch->schid)) {
-					css_clear_subchannel_slow_list();
-					need_rescan = 1;
-				}
+				/* Re-start path verification. */
+				if (sch->driver && sch->driver->verify)
+					sch->driver->verify(&sch->dev);
 			}
+		} else if (!sch->lpm) {
+			if (device_trigger_verify(sch) != 0)
+				css_schedule_eval(sch->schid);
 		} else if (sch->driver && sch->driver->verify)
 			sch->driver->verify(&sch->dev);
 		break;
@@ -780,11 +615,10 @@ __s390_subchannel_vary_chpid(struct subc
 	spin_unlock_irqrestore(sch->lock, flags);
 }
 
-static int
-s390_subchannel_vary_chpid_off(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
 {
 	struct subchannel *sch;
-	__u8 *chpid;
+	struct chp_id *chpid;
 
 	sch = to_subchannel(dev);
 	chpid = data;
@@ -793,11 +627,10 @@ s390_subchannel_vary_chpid_off(struct de
 	return 0;
 }
 
-static int
-s390_subchannel_vary_chpid_on(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
 {
 	struct subchannel *sch;
-	__u8 *chpid;
+	struct chp_id *chpid;
 
 	sch = to_subchannel(dev);
 	chpid = data;
@@ -821,40 +654,17 @@ __s390_vary_chpid_on(struct subchannel_i
 		/* We're through */
 		return -ENXIO;
 	/* Put it on the slow path. */
-	if (css_enqueue_subchannel_slow(schid)) {
-		css_clear_subchannel_slow_list();
-		need_rescan = 1;
-		return -EAGAIN;
-	}
+	css_schedule_eval(schid);
 	return 0;
 }
 
-/*
- * Function: s390_vary_chpid
- * Varies the specified chpid online or offline
+/**
+ * chsc_chp_vary - propagate channel-path vary operation to subchannels
+ * @chpid: channl-path ID
+ * @on: non-zero for vary online, zero for vary offline
  */
-static int
-s390_vary_chpid( __u8 chpid, int on)
+int chsc_chp_vary(struct chp_id chpid, int on)
 {
-	char dbf_text[15];
-	int status;
-
-	sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
-	CIO_TRACE_EVENT( 2, dbf_text);
-
-	status = get_chp_status(chpid);
-	if (status < 0) {
-		printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid);
-		return -EINVAL;
-	}
-
-	if (!on && !status) {
-		printk(KERN_ERR "chpid %x is already offline\n", chpid);
-		return -EINVAL;
-	}
-
-	set_chp_logically_online(chpid, on);
-
 	/*
 	 * Redo PathVerification on the devices the chpid connects to
 	 */
@@ -865,118 +675,9 @@ s390_vary_chpid( __u8 chpid, int on)
 	if (on)
 		/* Scan for new devices on varied on path. */
 		for_each_subchannel(__s390_vary_chpid_on, NULL);
-	if (need_rescan || css_slow_subchannels_exist())
-		queue_work(slow_path_wq, &slow_path_work);
 	return 0;
 }
 
-/*
- * Channel measurement related functions
- */
-static ssize_t
-chp_measurement_chars_read(struct kobject *kobj, char *buf, loff_t off,
-			   size_t count)
-{
-	struct channel_path *chp;
-	unsigned int size;
-
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
-	if (!chp->cmg_chars)
-		return 0;
-
-	size = sizeof(struct cmg_chars);
-
-	if (off > size)
-		return 0;
-	if (off + count > size)
-		count = size - off;
-	memcpy(buf, chp->cmg_chars + off, count);
-	return count;
-}
-
-static struct bin_attribute chp_measurement_chars_attr = {
-	.attr = {
-		.name = "measurement_chars",
-		.mode = S_IRUSR,
-		.owner = THIS_MODULE,
-	},
-	.size = sizeof(struct cmg_chars),
-	.read = chp_measurement_chars_read,
-};
-
-static void
-chp_measurement_copy_block(struct cmg_entry *buf,
-			   struct channel_subsystem *css, int chpid)
-{
-	void *area;
-	struct cmg_entry *entry, reference_buf;
-	int idx;
-
-	if (chpid < 128) {
-		area = css->cub_addr1;
-		idx = chpid;
-	} else {
-		area = css->cub_addr2;
-		idx = chpid - 128;
-	}
-	entry = area + (idx * sizeof(struct cmg_entry));
-	do {
-		memcpy(buf, entry, sizeof(*entry));
-		memcpy(&reference_buf, entry, sizeof(*entry));
-	} while (reference_buf.values[0] != buf->values[0]);
-}
-
-static ssize_t
-chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
-{
-	struct channel_path *chp;
-	struct channel_subsystem *css;
-	unsigned int size;
-
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
-	css = to_css(chp->dev.parent);
-
-	size = sizeof(struct cmg_entry);
-
-	/* Only allow single reads. */
-	if (off || count < size)
-		return 0;
-	chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);
-	count = size;
-	return count;
-}
-
-static struct bin_attribute chp_measurement_attr = {
-	.attr = {
-		.name = "measurement",
-		.mode = S_IRUSR,
-		.owner = THIS_MODULE,
-	},
-	.size = sizeof(struct cmg_entry),
-	.read = chp_measurement_read,
-};
-
-static void
-chsc_remove_chp_cmg_attr(struct channel_path *chp)
-{
-	device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
-	device_remove_bin_file(&chp->dev, &chp_measurement_attr);
-}
-
-static int
-chsc_add_chp_cmg_attr(struct channel_path *chp)
-{
-	int ret;
-
-	ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
-	if (ret)
-		return ret;
-	ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
-	if (ret)
-		device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
-	return ret;
-}
-
 static void
 chsc_remove_cmg_attr(struct channel_subsystem *css)
 {
@@ -985,7 +686,7 @@ chsc_remove_cmg_attr(struct channel_subs
 	for (i = 0; i <= __MAX_CHPID; i++) {
 		if (!css->chps[i])
 			continue;
-		chsc_remove_chp_cmg_attr(css->chps[i]);
+		chp_remove_cmg_attr(css->chps[i]);
 	}
 }
 
@@ -998,7 +699,7 @@ chsc_add_cmg_attr(struct channel_subsyst
 	for (i = 0; i <= __MAX_CHPID; i++) {
 		if (!css->chps[i])
 			continue;
-		ret = chsc_add_chp_cmg_attr(css->chps[i]);
+		ret = chp_add_cmg_attr(css->chps[i]);
 		if (ret)
 			goto cleanup;
 	}
@@ -1007,12 +708,11 @@ cleanup:
 	for (--i; i >= 0; i--) {
 		if (!css->chps[i])
 			continue;
-		chsc_remove_chp_cmg_attr(css->chps[i]);
+		chp_remove_cmg_attr(css->chps[i]);
 	}
 	return ret;
 }
 
-
 static int
 __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
 {
@@ -1118,7 +818,7 @@ chsc_secm(struct channel_subsystem *css,
 		} else
 			chsc_remove_cmg_attr(css);
 	}
-	if (enable && !css->cm_enabled) {
+	if (!css->cm_enabled) {
 		free_page((unsigned long)css->cub_addr1);
 		free_page((unsigned long)css->cub_addr2);
 	}
@@ -1127,109 +827,8 @@ chsc_secm(struct channel_subsystem *css,
 	return ret;
 }
 
-/*
- * Files for the channel path entries.
- */
-static ssize_t
-chp_status_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct channel_path *chp = container_of(dev, struct channel_path, dev);
-
-	if (!chp)
-		return 0;
-	return (get_chp_status(chp->id) ? sprintf(buf, "online\n") :
-		sprintf(buf, "offline\n"));
-}
-
-static ssize_t
-chp_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct channel_path *cp = container_of(dev, struct channel_path, dev);
-	char cmd[10];
-	int num_args;
-	int error;
-
-	num_args = sscanf(buf, "%5s", cmd);
-	if (!num_args)
-		return count;
-
-	if (!strnicmp(cmd, "on", 2))
-		error = s390_vary_chpid(cp->id, 1);
-	else if (!strnicmp(cmd, "off", 3))
-		error = s390_vary_chpid(cp->id, 0);
-	else
-		error = -EINVAL;
-
-	return error < 0 ? error : count;
-
-}
-
-static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write);
-
-static ssize_t
-chp_type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct channel_path *chp = container_of(dev, struct channel_path, dev);
-
-	if (!chp)
-		return 0;
-	return sprintf(buf, "%x\n", chp->desc.desc);
-}
-
-static DEVICE_ATTR(type, 0444, chp_type_show, NULL);
-
-static ssize_t
-chp_cmg_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct channel_path *chp = to_channelpath(dev);
-
-	if (!chp)
-		return 0;
-	if (chp->cmg == -1) /* channel measurements not available */
-		return sprintf(buf, "unknown\n");
-	return sprintf(buf, "%x\n", chp->cmg);
-}
-
-static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);
-
-static ssize_t
-chp_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct channel_path *chp = to_channelpath(dev);
-
-	if (!chp)
-		return 0;
-	if (chp->shared == -1) /* channel measurements not available */
-		return sprintf(buf, "unknown\n");
-	return sprintf(buf, "%x\n", chp->shared);
-}
-
-static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-
-static struct attribute * chp_attrs[] = {
-	&dev_attr_status.attr,
-	&dev_attr_type.attr,
-	&dev_attr_cmg.attr,
-	&dev_attr_shared.attr,
-	NULL,
-};
-
-static struct attribute_group chp_attr_group = {
-	.attrs = chp_attrs,
-};
-
-static void
-chp_release(struct device *dev)
-{
-	struct channel_path *cp;
-	
-	cp = container_of(dev, struct channel_path, dev);
-	kfree(cp);
-}
-
-static int
-chsc_determine_channel_path_description(int chpid,
-					struct channel_path_desc *desc)
+int chsc_determine_channel_path_description(struct chp_id chpid,
+					    struct channel_path_desc *desc)
 {
 	int ccode, ret;
 
@@ -1252,8 +851,8 @@ chsc_determine_channel_path_description(
 	scpd_area->request.length = 0x0010;
 	scpd_area->request.code = 0x0002;
 
-	scpd_area->first_chpid = chpid;
-	scpd_area->last_chpid = chpid;
+	scpd_area->first_chpid = chpid.id;
+	scpd_area->last_chpid = chpid.id;
 
 	ccode = chsc(scpd_area);
 	if (ccode > 0) {
@@ -1316,8 +915,7 @@ chsc_initialize_cmg_chars(struct channel
 	}
 }
 
-static int
-chsc_get_channel_measurement_chars(struct channel_path *chp)
+int chsc_get_channel_measurement_chars(struct channel_path *chp)
 {
 	int ccode, ret;
 
@@ -1349,8 +947,8 @@ chsc_get_channel_measurement_chars(struc
 	scmc_area->request.length = 0x0010;
 	scmc_area->request.code = 0x0022;
 
-	scmc_area->first_chpid = chp->id;
-	scmc_area->last_chpid = chp->id;
+	scmc_area->first_chpid = chp->chpid.id;
+	scmc_area->last_chpid = chp->chpid.id;
 
 	ccode = chsc(scmc_area);
 	if (ccode > 0) {
@@ -1392,94 +990,6 @@ out:
 	return ret;
 }
 
-/*
- * Entries for chpids on the system bus.
- * This replaces /proc/chpids.
- */
-static int
-new_channel_path(int chpid)
-{
-	struct channel_path *chp;
-	int ret;
-
-	chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);
-	if (!chp)
-		return -ENOMEM;
-
-	/* fill in status, etc. */
-	chp->id = chpid;
-	chp->state = 1;
-	chp->dev.parent = &css[0]->device;
-	chp->dev.release = chp_release;
-	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
-
-	/* Obtain channel path description and fill it in. */
-	ret = chsc_determine_channel_path_description(chpid, &chp->desc);
-	if (ret)
-		goto out_free;
-	/* Get channel-measurement characteristics. */
-	if (css_characteristics_avail && css_chsc_characteristics.scmc
-	    && css_chsc_characteristics.secm) {
-		ret = chsc_get_channel_measurement_chars(chp);
-		if (ret)
-			goto out_free;
-	} else {
-		static int msg_done;
-
-		if (!msg_done) {
-			printk(KERN_WARNING "cio: Channel measurements not "
-			       "available, continuing.\n");
-			msg_done = 1;
-		}
-		chp->cmg = -1;
-	}
-
-	/* make it known to the system */
-	ret = device_register(&chp->dev);
-	if (ret) {
-		printk(KERN_WARNING "%s: could not register %02x\n",
-		       __func__, chpid);
-		goto out_free;
-	}
-	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
-	if (ret) {
-		device_unregister(&chp->dev);
-		goto out_free;
-	}
-	mutex_lock(&css[0]->mutex);
-	if (css[0]->cm_enabled) {
-		ret = chsc_add_chp_cmg_attr(chp);
-		if (ret) {
-			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
-			device_unregister(&chp->dev);
-			mutex_unlock(&css[0]->mutex);
-			goto out_free;
-		}
-	}
-	css[0]->chps[chpid] = chp;
-	mutex_unlock(&css[0]->mutex);
-	return ret;
-out_free:
-	kfree(chp);
-	return ret;
-}
-
-void *
-chsc_get_chp_desc(struct subchannel *sch, int chp_no)
-{
-	struct channel_path *chp;
-	struct channel_path_desc *desc;
-
-	chp = css[0]->chps[sch->schib.pmcw.chpid[chp_no]];
-	if (!chp)
-		return NULL;
-	desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);
-	if (!desc)
-		return NULL;
-	memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));
-	return desc;
-}
-
 static int __init
 chsc_alloc_sei_area(void)
 {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 0fb2b02..2ad81d1 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -1,9 +1,10 @@
 #ifndef S390_CHSC_H
 #define S390_CHSC_H
 
-#define CHSC_SEI_ACC_CHPID        1
-#define CHSC_SEI_ACC_LINKADDR     2
-#define CHSC_SEI_ACC_FULLLINKADDR 3
+#include <linux/types.h>
+#include <linux/device.h>
+#include <asm/chpid.h>
+#include "schid.h"
 
 #define CHSC_SDA_OC_MSS   0x2
 
@@ -33,23 +34,9 @@ struct channel_path_desc {
 	u8 chpp;
 } __attribute__ ((packed));
 
-struct channel_path {
-	int id;
-	int state;
-	struct channel_path_desc desc;
-	/* Channel-measurement related stuff: */
-	int cmg;
-	int shared;
-	void *cmg_chars;
-	struct device dev;
-};
+struct channel_path;
 
-extern void s390_process_css( void );
-extern void chsc_validate_chpids(struct subchannel *);
-extern void chpid_is_actually_online(int);
-extern int css_get_ssd_info(struct subchannel *);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
+extern void chsc_process_crw(void);
 
 struct css_general_char {
 	u64 : 41;
@@ -82,15 +69,26 @@ struct css_chsc_char {
 extern struct css_general_char css_general_characteristics;
 extern struct css_chsc_char css_chsc_characteristics;
 
+struct chsc_ssd_info {
+	u8 path_mask;
+	u8 fla_valid_mask;
+	struct chp_id chpid[8];
+	u16 fla[8];
+};
+extern int chsc_get_ssd_info(struct subchannel_id schid,
+			     struct chsc_ssd_info *ssd);
 extern int chsc_determine_css_characteristics(void);
 extern int css_characteristics_avail;
 
-extern void *chsc_get_chp_desc(struct subchannel*, int);
-
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
 
-#define to_channelpath(device) container_of(device, struct channel_path, dev)
+int chsc_chp_vary(struct chp_id chpid, int on);
+int chsc_determine_channel_path_description(struct chp_id chpid,
+					    struct channel_path_desc *desc);
+void chsc_chp_online(struct chp_id chpid);
+void chsc_chp_offline(struct chp_id chpid);
+int chsc_get_channel_measurement_chars(struct channel_path *chp);
 
 #endif
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 9cb129a..ea1defb 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -22,6 +22,7 @@ #include <asm/irq_regs.h>
 #include <asm/setup.h>
 #include <asm/reset.h>
 #include <asm/ipl.h>
+#include <asm/chpid.h>
 #include "airq.h"
 #include "cio.h"
 #include "css.h"
@@ -29,6 +30,7 @@ #include "chsc.h"
 #include "ioasm.h"
 #include "blacklist.h"
 #include "cio_debug.h"
+#include "chp.h"
 #include "../s390mach.h"
 
 debug_info_t *cio_debug_msg_id;
@@ -592,9 +594,10 @@ cio_validate_subchannel (struct subchann
 		err = -ENODEV;
 		goto out;
 	}
-	sch->opm = 0xff;
-	if (!cio_is_console(sch->schid))
-		chsc_validate_chpids(sch);
+	if (cio_is_console(sch->schid))
+		sch->opm = 0xff;
+	else
+		sch->opm = chp_get_sch_opm(sch);
 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
 	CIO_DEBUG(KERN_INFO, 0,
@@ -954,6 +957,7 @@ static void css_reset(void)
 {
 	int i, ret;
 	unsigned long long timeout;
+	struct chp_id chpid;
 
 	/* Reset subchannels. */
 	for_each_subchannel(__shutdown_subchannel_easy,  NULL);
@@ -963,8 +967,10 @@ static void css_reset(void)
 	__ctl_set_bit(14, 28);
 	/* Temporarily reenable machine checks. */
 	local_mcck_enable();
+	chp_id_init(&chpid);
 	for (i = 0; i <= __MAX_CHPID; i++) {
-		ret = rchp(i);
+		chpid.id = i;
+		ret = rchp(chpid);
 		if ((ret == 0) || (ret == 2))
 			/*
 			 * rchp either succeeded, or another rchp is already
@@ -1048,37 +1054,19 @@ void reipl_ccw_dev(struct ccw_dev_id *de
 	do_reipl_asm(*((__u32*)&schid));
 }
 
-static struct schib __initdata 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)
+int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
 {
 	struct subchannel_id schid;
-	unsigned int *ipl_ptr;
-	void *src, *dst;
+	struct schib schib;
 
 	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;
+		return -ENODEV;
+	if (stsch(schid, &schib))
+		return -ENODEV;
+	if (!schib.pmcw.dnv)
+		return -ENODEV;
+	iplinfo->devno = schib.pmcw.dev;
+	iplinfo->is_qdio = schib.pmcw.qf;
+	return 0;
 }
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 35154a2..7446c39 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -1,18 +1,11 @@
 #ifndef S390_CIO_H
 #define S390_CIO_H
 
-#include "schid.h"
 #include <linux/mutex.h>
-
-/*
- * where we put the ssd info
- */
-struct ssd_info {
-	__u8  valid:1;
-	__u8  type:7;		/* subchannel type */
-	__u8  chpid[8];		/* chpids */
-	__u16 fla[8];		/* full link addresses */
-} __attribute__ ((packed));
+#include <linux/device.h>
+#include <asm/chpid.h>
+#include "chsc.h"
+#include "schid.h"
 
 /*
  * path management control word
@@ -108,7 +101,7 @@ struct subchannel {
 	struct schib schib;	/* subchannel information block */
 	struct orb orb;		/* operation request block */
 	struct ccw1 sense_ccw;	/* static ccw for sense command */
-	struct ssd_info ssd_info;	/* subchannel description */
+	struct chsc_ssd_info ssd_info;	/* subchannel description */
 	struct device dev;	/* entry in device tree */
 	struct css_driver *driver;
 } __attribute__ ((aligned(8)));
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 90b22fa..28abd69 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -476,7 +476,7 @@ struct cmb_area {
 };
 
 static struct cmb_area cmb_area = {
-	.lock = SPIN_LOCK_UNLOCKED,
+	.lock = __SPIN_LOCK_UNLOCKED(cmb_area.lock),
 	.list = LIST_HEAD_INIT(cmb_area.list),
 	.num_channels  = 1024,
 };
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index fe0ace7..27c6d9e 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -20,8 +20,9 @@ #include "cio_debug.h"
 #include "ioasm.h"
 #include "chsc.h"
 #include "device.h"
+#include "idset.h"
+#include "chp.h"
 
-int need_rescan = 0;
 int css_init_done = 0;
 static int need_reprobe = 0;
 static int max_ssid = 0;
@@ -125,8 +126,52 @@ void css_sch_device_unregister(struct su
 	mutex_unlock(&sch->reg_mutex);
 }
 
-static int
-css_register_subchannel(struct subchannel *sch)
+static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
+{
+	int i;
+	int mask;
+
+	memset(ssd, 0, sizeof(struct chsc_ssd_info));
+	ssd->path_mask = pmcw->pim;
+	for (i = 0; i < 8; i++) {
+		mask = 0x80 >> i;
+		if (pmcw->pim & mask) {
+			chp_id_init(&ssd->chpid[i]);
+			ssd->chpid[i].id = pmcw->chpid[i];
+		}
+	}
+}
+
+static void ssd_register_chpids(struct chsc_ssd_info *ssd)
+{
+	int i;
+	int mask;
+
+	for (i = 0; i < 8; i++) {
+		mask = 0x80 >> i;
+		if (ssd->path_mask & mask)
+			if (!chp_is_registered(ssd->chpid[i]))
+				chp_new(ssd->chpid[i]);
+	}
+}
+
+void css_update_ssd_info(struct subchannel *sch)
+{
+	int ret;
+
+	if (cio_is_console(sch->schid)) {
+		/* Console is initialized too early for functions requiring
+		 * memory allocation. */
+		ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
+	} else {
+		ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
+		if (ret)
+			ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
+		ssd_register_chpids(&sch->ssd_info);
+	}
+}
+
+static int css_register_subchannel(struct subchannel *sch)
 {
 	int ret;
 
@@ -135,9 +180,7 @@ css_register_subchannel(struct subchanne
 	sch->dev.bus = &css_bus_type;
 	sch->dev.release = &css_subchannel_release;
 	sch->dev.groups = subch_attr_groups;
-
-	css_get_ssd_info(sch);
-
+	css_update_ssd_info(sch);
 	/* make it known to the system */
 	ret = css_sch_device_register(sch);
 	if (ret) {
@@ -306,7 +349,7 @@ static int css_evaluate_new_subchannel(s
 	return css_probe_device(schid);
 }
 
-static int css_evaluate_subchannel(struct subchannel_id schid, int slow)
+static void css_evaluate_subchannel(struct subchannel_id schid, int slow)
 {
 	struct subchannel *sch;
 	int ret;
@@ -317,53 +360,66 @@ static int css_evaluate_subchannel(struc
 		put_device(&sch->dev);
 	} else
 		ret = css_evaluate_new_subchannel(schid, slow);
-
-	return ret;
+	if (ret == -EAGAIN)
+		css_schedule_eval(schid);
 }
 
-static int
-css_rescan_devices(struct subchannel_id schid, void *data)
+static struct idset *slow_subchannel_set;
+static spinlock_t slow_subchannel_lock;
+
+static int __init slow_subchannel_init(void)
 {
-	return css_evaluate_subchannel(schid, 1);
+	spin_lock_init(&slow_subchannel_lock);
+	slow_subchannel_set = idset_sch_new();
+	if (!slow_subchannel_set) {
+		printk(KERN_WARNING "cio: could not allocate slow subchannel "
+		       "set\n");
+		return -ENOMEM;
+	}
+	return 0;
 }
 
-struct slow_subchannel {
-	struct list_head slow_list;
-	struct subchannel_id schid;
-};
-
-static LIST_HEAD(slow_subchannels_head);
-static DEFINE_SPINLOCK(slow_subchannel_lock);
+subsys_initcall(slow_subchannel_init);
 
-static void
-css_trigger_slow_path(struct work_struct *unused)
+static void css_slow_path_func(struct work_struct *unused)
 {
-	CIO_TRACE_EVENT(4, "slowpath");
-
-	if (need_rescan) {
-		need_rescan = 0;
-		for_each_subchannel(css_rescan_devices, NULL);
-		return;
-	}
+	struct subchannel_id schid;
 
+	CIO_TRACE_EVENT(4, "slowpath");
 	spin_lock_irq(&slow_subchannel_lock);
-	while (!list_empty(&slow_subchannels_head)) {
-		struct slow_subchannel *slow_sch =
-			list_entry(slow_subchannels_head.next,
-				   struct slow_subchannel, slow_list);
-
-		list_del_init(slow_subchannels_head.next);
+	init_subchannel_id(&schid);
+	while (idset_sch_get_first(slow_subchannel_set, &schid)) {
+		idset_sch_del(slow_subchannel_set, schid);
 		spin_unlock_irq(&slow_subchannel_lock);
-		css_evaluate_subchannel(slow_sch->schid, 1);
+		css_evaluate_subchannel(schid, 1);
 		spin_lock_irq(&slow_subchannel_lock);
-		kfree(slow_sch);
 	}
 	spin_unlock_irq(&slow_subchannel_lock);
 }
 
-DECLARE_WORK(slow_path_work, css_trigger_slow_path);
+static DECLARE_WORK(slow_path_work, css_slow_path_func);
 struct workqueue_struct *slow_path_wq;
 
+void css_schedule_eval(struct subchannel_id schid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&slow_subchannel_lock, flags);
+	idset_sch_add(slow_subchannel_set, schid);
+	queue_work(slow_path_wq, &slow_path_work);
+	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
+}
+
+void css_schedule_eval_all(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&slow_subchannel_lock, flags);
+	idset_fill(slow_subchannel_set);
+	queue_work(slow_path_wq, &slow_path_work);
+	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
+}
+
 /* Reprobe subchannel if unregistered. */
 static int reprobe_subchannel(struct subchannel_id schid, void *data)
 {
@@ -426,33 +482,14 @@ void css_schedule_reprobe(void)
 EXPORT_SYMBOL_GPL(css_schedule_reprobe);
 
 /*
- * Rescan for new devices. FIXME: This is slow.
- * This function is called when we have lost CRWs due to overflows and we have
- * to do subchannel housekeeping.
- */
-void
-css_reiterate_subchannels(void)
-{
-	css_clear_subchannel_slow_list();
-	need_rescan = 1;
-}
-
-/*
  * Called from the machine check handler for subchannel report words.
  */
-int
-css_process_crw(int rsid1, int rsid2)
+void css_process_crw(int rsid1, int rsid2)
 {
-	int ret;
 	struct subchannel_id mchk_schid;
 
 	CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n",
 		      rsid1, rsid2);
-
-	if (need_rescan)
-		/* We need to iterate all subchannels anyway. */
-		return -EAGAIN;
-
 	init_subchannel_id(&mchk_schid);
 	mchk_schid.sch_no = rsid1;
 	if (rsid2 != 0)
@@ -463,14 +500,7 @@ css_process_crw(int rsid1, int rsid2)
 	 * use stsch() to find out if the subchannel in question has come
 	 * or gone.
 	 */
-	ret = css_evaluate_subchannel(mchk_schid, 0);
-	if (ret == -EAGAIN) {
-		if (css_enqueue_subchannel_slow(mchk_schid)) {
-			css_clear_subchannel_slow_list();
-			need_rescan = 1;
-		}
-	}
-	return ret;
+	css_evaluate_subchannel(mchk_schid, 0);
 }
 
 static int __init
@@ -745,47 +775,6 @@ struct bus_type css_bus_type = {
 
 subsys_initcall(init_channel_subsystem);
 
-int
-css_enqueue_subchannel_slow(struct subchannel_id schid)
-{
-	struct slow_subchannel *new_slow_sch;
-	unsigned long flags;
-
-	new_slow_sch = kzalloc(sizeof(struct slow_subchannel), GFP_ATOMIC);
-	if (!new_slow_sch)
-		return -ENOMEM;
-	new_slow_sch->schid = schid;
-	spin_lock_irqsave(&slow_subchannel_lock, flags);
-	list_add_tail(&new_slow_sch->slow_list, &slow_subchannels_head);
-	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
-	return 0;
-}
-
-void
-css_clear_subchannel_slow_list(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&slow_subchannel_lock, flags);
-	while (!list_empty(&slow_subchannels_head)) {
-		struct slow_subchannel *slow_sch =
-			list_entry(slow_subchannels_head.next,
-				   struct slow_subchannel, slow_list);
-
-		list_del_init(slow_subchannels_head.next);
-		kfree(slow_sch);
-	}
-	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
-}
-
-
-
-int
-css_slow_subchannels_exist(void)
-{
-	return (!list_empty(&slow_subchannels_head));
-}
-
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(css_bus_type);
 EXPORT_SYMBOL_GPL(css_characteristics_avail);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ca2bab9..71fcfdc 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -4,8 +4,11 @@ #define _CSS_H
 #include <linux/mutex.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/types.h>
 
 #include <asm/cio.h>
+#include <asm/chpid.h>
 
 #include "schid.h"
 
@@ -143,13 +146,12 @@ extern void css_sch_device_unregister(st
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
-extern int css_process_crw(int, int);
+extern void css_process_crw(int, int);
 extern void css_reiterate_subchannels(void);
+void css_update_ssd_info(struct subchannel *sch);
 
 #define __MAX_SUBCHANNEL 65535
 #define __MAX_SSID 3
-#define __MAX_CHPID 255
-#define __MAX_CSSID 0
 
 struct channel_subsystem {
 	u8 cssid;
@@ -185,16 +187,12 @@ int device_trigger_verify(struct subchan
 void device_kill_pending_timer(struct subchannel *);
 
 /* Helper functions to build lists for the slow path. */
-extern int css_enqueue_subchannel_slow(struct subchannel_id schid);
-void css_walk_subchannel_slow_list(void (*fn)(unsigned long));
-void css_clear_subchannel_slow_list(void);
-int css_slow_subchannels_exist(void);
-extern int need_rescan;
+void css_schedule_eval(struct subchannel_id schid);
+void css_schedule_eval_all(void);
 
 int sch_is_pseudo_sch(struct subchannel *);
 
 extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
 
 int subchannel_add_files (struct device *);
 extern struct attribute_group *subch_attr_groups[];
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e322111..a23ff58 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -56,13 +56,12 @@ ccw_bus_match (struct device * dev, stru
 /* 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,
+static int snprint_alias(char *buf, size_t size,
 			 struct ccw_device_id *id, const char *suffix)
 {
 	int len;
 
-	len = snprintf(buf, size, "%sccw:t%04Xm%02X", prefix, id->cu_type,
-		       id->cu_model);
+	len = snprintf(buf, size, "ccw:t%04Xm%02X", id->cu_type, id->cu_model);
 	if (len > size)
 		return len;
 	buf += len;
@@ -85,53 +84,40 @@ static int ccw_uevent(struct device *dev
 	struct ccw_device *cdev = to_ccwdev(dev);
 	struct ccw_device_id *id = &(cdev->id);
 	int i = 0;
-	int len;
+	int len = 0;
+	int ret;
+	char modalias_buf[30];
 
 	/* 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;
-	buffer += len;
-	buffer_size -= len;
+	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			     "CU_TYPE=%04X", id->cu_type);
+	if (ret)
+		return ret;
 
 	/* CU_MODEL= */
-	len = snprintf(buffer, buffer_size, "CU_MODEL=%02X", id->cu_model) + 1;
-	if (len > buffer_size || i >= num_envp)
-		return -ENOMEM;
-	envp[i++] = buffer;
-	buffer += len;
-	buffer_size -= len;
+	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			     "CU_MODEL=%02X", id->cu_model);
+	if (ret)
+		return ret;
 
 	/* The next two can be zero, that's ok for us */
 	/* DEV_TYPE= */
-	len = snprintf(buffer, buffer_size, "DEV_TYPE=%04X", id->dev_type) + 1;
-	if (len > buffer_size || i >= num_envp)
-		return -ENOMEM;
-	envp[i++] = buffer;
-	buffer += len;
-	buffer_size -= len;
+	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			     "DEV_TYPE=%04X", id->dev_type);
+	if (ret)
+		return ret;
 
 	/* 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;
-	buffer += len;
-	buffer_size -= len;
+	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			     "DEV_MODEL=%02X", id->dev_model);
+	if (ret)
+		return ret;
 
 	/* 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;
-
-	return 0;
+	snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
+	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			     "MODALIAS=%s", modalias_buf);
+	return ret;
 }
 
 struct bus_type ccw_bus_type;
@@ -230,12 +216,18 @@ static ssize_t
 chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
 {
 	struct subchannel *sch = to_subchannel(dev);
-	struct ssd_info *ssd = &sch->ssd_info;
+	struct chsc_ssd_info *ssd = &sch->ssd_info;
 	ssize_t ret = 0;
 	int chp;
+	int mask;
 
-	for (chp = 0; chp < 8; chp++)
-		ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
+	for (chp = 0; chp < 8; chp++) {
+		mask = 0x80 >> chp;
+		if (ssd->path_mask & mask)
+			ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id);
+		else
+			ret += sprintf(buf + ret, "00 ");
+	}
 	ret += sprintf (buf+ret, "\n");
 	return min((ssize_t)PAGE_SIZE, ret);
 }
@@ -280,7 +272,7 @@ modalias_show (struct device *dev, struc
 	struct ccw_device_id *id = &(cdev->id);
 	int len;
 
-	len = snprint_alias(buf, PAGE_SIZE, "", id, "\n") + 1;
+	len = snprint_alias(buf, PAGE_SIZE, id, "\n") + 1;
 
 	return len > PAGE_SIZE ? PAGE_SIZE : len;
 }
@@ -298,16 +290,10 @@ int ccw_device_is_orphan(struct ccw_devi
 	return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent));
 }
 
-static void ccw_device_unregister(struct work_struct *work)
+static void ccw_device_unregister(struct ccw_device *cdev)
 {
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
 	if (test_and_clear_bit(1, &cdev->private->registered))
-		device_unregister(&cdev->dev);
-	put_device(&cdev->dev);
+		device_del(&cdev->dev);
 }
 
 static void
@@ -324,11 +310,8 @@ ccw_device_remove_disconnected(struct cc
 		spin_lock_irqsave(cdev->ccwlock, flags);
 		cdev->private->state = DEV_STATE_NOT_OPER;
 		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		if (get_device(&cdev->dev)) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_unregister);
-			queue_work(ccw_device_work, &cdev->private->kick_work);
-		}
+		ccw_device_unregister(cdev);
+		put_device(&cdev->dev);
 		return ;
 	}
 	sch = to_subchannel(cdev->dev.parent);
@@ -413,11 +396,60 @@ ccw_device_set_online(struct ccw_device 
 	return (ret == 0) ? -ENODEV : ret;
 }
 
-static ssize_t
-online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static void online_store_handle_offline(struct ccw_device *cdev)
+{
+	if (cdev->private->state == DEV_STATE_DISCONNECTED)
+		ccw_device_remove_disconnected(cdev);
+	else if (cdev->drv && cdev->drv->set_offline)
+		ccw_device_set_offline(cdev);
+}
+
+static int online_store_recog_and_online(struct ccw_device *cdev)
+{
+	int ret;
+
+	/* Do device recognition, if needed. */
+	if (cdev->id.cu_type == 0) {
+		ret = ccw_device_recognition(cdev);
+		if (ret) {
+			printk(KERN_WARNING"Couldn't start recognition "
+			       "for device %s (ret=%d)\n",
+			       cdev->dev.bus_id, ret);
+			return ret;
+		}
+		wait_event(cdev->private->wait_q,
+			   cdev->private->flags.recog_done);
+	}
+	if (cdev->drv && cdev->drv->set_online)
+		ccw_device_set_online(cdev);
+	return 0;
+}
+static void online_store_handle_online(struct ccw_device *cdev, int force)
+{
+	int ret;
+
+	ret = online_store_recog_and_online(cdev);
+	if (ret)
+		return;
+	if (force && cdev->private->state == DEV_STATE_BOXED) {
+		ret = ccw_device_stlck(cdev);
+		if (ret) {
+			printk(KERN_WARNING"ccw_device_stlck for device %s "
+			       "returned %d!\n", cdev->dev.bus_id, ret);
+			return;
+		}
+		if (cdev->id.cu_type == 0)
+			cdev->private->state = DEV_STATE_NOT_OPER;
+		online_store_recog_and_online(cdev);
+	}
+
+}
+
+static ssize_t online_store (struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
-	int i, force, ret;
+	int i, force;
 	char *tmp;
 
 	if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
@@ -434,51 +466,17 @@ online_store (struct device *dev, struct
 		force = 0;
 		i = simple_strtoul(buf, &tmp, 16);
 	}
-	if (i == 1) {
-		/* Do device recognition, if needed. */
-		if (cdev->id.cu_type == 0) {
-			ret = ccw_device_recognition(cdev);
-			if (ret) {
-				printk(KERN_WARNING"Couldn't start recognition "
-				       "for device %s (ret=%d)\n",
-				       cdev->dev.bus_id, ret);
-				goto out;
-			}
-			wait_event(cdev->private->wait_q,
-				   cdev->private->flags.recog_done);
-		}
-		if (cdev->drv && cdev->drv->set_online)
-			ccw_device_set_online(cdev);
-	} else if (i == 0) {
-		if (cdev->private->state == DEV_STATE_DISCONNECTED)
-			ccw_device_remove_disconnected(cdev);
-		else if (cdev->drv && cdev->drv->set_offline)
-			ccw_device_set_offline(cdev);
-	}
-	if (force && cdev->private->state == DEV_STATE_BOXED) {
-		ret = ccw_device_stlck(cdev);
-		if (ret) {
-			printk(KERN_WARNING"ccw_device_stlck for device %s "
-			       "returned %d!\n", cdev->dev.bus_id, ret);
-			goto out;
-		}
-		/* Do device recognition, if needed. */
-		if (cdev->id.cu_type == 0) {
-			cdev->private->state = DEV_STATE_NOT_OPER;
-			ret = ccw_device_recognition(cdev);
-			if (ret) {
-				printk(KERN_WARNING"Couldn't start recognition "
-				       "for device %s (ret=%d)\n",
-				       cdev->dev.bus_id, ret);
-				goto out;
-			}
-			wait_event(cdev->private->wait_q,
-				   cdev->private->flags.recog_done);
-		}
-		if (cdev->drv && cdev->drv->set_online)
-			ccw_device_set_online(cdev);
+
+	switch (i) {
+	case 0:
+		online_store_handle_offline(cdev);
+		break;
+	case 1:
+		online_store_handle_online(cdev, force);
+		break;
+	default:
+		count = -EINVAL;
 	}
-	out:
 	if (cdev->drv)
 		module_put(cdev->drv->owner);
 	atomic_set(&cdev->private->onoff, 0);
@@ -548,17 +546,10 @@ static struct attribute_group ccwdev_att
 	.attrs = ccwdev_attrs,
 };
 
-static int
-device_add_files (struct device *dev)
-{
-	return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
-}
-
-static void
-device_remove_files(struct device *dev)
-{
-	sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
-}
+struct attribute_group *ccwdev_attr_groups[] = {
+	&ccwdev_attr_group,
+	NULL,
+};
 
 /* this is a simple abstraction for device_register that sets the
  * correct bus type and adds the bus specific files */
@@ -573,10 +564,6 @@ static int ccw_device_register(struct cc
 		return ret;
 
 	set_bit(1, &cdev->private->registered);
-	if ((ret = device_add_files(dev))) {
-		if (test_and_clear_bit(1, &cdev->private->registered))
-			device_del(dev);
-	}
 	return ret;
 }
 
@@ -648,10 +635,6 @@ ccw_device_add_changed(struct work_struc
 		return;
 	}
 	set_bit(1, &cdev->private->registered);
-	if (device_add_files(&cdev->dev)) {
-		if (test_and_clear_bit(1, &cdev->private->registered))
-			device_unregister(&cdev->dev);
-	}
 }
 
 void ccw_device_do_unreg_rereg(struct work_struct *work)
@@ -664,9 +647,7 @@ void ccw_device_do_unreg_rereg(struct wo
 	cdev = priv->cdev;
 	sch = to_subchannel(cdev->dev.parent);
 
-	device_remove_files(&cdev->dev);
-	if (test_and_clear_bit(1, &cdev->private->registered))
-		device_del(&cdev->dev);
+	ccw_device_unregister(cdev);
 	PREPARE_WORK(&cdev->private->kick_work,
 		     ccw_device_add_changed);
 	queue_work(ccw_device_work, &cdev->private->kick_work);
@@ -705,6 +686,7 @@ static int io_subchannel_initialize_dev(
 	cdev->dev.parent = &sch->dev;
 	cdev->dev.release = ccw_device_release;
 	INIT_LIST_HEAD(&cdev->private->kick_work.entry);
+	cdev->dev.groups = ccwdev_attr_groups;
 	/* Do first half of device_register. */
 	device_initialize(&cdev->dev);
 	if (!get_device(&sch->dev)) {
@@ -736,6 +718,7 @@ static int io_subchannel_recog(struct cc
 static void sch_attach_device(struct subchannel *sch,
 			      struct ccw_device *cdev)
 {
+	css_update_ssd_info(sch);
 	spin_lock_irq(sch->lock);
 	sch->dev.driver_data = cdev;
 	cdev->private->schid = sch->schid;
@@ -871,7 +854,7 @@ io_subchannel_register(struct work_struc
 	priv = container_of(work, struct ccw_device_private, kick_work);
 	cdev = priv->cdev;
 	sch = to_subchannel(cdev->dev.parent);
-
+	css_update_ssd_info(sch);
 	/*
 	 * io_subchannel_register() will also be called after device
 	 * recognition has been done for a boxed device (which will already
@@ -888,6 +871,12 @@ io_subchannel_register(struct work_struc
 		}
 		goto out;
 	}
+	/*
+	 * Now we know this subchannel will stay, we can throw
+	 * our delayed uevent.
+	 */
+	sch->dev.uevent_suppress = 0;
+	kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
 	/* make it known to the system */
 	ret = ccw_device_register(cdev);
 	if (ret) {
@@ -1133,15 +1122,8 @@ io_subchannel_remove (struct subchannel 
 	sch->dev.driver_data = NULL;
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	spin_unlock_irqrestore(cdev->ccwlock, flags);
-	/*
-	 * Put unregistration on workqueue to avoid livelocks on the css bus
-	 * semaphore.
-	 */
-	if (get_device(&cdev->dev)) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_unregister);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
-	}
+	ccw_device_unregister(cdev);
+	put_device(&cdev->dev);
 	return 0;
 }
 
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 089a3dd..898ec3b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -15,6 +15,7 @@ #include <linux/string.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
+#include <asm/chpid.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -22,6 +23,7 @@ #include "css.h"
 #include "device.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "chp.h"
 
 int
 device_is_online(struct subchannel *sch)
@@ -210,14 +212,18 @@ static void
 __recover_lost_chpids(struct subchannel *sch, int old_lpm)
 {
 	int mask, i;
+	struct chp_id chpid;
 
+	chp_id_init(&chpid);
 	for (i = 0; i<8; i++) {
 		mask = 0x80 >> i;
 		if (!(sch->lpm & mask))
 			continue;
 		if (old_lpm & mask)
 			continue;
-		chpid_is_actually_online(sch->schib.pmcw.chpid[i]);
+		chpid.id = sch->schib.pmcw.chpid[i];
+		if (!chp_is_registered(chpid))
+			css_schedule_eval_all();
 	}
 }
 
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 7c7775a..16f59fc 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -16,12 +16,14 @@ #include <linux/delay.h>
 
 #include <asm/ccwdev.h>
 #include <asm/idals.h>
+#include <asm/chpid.h>
 
 #include "cio.h"
 #include "cio_debug.h"
 #include "css.h"
 #include "chsc.h"
 #include "device.h"
+#include "chp.h"
 
 int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
 {
@@ -606,9 +608,12 @@ void *
 ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
 {
 	struct subchannel *sch;
+	struct chp_id chpid;
 
 	sch = to_subchannel(cdev->dev.parent);
-	return chsc_get_chp_desc(sch, chp_no);
+	chp_id_init(&chpid);
+	chpid.id = sch->schib.pmcw.chpid[chp_no];
+	return chp_get_chp_desc(chpid);
 }
 
 // FIXME: these have to go:
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
new file mode 100644
index 0000000..16ea828
--- /dev/null
+++ b/drivers/s390/cio/idset.c
@@ -0,0 +1,112 @@
+/*
+ *  drivers/s390/cio/idset.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/slab.h>
+#include <asm/bitops.h>
+#include "idset.h"
+#include "css.h"
+
+struct idset {
+	int num_ssid;
+	int num_id;
+	unsigned long bitmap[0];
+};
+
+static inline unsigned long bitmap_size(int num_ssid, int num_id)
+{
+	return __BITOPS_WORDS(num_ssid * num_id) * sizeof(unsigned long);
+}
+
+static struct idset *idset_new(int num_ssid, int num_id)
+{
+	struct idset *set;
+
+	set = kzalloc(sizeof(struct idset) + bitmap_size(num_ssid, num_id),
+		      GFP_KERNEL);
+	if (set) {
+		set->num_ssid = num_ssid;
+		set->num_id = num_id;
+	}
+	return set;
+}
+
+void idset_free(struct idset *set)
+{
+	kfree(set);
+}
+
+void idset_clear(struct idset *set)
+{
+	memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id));
+}
+
+void idset_fill(struct idset *set)
+{
+	memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id));
+}
+
+static inline void idset_add(struct idset *set, int ssid, int id)
+{
+	set_bit(ssid * set->num_id + id, set->bitmap);
+}
+
+static inline void idset_del(struct idset *set, int ssid, int id)
+{
+	clear_bit(ssid * set->num_id + id, set->bitmap);
+}
+
+static inline int idset_contains(struct idset *set, int ssid, int id)
+{
+	return test_bit(ssid * set->num_id + id, set->bitmap);
+}
+
+static inline int idset_get_first(struct idset *set, int *ssid, int *id)
+{
+	int bitnum;
+
+	bitnum = find_first_bit(set->bitmap, set->num_ssid * set->num_id);
+	if (bitnum >= set->num_ssid * set->num_id)
+		return 0;
+	*ssid = bitnum / set->num_id;
+	*id = bitnum % set->num_id;
+	return 1;
+}
+
+struct idset *idset_sch_new(void)
+{
+	return idset_new(__MAX_SSID + 1, __MAX_SUBCHANNEL + 1);
+}
+
+void idset_sch_add(struct idset *set, struct subchannel_id schid)
+{
+	idset_add(set, schid.ssid, schid.sch_no);
+}
+
+void idset_sch_del(struct idset *set, struct subchannel_id schid)
+{
+	idset_del(set, schid.ssid, schid.sch_no);
+}
+
+int idset_sch_contains(struct idset *set, struct subchannel_id schid)
+{
+	return idset_contains(set, schid.ssid, schid.sch_no);
+}
+
+int idset_sch_get_first(struct idset *set, struct subchannel_id *schid)
+{
+	int ssid = 0;
+	int id = 0;
+	int rc;
+
+	rc = idset_get_first(set, &ssid, &id);
+	if (rc) {
+		init_subchannel_id(schid);
+		schid->ssid = ssid;
+		schid->sch_no = id;
+	}
+	return rc;
+}
diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h
new file mode 100644
index 0000000..144466a
--- /dev/null
+++ b/drivers/s390/cio/idset.h
@@ -0,0 +1,25 @@
+/*
+ *  drivers/s390/cio/idset.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef S390_IDSET_H
+#define S390_IDSET_H S390_IDSET_H
+
+#include "schid.h"
+
+struct idset;
+
+void idset_free(struct idset *set);
+void idset_clear(struct idset *set);
+void idset_fill(struct idset *set);
+
+struct idset *idset_sch_new(void);
+void idset_sch_add(struct idset *set, struct subchannel_id id);
+void idset_sch_del(struct idset *set, struct subchannel_id id);
+int idset_sch_contains(struct idset *set, struct subchannel_id id);
+int idset_sch_get_first(struct idset *set, struct subchannel_id *id);
+
+#endif /* S390_IDSET_H */
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index ad6d829..7153dd9 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -1,6 +1,7 @@
 #ifndef S390_CIO_IOASM_H
 #define S390_CIO_IOASM_H
 
+#include <asm/chpid.h>
 #include "schid.h"
 
 /*
@@ -189,9 +190,9 @@ static inline int chsc(void *chsc_area)
 	return cc;
 }
 
-static inline int rchp(int chpid)
+static inline int rchp(struct chp_id chpid)
 {
-	register unsigned int reg1 asm ("1") = chpid;
+	register struct chp_id reg1 asm ("1") = chpid;
 	int ccode;
 
 	asm volatile(
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 05fac07..f770018 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -69,7 +69,6 @@ static const char version[] = "QDIO base
 
 static int qdio_performance_stats = 0;
 static int proc_perf_file_registration;
-static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
 static struct qdio_perf_stats perf_stats;
 
 static int hydra_thinints;
@@ -111,6 +110,31 @@ qdio_min(int a,int b)
 }
 
 /***************** SCRUBBER HELPER ROUTINES **********************/
+#ifdef CONFIG_64BIT
+static inline void qdio_perf_stat_inc(atomic64_t *count)
+{
+	if (qdio_performance_stats)
+		atomic64_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic64_t *count)
+{
+	if (qdio_performance_stats)
+		atomic64_dec(count);
+}
+#else /* CONFIG_64BIT */
+static inline void qdio_perf_stat_inc(atomic_t *count)
+{
+	if (qdio_performance_stats)
+		atomic_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic_t *count)
+{
+	if (qdio_performance_stats)
+		atomic_dec(count);
+}
+#endif /* CONFIG_64BIT */
 
 static inline __u64 
 qdio_get_micros(void)
@@ -277,8 +301,7 @@ qdio_siga_sync(struct qdio_q *q, unsigne
 	QDIO_DBF_TEXT4(0,trace,"sigasync");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-	if (qdio_performance_stats)
-		perf_stats.siga_syncs++;
+	qdio_perf_stat_inc(&perf_stats.siga_syncs);
 
 	cc = do_siga_sync(q->schid, gpr2, gpr3);
 	if (cc)
@@ -323,8 +346,7 @@ qdio_siga_output(struct qdio_q *q)
 	__u32 busy_bit;
 	__u64 start_time=0;
 
-	if (qdio_performance_stats)
-		perf_stats.siga_outs++;
+	qdio_perf_stat_inc(&perf_stats.siga_outs);
 
 	QDIO_DBF_TEXT4(0,trace,"sigaout");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -358,8 +380,7 @@ qdio_siga_input(struct qdio_q *q)
 	QDIO_DBF_TEXT4(0,trace,"sigain");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-	if (qdio_performance_stats)
-		perf_stats.siga_ins++;
+	qdio_perf_stat_inc(&perf_stats.siga_ins);
 
 	cc = do_siga_input(q->schid, q->mask);
 	
@@ -953,8 +974,7 @@ __qdio_outbound_processing(struct qdio_q
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-		if (qdio_performance_stats)
-			o_p_c++;
+		qdio_perf_stat_inc(&perf_stats.outbound_tl_runs_resched);
 		/* as we're sissies, we'll check next time */
 		if (likely(!atomic_read(&q->is_in_shutdown))) {
 			qdio_mark_q(q);
@@ -962,10 +982,8 @@ __qdio_outbound_processing(struct qdio_q
 		}
 		return;
 	}
-	if (qdio_performance_stats) {
-		o_p_nc++;
-		perf_stats.tl_runs++;
-	}
+	qdio_perf_stat_inc(&perf_stats.outbound_tl_runs);
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 	/* see comment in qdio_kick_outbound_q */
 	siga_attempts=atomic_read(&q->busy_siga_counter);
@@ -978,18 +996,25 @@ __qdio_outbound_processing(struct qdio_q
 	if (qdio_has_outbound_q_moved(q))
 		qdio_kick_outbound_handler(q);
 
-	if (q->is_iqdio_q) {
+	if (q->queue_type == QDIO_ZFCP_QFMT) {
+		if ((!q->hydra_gives_outbound_pcis) &&
+		    (!qdio_is_outbound_q_done(q)))
+			qdio_mark_q(q);
+	}
+	else if (((!q->is_iqdio_q) && (!q->is_pci_out)) ||
+		 (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) {
 		/* 
-		 * for asynchronous queues, we better check, if the sent
-		 * buffer is already switched from PRIMED to EMPTY.
+		 * make sure buffer switch from PRIMED to EMPTY is noticed
+		 * and outbound_handler is called
 		 */
-		if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
-		    !qdio_is_outbound_q_done(q))
-			qdio_mark_q(q);
-
-	} else if (!q->hydra_gives_outbound_pcis)
-		if (!qdio_is_outbound_q_done(q))
-			qdio_mark_q(q);
+		if (qdio_is_outbound_q_done(q)) {
+			del_timer(&q->timer);
+		} else {
+			if (!timer_pending(&q->timer))
+				mod_timer(&q->timer, jiffies +
+					  QDIO_FORCE_CHECK_TIMEOUT);
+		}
+	}
 
 	qdio_release_q(q);
 }
@@ -1139,17 +1164,6 @@ qdio_has_inbound_q_moved(struct qdio_q *
 {
 	int i;
 
-	static int old_pcis=0;
-	static int old_thinints=0;
-
-	if (qdio_performance_stats) {
-		if ((old_pcis==perf_stats.pcis)&&
-		    (old_thinints==perf_stats.thinints))
-			perf_stats.start_time_inbound=NOW;
-		else
-			old_pcis=perf_stats.pcis;
-	}
-
 	i=qdio_get_inbound_buffer_frontier(q);
 	if ( (i!=GET_SAVED_FRONTIER(q)) ||
 	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {
@@ -1337,10 +1351,7 @@ #endif /* CONFIG_QDIO_DEBUG */
 	q->siga_error=0;
 	q->error_status_flags=0;
 
-	if (qdio_performance_stats) {
-		perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
-		perf_stats.inbound_cnt++;
-	}
+	qdio_perf_stat_inc(&perf_stats.inbound_cnt);
 }
 
 static void
@@ -1360,8 +1371,7 @@ __tiqdio_inbound_processing(struct qdio_
 	 */
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-		if (qdio_performance_stats)
-			ii_p_c++;
+		qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
 		/* 
 		 * as we might just be about to stop polling, we make
 		 * sure that we check again at least once more 
@@ -1369,8 +1379,7 @@ __tiqdio_inbound_processing(struct qdio_
 		tiqdio_sched_tl();
 		return;
 	}
-	if (qdio_performance_stats)
-		ii_p_nc++;
+	qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs);
 	if (unlikely(atomic_read(&q->is_in_shutdown))) {
 		qdio_unmark_q(q);
 		goto out;
@@ -1412,8 +1421,7 @@ __tiqdio_inbound_processing(struct qdio_
 		for (i=0;i<irq_ptr->no_output_qs;i++) {
 			oq = irq_ptr->output_qs[i];
 			if (!qdio_is_outbound_q_done(oq)) {
-				if (qdio_performance_stats)
-					perf_stats.tl_runs--;
+				qdio_perf_stat_dec(&perf_stats.tl_runs);
 				__qdio_outbound_processing(oq);
 			}
 		}
@@ -1452,8 +1460,7 @@ __qdio_inbound_processing(struct qdio_q 
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-		if (qdio_performance_stats)
-			i_p_c++;
+		qdio_perf_stat_inc(&perf_stats.inbound_tl_runs_resched);
 		/* as we're sissies, we'll check next time */
 		if (likely(!atomic_read(&q->is_in_shutdown))) {
 			qdio_mark_q(q);
@@ -1461,10 +1468,8 @@ __qdio_inbound_processing(struct qdio_q 
 		}
 		return;
 	}
-	if (qdio_performance_stats) {
-		i_p_nc++;
-		perf_stats.tl_runs++;
-	}
+	qdio_perf_stat_inc(&perf_stats.inbound_tl_runs);
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 again:
 	if (qdio_has_inbound_q_moved(q)) {
@@ -1510,8 +1515,7 @@ tiqdio_reset_processing_state(struct qdi
 
 	if (unlikely(qdio_reserve_q(q))) {
 		qdio_release_q(q);
-		if (qdio_performance_stats)
-			ii_p_c++;
+		qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
 		/* 
 		 * as we might just be about to stop polling, we make
 		 * sure that we check again at least once more 
@@ -1602,8 +1606,7 @@ tiqdio_tl(unsigned long data)
 {
 	QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
 
-	if (qdio_performance_stats)
-		perf_stats.tl_runs++;
+	qdio_perf_stat_inc(&perf_stats.tl_runs);
 
 	tiqdio_inbound_checks();
 }
@@ -1830,6 +1833,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, s
 			q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
 		q->int_parm=int_parm;
 		q->is_input_q=0;
+		q->is_pci_out = 0;
 		q->schid = irq_ptr->schid;
 		q->cdev = cdev;
 		q->irq_ptr = irq_ptr;
@@ -1842,6 +1846,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, s
 		q->tasklet.data=(unsigned long)q;
 		q->tasklet.func=(void(*)(unsigned long))
 			&qdio_outbound_processing;
+		q->timer.function=(void(*)(unsigned long))
+			&qdio_outbound_processing;
+		q->timer.data = (long)q;
+		init_timer(&q->timer);
 
 		atomic_set(&q->busy_siga_counter,0);
 		q->timing.busy_start=0;
@@ -1914,10 +1922,7 @@ tiqdio_thinint_handler(void)
 {
 	QDIO_DBF_TEXT4(0,trace,"thin_int");
 
-	if (qdio_performance_stats) {
-		perf_stats.thinints++;
-		perf_stats.start_time_inbound=NOW;
-	}
+	qdio_perf_stat_inc(&perf_stats.thinints);
 
 	/* SVS only when needed:
 	 * issue SVS to benefit from iqdio interrupt avoidance
@@ -1972,17 +1977,12 @@ qdio_handle_pci(struct qdio_irq *irq_ptr
 	int i;
 	struct qdio_q *q;
 
-	if (qdio_performance_stats) {
-		perf_stats.pcis++;
-		perf_stats.start_time_inbound=NOW;
-	}
+	qdio_perf_stat_inc(&perf_stats.pcis);
 	for (i=0;i<irq_ptr->no_input_qs;i++) {
 		q=irq_ptr->input_qs[i];
 		if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
 			qdio_mark_q(q);
 		else {
-			if (qdio_performance_stats)
-				perf_stats.tl_runs--;
 			__qdio_inbound_processing(q);
 		}
 	}
@@ -1992,8 +1992,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr
 		q=irq_ptr->output_qs[i];
 		if (qdio_is_outbound_q_done(q))
 			continue;
-		if (qdio_performance_stats)
-			perf_stats.tl_runs--;
+		qdio_perf_stat_dec(&perf_stats.tl_runs);
 		if (!irq_ptr->sync_done_on_outb_pcis)
 			SYNC_MEMORY;
 		__qdio_outbound_processing(q);
@@ -2648,6 +2647,7 @@ qdio_shutdown(struct ccw_device *cdev, i
 
 	for (i=0;i<irq_ptr->no_output_qs;i++) {
 		tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
+		del_timer(&irq_ptr->output_qs[i]->timer);
 		wait_event_interruptible_timeout(cdev->private->wait_q,
 						 !atomic_read(&irq_ptr->
 							      output_qs[i]->
@@ -3463,20 +3463,18 @@ do_qdio_handle_outbound(struct qdio_q *q
 	struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
 
 	/* This is the outbound handling of queues */
-	if (qdio_performance_stats)
-		perf_stats.start_time_outbound=NOW;
-
 	qdio_do_qdio_fill_output(q,qidx,count,buffers);
 
 	used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 
 	if (callflags&QDIO_FLAG_DONT_SIGA) {
-		if (qdio_performance_stats) {
-			perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-			perf_stats.outbound_cnt++;
-		}
+		qdio_perf_stat_inc(&perf_stats.outbound_cnt);
 		return;
 	}
+	if (callflags & QDIO_FLAG_PCI_OUT)
+		q->is_pci_out = 1;
+	else
+		q->is_pci_out = 0;
 	if (q->is_iqdio_q) {
 		/* one siga for every sbal */
 		while (count--)
@@ -3504,8 +3502,7 @@ do_qdio_handle_outbound(struct qdio_q *q
 				qdio_kick_outbound_q(q);
 			} else {
 				QDIO_DBF_TEXT3(0,trace, "fast-req");
-				if (qdio_performance_stats)
-					perf_stats.fast_reqs++;
+				qdio_perf_stat_inc(&perf_stats.fast_reqs);
 			}
 		}
 		/* 
@@ -3516,10 +3513,7 @@ do_qdio_handle_outbound(struct qdio_q *q
 		__qdio_outbound_processing(q);
 	}
 
-	if (qdio_performance_stats) {
-		perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-		perf_stats.outbound_cnt++;
-	}
+	qdio_perf_stat_inc(&perf_stats.outbound_cnt);
 }
 
 /* count must be 1 in iqdio */
@@ -3589,33 +3583,67 @@ qdio_perf_procfile_read(char *buffer, ch
 		return 0;
 
 #define _OUTP_IT(x...) c+=sprintf(buffer+c,x)
-	_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
-	_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
-	_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
-	_OUTP_IT("Number of tasklet runs (total)                  : %lu\n",
-		 perf_stats.tl_runs);
+#ifdef CONFIG_64BIT
+	_OUTP_IT("Number of tasklet runs (total)                  : %li\n",
+		 (long)atomic64_read(&perf_stats.tl_runs));
+	_OUTP_IT("Inbound tasklet runs      tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.inbound_tl_runs),
+		 (long)atomic64_read(&perf_stats.inbound_tl_runs_resched));
+	_OUTP_IT("Inbound-thin tasklet runs tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.inbound_thin_tl_runs),
+		 (long)atomic64_read(&perf_stats.inbound_thin_tl_runs_resched));
+	_OUTP_IT("Outbound tasklet runs     tried/retried         : %li/%li\n",
+		 (long)atomic64_read(&perf_stats.outbound_tl_runs),
+		 (long)atomic64_read(&perf_stats.outbound_tl_runs_resched));
+	_OUTP_IT("\n");
+	_OUTP_IT("Number of SIGA sync's issued                    : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_syncs));
+	_OUTP_IT("Number of SIGA in's issued                      : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_ins));
+	_OUTP_IT("Number of SIGA out's issued                     : %li\n",
+		 (long)atomic64_read(&perf_stats.siga_outs));
+	_OUTP_IT("Number of PCIs caught                           : %li\n",
+		 (long)atomic64_read(&perf_stats.pcis));
+	_OUTP_IT("Number of adapter interrupts caught             : %li\n",
+		 (long)atomic64_read(&perf_stats.thinints));
+	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %li\n",
+		 (long)atomic64_read(&perf_stats.fast_reqs));
 	_OUTP_IT("\n");
-	_OUTP_IT("Number of SIGA sync's issued                    : %lu\n",
-		 perf_stats.siga_syncs);
-	_OUTP_IT("Number of SIGA in's issued                      : %lu\n",
-		 perf_stats.siga_ins);
-	_OUTP_IT("Number of SIGA out's issued                     : %lu\n",
-		 perf_stats.siga_outs);
-	_OUTP_IT("Number of PCIs caught                           : %lu\n",
-		 perf_stats.pcis);
-	_OUTP_IT("Number of adapter interrupts caught             : %lu\n",
-		 perf_stats.thinints);
-	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %lu\n",
-		 perf_stats.fast_reqs);
+	_OUTP_IT("Number of inbound transfers                     : %li\n",
+		 (long)atomic64_read(&perf_stats.inbound_cnt));
+	_OUTP_IT("Number of do_QDIOs outbound                     : %li\n",
+		 (long)atomic64_read(&perf_stats.outbound_cnt));
+#else /* CONFIG_64BIT */
+	_OUTP_IT("Number of tasklet runs (total)                  : %i\n",
+		 atomic_read(&perf_stats.tl_runs));
+	_OUTP_IT("Inbound tasklet runs      tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.inbound_tl_runs),
+		 atomic_read(&perf_stats.inbound_tl_runs_resched));
+	_OUTP_IT("Inbound-thin tasklet runs tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.inbound_thin_tl_runs),
+		 atomic_read(&perf_stats.inbound_thin_tl_runs_resched));
+	_OUTP_IT("Outbound tasklet runs     tried/retried         : %i/%i\n",
+		 atomic_read(&perf_stats.outbound_tl_runs),
+		 atomic_read(&perf_stats.outbound_tl_runs_resched));
 	_OUTP_IT("\n");
-	_OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
-		 perf_stats.inbound_time);
-	_OUTP_IT("Number of inbound transfers                     : %lu\n",
-		 perf_stats.inbound_cnt);
-	_OUTP_IT("Total time of all outbound do_QDIOs (us)        : %lu\n",
-		 perf_stats.outbound_time);
-	_OUTP_IT("Number of do_QDIOs outbound                     : %lu\n",
-		 perf_stats.outbound_cnt);
+	_OUTP_IT("Number of SIGA sync's issued                    : %i\n",
+		 atomic_read(&perf_stats.siga_syncs));
+	_OUTP_IT("Number of SIGA in's issued                      : %i\n",
+		 atomic_read(&perf_stats.siga_ins));
+	_OUTP_IT("Number of SIGA out's issued                     : %i\n",
+		 atomic_read(&perf_stats.siga_outs));
+	_OUTP_IT("Number of PCIs caught                           : %i\n",
+		 atomic_read(&perf_stats.pcis));
+	_OUTP_IT("Number of adapter interrupts caught             : %i\n",
+		 atomic_read(&perf_stats.thinints));
+	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %i\n",
+		 atomic_read(&perf_stats.fast_reqs));
+	_OUTP_IT("\n");
+	_OUTP_IT("Number of inbound transfers                     : %i\n",
+		 atomic_read(&perf_stats.inbound_cnt));
+	_OUTP_IT("Number of do_QDIOs outbound                     : %i\n",
+		 atomic_read(&perf_stats.outbound_cnt));
+#endif /* CONFIG_64BIT */
 	_OUTP_IT("\n");
 
         return c;
@@ -3642,8 +3670,6 @@ qdio_add_procfs_entry(void)
 static void
 qdio_remove_procfs_entry(void)
 {
-	perf_stats.tl_runs=0;
-
         if (!proc_perf_file_registration) /* means if it went ok earlier */
 		remove_proc_entry(QDIO_PERF,&proc_root);
 }
@@ -3671,13 +3697,38 @@ qdio_performance_stats_store(struct bus_
 		qdio_performance_stats = i;
 		if (i==0) {
 			/* reset perf. stat. info */
-			i_p_nc = 0;
-			i_p_c = 0;
-			ii_p_nc = 0;
-			ii_p_c = 0;
-			o_p_nc = 0;
-			o_p_c = 0;
-			memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+#ifdef CONFIG_64BIT
+			atomic64_set(&perf_stats.tl_runs, 0);
+			atomic64_set(&perf_stats.outbound_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_tl_runs_resched, 0);
+			atomic64_set(&perf_stats.inbound_thin_tl_runs, 0);
+			atomic64_set(&perf_stats.inbound_thin_tl_runs_resched,
+				     0);
+			atomic64_set(&perf_stats.siga_outs, 0);
+			atomic64_set(&perf_stats.siga_ins, 0);
+			atomic64_set(&perf_stats.siga_syncs, 0);
+			atomic64_set(&perf_stats.pcis, 0);
+			atomic64_set(&perf_stats.thinints, 0);
+			atomic64_set(&perf_stats.fast_reqs, 0);
+			atomic64_set(&perf_stats.outbound_cnt, 0);
+			atomic64_set(&perf_stats.inbound_cnt, 0);
+#else /* CONFIG_64BIT */
+			atomic_set(&perf_stats.tl_runs, 0);
+			atomic_set(&perf_stats.outbound_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_tl_runs_resched, 0);
+			atomic_set(&perf_stats.inbound_thin_tl_runs, 0);
+			atomic_set(&perf_stats.inbound_thin_tl_runs_resched, 0);
+			atomic_set(&perf_stats.siga_outs, 0);
+			atomic_set(&perf_stats.siga_ins, 0);
+			atomic_set(&perf_stats.siga_syncs, 0);
+			atomic_set(&perf_stats.pcis, 0);
+			atomic_set(&perf_stats.thinints, 0);
+			atomic_set(&perf_stats.fast_reqs, 0);
+			atomic_set(&perf_stats.outbound_cnt, 0);
+			atomic_set(&perf_stats.inbound_cnt, 0);
+#endif /* CONFIG_64BIT */
 		}
 	} else {
 		QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index ec9af72..6d7aad1 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -60,6 +60,7 @@ #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
 #define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
 #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
 #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
+#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
 
 enum qdio_irq_states {
 	QDIO_IRQ_STATE_INACTIVE,
@@ -406,21 +407,43 @@ #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THIN
 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
 
 struct qdio_perf_stats {
-	unsigned long tl_runs;
-
-	unsigned long siga_outs;
-	unsigned long siga_ins;
-	unsigned long siga_syncs;
-	unsigned long pcis;
-	unsigned long thinints;
-	unsigned long fast_reqs;
-
-	__u64 start_time_outbound;
-	unsigned long outbound_cnt;
-	unsigned long outbound_time;
-	__u64 start_time_inbound;
-	unsigned long inbound_cnt;
-	unsigned long inbound_time;
+#ifdef CONFIG_64BIT
+	atomic64_t tl_runs;
+	atomic64_t outbound_tl_runs;
+	atomic64_t outbound_tl_runs_resched;
+	atomic64_t inbound_tl_runs;
+	atomic64_t inbound_tl_runs_resched;
+	atomic64_t inbound_thin_tl_runs;
+	atomic64_t inbound_thin_tl_runs_resched;
+
+	atomic64_t siga_outs;
+	atomic64_t siga_ins;
+	atomic64_t siga_syncs;
+	atomic64_t pcis;
+	atomic64_t thinints;
+	atomic64_t fast_reqs;
+
+	atomic64_t outbound_cnt;
+	atomic64_t inbound_cnt;
+#else /* CONFIG_64BIT */
+	atomic_t tl_runs;
+	atomic_t outbound_tl_runs;
+	atomic_t outbound_tl_runs_resched;
+	atomic_t inbound_tl_runs;
+	atomic_t inbound_tl_runs_resched;
+	atomic_t inbound_thin_tl_runs;
+	atomic_t inbound_thin_tl_runs_resched;
+
+	atomic_t siga_outs;
+	atomic_t siga_ins;
+	atomic_t siga_syncs;
+	atomic_t pcis;
+	atomic_t thinints;
+	atomic_t fast_reqs;
+
+	atomic_t outbound_cnt;
+	atomic_t inbound_cnt;
+#endif /* CONFIG_64BIT */
 };
 
 /* unlikely as the later the better */
@@ -489,8 +512,8 @@ struct qdio_q {
 
 	void *irq_ptr;
 
-#ifdef QDIO_USE_TIMERS_FOR_POLLING
 	struct timer_list timer;
+#ifdef QDIO_USE_TIMERS_FOR_POLLING
 	atomic_t timer_already_set;
 	spinlock_t timer_lock;
 #else /* QDIO_USE_TIMERS_FOR_POLLING */
@@ -536,6 +559,7 @@ #endif /* QDIO_USE_TIMERS_FOR_POLLING */
 	} timing;
 	atomic_t busy_siga_counter;
         unsigned int queue_type;
+	unsigned int is_pci_out;
 
 	/* leave this member at the end. won't be cleared in qdio_fill_qs */
 	struct slib *slib; /* a page is allocated under this pointer,
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index bf37cdf..5aac0ec 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -423,27 +423,25 @@ static int ap_uevent (struct device *dev
 		       char *buffer, int buffer_size)
 {
 	struct ap_device *ap_dev = to_ap_dev(dev);
-	int length;
+	int retval = 0, length = 0, i = 0;
 
 	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;
-	buffer += length;
-	buffer_size -= length;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"DEV_TYPE=%04X", ap_dev->device_type);
+	if (retval)
+		return retval;
+
 	/* Add MODALIAS= */
-	envp[1] = buffer;
-	length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X",
-			   ap_dev->device_type);
-	if (buffer_size - length <= 0)
-		return -ENOMEM;
-	envp[2] = NULL;
-	return 0;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"MODALIAS=ap:t%02X", ap_dev->device_type);
+
+	envp[i] = NULL;
+	return retval;
 }
 
 static struct bus_type ap_bus_type = {
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 7809a79..6dd64d0 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -3525,8 +3525,8 @@ #endif
                                 memcpy(skb_put(skb,len_of_data),
 					privptr->p_mtc_envelope,
 					len_of_data);
-                                skb->mac.raw=skb->data;
                                 skb->dev=dev;
+				skb_reset_mac_header(skb);
                                 skb->protocol=htons(ETH_P_IP);
                                 skb->ip_summed=CHECKSUM_UNNECESSARY;
                                 privptr->stats.rx_packets++;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 0d6d5fc..b20fd06 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -455,7 +455,7 @@ #endif
 			return;
 		}
 		skb_put(pskb, header->length);
-		pskb->mac.raw = pskb->data;
+		skb_reset_mac_header(pskb);
 		len -= header->length;
 		skb = dev_alloc_skb(pskb->len);
 		if (!skb) {
@@ -472,8 +472,9 @@ #endif
 			privptr->stats.rx_dropped++;
 			return;
 		}
-		memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
-		skb->mac.raw = skb->data;
+		skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len),
+					  pskb->len);
+		skb_reset_mac_header(skb);
 		skb->dev = pskb->dev;
 		skb->protocol = pskb->protocol;
 		pskb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -706,7 +707,8 @@ ch_action_txdone(fsm_instance * fi, int 
 			spin_unlock(&ch->collect_lock);
 			return;
 		}
-		ch->trans_skb->tail = ch->trans_skb->data = ch->trans_skb_data;
+		ch->trans_skb->data = ch->trans_skb_data;
+		skb_reset_tail_pointer(ch->trans_skb);
 		ch->trans_skb->len = 0;
 		if (ch->prof.maxmulti < (ch->collect_len + 2))
 			ch->prof.maxmulti = ch->collect_len + 2;
@@ -715,8 +717,9 @@ ch_action_txdone(fsm_instance * fi, int 
 		*((__u16 *) skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
 		i = 0;
 		while ((skb = skb_dequeue(&ch->collect_queue))) {
-			memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
-			       skb->len);
+			skb_copy_from_linear_data(skb, skb_put(ch->trans_skb,
+							       skb->len),
+						  skb->len);
 			privptr->stats.tx_packets++;
 			privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
 			atomic_dec(&skb->users);
@@ -831,7 +834,8 @@ #endif
 		ctc_unpack_skb(ch, skb);
 	}
  again:
-	skb->data = skb->tail = ch->trans_skb_data;
+	skb->data = ch->trans_skb_data;
+	skb_reset_tail_pointer(skb);
 	skb->len = 0;
 	if (ctc_checkalloc_buffer(ch, 1))
 		return;
@@ -1638,21 +1642,19 @@ add_channel(struct ccw_device *cdev, enu
 	struct channel *ch;
 
 	DBF_TEXT(trace, 2, __FUNCTION__);
-	if ((ch =
-	     (struct channel *) kmalloc(sizeof (struct channel),
-					GFP_KERNEL)) == NULL) {
+	ch = kzalloc(sizeof(struct channel), GFP_KERNEL);
+	if (!ch) {
 		ctc_pr_warn("ctc: Out of memory in add_channel\n");
 		return -1;
 	}
-	memset(ch, 0, sizeof (struct channel));
-	if ((ch->ccw = kmalloc(8*sizeof(struct ccw1),
-					       GFP_KERNEL | GFP_DMA)) == NULL) {
+	/* assure all flags and counters are reset */
+	ch->ccw = kzalloc(8 * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+	if (!ch->ccw) {
 		kfree(ch);
 		ctc_pr_warn("ctc: Out of memory in add_channel\n");
 		return -1;
 	}
 
-	memset(ch->ccw, 0, 8*sizeof(struct ccw1));	// assure all flags and counters are reset
 
 	/**
 	 * "static" ccws are used in the following way:
@@ -1692,15 +1694,14 @@ add_channel(struct ccw_device *cdev, enu
 		return -1;
 	}
 	fsm_newstate(ch->fsm, CH_STATE_IDLE);
-	if ((ch->irb = kmalloc(sizeof (struct irb),
-					      GFP_KERNEL)) == NULL) {
+	ch->irb = kzalloc(sizeof(struct irb), GFP_KERNEL);
+	if (!ch->irb) {
 		ctc_pr_warn("ctc: Out of memory in add_channel\n");
 		kfree_fsm(ch->fsm);
 		kfree(ch->ccw);
 		kfree(ch);
 		return -1;
 	}
-	memset(ch->irb, 0, sizeof (struct irb));
 	while (*c && less_than((*c)->id, ch->id))
 		c = &(*c)->next;
 	if (*c && (!strncmp((*c)->id, ch->id, CTC_ID_SIZE))) {
@@ -2226,7 +2227,8 @@ transmit_skb(struct channel *ch, struct 
 		 * IDAL support in CTC is broken, so we have to
 		 * care about skb's above 2G ourselves.
 		 */
-		hi = ((unsigned long) skb->tail + LL_HEADER_LENGTH) >> 31;
+		hi = ((unsigned long)skb_tail_pointer(skb) +
+		      LL_HEADER_LENGTH) >> 31;
 		if (hi) {
 			nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
 			if (!nskb) {
@@ -2262,11 +2264,12 @@ transmit_skb(struct channel *ch, struct 
 				return -EBUSY;
 			}
 
-			ch->trans_skb->tail = ch->trans_skb->data;
+			skb_reset_tail_pointer(ch->trans_skb);
 			ch->trans_skb->len = 0;
 			ch->ccw[1].count = skb->len;
-			memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
-			       skb->len);
+			skb_copy_from_linear_data(skb, skb_put(ch->trans_skb,
+							       skb->len),
+						  skb->len);
 			atomic_dec(&skb->users);
 			dev_kfree_skb_irq(skb);
 			ccw_idx = 0;
@@ -2745,14 +2748,13 @@ ctc_probe_device(struct ccwgroup_device 
 	if (!get_device(&cgdev->dev))
 		return -ENODEV;
 
-	priv = kmalloc(sizeof (struct ctc_priv), GFP_KERNEL);
+	priv = kzalloc(sizeof(struct ctc_priv), GFP_KERNEL);
 	if (!priv) {
 		ctc_pr_err("%s: Out of memory\n", __func__);
 		put_device(&cgdev->dev);
 		return -ENOMEM;
 	}
 
-	memset(priv, 0, sizeof (struct ctc_priv));
 	rc = ctc_add_files(&cgdev->dev);
 	if (rc) {
 		kfree(priv);
@@ -2793,10 +2795,9 @@ ctc_init_netdevice(struct net_device * d
 	DBF_TEXT(setup, 3, __FUNCTION__);
 
 	if (alloc_device) {
-		dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
+		dev = kzalloc(sizeof(struct net_device), GFP_KERNEL);
 		if (!dev)
 			return NULL;
-		memset(dev, 0, sizeof (struct net_device));
 	}
 
 	dev->priv = privptr;
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index ecca104..08a994f 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1576,7 +1576,7 @@ __lcs_start_xmit(struct lcs_card *card, 
 	header->offset = card->tx_buffer->count;
 	header->type = card->lan_type;
 	header->slot = card->portno;
-	memcpy(header + 1, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, header + 1, skb->len);
 	spin_unlock(&card->lock);
 	card->stats.tx_bytes += skb->len;
 	card->stats.tx_packets++;
@@ -1784,7 +1784,6 @@ lcs_get_skb(struct lcs_card *card, char 
 		card->stats.rx_dropped++;
 		return;
 	}
-	skb->dev = card->dev;
 	memcpy(skb_put(skb, skb_len), skb_data, skb_len);
 	skb->protocol =	card->lan_type_trans(skb, card->dev);
 	card->stats.rx_bytes += skb_len;
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 594320c..c358764 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -635,7 +635,7 @@ static void netiucv_unpack_skb(struct iu
 			return;
 		}
 		skb_put(pskb, header->next);
-		pskb->mac.raw = pskb->data;
+		skb_reset_mac_header(pskb);
 		skb = dev_alloc_skb(pskb->len);
 		if (!skb) {
 			PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n",
@@ -645,8 +645,9 @@ static void netiucv_unpack_skb(struct iu
 			privptr->stats.rx_dropped++;
 			return;
 		}
-		memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
-		skb->mac.raw = skb->data;
+		skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len),
+					  pskb->len);
+		skb_reset_mac_header(skb);
 		skb->dev = pskb->dev;
 		skb->protocol = pskb->protocol;
 		pskb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -689,7 +690,8 @@ static void conn_action_rx(fsm_instance 
 			       msg->length, conn->max_buffsize);
 		return;
 	}
-	conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;
+	conn->rx_buff->data = conn->rx_buff->head;
+	skb_reset_tail_pointer(conn->rx_buff);
 	conn->rx_buff->len = 0;
 	rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
 				  msg->length, NULL);
@@ -735,14 +737,17 @@ static void conn_action_txdone(fsm_insta
 			}
 		}
 	}
-	conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head;
+	conn->tx_buff->data = conn->tx_buff->head;
+	skb_reset_tail_pointer(conn->tx_buff);
 	conn->tx_buff->len = 0;
 	spin_lock_irqsave(&conn->collect_lock, saveflags);
 	while ((skb = skb_dequeue(&conn->collect_queue))) {
 		header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN;
 		memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
 		       NETIUCV_HDRLEN);
-		memcpy(skb_put(conn->tx_buff, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb,
+					  skb_put(conn->tx_buff, skb->len),
+					  skb->len);
 		txbytes += skb->len;
 		txpackets++;
 		stat_maxcq++;
@@ -1164,8 +1169,8 @@ static int netiucv_transmit_skb(struct i
 		 * Copy the skb to a new allocated skb in lowmem only if the
 		 * data is located above 2G in memory or tailroom is < 2.
 		 */
-		unsigned long hi =
-			((unsigned long)(skb->tail + NETIUCV_HDRLEN)) >> 31;
+		unsigned long hi = ((unsigned long)(skb_tail_pointer(skb) +
+				    NETIUCV_HDRLEN)) >> 31;
 		int copied = 0;
 		if (hi || (skb_tailroom(skb) < 2)) {
 			nskb = alloc_skb(skb->len + NETIUCV_HDRLEN +
@@ -1857,12 +1862,14 @@ static void netiucv_remove_connection(st
 	write_lock_bh(&iucv_connection_rwlock);
 	list_del_init(&conn->list);
 	write_unlock_bh(&iucv_connection_rwlock);
+	fsm_deltimer(&conn->timer);
+	netiucv_purge_skb_queue(&conn->collect_queue);
 	if (conn->path) {
 		iucv_path_sever(conn->path, iucvMagic);
 		kfree(conn->path);
 		conn->path = NULL;
 	}
-	fsm_deltimer(&conn->timer);
+	netiucv_purge_skb_queue(&conn->commit_queue);
 	kfree_fsm(conn->fsm);
 	kfree_skb(conn->rx_buff);
 	kfree_skb(conn->tx_buff);
@@ -2110,7 +2117,6 @@ static void __exit netiucv_exit(void)
 	while (!list_empty(&iucv_connection_list)) {
 		cp = list_entry(iucv_connection_list.next,
 				struct iucv_connection, list);
-		list_del(&cp->list);
 		ndev = cp->netdev;
 		priv = netdev_priv(ndev);
 		dev = priv->dev;
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 84b108d..b34eb82 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -288,6 +288,7 @@ #define QETH_BUFSIZE	 	4096
  */
 #define IF_NAME_LEN	 	16
 #define QETH_TX_TIMEOUT		100 * HZ
+#define QETH_RCD_TIMEOUT	60 * HZ
 #define QETH_HEADER_SIZE	32
 #define MAX_PORTNO 		15
 #define QETH_FAKE_LL_LEN_ETH	ETH_HLEN
@@ -582,6 +583,8 @@ enum qeth_channel_states {
 	CH_STATE_ACTIVATING,
 	CH_STATE_HALTED,
 	CH_STATE_STOPPED,
+	CH_STATE_RCD,
+	CH_STATE_RCD_DONE,
 };
 /**
  * card state machine
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 7c735e1..4640f32 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -267,7 +267,8 @@ qeth_eddp_copy_data_tcp(char *dst, struc
 
 	QETH_DBF_TEXT(trace, 5, "eddpcdtc");
 	if (skb_shinfo(eddp->skb)->nr_frags == 0) {
-		memcpy(dst, eddp->skb->data + eddp->skb_offset, len);
+		skb_copy_from_linear_data_offset(eddp->skb, eddp->skb_offset,
+						 dst, len);
 		*hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len,
 				      *hcsum);
 		eddp->skb_offset += len;
@@ -416,7 +417,7 @@ #ifdef CONFIG_QETH_VLAN
                        eddp->skb_offset += VLAN_HLEN;
 #endif /* CONFIG_QETH_VLAN */
        }
-	tcph = eddp->skb->h.th;
+	tcph = tcp_hdr(eddp->skb);
 	while (eddp->skb_offset < eddp->skb->len) {
 		data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
 			       (int)(eddp->skb->len - eddp->skb_offset));
@@ -473,20 +474,24 @@ qeth_eddp_fill_context_tcp(struct qeth_e
 	QETH_DBF_TEXT(trace, 5, "eddpficx");
 	/* create our segmentation headers and copy original headers */
 	if (skb->protocol == htons(ETH_P_IP))
-		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph,
-				skb->nh.iph->ihl*4,
-				(u8 *)skb->h.th, skb->h.th->doff*4);
+		eddp = qeth_eddp_create_eddp_data(qhdr,
+						  skb_network_header(skb),
+						  ip_hdrlen(skb),
+						  skb_transport_header(skb),
+						  tcp_hdrlen(skb));
 	else
-		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h,
-				sizeof(struct ipv6hdr),
-				(u8 *)skb->h.th, skb->h.th->doff*4);
+		eddp = qeth_eddp_create_eddp_data(qhdr,
+						  skb_network_header(skb),
+						  sizeof(struct ipv6hdr),
+						  skb_transport_header(skb),
+						  tcp_hdrlen(skb));
 
 	if (eddp == NULL) {
 		QETH_DBF_TEXT(trace, 2, "eddpfcnm");
 		return -ENOMEM;
 	}
 	if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {
-		skb->mac.raw = (skb->data) + sizeof(struct qeth_hdr);
+		skb_set_mac_header(skb, sizeof(struct qeth_hdr));
 		memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);
 #ifdef CONFIG_QETH_VLAN
 		if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {
@@ -590,12 +595,13 @@ qeth_eddp_create_context_tcp(struct qeth
 	QETH_DBF_TEXT(trace, 5, "creddpct");
 	if (skb->protocol == htons(ETH_P_IP))
 		ctx = qeth_eddp_create_context_generic(card, skb,
-			sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 +
-			skb->h.th->doff*4);
+						       (sizeof(struct qeth_hdr) +
+						        ip_hdrlen(skb) +
+							tcp_hdrlen(skb)));
 	else if (skb->protocol == htons(ETH_P_IPV6))
 		ctx = qeth_eddp_create_context_generic(card, skb,
 			sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) +
-			skb->h.th->doff*4);
+			tcp_hdrlen(skb));
 	else
 		QETH_DBF_TEXT(trace, 2, "cetcpinv");
 
@@ -614,10 +620,10 @@ qeth_eddp_create_context_tcp(struct qeth
 
 struct qeth_eddp_context *
 qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
-			 struct qeth_hdr *qhdr)
+			 struct qeth_hdr *qhdr, unsigned char sk_protocol)
 {
 	QETH_DBF_TEXT(trace, 5, "creddpc");
-	switch (skb->sk->sk_protocol){
+	switch (sk_protocol) {
 	case IPPROTO_TCP:
 		return qeth_eddp_create_context_tcp(card, skb, qhdr);
 	default:
diff --git a/drivers/s390/net/qeth_eddp.h b/drivers/s390/net/qeth_eddp.h
index 103768d..52910c9 100644
--- a/drivers/s390/net/qeth_eddp.h
+++ b/drivers/s390/net/qeth_eddp.h
@@ -34,7 +34,8 @@ struct qeth_eddp_context_reference {
 };
 
 extern struct qeth_eddp_context *
-qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *);
+qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,
+			 struct qeth_hdr *, unsigned char);
 
 extern void
 qeth_eddp_put_context(struct qeth_eddp_context *);
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index d8a86f5..29d1760 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -315,7 +315,8 @@ qeth_alloc_card(void)
 }
 
 static long
-__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
+__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm,
+		       struct irb *irb)
 {
 	if (!IS_ERR(irb))
 		return 0;
@@ -330,6 +331,14 @@ __qeth_check_irb_error(struct ccw_device
 		PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
 		QETH_DBF_TEXT(trace, 2, "ckirberr");
 		QETH_DBF_TEXT_(trace, 2, "  rc%d", -ETIMEDOUT);
+		if (intparm == QETH_RCD_PARM) {
+			struct qeth_card *card = CARD_FROM_CDEV(cdev);
+
+			if (card && (card->data.ccwdev == cdev)) {
+				card->data.state = CH_STATE_DOWN;
+				wake_up(&card->wait_q);
+			}
+		}
 		break;
 	default:
 		PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
@@ -401,7 +410,7 @@ qeth_irq(struct ccw_device *cdev, unsign
 
 	QETH_DBF_TEXT(trace,5,"irq");
 
-	if (__qeth_check_irb_error(cdev, irb))
+	if (__qeth_check_irb_error(cdev, intparm, irb))
 		return;
 	cstat = irb->scsw.cstat;
 	dstat = irb->scsw.dstat;
@@ -429,7 +438,8 @@ qeth_irq(struct ccw_device *cdev, unsign
 		channel->state = CH_STATE_HALTED;
 
 	/*let's wake up immediately on data channel*/
-	if ((channel == &card->data) && (intparm != 0))
+	if ((channel == &card->data) && (intparm != 0) &&
+	    (intparm != QETH_RCD_PARM))
 		goto out;
 
 	if (intparm == QETH_CLEAR_CHANNEL_PARM) {
@@ -453,6 +463,10 @@ qeth_irq(struct ccw_device *cdev, unsign
 			HEXDUMP16(WARN,"irb: ",irb);
 			HEXDUMP16(WARN,"sense data: ",irb->ecw);
 		}
+		if (intparm == QETH_RCD_PARM) {
+			channel->state = CH_STATE_DOWN;
+			goto out;
+		}
 		rc = qeth_get_problem(cdev,irb);
 		if (rc) {
 			qeth_schedule_recovery(card);
@@ -460,6 +474,10 @@ qeth_irq(struct ccw_device *cdev, unsign
 		}
 	}
 
+	if (intparm == QETH_RCD_PARM) {
+		channel->state = CH_STATE_RCD_DONE;
+		goto out;
+	}
 	if (intparm) {
 		buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
 		buffer->state = BUF_STATE_PROCESSED;
@@ -1204,6 +1222,54 @@ qeth_probe_device(struct ccwgroup_device
 }
 
 
+static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
+			       int *length)
+{
+	struct ciw *ciw;
+	char *rcd_buf;
+	int ret;
+	struct qeth_channel *channel = &card->data;
+	unsigned long flags;
+
+	/*
+	 * scan for RCD command in extended SenseID data
+	 */
+	ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
+	if (!ciw || ciw->cmd == 0)
+		return -EOPNOTSUPP;
+	rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+	if (!rcd_buf)
+		return -ENOMEM;
+
+	channel->ccw.cmd_code = ciw->cmd;
+	channel->ccw.cda = (__u32) __pa (rcd_buf);
+	channel->ccw.count = ciw->count;
+	channel->ccw.flags = CCW_FLAG_SLI;
+	channel->state = CH_STATE_RCD;
+	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+	ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+				       QETH_RCD_PARM, LPM_ANYPATH, 0,
+				       QETH_RCD_TIMEOUT);
+	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+	if (!ret)
+		wait_event(card->wait_q,
+			   (channel->state == CH_STATE_RCD_DONE ||
+			    channel->state == CH_STATE_DOWN));
+	if (channel->state == CH_STATE_DOWN)
+		ret = -EIO;
+	else
+		channel->state = CH_STATE_DOWN;
+	if (ret) {
+		kfree(rcd_buf);
+		*buffer = NULL;
+		*length = 0;
+	} else {
+		*length = ciw->count;
+		*buffer = rcd_buf;
+	}
+	return ret;
+}
+
 static int
 qeth_get_unitaddr(struct qeth_card *card)
 {
@@ -1212,9 +1278,9 @@ qeth_get_unitaddr(struct qeth_card *card
 	int rc;
 
 	QETH_DBF_TEXT(setup, 2, "getunit");
-	rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length);
+	rc = qeth_read_conf_data(card, (void **) &prcd, &length);
 	if (rc) {
-		PRINT_ERR("read_conf_data for device %s returned %i\n",
+		PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",
 			  CARD_DDEV_ID(card), rc);
 		return rc;
 	}
@@ -1223,6 +1289,7 @@ qeth_get_unitaddr(struct qeth_card *card
 	card->info.cula = prcd[63];
 	card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
 			       (prcd[0x11] == _ascebc['M']));
+	kfree(prcd);
 	return 0;
 }
 
@@ -1615,6 +1682,21 @@ qeth_put_reply(struct qeth_reply *reply)
 		kfree(reply);
 }
 
+static void
+qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card)
+{
+	int rc;
+	int com;
+	char * ipa_name;
+
+	com = cmd->hdr.command;
+	rc  = cmd->hdr.return_code;
+	ipa_name = qeth_get_ipa_cmd_name(com);
+
+	PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com,
+		   QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc));
+}
+
 static struct qeth_ipa_cmd *
 qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
 {
@@ -1623,8 +1705,11 @@ qeth_check_ipa_data(struct qeth_card *ca
 	QETH_DBF_TEXT(trace,5,"chkipad");
 	if (IS_IPA(iob->data)){
 		cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
-		if (IS_IPA_REPLY(cmd))
+		if (IS_IPA_REPLY(cmd)) {
+			if (cmd->hdr.return_code)
+				qeth_issue_ipa_msg(cmd, card);
 			return cmd;
+		}
 		else {
 			switch (cmd->hdr.command) {
 			case IPA_CMD_STOPLAN:
@@ -2278,7 +2363,7 @@ #ifdef CONFIG_TR
 	    (card->info.link_type == QETH_LINK_TYPE_LANE_TR))
 	 	return tr_type_trans(skb,dev);
 #endif /* CONFIG_TR */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN );
 	eth = eth_hdr(skb);
 
@@ -2306,9 +2391,9 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_
 	struct iphdr *ip_hdr;
 
 	QETH_DBF_TEXT(trace,5,"skbfktr");
-	skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
+	skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR);
 	/* this is a fake ethernet header */
-	fake_hdr = (struct trh_hdr *) skb->mac.raw;
+	fake_hdr = tr_hdr(skb);
 
 	/* the destination MAC address */
 	switch (skb->pkt_type){
@@ -2359,9 +2444,9 @@ qeth_rebuild_skb_fake_ll_eth(struct qeth
 	struct iphdr *ip_hdr;
 
 	QETH_DBF_TEXT(trace,5,"skbfketh");
-	skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
+	skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_ETH);
 	/* this is a fake ethernet header */
-	fake_hdr = (struct ethhdr *) skb->mac.raw;
+	fake_hdr = eth_hdr(skb);
 
 	/* the destination MAC address */
 	switch (skb->pkt_type){
@@ -2461,7 +2546,7 @@ #endif /* CONFIG_QETH_IPV6 */
 	if (card->options.fake_ll)
 		qeth_rebuild_skb_fake_ll(card, skb, hdr);
 	else
-		skb->mac.raw = skb->data;
+		skb_reset_mac_header(skb);
 	skb->ip_summed = card->options.checksum_type;
 	if (card->options.checksum_type == HW_CHECKSUMMING){
 		if ( (hdr->hdr.l3.ext_flags &
@@ -2501,7 +2586,8 @@ qeth_process_inbound_buffer(struct qeth_
 			vlan_tag = qeth_rebuild_skb(card, skb, hdr);
 		else { /*in case of OSN*/
 			skb_push(skb, sizeof(struct qeth_hdr));
-			memcpy(skb->data, hdr, sizeof(struct qeth_hdr));
+			skb_copy_to_linear_data(skb, hdr,
+						sizeof(struct qeth_hdr));
 		}
 		/* is device UP ? */
 		if (!(card->dev->flags & IFF_UP)){
@@ -2748,6 +2834,7 @@ qeth_flush_buffers(struct qeth_qdio_out_
 	struct qeth_qdio_out_buffer *buf;
 	int rc;
 	int i;
+	unsigned int qdio_flags;
 
 	QETH_DBF_TEXT(trace, 6, "flushbuf");
 
@@ -2791,13 +2878,13 @@ qeth_flush_buffers(struct qeth_qdio_out_
 		queue->card->perf_stats.outbound_do_qdio_start_time =
 			qeth_get_micros();
 	}
+	qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
 	if (under_int)
-		rc = do_QDIO(CARD_DDEV(queue->card),
-			     QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
-			     queue->queue_no, index, count, NULL);
-	else
-		rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
-			     queue->queue_no, index, count, NULL);
+		qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT;
+	if (atomic_read(&queue->set_pci_flags_count))
+		qdio_flags |= QDIO_FLAG_PCI_OUT;
+	rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
+		     queue->queue_no, index, count, NULL);
 	if (queue->card->options.performance_stats)
 		queue->card->perf_stats.outbound_do_qdio_time +=
 			qeth_get_micros() -
@@ -3778,9 +3865,11 @@ qeth_get_cast_type(struct qeth_card *car
 	}
 	/* try something else */
 	if (skb->protocol == ETH_P_IPV6)
-		return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
+		return (skb_network_header(skb)[24] == 0xff) ?
+				RTN_MULTICAST : 0;
 	else if (skb->protocol == ETH_P_IP)
-		return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
+		return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ?
+				RTN_MULTICAST : 0;
 	/* ... */
 	if (!memcmp(skb->data, skb->dev->broadcast, 6))
 		return RTN_BROADCAST;
@@ -3818,18 +3907,20 @@ qeth_get_priority_queue(struct qeth_card
 			return card->info.is_multicast_different &
 				(card->qdio.no_out_queues - 1);
 		if (card->qdio.do_prio_queueing && (ipv == 4)) {
+			const u8 tos = ip_hdr(skb)->tos;
+
 			if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_TOS){
-				if (skb->nh.iph->tos & IP_TOS_NOTIMPORTANT)
+				if (tos & IP_TOS_NOTIMPORTANT)
 					return 3;
-				if (skb->nh.iph->tos & IP_TOS_HIGHRELIABILITY)
+				if (tos & IP_TOS_HIGHRELIABILITY)
 					return 2;
-				if (skb->nh.iph->tos & IP_TOS_HIGHTHROUGHPUT)
+				if (tos & IP_TOS_HIGHTHROUGHPUT)
 					return 1;
-				if (skb->nh.iph->tos & IP_TOS_LOWDELAY)
+				if (tos & IP_TOS_LOWDELAY)
 					return 0;
 			}
 			if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_PREC)
-				return 3 - (skb->nh.iph->tos >> 6);
+				return 3 - (tos >> 6);
 		} else if (card->qdio.do_prio_queueing && (ipv == 6)) {
 			/* TODO: IPv6!!! */
 		}
@@ -3866,9 +3957,9 @@ #ifdef CONFIG_QETH_VLAN
 		 * memcpys instead of one memmove to save cycles.
 		 */
 		skb_push(skb, VLAN_HLEN);
-		memcpy(skb->data, skb->data + 4, 4);
-		memcpy(skb->data + 4, skb->data + 8, 4);
-		memcpy(skb->data + 8, skb->data + 12, 4);
+		skb_copy_to_linear_data(skb, skb->data + 4, 4);
+		skb_copy_to_linear_data_offset(skb, 4, skb->data + 8, 4);
+		skb_copy_to_linear_data_offset(skb, 8, skb->data + 12, 4);
 		tag = (u16 *)(skb->data + 12);
 		/*
 		 * first two bytes  = ETH_P_8021Q (0x8100)
@@ -4039,7 +4130,8 @@ #endif /* CONFIG_QETH_VLAN */
 			    *((u32 *) skb->dst->neighbour->primary_key);
 		} else {
 			/* fill in destination address used in ip header */
-			*((u32 *) (&hdr->hdr.l3.dest_addr[12])) = skb->nh.iph->daddr;
+			*((u32 *)(&hdr->hdr.l3.dest_addr[12])) =
+							   ip_hdr(skb)->daddr;
 		}
 	} else if (ipv == 6) { /* IPv6 or passthru */
 		hdr->hdr.l3.flags = qeth_get_qeth_hdr_flags6(cast_type);
@@ -4048,7 +4140,8 @@ #endif /* CONFIG_QETH_VLAN */
 			       skb->dst->neighbour->primary_key, 16);
 		} else {
 			/* fill in destination address used in ip header */
-			memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
+			memcpy(hdr->hdr.l3.dest_addr,
+			       &ipv6_hdr(skb)->daddr, 16);
 		}
 	} else { /* passthrough */
                 if((skb->dev->type == ARPHRD_IEEE802_TR) &&
@@ -4416,7 +4509,8 @@ qeth_send_packet(struct qeth_card *card,
 		qeth_fill_header(card, hdr, new_skb, ipv, cast_type);
 	}
 	if (large_send == QETH_LARGE_SEND_EDDP) {
-		ctx = qeth_eddp_create_context(card, new_skb, hdr);
+		ctx = qeth_eddp_create_context(card, new_skb, hdr,
+					       skb->sk->sk_protocol);
 		if (ctx == NULL) {
 			__qeth_free_new_skb(skb, new_skb);
 			PRINT_WARN("could not create eddp context\n");
@@ -5874,9 +5968,6 @@ qeth_layer2_send_setmac_cb(struct qeth_c
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
 		QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code);
-		PRINT_WARN("Error in registering MAC address on " \
-			   "device %s: x%x\n", CARD_BUS_ID(card),
-			   cmd->hdr.return_code);
 		card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
 		cmd->hdr.return_code = -EIO;
 	} else {
@@ -5911,9 +6002,6 @@ qeth_layer2_send_delmac_cb(struct qeth_c
 	QETH_DBF_TEXT(trace, 2, "L2Dmaccb");
 	cmd = (struct qeth_ipa_cmd *) data;
 	if (cmd->hdr.return_code) {
-		PRINT_WARN("Error in deregistering MAC address on " \
-			   "device %s: x%x\n", CARD_BUS_ID(card),
-			   cmd->hdr.return_code);
 		QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);
 		cmd->hdr.return_code = -EIO;
 		return 0;
@@ -6577,7 +6665,7 @@ qeth_setadpparms_change_macaddr_cb(struc
 	QETH_DBF_TEXT(trace,4,"chgmaccb");
 
 	cmd = (struct qeth_ipa_cmd *) data;
-	if (!card->options.layer2 || card->info.guestlan ||
+	if (!card->options.layer2 ||
 	    !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
 		memcpy(card->dev->dev_addr,
 		       &cmd->data.setadapterparms.data.change_addr.addr,
@@ -8423,6 +8511,7 @@ __qeth_reboot_event_card(struct device *
 	card = (struct qeth_card *) dev->driver_data;
 	qeth_clear_ip_list(card, 0, 0);
 	qeth_qdio_clear_card(card, 0);
+	qeth_clear_qdio_buffers(card);
 	return 0;
 }
 
diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c
index 77c8320..f54fdfd 100644
--- a/drivers/s390/net/qeth_mpc.c
+++ b/drivers/s390/net/qeth_mpc.c
@@ -157,12 +157,113 @@ unsigned char READ_CCW[]={
 };
 
 
+struct ipa_rc_msg {
+	enum qeth_ipa_return_codes rc;
+	char *msg;
+};
 
+struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+	{IPA_RC_SUCCESS,		"success"},
+	{IPA_RC_NOTSUPP,		"Command not supported"},
+	{IPA_RC_IP_TABLE_FULL,		"Add Addr IP Table Full - ipv6"},
+	{IPA_RC_UNKNOWN_ERROR,		"IPA command failed - reason unknown"},
+	{IPA_RC_UNSUPPORTED_COMMAND,	"Command not supported"},
+	{IPA_RC_DUP_IPV6_REMOTE,"ipv6 address already registered remote"},
+	{IPA_RC_DUP_IPV6_HOME,		"ipv6 address already registered"},
+	{IPA_RC_UNREGISTERED_ADDR,	"Address not registered"},
+	{IPA_RC_NO_ID_AVAILABLE,	"No identifiers available"},
+	{IPA_RC_ID_NOT_FOUND,		"Identifier not found"},
+	{IPA_RC_INVALID_IP_VERSION,	"IP version incorrect"},
+	{IPA_RC_LAN_FRAME_MISMATCH,	"LAN and frame mismatch"},
+	{IPA_RC_L2_UNSUPPORTED_CMD,	"Unsupported layer 2 command"},
+	{IPA_RC_L2_DUP_MAC,		"Duplicate MAC address"},
+	{IPA_RC_L2_ADDR_TABLE_FULL,	"Layer2 address table full"},
+	{IPA_RC_L2_DUP_LAYER3_MAC,	"Duplicate with layer 3 MAC"},
+	{IPA_RC_L2_GMAC_NOT_FOUND,	"GMAC not found"},
+	{IPA_RC_L2_MAC_NOT_FOUND,	"L2 mac address not found"},
+	{IPA_RC_L2_INVALID_VLAN_ID,	"L2 invalid vlan id"},
+	{IPA_RC_L2_DUP_VLAN_ID,		"L2 duplicate vlan id"},
+	{IPA_RC_L2_VLAN_ID_NOT_FOUND,	"L2 vlan id not found"},
+	{IPA_RC_DATA_MISMATCH,		"Data field mismatch (v4/v6 mixed)"},
+	{IPA_RC_INVALID_MTU_SIZE,	"Invalid MTU size"},
+	{IPA_RC_INVALID_LANTYPE,	"Invalid LAN type"},
+	{IPA_RC_INVALID_LANNUM,		"Invalid LAN num"},
+	{IPA_RC_DUPLICATE_IP_ADDRESS,	"Address already registered"},
+	{IPA_RC_IP_ADDR_TABLE_FULL,	"IP address table full"},
+	{IPA_RC_LAN_PORT_STATE_ERROR,	"LAN port state error"},
+	{IPA_RC_SETIP_NO_STARTLAN,	"Setip no startlan received"},
+	{IPA_RC_SETIP_ALREADY_RECEIVED,	"Setip already received"},
+	{IPA_RC_IP_ADDR_ALREADY_USED,	"IP address already in use on LAN"},
+	{IPA_RC_MULTICAST_FULL,		"No task available, multicast full"},
+	{IPA_RC_SETIP_INVALID_VERSION,	"SETIP invalid IP version"},
+	{IPA_RC_UNSUPPORTED_SUBCMD,	"Unsupported assist subcommand"},
+	{IPA_RC_ARP_ASSIST_NO_ENABLE,	"Only partial success, no enable"},
+	{IPA_RC_PRIMARY_ALREADY_DEFINED,"Primary already defined"},
+	{IPA_RC_SECOND_ALREADY_DEFINED,	"Secondary already defined"},
+	{IPA_RC_INVALID_SETRTG_INDICATOR,"Invalid SETRTG indicator"},
+	{IPA_RC_MC_ADDR_ALREADY_DEFINED,"Multicast address already defined"},
+	{IPA_RC_LAN_OFFLINE,		"STRTLAN_LAN_DISABLED - LAN offline"},
+	{IPA_RC_INVALID_IP_VERSION2,	"Invalid IP version"},
+	{IPA_RC_FFFF,			"Unknown Error"}
+};
 
 
 
+char *
+qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
+{
+	int x = 0;
+	qeth_ipa_rc_msg[sizeof(qeth_ipa_rc_msg) /
+			sizeof(struct ipa_rc_msg) - 1].rc = rc;
+	while(qeth_ipa_rc_msg[x].rc != rc)
+		x++;
+	return qeth_ipa_rc_msg[x].msg;
+}
 
 
+struct ipa_cmd_names {
+	enum qeth_ipa_cmds cmd;
+	char *name;
+};
+
+struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+	{IPA_CMD_STARTLAN,	"startlan"},
+	{IPA_CMD_STOPLAN,	"stoplan"},
+	{IPA_CMD_SETVMAC,	"setvmac"},
+	{IPA_CMD_DELVMAC,	"delvmca"},
+	{IPA_CMD_SETGMAC,	"setgmac"},
+	{IPA_CMD_DELGMAC,	"delgmac"},
+	{IPA_CMD_SETVLAN,	"setvlan"},
+	{IPA_CMD_DELVLAN,	"delvlan"},
+	{IPA_CMD_SETCCID,	"setccid"},
+	{IPA_CMD_DELCCID,	"delccid"},
+	{IPA_CMD_MODCCID,	"setip"},
+	{IPA_CMD_SETIP,		"setip"},
+	{IPA_CMD_QIPASSIST,	"qipassist"},
+	{IPA_CMD_SETASSPARMS,	"setassparms"},
+	{IPA_CMD_SETIPM,	"setipm"},
+	{IPA_CMD_DELIPM,	"delipm"},
+	{IPA_CMD_SETRTG,	"setrtg"},
+	{IPA_CMD_DELIP,		"delip"},
+	{IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
+	{IPA_CMD_SET_DIAG_ASS,	"set_diag_ass"},
+	{IPA_CMD_CREATE_ADDR,	"create_addr"},
+	{IPA_CMD_DESTROY_ADDR,	"destroy_addr"},
+	{IPA_CMD_REGISTER_LOCAL_ADDR,	"register_local_addr"},
+	{IPA_CMD_UNREGISTER_LOCAL_ADDR,	"unregister_local_addr"},
+	{IPA_CMD_UNKNOWN,	"unknown"},
+};
 
+char *
+qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
+{
+	int x = 0;
+	qeth_ipa_cmd_names[
+		sizeof(qeth_ipa_cmd_names)/
+			sizeof(struct ipa_cmd_names)-1].cmd = cmd;
+	while(qeth_ipa_cmd_names[x].cmd != cmd)
+		x++;
+	return qeth_ipa_cmd_names[x].name;
+}
 
 
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 0477c47..1d8083c 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -25,18 +25,19 @@ #define QETH_IPA_CMD_DEST_ADDR(buffer) (
 
 #define IPA_CMD_LENGTH	(IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
 
-#define QETH_SEQ_NO_LENGTH 	4
-#define QETH_MPC_TOKEN_LENGTH 	4
+#define QETH_SEQ_NO_LENGTH	4
+#define QETH_MPC_TOKEN_LENGTH	4
 #define QETH_MCL_LENGTH		4
 #define OSA_ADDR_LEN		6
 
-#define QETH_TIMEOUT 		(10 * HZ)
-#define QETH_IPA_TIMEOUT 	(45 * HZ)
-#define QETH_IDX_COMMAND_SEQNO 	0xffff0000
+#define QETH_TIMEOUT		(10 * HZ)
+#define QETH_IPA_TIMEOUT	(45 * HZ)
+#define QETH_IDX_COMMAND_SEQNO	0xffff0000
 #define SR_INFO_LEN		16
 
 #define QETH_CLEAR_CHANNEL_PARM	-10
 #define QETH_HALT_CHANNEL_PARM	-11
+#define QETH_RCD_PARM -12
 
 /*****************************************************************************/
 /* IP Assist related definitions                                             */
@@ -92,79 +93,107 @@ #define QETH_CHECKSUM_DEFAULT SW_CHECKSU
  */
 #define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */
 enum qeth_routing_types {
-	NO_ROUTER           = 0, /* TODO: set to bit flag used in IPA Command */
-	PRIMARY_ROUTER      = 1,
-	SECONDARY_ROUTER    = 2,
-	MULTICAST_ROUTER    = 3,
-	PRIMARY_CONNECTOR   = 4,
-	SECONDARY_CONNECTOR = 5,
+	NO_ROUTER		= 0, /* TODO: set to bit flag used in IPA Command */
+	PRIMARY_ROUTER		= 1,
+	SECONDARY_ROUTER	= 2,
+	MULTICAST_ROUTER	= 3,
+	PRIMARY_CONNECTOR	= 4,
+	SECONDARY_CONNECTOR	= 5,
 };
 
-
 /* IPA Commands */
 enum qeth_ipa_cmds {
-	IPA_CMD_STARTLAN              = 0x01,
-	IPA_CMD_STOPLAN               = 0x02,
-	IPA_CMD_SETVMAC 	      = 0x21,
-	IPA_CMD_DELVMAC 	      =	0x22,
-	IPA_CMD_SETGMAC  	      = 0x23,
-	IPA_CMD_DELGMAC 	      = 0x24,
-	IPA_CMD_SETVLAN 	      = 0x25,
-	IPA_CMD_DELVLAN 	      = 0x26,
-	IPA_CMD_SETCCID               = 0x41,
-	IPA_CMD_DELCCID               = 0x42,
-	IPA_CMD_MODCCID               = 0x43,
-	IPA_CMD_SETIP                 = 0xb1,
-	IPA_CMD_DELIP                 = 0xb7,
-	IPA_CMD_QIPASSIST             = 0xb2,
-	IPA_CMD_SETASSPARMS           = 0xb3,
-	IPA_CMD_SETIPM                = 0xb4,
-	IPA_CMD_DELIPM                = 0xb5,
-	IPA_CMD_SETRTG                = 0xb6,
-	IPA_CMD_SETADAPTERPARMS       = 0xb8,
-	IPA_CMD_IPFRAME               = 0xb9,
-	IPA_CMD_ADD_ADDR_ENTRY        = 0xc1,
-	IPA_CMD_DELETE_ADDR_ENTRY     = 0xc2,
-	IPA_CMD_CREATE_ADDR           = 0xc3,
-	IPA_CMD_DESTROY_ADDR          = 0xc4,
-	IPA_CMD_REGISTER_LOCAL_ADDR   = 0xd1,
-	IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
+	IPA_CMD_STARTLAN		= 0x01,
+	IPA_CMD_STOPLAN			= 0x02,
+	IPA_CMD_SETVMAC			= 0x21,
+	IPA_CMD_DELVMAC			= 0x22,
+	IPA_CMD_SETGMAC			= 0x23,
+	IPA_CMD_DELGMAC			= 0x24,
+	IPA_CMD_SETVLAN			= 0x25,
+	IPA_CMD_DELVLAN			= 0x26,
+	IPA_CMD_SETCCID			= 0x41,
+	IPA_CMD_DELCCID			= 0x42,
+	IPA_CMD_MODCCID			= 0x43,
+	IPA_CMD_SETIP			= 0xb1,
+	IPA_CMD_QIPASSIST		= 0xb2,
+	IPA_CMD_SETASSPARMS		= 0xb3,
+	IPA_CMD_SETIPM			= 0xb4,
+	IPA_CMD_DELIPM			= 0xb5,
+	IPA_CMD_SETRTG			= 0xb6,
+	IPA_CMD_DELIP			= 0xb7,
+	IPA_CMD_SETADAPTERPARMS		= 0xb8,
+	IPA_CMD_SET_DIAG_ASS		= 0xb9,
+	IPA_CMD_CREATE_ADDR		= 0xc3,
+	IPA_CMD_DESTROY_ADDR		= 0xc4,
+	IPA_CMD_REGISTER_LOCAL_ADDR	= 0xd1,
+	IPA_CMD_UNREGISTER_LOCAL_ADDR	= 0xd2,
+	IPA_CMD_UNKNOWN			= 0x00
 };
 
 enum qeth_ip_ass_cmds {
 	IPA_CMD_ASS_START	= 0x0001,
 	IPA_CMD_ASS_STOP	= 0x0002,
-	IPA_CMD_ASS_CONFIGURE 	= 0x0003,
-	IPA_CMD_ASS_ENABLE 	= 0x0004,
+	IPA_CMD_ASS_CONFIGURE	= 0x0003,
+	IPA_CMD_ASS_ENABLE	= 0x0004,
 };
 
 enum qeth_arp_process_subcmds {
-	IPA_CMD_ASS_ARP_SET_NO_ENTRIES 	= 0x0003,
-	IPA_CMD_ASS_ARP_QUERY_CACHE 	= 0x0004,
-	IPA_CMD_ASS_ARP_ADD_ENTRY 	= 0x0005,
-	IPA_CMD_ASS_ARP_REMOVE_ENTRY 	= 0x0006,
-	IPA_CMD_ASS_ARP_FLUSH_CACHE 	= 0x0007,
-	IPA_CMD_ASS_ARP_QUERY_INFO 	= 0x0104,
-	IPA_CMD_ASS_ARP_QUERY_STATS 	= 0x0204,
+	IPA_CMD_ASS_ARP_SET_NO_ENTRIES	= 0x0003,
+	IPA_CMD_ASS_ARP_QUERY_CACHE	= 0x0004,
+	IPA_CMD_ASS_ARP_ADD_ENTRY	= 0x0005,
+	IPA_CMD_ASS_ARP_REMOVE_ENTRY	= 0x0006,
+	IPA_CMD_ASS_ARP_FLUSH_CACHE	= 0x0007,
+	IPA_CMD_ASS_ARP_QUERY_INFO	= 0x0104,
+	IPA_CMD_ASS_ARP_QUERY_STATS	= 0x0204,
 };
 
-/* Return Codes for IPA Commands */
+
+/* Return Codes for IPA Commands
+ * according to OSA card Specs */
+
 enum qeth_ipa_return_codes {
-	IPA_RC_SUCCESS             = 0x0000,
-	IPA_RC_NOTSUPP             = 0x0001,
-	IPA_RC_NO_ACCESS           = 0x0002,
-	IPA_RC_FAILED              = 0x0003,
-	IPA_RC_DATA_MISMATCH       = 0xe001,
-	IPA_RC_INVALID_LAN_TYPE    = 0xe003,
-	IPA_RC_INVALID_LAN_NO      = 0xe004,
-	IPA_RC_IPADDR_ALREADY_REG  = 0xe005,
-	IPA_RC_IPADDR_TABLE_FULL   = 0xe006,
-	IPA_RC_IPADDR_ALREADY_USED = 0xe00a,
-	IPA_RC_ASSNO_NOT_SUPP      = 0xe00d,
-	IPA_RC_ASSCMD_START_FAILED = 0xe00e,
-	IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f,
-	IPA_RC_IPADDR_NOT_DEFINED  = 0xe010,
-	IPA_RC_LAN_OFFLINE         = 0xe080,
+	IPA_RC_SUCCESS			= 0x0000,
+	IPA_RC_NOTSUPP			= 0x0001,
+	IPA_RC_IP_TABLE_FULL		= 0x0002,
+	IPA_RC_UNKNOWN_ERROR		= 0x0003,
+	IPA_RC_UNSUPPORTED_COMMAND	= 0x0004,
+	IPA_RC_DUP_IPV6_REMOTE		= 0x0008,
+	IPA_RC_DUP_IPV6_HOME		= 0x0010,
+	IPA_RC_UNREGISTERED_ADDR	= 0x0011,
+	IPA_RC_NO_ID_AVAILABLE		= 0x0012,
+	IPA_RC_ID_NOT_FOUND		= 0x0013,
+	IPA_RC_INVALID_IP_VERSION	= 0x0020,
+	IPA_RC_LAN_FRAME_MISMATCH	= 0x0040,
+	IPA_RC_L2_UNSUPPORTED_CMD	= 0x2003,
+	IPA_RC_L2_DUP_MAC		= 0x2005,
+	IPA_RC_L2_ADDR_TABLE_FULL	= 0x2006,
+	IPA_RC_L2_DUP_LAYER3_MAC	= 0x200a,
+	IPA_RC_L2_GMAC_NOT_FOUND	= 0x200b,
+	IPA_RC_L2_MAC_NOT_FOUND		= 0x2010,
+	IPA_RC_L2_INVALID_VLAN_ID	= 0x2015,
+	IPA_RC_L2_DUP_VLAN_ID		= 0x2016,
+	IPA_RC_L2_VLAN_ID_NOT_FOUND	= 0x2017,
+	IPA_RC_DATA_MISMATCH		= 0xe001,
+	IPA_RC_INVALID_MTU_SIZE		= 0xe002,
+	IPA_RC_INVALID_LANTYPE		= 0xe003,
+	IPA_RC_INVALID_LANNUM		= 0xe004,
+	IPA_RC_DUPLICATE_IP_ADDRESS	= 0xe005,
+	IPA_RC_IP_ADDR_TABLE_FULL	= 0xe006,
+	IPA_RC_LAN_PORT_STATE_ERROR	= 0xe007,
+	IPA_RC_SETIP_NO_STARTLAN	= 0xe008,
+	IPA_RC_SETIP_ALREADY_RECEIVED	= 0xe009,
+	IPA_RC_IP_ADDR_ALREADY_USED	= 0xe00a,
+	IPA_RC_MULTICAST_FULL		= 0xe00b,
+	IPA_RC_SETIP_INVALID_VERSION	= 0xe00d,
+	IPA_RC_UNSUPPORTED_SUBCMD	= 0xe00e,
+	IPA_RC_ARP_ASSIST_NO_ENABLE	= 0xe00f,
+	IPA_RC_PRIMARY_ALREADY_DEFINED	= 0xe010,
+	IPA_RC_SECOND_ALREADY_DEFINED	= 0xe011,
+	IPA_RC_INVALID_SETRTG_INDICATOR	= 0xe012,
+	IPA_RC_MC_ADDR_ALREADY_DEFINED	= 0xe013,
+	IPA_RC_LAN_OFFLINE		= 0xe080,
+	IPA_RC_INVALID_IP_VERSION2	= 0xf001,
+	IPA_RC_FFFF			= 0xffff
 };
 
 /* IPA function flags; each flag marks availability of respective function */
@@ -182,7 +211,9 @@ enum qeth_ipa_funcs {
 	IPA_SETADAPTERPARMS     = 0x00000400L,
 	IPA_VLAN_PRIO           = 0x00000800L,
 	IPA_PASSTHRU            = 0x00001000L,
+	IPA_FLUSH_ARP_SUPPORT   = 0x00002000L,
 	IPA_FULL_VLAN           = 0x00004000L,
+	IPA_INBOUND_PASSTHRU    = 0x00008000L,
 	IPA_SOURCE_MAC          = 0x00010000L,
 	IPA_OSA_MC_ROUTER       = 0x00020000L,
 	IPA_QUERY_ARP_ASSIST	= 0x00040000L,
@@ -203,31 +234,30 @@ enum qeth_ipa_setdelip_flags {
 /* SETADAPTER IPA Command: ****************************************************/
 enum qeth_ipa_setadp_cmd {
 	IPA_SETADP_QUERY_COMMANDS_SUPPORTED	= 0x01,
-	IPA_SETADP_ALTER_MAC_ADDRESS 		= 0x02,
-	IPA_SETADP_ADD_DELETE_GROUP_ADDRESS 	= 0x04,
-	IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR 	= 0x08,
-	IPA_SETADP_SET_ADDRESSING_MODE 		= 0x10,
-	IPA_SETADP_SET_CONFIG_PARMS 		= 0x20,
-	IPA_SETADP_SET_CONFIG_PARMS_EXTENDED 	= 0x40,
-	IPA_SETADP_SET_BROADCAST_MODE 		= 0x80,
-	IPA_SETADP_SEND_OSA_MESSAGE 		= 0x0100,
-	IPA_SETADP_SET_SNMP_CONTROL 		= 0x0200,
-	IPA_SETADP_READ_SNMP_PARMS 		= 0x0400,
+	IPA_SETADP_ALTER_MAC_ADDRESS		= 0x02,
+	IPA_SETADP_ADD_DELETE_GROUP_ADDRESS	= 0x04,
+	IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR	= 0x08,
+	IPA_SETADP_SET_ADDRESSING_MODE		= 0x10,
+	IPA_SETADP_SET_CONFIG_PARMS		= 0x20,
+	IPA_SETADP_SET_CONFIG_PARMS_EXTENDED	= 0x40,
+	IPA_SETADP_SET_BROADCAST_MODE		= 0x80,
+	IPA_SETADP_SEND_OSA_MESSAGE		= 0x0100,
+	IPA_SETADP_SET_SNMP_CONTROL		= 0x0200,
+	IPA_SETADP_QUERY_CARD_INFO		= 0x0400,
 	IPA_SETADP_SET_PROMISC_MODE		= 0x0800,
-	IPA_SETADP_QUERY_CARD_INFO 		= 0x1000,
 };
 enum qeth_ipa_mac_ops {
-	CHANGE_ADDR_READ_MAC 		= 0,
-	CHANGE_ADDR_REPLACE_MAC 	= 1,
-	CHANGE_ADDR_ADD_MAC 		= 2,
-	CHANGE_ADDR_DEL_MAC 		= 4,
-	CHANGE_ADDR_RESET_MAC 		= 8,
+	CHANGE_ADDR_READ_MAC		= 0,
+	CHANGE_ADDR_REPLACE_MAC		= 1,
+	CHANGE_ADDR_ADD_MAC		= 2,
+	CHANGE_ADDR_DEL_MAC		= 4,
+	CHANGE_ADDR_RESET_MAC		= 8,
 };
 enum qeth_ipa_addr_ops {
-	CHANGE_ADDR_READ_ADDR 		= 0,
-	CHANGE_ADDR_ADD_ADDR 		= 1,
-	CHANGE_ADDR_DEL_ADDR 		= 2,
-	CHANGE_ADDR_FLUSH_ADDR_TABLE 	= 4,
+	CHANGE_ADDR_READ_ADDR		= 0,
+	CHANGE_ADDR_ADD_ADDR		= 1,
+	CHANGE_ADDR_DEL_ADDR		= 2,
+	CHANGE_ADDR_FLUSH_ADDR_TABLE	= 4,
 };
 enum qeth_ipa_promisc_modes {
 	SET_PROMISC_MODE_OFF		= 0,
@@ -406,15 +436,15 @@ struct qeth_ipacmd_hdr {
 struct qeth_ipa_cmd {
 	struct qeth_ipacmd_hdr hdr;
 	union {
-		struct qeth_ipacmd_setdelip4   		setdelip4;
-		struct qeth_ipacmd_setdelip6   		setdelip6;
+		struct qeth_ipacmd_setdelip4		setdelip4;
+		struct qeth_ipacmd_setdelip6		setdelip6;
 		struct qeth_ipacmd_setdelipm		setdelipm;
-		struct qeth_ipacmd_setassparms 		setassparms;
-		struct qeth_ipacmd_layer2setdelmac  	setdelmac;
-		struct qeth_ipacmd_layer2setdelvlan 	setdelvlan;
-		struct qeth_create_destroy_address 	create_destroy_addr;
-		struct qeth_ipacmd_setadpparms 		setadapterparms;
-		struct qeth_set_routing 		setrtg;
+		struct qeth_ipacmd_setassparms		setassparms;
+		struct qeth_ipacmd_layer2setdelmac	setdelmac;
+		struct qeth_ipacmd_layer2setdelvlan	setdelvlan;
+		struct qeth_create_destroy_address	create_destroy_addr;
+		struct qeth_ipacmd_setadpparms		setadapterparms;
+		struct qeth_set_routing			setrtg;
 	} data;
 } __attribute__ ((packed));
 
@@ -432,6 +462,12 @@ enum qeth_ipa_arp_return_codes {
 	QETH_IPA_ARP_RC_Q_NO_DATA    = 0x0008,
 };
 
+
+extern char *
+qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
+extern char *
+qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
+
 #define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
 			       sizeof(struct qeth_ipacmd_setassparms_hdr))
 #define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
@@ -520,7 +556,7 @@ #define QETH_PDU_HEADER_ACK_SEQ_NO(buffe
 extern unsigned char IDX_ACTIVATE_READ[];
 extern unsigned char IDX_ACTIVATE_WRITE[];
 
-#define IDX_ACTIVATE_SIZE 	0x22
+#define IDX_ACTIVATE_SIZE	0x22
 #define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
 #define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
 #define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 81f805c..89d56c8 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -37,7 +37,6 @@ qeth_procfile_seq_start(struct seq_file 
 	struct device *dev = NULL;
 	loff_t nr = 0;
 
-	down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
 	if (*offset == 0)
 		return SEQ_START_TOKEN;
 	while (1) {
@@ -53,7 +52,6 @@ qeth_procfile_seq_start(struct seq_file 
 static void
 qeth_procfile_seq_stop(struct seq_file *s, void* it)
 {
-	up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
 }
 
 static void *
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index d518419..65ffc21 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -384,8 +384,6 @@ qeth_dev_route_store(struct qeth_card *c
 		route->type = PRIMARY_CONNECTOR;
 	} else if (!strcmp(tmp, "secondary_connector")) {
 		route->type = SECONDARY_CONNECTOR;
-	} else if (!strcmp(tmp, "multicast_router")) {
-		route->type = MULTICAST_ROUTER;
 	} else if (!strcmp(tmp, "primary_router")) {
 		route->type = PRIMARY_ROUTER;
 	} else if (!strcmp(tmp, "secondary_router")) {
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index 14504af..c20e923 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -40,8 +40,8 @@ qeth_tso_fill_header(struct qeth_card *c
 	QETH_DBF_TEXT(trace, 5, "tsofhdr");
 
 	hdr  = (struct qeth_hdr_tso *) skb->data;
-	iph  = skb->nh.iph;
-	tcph = skb->h.th;
+	iph  = ip_hdr(skb);
+	tcph = tcp_hdr(skb);
 	/*fix header to TSO values ...*/
 	hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
 	/*set values which are fix for the first approach ...*/
@@ -63,13 +63,9 @@ qeth_tso_fill_header(struct qeth_card *c
 static inline void
 qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb)
 {
-	struct iphdr *iph;
-	struct ipv6hdr *ip6h;
-	struct tcphdr *tcph;
-
-	iph  = skb->nh.iph;
-	ip6h = skb->nh.ipv6h;
-	tcph = skb->h.th;
+	struct iphdr *iph    = ip_hdr(skb);
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct tcphdr *tcph  = tcp_hdr(skb);
 
 	tcph->check = 0;
 	if (skb->protocol == ETH_P_IPV6) {
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 806bb1a..644a06e 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -21,6 +21,7 @@ #include <asm/cio.h>
 #include "cio/cio.h"
 #include "cio/chsc.h"
 #include "cio/css.h"
+#include "cio/chp.h"
 #include "s390mach.h"
 
 static struct semaphore m_sem;
@@ -44,14 +45,13 @@ static int
 s390_collect_crw_info(void *param)
 {
 	struct crw crw[2];
-	int ccode, ret, slow;
+	int ccode;
 	struct semaphore *sem;
 	unsigned int chain;
 
 	sem = (struct semaphore *)param;
 repeat:
 	down_interruptible(sem);
-	slow = 0;
 	chain = 0;
 	while (1) {
 		if (unlikely(chain > 1)) {
@@ -84,9 +84,8 @@ repeat:
 		/* Check for overflows. */
 		if (crw[chain].oflw) {
 			pr_debug("%s: crw overflow detected!\n", __FUNCTION__);
-			css_reiterate_subchannels();
+			css_schedule_eval_all();
 			chain = 0;
-			slow = 1;
 			continue;
 		}
 		switch (crw[chain].rsc) {
@@ -94,10 +93,7 @@ repeat:
 			if (crw[0].chn && !chain)
 				break;
 			pr_debug("source is subchannel %04X\n", crw[0].rsid);
-			ret = css_process_crw (crw[0].rsid,
-					       chain ? crw[1].rsid : 0);
-			if (ret == -EAGAIN)
-				slow = 1;
+			css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0);
 			break;
 		case CRW_RSC_MONITOR:
 			pr_debug("source is monitoring facility\n");
@@ -116,28 +112,23 @@ repeat:
 			}
 			switch (crw[0].erc) {
 			case CRW_ERC_IPARM: /* Path has come. */
-				ret = chp_process_crw(crw[0].rsid, 1);
+				chp_process_crw(crw[0].rsid, 1);
 				break;
 			case CRW_ERC_PERRI: /* Path has gone. */
 			case CRW_ERC_PERRN:
-				ret = chp_process_crw(crw[0].rsid, 0);
+				chp_process_crw(crw[0].rsid, 0);
 				break;
 			default:
 				pr_debug("Don't know how to handle erc=%x\n",
 					 crw[0].erc);
-				ret = 0;
 			}
-			if (ret == -EAGAIN)
-				slow = 1;
 			break;
 		case CRW_RSC_CONFIG:
 			pr_debug("source is configuration-alert facility\n");
 			break;
 		case CRW_RSC_CSS:
 			pr_debug("source is channel subsystem\n");
-			ret = chsc_process_crw();
-			if (ret == -EAGAIN)
-				slow = 1;
+			chsc_process_crw();
 			break;
 		default:
 			pr_debug("unknown source\n");
@@ -146,8 +137,6 @@ repeat:
 		/* chain is always 0 or 1 here. */
 		chain = crw[chain].chn ? chain + 1 : 0;
 	}
-	if (slow)
-		queue_work(slow_path_wq, &slow_path_work);
 	goto repeat;
 	return 0;
 }
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 421da1e..c1f2d4b 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -186,7 +186,7 @@ void zfcp_fsf_start_timer(struct zfcp_fs
 {
 	fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
 	fsf_req->timer.data = (unsigned long) fsf_req->adapter;
-	fsf_req->timer.expires = timeout;
+	fsf_req->timer.expires = jiffies + timeout;
 	add_timer(&fsf_req->timer);
 }
 
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index ef16f7c..4c0a59a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -299,9 +299,10 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf
 	}
 
 	/* log additional information provided by FSF (if any) */
-	if (unlikely(qtcb->header.log_length)) {
+	if (likely(qtcb->header.log_length)) {
 		/* do not trust them ;-) */
-		if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
+		if (unlikely(qtcb->header.log_start >
+			     sizeof(struct fsf_qtcb))) {
 			ZFCP_LOG_NORMAL
 			    ("bug: ULP (FSF logging) log data starts "
 			     "beyond end of packet header. Ignored. "
@@ -310,8 +311,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf
 			     sizeof(struct fsf_qtcb));
 			goto forget_log;
 		}
-		if ((size_t) (qtcb->header.log_start + qtcb->header.log_length)
-		    > sizeof(struct fsf_qtcb)) {
+		if (unlikely((size_t) (qtcb->header.log_start +
+				       qtcb->header.log_length) >
+			     sizeof(struct fsf_qtcb))) {
 			ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
 					"beyond end of packet header. Ignored. "
 					"(start=%i, length=%i, size=%li)\n",
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 090743d..19343f9 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -357,6 +357,24 @@ static __init int create_proc_sysinfo(vo
 
 __initcall(create_proc_sysinfo);
 
+int get_cpu_capability(unsigned int *capability)
+{
+	struct sysinfo_1_2_2 *info;
+	int rc;
+
+	info = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	rc = stsi(info, 1, 2, 2);
+	if (rc == -ENOSYS)
+		goto out;
+	rc = 0;
+	*capability = info->capability;
+out:
+	free_page((unsigned long) info);
+	return rc;
+}
+
 /*
  * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
  */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index a39ee80..74b999d 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -15,7 +15,6 @@ #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 2cea4f5..f2be2ea 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -726,7 +726,7 @@ static struct miscdevice envctrl_dev = {
  * Return: None.
  */
 static void envctrl_set_mon(struct i2c_child_t *pchild,
-			    char *chnl_desc,
+			    const char *chnl_desc,
 			    int chnl_no)
 {
 	/* Firmware only has temperature type.  It does not distinguish
@@ -763,8 +763,8 @@ static void envctrl_set_mon(struct i2c_c
 static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
 {
 	int i = 0, len;
-	char *pos;
-	unsigned int *pval;
+	const char *pos;
+	const unsigned int *pval;
 
 	/* Firmware describe channels into a stream separated by a '\0'. */
 	pos = of_get_property(dp, "channels-description", &len);
@@ -859,7 +859,7 @@ static void envctrl_init_i2c_child(struc
 {
 	int len, i, tbls_size = 0;
 	struct device_node *dp = edev_child->prom_node;
-	void *pval;
+	const void *pval;
 
 	/* Get device address. */
 	pval = of_get_property(dp, "reg", &len);
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 6e99507..262f01e 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -190,7 +190,7 @@ #endif
 	}
 	if (!sdev) {
 #ifdef CONFIG_PCI
-		struct linux_prom_registers *ebus_regs;
+		const struct linux_prom_registers *ebus_regs;
 
 		for_each_ebus(ebus) {
 			for_each_ebusdev(edev, ebus) {
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 5041c9d..fbfeb89 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -44,7 +44,6 @@ #include <asm/uaccess.h>
 #include <asm/openpromio.h>
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
-#include <asm/pbm.h>
 #endif
 
 MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost  (ecd@skynet.be)");
@@ -141,7 +140,7 @@ static int copyout(void __user *info, st
 
 static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
 {
-	void *pval;
+	const void *pval;
 	int len;
 
 	if (!dp ||
@@ -248,18 +247,17 @@ static int oprompci2node(void __user *ar
 	if (bufsize >= 2*sizeof(int)) {
 #ifdef CONFIG_PCI
 		struct pci_dev *pdev;
-		struct pcidev_cookie *pcp;
+		struct device_node *dp;
+
 		pdev = pci_get_bus_and_slot (((int *) op->oprom_array)[0],
 				      ((int *) op->oprom_array)[1]);
 
-		pcp = pdev->sysdata;
-		if (pcp != NULL) {
-			dp = pcp->prom_node;
-			data->current_node = dp;
-			*((int *)op->oprom_array) = dp->node;
-			op->oprom_size = sizeof(int);
-			err = copyout(argp, op, bufsize + sizeof(int));
-		}
+		dp = pci_device_to_OF_node(pdev);
+		data->current_node = dp;
+		*((int *)op->oprom_array) = dp->node;
+		op->oprom_size = sizeof(int);
+		err = copyout(argp, op, bufsize + sizeof(int));
+
 		pci_dev_put(pdev);
 #endif
 	}
@@ -410,7 +408,7 @@ static int opiocget(void __user *argp, D
 	struct opiocdesc op;
 	struct device_node *dp;
 	char *str;
-	void *pval;
+	const void *pval;
 	int err, len;
 
 	if (copy_from_user(&op, argp, sizeof(op)))
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index 94d1858..18d18f1 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -19,7 +19,6 @@ #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <asm/io.h>
 #include <asm/mostek.h>
 #include <asm/system.h>
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index c3135e2..6afc7e5 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -20,7 +20,6 @@ #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 6349dd6..0026433 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -6,7 +6,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/device.h>
 
 #include <asm/system.h>
@@ -35,7 +34,7 @@ struct sbus_bus *sbus_root;
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
 	unsigned long base;
-	void *pval;
+	const void *pval;
 	int len, err;
 
 	sdev->prom_node = dp->node;
@@ -86,7 +85,7 @@ static void __init fill_sbus_device(stru
 
 static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
 {
-	void *pval;
+	const void *pval;
 	int len;
 
 	pval = of_get_property(dp, "ranges", &len);
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index e874b89..96f4cab 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -579,17 +579,17 @@ static void __init BusLogic_InitializePr
 	/*
 	   Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
 	 */
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330)
 		BusLogic_AppendProbeAddressISA(0x330);
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334)
 		BusLogic_AppendProbeAddressISA(0x334);
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230)
 		BusLogic_AppendProbeAddressISA(0x230);
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234)
 		BusLogic_AppendProbeAddressISA(0x234);
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130)
 		BusLogic_AppendProbeAddressISA(0x130);
-	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+	if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134)
 		BusLogic_AppendProbeAddressISA(0x134);
 }
 
@@ -795,7 +795,9 @@ static int __init BusLogic_InitializeMul
 	   host adapters are probed.
 	 */
 	if (!BusLogic_ProbeOptions.NoProbeISA)
-		if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) {
+		if (PrimaryProbeInfo->IO_Address == 0 &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe330)) {
 			PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
 			PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
 			PrimaryProbeInfo->IO_Address = 0x330;
@@ -805,15 +807,25 @@ static int __init BusLogic_InitializeMul
 	   omitting the Primary I/O Address which has already been handled.
 	 */
 	if (!BusLogic_ProbeOptions.NoProbeISA) {
-		if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+		if (!StandardAddressSeen[1] &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe334))
 			BusLogic_AppendProbeAddressISA(0x334);
-		if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+		if (!StandardAddressSeen[2] &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe230))
 			BusLogic_AppendProbeAddressISA(0x230);
-		if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+		if (!StandardAddressSeen[3] &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe234))
 			BusLogic_AppendProbeAddressISA(0x234);
-		if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+		if (!StandardAddressSeen[4] &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe130))
 			BusLogic_AppendProbeAddressISA(0x130);
-		if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+		if (!StandardAddressSeen[5] &&
+				(!BusLogic_ProbeOptions.LimitedProbeISA ||
+				 BusLogic_ProbeOptions.Probe134))
 			BusLogic_AppendProbeAddressISA(0x134);
 	}
 	/*
@@ -2220,22 +2232,35 @@ #endif
 		HostAdapter->PCI_Device = ProbeInfo->PCI_Device;
 		HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
 		HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
+
+		/*
+		   Make sure region is free prior to probing.
+		 */
+		if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount,
+					"BusLogic"))
+			continue;
 		/*
 		   Probe the Host Adapter.  If unsuccessful, abort further initialization.
 		 */
-		if (!BusLogic_ProbeHostAdapter(HostAdapter))
+		if (!BusLogic_ProbeHostAdapter(HostAdapter)) {
+			release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
 			continue;
+		}
 		/*
 		   Hard Reset the Host Adapter.  If unsuccessful, abort further
 		   initialization.
 		 */
-		if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true))
+		if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) {
+			release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
 			continue;
+		}
 		/*
 		   Check the Host Adapter.  If unsuccessful, abort further initialization.
 		 */
-		if (!BusLogic_CheckHostAdapter(HostAdapter))
+		if (!BusLogic_CheckHostAdapter(HostAdapter)) {
+			release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
 			continue;
+		}
 		/*
 		   Initialize the Driver Options field if provided.
 		 */
@@ -2247,16 +2272,6 @@ #endif
 		 */
 		BusLogic_AnnounceDriver(HostAdapter);
 		/*
-		   Register usage of the I/O Address range.  From this point onward, any
-		   failure will be assumed to be due to a problem with the Host Adapter,
-		   rather than due to having mistakenly identified this port as belonging
-		   to a BusLogic Host Adapter.  The I/O Address range will not be
-		   released, thereby preventing it from being incorrectly identified as
-		   any other type of Host Adapter.
-		 */
-		if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic"))
-			continue;
-		/*
 		   Register the SCSI Host structure.
 		 */
 
@@ -2280,6 +2295,12 @@ #endif
 		   Acquire the System Resources necessary to use the Host Adapter, then
 		   Create the Initial CCBs, Initialize the Host Adapter, and finally
 		   perform Target Device Inquiry.
+
+		   From this point onward, any failure will be assumed to be due to a
+		   problem with the Host Adapter, rather than due to having mistakenly
+		   identified this port as belonging to a BusLogic Host Adapter.  The
+		   I/O Address range will not be released, thereby preventing it from
+		   being incorrectly identified as any other type of Host Adapter.
 		 */
 		if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
 		    BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
@@ -3598,6 +3619,7 @@ static void __exit BusLogic_exit(void)
 
 __setup("BusLogic=", BusLogic_Setup);
 
+#ifdef MODULE
 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},
@@ -3607,6 +3629,7 @@ static struct pci_device_id BusLogic_pci
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ }
 };
+#endif
 MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
 
 module_init(BusLogic_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4cd280e..e62d23f 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -170,7 +170,7 @@ config CHR_DEV_SCH
 	
 	  If you want to compile this as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/modules.txt> and
+	  say M here and read <file:Documentation/kbuild/modules.txt> and
 	  <file:Documentation/scsi.txt>. The module will be called ch.o.
 	  If unsure, say N.
 	
@@ -241,6 +241,12 @@ config SCSI_SCAN_ASYNC
 	  You can override this choice by specifying "scsi_mod.scan=sync"
 	  or async on the kernel's command line.
 
+config SCSI_WAIT_SCAN
+	tristate
+	default m
+	depends on SCSI
+	depends on MODULES
+
 menu "SCSI Transports"
 	depends on SCSI
 
@@ -1194,17 +1200,6 @@ config SCSI_NCR53C8XX_SYNC
 	  There is no safe option other than using good cabling, right
 	  terminations and SCSI conformant devices.
 
-config SCSI_NCR53C8XX_PROFILE
-	bool "enable profiling"
-	depends on SCSI_ZALON || SCSI_NCR_Q720
-	help
-	  This option allows you to enable profiling information gathering.
-	  These statistics are not very accurate due to the low frequency
-	  of the kernel clock (100 Hz on i386) and have performance impact
-	  on systems that use very fast devices.
-
-	  The normal answer therefore is N.
-
 config SCSI_NCR53C8XX_NO_DISCONNECT
 	bool "not allow targets to disconnect"
 	depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
@@ -1334,11 +1329,6 @@ config SCSI_SIM710
 
 	  It currently supports Compaq EISA cards and NCR MCA cards
 
-config 53C700_IO_MAPPED
-	bool
-	depends on SCSI_SIM710
-	default y
-
 config SCSI_SYM53C416
 	tristate "Symbios 53c416 SCSI support"
 	depends on ISA && SCSI
@@ -1649,7 +1639,7 @@ config OKTAGON_SCSI
 
 config ATARI_SCSI
 	tristate "Atari native SCSI support"
-	depends on ATARI && SCSI && BROKEN
+	depends on ATARI && SCSI
 	select SCSI_SPI_ATTRS
 	---help---
 	  If you have an Atari with built-in NCR5380 SCSI controller (TT,
@@ -1763,9 +1753,15 @@ config SUN3X_ESP
 	  The ESP was an on-board SCSI controller used on Sun 3/80
 	  machines.  Say Y here to compile in support for it.
 
+config SCSI_ESP_CORE
+	tristate "ESP Scsi Driver Core"
+	depends on SCSI
+	select SCSI_SPI_ATTRS
+
 config SCSI_SUNESP
 	tristate "Sparc ESP Scsi Driver"
 	depends on SBUS && SCSI
+	select SCSI_ESP_CORE
 	help
 	  This is the driver for the Sun ESP SCSI host adapter. The ESP
 	  chipset is present in most SPARC SBUS-based computers.
@@ -1787,7 +1783,7 @@ config ZFCP
 
           This driver is also available as a module. This module will be
           called zfcp. If you want to compile it as a module, say M here
-          and read <file:Documentation/modules.txt>.
+          and read <file:Documentation/kbuild/modules.txt>.
 
 config SCSI_SRP
 	tristate "SCSI RDMA Protocol helper library"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 79ecf4e..51e884f 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,8 @@ obj-$(CONFIG_MEGARAID_LEGACY)	+= megarai
 obj-$(CONFIG_MEGARAID_NEWGEN)	+= megaraid/
 obj-$(CONFIG_MEGARAID_SAS)	+= megaraid/
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
-obj-$(CONFIG_SCSI_SUNESP)	+= esp.o
+obj-$(CONFIG_SCSI_ESP_CORE)	+= esp_scsi.o
+obj-$(CONFIG_SCSI_SUNESP)	+= sun_esp.o
 obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
 obj-$(CONFIG_SCSI_INITIO)	+= initio.o
 obj-$(CONFIG_SCSI_INIA100)	+= a100u2w.o
@@ -145,7 +146,7 @@ obj-$(CONFIG_CHR_DEV_SCH)	+= ch.o
 # This goes last, so that "real" scsi devices probe earlier
 obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
 
-obj-$(CONFIG_SCSI)		+= scsi_wait_scan.o
+obj-$(CONFIG_SCSI_WAIT_SCAN)	+= scsi_wait_scan.o
 
 scsi_mod-y			+= scsi.o hosts.o scsi_ioctl.o constants.o \
 				   scsicam.o scsi_error.o scsi_lib.o \
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index d789e61..1e82c69 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -172,6 +172,30 @@ MODULE_PARM_DESC(acbsize, "Request a spe
 int expose_physicals = -1;
 module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
+
+
+static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
+		struct fib *fibptr) {
+	struct scsi_device *device;
+
+	if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
+		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"))
+;
+                aac_fib_complete(fibptr);
+                aac_fib_free(fibptr);
+                return 0;
+        }
+	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+	device = scsicmd->device;
+	if (unlikely(!device || !scsi_device_online(device))) {
+		dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
+		aac_fib_complete(fibptr);
+		aac_fib_free(fibptr);
+		return 0;
+	}
+	return 1;
+}
+
 /**
  *	aac_get_config_status	-	check the adapter configuration
  *	@common: adapter to query
@@ -258,13 +282,10 @@ int aac_get_containers(struct aac_dev *d
 	u32 index; 
 	int status = 0;
 	struct fib * fibptr;
-	unsigned instance;
 	struct aac_get_container_count *dinfo;
 	struct aac_get_container_count_resp *dresp;
 	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
 
-	instance = dev->scsi_host_ptr->unique_id;
-
 	if (!(fibptr = aac_fib_alloc(dev)))
 		return -ENOMEM;
 
@@ -284,88 +305,35 @@ int aac_get_containers(struct aac_dev *d
 		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
 		aac_fib_complete(fibptr);
 	}
+	aac_fib_free(fibptr);
 
 	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
 		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
-	fsa_dev_ptr = kmalloc(
-	  sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
-	if (!fsa_dev_ptr) {
-		aac_fib_free(fibptr);
+	fsa_dev_ptr =  kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
+			GFP_KERNEL);
+	if (!fsa_dev_ptr)
 		return -ENOMEM;
-	}
 	memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
 
 	dev->fsa_dev = fsa_dev_ptr;
 	dev->maximum_num_containers = maximum_num_containers;
 
-	for (index = 0; index < dev->maximum_num_containers; index++) {
-		struct aac_query_mount *dinfo;
-		struct aac_mount *dresp;
-
+	for (index = 0; index < dev->maximum_num_containers; ) {
 		fsa_dev_ptr[index].devname[0] = '\0';
 
-		aac_fib_init(fibptr);
-		dinfo = (struct aac_query_mount *) fib_data(fibptr);
-
-		dinfo->command = cpu_to_le32(VM_NameServe);
-		dinfo->count = cpu_to_le32(index);
-		dinfo->type = cpu_to_le32(FT_FILESYS);
+		status = aac_probe_container(dev, index);
 
-		status = aac_fib_send(ContainerCommand,
-				    fibptr,
-				    sizeof (struct aac_query_mount),
-				    FsaNormal,
-				    1, 1,
-				    NULL, NULL);
-		if (status < 0 ) {
+		if (status < 0) {
 			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
 			break;
 		}
-		dresp = (struct aac_mount *)fib_data(fibptr);
 
-		if ((le32_to_cpu(dresp->status) == ST_OK) &&
-		    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
-			dinfo->command = cpu_to_le32(VM_NameServe64);
-			dinfo->count = cpu_to_le32(index);
-			dinfo->type = cpu_to_le32(FT_FILESYS);
-
-			if (aac_fib_send(ContainerCommand,
-				    fibptr,
-				    sizeof(struct aac_query_mount),
-				    FsaNormal,
-				    1, 1,
-				    NULL, NULL) < 0)
-				continue;
-		} else
-			dresp->mnt[0].capacityhigh = 0;
-
-		dprintk ((KERN_DEBUG
-		  "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
-		  (int)index, (int)le32_to_cpu(dresp->status),
-		  (int)le32_to_cpu(dresp->mnt[0].vol),
-		  (int)le32_to_cpu(dresp->mnt[0].state),
-		  ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
-		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
-		if ((le32_to_cpu(dresp->status) == ST_OK) &&
-		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
-		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-			fsa_dev_ptr[index].valid = 1;
-			fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
-			fsa_dev_ptr[index].size
-			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
-			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
-			if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-				    fsa_dev_ptr[index].ro = 1;
-		}
-		aac_fib_complete(fibptr);
 		/*
 		 *	If there are no more containers, then stop asking.
 		 */
-		if ((index + 1) >= le32_to_cpu(dresp->count)){
+		if (++index >= status)
 			break;
-		}
 	}
-	aac_fib_free(fibptr);
 	return status;
 }
 
@@ -382,8 +350,9 @@ static void aac_internal_transfer(struct
 		buf = scsicmd->request_buffer;
 		transfer_len = min(scsicmd->request_bufflen, len + offset);
 	}
-
-	memcpy(buf + offset, data, transfer_len - offset);
+	transfer_len -= offset;
+	if (buf && transfer_len)
+		memcpy(buf + offset, data, transfer_len);
 
 	if (scsicmd->use_sg) 
 		kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -396,7 +365,9 @@ static void get_container_name_callback(
 	struct scsi_cmnd * scsicmd;
 
 	scsicmd = (struct scsi_cmnd *) context;
-	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	if (!aac_valid_context(scsicmd, fibptr))
+		return;
 
 	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
 	BUG_ON(fibptr == NULL);
@@ -431,7 +402,7 @@ static void get_container_name_callback(
 /**
  *	aac_get_container_name	-	get container name, none blocking.
  */
-static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
+static int aac_get_container_name(struct scsi_cmnd * scsicmd)
 {
 	int status;
 	struct aac_get_name *dinfo;
@@ -448,7 +419,7 @@ static int aac_get_container_name(struct
 
 	dinfo->command = cpu_to_le32(VM_ContainerConfig);
 	dinfo->type = cpu_to_le32(CT_READ_NAME);
-	dinfo->cid = cpu_to_le32(cid);
+	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
 
 	status = aac_fib_send(ContainerCommand,
@@ -473,85 +444,192 @@ static int aac_get_container_name(struct
 	return -1;
 }
 
-/**
- *	aac_probe_container		-	query a logical volume
- *	@dev: device to query
- *	@cid: container identifier
- *
- *	Queries the controller about the given volume. The volume information
- *	is updated in the struct fsa_dev_info structure rather than returned.
- */
- 
-int aac_probe_container(struct aac_dev *dev, int cid)
+static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
+{
+	struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+	if (fsa_dev_ptr[scmd_id(scsicmd)].valid)
+		return aac_scsi_cmd(scsicmd);
+
+	scsicmd->result = DID_NO_CONNECT << 16;
+	scsicmd->scsi_done(scsicmd);
+	return 0;
+}
+
+static int _aac_probe_container2(void * context, struct fib * fibptr)
 {
 	struct fsa_dev_info *fsa_dev_ptr;
-	int status;
+	int (*callback)(struct scsi_cmnd *);
+	struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
+
+	if (!aac_valid_context(scsicmd, fibptr))
+		return 0;
+
+	fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+	scsicmd->SCp.Status = 0;
+	if (fsa_dev_ptr) {
+		struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
+		fsa_dev_ptr += scmd_id(scsicmd);
+
+		if ((le32_to_cpu(dresp->status) == ST_OK) &&
+		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
+			fsa_dev_ptr->valid = 1;
+			fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
+			fsa_dev_ptr->size
+			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
+			fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
+		}
+		if ((fsa_dev_ptr->valid & 1) == 0)
+			fsa_dev_ptr->valid = 0;
+		scsicmd->SCp.Status = le32_to_cpu(dresp->count);
+	}
+	aac_fib_complete(fibptr);
+	aac_fib_free(fibptr);
+	callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
+	scsicmd->SCp.ptr = NULL;
+	return (*callback)(scsicmd);
+}
+
+static int _aac_probe_container1(void * context, struct fib * fibptr)
+{
+	struct scsi_cmnd * scsicmd;
+	struct aac_mount * dresp;
 	struct aac_query_mount *dinfo;
-	struct aac_mount *dresp;
-	struct fib * fibptr;
-	unsigned instance;
+	int status;
 
-	fsa_dev_ptr = dev->fsa_dev;
-	if (!fsa_dev_ptr)
-		return -ENOMEM;
-	instance = dev->scsi_host_ptr->unique_id;
+	dresp = (struct aac_mount *) fib_data(fibptr);
+	dresp->mnt[0].capacityhigh = 0;
+	if ((le32_to_cpu(dresp->status) != ST_OK) ||
+	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE))
+		return _aac_probe_container2(context, fibptr);
+	scsicmd = (struct scsi_cmnd *) context;
+	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
 
-	if (!(fibptr = aac_fib_alloc(dev)))
-		return -ENOMEM;
+	if (!aac_valid_context(scsicmd, fibptr))
+		return 0;
 
 	aac_fib_init(fibptr);
 
 	dinfo = (struct aac_query_mount *)fib_data(fibptr);
 
-	dinfo->command = cpu_to_le32(VM_NameServe);
-	dinfo->count = cpu_to_le32(cid);
+	dinfo->command = cpu_to_le32(VM_NameServe64);
+	dinfo->count = cpu_to_le32(scmd_id(scsicmd));
 	dinfo->type = cpu_to_le32(FT_FILESYS);
 
 	status = aac_fib_send(ContainerCommand,
-			    fibptr,
-			    sizeof(struct aac_query_mount),
-			    FsaNormal,
-			    1, 1,
-			    NULL, NULL);
+			  fibptr,
+			  sizeof(struct aac_query_mount),
+			  FsaNormal,
+			  0, 1,
+			  (fib_callback) _aac_probe_container2,
+			  (void *) scsicmd);
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+		return 0;
+	}
 	if (status < 0) {
-		printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n");
-		goto error;
+		/* Inherit results from VM_NameServe, if any */
+		dresp->status = cpu_to_le32(ST_OK);
+		return _aac_probe_container2(context, fibptr);
 	}
+	return 0;
+}
 
-	dresp = (struct aac_mount *) fib_data(fibptr);
+static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
+{
+	struct fib * fibptr;
+	int status = -ENOMEM;
 
-	if ((le32_to_cpu(dresp->status) == ST_OK) &&
-	    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
-		dinfo->command = cpu_to_le32(VM_NameServe64);
-		dinfo->count = cpu_to_le32(cid);
-		dinfo->type = cpu_to_le32(FT_FILESYS);
+	if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
+		struct aac_query_mount *dinfo;
 
-		if (aac_fib_send(ContainerCommand,
-			    fibptr,
-			    sizeof(struct aac_query_mount),
-			    FsaNormal,
-			    1, 1,
-			    NULL, NULL) < 0)
-			goto error;
-	} else
-		dresp->mnt[0].capacityhigh = 0;
+		aac_fib_init(fibptr);
+
+		dinfo = (struct aac_query_mount *)fib_data(fibptr);
+
+		dinfo->command = cpu_to_le32(VM_NameServe);
+		dinfo->count = cpu_to_le32(scmd_id(scsicmd));
+		dinfo->type = cpu_to_le32(FT_FILESYS);
+		scsicmd->SCp.ptr = (char *)callback;
 
-	if ((le32_to_cpu(dresp->status) == ST_OK) &&
-	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
-	    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
-		fsa_dev_ptr[cid].valid = 1;
-		fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
-		fsa_dev_ptr[cid].size
-		  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
-		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
-		if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
-			fsa_dev_ptr[cid].ro = 1;
+		status = aac_fib_send(ContainerCommand,
+			  fibptr,
+			  sizeof(struct aac_query_mount),
+			  FsaNormal,
+			  0, 1,
+			  (fib_callback) _aac_probe_container1,
+			  (void *) scsicmd);
+		/*
+		 *	Check that the command queued to the controller
+		 */
+		if (status == -EINPROGRESS) {
+			scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+			return 0;
+		}
+		if (status < 0) {
+			scsicmd->SCp.ptr = NULL;
+			aac_fib_complete(fibptr);
+			aac_fib_free(fibptr);
+		}
 	}
+	if (status < 0) {
+		struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+		if (fsa_dev_ptr) {
+			fsa_dev_ptr += scmd_id(scsicmd);
+			if ((fsa_dev_ptr->valid & 1) == 0) {
+				fsa_dev_ptr->valid = 0;
+				return (*callback)(scsicmd);
+			}
+		}
+	}
+	return status;
+}
 
-error:
-	aac_fib_complete(fibptr);
-	aac_fib_free(fibptr);
+/**
+ *	aac_probe_container		-	query a logical volume
+ *	@dev: device to query
+ *	@cid: container identifier
+ *
+ *	Queries the controller about the given volume. The volume information
+ *	is updated in the struct fsa_dev_info structure rather than returned.
+ */
+static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
+{
+	scsicmd->device = NULL;
+	return 0;
+}
+
+int aac_probe_container(struct aac_dev *dev, int cid)
+{
+	struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
+	struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
+	int status;
 
+	if (!scsicmd || !scsidev) {
+		kfree(scsicmd);
+		kfree(scsidev);
+		return -ENOMEM;
+	}
+	scsicmd->list.next = NULL;
+	scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1;
+
+	scsicmd->device = scsidev;
+	scsidev->sdev_state = 0;
+	scsidev->id = cid;
+	scsidev->host = dev->scsi_host_ptr;
+
+	if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
+		while (scsicmd->device == scsidev)
+			schedule();
+	kfree(scsidev);
+	status = scsicmd->SCp.Status;
+	kfree(scsicmd);
 	return status;
 }
 
@@ -1115,6 +1193,12 @@ int aac_get_adapter_info(struct aac_dev*
 			printk(KERN_INFO "%s%d: serial %x\n",
 				dev->name, dev->id,
 				le32_to_cpu(dev->adapter_info.serial[0]));
+		if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
+			printk(KERN_INFO "%s%d: TSID %.*s\n",
+			  dev->name, dev->id,
+			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
+			  dev->supplement_adapter_info.VpdInfo.Tsid);
+		}
 	}
 
 	dev->nondasd_support = 0;
@@ -1241,7 +1325,9 @@ static void io_callback(void *context, s
 	u32 cid;
 
 	scsicmd = (struct scsi_cmnd *) context;
-	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	if (!aac_valid_context(scsicmd, fibptr))
+		return;
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	cid = scmd_id(scsicmd);
@@ -1317,7 +1403,7 @@ #endif
 	scsicmd->scsi_done(scsicmd);
 }
 
-static int aac_read(struct scsi_cmnd * scsicmd, int cid)
+static int aac_read(struct scsi_cmnd * scsicmd)
 {
 	u64 lba;
 	u32 count;
@@ -1331,7 +1417,7 @@ static int aac_read(struct scsi_cmnd * s
 	 */
 	switch (scsicmd->cmnd[0]) {
 	case READ_6:
-		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
@@ -1341,7 +1427,7 @@ static int aac_read(struct scsi_cmnd * s
 			count = 256;
 		break;
 	case READ_16:
-		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = 	((u64)scsicmd->cmnd[2] << 56) |
 		 	((u64)scsicmd->cmnd[3] << 48) |
@@ -1355,7 +1441,7 @@ static int aac_read(struct scsi_cmnd * s
 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
 		break;
 	case READ_12:
-		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = ((u64)scsicmd->cmnd[2] << 24) | 
 			(scsicmd->cmnd[3] << 16) |
@@ -1365,7 +1451,7 @@ static int aac_read(struct scsi_cmnd * s
 		      	(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 		break;
 	default:
-		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = ((u64)scsicmd->cmnd[2] << 24) | 
 			(scsicmd->cmnd[3] << 16) | 
@@ -1405,7 +1491,7 @@ static int aac_read(struct scsi_cmnd * s
 	return 0;
 }
 
-static int aac_write(struct scsi_cmnd * scsicmd, int cid)
+static int aac_write(struct scsi_cmnd * scsicmd)
 {
 	u64 lba;
 	u32 count;
@@ -1424,7 +1510,7 @@ static int aac_write(struct scsi_cmnd * 
 		if (count == 0)
 			count = 256;
 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
-		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = 	((u64)scsicmd->cmnd[2] << 56) |
 			((u64)scsicmd->cmnd[3] << 48) |
@@ -1436,14 +1522,14 @@ static int aac_write(struct scsi_cmnd * 
 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
 	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
-		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
 
 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
 		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
 		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 	} else {
-		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
 		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
@@ -1488,7 +1574,9 @@ static void synchronize_callback(void *c
 	struct scsi_cmnd *cmd;
 
 	cmd = context;
-	cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	if (!aac_valid_context(cmd, fibptr))
+		return;
 
 	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 
 				smp_processor_id(), jiffies));
@@ -1523,7 +1611,7 @@ static void synchronize_callback(void *c
 	cmd->scsi_done(cmd);
 }
 
-static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+static int aac_synchronize(struct scsi_cmnd *scsicmd)
 {
 	int status;
 	struct fib *cmd_fibcontext;
@@ -1568,7 +1656,7 @@ static int aac_synchronize(struct scsi_c
 	synchronizecmd = fib_data(cmd_fibcontext);
 	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
 	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
-	synchronizecmd->cid = cpu_to_le32(cid);
+	synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
 	synchronizecmd->count = 
 	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
 
@@ -1646,29 +1734,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
 				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)
-						fsa_dev_ptr[cid].valid = 0;
-					spin_lock_irq(host->host_lock);
-					if (fsa_dev_ptr[cid].valid == 0) {
-						scsicmd->result = DID_NO_CONNECT << 16;
-						scsicmd->scsi_done(scsicmd);
-						return 0;
-					}
+					return _aac_probe_container(scsicmd,
+							aac_probe_container_callback2);
 				default:
 					break;
 				}
 			}
-			/*
-			 *	If the target container still doesn't exist, 
-			 *	return failure
-			 */
-			if (fsa_dev_ptr[cid].valid == 0) {
-				scsicmd->result = DID_BAD_TARGET << 16;
-				scsicmd->scsi_done(scsicmd);
-				return 0;
-			}
 		} else {  /* check for physical non-dasd devices */
 			if ((dev->nondasd_support == 1) || expose_physicals) {
 				if (dev->in_reset)
@@ -1733,7 +1804,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
 		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));
-		return aac_get_container_name(scsicmd, cid);
+		return aac_get_container_name(scsicmd);
 	}
 	case SERVICE_ACTION_IN:
 		if (!(dev->raw_io_interface) ||
@@ -1899,7 +1970,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
 			  	min(sizeof(fsa_dev_ptr[cid].devname),
 				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
 
-			return aac_read(scsicmd, cid);
+			return aac_read(scsicmd);
 
 		case WRITE_6:
 		case WRITE_10:
@@ -1907,11 +1978,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsi
 		case WRITE_16:
 			if (dev->in_reset)
 				return -1;
-			return aac_write(scsicmd, cid);
+			return aac_write(scsicmd);
 
 		case SYNCHRONIZE_CACHE:
 			/* Issue FIB to tell Firmware to flush it's cache */
-			return aac_synchronize(scsicmd, cid);
+			return aac_synchronize(scsicmd);
 			
 		default:
 			/*
@@ -2058,7 +2129,10 @@ static void aac_srb_callback(void *conte
 	struct scsi_cmnd *scsicmd;
 
 	scsicmd = (struct scsi_cmnd *) context;
-	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+	if (!aac_valid_context(scsicmd, fibptr))
+		return;
+
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 
 	BUG_ON(fibptr == NULL);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 39ecd0d..45ca3e8 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@ #include <linux/interrupt.h>
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2423
-# define AAC_DRIVER_BRANCH "-mh3"
+# define AAC_DRIVER_BUILD 2437
+# define AAC_DRIVER_BRANCH "-mh4"
 #endif
 #define MAXIMUM_NUM_CONTAINERS	32
 
@@ -48,49 +48,13 @@ struct diskparm
 
 
 /*
- *	DON'T CHANGE THE ORDER, this is set by the firmware
+ *	Firmware constants
  */
  
 #define		CT_NONE			0
-#define		CT_VOLUME		1
-#define		CT_MIRROR		2
-#define		CT_STRIPE		3
-#define		CT_RAID5		4
-#define		CT_SSRW			5
-#define		CT_SSRO			6
-#define		CT_MORPH		7
-#define		CT_PASSTHRU		8
-#define		CT_RAID4		9
-#define		CT_RAID10		10	/* stripe of mirror */
-#define		CT_RAID00		11	/* stripe of stripe */
-#define		CT_VOLUME_OF_MIRRORS	12	/* volume of mirror */
-#define		CT_PSEUDO_RAID		13	/* really raid4 */
-#define		CT_LAST_VOLUME_TYPE	14
 #define 	CT_OK        		218
-
-/*
- *	Types of objects addressable in some fashion by the client.
- *	This is a superset of those objects handled just by the filesystem
- *	and includes "raw" objects that an administrator would use to
- *	configure containers and filesystems.
- */
-
-#define		FT_REG		1	/* regular file */
-#define		FT_DIR		2	/* directory */
-#define		FT_BLK		3	/* "block" device - reserved */
-#define		FT_CHR		4	/* "character special" device - reserved */
-#define		FT_LNK		5	/* symbolic link */
-#define		FT_SOCK		6	/* socket */
-#define		FT_FIFO		7	/* fifo */
 #define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
 #define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
-#define		FT_SLICE	10	/* virtual disk - raw volume - slice */
-#define		FT_PARTITION	11	/* FSA partition - carved out of a slice - building block for containers */
-#define		FT_VOLUME	12	/* Container - Volume Set */
-#define		FT_STRIPE	13	/* Container - Stripe Set */
-#define		FT_MIRROR	14	/* Container - Mirror Set */
-#define		FT_RAID5	15	/* Container - Raid 5 Set */
-#define		FT_DATABASE	16	/* Storage object with "foreign" content manager */
 
 /*
  *	Host side memory scatter gather list
@@ -497,6 +461,7 @@ struct adapter_ops
 	void (*adapter_enable_int)(struct aac_dev *dev);
 	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_restart)(struct aac_dev *dev, int bled);
 	/* Transport operations */
 	int  (*adapter_ioremap)(struct aac_dev * dev, u32 size);
 	irqreturn_t (*adapter_intr)(int irq, void *dev_id);
@@ -833,7 +798,7 @@ struct fib {
 	 */
 	struct list_head	fiblink;
 	void 			*data;
-	struct hw_fib		*hw_fib;		/* Actual shared object */
+	struct hw_fib		*hw_fib_va;		/* Actual shared object */
 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
 };
 
@@ -878,10 +843,25 @@ struct aac_supplement_adapter_info
 	__le32	Version;
 	__le32	FeatureBits;
 	u8	SlotNumber;
-	u8	ReservedPad0[0];
+	u8	ReservedPad0[3];
 	u8	BuildDate[12];
 	__le32	CurrentNumberPorts;
-	__le32	ReservedGrowth[24];
+	struct {
+		u8	AssemblyPn[8];
+		u8	FruPn[8];
+		u8	BatteryFruPn[8];
+		u8	EcVersionString[8];
+		u8	Tsid[12];
+	}	VpdInfo;
+	__le32	FlashFirmwareRevision;
+	__le32	FlashFirmwareBuild;
+	__le32	RaidTypeMorphOptions;
+	__le32	FlashFirmwareBootRevision;
+	__le32	FlashFirmwareBootBuild;
+	u8	MfgPcbaSerialNo[12];
+	u8	MfgWWNName[8];
+	__le32	MoreFeatureBits;
+	__le32	ReservedGrowth[1];
 };
 #define AAC_FEATURE_FALCON	0x00000010
 #define AAC_SIS_VERSION_V3	3
@@ -970,7 +950,6 @@ struct aac_dev
 	struct fib              *fibs;
 
 	struct fib		*free_fib;
-	struct fib		*timeout_fib;
 	spinlock_t		fib_lock;
 	
 	struct aac_queue_block *queues;
@@ -1060,6 +1039,9 @@ #define aac_adapter_sync_cmd(dev, comman
 #define aac_adapter_check_health(dev) \
 	(dev)->a_ops.adapter_check_health(dev)
 
+#define aac_adapter_restart(dev,bled) \
+	(dev)->a_ops.adapter_restart(dev,bled)
+
 #define aac_adapter_ioremap(dev, size) \
 	(dev)->a_ops.adapter_ioremap(dev, size)
 
@@ -1516,8 +1498,7 @@ struct aac_mntent {
 	struct creation_info	create_info;	/* if applicable */
 	__le32			capacity;
 	__le32			vol;    	/* substrate structure */
-	__le32			obj;	        /* FT_FILESYS, 
-						   FT_DATABASE, etc. */
+	__le32			obj;	        /* FT_FILESYS, etc. */
 	__le32			state;		/* unready for mounting, 
 						   readonly, etc. */
 	union aac_contentinfo	fileinfo;	/* Info specific to content 
@@ -1817,7 +1798,7 @@ int aac_fib_send(u16 command, struct fib
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
 void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
 int aac_fib_complete(struct fib * context);
-#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
+#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
 struct aac_dev *aac_init_adapter(struct aac_dev *dev);
 int aac_get_config_status(struct aac_dev *dev, int commit_flag);
 int aac_get_containers(struct aac_dev *dev);
@@ -1840,8 +1821,11 @@ struct aac_driver_ident* aac_get_driver_
 int aac_get_adapter_info(struct aac_dev* dev);
 int aac_send_shutdown(struct aac_dev *dev);
 int aac_probe_container(struct aac_dev *dev, int cid);
+int _aac_rx_init(struct aac_dev *dev);
+int aac_rx_select_comm(struct aac_dev *dev, int comm);
 extern int numacb;
 extern int acbsize;
 extern char aac_driver_version[];
 extern int startup_timeout;
 extern int aif_timeout;
+extern int expose_physicals;
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index e21070f..72b0393 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -64,12 +64,15 @@ static int ioctl_send_fib(struct aac_dev
 	unsigned size;
 	int retval;
 
+	if (dev->in_reset) {
+		return -EBUSY;
+	}
 	fibptr = aac_fib_alloc(dev);
 	if(fibptr == NULL) {
 		return -ENOMEM;
 	}
 		
-	kfib = fibptr->hw_fib;
+	kfib = fibptr->hw_fib_va;
 	/*
 	 *	First copy in the header so that we can check the size field.
 	 */
@@ -91,9 +94,9 @@ static int ioctl_send_fib(struct aac_dev
 			goto cleanup;
 		}
 		/* Highjack the hw_fib */
-		hw_fib = fibptr->hw_fib;
+		hw_fib = fibptr->hw_fib_va;
 		hw_fib_pa = fibptr->hw_fib_pa;
-		fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
+		fibptr->hw_fib_va = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
 		memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);
 		memcpy(kfib, hw_fib, dev->max_fib_size);
 	}
@@ -137,7 +140,7 @@ cleanup:
 	if (hw_fib) {
 		pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);
 		fibptr->hw_fib_pa = hw_fib_pa;
-		fibptr->hw_fib = hw_fib;
+		fibptr->hw_fib_va = hw_fib;
 	}
 	if (retval != -EINTR)
 		aac_fib_free(fibptr);
@@ -282,15 +285,15 @@ return_fib:
 		fib = list_entry(entry, struct fib, fiblink);
 		fibctx->count--;
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
-			kfree(fib->hw_fib);
+		if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) {
+			kfree(fib->hw_fib_va);
 			kfree(fib);
 			return -EFAULT;
 		}	
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(fib->hw_fib);
+		kfree(fib->hw_fib_va);
 		kfree(fib);
 		status = 0;
 	} else {
@@ -340,7 +343,7 @@ int aac_close_fib_context(struct aac_dev
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(fib->hw_fib);
+		kfree(fib->hw_fib_va);
 		kfree(fib);
 	}
 	/*
@@ -388,10 +391,8 @@ static int close_getadapter_fib(struct a
 		/*
 		 *	Extract the fibctx from the input parameters
 		 */
-		if (fibctx->unique == (u32)(unsigned long)arg) {   
-			/* We found a winner */
+		if (fibctx->unique == (u32)(ptrdiff_t)arg) /* We found a winner */
 			break;
-		}
 		entry = entry->next;
 		fibctx = NULL;
 	}
@@ -465,16 +466,20 @@ static int aac_send_raw_srb(struct aac_d
 	void *sg_list[32];
 	u32   sg_indx = 0;
 	u32 byte_count = 0;
-	u32 actual_fibsize = 0;
+	u32 actual_fibsize64, actual_fibsize = 0;
 	int i;
 
 
+	if (dev->in_reset) {
+		dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n"));
+		return -EBUSY;
+	}
 	if (!capable(CAP_SYS_ADMIN)){
 		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
 		return -EPERM;
 	}
 	/*
-	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 *	Allocate and initialize a Fib then setup a SRB command
 	 */
 	if (!(srbfib = aac_fib_alloc(dev))) {
 		return -ENOMEM;
@@ -541,129 +546,183 @@ static int aac_send_raw_srb(struct aac_d
 		rcode = -EINVAL;
 		goto cleanup;
 	}
-	if (dev->dac_support == 1) {
+	actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) +
+		((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry));
+	actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) *
+	  (sizeof(struct sgentry64) - sizeof(struct sgentry));
+	/* User made a mistake - should not continue */
+	if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) {
+		dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+		  "Raw SRB command calculated fibsize=%lu;%lu "
+		  "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu "
+		  "issued fibsize=%d\n",
+		  actual_fibsize, actual_fibsize64, user_srbcmd->sg.count,
+		  sizeof(struct aac_srb), sizeof(struct sgentry),
+		  sizeof(struct sgentry64), fibsize));
+		rcode = -EINVAL;
+		goto cleanup;
+	}
+	if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
+		dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
+		rcode = -EINVAL;
+		goto cleanup;
+	}
+	byte_count = 0;
+	if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
 		struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
 		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
-		struct user_sgmap* usg;
-		byte_count = 0;
 
 		/*
 		 * This should also catch if user used the 32 bit sgmap
 		 */
-		actual_fibsize = sizeof(struct aac_srb) - 
-			sizeof(struct sgentry) +
-			((upsg->count & 0xff) * 
-		 	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"));
-			rcode = -EINVAL;
-			goto cleanup;
-		}
-		usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
-		  + sizeof(struct sgmap), GFP_KERNEL);
-		if (!usg) {
-			dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
-			rcode = -ENOMEM;
-			goto cleanup;
-		}
-		memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
-		  + sizeof(struct sgmap));
-		actual_fibsize = sizeof(struct aac_srb) - 
-			sizeof(struct sgentry) + ((usg->count & 0xff) * 
-			 	sizeof(struct sgentry64));
-		if ((data_dir == DMA_NONE) && upsg->count) {
-			kfree (usg);
-			dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
-			rcode = -EINVAL;
-			goto cleanup;
-		}
+		if (actual_fibsize64 == fibsize) {
+			actual_fibsize = actual_fibsize64;
+			for (i = 0; i < upsg->count; i++) {
+				u64 addr;
+				void* p;
+				/* Does this really need to be GFP_DMA? */
+				p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+				if(p == 0) {
+					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+					  upsg->sg[i].count,i,upsg->count));
+					rcode = -ENOMEM;
+					goto cleanup;
+				}
+				addr = (u64)upsg->sg[i].addr[0];
+				addr += ((u64)upsg->sg[i].addr[1]) << 32;
+				sg_user[i] = (void __user *)(ptrdiff_t)addr;
+				sg_list[i] = p; // save so we can clean up later
+				sg_indx = i;
+
+				if( flags & SRB_DataOut ){
+					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+						rcode = -EFAULT;
+						goto cleanup;
+					}
+				}
+				addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir);
 
-		for (i = 0; i < usg->count; i++) {
-			u64 addr;
-			void* p;
-			/* Does this really need to be GFP_DMA? */
-			p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-			if(p == 0) {
-				kfree (usg);
-				dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-				  usg->sg[i].count,i,usg->count));
+				psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+				psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+				byte_count += upsg->sg[i].count;
+				psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+			}
+		} else {
+			struct user_sgmap* usg;
+			usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
+			  + sizeof(struct sgmap), GFP_KERNEL);
+			if (!usg) {
+				dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
 				rcode = -ENOMEM;
 				goto cleanup;
 			}
-			sg_user[i] = (void __user *)(long)usg->sg[i].addr;
-			sg_list[i] = p; // save so we can clean up later
-			sg_indx = i;
-
-			if( flags & SRB_DataOut ){
-				if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+			memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
+			  + sizeof(struct sgmap));
+			actual_fibsize = actual_fibsize64;
+
+			for (i = 0; i < usg->count; i++) {
+				u64 addr;
+				void* p;
+				/* Does this really need to be GFP_DMA? */
+				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+				if(p == 0) {
 					kfree (usg);
-					dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 
-					rcode = -EFAULT;
+					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+					  usg->sg[i].count,i,usg->count));
+					rcode = -ENOMEM;
 					goto cleanup;
 				}
-			}
-			addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+				sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr;
+				sg_list[i] = p; // save so we can clean up later
+				sg_indx = i;
+
+				if( flags & SRB_DataOut ){
+					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+						kfree (usg);
+						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+						rcode = -EFAULT;
+						goto cleanup;
+					}
+				}
+				addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
 
-			psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
-			psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
-			psg->sg[i].count = cpu_to_le32(usg->sg[i].count);  
-			byte_count += usg->sg[i].count;
+				psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+				psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+				byte_count += usg->sg[i].count;
+				psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
+			}
+			kfree (usg);
 		}
-		kfree (usg);
-
 		srbcmd->count = cpu_to_le32(byte_count);
 		psg->count = cpu_to_le32(sg_indx+1);
 		status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
 	} else {
 		struct user_sgmap* upsg = &user_srbcmd->sg;
 		struct sgmap* psg = &srbcmd->sg;
-		byte_count = 0;
-
-		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 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;
-		}
-		if ((data_dir == DMA_NONE) && upsg->count) {
-			dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
-			rcode = -EINVAL;
-			goto cleanup;
-		}
-		for (i = 0; i < upsg->count; i++) {
-			dma_addr_t addr; 
-			void* p;
-			p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
-			if(p == 0) {
-				dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-				  upsg->sg[i].count, i, upsg->count));
-				rcode = -ENOMEM;
-				goto cleanup;
-			}
-			sg_user[i] = (void __user *)(long)upsg->sg[i].addr;
-			sg_list[i] = p; // save so we can clean up later
-			sg_indx = i;
-
-			if( flags & SRB_DataOut ){
-				if(copy_from_user(p, sg_user[i],
-						upsg->sg[i].count)) {
-					dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); 
-					rcode = -EFAULT;
+
+		if (actual_fibsize64 == fibsize) {
+			struct user_sgmap64* usg = (struct user_sgmap64 *)upsg;
+			for (i = 0; i < upsg->count; i++) {
+				u64 addr;
+				void* p;
+				/* Does this really need to be GFP_DMA? */
+				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+				if(p == 0) {
+					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+					  usg->sg[i].count,i,usg->count));
+					rcode = -ENOMEM;
 					goto cleanup;
 				}
+				addr = (u64)usg->sg[i].addr[0];
+				addr += ((u64)usg->sg[i].addr[1]) << 32;
+				sg_user[i] = (void __user *)(ptrdiff_t)addr;
+				sg_list[i] = p; // save so we can clean up later
+				sg_indx = i;
+
+				if( flags & SRB_DataOut ){
+					if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
+						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+						rcode = -EFAULT;
+						goto cleanup;
+					}
+				}
+				addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+
+				psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff);
+				byte_count += usg->sg[i].count;
+				psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
 			}
-			addr = pci_map_single(dev->pdev, p,
-				upsg->sg[i].count, data_dir);
+		} else {
+			for (i = 0; i < upsg->count; i++) {
+				dma_addr_t addr;
+				void* p;
+				p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
+				if(p == 0) {
+					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+					  upsg->sg[i].count, i, upsg->count));
+					rcode = -ENOMEM;
+					goto cleanup;
+				}
+				sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr;
+				sg_list[i] = p; // save so we can clean up later
+				sg_indx = i;
+
+				if( flags & SRB_DataOut ){
+					if(copy_from_user(p, sg_user[i],
+							upsg->sg[i].count)) {
+						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+						rcode = -EFAULT;
+						goto cleanup;
+					}
+				}
+				addr = pci_map_single(dev->pdev, p,
+					upsg->sg[i].count, data_dir);
 
-			psg->sg[i].addr = cpu_to_le32(addr);
-			psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);  
-			byte_count += upsg->sg[i].count;
+				psg->sg[i].addr = cpu_to_le32(addr);
+				byte_count += upsg->sg[i].count;
+				psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+			}
 		}
 		srbcmd->count = cpu_to_le32(byte_count);
 		psg->count = cpu_to_le32(sg_indx+1);
@@ -682,7 +741,8 @@ static int aac_send_raw_srb(struct aac_d
 
 	if( flags & SRB_DataIn ) {
 		for(i = 0 ; i <= sg_indx; i++){
-			byte_count = le32_to_cpu((dev->dac_support == 1)
+			byte_count = le32_to_cpu(
+			  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
 			      ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
 			      : srbcmd->sg.sg[i].count);
 			if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index ae34768..33682ce 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -110,7 +110,7 @@ static int aac_alloc_comm(struct aac_dev
 	/*
 	 *	Align the beginning of Headers to commalign
 	 */
-	align = (commalign - ((unsigned long)(base) & (commalign - 1)));
+	align = (commalign - ((ptrdiff_t)(base) & (commalign - 1)));
 	base = base + align;
 	phys = phys + align;
 	/*
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 1b97f60..5824a75 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -94,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *de
 int aac_fib_setup(struct aac_dev * dev)
 {
 	struct fib *fibptr;
-	struct hw_fib *hw_fib_va;
+	struct hw_fib *hw_fib;
 	dma_addr_t hw_fib_pa;
 	int i;
 
@@ -106,24 +106,24 @@ int aac_fib_setup(struct aac_dev * dev)
 	if (i<0)
 		return -ENOMEM;
 		
-	hw_fib_va = dev->hw_fib_va;
+	hw_fib = dev->hw_fib_va;
 	hw_fib_pa = dev->hw_fib_pa;
-	memset(hw_fib_va, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+	memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
 	/*
 	 *	Initialise the fibs
 	 */
 	for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
 	{
 		fibptr->dev = dev;
-		fibptr->hw_fib = hw_fib_va;
-		fibptr->data = (void *) fibptr->hw_fib->data;
+		fibptr->hw_fib_va = hw_fib;
+		fibptr->data = (void *) fibptr->hw_fib_va->data;
 		fibptr->next = fibptr+1;	/* Forward chain the fibs */
 		init_MUTEX_LOCKED(&fibptr->event_wait);
 		spin_lock_init(&fibptr->event_lock);
-		hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
-		hw_fib_va->header.SenderSize = cpu_to_le16(dev->max_fib_size);
+		hw_fib->header.XferState = cpu_to_le32(0xffffffff);
+		hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
 		fibptr->hw_fib_pa = hw_fib_pa;
-		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + dev->max_fib_size);
+		hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size);
 		hw_fib_pa = hw_fib_pa + dev->max_fib_size;
 	}
 	/*
@@ -166,7 +166,7 @@ struct fib *aac_fib_alloc(struct aac_dev
 	 *	Null out fields that depend on being zero at the start of
 	 *	each I/O
 	 */
-	fibptr->hw_fib->header.XferState = 0;
+	fibptr->hw_fib_va->header.XferState = 0;
 	fibptr->callback = NULL;
 	fibptr->callback_data = NULL;
 
@@ -178,7 +178,6 @@ struct fib *aac_fib_alloc(struct aac_dev
  *	@fibptr: fib to free up
  *
  *	Frees up a fib and places it on the appropriate queue
- *	(either free or timed out)
  */
  
 void aac_fib_free(struct fib *fibptr)
@@ -186,19 +185,15 @@ void aac_fib_free(struct fib *fibptr)
 	unsigned long flags;
 
 	spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
-	if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+	if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
 		aac_config.fib_timeouts++;
-		fibptr->next = fibptr->dev->timeout_fib;
-		fibptr->dev->timeout_fib = fibptr;
-	} else {
-		if (fibptr->hw_fib->header.XferState != 0) {
-			printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
-				 (void*)fibptr, 
-				 le32_to_cpu(fibptr->hw_fib->header.XferState));
-		}
-		fibptr->next = fibptr->dev->free_fib;
-		fibptr->dev->free_fib = fibptr;
-	}	
+	if (fibptr->hw_fib_va->header.XferState != 0) {
+		printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
+			 (void*)fibptr,
+			 le32_to_cpu(fibptr->hw_fib_va->header.XferState));
+	}
+	fibptr->next = fibptr->dev->free_fib;
+	fibptr->dev->free_fib = fibptr;
 	spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
 }
 
@@ -211,7 +206,7 @@ void aac_fib_free(struct fib *fibptr)
  
 void aac_fib_init(struct fib *fibptr)
 {
-	struct hw_fib *hw_fib = fibptr->hw_fib;
+	struct hw_fib *hw_fib = fibptr->hw_fib_va;
 
 	hw_fib->header.StructType = FIB_MAGIC;
 	hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size);
@@ -231,7 +226,7 @@ void aac_fib_init(struct fib *fibptr)
  
 static void fib_dealloc(struct fib * fibptr)
 {
-	struct hw_fib *hw_fib = fibptr->hw_fib;
+	struct hw_fib *hw_fib = fibptr->hw_fib_va;
 	BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
 	hw_fib->header.XferState = 0;        
 }
@@ -386,7 +381,7 @@ int aac_fib_send(u16 command, struct fib
 		void *callback_data)
 {
 	struct aac_dev * dev = fibptr->dev;
-	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib_va;
 	unsigned long flags = 0;
 	unsigned long qflags;
 
@@ -430,7 +425,7 @@ int aac_fib_send(u16 command, struct fib
 	 */
 	hw_fib->header.Command = cpu_to_le16(command);
 	hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
-	fibptr->hw_fib->header.Flags = 0;	/* 0 the flags field - internal only*/
+	fibptr->hw_fib_va->header.Flags = 0;	/* 0 the flags field - internal only*/
 	/*
 	 *	Set the size of the Fib we want to send to the adapter
 	 */
@@ -462,7 +457,7 @@ int aac_fib_send(u16 command, struct fib
 	dprintk((KERN_DEBUG "  Command =               %d.\n", le32_to_cpu(hw_fib->header.Command)));
 	dprintk((KERN_DEBUG "  SubCommand =            %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command)));
 	dprintk((KERN_DEBUG "  XferState  =            %x.\n", le32_to_cpu(hw_fib->header.XferState)));
-	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
+	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib_va));
 	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
 	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
 
@@ -513,22 +508,20 @@ int aac_fib_send(u16 command, struct fib
 				}
 				udelay(5);
 			}
-		} 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;
-			}
+		} else
+			(void)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)){
+		if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
 			return -ETIMEDOUT;
-		} else {
-			return 0;
-		}
+		return 0;
 	}
 	/*
 	 *	If the user does not want a response than return success otherwise
@@ -624,7 +617,7 @@ void aac_consumer_free(struct aac_dev * 
 
 int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
 {
-	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib_va;
 	struct aac_dev * dev = fibptr->dev;
 	struct aac_queue * q;
 	unsigned long nointr = 0;
@@ -688,7 +681,7 @@ int aac_fib_adapter_complete(struct fib 
  
 int aac_fib_complete(struct fib *fibptr)
 {
-	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib_va;
 
 	/*
 	 *	Check for a fib which has already been completed
@@ -774,9 +767,8 @@ void aac_printf(struct aac_dev *dev, u32
 #define AIF_SNIFF_TIMEOUT	(30*HZ)
 static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 {
-	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib_va;
 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
-	int busy;
 	u32 container;
 	struct scsi_device *device;
 	enum {
@@ -988,9 +980,6 @@ static void aac_handle_aif(struct aac_de
 	 * behind you.
 	 */
 
-	busy = 0;
-
-
 	/*
 	 *	Find the scsi_device associated with the SCSI address,
 	 * and mark it as changed, invalidating the cache. This deals
@@ -1035,7 +1024,6 @@ 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;
@@ -1059,35 +1047,29 @@ static int _aac_reset_adapter(struct aac
 	 *	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);
+	retval = aac_adapter_restart(aac, aac_adapter_check_health(aac));
 
 	if (retval)
 		goto out;
-	if (ret != 0x00000001) {
-		retval = -ENODEV;
-		goto out;
-	}
 
 	/*
 	 *	Loop through the fibs, close the synchronous FIBS
 	 */
-	for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+	for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
 		struct fib *fib = &aac->fibs[index];
-		if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
-		  (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) {
+		if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+		  (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) {
 			unsigned long flagv;
 			spin_lock_irqsave(&fib->event_lock, flagv);
 			up(&fib->event_wait);
 			spin_unlock_irqrestore(&fib->event_lock, flagv);
 			schedule();
+			retval = 0;
 		}
 	}
+	/* Give some extra time for ioctls to complete. */
+	if (retval == 0)
+		ssleep(2);
 	index = aac->cardtype;
 
 	/*
@@ -1248,7 +1230,7 @@ int aac_check_health(struct aac_dev * aa
 
 			memset(hw_fib, 0, sizeof(struct hw_fib));
 			memset(fib, 0, sizeof(struct fib));
-			fib->hw_fib = hw_fib;
+			fib->hw_fib_va = hw_fib;
 			fib->dev = aac;
 			aac_fib_init(fib);
 			fib->type = FSAFS_NTC_FIB_CONTEXT;
@@ -1354,11 +1336,11 @@ int aac_command_thread(void *data)
 			 *	do anything at this point since we don't have
 			 *	anything defined for this thread to do.
 			 */
-			hw_fib = fib->hw_fib;
+			hw_fib = fib->hw_fib_va;
 			memset(fib, 0, sizeof(struct fib));
 			fib->type = FSAFS_NTC_FIB_CONTEXT;
 			fib->size = sizeof( struct fib );
-			fib->hw_fib = hw_fib;
+			fib->hw_fib_va = hw_fib;
 			fib->data = hw_fib->data;
 			fib->dev = dev;
 			/*
@@ -1485,7 +1467,7 @@ int aac_command_thread(void *data)
 						 */
 						memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
 						memcpy(newfib, fib, sizeof(struct fib));
-						newfib->hw_fib = hw_newfib;
+						newfib->hw_fib_va = hw_newfib;
 						/*
 						 * Put the FIB onto the
 						 * fibctx's fibs
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index d38b628..42c7dcd 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -32,7 +32,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
@@ -73,7 +72,7 @@ unsigned int aac_response_normal(struct 
 		u32 index = le32_to_cpu(entry->addr);
 		fast = index & 0x01;
 		fib = &dev->fibs[index >> 2];
-		hwfib = fib->hw_fib;
+		hwfib = fib->hw_fib_va;
 		
 		aac_consumer_free(dev, q, HostNormRespQueue);
 		/*
@@ -84,11 +83,13 @@ unsigned int aac_response_normal(struct 
 		 *	continue. The caller has already been notified that
 		 *	the fib timed out.
 		 */
-		if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
-			dev->queues->queue[AdapNormCmdQueue].numpending--;
-		else {
-			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
-			printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+		dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			spin_unlock_irqrestore(q->lock, flags);
+			aac_fib_complete(fib);
+			aac_fib_free(fib);
+			spin_lock_irqsave(q->lock, flags);
 			continue;
 		}
 		spin_unlock_irqrestore(q->lock, flags);
@@ -193,7 +194,7 @@ unsigned int aac_command_normal(struct a
 		INIT_LIST_HEAD(&fib->fiblink);
 		fib->type = FSAFS_NTC_FIB_CONTEXT;
 		fib->size = sizeof(struct fib);
-		fib->hw_fib = hw_fib;
+		fib->hw_fib_va = hw_fib;
 		fib->data = hw_fib->data;
 		fib->dev = dev;
 		
@@ -254,12 +255,13 @@ unsigned int aac_intr_normal(struct aac_
 			return 1;
 		}
 		memset(hw_fib, 0, sizeof(struct hw_fib));
-		memcpy(hw_fib, (struct hw_fib *)(((unsigned long)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib));
+		memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
+		  (index & ~0x00000002L)), sizeof(struct hw_fib));
 		memset(fib, 0, sizeof(struct fib));
 		INIT_LIST_HEAD(&fib->fiblink);
 		fib->type = FSAFS_NTC_FIB_CONTEXT;
 		fib->size = sizeof(struct fib);
-		fib->hw_fib = hw_fib;
+		fib->hw_fib_va = hw_fib;
 		fib->data = hw_fib->data;
 		fib->dev = dev;
 	
@@ -271,7 +273,7 @@ unsigned int aac_intr_normal(struct aac_
 	} else {
 		int fast = index & 0x01;
 		struct fib * fib = &dev->fibs[index >> 2];
-		struct hw_fib * hwfib = fib->hw_fib;
+		struct hw_fib * hwfib = fib->hw_fib_va;
 
 		/*
 		 *	Remove this fib from the Outstanding I/O queue.
@@ -281,14 +283,14 @@ unsigned int aac_intr_normal(struct aac_
 		 *	continue. The caller has already been notified that
 		 *	the fib timed out.
 		 */
-		if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
-			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
-			printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+		dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+		if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			aac_fib_complete(fib);
+			aac_fib_free(fib);
 			return 0;
 		}
 
-		dev->queues->queue[AdapNormCmdQueue].numpending--;
-
 		if (fast) {
 			/*
 			 *	Doctor the fib
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 0f948c2..350ea7f 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -82,8 +82,6 @@ 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.
@@ -247,7 +245,19 @@ static struct aac_driver_ident aac_drive
 
 static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
+	struct Scsi_Host *host = cmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+	u32 count = 0;
 	cmd->scsi_done = done;
+	for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+		struct fib * fib = &dev->fibs[count];
+		struct scsi_cmnd * command;
+		if (fib->hw_fib_va->header.XferState &&
+		    ((command = fib->callback_data)) &&
+		    (command == cmd) &&
+		    (cmd->SCp.phase == AAC_OWNER_FIRMWARE))
+			return 0; /* Already owned by Adapter */
+	}
 	cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
 	return (aac_scsi_cmd(cmd) ? FAILED : 0);
 } 
@@ -446,6 +456,40 @@ static int aac_ioctl(struct scsi_device 
 	return aac_do_ioctl(dev, cmd, arg);
 }
 
+static int aac_eh_abort(struct scsi_cmnd* cmd)
+{
+	struct scsi_device * dev = cmd->device;
+	struct Scsi_Host * host = dev->host;
+	struct aac_dev * aac = (struct aac_dev *)host->hostdata;
+	int count;
+	int ret = FAILED;
+
+	printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n",
+		AAC_DRIVERNAME,
+		host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
+	switch (cmd->cmnd[0]) {
+	case SERVICE_ACTION_IN:
+		if (!(aac->raw_io_interface) ||
+		    !(aac->raw_io_64) ||
+		    ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+			break;
+	case INQUIRY:
+	case READ_CAPACITY:
+	case TEST_UNIT_READY:
+		/* Mark associated FIB to not complete, eh handler does this */
+		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+			struct fib * fib = &aac->fibs[count];
+			if (fib->hw_fib_va->header.XferState &&
+			  (fib->callback_data == cmd)) {
+				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+				cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+				ret = SUCCESS;
+			}
+		}
+	}
+	return ret;
+}
+
 /*
  *	aac_eh_reset	- Reset command handling
  *	@scsi_cmd:	SCSI command block causing the reset
@@ -457,12 +501,20 @@ static int aac_eh_reset(struct scsi_cmnd
 	struct Scsi_Host * host = dev->host;
 	struct scsi_cmnd * command;
 	int count;
-	struct aac_dev * aac;
+	struct aac_dev * aac = (struct aac_dev *)host->hostdata;
 	unsigned long flags;
 
+	/* Mark the associated FIB to not complete, eh handler does this */
+	for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+		struct fib * fib = &aac->fibs[count];
+		if (fib->hw_fib_va->header.XferState &&
+		  (fib->callback_data == cmd)) {
+			fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+			cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+		}
+	}
 	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
 					AAC_DRIVERNAME);
-	aac = (struct aac_dev *)host->hostdata;
 
 	if ((count = aac_check_health(aac)))
 		return count;
@@ -496,7 +548,7 @@ static int aac_eh_reset(struct scsi_cmnd
 		ssleep(1);
 	}
 	printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
-	return -ETIMEDOUT;
+	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
 }
 
 /**
@@ -796,6 +848,7 @@ #endif
 	.bios_param     		= aac_biosparm,	
 	.shost_attrs			= aac_attrs,
 	.slave_configure		= aac_slave_configure,
+	.eh_abort_handler		= aac_eh_abort,
 	.eh_host_reset_handler		= aac_eh_reset,
 	.can_queue      		= AAC_NUM_IO_FIB,	
 	.this_id        		= MAXIMUM_NUM_CONTAINERS,
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index c76b611..a8ace56 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -74,9 +74,6 @@ static int aac_nark_ioremap(struct aac_d
 
 int aac_nark_init(struct aac_dev * dev)
 {
-	extern int _aac_rx_init(struct aac_dev *dev);
-	extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
-
 	/*
 	 *	Fill in the function dispatch table.
 	 */
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index d953c3f..9c5fcfb 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -45,7 +45,6 @@ #define AAC_NUM_IO_FIB_RKT      (246 - A
 static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
 {
 	int retval;
-	extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
 	retval = aac_rx_select_comm(dev, comm);
 	if (comm == AAC_COMM_MESSAGE) {
 		/*
@@ -97,8 +96,6 @@ static int aac_rkt_ioremap(struct aac_de
 
 int aac_rkt_init(struct aac_dev *dev)
 {
-	extern int _aac_rx_init(struct aac_dev *dev);
-
 	/*
 	 *	Fill in the function dispatch table.
 	 */
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index d242e26..0c71315 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -57,25 +57,25 @@ static irqreturn_t aac_rx_intr_producer(
 	 *	been enabled.
 	 *	Check to see if this is our interrupt.  If it isn't just return
 	 */
-	if (intstat & ~(dev->OIMR)) {
+	if (likely(intstat & ~(dev->OIMR))) {
 		bellbits = rx_readl(dev, OutboundDoorbellReg);
-		if (bellbits & DoorBellPrintfReady) {
+		if (unlikely(bellbits & DoorBellPrintfReady)) {
 			aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
 			rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
 			rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
 		}
-		else if (bellbits & DoorBellAdapterNormCmdReady) {
+		else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) {
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
 			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
 		}
-		else if (bellbits & DoorBellAdapterNormRespReady) {
+		else if (likely(bellbits & DoorBellAdapterNormRespReady)) {
 			rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
 			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
 		}
-		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+		else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) {
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
 		}
-		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+		else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) {
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
 			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
 		}
@@ -88,11 +88,11 @@ static irqreturn_t aac_rx_intr_message(i
 {
 	struct aac_dev *dev = dev_id;
 	u32 Index = rx_readl(dev, MUnit.OutboundQueue);
-	if (Index == 0xFFFFFFFFL)
+	if (unlikely(Index == 0xFFFFFFFFL))
 		Index = rx_readl(dev, MUnit.OutboundQueue);
-	if (Index != 0xFFFFFFFFL) {
+	if (likely(Index != 0xFFFFFFFFL)) {
 		do {
-			if (aac_intr_normal(dev, Index)) {
+			if (unlikely(aac_intr_normal(dev, Index))) {
 				rx_writel(dev, MUnit.OutboundQueue, Index);
 				rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
 			}
@@ -204,7 +204,7 @@ static int rx_sync_cmd(struct aac_dev *d
 		 */
 		msleep(1);
 	}
-	if (ok != 1) {
+	if (unlikely(ok != 1)) {
 		/*
 		 *	Restore interrupt mask even though we timed out
 		 */
@@ -294,7 +294,7 @@ static void aac_rx_notify_adapter(struct
  *	Start up processing on an i960 based AAC adapter
  */
 
-void aac_rx_start_adapter(struct aac_dev *dev)
+static void aac_rx_start_adapter(struct aac_dev *dev)
 {
 	struct aac_init *init;
 
@@ -319,12 +319,12 @@ static int aac_rx_check_health(struct aa
 	/*
 	 *	Check to see if the board failed any self tests.
 	 */
-	if (status & SELF_TEST_FAILED)
+	if (unlikely(status & SELF_TEST_FAILED))
 		return -1;
 	/*
 	 *	Check to see if the board panic'd.
 	 */
-	if (status & KERNEL_PANIC) {
+	if (unlikely(status & KERNEL_PANIC)) {
 		char * buffer;
 		struct POSTSTATUS {
 			__le32 Post_Command;
@@ -333,15 +333,15 @@ static int aac_rx_check_health(struct aa
 		dma_addr_t paddr, baddr;
 		int ret;
 
-		if ((status & 0xFF000000L) == 0xBC000000L)
+		if (likely((status & 0xFF000000L) == 0xBC000000L))
 			return (status >> 16) & 0xFF;
 		buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
 		ret = -2;
-		if (buffer == NULL)
+		if (unlikely(buffer == NULL))
 			return ret;
 		post = pci_alloc_consistent(dev->pdev,
 		  sizeof(struct POSTSTATUS), &paddr);
-		if (post == NULL) {
+		if (unlikely(post == NULL)) {
 			pci_free_consistent(dev->pdev, 512, buffer, baddr);
 			return ret;
 		}
@@ -353,7 +353,7 @@ static int aac_rx_check_health(struct aa
 		  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'))) {
+		if (likely((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);
@@ -364,7 +364,7 @@ static int aac_rx_check_health(struct aa
 	/*
 	 *	Wait for the adapter to be up and running.
 	 */
-	if (!(status & KERNEL_UP_AND_RUNNING))
+	if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
 		return -3;
 	/*
 	 *	Everything is OK
@@ -387,7 +387,7 @@ static int aac_rx_deliver_producer(struc
 	unsigned long nointr = 0;
 
 	spin_lock_irqsave(q->lock, qflags);
-	aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr);
+	aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr);
 
 	q->numpending++;
 	*(q->headers.producer) = cpu_to_le32(Index + 1);
@@ -419,9 +419,9 @@ static int aac_rx_deliver_message(struct
 	spin_unlock_irqrestore(q->lock, qflags);
 	for(;;) {
 		Index = rx_readl(dev, MUnit.InboundQueue);
-		if (Index == 0xFFFFFFFFL)
+		if (unlikely(Index == 0xFFFFFFFFL))
 			Index = rx_readl(dev, MUnit.InboundQueue);
-		if (Index != 0xFFFFFFFFL)
+		if (likely(Index != 0xFFFFFFFFL))
 			break;
 		if (--count == 0) {
 			spin_lock_irqsave(q->lock, qflags);
@@ -437,7 +437,7 @@ static int aac_rx_deliver_message(struct
 	device += sizeof(u32);
 	writel((u32)(addr >> 32), device);
 	device += sizeof(u32);
-	writel(le16_to_cpu(fib->hw_fib->header.Size), device);
+	writel(le16_to_cpu(fib->hw_fib_va->header.Size), device);
 	rx_writel(dev, MUnit.InboundQueue, Index);
 	return 0;
 }
@@ -460,22 +460,34 @@ static int aac_rx_ioremap(struct aac_dev
 	return 0;
 }
 
-static int aac_rx_restart_adapter(struct aac_dev *dev)
+static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
 {
 	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 (bled)
+		printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+			dev->name, dev->id, bled);
+	else {
+		bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+		  0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+		if (!bled && (var != 0x00000001))
+			bled = -EINVAL;
+	}
+	if (bled && (bled != -ETIMEDOUT))
+		bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+		  0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+
+	if (bled && (bled != -ETIMEDOUT))
+		return -EINVAL;
+	if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
+		rx_writel(dev, MUnit.reserved2, 3);
+		msleep(5000); /* Delay 5 seconds */
+		var = 0x00000001;
+	}
 	if (var != 0x00000001)
-		 return 1;
+		return -EINVAL;
 	if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
-		return 1;
+		return -ENODEV;
 	return 0;
 }
 
@@ -517,24 +529,29 @@ int _aac_rx_init(struct aac_dev *dev)
 {
 	unsigned long start;
 	unsigned long status;
-	int instance;
-	const char * name;
-
-	instance = dev->id;
-	name     = dev->name;
+	int restart = 0;
+	int instance = dev->id;
+	const char * name = dev->name;
 
 	if (aac_adapter_ioremap(dev, dev->base_size)) {
 		printk(KERN_WARNING "%s: unable to map adapter.\n", name);
 		goto error_iounmap;
 	}
 
+	/* Failure to reset here is an option ... */
+	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
+	if ((((status & 0xff) != 0xff) || reset_devices) &&
+	  !aac_rx_restart_adapter(dev, 0))
+		++restart;
 	/*
 	 *	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))
+	if (status & KERNEL_PANIC) {
+		if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
 			goto error_iounmap;
+		++restart;
+	}
 	/*
 	 *	Check to see if the board failed any self tests.
 	 */
@@ -556,12 +573,23 @@ int _aac_rx_init(struct aac_dev *dev)
 	 */
 	while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
 	{
-		if(time_after(jiffies, start+startup_timeout*HZ))
-		{
+		if ((restart &&
+		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+		  time_after(jiffies, start+HZ*startup_timeout)) {
 			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
 					dev->name, instance, status);
 			goto error_iounmap;
 		}
+		if (!restart &&
+		  ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+		  time_after(jiffies, start + HZ *
+		  ((startup_timeout > 60)
+		    ? (startup_timeout - 60)
+		    : (startup_timeout / 2))))) {
+			if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
+				start = jiffies;
+			++restart;
+		}
 		msleep(1);
 	}
 	/*
@@ -572,6 +600,7 @@ int _aac_rx_init(struct aac_dev *dev)
 	dev->a_ops.adapter_notify = aac_rx_notify_adapter;
 	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
 	dev->a_ops.adapter_check_health = aac_rx_check_health;
+	dev->a_ops.adapter_restart = aac_rx_restart_adapter;
 
 	/*
 	 *	First clear out all interrupts.  Then enable the one's that we
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 6f1a178..f4b5e97 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -31,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 1d239f6..cbbfbc9 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -35,7 +35,6 @@ #include <linux/delay.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/pci.h>
 #include <linux/isapnp.h>
 #include <linux/blkdev.h>
 #include <linux/mca.h>
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 911ea17..5e6620f 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -57,18 +57,6 @@ config AIC79XX_BUILD_FIRMWARE
 	or modify the assembler Makefile or the files it includes if your
 	build environment is different than that of the author.
 
-config AIC79XX_ENABLE_RD_STRM
-	bool "Enable Read Streaming for All Targets"
-	depends on SCSI_AIC79XX
-	default n
-	help
-	Read Streaming is a U320 protocol option that should enhance
-	performance.  Early U320 drive firmware actually performs slower
-	with read streaming enabled so it is disabled by default.  Read
-	Streaming can be configured in much the same way as tagged queueing
-	using the "rd_strm" command line option.  See
-	drivers/scsi/aic7xxx/README.aic79xx for details.
-
 config AIC79XX_DEBUG_ENABLE
 	bool "Compile in Debugging Code"
 	depends on SCSI_AIC79XX
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index cd93f9a..88da670 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -50,16 +50,6 @@ config AIC7XXX_RESET_DELAY_MS
 
 	Default: 5000 (5 seconds)
 
-config AIC7XXX_PROBE_EISA_VL
-	bool "Probe for EISA and VL AIC7XXX Adapters"
-	depends on SCSI_AIC7XXX && EISA
-	help
-	Probe for EISA and VLB Aic7xxx controllers.  In many newer systems,
-	the invasive probes necessary to detect these controllers can cause
-	other devices to fail.  For this reason, the non-PCI probe code is
-	disabled by default.  The current value of this option can be "toggled"
-	via the no_probe kernel command line option.
-
 config AIC7XXX_BUILD_FIRMWARE
 	bool "Build Adapter Firmware with Kernel Build"
 	depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 2be03e9..6054881 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -363,6 +363,8 @@ static int ahd_linux_run_command(struct 
 				 struct scsi_cmnd *);
 static void ahd_linux_setup_tag_info_global(char *p);
 static int  aic79xx_setup(char *c);
+static void ahd_freeze_simq(struct ahd_softc *ahd);
+static void ahd_release_simq(struct ahd_softc *ahd);
 
 static int ahd_linux_unit;
 
@@ -2016,13 +2018,13 @@ ahd_linux_queue_cmd_complete(struct ahd_
 	cmd->scsi_done(cmd);
 }
 
-void
+static void
 ahd_freeze_simq(struct ahd_softc *ahd)
 {
 	scsi_block_requests(ahd->platform_data->host);
 }
 
-void
+static void
 ahd_release_simq(struct ahd_softc *ahd)
 {
 	scsi_unblock_requests(ahd->platform_data->host);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 147c83c..ad9761b 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -47,7 +47,6 @@ #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -837,8 +836,6 @@ int	ahd_platform_alloc(struct ahd_softc 
 void	ahd_platform_free(struct ahd_softc *ahd);
 void	ahd_platform_init(struct ahd_softc *ahd);
 void	ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
-void	ahd_freeze_simq(struct ahd_softc *ahd);
-void	ahd_release_simq(struct ahd_softc *ahd);
 
 static __inline void
 ahd_freeze_scb(struct scb *scb)
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 954c7c2..e1bd57b 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -1278,11 +1278,6 @@ typedef enum {
 	AHC_QUEUE_TAGGED
 } ahc_queue_alg;
 
-void			ahc_set_tags(struct ahc_softc *ahc,
-				     struct scsi_cmnd *cmd,
-				     struct ahc_devinfo *devinfo,
-				     ahc_queue_alg alg);
-
 /**************************** Target Mode *************************************/
 #ifdef AHC_TARGET_MODE
 void		ahc_send_lstate_events(struct ahc_softc *,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 50ef785..75733b0 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -2073,7 +2073,7 @@ ahc_set_width(struct ahc_softc *ahc, str
 /*
  * Update the current state of tagged queuing for a given target.
  */
-void
+static 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_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 85ae5d8..8fee7ed 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -64,7 +64,6 @@ #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 8f43ff7..db6ab1a 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -24,7 +24,6 @@
  *
  */
 
-#include <linux/pci.h>
 #include <scsi/scsi_host.h>
 
 #include "aic94xx.h"
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 12497da..03bfed6 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -49,7 +49,6 @@ #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>
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 0f920c8..eff846a 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1,19 +1,19 @@
-/* 
+/*
  * NCR 5380 generic driver routines.  These should make it *trivial*
- * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	to implement 5380 SCSI drivers under Linux with a non-trantor
  *	architecture.
  *
  *	Note that these routines also work with NR53c400 family chips.
  *
  * Copyright 1993, Drew Eckhardt
- *	Visionary Computing 
+ *	Visionary Computing
  *	(Unix and Linux consulting and custom programming)
- * 	drew@colorado.edu
+ *	drew@colorado.edu
  *	+1 (303) 666-5836
  *
- * DISTRIBUTION RELEASE 6. 
+ * DISTRIBUTION RELEASE 6.
  *
- * For more information, please consult 
+ * For more information, please consult
  *
  * NCR 5380 Family
  * SCSI Protocol Controller
@@ -57,7 +57,7 @@
  * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
  *    and USLEEP, because these were messing up readability and will never be
  *    needed for Atari SCSI.
- * 
+ *
  * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
  *   stuff), and 'main' is executed in a bottom half if awoken by an
  *   interrupt.
@@ -69,21 +69,29 @@
  */
 
 /*
- * Further development / testing that should be done : 
- * 1.  Test linked command handling code after Eric is ready with 
+ * Further development / testing that should be done :
+ * 1.  Test linked command handling code after Eric is ready with
  *     the high level code.
  */
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_transport_spi.h>
 
 #if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) \
-  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
-    if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) \
-  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
-	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
-    if ((x)==(y)) udelay(5); }
+#define LIST(x, y)						\
+	do {							\
+		printk("LINE:%d   Adding %p to %p\n",		\
+		       __LINE__, (void*)(x), (void*)(y));	\
+		if ((x) == (y))					\
+			udelay(5);				\
+	} while (0)
+#define REMOVE(w, x, y, z)					\
+	do {							\
+		printk("LINE:%d   Removing: %p->%p  %p->%p \n",	\
+		       __LINE__, (void*)(w), (void*)(x),	\
+		       (void*)(y), (void*)(z));			\
+		if ((x) == (y))					\
+			udelay(5);				\
+	} while (0)
 #else
 #define LIST(x,y)
 #define REMOVE(w,x,y,z)
@@ -103,62 +111,62 @@ #endif
  * more difficult than it has to be.
  *
  * Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued 
+ * routines were implemented, meaning their implementations of queued
  * commands were hacked on rather than designed in from the start.
  *
- * When I designed the Linux SCSI drivers I figured that 
+ * When I designed the Linux SCSI drivers I figured that
  * while having two different SCSI boards in a system might be useful
  * for debugging things, two of the same type wouldn't be used.
  * Well, I was wrong and a number of users have mailed me about running
  * multiple high-performance SCSI boards in a server.
  *
- * Finally, when I get questions from users, I have no idea what 
+ * Finally, when I get questions from users, I have no idea what
  * revision of my driver they are running.
  *
  * This driver attempts to address these problems :
- * This is a generic 5380 driver.  To use it on a different platform, 
+ * This is a generic 5380 driver.  To use it on a different platform,
  * one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use 
+ * transfer - some PC's will use the I/O bus, 68K's must use
  * memory mapped) and drops this file in their 'C' wrapper.
  *
- * As far as command queueing, two queues are maintained for 
+ * As far as command queueing, two queues are maintained for
  * each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing.  This means that an 
- * unlimited number of commands may be queued, letting 
- * more commands propagate from the higher driver levels giving higher 
- * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
- * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * and commands that are currently executing.  This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
  * while a command is already executing.
  *
- * To solve the multiple-boards-in-the-same-system problem, 
+ * To solve the multiple-boards-in-the-same-system problem,
  * there is a separate instance structure for each instance
  * of a 5380 in the system.  So, multiple NCR5380 drivers will
  * be able to coexist with appropriate changes to the high level
- * SCSI code.  
+ * SCSI code.
  *
  * A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the 
- * NCR5380_print_options command, which should be called from the 
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
  * wrapper detect function, so that I know what release of the driver
  * users are using.
  *
- * Issues specific to the NCR5380 : 
+ * Issues specific to the NCR5380 :
  *
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
- * piece of hardware that requires you to sit in a loop polling for 
- * the REQ signal as long as you are connected.  Some devices are 
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected.  Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
  * while doing long seek operations.
- * 
+ *
  * The workaround for this is to keep track of devices that have
  * disconnected.  If the device hasn't disconnected, for commands that
- * should disconnect, we do something like 
+ * should disconnect, we do something like
  *
  * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- * 
- * Some tweaking of N and M needs to be done.  An algorithm based 
+ *
+ * Some tweaking of N and M needs to be done.  An algorithm based
  * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these 
+ * to datas (ie, on the same track) were considered, however these
  * broken devices are the exception rather than the rule and I'd rather
  * spend my time optimizing for the normal case.
  *
@@ -167,9 +175,9 @@ #endif
  * At the heart of the design is a coroutine, NCR5380_main,
  * which is started when not running by the interrupt handler,
  * timer, and queue command function.  It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the 
- * issue queue and calling NCR5380_select() if a nexus 
- * is not established. 
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
  *
  * Once a nexus is established, the NCR5380_information_transfer()
  * phase goes through the various phases as instructed by the target.
@@ -183,10 +191,10 @@ #endif
  * calling NCR5380_intr()  which will in turn call NCR5380_reselect
  * to reestablish a nexus.  This will run main if necessary.
  *
- * On command termination, the done function will be called as 
+ * On command termination, the done function will be called as
  * appropriate.
  *
- * SCSI pointers are maintained in the SCp field of SCSI command 
+ * SCSI pointers are maintained in the SCp field of SCSI command
  * structures, being initialized after the command is connected
  * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
  * Note that in violation of the standard, an implicit SAVE POINTERS operation
@@ -196,12 +204,12 @@ #endif
 /*
  * Using this file :
  * This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips.  To use it, you write an architecture specific functions 
+ * of chips.  To use it, you write an architecture specific functions
  * and macros and include this file in your driver.
  *
- * These macros control options : 
+ * These macros control options :
  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- *	for commands that return with a CHECK CONDITION status. 
+ *	for commands that return with a CHECK CONDITION status.
  *
  * LINKED - if defined, linked commands are supported.
  *
@@ -210,18 +218,18 @@ #endif
  * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
  *
  * These macros MUST be defined :
- * 
+ *
  * NCR5380_read(register)  - read from the specified register
  *
- * NCR5380_write(register, value) - write to the specific register 
+ * NCR5380_write(register, value) - write to the specific register
  *
  * Either real DMA *or* pseudo DMA may be implemented
- * REAL functions : 
+ * REAL functions :
  * NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes 
+ * Note that the DMA setup functions should return the number of bytes
  *	that they were able to program the controller for.
  *
- * Also note that generic i386/PC versions of these macros are 
+ * Also note that generic i386/PC versions of these macros are
  *	available as NCR5380_i386_dma_write_setup,
  *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
  *
@@ -234,14 +242,14 @@ #endif
  * NCR5380_pread(instance, dst, count);
  *
  * If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define 
- *  
+ * hardware), you must also define
+ *
  * NCR5380_queue_command
  * NCR5380_reset
  * NCR5380_abort
  * NCR5380_proc_info
  *
- * to be the global entry points into the specific driver, ie 
+ * to be the global entry points into the specific driver, ie
  * #define NCR5380_queue_command t128_queue_command.
  *
  * If this is not done, the routines will be defined as static functions
@@ -249,7 +257,7 @@ #endif
  * accessible wrapper function.
  *
  * The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID.  If the 
+ * after setting the appropriate host specific fields and ID.  If the
  * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
  * possible) function may be used.  Before the specific driver initialization
  * code finishes, NCR5380_print_options should be called.
@@ -264,8 +272,9 @@ #define	SETUP_HOSTDATA(in)				\
 	(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)		((Scsi_Cmnd *)(cmd)->host_scribble)
+#define	SET_NEXT(cmd,next)	((cmd)->host_scribble = (void *)(next))
+#define	NEXTADDR(cmd)		((Scsi_Cmnd **)&(cmd)->host_scribble)
 
 #define	HOSTNO		instance->host_no
 #define	H_NO(cmd)	(cmd)->device->host->host_no
@@ -312,34 +321,34 @@ #undef TAG_NONE
 #define TAG_NONE 0xff
 
 typedef struct {
-    DECLARE_BITMAP(allocated, MAX_TAGS);
-    int		nr_allocated;
-    int		queue_size;
+	DECLARE_BITMAP(allocated, MAX_TAGS);
+	int nr_allocated;
+	int queue_size;
 } TAG_ALLOC;
 
-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+static TAG_ALLOC TagAlloc[8][8];	/* 8 targets and 8 LUNs */
 
 
-static void __init init_tags( void )
+static void __init init_tags(void)
 {
-    int target, lun;
-    TAG_ALLOC *ta;
-    
-    if (!setup_use_tagged_queuing)
-	return;
-    
-    for( target = 0; target < 8; ++target ) {
-	for( lun = 0; lun < 8; ++lun ) {
-	    ta = &TagAlloc[target][lun];
-	    bitmap_zero(ta->allocated, MAX_TAGS);
-	    ta->nr_allocated = 0;
-	    /* At the beginning, assume the maximum queue size we could
-	     * support (MAX_TAGS). This value will be decreased if the target
-	     * returns QUEUE_FULL status.
-	     */
-	    ta->queue_size = MAX_TAGS;
+	int target, lun;
+	TAG_ALLOC *ta;
+
+	if (!setup_use_tagged_queuing)
+		return;
+
+	for (target = 0; target < 8; ++target) {
+		for (lun = 0; lun < 8; ++lun) {
+			ta = &TagAlloc[target][lun];
+			bitmap_zero(ta->allocated, MAX_TAGS);
+			ta->nr_allocated = 0;
+			/* At the beginning, assume the maximum queue size we could
+			 * support (MAX_TAGS). This value will be decreased if the target
+			 * returns QUEUE_FULL status.
+			 */
+			ta->queue_size = MAX_TAGS;
+		}
 	}
-    }
 }
 
 
@@ -348,24 +357,24 @@ static void __init init_tags( void )
  * check that there is a free tag and the target's queue won't overflow. This
  * function should be called with interrupts disabled to avoid race
  * conditions.
- */ 
+ */
 
-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
 {
-    SETUP_HOSTDATA(cmd->device->host);
-
-    if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
-	return( 1 );
-    if (!should_be_tagged ||
-	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
-	return( 0 );
-    if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
-	TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
-	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
-		    H_NO(cmd), cmd->device->id, cmd->device->lun );
-	return( 1 );
-    }
-    return( 0 );
+	SETUP_HOSTDATA(cmd->device->host);
+
+	if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+		return 1;
+	if (!should_be_tagged ||
+	    !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+		return 0;
+	if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+	    TagAlloc[cmd->device->id][cmd->device->lun].queue_size) {
+		TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n",
+			   H_NO(cmd), cmd->device->id, cmd->device->lun);
+		return 1;
+	}
+	return 0;
 }
 
 
@@ -374,31 +383,30 @@ 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(Scsi_Cmnd *cmd, int should_be_tagged)
 {
-    SETUP_HOSTDATA(cmd->device->host);
-
-    /* If we or the target don't support tagged queuing, allocate the LUN for
-     * an untagged command.
-     */
-    if (!should_be_tagged ||
-	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
-	cmd->tag = TAG_NONE;
-	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
-		    "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
-    }
-    else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
-
-	cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
-	set_bit( cmd->tag, ta->allocated );
-	ta->nr_allocated++;
-	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
-		    "(now %d tags in use)\n",
-		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
-		    ta->nr_allocated );
-    }
+	SETUP_HOSTDATA(cmd->device->host);
+
+	/* If we or the target don't support tagged queuing, allocate the LUN for
+	 * an untagged command.
+	 */
+	if (!should_be_tagged ||
+	    !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+		cmd->tag = TAG_NONE;
+		hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+		TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged "
+			   "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun);
+	} else {
+		TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+
+		cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
+		set_bit(cmd->tag, ta->allocated);
+		ta->nr_allocated++;
+		TAG_PRINTK("scsi%d: using tag %d for target %d lun %d "
+			   "(now %d tags in use)\n",
+			   H_NO(cmd), cmd->tag, cmd->device->id,
+			   cmd->device->lun, ta->nr_allocated);
+	}
 }
 
 
@@ -406,44 +414,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd,
  * unlock the LUN.
  */
 
-static void cmd_free_tag( Scsi_Cmnd *cmd )
+static void cmd_free_tag(Scsi_Cmnd *cmd)
 {
-    SETUP_HOSTDATA(cmd->device->host);
-
-    if (cmd->tag == TAG_NONE) {
-	hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
-		    H_NO(cmd), cmd->device->id, cmd->device->lun );
-    }
-    else if (cmd->tag >= MAX_TAGS) {
-	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
-		H_NO(cmd), cmd->tag );
-    }
-    else {
-	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
-	clear_bit( cmd->tag, ta->allocated );
-	ta->nr_allocated--;
-	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
-		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
-    }
+	SETUP_HOSTDATA(cmd->device->host);
+
+	if (cmd->tag == TAG_NONE) {
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n",
+			   H_NO(cmd), cmd->device->id, cmd->device->lun);
+	} else if (cmd->tag >= MAX_TAGS) {
+		printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+		       H_NO(cmd), cmd->tag);
+	} else {
+		TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+		clear_bit(cmd->tag, ta->allocated);
+		ta->nr_allocated--;
+		TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n",
+			   H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun);
+	}
 }
 
 
-static void free_all_tags( void )
+static void free_all_tags(void)
 {
-    int target, lun;
-    TAG_ALLOC *ta;
-
-    if (!setup_use_tagged_queuing)
-	return;
-    
-    for( target = 0; target < 8; ++target ) {
-	for( lun = 0; lun < 8; ++lun ) {
-	    ta = &TagAlloc[target][lun];
-	    bitmap_zero(ta->allocated, MAX_TAGS);
-	    ta->nr_allocated = 0;
+	int target, lun;
+	TAG_ALLOC *ta;
+
+	if (!setup_use_tagged_queuing)
+		return;
+
+	for (target = 0; target < 8; ++target) {
+		for (lun = 0; lun < 8; ++lun) {
+			ta = &TagAlloc[target][lun];
+			bitmap_zero(ta->allocated, MAX_TAGS);
+			ta->nr_allocated = 0;
+		}
 	}
-    }
 }
 
 #endif /* SUPPORT_TAGS */
@@ -461,89 +467,94 @@ #endif /* SUPPORT_TAGS */
  *    assumed to be already transfered into ptr/this_residual.
  */
 
-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
 {
-    unsigned long endaddr;
+	unsigned long endaddr;
 #if (NDEBUG & NDEBUG_MERGING)
-    unsigned long oldlen = cmd->SCp.this_residual;
-    int		  cnt = 1;
+	unsigned long oldlen = cmd->SCp.this_residual;
+	int cnt = 1;
 #endif
 
-    for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
-	 cmd->SCp.buffers_residual &&
-	 virt_to_phys(page_address(cmd->SCp.buffer[1].page)+
-		      cmd->SCp.buffer[1].offset) == endaddr; ) {
-	MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
-		   cmd->SCp.buffer[1].address, endaddr);
+	for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+	     cmd->SCp.buffers_residual &&
+	     virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
+			  cmd->SCp.buffer[1].offset) == endaddr;) {
+		MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+			   page_address(cmd->SCp.buffer[1].page), endaddr);
 #if (NDEBUG & NDEBUG_MERGING)
-	++cnt;
+		++cnt;
 #endif
-	++cmd->SCp.buffer;
-	--cmd->SCp.buffers_residual;
-	cmd->SCp.this_residual += cmd->SCp.buffer->length;
-	endaddr += cmd->SCp.buffer->length;
-    }
+		++cmd->SCp.buffer;
+		--cmd->SCp.buffers_residual;
+		cmd->SCp.this_residual += cmd->SCp.buffer->length;
+		endaddr += cmd->SCp.buffer->length;
+	}
 #if (NDEBUG & NDEBUG_MERGING)
-    if (oldlen != cmd->SCp.this_residual)
-	MER_PRINTK("merged %d buffers from %p, new length %08x\n",
-		   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+	if (oldlen != cmd->SCp.this_residual)
+		MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+			   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
 #endif
 }
 
 /*
  * Function : void initialize_SCp(Scsi_Cmnd *cmd)
  *
- * Purpose : initialize the saved data pointers for cmd to point to the 
+ * 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.
  */
 
-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+static inline void initialize_SCp(Scsi_Cmnd *cmd)
 {
-    /* 
-     * Initialize the Scsi Pointer field so that all of the commands in the 
-     * various queues are valid.
-     */
-
-    if (cmd->use_sg) {
-	cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-	cmd->SCp.buffers_residual = cmd->use_sg - 1;
-	cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
-		       cmd->SCp.buffer->offset;
-	cmd->SCp.this_residual = cmd->SCp.buffer->length;
-	/* ++roman: Try to merge some scatter-buffers if they are at
-	 * contiguous physical addresses.
+	/*
+	 * Initialize the Scsi Pointer field so that all of the commands in the
+	 * various queues are valid.
 	 */
-	merge_contiguous_buffers( cmd );
-    } else {
-	cmd->SCp.buffer = NULL;
-	cmd->SCp.buffers_residual = 0;
-	cmd->SCp.ptr = (char *) cmd->request_buffer;
-	cmd->SCp.this_residual = cmd->request_bufflen;
-    }
+
+	if (cmd->use_sg) {
+		cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
+			       cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		/* ++roman: Try to merge some scatter-buffers if they are at
+		 * contiguous physical addresses.
+		 */
+		merge_contiguous_buffers(cmd);
+	} else {
+		cmd->SCp.buffer = NULL;
+		cmd->SCp.buffers_residual = 0;
+		cmd->SCp.ptr = (char *)cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+	}
 }
 
 #include <linux/delay.h>
 
 #if NDEBUG
 static struct {
-    unsigned char mask;
-    const char * name;} 
-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
-    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
-    { SR_SEL, "SEL" }, {0, NULL}}, 
-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
-    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
-    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
-    {0, NULL}},
-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
-    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
-    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
-    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
-    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
-    {0, NULL}};
+	unsigned char mask;
+	const char *name;
+} signals[] = {
+	{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+	{ SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" },
+	{ SR_SEL, "SEL" }, {0, NULL}
+}, basrs[] = {
+	{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
+}, icrs[] = {
+	{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+	{ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+	{ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+	{0, NULL}
+}, mrs[] = {
+	{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+	{MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+	"MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+	{MR_MONITOR_BSY, "MODE MONITOR BSY"},
+	{MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+	{0, NULL}
+};
 
 /*
  * Function : void NCR5380_print(struct Scsi_Host *instance)
@@ -553,45 +564,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK
  * Input : instance - which NCR5380
  */
 
-static void NCR5380_print(struct Scsi_Host *instance) {
-    unsigned char status, data, basr, mr, icr, i;
-    unsigned long flags;
-
-    local_irq_save(flags);
-    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
-    status = NCR5380_read(STATUS_REG);
-    mr = NCR5380_read(MODE_REG);
-    icr = NCR5380_read(INITIATOR_COMMAND_REG);
-    basr = NCR5380_read(BUS_AND_STATUS_REG);
-    local_irq_restore(flags);
-    printk("STATUS_REG: %02x ", status);
-    for (i = 0; signals[i].mask ; ++i) 
-	if (status & signals[i].mask)
-	    printk(",%s", signals[i].name);
-    printk("\nBASR: %02x ", basr);
-    for (i = 0; basrs[i].mask ; ++i) 
-	if (basr & basrs[i].mask)
-	    printk(",%s", basrs[i].name);
-    printk("\nICR: %02x ", icr);
-    for (i = 0; icrs[i].mask; ++i) 
-	if (icr & icrs[i].mask)
-	    printk(",%s", icrs[i].name);
-    printk("\nMODE: %02x ", mr);
-    for (i = 0; mrs[i].mask; ++i) 
-	if (mr & mrs[i].mask)
-	    printk(",%s", mrs[i].name);
-    printk("\n");
+static void NCR5380_print(struct Scsi_Host *instance)
+{
+	unsigned char status, data, basr, mr, icr, i;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+	status = NCR5380_read(STATUS_REG);
+	mr = NCR5380_read(MODE_REG);
+	icr = NCR5380_read(INITIATOR_COMMAND_REG);
+	basr = NCR5380_read(BUS_AND_STATUS_REG);
+	local_irq_restore(flags);
+	printk("STATUS_REG: %02x ", status);
+	for (i = 0; signals[i].mask; ++i)
+		if (status & signals[i].mask)
+			printk(",%s", signals[i].name);
+	printk("\nBASR: %02x ", basr);
+	for (i = 0; basrs[i].mask; ++i)
+		if (basr & basrs[i].mask)
+			printk(",%s", basrs[i].name);
+	printk("\nICR: %02x ", icr);
+	for (i = 0; icrs[i].mask; ++i)
+		if (icr & icrs[i].mask)
+			printk(",%s", icrs[i].name);
+	printk("\nMODE: %02x ", mr);
+	for (i = 0; mrs[i].mask; ++i)
+		if (mr & mrs[i].mask)
+			printk(",%s", mrs[i].name);
+	printk("\n");
 }
 
 static struct {
-    unsigned char value;
-    const char *name;
+	unsigned char value;
+	const char *name;
 } phases[] = {
-    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
-    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
-    {PHASE_UNKNOWN, "UNKNOWN"}};
+	{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+	{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+	{PHASE_UNKNOWN, "UNKNOWN"}
+};
 
-/* 
+/*
  * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
  *
  * Purpose : print the current SCSI phase for debugging purposes
@@ -601,30 +614,35 @@ static struct {
 
 static void NCR5380_print_phase(struct Scsi_Host *instance)
 {
-    unsigned char status;
-    int i;
-
-    status = NCR5380_read(STATUS_REG);
-    if (!(status & SR_REQ)) 
-	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
-    else {
-	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
-	    (phases[i].value != (status & PHASE_MASK)); ++i); 
-	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
-    }
+	unsigned char status;
+	int i;
+
+	status = NCR5380_read(STATUS_REG);
+	if (!(status & SR_REQ))
+		printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+	else {
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+		     (phases[i].value != (status & PHASE_MASK)); ++i)
+			;
+		printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+	}
 }
 
 #else /* !NDEBUG */
 
 /* dummies... */
-__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
-__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+static inline void NCR5380_print(struct Scsi_Host *instance)
+{
+};
+static inline void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+};
 
 #endif
 
 /*
  * ++roman: New scheme of calling NCR5380_main()
- * 
+ *
  * If we're not in an interrupt, we can call our main directly, it cannot be
  * already running. Else, we queue it on a task queue, if not 'main_running'
  * tells us that a lower level is already executing it. This way,
@@ -638,33 +656,33 @@ #endif
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 
-static volatile int main_running = 0;
-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+static volatile int main_running;
+static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
 
-static __inline__ void queue_main(void)
+static inline void queue_main(void)
 {
-    if (!main_running) {
-	/* If in interrupt and NCR5380_main() not already running,
-	   queue it on the 'immediate' task queue, to be processed
-	   immediately after the current interrupt processing has
-	   finished. */
-	schedule_work(&NCR5380_tqueue);
-    }
-    /* else: nothing to do: the running NCR5380_main() will pick up
-       any newly queued command. */
+	if (!main_running) {
+		/* If in interrupt and NCR5380_main() not already running,
+		   queue it on the 'immediate' task queue, to be processed
+		   immediately after the current interrupt processing has
+		   finished. */
+		schedule_work(&NCR5380_tqueue);
+	}
+	/* else: nothing to do: the running NCR5380_main() will pick up
+	   any newly queued command. */
 }
 
 
-static inline void NCR5380_all_init (void)
+static inline void NCR5380_all_init(void)
 {
-    static int done = 0;
-    if (!done) {
-	INI_PRINTK("scsi : NCR5380_all_init()\n");
-	done = 1;
-    }
+	static int done = 0;
+	if (!done) {
+		INI_PRINTK("scsi : NCR5380_all_init()\n");
+		done = 1;
+	}
 }
 
- 
+
 /*
  * Function : void NCR58380_print_options (struct Scsi_Host *instance)
  *
@@ -674,23 +692,23 @@ static inline void NCR5380_all_init (voi
  * Inputs : instance, pointer to this instance.  Unused.
  */
 
-static void __init NCR5380_print_options (struct Scsi_Host *instance)
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
 {
-    printk(" generic options"
-#ifdef AUTOSENSE 
-    " AUTOSENSE"
+	printk(" generic options"
+#ifdef AUTOSENSE
+	       " AUTOSENSE"
 #endif
 #ifdef REAL_DMA
-    " REAL DMA"
+	       " REAL DMA"
 #endif
 #ifdef PARITY
-    " PARITY"
+	       " PARITY"
 #endif
 #ifdef SUPPORT_TAGS
-    " SCSI-2 TAGGED QUEUING"
+	       " SCSI-2 TAGGED QUEUING"
 #endif
-    );
-    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+	       );
+	printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
 }
 
 /*
@@ -699,27 +717,27 @@ #endif
  * Purpose : print commands in the various queues, called from
  *	NCR5380_abort and NCR5380_debug to aid debugging.
  *
- * Inputs : instance, pointer to this instance.  
+ * Inputs : instance, pointer to this instance.
  */
 
-static void NCR5380_print_status (struct Scsi_Host *instance)
+static void NCR5380_print_status(struct Scsi_Host *instance)
 {
-    char *pr_bfr;
-    char *start;
-    int len;
-
-    NCR_PRINT(NDEBUG_ANY);
-    NCR_PRINT_PHASE(NDEBUG_ANY);
-
-    pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
-    if (!pr_bfr) {
-	printk("NCR5380_print_status: no memory for print buffer\n");
-	return;
-    }
-    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
-    pr_bfr[len] = 0;
-    printk("\n%s\n", pr_bfr);
-    free_page((unsigned long) pr_bfr);
+	char *pr_bfr;
+	char *start;
+	int len;
+
+	NCR_PRINT(NDEBUG_ANY);
+	NCR_PRINT_PHASE(NDEBUG_ANY);
+
+	pr_bfr = (char *)__get_free_page(GFP_ATOMIC);
+	if (!pr_bfr) {
+		printk("NCR5380_print_status: no memory for print buffer\n");
+		return;
+	}
+	len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+	pr_bfr[len] = 0;
+	printk("\n%s\n", pr_bfr);
+	free_page((unsigned long)pr_bfr);
 }
 
 
@@ -738,443 +756,478 @@ static void NCR5380_print_status (struct
 */
 
 #undef SPRINTF
-#define SPRINTF(fmt,args...) \
-  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);
-
-static
-int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
-		       int length, int inout)
+#define SPRINTF(fmt,args...)							\
+	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);
+
+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;
-    unsigned long flags;
-    off_t begin = 0;
-#define check_offset()				\
-    do {					\
-	if (pos - buffer < offset - begin) {	\
-	    begin += pos - buffer;		\
-	    pos = buffer;			\
-	}					\
-    } while (0)
-
-    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
-    if (inout) { /* Has data been written to the file ? */
-	return(-ENOSYS);  /* Currently this is a no-op */
-    }
-    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
-    check_offset();
-    local_irq_save(flags);
-    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
-    check_offset();
-    if (!hostdata->connected)
-	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
-    else
-	pos = lprint_Scsi_Cmnd ((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)) {
-	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	char *pos = buffer;
+	struct NCR5380_hostdata *hostdata;
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+	off_t begin = 0;
+#define check_offset()					\
+	do {						\
+		if (pos - buffer < offset - begin) {	\
+			begin += pos - buffer;		\
+			pos = buffer;			\
+		}					\
+	} while (0)
+
+	hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+	if (inout)			/* Has data been written to the file ? */
+		return -ENOSYS;		/* Currently this is a no-op */
+	SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
 	check_offset();
-    }
+	local_irq_save(flags);
+	SPRINTF("NCR5380: coroutine is%s running.\n",
+		main_running ? "" : "n't");
+	check_offset();
+	if (!hostdata->connected)
+		SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+	else
+		pos = lprint_Scsi_Cmnd((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)) {
+		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;
-	 ptr = NEXT(ptr)) {
-	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
 	check_offset();
-    }
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	     ptr = NEXT(ptr)) {
+		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+		check_offset();
+	}
 
-    local_irq_restore(flags);
-    *start = buffer + (offset - begin);
-    if (pos - buffer < offset - begin)
-	return 0;
-    else if (pos - buffer - (offset - begin) < length)
-	return pos - buffer - (offset - begin);
-    return length;
+	local_irq_restore(flags);
+	*start = buffer + (offset - begin);
+	if (pos - buffer < offset - begin)
+		return 0;
+	else if (pos - buffer - (offset - begin) < length)
+		return pos - buffer - (offset - begin);
+	return length;
 }
 
-static char *
-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
 {
-    int i, s;
-    unsigned char *command;
-    SPRINTF("scsi%d: destination target %d, lun %d\n",
-	    H_NO(cmd), cmd->device->id, cmd->device->lun);
-    SPRINTF("        command = ");
-    command = cmd->cmnd;
-    SPRINTF("%2d (0x%02x)", command[0], command[0]);
-    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
-	SPRINTF(" %02x", command[i]);
-    SPRINTF("\n");
-    return pos;
+	int i, s;
+	unsigned char *command;
+	SPRINTF("scsi%d: destination target %d, lun %d\n",
+		H_NO(cmd), cmd->device->id, cmd->device->lun);
+	SPRINTF("        command = ");
+	command = cmd->cmnd;
+	SPRINTF("%2d (0x%02x)", command[0], command[0]);
+	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+		SPRINTF(" %02x", command[i]);
+	SPRINTF("\n");
+	return pos;
 }
 
 
-/* 
+/*
  * Function : void NCR5380_init (struct Scsi_Host *instance)
  *
  * Purpose : initializes *instance and corresponding 5380 chip.
  *
- * Inputs : instance - instantiation of the 5380 driver.  
+ * Inputs : instance - instantiation of the 5380 driver.
  *
  * Notes : I assume that the host, hostno, and id bits have been
- * 	set correctly.  I don't care about the irq and other fields. 
- * 
+ *	set correctly.  I don't care about the irq and other fields.
+ *
  */
 
-static int NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init(struct Scsi_Host *instance, int flags)
 {
-    int i;
-    SETUP_HOSTDATA(instance);
-
-    NCR5380_all_init();
-
-    hostdata->aborted = 0;
-    hostdata->id_mask = 1 << instance->this_id;
-    hostdata->id_higher_mask = 0;
-    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
-	if (i > hostdata->id_mask)
-	    hostdata->id_higher_mask |= i;
-    for (i = 0; i < 8; ++i)
-	hostdata->busy[i] = 0;
+	int i;
+	SETUP_HOSTDATA(instance);
+
+	NCR5380_all_init();
+
+	hostdata->aborted = 0;
+	hostdata->id_mask = 1 << instance->this_id;
+	hostdata->id_higher_mask = 0;
+	for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+		if (i > hostdata->id_mask)
+			hostdata->id_higher_mask |= i;
+	for (i = 0; i < 8; ++i)
+		hostdata->busy[i] = 0;
 #ifdef SUPPORT_TAGS
-    init_tags();
+	init_tags();
 #endif
 #if defined (REAL_DMA)
-    hostdata->dma_len = 0;
+	hostdata->dma_len = 0;
 #endif
-    hostdata->targets_present = 0;
-    hostdata->connected = NULL;
-    hostdata->issue_queue = NULL;
-    hostdata->disconnected_queue = NULL;
-    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
-
-    if (!the_template) {
-	the_template = instance->hostt;
-	first_instance = instance;
-    }
-	
+	hostdata->targets_present = 0;
+	hostdata->connected = NULL;
+	hostdata->issue_queue = NULL;
+	hostdata->disconnected_queue = NULL;
+	hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+	if (!the_template) {
+		the_template = instance->hostt;
+		first_instance = instance;
+	}
 
 #ifndef AUTOSENSE
-    if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
-	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
-	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
-	        "        be incorrectly cleared.\n", HOSTNO);
+	if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+		printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+		       "        without AUTOSENSE option, contingent allegiance conditions may\n"
+		       "        be incorrectly cleared.\n", HOSTNO);
 #endif /* def AUTOSENSE */
 
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-    NCR5380_write(MODE_REG, MR_BASE);
-    NCR5380_write(TARGET_COMMAND_REG, 0);
-    NCR5380_write(SELECT_ENABLE_REG, 0);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+	NCR5380_write(SELECT_ENABLE_REG, 0);
 
-    return 0;
+	return 0;
 }
 
-/* 
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
- *	void (*done)(Scsi_Cmnd *)) 
+/*
+ * our own old-style timeout update
+ */
+/*
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
+
+int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
+{
+	int rtn;
+
+	/*
+	 * We are using the new error handling code to actually register/deregister
+	 * timers for timeout.
+	 */
+
+	if (!timer_pending(&SCset->eh_timeout))
+		rtn = 0;
+	else
+		rtn = SCset->eh_timeout.expires - jiffies;
+
+	if (timeout == 0) {
+		del_timer(&SCset->eh_timeout);
+		SCset->eh_timeout.data = (unsigned long)NULL;
+		SCset->eh_timeout.expires = 0;
+	} else {
+		if (SCset->eh_timeout.data != (unsigned long)NULL)
+			del_timer(&SCset->eh_timeout);
+		SCset->eh_timeout.data = (unsigned long)SCset;
+		SCset->eh_timeout.expires = jiffies + timeout;
+		add_timer(&SCset->eh_timeout);
+	}
+	return rtn;
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ *	void (*done)(Scsi_Cmnd *))
  *
  * Purpose :  enqueues a SCSI command
  *
  * Inputs : cmd - SCSI command, done - function called on completion, with
  *	a pointer to the command descriptor.
- * 
+ *
  * Returns : 0
  *
- * Side effects : 
- *      cmd is added to the per instance issue_queue, with minor 
- *	twiddling done to the host specific fields of cmd.  If the 
+ * Side effects :
+ *      cmd is added to the per instance issue_queue, with minor
+ *	twiddling done to the host specific fields of cmd.  If the
  *	main coroutine is not running, it is restarted.
  *
  */
 
-static
-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-    SETUP_HOSTDATA(cmd->device->host);
-    Scsi_Cmnd *tmp;
-    int oldto;
-    unsigned long flags;
-    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+	SETUP_HOSTDATA(cmd->device->host);
+	Scsi_Cmnd *tmp;
+	int oldto;
+	unsigned long flags;
+	// extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
-    switch (cmd->cmnd[0]) {
-    case WRITE_6:
-    case WRITE_10:
-	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
-	       H_NO(cmd));
-	cmd->result = (DID_ERROR << 16);
-	done(cmd);
-	return 0;
-    }
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+		printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+		       H_NO(cmd));
+		cmd->result = (DID_ERROR << 16);
+		done(cmd);
+		return 0;
+	}
 #endif /* (NDEBUG & NDEBUG_NO_WRITE) */
 
-
 #ifdef NCR5380_STATS
 # if 0
-    if (!hostdata->connected && !hostdata->issue_queue &&
-	!hostdata->disconnected_queue) {
-	hostdata->timebase = jiffies;
-    }
+	if (!hostdata->connected && !hostdata->issue_queue &&
+	    !hostdata->disconnected_queue) {
+		hostdata->timebase = jiffies;
+	}
 # endif
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
 # endif
-	switch (cmd->cmnd[0])
-	{
-	    case WRITE:
-	    case WRITE_6:
-	    case WRITE_10:
-		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
-		hostdata->pendingw++;
-		break;
-	    case READ:
-	    case READ_6:
-	    case READ_10:
-		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
-		hostdata->pendingr++;
-		break;
-	}
+		switch (cmd->cmnd[0]) {
+		case WRITE:
+		case WRITE_6:
+		case WRITE_10:
+			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+			hostdata->pendingw++;
+			break;
+		case READ:
+		case READ_6:
+		case READ_10:
+			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+			hostdata->pendingr++;
+			break;
+		}
 #endif
 
-    /* 
-     * We use the host_scribble field as a pointer to the next command  
-     * in a queue 
-     */
-
-    NEXT(cmd) = NULL;
-    cmd->scsi_done = done;
-
-    cmd->result = 0;
-
-
-    /* 
-     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
-     * commands are added to the head of the queue since any command will
-     * clear the contingent allegiance condition that exists and the 
-     * sense data is only guaranteed to be valid while the condition exists.
-     */
-
-    local_irq_save(flags);
-    /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
-     * Otherwise a running NCR5380_main may steal the lock.
-     * Lock before actually inserting due to fairness reasons explained in
-     * atari_scsi.c. If we insert first, then it's impossible for this driver
-     * to release the lock.
-     * Stop timer for this command while waiting for the lock, or timeouts
-     * may happen (and they really do), and it's no good if the command doesn't
-     * appear in any of the queues.
-     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
-     * because also a timer int can trigger an abort or reset, which would
-     * alter queues and touch the lock.
-     */
-    if (!IS_A_TT()) {
-	oldto = update_timeout(cmd, 0);
-	falcon_get_lock();
-	update_timeout(cmd, oldto);
-    }
-    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
-	LIST(cmd, hostdata->issue_queue);
-	NEXT(cmd) = hostdata->issue_queue;
-	hostdata->issue_queue = cmd;
-    } else {
-	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
-	     NEXT(tmp); tmp = NEXT(tmp))
-	    ;
-	LIST(cmd, tmp);
-	NEXT(tmp) = cmd;
-    }
-    local_irq_restore(flags);
-
-    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
-	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-
-    /* If queue_command() is called from an interrupt (real one or bottom
-     * half), we let queue_main() do the job of taking care about main. If it
-     * is already running, this is a no-op, else main will be queued.
-     *
-     * If we're not in an interrupt, we can call NCR5380_main()
-     * unconditionally, because it cannot be already running.
-     */
-    if (in_interrupt() || ((flags >> 8) & 7) >= 6)
-	queue_main();
-    else
-	NCR5380_main(NULL);
-    return 0;
+	/*
+	 * We use the host_scribble field as a pointer to the next command
+	 * in a queue
+	 */
+
+	SET_NEXT(cmd, NULL);
+	cmd->scsi_done = done;
+
+	cmd->result = 0;
+
+	/*
+	 * Insert the cmd into the issue queue. Note that REQUEST SENSE
+	 * commands are added to the head of the queue since any command will
+	 * clear the contingent allegiance condition that exists and the
+	 * sense data is only guaranteed to be valid while the condition exists.
+	 */
+
+	local_irq_save(flags);
+	/* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+	 * Otherwise a running NCR5380_main may steal the lock.
+	 * Lock before actually inserting due to fairness reasons explained in
+	 * atari_scsi.c. If we insert first, then it's impossible for this driver
+	 * to release the lock.
+	 * Stop timer for this command while waiting for the lock, or timeouts
+	 * may happen (and they really do), and it's no good if the command doesn't
+	 * appear in any of the queues.
+	 * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+	 * because also a timer int can trigger an abort or reset, which would
+	 * alter queues and touch the lock.
+	 */
+	if (!IS_A_TT()) {
+		oldto = atari_scsi_update_timeout(cmd, 0);
+		falcon_get_lock();
+		atari_scsi_update_timeout(cmd, oldto);
+	}
+	if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+		LIST(cmd, hostdata->issue_queue);
+		SET_NEXT(cmd, hostdata->issue_queue);
+		hostdata->issue_queue = cmd;
+	} else {
+		for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+		     NEXT(tmp); tmp = NEXT(tmp))
+			;
+		LIST(cmd, tmp);
+		SET_NEXT(tmp, cmd);
+	}
+	local_irq_restore(flags);
+
+	QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+		  (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+	/* If queue_command() is called from an interrupt (real one or bottom
+	 * half), we let queue_main() do the job of taking care about main. If it
+	 * is already running, this is a no-op, else main will be queued.
+	 *
+	 * If we're not in an interrupt, we can call NCR5380_main()
+	 * unconditionally, because it cannot be already running.
+	 */
+	if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+		queue_main();
+	else
+		NCR5380_main(NULL);
+	return 0;
 }
 
 /*
- * Function : NCR5380_main (void) 
+ * Function : NCR5380_main (void)
  *
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
- *	be done on the NCR5380 host adapters in a system.  Both 
- *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+ *	be done on the NCR5380 host adapters in a system.  Both
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it
  *	in case it is not running.
- * 
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
  *  reenable them.  This prevents reentrancy and kernel stack overflow.
- */ 	
-    
-static void NCR5380_main (void *bl)
+ */
+
+static void NCR5380_main(struct work_struct *work)
 {
-    Scsi_Cmnd *tmp, *prev;
-    struct Scsi_Host *instance = first_instance;
-    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
-    int done;
-    unsigned long flags;
-    
-    /*
-     * We run (with interrupts disabled) until we're sure that none of 
-     * the host adapters have anything that can be done, at which point 
-     * we set main_running to 0 and exit.
-     *
-     * Interrupts are enabled before doing various other internal 
-     * instructions, after we've decided that we need to run through
-     * the loop again.
-     *
-     * this should prevent any race conditions.
-     * 
-     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
-     * because also a timer int can trigger an abort or reset, which can
-     * alter queues and touch the Falcon lock.
-     */
-
-    /* Tell int handlers main() is now already executing.  Note that
-       no races are possible here. If an int comes in before
-       'main_running' is set here, and queues/executes main via the
-       task queue, it doesn't do any harm, just this instance of main
-       won't find any work left to do. */
-    if (main_running)
-    	return;
-    main_running = 1;
-
-    local_save_flags(flags);
-    do {
-	local_irq_disable(); /* Freeze request queues */
-	done = 1;
-	
-	if (!hostdata->connected) {
-	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
-	    /*
-	     * Search through the issue_queue for a command destined
-	     * for a target that's not busy.
-	     */
+	Scsi_Cmnd *tmp, *prev;
+	struct Scsi_Host *instance = first_instance;
+	struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+	int done;
+	unsigned long flags;
+
+	/*
+	 * We run (with interrupts disabled) until we're sure that none of
+	 * the host adapters have anything that can be done, at which point
+	 * we set main_running to 0 and exit.
+	 *
+	 * Interrupts are enabled before doing various other internal
+	 * instructions, after we've decided that we need to run through
+	 * the loop again.
+	 *
+	 * this should prevent any race conditions.
+	 *
+	 * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+	 * because also a timer int can trigger an abort or reset, which can
+	 * alter queues and touch the Falcon lock.
+	 */
+
+	/* Tell int handlers main() is now already executing.  Note that
+	   no races are possible here. If an int comes in before
+	   'main_running' is set here, and queues/executes main via the
+	   task queue, it doesn't do any harm, just this instance of main
+	   won't find any work left to do. */
+	if (main_running)
+		return;
+	main_running = 1;
+
+	local_save_flags(flags);
+	do {
+		local_irq_disable();	/* Freeze request queues */
+		done = 1;
+
+		if (!hostdata->connected) {
+			MAIN_PRINTK("scsi%d: not connected\n", HOSTNO);
+			/*
+			 * Search through the issue_queue for a command destined
+			 * for a target that's not busy.
+			 */
 #if (NDEBUG & NDEBUG_LISTS)
-	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
-		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
-		;
-		/*printk("%p  ", tmp);*/
-	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+			for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+			     tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+				;
+			/*printk("%p  ", tmp);*/
+			if ((tmp == prev) && tmp)
+				printk(" LOOP\n");
+			/* else printk("\n"); */
 #endif
-	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
-		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+			for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+			     prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
 
 #if (NDEBUG & NDEBUG_LISTS)
-		if (prev != tmp)
-		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
-			   tmp, tmp->device->id, hostdata->busy[tmp->device->id],
-			   tmp->device->lun);
+				if (prev != tmp)
+					printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+					       tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+					       tmp->device->lun);
 #endif
-		/*  When we find one, remove it from the issue queue. */
-		/* ++guenther: possible race with Falcon locking */
-		if (
+				/*  When we find one, remove it from the issue queue. */
+				/* ++guenther: possible race with Falcon locking */
+				if (
 #ifdef SUPPORT_TAGS
-		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+				    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
 #else
-		    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+				    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
 #endif
-		    ) {
-		    /* ++guenther: just to be sure, this must be atomic */
-		    local_irq_disable();
-		    if (prev) {
-		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
-			NEXT(prev) = NEXT(tmp);
-		    } else {
-		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
-			hostdata->issue_queue = NEXT(tmp);
-		    }
-		    NEXT(tmp) = NULL;
-		    falcon_dont_release++;
-		    
-		    /* reenable interrupts after finding one */
-		    local_irq_restore(flags);
-		    
-		    /* 
-		     * Attempt to establish an I_T_L nexus here. 
-		     * On success, instance->hostdata->connected is set.
-		     * On failure, we must add the command back to the
-		     *   issue queue so we can keep trying.	
-		     */
-		    MAIN_PRINTK("scsi%d: main(): command for target %d "
-				"lun %d removed from issue_queue\n",
-				HOSTNO, tmp->device->id, tmp->device->lun);
-		    /* 
-		     * REQUEST SENSE commands are issued without tagged
-		     * queueing, even on SCSI-II devices because the 
-		     * contingent allegiance condition exists for the 
-		     * entire unit.
-		     */
-		    /* ++roman: ...and the standard also requires that
-		     * REQUEST SENSE command are untagged.
-		     */
-		    
+				    ) {
+					/* ++guenther: just to be sure, this must be atomic */
+					local_irq_disable();
+					if (prev) {
+						REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+						SET_NEXT(prev, NEXT(tmp));
+					} else {
+						REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+						hostdata->issue_queue = NEXT(tmp);
+					}
+					SET_NEXT(tmp, NULL);
+					falcon_dont_release++;
+
+					/* reenable interrupts after finding one */
+					local_irq_restore(flags);
+
+					/*
+					 * Attempt to establish an I_T_L nexus here.
+					 * On success, instance->hostdata->connected is set.
+					 * On failure, we must add the command back to the
+					 *   issue queue so we can keep trying.
+					 */
+					MAIN_PRINTK("scsi%d: main(): command for target %d "
+						    "lun %d removed from issue_queue\n",
+						    HOSTNO, tmp->device->id, tmp->device->lun);
+					/*
+					 * REQUEST SENSE commands are issued without tagged
+					 * queueing, even on SCSI-II devices because the
+					 * contingent allegiance condition exists for the
+					 * entire unit.
+					 */
+					/* ++roman: ...and the standard also requires that
+					 * REQUEST SENSE command are untagged.
+					 */
+
 #ifdef SUPPORT_TAGS
-		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+					cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
 #endif
-		    if (!NCR5380_select(instance, tmp, 
-			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
-			    TAG_NEXT)) {
-			falcon_dont_release--;
-			/* release if target did not response! */
-			falcon_release_lock_if_possible( hostdata );
-			break;
-		    } else {
-			local_irq_disable();
-			LIST(tmp, hostdata->issue_queue);
-			NEXT(tmp) = hostdata->issue_queue;
-			hostdata->issue_queue = tmp;
+					if (!NCR5380_select(instance, tmp,
+					    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+					    TAG_NEXT)) {
+						falcon_dont_release--;
+						/* release if target did not response! */
+						falcon_release_lock_if_possible(hostdata);
+						break;
+					} else {
+						local_irq_disable();
+						LIST(tmp, hostdata->issue_queue);
+						SET_NEXT(tmp, hostdata->issue_queue);
+						hostdata->issue_queue = tmp;
 #ifdef SUPPORT_TAGS
-			cmd_free_tag( tmp );
+						cmd_free_tag(tmp);
 #endif
-			falcon_dont_release--;
-			local_irq_restore(flags);
-			MAIN_PRINTK("scsi%d: main(): select() failed, "
-				    "returned to issue_queue\n", HOSTNO);
-			if (hostdata->connected)
-			    break;
-		    }
-		} /* if target/lun/target queue is not busy */
-	    } /* for issue_queue */
-	} /* if (!hostdata->connected) */
-		
-	if (hostdata->connected 
+						falcon_dont_release--;
+						local_irq_restore(flags);
+						MAIN_PRINTK("scsi%d: main(): select() failed, "
+							    "returned to issue_queue\n", HOSTNO);
+						if (hostdata->connected)
+							break;
+					}
+				} /* if target/lun/target queue is not busy */
+			} /* for issue_queue */
+		} /* if (!hostdata->connected) */
+
+		if (hostdata->connected
 #ifdef REAL_DMA
-	    && !hostdata->dma_len
+		    && !hostdata->dma_len
 #endif
-	    ) {
-	    local_irq_restore(flags);
-	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
-			HOSTNO);
-	    NCR5380_information_transfer(instance);
-	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
-	    done = 0;
-	}
-    } while (!done);
+		    ) {
+			local_irq_restore(flags);
+			MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+				    HOSTNO);
+			NCR5380_information_transfer(instance);
+			MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+			done = 0;
+		}
+	} while (!done);
 
-    /* Better allow ints _after_ 'main_running' has been cleared, else
-       an interrupt could believe we'll pick up the work it left for
-       us, but we won't see it anymore here... */
-    main_running = 0;
-    local_irq_restore(flags);
+	/* Better allow ints _after_ 'main_running' has been cleared, else
+	   an interrupt could believe we'll pick up the work it left for
+	   us, but we won't see it anymore here... */
+	main_running = 0;
+	local_irq_restore(flags);
 }
 
 
@@ -1183,1441 +1236,1439 @@ #ifdef REAL_DMA
  * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
  *
  * Purpose : Called by interrupt handler when DMA finishes or a phase
- *	mismatch occurs (which would finish the DMA transfer).  
+ *	mismatch occurs (which would finish the DMA transfer).
  *
  * Inputs : instance - this instance of the NCR5380.
  *
  */
 
-static void NCR5380_dma_complete( struct Scsi_Host *instance )
+static void NCR5380_dma_complete(struct Scsi_Host *instance)
 {
-    SETUP_HOSTDATA(instance);
-    int           transfered, saved_data = 0, overrun = 0, cnt, toPIO;
-    unsigned char **data, p;
-    volatile int  *count;
-
-    if (!hostdata->connected) {
-	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
-	       "no connected cmd\n", HOSTNO);
-	return;
-    }
-    
-    if (atari_read_overruns) {
-	p = hostdata->connected->SCp.phase;
-	if (p & SR_IO) {
-	    udelay(10);
-	    if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
-		  (BASR_PHASE_MATCH|BASR_ACK)) ==
-		 (BASR_PHASE_MATCH|BASR_ACK))) {
-		saved_data = NCR5380_read(INPUT_DATA_REG);
-		overrun = 1;
-		DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
-	    }
+	SETUP_HOSTDATA(instance);
+	int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+	unsigned char **data, p;
+	volatile int *count;
+
+	if (!hostdata->connected) {
+		printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+		       "no connected cmd\n", HOSTNO);
+		return;
 	}
-    }
-
-    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
-	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
-	       NCR5380_read(STATUS_REG));
-
-    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-    NCR5380_write(MODE_REG, MR_BASE);
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
-    hostdata->dma_len = 0;
-
-    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
-    count = &(hostdata->connected->SCp.this_residual);
-    *data += transfered;
-    *count -= transfered;
-
-    if (atari_read_overruns) {
-	if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
-	    cnt = toPIO = atari_read_overruns;
-	    if (overrun) {
-		DMA_PRINTK("Got an input overrun, using saved byte\n");
-		*(*data)++ = saved_data;
-		(*count)--;
-		cnt--;
-		toPIO--;
-	    }
-	    DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
-	    NCR5380_transfer_pio(instance, &p, &cnt, data);
-	    *count -= toPIO - cnt;
+
+	if (atari_read_overruns) {
+		p = hostdata->connected->SCp.phase;
+		if (p & SR_IO) {
+			udelay(10);
+			if ((NCR5380_read(BUS_AND_STATUS_REG) &
+			     (BASR_PHASE_MATCH|BASR_ACK)) ==
+			    (BASR_PHASE_MATCH|BASR_ACK)) {
+				saved_data = NCR5380_read(INPUT_DATA_REG);
+				overrun = 1;
+				DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+			}
+		}
+	}
+
+	DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+		   HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+		   NCR5380_read(STATUS_REG));
+
+	(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+	hostdata->dma_len = 0;
+
+	data = (unsigned char **)&hostdata->connected->SCp.ptr;
+	count = &hostdata->connected->SCp.this_residual;
+	*data += transfered;
+	*count -= transfered;
+
+	if (atari_read_overruns) {
+		if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+			cnt = toPIO = atari_read_overruns;
+			if (overrun) {
+				DMA_PRINTK("Got an input overrun, using saved byte\n");
+				*(*data)++ = saved_data;
+				(*count)--;
+				cnt--;
+				toPIO--;
+			}
+			DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+			NCR5380_transfer_pio(instance, &p, &cnt, data);
+			*count -= toPIO - cnt;
+		}
 	}
-    }
 }
 #endif /* REAL_DMA */
 
 
 /*
  * Function : void NCR5380_intr (int irq)
- * 
+ *
  * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- *	from the disconnected queue, and restarting NCR5380_main() 
+ *	from the disconnected queue, and restarting NCR5380_main()
  *	as required.
  *
  * Inputs : int irq, irq that caused this interrupt.
  *
  */
 
-static irqreturn_t NCR5380_intr (int irq, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
 {
-    struct Scsi_Host *instance = first_instance;
-    int done = 1, handled = 0;
-    unsigned char basr;
-
-    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
-
-    /* Look for pending interrupts */
-    basr = NCR5380_read(BUS_AND_STATUS_REG);
-    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
-    /* dispatch to appropriate routine if found and done=0 */
-    if (basr & BASR_IRQ) {
-	NCR_PRINT(NDEBUG_INTR);
-	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
-	    done = 0;
-	    ENABLE_IRQ();
-	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
-	    NCR5380_reselect(instance);
-	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-	}
-	else if (basr & BASR_PARITY_ERROR) {
-	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
-	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-	}
-	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
-	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
-	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-	}
-	else {
-	    /*  
-	     * The rest of the interrupt conditions can occur only during a
-	     * DMA transfer
-	     */
+	struct Scsi_Host *instance = first_instance;
+	int done = 1, handled = 0;
+	unsigned char basr;
+
+	INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+	/* Look for pending interrupts */
+	basr = NCR5380_read(BUS_AND_STATUS_REG);
+	INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+	/* dispatch to appropriate routine if found and done=0 */
+	if (basr & BASR_IRQ) {
+		NCR_PRINT(NDEBUG_INTR);
+		if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+			done = 0;
+			ENABLE_IRQ();
+			INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+			NCR5380_reselect(instance);
+			(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+		} else if (basr & BASR_PARITY_ERROR) {
+			INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+			(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+		} else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+			INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+			(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+		} else {
+			/*
+			 * The rest of the interrupt conditions can occur only during a
+			 * DMA transfer
+			 */
 
 #if defined(REAL_DMA)
-	    /*
-	     * We should only get PHASE MISMATCH and EOP interrupts if we have
-	     * DMA enabled, so do a sanity check based on the current setting
-	     * of the MODE register.
-	     */
-
-	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
-		((basr & BASR_END_DMA_TRANSFER) || 
-		 !(basr & BASR_PHASE_MATCH))) {
-		    
-		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
-		NCR5380_dma_complete( instance );
-		done = 0;
-		ENABLE_IRQ();
-	    } else
+			/*
+			 * We should only get PHASE MISMATCH and EOP interrupts if we have
+			 * DMA enabled, so do a sanity check based on the current setting
+			 * of the MODE register.
+			 */
+
+			if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+			    ((basr & BASR_END_DMA_TRANSFER) ||
+			     !(basr & BASR_PHASE_MATCH))) {
+
+				INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+				NCR5380_dma_complete( instance );
+				done = 0;
+				ENABLE_IRQ();
+			} else
 #endif /* REAL_DMA */
-	    {
+			{
 /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
-		if (basr & BASR_PHASE_MATCH)
-		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
-			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
-			   HOSTNO, basr, NCR5380_read(MODE_REG),
-			   NCR5380_read(STATUS_REG));
-		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-	    }
-	} /* if !(SELECTION || PARITY) */
-	handled = 1;
-    } /* BASR & IRQ */
-    else {
-	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
-	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
-	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
-	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-    }
-    
-    if (!done) {
-	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
-	/* Put a call to NCR5380_main() on the queue... */
-	queue_main();
-    }
-    return IRQ_RETVAL(handled);
+				if (basr & BASR_PHASE_MATCH)
+					printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+					       "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+					       HOSTNO, basr, NCR5380_read(MODE_REG),
+					       NCR5380_read(STATUS_REG));
+				(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+			}
+		} /* if !(SELECTION || PARITY) */
+		handled = 1;
+	} /* BASR & IRQ */ else {
+		printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+		       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+		       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+		(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+
+	if (!done) {
+		INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+		/* Put a call to NCR5380_main() on the queue... */
+		queue_main();
+	}
+	return IRQ_RETVAL(handled);
 }
 
 #ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
 {
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
 # endif
-	switch (cmd->cmnd[0])
-	{
-	    case WRITE:
-	    case WRITE_6:
-	    case WRITE_10:
-		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
-		hostdata->pendingw--;
-		break;
-	    case READ:
-	    case READ_6:
-	    case READ_10:
-		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
-		hostdata->pendingr--;
-		break;
-	}
+		switch (cmd->cmnd[0]) {
+		case WRITE:
+		case WRITE_6:
+		case WRITE_10:
+			hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+			/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+			hostdata->pendingw--;
+			break;
+		case READ:
+		case READ_6:
+		case READ_10:
+			hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+			/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+			hostdata->pendingr--;
+			break;
+		}
 }
 #endif
 
-/* 
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, 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 
- *	IDENTIFY and queue messages. 
+ *	including ARBITRATION, SELECTION, and initial message out for
+ *	IDENTIFY and queue messages.
  *
- * Inputs : instance - instantiation of the 5380 driver on which this 
- * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
- *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ *	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
  *	the command that is presently connected.
- * 
+ *
  * Returns : -1 if selection could not execute for some reason,
- *	0 if selection succeeded or failed because the target 
- * 	did not respond.
+ *	0 if selection succeeded or failed because the target
+ *	did not respond.
  *
- * Side effects : 
- * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ * Side effects :
+ *	If bus busy, arbitration failed, etc, NCR5380_select() will exit
  *		with registers as they should have been on entry - ie
  *		SELECT_ENABLE will be set appropriately, the NCR5380
  *		will cease to drive any SCSI bus signals.
  *
- *	If successful : I_T_L or I_T_L_Q nexus will be established, 
- *		instance->connected will be set to cmd.  
- * 		SELECT interrupt will be disabled.
+ *	If successful : I_T_L or I_T_L_Q nexus will be established,
+ *		instance->connected will be set to cmd.
+ *		SELECT interrupt will be disabled.
  *
- *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *	If failed (no target) : cmd->scsi_done() will be called, and the
  *		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, Scsi_Cmnd *cmd, int tag)
 {
-    SETUP_HOSTDATA(instance);
-    unsigned char tmp[3], phase;
-    unsigned char *data;
-    int len;
-    unsigned long timeout;
-    unsigned long flags;
-
-    hostdata->restart_select = 0;
-    NCR_PRINT(NDEBUG_ARBITRATION);
-    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
-	       instance->this_id);
-
-    /* 
-     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
-     * data bus during SELECTION.
-     */
-
-    local_irq_save(flags);
-    if (hostdata->connected) {
+	SETUP_HOSTDATA(instance);
+	unsigned char tmp[3], phase;
+	unsigned char *data;
+	int len;
+	unsigned long timeout;
+	unsigned long flags;
+
+	hostdata->restart_select = 0;
+	NCR_PRINT(NDEBUG_ARBITRATION);
+	ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+		   instance->this_id);
+
+	/*
+	 * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+	 * data bus during SELECTION.
+	 */
+
+	local_irq_save(flags);
+	if (hostdata->connected) {
+		local_irq_restore(flags);
+		return -1;
+	}
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+
+	/*
+	 * Start arbitration.
+	 */
+
+	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+	NCR5380_write(MODE_REG, MR_ARBITRATE);
+
 	local_irq_restore(flags);
-	return -1;
-    }
-    NCR5380_write(TARGET_COMMAND_REG, 0);
-
-
-    /* 
-     * Start arbitration.
-     */
-    
-    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
-    NCR5380_write(MODE_REG, MR_ARBITRATE);
-
-    local_irq_restore(flags);
-
-    /* Wait for arbitration logic to complete */
-#if NCR_TIMEOUT
-    {
-      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
-
-      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-	   && time_before(jiffies, timeout) && !hostdata->connected)
-	;
-      if (time_after_eq(jiffies, timeout))
-      {
-	printk("scsi : arbitration timeout at %d\n", __LINE__);
-	NCR5380_write(MODE_REG, MR_BASE);
-	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-	return -1;
-      }
-    }
+
+	/* Wait for arbitration logic to complete */
+#if defined(NCR_TIMEOUT)
+	{
+		unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+		       time_before(jiffies, timeout) && !hostdata->connected)
+			;
+		if (time_after_eq(jiffies, timeout)) {
+			printk("scsi : arbitration timeout at %d\n", __LINE__);
+			NCR5380_write(MODE_REG, MR_BASE);
+			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+			return -1;
+		}
+	}
 #else /* NCR_TIMEOUT */
-    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-	 && !hostdata->connected);
+	while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+	       !hostdata->connected)
+		;
 #endif
 
-    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
-
-    if (hostdata->connected) {
-	NCR5380_write(MODE_REG, MR_BASE); 
-	return -1;
-    }
-    /* 
-     * The arbitration delay is 2.2us, but this is a minimum and there is 
-     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
-     * the integral nature of udelay().
-     *
-     */
-
-    udelay(3);
-
-    /* Check for lost arbitration */
-    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
-	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-	hostdata->connected) {
-	NCR5380_write(MODE_REG, MR_BASE); 
-	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
-		   HOSTNO);
-	return -1;
-    }
-
-     /* after/during arbitration, BSY should be asserted.
-	IBM DPES-31080 Version S31Q works now */
-     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
-					 ICR_ASSERT_BSY ) ;
-    
-    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
-	hostdata->connected) {
-	NCR5380_write(MODE_REG, MR_BASE);
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
-		   HOSTNO);
-	return -1;
-    }
+	ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
 
-    /* 
-     * Again, bus clear + bus settle time is 1.2us, however, this is 
-     * a minimum so we'll udelay ceil(1.2)
-     */
+	if (hostdata->connected) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		return -1;
+	}
+	/*
+	 * The arbitration delay is 2.2us, but this is a minimum and there is
+	 * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+	 * the integral nature of udelay().
+	 *
+	 */
+
+	udelay(3);
+
+	/* Check for lost arbitration */
+	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	    (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	    (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	    hostdata->connected) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+			   HOSTNO);
+		return -1;
+	}
+
+	/* after/during arbitration, BSY should be asserted.
+	   IBM DPES-31080 Version S31Q works now */
+	/* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+	NCR5380_write(INITIATOR_COMMAND_REG,
+		      ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	    hostdata->connected) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+			   HOSTNO);
+		return -1;
+	}
+
+	/*
+	 * Again, bus clear + bus settle time is 1.2us, however, this is
+	 * a minimum so we'll udelay ceil(1.2)
+	 */
 
 #ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-    /* ++roman: But some targets (see above :-) seem to need a bit more... */
-    udelay(15);
+	/* ++roman: But some targets (see above :-) seem to need a bit more... */
+	udelay(15);
 #else
-    udelay(2);
+	udelay(2);
 #endif
-    
-    if (hostdata->connected) {
+
+	if (hostdata->connected) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		return -1;
+	}
+
+	ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+	/*
+	 * Now that we have won arbitration, start Selection process, asserting
+	 * the host and target ID's on the SCSI bus.
+	 */
+
+	NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+	/*
+	 * Raise ATN while SEL is true before BSY goes false from arbitration,
+	 * since this is the only way to guarantee that we'll get a MESSAGE OUT
+	 * phase immediately after selection.
+	 */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+		      ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
 	NCR5380_write(MODE_REG, MR_BASE);
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	return -1;
-    }
 
-    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+	/*
+	 * Reselect interrupts must be turned off prior to the dropping of BSY,
+	 * otherwise we will trigger an interrupt.
+	 */
+
+	if (hostdata->connected) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		return -1;
+	}
 
-    /* 
-     * Now that we have won arbitration, start Selection process, asserting 
-     * the host and target ID's on the SCSI bus.
-     */
+	NCR5380_write(SELECT_ENABLE_REG, 0);
+
+	/*
+	 * The initiator shall then wait at least two deskew delays and release
+	 * the BSY signal.
+	 */
+	udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+	/* Reset BSY */
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+		      ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+	/*
+	 * Something weird happens when we cease to drive BSY - looks
+	 * like the board/chip is letting us do another read before the
+	 * appropriate propagation delay has expired, and we're confusing
+	 * a BSY signal from ourselves as the target's response to SELECTION.
+	 *
+	 * A small delay (the 'C++' frontend breaks the pipeline with an
+	 * unnecessary jump, making it work on my 386-33/Trantor T128, the
+	 * tighter 'C' code breaks and requires this) solves the problem -
+	 * the 1 us delay is arbitrary, and only used because this delay will
+	 * be the same on other platforms and since it works here, it should
+	 * work there.
+	 *
+	 * wingel suggests that this could be due to failing to wait
+	 * one deskew delay.
+	 */
 
-    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+	udelay(1);
 
-    /* 
-     * Raise ATN while SEL is true before BSY goes false from arbitration,
-     * since this is the only way to guarantee that we'll get a MESSAGE OUT
-     * phase immediately after selection.
-     */
+	SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
 
-    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
-	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
-    NCR5380_write(MODE_REG, MR_BASE);
+	/*
+	 * The SCSI specification calls for a 250 ms timeout for the actual
+	 * selection.
+	 */
 
-    /* 
-     * Reselect interrupts must be turned off prior to the dropping of BSY,
-     * otherwise we will trigger an interrupt.
-     */
+	timeout = jiffies + 25;
 
-    if (hostdata->connected) {
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	return -1;
-    }
-
-    NCR5380_write(SELECT_ENABLE_REG, 0);
-
-    /*
-     * The initiator shall then wait at least two deskew delays and release 
-     * the BSY signal.
-     */
-    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
-
-    /* Reset BSY */
-    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
-	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
-
-    /* 
-     * Something weird happens when we cease to drive BSY - looks
-     * like the board/chip is letting us do another read before the 
-     * appropriate propagation delay has expired, and we're confusing
-     * a BSY signal from ourselves as the target's response to SELECTION.
-     *
-     * A small delay (the 'C++' frontend breaks the pipeline with an
-     * unnecessary jump, making it work on my 386-33/Trantor T128, the
-     * tighter 'C' code breaks and requires this) solves the problem - 
-     * the 1 us delay is arbitrary, and only used because this delay will 
-     * be the same on other platforms and since it works here, it should 
-     * work there.
-     *
-     * wingel suggests that this could be due to failing to wait
-     * one deskew delay.
-     */
-
-    udelay(1);
-
-    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
-
-    /* 
-     * The SCSI specification calls for a 250 ms timeout for the actual 
-     * selection.
-     */
-
-    timeout = jiffies + 25; 
-
-    /* 
-     * XXX very interesting - we're seeing a bounce where the BSY we 
-     * asserted is being reflected / still asserted (propagation delay?)
-     * and it's detecting as true.  Sigh.
-     */
+	/*
+	 * XXX very interesting - we're seeing a bounce where the BSY we
+	 * asserted is being reflected / still asserted (propagation delay?)
+	 * and it's detecting as true.  Sigh.
+	 */
 
 #if 0
-    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
-     * IO while SEL is true. But again, there are some disks out the in the
-     * world that do that nevertheless. (Somebody claimed that this announces
-     * reselection capability of the target.) So we better skip that test and
-     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
-     */
-
-    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & 
-	(SR_BSY | SR_IO)));
-
-    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
-	    (SR_SEL | SR_IO)) {
-	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	    NCR5380_reselect(instance);
-	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
-		    HOSTNO);
-	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-	    return -1;
-    }
+	/* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+	 * IO while SEL is true. But again, there are some disks out the in the
+	 * world that do that nevertheless. (Somebody claimed that this announces
+	 * reselection capability of the target.) So we better skip that test and
+	 * only wait for BSY... (Famous german words: Der KlÃ¼gere gibt nach :-)
+	 */
+
+	while (time_before(jiffies, timeout) &&
+	       !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
+		;
+
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		NCR5380_reselect(instance);
+		printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		       HOSTNO);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		return -1;
+	}
 #else
-    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+	while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
+		;
 #endif
 
-    /* 
-     * No less than two deskew delays after the initiator detects the 
-     * BSY signal is true, it shall release the SEL signal and may 
-     * change the DATA BUS.                                     -wingel
-     */
+	/*
+	 * No less than two deskew delays after the initiator detects the
+	 * BSY signal is true, it shall release the SEL signal and may
+	 * change the DATA BUS.                                     -wingel
+	 */
 
-    udelay(1);
+	udelay(1);
 
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
 
-    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	if (hostdata->targets_present & (1 << cmd->device->id)) {
-	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
-	    if (hostdata->restart_select)
-		printk(KERN_NOTICE "\trestart select\n");
-	    NCR_PRINT(NDEBUG_ANY);
-	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-	    return -1;
-	}
-	cmd->result = DID_BAD_TARGET << 16;
+	if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		if (hostdata->targets_present & (1 << cmd->device->id)) {
+			printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+			if (hostdata->restart_select)
+				printk(KERN_NOTICE "\trestart select\n");
+			NCR_PRINT(NDEBUG_ANY);
+			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+			return -1;
+		}
+		cmd->result = DID_BAD_TARGET << 16;
 #ifdef NCR5380_STATS
-	collect_stats(hostdata, cmd);
+		collect_stats(hostdata, cmd);
 #endif
 #ifdef SUPPORT_TAGS
-	cmd_free_tag( cmd );
+		cmd_free_tag(cmd);
 #endif
-	cmd->scsi_done(cmd);
-	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
-	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-	return 0;
-    } 
-
-    hostdata->targets_present |= (1 << cmd->device->id);
-
-    /*
-     * Since we followed the SCSI spec, and raised ATN while SEL 
-     * was true but before BSY was false during selection, the information
-     * transfer phase should be a MESSAGE OUT phase so that we can send the
-     * IDENTIFY message.
-     * 
-     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
-     * message (2 bytes) with a tag ID that we increment with every command
-     * until it wraps back to 0.
-     *
-     * XXX - it turns out that there are some broken SCSI-II devices,
-     *	     which claim to support tagged queuing but fail when more than
-     *	     some number of commands are issued at once.
-     */
-
-    /* Wait for start of REQ/ACK handshake */
-    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
-    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
-	       HOSTNO, cmd->device->id);
-    tmp[0] = IDENTIFY(1, cmd->device->lun);
+		cmd->scsi_done(cmd);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		return 0;
+	}
+
+	hostdata->targets_present |= (1 << cmd->device->id);
+
+	/*
+	 * Since we followed the SCSI spec, and raised ATN while SEL
+	 * was true but before BSY was false during selection, the information
+	 * transfer phase should be a MESSAGE OUT phase so that we can send the
+	 * IDENTIFY message.
+	 *
+	 * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+	 * message (2 bytes) with a tag ID that we increment with every command
+	 * until it wraps back to 0.
+	 *
+	 * XXX - it turns out that there are some broken SCSI-II devices,
+	 *	     which claim to support tagged queuing but fail when more than
+	 *	     some number of commands are issued at once.
+	 */
+
+	/* Wait for start of REQ/ACK handshake */
+	while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+		;
+
+	SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+		   HOSTNO, cmd->device->id);
+	tmp[0] = IDENTIFY(1, cmd->device->lun);
 
 #ifdef SUPPORT_TAGS
-    if (cmd->tag != TAG_NONE) {
-	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
-	tmp[2] = cmd->tag;
-	len = 3;
-    } else 
-	len = 1;
+	if (cmd->tag != TAG_NONE) {
+		tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+		tmp[2] = cmd->tag;
+		len = 3;
+	} else
+		len = 1;
 #else
-    len = 1;
-    cmd->tag=0;
+	len = 1;
+	cmd->tag = 0;
 #endif /* SUPPORT_TAGS */
 
-    /* Send message(s) */
-    data = tmp;
-    phase = PHASE_MSGOUT;
-    NCR5380_transfer_pio(instance, &phase, &len, &data);
-    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
-    /* XXX need to handle errors here */
-    hostdata->connected = cmd;
+	/* Send message(s) */
+	data = tmp;
+	phase = PHASE_MSGOUT;
+	NCR5380_transfer_pio(instance, &phase, &len, &data);
+	SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+	/* XXX need to handle errors here */
+	hostdata->connected = cmd;
 #ifndef SUPPORT_TAGS
-    hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-#endif    
-
-    initialize_SCp(cmd);
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+#endif
 
+	initialize_SCp(cmd);
 
-    return 0;
+	return 0;
 }
 
-/* 
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
  *      unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using polled I/O
  *
- * Inputs : instance - instance of driver, *phase - pointer to 
- *	what phase is expected, *count - pointer to number of 
+ * Inputs : instance - instance of driver, *phase - pointer to
+ *	what phase is expected, *count - pointer to number of
  *	bytes to transfer, **data - pointer to data pointer.
- * 
+ *
  * Returns : -1 when different phase is entered without transferring
  *	maximum number of bytes, 0 if all bytes are transfered or exit
  *	is in same phase.
  *
- * 	Also, *phase, *count, *data are modified in place.
+ *	Also, *phase, *count, *data are modified in place.
  *
  * XXX Note : handling for bus free may be useful.
  */
 
 /*
- * Note : this code is not as quick as it could be, however it 
+ * Note : this code is not as quick as it could be, however it
  * IS 100% reliable, and for the actual data transfer where speed
  * counts, we will always do a pseudo DMA or DMA transfer.
  */
 
-static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
-				 unsigned char *phase, int *count,
-				 unsigned char **data)
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+				unsigned char *phase, int *count,
+				unsigned char **data)
 {
-    register unsigned char p = *phase, tmp;
-    register int c = *count;
-    register unsigned char *d = *data;
-
-    /* 
-     * The NCR5380 chip will only drive the SCSI bus when the 
-     * phase specified in the appropriate bits of the TARGET COMMAND
-     * REGISTER match the STATUS REGISTER
-     */
-
-    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
-    do {
-	/* 
-	 * Wait for assertion of REQ, after which the phase bits will be 
-	 * valid 
+	register unsigned char p = *phase, tmp;
+	register int c = *count;
+	register unsigned char *d = *data;
+
+	/*
+	 * The NCR5380 chip will only drive the SCSI bus when the
+	 * phase specified in the appropriate bits of the TARGET COMMAND
+	 * REGISTER match the STATUS REGISTER
 	 */
-	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
 
-	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
-	/* Check for phase mismatch */	
-	if ((tmp & PHASE_MASK) != p) {
-	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
-	    NCR_PRINT_PHASE(NDEBUG_PIO);
-	    break;
-	}
+	do {
+		/*
+		 * Wait for assertion of REQ, after which the phase bits will be
+		 * valid
+		 */
+		while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
+			;
 
-	/* Do actual transfer from SCSI bus to / from memory */
-	if (!(p & SR_IO)) 
-	    NCR5380_write(OUTPUT_DATA_REG, *d);
-	else 
-	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+		HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
 
-	++d;
+		/* Check for phase mismatch */
+		if ((tmp & PHASE_MASK) != p) {
+			PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+			NCR_PRINT_PHASE(NDEBUG_PIO);
+			break;
+		}
 
-	/* 
-	 * The SCSI standard suggests that in MSGOUT phase, the initiator
-	 * should drop ATN on the last byte of the message phase
-	 * after REQ has been asserted for the handshake but before
-	 * the initiator raises ACK.
-	 */
+		/* Do actual transfer from SCSI bus to / from memory */
+		if (!(p & SR_IO))
+			NCR5380_write(OUTPUT_DATA_REG, *d);
+		else
+			*d = NCR5380_read(CURRENT_SCSI_DATA_REG);
 
-	if (!(p & SR_IO)) {
-	    if (!((p & SR_MSG) && c > 1)) {
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-		    ICR_ASSERT_DATA);
-		NCR_PRINT(NDEBUG_PIO);
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
-	    } else {
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
-		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
-		NCR_PRINT(NDEBUG_PIO);
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
-	    }
-	} else {
-	    NCR_PRINT(NDEBUG_PIO);
-	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
-	}
+		++d;
 
-	while (NCR5380_read(STATUS_REG) & SR_REQ);
+		/*
+		 * The SCSI standard suggests that in MSGOUT phase, the initiator
+		 * should drop ATN on the last byte of the message phase
+		 * after REQ has been asserted for the handshake but before
+		 * the initiator raises ACK.
+		 */
 
-	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+		if (!(p & SR_IO)) {
+			if (!((p & SR_MSG) && c > 1)) {
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+				NCR_PRINT(NDEBUG_PIO);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+					      ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+			} else {
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+					      ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+				NCR_PRINT(NDEBUG_PIO);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+					      ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+			}
+		} else {
+			NCR_PRINT(NDEBUG_PIO);
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+		}
 
-/*
- * We have several special cases to consider during REQ/ACK handshaking : 
- * 1.  We were in MSGOUT phase, and we are on the last byte of the 
- *	message.  ATN must be dropped as ACK is dropped.
- *
- * 2.  We are in a MSGIN phase, and we are on the last byte of the  
- *	message.  We must exit with ACK asserted, so that the calling
- *	code may raise ATN before dropping ACK to reject the message.
- *
- * 3.  ACK and ATN are clear and the target may proceed as normal.
- */
-	if (!(p == PHASE_MSGIN && c == 1)) {  
-	    if (p == PHASE_MSGOUT && c > 1)
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-	    else
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-	} 
-    } while (--c);
-
-    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
-
-    *count = c;
-    *data = d;
-    tmp = NCR5380_read(STATUS_REG);
-    /* The phase read from the bus is valid if either REQ is (already)
-     * asserted or if ACK hasn't been released yet. The latter is the case if
-     * we're in MSGIN and all wanted bytes have been received. */
-    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
-	*phase = tmp & PHASE_MASK;
-    else 
-	*phase = PHASE_UNKNOWN;
-
-    if (!c || (*phase == p))
-	return 0;
-    else 
-	return -1;
+		while (NCR5380_read(STATUS_REG) & SR_REQ)
+			;
+
+		HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+		/*
+		 * We have several special cases to consider during REQ/ACK handshaking :
+		 * 1.  We were in MSGOUT phase, and we are on the last byte of the
+		 *	message.  ATN must be dropped as ACK is dropped.
+		 *
+		 * 2.  We are in a MSGIN phase, and we are on the last byte of the
+		 *	message.  We must exit with ACK asserted, so that the calling
+		 *	code may raise ATN before dropping ACK to reject the message.
+		 *
+		 * 3.  ACK and ATN are clear and the target may proceed as normal.
+		 */
+		if (!(p == PHASE_MSGIN && c == 1)) {
+			if (p == PHASE_MSGOUT && c > 1)
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+			else
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		}
+	} while (--c);
+
+	PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+	*count = c;
+	*data = d;
+	tmp = NCR5380_read(STATUS_REG);
+	/* The phase read from the bus is valid if either REQ is (already)
+	 * asserted or if ACK hasn't been released yet. The latter is the case if
+	 * we're in MSGIN and all wanted bytes have been received.
+	 */
+	if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+		*phase = tmp & PHASE_MASK;
+	else
+		*phase = PHASE_UNKNOWN;
+
+	if (!c || (*phase == p))
+		return 0;
+	else
+		return -1;
 }
 
 /*
  * Function : do_abort (Scsi_Host *host)
- * 
- * Purpose : abort the currently established nexus.  Should only be 
- * 	called from a routine which can drop into a 
- * 
+ *
+ * Purpose : abort the currently established nexus.  Should only be
+ *	called from a routine which can drop into a
+ *
  * Returns : 0 on success, -1 on failure.
  */
 
-static int do_abort (struct Scsi_Host *host) 
+static int do_abort(struct Scsi_Host *host)
 {
-    unsigned char tmp, *msgptr, phase;
-    int len;
-
-    /* Request message out phase */
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
-    /* 
-     * Wait for the target to indicate a valid phase by asserting 
-     * REQ.  Once this happens, we'll have either a MSGOUT phase 
-     * and can immediately send the ABORT message, or we'll have some 
-     * other phase and will have to source/sink data.
-     * 
-     * We really don't care what value was on the bus or what value
-     * the target sees, so we just handshake.
-     */
-    
-    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
-
-    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
-    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
-		      ICR_ASSERT_ACK);
-	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	unsigned char tmp, *msgptr, phase;
+	int len;
+
+	/* Request message out phase */
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-    }
-   
-    tmp = ABORT;
-    msgptr = &tmp;
-    len = 1;
-    phase = PHASE_MSGOUT;
-    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
-
-    /*
-     * If we got here, and the command completed successfully,
-     * we're about to go into bus free state.
-     */
-
-    return len ? -1 : 0;
+
+	/*
+	 * Wait for the target to indicate a valid phase by asserting
+	 * REQ.  Once this happens, we'll have either a MSGOUT phase
+	 * and can immediately send the ABORT message, or we'll have some
+	 * other phase and will have to source/sink data.
+	 *
+	 * We really don't care what value was on the bus or what value
+	 * the target sees, so we just handshake.
+	 */
+
+	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
+		;
+
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+	if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+			      ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ)
+			;
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	}
+
+	tmp = ABORT;
+	msgptr = &tmp;
+	len = 1;
+	phase = PHASE_MSGOUT;
+	NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+
+	/*
+	 * If we got here, and the command completed successfully,
+	 * we're about to go into bus free state.
+	 */
+
+	return len ? -1 : 0;
 }
 
 #if defined(REAL_DMA)
-/* 
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
  *      unsigned char *phase, int *count, unsigned char **data)
  *
  * Purpose : transfers data in given phase using either real
  *	or pseudo DMA.
  *
- * Inputs : instance - instance of driver, *phase - pointer to 
- *	what phase is expected, *count - pointer to number of 
+ * Inputs : instance - instance of driver, *phase - pointer to
+ *	what phase is expected, *count - pointer to number of
  *	bytes to transfer, **data - pointer to data pointer.
- * 
+ *
  * Returns : -1 when different phase is entered without transferring
  *	maximum number of bytes, 0 if all bytes or transfered or exit
  *	is in same phase.
  *
- * 	Also, *phase, *count, *data are modified in place.
+ *	Also, *phase, *count, *data are modified in place.
  *
  */
 
 
-static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
-				 unsigned char *phase, int *count,
-				 unsigned char **data)
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+				unsigned char *phase, int *count,
+				unsigned char **data)
 {
-    SETUP_HOSTDATA(instance);
-    register int c = *count;
-    register unsigned char p = *phase;
-    register unsigned char *d = *data;
-    unsigned char tmp;
-    unsigned long flags;
-
-    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
-        *phase = tmp;
-        return -1;
-    }
+	SETUP_HOSTDATA(instance);
+	register int c = *count;
+	register unsigned char p = *phase;
+	register unsigned char *d = *data;
+	unsigned char tmp;
+	unsigned long flags;
+
+	if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+		*phase = tmp;
+		return -1;
+	}
 
-    if (atari_read_overruns && (p & SR_IO)) {
-	c -= atari_read_overruns;
-    }
+	if (atari_read_overruns && (p & SR_IO))
+		c -= atari_read_overruns;
 
-    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
-	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
-	       c, (p & SR_IO) ? "to" : "from", d);
+	DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+		   HOSTNO, (p & SR_IO) ? "reading" : "writing",
+		   c, (p & SR_IO) ? "to" : "from", d);
 
-    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
 #ifdef REAL_DMA
-    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
 #endif /* def REAL_DMA  */
 
-    if (IS_A_TT()) {
-	/* On the Medusa, it is a must to initialize the DMA before
-	 * starting the NCR. This is also the cleaner way for the TT.
-	 */
-	local_irq_save(flags);
-	hostdata->dma_len = (p & SR_IO) ?
-	    NCR5380_dma_read_setup(instance, d, c) : 
-	    NCR5380_dma_write_setup(instance, d, c);
-	local_irq_restore(flags);
-    }
-    
-    if (p & SR_IO)
-	NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
-    else {
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
-	NCR5380_write(START_DMA_SEND_REG, 0);
-    }
-
-    if (!IS_A_TT()) {
-	/* On the Falcon, the DMA setup must be done after the last */
-	/* NCR access, else the DMA setup gets trashed!
-	 */
-	local_irq_save(flags);
-	hostdata->dma_len = (p & SR_IO) ?
-	    NCR5380_dma_read_setup(instance, d, c) : 
-	    NCR5380_dma_write_setup(instance, d, c);
-	local_irq_restore(flags);
-    }
-    return 0;
+	if (IS_A_TT()) {
+		/* On the Medusa, it is a must to initialize the DMA before
+		 * starting the NCR. This is also the cleaner way for the TT.
+		 */
+		local_irq_save(flags);
+		hostdata->dma_len = (p & SR_IO) ?
+			NCR5380_dma_read_setup(instance, d, c) :
+			NCR5380_dma_write_setup(instance, d, c);
+		local_irq_restore(flags);
+	}
+
+	if (p & SR_IO)
+		NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+	else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+		NCR5380_write(START_DMA_SEND_REG, 0);
+	}
+
+	if (!IS_A_TT()) {
+		/* On the Falcon, the DMA setup must be done after the last */
+		/* NCR access, else the DMA setup gets trashed!
+		 */
+		local_irq_save(flags);
+		hostdata->dma_len = (p & SR_IO) ?
+			NCR5380_dma_read_setup(instance, d, c) :
+			NCR5380_dma_write_setup(instance, d, c);
+		local_irq_restore(flags);
+	}
+	return 0;
 }
 #endif /* defined(REAL_DMA) */
 
 /*
  * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
  *
- * Purpose : run through the various SCSI phases and do as the target 
- * 	directs us to.  Operates on the currently connected command, 
+ * Purpose : run through the various SCSI phases and do as the target
+ *	directs us to.  Operates on the currently connected command,
  *	instance->connected.
  *
  * Inputs : instance, instance for which we are doing commands
  *
- * Side effects : SCSI things happen, the disconnected queue will be 
+ * Side effects : SCSI things happen, the disconnected queue will be
  *	modified if a command disconnects, *instance->connected will
  *	change.
  *
- * XXX Note : we need to watch for bus free or a reset condition here 
- * 	to recover from an unexpected bus free condition.
+ * XXX Note : we need to watch for bus free or a reset condition here
+ *	to recover from an unexpected bus free condition.
  */
- 
-static void NCR5380_information_transfer (struct Scsi_Host *instance)
+
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
 {
-    SETUP_HOSTDATA(instance);
-    unsigned long flags;
-    unsigned char msgout = NOP;
-    int sink = 0;
-    int len;
+	SETUP_HOSTDATA(instance);
+	unsigned long flags;
+	unsigned char msgout = NOP;
+	int sink = 0;
+	int len;
 #if defined(REAL_DMA)
-    int transfersize;
+	int transfersize;
 #endif
-    unsigned char *data;
-    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
-    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+	unsigned char *data;
+	unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
+	Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+	while (1) {
+		tmp = NCR5380_read(STATUS_REG);
+		/* We only have a valid SCSI phase when REQ is asserted */
+		if (tmp & SR_REQ) {
+			phase = (tmp & PHASE_MASK);
+			if (phase != old_phase) {
+				old_phase = phase;
+				NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+			}
 
-    while (1) {
-	tmp = NCR5380_read(STATUS_REG);
-	/* We only have a valid SCSI phase when REQ is asserted */
-	if (tmp & SR_REQ) {
-	    phase = (tmp & PHASE_MASK); 
-	    if (phase != old_phase) {
-		old_phase = phase;
-		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
-	    }
-	    
-	    if (sink && (phase != PHASE_MSGOUT)) {
-		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
-		    ICR_ASSERT_ACK);
-		while (NCR5380_read(STATUS_REG) & SR_REQ);
-		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-		    ICR_ASSERT_ATN);
-		sink = 0;
-		continue;
-	    }
-
-	    switch (phase) {
-	    case PHASE_DATAOUT:
+			if (sink && (phase != PHASE_MSGOUT)) {
+				NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+					      ICR_ASSERT_ACK);
+				while (NCR5380_read(STATUS_REG) & SR_REQ)
+					;
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+					      ICR_ASSERT_ATN);
+				sink = 0;
+				continue;
+			}
+
+			switch (phase) {
+			case PHASE_DATAOUT:
 #if (NDEBUG & NDEBUG_NO_DATAOUT)
-		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
-		       "aborted\n", HOSTNO);
-		sink = 1;
-		do_abort(instance);
-		cmd->result = DID_ERROR  << 16;
-		cmd->done(cmd);
-		return;
+				printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+				       "aborted\n", HOSTNO);
+				sink = 1;
+				do_abort(instance);
+				cmd->result = DID_ERROR << 16;
+				cmd->done(cmd);
+				return;
 #endif
-	    case PHASE_DATAIN:
-		/* 
-		 * If there is no room left in the current buffer in the
-		 * scatter-gather list, move onto the next one.
-		 */
-
-		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
-		    ++cmd->SCp.buffer;
-		    --cmd->SCp.buffers_residual;
-		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
-		    cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
-				   cmd->SCp.buffer->offset;
-		    /* ++roman: Try to merge some scatter-buffers if
-		     * they are at contiguous physical addresses.
-		     */
-		    merge_contiguous_buffers( cmd );
-		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
-			       HOSTNO, cmd->SCp.this_residual,
-			       cmd->SCp.buffers_residual);
-		}
-
-		/*
-		 * The preferred transfer method is going to be 
-		 * PSEUDO-DMA for systems that are strictly PIO,
-		 * since we can let the hardware do the handshaking.
-		 *
-		 * For this to work, we need to know the transfersize
-		 * ahead of time, since the pseudo-DMA code will sit
-		 * in an unconditional loop.
-		 */
-
-/* ++roman: I suggest, this should be
- *   #if def(REAL_DMA)
- * instead of leaving REAL_DMA out.
- */
+			case PHASE_DATAIN:
+				/*
+				 * If there is no room left in the current buffer in the
+				 * scatter-gather list, move onto the next one.
+				 */
+
+				if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+					++cmd->SCp.buffer;
+					--cmd->SCp.buffers_residual;
+					cmd->SCp.this_residual = cmd->SCp.buffer->length;
+					cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
+						   cmd->SCp.buffer->offset;
+					/* ++roman: Try to merge some scatter-buffers if
+					 * they are at contiguous physical addresses.
+					 */
+					merge_contiguous_buffers(cmd);
+					INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+						   HOSTNO, cmd->SCp.this_residual,
+						   cmd->SCp.buffers_residual);
+				}
+
+				/*
+				 * The preferred transfer method is going to be
+				 * PSEUDO-DMA for systems that are strictly PIO,
+				 * since we can let the hardware do the handshaking.
+				 *
+				 * For this to work, we need to know the transfersize
+				 * ahead of time, since the pseudo-DMA code will sit
+				 * in an unconditional loop.
+				 */
+
+				/* ++roman: I suggest, this should be
+				 *   #if def(REAL_DMA)
+				 * instead of leaving REAL_DMA out.
+				 */
 
 #if defined(REAL_DMA)
-		if (!cmd->device->borken &&
-		    (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
-		    len = transfersize;
-		    cmd->SCp.phase = phase;
-		    if (NCR5380_transfer_dma(instance, &phase,
-			&len, (unsigned char **) &cmd->SCp.ptr)) {
-			/*
-			 * If the watchdog timer fires, all future
-			 * accesses to this device will use the
-			 * polled-IO. */ 
-			printk(KERN_NOTICE "scsi%d: switching target %d "
-			       "lun %d to slow handshake\n", HOSTNO,
-			       cmd->device->id, cmd->device->lun);
-			cmd->device->borken = 1;
-			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-			    ICR_ASSERT_ATN);
-			sink = 1;
-			do_abort(instance);
-			cmd->result = DID_ERROR  << 16;
-			cmd->done(cmd);
-			/* XXX - need to source or sink data here, as appropriate */
-		    } else {
+				if (!cmd->device->borken &&
+				    (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+					len = transfersize;
+					cmd->SCp.phase = phase;
+					if (NCR5380_transfer_dma(instance, &phase,
+					    &len, (unsigned char **)&cmd->SCp.ptr)) {
+						/*
+						 * If the watchdog timer fires, all future
+						 * accesses to this device will use the
+						 * polled-IO. */
+						printk(KERN_NOTICE "scsi%d: switching target %d "
+							   "lun %d to slow handshake\n", HOSTNO,
+							   cmd->device->id, cmd->device->lun);
+						cmd->device->borken = 1;
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+							ICR_ASSERT_ATN);
+						sink = 1;
+						do_abort(instance);
+						cmd->result = DID_ERROR << 16;
+						cmd->done(cmd);
+						/* XXX - need to source or sink data here, as appropriate */
+					} else {
 #ifdef REAL_DMA
-			/* ++roman: When using real DMA,
-			 * information_transfer() should return after
-			 * starting DMA since it has nothing more to
-			 * do.
-			 */
-			return;
-#else			
-			cmd->SCp.this_residual -= transfersize - len;
+						/* ++roman: When using real DMA,
+						 * information_transfer() should return after
+						 * starting DMA since it has nothing more to
+						 * do.
+						 */
+						return;
+#else
+						cmd->SCp.this_residual -= transfersize - len;
 #endif
-		    }
-		} else
+					}
+				} else
 #endif /* defined(REAL_DMA) */
-		  NCR5380_transfer_pio(instance, &phase, 
-		    (int *) &cmd->SCp.this_residual, (unsigned char **)
-		    &cmd->SCp.ptr);
-		break;
-	    case PHASE_MSGIN:
-		len = 1;
-		data = &tmp;
-		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
-		NCR5380_transfer_pio(instance, &phase, &len, &data);
-		cmd->SCp.Message = tmp;
-
-		switch (tmp) {
-		/*
-		 * Linking lets us reduce the time required to get the 
-		 * next command out to the device, hopefully this will
-		 * mean we don't waste another revolution due to the delays
-		 * required by ARBITRATION and another SELECTION.
-		 *
-		 * In the current implementation proposal, low level drivers
-		 * merely have to start the next command, pointed to by 
-		 * next_link, done() is called as with unlinked commands.
-		 */
+					NCR5380_transfer_pio(instance, &phase,
+							     (int *)&cmd->SCp.this_residual,
+							     (unsigned char **)&cmd->SCp.ptr);
+				break;
+			case PHASE_MSGIN:
+				len = 1;
+				data = &tmp;
+				NCR5380_write(SELECT_ENABLE_REG, 0);	/* disable reselects */
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				cmd->SCp.Message = tmp;
+
+				switch (tmp) {
+				/*
+				 * Linking lets us reduce the time required to get the
+				 * next command out to the device, hopefully this will
+				 * mean we don't waste another revolution due to the delays
+				 * required by ARBITRATION and another SELECTION.
+				 *
+				 * In the current implementation proposal, low level drivers
+				 * merely have to start the next command, pointed to by
+				 * next_link, done() is called as with unlinked commands.
+				 */
 #ifdef LINKED
-		case LINKED_CMD_COMPLETE:
-		case LINKED_FLG_CMD_COMPLETE:
-		    /* Accept message by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    
-		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
-			       "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
-		    /* Enable reselect interrupts */
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    /*
-		     * Sanity check : A linked command should only terminate
-		     * with one of these messages if there are more linked
-		     * commands available.
-		     */
-
-		    if (!cmd->next_link) {
-			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
-				"linked command complete, no next_link\n",
-				HOSTNO, cmd->device->id, cmd->device->lun);
-			    sink = 1;
-			    do_abort (instance);
-			    return;
-		    }
-
-		    initialize_SCp(cmd->next_link);
-		    /* The next command is still part of this process; copy it
-		     * and don't free it! */
-		    cmd->next_link->tag = cmd->tag;
-		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
-		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
-			       "done, calling scsi_done().\n",
-			       HOSTNO, cmd->device->id, cmd->device->lun);
+				case LINKED_CMD_COMPLETE:
+				case LINKED_FLG_CMD_COMPLETE:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+					LNK_PRINTK("scsi%d: target %d lun %d linked command "
+						   "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+					/* Enable reselect interrupts */
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					/*
+					 * Sanity check : A linked command should only terminate
+					 * with one of these messages if there are more linked
+					 * commands available.
+					 */
+
+					if (!cmd->next_link) {
+						 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+							"linked command complete, no next_link\n",
+							HOSTNO, cmd->device->id, cmd->device->lun);
+						sink = 1;
+						do_abort(instance);
+						return;
+					}
+
+					initialize_SCp(cmd->next_link);
+					/* The next command is still part of this process; copy it
+					 * and don't free it! */
+					cmd->next_link->tag = cmd->tag;
+					cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+					LNK_PRINTK("scsi%d: target %d lun %d linked request "
+						   "done, calling scsi_done().\n",
+						   HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef NCR5380_STATS
-		    collect_stats(hostdata, cmd);
+					collect_stats(hostdata, cmd);
 #endif
-		    cmd->scsi_done(cmd);
-		    cmd = hostdata->connected;
-		    break;
+					cmd->scsi_done(cmd);
+					cmd = hostdata->connected;
+					break;
 #endif /* def LINKED */
-		case ABORT:
-		case COMMAND_COMPLETE: 
-		    /* Accept message by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    /* ++guenther: possible race with Falcon locking */
-		    falcon_dont_release++;
-		    hostdata->connected = NULL;
-		    QU_PRINTK("scsi%d: command for target %d, lun %d "
-			      "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+				case ABORT:
+				case COMMAND_COMPLETE:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					/* ++guenther: possible race with Falcon locking */
+					falcon_dont_release++;
+					hostdata->connected = NULL;
+					QU_PRINTK("scsi%d: command for target %d, lun %d "
+						  "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
 #ifdef SUPPORT_TAGS
-		    cmd_free_tag( cmd );
-		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
-			/* Turn a QUEUE FULL status into BUSY, I think the
-			 * mid level cannot handle QUEUE FULL :-( (The
-			 * command is retried after BUSY). Also update our
-			 * queue size to the number of currently issued
-			 * commands now.
-			 */
-			/* ++Andreas: the mid level code knows about
-			   QUEUE_FULL now. */
-			TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
-			TAG_PRINTK("scsi%d: target %d lun %d returned "
-				   "QUEUE_FULL after %d commands\n",
-				   HOSTNO, cmd->device->id, cmd->device->lun,
-				   ta->nr_allocated);
-			if (ta->queue_size > ta->nr_allocated)
-			    ta->nr_allocated = ta->queue_size;
-		    }
+					cmd_free_tag(cmd);
+					if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+						/* Turn a QUEUE FULL status into BUSY, I think the
+						 * mid level cannot handle QUEUE FULL :-( (The
+						 * command is retried after BUSY). Also update our
+						 * queue size to the number of currently issued
+						 * commands now.
+						 */
+						/* ++Andreas: the mid level code knows about
+						   QUEUE_FULL now. */
+						TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+						TAG_PRINTK("scsi%d: target %d lun %d returned "
+							   "QUEUE_FULL after %d commands\n",
+							   HOSTNO, cmd->device->id, cmd->device->lun,
+							   ta->nr_allocated);
+						if (ta->queue_size > ta->nr_allocated)
+							ta->nr_allocated = ta->queue_size;
+					}
 #else
-		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
-		    /* Enable reselect interrupts */
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
-		    /* 
-		     * I'm not sure what the correct thing to do here is : 
-		     * 
-		     * If the command that just executed is NOT a request 
-		     * sense, the obvious thing to do is to set the result
-		     * code to the values of the stored parameters.
-		     * 
-		     * If it was a REQUEST SENSE command, we need some way to
-		     * differentiate between the failure code of the original
-		     * and the failure code of the REQUEST sense - the obvious
-		     * case is success, where we fall through and leave the
-		     * result code unchanged.
-		     * 
-		     * The non-obvious place is where the REQUEST SENSE failed
-		     */
-
-		    if (cmd->cmnd[0] != REQUEST_SENSE) 
-			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
-		    else if (status_byte(cmd->SCp.Status) != GOOD)
-			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-		    
-#ifdef AUTOSENSE
-		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
-			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
-			ASEN_PRINTK("scsi%d: performing request sense\n",
-				    HOSTNO);
-			cmd->cmnd[0] = REQUEST_SENSE;
-			cmd->cmnd[1] &= 0xe0;
-			cmd->cmnd[2] = 0;
-			cmd->cmnd[3] = 0;
-			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
-			cmd->cmnd[5] = 0;
-			cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-			cmd->use_sg = 0;
-			/* this is initialized from initialize_SCp 
-			cmd->SCp.buffer = NULL;
-			cmd->SCp.buffers_residual = 0;
-			*/
-			cmd->request_buffer = (char *) cmd->sense_buffer;
-			cmd->request_bufflen = sizeof(cmd->sense_buffer);
+					/* Enable reselect interrupts */
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+					/*
+					 * I'm not sure what the correct thing to do here is :
+					 *
+					 * If the command that just executed is NOT a request
+					 * sense, the obvious thing to do is to set the result
+					 * code to the values of the stored parameters.
+					 *
+					 * If it was a REQUEST SENSE command, we need some way to
+					 * differentiate between the failure code of the original
+					 * and the failure code of the REQUEST sense - the obvious
+					 * case is success, where we fall through and leave the
+					 * result code unchanged.
+					 *
+					 * The non-obvious place is where the REQUEST SENSE failed
+					 */
+
+					if (cmd->cmnd[0] != REQUEST_SENSE)
+						cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+					else if (status_byte(cmd->SCp.Status) != GOOD)
+						cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
 
-			local_irq_save(flags);
-			LIST(cmd,hostdata->issue_queue);
-			NEXT(cmd) = hostdata->issue_queue;
-		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
-		        local_irq_restore(flags);
-			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
-				  "issue queue\n", H_NO(cmd));
-		   } else
+#ifdef AUTOSENSE
+					if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+					    (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+						ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
+						cmd->cmnd[0] = REQUEST_SENSE;
+						cmd->cmnd[1] &= 0xe0;
+						cmd->cmnd[2] = 0;
+						cmd->cmnd[3] = 0;
+						cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+						cmd->cmnd[5] = 0;
+						cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+						cmd->use_sg = 0;
+						/* this is initialized from initialize_SCp
+						cmd->SCp.buffer = NULL;
+						cmd->SCp.buffers_residual = 0;
+						*/
+						cmd->request_buffer = (char *) cmd->sense_buffer;
+						cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+						local_irq_save(flags);
+						LIST(cmd,hostdata->issue_queue);
+						SET_NEXT(cmd, hostdata->issue_queue);
+						hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+						local_irq_restore(flags);
+						QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+							  "issue queue\n", H_NO(cmd));
+					} else
 #endif /* def AUTOSENSE */
-		   {
+					{
 #ifdef NCR5380_STATS
-		       collect_stats(hostdata, cmd);
+						collect_stats(hostdata, cmd);
 #endif
-		       cmd->scsi_done(cmd);
-		    }
-
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    /* 
-		     * Restore phase bits to 0 so an interrupted selection, 
-		     * arbitration can resume.
-		     */
-		    NCR5380_write(TARGET_COMMAND_REG, 0);
-		    
-		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-			barrier();
-
-		    falcon_dont_release--;
-		    /* ++roman: For Falcon SCSI, release the lock on the
-		     * ST-DMA here if no other commands are waiting on the
-		     * disconnected queue.
-		     */
-		    falcon_release_lock_if_possible( hostdata );
-		    return;
-		case MESSAGE_REJECT:
-		    /* Accept message by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    /* Enable reselect interrupts */
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    switch (hostdata->last_message) {
-		    case HEAD_OF_QUEUE_TAG:
-		    case ORDERED_QUEUE_TAG:
-		    case SIMPLE_QUEUE_TAG:
-			/* The target obviously doesn't support tagged
-			 * queuing, even though it announced this ability in
-			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
-			 * clear 'tagged_supported' and lock the LUN, since
-			 * the command is treated as untagged further on.
-			 */
-			cmd->device->tagged_supported = 0;
-			hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-			cmd->tag = TAG_NONE;
-			TAG_PRINTK("scsi%d: target %d lun %d rejected "
-				   "QUEUE_TAG message; tagged queuing "
-				   "disabled\n",
-				   HOSTNO, cmd->device->id, cmd->device->lun);
-			break;
-		    }
-		    break;
-		case DISCONNECT:
-		    /* Accept message by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    local_irq_save(flags);
-		    cmd->device->disconnect = 1;
-		    LIST(cmd,hostdata->disconnected_queue);
-		    NEXT(cmd) = hostdata->disconnected_queue;
-		    hostdata->connected = NULL;
-		    hostdata->disconnected_queue = cmd;
-		    local_irq_restore(flags);
-		    QU_PRINTK("scsi%d: command for target %d lun %d was "
-			      "moved from connected to the "
-			      "disconnected_queue\n", HOSTNO, 
-			      cmd->device->id, cmd->device->lun);
-		    /* 
-		     * Restore phase bits to 0 so an interrupted selection, 
-		     * arbitration can resume.
-		     */
-		    NCR5380_write(TARGET_COMMAND_REG, 0);
-
-		    /* Enable reselect interrupts */
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    /* Wait for bus free to avoid nasty timeouts */
-		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
-		    	barrier();
-		    return;
-		/* 
-		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
-		 * operation, in violation of the SCSI spec so we can safely 
-		 * ignore SAVE/RESTORE pointers calls.
-		 *
-		 * Unfortunately, some disks violate the SCSI spec and 
-		 * don't issue the required SAVE_POINTERS message before
-		 * disconnecting, and we have to break spec to remain 
-		 * compatible.
-		 */
-		case SAVE_POINTERS:
-		case RESTORE_POINTERS:
-		    /* Accept message by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-		    /* Enable reselect interrupts */
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    break;
-		case EXTENDED_MESSAGE:
-/* 
- * Extended messages are sent in the following format :
- * Byte 	
- * 0		EXTENDED_MESSAGE == 1
- * 1		length (includes one byte for code, doesn't 
- *		include first two bytes)
- * 2 		code
- * 3..length+1	arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.  
- */
-		    extended_msg[0] = EXTENDED_MESSAGE;
-		    /* Accept first byte by clearing ACK */
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
-
-		    len = 2;
-		    data = extended_msg + 1;
-		    phase = PHASE_MSGIN;
-		    NCR5380_transfer_pio(instance, &phase, &len, &data);
-		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
-			       (int)extended_msg[1], (int)extended_msg[2]);
-
-		    if (!len && extended_msg[1] <= 
-			(sizeof (extended_msg) - 1)) {
-			/* Accept third byte by clearing ACK */
-			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-			len = extended_msg[1] - 1;
-			data = extended_msg + 3;
-			phase = PHASE_MSGIN;
-
-			NCR5380_transfer_pio(instance, &phase, &len, &data);
-			EXT_PRINTK("scsi%d: message received, residual %d\n",
-				   HOSTNO, len);
-
-			switch (extended_msg[2]) {
-			case EXTENDED_SDTR:
-			case EXTENDED_WDTR:
-			case EXTENDED_MODIFY_DATA_POINTER:
-			case EXTENDED_EXTENDED_IDENTIFY:
-			    tmp = 0;
-			}
-		    } else if (len) {
-			printk(KERN_NOTICE "scsi%d: error receiving "
-			       "extended message\n", HOSTNO);
-			tmp = 0;
-		    } else {
-			printk(KERN_NOTICE "scsi%d: extended message "
-			       "code %02x length %d is too long\n",
-			       HOSTNO, extended_msg[2], extended_msg[1]);
-			tmp = 0;
-		    }
-		/* Fall through to reject message */
-
-		/* 
-  		 * If we get something weird that we aren't expecting, 
- 		 * reject it.
-		 */
-		default:
-		    if (!tmp) {
-			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
-			spi_print_msg(extended_msg);
-			printk("\n");
-		    } else if (tmp != EXTENDED_MESSAGE)
-			printk(KERN_DEBUG "scsi%d: rejecting unknown "
-			       "message %02x from target %d, lun %d\n",
-			       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
-		    else
-			printk(KERN_DEBUG "scsi%d: rejecting unknown "
-			       "extended message "
-			       "code %02x, length %d from target %d, lun %d\n",
-			       HOSTNO, extended_msg[1], extended_msg[0],
-			       cmd->device->id, cmd->device->lun);
-   
-
-		    msgout = MESSAGE_REJECT;
-		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
-			ICR_ASSERT_ATN);
-		    break;
-		} /* switch (tmp) */
-		break;
-	    case PHASE_MSGOUT:
-		len = 1;
-		data = &msgout;
-		hostdata->last_message = msgout;
-		NCR5380_transfer_pio(instance, &phase, &len, &data);
-		if (msgout == ABORT) {
+						cmd->scsi_done(cmd);
+					}
+
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					/*
+					 * Restore phase bits to 0 so an interrupted selection,
+					 * arbitration can resume.
+					 */
+					NCR5380_write(TARGET_COMMAND_REG, 0);
+
+					while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+						barrier();
+
+					falcon_dont_release--;
+					/* ++roman: For Falcon SCSI, release the lock on the
+					 * ST-DMA here if no other commands are waiting on the
+					 * disconnected queue.
+					 */
+					falcon_release_lock_if_possible(hostdata);
+					return;
+				case MESSAGE_REJECT:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					/* Enable reselect interrupts */
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					switch (hostdata->last_message) {
+					case HEAD_OF_QUEUE_TAG:
+					case ORDERED_QUEUE_TAG:
+					case SIMPLE_QUEUE_TAG:
+						/* The target obviously doesn't support tagged
+						 * queuing, even though it announced this ability in
+						 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+						 * clear 'tagged_supported' and lock the LUN, since
+						 * the command is treated as untagged further on.
+						 */
+						cmd->device->tagged_supported = 0;
+						hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+						cmd->tag = TAG_NONE;
+						TAG_PRINTK("scsi%d: target %d lun %d rejected "
+							   "QUEUE_TAG message; tagged queuing "
+							   "disabled\n",
+							   HOSTNO, cmd->device->id, cmd->device->lun);
+						break;
+					}
+					break;
+				case DISCONNECT:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					local_irq_save(flags);
+					cmd->device->disconnect = 1;
+					LIST(cmd,hostdata->disconnected_queue);
+					SET_NEXT(cmd, hostdata->disconnected_queue);
+					hostdata->connected = NULL;
+					hostdata->disconnected_queue = cmd;
+					local_irq_restore(flags);
+					QU_PRINTK("scsi%d: command for target %d lun %d was "
+						  "moved from connected to the "
+						  "disconnected_queue\n", HOSTNO,
+						  cmd->device->id, cmd->device->lun);
+					/*
+					 * Restore phase bits to 0 so an interrupted selection,
+					 * arbitration can resume.
+					 */
+					NCR5380_write(TARGET_COMMAND_REG, 0);
+
+					/* Enable reselect interrupts */
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					/* Wait for bus free to avoid nasty timeouts */
+					while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+						barrier();
+					return;
+					/*
+					 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+					 * operation, in violation of the SCSI spec so we can safely
+					 * ignore SAVE/RESTORE pointers calls.
+					 *
+					 * Unfortunately, some disks violate the SCSI spec and
+					 * don't issue the required SAVE_POINTERS message before
+					 * disconnecting, and we have to break spec to remain
+					 * compatible.
+					 */
+				case SAVE_POINTERS:
+				case RESTORE_POINTERS:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					/* Enable reselect interrupts */
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					break;
+				case EXTENDED_MESSAGE:
+					/*
+					 * Extended messages are sent in the following format :
+					 * Byte
+					 * 0		EXTENDED_MESSAGE == 1
+					 * 1		length (includes one byte for code, doesn't
+					 *		include first two bytes)
+					 * 2		code
+					 * 3..length+1	arguments
+					 *
+					 * Start the extended message buffer with the EXTENDED_MESSAGE
+					 * byte, since spi_print_msg() wants the whole thing.
+					 */
+					extended_msg[0] = EXTENDED_MESSAGE;
+					/* Accept first byte by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+					EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+					len = 2;
+					data = extended_msg + 1;
+					phase = PHASE_MSGIN;
+					NCR5380_transfer_pio(instance, &phase, &len, &data);
+					EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+						   (int)extended_msg[1], (int)extended_msg[2]);
+
+					if (!len && extended_msg[1] <=
+					    (sizeof(extended_msg) - 1)) {
+						/* Accept third byte by clearing ACK */
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+						len = extended_msg[1] - 1;
+						data = extended_msg + 3;
+						phase = PHASE_MSGIN;
+
+						NCR5380_transfer_pio(instance, &phase, &len, &data);
+						EXT_PRINTK("scsi%d: message received, residual %d\n",
+							   HOSTNO, len);
+
+						switch (extended_msg[2]) {
+						case EXTENDED_SDTR:
+						case EXTENDED_WDTR:
+						case EXTENDED_MODIFY_DATA_POINTER:
+						case EXTENDED_EXTENDED_IDENTIFY:
+							tmp = 0;
+						}
+					} else if (len) {
+						printk(KERN_NOTICE "scsi%d: error receiving "
+						       "extended message\n", HOSTNO);
+						tmp = 0;
+					} else {
+						printk(KERN_NOTICE "scsi%d: extended message "
+							   "code %02x length %d is too long\n",
+							   HOSTNO, extended_msg[2], extended_msg[1]);
+						tmp = 0;
+					}
+					/* Fall through to reject message */
+
+					/*
+					 * If we get something weird that we aren't expecting,
+					 * reject it.
+					 */
+				default:
+					if (!tmp) {
+						printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+						spi_print_msg(extended_msg);
+						printk("\n");
+					} else if (tmp != EXTENDED_MESSAGE)
+						printk(KERN_DEBUG "scsi%d: rejecting unknown "
+						       "message %02x from target %d, lun %d\n",
+						       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+					else
+						printk(KERN_DEBUG "scsi%d: rejecting unknown "
+						       "extended message "
+						       "code %02x, length %d from target %d, lun %d\n",
+						       HOSTNO, extended_msg[1], extended_msg[0],
+						       cmd->device->id, cmd->device->lun);
+
+
+					msgout = MESSAGE_REJECT;
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+					break;
+				} /* switch (tmp) */
+				break;
+			case PHASE_MSGOUT:
+				len = 1;
+				data = &msgout;
+				hostdata->last_message = msgout;
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				if (msgout == ABORT) {
 #ifdef SUPPORT_TAGS
-		    cmd_free_tag( cmd );
+					cmd_free_tag(cmd);
 #else
-		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
-		    hostdata->connected = NULL;
-		    cmd->result = DID_ERROR << 16;
+					hostdata->connected = NULL;
+					cmd->result = DID_ERROR << 16;
 #ifdef NCR5380_STATS
-		    collect_stats(hostdata, cmd);
+					collect_stats(hostdata, cmd);
 #endif
-		    cmd->scsi_done(cmd);
-		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-		    falcon_release_lock_if_possible( hostdata );
-		    return;
-		}
-		msgout = NOP;
-		break;
-	    case PHASE_CMDOUT:
-		len = cmd->cmd_len;
-		data = cmd->cmnd;
-		/* 
-		 * XXX for performance reasons, on machines with a 
-		 * PSEUDO-DMA architecture we should probably 
-		 * use the dma transfer function.  
-		 */
-		NCR5380_transfer_pio(instance, &phase, &len, 
-		    &data);
-		break;
-	    case PHASE_STATIN:
-		len = 1;
-		data = &tmp;
-		NCR5380_transfer_pio(instance, &phase, &len, &data);
-		cmd->SCp.Status = tmp;
-		break;
-	    default:
-		printk("scsi%d: unknown phase\n", HOSTNO);
-		NCR_PRINT(NDEBUG_ANY);
-	    } /* switch(phase) */
-	} /* if (tmp * SR_REQ) */ 
-    } /* while (1) */
+					cmd->scsi_done(cmd);
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					falcon_release_lock_if_possible(hostdata);
+					return;
+				}
+				msgout = NOP;
+				break;
+			case PHASE_CMDOUT:
+				len = cmd->cmd_len;
+				data = cmd->cmnd;
+				/*
+				 * XXX for performance reasons, on machines with a
+				 * PSEUDO-DMA architecture we should probably
+				 * use the dma transfer function.
+				 */
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				break;
+			case PHASE_STATIN:
+				len = 1;
+				data = &tmp;
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				cmd->SCp.Status = tmp;
+				break;
+			default:
+				printk("scsi%d: unknown phase\n", HOSTNO);
+				NCR_PRINT(NDEBUG_ANY);
+			} /* switch(phase) */
+		} /* if (tmp * SR_REQ) */
+	} /* while (1) */
 }
 
 /*
  * 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 
+ * 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
  *	nexus has been reestablished,
- *	
+ *
  * Inputs : instance - this instance of the NCR5380.
  *
  */
 
 
-static void NCR5380_reselect (struct Scsi_Host *instance)
+static void NCR5380_reselect(struct Scsi_Host *instance)
 {
-    SETUP_HOSTDATA(instance);
-    unsigned char target_mask;
-    unsigned char lun, phase;
-    int len;
+	SETUP_HOSTDATA(instance);
+	unsigned char target_mask;
+	unsigned char lun, phase;
+	int len;
 #ifdef SUPPORT_TAGS
-    unsigned char tag;
+	unsigned char tag;
 #endif
-    unsigned char msg[3];
-    unsigned char *data;
-    Scsi_Cmnd *tmp = NULL, *prev;
-/*    unsigned long flags; */
-
-    /*
-     * Disable arbitration, etc. since the host adapter obviously
-     * lost, and tell an interrupted NCR5380_select() to restart.
-     */
-
-    NCR5380_write(MODE_REG, MR_BASE);
-    hostdata->restart_select = 1;
-
-    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-
-    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
-
-    /* 
-     * At this point, we have detected that our SCSI ID is on the bus,
-     * SEL is true and BSY was false for at least one bus settle delay
-     * (400 ns).
-     *
-     * We must assert BSY ourselves, until the target drops the SEL
-     * signal.
-     */
-
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-    
-    while (NCR5380_read(STATUS_REG) & SR_SEL);
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-    /*
-     * Wait for target to go into MSGIN.
-     */
-
-    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
-    len = 1;
-    data = msg;
-    phase = PHASE_MSGIN;
-    NCR5380_transfer_pio(instance, &phase, &len, &data);
-
-    if (!(msg[0] & 0x80)) {
-	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
-	spi_print_msg(msg);
-	do_abort(instance);
-	return;
-    }
-    lun = (msg[0] & 0x07);
+	unsigned char msg[3];
+	unsigned char *data;
+	Scsi_Cmnd *tmp = NULL, *prev;
+/*	unsigned long flags; */
+
+	/*
+	 * Disable arbitration, etc. since the host adapter obviously
+	 * lost, and tell an interrupted NCR5380_select() to restart.
+	 */
+
+	NCR5380_write(MODE_REG, MR_BASE);
+	hostdata->restart_select = 1;
+
+	target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+	RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+	/*
+	 * At this point, we have detected that our SCSI ID is on the bus,
+	 * SEL is true and BSY was false for at least one bus settle delay
+	 * (400 ns).
+	 *
+	 * We must assert BSY ourselves, until the target drops the SEL
+	 * signal.
+	 */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+	while (NCR5380_read(STATUS_REG) & SR_SEL)
+		;
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	/*
+	 * Wait for target to go into MSGIN.
+	 */
+
+	while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+		;
+
+	len = 1;
+	data = msg;
+	phase = PHASE_MSGIN;
+	NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+	if (!(msg[0] & 0x80)) {
+		printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+		spi_print_msg(msg);
+		do_abort(instance);
+		return;
+	}
+	lun = (msg[0] & 0x07);
 
 #ifdef SUPPORT_TAGS
-    /* If the phase is still MSGIN, the target wants to send some more
-     * messages. In case it supports tagged queuing, this is probably a
-     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
-     */
-    tag = TAG_NONE;
-    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
-	/* Accept previous IDENTIFY message by clearing ACK */
-	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
-	len = 2;
-	data = msg+1;
-	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
-	    msg[1] == SIMPLE_QUEUE_TAG)
-	    tag = msg[2];
-	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
-		   "reselection\n", HOSTNO, target_mask, lun, tag);
-    }
+	/* If the phase is still MSGIN, the target wants to send some more
+	 * messages. In case it supports tagged queuing, this is probably a
+	 * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+	 */
+	tag = TAG_NONE;
+	if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+		/* Accept previous IDENTIFY message by clearing ACK */
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		len = 2;
+		data = msg + 1;
+		if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+		    msg[1] == SIMPLE_QUEUE_TAG)
+			tag = msg[2];
+		TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+			   "reselection\n", HOSTNO, target_mask, lun, tag);
+	}
 #endif
-    
-    /* 
-     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
-     * just reestablished, and remove it from the disconnected queue.
-     */
-
-    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
-	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
-	if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+
+	/*
+	 * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we
+	 * just reestablished, and remove it from the disconnected queue.
+	 */
+
+	for (tmp = (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
-	    && (tag == tmp->tag) 
+		    && (tag == tmp->tag)
 #endif
-	    ) {
-	    /* ++guenther: prevent race with falcon_release_lock */
-	    falcon_dont_release++;
-	    if (prev) {
-		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
-		NEXT(prev) = NEXT(tmp);
-	    } else {
-		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
-		hostdata->disconnected_queue = NEXT(tmp);
-	    }
-	    NEXT(tmp) = NULL;
-	    break;
+		    ) {
+			/* ++guenther: prevent race with falcon_release_lock */
+			falcon_dont_release++;
+			if (prev) {
+				REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+				SET_NEXT(prev, NEXT(tmp));
+			} else {
+				REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+				hostdata->disconnected_queue = NEXT(tmp);
+			}
+			SET_NEXT(tmp, NULL);
+			break;
+		}
 	}
-    }
-    
-    if (!tmp) {
-	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+
+	if (!tmp) {
+		printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
 #ifdef SUPPORT_TAGS
-		"tag %d "
+		       "tag %d "
 #endif
-		"not in disconnected_queue.\n",
-		HOSTNO, target_mask, lun
+		       "not in disconnected_queue.\n",
+		       HOSTNO, target_mask, lun
 #ifdef SUPPORT_TAGS
-		, tag
+		       , tag
 #endif
-		);
-	/* 
-	 * Since we have an established nexus that we can't do anything
-	 * with, we must abort it.  
-	 */
-	do_abort(instance);
-	return;
-    }
+			);
+		/*
+		 * Since we have an established nexus that we can't do anything
+		 * with, we must abort it.
+		 */
+		do_abort(instance);
+		return;
+	}
 
-    /* Accept message by clearing ACK */
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	/* Accept message by clearing ACK */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
-    hostdata->connected = tmp;
-    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
-	       HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
-    falcon_dont_release--;
+	hostdata->connected = tmp;
+	RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+		   HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+	falcon_dont_release--;
 }
 
 
@@ -2626,362 +2677,361 @@ #endif
  *
  * Purpose : abort a command
  *
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
- * 	host byte of the result field to, if zero DID_ABORTED is 
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ *	host byte of the result field to, if zero DID_ABORTED is
  *	used.
  *
  * Returns : 0 - success, -1 on failure.
  *
- * XXX - there is no way to abort the command that is currently 
- * 	 connected, you have to wait for it to complete.  If this is 
+ * XXX - there is no way to abort the command that is currently
+ *	 connected, you have to wait for it to complete.  If this is
  *	 a problem, we could implement longjmp() / setjmp(), setjmp()
- * 	 called where the loop started in NCR5380_main().
+ *	 called where the loop started in NCR5380_main().
  */
 
 static
-int NCR5380_abort (Scsi_Cmnd *cmd)
+int NCR5380_abort(Scsi_Cmnd *cmd)
 {
-    struct Scsi_Host *instance = cmd->device->host;
-    SETUP_HOSTDATA(instance);
-    Scsi_Cmnd *tmp, **prev;
-    unsigned long flags;
+	struct Scsi_Host *instance = cmd->device->host;
+	SETUP_HOSTDATA(instance);
+	Scsi_Cmnd *tmp, **prev;
+	unsigned long flags;
+
+	printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+	scsi_print_command(cmd);
 
-    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
-    scsi_print_command(cmd);
+	NCR5380_print_status(instance);
 
-    NCR5380_print_status (instance);
+	local_irq_save(flags);
 
-    local_irq_save(flags);
-    
-    if (!IS_A_TT() && !falcon_got_lock)
-	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
-	       HOSTNO);
+	if (!IS_A_TT() && !falcon_got_lock)
+		printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+		       HOSTNO);
 
-    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
-		NCR5380_read(BUS_AND_STATUS_REG),
-		NCR5380_read(STATUS_REG));
+	ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		    NCR5380_read(BUS_AND_STATUS_REG),
+		    NCR5380_read(STATUS_REG));
 
 #if 1
-/* 
- * Case 1 : If the command is the currently executing command, 
- * we'll set the aborted flag and return control so that 
- * information transfer routine can exit cleanly.
- */
+	/*
+	 * Case 1 : If the command is the currently executing command,
+	 * we'll set the aborted flag and return control so that
+	 * information transfer routine can exit cleanly.
+	 */
 
-    if (hostdata->connected == cmd) {
+	if (hostdata->connected == cmd) {
 
-	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+		ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+		/*
+		 * We should perform BSY checking, and make sure we haven't slipped
+		 * into BUS FREE.
+		 */
 
-/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
-/* 
- * Since we can't change phases until we've completed the current 
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+		/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+		/*
+		 * Since we can't change phases until we've completed the current
+		 * handshake, we have to source or sink a byte of data if the current
+		 * phase is not MSGOUT.
+		 */
 
-/* 
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */ 
+		/*
+		 * Return control to the executing NCR drive so we can clear the
+		 * aborted flag and get back into our main loop.
+		 */
 
-	if (do_abort(instance) == 0) {
-	  hostdata->aborted = 1;
-	  hostdata->connected = NULL;
-	  cmd->result = DID_ABORT << 16;
+		if (do_abort(instance) == 0) {
+			hostdata->aborted = 1;
+			hostdata->connected = NULL;
+			cmd->result = DID_ABORT << 16;
 #ifdef SUPPORT_TAGS
-	  cmd_free_tag( cmd );
+			cmd_free_tag(cmd);
 #else
-	  hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
-	  local_irq_restore(flags);
-	  cmd->scsi_done(cmd);
-	  falcon_release_lock_if_possible( hostdata );
-	  return SCSI_ABORT_SUCCESS;
-	} else {
-/*	  local_irq_restore(flags); */
-	  printk("scsi%d: abort of connected command failed!\n", HOSTNO);
-	  return SCSI_ABORT_ERROR;
-	} 
-   }
+			local_irq_restore(flags);
+			cmd->scsi_done(cmd);
+			falcon_release_lock_if_possible(hostdata);
+			return SCSI_ABORT_SUCCESS;
+		} else {
+/*			local_irq_restore(flags); */
+			printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+			return SCSI_ABORT_ERROR;
+		}
+	}
 #endif
 
-/* 
- * 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) )
-	if (cmd == tmp) {
-	    REMOVE(5, *prev, tmp, NEXT(tmp));
-	    (*prev) = NEXT(tmp);
-	    NEXT(tmp) = NULL;
-	    tmp->result = DID_ABORT << 16;
-	    local_irq_restore(flags);
-	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
-			HOSTNO);
-	    /* Tagged queuing note: no tag to free here, hasn't been assigned
-	     * yet... */
-	    tmp->scsi_done(tmp);
-	    falcon_release_lock_if_possible( hostdata );
-	    return SCSI_ABORT_SUCCESS;
+	/*
+	 * 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)) {
+		if (cmd == tmp) {
+			REMOVE(5, *prev, tmp, NEXT(tmp));
+			(*prev) = NEXT(tmp);
+			SET_NEXT(tmp, NULL);
+			tmp->result = DID_ABORT << 16;
+			local_irq_restore(flags);
+			ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+				    HOSTNO);
+			/* Tagged queuing note: no tag to free here, hasn't been assigned
+			 * yet... */
+			tmp->scsi_done(tmp);
+			falcon_release_lock_if_possible(hostdata);
+			return SCSI_ABORT_SUCCESS;
+		}
 	}
 
-/* 
- * Case 3 : If any commands are connected, we're going to fail the abort
- *	    and let the high level SCSI driver retry at a later time or 
- *	    issue a reset.
- *
- *	    Timeouts, and therefore aborted commands, will be highly unlikely
- *          and handling them cleanly in this situation would make the common
- *	    case of noresets less efficient, and would pollute our code.  So,
- *	    we fail.
- */
+	/*
+	 * Case 3 : If any commands are connected, we're going to fail the abort
+	 *	    and let the high level SCSI driver retry at a later time or
+	 *	    issue a reset.
+	 *
+	 *	    Timeouts, and therefore aborted commands, will be highly unlikely
+	 *          and handling them cleanly in this situation would make the common
+	 *	    case of noresets less efficient, and would pollute our code.  So,
+	 *	    we fail.
+	 */
 
-    if (hostdata->connected) {
-	local_irq_restore(flags);
-	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
-        return SCSI_ABORT_SNOOZE;
-    }
+	if (hostdata->connected) {
+		local_irq_restore(flags);
+		ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+		return SCSI_ABORT_SNOOZE;
+	}
 
-/*
- * Case 4: If the command is currently disconnected from the bus, and 
- * 	there are no connected commands, we reconnect the I_T_L or 
- *	I_T_L_Q nexus associated with it, go into message out, and send 
- *      an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select().  The easiest way to implement this 
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we 
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that 
- * device reselected.
- * 
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
+	/*
+	 * Case 4: If the command is currently disconnected from the bus, and
+	 *	there are no connected commands, we reconnect the I_T_L or
+	 *	I_T_L_Q nexus associated with it, go into message out, and send
+	 *      an abort message.
+	 *
+	 * This case is especially ugly. In order to reestablish the nexus, we
+	 * need to call NCR5380_select().  The easiest way to implement this
+	 * function was to abort if the bus was busy, and let the interrupt
+	 * handler triggered on the SEL for reselect take care of lost arbitrations
+	 * where necessary, meaning interrupts need to be enabled.
+	 *
+	 * When interrupts are enabled, the queues may change - so we
+	 * can't remove it from the disconnected queue before selecting it
+	 * because that could cause a failure in hashing the nexus if that
+	 * device reselected.
+	 *
+	 * Since the queues may change, we can't use the pointers from when we
+	 * first locate it.
+	 *
+	 * So, we must first locate the command, and if NCR5380_select()
+	 * succeeds, then issue the abort, relocate the command and remove
+	 * it from the disconnected queue.
+	 */
+
+	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	     tmp = NEXT(tmp)) {
+		if (cmd == tmp) {
+			local_irq_restore(flags);
+			ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
 
-    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
-	 tmp = NEXT(tmp)) 
-        if (cmd == tmp) {
-            local_irq_restore(flags);
-	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
-  
-            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
-		return SCSI_ABORT_BUSY;
-
-	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
-
-	    do_abort (instance);
-
-	    local_irq_save(flags);
-	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
-		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
-		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
-		    if (cmd == tmp) {
-		    REMOVE(5, *prev, tmp, NEXT(tmp));
-		    *prev = NEXT(tmp);
-		    NEXT(tmp) = NULL;
-		    tmp->result = DID_ABORT << 16;
-		    /* We must unlock the tag/LUN immediately here, since the
-		     * target goes to BUS FREE and doesn't send us another
-		     * message (COMMAND_COMPLETE or the like)
-		     */
+			if (NCR5380_select(instance, cmd, (int)cmd->tag))
+				return SCSI_ABORT_BUSY;
+
+			ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+			do_abort(instance);
+
+			local_irq_save(flags);
+			for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
+			     tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
+			     tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
+				if (cmd == tmp) {
+					REMOVE(5, *prev, tmp, NEXT(tmp));
+					*prev = NEXT(tmp);
+					SET_NEXT(tmp, NULL);
+					tmp->result = DID_ABORT << 16;
+					/* We must unlock the tag/LUN immediately here, since the
+					 * target goes to BUS FREE and doesn't send us another
+					 * message (COMMAND_COMPLETE or the like)
+					 */
 #ifdef SUPPORT_TAGS
-		    cmd_free_tag( tmp );
+					cmd_free_tag(tmp);
 #else
-		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
 #endif
-		    local_irq_restore(flags);
-		    tmp->scsi_done(tmp);
-		    falcon_release_lock_if_possible( hostdata );
-		    return SCSI_ABORT_SUCCESS;
+					local_irq_restore(flags);
+					tmp->scsi_done(tmp);
+					falcon_release_lock_if_possible(hostdata);
+					return SCSI_ABORT_SUCCESS;
+				}
+			}
 		}
 	}
 
-/*
- * Case 5 : If we reached this point, the command was not found in any of 
- *	    the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
+	/*
+	 * Case 5 : If we reached this point, the command was not found in any of
+	 *	    the queues.
+	 *
+	 * We probably reached this point because of an unlikely race condition
+	 * between the command completing successfully and the abortion code,
+	 * so we won't panic, but we will notify the user in case something really
+	 * broke.
+	 */
 
-    local_irq_restore(flags);
-    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
-           KERN_INFO "        before abortion\n", HOSTNO); 
+	local_irq_restore(flags);
+	printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+	       KERN_INFO "        before abortion\n", HOSTNO);
 
-/* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
-    falcon_release_lock_if_possible( hostdata );
+	/* Maybe it is sufficient just to release the ST-DMA lock... (if
+	 * possible at all) At least, we should check if the lock could be
+	 * released after the abort, in case it is kept due to some bug.
+	 */
+	falcon_release_lock_if_possible(hostdata);
 
-    return SCSI_ABORT_NOT_RUNNING;
+	return SCSI_ABORT_NOT_RUNNING;
 }
 
 
-/* 
+/*
  * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
- * 
+ *
  * Purpose : reset the SCSI bus.
  *
  * Returns : SCSI_RESET_WAKEUP
  *
- */ 
+ */
 
-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
 {
-    SETUP_HOSTDATA(cmd->device->host);
-    int           i;
-    unsigned long flags;
+	SETUP_HOSTDATA(cmd->device->host);
+	int i;
+	unsigned long flags;
 #if 1
-    Scsi_Cmnd *connected, *disconnected_queue;
+	Scsi_Cmnd *connected, *disconnected_queue;
 #endif
 
-    if (!IS_A_TT() && !falcon_got_lock)
-	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
-	       H_NO(cmd) );
-
-    NCR5380_print_status (cmd->device->host);
-
-    /* get in phase */
-    NCR5380_write( TARGET_COMMAND_REG,
-		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-    /* assert RST */
-    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-    udelay (40);
-    /* reset NCR registers */
-    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
-    NCR5380_write( MODE_REG, MR_BASE );
-    NCR5380_write( TARGET_COMMAND_REG, 0 );
-    NCR5380_write( SELECT_ENABLE_REG, 0 );
-    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
-     * through anymore ... */
-    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
-#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
-      /* XXX see below                                            XXX */
-
-    /* MSch: old-style reset: actually abort all command processing here */
-
-    /* After the reset, there are no more connected or disconnected commands
-     * and no busy units; to avoid problems with re-inserting the commands
-     * into the issue_queue (via scsi_done()), the aborted commands are
-     * remembered in local variables first.
-     */
-    local_irq_save(flags);
-    connected = (Scsi_Cmnd *)hostdata->connected;
-    hostdata->connected = NULL;
-    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
-    hostdata->disconnected_queue = NULL;
+	if (!IS_A_TT() && !falcon_got_lock)
+		printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+		       H_NO(cmd));
+
+	NCR5380_print_status(cmd->device->host);
+
+	/* get in phase */
+	NCR5380_write(TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
+	/* assert RST */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+	udelay(40);
+	/* reset NCR registers */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+	NCR5380_write(SELECT_ENABLE_REG, 0);
+	/* ++roman: reset interrupt condition! otherwise no interrupts don't get
+	 * through anymore ... */
+	(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+#if 1	/* XXX Should now be done by midlevel code, but it's broken XXX */
+	/* XXX see below                                            XXX */
+
+	/* MSch: old-style reset: actually abort all command processing here */
+
+	/* After the reset, there are no more connected or disconnected commands
+	 * and no busy units; to avoid problems with re-inserting the commands
+	 * into the issue_queue (via scsi_done()), the aborted commands are
+	 * remembered in local variables first.
+	 */
+	local_irq_save(flags);
+	connected = (Scsi_Cmnd *)hostdata->connected;
+	hostdata->connected = NULL;
+	disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+	hostdata->disconnected_queue = NULL;
 #ifdef SUPPORT_TAGS
-    free_all_tags();
+	free_all_tags();
 #endif
-    for( i = 0; i < 8; ++i )
-	hostdata->busy[i] = 0;
+	for (i = 0; i < 8; ++i)
+		hostdata->busy[i] = 0;
 #ifdef REAL_DMA
-    hostdata->dma_len = 0;
+	hostdata->dma_len = 0;
 #endif
-    local_irq_restore(flags);
-
-    /* In order to tell the mid-level code which commands were aborted, 
-     * set the command status to DID_RESET and call scsi_done() !!!
-     * This ultimately aborts processing of these commands in the mid-level.
-     */
-
-    if ((cmd = connected)) {
-	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
-	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
-	cmd->scsi_done( cmd );
-    }
-
-    for (i = 0; (cmd = disconnected_queue); ++i) {
-	disconnected_queue = NEXT(cmd);
-	NEXT(cmd) = NULL;
-	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
-	cmd->scsi_done( cmd );
-    }
-    if (i > 0)
-	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
-
-/* The Falcon lock should be released after a reset...
- */
-/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
- * unlocking and enabling dma interrupt.
- */
-/*    falcon_release_lock_if_possible( hostdata );*/
+	local_irq_restore(flags);
+
+	/* In order to tell the mid-level code which commands were aborted,
+	 * set the command status to DID_RESET and call scsi_done() !!!
+	 * This ultimately aborts processing of these commands in the mid-level.
+	 */
+
+	if ((cmd = connected)) {
+		ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+		cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+		cmd->scsi_done(cmd);
+	}
 
-    /* since all commands have been explicitly terminated, we need to tell
-     * the midlevel code that the reset was SUCCESSFUL, and there is no 
-     * need to 'wake up' the commands by a request_sense
-     */
-    return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+	for (i = 0; (cmd = disconnected_queue); ++i) {
+		disconnected_queue = NEXT(cmd);
+		SET_NEXT(cmd, NULL);
+		cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+		cmd->scsi_done(cmd);
+	}
+	if (i > 0)
+		ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+	/* The Falcon lock should be released after a reset...
+	 */
+	/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+	 * unlocking and enabling dma interrupt.
+	 */
+/*	falcon_release_lock_if_possible( hostdata );*/
+
+	/* since all commands have been explicitly terminated, we need to tell
+	 * the midlevel code that the reset was SUCCESSFUL, and there is no
+	 * need to 'wake up' the commands by a request_sense
+	 */
+	return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
 #else /* 1 */
 
-    /* MSch: new-style reset handling: let the mid-level do what it can */
-
-    /* ++guenther: MID-LEVEL IS STILL BROKEN.
-     * Mid-level is supposed to requeue all commands that were active on the
-     * various low-level queues. In fact it does this, but that's not enough
-     * because all these commands are subject to timeout. And if a timeout
-     * happens for any removed command, *_abort() is called but all queues
-     * are now empty. Abort then gives up the falcon lock, which is fatal,
-     * since the mid-level will queue more commands and must have the lock
-     * (it's all happening inside timer interrupt handler!!).
-     * Even worse, abort will return NOT_RUNNING for all those commands not
-     * on any queue, so they won't be retried ...
-     *
-     * Conclusion: either scsi.c disables timeout for all resetted commands
-     * immediately, or we lose!  As of linux-2.0.20 it doesn't.
-     */
-
-    /* After the reset, there are no more connected or disconnected commands
-     * and no busy units; so clear the low-level status here to avoid 
-     * conflicts when the mid-level code tries to wake up the affected 
-     * commands!
-     */
-
-    if (hostdata->issue_queue)
-	ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
-    if (hostdata->connected) 
-	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
-    if (hostdata->disconnected_queue)
-	ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
-
-    local_irq_save(flags);
-    hostdata->issue_queue = NULL;
-    hostdata->connected = NULL;
-    hostdata->disconnected_queue = NULL;
+	/* MSch: new-style reset handling: let the mid-level do what it can */
+
+	/* ++guenther: MID-LEVEL IS STILL BROKEN.
+	 * Mid-level is supposed to requeue all commands that were active on the
+	 * various low-level queues. In fact it does this, but that's not enough
+	 * because all these commands are subject to timeout. And if a timeout
+	 * happens for any removed command, *_abort() is called but all queues
+	 * are now empty. Abort then gives up the falcon lock, which is fatal,
+	 * since the mid-level will queue more commands and must have the lock
+	 * (it's all happening inside timer interrupt handler!!).
+	 * Even worse, abort will return NOT_RUNNING for all those commands not
+	 * on any queue, so they won't be retried ...
+	 *
+	 * Conclusion: either scsi.c disables timeout for all resetted commands
+	 * immediately, or we lose!  As of linux-2.0.20 it doesn't.
+	 */
+
+	/* After the reset, there are no more connected or disconnected commands
+	 * and no busy units; so clear the low-level status here to avoid
+	 * conflicts when the mid-level code tries to wake up the affected
+	 * commands!
+	 */
+
+	if (hostdata->issue_queue)
+		ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+	if (hostdata->connected)
+		ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+	if (hostdata->disconnected_queue)
+		ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+	local_irq_save(flags);
+	hostdata->issue_queue = NULL;
+	hostdata->connected = NULL;
+	hostdata->disconnected_queue = NULL;
 #ifdef SUPPORT_TAGS
-    free_all_tags();
+	free_all_tags();
 #endif
-    for( i = 0; i < 8; ++i )
-	hostdata->busy[i] = 0;
+	for (i = 0; i < 8; ++i)
+		hostdata->busy[i] = 0;
 #ifdef REAL_DMA
-    hostdata->dma_len = 0;
+	hostdata->dma_len = 0;
 #endif
-    local_irq_restore(flags);
+	local_irq_restore(flags);
 
-    /* we did no complete reset of all commands, so a wakeup is required */
-    return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+	/* we did no complete reset of all commands, so a wakeup is required */
+	return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
 #endif /* 1 */
 }
-
-/* Local Variables: */
-/* tab-width: 8     */
-/* End:             */
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 642de7b..6f8403b 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -69,9 +69,9 @@ #include <linux/module.h>
 
 #define NDEBUG (0)
 
-#define NDEBUG_ABORT	0x800000
-#define NDEBUG_TAGS	0x1000000
-#define NDEBUG_MERGING	0x2000000
+#define NDEBUG_ABORT		0x00100000
+#define NDEBUG_TAGS		0x00200000
+#define NDEBUG_MERGING		0x00400000
 
 #define AUTOSENSE
 /* For the Atari version, use only polled IO or REAL_DMA */
@@ -186,38 +186,37 @@ #endif
 /***************************** Prototypes *****************************/
 
 #ifdef REAL_DMA
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
-static void atari_scsi_fetch_restbytes( void );
-static long atari_scsi_dma_residual( struct Scsi_Host *instance );
-static int falcon_classify_cmd( Scsi_Cmnd *cmd );
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
-                                         Scsi_Cmnd *cmd, int write_flag );
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
+static void atari_scsi_fetch_restbytes(void);
+static long atari_scsi_dma_residual(struct Scsi_Host *instance);
+static int falcon_classify_cmd(Scsi_Cmnd *cmd);
+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);
-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 );
+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);
 #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void atari_scsi_reset_boot( void );
+static void atari_scsi_reset_boot(void);
 #endif
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
 
 /************************* End of Prototypes **************************/
 
 
-static struct Scsi_Host *atari_scsi_host = NULL;
-static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+static struct Scsi_Host *atari_scsi_host;
+static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
+static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
 
 #ifdef REAL_DMA
 static unsigned long	atari_dma_residual, atari_dma_startaddr;
 static short		atari_dma_active;
 /* pointer to the dribble buffer */
-static char		*atari_dma_buffer = NULL;
+static char		*atari_dma_buffer;
 /* precalculated physical address of the dribble buffer */
 static unsigned long	atari_dma_phys_buffer;
 /* != 0 tells the Falcon int handler to copy data from the dribble buffer */
@@ -233,7 +232,7 @@ #define	STRAM_BUFFER_SIZE	(4096)
 static unsigned long	atari_dma_stram_mask;
 #define STRAM_ADDR(a)	(((a) & atari_dma_stram_mask) == 0)
 /* number of bytes to cut from a transfer to handle NCR overruns */
-static int atari_read_overruns = 0;
+static int atari_read_overruns;
 #endif
 
 static int setup_can_queue = -1;
@@ -256,10 +255,10 @@ #endif
 
 #if defined(REAL_DMA)
 
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
 {
 	int i;
-	unsigned long	addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+	unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr;
 
 	if (dma_stat & 0x01) {
 
@@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( u
 		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
 		 * Check for this case:
 		 */
-		
-		for( i = 0; i < m68k_num_memory; ++i ) {
-			end_addr = m68k_memory[i].addr +
-				m68k_memory[i].size;
+
+		for (i = 0; i < m68k_num_memory; ++i) {
+			end_addr = m68k_memory[i].addr + m68k_memory[i].size;
 			if (end_addr <= addr && addr <= end_addr + 4)
-				return( 1 );
+				return 1;
 		}
 	}
-	return( 0 );
+	return 0;
 }
 
 
@@ -284,28 +282,27 @@ #if 0
  * 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)
+static void scsi_dma_buserr(int irq, void *dummy)
 {
-	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;
+	unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
 
 	/* Don't do anything if a NCR interrupt is pending. Probably it's just
 	 * masked... */
-	if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
+	if (atari_irq_pending(IRQ_TT_MFP_SCSI))
 		return;
-	
+
 	printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
 	       SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
 	if (dma_stat & 0x80) {
-		if (!scsi_dma_is_ignored_buserr( dma_stat ))
-			printk( "SCSI DMA bus error -- bad DMA programming!\n" );
-	}
-	else {
+		if (!scsi_dma_is_ignored_buserr(dma_stat))
+			printk("SCSI DMA bus error -- bad DMA programming!\n");
+	} else {
 		/* Under normal circumstances we never should get to this point,
 		 * since both interrupts are triggered simultaneously and the 5380
 		 * int has higher priority. When this irq is handled, that DMA
 		 * interrupt is cleared. So a warning message is printed here.
 		 */
-		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+		printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
 	}
 }
 #endif
@@ -313,7 +310,7 @@ #endif
 #endif
 
 
-static irqreturn_t scsi_tt_intr (int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dummy)
 {
 #ifdef REAL_DMA
 	int dma_stat;
@@ -327,7 +324,7 @@ #ifdef REAL_DMA
 	 * is that a bus error occurred...
 	 */
 	if (dma_stat & 0x80) {
-		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+		if (!scsi_dma_is_ignored_buserr(dma_stat)) {
 			printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
 			       SCSI_DMA_READ_P(dma_addr));
 			printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
@@ -344,8 +341,7 @@ #ifdef REAL_DMA
 	 * data reg!
 	 */
 	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
-		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
-												atari_dma_startaddr);
+		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
 
 		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
 			   atari_dma_residual);
@@ -353,28 +349,30 @@ #ifdef REAL_DMA
 		if ((signed int)atari_dma_residual < 0)
 			atari_dma_residual = 0;
 		if ((dma_stat & 1) == 0) {
-			/* After read operations, we maybe have to
-			   transport some rest bytes */
+			/*
+			 * After read operations, we maybe have to
+			 * transport some rest bytes
+			 */
 			atari_scsi_fetch_restbytes();
-		}
-		else {
-			/* There seems to be a nasty bug in some SCSI-DMA/NCR
-			   combinations: If a target disconnects while a write
-			   operation is going on, the address register of the
-			   DMA may be a few bytes farer than it actually read.
-			   This is probably due to DMA prefetching and a delay
-			   between DMA and NCR.  Experiments showed that the
-			   dma_addr is 9 bytes to high, but this could vary.
-			   The problem is, that the residual is thus calculated
-			   wrong and the next transfer will start behind where
-			   it should.  So we round up the residual to the next
-			   multiple of a sector size, if it isn't already a
-			   multiple and the originally expected transfer size
-			   was.  The latter condition is there to ensure that
-			   the correction is taken only for "real" data
-			   transfers and not for, e.g., the parameters of some
-			   other command.  These shouldn't disconnect anyway.
-			   */
+		} else {
+			/*
+			 * There seems to be a nasty bug in some SCSI-DMA/NCR
+			 * combinations: If a target disconnects while a write
+			 * operation is going on, the address register of the
+			 * DMA may be a few bytes farer than it actually read.
+			 * This is probably due to DMA prefetching and a delay
+			 * between DMA and NCR.  Experiments showed that the
+			 * dma_addr is 9 bytes to high, but this could vary.
+			 * The problem is, that the residual is thus calculated
+			 * wrong and the next transfer will start behind where
+			 * it should.  So we round up the residual to the next
+			 * multiple of a sector size, if it isn't already a
+			 * multiple and the originally expected transfer size
+			 * was.  The latter condition is there to ensure that
+			 * the correction is taken only for "real" data
+			 * transfers and not for, e.g., the parameters of some
+			 * other command.  These shouldn't disconnect anyway.
+			 */
 			if (atari_dma_residual & 0x1ff) {
 				DMA_PRINTK("SCSI DMA: DMA bug corrected, "
 					   "difference %ld bytes\n",
@@ -394,18 +392,18 @@ #ifdef REAL_DMA
 	}
 
 #endif /* REAL_DMA */
-	
-	NCR5380_intr (0, 0, 0);
+
+	NCR5380_intr(0, 0);
 
 #if 0
 	/* To be sure the int is not masked */
-	atari_enable_irq( IRQ_TT_MFP_SCSI );
+	atari_enable_irq(IRQ_TT_MFP_SCSI);
 #endif
 	return IRQ_HANDLED;
 }
 
 
-static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
 {
 #ifdef REAL_DMA
 	int dma_stat;
@@ -430,7 +428,7 @@ #ifdef REAL_DMA
 	 * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
 	 */
 	if (atari_dma_active && (dma_stat & 0x02)) {
-		unsigned long	transferred;
+		unsigned long transferred;
 
 		transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
 		/* The ST-DMA address is incremented in 2-byte steps, but the
@@ -445,8 +443,7 @@ #ifdef REAL_DMA
 		atari_dma_residual = HOSTDATA_DMALEN - transferred;
 		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
 			   atari_dma_residual);
-	}
-	else
+	} else
 		atari_dma_residual = 0;
 	atari_dma_active = 0;
 
@@ -461,13 +458,13 @@ #ifdef REAL_DMA
 
 #endif /* REAL_DMA */
 
-	NCR5380_intr (0, 0, 0);
+	NCR5380_intr(0, 0);
 	return IRQ_HANDLED;
 }
 
 
 #ifdef REAL_DMA
-static void atari_scsi_fetch_restbytes( void )
+static void atari_scsi_fetch_restbytes(void)
 {
 	int nr;
 	char *src, *dst;
@@ -505,19 +502,17 @@ static int falcon_dont_release = 0;
  * again (but others waiting longer more probably will win).
  */
 
-static void
-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
 {
 	unsigned long flags;
-		
-	if (IS_A_TT()) return;
-	
+
+	if (IS_A_TT())
+		return;
+
 	local_irq_save(flags);
 
-	if (falcon_got_lock &&
-		!hostdata->disconnected_queue &&
-		!hostdata->issue_queue &&
-		!hostdata->connected) {
+	if (falcon_got_lock && !hostdata->disconnected_queue &&
+	    !hostdata->issue_queue && !hostdata->connected) {
 
 		if (falcon_dont_release) {
 #if 0
@@ -528,7 +523,7 @@ #endif
 		}
 		falcon_got_lock = 0;
 		stdma_release();
-		wake_up( &falcon_fairness_wait );
+		wake_up(&falcon_fairness_wait);
 	}
 
 	local_irq_restore(flags);
@@ -549,31 +544,31 @@ #endif
  * Complicated, complicated.... Sigh...
  */
 
-static void falcon_get_lock( void )
+static void falcon_get_lock(void)
 {
 	unsigned long flags;
 
-	if (IS_A_TT()) return;
+	if (IS_A_TT())
+		return;
 
 	local_irq_save(flags);
 
-	while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
-		sleep_on( &falcon_fairness_wait );
+	while (!in_irq() && falcon_got_lock && stdma_others_waiting())
+		sleep_on(&falcon_fairness_wait);
 
 	while (!falcon_got_lock) {
-		if (in_interrupt())
-			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+		if (in_irq())
+			panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
 		if (!falcon_trying_lock) {
 			falcon_trying_lock = 1;
 			stdma_lock(scsi_falcon_intr, NULL);
 			falcon_got_lock = 1;
 			falcon_trying_lock = 0;
-			wake_up( &falcon_try_wait );
-		}
-		else {
-			sleep_on( &falcon_try_wait );
+			wake_up(&falcon_try_wait);
+		} else {
+			sleep_on(&falcon_try_wait);
 		}
-	}	
+	}
 
 	local_irq_restore(flags);
 	if (!falcon_got_lock)
@@ -587,18 +582,18 @@ static void falcon_get_lock( void )
  */
 
 #if 0
-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
 	/* falcon_get_lock();
 	 * ++guenther: moved to NCR5380_queue_command() to prevent
 	 * race condition, see there for an explanation.
 	 */
-	return( NCR5380_queue_command( cmd, done ) );
+	return NCR5380_queue_command(cmd, done);
 }
 #endif
 
 
-int atari_scsi_detect (struct scsi_host_template *host)
+int atari_scsi_detect(struct scsi_host_template *host)
 {
 	static int called = 0;
 	struct Scsi_Host *instance;
@@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_
 	if (!MACH_IS_ATARI ||
 	    (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
 	    called)
-		return( 0 );
+		return 0;
 
 	host->proc_name = "Atari";
 
@@ -655,32 +650,33 @@ #ifdef REAL_DMA
 	    !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
 		atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
 		if (!atari_dma_buffer) {
-			printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
-					"double buffer\n" );
-			return( 0 );
+			printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+					"double buffer\n");
+			return 0;
 		}
-		atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );
+		atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer);
 		atari_dma_orig_addr = 0;
 	}
 #endif
-	instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
-	if(instance == NULL)
-	{
+	instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
+	if (instance == NULL) {
 		atari_stram_free(atari_dma_buffer);
 		atari_dma_buffer = 0;
 		return 0;
 	}
 	atari_scsi_host = instance;
-       /* Set irq to 0, to avoid that the mid-level code disables our interrupt
-        * during queue_command calls. This is completely unnecessary, and even
-        * worse causes bad problems on the Falcon, where the int is shared with
-        * IDE and floppy! */
+	/*
+	 * Set irq to 0, to avoid that the mid-level code disables our interrupt
+	 * during queue_command calls. This is completely unnecessary, and even
+	 * worse causes bad problems on the Falcon, where the int is shared with
+	 * IDE and floppy!
+	 */
        instance->irq = 0;
 
 #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
 	atari_scsi_reset_boot();
 #endif
-	NCR5380_init (instance, 0);
+	NCR5380_init(instance, 0);
 
 	if (IS_A_TT()) {
 
@@ -727,11 +723,10 @@ #endif
 			 * the rest data bug is fixed, this can be lowered to 1.
 			 */
 			atari_read_overruns = 4;
-		}		
+		}
 #endif /*REAL_DMA*/
-	}
-	else { /* ! IS_A_TT */
-		
+	} else { /* ! IS_A_TT */
+
 		/* Nothing to do for the interrupt: the ST-DMA is initialized
 		 * already by atari_init_INTS()
 		 */
@@ -756,23 +751,21 @@ #ifdef SUPPORT_TAGS
 			setup_use_tagged_queuing ? "yes" : "no",
 #endif
 			instance->hostt->this_id );
-	NCR5380_print_options (instance);
-	printk ("\n");
+	NCR5380_print_options(instance);
+	printk("\n");
 
 	called = 1;
-	return( 1 );
+	return 1;
 }
 
-#ifdef MODULE
-int atari_scsi_release (struct Scsi_Host *sh)
+int atari_scsi_release(struct Scsi_Host *sh)
 {
 	if (IS_A_TT())
 		free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
 	if (atari_dma_buffer)
-		atari_stram_free (atari_dma_buffer);
+		atari_stram_free(atari_dma_buffer);
 	return 1;
 }
-#endif
 
 void __init atari_scsi_setup(char *str, int *ints)
 {
@@ -781,9 +774,9 @@ void __init atari_scsi_setup(char *str, 
 	 * Defaults depend on TT or Falcon, hostid determined at run time.
 	 * Negative values mean don't change.
 	 */
-	
+
 	if (ints[0] < 1) {
-		printk( "atari_scsi_setup: no arguments!\n" );
+		printk("atari_scsi_setup: no arguments!\n");
 		return;
 	}
 
@@ -809,7 +802,7 @@ void __init atari_scsi_setup(char *str, 
 		if (ints[4] >= 0 && ints[4] <= 7)
 			setup_hostid = ints[4];
 		else if (ints[4] > 7)
-			printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
+			printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
 	}
 #ifdef SUPPORT_TAGS
 	if (ints[0] >= 5) {
@@ -821,7 +814,7 @@ #endif
 
 int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
 {
-	int		rv;
+	int rv;
 	struct NCR5380_hostdata *hostdata =
 		(struct NCR5380_hostdata *)cmd->device->host->hostdata;
 
@@ -831,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
 	 */
 	/* And abort a maybe active DMA transfer */
 	if (IS_A_TT()) {
-		atari_turnoff_irq( IRQ_TT_MFP_SCSI );
+		atari_turnoff_irq(IRQ_TT_MFP_SCSI);
 #ifdef REAL_DMA
 		tt_scsi_dma.dma_ctrl = 0;
 #endif /* REAL_DMA */
-	}
-	else {
-		atari_turnoff_irq( IRQ_MFP_FSCSI );
+	} else {
+		atari_turnoff_irq(IRQ_MFP_FSCSI);
 #ifdef REAL_DMA
 		st_dma.dma_mode_status = 0x90;
 		atari_dma_active = 0;
@@ -849,52 +841,51 @@ #endif /* REAL_DMA */
 
 	/* Re-enable ints */
 	if (IS_A_TT()) {
-		atari_turnon_irq( IRQ_TT_MFP_SCSI );
-	}
-	else {
-		atari_turnon_irq( IRQ_MFP_FSCSI );
+		atari_turnon_irq(IRQ_TT_MFP_SCSI);
+	} else {
+		atari_turnon_irq(IRQ_MFP_FSCSI);
 	}
 	if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS)
 		falcon_release_lock_if_possible(hostdata);
 
-	return( rv );
+	return rv;
 }
 
-	
+
 #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
 static void __init atari_scsi_reset_boot(void)
 {
 	unsigned long end;
-	
+
 	/*
 	 * Do a SCSI reset to clean up the bus during initialization. No messing
 	 * with the queues, interrupts, or locks necessary here.
 	 */
 
-	printk( "Atari SCSI: resetting the SCSI bus..." );
+	printk("Atari SCSI: resetting the SCSI bus...");
 
 	/* get in phase */
-	NCR5380_write( TARGET_COMMAND_REG,
-		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+	NCR5380_write(TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
 
 	/* assert RST */
-	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
 	/* The min. reset hold time is 25us, so 40us should be enough */
-	udelay( 50 );
+	udelay(50);
 	/* reset RST and interrupt */
-	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
-	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 
 	end = jiffies + AFTER_RESET_DELAY;
 	while (time_before(jiffies, end))
 		barrier();
 
-	printk( " done\n" );
+	printk(" done\n");
 }
 #endif
 
 
-const char * atari_scsi_info (struct Scsi_Host *host)
+const char *atari_scsi_info(struct Scsi_Host *host)
 {
 	/* atari_scsi_detect() is verbose enough... */
 	static const char string[] = "Atari native SCSI";
@@ -904,10 +895,10 @@ const char * atari_scsi_info (struct Scs
 
 #if defined(REAL_DMA)
 
-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
-				   unsigned long count, int dir )
+unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data,
+				   unsigned long count, int dir)
 {
-	unsigned long addr = virt_to_phys( data );
+	unsigned long addr = virt_to_phys(data);
 
 	DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
 		   "dir = %d\n", instance->host_no, data, addr, count, dir);
@@ -919,38 +910,37 @@ unsigned long atari_scsi_dma_setup( stru
 		 * wanted address.
 		 */
 		if (dir)
-			memcpy( atari_dma_buffer, data, count );
+			memcpy(atari_dma_buffer, data, count);
 		else
 			atari_dma_orig_addr = data;
 		addr = atari_dma_phys_buffer;
 	}
-	
+
 	atari_dma_startaddr = addr;	/* Needed for calculating residual later. */
-  
+
 	/* Cache cleanup stuff: On writes, push any dirty cache out before sending
 	 * it to the peripheral. (Must be done before DMA setup, since at least
 	 * the ST-DMA begins to fill internal buffers right after setup. For
 	 * reads, invalidate any cache, may be altered after DMA without CPU
 	 * knowledge.
-	 * 
+	 *
 	 * ++roman: For the Medusa, there's no need at all for that cache stuff,
 	 * because the hardware does bus snooping (fine!).
 	 */
-	dma_cache_maintenance( addr, count, dir );
+	dma_cache_maintenance(addr, count, dir);
 
 	if (count == 0)
 		printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
 
 	if (IS_A_TT()) {
 		tt_scsi_dma.dma_ctrl = dir;
-		SCSI_DMA_WRITE_P( dma_addr, addr );
-		SCSI_DMA_WRITE_P( dma_cnt, count );
+		SCSI_DMA_WRITE_P(dma_addr, addr);
+		SCSI_DMA_WRITE_P(dma_cnt, count);
 		tt_scsi_dma.dma_ctrl = dir | 2;
-	}
-	else { /* ! IS_A_TT */
-  
+	} else { /* ! IS_A_TT */
+
 		/* set address */
-		SCSI_DMA_SETADR( addr );
+		SCSI_DMA_SETADR(addr);
 
 		/* toggle direction bit to clear FIFO and set DMA direction */
 		dir <<= 8;
@@ -968,13 +958,13 @@ unsigned long atari_scsi_dma_setup( stru
 		atari_dma_active = 1;
 	}
 
-	return( count );
+	return count;
 }
 
 
-static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+static long atari_scsi_dma_residual(struct Scsi_Host *instance)
 {
-	return( atari_dma_residual );
+	return atari_dma_residual;
 }
 
 
@@ -982,13 +972,13 @@ #define	CMD_SURELY_BLOCK_MODE	0
 #define	CMD_SURELY_BYTE_MODE	1
 #define	CMD_MODE_UNKNOWN		2
 
-static int falcon_classify_cmd( Scsi_Cmnd *cmd )
+static int falcon_classify_cmd(Scsi_Cmnd *cmd)
 {
 	unsigned char opcode = cmd->cmnd[0];
-	
+
 	if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
-		opcode == READ_BUFFER)
-		return( CMD_SURELY_BYTE_MODE );
+	    opcode == READ_BUFFER)
+		return CMD_SURELY_BYTE_MODE;
 	else if (opcode == READ_6 || opcode == READ_10 ||
 		 opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
 		 opcode == RECOVER_BUFFERED_DATA) {
@@ -996,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmn
 		 * needed here: The transfer is block-mode only if the 'fixed' bit is
 		 * set! */
 		if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
-			return( CMD_SURELY_BYTE_MODE );
+			return CMD_SURELY_BYTE_MODE;
 		else
-			return( CMD_SURELY_BLOCK_MODE );
-	}
-	else
-		return( CMD_MODE_UNKNOWN );
+			return CMD_SURELY_BLOCK_MODE;
+	} else
+		return CMD_MODE_UNKNOWN;
 }
 
 
@@ -1014,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmn
  * the overrun problem, so this question is academic :-)
  */
 
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
-					Scsi_Cmnd *cmd,
-					int write_flag )
+static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
+					Scsi_Cmnd *cmd, int write_flag)
 {
 	unsigned long	possible_len, limit;
 #ifndef CONFIG_TT_DMA_EMUL
 	if (MACH_IS_HADES)
 		/* Hades has no SCSI DMA at all :-( Always force use of PIO */
-		return( 0 );
-#endif	
+		return 0;
+#endif
 	if (IS_A_TT())
 		/* TT SCSI DMA can transfer arbitrary #bytes */
-		return( wanted_len );
+		return wanted_len;
 
 	/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
 	 * 255*512 bytes, but this should be enough)
@@ -1062,8 +1050,7 @@ #endif	
 		 * this).
 		 */
 		possible_len = wanted_len;
-	}
-	else {
+	} else {
 		/* Read operations: if the wanted transfer length is not a multiple of
 		 * 512, we cannot use DMA, since the ST-DMA cannot split transfers
 		 * (no interrupt on DMA finished!)
@@ -1073,15 +1060,15 @@ #endif	
 		else {
 			/* Now classify the command (see above) and decide whether it is
 			 * allowed to do DMA at all */
-			switch( falcon_classify_cmd( cmd )) {
-			  case CMD_SURELY_BLOCK_MODE:
+			switch (falcon_classify_cmd(cmd)) {
+			case CMD_SURELY_BLOCK_MODE:
 				possible_len = wanted_len;
 				break;
-			  case CMD_SURELY_BYTE_MODE:
+			case CMD_SURELY_BYTE_MODE:
 				possible_len = 0; /* DMA prohibited */
 				break;
-			  case CMD_MODE_UNKNOWN:
-			  default:
+			case CMD_MODE_UNKNOWN:
+			default:
 				/* For unknown commands assume block transfers if the transfer
 				 * size/allocation length is >= 1024 */
 				possible_len = (wanted_len < 1024) ? 0 : wanted_len;
@@ -1089,9 +1076,9 @@ #endif	
 			}
 		}
 	}
-	
+
 	/* Last step: apply the hard limit on DMA transfers */
-	limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ?
+	limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ?
 		    STRAM_BUFFER_SIZE : 255*512;
 	if (possible_len > limit)
 		possible_len = limit;
@@ -1100,7 +1087,7 @@ #endif	
 		DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
 			   "instead of %ld\n", possible_len, wanted_len);
 
-	return( possible_len );
+	return possible_len;
 }
 
 
@@ -1114,23 +1101,23 @@ #endif	/* REAL_DMA */
  * NCR5380_write call these functions via function pointers.
  */
 
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg)
 {
-	return( tt_scsi_regp[reg * 2] );
+	return tt_scsi_regp[reg * 2];
 }
 
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value)
 {
 	tt_scsi_regp[reg * 2] = value;
 }
 
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg)
 {
 	dma_wd.dma_mode_status= (u_short)(0x88 + reg);
-	return( (u_char)dma_wd.fdc_acces_seccount );
+	return (u_char)dma_wd.fdc_acces_seccount;
 }
 
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
 {
 	dma_wd.dma_mode_status = (u_short)(0x88 + reg);
 	dma_wd.fdc_acces_seccount = (u_short)value;
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index f917bdd..efadb8d 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -21,11 +21,7 @@ #ifndef ASM
 int atari_scsi_detect (struct scsi_host_template *);
 const char *atari_scsi_info (struct Scsi_Host *);
 int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
-#ifdef MODULE
 int atari_scsi_release (struct Scsi_Host *);
-#else
-#define atari_scsi_release NULL
-#endif
 
 /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
  * values should work, too; try it! (but cmd_per_lun costs memory!) */
@@ -63,6 +59,32 @@ #define NCR5380_dma_residual(inst) atari
 #define	NCR5380_dma_xfer_len(i,cmd,phase) \
 	atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
 
+/* former generic SCSI error handling stuff */
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS		0x01
+#define SCSI_RESET_ASYNCHRONOUS		0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION   0xff
+
 /* Debugging printk definitions:
  *
  *  ARB  -> arbitration
@@ -91,144 +113,58 @@ #define	NCR5380_dma_xfer_len(i,cmd,phase
  *
  */
 
-#if NDEBUG & NDEBUG_ARBITRATION
+#define dprint(flg, format...)			\
+({						\
+	if (NDEBUG & (flg))			\
+		printk(KERN_DEBUG format);	\
+})
+
 #define ARB_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define ARB_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_AUTOSENSE
+	dprint(NDEBUG_ARBITRATION, format , ## args)
 #define ASEN_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define ASEN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_DMA
+	dprint(NDEBUG_AUTOSENSE, format , ## args)
 #define DMA_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define DMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_HANDSHAKE
+	dprint(NDEBUG_DMA, format , ## args)
 #define HSH_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define HSH_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INFORMATION
+	dprint(NDEBUG_HANDSHAKE, format , ## args)
 #define INF_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define INF_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INIT
+	dprint(NDEBUG_INFORMATION, format , ## args)
 #define INI_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define INI_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INTR
+	dprint(NDEBUG_INIT, format , ## args)
 #define INT_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define INT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LINKED
+	dprint(NDEBUG_INTR, format , ## args)
 #define LNK_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define LNK_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MAIN
+	dprint(NDEBUG_LINKED, format , ## args)
 #define MAIN_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define MAIN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_DATAOUT
+	dprint(NDEBUG_MAIN, format , ## args)
 #define NDAT_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define NDAT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_WRITE
+	dprint(NDEBUG_NO_DATAOUT, format , ## args)
 #define NWR_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define NWR_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PIO
+	dprint(NDEBUG_NO_WRITE, format , ## args)
 #define PIO_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define PIO_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PSEUDO_DMA
+	dprint(NDEBUG_PIO, format , ## args)
 #define PDMA_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define PDMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_QUEUES
+	dprint(NDEBUG_PSEUDO_DMA, format , ## args)
 #define QU_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define QU_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESELECTION
+	dprint(NDEBUG_QUEUES, format , ## args)
 #define RSL_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define RSL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_SELECTION
+	dprint(NDEBUG_RESELECTION, format , ## args)
 #define SEL_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define SEL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_USLEEP
+	dprint(NDEBUG_SELECTION, format , ## args)
 #define USL_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define USL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+	dprint(NDEBUG_USLEEP, format , ## args)
 #define LBS_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define LBS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESTART_SELECT
+	dprint(NDEBUG_LAST_BYTE_SENT, format , ## args)
 #define RSS_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define RSS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_EXTENDED
+	dprint(NDEBUG_RESTART_SELECT, format , ## args)
 #define EXT_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define EXT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_ABORT
+	dprint(NDEBUG_EXTENDED, format , ## args)
 #define ABRT_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define ABRT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_TAGS
+	dprint(NDEBUG_ABORT, format , ## args)
 #define TAG_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define TAG_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MERGING
+	dprint(NDEBUG_TAGS, format , ## args)
 #define MER_PRINTK(format, args...) \
-	printk(KERN_DEBUG format , ## args)
-#else
-#define MER_PRINTK(format, args...)
-#endif
+	dprint(NDEBUG_MERGING, format , ## args)
 
 /* conditional macros for NCR5380_print_{,phase,status} */
 
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 61f6024..2a458d6 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -202,31 +202,29 @@ static const char * get_sa_name(const st
 }
 
 /* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
-			      int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
 {
 	int sa, len, cdb0;
 	const char * name;
-	const char * leadin = start_of_line ? KERN_INFO : "";
 
 	cdb0 = cdbp[0];
 	switch(cdb0) {
 	case VARIABLE_LENGTH_CMD:
 		len = cdbp[7] + 8;
 		if (len < 10) {
-			printk("%sshort variable length command, "
-			       "len=%d ext_len=%d", leadin, len, cdb_len);
+			printk("short variable length command, "
+			       "len=%d ext_len=%d", len, cdb_len);
 			break;
 		}
 		sa = (cdbp[8] << 8) + cdbp[9];
 		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
 		if (name) {
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 			if ((cdb_len > 0) && (len != cdb_len))
 				printk(", in_cdb_len=%d, ext_len=%d",
 				       len, cdb_len);
 		} else {
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 			if ((cdb_len > 0) && (len != cdb_len))
 				printk(", in_cdb_len=%d, ext_len=%d",
 				       len, cdb_len);
@@ -236,83 +234,80 @@ static void print_opcode_name(unsigned c
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	case MAINTENANCE_OUT:
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	case SERVICE_ACTION_IN_12:
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	case SERVICE_ACTION_OUT_12:
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	case SERVICE_ACTION_IN_16:
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	case SERVICE_ACTION_OUT_16:
 		sa = cdbp[1] & 0x1f;
 		name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
 		if (name)
-			printk("%s%s", leadin, name);
+			printk("%s", name);
 		else
-			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	default:
 		if (cdb0 < 0xc0) {
 			name = cdb_byte0_names[cdb0];
 			if (name)
-				printk("%s%s", leadin, name);
+				printk("%s", name);
 			else
-				printk("%scdb[0]=0x%x (reserved)",
-				       leadin, cdb0);
+				printk("cdb[0]=0x%x (reserved)", cdb0);
 		} else
-			printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+			printk("cdb[0]=0x%x (vendor)", cdb0);
 		break;
 	}
 }
 
 #else /* ifndef CONFIG_SCSI_CONSTANTS */
 
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
-			      int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
 {
 	int sa, len, cdb0;
-	const char * leadin = start_of_line ? KERN_INFO : "";
 
 	cdb0 = cdbp[0];
 	switch(cdb0) {
 	case VARIABLE_LENGTH_CMD:
 		len = cdbp[7] + 8;
 		if (len < 10) {
-			printk("%sshort opcode=0x%x command, len=%d "
-			       "ext_len=%d", leadin, cdb0, len, cdb_len);
+			printk("short opcode=0x%x command, len=%d "
+			       "ext_len=%d", cdb0, len, cdb_len);
 			break;
 		}
 		sa = (cdbp[8] << 8) + cdbp[9];
-		printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		if (len != cdb_len)
 			printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
 		break;
@@ -323,49 +318,48 @@ static void print_opcode_name(unsigned c
 	case SERVICE_ACTION_IN_16:
 	case SERVICE_ACTION_OUT_16:
 		sa = cdbp[1] & 0x1f;
-		printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
 		break;
 	default:
 		if (cdb0 < 0xc0)
-			printk("%scdb[0]=0x%x", leadin, cdb0);
+			printk("cdb[0]=0x%x", cdb0);
 		else
-			printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+			printk("cdb[0]=0x%x (vendor)", cdb0);
 		break;
 	}
 }
 #endif  
 
-void __scsi_print_command(unsigned char *command)
+void __scsi_print_command(unsigned char *cdb)
 {
 	int k, len;
 
-	print_opcode_name(command, 0, 1);
-	if (VARIABLE_LENGTH_CMD == command[0])
-		len = command[7] + 8;
+	print_opcode_name(cdb, 0);
+	if (VARIABLE_LENGTH_CMD == cdb[0])
+		len = cdb[7] + 8;
 	else
-		len = COMMAND_SIZE(command[0]);
+		len = COMMAND_SIZE(cdb[0]);
 	/* print out all bytes in cdb */
 	for (k = 0; k < len; ++k) 
-		printk(" %02x", command[k]);
+		printk(" %02x", cdb[k]);
 	printk("\n");
 }
 EXPORT_SYMBOL(__scsi_print_command);
 
-/* This function (perhaps with the addition of peripheral device type)
- * is more approriate than __scsi_print_command(). Perhaps that static
- * can be dropped later if it replaces the __scsi_print_command version.
- */
-static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line)
+void scsi_print_command(struct scsi_cmnd *cmd)
 {
 	int k;
 
-	print_opcode_name(cdb, cdb_len, start_of_line);
+	scmd_printk(KERN_INFO, cmd, "CDB: ");
+	print_opcode_name(cmd->cmnd, cmd->cmd_len);
+
 	/* print out all bytes in cdb */
 	printk(":");
-	for (k = 0; k < cdb_len; ++k) 
-		printk(" %02x", cdb[k]);
+	for (k = 0; k < cmd->cmd_len; ++k)
+		printk(" %02x", cmd->cmnd[k]);
 	printk("\n");
 }
+EXPORT_SYMBOL(scsi_print_command);
 
 /**
  *
@@ -410,7 +404,11 @@ struct error_info {
 	const char * text;
 };
 
-static struct error_info additional[] =
+/*
+ * The canonical list of T10 Additional Sense Codes is available at:
+ * http://www.t10.org/lists/asc-num.txt
+ */
+static const struct error_info additional[] =
 {
 	{0x0000, "No additional sense information"},
 	{0x0001, "Filemark detected"},
@@ -714,6 +712,7 @@ static struct error_info additional[] =
 
 	{0x2F00, "Commands cleared by another initiator"},
 	{0x2F01, "Commands cleared by power loss notification"},
+	{0x2F02, "Commands cleared by device server"},
 
 	{0x3000, "Incompatible medium installed"},
 	{0x3001, "Cannot read medium - unknown format"},
@@ -1176,67 +1175,77 @@ #endif
 }
 EXPORT_SYMBOL(scsi_extd_sense_format);
 
-/* Print extended sense information; no leadin, no linefeed */
-static void
+void
 scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
 {
-	const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
+        const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
 
 	if (extd_sense_fmt) {
 		if (strstr(extd_sense_fmt, "%x")) {
-			printk("Additional sense: ");
+			printk("Add. Sense: ");
 			printk(extd_sense_fmt, ascq);
 		} else
-			printk("Additional sense: %s", extd_sense_fmt);
+			printk("Add. Sense: %s", extd_sense_fmt);
 	} else {
 		if (asc >= 0x80)
-			printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc, ascq);
+			printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
+			       ascq);
 		if (ascq >= 0x80)
-			printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc, ascq);
+			printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
+			       ascq);
 		else
 			printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
 	}
+
+	printk("\n");
 }
+EXPORT_SYMBOL(scsi_show_extd_sense);
 
 void
-scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr)
 {
 	const char *sense_txt;
-	/* An example of deferred is when an earlier write to disk cache
-	 * succeeded, but now the disk discovers that it cannot write the
-	 * data to the magnetic media.
-	 */
-	const char *error = scsi_sense_is_deferred(sshdr) ? 
-		"<<DEFERRED>>" : "Current";
-	printk(KERN_INFO "%s: %s", name, error);
-	if (sshdr->response_code >= 0x72)
-		printk(" [descriptor]");
 
 	sense_txt = scsi_sense_key_string(sshdr->sense_key);
 	if (sense_txt)
-		printk(": sense key: %s\n", sense_txt);
+		printk("Sense Key : %s ", sense_txt);
 	else
-		printk(": sense key=0x%x\n", sshdr->sense_key);
-	printk(KERN_INFO "    ");
-	scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+		printk("Sense Key : 0x%x ", sshdr->sense_key);
+
+	printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " :
+	       "[current] ");
+
+	if (sshdr->response_code >= 0x72)
+		printk("[descriptor]");
+
 	printk("\n");
 }
+EXPORT_SYMBOL(scsi_show_sense_hdr);
+
+/*
+ * Print normalized SCSI sense header with a prefix.
+ */
+void
+scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+{
+	printk(KERN_INFO "%s: ", name);
+	scsi_show_sense_hdr(sshdr);
+	printk(KERN_INFO "%s: ", name);
+	scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
 EXPORT_SYMBOL(scsi_print_sense_hdr);
 
-/* Print sense information */
 void
-__scsi_print_sense(const char *name, const unsigned char *sense_buffer,
-		   int sense_len)
+scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
+		       struct scsi_sense_hdr *sshdr)
 {
 	int k, num, res;
-	unsigned int info;
-	struct scsi_sense_hdr ssh;
     
-	res = scsi_normalize_sense(sense_buffer, sense_len, &ssh);
+	res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
 	if (0 == res) {
 		/* this may be SCSI-1 sense data */
 		num = (sense_len < 32) ? sense_len : 32;
-		printk(KERN_INFO "Unrecognized sense data (in hex):");
+		printk("Unrecognized sense data (in hex):");
 		for (k = 0; k < num; ++k) {
 			if (0 == (k % 16)) {
 				printk("\n");
@@ -1247,11 +1256,20 @@ __scsi_print_sense(const char *name, con
 		printk("\n");
 		return;
 	}
-	scsi_print_sense_hdr(name, &ssh);
-	if (ssh.response_code < 0x72) {
+}
+
+void
+scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
+			 struct scsi_sense_hdr *sshdr)
+{
+	int k, num, res;
+
+	if (sshdr->response_code < 0x72)
+	{
 		/* only decode extras for "fixed" format now */
 		char buff[80];
 		int blen, fixed_valid;
+		unsigned int info;
 
 		fixed_valid = sense_buffer[0] & 0x80;
 		info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
@@ -1281,13 +1299,13 @@ __scsi_print_sense(const char *name, con
 			res += snprintf(buff + res, blen - res, "ILI");
 		}
 		if (res > 0)
-			printk(KERN_INFO "%s\n", buff);
-	} else if (ssh.additional_length > 0) {
+			printk("%s\n", buff);
+	} else if (sshdr->additional_length > 0) {
 		/* descriptor format with sense descriptors */
-		num = 8 + ssh.additional_length;
+		num = 8 + sshdr->additional_length;
 		num = (sense_len < num) ? sense_len : num;
-		printk(KERN_INFO "Descriptor sense data with sense "
-		       "descriptors (in hex):");
+		printk("Descriptor sense data with sense descriptors "
+		       "(in hex):");
 		for (k = 0; k < num; ++k) {
 			if (0 == (k % 16)) {
 				printk("\n");
@@ -1295,29 +1313,42 @@ __scsi_print_sense(const char *name, con
 			}
 			printk("%02x ", sense_buffer[k]);
 		}
+
 		printk("\n");
 	}
+
 }
-EXPORT_SYMBOL(__scsi_print_sense);
 
-void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer with name prefix */
+void __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
+			int sense_len)
 {
-	const char *name = devclass;
-
-	if (cmd->request->rq_disk)
-		name = cmd->request->rq_disk->disk_name;
-	__scsi_print_sense(name, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+	struct scsi_sense_hdr sshdr;
+
+	printk(KERN_INFO "%s: ", name);
+	scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr);
+	scsi_show_sense_hdr(&sshdr);
+	scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr);
+	printk(KERN_INFO "%s: ", name);
+	scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
 }
-EXPORT_SYMBOL(scsi_print_sense);
+EXPORT_SYMBOL(__scsi_print_sense);
 
-void scsi_print_command(struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer in SCSI command */
+void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
 {
-	/* Assume appended output (i.e. not at start of line) */
-	sdev_printk("", cmd->device, "\n");
-	printk(KERN_INFO "        command: ");
-	scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0);
+	struct scsi_sense_hdr sshdr;
+
+	scmd_printk(KERN_INFO, cmd, "");
+	scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+				 &sshdr);
+	scsi_show_sense_hdr(&sshdr);
+	scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+				 &sshdr);
+	scmd_printk(KERN_INFO, cmd, "");
+	scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
 }
-EXPORT_SYMBOL(scsi_print_command);
+EXPORT_SYMBOL(scsi_print_sense);
 
 #ifdef CONFIG_SCSI_CONSTANTS
 
@@ -1327,25 +1358,6 @@ static const char * const hostbyte_table
 "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
 #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
 
-void scsi_print_hostbyte(int scsiresult)
-{
-	int hb = host_byte(scsiresult);
-
-	printk("Hostbyte=0x%02x", hb);
-	if (hb < NUM_HOSTBYTE_STRS)
-		printk("(%s) ", hostbyte_table[hb]);
-	else
-		printk("is invalid ");
-}
-#else
-void scsi_print_hostbyte(int scsiresult)
-{
-	printk("Hostbyte=0x%02x ", host_byte(scsiresult));
-}
-#endif
-
-#ifdef CONFIG_SCSI_CONSTANTS
-
 static const char * const driverbyte_table[]={
 "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR",
 "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
@@ -1356,19 +1368,35 @@ static const char * const driversuggest_
 "SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
 #define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table)
 
-void scsi_print_driverbyte(int scsiresult)
+void scsi_show_result(int result)
 {
-	int dr = (driver_byte(scsiresult) & DRIVER_MASK);
-	int su = ((driver_byte(scsiresult) & SUGGEST_MASK) >> 4);
+	int hb = host_byte(result);
+	int db = (driver_byte(result) & DRIVER_MASK);
+	int su = ((driver_byte(result) & SUGGEST_MASK) >> 4);
 
-	printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
-	printk("(%s,%s) ",
-	       (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"),
+	printk("Result: hostbyte=%s driverbyte=%s,%s\n",
+	       (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb]     : "invalid"),
+	       (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"),
 	       (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
 }
+
 #else
-void scsi_print_driverbyte(int scsiresult)
+
+void scsi_show_result(int result)
 {
-	printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
+	printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
+	       host_byte(result), driver_byte(result));
 }
+
 #endif
+EXPORT_SYMBOL(scsi_show_result);
+
+
+void scsi_print_result(struct scsi_cmnd *cmd)
+{
+	scmd_printk(KERN_INFO, cmd, "");
+	scsi_show_result(cmd->result);
+}
+EXPORT_SYMBOL(scsi_print_result);
+
+
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index 5a49216..100b49b 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -31,7 +31,7 @@ #include <asm/atomic.h>
  *	Tunable parameters first
  */
 
-/* How many different OSM's are we allowing */ 
+/* How many different OSM's are we allowing */
 #define MAX_I2O_MODULES		64
 
 #define I2O_EVT_CAPABILITY_OTHER		0x01
@@ -63,7 +63,7 @@ struct i2o_message
 	u16	size;
 	u32	target_tid:12;
 	u32	init_tid:12;
-	u32	function:8;	
+	u32	function:8;
 	u32	initiator_context;
 	/* List follows */
 };
@@ -77,7 +77,7 @@ struct i2o_device
 
 	char dev_name[8];		/* linux /dev name if available */
 	i2o_lct_entry lct_data;/* Device LCT information */
-	u32 flags;		
+	u32 flags;
 	struct proc_dir_entry* proc_entry;	/* /proc dir */
 	struct adpt_device *owner;
 	struct _adpt_hba *controller;	/* Controlling IOP */
@@ -86,7 +86,7 @@ struct i2o_device
 /*
  *	Each I2O controller has one of these objects
  */
- 
+
 struct i2o_controller
 {
 	char name[16];
@@ -111,9 +111,9 @@ struct i2o_sys_tbl_entry
 	u32	iop_id:12;
 	u32	reserved2:20;
 	u16	seg_num:12;
-	u16 	i2o_version:4;
-	u8 	iop_state;
-	u8 	msg_type;
+	u16	i2o_version:4;
+	u8	iop_state;
+	u8	msg_type;
 	u16	frame_size;
 	u16	reserved3;
 	u32	last_changed;
@@ -124,14 +124,14 @@ struct i2o_sys_tbl_entry
 
 struct i2o_sys_tbl
 {
-	u8 	num_entries;
-	u8 	version;
-	u16 	reserved1;
+	u8	num_entries;
+	u8	version;
+	u16	reserved1;
 	u32	change_ind;
 	u32	reserved2;
 	u32	reserved3;
 	struct i2o_sys_tbl_entry iops[0];
-};	
+};
 
 /*
  *	I2O classes / subclasses
@@ -146,7 +146,7 @@ #define    I2O_CLASS_VERSION_11         
 /*  Class code names
  *  (from v1.5 Table 6-1 Class Code Assignments.)
  */
- 
+
 #define    I2O_CLASS_EXECUTIVE                         0x000
 #define    I2O_CLASS_DDM                               0x001
 #define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
@@ -166,7 +166,7 @@ #define    I2O_CLASS_PEER_TRANSPORT     
 
 /*  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
  */
- 
+
 #define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
 
 /*  Subclasses
@@ -175,7 +175,7 @@ #define    I2O_CLASS_MATCH_ANYCLASS     
 #define    I2O_SUBCLASS_i960                           0x001
 #define    I2O_SUBCLASS_HDM                            0x020
 #define    I2O_SUBCLASS_ISM                            0x021
- 
+
 /* Operation functions */
 
 #define I2O_PARAMS_FIELD_GET	0x0001
@@ -219,7 +219,7 @@ #define TRL_MULTIPLE_FIXED_LENGTH	0x80
 /*
  *	Messaging API values
  */
- 
+
 #define	I2O_CMD_ADAPTER_ASSIGN		0xB3
 #define	I2O_CMD_ADAPTER_READ		0xB2
 #define	I2O_CMD_ADAPTER_RELEASE		0xB5
@@ -284,16 +284,16 @@ #define I2O_CMD_BLOCK_MEJECT		0x43
 #define I2O_PRIVATE_MSG			0xFF
 
 /*
- *	Init Outbound Q status 
+ *	Init Outbound Q status
  */
- 
+
 #define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS	0x01
 #define I2O_CMD_OUTBOUND_INIT_REJECTED		0x02
 #define I2O_CMD_OUTBOUND_INIT_FAILED		0x03
 #define I2O_CMD_OUTBOUND_INIT_COMPLETE		0x04
 
 /*
- *	I2O Get Status State values 
+ *	I2O Get Status State values
  */
 
 #define	ADAPTER_STATE_INITIALIZING		0x01
@@ -303,7 +303,7 @@ #define ADAPTER_STATE_READY			0x05
 #define	ADAPTER_STATE_OPERATIONAL		0x08
 #define	ADAPTER_STATE_FAILED			0x10
 #define	ADAPTER_STATE_FAULTED			0x11
-	
+
 /* I2O API function return values */
 
 #define I2O_RTN_NO_ERROR			0
@@ -321,9 +321,9 @@ #define	I2O_RTN_NO_LINK_SPEED			11
 
 /* Reply message status defines for all messages */
 
-#define I2O_REPLY_STATUS_SUCCESS                    	0x00
-#define I2O_REPLY_STATUS_ABORT_DIRTY                	0x01
-#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     	0x02
+#define I2O_REPLY_STATUS_SUCCESS			0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY			0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER		0x02
 #define	I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER		0x03
 #define	I2O_REPLY_STATUS_ERROR_DIRTY			0x04
 #define	I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER		0x05
@@ -338,7 +338,7 @@ #define	I2O_REPLY_STATUS_PROGRESS_REPORT
 
 #define I2O_PARAMS_STATUS_SUCCESS		0x00
 #define I2O_PARAMS_STATUS_BAD_KEY_ABORT		0x01
-#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE   	0x02
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE	0x02
 #define I2O_PARAMS_STATUS_BUFFER_FULL		0x03
 #define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL	0x04
 #define I2O_PARAMS_STATUS_FIELD_UNREADABLE	0x05
@@ -390,7 +390,7 @@ #define	I2O_CLAIM_PRIMARY					0x01000000
 #define	I2O_CLAIM_MANAGEMENT					0x02000000
 #define	I2O_CLAIM_AUTHORIZED					0x03000000
 #define	I2O_CLAIM_SECONDARY					0x04000000
- 
+
 /* Message header defines for VersionOffset */
 #define I2OVER15	0x0001
 #define I2OVER20	0x0002
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index 82d2486..cc784e8 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -99,7 +99,7 @@ typedef struct {
 	uCHAR    eataVersion;      /* EATA Version                    */
 	uLONG    cpLength;         /* EATA Command Packet Length      */
 	uLONG    spLength;         /* EATA Status Packet Length       */
-	uCHAR    drqNum;           /* DRQ Index (0,5,6,7)             */ 
+	uCHAR    drqNum;           /* DRQ Index (0,5,6,7)             */
 	uCHAR    flag1;            /* EATA Flags 1 (Byte 9)           */
 	uCHAR    flag2;            /* EATA Flags 2 (Byte 30)          */
 } CtrlInfo;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 4bf4477..94bc894 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -145,8 +145,8 @@ #define FT_HELPFILE     11      /* Help 
 #define FT_LOGGER       12      /* Event Logger */
 #define FT_INSTALL      13      /* An Install Program */
 #define FT_LIBRARY      14      /* Storage Manager Real-Mode Calls */
-#define FT_RESOURCE 	15 	/* Storage Manager Resource File */
-#define FT_MODEM_DB  	16  	/* Storage Manager Modem Database */
+#define FT_RESOURCE	15	/* Storage Manager Resource File */
+#define FT_MODEM_DB	16	/* Storage Manager Modem Database */
 
 /* Filetype flags - sigBYTE dsFiletypeFlags;    FLAG BITS */
 /* ------------------------------------------------------------------ */
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index cd36e81..fb6433a 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -55,7 +55,6 @@ #include <linux/kernel.h>	/* for printk 
 #include <linux/sched.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/dma-mapping.h>
 
 #include <linux/timer.h>
@@ -195,8 +194,6 @@ static int adpt_detect(struct scsi_host_
 			pci_dev_get(pDev);
 		}
 	}
-	if (pDev)
-		pci_dev_put(pDev);
 
 	/* In INIT state, Activate IOPs */
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
index 635c148..5016af5 100644
--- a/drivers/scsi/eata_generic.h
+++ b/drivers/scsi/eata_generic.h
@@ -18,13 +18,6 @@ #define _EATA_GENERIC_H
  * Misc. definitions			     *
  *********************************************/
 
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
 #define R_LIMIT 0x20000
 
 #define MAXISA	   4
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
deleted file mode 100644
index 2c2fe80..0000000
--- a/drivers/scsi/esp.c
+++ /dev/null
@@ -1,4394 +0,0 @@
-/* esp.c: ESP Sun SCSI driver.
- *
- * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
- */
-
-/* TODO:
- *
- * 1) Maybe disable parity checking in config register one for SCSI1
- *    targets.  (Gilmore says parity error on the SBus can lock up
- *    old sun4c's)
- * 2) Add support for DMA2 pipelining.
- * 3) Add tagged queueing.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "esp.h"
-
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#ifndef __sparc_v9__
-#include <asm/machines.h>
-#include <asm/idprom.h>
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-
-#define DRV_VERSION "1.101"
-
-#define DEBUG_ESP
-/* #define DEBUG_ESP_HME */
-/* #define DEBUG_ESP_DATA */
-/* #define DEBUG_ESP_QUEUE */
-/* #define DEBUG_ESP_DISCONNECT */
-/* #define DEBUG_ESP_STATUS */
-/* #define DEBUG_ESP_PHASES */
-/* #define DEBUG_ESP_WORKBUS */
-/* #define DEBUG_STATE_MACHINE */
-/* #define DEBUG_ESP_CMDS */
-/* #define DEBUG_ESP_IRQS */
-/* #define DEBUG_SDTR */
-/* #define DEBUG_ESP_SG */
-
-/* Use the following to sprinkle debugging messages in a way which
- * suits you if combinations of the above become too verbose when
- * trying to track down a specific problem.
- */
-/* #define DEBUG_ESP_MISC */
-
-#if defined(DEBUG_ESP)
-#define ESPLOG(foo)  printk foo
-#else
-#define ESPLOG(foo)
-#endif /* (DEBUG_ESP) */
-
-#if defined(DEBUG_ESP_HME)
-#define ESPHME(foo)  printk foo
-#else
-#define ESPHME(foo)
-#endif
-
-#if defined(DEBUG_ESP_DATA)
-#define ESPDATA(foo)  printk foo
-#else
-#define ESPDATA(foo)
-#endif
-
-#if defined(DEBUG_ESP_QUEUE)
-#define ESPQUEUE(foo)  printk foo
-#else
-#define ESPQUEUE(foo)
-#endif
-
-#if defined(DEBUG_ESP_DISCONNECT)
-#define ESPDISC(foo)  printk foo
-#else
-#define ESPDISC(foo)
-#endif
-
-#if defined(DEBUG_ESP_STATUS)
-#define ESPSTAT(foo)  printk foo
-#else
-#define ESPSTAT(foo)
-#endif
-
-#if defined(DEBUG_ESP_PHASES)
-#define ESPPHASE(foo)  printk foo
-#else
-#define ESPPHASE(foo)
-#endif
-
-#if defined(DEBUG_ESP_WORKBUS)
-#define ESPBUS(foo)  printk foo
-#else
-#define ESPBUS(foo)
-#endif
-
-#if defined(DEBUG_ESP_IRQS)
-#define ESPIRQ(foo)  printk foo
-#else
-#define ESPIRQ(foo)
-#endif
-
-#if defined(DEBUG_SDTR)
-#define ESPSDTR(foo)  printk foo
-#else
-#define ESPSDTR(foo)
-#endif
-
-#if defined(DEBUG_ESP_MISC)
-#define ESPMISC(foo)  printk foo
-#else
-#define ESPMISC(foo)
-#endif
-
-/* Command phase enumeration. */
-enum {
-	not_issued    = 0x00,  /* Still in the issue_SC queue.          */
-
-	/* Various forms of selecting a target. */
-#define in_slct_mask    0x10
-	in_slct_norm  = 0x10,  /* ESP is arbitrating, normal selection  */
-	in_slct_stop  = 0x11,  /* ESP will select, then stop with IRQ   */
-	in_slct_msg   = 0x12,  /* select, then send a message           */
-	in_slct_tag   = 0x13,  /* select and send tagged queue msg      */
-	in_slct_sneg  = 0x14,  /* select and acquire sync capabilities  */
-
-	/* Any post selection activity. */
-#define in_phases_mask  0x20
-	in_datain     = 0x20,  /* Data is transferring from the bus     */
-	in_dataout    = 0x21,  /* Data is transferring to the bus       */
-	in_data_done  = 0x22,  /* Last DMA data operation done (maybe)  */
-	in_msgin      = 0x23,  /* Eating message from target            */
-	in_msgincont  = 0x24,  /* Eating more msg bytes from target     */
-	in_msgindone  = 0x25,  /* Decide what to do with what we got    */
-	in_msgout     = 0x26,  /* Sending message to target             */
-	in_msgoutdone = 0x27,  /* Done sending msg out                  */
-	in_cmdbegin   = 0x28,  /* Sending cmd after abnormal selection  */
-	in_cmdend     = 0x29,  /* Done sending slow cmd                 */
-	in_status     = 0x2a,  /* Was in status phase, finishing cmd    */
-	in_freeing    = 0x2b,  /* freeing the bus for cmd cmplt or disc */
-	in_the_dark   = 0x2c,  /* Don't know what bus phase we are in   */
-
-	/* Special states, ie. not normal bus transitions... */
-#define in_spec_mask    0x80
-	in_abortone   = 0x80,  /* Aborting one command currently        */
-	in_abortall   = 0x81,  /* Blowing away all commands we have     */
-	in_resetdev   = 0x82,  /* SCSI target reset in progress         */
-	in_resetbus   = 0x83,  /* SCSI bus reset in progress            */
-	in_tgterror   = 0x84,  /* Target did something stupid           */
-};
-
-enum {
-	/* Zero has special meaning, see skipahead[12]. */
-/*0*/	do_never,
-
-/*1*/	do_phase_determine,
-/*2*/	do_reset_bus,
-/*3*/	do_reset_complete,
-/*4*/	do_work_bus,
-/*5*/	do_intr_end
-};
-
-/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id);
-
-/* Debugging routines */
-struct esp_cmdstrings {
-	u8 cmdchar;
-	char *text;
-} esp_cmd_strings[] = {
-	/* Miscellaneous */
-	{ ESP_CMD_NULL, "ESP_NOP", },
-	{ ESP_CMD_FLUSH, "FIFO_FLUSH", },
-	{ ESP_CMD_RC, "RSTESP", },
-	{ ESP_CMD_RS, "RSTSCSI", },
-	/* Disconnected State Group */
-	{ ESP_CMD_RSEL, "RESLCTSEQ", },
-	{ ESP_CMD_SEL, "SLCTNATN", },
-	{ ESP_CMD_SELA, "SLCTATN", },
-	{ ESP_CMD_SELAS, "SLCTATNSTOP", },
-	{ ESP_CMD_ESEL, "ENSLCTRESEL", },
-	{ ESP_CMD_DSEL, "DISSELRESEL", },
-	{ ESP_CMD_SA3, "SLCTATN3", },
-	{ ESP_CMD_RSEL3, "RESLCTSEQ", },
-	/* Target State Group */
-	{ ESP_CMD_SMSG, "SNDMSG", },
-	{ ESP_CMD_SSTAT, "SNDSTATUS", },
-	{ ESP_CMD_SDATA, "SNDDATA", },
-	{ ESP_CMD_DSEQ, "DISCSEQ", },
-	{ ESP_CMD_TSEQ, "TERMSEQ", },
-	{ ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
-	{ ESP_CMD_DCNCT, "DISC", },
-	{ ESP_CMD_RMSG, "RCVMSG", },
-	{ ESP_CMD_RCMD, "RCVCMD", },
-	{ ESP_CMD_RDATA, "RCVDATA", },
-	{ ESP_CMD_RCSEQ, "RCVCMDSEQ", },
-	/* Initiator State Group */
-	{ ESP_CMD_TI, "TRANSINFO", },
-	{ ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
-	{ ESP_CMD_MOK, "MSGACCEPTED", },
-	{ ESP_CMD_TPAD, "TPAD", },
-	{ ESP_CMD_SATN, "SATN", },
-	{ ESP_CMD_RATN, "RATN", },
-};
-#define NUM_ESP_COMMANDS  ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
-
-/* Print textual representation of an ESP command */
-static inline void esp_print_cmd(u8 espcmd)
-{
-	u8 dma_bit = espcmd & ESP_CMD_DMA;
-	int i;
-
-	espcmd &= ~dma_bit;
-	for (i = 0; i < NUM_ESP_COMMANDS; i++)
-		if (esp_cmd_strings[i].cmdchar == espcmd)
-			break;
-	if (i == NUM_ESP_COMMANDS)
-		printk("ESP_Unknown");
-	else
-		printk("%s%s", esp_cmd_strings[i].text,
-		       ((dma_bit) ? "+DMA" : ""));
-}
-
-/* Print the status register's value */
-static inline void esp_print_statreg(u8 statreg)
-{
-	u8 phase;
-
-	printk("STATUS<");
-	phase = statreg & ESP_STAT_PMASK;
-	printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
-		       (phase == ESP_DIP ? "DATA-IN" :
-			(phase == ESP_CMDP ? "COMMAND" :
-			 (phase == ESP_STATP ? "STATUS" :
-			  (phase == ESP_MOP ? "MSG-OUT" :
-			   (phase == ESP_MIP ? "MSG_IN" :
-			    "unknown")))))));
-	if (statreg & ESP_STAT_TDONE)
-		printk("TRANS_DONE,");
-	if (statreg & ESP_STAT_TCNT)
-		printk("TCOUNT_ZERO,");
-	if (statreg & ESP_STAT_PERR)
-		printk("P_ERROR,");
-	if (statreg & ESP_STAT_SPAM)
-		printk("SPAM,");
-	if (statreg & ESP_STAT_INTR)
-		printk("IRQ,");
-	printk(">");
-}
-
-/* Print the interrupt register's value */
-static inline void esp_print_ireg(u8 intreg)
-{
-	printk("INTREG< ");
-	if (intreg & ESP_INTR_S)
-		printk("SLCT_NATN ");
-	if (intreg & ESP_INTR_SATN)
-		printk("SLCT_ATN ");
-	if (intreg & ESP_INTR_RSEL)
-		printk("RSLCT ");
-	if (intreg & ESP_INTR_FDONE)
-		printk("FDONE ");
-	if (intreg & ESP_INTR_BSERV)
-		printk("BSERV ");
-	if (intreg & ESP_INTR_DC)
-		printk("DISCNCT ");
-	if (intreg & ESP_INTR_IC)
-		printk("ILL_CMD ");
-	if (intreg & ESP_INTR_SR)
-		printk("SCSI_BUS_RESET ");
-	printk(">");
-}
-
-/* Print the sequence step registers contents */
-static inline void esp_print_seqreg(u8 stepreg)
-{
-	stepreg &= ESP_STEP_VBITS;
-	printk("STEP<%s>",
-	       (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
-		(stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
-		 (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
-		  (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
-		   (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
-		    "UNKNOWN"))))));
-}
-
-static char *phase_string(int phase)
-{
-	switch (phase) {
-	case not_issued:
-		return "UNISSUED";
-	case in_slct_norm:
-		return "SLCTNORM";
-	case in_slct_stop:
-		return "SLCTSTOP";
-	case in_slct_msg:
-		return "SLCTMSG";
-	case in_slct_tag:
-		return "SLCTTAG";
-	case in_slct_sneg:
-		return "SLCTSNEG";
-	case in_datain:
-		return "DATAIN";
-	case in_dataout:
-		return "DATAOUT";
-	case in_data_done:
-		return "DATADONE";
-	case in_msgin:
-		return "MSGIN";
-	case in_msgincont:
-		return "MSGINCONT";
-	case in_msgindone:
-		return "MSGINDONE";
-	case in_msgout:
-		return "MSGOUT";
-	case in_msgoutdone:
-		return "MSGOUTDONE";
-	case in_cmdbegin:
-		return "CMDBEGIN";
-	case in_cmdend:
-		return "CMDEND";
-	case in_status:
-		return "STATUS";
-	case in_freeing:
-		return "FREEING";
-	case in_the_dark:
-		return "CLUELESS";
-	case in_abortone:
-		return "ABORTONE";
-	case in_abortall:
-		return "ABORTALL";
-	case in_resetdev:
-		return "RESETDEV";
-	case in_resetbus:
-		return "RESETBUS";
-	case in_tgterror:
-		return "TGTERROR";
-	default:
-		return "UNKNOWN";
-	};
-}
-
-#ifdef DEBUG_STATE_MACHINE
-static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase)
-{
-	ESPLOG(("<%s>", phase_string(newphase)));
-	s->SCp.sent_command = s->SCp.phase;
-	s->SCp.phase = newphase;
-}
-#else
-#define esp_advance_phase(__s, __newphase) \
-	(__s)->SCp.sent_command = (__s)->SCp.phase; \
-	(__s)->SCp.phase = (__newphase);
-#endif
-
-#ifdef DEBUG_ESP_CMDS
-static inline void esp_cmd(struct esp *esp, u8 cmd)
-{
-	esp->espcmdlog[esp->espcmdent] = cmd;
-	esp->espcmdent = (esp->espcmdent + 1) & 31;
-	sbus_writeb(cmd, esp->eregs + ESP_CMD);
-}
-#else
-#define esp_cmd(__esp, __cmd)	\
-	sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD)
-#endif
-
-#define ESP_INTSOFF(__dregs)	\
-	sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR)
-#define ESP_INTSON(__dregs)	\
-	sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR)
-#define ESP_IRQ_P(__dregs)	\
-	(sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR))
-
-/* How we use the various Linux SCSI data structures for operation.
- *
- * struct scsi_cmnd:
- *
- *   We keep track of the synchronous capabilities of a target
- *   in the device member, using sync_min_period and
- *   sync_max_offset.  These are the values we directly write
- *   into the ESP registers while running a command.  If offset
- *   is zero the ESP will use asynchronous transfers.
- *   If the borken flag is set we assume we shouldn't even bother
- *   trying to negotiate for synchronous transfer as this target
- *   is really stupid.  If we notice the target is dropping the
- *   bus, and we have been allowing it to disconnect, we clear
- *   the disconnect flag.
- */
-
-
-/* Manipulation of the ESP command queues.  Thanks to the aha152x driver
- * and its author, Juergen E. Fischer, for the methods used here.
- * Note that these are per-ESP queues, not global queues like
- * the aha152x driver uses.
- */
-static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
-	struct scsi_cmnd *end;
-
-	new_SC->host_scribble = (unsigned char *) NULL;
-	if (!*SC)
-		*SC = new_SC;
-	else {
-		for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble)
-			;
-		end->host_scribble = (unsigned char *) new_SC;
-	}
-}
-
-static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
-	new_SC->host_scribble = (unsigned char *) *SC;
-	*SC = new_SC;
-}
-
-static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC)
-{
-	struct scsi_cmnd *ptr;
-	ptr = *SC;
-	if (ptr)
-		*SC = (struct scsi_cmnd *) (*SC)->host_scribble;
-	return ptr;
-}
-
-static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun)
-{
-	struct scsi_cmnd *ptr, *prev;
-
-	for (ptr = *SC, prev = NULL;
-	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
-	     prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble)
-		;
-	if (ptr) {
-		if (prev)
-			prev->host_scribble=ptr->host_scribble;
-		else
-			*SC=(struct scsi_cmnd *)ptr->host_scribble;
-	}
-	return ptr;
-}
-
-/* Resetting various pieces of the ESP scsi driver chipset/buses. */
-static void esp_reset_dma(struct esp *esp)
-{
-	int can_do_burst16, can_do_burst32, can_do_burst64;
-	int can_do_sbus64;
-	u32 tmp;
-
-	can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
-	can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
-	can_do_burst64 = 0;
-	can_do_sbus64 = 0;
-	if (sbus_can_dma_64bit(esp->sdev))
-		can_do_sbus64 = 1;
-	if (sbus_can_burst64(esp->sdev))
-		can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
-
-	/* Punt the DVMA into a known state. */
-	if (esp->dma->revision != dvmahme) {
-		tmp = sbus_readl(esp->dregs + DMA_CSR);
-		sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR);
-		sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR);
-	}
-	switch (esp->dma->revision) {
-	case dvmahme:
-		/* This is the HME DVMA gate array. */
-
-		sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR);
-		sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
-		esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
-		esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
-
-		if (can_do_burst64)
-			esp->prev_hme_dmacsr |= DMA_BRST64;
-		else if (can_do_burst32)
-			esp->prev_hme_dmacsr |= DMA_BRST32;
-
-		if (can_do_sbus64) {
-			esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
-			sbus_set_sbus64(esp->sdev, esp->bursts);
-		}
-
-		/* This chip is horrible. */
-		while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ)
-			udelay(1);
-
-		sbus_writel(0, esp->dregs + DMA_CSR);
-		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
-		/* This is necessary to avoid having the SCSI channel
-		 * engine lock up on us.
-		 */
-		sbus_writel(0, esp->dregs + DMA_ADDR);
-
-		break;
-	case dvmarev2:
-		/* This is the gate array found in the sun4m
-		 * NCR SBUS I/O subsystem.
-		 */
-		if (esp->erev != esp100) {
-			tmp = sbus_readl(esp->dregs + DMA_CSR);
-			sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR);
-		}
-		break;
-	case dvmarev3:
-		tmp = sbus_readl(esp->dregs + DMA_CSR);
-		tmp &= ~DMA_3CLKS;
-		tmp |= DMA_2CLKS;
-		if (can_do_burst32) {
-			tmp &= ~DMA_BRST_SZ;
-			tmp |= DMA_BRST32;
-		}
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-		break;
-	case dvmaesc1:
-		/* This is the DMA unit found on SCSI/Ether cards. */
-		tmp = sbus_readl(esp->dregs + DMA_CSR);
-		tmp |= DMA_ADD_ENABLE;
-		tmp &= ~DMA_BCNT_ENAB;
-		if (!can_do_burst32 && can_do_burst16) {
-			tmp |= DMA_ESC_BURST;
-		} else {
-			tmp &= ~(DMA_ESC_BURST);
-		}
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-		break;
-	default:
-		break;
-	};
-	ESP_INTSON(esp->dregs);
-}
-
-/* Reset the ESP chip, _not_ the SCSI bus. */
-static void __init esp_reset_esp(struct esp *esp)
-{
-	u8 family_code, version;
-	int i;
-
-	/* Now reset the ESP chip */
-	esp_cmd(esp, ESP_CMD_RC);
-	esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
-	esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
-
-	/* Reload the configuration registers */
-	sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT);
-	esp->prev_stp = 0;
-	sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
-	esp->prev_soff = 0;
-	sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
-	sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO);
-
-	/* This is the only point at which it is reliable to read
-	 * the ID-code for a fast ESP chip variants.
-	 */
-	esp->max_period = ((35 * esp->ccycle) / 1000);
-	if (esp->erev == fast) {
-		version = sbus_readb(esp->eregs + ESP_UID);
-		family_code = (version & 0xf8) >> 3;
-		if (family_code == 0x02)
-			esp->erev = fas236;
-		else if (family_code == 0x0a)
-			esp->erev = fashme; /* Version is usually '5'. */
-		else
-			esp->erev = fas100a;
-		ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
-			 esp->esp_id,
-			 (esp->erev == fas236) ? "fas236" :
-			 ((esp->erev == fas100a) ? "fas100a" :
-			  "fasHME"), family_code, (version & 7)));
-
-		esp->min_period = ((4 * esp->ccycle) / 1000);
-	} else {
-		esp->min_period = ((5 * esp->ccycle) / 1000);
-	}
-	esp->max_period = (esp->max_period + 3)>>2;
-	esp->min_period = (esp->min_period + 3)>>2;
-
-	sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
-	switch (esp->erev) {
-	case esp100:
-		/* nothing to do */
-		break;
-	case esp100a:
-		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		break;
-	case esp236:
-		/* Slow 236 */
-		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		esp->prev_cfg3 = esp->config3[0];
-		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-		break;
-	case fashme:
-		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
-		/* fallthrough... */
-	case fas236:
-		/* Fast 236 or HME */
-		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		for (i = 0; i < 16; i++) {
-			if (esp->erev == fashme) {
-				u8 cfg3;
-
-				cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
-				if (esp->scsi_id >= 8)
-					cfg3 |= ESP_CONFIG3_IDBIT3;
-				esp->config3[i] |= cfg3;
-			} else {
-				esp->config3[i] |= ESP_CONFIG3_FCLK;
-			}
-		}
-		esp->prev_cfg3 = esp->config3[0];
-		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-		if (esp->erev == fashme) {
-			esp->radelay = 80;
-		} else {
-			if (esp->diff)
-				esp->radelay = 0;
-			else
-				esp->radelay = 96;
-		}
-		break;
-	case fas100a:
-		/* Fast 100a */
-		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		for (i = 0; i < 16; i++)
-			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
-		esp->prev_cfg3 = esp->config3[0];
-		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-		esp->radelay = 32;
-		break;
-	default:
-		panic("esp: what could it be... I wonder...");
-		break;
-	};
-
-	/* Eat any bitrot in the chip */
-	sbus_readb(esp->eregs + ESP_INTRPT);
-	udelay(100);
-}
-
-/* This places the ESP into a known state at boot time. */
-static void __init esp_bootup_reset(struct esp *esp)
-{
-	u8 tmp;
-
-	/* Reset the DMA */
-	esp_reset_dma(esp);
-
-	/* Reset the ESP */
-	esp_reset_esp(esp);
-
-	/* Reset the SCSI bus, but tell ESP not to generate an irq */
-	tmp = sbus_readb(esp->eregs + ESP_CFG1);
-	tmp |= ESP_CONFIG1_SRRDISAB;
-	sbus_writeb(tmp, esp->eregs + ESP_CFG1);
-
-	esp_cmd(esp, ESP_CMD_RS);
-	udelay(400);
-
-	sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
-
-	/* Eat any bitrot in the chip and we are done... */
-	sbus_readb(esp->eregs + ESP_INTRPT);
-}
-
-static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
-	struct sbus_dev *sdev = esp->sdev;
-	struct sbus_dma *dma;
-
-	if (dma_sdev != NULL) {
-		for_each_dvma(dma) {
-			if (dma->sdev == dma_sdev)
-				break;
-		}
-	} else {
-		for_each_dvma(dma) {
-			/* If allocated already, can't use it. */
-			if (dma->allocated)
-				continue;
-
-			if (dma->sdev == NULL)
-				break;
-
-			/* If bus + slot are the same and it has the
-			 * correct OBP name, it's ours.
-			 */
-			if (sdev->bus == dma->sdev->bus &&
-			    sdev->slot == dma->sdev->slot &&
-			    (!strcmp(dma->sdev->prom_name, "dma") ||
-			     !strcmp(dma->sdev->prom_name, "espdma")))
-				break;
-		}
-	}
-
-	/* If we don't know how to handle the dvma,
-	 * do not use this device.
-	 */
-	if (dma == NULL) {
-		printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id);
-		return -1;
-	}
-	if (dma->allocated) {
-		printk("esp%d: can't use my espdma\n", esp->esp_id);
-		return -1;
-	}
-	dma->allocated = 1;
-	esp->dma = dma;
-	esp->dregs = dma->regs;
-
-	return 0;
-}
-
-static int __init esp_map_regs(struct esp *esp, int hme)
-{
-	struct sbus_dev *sdev = esp->sdev;
-	struct resource *res;
-
-	/* On HME, two reg sets exist, first is DVMA,
-	 * second is ESP registers.
-	 */
-	if (hme)
-		res = &sdev->resource[1];
-	else
-		res = &sdev->resource[0];
-
-	esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers");
-
-	if (esp->eregs == 0)
-		return -1;
-	return 0;
-}
-
-static int __init esp_map_cmdarea(struct esp *esp)
-{
-	struct sbus_dev *sdev = esp->sdev;
-
-	esp->esp_command = sbus_alloc_consistent(sdev, 16,
-						 &esp->esp_command_dvma);
-	if (esp->esp_command == NULL ||
-	    esp->esp_command_dvma == 0)
-		return -1;
-	return 0;
-}
-
-static int __init esp_register_irq(struct esp *esp)
-{
-	esp->ehost->irq = esp->irq = esp->sdev->irqs[0];
-
-	/* We used to try various overly-clever things to
-	 * reduce the interrupt processing overhead on
-	 * sun4c/sun4m when multiple ESP's shared the
-	 * same IRQ.  It was too complex and messy to
-	 * sanely maintain.
-	 */
-	if (request_irq(esp->ehost->irq, esp_intr,
-			IRQF_SHARED, "ESP SCSI", esp)) {
-		printk("esp%d: Cannot acquire irq line\n",
-		       esp->esp_id);
-		return -1;
-	}
-
-	printk("esp%d: IRQ %d ", esp->esp_id,
-	       esp->ehost->irq);
-
-	return 0;
-}
-
-static void __init esp_get_scsi_id(struct esp *esp)
-{
-	struct sbus_dev *sdev = esp->sdev;
-	struct device_node *dp = sdev->ofdev.node;
-
-	esp->scsi_id = of_getintprop_default(dp,
-					     "initiator-id",
-					     -1);
-	if (esp->scsi_id == -1)
-		esp->scsi_id = of_getintprop_default(dp,
-						     "scsi-initiator-id",
-						     -1);
-	if (esp->scsi_id == -1)
-		esp->scsi_id = (sdev->bus == NULL) ? 7 :
-			of_getintprop_default(sdev->bus->ofdev.node,
-					      "scsi-initiator-id",
-					      7);
-	esp->ehost->this_id = esp->scsi_id;
-	esp->scsi_id_mask = (1 << esp->scsi_id);
-
-}
-
-static void __init esp_get_clock_params(struct esp *esp)
-{
-	struct sbus_dev *sdev = esp->sdev;
-	int prom_node = esp->prom_node;
-	int sbus_prom_node;
-	unsigned int fmhz;
-	u8 ccf;
-
-	if (sdev != NULL && sdev->bus != NULL)
-		sbus_prom_node = sdev->bus->prom_node;
-	else
-		sbus_prom_node = 0;
-
-	/* This is getting messy but it has to be done
-	 * correctly or else you get weird behavior all
-	 * over the place.  We are trying to basically
-	 * figure out three pieces of information.
-	 *
-	 * a) Clock Conversion Factor
-	 *
-	 *    This is a representation of the input
-	 *    crystal clock frequency going into the
-	 *    ESP on this machine.  Any operation whose
-	 *    timing is longer than 400ns depends on this
-	 *    value being correct.  For example, you'll
-	 *    get blips for arbitration/selection during
-	 *    high load or with multiple targets if this
-	 *    is not set correctly.
-	 *
-	 * b) Selection Time-Out
-	 *
-	 *    The ESP isn't very bright and will arbitrate
-	 *    for the bus and try to select a target
-	 *    forever if you let it.  This value tells
-	 *    the ESP when it has taken too long to
-	 *    negotiate and that it should interrupt
-	 *    the CPU so we can see what happened.
-	 *    The value is computed as follows (from
-	 *    NCR/Symbios chip docs).
-	 *
-	 *          (Time Out Period) *  (Input Clock)
-	 *    STO = ----------------------------------
-	 *          (8192) * (Clock Conversion Factor)
-	 *
-	 *    You usually want the time out period to be
-	 *    around 250ms, I think we'll set it a little
-	 *    bit higher to account for fully loaded SCSI
-	 *    bus's and slow devices that don't respond so
-	 *    quickly to selection attempts. (yeah, I know
-	 *    this is out of spec. but there is a lot of
-	 *    buggy pieces of firmware out there so bite me)
-	 *
-	 * c) Imperical constants for synchronous offset
-	 *    and transfer period register values
-	 *
-	 *    This entails the smallest and largest sync
-	 *    period we could ever handle on this ESP.
-	 */
-
-	fmhz = prom_getintdefault(prom_node, "clock-frequency", -1);
-	if (fmhz == -1)
-		fmhz = (!sbus_prom_node) ? 0 :
-			prom_getintdefault(sbus_prom_node, "clock-frequency", -1);
-
-	if (fmhz <= (5000000))
-		ccf = 0;
-	else
-		ccf = (((5000000 - 1) + (fmhz))/(5000000));
-
-	if (!ccf || ccf > 8) {
-		/* If we can't find anything reasonable,
-		 * just assume 20MHZ.  This is the clock
-		 * frequency of the older sun4c's where I've
-		 * been unable to find the clock-frequency
-		 * PROM property.  All other machines provide
-		 * useful values it seems.
-		 */
-		ccf = ESP_CCF_F4;
-		fmhz = (20000000);
-	}
-
-	if (ccf == (ESP_CCF_F7 + 1))
-		esp->cfact = ESP_CCF_F0;
-	else if (ccf == ESP_CCF_NEVER)
-		esp->cfact = ESP_CCF_F2;
-	else
-		esp->cfact = ccf;
-	esp->raw_cfact = ccf;
-
-	esp->cfreq = fmhz;
-	esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
-	esp->ctick = ESP_TICK(ccf, esp->ccycle);
-	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
-	esp->sync_defp = SYNC_DEFP_SLOW;
-
-	printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ",
-	       esp->scsi_id, (fmhz / 1000000),
-	       (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);
-}
-
-static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
-{
-	struct sbus_dev *sdev = esp->sdev;
-	u8 bursts;
-
-	bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
-
-	if (dma) {
-		u8 tmp = prom_getintdefault(dma->prom_node,
-					    "burst-sizes", 0xff);
-		if (tmp != 0xff)
-			bursts &= tmp;
-	}
-
-	if (sdev->bus) {
-		u8 tmp = prom_getintdefault(sdev->bus->prom_node,
-					    "burst-sizes", 0xff);
-		if (tmp != 0xff)
-			bursts &= tmp;
-	}
-
-	if (bursts == 0xff ||
-	    (bursts & DMA_BURST16) == 0 ||
-	    (bursts & DMA_BURST32) == 0)
-		bursts = (DMA_BURST32 - 1);
-
-	esp->bursts = bursts;
-}
-
-static void __init esp_get_revision(struct esp *esp)
-{
-	u8 tmp;
-
-	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
-	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
-	sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-
-	tmp = sbus_readb(esp->eregs + ESP_CFG2);
-	tmp &= ~ESP_CONFIG2_MAGIC;
-	if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
-		/* If what we write to cfg2 does not come back, cfg2
-		 * is not implemented, therefore this must be a plain
-		 * esp100.
-		 */
-		esp->erev = esp100;
-		printk("NCR53C90(esp100)\n");
-	} else {
-		esp->config2 = 0;
-		esp->prev_cfg3 = esp->config3[0] = 5;
-		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		sbus_writeb(0, esp->eregs + ESP_CFG3);
-		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
-		tmp = sbus_readb(esp->eregs + ESP_CFG3);
-		if (tmp != 5) {
-			/* The cfg2 register is implemented, however
-			 * cfg3 is not, must be esp100a.
-			 */
-			esp->erev = esp100a;
-			printk("NCR53C90A(esp100a)\n");
-		} else {
-			int target;
-
-			for (target = 0; target < 16; target++)
-				esp->config3[target] = 0;
-			esp->prev_cfg3 = 0;
-			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
-			/* All of cfg{1,2,3} implemented, must be one of
-			 * the fas variants, figure out which one.
-			 */
-			if (esp->raw_cfact > ESP_CCF_F5) {
-				esp->erev = fast;
-				esp->sync_defp = SYNC_DEFP_FAST;
-				printk("NCR53C9XF(espfast)\n");
-			} else {
-				esp->erev = esp236;
-				printk("NCR53C9x(esp236)\n");
-			}
-			esp->config2 = 0;
-			sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-		}
-	}
-}
-
-static void __init esp_init_swstate(struct esp *esp)
-{
-	int i;
-
-	/* Command queues... */
-	esp->current_SC = NULL;
-	esp->disconnected_SC = NULL;
-	esp->issue_SC = NULL;
-
-	/* Target and current command state... */
-	esp->targets_present = 0;
-	esp->resetting_bus = 0;
-	esp->snip = 0;
-
-	init_waitqueue_head(&esp->reset_queue);
-
-	/* Debugging... */
-	for(i = 0; i < 32; i++)
-		esp->espcmdlog[i] = 0;
-	esp->espcmdent = 0;
-
-	/* MSG phase state... */
-	for(i = 0; i < 16; i++) {
-		esp->cur_msgout[i] = 0;
-		esp->cur_msgin[i] = 0;
-	}
-	esp->prevmsgout = esp->prevmsgin = 0;
-	esp->msgout_len = esp->msgin_len = 0;
-
-	/* Clear the one behind caches to hold unmatchable values. */
-	esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
-	esp->prev_hme_dmacsr = 0xffffffff;
-}
-
-static int __init detect_one_esp(struct scsi_host_template *tpnt,
-				 struct device *dev,
-				 struct sbus_dev *esp_dev,
-				 struct sbus_dev *espdma,
-				 struct sbus_bus *sbus,
-				 int hme)
-{
-	static int instance;
-	struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
-	struct esp *esp;
-	
-	if (!esp_host)
-		return -ENOMEM;
-
-	if (hme)
-		esp_host->max_id = 16;
-	esp = (struct esp *) esp_host->hostdata;
-	esp->ehost = esp_host;
-	esp->sdev = esp_dev;
-	esp->esp_id = instance;
-	esp->prom_node = esp_dev->prom_node;
-	prom_getstring(esp->prom_node, "name", esp->prom_name,
-		       sizeof(esp->prom_name));
-
-	if (esp_find_dvma(esp, espdma) < 0)
-		goto fail_unlink;
-	if (esp_map_regs(esp, hme) < 0) {
-		printk("ESP registers unmappable");
-		goto fail_dvma_release;
-	}
-	if (esp_map_cmdarea(esp) < 0) {
-		printk("ESP DVMA transport area unmappable");
-		goto fail_unmap_regs;
-	}
-	if (esp_register_irq(esp) < 0)
-		goto fail_unmap_cmdarea;
-
-	esp_get_scsi_id(esp);
-
-	esp->diff = prom_getbool(esp->prom_node, "differential");
-	if (esp->diff)
-		printk("Differential ");
-
-	esp_get_clock_params(esp);
-	esp_get_bursts(esp, espdma);
-	esp_get_revision(esp);
-	esp_init_swstate(esp);
-
-	esp_bootup_reset(esp);
-
-	if (scsi_add_host(esp_host, dev))
-		goto fail_free_irq;
-
-	dev_set_drvdata(&esp_dev->ofdev.dev, esp);
-
-	scsi_scan_host(esp_host);
-	instance++;
-
-	return 0;
-
-fail_free_irq:
-	free_irq(esp->ehost->irq, esp);
-
-fail_unmap_cmdarea:
-	sbus_free_consistent(esp->sdev, 16,
-			     (void *) esp->esp_command,
-			     esp->esp_command_dvma);
-
-fail_unmap_regs:
-	sbus_iounmap(esp->eregs, ESP_REG_SIZE);
-
-fail_dvma_release:
-	esp->dma->allocated = 0;
-
-fail_unlink:
-	scsi_host_put(esp_host);
-	return -1;
-}
-
-/* Detecting ESP chips on the machine.  This is the simple and easy
- * version.
- */
-static int __devexit esp_remove_common(struct esp *esp)
-{
-	unsigned int irq = esp->ehost->irq;
-
-	scsi_remove_host(esp->ehost);
-
-	ESP_INTSOFF(esp->dregs);
-#if 0
-	esp_reset_dma(esp);
-	esp_reset_esp(esp);
-#endif
-
-	free_irq(irq, esp);
-	sbus_free_consistent(esp->sdev, 16,
-			     (void *) esp->esp_command, esp->esp_command_dvma);
-	sbus_iounmap(esp->eregs, ESP_REG_SIZE);
-	esp->dma->allocated = 0;
-
-	scsi_host_put(esp->ehost);
-
-	return 0;
-}
-
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-static struct sbus_dev sun4_esp_dev;
-
-static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
-{
-	if (sun4_esp_physaddr) {
-		memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev));
-		sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
-		sun4_esp_dev.irqs[0] = 4;
-		sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
-		sun4_esp_dev.resource[0].end =
-			sun4_esp_physaddr + ESP_REG_SIZE - 1;
-		sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
-
-		return detect_one_esp(tpnt, NULL,
-				      &sun4_esp_dev, NULL, NULL, 0);
-	}
-	return 0;
-}
-
-static int __devexit esp_sun4_remove(void)
-{
-	struct of_device *dev = &sun4_esp_dev.ofdev;
-	struct esp *esp = dev_get_drvdata(&dev->dev);
-
-	return esp_remove_common(esp);
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-	struct device_node *dp = dev->node;
-	struct sbus_dev *dma_sdev = NULL;
-	int hme = 0;
-
-	if (dp->parent &&
-	    (!strcmp(dp->parent->name, "espdma") ||
-	     !strcmp(dp->parent->name, "dma")))
-		dma_sdev = sdev->parent;
-	else if (!strcmp(dp->name, "SUNW,fas")) {
-		dma_sdev = sdev;
-		hme = 1;
-	}
-
-	return detect_one_esp(match->data, &dev->dev,
-			      sdev, dma_sdev, sdev->bus, hme);
-}
-
-static int __devexit esp_sbus_remove(struct of_device *dev)
-{
-	struct esp *esp = dev_get_drvdata(&dev->dev);
-
-	return esp_remove_common(esp);
-}
-
-#endif /* !CONFIG_SUN4 */
-
-/* The info function will return whatever useful
- * information the developer sees fit.  If not provided, then
- * the name field will be used instead.
- */
-static const char *esp_info(struct Scsi_Host *host)
-{
-	struct esp *esp;
-
-	esp = (struct esp *) host->hostdata;
-	switch (esp->erev) {
-	case esp100:
-		return "Sparc ESP100 (NCR53C90)";
-	case esp100a:
-		return "Sparc ESP100A (NCR53C90A)";
-	case esp236:
-		return "Sparc ESP236";
-	case fas236:
-		return "Sparc ESP236-FAST";
-	case fashme:
-		return "Sparc ESP366-HME";
-	case fas100a:
-		return "Sparc ESP100A-FAST";
-	default:
-		return "Bogon ESP revision";
-	};
-}
-
-/* From Wolfgang Stanglmeier's NCR scsi driver. */
-struct info_str
-{
-	char *buffer;
-	int length;
-	int offset;
-	int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
-	if (info->pos + len > info->length)
-		len = info->length - info->pos;
-
-	if (info->pos + len < info->offset) {
-		info->pos += len;
-		return;
-	}
-	if (info->pos < info->offset) {
-		data += (info->offset - info->pos);
-		len  -= (info->offset - info->pos);
-	}
-
-	if (len > 0) {
-		memcpy(info->buffer + info->pos, data, len);
-		info->pos += len;
-	}
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
-	va_list args;
-	char buf[81];
-	int len;
-
-	va_start(args, fmt);
-	len = vsprintf(buf, fmt, args);
-	va_end(args);
-
-	copy_mem_info(info, buf, len);
-	return len;
-}
-
-static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
-{
-	struct scsi_device *sdev;
-	struct info_str info;
-	int i;
-
-	info.buffer	= ptr;
-	info.length	= len;
-	info.offset	= offset;
-	info.pos	= 0;
-
-	copy_info(&info, "Sparc ESP Host Adapter:\n");
-	copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node);
-	copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
-	copy_info(&info, "\tESP Model\t\t");
-	switch (esp->erev) {
-	case esp100:
-		copy_info(&info, "ESP100\n");
-		break;
-	case esp100a:
-		copy_info(&info, "ESP100A\n");
-		break;
-	case esp236:
-		copy_info(&info, "ESP236\n");
-		break;
-	case fas236:
-		copy_info(&info, "FAS236\n");
-		break;
-	case fas100a:
-		copy_info(&info, "FAS100A\n");
-		break;
-	case fast:
-		copy_info(&info, "FAST\n");
-		break;
-	case fashme:
-		copy_info(&info, "Happy Meal FAS\n");
-		break;
-	case espunknown:
-	default:
-		copy_info(&info, "Unknown!\n");
-		break;
-	};
-	copy_info(&info, "\tDMA Revision\t\t");
-	switch (esp->dma->revision) {
-	case dvmarev0:
-		copy_info(&info, "Rev 0\n");
-		break;
-	case dvmaesc1:
-		copy_info(&info, "ESC Rev 1\n");
-		break;
-	case dvmarev1:
-		copy_info(&info, "Rev 1\n");
-		break;
-	case dvmarev2:
-		copy_info(&info, "Rev 2\n");
-		break;
-	case dvmarev3:
-		copy_info(&info, "Rev 3\n");
-		break;
-	case dvmarevplus:
-		copy_info(&info, "Rev 1+\n");
-		break;
-	case dvmahme:
-		copy_info(&info, "Rev HME/FAS\n");
-		break;
-	default:
-		copy_info(&info, "Unknown!\n");
-		break;
-	};
-	copy_info(&info, "\tLive Targets\t\t[ ");
-	for (i = 0; i < 15; i++) {
-		if (esp->targets_present & (1 << i))
-			copy_info(&info, "%d ", i);
-	}
-	copy_info(&info, "]\n\n");
-	
-	/* Now describe the state of each existing target. */
-	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
-
-	shost_for_each_device(sdev, esp->ehost) {
-		struct esp_device *esp_dev = sdev->hostdata;
-		uint id = sdev->id;
-
-		if (!(esp->targets_present & (1 << id)))
-			continue;
-
-		copy_info(&info, "%d\t\t", id);
-		copy_info(&info, "%08lx\t", esp->config3[id]);
-		copy_info(&info, "[%02lx,%02lx]\t\t\t",
-			esp_dev->sync_max_offset,
-			esp_dev->sync_min_period);
-		copy_info(&info, "%s\t\t",
-			esp_dev->disconnect ? "yes" : "no");
-		copy_info(&info, "%s\n",
-			(esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
-	}
-	return info.pos > info.offset? info.pos - info.offset : 0;
-}
-
-/* ESP proc filesystem code. */
-static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
-			 int length, int inout)
-{
-	struct esp *esp = (struct esp *) host->hostdata;
-
-	if (inout)
-		return -EINVAL; /* not yet */
-
-	if (start)
-		*start = buffer;
-
-	return esp_host_info(esp, buffer, offset, length);
-}
-
-static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
-	if (sp->use_sg == 0) {
-		sp->SCp.this_residual = sp->request_bufflen;
-		sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
-		sp->SCp.buffers_residual = 0;
-		if (sp->request_bufflen) {
-			sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
-							       sp->SCp.this_residual,
-							       sp->sc_data_direction);
-			sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
-		} else {
-			sp->SCp.ptr = NULL;
-		}
-	} else {
-		sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
-		sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
-						       sp->SCp.buffer,
-						       sp->use_sg,
-						       sp->sc_data_direction);
-		sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
-		sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
-	}
-}
-
-static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
-	if (sp->use_sg) {
-		sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
-			      sp->sc_data_direction);
-	} else if (sp->request_bufflen) {
-		sbus_unmap_single(esp->sdev,
-				  sp->SCp.have_data_in,
-				  sp->request_bufflen,
-				  sp->sc_data_direction);
-	}
-}
-
-static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
-	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
-	sp->SCp.ptr = ep->saved_ptr;
-	sp->SCp.buffer = ep->saved_buffer;
-	sp->SCp.this_residual = ep->saved_this_residual;
-	sp->SCp.buffers_residual = ep->saved_buffers_residual;
-}
-
-static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
-	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
-	ep->saved_ptr = sp->SCp.ptr;
-	ep->saved_buffer = sp->SCp.buffer;
-	ep->saved_this_residual = sp->SCp.this_residual;
-	ep->saved_buffers_residual = sp->SCp.buffers_residual;
-}
-
-/* Some rules:
- *
- *   1) Never ever panic while something is live on the bus.
- *      If there is to be any chance of syncing the disks this
- *      rule is to be obeyed.
- *
- *   2) Any target that causes a foul condition will no longer
- *      have synchronous transfers done to it, no questions
- *      asked.
- *
- *   3) Keep register accesses to a minimum.  Think about some
- *      day when we have Xbus machines this is running on and
- *      the ESP chip is on the other end of the machine on a
- *      different board from the cpu where this is running.
- */
-
-/* Fire off a command.  We assume the bus is free and that the only
- * case where we could see an interrupt is where we have disconnected
- * commands active and they are trying to reselect us.
- */
-static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp)
-{
-	switch (sp->cmd_len) {
-	case 6:
-	case 10:
-	case 12:
-		esp->esp_slowcmd = 0;
-		break;
-
-	default:
-		esp->esp_slowcmd = 1;
-		esp->esp_scmdleft = sp->cmd_len;
-		esp->esp_scmdp = &sp->cmnd[0];
-		break;
-	};
-}
-
-static inline void build_sync_nego_msg(struct esp *esp, int period, int offset)
-{
-	esp->cur_msgout[0] = EXTENDED_MESSAGE;
-	esp->cur_msgout[1] = 3;
-	esp->cur_msgout[2] = EXTENDED_SDTR;
-	esp->cur_msgout[3] = period;
-	esp->cur_msgout[4] = offset;
-	esp->msgout_len = 5;
-}
-
-/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
-static inline void build_wide_nego_msg(struct esp *esp, int size)
-{
-	esp->cur_msgout[0] = EXTENDED_MESSAGE;
-	esp->cur_msgout[1] = 2;
-	esp->cur_msgout[2] = EXTENDED_WDTR;
-	switch (size) {
-	case 32:
-		esp->cur_msgout[3] = 2;
-		break;
-	case 16:
-		esp->cur_msgout[3] = 1;
-		break;
-	case 8:
-	default:
-		esp->cur_msgout[3] = 0;
-		break;
-	};
-
-	esp->msgout_len = 4;
-}
-
-static void esp_exec_cmd(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr;
-	struct scsi_device *SDptr;
-	struct esp_device *esp_dev;
-	volatile u8 *cmdp = esp->esp_command;
-	u8 the_esp_command;
-	int lun, target;
-	int i;
-
-	/* Hold off if we have disconnected commands and
-	 * an IRQ is showing...
-	 */
-	if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs))
-		return;
-
-	/* Grab first member of the issue queue. */
-	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
-
-	/* Safe to panic here because current_SC is null. */
-	if (!SCptr)
-		panic("esp: esp_exec_cmd and issue queue is NULL");
-
-	SDptr = SCptr->device;
-	esp_dev = SDptr->hostdata;
-	lun = SCptr->device->lun;
-	target = SCptr->device->id;
-
-	esp->snip = 0;
-	esp->msgout_len = 0;
-
-	/* Send it out whole, or piece by piece?   The ESP
-	 * only knows how to automatically send out 6, 10,
-	 * and 12 byte commands.  I used to think that the
-	 * Linux SCSI code would never throw anything other
-	 * than that to us, but then again there is the
-	 * SCSI generic driver which can send us anything.
-	 */
-	esp_check_cmd(esp, SCptr);
-
-	/* If arbitration/selection is successful, the ESP will leave
-	 * ATN asserted, causing the target to go into message out
-	 * phase.  The ESP will feed the target the identify and then
-	 * the target can only legally go to one of command,
-	 * datain/out, status, or message in phase, or stay in message
-	 * out phase (should we be trying to send a sync negotiation
-	 * message after the identify).  It is not allowed to drop
-	 * BSY, but some buggy targets do and we check for this
-	 * condition in the selection complete code.  Most of the time
-	 * we'll make the command bytes available to the ESP and it
-	 * will not interrupt us until it finishes command phase, we
-	 * cannot do this for command sizes the ESP does not
-	 * understand and in this case we'll get interrupted right
-	 * when the target goes into command phase.
-	 *
-	 * It is absolutely _illegal_ in the presence of SCSI-2 devices
-	 * to use the ESP select w/o ATN command.  When SCSI-2 devices are
-	 * present on the bus we _must_ always go straight to message out
-	 * phase with an identify message for the target.  Being that
-	 * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
-	 * selections should not confuse SCSI-1 we hope.
-	 */
-
-	if (esp_dev->sync) {
-		/* this targets sync is known */
-#ifndef __sparc_v9__
-do_sync_known:
-#endif
-		if (esp_dev->disconnect)
-			*cmdp++ = IDENTIFY(1, lun);
-		else
-			*cmdp++ = IDENTIFY(0, lun);
-
-		if (esp->esp_slowcmd) {
-			the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
-			esp_advance_phase(SCptr, in_slct_stop);
-		} else {
-			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
-			esp_advance_phase(SCptr, in_slct_norm);
-		}
-	} else if (!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
-		/* After the bootup SCSI code sends both the
-		 * TEST_UNIT_READY and INQUIRY commands we want
-		 * to at least attempt allowing the device to
-		 * disconnect.
-		 */
-		ESPMISC(("esp: Selecting device for first time. target=%d "
-			 "lun=%d\n", target, SCptr->device->lun));
-		if (!SDptr->borken && !esp_dev->disconnect)
-			esp_dev->disconnect = 1;
-
-		*cmdp++ = IDENTIFY(0, lun);
-		esp->prevmsgout = NOP;
-		esp_advance_phase(SCptr, in_slct_norm);
-		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
-
-		/* Take no chances... */
-		esp_dev->sync_max_offset = 0;
-		esp_dev->sync_min_period = 0;
-	} else {
-		/* Sorry, I have had way too many problems with
-		 * various CDROM devices on ESP. -DaveM
-		 */
-		int cdrom_hwbug_wkaround = 0;
-
-#ifndef __sparc_v9__
-		/* Never allow disconnects or synchronous transfers on
-		 * SparcStation1 and SparcStation1+.  Allowing those
-		 * to be enabled seems to lockup the machine completely.
-		 */
-		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-			/* But we are nice and allow tapes and removable
-			 * disks (but not CDROMs) to disconnect.
-			 */
-			if(SDptr->type == TYPE_TAPE ||
-			   (SDptr->type != TYPE_ROM && SDptr->removable))
-				esp_dev->disconnect = 1;
-			else
-				esp_dev->disconnect = 0;
-			esp_dev->sync_max_offset = 0;
-			esp_dev->sync_min_period = 0;
-			esp_dev->sync = 1;
-			esp->snip = 0;
-			goto do_sync_known;
-		}
-#endif /* !(__sparc_v9__) */
-
-		/* We've talked to this guy before,
-		 * but never negotiated.  Let's try,
-		 * need to attempt WIDE first, before
-		 * sync nego, as per SCSI 2 standard.
-		 */
-		if (esp->erev == fashme && !esp_dev->wide) {
-			if (!SDptr->borken &&
-			   SDptr->type != TYPE_ROM &&
-			   SDptr->removable == 0) {
-				build_wide_nego_msg(esp, 16);
-				esp_dev->wide = 1;
-				esp->wnip = 1;
-				goto after_nego_msg_built;
-			} else {
-				esp_dev->wide = 1;
-				/* Fall through and try sync. */
-			}
-		}
-
-		if (!SDptr->borken) {
-			if ((SDptr->type == TYPE_ROM)) {
-				/* Nice try sucker... */
-				ESPMISC(("esp%d: Disabling sync for buggy "
-					 "CDROM.\n", esp->esp_id));
-				cdrom_hwbug_wkaround = 1;
-				build_sync_nego_msg(esp, 0, 0);
-			} else if (SDptr->removable != 0) {
-				ESPMISC(("esp%d: Not negotiating sync/wide but "
-					 "allowing disconnect for removable media.\n",
-					 esp->esp_id));
-				build_sync_nego_msg(esp, 0, 0);
-			} else {
-				build_sync_nego_msg(esp, esp->sync_defp, 15);
-			}
-		} else {
-			build_sync_nego_msg(esp, 0, 0);
-		}
-		esp_dev->sync = 1;
-		esp->snip = 1;
-
-after_nego_msg_built:
-		/* A fix for broken SCSI1 targets, when they disconnect
-		 * they lock up the bus and confuse ESP.  So disallow
-		 * disconnects for SCSI1 targets for now until we
-		 * find a better fix.
-		 *
-		 * Addendum: This is funny, I figured out what was going
-		 *           on.  The blotzed SCSI1 target would disconnect,
-		 *           one of the other SCSI2 targets or both would be
-		 *           disconnected as well.  The SCSI1 target would
-		 *           stay disconnected long enough that we start
-		 *           up a command on one of the SCSI2 targets.  As
-		 *           the ESP is arbitrating for the bus the SCSI1
-		 *           target begins to arbitrate as well to reselect
-		 *           the ESP.  The SCSI1 target refuses to drop it's
-		 *           ID bit on the data bus even though the ESP is
-		 *           at ID 7 and is the obvious winner for any
-		 *           arbitration.  The ESP is a poor sport and refuses
-		 *           to lose arbitration, it will continue indefinitely
-		 *           trying to arbitrate for the bus and can only be
-		 *           stopped via a chip reset or SCSI bus reset.
-		 *           Therefore _no_ disconnects for SCSI1 targets
-		 *           thank you very much. ;-)
-		 */
-		if(((SDptr->scsi_level < 3) &&
-		    (SDptr->type != TYPE_TAPE) &&
-		    SDptr->removable == 0) ||
-		    cdrom_hwbug_wkaround || SDptr->borken) {
-			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
-				 "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
-			esp_dev->disconnect = 0;
-			*cmdp++ = IDENTIFY(0, lun);
-		} else {
-			*cmdp++ = IDENTIFY(1, lun);
-		}
-
-		/* ESP fifo is only so big...
-		 * Make this look like a slow command.
-		 */
-		esp->esp_slowcmd = 1;
-		esp->esp_scmdleft = SCptr->cmd_len;
-		esp->esp_scmdp = &SCptr->cmnd[0];
-
-		the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
-		esp_advance_phase(SCptr, in_slct_msg);
-	}
-
-	if (!esp->esp_slowcmd)
-		for (i = 0; i < SCptr->cmd_len; i++)
-			*cmdp++ = SCptr->cmnd[i];
-
-	/* HME sucks... */
-	if (esp->erev == fashme)
-		sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT),
-			    esp->eregs + ESP_BUSID);
-	else
-		sbus_writeb(target & 7, esp->eregs + ESP_BUSID);
-	if (esp->prev_soff != esp_dev->sync_max_offset ||
-	    esp->prev_stp  != esp_dev->sync_min_period ||
-	    (esp->erev > esp100a &&
-	     esp->prev_cfg3 != esp->config3[target])) {
-		esp->prev_soff = esp_dev->sync_max_offset;
-		esp->prev_stp = esp_dev->sync_min_period;
-		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
-		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
-		if (esp->erev > esp100a) {
-			esp->prev_cfg3 = esp->config3[target];
-			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-		}
-	}
-	i = (cmdp - esp->esp_command);
-
-	if (esp->erev == fashme) {
-		esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */
-
-		/* Set up the DMA and HME counters */
-		sbus_writeb(i, esp->eregs + ESP_TCLOW);
-		sbus_writeb(0, esp->eregs + ESP_TCMED);
-		sbus_writeb(0, esp->eregs + FAS_RLO);
-		sbus_writeb(0, esp->eregs + FAS_RHI);
-		esp_cmd(esp, the_esp_command);
-
-		/* Talk about touchy hardware... */
-		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
-					 (DMA_SCSI_DISAB | DMA_ENABLE)) &
-					~(DMA_ST_WRITE));
-		sbus_writel(16, esp->dregs + DMA_COUNT);
-		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-	} else {
-		u32 tmp;
-
-		/* Set up the DMA and ESP counters */
-		sbus_writeb(i, esp->eregs + ESP_TCLOW);
-		sbus_writeb(0, esp->eregs + ESP_TCMED);
-		tmp = sbus_readl(esp->dregs + DMA_CSR);
-		tmp &= ~DMA_ST_WRITE;
-		tmp |= DMA_ENABLE;
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-		if (esp->dma->revision == dvmaesc1) {
-			if (i) /* Workaround ESC gate array SBUS rerun bug. */
-				sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT);
-		}
-		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-
-		/* Tell ESP to "go". */
-		esp_cmd(esp, the_esp_command);
-	}
-}
-
-/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
-static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
-{
-	struct esp *esp;
-
-	/* Set up func ptr and initial driver cmd-phase. */
-	SCpnt->scsi_done = done;
-	SCpnt->SCp.phase = not_issued;
-
-	/* We use the scratch area. */
-	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun));
-	ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun));
-
-	esp = (struct esp *) SCpnt->device->host->hostdata;
-	esp_get_dmabufs(esp, SCpnt);
-	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
-
-	SCpnt->SCp.Status           = CHECK_CONDITION;
-	SCpnt->SCp.Message          = 0xff;
-	SCpnt->SCp.sent_command     = 0;
-
-	/* Place into our queue. */
-	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
-		ESPQUEUE(("RQSENSE\n"));
-		prepend_SC(&esp->issue_SC, SCpnt);
-	} else {
-		ESPQUEUE(("\n"));
-		append_SC(&esp->issue_SC, SCpnt);
-	}
-
-	/* Run it now if we can. */
-	if (!esp->current_SC && !esp->resetting_bus)
-		esp_exec_cmd(esp);
-
-	return 0;
-}
-
-/* Dump driver state. */
-static void esp_dump_cmd(struct scsi_cmnd *SCptr)
-{
-	ESPLOG(("[tgt<%02x> lun<%02x> "
-		"pphase<%s> cphase<%s>]",
-		SCptr->device->id, SCptr->device->lun,
-		phase_string(SCptr->SCp.sent_command),
-		phase_string(SCptr->SCp.phase)));
-}
-
-static void esp_dump_state(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-#ifdef DEBUG_ESP_CMDS
-	int i;
-#endif
-
-	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
-	ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
-		esp->esp_id,
-		sbus_readl(esp->dregs + DMA_CSR),
-		sbus_readl(esp->dregs + DMA_ADDR)));
-	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
-		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
-	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
-		esp->esp_id,
-		sbus_readb(esp->eregs + ESP_STATUS),
-		sbus_readb(esp->eregs + ESP_SSTEP),
-		sbus_readb(esp->eregs + ESP_INTRPT)));
-#ifdef DEBUG_ESP_CMDS
-	printk("esp%d: last ESP cmds [", esp->esp_id);
-	i = (esp->espcmdent - 1) & 31;
-	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
-	i = (i - 1) & 31;
-	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
-	i = (i - 1) & 31;
-	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
-	i = (i - 1) & 31;
-	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
-	printk("]\n");
-#endif /* (DEBUG_ESP_CMDS) */
-
-	if (SCptr) {
-		ESPLOG(("esp%d: current command ", esp->esp_id));
-		esp_dump_cmd(SCptr);
-	}
-	ESPLOG(("\n"));
-	SCptr = esp->disconnected_SC;
-	ESPLOG(("esp%d: disconnected ", esp->esp_id));
-	while (SCptr) {
-		esp_dump_cmd(SCptr);
-		SCptr = (struct scsi_cmnd *) SCptr->host_scribble;
-	}
-	ESPLOG(("\n"));
-}
-
-/* Abort a command.  The host_lock is acquired by caller. */
-static int esp_abort(struct scsi_cmnd *SCptr)
-{
-	struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
-	int don;
-
-	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
-	esp_dump_state(esp);
-
-	/* Wheee, if this is the current command on the bus, the
-	 * best we can do is assert ATN and wait for msgout phase.
-	 * This should even fix a hung SCSI bus when we lose state
-	 * in the driver and timeout because the eventual phase change
-	 * will cause the ESP to (eventually) give an interrupt.
-	 */
-	if (esp->current_SC == SCptr) {
-		esp->cur_msgout[0] = ABORT;
-		esp->msgout_len = 1;
-		esp->msgout_ctr = 0;
-		esp_cmd(esp, ESP_CMD_SATN);
-		return SUCCESS;
-	}
-
-	/* If it is still in the issue queue then we can safely
-	 * call the completion routine and report abort success.
-	 */
-	don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB);
-	if (don) {
-		ESP_INTSOFF(esp->dregs);
-	}
-	if (esp->issue_SC) {
-		struct scsi_cmnd **prev, *this;
-		for (prev = (&esp->issue_SC), this = esp->issue_SC;
-		     this != NULL;
-		     prev = (struct scsi_cmnd **) &(this->host_scribble),
-			     this = (struct scsi_cmnd *) this->host_scribble) {
-
-			if (this == SCptr) {
-				*prev = (struct scsi_cmnd *) this->host_scribble;
-				this->host_scribble = NULL;
-
-				esp_release_dmabufs(esp, this);
-				this->result = DID_ABORT << 16;
-				this->scsi_done(this);
-
-				if (don)
-					ESP_INTSON(esp->dregs);
-
-				return SUCCESS;
-			}
-		}
-	}
-
-	/* Yuck, the command to abort is disconnected, it is not
-	 * worth trying to abort it now if something else is live
-	 * on the bus at this time.  So, we let the SCSI code wait
-	 * a little bit and try again later.
-	 */
-	if (esp->current_SC) {
-		if (don)
-			ESP_INTSON(esp->dregs);
-		return FAILED;
-	}
-
-	/* It's disconnected, we have to reconnect to re-establish
-	 * the nexus and tell the device to abort.  However, we really
-	 * cannot 'reconnect' per se.  Don't try to be fancy, just
-	 * indicate failure, which causes our caller to reset the whole
-	 * bus.
-	 */
-
-	if (don)
-		ESP_INTSON(esp->dregs);
-
-	return FAILED;
-}
-
-/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
- * arrived indicating the end of the SCSI bus reset.  Our job
- * is to clean out the command queues and begin re-execution
- * of SCSI commands once more.
- */
-static int esp_finish_reset(struct esp *esp)
-{
-	struct scsi_cmnd *sp = esp->current_SC;
-
-	/* Clean up currently executing command, if any. */
-	if (sp != NULL) {
-		esp->current_SC = NULL;
-
-		esp_release_dmabufs(esp, sp);
-		sp->result = (DID_RESET << 16);
-
-		sp->scsi_done(sp);
-	}
-
-	/* Clean up disconnected queue, they have been invalidated
-	 * by the bus reset.
-	 */
-	if (esp->disconnected_SC) {
-		while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
-			esp_release_dmabufs(esp, sp);
-			sp->result = (DID_RESET << 16);
-
-			sp->scsi_done(sp);
-		}
-	}
-
-	/* SCSI bus reset is complete. */
-	esp->resetting_bus = 0;
-	wake_up(&esp->reset_queue);
-
-	/* Ok, now it is safe to get commands going once more. */
-	if (esp->issue_SC)
-		esp_exec_cmd(esp);
-
-	return do_intr_end;
-}
-
-static int esp_do_resetbus(struct esp *esp)
-{
-	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
-	esp->resetting_bus = 1;
-	esp_cmd(esp, ESP_CMD_RS);
-
-	return do_intr_end;
-}
-
-/* Reset ESP chip, reset hanging bus, then kill active and
- * disconnected commands for targets without soft reset.
- *
- * The host_lock is acquired by caller.
- */
-static int esp_reset(struct scsi_cmnd *SCptr)
-{
-	struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
-
-	spin_lock_irq(esp->ehost->host_lock);
-	(void) esp_do_resetbus(esp);
-	spin_unlock_irq(esp->ehost->host_lock);
-
-	wait_event(esp->reset_queue, (esp->resetting_bus == 0));
-
-	return SUCCESS;
-}
-
-/* Internal ESP done function. */
-static void esp_done(struct esp *esp, int error)
-{
-	struct scsi_cmnd *done_SC = esp->current_SC;
-
-	esp->current_SC = NULL;
-
-	esp_release_dmabufs(esp, done_SC);
-	done_SC->result = error;
-
-	done_SC->scsi_done(done_SC);
-
-	/* Bus is free, issue any commands in the queue. */
-	if (esp->issue_SC && !esp->current_SC)
-		esp_exec_cmd(esp);
-
-}
-
-/* Wheee, ESP interrupt engine. */  
-
-/* Forward declarations. */
-static int esp_do_phase_determine(struct esp *esp);
-static int esp_do_data_finale(struct esp *esp);
-static int esp_select_complete(struct esp *esp);
-static int esp_do_status(struct esp *esp);
-static int esp_do_msgin(struct esp *esp);
-static int esp_do_msgindone(struct esp *esp);
-static int esp_do_msgout(struct esp *esp);
-static int esp_do_cmdbegin(struct esp *esp);
-
-#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
-#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
-
-/* Read any bytes found in the FAS366 fifo, storing them into
- * the ESP driver software state structure.
- */
-static void hme_fifo_read(struct esp *esp)
-{
-	u8 count = 0;
-	u8 status = esp->sreg;
-
-	/* Cannot safely frob the fifo for these following cases, but
-	 * we must always read the fifo when the reselect interrupt
-	 * is pending.
-	 */
-	if (((esp->ireg & ESP_INTR_RSEL) == 0)	&&
-	    (sreg_datainp(status)		||
-	     sreg_dataoutp(status)		||
-	     (esp->current_SC &&
-	      esp->current_SC->SCp.phase == in_data_done))) {
-		ESPHME(("<wkaround_skipped>"));
-	} else {
-		unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES;
-
-		/* The HME stores bytes in multiples of 2 in the fifo. */
-		ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
-		while (fcnt) {
-			esp->hme_fifo_workaround_buffer[count++] =
-				sbus_readb(esp->eregs + ESP_FDATA);
-			esp->hme_fifo_workaround_buffer[count++] =
-				sbus_readb(esp->eregs + ESP_FDATA);
-			ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
-			fcnt--;
-		}
-		if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) {
-			ESPHME(("<poke_byte>"));
-			sbus_writeb(0, esp->eregs + ESP_FDATA);
-			esp->hme_fifo_workaround_buffer[count++] =
-				sbus_readb(esp->eregs + ESP_FDATA);
-			ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
-			ESPHME(("CMD_FLUSH"));
-			esp_cmd(esp, ESP_CMD_FLUSH);
-		} else {
-			ESPHME(("no_xtra_byte"));
-		}
-	}
-	ESPHME(("wkarnd_cnt=%d]", (int)count));
-	esp->hme_fifo_workaround_count = count;
-}
-
-static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count)
-{
-	esp_cmd(esp, ESP_CMD_FLUSH);
-	while (count) {
-		u8 tmp = *bytes++;
-		sbus_writeb(tmp, esp->eregs + ESP_FDATA);
-		sbus_writeb(0, esp->eregs + ESP_FDATA);
-		count--;
-	}
-}
-
-/* We try to avoid some interrupts by jumping ahead and see if the ESP
- * has gotten far enough yet.  Hence the following.
- */
-static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp,
-			     int prev_phase, int new_phase)
-{
-	if (scp->SCp.sent_command != prev_phase)
-		return 0;
-	if (ESP_IRQ_P(esp->dregs)) {
-		/* Yes, we are able to save an interrupt. */
-		if (esp->erev == fashme)
-			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
-		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
-		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
-		if (esp->erev == fashme) {
-			/* This chip is really losing. */
-			ESPHME(("HME["));
-			/* Must latch fifo before reading the interrupt
-			 * register else garbage ends up in the FIFO
-			 * which confuses the driver utterly.
-			 * Happy Meal indeed....
-			 */
-			ESPHME(("fifo_workaround]"));
-			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
-			    (esp->sreg2 & ESP_STAT2_F1BYTE))
-				hme_fifo_read(esp);
-		}
-		if (!(esp->ireg & ESP_INTR_SR))
-			return 0;
-		else
-			return do_reset_complete;
-	}
-	/* Ho hum, target is taking forever... */
-	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
-	return do_intr_end;
-}
-
-static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp,
-			     int prev_phase1, int prev_phase2, int new_phase)
-{
-	if (scp->SCp.sent_command != prev_phase1 &&
-	    scp->SCp.sent_command != prev_phase2)
-		return 0;
-	if (ESP_IRQ_P(esp->dregs)) {
-		/* Yes, we are able to save an interrupt. */
-		if (esp->erev == fashme)
-			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
-		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
-		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
-		if (esp->erev == fashme) {
-			/* This chip is really losing. */
-			ESPHME(("HME["));
-
-			/* Must latch fifo before reading the interrupt
-			 * register else garbage ends up in the FIFO
-			 * which confuses the driver utterly.
-			 * Happy Meal indeed....
-			 */
-			ESPHME(("fifo_workaround]"));
-			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
-			    (esp->sreg2 & ESP_STAT2_F1BYTE))
-				hme_fifo_read(esp);
-		}
-		if (!(esp->ireg & ESP_INTR_SR))
-			return 0;
-		else
-			return do_reset_complete;
-	}
-	/* Ho hum, target is taking forever... */
-	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
-	return do_intr_end;
-}
-
-/* Now some dma helpers. */
-static void dma_setup(struct esp *esp, __u32 addr, int count, int write)
-{
-	u32 nreg = sbus_readl(esp->dregs + DMA_CSR);
-
-	if (write)
-		nreg |= DMA_ST_WRITE;
-	else
-		nreg &= ~(DMA_ST_WRITE);
-	nreg |= DMA_ENABLE;
-	sbus_writel(nreg, esp->dregs + DMA_CSR);
-	if (esp->dma->revision == dvmaesc1) {
-		/* This ESC gate array sucks! */
-		__u32 src = addr;
-		__u32 dest = src + count;
-
-		if (dest & (PAGE_SIZE - 1))
-			count = PAGE_ALIGN(count);
-		sbus_writel(count, esp->dregs + DMA_COUNT);
-	}
-	sbus_writel(addr, esp->dregs + DMA_ADDR);
-}
-
-static void dma_drain(struct esp *esp)
-{
-	u32 tmp;
-
-	if (esp->dma->revision == dvmahme)
-		return;
-	if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) {
-		switch (esp->dma->revision) {
-		default:
-			tmp |= DMA_FIFO_STDRAIN;
-			sbus_writel(tmp, esp->dregs + DMA_CSR);
-
-		case dvmarev3:
-		case dvmaesc1:
-			while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)
-				udelay(1);
-		};
-	}
-}
-
-static void dma_invalidate(struct esp *esp)
-{
-	u32 tmp;
-
-	if (esp->dma->revision == dvmahme) {
-		sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
-		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
-					 (DMA_PARITY_OFF | DMA_2CLKS |
-					  DMA_SCSI_DISAB | DMA_INT_ENAB)) &
-					~(DMA_ST_WRITE | DMA_ENABLE));
-
-		sbus_writel(0, esp->dregs + DMA_CSR);
-		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
-		/* This is necessary to avoid having the SCSI channel
-		 * engine lock up on us.
-		 */
-		sbus_writel(0, esp->dregs + DMA_ADDR);
-	} else {
-		while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
-			udelay(1);
-
-		tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
-		tmp |= DMA_FIFO_INV;
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-		tmp &= ~DMA_FIFO_INV;
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-	}
-}
-
-static inline void dma_flashclear(struct esp *esp)
-{
-	dma_drain(esp);
-	dma_invalidate(esp);
-}
-
-static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp)
-{
-	__u32 base, end, sz;
-
-	if (esp->dma->revision == dvmarev3) {
-		sz = sp->SCp.this_residual;
-		if (sz > 0x1000000)
-			sz = 0x1000000;
-	} else {
-		base = ((__u32)((unsigned long)sp->SCp.ptr));
-		base &= (0x1000000 - 1);
-		end = (base + sp->SCp.this_residual);
-		if (end > 0x1000000)
-			end = 0x1000000;
-		sz = (end - base);
-	}
-	return sz;
-}
-
-/* Misc. esp helper macros. */
-#define esp_setcount(__eregs, __cnt, __hme) \
-	sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \
-	sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \
-	if (__hme) { \
-		sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \
-		sbus_writeb(0, (__eregs) + FAS_RHI); \
-	}
-
-#define esp_getcount(__eregs, __hme) \
-	((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \
-	 ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \
-         ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))
-
-#define fcount(__esp) \
-	(((__esp)->erev == fashme) ? \
-	  (__esp)->hme_fifo_workaround_count : \
-	  sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)
-
-#define fnzero(__esp) \
-	(((__esp)->erev == fashme) ? 0 : \
-	 sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO)
-
-/* XXX speculative nops unnecessary when continuing amidst a data phase
- * XXX even on esp100!!!  another case of flooding the bus with I/O reg
- * XXX writes...
- */
-#define esp_maybe_nop(__esp) \
-	if ((__esp)->erev == esp100) \
-		esp_cmd((__esp), ESP_CMD_NULL)
-
-#define sreg_to_dataphase(__sreg) \
-	((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
-
-/* The ESP100 when in synchronous data phase, can mistake a long final
- * REQ pulse from the target as an extra byte, it places whatever is on
- * the data lines into the fifo.  For now, we will assume when this
- * happens that the target is a bit quirky and we don't want to
- * be talking synchronously to it anyways.  Regardless, we need to
- * tell the ESP to eat the extraneous byte so that we can proceed
- * to the next phase.
- */
-static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt)
-{
-	/* Do not touch this piece of code. */
-	if ((!(esp->erev == esp100)) ||
-	    (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) &&
-	       !fifocnt) &&
-	     !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) {
-		if (sp->SCp.phase == in_dataout)
-			esp_cmd(esp, ESP_CMD_FLUSH);
-		return 0;
-	} else {
-		/* Async mode for this guy. */
-		build_sync_nego_msg(esp, 0, 0);
-
-		/* Ack the bogus byte, but set ATN first. */
-		esp_cmd(esp, ESP_CMD_SATN);
-		esp_cmd(esp, ESP_CMD_MOK);
-		return 1;
-	}
-}
-
-/* This closes the window during a selection with a reselect pending, because
- * we use DMA for the selection process the FIFO should hold the correct
- * contents if we get reselected during this process.  So we just need to
- * ack the possible illegal cmd interrupt pending on the esp100.
- */
-static inline int esp100_reconnect_hwbug(struct esp *esp)
-{
-	u8 tmp;
-
-	if (esp->erev != esp100)
-		return 0;
-	tmp = sbus_readb(esp->eregs + ESP_INTRPT);
-	if (tmp & ESP_INTR_SR)
-		return 1;
-	return 0;
-}
-
-/* This verifies the BUSID bits during a reselection so that we know which
- * target is talking to us.
- */
-static inline int reconnect_target(struct esp *esp)
-{
-	int it, me = esp->scsi_id_mask, targ = 0;
-
-	if (2 != fcount(esp))
-		return -1;
-	if (esp->erev == fashme) {
-		/* HME does not latch it's own BUS ID bits during
-		 * a reselection.  Also the target number is given
-		 * as an unsigned char, not as a sole bit number
-		 * like the other ESP's do.
-		 * Happy Meal indeed....
-		 */
-		targ = esp->hme_fifo_workaround_buffer[0];
-	} else {
-		it = sbus_readb(esp->eregs + ESP_FDATA);
-		if (!(it & me))
-			return -1;
-		it &= ~me;
-		if (it & (it - 1))
-			return -1;
-		while (!(it & 1))
-			targ++, it >>= 1;
-	}
-	return targ;
-}
-
-/* This verifies the identify from the target so that we know which lun is
- * being reconnected.
- */
-static inline int reconnect_lun(struct esp *esp)
-{
-	int lun;
-
-	if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
-		return -1;
-	if (esp->erev == fashme)
-		lun = esp->hme_fifo_workaround_buffer[1];
-	else
-		lun = sbus_readb(esp->eregs + ESP_FDATA);
-
-	/* Yes, you read this correctly.  We report lun of zero
-	 * if we see parity error.  ESP reports parity error for
-	 * the lun byte, and this is the only way to hope to recover
-	 * because the target is connected.
-	 */
-	if (esp->sreg & ESP_STAT_PERR)
-		return 0;
-
-	/* Check for illegal bits being set in the lun. */
-	if ((lun & 0x40) || !(lun & 0x80))
-		return -1;
-
-	return lun & 7;
-}
-
-/* This puts the driver in a state where it can revitalize a command that
- * is being continued due to reselection.
- */
-static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp)
-{
-	struct esp_device *esp_dev = sp->device->hostdata;
-
-	if (esp->prev_soff  != esp_dev->sync_max_offset ||
-	    esp->prev_stp   != esp_dev->sync_min_period ||
-	    (esp->erev > esp100a &&
-	     esp->prev_cfg3 != esp->config3[sp->device->id])) {
-		esp->prev_soff = esp_dev->sync_max_offset;
-		esp->prev_stp = esp_dev->sync_min_period;
-		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
-		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
-		if (esp->erev > esp100a) {
-			esp->prev_cfg3 = esp->config3[sp->device->id];
-			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-		}
-	}
-	esp->current_SC = sp;
-}
-
-/* This will place the current working command back into the issue queue
- * if we are to receive a reselection amidst a selection attempt.
- */
-static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp)
-{
-	if (!esp->disconnected_SC)
-		ESPLOG(("esp%d: Weird, being reselected but disconnected "
-			"command queue is empty.\n", esp->esp_id));
-	esp->snip = 0;
-	esp->current_SC = NULL;
-	sp->SCp.phase = not_issued;
-	append_SC(&esp->issue_SC, sp);
-}
-
-/* Begin message in phase. */
-static int esp_do_msgin(struct esp *esp)
-{
-	/* Must be very careful with the fifo on the HME */
-	if ((esp->erev != fashme) ||
-	    !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY))
-		esp_cmd(esp, ESP_CMD_FLUSH);
-	esp_maybe_nop(esp);
-	esp_cmd(esp, ESP_CMD_TI);
-	esp->msgin_len = 1;
-	esp->msgin_ctr = 0;
-	esp_advance_phase(esp->current_SC, in_msgindone);
-	return do_work_bus;
-}
-
-/* This uses various DMA csr fields and the fifo flags count value to
- * determine how many bytes were successfully sent/received by the ESP.
- */
-static inline int esp_bytes_sent(struct esp *esp, int fifo_count)
-{
-	int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma;
-
-	if (esp->dma->revision == dvmarev1)
-		rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11));
-	return rval - fifo_count;
-}
-
-static inline void advance_sg(struct scsi_cmnd *sp)
-{
-	++sp->SCp.buffer;
-	--sp->SCp.buffers_residual;
-	sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
-	sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer));
-}
-
-/* Please note that the way I've coded these routines is that I _always_
- * check for a disconnect during any and all information transfer
- * phases.  The SCSI standard states that the target _can_ cause a BUS
- * FREE condition by dropping all MSG/CD/IO/BSY signals.  Also note
- * that during information transfer phases the target controls every
- * change in phase, the only thing the initiator can do is "ask" for
- * a message out phase by driving ATN true.  The target can, and sometimes
- * will, completely ignore this request so we cannot assume anything when
- * we try to force a message out phase to abort/reset a target.  Most of
- * the time the target will eventually be nice and go to message out, so
- * we may have to hold on to our state about what we want to tell the target
- * for some period of time.
- */
-
-/* I think I have things working here correctly.  Even partial transfers
- * within a buffer or sub-buffer should not upset us at all no matter
- * how bad the target and/or ESP fucks things up.
- */
-static int esp_do_data(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	int thisphase, hmuch;
-
-	ESPDATA(("esp_do_data: "));
-	esp_maybe_nop(esp);
-	thisphase = sreg_to_dataphase(esp->sreg);
-	esp_advance_phase(SCptr, thisphase);
-	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
-	hmuch = dma_can_transfer(esp, SCptr);
-	if (hmuch > (64 * 1024) && (esp->erev != fashme))
-		hmuch = (64 * 1024);
-	ESPDATA(("hmuch<%d> ", hmuch));
-	esp->current_transfer_size = hmuch;
-
-	if (esp->erev == fashme) {
-		u32 tmp = esp->prev_hme_dmacsr;
-
-		/* Always set the ESP count registers first. */
-		esp_setcount(esp->eregs, hmuch, 1);
-
-		/* Get the DMA csr computed. */
-		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
-		if (thisphase == in_datain)
-			tmp |= DMA_ST_WRITE;
-		else
-			tmp &= ~(DMA_ST_WRITE);
-		esp->prev_hme_dmacsr = tmp;
-
-		ESPDATA(("DMA|TI --> do_intr_end\n"));
-		if (thisphase == in_datain) {
-			sbus_writel(hmuch, esp->dregs + DMA_COUNT);
-			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-		} else {
-			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-			sbus_writel(hmuch, esp->dregs + DMA_COUNT);
-		}
-		sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR);
-		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-	} else {
-		esp_setcount(esp->eregs, hmuch, 0);
-		dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)),
-			  hmuch, (thisphase == in_datain));
-		ESPDATA(("DMA|TI --> do_intr_end\n"));
-		esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-	}
-	return do_intr_end;
-}
-
-/* See how successful the data transfer was. */
-static int esp_do_data_finale(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	struct esp_device *esp_dev = SCptr->device->hostdata;
-	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
-
-	ESPDATA(("esp_do_data_finale: "));
-
-	if (SCptr->SCp.phase == in_datain) {
-		if (esp->sreg & ESP_STAT_PERR) {
-			/* Yuck, parity error.  The ESP asserts ATN
-			 * so that we can go to message out phase
-			 * immediately and inform the target that
-			 * something bad happened.
-			 */
-			ESPLOG(("esp%d: data bad parity detected.\n",
-				esp->esp_id));
-			esp->cur_msgout[0] = INITIATOR_ERROR;
-			esp->msgout_len = 1;
-		}
-		dma_drain(esp);
-	}
-	dma_invalidate(esp);
-
-	/* This could happen for the above parity error case. */
-	if (esp->ireg != ESP_INTR_BSERV) {
-		/* Please go to msgout phase, please please please... */
-		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
-			esp->esp_id));
-		return esp_do_phase_determine(esp);
-	}	
-
-	/* Check for partial transfers and other horrible events.
-	 * Note, here we read the real fifo flags register even
-	 * on HME broken adapters because we skip the HME fifo
-	 * workaround code in esp_handle() if we are doing data
-	 * phase things.  We don't want to fuck directly with
-	 * the fifo like that, especially if doing synchronous
-	 * transfers!  Also, will need to double the count on
-	 * HME if we are doing wide transfers, as the HME fifo
-	 * will move and count 16-bit quantities during wide data.
-	 * SMCC _and_ Qlogic can both bite me.
-	 */
-	fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
-	if (esp->erev != fashme)
-		ecount = esp_getcount(esp->eregs, 0);
-	bytes_sent = esp->current_transfer_size;
-
-	ESPDATA(("trans_sz(%d), ", bytes_sent));
-	if (esp->erev == fashme) {
-		if (!(esp->sreg & ESP_STAT_TCNT)) {
-			ecount = esp_getcount(esp->eregs, 1);
-			bytes_sent -= ecount;
-		}
-
-		/* Always subtract any cruft remaining in the FIFO. */
-		if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
-			fifocnt <<= 1;
-		if (SCptr->SCp.phase == in_dataout)
-			bytes_sent -= fifocnt;
-
-		/* I have an IBM disk which exhibits the following
-		 * behavior during writes to it.  It disconnects in
-		 * the middle of a partial transfer, the current sglist
-		 * buffer is 1024 bytes, the disk stops data transfer
-		 * at 512 bytes.
-		 *
-		 * However the FAS366 reports that 32 more bytes were
-		 * transferred than really were.  This is precisely
-		 * the size of a fully loaded FIFO in wide scsi mode.
-		 * The FIFO state recorded indicates that it is empty.
-		 *
-		 * I have no idea if this is a bug in the FAS366 chip
-		 * or a bug in the firmware on this IBM disk.  In any
-		 * event the following seems to be a good workaround.  -DaveM
-		 */
-		if (bytes_sent != esp->current_transfer_size &&
-		    SCptr->SCp.phase == in_dataout) {
-			int mask = (64 - 1);
-
-			if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
-				mask >>= 1;
-
-			if (bytes_sent & mask)
-				bytes_sent -= (bytes_sent & mask);
-		}
-	} else {
-		if (!(esp->sreg & ESP_STAT_TCNT))
-			bytes_sent -= ecount;
-		if (SCptr->SCp.phase == in_dataout)
-			bytes_sent -= fifocnt;
-	}
-
-	ESPDATA(("bytes_sent(%d), ", bytes_sent));
-
-	/* If we were in synchronous mode, check for peculiarities. */
-	if (esp->erev == fashme) {
-		if (esp_dev->sync_max_offset) {
-			if (SCptr->SCp.phase == in_dataout)
-				esp_cmd(esp, ESP_CMD_FLUSH);
-		} else {
-			esp_cmd(esp, ESP_CMD_FLUSH);
-		}
-	} else {
-		if (esp_dev->sync_max_offset)
-			bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt);
-		else
-			esp_cmd(esp, ESP_CMD_FLUSH);
-	}
-
-	/* Until we are sure of what has happened, we are certainly
-	 * in the dark.
-	 */
-	esp_advance_phase(SCptr, in_the_dark);
-
-	if (bytes_sent < 0) {
-		/* I've seen this happen due to lost state in this
-		 * driver.  No idea why it happened, but allowing
-		 * this value to be negative caused things to
-		 * lock up.  This allows greater chance of recovery.
-		 * In fact every time I've seen this, it has been
-		 * a driver bug without question.
-		 */
-		ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
-		ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
-			esp->esp_id,
-			esp->current_transfer_size, fifocnt, ecount));
-		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
-			esp->esp_id,
-			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
-		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
-			SCptr->device->id));
-		SCptr->device->borken = 1;
-		esp_dev->sync = 0;
-		bytes_sent = 0;
-	}
-
-	/* Update the state of our transfer. */
-	SCptr->SCp.ptr += bytes_sent;
-	SCptr->SCp.this_residual -= bytes_sent;
-	if (SCptr->SCp.this_residual < 0) {
-		/* shit */
-		ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
-		SCptr->SCp.this_residual = 0;
-	}
-
-	/* Maybe continue. */
-	if (!bogus_data) {
-		ESPDATA(("!bogus_data, "));
-
-		/* NO MATTER WHAT, we advance the scatterlist,
-		 * if the target should decide to disconnect
-		 * in between scatter chunks (which is common)
-		 * we could die horribly!  I used to have the sg
-		 * advance occur only if we are going back into
-		 * (or are staying in) a data phase, you can
-		 * imagine the hell I went through trying to
-		 * figure this out.
-		 */
-		if (SCptr->use_sg && !SCptr->SCp.this_residual)
-			advance_sg(SCptr);
-		if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
-			ESPDATA(("to more data\n"));
-			return esp_do_data(esp);
-		}
-		ESPDATA(("to new phase\n"));
-		return esp_do_phase_determine(esp);
-	}
-	/* Bogus data, just wait for next interrupt. */
-	ESPLOG(("esp%d: bogus_data during end of data phase\n",
-		esp->esp_id));
-	return do_intr_end;
-}
-
-/* We received a non-good status return at the end of
- * running a SCSI command.  This is used to decide if
- * we should clear our synchronous transfer state for
- * such a device when that happens.
- *
- * The idea is that when spinning up a disk or rewinding
- * a tape, we don't want to go into a loop re-negotiating
- * synchronous capabilities over and over.
- */
-static int esp_should_clear_sync(struct scsi_cmnd *sp)
-{
-	u8 cmd = sp->cmnd[0];
-
-	/* These cases are for spinning up a disk and
-	 * waiting for that spinup to complete.
-	 */
-	if (cmd == START_STOP)
-		return 0;
-
-	if (cmd == TEST_UNIT_READY)
-		return 0;
-
-	/* One more special case for SCSI tape drives,
-	 * this is what is used to probe the device for
-	 * completion of a rewind or tape load operation.
-	 */
-	if (sp->device->type == TYPE_TAPE) {
-		if (cmd == MODE_SENSE)
-			return 0;
-	}
-
-	return 1;
-}
-
-/* Either a command is completing or a target is dropping off the bus
- * to continue the command in the background so we can do other work.
- */
-static int esp_do_freebus(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	struct esp_device *esp_dev = SCptr->device->hostdata;
-	int rval;
-
-	rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing);
-	if (rval)
-		return rval;
-	if (esp->ireg != ESP_INTR_DC) {
-		ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
-		return do_reset_bus; /* target will not drop BSY... */
-	}
-	esp->msgout_len = 0;
-	esp->prevmsgout = NOP;
-	if (esp->prevmsgin == COMMAND_COMPLETE) {
-		/* Normal end of nexus. */
-		if (esp->disconnected_SC || (esp->erev == fashme))
-			esp_cmd(esp, ESP_CMD_ESEL);
-
-		if (SCptr->SCp.Status != GOOD &&
-		    SCptr->SCp.Status != CONDITION_GOOD &&
-		    ((1<<SCptr->device->id) & esp->targets_present) &&
-		    esp_dev->sync &&
-		    esp_dev->sync_max_offset) {
-			/* SCSI standard says that the synchronous capabilities
-			 * should be renegotiated at this point.  Most likely
-			 * we are about to request sense from this target
-			 * in which case we want to avoid using sync
-			 * transfers until we are sure of the current target
-			 * state.
-			 */
-			ESPMISC(("esp: Status <%d> for target %d lun %d\n",
-				 SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
-
-			/* But don't do this when spinning up a disk at
-			 * boot time while we poll for completion as it
-			 * fills up the console with messages.  Also, tapes
-			 * can report not ready many times right after
-			 * loading up a tape.
-			 */
-			if (esp_should_clear_sync(SCptr) != 0)
-				esp_dev->sync = 0;
-		}
-		ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
-		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
-			       ((SCptr->SCp.Message & 0xff)<<8) |
-			       (DID_OK << 16)));
-	} else if (esp->prevmsgin == DISCONNECT) {
-		/* Normal disconnect. */
-		esp_cmd(esp, ESP_CMD_ESEL);
-		ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
-		append_SC(&esp->disconnected_SC, SCptr);
-		esp->current_SC = NULL;
-		if (esp->issue_SC)
-			esp_exec_cmd(esp);
-	} else {
-		/* Driver bug, we do not expect a disconnect here
-		 * and should not have advanced the state engine
-		 * to in_freeing.
-		 */
-		ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
-			esp->esp_id));
-		return do_reset_bus;
-	}
-	return do_intr_end;
-}
-
-/* When a reselect occurs, and we cannot find the command to
- * reconnect to in our queues, we do this.
- */
-static int esp_bad_reconnect(struct esp *esp)
-{
-	struct scsi_cmnd *sp;
-
-	ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
-		esp->esp_id));
-	ESPLOG(("QUEUE DUMP\n"));
-	sp = esp->issue_SC;
-	ESPLOG(("esp%d: issue_SC[", esp->esp_id));
-	while (sp) {
-		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
-		sp = (struct scsi_cmnd *) sp->host_scribble;
-	}
-	ESPLOG(("]\n"));
-	sp = esp->current_SC;
-	ESPLOG(("esp%d: current_SC[", esp->esp_id));
-	if (sp)
-		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
-	else
-		ESPLOG(("<NULL>"));
-	ESPLOG(("]\n"));
-	sp = esp->disconnected_SC;
-	ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
-	while (sp) {
-		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
-		sp = (struct scsi_cmnd *) sp->host_scribble;
-	}
-	ESPLOG(("]\n"));
-	return do_reset_bus;
-}
-
-/* Do the needy when a target tries to reconnect to us. */
-static int esp_do_reconnect(struct esp *esp)
-{
-	int lun, target;
-	struct scsi_cmnd *SCptr;
-
-	/* Check for all bogus conditions first. */
-	target = reconnect_target(esp);
-	if (target < 0) {
-		ESPDISC(("bad bus bits\n"));
-		return do_reset_bus;
-	}
-	lun = reconnect_lun(esp);
-	if (lun < 0) {
-		ESPDISC(("target=%2x, bad identify msg\n", target));
-		return do_reset_bus;
-	}
-
-	/* Things look ok... */
-	ESPDISC(("R<%02x,%02x>", target, lun));
-
-	/* Must not flush FIFO or DVMA on HME. */
-	if (esp->erev != fashme) {
-		esp_cmd(esp, ESP_CMD_FLUSH);
-		if (esp100_reconnect_hwbug(esp))
-			return do_reset_bus;
-		esp_cmd(esp, ESP_CMD_NULL);
-	}
-
-	SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun);
-	if (!SCptr)
-		return esp_bad_reconnect(esp);
-
-	esp_connect(esp, SCptr);
-	esp_cmd(esp, ESP_CMD_MOK);
-
-	if (esp->erev == fashme)
-		sbus_writeb(((SCptr->device->id & 0xf) |
-			     (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)),
-			    esp->eregs + ESP_BUSID);
-
-	/* Reconnect implies a restore pointers operation. */
-	esp_restore_pointers(esp, SCptr);
-
-	esp->snip = 0;
-	esp_advance_phase(SCptr, in_the_dark);
-	return do_intr_end;
-}
-
-/* End of NEXUS (hopefully), pick up status + message byte then leave if
- * all goes well.
- */
-static int esp_do_status(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	int intr, rval;
-
-	rval = skipahead1(esp, SCptr, in_the_dark, in_status);
-	if (rval)
-		return rval;
-	intr = esp->ireg;
-	ESPSTAT(("esp_do_status: "));
-	if (intr != ESP_INTR_DC) {
-		int message_out = 0; /* for parity problems */
-
-		/* Ack the message. */
-		ESPSTAT(("ack msg, "));
-		esp_cmd(esp, ESP_CMD_MOK);
-
-		if (esp->erev != fashme) {
-			dma_flashclear(esp);
-
-			/* Wait till the first bits settle. */
-			while (esp->esp_command[0] == 0xff)
-				udelay(1);
-		} else {
-			esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0];
-			esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1];
-		}
-
-		ESPSTAT(("got something, "));
-		/* ESP chimes in with one of
-		 *
-		 * 1) function done interrupt:
-		 *	both status and message in bytes
-		 *	are available
-		 *
-		 * 2) bus service interrupt:
-		 *	only status byte was acquired
-		 *
-		 * 3) Anything else:
-		 *	can't happen, but we test for it
-		 *	anyways
-		 *
-		 * ALSO: If bad parity was detected on either
-		 *       the status _or_ the message byte then
-		 *       the ESP has asserted ATN on the bus
-		 *       and we must therefore wait for the
-		 *       next phase change.
-		 */
-		if (intr & ESP_INTR_FDONE) {
-			/* We got it all, hallejulia. */
-			ESPSTAT(("got both, "));
-			SCptr->SCp.Status = esp->esp_command[0];
-			SCptr->SCp.Message = esp->esp_command[1];
-			esp->prevmsgin = SCptr->SCp.Message;
-			esp->cur_msgin[0] = SCptr->SCp.Message;
-			if (esp->sreg & ESP_STAT_PERR) {
-				/* There was bad parity for the
-				 * message byte, the status byte
-				 * was ok.
-				 */
-				message_out = MSG_PARITY_ERROR;
-			}
-		} else if (intr == ESP_INTR_BSERV) {
-			/* Only got status byte. */
-			ESPLOG(("esp%d: got status only, ", esp->esp_id));
-			if (!(esp->sreg & ESP_STAT_PERR)) {
-				SCptr->SCp.Status = esp->esp_command[0];
-				SCptr->SCp.Message = 0xff;
-			} else {
-				/* The status byte had bad parity.
-				 * we leave the scsi_pointer Status
-				 * field alone as we set it to a default
-				 * of CHECK_CONDITION in esp_queue.
-				 */
-				message_out = INITIATOR_ERROR;
-			}
-		} else {
-			/* This shouldn't happen ever. */
-			ESPSTAT(("got bolixed\n"));
-			esp_advance_phase(SCptr, in_the_dark);
-			return esp_do_phase_determine(esp);
-		}
-
-		if (!message_out) {
-			ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
-				SCptr->SCp.Message));
-			if (SCptr->SCp.Message == COMMAND_COMPLETE) {
-				ESPSTAT(("and was COMMAND_COMPLETE\n"));
-				esp_advance_phase(SCptr, in_freeing);
-				return esp_do_freebus(esp);
-			} else {
-				ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
-					esp->esp_id));
-				esp->msgin_len = esp->msgin_ctr = 1;
-				esp_advance_phase(SCptr, in_msgindone);
-				return esp_do_msgindone(esp);
-			}
-		} else {
-			/* With luck we'll be able to let the target
-			 * know that bad parity happened, it will know
-			 * which byte caused the problems and send it
-			 * again.  For the case where the status byte
-			 * receives bad parity, I do not believe most
-			 * targets recover very well.  We'll see.
-			 */
-			ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
-				esp->esp_id, message_out));
-			esp->cur_msgout[0] = message_out;
-			esp->msgout_len = esp->msgout_ctr = 1;
-			esp_advance_phase(SCptr, in_the_dark);
-			return esp_do_phase_determine(esp);
-		}
-	} else {
-		/* If we disconnect now, all hell breaks loose. */
-		ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
-		esp_advance_phase(SCptr, in_the_dark);
-		return esp_do_phase_determine(esp);
-	}
-}
-
-static int esp_enter_status(struct esp *esp)
-{
-	u8 thecmd = ESP_CMD_ICCSEQ;
-
-	esp_cmd(esp, ESP_CMD_FLUSH);
-	if (esp->erev != fashme) {
-		u32 tmp;
-
-		esp->esp_command[0] = esp->esp_command[1] = 0xff;
-		sbus_writeb(2, esp->eregs + ESP_TCLOW);
-		sbus_writeb(0, esp->eregs + ESP_TCMED);
-		tmp = sbus_readl(esp->dregs + DMA_CSR);
-		tmp |= (DMA_ST_WRITE | DMA_ENABLE);
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-		if (esp->dma->revision == dvmaesc1)
-			sbus_writel(0x100, esp->dregs + DMA_COUNT);
-		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-		thecmd |= ESP_CMD_DMA;
-	}
-	esp_cmd(esp, thecmd);
-	esp_advance_phase(esp->current_SC, in_status);
-
-	return esp_do_status(esp);
-}
-
-static int esp_disconnect_amidst_phases(struct esp *esp)
-{
-	struct scsi_cmnd *sp = esp->current_SC;
-	struct esp_device *esp_dev = sp->device->hostdata;
-
-	/* This means real problems if we see this
-	 * here.  Unless we were actually trying
-	 * to force the device to abort/reset.
-	 */
-	ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
-	ESPLOG(("pphase<%s> cphase<%s>, ",
-		phase_string(sp->SCp.phase),
-		phase_string(sp->SCp.sent_command)));
-
-	if (esp->disconnected_SC != NULL || (esp->erev == fashme))
-		esp_cmd(esp, ESP_CMD_ESEL);
-
-	switch (esp->cur_msgout[0]) {
-	default:
-		/* We didn't expect this to happen at all. */
-		ESPLOG(("device is bolixed\n"));
-		esp_advance_phase(sp, in_tgterror);
-		esp_done(esp, (DID_ERROR << 16));
-		break;
-
-	case BUS_DEVICE_RESET:
-		ESPLOG(("device reset successful\n"));
-		esp_dev->sync_max_offset = 0;
-		esp_dev->sync_min_period = 0;
-		esp_dev->sync = 0;
-		esp_advance_phase(sp, in_resetdev);
-		esp_done(esp, (DID_RESET << 16));
-		break;
-
-	case ABORT:
-		ESPLOG(("device abort successful\n"));
-		esp_advance_phase(sp, in_abortone);
-		esp_done(esp, (DID_ABORT << 16));
-		break;
-
-	};
-	return do_intr_end;
-}
-
-static int esp_enter_msgout(struct esp *esp)
-{
-	esp_advance_phase(esp->current_SC, in_msgout);
-	return esp_do_msgout(esp);
-}
-
-static int esp_enter_msgin(struct esp *esp)
-{
-	esp_advance_phase(esp->current_SC, in_msgin);
-	return esp_do_msgin(esp);
-}
-
-static int esp_enter_cmd(struct esp *esp)
-{
-	esp_advance_phase(esp->current_SC, in_cmdbegin);
-	return esp_do_cmdbegin(esp);
-}
-
-static int esp_enter_badphase(struct esp *esp)
-{
-	ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
-		esp->sreg & ESP_STAT_PMASK));
-	return do_reset_bus;
-}
-
-typedef int (*espfunc_t)(struct esp *);
-
-static espfunc_t phase_vector[] = {
-	esp_do_data,		/* ESP_DOP */
-	esp_do_data,		/* ESP_DIP */
-	esp_enter_cmd,		/* ESP_CMDP */
-	esp_enter_status,	/* ESP_STATP */
-	esp_enter_badphase,	/* ESP_STAT_PMSG */
-	esp_enter_badphase,	/* ESP_STAT_PMSG | ESP_STAT_PIO */
-	esp_enter_msgout,	/* ESP_MOP */
-	esp_enter_msgin,	/* ESP_MIP */
-};
-
-/* The target has control of the bus and we have to see where it has
- * taken us.
- */
-static int esp_do_phase_determine(struct esp *esp)
-{
-	if ((esp->ireg & ESP_INTR_DC) != 0)
-		return esp_disconnect_amidst_phases(esp);
-	return phase_vector[esp->sreg & ESP_STAT_PMASK](esp);
-}
-
-/* First interrupt after exec'ing a cmd comes here. */
-static int esp_select_complete(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	struct esp_device *esp_dev = SCptr->device->hostdata;
-	int cmd_bytes_sent, fcnt;
-
-	if (esp->erev != fashme)
-		esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
-
-	if (esp->erev == fashme)
-		fcnt = esp->hme_fifo_workaround_count;
-	else
-		fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
-
-	cmd_bytes_sent = esp_bytes_sent(esp, fcnt);
-	dma_invalidate(esp);
-
-	/* Let's check to see if a reselect happened
-	 * while we we're trying to select.  This must
-	 * be checked first.
-	 */
-	if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
-		esp_reconnect(esp, SCptr);
-		return esp_do_reconnect(esp);
-	}
-
-	/* Looks like things worked, we should see a bus service &
-	 * a function complete interrupt at this point.  Note we
-	 * are doing a direct comparison because we don't want to
-	 * be fooled into thinking selection was successful if
-	 * ESP_INTR_DC is set, see below.
-	 */
-	if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
-		/* target speaks... */
-		esp->targets_present |= (1<<SCptr->device->id);
-
-		/* What if the target ignores the sdtr? */
-		if (esp->snip)
-			esp_dev->sync = 1;
-
-		/* See how far, if at all, we got in getting
-		 * the information out to the target.
-		 */
-		switch (esp->seqreg) {
-		default:
-
-		case ESP_STEP_ASEL:
-			/* Arbitration won, target selected, but
-			 * we are in some phase which is not command
-			 * phase nor is it message out phase.
-			 *
-			 * XXX We've confused the target, obviously.
-			 * XXX So clear it's state, but we also end
-			 * XXX up clearing everyone elses.  That isn't
-			 * XXX so nice.  I'd like to just reset this
-			 * XXX target, but if I cannot even get it's
-			 * XXX attention and finish selection to talk
-			 * XXX to it, there is not much more I can do.
-			 * XXX If we have a loaded bus we're going to
-			 * XXX spend the next second or so renegotiating
-			 * XXX for synchronous transfers.
-			 */
-			ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
-				esp->esp_id, SCptr->device->id));
-
-		case ESP_STEP_SID:
-			/* Arbitration won, target selected, went
-			 * to message out phase, sent one message
-			 * byte, then we stopped.  ATN is asserted
-			 * on the SCSI bus and the target is still
-			 * there hanging on.  This is a legal
-			 * sequence step if we gave the ESP a select
-			 * and stop command.
-			 *
-			 * XXX See above, I could set the borken flag
-			 * XXX in the device struct and retry the
-			 * XXX command.  But would that help for
-			 * XXX tagged capable targets?
-			 */
-
-		case ESP_STEP_NCMD:
-			/* Arbitration won, target selected, maybe
-			 * sent the one message byte in message out
-			 * phase, but we did not go to command phase
-			 * in the end.  Actually, we could have sent
-			 * only some of the message bytes if we tried
-			 * to send out the entire identify and tag
-			 * message using ESP_CMD_SA3.
-			 */
-			cmd_bytes_sent = 0;
-			break;
-
-		case ESP_STEP_PPC:
-			/* No, not the powerPC pinhead.  Arbitration
-			 * won, all message bytes sent if we went to
-			 * message out phase, went to command phase
-			 * but only part of the command was sent.
-			 *
-			 * XXX I've seen this, but usually in conjunction
-			 * XXX with a gross error which appears to have
-			 * XXX occurred between the time I told the
-			 * XXX ESP to arbitrate and when I got the
-			 * XXX interrupt.  Could I have misloaded the
-			 * XXX command bytes into the fifo?  Actually,
-			 * XXX I most likely missed a phase, and therefore
-			 * XXX went into never never land and didn't even
-			 * XXX know it.  That was the old driver though.
-			 * XXX What is even more peculiar is that the ESP
-			 * XXX showed the proper function complete and
-			 * XXX bus service bits in the interrupt register.
-			 */
-
-		case ESP_STEP_FINI4:
-		case ESP_STEP_FINI5:
-		case ESP_STEP_FINI6:
-		case ESP_STEP_FINI7:
-			/* Account for the identify message */
-			if (SCptr->SCp.phase == in_slct_norm)
-				cmd_bytes_sent -= 1;
-		};
-
-		if (esp->erev != fashme)
-			esp_cmd(esp, ESP_CMD_NULL);
-
-		/* Be careful, we could really get fucked during synchronous
-		 * data transfers if we try to flush the fifo now.
-		 */
-		if ((esp->erev != fashme) && /* not a Happy Meal and... */
-		    !fcnt && /* Fifo is empty and... */
-		    /* either we are not doing synchronous transfers or... */
-		    (!esp_dev->sync_max_offset ||
-		     /* We are not going into data in phase. */
-		     ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
-			esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */
-
-		/* See how far we got if this is not a slow command. */
-		if (!esp->esp_slowcmd) {
-			if (cmd_bytes_sent < 0)
-				cmd_bytes_sent = 0;
-			if (cmd_bytes_sent != SCptr->cmd_len) {
-				/* Crapola, mark it as a slowcmd
-				 * so that we have some chance of
-				 * keeping the command alive with
-				 * good luck.
-				 *
-				 * XXX Actually, if we didn't send it all
-				 * XXX this means either we didn't set things
-				 * XXX up properly (driver bug) or the target
-				 * XXX or the ESP detected parity on one of
-				 * XXX the command bytes.  This makes much
-				 * XXX more sense, and therefore this code
-				 * XXX should be changed to send out a
-				 * XXX parity error message or if the status
-				 * XXX register shows no parity error then
-				 * XXX just expect the target to bring the
-				 * XXX bus into message in phase so that it
-				 * XXX can send us the parity error message.
-				 * XXX SCSI sucks...
-				 */
-				esp->esp_slowcmd = 1;
-				esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
-				esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
-			}
-		}
-
-		/* Now figure out where we went. */
-		esp_advance_phase(SCptr, in_the_dark);
-		return esp_do_phase_determine(esp);
-	}
-
-	/* Did the target even make it? */
-	if (esp->ireg == ESP_INTR_DC) {
-		/* wheee... nobody there or they didn't like
-		 * what we told it to do, clean up.
-		 */
-
-		/* If anyone is off the bus, but working on
-		 * a command in the background for us, tell
-		 * the ESP to listen for them.
-		 */
-		if (esp->disconnected_SC)
-			esp_cmd(esp, ESP_CMD_ESEL);
-
-		if (((1<<SCptr->device->id) & esp->targets_present) &&
-		    esp->seqreg != 0 &&
-		    (esp->cur_msgout[0] == EXTENDED_MESSAGE) &&
-		    (SCptr->SCp.phase == in_slct_msg ||
-		     SCptr->SCp.phase == in_slct_stop)) {
-			/* shit */
-			esp->snip = 0;
-			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
-				"lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
-			esp_dev->sync_max_offset = 0;
-			esp_dev->sync_min_period = 0;
-			esp_dev->sync = 1; /* so we don't negotiate again */
-
-			/* Run the command again, this time though we
-			 * won't try to negotiate for synchronous transfers.
-			 *
-			 * XXX I'd like to do something like send an
-			 * XXX INITIATOR_ERROR or ABORT message to the
-			 * XXX target to tell it, "Sorry I confused you,
-			 * XXX please come back and I will be nicer next
-			 * XXX time".  But that requires having the target
-			 * XXX on the bus, and it has dropped BSY on us.
-			 */
-			esp->current_SC = NULL;
-			esp_advance_phase(SCptr, not_issued);
-			prepend_SC(&esp->issue_SC, SCptr);
-			esp_exec_cmd(esp);
-			return do_intr_end;
-		}
-
-		/* Ok, this is normal, this is what we see during boot
-		 * or whenever when we are scanning the bus for targets.
-		 * But first make sure that is really what is happening.
-		 */
-		if (((1<<SCptr->device->id) & esp->targets_present)) {
-			ESPLOG(("esp%d: Warning, live target %d not responding to "
-				"selection.\n", esp->esp_id, SCptr->device->id));
-
-			/* This _CAN_ happen.  The SCSI standard states that
-			 * the target is to _not_ respond to selection if
-			 * _it_ detects bad parity on the bus for any reason.
-			 * Therefore, we assume that if we've talked successfully
-			 * to this target before, bad parity is the problem.
-			 */
-			esp_done(esp, (DID_PARITY << 16));
-		} else {
-			/* Else, there really isn't anyone there. */
-			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
-			ESPMISC(("esp: target %d lun %d\n",
-				 SCptr->device->id, SCptr->device->lun));
-			esp_done(esp, (DID_BAD_TARGET << 16));
-		}
-		return do_intr_end;
-	}
-
-	ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
-	printk("esp%d: Currently -- ", esp->esp_id);
-	esp_print_ireg(esp->ireg); printk(" ");
-	esp_print_statreg(esp->sreg); printk(" ");
-	esp_print_seqreg(esp->seqreg); printk("\n");
-	printk("esp%d: New -- ", esp->esp_id);
-	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
-	esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP);
-	esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
-	esp_print_ireg(esp->ireg); printk(" ");
-	esp_print_statreg(esp->sreg); printk(" ");
-	esp_print_seqreg(esp->seqreg); printk("\n");
-	ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
-	return do_reset_bus; /* ugh... */
-}
-
-/* Continue reading bytes for msgin phase. */
-static int esp_do_msgincont(struct esp *esp)
-{
-	if (esp->ireg & ESP_INTR_BSERV) {
-		/* in the right phase too? */
-		if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
-			/* phew... */
-			esp_cmd(esp, ESP_CMD_TI);
-			esp_advance_phase(esp->current_SC, in_msgindone);
-			return do_intr_end;
-		}
-
-		/* We changed phase but ESP shows bus service,
-		 * in this case it is most likely that we, the
-		 * hacker who has been up for 20hrs straight
-		 * staring at the screen, drowned in coffee
-		 * smelling like retched cigarette ashes
-		 * have miscoded something..... so, try to
-		 * recover as best we can.
-		 */
-		ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
-	}
-	esp_advance_phase(esp->current_SC, in_the_dark);
-	return do_phase_determine;
-}
-
-static int check_singlebyte_msg(struct esp *esp)
-{
-	esp->prevmsgin = esp->cur_msgin[0];
-	if (esp->cur_msgin[0] & 0x80) {
-		/* wheee... */
-		ESPLOG(("esp%d: target sends identify amidst phases\n",
-			esp->esp_id));
-		esp_advance_phase(esp->current_SC, in_the_dark);
-		return 0;
-	} else if (((esp->cur_msgin[0] & 0xf0) == 0x20) ||
-		   (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
-		esp->msgin_len = 2;
-		esp_advance_phase(esp->current_SC, in_msgincont);
-		return 0;
-	}
-	esp_advance_phase(esp->current_SC, in_the_dark);
-	switch (esp->cur_msgin[0]) {
-	default:
-		/* We don't want to hear about it. */
-		ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
-			esp->cur_msgin[0]));
-		return MESSAGE_REJECT;
-
-	case NOP:
-		ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
-			esp->current_SC->device->id));
-		return 0;
-
-	case RESTORE_POINTERS:
-		/* In this case we might also have to backup the
-		 * "slow command" pointer.  It is rare to get such
-		 * a save/restore pointer sequence so early in the
-		 * bus transition sequences, but cover it.
-		 */
-		if (esp->esp_slowcmd) {
-			esp->esp_scmdleft = esp->current_SC->cmd_len;
-			esp->esp_scmdp = &esp->current_SC->cmnd[0];
-		}
-		esp_restore_pointers(esp, esp->current_SC);
-		return 0;
-
-	case SAVE_POINTERS:
-		esp_save_pointers(esp, esp->current_SC);
-		return 0;
-
-	case COMMAND_COMPLETE:
-	case DISCONNECT:
-		/* Freeing the bus, let it go. */
-		esp->current_SC->SCp.phase = in_freeing;
-		return 0;
-
-	case MESSAGE_REJECT:
-		ESPMISC(("msg reject, "));
-		if (esp->prevmsgout == EXTENDED_MESSAGE) {
-			struct esp_device *esp_dev = esp->current_SC->device->hostdata;
-
-			/* Doesn't look like this target can
-			 * do synchronous or WIDE transfers.
-			 */
-			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
-			esp_dev->sync = 1;
-			esp_dev->wide = 1;
-			esp_dev->sync_min_period = 0;
-			esp_dev->sync_max_offset = 0;
-			return 0;
-		} else {
-			ESPMISC(("not sync nego, sending ABORT\n"));
-			return ABORT;
-		}
-	};
-}
-
-/* Target negotiates for synchronous transfers before we do, this
- * is legal although very strange.  What is even funnier is that
- * the SCSI2 standard specifically recommends against targets doing
- * this because so many initiators cannot cope with this occurring.
- */
-static int target_with_ants_in_pants(struct esp *esp,
-				     struct scsi_cmnd *SCptr,
-				     struct esp_device *esp_dev)
-{
-	if (esp_dev->sync || SCptr->device->borken) {
-		/* sorry, no can do */
-		ESPSDTR(("forcing to async, "));
-		build_sync_nego_msg(esp, 0, 0);
-		esp_dev->sync = 1;
-		esp->snip = 1;
-		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
-		esp_advance_phase(SCptr, in_the_dark);
-		return EXTENDED_MESSAGE;
-	}
-
-	/* Ok, we'll check them out... */
-	return 0;
-}
-
-static void sync_report(struct esp *esp)
-{
-	int msg3, msg4;
-	char *type;
-
-	msg3 = esp->cur_msgin[3];
-	msg4 = esp->cur_msgin[4];
-	if (msg4) {
-		int hz = 1000000000 / (msg3 * 4);
-		int integer = hz / 1000000;
-		int fraction = (hz - (integer * 1000000)) / 10000;
-		if ((esp->erev == fashme) &&
-		    (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) {
-			type = "FAST-WIDE";
-			integer <<= 1;
-			fraction <<= 1;
-		} else if ((msg3 * 4) < 200) {
-			type = "FAST";
-		} else {
-			type = "synchronous";
-		}
-
-		/* Do not transform this back into one big printk
-		 * again, it triggers a bug in our sparc64-gcc272
-		 * sibling call optimization.  -DaveM
-		 */
-		ESPLOG((KERN_INFO "esp%d: target %d ",
-			esp->esp_id, esp->current_SC->device->id));
-		ESPLOG(("[period %dns offset %d %d.%02dMHz ",
-			(int) msg3 * 4, (int) msg4,
-			integer, fraction));
-		ESPLOG(("%s SCSI%s]\n", type,
-			(((msg3 * 4) < 200) ? "-II" : "")));
-	} else {
-		ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
-			esp->esp_id, esp->current_SC->device->id));
-	}
-}
-
-static int check_multibyte_msg(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	struct esp_device *esp_dev = SCptr->device->hostdata;
-	u8 regval = 0;
-	int message_out = 0;
-
-	ESPSDTR(("chk multibyte msg: "));
-	if (esp->cur_msgin[2] == EXTENDED_SDTR) {
-		int period = esp->cur_msgin[3];
-		int offset = esp->cur_msgin[4];
-
-		ESPSDTR(("is sync nego response, "));
-		if (!esp->snip) {
-			int rval;
-
-			/* Target negotiates first! */
-			ESPSDTR(("target jumps the gun, "));
-			message_out = EXTENDED_MESSAGE; /* we must respond */
-			rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
-			if (rval)
-				return rval;
-		}
-
-		ESPSDTR(("examining sdtr, "));
-
-		/* Offset cannot be larger than ESP fifo size. */
-		if (offset > 15) {
-			ESPSDTR(("offset too big %2x, ", offset));
-			offset = 15;
-			ESPSDTR(("sending back new offset\n"));
-			build_sync_nego_msg(esp, period, offset);
-			return EXTENDED_MESSAGE;
-		}
-
-		if (offset && period > esp->max_period) {
-			/* Yeee, async for this slow device. */
-			ESPSDTR(("period too long %2x, ", period));
-			build_sync_nego_msg(esp, 0, 0);
-			ESPSDTR(("hoping for msgout\n"));
-			esp_advance_phase(esp->current_SC, in_the_dark);
-			return EXTENDED_MESSAGE;
-		} else if (offset && period < esp->min_period) {
-			ESPSDTR(("period too short %2x, ", period));
-			period = esp->min_period;
-			if (esp->erev > esp236)
-				regval = 4;
-			else
-				regval = 5;
-		} else if (offset) {
-			int tmp;
-
-			ESPSDTR(("period is ok, "));
-			tmp = esp->ccycle / 1000;
-			regval = (((period << 2) + tmp - 1) / tmp);
-			if (regval && ((esp->erev == fas100a ||
-					esp->erev == fas236  ||
-					esp->erev == fashme))) {
-				if (period >= 50)
-					regval--;
-			}
-		}
-
-		if (offset) {
-			u8 bit;
-
-			esp_dev->sync_min_period = (regval & 0x1f);
-			esp_dev->sync_max_offset = (offset | esp->radelay);
-			if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
-				if ((esp->erev == fas100a) || (esp->erev == fashme))
-					bit = ESP_CONFIG3_FAST;
-				else
-					bit = ESP_CONFIG3_FSCSI;
-				if (period < 50) {
-					/* On FAS366, if using fast-20 synchronous transfers
-					 * we need to make sure the REQ/ACK assert/deassert
-					 * control bits are clear.
-					 */
-					if (esp->erev == fashme)
-						esp_dev->sync_max_offset &= ~esp->radelay;
-					esp->config3[SCptr->device->id] |= bit;
-				} else {
-					esp->config3[SCptr->device->id] &= ~bit;
-				}
-				esp->prev_cfg3 = esp->config3[SCptr->device->id];
-				sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-			}
-			esp->prev_soff = esp_dev->sync_max_offset;
-			esp->prev_stp = esp_dev->sync_min_period;
-			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
-			sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
-			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
-				 esp_dev->sync_max_offset,
-				 esp_dev->sync_min_period,
-				 esp->config3[SCptr->device->id]));
-
-			esp->snip = 0;
-		} else if (esp_dev->sync_max_offset) {
-			u8 bit;
-
-			/* back to async mode */
-			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
-			esp_dev->sync_max_offset = 0;
-			esp_dev->sync_min_period = 0;
-			esp->prev_soff = 0;
-			esp->prev_stp = 0;
-			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
-			sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
-			if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
-				if ((esp->erev == fas100a) || (esp->erev == fashme))
-					bit = ESP_CONFIG3_FAST;
-				else
-					bit = ESP_CONFIG3_FSCSI;
-				esp->config3[SCptr->device->id] &= ~bit;
-				esp->prev_cfg3 = esp->config3[SCptr->device->id];
-				sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-			}
-		}
-
-		sync_report(esp);
-
-		ESPSDTR(("chk multibyte msg: sync is known, "));
-		esp_dev->sync = 1;
-
-		if (message_out) {
-			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
-				esp->esp_id));
-			build_sync_nego_msg(esp, period, offset);
-			esp_advance_phase(SCptr, in_the_dark);
-			return EXTENDED_MESSAGE;
-		}
-
-		ESPSDTR(("returning zero\n"));
-		esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
-		return 0;
-	} else if (esp->cur_msgin[2] == EXTENDED_WDTR) {
-		int size = 8 << esp->cur_msgin[3];
-
-		esp->wnip = 0;
-		if (esp->erev != fashme) {
-			ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n",
-				esp->esp_id));
-			message_out = MESSAGE_REJECT;
-		} else if (size > 16) {
-			ESPLOG(("esp%d: AIEEE wide transfer for %d size "
-				"not supported.\n", esp->esp_id, size));
-			message_out = MESSAGE_REJECT;
-		} else {
-			/* Things look good; let's see what we got. */
-			if (size == 16) {
-				/* Set config 3 register for this target. */
-				esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE;
-			} else {
-				/* Just make sure it was one byte sized. */
-				if (size != 8) {
-					ESPLOG(("esp%d: Aieee, wide nego of %d size.\n",
-						esp->esp_id, size));
-					message_out = MESSAGE_REJECT;
-					goto finish;
-				}
-				/* Pure paranoia. */
-				esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE);
-			}
-			esp->prev_cfg3 = esp->config3[SCptr->device->id];
-			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
-			/* Regardless, next try for sync transfers. */
-			build_sync_nego_msg(esp, esp->sync_defp, 15);
-			esp_dev->sync = 1;
-			esp->snip = 1;
-			message_out = EXTENDED_MESSAGE;
-		}
-	} else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
-		ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
-		message_out = MESSAGE_REJECT;
-	}
-finish:
-	esp_advance_phase(SCptr, in_the_dark);
-	return message_out;
-}
-
-static int esp_do_msgindone(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	int message_out = 0, it = 0, rval;
-
-	rval = skipahead1(esp, SCptr, in_msgin, in_msgindone);
-	if (rval)
-		return rval;
-	if (SCptr->SCp.sent_command != in_status) {
-		if (!(esp->ireg & ESP_INTR_DC)) {
-			if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
-				message_out = MSG_PARITY_ERROR;
-				esp_cmd(esp, ESP_CMD_FLUSH);
-			} else if (esp->erev != fashme &&
-			  (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) {
-				/* We certainly dropped the ball somewhere. */
-				message_out = INITIATOR_ERROR;
-				esp_cmd(esp, ESP_CMD_FLUSH);
-			} else if (!esp->msgin_len) {
-				if (esp->erev == fashme)
-					it = esp->hme_fifo_workaround_buffer[0];
-				else
-					it = sbus_readb(esp->eregs + ESP_FDATA);
-				esp_advance_phase(SCptr, in_msgincont);
-			} else {
-				/* it is ok and we want it */
-				if (esp->erev == fashme)
-					it = esp->cur_msgin[esp->msgin_ctr] =
-						esp->hme_fifo_workaround_buffer[0];
-				else
-					it = esp->cur_msgin[esp->msgin_ctr] =
-						sbus_readb(esp->eregs + ESP_FDATA);
-				esp->msgin_ctr++;
-			}
-		} else {
-			esp_advance_phase(SCptr, in_the_dark);
-			return do_work_bus;
-		}
-	} else {
-		it = esp->cur_msgin[0];
-	}
-	if (!message_out && esp->msgin_len) {
-		if (esp->msgin_ctr < esp->msgin_len) {
-			esp_advance_phase(SCptr, in_msgincont);
-		} else if (esp->msgin_len == 1) {
-			message_out = check_singlebyte_msg(esp);
-		} else if (esp->msgin_len == 2) {
-			if (esp->cur_msgin[0] == EXTENDED_MESSAGE) {
-				if ((it + 2) >= 15) {
-					message_out = MESSAGE_REJECT;
-				} else {
-					esp->msgin_len = (it + 2);
-					esp_advance_phase(SCptr, in_msgincont);
-				}
-			} else {
-				message_out = MESSAGE_REJECT; /* foo on you */
-			}
-		} else {
-			message_out = check_multibyte_msg(esp);
-		}
-	}
-	if (message_out < 0) {
-		return -message_out;
-	} else if (message_out) {
-		if (((message_out != 1) &&
-		     ((message_out < 0x20) || (message_out & 0x80))))
-			esp->msgout_len = 1;
-		esp->cur_msgout[0] = message_out;
-		esp_cmd(esp, ESP_CMD_SATN);
-		esp_advance_phase(SCptr, in_the_dark);
-		esp->msgin_len = 0;
-	}
-	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
-	esp->sreg &= ~(ESP_STAT_INTR);
-	if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
-		esp_cmd(esp, ESP_CMD_MOK);
-	if ((SCptr->SCp.sent_command == in_msgindone) &&
-	    (SCptr->SCp.phase == in_freeing))
-		return esp_do_freebus(esp);
-	return do_intr_end;
-}
-
-static int esp_do_cmdbegin(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-
-	esp_advance_phase(SCptr, in_cmdend);
-	if (esp->erev == fashme) {
-		u32 tmp = sbus_readl(esp->dregs + DMA_CSR);
-		int i;
-
-		for (i = 0; i < esp->esp_scmdleft; i++)
-			esp->esp_command[i] = *esp->esp_scmdp++;
-		esp->esp_scmdleft = 0;
-		esp_cmd(esp, ESP_CMD_FLUSH);
-		esp_setcount(esp->eregs, i, 1);
-		esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI));
-		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
-		tmp &= ~(DMA_ST_WRITE);
-		sbus_writel(i, esp->dregs + DMA_COUNT);
-		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-		sbus_writel(tmp, esp->dregs + DMA_CSR);
-	} else {
-		u8 tmp;
-
-		esp_cmd(esp, ESP_CMD_FLUSH);
-		tmp = *esp->esp_scmdp++;
-		esp->esp_scmdleft--;
-		sbus_writeb(tmp, esp->eregs + ESP_FDATA);
-		esp_cmd(esp, ESP_CMD_TI);
-	}
-	return do_intr_end;
-}
-
-static int esp_do_cmddone(struct esp *esp)
-{
-	if (esp->erev == fashme)
-		dma_invalidate(esp);
-	else
-		esp_cmd(esp, ESP_CMD_NULL);
-
-	if (esp->ireg & ESP_INTR_BSERV) {
-		esp_advance_phase(esp->current_SC, in_the_dark);
-		return esp_do_phase_determine(esp);
-	}
-
-	ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
-		esp->esp_id));
-	return do_reset_bus;
-}
-
-static int esp_do_msgout(struct esp *esp)
-{
-	esp_cmd(esp, ESP_CMD_FLUSH);
-	switch (esp->msgout_len) {
-	case 1:
-		if (esp->erev == fashme)
-			hme_fifo_push(esp, &esp->cur_msgout[0], 1);
-		else
-			sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
-
-		esp_cmd(esp, ESP_CMD_TI);
-		break;
-
-	case 2:
-		esp->esp_command[0] = esp->cur_msgout[0];
-		esp->esp_command[1] = esp->cur_msgout[1];
-
-		if (esp->erev == fashme) {
-			hme_fifo_push(esp, &esp->cur_msgout[0], 2);
-			esp_cmd(esp, ESP_CMD_TI);
-		} else {
-			dma_setup(esp, esp->esp_command_dvma, 2, 0);
-			esp_setcount(esp->eregs, 2, 0);
-			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-		}
-		break;
-
-	case 4:
-		esp->esp_command[0] = esp->cur_msgout[0];
-		esp->esp_command[1] = esp->cur_msgout[1];
-		esp->esp_command[2] = esp->cur_msgout[2];
-		esp->esp_command[3] = esp->cur_msgout[3];
-		esp->snip = 1;
-
-		if (esp->erev == fashme) {
-			hme_fifo_push(esp, &esp->cur_msgout[0], 4);
-			esp_cmd(esp, ESP_CMD_TI);
-		} else {
-			dma_setup(esp, esp->esp_command_dvma, 4, 0);
-			esp_setcount(esp->eregs, 4, 0);
-			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-		}
-		break;
-
-	case 5:
-		esp->esp_command[0] = esp->cur_msgout[0];
-		esp->esp_command[1] = esp->cur_msgout[1];
-		esp->esp_command[2] = esp->cur_msgout[2];
-		esp->esp_command[3] = esp->cur_msgout[3];
-		esp->esp_command[4] = esp->cur_msgout[4];
-		esp->snip = 1;
-
-		if (esp->erev == fashme) {
-			hme_fifo_push(esp, &esp->cur_msgout[0], 5);
-			esp_cmd(esp, ESP_CMD_TI);
-		} else {
-			dma_setup(esp, esp->esp_command_dvma, 5, 0);
-			esp_setcount(esp->eregs, 5, 0);
-			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
-		}
-		break;
-
-	default:
-		/* whoops */
-		ESPMISC(("bogus msgout sending NOP\n"));
-		esp->cur_msgout[0] = NOP;
-
-		if (esp->erev == fashme) {
-			hme_fifo_push(esp, &esp->cur_msgout[0], 1);
-		} else {
-			sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
-		}
-
-		esp->msgout_len = 1;
-		esp_cmd(esp, ESP_CMD_TI);
-		break;
-	};
-
-	esp_advance_phase(esp->current_SC, in_msgoutdone);
-	return do_intr_end;
-}
-
-static int esp_do_msgoutdone(struct esp *esp)
-{
-	if (esp->msgout_len > 1) {
-		/* XXX HME/FAS ATN deassert workaround required,
-		 * XXX no DMA flushing, only possible ESP_CMD_FLUSH
-		 * XXX to kill the fifo.
-		 */
-		if (esp->erev != fashme) {
-			u32 tmp;
-
-			while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
-				udelay(1);
-			tmp &= ~DMA_ENABLE;
-			sbus_writel(tmp, esp->dregs + DMA_CSR);
-			dma_invalidate(esp);
-		} else {
-			esp_cmd(esp, ESP_CMD_FLUSH);
-		}
-	}
-	if (!(esp->ireg & ESP_INTR_DC)) {
-		if (esp->erev != fashme)
-			esp_cmd(esp, ESP_CMD_NULL);
-		switch (esp->sreg & ESP_STAT_PMASK) {
-		case ESP_MOP:
-			/* whoops, parity error */
-			ESPLOG(("esp%d: still in msgout, parity error assumed\n",
-				esp->esp_id));
-			if (esp->msgout_len > 1)
-				esp_cmd(esp, ESP_CMD_SATN);
-			esp_advance_phase(esp->current_SC, in_msgout);
-			return do_work_bus;
-
-		case ESP_DIP:
-			break;
-
-		default:
-			/* Happy Meal fifo is touchy... */
-			if ((esp->erev != fashme) &&
-			    !fcount(esp) &&
-			    !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
-				esp_cmd(esp, ESP_CMD_FLUSH);
-			break;
-
-		};
-	} else {
-		ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
-		return do_reset_bus;
-	}
-
-	/* If we sent out a synchronous negotiation message, update
-	 * our state.
-	 */
-	if (esp->cur_msgout[2] == EXTENDED_MESSAGE &&
-	    esp->cur_msgout[4] == EXTENDED_SDTR) {
-		esp->snip = 1; /* anal retentiveness... */
-	}
-
-	esp->prevmsgout = esp->cur_msgout[0];
-	esp->msgout_len = 0;
-	esp_advance_phase(esp->current_SC, in_the_dark);
-	return esp_do_phase_determine(esp);
-}
-
-static int esp_bus_unexpected(struct esp *esp)
-{
-	ESPLOG(("esp%d: command in weird state %2x\n",
-		esp->esp_id, esp->current_SC->SCp.phase));
-	return do_reset_bus;
-}
-
-static espfunc_t bus_vector[] = {
-	esp_do_data_finale,
-	esp_do_data_finale,
-	esp_bus_unexpected,
-	esp_do_msgin,
-	esp_do_msgincont,
-	esp_do_msgindone,
-	esp_do_msgout,
-	esp_do_msgoutdone,
-	esp_do_cmdbegin,
-	esp_do_cmddone,
-	esp_do_status,
-	esp_do_freebus,
-	esp_do_phase_determine,
-	esp_bus_unexpected,
-	esp_bus_unexpected,
-	esp_bus_unexpected,
-};
-
-/* This is the second tier in our dual-level SCSI state machine. */
-static int esp_work_bus(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr = esp->current_SC;
-	unsigned int phase;
-
-	ESPBUS(("esp_work_bus: "));
-	if (!SCptr) {
-		ESPBUS(("reconnect\n"));
-		return esp_do_reconnect(esp);
-	}
-	phase = SCptr->SCp.phase;
-	if ((phase & 0xf0) == in_phases_mask)
-		return bus_vector[(phase & 0x0f)](esp);
-	else if ((phase & 0xf0) == in_slct_mask)
-		return esp_select_complete(esp);
-	else
-		return esp_bus_unexpected(esp);
-}
-
-static espfunc_t isvc_vector[] = {
-	NULL,
-	esp_do_phase_determine,
-	esp_do_resetbus,
-	esp_finish_reset,
-	esp_work_bus
-};
-
-/* Main interrupt handler for an esp adapter. */
-static void esp_handle(struct esp *esp)
-{
-	struct scsi_cmnd *SCptr;
-	int what_next = do_intr_end;
-
-	SCptr = esp->current_SC;
-
-	/* Check for errors. */
-	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
-	esp->sreg &= (~ESP_STAT_INTR);
-	if (esp->erev == fashme) {
-		esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
-		esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
-	}
-
-	if (esp->sreg & (ESP_STAT_SPAM)) {
-		/* Gross error, could be due to one of:
-		 *
-		 * - top of fifo overwritten, could be because
-		 *   we tried to do a synchronous transfer with
-		 *   an offset greater than ESP fifo size
-		 *
-		 * - top of command register overwritten
-		 *
-		 * - DMA setup to go in one direction, SCSI
-		 *   bus points in the other, whoops
-		 *
-		 * - weird phase change during asynchronous
-		 *   data phase while we are initiator
-		 */
-		ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
-
-		/* If a command is live on the bus we cannot safely
-		 * reset the bus, so we'll just let the pieces fall
-		 * where they may.  Here we are hoping that the
-		 * target will be able to cleanly go away soon
-		 * so we can safely reset things.
-		 */
-		if (!SCptr) {
-			ESPLOG(("esp%d: No current cmd during gross error, "
-				"resetting bus\n", esp->esp_id));
-			what_next = do_reset_bus;
-			goto state_machine;
-		}
-	}
-
-	if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) {
-		/* A DMA gate array error.  Here we must
-		 * be seeing one of two things.  Either the
-		 * virtual to physical address translation
-		 * on the SBUS could not occur, else the
-		 * translation it did get pointed to a bogus
-		 * page.  Ho hum...
-		 */
-		ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
-			sbus_readl(esp->dregs + DMA_CSR)));
-
-		/* DMA gate array itself must be reset to clear the
-		 * error condition.
-		 */
-		esp_reset_dma(esp);
-
-		what_next = do_reset_bus;
-		goto state_machine;
-	}
-
-	esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);   /* Unlatch intr reg */
-
-	if (esp->erev == fashme) {
-		/* This chip is really losing. */
-		ESPHME(("HME["));
-
-		ESPHME(("sreg2=%02x,", esp->sreg2));
-		/* Must latch fifo before reading the interrupt
-		 * register else garbage ends up in the FIFO
-		 * which confuses the driver utterly.
-		 */
-		if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
-		    (esp->sreg2 & ESP_STAT2_F1BYTE)) {
-			ESPHME(("fifo_workaround]"));
-			hme_fifo_read(esp);
-		} else {
-			ESPHME(("no_fifo_workaround]"));
-		}
-	}
-
-	/* No current cmd is only valid at this point when there are
-	 * commands off the bus or we are trying a reset.
-	 */
-	if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
-		/* Panic is safe, since current_SC is null. */
-		ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
-		panic("esp_handle: current_SC == penguin within interrupt!");
-	}
-
-	if (esp->ireg & (ESP_INTR_IC)) {
-		/* Illegal command fed to ESP.  Outside of obvious
-		 * software bugs that could cause this, there is
-		 * a condition with esp100 where we can confuse the
-		 * ESP into an erroneous illegal command interrupt
-		 * because it does not scrape the FIFO properly
-		 * for reselection.  See esp100_reconnect_hwbug()
-		 * to see how we try very hard to avoid this.
-		 */
-		ESPLOG(("esp%d: invalid command\n", esp->esp_id));
-
-		esp_dump_state(esp);
-
-		if (SCptr != NULL) {
-			/* Devices with very buggy firmware can drop BSY
-			 * during a scatter list interrupt when using sync
-			 * mode transfers.  We continue the transfer as
-			 * expected, the target drops the bus, the ESP
-			 * gets confused, and we get a illegal command
-			 * interrupt because the bus is in the disconnected
-			 * state now and ESP_CMD_TI is only allowed when
-			 * a nexus is alive on the bus.
-			 */
-			ESPLOG(("esp%d: Forcing async and disabling disconnect for "
-				"target %d\n", esp->esp_id, SCptr->device->id));
-			SCptr->device->borken = 1; /* foo on you */
-		}
-
-		what_next = do_reset_bus;
-	} else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
-		if (SCptr) {
-			unsigned int phase = SCptr->SCp.phase;
-
-			if (phase & in_phases_mask) {
-				what_next = esp_work_bus(esp);
-			} else if (phase & in_slct_mask) {
-				what_next = esp_select_complete(esp);
-			} else {
-				ESPLOG(("esp%d: interrupt for no good reason...\n",
-					esp->esp_id));
-				what_next = do_intr_end;
-			}
-		} else {
-			ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
-				esp->esp_id));
-			what_next = do_reset_bus;
-		}
-	} else if (esp->ireg & ESP_INTR_SR) {
-		ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
-		what_next = do_reset_complete;
-	} else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
-		ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
-			esp->esp_id));
-		what_next = do_reset_bus;
-	} else if (esp->ireg & ESP_INTR_RSEL) {
-		if (SCptr == NULL) {
-			/* This is ok. */
-			what_next = esp_do_reconnect(esp);
-		} else if (SCptr->SCp.phase & in_slct_mask) {
-			/* Only selection code knows how to clean
-			 * up properly.
-			 */
-			ESPDISC(("Reselected during selection attempt\n"));
-			what_next = esp_select_complete(esp);
-		} else {
-			ESPLOG(("esp%d: Reselected while bus is busy\n",
-				esp->esp_id));
-			what_next = do_reset_bus;
-		}
-	}
-
-	/* This is tier-one in our dual level SCSI state machine. */
-state_machine:
-	while (what_next != do_intr_end) {
-		if (what_next >= do_phase_determine &&
-		    what_next < do_intr_end) {
-			what_next = isvc_vector[what_next](esp);
-		} else {
-			/* state is completely lost ;-( */
-			ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
-				esp->esp_id));
-			what_next = do_reset_bus;
-		}
-	}
-}
-
-/* Service only the ESP described by dev_id. */
-static irqreturn_t esp_intr(int irq, void *dev_id)
-{
-	struct esp *esp = dev_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(esp->ehost->host_lock, flags);
-	if (ESP_IRQ_P(esp->dregs)) {
-		ESP_INTSOFF(esp->dregs);
-
-		ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
-		esp_handle(esp);
-		ESPIRQ((")"));
-
-		ESP_INTSON(esp->dregs);
-	}
-	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
-
-	return IRQ_HANDLED;
-}
-
-static int esp_slave_alloc(struct scsi_device *SDptr)
-{
-	struct esp_device *esp_dev =
-		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
-
-	if (!esp_dev)
-		return -ENOMEM;
-	memset(esp_dev, 0, sizeof(struct esp_device));
-	SDptr->hostdata = esp_dev;
-	return 0;
-}
-
-static void esp_slave_destroy(struct scsi_device *SDptr)
-{
-	struct esp *esp = (struct esp *) SDptr->host->hostdata;
-
-	esp->targets_present &= ~(1 << SDptr->id);
-	kfree(SDptr->hostdata);
-	SDptr->hostdata = NULL;
-}
-
-static struct scsi_host_template esp_template = {
-	.module			= THIS_MODULE,
-	.name			= "esp",
-	.info			= esp_info,
-	.slave_alloc		= esp_slave_alloc,
-	.slave_destroy		= esp_slave_destroy,
-	.queuecommand		= esp_queue,
-	.eh_abort_handler	= esp_abort,
-	.eh_bus_reset_handler	= esp_reset,
-	.can_queue		= 7,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= 1,
-	.use_clustering		= ENABLE_CLUSTERING,
-	.proc_name		= "esp",
-	.proc_info		= esp_proc_info,
-};
-
-#ifndef CONFIG_SUN4
-static struct of_device_id esp_match[] = {
-	{
-		.name = "SUNW,esp",
-		.data = &esp_template,
-	},
-	{
-		.name = "SUNW,fas",
-		.data = &esp_template,
-	},
-	{
-		.name = "esp",
-		.data = &esp_template,
-	},
-	{},
-};
-MODULE_DEVICE_TABLE(of, esp_match);
-
-static struct of_platform_driver esp_sbus_driver = {
-	.name		= "esp",
-	.match_table	= esp_match,
-	.probe		= esp_sbus_probe,
-	.remove		= __devexit_p(esp_sbus_remove),
-};
-#endif
-
-static int __init esp_init(void)
-{
-#ifdef CONFIG_SUN4
-	return esp_sun4_probe(&esp_template);
-#else
-	return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
-#endif
-}
-
-static void __exit esp_exit(void)
-{
-#ifdef CONFIG_SUN4
-	esp_sun4_remove();
-#else
-	of_unregister_driver(&esp_sbus_driver);
-#endif
-}
-
-MODULE_DESCRIPTION("ESP Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_init(esp_init);
-module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
deleted file mode 100644
index a98cda9..0000000
--- a/drivers/scsi/esp.h
+++ /dev/null
@@ -1,406 +0,0 @@
-/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $
- * esp.h:  Defines and structures for the Sparc ESP (Enhanced SCSI
- *         Processor) driver under Linux.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_ESP_H
-#define _SPARC_ESP_H
-
-/* For dvma controller register definitions. */
-#include <asm/dma.h>
-
-/* The ESP SCSI controllers have their register sets in three
- * "classes":
- *
- * 1) Registers which are both read and write.
- * 2) Registers which are read only.
- * 3) Registers which are write only.
- *
- * Yet, they all live within the same IO space.
- */
-
-/* All the ESP registers are one byte each and are accessed longwords
- * apart with a big-endian ordering to the bytes.
- */
-					/* Access    Description              Offset */
-#define ESP_TCLOW	0x00UL		/* rw  Low bits of the transfer count 0x00   */
-#define ESP_TCMED	0x04UL		/* rw  Mid bits of the transfer count 0x04   */
-#define ESP_FDATA	0x08UL		/* rw  FIFO data bits                 0x08   */
-#define ESP_CMD		0x0cUL		/* rw  SCSI command bits              0x0c   */
-#define ESP_STATUS	0x10UL		/* ro  ESP status register            0x10   */
-#define ESP_BUSID	ESP_STATUS	/* wo  Bus ID for select/reselect     0x10   */
-#define ESP_INTRPT	0x14UL		/* ro  Kind of interrupt              0x14   */
-#define ESP_TIMEO	ESP_INTRPT	/* wo  Timeout value for select/resel 0x14   */
-#define ESP_SSTEP	0x18UL		/* ro  Sequence step register         0x18   */
-#define ESP_STP		ESP_SSTEP	/* wo  Transfer period per sync       0x18   */
-#define ESP_FFLAGS	0x1cUL		/* ro  Bits of current FIFO info      0x1c   */
-#define ESP_SOFF	ESP_FFLAGS	/* wo  Sync offset                    0x1c   */
-#define ESP_CFG1	0x20UL		/* rw  First configuration register   0x20   */
-#define ESP_CFACT	0x24UL		/* wo  Clock conversion factor        0x24   */
-#define ESP_STATUS2	ESP_CFACT	/* ro  HME status2 register           0x24   */
-#define ESP_CTEST	0x28UL		/* wo  Chip test register             0x28   */
-#define ESP_CFG2	0x2cUL		/* rw  Second configuration register  0x2c   */
-#define ESP_CFG3	0x30UL		/* rw  Third configuration register   0x30   */
-#define ESP_TCHI	0x38UL		/* rw  High bits of transfer count    0x38   */
-#define ESP_UID		ESP_TCHI	/* ro  Unique ID code                 0x38   */
-#define FAS_RLO		ESP_TCHI	/* rw  HME extended counter           0x38   */
-#define ESP_FGRND	0x3cUL		/* rw  Data base for fifo             0x3c   */
-#define FAS_RHI		ESP_FGRND	/* rw  HME extended counter           0x3c   */
-#define ESP_REG_SIZE	0x40UL
-
-/* Various revisions of the ESP board. */
-enum esp_rev {
-	esp100     = 0x00,  /* NCR53C90 - very broken */
-	esp100a    = 0x01,  /* NCR53C90A */
-	esp236     = 0x02,
-	fas236     = 0x03,
-	fas100a    = 0x04,
-	fast       = 0x05,
-	fashme     = 0x06,
-	espunknown = 0x07
-};
-
-/* We allocate one of these for each scsi device and attach it to
- * SDptr->hostdata for use in the driver
- */
-struct esp_device {
-  unsigned char sync_min_period;
-  unsigned char sync_max_offset;
-  unsigned sync:1;
-  unsigned wide:1;
-  unsigned disconnect:1;
-};
-
-struct scsi_cmnd;
-
-/* We get one of these for each ESP probed. */
-struct esp {
-	void __iomem		*eregs;		/* ESP controller registers */
-	void __iomem		*dregs;		/* DMA controller registers */
-	struct sbus_dma		*dma;		/* DMA controller sw state */
-	struct Scsi_Host	*ehost;		/* Backpointer to SCSI Host */
-	struct sbus_dev		*sdev;		/* Pointer to SBus entry */
-
-	/* ESP Configuration Registers */
-	u8			config1;	/* Copy of the 1st config register */
-	u8			config2;	/* Copy of the 2nd config register */
-	u8			config3[16];	/* Copy of the 3rd config register */
-
-	/* The current command we are sending to the ESP chip.  This esp_command
-	 * ptr needs to be mapped in DVMA area so we can send commands and read
-	 * from the ESP fifo without burning precious CPU cycles.  Programmed I/O
-	 * sucks when we have the DVMA to do it for us.  The ESP is stupid and will
-	 * only send out 6, 10, and 12 byte SCSI commands, others we need to send
-	 * one byte at a time.  esp_slowcmd being set says that we are doing one
-	 * of the command types ESP doesn't understand, esp_scmdp keeps track of
-	 * which byte we are sending, esp_scmdleft says how many bytes to go.
-	 */
-	volatile u8		*esp_command;    /* Location of command (CPU view)  */
-	__u32			esp_command_dvma;/* Location of command (DVMA view) */
-	unsigned char		esp_clen;	 /* Length of this command */
-	unsigned char		esp_slowcmd;
-	unsigned char		*esp_scmdp;
-	unsigned char		esp_scmdleft;
-
-	/* The following are used to determine the cause of an IRQ. Upon every
-	 * IRQ entry we synchronize these with the hardware registers.
-	 */
-	u8			ireg;		/* Copy of ESP interrupt register */
-	u8			sreg;		/* Copy of ESP status register */
-	u8			seqreg;		/* Copy of ESP sequence step register */
-	u8			sreg2;		/* Copy of HME status2 register */
-
-	/* To save register writes to the ESP, which can be expensive, we
-	 * keep track of the previous value that various registers had for
-	 * the last target we connected to.  If they are the same for the
-	 * current target, we skip the register writes as they are not needed.
-	 */
-	u8			prev_soff, prev_stp;
-	u8			prev_cfg3, __cache_pad;
-
-	/* We also keep a cache of the previous FAS/HME DMA CSR register value.  */
-	u32			prev_hme_dmacsr;
-
-	/* The HME is the biggest piece of shit I have ever seen. */
-	u8			hme_fifo_workaround_buffer[16 * 2];
-	u8			hme_fifo_workaround_count;
-
-	/* For each target we keep track of save/restore data
-	 * pointer information.  This needs to be updated majorly
-	 * when we add support for tagged queueing.  -DaveM
-	 */
-	struct esp_pointers {
-		char			*saved_ptr;
-		struct scatterlist	*saved_buffer;
-		int			saved_this_residual;
-		int			saved_buffers_residual;
-	} data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
-
-	/* Clock periods, frequencies, synchronization, etc. */
-	unsigned int		cfreq;		/* Clock frequency in HZ */
-	unsigned int		cfact;		/* Clock conversion factor */
-	unsigned int		raw_cfact;	/* Raw copy from probing */
-	unsigned int		ccycle;		/* One ESP clock cycle */
-	unsigned int		ctick;		/* One ESP clock time */
-	unsigned int		radelay;	/* FAST chip req/ack delay */
-	unsigned int		neg_defp;	/* Default negotiation period */
-	unsigned int		sync_defp;	/* Default sync transfer period */
-	unsigned int		max_period;	/* longest our period can be */
-	unsigned int		min_period;	/* shortest period we can withstand */
-
-	struct esp		*next;		/* Next ESP we probed or NULL */
-	char			prom_name[64];	/* Name of ESP device from prom */
-	int			prom_node;	/* Prom node where ESP found */
-	int			esp_id;		/* Unique per-ESP ID number */
-
-	/* For slow to medium speed input clock rates we shoot for 5mb/s,
-	 * but for high input clock rates we try to do 10mb/s although I
-	 * don't think a transfer can even run that fast with an ESP even
-	 * with DMA2 scatter gather pipelining.
-	 */
-#define SYNC_DEFP_SLOW            0x32   /* 5mb/s  */
-#define SYNC_DEFP_FAST            0x19   /* 10mb/s */
-
-	unsigned int		snip;		/* Sync. negotiation in progress */
-	unsigned int		wnip;		/* WIDE negotiation in progress */
-	unsigned int		targets_present;/* targets spoken to before */
-
-	int		current_transfer_size;	/* Set at beginning of data dma */
-
-	u8			espcmdlog[32];	/* Log of current esp cmds sent. */
-	u8			espcmdent;	/* Current entry in esp cmd log. */
-
-	/* Misc. info about this ESP */
-	enum esp_rev		erev;		/* ESP revision */
-	int			irq;		/* SBus IRQ for this ESP */
-	int			scsi_id;	/* Who am I as initiator? */
-	int			scsi_id_mask;	/* Bitmask of 'me'. */
-	int			diff;		/* Differential SCSI bus? */
-	int			bursts;		/* Burst sizes our DVMA supports */
-
-	/* Our command queues, only one cmd lives in the current_SC queue. */
-	struct scsi_cmnd	*issue_SC;	/* Commands to be issued */
-	struct scsi_cmnd	*current_SC;	/* Who is currently working the bus */
-	struct scsi_cmnd	*disconnected_SC;/* Commands disconnected from the bus */
-
-	/* Message goo */
-	u8			cur_msgout[16];
-	u8			cur_msgin[16];
-	u8			prevmsgout, prevmsgin;
-	u8			msgout_len, msgin_len;
-	u8			msgout_ctr, msgin_ctr;
-
-	/* States that we cannot keep in the per cmd structure because they
-	 * cannot be assosciated with any specific command.
-	 */
-	u8			resetting_bus;
-	wait_queue_head_t	reset_queue;
-};
-
-/* Bitfield meanings for the above registers. */
-
-/* ESP config reg 1, read-write, found on all ESP chips */
-#define ESP_CONFIG1_ID        0x07             /* My BUS ID bits */
-#define ESP_CONFIG1_CHTEST    0x08             /* Enable ESP chip tests */
-#define ESP_CONFIG1_PENABLE   0x10             /* Enable parity checks */
-#define ESP_CONFIG1_PARTEST   0x20             /* Parity test mode enabled? */
-#define ESP_CONFIG1_SRRDISAB  0x40             /* Disable SCSI reset reports */
-#define ESP_CONFIG1_SLCABLE   0x80             /* Enable slow cable mode */
-
-/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
-#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236) */
-#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236) */
-#define ESP_CONFIG2_BADPARITY 0x04             /* Bad parity target abort  */
-#define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features (tmode only) */
-#define ESP_CONFIG2_HI        0x10             /* High Impedance DREQ ???  */
-#define ESP_CONFIG2_HMEFENAB  0x10             /* HME features enable */
-#define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236)   */
-#define ESP_CONFIG2_DISPINT   0x20             /* Disable pause irq (hme) */
-#define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216)      */
-#define ESP_CONFIG2_SPL       0x40             /* Enable status-phase latch (esp236)   */
-#define ESP_CONFIG2_MKDONE    0x40             /* HME magic feature */
-#define ESP_CONFIG2_HME32     0x80             /* HME 32 extended */
-#define ESP_CONFIG2_MAGIC     0xe0             /* Invalid bits... */
-
-/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
-#define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a/hme) */
-#define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236)  */
-#define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a/hme) */
-#define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236)  */
-#define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a/hme) */
-#define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236)  */
-#define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a/hme) */
-#define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236)  */
-#define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a/hme) */
-#define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236)  */
-#define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236)  */
-#define ESP_CONFIG3_IDBIT3    0x20             /* Bit 3 of HME SCSI-ID (hme)         */
-#define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236)  */
-#define ESP_CONFIG3_EWIDE     0x40             /* Enable Wide-SCSI     (hme)         */
-#define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236)  */
-#define ESP_CONFIG3_OBPUSH    0x80             /* Push odd-byte to dma (hme)         */
-
-/* ESP command register read-write */
-/* Group 1 commands:  These may be sent at any point in time to the ESP
- *                    chip.  None of them can generate interrupts 'cept
- *                    the "SCSI bus reset" command if you have not disabled
- *                    SCSI reset interrupts in the config1 ESP register.
- */
-#define ESP_CMD_NULL          0x00             /* Null command, ie. a nop */
-#define ESP_CMD_FLUSH         0x01             /* FIFO Flush */
-#define ESP_CMD_RC            0x02             /* Chip reset */
-#define ESP_CMD_RS            0x03             /* SCSI bus reset */
-
-/* Group 2 commands:  ESP must be an initiator and connected to a target
- *                    for these commands to work.
- */
-#define ESP_CMD_TI            0x10             /* Transfer Information */
-#define ESP_CMD_ICCSEQ        0x11             /* Initiator cmd complete sequence */
-#define ESP_CMD_MOK           0x12             /* Message okie-dokie */
-#define ESP_CMD_TPAD          0x18             /* Transfer Pad */
-#define ESP_CMD_SATN          0x1a             /* Set ATN */
-#define ESP_CMD_RATN          0x1b             /* De-assert ATN */
-
-/* Group 3 commands:  ESP must be in the MSGOUT or MSGIN state and be connected
- *                    to a target as the initiator for these commands to work.
- */
-#define ESP_CMD_SMSG          0x20             /* Send message */
-#define ESP_CMD_SSTAT         0x21             /* Send status */
-#define ESP_CMD_SDATA         0x22             /* Send data */
-#define ESP_CMD_DSEQ          0x23             /* Discontinue Sequence */
-#define ESP_CMD_TSEQ          0x24             /* Terminate Sequence */
-#define ESP_CMD_TCCSEQ        0x25             /* Target cmd cmplt sequence */
-#define ESP_CMD_DCNCT         0x27             /* Disconnect */
-#define ESP_CMD_RMSG          0x28             /* Receive Message */
-#define ESP_CMD_RCMD          0x29             /* Receive Command */
-#define ESP_CMD_RDATA         0x2a             /* Receive Data */
-#define ESP_CMD_RCSEQ         0x2b             /* Receive cmd sequence */
-
-/* Group 4 commands:  The ESP must be in the disconnected state and must
- *                    not be connected to any targets as initiator for
- *                    these commands to work.
- */
-#define ESP_CMD_RSEL          0x40             /* Reselect */
-#define ESP_CMD_SEL           0x41             /* Select w/o ATN */
-#define ESP_CMD_SELA          0x42             /* Select w/ATN */
-#define ESP_CMD_SELAS         0x43             /* Select w/ATN & STOP */
-#define ESP_CMD_ESEL          0x44             /* Enable selection */
-#define ESP_CMD_DSEL          0x45             /* Disable selections */
-#define ESP_CMD_SA3           0x46             /* Select w/ATN3 */
-#define ESP_CMD_RSEL3         0x47             /* Reselect3 */
-
-/* This bit enables the ESP's DMA on the SBus */
-#define ESP_CMD_DMA           0x80             /* Do DMA? */
-
-
-/* ESP status register read-only */
-#define ESP_STAT_PIO          0x01             /* IO phase bit */
-#define ESP_STAT_PCD          0x02             /* CD phase bit */
-#define ESP_STAT_PMSG         0x04             /* MSG phase bit */
-#define ESP_STAT_PMASK        0x07             /* Mask of phase bits */
-#define ESP_STAT_TDONE        0x08             /* Transfer Completed */
-#define ESP_STAT_TCNT         0x10             /* Transfer Counter Is Zero */
-#define ESP_STAT_PERR         0x20             /* Parity error */
-#define ESP_STAT_SPAM         0x40             /* Real bad error */
-/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
- * bit on other revs of the ESP.
- */
-#define ESP_STAT_INTR         0x80             /* Interrupt */
-
-/* HME only: status 2 register */
-#define ESP_STAT2_SCHBIT      0x01 /* Upper bits 3-7 of sstep enabled */
-#define ESP_STAT2_FFLAGS      0x02 /* The fifo flags are now latched */
-#define ESP_STAT2_XCNT        0x04 /* The transfer counter is latched */
-#define ESP_STAT2_CREGA       0x08 /* The command reg is active now */
-#define ESP_STAT2_WIDE        0x10 /* Interface on this adapter is wide */
-#define ESP_STAT2_F1BYTE      0x20 /* There is one byte at top of fifo */
-#define ESP_STAT2_FMSB        0x40 /* Next byte in fifo is most significant */
-#define ESP_STAT2_FEMPTY      0x80 /* FIFO is empty */
-
-/* The status register can be masked with ESP_STAT_PMASK and compared
- * with the following values to determine the current phase the ESP
- * (at least thinks it) is in.  For our purposes we also add our own
- * software 'done' bit for our phase management engine.
- */
-#define ESP_DOP   (0)                                       /* Data Out  */
-#define ESP_DIP   (ESP_STAT_PIO)                            /* Data In   */
-#define ESP_CMDP  (ESP_STAT_PCD)                            /* Command   */
-#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO)               /* Status    */
-#define ESP_MOP   (ESP_STAT_PMSG|ESP_STAT_PCD)              /* Message Out */
-#define ESP_MIP   (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
-
-/* ESP interrupt register read-only */
-#define ESP_INTR_S            0x01             /* Select w/o ATN */
-#define ESP_INTR_SATN         0x02             /* Select w/ATN */
-#define ESP_INTR_RSEL         0x04             /* Reselected */
-#define ESP_INTR_FDONE        0x08             /* Function done */
-#define ESP_INTR_BSERV        0x10             /* Bus service */
-#define ESP_INTR_DC           0x20             /* Disconnect */
-#define ESP_INTR_IC           0x40             /* Illegal command given */
-#define ESP_INTR_SR           0x80             /* SCSI bus reset detected */
-
-/* Interrupt status macros */
-#define ESP_SRESET_IRQ(esp)  ((esp)->intreg & (ESP_INTR_SR))
-#define ESP_ILLCMD_IRQ(esp)  ((esp)->intreg & (ESP_INTR_IC))
-#define ESP_SELECT_WITH_ATN_IRQ(esp)     ((esp)->intreg & (ESP_INTR_SATN))
-#define ESP_SELECT_WITHOUT_ATN_IRQ(esp)  ((esp)->intreg & (ESP_INTR_S))
-#define ESP_SELECTION_IRQ(esp)  ((ESP_SELECT_WITH_ATN_IRQ(esp)) ||         \
-				 (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
-#define ESP_RESELECTION_IRQ(esp)         ((esp)->intreg & (ESP_INTR_RSEL))
-
-/* ESP sequence step register read-only */
-#define ESP_STEP_VBITS        0x07             /* Valid bits */
-#define ESP_STEP_ASEL         0x00             /* Selection&Arbitrate cmplt */
-#define ESP_STEP_SID          0x01             /* One msg byte sent */
-#define ESP_STEP_NCMD         0x02             /* Was not in command phase */
-#define ESP_STEP_PPC          0x03             /* Early phase chg caused cmnd
-                                                * bytes to be lost
-                                                */
-#define ESP_STEP_FINI4        0x04             /* Command was sent ok */
-
-/* Ho hum, some ESP's set the step register to this as well... */
-#define ESP_STEP_FINI5        0x05
-#define ESP_STEP_FINI6        0x06
-#define ESP_STEP_FINI7        0x07
-
-/* ESP chip-test register read-write */
-#define ESP_TEST_TARG         0x01             /* Target test mode */
-#define ESP_TEST_INI          0x02             /* Initiator test mode */
-#define ESP_TEST_TS           0x04             /* Tristate test mode */
-
-/* ESP unique ID register read-only, found on fas236+fas100a only */
-#define ESP_UID_F100A         0x00             /* ESP FAS100A  */
-#define ESP_UID_F236          0x02             /* ESP FAS236   */
-#define ESP_UID_REV           0x07             /* ESP revision */
-#define ESP_UID_FAM           0xf8             /* ESP family   */
-
-/* ESP fifo flags register read-only */
-/* Note that the following implies a 16 byte FIFO on the ESP. */
-#define ESP_FF_FBYTES         0x1f             /* Num bytes in FIFO */
-#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100) */
-#define ESP_FF_SSTEP          0xe0             /* Sequence step */
-
-/* ESP clock conversion factor register write-only */
-#define ESP_CCF_F0            0x00             /* 35.01MHz - 40MHz */
-#define ESP_CCF_NEVER         0x01             /* Set it to this and die */
-#define ESP_CCF_F2            0x02             /* 10MHz */
-#define ESP_CCF_F3            0x03             /* 10.01MHz - 15MHz */
-#define ESP_CCF_F4            0x04             /* 15.01MHz - 20MHz */
-#define ESP_CCF_F5            0x05             /* 20.01MHz - 25MHz */
-#define ESP_CCF_F6            0x06             /* 25.01MHz - 30MHz */
-#define ESP_CCF_F7            0x07             /* 30.01MHz - 35MHz */
-
-/* HME only... */
-#define ESP_BUSID_RESELID     0x10
-#define ESP_BUSID_CTR32BIT    0x40
-
-#define ESP_BUS_TIMEOUT        275             /* In milli-seconds */
-#define ESP_TIMEO_CONST       8192
-#define ESP_NEG_DEFP(mhz, cfact) \
-        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
-#define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
-#define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
-
-#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
new file mode 100644
index 0000000..ec71061
--- /dev/null
+++ b/drivers/scsi/esp_scsi.c
@@ -0,0 +1,2711 @@
+/* esp_scsi.c: ESP SCSI driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/irqreturn.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME		"esp"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_VERSION		"2.000"
+#define DRV_MODULE_RELDATE	"April 19, 2007"
+
+/* SCSI bus reset settle time in seconds.  */
+static int esp_bus_reset_settle = 3;
+
+static u32 esp_debug;
+#define ESP_DEBUG_INTR		0x00000001
+#define ESP_DEBUG_SCSICMD	0x00000002
+#define ESP_DEBUG_RESET		0x00000004
+#define ESP_DEBUG_MSGIN		0x00000008
+#define ESP_DEBUG_MSGOUT	0x00000010
+#define ESP_DEBUG_CMDDONE	0x00000020
+#define ESP_DEBUG_DISCONNECT	0x00000040
+#define ESP_DEBUG_DATASTART	0x00000080
+#define ESP_DEBUG_DATADONE	0x00000100
+#define ESP_DEBUG_RECONNECT	0x00000200
+#define ESP_DEBUG_AUTOSENSE	0x00000400
+
+#define esp_log_intr(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_INTR) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_reset(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_RESET) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgin(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_MSGIN) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgout(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_MSGOUT) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_cmddone(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_CMDDONE) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_disconnect(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_DISCONNECT) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_datastart(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_DATASTART) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_datadone(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_DATADONE) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_reconnect(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_RECONNECT) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_log_autosense(f, a...) \
+do {	if (esp_debug & ESP_DEBUG_AUTOSENSE) \
+		printk(f, ## a); \
+} while (0)
+
+#define esp_read8(REG)		esp->ops->esp_read8(esp, REG)
+#define esp_write8(VAL,REG)	esp->ops->esp_write8(esp, VAL, REG)
+
+static void esp_log_fill_regs(struct esp *esp,
+			      struct esp_event_ent *p)
+{
+	p->sreg = esp->sreg;
+	p->seqreg = esp->seqreg;
+	p->sreg2 = esp->sreg2;
+	p->ireg = esp->ireg;
+	p->select_state = esp->select_state;
+	p->event = esp->event;
+}
+
+void scsi_esp_cmd(struct esp *esp, u8 val)
+{
+	struct esp_event_ent *p;
+	int idx = esp->esp_event_cur;
+
+	p = &esp->esp_event_log[idx];
+	p->type = ESP_EVENT_TYPE_CMD;
+	p->val = val;
+	esp_log_fill_regs(esp, p);
+
+	esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+	esp_write8(val, ESP_CMD);
+}
+EXPORT_SYMBOL(scsi_esp_cmd);
+
+static void esp_event(struct esp *esp, u8 val)
+{
+	struct esp_event_ent *p;
+	int idx = esp->esp_event_cur;
+
+	p = &esp->esp_event_log[idx];
+	p->type = ESP_EVENT_TYPE_EVENT;
+	p->val = val;
+	esp_log_fill_regs(esp, p);
+
+	esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+	esp->event = val;
+}
+
+static void esp_dump_cmd_log(struct esp *esp)
+{
+	int idx = esp->esp_event_cur;
+	int stop = idx;
+
+	printk(KERN_INFO PFX "esp%d: Dumping command log\n",
+	       esp->host->unique_id);
+	do {
+		struct esp_event_ent *p = &esp->esp_event_log[idx];
+
+		printk(KERN_INFO PFX "esp%d: ent[%d] %s ",
+		       esp->host->unique_id, idx,
+		       p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");
+
+		printk("val[%02x] sreg[%02x] seqreg[%02x] "
+		       "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
+		       p->val, p->sreg, p->seqreg,
+		       p->sreg2, p->ireg, p->select_state, p->event);
+
+		idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+	} while (idx != stop);
+}
+
+static void esp_flush_fifo(struct esp *esp)
+{
+	scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+	if (esp->rev == ESP236) {
+		int lim = 1000;
+
+		while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {
+			if (--lim == 0) {
+				printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "
+				       "will not clear!\n",
+				       esp->host->unique_id);
+				break;
+			}
+			udelay(1);
+		}
+	}
+}
+
+static void hme_read_fifo(struct esp *esp)
+{
+	int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+	int idx = 0;
+
+	while (fcnt--) {
+		esp->fifo[idx++] = esp_read8(ESP_FDATA);
+		esp->fifo[idx++] = esp_read8(ESP_FDATA);
+	}
+	if (esp->sreg2 & ESP_STAT2_F1BYTE) {
+		esp_write8(0, ESP_FDATA);
+		esp->fifo[idx++] = esp_read8(ESP_FDATA);
+		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+	}
+	esp->fifo_cnt = idx;
+}
+
+static void esp_set_all_config3(struct esp *esp, u8 val)
+{
+	int i;
+
+	for (i = 0; i < ESP_MAX_TARGET; i++)
+		esp->target[i].esp_config3 = val;
+}
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void esp_reset_esp(struct esp *esp)
+{
+	u8 family_code, version;
+
+	/* Now reset the ESP chip */
+	scsi_esp_cmd(esp, ESP_CMD_RC);
+	scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+	scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+
+	/* Reload the configuration registers */
+	esp_write8(esp->cfact, ESP_CFACT);
+
+	esp->prev_stp = 0;
+	esp_write8(esp->prev_stp, ESP_STP);
+
+	esp->prev_soff = 0;
+	esp_write8(esp->prev_soff, ESP_SOFF);
+
+	esp_write8(esp->neg_defp, ESP_TIMEO);
+
+	/* This is the only point at which it is reliable to read
+	 * the ID-code for a fast ESP chip variants.
+	 */
+	esp->max_period = ((35 * esp->ccycle) / 1000);
+	if (esp->rev == FAST) {
+		version = esp_read8(ESP_UID);
+		family_code = (version & 0xf8) >> 3;
+		if (family_code == 0x02)
+			esp->rev = FAS236;
+		else if (family_code == 0x0a)
+			esp->rev = FASHME; /* Version is usually '5'. */
+		else
+			esp->rev = FAS100A;
+		esp->min_period = ((4 * esp->ccycle) / 1000);
+	} else {
+		esp->min_period = ((5 * esp->ccycle) / 1000);
+	}
+	esp->max_period = (esp->max_period + 3)>>2;
+	esp->min_period = (esp->min_period + 3)>>2;
+
+	esp_write8(esp->config1, ESP_CFG1);
+	switch (esp->rev) {
+	case ESP100:
+		/* nothing to do */
+		break;
+
+	case ESP100A:
+		esp_write8(esp->config2, ESP_CFG2);
+		break;
+
+	case ESP236:
+		/* Slow 236 */
+		esp_write8(esp->config2, ESP_CFG2);
+		esp->prev_cfg3 = esp->target[0].esp_config3;
+		esp_write8(esp->prev_cfg3, ESP_CFG3);
+		break;
+
+	case FASHME:
+		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+		/* fallthrough... */
+
+	case FAS236:
+		/* Fast 236 or HME */
+		esp_write8(esp->config2, ESP_CFG2);
+		if (esp->rev == FASHME) {
+			u8 cfg3 = esp->target[0].esp_config3;
+
+			cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
+			if (esp->scsi_id >= 8)
+				cfg3 |= ESP_CONFIG3_IDBIT3;
+			esp_set_all_config3(esp, cfg3);
+		} else {
+			u32 cfg3 = esp->target[0].esp_config3;
+
+			cfg3 |= ESP_CONFIG3_FCLK;
+			esp_set_all_config3(esp, cfg3);
+		}
+		esp->prev_cfg3 = esp->target[0].esp_config3;
+		esp_write8(esp->prev_cfg3, ESP_CFG3);
+		if (esp->rev == FASHME) {
+			esp->radelay = 80;
+		} else {
+			if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+				esp->radelay = 0;
+			else
+				esp->radelay = 96;
+		}
+		break;
+
+	case FAS100A:
+		/* Fast 100a */
+		esp_write8(esp->config2, ESP_CFG2);
+		esp_set_all_config3(esp,
+				    (esp->target[0].esp_config3 |
+				     ESP_CONFIG3_FCLOCK));
+		esp->prev_cfg3 = esp->target[0].esp_config3;
+		esp_write8(esp->prev_cfg3, ESP_CFG3);
+		esp->radelay = 32;
+		break;
+
+	default:
+		break;
+	}
+
+	/* Eat any bitrot in the chip */
+	esp_read8(ESP_INTRPT);
+	udelay(100);
+}
+
+static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+	struct scatterlist *sg = cmd->request_buffer;
+	int dir = cmd->sc_data_direction;
+	int total, i;
+
+	if (dir == DMA_NONE)
+		return;
+
+	BUG_ON(cmd->use_sg == 0);
+
+	spriv->u.num_sg = esp->ops->map_sg(esp, sg,
+					   cmd->use_sg, dir);
+	spriv->cur_residue = sg_dma_len(sg);
+	spriv->cur_sg = sg;
+
+	total = 0;
+	for (i = 0; i < spriv->u.num_sg; i++)
+		total += sg_dma_len(&sg[i]);
+	spriv->tot_residue = total;
+}
+
+static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent,
+				   struct scsi_cmnd *cmd)
+{
+	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		return ent->sense_dma +
+			(ent->sense_ptr - cmd->sense_buffer);
+	}
+
+	return sg_dma_address(p->cur_sg) +
+		(sg_dma_len(p->cur_sg) -
+		 p->cur_residue);
+}
+
+static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent,
+				    struct scsi_cmnd *cmd)
+{
+	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		return SCSI_SENSE_BUFFERSIZE -
+			(ent->sense_ptr - cmd->sense_buffer);
+	}
+	return p->cur_residue;
+}
+
+static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
+			    struct scsi_cmnd *cmd, unsigned int len)
+{
+	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		ent->sense_ptr += len;
+		return;
+	}
+
+	p->cur_residue -= len;
+	p->tot_residue -= len;
+	if (p->cur_residue < 0 || p->tot_residue < 0) {
+		printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",
+		       esp->host->unique_id);
+		printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "
+		       "len[%u]\n",
+		       esp->host->unique_id,
+		       p->cur_residue, p->tot_residue, len);
+		p->cur_residue = 0;
+		p->tot_residue = 0;
+	}
+	if (!p->cur_residue && p->tot_residue) {
+		p->cur_sg++;
+		p->cur_residue = sg_dma_len(p->cur_sg);
+	}
+}
+
+static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+	int dir = cmd->sc_data_direction;
+
+	if (dir == DMA_NONE)
+		return;
+
+	esp->ops->unmap_sg(esp, cmd->request_buffer,
+			   spriv->u.num_sg, dir);
+}
+
+static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	struct scsi_cmnd *cmd = ent->cmd;
+	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		ent->saved_sense_ptr = ent->sense_ptr;
+		return;
+	}
+	ent->saved_cur_residue = spriv->cur_residue;
+	ent->saved_cur_sg = spriv->cur_sg;
+	ent->saved_tot_residue = spriv->tot_residue;
+}
+
+static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	struct scsi_cmnd *cmd = ent->cmd;
+	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		ent->sense_ptr = ent->saved_sense_ptr;
+		return;
+	}
+	spriv->cur_residue = ent->saved_cur_residue;
+	spriv->cur_sg = ent->saved_cur_sg;
+	spriv->tot_residue = ent->saved_tot_residue;
+}
+
+static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd)
+{
+	if (cmd->cmd_len == 6 ||
+	    cmd->cmd_len == 10 ||
+	    cmd->cmd_len == 12) {
+		esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+	} else {
+		esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+	}
+}
+
+static void esp_write_tgt_config3(struct esp *esp, int tgt)
+{
+	if (esp->rev > ESP100A) {
+		u8 val = esp->target[tgt].esp_config3;
+
+		if (val != esp->prev_cfg3) {
+			esp->prev_cfg3 = val;
+			esp_write8(val, ESP_CFG3);
+		}
+	}
+}
+
+static void esp_write_tgt_sync(struct esp *esp, int tgt)
+{
+	u8 off = esp->target[tgt].esp_offset;
+	u8 per = esp->target[tgt].esp_period;
+
+	if (off != esp->prev_soff) {
+		esp->prev_soff = off;
+		esp_write8(off, ESP_SOFF);
+	}
+	if (per != esp->prev_stp) {
+		esp->prev_stp = per;
+		esp_write8(per, ESP_STP);
+	}
+}
+
+static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
+{
+	if (esp->rev == FASHME) {
+		/* Arbitrary segment boundaries, 24-bit counts.  */
+		if (dma_len > (1U << 24))
+			dma_len = (1U << 24);
+	} else {
+		u32 base, end;
+
+		/* ESP chip limits other variants by 16-bits of transfer
+		 * count.  Actually on FAS100A and FAS236 we could get
+		 * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB
+		 * in the ESP_CFG2 register but that causes other unwanted
+		 * changes so we don't use it currently.
+		 */
+		if (dma_len > (1U << 16))
+			dma_len = (1U << 16);
+
+		/* All of the DMA variants hooked up to these chips
+		 * cannot handle crossing a 24-bit address boundary.
+		 */
+		base = dma_addr & ((1U << 24) - 1U);
+		end = base + dma_len;
+		if (end > (1U << 24))
+			end = (1U <<24);
+		dma_len = end - base;
+	}
+	return dma_len;
+}
+
+static int esp_need_to_nego_wide(struct esp_target_data *tp)
+{
+	struct scsi_target *target = tp->starget;
+
+	return spi_width(target) != tp->nego_goal_width;
+}
+
+static int esp_need_to_nego_sync(struct esp_target_data *tp)
+{
+	struct scsi_target *target = tp->starget;
+
+	/* When offset is zero, period is "don't care".  */
+	if (!spi_offset(target) && !tp->nego_goal_offset)
+		return 0;
+
+	if (spi_offset(target) == tp->nego_goal_offset &&
+	    spi_period(target) == tp->nego_goal_period)
+		return 0;
+
+	return 1;
+}
+
+static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
+			     struct esp_lun_data *lp)
+{
+	if (!ent->tag[0]) {
+		/* Non-tagged, slot already taken?  */
+		if (lp->non_tagged_cmd)
+			return -EBUSY;
+
+		if (lp->hold) {
+			/* We are being held by active tagged
+			 * commands.
+			 */
+			if (lp->num_tagged)
+				return -EBUSY;
+
+			/* Tagged commands completed, we can unplug
+			 * the queue and run this untagged command.
+			 */
+			lp->hold = 0;
+		} else if (lp->num_tagged) {
+			/* Plug the queue until num_tagged decreases
+			 * to zero in esp_free_lun_tag.
+			 */
+			lp->hold = 1;
+			return -EBUSY;
+		}
+
+		lp->non_tagged_cmd = ent;
+		return 0;
+	} else {
+		/* Tagged command, see if blocked by a
+		 * non-tagged one.
+		 */
+		if (lp->non_tagged_cmd || lp->hold)
+			return -EBUSY;
+	}
+
+	BUG_ON(lp->tagged_cmds[ent->tag[1]]);
+
+	lp->tagged_cmds[ent->tag[1]] = ent;
+	lp->num_tagged++;
+
+	return 0;
+}
+
+static void esp_free_lun_tag(struct esp_cmd_entry *ent,
+			     struct esp_lun_data *lp)
+{
+	if (ent->tag[0]) {
+		BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent);
+		lp->tagged_cmds[ent->tag[1]] = NULL;
+		lp->num_tagged--;
+	} else {
+		BUG_ON(lp->non_tagged_cmd != ent);
+		lp->non_tagged_cmd = NULL;
+	}
+}
+
+/* When a contingent allegiance conditon is created, we force feed a
+ * REQUEST_SENSE command to the device to fetch the sense data.  I
+ * tried many other schemes, relying on the scsi error handling layer
+ * to send out the REQUEST_SENSE automatically, but this was difficult
+ * to get right especially in the presence of applications like smartd
+ * which use SG_IO to send out their own REQUEST_SENSE commands.
+ */
+static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	struct scsi_cmnd *cmd = ent->cmd;
+	struct scsi_device *dev = cmd->device;
+	int tgt, lun;
+	u8 *p, val;
+
+	tgt = dev->id;
+	lun = dev->lun;
+
+
+	if (!ent->sense_ptr) {
+		esp_log_autosense("esp%d: Doing auto-sense for "
+				  "tgt[%d] lun[%d]\n",
+				  esp->host->unique_id, tgt, lun);
+
+		ent->sense_ptr = cmd->sense_buffer;
+		ent->sense_dma = esp->ops->map_single(esp,
+						      ent->sense_ptr,
+						      SCSI_SENSE_BUFFERSIZE,
+						      DMA_FROM_DEVICE);
+	}
+	ent->saved_sense_ptr = ent->sense_ptr;
+
+	esp->active_cmd = ent;
+
+	p = esp->command_block;
+	esp->msg_out_len = 0;
+
+	*p++ = IDENTIFY(0, lun);
+	*p++ = REQUEST_SENSE;
+	*p++ = ((dev->scsi_level <= SCSI_2) ?
+		(lun << 5) : 0);
+	*p++ = 0;
+	*p++ = 0;
+	*p++ = SCSI_SENSE_BUFFERSIZE;
+	*p++ = 0;
+
+	esp->select_state = ESP_SELECT_BASIC;
+
+	val = tgt;
+	if (esp->rev == FASHME)
+		val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+	esp_write8(val, ESP_BUSID);
+
+	esp_write_tgt_sync(esp, tgt);
+	esp_write_tgt_config3(esp, tgt);
+
+	val = (p - esp->command_block);
+
+	if (esp->rev == FASHME)
+		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+	esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+			       val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
+}
+
+static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
+{
+	struct esp_cmd_entry *ent;
+
+	list_for_each_entry(ent, &esp->queued_cmds, list) {
+		struct scsi_cmnd *cmd = ent->cmd;
+		struct scsi_device *dev = cmd->device;
+		struct esp_lun_data *lp = dev->hostdata;
+
+		if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+			ent->tag[0] = 0;
+			ent->tag[1] = 0;
+			return ent;
+		}
+
+		if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
+			ent->tag[0] = 0;
+			ent->tag[1] = 0;
+		}
+
+		if (esp_alloc_lun_tag(ent, lp) < 0)
+			continue;
+
+		return ent;
+	}
+
+	return NULL;
+}
+
+static void esp_maybe_execute_command(struct esp *esp)
+{
+	struct esp_target_data *tp;
+	struct esp_lun_data *lp;
+	struct scsi_device *dev;
+	struct scsi_cmnd *cmd;
+	struct esp_cmd_entry *ent;
+	int tgt, lun, i;
+	u32 val, start_cmd;
+	u8 *p;
+
+	if (esp->active_cmd ||
+	    (esp->flags & ESP_FLAG_RESETTING))
+		return;
+
+	ent = find_and_prep_issuable_command(esp);
+	if (!ent)
+		return;
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		esp_autosense(esp, ent);
+		return;
+	}
+
+	cmd = ent->cmd;
+	dev = cmd->device;
+	tgt = dev->id;
+	lun = dev->lun;
+	tp = &esp->target[tgt];
+	lp = dev->hostdata;
+
+	list_del(&ent->list);
+	list_add(&ent->list, &esp->active_cmds);
+
+	esp->active_cmd = ent;
+
+	esp_map_dma(esp, cmd);
+	esp_save_pointers(esp, ent);
+
+	esp_check_command_len(esp, cmd);
+
+	p = esp->command_block;
+
+	esp->msg_out_len = 0;
+	if (tp->flags & ESP_TGT_CHECK_NEGO) {
+		/* Need to negotiate.  If the target is broken
+		 * go for synchronous transfers and non-wide.
+		 */
+		if (tp->flags & ESP_TGT_BROKEN) {
+			tp->flags &= ~ESP_TGT_DISCONNECT;
+			tp->nego_goal_period = 0;
+			tp->nego_goal_offset = 0;
+			tp->nego_goal_width = 0;
+			tp->nego_goal_tags = 0;
+		}
+
+		/* If the settings are not changing, skip this.  */
+		if (spi_width(tp->starget) == tp->nego_goal_width &&
+		    spi_period(tp->starget) == tp->nego_goal_period &&
+		    spi_offset(tp->starget) == tp->nego_goal_offset) {
+			tp->flags &= ~ESP_TGT_CHECK_NEGO;
+			goto build_identify;
+		}
+
+		if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) {
+			esp->msg_out_len =
+				spi_populate_width_msg(&esp->msg_out[0],
+						       (tp->nego_goal_width ?
+							1 : 0));
+			tp->flags |= ESP_TGT_NEGO_WIDE;
+		} else if (esp_need_to_nego_sync(tp)) {
+			esp->msg_out_len =
+				spi_populate_sync_msg(&esp->msg_out[0],
+						      tp->nego_goal_period,
+						      tp->nego_goal_offset);
+			tp->flags |= ESP_TGT_NEGO_SYNC;
+		} else {
+			tp->flags &= ~ESP_TGT_CHECK_NEGO;
+		}
+
+		/* Process it like a slow command.  */
+		if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC))
+			esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+	}
+
+build_identify:
+	/* If we don't have a lun-data struct yet, we're probing
+	 * so do not disconnect.  Also, do not disconnect unless
+	 * we have a tag on this command.
+	 */
+	if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0])
+		*p++ = IDENTIFY(1, lun);
+	else
+		*p++ = IDENTIFY(0, lun);
+
+	if (ent->tag[0] && esp->rev == ESP100) {
+		/* ESP100 lacks select w/atn3 command, use select
+		 * and stop instead.
+		 */
+		esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+	}
+
+	if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
+		start_cmd = ESP_CMD_DMA | ESP_CMD_SELA;
+		if (ent->tag[0]) {
+			*p++ = ent->tag[0];
+			*p++ = ent->tag[1];
+
+			start_cmd = ESP_CMD_DMA | ESP_CMD_SA3;
+		}
+
+		for (i = 0; i < cmd->cmd_len; i++)
+			*p++ = cmd->cmnd[i];
+
+		esp->select_state = ESP_SELECT_BASIC;
+	} else {
+		esp->cmd_bytes_left = cmd->cmd_len;
+		esp->cmd_bytes_ptr = &cmd->cmnd[0];
+
+		if (ent->tag[0]) {
+			for (i = esp->msg_out_len - 1;
+			     i >= 0; i--)
+				esp->msg_out[i + 2] = esp->msg_out[i];
+			esp->msg_out[0] = ent->tag[0];
+			esp->msg_out[1] = ent->tag[1];
+			esp->msg_out_len += 2;
+		}
+
+		start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS;
+		esp->select_state = ESP_SELECT_MSGOUT;
+	}
+	val = tgt;
+	if (esp->rev == FASHME)
+		val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+	esp_write8(val, ESP_BUSID);
+
+	esp_write_tgt_sync(esp, tgt);
+	esp_write_tgt_config3(esp, tgt);
+
+	val = (p - esp->command_block);
+
+	if (esp_debug & ESP_DEBUG_SCSICMD) {
+		printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun);
+		for (i = 0; i < cmd->cmd_len; i++)
+			printk("%02x ", cmd->cmnd[i]);
+		printk("]\n");
+	}
+
+	if (esp->rev == FASHME)
+		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+	esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+			       val, 16, 0, start_cmd);
+}
+
+static struct esp_cmd_entry *esp_get_ent(struct esp *esp)
+{
+	struct list_head *head = &esp->esp_cmd_pool;
+	struct esp_cmd_entry *ret;
+
+	if (list_empty(head)) {
+		ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC);
+	} else {
+		ret = list_entry(head->next, struct esp_cmd_entry, list);
+		list_del(&ret->list);
+		memset(ret, 0, sizeof(*ret));
+	}
+	return ret;
+}
+
+static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	list_add(&ent->list, &esp->esp_cmd_pool);
+}
+
+static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent,
+			    struct scsi_cmnd *cmd, unsigned int result)
+{
+	struct scsi_device *dev = cmd->device;
+	int tgt = dev->id;
+	int lun = dev->lun;
+
+	esp->active_cmd = NULL;
+	esp_unmap_dma(esp, cmd);
+	esp_free_lun_tag(ent, dev->hostdata);
+	cmd->result = result;
+
+	if (ent->eh_done) {
+		complete(ent->eh_done);
+		ent->eh_done = NULL;
+	}
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		esp->ops->unmap_single(esp, ent->sense_dma,
+				       SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+		ent->sense_ptr = NULL;
+
+		/* Restore the message/status bytes to what we actually
+		 * saw originally.  Also, report that we are providing
+		 * the sense data.
+		 */
+		cmd->result = ((DRIVER_SENSE << 24) |
+			       (DID_OK << 16) |
+			       (COMMAND_COMPLETE << 8) |
+			       (SAM_STAT_CHECK_CONDITION << 0));
+
+		ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE;
+		if (esp_debug & ESP_DEBUG_AUTOSENSE) {
+			int i;
+
+			printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ",
+			       esp->host->unique_id, tgt, lun);
+			for (i = 0; i < 18; i++)
+				printk("%02x ", cmd->sense_buffer[i]);
+			printk("]\n");
+		}
+	}
+
+	cmd->scsi_done(cmd);
+
+	list_del(&ent->list);
+	esp_put_ent(esp, ent);
+
+	esp_maybe_execute_command(esp);
+}
+
+static unsigned int compose_result(unsigned int status, unsigned int message,
+				   unsigned int driver_code)
+{
+	return (status | (message << 8) | (driver_code << 16));
+}
+
+static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	struct scsi_device *dev = ent->cmd->device;
+	struct esp_lun_data *lp = dev->hostdata;
+
+	scsi_track_queue_full(dev, lp->num_tagged - 1);
+}
+
+static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct scsi_device *dev = cmd->device;
+	struct esp *esp = host_to_esp(dev->host);
+	struct esp_cmd_priv *spriv;
+	struct esp_cmd_entry *ent;
+
+	ent = esp_get_ent(esp);
+	if (!ent)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	ent->cmd = cmd;
+
+	cmd->scsi_done = done;
+
+	spriv = ESP_CMD_PRIV(cmd);
+	spriv->u.dma_addr = ~(dma_addr_t)0x0;
+
+	list_add_tail(&ent->list, &esp->queued_cmds);
+
+	esp_maybe_execute_command(esp);
+
+	return 0;
+}
+
+static int esp_check_gross_error(struct esp *esp)
+{
+	if (esp->sreg & ESP_STAT_SPAM) {
+		/* Gross Error, could be one of:
+		 * - top of fifo overwritten
+		 * - top of command register overwritten
+		 * - DMA programmed with wrong direction
+		 * - improper phase change
+		 */
+		printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n",
+		       esp->host->unique_id, esp->sreg);
+		/* XXX Reset the chip. XXX */
+		return 1;
+	}
+	return 0;
+}
+
+static int esp_check_spur_intr(struct esp *esp)
+{
+	switch (esp->rev) {
+	case ESP100:
+	case ESP100A:
+		/* The interrupt pending bit of the status register cannot
+		 * be trusted on these revisions.
+		 */
+		esp->sreg &= ~ESP_STAT_INTR;
+		break;
+
+	default:
+		if (!(esp->sreg & ESP_STAT_INTR)) {
+			esp->ireg = esp_read8(ESP_INTRPT);
+			if (esp->ireg & ESP_INTR_SR)
+				return 1;
+
+			/* If the DMA is indicating interrupt pending and the
+			 * ESP is not, the only possibility is a DMA error.
+			 */
+			if (!esp->ops->dma_error(esp)) {
+				printk(KERN_ERR PFX "esp%d: Spurious irq, "
+				       "sreg=%x.\n",
+				       esp->host->unique_id, esp->sreg);
+				return -1;
+			}
+
+			printk(KERN_ERR PFX "esp%d: DMA error\n",
+			       esp->host->unique_id);
+
+			/* XXX Reset the chip. XXX */
+			return -1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static void esp_schedule_reset(struct esp *esp)
+{
+	esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+		      __builtin_return_address(0));
+	esp->flags |= ESP_FLAG_RESETTING;
+	esp_event(esp, ESP_EVENT_RESET);
+}
+
+/* In order to avoid having to add a special half-reconnected state
+ * into the driver we just sit here and poll through the rest of
+ * the reselection process to get the tag message bytes.
+ */
+static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
+						    struct esp_lun_data *lp)
+{
+	struct esp_cmd_entry *ent;
+	int i;
+
+	if (!lp->num_tagged) {
+		printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n",
+		       esp->host->unique_id);
+		return NULL;
+	}
+
+	esp_log_reconnect("ESP: reconnect tag, ");
+
+	for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+		if (esp->ops->irq_pending(esp))
+			break;
+	}
+	if (i == ESP_QUICKIRQ_LIMIT) {
+		printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n",
+		       esp->host->unique_id);
+		return NULL;
+	}
+
+	esp->sreg = esp_read8(ESP_STATUS);
+	esp->ireg = esp_read8(ESP_INTRPT);
+
+	esp_log_reconnect("IRQ(%d:%x:%x), ",
+			  i, esp->ireg, esp->sreg);
+
+	if (esp->ireg & ESP_INTR_DC) {
+		printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n",
+		       esp->host->unique_id);
+		return NULL;
+	}
+
+	if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
+		printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n",
+		       esp->host->unique_id, esp->sreg);
+		return NULL;
+	}
+
+	/* DMA in the tag bytes... */
+	esp->command_block[0] = 0xff;
+	esp->command_block[1] = 0xff;
+	esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+			       2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI);
+
+	/* ACK the msssage.  */
+	scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+	for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) {
+		if (esp->ops->irq_pending(esp)) {
+			esp->sreg = esp_read8(ESP_STATUS);
+			esp->ireg = esp_read8(ESP_INTRPT);
+			if (esp->ireg & ESP_INTR_FDONE)
+				break;
+		}
+		udelay(1);
+	}
+	if (i == ESP_RESELECT_TAG_LIMIT) {
+		printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n",
+		       esp->host->unique_id);
+		return NULL;
+	}
+	esp->ops->dma_drain(esp);
+	esp->ops->dma_invalidate(esp);
+
+	esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n",
+			  i, esp->ireg, esp->sreg,
+			  esp->command_block[0],
+			  esp->command_block[1]);
+
+	if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
+	    esp->command_block[0] > ORDERED_QUEUE_TAG) {
+		printk(KERN_ERR PFX "esp%d: Reconnect, bad tag "
+		       "type %02x.\n",
+		       esp->host->unique_id, esp->command_block[0]);
+		return NULL;
+	}
+
+	ent = lp->tagged_cmds[esp->command_block[1]];
+	if (!ent) {
+		printk(KERN_ERR PFX "esp%d: Reconnect, no entry for "
+		       "tag %02x.\n",
+		       esp->host->unique_id, esp->command_block[1]);
+		return NULL;
+	}
+
+	return ent;
+}
+
+static int esp_reconnect(struct esp *esp)
+{
+	struct esp_cmd_entry *ent;
+	struct esp_target_data *tp;
+	struct esp_lun_data *lp;
+	struct scsi_device *dev;
+	int target, lun;
+
+	BUG_ON(esp->active_cmd);
+	if (esp->rev == FASHME) {
+		/* FASHME puts the target and lun numbers directly
+		 * into the fifo.
+		 */
+		target = esp->fifo[0];
+		lun = esp->fifo[1] & 0x7;
+	} else {
+		u8 bits = esp_read8(ESP_FDATA);
+
+		/* Older chips put the lun directly into the fifo, but
+		 * the target is given as a sample of the arbitration
+		 * lines on the bus at reselection time.  So we should
+		 * see the ID of the ESP and the one reconnecting target
+		 * set in the bitmap.
+		 */
+		if (!(bits & esp->scsi_id_mask))
+			goto do_reset;
+		bits &= ~esp->scsi_id_mask;
+		if (!bits || (bits & (bits - 1)))
+			goto do_reset;
+
+		target = ffs(bits) - 1;
+		lun = (esp_read8(ESP_FDATA) & 0x7);
+
+		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+		if (esp->rev == ESP100) {
+			u8 ireg = esp_read8(ESP_INTRPT);
+			/* This chip has a bug during reselection that can
+			 * cause a spurious illegal-command interrupt, which
+			 * we simply ACK here.  Another possibility is a bus
+			 * reset so we must check for that.
+			 */
+			if (ireg & ESP_INTR_SR)
+				goto do_reset;
+		}
+		scsi_esp_cmd(esp, ESP_CMD_NULL);
+	}
+
+	esp_write_tgt_sync(esp, target);
+	esp_write_tgt_config3(esp, target);
+
+	scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+	if (esp->rev == FASHME)
+		esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT,
+			   ESP_BUSID);
+
+	tp = &esp->target[target];
+	dev = __scsi_device_lookup_by_target(tp->starget, lun);
+	if (!dev) {
+		printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
+		       "tgt[%u] lun[%u]\n",
+		       esp->host->unique_id, target, lun);
+		goto do_reset;
+	}
+	lp = dev->hostdata;
+
+	ent = lp->non_tagged_cmd;
+	if (!ent) {
+		ent = esp_reconnect_with_tag(esp, lp);
+		if (!ent)
+			goto do_reset;
+	}
+
+	esp->active_cmd = ent;
+
+	if (ent->flags & ESP_CMD_FLAG_ABORT) {
+		esp->msg_out[0] = ABORT_TASK_SET;
+		esp->msg_out_len = 1;
+		scsi_esp_cmd(esp, ESP_CMD_SATN);
+	}
+
+	esp_event(esp, ESP_EVENT_CHECK_PHASE);
+	esp_restore_pointers(esp, ent);
+	esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+	return 1;
+
+do_reset:
+	esp_schedule_reset(esp);
+	return 0;
+}
+
+static int esp_finish_select(struct esp *esp)
+{
+	struct esp_cmd_entry *ent;
+	struct scsi_cmnd *cmd;
+	u8 orig_select_state;
+
+	orig_select_state = esp->select_state;
+
+	/* No longer selecting.  */
+	esp->select_state = ESP_SELECT_NONE;
+
+	esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS;
+	ent = esp->active_cmd;
+	cmd = ent->cmd;
+
+	if (esp->ops->dma_error(esp)) {
+		/* If we see a DMA error during or as a result of selection,
+		 * all bets are off.
+		 */
+		esp_schedule_reset(esp);
+		esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16));
+		return 0;
+	}
+
+	esp->ops->dma_invalidate(esp);
+
+	if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+		struct esp_target_data *tp = &esp->target[cmd->device->id];
+
+		/* Carefully back out of the selection attempt.  Release
+		 * resources (such as DMA mapping & TAG) and reset state (such
+		 * as message out and command delivery variables).
+		 */
+		if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+			esp_unmap_dma(esp, cmd);
+			esp_free_lun_tag(ent, cmd->device->hostdata);
+			tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE);
+			esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+			esp->cmd_bytes_ptr = NULL;
+			esp->cmd_bytes_left = 0;
+		} else {
+			esp->ops->unmap_single(esp, ent->sense_dma,
+					       SCSI_SENSE_BUFFERSIZE,
+					       DMA_FROM_DEVICE);
+			ent->sense_ptr = NULL;
+		}
+
+		/* Now that the state is unwound properly, put back onto
+		 * the issue queue.  This command is no longer active.
+		 */
+		list_del(&ent->list);
+		list_add(&ent->list, &esp->queued_cmds);
+		esp->active_cmd = NULL;
+
+		/* Return value ignored by caller, it directly invokes
+		 * esp_reconnect().
+		 */
+		return 0;
+	}
+
+	if (esp->ireg == ESP_INTR_DC) {
+		struct scsi_device *dev = cmd->device;
+
+		/* Disconnect.  Make sure we re-negotiate sync and
+		 * wide parameters if this target starts responding
+		 * again in the future.
+		 */
+		esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO;
+
+		scsi_esp_cmd(esp, ESP_CMD_ESEL);
+		esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16));
+		return 1;
+	}
+
+	if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+		/* Selection successful.  On pre-FAST chips we have
+		 * to do a NOP and possibly clean out the FIFO.
+		 */
+		if (esp->rev <= ESP236) {
+			int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+			scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+			if (!fcnt &&
+			    (!esp->prev_soff ||
+			     ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+				esp_flush_fifo(esp);
+		}
+
+		/* If we are doing a slow command, negotiation, etc.
+		 * we'll do the right thing as we transition to the
+		 * next phase.
+		 */
+		esp_event(esp, ESP_EVENT_CHECK_PHASE);
+		return 0;
+	}
+
+	printk("ESP: Unexpected selection completion ireg[%x].\n",
+	       esp->ireg);
+	esp_schedule_reset(esp);
+	return 0;
+}
+
+static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
+			       struct scsi_cmnd *cmd)
+{
+	int fifo_cnt, ecount, bytes_sent, flush_fifo;
+
+	fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+	if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+		fifo_cnt <<= 1;
+
+	ecount = 0;
+	if (!(esp->sreg & ESP_STAT_TCNT)) {
+		ecount = ((unsigned int)esp_read8(ESP_TCLOW) |
+			  (((unsigned int)esp_read8(ESP_TCMED)) << 8));
+		if (esp->rev == FASHME)
+			ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16;
+	}
+
+	bytes_sent = esp->data_dma_len;
+	bytes_sent -= ecount;
+
+	if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+		bytes_sent -= fifo_cnt;
+
+	flush_fifo = 0;
+	if (!esp->prev_soff) {
+		/* Synchronous data transfer, always flush fifo. */
+		flush_fifo = 1;
+	} else {
+		if (esp->rev == ESP100) {
+			u32 fflags, phase;
+
+			/* ESP100 has a chip bug where in the synchronous data
+			 * phase it can mistake a final long REQ pulse from the
+			 * target as an extra data byte.  Fun.
+			 *
+			 * To detect this case we resample the status register
+			 * and fifo flags.  If we're still in a data phase and
+			 * we see spurious chunks in the fifo, we return error
+			 * to the caller which should reset and set things up
+			 * such that we only try future transfers to this
+			 * target in synchronous mode.
+			 */
+			esp->sreg = esp_read8(ESP_STATUS);
+			phase = esp->sreg & ESP_STAT_PMASK;
+			fflags = esp_read8(ESP_FFLAGS);
+
+			if ((phase == ESP_DOP &&
+			     (fflags & ESP_FF_ONOTZERO)) ||
+			    (phase == ESP_DIP &&
+			     (fflags & ESP_FF_FBYTES)))
+				return -1;
+		}
+		if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+			flush_fifo = 1;
+	}
+
+	if (flush_fifo)
+		esp_flush_fifo(esp);
+
+	return bytes_sent;
+}
+
+static void esp_setsync(struct esp *esp, struct esp_target_data *tp,
+			u8 scsi_period, u8 scsi_offset,
+			u8 esp_stp, u8 esp_soff)
+{
+	spi_period(tp->starget) = scsi_period;
+	spi_offset(tp->starget) = scsi_offset;
+	spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0;
+
+	if (esp_soff) {
+		esp_stp &= 0x1f;
+		esp_soff |= esp->radelay;
+		if (esp->rev >= FAS236) {
+			u8 bit = ESP_CONFIG3_FSCSI;
+			if (esp->rev >= FAS100A)
+				bit = ESP_CONFIG3_FAST;
+
+			if (scsi_period < 50) {
+				if (esp->rev == FASHME)
+					esp_soff &= ~esp->radelay;
+				tp->esp_config3 |= bit;
+			} else {
+				tp->esp_config3 &= ~bit;
+			}
+			esp->prev_cfg3 = tp->esp_config3;
+			esp_write8(esp->prev_cfg3, ESP_CFG3);
+		}
+	}
+
+	tp->esp_period = esp->prev_stp = esp_stp;
+	tp->esp_offset = esp->prev_soff = esp_soff;
+
+	esp_write8(esp_soff, ESP_SOFF);
+	esp_write8(esp_stp, ESP_STP);
+
+	tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+
+	spi_display_xfer_agreement(tp->starget);
+}
+
+static void esp_msgin_reject(struct esp *esp)
+{
+	struct esp_cmd_entry *ent = esp->active_cmd;
+	struct scsi_cmnd *cmd = ent->cmd;
+	struct esp_target_data *tp;
+	int tgt;
+
+	tgt = cmd->device->id;
+	tp = &esp->target[tgt];
+
+	if (tp->flags & ESP_TGT_NEGO_WIDE) {
+		tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE);
+
+		if (!esp_need_to_nego_sync(tp)) {
+			tp->flags &= ~ESP_TGT_CHECK_NEGO;
+			scsi_esp_cmd(esp, ESP_CMD_RATN);
+		} else {
+			esp->msg_out_len =
+				spi_populate_sync_msg(&esp->msg_out[0],
+						      tp->nego_goal_period,
+						      tp->nego_goal_offset);
+			tp->flags |= ESP_TGT_NEGO_SYNC;
+			scsi_esp_cmd(esp, ESP_CMD_SATN);
+		}
+		return;
+	}
+
+	if (tp->flags & ESP_TGT_NEGO_SYNC) {
+		tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+		tp->esp_period = 0;
+		tp->esp_offset = 0;
+		esp_setsync(esp, tp, 0, 0, 0, 0);
+		scsi_esp_cmd(esp, ESP_CMD_RATN);
+		return;
+	}
+
+	esp->msg_out[0] = ABORT_TASK_SET;
+	esp->msg_out_len = 1;
+	scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
+{
+	u8 period = esp->msg_in[3];
+	u8 offset = esp->msg_in[4];
+	u8 stp;
+
+	if (!(tp->flags & ESP_TGT_NEGO_SYNC))
+		goto do_reject;
+
+	if (offset > 15)
+		goto do_reject;
+
+	if (offset) {
+		int rounded_up, one_clock;
+
+		if (period > esp->max_period) {
+			period = offset = 0;
+			goto do_sdtr;
+		}
+		if (period < esp->min_period)
+			goto do_reject;
+
+		one_clock = esp->ccycle / 1000;
+		rounded_up = (period << 2);
+		rounded_up = (rounded_up + one_clock - 1) / one_clock;
+		stp = rounded_up;
+		if (stp && esp->rev >= FAS236) {
+			if (stp >= 50)
+				stp--;
+		}
+	} else {
+		stp = 0;
+	}
+
+	esp_setsync(esp, tp, period, offset, stp, offset);
+	return;
+
+do_reject:
+	esp->msg_out[0] = MESSAGE_REJECT;
+	esp->msg_out_len = 1;
+	scsi_esp_cmd(esp, ESP_CMD_SATN);
+	return;
+
+do_sdtr:
+	tp->nego_goal_period = period;
+	tp->nego_goal_offset = offset;
+	esp->msg_out_len =
+		spi_populate_sync_msg(&esp->msg_out[0],
+				      tp->nego_goal_period,
+				      tp->nego_goal_offset);
+	scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp)
+{
+	int size = 8 << esp->msg_in[3];
+	u8 cfg3;
+
+	if (esp->rev != FASHME)
+		goto do_reject;
+
+	if (size != 8 && size != 16)
+		goto do_reject;
+
+	if (!(tp->flags & ESP_TGT_NEGO_WIDE))
+		goto do_reject;
+
+	cfg3 = tp->esp_config3;
+	if (size == 16) {
+		tp->flags |= ESP_TGT_WIDE;
+		cfg3 |= ESP_CONFIG3_EWIDE;
+	} else {
+		tp->flags &= ~ESP_TGT_WIDE;
+		cfg3 &= ~ESP_CONFIG3_EWIDE;
+	}
+	tp->esp_config3 = cfg3;
+	esp->prev_cfg3 = cfg3;
+	esp_write8(cfg3, ESP_CFG3);
+
+	tp->flags &= ~ESP_TGT_NEGO_WIDE;
+
+	spi_period(tp->starget) = 0;
+	spi_offset(tp->starget) = 0;
+	if (!esp_need_to_nego_sync(tp)) {
+		tp->flags &= ~ESP_TGT_CHECK_NEGO;
+		scsi_esp_cmd(esp, ESP_CMD_RATN);
+	} else {
+		esp->msg_out_len =
+			spi_populate_sync_msg(&esp->msg_out[0],
+					      tp->nego_goal_period,
+					      tp->nego_goal_offset);
+		tp->flags |= ESP_TGT_NEGO_SYNC;
+		scsi_esp_cmd(esp, ESP_CMD_SATN);
+	}
+	return;
+
+do_reject:
+	esp->msg_out[0] = MESSAGE_REJECT;
+	esp->msg_out_len = 1;
+	scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_extended(struct esp *esp)
+{
+	struct esp_cmd_entry *ent = esp->active_cmd;
+	struct scsi_cmnd *cmd = ent->cmd;
+	struct esp_target_data *tp;
+	int tgt = cmd->device->id;
+
+	tp = &esp->target[tgt];
+	if (esp->msg_in[2] == EXTENDED_SDTR) {
+		esp_msgin_sdtr(esp, tp);
+		return;
+	}
+	if (esp->msg_in[2] == EXTENDED_WDTR) {
+		esp_msgin_wdtr(esp, tp);
+		return;
+	}
+
+	printk("ESP: Unexpected extended msg type %x\n",
+	       esp->msg_in[2]);
+
+	esp->msg_out[0] = ABORT_TASK_SET;
+	esp->msg_out_len = 1;
+	scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+/* Analyze msgin bytes received from target so far.  Return non-zero
+ * if there are more bytes needed to complete the message.
+ */
+static int esp_msgin_process(struct esp *esp)
+{
+	u8 msg0 = esp->msg_in[0];
+	int len = esp->msg_in_len;
+
+	if (msg0 & 0x80) {
+		/* Identify */
+		printk("ESP: Unexpected msgin identify\n");
+		return 0;
+	}
+
+	switch (msg0) {
+	case EXTENDED_MESSAGE:
+		if (len == 1)
+			return 1;
+		if (len < esp->msg_in[1] + 2)
+			return 1;
+		esp_msgin_extended(esp);
+		return 0;
+
+	case IGNORE_WIDE_RESIDUE: {
+		struct esp_cmd_entry *ent;
+		struct esp_cmd_priv *spriv;
+		if (len == 1)
+			return 1;
+
+		if (esp->msg_in[1] != 1)
+			goto do_reject;
+
+		ent = esp->active_cmd;
+		spriv = ESP_CMD_PRIV(ent->cmd);
+
+		if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
+			spriv->cur_sg--;
+			spriv->cur_residue = 1;
+		} else
+			spriv->cur_residue++;
+		spriv->tot_residue++;
+		return 0;
+	}
+	case NOP:
+		return 0;
+	case RESTORE_POINTERS:
+		esp_restore_pointers(esp, esp->active_cmd);
+		return 0;
+	case SAVE_POINTERS:
+		esp_save_pointers(esp, esp->active_cmd);
+		return 0;
+
+	case COMMAND_COMPLETE:
+	case DISCONNECT: {
+		struct esp_cmd_entry *ent = esp->active_cmd;
+
+		ent->message = msg0;
+		esp_event(esp, ESP_EVENT_FREE_BUS);
+		esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+		return 0;
+	}
+	case MESSAGE_REJECT:
+		esp_msgin_reject(esp);
+		return 0;
+
+	default:
+	do_reject:
+		esp->msg_out[0] = MESSAGE_REJECT;
+		esp->msg_out_len = 1;
+		scsi_esp_cmd(esp, ESP_CMD_SATN);
+		return 0;
+	}
+}
+
+static int esp_process_event(struct esp *esp)
+{
+	int write;
+
+again:
+	write = 0;
+	switch (esp->event) {
+	case ESP_EVENT_CHECK_PHASE:
+		switch (esp->sreg & ESP_STAT_PMASK) {
+		case ESP_DOP:
+			esp_event(esp, ESP_EVENT_DATA_OUT);
+			break;
+		case ESP_DIP:
+			esp_event(esp, ESP_EVENT_DATA_IN);
+			break;
+		case ESP_STATP:
+			esp_flush_fifo(esp);
+			scsi_esp_cmd(esp, ESP_CMD_ICCSEQ);
+			esp_event(esp, ESP_EVENT_STATUS);
+			esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+			return 1;
+
+		case ESP_MOP:
+			esp_event(esp, ESP_EVENT_MSGOUT);
+			break;
+
+		case ESP_MIP:
+			esp_event(esp, ESP_EVENT_MSGIN);
+			break;
+
+		case ESP_CMDP:
+			esp_event(esp, ESP_EVENT_CMD_START);
+			break;
+
+		default:
+			printk("ESP: Unexpected phase, sreg=%02x\n",
+			       esp->sreg);
+			esp_schedule_reset(esp);
+			return 0;
+		}
+		goto again;
+		break;
+
+	case ESP_EVENT_DATA_IN:
+		write = 1;
+		/* fallthru */
+
+	case ESP_EVENT_DATA_OUT: {
+		struct esp_cmd_entry *ent = esp->active_cmd;
+		struct scsi_cmnd *cmd = ent->cmd;
+		dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd);
+		unsigned int dma_len = esp_cur_dma_len(ent, cmd);
+
+		if (esp->rev == ESP100)
+			scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+		if (write)
+			ent->flags |= ESP_CMD_FLAG_WRITE;
+		else
+			ent->flags &= ~ESP_CMD_FLAG_WRITE;
+
+		dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
+		esp->data_dma_len = dma_len;
+
+		if (!dma_len) {
+			printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
+			       esp->host->unique_id);
+			printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n",
+			       esp->host->unique_id,
+			       (unsigned long long)esp_cur_dma_addr(ent, cmd),
+			       esp_cur_dma_len(ent, cmd));
+			esp_schedule_reset(esp);
+			return 0;
+		}
+
+		esp_log_datastart("ESP: start data addr[%08llx] len[%u] "
+				  "write(%d)\n",
+				  (unsigned long long)dma_addr, dma_len, write);
+
+		esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
+				       write, ESP_CMD_DMA | ESP_CMD_TI);
+		esp_event(esp, ESP_EVENT_DATA_DONE);
+		break;
+	}
+	case ESP_EVENT_DATA_DONE: {
+		struct esp_cmd_entry *ent = esp->active_cmd;
+		struct scsi_cmnd *cmd = ent->cmd;
+		int bytes_sent;
+
+		if (esp->ops->dma_error(esp)) {
+			printk("ESP: data done, DMA error, resetting\n");
+			esp_schedule_reset(esp);
+			return 0;
+		}
+
+		if (ent->flags & ESP_CMD_FLAG_WRITE) {
+			/* XXX parity errors, etc. XXX */
+
+			esp->ops->dma_drain(esp);
+		}
+		esp->ops->dma_invalidate(esp);
+
+		if (esp->ireg != ESP_INTR_BSERV) {
+			/* We should always see exactly a bus-service
+			 * interrupt at the end of a successful transfer.
+			 */
+			printk("ESP: data done, not BSERV, resetting\n");
+			esp_schedule_reset(esp);
+			return 0;
+		}
+
+		bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
+
+		esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n",
+				 ent->flags, bytes_sent);
+
+		if (bytes_sent < 0) {
+			/* XXX force sync mode for this target XXX */
+			esp_schedule_reset(esp);
+			return 0;
+		}
+
+		esp_advance_dma(esp, ent, cmd, bytes_sent);
+		esp_event(esp, ESP_EVENT_CHECK_PHASE);
+		goto again;
+		break;
+	}
+
+	case ESP_EVENT_STATUS: {
+		struct esp_cmd_entry *ent = esp->active_cmd;
+
+		if (esp->ireg & ESP_INTR_FDONE) {
+			ent->status = esp_read8(ESP_FDATA);
+			ent->message = esp_read8(ESP_FDATA);
+			scsi_esp_cmd(esp, ESP_CMD_MOK);
+		} else if (esp->ireg == ESP_INTR_BSERV) {
+			ent->status = esp_read8(ESP_FDATA);
+			ent->message = 0xff;
+			esp_event(esp, ESP_EVENT_MSGIN);
+			return 0;
+		}
+
+		if (ent->message != COMMAND_COMPLETE) {
+			printk("ESP: Unexpected message %x in status\n",
+			       ent->message);
+			esp_schedule_reset(esp);
+			return 0;
+		}
+
+		esp_event(esp, ESP_EVENT_FREE_BUS);
+		esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+		break;
+	}
+	case ESP_EVENT_FREE_BUS: {
+		struct esp_cmd_entry *ent = esp->active_cmd;
+		struct scsi_cmnd *cmd = ent->cmd;
+
+		if (ent->message == COMMAND_COMPLETE ||
+		    ent->message == DISCONNECT)
+			scsi_esp_cmd(esp, ESP_CMD_ESEL);
+
+		if (ent->message == COMMAND_COMPLETE) {
+			esp_log_cmddone("ESP: Command done status[%x] "
+					"message[%x]\n",
+					ent->status, ent->message);
+			if (ent->status == SAM_STAT_TASK_SET_FULL)
+				esp_event_queue_full(esp, ent);
+
+			if (ent->status == SAM_STAT_CHECK_CONDITION &&
+			    !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+				ent->flags |= ESP_CMD_FLAG_AUTOSENSE;
+				esp_autosense(esp, ent);
+			} else {
+				esp_cmd_is_done(esp, ent, cmd,
+						compose_result(ent->status,
+							       ent->message,
+							       DID_OK));
+			}
+		} else if (ent->message == DISCONNECT) {
+			esp_log_disconnect("ESP: Disconnecting tgt[%d] "
+					   "tag[%x:%x]\n",
+					   cmd->device->id,
+					   ent->tag[0], ent->tag[1]);
+
+			esp->active_cmd = NULL;
+			esp_maybe_execute_command(esp);
+		} else {
+			printk("ESP: Unexpected message %x in freebus\n",
+			       ent->message);
+			esp_schedule_reset(esp);
+			return 0;
+		}
+		if (esp->active_cmd)
+			esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+		break;
+	}
+	case ESP_EVENT_MSGOUT: {
+		scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+		if (esp_debug & ESP_DEBUG_MSGOUT) {
+			int i;
+			printk("ESP: Sending message [ ");
+			for (i = 0; i < esp->msg_out_len; i++)
+				printk("%02x ", esp->msg_out[i]);
+			printk("]\n");
+		}
+
+		if (esp->rev == FASHME) {
+			int i;
+
+			/* Always use the fifo.  */
+			for (i = 0; i < esp->msg_out_len; i++) {
+				esp_write8(esp->msg_out[i], ESP_FDATA);
+				esp_write8(0, ESP_FDATA);
+			}
+			scsi_esp_cmd(esp, ESP_CMD_TI);
+		} else {
+			if (esp->msg_out_len == 1) {
+				esp_write8(esp->msg_out[0], ESP_FDATA);
+				scsi_esp_cmd(esp, ESP_CMD_TI);
+			} else {
+				/* Use DMA. */
+				memcpy(esp->command_block,
+				       esp->msg_out,
+				       esp->msg_out_len);
+
+				esp->ops->send_dma_cmd(esp,
+						       esp->command_block_dma,
+						       esp->msg_out_len,
+						       esp->msg_out_len,
+						       0,
+						       ESP_CMD_DMA|ESP_CMD_TI);
+			}
+		}
+		esp_event(esp, ESP_EVENT_MSGOUT_DONE);
+		break;
+	}
+	case ESP_EVENT_MSGOUT_DONE:
+		if (esp->rev == FASHME) {
+			scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+		} else {
+			if (esp->msg_out_len > 1)
+				esp->ops->dma_invalidate(esp);
+		}
+
+		if (!(esp->ireg & ESP_INTR_DC)) {
+			if (esp->rev != FASHME)
+				scsi_esp_cmd(esp, ESP_CMD_NULL);
+		}
+		esp_event(esp, ESP_EVENT_CHECK_PHASE);
+		goto again;
+	case ESP_EVENT_MSGIN:
+		if (esp->ireg & ESP_INTR_BSERV) {
+			if (esp->rev == FASHME) {
+				if (!(esp_read8(ESP_STATUS2) &
+				      ESP_STAT2_FEMPTY))
+					scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+			} else {
+				scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+				if (esp->rev == ESP100)
+					scsi_esp_cmd(esp, ESP_CMD_NULL);
+			}
+			scsi_esp_cmd(esp, ESP_CMD_TI);
+			esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+			return 1;
+		}
+		if (esp->ireg & ESP_INTR_FDONE) {
+			u8 val;
+
+			if (esp->rev == FASHME)
+				val = esp->fifo[0];
+			else
+				val = esp_read8(ESP_FDATA);
+			esp->msg_in[esp->msg_in_len++] = val;
+
+			esp_log_msgin("ESP: Got msgin byte %x\n", val);
+
+			if (!esp_msgin_process(esp))
+				esp->msg_in_len = 0;
+
+			if (esp->rev == FASHME)
+				scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+			scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+			if (esp->event != ESP_EVENT_FREE_BUS)
+				esp_event(esp, ESP_EVENT_CHECK_PHASE);
+		} else {
+			printk("ESP: MSGIN neither BSERV not FDON, resetting");
+			esp_schedule_reset(esp);
+			return 0;
+		}
+		break;
+	case ESP_EVENT_CMD_START:
+		memcpy(esp->command_block, esp->cmd_bytes_ptr,
+		       esp->cmd_bytes_left);
+		if (esp->rev == FASHME)
+			scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+		esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+				       esp->cmd_bytes_left, 16, 0,
+				       ESP_CMD_DMA | ESP_CMD_TI);
+		esp_event(esp, ESP_EVENT_CMD_DONE);
+		esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+		break;
+	case ESP_EVENT_CMD_DONE:
+		esp->ops->dma_invalidate(esp);
+		if (esp->ireg & ESP_INTR_BSERV) {
+			esp_event(esp, ESP_EVENT_CHECK_PHASE);
+			goto again;
+		}
+		esp_schedule_reset(esp);
+		return 0;
+		break;
+
+	case ESP_EVENT_RESET:
+		scsi_esp_cmd(esp, ESP_CMD_RS);
+		break;
+
+	default:
+		printk("ESP: Unexpected event %x, resetting\n",
+		       esp->event);
+		esp_schedule_reset(esp);
+		return 0;
+		break;
+	}
+	return 1;
+}
+
+static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent)
+{
+	struct scsi_cmnd *cmd = ent->cmd;
+
+	esp_unmap_dma(esp, cmd);
+	esp_free_lun_tag(ent, cmd->device->hostdata);
+	cmd->result = DID_RESET << 16;
+
+	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+		esp->ops->unmap_single(esp, ent->sense_dma,
+				       SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+		ent->sense_ptr = NULL;
+	}
+
+	cmd->scsi_done(cmd);
+	list_del(&ent->list);
+	esp_put_ent(esp, ent);
+}
+
+static void esp_clear_hold(struct scsi_device *dev, void *data)
+{
+	struct esp_lun_data *lp = dev->hostdata;
+
+	BUG_ON(lp->num_tagged);
+	lp->hold = 0;
+}
+
+static void esp_reset_cleanup(struct esp *esp)
+{
+	struct esp_cmd_entry *ent, *tmp;
+	int i;
+
+	list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) {
+		struct scsi_cmnd *cmd = ent->cmd;
+
+		list_del(&ent->list);
+		cmd->result = DID_RESET << 16;
+		cmd->scsi_done(cmd);
+		esp_put_ent(esp, ent);
+	}
+
+	list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) {
+		if (ent == esp->active_cmd)
+			esp->active_cmd = NULL;
+		esp_reset_cleanup_one(esp, ent);
+	}
+
+	BUG_ON(esp->active_cmd != NULL);
+
+	/* Force renegotiation of sync/wide transfers.  */
+	for (i = 0; i < ESP_MAX_TARGET; i++) {
+		struct esp_target_data *tp = &esp->target[i];
+
+		tp->esp_period = 0;
+		tp->esp_offset = 0;
+		tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE |
+				     ESP_CONFIG3_FSCSI |
+				     ESP_CONFIG3_FAST);
+		tp->flags &= ~ESP_TGT_WIDE;
+		tp->flags |= ESP_TGT_CHECK_NEGO;
+
+		if (tp->starget)
+			starget_for_each_device(tp->starget, NULL,
+						esp_clear_hold);
+	}
+}
+
+/* Runs under host->lock */
+static void __esp_interrupt(struct esp *esp)
+{
+	int finish_reset, intr_done;
+	u8 phase;
+
+	esp->sreg = esp_read8(ESP_STATUS);
+
+	if (esp->flags & ESP_FLAG_RESETTING) {
+		finish_reset = 1;
+	} else {
+		if (esp_check_gross_error(esp))
+			return;
+
+		finish_reset = esp_check_spur_intr(esp);
+		if (finish_reset < 0)
+			return;
+	}
+
+	esp->ireg = esp_read8(ESP_INTRPT);
+
+	if (esp->ireg & ESP_INTR_SR)
+		finish_reset = 1;
+
+	if (finish_reset) {
+		esp_reset_cleanup(esp);
+		if (esp->eh_reset) {
+			complete(esp->eh_reset);
+			esp->eh_reset = NULL;
+		}
+		return;
+	}
+
+	phase = (esp->sreg & ESP_STAT_PMASK);
+	if (esp->rev == FASHME) {
+		if (((phase != ESP_DIP && phase != ESP_DOP) &&
+		     esp->select_state == ESP_SELECT_NONE &&
+		     esp->event != ESP_EVENT_STATUS &&
+		     esp->event != ESP_EVENT_DATA_DONE) ||
+		    (esp->ireg & ESP_INTR_RSEL)) {
+			esp->sreg2 = esp_read8(ESP_STATUS2);
+			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+			    (esp->sreg2 & ESP_STAT2_F1BYTE))
+				hme_read_fifo(esp);
+		}
+	}
+
+	esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] "
+		     "sreg2[%02x] ireg[%02x]\n",
+		     esp->sreg, esp->seqreg, esp->sreg2, esp->ireg);
+
+	intr_done = 0;
+
+	if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) {
+		printk("ESP: unexpected IREG %02x\n", esp->ireg);
+		if (esp->ireg & ESP_INTR_IC)
+			esp_dump_cmd_log(esp);
+
+		esp_schedule_reset(esp);
+	} else {
+		if (!(esp->ireg & ESP_INTR_RSEL)) {
+			/* Some combination of FDONE, BSERV, DC.  */
+			if (esp->select_state != ESP_SELECT_NONE)
+				intr_done = esp_finish_select(esp);
+		} else if (esp->ireg & ESP_INTR_RSEL) {
+			if (esp->active_cmd)
+				(void) esp_finish_select(esp);
+			intr_done = esp_reconnect(esp);
+		}
+	}
+	while (!intr_done)
+		intr_done = esp_process_event(esp);
+}
+
+irqreturn_t scsi_esp_intr(int irq, void *dev_id)
+{
+	struct esp *esp = dev_id;
+	unsigned long flags;
+	irqreturn_t ret;
+
+	spin_lock_irqsave(esp->host->host_lock, flags);
+	ret = IRQ_NONE;
+	if (esp->ops->irq_pending(esp)) {
+		ret = IRQ_HANDLED;
+		for (;;) {
+			int i;
+
+			__esp_interrupt(esp);
+			if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK))
+				break;
+			esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK;
+
+			for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+				if (esp->ops->irq_pending(esp))
+					break;
+			}
+			if (i == ESP_QUICKIRQ_LIMIT)
+				break;
+		}
+	}
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(scsi_esp_intr);
+
+static void __devinit esp_get_revision(struct esp *esp)
+{
+	u8 val;
+
+	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+	esp_write8(esp->config2, ESP_CFG2);
+
+	val = esp_read8(ESP_CFG2);
+	val &= ~ESP_CONFIG2_MAGIC;
+	if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+		/* If what we write to cfg2 does not come back, cfg2 is not
+		 * implemented, therefore this must be a plain esp100.
+		 */
+		esp->rev = ESP100;
+	} else {
+		esp->config2 = 0;
+		esp_set_all_config3(esp, 5);
+		esp->prev_cfg3 = 5;
+		esp_write8(esp->config2, ESP_CFG2);
+		esp_write8(0, ESP_CFG3);
+		esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+		val = esp_read8(ESP_CFG3);
+		if (val != 5) {
+			/* The cfg2 register is implemented, however
+			 * cfg3 is not, must be esp100a.
+			 */
+			esp->rev = ESP100A;
+		} else {
+			esp_set_all_config3(esp, 0);
+			esp->prev_cfg3 = 0;
+			esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+			/* All of cfg{1,2,3} implemented, must be one of
+			 * the fas variants, figure out which one.
+			 */
+			if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
+				esp->rev = FAST;
+				esp->sync_defp = SYNC_DEFP_FAST;
+			} else {
+				esp->rev = ESP236;
+			}
+			esp->config2 = 0;
+			esp_write8(esp->config2, ESP_CFG2);
+		}
+	}
+}
+
+static void __devinit esp_init_swstate(struct esp *esp)
+{
+	int i;
+
+	INIT_LIST_HEAD(&esp->queued_cmds);
+	INIT_LIST_HEAD(&esp->active_cmds);
+	INIT_LIST_HEAD(&esp->esp_cmd_pool);
+
+	/* Start with a clear state, domain validation (via ->slave_configure,
+	 * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged
+	 * commands.
+	 */
+	for (i = 0 ; i < ESP_MAX_TARGET; i++) {
+		esp->target[i].flags = 0;
+		esp->target[i].nego_goal_period = 0;
+		esp->target[i].nego_goal_offset = 0;
+		esp->target[i].nego_goal_width = 0;
+		esp->target[i].nego_goal_tags = 0;
+	}
+}
+
+/* This places the ESP into a known state at boot time. */
+static void esp_bootup_reset(struct esp *esp)
+{
+	u8 val;
+
+	/* Reset the DMA */
+	esp->ops->reset_dma(esp);
+
+	/* Reset the ESP */
+	esp_reset_esp(esp);
+
+	/* Reset the SCSI bus, but tell ESP not to generate an irq */
+	val = esp_read8(ESP_CFG1);
+	val |= ESP_CONFIG1_SRRDISAB;
+	esp_write8(val, ESP_CFG1);
+
+	scsi_esp_cmd(esp, ESP_CMD_RS);
+	udelay(400);
+
+	esp_write8(esp->config1, ESP_CFG1);
+
+	/* Eat any bitrot in the chip and we are done... */
+	esp_read8(ESP_INTRPT);
+}
+
+static void __devinit esp_set_clock_params(struct esp *esp)
+{
+	int fmhz;
+	u8 ccf;
+
+	/* This is getting messy but it has to be done correctly or else
+	 * you get weird behavior all over the place.  We are trying to
+	 * basically figure out three pieces of information.
+	 *
+	 * a) Clock Conversion Factor
+	 *
+	 *    This is a representation of the input crystal clock frequency
+	 *    going into the ESP on this machine.  Any operation whose timing
+	 *    is longer than 400ns depends on this value being correct.  For
+	 *    example, you'll get blips for arbitration/selection during high
+	 *    load or with multiple targets if this is not set correctly.
+	 *
+	 * b) Selection Time-Out
+	 *
+	 *    The ESP isn't very bright and will arbitrate for the bus and try
+	 *    to select a target forever if you let it.  This value tells the
+	 *    ESP when it has taken too long to negotiate and that it should
+	 *    interrupt the CPU so we can see what happened.  The value is
+	 *    computed as follows (from NCR/Symbios chip docs).
+	 *
+	 *          (Time Out Period) *  (Input Clock)
+	 *    STO = ----------------------------------
+	 *          (8192) * (Clock Conversion Factor)
+	 *
+	 *    We use a time out period of 250ms (ESP_BUS_TIMEOUT).
+	 *
+	 * c) Imperical constants for synchronous offset and transfer period
+         *    register values
+	 *
+	 *    This entails the smallest and largest sync period we could ever
+	 *    handle on this ESP.
+	 */
+	fmhz = esp->cfreq;
+
+	ccf = ((fmhz / 1000000) + 4) / 5;
+	if (ccf == 1)
+		ccf = 2;
+
+	/* If we can't find anything reasonable, just assume 20MHZ.
+	 * This is the clock frequency of the older sun4c's where I've
+	 * been unable to find the clock-frequency PROM property.  All
+	 * other machines provide useful values it seems.
+	 */
+	if (fmhz <= 5000000 || ccf < 1 || ccf > 8) {
+		fmhz = 20000000;
+		ccf = 4;
+	}
+
+	esp->cfact = (ccf == 8 ? 0 : ccf);
+	esp->cfreq = fmhz;
+	esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+	esp->ctick = ESP_TICK(ccf, esp->ccycle);
+	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+	esp->sync_defp = SYNC_DEFP_SLOW;
+}
+
+static const char *esp_chip_names[] = {
+	"ESP100",
+	"ESP100A",
+	"ESP236",
+	"FAS236",
+	"FAS100A",
+	"FAST",
+	"FASHME",
+};
+
+static struct scsi_transport_template *esp_transport_template;
+
+int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+{
+	static int instance;
+	int err;
+
+	esp->host->transportt = esp_transport_template;
+	esp->host->max_lun = ESP_MAX_LUN;
+	esp->host->cmd_per_lun = 2;
+
+	esp_set_clock_params(esp);
+
+	esp_get_revision(esp);
+
+	esp_init_swstate(esp);
+
+	esp_bootup_reset(esp);
+
+	printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n",
+	       esp->host->unique_id, esp->regs, esp->dma_regs,
+	       esp->host->irq);
+	printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
+	       esp->host->unique_id, esp_chip_names[esp->rev],
+	       esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
+
+	/* Let the SCSI bus reset settle. */
+	ssleep(esp_bus_reset_settle);
+
+	err = scsi_add_host(esp->host, dev);
+	if (err)
+		return err;
+
+	esp->host->unique_id = instance++;
+
+	scsi_scan_host(esp->host);
+
+	return 0;
+}
+EXPORT_SYMBOL(scsi_esp_register);
+
+void __devexit scsi_esp_unregister(struct esp *esp)
+{
+	scsi_remove_host(esp->host);
+}
+EXPORT_SYMBOL(scsi_esp_unregister);
+
+static int esp_slave_alloc(struct scsi_device *dev)
+{
+	struct esp *esp = host_to_esp(dev->host);
+	struct esp_target_data *tp = &esp->target[dev->id];
+	struct esp_lun_data *lp;
+
+	lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+	dev->hostdata = lp;
+
+	tp->starget = dev->sdev_target;
+
+	spi_min_period(tp->starget) = esp->min_period;
+	spi_max_offset(tp->starget) = 15;
+
+	if (esp->flags & ESP_FLAG_WIDE_CAPABLE)
+		spi_max_width(tp->starget) = 1;
+	else
+		spi_max_width(tp->starget) = 0;
+
+	return 0;
+}
+
+static int esp_slave_configure(struct scsi_device *dev)
+{
+	struct esp *esp = host_to_esp(dev->host);
+	struct esp_target_data *tp = &esp->target[dev->id];
+	int goal_tags, queue_depth;
+
+	goal_tags = 0;
+
+	if (dev->tagged_supported) {
+		/* XXX make this configurable somehow XXX */
+		goal_tags = ESP_DEFAULT_TAGS;
+
+		if (goal_tags > ESP_MAX_TAG)
+			goal_tags = ESP_MAX_TAG;
+	}
+
+	queue_depth = goal_tags;
+	if (queue_depth < dev->host->cmd_per_lun)
+		queue_depth = dev->host->cmd_per_lun;
+
+	if (goal_tags) {
+		scsi_set_tag_type(dev, MSG_ORDERED_TAG);
+		scsi_activate_tcq(dev, queue_depth);
+	} else {
+		scsi_deactivate_tcq(dev, queue_depth);
+	}
+	tp->flags |= ESP_TGT_DISCONNECT;
+
+	if (!spi_initial_dv(dev->sdev_target))
+		spi_dv_device(dev);
+
+	return 0;
+}
+
+static void esp_slave_destroy(struct scsi_device *dev)
+{
+	struct esp_lun_data *lp = dev->hostdata;
+
+	kfree(lp);
+	dev->hostdata = NULL;
+}
+
+static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+	struct esp *esp = host_to_esp(cmd->device->host);
+	struct esp_cmd_entry *ent, *tmp;
+	struct completion eh_done;
+	unsigned long flags;
+
+	/* XXX This helps a lot with debugging but might be a bit
+	 * XXX much for the final driver.
+	 */
+	spin_lock_irqsave(esp->host->host_lock, flags);
+	printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n",
+	       esp->host->unique_id, cmd, cmd->cmnd[0]);
+	ent = esp->active_cmd;
+	if (ent)
+		printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n",
+		       esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+	list_for_each_entry(ent, &esp->queued_cmds, list) {
+		printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n",
+		       esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+	}
+	list_for_each_entry(ent, &esp->active_cmds, list) {
+		printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n",
+		       esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+	}
+	esp_dump_cmd_log(esp);
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+	spin_lock_irqsave(esp->host->host_lock, flags);
+
+	ent = NULL;
+	list_for_each_entry(tmp, &esp->queued_cmds, list) {
+		if (tmp->cmd == cmd) {
+			ent = tmp;
+			break;
+		}
+	}
+
+	if (ent) {
+		/* Easiest case, we didn't even issue the command
+		 * yet so it is trivial to abort.
+		 */
+		list_del(&ent->list);
+
+		cmd->result = DID_ABORT << 16;
+		cmd->scsi_done(cmd);
+
+		esp_put_ent(esp, ent);
+
+		goto out_success;
+	}
+
+	init_completion(&eh_done);
+
+	ent = esp->active_cmd;
+	if (ent && ent->cmd == cmd) {
+		/* Command is the currently active command on
+		 * the bus.  If we already have an output message
+		 * pending, no dice.
+		 */
+		if (esp->msg_out_len)
+			goto out_failure;
+
+		/* Send out an abort, encouraging the target to
+		 * go to MSGOUT phase by asserting ATN.
+		 */
+		esp->msg_out[0] = ABORT_TASK_SET;
+		esp->msg_out_len = 1;
+		ent->eh_done = &eh_done;
+
+		scsi_esp_cmd(esp, ESP_CMD_SATN);
+	} else {
+		/* The command is disconnected.  This is not easy to
+		 * abort.  For now we fail and let the scsi error
+		 * handling layer go try a scsi bus reset or host
+		 * reset.
+		 *
+		 * What we could do is put together a scsi command
+		 * solely for the purpose of sending an abort message
+		 * to the target.  Coming up with all the code to
+		 * cook up scsi commands, special case them everywhere,
+		 * etc. is for questionable gain and it would be better
+		 * if the generic scsi error handling layer could do at
+		 * least some of that for us.
+		 *
+		 * Anyways this is an area for potential future improvement
+		 * in this driver.
+		 */
+		goto out_failure;
+	}
+
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+	if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) {
+		spin_lock_irqsave(esp->host->host_lock, flags);
+		ent->eh_done = NULL;
+		spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+		return FAILED;
+	}
+
+	return SUCCESS;
+
+out_success:
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+	return SUCCESS;
+
+out_failure:
+	/* XXX This might be a good location to set ESP_TGT_BROKEN
+	 * XXX since we know which target/lun in particular is
+	 * XXX causing trouble.
+	 */
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+	return FAILED;
+}
+
+static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+	struct esp *esp = host_to_esp(cmd->device->host);
+	struct completion eh_reset;
+	unsigned long flags;
+
+	init_completion(&eh_reset);
+
+	spin_lock_irqsave(esp->host->host_lock, flags);
+
+	esp->eh_reset = &eh_reset;
+
+	/* XXX This is too simple... We should add lots of
+	 * XXX checks here so that if we find that the chip is
+	 * XXX very wedged we return failure immediately so
+	 * XXX that we can perform a full chip reset.
+	 */
+	esp->flags |= ESP_FLAG_RESETTING;
+	scsi_esp_cmd(esp, ESP_CMD_RS);
+
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+	ssleep(esp_bus_reset_settle);
+
+	if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) {
+		spin_lock_irqsave(esp->host->host_lock, flags);
+		esp->eh_reset = NULL;
+		spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+		return FAILED;
+	}
+
+	return SUCCESS;
+}
+
+/* All bets are off, reset the entire device.  */
+static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd)
+{
+	struct esp *esp = host_to_esp(cmd->device->host);
+	unsigned long flags;
+
+	spin_lock_irqsave(esp->host->host_lock, flags);
+	esp_bootup_reset(esp);
+	esp_reset_cleanup(esp);
+	spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+	ssleep(esp_bus_reset_settle);
+
+	return SUCCESS;
+}
+
+static const char *esp_info(struct Scsi_Host *host)
+{
+	return "esp";
+}
+
+struct scsi_host_template scsi_esp_template = {
+	.module			= THIS_MODULE,
+	.name			= "esp",
+	.info			= esp_info,
+	.queuecommand		= esp_queuecommand,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_configure	= esp_slave_configure,
+	.slave_destroy		= esp_slave_destroy,
+	.eh_abort_handler	= esp_eh_abort_handler,
+	.eh_bus_reset_handler	= esp_eh_bus_reset_handler,
+	.eh_host_reset_handler	= esp_eh_host_reset_handler,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.max_sectors		= 0xffff,
+	.skip_settle_delay	= 1,
+};
+EXPORT_SYMBOL(scsi_esp_template);
+
+static void esp_get_signalling(struct Scsi_Host *host)
+{
+	struct esp *esp = host_to_esp(host);
+	enum spi_signal_type type;
+
+	if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+		type = SPI_SIGNAL_HVD;
+	else
+		type = SPI_SIGNAL_SE;
+
+	spi_signalling(host) = type;
+}
+
+static void esp_set_offset(struct scsi_target *target, int offset)
+{
+	struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+	struct esp *esp = host_to_esp(host);
+	struct esp_target_data *tp = &esp->target[target->id];
+
+	tp->nego_goal_offset = offset;
+	tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_period(struct scsi_target *target, int period)
+{
+	struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+	struct esp *esp = host_to_esp(host);
+	struct esp_target_data *tp = &esp->target[target->id];
+
+	tp->nego_goal_period = period;
+	tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_width(struct scsi_target *target, int width)
+{
+	struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+	struct esp *esp = host_to_esp(host);
+	struct esp_target_data *tp = &esp->target[target->id];
+
+	tp->nego_goal_width = (width ? 1 : 0);
+	tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static struct spi_function_template esp_transport_ops = {
+	.set_offset		= esp_set_offset,
+	.show_offset		= 1,
+	.set_period		= esp_set_period,
+	.show_period		= 1,
+	.set_width		= esp_set_width,
+	.show_width		= 1,
+	.get_signalling		= esp_get_signalling,
+};
+
+static int __init esp_init(void)
+{
+	BUILD_BUG_ON(sizeof(struct scsi_pointer) <
+		     sizeof(struct esp_cmd_priv));
+
+	esp_transport_template = spi_attach_transport(&esp_transport_ops);
+	if (!esp_transport_template)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void __exit esp_exit(void)
+{
+	spi_release_transport(esp_transport_template);
+}
+
+MODULE_DESCRIPTION("ESP SCSI driver core");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(esp_bus_reset_settle, int, 0);
+MODULE_PARM_DESC(esp_bus_reset_settle,
+		 "ESP scsi bus reset delay in seconds");
+
+module_param(esp_debug, int, 0);
+MODULE_PARM_DESC(esp_debug,
+"ESP bitmapped debugging message enable value:\n"
+"	0x00000001	Log interrupt events\n"
+"	0x00000002	Log scsi commands\n"
+"	0x00000004	Log resets\n"
+"	0x00000008	Log message in events\n"
+"	0x00000010	Log message out events\n"
+"	0x00000020	Log command completion\n"
+"	0x00000040	Log disconnects\n"
+"	0x00000080	Log data start\n"
+"	0x00000100	Log data done\n"
+"	0x00000200	Log reconnects\n"
+"	0x00000400	Log auto-sense data\n"
+);
+
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
new file mode 100644
index 0000000..8d4a669
--- /dev/null
+++ b/drivers/scsi/esp_scsi.h
@@ -0,0 +1,560 @@
+/* esp_scsi.h: Defines and structures for the ESP drier.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _ESP_SCSI_H
+#define _ESP_SCSI_H
+
+					/* Access    Description      Offset */
+#define ESP_TCLOW	0x00UL		/* rw  Low bits transfer count 0x00  */
+#define ESP_TCMED	0x01UL		/* rw  Mid bits transfer count 0x04  */
+#define ESP_FDATA	0x02UL		/* rw  FIFO data bits          0x08  */
+#define ESP_CMD		0x03UL		/* rw  SCSI command bits       0x0c  */
+#define ESP_STATUS	0x04UL		/* ro  ESP status register     0x10  */
+#define ESP_BUSID	ESP_STATUS	/* wo  BusID for sel/resel     0x10  */
+#define ESP_INTRPT	0x05UL		/* ro  Kind of interrupt       0x14  */
+#define ESP_TIMEO	ESP_INTRPT	/* wo  Timeout for sel/resel   0x14  */
+#define ESP_SSTEP	0x06UL		/* ro  Sequence step register  0x18  */
+#define ESP_STP		ESP_SSTEP	/* wo  Transfer period/sync    0x18  */
+#define ESP_FFLAGS	0x07UL		/* ro  Bits current FIFO info  0x1c  */
+#define ESP_SOFF	ESP_FFLAGS	/* wo  Sync offset             0x1c  */
+#define ESP_CFG1	0x08UL		/* rw  First cfg register      0x20  */
+#define ESP_CFACT	0x09UL		/* wo  Clock conv factor       0x24  */
+#define ESP_STATUS2	ESP_CFACT	/* ro  HME status2 register    0x24  */
+#define ESP_CTEST	0x0aUL		/* wo  Chip test register      0x28  */
+#define ESP_CFG2	0x0bUL		/* rw  Second cfg register     0x2c  */
+#define ESP_CFG3	0x0cUL		/* rw  Third cfg register      0x30  */
+#define ESP_TCHI	0x0eUL		/* rw  High bits transf count  0x38  */
+#define ESP_UID		ESP_TCHI	/* ro  Unique ID code          0x38  */
+#define FAS_RLO		ESP_TCHI	/* rw  HME extended counter    0x38  */
+#define ESP_FGRND	0x0fUL		/* rw  Data base for fifo      0x3c  */
+#define FAS_RHI		ESP_FGRND	/* rw  HME extended counter    0x3c  */
+
+#define SBUS_ESP_REG_SIZE	0x40UL
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID        0x07      /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST    0x08      /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE   0x10      /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST   0x20      /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB  0x40      /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE   0x80      /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
+#define ESP_CONFIG2_DMAPARITY 0x01      /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02      /* enable reg Parity (200,236) */
+#define ESP_CONFIG2_BADPARITY 0x04      /* Bad parity target abort  */
+#define ESP_CONFIG2_SCSI2ENAB 0x08      /* Enable SCSI-2 features (tgtmode) */
+#define ESP_CONFIG2_HI        0x10      /* High Impedance DREQ ???  */
+#define ESP_CONFIG2_HMEFENAB  0x10      /* HME features enable */
+#define ESP_CONFIG2_BCM       0x20      /* Enable byte-ctrl (236)   */
+#define ESP_CONFIG2_DISPINT   0x20      /* Disable pause irq (hme) */
+#define ESP_CONFIG2_FENAB     0x40      /* Enable features (fas100,216) */
+#define ESP_CONFIG2_SPL       0x40      /* Enable status-phase latch (236) */
+#define ESP_CONFIG2_MKDONE    0x40      /* HME magic feature */
+#define ESP_CONFIG2_HME32     0x80      /* HME 32 extended */
+#define ESP_CONFIG2_MAGIC     0xe0      /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK    0x01     /* FAST SCSI clock rate (esp100a/hme) */
+#define ESP_CONFIG3_TEM       0x01     /* Enable thresh-8 mode (esp/fas236)  */
+#define ESP_CONFIG3_FAST      0x02     /* Enable FAST SCSI     (esp100a/hme) */
+#define ESP_CONFIG3_ADMA      0x02     /* Enable alternate-dma (esp/fas236)  */
+#define ESP_CONFIG3_TENB      0x04     /* group2 SCSI2 support (esp100a/hme) */
+#define ESP_CONFIG3_SRB       0x04     /* Save residual byte   (esp/fas236)  */
+#define ESP_CONFIG3_TMS       0x08     /* Three-byte msg's ok  (esp100a/hme) */
+#define ESP_CONFIG3_FCLK      0x08     /* Fast SCSI clock rate (esp/fas236)  */
+#define ESP_CONFIG3_IDMSG     0x10     /* ID message checking  (esp100a/hme) */
+#define ESP_CONFIG3_FSCSI     0x10     /* Enable FAST SCSI     (esp/fas236)  */
+#define ESP_CONFIG3_GTM       0x20     /* group2 SCSI2 support (esp/fas236)  */
+#define ESP_CONFIG3_IDBIT3    0x20     /* Bit 3 of HME SCSI-ID (hme)         */
+#define ESP_CONFIG3_TBMS      0x40     /* Three-byte msg's ok  (esp/fas236)  */
+#define ESP_CONFIG3_EWIDE     0x40     /* Enable Wide-SCSI     (hme)         */
+#define ESP_CONFIG3_IMS       0x80     /* ID msg chk'ng        (esp/fas236)  */
+#define ESP_CONFIG3_OBPUSH    0x80     /* Push odd-byte to dma (hme)         */
+
+/* ESP command register read-write */
+/* Group 1 commands:  These may be sent at any point in time to the ESP
+ *                    chip.  None of them can generate interrupts 'cept
+ *                    the "SCSI bus reset" command if you have not disabled
+ *                    SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL          0x00     /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH         0x01     /* FIFO Flush */
+#define ESP_CMD_RC            0x02     /* Chip reset */
+#define ESP_CMD_RS            0x03     /* SCSI bus reset */
+
+/* Group 2 commands:  ESP must be an initiator and connected to a target
+ *                    for these commands to work.
+ */
+#define ESP_CMD_TI            0x10     /* Transfer Information */
+#define ESP_CMD_ICCSEQ        0x11     /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK           0x12     /* Message okie-dokie */
+#define ESP_CMD_TPAD          0x18     /* Transfer Pad */
+#define ESP_CMD_SATN          0x1a     /* Set ATN */
+#define ESP_CMD_RATN          0x1b     /* De-assert ATN */
+
+/* Group 3 commands:  ESP must be in the MSGOUT or MSGIN state and be connected
+ *                    to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG          0x20     /* Send message */
+#define ESP_CMD_SSTAT         0x21     /* Send status */
+#define ESP_CMD_SDATA         0x22     /* Send data */
+#define ESP_CMD_DSEQ          0x23     /* Discontinue Sequence */
+#define ESP_CMD_TSEQ          0x24     /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ        0x25     /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT         0x27     /* Disconnect */
+#define ESP_CMD_RMSG          0x28     /* Receive Message */
+#define ESP_CMD_RCMD          0x29     /* Receive Command */
+#define ESP_CMD_RDATA         0x2a     /* Receive Data */
+#define ESP_CMD_RCSEQ         0x2b     /* Receive cmd sequence */
+
+/* Group 4 commands:  The ESP must be in the disconnected state and must
+ *                    not be connected to any targets as initiator for
+ *                    these commands to work.
+ */
+#define ESP_CMD_RSEL          0x40     /* Reselect */
+#define ESP_CMD_SEL           0x41     /* Select w/o ATN */
+#define ESP_CMD_SELA          0x42     /* Select w/ATN */
+#define ESP_CMD_SELAS         0x43     /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL          0x44     /* Enable selection */
+#define ESP_CMD_DSEL          0x45     /* Disable selections */
+#define ESP_CMD_SA3           0x46     /* Select w/ATN3 */
+#define ESP_CMD_RSEL3         0x47     /* Reselect3 */
+
+/* This bit enables the ESP's DMA on the SBus */
+#define ESP_CMD_DMA           0x80     /* Do DMA? */
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO          0x01     /* IO phase bit */
+#define ESP_STAT_PCD          0x02     /* CD phase bit */
+#define ESP_STAT_PMSG         0x04     /* MSG phase bit */
+#define ESP_STAT_PMASK        0x07     /* Mask of phase bits */
+#define ESP_STAT_TDONE        0x08     /* Transfer Completed */
+#define ESP_STAT_TCNT         0x10     /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR         0x20     /* Parity error */
+#define ESP_STAT_SPAM         0x40     /* Real bad error */
+/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
+ * bit on other revs of the ESP.
+ */
+#define ESP_STAT_INTR         0x80             /* Interrupt */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in.  For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP   (0)                                       /* Data Out  */
+#define ESP_DIP   (ESP_STAT_PIO)                            /* Data In   */
+#define ESP_CMDP  (ESP_STAT_PCD)                            /* Command   */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO)               /* Status    */
+#define ESP_MOP   (ESP_STAT_PMSG|ESP_STAT_PCD)              /* Message Out */
+#define ESP_MIP   (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT      0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS      0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT        0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA       0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE        0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE      0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB        0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY      0x80 /* FIFO is empty */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S            0x01     /* Select w/o ATN */
+#define ESP_INTR_SATN         0x02     /* Select w/ATN */
+#define ESP_INTR_RSEL         0x04     /* Reselected */
+#define ESP_INTR_FDONE        0x08     /* Function done */
+#define ESP_INTR_BSERV        0x10     /* Bus service */
+#define ESP_INTR_DC           0x20     /* Disconnect */
+#define ESP_INTR_IC           0x40     /* Illegal command given */
+#define ESP_INTR_SR           0x80     /* SCSI bus reset detected */
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS        0x07     /* Valid bits */
+#define ESP_STEP_ASEL         0x00     /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID          0x01     /* One msg byte sent */
+#define ESP_STEP_NCMD         0x02     /* Was not in command phase */
+#define ESP_STEP_PPC          0x03     /* Early phase chg caused cmnd
+                                        * bytes to be lost
+                                        */
+#define ESP_STEP_FINI4        0x04     /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5        0x05
+#define ESP_STEP_FINI6        0x06
+#define ESP_STEP_FINI7        0x07
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG         0x01     /* Target test mode */
+#define ESP_TEST_INI          0x02     /* Initiator test mode */
+#define ESP_TEST_TS           0x04     /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a only */
+#define ESP_UID_F100A         0x00     /* ESP FAS100A  */
+#define ESP_UID_F236          0x02     /* ESP FAS236   */
+#define ESP_UID_REV           0x07     /* ESP revision */
+#define ESP_UID_FAM           0xf8     /* ESP family   */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES         0x1f     /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO       0x20     /* offset ctr not zero (esp100) */
+#define ESP_FF_SSTEP          0xe0     /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0            0x00     /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER         0x01     /* Set it to this and die */
+#define ESP_CCF_F2            0x02     /* 10MHz */
+#define ESP_CCF_F3            0x03     /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4            0x04     /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5            0x05     /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6            0x06     /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7            0x07     /* 30.01MHz - 35MHz */
+
+/* HME only... */
+#define ESP_BUSID_RESELID     0x10
+#define ESP_BUSID_CTR32BIT    0x40
+
+#define ESP_BUS_TIMEOUT        250     /* In milli-seconds */
+#define ESP_TIMEO_CONST       8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
+
+/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high
+ * input clock rates we try to do 10mb/s although I don't think a transfer can
+ * even run that fast with an ESP even with DMA2 scatter gather pipelining.
+ */
+#define SYNC_DEFP_SLOW            0x32   /* 5mb/s  */
+#define SYNC_DEFP_FAST            0x19   /* 10mb/s */
+
+struct esp_cmd_priv {
+	union {
+		dma_addr_t	dma_addr;
+		int		num_sg;
+	} u;
+
+	unsigned int		cur_residue;
+	struct scatterlist	*cur_sg;
+	unsigned int		tot_residue;
+};
+#define ESP_CMD_PRIV(CMD)	((struct esp_cmd_priv *)(&(CMD)->SCp))
+
+enum esp_rev {
+	ESP100     = 0x00,  /* NCR53C90 - very broken */
+	ESP100A    = 0x01,  /* NCR53C90A */
+	ESP236     = 0x02,
+	FAS236     = 0x03,
+	FAS100A    = 0x04,
+	FAST       = 0x05,
+	FASHME     = 0x06,
+};
+
+struct esp_cmd_entry {
+	struct list_head	list;
+
+	struct scsi_cmnd	*cmd;
+
+	unsigned int		saved_cur_residue;
+	struct scatterlist	*saved_cur_sg;
+	unsigned int		saved_tot_residue;
+
+	u8			flags;
+#define ESP_CMD_FLAG_WRITE	0x01 /* DMA is a write */
+#define ESP_CMD_FLAG_ABORT	0x02 /* being aborted */
+#define ESP_CMD_FLAG_AUTOSENSE	0x04 /* Doing automatic REQUEST_SENSE */
+
+	u8			tag[2];
+
+	u8			status;
+	u8			message;
+
+	unsigned char		*sense_ptr;
+	unsigned char		*saved_sense_ptr;
+	dma_addr_t		sense_dma;
+
+	struct completion	*eh_done;
+};
+
+/* XXX make this configurable somehow XXX */
+#define ESP_DEFAULT_TAGS	16
+
+#define ESP_MAX_TARGET		16
+#define ESP_MAX_LUN		8
+#define ESP_MAX_TAG		256
+
+struct esp_lun_data {
+	struct esp_cmd_entry	*non_tagged_cmd;
+	int			num_tagged;
+	int			hold;
+	struct esp_cmd_entry	*tagged_cmds[ESP_MAX_TAG];
+};
+
+struct esp_target_data {
+	/* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which
+	 * match the currently negotiated settings for this target.  The SCSI
+	 * protocol values are maintained in spi_{offset,period,wide}(starget).
+	 */
+	u8			esp_period;
+	u8			esp_offset;
+	u8			esp_config3;
+
+	u8			flags;
+#define ESP_TGT_WIDE		0x01
+#define ESP_TGT_DISCONNECT	0x02
+#define ESP_TGT_NEGO_WIDE	0x04
+#define ESP_TGT_NEGO_SYNC	0x08
+#define ESP_TGT_CHECK_NEGO	0x40
+#define ESP_TGT_BROKEN		0x80
+
+	/* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this
+	 * device we will try to negotiate the following parameters.
+	 */
+	u8			nego_goal_period;
+	u8			nego_goal_offset;
+	u8			nego_goal_width;
+	u8			nego_goal_tags;
+
+	struct scsi_target	*starget;
+};
+
+struct esp_event_ent {
+	u8			type;
+#define ESP_EVENT_TYPE_EVENT	0x01
+#define ESP_EVENT_TYPE_CMD	0x02
+	u8			val;
+
+	u8			sreg;
+	u8			seqreg;
+	u8			sreg2;
+	u8			ireg;
+	u8			select_state;
+	u8			event;
+	u8			__pad;
+};
+
+struct esp;
+struct esp_driver_ops {
+	/* Read and write the ESP 8-bit registers.  On some
+	 * applications of the ESP chip the registers are at 4-byte
+	 * instead of 1-byte intervals.
+	 */
+	void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg);
+	u8 (*esp_read8)(struct esp *esp, unsigned long reg);
+
+	/* Map and unmap DMA memory.  Eventually the driver will be
+	 * converted to the generic DMA API as soon as SBUS is able to
+	 * cope with that.  At such time we can remove this.
+	 */
+	dma_addr_t (*map_single)(struct esp *esp, void *buf,
+				 size_t sz, int dir);
+	int (*map_sg)(struct esp *esp, struct scatterlist *sg,
+		      int num_sg, int dir);
+	void (*unmap_single)(struct esp *esp, dma_addr_t addr,
+			     size_t sz, int dir);
+	void (*unmap_sg)(struct esp *esp, struct scatterlist *sg,
+			 int num_sg, int dir);
+
+	/* Return non-zero if there is an IRQ pending.  Usually this
+	 * status bit lives in the DMA controller sitting in front of
+	 * the ESP.  This has to be accurate or else the ESP interrupt
+	 * handler will not run.
+	 */
+	int (*irq_pending)(struct esp *esp);
+
+	/* Reset the DMA engine entirely.  On return, ESP interrupts
+	 * should be enabled.  Often the interrupt enabling is
+	 * controlled in the DMA engine.
+	 */
+	void (*reset_dma)(struct esp *esp);
+
+	/* Drain any pending DMA in the DMA engine after a transfer.
+	 * This is for writes to memory.
+	 */
+	void (*dma_drain)(struct esp *esp);
+
+	/* Invalidate the DMA engine after a DMA transfer.  */
+	void (*dma_invalidate)(struct esp *esp);
+
+	/* Setup an ESP command that will use a DMA transfer.
+	 * The 'esp_count' specifies what transfer length should be
+	 * programmed into the ESP transfer counter registers, whereas
+	 * the 'dma_count' is the length that should be programmed into
+	 * the DMA controller.  Usually they are the same.  If 'write'
+	 * is non-zero, this transfer is a write into memory.  'cmd'
+	 * holds the ESP command that should be issued by calling
+	 * scsi_esp_cmd() at the appropriate time while programming
+	 * the DMA hardware.
+	 */
+	void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count,
+			     u32 dma_count, int write, u8 cmd);
+
+	/* Return non-zero if the DMA engine is reporting an error
+	 * currently.
+	 */
+	int (*dma_error)(struct esp *esp);
+};
+
+#define ESP_MAX_MSG_SZ		8
+#define ESP_EVENT_LOG_SZ	32
+
+#define ESP_QUICKIRQ_LIMIT	100
+#define ESP_RESELECT_TAG_LIMIT	2500
+
+struct esp {
+	void __iomem		*regs;
+	void __iomem		*dma_regs;
+
+	const struct esp_driver_ops *ops;
+
+	struct Scsi_Host	*host;
+	void			*dev;
+
+	struct esp_cmd_entry	*active_cmd;
+
+	struct list_head	queued_cmds;
+	struct list_head	active_cmds;
+
+	u8			*command_block;
+	dma_addr_t		command_block_dma;
+
+	unsigned int		data_dma_len;
+
+	/* The following are used to determine the cause of an IRQ. Upon every
+	 * IRQ entry we synchronize these with the hardware registers.
+	 */
+	u8			sreg;
+	u8			seqreg;
+	u8			sreg2;
+	u8			ireg;
+
+	u32			prev_hme_dmacsr;
+	u8			prev_soff;
+	u8			prev_stp;
+	u8			prev_cfg3;
+	u8			__pad;
+
+	struct list_head	esp_cmd_pool;
+
+	struct esp_target_data	target[ESP_MAX_TARGET];
+
+	int			fifo_cnt;
+	u8			fifo[16];
+
+	struct esp_event_ent	esp_event_log[ESP_EVENT_LOG_SZ];
+	int			esp_event_cur;
+
+	u8			msg_out[ESP_MAX_MSG_SZ];
+	int			msg_out_len;
+
+	u8			msg_in[ESP_MAX_MSG_SZ];
+	int			msg_in_len;
+
+	u8			bursts;
+	u8			config1;
+	u8			config2;
+
+	u8			scsi_id;
+	u32			scsi_id_mask;
+
+	enum esp_rev		rev;
+
+	u32			flags;
+#define ESP_FLAG_DIFFERENTIAL	0x00000001
+#define ESP_FLAG_RESETTING	0x00000002
+#define ESP_FLAG_DOING_SLOWCMD	0x00000004
+#define ESP_FLAG_WIDE_CAPABLE	0x00000008
+#define ESP_FLAG_QUICKIRQ_CHECK	0x00000010
+
+	u8			select_state;
+#define ESP_SELECT_NONE		0x00 /* Not selecting */
+#define ESP_SELECT_BASIC	0x01 /* Select w/o MSGOUT phase */
+#define ESP_SELECT_MSGOUT	0x02 /* Select with MSGOUT */
+
+	/* When we are not selecting, we are expecting an event.  */
+	u8			event;
+#define ESP_EVENT_NONE		0x00
+#define ESP_EVENT_CMD_START	0x01
+#define ESP_EVENT_CMD_DONE	0x02
+#define ESP_EVENT_DATA_IN	0x03
+#define ESP_EVENT_DATA_OUT	0x04
+#define ESP_EVENT_DATA_DONE	0x05
+#define ESP_EVENT_MSGIN		0x06
+#define ESP_EVENT_MSGIN_MORE	0x07
+#define ESP_EVENT_MSGIN_DONE	0x08
+#define ESP_EVENT_MSGOUT	0x09
+#define ESP_EVENT_MSGOUT_DONE	0x0a
+#define ESP_EVENT_STATUS	0x0b
+#define ESP_EVENT_FREE_BUS	0x0c
+#define ESP_EVENT_CHECK_PHASE	0x0d
+#define ESP_EVENT_RESET		0x10
+
+	/* Probed in esp_get_clock_params() */
+	u32			cfact;
+	u32			cfreq;
+	u32			ccycle;
+	u32			ctick;
+	u32			neg_defp;
+	u32			sync_defp;
+
+	/* Computed in esp_reset_esp() */
+	u32			max_period;
+	u32			min_period;
+	u32			radelay;
+
+	/* Slow command state.  */
+	u8			*cmd_bytes_ptr;
+	int			cmd_bytes_left;
+
+	struct completion	*eh_reset;
+
+	struct sbus_dma		*dma;
+};
+
+#define host_to_esp(host)	((struct esp *)(host)->hostdata)
+
+/* A front-end driver for the ESP chip should do the following in
+ * it's device probe routine:
+ * 1) Allocate the host and private area using scsi_host_alloc()
+ *    with size 'sizeof(struct esp)'.  The first argument to
+ *    scsi_host_alloc() should be &scsi_esp_template.
+ * 2) Set host->max_id as appropriate.
+ * 3) Set esp->host to the scsi_host itself, and esp->dev
+ *    to the device object pointer.
+ * 4) Hook up esp->ops to the front-end implementation.
+ * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE
+ *    in esp->flags.
+ * 6) Map the DMA and ESP chip registers.
+ * 7) DMA map the ESP command block, store the DMA address
+ *    in esp->command_block_dma.
+ * 8) Register the scsi_esp_intr() interrupt handler.
+ * 9) Probe for and provide the following chip properties:
+ *    esp->scsi_id (assign to esp->host->this_id too)
+ *    esp->scsi_id_mask
+ *    If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL
+ *    esp->cfreq
+ *    DMA burst bit mask in esp->bursts, if necessary
+ * 10) Perform any actions necessary before the ESP device can
+ *     be programmed for the first time.  On some configs, for
+ *     example, the DMA engine has to be reset before ESP can
+ *     be programmed.
+ * 11) If necessary, call dev_set_drvdata() as needed.
+ * 12) Call scsi_esp_register() with prepared 'esp' structure
+ *     and a device pointer if possible.
+ * 13) Check scsi_esp_register() return value, release all resources
+ *     if an error was returned.
+ */
+extern struct scsi_host_template scsi_esp_template;
+extern int scsi_esp_register(struct esp *, struct device *);
+
+extern void scsi_esp_unregister(struct esp *);
+extern irqreturn_t scsi_esp_intr(int, void *);
+extern void scsi_esp_cmd(struct esp *, u8);
+
+#endif /* !(_ESP_SCSI_H) */
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 38c3a29..bd8e7f3 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsig
 	struct class_device *cdev;
 	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
 
-	down_read(&class->subsys.rwsem);
+	down(&class->sem);
 	list_for_each_entry(cdev, &class->children, node) {
 		p = class_to_shost(cdev);
 		if (p->host_no == hostnum) {
@@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsig
 			break;
 		}
 	}
-	up_read(&class->subsys.rwsem);
+	up(&class->sem);
 
 	return shost;
 }
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index fbc1d5c..b10eefe 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -85,7 +85,7 @@ #include "ibmvscsi.h"
 static int max_id = 64;
 static int max_channel = 3;
 static int init_timeout = 5;
-static int max_requests = 50;
+static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
 
 #define IBMVSCSI_VERSION "1.5.8"
 
@@ -538,7 +538,8 @@ static int ibmvscsi_send_srp_event(struc
 	int request_status;
 	int rc;
 
-	/* If we have exhausted our request limit, just fail this request.
+	/* If we have exhausted our request limit, just fail this request,
+	 * unless it is for a reset or abort.
 	 * Note that there are rare cases involving driver generated requests 
 	 * (such as task management requests) that the mid layer may think we
 	 * can handle more requests (can_queue) when we actually can't
@@ -551,9 +552,30 @@ static int ibmvscsi_send_srp_event(struc
 		 */
 		if (request_status < -1)
 			goto send_error;
-		/* Otherwise, if we have run out of requests */
-		else if (request_status < 0)
-			goto send_busy;
+		/* Otherwise, we may have run out of requests. */
+		/* Abort and reset calls should make it through.
+		 * Nothing except abort and reset should use the last two
+		 * slots unless we had two or less to begin with.
+		 */
+		else if (request_status < 2 &&
+		         evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
+			/* In the case that we have less than two requests
+			 * available, check the server limit as a combination
+			 * of the request limit and the number of requests
+			 * in-flight (the size of the send list).  If the
+			 * server limit is greater than 2, return busy so
+			 * that the last two are reserved for reset and abort.
+			 */
+			int server_limit = request_status;
+			struct srp_event_struct *tmp_evt;
+
+			list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+				server_limit++;
+			}
+
+			if (server_limit > 2)
+				goto send_busy;
+		}
 	}
 
 	/* Copy the IU into the transfer area */
@@ -572,6 +594,7 @@ static int ibmvscsi_send_srp_event(struc
 
 		printk(KERN_ERR "ibmvscsi: send error %d\n",
 		       rc);
+		atomic_inc(&hostdata->request_limit);
 		goto send_error;
 	}
 
@@ -581,7 +604,8 @@ static int ibmvscsi_send_srp_event(struc
 	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
 
 	free_event_struct(&hostdata->pool, evt_struct);
- 	return SCSI_MLQUEUE_HOST_BUSY;
+	atomic_inc(&hostdata->request_limit);
+	return SCSI_MLQUEUE_HOST_BUSY;
 
  send_error:
 	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
@@ -831,23 +855,16 @@ static void login_rsp(struct srp_event_s
 
 	printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
 
-	if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta >
-	    (max_requests - 2))
-		evt_struct->xfer_iu->srp.login_rsp.req_lim_delta =
-		    max_requests - 2;
+	if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
+		printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n");
 
-	/* Now we know what the real request-limit is */
+	/* Now we know what the real request-limit is.
+	 * This value is set rather than added to request_limit because
+	 * request_limit could have been set to -1 by this client.
+	 */
 	atomic_set(&hostdata->request_limit,
 		   evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
 
-	hostdata->host->can_queue =
-	    evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2;
-
-	if (hostdata->host->can_queue < 1) {
-		printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
-		return;
-	}
-
 	/* If we had any pending I/Os, kick them */
 	scsi_unblock_requests(hostdata->host);
 
@@ -1337,6 +1354,27 @@ static int ibmvscsi_do_host_config(struc
 	return rc;
 }
 
+/**
+ * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
+ * @sdev:	struct scsi_device device to configure
+ *
+ * Enable allow_restart for a device if it is a disk.  Adjust the
+ * queue_depth here also as is required by the documentation for
+ * struct scsi_host_template.
+ */
+static int ibmvscsi_slave_configure(struct scsi_device *sdev)
+{
+	struct Scsi_Host *shost = sdev->host;
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(shost->host_lock, lock_flags);
+	if (sdev->type == TYPE_DISK)
+		sdev->allow_restart = 1;
+	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
+	spin_unlock_irqrestore(shost->host_lock, lock_flags);
+	return 0;
+}
+
 /* ------------------------------------------------------------
  * sysfs attributes
  */
@@ -1482,8 +1520,9 @@ static struct scsi_host_template driver_
 	.queuecommand = ibmvscsi_queuecommand,
 	.eh_abort_handler = ibmvscsi_eh_abort_handler,
 	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+	.slave_configure = ibmvscsi_slave_configure,
 	.cmd_per_lun = 16,
-	.can_queue = 1,		/* Updated after SRP_LOGIN */
+	.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
 	.this_id = -1,
 	.sg_tablesize = SG_ALL,
 	.use_clustering = ENABLE_CLUSTERING,
@@ -1503,6 +1542,7 @@ static int ibmvscsi_probe(struct vio_dev
 
 	vdev->dev.driver_data = NULL;
 
+	driver_template.can_queue = max_requests;
 	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
 	if (!host) {
 		printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 5c6d935..77cc1d4 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -44,6 +44,8 @@ struct Scsi_Host;
  */
 #define MAX_INDIRECT_BUFS 10
 
+#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
+
 /* ------------------------------------------------------------
  * Data Structures
  */
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 4368ca0..8ba7dd0 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -35,7 +35,7 @@ #include <asm/vio.h>
 #include "ibmvscsi.h"
 
 #define	INITIAL_SRP_LIMIT	16
-#define	DEFAULT_MAX_SECTORS	512
+#define	DEFAULT_MAX_SECTORS	256
 
 #define	TGT_NAME	"ibmvstgt"
 
@@ -248,8 +248,8 @@ static int ibmvstgt_rdma(struct scsi_cmn
 						  md[i].va + mdone);
 
 			if (err != H_SUCCESS) {
-				eprintk("rdma error %d %d\n", dir, slen);
-				goto out;
+				eprintk("rdma error %d %d %ld\n", dir, slen, err);
+				return -EIO;
 			}
 
 			mlen -= slen;
@@ -265,45 +265,35 @@ static int ibmvstgt_rdma(struct scsi_cmn
 				if (sidx > nsg) {
 					eprintk("out of sg %p %d %d\n",
 						iue, sidx, nsg);
-					goto out;
+					return -EIO;
 				}
 			}
 		};
 
 		rest -= mlen;
 	}
-out:
-
 	return 0;
 }
 
-static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
-				  void (*done)(struct scsi_cmnd *))
-{
-	struct iu_entry	*iue = (struct iu_entry *) sc->SCp.ptr;
-	int err;
-
-	err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
-
-	done(sc);
-
-	return err;
-}
-
 static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
 			     void (*done)(struct scsi_cmnd *))
 {
 	unsigned long flags;
 	struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
 	struct srp_target *target = iue->target;
+	int err = 0;
 
-	dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+	dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+		cmd->usg_sg);
+
+	if (sc->use_sg)
+		err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
 
 	spin_lock_irqsave(&target->lock, flags);
 	list_del(&iue->ilist);
 	spin_unlock_irqrestore(&target->lock, flags);
 
-	if (sc->result != SAM_STAT_GOOD) {
+	if (err|| sc->result != SAM_STAT_GOOD) {
 		eprintk("operation failed %p %d %x\n",
 			iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
 		send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
@@ -503,7 +493,8 @@ static void process_iu(struct viosrp_crq
 {
 	struct vio_port *vport = target_to_port(target);
 	struct iu_entry *iue;
-	long err, done;
+	long err;
+	int done = 1;
 
 	iue = srp_iu_get(target);
 	if (!iue) {
@@ -518,7 +509,6 @@ static void process_iu(struct viosrp_crq
 
 	if (err != H_SUCCESS) {
 		eprintk("%ld transferring data error %p\n", err, iue);
-		done = 1;
 		goto out;
 	}
 
@@ -794,7 +784,6 @@ static struct scsi_host_template ibmvstg
 	.use_clustering		= DISABLE_CLUSTERING,
 	.max_sectors		= DEFAULT_MAX_SECTORS,
 	.transfer_response	= ibmvstgt_cmd_done,
-	.transfer_data		= ibmvstgt_transfer_data,
 	.eh_abort_handler	= ibmvstgt_eh_abort_handler,
 	.tsk_mgmt_response	= ibmvstgt_tsk_mgmt_response,
 	.shost_attrs		= ibmvstgt_attrs,
@@ -897,25 +886,26 @@ static int get_system_info(void)
 {
 	struct device_node *rootdn;
 	const char *id, *model, *name;
-	unsigned int *num;
+	const unsigned int *num;
 
-	rootdn = find_path_device("/");
+	rootdn = of_find_node_by_path("/");
 	if (!rootdn)
 		return -ENOENT;
 
-	model = get_property(rootdn, "model", NULL);
-	id = get_property(rootdn, "system-id", NULL);
+	model = of_get_property(rootdn, "model", NULL);
+	id = of_get_property(rootdn, "system-id", NULL);
 	if (model && id)
 		snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
 
-	name = get_property(rootdn, "ibm,partition-name", NULL);
+	name = of_get_property(rootdn, "ibm,partition-name", NULL);
 	if (name)
 		strncpy(partition_name, name, sizeof(partition_name));
 
-	num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+	num = of_get_property(rootdn, "ibm,partition-no", NULL);
 	if (num)
 		partition_number = *num;
 
+	of_node_put(rootdn);
 	return 0;
 }
 
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 227c0f2..d8700aa 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -157,18 +157,19 @@ static void gather_partition_info(void)
 	const unsigned int *p_number_ptr;
 
 	/* Retrieve information about this partition */
-	rootdn = find_path_device("/");
+	rootdn = of_find_node_by_path("/");
 	if (!rootdn) {
 		return;
 	}
 
-	ppartition_name = get_property(rootdn, "ibm,partition-name", NULL);
+	ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL);
 	if (ppartition_name)
 		strncpy(partition_name, ppartition_name,
 				sizeof(partition_name));
-	p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+	p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
 	if (p_number_ptr)
 		partition_number = *p_number_ptr;
+	of_node_put(rootdn);
 }
 
 static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 95045e3..2c7b77e 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -89,10 +89,9 @@ static unsigned int ipr_log_level = IPR_
 static unsigned int ipr_max_speed = 1;
 static int ipr_testmode = 0;
 static unsigned int ipr_fastfail = 0;
-static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+static unsigned int ipr_transop_timeout = 0;
 static unsigned int ipr_enable_cache = 1;
 static unsigned int ipr_debug = 0;
-static int ipr_auto_create = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
@@ -159,15 +158,13 @@ module_param_named(enable_cache, ipr_ena
 MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
 module_param_named(debug, ipr_debug, int, 0);
 MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
-module_param_named(auto_create, ipr_auto_create, int, 0);
-MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
 /*  A constant array of IOASCs/URCs/Error Messages */
 static const
 struct ipr_error_table_t ipr_error_table[] = {
-	{0x00000000, 1, 1,
+	{0x00000000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"8155: An unknown error was received"},
 	{0x00330000, 0, 0,
 	"Soft underlength error"},
@@ -175,37 +172,37 @@ struct ipr_error_table_t ipr_error_table
 	"Command to be cancelled not found"},
 	{0x00808000, 0, 0,
 	"Qualified success"},
-	{0x01080000, 1, 1,
+	{0x01080000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFFE: Soft device bus error recovered by the IOA"},
-	{0x01088100, 0, 1,
+	{0x01088100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4101: Soft device bus fabric error"},
-	{0x01170600, 0, 1,
+	{0x01170600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF9: Device sector reassign successful"},
-	{0x01170900, 0, 1,
+	{0x01170900, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF7: Media error recovered by device rewrite procedures"},
-	{0x01180200, 0, 1,
+	{0x01180200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"7001: IOA sector reassignment successful"},
-	{0x01180500, 0, 1,
+	{0x01180500, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF9: Soft media error. Sector reassignment recommended"},
-	{0x01180600, 0, 1,
+	{0x01180600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF7: Media error recovered by IOA rewrite procedures"},
-	{0x01418000, 0, 1,
+	{0x01418000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FF3D: Soft PCI bus error recovered by the IOA"},
-	{0x01440000, 1, 1,
+	{0x01440000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFF6: Device hardware error recovered by the IOA"},
-	{0x01448100, 0, 1,
+	{0x01448100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF6: Device hardware error recovered by the device"},
-	{0x01448200, 1, 1,
+	{0x01448200, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FF3D: Soft IOA error recovered by the IOA"},
-	{0x01448300, 0, 1,
+	{0x01448300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFFA: Undefined device response recovered by the IOA"},
-	{0x014A0000, 1, 1,
+	{0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFF6: Device bus error, message or command phase"},
-	{0x014A8000, 0, 1,
+	{0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFFE: Task Management Function failed"},
-	{0x015D0000, 0, 1,
+	{0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF6: Failure prediction threshold exceeded"},
-	{0x015D9200, 0, 1,
+	{0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"8009: Impending cache battery pack failure"},
 	{0x02040400, 0, 0,
 	"34FF: Disk device format in progress"},
@@ -215,85 +212,85 @@ struct ipr_error_table_t ipr_error_table
 	"No ready, IOA shutdown"},
 	{0x025A0000, 0, 0,
 	"Not ready, IOA has been shutdown"},
-	{0x02670100, 0, 1,
+	{0x02670100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3020: Storage subsystem configuration error"},
 	{0x03110B00, 0, 0,
 	"FFF5: Medium error, data unreadable, recommend reassign"},
 	{0x03110C00, 0, 0,
 	"7000: Medium error, data unreadable, do not reassign"},
-	{0x03310000, 0, 1,
+	{0x03310000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF3: Disk media format bad"},
-	{0x04050000, 0, 1,
+	{0x04050000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3002: Addressed device failed to respond to selection"},
-	{0x04080000, 1, 1,
+	{0x04080000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"3100: Device bus error"},
-	{0x04080100, 0, 1,
+	{0x04080100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3109: IOA timed out a device command"},
 	{0x04088000, 0, 0,
 	"3120: SCSI bus is not operational"},
-	{0x04088100, 0, 1,
+	{0x04088100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4100: Hard device bus fabric error"},
-	{0x04118000, 0, 1,
+	{0x04118000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9000: IOA reserved area data check"},
-	{0x04118100, 0, 1,
+	{0x04118100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9001: IOA reserved area invalid data pattern"},
-	{0x04118200, 0, 1,
+	{0x04118200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9002: IOA reserved area LRC error"},
-	{0x04320000, 0, 1,
+	{0x04320000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"102E: Out of alternate sectors for disk storage"},
-	{0x04330000, 1, 1,
+	{0x04330000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFF4: Data transfer underlength error"},
-	{0x04338000, 1, 1,
+	{0x04338000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFF4: Data transfer overlength error"},
-	{0x043E0100, 0, 1,
+	{0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3400: Logical unit failure"},
-	{0x04408500, 0, 1,
+	{0x04408500, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF4: Device microcode is corrupt"},
-	{0x04418000, 1, 1,
+	{0x04418000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"8150: PCI bus error"},
 	{0x04430000, 1, 0,
 	"Unsupported device bus message received"},
-	{0x04440000, 1, 1,
+	{0x04440000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"FFF4: Disk device problem"},
-	{0x04448200, 1, 1,
+	{0x04448200, 1, IPR_DEFAULT_LOG_LEVEL,
 	"8150: Permanent IOA failure"},
-	{0x04448300, 0, 1,
+	{0x04448300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3010: Disk device returned wrong response to IOA"},
-	{0x04448400, 0, 1,
+	{0x04448400, 0, IPR_DEFAULT_LOG_LEVEL,
 	"8151: IOA microcode error"},
 	{0x04448500, 0, 0,
 	"Device bus status error"},
-	{0x04448600, 0, 1,
+	{0x04448600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"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,
+	{0x04449200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"8008: A permanent cache battery pack failure occurred"},
-	{0x0444A000, 0, 1,
+	{0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9090: Disk unit has been modified after the last known status"},
-	{0x0444A200, 0, 1,
+	{0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9081: IOA detected device error"},
-	{0x0444A300, 0, 1,
+	{0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9082: IOA detected device error"},
-	{0x044A0000, 1, 1,
+	{0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"3110: Device bus error, message or command phase"},
-	{0x044A8000, 1, 1,
+	{0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL,
 	"3110: SAS Command / Task Management Function failed"},
-	{0x04670400, 0, 1,
+	{0x04670400, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9091: Incorrect hardware configuration change has been detected"},
-	{0x04678000, 0, 1,
+	{0x04678000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9073: Invalid multi-adapter configuration"},
-	{0x04678100, 0, 1,
+	{0x04678100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4010: Incorrect connection between cascaded expanders"},
-	{0x04678200, 0, 1,
+	{0x04678200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4020: Connections exceed IOA design limits"},
-	{0x04678300, 0, 1,
+	{0x04678300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4030: Incorrect multipath connection"},
-	{0x04679000, 0, 1,
+	{0x04679000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4110: Unsupported enclosure function"},
-	{0x046E0000, 0, 1,
+	{0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFF4: Command to logical unit failed"},
 	{0x05240000, 1, 0,
 	"Illegal request, invalid request type or request packet"},
@@ -313,101 +310,103 @@ struct ipr_error_table_t ipr_error_table
 	"Illegal request, command sequence error"},
 	{0x052C8000, 1, 0,
 	"Illegal request, dual adapter support not enabled"},
-	{0x06040500, 0, 1,
+	{0x06040500, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9031: Array protection temporarily suspended, protection resuming"},
-	{0x06040600, 0, 1,
+	{0x06040600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9040: Array protection temporarily suspended, protection resuming"},
-	{0x06288000, 0, 1,
+	{0x06288000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3140: Device bus not ready to ready transition"},
-	{0x06290000, 0, 1,
+	{0x06290000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFFB: SCSI bus was reset"},
 	{0x06290500, 0, 0,
 	"FFFE: SCSI bus transition to single ended"},
 	{0x06290600, 0, 0,
 	"FFFE: SCSI bus transition to LVD"},
-	{0x06298000, 0, 1,
+	{0x06298000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"FFFB: SCSI bus was reset by another initiator"},
-	{0x063F0300, 0, 1,
+	{0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3029: A device replacement has occurred"},
-	{0x064C8000, 0, 1,
+	{0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9051: IOA cache data exists for a missing or failed device"},
-	{0x064C8100, 0, 1,
+	{0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9055: Auxiliary cache IOA contains cache data needed by the primary IOA"},
-	{0x06670100, 0, 1,
+	{0x06670100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9025: Disk unit is not supported at its physical location"},
-	{0x06670600, 0, 1,
+	{0x06670600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3020: IOA detected a SCSI bus configuration error"},
-	{0x06678000, 0, 1,
+	{0x06678000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"3150: SCSI bus configuration error"},
-	{0x06678100, 0, 1,
+	{0x06678100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9074: Asymmetric advanced function disk configuration"},
-	{0x06678300, 0, 1,
+	{0x06678300, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4040: Incomplete multipath connection between IOA and enclosure"},
-	{0x06678400, 0, 1,
+	{0x06678400, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4041: Incomplete multipath connection between enclosure and device"},
-	{0x06678500, 0, 1,
+	{0x06678500, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9075: Incomplete multipath connection between IOA and remote IOA"},
-	{0x06678600, 0, 1,
+	{0x06678600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9076: Configuration error, missing remote IOA"},
-	{0x06679100, 0, 1,
+	{0x06679100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4050: Enclosure does not support a required multipath function"},
-	{0x06690200, 0, 1,
+	{0x06690200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9041: Array protection temporarily suspended"},
-	{0x06698200, 0, 1,
+	{0x06698200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9042: Corrupt array parity detected on specified device"},
-	{0x066B0200, 0, 1,
+	{0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9030: Array no longer protected due to missing or failed disk unit"},
-	{0x066B8000, 0, 1,
+	{0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9071: Link operational transition"},
-	{0x066B8100, 0, 1,
+	{0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9072: Link not operational transition"},
-	{0x066B8200, 0, 1,
+	{0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9032: Array exposed but still protected"},
-	{0x066B9100, 0, 1,
+	{0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1,
+	"70DD: Device forced failed by disrupt device command"},
+	{0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4061: Multipath redundancy level got better"},
-	{0x066B9200, 0, 1,
+	{0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"4060: Multipath redundancy level got worse"},
 	{0x07270000, 0, 0,
 	"Failure due to other device"},
-	{0x07278000, 0, 1,
+	{0x07278000, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9008: IOA does not support functions expected by devices"},
-	{0x07278100, 0, 1,
+	{0x07278100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9010: Cache data associated with attached devices cannot be found"},
-	{0x07278200, 0, 1,
+	{0x07278200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9011: Cache data belongs to devices other than those attached"},
-	{0x07278400, 0, 1,
+	{0x07278400, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9020: Array missing 2 or more devices with only 1 device present"},
-	{0x07278500, 0, 1,
+	{0x07278500, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9021: Array missing 2 or more devices with 2 or more devices present"},
-	{0x07278600, 0, 1,
+	{0x07278600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9022: Exposed array is missing a required device"},
-	{0x07278700, 0, 1,
+	{0x07278700, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9023: Array member(s) not at required physical locations"},
-	{0x07278800, 0, 1,
+	{0x07278800, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9024: Array not functional due to present hardware configuration"},
-	{0x07278900, 0, 1,
+	{0x07278900, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9026: Array not functional due to present hardware configuration"},
-	{0x07278A00, 0, 1,
+	{0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9027: Array is missing a device and parity is out of sync"},
-	{0x07278B00, 0, 1,
+	{0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9028: Maximum number of arrays already exist"},
-	{0x07278C00, 0, 1,
+	{0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9050: Required cache data cannot be located for a disk unit"},
-	{0x07278D00, 0, 1,
+	{0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9052: Cache data exists for a device that has been modified"},
-	{0x07278F00, 0, 1,
+	{0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9054: IOA resources not available due to previous problems"},
-	{0x07279100, 0, 1,
+	{0x07279100, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9092: Disk unit requires initialization before use"},
-	{0x07279200, 0, 1,
+	{0x07279200, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9029: Incorrect hardware configuration change has been detected"},
-	{0x07279600, 0, 1,
+	{0x07279600, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9060: One or more disk pairs are missing from an array"},
-	{0x07279700, 0, 1,
+	{0x07279700, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9061: One or more disks are missing from an array"},
-	{0x07279800, 0, 1,
+	{0x07279800, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9062: One or more disks are missing from an array"},
-	{0x07279900, 0, 1,
+	{0x07279900, 0, IPR_DEFAULT_LOG_LEVEL,
 	"9063: Maximum number of functional arrays has been exceeded"},
 	{0x0B260000, 0, 0,
 	"Aborted command, invalid descriptor"},
@@ -481,12 +480,16 @@ static void ipr_reinit_ipr_cmnd(struct i
 {
 	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
 	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+	dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
 
 	memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
 	ioarcb->write_data_transfer_length = 0;
 	ioarcb->read_data_transfer_length = 0;
 	ioarcb->write_ioadl_len = 0;
 	ioarcb->read_ioadl_len = 0;
+	ioarcb->write_ioadl_addr =
+		cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+	ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
 	ioasa->ioasc = 0;
 	ioasa->residual_data_len = 0;
 	ioasa->u.gata.status = 0;
@@ -1610,7 +1613,7 @@ static void ipr_handle_log_data(struct i
 	/* Set indication we have logged an error */
 	ioa_cfg->errors_logged++;
 
-	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
+	if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam)
 		return;
 	if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw))
 		hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw));
@@ -3770,7 +3773,8 @@ static int ipr_device_reset(struct ipr_i
  * Return value:
  *	0 on success / non-zero on failure
  **/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+				unsigned long deadline)
 {
 	struct ipr_sata_port *sata_port = ap->private_data;
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
@@ -3849,6 +3853,8 @@ static int __ipr_eh_dev_reset(struct scs
 		if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
 			if (ipr_cmd->scsi_cmd)
 				ipr_cmd->done = ipr_scsi_eh_done;
+			if (ipr_cmd->qc)
+				ipr_cmd->done = ipr_sata_eh_done;
 			if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
 				ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
 				ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
@@ -4229,6 +4235,14 @@ static int ipr_build_ioadl(struct ipr_io
 
 		sglist = scsi_cmd->request_buffer;
 
+		if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
+			ioadl = ioarcb->add_data.u.ioadl;
+			ioarcb->write_ioadl_addr =
+				cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+					    offsetof(struct ipr_ioarcb, add_data));
+			ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+		}
+
 		for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
 			ioadl[i].flags_and_data_len =
 				cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
@@ -4259,6 +4273,11 @@ static int ipr_build_ioadl(struct ipr_io
 						     scsi_cmd->sc_data_direction);
 
 		if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
+			ioadl = ioarcb->add_data.u.ioadl;
+			ioarcb->write_ioadl_addr =
+				cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+					    offsetof(struct ipr_ioarcb, add_data));
+			ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
 			ipr_cmd->dma_use_sg = 1;
 			ioadl[0].flags_and_data_len =
 				cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
@@ -4345,11 +4364,9 @@ static void ipr_erp_done(struct ipr_cmnd
  **/
 static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
 {
-	struct ipr_ioarcb *ioarcb;
-	struct ipr_ioasa *ioasa;
-
-	ioarcb = &ipr_cmd->ioarcb;
-	ioasa = &ipr_cmd->ioasa;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+	dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
 
 	memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
 	ioarcb->write_data_transfer_length = 0;
@@ -4358,6 +4375,9 @@ static void ipr_reinit_ipr_cmnd_for_erp(
 	ioarcb->read_ioadl_len = 0;
 	ioasa->ioasc = 0;
 	ioasa->residual_data_len = 0;
+	ioarcb->write_ioadl_addr =
+		cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+	ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
 }
 
 /**
@@ -4456,12 +4476,13 @@ static void ipr_dump_ioasa(struct ipr_io
 {
 	int i;
 	u16 data_len;
-	u32 ioasc;
+	u32 ioasc, fd_ioasc;
 	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
 	__be32 *ioasa_data = (__be32 *)ioasa;
 	int error_index;
 
 	ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
+	fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK;
 
 	if (0 == ioasc)
 		return;
@@ -4469,13 +4490,19 @@ static void ipr_dump_ioasa(struct ipr_io
 	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
 		return;
 
-	error_index = ipr_get_error(ioasc);
+	if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc)
+		error_index = ipr_get_error(fd_ioasc);
+	else
+		error_index = ipr_get_error(ioasc);
 
 	if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) {
 		/* Don't log an error if the IOA already logged one */
 		if (ioasa->ilid != 0)
 			return;
 
+		if (!ipr_is_gscsi(res))
+			return;
+
 		if (ipr_error_table[error_index].log_ioasa == 0)
 			return;
 	}
@@ -4635,11 +4662,11 @@ static void ipr_erp_start(struct ipr_ioa
 		return;
 	}
 
-	if (ipr_is_gscsi(res))
-		ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
-	else
+	if (!ipr_is_gscsi(res))
 		ipr_gen_sense(ipr_cmd);
 
+	ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+
 	switch (ioasc & IPR_IOASC_IOASC_MASK) {
 	case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
 		if (ipr_is_naca_model(res))
@@ -5120,7 +5147,7 @@ static unsigned int ipr_qc_issue(struct 
 	struct ipr_ioarcb_ata_regs *regs;
 
 	if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
-		return -EIO;
+		return AC_ERR_SYSTEM;
 
 	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
 	ioarcb = &ipr_cmd->ioarcb;
@@ -5165,7 +5192,7 @@ static unsigned int ipr_qc_issue(struct 
 
 	default:
 		WARN_ON(1);
-		return -1;
+		return AC_ERR_INVALID;
 	}
 
 	mb();
@@ -6187,7 +6214,7 @@ static int ipr_reset_enable_ioa(struct i
 	dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
 
 	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
-	ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ);
+	ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
 	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
 	ipr_cmd->done = ipr_reset_ioa_job;
 	add_timer(&ipr_cmd->timer);
@@ -6384,6 +6411,7 @@ static int ipr_reset_start_bist(struct i
 	rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
 
 	if (rc != PCIBIOS_SUCCESSFUL) {
+		pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
 		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
 		rc = IPR_RC_JOB_CONTINUE;
 	} else {
@@ -7116,8 +7144,6 @@ static void __devinit ipr_init_ioa_cfg(s
 	ioa_cfg->pdev = pdev;
 	ioa_cfg->log_level = ipr_log_level;
 	ioa_cfg->doorbell = IPR_DOORBELL;
-	if (!ipr_auto_create)
-		ioa_cfg->doorbell |= IPR_RUNTIME_RESET;
 	sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
 	sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
 	sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
@@ -7232,6 +7258,13 @@ static int __devinit ipr_probe_ioa(struc
 		goto out_scsi_host_put;
 	}
 
+	if (ipr_transop_timeout)
+		ioa_cfg->transop_timeout = ipr_transop_timeout;
+	else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT)
+		ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT;
+	else
+		ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+
 	ipr_regs_pci = pci_resource_start(pdev, 0);
 
 	rc = pci_request_regions(pdev, IPR_NAME);
@@ -7539,29 +7572,45 @@ static struct pci_device_id ipr_pci_tabl
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 },
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0,
+		IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
 	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
-	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 },
+	      PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
+	      IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 },
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0,
+		IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
-		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 },
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0,
+		IPR_USE_LONG_TRANSOP_TIMEOUT },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0,
+		IPR_USE_LONG_TRANSOP_TIMEOUT },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 88f285d..bc53d7c 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -37,8 +37,8 @@ #include <scsi/scsi_cmnd.h>
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.3.1"
-#define IPR_DRIVER_DATE "(January 23, 2007)"
+#define IPR_DRIVER_VERSION "2.3.2"
+#define IPR_DRIVER_DATE "(March 23, 2007)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -55,6 +55,7 @@ #define IPR_MAX_CMD_PER_ATA_LUN			1
 #define IPR_NUM_BASE_CMD_BLKS				100
 
 #define PCI_DEVICE_ID_IBM_OBSIDIAN_E	0x0339
+#define PCI_DEVICE_ID_IBM_SCAMP_E		0x034A
 
 #define IPR_SUBS_DEV_ID_2780	0x0264
 #define IPR_SUBS_DEV_ID_5702	0x0266
@@ -69,8 +70,12 @@ #define IPR_SUBS_DEV_ID_571F	0x02D5
 #define IPR_SUBS_DEV_ID_572A	0x02C1
 #define IPR_SUBS_DEV_ID_572B	0x02C2
 #define IPR_SUBS_DEV_ID_572F	0x02C3
+#define IPR_SUBS_DEV_ID_574D	0x030B
+#define IPR_SUBS_DEV_ID_574E	0x030A
 #define IPR_SUBS_DEV_ID_575B	0x030D
 #define IPR_SUBS_DEV_ID_575C	0x0338
+#define IPR_SUBS_DEV_ID_575D	0x033E
+#define IPR_SUBS_DEV_ID_57B3	0x033A
 #define IPR_SUBS_DEV_ID_57B7	0x0360
 #define IPR_SUBS_DEV_ID_57B8	0x02C2
 
@@ -104,6 +109,9 @@ #define IPR_FIRST_DRIVER_IOASC			0x10000
 #define IPR_IOASC_IOA_WAS_RESET			0x10000001
 #define IPR_IOASC_PCI_ACCESS_ERROR			0x10000002
 
+/* Driver data flags */
+#define IPR_USE_LONG_TRANSOP_TIMEOUT		0x00000001
+
 #define IPR_DEFAULT_MAX_ERROR_DUMP			984
 #define IPR_NUM_LOG_HCAMS				2
 #define IPR_NUM_CFG_CHG_HCAMS				2
@@ -179,6 +187,7 @@ #define IPR_WRITE_BUFFER_TIMEOUT		(10 * 
 #define IPR_SET_SUP_DEVICE_TIMEOUT		(2 * 60 * HZ)
 #define IPR_REQUEST_SENSE_TIMEOUT		(10 * HZ)
 #define IPR_OPERATIONAL_TIMEOUT		(5 * 60)
+#define IPR_LONG_OPERATIONAL_TIMEOUT	(12 * 60)
 #define IPR_WAIT_FOR_RESET_TIMEOUT		(2 * HZ)
 #define IPR_CHECK_FOR_RESET_TIMEOUT		(HZ / 10)
 #define IPR_WAIT_FOR_BIST_TIMEOUT		(2 * HZ)
@@ -413,9 +422,25 @@ #define IPR_ATA_FLAG_STATUS_ON_GOOD_COMP
 	u8 ctl;
 }__attribute__ ((packed, aligned(4)));
 
+struct ipr_ioadl_desc {
+	__be32 flags_and_data_len;
+#define IPR_IOADL_FLAGS_MASK		0xff000000
+#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
+#define IPR_IOADL_DATA_LEN_MASK		0x00ffffff
+#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
+#define IPR_IOADL_FLAGS_READ		0x48000000
+#define IPR_IOADL_FLAGS_READ_LAST	0x49000000
+#define IPR_IOADL_FLAGS_WRITE		0x68000000
+#define IPR_IOADL_FLAGS_WRITE_LAST	0x69000000
+#define IPR_IOADL_FLAGS_LAST		0x01000000
+
+	__be32 address;
+}__attribute__((packed, aligned (8)));
+
 struct ipr_ioarcb_add_data {
 	union {
 		struct ipr_ioarcb_ata_regs regs;
+		struct ipr_ioadl_desc ioadl[5];
 		__be32 add_cmd_parms[10];
 	}u;
 }__attribute__ ((packed, aligned(4)));
@@ -447,21 +472,6 @@ struct ipr_ioarcb {
 	struct ipr_ioarcb_add_data add_data;
 }__attribute__((packed, aligned (4)));
 
-struct ipr_ioadl_desc {
-	__be32 flags_and_data_len;
-#define IPR_IOADL_FLAGS_MASK		0xff000000
-#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
-#define IPR_IOADL_DATA_LEN_MASK		0x00ffffff
-#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
-#define IPR_IOADL_FLAGS_READ		0x48000000
-#define IPR_IOADL_FLAGS_READ_LAST	0x49000000
-#define IPR_IOADL_FLAGS_WRITE		0x68000000
-#define IPR_IOADL_FLAGS_WRITE_LAST	0x69000000
-#define IPR_IOADL_FLAGS_LAST		0x01000000
-
-	__be32 address;
-}__attribute__((packed, aligned (8)));
-
 struct ipr_ioasa_vset {
 	__be32 failing_lba_hi;
 	__be32 failing_lba_lo;
@@ -1119,6 +1129,7 @@ #define IPR_HRRQ_REQ_RESP_HANDLE_SHIFT	2
 
 	struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
 
+	unsigned int transop_timeout;
 	const struct ipr_chip_cfg_t *chip_cfg;
 
 	void __iomem *hdw_dma_regs;	/* iomapped PCI memory space */
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 8f55e14..c9a3abf 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -527,12 +527,12 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co
 		 * than 8K, but there are no targets that currently do this.
 		 * For now we fail until we find a vendor that needs it
 		 */
-		if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
+		if (ISCSI_DEF_MAX_RECV_SEG_LEN <
 		    tcp_conn->in.datalen) {
 			printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
 			      "but conn buffer is only %u (opcode %0x)\n",
 			      tcp_conn->in.datalen,
-			      DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
+			      ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
 			rc = ISCSI_ERR_PROTO;
 			break;
 		}
@@ -1762,7 +1762,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_s
 	 * due to strange issues with iser these are not set
 	 * in iscsi_conn_setup
 	 */
-	conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+	conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
 
 	tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);
 	if (!tcp_conn)
@@ -1777,14 +1777,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_s
 	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 						  CRYPTO_ALG_ASYNC);
 	tcp_conn->tx_hash.flags = 0;
-	if (IS_ERR(tcp_conn->tx_hash.tfm))
+	if (IS_ERR(tcp_conn->tx_hash.tfm)) {
+		printk(KERN_ERR "Could not create connection due to crc32c "
+		       "loading error %ld. Make sure the crc32c module is "
+		       "built as a module or into the kernel\n",
+			PTR_ERR(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 (IS_ERR(tcp_conn->rx_hash.tfm))
+	if (IS_ERR(tcp_conn->rx_hash.tfm)) {
+		printk(KERN_ERR "Could not create connection due to crc32c "
+		       "loading error %ld. Make sure the crc32c module is "
+		       "built as a module or into the kernel\n",
+			PTR_ERR(tcp_conn->rx_hash.tfm));
 		goto free_tx_tfm;
+	}
 
 	return cls_conn;
 
@@ -2138,6 +2148,7 @@ static struct scsi_host_template iscsi_s
 	.change_queue_depth	= iscsi_change_queue_depth,
 	.can_queue		= ISCSI_XMIT_CMDS_MAX - 1,
 	.sg_tablesize		= ISCSI_SG_TABLESIZE,
+	.max_sectors		= 0xFFFF,
 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
 	.eh_abort_handler       = iscsi_eh_abort,
 	.eh_host_reset_handler	= iscsi_eh_host_reset,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 7c75771..3f5b9b4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -25,6 +25,7 @@ #include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/kfifo.h>
 #include <linux/delay.h>
+#include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -269,14 +270,14 @@ invalid_datalen:
 			goto out;
 		}
 
-		senselen = be16_to_cpu(*(__be16 *)data);
+		senselen = be16_to_cpu(get_unaligned((__be16 *) data));
 		if (datalen < senselen)
 			goto invalid_datalen;
 
 		memcpy(sc->sense_buffer, data + 2,
 		       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
 		debug_scsi("copied %d bytes of sense\n",
-			   min(senselen, SCSI_SENSE_BUFFERSIZE));
+			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
 	}
 
 	if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -577,7 +578,7 @@ void iscsi_conn_failure(struct iscsi_con
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 
-static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 {
 	struct iscsi_hdr *hdr = conn->mtask->hdr;
 	int rc, was_logout = 0;
@@ -591,6 +592,9 @@ static int iscsi_xmit_imm_task(struct is
 	if (rc)
 		return rc;
 
+	/* done with this in-progress mtask */
+	conn->mtask = NULL;
+
 	if (was_logout) {
 		set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
 		return -ENODATA;
@@ -643,11 +647,9 @@ static int iscsi_data_xmit(struct iscsi_
 		conn->ctask = NULL;
 	}
 	if (conn->mtask) {
-		rc = iscsi_xmit_imm_task(conn);
+		rc = iscsi_xmit_mtask(conn);
 	        if (rc)
 		        goto again;
-		/* done with this in-progress mtask */
-		conn->mtask = NULL;
 	}
 
 	/* process immediate first */
@@ -658,12 +660,10 @@ static int iscsi_data_xmit(struct iscsi_
 			list_add_tail(&conn->mtask->running,
 				      &conn->mgmt_run_list);
 			spin_unlock_bh(&conn->session->lock);
-			rc = iscsi_xmit_imm_task(conn);
+			rc = iscsi_xmit_mtask(conn);
 		        if (rc)
 			        goto again;
 	        }
-		/* done with this mtask */
-		conn->mtask = NULL;
 	}
 
 	/* process command queue */
@@ -701,12 +701,10 @@ 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);
-			if (rc)
+			rc = iscsi_xmit_mtask(conn);
+		        if (rc)
 			        goto again;
 	        }
-		/* done with this mtask */
-		conn->mtask = NULL;
 	}
 
 	return -ENODATA;
@@ -1523,7 +1521,7 @@ iscsi_conn_setup(struct iscsi_cls_sessio
 	}
 	spin_unlock_bh(&session->lock);
 
-	data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
+	data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
 	if (!data)
 		goto login_mtask_data_alloc_fail;
 	conn->login_mtask->data = conn->data = data;
@@ -1597,6 +1595,9 @@ void iscsi_conn_teardown(struct iscsi_cl
 		wake_up(&conn->ehwait);
 	}
 
+	/* flush queued up work because we free the connection below */
+	scsi_flush_work(session->host);
+
 	spin_lock_bh(&session->lock);
 	kfree(conn->data);
 	kfree(conn->persistent_address);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index dc70c18..e34442e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -22,7 +22,6 @@
  *
  */
 
-#include <linux/pci.h>
 #include <linux/scatterlist.h>
 
 #include "sas_internal.h"
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 89403b0..5631c19 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -22,7 +22,6 @@ #include <linux/err.h>
 #include <linux/kfifo.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
-#include <linux/pci.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_tcq.h>
@@ -225,8 +224,7 @@ static int srp_indirect_data(struct scsi
 	struct srp_direct_buf *md = NULL;
 	struct scatterlist dummy, *sg = NULL;
 	dma_addr_t token = 0;
-	long err;
-	unsigned int done = 0;
+	int err = 0;
 	int nmd, nsg = 0, len;
 
 	if (dma_map || ext_desc) {
@@ -258,8 +256,8 @@ static int srp_indirect_data(struct scsi
 		sg_dma_address(&dummy) = token;
 		err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
 			      id->table_desc.len);
-		if (err < 0) {
-			eprintk("Error copying indirect table %ld\n", err);
+		if (err) {
+			eprintk("Error copying indirect table %d\n", err);
 			goto free_mem;
 		}
 	} else {
@@ -272,6 +270,7 @@ rdma:
 		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
 		if (!nsg) {
 			eprintk("fail to map %p %d\n", iue, sc->use_sg);
+			err = -EIO;
 			goto free_mem;
 		}
 		len = min(sc->request_bufflen, id->len);
@@ -287,7 +286,7 @@ free_mem:
 	if (token && dma_map)
 		dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
 
-	return done;
+	return err;
 }
 
 static int data_out_desc_size(struct srp_cmd *cmd)
@@ -352,7 +351,7 @@ int srp_transfer_data(struct scsi_cmnd *
 		break;
 	default:
 		eprintk("Unknown format %d %x\n", dir, format);
-		break;
+		err = -EINVAL;
 	}
 
 	return err;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 057fd7e..dcf6106 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -671,7 +671,7 @@ static int
 lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
 {
 	uint8_t lenlo, lenhi;
-	uint32_t Length;
+	int Length;
 	int i, j;
 	int finished = 0;
 	int index = 0;
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 753d883..5806ede 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -471,7 +471,7 @@ static int mac53c94_probe(struct macio_d
 		goto out_free;
 	}
 
-       	clkprop = get_property(node, "clock-frequency", &proplen);
+	clkprop = of_get_property(node, "clock-frequency", &proplen);
        	if (clkprop == NULL || proplen != sizeof(int)) {
        		printk(KERN_ERR "%s: can't get clock frequency, "
        		       "assuming 25MHz\n", node->full_name);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 0aa3304..7fc6e06 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -2088,7 +2088,7 @@ megaraid_abort_and_reset(adapter_t *adap
 static inline int
 make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
 {
-	*pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	*pdev = alloc_pci_dev();
 
 	if( *pdev == NULL ) return -1;
 
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 1fd3c75..cf3666d 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1947,7 +1947,7 @@ #endif
 	       	ms->tgts[tgt].current_req = NULL;
        	}
 
-	if ((cfp = get_property(mesh, "clock-frequency", NULL)))
+	if ((cfp = of_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/osst.c b/drivers/scsi/osst.c
index a967fad..08060fb 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -87,6 +87,7 @@ MODULE_AUTHOR("Willem Riede");
 MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
 
 module_param(max_dev, int, 0444);
 MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
deleted file mode 100644
index 0ebd8ce..0000000
--- a/drivers/scsi/pci2000.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
- * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
- *
- * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
- *
- * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * Technical updates and product information at:
- *  http://www.psidisk.com
- *
- * Please send questions, comments, bug reports to:
- *  tech@psidisk.com Technical Support
- *
- ****************************************************************************/
-#ifndef _PCI2000_H
-#define _PCI2000_H
-
-#include <linux/types.h>
-
-#ifndef	PSI_EIDE_SCSIOP
-#define	PSI_EIDE_SCSIOP	1
-
-#define	LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
-
-/************************************************/
-/*		definition of standard data types		*/
-/************************************************/
-#define	CHAR	char
-#define	UCHAR	unsigned char
-#define	SHORT	short
-#define	USHORT	unsigned short
-#define	BOOL	long
-#define	LONG	long
-#define	ULONG	unsigned long
-#define	VOID	void
-
-typedef	CHAR	*PCHAR;
-typedef	UCHAR	*PUCHAR;
-typedef	SHORT	*PSHORT;
-typedef	USHORT	*PUSHORT;
-typedef	BOOL	*PBOOL;
-typedef	LONG	*PLONG;
-typedef	ULONG	*PULONG;
-typedef	VOID	*PVOID;
-
-
-/************************************************/
-/*		Misc. macros			 				*/
-/************************************************/
-#define ANY2SCSI(up, p)					\
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up)					\
-( (((long)*(((UCHAR *)up))) << 16)		\
-+ (((long)(((UCHAR *)up)[1])) << 8)		\
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p)				\
-((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
-((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
-((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up)					\
-( (((long)(((UCHAR *)up)[0])) << 24)	\
-+ (((long)(((UCHAR *)up)[1])) << 16)	\
-+ (((long)(((UCHAR *)up)[2])) <<  8)	\
-+ ((long)(((UCHAR *)up)[3])) )
-
-/************************************************/
-/*		SCSI CDB operation codes 				*/
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY		0x00
-#define SCSIOP_REZERO_UNIT			0x01
-#define SCSIOP_REWIND				0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
-#define SCSIOP_REQUEST_SENSE		0x03
-#define SCSIOP_FORMAT_UNIT			0x04
-#define SCSIOP_READ_BLOCK_LIMITS	0x05
-#define SCSIOP_REASSIGN_BLOCKS		0x07
-#define SCSIOP_READ6				0x08
-#define SCSIOP_RECEIVE				0x08
-#define SCSIOP_WRITE6				0x0A
-#define SCSIOP_PRINT				0x0A
-#define SCSIOP_SEND					0x0A
-#define SCSIOP_SEEK6				0x0B
-#define SCSIOP_TRACK_SELECT			0x0B
-#define SCSIOP_SLEW_PRINT			0x0B
-#define SCSIOP_SEEK_BLOCK			0x0C
-#define SCSIOP_PARTITION			0x0D
-#define SCSIOP_READ_REVERSE			0x0F
-#define SCSIOP_WRITE_FILEMARKS		0x10
-#define SCSIOP_FLUSH_BUFFER			0x10
-#define SCSIOP_SPACE				0x11
-#define SCSIOP_INQUIRY				0x12
-#define SCSIOP_VERIFY6				0x13
-#define SCSIOP_RECOVER_BUF_DATA		0x14
-#define SCSIOP_MODE_SELECT			0x15
-#define SCSIOP_RESERVE_UNIT			0x16
-#define SCSIOP_RELEASE_UNIT			0x17
-#define SCSIOP_COPY					0x18
-#define SCSIOP_ERASE				0x19
-#define SCSIOP_MODE_SENSE			0x1A
-#define SCSIOP_START_STOP_UNIT		0x1B
-#define SCSIOP_STOP_PRINT			0x1B
-#define SCSIOP_LOAD_UNLOAD			0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
-#define SCSIOP_SEND_DIAGNOSTIC		0x1D
-#define SCSIOP_MEDIUM_REMOVAL		0x1E
-#define SCSIOP_READ_CAPACITY		0x25
-#define SCSIOP_READ					0x28
-#define SCSIOP_WRITE				0x2A
-#define SCSIOP_SEEK					0x2B
-#define SCSIOP_LOCATE				0x2B
-#define SCSIOP_WRITE_VERIFY			0x2E
-#define SCSIOP_VERIFY				0x2F
-#define SCSIOP_SEARCH_DATA_HIGH		0x30
-#define SCSIOP_SEARCH_DATA_EQUAL	0x31
-#define SCSIOP_SEARCH_DATA_LOW		0x32
-#define SCSIOP_SET_LIMITS			0x33
-#define SCSIOP_READ_POSITION		0x34
-#define SCSIOP_SYNCHRONIZE_CACHE	0x35
-#define SCSIOP_COMPARE				0x39
-#define SCSIOP_COPY_COMPARE			0x3A
-#define SCSIOP_WRITE_DATA_BUFF		0x3B
-#define SCSIOP_READ_DATA_BUFF		0x3C
-#define SCSIOP_CHANGE_DEFINITION	0x40
-#define SCSIOP_READ_SUB_CHANNEL		0x42
-#define SCSIOP_READ_TOC				0x43
-#define SCSIOP_READ_HEADER			0x44
-#define SCSIOP_PLAY_AUDIO			0x45
-#define SCSIOP_PLAY_AUDIO_MSF		0x47
-#define SCSIOP_PLAY_TRACK_INDEX		0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
-#define SCSIOP_PAUSE_RESUME			0x4B
-#define SCSIOP_LOG_SELECT			0x4C
-#define SCSIOP_LOG_SENSE			0x4D
-#define SCSIOP_MODE_SELECT10		0x55
-#define SCSIOP_MODE_SENSE10			0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
-#define SCSIOP_MECHANISM_STATUS		0xBD
-#define SCSIOP_READ_CD				0xBE
-
-// SCSI read capacity structure
-typedef	struct _READ_CAPACITY_DATA
-	{
-	ULONG blks;				/* total blocks (converted to little endian) */
-	ULONG blksiz;			/* size of each (converted to little endian) */
-	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
-	{
-	UCHAR DeviceType			:5;
-	UCHAR DeviceTypeQualifier	:3;
-	UCHAR DeviceTypeModifier	:7;
-	UCHAR RemovableMedia		:1;
-    UCHAR Versions;
-    UCHAR ResponseDataFormat;
-    UCHAR AdditionalLength;
-    UCHAR Reserved[2];
-	UCHAR SoftReset				:1;
-	UCHAR CommandQueue			:1;
-	UCHAR Reserved2				:1;
-	UCHAR LinkedCommands		:1;
-	UCHAR Synchronous			:1;
-	UCHAR Wide16Bit				:1;
-	UCHAR Wide32Bit				:1;
-	UCHAR RelativeAddressing	:1;
-    UCHAR VendorId[8];
-    UCHAR ProductId[16];
-    UCHAR ProductRevisionLevel[4];
-    UCHAR VendorSpecific[20];
-    UCHAR Reserved3[40];
-	}	INQUIRYDATA, *PINQUIRYDATA;
-
-#endif
-
-// function prototypes
-int Pci2000_Detect			(struct scsi_host_template *tpnt);
-int Pci2000_Command			(Scsi_Cmnd *SCpnt);
-int Pci2000_QueueCommand	(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-int Pci2000_Abort			(Scsi_Cmnd *SCpnt);
-int Pci2000_Reset			(Scsi_Cmnd *SCpnt, unsigned int flags);
-int Pci2000_Release			(struct Scsi_Host *pshost);
-int Pci2000_BiosParam		(struct scsi_device *sdev,
-					struct block_device *bdev,
-					sector_t capacity, int geom[]);
-
-#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index eac8e17..7dd787f 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -3,11 +3,11 @@ # PCMCIA SCSI adapter configuration
 #
 
 menu "PCMCIA SCSI adapter support"
-	depends on SCSI!=n && PCMCIA!=n && MODULES
+	depends on SCSI!=n && PCMCIA!=n
 
 config PCMCIA_AHA152X
 	tristate "Adaptec AHA152X PCMCIA support"
-	depends on m && !64BIT
+	depends on !64BIT
 	select SCSI_SPI_ATTRS
 	help
 	  Say Y here if you intend to attach this type of PCMCIA SCSI host
@@ -18,7 +18,6 @@ config PCMCIA_AHA152X
 
 config PCMCIA_FDOMAIN
 	tristate "Future Domain PCMCIA support"
-	depends on m
 	help
 	  Say Y here if you intend to attach this type of PCMCIA SCSI host
 	  adapter to your computer.
@@ -28,7 +27,7 @@ config PCMCIA_FDOMAIN
 
 config PCMCIA_NINJA_SCSI
 	tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
-	depends on m && !64BIT
+	depends on !64BIT
 	help
 	  If you intend to attach this type of PCMCIA SCSI host adapter to
 	  your computer, say Y here and read
@@ -62,7 +61,6 @@ config PCMCIA_NINJA_SCSI
 
 config PCMCIA_QLOGIC
 	tristate "Qlogic PCMCIA support"
-	depends on m
 	help
 	  Say Y here if you intend to attach this type of PCMCIA SCSI host
 	  adapter to your computer.
@@ -72,7 +70,6 @@ config PCMCIA_QLOGIC
 
 config PCMCIA_SYM53C500
 	tristate "Symbios 53c500 PCMCIA support"
-	depends on m
 	help
 	  Say Y here if you have a New Media Bus Toaster or other PCMCIA
 	  SCSI adapter based on the Symbios 53c500 controller.
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 05f4f2a..e8948b6 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1478,14 +1478,17 @@ typedef union {
 	uint32_t b24 : 24;
 
 	struct {
-		uint8_t d_id[3];
-		uint8_t rsvd_1;
-	} r;
-
-	struct {
+#ifdef __BIG_ENDIAN
+		uint8_t domain;
+		uint8_t area;
+		uint8_t al_pa;
+#elif __LITTLE_ENDIAN
 		uint8_t al_pa;
 		uint8_t area;
 		uint8_t domain;
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!"
+#endif
 		uint8_t rsvd_1;
 	} b;
 } port_id_t;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 98c01cd..3e296ab 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -11,6 +11,11 @@ #include <linux/vmalloc.h>
 
 #include "qla_devtbl.h"
 
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
+#include <asm/pbm.h>
+#endif
+
 /* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
 #ifndef EXT_IS_LUN_BIT_SET
 #define EXT_IS_LUN_BIT_SET(P,L) \
@@ -88,12 +93,7 @@ qla2x00_initialize_adapter(scsi_qla_host
 
 	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
 
-	rval = ha->isp_ops.nvram_config(ha);
-	if (rval) {
-		DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n",
-		    ha->host_no));
-		return rval;
-	}
+	ha->isp_ops.nvram_config(ha);
 
 	if (ha->flags.disable_serdes) {
 		/* Mask HBA via NVRAM settings? */
@@ -1393,6 +1393,28 @@ qla2x00_set_model_info(scsi_qla_host_t *
 	}
 }
 
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
+{
+#ifdef CONFIG_SPARC
+	struct pci_dev *pdev = ha->pdev;
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	struct device_node *dp = pcp->prom_node;
+	u8 *val;
+	int len;
+
+	val = of_get_property(dp, "port-wwn", &len);
+	if (val && len >= WWN_SIZE)
+		memcpy(nv->port_name, val, WWN_SIZE);
+
+	val = of_get_property(dp, "node-wwn", &len);
+	if (val && len >= WWN_SIZE)
+		memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
 /*
 * NVRAM configuration for ISP 2xxx
 *
@@ -1409,6 +1431,7 @@ qla2x00_set_model_info(scsi_qla_host_t *
 int
 qla2x00_nvram_config(scsi_qla_host_t *ha)
 {
+	int             rval;
 	uint8_t         chksum = 0;
 	uint16_t        cnt;
 	uint8_t         *dptr1, *dptr2;
@@ -1417,6 +1440,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha
 	uint8_t         *ptr = (uint8_t *)ha->request_ring;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
+	rval = QLA_SUCCESS;
+
 	/* Determine NVRAM starting address. */
 	ha->nvram_size = sizeof(nvram_t);
 	ha->nvram_base = 0;
@@ -1440,7 +1465,57 @@ qla2x00_nvram_config(scsi_qla_host_t *ha
 		qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
 		    "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
 		    nv->nvram_version);
-		return QLA_FUNCTION_FAILED;
+		qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+		    "invalid -- WWPN) defaults.\n");
+
+		/*
+		 * Set default initialization control block.
+		 */
+		memset(nv, 0, ha->nvram_size);
+		nv->parameter_block_version = ICB_VERSION;
+
+		if (IS_QLA23XX(ha)) {
+			nv->firmware_options[0] = BIT_2 | BIT_1;
+			nv->firmware_options[1] = BIT_7 | BIT_5;
+			nv->add_firmware_options[0] = BIT_5;
+			nv->add_firmware_options[1] = BIT_5 | BIT_4;
+			nv->frame_payload_size = __constant_cpu_to_le16(2048);
+			nv->special_options[1] = BIT_7;
+		} else if (IS_QLA2200(ha)) {
+			nv->firmware_options[0] = BIT_2 | BIT_1;
+			nv->firmware_options[1] = BIT_7 | BIT_5;
+			nv->add_firmware_options[0] = BIT_5;
+			nv->add_firmware_options[1] = BIT_5 | BIT_4;
+			nv->frame_payload_size = __constant_cpu_to_le16(1024);
+		} else if (IS_QLA2100(ha)) {
+			nv->firmware_options[0] = BIT_3 | BIT_1;
+			nv->firmware_options[1] = BIT_5;
+			nv->frame_payload_size = __constant_cpu_to_le16(1024);
+		}
+
+		nv->max_iocb_allocation = __constant_cpu_to_le16(256);
+		nv->execution_throttle = __constant_cpu_to_le16(16);
+		nv->retry_count = 8;
+		nv->retry_delay = 1;
+
+		nv->port_name[0] = 33;
+		nv->port_name[3] = 224;
+		nv->port_name[4] = 139;
+
+		qla2xxx_nvram_wwn_from_ofw(ha, nv);
+
+		nv->login_timeout = 4;
+
+		/*
+		 * Set default host adapter parameters
+		 */
+		nv->host_p[1] = BIT_2;
+		nv->reset_delay = 5;
+		nv->port_down_retry_count = 8;
+		nv->max_luns_per_target = __constant_cpu_to_le16(8);
+		nv->link_down_timeout = 60;
+
+		rval = 1;
 	}
 
 #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
@@ -1653,7 +1728,11 @@ #endif
 		}
 	}
 
-	return QLA_SUCCESS;
+	if (rval) {
+		DEBUG2_3(printk(KERN_WARNING
+		    "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+	}
+	return (rval);
 }
 
 static void
@@ -3071,9 +3150,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 
 		ha->isp_ops.get_flash_version(ha, ha->request_ring);
 
-		rval = ha->isp_ops.nvram_config(ha);
-		if (rval)
-			goto isp_abort_retry;
+		ha->isp_ops.nvram_config(ha);
 
 		if (!qla2x00_restart_isp(ha)) {
 			clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3103,7 +3180,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 				}
 			}
 		} else {	/* failed the ISP abort */
-isp_abort_retry:
 			ha->flags.online = 1;
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
 				if (ha->isp_abort_cnt == 0) {
@@ -3290,9 +3366,32 @@ qla24xx_reset_adapter(scsi_qla_host_t *h
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv)
+{
+#ifdef CONFIG_SPARC
+	struct pci_dev *pdev = ha->pdev;
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	struct device_node *dp = pcp->prom_node;
+	u8 *val;
+	int len;
+
+	val = of_get_property(dp, "port-wwn", &len);
+	if (val && len >= WWN_SIZE)
+		memcpy(nv->port_name, val, WWN_SIZE);
+
+	val = of_get_property(dp, "node-wwn", &len);
+	if (val && len >= WWN_SIZE)
+		memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
 int
 qla24xx_nvram_config(scsi_qla_host_t *ha)
 {
+	int   rval;
 	struct init_cb_24xx *icb;
 	struct nvram_24xx *nv;
 	uint32_t *dptr;
@@ -3300,6 +3399,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha
 	uint32_t chksum;
 	uint16_t cnt;
 
+	rval = QLA_SUCCESS;
 	icb = (struct init_cb_24xx *)ha->init_cb;
 	nv = (struct nvram_24xx *)ha->request_ring;
 
@@ -3332,7 +3432,52 @@ qla24xx_nvram_config(scsi_qla_host_t *ha
 		qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
 		    "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
 		    le16_to_cpu(nv->nvram_version));
-		return QLA_FUNCTION_FAILED;
+		qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+		    "invalid -- WWPN) defaults.\n");
+
+		/*
+		 * Set default initialization control block.
+		 */
+		memset(nv, 0, ha->nvram_size);
+		nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
+		nv->version = __constant_cpu_to_le16(ICB_VERSION);
+		nv->frame_payload_size = __constant_cpu_to_le16(2048);
+		nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+		nv->exchange_count = __constant_cpu_to_le16(0);
+		nv->hard_address = __constant_cpu_to_le16(124);
+		nv->port_name[0] = 0x21;
+		nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+		nv->port_name[2] = 0x00;
+		nv->port_name[3] = 0xe0;
+		nv->port_name[4] = 0x8b;
+		nv->port_name[5] = 0x1c;
+		nv->port_name[6] = 0x55;
+		nv->port_name[7] = 0x86;
+		nv->node_name[0] = 0x20;
+		nv->node_name[1] = 0x00;
+		nv->node_name[2] = 0x00;
+		nv->node_name[3] = 0xe0;
+		nv->node_name[4] = 0x8b;
+		nv->node_name[5] = 0x1c;
+		nv->node_name[6] = 0x55;
+		nv->node_name[7] = 0x86;
+		qla24xx_nvram_wwn_from_ofw(ha, nv);
+		nv->login_retry_count = __constant_cpu_to_le16(8);
+		nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
+		nv->login_timeout = __constant_cpu_to_le16(0);
+		nv->firmware_options_1 =
+		    __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
+		nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
+		nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
+		nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
+		nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
+		nv->efi_parameters = __constant_cpu_to_le32(0);
+		nv->reset_delay = 5;
+		nv->max_luns_per_target = __constant_cpu_to_le16(128);
+		nv->port_down_retry_count = __constant_cpu_to_le16(30);
+		nv->link_down_timeout = __constant_cpu_to_le16(30);
+
+		rval = 1;
 	}
 
 	/* Reset Initialization control block */
@@ -3479,7 +3624,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha
 		ha->flags.process_response_queue = 1;
 	}
 
-	return QLA_SUCCESS;
+	if (rval) {
+		DEBUG2_3(printk(KERN_WARNING
+		    "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+	}
+	return (rval);
 }
 
 static int
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 83376f6..71e32a2 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1280,14 +1280,14 @@ qla2x00_get_port_name(scsi_qla_host_t *h
 	} else {
 		if (name != NULL) {
 			/* This function returns name in big endian. */
-			name[0] = LSB(mcp->mb[2]);
-			name[1] = MSB(mcp->mb[2]);
-			name[2] = LSB(mcp->mb[3]);
-			name[3] = MSB(mcp->mb[3]);
-			name[4] = LSB(mcp->mb[6]);
-			name[5] = MSB(mcp->mb[6]);
-			name[6] = LSB(mcp->mb[7]);
-			name[7] = MSB(mcp->mb[7]);
+			name[0] = MSB(mcp->mb[2]);
+			name[1] = LSB(mcp->mb[2]);
+			name[2] = MSB(mcp->mb[3]);
+			name[3] = LSB(mcp->mb[3]);
+			name[4] = MSB(mcp->mb[6]);
+			name[5] = LSB(mcp->mb[6]);
+			name[6] = MSB(mcp->mb[7]);
+			name[7] = LSB(mcp->mb[7]);
 		}
 
 		DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 68f5d24..b78919a 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(ql2xallocfwdump,
 		"vary by ISP type.  Default is 1 - allocate memory.");
 
 int ql2xextended_error_logging;
-module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR);
+module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xextended_error_logging,
 		"Option to enable extended error logging, "
 		"Default is 0 - no logging. 1 - log errors.");
@@ -157,6 +157,8 @@ static struct scsi_host_template qla24xx
 
 	.slave_alloc		= qla2xxx_slave_alloc,
 	.slave_destroy		= qla2xxx_slave_destroy,
+	.scan_finished		= qla2xxx_scan_finished,
+	.scan_start		= qla2xxx_scan_start,
 	.change_queue_depth	= qla2x00_change_queue_depth,
 	.change_queue_type	= qla2x00_change_queue_type,
 	.this_id		= -1,
@@ -1705,6 +1707,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
 	scsi_host_put(ha->host);
 
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 }
 
@@ -1747,8 +1750,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
 	if (ha->iobase)
 		iounmap(ha->iobase);
 	pci_release_regions(ha->pdev);
-
-	pci_disable_device(ha->pdev);
 }
 
 static inline void
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index ff1dd41..206bda0 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -466,6 +466,7 @@ qla24xx_read_flash_dword(scsi_qla_host_t
 			udelay(10);
 		else
 			rval = QLA_FUNCTION_TIMEOUT;
+		cond_resched();
 	}
 
 	/* TODO: What happens if we time out? */
@@ -508,6 +509,7 @@ qla24xx_write_flash_dword(scsi_qla_host_
 			udelay(10);
 		else
 			rval = QLA_FUNCTION_TIMEOUT;
+		cond_resched();
 	}
 	return rval;
 }
@@ -1255,6 +1257,7 @@ qla2x00_poll_flash(scsi_qla_host_t *ha, 
 		}
 		udelay(10);
 		barrier();
+		cond_resched();
 	}
 	return status;
 }
@@ -1403,6 +1406,7 @@ qla2x00_read_flash_data(scsi_qla_host_t 
 		if (saddr % 100)
 			udelay(10);
 		*tmp_buf = data;
+		cond_resched();
 	}
 }
 
@@ -1449,7 +1453,6 @@ uint8_t *
 qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
     uint32_t offset, uint32_t length)
 {
-	unsigned long flags;
 	uint32_t addr, midpoint;
 	uint8_t *data;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -1458,7 +1461,6 @@ qla2x00_read_optrom_data(struct scsi_qla
 	qla2x00_suspend_hba(ha);
 
 	/* Go with read. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
 	midpoint = ha->optrom_size / 2;
 
 	qla2x00_flash_enable(ha);
@@ -1473,7 +1475,6 @@ qla2x00_read_optrom_data(struct scsi_qla
 		*data = qla2x00_read_flash_byte(ha, addr);
 	}
 	qla2x00_flash_disable(ha);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	/* Resume HBA. */
 	qla2x00_resume_hba(ha);
@@ -1487,7 +1488,6 @@ qla2x00_write_optrom_data(struct scsi_ql
 {
 
 	int rval;
-	unsigned long flags;
 	uint8_t man_id, flash_id, sec_number, data;
 	uint16_t wd;
 	uint32_t addr, liter, sec_mask, rest_addr;
@@ -1500,7 +1500,6 @@ qla2x00_write_optrom_data(struct scsi_ql
 	sec_number = 0;
 
 	/* Reset ISP chip. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
 	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
 
@@ -1689,10 +1688,10 @@ update_flash:
 				rval = QLA_FUNCTION_FAILED;
 				break;
 			}
+			cond_resched();
 		}
 	} while (0);
 	qla2x00_flash_disable(ha);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	/* Resume HBA. */
 	qla2x00_resume_hba(ha);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 61347ae..dc85495 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-k5"
+#define QLA2XXX_VERSION      "8.01.07-k6"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	1
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 9f10689..c4195ea 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(str
 	struct scsi_host_template *tpnt = match->data;
 	struct Scsi_Host *host;
 	struct qlogicpti *qpti;
-	char *fcode;
+	const char *fcode;
 
 	/* Sometimes Antares cards come up not completely
 	 * setup, and we get a report of a zero IRQ.
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 1c89ee3..4c1e313 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -344,7 +344,6 @@ #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd)
 {
 	unsigned int level;
-	struct scsi_device *sdev;
 
 	/*
 	 * If ML QUEUE log level is greater than or equal to:
@@ -361,22 +360,17 @@ void scsi_log_send(struct scsi_cmnd *cmd
 		level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
 				       SCSI_LOG_MLQUEUE_BITS);
 		if (level > 1) {
-			sdev = cmd->device;
-			sdev_printk(KERN_INFO, sdev, "send ");
+			scmd_printk(KERN_INFO, cmd, "Send: ");
 			if (level > 2)
 				printk("0x%p ", cmd);
-			/*
-			 * spaces to match disposition and cmd->result
-			 * output in scsi_log_completion.
-			 */
-			printk("                 ");
+			printk("\n");
 			scsi_print_command(cmd);
 			if (level > 3) {
 				printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
 				       " done = 0x%p, queuecommand 0x%p\n",
 					cmd->request_buffer, cmd->request_bufflen,
 					cmd->done,
-					sdev->host->hostt->queuecommand);
+					cmd->device->host->hostt->queuecommand);
 
 			}
 		}
@@ -386,7 +380,6 @@ void scsi_log_send(struct scsi_cmnd *cmd
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 {
 	unsigned int level;
-	struct scsi_device *sdev;
 
 	/*
 	 * If ML COMPLETE log level is greater than or equal to:
@@ -405,8 +398,7 @@ void scsi_log_completion(struct scsi_cmn
 				       SCSI_LOG_MLCOMPLETE_BITS);
 		if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
 		    (level > 1)) {
-			sdev = cmd->device;
-			sdev_printk(KERN_INFO, sdev, "done ");
+			scmd_printk(KERN_INFO, cmd, "Done: ");
 			if (level > 2)
 				printk("0x%p ", cmd);
 			/*
@@ -415,40 +407,35 @@ void scsi_log_completion(struct scsi_cmn
 			 */
 			switch (disposition) {
 			case SUCCESS:
-				printk("SUCCESS");
+				printk("SUCCESS\n");
 				break;
 			case NEEDS_RETRY:
-				printk("RETRY  ");
+				printk("RETRY\n");
 				break;
 			case ADD_TO_MLQUEUE:
-				printk("MLQUEUE");
+				printk("MLQUEUE\n");
 				break;
 			case FAILED:
-				printk("FAILED ");
+				printk("FAILED\n");
 				break;
 			case TIMEOUT_ERROR:
 				/* 
 				 * If called via scsi_times_out.
 				 */
-				printk("TIMEOUT");
+				printk("TIMEOUT\n");
 				break;
 			default:
-				printk("UNKNOWN");
+				printk("UNKNOWN\n");
 			}
-			printk(" %8x ", cmd->result);
+			scsi_print_result(cmd);
 			scsi_print_command(cmd);
-			if (status_byte(cmd->result) & CHECK_CONDITION) {
-				/*
-				 * XXX The scsi_print_sense formatting/prefix
-				 * doesn't match this function.
-				 */
+			if (status_byte(cmd->result) & CHECK_CONDITION)
 				scsi_print_sense("", cmd);
-			}
-			if (level > 3) {
-				printk(KERN_INFO "scsi host busy %d failed %d\n",
-				       sdev->host->host_busy,
-				       sdev->host->host_failed);
-			}
+			if (level > 3)
+				scmd_printk(KERN_INFO, cmd,
+					    "scsi host busy %d failed %d\n",
+					    cmd->device->host->host_busy,
+					    cmd->device->host->host_failed);
 		}
 	}
 }
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 3e2930b..06229f2 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -36,7 +36,6 @@ #include <linux/genhd.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
 
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 918bb60..3963e70 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -184,10 +184,19 @@ int scsi_delete_timer(struct scsi_cmnd *
  **/
 void scsi_times_out(struct scsi_cmnd *scmd)
 {
+	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
 	if (scmd->device->host->transportt->eh_timed_out)
-		switch (scmd->device->host->transportt->eh_timed_out(scmd)) {
+		eh_timed_out = scmd->device->host->transportt->eh_timed_out;
+	else if (scmd->device->host->hostt->eh_timed_out)
+		eh_timed_out = scmd->device->host->hostt->eh_timed_out;
+	else
+		eh_timed_out = NULL;
+
+	if (eh_timed_out)
+		switch (eh_timed_out(scmd)) {
 		case EH_HANDLED:
 			__scsi_done(scmd);
 			return;
@@ -923,10 +932,12 @@ static int scsi_eh_try_stu(struct scsi_c
 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
 
 	if (scmd->device->allow_restart) {
-		int rtn;
+		int i, rtn = NEEDS_RETRY;
+
+		for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
+			rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+						START_UNIT_TIMEOUT, 0);
 
-		rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
-					START_UNIT_TIMEOUT, 0);
 		if (rtn == SUCCESS)
 			return 0;
 	}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f7482d..61fbcdc 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -31,7 +31,7 @@ #include "scsi_logging.h"
 
 
 #define SG_MEMPOOL_NR		ARRAY_SIZE(scsi_sg_pools)
-#define SG_MEMPOOL_SIZE		32
+#define SG_MEMPOOL_SIZE		2
 
 struct scsi_host_sg_pool {
 	size_t		size;
@@ -848,8 +848,8 @@ void scsi_io_completion(struct scsi_cmnd
 				memcpy(req->sense, cmd->sense_buffer,  len);
 				req->sense_len = len;
 			}
-		} else
-			req->data_len = cmd->resid;
+		}
+		req->data_len = cmd->resid;
 	}
 
 	/*
@@ -968,9 +968,7 @@ void scsi_io_completion(struct scsi_cmnd
 	}
 	if (result) {
 		if (!(req->cmd_flags & REQ_QUIET)) {
-			scmd_printk(KERN_INFO, cmd,
-				    "SCSI error: return code = 0x%08x\n",
-				    result);
+			scsi_print_result(cmd);
 			if (driver_byte(result) & DRIVER_SENSE)
 				scsi_print_sense("", cmd);
 		}
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 1b59b27..4bf9aa5 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -50,7 +50,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
 	while (skb->len >= NLMSG_SPACE(0)) {
 		err = 0;
 
-		nlh = (struct nlmsghdr *) skb->data;
+		nlh = nlmsg_hdr(skb);
 		if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
 		    (skb->len < nlh->nlmsg_len)) {
 			printk(KERN_WARNING "%s: discarding partial skb\n",
@@ -168,7 +168,8 @@ scsi_netlink_init(void)
 	}
 
 	scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
-				SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE);
+				SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+				THIS_MODULE);
 	if (!scsi_nl_sock) {
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
 				__FUNCTION__);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0949145..a67f315 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -181,10 +181,8 @@ int scsi_complete_async_scans(void)
 	return 0;
 }
 
-#ifdef MODULE
 /* Only exported for the benefit of scsi_wait_scan */
 EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
-#endif
 
 /**
  * scsi_unlock_floptical - unlock device via a special MODE SENSE command
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 939de0d..67a38a1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -276,8 +276,22 @@ static int scsi_bus_match(struct device 
 	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
 }
 
+static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
+		           char *buffer, int buffer_size)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	int i = 0;
+	int length = 0;
+
+	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+		       "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
+	envp[i] = NULL;
+	return 0;
+}
+
 static int scsi_bus_suspend(struct device * dev, pm_message_t state)
 {
+	struct device_driver *drv = dev->driver;
 	struct scsi_device *sdev = to_scsi_device(dev);
 	struct scsi_host_template *sht = sdev->host->hostt;
 	int err;
@@ -286,28 +300,51 @@ static int scsi_bus_suspend(struct devic
 	if (err)
 		return err;
 
-	if (sht->suspend)
+	/* call HLD suspend first */
+	if (drv && drv->suspend) {
+		err = drv->suspend(dev, state);
+		if (err)
+			return err;
+	}
+
+	/* then, call host suspend */
+	if (sht->suspend) {
 		err = sht->suspend(sdev, state);
+		if (err) {
+			if (drv && drv->resume)
+				drv->resume(dev);
+			return err;
+		}
+	}
 
-	return err;
+	return 0;
 }
 
 static int scsi_bus_resume(struct device * dev)
 {
+	struct device_driver *drv = dev->driver;
 	struct scsi_device *sdev = to_scsi_device(dev);
 	struct scsi_host_template *sht = sdev->host->hostt;
-	int err = 0;
+	int err = 0, err2 = 0;
 
+	/* call host resume first */
 	if (sht->resume)
 		err = sht->resume(sdev);
 
+	/* then, call HLD resume */
+	if (drv && drv->resume)
+		err2 = drv->resume(dev);
+
 	scsi_device_resume(sdev);
-	return err;
+
+	/* favor LLD failure */
+	return err ? err : err2;;
 }
 
 struct bus_type scsi_bus_type = {
         .name		= "scsi",
         .match		= scsi_bus_match,
+	.uevent		= scsi_bus_uevent,
 	.suspend	= scsi_bus_suspend,
 	.resume		= scsi_bus_resume,
 };
@@ -547,6 +584,14 @@ show_sdev_iostat(iorequest_cnt);
 show_sdev_iostat(iodone_cnt);
 show_sdev_iostat(ioerr_cnt);
 
+static ssize_t
+sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev;
+	sdev = to_scsi_device(dev);
+	return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type);
+}
+static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
 
 /* Default template for device attributes.  May NOT be modified */
 static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -566,6 +611,7 @@ static struct device_attribute *scsi_sys
 	&dev_attr_iorequest_cnt,
 	&dev_attr_iodone_cnt,
 	&dev_attr_ioerr_cnt,
+	&dev_attr_modalias,
 	NULL
 };
 
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 0e08817..ca22ddf 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -179,10 +179,12 @@ static int event_recv_msg(struct tgt_eve
 	switch (ev->hdr.type) {
 	case TGT_UEVENT_CMD_RSP:
 		err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
-					   ev->p.cmd_rsp.tag,
 					   ev->p.cmd_rsp.result,
-					   ev->p.cmd_rsp.len,
+					   ev->p.cmd_rsp.tag,
 					   ev->p.cmd_rsp.uaddr,
+					   ev->p.cmd_rsp.len,
+					   ev->p.cmd_rsp.sense_uaddr,
+					   ev->p.cmd_rsp.sense_len,
 					   ev->p.cmd_rsp.rw);
 		break;
 	case TGT_UEVENT_TSK_MGMT_RSP:
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index d402aff..2570f48 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -28,7 +28,6 @@ #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tgt.h>
-#include <../drivers/md/dm-bio-list.h>
 
 #include "scsi_tgt_priv.h"
 
@@ -42,16 +41,12 @@ static struct kmem_cache *scsi_tgt_cmd_c
 struct scsi_tgt_cmd {
 	/* TODO replace work with James b's code */
 	struct work_struct work;
-	/* TODO replace the lists with a large bio */
-	struct bio_list xfer_done_list;
-	struct bio_list xfer_list;
+	/* TODO fix limits of some drivers */
+	struct bio *bio;
 
 	struct list_head hash_list;
 	struct request *rq;
 	u64 tag;
-
-	void *buffer;
-	unsigned bufflen;
 };
 
 #define TGT_HASH_ORDER	4
@@ -93,7 +88,12 @@ struct scsi_cmnd *scsi_host_get_command(
 	if (!tcmd)
 		goto put_dev;
 
-	rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
+	/*
+	 * The blk helpers are used to the READ/WRITE requests
+	 * transfering data from a initiator point of view. Since
+	 * we are in target mode we want the opposite.
+	 */
+	rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
 	if (!rq)
 		goto free_tcmd;
 
@@ -111,8 +111,6 @@ struct scsi_cmnd *scsi_host_get_command(
 	rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
 	rq->end_io_data = tcmd;
 
-	bio_list_init(&tcmd->xfer_list);
-	bio_list_init(&tcmd->xfer_done_list);
 	tcmd->rq = rq;
 
 	return cmd;
@@ -157,22 +155,6 @@ void scsi_host_put_command(struct Scsi_H
 }
 EXPORT_SYMBOL_GPL(scsi_host_put_command);
 
-static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
-{
-	struct bio *bio;
-
-	/* must call bio_endio in case bio was bounced */
-	while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
-		bio_endio(bio, bio->bi_size, 0);
-		bio_unmap_user(bio);
-	}
-
-	while ((bio = bio_list_pop(&tcmd->xfer_list))) {
-		bio_endio(bio, bio->bi_size, 0);
-		bio_unmap_user(bio);
-	}
-}
-
 static void cmd_hashlist_del(struct scsi_cmnd *cmd)
 {
 	struct request_queue *q = cmd->request->q;
@@ -185,6 +167,11 @@ static void cmd_hashlist_del(struct scsi
 	spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 }
 
+static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
+{
+	blk_rq_unmap_user(tcmd->bio);
+}
+
 static void scsi_tgt_cmd_destroy(struct work_struct *work)
 {
 	struct scsi_tgt_cmd *tcmd =
@@ -193,16 +180,6 @@ static void scsi_tgt_cmd_destroy(struct 
 
 	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
 		rq_data_dir(cmd->request));
-	/*
-	 * We fix rq->cmd_flags here since when we told bio_map_user
-	 * to write vm for WRITE commands, blk_rq_bio_prep set
-	 * rq_data_dir the flags to READ.
-	 */
-	if (cmd->sc_data_direction == DMA_TO_DEVICE)
-		cmd->request->cmd_flags |= REQ_RW;
-	else
-		cmd->request->cmd_flags &= ~REQ_RW;
-
 	scsi_unmap_user_pages(tcmd);
 	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
 }
@@ -215,6 +192,7 @@ static void init_scsi_tgt_cmd(struct req
 	struct list_head *head;
 
 	tcmd->tag = tag;
+	tcmd->bio = NULL;
 	INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
 	spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 	head = &qdata->cmd_hash[cmd_hashfn(tag)];
@@ -349,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scs
 	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
 
 	scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+
+	if (cmd->request_buffer)
+		scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+
 	queue_work(scsi_tgtd, &tcmd->work);
 }
 
-static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 	int err;
@@ -365,30 +347,12 @@ static int __scsi_tgt_transfer_response(
 	case SCSI_MLQUEUE_DEVICE_BUSY:
 		return -EAGAIN;
 	}
-
 	return 0;
 }
 
-static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
-{
-	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
-	int err;
-
-	err = __scsi_tgt_transfer_response(cmd);
-	if (!err)
-		return;
-
-	cmd->result = DID_BUS_BUSY << 16;
-	err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
-	if (err <= 0)
-		/* the eh will have to pick this up */
-		printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-}
-
 static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 {
 	struct request *rq = cmd->request;
-	struct scsi_tgt_cmd *tcmd = rq->end_io_data;
 	int count;
 
 	cmd->use_sg = rq->nr_phys_segments;
@@ -398,143 +362,54 @@ static int scsi_tgt_init_cmd(struct scsi
 
 	cmd->request_bufflen = rq->data_len;
 
-	dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
-		rq_data_dir(rq));
+	dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
 	count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
 	if (likely(count <= cmd->use_sg)) {
 		cmd->use_sg = count;
 		return 0;
 	}
 
-	eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
+	eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
 	scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
 	return -EINVAL;
 }
 
 /* TODO: test this crap and replace bio_map_user with new interface maybe */
 static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
-			       int rw)
+			       unsigned long uaddr, unsigned int len, int rw)
 {
 	struct request_queue *q = cmd->request->q;
 	struct request *rq = cmd->request;
-	void *uaddr = tcmd->buffer;
-	unsigned int len = tcmd->bufflen;
-	struct bio *bio;
 	int err;
 
-	while (len > 0) {
-		dprintk("%lx %u\n", (unsigned long) uaddr, len);
-		bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
-		if (IS_ERR(bio)) {
-			err = PTR_ERR(bio);
-			dprintk("fail to map %lx %u %d %x\n",
-				(unsigned long) uaddr, len, err, cmd->cmnd[0]);
-			goto unmap_bios;
-		}
-
-		uaddr += bio->bi_size;
-		len -= bio->bi_size;
-
+	dprintk("%lx %u\n", uaddr, len);
+	err = blk_rq_map_user(q, rq, (void *)uaddr, len);
+	if (err) {
 		/*
-		 * The first bio is added and merged. We could probably
-		 * try to add others using scsi_merge_bio() but for now
-		 * we keep it simple. The first bio should be pretty large
-		 * (either hitting the 1 MB bio pages limit or a queue limit)
-		 * already but for really large IO we may want to try and
-		 * merge these.
+		 * TODO: need to fixup sg_tablesize, max_segment_size,
+		 * max_sectors, etc for modern HW and software drivers
+		 * where this value is bogus.
+		 *
+		 * TODO2: we can alloc a reserve buffer of max size
+		 * we can handle and do the slow copy path for really large
+		 * IO.
 		 */
-		if (!rq->bio) {
-			blk_rq_bio_prep(q, rq, bio);
-			rq->data_len = bio->bi_size;
-		} else
-			/* put list of bios to transfer in next go around */
-			bio_list_add(&tcmd->xfer_list, bio);
+		eprintk("Could not handle request of size %u.\n", len);
+		return err;
 	}
 
-	cmd->offset = 0;
+	tcmd->bio = rq->bio;
 	err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
 	if (err)
-		goto unmap_bios;
+		goto unmap_rq;
 
 	return 0;
 
-unmap_bios:
-	if (rq->bio) {
-		bio_unmap_user(rq->bio);
-		while ((bio = bio_list_pop(&tcmd->xfer_list)))
-			bio_unmap_user(bio);
-	}
-
+unmap_rq:
+	scsi_unmap_user_pages(tcmd);
 	return err;
 }
 
-static int scsi_tgt_transfer_data(struct scsi_cmnd *);
-
-static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
-{
-	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
-	struct bio *bio;
-	int err;
-
-	/* should we free resources here on error ? */
-	if (cmd->result) {
-send_uspace_err:
-		err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
-		if (err <= 0)
-			/* the tgt uspace eh will have to pick this up */
-			printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-		return;
-	}
-
-	dprintk("cmd %p request_bufflen %u bufflen %u\n",
-		cmd, cmd->request_bufflen, tcmd->bufflen);
-
-	scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
-	bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
-
-	tcmd->buffer += cmd->request_bufflen;
-	cmd->offset += cmd->request_bufflen;
-
-	if (!tcmd->xfer_list.head) {
-		scsi_tgt_transfer_response(cmd);
-		return;
-	}
-
-	dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
-		cmd, cmd->request_bufflen, tcmd->bufflen);
-
-	bio = bio_list_pop(&tcmd->xfer_list);
-	BUG_ON(!bio);
-
-	blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
-	cmd->request->data_len = bio->bi_size;
-	err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
-	if (err) {
-		cmd->result = DID_ERROR << 16;
-		goto send_uspace_err;
-	}
-
-	if (scsi_tgt_transfer_data(cmd)) {
-		cmd->result = DID_NO_CONNECT << 16;
-		goto send_uspace_err;
-	}
-}
-
-static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
-{
-	int err;
-	struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
-
-	err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
-	switch (err) {
-		case SCSI_MLQUEUE_HOST_BUSY:
-		case SCSI_MLQUEUE_DEVICE_BUSY:
-			return -EAGAIN;
-	default:
-		return 0;
-	}
-}
-
 static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
 				unsigned len)
 {
@@ -584,8 +459,9 @@ static struct request *tgt_cmd_hash_look
 	return rq;
 }
 
-int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
-			 unsigned long uaddr, u8 rw)
+int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+			 unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+			 u32 sense_len, u8 rw)
 {
 	struct Scsi_Host *shost;
 	struct scsi_cmnd *cmd;
@@ -617,8 +493,9 @@ int scsi_tgt_kspace_exec(int host_no, u6
 	}
 	cmd = rq->special;
 
-	dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
-		result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+	dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
+		cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
+		rq_data_dir(rq), cmd->cmnd[0]);
 
 	if (result == TASK_ABORTED) {
 		scsi_tgt_abort_cmd(shost, cmd);
@@ -629,36 +506,36 @@ int scsi_tgt_kspace_exec(int host_no, u6
 	 * in the request_* values
 	 */
 	tcmd = cmd->request->end_io_data;
-	tcmd->buffer = (void *)uaddr;
-	tcmd->bufflen = len;
 	cmd->result = result;
 
-	if (!tcmd->bufflen || cmd->request_buffer) {
-		err = __scsi_tgt_transfer_response(cmd);
-		goto done;
-	}
+	if (cmd->result == SAM_STAT_CHECK_CONDITION)
+		scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
 
-	/*
-	 * TODO: Do we need to handle case where request does not
-	 * align with LLD.
-	 */
-	err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
-	if (err) {
-		eprintk("%p %d\n", cmd, err);
-		err = -EAGAIN;
-		goto done;
-	}
+	if (len) {
+		err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
+		if (err) {
+			/*
+			 * user-space daemon bugs or OOM
+			 * TODO: we can do better for OOM.
+			 */
+			struct scsi_tgt_queuedata *qdata;
+			struct list_head *head;
+			unsigned long flags;
 
-	/* userspace failure */
-	if (cmd->result) {
-		if (status_byte(cmd->result) == CHECK_CONDITION)
-			scsi_tgt_copy_sense(cmd, uaddr, len);
-		err = __scsi_tgt_transfer_response(cmd);
-		goto done;
-	}
-	/* ask the target LLD to transfer the data to the buffer */
-	err = scsi_tgt_transfer_data(cmd);
+			eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n",
+				cmd, err, uaddr, len, rw);
+
+			qdata = shost->uspace_req_q->queuedata;
+			head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)];
+
+			spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+			list_add(&tcmd->hash_list, head);
+			spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 
+			goto done;
+		}
+	}
+	err = scsi_tgt_transfer_response(cmd);
 done:
 	scsi_host_put(shost);
 	return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 84488c5..e9e6db1 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -18,8 +18,9 @@ extern int scsi_tgt_if_init(void);
 extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
 				    u64 tag);
 extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
-				unsigned long uaddr, u8 rw);
+extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+				unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+				u32 sense_len, u8 rw);
 extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
 					 struct scsi_lun *scsilun, void *data);
 extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 58afdb4..14c4f06 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -200,6 +200,8 @@ static const struct {
 	{ FC_PORTSPEED_2GBIT,		"2 Gbit" },
 	{ FC_PORTSPEED_4GBIT,		"4 Gbit" },
 	{ FC_PORTSPEED_10GBIT,		"10 Gbit" },
+	{ FC_PORTSPEED_8GBIT,		"8 Gbit" },
+	{ FC_PORTSPEED_16GBIT,		"16 Gbit" },
 	{ FC_PORTSPEED_NOT_NEGOTIATED,	"Not Negotiated" },
 };
 fc_bitfield_name_search(port_speed, fc_port_speed_names)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index ce0d14a..caf1836 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -49,7 +49,7 @@ struct iscsi_internal {
 	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
 };
 
-static int iscsi_session_nr;	/* sysfs session id for next new session */
+static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
 
 /*
  * list of registered transports and lock that must
@@ -300,7 +300,7 @@ int iscsi_add_session(struct iscsi_cls_s
 	int err;
 
 	ihost = shost->shost_data;
-	session->sid = iscsi_session_nr++;
+	session->sid = atomic_add_return(1, &iscsi_session_nr);
 	session->target_id = target_id;
 
 	snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
@@ -1081,7 +1081,7 @@ iscsi_if_rx(struct sock *sk, int len)
 			struct nlmsghdr	*nlh;
 			struct iscsi_uevent *ev;
 
-			nlh = (struct nlmsghdr *)skb->data;
+			nlh = nlmsg_hdr(skb);
 			if (nlh->nlmsg_len < sizeof(*nlh) ||
 			    skb->len < nlh->nlmsg_len) {
 				break;
@@ -1419,6 +1419,8 @@ static __init int iscsi_transport_init(v
 	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
 		ISCSI_TRANSPORT_VERSION);
 
+	atomic_set(&iscsi_session_nr, 0);
+
 	err = class_register(&iscsi_transport_class);
 	if (err)
 		return err;
@@ -1435,7 +1437,7 @@ static __init int iscsi_transport_init(v
 	if (err)
 		goto unregister_conn_class;
 
-	nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
+	nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
 			THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5a8f55f..00e4666 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -58,16 +58,10 @@ #include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsicam.h>
+#include <scsi/sd.h>
 
 #include "scsi_logging.h"
 
-/*
- * More than enough for everybody ;)  The huge number of majors
- * is a leftover from 16bit dev_t days, we don't really need that
- * much numberspace.
- */
-#define SD_MAJORS	16
-
 MODULE_AUTHOR("Eric Youngdale");
 MODULE_DESCRIPTION("SCSI disk (sd) driver");
 MODULE_LICENSE("GPL");
@@ -88,45 +82,9 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
-
-/*
- * This is limited by the naming scheme enforced in sd_probe,
- * add another character to it if you really need more disks.
- */
-#define SD_MAX_DISKS	(((26 * 26) + 26 + 1) * 26)
-
-/*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
- */
-#define SD_TIMEOUT		(30 * HZ)
-#define SD_MOD_TIMEOUT		(75 * HZ)
-
-/*
- * Number of allowed retries
- */
-#define SD_MAX_RETRIES		5
-#define SD_PASSTHROUGH_RETRIES	1
-
-/*
- * Size of the initial data buffer for mode and read capacity data
- */
-#define SD_BUF_SIZE		512
-
-struct scsi_disk {
-	struct scsi_driver *driver;	/* always &sd_template */
-	struct scsi_device *device;
-	struct class_device cdev;
-	struct gendisk	*disk;
-	unsigned int	openers;	/* protected by BKL for now, yuck */
-	sector_t	capacity;	/* size in 512-byte sectors */
-	u32		index;
-	u8		media_present;
-	u8		write_prot;
-	unsigned	WCE : 1;	/* state of disk WCE bit */
-	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
-	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
-};
-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
+MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
 
 static DEFINE_IDR(sd_index_idr);
 static DEFINE_SPINLOCK(sd_index_lock);
@@ -136,20 +94,6 @@ static DEFINE_SPINLOCK(sd_index_lock);
  * object after last put) */
 static DEFINE_MUTEX(sd_ref_mutex);
 
-static int sd_revalidate_disk(struct gendisk *disk);
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-
-static int sd_probe(struct device *);
-static int sd_remove(struct device *);
-static void sd_shutdown(struct device *dev);
-static void sd_rescan(struct device *);
-static int sd_init_command(struct scsi_cmnd *);
-static int sd_issue_flush(struct device *, sector_t *);
-static void sd_prepare_flush(request_queue_t *, struct request *);
-static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
-			     unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-
 static const char *sd_cache_types[] = {
 	"write through", "none", "write back",
 	"write back, no read (daft)"
@@ -199,13 +143,27 @@ static ssize_t sd_store_cache_type(struc
 	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
 			     SD_MAX_RETRIES, &data, &sshdr)) {
 		if (scsi_sense_valid(&sshdr))
-			scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr);
+			sd_print_sense_hdr(sdkp, &sshdr);
 		return -EINVAL;
 	}
 	sd_revalidate_disk(sdkp->disk);
 	return count;
 }
 
+static ssize_t sd_store_manage_start_stop(struct class_device *cdev,
+					  const char *buf, size_t count)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(cdev);
+	struct scsi_device *sdp = sdkp->device;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);
+
+	return count;
+}
+
 static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
 				      size_t count)
 {
@@ -238,6 +196,14 @@ static ssize_t sd_show_fua(struct class_
 	return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
 }
 
+static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(cdev);
+	struct scsi_device *sdp = sdkp->device;
+
+	return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
+}
+
 static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -251,6 +217,8 @@ static struct class_device_attribute sd_
 	__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
 	__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
 	       sd_store_allow_restart),
+	__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
+	       sd_store_manage_start_stop),
 	__ATTR_NULL,
 };
 
@@ -267,6 +235,8 @@ static struct scsi_driver sd_template = 
 		.name		= "sd",
 		.probe		= sd_probe,
 		.remove		= sd_remove,
+		.suspend	= sd_suspend,
+		.resume		= sd_resume,
 		.shutdown	= sd_shutdown,
 	},
 	.rescan			= sd_rescan,
@@ -371,15 +341,19 @@ static int sd_init_command(struct scsi_c
 	unsigned int this_count = SCpnt->request_bufflen >> 9;
 	unsigned int timeout = sdp->timeout;
 
-	SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
-			    "count=%d\n", disk->disk_name,
-			 (unsigned long long)block, this_count));
+	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
+					"sd_init_command: block=%llu, "
+					"count=%d\n",
+					(unsigned long long)block,
+					this_count));
 
 	if (!sdp || !scsi_device_online(sdp) ||
  	    block + rq->nr_sectors > get_capacity(disk)) {
-		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", 
-				 rq->nr_sectors));
-		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+						"Finishing %ld sectors\n",
+						rq->nr_sectors));
+		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+						"Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
 
@@ -391,8 +365,8 @@ static int sd_init_command(struct scsi_c
 		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
 		return 0;
 	}
-	SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
-				   disk->disk_name, (unsigned long long)block));
+	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
+					(unsigned long long)block));
 
 	/*
 	 * If we have a 1K hardware sectorsize, prevent access to single
@@ -407,7 +381,8 @@ static int sd_init_command(struct scsi_c
 	 */
 	if (sdp->sector_size == 1024) {
 		if ((block & 1) || (rq->nr_sectors & 1)) {
-			printk(KERN_ERR "sd: Bad block number requested");
+			scmd_printk(KERN_ERR, SCpnt,
+				    "Bad block number requested\n");
 			return 0;
 		} else {
 			block = block >> 1;
@@ -416,7 +391,8 @@ static int sd_init_command(struct scsi_c
 	}
 	if (sdp->sector_size == 2048) {
 		if ((block & 3) || (rq->nr_sectors & 3)) {
-			printk(KERN_ERR "sd: Bad block number requested");
+			scmd_printk(KERN_ERR, SCpnt,
+				    "Bad block number requested\n");
 			return 0;
 		} else {
 			block = block >> 2;
@@ -425,7 +401,8 @@ static int sd_init_command(struct scsi_c
 	}
 	if (sdp->sector_size == 4096) {
 		if ((block & 7) || (rq->nr_sectors & 7)) {
-			printk(KERN_ERR "sd: Bad block number requested");
+			scmd_printk(KERN_ERR, SCpnt,
+				    "Bad block number requested\n");
 			return 0;
 		} else {
 			block = block >> 3;
@@ -442,13 +419,15 @@ 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 %x\n", rq->cmd_flags);
+		scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
 		return 0;
 	}
 
-	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", 
-		disk->disk_name, (rq_data_dir(rq) == WRITE) ? 
-		"writing" : "reading", this_count, rq->nr_sectors));
+	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+					"%s %d/%ld 512 byte blocks.\n",
+					(rq_data_dir(rq) == WRITE) ?
+					"writing" : "reading", this_count,
+					rq->nr_sectors));
 
 	SCpnt->cmnd[1] = 0;
 	
@@ -490,7 +469,8 @@ static int sd_init_command(struct scsi_c
 			 * during operation and thus turned off
 			 * use_10_for_rw.
 			 */
-			printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n");
+			scmd_printk(KERN_ERR, SCpnt,
+				    "FUA write on READ/WRITE(6) drive\n");
 			return 0;
 		}
 
@@ -549,7 +529,7 @@ static int sd_open(struct inode *inode, 
 		return -ENXIO;
 
 
-	SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));
+	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));
 
 	sdev = sdkp->device;
 
@@ -619,7 +599,7 @@ static int sd_release(struct inode *inod
 	struct scsi_disk *sdkp = scsi_disk(disk);
 	struct scsi_device *sdev = sdkp->device;
 
-	SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
+	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n"));
 
 	if (!--sdkp->openers && sdev->removable) {
 		if (scsi_block_when_processing_errors(sdev))
@@ -732,8 +712,7 @@ static int sd_media_changed(struct gendi
 	struct scsi_device *sdp = sdkp->device;
 	int retval;
 
-	SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n",
-						disk->disk_name));
+	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
 
 	if (!sdp->removable)
 		return 0;
@@ -786,9 +765,10 @@ not_present:
 	return 1;
 }
 
-static int sd_sync_cache(struct scsi_device *sdp)
+static int sd_sync_cache(struct scsi_disk *sdkp)
 {
 	int retries, res;
+	struct scsi_device *sdp = sdkp->device;
 	struct scsi_sense_hdr sshdr;
 
 	if (!scsi_device_online(sdp))
@@ -809,28 +789,27 @@ static int sd_sync_cache(struct scsi_dev
 			break;
 	}
 
-	if (res) {		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
-				    "host = %d, driver = %02x\n  ",
-				    status_byte(res), msg_byte(res),
-				    host_byte(res), driver_byte(res));
-			if (driver_byte(res) & DRIVER_SENSE)
-				scsi_print_sense_hdr("sd", &sshdr);
+	if (res) {
+		sd_print_result(sdkp, res);
+		if (driver_byte(res) & DRIVER_SENSE)
+			sd_print_sense_hdr(sdkp, &sshdr);
 	}
 
-	return res;
+	if (res)
+		return -EIO;
+	return 0;
 }
 
 static int sd_issue_flush(struct device *dev, sector_t *error_sector)
 {
 	int ret = 0;
-	struct scsi_device *sdp = to_scsi_device(dev);
 	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 
 	if (!sdkp)
                return -ENODEV;
 
 	if (sdkp->WCE)
-		ret = sd_sync_cache(sdp);
+		ret = sd_sync_cache(sdkp);
 	scsi_disk_put(sdkp);
 	return ret;
 }
@@ -928,12 +907,14 @@ static void sd_rw_intr(struct scsi_cmnd 
 			sense_deferred = scsi_sense_is_deferred(&sshdr);
 	}
 #ifdef CONFIG_SCSI_LOGGING
-	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
-				SCpnt->request->rq_disk->disk_name, result));
+	SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
 	if (sense_valid) {
-		SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
-				"ascq]=%x,%x,%x,%x\n", sshdr.response_code,
-				sshdr.sense_key, sshdr.asc, sshdr.ascq));
+		SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
+						   "sd_rw_intr: sb[respc,sk,asc,"
+						   "ascq]=%x,%x,%x,%x\n",
+						   sshdr.response_code,
+						   sshdr.sense_key, sshdr.asc,
+						   sshdr.ascq));
 	}
 #endif
 	if (driver_byte(result) != DRIVER_SENSE &&
@@ -1025,7 +1006,7 @@ static int media_not_present(struct scsi
  * spinup disk - called only in sd_revalidate_disk()
  */
 static void
-sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
+sd_spinup_disk(struct scsi_disk *sdkp)
 {
 	unsigned char cmd[10];
 	unsigned long spintime_expire = 0;
@@ -1069,9 +1050,10 @@ sd_spinup_disk(struct scsi_disk *sdkp, c
 		if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
 			/* no sense, TUR either succeeded or failed
 			 * with a status error */
-			if(!spintime && !scsi_status_is_good(the_result))
-				printk(KERN_NOTICE "%s: Unit Not Ready, "
-				       "error = 0x%x\n", diskname, the_result);
+			if(!spintime && !scsi_status_is_good(the_result)) {
+				sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+				sd_print_result(sdkp, the_result);
+			}
 			break;
 		}
 					
@@ -1096,8 +1078,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, c
 		 */
 		} else if (sense_valid && sshdr.sense_key == NOT_READY) {
 			if (!spintime) {
-				printk(KERN_NOTICE "%s: Spinning up disk...",
-				       diskname);
+				sd_printk(KERN_NOTICE, sdkp, "Spinning up disk...");
 				cmd[0] = START_STOP;
 				cmd[1] = 1;	/* Return immediately */
 				memset((void *) &cmd[2], 0, 8);
@@ -1130,9 +1111,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, c
 			/* we don't understand the sense code, so it's
 			 * probably pointless to loop */
 			if(!spintime) {
-				printk(KERN_NOTICE "%s: Unit Not Ready, "
-					"sense:\n", diskname);
-				scsi_print_sense_hdr("", &sshdr);
+				sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+				sd_print_sense_hdr(sdkp, &sshdr);
 			}
 			break;
 		}
@@ -1151,8 +1131,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, c
  * read disk capacity
  */
 static void
-sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
-		 unsigned char *buffer)
+sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
 {
 	unsigned char cmd[16];
 	int the_result, retries;
@@ -1191,18 +1170,12 @@ repeat:
 	} while (the_result && retries);
 
 	if (the_result && !longrc) {
-		printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
-		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
-		       diskname, diskname,
-		       status_byte(the_result),
-		       msg_byte(the_result),
-		       host_byte(the_result),
-		       driver_byte(the_result));
-
+		sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
+		sd_print_result(sdkp, the_result);
 		if (driver_byte(the_result) & DRIVER_SENSE)
-			scsi_print_sense_hdr("sd", &sshdr);
+			sd_print_sense_hdr(sdkp, &sshdr);
 		else
-			printk("%s : sense not available. \n", diskname);
+			sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
 
 		/* Set dirty bit for removable devices if not ready -
 		 * sometimes drives will not report this properly. */
@@ -1218,16 +1191,10 @@ repeat:
 		return;
 	} else if (the_result && longrc) {
 		/* READ CAPACITY(16) has been failed */
-		printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n"
-		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
-		       diskname, diskname,
-		       status_byte(the_result),
-		       msg_byte(the_result),
-		       host_byte(the_result),
-		       driver_byte(the_result));
-		printk(KERN_NOTICE "%s : use 0xffffffff as device size\n",
-		       diskname);
-		
+		sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
+		sd_print_result(sdkp, the_result);
+		sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n");
+
 		sdkp->capacity = 1 + (sector_t) 0xffffffff;		
 		goto got_data;
 	}	
@@ -1238,14 +1205,14 @@ repeat:
 		if (buffer[0] == 0xff && buffer[1] == 0xff &&
 		    buffer[2] == 0xff && buffer[3] == 0xff) {
 			if(sizeof(sdkp->capacity) > 4) {
-				printk(KERN_NOTICE "%s : very big device. try to use"
-				       " READ CAPACITY(16).\n", diskname);
+				sd_printk(KERN_NOTICE, sdkp, "Very big device. "
+					  "Trying to use READ CAPACITY(16).\n");
 				longrc = 1;
 				goto repeat;
 			}
-			printk(KERN_ERR "%s: too big for this kernel.  Use a "
-			       "kernel compiled with support for large block "
-			       "devices.\n", diskname);
+			sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use "
+				  "a kernel compiled with support for large "
+				  "block devices.\n");
 			sdkp->capacity = 0;
 			goto got_data;
 		}
@@ -1284,8 +1251,8 @@ repeat:
 got_data:
 	if (sector_size == 0) {
 		sector_size = 512;
-		printk(KERN_NOTICE "%s : sector size 0 reported, "
-		       "assuming 512.\n", diskname);
+		sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, "
+			  "assuming 512.\n");
 	}
 
 	if (sector_size != 512 &&
@@ -1293,8 +1260,8 @@ got_data:
 	    sector_size != 2048 &&
 	    sector_size != 4096 &&
 	    sector_size != 256) {
-		printk(KERN_NOTICE "%s : unsupported sector size "
-		       "%d.\n", diskname, sector_size);
+		sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n",
+			  sector_size);
 		/*
 		 * The user might want to re-format the drive with
 		 * a supported sectorsize.  Once this happens, it
@@ -1327,10 +1294,10 @@ got_data:
 		mb -= sz - 974;
 		sector_div(mb, 1950);
 
-		printk(KERN_NOTICE "SCSI device %s: "
-		       "%llu %d-byte hdwr sectors (%llu MB)\n",
-		       diskname, (unsigned long long)sdkp->capacity,
-		       hard_sector, (unsigned long long)mb);
+		sd_printk(KERN_NOTICE, sdkp,
+			  "%llu %d-byte hardware sectors (%llu MB)\n",
+			  (unsigned long long)sdkp->capacity,
+			  hard_sector, (unsigned long long)mb);
 	}
 
 	/* Rescale capacity to 512-byte units */
@@ -1362,8 +1329,7 @@ sd_do_mode_sense(struct scsi_device *sdp
  * called with buffer of length SD_BUF_SIZE
  */
 static void
-sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
-			   unsigned char *buffer)
+sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
 {
 	int res;
 	struct scsi_device *sdp = sdkp->device;
@@ -1371,7 +1337,7 @@ sd_read_write_protect_flag(struct scsi_d
 
 	set_disk_ro(sdkp->disk, 0);
 	if (sdp->skip_ms_page_3f) {
-		printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
+		sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
 		return;
 	}
 
@@ -1403,15 +1369,16 @@ sd_read_write_protect_flag(struct scsi_d
 	}
 
 	if (!scsi_status_is_good(res)) {
-		printk(KERN_WARNING
-		       "%s: test WP failed, assume Write Enabled\n", diskname);
+		sd_printk(KERN_WARNING, sdkp,
+			  "Test WP failed, assume Write Enabled\n");
 	} else {
 		sdkp->write_prot = ((data.device_specific & 0x80) != 0);
 		set_disk_ro(sdkp->disk, sdkp->write_prot);
-		printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
-		       sdkp->write_prot ? "on" : "off");
-		printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
-		       diskname, buffer[0], buffer[1], buffer[2], buffer[3]);
+		sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
+			  sdkp->write_prot ? "on" : "off");
+		sd_printk(KERN_DEBUG, sdkp,
+			  "Mode Sense: %02x %02x %02x %02x\n",
+			  buffer[0], buffer[1], buffer[2], buffer[3]);
 	}
 }
 
@@ -1420,8 +1387,7 @@ sd_read_write_protect_flag(struct scsi_d
  * called with buffer of length SD_BUF_SIZE
  */
 static void
-sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
-		   unsigned char *buffer)
+sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
 {
 	int len = 0, res;
 	struct scsi_device *sdp = sdkp->device;
@@ -1450,8 +1416,7 @@ sd_read_cache_type(struct scsi_disk *sdk
 
 	if (!data.header_length) {
 		modepage = 6;
-		printk(KERN_ERR "%s: missing header in MODE_SENSE response\n",
-		       diskname);
+		sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
 	}
 
 	/* that went OK, now ask for the proper length */
@@ -1478,13 +1443,12 @@ sd_read_cache_type(struct scsi_disk *sdk
 		int offset = data.header_length + data.block_descriptor_length;
 
 		if (offset >= SD_BUF_SIZE - 2) {
-			printk(KERN_ERR "%s: malformed MODE SENSE response",
-				diskname);
+			sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
 			goto defaults;
 		}
 
 		if ((buffer[offset] & 0x3f) != modepage) {
-			printk(KERN_ERR "%s: got wrong page\n", diskname);
+			sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
 			goto defaults;
 		}
 
@@ -1498,14 +1462,13 @@ sd_read_cache_type(struct scsi_disk *sdk
 
 		sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
 		if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
-			printk(KERN_NOTICE "SCSI device %s: uses "
-			       "READ/WRITE(6), disabling FUA\n", diskname);
+			sd_printk(KERN_NOTICE, sdkp,
+				  "Uses READ/WRITE(6), disabling FUA\n");
 			sdkp->DPOFUA = 0;
 		}
 
-		printk(KERN_NOTICE "SCSI device %s: "
-		       "write cache: %s, read cache: %s, %s\n",
-		       diskname,
+		sd_printk(KERN_NOTICE, sdkp,
+		       "Write cache: %s, read cache: %s, %s\n",
 		       sdkp->WCE ? "enabled" : "disabled",
 		       sdkp->RCD ? "disabled" : "enabled",
 		       sdkp->DPOFUA ? "supports DPO and FUA"
@@ -1518,15 +1481,13 @@ bad_sense:
 	if (scsi_sense_valid(&sshdr) &&
 	    sshdr.sense_key == ILLEGAL_REQUEST &&
 	    sshdr.asc == 0x24 && sshdr.ascq == 0x0)
-		printk(KERN_NOTICE "%s: cache data unavailable\n",
-		       diskname);	/* Invalid field in CDB */
+		/* Invalid field in CDB */
+		sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
 	else
-		printk(KERN_ERR "%s: asking for cache data failed\n",
-		       diskname);
+		sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");
 
 defaults:
-	printk(KERN_ERR "%s: assuming drive cache: write through\n",
-	       diskname);
+	sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n");
 	sdkp->WCE = 0;
 	sdkp->RCD = 0;
 	sdkp->DPOFUA = 0;
@@ -1544,7 +1505,8 @@ static int sd_revalidate_disk(struct gen
 	unsigned char *buffer;
 	unsigned ordered;
 
-	SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
+	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
+				      "sd_revalidate_disk\n"));
 
 	/*
 	 * If the device is offline, don't try and read capacity or any
@@ -1555,8 +1517,8 @@ static int sd_revalidate_disk(struct gen
 
 	buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
 	if (!buffer) {
-		printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
-		       "failure.\n");
+		sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory "
+			  "allocation failure.\n");
 		goto out;
 	}
 
@@ -1568,16 +1530,16 @@ static int sd_revalidate_disk(struct gen
 	sdkp->WCE = 0;
 	sdkp->RCD = 0;
 
-	sd_spinup_disk(sdkp, disk->disk_name);
+	sd_spinup_disk(sdkp);
 
 	/*
 	 * Without media there is no reason to ask; moreover, some devices
 	 * react badly if we do.
 	 */
 	if (sdkp->media_present) {
-		sd_read_capacity(sdkp, disk->disk_name, buffer);
-		sd_read_write_protect_flag(sdkp, disk->disk_name, buffer);
-		sd_read_cache_type(sdkp, disk->disk_name, buffer);
+		sd_read_capacity(sdkp, buffer);
+		sd_read_write_protect_flag(sdkp, buffer);
+		sd_read_cache_type(sdkp, buffer);
 	}
 
 	/*
@@ -1709,8 +1671,8 @@ static int sd_probe(struct device *dev)
 	dev_set_drvdata(dev, sdkp);
 	add_disk(gd);
 
-	sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n",
-		    sdp->removable ? "removable " : "", gd->disk_name);
+	sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+		  sdp->removable ? "removable " : "");
 
 	return 0;
 
@@ -1774,6 +1736,31 @@ static void scsi_disk_release(struct cla
 	kfree(sdkp);
 }
 
+static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
+{
+	unsigned char cmd[6] = { START_STOP };	/* START_VALID */
+	struct scsi_sense_hdr sshdr;
+	struct scsi_device *sdp = sdkp->device;
+	int res;
+
+	if (start)
+		cmd[4] |= 1;	/* START */
+
+	if (!scsi_device_online(sdp))
+		return -ENODEV;
+
+	res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+			       SD_TIMEOUT, SD_MAX_RETRIES);
+	if (res) {
+		sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
+		sd_print_result(sdkp, res);
+		if (driver_byte(res) & DRIVER_SENSE)
+			sd_print_sense_hdr(sdkp, &sshdr);
+	}
+
+	return res;
+}
+
 /*
  * Send a SYNCHRONIZE CACHE instruction down to the device through
  * the normal SCSI command structure.  Wait for the command to
@@ -1781,20 +1768,62 @@ static void scsi_disk_release(struct cla
  */
 static void sd_shutdown(struct device *dev)
 {
-	struct scsi_device *sdp = to_scsi_device(dev);
 	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
 
 	if (!sdkp)
 		return;         /* this can happen */
 
 	if (sdkp->WCE) {
-		printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
-				sdkp->disk->disk_name);
-		sd_sync_cache(sdp);
+		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+		sd_sync_cache(sdkp);
+	}
+
+	if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+		sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+		sd_start_stop_device(sdkp, 0);
 	}
+
 	scsi_disk_put(sdkp);
 }
 
+static int sd_suspend(struct device *dev, pm_message_t mesg)
+{
+	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+	int ret;
+
+	if (!sdkp)
+		return 0;	/* this can happen */
+
+	if (sdkp->WCE) {
+		sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+		ret = sd_sync_cache(sdkp);
+		if (ret)
+			return ret;
+	}
+
+	if (mesg.event == PM_EVENT_SUSPEND &&
+	    sdkp->device->manage_start_stop) {
+		sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+		ret = sd_start_stop_device(sdkp, 0);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sd_resume(struct device *dev)
+{
+	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+
+	if (!sdkp->device->manage_start_stop)
+		return 0;
+
+	sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
+
+	return sd_start_stop_device(sdkp, 1);
+}
+
 /**
  *	init_sd - entry point for this driver (both when built in or when
  *	a module).
@@ -1852,3 +1881,19 @@ static void __exit exit_sd(void)
 
 module_init(init_sd);
 module_exit(exit_sd);
+
+static void sd_print_sense_hdr(struct scsi_disk *sdkp,
+			       struct scsi_sense_hdr *sshdr)
+{
+	sd_printk(KERN_INFO, sdkp, "");
+	scsi_show_sense_hdr(sshdr);
+	sd_printk(KERN_INFO, sdkp, "");
+	scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+
+static void sd_print_result(struct scsi_disk *sdkp, int result)
+{
+	sd_printk(KERN_INFO, sdkp, "");
+	scsi_show_result(result);
+}
+
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 81e3bc7..0c691a6 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -41,7 +41,6 @@ #include <linux/ioctl.h>
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
 #include <linux/cdev.h>
 #include <linux/seq_file.h>
@@ -917,6 +916,8 @@ sg_ioctl(struct inode *inode, struct fil
 			return result;
                 if (val < 0)
                         return -EINVAL;
+		val = min_t(int, val,
+				sdp->device->request_queue->max_sectors * 512);
 		if (val != sfp->reserve.bufflen) {
 			if (sg_res_in_use(sfp) || sfp->mmap_called)
 				return -EBUSY;
@@ -925,7 +926,8 @@ sg_ioctl(struct inode *inode, struct fil
 		}
 		return 0;
 	case SG_GET_RESERVED_SIZE:
-		val = (int) sfp->reserve.bufflen;
+		val = min_t(int, sfp->reserve.bufflen,
+				sdp->device->request_queue->max_sectors * 512);
 		return put_user(val, ip);
 	case SG_SET_COMMAND_Q:
 		result = get_user(val, ip);
@@ -1061,6 +1063,9 @@ sg_ioctl(struct inode *inode, struct fil
 		if (sdp->detached)
 			return -ENODEV;
 		return scsi_ioctl(sdp->device, cmd_in, p);
+	case BLKSECTGET:
+		return put_user(sdp->device->request_queue->max_sectors * 512,
+				ip);
 	default:
 		if (read_only)
 			return -EPERM;	/* don't know so take safe approach */
@@ -2339,6 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
 {
 	Sg_fd *sfp;
 	unsigned long iflags;
+	int bufflen;
 
 	sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
 	if (!sfp)
@@ -2369,7 +2375,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
 	if (unlikely(sg_big_buff != def_reserved_size))
 		sg_big_buff = def_reserved_size;
 
-	sg_build_reserve(sfp, sg_big_buff);
+	bufflen = min_t(int, sg_big_buff,
+			sdp->device->request_queue->max_sectors * 512);
+	sg_build_reserve(sfp, bufflen);
 	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
 			   sfp->reserve.bufflen, sfp->reserve.k_use_sg));
 	return sfp;
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 6bc5051..a7dfb65 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -98,7 +98,7 @@ static int __init snirm710_probe(struct 
 	host->this_id = 7;
 	host->base = base;
 	host->irq = platform_get_irq(dev, 0);
-	if(request_irq(host->irq, NCR_700_intr, SA_SHIRQ, "snirm710", host)) {
+	if(request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "snirm710", host)) {
 		printk(KERN_ERR "snirm710: request_irq failed!\n");
 		goto out_put_host;
 	}
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 1857d68..f9a52af 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -62,6 +62,8 @@ #include "sr.h"
 MODULE_DESCRIPTION("SCSI cdrom (sr) driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
 
 #define SR_DISKS	256
 
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 98d8411..55bfecc 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -89,6 +89,7 @@ MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI tape (st) driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
 
 /* Set 'perm' (4th argument) to 0 to disable module_param's definition
  * of sysfs parameters (which module_param doesn't yet support).
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
new file mode 100644
index 0000000..bbeb245
--- /dev/null
+++ b/drivers/scsi/sun_esp.c
@@ -0,0 +1,635 @@
+/* sun_esp.c: ESP front-end for Sparc SBUS systems.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/sbus.h>
+
+#include <scsi/scsi_host.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME		"sun_esp"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_VERSION		"1.000"
+#define DRV_MODULE_RELDATE	"April 19, 2007"
+
+#define dma_read32(REG) \
+	sbus_readl(esp->dma_regs + (REG))
+#define dma_write32(VAL, REG) \
+	sbus_writel((VAL), esp->dma_regs + (REG))
+
+static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct sbus_dma *dma;
+
+	if (dma_sdev != NULL) {
+		for_each_dvma(dma) {
+			if (dma->sdev == dma_sdev)
+				break;
+		}
+	} else {
+		for_each_dvma(dma) {
+			if (dma->sdev == NULL)
+				break;
+
+			/* If bus + slot are the same and it has the
+			 * correct OBP name, it's ours.
+			 */
+			if (sdev->bus == dma->sdev->bus &&
+			    sdev->slot == dma->sdev->slot &&
+			    (!strcmp(dma->sdev->prom_name, "dma") ||
+			     !strcmp(dma->sdev->prom_name, "espdma")))
+				break;
+		}
+	}
+
+	if (dma == NULL) {
+		printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
+		       sdev->ofdev.node->full_name);
+		return -ENODEV;
+	}
+	esp->dma = dma;
+	esp->dma_regs = dma->regs;
+
+	return 0;
+
+}
+
+static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct resource *res;
+
+	/* On HME, two reg sets exist, first is DVMA,
+	 * second is ESP registers.
+	 */
+	if (hme)
+		res = &sdev->resource[1];
+	else
+		res = &sdev->resource[0];
+
+	esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+	if (!esp->regs)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int __devinit esp_sbus_map_command_block(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->dev;
+
+	esp->command_block = sbus_alloc_consistent(sdev, 16,
+						   &esp->command_block_dma);
+	if (!esp->command_block)
+		return -ENOMEM;
+	return 0;
+}
+
+static int __devinit esp_sbus_register_irq(struct esp *esp)
+{
+	struct Scsi_Host *host = esp->host;
+	struct sbus_dev *sdev = esp->dev;
+
+	host->irq = sdev->irqs[0];
+	return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
+}
+
+static void __devinit esp_get_scsi_id(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct device_node *dp = sdev->ofdev.node;
+
+	esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
+	if (esp->scsi_id != 0xff)
+		goto done;
+
+	esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff);
+	if (esp->scsi_id != 0xff)
+		goto done;
+
+	if (!sdev->bus) {
+		/* SUN4 */
+		esp->scsi_id = 7;
+		goto done;
+	}
+
+	esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+					     "scsi-initiator-id", 7);
+
+done:
+	esp->host->this_id = esp->scsi_id;
+	esp->scsi_id_mask = (1 << esp->scsi_id);
+}
+
+static void __devinit esp_get_differential(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct device_node *dp = sdev->ofdev.node;
+
+	if (of_find_property(dp, "differential", NULL))
+		esp->flags |= ESP_FLAG_DIFFERENTIAL;
+	else
+		esp->flags &= ~ESP_FLAG_DIFFERENTIAL;
+}
+
+static void __devinit esp_get_clock_params(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct device_node *dp = sdev->ofdev.node;
+	struct device_node *bus_dp;
+	int fmhz;
+
+	bus_dp = NULL;
+	if (sdev != NULL && sdev->bus != NULL)
+		bus_dp = sdev->bus->ofdev.node;
+
+	fmhz = of_getintprop_default(dp, "clock-frequency", 0);
+	if (fmhz == 0)
+		fmhz = (!bus_dp) ? 0 :
+			of_getintprop_default(bus_dp, "clock-frequency", 0);
+
+	esp->cfreq = fmhz;
+}
+
+static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+{
+	struct sbus_dev *sdev = esp->dev;
+	struct device_node *dp = sdev->ofdev.node;
+	u8 bursts;
+
+	bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
+	if (dma) {
+		struct device_node *dma_dp = dma->ofdev.node;
+		u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+		if (val != 0xff)
+			bursts &= val;
+	}
+
+	if (sdev->bus) {
+		u8 val = of_getintprop_default(sdev->bus->ofdev.node,
+					       "burst-sizes", 0xff);
+		if (val != 0xff)
+			bursts &= val;
+	}
+
+	if (bursts == 0xff ||
+	    (bursts & DMA_BURST16) == 0 ||
+	    (bursts & DMA_BURST32) == 0)
+		bursts = (DMA_BURST32 - 1);
+
+	esp->bursts = bursts;
+}
+
+static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+{
+	esp_get_scsi_id(esp);
+	esp_get_differential(esp);
+	esp_get_clock_params(esp);
+	esp_get_bursts(esp, espdma);
+}
+
+static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+	sbus_writeb(val, esp->regs + (reg * 4UL));
+}
+
+static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
+{
+	return sbus_readb(esp->regs + (reg * 4UL));
+}
+
+static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
+				      size_t sz, int dir)
+{
+	return sbus_map_single(esp->dev, buf, sz, dir);
+}
+
+static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+				  int num_sg, int dir)
+{
+	return sbus_map_sg(esp->dev, sg, num_sg, dir);
+}
+
+static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+				  size_t sz, int dir)
+{
+	sbus_unmap_single(esp->dev, addr, sz, dir);
+}
+
+static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+			      int num_sg, int dir)
+{
+	sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+}
+
+static int sbus_esp_irq_pending(struct esp *esp)
+{
+	if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+		return 1;
+	return 0;
+}
+
+static void sbus_esp_reset_dma(struct esp *esp)
+{
+	int can_do_burst16, can_do_burst32, can_do_burst64;
+	int can_do_sbus64, lim;
+	u32 val;
+
+	can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
+	can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
+	can_do_burst64 = 0;
+	can_do_sbus64 = 0;
+	if (sbus_can_dma_64bit(esp->dev))
+		can_do_sbus64 = 1;
+	if (sbus_can_burst64(esp->sdev))
+		can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
+
+	/* Put the DVMA into a known state. */
+	if (esp->dma->revision != dvmahme) {
+		val = dma_read32(DMA_CSR);
+		dma_write32(val | DMA_RST_SCSI, DMA_CSR);
+		dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+	}
+	switch (esp->dma->revision) {
+	case dvmahme:
+		dma_write32(DMA_RESET_FAS366, DMA_CSR);
+		dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+		esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS |
+					DMA_SCSI_DISAB | DMA_INT_ENAB);
+
+		esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE |
+					  DMA_BRST_SZ);
+
+		if (can_do_burst64)
+			esp->prev_hme_dmacsr |= DMA_BRST64;
+		else if (can_do_burst32)
+			esp->prev_hme_dmacsr |= DMA_BRST32;
+
+		if (can_do_sbus64) {
+			esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
+			sbus_set_sbus64(esp->dev, esp->bursts);
+		}
+
+		lim = 1000;
+		while (dma_read32(DMA_CSR) & DMA_PEND_READ) {
+			if (--lim == 0) {
+				printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ "
+				       "will not clear!\n",
+				       esp->host->unique_id);
+				break;
+			}
+			udelay(1);
+		}
+
+		dma_write32(0, DMA_CSR);
+		dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+		dma_write32(0, DMA_ADDR);
+		break;
+
+	case dvmarev2:
+		if (esp->rev != ESP100) {
+			val = dma_read32(DMA_CSR);
+			dma_write32(val | DMA_3CLKS, DMA_CSR);
+		}
+		break;
+
+	case dvmarev3:
+		val = dma_read32(DMA_CSR);
+		val &= ~DMA_3CLKS;
+		val |= DMA_2CLKS;
+		if (can_do_burst32) {
+			val &= ~DMA_BRST_SZ;
+			val |= DMA_BRST32;
+		}
+		dma_write32(val, DMA_CSR);
+		break;
+
+	case dvmaesc1:
+		val = dma_read32(DMA_CSR);
+		val |= DMA_ADD_ENABLE;
+		val &= ~DMA_BCNT_ENAB;
+		if (!can_do_burst32 && can_do_burst16) {
+			val |= DMA_ESC_BURST;
+		} else {
+			val &= ~(DMA_ESC_BURST);
+		}
+		dma_write32(val, DMA_CSR);
+		break;
+
+	default:
+		break;
+	}
+
+	/* Enable interrupts.  */
+	val = dma_read32(DMA_CSR);
+	dma_write32(val | DMA_INT_ENAB, DMA_CSR);
+}
+
+static void sbus_esp_dma_drain(struct esp *esp)
+{
+	u32 csr;
+	int lim;
+
+	if (esp->dma->revision == dvmahme)
+		return;
+
+	csr = dma_read32(DMA_CSR);
+	if (!(csr & DMA_FIFO_ISDRAIN))
+		return;
+
+	if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+		dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
+
+	lim = 1000;
+	while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
+		if (--lim == 0) {
+			printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
+			       esp->host->unique_id);
+			break;
+		}
+		udelay(1);
+	}
+}
+
+static void sbus_esp_dma_invalidate(struct esp *esp)
+{
+	if (esp->dma->revision == dvmahme) {
+		dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+					 (DMA_PARITY_OFF | DMA_2CLKS |
+					  DMA_SCSI_DISAB | DMA_INT_ENAB)) &
+					~(DMA_ST_WRITE | DMA_ENABLE));
+
+		dma_write32(0, DMA_CSR);
+		dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+		/* This is necessary to avoid having the SCSI channel
+		 * engine lock up on us.
+		 */
+		dma_write32(0, DMA_ADDR);
+	} else {
+		u32 val;
+		int lim;
+
+		lim = 1000;
+		while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
+			if (--lim == 0) {
+				printk(KERN_ALERT PFX "esp%d: DMA will not "
+				       "invalidate!\n", esp->host->unique_id);
+				break;
+			}
+			udelay(1);
+		}
+
+		val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
+		val |= DMA_FIFO_INV;
+		dma_write32(val, DMA_CSR);
+		val &= ~DMA_FIFO_INV;
+		dma_write32(val, DMA_CSR);
+	}
+}
+
+static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+				  u32 dma_count, int write, u8 cmd)
+{
+	u32 csr;
+
+	BUG_ON(!(cmd & ESP_CMD_DMA));
+
+	sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+	sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+	if (esp->rev == FASHME) {
+		sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO);
+		sbus_esp_write8(esp, 0, FAS_RHI);
+
+		scsi_esp_cmd(esp, cmd);
+
+		csr = esp->prev_hme_dmacsr;
+		csr |= DMA_SCSI_DISAB | DMA_ENABLE;
+		if (write)
+			csr |= DMA_ST_WRITE;
+		else
+			csr &= ~DMA_ST_WRITE;
+		esp->prev_hme_dmacsr = csr;
+
+		dma_write32(dma_count, DMA_COUNT);
+		dma_write32(addr, DMA_ADDR);
+		dma_write32(csr, DMA_CSR);
+	} else {
+		csr = dma_read32(DMA_CSR);
+		csr |= DMA_ENABLE;
+		if (write)
+			csr |= DMA_ST_WRITE;
+		else
+			csr &= ~DMA_ST_WRITE;
+		dma_write32(csr, DMA_CSR);
+		if (esp->dma->revision == dvmaesc1) {
+			u32 end = PAGE_ALIGN(addr + dma_count + 16U);
+			dma_write32(end - addr, DMA_COUNT);
+		}
+		dma_write32(addr, DMA_ADDR);
+
+		scsi_esp_cmd(esp, cmd);
+	}
+
+}
+
+static int sbus_esp_dma_error(struct esp *esp)
+{
+	u32 csr = dma_read32(DMA_CSR);
+
+	if (csr & DMA_HNDL_ERROR)
+		return 1;
+
+	return 0;
+}
+
+static const struct esp_driver_ops sbus_esp_ops = {
+	.esp_write8	=	sbus_esp_write8,
+	.esp_read8	=	sbus_esp_read8,
+	.map_single	=	sbus_esp_map_single,
+	.map_sg		=	sbus_esp_map_sg,
+	.unmap_single	=	sbus_esp_unmap_single,
+	.unmap_sg	=	sbus_esp_unmap_sg,
+	.irq_pending	=	sbus_esp_irq_pending,
+	.reset_dma	=	sbus_esp_reset_dma,
+	.dma_drain	=	sbus_esp_dma_drain,
+	.dma_invalidate	=	sbus_esp_dma_invalidate,
+	.send_dma_cmd	=	sbus_esp_send_dma_cmd,
+	.dma_error	=	sbus_esp_dma_error,
+};
+
+static int __devinit esp_sbus_probe_one(struct device *dev,
+					struct sbus_dev *esp_dev,
+					struct sbus_dev *espdma,
+					struct sbus_bus *sbus,
+					int hme)
+{
+	struct scsi_host_template *tpnt = &scsi_esp_template;
+	struct Scsi_Host *host;
+	struct esp *esp;
+	int err;
+
+	host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+	err = -ENOMEM;
+	if (!host)
+		goto fail;
+
+	host->max_id = (hme ? 16 : 8);
+	esp = host_to_esp(host);
+
+	esp->host = host;
+	esp->dev = esp_dev;
+	esp->ops = &sbus_esp_ops;
+
+	if (hme)
+		esp->flags |= ESP_FLAG_WIDE_CAPABLE;
+
+	err = esp_sbus_find_dma(esp, espdma);
+	if (err < 0)
+		goto fail_unlink;
+
+	err = esp_sbus_map_regs(esp, hme);
+	if (err < 0)
+		goto fail_unlink;
+
+	err = esp_sbus_map_command_block(esp);
+	if (err < 0)
+		goto fail_unmap_regs;
+
+	err = esp_sbus_register_irq(esp);
+	if (err < 0)
+		goto fail_unmap_command_block;
+
+	esp_sbus_get_props(esp, espdma);
+
+	/* Before we try to touch the ESP chip, ESC1 dma can
+	 * come up with the reset bit set, so make sure that
+	 * is clear first.
+	 */
+	if (esp->dma->revision == dvmaesc1) {
+		u32 val = dma_read32(DMA_CSR);
+
+		dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+	}
+
+	dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+	err = scsi_esp_register(esp, dev);
+	if (err)
+		goto fail_free_irq;
+
+	return 0;
+
+fail_free_irq:
+	free_irq(host->irq, esp);
+fail_unmap_command_block:
+	sbus_free_consistent(esp->dev, 16,
+			     esp->command_block,
+			     esp->command_block_dma);
+fail_unmap_regs:
+	sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+fail_unlink:
+	scsi_host_put(host);
+fail:
+	return err;
+}
+
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+	struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+	struct device_node *dp = dev->node;
+	struct sbus_dev *dma_sdev = NULL;
+	int hme = 0;
+
+	if (dp->parent &&
+	    (!strcmp(dp->parent->name, "espdma") ||
+	     !strcmp(dp->parent->name, "dma")))
+		dma_sdev = sdev->parent;
+	else if (!strcmp(dp->name, "SUNW,fas")) {
+		dma_sdev = sdev;
+		hme = 1;
+	}
+
+	return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
+				  sdev->bus, hme);
+}
+
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+	struct esp *esp = dev_get_drvdata(&dev->dev);
+	unsigned int irq = esp->host->irq;
+	u32 val;
+
+	scsi_esp_unregister(esp);
+
+	/* Disable interrupts.  */
+	val = dma_read32(DMA_CSR);
+	dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
+
+	free_irq(irq, esp);
+	sbus_free_consistent(esp->dev, 16,
+			     esp->command_block,
+			     esp->command_block_dma);
+	sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+	scsi_host_put(esp->host);
+
+	return 0;
+}
+
+static struct of_device_id esp_match[] = {
+	{
+		.name = "SUNW,esp",
+	},
+	{
+		.name = "SUNW,fas",
+	},
+	{
+		.name = "esp",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+	.name		= "esp",
+	.match_table	= esp_match,
+	.probe		= esp_sbus_probe,
+	.remove		= __devexit_p(esp_sbus_remove),
+};
+
+static int __init sunesp_init(void)
+{
+	return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit sunesp_exit(void)
+{
+	of_unregister_driver(&esp_sbus_driver);
+}
+
+MODULE_DESCRIPTION("Sun ESP SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sunesp_init);
+module_exit(sunesp_exit);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index a583e89..3158949 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2680,7 +2680,7 @@ static int __init dc390_module_init(void
 		printk (KERN_INFO "DC390: Using safe settings.\n");
 	}
 
-	return pci_module_init(&dc390_driver);
+	return pci_register_driver(&dc390_driver);
 }
 
 static void __exit dc390_module_exit(void)
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 90621c3..48e259a 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -251,9 +251,16 @@ static const struct serial8250_config ua
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
 		.flags		= UART_CAP_FIFO | UART_CAP_UUE,
 	},
+	[PORT_RM9000] = {
+		.name		= "RM9000",
+		.fifo_size	= 16,
+		.tx_loadsz	= 16,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
-#ifdef CONFIG_SERIAL_8250_AU1X00
+#if defined (CONFIG_SERIAL_8250_AU1X00)
 
 /* Au1x00 UART hardware has a weird register layout */
 static const u8 au_io_in_map[] = {
@@ -289,6 +296,44 @@ static inline int map_8250_out_reg(struc
 	return au_io_out_map[offset];
 }
 
+#elif defined (CONFIG_SERIAL_8250_RM9K)
+
+static const u8
+	regmap_in[8] = {
+		[UART_RX]	= 0x00,
+		[UART_IER]	= 0x0c,
+		[UART_IIR]	= 0x14,
+		[UART_LCR]	= 0x1c,
+		[UART_MCR]	= 0x20,
+		[UART_LSR]	= 0x24,
+		[UART_MSR]	= 0x28,
+		[UART_SCR]	= 0x2c
+	},
+	regmap_out[8] = {
+		[UART_TX] 	= 0x04,
+		[UART_IER]	= 0x0c,
+		[UART_FCR]	= 0x18,
+		[UART_LCR]	= 0x1c,
+		[UART_MCR]	= 0x20,
+		[UART_LSR]	= 0x24,
+		[UART_MSR]	= 0x28,
+		[UART_SCR]	= 0x2c
+	};
+
+static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+{
+	if (up->port.iotype != UPIO_RM9000)
+		return offset;
+	return regmap_in[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+{
+	if (up->port.iotype != UPIO_RM9000)
+		return offset;
+	return regmap_out[offset];
+}
+
 #else
 
 /* sane hardware needs no mapping */
@@ -308,8 +353,10 @@ static unsigned int serial_in(struct uar
 		return inb(up->port.iobase + 1);
 
 	case UPIO_MEM:
+	case UPIO_DWAPB:
 		return readb(up->port.membase + offset);
 
+	case UPIO_RM9000:
 	case UPIO_MEM32:
 		return readl(up->port.membase + offset);
 
@@ -333,6 +380,8 @@ #endif
 static void
 serial_out(struct uart_8250_port *up, int offset, int value)
 {
+	/* Save the offset before it's remapped */
+	int save_offset = offset;
 	offset = map_8250_out_reg(up, offset) << up->port.regshift;
 
 	switch (up->port.iotype) {
@@ -345,6 +394,7 @@ serial_out(struct uart_8250_port *up, in
 		writeb(value, up->port.membase + offset);
 		break;
 
+	case UPIO_RM9000:
 	case UPIO_MEM32:
 		writel(value, up->port.membase + offset);
 		break;
@@ -359,6 +409,18 @@ #endif
 			writeb(value, up->port.membase + offset);
 		break;
 
+	case UPIO_DWAPB:
+		/* Save the LCR value so it can be re-written when a
+		 * Busy Detect interrupt occurs. */
+		if (save_offset == UART_LCR)
+			up->lcr = value;
+		writeb(value, up->port.membase + offset);
+		/* Read the IER to ensure any interrupt is cleared before
+		 * returning from ISR. */
+		if (save_offset == UART_TX || save_offset == UART_IER)
+			value = serial_in(up, UART_IER);
+		break;
+
 	default:
 		outb(value, up->port.iobase + offset);
 	}
@@ -373,6 +435,7 @@ serial_out_sync(struct uart_8250_port *u
 #ifdef CONFIG_SERIAL_8250_AU1X00
 	case UPIO_AU:
 #endif
+	case UPIO_DWAPB:
 		serial_out(up, offset, value);
 		serial_in(up, UART_LCR);	/* safe, no side-effects */
 		break;
@@ -403,7 +466,7 @@ static inline void _serial_dl_write(stru
 	serial_outp(up, UART_DLM, value >> 8 & 0xff);
 }
 
-#ifdef CONFIG_SERIAL_8250_AU1X00
+#if defined (CONFIG_SERIAL_8250_AU1X00)
 /* Au1x00 haven't got a standard divisor latch */
 static int serial_dl_read(struct uart_8250_port *up)
 {
@@ -420,6 +483,24 @@ static void serial_dl_write(struct uart_
 	else
 		_serial_dl_write(up, value);
 }
+#elif defined (CONFIG_SERIAL_8250_RM9K)
+static int serial_dl_read(struct uart_8250_port *up)
+{
+	return	(up->port.iotype == UPIO_RM9000) ?
+		(((__raw_readl(up->port.membase + 0x10) << 8) |
+		(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
+		_serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+	if (up->port.iotype == UPIO_RM9000) {
+		__raw_writel(value, up->port.membase + 0x08);
+		__raw_writel(value >> 8, up->port.membase + 0x10);
+	} else {
+		_serial_dl_write(up, value);
+	}
+}
 #else
 #define serial_dl_read(up) _serial_dl_read(up)
 #define serial_dl_write(up, value) _serial_dl_write(up, value)
@@ -621,7 +702,7 @@ static unsigned int autoconfig_read_divi
  * its clones.  (We treat the broken original StarTech 16650 V1 as a
  * 16550, and why not?  Startech doesn't seem to even acknowledge its
  * existence.)
- * 
+ *
  * What evil have men's minds wrought...
  */
 static void autoconfig_has_efr(struct uart_8250_port *up)
@@ -674,7 +755,7 @@ static void autoconfig_has_efr(struct ua
 			up->bugs |= UART_BUG_QUOT;
 		return;
 	}
-	
+
 	/*
 	 * We check for a XR16C850 by setting DLL and DLM to 0, and then
 	 * reading back DLL and DLM.  The chip type depends on the DLM
@@ -817,7 +898,7 @@ static void autoconfig_16550a(struct uar
 			status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
 			status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
 			serial_outp(up, 0x04, status1);
-			
+
 			serial_dl_write(up, quot);
 
 			serial_outp(up, UART_LCR, 0);
@@ -913,7 +994,6 @@ static void autoconfig(struct uart_8250_
 	 * be frobbing the chips IRQ enable register to see if it exists.
 	 */
 	spin_lock_irqsave(&up->port.lock, flags);
-//	save_flags(flags); cli();
 
 	up->capabilities = 0;
 	up->bugs = 0;
@@ -922,7 +1002,7 @@ static void autoconfig(struct uart_8250_
 		/*
 		 * Do a simple existence test first; if we fail this,
 		 * there's no point trying anything else.
-		 * 
+		 *
 		 * 0x80 is used as a nonsense port to prevent against
 		 * false positives due to ISA bus float.  The
 		 * assumption is that 0x80 is a non-existent port;
@@ -961,7 +1041,7 @@ #endif
 	save_mcr = serial_in(up, UART_MCR);
 	save_lcr = serial_in(up, UART_LCR);
 
-	/* 
+	/*
 	 * Check to see if a UART is really there.  Certain broken
 	 * internal modems based on the Rockwell chipset fail this
 	 * test, because they apparently don't implement the loopback
@@ -1068,9 +1148,8 @@ #endif
 	else
 		serial_outp(up, UART_IER, 0);
 
- out:	
+ out:
 	spin_unlock_irqrestore(&up->port.lock, flags);
-//	restore_flags(flags);
 	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
 }
 
@@ -1094,7 +1173,7 @@ static void autoconfig_irq(struct uart_8
 	save_mcr = serial_inp(up, UART_MCR);
 	save_ier = serial_inp(up, UART_IER);
 	serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-	
+
 	irqs = probe_irq_on();
 	serial_outp(up, UART_MCR, 0);
 	udelay (10);
@@ -1159,8 +1238,11 @@ static void serial8250_start_tx(struct u
 		if (up->bugs & UART_BUG_TXEN) {
 			unsigned char lsr, iir;
 			lsr = serial_in(up, UART_LSR);
-			iir = serial_in(up, UART_IIR);
-			if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)
+			iir = serial_in(up, UART_IIR) & 0x0f;
+			if ((up->port.type == PORT_RM9000) ?
+				(lsr & UART_LSR_THRE &&
+				(iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
+				(lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
 				transmit_chars(up);
 		}
 	}
@@ -1389,6 +1471,19 @@ static irqreturn_t serial8250_interrupt(
 			handled = 1;
 
 			end = NULL;
+		} else if (up->port.iotype == UPIO_DWAPB &&
+			  (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+			/* The DesignWare APB UART has an Busy Detect (0x07)
+			 * interrupt meaning an LCR write attempt occured while the
+			 * UART was busy. The interrupt must be cleared by reading
+			 * the UART status register (USR) and the LCR re-written. */
+			unsigned int status;
+			status = *(volatile u32 *)up->port.private_data;
+			serial_out(up, UART_LCR, up->lcr);
+
+			handled = 1;
+
+			end = NULL;
 		} else if (end == NULL)
 			end = l;
 
@@ -1928,7 +2023,7 @@ #endif
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
 	quot = serial8250_get_divisor(port, baud);
 
 	/*
@@ -2090,6 +2185,7 @@ static int serial8250_request_std_resour
 	case UPIO_TSI:
 	case UPIO_MEM32:
 	case UPIO_MEM:
+	case UPIO_DWAPB:
 		if (!up->port.mapbase)
 			break;
 
@@ -2127,6 +2223,7 @@ static void serial8250_release_std_resou
 	case UPIO_TSI:
 	case UPIO_MEM32:
 	case UPIO_MEM:
+	case UPIO_DWAPB:
 		if (!up->port.mapbase)
 			break;
 
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ad9f321..e8efe93 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -73,17 +73,21 @@ config SERIAL_8250_PCI
 	depends on SERIAL_8250 && PCI
 	default SERIAL_8250
 	help
-	  This builds standard PCI serial support. You may be able to
-	  disable this feature if you only need legacy serial support.
-	  Saves about 9K.
+	  Say Y here if you have PCI serial ports.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_pci.
 
 config SERIAL_8250_PNP
 	tristate "8250/16550 PNP device support" if EMBEDDED
 	depends on SERIAL_8250 && PNP
 	default SERIAL_8250
 	help
-	  This builds standard PNP serial support. You may be able to
-	  disable this feature if you only need legacy serial support.
+	  Say Y here if you have serial ports described by PNPBIOS or ACPI.
+	  These are typically ports built into the system board.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_pnp.
 
 config SERIAL_8250_HP300
 	tristate
@@ -254,6 +258,15 @@ config SERIAL_8250_AU1X00
 	  to this option.  The driver can handle 1 or 2 serial ports.
 	  If unsure, say N.
 
+config SERIAL_8250_RM9K
+	bool "Support for MIPS RM9xxx integrated serial port"
+	depends on SERIAL_8250 != n && SERIAL_RM9000
+	select SERIAL_8250_SHARE_IRQ
+	help
+	  Selecting this option will add support for the integrated serial
+	  port hardware found on MIPS RM9122 and similar processors.
+	  If unsure, say N.
+
 comment "Non-8250 serial port support"
 
 config SERIAL_AMBA_PL010
@@ -499,6 +512,100 @@ config SERIAL_SA1100_CONSOLE
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
+config SERIAL_BFIN
+	tristate "Blackfin serial port support"
+	depends on BFIN
+	select SERIAL_CORE
+	select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
+	help
+	  Add support for the built-in UARTs on the Blackfin.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bfin_5xx.
+
+config SERIAL_BFIN_CONSOLE
+	bool "Console on Blackfin serial port"
+	depends on SERIAL_BFIN
+	select SERIAL_CORE_CONSOLE
+
+choice
+	prompt "UART Mode"
+	depends on SERIAL_BFIN
+	default SERIAL_BFIN_DMA
+	help
+	  This driver supports the built-in serial ports of the Blackfin family
+	  of CPUs
+
+config SERIAL_BFIN_DMA
+	bool "DMA mode"
+	depends on DMA_UNCACHED_1M
+	help
+	  This driver works under DMA mode. If this option is selected, the
+	  blackfin simple dma driver is also enabled.
+
+config SERIAL_BFIN_PIO
+	bool "PIO mode"
+	help
+	  This driver works under PIO mode.
+
+endchoice
+
+config SERIAL_BFIN_UART0
+	bool "Enable UART0"
+	depends on SERIAL_BFIN
+	help
+	  Enable UART0
+
+config BFIN_UART0_CTSRTS
+	bool "Enable UART0 hardware flow control"
+	depends on SERIAL_BFIN_UART0
+	help
+	  Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+	  signal.
+
+config UART0_CTS_PIN
+	int "UART0 CTS pin"
+	depends on BFIN_UART0_CTSRTS
+	default 23
+	help
+	  The default pin is GPIO_GP7.
+	  Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config UART0_RTS_PIN
+	int "UART0 RTS pin"
+	depends on BFIN_UART0_CTSRTS
+	default 22
+	help
+	  The default pin is GPIO_GP6.
+	  Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config SERIAL_BFIN_UART1
+	bool "Enable UART1"
+	depends on SERIAL_BFIN && (BF534 || BF536 || BF537)
+	help
+	  Enable UART1
+
+config BFIN_UART1_CTSRTS
+	bool "Enable UART1 hardware flow control"
+	depends on SERIAL_BFIN_UART1
+	help
+	  Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+	  signal.
+
+config UART1_CTS_PIN
+	int "UART1 CTS pin"
+	depends on BFIN_UART1_CTSRTS
+	default -1
+	help
+	  Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config UART1_RTS_PIN
+	int "UART1 RTS pin"
+	depends on BFIN_UART1_CTSRTS
+	default -1
+	help
+	  Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
 config SERIAL_IMX
 	bool "IMX serial port support"
 	depends on ARM && ARCH_IMX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 6b3560c..4959bcb 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_CLPS711X) += clps711
 obj-$(CONFIG_SERIAL_PXA) += pxa.o
 obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
 obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
+obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
 obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index f69bd09..1a9a24b 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -48,6 +48,7 @@ #include <linux/serial_core.h>
 #include <linux/serial.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 
@@ -70,6 +71,7 @@ #define UART_PORT_SIZE		64
  */
 struct uart_amba_port {
 	struct uart_port	port;
+	struct clk		*clk;
 	struct amba_device	*dev;
 	struct amba_pl010_data	*data;
 	unsigned int		old_status;
@@ -77,73 +79,77 @@ struct uart_amba_port {
 
 static void pl010_stop_tx(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int cr;
 
-	cr = readb(port->membase + UART010_CR);
+	cr = readb(uap->port.membase + UART010_CR);
 	cr &= ~UART010_CR_TIE;
-	writel(cr, port->membase + UART010_CR);
+	writel(cr, uap->port.membase + UART010_CR);
 }
 
 static void pl010_start_tx(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int cr;
 
-	cr = readb(port->membase + UART010_CR);
+	cr = readb(uap->port.membase + UART010_CR);
 	cr |= UART010_CR_TIE;
-	writel(cr, port->membase + UART010_CR);
+	writel(cr, uap->port.membase + UART010_CR);
 }
 
 static void pl010_stop_rx(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int cr;
 
-	cr = readb(port->membase + UART010_CR);
+	cr = readb(uap->port.membase + UART010_CR);
 	cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
-	writel(cr, port->membase + UART010_CR);
+	writel(cr, uap->port.membase + UART010_CR);
 }
 
 static void pl010_enable_ms(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int cr;
 
-	cr = readb(port->membase + UART010_CR);
+	cr = readb(uap->port.membase + UART010_CR);
 	cr |= UART010_CR_MSIE;
-	writel(cr, port->membase + UART010_CR);
+	writel(cr, uap->port.membase + UART010_CR);
 }
 
-static void pl010_rx_chars(struct uart_port *port)
+static void pl010_rx_chars(struct uart_amba_port *uap)
 {
-	struct tty_struct *tty = port->info->tty;
+	struct tty_struct *tty = uap->port.info->tty;
 	unsigned int status, ch, flag, rsr, max_count = 256;
 
-	status = readb(port->membase + UART01x_FR);
+	status = readb(uap->port.membase + UART01x_FR);
 	while (UART_RX_DATA(status) && max_count--) {
-		ch = readb(port->membase + UART01x_DR);
+		ch = readb(uap->port.membase + UART01x_DR);
 		flag = TTY_NORMAL;
 
-		port->icount.rx++;
+		uap->port.icount.rx++;
 
 		/*
 		 * Note that the error handling code is
 		 * out of the main execution path
 		 */
-		rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
+		rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
 		if (unlikely(rsr & UART01x_RSR_ANY)) {
-			writel(0, port->membase + UART01x_ECR);
+			writel(0, uap->port.membase + UART01x_ECR);
 
 			if (rsr & UART01x_RSR_BE) {
 				rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
-				port->icount.brk++;
-				if (uart_handle_break(port))
+				uap->port.icount.brk++;
+				if (uart_handle_break(&uap->port))
 					goto ignore_char;
 			} else if (rsr & UART01x_RSR_PE)
-				port->icount.parity++;
+				uap->port.icount.parity++;
 			else if (rsr & UART01x_RSR_FE)
-				port->icount.frame++;
+				uap->port.icount.frame++;
 			if (rsr & UART01x_RSR_OE)
-				port->icount.overrun++;
+				uap->port.icount.overrun++;
 
-			rsr &= port->read_status_mask;
+			rsr &= uap->port.read_status_mask;
 
 			if (rsr & UART01x_RSR_BE)
 				flag = TTY_BREAK;
@@ -153,53 +159,52 @@ static void pl010_rx_chars(struct uart_p
 				flag = TTY_FRAME;
 		}
 
-		if (uart_handle_sysrq_char(port, ch))
+		if (uart_handle_sysrq_char(&uap->port, ch))
 			goto ignore_char;
 
-		uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
+		uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
 
 	ignore_char:
-		status = readb(port->membase + UART01x_FR);
+		status = readb(uap->port.membase + UART01x_FR);
 	}
 	tty_flip_buffer_push(tty);
 	return;
 }
 
-static void pl010_tx_chars(struct uart_port *port)
+static void pl010_tx_chars(struct uart_amba_port *uap)
 {
-	struct circ_buf *xmit = &port->info->xmit;
+	struct circ_buf *xmit = &uap->port.info->xmit;
 	int count;
 
-	if (port->x_char) {
-		writel(port->x_char, port->membase + UART01x_DR);
-		port->icount.tx++;
-		port->x_char = 0;
+	if (uap->port.x_char) {
+		writel(uap->port.x_char, uap->port.membase + UART01x_DR);
+		uap->port.icount.tx++;
+		uap->port.x_char = 0;
 		return;
 	}
-	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-		pl010_stop_tx(port);
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+		pl010_stop_tx(&uap->port);
 		return;
 	}
 
-	count = port->fifosize >> 1;
+	count = uap->port.fifosize >> 1;
 	do {
-		writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
+		writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-		port->icount.tx++;
+		uap->port.icount.tx++;
 		if (uart_circ_empty(xmit))
 			break;
 	} while (--count > 0);
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(port);
+		uart_write_wakeup(&uap->port);
 
 	if (uart_circ_empty(xmit))
-		pl010_stop_tx(port);
+		pl010_stop_tx(&uap->port);
 }
 
-static void pl010_modem_status(struct uart_port *port)
+static void pl010_modem_status(struct uart_amba_port *uap)
 {
-	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int status, delta;
 
 	writel(0, uap->port.membase + UART010_ICR);
@@ -226,47 +231,50 @@ static void pl010_modem_status(struct ua
 
 static irqreturn_t pl010_int(int irq, void *dev_id)
 {
-	struct uart_port *port = dev_id;
+	struct uart_amba_port *uap = dev_id;
 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
 	int handled = 0;
 
-	spin_lock(&port->lock);
+	spin_lock(&uap->port.lock);
 
-	status = readb(port->membase + UART010_IIR);
+	status = readb(uap->port.membase + UART010_IIR);
 	if (status) {
 		do {
 			if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
-				pl010_rx_chars(port);
+				pl010_rx_chars(uap);
 			if (status & UART010_IIR_MIS)
-				pl010_modem_status(port);
+				pl010_modem_status(uap);
 			if (status & UART010_IIR_TIS)
-				pl010_tx_chars(port);
+				pl010_tx_chars(uap);
 
 			if (pass_counter-- == 0)
 				break;
 
-			status = readb(port->membase + UART010_IIR);
+			status = readb(uap->port.membase + UART010_IIR);
 		} while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
 				   UART010_IIR_TIS));
 		handled = 1;
 	}
 
-	spin_unlock(&port->lock);
+	spin_unlock(&uap->port.lock);
 
 	return IRQ_RETVAL(handled);
 }
 
 static unsigned int pl010_tx_empty(struct uart_port *port)
 {
-	return readb(port->membase + UART01x_FR) & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+	unsigned int status = readb(uap->port.membase + UART01x_FR);
+	return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
 }
 
 static unsigned int pl010_get_mctrl(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int result = 0;
 	unsigned int status;
 
-	status = readb(port->membase + UART01x_FR);
+	status = readb(uap->port.membase + UART01x_FR);
 	if (status & UART01x_FR_DCD)
 		result |= TIOCM_CAR;
 	if (status & UART01x_FR_DSR)
@@ -287,17 +295,18 @@ static void pl010_set_mctrl(struct uart_
 
 static void pl010_break_ctl(struct uart_port *port, int break_state)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned long flags;
 	unsigned int lcr_h;
 
-	spin_lock_irqsave(&port->lock, flags);
-	lcr_h = readb(port->membase + UART010_LCRH);
+	spin_lock_irqsave(&uap->port.lock, flags);
+	lcr_h = readb(uap->port.membase + UART010_LCRH);
 	if (break_state == -1)
 		lcr_h |= UART01x_LCRH_BRK;
 	else
 		lcr_h &= ~UART01x_LCRH_BRK;
-	writel(lcr_h, port->membase + UART010_LCRH);
-	spin_unlock_irqrestore(&port->lock, flags);
+	writel(lcr_h, uap->port.membase + UART010_LCRH);
+	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
 static int pl010_startup(struct uart_port *port)
@@ -306,48 +315,70 @@ static int pl010_startup(struct uart_por
 	int retval;
 
 	/*
+	 * Try to enable the clock producer.
+	 */
+	retval = clk_enable(uap->clk);
+	if (retval)
+		goto out;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
+
+	/*
 	 * Allocate the IRQ
 	 */
-	retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port);
+	retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
 	if (retval)
-		return retval;
+		goto clk_dis;
 
 	/*
 	 * initialise the old status of the modem signals
 	 */
-	uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+	uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
 
 	/*
 	 * Finally, enable interrupts
 	 */
 	writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
-	       port->membase + UART010_CR);
+	       uap->port.membase + UART010_CR);
 
 	return 0;
+
+ clk_dis:
+	clk_disable(uap->clk);
+ out:
+	return retval;
 }
 
 static void pl010_shutdown(struct uart_port *port)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
 	/*
 	 * Free the interrupt
 	 */
-	free_irq(port->irq, port);
+	free_irq(uap->port.irq, uap);
 
 	/*
 	 * disable all interrupts, disable the port
 	 */
-	writel(0, port->membase + UART010_CR);
+	writel(0, uap->port.membase + UART010_CR);
 
 	/* disable break condition and fifos */
-	writel(readb(port->membase + UART010_LCRH) &
+	writel(readb(uap->port.membase + UART010_LCRH) &
 		~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
-	       port->membase + UART010_LCRH);
+	       uap->port.membase + UART010_LCRH);
+
+	/*
+	 * Shut down the clock producer
+	 */
+	clk_disable(uap->clk);
 }
 
 static void
 pl010_set_termios(struct uart_port *port, struct ktermios *termios,
 		     struct ktermios *old)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int lcr_h, old_cr;
 	unsigned long flags;
 	unsigned int baud, quot;
@@ -355,7 +386,7 @@ pl010_set_termios(struct uart_port *port
 	/*
 	 * Ask the core to calculate the divisor for us.
 	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
+	baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); 
 	quot = uart_get_divisor(port, baud);
 
 	switch (termios->c_cflag & CSIZE) {
@@ -379,66 +410,66 @@ pl010_set_termios(struct uart_port *port
 		if (!(termios->c_cflag & PARODD))
 			lcr_h |= UART01x_LCRH_EPS;
 	}
-	if (port->fifosize > 1)
+	if (uap->port.fifosize > 1)
 		lcr_h |= UART01x_LCRH_FEN;
 
-	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&uap->port.lock, flags);
 
 	/*
 	 * Update the per-port timeout.
 	 */
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	port->read_status_mask = UART01x_RSR_OE;
+	uap->port.read_status_mask = UART01x_RSR_OE;
 	if (termios->c_iflag & INPCK)
-		port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+		uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
 	if (termios->c_iflag & (BRKINT | PARMRK))
-		port->read_status_mask |= UART01x_RSR_BE;
+		uap->port.read_status_mask |= UART01x_RSR_BE;
 
 	/*
 	 * Characters to ignore
 	 */
-	port->ignore_status_mask = 0;
+	uap->port.ignore_status_mask = 0;
 	if (termios->c_iflag & IGNPAR)
-		port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+		uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
 	if (termios->c_iflag & IGNBRK) {
-		port->ignore_status_mask |= UART01x_RSR_BE;
+		uap->port.ignore_status_mask |= UART01x_RSR_BE;
 		/*
 		 * If we're ignoring parity and break indicators,
 		 * ignore overruns too (for real raw support).
 		 */
 		if (termios->c_iflag & IGNPAR)
-			port->ignore_status_mask |= UART01x_RSR_OE;
+			uap->port.ignore_status_mask |= UART01x_RSR_OE;
 	}
 
 	/*
 	 * Ignore all characters if CREAD is not set.
 	 */
 	if ((termios->c_cflag & CREAD) == 0)
-		port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+		uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
 
 	/* first, disable everything */
-	old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE;
+	old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
 
 	if (UART_ENABLE_MS(port, termios->c_cflag))
 		old_cr |= UART010_CR_MSIE;
 
-	writel(0, port->membase + UART010_CR);
+	writel(0, uap->port.membase + UART010_CR);
 
 	/* Set baud rate */
 	quot -= 1;
-	writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM);
-	writel(quot & 0xff, port->membase + UART010_LCRL);
+	writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
+	writel(quot & 0xff, uap->port.membase + UART010_LCRL);
 
 	/*
 	 * ----------v----------v----------v----------v-----
 	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
 	 * ----------^----------^----------^----------^-----
 	 */
-	writel(lcr_h, port->membase + UART010_LCRH);
-	writel(old_cr, port->membase + UART010_CR);
+	writel(lcr_h, uap->port.membase + UART010_LCRH);
+	writel(old_cr, uap->port.membase + UART010_CR);
 
-	spin_unlock_irqrestore(&port->lock, flags);
+	spin_unlock_irqrestore(&uap->port.lock, flags);
 }
 
 static const char *pl010_type(struct uart_port *port)
@@ -514,47 +545,52 @@ #ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
 
 static void pl010_console_putchar(struct uart_port *port, int ch)
 {
+	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 	unsigned int status;
 
 	do {
-		status = readb(port->membase + UART01x_FR);
+		status = readb(uap->port.membase + UART01x_FR);
 		barrier();
 	} while (!UART_TX_READY(status));
-	writel(ch, port->membase + UART01x_DR);
+	writel(ch, uap->port.membase + UART01x_DR);
 }
 
 static void
 pl010_console_write(struct console *co, const char *s, unsigned int count)
 {
-	struct uart_port *port = &amba_ports[co->index]->port;
+	struct uart_amba_port *uap = amba_ports[co->index];
 	unsigned int status, old_cr;
 
+	clk_enable(uap->clk);
+
 	/*
 	 *	First save the CR then disable the interrupts
 	 */
-	old_cr = readb(port->membase + UART010_CR);
-	writel(UART01x_CR_UARTEN, port->membase + UART010_CR);
+	old_cr = readb(uap->port.membase + UART010_CR);
+	writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
 
-	uart_console_write(port, s, count, pl010_console_putchar);
+	uart_console_write(&uap->port, s, count, pl010_console_putchar);
 
 	/*
 	 *	Finally, wait for transmitter to become empty
 	 *	and restore the TCR
 	 */
 	do {
-		status = readb(port->membase + UART01x_FR);
+		status = readb(uap->port.membase + UART01x_FR);
 		barrier();
 	} while (status & UART01x_FR_BUSY);
-	writel(old_cr, port->membase + UART010_CR);
+	writel(old_cr, uap->port.membase + UART010_CR);
+
+	clk_disable(uap->clk);
 }
 
 static void __init
-pl010_console_get_options(struct uart_port *port, int *baud,
+pl010_console_get_options(struct uart_amba_port *uap, int *baud,
 			     int *parity, int *bits)
 {
-	if (readb(port->membase + UART010_CR) & UART01x_CR_UARTEN) {
+	if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
 		unsigned int lcr_h, quot;
-		lcr_h = readb(port->membase + UART010_LCRH);
+		lcr_h = readb(uap->port.membase + UART010_LCRH);
 
 		*parity = 'n';
 		if (lcr_h & UART01x_LCRH_PEN) {
@@ -569,14 +605,15 @@ pl010_console_get_options(struct uart_po
 		else
 			*bits = 8;
 
-		quot = readb(port->membase + UART010_LCRL) | readb(port->membase + UART010_LCRM) << 8;
-		*baud = port->uartclk / (16 * (quot + 1));
+		quot = readb(uap->port.membase + UART010_LCRL) |
+		       readb(uap->port.membase + UART010_LCRM) << 8;
+		*baud = uap->port.uartclk / (16 * (quot + 1));
 	}
 }
 
 static int __init pl010_console_setup(struct console *co, char *options)
 {
-	struct uart_port *port;
+	struct uart_amba_port *uap;
 	int baud = 38400;
 	int bits = 8;
 	int parity = 'n';
@@ -589,16 +626,18 @@ static int __init pl010_console_setup(st
 	 */
 	if (co->index >= UART_NR)
 		co->index = 0;
-	if (!amba_ports[co->index])
+	uap = amba_ports[co->index];
+	if (!uap)
 		return -ENODEV;
-	port = &amba_ports[co->index]->port;
+
+	uap->port.uartclk = clk_get_rate(uap->clk);
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
-		pl010_console_get_options(port, &baud, &parity, &bits);
+		pl010_console_get_options(uap, &baud, &parity, &bits);
 
-	return uart_set_options(port, co, baud, parity, bits, flow);
+	return uart_set_options(&uap->port, co, baud, parity, bits, flow);
 }
 
 static struct uart_driver amba_reg;
@@ -629,7 +668,7 @@ static struct uart_driver amba_reg = {
 
 static int pl010_probe(struct amba_device *dev, void *id)
 {
-	struct uart_amba_port *port;
+	struct uart_amba_port *uap;
 	void __iomem *base;
 	int i, ret;
 
@@ -642,8 +681,8 @@ static int pl010_probe(struct amba_devic
 		goto out;
 	}
 
-	port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
-	if (!port) {
+	uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+	if (!uap) {
 		ret = -ENOMEM;
 		goto out;
 	}
@@ -654,51 +693,57 @@ static int pl010_probe(struct amba_devic
 		goto free;
 	}
 
-	port->port.dev = &dev->dev;
-	port->port.mapbase = dev->res.start;
-	port->port.membase = base;
-	port->port.iotype = UPIO_MEM;
-	port->port.irq = dev->irq[0];
-	port->port.uartclk = 14745600;
-	port->port.fifosize = 16;
-	port->port.ops = &amba_pl010_pops;
-	port->port.flags = UPF_BOOT_AUTOCONF;
-	port->port.line = i;
-	port->dev = dev;
-	port->data = dev->dev.platform_data;
-
-	amba_ports[i] = port;
-
-	amba_set_drvdata(dev, port);
-	ret = uart_add_one_port(&amba_reg, &port->port);
+	uap->clk = clk_get(&dev->dev, "UARTCLK");
+	if (IS_ERR(uap->clk)) {
+		ret = PTR_ERR(uap->clk);
+		goto unmap;
+	}
+
+	uap->port.dev = &dev->dev;
+	uap->port.mapbase = dev->res.start;
+	uap->port.membase = base;
+	uap->port.iotype = UPIO_MEM;
+	uap->port.irq = dev->irq[0];
+	uap->port.fifosize = 16;
+	uap->port.ops = &amba_pl010_pops;
+	uap->port.flags = UPF_BOOT_AUTOCONF;
+	uap->port.line = i;
+	uap->dev = dev;
+	uap->data = dev->dev.platform_data;
+
+	amba_ports[i] = uap;
+
+	amba_set_drvdata(dev, uap);
+	ret = uart_add_one_port(&amba_reg, &uap->port);
 	if (ret) {
 		amba_set_drvdata(dev, NULL);
 		amba_ports[i] = NULL;
+		clk_put(uap->clk);
+ unmap:
 		iounmap(base);
  free:
-		kfree(port);
+		kfree(uap);
 	}
-
  out:
 	return ret;
 }
 
 static int pl010_remove(struct amba_device *dev)
 {
-	struct uart_amba_port *port = amba_get_drvdata(dev);
+	struct uart_amba_port *uap = amba_get_drvdata(dev);
 	int i;
 
 	amba_set_drvdata(dev, NULL);
 
-	uart_remove_one_port(&amba_reg, &port->port);
+	uart_remove_one_port(&amba_reg, &uap->port);
 
 	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
-		if (amba_ports[i] == port)
+		if (amba_ports[i] == uap)
 			amba_ports[i] = NULL;
 
-	iounmap(port->port.membase);
-	kfree(port);
-
+	iounmap(uap->port.membase);
+	clk_put(uap->clk);
+	kfree(uap);
 	return 0;
 }
 
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 935f48f..3320bcd 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -484,11 +484,16 @@ static void atmel_set_termios(struct uar
 	unsigned long flags;
 	unsigned int mode, imr, quot, baud;
 
+	/* Get current mode register */
+	mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
 	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);
+	if (quot > 65535) {		/* BRGR is 16-bit, so switch to slower clock */
+		quot /= 8;
+		mode |= ATMEL_US_USCLKS_MCK_DIV8;
+	}
 
 	/* byte size */
 	switch (termios->c_cflag & CSIZE) {
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
index 11b4436..e014177 100644
--- a/drivers/serial/atmel_serial.h
+++ b/drivers/serial/atmel_serial.h
@@ -46,6 +46,9 @@ #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_USCLKS_MCK		(0 <<  4)
+#define			ATMEL_US_USCLKS_MCK_DIV8	(1 <<  4)
+#define			ATMEL_US_USCLKS_SCK		(3 <<  4)
 #define		ATMEL_US_CHRL		(3   <<  6)		/* Character Length */
 #define			ATMEL_US_CHRL_5			(0 <<  6)
 #define			ATMEL_US_CHRL_6			(1 <<  6)
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
new file mode 100644
index 0000000..408390f
--- /dev/null
+++ b/drivers/serial/bfin_5xx.c
@@ -0,0 +1,1012 @@
+/*
+ * File:         drivers/serial/bfin_5xx.c
+ * Based on:     Based on drivers/serial/sa1100.c
+ * Author:       Aubrey Li <aubrey.li@analog.com>
+ *
+ * Created:
+ * Description:  Driver for blackfin 5xx serial ports
+ *
+ * Rev:          $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $
+ *
+ * Modified:
+ *               Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/gpio.h>
+#include <asm/mach/bfin_serial_5xx.h>
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/cacheflush.h>
+#endif
+
+/* UART name and device definitions */
+#define BFIN_SERIAL_NAME	"ttyBF"
+#define BFIN_SERIAL_MAJOR	204
+#define BFIN_SERIAL_MINOR	64
+
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+#define DMA_RX_XCOUNT		512
+#define DMA_RX_YCOUNT		(PAGE_SIZE / DMA_RX_XCOUNT)
+
+#define DMA_RX_FLUSH_JIFFIES	5
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
+#else
+static void bfin_serial_do_work(struct work_struct *work);
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
+static void local_put_char(struct bfin_serial_port *uart, char ch);
+#endif
+
+static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
+
+/*
+ * interrupts are disabled on entry
+ */
+static void bfin_serial_stop_tx(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	disable_dma(uart->tx_dma_channel);
+#else
+	unsigned short ier;
+
+	ier = UART_GET_IER(uart);
+	ier &= ~ETBEI;
+	UART_PUT_IER(uart, ier);
+#endif
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void bfin_serial_start_tx(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	bfin_serial_dma_tx_chars(uart);
+#else
+	unsigned short ier;
+	ier = UART_GET_IER(uart);
+	ier |= ETBEI;
+	UART_PUT_IER(uart, ier);
+	bfin_serial_tx_chars(uart);
+#endif
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void bfin_serial_stop_rx(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	unsigned short ier;
+
+	ier = UART_GET_IER(uart);
+	ier &= ~ERBFI;
+	UART_PUT_IER(uart, ier);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void bfin_serial_enable_ms(struct uart_port *port)
+{
+}
+
+#ifdef CONFIG_SERIAL_BFIN_PIO
+static void local_put_char(struct bfin_serial_port *uart, char ch)
+{
+	unsigned short status;
+	int flags = 0;
+
+	spin_lock_irqsave(&uart->port.lock, flags);
+
+	do {
+		status = UART_GET_LSR(uart);
+	} while (!(status & THRE));
+
+	UART_PUT_CHAR(uart, ch);
+	SSYNC();
+
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
+{
+	struct tty_struct *tty = uart->port.info?uart->port.info->tty:0;
+	unsigned int status, ch, flg;
+#ifdef BF533_FAMILY
+	static int in_break = 0;
+#endif
+
+	status = UART_GET_LSR(uart);
+ 	ch = UART_GET_CHAR(uart);
+ 	uart->port.icount.rx++;
+
+#ifdef BF533_FAMILY
+	/* The BF533 family of processors have a nice misbehavior where
+	 * they continuously generate characters for a "single" break.
+	 * We have to basically ignore this flood until the "next" valid
+	 * character comes across.  All other Blackfin families operate
+	 * properly though.
+	 */
+	if (in_break) {
+		if (ch != 0) {
+			in_break = 0;
+			ch = UART_GET_CHAR(uart);
+		}
+		return;
+	}
+#endif
+
+	if (status & BI) {
+#ifdef BF533_FAMILY
+		in_break = 1;
+#endif
+		uart->port.icount.brk++;
+		if (uart_handle_break(&uart->port))
+			goto ignore_char;
+		flg = TTY_BREAK;
+	} else if (status & PE) {
+		flg = TTY_PARITY;
+		uart->port.icount.parity++;
+	} else if (status & OE) {
+		flg = TTY_OVERRUN;
+		uart->port.icount.overrun++;
+	} else if (status & FE) {
+		flg = TTY_FRAME;
+		uart->port.icount.frame++;
+	} else
+		flg = TTY_NORMAL;
+
+	if (uart_handle_sysrq_char(&uart->port, ch))
+		goto ignore_char;
+	if (tty)
+		uart_insert_char(&uart->port, status, 2, ch, flg);
+
+ignore_char:
+	if (tty)
+		tty_flip_buffer_push(tty);
+}
+
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
+{
+	struct circ_buf *xmit = &uart->port.info->xmit;
+
+	if (uart->port.x_char) {
+		UART_PUT_CHAR(uart, uart->port.x_char);
+		uart->port.icount.tx++;
+		uart->port.x_char = 0;
+		return;
+	}
+	/*
+	 * Check the modem control lines before
+	 * transmitting anything.
+	 */
+	bfin_serial_mctrl_check(uart);
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+		bfin_serial_stop_tx(&uart->port);
+		return;
+	}
+
+	local_put_char(uart, xmit->buf[xmit->tail]);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	uart->port.icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&uart->port);
+
+	if (uart_circ_empty(xmit))
+		bfin_serial_stop_tx(&uart->port);
+}
+
+static irqreturn_t bfin_serial_int(int irq, void *dev_id)
+{
+	struct bfin_serial_port *uart = dev_id;
+	unsigned short status;
+
+	spin_lock(&uart->port.lock);
+	status = UART_GET_IIR(uart);
+	do {
+		if ((status & IIR_STATUS) == IIR_TX_READY)
+			bfin_serial_tx_chars(uart);
+		if ((status & IIR_STATUS) == IIR_RX_READY)
+			bfin_serial_rx_chars(uart);
+		status = UART_GET_IIR(uart);
+	} while (status & (IIR_TX_READY | IIR_RX_READY));
+	spin_unlock(&uart->port.lock);
+	return IRQ_HANDLED;
+}
+
+static void bfin_serial_do_work(struct work_struct *work)
+{
+	struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
+
+	bfin_serial_mctrl_check(uart);
+}
+
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
+{
+	struct circ_buf *xmit = &uart->port.info->xmit;
+	unsigned short ier;
+	int flags = 0;
+
+	if (!uart->tx_done)
+		return;
+
+	uart->tx_done = 0;
+
+	if (uart->port.x_char) {
+		UART_PUT_CHAR(uart, uart->port.x_char);
+		uart->port.icount.tx++;
+		uart->port.x_char = 0;
+		uart->tx_done = 1;
+		return;
+	}
+	/*
+	 * Check the modem control lines before
+	 * transmitting anything.
+	 */
+	bfin_serial_mctrl_check(uart);
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+		bfin_serial_stop_tx(&uart->port);
+		uart->tx_done = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&uart->port.lock, flags);
+	uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+	if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
+		uart->tx_count = UART_XMIT_SIZE - xmit->tail;
+	blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
+					(unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
+	set_dma_config(uart->tx_dma_channel,
+		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+			INTR_ON_BUF,
+			DIMENSION_LINEAR,
+			DATA_SIZE_8));
+	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
+	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
+	set_dma_x_modify(uart->tx_dma_channel, 1);
+	enable_dma(uart->tx_dma_channel);
+	ier = UART_GET_IER(uart);
+	ier |= ETBEI;
+	UART_PUT_IER(uart, ier);
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
+{
+	struct tty_struct *tty = uart->port.info->tty;
+	int i, flg, status;
+
+	status = UART_GET_LSR(uart);
+	uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
+
+	if (status & BI) {
+		uart->port.icount.brk++;
+		if (uart_handle_break(&uart->port))
+			goto dma_ignore_char;
+		flg = TTY_BREAK;
+	} else if (status & PE) {
+		flg = TTY_PARITY;
+		uart->port.icount.parity++;
+	} else if (status & OE) {
+		flg = TTY_OVERRUN;
+		uart->port.icount.overrun++;
+	} else if (status & FE) {
+		flg = TTY_FRAME;
+		uart->port.icount.frame++;
+	} else
+		flg = TTY_NORMAL;
+
+	for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
+		if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+			goto dma_ignore_char;
+		uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg);
+	}
+dma_ignore_char:
+	tty_flip_buffer_push(tty);
+}
+
+void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
+{
+	int x_pos, pos;
+	int flags = 0;
+
+	bfin_serial_dma_tx_chars(uart);
+
+	spin_lock_irqsave(&uart->port.lock, flags);
+	x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
+	if (x_pos == DMA_RX_XCOUNT)
+		x_pos = 0;
+
+	pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
+
+	if (pos>uart->rx_dma_buf.tail) {
+		uart->rx_dma_buf.tail = pos;
+		bfin_serial_dma_rx_chars(uart);
+		uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+	}
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+	add_timer(&(uart->rx_dma_timer));
+}
+
+static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
+{
+	struct bfin_serial_port *uart = dev_id;
+	struct circ_buf *xmit = &uart->port.info->xmit;
+	unsigned short ier;
+
+	spin_lock(&uart->port.lock);
+	if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
+		clear_dma_irqstat(uart->tx_dma_channel);
+		disable_dma(uart->tx_dma_channel);
+		ier = UART_GET_IER(uart);
+		ier &= ~ETBEI;
+		UART_PUT_IER(uart, ier);
+		xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
+		uart->port.icount.tx+=uart->tx_count;
+
+		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+			uart_write_wakeup(&uart->port);
+
+		if (uart_circ_empty(xmit))
+			bfin_serial_stop_tx(&uart->port);
+		uart->tx_done = 1;
+	}
+
+	spin_unlock(&uart->port.lock);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
+{
+	struct bfin_serial_port *uart = dev_id;
+	unsigned short irqstat;
+
+	uart->rx_dma_nrows++;
+	if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
+		uart->rx_dma_nrows = 0;
+		uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
+		bfin_serial_dma_rx_chars(uart);
+		uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
+	}
+	spin_lock(&uart->port.lock);
+	irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
+	clear_dma_irqstat(uart->rx_dma_channel);
+
+	spin_unlock(&uart->port.lock);
+	return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int bfin_serial_tx_empty(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	unsigned short lsr;
+
+	lsr = UART_GET_LSR(uart);
+	if (lsr & TEMT)
+		return TIOCSER_TEMT;
+	else
+		return 0;
+}
+
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	if (uart->cts_pin < 0)
+		return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+	if (gpio_get_value(uart->cts_pin))
+		return TIOCM_DSR | TIOCM_CAR;
+	else
+#endif
+		return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	if (uart->rts_pin < 0)
+		return;
+
+	if (mctrl & TIOCM_RTS)
+		gpio_set_value(uart->rts_pin, 0);
+	else
+		gpio_set_value(uart->rts_pin, 1);
+#endif
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	unsigned int status;
+# ifdef CONFIG_SERIAL_BFIN_DMA
+	struct uart_info *info = uart->port.info;
+	struct tty_struct *tty = info->tty;
+
+	status = bfin_serial_get_mctrl(&uart->port);
+	if (!(status & TIOCM_CTS)) {
+		tty->hw_stopped = 1;
+	} else {
+		tty->hw_stopped = 0;
+	}
+# else
+	status = bfin_serial_get_mctrl(&uart->port);
+	uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+	if (!(status & TIOCM_CTS))
+		schedule_work(&uart->cts_workqueue);
+# endif
+#endif
+}
+
+/*
+ * Interrupts are always disabled.
+ */
+static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int bfin_serial_startup(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	dma_addr_t dma_handle;
+
+	if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
+		printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
+		return -EBUSY;
+	}
+
+	if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
+		printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
+		free_dma(uart->rx_dma_channel);
+		return -EBUSY;
+	}
+
+	set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
+	set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
+
+	uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
+	uart->rx_dma_buf.head = 0;
+	uart->rx_dma_buf.tail = 0;
+	uart->rx_dma_nrows = 0;
+
+	set_dma_config(uart->rx_dma_channel,
+		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
+				INTR_ON_ROW, DIMENSION_2D,
+				DATA_SIZE_8));
+	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
+	set_dma_x_modify(uart->rx_dma_channel, 1);
+	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
+	set_dma_y_modify(uart->rx_dma_channel, 1);
+	set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
+	enable_dma(uart->rx_dma_channel);
+
+	uart->rx_dma_timer.data = (unsigned long)(uart);
+	uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
+	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+	add_timer(&(uart->rx_dma_timer));
+#else
+	if (request_irq
+	    (uart->port.irq, bfin_serial_int, IRQF_DISABLED,
+	     "BFIN_UART_RX", uart)) {
+		printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
+		return -EBUSY;
+	}
+
+	if (request_irq
+	    (uart->port.irq+1, bfin_serial_int, IRQF_DISABLED,
+	     "BFIN_UART_TX", uart)) {
+		printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
+		free_irq(uart->port.irq, uart);
+		return -EBUSY;
+	}
+#endif
+	UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
+	return 0;
+}
+
+static void bfin_serial_shutdown(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	disable_dma(uart->tx_dma_channel);
+	free_dma(uart->tx_dma_channel);
+	disable_dma(uart->rx_dma_channel);
+	free_dma(uart->rx_dma_channel);
+	del_timer(&(uart->rx_dma_timer));
+#else
+	free_irq(uart->port.irq, uart);
+	free_irq(uart->port.irq+1, uart);
+#endif
+}
+
+static void
+bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
+		   struct ktermios *old)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	unsigned long flags;
+	unsigned int baud, quot;
+	unsigned short val, ier, lsr, lcr = 0;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS8:
+		lcr = WLS(8);
+		break;
+	case CS7:
+		lcr = WLS(7);
+		break;
+	case CS6:
+		lcr = WLS(6);
+		break;
+	case CS5:
+		lcr = WLS(5);
+		break;
+	default:
+		printk(KERN_ERR "%s: word lengh not supported\n",
+			__FUNCTION__);
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		lcr |= STB;
+	if (termios->c_cflag & PARENB) {
+		lcr |= PEN;
+		if (!(termios->c_cflag & PARODD))
+			lcr |= EPS;
+	}
+
+	/* These controls are not implemented for this port */
+	termios->c_iflag |= INPCK | BRKINT | PARMRK;
+	termios->c_iflag &= ~(IGNPAR | IGNBRK);
+
+	/* These controls are not implemented for this port */
+	termios->c_iflag |= INPCK | BRKINT | PARMRK;
+	termios->c_iflag &= ~(IGNPAR | IGNBRK);
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+	quot = uart_get_divisor(port, baud);
+	spin_lock_irqsave(&uart->port.lock, flags);
+
+	do {
+		lsr = UART_GET_LSR(uart);
+	} while (!(lsr & TEMT));
+
+	/* Disable UART */
+	ier = UART_GET_IER(uart);
+	UART_PUT_IER(uart, 0);
+
+	/* Set DLAB in LCR to Access DLL and DLH */
+	val = UART_GET_LCR(uart);
+	val |= DLAB;
+	UART_PUT_LCR(uart, val);
+	SSYNC();
+
+	UART_PUT_DLL(uart, quot & 0xFF);
+	SSYNC();
+	UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+	SSYNC();
+
+	/* Clear DLAB in LCR to Access THR RBR IER */
+	val = UART_GET_LCR(uart);
+	val &= ~DLAB;
+	UART_PUT_LCR(uart, val);
+	SSYNC();
+
+	UART_PUT_LCR(uart, lcr);
+
+	/* Enable UART */
+	UART_PUT_IER(uart, ier);
+
+	val = UART_GET_GCTL(uart);
+	val |= UCEN;
+	UART_PUT_GCTL(uart, val);
+
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static const char *bfin_serial_type(struct uart_port *port)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+	return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void bfin_serial_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int bfin_serial_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void bfin_serial_config_port(struct uart_port *port, int flags)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+	if (flags & UART_CONFIG_TYPE &&
+	    bfin_serial_request_port(&uart->port) == 0)
+		uart->port.type = PORT_BFIN;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_BFIN and PORT_UNKNOWN
+ */
+static int
+bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	return 0;
+}
+
+static struct uart_ops bfin_serial_pops = {
+	.tx_empty	= bfin_serial_tx_empty,
+	.set_mctrl	= bfin_serial_set_mctrl,
+	.get_mctrl	= bfin_serial_get_mctrl,
+	.stop_tx	= bfin_serial_stop_tx,
+	.start_tx	= bfin_serial_start_tx,
+	.stop_rx	= bfin_serial_stop_rx,
+	.enable_ms	= bfin_serial_enable_ms,
+	.break_ctl	= bfin_serial_break_ctl,
+	.startup	= bfin_serial_startup,
+	.shutdown	= bfin_serial_shutdown,
+	.set_termios	= bfin_serial_set_termios,
+	.type		= bfin_serial_type,
+	.release_port	= bfin_serial_release_port,
+	.request_port	= bfin_serial_request_port,
+	.config_port	= bfin_serial_config_port,
+	.verify_port	= bfin_serial_verify_port,
+};
+
+static void __init bfin_serial_init_ports(void)
+{
+	static int first = 1;
+	int i;
+
+	if (!first)
+		return;
+	first = 0;
+
+	for (i = 0; i < nr_ports; i++) {
+		bfin_serial_ports[i].port.uartclk   = get_sclk();
+		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
+		bfin_serial_ports[i].port.line      = i;
+		bfin_serial_ports[i].port.iotype    = UPIO_MEM;
+		bfin_serial_ports[i].port.membase   =
+			(void __iomem *)bfin_serial_resource[i].uart_base_addr;
+		bfin_serial_ports[i].port.mapbase   =
+			bfin_serial_resource[i].uart_base_addr;
+		bfin_serial_ports[i].port.irq       =
+			bfin_serial_resource[i].uart_irq;
+		bfin_serial_ports[i].port.flags     = UPF_BOOT_AUTOCONF;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+		bfin_serial_ports[i].tx_done	    = 1;
+		bfin_serial_ports[i].tx_count	    = 0;
+		bfin_serial_ports[i].tx_dma_channel =
+			bfin_serial_resource[i].uart_tx_dma_channel;
+		bfin_serial_ports[i].rx_dma_channel =
+			bfin_serial_resource[i].uart_rx_dma_channel;
+		init_timer(&(bfin_serial_ports[i].rx_dma_timer));
+#else
+		INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+		bfin_serial_ports[i].cts_pin	    =
+			bfin_serial_resource[i].uart_cts_pin;
+		bfin_serial_ports[i].rts_pin	    =
+			bfin_serial_resource[i].uart_rts_pin;
+#endif
+		bfin_serial_hw_init(&bfin_serial_ports[i]);
+
+	}
+}
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	while (!(UART_GET_LSR(uart)))
+		barrier();
+	UART_PUT_CHAR(uart, ch);
+	SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+	int flags = 0;
+
+	spin_lock_irqsave(&uart->port.lock, flags);
+	uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
+			   int *parity, int *bits)
+{
+	unsigned short status;
+
+	status = UART_GET_IER(uart) & (ERBFI | ETBEI);
+	if (status == (ERBFI | ETBEI)) {
+		/* ok, the port was enabled */
+		unsigned short lcr, val;
+		unsigned short dlh, dll;
+
+		lcr = UART_GET_LCR(uart);
+
+		*parity = 'n';
+		if (lcr & PEN) {
+			if (lcr & EPS)
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+		switch (lcr & 0x03) {
+			case 0:	*bits = 5; break;
+			case 1:	*bits = 6; break;
+			case 2:	*bits = 7; break;
+			case 3:	*bits = 8; break;
+		}
+		/* Set DLAB in LCR to Access DLL and DLH */
+		val = UART_GET_LCR(uart);
+		val |= DLAB;
+		UART_PUT_LCR(uart, val);
+
+		dll = UART_GET_DLL(uart);
+		dlh = UART_GET_DLH(uart);
+
+		/* Clear DLAB in LCR to Access THR RBR IER */
+		val = UART_GET_LCR(uart);
+		val &= ~DLAB;
+		UART_PUT_LCR(uart, val);
+
+		*baud = get_sclk() / (16*(dll | dlh << 8));
+	}
+	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+}
+
+static int __init
+bfin_serial_console_setup(struct console *co, char *options)
+{
+	struct bfin_serial_port *uart;
+	int baud = 57600;
+	int bits = 8;
+	int parity = 'n';
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int flow = 'r';
+#else
+	int flow = 'n';
+#endif
+
+	/*
+	 * 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 == -1 || co->index >= nr_ports)
+		co->index = 0;
+	uart = &bfin_serial_ports[co->index];
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		bfin_serial_console_get_options(uart, &baud, &parity, &bits);
+
+	return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver bfin_serial_reg;
+static struct console bfin_serial_console = {
+	.name		= BFIN_SERIAL_NAME,
+	.write		= bfin_serial_console_write,
+	.device		= uart_console_device,
+	.setup		= bfin_serial_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &bfin_serial_reg,
+};
+
+static int __init bfin_serial_rs_console_init(void)
+{
+	bfin_serial_init_ports();
+	register_console(&bfin_serial_console);
+	return 0;
+}
+console_initcall(bfin_serial_rs_console_init);
+
+#define BFIN_SERIAL_CONSOLE	&bfin_serial_console
+#else
+#define BFIN_SERIAL_CONSOLE	NULL
+#endif
+
+static struct uart_driver bfin_serial_reg = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "bfin-uart",
+	.dev_name		= BFIN_SERIAL_NAME,
+	.major			= BFIN_SERIAL_MAJOR,
+	.minor			= BFIN_SERIAL_MINOR,
+	.nr			= NR_PORTS,
+	.cons			= BFIN_SERIAL_CONSOLE,
+};
+
+static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+
+	if (uart)
+		uart_suspend_port(&bfin_serial_reg, &uart->port);
+
+	return 0;
+}
+
+static int bfin_serial_resume(struct platform_device *dev)
+{
+	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+
+	if (uart)
+		uart_resume_port(&bfin_serial_reg, &uart->port);
+
+	return 0;
+}
+
+static int bfin_serial_probe(struct platform_device *dev)
+{
+	struct resource *res = dev->resource;
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++, res++)
+		if (res->flags & IORESOURCE_MEM)
+			break;
+
+	if (i < dev->num_resources) {
+		for (i = 0; i < nr_ports; i++, res++) {
+			if (bfin_serial_ports[i].port.mapbase != res->start)
+				continue;
+			bfin_serial_ports[i].port.dev = &dev->dev;
+			uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+			platform_set_drvdata(dev, &bfin_serial_ports[i]);
+		}
+	}
+
+	return 0;
+}
+
+static int bfin_serial_remove(struct platform_device *pdev)
+{
+	struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	gpio_free(uart->cts_pin);
+	gpio_free(uart->rts_pin);
+#endif
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (uart)
+		uart_remove_one_port(&bfin_serial_reg, &uart->port);
+
+	return 0;
+}
+
+static struct platform_driver bfin_serial_driver = {
+	.probe		= bfin_serial_probe,
+	.remove		= bfin_serial_remove,
+	.suspend	= bfin_serial_suspend,
+	.resume		= bfin_serial_resume,
+	.driver		= {
+		.name	= "bfin-uart",
+	},
+};
+
+static int __init bfin_serial_init(void)
+{
+	int ret;
+
+	pr_info("Serial: Blackfin serial driver\n");
+
+	bfin_serial_init_ports();
+
+	ret = uart_register_driver(&bfin_serial_reg);
+	if (ret == 0) {
+		ret = platform_driver_register(&bfin_serial_driver);
+		if (ret) {
+			pr_debug("uart register failed\n");
+			uart_unregister_driver(&bfin_serial_reg);
+		}
+	}
+	return ret;
+}
+
+static void __exit bfin_serial_exit(void)
+{
+	platform_driver_unregister(&bfin_serial_driver);
+	uart_unregister_driver(&bfin_serial_reg);
+}
+
+module_init(bfin_serial_init);
+module_exit(bfin_serial_exit);
+
+MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
+MODULE_DESCRIPTION("Blackfin generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 7a3b97f..f23972b 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -934,7 +934,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SMC1_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC1].port.lock),
 		},
 		.flags = FLAG_SMC,
 		.tx_nrfifos = TX_NUM_FIFO,
@@ -948,7 +948,7 @@ struct uart_cpm_port cpm_uart_ports[UART
 			.irq		= SMC2_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC2].port.lock),
 		},
 		.flags = FLAG_SMC,
 		.tx_nrfifos = TX_NUM_FIFO,
@@ -965,7 +965,7 @@ #endif
 			.irq		= SCC1_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC1].port.lock),
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -979,7 +979,7 @@ #endif
 			.irq		= SCC2_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC2].port.lock),
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -993,7 +993,7 @@ #endif
 			.irq		= SCC3_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC3].port.lock),
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
@@ -1007,7 +1007,7 @@ #endif
 			.irq		= SCC4_IRQ,
 			.ops		= &cpm_uart_pops,
 			.iotype		= UPIO_MEM,
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC4].port.lock),
 		},
 		.tx_nrfifos = TX_NUM_FIFO,
 		.tx_fifosize = TX_BUF_SIZE,
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
deleted file mode 100644
index 4a23340..0000000
--- a/drivers/serial/crisv10.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * serial.h: Arch-dep definitions for the Etrax100 serial driver.
- *
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
- */
-
-#ifndef _ETRAX_SERIAL_H
-#define _ETRAX_SERIAL_H
-
-#include <linux/circ_buf.h>
-#include <asm/termios.h>
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#define SERIAL_RECV_DESCRIPTORS 8
-
-struct etrax_recv_buffer {
-	struct etrax_recv_buffer *next;
-	unsigned short length;
-	unsigned char error;
-	unsigned char pad;
-
-	unsigned char buffer[0];
-};
-
-struct e100_serial {
-	int			baud;
-	volatile u8		*port; /* R_SERIALx_CTRL */
-	u32			irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
-	/* Output registers */
-	volatile u8		*oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
-	volatile u32		*ofirstadr;   /* adr to R_DMA_CHx_FIRST */
-	volatile u8		*ocmdadr;     /* adr to R_DMA_CHx_CMD */
-	const volatile u8	*ostatusadr;  /* adr to R_DMA_CHx_STATUS */
-
-	/* Input registers */
-	volatile u8		*iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
-	volatile u32		*ifirstadr;   /* adr to R_DMA_CHx_FIRST */
-	volatile u8		*icmdadr;     /* adr to R_DMA_CHx_CMD */
-	volatile u32		*idescradr;   /* adr to R_DMA_CHx_DESCR */
-
-	int			flags;	/* defined in tty.h */
-
-	u8			rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
-	u8			tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
-	u8			iseteop; /* bit number for R_SET_EOP for the input dma */
-	int			enabled; /* Set to 1 if the port is enabled in HW config */
-
-	u8		dma_out_enabled:1; /* Set to 1 if DMA should be used */
-	u8		dma_in_enabled:1;  /* Set to 1 if DMA should be used */
-
-	/* end of fields defined in rs_table[] in .c-file */
-	u8		uses_dma_in;  /* Set to 1 if DMA is used */
-	u8		uses_dma_out; /* Set to 1 if DMA is used */
-	u8		forced_eop;   /* a fifo eop has been forced */
-	int			baud_base;     /* For special baudrates */
-	int			custom_divisor; /* For special baudrates */
-	struct etrax_dma_descr	tr_descr;
-	struct etrax_dma_descr	rec_descr[SERIAL_RECV_DESCRIPTORS];
-	int			cur_rec_descr;
-
-	volatile int		tr_running; /* 1 if output is running */
-
-	struct tty_struct	*tty;
-	int			read_status_mask;
-	int			ignore_status_mask;
-	int			x_char;	/* xon/xoff character */
-	int			close_delay;
-	unsigned short		closing_wait;
-	unsigned short		closing_wait2;
-	unsigned long		event;
-	unsigned long		last_active;
-	int			line;
-	int			type;  /* PORT_ETRAX */
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
-	struct circ_buf		xmit;
-	struct etrax_recv_buffer *first_recv_buffer;
-	struct etrax_recv_buffer *last_recv_buffer;
-	unsigned int		recv_cnt;
-	unsigned int		max_recv_cnt;
-
-	struct work_struct	work;
-	struct async_icount	icount;   /* error-statistics etc.*/
-	struct ktermios		normal_termios;
-	struct ktermios		callout_termios;
-#ifdef DECLARE_WAITQUEUE
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-#else
-	struct wait_queue	*open_wait;
-	struct wait_queue	*close_wait;
-#endif
-
-	unsigned long		char_time_usec;       /* The time for 1 char, in usecs */
-	unsigned long		flush_time_usec;      /* How often we should flush */
-	unsigned long		last_tx_active_usec;  /* Last tx usec in the jiffies */
-	unsigned long		last_tx_active;       /* Last tx time in jiffies */
-	unsigned long		last_rx_active_usec;  /* Last rx usec in the jiffies */
-	unsigned long		last_rx_active;       /* Last rx time in jiffies */
-
-	int			break_detected_cnt;
-	int			errorcode;
-
-#ifdef CONFIG_ETRAX_RS485
-	struct rs485_control	rs485;  /* RS-485 support */
-#endif
-};
-
-/* this PORT is not in the standard serial.h. it's not actually used for
- * anything since we only have one type of async serial-port anyway in this
- * system.
- */
-
-#define PORT_ETRAX 1
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP	0
-
-#endif /* __KERNEL__ */
-
-#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 246c557..6202995 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -47,7 +47,6 @@ #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/kobject.h>
 #include <linux/firmware.h>
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 04cc88c..e42faa4 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -46,6 +46,122 @@ #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/arch/imx-uart.h>
 
+/* Register definitions */
+#define URXD0 0x0  /* Receiver Register */
+#define URTX0 0x40 /* Transmitter Register */
+#define UCR1  0x80 /* Control Register 1 */
+#define UCR2  0x84 /* Control Register 2 */
+#define UCR3  0x88 /* Control Register 3 */
+#define UCR4  0x8c /* Control Register 4 */
+#define UFCR  0x90 /* FIFO Control Register */
+#define USR1  0x94 /* Status Register 1 */
+#define USR2  0x98 /* Status Register 2 */
+#define UESC  0x9c /* Escape Character Register */
+#define UTIM  0xa0 /* Escape Timer Register */
+#define UBIR  0xa4 /* BRM Incremental Register */
+#define UBMR  0xa8 /* BRM Modulator Register */
+#define UBRC  0xac /* Baud Rate Count Register */
+#define BIPR1 0xb0 /* Incremental Preset Register 1 */
+#define BIPR2 0xb4 /* Incremental Preset Register 2 */
+#define BIPR3 0xb8 /* Incremental Preset Register 3 */
+#define BIPR4 0xbc /* Incremental Preset Register 4 */
+#define BMPR1 0xc0 /* BRM Modulator Register 1 */
+#define BMPR2 0xc4 /* BRM Modulator Register 2 */
+#define BMPR3 0xc8 /* BRM Modulator Register 3 */
+#define BMPR4 0xcc /* BRM Modulator Register 4 */
+#define UTS   0xd0 /* UART Test Register */
+
+/* UART Control Register Bit Fields.*/
+#define  URXD_CHARRDY    (1<<15)
+#define  URXD_ERR        (1<<14)
+#define  URXD_OVRRUN     (1<<13)
+#define  URXD_FRMERR     (1<<12)
+#define  URXD_BRK        (1<<11)
+#define  URXD_PRERR      (1<<10)
+#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
+#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
+#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
+#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
+#define  UCR1_RRDYEN     (1<<9)	 /* Recv ready interrupt enable */
+#define  UCR1_RDMAEN     (1<<8)	 /* Recv ready DMA enable */
+#define  UCR1_IREN       (1<<7)	 /* Infrared interface enable */
+#define  UCR1_TXMPTYEN   (1<<6)	 /* Transimitter empty interrupt enable */
+#define  UCR1_RTSDEN     (1<<5)	 /* RTS delta interrupt enable */
+#define  UCR1_SNDBRK     (1<<4)	 /* Send break */
+#define  UCR1_TDMAEN     (1<<3)	 /* Transmitter ready DMA enable */
+#define  UCR1_UARTCLKEN  (1<<2)	 /* UART clock enabled */
+#define  UCR1_DOZE       (1<<1)	 /* Doze */
+#define  UCR1_UARTEN     (1<<0)	 /* UART enabled */
+#define  UCR2_ESCI     	 (1<<15) /* Escape seq interrupt enable */
+#define  UCR2_IRTS  	 (1<<14) /* Ignore RTS pin */
+#define  UCR2_CTSC  	 (1<<13) /* CTS pin control */
+#define  UCR2_CTS        (1<<12) /* Clear to send */
+#define  UCR2_ESCEN      (1<<11) /* Escape enable */
+#define  UCR2_PREN       (1<<8)  /* Parity enable */
+#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
+#define  UCR2_STPB       (1<<6)	 /* Stop */
+#define  UCR2_WS         (1<<5)	 /* Word size */
+#define  UCR2_RTSEN      (1<<4)	 /* Request to send interrupt enable */
+#define  UCR2_TXEN       (1<<2)	 /* Transmitter enabled */
+#define  UCR2_RXEN       (1<<1)	 /* Receiver enabled */
+#define  UCR2_SRST 	 (1<<0)	 /* SW reset */
+#define  UCR3_DTREN 	 (1<<13) /* DTR interrupt enable */
+#define  UCR3_PARERREN   (1<<12) /* Parity enable */
+#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
+#define  UCR3_DSR        (1<<10) /* Data set ready */
+#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
+#define  UCR3_RI         (1<<8)  /* Ring indicator */
+#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
+#define  UCR3_RXDSEN	 (1<<6)  /* Receive status interrupt enable */
+#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+#define  UCR3_AWAKEN	 (1<<4)  /* Async wake interrupt enable */
+#define  UCR3_REF25 	 (1<<3)  /* Ref freq 25 MHz */
+#define  UCR3_REF30 	 (1<<2)  /* Ref Freq 30 MHz */
+#define  UCR3_INVT  	 (1<<1)  /* Inverted Infrared transmission */
+#define  UCR3_BPEN  	 (1<<0)  /* Preset registers enable */
+#define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
+#define  UCR4_INVR  	 (1<<9)  /* Inverted infrared reception */
+#define  UCR4_ENIRI 	 (1<<8)  /* Serial infrared interrupt enable */
+#define  UCR4_WKEN  	 (1<<7)  /* Wake interrupt enable */
+#define  UCR4_REF16 	 (1<<6)  /* Ref freq 16 MHz */
+#define  UCR4_IRSC  	 (1<<5)  /* IR special case */
+#define  UCR4_TCEN  	 (1<<3)  /* Transmit complete interrupt enable */
+#define  UCR4_BKEN  	 (1<<2)  /* Break condition interrupt enable */
+#define  UCR4_OREN  	 (1<<1)  /* Receiver overrun interrupt enable */
+#define  UCR4_DREN  	 (1<<0)  /* Recv data ready interrupt enable */
+#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
+#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
+#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
+#define  USR1_RTSS  	 (1<<14) /* RTS pin status */
+#define  USR1_TRDY  	 (1<<13) /* Transmitter ready interrupt/dma flag */
+#define  USR1_RTSD  	 (1<<12) /* RTS delta */
+#define  USR1_ESCF  	 (1<<11) /* Escape seq interrupt flag */
+#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
+#define  USR1_RRDY       (1<<9)	 /* Receiver ready interrupt/dma flag */
+#define  USR1_TIMEOUT    (1<<7)	 /* Receive timeout interrupt status */
+#define  USR1_RXDS  	 (1<<6)	 /* Receiver idle interrupt flag */
+#define  USR1_AIRINT	 (1<<5)	 /* Async IR wake interrupt flag */
+#define  USR1_AWAKE 	 (1<<4)	 /* Aysnc wake interrupt flag */
+#define  USR2_ADET  	 (1<<15) /* Auto baud rate detect complete */
+#define  USR2_TXFE  	 (1<<14) /* Transmit buffer FIFO empty */
+#define  USR2_DTRF  	 (1<<13) /* DTR edge interrupt flag */
+#define  USR2_IDLE  	 (1<<12) /* Idle condition */
+#define  USR2_IRINT 	 (1<<8)	 /* Serial infrared interrupt flag */
+#define  USR2_WAKE  	 (1<<7)	 /* Wake */
+#define  USR2_RTSF  	 (1<<4)	 /* RTS edge interrupt flag */
+#define  USR2_TXDC  	 (1<<3)	 /* Transmitter complete */
+#define  USR2_BRCD  	 (1<<2)	 /* Break condition */
+#define  USR2_ORE        (1<<1)	 /* Overrun error */
+#define  USR2_RDR        (1<<0)	 /* Recv data ready */
+#define  UTS_FRCPERR	 (1<<13) /* Force parity error */
+#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
+#define  UTS_TXEMPTY	 (1<<6)	 /* TxFIFO empty */
+#define  UTS_RXEMPTY	 (1<<5)	 /* RxFIFO empty */
+#define  UTS_TXFULL 	 (1<<4)	 /* TxFIFO full */
+#define  UTS_RXFULL 	 (1<<3)	 /* RxFIFO full */
+#define  UTS_SOFTRST	 (1<<0)	 /* Software reset */
+
 /* We've been assigned a range on the "Low-density serial ports" major */
 #define SERIAL_IMX_MAJOR	204
 #define MINOR_START		41
@@ -128,7 +244,10 @@ static void imx_timeout(unsigned long da
 static void imx_stop_tx(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
-	UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
+	unsigned long temp;
+
+	temp = readl(sport->port.membase + UCR1);
+	writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
 }
 
 /*
@@ -137,7 +256,10 @@ static void imx_stop_tx(struct uart_port
 static void imx_stop_rx(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
-	UCR2((u32)sport->port.membase) &= ~UCR2_RXEN;
+	unsigned long temp;
+
+	temp = readl(sport->port.membase + UCR2);
+	writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
 }
 
 /*
@@ -154,10 +276,10 @@ static inline void imx_transmit_buffer(s
 {
 	struct circ_buf *xmit = &sport->port.info->xmit;
 
-	while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) {
+	while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
 		/* send xmit->buf[xmit->tail]
 		 * out the port here */
-		URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
+		writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
 		xmit->tail = (xmit->tail + 1) &
 		         (UART_XMIT_SIZE - 1);
 		sport->port.icount.tx++;
@@ -175,21 +297,24 @@ static inline void imx_transmit_buffer(s
 static void imx_start_tx(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long temp;
 
-	UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
+	temp = readl(sport->port.membase + UCR1);
+	writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
 
-	imx_transmit_buffer(sport);
+	if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+		imx_transmit_buffer(sport);
 }
 
 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;
+	unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
 	unsigned long flags;
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
-	USR1((u32)sport->port.membase) = USR1_RTSD;
+	writel(USR1_RTSD, sport->port.membase + USR1);
 	uart_handle_cts_change(&sport->port, !!val);
 	wake_up_interruptible(&sport->port.info->delta_msr_wait);
 
@@ -207,7 +332,7 @@ static irqreturn_t imx_txint(int irq, vo
 	if (sport->port.x_char)
 	{
 		/* Send next char */
-		URTX0((u32)sport->port.membase) = sport->port.x_char;
+		writel(sport->port.x_char, sport->port.membase + URTX0);
 		goto out;
 	}
 
@@ -231,17 +356,18 @@ static irqreturn_t imx_rxint(int irq, vo
 	struct imx_port *sport = dev_id;
 	unsigned int rx,flg,ignored = 0;
 	struct tty_struct *tty = sport->port.info->tty;
-	unsigned long flags;
+	unsigned long flags, temp;
 
-	rx = URXD0((u32)sport->port.membase);
+	rx = readl(sport->port.membase + URXD0);
 	spin_lock_irqsave(&sport->port.lock,flags);
 
 	do {
 		flg = TTY_NORMAL;
 		sport->port.icount.rx++;
 
-		if( USR2((u32)sport->port.membase) & USR2_BRCD ) {
-			USR2((u32)sport->port.membase) |= USR2_BRCD;
+		temp = readl(sport->port.membase + USR2);
+		if( temp & USR2_BRCD ) {
+			writel(temp | USR2_BRCD, sport->port.membase + USR2);
 			if(uart_handle_break(&sport->port))
 				goto ignore_char;
 		}
@@ -257,7 +383,7 @@ static irqreturn_t imx_rxint(int irq, vo
 		tty_insert_flip_char(tty, rx, flg);
 
 	ignore_char:
-		rx = URXD0((u32)sport->port.membase);
+		rx = readl(sport->port.membase + URXD0);
 	} while(rx & URXD_CHARRDY);
 
 out:
@@ -301,7 +427,7 @@ static unsigned int imx_tx_empty(struct 
 {
 	struct imx_port *sport = (struct imx_port *)port;
 
-	return USR2((u32)sport->port.membase) & USR2_TXDC ?  TIOCSER_TEMT : 0;
+	return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
 }
 
 /*
@@ -312,10 +438,10 @@ static unsigned int imx_get_mctrl(struct
         struct imx_port *sport = (struct imx_port *)port;
         unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
 
-        if (USR1((u32)sport->port.membase) & USR1_RTSS)
+        if (readl(sport->port.membase + USR1) & USR1_RTSS)
                 tmp |= TIOCM_CTS;
 
-        if (UCR2((u32)sport->port.membase) & UCR2_CTS)
+        if (readl(sport->port.membase + UCR2) & UCR2_CTS)
                 tmp |= TIOCM_RTS;
 
         return tmp;
@@ -324,11 +450,14 @@ static unsigned int imx_get_mctrl(struct
 static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
         struct imx_port *sport = (struct imx_port *)port;
+	unsigned long temp;
+
+	temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
 
         if (mctrl & TIOCM_RTS)
-                UCR2((u32)sport->port.membase) |= UCR2_CTS;
-        else
-                UCR2((u32)sport->port.membase) &= ~UCR2_CTS;
+		temp |= UCR2_CTS;
+
+	writel(temp, sport->port.membase + UCR2);
 }
 
 /*
@@ -337,14 +466,16 @@ static void imx_set_mctrl(struct uart_po
 static void imx_break_ctl(struct uart_port *port, int break_state)
 {
 	struct imx_port *sport = (struct imx_port *)port;
-	unsigned long flags;
+	unsigned long flags, temp;
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
+	temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+
 	if ( break_state != 0 )
-		UCR1((u32)sport->port.membase) |= UCR1_SNDBRK;
-	else
-		UCR1((u32)sport->port.membase) &= ~UCR1_SNDBRK;
+		temp |= UCR1_SNDBRK;
+
+	writel(temp, sport->port.membase + UCR1);
 
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
@@ -360,7 +491,7 @@ static int imx_setup_ufcr(struct imx_por
 	/* set receiver / transmitter trigger level.
 	 * RFDIV is set such way to satisfy requested uartclk value
 	 */
-	val = TXTL<<10 | RXTL;
+	val = TXTL << 10 | RXTL;
 	ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
 
 	if(!ufcr_rfdiv)
@@ -373,7 +504,7 @@ static int imx_setup_ufcr(struct imx_por
 
 	val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
 
-	UFCR((u32)sport->port.membase) = val;
+	writel(val, sport->port.membase + UFCR);
 
 	return 0;
 }
@@ -382,14 +513,15 @@ static int imx_startup(struct uart_port 
 {
 	struct imx_port *sport = (struct imx_port *)port;
 	int retval;
-	unsigned long flags;
+	unsigned long flags, temp;
 
 	imx_setup_ufcr(sport, 0);
 
 	/* disable the DREN bit (Data Ready interrupt enable) before
 	 * requesting IRQs
 	 */
-	UCR4((u32)sport->port.membase) &= ~UCR4_DREN;
+	temp = readl(sport->port.membase + UCR4);
+	writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
 	/*
 	 * Allocate the IRQ
@@ -411,12 +543,16 @@ static int imx_startup(struct uart_port 
 	/*
 	 * Finally, clear and enable interrupts
 	 */
+	writel(USR1_RTSD, sport->port.membase + USR1);
+
+	temp = readl(sport->port.membase + UCR1);
+	temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+	writel(temp, sport->port.membase + UCR1);
 
-	USR1((u32)sport->port.membase) = USR1_RTSD;
-	UCR1((u32)sport->port.membase) |=
-	                 (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+	temp = readl(sport->port.membase + UCR2);
+	temp |= (UCR2_RXEN | UCR2_TXEN);
+	writel(temp, sport->port.membase + UCR2);
 
-	UCR2((u32)sport->port.membase) |= (UCR2_RXEN | UCR2_TXEN);
 	/*
 	 * Enable modem status interrupts
 	 */
@@ -437,6 +573,7 @@ error_out1:
 static void imx_shutdown(struct uart_port *port)
 {
 	struct imx_port *sport = (struct imx_port *)port;
+	unsigned long temp;
 
 	/*
 	 * Stop our timer.
@@ -454,8 +591,9 @@ static void imx_shutdown(struct uart_por
 	 * Disable all interrupts, port and break condition.
 	 */
 
-	UCR1((u32)sport->port.membase) &=
-	                 ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+	temp = readl(sport->port.membase + UCR1);
+	temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+	writel(temp, sport->port.membase + UCR1);
 }
 
 static void
@@ -548,18 +686,18 @@ imx_set_termios(struct uart_port *port, 
 	/*
 	 * disable interrupts and drain transmitter
 	 */
-	old_ucr1 = UCR1((u32)sport->port.membase);
-	UCR1((u32)sport->port.membase) &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
+	old_ucr1 = readl(sport->port.membase + UCR1);
+	writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+			sport->port.membase + UCR1);
 
-	while ( !(USR2((u32)sport->port.membase) & USR2_TXDC))
+	while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
 		barrier();
 
 	/* then, disable everything */
-	old_txrxen = UCR2((u32)sport->port.membase) & ( UCR2_TXEN | UCR2_RXEN );
-	UCR2((u32)sport->port.membase) &= ~( UCR2_TXEN | UCR2_RXEN);
-
-	/* set the parity, stop bits and data size */
-	UCR2((u32)sport->port.membase) = ucr2;
+	old_txrxen = readl(sport->port.membase + UCR2);
+	writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
+			sport->port.membase + UCR2);
+	old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
 
 	/* set the baud rate. We assume uartclk = 16 MHz
 	 *
@@ -567,11 +705,13 @@ imx_set_termios(struct uart_port *port, 
 	 * --------- = --------
 	 *  uartclk    UBMR - 1
 	 */
-	UBIR((u32)sport->port.membase) = (baud / 100) - 1;
-	UBMR((u32)sport->port.membase) = 10000 - 1;
+	writel((baud / 100) - 1, sport->port.membase + UBIR);
+	writel(10000 - 1, sport->port.membase + UBMR);
+
+	writel(old_ucr1, sport->port.membase + UCR1);
 
-	UCR1((u32)sport->port.membase) = old_ucr1;
-	UCR2((u32)sport->port.membase) |= old_txrxen;
+	/* set the parity, stop bits and data size */
+	writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
 
 	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
 		imx_enable_ms(&sport->port);
@@ -730,9 +870,11 @@ #ifdef CONFIG_SERIAL_IMX_CONSOLE
 static void imx_console_putchar(struct uart_port *port, int ch)
 {
 	struct imx_port *sport = (struct imx_port *)port;
-	while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
+
+	while (readl(sport->port.membase + UTS) & UTS_TXFULL)
 		barrier();
-	URTX0((u32)sport->port.membase) = ch;
+
+	writel(ch, sport->port.membase + URTX0);
 }
 
 /*
@@ -747,13 +889,14 @@ imx_console_write(struct console *co, co
 	/*
 	 *	First, save UCR1/2 and then disable interrupts
 	 */
-	old_ucr1 = UCR1((u32)sport->port.membase);
-	old_ucr2 = UCR2((u32)sport->port.membase);
+	old_ucr1 = readl(sport->port.membase + UCR1);
+	old_ucr2 = readl(sport->port.membase + UCR2);
 
-	UCR1((u32)sport->port.membase) =
-	                   (old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN)
-	                   & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
-	UCR2((u32)sport->port.membase) = old_ucr2 | UCR2_TXEN;
+	writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) &
+		~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+		sport->port.membase + UCR1);
+
+	writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
 
 	uart_console_write(&sport->port, s, count, imx_console_putchar);
 
@@ -761,10 +904,10 @@ imx_console_write(struct console *co, co
 	 *	Finally, wait for transmitter to become empty
 	 *	and restore UCR1/2
 	 */
-	while (!(USR2((u32)sport->port.membase) & USR2_TXDC));
+	while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
 
-	UCR1((u32)sport->port.membase) = old_ucr1;
-	UCR2((u32)sport->port.membase) = old_ucr2;
+	writel(old_ucr1, sport->port.membase + UCR1);
+	writel(old_ucr2, sport->port.membase + UCR2);
 }
 
 /*
@@ -776,13 +919,13 @@ imx_console_get_options(struct imx_port 
 			   int *parity, int *bits)
 {
 
-	if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
+	if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) {
 		/* ok, the port was enabled */
 		unsigned int ucr2, ubir,ubmr, uartclk;
 		unsigned int baud_raw;
 		unsigned int ucfr_rfdiv;
 
-		ucr2 = UCR2((u32)sport->port.membase);
+		ucr2 = readl(sport->port.membase + UCR2);
 
 		*parity = 'n';
 		if (ucr2 & UCR2_PREN) {
@@ -797,11 +940,10 @@ imx_console_get_options(struct imx_port 
 		else
 			*bits = 7;
 
-		ubir = UBIR((u32)sport->port.membase) & 0xffff;
-		ubmr = UBMR((u32)sport->port.membase) & 0xffff;
-
+		ubir = readl(sport->port.membase + UBIR) & 0xffff;
+		ubmr = readl(sport->port.membase + UBMR) & 0xffff;
 
-		ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7;
+		ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
 		if (ucfr_rfdiv == 6)
 			ucfr_rfdiv = 7;
 		else
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index 8be8da3..b2d6f5b 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -581,8 +581,13 @@ static void neo_parse_modem(struct jsm_c
 		return;
 
 	/* Scrub off lower bits. They signify delta's, which I don't care about */
-	msignals &= 0xf0;
+	/* Keep DDCD and DDSR though */
+	msignals &= 0xf8;
 
+	if (msignals & UART_MSR_DDCD)
+		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+	if (msignals & UART_MSR_DDSR)
+		uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
 	if (msignals & UART_MSR_DCD)
 		ch->ch_mistat |= UART_MSR_DCD;
 	else
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index be22bbd..281f23a 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -448,6 +448,7 @@ int jsm_uart_port_init(struct jsm_board 
 			continue;
 
 		brd->channels[i]->uart_port.irq = brd->irq;
+		brd->channels[i]->uart_port.uartclk = 14745600;
 		brd->channels[i]->uart_port.type = PORT_JSM;
 		brd->channels[i]->uart_port.iotype = UPIO_MEM;
 		brd->channels[i]->uart_port.membase = brd->re_map_membase;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 8d24cd5..35f8b86 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -257,9 +257,10 @@ mpc52xx_uart_shutdown(struct uart_port *
 {
 	struct mpc52xx_psc __iomem *psc = PSC(port);
 
-	/* Shut down the port, interrupt and all */
+	/* Shut down the port.  Leave TX active if on a console port */
 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
-	out_8(&psc->command,MPC52xx_PSC_RST_TX);
+	if (!uart_console(port))
+		out_8(&psc->command,MPC52xx_PSC_RST_TX);
 
 	port->read_status_mask = 0;
 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
@@ -1069,7 +1070,7 @@ mpc52xx_uart_of_enumerate(void)
 			continue;
 
 		/* Is a particular device number requested? */
-		devno = get_property(np, "port-number", NULL);
+		devno = of_get_property(np, "port-number", NULL);
 		mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
 	}
 
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 3d2fcc5..d09f209 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -183,6 +183,7 @@ struct mpsc_port_info {
 	u8 *txb_p;		/* Phys addr of txb */
 	int txr_head;		/* Where new data goes */
 	int txr_tail;		/* Where sent data comes off */
+	spinlock_t tx_lock;	/* transmit lock */
 
 	/* Mirrored values of regs we can't read (if 'mirror_regs' set) */
 	u32 MPSC_MPCR_m;
@@ -1212,6 +1213,9 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
 {
 	struct mpsc_tx_desc *txre;
 	int rc = 0;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&pi->tx_lock, iflags);
 
 	if (!mpsc_sdma_tx_active(pi)) {
 		txre = (struct mpsc_tx_desc *)(pi->txr +
@@ -1248,6 +1252,7 @@ #endif
 		mpsc_sdma_start_tx(pi);	/* start next desc if ready */
 	}
 
+	spin_unlock_irqrestore(&pi->tx_lock, iflags);
 	return rc;
 }
 
@@ -1338,11 +1343,16 @@ static void
 mpsc_start_tx(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&pi->tx_lock, iflags);
 
 	mpsc_unfreeze(pi);
 	mpsc_copy_tx_data(pi);
 	mpsc_sdma_start_tx(pi);
 
+	spin_unlock_irqrestore(&pi->tx_lock, iflags);
+
 	pr_debug("mpsc_start_tx[%d]\n", port->line);
 	return;
 }
@@ -1625,6 +1635,16 @@ mpsc_console_write(struct console *co, c
 	struct mpsc_port_info *pi = &mpsc_ports[co->index];
 	u8 *bp, *dp, add_cr = 0;
 	int i;
+	unsigned long iflags;
+
+	spin_lock_irqsave(&pi->tx_lock, iflags);
+
+	while (pi->txr_head != pi->txr_tail) {
+		while (mpsc_sdma_tx_active(pi))
+			udelay(100);
+		mpsc_sdma_intr_ack(pi);
+		mpsc_tx_intr(pi);
+	}
 
 	while (mpsc_sdma_tx_active(pi))
 		udelay(100);
@@ -1668,6 +1688,7 @@ #endif
 		pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
 	}
 
+	spin_unlock_irqrestore(&pi->tx_lock, iflags);
 	return;
 }
 
@@ -2005,7 +2026,8 @@ mpsc_drv_probe(struct platform_device *d
 		if (!(rc = mpsc_drv_map_regs(pi, dev))) {
 			mpsc_drv_get_platform_data(pi, dev, dev->id);
 
-			if (!(rc = mpsc_make_ready(pi)))
+			if (!(rc = mpsc_make_ready(pi))) {
+				spin_lock_init(&pi->tx_lock);
 				if (!(rc = uart_add_one_port(&mpsc_reg,
 					&pi->port)))
 					rc = 0;
@@ -2014,6 +2036,7 @@ mpsc_drv_probe(struct platform_device *d
 						(struct uart_port *)pi);
 					mpsc_drv_unmap_regs(pi);
 				}
+			}
 			else
 				mpsc_drv_unmap_regs(pi);
 		}
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 09b0b73..7ffdaea 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -29,8 +29,8 @@ static int __devinit of_platform_serial_
 	int ret;
 
 	memset(port, 0, sizeof *port);
-	spd = get_property(np, "current-speed", NULL);
-	clk = get_property(np, "clock-frequency", NULL);
+	spd = of_get_property(np, "current-speed", NULL);
+	clk = of_get_property(np, "clock-frequency", NULL);
 	if (!clk) {
 		dev_warn(&ofdev->dev, "no clock-frequency property set\n");
 		return -ENODEV;
@@ -48,7 +48,8 @@ static int __devinit of_platform_serial_
 	port->iotype = UPIO_MEM;
 	port->type = type;
 	port->uartclk = *clk;
-	port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+	port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
+		| UPF_FIXED_PORT;
 	port->dev = &ofdev->dev;
 	port->custom_divisor = *clk / (16 * (*spd));
 
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 752ef07..0fa9f67 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1450,14 +1450,14 @@ no_dma:
 	/*
 	 * Detect port type
 	 */
-	if (device_is_compatible(np, "cobalt"))
+	if (of_device_is_compatible(np, "cobalt"))
 		uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
-	conn = get_property(np, "AAPL,connector", &len);
+	conn = of_get_property(np, "AAPL,connector", &len);
 	if (conn && (strcmp(conn, "infrared") == 0))
 		uap->flags |= PMACZILOG_FLAG_IS_IRDA;
 	uap->port_type = PMAC_SCC_ASYNC;
 	/* 1999 Powerbook G3 has slot-names property instead */
-	slots = get_property(np, "slot-names", &len);
+	slots = of_get_property(np, "slot-names", &len);
 	if (slots && slots->count > 0) {
 		if (strcmp(slots->name, "IrDA") == 0)
 			uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1467,10 +1467,11 @@ no_dma:
 	if (ZS_IS_IRDA(uap))
 		uap->port_type = PMAC_SCC_IRDA;
 	if (ZS_IS_INTMODEM(uap)) {
-		struct device_node* i2c_modem = find_devices("i2c-modem");
+		struct device_node* i2c_modem =
+			of_find_node_by_name(NULL, "i2c-modem");
 		if (i2c_modem) {
 			const char* mid =
-				get_property(i2c_modem, "modem-id", NULL);
+				of_get_property(i2c_modem, "modem-id", NULL);
 			if (mid) switch(*mid) {
 			case 0x04 :
 			case 0x05 :
@@ -1482,6 +1483,7 @@ no_dma:
 			}
 			printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
 				mid ? (*mid) : 0);
+			of_node_put(i2c_modem);
 		} else {
 			printk(KERN_INFO "pmac_zilog: serial modem detected\n");
 		}
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index d403aaa..e9c6cb3 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -717,7 +717,7 @@ struct uart_ops serial_pxa_pops = {
 static struct uart_pxa_port serial_pxa_ports[] = {
      {	/* FFUART */
 	.name	= "FFUART",
-	.cken	= CKEN6_FFUART,
+	.cken	= CKEN_FFUART,
 	.port	= {
 		.type		= PORT_PXA,
 		.iotype		= UPIO_MEM,
@@ -731,7 +731,7 @@ static struct uart_pxa_port serial_pxa_p
 	},
   }, {	/* BTUART */
 	.name	= "BTUART",
-	.cken	= CKEN7_BTUART,
+	.cken	= CKEN_BTUART,
 	.port	= {
 		.type		= PORT_PXA,
 		.iotype		= UPIO_MEM,
@@ -745,7 +745,7 @@ static struct uart_pxa_port serial_pxa_p
 	},
   }, {	/* STUART */
 	.name	= "STUART",
-	.cken	= CKEN5_STUART,
+	.cken	= CKEN_STUART,
 	.port	= {
 		.type		= PORT_PXA,
 		.iotype		= UPIO_MEM,
@@ -759,7 +759,7 @@ static struct uart_pxa_port serial_pxa_p
 	},
   }, {  /* HWUART */
 	.name	= "HWUART",
-	.cken	= CKEN4_HWUART,
+	.cken	= CKEN_HWUART,
 	.port = {
 		.type		= PORT_PXA,
 		.iotype		= UPIO_MEM,
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 3ba9208..10bc020 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -957,7 +957,7 @@ static struct uart_driver s3c24xx_uart_d
 static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
 	[0] = {
 		.port = {
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX0,
 			.uartclk	= 0,
@@ -969,7 +969,7 @@ static struct s3c24xx_uart_port s3c24xx_
 	},
 	[1] = {
 		.port = {
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX1,
 			.uartclk	= 0,
@@ -983,7 +983,7 @@ #if NR_PORTS > 2
 
 	[2] = {
 		.port = {
-			.lock		= SPIN_LOCK_UNLOCKED,
+			.lock		= __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
 			.iotype		= UPIO_MEM,
 			.irq		= IRQ_S3CUART_RX2,
 			.uartclk	= 0,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0422c0f..326020f 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -37,13 +37,6 @@ #include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#undef	DEBUG
-#ifdef DEBUG
-#define DPRINTK(x...)	printk(x)
-#else
-#define DPRINTK(x...)	do { } while (0)
-#endif
-
 /*
  * This is used to lock changes in serial line configuration.
  */
@@ -552,7 +545,7 @@ static void uart_flush_buffer(struct tty
 		return;
 	}
 
-	DPRINTK("uart_flush_buffer(%d) called\n", tty->index);
+	pr_debug("uart_flush_buffer(%d) called\n", tty->index);
 
 	spin_lock_irqsave(&port->lock, flags);
 	uart_circ_clear(&state->info->xmit);
@@ -672,19 +665,21 @@ static int uart_set_info(struct uart_sta
 	 */
 	mutex_lock(&state->mutex);
 
-	change_irq  = new_serial.irq != port->irq;
+	change_irq  = !(port->flags & UPF_FIXED_PORT)
+		&& new_serial.irq != port->irq;
 
 	/*
 	 * Since changing the 'type' of the port changes its resource
 	 * allocations, we should treat type changes the same as
 	 * IO port changes.
 	 */
-	change_port = new_port != port->iobase ||
-		      (unsigned long)new_serial.iomem_base != port->mapbase ||
-		      new_serial.hub6 != port->hub6 ||
-		      new_serial.io_type != port->iotype ||
-		      new_serial.iomem_reg_shift != port->regshift ||
-		      new_serial.type != port->type;
+	change_port = !(port->flags & UPF_FIXED_PORT)
+		&& (new_port != port->iobase ||
+		    (unsigned long)new_serial.iomem_base != port->mapbase ||
+		    new_serial.hub6 != port->hub6 ||
+		    new_serial.io_type != port->iotype ||
+		    new_serial.iomem_reg_shift != port->regshift ||
+		    new_serial.type != port->type);
 
 	old_flags = port->flags;
 	new_flags = new_serial.flags;
@@ -796,8 +791,10 @@ static int uart_set_info(struct uart_sta
 		}
 	}
 
-	port->irq              = new_serial.irq;
-	port->uartclk          = new_serial.baud_base * 16;
+	if (change_irq)
+		port->irq      = new_serial.irq;
+	if (!(port->flags & UPF_FIXED_PORT))
+		port->uartclk  = new_serial.baud_base * 16;
 	port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
 				 (new_flags & UPF_CHANGE_MASK);
 	port->custom_divisor   = new_serial.custom_divisor;
@@ -1220,7 +1217,7 @@ static void uart_close(struct tty_struct
 
 	port = state->port;
 
-	DPRINTK("uart_close(%d) called\n", port->line);
+	pr_debug("uart_close(%d) called\n", port->line);
 
 	mutex_lock(&state->mutex);
 
@@ -1339,7 +1336,7 @@ static void uart_wait_until_sent(struct 
 
 	expire = jiffies + timeout;
 
-	DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+	pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
 	        port->line, jiffies, expire);
 
 	/*
@@ -1368,7 +1365,7 @@ static void uart_hangup(struct tty_struc
 	struct uart_state *state = tty->driver_data;
 
 	BUG_ON(!kernel_locked());
-	DPRINTK("uart_hangup(%d)\n", state->port->line);
+	pr_debug("uart_hangup(%d)\n", state->port->line);
 
 	mutex_lock(&state->mutex);
 	if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
@@ -1566,7 +1563,7 @@ static int uart_open(struct tty_struct *
 	int retval, line = tty->index;
 
 	BUG_ON(!kernel_locked());
-	DPRINTK("uart_open(%d) called\n", line);
+	pr_debug("uart_open(%d) called\n", line);
 
 	/*
 	 * tty->driver->num won't change, so we won't fail here with
@@ -2064,6 +2061,7 @@ uart_report_port(struct uart_driver *drv
 	case UPIO_MEM32:
 	case UPIO_AU:
 	case UPIO_TSI:
+	case UPIO_DWAPB:
 		snprintf(address, sizeof(address),
 			 "MMIO 0x%lx", port->mapbase);
 		break;
@@ -2409,6 +2407,7 @@ int uart_match_port(struct uart_port *po
 	case UPIO_MEM32:
 	case UPIO_AU:
 	case UPIO_TSI:
+	case UPIO_DWAPB:
 		return (port1->mapbase == port2->mapbase);
 	}
 	return 0;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 509ace7..1deb576 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -15,31 +15,6 @@
  * published by the Free Software Foundation.
  *
  *  Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
- *
- *  Revision History:
- *	0.30	Initial revision. (Renamed from serial_txx927.c)
- *	0.31	Use save_flags instead of local_irq_save.
- *	0.32	Support SCLK.
- *	0.33	Switch TXX9_TTY_NAME by CONFIG_SERIAL_TXX9_STDSERIAL.
- *		Support TIOCSERGETLSR.
- *	0.34	Support slow baudrate.
- *	0.40	Merge codes from mainstream kernel (2.4.22).
- *	0.41	Fix console checking in rs_shutdown_port().
- *		Disable flow-control in serial_console_write().
- *	0.42	Fix minor compiler warning.
- *	1.00	Kernel 2.6.  Converted to new serial core (based on 8250.c).
- *	1.01	Set fifosize to make tx_empry called properly.
- *		Use standard uart_get_divisor.
- *	1.02	Cleanup. (import 8250.c changes)
- *	1.03	Fix low-latency mode. (import 8250.c changes)
- *	1.04	Remove usage of deprecated functions, cleanup.
- *	1.05	More strict check in verify_port.  Cleanup.
- *	1.06	Do not insert a char caused previous overrun.
- *		Fix some spin_locks.
- *		Do not call uart_add_one_port for absent ports.
- *	1.07	Use CONFIG_SERIAL_TXX9_NR_UARTS.  Cleanup.
- *	1.08	Use platform_device.
- *		Fix and cleanup suspend/resume/initialization codes.
  */
 
 #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -62,7 +37,7 @@ #include <linux/mutex.h>
 
 #include <asm/io.h>
 
-static char *serial_version = "1.08";
+static char *serial_version = "1.09";
 static char *serial_name = "TX39/49 Serial driver";
 
 #define PASS_LIMIT	256
@@ -70,13 +45,14 @@ #define PASS_LIMIT	256
 #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
 /* "ttyS" is used for standard serial driver */
 #define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_MINOR_START	(64 + 64)	/* ttyTX0(128), ttyTX1(129) */
+#define TXX9_TTY_MINOR_START	196
+#define TXX9_TTY_MAJOR	204
 #else
 /* acts like standard serial driver */
 #define TXX9_TTY_NAME "ttyS"
 #define TXX9_TTY_MINOR_START	64
-#endif
 #define TXX9_TTY_MAJOR	TTY_MAJOR
+#endif
 
 /* flag aliases */
 #define UPF_TXX9_HAVE_CTS_LINE	UPF_BUGGY_UART
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 46c40bb..1f89496 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -46,6 +46,7 @@ #include <linux/cpufreq.h>
 #endif
 
 #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#include <linux/ctype.h>
 #include <asm/clock.h>
 #include <asm/sh_bios.h>
 #include <asm/kgdb.h>
@@ -61,7 +62,7 @@ struct sci_port {
 	unsigned int		type;
 
 	/* Port IRQs: ERI, RXI, TXI, BRI (optional) */
-	unsigned int		irqs[SCIx_NR_IRQS]; 
+	unsigned int		irqs[SCIx_NR_IRQS];
 
 	/* Port pin configuration */
 	void			(*init_pins)(struct uart_port *port,
@@ -76,6 +77,11 @@ struct sci_port {
 	/* Break timer */
 	struct timer_list	break_timer;
 	int			break_flag;
+
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+	/* Port clock */
+	struct clk		*clk;
+#endif
 };
 
 #ifdef CONFIG_SH_KGDB
@@ -163,7 +169,7 @@ #ifdef CONFIG_SH_STANDARD_BIOS
 	usegdb |= sh_bios_in_gdb_mode();
 #endif
 #ifdef CONFIG_SH_KGDB
-	usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
+	usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
 #endif
 
 	if (usegdb) {
@@ -204,7 +210,7 @@ static int kgdb_sci_getchar(void)
         int c;
 
         /* Keep trying to read a character, this could be neater */
-        while ((c = get_char(kgdb_sci_port)) < 0)
+        while ((c = get_char(&kgdb_sci_port->port)) < 0)
 		cpu_relax();
 
         return c;
@@ -212,7 +218,7 @@ static int kgdb_sci_getchar(void)
 
 static inline void kgdb_sci_putchar(int c)
 {
-        put_char(kgdb_sci_port, c);
+        put_char(&kgdb_sci_port->port, c);
 }
 #endif /* CONFIG_SH_KGDB */
 
@@ -283,12 +289,23 @@ #define sci_init_pins_scif NULL
 #endif
 
 #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) 
 /* 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_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
+{
+	unsigned int fcr_val = 0;
+
+	set_sh771x_scif_pfc(port);
+	if (cflag & CRTSCTS) {
+		fcr_val |= SCFCR_MCE;
+	}
+	sci_out(port, SCFCR, fcr_val);
+}
 #elif defined(CONFIG_CPU_SH3)
 /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -350,7 +367,7 @@ static void sci_init_pins_scif(struct ua
 	} else {
 #ifdef CONFIG_CPU_SUBTYPE_SH7343
 		/* Nothing */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
 		ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
 #else
 		ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
@@ -360,7 +377,9 @@ #endif
 }
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
 static inline int scif_txroom(struct uart_port *port)
 {
 	return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
@@ -735,12 +754,6 @@ static irqreturn_t sci_br_interrupt(int 
 
 	/* 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;
@@ -947,6 +960,10 @@ static int sci_startup(struct uart_port 
 	if (s->enable)
 		s->enable(port);
 
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+	s->clk = clk_get(NULL, "module_clk");
+#endif
+
 	sci_request_irq(s);
 	sci_start_tx(port);
 	sci_start_rx(port, 1);
@@ -964,6 +981,11 @@ static void sci_shutdown(struct uart_por
 
 	if (s->disable)
 		s->disable(port);
+
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+	clk_put(s->clk);
+	s->clk = NULL;
+#endif
 }
 
 static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -971,7 +993,6 @@ static void sci_set_termios(struct uart_
 {
 	struct sci_port *s = &sci_ports[port->line];
 	unsigned int status, baud, smr_val;
-	unsigned long flags;
 	int t;
 
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
@@ -983,18 +1004,14 @@ static void sci_set_termios(struct uart_
 		default:
 		{
 #if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
-			struct clk *clk = clk_get(NULL, "module_clk");
-			t = SCBRR_VALUE(baud, clk_get_rate(clk));
-			clk_put(clk);
+			t = SCBRR_VALUE(baud, clk_get_rate(s->clk));
 #else
 			t = SCBRR_VALUE(baud);
 #endif
-		}
 			break;
+		}
 	}
 
-	spin_lock_irqsave(&port->lock, flags);
-
 	do {
 		status = sci_in(port, SCxSR);
 	} while (!(status & SCxSR_TEND(port)));
@@ -1038,8 +1055,6 @@ #endif
 
 	if ((termios->c_cflag & CREAD) != 0)
               sci_start_rx(port,0);
-
-	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static const char *sci_type(struct uart_port *port)
@@ -1220,10 +1235,13 @@ static int __init serial_console_setup(s
 	if (!port->membase || !port->mapbase)
 		return -ENODEV;
 
-	spin_lock_init(&port->lock);
-
 	port->type = serial_console_port->type;
 
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+	if (!serial_console_port->clk)
+		serial_console_port->clk = clk_get(NULL, "module_clk");
+#endif
+
 	if (port->flags & UPF_IOREMAP)
 		sci_config_port(port, 0);
 
@@ -1247,7 +1265,7 @@ 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,
 };
@@ -1292,11 +1310,23 @@ 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;
 
+	kgdb_sci_port = &sci_ports[co->index];
+	port = &kgdb_sci_port->port;
+
+	/*
+	 * 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 (!port->type)
+		return -ENODEV;
+	if (!port->membase || !port->mapbase)
+		return -ENODEV;
+
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
@@ -1311,11 +1341,12 @@ #endif /* CONFIG_SH_KGDB */
 
 #ifdef CONFIG_SH_KGDB_CONSOLE
 static struct console kgdb_console = {
-        .name		= "ttySC",
-        .write		= kgdb_console_write,
-        .setup		= kgdb_console_setup,
-        .flags		= CON_PRINTBUFFER | CON_ENABLED,
-        .index		= -1,
+	.name		= "ttySC",
+	.device		= uart_console_device,
+	.write		= kgdb_console_write,
+	.setup		= kgdb_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 	.data		= &sci_uart_driver,
 };
 
@@ -1361,9 +1392,19 @@ static int __devinit sci_probe(struct pl
 	struct plat_sci_port *p = dev->dev.platform_data;
 	int i;
 
-	for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
+	for (i = 0; p && p->flags != 0; p++, i++) {
 		struct sci_port *sciport = &sci_ports[i];
 
+		/* Sanity check */
+		if (unlikely(i == SCI_NPORTS)) {
+			dev_notice(&dev->dev, "Attempting to register port "
+				   "%d when only %d are available.\n",
+				   i+1, SCI_NPORTS);
+			dev_notice(&dev->dev, "Consider bumping "
+				   "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+			break;
+		}
+
 		sciport->port.mapbase	= p->mapbase;
 
 		/*
@@ -1386,6 +1427,12 @@ static int __devinit sci_probe(struct pl
 		uart_add_one_port(&sci_uart_driver, &sciport->port);
 	}
 
+#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
+	kgdb_sci_port	= &sci_ports[kgdb_portnum];
+	kgdb_getchar	= kgdb_sci_getchar;
+	kgdb_putchar	= kgdb_sci_putchar;
+#endif
+
 #ifdef CONFIG_CPU_FREQ
 	cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
 	dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 77f7d63..fb04fb5 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -73,9 +73,13 @@ # define SCPCR  0xA4050116        /* 16 
 # 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)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) 
 # define SCSPTR0 0xA4400000	  /* 16 bit SCIF */
-# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_NPORTS 2
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define PACR 0xa4050100
+# define PBCR 0xa4050102
+# define SCSCR_INIT(port)          0x3B
 # define SCIF_ONLY
 #elif defined(CONFIG_CPU_SUBTYPE_SH73180)
 # define SCPDR  0xA4050138        /* 16 bit SCIF */
@@ -140,6 +144,16 @@ # define SCSPTR1	0xffe10024	/* 16 bit SC
 # 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
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+# define SCSPTR0	0xffea0024	/* 16 bit SCIF */
+# define SCSPTR1	0xffeb0024	/* 16 bit SCIF */
+# define SCSPTR2	0xffec0024	/* 16 bit SCIF */
+# define SCSPTR3	0xffed0024	/* 16 bit SCIF */
+# define SCSPTR4	0xffee0024	/* 16 bit SCIF */
+# define SCSPTR5	0xffef0024	/* 16 bit SCIF */
+# define SCIF_OPER	0x0001		/* Overrun error bit */
+# define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
 # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
 # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
@@ -163,7 +177,10 @@ #define SCI_CTRL_FLAGS_TIE  0x80 /* all 
 #define SCI_CTRL_FLAGS_RIE  0x40 /* all */
 #define SCI_CTRL_FLAGS_TE   0x20 /* all */
 #define SCI_CTRL_FLAGS_RE   0x10 /* all */
-#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
 #else
 #define SCI_CTRL_FLAGS_REIE 0
@@ -333,9 +350,15 @@ #define CPU_SCI_FNS(name, sci_offset, sc
   }
 
 #ifdef CONFIG_CPU_SH3
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+		                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+		                 h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+	  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7705) 
 #define SCIF_FNS(name, scif_offset, scif_size) \
   CPU_SCIF_FNS(name, scif_offset, scif_size)
 #else
@@ -362,8 +385,8 @@ #define SCIF_FNS(name, sh3_scif_offset, 
 #endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7710)
+    defined(CONFIG_CPU_SUBTYPE_SH7705) 
+
 SCIF_FNS(SCSMR,  0x00, 16)
 SCIF_FNS(SCBRR,  0x04,  8)
 SCIF_FNS(SCSCR,  0x08, 16)
@@ -385,7 +408,9 @@ SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x0
 SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
 SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
 SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
 SCIF_FNS(SCFDR,			     0x0e, 16, 0x1C, 16)
 SCIF_FNS(SCTFDR,		     0x0e, 16, 0x1C, 16)
 SCIF_FNS(SCRFDR,		     0x0e, 16, 0x20, 16)
@@ -471,13 +496,24 @@ static inline int sci_rxd_in(struct uart
 		return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
 	return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
 static inline int sci_rxd_in(struct uart_port *port)
 {
-	if (port->mapbase == SCSPTR0)
-		return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0;
-	return 1;
+	  return sci_in(port,SCxSR)&0x0010 ? 1 : 0;
+}
+static inline void set_sh771x_scif_pfc(struct uart_port *port)
+{
+	if (port->mapbase == 0xA4400000){
+		ctrl_outw(ctrl_inw(PACR)&0xffc0,PACR);
+		ctrl_outw(ctrl_inw(PBCR)&0x0fff,PBCR);
+		return;
+	}
+	if (port->mapbase == 0xA4410000){
+		ctrl_outw(ctrl_inw(PBCR)&0xf003,PBCR);
+		return;
+	}
 }
+
 #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
       defined(CONFIG_CPU_SUBTYPE_SH4_202)
@@ -576,6 +612,23 @@ static inline int sci_rxd_in(struct uart
 		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
 	return 1;
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xffea0000)
+		return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffeb0000)
+		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffec0000)
+		return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffed0000)
+		return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffee0000)
+		return ctrl_inw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffef0000)
+		return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
+	return 1;
+}
 #elif defined(CONFIG_CPU_SUBTYPE_SH7206)
 static inline int sci_rxd_in(struct uart_port *port)
 {
@@ -634,7 +687,9 @@ #endif
  * -- Mitch Davis - 15 Jul 2000
  */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705)
 #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 96a852a..2a63cdb 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1312,7 +1312,7 @@ static void sunsu_console_write(struct c
  *	- initialize the serial port
  *	Return non-zero if we didn't find a serial port.
  */
-static int sunsu_console_setup(struct console *co, char *options)
+static int __init sunsu_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port;
 	int baud = 9600;
@@ -1343,7 +1343,7 @@ static int sunsu_console_setup(struct co
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
-static struct console sunsu_cons = {
+static struct console sunsu_console = {
 	.name	=	"ttyS",
 	.write	=	sunsu_console_write,
 	.device	=	uart_console_device,
@@ -1373,9 +1373,9 @@ static inline struct console *SUNSU_CONS
 	if (i == num_uart)
 		return NULL;
 
-	sunsu_cons.index = i;
+	sunsu_console.index = i;
 
-	return &sunsu_cons;
+	return &sunsu_console;
 }
 #else
 #define SUNSU_CONSOLE(num_uart)		(NULL)
@@ -1387,8 +1387,8 @@ static enum su_type __devinit su_get_typ
 	struct device_node *ap = of_find_node_by_path("/aliases");
 
 	if (ap) {
-		char *keyb = of_get_property(ap, "keyboard", NULL);
-		char *ms = of_get_property(ap, "mouse", NULL);
+		const char *keyb = of_get_property(ap, "keyboard", NULL);
+		const char *ms = of_get_property(ap, "mouse", NULL);
 
 		if (keyb) {
 			if (dp == of_find_node_by_path(keyb))
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7e54e48..07c587e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -58,6 +58,23 @@ config SPI_ATMEL
 	  This selects a driver for the Atmel SPI Controller, present on
 	  many AT32 (AVR32) and AT91 (ARM) chips.
 
+config SPI_BFIN
+	tristate "SPI controller driver for ADI Blackfin5xx"
+	depends on SPI_MASTER && BFIN
+	help
+	  This is the SPI controller master driver for Blackfin 5xx processor.
+
+config SPI_AU1550
+	tristate "Au1550/Au12x0 SPI Controller"
+	depends on SPI_MASTER && (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+	select SPI_BITBANG
+	help
+	  If you say yes to this option, support will be included for the
+	  Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called au1550_spi.
+
 config SPI_BITBANG
 	tristate "Bitbanging SPI master"
 	depends on SPI_MASTER && EXPERIMENTAL
@@ -153,11 +170,19 @@ config SPI_AT25
 	  This driver can also be built as a module.  If so, the module
 	  will be called at25.
 
+config SPI_SPIDEV
+	tristate "User mode SPI device driver support"
+	depends on SPI_MASTER && EXPERIMENTAL
+	help
+	  This supports user mode SPI protocol drivers.
+
+	  Note that this application programming interface is EXPERIMENTAL
+	  and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+
 #
 # Add new SPI protocol masters in alphabetical order above this line
 #
 
-
 # (slave support would go here)
 
 endmenu # "SPI support"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c280ad..624b636 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -11,8 +11,10 @@ # config declarations into driver model 
 obj-$(CONFIG_SPI_MASTER)		+= spi.o
 
 # SPI master controller drivers (bus)
-obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
 obj-$(CONFIG_SPI_ATMEL)			+= atmel_spi.o
+obj-$(CONFIG_SPI_BFIN)			+= spi_bfin5xx.o
+obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
+obj-$(CONFIG_SPI_AU1550)		+= au1550_spi.o
 obj-$(CONFIG_SPI_BUTTERFLY)		+= spi_butterfly.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.o
@@ -24,6 +26,7 @@ # 	... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
 obj-$(CONFIG_SPI_AT25)		+= at25.o
+obj-$(CONFIG_SPI_SPIDEV)	+= spidev.o
 # 	... add above this line ...
 
 # SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
new file mode 100644
index 0000000..ae2b1af
--- /dev/null
+++ b/drivers/spi/au1550_spi.c
@@ -0,0 +1,974 @@
+/*
+ * au1550_spi.c - au1550 psc spi controller driver
+ * may work also with au1200, au1210, au1250
+ * will not work on au1000, au1100 and au1500 (no full spi controller there)
+ *
+ * Copyright (c) 2006 ATRON electronic GmbH
+ * Author: Jan Nikitenko <jan.nikitenko@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
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include <asm/mach-au1x00/au1550_spi.h>
+
+static unsigned usedma = 1;
+module_param(usedma, uint, 0644);
+
+/*
+#define AU1550_SPI_DEBUG_LOOPBACK
+*/
+
+
+#define AU1550_SPI_DBDMA_DESCRIPTORS 1
+#define AU1550_SPI_DMA_RXTMP_MINSIZE 2048U
+
+struct au1550_spi {
+	struct spi_bitbang bitbang;
+
+	volatile psc_spi_t __iomem *regs;
+	int irq;
+	unsigned freq_max;
+	unsigned freq_min;
+
+	unsigned len;
+	unsigned tx_count;
+	unsigned rx_count;
+	const u8 *tx;
+	u8 *rx;
+
+	void (*rx_word)(struct au1550_spi *hw);
+	void (*tx_word)(struct au1550_spi *hw);
+	int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
+	irqreturn_t (*irq_callback)(struct au1550_spi *hw);
+
+	struct completion master_done;
+
+	unsigned usedma;
+	u32 dma_tx_id;
+	u32 dma_rx_id;
+	u32 dma_tx_ch;
+	u32 dma_rx_ch;
+
+	u8 *dma_rx_tmpbuf;
+	unsigned dma_rx_tmpbuf_size;
+	u32 dma_rx_tmpbuf_addr;
+
+	struct spi_master *master;
+	struct device *dev;
+	struct au1550_spi_info *pdata;
+};
+
+
+/* we use an 8-bit memory device for dma transfers to/from spi fifo */
+static dbdev_tab_t au1550_spi_mem_dbdev =
+{
+	.dev_id			= DBDMA_MEM_CHAN,
+	.dev_flags		= DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC,
+	.dev_tsize		= 0,
+	.dev_devwidth		= 8,
+	.dev_physaddr		= 0x00000000,
+	.dev_intlevel		= 0,
+	.dev_intpolarity	= 0
+};
+
+static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);
+
+
+/**
+ *  compute BRG and DIV bits to setup spi clock based on main input clock rate
+ *  that was specified in platform data structure
+ *  according to au1550 datasheet:
+ *    psc_tempclk = psc_mainclk / (2 << DIV)
+ *    spiclk = psc_tempclk / (2 * (BRG + 1))
+ *    BRG valid range is 4..63
+ *    DIV valid range is 0..3
+ */
+static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz)
+{
+	u32 mainclk_hz = hw->pdata->mainclk_hz;
+	u32 div, brg;
+
+	for (div = 0; div < 4; div++) {
+		brg = mainclk_hz / speed_hz / (4 << div);
+		/* now we have BRG+1 in brg, so count with that */
+		if (brg < (4 + 1)) {
+			brg = (4 + 1);	/* speed_hz too big */
+			break;		/* set lowest brg (div is == 0) */
+		}
+		if (brg <= (63 + 1))
+			break;		/* we have valid brg and div */
+	}
+	if (div == 4) {
+		div = 3;		/* speed_hz too small */
+		brg = (63 + 1);		/* set highest brg and div */
+	}
+	brg--;
+	return PSC_SPICFG_SET_BAUD(brg) | PSC_SPICFG_SET_DIV(div);
+}
+
+static inline void au1550_spi_mask_ack_all(struct au1550_spi *hw)
+{
+	hw->regs->psc_spimsk =
+		  PSC_SPIMSK_MM | PSC_SPIMSK_RR | PSC_SPIMSK_RO
+		| PSC_SPIMSK_RU | PSC_SPIMSK_TR | PSC_SPIMSK_TO
+		| PSC_SPIMSK_TU | PSC_SPIMSK_SD | PSC_SPIMSK_MD;
+	au_sync();
+
+	hw->regs->psc_spievent =
+		  PSC_SPIEVNT_MM | PSC_SPIEVNT_RR | PSC_SPIEVNT_RO
+		| PSC_SPIEVNT_RU | PSC_SPIEVNT_TR | PSC_SPIEVNT_TO
+		| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD | PSC_SPIEVNT_MD;
+	au_sync();
+}
+
+static void au1550_spi_reset_fifos(struct au1550_spi *hw)
+{
+	u32 pcr;
+
+	hw->regs->psc_spipcr = PSC_SPIPCR_RC | PSC_SPIPCR_TC;
+	au_sync();
+	do {
+		pcr = hw->regs->psc_spipcr;
+		au_sync();
+	} while (pcr != 0);
+}
+
+/*
+ * dma transfers are used for the most common spi word size of 8-bits
+ * we cannot easily change already set up dma channels' width, so if we wanted
+ * dma support for more than 8-bit words (up to 24 bits), we would need to
+ * setup dma channels from scratch on each spi transfer, based on bits_per_word
+ * instead we have pre set up 8 bit dma channels supporting spi 4 to 8 bits
+ * transfers, and 9 to 24 bits spi transfers will be done in pio irq based mode
+ * callbacks to handle dma or pio are set up in au1550_spi_bits_handlers_set()
+ */
+static void au1550_spi_chipsel(struct spi_device *spi, int value)
+{
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+	unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+	u32 cfg, stat;
+
+	switch (value) {
+	case BITBANG_CS_INACTIVE:
+		if (hw->pdata->deactivate_cs)
+			hw->pdata->deactivate_cs(hw->pdata, spi->chip_select,
+					cspol);
+		break;
+
+	case BITBANG_CS_ACTIVE:
+		au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
+
+		cfg = hw->regs->psc_spicfg;
+		au_sync();
+		hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;
+		au_sync();
+
+		if (spi->mode & SPI_CPOL)
+			cfg |= PSC_SPICFG_BI;
+		else
+			cfg &= ~PSC_SPICFG_BI;
+		if (spi->mode & SPI_CPHA)
+			cfg &= ~PSC_SPICFG_CDE;
+		else
+			cfg |= PSC_SPICFG_CDE;
+
+		if (spi->mode & SPI_LSB_FIRST)
+			cfg |= PSC_SPICFG_MLF;
+		else
+			cfg &= ~PSC_SPICFG_MLF;
+
+		if (hw->usedma && spi->bits_per_word <= 8)
+			cfg &= ~PSC_SPICFG_DD_DISABLE;
+		else
+			cfg |= PSC_SPICFG_DD_DISABLE;
+		cfg = PSC_SPICFG_CLR_LEN(cfg);
+		cfg |= PSC_SPICFG_SET_LEN(spi->bits_per_word);
+
+		cfg = PSC_SPICFG_CLR_BAUD(cfg);
+		cfg &= ~PSC_SPICFG_SET_DIV(3);
+		cfg |= au1550_spi_baudcfg(hw, spi->max_speed_hz);
+
+		hw->regs->psc_spicfg = cfg | PSC_SPICFG_DE_ENABLE;
+		au_sync();
+		do {
+			stat = hw->regs->psc_spistat;
+			au_sync();
+		} while ((stat & PSC_SPISTAT_DR) == 0);
+
+		if (hw->pdata->activate_cs)
+			hw->pdata->activate_cs(hw->pdata, spi->chip_select,
+					cspol);
+		break;
+	}
+}
+
+static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+	unsigned bpw, hz;
+	u32 cfg, stat;
+
+	bpw = t ? t->bits_per_word : spi->bits_per_word;
+	hz = t ? t->speed_hz : spi->max_speed_hz;
+
+	if (bpw < 4 || bpw > 24) {
+		dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
+			bpw);
+		return -EINVAL;
+	}
+	if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
+		dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
+			hz);
+		return -EINVAL;
+	}
+
+	au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
+
+	cfg = hw->regs->psc_spicfg;
+	au_sync();
+	hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;
+	au_sync();
+
+	if (hw->usedma && bpw <= 8)
+		cfg &= ~PSC_SPICFG_DD_DISABLE;
+	else
+		cfg |= PSC_SPICFG_DD_DISABLE;
+	cfg = PSC_SPICFG_CLR_LEN(cfg);
+	cfg |= PSC_SPICFG_SET_LEN(bpw);
+
+	cfg = PSC_SPICFG_CLR_BAUD(cfg);
+	cfg &= ~PSC_SPICFG_SET_DIV(3);
+	cfg |= au1550_spi_baudcfg(hw, hz);
+
+	hw->regs->psc_spicfg = cfg;
+	au_sync();
+
+	if (cfg & PSC_SPICFG_DE_ENABLE) {
+		do {
+			stat = hw->regs->psc_spistat;
+			au_sync();
+		} while ((stat & PSC_SPISTAT_DR) == 0);
+	}
+
+	au1550_spi_reset_fifos(hw);
+	au1550_spi_mask_ack_all(hw);
+	return 0;
+}
+
+static int au1550_spi_setup(struct spi_device *spi)
+{
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+
+	if (spi->bits_per_word == 0)
+		spi->bits_per_word = 8;
+	if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
+		dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
+			spi->bits_per_word);
+		return -EINVAL;
+	}
+
+	if (spi->max_speed_hz == 0)
+		spi->max_speed_hz = hw->freq_max;
+	if (spi->max_speed_hz > hw->freq_max
+			|| spi->max_speed_hz < hw->freq_min)
+		return -EINVAL;
+	/*
+	 * NOTE: cannot change speed and other hw settings immediately,
+	 *       otherwise sharing of spi bus is not possible,
+	 *       so do not call setupxfer(spi, NULL) here
+	 */
+	return 0;
+}
+
+/*
+ * for dma spi transfers, we have to setup rx channel, otherwise there is
+ * no reliable way how to recognize that spi transfer is done
+ * dma complete callbacks are called before real spi transfer is finished
+ * and if only tx dma channel is set up (and rx fifo overflow event masked)
+ * spi master done event irq is not generated unless rx fifo is empty (emptied)
+ * so we need rx tmp buffer to use for rx dma if user does not provide one
+ */
+static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size)
+{
+	hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL);
+	if (!hw->dma_rx_tmpbuf)
+		return -ENOMEM;
+	hw->dma_rx_tmpbuf_size = size;
+	hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf,
+			size, DMA_FROM_DEVICE);
+	if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) {
+		kfree(hw->dma_rx_tmpbuf);
+		hw->dma_rx_tmpbuf = 0;
+		hw->dma_rx_tmpbuf_size = 0;
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw)
+{
+	dma_unmap_single(hw->dev, hw->dma_rx_tmpbuf_addr,
+			hw->dma_rx_tmpbuf_size, DMA_FROM_DEVICE);
+	kfree(hw->dma_rx_tmpbuf);
+	hw->dma_rx_tmpbuf = 0;
+	hw->dma_rx_tmpbuf_size = 0;
+}
+
+static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+	dma_addr_t dma_tx_addr;
+	dma_addr_t dma_rx_addr;
+	u32 res;
+
+	hw->len = t->len;
+	hw->tx_count = 0;
+	hw->rx_count = 0;
+
+	hw->tx = t->tx_buf;
+	hw->rx = t->rx_buf;
+	dma_tx_addr = t->tx_dma;
+	dma_rx_addr = t->rx_dma;
+
+	/*
+	 * check if buffers are already dma mapped, map them otherwise
+	 * use rx buffer in place of tx if tx buffer was not provided
+	 * use temp rx buffer (preallocated or realloc to fit) for rx dma
+	 */
+	if (t->rx_buf) {
+		if (t->rx_dma == 0) {	/* if DMA_ADDR_INVALID, map it */
+			dma_rx_addr = dma_map_single(hw->dev,
+					(void *)t->rx_buf,
+					t->len, DMA_FROM_DEVICE);
+			if (dma_mapping_error(dma_rx_addr))
+				dev_err(hw->dev, "rx dma map error\n");
+		}
+	} else {
+		if (t->len > hw->dma_rx_tmpbuf_size) {
+			int ret;
+
+			au1550_spi_dma_rxtmp_free(hw);
+			ret = au1550_spi_dma_rxtmp_alloc(hw, max(t->len,
+					AU1550_SPI_DMA_RXTMP_MINSIZE));
+			if (ret < 0)
+				return ret;
+		}
+		hw->rx = hw->dma_rx_tmpbuf;
+		dma_rx_addr = hw->dma_rx_tmpbuf_addr;
+		dma_sync_single_for_device(hw->dev, dma_rx_addr,
+			t->len, DMA_FROM_DEVICE);
+	}
+	if (t->tx_buf) {
+		if (t->tx_dma == 0) {	/* if DMA_ADDR_INVALID, map it */
+			dma_tx_addr = dma_map_single(hw->dev,
+					(void *)t->tx_buf,
+					t->len, DMA_TO_DEVICE);
+			if (dma_mapping_error(dma_tx_addr))
+				dev_err(hw->dev, "tx dma map error\n");
+		}
+	} else {
+		dma_sync_single_for_device(hw->dev, dma_rx_addr,
+				t->len, DMA_BIDIRECTIONAL);
+		hw->tx = hw->rx;
+	}
+
+	/* put buffers on the ring */
+	res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len);
+	if (!res)
+		dev_err(hw->dev, "rx dma put dest error\n");
+
+	res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len);
+	if (!res)
+		dev_err(hw->dev, "tx dma put source error\n");
+
+	au1xxx_dbdma_start(hw->dma_rx_ch);
+	au1xxx_dbdma_start(hw->dma_tx_ch);
+
+	/* by default enable nearly all events interrupt */
+	hw->regs->psc_spimsk = PSC_SPIMSK_SD;
+	au_sync();
+
+	/* start the transfer */
+	hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+	au_sync();
+
+	wait_for_completion(&hw->master_done);
+
+	au1xxx_dbdma_stop(hw->dma_tx_ch);
+	au1xxx_dbdma_stop(hw->dma_rx_ch);
+
+	if (!t->rx_buf) {
+		/* using the temporal preallocated and premapped buffer */
+		dma_sync_single_for_cpu(hw->dev, dma_rx_addr, t->len,
+			DMA_FROM_DEVICE);
+	}
+	/* unmap buffers if mapped above */
+	if (t->rx_buf && t->rx_dma == 0 )
+		dma_unmap_single(hw->dev, dma_rx_addr, t->len,
+			DMA_FROM_DEVICE);
+	if (t->tx_buf && t->tx_dma == 0 )
+		dma_unmap_single(hw->dev, dma_tx_addr, t->len,
+			DMA_TO_DEVICE);
+
+	return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;
+}
+
+static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
+{
+	u32 stat, evnt;
+
+	stat = hw->regs->psc_spistat;
+	evnt = hw->regs->psc_spievent;
+	au_sync();
+	if ((stat & PSC_SPISTAT_DI) == 0) {
+		dev_err(hw->dev, "Unexpected IRQ!\n");
+		return IRQ_NONE;
+	}
+
+	if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
+				| PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
+				| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+			!= 0) {
+		/*
+		 * due to an spi error we consider transfer as done,
+		 * so mask all events until before next transfer start
+		 * and stop the possibly running dma immediatelly
+		 */
+		au1550_spi_mask_ack_all(hw);
+		au1xxx_dbdma_stop(hw->dma_rx_ch);
+		au1xxx_dbdma_stop(hw->dma_tx_ch);
+
+		/* get number of transfered bytes */
+		hw->rx_count = hw->len - au1xxx_get_dma_residue(hw->dma_rx_ch);
+		hw->tx_count = hw->len - au1xxx_get_dma_residue(hw->dma_tx_ch);
+
+		au1xxx_dbdma_reset(hw->dma_rx_ch);
+		au1xxx_dbdma_reset(hw->dma_tx_ch);
+		au1550_spi_reset_fifos(hw);
+
+		dev_err(hw->dev,
+			"Unexpected SPI error: event=0x%x stat=0x%x!\n",
+			evnt, stat);
+
+		complete(&hw->master_done);
+		return IRQ_HANDLED;
+	}
+
+	if ((evnt & PSC_SPIEVNT_MD) != 0) {
+		/* transfer completed successfully */
+		au1550_spi_mask_ack_all(hw);
+		hw->rx_count = hw->len;
+		hw->tx_count = hw->len;
+		complete(&hw->master_done);
+	}
+	return IRQ_HANDLED;
+}
+
+
+/* routines to handle different word sizes in pio mode */
+#define AU1550_SPI_RX_WORD(size, mask)					\
+static void au1550_spi_rx_word_##size(struct au1550_spi *hw)		\
+{									\
+	u32 fifoword = hw->regs->psc_spitxrx & (u32)(mask);		\
+	au_sync();							\
+	if (hw->rx) {							\
+		*(u##size *)hw->rx = (u##size)fifoword;			\
+		hw->rx += (size) / 8;					\
+	}								\
+	hw->rx_count += (size) / 8;					\
+}
+
+#define AU1550_SPI_TX_WORD(size, mask)					\
+static void au1550_spi_tx_word_##size(struct au1550_spi *hw)		\
+{									\
+	u32 fifoword = 0;						\
+	if (hw->tx) {							\
+		fifoword = *(u##size *)hw->tx & (u32)(mask);		\
+		hw->tx += (size) / 8;					\
+	}								\
+	hw->tx_count += (size) / 8;					\
+	if (hw->tx_count >= hw->len)					\
+		fifoword |= PSC_SPITXRX_LC;				\
+	hw->regs->psc_spitxrx = fifoword;				\
+	au_sync();							\
+}
+
+AU1550_SPI_RX_WORD(8,0xff)
+AU1550_SPI_RX_WORD(16,0xffff)
+AU1550_SPI_RX_WORD(32,0xffffff)
+AU1550_SPI_TX_WORD(8,0xff)
+AU1550_SPI_TX_WORD(16,0xffff)
+AU1550_SPI_TX_WORD(32,0xffffff)
+
+static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
+{
+	u32 stat, mask;
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+
+	hw->tx = t->tx_buf;
+	hw->rx = t->rx_buf;
+	hw->len = t->len;
+	hw->tx_count = 0;
+	hw->rx_count = 0;
+
+	/* by default enable nearly all events after filling tx fifo */
+	mask = PSC_SPIMSK_SD;
+
+	/* fill the transmit FIFO */
+	while (hw->tx_count < hw->len) {
+
+		hw->tx_word(hw);
+
+		if (hw->tx_count >= hw->len) {
+			/* mask tx fifo request interrupt as we are done */
+			mask |= PSC_SPIMSK_TR;
+		}
+
+		stat = hw->regs->psc_spistat;
+		au_sync();
+		if (stat & PSC_SPISTAT_TF)
+			break;
+	}
+
+	/* enable event interrupts */
+	hw->regs->psc_spimsk = mask;
+	au_sync();
+
+	/* start the transfer */
+	hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+	au_sync();
+
+	wait_for_completion(&hw->master_done);
+
+	return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;
+}
+
+static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
+{
+	int busy;
+	u32 stat, evnt;
+
+	stat = hw->regs->psc_spistat;
+	evnt = hw->regs->psc_spievent;
+	au_sync();
+	if ((stat & PSC_SPISTAT_DI) == 0) {
+		dev_err(hw->dev, "Unexpected IRQ!\n");
+		return IRQ_NONE;
+	}
+
+	if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
+				| PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
+				| PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+			!= 0) {
+		dev_err(hw->dev,
+			"Unexpected SPI error: event=0x%x stat=0x%x!\n",
+			evnt, stat);
+		/*
+		 * due to an error we consider transfer as done,
+		 * so mask all events until before next transfer start
+		 */
+		au1550_spi_mask_ack_all(hw);
+		au1550_spi_reset_fifos(hw);
+		complete(&hw->master_done);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * while there is something to read from rx fifo
+	 * or there is a space to write to tx fifo:
+	 */
+	do {
+		busy = 0;
+		stat = hw->regs->psc_spistat;
+		au_sync();
+
+		if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) {
+			hw->rx_word(hw);
+			/* ack the receive request event */
+			hw->regs->psc_spievent = PSC_SPIEVNT_RR;
+			au_sync();
+			busy = 1;
+		}
+
+		if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) {
+			hw->tx_word(hw);
+			/* ack the transmit request event */
+			hw->regs->psc_spievent = PSC_SPIEVNT_TR;
+			au_sync();
+			busy = 1;
+		}
+	} while (busy);
+
+	evnt = hw->regs->psc_spievent;
+	au_sync();
+
+	if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) {
+		/* transfer completed successfully */
+		au1550_spi_mask_ack_all(hw);
+		complete(&hw->master_done);
+	}
+	return IRQ_HANDLED;
+}
+
+static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+	return hw->txrx_bufs(spi, t);
+}
+
+static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs)
+{
+	struct au1550_spi *hw = dev;
+	return hw->irq_callback(hw);
+}
+
+static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw)
+{
+	if (bpw <= 8) {
+		if (hw->usedma) {
+			hw->txrx_bufs = &au1550_spi_dma_txrxb;
+			hw->irq_callback = &au1550_spi_dma_irq_callback;
+		} else {
+			hw->rx_word = &au1550_spi_rx_word_8;
+			hw->tx_word = &au1550_spi_tx_word_8;
+			hw->txrx_bufs = &au1550_spi_pio_txrxb;
+			hw->irq_callback = &au1550_spi_pio_irq_callback;
+		}
+	} else if (bpw <= 16) {
+		hw->rx_word = &au1550_spi_rx_word_16;
+		hw->tx_word = &au1550_spi_tx_word_16;
+		hw->txrx_bufs = &au1550_spi_pio_txrxb;
+		hw->irq_callback = &au1550_spi_pio_irq_callback;
+	} else {
+		hw->rx_word = &au1550_spi_rx_word_32;
+		hw->tx_word = &au1550_spi_tx_word_32;
+		hw->txrx_bufs = &au1550_spi_pio_txrxb;
+		hw->irq_callback = &au1550_spi_pio_irq_callback;
+	}
+}
+
+static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
+{
+	u32 stat, cfg;
+
+	/* set up the PSC for SPI mode */
+	hw->regs->psc_ctrl = PSC_CTRL_DISABLE;
+	au_sync();
+	hw->regs->psc_sel = PSC_SEL_PS_SPIMODE;
+	au_sync();
+
+	hw->regs->psc_spicfg = 0;
+	au_sync();
+
+	hw->regs->psc_ctrl = PSC_CTRL_ENABLE;
+	au_sync();
+
+	do {
+		stat = hw->regs->psc_spistat;
+		au_sync();
+	} while ((stat & PSC_SPISTAT_SR) == 0);
+
+
+	cfg = hw->usedma ? 0 : PSC_SPICFG_DD_DISABLE;
+	cfg |= PSC_SPICFG_SET_LEN(8);
+	cfg |= PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8;
+	/* use minimal allowed brg and div values as initial setting: */
+	cfg |= PSC_SPICFG_SET_BAUD(4) | PSC_SPICFG_SET_DIV(0);
+
+#ifdef AU1550_SPI_DEBUG_LOOPBACK
+	cfg |= PSC_SPICFG_LB;
+#endif
+
+	hw->regs->psc_spicfg = cfg;
+	au_sync();
+
+	au1550_spi_mask_ack_all(hw);
+
+	hw->regs->psc_spicfg |= PSC_SPICFG_DE_ENABLE;
+	au_sync();
+
+	do {
+		stat = hw->regs->psc_spistat;
+		au_sync();
+	} while ((stat & PSC_SPISTAT_DR) == 0);
+}
+
+
+static int __init au1550_spi_probe(struct platform_device *pdev)
+{
+	struct au1550_spi *hw;
+	struct spi_master *master;
+	int err = 0;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));
+	if (master == NULL) {
+		dev_err(&pdev->dev, "No memory for spi_master\n");
+		err = -ENOMEM;
+		goto err_nomem;
+	}
+
+	hw = spi_master_get_devdata(master);
+
+	hw->master = spi_master_get(master);
+	hw->pdata = pdev->dev.platform_data;
+	hw->dev = &pdev->dev;
+
+	if (hw->pdata == NULL) {
+		dev_err(&pdev->dev, "No platform data supplied\n");
+		err = -ENOENT;
+		goto err_no_pdata;
+	}
+
+	platform_set_drvdata(pdev, hw);
+
+	init_completion(&hw->master_done);
+
+	hw->bitbang.master = hw->master;
+	hw->bitbang.setup_transfer = au1550_spi_setupxfer;
+	hw->bitbang.chipselect = au1550_spi_chipsel;
+	hw->bitbang.master->setup = au1550_spi_setup;
+	hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
+
+	switch (hw->pdata->bus_num) {
+	case 0:
+		hw->irq = AU1550_PSC0_INT;
+		hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR;
+		hw->dma_rx_id = DSCR_CMD0_PSC0_RX;
+		hw->dma_tx_id = DSCR_CMD0_PSC0_TX;
+		break;
+	case 1:
+		hw->irq = AU1550_PSC1_INT;
+		hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR;
+		hw->dma_rx_id = DSCR_CMD0_PSC1_RX;
+		hw->dma_tx_id = DSCR_CMD0_PSC1_TX;
+		break;
+	case 2:
+		hw->irq = AU1550_PSC2_INT;
+		hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR;
+		hw->dma_rx_id = DSCR_CMD0_PSC2_RX;
+		hw->dma_tx_id = DSCR_CMD0_PSC2_TX;
+		break;
+	case 3:
+		hw->irq = AU1550_PSC3_INT;
+		hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR;
+		hw->dma_rx_id = DSCR_CMD0_PSC3_RX;
+		hw->dma_tx_id = DSCR_CMD0_PSC3_TX;
+		break;
+	default:
+		dev_err(&pdev->dev, "Wrong bus_num of SPI\n");
+		err = -ENOENT;
+		goto err_no_pdata;
+	}
+
+	if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t),
+			pdev->name) == NULL) {
+		dev_err(&pdev->dev, "Cannot reserve iomem region\n");
+		err = -ENXIO;
+		goto err_no_iores;
+	}
+
+
+	if (usedma) {
+		if (pdev->dev.dma_mask == NULL)
+			dev_warn(&pdev->dev, "no dma mask\n");
+		else
+			hw->usedma = 1;
+	}
+
+	if (hw->usedma) {
+		/*
+		 * create memory device with 8 bits dev_devwidth
+		 * needed for proper byte ordering to spi fifo
+		 */
+		int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
+		if (!memid) {
+			dev_err(&pdev->dev,
+				"Cannot create dma 8 bit mem device\n");
+			err = -ENXIO;
+			goto err_dma_add_dev;
+		}
+
+		hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid,
+			hw->dma_tx_id, NULL, (void *)hw);
+		if (hw->dma_tx_ch == 0) {
+			dev_err(&pdev->dev,
+				"Cannot allocate tx dma channel\n");
+			err = -ENXIO;
+			goto err_no_txdma;
+		}
+		au1xxx_dbdma_set_devwidth(hw->dma_tx_ch, 8);
+		if (au1xxx_dbdma_ring_alloc(hw->dma_tx_ch,
+			AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {
+			dev_err(&pdev->dev,
+				"Cannot allocate tx dma descriptors\n");
+			err = -ENXIO;
+			goto err_no_txdma_descr;
+		}
+
+
+		hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id,
+			memid, NULL, (void *)hw);
+		if (hw->dma_rx_ch == 0) {
+			dev_err(&pdev->dev,
+				"Cannot allocate rx dma channel\n");
+			err = -ENXIO;
+			goto err_no_rxdma;
+		}
+		au1xxx_dbdma_set_devwidth(hw->dma_rx_ch, 8);
+		if (au1xxx_dbdma_ring_alloc(hw->dma_rx_ch,
+			AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {
+			dev_err(&pdev->dev,
+				"Cannot allocate rx dma descriptors\n");
+			err = -ENXIO;
+			goto err_no_rxdma_descr;
+		}
+
+		err = au1550_spi_dma_rxtmp_alloc(hw,
+			AU1550_SPI_DMA_RXTMP_MINSIZE);
+		if (err < 0) {
+			dev_err(&pdev->dev,
+				"Cannot allocate initial rx dma tmp buffer\n");
+			goto err_dma_rxtmp_alloc;
+		}
+	}
+
+	au1550_spi_bits_handlers_set(hw, 8);
+
+	err = request_irq(hw->irq, au1550_spi_irq, 0, pdev->name, hw);
+	if (err) {
+		dev_err(&pdev->dev, "Cannot claim IRQ\n");
+		goto err_no_irq;
+	}
+
+	master->bus_num = hw->pdata->bus_num;
+	master->num_chipselect = hw->pdata->num_chipselect;
+
+	/*
+	 *  precompute valid range for spi freq - from au1550 datasheet:
+	 *    psc_tempclk = psc_mainclk / (2 << DIV)
+	 *    spiclk = psc_tempclk / (2 * (BRG + 1))
+	 *    BRG valid range is 4..63
+	 *    DIV valid range is 0..3
+	 *  round the min and max frequencies to values that would still
+	 *  produce valid brg and div
+	 */
+	{
+		int min_div = (2 << 0) * (2 * (4 + 1));
+		int max_div = (2 << 3) * (2 * (63 + 1));
+		hw->freq_max = hw->pdata->mainclk_hz / min_div;
+		hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+	}
+
+	au1550_spi_setup_psc_as_spi(hw);
+
+	err = spi_bitbang_start(&hw->bitbang);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register SPI master\n");
+		goto err_register;
+	}
+
+	dev_info(&pdev->dev,
+		"spi master registered: bus_num=%d num_chipselect=%d\n",
+		master->bus_num, master->num_chipselect);
+
+	return 0;
+
+err_register:
+	free_irq(hw->irq, hw);
+
+err_no_irq:
+	au1550_spi_dma_rxtmp_free(hw);
+
+err_dma_rxtmp_alloc:
+err_no_rxdma_descr:
+	if (hw->usedma)
+		au1xxx_dbdma_chan_free(hw->dma_rx_ch);
+
+err_no_rxdma:
+err_no_txdma_descr:
+	if (hw->usedma)
+		au1xxx_dbdma_chan_free(hw->dma_tx_ch);
+
+err_no_txdma:
+err_dma_add_dev:
+	release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+
+err_no_iores:
+err_no_pdata:
+	spi_master_put(hw->master);
+
+err_nomem:
+	return err;
+}
+
+static int __exit au1550_spi_remove(struct platform_device *pdev)
+{
+	struct au1550_spi *hw = platform_get_drvdata(pdev);
+
+	dev_info(&pdev->dev, "spi master remove: bus_num=%d\n",
+		hw->master->bus_num);
+
+	spi_bitbang_stop(&hw->bitbang);
+	free_irq(hw->irq, hw);
+	release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+
+	if (hw->usedma) {
+		au1550_spi_dma_rxtmp_free(hw);
+		au1xxx_dbdma_chan_free(hw->dma_rx_ch);
+		au1xxx_dbdma_chan_free(hw->dma_tx_ch);
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	spi_master_put(hw->master);
+	return 0;
+}
+
+static struct platform_driver au1550_spi_drv = {
+	.remove = __exit_p(au1550_spi_remove),
+	.driver = {
+		.name = "au1550-spi",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init au1550_spi_init(void)
+{
+	return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);
+}
+module_init(au1550_spi_init);
+
+static void __exit au1550_spi_exit(void)
+{
+	platform_driver_unregister(&au1550_spi_drv);
+}
+module_exit(au1550_spi_exit);
+
+MODULE_DESCRIPTION("Au1550 PSC SPI Driver");
+MODULE_AUTHOR("Jan Nikitenko <jan.nikitenko@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6657331..c3219b2 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -152,6 +152,11 @@ static void spi_drv_shutdown(struct devi
 	sdrv->shutdown(to_spi_device(dev));
 }
 
+/**
+ * spi_register_driver - register a SPI driver
+ * @sdrv: the driver to register
+ * Context: can sleep
+ */
 int spi_register_driver(struct spi_driver *sdrv)
 {
 	sdrv->driver.bus = &spi_bus_type;
@@ -183,7 +188,13 @@ static LIST_HEAD(board_list);
 static DECLARE_MUTEX(board_lock);
 
 
-/* On typical mainboards, this is purely internal; and it's not needed
+/**
+ * spi_new_device - instantiate one new SPI device
+ * @master: Controller to which device is connected
+ * @chip: Describes the SPI device
+ * Context: can sleep
+ *
+ * On typical mainboards, this is purely internal; and it's not needed
  * after board init creates the hard-wired devices.  Some development
  * platforms may not be able to use spi_register_board_info though, and
  * this is exported so that for example a USB or parport based adapter
@@ -251,7 +262,12 @@ fail:
 }
 EXPORT_SYMBOL_GPL(spi_new_device);
 
-/*
+/**
+ * spi_register_board_info - register SPI devices for a given board
+ * @info: array of chip descriptors
+ * @n: how many descriptors are provided
+ * Context: can sleep
+ *
  * Board-specific early init code calls this (probably during arch_initcall)
  * with segments of the SPI device table.  Any device nodes are created later,
  * after the relevant parent SPI controller (bus_num) is defined.  We keep
@@ -337,9 +353,10 @@ static struct class spi_master_class = {
 /**
  * spi_alloc_master - allocate SPI master controller
  * @dev: the controller, possibly using the platform_bus
- * @size: how much driver-private data to preallocate; the pointer to this
+ * @size: how much zeroed driver-private data to allocate; the pointer to this
  *	memory is in the class_data field of the returned class_device,
  *	accessible with spi_master_get_devdata().
+ * Context: can sleep
  *
  * This call is used only by SPI master controller drivers, which are the
  * only ones directly touching chip registers.  It's how they allocate
@@ -375,6 +392,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master);
 /**
  * spi_register_master - register SPI master controller
  * @master: initialized master, originally from spi_alloc_master()
+ * Context: can sleep
  *
  * SPI master controllers connect to their drivers using some non-SPI bus,
  * such as the platform bus.  The final stage of probe() in that code
@@ -437,6 +455,7 @@ static int __unregister(struct device *d
 /**
  * spi_unregister_master - unregister SPI master controller
  * @master: the master being unregistered
+ * Context: can sleep
  *
  * This call is used only by SPI master controller drivers, which are the
  * only ones directly touching chip registers.
@@ -455,6 +474,7 @@ EXPORT_SYMBOL_GPL(spi_unregister_master)
 /**
  * spi_busnum_to_master - look up master associated with bus_num
  * @bus_num: the master's bus number
+ * Context: can sleep
  *
  * This call may be used with devices that are registered after
  * arch init time.  It returns a refcounted pointer to the relevant
@@ -492,6 +512,7 @@ static void spi_complete(void *arg)
  * spi_sync - blocking/synchronous SPI data transfers
  * @spi: device with which data will be exchanged
  * @message: describes the data transfers
+ * Context: can sleep
  *
  * This call may only be used from a context that may sleep.  The sleep
  * is non-interruptible, and has no timeout.  Low-overhead controller
@@ -508,7 +529,7 @@ static void spi_complete(void *arg)
  *
  * The return value is a negative error code if the message could not be
  * submitted, else zero.  When the value is zero, then message->status is
- * also defined:  it's the completion code for the transfer, either zero
+ * also defined;  it's the completion code for the transfer, either zero
  * or a negative error code from the controller driver.
  */
 int spi_sync(struct spi_device *spi, struct spi_message *message)
@@ -538,6 +559,7 @@ static u8	*buf;
  * @n_tx: size of txbuf, in bytes
  * @rxbuf: buffer into which data will be read
  * @n_rx: size of rxbuf, in bytes (need not be dma-safe)
+ * Context: can sleep
  *
  * This performs a half duplex MicroWire style transaction with the
  * device, sending txbuf and then reading rxbuf.  The return value
@@ -545,7 +567,8 @@ static u8	*buf;
  * This call may only be used from a context that may sleep.
  *
  * Parameters to this routine are always copied using a small buffer;
- * performance-sensitive or bulk transfer code should instead use
+ * portable code should never use this for more than 32 bytes.
+ * Performance-sensitive or bulk transfer code should instead use
  * spi_{async,sync}() calls with dma-safe buffers.
  */
 int spi_write_then_read(struct spi_device *spi,
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
new file mode 100644
index 0000000..ce3c0ce
--- /dev/null
+++ b/drivers/spi/spi_bfin5xx.c
@@ -0,0 +1,1313 @@
+/*
+ * File:         drivers/spi/bfin5xx_spi.c
+ * Based on:     N/A
+ * Author:       Luke Yang (Analog Devices Inc.)
+ *
+ * Created:      March. 10th 2006
+ * Description:  SPI controller driver for Blackfin 5xx
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Modified:
+ *	March 10, 2006  bfin5xx_spi.c Created. (Luke Yang)
+ *      August 7, 2006  added full duplex mode (Axel Weiss & Luke Yang)
+ *
+ * Copyright 2004-2006 Analog Devices 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/dma.h>
+
+#include <asm/bfin5xx_spi.h>
+
+MODULE_AUTHOR("Luke Yang");
+MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller");
+MODULE_LICENSE("GPL");
+
+#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+
+#define DEFINE_SPI_REG(reg, off) \
+static inline u16 read_##reg(void) \
+            { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \
+static inline void write_##reg(u16 v) \
+            {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\
+             SSYNC();}
+
+DEFINE_SPI_REG(CTRL, 0x00)
+DEFINE_SPI_REG(FLAG, 0x04)
+DEFINE_SPI_REG(STAT, 0x08)
+DEFINE_SPI_REG(TDBR, 0x0C)
+DEFINE_SPI_REG(RDBR, 0x10)
+DEFINE_SPI_REG(BAUD, 0x14)
+DEFINE_SPI_REG(SHAW, 0x18)
+#define START_STATE ((void*)0)
+#define RUNNING_STATE ((void*)1)
+#define DONE_STATE ((void*)2)
+#define ERROR_STATE ((void*)-1)
+#define QUEUE_RUNNING 0
+#define QUEUE_STOPPED 1
+int dma_requested;
+
+struct driver_data {
+	/* Driver model hookup */
+	struct platform_device *pdev;
+
+	/* SPI framework hookup */
+	struct spi_master *master;
+
+	/* BFIN hookup */
+	struct bfin5xx_spi_master *master_info;
+
+	/* Driver message queue */
+	struct workqueue_struct *workqueue;
+	struct work_struct pump_messages;
+	spinlock_t lock;
+	struct list_head queue;
+	int busy;
+	int run;
+
+	/* Message Transfer pump */
+	struct tasklet_struct pump_transfers;
+
+	/* Current message transfer state info */
+	struct spi_message *cur_msg;
+	struct spi_transfer *cur_transfer;
+	struct chip_data *cur_chip;
+	size_t len_in_bytes;
+	size_t len;
+	void *tx;
+	void *tx_end;
+	void *rx;
+	void *rx_end;
+	int dma_mapped;
+	dma_addr_t rx_dma;
+	dma_addr_t tx_dma;
+	size_t rx_map_len;
+	size_t tx_map_len;
+	u8 n_bytes;
+	void (*write) (struct driver_data *);
+	void (*read) (struct driver_data *);
+	void (*duplex) (struct driver_data *);
+};
+
+struct chip_data {
+	u16 ctl_reg;
+	u16 baud;
+	u16 flag;
+
+	u8 chip_select_num;
+	u8 n_bytes;
+	u32 width;		/* 0 or 1 */
+	u8 enable_dma;
+	u8 bits_per_word;	/* 8 or 16 */
+	u8 cs_change_per_word;
+	u8 cs_chg_udelay;
+	void (*write) (struct driver_data *);
+	void (*read) (struct driver_data *);
+	void (*duplex) (struct driver_data *);
+};
+
+void bfin_spi_enable(struct driver_data *drv_data)
+{
+	u16 cr;
+
+	cr = read_CTRL();
+	write_CTRL(cr | BIT_CTL_ENABLE);
+	SSYNC();
+}
+
+void bfin_spi_disable(struct driver_data *drv_data)
+{
+	u16 cr;
+
+	cr = read_CTRL();
+	write_CTRL(cr & (~BIT_CTL_ENABLE));
+	SSYNC();
+}
+
+/* Caculate the SPI_BAUD register value based on input HZ */
+static u16 hz_to_spi_baud(u32 speed_hz)
+{
+	u_long sclk = get_sclk();
+	u16 spi_baud = (sclk / (2 * speed_hz));
+
+	if ((sclk % (2 * speed_hz)) > 0)
+		spi_baud++;
+
+	pr_debug("sclk = %ld, speed_hz = %d, spi_baud = %d\n", sclk, speed_hz,
+		 spi_baud);
+
+	return spi_baud;
+}
+
+static int flush(struct driver_data *drv_data)
+{
+	unsigned long limit = loops_per_jiffy << 1;
+
+	/* wait for stop and clear stat */
+	while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
+		continue;
+
+	write_STAT(BIT_STAT_CLR);
+
+	return limit;
+}
+
+/* stop controller and re-config current chip*/
+static void restore_state(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	/* Clear status and disable clock */
+	write_STAT(BIT_STAT_CLR);
+	bfin_spi_disable(drv_data);
+	pr_debug("restoring spi ctl state\n");
+
+#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537)
+	pr_debug("chip select number is %d\n", chip->chip_select_num);
+
+	switch (chip->chip_select_num) {
+	case 1:
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00);
+		SSYNC();
+		break;
+
+	case 2:
+	case 3:
+		bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI);
+		SSYNC();
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
+		SSYNC();
+		break;
+
+	case 4:
+		bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI);
+		SSYNC();
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840);
+		SSYNC();
+		break;
+
+	case 5:
+		bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI);
+		SSYNC();
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820);
+		SSYNC();
+		break;
+
+	case 6:
+		bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI);
+		SSYNC();
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810);
+		SSYNC();
+		break;
+
+	case 7:
+		bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI);
+		SSYNC();
+		bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
+		SSYNC();
+		break;
+	}
+#endif
+
+	/* Load the registers */
+	write_CTRL(chip->ctl_reg);
+	write_BAUD(chip->baud);
+	write_FLAG(chip->flag);
+}
+
+/* used to kick off transfer in rx mode */
+static unsigned short dummy_read(void)
+{
+	unsigned short tmp;
+	tmp = read_RDBR();
+	return tmp;
+}
+
+static void null_writer(struct driver_data *drv_data)
+{
+	u8 n_bytes = drv_data->n_bytes;
+
+	while (drv_data->tx < drv_data->tx_end) {
+		write_TDBR(0);
+		while ((read_STAT() & BIT_STAT_TXS))
+			continue;
+		drv_data->tx += n_bytes;
+	}
+}
+
+static void null_reader(struct driver_data *drv_data)
+{
+	u8 n_bytes = drv_data->n_bytes;
+	dummy_read();
+
+	while (drv_data->rx < drv_data->rx_end) {
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		dummy_read();
+		drv_data->rx += n_bytes;
+	}
+}
+
+static void u8_writer(struct driver_data *drv_data)
+{
+	pr_debug("cr8-s is 0x%x\n", read_STAT());
+	while (drv_data->tx < drv_data->tx_end) {
+		write_TDBR(*(u8 *) (drv_data->tx));
+		while (read_STAT() & BIT_STAT_TXS)
+			continue;
+		++drv_data->tx;
+	}
+
+	/* poll for SPI completion before returning */
+	while (!(read_STAT() & BIT_STAT_SPIF))
+		continue;
+}
+
+static void u8_cs_chg_writer(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->tx < drv_data->tx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		write_TDBR(*(u8 *) (drv_data->tx));
+		while (read_STAT() & BIT_STAT_TXS)
+			continue;
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		++drv_data->tx;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+static void u8_reader(struct driver_data *drv_data)
+{
+	pr_debug("cr-8 is 0x%x\n", read_STAT());
+
+	/* clear TDBR buffer before read(else it will be shifted out) */
+	write_TDBR(0xFFFF);
+
+	dummy_read();
+
+	while (drv_data->rx < drv_data->rx_end - 1) {
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u8 *) (drv_data->rx) = read_RDBR();
+		++drv_data->rx;
+	}
+
+	while (!(read_STAT() & BIT_STAT_RXS))
+		continue;
+	*(u8 *) (drv_data->rx) = read_SHAW();
+	++drv_data->rx;
+}
+
+static void u8_cs_chg_reader(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->rx < drv_data->rx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		read_RDBR();	/* kick off */
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		*(u8 *) (drv_data->rx) = read_SHAW();
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		++drv_data->rx;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+static void u8_duplex(struct driver_data *drv_data)
+{
+	/* in duplex mode, clk is triggered by writing of TDBR */
+	while (drv_data->rx < drv_data->rx_end) {
+		write_TDBR(*(u8 *) (drv_data->tx));
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u8 *) (drv_data->rx) = read_RDBR();
+		++drv_data->rx;
+		++drv_data->tx;
+	}
+}
+
+static void u8_cs_chg_duplex(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->rx < drv_data->rx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		write_TDBR(*(u8 *) (drv_data->tx));
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u8 *) (drv_data->rx) = read_RDBR();
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		++drv_data->rx;
+		++drv_data->tx;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+static void u16_writer(struct driver_data *drv_data)
+{
+	pr_debug("cr16 is 0x%x\n", read_STAT());
+	while (drv_data->tx < drv_data->tx_end) {
+		write_TDBR(*(u16 *) (drv_data->tx));
+		while ((read_STAT() & BIT_STAT_TXS))
+			continue;
+		drv_data->tx += 2;
+	}
+
+	/* poll for SPI completion before returning */
+	while (!(read_STAT() & BIT_STAT_SPIF))
+		continue;
+}
+
+static void u16_cs_chg_writer(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->tx < drv_data->tx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		write_TDBR(*(u16 *) (drv_data->tx));
+		while ((read_STAT() & BIT_STAT_TXS))
+			continue;
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		drv_data->tx += 2;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+static void u16_reader(struct driver_data *drv_data)
+{
+	pr_debug("cr-16 is 0x%x\n", read_STAT());
+	dummy_read();
+
+	while (drv_data->rx < (drv_data->rx_end - 2)) {
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u16 *) (drv_data->rx) = read_RDBR();
+		drv_data->rx += 2;
+	}
+
+	while (!(read_STAT() & BIT_STAT_RXS))
+		continue;
+	*(u16 *) (drv_data->rx) = read_SHAW();
+	drv_data->rx += 2;
+}
+
+static void u16_cs_chg_reader(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->rx < drv_data->rx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		read_RDBR();	/* kick off */
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		*(u16 *) (drv_data->rx) = read_SHAW();
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		drv_data->rx += 2;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+static void u16_duplex(struct driver_data *drv_data)
+{
+	/* in duplex mode, clk is triggered by writing of TDBR */
+	while (drv_data->tx < drv_data->tx_end) {
+		write_TDBR(*(u16 *) (drv_data->tx));
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u16 *) (drv_data->rx) = read_RDBR();
+		drv_data->rx += 2;
+		drv_data->tx += 2;
+	}
+}
+
+static void u16_cs_chg_duplex(struct driver_data *drv_data)
+{
+	struct chip_data *chip = drv_data->cur_chip;
+
+	while (drv_data->tx < drv_data->tx_end) {
+		write_FLAG(chip->flag);
+		SSYNC();
+
+		write_TDBR(*(u16 *) (drv_data->tx));
+		while (!(read_STAT() & BIT_STAT_SPIF))
+			continue;
+		while (!(read_STAT() & BIT_STAT_RXS))
+			continue;
+		*(u16 *) (drv_data->rx) = read_RDBR();
+		write_FLAG(0xFF00 | chip->flag);
+		SSYNC();
+		if (chip->cs_chg_udelay)
+			udelay(chip->cs_chg_udelay);
+		drv_data->rx += 2;
+		drv_data->tx += 2;
+	}
+	write_FLAG(0xFF00);
+	SSYNC();
+}
+
+/* test if ther is more transfer to be done */
+static void *next_transfer(struct driver_data *drv_data)
+{
+	struct spi_message *msg = drv_data->cur_msg;
+	struct spi_transfer *trans = drv_data->cur_transfer;
+
+	/* Move to next transfer */
+	if (trans->transfer_list.next != &msg->transfers) {
+		drv_data->cur_transfer =
+		    list_entry(trans->transfer_list.next,
+			       struct spi_transfer, transfer_list);
+		return RUNNING_STATE;
+	} else
+		return DONE_STATE;
+}
+
+/*
+ * caller already set message->status;
+ * dma and pio irqs are blocked give finished message back
+ */
+static void giveback(struct driver_data *drv_data)
+{
+	struct spi_transfer *last_transfer;
+	unsigned long flags;
+	struct spi_message *msg;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	msg = drv_data->cur_msg;
+	drv_data->cur_msg = NULL;
+	drv_data->cur_transfer = NULL;
+	drv_data->cur_chip = NULL;
+	queue_work(drv_data->workqueue, &drv_data->pump_messages);
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	last_transfer = list_entry(msg->transfers.prev,
+				   struct spi_transfer, transfer_list);
+
+	msg->state = NULL;
+
+	/* disable chip select signal. And not stop spi in autobuffer mode */
+	if (drv_data->tx_dma != 0xFFFF) {
+		write_FLAG(0xFF00);
+		bfin_spi_disable(drv_data);
+	}
+
+	if (msg->complete)
+		msg->complete(msg->context);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct driver_data *drv_data = (struct driver_data *)dev_id;
+	struct spi_message *msg = drv_data->cur_msg;
+
+	pr_debug("in dma_irq_handler\n");
+	clear_dma_irqstat(CH_SPI);
+
+	/*
+	 * wait for the last transaction shifted out.  yes, these two
+	 * while loops are supposed to be the same (see the HRM).
+	 */
+	if (drv_data->tx != NULL) {
+		while (bfin_read_SPI_STAT() & TXS)
+			continue;
+		while (bfin_read_SPI_STAT() & TXS)
+			continue;
+	}
+
+	while (!(bfin_read_SPI_STAT() & SPIF))
+		continue;
+
+	bfin_spi_disable(drv_data);
+
+	msg->actual_length += drv_data->len_in_bytes;
+
+	/* Move to next transfer */
+	msg->state = next_transfer(drv_data);
+
+	/* Schedule transfer tasklet */
+	tasklet_schedule(&drv_data->pump_transfers);
+
+	/* free the irq handler before next transfer */
+	pr_debug("disable dma channel irq%d\n", CH_SPI);
+	dma_disable_irq(CH_SPI);
+
+	return IRQ_HANDLED;
+}
+
+static void pump_transfers(unsigned long data)
+{
+	struct driver_data *drv_data = (struct driver_data *)data;
+	struct spi_message *message = NULL;
+	struct spi_transfer *transfer = NULL;
+	struct spi_transfer *previous = NULL;
+	struct chip_data *chip = NULL;
+	u16 cr, width, dma_width, dma_config;
+	u32 tranf_success = 1;
+
+	/* Get current state information */
+	message = drv_data->cur_msg;
+	transfer = drv_data->cur_transfer;
+	chip = drv_data->cur_chip;
+
+	/*
+	 * if msg is error or done, report it back using complete() callback
+	 */
+
+	 /* Handle for abort */
+	if (message->state == ERROR_STATE) {
+		message->status = -EIO;
+		giveback(drv_data);
+		return;
+	}
+
+	/* Handle end of message */
+	if (message->state == DONE_STATE) {
+		message->status = 0;
+		giveback(drv_data);
+		return;
+	}
+
+	/* Delay if requested at end of transfer */
+	if (message->state == RUNNING_STATE) {
+		previous = list_entry(transfer->transfer_list.prev,
+				      struct spi_transfer, transfer_list);
+		if (previous->delay_usecs)
+			udelay(previous->delay_usecs);
+	}
+
+	/* Setup the transfer state based on the type of transfer */
+	if (flush(drv_data) == 0) {
+		dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
+		message->status = -EIO;
+		giveback(drv_data);
+		return;
+	}
+
+	if (transfer->tx_buf != NULL) {
+		drv_data->tx = (void *)transfer->tx_buf;
+		drv_data->tx_end = drv_data->tx + transfer->len;
+		pr_debug("tx_buf is %p, tx_end is %p\n", transfer->tx_buf,
+			 drv_data->tx_end);
+	} else {
+		drv_data->tx = NULL;
+	}
+
+	if (transfer->rx_buf != NULL) {
+		drv_data->rx = transfer->rx_buf;
+		drv_data->rx_end = drv_data->rx + transfer->len;
+		pr_debug("rx_buf is %p, rx_end is %p\n", transfer->rx_buf,
+			 drv_data->rx_end);
+	} else {
+		drv_data->rx = NULL;
+	}
+
+	drv_data->rx_dma = transfer->rx_dma;
+	drv_data->tx_dma = transfer->tx_dma;
+	drv_data->len_in_bytes = transfer->len;
+
+	width = chip->width;
+	if (width == CFG_SPI_WORDSIZE16) {
+		drv_data->len = (transfer->len) >> 1;
+	} else {
+		drv_data->len = transfer->len;
+	}
+	drv_data->write = drv_data->tx ? chip->write : null_writer;
+	drv_data->read = drv_data->rx ? chip->read : null_reader;
+	drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+	pr_debug
+	    ("transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
+	     drv_data->write, chip->write, null_writer);
+
+	/* speed and width has been set on per message */
+	message->state = RUNNING_STATE;
+	dma_config = 0;
+
+	/* restore spi status for each spi transfer */
+	if (transfer->speed_hz) {
+		write_BAUD(hz_to_spi_baud(transfer->speed_hz));
+	} else {
+		write_BAUD(chip->baud);
+	}
+	write_FLAG(chip->flag);
+
+	pr_debug("now pumping a transfer: width is %d, len is %d\n", width,
+		 transfer->len);
+
+	/*
+	 * Try to map dma buffer and do a dma transfer if
+	 * successful use different way to r/w according to
+	 * drv_data->cur_chip->enable_dma
+	 */
+	if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+
+		write_STAT(BIT_STAT_CLR);
+		disable_dma(CH_SPI);
+		clear_dma_irqstat(CH_SPI);
+		bfin_spi_disable(drv_data);
+
+		/* config dma channel */
+		pr_debug("doing dma transfer\n");
+		if (width == CFG_SPI_WORDSIZE16) {
+			set_dma_x_count(CH_SPI, drv_data->len);
+			set_dma_x_modify(CH_SPI, 2);
+			dma_width = WDSIZE_16;
+		} else {
+			set_dma_x_count(CH_SPI, drv_data->len);
+			set_dma_x_modify(CH_SPI, 1);
+			dma_width = WDSIZE_8;
+		}
+
+		/* set transfer width,direction. And enable spi */
+		cr = (read_CTRL() & (~BIT_CTL_TIMOD));
+
+		/* dirty hack for autobuffer DMA mode */
+		if (drv_data->tx_dma == 0xFFFF) {
+			pr_debug("doing autobuffer DMA out.\n");
+
+			/* no irq in autobuffer mode */
+			dma_config =
+			    (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
+			set_dma_config(CH_SPI, dma_config);
+			set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
+			enable_dma(CH_SPI);
+			write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
+				   (CFG_SPI_ENABLE << 14));
+
+			/* just return here, there can only be one transfer in this mode */
+			message->status = 0;
+			giveback(drv_data);
+			return;
+		}
+
+		/* In dma mode, rx or tx must be NULL in one transfer */
+		if (drv_data->rx != NULL) {
+			/* set transfer mode, and enable SPI */
+			pr_debug("doing DMA in.\n");
+
+			/* disable SPI before write to TDBR */
+			write_CTRL(cr & ~BIT_CTL_ENABLE);
+
+			/* clear tx reg soformer data is not shifted out */
+			write_TDBR(0xFF);
+
+			set_dma_x_count(CH_SPI, drv_data->len);
+
+			/* start dma */
+			dma_enable_irq(CH_SPI);
+			dma_config = (WNR | RESTART | dma_width | DI_EN);
+			set_dma_config(CH_SPI, dma_config);
+			set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx);
+			enable_dma(CH_SPI);
+
+			cr |=
+			    CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
+							      14);
+			/* set transfer mode, and enable SPI */
+			write_CTRL(cr);
+		} else if (drv_data->tx != NULL) {
+			pr_debug("doing DMA out.\n");
+
+			/* start dma */
+			dma_enable_irq(CH_SPI);
+			dma_config = (RESTART | dma_width | DI_EN);
+			set_dma_config(CH_SPI, dma_config);
+			set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
+			enable_dma(CH_SPI);
+
+			write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
+				   (CFG_SPI_ENABLE << 14));
+
+		}
+	} else {
+		/* IO mode write then read */
+		pr_debug("doing IO transfer\n");
+
+		write_STAT(BIT_STAT_CLR);
+
+		if (drv_data->tx != NULL && drv_data->rx != NULL) {
+			/* full duplex mode */
+			BUG_ON((drv_data->tx_end - drv_data->tx) !=
+			       (drv_data->rx_end - drv_data->rx));
+			cr = (read_CTRL() & (~BIT_CTL_TIMOD));	/* clear the TIMOD bits */
+			cr |=
+			    CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE <<
+							    14);
+			pr_debug("IO duplex: cr is 0x%x\n", cr);
+
+			write_CTRL(cr);
+			SSYNC();
+
+			drv_data->duplex(drv_data);
+
+			if (drv_data->tx != drv_data->tx_end)
+				tranf_success = 0;
+		} else if (drv_data->tx != NULL) {
+			/* write only half duplex */
+			cr = (read_CTRL() & (~BIT_CTL_TIMOD));	/* clear the TIMOD bits */
+			cr |=
+			    CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE <<
+							    14);
+			pr_debug("IO write: cr is 0x%x\n", cr);
+
+			write_CTRL(cr);
+			SSYNC();
+
+			drv_data->write(drv_data);
+
+			if (drv_data->tx != drv_data->tx_end)
+				tranf_success = 0;
+		} else if (drv_data->rx != NULL) {
+			/* read only half duplex */
+			cr = (read_CTRL() & (~BIT_CTL_TIMOD));	/* cleare the TIMOD bits */
+			cr |=
+			    CFG_SPI_READ | (width << 8) | (CFG_SPI_ENABLE <<
+							   14);
+			pr_debug("IO read: cr is 0x%x\n", cr);
+
+			write_CTRL(cr);
+			SSYNC();
+
+			drv_data->read(drv_data);
+			if (drv_data->rx != drv_data->rx_end)
+				tranf_success = 0;
+		}
+
+		if (!tranf_success) {
+			pr_debug("IO write error!\n");
+			message->state = ERROR_STATE;
+		} else {
+			/* Update total byte transfered */
+			message->actual_length += drv_data->len;
+
+			/* Move to next transfer of this msg */
+			message->state = next_transfer(drv_data);
+		}
+
+		/* Schedule next transfer tasklet */
+		tasklet_schedule(&drv_data->pump_transfers);
+
+	}
+}
+
+/* pop a msg from queue and kick off real transfer */
+static void pump_messages(struct work_struct *work)
+{
+	struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages);
+	unsigned long flags;
+
+	/* Lock queue and check for queue work */
+	spin_lock_irqsave(&drv_data->lock, flags);
+	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+		/* pumper kicked off but no work to do */
+		drv_data->busy = 0;
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+		return;
+	}
+
+	/* Make sure we are not already running a message */
+	if (drv_data->cur_msg) {
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+		return;
+	}
+
+	/* Extract head of queue */
+	drv_data->cur_msg = list_entry(drv_data->queue.next,
+				       struct spi_message, queue);
+	list_del_init(&drv_data->cur_msg->queue);
+
+	/* Initial message state */
+	drv_data->cur_msg->state = START_STATE;
+	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+					    struct spi_transfer, transfer_list);
+
+	/* Setup the SSP using the per chip configuration */
+	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+	restore_state(drv_data);
+	pr_debug
+	    ("got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
+	     drv_data->cur_chip->baud, drv_data->cur_chip->flag,
+	     drv_data->cur_chip->ctl_reg);
+	pr_debug("the first transfer len is %d\n", drv_data->cur_transfer->len);
+
+	/* Mark as busy and launch transfers */
+	tasklet_schedule(&drv_data->pump_transfers);
+
+	drv_data->busy = 1;
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+/*
+ * got a msg to transfer, queue it in drv_data->queue.
+ * And kick off message pumper
+ */
+static int transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+
+	if (drv_data->run == QUEUE_STOPPED) {
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+		return -ESHUTDOWN;
+	}
+
+	msg->actual_length = 0;
+	msg->status = -EINPROGRESS;
+	msg->state = START_STATE;
+
+	pr_debug("adding an msg in transfer() \n");
+	list_add_tail(&msg->queue, &drv_data->queue);
+
+	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+		queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	return 0;
+}
+
+/* first setup for new devices */
+static int setup(struct spi_device *spi)
+{
+	struct bfin5xx_spi_chip *chip_info = NULL;
+	struct chip_data *chip;
+	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	u8 spi_flg;
+
+	/* Abort device setup if requested features are not supported */
+	if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
+		dev_err(&spi->dev, "requested mode not fully supported\n");
+		return -EINVAL;
+	}
+
+	/* Zero (the default) here means 8 bits */
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
+		return -EINVAL;
+
+	/* Only alloc (or use chip_info) on first setup */
+	chip = spi_get_ctldata(spi);
+	if (chip == NULL) {
+		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		chip->enable_dma = 0;
+		chip_info = spi->controller_data;
+	}
+
+	/* chip_info isn't always needed */
+	if (chip_info) {
+		chip->enable_dma = chip_info->enable_dma != 0
+		    && drv_data->master_info->enable_dma;
+		chip->ctl_reg = chip_info->ctl_reg;
+		chip->bits_per_word = chip_info->bits_per_word;
+		chip->cs_change_per_word = chip_info->cs_change_per_word;
+		chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+	}
+
+	/* translate common spi framework into our register */
+	if (spi->mode & SPI_CPOL)
+		chip->ctl_reg |= CPOL;
+	if (spi->mode & SPI_CPHA)
+		chip->ctl_reg |= CPHA;
+	if (spi->mode & SPI_LSB_FIRST)
+		chip->ctl_reg |= LSBF;
+	/* we dont support running in slave mode (yet?) */
+	chip->ctl_reg |= MSTR;
+
+	/*
+	 * if any one SPI chip is registered and wants DMA, request the
+	 * DMA channel for it
+	 */
+	if (chip->enable_dma && !dma_requested) {
+		/* register dma irq handler */
+		if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) {
+			pr_debug
+			    ("Unable to request BlackFin SPI DMA channel\n");
+			return -ENODEV;
+		}
+		if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data)
+		    < 0) {
+			pr_debug("Unable to set dma callback\n");
+			return -EPERM;
+		}
+		dma_disable_irq(CH_SPI);
+		dma_requested = 1;
+	}
+
+	/*
+	 * Notice: for blackfin, the speed_hz is the value of register
+	 * SPI_BAUD, not the real baudrate
+	 */
+	chip->baud = hz_to_spi_baud(spi->max_speed_hz);
+	spi_flg = ~(1 << (spi->chip_select));
+	chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select));
+	chip->chip_select_num = spi->chip_select;
+
+	switch (chip->bits_per_word) {
+	case 8:
+		chip->n_bytes = 1;
+		chip->width = CFG_SPI_WORDSIZE8;
+		chip->read = chip->cs_change_per_word ?
+			u8_cs_chg_reader : u8_reader;
+		chip->write = chip->cs_change_per_word ?
+			u8_cs_chg_writer : u8_writer;
+		chip->duplex = chip->cs_change_per_word ?
+			u8_cs_chg_duplex : u8_duplex;
+		break;
+
+	case 16:
+		chip->n_bytes = 2;
+		chip->width = CFG_SPI_WORDSIZE16;
+		chip->read = chip->cs_change_per_word ?
+			u16_cs_chg_reader : u16_reader;
+		chip->write = chip->cs_change_per_word ?
+			u16_cs_chg_writer : u16_writer;
+		chip->duplex = chip->cs_change_per_word ?
+			u16_cs_chg_duplex : u16_duplex;
+		break;
+
+	default:
+		dev_err(&spi->dev, "%d bits_per_word is not supported\n",
+				chip->bits_per_word);
+		kfree(chip);
+		return -ENODEV;
+	}
+
+	pr_debug("setup spi chip %s, width is %d, dma is %d,",
+			spi->modalias, chip->width, chip->enable_dma);
+	pr_debug("ctl_reg is 0x%x, flag_reg is 0x%x\n",
+			chip->ctl_reg, chip->flag);
+
+	spi_set_ctldata(spi, chip);
+
+	return 0;
+}
+
+/*
+ * callback for spi framework.
+ * clean driver specific data
+ */
+static void cleanup(const struct spi_device *spi)
+{
+	struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+
+	kfree(chip);
+}
+
+static inline int init_queue(struct driver_data *drv_data)
+{
+	INIT_LIST_HEAD(&drv_data->queue);
+	spin_lock_init(&drv_data->lock);
+
+	drv_data->run = QUEUE_STOPPED;
+	drv_data->busy = 0;
+
+	/* init transfer tasklet */
+	tasklet_init(&drv_data->pump_transfers,
+		     pump_transfers, (unsigned long)drv_data);
+
+	/* init messages workqueue */
+	INIT_WORK(&drv_data->pump_messages, pump_messages);
+	drv_data->workqueue =
+	    create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id);
+	if (drv_data->workqueue == NULL)
+		return -EBUSY;
+
+	return 0;
+}
+
+static inline int start_queue(struct driver_data *drv_data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+
+	if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+		return -EBUSY;
+	}
+
+	drv_data->run = QUEUE_RUNNING;
+	drv_data->cur_msg = NULL;
+	drv_data->cur_transfer = NULL;
+	drv_data->cur_chip = NULL;
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+	return 0;
+}
+
+static inline int stop_queue(struct driver_data *drv_data)
+{
+	unsigned long flags;
+	unsigned limit = 500;
+	int status = 0;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+
+	/*
+	 * This is a bit lame, but is optimized for the common execution path.
+	 * A wait_queue on the drv_data->busy could be used, but then the common
+	 * execution path (pump_messages) would be required to call wake_up or
+	 * friends on every SPI message. Do this instead
+	 */
+	drv_data->run = QUEUE_STOPPED;
+	while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+		msleep(10);
+		spin_lock_irqsave(&drv_data->lock, flags);
+	}
+
+	if (!list_empty(&drv_data->queue) || drv_data->busy)
+		status = -EBUSY;
+
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	return status;
+}
+
+static inline int destroy_queue(struct driver_data *drv_data)
+{
+	int status;
+
+	status = stop_queue(drv_data);
+	if (status != 0)
+		return status;
+
+	destroy_workqueue(drv_data->workqueue);
+
+	return 0;
+}
+
+static int __init bfin5xx_spi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bfin5xx_spi_master *platform_info;
+	struct spi_master *master;
+	struct driver_data *drv_data = 0;
+	int status = 0;
+
+	platform_info = dev->platform_data;
+
+	/* Allocate master with space for drv_data */
+	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+	if (!master) {
+		dev_err(&pdev->dev, "can not alloc spi_master\n");
+		return -ENOMEM;
+	}
+	drv_data = spi_master_get_devdata(master);
+	drv_data->master = master;
+	drv_data->master_info = platform_info;
+	drv_data->pdev = pdev;
+
+	master->bus_num = pdev->id;
+	master->num_chipselect = platform_info->num_chipselect;
+	master->cleanup = cleanup;
+	master->setup = setup;
+	master->transfer = transfer;
+
+	/* Initial and start queue */
+	status = init_queue(drv_data);
+	if (status != 0) {
+		dev_err(&pdev->dev, "problem initializing queue\n");
+		goto out_error_queue_alloc;
+	}
+	status = start_queue(drv_data);
+	if (status != 0) {
+		dev_err(&pdev->dev, "problem starting queue\n");
+		goto out_error_queue_alloc;
+	}
+
+	/* Register with the SPI framework */
+	platform_set_drvdata(pdev, drv_data);
+	status = spi_register_master(master);
+	if (status != 0) {
+		dev_err(&pdev->dev, "problem registering spi master\n");
+		goto out_error_queue_alloc;
+	}
+	pr_debug("controller probe successfully\n");
+	return status;
+
+      out_error_queue_alloc:
+	destroy_queue(drv_data);
+	spi_master_put(master);
+	return status;
+}
+
+/* stop hardware and remove the driver */
+static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
+{
+	struct driver_data *drv_data = platform_get_drvdata(pdev);
+	int status = 0;
+
+	if (!drv_data)
+		return 0;
+
+	/* Remove the queue */
+	status = destroy_queue(drv_data);
+	if (status != 0)
+		return status;
+
+	/* Disable the SSP at the peripheral and SOC level */
+	bfin_spi_disable(drv_data);
+
+	/* Release DMA */
+	if (drv_data->master_info->enable_dma) {
+		if (dma_channel_active(CH_SPI))
+			free_dma(CH_SPI);
+	}
+
+	/* Disconnect from the SPI framework */
+	spi_unregister_master(drv_data->master);
+
+	/* Prevent double remove */
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct driver_data *drv_data = platform_get_drvdata(pdev);
+	int status = 0;
+
+	status = stop_queue(drv_data);
+	if (status != 0)
+		return status;
+
+	/* stop hardware */
+	bfin_spi_disable(drv_data);
+
+	return 0;
+}
+
+static int bfin5xx_spi_resume(struct platform_device *pdev)
+{
+	struct driver_data *drv_data = platform_get_drvdata(pdev);
+	int status = 0;
+
+	/* Enable the SPI interface */
+	bfin_spi_enable(drv_data);
+
+	/* Start the queue running */
+	status = start_queue(drv_data);
+	if (status != 0) {
+		dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+		return status;
+	}
+
+	return 0;
+}
+#else
+#define bfin5xx_spi_suspend NULL
+#define bfin5xx_spi_resume NULL
+#endif				/* CONFIG_PM */
+
+static struct platform_driver bfin5xx_spi_driver = {
+	.driver = {
+		   .name = "bfin-spi-master",
+		   .bus = &platform_bus_type,
+		   .owner = THIS_MODULE,
+		   },
+	.probe = bfin5xx_spi_probe,
+	.remove = __devexit_p(bfin5xx_spi_remove),
+	.suspend = bfin5xx_spi_suspend,
+	.resume = bfin5xx_spi_resume,
+};
+
+static int __init bfin5xx_spi_init(void)
+{
+	return platform_driver_register(&bfin5xx_spi_driver);
+}
+
+module_init(bfin5xx_spi_init);
+
+static void __exit bfin5xx_spi_exit(void)
+{
+	platform_driver_unregister(&bfin5xx_spi_driver);
+}
+
+module_exit(bfin5xx_spi_exit);
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
index 312987a..0ee2b20 100644
--- a/drivers/spi/spi_butterfly.c
+++ b/drivers/spi/spi_butterfly.c
@@ -20,7 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/platform_device.h>
+#include <linux/device.h>
 #include <linux/parport.h>
 
 #include <linux/sched.h>
@@ -40,8 +40,6 @@ #include <linux/mtd/partitions.h>
  * and use this custom parallel port cable.
  */
 
-#undef	HAVE_USI	/* nyet */
-
 
 /* DATA output bits (pins 2..9 == D0..D7) */
 #define	butterfly_nreset (1 << 1)		/* pin 3 */
@@ -49,19 +47,13 @@ #define	butterfly_nreset (1 << 1)		/* pi
 #define	spi_sck_bit	(1 << 0)		/* pin 2 */
 #define	spi_mosi_bit	(1 << 7)		/* pin 9 */
 
-#define	usi_sck_bit	(1 << 3)		/* pin 5 */
-#define	usi_mosi_bit	(1 << 4)		/* pin 6 */
-
 #define	vcc_bits	((1 << 6) | (1 << 5))	/* pins 7, 8 */
 
 /* STATUS input bits */
 #define	spi_miso_bit	PARPORT_STATUS_BUSY	/* pin 11 */
 
-#define	usi_miso_bit	PARPORT_STATUS_PAPEROUT	/* pin 12 */
-
 /* CONTROL output bits */
 #define	spi_cs_bit	PARPORT_CONTROL_SELECT	/* pin 17 */
-/* USI uses no chipselect */
 
 
 
@@ -70,15 +62,6 @@ static inline struct butterfly *spidev_t
 	return spi->controller_data;
 }
 
-static inline int is_usidev(struct spi_device *spi)
-{
-#ifdef	HAVE_USI
-	return spi->chip_select != 1;
-#else
-	return 0;
-#endif
-}
-
 
 struct butterfly {
 	/* REVISIT ... for now, this must be first */
@@ -97,23 +80,13 @@ struct butterfly {
 
 /*----------------------------------------------------------------------*/
 
-/*
- * these routines may be slower than necessary because they're hiding
- * the fact that there are two different SPI busses on this cable: one
- * to the DataFlash chip (or AVR SPI controller), the other to the
- * AVR USI controller.
- */
-
 static inline void
 setsck(struct spi_device *spi, int is_on)
 {
 	struct butterfly	*pp = spidev_to_pp(spi);
 	u8			bit, byte = pp->lastbyte;
 
-	if (is_usidev(spi))
-		bit = usi_sck_bit;
-	else
-		bit = spi_sck_bit;
+	bit = spi_sck_bit;
 
 	if (is_on)
 		byte |= bit;
@@ -129,10 +102,7 @@ setmosi(struct spi_device *spi, int is_o
 	struct butterfly	*pp = spidev_to_pp(spi);
 	u8			bit, byte = pp->lastbyte;
 
-	if (is_usidev(spi))
-		bit = usi_mosi_bit;
-	else
-		bit = spi_mosi_bit;
+	bit = spi_mosi_bit;
 
 	if (is_on)
 		byte |= bit;
@@ -148,10 +118,7 @@ static inline int getmiso(struct spi_dev
 	int			value;
 	u8			bit;
 
-	if (is_usidev(spi))
-		bit = usi_miso_bit;
-	else
-		bit = spi_miso_bit;
+	bit = spi_miso_bit;
 
 	/* only STATUS_BUSY is NOT negated */
 	value = !(parport_read_status(pp->port) & bit);
@@ -166,10 +133,6 @@ static void butterfly_chipselect(struct 
 	if (value != BITBANG_CS_INACTIVE)
 		setsck(spi, spi->mode & SPI_CPOL);
 
-	/* no chipselect on this USI link config */
-	if (is_usidev(spi))
-		return;
-
 	/* here, value == "activate or not";
 	 * most PARPORT_CONTROL_* bits are negated, so we must
 	 * morph it to value == "bit value to write in control register"
@@ -237,24 +200,16 @@ static void butterfly_attach(struct parp
 	int			status;
 	struct butterfly	*pp;
 	struct spi_master	*master;
-	struct platform_device	*pdev;
+	struct device		*dev = p->physport->dev;
 
-	if (butterfly)
+	if (butterfly || !dev)
 		return;
 
 	/* REVISIT:  this just _assumes_ a butterfly is there ... no probe,
 	 * and no way to be selective about what it binds to.
 	 */
 
-	/* FIXME where should master->cdev.dev come from?
-	 * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc
-	 * setting up a platform device like this is an ugly kluge...
-	 */
-	pdev = platform_device_register_simple("butterfly", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return;
-
-	master = spi_alloc_master(&pdev->dev, sizeof *pp);
+	master = spi_alloc_master(dev, sizeof *pp);
 	if (!master) {
 		status = -ENOMEM;
 		goto done;
@@ -300,7 +255,7 @@ static void butterfly_attach(struct parp
 	parport_frob_control(pp->port, spi_cs_bit, 0);
 
 	/* stabilize power with chip in reset (nRESET), and
-	 * both spi_sck_bit and usi_sck_bit clear (CPOL=0)
+	 * spi_sck_bit clear (CPOL=0)
 	 */
 	pp->lastbyte |= vcc_bits;
 	parport_write_data(pp->port, pp->lastbyte);
@@ -334,23 +289,6 @@ static void butterfly_attach(struct parp
 		pr_debug("%s: dataflash at %s\n", p->name,
 				pp->dataflash->dev.bus_id);
 
-#ifdef	HAVE_USI
-	/* Bus 2 is only for talking to the AVR, and it can work no
-	 * matter who masters bus 1; needs appropriate AVR firmware.
-	 */
-	pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000;
-	strcpy(pp->info[1].modalias, "butterfly");
-	// pp->info[1].platform_data = ... TBD ... ;
-	pp->info[1].chip_select = 2,
-	pp->info[1].controller_data = pp;
-	pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]);
-	if (pp->butterfly)
-		pr_debug("%s: butterfly at %s\n", p->name,
-				pp->butterfly->dev.bus_id);
-
-	/* FIXME setup ACK for the IRQ line ...  */
-#endif
-
 	// dev_info(_what?_, ...)
 	pr_info("%s: AVR Butterfly\n", p->name);
 	butterfly = pp;
@@ -366,14 +304,12 @@ clean1:
 clean0:
 	(void) spi_master_put(pp->bitbang.master);
 done:
-	platform_device_unregister(pdev);
 	pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
 }
 
 static void butterfly_detach(struct parport *p)
 {
 	struct butterfly	*pp;
-	struct platform_device	*pdev;
 	int			status;
 
 	/* FIXME this global is ugly ... but, how to quickly get from
@@ -386,7 +322,6 @@ static void butterfly_detach(struct parp
 	butterfly = NULL;
 
 	/* stop() unregisters child devices too */
-	pdev = to_platform_device(pp->bitbang.master->cdev.dev);
 	status = spi_bitbang_stop(&pp->bitbang);
 
 	/* turn off VCC */
@@ -397,8 +332,6 @@ static void butterfly_detach(struct parp
 	parport_unregister_device(pp->pd);
 
 	(void) spi_master_put(pp->bitbang.master);
-
-	platform_device_unregister(pdev);
 }
 
 static struct parport_driver butterfly_driver = {
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index b10211c..d5a710f 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -342,8 +342,6 @@ static int s3c24xx_spi_probe(struct plat
 		goto err_register;
 	}
 
-	dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);
-
 	/* register all the devices associated */
 
 	bi = &hw->pdata->board_info[0];
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
new file mode 100644
index 0000000..c0a6dce
--- /dev/null
+++ b/drivers/spi/spidev.c
@@ -0,0 +1,584 @@
+/*
+ * spidev.c -- simple synchronous userspace interface to SPI devices
+ *
+ * Copyright (C) 2006 SWAPP
+ *	Andrea Paterniani <a.paterniani@swapp-eng.it>
+ * Copyright (C) 2007 David Brownell (simplification, cleanup)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spidev.h>
+
+#include <asm/uaccess.h>
+
+
+/*
+ * This supports acccess to SPI devices using normal userspace I/O calls.
+ * Note that while traditional UNIX/POSIX I/O semantics are half duplex,
+ * and often mask message boundaries, full SPI support requires full duplex
+ * transfers.  There are several kinds of of internal message boundaries to
+ * handle chipselect management and other protocol options.
+ *
+ * SPI has a character major number assigned.  We allocate minor numbers
+ * dynamically using a bitmask.  You must use hotplug tools, such as udev
+ * (or mdev with busybox) to create and destroy the /dev/spidevB.C device
+ * nodes, since there is no fixed association of minor numbers with any
+ * particular SPI bus or device.
+ */
+#define SPIDEV_MAJOR			153	/* assigned */
+#define N_SPI_MINORS			32	/* ... up to 256 */
+
+static unsigned long	minors[N_SPI_MINORS / BITS_PER_LONG];
+
+
+/* Bit masks for spi_device.mode management */
+#define SPI_MODE_MASK			(SPI_CPHA | SPI_CPOL)
+
+
+struct spidev_data {
+	struct device		dev;
+	struct spi_device	*spi;
+	struct list_head	device_entry;
+
+	struct mutex		buf_lock;
+	unsigned		users;
+	u8			*buffer;
+};
+
+static LIST_HEAD(device_list);
+static DEFINE_MUTEX(device_list_lock);
+
+static unsigned bufsiz = 4096;
+module_param(bufsiz, uint, S_IRUGO);
+MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
+
+/*-------------------------------------------------------------------------*/
+
+/* Read-only message with current device setup */
+static ssize_t
+spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+	struct spidev_data	*spidev;
+	struct spi_device	*spi;
+	ssize_t			status = 0;
+
+	/* chipselect only toggles at start or end of operation */
+	if (count > bufsiz)
+		return -EMSGSIZE;
+
+	spidev = filp->private_data;
+	spi = spidev->spi;
+
+	mutex_lock(&spidev->buf_lock);
+	status = spi_read(spi, spidev->buffer, count);
+	if (status == 0) {
+		unsigned long	missing;
+
+		missing = copy_to_user(buf, spidev->buffer, count);
+		if (count && missing == count)
+			status = -EFAULT;
+		else
+			status = count - missing;
+	}
+	mutex_unlock(&spidev->buf_lock);
+
+	return status;
+}
+
+/* Write-only message with current device setup */
+static ssize_t
+spidev_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct spidev_data	*spidev;
+	struct spi_device	*spi;
+	ssize_t			status = 0;
+	unsigned long		missing;
+
+	/* chipselect only toggles at start or end of operation */
+	if (count > bufsiz)
+		return -EMSGSIZE;
+
+	spidev = filp->private_data;
+	spi = spidev->spi;
+
+	mutex_lock(&spidev->buf_lock);
+	missing = copy_from_user(spidev->buffer, buf, count);
+	if (missing == 0) {
+		status = spi_write(spi, spidev->buffer, count);
+		if (status == 0)
+			status = count;
+	} else
+		status = -EFAULT;
+	mutex_unlock(&spidev->buf_lock);
+
+	return status;
+}
+
+static int spidev_message(struct spidev_data *spidev,
+		struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
+{
+	struct spi_message	msg;
+	struct spi_transfer	*k_xfers;
+	struct spi_transfer	*k_tmp;
+	struct spi_ioc_transfer *u_tmp;
+	struct spi_device	*spi = spidev->spi;
+	unsigned		n, total;
+	u8			*buf;
+	int			status = -EFAULT;
+
+	spi_message_init(&msg);
+	k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
+	if (k_xfers == NULL)
+		return -ENOMEM;
+
+	/* Construct spi_message, copying any tx data to bounce buffer.
+	 * We walk the array of user-provided transfers, using each one
+	 * to initialize a kernel version of the same transfer.
+	 */
+	mutex_lock(&spidev->buf_lock);
+	buf = spidev->buffer;
+	total = 0;
+	for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
+			n;
+			n--, k_tmp++, u_tmp++) {
+		k_tmp->len = u_tmp->len;
+
+		if (u_tmp->rx_buf) {
+			k_tmp->rx_buf = buf;
+			if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
+				goto done;
+		}
+		if (u_tmp->tx_buf) {
+			k_tmp->tx_buf = buf;
+			if (copy_from_user(buf, (const u8 __user *)u_tmp->tx_buf,
+					u_tmp->len))
+				goto done;
+		}
+
+		total += k_tmp->len;
+		if (total > bufsiz) {
+			status = -EMSGSIZE;
+			goto done;
+		}
+		buf += k_tmp->len;
+
+		k_tmp->cs_change = !!u_tmp->cs_change;
+		k_tmp->bits_per_word = u_tmp->bits_per_word;
+		k_tmp->delay_usecs = u_tmp->delay_usecs;
+		k_tmp->speed_hz = u_tmp->speed_hz;
+#ifdef VERBOSE
+		dev_dbg(&spi->dev,
+			"  xfer len %zd %s%s%s%dbits %u usec %uHz\n",
+			u_tmp->len,
+			u_tmp->rx_buf ? "rx " : "",
+			u_tmp->tx_buf ? "tx " : "",
+			u_tmp->cs_change ? "cs " : "",
+			u_tmp->bits_per_word ? : spi->bits_per_word,
+			u_tmp->delay_usecs,
+			u_tmp->speed_hz ? : spi->max_speed_hz);
+#endif
+		spi_message_add_tail(k_tmp, &msg);
+	}
+
+	status = spi_sync(spi, &msg);
+	if (status < 0)
+		goto done;
+
+	/* copy any rx data out of bounce buffer */
+	buf = spidev->buffer;
+	for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
+		if (u_tmp->rx_buf) {
+			if (__copy_to_user((u8 __user *)u_tmp->rx_buf, buf,
+					u_tmp->len)) {
+				status = -EFAULT;
+				goto done;
+			}
+		}
+		buf += u_tmp->len;
+	}
+	status = total;
+
+done:
+	mutex_unlock(&spidev->buf_lock);
+	kfree(k_xfers);
+	return status;
+}
+
+static int
+spidev_ioctl(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	int			err = 0;
+	int			retval = 0;
+	struct spidev_data	*spidev;
+	struct spi_device	*spi;
+	u32			tmp;
+	unsigned		n_ioc;
+	struct spi_ioc_transfer	*ioc;
+
+	/* Check type and command number */
+	if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
+		return -ENOTTY;
+
+	/* Check access direction once here; don't repeat below.
+	 * IOC_DIR is from the user perspective, while access_ok is
+	 * from the kernel perspective; so they look reversed.
+	 */
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE,
+				(void __user *)arg, _IOC_SIZE(cmd));
+	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+		err = !access_ok(VERIFY_READ,
+				(void __user *)arg, _IOC_SIZE(cmd));
+	if (err)
+		return -EFAULT;
+
+	spidev = filp->private_data;
+	spi = spidev->spi;
+
+	switch (cmd) {
+	/* read requests */
+	case SPI_IOC_RD_MODE:
+		retval = __put_user(spi->mode & SPI_MODE_MASK,
+					(__u8 __user *)arg);
+		break;
+	case SPI_IOC_RD_LSB_FIRST:
+		retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,
+					(__u8 __user *)arg);
+		break;
+	case SPI_IOC_RD_BITS_PER_WORD:
+		retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
+		break;
+	case SPI_IOC_RD_MAX_SPEED_HZ:
+		retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
+		break;
+
+	/* write requests */
+	case SPI_IOC_WR_MODE:
+		retval = __get_user(tmp, (u8 __user *)arg);
+		if (retval == 0) {
+			u8	save = spi->mode;
+
+			if (tmp & ~SPI_MODE_MASK) {
+				retval = -EINVAL;
+				break;
+			}
+
+			tmp |= spi->mode & ~SPI_MODE_MASK;
+			spi->mode = (u8)tmp;
+			retval = spi_setup(spi);
+			if (retval < 0)
+				spi->mode = save;
+			else
+				dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+		}
+		break;
+	case SPI_IOC_WR_LSB_FIRST:
+		retval = __get_user(tmp, (__u8 __user *)arg);
+		if (retval == 0) {
+			u8	save = spi->mode;
+
+			if (tmp)
+				spi->mode |= SPI_LSB_FIRST;
+			else
+				spi->mode &= ~SPI_LSB_FIRST;
+			retval = spi_setup(spi);
+			if (retval < 0)
+				spi->mode = save;
+			else
+				dev_dbg(&spi->dev, "%csb first\n",
+						tmp ? 'l' : 'm');
+		}
+		break;
+	case SPI_IOC_WR_BITS_PER_WORD:
+		retval = __get_user(tmp, (__u8 __user *)arg);
+		if (retval == 0) {
+			u8	save = spi->bits_per_word;
+
+			spi->bits_per_word = tmp;
+			retval = spi_setup(spi);
+			if (retval < 0)
+				spi->bits_per_word = save;
+			else
+				dev_dbg(&spi->dev, "%d bits per word\n", tmp);
+		}
+		break;
+	case SPI_IOC_WR_MAX_SPEED_HZ:
+		retval = __get_user(tmp, (__u32 __user *)arg);
+		if (retval == 0) {
+			u32	save = spi->max_speed_hz;
+
+			spi->max_speed_hz = tmp;
+			retval = spi_setup(spi);
+			if (retval < 0)
+				spi->max_speed_hz = save;
+			else
+				dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
+		}
+		break;
+
+	default:
+		/* segmented and/or full-duplex I/O request */
+		if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
+				|| _IOC_DIR(cmd) != _IOC_WRITE)
+			return -ENOTTY;
+
+		tmp = _IOC_SIZE(cmd);
+		if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
+			retval = -EINVAL;
+			break;
+		}
+		n_ioc = tmp / sizeof(struct spi_ioc_transfer);
+		if (n_ioc == 0)
+			break;
+
+		/* copy into scratch area */
+		ioc = kmalloc(tmp, GFP_KERNEL);
+		if (!ioc) {
+			retval = -ENOMEM;
+			break;
+		}
+		if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
+			retval = -EFAULT;
+			break;
+		}
+
+		/* translate to spi_message, execute */
+		retval = spidev_message(spidev, ioc, n_ioc);
+		kfree(ioc);
+		break;
+	}
+	return retval;
+}
+
+static int spidev_open(struct inode *inode, struct file *filp)
+{
+	struct spidev_data	*spidev;
+	int			status = -ENXIO;
+
+	mutex_lock(&device_list_lock);
+
+	list_for_each_entry(spidev, &device_list, device_entry) {
+		if (spidev->dev.devt == inode->i_rdev) {
+			status = 0;
+			break;
+		}
+	}
+	if (status == 0) {
+		if (!spidev->buffer) {
+			spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
+			if (!spidev->buffer) {
+				dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
+				status = -ENOMEM;
+			}
+		}
+		if (status == 0) {
+			spidev->users++;
+			filp->private_data = spidev;
+			nonseekable_open(inode, filp);
+		}
+	} else
+		pr_debug("spidev: nothing for minor %d\n", iminor(inode));
+
+	mutex_unlock(&device_list_lock);
+	return status;
+}
+
+static int spidev_release(struct inode *inode, struct file *filp)
+{
+	struct spidev_data	*spidev;
+	int			status = 0;
+
+	mutex_lock(&device_list_lock);
+	spidev = filp->private_data;
+	filp->private_data = NULL;
+	spidev->users--;
+	if (!spidev->users) {
+		kfree(spidev->buffer);
+		spidev->buffer = NULL;
+	}
+	mutex_unlock(&device_list_lock);
+
+	return status;
+}
+
+static struct file_operations spidev_fops = {
+	.owner =	THIS_MODULE,
+	/* REVISIT switch to aio primitives, so that userspace
+	 * gets more complete API coverage.  It'll simplify things
+	 * too, except for the locking.
+	 */
+	.write =	spidev_write,
+	.read =		spidev_read,
+	.ioctl =	spidev_ioctl,
+	.open =		spidev_open,
+	.release =	spidev_release,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* The main reason to have this class is to make mdev/udev create the
+ * /dev/spidevB.C character device nodes exposing our userspace API.
+ * It also simplifies memory management.
+ */
+
+static void spidev_classdev_release(struct device *dev)
+{
+	struct spidev_data	*spidev;
+
+	spidev = container_of(dev, struct spidev_data, dev);
+	kfree(spidev);
+}
+
+static struct class spidev_class = {
+	.name		= "spidev",
+	.owner		= THIS_MODULE,
+	.dev_release	= spidev_classdev_release,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int spidev_probe(struct spi_device *spi)
+{
+	struct spidev_data	*spidev;
+	int			status;
+	unsigned long		minor;
+
+	/* Allocate driver data */
+	spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
+	if (!spidev)
+		return -ENOMEM;
+
+	/* Initialize the driver data */
+	spidev->spi = spi;
+	mutex_init(&spidev->buf_lock);
+
+	INIT_LIST_HEAD(&spidev->device_entry);
+
+	/* If we can allocate a minor number, hook up this device.
+	 * Reusing minors is fine so long as udev or mdev is working.
+	 */
+	mutex_lock(&device_list_lock);
+	minor = find_first_zero_bit(minors, ARRAY_SIZE(minors));
+	if (minor < N_SPI_MINORS) {
+		spidev->dev.parent = &spi->dev;
+		spidev->dev.class = &spidev_class;
+		spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor);
+		snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id,
+				"spidev%d.%d",
+				spi->master->bus_num, spi->chip_select);
+		status = device_register(&spidev->dev);
+	} else {
+		dev_dbg(&spi->dev, "no minor number available!\n");
+		status = -ENODEV;
+	}
+	if (status == 0) {
+		set_bit(minor, minors);
+		dev_set_drvdata(&spi->dev, spidev);
+		list_add(&spidev->device_entry, &device_list);
+	}
+	mutex_unlock(&device_list_lock);
+
+	if (status != 0)
+		kfree(spidev);
+
+	return status;
+}
+
+static int spidev_remove(struct spi_device *spi)
+{
+	struct spidev_data	*spidev = dev_get_drvdata(&spi->dev);
+
+	mutex_lock(&device_list_lock);
+
+	list_del(&spidev->device_entry);
+	dev_set_drvdata(&spi->dev, NULL);
+	clear_bit(MINOR(spidev->dev.devt), minors);
+	device_unregister(&spidev->dev);
+
+	mutex_unlock(&device_list_lock);
+
+	return 0;
+}
+
+static struct spi_driver spidev_spi = {
+	.driver = {
+		.name =		"spidev",
+		.owner =	THIS_MODULE,
+	},
+	.probe =	spidev_probe,
+	.remove =	__devexit_p(spidev_remove),
+
+	/* NOTE:  suspend/resume methods are not necessary here.
+	 * We don't do anything except pass the requests to/from
+	 * the underlying controller.  The refrigerator handles
+	 * most issues; the controller driver handles the rest.
+	 */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spidev_init(void)
+{
+	int status;
+
+	/* Claim our 256 reserved device numbers.  Then register a class
+	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
+	 * the driver which manages those device numbers.
+	 */
+	BUILD_BUG_ON(N_SPI_MINORS > 256);
+	status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
+	if (status < 0)
+		return status;
+
+	status = class_register(&spidev_class);
+	if (status < 0) {
+		unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+		return status;
+	}
+
+	status = spi_register_driver(&spidev_spi);
+	if (status < 0) {
+		class_unregister(&spidev_class);
+		unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+	}
+	return status;
+}
+module_init(spidev_init);
+
+static void __exit spidev_exit(void)
+{
+	spi_unregister_driver(&spidev_spi);
+	class_unregister(&spidev_class);
+	unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+}
+module_exit(spidev_exit);
+
+MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
+MODULE_DESCRIPTION("User mode SPI device interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 71cb64e..c7b0a35 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -7692,7 +7692,7 @@ static int __init ixj_probe_pci(int *cnt
 	IXJ *j = NULL;
 
 	for (i = 0; i < IXJMAX - *cnt; i++) {
-		pci = pci_find_device(PCI_VENDOR_ID_QUICKNET,
+		pci = pci_get_device(PCI_VENDOR_ID_QUICKNET,
 				      PCI_DEVICE_ID_QUICKNET_XJ, pci);
 		if (!pci)
 			break;
@@ -7712,6 +7712,7 @@ static int __init ixj_probe_pci(int *cnt
 			printk(KERN_INFO "ixj: found Internet PhoneJACK PCI at 0x%x\n", j->DSPbase);
 		++*cnt;
 	}
+	pci_dev_put(pci);
 	return probe;
 }
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 9980a4d..b847bbc 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -85,8 +85,6 @@ source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
 
-source "drivers/usb/input/Kconfig"
-
 source "drivers/usb/image/Kconfig"
 
 source "drivers/usb/net/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 8b7ff46..0ef090b 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -15,7 +15,6 @@ 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/
 
 obj-$(CONFIG_USB_ACM)		+= class/
@@ -24,18 +23,6 @@ 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/
-obj-$(CONFIG_USB_KBD)		+= input/
-obj-$(CONFIG_USB_KBTAB)		+= input/
-obj-$(CONFIG_USB_MOUSE)		+= input/
-obj-$(CONFIG_USB_MTOUCH)	+= input/
-obj-$(CONFIG_USB_POWERMATE)	+= input/
-obj-$(CONFIG_USB_WACOM)		+= input/
-obj-$(CONFIG_USB_XPAD)		+= input/
-
 obj-$(CONFIG_USB_CATC)		+= net/
 obj-$(CONFIG_USB_KAWETH)	+= net/
 obj-$(CONFIG_USB_PEGASUS)	+= net/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 3dfa3e4..30b7bfb 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
  *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *  Copyright (C) 2007 Simon Arlott
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms of the GNU General Public License as published by the Free
@@ -34,14 +35,14 @@ #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/device.h>	/* FIXME: linux/firmware.h should include it itself */
+#include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/mutex.h>
 
 #include "usbatm.h"
 
-#define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands"
-#define DRIVER_VERSION	"0.2"
+#define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
+#define DRIVER_VERSION	"0.3"
 #define DRIVER_DESC	"Conexant AccessRunner ADSL USB modem driver"
 
 static const char cxacru_driver_name[] = "cxacru";
@@ -64,7 +65,7 @@ #define BR_STACK_ADDR	0x00187f10
 #define SDRAM_ENA	0x1
 
 #define CMD_TIMEOUT	2000	/* msecs */
-#define POLL_INTERVAL	5000	/* msecs */
+#define POLL_INTERVAL	1	/* secs */
 
 /* commands for interaction with the modem through the control channel before
  * firmware is loaded  */
@@ -146,6 +147,13 @@ enum cxacru_info_idx {
 	CXINF_MAX = 0x1c,
 };
 
+enum cxacru_poll_state {
+	CXPOLL_STOPPING,
+	CXPOLL_STOPPED,
+	CXPOLL_POLLING,
+	CXPOLL_SHUTDOWN
+};
+
 struct cxacru_modem_type {
 	u32 pll_f_clk;
 	u32 pll_b_clk;
@@ -158,7 +166,12 @@ struct cxacru_data {
 	const struct cxacru_modem_type *modem_type;
 
 	int line_status;
+	struct mutex adsl_state_serialize;
+	int adsl_status;
 	struct delayed_work poll_work;
+	u32 card_info[CXINF_MAX];
+	struct mutex poll_state_serialize;
+	int poll_state;
 
 	/* contol handles */
 	struct mutex cm_serialize;
@@ -170,6 +183,275 @@ struct cxacru_data {
 	struct completion snd_done;
 };
 
+static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
+	u8 *wdata, int wsize, u8 *rdata, int rsize);
+static void cxacru_poll_status(struct work_struct *work);
+
+/* Card info exported through sysfs */
+#define CXACRU__ATTR_INIT(_name) \
+static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
+
+#define CXACRU_CMD_INIT(_name) \
+static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
+	cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
+
+#define CXACRU_ATTR_INIT(_value, _type, _name) \
+static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
+	struct device_attribute *attr, char *buf) \
+{ \
+	struct usb_interface *intf = to_usb_interface(dev); \
+	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
+	struct cxacru_data *instance = usbatm_instance->driver_data; \
+	return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
+} \
+CXACRU__ATTR_INIT(_name)
+
+#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
+#define CXACRU_CMD_CREATE(_name)          CXACRU_DEVICE_CREATE_FILE(_name)
+#define CXACRU__ATTR_CREATE(_name)        CXACRU_DEVICE_CREATE_FILE(_name)
+
+#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
+#define CXACRU_CMD_REMOVE(_name)          CXACRU_DEVICE_REMOVE_FILE(_name)
+#define CXACRU__ATTR_REMOVE(_name)        CXACRU_DEVICE_REMOVE_FILE(_name)
+
+static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", value);
+}
+
+static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
+{
+	if (unlikely(value < 0)) {
+		return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
+						value / 100, -value % 100);
+	} else {
+		return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
+						value / 100, value % 100);
+	}
+}
+
+static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
+{
+	switch (value) {
+	case 0: return snprintf(buf, PAGE_SIZE, "no\n");
+	case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
+	default: return 0;
+	}
+}
+
+static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
+{
+	switch (value) {
+	case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
+	case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
+	case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
+	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
+	}
+}
+
+static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
+{
+	switch (value) {
+	case 0: return snprintf(buf, PAGE_SIZE, "down\n");
+	case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
+	case 2: return snprintf(buf, PAGE_SIZE, "training\n");
+	case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
+	case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
+	case 5: return snprintf(buf, PAGE_SIZE, "up\n");
+	case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
+	case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
+	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
+	}
+}
+
+static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
+{
+	switch (value) {
+	case 0: return 0;
+	case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
+	case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
+	case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
+	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
+	}
+}
+
+/*
+ * This could use MAC_ADDRESS_HIGH and MAC_ADDRESS_LOW, but since
+ * this data is already in atm_dev there's no point.
+ *
+ * MAC_ADDRESS_HIGH = 0x????5544
+ * MAC_ADDRESS_LOW  = 0x33221100
+ * Where 00-55 are bytes 0-5 of the MAC.
+ */
+static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
+	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+
+	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+			atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
+			atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
+}
+
+static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
+	struct cxacru_data *instance = usbatm_instance->driver_data;
+	u32 value = instance->card_info[CXINF_LINE_STARTABLE];
+
+	switch (value) {
+	case 0: return snprintf(buf, PAGE_SIZE, "running\n");
+	case 1: return snprintf(buf, PAGE_SIZE, "stopped\n");
+	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
+	}
+}
+
+static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
+	struct cxacru_data *instance = usbatm_instance->driver_data;
+	int ret;
+	int poll = -1;
+	char str_cmd[8];
+	int len = strlen(buf);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EACCES;
+
+	ret = sscanf(buf, "%7s", str_cmd);
+	if (ret != 1)
+		return -EINVAL;
+	ret = 0;
+
+	if (mutex_lock_interruptible(&instance->adsl_state_serialize))
+		return -ERESTARTSYS;
+
+	if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
+		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
+		if (ret < 0) {
+			atm_err(usbatm_instance, "change adsl state:"
+				" CHIP_ADSL_LINE_STOP returned %d\n", ret);
+
+			ret = -EIO;
+		} else {
+			ret = len;
+			poll = CXPOLL_STOPPED;
+		}
+	}
+
+	/* Line status is only updated every second
+	 * and the device appears to only react to
+	 * START/STOP every second too. Wait 1.5s to
+	 * be sure that restart will have an effect. */
+	if (!strcmp(str_cmd, "restart"))
+		msleep(1500);
+
+	if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
+		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
+		if (ret < 0) {
+			atm_err(usbatm_instance, "change adsl state:"
+				" CHIP_ADSL_LINE_START returned %d\n", ret);
+
+			ret = -EIO;
+		} else {
+			ret = len;
+			poll = CXPOLL_POLLING;
+		}
+	}
+
+	if (!strcmp(str_cmd, "poll")) {
+		ret = len;
+		poll = CXPOLL_POLLING;
+	}
+
+	if (ret == 0) {
+		ret = -EINVAL;
+		poll = -1;
+	}
+
+	if (poll == CXPOLL_POLLING) {
+		mutex_lock(&instance->poll_state_serialize);
+		switch (instance->poll_state) {
+		case CXPOLL_STOPPED:
+			/* start polling */
+			instance->poll_state = CXPOLL_POLLING;
+			break;
+
+		case CXPOLL_STOPPING:
+			/* abort stop request */
+			instance->poll_state = CXPOLL_POLLING;
+		case CXPOLL_POLLING:
+		case CXPOLL_SHUTDOWN:
+			/* don't start polling */
+			poll = -1;
+		}
+		mutex_unlock(&instance->poll_state_serialize);
+	} else if (poll == CXPOLL_STOPPED) {
+		mutex_lock(&instance->poll_state_serialize);
+		/* request stop */
+		if (instance->poll_state == CXPOLL_POLLING)
+			instance->poll_state = CXPOLL_STOPPING;
+		mutex_unlock(&instance->poll_state_serialize);
+	}
+
+	mutex_unlock(&instance->adsl_state_serialize);
+
+	if (poll == CXPOLL_POLLING)
+		cxacru_poll_status(&instance->poll_work.work);
+
+	return ret;
+}
+
+/*
+ * All device attributes are included in CXACRU_ALL_FILES
+ * so that the same list can be used multiple times:
+ *     INIT   (define the device attributes)
+ *     CREATE (create all the device files)
+ *     REMOVE (remove all the device files)
+ *
+ * With the last two being defined as needed in the functions
+ * they are used in before calling CXACRU_ALL_FILES()
+ */
+#define CXACRU_ALL_FILES(_action) \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_RATE,           u32,  downstream_rate); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_RATE,             u32,  upstream_rate); \
+CXACRU_ATTR_##_action(CXINF_LINK_STATUS,               LINK, link_status); \
+CXACRU_ATTR_##_action(CXINF_LINE_STATUS,               LINE, line_status); \
+CXACRU__ATTR_##_action(                                      mac_address); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_SNR_MARGIN,       dB,   upstream_snr_margin); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_SNR_MARGIN,     dB,   downstream_snr_margin); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_ATTENUATION,      dB,   upstream_attenuation); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_ATTENUATION,    dB,   downstream_attenuation); \
+CXACRU_ATTR_##_action(CXINF_TRANSMITTER_POWER,         s8,   transmitter_power); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_BITS_PER_FRAME,   u32,  upstream_bits_per_frame); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_BITS_PER_FRAME, u32,  downstream_bits_per_frame); \
+CXACRU_ATTR_##_action(CXINF_STARTUP_ATTEMPTS,          u32,  startup_attempts); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_CRC_ERRORS,       u32,  upstream_crc_errors); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_CRC_ERRORS,     u32,  downstream_crc_errors); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC_ERRORS,       u32,  upstream_fec_errors); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS,     u32,  downstream_fec_errors); \
+CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS,       u32,  upstream_hec_errors); \
+CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS,     u32,  downstream_hec_errors); \
+CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE,            bool, line_startable); \
+CXACRU_ATTR_##_action(CXINF_MODULATION,                MODU, modulation); \
+CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND,              u32,  adsl_headend); \
+CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT,  u32,  adsl_headend_environment); \
+CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION,        u32,  adsl_controller_version); \
+CXACRU_CMD_##_action(                                        adsl_state);
+
+CXACRU_ALL_FILES(INIT);
+
 /* the following three functions are stolen from drivers/usb/core/message.c */
 static void cxacru_blocking_completion(struct urb *urb)
 {
@@ -347,8 +629,6 @@ static int cxacru_card_status(struct cxa
 	return 0;
 }
 
-static void cxacru_poll_status(struct work_struct *work);
-
 static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
 		struct atm_dev *atm_dev)
 {
@@ -357,6 +637,7 @@ static int cxacru_atm_start(struct usbat
 	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
 	*/
 	int ret;
+	int start_polling = 1;
 
 	dbg("cxacru_atm_start");
 
@@ -369,14 +650,35 @@ static int cxacru_atm_start(struct usbat
 	}
 
 	/* start ADSL */
+	mutex_lock(&instance->adsl_state_serialize);
 	ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
 	if (ret < 0) {
 		atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
+		mutex_unlock(&instance->adsl_state_serialize);
 		return ret;
 	}
 
 	/* Start status polling */
-	cxacru_poll_status(&instance->poll_work.work);
+	mutex_lock(&instance->poll_state_serialize);
+	switch (instance->poll_state) {
+	case CXPOLL_STOPPED:
+		/* start polling */
+		instance->poll_state = CXPOLL_POLLING;
+		break;
+
+	case CXPOLL_STOPPING:
+		/* abort stop request */
+		instance->poll_state = CXPOLL_POLLING;
+	case CXPOLL_POLLING:
+	case CXPOLL_SHUTDOWN:
+		/* don't start polling */
+		start_polling = 0;
+	}
+	mutex_unlock(&instance->poll_state_serialize);
+	mutex_unlock(&instance->adsl_state_serialize);
+
+	if (start_polling)
+		cxacru_poll_status(&instance->poll_work.work);
 	return 0;
 }
 
@@ -387,14 +689,46 @@ static void cxacru_poll_status(struct wo
 	u32 buf[CXINF_MAX] = {};
 	struct usbatm_data *usbatm = instance->usbatm;
 	struct atm_dev *atm_dev = usbatm->atm_dev;
+	int keep_polling = 1;
 	int ret;
 
 	ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
 	if (ret < 0) {
-		atm_warn(usbatm, "poll status: error %d\n", ret);
+		if (ret != -ESHUTDOWN)
+			atm_warn(usbatm, "poll status: error %d\n", ret);
+
+		mutex_lock(&instance->poll_state_serialize);
+		if (instance->poll_state != CXPOLL_SHUTDOWN) {
+			instance->poll_state = CXPOLL_STOPPED;
+
+			if (ret != -ESHUTDOWN)
+				atm_warn(usbatm, "polling disabled, set adsl_state"
+						" to 'start' or 'poll' to resume\n");
+		}
+		mutex_unlock(&instance->poll_state_serialize);
 		goto reschedule;
 	}
 
+	memcpy(instance->card_info, buf, sizeof(instance->card_info));
+
+	if (instance->adsl_status != buf[CXINF_LINE_STARTABLE]) {
+		instance->adsl_status = buf[CXINF_LINE_STARTABLE];
+
+		switch (instance->adsl_status) {
+		case 0:
+			atm_printk(KERN_INFO, usbatm, "ADSL state: running\n");
+			break;
+
+		case 1:
+			atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n");
+			break;
+
+		default:
+			atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status);
+			break;
+		}
+	}
+
 	if (instance->line_status == buf[CXINF_LINE_STATUS])
 		goto reschedule;
 
@@ -449,7 +783,20 @@ static void cxacru_poll_status(struct wo
 		break;
 	}
 reschedule:
-	schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
+
+	mutex_lock(&instance->poll_state_serialize);
+	if (instance->poll_state == CXPOLL_STOPPING &&
+				instance->adsl_status == 1 && /* stopped */
+				instance->line_status == 0) /* down */
+		instance->poll_state = CXPOLL_STOPPED;
+
+	if (instance->poll_state == CXPOLL_STOPPED)
+		keep_polling = 0;
+	mutex_unlock(&instance->poll_state_serialize);
+
+	if (keep_polling)
+		schedule_delayed_work(&instance->poll_work,
+				round_jiffies_relative(POLL_INTERVAL*HZ));
 }
 
 static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
@@ -684,6 +1031,14 @@ static int cxacru_bind(struct usbatm_dat
 
 	instance->usbatm = usbatm_instance;
 	instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
+	memset(instance->card_info, 0, sizeof(instance->card_info));
+
+	mutex_init(&instance->poll_state_serialize);
+	instance->poll_state = CXPOLL_STOPPED;
+	instance->line_status = -1;
+	instance->adsl_status = -1;
+
+	mutex_init(&instance->adsl_state_serialize);
 
 	instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
 	if (!instance->rcv_buf) {
@@ -710,6 +1065,13 @@ static int cxacru_bind(struct usbatm_dat
 		goto fail;
 	}
 
+	#define CXACRU_DEVICE_CREATE_FILE(_name) \
+		ret = device_create_file(&intf->dev, &dev_attr_##_name); \
+		if (unlikely(ret)) \
+			goto fail_sysfs;
+	CXACRU_ALL_FILES(CREATE);
+	#undef CXACRU_DEVICE_CREATE_FILE
+
 	usb_fill_int_urb(instance->rcv_urb,
 			usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
 			instance->rcv_buf, PAGE_SIZE,
@@ -730,6 +1092,14 @@ static int cxacru_bind(struct usbatm_dat
 
 	return 0;
 
+ fail_sysfs:
+	dbg("cxacru_bind: device_create_file failed (%d)\n", ret);
+
+	#define CXACRU_DEVICE_REMOVE_FILE(_name) \
+		device_remove_file(&intf->dev, &dev_attr_##_name);
+	CXACRU_ALL_FILES(REMOVE);
+	#undef CXACRU_DEVICE_REVOVE_FILE
+
  fail:
 	free_page((unsigned long) instance->snd_buf);
 	free_page((unsigned long) instance->rcv_buf);
@@ -744,6 +1114,7 @@ static void cxacru_unbind(struct usbatm_
 		struct usb_interface *intf)
 {
 	struct cxacru_data *instance = usbatm_instance->driver_data;
+	int is_polling = 1;
 
 	dbg("cxacru_unbind entered");
 
@@ -752,8 +1123,20 @@ static void cxacru_unbind(struct usbatm_
 		return;
 	}
 
-	while (!cancel_delayed_work(&instance->poll_work))
-	       flush_scheduled_work();
+	mutex_lock(&instance->poll_state_serialize);
+	BUG_ON(instance->poll_state == CXPOLL_SHUTDOWN);
+
+	/* ensure that status polling continues unless
+	 * it has already stopped */
+	if (instance->poll_state == CXPOLL_STOPPED)
+		is_polling = 0;
+
+	/* stop polling from being stopped or started */
+	instance->poll_state = CXPOLL_SHUTDOWN;
+	mutex_unlock(&instance->poll_state_serialize);
+
+	if (is_polling)
+		cancel_rearming_delayed_work(&instance->poll_work);
 
 	usb_kill_urb(instance->snd_urb);
 	usb_kill_urb(instance->rcv_urb);
@@ -762,6 +1145,12 @@ static void cxacru_unbind(struct usbatm_
 
 	free_page((unsigned long) instance->snd_buf);
 	free_page((unsigned long) instance->rcv_buf);
+
+	#define CXACRU_DEVICE_REMOVE_FILE(_name) \
+		device_remove_file(&intf->dev, &dev_attr_##_name);
+	CXACRU_ALL_FILES(REMOVE);
+	#undef CXACRU_DEVICE_REVOVE_FILE
+
 	kfree(instance);
 
 	usbatm_instance->driver_data = NULL;
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index ec63b0e..b082d95 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -77,7 +77,6 @@ #include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
@@ -274,6 +273,9 @@ static void usbatm_complete(struct urb *
 			(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
 			 urb->status != -EILSEQ ))
 	{
+		if (urb->status == -ESHUTDOWN)
+			return;
+
 		if (printk_ratelimit())
 			atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
 				__func__, urb, urb->status);
@@ -343,7 +345,7 @@ static void usbatm_extract_one_cell(stru
 		UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
 	}
 
-	memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+	memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
 	__skb_put(sarb, ATM_CELL_PAYLOAD);
 
 	if (pti & 1) {
@@ -370,7 +372,7 @@ static void usbatm_extract_one_cell(stru
 			goto out;
 		}
 
-		if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+		if (crc32_be(~0, skb_tail_pointer(sarb) - pdu_length, pdu_length) != 0xc704dd7b) {
 			atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
 				  __func__, vcc);
 			atomic_inc(&vcc->stats->rx_err);
@@ -396,7 +398,9 @@ static void usbatm_extract_one_cell(stru
 			goto out;	/* atm_charge increments rx_drop */
 		}
 
-		memcpy(skb->data, sarb->tail - pdu_length, length);
+		skb_copy_to_linear_data(skb,
+					skb_tail_pointer(sarb) - pdu_length,
+					length);
 		__skb_put(skb, length);
 
 		vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
@@ -484,7 +488,7 @@ static unsigned int usbatm_write_cells(s
 		ptr[4] = 0xec;
 		ptr += ATM_CELL_HEADER;
 
-		memcpy(ptr, skb->data, data_len);
+		skb_copy_from_linear_data(skb, ptr, data_len);
 		ptr += data_len;
 		__skb_pull(skb, data_len);
 
@@ -966,6 +970,14 @@ static int usbatm_atm_init(struct usbatm
 	/* temp init ATM device, set to 128kbit */
 	atm_dev->link_rate = 128 * 1000 / 424;
 
+	ret = sysfs_create_link(&atm_dev->class_dev.kobj,
+				&instance->usb_intf->dev.kobj, "device");
+	if (ret) {
+		atm_err(instance, "%s: sysfs_create_link failed: %d\n",
+					__func__, ret);
+		goto fail_sysfs;
+	}
+
 	if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
 		atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
 		goto fail;
@@ -984,6 +996,8 @@ static int usbatm_atm_init(struct usbatm
 	return 0;
 
  fail:
+	sysfs_remove_link(&atm_dev->class_dev.kobj, "device");
+ fail_sysfs:
 	instance->atm_dev = NULL;
 	atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */
 	return ret;
@@ -1316,8 +1330,10 @@ void usbatm_usb_disconnect(struct usb_in
 	kfree(instance->cell_buf);
 
 	/* ATM finalize */
-	if (instance->atm_dev)
+	if (instance->atm_dev) {
+		sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
 		atm_dev_deregister(instance->atm_dev);
+	}
 
 	usbatm_put_instance(instance);	/* taken in usbatm_usb_probe */
 }
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 31ae661..0081c1d 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -59,7 +59,6 @@ #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
@@ -212,7 +211,41 @@ static int acm_write_start(struct acm *a
 	}
 	return rc;
 }
+/*
+ * attributes exported through sysfs
+ */
+static ssize_t show_caps
+(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct acm *acm = usb_get_intfdata(intf);
+
+	return sprintf(buf, "%d", acm->ctrl_caps);
+}
+static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL);
+
+static ssize_t show_country_codes
+(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct acm *acm = usb_get_intfdata(intf);
+
+	memcpy(buf, acm->country_codes, acm->country_code_size);
+	return acm->country_code_size;
+}
+
+static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL);
+
+static ssize_t show_country_rel_date
+(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_interface *intf = to_usb_interface(dev);
+	struct acm *acm = usb_get_intfdata(intf);
+
+	return sprintf(buf, "%d", acm->country_rel_date);
+}
 
+static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
 /*
  * Interrupt handlers for various ACM device responses
  */
@@ -514,6 +547,7 @@ static void acm_tty_unregister(struct ac
 	usb_free_urb(acm->writeurb);
 	for (i = 0; i < nr; i++)
 		usb_free_urb(acm->ru[i].urb);
+	kfree(acm->country_codes);
 	kfree(acm);
 }
 
@@ -761,6 +795,7 @@ static int acm_probe (struct usb_interfa
 		      const struct usb_device_id *id)
 {
 	struct usb_cdc_union_desc *union_header = NULL;
+	struct usb_cdc_country_functional_desc *cfd = NULL;
 	char *buffer = intf->altsetting->extra;
 	int buflen = intf->altsetting->extralen;
 	struct usb_interface *control_interface;
@@ -824,8 +859,9 @@ static int acm_probe (struct usb_interfa
 				union_header = (struct usb_cdc_union_desc *)
 							buffer;
 				break;
-			case USB_CDC_COUNTRY_TYPE: /* maybe somehow export */
-				break; /* for now we ignore it */
+			case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+				cfd = (struct usb_cdc_country_functional_desc *)buffer;
+				break;
 			case USB_CDC_HEADER_TYPE: /* maybe check version */ 
 				break; /* for now we ignore it */ 
 			case USB_CDC_ACM_TYPE:
@@ -983,6 +1019,34 @@ skip_normal_probe:
 		goto alloc_fail7;
 	}
 
+	usb_set_intfdata (intf, acm);
+
+	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
+	if (i < 0)
+		goto alloc_fail8;
+
+	if (cfd) { /* export the country data */
+		acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
+		if (!acm->country_codes)
+			goto skip_countries;
+		acm->country_code_size = cfd->bLength - 4;
+		memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
+		acm->country_rel_date = cfd->iCountryCodeRelDate;
+
+		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
+		if (i < 0) {
+			kfree(acm->country_codes);
+			goto skip_countries;
+		}
+
+		i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
+		if (i < 0) {
+			kfree(acm->country_codes);
+			goto skip_countries;
+		}
+	}
+
+skip_countries:
 	usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
 			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -1006,9 +1070,10 @@ skip_normal_probe:
 	tty_register_device(acm_tty_driver, minor, &control_interface->dev);
 
 	acm_table[minor] = acm;
-	usb_set_intfdata (intf, acm);
-	return 0;
 
+	return 0;
+alloc_fail8:
+	usb_free_urb(acm->writeurb);
 alloc_fail7:
 	for (i = 0; i < num_rx_buf; i++)
 		usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
@@ -1027,7 +1092,7 @@ alloc_fail:
 
 static void acm_disconnect(struct usb_interface *intf)
 {
-	struct acm *acm = usb_get_intfdata (intf);
+	struct acm *acm = usb_get_intfdata(intf);
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	int i;
 
@@ -1041,6 +1106,11 @@ static void acm_disconnect(struct usb_in
 		mutex_unlock(&open_mutex);
 		return;
 	}
+	if (acm->country_codes){
+		device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
+		device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
+	}
+	device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
 	acm->dev = NULL;
 	usb_set_intfdata(acm->control, NULL);
 	usb_set_intfdata(acm->data, NULL);
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 1bcaea3..09f7765 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -91,6 +91,9 @@ struct acm {
 	struct urb *ctrlurb, *writeurb;			/* urbs */
 	u8 *ctrl_buffer;				/* buffers of urbs */
 	dma_addr_t ctrl_dma;				/* dma handles of buffers */
+	u8 *country_codes;				/* country codes from device */
+	unsigned int country_code_size;			/* size of this buffer */
+	unsigned int country_rel_date;			/* release date of version */
 	struct acm_wb wb[ACM_NW];
 	struct acm_ru ru[ACM_NR];
 	struct acm_rb rb[ACM_NR];
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6584cf0..15e740e 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -49,7 +49,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/init.h>
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 2fc0f88..f493fb1 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -31,7 +31,30 @@ config USB_DEVICEFS
 	  For the format of the various /proc/bus/usb/ files, please read
 	  <file:Documentation/usb/proc_usb_info.txt>.
 
-	  Most users want to say Y here.
+	  Usbfs files can't handle Access Control Lists (ACL), which are the
+	  default way to grant access to USB devices for untrusted users of a
+	  desktop system. The usbfs functionality is replaced by real
+	  device-nodes managed by udev. These nodes live in /dev/bus/usb and
+	  are used by libusb.
+
+config USB_DEVICE_CLASS
+	bool "USB device class-devices (DEPRECATED)"
+	depends on USB
+	default n
+	---help---
+	  Userspace access to USB devices is granted by device-nodes exported
+	  directly from the usbdev in sysfs. Old versions of the driver
+	  core and udev needed additional class devices to export device nodes.
+
+	  These additional devices are difficult to handle in userspace, if
+	  information about USB interfaces must be available. One device contains
+	  the device node, the other device contains the interface data. Both
+	  devices are at the same level in sysfs (siblings) and one can't access
+	  the other. The device node created directly by the usbdev is the parent
+	  device of the interface and therefore easily accessible from the interface
+	  event.
+
+	  This option provides backward compatibility if needed.
 
 config USB_DYNAMIC_MINORS
 	bool "Dynamic USB minor allocation (EXPERIMENTAL)"
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index aefc798..6753ca0 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -246,7 +246,6 @@ static char *usb_dump_interface_descript
 
 	if (start > end)
 		return start;
-	down_read(&usb_bus_type.subsys.rwsem);
 	if (iface) {
 		driver_name = (iface->dev.driver
 				? iface->dev.driver->name
@@ -263,7 +262,6 @@ static char *usb_dump_interface_descript
 			 desc->bInterfaceSubClass,
 			 desc->bInterfaceProtocol,
 			 driver_name);
-	up_read(&usb_bus_type.subsys.rwsem);
 	return start;
 }
 
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 36e7a84..927a181 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -57,7 +57,6 @@ #include "usb.h"
 
 #define USB_MAXBUS			64
 #define USB_DEVICE_MAX			USB_MAXBUS * 128
-static struct class *usb_device_class;
 
 /* Mutual exclusion for removal, open, and release */
 DEFINE_MUTEX(usbfs_mutex);
@@ -421,14 +420,11 @@ static int claimintf(struct dev_state *p
 	if (test_bit(ifnum, &ps->ifclaimed))
 		return 0;
 
-	/* lock against other changes to driver bindings */
-	down_write(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(dev, ifnum);
 	if (!intf)
 		err = -ENOENT;
 	else
 		err = usb_driver_claim_interface(&usbfs_driver, intf, ps);
-	up_write(&usb_bus_type.subsys.rwsem);
 	if (err == 0)
 		set_bit(ifnum, &ps->ifclaimed);
 	return err;
@@ -444,8 +440,6 @@ static int releaseintf(struct dev_state 
 	if (ifnum >= 8*sizeof(ps->ifclaimed))
 		return err;
 	dev = ps->dev;
-	/* lock against other changes to driver bindings */
-	down_write(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(dev, ifnum);
 	if (!intf)
 		err = -ENOENT;
@@ -453,7 +447,6 @@ static int releaseintf(struct dev_state 
 		usb_driver_release_interface(&usbfs_driver, intf);
 		err = 0;
 	}
-	up_write(&usb_bus_type.subsys.rwsem);
 	return err;
 }
 
@@ -520,22 +513,25 @@ static int check_ctrlrecip(struct dev_st
 	return ret;
 }
 
-static struct usb_device *usbdev_lookup_minor(int minor)
+static int __match_minor(struct device *dev, void *data)
 {
-	struct device *device;
-	struct usb_device *udev = NULL;
+	int minor = *((int *)data);
 
-	down(&usb_device_class->sem);
-	list_for_each_entry(device, &usb_device_class->devices, node) {
-		if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-			udev = device->platform_data;
-			break;
-		}
-	}
-	up(&usb_device_class->sem);
+	if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
+		return 1;
+	return 0;
+}
 
-	return udev;
-};
+static struct usb_device *usbdev_lookup_by_minor(int minor)
+{
+	struct device *dev;
+
+	dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor);
+	if (!dev)
+		return NULL;
+	put_device(dev);
+	return container_of(dev, struct usb_device, dev);
+}
 
 /*
  * file operations
@@ -554,11 +550,14 @@ static int usbdev_open(struct inode *ino
 		goto out;
 
 	ret = -ENOENT;
-	/* check if we are called from a real node or usbfs */
+	/* usbdev device-node */
 	if (imajor(inode) == USB_DEVICE_MAJOR)
-		dev = usbdev_lookup_minor(iminor(inode));
+		dev = usbdev_lookup_by_minor(iminor(inode));
+#ifdef CONFIG_USB_DEVICEFS
+	/* procfs file */
 	if (!dev)
 		dev = inode->i_private;
+#endif
 	if (!dev)
 		goto out;
 	ret = usb_autoresume_device(dev);
@@ -581,7 +580,7 @@ static int usbdev_open(struct inode *ino
 	ps->disccontext = NULL;
 	ps->ifclaimed = 0;
 	security_task_getsecid(current, &ps->secid);
-	wmb();
+	smp_wmb();
 	list_add_tail(&ps->list, &dev->filelist);
 	file->private_data = ps;
  out:
@@ -813,7 +812,6 @@ static int proc_getdriver(struct dev_sta
 
 	if (copy_from_user(&gd, arg, sizeof(gd)))
 		return -EFAULT;
-	down_read(&usb_bus_type.subsys.rwsem);
 	intf = usb_ifnum_to_if(ps->dev, gd.interface);
 	if (!intf || !intf->dev.driver)
 		ret = -ENODATA;
@@ -822,7 +820,6 @@ static int proc_getdriver(struct dev_sta
 				sizeof(gd.driver));
 		ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0);
 	}
-	up_read(&usb_bus_type.subsys.rwsem);
 	return ret;
 }
 
@@ -1351,15 +1348,12 @@ static int proc_ioctl(struct dev_state *
 
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
-
-		down_write(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver) {
 			driver = to_usb_driver(intf->dev.driver);
 			dev_dbg (&intf->dev, "disconnect by usbfs\n");
 			usb_driver_release_interface(driver, intf);
 		} else
 			retval = -ENODATA;
-		up_write(&usb_bus_type.subsys.rwsem);
 		break;
 
 	/* let kernel drivers try to (re)bind to the interface */
@@ -1371,7 +1365,6 @@ static int proc_ioctl(struct dev_state *
 
 	/* talk directly to the interface's driver */
 	default:
-		down_read(&usb_bus_type.subsys.rwsem);
 		if (intf->dev.driver)
 			driver = to_usb_driver(intf->dev.driver);
 		if (driver == NULL || driver->ioctl == NULL) {
@@ -1381,7 +1374,6 @@ static int proc_ioctl(struct dev_state *
 			if (retval == -ENOIOCTLCMD)
 				retval = -ENOTTY;
 		}
-		up_read(&usb_bus_type.subsys.rwsem);
 	}
 
 	/* cleanup and return */
@@ -1583,7 +1575,7 @@ static unsigned int usbdev_poll(struct f
 	return mask;
 }
 
-const struct file_operations usbfs_device_file_operations = {
+const struct file_operations usbdev_file_operations = {
 	.llseek =	usbdev_lseek,
 	.read =		usbdev_read,
 	.poll =		usbdev_poll,
@@ -1592,50 +1584,53 @@ const struct file_operations usbfs_devic
 	.release =	usbdev_release,
 };
 
-static int usbdev_add(struct usb_device *dev)
+#ifdef CONFIG_USB_DEVICE_CLASS
+static struct class *usb_classdev_class;
+
+static int usb_classdev_add(struct usb_device *dev)
 {
 	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-	dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+	dev->usb_classdev = device_create(usb_classdev_class, &dev->dev,
 				MKDEV(USB_DEVICE_MAJOR, minor),
 				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
-	if (IS_ERR(dev->usbfs_dev))
-		return PTR_ERR(dev->usbfs_dev);
+	if (IS_ERR(dev->usb_classdev))
+		return PTR_ERR(dev->usb_classdev);
 
-	dev->usbfs_dev->platform_data = dev;
 	return 0;
 }
 
-static void usbdev_remove(struct usb_device *dev)
+static void usb_classdev_remove(struct usb_device *dev)
 {
-	device_unregister(dev->usbfs_dev);
+	device_unregister(dev->usb_classdev);
 }
 
-static int usbdev_notify(struct notifier_block *self, unsigned long action,
-			 void *dev)
+static int usb_classdev_notify(struct notifier_block *self,
+			       unsigned long action, void *dev)
 {
 	switch (action) {
 	case USB_DEVICE_ADD:
-		if (usbdev_add(dev))
+		if (usb_classdev_add(dev))
 			return NOTIFY_BAD;
 		break;
 	case USB_DEVICE_REMOVE:
-		usbdev_remove(dev);
+		usb_classdev_remove(dev);
 		break;
 	}
 	return NOTIFY_OK;
 }
 
 static struct notifier_block usbdev_nb = {
-	.notifier_call = 	usbdev_notify,
+	.notifier_call = 	usb_classdev_notify,
 };
+#endif
 
 static struct cdev usb_device_cdev = {
 	.kobj   = {.name = "usb_device", },
 	.owner  = THIS_MODULE,
 };
 
-int __init usbdev_init(void)
+int __init usb_devio_init(void)
 {
 	int retval;
 
@@ -1645,38 +1640,38 @@ int __init usbdev_init(void)
 		err("unable to register minors for usb_device");
 		goto out;
 	}
-	cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
+	cdev_init(&usb_device_cdev, &usbdev_file_operations);
 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
 	if (retval) {
 		err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
 		goto error_cdev;
 	}
-	usb_device_class = class_create(THIS_MODULE, "usb_device");
-	if (IS_ERR(usb_device_class)) {
+#ifdef CONFIG_USB_DEVICE_CLASS
+	usb_classdev_class = class_create(THIS_MODULE, "usb_device");
+	if (IS_ERR(usb_classdev_class)) {
 		err("unable to register usb_device class");
-		retval = PTR_ERR(usb_device_class);
-		goto error_class;
+		retval = PTR_ERR(usb_classdev_class);
+		cdev_del(&usb_device_cdev);
+		usb_classdev_class = NULL;
+		goto out;
 	}
 
 	usb_register_notify(&usbdev_nb);
-
+#endif
 out:
 	return retval;
 
-error_class:
-	usb_device_class = NULL;
-	cdev_del(&usb_device_cdev);
-
 error_cdev:
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
 	goto out;
 }
 
-void usbdev_cleanup(void)
+void usb_devio_cleanup(void)
 {
+#ifdef CONFIG_USB_DEVICE_CLASS
 	usb_unregister_notify(&usbdev_nb);
-	class_destroy(usb_device_class);
+	class_destroy(usb_classdev_class);
+#endif
 	cdev_del(&usb_device_cdev);
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
 }
-
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9e3e943..b9f7f90 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -287,9 +287,9 @@ static int usb_unbind_interface(struct d
  * 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.
+ * Callers must own the device lock, so driver probe() entries don't need
+ * extra locking, but other call contexts may need to explicitly claim that
+ * lock.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
 				struct usb_interface *iface, void* priv)
@@ -330,9 +330,9 @@ EXPORT_SYMBOL(usb_driver_claim_interface
  * 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.
+ * Callers must own the device lock, so driver disconnect() entries don't
+ * need extra locking, but other call contexts may need to explicitly claim
+ * that lock.
  */
 void usb_driver_release_interface(struct usb_driver *driver,
 					struct usb_interface *iface)
@@ -574,23 +574,10 @@ static int usb_device_match(struct devic
 }
 
 #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_device *usb_dev;
-	struct usb_host_interface *alt;
 	int i = 0;
 	int length = 0;
 
@@ -600,13 +587,11 @@ static int usb_uevent(struct device *dev
 	/* driver is often null here; dev_dbg() would oops */
 	pr_debug ("usb %s: uevent\n", dev->bus_id);
 
-	if (is_usb_device(dev)) {
+	if (is_usb_device(dev))
 		usb_dev = to_usb_device(dev);
-		alt = NULL;
-	} else {
-		intf = to_usb_interface(dev);
+	else {
+		struct usb_interface *intf = to_usb_interface(dev);
 		usb_dev = interface_to_usbdev(intf);
-		alt = intf->cur_altsetting;
 	}
 
 	if (usb_dev->devnum < 0) {
@@ -621,9 +606,7 @@ static int usb_uevent(struct 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
+	 * act as usermode drivers.
 	 */
 	if (add_uevent_var(envp, num_envp, &i,
 			   buffer, buffer_size, &length,
@@ -650,44 +633,29 @@ #endif
 			   usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 
-	if (!is_usb_device(dev)) {
-
-		if (add_uevent_var(envp, num_envp, &i,
+	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;
+			   "BUSNUM=%03d",
+			   usb_dev->bus->busnum))
+		return -ENOMEM;
 
-		if (add_uevent_var(envp, num_envp, &i,
+	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;
-	}
+			   "DEVNUM=%03d",
+			   usb_dev->devnum))
+		return -ENOMEM;
 
 	envp[i] = NULL;
-
 	return 0;
 }
 
 #else
 
 static int usb_uevent(struct device *dev, char **envp,
-			int num_envp, char *buffer, int buffer_size)
+		      int num_envp, char *buffer, int buffer_size)
 {
 	return -ENODEV;
 }
-
 #endif	/* CONFIG_HOTPLUG */
 
 /**
@@ -872,8 +840,10 @@ static int usb_resume_device(struct usb_
 
 done:
 	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
-	if (status == 0)
+	if (status == 0) {
+		udev->autoresume_disabled = 0;
 		udev->dev.power.power_state.event = PM_EVENT_ON;
+	}
 	return status;
 }
 
@@ -962,6 +932,7 @@ static int autosuspend_check(struct usb_
 {
 	int			i;
 	struct usb_interface	*intf;
+	unsigned long		suspend_time;
 
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	 * is disabled.  Also fail if any interfaces require remote wakeup
@@ -970,9 +941,10 @@ static int autosuspend_check(struct usb_
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 	if (udev->pm_usage_cnt > 0)
 		return -EBUSY;
-	if (!udev->autosuspend_delay)
+	if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
 		return -EPERM;
 
+	suspend_time = udev->last_busy + udev->autosuspend_delay;
 	if (udev->actconfig) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			intf = udev->actconfig->interface[i];
@@ -988,6 +960,24 @@ static int autosuspend_check(struct usb_
 			}
 		}
 	}
+
+	/* If everything is okay but the device hasn't been idle for long
+	 * enough, queue a delayed autosuspend request.
+	 */
+	if (time_after(suspend_time, jiffies)) {
+		if (!timer_pending(&udev->autosuspend.timer)) {
+
+			/* The value of jiffies may change between the
+			 * time_after() comparison above and the subtraction
+			 * below.  That's okay; the system behaves sanely
+			 * when a timer is registered for the present moment
+			 * or for the past.
+			 */
+			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+					suspend_time - jiffies);
+			}
+		return -EAGAIN;
+	}
 	return 0;
 }
 
@@ -1033,26 +1023,25 @@ #endif	/* CONFIG_USB_SUSPEND */
  *
  * This routine can run only in process context.
  */
-int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
+static 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;
+	if (udev->state == USB_STATE_NOTATTACHED ||
+			udev->state == USB_STATE_SUSPENDED)
+		goto done;
 
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
 	if (udev->auto_pm) {
 		status = autosuspend_check(udev);
 		if (status < 0)
-			return status;
+			goto done;
 	}
+	cancel_delayed_work(&udev->autosuspend);
 
 	/* Suspend all the interfaces and then udev itself */
 	if (udev->actconfig) {
@@ -1077,6 +1066,7 @@ int usb_suspend_both(struct usb_device *
 	} else if (parent)
 		usb_autosuspend_device(parent);
 
+ done:
 	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
 	return status;
 }
@@ -1109,7 +1099,7 @@ int usb_suspend_both(struct usb_device *
  *
  * This routine can run only in process context.
  */
-int usb_resume_both(struct usb_device *udev)
+static int usb_resume_both(struct usb_device *udev)
 {
 	int			status = 0;
 	int			i;
@@ -1117,11 +1107,17 @@ int usb_resume_both(struct usb_device *u
 	struct usb_device	*parent = udev->parent;
 
 	cancel_delayed_work(&udev->autosuspend);
-	if (udev->state == USB_STATE_NOTATTACHED)
-		return -ENODEV;
+	if (udev->state == USB_STATE_NOTATTACHED) {
+		status = -ENODEV;
+		goto done;
+	}
 
 	/* Propagate the resume up the tree, if necessary */
 	if (udev->state == USB_STATE_SUSPENDED) {
+		if (udev->auto_pm && udev->autoresume_disabled) {
+			status = -EPERM;
+			goto done;
+		}
 		if (parent) {
 			status = usb_autoresume_device(parent);
 			if (status == 0) {
@@ -1167,6 +1163,7 @@ int usb_resume_both(struct usb_device *u
 		}
 	}
 
+ done:
 	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
 	return status;
 }
@@ -1181,20 +1178,34 @@ static int usb_autopm_do_device(struct u
 	int	status = 0;
 
 	usb_pm_lock(udev);
+	udev->auto_pm = 1;
 	udev->pm_usage_cnt += inc_usage_cnt;
 	WARN_ON(udev->pm_usage_cnt < 0);
 	if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
-		udev->auto_pm = 1;
-		status = usb_resume_both(udev);
+		if (udev->state == USB_STATE_SUSPENDED)
+			status = usb_resume_both(udev);
 		if (status != 0)
 			udev->pm_usage_cnt -= inc_usage_cnt;
-	} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
-		queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				udev->autosuspend_delay);
+		else if (inc_usage_cnt)
+			udev->last_busy = jiffies;
+	} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
+		if (inc_usage_cnt)
+			udev->last_busy = jiffies;
+		status = usb_suspend_both(udev, PMSG_SUSPEND);
+	}
 	usb_pm_unlock(udev);
 	return status;
 }
 
+/* usb_autosuspend_work - callback routine to autosuspend a USB device */
+void usb_autosuspend_work(struct work_struct *work)
+{
+	struct usb_device *udev =
+		container_of(work, struct usb_device, autosuspend.work);
+
+	usb_autopm_do_device(udev, 0);
+}
+
 /**
  * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
  * @udev: the usb_device to autosuspend
@@ -1286,15 +1297,20 @@ static int usb_autopm_do_interface(struc
 	if (intf->condition == USB_INTERFACE_UNBOUND)
 		status = -ENODEV;
 	else {
+		udev->auto_pm = 1;
 		intf->pm_usage_cnt += inc_usage_cnt;
 		if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
-			udev->auto_pm = 1;
-			status = usb_resume_both(udev);
+			if (udev->state == USB_STATE_SUSPENDED)
+				status = usb_resume_both(udev);
 			if (status != 0)
 				intf->pm_usage_cnt -= inc_usage_cnt;
-		} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
-			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-					udev->autosuspend_delay);
+			else if (inc_usage_cnt)
+				udev->last_busy = jiffies;
+		} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
+			if (inc_usage_cnt)
+				udev->last_busy = jiffies;
+			status = usb_suspend_both(udev, PMSG_SUSPEND);
+		}
 	}
 	usb_pm_unlock(udev);
 	return status;
@@ -1353,11 +1369,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interfa
  * 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).
+ *
+ * The routine increments @intf's usage counter.  (However if the
+ * autoresume fails then the counter is re-decremented.)  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
@@ -1405,50 +1424,96 @@ int usb_autopm_set_interface(struct usb_
 }
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
 
+#else
+
+void usb_autosuspend_work(struct work_struct *work)
+{}
+
 #endif /* CONFIG_USB_SUSPEND */
 
-static int usb_suspend(struct device *dev, pm_message_t message)
+/**
+ * usb_external_suspend_device - external suspend of a USB device and its interfaces
+ * @udev: the usb_device to suspend
+ * @msg: Power Management message describing this state transition
+ *
+ * This routine handles external suspend requests: ones not generated
+ * internally by a USB driver (autosuspend) but rather coming from the user
+ * (via sysfs) or the PM core (system sleep).  The suspend will be carried
+ * out regardless of @udev's usage counter or those of its interfaces,
+ * and regardless of whether or not remote wakeup is enabled.  Of course,
+ * interface drivers still have the option of failing the suspend (if
+ * there are unsuspended children, for example).
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
 	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;
+	usb_pm_lock(udev);
+	udev->auto_pm = 0;
+	status = usb_suspend_both(udev, msg);
+	usb_pm_unlock(udev);
 	return status;
 }
 
-static int usb_resume(struct device *dev)
+/**
+ * usb_external_resume_device - external resume of a USB device and its interfaces
+ * @udev: the usb_device to resume
+ *
+ * This routine handles external resume requests: ones not generated
+ * internally by a USB driver (autoresume) but rather coming from the user
+ * (via sysfs), the PM core (system resume), or the device itself (remote
+ * wakeup).  @udev's usage counter is unaffected.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_external_resume_device(struct usb_device *udev)
 {
 	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);
+	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;
+	/* Now that the device is awake, we can start trying to autosuspend
+	 * it again. */
+	if (status == 0)
+		usb_try_autosuspend_device(udev);
 	return status;
 }
 
+static int usb_suspend(struct device *dev, pm_message_t message)
+{
+	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
+		return 0;
+	return usb_external_suspend_device(to_usb_device(dev), message);
+}
+
+static int usb_resume(struct device *dev)
+{
+	struct usb_device	*udev;
+
+	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
+		return 0;
+	udev = to_usb_device(dev);
+	if (udev->autoresume_disabled)
+		return -EPERM;
+	return usb_external_resume_device(udev);
+}
+
+#else
+
+#define usb_suspend	NULL
+#define usb_resume	NULL
+
 #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/hcd.c b/drivers/usb/core/hcd.c
index b26c19e..40cf882 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -37,6 +37,7 @@ #include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include <linux/platform_device.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb.h>
 
@@ -544,6 +545,8 @@ void usb_hcd_poll_rh_status(struct usb_h
 	unsigned long	flags;
 	char		buffer[4];	/* Any root hubs with > 31 ports? */
 
+	if (unlikely(!hcd->rh_registered))
+		return;
 	if (!hcd->uses_new_polling && !hcd->status_urb)
 		return;
 
@@ -1296,14 +1299,26 @@ int hcd_bus_resume (struct usb_bus *bus)
 	return status;
 }
 
+/* Workqueue routine for root-hub remote wakeup */
+static void hcd_resume_work(struct work_struct *work)
+{
+	struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
+	struct usb_device *udev = hcd->self.root_hub;
+
+	usb_lock_device(udev);
+	usb_mark_last_busy(udev);
+	usb_external_resume_device(udev);
+	usb_unlock_device(udev);
+}
+
 /**
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
  *
  * The USB host controller calls this function when its root hub is
  * suspended (with the remote wakeup feature enabled) and a remote
- * wakeup request is received.  It queues a request for khubd to
- * resume the root hub (that is, manage its downstream ports again).
+ * wakeup request is received.  The routine submits a workqueue request
+ * to resume the root hub (that is, manage its downstream ports again).
  */
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
@@ -1311,7 +1326,7 @@ void usb_hcd_resume_root_hub (struct usb
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	if (hcd->rh_registered)
-		usb_resume_root_hub (hcd->self.root_hub);
+		queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
@@ -1500,6 +1515,9 @@ struct usb_hcd *usb_create_hcd (const st
 	init_timer(&hcd->rh_timer);
 	hcd->rh_timer.function = rh_timer_func;
 	hcd->rh_timer.data = (unsigned long) hcd;
+#ifdef CONFIG_PM
+	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
+#endif
 
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1666,16 +1684,20 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	hcd->rh_registered = 0;
 	spin_unlock_irq (&hcd_root_hub_lock);
 
+#ifdef CONFIG_PM
+	flush_workqueue(ksuspend_usb_wq);
+#endif
+
 	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	mutex_unlock(&usb_bus_list_lock);
 
-	hcd->poll_rh = 0;
-	del_timer_sync(&hcd->rh_timer);
-
 	hcd->driver->stop(hcd);
 	hcd->state = HC_STATE_HALT;
 
+	hcd->poll_rh = 0;
+	del_timer_sync(&hcd->rh_timer);
+
 	if (hcd->irq >= 0)
 		free_irq(hcd->irq, hcd);
 	usb_deregister_bus(&hcd->self);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 2a269ca..ef50fa4 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -68,6 +68,9 @@ struct usb_hcd {
 
 	struct timer_list	rh_timer;	/* drives root-hub polling */
 	struct urb		*status_urb;	/* the current status urb */
+#ifdef CONFIG_PM
+	struct work_struct	wakeup_work;	/* for remote wakeup */
+#endif
 
 	/*
 	 * hardware info/state
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b89a98e..f6b74a6 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -16,7 +16,6 @@ #include <linux/completion.h>
 #include <linux/sched.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
@@ -119,8 +118,7 @@ MODULE_PARM_DESC(use_both_schemes,
 		"first one fails");
 
 
-#ifdef	DEBUG
-static inline char *portspeed (int portstatus)
+static inline char *portspeed(int portstatus)
 {
 	if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
     		return "480 Mb/s";
@@ -129,7 +127,6 @@ static inline char *portspeed (int ports
 	else
 		return "12 Mb/s";
 }
-#endif
 
 /* Note that hdev or one of its children must be locked! */
 static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev)
@@ -1369,11 +1366,15 @@ #ifdef	CONFIG_USB_OTG
 	}
 #endif
 
+	/* export the usbdev device-node for libusb */
+	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
+			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+
 	/* Register the device.  The device driver is responsible
-	 * for adding the device files to usbfs and sysfs and for
-	 * configuring the device.
+	 * for adding the device files to sysfs and for configuring
+	 * the device.
 	 */
-	err = device_add (&udev->dev);
+	err = device_add(&udev->dev);
 	if (err) {
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
 		goto fail;
@@ -1857,12 +1858,8 @@ static int remote_wakeup(struct usb_devi
 	usb_lock_device(udev);
 	if (udev->state == USB_STATE_SUSPENDED) {
 		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
-		status = usb_autoresume_device(udev);
-
-		/* Give the interface drivers a chance to do something,
-		 * then autosuspend the device again. */
-		if (status == 0)
-			usb_autosuspend_device(udev);
+		usb_mark_last_busy(udev);
+		status = usb_external_resume_device(udev);
 	}
 	usb_unlock_device(udev);
 	return status;
@@ -1986,13 +1983,6 @@ #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);
-
-	kick_khubd(hub);
-}
-
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 11dad22..cd4f111 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -36,7 +36,6 @@ #include <linux/proc_fs.h>
 #include <linux/usb.h>
 #include <linux/namei.h>
 #include <linux/usbdevice_fs.h>
-#include <linux/smp_lock.h>
 #include <linux/parser.h>
 #include <linux/notifier.h>
 #include <asm/byteorder.h>
@@ -662,7 +661,7 @@ static void usbfs_add_device(struct usb_
 	sprintf (name, "%03d", dev->devnum);
 	dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
 					    dev->bus->usbfs_dentry, dev,
-					    &usbfs_device_file_operations,
+					    &usbdev_file_operations,
 					    devuid, devgid);
 	if (dev->usbfs_dentry == NULL) {
 		err ("error creating usbfs device entry");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 217a3d6..b743478 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -412,10 +412,24 @@ int usb_sg_init (
 		io->urbs [i]->status = -EINPROGRESS;
 		io->urbs [i]->actual_length = 0;
 
+		/*
+		 * Some systems need to revert to PIO when DMA is temporarily
+		 * unavailable.  For their sakes, both transfer_buffer and
+		 * transfer_dma are set when possible.  However this can only
+		 * work on systems without HIGHMEM, since DMA buffers located
+		 * in high memory are not directly addressable by the CPU for
+		 * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
+		 * to prevent stale pointers and to help spot bugs.
+		 */
 		if (dma) {
-			/* hc may use _only_ transfer_dma */
 			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
 			len = sg_dma_len (sg + i);
+#ifdef CONFIG_HIGHMEM
+			io->urbs[i]->transfer_buffer = NULL;
+#else
+			io->urbs[i]->transfer_buffer =
+				page_address(sg[i].page) + sg[i].offset;
+#endif
 		} else {
 			/* hc may use _only_ transfer_buffer */
 			io->urbs [i]->transfer_buffer =
@@ -1305,7 +1319,7 @@ int usb_reset_configuration(struct usb_d
 	return 0;
 }
 
-static void release_interface(struct device *dev)
+void usb_release_interface(struct device *dev)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_interface_cache *intfc =
@@ -1315,6 +1329,67 @@ static void release_interface(struct dev
 	kfree(intf);
 }
 
+#ifdef	CONFIG_HOTPLUG
+static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
+		 char *buffer, int buffer_size)
+{
+	struct usb_device *usb_dev;
+	struct usb_interface *intf;
+	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);
+
+	intf = to_usb_interface(dev);
+	usb_dev = interface_to_usbdev(intf);
+	alt = intf->cur_altsetting;
+
+	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;
+	return 0;
+}
+
+#else
+
+static int usb_if_uevent(struct device *dev, char **envp,
+			 int num_envp, char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+#endif	/* CONFIG_HOTPLUG */
+
+struct device_type usb_if_device_type = {
+	.name =		"usb_interface",
+	.release =	usb_release_interface,
+	.uevent =	usb_if_uevent,
+};
+
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
@@ -1349,7 +1424,7 @@ static void release_interface(struct dev
  *
  * This call is synchronous. The calling context must be able to sleep,
  * must own the device lock, and must not hold the driver model's USB
- * bus rwsem; usb device driver probe() methods cannot use this routine.
+ * bus mutex; usb device driver probe() methods cannot use this routine.
  *
  * Returns zero on success, or else the status code returned by the
  * underlying call that failed.  On successful completion, each interface
@@ -1478,8 +1553,8 @@ free_interfaces:
 		intf->dev.parent = &dev->dev;
 		intf->dev.driver = NULL;
 		intf->dev.bus = &usb_bus_type;
+		intf->dev.type = &usb_if_device_type;
 		intf->dev.dma_mask = dev->dev.dma_mask;
-		intf->dev.release = release_interface;
 		device_initialize (&intf->dev);
 		mark_quiesced(intf);
 		sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f08ec85..739f520 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -42,7 +42,7 @@ static void usb_autosuspend_quirk(struct
 {
 #ifdef	CONFIG_USB_SUSPEND
 	/* disable autosuspend, but allow the user to re-enable it via sysfs */
-	udev->autosuspend_delay = 0;
+	udev->autosuspend_disabled = 1;
 #endif
 }
 
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 311d5df..e7c9823 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -11,6 +11,7 @@
 
 
 #include <linux/kernel.h>
+#include <linux/string.h>
 #include <linux/usb.h>
 #include "usb.h"
 
@@ -117,6 +118,16 @@ show_speed(struct device *dev, struct de
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 static ssize_t
+show_busnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", udev->bus->busnum);
+}
+static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL);
+
+static ssize_t
 show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
@@ -165,7 +176,7 @@ show_autosuspend(struct device *dev, str
 {
 	struct usb_device *udev = to_usb_device(dev);
 
-	return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ);
+	return sprintf(buf, "%d\n", udev->autosuspend_delay / HZ);
 }
 
 static ssize_t
@@ -173,39 +184,115 @@ set_autosuspend(struct device *dev, stru
 		const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
-	unsigned value, old;
+	int value;
 
-	if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ)
+	if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
+			value <= - INT_MAX/HZ)
 		return -EINVAL;
 	value *= HZ;
 
-	old = udev->autosuspend_delay;
 	udev->autosuspend_delay = value;
-	if (value > 0 && old == 0)
+	if (value >= 0)
 		usb_try_autosuspend_device(udev);
-
+	else {
+		if (usb_autoresume_device(udev) == 0)
+			usb_autosuspend_device(udev);
+	}
 	return count;
 }
 
 static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
 		show_autosuspend, set_autosuspend);
 
+static const char on_string[] = "on";
+static const char auto_string[] = "auto";
+static const char suspend_string[] = "suspend";
+
+static ssize_t
+show_level(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	const char *p = auto_string;
+
+	if (udev->state == USB_STATE_SUSPENDED) {
+		if (udev->autoresume_disabled)
+			p = suspend_string;
+	} else {
+		if (udev->autosuspend_disabled)
+			p = on_string;
+	}
+	return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t
+set_level(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	int len = count;
+	char *cp;
+	int rc = 0;
+
+	cp = memchr(buf, '\n', count);
+	if (cp)
+		len = cp - buf;
+
+	usb_lock_device(udev);
+
+	/* Setting the flags without calling usb_pm_lock is a subject to
+	 * races, but who cares...
+	 */
+	if (len == sizeof on_string - 1 &&
+			strncmp(buf, on_string, len) == 0) {
+		udev->autosuspend_disabled = 1;
+		udev->autoresume_disabled = 0;
+		rc = usb_external_resume_device(udev);
+
+	} else if (len == sizeof auto_string - 1 &&
+			strncmp(buf, auto_string, len) == 0) {
+		udev->autosuspend_disabled = 0;
+		udev->autoresume_disabled = 0;
+		rc = usb_external_resume_device(udev);
+
+	} else if (len == sizeof suspend_string - 1 &&
+			strncmp(buf, suspend_string, len) == 0) {
+		udev->autosuspend_disabled = 0;
+		udev->autoresume_disabled = 1;
+		rc = usb_external_suspend_device(udev, PMSG_SUSPEND);
+
+	} else
+		rc = -EINVAL;
+
+	usb_unlock_device(udev);
+	return (rc < 0 ? rc : count);
+}
+
+static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
+
 static char power_group[] = "power";
 
 static int add_power_attributes(struct device *dev)
 {
 	int rc = 0;
 
-	if (is_usb_device(dev))
+	if (is_usb_device(dev)) {
 		rc = sysfs_add_file_to_group(&dev->kobj,
 				&dev_attr_autosuspend.attr,
 				power_group);
+		if (rc == 0)
+			rc = sysfs_add_file_to_group(&dev->kobj,
+					&dev_attr_level.attr,
+					power_group);
+	}
 	return rc;
 }
 
 static void remove_power_attributes(struct device *dev)
 {
 	sysfs_remove_file_from_group(&dev->kobj,
+			&dev_attr_level.attr,
+			power_group);
+	sysfs_remove_file_from_group(&dev->kobj,
 			&dev_attr_autosuspend.attr,
 			power_group);
 }
@@ -270,6 +357,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_bNumConfigurations.attr,
 	&dev_attr_bMaxPacketSize0.attr,
 	&dev_attr_speed.attr,
+	&dev_attr_busnum.attr,
 	&dev_attr_devnum.attr,
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 54b42ce..18ddc5e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -31,7 +31,6 @@ #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
@@ -49,12 +48,13 @@ const char *usbcore_name = "usbcore";
 
 static int nousb;	/* Disable USB when built into kernel image */
 
-struct workqueue_struct *ksuspend_usb_wq;	/* For autosuspend */
+/* Workqueue for autosuspend and for remote wakeup of root hubs */
+struct workqueue_struct *ksuspend_usb_wq;
 
 #ifdef	CONFIG_USB_SUSPEND
 static int usb_autosuspend_delay = 2;		/* Default delay value,
 						 * in seconds */
-module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644);
+module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
 MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
 
 #else
@@ -196,6 +196,11 @@ #endif
 	kfree(udev);
 }
 
+struct device_type usb_device_type = {
+	.name =		"usb_device",
+	.release =	usb_release_dev,
+};
+
 #ifdef	CONFIG_PM
 
 static int ksuspend_usb_init(void)
@@ -211,27 +216,6 @@ static void ksuspend_usb_cleanup(void)
 	destroy_workqueue(ksuspend_usb_wq);
 }
 
-#ifdef	CONFIG_USB_SUSPEND
-
-/* usb_autosuspend_work - callback routine to autosuspend a USB device */
-static void usb_autosuspend_work(struct work_struct *work)
-{
-	struct usb_device *udev =
-		container_of(work, struct usb_device, autosuspend.work);
-
-	usb_pm_lock(udev);
-	udev->auto_pm = 1;
-	usb_suspend_both(udev, PMSG_SUSPEND);
-	usb_pm_unlock(udev);
-}
-
-#else
-
-static void usb_autosuspend_work(struct work_struct *work)
-{}
-
-#endif	/* CONFIG_USB_SUSPEND */
-
 #else
 
 #define ksuspend_usb_init()	0
@@ -267,13 +251,10 @@ usb_alloc_dev(struct usb_device *parent,
 
 	device_initialize(&dev->dev);
 	dev->dev.bus = &usb_bus_type;
+	dev->dev.type = &usb_device_type;
 	dev->dev.dma_mask = bus->controller->dma_mask;
-	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;
@@ -902,9 +883,9 @@ static int __init usb_init(void)
 	retval = usb_register(&usbfs_driver);
 	if (retval)
 		goto driver_register_failed;
-	retval = usbdev_init();
+	retval = usb_devio_init();
 	if (retval)
-		goto usbdevice_init_failed;
+		goto usb_devio_init_failed;
 	retval = usbfs_init();
 	if (retval)
 		goto fs_init_failed;
@@ -919,8 +900,8 @@ static int __init usb_init(void)
 hub_init_failed:
 	usbfs_cleanup();
 fs_init_failed:
-	usbdev_cleanup();
-usbdevice_init_failed:
+	usb_devio_cleanup();
+usb_devio_init_failed:
 	usb_deregister(&usbfs_driver);
 driver_register_failed:
 	usb_major_cleanup();
@@ -947,7 +928,7 @@ static void __exit usb_exit(void)
 	usb_major_cleanup();
 	usbfs_cleanup();
 	usb_deregister(&usbfs_driver);
-	usbdev_cleanup();
+	usb_devio_cleanup();
 	usb_hub_cleanup();
 	usb_host_cleanup();
 	bus_unregister(&usb_bus_type);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 08b5a04..bf2eb0d 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -21,7 +21,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_resume_root_hub(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
 			    const struct usb_device_id *id);
 
@@ -34,10 +33,12 @@ extern void usb_host_cleanup(void);
 
 #ifdef	CONFIG_PM
 
-extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
-extern int usb_resume_both(struct usb_device *udev);
+extern void usb_autosuspend_work(struct work_struct *work);
 extern int usb_port_suspend(struct usb_device *dev);
 extern int usb_port_resume(struct usb_device *dev);
+extern int usb_external_suspend_device(struct usb_device *udev,
+		pm_message_t msg);
+extern int usb_external_resume_device(struct usb_device *udev);
 
 static inline void usb_pm_lock(struct usb_device *udev)
 {
@@ -51,11 +52,6 @@ static inline void usb_pm_unlock(struct 
 
 #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) {}
@@ -82,15 +78,13 @@ #endif
 
 extern struct workqueue_struct *ksuspend_usb_wq;
 extern struct bus_type usb_bus_type;
+extern struct device_type usb_device_type;
+extern struct device_type usb_if_device_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;
+	return dev->type == &usb_device_type;
 }
 
 /* Do the same for device drivers and interface drivers. */
@@ -126,11 +120,11 @@ extern const char *usbcore_name;
 extern struct mutex usbfs_mutex;
 extern struct usb_driver usbfs_driver;
 extern const struct file_operations usbfs_devices_fops;
-extern const struct file_operations usbfs_device_file_operations;
+extern const struct file_operations usbdev_file_operations;
 extern void usbfs_conn_disc_event(void);
 
-extern int usbdev_init(void);
-extern void usbdev_cleanup(void);
+extern int usb_devio_init(void);
+extern void usb_devio_cleanup(void);
 
 struct dev_state {
 	struct list_head list;      /* state list */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 4097a86..8065f2b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -68,6 +68,27 @@ choice
 	   Many controller drivers are platform-specific; these
 	   often need board-specific hooks.
 
+config USB_GADGET_FSL_USB2
+	boolean "Freescale Highspeed USB DR Peripheral Controller"
+	depends on MPC834x || PPC_MPC831x
+	select USB_GADGET_DUALSPEED
+	help
+	   Some of Freescale PowerPC processors have a High Speed
+	   Dual-Role(DR) USB controller, which supports device mode.
+
+	   The number of programmable endpoints is different through
+	   SOC revisions.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "fsl_usb2_udc" and force
+	   all gadget drivers to also be dynamically linked.
+
+config USB_FSL_USB2
+	tristate
+	depends on USB_GADGET_FSL_USB2
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_NET2280
 	boolean "NetChip 228x"
 	depends on PCI
@@ -370,6 +391,7 @@ config USB_GADGETFS
 
 config USB_FILE_STORAGE
 	tristate "File-backed Storage Gadget"
+	depends on BLOCK
 	help
 	  The File-backed Storage Gadget acts as a USB Mass Storage
 	  disk drive.  As its storage repository it can use a regular
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e71e086..5db1939 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
+obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 
 #
 # USB gadget drivers
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 2a6e316..ba163f3 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -31,7 +31,6 @@ #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/list.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 7d7909c..fcb5526 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -41,7 +41,6 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 04e6b85..325bf7c 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -28,7 +28,6 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
@@ -282,6 +281,9 @@ #ifdef CONFIG_USB_GADGET_HUSB2DEV
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define DEV_CONFIG_CDC
+#endif
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -1735,7 +1737,8 @@ enomem:
 		defer_kevent (dev, WORK_RX_MEMORY);
 	if (retval) {
 		DEBUG (dev, "rx submit --> %d\n", retval);
-		dev_kfree_skb_any (skb);
+		if (skb)
+			dev_kfree_skb_any(skb);
 		spin_lock(&dev->req_lock);
 		list_add (&req->list, &dev->rx_reqs);
 		spin_unlock(&dev->req_lock);
@@ -1766,7 +1769,6 @@ static void rx_complete (struct usb_ep *
 			break;
 		}
 
-		skb->dev = dev->net;
 		skb->protocol = eth_type_trans (skb, dev->net);
 		dev->stats.rx_packets++;
 		dev->stats.rx_bytes += skb->len;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
new file mode 100644
index 0000000..157054e
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -0,0 +1,2500 @@
+/*
+ * Copyright (C) 2004-2007 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ *         Jiang Bo <tanya.jiang@freescale.com>
+ *
+ * Description:
+ * Freescale high-speed USB SOC DR module device controller driver.
+ * This can be found on MPC8349E/MPC8313E cpus.
+ * The driver is previously named as mpc_udc.  Based on bare board
+ * code from Dave Liu and Shlomi Gridish.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#undef VERBOSE
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/dmapool.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+#include "fsl_usb2_udc.h"
+
+#define	DRIVER_DESC	"Freescale High-Speed USB SOC Device Controller driver"
+#define	DRIVER_AUTHOR	"Li Yang/Jiang Bo"
+#define	DRIVER_VERSION	"Apr 20, 2007"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+static const char driver_name[] = "fsl-usb2-udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+volatile static struct usb_dr_device *dr_regs = NULL;
+volatile static struct usb_sys_interface *usb_sys_regs = NULL;
+
+/* it is initialized in probe()  */
+static struct fsl_udc *udc_controller = NULL;
+
+static const struct usb_endpoint_descriptor
+fsl_ep0_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	0,
+	.bmAttributes =		USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize =	USB_MAX_CTRL_PAYLOAD,
+};
+
+static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state);
+static int fsl_udc_resume(struct platform_device *pdev);
+static void fsl_ep_fifo_flush(struct usb_ep *_ep);
+
+#ifdef CONFIG_PPC32
+#define fsl_readl(addr)		in_le32(addr)
+#define fsl_writel(addr, val32) out_le32(val32, addr)
+#else
+#define fsl_readl(addr)		readl(addr)
+#define fsl_writel(addr, val32) writel(addr, val32)
+#endif
+
+/********************************************************************
+ *	Internal Used Function
+********************************************************************/
+/*-----------------------------------------------------------------
+ * done() - retire a request; caller blocked irqs
+ * @status : request status to be set, only works when
+ *	request is still in progress.
+ *--------------------------------------------------------------*/
+static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
+{
+	struct fsl_udc *udc = NULL;
+	unsigned char stopped = ep->stopped;
+	struct ep_td_struct *curr_td, *next_td;
+	int j;
+
+	udc = (struct fsl_udc *)ep->udc;
+	/* Removed the req from fsl_ep->queue */
+	list_del_init(&req->queue);
+
+	/* req.status should be set as -EINPROGRESS in ep_queue() */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	/* Free dtd for the request */
+	next_td = req->head;
+	for (j = 0; j < req->dtd_count; j++) {
+		curr_td = next_td;
+		if (j != req->dtd_count - 1) {
+			next_td = curr_td->next_td_virt;
+		}
+		dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+	}
+
+	if (req->mapped) {
+		dma_unmap_single(ep->udc->gadget.dev.parent,
+			req->req.dma, req->req.length,
+			ep_is_in(ep)
+				? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	} else
+		dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+			req->req.dma, req->req.length,
+			ep_is_in(ep)
+				? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+
+	if (status && (status != -ESHUTDOWN))
+		VDBG("complete %s req %p stat %d len %u/%u",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	ep->stopped = 1;
+
+	spin_unlock(&ep->udc->lock);
+	/* complete() is from gadget layer,
+	 * eg fsg->bulk_in_complete() */
+	if (req->req.complete)
+		req->req.complete(&ep->ep, &req->req);
+
+	spin_lock(&ep->udc->lock);
+	ep->stopped = stopped;
+}
+
+/*-----------------------------------------------------------------
+ * nuke(): delete all requests related to this ep
+ * called with spinlock held
+ *--------------------------------------------------------------*/
+static void nuke(struct fsl_ep *ep, int status)
+{
+	ep->stopped = 1;
+
+	/* Flush fifo */
+	fsl_ep_fifo_flush(&ep->ep);
+
+	/* Whether this eq has request linked */
+	while (!list_empty(&ep->queue)) {
+		struct fsl_req *req = NULL;
+
+		req = list_entry(ep->queue.next, struct fsl_req, queue);
+		done(ep, req, status);
+	}
+}
+
+/*------------------------------------------------------------------
+	Internal Hardware related function
+ ------------------------------------------------------------------*/
+
+static int dr_controller_setup(struct fsl_udc *udc)
+{
+	unsigned int tmp = 0, portctrl = 0, ctrl = 0;
+	unsigned long timeout;
+#define FSL_UDC_RESET_TIMEOUT 1000
+
+	/* before here, make sure dr_regs has been initialized */
+	if (!udc)
+		return -EINVAL;
+
+	/* Stop and reset the usb controller */
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp &= ~USB_CMD_RUN_STOP;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp |= USB_CMD_CTRL_RESET;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	/* Wait for reset to complete */
+	timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
+	while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+		if (time_after(jiffies, timeout)) {
+			ERR("udc reset timeout! \n");
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+	}
+
+	/* Set the controller as device mode */
+	tmp = fsl_readl(&dr_regs->usbmode);
+	tmp |= USB_MODE_CTRL_MODE_DEVICE;
+	/* Disable Setup Lockout */
+	tmp |= USB_MODE_SETUP_LOCK_OFF;
+	fsl_writel(tmp, &dr_regs->usbmode);
+
+	/* Clear the setup status */
+	fsl_writel(0, &dr_regs->usbsts);
+
+	tmp = udc->ep_qh_dma;
+	tmp &= USB_EP_LIST_ADDRESS_MASK;
+	fsl_writel(tmp, &dr_regs->endpointlistaddr);
+
+	VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+		(int)udc->ep_qh, (int)tmp,
+		fsl_readl(&dr_regs->endpointlistaddr));
+
+	/* Config PHY interface */
+	portctrl = fsl_readl(&dr_regs->portsc1);
+	portctrl &= ~PORTSCX_PHY_TYPE_SEL;
+	switch (udc->phy_mode) {
+	case FSL_USB2_PHY_ULPI:
+		portctrl |= PORTSCX_PTS_ULPI;
+		break;
+	case FSL_USB2_PHY_UTMI:
+	case FSL_USB2_PHY_UTMI_WIDE:
+		portctrl |= PORTSCX_PTS_UTMI;
+		break;
+	case FSL_USB2_PHY_SERIAL:
+		portctrl |= PORTSCX_PTS_FSLS;
+		break;
+	default:
+		return -EINVAL;
+	}
+	fsl_writel(portctrl, &dr_regs->portsc1);
+
+	/* Config control enable i/o output, cpu endian register */
+	ctrl = __raw_readl(&usb_sys_regs->control);
+	ctrl |= USB_CTRL_IOENB;
+	__raw_writel(ctrl, &usb_sys_regs->control);
+
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+	/* Turn on cache snooping hardware, since some PowerPC platforms
+	 * wholly rely on hardware to deal with cache coherent. */
+
+	/* Setup Snooping for all the 4GB space */
+	tmp = SNOOP_SIZE_2GB;	/* starts from 0x0, size 2G */
+	__raw_writel(tmp, &usb_sys_regs->snoop1);
+	tmp |= 0x80000000;	/* starts from 0x8000000, size 2G */
+	__raw_writel(tmp, &usb_sys_regs->snoop2);
+#endif
+
+	return 0;
+}
+
+/* Enable DR irq and set controller to run state */
+static void dr_controller_run(struct fsl_udc *udc)
+{
+	u32 temp;
+
+	/* Enable DR irq reg */
+	temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN
+		| USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN
+		| USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+	fsl_writel(temp, &dr_regs->usbintr);
+
+	/* Clear stopped bit */
+	udc->stopped = 0;
+
+	/* Set the controller as device mode */
+	temp = fsl_readl(&dr_regs->usbmode);
+	temp |= USB_MODE_CTRL_MODE_DEVICE;
+	fsl_writel(temp, &dr_regs->usbmode);
+
+	/* Set controller to Run */
+	temp = fsl_readl(&dr_regs->usbcmd);
+	temp |= USB_CMD_RUN_STOP;
+	fsl_writel(temp, &dr_regs->usbcmd);
+
+	return;
+}
+
+static void dr_controller_stop(struct fsl_udc *udc)
+{
+	unsigned int tmp;
+
+	/* disable all INTR */
+	fsl_writel(0, &dr_regs->usbintr);
+
+	/* Set stopped bit for isr */
+	udc->stopped = 1;
+
+	/* disable IO output */
+/*	usb_sys_regs->control = 0; */
+
+	/* set controller to Stop */
+	tmp = fsl_readl(&dr_regs->usbcmd);
+	tmp &= ~USB_CMD_RUN_STOP;
+	fsl_writel(tmp, &dr_regs->usbcmd);
+
+	return;
+}
+
+void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type)
+{
+	unsigned int tmp_epctrl = 0;
+
+	tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (dir) {
+		if (ep_num)
+			tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+		tmp_epctrl |= EPCTRL_TX_ENABLE;
+		tmp_epctrl |= ((unsigned int)(ep_type)
+				<< EPCTRL_TX_EP_TYPE_SHIFT);
+	} else {
+		if (ep_num)
+			tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+		tmp_epctrl |= EPCTRL_RX_ENABLE;
+		tmp_epctrl |= ((unsigned int)(ep_type)
+				<< EPCTRL_RX_EP_TYPE_SHIFT);
+	}
+
+	fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
+}
+
+static void
+dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value)
+{
+	u32 tmp_epctrl = 0;
+
+	tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+
+	if (value) {
+		/* set the stall bit */
+		if (dir)
+			tmp_epctrl |= EPCTRL_TX_EP_STALL;
+		else
+			tmp_epctrl |= EPCTRL_RX_EP_STALL;
+	} else {
+		/* clear the stall bit and reset data toggle */
+		if (dir) {
+			tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+			tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+		} else {
+			tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+			tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+		}
+	}
+	fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]);
+}
+
+/* Get stall status of a specific ep
+   Return: 0: not stalled; 1:stalled */
+static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir)
+{
+	u32 epctrl;
+
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (dir)
+		return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0;
+	else
+		return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0;
+}
+
+/********************************************************************
+	Internal Structure Build up functions
+********************************************************************/
+
+/*------------------------------------------------------------------
+* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select (1: disable; 0: enable)
+ * @mult: Mult field
+ ------------------------------------------------------------------*/
+static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
+		unsigned char dir, unsigned char ep_type,
+		unsigned int max_pkt_len,
+		unsigned int zlt, unsigned char mult)
+{
+	struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir];
+	unsigned int tmp = 0;
+
+	/* set the Endpoint Capabilites in QH */
+	switch (ep_type) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		/* Interrupt On Setup (IOS). for control ep  */
+		tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+			| EP_QUEUE_HEAD_IOS;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
+			| (mult << EP_QUEUE_HEAD_MULT_POS);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+		break;
+	default:
+		VDBG("error ep type is %d", ep_type);
+		return;
+	}
+	if (zlt)
+		tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+	p_QH->max_pkt_length = cpu_to_le32(tmp);
+
+	return;
+}
+
+/* Setup qh structure and ep register for ep0. */
+static void ep0_setup(struct fsl_udc *udc)
+{
+	/* the intialization of an ep includes: fields in QH, Regs,
+	 * fsl_ep struct */
+	struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL,
+			USB_MAX_CTRL_PAYLOAD, 0, 0);
+	struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL,
+			USB_MAX_CTRL_PAYLOAD, 0, 0);
+	dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+	dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+	return;
+
+}
+
+/***********************************************************************
+		Endpoint Management Functions
+***********************************************************************/
+
+/*-------------------------------------------------------------------------
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 doesn't use this routine. It is always enabled.
+-------------------------------------------------------------------------*/
+static int fsl_ep_enable(struct usb_ep *_ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct fsl_udc *udc = NULL;
+	struct fsl_ep *ep = NULL;
+	unsigned short max = 0;
+	unsigned char mult = 0, zlt;
+	int retval = -EINVAL;
+	unsigned long flags = 0;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+
+	/* catch various bogus parameters */
+	if (!_ep || !desc || ep->desc
+			|| (desc->bDescriptorType != USB_DT_ENDPOINT))
+		return -EINVAL;
+
+	udc = ep->udc;
+
+	if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+		return -ESHUTDOWN;
+
+	max = le16_to_cpu(desc->wMaxPacketSize);
+
+	/* Disable automatic zlp generation.  Driver is reponsible to indicate
+	 * explicitly through req->req.zero.  This is needed to enable multi-td
+	 * request. */
+	zlt = 1;
+
+	/* Assume the max packet size from gadget is always correct */
+	switch (desc->bmAttributes & 0x03) {
+	case USB_ENDPOINT_XFER_CONTROL:
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		/* mult = 0.  Execute N Transactions as demonstrated by
+		 * the USB variable length packet protocol where N is
+		 * computed using the Maximum Packet Length (dQH) and
+		 * the Total Bytes field (dTD) */
+		mult = 0;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		/* Calculate transactions needed for high bandwidth iso */
+		mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+		max = max & 0x8ff;	/* bit 0~10 */
+		/* 3 transactions at most */
+		if (mult > 3)
+			goto en_done;
+		break;
+	default:
+		goto en_done;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+	ep->ep.maxpacket = max;
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	/* Controller related setup */
+	/* Init EPx Queue Head (Ep Capabilites field in QH
+	 * according to max, zlt, mult) */
+	struct_ep_qh_setup(udc, (unsigned char) ep_index(ep),
+			(unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+					?  USB_SEND : USB_RECV),
+			(unsigned char) (desc->bmAttributes
+					& USB_ENDPOINT_XFERTYPE_MASK),
+			max, zlt, mult);
+
+	/* Init endpoint ctrl register */
+	dr_ep_setup((unsigned char) ep_index(ep),
+			(unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+					? USB_SEND : USB_RECV),
+			(unsigned char) (desc->bmAttributes
+					& USB_ENDPOINT_XFERTYPE_MASK));
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	retval = 0;
+
+	VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
+			ep->desc->bEndpointAddress & 0x0f,
+			(desc->bEndpointAddress & USB_DIR_IN)
+				? "in" : "out", max);
+en_done:
+	return retval;
+}
+
+/*---------------------------------------------------------------------
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+*---------------------------------------------------------------------*/
+static int fsl_ep_disable(struct usb_ep *_ep)
+{
+	struct fsl_udc *udc = NULL;
+	struct fsl_ep *ep = NULL;
+	unsigned long flags = 0;
+	u32 epctrl;
+	int ep_num;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+	if (!_ep || !ep->desc) {
+		VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	/* disable ep on controller */
+	ep_num = ep_index(ep);
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl &= ~EPCTRL_TX_ENABLE;
+	else
+		epctrl &= ~EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+
+	udc = (struct fsl_udc *)ep->udc;
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* nuke all pending requests (does flush) */
+	nuke(ep, -ESHUTDOWN);
+
+	ep->desc = 0;
+	ep->stopped = 1;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	VDBG("disabled %s OK", _ep->name);
+	return 0;
+}
+
+/*---------------------------------------------------------------------
+ * allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static struct usb_request *
+fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fsl_req *req = NULL;
+
+	req = kzalloc(sizeof *req, gfp_flags);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fsl_req *req = NULL;
+
+	req = container_of(_req, struct fsl_req, req);
+
+	if (_req)
+		kfree(req);
+}
+
+/*------------------------------------------------------------------
+ * Allocate an I/O buffer
+*---------------------------------------------------------------------*/
+static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+		dma_addr_t *dma, gfp_t gfp_flags)
+{
+	struct fsl_ep *ep;
+
+	if (!_ep)
+		return NULL;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+
+	return dma_alloc_coherent(ep->udc->gadget.dev.parent,
+			bytes, dma, gfp_flags);
+}
+
+/*------------------------------------------------------------------
+ * frees an i/o buffer
+*---------------------------------------------------------------------*/
+static void fsl_free_buffer(struct usb_ep *_ep, void *buf,
+		dma_addr_t dma, unsigned bytes)
+{
+	struct fsl_ep *ep;
+
+	if (!_ep)
+		return NULL;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+
+	dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
+}
+
+/*-------------------------------------------------------------------------*/
+static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
+{
+	int i = ep_index(ep) * 2 + ep_is_in(ep);
+	u32 temp, bitmask, tmp_stat;
+	struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+
+	/* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
+	VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
+
+	bitmask = ep_is_in(ep)
+		? (1 << (ep_index(ep) + 16))
+		: (1 << (ep_index(ep)));
+
+	/* check if the pipe is empty */
+	if (!(list_empty(&ep->queue))) {
+		/* Add td to the end */
+		struct fsl_req *lastreq;
+		lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
+		lastreq->tail->next_td_ptr =
+			cpu_to_le32(req->head->td_dma & DTD_ADDR_MASK);
+		/* Read prime bit, if 1 goto done */
+		if (fsl_readl(&dr_regs->endpointprime) & bitmask)
+			goto out;
+
+		do {
+			/* Set ATDTW bit in USBCMD */
+			temp = fsl_readl(&dr_regs->usbcmd);
+			fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd);
+
+			/* Read correct status bit */
+			tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask;
+
+		} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW));
+
+		/* Write ATDTW bit to 0 */
+		temp = fsl_readl(&dr_regs->usbcmd);
+		fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
+
+		if (tmp_stat)
+			goto out;
+	}
+
+	/* Write dQH next pointer and terminate bit to 0 */
+	temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+	dQH->next_dtd_ptr = cpu_to_le32(temp);
+
+	/* Clear active and halt bit */
+	temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+			| EP_QUEUE_HEAD_STATUS_HALT));
+	dQH->size_ioc_int_sts &= temp;
+
+	/* Prime endpoint by writing 1 to ENDPTPRIME */
+	temp = ep_is_in(ep)
+		? (1 << (ep_index(ep) + 16))
+		: (1 << (ep_index(ep)));
+	fsl_writel(temp, &dr_regs->endpointprime);
+out:
+	return 0;
+}
+
+/* Fill in the dTD structure
+ * @req: request that the transfer belongs to
+ * @length: return actually data length of the dTD
+ * @dma: return dma address of the dTD
+ * @is_last: return flag if it is the last dTD of the request
+ * return: pointer to the built dTD */
+static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
+		dma_addr_t *dma, int *is_last)
+{
+	u32 swap_temp;
+	struct ep_td_struct *dtd;
+
+	/* how big will this transfer be? */
+	*length = min(req->req.length - req->req.actual,
+			(unsigned)EP_MAX_LENGTH_TRANSFER);
+
+	dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
+	if (dtd == NULL)
+		return dtd;
+
+	dtd->td_dma = *dma;
+	/* Clear reserved field */
+	swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+	swap_temp &= ~DTD_RESERVED_FIELDS;
+	dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+	/* Init all of buffer page pointers */
+	swap_temp = (u32) (req->req.dma + req->req.actual);
+	dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+	dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+	dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+	dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+	dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+	req->req.actual += *length;
+
+	/* zlp is needed if req->req.zero is set */
+	if (req->req.zero) {
+		if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+			*is_last = 1;
+		else
+			*is_last = 0;
+	} else if (req->req.length == req->req.actual)
+		*is_last = 1;
+	else
+		*is_last = 0;
+
+	if ((*is_last) == 0)
+		VDBG("multi-dtd request!\n");
+	/* Fill in the transfer size; set active bit */
+	swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
+
+	/* Enable interrupt for the last dtd of a request */
+	if (*is_last && !req->req.no_interrupt)
+		swap_temp |= DTD_IOC;
+
+	dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+	mb();
+
+	VDBG("length = %d address= 0x%x", *length, (int)*dma);
+
+	return dtd;
+}
+
+/* Generate dtd chain for a request */
+static int fsl_req_to_dtd(struct fsl_req *req)
+{
+	unsigned	count;
+	int		is_last;
+	int		is_first =1;
+	struct ep_td_struct	*last_dtd = NULL, *dtd;
+	dma_addr_t dma;
+
+	do {
+		dtd = fsl_build_dtd(req, &count, &dma, &is_last);
+		if (dtd == NULL)
+			return -ENOMEM;
+
+		if (is_first) {
+			is_first = 0;
+			req->head = dtd;
+		} else {
+			last_dtd->next_td_ptr = cpu_to_le32(dma);
+			last_dtd->next_td_virt = dtd;
+		}
+		last_dtd = dtd;
+
+		req->dtd_count++;
+	} while (!is_last);
+
+	dtd->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+
+	req->tail = dtd;
+
+	return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
+	struct fsl_req *req = container_of(_req, struct fsl_req, req);
+	struct fsl_udc *udc;
+	unsigned long flags;
+	int is_iso = 0;
+
+	/* catch various bogus parameters */
+	if (!_req || !req->req.complete || !req->req.buf
+			|| !list_empty(&req->queue)) {
+		VDBG("%s, bad params\n", __FUNCTION__);
+		return -EINVAL;
+	}
+	if (!_ep || (!ep->desc && ep_index(ep))) {
+		VDBG("%s, bad ep\n", __FUNCTION__);
+		return -EINVAL;
+	}
+	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		if (req->req.length > ep->ep.maxpacket)
+			return -EMSGSIZE;
+		is_iso = 1;
+	}
+
+	udc = ep->udc;
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	req->ep = ep;
+
+	/* map virtual address to hardware */
+	if (req->req.dma == DMA_ADDR_INVALID) {
+		req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+					req->req.buf,
+					req->req.length, ep_is_in(ep)
+						? DMA_TO_DEVICE
+						: DMA_FROM_DEVICE);
+		req->mapped = 1;
+	} else {
+		dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+					req->req.dma, req->req.length,
+					ep_is_in(ep)
+						? DMA_TO_DEVICE
+						: DMA_FROM_DEVICE);
+		req->mapped = 0;
+	}
+
+	req->req.status = -EINPROGRESS;
+	req->req.actual = 0;
+	req->dtd_count = 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* build dtds and push them to device queue */
+	if (!fsl_req_to_dtd(req)) {
+		fsl_queue_td(ep, req);
+	} else {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -ENOMEM;
+	}
+
+	/* Update ep0 state */
+	if ((ep_index(ep) == 0))
+		udc->ep0_state = DATA_STATE_XMIT;
+
+	/* irq handler advances the queue */
+	if (req != NULL)
+		list_add_tail(&req->queue, &ep->queue);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep);
+	struct fsl_req *req;
+	unsigned long flags;
+	int ep_num, stopped, ret = 0;
+	u32 epctrl;
+
+	if (!_ep || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+	stopped = ep->stopped;
+
+	/* Stop the ep before we deal with the queue */
+	ep->stopped = 1;
+	ep_num = ep_index(ep);
+	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl &= ~EPCTRL_TX_ENABLE;
+	else
+		epctrl &= ~EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* The request is in progress, or completed but not dequeued */
+	if (ep->queue.next == &req->queue) {
+		_req->status = -ECONNRESET;
+		fsl_ep_fifo_flush(_ep);	/* flush current transfer */
+
+		/* The request isn't the last request in this ep queue */
+		if (req->queue.next != &ep->queue) {
+			struct ep_queue_head *qh;
+			struct fsl_req *next_req;
+
+			qh = ep->qh;
+			next_req = list_entry(req->queue.next, struct fsl_req,
+					queue);
+
+			/* Point the QH to the first TD of next request */
+			fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr);
+		}
+
+		/* The request hasn't been processed, patch up the TD chain */
+	} else {
+		struct fsl_req *prev_req;
+
+		prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
+		fsl_writel(fsl_readl(&req->tail->next_td_ptr),
+				&prev_req->tail->next_td_ptr);
+
+	}
+
+	done(ep, req, -ECONNRESET);
+
+	/* Enable EP */
+out:	epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]);
+	if (ep_is_in(ep))
+		epctrl |= EPCTRL_TX_ENABLE;
+	else
+		epctrl |= EPCTRL_RX_ENABLE;
+	fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]);
+	ep->stopped = stopped;
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt  0--clear halt
+ * Returns zero, or a negative error code.
+*----------------------------------------------------------------*/
+static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct fsl_ep *ep = NULL;
+	unsigned long flags = 0;
+	int status = -EOPNOTSUPP;	/* operation not supported */
+	unsigned char ep_dir = 0, ep_num = 0;
+	struct fsl_udc *udc = NULL;
+
+	ep = container_of(_ep, struct fsl_ep, ep);
+	udc = ep->udc;
+	if (!_ep || !ep->desc) {
+		status = -EINVAL;
+		goto out;
+	}
+
+	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+		status = -EOPNOTSUPP;
+		goto out;
+	}
+
+	/* Attempt to halt IN ep will fail if any transfer requests
+	 * are still queue */
+	if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+		status = -EAGAIN;
+		goto out;
+	}
+
+	status = 0;
+	ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+	ep_num = (unsigned char)(ep_index(ep));
+	spin_lock_irqsave(&ep->udc->lock, flags);
+	dr_ep_change_stall(ep_num, ep_dir, value);
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+	if (ep_index(ep) == 0) {
+		udc->ep0_state = WAIT_FOR_SETUP;
+		udc->ep0_dir = 0;
+	}
+out:
+	VDBG(" %s %s halt stat %d", ep->ep.name,
+			value ?  "set" : "clear", status);
+
+	return status;
+}
+
+static void fsl_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct fsl_ep *ep;
+	int ep_num, ep_dir;
+	u32 bits;
+	unsigned long timeout;
+#define FSL_UDC_FLUSH_TIMEOUT 1000
+
+	if (!_ep) {
+		return;
+	} else {
+		ep = container_of(_ep, struct fsl_ep, ep);
+		if (!ep->desc)
+			return;
+	}
+	ep_num = ep_index(ep);
+	ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+
+	if (ep_num == 0)
+		bits = (1 << 16) | 1;
+	else if (ep_dir == USB_SEND)
+		bits = 1 << (16 + ep_num);
+	else
+		bits = 1 << ep_num;
+
+	timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT;
+	do {
+		fsl_writel(bits, &dr_regs->endptflush);
+
+		/* Wait until flush complete */
+		while (fsl_readl(&dr_regs->endptflush)) {
+			if (time_after(jiffies, timeout)) {
+				ERR("ep flush timeout\n");
+				return;
+			}
+			cpu_relax();
+		}
+		/* See if we need to flush again */
+	} while (fsl_readl(&dr_regs->endptstatus) & bits);
+}
+
+static struct usb_ep_ops fsl_ep_ops = {
+	.enable = fsl_ep_enable,
+	.disable = fsl_ep_disable,
+
+	.alloc_request = fsl_alloc_request,
+	.free_request = fsl_free_request,
+
+	.alloc_buffer = fsl_alloc_buffer,
+	.free_buffer = fsl_free_buffer,
+
+	.queue = fsl_ep_queue,
+	.dequeue = fsl_ep_dequeue,
+
+	.set_halt = fsl_ep_set_halt,
+	.fifo_flush = fsl_ep_fifo_flush,	/* flush fifo */
+};
+
+/*-------------------------------------------------------------------------
+		Gadget Driver Layer Operations
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+ * Get the current frame number (from DR frame_index Reg )
+ *----------------------------------------------------------------------*/
+static int fsl_get_frame(struct usb_gadget *gadget)
+{
+	return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS);
+}
+
+/*-----------------------------------------------------------------------
+ * Tries to wake up the host connected to this gadget
+ -----------------------------------------------------------------------*/
+static int fsl_wakeup(struct usb_gadget *gadget)
+{
+	struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget);
+	u32 portsc;
+
+	/* Remote wakeup feature not enabled by host */
+	if (!udc->remote_wakeup)
+		return -ENOTSUPP;
+
+	portsc = fsl_readl(&dr_regs->portsc1);
+	/* not suspended? */
+	if (!(portsc & PORTSCX_PORT_SUSPEND))
+		return 0;
+	/* trigger force resume */
+	portsc |= PORTSCX_PORT_FORCE_RESUME;
+	fsl_writel(portsc, &dr_regs->portsc1);
+	return 0;
+}
+
+static int can_pullup(struct fsl_udc *udc)
+{
+	return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+/* Notify controller that VBUS is powered, Called by whatever
+   detects VBUS sessions */
+static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct fsl_udc	*udc;
+	unsigned long	flags;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+	spin_lock_irqsave(&udc->lock, flags);
+	VDBG("VBUS %s\n", is_active ? "on" : "off");
+	udc->vbus_active = (is_active != 0);
+	if (can_pullup(udc))
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	else
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return 0;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+#ifdef CONFIG_USB_OTG
+	struct fsl_udc *udc;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+
+	if (udc->transceiver)
+		return otg_set_power(udc->transceiver, mA);
+#endif
+	return -ENOTSUPP;
+}
+
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnet
+ */
+static int fsl_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct fsl_udc *udc;
+
+	udc = container_of(gadget, struct fsl_udc, gadget);
+	udc->softconnect = (is_on != 0);
+	if (can_pullup(udc))
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+	else
+		fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP),
+				&dr_regs->usbcmd);
+
+	return 0;
+}
+
+/* defined in usb_gadget.h */
+static struct usb_gadget_ops fsl_gadget_ops = {
+	.get_frame = fsl_get_frame,
+	.wakeup = fsl_wakeup,
+/*	.set_selfpowered = fsl_set_selfpowered,	*/ /* Always selfpowered */
+	.vbus_session = fsl_vbus_session,
+	.vbus_draw = fsl_vbus_draw,
+	.pullup = fsl_pullup,
+};
+
+/* Set protocol stall on ep0, protocol stall will automatically be cleared
+   on new transaction */
+static void ep0stall(struct fsl_udc *udc)
+{
+	u32 tmp;
+
+	/* must set tx and rx to stall at the same time */
+	tmp = fsl_readl(&dr_regs->endptctrl[0]);
+	tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+	fsl_writel(tmp, &dr_regs->endptctrl[0]);
+	udc->ep0_state = WAIT_FOR_SETUP;
+	udc->ep0_dir = 0;
+}
+
+/* Prime a status phase for ep0 */
+static int ep0_prime_status(struct fsl_udc *udc, int direction)
+{
+	struct fsl_req *req = udc->status_req;
+	struct fsl_ep *ep;
+	int status = 0;
+
+	if (direction == EP_DIR_IN)
+		udc->ep0_dir = USB_DIR_IN;
+	else
+		udc->ep0_dir = USB_DIR_OUT;
+
+	ep = &udc->eps[0];
+	udc->ep0_state = WAIT_FOR_OUT_STATUS;
+
+	req->ep = ep;
+	req->req.length = 0;
+	req->req.status = -EINPROGRESS;
+	req->req.actual = 0;
+	req->req.complete = NULL;
+	req->dtd_count = 0;
+
+	if (fsl_req_to_dtd(req) == 0)
+		status = fsl_queue_td(ep, req);
+	else
+		return -ENOMEM;
+
+	if (status)
+		ERR("Can't queue ep0 status request \n");
+	list_add_tail(&req->queue, &ep->queue);
+
+	return status;
+}
+
+static inline int udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
+{
+	struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
+
+	if (!ep->name)
+		return 0;
+
+	nuke(ep, -ESHUTDOWN);
+
+	return 0;
+}
+
+/*
+ * ch9 Set address
+ */
+static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length)
+{
+	/* Save the new address to device struct */
+	udc->device_address = (u8) value;
+	/* Update usb state */
+	udc->usb_state = USB_STATE_ADDRESS;
+	/* Status phase */
+	if (ep0_prime_status(udc, EP_DIR_IN))
+		ep0stall(udc);
+}
+
+/*
+ * ch9 Get status
+ */
+static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
+		u16 index, u16 length)
+{
+	u16 tmp = 0;		/* Status, cpu endian */
+
+	struct fsl_req *req;
+	struct fsl_ep *ep;
+	int status = 0;
+
+	ep = &udc->eps[0];
+
+	if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		/* Get device status */
+		tmp = 1 << USB_DEVICE_SELF_POWERED;
+		tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+		/* Get interface status */
+		/* We don't have interface information in udc driver */
+		tmp = 0;
+	} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+		/* Get endpoint status */
+		struct fsl_ep *target_ep;
+
+		target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
+
+		/* stall if endpoint doesn't exist */
+		if (!target_ep->desc)
+			goto stall;
+		tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))
+				<< USB_ENDPOINT_HALT;
+	}
+
+	udc->ep0_dir = USB_DIR_IN;
+	/* Borrow the per device status_req */
+	req = udc->status_req;
+	/* Fill in the reqest structure */
+	*((u16 *) req->req.buf) = cpu_to_le16(tmp);
+	req->ep = ep;
+	req->req.length = 2;
+	req->req.status = -EINPROGRESS;
+	req->req.actual = 0;
+	req->req.complete = NULL;
+	req->dtd_count = 0;
+
+	/* prime the data phase */
+	if ((fsl_req_to_dtd(req) == 0))
+		status = fsl_queue_td(ep, req);
+	else			/* no mem */
+		goto stall;
+
+	if (status) {
+		ERR("Can't respond to getstatus request \n");
+		goto stall;
+	}
+	list_add_tail(&req->queue, &ep->queue);
+	udc->ep0_state = DATA_STATE_XMIT;
+	return;
+stall:
+	ep0stall(udc);
+}
+
+static void setup_received_irq(struct fsl_udc *udc,
+		struct usb_ctrlrequest *setup)
+{
+	u16 wValue = le16_to_cpu(setup->wValue);
+	u16 wIndex = le16_to_cpu(setup->wIndex);
+	u16 wLength = le16_to_cpu(setup->wLength);
+
+	udc_reset_ep_queue(udc, 0);
+
+	switch (setup->bRequest) {
+		/* Request that need Data+Status phase from udc */
+	case USB_REQ_GET_STATUS:
+		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+					!= (USB_DIR_IN | USB_TYPE_STANDARD))
+			break;
+		ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
+		break;
+
+		/* Requests that need Status phase from udc */
+	case USB_REQ_SET_ADDRESS:
+		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
+						| USB_RECIP_DEVICE))
+			break;
+		ch9setaddress(udc, wValue, wIndex, wLength);
+		break;
+
+		/* Handled by udc, no data, status by udc */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+	{	/* status transaction */
+		int rc = -EOPNOTSUPP;
+
+		if ((setup->bRequestType & USB_RECIP_MASK)
+				== USB_RECIP_ENDPOINT) {
+			int pipe = get_pipe_by_windex(wIndex);
+			struct fsl_ep *ep;
+
+			if (wValue != 0 || wLength != 0 || pipe > udc->max_ep)
+				break;
+			ep = get_ep_by_pipe(udc, pipe);
+
+			spin_unlock(&udc->lock);
+			rc = fsl_ep_set_halt(&ep->ep,
+					(setup->bRequest == USB_REQ_SET_FEATURE)
+						? 1 : 0);
+			spin_lock(&udc->lock);
+
+		} else if ((setup->bRequestType & USB_RECIP_MASK)
+				== USB_RECIP_DEVICE) {
+			/* Note: The driver has not include OTG support yet.
+			 * This will be set when OTG support is added */
+			if (!udc->gadget.is_otg)
+				break;
+			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+				udc->gadget.b_hnp_enable = 1;
+			else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+				udc->gadget.a_hnp_support = 1;
+			else if (setup->bRequest ==
+					USB_DEVICE_A_ALT_HNP_SUPPORT)
+				udc->gadget.a_alt_hnp_support = 1;
+			rc = 0;
+		}
+		if (rc == 0) {
+			if (ep0_prime_status(udc, EP_DIR_IN))
+				ep0stall(udc);
+		}
+		break;
+	}
+		/* Requests handled by gadget */
+	default:
+		if (wLength) {
+			/* Data phase from gadget, status phase from udc */
+			udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+					?  USB_DIR_IN : USB_DIR_OUT;
+			spin_unlock(&udc->lock);
+			if (udc->driver->setup(&udc->gadget,
+					&udc->local_setup_buff) < 0)
+				ep0stall(udc);
+			spin_lock(&udc->lock);
+			udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+					?  DATA_STATE_XMIT : DATA_STATE_RECV;
+
+		} else {
+			/* No data phase, IN status from gadget */
+			udc->ep0_dir = USB_DIR_IN;
+			spin_unlock(&udc->lock);
+			if (udc->driver->setup(&udc->gadget,
+					&udc->local_setup_buff) < 0)
+				ep0stall(udc);
+			spin_lock(&udc->lock);
+			udc->ep0_state = WAIT_FOR_OUT_STATUS;
+		}
+		break;
+	}
+}
+
+/* Process request for Data or Status phase of ep0
+ * prime status phase if needed */
+static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
+		struct fsl_req *req)
+{
+	if (udc->usb_state == USB_STATE_ADDRESS) {
+		/* Set the new address */
+		u32 new_address = (u32) udc->device_address;
+		fsl_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS,
+				&dr_regs->deviceaddr);
+	}
+
+	done(ep0, req, 0);
+
+	switch (udc->ep0_state) {
+	case DATA_STATE_XMIT:
+		/* receive status phase */
+		if (ep0_prime_status(udc, EP_DIR_OUT))
+			ep0stall(udc);
+		break;
+	case DATA_STATE_RECV:
+		/* send status phase */
+		if (ep0_prime_status(udc, EP_DIR_IN))
+			ep0stall(udc);
+		break;
+	case WAIT_FOR_OUT_STATUS:
+		udc->ep0_state = WAIT_FOR_SETUP;
+		break;
+	case WAIT_FOR_SETUP:
+		ERR("Unexpect ep0 packets \n");
+		break;
+	default:
+		ep0stall(udc);
+		break;
+	}
+}
+
+/* Tripwire mechanism to ensure a setup packet payload is extracted without
+ * being corrupted by another incoming setup packet */
+static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr)
+{
+	u32 temp;
+	struct ep_queue_head *qh;
+
+	qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT];
+
+	/* Clear bit in ENDPTSETUPSTAT */
+	temp = fsl_readl(&dr_regs->endptsetupstat);
+	fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat);
+
+	/* while a hazard exists when setup package arrives */
+	do {
+		/* Set Setup Tripwire */
+		temp = fsl_readl(&dr_regs->usbcmd);
+		fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd);
+
+		/* Copy the setup packet to local buffer */
+		memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+	} while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW));
+
+	/* Clear Setup Tripwire */
+	temp = fsl_readl(&dr_regs->usbcmd);
+	fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd);
+}
+
+/* process-ep_req(): free the completed Tds for this req */
+static int process_ep_req(struct fsl_udc *udc, int pipe,
+		struct fsl_req *curr_req)
+{
+	struct ep_td_struct *curr_td;
+	int	td_complete, actual, remaining_length, j, tmp;
+	int	status = 0;
+	int	errors = 0;
+	struct  ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+	int direction = pipe % 2;
+
+	curr_td = curr_req->head;
+	td_complete = 0;
+	actual = curr_req->req.length;
+
+	for (j = 0; j < curr_req->dtd_count; j++) {
+		remaining_length = (le32_to_cpu(curr_td->size_ioc_sts)
+					& DTD_PACKET_SIZE)
+				>> DTD_LENGTH_BIT_POS;
+		actual -= remaining_length;
+
+		if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
+						DTD_ERROR_MASK)) {
+			if (errors & DTD_STATUS_HALTED) {
+				ERR("dTD error %08x QH=%d\n", errors, pipe);
+				/* Clear the errors and Halt condition */
+				tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
+				tmp &= ~errors;
+				curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
+				status = -EPIPE;
+				/* FIXME: continue with next queued TD? */
+
+				break;
+			}
+			if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+				VDBG("Transfer overflow");
+				status = -EPROTO;
+				break;
+			} else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+				VDBG("ISO error");
+				status = -EILSEQ;
+				break;
+			} else
+				ERR("Unknown error has occured (0x%x)!\r\n",
+					errors);
+
+		} else if (le32_to_cpu(curr_td->size_ioc_sts)
+				& DTD_STATUS_ACTIVE) {
+			VDBG("Request not complete");
+			status = REQ_UNCOMPLETE;
+			return status;
+		} else if (remaining_length) {
+			if (direction) {
+				VDBG("Transmit dTD remaining length not zero");
+				status = -EPROTO;
+				break;
+			} else {
+				td_complete++;
+				break;
+			}
+		} else {
+			td_complete++;
+			VDBG("dTD transmitted successful ");
+		}
+
+		if (j != curr_req->dtd_count - 1)
+			curr_td = (struct ep_td_struct *)curr_td->next_td_virt;
+	}
+
+	if (status)
+		return status;
+
+	curr_req->req.actual = actual;
+
+	return 0;
+}
+
+/* Process a DTD completion interrupt */
+static void dtd_complete_irq(struct fsl_udc *udc)
+{
+	u32 bit_pos;
+	int i, ep_num, direction, bit_mask, status;
+	struct fsl_ep *curr_ep;
+	struct fsl_req *curr_req, *temp_req;
+
+	/* Clear the bits in the register */
+	bit_pos = fsl_readl(&dr_regs->endptcomplete);
+	fsl_writel(bit_pos, &dr_regs->endptcomplete);
+
+	if (!bit_pos)
+		return;
+
+	for (i = 0; i < udc->max_ep * 2; i++) {
+		ep_num = i >> 1;
+		direction = i % 2;
+
+		bit_mask = 1 << (ep_num + 16 * direction);
+
+		if (!(bit_pos & bit_mask))
+			continue;
+
+		curr_ep = get_ep_by_pipe(udc, i);
+
+		/* If the ep is configured */
+		if (curr_ep->name == NULL) {
+			WARN("Invalid EP?");
+			continue;
+		}
+
+		/* process the req queue until an uncomplete request */
+		list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+				queue) {
+			status = process_ep_req(udc, i, curr_req);
+
+			VDBG("status of process_ep_req= %d, ep = %d",
+					status, ep_num);
+			if (status == REQ_UNCOMPLETE)
+				break;
+			/* write back status to req */
+			curr_req->req.status = status;
+
+			if (ep_num == 0) {
+				ep0_req_complete(udc, curr_ep, curr_req);
+				break;
+			} else
+				done(curr_ep, curr_req, status);
+		}
+	}
+}
+
+/* Process a port change interrupt */
+static void port_change_irq(struct fsl_udc *udc)
+{
+	u32 speed;
+
+	if (udc->bus_reset)
+		udc->bus_reset = 0;
+
+	/* Bus resetting is finished */
+	if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
+		/* Get the speed */
+		speed = (fsl_readl(&dr_regs->portsc1)
+				& PORTSCX_PORT_SPEED_MASK);
+		switch (speed) {
+		case PORTSCX_PORT_SPEED_HIGH:
+			udc->gadget.speed = USB_SPEED_HIGH;
+			break;
+		case PORTSCX_PORT_SPEED_FULL:
+			udc->gadget.speed = USB_SPEED_FULL;
+			break;
+		case PORTSCX_PORT_SPEED_LOW:
+			udc->gadget.speed = USB_SPEED_LOW;
+			break;
+		default:
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			break;
+		}
+	}
+
+	/* Update USB state */
+	if (!udc->resume_state)
+		udc->usb_state = USB_STATE_DEFAULT;
+}
+
+/* Process suspend interrupt */
+static void suspend_irq(struct fsl_udc *udc)
+{
+	udc->resume_state = udc->usb_state;
+	udc->usb_state = USB_STATE_SUSPENDED;
+
+	/* report suspend to the driver, serial.c does not support this */
+	if (udc->driver->suspend)
+		udc->driver->suspend(&udc->gadget);
+}
+
+static void bus_resume(struct fsl_udc *udc)
+{
+	udc->usb_state = udc->resume_state;
+	udc->resume_state = 0;
+
+	/* report resume to the driver, serial.c does not support this */
+	if (udc->driver->resume)
+		udc->driver->resume(&udc->gadget);
+}
+
+/* Clear up all ep queues */
+static int reset_queues(struct fsl_udc *udc)
+{
+	u8 pipe;
+
+	for (pipe = 0; pipe < udc->max_pipes; pipe++)
+		udc_reset_ep_queue(udc, pipe);
+
+	/* report disconnect; the driver is already quiesced */
+	udc->driver->disconnect(&udc->gadget);
+
+	return 0;
+}
+
+/* Process reset interrupt */
+static void reset_irq(struct fsl_udc *udc)
+{
+	u32 temp;
+	unsigned long timeout;
+
+	/* Clear the device address */
+	temp = fsl_readl(&dr_regs->deviceaddr);
+	fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr);
+
+	udc->device_address = 0;
+
+	/* Clear usb state */
+	udc->resume_state = 0;
+	udc->ep0_dir = 0;
+	udc->ep0_state = WAIT_FOR_SETUP;
+	udc->remote_wakeup = 0;	/* default to 0 on reset */
+	udc->gadget.b_hnp_enable = 0;
+	udc->gadget.a_hnp_support = 0;
+	udc->gadget.a_alt_hnp_support = 0;
+
+	/* Clear all the setup token semaphores */
+	temp = fsl_readl(&dr_regs->endptsetupstat);
+	fsl_writel(temp, &dr_regs->endptsetupstat);
+
+	/* Clear all the endpoint complete status bits */
+	temp = fsl_readl(&dr_regs->endptcomplete);
+	fsl_writel(temp, &dr_regs->endptcomplete);
+
+	timeout = jiffies + 100;
+	while (fsl_readl(&dr_regs->endpointprime)) {
+		/* Wait until all endptprime bits cleared */
+		if (time_after(jiffies, timeout)) {
+			ERR("Timeout for reset\n");
+			break;
+		}
+		cpu_relax();
+	}
+
+	/* Write 1s to the flush register */
+	fsl_writel(0xffffffff, &dr_regs->endptflush);
+
+	if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
+		VDBG("Bus reset");
+		/* Bus is reseting */
+		udc->bus_reset = 1;
+		/* Reset all the queues, include XD, dTD, EP queue
+		 * head and TR Queue */
+		reset_queues(udc);
+		udc->usb_state = USB_STATE_DEFAULT;
+	} else {
+		VDBG("Controller reset");
+		/* initialize usb hw reg except for regs for EP, not
+		 * touch usbintr reg */
+		dr_controller_setup(udc);
+
+		/* Reset all internal used Queues */
+		reset_queues(udc);
+
+		ep0_setup(udc);
+
+		/* Enable DR IRQ reg, Set Run bit, change udc state */
+		dr_controller_run(udc);
+		udc->usb_state = USB_STATE_ATTACHED;
+	}
+}
+
+/*
+ * USB device controller interrupt handler
+ */
+static irqreturn_t fsl_udc_irq(int irq, void *_udc)
+{
+	struct fsl_udc *udc = _udc;
+	u32 irq_src;
+	irqreturn_t status = IRQ_NONE;
+	unsigned long flags;
+
+	/* Disable ISR for OTG host mode */
+	if (udc->stopped)
+		return IRQ_NONE;
+	spin_lock_irqsave(&udc->lock, flags);
+	irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
+	/* Clear notification bits */
+	fsl_writel(irq_src, &dr_regs->usbsts);
+
+	/* VDBG("irq_src [0x%8x]", irq_src); */
+
+	/* Need to resume? */
+	if (udc->usb_state == USB_STATE_SUSPENDED)
+		if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0)
+			bus_resume(udc);
+
+	/* USB Interrupt */
+	if (irq_src & USB_STS_INT) {
+		VDBG("Packet int");
+		/* Setup package, we only support ep0 as control ep */
+		if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
+			tripwire_handler(udc, 0,
+					(u8 *) (&udc->local_setup_buff));
+			setup_received_irq(udc, &udc->local_setup_buff);
+			status = IRQ_HANDLED;
+		}
+
+		/* completion of dtd */
+		if (fsl_readl(&dr_regs->endptcomplete)) {
+			dtd_complete_irq(udc);
+			status = IRQ_HANDLED;
+		}
+	}
+
+	/* SOF (for ISO transfer) */
+	if (irq_src & USB_STS_SOF) {
+		status = IRQ_HANDLED;
+	}
+
+	/* Port Change */
+	if (irq_src & USB_STS_PORT_CHANGE) {
+		port_change_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	/* Reset Received */
+	if (irq_src & USB_STS_RESET) {
+		reset_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	/* Sleep Enable (Suspend) */
+	if (irq_src & USB_STS_SUSPEND) {
+		suspend_irq(udc);
+		status = IRQ_HANDLED;
+	}
+
+	if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
+		VDBG("Error IRQ %x ", irq_src);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+	return status;
+}
+
+/*----------------------------------------------------------------*
+ * Hook to gadget drivers
+ * Called by initialization code of gadget drivers
+*----------------------------------------------------------------*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int retval = -ENODEV;
+	unsigned long flags = 0;
+
+	if (!udc_controller)
+		return -ENODEV;
+
+	if (!driver || (driver->speed != USB_SPEED_FULL
+				&& driver->speed != USB_SPEED_HIGH)
+			|| !driver->bind || !driver->disconnect
+			|| !driver->setup)
+		return -EINVAL;
+
+	if (udc_controller->driver)
+		return -EBUSY;
+
+	/* lock is needed but whether should use this lock or another */
+	spin_lock_irqsave(&udc_controller->lock, flags);
+
+	driver->driver.bus = 0;
+	/* hook up the driver */
+	udc_controller->driver = driver;
+	udc_controller->gadget.dev.driver = &driver->driver;
+	spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+	/* bind udc driver to gadget driver */
+	retval = driver->bind(&udc_controller->gadget);
+	if (retval) {
+		VDBG("bind to %s --> %d", driver->driver.name, retval);
+		udc_controller->gadget.dev.driver = 0;
+		udc_controller->driver = 0;
+		goto out;
+	}
+
+	/* Enable DR IRQ reg and Set usbcmd reg  Run bit */
+	dr_controller_run(udc_controller);
+	udc_controller->usb_state = USB_STATE_ATTACHED;
+	udc_controller->ep0_state = WAIT_FOR_SETUP;
+	udc_controller->ep0_dir = 0;
+	printk(KERN_INFO "%s: bind to driver %s \n",
+			udc_controller->gadget.name, driver->driver.name);
+
+out:
+	if (retval)
+		printk("retval %d \n", retval);
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* Disconnect from gadget driver */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fsl_ep *loop_ep;
+	unsigned long flags;
+
+	if (!udc_controller)
+		return -ENODEV;
+
+	if (!driver || driver != udc_controller->driver || !driver->unbind)
+		return -EINVAL;
+
+#ifdef CONFIG_USB_OTG
+	if (udc_controller->transceiver)
+		(void)otg_set_peripheral(udc_controller->transceiver, 0);
+#endif
+
+	/* stop DR, disable intr */
+	dr_controller_stop(udc_controller);
+
+	/* in fact, no needed */
+	udc_controller->usb_state = USB_STATE_ATTACHED;
+	udc_controller->ep0_state = WAIT_FOR_SETUP;
+	udc_controller->ep0_dir = 0;
+
+	/* stand operation */
+	spin_lock_irqsave(&udc_controller->lock, flags);
+	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+	nuke(&udc_controller->eps[0], -ESHUTDOWN);
+	list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+			ep.ep_list)
+		nuke(loop_ep, -ESHUTDOWN);
+	spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+	/* unbind gadget and unhook driver. */
+	driver->unbind(&udc_controller->gadget);
+	udc_controller->gadget.dev.driver = 0;
+	udc_controller->driver = 0;
+
+	printk("unregistered gadget driver '%s'\r\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------
+		PROC File System Support
+-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char proc_filename[] = "driver/fsl_usb2_udc";
+
+static int fsl_proc_read(char *page, char **start, off_t off, int count,
+		int *eof, void *_dev)
+{
+	char *buf = page;
+	char *next = buf;
+	unsigned size = count;
+	unsigned long flags;
+	int t, i;
+	u32 tmp_reg;
+	struct fsl_ep *ep = NULL;
+	struct fsl_req *req;
+
+	struct fsl_udc *udc = udc_controller;
+	if (off != 0)
+		return 0;
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/* ------basic driver infomation ---- */
+	t = scnprintf(next, size,
+			DRIVER_DESC "\n"
+			"%s version: %s\n"
+			"Gadget driver: %s\n\n",
+			driver_name, DRIVER_VERSION,
+			udc->driver ? udc->driver->driver.name : "(none)");
+	size -= t;
+	next += t;
+
+	/* ------ DR Registers ----- */
+	tmp_reg = fsl_readl(&dr_regs->usbcmd);
+	t = scnprintf(next, size,
+			"USBCMD reg:\n"
+			"SetupTW: %d\n"
+			"Run/Stop: %s\n\n",
+			(tmp_reg & USB_CMD_SUTW) ? 1 : 0,
+			(tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop");
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->usbsts);
+	t = scnprintf(next, size,
+			"USB Status Reg:\n"
+			"Dr Suspend: %d" "Reset Received: %d" "System Error: %s"
+			"USB Error Interrupt: %s\n\n",
+			(tmp_reg & USB_STS_SUSPEND) ? 1 : 0,
+			(tmp_reg & USB_STS_RESET) ? 1 : 0,
+			(tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal",
+			(tmp_reg & USB_STS_ERR) ? "Err detected" : "No err");
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->usbintr);
+	t = scnprintf(next, size,
+			"USB Intrrupt Enable Reg:\n"
+			"Sleep Enable: %d" "SOF Received Enable: %d"
+			"Reset Enable: %d\n"
+			"System Error Enable: %d"
+			"Port Change Dectected Enable: %d\n"
+			"USB Error Intr Enable: %d" "USB Intr Enable: %d\n\n",
+			(tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,
+			(tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,
+			(tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,
+			(tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0,
+			(tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0,
+			(tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0,
+			(tmp_reg & USB_INTR_INT_EN) ? 1 : 0);
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->frindex);
+	t = scnprintf(next, size,
+			"USB Frame Index Reg:" "Frame Number is 0x%x\n\n",
+			(tmp_reg & USB_FRINDEX_MASKS));
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->deviceaddr);
+	t = scnprintf(next, size,
+			"USB Device Address Reg:" "Device Addr is 0x%x\n\n",
+			(tmp_reg & USB_DEVICE_ADDRESS_MASK));
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->endpointlistaddr);
+	t = scnprintf(next, size,
+			"USB Endpoint List Address Reg:"
+			"Device Addr is 0x%x\n\n",
+			(tmp_reg & USB_EP_LIST_ADDRESS_MASK));
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->portsc1);
+	t = scnprintf(next, size,
+		"USB Port Status&Control Reg:\n"
+		"Port Transceiver Type : %s" "Port Speed: %s \n"
+		"PHY Low Power Suspend: %s" "Port Reset: %s"
+		"Port Suspend Mode: %s \n" "Over-current Change: %s"
+		"Port Enable/Disable Change: %s\n"
+		"Port Enabled/Disabled: %s"
+		"Current Connect Status: %s\n\n", ( {
+			char *s;
+			switch (tmp_reg & PORTSCX_PTS_FSLS) {
+			case PORTSCX_PTS_UTMI:
+				s = "UTMI"; break;
+			case PORTSCX_PTS_ULPI:
+				s = "ULPI "; break;
+			case PORTSCX_PTS_FSLS:
+				s = "FS/LS Serial"; break;
+			default:
+				s = "None"; break;
+			}
+			s;} ), ( {
+			char *s;
+			switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
+			case PORTSCX_PORT_SPEED_FULL:
+				s = "Full Speed"; break;
+			case PORTSCX_PORT_SPEED_LOW:
+				s = "Low Speed"; break;
+			case PORTSCX_PORT_SPEED_HIGH:
+				s = "High Speed"; break;
+			default:
+				s = "Undefined"; break;
+			}
+			s;
+		} ),
+		(tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ?
+		"Normal PHY mode" : "Low power mode",
+		(tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" :
+		"Not in Reset",
+		(tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in",
+		(tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" :
+		"No",
+		(tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" :
+		"Not change",
+		(tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" :
+		"Not correct",
+		(tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ?
+		"Attached" : "Not-Att");
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->usbmode);
+	t = scnprintf(next, size,
+			"USB Mode Reg:" "Controller Mode is : %s\n\n", ( {
+				char *s;
+				switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) {
+				case USB_MODE_CTRL_MODE_IDLE:
+					s = "Idle"; break;
+				case USB_MODE_CTRL_MODE_DEVICE:
+					s = "Device Controller"; break;
+				case USB_MODE_CTRL_MODE_HOST:
+					s = "Host Controller"; break;
+				default:
+					s = "None"; break;
+				}
+				s;
+			} ));
+	size -= t;
+	next += t;
+
+	tmp_reg = fsl_readl(&dr_regs->endptsetupstat);
+	t = scnprintf(next, size,
+			"Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n",
+			(tmp_reg & EP_SETUP_STATUS_MASK));
+	size -= t;
+	next += t;
+
+	for (i = 0; i < udc->max_ep / 2; i++) {
+		tmp_reg = fsl_readl(&dr_regs->endptctrl[i]);
+		t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n",
+				i, tmp_reg);
+		size -= t;
+		next += t;
+	}
+	tmp_reg = fsl_readl(&dr_regs->endpointprime);
+	t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg);
+	size -= t;
+	next += t;
+
+	tmp_reg = usb_sys_regs->snoop1;
+	t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg);
+	size -= t;
+	next += t;
+
+	tmp_reg = usb_sys_regs->control;
+	t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
+			tmp_reg);
+	size -= t;
+	next += t;
+
+	/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
+	ep = &udc->eps[0];
+	t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n",
+			ep->ep.name, ep_maxpacket(ep), ep_index(ep));
+	size -= t;
+	next += t;
+
+	if (list_empty(&ep->queue)) {
+		t = scnprintf(next, size, "its req queue is empty\n\n");
+		size -= t;
+		next += t;
+	} else {
+		list_for_each_entry(req, &ep->queue, queue) {
+			t = scnprintf(next, size,
+				"req %p actual 0x%x length 0x%x  buf %p\n",
+				&req->req, req->req.actual,
+				req->req.length, req->req.buf);
+			size -= t;
+			next += t;
+		}
+	}
+	/* other gadget->eplist ep */
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			t = scnprintf(next, size,
+					"\nFor %s Maxpkt is 0x%x "
+					"index is 0x%x\n",
+					ep->ep.name, ep_maxpacket(ep),
+					ep_index(ep));
+			size -= t;
+			next += t;
+
+			if (list_empty(&ep->queue)) {
+				t = scnprintf(next, size,
+						"its req queue is empty\n\n");
+				size -= t;
+				next += t;
+			} else {
+				list_for_each_entry(req, &ep->queue, queue) {
+					t = scnprintf(next, size,
+						"req %p actual 0x%x length"
+						"0x%x  buf %p\n",
+						&req->req, req->req.actual,
+						req->req.length, req->req.buf);
+					size -= t;
+					next += t;
+					}	/* end for each_entry of ep req */
+				}	/* end for else */
+			}	/* end for if(ep->queue) */
+		}		/* end (ep->desc) */
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	*eof = 1;
+	return count - size;
+}
+
+#define create_proc_file()	create_proc_read_entry(proc_filename, \
+				0, NULL, fsl_proc_read, NULL)
+
+#define remove_proc_file()	remove_proc_entry(proc_filename, NULL)
+
+#else				/* !CONFIG_USB_GADGET_DEBUG_FILES */
+
+#define create_proc_file()	do {} while (0)
+#define remove_proc_file()	do {} while (0)
+
+#endif				/* CONFIG_USB_GADGET_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
+
+/* Release udc structures */
+static void fsl_udc_release(struct device *dev)
+{
+	complete(udc_controller->done);
+	dma_free_coherent(dev, udc_controller->ep_qh_size,
+			udc_controller->ep_qh, udc_controller->ep_qh_dma);
+	kfree(udc_controller);
+}
+
+/******************************************************************
+	Internal structure setup functions
+*******************************************************************/
+/*------------------------------------------------------------------
+ * init resource for globle controller
+ * Return the udc handle on success or NULL on failure
+ ------------------------------------------------------------------*/
+static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
+{
+	struct fsl_udc *udc;
+	struct fsl_usb2_platform_data *pdata;
+	size_t size;
+
+	udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
+	if (udc == NULL) {
+		ERR("malloc udc failed\n");
+		return NULL;
+	}
+
+	pdata = pdev->dev.platform_data;
+	udc->phy_mode = pdata->phy_mode;
+	/* max_ep_nr is bidirectional ep number, max_ep doubles the number */
+	udc->max_ep = pdata->max_ep_nr * 2;
+
+	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
+	if (!udc->eps) {
+		ERR("malloc fsl_ep failed\n");
+		goto cleanup;
+	}
+
+	/* initialized QHs, take care of alignment */
+	size = udc->max_ep * sizeof(struct ep_queue_head);
+	if (size < QH_ALIGNMENT)
+		size = QH_ALIGNMENT;
+	else if ((size % QH_ALIGNMENT) != 0) {
+		size += QH_ALIGNMENT + 1;
+		size &= ~(QH_ALIGNMENT - 1);
+	}
+	udc->ep_qh = dma_alloc_coherent(&pdev->dev, size,
+					&udc->ep_qh_dma, GFP_KERNEL);
+	if (!udc->ep_qh) {
+		ERR("malloc QHs for udc failed\n");
+		kfree(udc->eps);
+		goto cleanup;
+	}
+
+	udc->ep_qh_size = size;
+
+	/* Initialize ep0 status request structure */
+	/* FIXME: fsl_alloc_request() ignores ep argument */
+	udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
+			struct fsl_req, req);
+	/* allocate a small amount of memory to get valid address */
+	udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+	udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+
+	udc->resume_state = USB_STATE_NOTATTACHED;
+	udc->usb_state = USB_STATE_POWERED;
+	udc->ep0_dir = 0;
+	udc->remote_wakeup = 0;	/* default to 0 on reset */
+	spin_lock_init(&udc->lock);
+
+	return udc;
+
+cleanup:
+	kfree(udc);
+	return NULL;
+}
+
+/*----------------------------------------------------------------
+ * Setup the fsl_ep struct for eps
+ * Link fsl_ep->ep to gadget->ep_list
+ * ep0out is not used so do nothing here
+ * ep0in should be taken care
+ *--------------------------------------------------------------*/
+static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
+		char *name, int link)
+{
+	struct fsl_ep *ep = &udc->eps[index];
+
+	ep->udc = udc;
+	strcpy(ep->name, name);
+	ep->ep.name = ep->name;
+
+	ep->ep.ops = &fsl_ep_ops;
+	ep->stopped = 0;
+
+	/* for ep0: maxP defined in desc
+	 * for other eps, maxP is set by epautoconfig() called by gadget layer
+	 */
+	ep->ep.maxpacket = (unsigned short) ~0;
+
+	/* the queue lists any req for this ep */
+	INIT_LIST_HEAD(&ep->queue);
+
+	/* gagdet.ep_list used for ep_autoconfig so no ep0 */
+	if (link)
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	ep->gadget = &udc->gadget;
+	ep->qh = &udc->ep_qh[index];
+
+	return 0;
+}
+
+/* Driver probe function
+ * all intialize operations implemented here except enabling usb_intr reg
+ */
+static int __init fsl_udc_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret = -ENODEV;
+	unsigned int i;
+
+	if (strcmp(pdev->name, driver_name)) {
+		VDBG("Wrong device\n");
+		return -ENODEV;
+	}
+
+	/* board setup should have been done in the platform code */
+
+	/* Initialize the udc structure including QH member and other member */
+	udc_controller = struct_udc_setup(pdev);
+	if (!udc_controller) {
+		VDBG("udc_controller is NULL \n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				driver_name)) {
+		ERR("request mem region for %s failed \n", pdev->name);
+		return -EBUSY;
+	}
+
+	dr_regs = ioremap(res->start, res->end - res->start + 1);
+	if (!dr_regs) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	usb_sys_regs = (struct usb_sys_interface *)
+			((u32)dr_regs + USB_DR_SYS_OFFSET);
+
+	udc_controller->irq = platform_get_irq(pdev, 0);
+	if (!udc_controller->irq) {
+		ret = -ENODEV;
+		goto err2;
+	}
+
+	ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ,
+			driver_name, udc_controller);
+	if (ret != 0) {
+		ERR("cannot request irq %d err %d \n",
+				udc_controller->irq, ret);
+		goto err2;
+	}
+
+	/* initialize usb hw reg except for regs for EP,
+	 * leave usbintr reg untouched */
+	dr_controller_setup(udc_controller);
+
+	/* Setup gadget structure */
+	udc_controller->gadget.ops = &fsl_gadget_ops;
+	udc_controller->gadget.is_dualspeed = 1;
+	udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+	INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+	udc_controller->gadget.name = driver_name;
+
+	/* Setup gadget.dev and register with kernel */
+	strcpy(udc_controller->gadget.dev.bus_id, "gadget");
+	udc_controller->gadget.dev.release = fsl_udc_release;
+	udc_controller->gadget.dev.parent = &pdev->dev;
+	ret = device_register(&udc_controller->gadget.dev);
+	if (ret < 0)
+		goto err3;
+
+	/* setup QH and epctrl for ep0 */
+	ep0_setup(udc_controller);
+
+	/* setup udc->eps[] for ep0 */
+	struct_ep_setup(udc_controller, 0, "ep0", 0);
+	/* for ep0: the desc defined here;
+	 * for other eps, gadget layer called ep_enable with defined desc
+	 */
+	udc_controller->eps[0].desc = &fsl_ep0_desc;
+	udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+
+	/* setup the udc->eps[] for non-control endpoints and link
+	 * to gadget.ep_list */
+	for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) {
+		char name[14];
+
+		sprintf(name, "ep%dout", i);
+		struct_ep_setup(udc_controller, i * 2, name, 1);
+		sprintf(name, "ep%din", i);
+		struct_ep_setup(udc_controller, i * 2 + 1, name, 1);
+	}
+
+	/* use dma_pool for TD management */
+	udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev,
+			sizeof(struct ep_td_struct),
+			DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
+	if (udc_controller->td_pool == NULL) {
+		ret = -ENOMEM;
+		goto err4;
+	}
+	create_proc_file();
+	return 0;
+
+err4:
+	device_unregister(&udc_controller->gadget.dev);
+err3:
+	free_irq(udc_controller->irq, udc_controller);
+err2:
+	iounmap(dr_regs);
+err1:
+	release_mem_region(res->start, res->end - res->start + 1);
+	return ret;
+}
+
+/* Driver removal function
+ * Free resources and finish pending transactions
+ */
+static int __exit fsl_udc_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	DECLARE_COMPLETION(done);
+
+	if (!udc_controller)
+		return -ENODEV;
+	udc_controller->done = &done;
+
+	/* DR has been stopped in usb_gadget_unregister_driver() */
+	remove_proc_file();
+
+	/* Free allocated memory */
+	kfree(udc_controller->status_req->req.buf);
+	kfree(udc_controller->status_req);
+	kfree(udc_controller->eps);
+
+	dma_pool_destroy(udc_controller->td_pool);
+	free_irq(udc_controller->irq, udc_controller);
+	iounmap(dr_regs);
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	device_unregister(&udc_controller->gadget.dev);
+	/* free udc --wait for the release() finished */
+	wait_for_completion(&done);
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Modify Power management attributes
+ * Used by OTG statemachine to disable gadget temporarily
+ -----------------------------------------------------------------*/
+static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	dr_controller_stop(udc_controller);
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Invoked on USB resume. May be called in_interrupt.
+ * Here we start the DR controller and enable the irq
+ *-----------------------------------------------------------------*/
+static int fsl_udc_resume(struct platform_device *pdev)
+{
+	/* Enable DR irq reg and set controller Run */
+	if (udc_controller->stopped) {
+		dr_controller_setup(udc_controller);
+		dr_controller_run(udc_controller);
+	}
+	udc_controller->usb_state = USB_STATE_ATTACHED;
+	udc_controller->ep0_state = WAIT_FOR_SETUP;
+	udc_controller->ep0_dir = 0;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+	Register entry point for the peripheral controller driver
+--------------------------------------------------------------------------*/
+
+static struct platform_driver udc_driver = {
+	.remove  = __exit_p(fsl_udc_remove),
+	/* these suspend and resume are not usb suspend and resume */
+	.suspend = fsl_udc_suspend,
+	.resume  = fsl_udc_resume,
+	.driver  = {
+		.name = (char *)driver_name,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init udc_init(void)
+{
+	printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
+	return platform_driver_probe(&udc_driver, fsl_udc_probe);
+}
+
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver);
+	printk("%s unregistered \n", driver_desc);
+}
+
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
new file mode 100644
index 0000000..c6291e0
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -0,0 +1,579 @@
+/*
+ * Freescale USB device/endpoint management registers
+ */
+#ifndef __FSL_USB2_UDC_H
+#define __FSL_USB2_UDC_H
+
+/* ### define USB registers here
+ */
+#define USB_MAX_CTRL_PAYLOAD		64
+#define USB_DR_SYS_OFFSET		0x400
+
+ /* USB DR device mode registers (Little Endian) */
+struct usb_dr_device {
+	/* Capability register */
+	u8 res1[256];
+	u16 caplength;		/* Capability Register Length */
+	u16 hciversion;		/* Host Controller Interface Version */
+	u32 hcsparams;		/* Host Controller Structual Parameters */
+	u32 hccparams;		/* Host Controller Capability Parameters */
+	u8 res2[20];
+	u32 dciversion;		/* Device Controller Interface Version */
+	u32 dccparams;		/* Device Controller Capability Parameters */
+	u8 res3[24];
+	/* Operation register */
+	u32 usbcmd;		/* USB Command Register */
+	u32 usbsts;		/* USB Status Register */
+	u32 usbintr;		/* USB Interrupt Enable Register */
+	u32 frindex;		/* Frame Index Register */
+	u8 res4[4];
+	u32 deviceaddr;		/* Device Address */
+	u32 endpointlistaddr;	/* Endpoint List Address Register */
+	u8 res5[4];
+	u32 burstsize;		/* Master Interface Data Burst Size Register */
+	u32 txttfilltuning;	/* Transmit FIFO Tuning Controls Register */
+	u8 res6[24];
+	u32 configflag;		/* Configure Flag Register */
+	u32 portsc1;		/* Port 1 Status and Control Register */
+	u8 res7[28];
+	u32 otgsc;		/* On-The-Go Status and Control */
+	u32 usbmode;		/* USB Mode Register */
+	u32 endptsetupstat;	/* Endpoint Setup Status Register */
+	u32 endpointprime;	/* Endpoint Initialization Register */
+	u32 endptflush;		/* Endpoint Flush Register */
+	u32 endptstatus;	/* Endpoint Status Register */
+	u32 endptcomplete;	/* Endpoint Complete Register */
+	u32 endptctrl[6];	/* Endpoint Control Registers */
+};
+
+ /* USB DR host mode registers (Little Endian) */
+struct usb_dr_host {
+	/* Capability register */
+	u8 res1[256];
+	u16 caplength;		/* Capability Register Length */
+	u16 hciversion;		/* Host Controller Interface Version */
+	u32 hcsparams;		/* Host Controller Structual Parameters */
+	u32 hccparams;		/* Host Controller Capability Parameters */
+	u8 res2[20];
+	u32 dciversion;		/* Device Controller Interface Version */
+	u32 dccparams;		/* Device Controller Capability Parameters */
+	u8 res3[24];
+	/* Operation register */
+	u32 usbcmd;		/* USB Command Register */
+	u32 usbsts;		/* USB Status Register */
+	u32 usbintr;		/* USB Interrupt Enable Register */
+	u32 frindex;		/* Frame Index Register */
+	u8 res4[4];
+	u32 periodiclistbase;	/* Periodic Frame List Base Address Register */
+	u32 asynclistaddr;	/* Current Asynchronous List Address Register */
+	u8 res5[4];
+	u32 burstsize;		/* Master Interface Data Burst Size Register */
+	u32 txttfilltuning;	/* Transmit FIFO Tuning Controls Register */
+	u8 res6[24];
+	u32 configflag;		/* Configure Flag Register */
+	u32 portsc1;		/* Port 1 Status and Control Register */
+	u8 res7[28];
+	u32 otgsc;		/* On-The-Go Status and Control */
+	u32 usbmode;		/* USB Mode Register */
+	u32 endptsetupstat;	/* Endpoint Setup Status Register */
+	u32 endpointprime;	/* Endpoint Initialization Register */
+	u32 endptflush;		/* Endpoint Flush Register */
+	u32 endptstatus;	/* Endpoint Status Register */
+	u32 endptcomplete;	/* Endpoint Complete Register */
+	u32 endptctrl[6];	/* Endpoint Control Registers */
+};
+
+ /* non-EHCI USB system interface registers (Big Endian) */
+struct usb_sys_interface {
+	u32 snoop1;
+	u32 snoop2;
+	u32 age_cnt_thresh;	/* Age Count Threshold Register */
+	u32 pri_ctrl;		/* Priority Control Register */
+	u32 si_ctrl;		/* System Interface Control Register */
+	u8 res[236];
+	u32 control;		/* General Purpose Control Register */
+};
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP          0
+#define DATA_STATE_XMIT         1
+#define DATA_STATE_NEED_ZLP     2
+#define WAIT_FOR_OUT_STATUS     3
+#define DATA_STATE_RECV         4
+
+/* Frame Index Register Bit Masks */
+#define	USB_FRINDEX_MASKS			0x3fff
+/* USB CMD  Register Bit Masks */
+#define  USB_CMD_RUN_STOP                     0x00000001
+#define  USB_CMD_CTRL_RESET                   0x00000002
+#define  USB_CMD_PERIODIC_SCHEDULE_EN         0x00000010
+#define  USB_CMD_ASYNC_SCHEDULE_EN            0x00000020
+#define  USB_CMD_INT_AA_DOORBELL              0x00000040
+#define  USB_CMD_ASP                          0x00000300
+#define  USB_CMD_ASYNC_SCH_PARK_EN            0x00000800
+#define  USB_CMD_SUTW                         0x00002000
+#define  USB_CMD_ATDTW                        0x00004000
+#define  USB_CMD_ITC                          0x00FF0000
+
+/* bit 15,3,2 are frame list size */
+#define  USB_CMD_FRAME_SIZE_1024              0x00000000
+#define  USB_CMD_FRAME_SIZE_512               0x00000004
+#define  USB_CMD_FRAME_SIZE_256               0x00000008
+#define  USB_CMD_FRAME_SIZE_128               0x0000000C
+#define  USB_CMD_FRAME_SIZE_64                0x00008000
+#define  USB_CMD_FRAME_SIZE_32                0x00008004
+#define  USB_CMD_FRAME_SIZE_16                0x00008008
+#define  USB_CMD_FRAME_SIZE_8                 0x0000800C
+
+/* bit 9-8 are async schedule park mode count */
+#define  USB_CMD_ASP_00                       0x00000000
+#define  USB_CMD_ASP_01                       0x00000100
+#define  USB_CMD_ASP_10                       0x00000200
+#define  USB_CMD_ASP_11                       0x00000300
+#define  USB_CMD_ASP_BIT_POS                  8
+
+/* bit 23-16 are interrupt threshold control */
+#define  USB_CMD_ITC_NO_THRESHOLD             0x00000000
+#define  USB_CMD_ITC_1_MICRO_FRM              0x00010000
+#define  USB_CMD_ITC_2_MICRO_FRM              0x00020000
+#define  USB_CMD_ITC_4_MICRO_FRM              0x00040000
+#define  USB_CMD_ITC_8_MICRO_FRM              0x00080000
+#define  USB_CMD_ITC_16_MICRO_FRM             0x00100000
+#define  USB_CMD_ITC_32_MICRO_FRM             0x00200000
+#define  USB_CMD_ITC_64_MICRO_FRM             0x00400000
+#define  USB_CMD_ITC_BIT_POS                  16
+
+/* USB STS Register Bit Masks */
+#define  USB_STS_INT                          0x00000001
+#define  USB_STS_ERR                          0x00000002
+#define  USB_STS_PORT_CHANGE                  0x00000004
+#define  USB_STS_FRM_LST_ROLL                 0x00000008
+#define  USB_STS_SYS_ERR                      0x00000010
+#define  USB_STS_IAA                          0x00000020
+#define  USB_STS_RESET                        0x00000040
+#define  USB_STS_SOF                          0x00000080
+#define  USB_STS_SUSPEND                      0x00000100
+#define  USB_STS_HC_HALTED                    0x00001000
+#define  USB_STS_RCL                          0x00002000
+#define  USB_STS_PERIODIC_SCHEDULE            0x00004000
+#define  USB_STS_ASYNC_SCHEDULE               0x00008000
+
+/* USB INTR Register Bit Masks */
+#define  USB_INTR_INT_EN                      0x00000001
+#define  USB_INTR_ERR_INT_EN                  0x00000002
+#define  USB_INTR_PTC_DETECT_EN               0x00000004
+#define  USB_INTR_FRM_LST_ROLL_EN             0x00000008
+#define  USB_INTR_SYS_ERR_EN                  0x00000010
+#define  USB_INTR_ASYN_ADV_EN                 0x00000020
+#define  USB_INTR_RESET_EN                    0x00000040
+#define  USB_INTR_SOF_EN                      0x00000080
+#define  USB_INTR_DEVICE_SUSPEND              0x00000100
+
+/* Device Address bit masks */
+#define  USB_DEVICE_ADDRESS_MASK              0xFE000000
+#define  USB_DEVICE_ADDRESS_BIT_POS           25
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK              0xfffff800
+
+/* PORTSCX  Register Bit Masks */
+#define  PORTSCX_CURRENT_CONNECT_STATUS       0x00000001
+#define  PORTSCX_CONNECT_STATUS_CHANGE        0x00000002
+#define  PORTSCX_PORT_ENABLE                  0x00000004
+#define  PORTSCX_PORT_EN_DIS_CHANGE           0x00000008
+#define  PORTSCX_OVER_CURRENT_ACT             0x00000010
+#define  PORTSCX_OVER_CURRENT_CHG             0x00000020
+#define  PORTSCX_PORT_FORCE_RESUME            0x00000040
+#define  PORTSCX_PORT_SUSPEND                 0x00000080
+#define  PORTSCX_PORT_RESET                   0x00000100
+#define  PORTSCX_LINE_STATUS_BITS             0x00000C00
+#define  PORTSCX_PORT_POWER                   0x00001000
+#define  PORTSCX_PORT_INDICTOR_CTRL           0x0000C000
+#define  PORTSCX_PORT_TEST_CTRL               0x000F0000
+#define  PORTSCX_WAKE_ON_CONNECT_EN           0x00100000
+#define  PORTSCX_WAKE_ON_CONNECT_DIS          0x00200000
+#define  PORTSCX_WAKE_ON_OVER_CURRENT         0x00400000
+#define  PORTSCX_PHY_LOW_POWER_SPD            0x00800000
+#define  PORTSCX_PORT_FORCE_FULL_SPEED        0x01000000
+#define  PORTSCX_PORT_SPEED_MASK              0x0C000000
+#define  PORTSCX_PORT_WIDTH                   0x10000000
+#define  PORTSCX_PHY_TYPE_SEL                 0xC0000000
+
+/* bit 11-10 are line status */
+#define  PORTSCX_LINE_STATUS_SE0              0x00000000
+#define  PORTSCX_LINE_STATUS_JSTATE           0x00000400
+#define  PORTSCX_LINE_STATUS_KSTATE           0x00000800
+#define  PORTSCX_LINE_STATUS_UNDEF            0x00000C00
+#define  PORTSCX_LINE_STATUS_BIT_POS          10
+
+/* bit 15-14 are port indicator control */
+#define  PORTSCX_PIC_OFF                      0x00000000
+#define  PORTSCX_PIC_AMBER                    0x00004000
+#define  PORTSCX_PIC_GREEN                    0x00008000
+#define  PORTSCX_PIC_UNDEF                    0x0000C000
+#define  PORTSCX_PIC_BIT_POS                  14
+
+/* bit 19-16 are port test control */
+#define  PORTSCX_PTC_DISABLE                  0x00000000
+#define  PORTSCX_PTC_JSTATE                   0x00010000
+#define  PORTSCX_PTC_KSTATE                   0x00020000
+#define  PORTSCX_PTC_SEQNAK                   0x00030000
+#define  PORTSCX_PTC_PACKET                   0x00040000
+#define  PORTSCX_PTC_FORCE_EN                 0x00050000
+#define  PORTSCX_PTC_BIT_POS                  16
+
+/* bit 27-26 are port speed */
+#define  PORTSCX_PORT_SPEED_FULL              0x00000000
+#define  PORTSCX_PORT_SPEED_LOW               0x04000000
+#define  PORTSCX_PORT_SPEED_HIGH              0x08000000
+#define  PORTSCX_PORT_SPEED_UNDEF             0x0C000000
+#define  PORTSCX_SPEED_BIT_POS                26
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define  PORTSCX_PTW                          0x10000000
+#define  PORTSCX_PTW_8BIT                     0x00000000
+#define  PORTSCX_PTW_16BIT                    0x10000000
+
+/* bit 31-30 are port transceiver select */
+#define  PORTSCX_PTS_UTMI                     0x00000000
+#define  PORTSCX_PTS_ULPI                     0x80000000
+#define  PORTSCX_PTS_FSLS                     0xC0000000
+#define  PORTSCX_PTS_BIT_POS                  30
+
+/* otgsc Register Bit Masks */
+#define  OTGSC_CTRL_VUSB_DISCHARGE            0x00000001
+#define  OTGSC_CTRL_VUSB_CHARGE               0x00000002
+#define  OTGSC_CTRL_OTG_TERM                  0x00000008
+#define  OTGSC_CTRL_DATA_PULSING              0x00000010
+#define  OTGSC_STS_USB_ID                     0x00000100
+#define  OTGSC_STS_A_VBUS_VALID               0x00000200
+#define  OTGSC_STS_A_SESSION_VALID            0x00000400
+#define  OTGSC_STS_B_SESSION_VALID            0x00000800
+#define  OTGSC_STS_B_SESSION_END              0x00001000
+#define  OTGSC_STS_1MS_TOGGLE                 0x00002000
+#define  OTGSC_STS_DATA_PULSING               0x00004000
+#define  OTGSC_INTSTS_USB_ID                  0x00010000
+#define  OTGSC_INTSTS_A_VBUS_VALID            0x00020000
+#define  OTGSC_INTSTS_A_SESSION_VALID         0x00040000
+#define  OTGSC_INTSTS_B_SESSION_VALID         0x00080000
+#define  OTGSC_INTSTS_B_SESSION_END           0x00100000
+#define  OTGSC_INTSTS_1MS                     0x00200000
+#define  OTGSC_INTSTS_DATA_PULSING            0x00400000
+#define  OTGSC_INTR_USB_ID                    0x01000000
+#define  OTGSC_INTR_A_VBUS_VALID              0x02000000
+#define  OTGSC_INTR_A_SESSION_VALID           0x04000000
+#define  OTGSC_INTR_B_SESSION_VALID           0x08000000
+#define  OTGSC_INTR_B_SESSION_END             0x10000000
+#define  OTGSC_INTR_1MS_TIMER                 0x20000000
+#define  OTGSC_INTR_DATA_PULSING              0x40000000
+
+/* USB MODE Register Bit Masks */
+#define  USB_MODE_CTRL_MODE_IDLE              0x00000000
+#define  USB_MODE_CTRL_MODE_DEVICE            0x00000002
+#define  USB_MODE_CTRL_MODE_HOST              0x00000003
+#define  USB_MODE_CTRL_MODE_RSV               0x00000001
+#define  USB_MODE_SETUP_LOCK_OFF              0x00000008
+#define  USB_MODE_STREAM_DISABLE              0x00000010
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET		      0x00010000
+#define EPFLUSH_RX_OFFSET		      0x00000000
+
+/* Endpoint Setup Status bit masks */
+#define  EP_SETUP_STATUS_MASK                 0x0000003F
+#define  EP_SETUP_STATUS_EP0		      0x00000001
+
+/* ENDPOINTCTRLx  Register Bit Masks */
+#define  EPCTRL_TX_ENABLE                     0x00800000
+#define  EPCTRL_TX_DATA_TOGGLE_RST            0x00400000	/* Not EP0 */
+#define  EPCTRL_TX_DATA_TOGGLE_INH            0x00200000	/* Not EP0 */
+#define  EPCTRL_TX_TYPE                       0x000C0000
+#define  EPCTRL_TX_DATA_SOURCE                0x00020000	/* Not EP0 */
+#define  EPCTRL_TX_EP_STALL                   0x00010000
+#define  EPCTRL_RX_ENABLE                     0x00000080
+#define  EPCTRL_RX_DATA_TOGGLE_RST            0x00000040	/* Not EP0 */
+#define  EPCTRL_RX_DATA_TOGGLE_INH            0x00000020	/* Not EP0 */
+#define  EPCTRL_RX_TYPE                       0x0000000C
+#define  EPCTRL_RX_DATA_SINK                  0x00000002	/* Not EP0 */
+#define  EPCTRL_RX_EP_STALL                   0x00000001
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define  EPCTRL_EP_TYPE_CONTROL               0
+#define  EPCTRL_EP_TYPE_ISO                   1
+#define  EPCTRL_EP_TYPE_BULK                  2
+#define  EPCTRL_EP_TYPE_INTERRUPT             3
+#define  EPCTRL_TX_EP_TYPE_SHIFT              18
+#define  EPCTRL_RX_EP_TYPE_SHIFT              2
+
+/* SNOOPn Register Bit Masks */
+#define  SNOOP_ADDRESS_MASK                   0xFFFFF000
+#define  SNOOP_SIZE_ZERO                      0x00	/* snooping disable */
+#define  SNOOP_SIZE_4KB                       0x0B	/* 4KB snoop size */
+#define  SNOOP_SIZE_8KB                       0x0C
+#define  SNOOP_SIZE_16KB                      0x0D
+#define  SNOOP_SIZE_32KB                      0x0E
+#define  SNOOP_SIZE_64KB                      0x0F
+#define  SNOOP_SIZE_128KB                     0x10
+#define  SNOOP_SIZE_256KB                     0x11
+#define  SNOOP_SIZE_512KB                     0x12
+#define  SNOOP_SIZE_1MB                       0x13
+#define  SNOOP_SIZE_2MB                       0x14
+#define  SNOOP_SIZE_4MB                       0x15
+#define  SNOOP_SIZE_8MB                       0x16
+#define  SNOOP_SIZE_16MB                      0x17
+#define  SNOOP_SIZE_32MB                      0x18
+#define  SNOOP_SIZE_64MB                      0x19
+#define  SNOOP_SIZE_128MB                     0x1A
+#define  SNOOP_SIZE_256MB                     0x1B
+#define  SNOOP_SIZE_512MB                     0x1C
+#define  SNOOP_SIZE_1GB                       0x1D
+#define  SNOOP_SIZE_2GB                       0x1E	/* 2GB snoop size */
+
+/* pri_ctrl Register Bit Masks */
+#define  PRI_CTRL_PRI_LVL1                    0x0000000C
+#define  PRI_CTRL_PRI_LVL0                    0x00000003
+
+/* si_ctrl Register Bit Masks */
+#define  SI_CTRL_ERR_DISABLE                  0x00000010
+#define  SI_CTRL_IDRC_DISABLE                 0x00000008
+#define  SI_CTRL_RD_SAFE_EN                   0x00000004
+#define  SI_CTRL_RD_PREFETCH_DISABLE          0x00000002
+#define  SI_CTRL_RD_PREFEFETCH_VAL            0x00000001
+
+/* control Register Bit Masks */
+#define  USB_CTRL_IOENB                       0x00000004
+#define  USB_CTRL_ULPI_INT0EN                 0x00000001
+
+/* Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+	u32 max_pkt_length;	/* Mult(31-30) , Zlt(29) , Max Pkt len
+				   and IOS(15) */
+	u32 curr_dtd_ptr;	/* Current dTD Pointer(31-5) */
+	u32 next_dtd_ptr;	/* Next dTD Pointer(31-5), T(0) */
+	u32 size_ioc_int_sts;	/* Total bytes (30-16), IOC (15),
+				   MultO(11-10), STS (7-0)  */
+	u32 buff_ptr0;		/* Buffer pointer Page 0 (31-12) */
+	u32 buff_ptr1;		/* Buffer pointer Page 1 (31-12) */
+	u32 buff_ptr2;		/* Buffer pointer Page 2 (31-12) */
+	u32 buff_ptr3;		/* Buffer pointer Page 3 (31-12) */
+	u32 buff_ptr4;		/* Buffer pointer Page 4 (31-12) */
+	u32 res1;
+	u8 setup_buffer[8];	/* Setup data 8 bytes */
+	u32 res2[4];
+};
+
+/* Endpoint Queue Head Bit Masks */
+#define  EP_QUEUE_HEAD_MULT_POS               30
+#define  EP_QUEUE_HEAD_ZLT_SEL                0x20000000
+#define  EP_QUEUE_HEAD_MAX_PKT_LEN_POS        16
+#define  EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info)   (((ep_info)>>16)&0x07ff)
+#define  EP_QUEUE_HEAD_IOS                    0x00008000
+#define  EP_QUEUE_HEAD_NEXT_TERMINATE         0x00000001
+#define  EP_QUEUE_HEAD_IOC                    0x00008000
+#define  EP_QUEUE_HEAD_MULTO                  0x00000C00
+#define  EP_QUEUE_HEAD_STATUS_HALT	      0x00000040
+#define  EP_QUEUE_HEAD_STATUS_ACTIVE          0x00000080
+#define  EP_QUEUE_CURRENT_OFFSET_MASK         0x00000FFF
+#define  EP_QUEUE_HEAD_NEXT_POINTER_MASK      0xFFFFFFE0
+#define  EP_QUEUE_FRINDEX_MASK                0x000007FF
+#define  EP_MAX_LENGTH_TRANSFER               0x4000
+
+/* Endpoint Transfer Descriptor data struct */
+/* Rem: all the variables of td are LittleEndian Mode */
+struct ep_td_struct {
+	u32 next_td_ptr;	/* Next TD pointer(31-5), T(0) set
+				   indicate invalid */
+	u32 size_ioc_sts;	/* Total bytes (30-16), IOC (15),
+				   MultO(11-10), STS (7-0)  */
+	u32 buff_ptr0;		/* Buffer pointer Page 0 */
+	u32 buff_ptr1;		/* Buffer pointer Page 1 */
+	u32 buff_ptr2;		/* Buffer pointer Page 2 */
+	u32 buff_ptr3;		/* Buffer pointer Page 3 */
+	u32 buff_ptr4;		/* Buffer pointer Page 4 */
+	u32 res;
+	/* 32 bytes */
+	dma_addr_t td_dma;	/* dma address for this td */
+	/* virtual address of next td specified in next_td_ptr */
+	struct ep_td_struct *next_td_virt;
+};
+
+/* Endpoint Transfer Descriptor bit Masks */
+#define  DTD_NEXT_TERMINATE                   0x00000001
+#define  DTD_IOC                              0x00008000
+#define  DTD_STATUS_ACTIVE                    0x00000080
+#define  DTD_STATUS_HALTED                    0x00000040
+#define  DTD_STATUS_DATA_BUFF_ERR             0x00000020
+#define  DTD_STATUS_TRANSACTION_ERR           0x00000008
+#define  DTD_RESERVED_FIELDS                  0x80007300
+#define  DTD_ADDR_MASK                        0xFFFFFFE0
+#define  DTD_PACKET_SIZE                      0x7FFF0000
+#define  DTD_LENGTH_BIT_POS                   16
+#define  DTD_ERROR_MASK                       (DTD_STATUS_HALTED | \
+                                               DTD_STATUS_DATA_BUFF_ERR | \
+                                               DTD_STATUS_TRANSACTION_ERR)
+/* Alignment requirements; must be a power of two */
+#define DTD_ALIGNMENT				0x20
+#define QH_ALIGNMENT				2048
+
+/* Controller dma boundary */
+#define UDC_DMA_BOUNDARY			0x1000
+
+/* -----------------------------------------------------------------------*/
+/* ##### enum data
+*/
+typedef enum {
+	e_ULPI,
+	e_UTMI_8BIT,
+	e_UTMI_16BIT,
+	e_SERIAL
+} e_PhyInterface;
+
+/*-------------------------------------------------------------------------*/
+
+/* ### driver private data
+ */
+struct fsl_req {
+	struct usb_request req;
+	struct list_head queue;
+	/* ep_queue() func will add
+	   a request->queue into a udc_ep->queue 'd tail */
+	struct fsl_ep *ep;
+	unsigned mapped:1;
+
+	struct ep_td_struct *head, *tail;	/* For dTD List
+						   cpu endian Virtual addr */
+	unsigned int dtd_count;
+};
+
+#define REQ_UNCOMPLETE			1
+
+struct fsl_ep {
+	struct usb_ep ep;
+	struct list_head queue;
+	struct fsl_udc *udc;
+	struct ep_queue_head *qh;
+	const struct usb_endpoint_descriptor *desc;
+	struct usb_gadget *gadget;
+
+	char name[14];
+	unsigned stopped:1;
+};
+
+#define EP_DIR_IN	1
+#define EP_DIR_OUT	0
+
+struct fsl_udc {
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct fsl_ep *eps;
+	unsigned int max_ep;
+	unsigned int irq;
+
+	struct usb_ctrlrequest local_setup_buff;
+	spinlock_t lock;
+	struct otg_transceiver *transceiver;
+	unsigned softconnect:1;
+	unsigned vbus_active:1;
+	unsigned stopped:1;
+	unsigned remote_wakeup:1;
+
+	struct ep_queue_head *ep_qh;	/* Endpoints Queue-Head */
+	struct fsl_req *status_req;	/* ep0 status request */
+	struct dma_pool *td_pool;	/* dma pool for DTD */
+	enum fsl_usb2_phy_modes phy_mode;
+
+	size_t ep_qh_size;		/* size after alignment adjustment*/
+	dma_addr_t ep_qh_dma;		/* dma address of QH */
+
+	u32 max_pipes;		/* Device max pipes */
+	u32 max_use_endpts;	/* Max endpointes to be used */
+	u32 bus_reset;		/* Device is bus reseting */
+	u32 resume_state;	/* USB state to resume */
+	u32 usb_state;		/* USB current state */
+	u32 usb_next_state;	/* USB next state */
+	u32 ep0_state;		/* Endpoint zero state */
+	u32 ep0_dir;		/* Endpoint zero direction: can be
+				   USB_DIR_IN or USB_DIR_OUT */
+	u32 usb_sof_count;	/* SOF count */
+	u32 errors;		/* USB ERRORs count */
+	u8 device_address;	/* Device USB address */
+
+	struct completion *done;	/* to make sure release() is done */
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(fmt, args...) 	printk(KERN_DEBUG "[%s]  " fmt "\n", \
+				__FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)	do{}while(0)
+#endif
+
+#if 0
+static void dump_msg(const char *label, const u8 * buf, unsigned int length)
+{
+	unsigned int start, num, i;
+	char line[52], *p;
+
+	if (length >= 512)
+		return;
+	DBG("%s, length %u:\n", label, length);
+	start = 0;
+	while (length > 0) {
+		num = min(length, 16u);
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			sprintf(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		printk(KERN_DEBUG "%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+#endif
+
+#ifdef VERBOSE
+#define VDBG		DBG
+#else
+#define VDBG(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
+
+/*-------------------------------------------------------------------------*/
+
+/* ### Add board specific defines here
+ */
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV	0	/* OUT EP */
+#define USB_SEND	1	/* IN EP */
+
+/*
+ * ### internal used help routines.
+ */
+#define ep_index(EP)		((EP)->desc->bEndpointAddress&0xF)
+#define ep_maxpacket(EP)	((EP)->ep.maxpacket)
+#define ep_is_in(EP)	( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+			USB_DIR_IN ):((EP)->desc->bEndpointAddress \
+			& USB_DIR_IN)==USB_DIR_IN)
+#define get_ep_by_pipe(udc, pipe)	((pipe == 1)? &udc->eps[0]: \
+					&udc->eps[pipe])
+#define get_pipe_by_windex(windex)	((windex & USB_ENDPOINT_NUMBER_MASK) \
+					* 2 + ((windex & USB_DIR_IN) ? 1 : 0))
+#define get_pipe_by_ep(EP)	(ep_index(EP) * 2 + ep_is_in(EP))
+
+#endif
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 2e3d662..d041b91 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -99,6 +99,12 @@ #else
 #define gadget_is_imx(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define gadget_is_fsl_usb2(g)	!strcmp("fsl-usb2-udc", (g)->name)
+#else
+#define gadget_is_fsl_usb2(g)	0
+#endif
+
 /* Mentor high speed function controller */
 #ifdef CONFIG_USB_GADGET_MUSBHSFC
 #define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
@@ -177,5 +183,7 @@ static inline int usb_gadget_controller_
 		return 0x17;
 	else if (gadget_is_husb2dev(gadget))
 		return 0x18;
+	else if (gadget_is_fsl_usb2(gadget))
+		return 0x19;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 65c91d3..ae931af 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -30,7 +30,6 @@ #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 49d7377..52779c5 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -54,7 +54,6 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index f01890d..84392e8 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -71,7 +71,7 @@ #include <asm/arch/udc.h>
  * by the host to interact with this device, and allocates endpoints to
  * the different protocol interfaces.  The controller driver virtualizes
  * usb hardware so that the gadget drivers will be more portable.
- * 
+ *
  * This UDC hardware wants to implement a bit too much USB protocol, so
  * it constrains the sorts of USB configuration change events that work.
  * The errata for these chips are misleading; some "fixed" bugs from
@@ -141,7 +141,7 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc
 #endif
 
 /* ---------------------------------------------------------------------------
- * 	endpoint related parts of the api to the usb controller hardware,
+ *	endpoint related parts of the api to the usb controller hardware,
  *	used by gadget driver; and the inner talker-to-hardware core.
  * ---------------------------------------------------------------------------
  */
@@ -293,7 +293,7 @@ static int pxa2xx_ep_enable (struct usb_
 
 #ifdef	USE_DMA
 	/* for (some) bulk and ISO endpoints, try to get a DMA channel and
-	 * bind it to the endpoint.  otherwise use PIO. 
+	 * bind it to the endpoint.  otherwise use PIO.
 	 */
 	switch (ep->bmAttributes) {
 	case USB_ENDPOINT_XFER_ISOC:
@@ -304,7 +304,7 @@ #ifdef	USE_DMA
 		if (!use_dma || !ep->reg_drcmr)
 			break;
 		ep->dma = pxa_request_dma ((char *)_ep->name,
- 				(le16_to_cpu (desc->wMaxPacketSize) > 64)
+				(le16_to_cpu (desc->wMaxPacketSize) > 64)
 					? DMA_PRIO_MEDIUM /* some iso */
 					: DMA_PRIO_LOW,
 				dma_nodesc_handler, ep);
@@ -361,7 +361,7 @@ #endif
  */
 
 /*
- * 	pxa2xx_ep_alloc_request - allocate a request data structure
+ *	pxa2xx_ep_alloc_request - allocate a request data structure
  */
 static struct usb_request *
 pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
@@ -378,7 +378,7 @@ pxa2xx_ep_alloc_request (struct usb_ep *
 
 
 /*
- * 	pxa2xx_ep_free_request - deallocate a request data structure
+ *	pxa2xx_ep_free_request - deallocate a request data structure
  */
 static void
 pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
@@ -1031,7 +1031,7 @@ #endif
 
 
 /*
- * 	nuke - dequeue ALL requests
+ *	nuke - dequeue ALL requests
  */
 static void nuke(struct pxa2xx_ep *ep, int status)
 {
@@ -1136,16 +1136,16 @@ static int pxa2xx_ep_set_halt(struct usb
 		ep->dev->req_pending = 0;
 		ep->dev->ep0state = EP0_STALL;
 
- 	/* and bulk/intr endpoints like dropping stalls too */
- 	} else {
- 		unsigned i;
- 		for (i = 0; i < 1000; i += 20) {
- 			if (*ep->reg_udccs & UDCCS_BI_SST)
- 				break;
- 			udelay(20);
- 		}
-  	}
- 	local_irq_restore(flags);
+	/* and bulk/intr endpoints like dropping stalls too */
+	} else {
+		unsigned i;
+		for (i = 0; i < 1000; i += 20) {
+			if (*ep->reg_udccs & UDCCS_BI_SST)
+				break;
+			udelay(20);
+		}
+	}
+	local_irq_restore(flags);
 
 	DBG(DBG_VERBOSE, "%s halt\n", _ep->name);
 	return 0;
@@ -1216,7 +1216,7 @@ static struct usb_ep_ops pxa2xx_ep_ops =
 
 
 /* ---------------------------------------------------------------------------
- * 	device-scoped parts of the api to the usb controller hardware
+ *	device-scoped parts of the api to the usb controller hardware
  * ---------------------------------------------------------------------------
  */
 
@@ -1239,7 +1239,7 @@ static void udc_enable (struct pxa2xx_ud
 static void udc_disable(struct pxa2xx_udc *);
 
 /* We disable the UDC -- and its 48 MHz clock -- whenever it's not
- * in active use.  
+ * in active use.
  */
 static int pullup(struct pxa2xx_udc *udc, int is_active)
 {
@@ -1464,24 +1464,10 @@ #define remove_proc_files() do {} while 
 
 #endif	/* CONFIG_USB_GADGET_DEBUG_FILES */
 
-/* "function" sysfs attribute */
-static ssize_t
-show_function (struct device *_dev, struct device_attribute *attr, char *buf)
-{
-	struct pxa2xx_udc	*dev = dev_get_drvdata (_dev);
-
-	if (!dev->driver
-			|| !dev->driver->function
-			|| strlen (dev->driver->function) > PAGE_SIZE)
-		return 0;
-	return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
-}
-static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
-
 /*-------------------------------------------------------------------------*/
 
 /*
- * 	udc_disable - disable USB device controller
+ *	udc_disable - disable USB device controller
  */
 static void udc_disable(struct pxa2xx_udc *dev)
 {
@@ -1497,7 +1483,7 @@ static void udc_disable(struct pxa2xx_ud
 
 #ifdef	CONFIG_ARCH_PXA
         /* Disable clock for USB device */
-	pxa_set_cken(CKEN11_USB, 0);
+	pxa_set_cken(CKEN_USB, 0);
 #endif
 
 	ep0_idle (dev);
@@ -1507,7 +1493,7 @@ #endif
 
 
 /*
- * 	udc_reinit - initialize software state
+ *	udc_reinit - initialize software state
  */
 static void udc_reinit(struct pxa2xx_udc *dev)
 {
@@ -1543,7 +1529,7 @@ static void udc_enable (struct pxa2xx_ud
 
 #ifdef	CONFIG_ARCH_PXA
         /* Enable clock for USB device */
-	pxa_set_cken(CKEN11_USB, 1);
+	pxa_set_cken(CKEN_USB, 1);
 	udelay(5);
 #endif
 
@@ -1635,18 +1621,20 @@ int usb_gadget_register_driver(struct us
 	dev->gadget.dev.driver = &driver->driver;
 	dev->pullup = 1;
 
-	device_add (&dev->gadget.dev);
+	retval = device_add (&dev->gadget.dev);
+	if (retval) {
+fail:
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
+		return retval;
+	}
 	retval = driver->bind(&dev->gadget);
 	if (retval) {
 		DMSG("bind to driver %s --> error %d\n",
 				driver->driver.name, retval);
 		device_del (&dev->gadget.dev);
-
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
+		goto fail;
 	}
-	device_create_file(dev->dev, &dev_attr_function);
 
 	/* ... then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
@@ -1704,7 +1692,6 @@ int usb_gadget_unregister_driver(struct 
 	dev->driver = NULL;
 
 	device_del (&dev->gadget.dev);
-	device_remove_file(dev->dev, &dev_attr_function);
 
 	DMSG("unregistered gadget driver '%s'\n", driver->driver.name);
 	dump_state(dev);
@@ -2474,12 +2461,12 @@ #define IXP425_B0		0x000001f1
 #define IXP465_AD		0x00000200
 
 /*
- * 	probe - binds to the platform device
+ *	probe - binds to the platform device
  */
 static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 {
 	struct pxa2xx_udc *dev = &memory;
-	int retval, out_dma = 1, vbus_irq;
+	int retval, out_dma = 1, vbus_irq, irq;
 	u32 chiprev;
 
 	/* insist on Intel/ARM/XScale */
@@ -2522,7 +2509,11 @@ #endif
 		return -ENODEV;
 	}
 
-	pr_debug("%s: IRQ %d%s%s%s\n", driver_name, IRQ_USB,
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENODEV;
+
+	pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
 		dev->has_cfr ? "" : " (!cfr)",
 		out_dma ? "" : " (broken dma-out)",
 		SIZE_STR DMASTR
@@ -2570,11 +2561,11 @@ #endif
 	dev->vbus = is_vbus_present();
 
 	/* irq setup after old hardware state is cleaned up */
-	retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
+	retval = request_irq(irq, pxa2xx_udc_irq,
 			IRQF_DISABLED, driver_name, dev);
 	if (retval != 0) {
-		printk(KERN_ERR "%s: can't get irq %i, err %d\n",
-			driver_name, IRQ_USB, retval);
+		printk(KERN_ERR "%s: can't get irq %d, err %d\n",
+			driver_name, irq, retval);
 		return -EBUSY;
 	}
 	dev->got_irq = 1;
@@ -2589,7 +2580,7 @@ #ifdef CONFIG_ARCH_LUBBOCK
 			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
 				driver_name, LUBBOCK_USB_DISC_IRQ, retval);
 lubbock_fail0:
-			free_irq(IRQ_USB, dev);
+			free_irq(irq, dev);
 			return -EBUSY;
 		}
 		retval = request_irq(LUBBOCK_USB_IRQ,
@@ -2616,7 +2607,7 @@ #endif
 		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);
+			free_irq(irq, dev);
 			return -EBUSY;
 		}
 	}
@@ -2641,7 +2632,7 @@ static int __exit pxa2xx_udc_remove(stru
 	remove_proc_files();
 
 	if (dev->got_irq) {
-		free_irq(IRQ_USB, dev);
+		free_irq(platform_get_irq(pdev, 0), dev);
 		dev->got_irq = 0;
 	}
 #ifdef CONFIG_ARCH_LUBBOCK
@@ -2668,7 +2659,7 @@ #ifdef	CONFIG_PM
  *
  * For now, we punt and forcibly disconnect from the USB host when PXA
  * enters any suspend state.  While we're disconnected, we always disable
- * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. 
+ * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states.
  * Boards without software pullup control shouldn't use those states.
  * VBUS IRQs should probably be ignored so that the PXA device just acts
  * "dead" to USB hosts until system resume.
@@ -2701,7 +2692,6 @@ #endif
 /*-------------------------------------------------------------------------*/
 
 static struct platform_driver udc_driver = {
-	.probe		= pxa2xx_udc_probe,
 	.shutdown	= pxa2xx_udc_shutdown,
 	.remove		= __exit_p(pxa2xx_udc_remove),
 	.suspend	= pxa2xx_udc_suspend,
@@ -2715,7 +2705,7 @@ static struct platform_driver udc_driver
 static int __init udc_init(void)
 {
 	printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
-	return platform_driver_register(&udc_driver);
+	return platform_driver_probe(&udc_driver, pxa2xx_udc_probe);
 }
 module_init(udc_init);
 
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 4c3c725..397b149 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -195,7 +195,7 @@ struct rndis_packet_msg_type
 	__le32	PerPacketInfoLength;
 	__le32	VcHandle;
 	__le32	Reserved;
-};
+} __attribute__ ((packed));
 
 struct rndis_config_parameter
 {
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index e552668..f847c34 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -22,7 +22,6 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 8c85e33..7078374 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -67,7 +67,6 @@ #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index a2e58c8..2ff396b 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,4 +15,3 @@ 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-fsl.h b/drivers/usb/host/ehci-fsl.h
index caac0d1..f28736a 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -31,7 +31,7 @@ #define FSL_SOC_USB_USBMODE	0x1a8
 #define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
 #define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
 #define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
-#define FSL_SOC_USB_SICTRL	0x40c	/* NOTE: big-endian */
-#define FSL_SOC_USB_PRICTRL	0x410	/* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL	0x40c	/* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL	0x410	/* NOTE: big-endian */
 #define FSL_SOC_USB_CTRL	0x500	/* NOTE: big-endian */
 #endif				/* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c7458f7..099aff6 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -24,7 +24,6 @@ #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>
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 1813b7c..f4d301b 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -136,6 +136,10 @@ static int ehci_bus_resume (struct usb_h
 	/* restore CMD_RUN, framelist size, and irq threshold */
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
+	/* Some controller/firmware combinations need a delay during which
+	 * they set up the port statuses.  See Bugzilla #8190. */
+	mdelay(8);
+
 	/* manually resume the ports we suspended during bus_suspend() */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 4d781a2..37b83ba 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -73,13 +73,6 @@ #if defined(CONFIG_PM)
 #endif
 };
 
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-	const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
-
 static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
 {
 	int result;
@@ -104,7 +97,7 @@ static int ps3_ehci_sb_probe(struct ps3_
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 		__LINE__, dev->m_region->lpar_addr);
 
-	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+	result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 
 	if (result) {
 		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@ -162,7 +155,7 @@ fail_add_hcd:
 fail_ioremap:
 	usb_put_hcd(hcd);
 fail_create_hcd:
-	ps3_free_io_irq(virq);
+	ps3_io_irq_destroy(virq);
 fail_irq:
 	ps3_free_mmio_region(dev->m_region);
 fail_mmio:
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
deleted file mode 100644
index 32f7caf..0000000
--- a/drivers/usb/host/hc_crisv10.c
+++ /dev/null
@@ -1,4550 +0,0 @@
-/*
- * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD)
- *
- * Copyright (c) 2002, 2003 Axis Communications AB.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/arch/svinto.h>
-
-#include <linux/usb.h>
-/* Ugly include because we don't live with the other host drivers. */
-#include <../drivers/usb/core/hcd.h>
-#include <../drivers/usb/core/usb.h>
-
-#include "hc_crisv10.h"
-
-#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR
-#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR
-#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR
-
-static const char *usb_hcd_version = "$Revision: 1.2 $";
-
-#undef KERN_DEBUG
-#define KERN_DEBUG ""
-
-
-#undef USB_DEBUG_RH
-#undef USB_DEBUG_EPID
-#undef USB_DEBUG_SB
-#undef USB_DEBUG_DESC
-#undef USB_DEBUG_URB
-#undef USB_DEBUG_TRACE
-#undef USB_DEBUG_BULK
-#undef USB_DEBUG_CTRL
-#undef USB_DEBUG_INTR
-#undef USB_DEBUG_ISOC
-
-#ifdef USB_DEBUG_RH
-#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg)
-#else
-#define dbg_rh(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_EPID
-#define dbg_epid(format, arg...) printk(KERN_DEBUG __FILE__ ": (EPID) " format "\n" , ## arg)
-#else
-#define dbg_epid(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_SB
-#define dbg_sb(format, arg...) printk(KERN_DEBUG __FILE__ ": (SB) " format "\n" , ## arg)
-#else
-#define dbg_sb(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_CTRL
-#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg)
-#else
-#define dbg_ctrl(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_BULK
-#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg)
-#else
-#define dbg_bulk(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_INTR
-#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg)
-#else
-#define dbg_intr(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_ISOC
-#define dbg_isoc(format, arg...) printk(KERN_DEBUG __FILE__ ": (ISOC) " format "\n" , ## arg)
-#else
-#define dbg_isoc(format, arg...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_TRACE
-#define DBFENTER (printk(": Entering: %s\n", __FUNCTION__))
-#define DBFEXIT  (printk(": Exiting:  %s\n", __FUNCTION__))
-#else
-#define DBFENTER do {} while (0)
-#define DBFEXIT  do {} while (0)
-#endif
-
-#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
-
-/*-------------------------------------------------------------------
- Virtual Root Hub
- -------------------------------------------------------------------*/
-
-static __u8 root_hub_dev_des[] =
-{
-	0x12,  /*  __u8  bLength; */
-	0x01,  /*  __u8  bDescriptorType; Device */
-	0x00,  /*  __le16 bcdUSB; v1.0 */
-	0x01,
-	0x09,  /*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,  /*  __u8  bDeviceSubClass; */
-	0x00,  /*  __u8  bDeviceProtocol; */
-	0x08,  /*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,  /*  __le16 idVendor; */
-	0x00,
-	0x00,  /*  __le16 idProduct; */
-	0x00,
-	0x00,  /*  __le16 bcdDevice; */
-	0x00,
-	0x00,  /*  __u8  iManufacturer; */
-	0x02,  /*  __u8  iProduct; */
-	0x01,  /*  __u8  iSerialNumber; */
-	0x01   /*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,  /*  __u8  bLength; */
-	0x02,  /*  __u8  bDescriptorType; Configuration */
-	0x19,  /*  __le16 wTotalLength; */
-	0x00,
-	0x01,  /*  __u8  bNumInterfaces; */
-	0x01,  /*  __u8  bConfigurationValue; */
-	0x00,  /*  __u8  iConfiguration; */
-	0x40,  /*  __u8  bmAttributes; Bit 7: Bus-powered */
-	0x00,  /*  __u8  MaxPower; */
-
-     /* interface */
-	0x09,  /*  __u8  if_bLength; */
-	0x04,  /*  __u8  if_bDescriptorType; Interface */
-	0x00,  /*  __u8  if_bInterfaceNumber; */
-	0x00,  /*  __u8  if_bAlternateSetting; */
-	0x01,  /*  __u8  if_bNumEndpoints; */
-	0x09,  /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,  /*  __u8  if_bInterfaceSubClass; */
-	0x00,  /*  __u8  if_bInterfaceProtocol; */
-	0x00,  /*  __u8  if_iInterface; */
-
-     /* endpoint */
-	0x07,  /*  __u8  ep_bLength; */
-	0x05,  /*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,  /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,  /*  __u8  ep_bmAttributes; Interrupt */
-	0x08,  /*  __le16 ep_wMaxPacketSize; 8 Bytes */
-	0x00,
-	0xff   /*  __u8  ep_bInterval; 255 ms */
-};
-
-static __u8 root_hub_hub_des[] =
-{
-	0x09,  /*  __u8  bLength; */
-	0x29,  /*  __u8  bDescriptorType; Hub-descriptor */
-	0x02,  /*  __u8  bNbrPorts; */
-	0x00,  /* __u16  wHubCharacteristics; */
-	0x00,
-	0x01,  /*  __u8  bPwrOn2pwrGood; 2ms */
-	0x00,  /*  __u8  bHubContrCurrent; 0 mA */
-	0x00,  /*  __u8  DeviceRemovable; *** 7 Ports max *** */
-	0xff   /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-static DEFINE_TIMER(bulk_start_timer, NULL, 0, 0);
-static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0);
-
-/* We want the start timer to expire before the eot timer, because the former might start
-   traffic, thus making it unnecessary for the latter to time out. */
-#define BULK_START_TIMER_INTERVAL (HZ/10) /* 100 ms */
-#define BULK_EOT_TIMER_INTERVAL (HZ/10+2) /* 120 ms */
-
-#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break
-#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \
-{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);}
-
-#define SLAB_FLAG     (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-/* Alternative assert define which stops after a failed assert. */
-/*
-#define assert(expr)                                      \
-{                                                         \
-        if (!(expr)) {                                    \
-                err("assert failed at line %d",__LINE__); \
-                while (1);                                \
-        }                                                 \
-}
-*/
-
-
-/* FIXME: Should RX_BUF_SIZE be a config option, or maybe we should adjust it dynamically?
-   To adjust it dynamically we would have to get an interrupt when we reach the end
-   of the rx descriptor list, or when we get close to the end, and then allocate more
-   descriptors. */
-
-#define NBR_OF_RX_DESC     512
-#define RX_DESC_BUF_SIZE   1024
-#define RX_BUF_SIZE        (NBR_OF_RX_DESC * RX_DESC_BUF_SIZE)
-
-/* The number of epids is, among other things, used for pre-allocating
-   ctrl, bulk and isoc EP descriptors (one for each epid).
-   Assumed to be > 1 when initiating the DMA lists. */
-#define NBR_OF_EPIDS       32
-
-/* Support interrupt traffic intervals up to 128 ms. */
-#define MAX_INTR_INTERVAL 128
-
-/* If periodic traffic (intr or isoc) is to be used, then one entry in the EP table
-   must be "invalid". By this we mean that we shouldn't care about epid attentions
-   for this epid, or at least handle them differently from epid attentions for "valid"
-   epids. This define determines which one to use (don't change it). */
-#define INVALID_EPID     31
-/* A special epid for the bulk dummys. */
-#define DUMMY_EPID       30
-
-/* This is just a software cache for the valid entries in R_USB_EPT_DATA. */
-static __u32 epid_usage_bitmask;
-
-/* A bitfield to keep information on in/out traffic is needed to uniquely identify
-   an endpoint on a device, since the most significant bit which indicates traffic
-   direction is lacking in the ep_id field (ETRAX epids can handle both in and
-   out traffic on endpoints that are otherwise identical). The USB framework, however,
-   relies on them to be handled separately.  For example, bulk IN and OUT urbs cannot
-   be queued in the same list, since they would block each other. */
-static __u32 epid_out_traffic;
-
-/* DMA IN cache bug. Align the DMA IN buffers to 32 bytes, i.e. a cache line.
-   Since RX_DESC_BUF_SIZE is 1024 is a multiple of 32, all rx buffers will be cache aligned. */
-static volatile unsigned char RxBuf[RX_BUF_SIZE] __attribute__ ((aligned (32)));
-static volatile USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4)));
-
-/* Pointers into RxDescList. */
-static volatile USB_IN_Desc_t *myNextRxDesc;
-static volatile USB_IN_Desc_t *myLastRxDesc;
-static volatile USB_IN_Desc_t *myPrevRxDesc;
-
-/* EP descriptors must be 32-bit aligned. */
-static volatile USB_EP_Desc_t TxCtrlEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-static volatile USB_EP_Desc_t TxBulkEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-/* After each enabled bulk EP (IN or OUT) we put two disabled EP descriptors with the eol flag set,
-   causing the DMA to stop the DMA channel. The first of these two has the intr flag set, which
-   gives us a dma8_sub0_descr interrupt. When we receive this, we advance the DMA one step in the
-   EP list and then restart the bulk channel, thus forcing a switch between bulk EP descriptors
-   in each frame. */
-static volatile USB_EP_Desc_t TxBulkDummyEPList[NBR_OF_EPIDS][2] __attribute__ ((aligned (4)));
-
-static volatile USB_EP_Desc_t TxIsocEPList[NBR_OF_EPIDS] __attribute__ ((aligned (4)));
-static volatile USB_SB_Desc_t TxIsocSB_zout __attribute__ ((aligned (4)));
-
-static volatile USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4)));
-static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4)));
-
-/* A zout transfer makes a memory access at the address of its buf pointer, which means that setting
-   this buf pointer to 0 will cause an access to the flash. In addition to this, setting sw_len to 0
-   results in a 16/32 bytes (depending on DMA burst size) transfer. Instead, we set it to 1, and point
-   it to this buffer. */
-static int zout_buffer[4] __attribute__ ((aligned (4)));
-
-/* Cache for allocating new EP and SB descriptors. */
-static struct kmem_cache *usb_desc_cache;
-
-/* Cache for the registers allocated in the top half. */
-static struct kmem_cache *top_half_reg_cache;
-
-/* Cache for the data allocated in the isoc descr top half. */
-static struct kmem_cache *isoc_compl_cache;
-
-static struct usb_bus *etrax_usb_bus;
-
-/* This is a circular (double-linked) list of the active urbs for each epid.
-   The head is never removed, and new urbs are linked onto the list as
-   urb_entry_t elements. Don't reference urb_list directly; use the wrapper
-   functions instead. Note that working with these lists might require spinlock
-   protection. */
-static struct list_head urb_list[NBR_OF_EPIDS];
-
-/* Read about the need and usage of this lock in submit_ctrl_urb. */
-static spinlock_t urb_list_lock;
-
-/* Used when unlinking asynchronously. */
-static struct list_head urb_unlink_list;
-
-/* for returning string descriptors in UTF-16LE */
-static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
-{
-	int retval;
-
-	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
-		*utf++ = *ascii++ & 0x7f;
-		*utf++ = 0;
-	}
-	return retval;
-}
-
-static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
-{
-	char buf [30];
-
-	// assert (len > (2 * (sizeof (buf) + 1)));
-	// assert (strlen (type) <= 8);
-
-	// language ids
-	if (id == 0) {
-		*data++ = 4; *data++ = 3;	/* 4 bytes data */
-		*data++ = 0; *data++ = 0;	/* some language id */
-		return 4;
-
-	// serial number
-	} else if (id == 1) {
-		sprintf (buf, "%x", serial);
-
-	// product description
-	} else if (id == 2) {
-		sprintf (buf, "USB %s Root Hub", type);
-
-	// id 3 == vendor description
-
-	// unsupported IDs --> "stall"
-	} else
-	    return 0;
-
-	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
-	data [1] = 3;
-	return data [0];
-}
-
-/* Wrappers around the list functions (include/linux/list.h). */
-
-static inline int urb_list_empty(int epid)
-{
-	return list_empty(&urb_list[epid]);
-}
-
-/* Returns first urb for this epid, or NULL if list is empty. */
-static inline struct urb *urb_list_first(int epid)
-{
-	struct urb *first_urb = 0;
-
-	if (!urb_list_empty(epid)) {
-		/* Get the first urb (i.e. head->next). */
-		urb_entry_t *urb_entry = list_entry((&urb_list[epid])->next, urb_entry_t, list);
-		first_urb = urb_entry->urb;
-	}
-	return first_urb;
-}
-
-/* Adds an urb_entry last in the list for this epid. */
-static inline void urb_list_add(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = kmalloc(sizeof(urb_entry_t), KMALLOC_FLAG);
-	assert(urb_entry);
-
-	urb_entry->urb = urb;
-	list_add_tail(&urb_entry->list, &urb_list[epid]);
-}
-
-/* Search through the list for an element that contains this urb. (The list
-   is expected to be short and the one we are about to delete will often be
-   the first in the list.) */
-static inline urb_entry_t *__urb_list_entry(struct urb *urb, int epid)
-{
-	struct list_head *entry;
-	struct list_head *tmp;
-	urb_entry_t *urb_entry;
-
-	list_for_each_safe(entry, tmp, &urb_list[epid]) {
-		urb_entry = list_entry(entry, urb_entry_t, list);
-		assert(urb_entry);
-		assert(urb_entry->urb);
-
-		if (urb_entry->urb == urb) {
-			return urb_entry;
-		}
-	}
-	return 0;
-}
-
-/* Delete an urb from the list. */
-static inline void urb_list_del(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-	assert(urb_entry);
-
-	/* Delete entry and free. */
-	list_del(&urb_entry->list);
-	kfree(urb_entry);
-}
-
-/* Move an urb to the end of the list. */
-static inline void urb_list_move_last(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-	assert(urb_entry);
-
-	list_move_tail(&urb_entry->list, &urb_list[epid]);
-}
-
-/* Get the next urb in the list. */
-static inline struct urb *urb_list_next(struct urb *urb, int epid)
-{
-	urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
-
-	assert(urb_entry);
-
-	if (urb_entry->list.next != &urb_list[epid]) {
-		struct list_head *elem = urb_entry->list.next;
-		urb_entry = list_entry(elem, urb_entry_t, list);
-		return urb_entry->urb;
-	} else {
-		return NULL;
-	}
-}
-
-
-
-/* For debug purposes only. */
-static inline void urb_list_dump(int epid)
-{
-	struct list_head *entry;
-	struct list_head *tmp;
-	urb_entry_t *urb_entry;
-	int i = 0;
-
-	info("Dumping urb list for epid %d", epid);
-
-	list_for_each_safe(entry, tmp, &urb_list[epid]) {
-		urb_entry = list_entry(entry, urb_entry_t, list);
-		info("   entry %d, urb = 0x%lx", i, (unsigned long)urb_entry->urb);
-	}
-}
-
-static void init_rx_buffers(void);
-static int etrax_rh_unlink_urb(struct urb *urb);
-static void etrax_rh_send_irq(struct urb *urb);
-static void etrax_rh_init_int_timer(struct urb *urb);
-static void etrax_rh_int_timer_do(unsigned long ptr);
-
-static int etrax_usb_setup_epid(struct urb *urb);
-static int etrax_usb_lookup_epid(struct urb *urb);
-static int etrax_usb_allocate_epid(void);
-static void etrax_usb_free_epid(int epid);
-
-static int etrax_remove_from_sb_list(struct urb *urb);
-
-static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size,
-	unsigned mem_flags, dma_addr_t *dma);
-static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
-
-static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid);
-static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid);
-
-static int etrax_usb_submit_bulk_urb(struct urb *urb);
-static int etrax_usb_submit_ctrl_urb(struct urb *urb);
-static int etrax_usb_submit_intr_urb(struct urb *urb);
-static int etrax_usb_submit_isoc_urb(struct urb *urb);
-
-static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags);
-static int etrax_usb_unlink_urb(struct urb *urb, int status);
-static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
-
-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);
-
-
-/* The following is a list of interrupt handlers for the host controller interrupts we use.
-   They are called from etrax_usb_hc_interrupt_bottom_half. */
-static void etrax_usb_hc_isoc_eof_interrupt(void);
-static void etrax_usb_hc_bulk_eot_interrupt(int timer_induced);
-static void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg);
-static void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg);
-static void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg);
-
-static int etrax_rh_submit_urb (struct urb *urb);
-
-/* Forward declaration needed because they are used in the rx interrupt routine. */
-static void etrax_usb_complete_urb(struct urb *urb, int status);
-static void etrax_usb_complete_bulk_urb(struct urb *urb, int status);
-static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status);
-static void etrax_usb_complete_intr_urb(struct urb *urb, int status);
-static void etrax_usb_complete_isoc_urb(struct urb *urb, int status);
-
-static int etrax_usb_hc_init(void);
-static void etrax_usb_hc_cleanup(void);
-
-static struct usb_operations etrax_usb_device_operations =
-{
-	.get_frame_number = etrax_usb_get_frame_number,
-	.submit_urb = etrax_usb_submit_urb,
-	.unlink_urb = etrax_usb_unlink_urb,
-        .buffer_alloc = etrax_usb_buffer_alloc,
-        .buffer_free = etrax_usb_buffer_free
-};
-
-/* Note that these functions are always available in their "__" variants, for use in
-   error situations. The "__" missing variants are controlled by the USB_DEBUG_DESC/
-   USB_DEBUG_URB macros. */
-static void __dump_urb(struct urb* purb)
-{
-	printk("\nurb                  :0x%08lx\n", (unsigned long)purb);
-	printk("dev                   :0x%08lx\n", (unsigned long)purb->dev);
-	printk("pipe                  :0x%08x\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08x\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08lx\n", (unsigned long)purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08lx\n", (unsigned long)purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08lx\n", (unsigned long)purb->context);
-	printk("complete              :0x%08lx\n\n", (unsigned long)purb->complete);
-}
-
-static void __dump_in_desc(volatile USB_IN_Desc_t *in)
-{
-	printk("\nUSB_IN_Desc at 0x%08lx\n", (unsigned long)in);
-	printk("  sw_len  : 0x%04x (%d)\n", in->sw_len, in->sw_len);
-	printk("  command : 0x%04x\n", in->command);
-	printk("  next    : 0x%08lx\n", in->next);
-	printk("  buf     : 0x%08lx\n", in->buf);
-	printk("  hw_len  : 0x%04x (%d)\n", in->hw_len, in->hw_len);
-	printk("  status  : 0x%04x\n\n", in->status);
-}
-
-static void __dump_sb_desc(volatile USB_SB_Desc_t *sb)
-{
-	char tt = (sb->command & 0x30) >> 4;
-	char *tt_string;
-
-	switch (tt) {
-	case 0:
-		tt_string = "zout";
-		break;
-	case 1:
-		tt_string = "in";
-		break;
-	case 2:
-		tt_string = "out";
-		break;
-	case 3:
-		tt_string = "setup";
-		break;
-	default:
-		tt_string = "unknown (weird)";
-	}
-
-	printk("\n   USB_SB_Desc at 0x%08lx\n", (unsigned long)sb);
-	printk("     command : 0x%04x\n", sb->command);
-	printk("        rem     : %d\n", (sb->command & 0x3f00) >> 8);
-	printk("        full    : %d\n", (sb->command & 0x40) >> 6);
-	printk("        tt      : %d (%s)\n", tt, tt_string);
-	printk("        intr    : %d\n", (sb->command & 0x8) >> 3);
-	printk("        eot     : %d\n", (sb->command & 0x2) >> 1);
-	printk("        eol     : %d\n", sb->command & 0x1);
-	printk("     sw_len  : 0x%04x (%d)\n", sb->sw_len, sb->sw_len);
-	printk("     next    : 0x%08lx\n", sb->next);
-	printk("     buf     : 0x%08lx\n\n", sb->buf);
-}
-
-
-static void __dump_ep_desc(volatile USB_EP_Desc_t *ep)
-{
-	printk("\nUSB_EP_Desc at 0x%08lx\n", (unsigned long)ep);
-	printk("  command : 0x%04x\n", ep->command);
-	printk("     ep_id   : %d\n", (ep->command & 0x1f00) >> 8);
-	printk("     enable  : %d\n", (ep->command & 0x10) >> 4);
-	printk("     intr    : %d\n", (ep->command & 0x8) >> 3);
-	printk("     eof     : %d\n", (ep->command & 0x2) >> 1);
-	printk("     eol     : %d\n", ep->command & 0x1);
-	printk("  hw_len  : 0x%04x (%d)\n", ep->hw_len, ep->hw_len);
-	printk("  next    : 0x%08lx\n", ep->next);
-	printk("  sub     : 0x%08lx\n\n", ep->sub);
-}
-
-static inline void __dump_ep_list(int pipe_type)
-{
-	volatile USB_EP_Desc_t *ep;
-	volatile USB_EP_Desc_t *first_ep;
-	volatile USB_SB_Desc_t *sb;
-
-	switch (pipe_type)
-	{
-	case PIPE_BULK:
-		first_ep = &TxBulkEPList[0];
-		break;
-	case PIPE_CONTROL:
-		first_ep = &TxCtrlEPList[0];
-		break;
-	case PIPE_INTERRUPT:
-		first_ep = &TxIntrEPList[0];
-		break;
-	case PIPE_ISOCHRONOUS:
-		first_ep = &TxIsocEPList[0];
-		break;
-	default:
-		warn("Cannot dump unknown traffic type");
-		return;
-	}
-	ep = first_ep;
-
-	printk("\n\nDumping EP list...\n\n");
-
-	do {
-		__dump_ep_desc(ep);
-		/* Cannot phys_to_virt on 0 as it turns into 80000000, which is != 0. */
-		sb = ep->sub ? phys_to_virt(ep->sub) : 0;
-		while (sb) {
-			__dump_sb_desc(sb);
-			sb = sb->next ? phys_to_virt(sb->next) : 0;
-		}
-		ep = (volatile USB_EP_Desc_t *)(phys_to_virt(ep->next));
-
-	} while (ep != first_ep);
-}
-
-static inline void __dump_ept_data(int epid)
-{
-	unsigned long flags;
-	__u32 r_usb_ept_data;
-
-	if (epid < 0 || epid > 31) {
-		printk("Cannot dump ept data for invalid epid %d\n", epid);
-		return;
-	}
-
-	save_flags(flags);
-	cli();
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	r_usb_ept_data = *R_USB_EPT_DATA;
-	restore_flags(flags);
-
-	printk("\nR_USB_EPT_DATA = 0x%x for epid %d :\n", r_usb_ept_data, epid);
-	if (r_usb_ept_data == 0) {
-		/* No need for more detailed printing. */
-		return;
-	}
-	printk("  valid           : %d\n", (r_usb_ept_data & 0x80000000) >> 31);
-	printk("  hold            : %d\n", (r_usb_ept_data & 0x40000000) >> 30);
-	printk("  error_count_in  : %d\n", (r_usb_ept_data & 0x30000000) >> 28);
-	printk("  t_in            : %d\n", (r_usb_ept_data & 0x08000000) >> 27);
-	printk("  low_speed       : %d\n", (r_usb_ept_data & 0x04000000) >> 26);
-	printk("  port            : %d\n", (r_usb_ept_data & 0x03000000) >> 24);
-	printk("  error_code      : %d\n", (r_usb_ept_data & 0x00c00000) >> 22);
-	printk("  t_out           : %d\n", (r_usb_ept_data & 0x00200000) >> 21);
-	printk("  error_count_out : %d\n", (r_usb_ept_data & 0x00180000) >> 19);
-	printk("  max_len         : %d\n", (r_usb_ept_data & 0x0003f800) >> 11);
-	printk("  ep              : %d\n", (r_usb_ept_data & 0x00000780) >> 7);
-	printk("  dev             : %d\n", (r_usb_ept_data & 0x0000003f));
-}
-
-static inline void __dump_ept_data_list(void)
-{
-	int i;
-
-	printk("Dumping the whole R_USB_EPT_DATA list\n");
-
-	for (i = 0; i < 32; i++) {
-		__dump_ept_data(i);
-	}
-}
-#ifdef USB_DEBUG_DESC
-#define dump_in_desc(...) __dump_in_desc(...)
-#define dump_sb_desc(...) __dump_sb_desc(...)
-#define dump_ep_desc(...) __dump_ep_desc(...)
-#else
-#define dump_in_desc(...) do {} while (0)
-#define dump_sb_desc(...) do {} while (0)
-#define dump_ep_desc(...) do {} while (0)
-#endif
-
-#ifdef USB_DEBUG_URB
-#define dump_urb(x)     __dump_urb(x)
-#else
-#define dump_urb(x)     do {} while (0)
-#endif
-
-static void init_rx_buffers(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
-		RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-		RxDescList[i].command = 0;
-		RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
-		RxDescList[i].hw_len = 0;
-		RxDescList[i].status = 0;
-
-		/* DMA IN cache bug. (struct etrax_dma_descr has the same layout as USB_IN_Desc
-		   for the relevant fields.) */
-		prepare_rx_descriptor((struct etrax_dma_descr*)&RxDescList[i]);
-
-	}
-
-	RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
-	RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes);
-	RxDescList[i].next = virt_to_phys(&RxDescList[0]);
-	RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE));
-	RxDescList[i].hw_len = 0;
-	RxDescList[i].status = 0;
-
-	myNextRxDesc = &RxDescList[0];
-	myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
-	myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
-
-	*R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc);
-	*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void init_tx_bulk_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxBulkEPList[i]);
-		TxBulkEPList[i].hw_len = 0;
-		TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxBulkEPList[i].sub = 0;
-		TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[i + 1]);
-
-		/* Initiate two EPs, disabled and with the eol flag set. No need for any
-		   preserved epid. */
-
-		/* The first one has the intr flag set so we get an interrupt when the DMA
-		   channel is about to become disabled. */
-		CHECK_ALIGN(&TxBulkDummyEPList[i][0]);
-		TxBulkDummyEPList[i][0].hw_len = 0;
-		TxBulkDummyEPList[i][0].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
-						   IO_STATE(USB_EP_command, eol, yes) |
-						   IO_STATE(USB_EP_command, intr, yes));
-		TxBulkDummyEPList[i][0].sub = 0;
-		TxBulkDummyEPList[i][0].next = virt_to_phys(&TxBulkDummyEPList[i][1]);
-
-		/* The second one. */
-		CHECK_ALIGN(&TxBulkDummyEPList[i][1]);
-		TxBulkDummyEPList[i][1].hw_len = 0;
-		TxBulkDummyEPList[i][1].command = (IO_FIELD(USB_EP_command, epid, DUMMY_EPID) |
-						   IO_STATE(USB_EP_command, eol, yes));
-		TxBulkDummyEPList[i][1].sub = 0;
-		/* The last dummy's next pointer is the same as the current EP's next pointer. */
-		TxBulkDummyEPList[i][1].next = virt_to_phys(&TxBulkEPList[i + 1]);
-	}
-
-	/* Configure the last one. */
-	CHECK_ALIGN(&TxBulkEPList[i]);
-	TxBulkEPList[i].hw_len = 0;
-	TxBulkEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, i));
-	TxBulkEPList[i].sub = 0;
-	TxBulkEPList[i].next = virt_to_phys(&TxBulkEPList[0]);
-
-	/* No need configuring dummy EPs for the last one as it will never be used for
-	   bulk traffic (i == INVALD_EPID at this point). */
-
-	/* Set up to start on the last EP so we will enable it when inserting traffic
-	   for the first time (imitating the situation where the DMA has stopped
-	   because there was no more traffic). */
-	*R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[i]);
-	/* No point in starting the bulk channel yet.
-	 *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); */
-	DBFEXIT;
-}
-
-static void init_tx_ctrl_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxCtrlEPList[i]);
-		TxCtrlEPList[i].hw_len = 0;
-		TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxCtrlEPList[i].sub = 0;
-		TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxCtrlEPList[i]);
-	TxCtrlEPList[i].hw_len = 0;
-	TxCtrlEPList[i].command = (IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, i));
-
-	TxCtrlEPList[i].sub = 0;
-	TxCtrlEPList[i].next = virt_to_phys(&TxCtrlEPList[0]);
-
-	*R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]);
-	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-
-static void init_tx_intr_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	/* Read comment at zout_buffer declaration for an explanation to this. */
-	TxIntrSB_zout.sw_len = 1;
-	TxIntrSB_zout.next = 0;
-	TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]);
-	TxIntrSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
-				 IO_STATE(USB_SB_command, tt, zout) |
-				 IO_STATE(USB_SB_command, full, yes) |
-				 IO_STATE(USB_SB_command, eot, yes) |
-				 IO_STATE(USB_SB_command, eol, yes));
-
-	for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) {
-		CHECK_ALIGN(&TxIntrEPList[i]);
-		TxIntrEPList[i].hw_len = 0;
-		TxIntrEPList[i].command =
-			(IO_STATE(USB_EP_command, eof, yes) |
-			 IO_STATE(USB_EP_command, enable, yes) |
-			 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-		TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
-		TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxIntrEPList[i]);
-	TxIntrEPList[i].hw_len = 0;
-	TxIntrEPList[i].command =
-		(IO_STATE(USB_EP_command, eof, yes) |
-		 IO_STATE(USB_EP_command, eol, yes) |
-		 IO_STATE(USB_EP_command, enable, yes) |
-		 IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-	TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout);
-	TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]);
-
-	*R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]);
-	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
-	DBFEXIT;
-}
-
-static void init_tx_isoc_ep(void)
-{
-	int i;
-
-	DBFENTER;
-
-	/* Read comment at zout_buffer declaration for an explanation to this. */
-	TxIsocSB_zout.sw_len = 1;
-	TxIsocSB_zout.next = 0;
-	TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]);
-	TxIsocSB_zout.command = (IO_FIELD(USB_SB_command, rem, 0) |
-				 IO_STATE(USB_SB_command, tt, zout) |
-				 IO_STATE(USB_SB_command, full, yes) |
-				 IO_STATE(USB_SB_command, eot, yes) |
-				 IO_STATE(USB_SB_command, eol, yes));
-
-	/* The last isochronous EP descriptor is a dummy. */
-
-	for (i = 0; i < (NBR_OF_EPIDS - 1); i++) {
-		CHECK_ALIGN(&TxIsocEPList[i]);
-		TxIsocEPList[i].hw_len = 0;
-		TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i);
-		TxIsocEPList[i].sub = 0;
-		TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]);
-	}
-
-	CHECK_ALIGN(&TxIsocEPList[i]);
-	TxIsocEPList[i].hw_len = 0;
-
-	/* Must enable the last EP descr to get eof interrupt. */
-	TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) |
-				   IO_STATE(USB_EP_command, eof, yes) |
-				   IO_STATE(USB_EP_command, eol, yes) |
-				   IO_FIELD(USB_EP_command, epid, INVALID_EPID));
-	TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout);
-	TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]);
-
-	*R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]);
-	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_unlink_intr_urb(struct urb *urb)
-{
-	volatile USB_EP_Desc_t *first_ep;  /* First EP in the list. */
-	volatile USB_EP_Desc_t *curr_ep;   /* Current EP, the iterator. */
-	volatile USB_EP_Desc_t *next_ep;   /* The EP after current. */
-	volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */
-
-	int epid;
-
-	/* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */
-
-	DBFENTER;
-
-	epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid;
-
-	first_ep = &TxIntrEPList[0];
-	curr_ep = first_ep;
-
-
-	/* Note that this loop removes all EP descriptors with this epid. This assumes
-	   that all EP descriptors belong to the one and only urb for this epid. */
-
-	do {
-		next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next);
-
-		if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) {
-
-			dbg_intr("Found EP to unlink for epid %d", epid);
-
-			/* This is the one we should unlink. */
-			unlink_ep = next_ep;
-
-			/* Actually unlink the EP from the DMA list. */
-			curr_ep->next = unlink_ep->next;
-
-			/* Wait until the DMA is no longer at this descriptor. */
-			while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep));
-
-			/* Now we are free to remove it and its SB descriptor.
-			   Note that it is assumed here that there is only one sb in the
-			   sb list for this ep. */
-			kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub));
-			kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep);
-		}
-
-		curr_ep = phys_to_virt(curr_ep->next);
-
-	} while (curr_ep != first_ep);
-        urb->hcpriv = NULL;
-}
-
-void etrax_usb_do_intr_recover(int epid)
-{
-	USB_EP_Desc_t *first_ep, *tmp_ep;
-
-	DBFENTER;
-
-	first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);
-	tmp_ep = first_ep;
-
-	/* What this does is simply to walk the list of interrupt
-	   ep descriptors and enable those that are disabled. */
-
-	do {
-		if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid &&
-		    !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) {
-			tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes);
-		}
-
-		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
-
-	} while (tmp_ep != first_ep);
-
-
-	DBFEXIT;
-}
-
-static int etrax_rh_unlink_urb (struct urb *urb)
-{
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	hc = urb->dev->bus->hcpriv;
-
-	if (hc->rh.urb == urb) {
-		hc->rh.send = 0;
-		del_timer(&hc->rh.rh_int_timer);
-	}
-
-	DBFEXIT;
-	return 0;
-}
-
-static void etrax_rh_send_irq(struct urb *urb)
-{
-	__u16 data = 0;
-	etrax_hc_t *hc = urb->dev->bus->hcpriv;
-	DBFENTER;
-
-/*
-  dbg_rh("R_USB_FM_NUMBER   : 0x%08X", *R_USB_FM_NUMBER);
-  dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);
-*/
-
-	data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0;
-	data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0;
-
-	*((__u16 *)urb->transfer_buffer) = cpu_to_le16(data);
-	/* FIXME: Why is actual_length set to 1 when data is 2 bytes?
-	   Since only 1 byte is used, why not declare data as __u8? */
-	urb->actual_length = 1;
-	urb->status = 0;
-
-	if (hc->rh.send && urb->complete) {
-		dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1);
-		dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2);
-
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_rh_init_int_timer(struct urb *urb)
-{
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	hc = urb->dev->bus->hcpriv;
-	hc->rh.interval = urb->interval;
-	init_timer(&hc->rh.rh_int_timer);
-	hc->rh.rh_int_timer.function = etrax_rh_int_timer_do;
-	hc->rh.rh_int_timer.data = (unsigned long)urb;
-	/* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped
-	   to 0, and the rest to the nearest lower 10 ms. */
-	hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000);
-	add_timer(&hc->rh.rh_int_timer);
-
-	DBFEXIT;
-}
-
-static void etrax_rh_int_timer_do(unsigned long ptr)
-{
-	struct urb *urb;
-	etrax_hc_t *hc;
-
-	DBFENTER;
-
-	urb = (struct urb*)ptr;
-	hc = urb->dev->bus->hcpriv;
-
-	if (hc->rh.send) {
-		etrax_rh_send_irq(urb);
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_setup_epid(struct urb *urb)
-{
-	int epid;
-	char devnum, endpoint, out_traffic, slow;
-	int maxlen;
-	unsigned long flags;
-
-	DBFENTER;
-
-	epid = etrax_usb_lookup_epid(urb);
-	if ((epid != -1)){
-		/* An epid that fits this urb has been found. */
-		DBFEXIT;
-		return epid;
-	}
-
-	/* We must find and initiate a new epid for this urb. */
-	epid = etrax_usb_allocate_epid();
-
-	if (epid == -1) {
-		/* Failed to allocate a new epid. */
-		DBFEXIT;
-		return epid;
-	}
-
-	/* We now have a new epid to use. Initiate it. */
-	set_bit(epid, (void *)&epid_usage_bitmask);
-
-	devnum = usb_pipedevice(urb->pipe);
-	endpoint = usb_pipeendpoint(urb->pipe);
-	slow = usb_pipeslow(urb->pipe);
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
-		out_traffic = 1;
-	} else {
-		out_traffic = usb_pipeout(urb->pipe);
-	}
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-		*R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) |
-			/* FIXME: Change any to the actual port? */
-			IO_STATE(R_USB_EPT_DATA_ISO, port, any) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) |
-			IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum);
-	} else {
-		*R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) |
-			IO_FIELD(R_USB_EPT_DATA, low_speed, slow) |
-			/* FIXME: Change any to the actual port? */
-			IO_STATE(R_USB_EPT_DATA, port, any) |
-			IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) |
-			IO_FIELD(R_USB_EPT_DATA, ep, endpoint) |
-			IO_FIELD(R_USB_EPT_DATA, dev, devnum);
-	}
-
-	restore_flags(flags);
-
-	if (out_traffic) {
-		set_bit(epid, (void *)&epid_out_traffic);
-	} else {
-		clear_bit(epid, (void *)&epid_out_traffic);
-	}
-
-	dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)",
-		 epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN");
-
-	DBFEXIT;
-	return epid;
-}
-
-static void etrax_usb_free_epid(int epid)
-{
-	unsigned long flags;
-
-	DBFENTER;
-
-	if (!test_bit(epid, (void *)&epid_usage_bitmask)) {
-		warn("Trying to free unused epid %d", epid);
-		DBFEXIT;
-		return;
-	}
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold));
-	/* This will, among other things, set the valid field to 0. */
-	*R_USB_EPT_DATA = 0;
-	restore_flags(flags);
-
-	clear_bit(epid, (void *)&epid_usage_bitmask);
-
-
-	dbg_epid("Freed epid %d", epid);
-
-	DBFEXIT;
-}
-
-static int etrax_usb_lookup_epid(struct urb *urb)
-{
-	int i;
-	__u32 data;
-	char devnum, endpoint, slow, out_traffic;
-	int maxlen;
-	unsigned long flags;
-
-	DBFENTER;
-
-	devnum = usb_pipedevice(urb->pipe);
-	endpoint = usb_pipeendpoint(urb->pipe);
-	slow = usb_pipeslow(urb->pipe);
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		/* We want both IN and OUT control traffic to be put on the same EP/SB list. */
-		out_traffic = 1;
-	} else {
-		out_traffic = usb_pipeout(urb->pipe);
-	}
-
-	/* Step through att epids. */
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		if (test_bit(i, (void *)&epid_usage_bitmask) &&
-		    test_bit(i, (void *)&epid_out_traffic) == out_traffic) {
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
-			nop();
-
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				data = *R_USB_EPT_DATA_ISO;
-				restore_flags(flags);
-
-				if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) {
-					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
-						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
-					DBFEXIT;
-					return i;
-				}
-			} else {
-				data = *R_USB_EPT_DATA;
-				restore_flags(flags);
-
-				if ((IO_MASK(R_USB_EPT_DATA, valid) & data) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) {
-					dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)",
-						 i, devnum, endpoint, out_traffic ? "OUT" : "IN");
-					DBFEXIT;
-					return i;
-				}
-			}
-		}
-	}
-
-	DBFEXIT;
-	return -1;
-}
-
-static int etrax_usb_allocate_epid(void)
-{
-	int i;
-
-	DBFENTER;
-
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		if (!test_bit(i, (void *)&epid_usage_bitmask)) {
-			dbg_epid("Found free epid %d", i);
-			DBFEXIT;
-			return i;
-		}
-	}
-
-	dbg_epid("Found no free epids");
-	DBFEXIT;
-	return -1;
-}
-
-static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags)
-{
-	etrax_hc_t *hc;
-	int ret = -EINVAL;
-
-	DBFENTER;
-
-	if (!urb->dev || !urb->dev->bus) {
-		return -ENODEV;
-	}
-	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
-		info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe);
-		return -EMSGSIZE;
-	}
-
-	if (urb->timeout) {
-		/* FIXME. */
-		warn("urb->timeout specified, ignoring.");
-	}
-
-	hc = (etrax_hc_t*)urb->dev->bus->hcpriv;
-
-	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
-		/* This request is for the Virtual Root Hub. */
-		ret = etrax_rh_submit_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		ret = etrax_usb_submit_bulk_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		ret = etrax_usb_submit_ctrl_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-		int bustime;
-
-		if (urb->bandwidth == 0) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-			} else {
-				ret = etrax_usb_submit_intr_urb(urb);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {
-			/* Bandwidth already set. */
-			ret = etrax_usb_submit_intr_urb(urb);
-		}
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-		int bustime;
-
-		if (urb->bandwidth == 0) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-			} else {
-				ret = etrax_usb_submit_isoc_urb(urb);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {
-			/* Bandwidth already set. */
-			ret = etrax_usb_submit_isoc_urb(urb);
-		}
-	}
-
-	DBFEXIT;
-
-        if (ret != 0)
-          printk("Submit URB error %d\n", ret);
-
-	return ret;
-}
-
-static int etrax_usb_unlink_urb(struct urb *urb, int status)
-{
-	etrax_hc_t *hc;
-	etrax_urb_priv_t *urb_priv;
-	int epid;
-	unsigned int flags;
-
-	DBFENTER;
-
-	if (!urb) {
-		return -EINVAL;
-	}
-
-	/* Disable interrupts here since a descriptor interrupt for the isoc epid
-	   will modify the sb list.  This could possibly be done more granular, but
-	   unlink_urb should not be used frequently anyway.
-	*/
-
-	save_flags(flags);
-	cli();
-
-	if (!urb->dev || !urb->dev->bus) {
-		restore_flags(flags);
-		return -ENODEV;
-	}
-	if (!urb->hcpriv) {
-		/* This happens if a device driver calls unlink on an urb that
-		   was never submitted (lazy driver) or if the urb was completed
-		   while unlink was being called. */
-		restore_flags(flags);
-		return 0;
-	}
-	if (urb->transfer_flags & URB_ASYNC_UNLINK) {
-		/* FIXME. */
-		/* If URB_ASYNC_UNLINK is set:
-		   unlink
-		   move to a separate urb list
-		   call complete at next sof with ECONNRESET
-
-		   If not:
-		   wait 1 ms
-		   unlink
-		   call complete with ENOENT
-		*/
-		warn("URB_ASYNC_UNLINK set, ignoring.");
-	}
-
-	/* One might think that urb->status = -EINPROGRESS would be a requirement for unlinking,
-	   but that doesn't work for interrupt and isochronous traffic since they are completed
-	   repeatedly, and urb->status is set then. That may in itself be a bug though. */
-
-	hc = urb->dev->bus->hcpriv;
-	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	epid = urb_priv->epid;
-
-	/* Set the urb status (synchronous unlink). */
-	urb->status = -ENOENT;
-	urb_priv->urb_state = UNLINK;
-
-	if (usb_pipedevice(urb->pipe) == hc->rh.devnum) {
-		int ret;
-		ret = etrax_rh_unlink_urb(urb);
-		DBFEXIT;
-		restore_flags(flags);
-		return ret;
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		dbg_bulk("Unlink of bulk urb (0x%lx)", (unsigned long)urb);
-
-		if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid]));
-		}
-		/* Kicking dummy list out of the party. */
-		TxBulkEPList[epid].next = virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		dbg_ctrl("Unlink of ctrl urb (0x%lx)", (unsigned long)urb);
-
-		if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid]));
-		}
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-
-		dbg_intr("Unlink of intr urb (0x%lx)", (unsigned long)urb);
-
-		/* Separate function because it's a tad more complicated. */
-		etrax_usb_unlink_intr_urb(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-		dbg_isoc("Unlink of isoc urb (0x%lx)", (unsigned long)urb);
-
-		if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-			/* The EP was enabled, disable it and wait. */
-			TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-			/* Ah, the luxury of busy-wait. */
-			while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
-		}
-	}
-
-	/* Note that we need to remove the urb from the urb list *before* removing its SB
-	   descriptors. (This means that the isoc eof handler might get a null urb when we
-	   are unlinking the last urb.) */
-
-	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-
-		urb_list_del(urb, epid);
-		TxBulkEPList[epid].sub = 0;
-		etrax_remove_from_sb_list(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-
-		urb_list_del(urb, epid);
-		TxCtrlEPList[epid].sub = 0;
-		etrax_remove_from_sb_list(urb);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
-
-		urb_list_del(urb, epid);
-		/* Sanity check (should never happen). */
-		assert(urb_list_empty(epid));
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-
-	} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-		if (usb_pipeout(urb->pipe)) {
-
-			USB_SB_Desc_t *iter_sb, *prev_sb, *next_sb;
-
-			if (__urb_list_entry(urb, epid)) {
-
-				urb_list_del(urb, epid);
-				iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
-				prev_sb = 0;
-				while (iter_sb && (iter_sb != urb_priv->first_sb)) {
-					prev_sb = iter_sb;
-					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				}
-
-				if (iter_sb == 0) {
-					/* Unlink of the URB currently being transmitted. */
-					prev_sb = 0;
-					iter_sb = TxIsocEPList[epid].sub ? phys_to_virt(TxIsocEPList[epid].sub) : 0;
-				}
-
-				while (iter_sb && (iter_sb != urb_priv->last_sb)) {
-					iter_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				}
-				if (iter_sb) {
-					next_sb = iter_sb->next ? phys_to_virt(iter_sb->next) : 0;
-				} else {
-					/* This should only happen if the DMA has completed
-					   processing the SB list for this EP while interrupts
-					   are disabled. */
-					dbg_isoc("Isoc urb not found, already sent?");
-					next_sb = 0;
-				}
-				if (prev_sb) {
-					prev_sb->next = next_sb ? virt_to_phys(next_sb) : 0;
-				} else {
-					TxIsocEPList[epid].sub = next_sb ? virt_to_phys(next_sb) : 0;
-				}
-
-				etrax_remove_from_sb_list(urb);
-				if (urb_list_empty(epid)) {
-					TxIsocEPList[epid].sub = 0;
-					dbg_isoc("Last isoc out urb epid %d", epid);
-				} else if (next_sb || prev_sb) {
-					dbg_isoc("Re-enable isoc out epid %d", epid);
-
-					TxIsocEPList[epid].hw_len = 0;
-					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-				} else {
-					TxIsocEPList[epid].sub = 0;
-					dbg_isoc("URB list non-empty and no SB list, EP disabled");
-				}
-			} else {
-				dbg_isoc("Urb 0x%p not found, completed already?", urb);
-			}
-		} else {
-
-			urb_list_del(urb, epid);
-
-			/* For in traffic there is only one SB descriptor for each EP even
-			   though there may be several urbs (all urbs point at the same SB). */
-			if (urb_list_empty(epid)) {
-				/* No more urbs, remove the SB. */
-				TxIsocEPList[epid].sub = 0;
-				etrax_remove_from_sb_list(urb);
-			} else {
-				TxIsocEPList[epid].hw_len = 0;
-				TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-			}
-		}
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 1);
-	}
-	/* Free the epid if urb list is empty. */
-	if (urb_list_empty(epid)) {
-		etrax_usb_free_epid(epid);
-	}
-	restore_flags(flags);
-
-	/* Must be done before calling completion handler. */
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-	return 0;
-}
-
-static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
-{
-	DBFENTER;
-	DBFEXIT;
-	return (*R_USB_FM_NUMBER & 0x7ff);
-}
-
-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc)
-{
-	DBFENTER;
-
-	/* This interrupt handler could be used when unlinking EP descriptors. */
-
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) {
-		USB_EP_Desc_t *ep;
-
-		//dbg_bulk("dma8_sub0_descr (BULK) intr.");
-
-		/* It should be safe clearing the interrupt here, since we don't expect to get a new
-		   one until we restart the bulk channel. */
-		*R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do);
-
-		/* Wait while the DMA is running (though we don't expect it to be). */
-		while (*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd));
-
-		/* Advance the DMA to the next EP descriptor. */
-		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
-
-		//dbg_bulk("descr intr: DMA is at 0x%lx", (unsigned long)ep);
-
-		/* ep->next is already a physical address; no need for a virt_to_phys. */
-		*R_DMA_CH8_SUB0_EP = ep->next;
-
-		/* Start the DMA bulk channel again. */
-		*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) {
-		struct urb *urb;
-		int epid;
-		etrax_urb_priv_t *urb_priv;
-		unsigned long int flags;
-
-		dbg_ctrl("dma8_sub1_descr (CTRL) intr.");
-		*R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do);
-
-		/* The complete callback gets called so we cli. */
-		save_flags(flags);
-		cli();
-
-		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-			if ((TxCtrlEPList[epid].sub == 0) ||
-			    (epid == DUMMY_EPID) ||
-			    (epid == INVALID_EPID)) {
-				/* Nothing here to see. */
-				continue;
-			}
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-
-			if (urb) {
-
-				/* Sanity check. */
-				assert(usb_pipetype(urb->pipe) == PIPE_CONTROL);
-
-				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-				assert(urb_priv);
-
-				if (urb_priv->urb_state == WAITING_FOR_DESCR_INTR) {
-					assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-
-					etrax_usb_complete_urb(urb, 0);
-				}
-			}
-		}
-		restore_flags(flags);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) {
-		dbg_intr("dma8_sub2_descr (INTR) intr.");
-		*R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do);
-	}
-	if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) {
-		struct urb *urb;
-		int epid;
-		int epid_done;
-		etrax_urb_priv_t *urb_priv;
-		USB_SB_Desc_t *sb_desc;
-
-		usb_isoc_complete_data_t *comp_data = NULL;
-
-		/* One or more isoc out transfers are done. */
-		dbg_isoc("dma8_sub3_descr (ISOC) intr.");
-
-		/* For each isoc out EP search for the first sb_desc with the intr flag
-		   set.  This descriptor must be the last packet from an URB.  Then
-		   traverse the URB list for the EP until the URB with urb_priv->last_sb
-		   matching the intr-marked sb_desc is found.  All URBs before this have
-		   been sent.
-		*/
-
-		for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-			/* Skip past epids with no SB lists, epids used for in traffic,
-			   and special (dummy, invalid) epids. */
-			if ((TxIsocEPList[epid].sub == 0) ||
-			    (test_bit(epid, (void *)&epid_out_traffic) == 0) ||
-			    (epid == DUMMY_EPID) ||
-			    (epid == INVALID_EPID)) {
-				/* Nothing here to see. */
-				continue;
-			}
-			sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
-
-			/* Find the last descriptor of the currently active URB for this ep.
-			   This is the first descriptor in the sub list marked for a descriptor
-			   interrupt. */
-			while (sb_desc && !IO_EXTRACT(USB_SB_command, intr, sb_desc->command)) {
-				sb_desc = sb_desc->next ? phys_to_virt(sb_desc->next) : 0;
-			}
-			assert(sb_desc);
-
-			dbg_isoc("Check epid %d, sub 0x%p, SB 0x%p",
-				 epid,
-				 phys_to_virt(TxIsocEPList[epid].sub),
-				 sb_desc);
-
-			epid_done = 0;
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-			assert(urb);
-
-			while (urb && !epid_done) {
-
-				/* Sanity check. */
-				assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
-
-				if (!usb_pipeout(urb->pipe)) {
-					/* descr interrupts are generated only for out pipes. */
-					epid_done = 1;
-					continue;
-				}
-
-				urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-				assert(urb_priv);
-
-				if (sb_desc != urb_priv->last_sb) {
-
-					/* This urb has been sent. */
-					dbg_isoc("out URB 0x%p sent", urb);
-
-					urb_priv->urb_state = TRANSFER_DONE;
-
-				} else if ((sb_desc == urb_priv->last_sb) &&
-					   !(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
-
-					assert((sb_desc->command & IO_MASK(USB_SB_command, eol)) == IO_STATE(USB_SB_command, eol, yes));
-					assert(sb_desc->next == 0);
-
-					dbg_isoc("out URB 0x%p last in list, epid disabled", urb);
-					TxIsocEPList[epid].sub = 0;
-					TxIsocEPList[epid].hw_len = 0;
-					urb_priv->urb_state = TRANSFER_DONE;
-
-					epid_done = 1;
-
-				} else {
-					epid_done = 1;
-				}
-				if (!epid_done) {
-					urb = urb_list_next(urb, epid);
-				}
-			}
-
-		}
-
-		*R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do);
-
-		comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC);
-		assert(comp_data != NULL);
-
-                INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data);
-                schedule_work(&comp_data->usb_bh);
-	}
-
-	DBFEXIT;
-        return IRQ_HANDLED;
-}
-
-static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
-{
-	usb_isoc_complete_data_t *comp_data = (usb_isoc_complete_data_t*)data;
-
-	struct urb *urb;
-	int epid;
-	int epid_done;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	dbg_isoc("dma8_sub3_descr (ISOC) bottom half.");
-
-	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-		unsigned long flags;
-
-		save_flags(flags);
-		cli();
-
-		epid_done = 0;
-
-		/* The descriptor interrupt handler has marked all transmitted isoch. out
-		   URBs with TRANSFER_DONE.  Now we traverse all epids and for all that
- 		   have isoch. out traffic traverse its URB list and complete the
-		   transmitted URB.
-		*/
-
-		while (!epid_done) {
-
-			/* Get the first urb (if any). */
-			urb = urb_list_first(epid);
-			if (urb == 0) {
-				epid_done = 1;
-				continue;
-			}
-
-			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
-					epid_done = 1;
-					continue;
-			}
-
-			if (!usb_pipeout(urb->pipe)) {
-				/* descr interrupts are generated only for out pipes. */
-				epid_done = 1;
-				continue;
-			}
-
-			dbg_isoc("Check epid %d, SB 0x%p", epid, (char*)TxIsocEPList[epid].sub);
-
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			if (urb_priv->urb_state == TRANSFER_DONE) {
-				int i;
-				struct usb_iso_packet_descriptor *packet;
-
-				/* This urb has been sent. */
-				dbg_isoc("Completing isoc out URB 0x%p", urb);
-
-				for (i = 0; i < urb->number_of_packets; i++) {
-					packet = &urb->iso_frame_desc[i];
-					packet->status = 0;
-					packet->actual_length = packet->length;
-				}
-
-				etrax_usb_complete_isoc_urb(urb, 0);
-
-				if (urb_list_empty(epid)) {
-					etrax_usb_free_epid(epid);
-					epid_done = 1;
-				}
-			} else {
-				epid_done = 1;
-			}
-		}
-		restore_flags(flags);
-
-	}
-	kmem_cache_free(isoc_compl_cache, comp_data);
-
-	DBFEXIT;
-}
-
-
-
-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc)
-{
-	struct urb *urb;
-	etrax_urb_priv_t *urb_priv;
-	int epid = 0;
-	unsigned long flags;
-
-	/* Isoc diagnostics. */
-	static int curr_fm = 0;
-	static int prev_fm = 0;
-
-	DBFENTER;
-
-	/* Clear this interrupt. */
-	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do);
-
-	/* Note that this while loop assumes that all packets span only
-	   one rx descriptor. */
-
-	/* The reason we cli here is that we call the driver's callback functions. */
-	save_flags(flags);
-	cli();
-
-	while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) {
-
-		epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status);
-		urb = urb_list_first(epid);
-
-		//printk("eop for epid %d, first urb 0x%lx\n", epid, (unsigned long)urb);
-
-		if (!urb) {
-			err("No urb for epid %d in rx interrupt", epid);
-			__dump_ept_data(epid);
-			goto skip_out;
-		}
-
-		/* Note that we cannot indescriminately assert(usb_pipein(urb->pipe)) since
-		   ctrl pipes are not. */
-
-		if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) {
-			__u32 r_usb_ept_data;
-			int no_error = 0;
-
-			assert(test_bit(epid, (void *)&epid_usage_bitmask));
-
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				r_usb_ept_data = *R_USB_EPT_DATA_ISO;
-
-				if ((r_usb_ept_data & IO_MASK(R_USB_EPT_DATA_ISO, valid)) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data) == 0) &&
-				    (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata))) {
-					/* Not an error, just a failure to receive an expected iso
-					   in packet in this frame.  This is not documented
-					   in the designers reference.
-					*/
-					no_error++;
-				} else {
-					warn("R_USB_EPT_DATA_ISO for epid %d = 0x%x", epid, r_usb_ept_data);
-				}
-			} else {
-				r_usb_ept_data = *R_USB_EPT_DATA;
-				warn("R_USB_EPT_DATA for epid %d = 0x%x", epid, r_usb_ept_data);
-			}
-
-			if (!no_error){
-				warn("error in rx desc->status, epid %d, first urb = 0x%lx",
-				     epid, (unsigned long)urb);
-				__dump_in_desc(myNextRxDesc);
-
-				warn("R_USB_STATUS = 0x%x", *R_USB_STATUS);
-
-				/* Check that ept was disabled when error occurred. */
-				switch (usb_pipetype(urb->pipe)) {
-				case PIPE_BULK:
-					assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_CONTROL:
-					assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_INTERRUPT:
-					assert(!(TxIntrEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				case PIPE_ISOCHRONOUS:
-					assert(!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-					break;
-				default:
-					warn("etrax_usb_rx_interrupt: bad pipetype %d in urb 0x%p",
-					     usb_pipetype(urb->pipe),
-					     urb);
-				}
-				etrax_usb_complete_urb(urb, -EPROTO);
-				goto skip_out;
-			}
-		}
-
-		urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-		assert(urb_priv);
-
-		if ((usb_pipetype(urb->pipe) == PIPE_BULK) ||
-		    (usb_pipetype(urb->pipe) == PIPE_CONTROL) ||
-		    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
-				/* We get nodata for empty data transactions, and the rx descriptor's
-				   hw_len field is not valid in that case. No data to copy in other
-				   words. */
-			} else {
-				/* Make sure the data fits in the buffer. */
-				assert(urb_priv->rx_offset + myNextRxDesc->hw_len
-				       <= urb->transfer_buffer_length);
-
-				memcpy(urb->transfer_buffer + urb_priv->rx_offset,
-				       phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len);
-				urb_priv->rx_offset += myNextRxDesc->hw_len;
-			}
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) {
-				if ((usb_pipetype(urb->pipe) == PIPE_CONTROL) &&
-				    ((TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)) ==
-				     IO_STATE(USB_EP_command, enable, yes))) {
-					/* The EP is still enabled, so the OUT packet used to ack
-					   the in data is probably not processed yet.  If the EP
-					   sub pointer has not moved beyond urb_priv->last_sb mark
-					   it for a descriptor interrupt and complete the urb in
-					   the descriptor interrupt handler.
-					*/
-					USB_SB_Desc_t *sub = TxCtrlEPList[urb_priv->epid].sub ? phys_to_virt(TxCtrlEPList[urb_priv->epid].sub) : 0;
-
-					while ((sub != NULL) && (sub != urb_priv->last_sb)) {
-						sub = sub->next ? phys_to_virt(sub->next) : 0;
-					}
-					if (sub != NULL) {
-						/* The urb has not been fully processed. */
-						urb_priv->urb_state = WAITING_FOR_DESCR_INTR;
-					} else {
-						warn("(CTRL) epid enabled and urb (0x%p) processed, ep->sub=0x%p", urb, (char*)TxCtrlEPList[urb_priv->epid].sub);
-						etrax_usb_complete_urb(urb, 0);
-					}
-				} else {
-					etrax_usb_complete_urb(urb, 0);
-				}
-			}
-
-		} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-
-			struct usb_iso_packet_descriptor *packet;
-
-			if (urb_priv->urb_state == UNLINK) {
-				info("Ignoring rx data for urb being unlinked.");
-				goto skip_out;
-			} else if (urb_priv->urb_state == NOT_STARTED) {
-				info("What? Got rx data for urb that isn't started?");
-				goto skip_out;
-			}
-
-			packet = &urb->iso_frame_desc[urb_priv->isoc_packet_counter];
-			packet->status = 0;
-
-			if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) {
-				/* We get nodata for empty data transactions, and the rx descriptor's
-				   hw_len field is not valid in that case. We copy 0 bytes however to
-				   stay in synch. */
-				packet->actual_length = 0;
-			} else {
-				packet->actual_length = myNextRxDesc->hw_len;
-				/* Make sure the data fits in the buffer. */
-				assert(packet->actual_length <= packet->length);
-				memcpy(urb->transfer_buffer + packet->offset,
-				       phys_to_virt(myNextRxDesc->buf), packet->actual_length);
-			}
-
-			/* Increment the packet counter. */
-			urb_priv->isoc_packet_counter++;
-
-			/* Note that we don't care about the eot field in the rx descriptor's status.
-			   It will always be set for isoc traffic. */
-			if (urb->number_of_packets == urb_priv->isoc_packet_counter) {
-
-				/* Out-of-synch diagnostics. */
-				curr_fm = (*R_USB_FM_NUMBER & 0x7ff);
-				if (((prev_fm + urb_priv->isoc_packet_counter) % (0x7ff + 1)) != curr_fm) {
-					/* This test is wrong, if there is more than one isoc
-					   in endpoint active it will always calculate wrong
-					   since prev_fm is shared by all endpoints.
-
-					   FIXME Make this check per URB using urb->start_frame.
-					*/
-					dbg_isoc("Out of synch? Previous frame = %d, current frame = %d",
-						 prev_fm, curr_fm);
-
-				}
-				prev_fm = curr_fm;
-
-				/* Complete the urb with status OK. */
-				etrax_usb_complete_isoc_urb(urb, 0);
-			}
-		}
-
-	skip_out:
-
-		/* DMA IN cache bug. Flush the DMA IN buffer from the cache. (struct etrax_dma_descr
-		   has the same layout as USB_IN_Desc for the relevant fields.) */
-		prepare_rx_descriptor((struct etrax_dma_descr*)myNextRxDesc);
-
-		myPrevRxDesc = myNextRxDesc;
-		myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol);
-		myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol);
-		myLastRxDesc = myPrevRxDesc;
-
-		myNextRxDesc->status = 0;
-		myNextRxDesc = phys_to_virt(myNextRxDesc->next);
-	}
-
-	restore_flags(flags);
-
-	DBFEXIT;
-
-        return IRQ_HANDLED;
-}
-
-
-/* This function will unlink the SB descriptors associated with this urb. */
-static int etrax_remove_from_sb_list(struct urb *urb)
-{
-	USB_SB_Desc_t *next_sb, *first_sb, *last_sb;
-	etrax_urb_priv_t *urb_priv;
-	int i = 0;
-
-	DBFENTER;
-
-	urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	assert(urb_priv);
-
-	/* Just a sanity check. Since we don't fiddle with the DMA list the EP descriptor
-	   doesn't really need to be disabled, it's just that we expect it to be. */
-	if (usb_pipetype(urb->pipe) == PIPE_BULK) {
-		assert(!(TxBulkEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-	} else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) {
-		assert(!(TxCtrlEPList[urb_priv->epid].command & IO_MASK(USB_EP_command, enable)));
-	}
-
-	first_sb = urb_priv->first_sb;
-	last_sb = urb_priv->last_sb;
-
-	assert(first_sb);
-	assert(last_sb);
-
-	while (first_sb != last_sb) {
-		next_sb = (USB_SB_Desc_t *)phys_to_virt(first_sb->next);
-		kmem_cache_free(usb_desc_cache, first_sb);
-		first_sb = next_sb;
-		i++;
-	}
-	kmem_cache_free(usb_desc_cache, last_sb);
-	i++;
-	dbg_sb("%d SB descriptors freed", i);
-	/* Compare i with urb->number_of_packets for Isoc traffic.
-	   Should be same when calling unlink_urb */
-
-	DBFEXIT;
-
-	return i;
-}
-
-static int etrax_usb_submit_bulk_urb(struct urb *urb)
-{
-	int epid;
-	int empty;
-	unsigned long flags;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	/* Epid allocation, empty check and list add must be protected.
-	   Read about this in etrax_usb_submit_ctrl_urb. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		return -ENOMEM;
-	}
-	empty = urb_list_empty(epid);
-	urb_list_add(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	dbg_bulk("Adding bulk %s urb 0x%lx to %s list, epid %d",
-		 usb_pipein(urb->pipe) ? "IN" : "OUT", (unsigned long)urb, empty ? "empty" : "", epid);
-
-	/* Mark the urb as being in progress. */
-	urb->status = -EINPROGRESS;
-
-	/* Setup the hcpriv data. */
-	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	/* This sets rx_offset to 0. */
-	urb_priv->urb_state = NOT_STARTED;
-	urb->hcpriv = urb_priv;
-
-	if (empty) {
-		etrax_usb_add_to_bulk_sb_list(urb, epid);
-	}
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
-{
-	USB_SB_Desc_t *sb_desc;
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	unsigned long flags;
-	char maxlen;
-
-	DBFENTER;
-
-	dbg_bulk("etrax_usb_add_to_bulk_sb_list, urb 0x%lx", (unsigned long)urb);
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-
-	sb_desc = kmem_cache_zalloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc != NULL);
-
-
-	if (usb_pipeout(urb->pipe)) {
-
-		dbg_bulk("Grabbing bulk OUT, urb 0x%lx, epid %d", (unsigned long)urb, epid);
-
-		/* This is probably a sanity check of the bulk transaction length
-		   not being larger than 64 kB. */
-		if (urb->transfer_buffer_length > 0xffff) {
-			panic("urb->transfer_buffer_length > 0xffff");
-		}
-
-		sb_desc->sw_len = urb->transfer_buffer_length;
-
-		/* The rem field is don't care if it's not a full-length transfer, so setting
-		   it shouldn't hurt. Also, rem isn't used for OUT traffic. */
-		sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
-				    IO_STATE(USB_SB_command, tt, out) |
-				    IO_STATE(USB_SB_command, eot, yes) |
-				    IO_STATE(USB_SB_command, eol, yes));
-
-		/* The full field is set to yes, even if we don't actually check that this is
-		   a full-length transfer (i.e., that transfer_buffer_length % maxlen = 0).
-		   Setting full prevents the USB controller from sending an empty packet in
-		   that case.  However, if URB_ZERO_PACKET was set we want that. */
-		if (!(urb->transfer_flags & URB_ZERO_PACKET)) {
-			sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
-		}
-
-		sb_desc->buf = virt_to_phys(urb->transfer_buffer);
-		sb_desc->next = 0;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_bulk("Grabbing bulk IN, urb 0x%lx, epid %d", (unsigned long)urb, epid);
-
-		sb_desc->sw_len = urb->transfer_buffer_length ?
-			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-
-		/* The rem field is don't care if it's not a full-length transfer, so setting
-		   it shouldn't hurt. */
-		sb_desc->command =
-			(IO_FIELD(USB_SB_command, rem,
-				  urb->transfer_buffer_length % maxlen) |
-			 IO_STATE(USB_SB_command, tt, in) |
-			 IO_STATE(USB_SB_command, eot, yes) |
-			 IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc->buf = 0;
-		sb_desc->next = 0;
-	}
-
-	urb_priv->first_sb = sb_desc;
-	urb_priv->last_sb = sb_desc;
-	urb_priv->epid = epid;
-
-	urb->hcpriv = urb_priv;
-
-	/* Reset toggle bits and reset error count. */
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	/* FIXME: Is this a special case since the hold field is checked,
-	   or should we check hold in a lot of other cases as well? */
-	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
-		panic("Hold was set in %s", __FUNCTION__);
-	}
-
-	/* Reset error counters (regardless of which direction this traffic is). */
-	*R_USB_EPT_DATA &=
-		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
-		  IO_MASK(R_USB_EPT_DATA, error_count_out));
-
-	/* Software must preset the toggle bits. */
-	if (usb_pipeout(urb->pipe)) {
-		char toggle =
-			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out);
-		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle);
-	} else {
-		char toggle =
-			usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-		*R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in);
-		*R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle);
-	}
-
-	/* Assert that the EP descriptor is disabled. */
-	assert(!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-
-	/* The reason we set the EP's sub pointer directly instead of
-	   walking the SB list and linking it last in the list is that we only
-	   have one active urb at a time (the rest are queued). */
-
-	/* Note that we cannot have interrupts running when we have set the SB descriptor
-	   but the EP is not yet enabled.  If a bulk eot happens for another EP, we will
-	   find this EP disabled and with a SB != 0, which will make us think that it's done. */
-	TxBulkEPList[epid].sub = virt_to_phys(sb_desc);
-	TxBulkEPList[epid].hw_len = 0;
-	/* Note that we don't have to fill in the ep_id field since this
-	   was done when we allocated the EP descriptors in init_tx_bulk_ep. */
-
-	/* Check if the dummy list is already with us (if several urbs were queued). */
-	if (TxBulkEPList[epid].next != virt_to_phys(&TxBulkDummyEPList[epid][0])) {
-
-		dbg_bulk("Inviting dummy list to the party for urb 0x%lx, epid %d",
-			 (unsigned long)urb, epid);
-
-		/* The last EP in the dummy list already has its next pointer set to
-		   TxBulkEPList[epid].next. */
-
-		/* We don't need to check if the DMA is at this EP or not before changing the
-		   next pointer, since we will do it in one 32-bit write (EP descriptors are
-		   32-bit aligned). */
-		TxBulkEPList[epid].next = virt_to_phys(&TxBulkDummyEPList[epid][0]);
-	}
-	/* Enable the EP descr. */
-	dbg_bulk("Enabling bulk EP for urb 0x%lx, epid %d", (unsigned long)urb, epid);
-	TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-	/* Everything is set up, safe to enable interrupts again. */
-	restore_flags(flags);
-
-	/* If the DMA bulk channel isn't running, we need to restart it if it
-	   has stopped at the last EP descriptor (DMA stopped because there was
-	   no more traffic) or if it has stopped at a dummy EP with the intr flag
-	   set (DMA stopped because we were too slow in inserting new traffic). */
-	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
-
-		USB_EP_Desc_t *ep;
-		ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB0_EP);
-		dbg_bulk("DMA channel not running in add");
-		dbg_bulk("DMA is at 0x%lx", (unsigned long)ep);
-
-		if (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[NBR_OF_EPIDS - 1]) ||
-		    (ep->command & 0x8) >> 3) {
-			*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-			/* Update/restart the bulk start timer since we just started the channel. */
-			mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
-			/* Update/restart the bulk eot timer since we just inserted traffic. */
-			mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-		}
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_bulk_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing bulk urb with status %d.", status);
-
-	dbg_bulk("Completing bulk urb 0x%lx for epid %d", (unsigned long)urb, epid);
-
-	/* Update the urb list. */
-	urb_list_del(urb, epid);
-
-	/* For an IN pipe, we always set the actual length, regardless of whether there was
-	   an error or not (which means the device driver can use the data if it wants to). */
-	if (usb_pipein(urb->pipe)) {
-		urb->actual_length = urb_priv->rx_offset;
-	} else {
-		/* Set actual_length for OUT urbs also; the USB mass storage driver seems
-		   to want that. We wouldn't know of any partial writes if there was an error. */
-		if (status == 0) {
-			urb->actual_length = urb->transfer_buffer_length;
-		} else {
-			urb->actual_length = 0;
-		}
-	}
-
-	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
-	   Like, maybe we shouldn't toggle the toggle bits, or maybe we shouldn't insert more traffic. */
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-
-	/* We need to fiddle with the toggle bits because the hardware doesn't do it for us. */
-	if (usb_pipeout(urb->pipe)) {
-		char toggle =
-			IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA);
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			      usb_pipeout(urb->pipe), toggle);
-	} else {
-		char toggle =
-			IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA);
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			      usb_pipeout(urb->pipe), toggle);
-	}
-	restore_flags(flags);
-
-	/* Remember to free the SBs. */
-	etrax_remove_from_sb_list(urb);
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	/* If there are any more urb's in the list we'd better start sending */
-	if (!urb_list_empty(epid)) {
-
-		struct urb *new_urb;
-
-		/* Get the first urb. */
-		new_urb = urb_list_first(epid);
-		assert(new_urb);
-
-		dbg_bulk("More bulk for epid %d", epid);
-
-		etrax_usb_add_to_bulk_sb_list(new_urb, epid);
-	}
-
-	urb->status = status;
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (usb_pipein(urb->pipe) &&
-			    (urb->actual_length !=
-			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (urb_list_empty(epid)) {
-		/* This means that this EP is now free, deconfigure it. */
-		etrax_usb_free_epid(epid);
-
-		/* No more traffic; time to clean up.
-		   Must set sub pointer to 0, since we look at the sub pointer when handling
-		   the bulk eot interrupt. */
-
-		dbg_bulk("No bulk for epid %d", epid);
-
-		TxBulkEPList[epid].sub = 0;
-
-		/* Unlink the dummy list. */
-
-		dbg_bulk("Kicking dummy list out of party for urb 0x%lx, epid %d",
-			 (unsigned long)urb, epid);
-
-		/* No need to wait for the DMA before changing the next pointer.
-		   The modulo NBR_OF_EPIDS isn't actually necessary, since we will never use
-		   the last one (INVALID_EPID) for actual traffic. */
-		TxBulkEPList[epid].next =
-			virt_to_phys(&TxBulkEPList[(epid + 1) % NBR_OF_EPIDS]);
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_submit_ctrl_urb(struct urb *urb)
-{
-	int epid;
-	int empty;
-	unsigned long flags;
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	/* FIXME: Return -ENXIO if there is already a queued urb for this endpoint? */
-
-	/* Epid allocation, empty check and list add must be protected.
-
-	   Epid allocation because if we find an existing epid for this endpoint an urb might be
-	   completed (emptying the list) before we add the new urb to the list, causing the epid
-	   to be de-allocated. We would then start the transfer with an invalid epid -> epid attn.
-
-	   Empty check and add because otherwise we might conclude that the list is not empty,
-	   after which it becomes empty before we add the new urb to the list, causing us not to
-	   insert the new traffic into the SB list. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		DBFEXIT;
-		return -ENOMEM;
-	}
-	empty = urb_list_empty(epid);
-	urb_list_add(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	dbg_ctrl("Adding ctrl urb 0x%lx to %s list, epid %d",
-		 (unsigned long)urb, empty ? "empty" : "", epid);
-
-	/* Mark the urb as being in progress. */
-	urb->status = -EINPROGRESS;
-
-	/* Setup the hcpriv data. */
-	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	/* This sets rx_offset to 0. */
-	urb_priv->urb_state = NOT_STARTED;
-	urb->hcpriv = urb_priv;
-
-	if (empty) {
-		etrax_usb_add_to_ctrl_sb_list(urb, epid);
-	}
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_add_to_ctrl_sb_list(struct urb *urb, int epid)
-{
-	USB_SB_Desc_t *sb_desc_setup;
-	USB_SB_Desc_t *sb_desc_data;
-	USB_SB_Desc_t *sb_desc_status;
-
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-
-	unsigned long flags;
-	char maxlen;
-
-	DBFENTER;
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-
-	sb_desc_setup = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc_setup != NULL);
-	sb_desc_status = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-	assert(sb_desc_status != NULL);
-
-	/* Initialize the mandatory setup SB descriptor (used only in control transfers) */
-	sb_desc_setup->sw_len = 8;
-	sb_desc_setup->command = (IO_FIELD(USB_SB_command, rem, 0) |
-				  IO_STATE(USB_SB_command, tt, setup) |
-				  IO_STATE(USB_SB_command, full, yes) |
-				  IO_STATE(USB_SB_command, eot, yes));
-
-	sb_desc_setup->buf = virt_to_phys(urb->setup_packet);
-
-	if (usb_pipeout(urb->pipe)) {
-		dbg_ctrl("Transfer for epid %d is OUT", epid);
-
-		/* If this Control OUT transfer has an optional data stage we add an OUT token
-		   before the mandatory IN (status) token, hence the reordered SB list */
-
-		sb_desc_setup->next = virt_to_phys(sb_desc_status);
-		if (urb->transfer_buffer) {
-
-			dbg_ctrl("This OUT transfer has an extra data stage");
-
-			sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-			assert(sb_desc_data != NULL);
-
-			sb_desc_setup->next = virt_to_phys(sb_desc_data);
-
-			sb_desc_data->sw_len = urb->transfer_buffer_length;
-			sb_desc_data->command = (IO_STATE(USB_SB_command, tt, out) |
-						 IO_STATE(USB_SB_command, full, yes) |
-						 IO_STATE(USB_SB_command, eot, yes));
-			sb_desc_data->buf = virt_to_phys(urb->transfer_buffer);
-			sb_desc_data->next = virt_to_phys(sb_desc_status);
-		}
-
-		sb_desc_status->sw_len = 1;
-		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
-					   IO_STATE(USB_SB_command, tt, in) |
-					   IO_STATE(USB_SB_command, eot, yes) |
-					   IO_STATE(USB_SB_command, intr, yes) |
-					   IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc_status->buf = 0;
-		sb_desc_status->next = 0;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_ctrl("Transfer for epid %d is IN", epid);
-		dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length);
-		dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen);
-
-		sb_desc_data = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-		assert(sb_desc_data != NULL);
-
-		sb_desc_setup->next = virt_to_phys(sb_desc_data);
-
-		sb_desc_data->sw_len = urb->transfer_buffer_length ?
-			(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-		dbg_ctrl("sw_len got %d", sb_desc_data->sw_len);
-
-		sb_desc_data->command =
-			(IO_FIELD(USB_SB_command, rem,
-				  urb->transfer_buffer_length % maxlen) |
-			 IO_STATE(USB_SB_command, tt, in) |
-			 IO_STATE(USB_SB_command, eot, yes));
-
-		sb_desc_data->buf = 0;
-		sb_desc_data->next = virt_to_phys(sb_desc_status);
-
-		/* Read comment at zout_buffer declaration for an explanation to this. */
-		sb_desc_status->sw_len = 1;
-		sb_desc_status->command = (IO_FIELD(USB_SB_command, rem, 0) |
-					   IO_STATE(USB_SB_command, tt, zout) |
-					   IO_STATE(USB_SB_command, full, yes) |
-					   IO_STATE(USB_SB_command, eot, yes) |
-					   IO_STATE(USB_SB_command, intr, yes) |
-					   IO_STATE(USB_SB_command, eol, yes));
-
-		sb_desc_status->buf = virt_to_phys(&zout_buffer[0]);
-		sb_desc_status->next = 0;
-	}
-
-	urb_priv->first_sb = sb_desc_setup;
-	urb_priv->last_sb = sb_desc_status;
-	urb_priv->epid = epid;
-
-	urb_priv->urb_state = STARTED;
-
-	/* Reset toggle bits and reset error count, remember to di and ei */
-	/* Warning: it is possible that this locking doesn't work with bottom-halves */
-
-	save_flags(flags);
-	cli();
-
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) {
-		panic("Hold was set in %s", __FUNCTION__);
-	}
-
-
-	/* FIXME: Compare with etrax_usb_add_to_bulk_sb_list where the toggle bits
-	   are set to a specific value. Why the difference? Read "Transfer and Toggle Bits
-	   in Designer's Reference, p. 8 - 11. */
-	*R_USB_EPT_DATA &=
-		~(IO_MASK(R_USB_EPT_DATA, error_count_in) |
-		  IO_MASK(R_USB_EPT_DATA, error_count_out) |
-		  IO_MASK(R_USB_EPT_DATA, t_in) |
-		  IO_MASK(R_USB_EPT_DATA, t_out));
-
-	/* Since we use the rx interrupt to complete ctrl urbs, we can enable interrupts now
-	   (i.e. we don't check the sub pointer on an eot interrupt like we do for bulk traffic). */
-	restore_flags(flags);
-
-	/* Assert that the EP descriptor is disabled. */
-	assert(!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)));
-
-	/* Set up and enable the EP descriptor. */
-	TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_setup);
-	TxCtrlEPList[epid].hw_len = 0;
-	TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-	/* We start the DMA sub channel without checking if it's running or not, because:
-	   1) If it's already running, issuing the start command is a nop.
-	   2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_ctrl_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing ctrl urb with status %d.", status);
-
-	dbg_ctrl("Completing ctrl epid %d, urb 0x%lx", epid, (unsigned long)urb);
-
-	/* Remove this urb from the list. */
-	urb_list_del(urb, epid);
-
-	/* For an IN pipe, we always set the actual length, regardless of whether there was
-	   an error or not (which means the device driver can use the data if it wants to). */
-	if (usb_pipein(urb->pipe)) {
-		urb->actual_length = urb_priv->rx_offset;
-	}
-
-	/* FIXME: Is there something of the things below we shouldn't do if there was an error?
-	   Like, maybe we shouldn't insert more traffic. */
-
-	/* Remember to free the SBs. */
-	etrax_remove_from_sb_list(urb);
-	kfree(urb_priv);
-	urb->hcpriv = 0;
-
-	/* If there are any more urbs in the list we'd better start sending. */
-	if (!urb_list_empty(epid)) {
-		struct urb *new_urb;
-
-		/* Get the first urb. */
-		new_urb = urb_list_first(epid);
-		assert(new_urb);
-
-		dbg_ctrl("More ctrl for epid %d, first urb = 0x%lx", epid, (unsigned long)new_urb);
-
-		etrax_usb_add_to_ctrl_sb_list(new_urb, epid);
-	}
-
-	urb->status = status;
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (usb_pipein(urb->pipe) &&
-			    (urb->actual_length !=
-			     usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (urb_list_empty(epid)) {
-		/* No more traffic. Time to clean up. */
-		etrax_usb_free_epid(epid);
-		/* Must set sub pointer to 0. */
-		dbg_ctrl("No ctrl for epid %d", epid);
-		TxCtrlEPList[epid].sub = 0;
-	}
-
-	DBFEXIT;
-}
-
-static int etrax_usb_submit_intr_urb(struct urb *urb)
-{
-
-	int epid;
-
-	DBFENTER;
-
-	if (usb_pipeout(urb->pipe)) {
-		/* Unsupported transfer type.
-		   We don't support interrupt out traffic. (If we do, we can't support
-		   intervals for neither in or out traffic, but are forced to schedule all
-		   interrupt traffic in one frame.) */
-		return -EINVAL;
-	}
-
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		return -ENOMEM;
-	}
-
-	if (!urb_list_empty(epid)) {
-		/* There is already a queued urb for this endpoint. */
-		etrax_usb_free_epid(epid);
-		return -ENXIO;
-	}
-
-	urb->status = -EINPROGRESS;
-
-	dbg_intr("Add intr urb 0x%lx, to list, epid %d", (unsigned long)urb, epid);
-
-	urb_list_add(urb, epid);
-	etrax_usb_add_to_intr_sb_list(urb, epid);
-
-	return 0;
-
-	DBFEXIT;
-}
-
-static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
-{
-
-	volatile USB_EP_Desc_t *tmp_ep;
-	volatile USB_EP_Desc_t *first_ep;
-
-	char maxlen;
-	int interval;
-	int i;
-
-	etrax_urb_priv_t *urb_priv;
-
-	DBFENTER;
-
-	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	interval = urb->interval;
-
-	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
-	assert(urb_priv != NULL);
-	urb->hcpriv = urb_priv;
-
-	first_ep = &TxIntrEPList[0];
-
-	/* Round of the interval to 2^n, it is obvious that this code favours
-	   smaller numbers, but that is actually a good thing */
-	/* FIXME: The "rounding error" for larger intervals will be quite
-	   large. For in traffic this shouldn't be a problem since it will only
-	   mean that we "poll" more often. */
-	for (i = 0; interval; i++) {
-		interval = interval >> 1;
-	}
-	interval = 1 << (i - 1);
-
-	dbg_intr("Interval rounded to %d", interval);
-
-	tmp_ep = first_ep;
-	i = 0;
-	do {
-		if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) {
-			if ((i % interval) == 0) {
-				/* Insert the traffic ep after tmp_ep */
-				USB_EP_Desc_t *ep_desc;
-				USB_SB_Desc_t *sb_desc;
-
-				dbg_intr("Inserting EP for epid %d", epid);
-
-				ep_desc = (USB_EP_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-				sb_desc = (USB_SB_Desc_t *)
-					kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
-				assert(ep_desc != NULL);
-				CHECK_ALIGN(ep_desc);
-				assert(sb_desc != NULL);
-
-				ep_desc->sub = virt_to_phys(sb_desc);
-				ep_desc->hw_len = 0;
-				ep_desc->command = (IO_FIELD(USB_EP_command, epid, epid) |
-						    IO_STATE(USB_EP_command, enable, yes));
-
-
-				/* Round upwards the number of packets of size maxlen
-				   that this SB descriptor should receive. */
-				sb_desc->sw_len = urb->transfer_buffer_length ?
-					(urb->transfer_buffer_length - 1) / maxlen + 1 : 0;
-				sb_desc->next = 0;
-				sb_desc->buf = 0;
-				sb_desc->command =
-					(IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) |
-					 IO_STATE(USB_SB_command, tt, in) |
-					 IO_STATE(USB_SB_command, eot, yes) |
-					 IO_STATE(USB_SB_command, eol, yes));
-
-				ep_desc->next = tmp_ep->next;
-				tmp_ep->next = virt_to_phys(ep_desc);
-			}
-			i++;
-		}
-		tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next);
-	} while (tmp_ep != first_ep);
-
-
-	/* Note that first_sb/last_sb doesn't apply to interrupt traffic. */
-	urb_priv->epid = epid;
-
-	/* We start the DMA sub channel without checking if it's running or not, because:
-	   1) If it's already running, issuing the start command is a nop.
-	   2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-
-
-static void etrax_usb_complete_intr_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-
-	DBFENTER;
-
-	if (status)
-		warn("Completing intr urb with status %d.", status);
-
-	dbg_intr("Completing intr epid %d, urb 0x%lx", epid, (unsigned long)urb);
-
-	urb->status = status;
-	urb->actual_length = urb_priv->rx_offset;
-
-	dbg_intr("interrupt urb->actual_length = %d", urb->actual_length);
-
-	/* We let any non-zero status from the layer above have precedence. */
-	if (status == 0) {
-		/* URB_SHORT_NOT_OK means that short reads (shorter than the endpoint's max length)
-		   is to be treated as an error. */
-		if (urb->transfer_flags & URB_SHORT_NOT_OK) {
-			if (urb->actual_length !=
-			    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
-				urb->status = -EREMOTEIO;
-			}
-		}
-	}
-
-	/* The driver will resubmit the URB so we need to remove it first */
-        etrax_usb_unlink_urb(urb, 0);
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	DBFEXIT;
-}
-
-
-static int etrax_usb_submit_isoc_urb(struct urb *urb)
-{
-	int epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	dbg_isoc("Submitting isoc urb = 0x%lx", (unsigned long)urb);
-
-	/* Epid allocation, empty check and list add must be protected.
-	   Read about this in etrax_usb_submit_ctrl_urb. */
-
-	spin_lock_irqsave(&urb_list_lock, flags);
-	/* Is there an active epid for this urb ? */
-	epid = etrax_usb_setup_epid(urb);
-	if (epid == -1) {
-		DBFEXIT;
-		spin_unlock_irqrestore(&urb_list_lock, flags);
-		return -ENOMEM;
-	}
-
-	/* Ok, now we got valid endpoint, lets insert some traffic */
-
-	urb->status = -EINPROGRESS;
-
-	/* Find the last urb in the URB_List and add this urb after that one.
-	   Also add the traffic, that is do an etrax_usb_add_to_isoc_sb_list.  This
-	   is important to make this in "real time" since isochronous traffic is
-	   time sensitive. */
-
-	dbg_isoc("Adding isoc urb to (possibly empty) list");
-	urb_list_add(urb, epid);
-	etrax_usb_add_to_isoc_sb_list(urb, epid);
-	spin_unlock_irqrestore(&urb_list_lock, flags);
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_check_error_isoc_ep(const int epid)
-{
-	unsigned long int flags;
-	int error_code;
-	__u32 r_usb_ept_data;
-
-	/* We can't read R_USB_EPID_ATTN here since it would clear the iso_eof,
-	   bulk_eot and epid_attn interrupts.  So we just check the status of
-	   the epid without testing if for it in R_USB_EPID_ATTN. */
-
-
-	save_flags(flags);
-	cli();
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-	nop();
-	/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
-	   registers, they are located at the same address and are of the same size.
-	   In other words, this read should be ok for isoc also. */
-	r_usb_ept_data = *R_USB_EPT_DATA;
-	restore_flags(flags);
-
-	error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
-
-	if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
-		warn("Hold was set for epid %d.", epid);
-		return;
-	}
-
-	if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, no_error)) {
-
-		/* This indicates that the SB list of the ept was completed before
-		   new data was appended to it.  This is not an error, but indicates
-		   large system or USB load and could possibly cause trouble for
-		   very timing sensitive USB device drivers so we log it.
-		*/
-		info("Isoc. epid %d disabled with no error", epid);
-		return;
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, stall)) {
-		/* Not really a protocol error, just says that the endpoint gave
-		   a stall response. Note that error_code cannot be stall for isoc. */
-		panic("Isoc traffic cannot stall");
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA_ISO, error_code, bus_error)) {
-		/* Two devices responded to a transaction request. Must be resolved
-		   by software. FIXME: Reset ports? */
-		panic("Bus error for epid %d."
-		      " Two devices responded to transaction request",
-		      epid);
-
-	} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
-		/* DMA overrun or underrun. */
-		warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-
-		/* It seems that error_code = buffer_error in
-		   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
-		   are the same error. */
-	}
-}
-
-
-static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
-{
-
-	int i = 0;
-
-	etrax_urb_priv_t *urb_priv;
-	USB_SB_Desc_t *prev_sb_desc,  *next_sb_desc, *temp_sb_desc;
-
-	DBFENTER;
-
-	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
-
-	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
-	assert(urb_priv != NULL);
-
-	urb->hcpriv = urb_priv;
-	urb_priv->epid = epid;
-
-	if (usb_pipeout(urb->pipe)) {
-
-		if (urb->number_of_packets == 0) panic("etrax_usb_add_to_isoc_sb_list 0 packets\n");
-
-		dbg_isoc("Transfer for epid %d is OUT", epid);
-		dbg_isoc("%d packets in URB", urb->number_of_packets);
-
-		/* Create one SB descriptor for each packet and link them together. */
-		for (i = 0; i < urb->number_of_packets; i++) {
-			if (!urb->iso_frame_desc[i].length)
-				continue;
-
-			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC);
-			assert(next_sb_desc != NULL);
-
-			if (urb->iso_frame_desc[i].length > 0) {
-
-				next_sb_desc->command = (IO_STATE(USB_SB_command, tt, out) |
-							 IO_STATE(USB_SB_command, eot, yes));
-
-				next_sb_desc->sw_len = urb->iso_frame_desc[i].length;
-				next_sb_desc->buf = virt_to_phys((char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset);
-
-				/* Check if full length transfer. */
-				if (urb->iso_frame_desc[i].length ==
-				    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) {
-					next_sb_desc->command |= IO_STATE(USB_SB_command, full, yes);
-				}
-			} else {
-				dbg_isoc("zero len packet");
-				next_sb_desc->command = (IO_FIELD(USB_SB_command, rem, 0) |
-							 IO_STATE(USB_SB_command, tt, zout) |
-							 IO_STATE(USB_SB_command, eot, yes) |
-							 IO_STATE(USB_SB_command, full, yes));
-
-				next_sb_desc->sw_len = 1;
-				next_sb_desc->buf = virt_to_phys(&zout_buffer[0]);
-			}
-
-			/* First SB descriptor that belongs to this urb */
-			if (i == 0)
-				urb_priv->first_sb = next_sb_desc;
-			else
-				prev_sb_desc->next = virt_to_phys(next_sb_desc);
-
-			prev_sb_desc = next_sb_desc;
-		}
-
-		next_sb_desc->command |= (IO_STATE(USB_SB_command, intr, yes) |
-					  IO_STATE(USB_SB_command, eol, yes));
-		next_sb_desc->next = 0;
-		urb_priv->last_sb = next_sb_desc;
-
-	} else if (usb_pipein(urb->pipe)) {
-
-		dbg_isoc("Transfer for epid %d is IN", epid);
-		dbg_isoc("transfer_buffer_length = %d", urb->transfer_buffer_length);
-		dbg_isoc("rem is calculated to %d", urb->iso_frame_desc[urb->number_of_packets - 1].length);
-
-		/* Note that in descriptors for periodic traffic are not consumed. This means that
-		   the USB controller never propagates in the SB list. In other words, if there already
-		   is an SB descriptor in the list for this EP we don't have to do anything. */
-		if (TxIsocEPList[epid].sub == 0) {
-			dbg_isoc("Isoc traffic not already running, allocating SB");
-
-			next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC);
-			assert(next_sb_desc != NULL);
-
-			next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) |
-						 IO_STATE(USB_SB_command, eot, yes) |
-						 IO_STATE(USB_SB_command, eol, yes));
-
-			next_sb_desc->next = 0;
-			next_sb_desc->sw_len = 1; /* Actual number of packets is not relevant
-						     for periodic in traffic as long as it is more
-						     than zero.  Set to 1 always. */
-			next_sb_desc->buf = 0;
-
-			/* The rem field is don't care for isoc traffic, so we don't set it. */
-
-			/* Only one SB descriptor that belongs to this urb. */
-			urb_priv->first_sb = next_sb_desc;
-			urb_priv->last_sb = next_sb_desc;
-
-		} else {
-
-			dbg_isoc("Isoc traffic already running, just setting first/last_sb");
-
-			/* Each EP for isoc in will have only one SB descriptor, setup when submitting the
-			   already active urb. Note that even though we may have several first_sb/last_sb
-			   pointing at the same SB descriptor, they are freed only once (when the list has
-			   become empty). */
-			urb_priv->first_sb = phys_to_virt(TxIsocEPList[epid].sub);
-			urb_priv->last_sb = phys_to_virt(TxIsocEPList[epid].sub);
-			return;
-		}
-
-	}
-
-	/* Find the spot to insert this urb and add it. */
-	if (TxIsocEPList[epid].sub == 0) {
-		/* First SB descriptor inserted in this list (in or out). */
-		dbg_isoc("Inserting SB desc first in list");
-		TxIsocEPList[epid].hw_len = 0;
-		TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
-
-	} else {
-		/* Isochronous traffic is already running, insert new traffic last (only out). */
-		dbg_isoc("Inserting SB desc last in list");
-		temp_sb_desc = phys_to_virt(TxIsocEPList[epid].sub);
-		while ((temp_sb_desc->command & IO_MASK(USB_SB_command, eol)) !=
-		       IO_STATE(USB_SB_command, eol, yes)) {
-			assert(temp_sb_desc->next);
-			temp_sb_desc = phys_to_virt(temp_sb_desc->next);
-		}
-		dbg_isoc("Appending list on desc 0x%p", temp_sb_desc);
-
-		/* Next pointer must be set before eol is removed. */
-		temp_sb_desc->next = virt_to_phys(urb_priv->first_sb);
-		/* Clear the previous end of list flag since there is a new in the
-		   added SB descriptor list. */
-		temp_sb_desc->command &= ~IO_MASK(USB_SB_command, eol);
-
-		if (!(TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable))) {
-			/* 8.8.5 in Designer's Reference says we should check for and correct
-			   any errors in the EP here.  That should not be necessary if epid_attn
-			   is handled correctly, so we assume all is ok. */
-			dbg_isoc("EP disabled");
-			etrax_usb_check_error_isoc_ep(epid);
-
-			/* The SB list was exhausted. */
-			if (virt_to_phys(urb_priv->last_sb) != TxIsocEPList[epid].sub) {
-				/* The new sublist did not get processed before the EP was
-				   disabled.  Setup the EP again. */
-				dbg_isoc("Set EP sub to new list");
-				TxIsocEPList[epid].hw_len = 0;
-				TxIsocEPList[epid].sub = virt_to_phys(urb_priv->first_sb);
-			}
-		}
-	}
-
-	if (urb->transfer_flags & URB_ISO_ASAP) {
-		/* The isoc transfer should be started as soon as possible. The start_frame
-		   field is a return value if URB_ISO_ASAP was set. Comparing R_USB_FM_NUMBER
-		   with a USB Chief trace shows that the first isoc IN token is sent 2 frames
-		   later. I'm not sure how this affects usage of the start_frame field by the
-		   device driver, or how it affects things when USB_ISO_ASAP is not set, so
-		   therefore there's no compensation for the 2 frame "lag" here. */
-		urb->start_frame = (*R_USB_FM_NUMBER & 0x7ff);
-		TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-		urb_priv->urb_state = STARTED;
-		dbg_isoc("URB_ISO_ASAP set, urb->start_frame set to %d", urb->start_frame);
-	} else {
-		/* Not started yet. */
-		urb_priv->urb_state = NOT_STARTED;
-		dbg_isoc("urb_priv->urb_state set to NOT_STARTED");
-	}
-
-       /* We start the DMA sub channel without checking if it's running or not, because:
-	  1) If it's already running, issuing the start command is a nop.
-	  2) We avoid a test-and-set race condition. */
-	*R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start);
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_isoc_urb(struct urb *urb, int status)
-{
-	etrax_urb_priv_t *urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-	int epid = urb_priv->epid;
-	int auto_resubmit = 0;
-
-	DBFENTER;
-	dbg_isoc("complete urb 0x%p, status %d", urb, status);
-
-	if (status)
-		warn("Completing isoc urb with status %d.", status);
-
-	if (usb_pipein(urb->pipe)) {
-		int i;
-
-		/* Make that all isoc packets have status and length set before
-		   completing the urb. */
-		for (i = urb_priv->isoc_packet_counter; i < urb->number_of_packets; i++) {
-			urb->iso_frame_desc[i].actual_length = 0;
-			urb->iso_frame_desc[i].status = -EPROTO;
-		}
-
-		urb_list_del(urb, epid);
-
-		if (!list_empty(&urb_list[epid])) {
-			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
-		} else {
-			unsigned long int flags;
-			if (TxIsocEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-				/* The EP was enabled, disable it and wait. */
-				TxIsocEPList[epid].command &= ~IO_MASK(USB_EP_command, enable);
-
-				/* Ah, the luxury of busy-wait. */
-				while (*R_DMA_CH8_SUB3_EP == virt_to_phys(&TxIsocEPList[epid]));
-			}
-
-			etrax_remove_from_sb_list(urb);
-			TxIsocEPList[epid].sub = 0;
-			TxIsocEPList[epid].hw_len = 0;
-
-			save_flags(flags);
-			cli();
-			etrax_usb_free_epid(epid);
-			restore_flags(flags);
-		}
-
-		urb->hcpriv = 0;
-		kfree(urb_priv);
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-	} else if (usb_pipeout(urb->pipe)) {
-		int freed_descr;
-
-		dbg_isoc("Isoc out urb complete 0x%p", urb);
-
-		/* Update the urb list. */
-		urb_list_del(urb, epid);
-
-		freed_descr = etrax_remove_from_sb_list(urb);
-		dbg_isoc("freed %d descriptors of %d packets", freed_descr, urb->number_of_packets);
-		assert(freed_descr == urb->number_of_packets);
-		urb->hcpriv = 0;
-		kfree(urb_priv);
-
-		/* Release allocated bandwidth. */
-		usb_release_bandwidth(urb->dev, urb, 0);
-	}
-
-	urb->status = status;
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-
-	if (auto_resubmit) {
-		/* Check that urb was not unlinked by the complete callback. */
-		if (__urb_list_entry(urb, epid)) {
-			/* Move this one down the list. */
-			urb_list_move_last(urb, epid);
-
-			/* Mark the now first urb as started (may already be). */
-			((etrax_urb_priv_t *)(urb_list_first(epid)->hcpriv))->urb_state = STARTED;
-
-			/* Must set this to 0 since this urb is still active after
-			   completion. */
-			urb_priv->isoc_packet_counter = 0;
-		} else {
-			warn("(ISOC) automatic resubmit urb 0x%p removed by complete.", urb);
-		}
-	}
-
-	DBFEXIT;
-}
-
-static void etrax_usb_complete_urb(struct urb *urb, int status)
-{
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_BULK:
-		etrax_usb_complete_bulk_urb(urb, status);
-		break;
-	case PIPE_CONTROL:
-		etrax_usb_complete_ctrl_urb(urb, status);
-		break;
-	case PIPE_INTERRUPT:
-		etrax_usb_complete_intr_urb(urb, status);
-		break;
-	case PIPE_ISOCHRONOUS:
-		etrax_usb_complete_isoc_urb(urb, status);
-		break;
-	default:
-		err("Unknown pipetype");
-	}
-}
-
-
-
-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc)
-{
-	usb_interrupt_registers_t *reg;
-	unsigned long flags;
-	__u32 irq_mask;
-	__u8 status;
-	__u32 epid_attn;
-	__u16 port_status_1;
-	__u16 port_status_2;
-	__u32 fm_number;
-
-	DBFENTER;
-
-	/* Read critical registers into local variables, do kmalloc afterwards. */
-	save_flags(flags);
-	cli();
-
-	irq_mask = *R_USB_IRQ_MASK_READ;
-	/* Reading R_USB_STATUS clears the ctl_status interrupt. Note that R_USB_STATUS
-	   must be read before R_USB_EPID_ATTN since reading the latter clears the
-	   ourun and perror fields of R_USB_STATUS. */
-	status = *R_USB_STATUS;
-
-	/* Reading R_USB_EPID_ATTN clears the iso_eof, bulk_eot and epid_attn interrupts. */
-	epid_attn = *R_USB_EPID_ATTN;
-
-	/* Reading R_USB_RH_PORT_STATUS_1 and R_USB_RH_PORT_STATUS_2 clears the
-	   port_status interrupt. */
-	port_status_1 = *R_USB_RH_PORT_STATUS_1;
-	port_status_2 = *R_USB_RH_PORT_STATUS_2;
-
-	/* Reading R_USB_FM_NUMBER clears the sof interrupt. */
-	/* Note: the lower 11 bits contain the actual frame number, sent with each sof. */
-	fm_number = *R_USB_FM_NUMBER;
-
-	restore_flags(flags);
-
-	reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, GFP_ATOMIC);
-
-	assert(reg != NULL);
-
-	reg->hc = (etrax_hc_t *)vhc;
-
-	/* Now put register values into kmalloc'd area. */
-	reg->r_usb_irq_mask_read = irq_mask;
-	reg->r_usb_status = status;
-	reg->r_usb_epid_attn = epid_attn;
-	reg->r_usb_rh_port_status_1 = port_status_1;
-	reg->r_usb_rh_port_status_2 = port_status_2;
-	reg->r_usb_fm_number = fm_number;
-
-        INIT_WORK(&reg->usb_bh, etrax_usb_hc_interrupt_bottom_half, reg);
-        schedule_work(&reg->usb_bh);
-
-	DBFEXIT;
-
-        return IRQ_HANDLED;
-}
-
-static void etrax_usb_hc_interrupt_bottom_half(void *data)
-{
-	usb_interrupt_registers_t *reg = (usb_interrupt_registers_t *)data;
-	__u32 irq_mask = reg->r_usb_irq_mask_read;
-
-	DBFENTER;
-
-	/* Interrupts are handled in order of priority. */
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, epid_attn)) {
-		etrax_usb_hc_epid_attn_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) {
-		etrax_usb_hc_port_status_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, ctl_status)) {
-		etrax_usb_hc_ctl_status_interrupt(reg);
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, iso_eof)) {
-		etrax_usb_hc_isoc_eof_interrupt();
-	}
-	if (irq_mask & IO_MASK(R_USB_IRQ_MASK_READ, bulk_eot)) {
-		/* Update/restart the bulk start timer since obviously the channel is running. */
-		mod_timer(&bulk_start_timer, jiffies + BULK_START_TIMER_INTERVAL);
-		/* Update/restart the bulk eot timer since we just received an bulk eot interrupt. */
-		mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-
-		etrax_usb_hc_bulk_eot_interrupt(0);
-	}
-
-	kmem_cache_free(top_half_reg_cache, reg);
-
-	DBFEXIT;
-}
-
-
-void etrax_usb_hc_isoc_eof_interrupt(void)
-{
-	struct urb *urb;
-	etrax_urb_priv_t *urb_priv;
-	int epid;
-	unsigned long flags;
-
-	DBFENTER;
-
-	/* Do not check the invalid epid (it has a valid sub pointer). */
-	for (epid = 0; epid < NBR_OF_EPIDS - 1; epid++) {
-
-		/* Do not check the invalid epid (it has a valid sub pointer). */
-		if ((epid == DUMMY_EPID) || (epid == INVALID_EPID))
-			continue;
-
-		/* Disable interrupts to block the isoc out descriptor interrupt handler
-		   from being called while the isoc EPID list is being checked.
-		*/
-		save_flags(flags);
-		cli();
-
-		if (TxIsocEPList[epid].sub == 0) {
-			/* Nothing here to see. */
-			restore_flags(flags);
-			continue;
-		}
-
-		/* Get the first urb (if any). */
-		urb = urb_list_first(epid);
-		if (urb == 0) {
-			warn("Ignoring NULL urb");
-			restore_flags(flags);
-			continue;
-		}
-		if (usb_pipein(urb->pipe)) {
-
-			/* Sanity check. */
-			assert(usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS);
-
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			if (urb_priv->urb_state == NOT_STARTED) {
-
-				/* If ASAP is not set and urb->start_frame is the current frame,
-				   start the transfer. */
-				if (!(urb->transfer_flags & URB_ISO_ASAP) &&
-				    (urb->start_frame == (*R_USB_FM_NUMBER & 0x7ff))) {
-
-					dbg_isoc("Enabling isoc IN EP descr for epid %d", epid);
-					TxIsocEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes);
-
-					/* This urb is now active. */
-					urb_priv->urb_state = STARTED;
-					continue;
-				}
-			}
-		}
-		restore_flags(flags);
-	}
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_bulk_eot_interrupt(int timer_induced)
-{
- 	int epid;
-
-	/* The technique is to run one urb at a time, wait for the eot interrupt at which
-	   point the EP descriptor has been disabled. */
-
-	DBFENTER;
-	dbg_bulk("bulk eot%s", timer_induced ? ", called by timer" : "");
-
-	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-
-		if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) &&
-		    (TxBulkEPList[epid].sub != 0)) {
-
-			struct urb *urb;
-			etrax_urb_priv_t *urb_priv;
-			unsigned long flags;
-			__u32 r_usb_ept_data;
-
-			/* Found a disabled EP descriptor which has a non-null sub pointer.
-			   Verify that this ctrl EP descriptor got disabled no errors.
-			   FIXME: Necessary to check error_code? */
-			dbg_bulk("for epid %d?", epid);
-
-			/* Get the first urb. */
-			urb = urb_list_first(epid);
-
-			/* FIXME: Could this happen for valid reasons? Why did it disappear? Because of
-			   wrong unlinking? */
-			if (!urb) {
-				warn("NULL urb for epid %d", epid);
-				continue;
-			}
-
-			assert(urb);
-			urb_priv = (etrax_urb_priv_t *)urb->hcpriv;
-			assert(urb_priv);
-
-			/* Sanity checks. */
-			assert(usb_pipetype(urb->pipe) == PIPE_BULK);
-			if (phys_to_virt(TxBulkEPList[epid].sub) != urb_priv->last_sb) {
-				err("bulk endpoint got disabled before reaching last sb");
-			}
-
-			/* For bulk IN traffic, there seems to be a race condition between
-			   between the bulk eot and eop interrupts, or rather an uncertainty regarding
-			   the order in which they happen. Normally we expect the eop interrupt from
-			   DMA channel 9 to happen before the eot interrupt.
-
-			   Therefore, we complete the bulk IN urb in the rx interrupt handler instead. */
-
-			if (usb_pipein(urb->pipe)) {
-				dbg_bulk("in urb, continuing");
-				continue;
-			}
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			r_usb_ept_data = *R_USB_EPT_DATA;
-			restore_flags(flags);
-
-			if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) ==
-			    IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
-				/* This means that the endpoint has no error, is disabled
-				   and had inserted traffic, i.e. transfer successfully completed. */
-				etrax_usb_complete_bulk_urb(urb, 0);
-			} else {
-				/* Shouldn't happen. We expect errors to be caught by epid attention. */
-				err("Found disabled bulk EP desc, error_code != no_error");
-			}
-		}
-	}
-
-	/* Normally, we should find (at least) one disabled EP descriptor with a valid sub pointer.
-	   However, because of the uncertainty in the deliverance of the eop/eot interrupts, we may
-	   not.  Also, we might find two disabled EPs when handling an eot interrupt, and then find
-	   none the next time. */
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_epid_attn_interrupt(usb_interrupt_registers_t *reg)
-{
-	/* This function handles the epid attention interrupt.  There are a variety of reasons
-	   for this interrupt to happen (Designer's Reference, p. 8 - 22 for the details):
-
-	   invalid ep_id  - Invalid epid in an EP (EP disabled).
-	   stall	  - Not strictly an error condition (EP disabled).
-	   3rd error      - Three successive transaction errors  (EP disabled).
-	   buffer ourun   - Buffer overrun or underrun (EP disabled).
-	   past eof1      - Intr or isoc transaction proceeds past EOF1.
-	   near eof       - Intr or isoc transaction would not fit inside the frame.
-	   zout transfer  - If zout transfer for a bulk endpoint (EP disabled).
-	   setup transfer - If setup transfer for a non-ctrl endpoint (EP disabled). */
-
-	int epid;
-
-
-	DBFENTER;
-
-	assert(reg != NULL);
-
-	/* Note that we loop through all epids. We still want to catch errors for
-	   the invalid one, even though we might handle them differently. */
-	for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-
-		if (test_bit(epid, (void *)&reg->r_usb_epid_attn)) {
-
-			struct urb *urb;
-			__u32 r_usb_ept_data;
-			unsigned long flags;
-			int error_code;
-
-			save_flags(flags);
-			cli();
-			*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid);
-			nop();
-			/* Note that although there are separate R_USB_EPT_DATA and R_USB_EPT_DATA_ISO
-			   registers, they are located at the same address and are of the same size.
-			   In other words, this read should be ok for isoc also. */
-			r_usb_ept_data = *R_USB_EPT_DATA;
-			restore_flags(flags);
-
-			/* First some sanity checks. */
-			if (epid == INVALID_EPID) {
-				/* FIXME: What if it became disabled? Could seriously hurt interrupt
-				   traffic. (Use do_intr_recover.) */
-				warn("Got epid_attn for INVALID_EPID (%d).", epid);
-				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
-				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
-				continue;
-			} else 	if (epid == DUMMY_EPID) {
-				/* We definitely don't care about these ones. Besides, they are
-				   always disabled, so any possible disabling caused by the
-				   epid attention interrupt is irrelevant. */
-				warn("Got epid_attn for DUMMY_EPID (%d).", epid);
-				continue;
-			}
-
-			/* Get the first urb in the urb list for this epid. We blatantly assume
-			   that only the first urb could have caused the epid attention.
-			   (For bulk and ctrl, only one urb is active at any one time. For intr
-			   and isoc we remove them once they are completed.) */
-			urb = urb_list_first(epid);
-
-			if (urb == NULL) {
-				err("Got epid_attn for epid %i with no urb.", epid);
-				err("R_USB_EPT_DATA = 0x%x", r_usb_ept_data);
-				err("R_USB_STATUS = 0x%x", reg->r_usb_status);
-				continue;
-			}
-
-			switch (usb_pipetype(urb->pipe)) {
-			case PIPE_BULK:
-				warn("Got epid attn for bulk endpoint, epid %d", epid);
-				break;
-			case PIPE_CONTROL:
-				warn("Got epid attn for control endpoint, epid %d", epid);
-				break;
-			case PIPE_INTERRUPT:
-				warn("Got epid attn for interrupt endpoint, epid %d", epid);
-				break;
-			case PIPE_ISOCHRONOUS:
-				warn("Got epid attn for isochronous endpoint, epid %d", epid);
-				break;
-			}
-
-			if (usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) {
-				if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) {
-					warn("Hold was set for epid %d.", epid);
-					continue;
-				}
-			}
-
-			/* Even though error_code occupies bits 22 - 23 in both R_USB_EPT_DATA and
-			   R_USB_EPT_DATA_ISOC, we separate them here so we don't forget in other places. */
-			if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-				error_code = IO_EXTRACT(R_USB_EPT_DATA_ISO, error_code, r_usb_ept_data);
-			} else {
-				error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data);
-			}
-
-			/* Using IO_STATE_VALUE on R_USB_EPT_DATA should be ok for isoc also. */
-			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
-
-				/* Isoc traffic doesn't have error_count_in/error_count_out. */
-				if ((usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS) &&
-				    (IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3 ||
-				     IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3)) {
-					/* 3rd error. */
-					warn("3rd error for epid %i", epid);
-					etrax_usb_complete_urb(urb, -EPROTO);
-
-				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
-
-					warn("Perror for epid %d", epid);
-
-					if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) {
-						/* invalid ep_id */
-						panic("Perror because of invalid epid."
-						      " Deconfigured too early?");
-					} else {
-						/* past eof1, near eof, zout transfer, setup transfer */
-
-						/* Dump the urb and the relevant EP descriptor list. */
-
-						__dump_urb(urb);
-						__dump_ept_data(epid);
-						__dump_ep_list(usb_pipetype(urb->pipe));
-
-						panic("Something wrong with DMA descriptor contents."
-						      " Too much traffic inserted?");
-					}
-				} else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
-					/* buffer ourun */
-					panic("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-				}
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) {
-				/* Not really a protocol error, just says that the endpoint gave
-				   a stall response. Note that error_code cannot be stall for isoc. */
-				if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-					panic("Isoc traffic cannot stall");
-				}
-
-				warn("Stall for epid %d", epid);
-				etrax_usb_complete_urb(urb, -EPIPE);
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) {
-				/* Two devices responded to a transaction request. Must be resolved
-				   by software. FIXME: Reset ports? */
-				panic("Bus error for epid %d."
-				      " Two devices responded to transaction request",
-				      epid);
-
-			} else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) {
-				/* DMA overrun or underrun. */
-				warn("Buffer overrun/underrun for epid %d. DMA too busy?", epid);
-
-				/* It seems that error_code = buffer_error in
-				   R_USB_EPT_DATA/R_USB_EPT_DATA_ISO and ourun = yes in R_USB_STATUS
-				   are the same error. */
-				etrax_usb_complete_urb(urb, -EPROTO);
-			}
-		}
-	}
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_bulk_start_timer_func(unsigned long dummy)
-{
-
-	/* We might enable an EP descriptor behind the current DMA position when it's about
-	   to decide that there are no more bulk traffic and it should stop the bulk channel.
-	   Therefore we periodically check if the bulk channel is stopped and there is an
-	   enabled bulk EP descriptor, in which case we start the bulk channel. */
-	dbg_bulk("bulk_start_timer timed out.");
-
-	if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) {
-		int epid;
-
-		dbg_bulk("Bulk DMA channel not running.");
-
-		for (epid = 0; epid < NBR_OF_EPIDS; epid++) {
-			if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) {
-				dbg_bulk("Found enabled EP for epid %d, starting bulk channel.\n",
-					 epid);
-				*R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start);
-
-				/* Restart the bulk eot timer since we just started the bulk channel. */
-				mod_timer(&bulk_eot_timer, jiffies + BULK_EOT_TIMER_INTERVAL);
-
-				/* No need to search any further. */
-				break;
-			}
-		}
-	} else {
-		dbg_bulk("Bulk DMA channel running.");
-	}
-}
-
-void etrax_usb_hc_port_status_interrupt(usb_interrupt_registers_t *reg)
-{
-	etrax_hc_t *hc = reg->hc;
-	__u16 r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1;
-	__u16 r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2;
-
-	DBFENTER;
-
-	/* The Etrax RH does not include a wPortChange register, so this has to be handled in software
-	   (by saving the old port status value for comparison when the port status interrupt happens).
-	   See section 11.16.2.6.2 in the USB 1.1 spec for details. */
-
-	dbg_rh("hc->rh.prev_wPortStatus_1 = 0x%x", hc->rh.prev_wPortStatus_1);
-	dbg_rh("hc->rh.prev_wPortStatus_2 = 0x%x", hc->rh.prev_wPortStatus_2);
-	dbg_rh("r_usb_rh_port_status_1 = 0x%x", r_usb_rh_port_status_1);
-	dbg_rh("r_usb_rh_port_status_2 = 0x%x", r_usb_rh_port_status_2);
-
-	/* C_PORT_CONNECTION is set on any transition. */
-	hc->rh.wPortChange_1 |=
-		((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) !=
-		 (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ?
-		(1 << RH_PORT_CONNECTION) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) !=
-		 (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ?
-		(1 << RH_PORT_CONNECTION) : 0;
-
-	/* C_PORT_ENABLE is _only_ set on a one to zero transition, i.e. when
-	   the port is disabled, not when it's enabled. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ?
-		(1 << RH_PORT_ENABLE) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ?
-		(1 << RH_PORT_ENABLE) : 0;
-
-	/* C_PORT_SUSPEND is set to one when the device has transitioned out
-	   of the suspended state, i.e. when suspend goes from one to zero. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_SUSPEND))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_SUSPEND))) ?
-		(1 << RH_PORT_SUSPEND) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_SUSPEND))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_SUSPEND))) ?
-		(1 << RH_PORT_SUSPEND) : 0;
-
-
-	/* C_PORT_RESET is set when reset processing on this port is complete. */
-	hc->rh.wPortChange_1 |=
-		((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET))
-		 && !(r_usb_rh_port_status_1 & (1 << RH_PORT_RESET))) ?
-		(1 << RH_PORT_RESET) : 0;
-
-	hc->rh.wPortChange_2 |=
-		((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET))
-		 && !(r_usb_rh_port_status_2 & (1 << RH_PORT_RESET))) ?
-		(1 << RH_PORT_RESET) : 0;
-
-	/* Save the new values for next port status change. */
-	hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1;
-	hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2;
-
-	dbg_rh("hc->rh.wPortChange_1 set to 0x%x", hc->rh.wPortChange_1);
-	dbg_rh("hc->rh.wPortChange_2 set to 0x%x", hc->rh.wPortChange_2);
-
-	DBFEXIT;
-
-}
-
-void etrax_usb_hc_ctl_status_interrupt(usb_interrupt_registers_t *reg)
-{
-	DBFENTER;
-
-	/* FIXME: What should we do if we get ourun or perror? Dump the EP and SB
-	   list for the corresponding epid? */
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) {
-		panic("USB controller got ourun.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) {
-
-		/* Before, etrax_usb_do_intr_recover was called on this epid if it was
-		   an interrupt pipe. I don't see how re-enabling all EP descriptors
-		   will help if there was a programming error. */
-		panic("USB controller got perror.");
-	}
-
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, device_mode)) {
-		/* We should never operate in device mode. */
-		panic("USB controller in device mode.");
-	}
-
-	/* These if-statements could probably be nested. */
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, host_mode)) {
-		info("USB controller in host mode.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, started)) {
-		info("USB controller started.");
-	}
-	if (reg->r_usb_status & IO_MASK(R_USB_STATUS, running)) {
-		info("USB controller running.");
-	}
-
-	DBFEXIT;
-
-}
-
-
-static int etrax_rh_submit_urb(struct urb *urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	etrax_hc_t *hc = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int stat = 0;
-
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	DBFENTER;
-
-	/* FIXME: What is this interrupt urb that is sent to the root hub? */
-	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
-		dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval);
-		hc->rh.urb = urb;
-		hc->rh.send = 1;
-		/* FIXME: We could probably remove this line since it's done
-		   in etrax_rh_init_int_timer. (Don't remove it from
-		   etrax_rh_init_int_timer though.) */
-		hc->rh.interval = urb->interval;
-		etrax_rh_init_int_timer(urb);
-		DBFEXIT;
-
-		return 0;
-	}
-
-	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
-	wValue = le16_to_cpu(cmd->wValue);
-	wIndex = le16_to_cpu(cmd->wIndex);
-	wLength = le16_to_cpu(cmd->wLength);
-
-	dbg_rh("bmRType_bReq : 0x%04x (%d)", bmRType_bReq, bmRType_bReq);
-	dbg_rh("wValue       : 0x%04x (%d)", wValue, wValue);
-	dbg_rh("wIndex       : 0x%04x (%d)", wIndex, wIndex);
-	dbg_rh("wLength      : 0x%04x (%d)", wLength, wLength);
-
-	switch (bmRType_bReq) {
-
-		/* Request Destination:
-		   without flags: Device,
-		   RH_INTERFACE: interface,
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here,
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
-		 */
-
-	case RH_GET_STATUS:
-		*(__u16 *) data = cpu_to_le16 (1);
-		OK (2);
-
-	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data = cpu_to_le32 (0);
-		OK (4);		/* hub power ** */
-
-	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		if (wIndex == 1) {
-			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1);
-			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1);
-		} else if (wIndex == 2) {
-			*((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2);
-			*((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2);
-		} else {
-			dbg_rh("RH_GET_STATUS whith invalid wIndex!");
-			OK(0);
-		}
-
-		OK(4);
-
-	case RH_CLEAR_FEATURE | RH_ENDPOINT:
-		switch (wValue) {
-		case (RH_ENDPOINT_STALL):
-			OK (0);
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_CLASS:
-		switch (wValue) {
-		case (RH_C_HUB_OVER_CURRENT):
-			OK (0);	/* hub power over current ** */
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_ENABLE):
-			if (wIndex == 1) {
-
-				dbg_rh("trying to do disable port 1");
-
-				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes);
-
-				while (hc->rh.prev_wPortStatus_1 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes));
-				*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
-				dbg_rh("Port 1 is disabled");
-
-			} else if (wIndex == 2) {
-
-				dbg_rh("trying to do disable port 2");
-
-				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes);
-
-				while (hc->rh.prev_wPortStatus_2 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes));
-				*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
-				dbg_rh("Port 2 is disabled");
-
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_SUSPEND):
-			/* Opposite to suspend should be resume, so we'll do a resume. */
-			/* FIXME: USB 1.1, 11.16.2.2 says:
-			   "Clearing the PORT_SUSPEND feature causes a host-initiated resume
-			   on the specified port. If the port is not in the Suspended state,
-			   the hub should treat this request as a functional no-operation."
-			   Shouldn't we check if the port is in a suspended state before
-			   resuming? */
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			if (wIndex == 1) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else if (wIndex == 2) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, resume) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_C_PORT_CONNECTION):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_C_PORT_ENABLE):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-			OK (0);
-		case (RH_C_PORT_SUSPEND):
-/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-			OK (0);
-		case (RH_C_PORT_OVER_CURRENT):
-			OK (0);	/* port power over current ** */
-		case (RH_C_PORT_RESET):
-			if (wIndex == 1) {
-				hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET);
-			} else if (wIndex == 2) {
-				hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET);
-			} else {
-				dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET "
-				       "with invalid index == %d!", wIndex);
-			}
-
-			OK (0);
-
-		}
-		break;
-
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_SUSPEND):
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			if (wIndex == 1) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else if (wIndex == 2) {
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, suspend) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_PORT_SUSPEND "
-				       "with invalid wIndex == %d!", wIndex);
-			}
-
-			OK (0);
-		case (RH_PORT_RESET):
-			if (wIndex == 1) {
-
-			port_1_reset:
-				dbg_rh("Doing reset of port 1");
-
-				/* Make sure the controller isn't busy. */
-				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port1) |
-					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-
-				/* We must wait at least 10 ms for the device to recover.
-				   15 ms should be enough. */
-				udelay(15000);
-
-				/* Wait for reset bit to go low (should be done by now). */
-				while (hc->rh.prev_wPortStatus_1 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_1, reset, yes));
-
-				/* If the port status is
-				   1) connected and enabled then there is a device and everything is fine
-				   2) neither connected nor enabled then there is no device, also fine
-				   3) connected and not enabled then we try again
-				   (Yes, there are other port status combinations besides these.) */
-
-				if ((hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
-				    (hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
-					dbg_rh("Connected device on port 1, but port not enabled?"
-					       " Trying reset again.");
-					goto port_2_reset;
-				}
-
-				/* Diagnostic printouts. */
-				if ((hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, connected, no)) &&
-				    (hc->rh.prev_wPortStatus_1 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no))) {
-					dbg_rh("No connected device on port 1");
-				} else if ((hc->rh.prev_wPortStatus_1 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_1, connected, yes)) &&
-					   (hc->rh.prev_wPortStatus_1 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) {
-					dbg_rh("Connected device on port 1, port 1 enabled");
-				}
-
-			} else if (wIndex == 2) {
-
-			port_2_reset:
-				dbg_rh("Doing reset of port 2");
-
-				/* Make sure the controller isn't busy. */
-				while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-				/* Issue the reset command. */
-				*R_USB_COMMAND =
-					IO_STATE(R_USB_COMMAND, port_sel, port2) |
-					IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-					IO_STATE(R_USB_COMMAND, ctrl_cmd, nop);
-
-				/* We must wait at least 10 ms for the device to recover.
-				   15 ms should be enough. */
-				udelay(15000);
-
-				/* Wait for reset bit to go low (should be done by now). */
-				while (hc->rh.prev_wPortStatus_2 &
-				       IO_STATE(R_USB_RH_PORT_STATUS_2, reset, yes));
-
-				/* If the port status is
-				   1) connected and enabled then there is a device and everything is fine
-				   2) neither connected nor enabled then there is no device, also fine
-				   3) connected and not enabled then we try again
-				   (Yes, there are other port status combinations besides these.) */
-
-				if ((hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
-				    (hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
-					dbg_rh("Connected device on port 2, but port not enabled?"
-					       " Trying reset again.");
-					goto port_2_reset;
-				}
-
-				/* Diagnostic printouts. */
-				if ((hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, connected, no)) &&
-				    (hc->rh.prev_wPortStatus_2 &
-				     IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no))) {
-					dbg_rh("No connected device on port 2");
-				} else if ((hc->rh.prev_wPortStatus_2 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_2, connected, yes)) &&
-					   (hc->rh.prev_wPortStatus_2 &
-					    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) {
-					dbg_rh("Connected device on port 2, port 2 enabled");
-				}
-
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_PORT_RESET with invalid wIndex = %d", wIndex);
-			}
-
-			/* Make sure the controller isn't busy. */
-			while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-			/* If all enabled ports were disabled the host controller goes down into
-			   started mode, so we need to bring it back into the running state.
-			   (This is safe even if it's already in the running state.) */
-			*R_USB_COMMAND =
-				IO_STATE(R_USB_COMMAND, port_sel, nop) |
-				IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-				IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
-
-			dbg_rh("...Done");
-			OK(0);
-
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_PORT_ENABLE):
-			/* There is no port enable command in the host controller, so if the
-			   port is already enabled, we do nothing. If not, we reset the port
-			   (with an ugly goto). */
-
-			if (wIndex == 1) {
-				if (hc->rh.prev_wPortStatus_1 &
-				    IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, no)) {
-					goto port_1_reset;
-				}
-			} else if (wIndex == 2) {
-				if (hc->rh.prev_wPortStatus_2 &
-				    IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, no)) {
-					goto port_2_reset;
-				}
-			} else {
-				dbg_rh("RH_SET_FEATURE->RH_GET_STATUS with invalid wIndex = %d", wIndex);
-			}
-			OK (0);
-		}
-		break;
-
-	case RH_SET_ADDRESS:
-		hc->rh.devnum = wValue;
-		dbg_rh("RH address set to: %d", hc->rh.devnum);
-		OK (0);
-
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case (0x01):	/* device descriptor */
-			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength));
-			memcpy (data, root_hub_dev_des, len);
-			OK (len);
-		case (0x02):	/* configuration descriptor */
-			len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK (len);
-		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-						   0xff, "ETRAX 100LX",
-						   data, wLength);
-			if (len > 0) {
-				OK(min(leni, len));
-			} else {
-				stat = -EPIPE;
-			}
-
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = hc->rh.numports;
-		len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
-		memcpy (data, root_hub_hub_des, len);
-		OK (len);
-
-	case RH_GET_CONFIGURATION:
-		*(__u8 *) data = 0x01;
-		OK (1);
-
-	case RH_SET_CONFIGURATION:
-		OK (0);
-
-	default:
-		stat = -EPIPE;
-	}
-
-	urb->actual_length = len;
-	urb->status = stat;
-	urb->dev = NULL;
-	if (urb->complete) {
-		urb->complete(urb, NULL);
-	}
-	DBFEXIT;
-
-	return 0;
-}
-
-static void
-etrax_usb_bulk_eot_timer_func(unsigned long dummy)
-{
-	/* Because of a race condition in the top half, we might miss a bulk eot.
-	   This timer "simulates" a bulk eot if we don't get one for a while, hopefully
-	   correcting the situation. */
-	dbg_bulk("bulk_eot_timer timed out.");
-	etrax_usb_hc_bulk_eot_interrupt(1);
-}
-
-static void*
-etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size,
-	unsigned mem_flags, dma_addr_t *dma)
-{
-  return kmalloc(size, mem_flags);
-}
-
-static void
-etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma)
-{
-  kfree(addr);
-}
-
-
-static struct device fake_device;
-
-static int __init etrax_usb_hc_init(void)
-{
-	static etrax_hc_t *hc;
-	struct usb_bus *bus;
-	struct usb_device *usb_rh;
-	int i;
-
-	DBFENTER;
-
-	info("ETRAX 100LX USB-HCD %s (c) 2001-2003 Axis Communications AB\n", usb_hcd_version);
-
- 	hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL);
-	assert(hc != NULL);
-
-	/* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */
-	/* Note that we specify sizeof(USB_EP_Desc_t) as the size, but also allocate
-	   SB descriptors from this cache. This is ok since sizeof(USB_EP_Desc_t) ==
-	   sizeof(USB_SB_Desc_t). */
-
-	usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0,
-					   SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(usb_desc_cache != NULL);
-
-	top_half_reg_cache = kmem_cache_create("top_half_reg_cache",
-					       sizeof(usb_interrupt_registers_t),
-					       0, SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(top_half_reg_cache != NULL);
-
-	isoc_compl_cache = kmem_cache_create("isoc_compl_cache",
-						sizeof(usb_isoc_complete_data_t),
-						0, SLAB_HWCACHE_ALIGN, 0, 0);
-	assert(isoc_compl_cache != NULL);
-
-	etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations);
-	hc->bus = bus;
-	bus->bus_name="ETRAX 100LX";
-	bus->hcpriv = hc;
-
-	/* Initialize RH to the default address.
-	   And make sure that we have no status change indication */
-	hc->rh.numports = 2;  /* The RH has two ports */
-	hc->rh.devnum = 1;
-	hc->rh.wPortChange_1 = 0;
-	hc->rh.wPortChange_2 = 0;
-
-	/* Also initate the previous values to zero */
-	hc->rh.prev_wPortStatus_1 = 0;
-	hc->rh.prev_wPortStatus_2 = 0;
-
-	/* Initialize the intr-traffic flags */
-	/* FIXME: This isn't used. (Besides, the error field isn't initialized.) */
-	hc->intr.sleeping = 0;
-	hc->intr.wq = NULL;
-
-	epid_usage_bitmask = 0;
-	epid_out_traffic = 0;
-
-	/* Mark the invalid epid as being used. */
-	set_bit(INVALID_EPID, (void *)&epid_usage_bitmask);
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, INVALID_EPID);
-	nop();
-	/* The valid bit should still be set ('invalid' is in our world; not the hardware's). */
-	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, yes) |
-			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
-
-	/* Mark the dummy epid as being used. */
-	set_bit(DUMMY_EPID, (void *)&epid_usage_bitmask);
-	*R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, DUMMY_EPID);
-	nop();
-	*R_USB_EPT_DATA = (IO_STATE(R_USB_EPT_DATA, valid, no) |
-			   IO_FIELD(R_USB_EPT_DATA, max_len, 1));
-
-	/* Initialize the urb list by initiating a head for each list. */
-	for (i = 0; i < NBR_OF_EPIDS; i++) {
-		INIT_LIST_HEAD(&urb_list[i]);
-	}
-	spin_lock_init(&urb_list_lock);
-
-	INIT_LIST_HEAD(&urb_unlink_list);
-
-
-	/* Initiate the bulk start timer. */
-	init_timer(&bulk_start_timer);
-	bulk_start_timer.expires = jiffies + BULK_START_TIMER_INTERVAL;
-	bulk_start_timer.function = etrax_usb_bulk_start_timer_func;
-	add_timer(&bulk_start_timer);
-
-
-	/* Initiate the bulk eot timer. */
-	init_timer(&bulk_eot_timer);
-	bulk_eot_timer.expires = jiffies + BULK_EOT_TIMER_INTERVAL;
-	bulk_eot_timer.function = etrax_usb_bulk_eot_timer_func;
-	add_timer(&bulk_eot_timer);
-
-	/* Set up the data structures for USB traffic. Note that this must be done before
-	   any interrupt that relies on sane DMA list occurrs. */
-	init_rx_buffers();
-	init_tx_bulk_ep();
-	init_tx_ctrl_ep();
-	init_tx_intr_ep();
-	init_tx_isoc_ep();
-
-        device_initialize(&fake_device);
-        kobject_set_name(&fake_device.kobj, "etrax_usb");
-        kobject_add(&fake_device.kobj);
-	kobject_uevent(&fake_device.kobj, KOBJ_ADD);
-        hc->bus->controller = &fake_device;
-	usb_register_bus(hc->bus);
-
-	*R_IRQ_MASK2_SET =
-		/* Note that these interrupts are not used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) |
-		/* Sub channel 1 (ctrl) descr. interrupts are used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) |
-		/* Sub channel 3 (isoc) descr. interrupts are used. */
-		IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set);
-
-	/* Note that the dma9_descr interrupt is not used. */
-	*R_IRQ_MASK2_SET =
-		IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) |
-		IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
-
-	/* FIXME: Enable iso_eof only when isoc traffic is running. */
-	*R_USB_IRQ_MASK_SET =
-		IO_STATE(R_USB_IRQ_MASK_SET, iso_eof, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, port_status, set) |
-		IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set);
-
-
-	if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_interrupt_top_half, 0,
-			"ETRAX 100LX built-in USB (HC)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0,
-			"ETRAX 100LX built-in USB (Rx)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0,
-			"ETRAX 100LX built-in USB (Tx)", hc)) {
-		err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ);
-		etrax_usb_hc_cleanup();
-		DBFEXIT;
-		return -1;
-	}
-
-	/* R_USB_COMMAND:
-	   USB commands in host mode. The fields in this register should all be
-	   written to in one write. Do not read-modify-write one field at a time. A
-	   write to this register will trigger events in the USB controller and an
-	   incomplete command may lead to unpredictable results, and in worst case
-	   even to a deadlock in the controller.
-	   (Note however that the busy field is read-only, so no need to write to it.) */
-
-	/* Check the busy bit before writing to R_USB_COMMAND. */
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Reset the USB interface. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, reset);
-
-	/* Designer's Reference, p. 8 - 10 says we should Initate R_USB_FM_PSTART to 0x2A30 (10800),
-	   to guarantee that control traffic gets 10% of the bandwidth, and periodic transfer may
-	   allocate the rest (90%). This doesn't work though. Read on for a lenghty explanation.
-
-	   While there is a difference between rev. 2 and rev. 3 of the ETRAX 100LX regarding the NAK
-	   behaviour, it doesn't solve this problem. What happens is that a control transfer will not
-	   be interrupted in its data stage when PSTART happens (the point at which periodic traffic
-	   is started). Thus, if PSTART is set to 10800 and its IN or OUT token is NAKed until just before
-	   PSTART happens, it will continue the IN/OUT transfer as long as it's ACKed. After it's done,
-	   there may be too little time left for an isochronous transfer, causing an epid attention
-	   interrupt due to perror. The work-around for this is to let the control transfers run at the
-	   end of the frame instead of at the beginning, and will be interrupted just fine if it doesn't
-	   fit into the frame. However, since there will *always* be a control transfer at the beginning
-	   of the frame, regardless of what we set PSTART to, that transfer might be a 64-byte transfer
-	   which consumes up to 15% of the frame, leaving only 85% for periodic traffic. The solution to
-	   this would be to 'dummy allocate' 5% of the frame with the usb_claim_bandwidth function to make
-	   sure that the periodic transfers that are inserted will always fit in the frame.
-
-	   The idea was suggested that a control transfer could be split up into several 8 byte transfers,
-	   so that it would be interrupted by PSTART, but since this can't be done for an IN transfer this
-	   hasn't been implemented.
-
-	   The value 11960 is chosen to be just after the SOF token, with a couple of bit times extra
-	   for possible bit stuffing. */
-
-	*R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 11960);
-
-#ifdef CONFIG_ETRAX_USB_HOST_PORT1
-	*R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no);
-#endif
-
-#ifdef CONFIG_ETRAX_USB_HOST_PORT2
-	*R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no);
-#endif
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Configure the USB interface as a host controller. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config);
-
-	/* Note: Do not reset any ports here. Await the port status interrupts, to have a controlled
-	   sequence of resetting the ports. If we reset both ports now, and there are devices
-	   on both ports, we will get a bus error because both devices will answer the set address
-	   request. */
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	/* Start processing of USB traffic. */
-	*R_USB_COMMAND =
-		IO_STATE(R_USB_COMMAND, port_sel, nop) |
-		IO_STATE(R_USB_COMMAND, port_cmd, reset) |
-		IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run);
-
-	while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy));
-
-	usb_rh = usb_alloc_dev(NULL, hc->bus, 0);
-	hc->bus->root_hub = usb_rh;
-        usb_rh->state = USB_STATE_ADDRESS;
-        usb_rh->speed = USB_SPEED_FULL;
-        usb_rh->devnum = 1;
-        hc->bus->devnum_next = 2;
-        usb_rh->ep0.desc.wMaxPacketSize = __const_cpu_to_le16(64);
-        usb_get_device_descriptor(usb_rh, USB_DT_DEVICE_SIZE);
-	usb_new_device(usb_rh);
-
-	DBFEXIT;
-
-	return 0;
-}
-
-static void etrax_usb_hc_cleanup(void)
-{
-	DBFENTER;
-
-	free_irq(ETRAX_USB_HC_IRQ, NULL);
-	free_irq(ETRAX_USB_RX_IRQ, NULL);
-	free_irq(ETRAX_USB_TX_IRQ, NULL);
-
-	usb_deregister_bus(etrax_usb_bus);
-
-	/* FIXME: call kmem_cache_destroy here? */
-
-	DBFEXIT;
-}
-
-module_init(etrax_usb_hc_init);
-module_exit(etrax_usb_hc_cleanup);
diff --git a/drivers/usb/host/hc_crisv10.h b/drivers/usb/host/hc_crisv10.h
deleted file mode 100644
index 62f7711..0000000
--- a/drivers/usb/host/hc_crisv10.h
+++ /dev/null
@@ -1,289 +0,0 @@
-#ifndef __LINUX_ETRAX_USB_H
-#define __LINUX_ETRAX_USB_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-
-typedef struct USB_IN_Desc {
-	volatile __u16 sw_len;
-	volatile __u16 command;
-	volatile unsigned long next;
-	volatile unsigned long buf;
-	volatile __u16 hw_len;
-	volatile __u16 status;
-} USB_IN_Desc_t;
-
-typedef struct USB_SB_Desc {
-	volatile __u16 sw_len;
-	volatile __u16 command;
-	volatile unsigned long next;
-	volatile unsigned long buf;
-	__u32 dummy;
-} USB_SB_Desc_t;
-
-typedef struct USB_EP_Desc {
-	volatile __u16 hw_len;
-	volatile __u16 command;
-	volatile unsigned long sub;
-	volatile unsigned long next;
-	__u32 dummy;
-} USB_EP_Desc_t;
-
-struct virt_root_hub {
-	int devnum;
-	void *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	struct timer_list rh_int_timer;
-	volatile __u16 wPortChange_1;
-	volatile __u16 wPortChange_2;
-	volatile __u16 prev_wPortStatus_1;
-	volatile __u16 prev_wPortStatus_2;
-};
-
-struct etrax_usb_intr_traffic {
-	int sleeping;
-	int error;
-	struct wait_queue *wq;
-};
-
-typedef struct etrax_usb_hc {
-	struct usb_bus *bus;
-	struct virt_root_hub rh;
-	struct etrax_usb_intr_traffic intr;
-} etrax_hc_t;
-
-typedef enum {
-	STARTED,
-	NOT_STARTED,
-	UNLINK,
-	TRANSFER_DONE,
-	WAITING_FOR_DESCR_INTR
-} etrax_usb_urb_state_t;
-
-
-
-typedef struct etrax_usb_urb_priv {
-	/* The first_sb field is used for freeing all SB descriptors belonging
-	   to an urb. The corresponding ep descriptor's sub pointer cannot be
-	   used for this since the DMA advances the sub pointer as it processes
-	   the sb list. */
-	USB_SB_Desc_t *first_sb;
-	/* The last_sb field referes to the last SB descriptor that belongs to
-	   this urb. This is important to know so we can free the SB descriptors
-	   that ranges between first_sb and last_sb. */
-	USB_SB_Desc_t *last_sb;
-
-	/* The rx_offset field is used in ctrl and bulk traffic to keep track
-	   of the offset in the urb's transfer_buffer where incoming data should be
-	   copied to. */
-	__u32 rx_offset;
-
-	/* Counter used in isochronous transfers to keep track of the
-	   number of packets received/transmitted.  */
-	__u32 isoc_packet_counter;
-
-	/* This field is used to pass information about the urb's current state between
-	   the various interrupt handlers (thus marked volatile). */
-	volatile etrax_usb_urb_state_t urb_state;
-
-	/* Connection between the submitted urb and ETRAX epid number */
-	__u8 epid;
-
-	/* The rx_data_list field is used for periodic traffic, to hold
-	   received data for later processing in the the complete_urb functions,
-	   where the data us copied to the urb's transfer_buffer. Basically, we
-	   use this intermediate storage because we don't know when it's safe to
-	   reuse the transfer_buffer (FIXME?). */
-	struct list_head rx_data_list;
-} etrax_urb_priv_t;
-
-/* This struct is for passing data from the top half to the bottom half. */
-typedef struct usb_interrupt_registers
-{
-	etrax_hc_t *hc;
-	__u32 r_usb_epid_attn;
-	__u8 r_usb_status;
-	__u16 r_usb_rh_port_status_1;
-	__u16 r_usb_rh_port_status_2;
-	__u32 r_usb_irq_mask_read;
-	__u32 r_usb_fm_number;
-	struct work_struct usb_bh;
-} usb_interrupt_registers_t;
-
-/* This struct is for passing data from the isoc top half to the isoc bottom half. */
-typedef struct usb_isoc_complete_data
-{
-	struct urb *urb;
-	struct work_struct usb_bh;
-} usb_isoc_complete_data_t;
-
-/* This struct holds data we get from the rx descriptors for DMA channel 9
-   for periodic traffic (intr and isoc). */
-typedef struct rx_data
-{
-	void *data;
-	int length;
-	struct list_head list;
-} rx_data_t;
-
-typedef struct urb_entry
-{
-	struct urb *urb;
-	struct list_head list;
-} urb_entry_t;
-
-/* ---------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* destination of request */
-#define RH_INTERFACE               0x01
-#define RH_ENDPOINT                0x02
-#define RH_OTHER                   0x03
-
-#define RH_CLASS                   0x20
-#define RH_VENDOR                  0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS		0x0500
-#define RH_GET_DESCRIPTOR	0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP               0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION         0x00
-#define RH_PORT_ENABLE             0x01
-#define RH_PORT_SUSPEND            0x02
-#define RH_PORT_OVER_CURRENT       0x03
-#define RH_PORT_RESET              0x04
-#define RH_PORT_POWER              0x08
-#define RH_PORT_LOW_SPEED          0x09
-#define RH_C_PORT_CONNECTION       0x10
-#define RH_C_PORT_ENABLE           0x11
-#define RH_C_PORT_SUSPEND          0x12
-#define RH_C_PORT_OVER_CURRENT     0x13
-#define RH_C_PORT_RESET            0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER       0x00
-#define RH_C_HUB_OVER_CURRENT      0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP    0x00
-#define RH_ENDPOINT_STALL          0x01
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP               0x00
-
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-
-/* Field definitions for */
-
-#define USB_IN_command__eol__BITNR      0 /* command macros */
-#define USB_IN_command__eol__WIDTH      1
-#define USB_IN_command__eol__no         0
-#define USB_IN_command__eol__yes        1
-
-#define USB_IN_command__intr__BITNR     3
-#define USB_IN_command__intr__WIDTH     1
-#define USB_IN_command__intr__no        0
-#define USB_IN_command__intr__yes       1
-
-#define USB_IN_status__eop__BITNR       1 /* status macros. */
-#define USB_IN_status__eop__WIDTH       1
-#define USB_IN_status__eop__no          0
-#define USB_IN_status__eop__yes         1
-
-#define USB_IN_status__eot__BITNR       5
-#define USB_IN_status__eot__WIDTH       1
-#define USB_IN_status__eot__no          0
-#define USB_IN_status__eot__yes         1
-
-#define USB_IN_status__error__BITNR     6
-#define USB_IN_status__error__WIDTH     1
-#define USB_IN_status__error__no        0
-#define USB_IN_status__error__yes       1
-
-#define USB_IN_status__nodata__BITNR    7
-#define USB_IN_status__nodata__WIDTH    1
-#define USB_IN_status__nodata__no       0
-#define USB_IN_status__nodata__yes      1
-
-#define USB_IN_status__epid__BITNR      8
-#define USB_IN_status__epid__WIDTH      5
-
-#define USB_EP_command__eol__BITNR      0
-#define USB_EP_command__eol__WIDTH      1
-#define USB_EP_command__eol__no         0
-#define USB_EP_command__eol__yes        1
-
-#define USB_EP_command__eof__BITNR      1
-#define USB_EP_command__eof__WIDTH      1
-#define USB_EP_command__eof__no         0
-#define USB_EP_command__eof__yes        1
-
-#define USB_EP_command__intr__BITNR     3
-#define USB_EP_command__intr__WIDTH     1
-#define USB_EP_command__intr__no        0
-#define USB_EP_command__intr__yes       1
-
-#define USB_EP_command__enable__BITNR   4
-#define USB_EP_command__enable__WIDTH   1
-#define USB_EP_command__enable__no      0
-#define USB_EP_command__enable__yes     1
-
-#define USB_EP_command__hw_valid__BITNR 5
-#define USB_EP_command__hw_valid__WIDTH 1
-#define USB_EP_command__hw_valid__no    0
-#define USB_EP_command__hw_valid__yes   1
-
-#define USB_EP_command__epid__BITNR     8
-#define USB_EP_command__epid__WIDTH     5
-
-#define USB_SB_command__eol__BITNR      0 /* command macros. */
-#define USB_SB_command__eol__WIDTH      1
-#define USB_SB_command__eol__no         0
-#define USB_SB_command__eol__yes        1
-
-#define USB_SB_command__eot__BITNR      1
-#define USB_SB_command__eot__WIDTH      1
-#define USB_SB_command__eot__no         0
-#define USB_SB_command__eot__yes        1
-
-#define USB_SB_command__intr__BITNR     3
-#define USB_SB_command__intr__WIDTH     1
-#define USB_SB_command__intr__no        0
-#define USB_SB_command__intr__yes       1
-
-#define USB_SB_command__tt__BITNR       4
-#define USB_SB_command__tt__WIDTH       2
-#define USB_SB_command__tt__zout        0
-#define USB_SB_command__tt__in          1
-#define USB_SB_command__tt__out         2
-#define USB_SB_command__tt__setup       3
-
-
-#define USB_SB_command__rem__BITNR      8
-#define USB_SB_command__rem__WIDTH      6
-
-#define USB_SB_command__full__BITNR     6
-#define USB_SB_command__full__WIDTH     1
-#define USB_SB_command__full__no        0
-#define USB_SB_command__full__yes       1
-
-#endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f0d29ed..a66637e 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -26,7 +26,6 @@ #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>
@@ -486,9 +485,6 @@ static int ohci_run (struct ohci_hcd *oh
 	 * or if bus glue did the same (e.g. for PCI add-in cards with
 	 * PCI PM support).
 	 */
-	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
-			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-			ohci_readl (ohci, &ohci->regs->control));
 	if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
 			&& !device_may_wakeup(hcd->self.controller))
 		device_init_wakeup(hcd->self.controller, 1);
@@ -744,9 +740,6 @@ static void ohci_stop (struct usb_hcd *h
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
-	ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
-		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-		hcd->state);
 	ohci_dump (ohci, 1);
 
 	flush_scheduled_work();
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index b331ac4..7970560 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -20,10 +20,16 @@ #endif
 
 /*-------------------------------------------------------------------------*/
 
+static int broken_suspend(struct usb_hcd *hcd)
+{
+	device_init_wakeup(&hcd->self.root_hub->dev, 0);
+	return 0;
+}
+
 /* AMD 756, for most chips (early revs), corrupts register
  * values on read ... so enable the vendor workaround.
  */
-static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
+static int ohci_quirk_amd756(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
@@ -31,16 +37,14 @@ static int __devinit ohci_quirk_amd756(s
 	ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
 
 	/* also erratum 10 (suspend/resume issues) */
-	device_init_wakeup(&hcd->self.root_hub->dev, 0);
-
-	return 0;
+	return broken_suspend(hcd);
 }
 
 /* Apple's OHCI driver has a lot of bizarre workarounds
  * for this chip.  Evidently control and bulk lists
  * can get confused.  (B&W G3 models, and ...)
  */
-static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
+static int ohci_quirk_opti(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
@@ -53,7 +57,7 @@ static int __devinit ohci_quirk_opti(str
  * identify the USB (fn2). This quirk might apply to more or
  * even all NSC stuff.
  */
-static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+static int ohci_quirk_ns(struct usb_hcd *hcd)
 {
 	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 	struct pci_dev	*b;
@@ -75,7 +79,7 @@ static int __devinit ohci_quirk_ns(struc
  * delays before control or bulk queues get re-activated
  * in finish_unlinks()
  */
-static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
@@ -88,7 +92,7 @@ static int __devinit ohci_quirk_zfmicro(
 /* Check for Toshiba SCC OHCI which has big endian registers
  * and little endian in memory data structures
  */
-static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
@@ -129,6 +133,18 @@ static const struct pci_device_id ohci_p
 		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
 		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
 	},
+	{
+		/* Toshiba portege 4000 */
+		.vendor		= PCI_VENDOR_ID_AL,
+		.device		= 0x5237,
+		.subvendor	= PCI_VENDOR_ID_TOSHIBA_2,
+		.subdevice	= 0x0004,
+		.driver_data	= (unsigned long) broken_suspend,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152),
+		.driver_data = (unsigned long) broken_suspend,
+	},
 	/* FIXME for some of the early AMD 760 southbridges, OHCI
 	 * won't work at all.  blacklist them.
 	 */
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 08e237c..c43b66a 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -97,8 +97,8 @@ ohci_hcd_ppc_of_probe(struct of_device *
 		return -ENODEV;
 
 	is_bigendian =
-		device_is_compatible(dn, "ohci-bigendian") ||
-		device_is_compatible(dn, "ohci-be");
+		of_device_is_compatible(dn, "ohci-bigendian") ||
+		of_device_is_compatible(dn, "ohci-be");
 
 	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
 
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 62283a3..d7cf072 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -75,14 +75,6 @@ #if defined(CONFIG_PM)
 #endif
 };
 
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-	const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
 static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
 {
 	int result;
@@ -107,7 +99,7 @@ static int ps3_ohci_sb_probe(struct ps3_
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 		__LINE__, dev->m_region->lpar_addr);
 
-	result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+	result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 
 	if (result) {
 		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@ -165,7 +157,7 @@ fail_add_hcd:
 fail_ioremap:
 	usb_put_hcd(hcd);
 fail_create_hcd:
-	ps3_free_io_irq(virq);
+	ps3_io_irq_destroy(virq);
 fail_irq:
 	ps3_free_mmio_region(dev->m_region);
 fail_mmio:
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index f1563dc..23d2fe5 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -80,7 +80,7 @@ static int pxa27x_start_hc(struct device
 
 	inf = dev->platform_data;
 
-	pxa_set_cken(CKEN10_USBHOST, 1);
+	pxa_set_cken(CKEN_USBHOST, 1);
 
 	UHCHR |= UHCHR_FHR;
 	udelay(11);
@@ -123,7 +123,7 @@ static void pxa27x_stop_hc(struct device
 	UHCCOMS |= 1;
 	udelay(10);
 
-	pxa_set_cken(CKEN10_USBHOST, 0);
+	pxa_set_cken(CKEN_USBHOST, 0);
 }
 
 
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 5fa5647..4cfa3ff 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -38,7 +38,6 @@ #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>
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index a7fa0d7..ff0dba0 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -43,7 +43,6 @@ #include <linux/ioport.h>
 #include <linux/pci_ids.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>
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 19a0cc0..4aed305 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -123,10 +123,14 @@ static struct uhci_td *uhci_alloc_td(str
 
 static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
 {
-	if (!list_empty(&td->list))
+	if (!list_empty(&td->list)) {
 		dev_warn(uhci_dev(uhci), "td %p still in list!\n", td);
-	if (!list_empty(&td->fl_list))
+		WARN_ON(1);
+	}
+	if (!list_empty(&td->fl_list)) {
 		dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
+		WARN_ON(1);
+	}
 
 	dma_pool_free(uhci->td_pool, td, td->dma_handle);
 }
@@ -291,8 +295,10 @@ static struct uhci_qh *uhci_alloc_qh(str
 static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
 	WARN_ON(qh->state != QH_STATE_IDLE && qh->udev);
-	if (!list_empty(&qh->queue))
+	if (!list_empty(&qh->queue)) {
 		dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh);
+		WARN_ON(1);
+	}
 
 	list_del(&qh->node);
 	if (qh->udev) {
@@ -740,9 +746,11 @@ static void uhci_free_urb_priv(struct uh
 {
 	struct uhci_td *td, *tmp;
 
-	if (!list_empty(&urbp->node))
+	if (!list_empty(&urbp->node)) {
 		dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n",
 				urbp->urb);
+		WARN_ON(1);
+	}
 
 	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
 		uhci_remove_td_from_urbp(td);
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index d308afd..36502a0 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -94,7 +94,6 @@ #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 896cb2b..51bd80d 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -128,7 +128,6 @@ #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/proc_fs.h>
 
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
deleted file mode 100644
index 69a9f3b..0000000
--- a/drivers/usb/input/Kconfig
+++ /dev/null
@@ -1,370 +0,0 @@
-#
-# USB Input driver configuration
-#
-comment "USB Input Devices"
-	depends on USB
-
-config USB_HID
-	tristate "USB Human Interface Device (full HID) support"
-	default y
-	depends on USB && INPUT
-	select HID
-	---help---
-	  Say Y here if you want full HID support to connect USB keyboards,
-	  mice, joysticks, graphic tablets, or any other HID based devices
-	  to your computer via USB, as well as Uninterruptible Power Supply
-	  (UPS) and monitor control devices.
-
-	  You can't use this driver and the HIDBP (Boot Protocol) keyboard
-	  and mouse drivers at the same time. More information is available:
-	  <file:Documentation/input/input.txt>.
-
-	  If unsure, say Y.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usbhid.
-
-comment "Input core support is needed for USB HID input layer or HIDBP support"
-	depends on USB_HID && INPUT=n
-
-config USB_HIDINPUT_POWERBOOK
-	bool "Enable support for iBook/PowerBook special keys"
-	default n
-	depends on USB_HID
-	help
-	  Say Y here if you want support for the special keys (Fn, Numlock) on
-	  Apple iBooks and PowerBooks.
-
-	  If unsure, say N.
-
-config HID_FF
-	bool "Force feedback support (EXPERIMENTAL)"
-	depends on USB_HID && EXPERIMENTAL
-	help
-	  Say Y here is you want force feedback support for a few HID devices.
-	  See below for a list of supported devices.
-
-	  See <file:Documentation/input/ff.txt> for a description of the force
-	  feedback API.
-
-	  If unsure, say N.
-
-config HID_PID
-	bool "PID device support"
-	depends on HID_FF
-	help
-	  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 devices 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
-	  - Logitech WingMan Cordless RumblePad 2
-	  - Logitech WingMan Force 3D
-	  - Logitech Formula Force EX
-	  - Logitech MOMO Force wheel
-
-	  and if you want to enable force feedback for them.
-	  Note: if you say N here, this device will still be supported, but without
-	  force feedback.
-
-config PANTHERLORD_FF
-	bool "PantherLord USB/PS2 2in1 Adapter support"
-	depends on HID_FF
-	select INPUT_FF_MEMLESS if USB_HID
-	help
-	  Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
-	  to enable force feedback support for it.
-
-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
-	help
-	  Say Y here if you want to support HID devices (from the USB
-	  specification standpoint) that aren't strictly user interface
-	  devices, like monitor controls and Uninterruptable Power Supplies.
-
-	  This module supports these devices separately using a separate
-	  event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
-
-	  If unsure, say Y.
-
-menu "USB HID Boot Protocol drivers"
-	depends on USB!=n && USB_HID!=y
-
-config USB_KBD
-	tristate "USB HIDBP Keyboard (simple Boot) support"
-	depends on USB && INPUT
-	---help---
-	  Say Y here only if you are absolutely sure that you don't want
-	  to use the generic HID driver for your USB keyboard and prefer
-	  to use the keyboard in its limited Boot Protocol mode instead.
-
-	  This is almost certainly not what you want.  This is mostly
-	  useful for embedded applications or simple keyboards.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usbkbd.
-
-	  If even remotely unsure, say N.
-
-config USB_MOUSE
-	tristate "USB HIDBP Mouse (simple Boot) support"
-	depends on USB && INPUT
-	---help---
-	  Say Y here only if you are absolutely sure that you don't want
-	  to use the generic HID driver for your USB mouse and prefer
-	  to use the mouse in its limited Boot Protocol mode instead.
-
-	  This is almost certainly not what you want.  This is mostly
-	  useful for embedded applications or simple mice.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usbmouse.
-
-	  If even remotely unsure, say N.
-
-endmenu
-
-config USB_AIPTEK
-	tristate "Aiptek 6000U/8000U tablet support"
-	depends on USB && INPUT
-	help
-	  Say Y here if you want to use the USB version of the Aiptek 6000U
-	  or Aiptek 8000U tablet.  Make sure to say Y to "Mouse support"
-	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-	  (CONFIG_INPUT_EVDEV) as well.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called aiptek.
-
-config USB_WACOM
-	tristate "Wacom Intuos/Graphire tablet support"
-	depends on USB && INPUT
-	help
-	  Say Y here if you want to use the USB version of the Wacom Intuos
-	  or Graphire tablet.  Make sure to say Y to "Mouse support"
-	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-	  (CONFIG_INPUT_EVDEV) as well.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called wacom.
-
-config USB_ACECAD
-	tristate "Acecad Flair tablet support"
-	depends on USB && INPUT
-	help
-	  Say Y here if you want to use the USB version of the Acecad Flair
-	  tablet.  Make sure to say Y to "Mouse support"
-	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-	  (CONFIG_INPUT_EVDEV) as well.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called acecad.
-
-config USB_KBTAB
-	tristate "KB Gear JamStudio tablet support"
-	depends on USB && INPUT
-	help
-	  Say Y here if you want to use the USB version of the KB Gear
-	  JamStudio tablet.  Make sure to say Y to "Mouse support"
-	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-	  (CONFIG_INPUT_EVDEV) as well.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called kbtab.
-
-config USB_POWERMATE
-	tristate "Griffin PowerMate and Contour Jog support"
-	depends on USB && INPUT
-	---help---
-	  Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
-	  These are aluminum dials which can measure clockwise and anticlockwise
-	  rotation.  The dial also acts as a pushbutton.  The base contains an LED
-	  which can be instructed to pulse or to switch to a particular intensity.
-
-	  You can download userspace tools from
-	  <http://sowerbutts.com/powermate/>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called powermate.
-
-config USB_TOUCHSCREEN
-	tristate "USB Touchscreen Driver"
-	depends on USB && INPUT
-	---help---
-	  USB Touchscreen driver for:
-	  - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
-	  - PanJit TouchSet USB
-	  - 3M MicroTouch USB (EX II series)
-	  - ITM
-	  - some other eTurboTouch
-	  - Gunze AHL61
-	  - DMC TSC-10/25
-
-	  Have a look at <http://linux.chapter7.ch/touchkit/> for
-	  a usage description and the required user-space stuff.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usbtouchscreen.
-
-config USB_TOUCHSCREEN_EGALAX
-	default y
-	bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
-	depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_PANJIT
-	default y
-	bool "PanJit device support" if EMBEDDED
-	depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_3M
-	default y
-	bool "3M/Microtouch EX II series device support" if EMBEDDED
-	depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_ITM
-	default y
-	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_TOUCHSCREEN_DMC_TSC10
-	default y
-	bool "DMC TSC-10/25 device support" if EMBEDDED
-	depends on USB_TOUCHSCREEN
-
-config USB_YEALINK
-	tristate "Yealink usb-p1k voip phone"
-	depends on USB && INPUT && EXPERIMENTAL
-	---help---
-	  Say Y here if you want to enable keyboard and LCD functions of the
-	  Yealink usb-p1k usb phones. The audio part is enabled by the generic
-	  usb sound driver, so you might want to enable that as well.
-
-	  For information about how to use these additional functions, see
-	  <file:Documentation/input/yealink.txt>.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called yealink.
-
-config USB_XPAD
-	tristate "X-Box gamepad support"
-	depends on USB && INPUT
-	---help---
-	  Say Y here if you want to use the X-Box pad with your computer.
-	  Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
-	  and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
-
-	  For information about how to connect the X-Box pad to USB, see
-	  <file:Documentation/input/xpad.txt>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called xpad.
-	  
-config USB_ATI_REMOTE
-	tristate "ATI / X10 USB RF remote control"
-	depends on USB && INPUT
-	---help---
-	  Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
-	  These are RF remotes with USB receivers. 
-	  The ATI remote comes with many of ATI's All-In-Wonder video cards.
-	  The X10 "Lola" remote is available at:
-	     <http://www.x10.com/products/lola_sg1.htm>
-	  This driver provides mouse pointer, left and right mouse buttons, 
-	  and maps all the other remote buttons to keypress events.
-	  
-	  To compile this driver as a module, choose M here: the module will be
-	  called ati_remote.
-
-config USB_ATI_REMOTE2
-	tristate "ATI / Philips USB RF remote control"
-	depends on USB && INPUT
-	---help---
-	  Say Y here if you want to use an ATI or Philips USB RF remote control.
-	  These are RF remotes with USB receivers.
-	  ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
-	  and is also available as a separate product.
-	  This driver provides mouse pointer, left and right mouse buttons,
-	  and maps all the other remote buttons to keypress events.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called ati_remote2.
-
-config USB_KEYSPAN_REMOTE
-	tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
-	depends on USB && INPUT && EXPERIMENTAL
-	---help---
-	  Say Y here if you want to use a Keyspan DMR USB remote control.
-	  Currently only the UIA-11 type of receiver has been tested.  The tag
-	  on the receiver that connects to the USB port should have a P/N that
-	  will tell you what type of DMR you have.  The UIA-10 type is not
-	  supported at this time.  This driver maps all buttons to keypress
-	  events.
-
-	  To compile this driver as a module, choose M here: the module will
-	  be called keyspan_remote.
-
-config USB_APPLETOUCH
-	tristate "Apple USB Touchpad support"
-	depends on USB && INPUT
-	---help---
-	  Say Y here if you want to use an Apple USB Touchpad.
-
-	  These are the touchpads that can be found on post-February 2005
-	  Apple Powerbooks (prior models have a Synaptics touchpad connected
-	  to the ADB bus).
-
-	  This driver provides a basic mouse driver but can be interfaced
-	  with the synaptics X11 driver to provide acceleration and
-	  scrolling in X11.
-
-	  For further information, see
-	  <file:Documentation/input/appletouch.txt>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called appletouch.
-
-config USB_GTCO
-        tristate "GTCO CalComp/InterWrite USB Support"
-        depends on USB && INPUT
-        ---help---
-          Say Y here if you want to use the USB version of the GTCO
-          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
-          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-          (CONFIG_INPUT_EVDEV) as well.
-
-          To compile this driver as a module, choose M here: the
-          module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
deleted file mode 100644
index a9d206c..0000000
--- a/drivers/usb/input/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Makefile for the USB input drivers
-#
-
-# Multipart objects.
-wacom-objs	:= wacom_wac.o wacom_sys.o
-usbhid-objs	:= hid-core.o
-
-# Optional parts of multipart objects.
-
-ifeq ($(CONFIG_USB_HIDDEV),y)
-	usbhid-objs	+= hiddev.o
-endif
-ifeq ($(CONFIG_HID_PID),y)
-	usbhid-objs	+= hid-pidff.o
-endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
-	usbhid-objs	+= hid-lgff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
-	usbhid-objs	+= hid-plff.o
-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
-
-obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
-obj-$(CONFIG_USB_ATI_REMOTE)	+= ati_remote.o
-obj-$(CONFIG_USB_ATI_REMOTE2)	+= ati_remote2.o
-obj-$(CONFIG_USB_HID)		+= usbhid.o
-obj-$(CONFIG_USB_KBD)		+= usbkbd.o
-obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
-obj-$(CONFIG_USB_KEYSPAN_REMOTE)	+= keyspan_remote.o
-obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
-obj-$(CONFIG_USB_MTOUCH)	+= mtouchusb.o
-obj-$(CONFIG_USB_ITMTOUCH)	+= itmtouch.o
-obj-$(CONFIG_USB_EGALAX)	+= touchkitusb.o
-obj-$(CONFIG_USB_TOUCHSCREEN)	+= usbtouchscreen.o
-obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
-obj-$(CONFIG_USB_WACOM)		+= wacom.o
-obj-$(CONFIG_USB_ACECAD)	+= acecad.o
-obj-$(CONFIG_USB_YEALINK)	+= yealink.o
-obj-$(CONFIG_USB_XPAD)		+= xpad.o
-obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
-obj-$(CONFIG_USB_GTCO)         += gtco.o
-
-ifeq ($(CONFIG_USB_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
deleted file mode 100644
index 909138e..0000000
--- a/drivers/usb/input/acecad.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
- *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
- *
- *  USB Acecad "Acecad Flair" tablet support
- *
- *  Changelog:
- *      v3.2 - Added sysfs support
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v3.2"
-#define DRIVER_DESC    "USB Acecad Flair tablet driver"
-#define DRIVER_LICENSE "GPL"
-#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_ACECAD	0x0460
-#define USB_DEVICE_ID_FLAIR	0x0004
-#define USB_DEVICE_ID_302	0x0008
-
-struct usb_acecad {
-	char name[128];
-	char phys[64];
-	struct usb_device *usbdev;
-	struct input_dev *input;
-	struct urb *irq;
-
-	signed char *data;
-	dma_addr_t data_dma;
-};
-
-static void usb_acecad_irq(struct urb *urb)
-{
-	struct usb_acecad *acecad = urb->context;
-	unsigned char *data = acecad->data;
-	struct input_dev *dev = acecad->input;
-	int prox, status;
-
-	switch (urb->status) {
-		case 0:
-			/* success */
-			break;
-		case -ECONNRESET:
-		case -ENOENT:
-		case -ESHUTDOWN:
-			/* this urb is terminated, clean up */
-			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-			return;
-		default:
-			dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-			goto resubmit;
-	}
-
-	prox = (data[0] & 0x04) >> 2;
-	input_report_key(dev, BTN_TOOL_PEN, prox);
-
-	if (prox) {
-		int x = data[1] | (data[2] << 8);
-		int y = data[3] | (data[4] << 8);
-		/* Pressure should compute the same way for flair and 302 */
-		int pressure = data[5] | (data[6] << 8);
-		int touch = data[0] & 0x01;
-		int stylus = (data[0] & 0x10) >> 4;
-		int stylus2 = (data[0] & 0x20) >> 5;
-		input_report_abs(dev, ABS_X, x);
-		input_report_abs(dev, ABS_Y, y);
-		input_report_abs(dev, ABS_PRESSURE, pressure);
-		input_report_key(dev, BTN_TOUCH, touch);
-		input_report_key(dev, BTN_STYLUS, stylus);
-		input_report_key(dev, BTN_STYLUS2, stylus2);
-	}
-
-	/* event termination */
-	input_sync(dev);
-
-resubmit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
-		err("can't resubmit intr, %s-%s/input0, status %d",
-			acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
-}
-
-static int usb_acecad_open(struct input_dev *dev)
-{
-	struct usb_acecad *acecad = dev->private;
-
-	acecad->irq->dev = acecad->usbdev;
-	if (usb_submit_urb(acecad->irq, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void usb_acecad_close(struct input_dev *dev)
-{
-	struct usb_acecad *acecad = dev->private;
-
-	usb_kill_urb(acecad->irq);
-}
-
-static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(intf);
-	struct usb_host_interface *interface = intf->cur_altsetting;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_acecad *acecad;
-	struct input_dev *input_dev;
-	int pipe, maxp;
-
-	if (interface->desc.bNumEndpoints != 1)
-		return -ENODEV;
-
-	endpoint = &interface->endpoint[0].desc;
-
-	if (!usb_endpoint_is_int_in(endpoint))
-		return -ENODEV;
-
-	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-	acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!acecad || !input_dev)
-		goto fail1;
-
-	acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
-	if (!acecad->data)
-		goto fail1;
-
-	acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!acecad->irq)
-		goto fail2;
-
-	acecad->usbdev = dev;
-	acecad->input = input_dev;
-
-	if (dev->manufacturer)
-		strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
-
-	if (dev->product) {
-		if (dev->manufacturer)
-			strlcat(acecad->name, " ", sizeof(acecad->name));
-		strlcat(acecad->name, dev->product, sizeof(acecad->name));
-	}
-
-	usb_make_path(dev, acecad->phys, sizeof(acecad->phys));
-	strlcat(acecad->phys, "/input0", sizeof(acecad->phys));
-
-	input_dev->name = acecad->name;
-	input_dev->phys = acecad->phys;
-	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = acecad;
-
-	input_dev->open = usb_acecad_open;
-	input_dev->close = usb_acecad_close;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
-	input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-	input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
-
-	switch (id->driver_info) {
-		case 0:
-			input_dev->absmax[ABS_X] = 5000;
-			input_dev->absmax[ABS_Y] = 3750;
-			input_dev->absmax[ABS_PRESSURE] = 512;
-			if (!strlen(acecad->name))
-				snprintf(acecad->name, sizeof(acecad->name),
-					"USB Acecad Flair Tablet %04x:%04x",
-					le16_to_cpu(dev->descriptor.idVendor),
-					le16_to_cpu(dev->descriptor.idProduct));
-			break;
-		case 1:
-			input_dev->absmax[ABS_X] = 3000;
-			input_dev->absmax[ABS_Y] = 2250;
-			input_dev->absmax[ABS_PRESSURE] = 1024;
-			if (!strlen(acecad->name))
-				snprintf(acecad->name, sizeof(acecad->name),
-					"USB Acecad 302 Tablet %04x:%04x",
-					le16_to_cpu(dev->descriptor.idVendor),
-					le16_to_cpu(dev->descriptor.idProduct));
-			break;
-	}
-
-	input_dev->absfuzz[ABS_X] = 4;
-	input_dev->absfuzz[ABS_Y] = 4;
-
-	usb_fill_int_urb(acecad->irq, dev, pipe,
-			acecad->data, maxp > 8 ? 8 : maxp,
-			usb_acecad_irq, acecad, endpoint->bInterval);
-	acecad->irq->transfer_dma = acecad->data_dma;
-	acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	input_register_device(acecad->input);
-
-	usb_set_intfdata(intf, acecad);
-
-	return 0;
-
- fail2:	usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
- fail1: input_free_device(input_dev);
-	kfree(acecad);
-	return -ENOMEM;
-}
-
-static void usb_acecad_disconnect(struct usb_interface *intf)
-{
-	struct usb_acecad *acecad = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (acecad) {
-		usb_kill_urb(acecad->irq);
-		input_unregister_device(acecad->input);
-		usb_free_urb(acecad->irq);
-		usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
-		kfree(acecad);
-	}
-}
-
-static struct usb_device_id usb_acecad_id_table [] = {
-	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
-	{ USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),	 .driver_info = 1 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
-
-static struct usb_driver usb_acecad_driver = {
-	.name =		"usb_acecad",
-	.probe =	usb_acecad_probe,
-	.disconnect =	usb_acecad_disconnect,
-	.id_table =	usb_acecad_id_table,
-};
-
-static int __init usb_acecad_init(void)
-{
-	int result = usb_register(&usb_acecad_driver);
-	if (result == 0)
-		info(DRIVER_VERSION ":" DRIVER_DESC);
-	return result;
-}
-
-static void __exit usb_acecad_exit(void)
-{
-	usb_deregister(&usb_acecad_driver);
-}
-
-module_init(usb_acecad_init);
-module_exit(usb_acecad_exit);
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
deleted file mode 100644
index f857935..0000000
--- a/drivers/usb/input/aiptek.c
+++ /dev/null
@@ -1,2234 +0,0 @@
-/*
- *  Native support for the Aiptek HyperPen USB Tablets
- *  (4000U/5000U/6000U/8000U/12000U)
- *
- *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
- *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
- *
- *  based on wacom.c by
- *     Vojtech Pavlik      <vojtech@suse.cz>
- *     Andreas Bach Aaen   <abach@stofanet.dk>
- *     Clifford Wolf       <clifford@clifford.at>
- *     Sam Mosel           <sam.mosel@computer.org>
- *     James E. Blair      <corvus@gnu.org>
- *     Daniel Egger        <egger@suse.de>
- *
- *  Many thanks to Oliver Kuechemann for his support.
- *
- *  ChangeLog:
- *      v0.1 - Initial release
- *      v0.2 - Hack to get around fake event 28's. (Bryan W. Headley)
- *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
- *             Released to Linux 2.4.19 and 2.5.x
- *      v0.4 - Rewrote substantial portions of the code to deal with
- *             corrected control sequences, timing, dynamic configuration,
- *             support of 6000U - 12000U, procfs, and macro key support
- *             (Jan-1-2003 - Feb-5-2003, Bryan W. Headley)
- *      v1.0 - Added support for diagnostic messages, count of messages
- *             received from URB - Mar-8-2003, Bryan W. Headley
- *      v1.1 - added support for tablet resolution, changed DV and proximity
- *             some corrections - Jun-22-2003, martin schneebacher
- *           - Added support for the sysfs interface, deprecating the
- *             procfs interface for 2.5.x kernel. Also added support for
- *             Wheel command. Bryan W. Headley July-15-2003.
- *      v1.2 - Reworked jitter timer as a kernel thread.
- *             Bryan W. Headley November-28-2003/Jan-10-2004.
- *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
- *             machines, introduced programmableDelay as a command line
- *             parameter. Feb 7 2004, Bryan W. Headley.
- *      v1.4 - Re-wire jitter so it does not require a thread. Courtesy of
- *             Rene van Paassen. Added reporting of physical pointer device
- *             (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know
- *             for reports 1, 6.)
- *             what physical device reports for reports 1, 6.) Also enabled
- *             MOUSE and LENS tool button modes. Renamed "rubber" to "eraser".
- *             Feb 20, 2004, Bryan W. Headley.
- *      v1.5 - Added previousJitterable, so we don't do jitter delay when the
- *             user is holding a button down for periods of time.
- *
- * NOTE:
- *      This kernel driver is augmented by the "Aiptek" XFree86 input
- *      driver for your X server, as well as the Gaiptek GUI Front-end
- *      "Tablet Manager".
- *      These three products are highly interactive with one another,
- *      so therefore it's easier to document them all as one subsystem.
- *      Please visit the project's "home page", located at,
- *      http://aiptektablet.sourceforge.net.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.5 (May-15-2004)"
-#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio"
-#define DRIVER_DESC    "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
-
-/*
- * Aiptek status packet:
- *
- * (returned as Report 1 - relative coordinates from mouse and stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     0     1
- * byte1   0     0     0     0     0    BS2   BS    Tip
- * byte2  X7    X6    X5    X4    X3    X2    X1    X0
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- *
- * (returned as Report 2 - absolute coordinates from the stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     1     0
- * byte1  X7    X6    X5    X4    X3    X2    X1    X0
- * byte2  X15   X14   X13   X12   X11   X10   X9    X8
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
- * byte5   *     *     *    BS2   BS1   Tip   IR    DV
- * byte6  P7    P6    P5    P4    P3    P2    P1    P0
- * byte7  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 3 - absolute coordinates from the mouse)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     1     0
- * byte1  X7    X6    X5    X4    X3    X2    X1    X0
- * byte2  X15   X14   X13   X12   X11   X10   X9    X8
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
- * byte5   *     *     *    BS2   BS1   Tip   IR    DV
- * byte6  P7    P6    P5    P4    P3    P2    P1    P0
- * byte7  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 4 - macrokeys from the stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     1     0     0
- * byte1   0     0     0    BS2   BS    Tip   IR    DV
- * byte2   0     0     0     0     0     0     1     0
- * byte3   0     0     0    K4    K3    K2    K1    K0
- * byte4  P7    P6    P5    P4    P3    P2    P1    P0
- * byte5  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 5 - macrokeys from the mouse)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     1     0     0
- * byte1   0     0     0    BS2   BS    Tip   IR    DV
- * byte2   0     0     0     0     0     0     1     0
- * byte3   0     0     0    K4    K3    K2    K1    K0
- * byte4  P7    P6    P5    P4    P3    P2    P1    P0
- * byte5  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * IR: In Range = Proximity on
- * DV = Data Valid
- * BS = Barrel Switch (as in, macro keys)
- * BS2 also referred to as Tablet Pick
- *
- * Command Summary:
- *
- * Use report_type CONTROL (3)
- * Use report_id   2
- *
- * Command/Data    Description     Return Bytes    Return Value
- * 0x10/0x00       SwitchToMouse       0
- * 0x10/0x01       SwitchToTablet      0
- * 0x18/0x04       SetResolution       0
- * 0x12/0xFF       AutoGainOn          0
- * 0x17/0x00       FilterOn            0
- * 0x01/0x00       GetXExtension       2           MaxX
- * 0x01/0x01       GetYExtension       2           MaxY
- * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
- * 0x03/0x00       GetODMCode          2           ODMCode
- * 0x08/0x00       GetPressureLevels   2           =512
- * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
- * 0x11/0x02       EnableMacroKeys     0
- *
- * To initialize the tablet:
- *
- * (1) Send Resolution500LPI (Command)
- * (2) Query for Model code (Option Report)
- * (3) Query for ODM code (Option Report)
- * (4) Query for firmware (Option Report)
- * (5) Query for GetXExtension (Option Report)
- * (6) Query for GetYExtension (Option Report)
- * (7) Query for GetPressureLevels (Option Report)
- * (8) SwitchToTablet for Absolute coordinates, or
- *     SwitchToMouse for Relative coordinates (Command)
- * (9) EnableMacroKeys (Command)
- * (10) FilterOn (Command)
- * (11) AutoGainOn (Command)
- *
- * (Step 9 can be omitted, but you'll then have no function keys.)
- */
-
-#define USB_VENDOR_ID_AIPTEK				0x08ca
-#define USB_REQ_GET_REPORT				0x01
-#define USB_REQ_SET_REPORT				0x09
-
-	/* PointerMode codes
-	 */
-#define AIPTEK_POINTER_ONLY_MOUSE_MODE			0
-#define AIPTEK_POINTER_ONLY_STYLUS_MODE			1
-#define AIPTEK_POINTER_EITHER_MODE			2
-
-#define AIPTEK_POINTER_ALLOW_MOUSE_MODE(a)		\
-	(a == AIPTEK_POINTER_ONLY_MOUSE_MODE ||		\
-	 a == AIPTEK_POINTER_EITHER_MODE)
-#define AIPTEK_POINTER_ALLOW_STYLUS_MODE(a)		\
-	(a == AIPTEK_POINTER_ONLY_STYLUS_MODE ||	\
-	 a == AIPTEK_POINTER_EITHER_MODE)
-
-	/* CoordinateMode code
-	 */
-#define AIPTEK_COORDINATE_RELATIVE_MODE			0
-#define AIPTEK_COORDINATE_ABSOLUTE_MODE			1
-
-       /* XTilt and YTilt values
-        */
-#define AIPTEK_TILT_MIN					(-128)
-#define AIPTEK_TILT_MAX					127
-#define AIPTEK_TILT_DISABLE				(-10101)
-
-	/* Wheel values
-	 */
-#define AIPTEK_WHEEL_MIN				0
-#define AIPTEK_WHEEL_MAX				1024
-#define AIPTEK_WHEEL_DISABLE				(-10101)
-
-	/* ToolCode values, which BTW are 0x140 .. 0x14f
-	 * We have things set up such that if TOOL_BUTTON_FIRED_BIT is
-	 * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx.
-	 *
-	 * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will
-	 * get reset.
-	 */
-#define TOOL_BUTTON(x)					((x) & 0x14f)
-#define TOOL_BUTTON_FIRED(x)				((x) & 0x200)
-#define TOOL_BUTTON_FIRED_BIT				0x200
-	/* toolMode codes
-	 */
-#define AIPTEK_TOOL_BUTTON_PEN_MODE			BTN_TOOL_PEN
-#define AIPTEK_TOOL_BUTTON_PEN_MODE			BTN_TOOL_PEN
-#define AIPTEK_TOOL_BUTTON_PENCIL_MODE			BTN_TOOL_PENCIL
-#define AIPTEK_TOOL_BUTTON_BRUSH_MODE			BTN_TOOL_BRUSH
-#define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE		BTN_TOOL_AIRBRUSH
-#define AIPTEK_TOOL_BUTTON_ERASER_MODE			BTN_TOOL_RUBBER
-#define AIPTEK_TOOL_BUTTON_MOUSE_MODE			BTN_TOOL_MOUSE
-#define AIPTEK_TOOL_BUTTON_LENS_MODE			BTN_TOOL_LENS
-
-	/* Diagnostic message codes
-	 */
-#define AIPTEK_DIAGNOSTIC_NA				0
-#define AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE	1
-#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE	2
-#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED		3
-
-	/* Time to wait (in ms) to help mask hand jittering
-	 * when pressing the stylus buttons.
-	 */
-#define AIPTEK_JITTER_DELAY_DEFAULT			50
-
-	/* Time to wait (in ms) in-between sending the tablet
-	 * a command and beginning the process of reading the return
-	 * sequence from the tablet.
-	 */
-#define AIPTEK_PROGRAMMABLE_DELAY_25		25
-#define AIPTEK_PROGRAMMABLE_DELAY_50		50
-#define AIPTEK_PROGRAMMABLE_DELAY_100		100
-#define AIPTEK_PROGRAMMABLE_DELAY_200		200
-#define AIPTEK_PROGRAMMABLE_DELAY_300		300
-#define AIPTEK_PROGRAMMABLE_DELAY_400		400
-#define AIPTEK_PROGRAMMABLE_DELAY_DEFAULT	AIPTEK_PROGRAMMABLE_DELAY_400
-
-	/* Mouse button programming
-	 */
-#define AIPTEK_MOUSE_LEFT_BUTTON		0x01
-#define AIPTEK_MOUSE_RIGHT_BUTTON		0x02
-#define AIPTEK_MOUSE_MIDDLE_BUTTON		0x04
-
-	/* Stylus button programming
-	 */
-#define AIPTEK_STYLUS_LOWER_BUTTON		0x08
-#define AIPTEK_STYLUS_UPPER_BUTTON		0x10
-
-	/* Length of incoming packet from the tablet
-	 */
-#define AIPTEK_PACKET_LENGTH			8
-
-	/* We report in EV_MISC both the proximity and
-	 * whether the report came from the stylus, tablet mouse
-	 * or "unknown" -- Unknown when the tablet is in relative
-	 * mode, because we only get report 1's.
-	 */
-#define AIPTEK_REPORT_TOOL_UNKNOWN		0x10
-#define AIPTEK_REPORT_TOOL_STYLUS		0x20
-#define AIPTEK_REPORT_TOOL_MOUSE		0x40
-
-static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT;
-static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT;
-
-struct aiptek_features {
-	int odmCode;		/* Tablet manufacturer code       */
-	int modelCode;		/* Tablet model code (not unique) */
-	int firmwareCode;	/* prom/eeprom version            */
-	char usbPath[64 + 1];	/* device's physical usb path     */
-	char inputPath[64 + 1];	/* input device path              */
-};
-
-struct aiptek_settings {
-	int pointerMode;	/* stylus-, mouse-only or either */
-	int coordinateMode;	/* absolute/relative coords      */
-	int toolMode;		/* pen, pencil, brush, etc. tool */
-	int xTilt;		/* synthetic xTilt amount        */
-	int yTilt;		/* synthetic yTilt amount        */
-	int wheel;		/* synthetic wheel amount        */
-	int stylusButtonUpper;	/* stylus upper btn delivers...  */
-	int stylusButtonLower;	/* stylus lower btn delivers...  */
-	int mouseButtonLeft;	/* mouse left btn delivers...    */
-	int mouseButtonMiddle;	/* mouse middle btn delivers...  */
-	int mouseButtonRight;	/* mouse right btn delivers...   */
-	int programmableDelay;	/* delay for tablet programming  */
-	int jitterDelay;	/* delay for hand jittering      */
-};
-
-struct aiptek {
-	struct input_dev *inputdev;		/* input device struct           */
-	struct usb_device *usbdev;		/* usb device struct             */
-	struct urb *urb;			/* urb for incoming reports      */
-	dma_addr_t data_dma;			/* our dma stuffage              */
-	struct aiptek_features features;	/* tablet's array of features    */
-	struct aiptek_settings curSetting;	/* tablet's current programmable */
-	struct aiptek_settings newSetting;	/* ... and new param settings    */
-	unsigned int ifnum;			/* interface number for IO       */
-	int diagnostic;				/* tablet diagnostic codes       */
-	unsigned long eventCount;		/* event count                   */
-	int inDelay;				/* jitter: in jitter delay?      */
-	unsigned long endDelay;			/* jitter: time when delay ends  */
-	int previousJitterable;			/* jitterable prev value     */
-	unsigned char *data;			/* incoming packet data          */
-};
-
-/*
- * Permit easy lookup of keyboard events to send, versus
- * the bitmap which comes from the tablet. This hides the
- * issue that the F_keys are not sequentially numbered.
- */
-static const int macroKeyEvents[] = {
-	KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
-	KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
-	KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17,
-	KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23,
-	KEY_F24, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO,
-	KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, 0
-};
-
-/***********************************************************************
- * Relative reports deliver values in 2's complement format to
- * deal with negative offsets.
- */
-static int aiptek_convert_from_2s_complement(unsigned char c)
-{
-	int ret;
-	unsigned char b = c;
-	int negate = 0;
-
-	if ((b & 0x80) != 0) {
-		b = ~b;
-		b--;
-		negate = 1;
-	}
-	ret = b;
-	ret = (negate == 1) ? -ret : ret;
-	return ret;
-}
-
-/***********************************************************************
- * aiptek_irq can receive one of six potential reports.
- * The documentation for each is in the body of the function.
- *
- * The tablet reports on several attributes per invocation of
- * aiptek_irq. Because the Linux Input Event system allows the
- * transmission of ONE attribute per input_report_xxx() call,
- * collation has to be done on the other end to reconstitute
- * a complete tablet report. Further, the number of Input Event reports
- * submitted varies, depending on what USB report type, and circumstance.
- * To deal with this, EV_MSC is used to indicate an 'end-of-report'
- * message. This has been an undocumented convention understood by the kernel
- * tablet driver and clients such as gpm and XFree86's tablet drivers.
- *
- * Of the information received from the tablet, the one piece I
- * cannot transmit is the proximity bit (without resorting to an EV_MSC
- * convention above.) I therefore have taken over REL_MISC and ABS_MISC
- * (for relative and absolute reports, respectively) for communicating
- * Proximity. Why two events? I thought it interesting to know if the
- * Proximity event occurred while the tablet was in absolute or relative
- * mode.
- *
- * Other tablets use the notion of a certain minimum stylus pressure
- * to infer proximity. While that could have been done, that is yet
- * another 'by convention' behavior, the documentation for which
- * would be spread between two (or more) pieces of software.
- *
- * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
- * replaced with the input_sync() method (which emits EV_SYN.)
- */
-
-static void aiptek_irq(struct urb *urb)
-{
-	struct aiptek *aiptek = urb->context;
-	unsigned char *data = aiptek->data;
-	struct input_dev *inputdev = aiptek->inputdev;
-	int jitterable = 0;
-	int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
-
-	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;
-	}
-
-	/* See if we are in a delay loop -- throw out report if true.
-	 */
-	if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
-		goto exit;
-	}
-
-	aiptek->inDelay = 0;
-	aiptek->eventCount++;
-
-	/* Report 1 delivers relative coordinates with either a stylus
-	 * or the mouse. You do not know, however, which input
-	 * tool generated the event.
-	 */
-	if (data[0] == 1) {
-		if (aiptek->curSetting.coordinateMode ==
-		    AIPTEK_COORDINATE_ABSOLUTE_MODE) {
-			aiptek->diagnostic =
-			    AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
-		} else {
-			x = aiptek_convert_from_2s_complement(data[2]);
-			y = aiptek_convert_from_2s_complement(data[3]);
-
-			/* jitterable keeps track of whether any button has been pressed.
-			 * We're also using it to remap the physical mouse button mask
-			 * to pseudo-settings. (We don't specifically care about it's
-			 * value after moving/transposing mouse button bitmasks, except
-			 * that a non-zero value indicates that one or more
-			 * mouse button was pressed.)
-			 */
-			jitterable = data[5] & 0x07;
-
-			left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-			right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-			middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-
-			input_report_key(inputdev, BTN_LEFT, left);
-			input_report_key(inputdev, BTN_MIDDLE, middle);
-			input_report_key(inputdev, BTN_RIGHT, right);
-			input_report_rel(inputdev, REL_X, x);
-			input_report_rel(inputdev, REL_Y, y);
-			input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
-
-			/* Wheel support is in the form of a single-event
-			 * firing.
-			 */
-			if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
-				input_report_rel(inputdev, REL_WHEEL,
-						 aiptek->curSetting.wheel);
-				aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-			}
-			input_sync(inputdev);
-		}
-	}
-	/* Report 2 is delivered only by the stylus, and delivers
-	 * absolute coordinates.
-	 */
-	else if (data[0] == 2) {
-		if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
-			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
-		} else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
-			    (aiptek->curSetting.pointerMode)) {
-				aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
-		} else {
-			x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-			y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
-			z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
-
-			p = (data[5] & 0x01) != 0 ? 1 : 0;
-			dv = (data[5] & 0x02) != 0 ? 1 : 0;
-			tip = (data[5] & 0x04) != 0 ? 1 : 0;
-
-			/* Use jitterable to re-arrange button masks
-			 */
-			jitterable = data[5] & 0x18;
-
-			bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
-			pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
-
-			/* dv indicates 'data valid' (e.g., the tablet is in sync
-			 * and has delivered a "correct" report) We will ignore
-			 * all 'bad' reports...
-			 */
-			if (dv != 0) {
-				/* 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.
-				 */
-				if (TOOL_BUTTON_FIRED
-				    (aiptek->curSetting.toolMode) == 0) {
-					input_report_key(inputdev,
-							 TOOL_BUTTON(aiptek->curSetting.toolMode),
-							 1);
-					aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-				}
-
-				if (p != 0) {
-					input_report_abs(inputdev, ABS_X, x);
-					input_report_abs(inputdev, ABS_Y, y);
-					input_report_abs(inputdev, ABS_PRESSURE, z);
-
-					input_report_key(inputdev, BTN_TOUCH, tip);
-					input_report_key(inputdev, BTN_STYLUS, bs);
-					input_report_key(inputdev, BTN_STYLUS2, pck);
-
-					if (aiptek->curSetting.xTilt !=
-					    AIPTEK_TILT_DISABLE) {
-						input_report_abs(inputdev,
-								 ABS_TILT_X,
-								 aiptek->curSetting.xTilt);
-					}
-					if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
-						input_report_abs(inputdev,
-								 ABS_TILT_Y,
-								 aiptek->curSetting.yTilt);
-					}
-
-					/* Wheel support is in the form of a single-event
-					 * firing.
-					 */
-					if (aiptek->curSetting.wheel !=
-					    AIPTEK_WHEEL_DISABLE) {
-						input_report_abs(inputdev,
-								 ABS_WHEEL,
-								 aiptek->curSetting.wheel);
-						aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-					}
-				}
-				input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
-				input_sync(inputdev);
-			}
-		}
-	}
-	/* Report 3's come from the mouse in absolute mode.
-	 */
-	else if (data[0] == 3) {
-		if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
-			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
-		} else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
-			(aiptek->curSetting.pointerMode)) {
-			aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
-		} else {
-			x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-			y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
-
-			jitterable = data[5] & 0x1c;
-
-			p = (data[5] & 0x01) != 0 ? 1 : 0;
-			dv = (data[5] & 0x02) != 0 ? 1 : 0;
-			left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-			right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-			middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-
-			if (dv != 0) {
-				/* 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.
-				 */
-				if (TOOL_BUTTON_FIRED
-				    (aiptek->curSetting.toolMode) == 0) {
-					input_report_key(inputdev,
-							 TOOL_BUTTON(aiptek->curSetting.toolMode),
-							 1);
-					aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-				}
-
-				if (p != 0) {
-					input_report_abs(inputdev, ABS_X, x);
-					input_report_abs(inputdev, ABS_Y, y);
-
-					input_report_key(inputdev, BTN_LEFT, left);
-					input_report_key(inputdev, BTN_MIDDLE, middle);
-					input_report_key(inputdev, BTN_RIGHT, right);
-
-					/* Wheel support is in the form of a single-event
-					 * firing.
-					 */
-					if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
-						input_report_abs(inputdev,
-								 ABS_WHEEL,
-								 aiptek->curSetting.wheel);
-						aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-					}
-				}
-				input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
-				input_sync(inputdev);
-			}
-		}
-	}
-	/* Report 4s come from the macro keys when pressed by stylus
-	 */
-	else if (data[0] == 4) {
-		jitterable = data[1] & 0x18;
-
-		p = (data[1] & 0x01) != 0 ? 1 : 0;
-		dv = (data[1] & 0x02) != 0 ? 1 : 0;
-		tip = (data[1] & 0x04) != 0 ? 1 : 0;
-		bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
-		pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
-
-		macro = data[3];
-		z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
-
-		if (dv != 0) {
-			/* 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.
-			 */
-			if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-				input_report_key(inputdev,
-						 TOOL_BUTTON(aiptek->curSetting.toolMode),
-						 1);
-				aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-			}
-
-			if (p != 0) {
-				input_report_key(inputdev, BTN_TOUCH, tip);
-				input_report_key(inputdev, BTN_STYLUS, bs);
-				input_report_key(inputdev, BTN_STYLUS2, pck);
-				input_report_abs(inputdev, ABS_PRESSURE, z);
-			}
-
-			/* For safety, we're sending key 'break' codes for the
-			 * neighboring macro keys.
-			 */
-			if (macro > 0) {
-				input_report_key(inputdev,
-						 macroKeyEvents[macro - 1], 0);
-			}
-			if (macro < 25) {
-				input_report_key(inputdev,
-						 macroKeyEvents[macro + 1], 0);
-			}
-			input_report_key(inputdev, macroKeyEvents[macro], p);
-			input_report_abs(inputdev, ABS_MISC,
-					 p | AIPTEK_REPORT_TOOL_STYLUS);
-			input_sync(inputdev);
-		}
-	}
-	/* Report 5s come from the macro keys when pressed by mouse
-	 */
-	else if (data[0] == 5) {
-		jitterable = data[1] & 0x1c;
-
-		p = (data[1] & 0x01) != 0 ? 1 : 0;
-		dv = (data[1] & 0x02) != 0 ? 1 : 0;
-		left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-		right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-		middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-		macro = data[3];
-
-		if (dv != 0) {
-			/* 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.
-			 */
-			if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-				input_report_key(inputdev,
-						 TOOL_BUTTON(aiptek->curSetting.toolMode),
-						 1);
-				aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-			}
-
-			if (p != 0) {
-				input_report_key(inputdev, BTN_LEFT, left);
-				input_report_key(inputdev, BTN_MIDDLE, middle);
-				input_report_key(inputdev, BTN_RIGHT, right);
-			}
-
-			/* For safety, we're sending key 'break' codes for the
-			 * neighboring macro keys.
-			 */
-			if (macro > 0) {
-				input_report_key(inputdev,
-						 macroKeyEvents[macro - 1], 0);
-			}
-			if (macro < 25) {
-				input_report_key(inputdev,
-						 macroKeyEvents[macro + 1], 0);
-			}
-
-			input_report_key(inputdev, macroKeyEvents[macro], 1);
-			input_report_rel(inputdev, ABS_MISC,
-					 p | AIPTEK_REPORT_TOOL_MOUSE);
-			input_sync(inputdev);
-		}
-	}
-	/* We have no idea which tool can generate a report 6. Theoretically,
-	 * neither need to, having been given reports 4 & 5 for such use.
-	 * However, report 6 is the 'official-looking' report for macroKeys;
-	 * reports 4 & 5 supposively are used to support unnamed, unknown
-	 * hat switches (which just so happen to be the macroKeys.)
-	 */
-	else if (data[0] == 6) {
-		macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-		if (macro > 0) {
-			input_report_key(inputdev, macroKeyEvents[macro - 1],
-					 0);
-		}
-		if (macro < 25) {
-			input_report_key(inputdev, macroKeyEvents[macro + 1],
-					 0);
-		}
-
-		/* 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.
-		 */
-		if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-			input_report_key(inputdev,
-					 TOOL_BUTTON(aiptek->curSetting.
-						     toolMode), 1);
-			aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-		}
-
-		input_report_key(inputdev, macroKeyEvents[macro], 1);
-		input_report_abs(inputdev, ABS_MISC,
-				 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
-		input_sync(inputdev);
-	} else {
-		dbg("Unknown report %d", data[0]);
-	}
-
-	/* Jitter may occur when the user presses a button on the stlyus
-	 * or the mouse. What we do to prevent that is wait 'x' milliseconds
-	 * following a 'jitterable' event, which should give the hand some time
-	 * stabilize itself.
-	 *
-	 * We just introduced aiptek->previousJitterable to carry forth the
-	 * notion that jitter occurs when the button state changes from on to off:
-	 * a person drawing, holding a button down is not subject to jittering.
-	 * With that in mind, changing from upper button depressed to lower button
-	 * WILL transition through a jitter delay.
-	 */
-
-	if (aiptek->previousJitterable != jitterable &&
-	    aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
-		aiptek->endDelay = jiffies +
-		    ((aiptek->curSetting.jitterDelay * HZ) / 1000);
-		aiptek->inDelay = 1;
-	}
-	aiptek->previousJitterable = jitterable;
-
-exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval != 0) {
-		err("%s - usb_submit_urb failed with result %d",
-		    __FUNCTION__, retval);
-	}
-}
-
-/***********************************************************************
- * These are the USB id's known so far. We do not identify them to
- * specific Aiptek model numbers, because there has been overlaps,
- * use, and reuse of id's in existing models. Certain models have
- * been known to use more than one ID, indicative perhaps of
- * manufacturing revisions. In any event, we consider these
- * IDs to not be model-specific nor unique.
- */
-static const struct usb_device_id aiptek_ids[] = {
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)},
-	{USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)},
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, aiptek_ids);
-
-/***********************************************************************
- * Open an instance of the tablet driver.
- */
-static int aiptek_open(struct input_dev *inputdev)
-{
-	struct aiptek *aiptek = inputdev->private;
-
-	aiptek->urb->dev = aiptek->usbdev;
-	if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
-		return -EIO;
-
-	return 0;
-}
-
-/***********************************************************************
- * Close an instance of the tablet driver.
- */
-static void aiptek_close(struct input_dev *inputdev)
-{
-	struct aiptek *aiptek = inputdev->private;
-
-	usb_kill_urb(aiptek->urb);
-}
-
-/***********************************************************************
- * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
- * where they were known as usb_set_report and usb_get_report.
- */
-static int
-aiptek_set_report(struct aiptek *aiptek,
-		  unsigned char report_type,
-		  unsigned char report_id, void *buffer, int size)
-{
-	return usb_control_msg(aiptek->usbdev,
-			       usb_sndctrlpipe(aiptek->usbdev, 0),
-			       USB_REQ_SET_REPORT,
-			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-			       USB_DIR_OUT, (report_type << 8) + report_id,
-			       aiptek->ifnum, buffer, size, 5000);
-}
-
-static int
-aiptek_get_report(struct aiptek *aiptek,
-		  unsigned char report_type,
-		  unsigned char report_id, void *buffer, int size)
-{
-	return usb_control_msg(aiptek->usbdev,
-			       usb_rcvctrlpipe(aiptek->usbdev, 0),
-			       USB_REQ_GET_REPORT,
-			       USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-			       USB_DIR_IN, (report_type << 8) + report_id,
-			       aiptek->ifnum, buffer, size, 5000);
-}
-
-/***********************************************************************
- * Send a command to the tablet.
- */
-static int
-aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
-{
-	const int sizeof_buf = 3 * sizeof(u8);
-	int ret;
-	u8 *buf;
-
-	buf = kmalloc(sizeof_buf, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	buf[0] = 2;
-	buf[1] = command;
-	buf[2] = data;
-
-	if ((ret =
-	     aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-		dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
-		    command, data);
-	}
-	kfree(buf);
-	return ret < 0 ? ret : 0;
-}
-
-/***********************************************************************
- * Retrieve information from the tablet. Querying info is defined as first
- * sending the {command,data} sequence as a command, followed by a wait
- * (aka, "programmaticDelay") and then a "read" request.
- */
-static int
-aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
-{
-	const int sizeof_buf = 3 * sizeof(u8);
-	int ret;
-	u8 *buf;
-
-	buf = kmalloc(sizeof_buf, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	buf[0] = 2;
-	buf[1] = command;
-	buf[2] = data;
-
-	if (aiptek_command(aiptek, command, data) != 0) {
-		kfree(buf);
-		return -EIO;
-	}
-	msleep(aiptek->curSetting.programmableDelay);
-
-	if ((ret =
-	     aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-		dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
-		    buf[0], buf[1], buf[2]);
-		ret = -EIO;
-	} else {
-		ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
-	}
-	kfree(buf);
-	return ret;
-}
-
-/***********************************************************************
- * Program the tablet into either absolute or relative mode.
- * We also get information about the tablet's size.
- */
-static int aiptek_program_tablet(struct aiptek *aiptek)
-{
-	int ret;
-	/* Execute Resolution500LPI */
-	if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0)
-		return ret;
-
-	/* Query getModelCode */
-	if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0)
-		return ret;
-	aiptek->features.modelCode = ret & 0xff;
-
-	/* Query getODMCode */
-	if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0)
-		return ret;
-	aiptek->features.odmCode = ret;
-
-	/* Query getFirmwareCode */
-	if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0)
-		return ret;
-	aiptek->features.firmwareCode = ret;
-
-	/* Query getXextension */
-	if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0)
-		return ret;
-	aiptek->inputdev->absmin[ABS_X] = 0;
-	aiptek->inputdev->absmax[ABS_X] = ret - 1;
-
-	/* Query getYextension */
-	if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0)
-		return ret;
-	aiptek->inputdev->absmin[ABS_Y] = 0;
-	aiptek->inputdev->absmax[ABS_Y] = ret - 1;
-
-	/* Query getPressureLevels */
-	if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0)
-		return ret;
-	aiptek->inputdev->absmin[ABS_PRESSURE] = 0;
-	aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1;
-
-	/* Depending on whether we are in absolute or relative mode, we will
-	 * do a switchToTablet(absolute) or switchToMouse(relative) command.
-	 */
-	if (aiptek->curSetting.coordinateMode ==
-	    AIPTEK_COORDINATE_ABSOLUTE_MODE) {
-		/* Execute switchToTablet */
-		if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) {
-			return ret;
-		}
-	} else {
-		/* Execute switchToMouse */
-		if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) {
-			return ret;
-		}
-	}
-
-	/* Enable the macro keys */
-	if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0)
-		return ret;
-#if 0
-	/* Execute FilterOn */
-	if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0)
-		return ret;
-#endif
-
-	/* Execute AutoGainOn */
-	if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0)
-		return ret;
-
-	/* Reset the eventCount, so we track events from last (re)programming
-	 */
-	aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA;
-	aiptek->eventCount = 0;
-
-	return 0;
-}
-
-/***********************************************************************
- * Sysfs functions. Sysfs prefers that individually-tunable parameters
- * exist in their separate pseudo-files. Summary data that is immutable
- * may exist in a singular file so long as you don't define a writeable
- * interface.
- */
-
-/***********************************************************************
- * support the 'size' file -- display support
- */
-static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "%dx%d\n",
-			aiptek->inputdev->absmax[ABS_X] + 1,
-			aiptek->inputdev->absmax[ABS_Y] + 1);
-}
-
-/* These structs define the sysfs files, param #1 is the name of the
- * file, param 2 is the file permissions, param 3 & 4 are to the
- * output generator and input parser routines. Absence of a routine is
- * permitted -- it only means can't either 'cat' the file, or send data
- * to it.
- */
-static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);
-
-/***********************************************************************
- * support routines for the 'product_id' file
- */
-static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n",
-			aiptek->inputdev->id.product);
-}
-
-static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor_id' file
- */
-static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor);
-}
-
-static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor' file
- */
-static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int retval;
-
-	if (aiptek == NULL)
-		return 0;
-
-	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
-	return retval;
-}
-
-static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL);
-
-/***********************************************************************
- * support routines for the 'product' file
- */
-static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int retval;
-
-	if (aiptek == NULL)
-		return 0;
-
-	retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
-	return retval;
-}
-
-static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL);
-
-/***********************************************************************
- * support routines for the 'pointer_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.pointerMode) {
-	case AIPTEK_POINTER_ONLY_STYLUS_MODE:
-		s = "stylus";
-		break;
-
-	case AIPTEK_POINTER_ONLY_MOUSE_MODE:
-		s = "mouse";
-		break;
-
-	case AIPTEK_POINTER_EITHER_MODE:
-		s = "either";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "stylus") == 0) {
-		aiptek->newSetting.pointerMode =
-		    AIPTEK_POINTER_ONLY_STYLUS_MODE;
-	} else if (strcmp(buf, "mouse") == 0) {
-		aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE;
-	} else if (strcmp(buf, "either") == 0) {
-		aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(pointer_mode,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletPointerMode, store_tabletPointerMode);
-
-/***********************************************************************
- * support routines for the 'coordinate_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.coordinateMode) {
-	case AIPTEK_COORDINATE_ABSOLUTE_MODE:
-		s = "absolute";
-		break;
-
-	case AIPTEK_COORDINATE_RELATIVE_MODE:
-		s = "relative";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "absolute") == 0) {
-		aiptek->newSetting.pointerMode =
-		    AIPTEK_COORDINATE_ABSOLUTE_MODE;
-	} else if (strcmp(buf, "relative") == 0) {
-		aiptek->newSetting.pointerMode =
-		    AIPTEK_COORDINATE_RELATIVE_MODE;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(coordinate_mode,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletCoordinateMode, store_tabletCoordinateMode);
-
-/***********************************************************************
- * support routines for the 'tool_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) {
-	case AIPTEK_TOOL_BUTTON_MOUSE_MODE:
-		s = "mouse";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_ERASER_MODE:
-		s = "eraser";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_PENCIL_MODE:
-		s = "pencil";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_PEN_MODE:
-		s = "pen";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_BRUSH_MODE:
-		s = "brush";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE:
-		s = "airbrush";
-		break;
-
-	case AIPTEK_TOOL_BUTTON_LENS_MODE:
-		s = "lens";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "mouse") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE;
-	} else if (strcmp(buf, "eraser") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE;
-	} else if (strcmp(buf, "pencil") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE;
-	} else if (strcmp(buf, "pen") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
-	} else if (strcmp(buf, "brush") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE;
-	} else if (strcmp(buf, "airbrush") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE;
-	} else if (strcmp(buf, "lens") == 0) {
-		aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE;
-	}
-
-	return count;
-}
-
-static DEVICE_ATTR(tool_mode,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletToolMode, store_tabletToolMode);
-
-/***********************************************************************
- * support routines for the 'xtilt' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
-		return snprintf(buf, PAGE_SIZE, "disable\n");
-	} else {
-		return snprintf(buf, PAGE_SIZE, "%d\n",
-				aiptek->curSetting.xTilt);
-	}
-}
-
-static ssize_t
-store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int x;
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "disable") == 0) {
-		aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
-	} else {
-		x = (int)simple_strtol(buf, NULL, 10);
-		if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
-			aiptek->newSetting.xTilt = x;
-		}
-	}
-	return count;
-}
-
-static DEVICE_ATTR(xtilt,
-		   S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
-
-/***********************************************************************
- * support routines for the 'ytilt' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
-		return snprintf(buf, PAGE_SIZE, "disable\n");
-	} else {
-		return snprintf(buf, PAGE_SIZE, "%d\n",
-				aiptek->curSetting.yTilt);
-	}
-}
-
-static ssize_t
-store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	int y;
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "disable") == 0) {
-		aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
-	} else {
-		y = (int)simple_strtol(buf, NULL, 10);
-		if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
-			aiptek->newSetting.yTilt = y;
-		}
-	}
-	return count;
-}
-
-static DEVICE_ATTR(ytilt,
-		   S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
-
-/***********************************************************************
- * support routines for the 'jitter' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
-}
-
-static ssize_t
-store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
-	return count;
-}
-
-static DEVICE_ATTR(jitter,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletJitterDelay, store_tabletJitterDelay);
-
-/***********************************************************************
- * support routines for the 'delay' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			aiptek->curSetting.programmableDelay);
-}
-
-static ssize_t
-store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
-	return count;
-}
-
-static DEVICE_ATTR(delay,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletProgrammableDelay, store_tabletProgrammableDelay);
-
-/***********************************************************************
- * support routines for the 'input_path' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n",
-			aiptek->features.inputPath);
-}
-
-static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL);
-
-/***********************************************************************
- * support routines for the 'event_count' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
-}
-
-static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
-
-/***********************************************************************
- * support routines for the 'diagnostic' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *retMsg;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->diagnostic) {
-	case AIPTEK_DIAGNOSTIC_NA:
-		retMsg = "no errors\n";
-		break;
-
-	case AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE:
-		retMsg = "Error: receiving relative reports\n";
-		break;
-
-	case AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE:
-		retMsg = "Error: receiving absolute reports\n";
-		break;
-
-	case AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED:
-		if (aiptek->curSetting.pointerMode ==
-		    AIPTEK_POINTER_ONLY_MOUSE_MODE) {
-			retMsg = "Error: receiving stylus reports\n";
-		} else {
-			retMsg = "Error: receiving mouse reports\n";
-		}
-		break;
-
-	default:
-		return 0;
-	}
-	return snprintf(buf, PAGE_SIZE, retMsg);
-}
-
-static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
-
-/***********************************************************************
- * support routines for the 'stylus_upper' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.stylusButtonUpper) {
-	case AIPTEK_STYLUS_UPPER_BUTTON:
-		s = "upper";
-		break;
-
-	case AIPTEK_STYLUS_LOWER_BUTTON:
-		s = "lower";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "upper") == 0) {
-		aiptek->newSetting.stylusButtonUpper =
-		    AIPTEK_STYLUS_UPPER_BUTTON;
-	} else if (strcmp(buf, "lower") == 0) {
-		aiptek->newSetting.stylusButtonUpper =
-		    AIPTEK_STYLUS_LOWER_BUTTON;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(stylus_upper,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletStylusUpper, store_tabletStylusUpper);
-
-/***********************************************************************
- * support routines for the 'stylus_lower' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.stylusButtonLower) {
-	case AIPTEK_STYLUS_UPPER_BUTTON:
-		s = "upper";
-		break;
-
-	case AIPTEK_STYLUS_LOWER_BUTTON:
-		s = "lower";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "upper") == 0) {
-		aiptek->newSetting.stylusButtonLower =
-		    AIPTEK_STYLUS_UPPER_BUTTON;
-	} else if (strcmp(buf, "lower") == 0) {
-		aiptek->newSetting.stylusButtonLower =
-		    AIPTEK_STYLUS_LOWER_BUTTON;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(stylus_lower,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletStylusLower, store_tabletStylusLower);
-
-/***********************************************************************
- * support routines for the 'mouse_left' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.mouseButtonLeft) {
-	case AIPTEK_MOUSE_LEFT_BUTTON:
-		s = "left";
-		break;
-
-	case AIPTEK_MOUSE_MIDDLE_BUTTON:
-		s = "middle";
-		break;
-
-	case AIPTEK_MOUSE_RIGHT_BUTTON:
-		s = "right";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "left") == 0) {
-		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
-	} else if (strcmp(buf, "middle") == 0) {
-		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON;
-	} else if (strcmp(buf, "right") == 0) {
-		aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(mouse_left,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletMouseLeft, store_tabletMouseLeft);
-
-/***********************************************************************
- * support routines for the 'mouse_middle' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.mouseButtonMiddle) {
-	case AIPTEK_MOUSE_LEFT_BUTTON:
-		s = "left";
-		break;
-
-	case AIPTEK_MOUSE_MIDDLE_BUTTON:
-		s = "middle";
-		break;
-
-	case AIPTEK_MOUSE_RIGHT_BUTTON:
-		s = "right";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "left") == 0) {
-		aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON;
-	} else if (strcmp(buf, "middle") == 0) {
-		aiptek->newSetting.mouseButtonMiddle =
-		    AIPTEK_MOUSE_MIDDLE_BUTTON;
-	} else if (strcmp(buf, "right") == 0) {
-		aiptek->newSetting.mouseButtonMiddle =
-		    AIPTEK_MOUSE_RIGHT_BUTTON;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(mouse_middle,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletMouseMiddle, store_tabletMouseMiddle);
-
-/***********************************************************************
- * support routines for the 'mouse_right' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-	char *s;
-
-	if (aiptek == NULL)
-		return 0;
-
-	switch (aiptek->curSetting.mouseButtonRight) {
-	case AIPTEK_MOUSE_LEFT_BUTTON:
-		s = "left";
-		break;
-
-	case AIPTEK_MOUSE_MIDDLE_BUTTON:
-		s = "middle";
-		break;
-
-	case AIPTEK_MOUSE_RIGHT_BUTTON:
-		s = "right";
-		break;
-
-	default:
-		s = "unknown";
-		break;
-	}
-	return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (strcmp(buf, "left") == 0) {
-		aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON;
-	} else if (strcmp(buf, "middle") == 0) {
-		aiptek->newSetting.mouseButtonRight =
-		    AIPTEK_MOUSE_MIDDLE_BUTTON;
-	} else if (strcmp(buf, "right") == 0) {
-		aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
-	}
-	return count;
-}
-
-static DEVICE_ATTR(mouse_right,
-		   S_IRUGO | S_IWUGO,
-		   show_tabletMouseRight, store_tabletMouseRight);
-
-/***********************************************************************
- * support routines for the 'wheel' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
-		return snprintf(buf, PAGE_SIZE, "disable\n");
-	} else {
-		return snprintf(buf, PAGE_SIZE, "%d\n",
-				aiptek->curSetting.wheel);
-	}
-}
-
-static ssize_t
-store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
-	return count;
-}
-
-static DEVICE_ATTR(wheel,
-		   S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
-
-/***********************************************************************
- * support routines for the 'execute' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	/* There is nothing useful to display, so a one-line manual
-	 * is in order...
-	 */
-	return snprintf(buf, PAGE_SIZE,
-			"Write anything to this file to program your tablet.\n");
-}
-
-static ssize_t
-store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	/* We do not care what you write to this file. Merely the action
-	 * of writing to this file triggers a tablet reprogramming.
-	 */
-	memcpy(&aiptek->curSetting, &aiptek->newSetting,
-	       sizeof(struct aiptek_settings));
-
-	if (aiptek_program_tablet(aiptek) < 0)
-		return -EIO;
-
-	return count;
-}
-
-static DEVICE_ATTR(execute,
-		   S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
-
-/***********************************************************************
- * support routines for the 'odm_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
-}
-
-static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
-
-/***********************************************************************
- * support routines for the 'model_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
-}
-
-static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
-
-/***********************************************************************
- * support routines for the 'firmware_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct aiptek *aiptek = dev_get_drvdata(dev);
-
-	if (aiptek == NULL)
-		return 0;
-
-	return snprintf(buf, PAGE_SIZE, "%04x\n",
-			aiptek->features.firmwareCode);
-}
-
-static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
-
-/***********************************************************************
- * This routine removes all existing sysfs files managed by this device
- * driver.
- */
-static void aiptek_delete_files(struct device *dev)
-{
-	device_remove_file(dev, &dev_attr_size);
-	device_remove_file(dev, &dev_attr_product_id);
-	device_remove_file(dev, &dev_attr_vendor_id);
-	device_remove_file(dev, &dev_attr_vendor);
-	device_remove_file(dev, &dev_attr_product);
-	device_remove_file(dev, &dev_attr_pointer_mode);
-	device_remove_file(dev, &dev_attr_coordinate_mode);
-	device_remove_file(dev, &dev_attr_tool_mode);
-	device_remove_file(dev, &dev_attr_xtilt);
-	device_remove_file(dev, &dev_attr_ytilt);
-	device_remove_file(dev, &dev_attr_jitter);
-	device_remove_file(dev, &dev_attr_delay);
-	device_remove_file(dev, &dev_attr_input_path);
-	device_remove_file(dev, &dev_attr_event_count);
-	device_remove_file(dev, &dev_attr_diagnostic);
-	device_remove_file(dev, &dev_attr_odm_code);
-	device_remove_file(dev, &dev_attr_model_code);
-	device_remove_file(dev, &dev_attr_firmware_code);
-	device_remove_file(dev, &dev_attr_stylus_lower);
-	device_remove_file(dev, &dev_attr_stylus_upper);
-	device_remove_file(dev, &dev_attr_mouse_left);
-	device_remove_file(dev, &dev_attr_mouse_middle);
-	device_remove_file(dev, &dev_attr_mouse_right);
-	device_remove_file(dev, &dev_attr_wheel);
-	device_remove_file(dev, &dev_attr_execute);
-}
-
-/***********************************************************************
- * This routine creates the sysfs files managed by this device
- * driver.
- */
-static int aiptek_add_files(struct device *dev)
-{
-	int ret;
-
-	if ((ret = device_create_file(dev, &dev_attr_size)) ||
-	    (ret = device_create_file(dev, &dev_attr_product_id)) ||
-	    (ret = device_create_file(dev, &dev_attr_vendor_id)) ||
-	    (ret = device_create_file(dev, &dev_attr_vendor)) ||
-	    (ret = device_create_file(dev, &dev_attr_product)) ||
-	    (ret = device_create_file(dev, &dev_attr_pointer_mode)) ||
-	    (ret = device_create_file(dev, &dev_attr_coordinate_mode)) ||
-	    (ret = device_create_file(dev, &dev_attr_tool_mode)) ||
-	    (ret = device_create_file(dev, &dev_attr_xtilt)) ||
-	    (ret = device_create_file(dev, &dev_attr_ytilt)) ||
-	    (ret = device_create_file(dev, &dev_attr_jitter)) ||
-	    (ret = device_create_file(dev, &dev_attr_delay)) ||
-	    (ret = device_create_file(dev, &dev_attr_input_path)) ||
-	    (ret = device_create_file(dev, &dev_attr_event_count)) ||
-	    (ret = device_create_file(dev, &dev_attr_diagnostic)) ||
-	    (ret = device_create_file(dev, &dev_attr_odm_code)) ||
-	    (ret = device_create_file(dev, &dev_attr_model_code)) ||
-	    (ret = device_create_file(dev, &dev_attr_firmware_code)) ||
-	    (ret = device_create_file(dev, &dev_attr_stylus_lower)) ||
-	    (ret = device_create_file(dev, &dev_attr_stylus_upper)) ||
-	    (ret = device_create_file(dev, &dev_attr_mouse_left)) ||
-	    (ret = device_create_file(dev, &dev_attr_mouse_middle)) ||
-	    (ret = device_create_file(dev, &dev_attr_mouse_right)) ||
-	    (ret = device_create_file(dev, &dev_attr_wheel)) ||
-	    (ret = device_create_file(dev, &dev_attr_execute))) {
-		err("aiptek: killing own sysfs device files\n");
-		aiptek_delete_files(dev);
-	}
-	return ret;
-}
-
-/***********************************************************************
- * This routine is called when a tablet has been identified. It basically
- * sets up the tablet and the driver's internal structures.
- */
-static int
-aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *usbdev = interface_to_usbdev(intf);
-	struct usb_endpoint_descriptor *endpoint;
-	struct aiptek *aiptek;
-	struct input_dev *inputdev;
-	struct input_handle *inputhandle;
-	struct list_head *node, *next;
-	int i;
-	int speeds[] = { 0,
-		AIPTEK_PROGRAMMABLE_DELAY_50,
-		AIPTEK_PROGRAMMABLE_DELAY_400,
-		AIPTEK_PROGRAMMABLE_DELAY_25,
-		AIPTEK_PROGRAMMABLE_DELAY_100,
-		AIPTEK_PROGRAMMABLE_DELAY_200,
-		AIPTEK_PROGRAMMABLE_DELAY_300
-	};
-
-	/* programmableDelay is where the command-line specified
-	 * delay is kept. We make it the first element of speeds[],
-	 * so therefore, your override speed is tried first, then the
-	 * remainder. Note that the default value of 400ms will be tried
-	 * if you do not specify any command line parameter.
-	 */
-	speeds[0] = programmableDelay;
-
-	aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
-	inputdev = input_allocate_device();
-	if (!aiptek || !inputdev)
-		goto fail1;
-
-	aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
-					GFP_ATOMIC, &aiptek->data_dma);
-	if (!aiptek->data)
-		goto fail1;
-
-	aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!aiptek->urb)
-		goto fail2;
-
-	aiptek->inputdev = inputdev;
-	aiptek->usbdev = usbdev;
-	aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
-	aiptek->inDelay = 0;
-	aiptek->endDelay = 0;
-	aiptek->previousJitterable = 0;
-
-	/* Set up the curSettings struct. Said struct contains the current
-	 * programmable parameters. The newSetting struct contains changes
-	 * the user makes to the settings via the sysfs interface. Those
-	 * changes are not "committed" to curSettings until the user
-	 * writes to the sysfs/.../execute file.
-	 */
-	aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
-	aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE;
-	aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
-	aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE;
-	aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE;
-	aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
-	aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON;
-	aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
-	aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON;
-	aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON;
-	aiptek->curSetting.jitterDelay = jitterDelay;
-	aiptek->curSetting.programmableDelay = programmableDelay;
-
-	/* Both structs should have equivalent settings
-	 */
-	aiptek->newSetting = aiptek->curSetting;
-
-	/* Determine the usb devices' physical path.
-	 * Asketh not why we always pretend we're using "../input0",
-	 * but I suspect this will have to be refactored one
-	 * day if a single USB device can be a keyboard & a mouse
-	 * & a tablet, and the inputX number actually will tell
-	 * us something...
-	 */
-	usb_make_path(usbdev, aiptek->features.usbPath,
-			sizeof(aiptek->features.usbPath));
-	strlcat(aiptek->features.usbPath, "/input0",
-		sizeof(aiptek->features.usbPath));
-
-	/* Set up client data, pointers to open and close routines
-	 * for the input device.
-	 */
-	inputdev->name = "Aiptek";
-	inputdev->phys = aiptek->features.usbPath;
-	usb_to_input_id(usbdev, &inputdev->id);
-	inputdev->cdev.dev = &intf->dev;
-	inputdev->private = aiptek;
-	inputdev->open = aiptek_open;
-	inputdev->close = aiptek_close;
-
-	/* Now program the capacities of the tablet, in terms of being
-	 * an input device.
-	 */
-	inputdev->evbit[0] |= BIT(EV_KEY)
-	    | BIT(EV_ABS)
-	    | BIT(EV_REL)
-	    | BIT(EV_MSC);
-
-	inputdev->absbit[0] |= BIT(ABS_MISC);
-
-	inputdev->relbit[0] |=
-	    (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC));
-
-	inputdev->keybit[LONG(BTN_LEFT)] |=
-	    (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE));
-
-	inputdev->keybit[LONG(BTN_DIGI)] |=
-	    (BIT(BTN_TOOL_PEN) |
-	     BIT(BTN_TOOL_RUBBER) |
-	     BIT(BTN_TOOL_PENCIL) |
-	     BIT(BTN_TOOL_AIRBRUSH) |
-	     BIT(BTN_TOOL_BRUSH) |
-	     BIT(BTN_TOOL_MOUSE) |
-	     BIT(BTN_TOOL_LENS) |
-	     BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2));
-
-	inputdev->mscbit[0] = BIT(MSC_SERIAL);
-
-	/* Programming the tablet macro keys needs to be done with a for loop
-	 * as the keycodes are discontiguous.
-	 */
-	for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
-		set_bit(macroKeyEvents[i], inputdev->keybit);
-
-	/*
-	 * Program the input device coordinate capacities. We do not yet
-	 * know what maximum X, Y, and Z values are, so we're putting fake
-	 * values in. Later, we'll ask the tablet to put in the correct
-	 * values.
-	 */
-	input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0);
-	input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0);
-	input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0);
-	input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
-	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
-	input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
-
-	endpoint = &intf->altsetting[0].endpoint[0].desc;
-
-	/* Go set up our URB, which is called when the tablet receives
-	 * input.
-	 */
-	usb_fill_int_urb(aiptek->urb,
-			 aiptek->usbdev,
-			 usb_rcvintpipe(aiptek->usbdev,
-					endpoint->bEndpointAddress),
-			 aiptek->data, 8, aiptek_irq, aiptek,
-			 endpoint->bInterval);
-
-	aiptek->urb->transfer_dma = aiptek->data_dma;
-	aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* Program the tablet. This sets the tablet up in the mode
-	 * specified in newSetting, and also queries the tablet's
-	 * physical capacities.
-	 *
-	 * Sanity check: if a tablet doesn't like the slow programmatic
-	 * delay, we often get sizes of 0x0. Let's use that as an indicator
-	 * to try faster delays, up to 25 ms. If that logic fails, well, you'll
-	 * have to explain to us how your tablet thinks it's 0x0, and yet that's
-	 * not an error :-)
-	 */
-
-	for (i = 0; i < ARRAY_SIZE(speeds); ++i) {
-		aiptek->curSetting.programmableDelay = speeds[i];
-		(void)aiptek_program_tablet(aiptek);
-		if (aiptek->inputdev->absmax[ABS_X] > 0) {
-			info("input: Aiptek using %d ms programming speed\n",
-			     aiptek->curSetting.programmableDelay);
-			break;
-		}
-	}
-
-	/* Register the tablet as an Input Device
-	 */
-	input_register_device(aiptek->inputdev);
-
-	/* We now will look for the evdev device which is mapped to
-	 * the tablet. The partial name is kept in the link list of
-	 * input_handles associated with this input device.
-	 * What identifies an evdev input_handler is that it begins
-	 * with 'event', continues with a digit, and that in turn
-	 * is mapped to input/eventN.
-	 */
-	list_for_each_safe(node, next, &inputdev->h_list) {
-		inputhandle = to_handle(node);
-		if (strncmp(inputhandle->name, "event", 5) == 0) {
-			strcpy(aiptek->features.inputPath, inputhandle->name);
-			break;
-		}
-	}
-
-	/* Associate this driver's struct with the usb interface.
-	 */
-	usb_set_intfdata(intf, aiptek);
-
-	/* Set up the sysfs files
-	 */
-	aiptek_add_files(&intf->dev);
-
-	/* Make sure the evdev module is loaded. Assuming evdev IS a module :-)
-	 */
-	if (request_module("evdev") != 0)
-		info("aiptek: error loading 'evdev' module");
-
-	return 0;
-
-fail2:	usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
-			aiptek->data_dma);
-fail1:	input_free_device(inputdev);
-	kfree(aiptek);
-	return -ENOMEM;
-}
-
-/* Forward declaration */
-static void aiptek_disconnect(struct usb_interface *intf);
-
-static struct usb_driver aiptek_driver = {
-	.name = "aiptek",
-	.probe = aiptek_probe,
-	.disconnect = aiptek_disconnect,
-	.id_table = aiptek_ids,
-};
-
-/***********************************************************************
- * Deal with tablet disconnecting from the system.
- */
-static void aiptek_disconnect(struct usb_interface *intf)
-{
-	struct aiptek *aiptek = usb_get_intfdata(intf);
-
-	/* Disassociate driver's struct with usb interface
-	 */
-	usb_set_intfdata(intf, NULL);
-	if (aiptek != NULL) {
-		/* Free & unhook everything from the system.
-		 */
-		usb_kill_urb(aiptek->urb);
-		input_unregister_device(aiptek->inputdev);
-		aiptek_delete_files(&intf->dev);
-		usb_free_urb(aiptek->urb);
-		usb_buffer_free(interface_to_usbdev(intf),
-				AIPTEK_PACKET_LENGTH,
-				aiptek->data, aiptek->data_dma);
-		kfree(aiptek);
-	}
-}
-
-static int __init aiptek_init(void)
-{
-	int result = usb_register(&aiptek_driver);
-	if (result == 0) {
-		info(DRIVER_VERSION ": " DRIVER_AUTHOR);
-		info(DRIVER_DESC);
-	}
-	return result;
-}
-
-static void __exit aiptek_exit(void)
-{
-	usb_deregister(&aiptek_driver);
-}
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-module_param(programmableDelay, int, 0);
-MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");
-module_param(jitterDelay, int, 0);
-MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");
-
-module_init(aiptek_init);
-module_exit(aiptek_exit);
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
deleted file mode 100644
index c77291d..0000000
--- a/drivers/usb/input/appletouch.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver
- *
- * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2005      Johannes Berg (johannes@sipsolutions.net)
- * Copyright (C) 2005      Stelian Pop (stelian@popies.net)
- * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)
- * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)
- * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch)
- * Copyright (C) 2006      Nicolas Boichat (nicolas@boichat.ch)
- *
- * Thanks to Alex Harper <basilisk@foobox.net> for his inputs.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb/input.h>
-
-/* Apple has powerbooks which have the keyboard with different Product IDs */
-#define APPLE_VENDOR_ID		0x05AC
-
-/* These names come from Info.plist in AppleUSBTrackpad.kext */
-#define FOUNTAIN_ANSI_PRODUCT_ID	0x020E
-#define FOUNTAIN_ISO_PRODUCT_ID		0x020F
-
-#define FOUNTAIN_TP_ONLY_PRODUCT_ID	0x030A
-
-#define GEYSER1_TP_ONLY_PRODUCT_ID	0x030B
-
-#define GEYSER_ANSI_PRODUCT_ID		0x0214
-#define GEYSER_ISO_PRODUCT_ID		0x0215
-#define GEYSER_JIS_PRODUCT_ID		0x0216
-
-/* MacBook devices */
-#define GEYSER3_ANSI_PRODUCT_ID		0x0217
-#define GEYSER3_ISO_PRODUCT_ID		0x0218
-#define GEYSER3_JIS_PRODUCT_ID		0x0219
-
-/*
- * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext
- * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables
- */
-#define GEYSER4_ANSI_PRODUCT_ID	0x021A
-#define GEYSER4_ISO_PRODUCT_ID	0x021B
-#define GEYSER4_JIS_PRODUCT_ID	0x021C
-
-#define ATP_DEVICE(prod)					\
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |		\
-		       USB_DEVICE_ID_MATCH_INT_CLASS |		\
-		       USB_DEVICE_ID_MATCH_INT_PROTOCOL,	\
-	.idVendor = APPLE_VENDOR_ID,				\
-	.idProduct = (prod),					\
-	.bInterfaceClass = 0x03,				\
-	.bInterfaceProtocol = 0x02
-
-/* table of devices that work with this driver */
-static struct usb_device_id atp_table [] = {
-	{ ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) },
-	{ ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) },
-	{ ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) },
-
-	/* PowerBooks Oct 2005 */
-	{ ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) },
-
-	/* Core Duo MacBook & MacBook Pro */
-	{ ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) },
-
-	/* Core2 Duo MacBook & MacBook Pro */
-	{ ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) },
-	{ ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) },
-
-	/* Terminating entry */
-	{ }
-};
-MODULE_DEVICE_TABLE (usb, atp_table);
-
-/*
- * number of sensors. Note that only 16 instead of 26 X (horizontal)
- * sensors exist on 12" and 15" PowerBooks. All models have 16 Y
- * (vertical) sensors.
- */
-#define ATP_XSENSORS	26
-#define ATP_YSENSORS	16
-
-/* amount of fuzz this touchpad generates */
-#define ATP_FUZZ	16
-
-/* maximum pressure this driver will report */
-#define ATP_PRESSURE	300
-/*
- * multiplication factor for the X and Y coordinates.
- * We try to keep the touchpad aspect ratio while still doing only simple
- * arithmetics.
- * The factors below give coordinates like:
- *	0 <= x <  960 on 12" and 15" Powerbooks
- *	0 <= x < 1600 on 17" Powerbooks
- *	0 <= y <  646
- */
-#define ATP_XFACT	64
-#define ATP_YFACT	43
-
-/*
- * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is
- * ignored.
- */
-#define ATP_THRESHOLD	 5
-
-/* MacBook Pro (Geyser 3 & 4) initialization constants */
-#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
-#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
-#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
-#define ATP_GEYSER3_MODE_REQUEST_INDEX 0
-#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04
-
-/* Structure to hold all of our device specific stuff */
-struct atp {
-	char			phys[64];
-	struct usb_device *	udev;		/* usb device */
-	struct urb *		urb;		/* usb request block */
-	signed char *		data;		/* transferred data */
-	int			open;		/* non-zero if opened */
-	struct input_dev	*input;		/* input dev */
-	int			valid;		/* are the sensors valid ? */
-	int			x_old;		/* last reported x/y, */
-	int			y_old;		/* used for smoothing */
-						/* current value of the sensors */
-	signed char		xy_cur[ATP_XSENSORS + ATP_YSENSORS];
-						/* last value of the sensors */
-	signed char		xy_old[ATP_XSENSORS + ATP_YSENSORS];
-						/* accumulated sensors */
-	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS];
-	int			overflowwarn;	/* overflow warning printed? */
-	int			datalen;	/* size of an USB urb transfer */
-};
-
-#define dbg_dump(msg, tab) \
-	if (debug > 1) {						\
-		int i;							\
-		printk("appletouch: %s %lld", msg, (long long)jiffies); \
-		for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++)	\
-			printk(" %02x", tab[i]);			\
-		printk("\n");						\
-	}
-
-#define dprintk(format, a...)						\
-	do {								\
-		if (debug) printk(format, ##a);				\
-	} while (0)
-
-MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann");
-MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Make the threshold a module parameter
- */
-static int threshold = ATP_THRESHOLD;
-module_param(threshold, int, 0644);
-MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value");
-
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activate debugging output");
-
-/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
-static inline int atp_is_geyser_2(struct atp *dev)
-{
-	u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
-
-	return (productId == GEYSER_ANSI_PRODUCT_ID) ||
-		(productId == GEYSER_ISO_PRODUCT_ID) ||
-		(productId == GEYSER_JIS_PRODUCT_ID);
-}
-
-static inline int atp_is_geyser_3(struct atp *dev)
-{
-	u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
-
-	return (productId == GEYSER3_ANSI_PRODUCT_ID) ||
-		(productId == GEYSER3_ISO_PRODUCT_ID) ||
-		(productId == GEYSER3_JIS_PRODUCT_ID) ||
-		(productId == GEYSER4_ANSI_PRODUCT_ID) ||
-		(productId == GEYSER4_ISO_PRODUCT_ID) ||
-		(productId == GEYSER4_JIS_PRODUCT_ID);
-}
-
-static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
-			     int *z, int *fingers)
-{
-	int i;
-	/* values to calculate mean */
-	int pcum = 0, psum = 0;
-	int is_increasing = 0;
-
-	*fingers = 0;
-
-	for (i = 0; i < nb_sensors; i++) {
-		if (xy_sensors[i] < threshold) {
-			if (is_increasing)
-				is_increasing = 0;
-
-			continue;
-		}
-
-		/*
-		 * Makes the finger detection more versatile.  For example,
-		 * two fingers with no gap will be detected.  Also, my
-		 * tests show it less likely to have intermittent loss
-		 * of multiple finger readings while moving around (scrolling).
-		 *
-		 * Changes the multiple finger detection to counting humps on
-		 * sensors (transitions from nonincreasing to increasing)
-		 * instead of counting transitions from low sensors (no
-		 * finger reading) to high sensors (finger above
-		 * sensor)
-		 *
-		 * - Jason Parekh <jasonparekh@gmail.com>
-		 */
-		if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
-			(*fingers)++;
-			is_increasing = 1;
-		} else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) {
-			is_increasing = 0;
-		}
-
-		/*
-		 * Subtracts threshold so a high sensor that just passes the threshold
-		 * won't skew the calculated absolute coordinate.  Fixes an issue
-		 * where slowly moving the mouse would occassionaly jump a number of
-		 * pixels (let me restate--slowly moving the mouse makes this issue
-		 * most apparent).
-		 */
-		pcum += (xy_sensors[i] - threshold) * i;
-		psum += (xy_sensors[i] - threshold);
-	}
-
-	if (psum > 0) {
-		*z = psum;
-		return pcum * fact / psum;
-	}
-
-	return 0;
-}
-
-static inline void atp_report_fingers(struct input_dev *input, int fingers)
-{
-	input_report_key(input, BTN_TOOL_FINGER, fingers == 1);
-	input_report_key(input, BTN_TOOL_DOUBLETAP, fingers == 2);
-	input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
-}
-
-static void atp_complete(struct urb* urb)
-{
-	int x, y, x_z, y_z, x_f, y_f;
-	int retval, i, j;
-	struct atp *dev = urb->context;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -EOVERFLOW:
-		if(!dev->overflowwarn) {
-			printk("appletouch: OVERFLOW with data "
-				"length %d, actual length is %d\n",
-				dev->datalen, dev->urb->actual_length);
-			dev->overflowwarn = 1;
-		}
-	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;
-	}
-
-	/* drop incomplete datasets */
-	if (dev->urb->actual_length != dev->datalen) {
-		dprintk("appletouch: incomplete data package"
-			" (first byte: %d, length: %d).\n",
-			dev->data[0], dev->urb->actual_length);
-		goto exit;
-	}
-
-	/* reorder the sensors values */
-	if (atp_is_geyser_3(dev)) {
-		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
-
-		/*
-		 * The values are laid out like this:
-		 * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
-		 * '-' is an unused value.
-		 */
-
-		/* read X values */
-		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
-			dev->xy_cur[i] = dev->data[j + 1];
-			dev->xy_cur[i + 1] = dev->data[j + 2];
-		}
-		/* read Y values */
-		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
-			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
-			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
-		}
-	} else if (atp_is_geyser_2(dev)) {
-		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
-
-		/*
-		 * The values are laid out like this:
-		 * Y1, Y2, -, Y3, Y4, -, ..., X1, X2, -, X3, X4, -, ...
-		 * '-' is an unused value.
-		 */
-
-		/* read X values */
-		for (i = 0, j = 19; i < 20; i += 2, j += 3) {
-			dev->xy_cur[i] = dev->data[j];
-			dev->xy_cur[i + 1] = dev->data[j + 1];
-		}
-
-		/* read Y values */
-		for (i = 0, j = 1; i < 9; i += 2, j += 3) {
-			dev->xy_cur[ATP_XSENSORS + i] = dev->data[j];
-			dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 1];
-		}
-	} else {
-		for (i = 0; i < 8; i++) {
-			/* X values */
-			dev->xy_cur[i     ] = dev->data[5 * i +  2];
-			dev->xy_cur[i +  8] = dev->data[5 * i +  4];
-			dev->xy_cur[i + 16] = dev->data[5 * i + 42];
-			if (i < 2)
-				dev->xy_cur[i + 24] = dev->data[5 * i + 44];
-
-			/* Y values */
-			dev->xy_cur[i + 26] = dev->data[5 * i +  1];
-			dev->xy_cur[i + 34] = dev->data[5 * i +  3];
-		}
-	}
-
-	dbg_dump("sample", dev->xy_cur);
-
-	if (!dev->valid) {
-		/* first sample */
-		dev->valid = 1;
-		dev->x_old = dev->y_old = -1;
-		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
-
-		if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
-			goto exit;
-
-		/* 17" Powerbooks have extra X sensors */
-		for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
-			if (!dev->xy_cur[i]) continue;
-
-			printk("appletouch: 17\" model detected.\n");
-			if(atp_is_geyser_2(dev))
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (20 - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-			else
-				input_set_abs_params(dev->input, ABS_X, 0,
-						     (ATP_XSENSORS - 1) *
-						     ATP_XFACT - 1,
-						     ATP_FUZZ, 0);
-
-			break;
-		}
-
-		goto exit;
-	}
-
-	for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
-		/* accumulate the change */
-		signed char change = dev->xy_old[i] - dev->xy_cur[i];
-		dev->xy_acc[i] -= change;
-
-		/* prevent down drifting */
-		if (dev->xy_acc[i] < 0)
-			dev->xy_acc[i] = 0;
-	}
-
-	memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
-
-	dbg_dump("accumulator", dev->xy_acc);
-
-	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
-			      ATP_XFACT, &x_z, &x_f);
-	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
-			      ATP_YFACT, &y_z, &y_f);
-
-	if (x && y) {
-		if (dev->x_old != -1) {
-			x = (dev->x_old * 3 + x) >> 2;
-			y = (dev->y_old * 3 + y) >> 2;
-			dev->x_old = x;
-			dev->y_old = y;
-
-			if (debug > 1)
-				printk("appletouch: X: %3d Y: %3d "
-				       "Xz: %3d Yz: %3d\n",
-				       x, y, x_z, y_z);
-
-			input_report_key(dev->input, BTN_TOUCH, 1);
-			input_report_abs(dev->input, ABS_X, x);
-			input_report_abs(dev->input, ABS_Y, y);
-			input_report_abs(dev->input, ABS_PRESSURE,
-					 min(ATP_PRESSURE, x_z + y_z));
-			atp_report_fingers(dev->input, max(x_f, y_f));
-		}
-		dev->x_old = x;
-		dev->y_old = y;
-	}
-	else if (!x && !y) {
-
-		dev->x_old = dev->y_old = -1;
-		input_report_key(dev->input, BTN_TOUCH, 0);
-		input_report_abs(dev->input, ABS_PRESSURE, 0);
-		atp_report_fingers(dev->input, 0);
-
-		/* reset the accumulator on release */
-		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
-	}
-
-	input_report_key(dev->input, BTN_LEFT,
-			 !!dev->data[dev->datalen - 1]);
-
-	input_sync(dev->input);
-
-exit:
-	retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
-	if (retval) {
-		err("%s - usb_submit_urb failed with result %d",
-		    __FUNCTION__, retval);
-	}
-}
-
-static int atp_open(struct input_dev *input)
-{
-	struct atp *dev = input->private;
-
-	if (usb_submit_urb(dev->urb, GFP_ATOMIC))
-		return -EIO;
-
-	dev->open = 1;
-	return 0;
-}
-
-static void atp_close(struct input_dev *input)
-{
-	struct atp *dev = input->private;
-
-	usb_kill_urb(dev->urb);
-	dev->open = 0;
-}
-
-static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
-{
-	struct atp *dev;
-	struct input_dev *input_dev;
-	struct usb_device *udev = interface_to_usbdev(iface);
-	struct usb_host_interface *iface_desc;
-	struct usb_endpoint_descriptor *endpoint;
-	int int_in_endpointAddr = 0;
-	int i, retval = -ENOMEM;
-
-
-	/* set up the endpoint information */
-	/* use only the first interrupt-in endpoint */
-	iface_desc = iface->cur_altsetting;
-	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
-		endpoint = &iface_desc->endpoint[i].desc;
-		if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
-			/* we found an interrupt in endpoint */
-			int_in_endpointAddr = endpoint->bEndpointAddress;
-			break;
-		}
-	}
-	if (!int_in_endpointAddr) {
-		err("Could not find int-in endpoint");
-		return -EIO;
-	}
-
-	/* allocate memory for our device state and initialize it */
-	dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!dev || !input_dev) {
-		err("Out of memory");
-		goto err_free_devs;
-	}
-
-	dev->udev = udev;
-	dev->input = input_dev;
-	dev->overflowwarn = 0;
-	if (atp_is_geyser_3(dev))
-		dev->datalen = 64;
-	else if (atp_is_geyser_2(dev))
-		dev->datalen = 64;
-	else
-		dev->datalen = 81;
-
-	if (atp_is_geyser_3(dev)) {
-		/*
-		 * By default Geyser 3 device sends standard USB HID mouse
-		 * packets (Report ID 2). This code changes device mode, so it
-		 * sends raw sensor reports (Report ID 5).
-		 */
-		char data[8];
-		int size;
-
-		size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_READ_REQUEST_ID,
-			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode read request from device"
-							" (Geyser 3 mode)");
-			goto err_free_devs;
-		}
-
-		/* Apply the mode switch */
-		data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
-		size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
-			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode write request to device"
-							" (Geyser 3 mode)");
-			goto err_free_devs;
-		}
-		printk("appletouch Geyser 3 inited.\n");
-	}
-
-	dev->urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!dev->urb) {
-		retval = -ENOMEM;
-		goto err_free_devs;
-	}
-
-	dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
-				     &dev->urb->transfer_dma);
-	if (!dev->data) {
-		retval = -ENOMEM;
-		goto err_free_urb;
-	}
-
-	usb_fill_int_urb(dev->urb, udev,
-			 usb_rcvintpipe(udev, int_in_endpointAddr),
-			 dev->data, dev->datalen, atp_complete, dev, 1);
-
-	usb_make_path(udev, dev->phys, sizeof(dev->phys));
-	strlcat(dev->phys, "/input0", sizeof(dev->phys));
-
-	input_dev->name = "appletouch";
-	input_dev->phys = dev->phys;
-	usb_to_input_id(dev->udev, &input_dev->id);
-	input_dev->cdev.dev = &iface->dev;
-
-	input_dev->private = dev;
-	input_dev->open = atp_open;
-	input_dev->close = atp_close;
-
-	set_bit(EV_ABS, input_dev->evbit);
-
-	if (atp_is_geyser_3(dev)) {
-		/*
-		 * MacBook have 20 X sensors, 10 Y sensors
-		 */
-		input_set_abs_params(input_dev, ABS_X, 0,
-				     ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
-		input_set_abs_params(input_dev, ABS_Y, 0,
-				     ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
-	} else if (atp_is_geyser_2(dev)) {
-		/*
-		 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected
-		 * later.
-		 */
-		input_set_abs_params(input_dev, ABS_X, 0,
-				     ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0);
-		input_set_abs_params(input_dev, ABS_Y, 0,
-				     ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0);
-	} else {
-		/*
-		 * 12" and 15" Powerbooks only have 16 x sensors,
-		 * 17" models are detected later.
-		 */
-		input_set_abs_params(input_dev, ABS_X, 0,
-				     (16 - 1) * ATP_XFACT - 1, ATP_FUZZ, 0);
-		input_set_abs_params(input_dev, ABS_Y, 0,
-				     (ATP_YSENSORS - 1) * ATP_YFACT - 1, ATP_FUZZ, 0);
-	}
-	input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);
-
-	set_bit(EV_KEY, input_dev->evbit);
-	set_bit(BTN_TOUCH, input_dev->keybit);
-	set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-	set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-	set_bit(BTN_LEFT, input_dev->keybit);
-
-	input_register_device(dev->input);
-
-	/* save our data pointer in this interface device */
-	usb_set_intfdata(iface, dev);
-
-	return 0;
-
- err_free_urb:
-	usb_free_urb(dev->urb);
- err_free_devs:
-	usb_set_intfdata(iface, NULL);
-	kfree(dev);
-	input_free_device(input_dev);
-	return retval;
-}
-
-static void atp_disconnect(struct usb_interface *iface)
-{
-	struct atp *dev = usb_get_intfdata(iface);
-
-	usb_set_intfdata(iface, NULL);
-	if (dev) {
-		usb_kill_urb(dev->urb);
-		input_unregister_device(dev->input);
-		usb_buffer_free(dev->udev, dev->datalen,
-				dev->data, dev->urb->transfer_dma);
-		usb_free_urb(dev->urb);
-		kfree(dev);
-	}
-	printk(KERN_INFO "input: appletouch disconnected\n");
-}
-
-static int atp_suspend(struct usb_interface *iface, pm_message_t message)
-{
-	struct atp *dev = usb_get_intfdata(iface);
-	usb_kill_urb(dev->urb);
-	dev->valid = 0;
-	return 0;
-}
-
-static int atp_resume(struct usb_interface *iface)
-{
-	struct atp *dev = usb_get_intfdata(iface);
-	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
-		return -EIO;
-
-	return 0;
-}
-
-static struct usb_driver atp_driver = {
-	.name		= "appletouch",
-	.probe		= atp_probe,
-	.disconnect	= atp_disconnect,
-	.suspend	= atp_suspend,
-	.resume		= atp_resume,
-	.id_table	= atp_table,
-};
-
-static int __init atp_init(void)
-{
-	return usb_register(&atp_driver);
-}
-
-static void __exit atp_exit(void)
-{
-	usb_deregister(&atp_driver);
-}
-
-module_init(atp_init);
-module_exit(atp_exit);
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
deleted file mode 100644
index b724e36..0000000
--- a/drivers/usb/input/ati_remote.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- *  USB ATI Remote support
- *
- *  Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
- *  Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
- *
- *  This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- *  porting to the 2.6 kernel interfaces, along with other modification
- *  to better match the style of the existing usb/input drivers.  However, the
- *  protocol and hardware handling is essentially unchanged from 2.1.1.
- *
- *  The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
- *  Vojtech Pavlik.
- *
- *  Changes:
- *
- *  Feb 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.0
- *  Jun 2004: Torrey Hoffman <thoffman@arnor.net>
- *            Version 2.2.1
- *            Added key repeat support contributed by:
- *                Vincent Vanackere <vanackere@lif.univ-mrs.fr>
- *            Added support for the "Lola" remote contributed by:
- *                Seth Cohn <sethcohn@yahoo.com>
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Hardware & software notes
- *
- * These remote controls are distributed by ATI as part of their
- * "All-In-Wonder" video card packages.  The receiver self-identifies as a
- * "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
- *
- * The "Lola" remote is available from X10.  See:
- *    http://www.x10.com/products/lola_sg1.htm
- * The Lola is similar to the ATI remote but has no mouse support, and slightly
- * different keys.
- *
- * It is possible to use multiple receivers and remotes on multiple computers
- * simultaneously by configuring them to use specific channels.
- *
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
- * Actually, it may even support more, at least in some revisions of the
- * hardware.
- *
- * Each remote can be configured to transmit on one channel as follows:
- *   - Press and hold the "hand icon" button.
- *   - When the red LED starts to blink, let go of the "hand icon" button.
- *   - When it stops blinking, input the channel code as two digits, from 01
- *     to 16, and press the hand icon again.
- *
- * The timing can be a little tricky.  Try loading the module with debug=1
- * to have the kernel print out messages about the remote control number
- * and mask.  Note: debugging prints remote numbers as zero-based hexadecimal.
- *
- * The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module.  To mask out channels, just add
- * all the 2^channel_number values together.
- *
- * For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but
- * accept all other channels.
- *
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
- * ignored.
- *
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
- * parameter are unused.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/usb/input.h>
-#include <linux/wait.h>
-#include <linux/jiffies.h>
-
-/*
- * Module and Version Information, Module Parameters
- */
-
-#define ATI_REMOTE_VENDOR_ID	0x0bc7
-#define ATI_REMOTE_PRODUCT_ID	0x004
-#define LOLA_REMOTE_PRODUCT_ID	0x002
-#define MEDION_REMOTE_PRODUCT_ID 0x006
-
-#define DRIVER_VERSION	        "2.2.1"
-#define DRIVER_AUTHOR           "Torrey Hoffman <thoffman@arnor.net>"
-#define DRIVER_DESC             "ATI/X10 RF USB Remote Control"
-
-#define NAME_BUFSIZE      80    /* size of product name, path buffers */
-#define DATA_BUFSIZE      63    /* size of URB data buffers */
-
-/*
- * Duplicate event filtering time.
- * Sequential, identical KIND_FILTERED inputs with less than
- * FILTER_TIME milliseconds between them are considered as repeat
- * events. The hardware generates 5 events for the first keypress
- * and we have to take this into account for an accurate repeat
- * behaviour.
- */
-#define FILTER_TIME	60 /* msec */
-
-static unsigned long channel_mask;
-module_param(channel_mask, ulong, 0644);
-MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
-
-static int repeat_filter = FILTER_TIME;
-module_param(repeat_filter, int, 0644);
-MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
-
-#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-#undef err
-#define err(format, arg...) printk(KERN_ERR format , ## arg)
-
-static struct usb_device_id ati_remote_table[] = {
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
-	{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
-	{}	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ati_remote_table);
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a)	((unsigned char)((a) >> 8))
-#define LO(a)	((unsigned char)((a) & 0xff))
-
-#define SEND_FLAG_IN_PROGRESS	1
-#define SEND_FLAG_COMPLETE	2
-
-/* Device initialization strings */
-static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
-static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-
-struct ati_remote {
-	struct input_dev *idev;
-	struct usb_device *udev;
-	struct usb_interface *interface;
-
-	struct urb *irq_urb;
-	struct urb *out_urb;
-	struct usb_endpoint_descriptor *endpoint_in;
-	struct usb_endpoint_descriptor *endpoint_out;
-	unsigned char *inbuf;
-	unsigned char *outbuf;
-	dma_addr_t inbuf_dma;
-	dma_addr_t outbuf_dma;
-
-	unsigned char old_data[2];  /* Detect duplicate events */
-	unsigned long old_jiffies;
-	unsigned long acc_jiffies;  /* handle acceleration */
-	unsigned int repeat_count;
-
-	char name[NAME_BUFSIZE];
-	char phys[NAME_BUFSIZE];
-
-	wait_queue_head_t wait;
-	int send_flags;
-};
-
-/* "Kinds" of messages sent from the hardware to the driver. */
-#define KIND_END        0
-#define KIND_LITERAL    1   /* Simply pass to input system */
-#define KIND_FILTERED   2   /* Add artificial key-up events, drop keyrepeats */
-#define KIND_LU         3   /* Directional keypad diagonals - left up, */
-#define KIND_RU         4   /*   right up,  */
-#define KIND_LD         5   /*   left down, */
-#define KIND_RD         6   /*   right down */
-#define KIND_ACCEL      7   /* Directional keypad - left, right, up, down.*/
-
-/* Translation table from hardware messages to input events. */
-static const struct {
-	short kind;
-	unsigned char data1, data2;
-	int type;
-	unsigned int code;
-	int value;
-}  ati_remote_tbl[] = {
-	/* Directional control pad axes */
-	{KIND_ACCEL,   0x35, 0x70, EV_REL, REL_X, -1},	 /* left */
-	{KIND_ACCEL,   0x36, 0x71, EV_REL, REL_X, 1},    /* right */
-	{KIND_ACCEL,   0x37, 0x72, EV_REL, REL_Y, -1},	 /* up */
-	{KIND_ACCEL,   0x38, 0x73, EV_REL, REL_Y, 1},    /* down */
-	/* Directional control pad diagonals */
-	{KIND_LU,      0x39, 0x74, EV_REL, 0, 0},        /* left up */
-	{KIND_RU,      0x3a, 0x75, EV_REL, 0, 0},        /* right up */
-	{KIND_LD,      0x3c, 0x77, EV_REL, 0, 0},        /* left down */
-	{KIND_RD,      0x3b, 0x76, EV_REL, 0, 0},        /* right down */
-
-	/* "Mouse button" buttons */
-	{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
-	{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
-	{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
-	{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
-
-	/* Artificial "doubleclick" events are generated by the hardware.
-	 * They are mapped to the "side" and "extra" mouse buttons here. */
-	{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
-	{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
-
-	/* keyboard. */
-	{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
-	{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
-	{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
-	{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
-	{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
-	{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
-	{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
-	{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
-	{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
-	{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
-	{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
-	{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_B, 1},
-	{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_C, 1},
-	{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
-	{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
-	{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
-
-	/* "special" keys */
-	{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
-	{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_MENU, 1},       /* "menu" */
-	{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_POWER, 1},      /* Power */
-	{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_TV, 1},         /* TV */
-	{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_DVD, 1},        /* DVD */
-	{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1},        /* WEB */
-	{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1},  /* "book" */
-	{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_EDIT, 1},       /* "hand" */
-	{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_COFFEE, 1},     /* "timer" */
-	{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_FRONT, 1},      /* "max" */
-	{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1},       /* left */
-	{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1},      /* right */
-	{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1},       /* down */
-	{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1},         /* up */
-	{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_OK, 1},         /* "OK" */
-	{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_VOLUMEDOWN, 1}, /* VOL + */
-	{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_VOLUMEUP, 1},   /* VOL - */
-	{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_MUTE, 1},       /* MUTE  */
-	{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_CHANNELUP, 1},  /* CH + */
-	{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_CHANNELDOWN, 1},/* CH - */
-	{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_RECORD, 1},     /* ( o) red */
-	{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1},       /* ( >) */
-	{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1},     /* (<<) */
-	{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1},    /* (>>) */
-	{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1},       /* ([]) */
-	{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1},      /* ('') */
-	{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1},   /* (<-) */
-	{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1},       /* (>+) */
-	{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1},       /* PLAYING */
-	{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1},       /* TOP */
-	{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
-	{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */
-
-	{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
-};
-
-/* Local function prototypes */
-static void ati_remote_dump		(unsigned char *data, unsigned int actual_length);
-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);
-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);
-
-/* usb specific object to register with the usb subsystem */
-static struct usb_driver ati_remote_driver = {
-	.name         = "ati_remote",
-	.probe        = ati_remote_probe,
-	.disconnect   = ati_remote_disconnect,
-	.id_table     = ati_remote_table,
-};
-
-/*
- *	ati_remote_dump_input
- */
-static void ati_remote_dump(unsigned char *data, unsigned int len)
-{
-	if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
-		warn("Weird byte 0x%02x", data[0]);
-	else if (len == 4)
-		warn("Weird key %02x %02x %02x %02x",
-		     data[0], data[1], data[2], data[3]);
-	else
-		warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
-		     len, data[0], data[1], data[2], data[3], data[4], data[5]);
-}
-
-/*
- *	ati_remote_open
- */
-static int ati_remote_open(struct input_dev *inputdev)
-{
-	struct ati_remote *ati_remote = inputdev->private;
-
-	/* On first open, submit the read urb which was set up previously. */
-	ati_remote->irq_urb->dev = ati_remote->udev;
-	if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
-		dev_err(&ati_remote->interface->dev,
-			"%s: usb_submit_urb failed!\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*
- *	ati_remote_close
- */
-static void ati_remote_close(struct input_dev *inputdev)
-{
-	struct ati_remote *ati_remote = inputdev->private;
-
-	usb_kill_urb(ati_remote->irq_urb);
-}
-
-/*
- *		ati_remote_irq_out
- */
-static void ati_remote_irq_out(struct urb *urb)
-{
-	struct ati_remote *ati_remote = urb->context;
-
-	if (urb->status) {
-		dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
-			__FUNCTION__, urb->status);
-		return;
-	}
-
-	ati_remote->send_flags |= SEND_FLAG_COMPLETE;
-	wmb();
-	wake_up(&ati_remote->wait);
-}
-
-/*
- *	ati_remote_sendpacket
- *
- *	Used to send device initialization strings
- */
-static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
-{
-	int retval = 0;
-
-	/* Set up out_urb */
-	memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
-	((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
-
-	ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
-	ati_remote->out_urb->dev = ati_remote->udev;
-	ati_remote->send_flags = SEND_FLAG_IN_PROGRESS;
-
-	retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
-	if (retval) {
-		dev_dbg(&ati_remote->interface->dev,
-			 "sendpacket: usb_submit_urb failed: %d\n", retval);
-		return retval;
-	}
-
-	wait_event_timeout(ati_remote->wait,
-		((ati_remote->out_urb->status != -EINPROGRESS) ||
-			(ati_remote->send_flags & SEND_FLAG_COMPLETE)),
-		HZ);
-	usb_kill_urb(ati_remote->out_urb);
-
-	return retval;
-}
-
-/*
- *	ati_remote_event_lookup
- */
-static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
-{
-	int i;
-
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
-		/*
-		 * Decide if the table entry matches the remote input.
-		 */
-		if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-		    ((((ati_remote_tbl[i].data1 >> 4) -
-		       (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-		    (ati_remote_tbl[i].data2 == d2))
-			return i;
-
-	}
-	return -1;
-}
-
-/*
- *	ati_remote_compute_accel
- *
- * Implements acceleration curve for directional control pad
- * If elapsed time since last event is > 1/4 second, user "stopped",
- * so reset acceleration. Otherwise, user is probably holding the control
- * pad down, so we increase acceleration, ramping up over two seconds to
- * a maximum speed.
- */
-static int ati_remote_compute_accel(struct ati_remote *ati_remote)
-{
-	static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-	unsigned long now = jiffies;
-	int acc;
-
-	if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
-		acc = 1;
-		ati_remote->acc_jiffies = now;
-	}
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
-		acc = accel[0];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
-		acc = accel[1];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
-		acc = accel[2];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
-		acc = accel[3];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
-		acc = accel[4];
-	else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
-		acc = accel[5];
-	else
-		acc = accel[6];
-
-	return acc;
-}
-
-/*
- *	ati_remote_report_input
- */
-static void ati_remote_input_report(struct urb *urb)
-{
-	struct ati_remote *ati_remote = urb->context;
-	unsigned char *data= ati_remote->inbuf;
-	struct input_dev *dev = ati_remote->idev;
-	int index, acc;
-	int remote_num;
-
-	/* Deal with strange looking inputs */
-	if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
-		((data[3] & 0x0f) != 0x00) ) {
-		ati_remote_dump(data, urb->actual_length);
-		return;
-	}
-
-	/* Mask unwanted remote channels.  */
-	/* note: remote_num is 0-based, channel 1 on remote == 0 here */
-	remote_num = (data[3] >> 4) & 0x0f;
-        if (channel_mask & (1 << (remote_num + 1))) {
-		dbginfo(&ati_remote->interface->dev,
-			"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
-			remote_num, data[1], data[2], channel_mask);
-		return;
-	}
-
-	/* Look up event code index in translation table */
-	index = ati_remote_event_lookup(remote_num, data[1], data[2]);
-	if (index < 0) {
-		dev_warn(&ati_remote->interface->dev,
-			 "Unknown input from channel 0x%02x: data %02x,%02x\n",
-			 remote_num, data[1], data[2]);
-		return;
-	}
-	dbginfo(&ati_remote->interface->dev,
-		"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
-		remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-
-	if (ati_remote_tbl[index].kind == KIND_LITERAL) {
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code,
-			ati_remote_tbl[index].value);
-		input_sync(dev);
-
-		ati_remote->old_jiffies = jiffies;
-		return;
-	}
-
-	if (ati_remote_tbl[index].kind == KIND_FILTERED) {
-		/* Filter duplicate events which happen "too close" together. */
-		if (ati_remote->old_data[0] == data[1] &&
-		    ati_remote->old_data[1] == data[2] &&
-		    time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
-			ati_remote->repeat_count++;
-		} else {
-			ati_remote->repeat_count = 0;
-		}
-
-		ati_remote->old_data[0] = data[1];
-		ati_remote->old_data[1] = data[2];
-		ati_remote->old_jiffies = jiffies;
-
-		if (ati_remote->repeat_count > 0 &&
-		    ati_remote->repeat_count < 5)
-			return;
-
-
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 1);
-		input_sync(dev);
-		input_event(dev, ati_remote_tbl[index].type,
-			ati_remote_tbl[index].code, 0);
-		input_sync(dev);
-
-	} else {
-
-		/*
-		 * Other event kinds are from the directional control pad, and have an
-		 * acceleration factor applied to them.  Without this acceleration, the
-		 * control pad is mostly unusable.
-		 */
-		acc = ati_remote_compute_accel(ati_remote);
-
-		switch (ati_remote_tbl[index].kind) {
-		case KIND_ACCEL:
-			input_event(dev, ati_remote_tbl[index].type,
-				ati_remote_tbl[index].code,
-				ati_remote_tbl[index].value * acc);
-			break;
-		case KIND_LU:
-			input_report_rel(dev, REL_X, -acc);
-			input_report_rel(dev, REL_Y, -acc);
-			break;
-		case KIND_RU:
-			input_report_rel(dev, REL_X, acc);
-			input_report_rel(dev, REL_Y, -acc);
-			break;
-		case KIND_LD:
-			input_report_rel(dev, REL_X, -acc);
-			input_report_rel(dev, REL_Y, acc);
-			break;
-		case KIND_RD:
-			input_report_rel(dev, REL_X, acc);
-			input_report_rel(dev, REL_Y, acc);
-			break;
-		default:
-			dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
-				ati_remote_tbl[index].kind);
-		}
-		input_sync(dev);
-
-		ati_remote->old_jiffies = jiffies;
-		ati_remote->old_data[0] = data[1];
-		ati_remote->old_data[1] = data[2];
-	}
-}
-
-/*
- *	ati_remote_irq_in
- */
-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);
-		break;
-	case -ECONNRESET:	/* unlink */
-	case -ENOENT:
-	case -ESHUTDOWN:
-		dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
-			__FUNCTION__);
-		return;
-	default:		/* error */
-		dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
-			__FUNCTION__, urb->status);
-	}
-
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
-			__FUNCTION__, retval);
-}
-
-/*
- *	ati_remote_alloc_buffers
- */
-static int ati_remote_alloc_buffers(struct usb_device *udev,
-				    struct ati_remote *ati_remote)
-{
-	ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					     &ati_remote->inbuf_dma);
-	if (!ati_remote->inbuf)
-		return -1;
-
-	ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC,
-					      &ati_remote->outbuf_dma);
-	if (!ati_remote->outbuf)
-		return -1;
-
-	ati_remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ati_remote->irq_urb)
-		return -1;
-
-	ati_remote->out_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!ati_remote->out_urb)
-		return -1;
-
-	return 0;
-}
-
-/*
- *	ati_remote_free_buffers
- */
-static void ati_remote_free_buffers(struct ati_remote *ati_remote)
-{
-	usb_free_urb(ati_remote->irq_urb);
-	usb_free_urb(ati_remote->out_urb);
-
-	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
-		ati_remote->inbuf, ati_remote->inbuf_dma);
-
-	usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
-		ati_remote->outbuf, ati_remote->outbuf_dma);
-}
-
-static void ati_remote_input_init(struct ati_remote *ati_remote)
-{
-	struct input_dev *idev = ati_remote->idev;
-	int i;
-
-	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-	idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
-					  BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
-	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
-		if (ati_remote_tbl[i].type == EV_KEY)
-			set_bit(ati_remote_tbl[i].code, idev->keybit);
-
-	idev->private = ati_remote;
-	idev->open = ati_remote_open;
-	idev->close = ati_remote_close;
-
-	idev->name = ati_remote->name;
-	idev->phys = ati_remote->phys;
-
-	usb_to_input_id(ati_remote->udev, &idev->id);
-	idev->cdev.dev = &ati_remote->udev->dev;
-}
-
-static int ati_remote_initialize(struct ati_remote *ati_remote)
-{
-	struct usb_device *udev = ati_remote->udev;
-	int pipe, maxp;
-
-	init_waitqueue_head(&ati_remote->wait);
-
-	/* Set up irq_urb */
-	pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-	usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
-			 maxp, ati_remote_irq_in, ati_remote,
-			 ati_remote->endpoint_in->bInterval);
-	ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
-	ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* Set up out_urb */
-	pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-	maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
-	usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
-			 maxp, ati_remote_irq_out, ati_remote,
-			 ati_remote->endpoint_out->bInterval);
-	ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
-	ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* send initialization strings */
-	if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
-	    (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
-		dev_err(&ati_remote->interface->dev,
-			 "Initializing ati_remote hardware failed.\n");
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/*
- *	ati_remote_probe
- */
-static int ati_remote_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(interface);
-	struct usb_host_interface *iface_host = interface->cur_altsetting;
-	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
-	struct ati_remote *ati_remote;
-	struct input_dev *input_dev;
-	int err = -ENOMEM;
-
-	if (iface_host->desc.bNumEndpoints != 2) {
-		err("%s: Unexpected desc.bNumEndpoints\n", __FUNCTION__);
-		return -ENODEV;
-	}
-
-	endpoint_in = &iface_host->endpoint[0].desc;
-	endpoint_out = &iface_host->endpoint[1].desc;
-
-	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) {
-		err("%s: endpoint_in message size==0? \n", __FUNCTION__);
-		return -ENODEV;
-	}
-
-	ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!ati_remote || !input_dev)
-		goto fail1;
-
-	/* Allocate URB buffers, URBs */
-	if (ati_remote_alloc_buffers(udev, ati_remote))
-		goto fail2;
-
-	ati_remote->endpoint_in = endpoint_in;
-	ati_remote->endpoint_out = endpoint_out;
-	ati_remote->udev = udev;
-	ati_remote->idev = input_dev;
-	ati_remote->interface = interface;
-
-	usb_make_path(udev, ati_remote->phys, sizeof(ati_remote->phys));
-	strlcpy(ati_remote->phys, "/input0", sizeof(ati_remote->phys));
-
-	if (udev->manufacturer)
-		strlcpy(ati_remote->name, udev->manufacturer, sizeof(ati_remote->name));
-
-	if (udev->product)
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
-			 "%s %s", ati_remote->name, udev->product);
-
-	if (!strlen(ati_remote->name))
-		snprintf(ati_remote->name, sizeof(ati_remote->name),
-			DRIVER_DESC "(%04x,%04x)",
-			le16_to_cpu(ati_remote->udev->descriptor.idVendor),
-			le16_to_cpu(ati_remote->udev->descriptor.idProduct));
-
-	ati_remote_input_init(ati_remote);
-
-	/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
-	err = ati_remote_initialize(ati_remote);
-	if (err)
-		goto fail3;
-
-	/* Set up and register input device */
-	input_register_device(ati_remote->idev);
-
-	usb_set_intfdata(interface, ati_remote);
-	return 0;
-
-fail3:	usb_kill_urb(ati_remote->irq_urb);
-	usb_kill_urb(ati_remote->out_urb);
-fail2:	ati_remote_free_buffers(ati_remote);
-fail1:	input_free_device(input_dev);
-	kfree(ati_remote);
-	return err;
-}
-
-/*
- *	ati_remote_disconnect
- */
-static void ati_remote_disconnect(struct usb_interface *interface)
-{
-	struct ati_remote *ati_remote;
-
-	ati_remote = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-	if (!ati_remote) {
-		warn("%s - null device?\n", __FUNCTION__);
-		return;
-	}
-
-	usb_kill_urb(ati_remote->irq_urb);
-	usb_kill_urb(ati_remote->out_urb);
-	input_unregister_device(ati_remote->idev);
-	ati_remote_free_buffers(ati_remote);
-	kfree(ati_remote);
-}
-
-/*
- *	ati_remote_init
- */
-static int __init ati_remote_init(void)
-{
-	int result;
-
-	result = usb_register(&ati_remote_driver);
-	if (result)
-		err("usb_register error #%d\n", result);
-	else
-		info("Registered USB driver " DRIVER_DESC " v. " DRIVER_VERSION);
-
-	return result;
-}
-
-/*
- *	ati_remote_exit
- */
-static void __exit ati_remote_exit(void)
-{
-	usb_deregister(&ati_remote_driver);
-}
-
-/*
- *	module specification
- */
-
-module_init(ati_remote_init);
-module_exit(ati_remote_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c
deleted file mode 100644
index 83f1f79..0000000
--- a/drivers/usb/input/ati_remote2.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * ati_remote2 - ATI/Philips USB RF remote driver
- *
- * Copyright (C) 2005 Ville Syrjala <syrjala@sci.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 published by the Free Software Foundation.
- */
-
-#include <linux/usb/input.h>
-
-#define DRIVER_DESC    "ATI/Philips USB RF remote driver"
-#define DRIVER_VERSION "0.1"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
-MODULE_LICENSE("GPL");
-
-static unsigned int mode_mask = 0x1F;
-module_param(mode_mask, uint, 0644);
-MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
-
-static struct usb_device_id ati_remote2_id_table[] = {
-	{ USB_DEVICE(0x0471, 0x0602) },	/* ATI Remote Wonder II */
-	{ }
-};
-MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
-
-static struct {
-	int hw_code;
-	int key_code;
-} ati_remote2_key_table[] = {
-	{ 0x00, KEY_0 },
-	{ 0x01, KEY_1 },
-	{ 0x02, KEY_2 },
-	{ 0x03, KEY_3 },
-	{ 0x04, KEY_4 },
-	{ 0x05, KEY_5 },
-	{ 0x06, KEY_6 },
-	{ 0x07, KEY_7 },
-	{ 0x08, KEY_8 },
-	{ 0x09, KEY_9 },
-	{ 0x0c, KEY_POWER },
-	{ 0x0d, KEY_MUTE },
-	{ 0x10, KEY_VOLUMEUP },
-	{ 0x11, KEY_VOLUMEDOWN },
-	{ 0x20, KEY_CHANNELUP },
-	{ 0x21, KEY_CHANNELDOWN },
-	{ 0x28, KEY_FORWARD },
-	{ 0x29, KEY_REWIND },
-	{ 0x2c, KEY_PLAY },
-	{ 0x30, KEY_PAUSE },
-	{ 0x31, KEY_STOP },
-	{ 0x37, KEY_RECORD },
-	{ 0x38, KEY_DVD },
-	{ 0x39, KEY_TV },
-	{ 0x54, KEY_MENU },
-	{ 0x58, KEY_UP },
-	{ 0x59, KEY_DOWN },
-	{ 0x5a, KEY_LEFT },
-	{ 0x5b, KEY_RIGHT },
-	{ 0x5c, KEY_OK },
-	{ 0x78, KEY_A },
-	{ 0x79, KEY_B },
-	{ 0x7a, KEY_C },
-	{ 0x7b, KEY_D },
-	{ 0x7c, KEY_E },
-	{ 0x7d, KEY_F },
-	{ 0x82, KEY_ENTER },
-	{ 0x8e, KEY_VENDOR },
-	{ 0x96, KEY_COFFEE },
-	{ 0xa9, BTN_LEFT },
-	{ 0xaa, BTN_RIGHT },
-	{ 0xbe, KEY_QUESTION },
-	{ 0xd5, KEY_FRONT },
-	{ 0xd0, KEY_EDIT },
-	{ 0xf9, KEY_INFO },
-	{ (0x00 << 8) | 0x3f, KEY_PROG1 },
-	{ (0x01 << 8) | 0x3f, KEY_PROG2 },
-	{ (0x02 << 8) | 0x3f, KEY_PROG3 },
-	{ (0x03 << 8) | 0x3f, KEY_PROG4 },
-	{ (0x04 << 8) | 0x3f, KEY_PC },
-	{ 0, KEY_RESERVED }
-};
-
-struct ati_remote2 {
-	struct input_dev *idev;
-	struct usb_device *udev;
-
-	struct usb_interface *intf[2];
-	struct usb_endpoint_descriptor *ep[2];
-	struct urb *urb[2];
-	void *buf[2];
-	dma_addr_t buf_dma[2];
-
-	unsigned long jiffies;
-	int mode;
-
-	char name[64];
-	char phys[64];
-};
-
-static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
-static void ati_remote2_disconnect(struct usb_interface *interface);
-
-static struct usb_driver ati_remote2_driver = {
-	.name       = "ati_remote2",
-	.probe      = ati_remote2_probe,
-	.disconnect = ati_remote2_disconnect,
-	.id_table   = ati_remote2_id_table,
-};
-
-static int ati_remote2_open(struct input_dev *idev)
-{
-	struct ati_remote2 *ar2 = idev->private;
-	int r;
-
-	r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
-	if (r) {
-		dev_err(&ar2->intf[0]->dev,
-			"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
-		return r;
-	}
-	r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
-	if (r) {
-		usb_kill_urb(ar2->urb[0]);
-		dev_err(&ar2->intf[1]->dev,
-			"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
-		return r;
-	}
-
-	return 0;
-}
-
-static void ati_remote2_close(struct input_dev *idev)
-{
-	struct ati_remote2 *ar2 = idev->private;
-
-	usb_kill_urb(ar2->urb[0]);
-	usb_kill_urb(ar2->urb[1]);
-}
-
-static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
-{
-	struct input_dev *idev = ar2->idev;
-	u8 *data = ar2->buf[0];
-
-	if (data[0] > 4) {
-		dev_err(&ar2->intf[0]->dev,
-			"Unknown mode byte (%02x %02x %02x %02x)\n",
-			data[3], data[2], data[1], data[0]);
-		return;
-	}
-
-	if (!((1 << data[0]) & mode_mask))
-		return;
-
-	input_event(idev, EV_REL, REL_X, (s8) data[1]);
-	input_event(idev, EV_REL, REL_Y, (s8) data[2]);
-	input_sync(idev);
-}
-
-static int ati_remote2_lookup(unsigned int hw_code)
-{
-	int i;
-
-	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
-		if (ati_remote2_key_table[i].hw_code == hw_code)
-			return i;
-
-	return -1;
-}
-
-static void ati_remote2_input_key(struct ati_remote2 *ar2)
-{
-	struct input_dev *idev = ar2->idev;
-	u8 *data = ar2->buf[1];
-	int hw_code, index;
-
-	if (data[0] > 4) {
-		dev_err(&ar2->intf[1]->dev,
-			"Unknown mode byte (%02x %02x %02x %02x)\n",
-			data[3], data[2], data[1], data[0]);
-		return;
-	}
-
-	hw_code = data[2];
-	/*
-	 * Mode keys (AUX1-AUX4, PC) all generate the same code byte.
-	 * Use the mode byte to figure out which one was pressed.
-	 */
-	if (hw_code == 0x3f) {
-		/*
-		 * For some incomprehensible reason the mouse pad generates
-		 * events which look identical to the events from the last
-		 * pressed mode key. Naturally we don't want to generate key
-		 * events for the mouse pad so we filter out any subsequent
-		 * events from the same mode key.
-		 */
-		if (ar2->mode == data[0])
-			return;
-
-		if (data[1] == 0)
-			ar2->mode = data[0];
-
-		hw_code |= data[0] << 8;
-	}
-
-	if (!((1 << data[0]) & mode_mask))
-		return;
-
-	index = ati_remote2_lookup(hw_code);
-	if (index < 0) {
-		dev_err(&ar2->intf[1]->dev,
-			"Unknown code byte (%02x %02x %02x %02x)\n",
-			data[3], data[2], data[1], data[0]);
-		return;
-	}
-
-	switch (data[1]) {
-	case 0:	/* release */
-		break;
-	case 1:	/* press */
-		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
-		break;
-	case 2:	/* repeat */
-
-		/* No repeat for mouse buttons. */
-		if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
-		    ati_remote2_key_table[index].key_code == BTN_RIGHT)
-			return;
-
-		if (!time_after_eq(jiffies, ar2->jiffies))
-			return;
-
-		ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
-		break;
-	default:
-		dev_err(&ar2->intf[1]->dev,
-			"Unknown state byte (%02x %02x %02x %02x)\n",
-			data[3], data[2], data[1], data[0]);
-		return;
-	}
-
-	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 ati_remote2 *ar2 = urb->context;
-	int r;
-
-	switch (urb->status) {
-	case 0:
-		ati_remote2_input_mouse(ar2);
-		break;
-	case -ENOENT:
-	case -EILSEQ:
-	case -ECONNRESET:
-	case -ESHUTDOWN:
-		dev_dbg(&ar2->intf[0]->dev,
-			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
-		return;
-	default:
-		dev_err(&ar2->intf[0]->dev,
-			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
-	}
-
-	r = usb_submit_urb(urb, GFP_ATOMIC);
-	if (r)
-		dev_err(&ar2->intf[0]->dev,
-			"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
-}
-
-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);
-		break;
-	case -ENOENT:
-	case -EILSEQ:
-	case -ECONNRESET:
-	case -ESHUTDOWN:
-		dev_dbg(&ar2->intf[1]->dev,
-			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
-		return;
-	default:
-		dev_err(&ar2->intf[1]->dev,
-			"%s(): urb status = %d\n", __FUNCTION__, urb->status);
-	}
-
-	r = usb_submit_urb(urb, GFP_ATOMIC);
-	if (r)
-		dev_err(&ar2->intf[1]->dev,
-			"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
-}
-
-static int ati_remote2_input_init(struct ati_remote2 *ar2)
-{
-	struct input_dev *idev;
-	int i;
-
-	idev = input_allocate_device();
-	if (!idev)
-		return -ENOMEM;
-
-	ar2->idev = idev;
-	idev->private = ar2;
-
-	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
-	idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
-	idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
-		set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
-
-	idev->rep[REP_DELAY]  = 250;
-	idev->rep[REP_PERIOD] = 33;
-
-	idev->open = ati_remote2_open;
-	idev->close = ati_remote2_close;
-
-	idev->name = ar2->name;
-	idev->phys = ar2->phys;
-
-	usb_to_input_id(ar2->udev, &idev->id);
-	idev->cdev.dev = &ar2->udev->dev;
-
-	i = input_register_device(idev);
-	if (i)
-		input_free_device(idev);
-
-	return i;
-}
-
-static int ati_remote2_urb_init(struct ati_remote2 *ar2)
-{
-	struct usb_device *udev = ar2->udev;
-	int i, pipe, maxp;
-
-	for (i = 0; i < 2; i++) {
-		ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
-		if (!ar2->buf[i])
-			return -ENOMEM;
-
-		ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-		if (!ar2->urb[i])
-			return -ENOMEM;
-
-		pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
-		maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-		maxp = maxp > 4 ? 4 : maxp;
-
-		usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
-				 i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
-				 ar2, ar2->ep[i]->bInterval);
-		ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
-		ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	}
-
-	return 0;
-}
-
-static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
-{
-	int i;
-
-	for (i = 0; i < 2; i++) {
-		usb_free_urb(ar2->urb[i]);
-
-		if (ar2->buf[i])
-			usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
-	}
-}
-
-static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(interface);
-	struct usb_host_interface *alt = interface->cur_altsetting;
-	struct ati_remote2 *ar2;
-	int r;
-
-	if (alt->desc.bInterfaceNumber)
-		return -ENODEV;
-
-	ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
-	if (!ar2)
-		return -ENOMEM;
-
-	ar2->udev = udev;
-
-	ar2->intf[0] = interface;
-	ar2->ep[0] = &alt->endpoint[0].desc;
-
-	ar2->intf[1] = usb_ifnum_to_if(udev, 1);
-	r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
-	if (r)
-		goto fail1;
-	alt = ar2->intf[1]->cur_altsetting;
-	ar2->ep[1] = &alt->endpoint[0].desc;
-
-	r = ati_remote2_urb_init(ar2);
-	if (r)
-		goto fail2;
-
-	usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
-	strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
-
-	strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
-
-	r = ati_remote2_input_init(ar2);
-	if (r)
-		goto fail2;
-
-	usb_set_intfdata(interface, ar2);
-
-	return 0;
-
- fail2:
-	ati_remote2_urb_cleanup(ar2);
-
-	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
- fail1:
-	kfree(ar2);
-
-	return r;
-}
-
-static void ati_remote2_disconnect(struct usb_interface *interface)
-{
-	struct ati_remote2 *ar2;
-	struct usb_host_interface *alt = interface->cur_altsetting;
-
-	if (alt->desc.bInterfaceNumber)
-		return;
-
-	ar2 = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
-	input_unregister_device(ar2->idev);
-
-	ati_remote2_urb_cleanup(ar2);
-
-	usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
-
-	kfree(ar2);
-}
-
-static int __init ati_remote2_init(void)
-{
-	int r;
-
-	r = usb_register(&ati_remote2_driver);
-	if (r)
-		printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
-	else
-		printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
-
-	return r;
-}
-
-static void __exit ati_remote2_exit(void)
-{
-	usb_deregister(&ati_remote2_driver);
-}
-
-module_init(ati_remote2_init);
-module_exit(ati_remote2_exit);
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
deleted file mode 100644
index 203cdc1..0000000
--- a/drivers/usb/input/gtco.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*    -*- linux-c -*-
-
-GTCO digitizer USB driver
-
-Use the err(), dbg() and info() macros from usb.h for system logging
-
-TO CHECK:  Is pressure done right on report 5?
-
-Copyright (C) 2006  GTCO CalComp
-
-This program is free software; 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation, and that the name of GTCO-CalComp not be used in advertising
-or publicity pertaining to distribution of the software without specific,
-written prior permission. GTCO-CalComp makes no representations about the
-suitability of this software for any purpose.  It is provided "as is"
-without express or implied warranty.
-
-GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
-GTCO CalComp, Inc.
-7125 Riverwood Drive
-Columbia, MD 21046
-
-Jeremy Roberson jroberson@gtcocalcomp.com
-Scott Hill shill@gtcocalcomp.com
-*/
-
-
-
-/*#define DEBUG*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
-
-#include <linux/version.h>
-#include <linux/usb/input.h>
-
-/* Version with a Major number of 2 is for kernel inclusion only. */
-#define  GTCO_VERSION   "2.00.0006"
-
-
-/*   MACROS  */
-
-#define VENDOR_ID_GTCO	      0x078C
-#define PID_400               0x400
-#define PID_401               0x401
-#define PID_1000              0x1000
-#define PID_1001              0x1001
-#define PID_1002              0x1002
-
-/* Max size of a single report */
-#define REPORT_MAX_SIZE       10
-
-
-/* Bitmask whether pen is in range */
-#define MASK_INRANGE 0x20
-#define MASK_BUTTON  0x01F
-
-#define  PATHLENGTH     64
-
-/* DATA STRUCTURES */
-
-/* Device table */
-static struct usb_device_id gtco_usbid_table [] = {
-	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
-	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
-	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
-	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
-	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
-	{ }
-};
-MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
-
-
-/* Structure to hold all of our device specific stuff */
-struct gtco {
-
-	struct input_dev  *inputdevice; /* input device struct pointer  */
-	struct usb_device *usbdev; /* the usb device for this device */
-	struct urb        *urbinfo;	 /* urb for incoming reports      */
-	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
-	unsigned char *   buffer;   /* databuffer for reports */
-
-	char  usbpath[PATHLENGTH];
-	int   openCount;
-
-	/* Information pulled from Report Descriptor */
-	u32  usage;
-	u32  min_X;
-	u32  max_X;
-	u32  min_Y;
-	u32  max_Y;
-	s8   mintilt_X;
-	s8   maxtilt_X;
-	s8   mintilt_Y;
-	s8   maxtilt_Y;
-	u32  maxpressure;
-	u32  minpressure;
-};
-
-
-
-/*   Code for parsing the HID REPORT DESCRIPTOR          */
-
-/* From HID1.11 spec */
-struct hid_descriptor
-{
-	struct usb_descriptor_header header;
-	__le16   bcdHID;
-	u8       bCountryCode;
-	u8       bNumDescriptors;
-	u8       bDescriptorType;
-	__le16   wDescriptorLength;
-} __attribute__ ((packed));
-
-
-#define HID_DESCRIPTOR_SIZE   9
-#define HID_DEVICE_TYPE       33
-#define REPORT_DEVICE_TYPE    34
-
-
-#define PREF_TAG(x)     ((x)>>4)
-#define PREF_TYPE(x)    ((x>>2)&0x03)
-#define PREF_SIZE(x)    ((x)&0x03)
-
-#define TYPE_MAIN       0
-#define TYPE_GLOBAL     1
-#define TYPE_LOCAL      2
-#define TYPE_RESERVED   3
-
-#define TAG_MAIN_INPUT        0x8
-#define TAG_MAIN_OUTPUT       0x9
-#define TAG_MAIN_FEATURE      0xB
-#define TAG_MAIN_COL_START    0xA
-#define TAG_MAIN_COL_END      0xC
-
-#define TAG_GLOB_USAGE        0
-#define TAG_GLOB_LOG_MIN      1
-#define TAG_GLOB_LOG_MAX      2
-#define TAG_GLOB_PHYS_MIN     3
-#define TAG_GLOB_PHYS_MAX     4
-#define TAG_GLOB_UNIT_EXP     5
-#define TAG_GLOB_UNIT         6
-#define TAG_GLOB_REPORT_SZ    7
-#define TAG_GLOB_REPORT_ID    8
-#define TAG_GLOB_REPORT_CNT   9
-#define TAG_GLOB_PUSH         10
-#define TAG_GLOB_POP          11
-
-#define TAG_GLOB_MAX          12
-
-#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
-#define DIGITIZER_USAGE_TILT_X         0x3D
-#define DIGITIZER_USAGE_TILT_Y         0x3E
-
-
-/*
- *
- *   This is an abbreviated parser for the HID Report Descriptor.  We
- *   know what devices we are talking to, so this is by no means meant
- *   to be generic.  We can make some safe assumptions:
- *
- *   - We know there are no LONG tags, all short
- *   - We know that we have no MAIN Feature and MAIN Output items
- *   - We know what the IRQ reports are supposed to look like.
- *
- *   The main purpose of this is to use the HID report desc to figure
- *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
- *   reports for 400/401 change slightly if the max X is bigger than 64K.
- *
- */
-static void parse_hid_report_descriptor(struct gtco *device, char * report,
-					int length)
-{
-	int   x,i=0;
-
-	/* Tag primitive vars */
-	__u8   prefix;
-	__u8   size;
-	__u8   tag;
-	__u8   type;
-	__u8   data   = 0;
-	__u16  data16 = 0;
-	__u32  data32 = 0;
-
-
-	/* For parsing logic */
-	int   inputnum = 0;
-	__u32 usage = 0;
-
-	/* Global Values, indexed by TAG */
-	__u32 globalval[TAG_GLOB_MAX];
-	__u32 oldval[TAG_GLOB_MAX];
-
-	/* Debug stuff */
-	char  maintype='x';
-	char  globtype[12];
-	int   indent=0;
-	char  indentstr[10]="";
-
-
-
-	dbg("======>>>>>>PARSE<<<<<<======");
-
-	/* Walk  this report and pull out the info we need */
-	while (i<length){
-		prefix=report[i];
-
-		/* Skip over prefix */
-		i++;
-
-		/* Determine data size and save the data in the proper variable */
-		size = PREF_SIZE(prefix);
-		switch(size){
-		case 1:
-			data = report[i];
-			break;
-		case 2:
-			data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
-			break;
-		case 3:
-			size = 4;
-			data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
-		}
-
-		/* Skip size of data */
-		i+=size;
-
-		/* What we do depends on the tag type */
-		tag  = PREF_TAG(prefix);
-		type = PREF_TYPE(prefix);
-		switch(type){
-		case TYPE_MAIN:
-			strcpy(globtype,"");
-			switch(tag){
-
-			case TAG_MAIN_INPUT:
-				/*
-				 * The INPUT MAIN tag signifies this is
-				 * information from a report.  We need to
-				 * figure out what it is and store the
-				 * min/max values
-				 */
-
-				maintype='I';
-				if (data==2){
-					strcpy(globtype,"Variable");
-				}
-				if (data==3){
-					strcpy(globtype,"Var|Const");
-				}
-
-				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
-				    globalval[TAG_GLOB_REPORT_ID],inputnum,
-				    globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
-				    globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
-				    (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
-
-
-				/*
-				  We can assume that the first two input items
-				  are always the X and Y coordinates.  After
-				  that, we look for everything else by
-				  local usage value
-				 */
-				switch (inputnum){
-				case 0:  /* X coord */
-					dbg("GER: X Usage: 0x%x",usage);
-					if (device->max_X == 0){
-						device->max_X = globalval[TAG_GLOB_LOG_MAX];
-						device->min_X = globalval[TAG_GLOB_LOG_MIN];
-					}
-
-					break;
-				case 1:  /* Y coord */
-					dbg("GER: Y Usage: 0x%x",usage);
-					if (device->max_Y == 0){
-						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
-						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
-					}
-					break;
-				default:
-					/* Tilt X */
-					if (usage == DIGITIZER_USAGE_TILT_X){
-						if (device->maxtilt_X == 0){
-							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
-							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
-						}
-					}
-
-					/* Tilt Y */
-					if (usage == DIGITIZER_USAGE_TILT_Y){
-						if (device->maxtilt_Y == 0){
-							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
-							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
-						}
-					}
-
-
-					/* Pressure */
-					if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
-						if (device->maxpressure == 0){
-							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
-							device->minpressure = globalval[TAG_GLOB_LOG_MIN];
-						}
-					}
-
-					break;
-				}
-
-				inputnum++;
-
-
-				break;
-			case TAG_MAIN_OUTPUT:
-				maintype='O';
-				break;
-			case TAG_MAIN_FEATURE:
-				maintype='F';
-				break;
-			case TAG_MAIN_COL_START:
-				maintype='S';
-
-				if (data==0){
-					dbg("======>>>>>> Physical");
-					strcpy(globtype,"Physical");
-				}else{
-					dbg("======>>>>>>");
-				}
-
-				/* Indent the debug output */
-				indent++;
-				for (x=0;x<indent;x++){
-					indentstr[x]='-';
-				}
-				indentstr[x]=0;
-
-				/* Save global tags */
-				for (x=0;x<TAG_GLOB_MAX;x++){
-					oldval[x] = globalval[x];
-				}
-
-				break;
-			case TAG_MAIN_COL_END:
-				dbg("<<<<<<======");
-				maintype='E';
-				indent--;
-				for (x=0;x<indent;x++){
-					indentstr[x]='-';
-				}
-				indentstr[x]=0;
-
-				/* Copy global tags back */
-				for (x=0;x<TAG_GLOB_MAX;x++){
-					globalval[x] = oldval[x];
-				}
-
-				break;
-			}
-
-			switch (size){
-			case 1:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr,tag,maintype,size,globtype,data);
-				break;
-			case 2:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr,tag,maintype,size,globtype, data16);
-				break;
-			case 4:
-				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-				    indentstr,tag,maintype,size,globtype,data32);
-				break;
-			}
-			break;
-		case TYPE_GLOBAL:
-			switch(tag){
-			case TAG_GLOB_USAGE:
-				/*
-				 * First time we hit the global usage tag,
-				 * it should tell us the type of device
-				 */
-				if (device->usage == 0){
-					device->usage = data;
-				}
-				strcpy(globtype,"USAGE");
-				break;
-			case TAG_GLOB_LOG_MIN   :
-				strcpy(globtype,"LOG_MIN");
-				break;
-			case TAG_GLOB_LOG_MAX   :
-				strcpy(globtype,"LOG_MAX");
-				break;
-			case TAG_GLOB_PHYS_MIN  :
-				strcpy(globtype,"PHYS_MIN");
-				break;
-			case TAG_GLOB_PHYS_MAX  :
-				strcpy(globtype,"PHYS_MAX");
-				break;
-			case TAG_GLOB_UNIT_EXP  :
-				strcpy(globtype,"EXP");
-				break;
-			case TAG_GLOB_UNIT      :
-				strcpy(globtype,"UNIT");
-				break;
-			case TAG_GLOB_REPORT_SZ :
-				strcpy(globtype,"REPORT_SZ");
-				break;
-			case TAG_GLOB_REPORT_ID :
-				strcpy(globtype,"REPORT_ID");
-				/* New report, restart numbering */
-				inputnum=0;
-				break;
-			case TAG_GLOB_REPORT_CNT:
-				strcpy(globtype,"REPORT_CNT");
-				break;
-			case TAG_GLOB_PUSH :
-				strcpy(globtype,"PUSH");
-				break;
-			case TAG_GLOB_POP:
-				strcpy(globtype,"POP");
-				break;
-			}
-
-
-			/* Check to make sure we have a good tag number
-			   so we don't overflow array */
-			if (tag < TAG_GLOB_MAX){
-				switch (size){
-				case 1:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
-					globalval[tag]=data;
-					break;
-				case 2:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
-					globalval[tag]=data16;
-					break;
-				case 4:
-					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
-					globalval[tag]=data32;
-					break;
-				}
-			}else{
-				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
-				    indentstr,tag,size);
-			}
-
-
-			break;
-
-		case TYPE_LOCAL:
-			switch(tag){
-			case TAG_GLOB_USAGE:
-				strcpy(globtype,"USAGE");
-				/* Always 1 byte */
-				usage = data;
-				break;
-			case TAG_GLOB_LOG_MIN   :
-				strcpy(globtype,"MIN");
-				break;
-			case TAG_GLOB_LOG_MAX   :
-				strcpy(globtype,"MAX");
-				break;
-			default:
-				strcpy(globtype,"UNKNOWN");
-			}
-
-			switch (size){
-			case 1:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr,tag,globtype,size,data);
-				break;
-			case 2:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr,tag,globtype,size,data16);
-				break;
-			case 4:
-				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-				    indentstr,tag,globtype,size,data32);
-				break;
-			}
-
-			break;
-		}
-
-	}
-
-}
-
-
-
-/*   INPUT DRIVER Routines                               */
-
-
-/*
- *    Called when opening the input device.  This will submit the URB to
- *    the usb system so we start getting reports
- */
-static int gtco_input_open(struct input_dev *inputdev)
-{
-	struct gtco *device;
-	device = inputdev->private;
-
-	device->urbinfo->dev = device->usbdev;
-	if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
-		return -EIO;
-	}
-	return 0;
-}
-
-/**
-    Called when closing the input device.  This will unlink the URB
-*/
-static void gtco_input_close(struct input_dev *inputdev)
-{
-	struct gtco *device = inputdev->private;
-
-	usb_kill_urb(device->urbinfo);
-
-}
-
-
-/*
- *  Setup input device capabilities.  Tell the input system what this
- *  device is capable of generating.
- *
- *  This information is based on what is read from the HID report and
- *  placed in the struct gtco structure
- *
- */
-static void  gtco_setup_caps(struct input_dev  *inputdev)
-{
-	struct gtco *device = inputdev->private;
-
-
-	/* Which events */
-	inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
-
-
-	/* Misc event menu block */
-	inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
-
-
-	/* Absolute values based on HID report info */
-	input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
-			     0, 0);
-	input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
-			     0, 0);
-
-	/* Proximity */
-	input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
-
-	/* Tilt & pressure */
-	input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
-			     device->maxtilt_X, 0, 0);
-	input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
-			     device->maxtilt_Y, 0, 0);
-	input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
-			     device->maxpressure, 0, 0);
-
-
-	/* Transducer */
-	input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
-
-}
-
-
-
-/*   USB Routines  */
-
-
-/*
- * URB callback routine.  Called when we get IRQ reports from the
- *  digitizer.
- *
- *  This bridges the USB and input device worlds.  It generates events
- *  on the input device based on the USB reports.
- */
-static void gtco_urb_callback(struct urb *urbinfo)
-{
-
-
-	struct gtco     *device = urbinfo->context;
-	struct input_dev  *inputdev;
-	int               rc;
-	u32               val = 0;
-	s8                valsigned = 0;
-	char              le_buffer[2];
-
-	inputdev = device->inputdevice;
-
-
-	/* Was callback OK? */
-	if ((urbinfo->status == -ECONNRESET ) ||
-	    (urbinfo->status == -ENOENT ) ||
-	    (urbinfo->status == -ESHUTDOWN )){
-
-		/* Shutdown is occurring. Return and don't queue up any more */
-		return;
-	}
-
-	if (urbinfo->status != 0 ) {
-		/* Some unknown error.  Hopefully temporary.  Just go and */
-		/* requeue an URB */
-		goto resubmit;
-	}
-
-	/*
-	 * Good URB, now process
-	 */
-
-	/* PID dependent when we interpret the report */
-	if ((inputdev->id.product == PID_1000 )||
-	    (inputdev->id.product == PID_1001 )||
-	    (inputdev->id.product == PID_1002 ))
-	{
-
-		/*
-		 * Switch on the report ID
-		 * Conveniently, the reports have more information, the higher
-		 * the report number.  We can just fall through the case
-		 * statements if we start with the highest number report
-		 */
-		switch(device->buffer[0]){
-		case 5:
-			/* Pressure is 9 bits */
-			val =  ((u16)(device->buffer[8]) << 1);
-			val |= (u16)(device->buffer[7] >> 7);
-			input_report_abs(inputdev, ABS_PRESSURE,
-					 device->buffer[8]);
-
-			/* Mask out the Y tilt value used for pressure */
-			device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
-
-
-			/* Fall thru */
-		case 4:
-			/* Tilt */
-
-			/* Sign extend these 7 bit numbers.  */
-			if (device->buffer[6] & 0x40)
-				device->buffer[6] |= 0x80;
-
-			if (device->buffer[7] & 0x40)
-				device->buffer[7] |= 0x80;
-
-
-			valsigned = (device->buffer[6]);
-			input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
-
-			valsigned = (device->buffer[7]);
-			input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
-
-			/* Fall thru */
-
-		case 2:
-		case 3:
-			/* Convert buttons, only 5 bits possible */
-			val = (device->buffer[5])&MASK_BUTTON;
-
-			/* We don't apply any meaning to the bitmask,
-			   just report */
-			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-
-			/*  Fall thru */
-		case 1:
-
-			/* All reports have X and Y coords in the same place */
-			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
-			input_report_abs(inputdev, ABS_X, val);
-
-			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
-			input_report_abs(inputdev, ABS_Y, val);
-
-
-			/* Ditto for proximity bit */
-			if (device->buffer[5]& MASK_INRANGE){
-				val = 1;
-			}else{
-				val=0;
-			}
-			input_report_abs(inputdev, ABS_DISTANCE, val);
-
-
-			/* Report 1 is an exception to how we handle buttons */
-			/* Buttons are an index, not a bitmask */
-			if (device->buffer[0] == 1){
-
-				/* Convert buttons, 5 bit index */
-				/* Report value of index set as one,
-				   the rest as 0 */
-				val = device->buffer[5]& MASK_BUTTON;
-				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
-				    val,val);
-
-				/*
-				 * We don't apply any meaning to the button
-				 * index, just report it
-				 */
-				input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-
-
-			}
-
-			break;
-		case 7:
-			/* Menu blocks */
-			input_event(inputdev, EV_MSC, MSC_SCAN,
-				    device->buffer[1]);
-
-
-			break;
-
-		}
-
-
-	}
-	/* Other pid class */
-	if ((inputdev->id.product == PID_400 )||
-	    (inputdev->id.product == PID_401 ))
-	{
-
-		/* Report 2 */
-		if (device->buffer[0] == 2){
-			/* Menu blocks */
-			input_event(inputdev, EV_MSC, MSC_SCAN,
-				    device->buffer[1]);
-		}
-
-		/*  Report 1 */
-		if (device->buffer[0] == 1){
-			char buttonbyte;
-
-
-			/*  IF X max > 64K, we still a bit from the y report */
-			if (device->max_X > 0x10000){
-
-				val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
-				val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
-
-				input_report_abs(inputdev, ABS_X, val);
-
-				le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
-				le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
-
-				le_buffer[1]  = (u8)(device->buffer[4]>>1);
-				le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
-
-				val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
-
-				input_report_abs(inputdev, ABS_Y, val);
-
-
-				/*
-				 * Shift the button byte right by one to
-				 * make it look like the standard report
-				 */
-				buttonbyte = (device->buffer[5])>>1;
-			}else{
-
-				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
-				input_report_abs(inputdev, ABS_X, val);
-
-				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
-				input_report_abs(inputdev, ABS_Y, val);
-
-				buttonbyte = device->buffer[5];
-
-			}
-
-
-			/* BUTTONS and PROXIMITY */
-			if (buttonbyte& MASK_INRANGE){
-				val = 1;
-			}else{
-				val=0;
-			}
-			input_report_abs(inputdev, ABS_DISTANCE, val);
-
-			/* Convert buttons, only 4 bits possible */
-			val = buttonbyte&0x0F;
-#ifdef USE_BUTTONS
-			for ( i=0;i<5;i++){
-				input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
-			}
-#else
-			/* We don't apply any meaning to the bitmask, just report */
-			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-#endif
-			/* TRANSDUCER */
-			input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
-
-		}
-	}
-
-	/* Everybody gets report ID's */
-	input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
-
-	/* Sync it up */
-	input_sync(inputdev);
-
- resubmit:
-	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
-	if (rc != 0) {
-		err("usb_submit_urb failed rc=0x%x",rc);
-	}
-
-}
-
-/*
- *  The probe routine.  This is called when the kernel find the matching USB
- *   vendor/product.  We do the following:
- *
- *    - Allocate mem for a local structure to manage the device
- *    - Request a HID Report Descriptor from the device and parse it to
- *      find out the device parameters
- *    - Create an input device and assign it attributes
- *   - Allocate an URB so the device can talk to us when the input
- *      queue is open
- */
-static int gtco_probe(struct usb_interface *usbinterface,
-		      const struct usb_device_id *id)
-{
-
-	struct gtco             *device = NULL;
-	char                    path[PATHLENGTH];
-	struct input_dev        *inputdev;
-	struct hid_descriptor   *hid_desc;
-	char                    *report;
-	int                     result=0, retry;
-	struct usb_endpoint_descriptor *endpoint;
-
-	/* Allocate memory for device structure */
-	device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
-	if (device == NULL) {
-		err("No more memory");
-		return -ENOMEM;
-	}
-
-
-	device->inputdevice = input_allocate_device();
-	if (!device->inputdevice){
-		kfree(device);
-		err("No more memory");
-		return -ENOMEM;
-	}
-
-	/* Get pointer to the input device */
-	inputdev = device->inputdevice;
-
-	/* Save interface information */
-	device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
-
-
-	/* Allocate some data for incoming reports */
-	device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
-					   GFP_KERNEL, &(device->buf_dma));
-	if (!device->buffer){
-		input_free_device(device->inputdevice);
-		kfree(device);
-		err("No more memory");
-		return -ENOMEM;
-	}
-
-	/* Allocate URB for reports */
-	device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
-	if (!device->urbinfo) {
-		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
-				device->buffer, device->buf_dma);
-		input_free_device(device->inputdevice);
-		kfree(device);
-		err("No more memory");
-		return -ENOMEM;
-	}
-
-
-	/*
-	 * The endpoint is always altsetting 0, we know this since we know
-	 * this device only has one interrupt endpoint
-	 */
-	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
-
-	/* Some debug */
-	dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
-	dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
-	dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
-	dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
-		dbg("endpoint: we have interrupt endpoint\n");
-
-	dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
-
-
-
-	/*
-	 * Find the HID descriptor so we can find out the size of the
-	 * HID report descriptor
-	 */
-	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
-				     HID_DEVICE_TYPE,&hid_desc) != 0){
-		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
-		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
-				device->buffer, device->buf_dma);
-		input_free_device(device->inputdevice);
-		kfree(device);
-		return -EIO;
-	}
-
-	dbg("Extra descriptor success: type:%d  len:%d",
-	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
-
-	if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
-		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
-				device->buffer, device->buf_dma);
-
-		input_free_device(device->inputdevice);
-		kfree(device);
-		err("No more memory");
-		return -ENOMEM;
-	}
-
-	/* Couple of tries to get reply */
-	for (retry=0;retry<3;retry++) {
-		result = usb_control_msg(device->usbdev,
-					 usb_rcvctrlpipe(device->usbdev, 0),
-					 USB_REQ_GET_DESCRIPTOR,
-					 USB_RECIP_INTERFACE | USB_DIR_IN,
-					 (REPORT_DEVICE_TYPE << 8),
-					 0, /* interface */
-					 report,
-					 hid_desc->wDescriptorLength,
-					 5000); /* 5 secs */
-
-		if (result == hid_desc->wDescriptorLength)
-			break;
-	}
-
-	/* If we didn't get the report, fail */
-	dbg("usb_control_msg result: :%d", result);
-	if (result != hid_desc->wDescriptorLength){
-		kfree(report);
-		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
-				device->buffer, device->buf_dma);
-		input_free_device(device->inputdevice);
-		kfree(device);
-		err("Failed to get HID Report Descriptor of size: %d",
-		    hid_desc->wDescriptorLength);
-		return -EIO;
-	}
-
-
-	/* Now we parse the report */
-	parse_hid_report_descriptor(device,report,result);
-
-	/* Now we delete it */
-	kfree(report);
-
-	/* Create a device file node */
-	usb_make_path(device->usbdev, path, PATHLENGTH);
-	sprintf(device->usbpath, "%s/input0", path);
-
-
-	/* Set Input device functions */
-	inputdev->open     = gtco_input_open;
-	inputdev->close    = gtco_input_close;
-
-	/* Set input device information */
-	inputdev->name     = "GTCO_CalComp";
-	inputdev->phys     = device->usbpath;
-	inputdev->private  = device;
-
-
-	/* Now set up all the input device capabilities */
-	gtco_setup_caps(inputdev);
-
-	/* Set input device required ID information */
-	usb_to_input_id(device->usbdev, &device->inputdevice->id);
-	inputdev->cdev.dev = &usbinterface->dev;
-
-	/* Setup the URB, it will be posted later on open of input device */
-	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
-
-	usb_fill_int_urb(device->urbinfo,
-			 device->usbdev,
-			 usb_rcvintpipe(device->usbdev,
-					endpoint->bEndpointAddress),
-			 device->buffer,
-			 REPORT_MAX_SIZE,
-			 gtco_urb_callback,
-			 device,
-			 endpoint->bInterval);
-
-	device->urbinfo->transfer_dma = device->buf_dma;
-	device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-
-	/* Save device pointer in USB interface device */
-	usb_set_intfdata(usbinterface, device);
-
-	/* All done, now register the input device */
-	input_register_device(inputdev);
-
-	info( "gtco driver created usb:  %s\n",  path);
-	return 0;
-
-}
-
-/*
- *  This function is a standard USB function called when the USB device
- *  is disconnected.  We will get rid of the URV, de-register the input
- *  device, and free up allocated memory
- */
-static void gtco_disconnect(struct usb_interface *interface)
-{
-
-	/* Grab private device ptr */
-	struct gtco    *device = usb_get_intfdata (interface);
-	struct input_dev *inputdev;
-
-	inputdev = device->inputdevice;
-
-	/* Now reverse all the registration stuff */
-	if (device) {
-		input_unregister_device(inputdev);
-		usb_kill_urb(device->urbinfo);
-		usb_free_urb(device->urbinfo);
-		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
-				device->buffer, device->buf_dma);
-		kfree(device);
-	}
-
-	info("gtco driver disconnected");
-}
-
-
-/*   STANDARD MODULE LOAD ROUTINES  */
-
-static struct usb_driver gtco_driverinfo_table = {
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
-	.owner      = THIS_MODULE,
-#endif
-	.name       = "gtco",
-	.id_table   = gtco_usbid_table,
-	.probe      = gtco_probe,
-	.disconnect = gtco_disconnect,
-};
-/*
- *  Register this module with the USB subsystem
- */
-static int __init gtco_init(void)
-{
-	int rc;
-	rc = usb_register(&gtco_driverinfo_table);
-	if (rc) {
-		err("usb_register() failed rc=0x%x", rc);
-	}
-	printk("GTCO usb driver version: %s",GTCO_VERSION);
-	return rc;
-}
-
-/*
- *   Deregister this module with the USB subsystem
- */
-static void __exit gtco_exit(void)
-{
-	usb_deregister(&gtco_driverinfo_table);
-}
-
-module_init (gtco_init);
-module_exit (gtco_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
deleted file mode 100644
index 827a75a..0000000
--- a/drivers/usb/input/hid-core.c
+++ /dev/null
@@ -1,1477 +0,0 @@
-/*
- *  USB HID support for Linux
- *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the 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/slab.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-#include <linux/input.h>
-#include <linux/wait.h>
-
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include <linux/hid-debug.h>
-#include "usbhid.h"
-
-/*
- * Version Information
- */
-
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
-#define DRIVER_DESC "USB HID core driver"
-#define DRIVER_LICENSE "GPL"
-
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
-				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
-/*
- * Module parameters.
- */
-
-static unsigned int hid_mousepoll_interval;
-module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
-MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
-
-/*
- * Input submission and I/O error handler.
- */
-
-static void hid_io_error(struct hid_device *hid);
-
-/* Start up the input URB */
-static int hid_start_in(struct hid_device *hid)
-{
-	unsigned long flags;
-	int rc = 0;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	spin_lock_irqsave(&usbhid->inlock, flags);
-	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
-			!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
-		rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
-		if (rc != 0)
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-	}
-	spin_unlock_irqrestore(&usbhid->inlock, flags);
-	return rc;
-}
-
-/* I/O retry timer routine */
-static void hid_retry_timeout(unsigned long _hid)
-{
-	struct hid_device *hid = (struct hid_device *) _hid;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	dev_dbg(&usbhid->intf->dev, "retrying intr urb\n");
-	if (hid_start_in(hid))
-		hid_io_error(hid);
-}
-
-/* Workqueue routine to reset the device or clear a halt */
-static void hid_reset(struct work_struct *work)
-{
-	struct usbhid_device *usbhid =
-		container_of(work, struct usbhid_device, reset_work);
-	struct hid_device *hid = usbhid->hid;
-	int rc_lock, rc = 0;
-
-	if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
-		dev_dbg(&usbhid->intf->dev, "clear halt\n");
-		rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
-		clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
-		hid_start_in(hid);
-	}
-
-	else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
-		dev_dbg(&usbhid->intf->dev, "resetting device\n");
-		rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
-		if (rc_lock >= 0) {
-			rc = usb_reset_composite_device(hid_to_usb_dev(hid), usbhid->intf);
-			if (rc_lock)
-				usb_unlock_device(hid_to_usb_dev(hid));
-		}
-		clear_bit(HID_RESET_PENDING, &usbhid->iofl);
-	}
-
-	switch (rc) {
-	case 0:
-		if (!test_bit(HID_IN_RUNNING, &usbhid->iofl))
-			hid_io_error(hid);
-		break;
-	default:
-		err("can't reset device, %s-%s/input%d, status %d",
-				hid_to_usb_dev(hid)->bus->bus_name,
-				hid_to_usb_dev(hid)->devpath,
-				usbhid->ifnum, rc);
-		/* FALLTHROUGH */
-	case -EHOSTUNREACH:
-	case -ENODEV:
-	case -EINTR:
-		break;
-	}
-}
-
-/* Main I/O error handler */
-static void hid_io_error(struct hid_device *hid)
-{
-	unsigned long flags;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	spin_lock_irqsave(&usbhid->inlock, flags);
-
-	/* Stop when disconnected */
-	if (usb_get_intfdata(usbhid->intf) == NULL)
-		goto done;
-
-	/* When an error occurs, retry at increasing intervals */
-	if (usbhid->retry_delay == 0) {
-		usbhid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
-		usbhid->stop_retry = jiffies + msecs_to_jiffies(1000);
-	} else if (usbhid->retry_delay < 100)
-		usbhid->retry_delay *= 2;
-
-	if (time_after(jiffies, usbhid->stop_retry)) {
-
-		/* Retries failed, so do a port reset */
-		if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
-			schedule_work(&usbhid->reset_work);
-			goto done;
-		}
-	}
-
-	mod_timer(&usbhid->io_retry,
-			jiffies + msecs_to_jiffies(usbhid->retry_delay));
-done:
-	spin_unlock_irqrestore(&usbhid->inlock, flags);
-}
-
-/*
- * Input interrupt completion handler.
- */
-
-static void hid_irq_in(struct urb *urb)
-{
-	struct hid_device	*hid = urb->context;
-	struct usbhid_device 	*usbhid = hid->driver_data;
-	int			status;
-
-	switch (urb->status) {
-		case 0:			/* success */
-			usbhid->retry_delay = 0;
-			hid_input_report(urb->context, HID_INPUT_REPORT,
-					 urb->transfer_buffer,
-					 urb->actual_length, 1);
-			break;
-		case -EPIPE:		/* stall */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			set_bit(HID_CLEAR_HALT, &usbhid->iofl);
-			schedule_work(&usbhid->reset_work);
-			return;
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-		case -ESHUTDOWN:	/* unplug */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			return;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ETIME:		/* protocol error or unplug */
-		case -ETIMEDOUT:	/* Should never happen, but... */
-			clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-			hid_io_error(hid);
-			return;
-		default:		/* error */
-			warn("input irq status %d received", urb->status);
-	}
-
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status) {
-		clear_bit(HID_IN_RUNNING, &usbhid->iofl);
-		if (status != -EPERM) {
-			err("can't resubmit intr, %s-%s/input%d, status %d",
-					hid_to_usb_dev(hid)->bus->bus_name,
-					hid_to_usb_dev(hid)->devpath,
-					usbhid->ifnum, status);
-			hid_io_error(hid);
-		}
-	}
-}
-
-static int hid_submit_out(struct hid_device *hid)
-{
-	struct hid_report *report;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	report = usbhid->out[usbhid->outtail];
-
-	hid_output_report(report, usbhid->outbuf);
-	usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-	usbhid->urbout->dev = hid_to_usb_dev(hid);
-
-	dbg("submitting out urb");
-
-	if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
-		err("usb_submit_urb(out) failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int hid_submit_ctrl(struct hid_device *hid)
-{
-	struct hid_report *report;
-	unsigned char dir;
-	int len;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	report = usbhid->ctrl[usbhid->ctrltail].report;
-	dir = usbhid->ctrl[usbhid->ctrltail].dir;
-
-	len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-	if (dir == USB_DIR_OUT) {
-		hid_output_report(report, usbhid->ctrlbuf);
-		usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
-		usbhid->urbctrl->transfer_buffer_length = len;
-	} else {
-		int maxpacket, padlen;
-
-		usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
-		maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
-		if (maxpacket > 0) {
-			padlen = (len + maxpacket - 1) / maxpacket;
-			padlen *= maxpacket;
-			if (padlen > usbhid->bufsize)
-				padlen = usbhid->bufsize;
-		} else
-			padlen = 0;
-		usbhid->urbctrl->transfer_buffer_length = padlen;
-	}
-	usbhid->urbctrl->dev = hid_to_usb_dev(hid);
-
-	usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
-	usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
-	usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
-	usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
-	usbhid->cr->wLength = cpu_to_le16(len);
-
-	dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u",
-		usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
-		usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
-
-	if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
-		err("usb_submit_urb(ctrl) failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Output interrupt completion handler.
- */
-
-static void hid_irq_out(struct urb *urb)
-{
-	struct hid_device *hid = urb->context;
-	struct usbhid_device *usbhid = hid->driver_data;
-	unsigned long flags;
-	int unplug = 0;
-
-	switch (urb->status) {
-		case 0:			/* success */
-			break;
-		case -ESHUTDOWN:	/* unplug */
-			unplug = 1;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-			break;
-		default:		/* error */
-			warn("output irq status %d received", urb->status);
-	}
-
-	spin_lock_irqsave(&usbhid->outlock, flags);
-
-	if (unplug)
-		usbhid->outtail = usbhid->outhead;
-	else
-		usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
-
-	if (usbhid->outhead != usbhid->outtail) {
-		if (hid_submit_out(hid)) {
-			clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-			wake_up(&hid->wait);
-		}
-		spin_unlock_irqrestore(&usbhid->outlock, flags);
-		return;
-	}
-
-	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-	spin_unlock_irqrestore(&usbhid->outlock, flags);
-	wake_up(&hid->wait);
-}
-
-/*
- * Control pipe completion handler.
- */
-
-static void hid_ctrl(struct urb *urb)
-{
-	struct hid_device *hid = urb->context;
-	struct usbhid_device *usbhid = hid->driver_data;
-	unsigned long flags;
-	int unplug = 0;
-
-	spin_lock_irqsave(&usbhid->ctrllock, flags);
-
-	switch (urb->status) {
-		case 0:			/* success */
-			if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
-				hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
-						urb->transfer_buffer, urb->actual_length, 0);
-			break;
-		case -ESHUTDOWN:	/* unplug */
-			unplug = 1;
-		case -EILSEQ:		/* protocol error or unplug */
-		case -EPROTO:		/* protocol error or unplug */
-		case -ECONNRESET:	/* unlink */
-		case -ENOENT:
-		case -EPIPE:		/* report not available */
-			break;
-		default:		/* error */
-			warn("ctrl urb status %d received", urb->status);
-	}
-
-	if (unplug)
-		usbhid->ctrltail = usbhid->ctrlhead;
-	else
-		usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
-
-	if (usbhid->ctrlhead != usbhid->ctrltail) {
-		if (hid_submit_ctrl(hid)) {
-			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-			wake_up(&hid->wait);
-		}
-		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-		return;
-	}
-
-	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-	wake_up(&hid->wait);
-}
-
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
-{
-	int head;
-	unsigned long flags;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
-		return;
-
-	if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
-
-		spin_lock_irqsave(&usbhid->outlock, flags);
-
-		if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
-			spin_unlock_irqrestore(&usbhid->outlock, flags);
-			warn("output queue full");
-			return;
-		}
-
-		usbhid->out[usbhid->outhead] = report;
-		usbhid->outhead = head;
-
-		if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
-			if (hid_submit_out(hid))
-				clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-
-		spin_unlock_irqrestore(&usbhid->outlock, flags);
-		return;
-	}
-
-	spin_lock_irqsave(&usbhid->ctrllock, flags);
-
-	if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
-		spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-		warn("control queue full");
-		return;
-	}
-
-	usbhid->ctrl[usbhid->ctrlhead].report = report;
-	usbhid->ctrl[usbhid->ctrlhead].dir = dir;
-	usbhid->ctrlhead = head;
-
-	if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-		if (hid_submit_ctrl(hid))
-			clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-
-	spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-}
-
-static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	struct hid_device *hid = dev->private;
-	struct hid_field *field;
-	int offset;
-
-	if (type == EV_FF)
-		return input_ff_event(dev, type, code, value);
-
-	if (type != EV_LED)
-		return -1;
-
-	if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
-		warn("event field not found");
-		return -1;
-	}
-
-	hid_set_field(field, offset, value);
-	usbhid_submit_report(hid, field->report, USB_DIR_OUT);
-
-	return 0;
-}
-
-int usbhid_wait_io(struct hid_device *hid)
-{
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
-					!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
-					10*HZ)) {
-		dbg("timeout waiting for ctrl or out queue to clear");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
-{
-	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-		HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
-		ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
-		unsigned char type, void *buf, int size)
-{
-	int result, retries = 4;
-
-	memset(buf, 0, size);
-
-	do {
-		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-				USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
-				(type << 8), ifnum, buf, size, USB_CTRL_GET_TIMEOUT);
-		retries--;
-	} while (result < size && retries);
-	return result;
-}
-
-int usbhid_open(struct hid_device *hid)
-{
-	++hid->open;
-	if (hid_start_in(hid))
-		hid_io_error(hid);
-	return 0;
-}
-
-void usbhid_close(struct hid_device *hid)
-{
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	if (!--hid->open)
-		usb_kill_urb(usbhid->urbin);
-}
-
-#define USB_VENDOR_ID_PANJIT		0x134c
-
-#define USB_VENDOR_ID_TURBOX		0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD	0x0201
-#define USB_VENDOR_ID_CIDC		0x1677
-
-/*
- * Initialize all reports
- */
-
-void usbhid_init_reports(struct hid_device *hid)
-{
-	struct hid_report *report;
-	struct usbhid_device *usbhid = hid->driver_data;
-	int err, ret;
-
-	list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-		usbhid_submit_report(hid, report, USB_DIR_IN);
-
-	list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-		usbhid_submit_report(hid, report, USB_DIR_IN);
-
-	err = 0;
-	ret = usbhid_wait_io(hid);
-	while (ret) {
-		err |= ret;
-		if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
-			usb_kill_urb(usbhid->urbctrl);
-		if (test_bit(HID_OUT_RUNNING, &usbhid->iofl))
-			usb_kill_urb(usbhid->urbout);
-		ret = usbhid_wait_io(hid);
-	}
-
-	if (err)
-		warn("timeout initializing reports");
-}
-
-#define USB_VENDOR_ID_GTCO		0x078c
-#define USB_DEVICE_ID_GTCO_90		0x0090
-#define USB_DEVICE_ID_GTCO_100		0x0100
-#define USB_DEVICE_ID_GTCO_101		0x0101
-#define USB_DEVICE_ID_GTCO_103		0x0103
-#define USB_DEVICE_ID_GTCO_104		0x0104
-#define USB_DEVICE_ID_GTCO_105		0x0105
-#define USB_DEVICE_ID_GTCO_106		0x0106
-#define USB_DEVICE_ID_GTCO_107		0x0107
-#define USB_DEVICE_ID_GTCO_108		0x0108
-#define USB_DEVICE_ID_GTCO_200		0x0200
-#define USB_DEVICE_ID_GTCO_201		0x0201
-#define USB_DEVICE_ID_GTCO_202		0x0202
-#define USB_DEVICE_ID_GTCO_203		0x0203
-#define USB_DEVICE_ID_GTCO_204		0x0204
-#define USB_DEVICE_ID_GTCO_205		0x0205
-#define USB_DEVICE_ID_GTCO_206		0x0206
-#define USB_DEVICE_ID_GTCO_207		0x0207
-#define USB_DEVICE_ID_GTCO_300		0x0300
-#define USB_DEVICE_ID_GTCO_301		0x0301
-#define USB_DEVICE_ID_GTCO_302		0x0302
-#define USB_DEVICE_ID_GTCO_303		0x0303
-#define USB_DEVICE_ID_GTCO_304		0x0304
-#define USB_DEVICE_ID_GTCO_305		0x0305
-#define USB_DEVICE_ID_GTCO_306		0x0306
-#define USB_DEVICE_ID_GTCO_307		0x0307
-#define USB_DEVICE_ID_GTCO_308		0x0308
-#define USB_DEVICE_ID_GTCO_309		0x0309
-#define USB_DEVICE_ID_GTCO_400		0x0400
-#define USB_DEVICE_ID_GTCO_401		0x0401
-#define USB_DEVICE_ID_GTCO_402		0x0402
-#define USB_DEVICE_ID_GTCO_403		0x0403
-#define USB_DEVICE_ID_GTCO_404		0x0404
-#define USB_DEVICE_ID_GTCO_405		0x0405
-#define USB_DEVICE_ID_GTCO_500		0x0500
-#define USB_DEVICE_ID_GTCO_501		0x0501
-#define USB_DEVICE_ID_GTCO_502		0x0502
-#define USB_DEVICE_ID_GTCO_503		0x0503
-#define USB_DEVICE_ID_GTCO_504		0x0504
-#define USB_DEVICE_ID_GTCO_1000		0x1000
-#define USB_DEVICE_ID_GTCO_1001		0x1001
-#define USB_DEVICE_ID_GTCO_1002		0x1002
-#define USB_DEVICE_ID_GTCO_1003		0x1003
-#define USB_DEVICE_ID_GTCO_1004		0x1004
-#define USB_DEVICE_ID_GTCO_1005		0x1005
-#define USB_DEVICE_ID_GTCO_1006		0x1006
-
-#define USB_VENDOR_ID_WACOM		0x056a
-
-#define USB_VENDOR_ID_ACECAD		0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
-#define USB_DEVICE_ID_ACECAD_302	0x0008
-
-#define USB_VENDOR_ID_KBGEAR		0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
-
-#define USB_VENDOR_ID_AIPTEK		0x08ca
-#define USB_DEVICE_ID_AIPTEK_01		0x0001
-#define USB_DEVICE_ID_AIPTEK_10		0x0010
-#define USB_DEVICE_ID_AIPTEK_20		0x0020
-#define USB_DEVICE_ID_AIPTEK_21		0x0021
-#define USB_DEVICE_ID_AIPTEK_22		0x0022
-#define USB_DEVICE_ID_AIPTEK_23		0x0023
-#define USB_DEVICE_ID_AIPTEK_24		0x0024
-
-#define USB_VENDOR_ID_GRIFFIN		0x077d
-#define USB_DEVICE_ID_POWERMATE		0x0410
-#define USB_DEVICE_ID_SOUNDKNOB		0x04AA
-
-#define USB_VENDOR_ID_ATEN		0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM	0x2004
-#define USB_DEVICE_ID_ATEN_CS124U	0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC	0x2208
-
-#define USB_VENDOR_ID_TOPMAX		0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD	0x0103
-
-#define USB_VENDOR_ID_HAPP		0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING	0x0010
-#define USB_DEVICE_ID_UGCI_FLYING	0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING	0x0030
-
-#define USB_VENDOR_ID_MGE		0x0463
-#define USB_DEVICE_ID_MGE_UPS		0xffff
-#define USB_DEVICE_ID_MGE_UPS1		0x0001
-
-#define USB_VENDOR_ID_ONTRAK		0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_A4TECH		0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
-
-#define USB_VENDOR_ID_AASHIMA		0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR	0x0026
-
-#define USB_VENDOR_ID_CYPRESS		0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE	0x7417
-
-#define USB_VENDOR_ID_BERKSHIRE		0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD	0x1140
-
-#define USB_VENDOR_ID_ALPS		0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD	0x1101
-
-#define USB_VENDOR_ID_SAITEK		0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
-
-#define USB_VENDOR_ID_NEC		0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
-
-#define USB_VENDOR_ID_CHIC		0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
-
-#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_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
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_CODEMERCS		0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST	0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST	0x15ff
-
-#define USB_VENDOR_ID_DELORME		0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20	0x0200
-
-#define USB_VENDOR_ID_MCC		0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS	0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS	0x007a
-
-#define USB_VENDOR_ID_VERNIER		0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP	0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP	0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
-
-#define USB_VENDOR_ID_LD		0x0f11
-#define USB_DEVICE_ID_LD_CASSY		0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY	0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY	0x1020
-#define USB_DEVICE_ID_LD_JWM		0x1080
-#define USB_DEVICE_ID_LD_DMMP		0x1081
-#define USB_DEVICE_ID_LD_UMIP		0x1090
-#define USB_DEVICE_ID_LD_XRAY1		0x1100
-#define USB_DEVICE_ID_LD_XRAY2		0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM	0x1200
-#define USB_DEVICE_ID_LD_COM3LAB	0x2000
-#define USB_DEVICE_ID_LD_TELEPORT	0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL	0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST	0x2040
-
-#define USB_VENDOR_ID_APPLE		0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO	0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI	0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO	0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS	0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI	0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO	0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS	0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI	0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO	0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
-#define USB_DEVICE_ID_APPLE_IR		0x8240
-
-#define USB_VENDOR_ID_CHERRY		0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
-
-#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
-
-#define USB_VENDOR_ID_LOGITECH		0x046d
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER	0xc101
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2	0xc517
-#define USB_DEVICE_ID_DINOVO_EDGE	0xc714
-
-#define USB_VENDOR_ID_IMATION		0x0718
-#define USB_DEVICE_ID_DISC_STAKKA	0xd000
-
-#define USB_VENDOR_ID_PANTHERLORD	0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
-
-#define USB_VENDOR_ID_SONY			0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
-
-/*
- * Alphabetically sorted blacklist by quirk type.
- */
-
-static const struct hid_blacklist {
-	__u16 idVendor;
-	__u16 idProduct;
-	unsigned quirks;
-} hid_blacklist[] = {
-
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
-
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
-	{ 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_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
-	{ 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_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 },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
-	{ 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 },
-	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
-	{ 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 },
-	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
-	{ 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 },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
-	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
-	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
-	{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
-	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-
-	{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
-
-	{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
-	{ 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 },
-
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
-	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
-
-	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
-
-	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
-
-	{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
-
-	{ 0, 0 }
-};
-
-/*
- * Traverse the supplied list of reports and find the longest
- */
-static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
-{
-	struct hid_report *report;
-	int size;
-
-	list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
-		size = ((report->size - 1) >> 3) + 1;
-		if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
-			size++;
-		if (*max < size)
-			*max = size;
-	}
-}
-
-static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
-{
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
-		return -1;
-	if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
-		return -1;
-	if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
-		return -1;
-	if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
-		return -1;
-
-	return 0;
-}
-
-static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
-{
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	if (usbhid->inbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-	if (usbhid->outbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-	if (usbhid->cr)
-		usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-	if (usbhid->ctrlbuf)
-		usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
-}
-
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-
-static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
-	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
-		info("Fixing up Cherry Cymotion report descriptor");
-		rdesc[11] = rdesc[16] = 0xff;
-		rdesc[12] = rdesc[17] = 0x03;
-	}
-}
-
-/*
- * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
- * to "operational".  Without this, the ps3 controller will not report any
- * events.
- */
-static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
-{
-	int result;
-	char *buf = kmalloc(18, GFP_KERNEL);
-
-	if (!buf)
-		return;
-
-	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-				 HID_REQ_GET_REPORT,
-				 USB_DIR_IN | USB_TYPE_CLASS |
-				 USB_RECIP_INTERFACE,
-				 (3 << 8) | 0xf2, ifnum, buf, 17,
-				 USB_CTRL_GET_TIMEOUT);
-
-	if (result < 0)
-		err("%s failed: %d\n", __func__, result);
-
-	kfree(buf);
-}
-
-/*
- * Logitech S510 keyboard sends in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
-{
-	if (rsize >= 90 && rdesc[83] == 0x26
-			&& rdesc[84] == 0x8c
-			&& rdesc[85] == 0x02) {
-		info("Fixing up Logitech S510 report descriptor");
-		rdesc[84] = rdesc[89] = 0x4d;
-		rdesc[85] = rdesc[90] = 0x10;
-	}
-}
-
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
-{
-	struct usb_host_interface *interface = intf->cur_altsetting;
-	struct usb_device *dev = interface_to_usbdev (intf);
-	struct hid_descriptor *hdesc;
-	struct hid_device *hid;
-	unsigned quirks = 0, rsize = 0;
-	char *rdesc;
-	int n, len, insize = 0;
-	struct usbhid_device *usbhid;
-
-	/* Ignore all Wacom devices */
-	if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
-		return NULL;
-	/* ignore all Code Mercenaries IOWarrior devices */
-	if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS)
-		if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
-		    le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
-			return NULL;
-
-	for (n = 0; hid_blacklist[n].idVendor; n++)
-		if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
-			(hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
-				quirks = hid_blacklist[n].quirks;
-
-	/* Many keyboards and mice don't like to be polled for reports,
-	 * so we will always set the HID_QUIRK_NOGET flag for them. */
-	if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
-		if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD ||
-			interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
-				quirks |= HID_QUIRK_NOGET;
-	}
-
-	if (quirks & HID_QUIRK_IGNORE)
-		return NULL;
-
-	if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
-		(interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
-			return NULL;
-
-
-	if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
-	    (!interface->desc.bNumEndpoints ||
-	     usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
-		dbg("class descriptor not present\n");
-		return NULL;
-	}
-
-	for (n = 0; n < hdesc->bNumDescriptors; n++)
-		if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
-			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
-
-	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
-		dbg("weird size of report descriptor (%u)", rsize);
-		return NULL;
-	}
-
-	if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
-		dbg("couldn't allocate rdesc memory");
-		return NULL;
-	}
-
-	hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
-
-	if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
-		dbg("reading report descriptor failed");
-		kfree(rdesc);
-		return NULL;
-	}
-
-	if ((quirks & HID_QUIRK_CYMOTION))
-		hid_fixup_cymotion_descriptor(rdesc, rsize);
-
-	if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
-		hid_fixup_s510_descriptor(rdesc, rsize);
-
-#ifdef CONFIG_HID_DEBUG
-	printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
-	for (n = 0; n < rsize; n++)
-		printk(" %02x", (unsigned char) rdesc[n]);
-	printk("\n");
-#endif
-
-	if (!(hid = hid_parse_report(rdesc, n))) {
-		dbg("parsing report descriptor failed");
-		kfree(rdesc);
-		return NULL;
-	}
-
-	kfree(rdesc);
-	hid->quirks = quirks;
-
-	if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
-		goto fail;
-
-	hid->driver_data = usbhid;
-	usbhid->hid = hid;
-
-	usbhid->bufsize = HID_MIN_BUFFER_SIZE;
-	hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
-	hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
-	hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize);
-
-	if (usbhid->bufsize > HID_MAX_BUFFER_SIZE)
-		usbhid->bufsize = HID_MAX_BUFFER_SIZE;
-
-	hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
-
-	if (insize > HID_MAX_BUFFER_SIZE)
-		insize = HID_MAX_BUFFER_SIZE;
-
-	if (hid_alloc_buffers(dev, hid)) {
-		hid_free_buffers(dev, hid);
-		goto fail;
-	}
-
-	for (n = 0; n < interface->desc.bNumEndpoints; n++) {
-
-		struct usb_endpoint_descriptor *endpoint;
-		int pipe;
-		int interval;
-
-		endpoint = &interface->endpoint[n].desc;
-		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
-			continue;
-
-		interval = endpoint->bInterval;
-
-		/* Change the polling interval of mice. */
-		if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
-			interval = hid_mousepoll_interval;
-
-		if (usb_endpoint_dir_in(endpoint)) {
-			if (usbhid->urbin)
-				continue;
-			if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
-				goto fail;
-			pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-			usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize,
-					 hid_irq_in, hid, interval);
-			usbhid->urbin->transfer_dma = usbhid->inbuf_dma;
-			usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-		} else {
-			if (usbhid->urbout)
-				continue;
-			if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL)))
-				goto fail;
-			pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress);
-			usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0,
-					 hid_irq_out, hid, interval);
-			usbhid->urbout->transfer_dma = usbhid->outbuf_dma;
-			usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-		}
-	}
-
-	if (!usbhid->urbin) {
-		err("couldn't find an input interrupt endpoint");
-		goto fail;
-	}
-
-	init_waitqueue_head(&hid->wait);
-
-	INIT_WORK(&usbhid->reset_work, hid_reset);
-	setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
-
-	spin_lock_init(&usbhid->inlock);
-	spin_lock_init(&usbhid->outlock);
-	spin_lock_init(&usbhid->ctrllock);
-
-	hid->version = le16_to_cpu(hdesc->bcdHID);
-	hid->country = hdesc->bCountryCode;
-	hid->dev = &intf->dev;
-	usbhid->intf = intf;
-	usbhid->ifnum = interface->desc.bInterfaceNumber;
-
-	hid->name[0] = 0;
-
-	if (dev->manufacturer)
-		strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
-	if (dev->product) {
-		if (dev->manufacturer)
-			strlcat(hid->name, " ", sizeof(hid->name));
-		strlcat(hid->name, dev->product, sizeof(hid->name));
-	}
-
-	if (!strlen(hid->name))
-		snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
-
-	hid->bus = BUS_USB;
-	hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
-	hid->product = le16_to_cpu(dev->descriptor.idProduct);
-
-	usb_make_path(dev, hid->phys, sizeof(hid->phys));
-	strlcat(hid->phys, "/input", sizeof(hid->phys));
-	len = strlen(hid->phys);
-	if (len < sizeof(hid->phys) - 1)
-		snprintf(hid->phys + len, sizeof(hid->phys) - len,
-			 "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
-	if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
-		hid->uniq[0] = 0;
-
-	usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usbhid->urbctrl)
-		goto fail;
-
-	usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
-			     usbhid->ctrlbuf, 1, hid_ctrl, hid);
-	usbhid->urbctrl->setup_dma = usbhid->cr_dma;
-	usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
-	usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-	hid->hidinput_input_event = usb_hidinput_input_event;
-	hid->hid_open = usbhid_open;
-	hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
-	hid->hiddev_hid_event = hiddev_hid_event;
-	hid->hiddev_report_event = hiddev_report_event;
-#endif
-	return hid;
-
-fail:
-	usb_free_urb(usbhid->urbin);
-	usb_free_urb(usbhid->urbout);
-	usb_free_urb(usbhid->urbctrl);
-	hid_free_buffers(dev, hid);
-	hid_free_device(hid);
-
-	return NULL;
-}
-
-static void hid_disconnect(struct usb_interface *intf)
-{
-	struct hid_device *hid = usb_get_intfdata (intf);
-	struct usbhid_device *usbhid;
-
-	if (!hid)
-		return;
-
-	usbhid = hid->driver_data;
-
-	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
-	usb_set_intfdata(intf, NULL);
-	spin_unlock_irq(&usbhid->inlock);
-	usb_kill_urb(usbhid->urbin);
-	usb_kill_urb(usbhid->urbout);
-	usb_kill_urb(usbhid->urbctrl);
-
-	del_timer_sync(&usbhid->io_retry);
-	flush_scheduled_work();
-
-	if (hid->claimed & HID_CLAIMED_INPUT)
-		hidinput_disconnect(hid);
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
-		hiddev_disconnect(hid);
-
-	usb_free_urb(usbhid->urbin);
-	usb_free_urb(usbhid->urbctrl);
-	usb_free_urb(usbhid->urbout);
-
-	hid_free_buffers(hid_to_usb_dev(hid), hid);
-	hid_free_device(hid);
-}
-
-static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct hid_device *hid;
-	char path[64];
-	int i;
-	char *c;
-
-	dbg("HID probe called for ifnum %d",
-			intf->altsetting->desc.bInterfaceNumber);
-
-	if (!(hid = usb_hid_configure(intf)))
-		return -ENODEV;
-
-	usbhid_init_reports(hid);
-	hid_dump_device(hid);
-
-	if (!hidinput_connect(hid))
-		hid->claimed |= HID_CLAIMED_INPUT;
-	if (!hiddev_connect(hid))
-		hid->claimed |= HID_CLAIMED_HIDDEV;
-
-	usb_set_intfdata(intf, hid);
-
-	if (!hid->claimed) {
-		printk ("HID device not claimed by input or hiddev\n");
-		hid_disconnect(intf);
-		return -ENODEV;
-	}
-
-	if ((hid->claimed & HID_CLAIMED_INPUT))
-		hid_ff_init(hid);
-
-	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
-		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
-			intf->cur_altsetting->desc.bInterfaceNumber);
-
-	printk(KERN_INFO);
-
-	if (hid->claimed & HID_CLAIMED_INPUT)
-		printk("input");
-	if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
-		printk(",");
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
-		printk("hiddev%d", hid->minor);
-
-	c = "Device";
-	for (i = 0; i < hid->maxcollection; i++) {
-		if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
-		    (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
-		    (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
-			c = hid_types[hid->collection[i].usage & 0xffff];
-			break;
-		}
-	}
-
-	usb_make_path(interface_to_usbdev(intf), path, 63);
-
-	printk(": USB HID v%x.%02x %s [%s] on %s\n",
-		hid->version >> 8, hid->version & 0xff, c, hid->name, path);
-
-	return 0;
-}
-
-static int hid_suspend(struct usb_interface *intf, pm_message_t message)
-{
-	struct hid_device *hid = usb_get_intfdata (intf);
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	spin_lock_irq(&usbhid->inlock);	/* Sync with error handler */
-	set_bit(HID_SUSPENDED, &usbhid->iofl);
-	spin_unlock_irq(&usbhid->inlock);
-	del_timer(&usbhid->io_retry);
-	usb_kill_urb(usbhid->urbin);
-	dev_dbg(&intf->dev, "suspend\n");
-	return 0;
-}
-
-static int hid_resume(struct usb_interface *intf)
-{
-	struct hid_device *hid = usb_get_intfdata (intf);
-	struct usbhid_device *usbhid = hid->driver_data;
-	int status;
-
-	clear_bit(HID_SUSPENDED, &usbhid->iofl);
-	usbhid->retry_delay = 0;
-	status = hid_start_in(hid);
-	dev_dbg(&intf->dev, "resume status %d\n", status);
-	return status;
-}
-
-/* Treat USB reset pretty much the same as suspend/resume */
-static void hid_pre_reset(struct usb_interface *intf)
-{
-	/* FIXME: What if the interface is already suspended? */
-	hid_suspend(intf, PMSG_ON);
-}
-
-static void hid_post_reset(struct usb_interface *intf)
-{
-	struct usb_device *dev = interface_to_usbdev (intf);
-
-	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
-	/* FIXME: Any more reinitialization needed? */
-
-	hid_resume(intf);
-}
-
-static struct usb_device_id hid_usb_ids [] = {
-	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
-		.bInterfaceClass = USB_INTERFACE_CLASS_HID },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, hid_usb_ids);
-
-static struct usb_driver hid_driver = {
-	.name =		"usbhid",
-	.probe =	hid_probe,
-	.disconnect =	hid_disconnect,
-	.suspend =	hid_suspend,
-	.resume =	hid_resume,
-	.pre_reset =	hid_pre_reset,
-	.post_reset =	hid_post_reset,
-	.id_table =	hid_usb_ids,
-};
-
-static int __init hid_init(void)
-{
-	int retval;
-	retval = hiddev_init();
-	if (retval)
-		goto hiddev_init_fail;
-	retval = usb_register(&hid_driver);
-	if (retval)
-		goto usb_register_fail;
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-
-	return 0;
-usb_register_fail:
-	hiddev_exit();
-hiddev_init_fail:
-	return retval;
-}
-
-static void __exit hid_exit(void)
-{
-	usb_deregister(&hid_driver);
-	hiddev_exit();
-}
-
-module_init(hid_init);
-module_exit(hid_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
deleted file mode 100644
index e431faa..0000000
--- a/drivers/usb/input/hid-ff.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
- *
- *  Force feedback support for hid devices.
- *  Not all hid devices use the same protocol. For example, some use PID,
- *  other use their own proprietary procotol.
- *
- *  Copyright (c) 2002-2004 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 <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
-	u16 idVendor;
-	u16 idProduct;
-	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, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
-	{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
-	{ 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
-	{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
-	{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
-	{ 0x810, 0x0001, hid_plff_init },
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
-	{ 0x44f, 0xb304, hid_tmff_init },
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
-	{ 0xc12, 0x0005, hid_zpff_init },
-	{ 0xc12, 0x0030, hid_zpff_init },
-#endif
-	{ 0,	 0,	 hid_pidff_init}  /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
-	struct hid_ff_initializer *init;
-	int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
-	int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
-	for (init = inits; init->idVendor; init++)
-		if (init->idVendor == vendor && init->idProduct == product)
-			break;
-
-	return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
deleted file mode 100644
index e6f3af3..0000000
--- a/drivers/usb/input/hid-lgff.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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@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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct dev_type {
-	u16 idVendor;
-	u16 idProduct;
-	const signed short *ff;
-};
-
-static const signed short ff_rumble[] = {
-	FF_RUMBLE,
-	-1
-};
-
-static const signed short ff_joystick[] = {
-	FF_CONSTANT,
-	-1
-};
-
-static const struct dev_type devices[] = {
-	{ 0x046d, 0xc211, ff_rumble },
-	{ 0x046d, 0xc219, ff_rumble },
-	{ 0x046d, 0xc283, ff_joystick },
-	{ 0x046d, 0xc294, ff_joystick },
-	{ 0x046d, 0xc295, ff_joystick },
-	{ 0x046d, 0xca03, 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);
-		usbhid_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);
-		usbhid_submit_report(hid, report, USB_DIR_OUT);
-		break;
-	}
-	return 0;
-}
-
-int hid_lgff_init(struct hid_device* hid)
-{
-	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;
-	const signed short *ff_bits = ff_joystick;
-	int error;
-	int i;
-
-	/* Find the report to use */
-	if (list_empty(report_list)) {
-		err("No output report found");
-		return -1;
-	}
-
-	/* Check that the report looks ok */
-	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;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(devices); i++) {
-		if (dev->id.vendor == devices[i].idVendor &&
-		    dev->id.product == devices[i].idProduct) {
-			ff_bits = devices[i].ff;
-			break;
-		}
-	}
-
-	for (i = 0; ff_bits[i] >= 0; i++)
-		set_bit(ff_bits[i], dev->ffbit);
-
-	error = input_ff_create_memless(dev, NULL, hid_lgff_play);
-	if (error)
-		return error;
-
-	printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
-
-	return 0;
-}
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
deleted file mode 100644
index f5a90e9..0000000
--- a/drivers/usb/input/hid-pidff.c
+++ /dev/null
@@ -1,1331 +0,0 @@
-/*
- *  Force feedback driver for USB HID PID compliant devices
- *
- *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@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/input.h>
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-
-#include "usbhid.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]);
-
-	usbhid_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);
-
-	usbhid_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;
-
-	usbhid_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;
-
-	usbhid_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);
-		usbhid_wait_io(pidff->hid);
-		usbhid_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);
-	usbhid_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;
-	usbhid_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;
-	usbhid_wait_io(pidff->hid);
-
-	for (j = 0; j < 60; j++) {
-		debug("pid_block_load requested");
-		usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
-				  USB_DIR_IN);
-		usbhid_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;
-	}
-
-	usbhid_wait_io(pidff->hid);
-	usbhid_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;
-	usbhid_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);
-	usbhid_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;
-
-	usbhid_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 */
-	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-	usbhid_wait_io(hid);
-	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-	usbhid_wait_io(hid);
-
-	pidff->device_control->value[0] =
-		pidff->control_id[PID_ENABLE_ACTUATORS];
-	usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
-	usbhid_wait_io(hid);
-
-	/* pool report is sometimes messed up, refetch it */
-	usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
-	usbhid_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");
-			usbhid_submit_report(hid, pidff->reports[PID_POOL],
-					  USB_DIR_IN);
-			usbhid_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);
-		usbhid_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@gmail.com>\n");
-
-	return 0;
-
- fail:
-	kfree(pidff);
-	return error;
-}
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
deleted file mode 100644
index 76d2e6e..0000000
--- a/drivers/usb/input/hid-plff.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
- *
- *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@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-plff: " format "\n" , ## arg)
-
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
-
-struct plff_device {
-	struct hid_report *report;
-};
-
-static int hid_plff_play(struct input_dev *dev, void *data,
-			 struct ff_effect *effect)
-{
-	struct hid_device *hid = dev->private;
-	struct plff_device *plff = data;
-	int left, right;
-
-	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;
-
-	plff->report->field[0]->value[2] = left;
-	plff->report->field[0]->value[3] = right;
-	debug("running with 0x%02x 0x%02x", left, right);
-	usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-
-	return 0;
-}
-
-int hid_plff_init(struct hid_device *hid)
-{
-	struct plff_device *plff;
-	struct hid_report *report;
-	struct hid_input *hidinput;
-	struct list_head *report_list =
-			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct list_head *report_ptr = report_list;
-	struct input_dev *dev;
-	int error;
-
-	/* The device contains 2 output reports (one for each
-	   HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
-	   contains 4 ff00.0002 usages and 4 16bit absolute values.
-
-	   The 2 input reports also contain a field which contains
-	   8 ff00.0001 usages and 8 boolean values. Their meaning is
-	   currently unknown. */
-
-	if (list_empty(report_list)) {
-		printk(KERN_ERR "hid-plff: no output reports found\n");
-		return -ENODEV;
-	}
-
-	list_for_each_entry(hidinput, &hid->inputs, list) {
-
-		report_ptr = report_ptr->next;
-
-		if (report_ptr == report_list) {
-			printk(KERN_ERR "hid-plff: required output report is missing\n");
-			return -ENODEV;
-		}
-
-		report = list_entry(report_ptr, struct hid_report, list);
-		if (report->maxfield < 1) {
-			printk(KERN_ERR "hid-plff: no fields in the report\n");
-			return -ENODEV;
-		}
-
-		if (report->field[0]->report_count < 4) {
-			printk(KERN_ERR "hid-plff: not enough values in the field\n");
-			return -ENODEV;
-		}
-
-		plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
-		if (!plff)
-			return -ENOMEM;
-
-		dev = hidinput->input;
-
-		set_bit(FF_RUMBLE, dev->ffbit);
-
-		error = input_ff_create_memless(dev, plff, hid_plff_play);
-		if (error) {
-			kfree(plff);
-			return error;
-		}
-
-		plff->report = report;
-		plff->report->field[0]->value[0] = 0x00;
-		plff->report->field[0]->value[1] = 0x00;
-		plff->report->field[0]->value[2] = 0x00;
-		plff->report->field[0]->value[3] = 0x00;
-		usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
-	}
-
-	printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
-	       "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-	return 0;
-}
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
deleted file mode 100644
index ab67331..0000000
--- a/drivers/usb/input/hid-tmff.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Force feedback support for various HID compliant devices by ThrustMaster:
- *    ThrustMaster FireStorm Dual Power 2
- * and possibly others whose device ids haven't been added.
- *
- *  Modified to support ThrustMaster devices by Zinx Verituse
- *  on 2003-01-25 from the Logitech force feedback driver,
- *  which is by Johann Deneux.
- *
- *  Copyright (c) 2003 Zinx Verituse <zinx@epicsol.org>
- *  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
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR	(HID_UP_GENDESK | 0xbb)
-
-
-struct tmff_device {
-	struct hid_report *report;
-	struct hid_field *rumble;
-};
-
-/* 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 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 */
-
-	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);
-
-	tmff->rumble->value[0] = left;
-	tmff->rumble->value[1] = right;
-	dbg("(left,right)=(%08x, %08x)", left, right);
-	usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
-	return 0;
-}
-
-int hid_tmff_init(struct hid_device *hid)
-{
-	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;
-
-	tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
-	if (!tmff)
-		return -ENOMEM;
-
-	/* 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;
-		int fieldnum;
-
-		for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
-			struct hid_field *field = report->field[fieldnum];
-
-			if (field->maxusage <= 0)
-				continue;
-
-			switch (field->usage[0].hid) {
-				case THRUSTMASTER_USAGE_RUMBLE_LR:
-					if (field->report_count < 2) {
-						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
-						continue;
-					}
-
-					if (field->logical_maximum == field->logical_minimum) {
-						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
-						continue;
-					}
-
-					if (tmff->report && tmff->report != report) {
-						warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
-						continue;
-					}
-
-					if (tmff->rumble && tmff->rumble != field) {
-						warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
-						continue;
-					}
-
-					tmff->report = report;
-					tmff->rumble = field;
-
-					set_bit(FF_RUMBLE, input_dev->ffbit);
-					break;
-
-				default:
-					warn("ignoring unknown output usage %08x", field->usage[0].hid);
-					continue;
-			}
-		}
-	}
-
-	error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
-	if (error) {
-		kfree(tmff);
-		return error;
-	}
-
-	info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
-
-	return 0;
-}
-
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c
deleted file mode 100644
index 7bd8238..0000000
--- a/drivers/usb/input/hid-zpff.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- *  Force feedback support for Zeroplus based devices
- *
- *  Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@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 <linux/hid.h>
-#include "usbhid.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);
-	usbhid_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;
-	usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
-
-	printk(KERN_INFO "Force feedback for Zeroplus based devices by "
-	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
-
-	return 0;
-}
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
deleted file mode 100644
index a8b3d66..0000000
--- a/drivers/usb/input/hiddev.c
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- *  Copyright (c) 2001 Paul Stewart
- *  Copyright (c) 2001 Vojtech Pavlik
- *
- *  HID char devices, giving access to raw HID device events.
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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 Paul Stewart <stewart@wetlogic.net>
- */
-
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include "usbhid.h"
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define HIDDEV_MINOR_BASE	0
-#define HIDDEV_MINORS		256
-#else
-#define HIDDEV_MINOR_BASE	96
-#define HIDDEV_MINORS		16
-#endif
-#define HIDDEV_BUFFER_SIZE	64
-
-struct hiddev {
-	int exist;
-	int open;
-	wait_queue_head_t wait;
-	struct hid_device *hid;
-	struct list_head list;
-};
-
-struct hiddev_list {
-	struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
-	int head;
-	int tail;
-	unsigned flags;
-	struct fasync_struct *fasync;
-	struct hiddev *hiddev;
-	struct list_head node;
-};
-
-static struct hiddev *hiddev_table[HIDDEV_MINORS];
-
-/*
- * Find a report, given the report's type and ID.  The ID can be specified
- * indirectly by REPORT_ID_FIRST (which returns the first report of the given
- * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
- * given type which follows old_id.
- */
-static struct hid_report *
-hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
-{
-	unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
-	unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
-	struct hid_report_enum *report_enum;
-	struct hid_report *report;
-	struct list_head *list;
-
-	if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
-	    rinfo->report_type > HID_REPORT_TYPE_MAX)
-		return NULL;
-
-	report_enum = hid->report_enum +
-		(rinfo->report_type - HID_REPORT_TYPE_MIN);
-
-	switch (flags) {
-	case 0: /* Nothing to do -- report_id is already set correctly */
-		break;
-
-	case HID_REPORT_ID_FIRST:
-		if (list_empty(&report_enum->report_list))
-			return NULL;
-
-		list = report_enum->report_list.next;
-		report = list_entry(list, struct hid_report, list);
-		rinfo->report_id = report->id;
-		break;
-
-	case HID_REPORT_ID_NEXT:
-		report = report_enum->report_id_hash[rid];
-		if (!report)
-			return NULL;
-
-		list = report->list.next;
-		if (list == &report_enum->report_list)
-			return NULL;
-
-		report = list_entry(list, struct hid_report, list);
-		rinfo->report_id = report->id;
-		break;
-
-	default:
-		return NULL;
-	}
-
-	return report_enum->report_id_hash[rinfo->report_id];
-}
-
-/*
- * Perform an exhaustive search of the report table for a usage, given its
- * type and usage id.
- */
-static struct hid_field *
-hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
-{
-	int i, j;
-	struct hid_report *report;
-	struct hid_report_enum *report_enum;
-	struct hid_field *field;
-
-	if (uref->report_type < HID_REPORT_TYPE_MIN ||
-	    uref->report_type > HID_REPORT_TYPE_MAX)
-		return NULL;
-
-	report_enum = hid->report_enum +
-		(uref->report_type - HID_REPORT_TYPE_MIN);
-
-	list_for_each_entry(report, &report_enum->report_list, list) {
-		for (i = 0; i < report->maxfield; i++) {
-			field = report->field[i];
-			for (j = 0; j < field->maxusage; j++) {
-				if (field->usage[j].hid == uref->usage_code) {
-					uref->report_id = report->id;
-					uref->field_index = i;
-					uref->usage_index = j;
-					return field;
-				}
-			}
-		}
-	}
-
-	return NULL;
-}
-
-static void hiddev_send_event(struct hid_device *hid,
-			      struct hiddev_usage_ref *uref)
-{
-	struct hiddev *hiddev = hid->hiddev;
-	struct hiddev_list *list;
-
-	list_for_each_entry(list, &hiddev->list, node) {
-		if (uref->field_index != HID_FIELD_INDEX_NONE ||
-		    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
-			list->buffer[list->head] = *uref;
-			list->head = (list->head + 1) &
-				(HIDDEV_BUFFER_SIZE - 1);
-			kill_fasync(&list->fasync, SIGIO, POLL_IN);
-		}
-	}
-
-	wake_up_interruptible(&hiddev->wait);
-}
-
-/*
- * This is where hid.c calls into hiddev to pass an event that occurred over
- * the interrupt pipe
- */
-void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
-		      struct hid_usage *usage, __s32 value)
-{
-	unsigned type = field->report_type;
-	struct hiddev_usage_ref uref;
-
-	uref.report_type =
-	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
-	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
-	uref.report_id = field->report->id;
-	uref.field_index = field->index;
-	uref.usage_index = (usage - field->usage);
-	uref.usage_code = usage->hid;
-	uref.value = value;
-
-	hiddev_send_event(hid, &uref);
-}
-EXPORT_SYMBOL_GPL(hiddev_hid_event);
-
-void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
-{
-	unsigned type = report->type;
-	struct hiddev_usage_ref uref;
-
-	memset(&uref, 0, sizeof(uref));
-	uref.report_type =
-	  (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
-	  ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
-	   ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
-	uref.report_id = report->id;
-	uref.field_index = HID_FIELD_INDEX_NONE;
-
-	hiddev_send_event(hid, &uref);
-}
-
-/*
- * fasync file op
- */
-static int hiddev_fasync(int fd, struct file *file, int on)
-{
-	int retval;
-	struct hiddev_list *list = file->private_data;
-
-	retval = fasync_helper(fd, file, on, &list->fasync);
-
-	return retval < 0 ? retval : 0;
-}
-
-
-/*
- * release file op
- */
-static int hiddev_release(struct inode * inode, struct file * file)
-{
-	struct hiddev_list *list = file->private_data;
-
-	hiddev_fasync(-1, file, 0);
-	list_del(&list->node);
-
-	if (!--list->hiddev->open) {
-		if (list->hiddev->exist)
-			usbhid_close(list->hiddev->hid);
-		else
-			kfree(list->hiddev);
-	}
-
-	kfree(list);
-
-	return 0;
-}
-
-/*
- * open file op
- */
-static int hiddev_open(struct inode *inode, struct file *file)
-{
-	struct hiddev_list *list;
-
-	int i = iminor(inode) - HIDDEV_MINOR_BASE;
-
-	if (i >= HIDDEV_MINORS || !hiddev_table[i])
-		return -ENODEV;
-
-	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
-		return -ENOMEM;
-
-	list->hiddev = hiddev_table[i];
-	list_add_tail(&list->node, &hiddev_table[i]->list);
-	file->private_data = list;
-
-	if (!list->hiddev->open++)
-		if (list->hiddev->exist)
-			usbhid_open(hiddev_table[i]->hid);
-
-	return 0;
-}
-
-/*
- * "write" file op
- */
-static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-/*
- * "read" file op
- */
-static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	struct hiddev_list *list = file->private_data;
-	int event_size;
-	int retval = 0;
-
-	event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
-		sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
-
-	if (count < event_size)
-		return 0;
-
-	while (retval == 0) {
-		if (list->head == list->tail) {
-			add_wait_queue(&list->hiddev->wait, &wait);
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			while (list->head == list->tail) {
-				if (file->f_flags & O_NONBLOCK) {
-					retval = -EAGAIN;
-					break;
-				}
-				if (signal_pending(current)) {
-					retval = -ERESTARTSYS;
-					break;
-				}
-				if (!list->hiddev->exist) {
-					retval = -EIO;
-					break;
-				}
-
-				schedule();
-				set_current_state(TASK_INTERRUPTIBLE);
-			}
-
-			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&list->hiddev->wait, &wait);
-		}
-
-		if (retval)
-			return retval;
-
-
-		while (list->head != list->tail &&
-		       retval + event_size <= count) {
-			if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
-				if (list->buffer[list->tail].field_index !=
-				    HID_FIELD_INDEX_NONE) {
-					struct hiddev_event event;
-					event.hid = list->buffer[list->tail].usage_code;
-					event.value = list->buffer[list->tail].value;
-					if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event)))
-						return -EFAULT;
-					retval += sizeof(struct hiddev_event);
-				}
-			} else {
-				if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
-				    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
-					if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref)))
-						return -EFAULT;
-					retval += sizeof(struct hiddev_usage_ref);
-				}
-			}
-			list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
-		}
-
-	}
-
-	return retval;
-}
-
-/*
- * "poll" file op
- * No kernel lock - fine
- */
-static unsigned int hiddev_poll(struct file *file, poll_table *wait)
-{
-	struct hiddev_list *list = file->private_data;
-
-	poll_wait(file, &list->hiddev->wait, wait);
-	if (list->head != list->tail)
-		return POLLIN | POLLRDNORM;
-	if (!list->hiddev->exist)
-		return POLLERR | POLLHUP;
-	return 0;
-}
-
-/*
- * "ioctl" file op
- */
-static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct hiddev_list *list = file->private_data;
-	struct hiddev *hiddev = list->hiddev;
-	struct hid_device *hid = hiddev->hid;
-	struct usb_device *dev = hid_to_usb_dev(hid);
-	struct hiddev_collection_info cinfo;
-	struct hiddev_report_info rinfo;
-	struct hiddev_field_info finfo;
-	struct hiddev_usage_ref_multi *uref_multi = NULL;
-	struct hiddev_usage_ref *uref;
-	struct hiddev_devinfo dinfo;
-	struct hid_report *report;
-	struct hid_field *field;
-	struct usbhid_device *usbhid = hid->driver_data;
-	void __user *user_arg = (void __user *)arg;
-	int i;
-
-	if (!hiddev->exist)
-		return -EIO;
-
-	switch (cmd) {
-
-	case HIDIOCGVERSION:
-		return put_user(HID_VERSION, (int __user *)arg);
-
-	case HIDIOCAPPLICATION:
-		if (arg < 0 || arg >= hid->maxapplication)
-			return -EINVAL;
-
-		for (i = 0; i < hid->maxcollection; i++)
-			if (hid->collection[i].type ==
-			    HID_COLLECTION_APPLICATION && arg-- == 0)
-				break;
-
-		if (i == hid->maxcollection)
-			return -EINVAL;
-
-		return hid->collection[i].usage;
-
-	case HIDIOCGDEVINFO:
-		dinfo.bustype = BUS_USB;
-		dinfo.busnum = dev->bus->busnum;
-		dinfo.devnum = dev->devnum;
-		dinfo.ifnum = usbhid->ifnum;
-		dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
-		dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
-		dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
-		dinfo.num_applications = hid->maxapplication;
-		if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
-			return -EFAULT;
-
-		return 0;
-
-	case HIDIOCGFLAG:
-		if (put_user(list->flags, (int __user *)arg))
-			return -EFAULT;
-
-		return 0;
-
-	case HIDIOCSFLAG:
-		{
-			int newflags;
-			if (get_user(newflags, (int __user *)arg))
-				return -EFAULT;
-
-			if ((newflags & ~HIDDEV_FLAGS) != 0 ||
-			    ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
-			     (newflags & HIDDEV_FLAG_UREF) == 0))
-				return -EINVAL;
-
-			list->flags = newflags;
-
-			return 0;
-		}
-
-	case HIDIOCGSTRING:
-		{
-			int idx, len;
-			char *buf;
-
-			if (get_user(idx, (int __user *)arg))
-				return -EFAULT;
-
-			if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
-				return -ENOMEM;
-
-			if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
-				kfree(buf);
-				return -EINVAL;
-			}
-
-			if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
-				kfree(buf);
-				return -EFAULT;
-			}
-
-			kfree(buf);
-
-			return len;
-		}
-
-	case HIDIOCINITREPORT:
-		usbhid_init_reports(hid);
-
-		return 0;
-
-	case HIDIOCGREPORT:
-		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-			return -EFAULT;
-
-		if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
-			return -EINVAL;
-
-		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			return -EINVAL;
-
-		usbhid_submit_report(hid, report, USB_DIR_IN);
-		usbhid_wait_io(hid);
-
-		return 0;
-
-	case HIDIOCSREPORT:
-		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-			return -EFAULT;
-
-		if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
-			return -EINVAL;
-
-		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			return -EINVAL;
-
-		usbhid_submit_report(hid, report, USB_DIR_OUT);
-		usbhid_wait_io(hid);
-
-		return 0;
-
-	case HIDIOCGREPORTINFO:
-		if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
-			return -EFAULT;
-
-		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			return -EINVAL;
-
-		rinfo.num_fields = report->maxfield;
-
-		if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
-			return -EFAULT;
-
-		return 0;
-
-	case HIDIOCGFIELDINFO:
-		if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
-			return -EFAULT;
-		rinfo.report_type = finfo.report_type;
-		rinfo.report_id = finfo.report_id;
-		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			return -EINVAL;
-
-		if (finfo.field_index >= report->maxfield)
-			return -EINVAL;
-
-		field = report->field[finfo.field_index];
-		memset(&finfo, 0, sizeof(finfo));
-		finfo.report_type = rinfo.report_type;
-		finfo.report_id = rinfo.report_id;
-		finfo.field_index = field->report_count - 1;
-		finfo.maxusage = field->maxusage;
-		finfo.flags = field->flags;
-		finfo.physical = field->physical;
-		finfo.logical = field->logical;
-		finfo.application = field->application;
-		finfo.logical_minimum = field->logical_minimum;
-		finfo.logical_maximum = field->logical_maximum;
-		finfo.physical_minimum = field->physical_minimum;
-		finfo.physical_maximum = field->physical_maximum;
-		finfo.unit_exponent = field->unit_exponent;
-		finfo.unit = field->unit;
-
-		if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
-			return -EFAULT;
-
-		return 0;
-
-	case HIDIOCGUCODE:
-		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-		if (!uref_multi)
-			return -ENOMEM;
-		uref = &uref_multi->uref;
-		if (copy_from_user(uref, user_arg, sizeof(*uref)))
-			goto fault;
-
-		rinfo.report_type = uref->report_type;
-		rinfo.report_id = uref->report_id;
-		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-			goto inval;
-
-		if (uref->field_index >= report->maxfield)
-			goto inval;
-
-		field = report->field[uref->field_index];
-		if (uref->usage_index >= field->maxusage)
-			goto inval;
-
-		uref->usage_code = field->usage[uref->usage_index].hid;
-
-		if (copy_to_user(user_arg, uref, sizeof(*uref)))
-			goto fault;
-
-		kfree(uref_multi);
-		return 0;
-
-	case HIDIOCGUSAGE:
-	case HIDIOCSUSAGE:
-	case HIDIOCGUSAGES:
-	case HIDIOCSUSAGES:
-	case HIDIOCGCOLLECTIONINDEX:
-		uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-		if (!uref_multi)
-			return -ENOMEM;
-		uref = &uref_multi->uref;
-		if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-			if (copy_from_user(uref_multi, user_arg,
-					   sizeof(*uref_multi)))
-				goto fault;
-		} else {
-			if (copy_from_user(uref, user_arg, sizeof(*uref)))
-				goto fault;
-		}
-
-		if (cmd != HIDIOCGUSAGE &&
-		    cmd != HIDIOCGUSAGES &&
-		    uref->report_type == HID_REPORT_TYPE_INPUT)
-			goto inval;
-
-		if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
-			field = hiddev_lookup_usage(hid, uref);
-			if (field == NULL)
-				goto inval;
-		} else {
-			rinfo.report_type = uref->report_type;
-			rinfo.report_id = uref->report_id;
-			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-				goto inval;
-
-			if (uref->field_index >= report->maxfield)
-				goto inval;
-
-			field = report->field[uref->field_index];
-
-			if (cmd == HIDIOCGCOLLECTIONINDEX) {
-				if (uref->usage_index >= field->maxusage)
-					goto inval;
-			} else if (uref->usage_index >= field->report_count)
-				goto inval;
-
-			else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-				 (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
-				  uref->usage_index + uref_multi->num_values > field->report_count))
-				goto inval;
-			}
-
-		switch (cmd) {
-			case HIDIOCGUSAGE:
-				uref->value = field->value[uref->usage_index];
-				if (copy_to_user(user_arg, uref, sizeof(*uref)))
-					goto fault;
-				goto goodreturn;
-
-			case HIDIOCSUSAGE:
-				field->value[uref->usage_index] = uref->value;
-				goto goodreturn;
-
-			case HIDIOCGCOLLECTIONINDEX:
-				kfree(uref_multi);
-				return field->usage[uref->usage_index].collection_index;
-			case HIDIOCGUSAGES:
-				for (i = 0; i < uref_multi->num_values; i++)
-					uref_multi->values[i] =
-					    field->value[uref->usage_index + i];
-				if (copy_to_user(user_arg, uref_multi,
-						 sizeof(*uref_multi)))
-					goto fault;
-				goto goodreturn;
-			case HIDIOCSUSAGES:
-				for (i = 0; i < uref_multi->num_values; i++)
-					field->value[uref->usage_index + i] =
-					    uref_multi->values[i];
-				goto goodreturn;
-		}
-
-goodreturn:
-		kfree(uref_multi);
-		return 0;
-fault:
-		kfree(uref_multi);
-		return -EFAULT;
-inval:
-		kfree(uref_multi);
-		return -EINVAL;
-
-	case HIDIOCGCOLLECTIONINFO:
-		if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
-			return -EFAULT;
-
-		if (cinfo.index >= hid->maxcollection)
-			return -EINVAL;
-
-		cinfo.type = hid->collection[cinfo.index].type;
-		cinfo.usage = hid->collection[cinfo.index].usage;
-		cinfo.level = hid->collection[cinfo.index].level;
-
-		if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-	default:
-
-		if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
-			return -EINVAL;
-
-		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
-			int len;
-			if (!hid->name)
-				return 0;
-			len = strlen(hid->name) + 1;
-			if (len > _IOC_SIZE(cmd))
-				 len = _IOC_SIZE(cmd);
-			return copy_to_user(user_arg, hid->name, len) ?
-				-EFAULT : len;
-		}
-
-		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
-			int len;
-			if (!hid->phys)
-				return 0;
-			len = strlen(hid->phys) + 1;
-			if (len > _IOC_SIZE(cmd))
-				len = _IOC_SIZE(cmd);
-			return copy_to_user(user_arg, hid->phys, len) ?
-				-EFAULT : len;
-		}
-	}
-	return -EINVAL;
-}
-
-static const struct file_operations hiddev_fops = {
-	.owner =	THIS_MODULE,
-	.read =		hiddev_read,
-	.write =	hiddev_write,
-	.poll =		hiddev_poll,
-	.open =		hiddev_open,
-	.release =	hiddev_release,
-	.ioctl =	hiddev_ioctl,
-	.fasync =	hiddev_fasync,
-};
-
-static struct usb_class_driver hiddev_class = {
-	.name =		"hiddev%d",
-	.fops =		&hiddev_fops,
-	.minor_base =	HIDDEV_MINOR_BASE,
-};
-
-/*
- * This is where hid.c calls us to connect a hid device to the hiddev driver
- */
-int hiddev_connect(struct hid_device *hid)
-{
-	struct hiddev *hiddev;
-	struct usbhid_device *usbhid = hid->driver_data;
-	int i;
-	int retval;
-
-	for (i = 0; i < hid->maxcollection; i++)
-		if (hid->collection[i].type ==
-		    HID_COLLECTION_APPLICATION &&
-		    !IS_INPUT_APPLICATION(hid->collection[i].usage))
-			break;
-
-	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
-		return -1;
-
-	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
-		return -1;
-
-	retval = usb_register_dev(usbhid->intf, &hiddev_class);
-	if (retval) {
-		err("Not able to get a minor for this device.");
-		kfree(hiddev);
-		return -1;
-	}
-
-	init_waitqueue_head(&hiddev->wait);
-	INIT_LIST_HEAD(&hiddev->list);
-	hiddev->hid = hid;
-	hiddev->exist = 1;
-
-	hid->minor = usbhid->intf->minor;
-	hid->hiddev = hiddev;
-
-	hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
-
-	return 0;
-}
-
-/*
- * This is where hid.c calls us to disconnect a hiddev device from the
- * corresponding hid device (usually because the usb device has disconnected)
- */
-static struct usb_class_driver hiddev_class;
-void hiddev_disconnect(struct hid_device *hid)
-{
-	struct hiddev *hiddev = hid->hiddev;
-	struct usbhid_device *usbhid = hid->driver_data;
-
-	hiddev->exist = 0;
-
-	hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
-	usb_deregister_dev(usbhid->intf, &hiddev_class);
-
-	if (hiddev->open) {
-		usbhid_close(hiddev->hid);
-		wake_up_interruptible(&hiddev->wait);
-	} else {
-		kfree(hiddev);
-	}
-}
-
-/* Currently this driver is a USB driver.  It's not a conventional one in
- * the sense that it doesn't probe at the USB level.  Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines.  The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us.  This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
-			     const struct usb_device_id *hiddev_info)
-{
-	return -ENODEV;
-}
-
-
-static /* const */ struct usb_driver hiddev_driver = {
-	.name =		"hiddev",
-	.probe =	hiddev_usbd_probe,
-};
-
-int __init hiddev_init(void)
-{
-	return usb_register(&hiddev_driver);
-}
-
-void hiddev_exit(void)
-{
-	usb_deregister(&hiddev_driver);
-}
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
deleted file mode 100644
index aac968a..0000000
--- a/drivers/usb/input/itmtouch.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/******************************************************************************
- * itmtouch.c  --  Driver for ITM touchscreen panel
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
- *
- * Kudos to ITM for providing me with the datasheet for the panel,
- * even though it was a day later than I had finished writing this
- * driver.
- *
- * It has meant that I've been able to correct my interpretation of the
- * protocol packets however.
- *
- * CC -- 2003/9/29
- *
- * History
- * 1.0 & 1.1  2003 (CC) vojtech@suse.cz
- *   Original version for 2.4.x kernels
- *
- * 1.2  02/03/2005 (HCE) hc@mivu.no
- *   Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
- *   Unfortunately no calibration support at this time.
- *
- * 1.2.1  09/03/2005 (HCE) hc@mivu.no
- *   Code cleanup and adjusting syntax to start matching kernel standards
- * 
- * 1.2.2  10/05/2006 (MJA) massad@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>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-/* only an 8 byte buffer necessary for a single packet */
-#define ITM_BUFSIZE			8
-#define PATH_SIZE			64
-
-#define USB_VENDOR_ID_ITMINC		0x0403
-#define USB_PRODUCT_ID_TOUCHPANEL	0xf9e9
-
-#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
-#define DRIVER_VERSION "v1.2.2"
-#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE( DRIVER_LICENSE );
-
-struct itmtouch_dev {
-	struct usb_device	*usbdev; /* usb device */
-	struct input_dev	*inputdev; /* input device */
-	struct urb		*readurb; /* urb */
-	char			rbuf[ITM_BUFSIZE]; /* data */
-	int			users;
-	char name[128];
-	char phys[64];
-};
-
-static struct usb_device_id itmtouch_ids [] = {
-	{ USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
-	{ }
-};
-
-static void itmtouch_irq(struct urb *urb)
-{
-	struct itmtouch_dev *itmtouch = urb->context;
-	unsigned char *data = urb->transfer_buffer;
-	struct input_dev *dev = itmtouch->inputdev;
-	int retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ETIME:
-		/* this urb is timing out */
-		dbg("%s - urb timed out - was the device unplugged?",
-		    __FUNCTION__);
-		return;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	/* if pressure has been released, then don't report X/Y */
-	if (!(data[7] & 0x20)) {
-		input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
-		input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
-	}
-
-	input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
-	input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
-	input_sync(dev);
-
-exit:
-	retval = usb_submit_urb (urb, GFP_ATOMIC);
-	if (retval)
-		printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
-				__FUNCTION__, retval);
-}
-
-static int itmtouch_open(struct input_dev *input)
-{
-	struct itmtouch_dev *itmtouch = input->private;
-
-	itmtouch->readurb->dev = itmtouch->usbdev;
-
-	if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void itmtouch_close(struct input_dev *input)
-{
-	struct itmtouch_dev *itmtouch = input->private;
-
-	usb_kill_urb(itmtouch->readurb);
-}
-
-static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct itmtouch_dev *itmtouch;
-	struct input_dev *input_dev;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *udev = interface_to_usbdev(intf);
-	unsigned int pipe;
-	unsigned int maxp;
-
-	interface = intf->cur_altsetting;
-	endpoint = &interface->endpoint[0].desc;
-
-	itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!itmtouch || !input_dev) {
-		err("%s - Out of memory.", __FUNCTION__);
-		goto fail;
-	}
-
-	itmtouch->usbdev = udev;
-	itmtouch->inputdev = input_dev;
-
-	if (udev->manufacturer)
-		strlcpy(itmtouch->name, udev->manufacturer, sizeof(itmtouch->name));
-
-	if (udev->product) {
-		if (udev->manufacturer)
-			strlcat(itmtouch->name, " ", sizeof(itmtouch->name));
-		strlcat(itmtouch->name, udev->product, sizeof(itmtouch->name));
-	}
-
-	if (!strlen(itmtouch->name))
-		sprintf(itmtouch->name, "USB ITM touchscreen");
-
-	usb_make_path(udev, itmtouch->phys, sizeof(itmtouch->phys));
-	strlcpy(itmtouch->phys, "/input0", sizeof(itmtouch->phys));
-
-	input_dev->name = itmtouch->name;
-	input_dev->phys = itmtouch->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = itmtouch;
-
-	input_dev->open = itmtouch_open;
-	input_dev->close = itmtouch_close;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-
-	/* device limits */
-	/* as specified by the ITM datasheet, X and Y are 12bit,
-	 * Z (pressure) is 8 bit. However, the fields are defined up
-	 * to 14 bits for future possible expansion.
-	 */
-	input_set_abs_params(input_dev, ABS_X, 0, 0x0FFF, 2, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, 0x0FFF, 2, 0);
-	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFF, 2, 0);
-
-	/* initialise the URB so we can read from the transport stream */
-	pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-
-	if (maxp > ITM_BUFSIZE)
-		maxp = ITM_BUFSIZE;
-
-	itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!itmtouch->readurb) {
-		dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
-		goto fail;
-	}
-
-	usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
-			 maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
-
-	input_register_device(itmtouch->inputdev);
-
-	usb_set_intfdata(intf, itmtouch);
-
-	return 0;
-
- fail:	input_free_device(input_dev);
-	kfree(itmtouch);
-	return -ENOMEM;
-}
-
-static void itmtouch_disconnect(struct usb_interface *intf)
-{
-	struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-
-	if (itmtouch) {
-		input_unregister_device(itmtouch->inputdev);
-		usb_kill_urb(itmtouch->readurb);
-		usb_free_urb(itmtouch->readurb);
-		kfree(itmtouch);
-	}
-}
-
-MODULE_DEVICE_TABLE(usb, itmtouch_ids);
-
-static struct usb_driver itmtouch_driver = {
-	.name =         "itmtouch",
-	.probe =        itmtouch_probe,
-	.disconnect =   itmtouch_disconnect,
-	.id_table =     itmtouch_ids,
-};
-
-static int __init itmtouch_init(void)
-{
-	info(DRIVER_DESC " " DRIVER_VERSION);
-	info(DRIVER_AUTHOR);
-	return usb_register(&itmtouch_driver);
-}
-
-static void __exit itmtouch_exit(void)
-{
-	usb_deregister(&itmtouch_driver);
-}
-
-module_init(itmtouch_init);
-module_exit(itmtouch_exit);
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
deleted file mode 100644
index fedbcb1..0000000
--- a/drivers/usb/input/kbtab.c
+++ /dev/null
@@ -1,220 +0,0 @@
-#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
- * v0.0.1 - Original, extremely basic version, 2.4.xx only
- * v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
- *           - added pressure-threshold modules param code from
- *              Alex Perry <alex.perry@ieee.org>
- */
-
-#define DRIVER_VERSION "v0.0.2"
-#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
-#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_KBGEAR	0x084e
-
-static int kb_pressure_click = 0x10;
-module_param(kb_pressure_click, int, 0);
-MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks");
-
-struct kbtab {
-	signed char *data;
-	dma_addr_t data_dma;
-	struct input_dev *dev;
-	struct usb_device *usbdev;
-	struct urb *irq;
-	int x, y;
-	int button;
-	int pressure;
-	__u32 serial[2];
-	char phys[32];
-};
-
-static void kbtab_irq(struct urb *urb)
-{
-	struct kbtab *kbtab = urb->context;
-	unsigned char *data = kbtab->data;
-	struct input_dev *dev = kbtab->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;
-	}
-
-	kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
-	kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
-
-	kbtab->pressure = (data[5]);
-
-	input_report_key(dev, BTN_TOOL_PEN, 1);
-
-	input_report_abs(dev, ABS_X, kbtab->x);
-	input_report_abs(dev, ABS_Y, kbtab->y);
-
-	/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
-	input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
-
-	if (-1 == kb_pressure_click) {
-		input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
-	} else {
-		input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
-	};
-
-	input_sync(dev);
-
- exit:
-	retval = usb_submit_urb (urb, GFP_ATOMIC);
-	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, retval);
-}
-
-static struct usb_device_id kbtab_ids[] = {
-	{ USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, kbtab_ids);
-
-static int kbtab_open(struct input_dev *dev)
-{
-	struct kbtab *kbtab = dev->private;
-
-	kbtab->irq->dev = kbtab->usbdev;
-	if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void kbtab_close(struct input_dev *dev)
-{
-	struct kbtab *kbtab = dev->private;
-
-	usb_kill_urb(kbtab->irq);
-}
-
-static int kbtab_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 kbtab *kbtab;
-	struct input_dev *input_dev;
-
-	kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!kbtab || !input_dev)
-		goto fail1;
-
-	kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
-	if (!kbtab->data)
-		goto fail1;
-
-	kbtab->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!kbtab->irq)
-		goto fail2;
-
-	kbtab->usbdev = dev;
-	kbtab->dev = input_dev;
-
-	usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
-	strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys));
-
-	input_dev->name = "KB Gear Tablet";
-	input_dev->phys = kbtab->phys;
-	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = kbtab;
-
-	input_dev->open = kbtab_open;
-	input_dev->close = kbtab_close;
-
-	input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
-	input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-	input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
-	input_dev->mscbit[0] |= BIT(MSC_SERIAL);
-	input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
-	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
-
-	endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
-	usb_fill_int_urb(kbtab->irq, dev,
-			 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-			 kbtab->data, 8,
-			 kbtab_irq, kbtab, endpoint->bInterval);
-	kbtab->irq->transfer_dma = kbtab->data_dma;
-	kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	input_register_device(kbtab->dev);
-
-	usb_set_intfdata(intf, kbtab);
-	return 0;
-
-fail2:	usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
-fail1:	input_free_device(input_dev);
-	kfree(kbtab);
-	return -ENOMEM;
-}
-
-static void kbtab_disconnect(struct usb_interface *intf)
-{
-	struct kbtab *kbtab = usb_get_intfdata(intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (kbtab) {
-		usb_kill_urb(kbtab->irq);
-		input_unregister_device(kbtab->dev);
-		usb_free_urb(kbtab->irq);
-		usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
-		kfree(kbtab);
-	}
-}
-
-static struct usb_driver kbtab_driver = {
-	.name =		"kbtab",
-	.probe =	kbtab_probe,
-	.disconnect =	kbtab_disconnect,
-	.id_table =	kbtab_ids,
-};
-
-static int __init kbtab_init(void)
-{
-	int retval;
-	retval = usb_register(&kbtab_driver);
-	if (retval)
-		goto out;
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-out:
-	return retval;
-}
-
-static void __exit kbtab_exit(void)
-{
-	usb_deregister(&kbtab_driver);
-}
-
-module_init(kbtab_init);
-module_exit(kbtab_exit);
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
deleted file mode 100644
index 98bd323..0000000
--- a/drivers/usb/input/keyspan_remote.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * keyspan_remote: USB driver for the Keyspan DMR
- *
- * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.com)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- * This driver has been put together with the support of Innosys, Inc.
- * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/usb/input.h>
-
-#define DRIVER_VERSION	"v0.1"
-#define DRIVER_AUTHOR	"Michael Downey <downey@zymeta.com>"
-#define DRIVER_DESC	"Driver for the USB Keyspan remote control."
-#define DRIVER_LICENSE	"GPL"
-
-/* Parameters that can be passed to the driver. */
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
-
-/* Vendor and product ids */
-#define USB_KEYSPAN_VENDOR_ID		0x06CD
-#define USB_KEYSPAN_PRODUCT_UIA11	0x0202
-
-/* Defines for converting the data from the remote. */
-#define ZERO		0x18
-#define ZERO_MASK	0x1F	/* 5 bits for a 0 */
-#define ONE		0x3C
-#define ONE_MASK	0x3F	/* 6 bits for a 1 */
-#define SYNC		0x3F80
-#define SYNC_MASK	0x3FFF	/* 14 bits for a SYNC sequence */
-#define STOP		0x00
-#define STOP_MASK	0x1F	/* 5 bits for the STOP sequence */
-#define GAP		0xFF
-
-#define RECV_SIZE	8	/* The UIA-11 type have a 8 byte limit. */
-
-/* table of devices that work with this driver */
-static struct usb_device_id keyspan_table[] = {
-	{ USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
-	{ }					/* Terminating entry */
-};
-
-/* Structure to store all the real stuff that a remote sends to us. */
-struct keyspan_message {
-	u16	system;
-	u8	button;
-	u8	toggle;
-};
-
-/* Structure used for all the bit testing magic needed to be done. */
-struct bit_tester {
-	u32	tester;
-	int	len;
-	int	pos;
-	int	bits_left;
-	u8	buffer[32];
-};
-
-/* Structure to hold all of our driver specific stuff */
-struct usb_keyspan {
-	char				name[128];
-	char				phys[64];
-	struct usb_device*		udev;
-	struct input_dev		*input;
-	struct usb_interface*		interface;
-	struct usb_endpoint_descriptor* in_endpoint;
-	struct urb*			irq_urb;
-	int				open;
-	dma_addr_t			in_dma;
-	unsigned char*			in_buffer;
-
-	/* variables used to parse messages from remote. */
-	struct bit_tester		data;
-	int				stage;
-	int				toggle;
-};
-
-/*
- * Table that maps the 31 possible keycodes to input keys.
- * Currently there are 15 and 17 button models so RESERVED codes
- * are blank areas in the mapping.
- */
-static const int keyspan_key_table[] = {
-	KEY_RESERVED,		/* 0 is just a place holder. */
-	KEY_RESERVED,
-	KEY_STOP,
-	KEY_PLAYCD,
-	KEY_RESERVED,
-	KEY_PREVIOUSSONG,
-	KEY_REWIND,
-	KEY_FORWARD,
-	KEY_NEXTSONG,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_PAUSE,
-	KEY_VOLUMEUP,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_VOLUMEDOWN,
-	KEY_RESERVED,
-	KEY_UP,
-	KEY_RESERVED,
-	KEY_MUTE,
-	KEY_LEFT,
-	KEY_ENTER,
-	KEY_RIGHT,
-	KEY_RESERVED,
-	KEY_RESERVED,
-	KEY_DOWN,
-	KEY_RESERVED,
-	KEY_KPASTERISK,
-	KEY_RESERVED,
-	KEY_MENU
-};
-
-static struct usb_driver keyspan_driver;
-
-/*
- * Debug routine that prints out what we've received from the remote.
- */
-static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
-{
-	char codes[4 * RECV_SIZE];
-	int i;
-
-	for (i = 0; i < RECV_SIZE; i++)
-		snprintf(codes + i * 3, 4, "%02x ", dev->in_buffer[i]);
-
-	dev_info(&dev->udev->dev, "%s\n", codes);
-}
-
-/*
- * Routine that manages the bit_tester structure.  It makes sure that there are
- * at least bits_needed bits loaded into the tester.
- */
-static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
-{
-	if (dev->data.bits_left >= bits_needed)
-		return 0;
-
-	/*
-	 * Somehow we've missed the last message. The message will be repeated
-	 * though so it's not too big a deal
-	 */
-	if (dev->data.pos >= dev->data.len) {
-		dev_dbg(&dev->udev->dev,
-			"%s - Error ran out of data. pos: %d, len: %d\n",
-			__FUNCTION__, dev->data.pos, dev->data.len);
-		return -1;
-	}
-
-	/* Load as much as we can into the tester. */
-	while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
-	       (dev->data.pos < dev->data.len)) {
-		dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
-		dev->data.bits_left += 8;
-	}
-
-	return 0;
-}
-
-/*
- * Routine that handles all the logic needed to parse out the message from the remote.
- */
-static void keyspan_check_data(struct usb_keyspan *remote)
-{
-	int i;
-	int found = 0;
-	struct keyspan_message message;
-
-	switch(remote->stage) {
-	case 0:
-		/*
-		 * In stage 0 we want to find the start of a message.  The remote sends a 0xFF as filler.
-		 * So the first byte that isn't a FF should be the start of a new message.
-		 */
-		for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
-
-		if (i < RECV_SIZE) {
-			memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
-			remote->data.len = RECV_SIZE;
-			remote->data.pos = 0;
-			remote->data.tester = 0;
-			remote->data.bits_left = 0;
-			remote->stage = 1;
-		}
-		break;
-
-	case 1:
-		/*
-		 * Stage 1 we should have 16 bytes and should be able to detect a
-		 * SYNC.  The SYNC is 14 bits, 7 0's and then 7 1's.
-		 */
-		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
-		remote->data.len += RECV_SIZE;
-
-		found = 0;
-		while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
-			for (i = 0; i < 8; ++i) {
-				if (keyspan_load_tester(remote, 14) != 0) {
-					remote->stage = 0;
-					return;
-				}
-
-				if ((remote->data.tester & SYNC_MASK) == SYNC) {
-					remote->data.tester = remote->data.tester >> 14;
-					remote->data.bits_left -= 14;
-					found = 1;
-					break;
-				} else {
-					remote->data.tester = remote->data.tester >> 1;
-					--remote->data.bits_left;
-				}
-			}
-		}
-
-		if (!found) {
-			remote->stage = 0;
-			remote->data.len = 0;
-		} else {
-			remote->stage = 2;
-		}
-		break;
-
-	case 2:
-		/*
-		 * Stage 2 we should have 24 bytes which will be enough for a full
-		 * message.  We need to parse out the system code, button code,
-		 * toggle code, and stop.
-		 */
-		memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
-		remote->data.len += RECV_SIZE;
-
-		message.system = 0;
-		for (i = 0; i < 9; i++) {
-			keyspan_load_tester(remote, 6);
-
-			if ((remote->data.tester & ZERO_MASK) == ZERO) {
-				message.system = message.system << 1;
-				remote->data.tester = remote->data.tester >> 5;
-				remote->data.bits_left -= 5;
-			} else if ((remote->data.tester & ONE_MASK) == ONE) {
-				message.system = (message.system << 1) + 1;
-				remote->data.tester = remote->data.tester >> 6;
-				remote->data.bits_left -= 6;
-			} else {
-				err("%s - Unknown sequence found in system data.\n", __FUNCTION__);
-				remote->stage = 0;
-				return;
-			}
-		}
-
-		message.button = 0;
-		for (i = 0; i < 5; i++) {
-			keyspan_load_tester(remote, 6);
-
-			if ((remote->data.tester & ZERO_MASK) == ZERO) {
-				message.button = message.button << 1;
-				remote->data.tester = remote->data.tester >> 5;
-				remote->data.bits_left -= 5;
-			} else if ((remote->data.tester & ONE_MASK) == ONE) {
-				message.button = (message.button << 1) + 1;
-				remote->data.tester = remote->data.tester >> 6;
-				remote->data.bits_left -= 6;
-			} else {
-				err("%s - Unknown sequence found in button data.\n", __FUNCTION__);
-				remote->stage = 0;
-				return;
-			}
-		}
-
-		keyspan_load_tester(remote, 6);
-		if ((remote->data.tester & ZERO_MASK) == ZERO) {
-			message.toggle = 0;
-			remote->data.tester = remote->data.tester >> 5;
-			remote->data.bits_left -= 5;
-		} else if ((remote->data.tester & ONE_MASK) == ONE) {
-			message.toggle = 1;
-			remote->data.tester = remote->data.tester >> 6;
-			remote->data.bits_left -= 6;
-		} else {
-			err("%s - Error in message, invalid toggle.\n", __FUNCTION__);
-			remote->stage = 0;
-			return;
-		}
-
-		keyspan_load_tester(remote, 5);
-		if ((remote->data.tester & STOP_MASK) == STOP) {
-			remote->data.tester = remote->data.tester >> 5;
-			remote->data.bits_left -= 5;
-		} else {
-			err("Bad message recieved, no stop bit found.\n");
-		}
-
-		dev_dbg(&remote->udev->dev,
-			"%s found valid message: system: %d, button: %d, toggle: %d\n",
-			__FUNCTION__, message.system, message.button, message.toggle);
-
-		if (message.toggle != remote->toggle) {
-			input_report_key(remote->input, keyspan_key_table[message.button], 1);
-			input_report_key(remote->input, keyspan_key_table[message.button], 0);
-			input_sync(remote->input);
-			remote->toggle = message.toggle;
-		}
-
-		remote->stage = 0;
-		break;
-	}
-}
-
-/*
- * Routine for sending all the initialization messages to the remote.
- */
-static int keyspan_setup(struct usb_device* dev)
-{
-	int retval = 0;
-
-	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
-	if (retval) {
-		dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
-			__FUNCTION__, retval);
-		return(retval);
-	}
-
-	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
-	if (retval) {
-		dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
-			__FUNCTION__, retval);
-		return(retval);
-	}
-
-	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-				 0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
-	if (retval) {
-		dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
-			__FUNCTION__, retval);
-		return(retval);
-	}
-
-	dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__);
-	return(retval);
-}
-
-/*
- * Routine used to handle a new message that has come in.
- */
-static void keyspan_irq_recv(struct urb *urb)
-{
-	struct usb_keyspan *dev = urb->context;
-	int retval;
-
-	/* Check our status in case we need to bail out early. */
-	switch (urb->status) {
-	case 0:
-		break;
-
-	/* Device went away so don't keep trying to read from it. */
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		return;
-
-	default:
-		goto resubmit;
-		break;
-	}
-
-	if (debug)
-		keyspan_print(dev);
-
-	keyspan_check_data(dev);
-
-resubmit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval);
-}
-
-static int keyspan_open(struct input_dev *dev)
-{
-	struct usb_keyspan *remote = dev->private;
-
-	remote->irq_urb->dev = remote->udev;
-	if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void keyspan_close(struct input_dev *dev)
-{
-	struct usb_keyspan *remote = dev->private;
-
-	usb_kill_urb(remote->irq_urb);
-}
-
-static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
-{
-
-	struct usb_endpoint_descriptor *endpoint;
-	int i;
-
-	for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
-		endpoint = &iface->endpoint[i].desc;
-
-		if (usb_endpoint_is_int_in(endpoint)) {
-			/* we found our interrupt in endpoint */
-			return endpoint;
-		}
-	}
-
-	return NULL;
-}
-
-/*
- * Routine that sets up the driver to handle a specific USB device detected on the bus.
- */
-static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(interface);
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_keyspan *remote;
-	struct input_dev *input_dev;
-	int i, retval;
-
-	endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
-	if (!endpoint)
-		return -ENODEV;
-
-	remote = kzalloc(sizeof(*remote), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!remote || !input_dev) {
-		retval = -ENOMEM;
-		goto fail1;
-	}
-
-	remote->udev = udev;
-	remote->input = input_dev;
-	remote->interface = interface;
-	remote->in_endpoint = endpoint;
-	remote->toggle = -1;	/* Set to -1 so we will always not match the toggle from the first remote message. */
-
-	remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
-	if (!remote->in_buffer) {
-		retval = -ENOMEM;
-		goto fail1;
-	}
-
-	remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!remote->irq_urb) {
-		retval = -ENOMEM;
-		goto fail2;
-	}
-
-	retval = keyspan_setup(udev);
-	if (retval) {
-		retval = -ENODEV;
-		goto fail3;
-	}
-
-	if (udev->manufacturer)
-		strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
-
-	if (udev->product) {
-		if (udev->manufacturer)
-			strlcat(remote->name, " ", sizeof(remote->name));
-		strlcat(remote->name, udev->product, sizeof(remote->name));
-	}
-
-	if (!strlen(remote->name))
-		snprintf(remote->name, sizeof(remote->name),
-			 "USB Keyspan Remote %04x:%04x",
-			 le16_to_cpu(udev->descriptor.idVendor),
-			 le16_to_cpu(udev->descriptor.idProduct));
-
-	usb_make_path(udev, remote->phys, sizeof(remote->phys));
-	strlcat(remote->phys, "/input0", sizeof(remote->phys));
-
-	input_dev->name = remote->name;
-	input_dev->phys = remote->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &interface->dev;
-
-	input_dev->evbit[0] = BIT(EV_KEY);		/* We will only report KEY events. */
-	for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
-		if (keyspan_key_table[i] != KEY_RESERVED)
-			set_bit(keyspan_key_table[i], input_dev->keybit);
-
-	input_dev->private = remote;
-	input_dev->open = keyspan_open;
-	input_dev->close = keyspan_close;
-
-	/*
-	 * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
-	 */
-	usb_fill_int_urb(remote->irq_urb,
-			 remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
-			 remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
-			 remote->in_endpoint->bInterval);
-	remote->irq_urb->transfer_dma = remote->in_dma;
-	remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* we can register the device now, as it is ready */
-	input_register_device(remote->input);
-
-	/* save our data pointer in this interface device */
-	usb_set_intfdata(interface, remote);
-
-	return 0;
-
- fail3:	usb_free_urb(remote->irq_urb);
- fail2:	usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
- fail1:	kfree(remote);
-	input_free_device(input_dev);
-
-	return retval;
-}
-
-/*
- * Routine called when a device is disconnected from the USB.
- */
-static void keyspan_disconnect(struct usb_interface *interface)
-{
-	struct usb_keyspan *remote;
-
-	remote = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
-	if (remote) {	/* We have a valid driver structure so clean up everything we allocated. */
-		input_unregister_device(remote->input);
-		usb_kill_urb(remote->irq_urb);
-		usb_free_urb(remote->irq_urb);
-		usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
-		kfree(remote);
-	}
-}
-
-/*
- * Standard driver set up sections
- */
-static struct usb_driver keyspan_driver =
-{
-	.name =		"keyspan_remote",
-	.probe =	keyspan_probe,
-	.disconnect =	keyspan_disconnect,
-	.id_table =	keyspan_table
-};
-
-static int __init usb_keyspan_init(void)
-{
-	int result;
-
-	/* register this driver with the USB subsystem */
-	result = usb_register(&keyspan_driver);
-	if (result)
-		err("usb_register failed. Error number %d\n", result);
-
-	return result;
-}
-
-static void __exit usb_keyspan_exit(void)
-{
-	/* deregister this driver with the USB subsystem */
-	usb_deregister(&keyspan_driver);
-}
-
-module_init(usb_keyspan_init);
-module_exit(usb_keyspan_exit);
-
-MODULE_DEVICE_TABLE(usb, keyspan_table);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/usb/input/map_to_7segment.h
deleted file mode 100644
index a424094..0000000
--- a/drivers/usb/input/map_to_7segment.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * drivers/usb/input/map_to_7segment.h
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
- */
-
-#ifndef MAP_TO_7SEGMENT_H
-#define MAP_TO_7SEGMENT_H
-
-/* This file provides translation primitives and tables for the conversion
- * of (ASCII) characters to a 7-segments notation.
- *
- * The 7 segment's wikipedia notation below is used as standard.
- * See: http://en.wikipedia.org/wiki/Seven_segment_display
- *
- * Notation:	+-a-+
- *		f   b
- *		+-g-+
- *		e   c
- *		+-d-+
- *
- * Usage:
- *
- *   Register a map variable, and fill it with a character set:
- * 	static SEG7_DEFAULT_MAP(map_seg7);
- *
- *
- *   Then use for conversion:
- *	seg7 = map_to_seg7(&map_seg7, some_char);
- *	...
- *
- * In device drivers it is recommended, if required, to make the char map
- * accessible via the sysfs interface using the following scheme:
- *
- * static ssize_t show_map(struct device *dev, char *buf) {
- *	memcpy(buf, &map_seg7, sizeof(map_seg7));
- *	return sizeof(map_seg7);
- * }
- * static ssize_t store_map(struct device *dev, const char *buf, size_t cnt) {
- *	if(cnt != sizeof(map_seg7))
- *		return -EINVAL;
- *	memcpy(&map_seg7, buf, cnt);
- *	return cnt;
- * }
- * static DEVICE_ATTR(map_seg7, PERMS_RW, show_map, store_map);
- *
- * History:
- * 2005-05-31	RFC linux-kernel@vger.kernel.org
- */
-#include <linux/errno.h>
-
-
-#define BIT_SEG7_A		0
-#define BIT_SEG7_B		1
-#define BIT_SEG7_C		2
-#define BIT_SEG7_D		3
-#define BIT_SEG7_E		4
-#define BIT_SEG7_F		5
-#define BIT_SEG7_G		6
-#define BIT_SEG7_RESERVED	7
-
-struct seg7_conversion_map {
-	unsigned char	table[128];
-};
-
-static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
-{
-	return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
-}
-
-#define SEG7_CONVERSION_MAP(_name, _map)	\
-	struct seg7_conversion_map _name = { .table = { _map } }
-
-/*
- * It is recommended to use a facility that allows user space to redefine
- * custom character sets for LCD devices. Please use a sysfs interface
- * as described above.
- */
-#define MAP_TO_SEG7_SYSFS_FILE	"map_seg7"
-
-/*******************************************************************************
- * ASCII conversion table
- ******************************************************************************/
-
-#define _SEG7(l,a,b,c,d,e,f,g)	\
-      (	a<<BIT_SEG7_A |	b<<BIT_SEG7_B |	c<<BIT_SEG7_C |	d<<BIT_SEG7_D |	\
-	e<<BIT_SEG7_E |	f<<BIT_SEG7_F |	g<<BIT_SEG7_G )
-
-#define _MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-
-#define _MAP_33_47_ASCII_SEG7_SYMBOL		\
- _SEG7('!',0,0,0,0,1,1,0), _SEG7('"',0,1,0,0,0,1,0), _SEG7('#',0,1,1,0,1,1,0),\
- _SEG7('$',1,0,1,1,0,1,1), _SEG7('%',0,0,1,0,0,1,0), _SEG7('&',1,0,1,1,1,1,1),\
- _SEG7('\'',0,0,0,0,0,1,0),_SEG7('(',1,0,0,1,1,1,0), _SEG7(')',1,1,1,1,0,0,0),\
- _SEG7('*',0,1,1,0,1,1,1), _SEG7('+',0,1,1,0,0,0,1), _SEG7(',',0,0,0,0,1,0,0),\
- _SEG7('-',0,0,0,0,0,0,1), _SEG7('.',0,0,0,0,1,0,0), _SEG7('/',0,1,0,0,1,0,1),
-
-#define _MAP_48_57_ASCII_SEG7_NUMERIC		\
- _SEG7('0',1,1,1,1,1,1,0), _SEG7('1',0,1,1,0,0,0,0), _SEG7('2',1,1,0,1,1,0,1),\
- _SEG7('3',1,1,1,1,0,0,1), _SEG7('4',0,1,1,0,0,1,1), _SEG7('5',1,0,1,1,0,1,1),\
- _SEG7('6',1,0,1,1,1,1,1), _SEG7('7',1,1,1,0,0,0,0), _SEG7('8',1,1,1,1,1,1,1),\
- _SEG7('9',1,1,1,1,0,1,1),
-
-#define _MAP_58_64_ASCII_SEG7_SYMBOL		\
- _SEG7(':',0,0,0,1,0,0,1), _SEG7(';',0,0,0,1,0,0,1), _SEG7('<',1,0,0,0,0,1,1),\
- _SEG7('=',0,0,0,1,0,0,1), _SEG7('>',1,1,0,0,0,0,1), _SEG7('?',1,1,1,0,0,1,0),\
- _SEG7('@',1,1,0,1,1,1,1),
-
-#define _MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
- _SEG7('A',1,1,1,0,1,1,1), _SEG7('B',1,1,1,1,1,1,1), _SEG7('C',1,0,0,1,1,1,0),\
- _SEG7('D',1,1,1,1,1,1,0), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
- _SEG7('G',1,1,1,1,0,1,1), _SEG7('H',0,1,1,0,1,1,1), _SEG7('I',0,1,1,0,0,0,0),\
- _SEG7('J',0,1,1,1,0,0,0), _SEG7('K',0,1,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
- _SEG7('M',1,1,1,0,1,1,0), _SEG7('N',1,1,1,0,1,1,0), _SEG7('O',1,1,1,1,1,1,0),\
- _SEG7('P',1,1,0,0,1,1,1), _SEG7('Q',1,1,1,1,1,1,0), _SEG7('R',1,1,1,0,1,1,1),\
- _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('U',0,1,1,1,1,1,0),\
- _SEG7('V',0,1,1,1,1,1,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
- _SEG7('Y',0,1,1,0,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
-
-#define _MAP_91_96_ASCII_SEG7_SYMBOL		\
- _SEG7('[',1,0,0,1,1,1,0), _SEG7('\\',0,0,1,0,0,1,1),_SEG7(']',1,1,1,1,0,0,0),\
- _SEG7('^',1,1,0,0,0,1,0), _SEG7('_',0,0,0,1,0,0,0), _SEG7('`',0,1,0,0,0,0,0),
-
-#define _MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
- _SEG7('A',1,1,1,0,1,1,1), _SEG7('b',0,0,1,1,1,1,1), _SEG7('c',0,0,0,1,1,0,1),\
- _SEG7('d',0,1,1,1,1,0,1), _SEG7('E',1,0,0,1,1,1,1), _SEG7('F',1,0,0,0,1,1,1),\
- _SEG7('G',1,1,1,1,0,1,1), _SEG7('h',0,0,1,0,1,1,1), _SEG7('i',0,0,1,0,0,0,0),\
- _SEG7('j',0,0,1,1,0,0,0), _SEG7('k',0,0,1,0,1,1,1), _SEG7('L',0,0,0,1,1,1,0),\
- _SEG7('M',1,1,1,0,1,1,0), _SEG7('n',0,0,1,0,1,0,1), _SEG7('o',0,0,1,1,1,0,1),\
- _SEG7('P',1,1,0,0,1,1,1), _SEG7('q',1,1,1,0,0,1,1), _SEG7('r',0,0,0,0,1,0,1),\
- _SEG7('S',1,0,1,1,0,1,1), _SEG7('T',0,0,0,1,1,1,1), _SEG7('u',0,0,1,1,1,0,0),\
- _SEG7('v',0,0,1,1,1,0,0), _SEG7('W',0,1,1,1,1,1,1), _SEG7('X',0,1,1,0,1,1,1),\
- _SEG7('y',0,1,1,1,0,1,1), _SEG7('Z',1,1,0,1,1,0,1),
-
-#define _MAP_123_126_ASCII_SEG7_SYMBOL		\
- _SEG7('{',1,0,0,1,1,1,0), _SEG7('|',0,0,0,0,1,1,0), _SEG7('}',1,1,1,1,0,0,0),\
- _SEG7('~',1,0,0,0,0,0,0),
-
-/* Maps */
-
-/* This set tries to map as close as possible to the visible characteristics
- * of the ASCII symbol, lowercase and uppercase letters may differ in
- * presentation on the display.
- */
-#define MAP_ASCII7SEG_ALPHANUM			\
-	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
-	_MAP_33_47_ASCII_SEG7_SYMBOL		\
-	_MAP_48_57_ASCII_SEG7_NUMERIC		\
-	_MAP_58_64_ASCII_SEG7_SYMBOL		\
-	_MAP_65_90_ASCII_SEG7_ALPHA_UPPR	\
-	_MAP_91_96_ASCII_SEG7_SYMBOL		\
-	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
-	_MAP_123_126_ASCII_SEG7_SYMBOL
-
-/* This set tries to map as close as possible to the symbolic characteristics
- * of the ASCII character for maximum discrimination.
- * For now this means all alpha chars are in lower case representations.
- * (This for example facilitates the use of hex numbers with uppercase input.)
- */
-#define MAP_ASCII7SEG_ALPHANUM_LC			\
-	_MAP_0_32_ASCII_SEG7_NON_PRINTABLE	\
-	_MAP_33_47_ASCII_SEG7_SYMBOL		\
-	_MAP_48_57_ASCII_SEG7_NUMERIC		\
-	_MAP_58_64_ASCII_SEG7_SYMBOL		\
-	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
-	_MAP_91_96_ASCII_SEG7_SYMBOL		\
-	_MAP_97_122_ASCII_SEG7_ALPHA_LOWER	\
-	_MAP_123_126_ASCII_SEG7_SYMBOL
-
-#define SEG7_DEFAULT_MAP(_name)		\
-	SEG7_CONVERSION_MAP(_name,MAP_ASCII7SEG_ALPHANUM)
-
-#endif	/* MAP_TO_7SEGMENT_H */
-
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
deleted file mode 100644
index 92c4e07..0000000
--- a/drivers/usb/input/mtouchusb.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/******************************************************************************
- * mtouchusb.c  --  Driver for Microtouch (Now 3M) USB Touchscreens
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl)
- *  (http://freshmeat.net/projects/3mtouchscreendriver)
- *
- * History
- *
- *  0.3 & 0.4  2002 (TEJ) tejohnson@yahoo.com
- *    Updated to 2.4.18, then 2.4.19
- *    Old version still relied on stealing a minor
- *
- *  0.5  02/26/2004 (TEJ) tejohnson@yahoo.com
- *    Complete rewrite using Linux Input in 2.6.3
- *    Unfortunately no calibration support at this time
- *
- *  1.4 04/25/2004 (TEJ) tejohnson@yahoo.com
- *    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 successful tests with an EXII-5010UC
- *
- *  1.5 02/27/2005 ddstreet@ieee.org
- *    Added module parameter to select raw or hw-calibrated coordinate reporting
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-#define MTOUCHUSB_MIN_XC                0x0
-#define MTOUCHUSB_MAX_RAW_XC            0x4000
-#define MTOUCHUSB_MAX_CALIB_XC          0xffff
-#define MTOUCHUSB_XC_FUZZ               0x0
-#define MTOUCHUSB_XC_FLAT               0x0
-#define MTOUCHUSB_MIN_YC                0x0
-#define MTOUCHUSB_MAX_RAW_YC            0x4000
-#define MTOUCHUSB_MAX_CALIB_YC          0xffff
-#define MTOUCHUSB_YC_FUZZ               0x0
-#define MTOUCHUSB_YC_FLAT               0x0
-
-#define MTOUCHUSB_ASYNC_REPORT          1
-#define MTOUCHUSB_RESET                 7
-#define MTOUCHUSB_REPORT_DATA_SIZE      11
-#define MTOUCHUSB_REQ_CTRLLR_ID         10
-
-#define MTOUCHUSB_GET_RAW_XC(data)      (data[8]<<8 | data[7])
-#define MTOUCHUSB_GET_CALIB_XC(data)    (data[4]<<8 | data[3])
-#define MTOUCHUSB_GET_RAW_YC(data)      (data[10]<<8 | data[9])
-#define MTOUCHUSB_GET_CALIB_YC(data)    (data[6]<<8 | data[5])
-#define MTOUCHUSB_GET_XC(data)          (raw_coordinates ? \
-                                         MTOUCHUSB_GET_RAW_XC(data) : \
-                                         MTOUCHUSB_GET_CALIB_XC(data))
-#define MTOUCHUSB_GET_YC(data)          (raw_coordinates ? \
-                                         MTOUCHUSB_GET_RAW_YC(data) : \
-                                         MTOUCHUSB_GET_CALIB_YC(data))
-#define MTOUCHUSB_GET_TOUCHED(data)     ((data[2] & 0x40) ? 1:0)
-
-#define DRIVER_VERSION "v1.5"
-#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
-#define DRIVER_DESC "3M USB Touchscreen Driver"
-#define DRIVER_LICENSE "GPL"
-
-static int raw_coordinates = 1;
-
-module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
-
-struct mtouch_usb {
-	unsigned char *data;
-	dma_addr_t data_dma;
-	struct urb *irq;
-	struct usb_device *udev;
-	struct input_dev *input;
-	char name[128];
-	char phys[64];
-};
-
-static struct usb_device_id mtouchusb_devices[] = {
-	{ USB_DEVICE(0x0596, 0x0001) },
-	{ }
-};
-
-static void mtouchusb_irq(struct urb *urb)
-{
-	struct mtouch_usb *mtouch = urb->context;
-	int retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ETIME:
-		/* this urb is timing out */
-		dbg("%s - urb timed out - was the device unplugged?",
-		    __FUNCTION__);
-		return;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	input_report_key(mtouch->input, BTN_TOUCH,
-			 MTOUCHUSB_GET_TOUCHED(mtouch->data));
-	input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
-	input_report_abs(mtouch->input, ABS_Y,
-			 (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
-			 - MTOUCHUSB_GET_YC(mtouch->data));
-	input_sync(mtouch->input);
-
-exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		err("%s - usb_submit_urb failed with result: %d",
-		    __FUNCTION__, retval);
-}
-
-static int mtouchusb_open(struct input_dev *input)
-{
-	struct mtouch_usb *mtouch = input->private;
-
-	mtouch->irq->dev = mtouch->udev;
-
-	if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
-		return -EIO;
-
-	return 0;
-}
-
-static void mtouchusb_close(struct input_dev *input)
-{
-	struct mtouch_usb *mtouch = input->private;
-
-	usb_kill_urb(mtouch->irq);
-}
-
-static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
-{
-	dbg("%s - called", __FUNCTION__);
-
-	mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-					GFP_ATOMIC, &mtouch->data_dma);
-
-	if (!mtouch->data)
-		return -1;
-
-	return 0;
-}
-
-static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
-{
-	dbg("%s - called", __FUNCTION__);
-
-	if (mtouch->data)
-		usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
-				mtouch->data, mtouch->data_dma);
-}
-
-static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct mtouch_usb *mtouch;
-	struct input_dev *input_dev;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *udev = interface_to_usbdev(intf);
-	int nRet;
-
-	dbg("%s - called", __FUNCTION__);
-
-	dbg("%s - setting interface", __FUNCTION__);
-	interface = intf->cur_altsetting;
-
-	dbg("%s - setting endpoint", __FUNCTION__);
-	endpoint = &interface->endpoint[0].desc;
-
-	mtouch = kzalloc(sizeof(struct mtouch_usb), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!mtouch || !input_dev) {
-		err("%s - Out of memory.", __FUNCTION__);
-		goto fail1;
-	}
-
-	dbg("%s - allocating buffers", __FUNCTION__);
-	if (mtouchusb_alloc_buffers(udev, mtouch))
-		goto fail2;
-
-	mtouch->udev = udev;
-	mtouch->input = input_dev;
-
-	if (udev->manufacturer)
-		strlcpy(mtouch->name, udev->manufacturer, sizeof(mtouch->name));
-
-	if (udev->product) {
-		if (udev->manufacturer)
-			strlcat(mtouch->name, " ", sizeof(mtouch->name));
-		strlcat(mtouch->name, udev->product, sizeof(mtouch->name));
-	}
-
-	if (!strlen(mtouch->name))
-		snprintf(mtouch->name, sizeof(mtouch->name),
-			"USB Touchscreen %04x:%04x",
-			le16_to_cpu(udev->descriptor.idVendor),
-			le16_to_cpu(udev->descriptor.idProduct));
-
-	usb_make_path(udev, mtouch->phys, sizeof(mtouch->phys));
-	strlcpy(mtouch->phys, "/input0", sizeof(mtouch->phys));
-
-	input_dev->name = mtouch->name;
-	input_dev->phys = mtouch->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = mtouch;
-
-	input_dev->open = mtouchusb_open;
-	input_dev->close = mtouchusb_close;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_set_abs_params(input_dev, ABS_X, MTOUCHUSB_MIN_XC,
-		raw_coordinates ? MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC,
-				MTOUCHUSB_XC_FUZZ, MTOUCHUSB_XC_FLAT);
-	input_set_abs_params(input_dev, ABS_Y, MTOUCHUSB_MIN_YC,
-		raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC,
-		MTOUCHUSB_YC_FUZZ, MTOUCHUSB_YC_FLAT);
-
-	nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
-			       MTOUCHUSB_RESET,
-			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			       1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
-	    __FUNCTION__, nRet);
-
-	dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
-	mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!mtouch->irq) {
-		dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
-		goto fail2;
-	}
-
-	dbg("%s - usb_fill_int_urb", __FUNCTION__);
-	usb_fill_int_urb(mtouch->irq, mtouch->udev,
-			 usb_rcvintpipe(mtouch->udev, 0x81),
-			 mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
-			 mtouchusb_irq, mtouch, endpoint->bInterval);
-
-	dbg("%s - input_register_device", __FUNCTION__);
-	input_register_device(mtouch->input);
-
-	nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
-			       MTOUCHUSB_ASYNC_REPORT,
-			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			       1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
-	dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
-	    __FUNCTION__, nRet);
-
-	usb_set_intfdata(intf, mtouch);
-	return 0;
-
-fail2:	mtouchusb_free_buffers(udev, mtouch);
-fail1:	input_free_device(input_dev);
-	kfree(mtouch);
-	return -ENOMEM;
-}
-
-static void mtouchusb_disconnect(struct usb_interface *intf)
-{
-	struct mtouch_usb *mtouch = usb_get_intfdata(intf);
-
-	dbg("%s - called", __FUNCTION__);
-	usb_set_intfdata(intf, NULL);
-	if (mtouch) {
-		dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
-		usb_kill_urb(mtouch->irq);
-		input_unregister_device(mtouch->input);
-		usb_free_urb(mtouch->irq);
-		mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
-		kfree(mtouch);
-	}
-}
-
-MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
-
-static struct usb_driver mtouchusb_driver = {
-	.name		= "mtouchusb",
-	.probe		= mtouchusb_probe,
-	.disconnect	= mtouchusb_disconnect,
-	.id_table	= mtouchusb_devices,
-};
-
-static int __init mtouchusb_init(void)
-{
-	dbg("%s - called", __FUNCTION__);
-	return usb_register(&mtouchusb_driver);
-}
-
-static void __exit mtouchusb_cleanup(void)
-{
-	dbg("%s - called", __FUNCTION__);
-	usb_deregister(&mtouchusb_driver);
-}
-
-module_init(mtouchusb_init);
-module_exit(mtouchusb_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
deleted file mode 100644
index fea97e5..0000000
--- a/drivers/usb/input/powermate.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
- *
- * v1.1, (c)2002 William R Sowerbutts <will@sowerbutts.com>
- *
- * This device is a anodised aluminium knob which connects over USB. It can measure
- * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
- * a spring for automatic release. The base contains a pair of LEDs which illuminate
- * the translucent base. It rotates without limit and reports its relative rotation
- * back to the host when polled by the USB controller.
- *
- * Testing with the knob I have has shown that it measures approximately 94 "clicks"
- * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
- * a variable speed cordless electric drill) has shown that the device can measure
- * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
- * the host. If it counts more than 7 clicks before it is polled, it will wrap back
- * to zero and start counting again. This was at quite high speed, however, almost
- * certainly faster than the human hand could turn it. Griffin say that it loses a
- * pulse or two on a direction change; the granularity is so fine that I never
- * noticed this in practice.
- *
- * The device's microcontroller can be programmed to set the LED to either a constant
- * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
- *
- * Griffin were very happy to provide documentation and free hardware for development.
- *
- * Some userspace tools are available on the web: http://sowerbutts.com/powermate/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/usb/input.h>
-
-#define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
-#define POWERMATE_PRODUCT_NEW	0x0410	/* Griffin PowerMate */
-#define POWERMATE_PRODUCT_OLD	0x04AA	/* Griffin soundKnob */
-
-#define CONTOUR_VENDOR		0x05f3	/* Contour Design, Inc. */
-#define CONTOUR_JOG		0x0240	/* Jog and Shuttle */
-
-/* these are the command codes we send to the device */
-#define SET_STATIC_BRIGHTNESS  0x01
-#define SET_PULSE_ASLEEP       0x02
-#define SET_PULSE_AWAKE        0x03
-#define SET_PULSE_MODE         0x04
-
-/* these refer to bits in the powermate_device's requires_update field. */
-#define UPDATE_STATIC_BRIGHTNESS (1<<0)
-#define UPDATE_PULSE_ASLEEP      (1<<1)
-#define UPDATE_PULSE_AWAKE       (1<<2)
-#define UPDATE_PULSE_MODE        (1<<3)
-
-/* at least two versions of the hardware exist, with differing payload
-   sizes. the first three bytes always contain the "interesting" data in
-   the relevant format. */
-#define POWERMATE_PAYLOAD_SIZE_MAX 6
-#define POWERMATE_PAYLOAD_SIZE_MIN 3
-struct powermate_device {
-	signed char *data;
-	dma_addr_t data_dma;
-	struct urb *irq, *config;
-	struct usb_ctrlrequest *configcr;
-	dma_addr_t configcr_dma;
-	struct usb_device *udev;
-	struct input_dev *input;
-	spinlock_t lock;
-	int static_brightness;
-	int pulse_speed;
-	int pulse_table;
-	int pulse_asleep;
-	int pulse_awake;
-	int requires_update; // physical settings which are out of sync
-	char phys[64];
-};
-
-static char pm_name_powermate[] = "Griffin PowerMate";
-static char pm_name_soundknob[] = "Griffin SoundKnob";
-
-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 powermate_device *pm = urb->context;
-	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;
-	}
-
-	/* handle updates to device state */
-	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);
-
-exit:
-	retval = usb_submit_urb (urb, GFP_ATOMIC);
-	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, retval);
-}
-
-/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
-static void powermate_sync_state(struct powermate_device *pm)
-{
-	if (pm->requires_update == 0)
-		return; /* no updates are required */
-	if (pm->config->status == -EINPROGRESS)
-		return; /* an update is already in progress; it'll issue this update when it completes */
-
-	if (pm->requires_update & UPDATE_PULSE_ASLEEP){
-		pm->configcr->wValue = cpu_to_le16( SET_PULSE_ASLEEP );
-		pm->configcr->wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
-		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
-	}else if (pm->requires_update & UPDATE_PULSE_AWAKE){
-		pm->configcr->wValue = cpu_to_le16( SET_PULSE_AWAKE );
-		pm->configcr->wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
-		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
-	}else if (pm->requires_update & UPDATE_PULSE_MODE){
-		int op, arg;
-		/* the powermate takes an operation and an argument for its pulse algorithm.
-		   the operation can be:
-		   0: divide the speed
-		   1: pulse at normal speed
-		   2: multiply the speed
-		   the argument only has an effect for operations 0 and 2, and ranges between
-		   1 (least effect) to 255 (maximum effect).
-
-		   thus, several states are equivalent and are coalesced into one state.
-
-		   we map this onto a range from 0 to 510, with:
-		   0 -- 254    -- use divide (0 = slowest)
-		   255         -- use normal speed
-		   256 -- 510  -- use multiple (510 = fastest).
-
-		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
-		*/
-		if (pm->pulse_speed < 255) {
-			op = 0;                   // divide
-			arg = 255 - pm->pulse_speed;
-		} else if (pm->pulse_speed > 255) {
-			op = 2;                   // multiply
-			arg = pm->pulse_speed - 255;
-		} else {
-			op = 1;                   // normal speed
-			arg = 0;                  // can be any value
-		}
-		pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
-		pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op );
-		pm->requires_update &= ~UPDATE_PULSE_MODE;
-	} else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) {
-		pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
-		pm->configcr->wIndex = cpu_to_le16( pm->static_brightness );
-		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
-	} else {
-		printk(KERN_ERR "powermate: unknown update required");
-		pm->requires_update = 0; /* fudge the bug */
-		return;
-	}
-
-/*	printk("powermate: %04x %04x\n", pm->configcr->wValue, pm->configcr->wIndex); */
-
-	pm->configcr->bRequestType = 0x41; /* vendor request */
-	pm->configcr->bRequest = 0x01;
-	pm->configcr->wLength = 0;
-
-	usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0),
-			     (void *) pm->configcr, NULL, 0,
-			     powermate_config_complete, pm);
-	pm->config->setup_dma = pm->configcr_dma;
-	pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP;
-
-	if (usb_submit_urb(pm->config, GFP_ATOMIC))
-		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
-}
-
-/* Called when our asynchronous control message completes. We may need to issue another immediately */
-static void powermate_config_complete(struct urb *urb)
-{
-	struct powermate_device *pm = urb->context;
-	unsigned long flags;
-
-	if (urb->status)
-		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
-
-	spin_lock_irqsave(&pm->lock, flags);
-	powermate_sync_state(pm);
-	spin_unlock_irqrestore(&pm->lock, flags);
-}
-
-/* Set the LED up as described and begin the sync with the hardware if required */
-static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
-				int pulse_table, int pulse_asleep, int pulse_awake)
-{
-	unsigned long flags;
-
-	if (pulse_speed < 0)
-		pulse_speed = 0;
-	if (pulse_table < 0)
-		pulse_table = 0;
-	if (pulse_speed > 510)
-		pulse_speed = 510;
-	if (pulse_table > 2)
-		pulse_table = 2;
-
-	pulse_asleep = !!pulse_asleep;
-	pulse_awake = !!pulse_awake;
-
-
-	spin_lock_irqsave(&pm->lock, flags);
-
-	/* mark state updates which are required */
-	if (static_brightness != pm->static_brightness) {
-		pm->static_brightness = static_brightness;
-		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
-	}
-	if (pulse_asleep != pm->pulse_asleep) {
-		pm->pulse_asleep = pulse_asleep;
-		pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
-	}
-	if (pulse_awake != pm->pulse_awake) {
-		pm->pulse_awake = pulse_awake;
-		pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
-	}
-	if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) {
-		pm->pulse_speed = pulse_speed;
-		pm->pulse_table = pulse_table;
-		pm->requires_update |= UPDATE_PULSE_MODE;
-	}
-
-	powermate_sync_state(pm);
-
-	spin_unlock_irqrestore(&pm->lock, flags);
-}
-
-/* Callback from the Input layer when an event arrives from userspace to configure the LED */
-static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
-{
-	unsigned int command = (unsigned int)_value;
-	struct powermate_device *pm = dev->private;
-
-	if (type == EV_MSC && code == MSC_PULSELED){
-		/*
-		    bits  0- 7: 8 bits: LED brightness
-		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
-		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
-		    bit     19: 1 bit : pulse whilst asleep?
-		    bit     20: 1 bit : pulse constantly?
-		*/
-		int static_brightness = command & 0xFF;   // bits 0-7
-		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
-		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
-		int pulse_asleep = (command >> 19) & 0x1; // bit 19
-		int pulse_awake  = (command >> 20) & 0x1; // bit 20
-
-		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
-	}
-
-	return 0;
-}
-
-static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm)
-{
-	pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-				    GFP_ATOMIC, &pm->data_dma);
-	if (!pm->data)
-		return -1;
-
-	pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)),
-					GFP_ATOMIC, &pm->configcr_dma);
-	if (!pm->configcr)
-		return -1;
-
-	return 0;
-}
-
-static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
-{
-	if (pm->data)
-		usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
-				pm->data, pm->data_dma);
-	if (pm->configcr)
-		usb_buffer_free(udev, sizeof(*(pm->configcr)),
-				pm->configcr, pm->configcr_dma);
-}
-
-/* Called whenever a USB device matching one in our supported devices table is connected */
-static int powermate_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev (intf);
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct powermate_device *pm;
-	struct input_dev *input_dev;
-	int pipe, maxp;
-	int err = -ENOMEM;
-
-	interface = intf->cur_altsetting;
-	endpoint = &interface->endpoint[0].desc;
-	if (!usb_endpoint_is_int_in(endpoint))
-		return -EIO;
-
-	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-		0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		0, interface->desc.bInterfaceNumber, NULL, 0,
-		USB_CTRL_SET_TIMEOUT);
-
-	pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!pm || !input_dev)
-		goto fail1;
-
-	if (powermate_alloc_buffers(udev, pm))
-		goto fail2;
-
-	pm->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pm->irq)
-		goto fail2;
-
-	pm->config = usb_alloc_urb(0, GFP_KERNEL);
-	if (!pm->config)
-		goto fail3;
-
-	pm->udev = udev;
-	pm->input = input_dev;
-
-	usb_make_path(udev, pm->phys, sizeof(pm->phys));
-	strlcpy(pm->phys, "/input0", sizeof(pm->phys));
-
-	spin_lock_init(&pm->lock);
-
-	switch (le16_to_cpu(udev->descriptor.idProduct)) {
-	case POWERMATE_PRODUCT_NEW:
-		input_dev->name = pm_name_powermate;
-		break;
-	case POWERMATE_PRODUCT_OLD:
-		input_dev->name = pm_name_soundknob;
-		break;
-	default:
-		input_dev->name = pm_name_soundknob;
-		printk(KERN_WARNING "powermate: unknown product id %04x\n",
-		       le16_to_cpu(udev->descriptor.idProduct));
-	}
-
-	input_dev->phys = pm->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = pm;
-
-	input_dev->event = powermate_input_event;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
-	input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
-	input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
-	input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
-
-	/* get a handle to the interrupt data pipe */
-	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-
-	if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
-		printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
-			POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp);
-		maxp = POWERMATE_PAYLOAD_SIZE_MAX;
-	}
-
-	usb_fill_int_urb(pm->irq, udev, pipe, pm->data,
-			 maxp, powermate_irq,
-			 pm, endpoint->bInterval);
-	pm->irq->transfer_dma = pm->data_dma;
-	pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	/* register our interrupt URB with the USB system */
-	if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
-		err = -EIO;
-		goto fail4;
-	}
-
-	input_register_device(pm->input);
-
-	/* force an update of everything */
-	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
-	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
-
-	usb_set_intfdata(intf, pm);
-	return 0;
-
-fail4:	usb_free_urb(pm->config);
-fail3:	usb_free_urb(pm->irq);
-fail2:	powermate_free_buffers(udev, pm);
-fail1:	input_free_device(input_dev);
-	kfree(pm);
-	return err;
-}
-
-/* Called when a USB device we've accepted ownership of is removed */
-static void powermate_disconnect(struct usb_interface *intf)
-{
-	struct powermate_device *pm = usb_get_intfdata (intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (pm) {
-		pm->requires_update = 0;
-		usb_kill_urb(pm->irq);
-		input_unregister_device(pm->input);
-		usb_free_urb(pm->irq);
-		usb_free_urb(pm->config);
-		powermate_free_buffers(interface_to_usbdev(intf), pm);
-
-		kfree(pm);
-	}
-}
-
-static struct usb_device_id powermate_devices [] = {
-	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
-	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
-	{ USB_DEVICE(CONTOUR_VENDOR, CONTOUR_JOG) },
-	{ } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, powermate_devices);
-
-static struct usb_driver powermate_driver = {
-        .name =         "powermate",
-        .probe =        powermate_probe,
-        .disconnect =   powermate_disconnect,
-        .id_table =     powermate_devices,
-};
-
-static int __init powermate_init(void)
-{
-	return usb_register(&powermate_driver);
-}
-
-static void __exit powermate_cleanup(void)
-{
-	usb_deregister(&powermate_driver);
-}
-
-module_init(powermate_init);
-module_exit(powermate_cleanup);
-
-MODULE_AUTHOR( "William R Sowerbutts" );
-MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
deleted file mode 100644
index 2a314b0..0000000
--- a/drivers/usb/input/touchkitusb.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/******************************************************************************
- * touchkitusb.c  --  Driver for eGalax TouchKit USB Touchscreens
- *
- * Copyright (C) 2004-2005 by Daniel Ritz <daniel.ritz@gmx.ch>
- * Copyright (C) by Todd E. Johnson (mtouchusb.c)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Based upon mtouchusb.c
- *
- *****************************************************************************/
-
-//#define DEBUG
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-#define TOUCHKIT_MIN_XC			0x0
-#define TOUCHKIT_MAX_XC			0x07ff
-#define TOUCHKIT_XC_FUZZ		0x0
-#define TOUCHKIT_XC_FLAT		0x0
-#define TOUCHKIT_MIN_YC			0x0
-#define TOUCHKIT_MAX_YC			0x07ff
-#define TOUCHKIT_YC_FUZZ		0x0
-#define TOUCHKIT_YC_FLAT		0x0
-#define TOUCHKIT_REPORT_DATA_SIZE	16
-
-#define TOUCHKIT_DOWN			0x01
-
-#define TOUCHKIT_PKT_TYPE_MASK		0xFE
-#define TOUCHKIT_PKT_TYPE_REPT		0x80
-#define TOUCHKIT_PKT_TYPE_DIAG		0x0A
-
-#define DRIVER_VERSION			"v0.1"
-#define DRIVER_AUTHOR			"Daniel Ritz <daniel.ritz@gmx.ch>"
-#define DRIVER_DESC			"eGalax TouchKit USB HID Touchscreen Driver"
-
-static int swap_xy;
-module_param(swap_xy, bool, 0644);
-MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
-
-struct touchkit_usb {
-	unsigned char *data;
-	dma_addr_t data_dma;
-	char buffer[TOUCHKIT_REPORT_DATA_SIZE];
-	int buf_len;
-	struct urb *irq;
-	struct usb_device *udev;
-	struct input_dev *input;
-	char name[128];
-	char phys[64];
-};
-
-static struct usb_device_id touchkit_devices[] = {
-	{USB_DEVICE(0x3823, 0x0001)},
-	{USB_DEVICE(0x0123, 0x0001)},
-	{USB_DEVICE(0x0eef, 0x0001)},
-	{USB_DEVICE(0x0eef, 0x0002)},
-	{}
-};
-
-/* helpers to read the data */
-static inline int touchkit_get_touched(char *data)
-{
-	return (data[0] & TOUCHKIT_DOWN) ? 1 : 0;
-}
-
-static inline int touchkit_get_x(char *data)
-{
-	return ((data[3] & 0x0F) << 7) | (data[4] & 0x7F);
-}
-
-static inline int touchkit_get_y(char *data)
-{
-	return ((data[1] & 0x0F) << 7) | (data[2] & 0x7F);
-}
-
-
-/* processes one input packet. */
-static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt)
-{
-	int x, y;
-
-	/* only process report packets */
-	if ((pkt[0] & TOUCHKIT_PKT_TYPE_MASK) != TOUCHKIT_PKT_TYPE_REPT)
-		return;
-
-	if (swap_xy) {
-		y = touchkit_get_x(pkt);
-		x = touchkit_get_y(pkt);
-	} else {
-		x = touchkit_get_x(pkt);
-		y = touchkit_get_y(pkt);
-	}
-
-	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);
-	input_sync(touchkit->input);
-}
-
-
-static int touchkit_get_pkt_len(char *buf)
-{
-	switch (buf[0] & TOUCHKIT_PKT_TYPE_MASK) {
-	case TOUCHKIT_PKT_TYPE_REPT:
-		return 5;
-
-	case TOUCHKIT_PKT_TYPE_DIAG:
-		return buf[1] + 2;
-	}
-
-	return 0;
-}
-
-static void touchkit_process(struct touchkit_usb *touchkit, int len)
-{
-	char *buffer;
-	int pkt_len, buf_len, pos;
-
-	/* if the buffer contains data, append */
-	if (unlikely(touchkit->buf_len)) {
-		int tmp;
-
-		/* if only 1 byte in buffer, add another one to get length */
-		if (touchkit->buf_len == 1)
-			touchkit->buffer[1] = touchkit->data[0];
-
-		pkt_len = touchkit_get_pkt_len(touchkit->buffer);
-
-		/* unknown packet: drop everything */
-		if (!pkt_len)
-			return;
-
-		/* append, process */
-		tmp = pkt_len - touchkit->buf_len;
-		memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp);
-		touchkit_process_pkt(touchkit, touchkit->buffer);
-
-		buffer = touchkit->data + tmp;
-		buf_len = len - tmp;
-	} else {
-		buffer = touchkit->data;
-		buf_len = len;
-	}
-
-	/* only one byte left in buffer */
-	if (unlikely(buf_len == 1)) {
-		touchkit->buffer[0] = buffer[0];
-		touchkit->buf_len = 1;
-		return;
-	}
-
-	/* loop over the buffer */
-	pos = 0;
-	while (pos < buf_len) {
-		/* get packet len */
-		pkt_len = touchkit_get_pkt_len(buffer + pos);
-
-		/* unknown packet: drop everything */
-		if (unlikely(!pkt_len))
-			return;
-
-		/* full packet: process */
-		if (likely(pkt_len <= buf_len)) {
-			touchkit_process_pkt(touchkit, buffer + pos);
-		} else {
-			/* incomplete packet: save in buffer */
-			memcpy(touchkit->buffer, buffer + pos, buf_len - pos);
-			touchkit->buf_len = buf_len - pos;
-		}
-		pos += pkt_len;
-	}
-}
-
-
-static void touchkit_irq(struct urb *urb)
-{
-	struct touchkit_usb *touchkit = urb->context;
-	int retval;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ETIME:
-		/* this urb is timing out */
-		dbg("%s - urb timed out - was the device unplugged?",
-		    __FUNCTION__);
-		return;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	touchkit_process(touchkit, urb->actual_length);
-
-exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		err("%s - usb_submit_urb failed with result: %d",
-		    __FUNCTION__, retval);
-}
-
-static int touchkit_open(struct input_dev *input)
-{
-	struct touchkit_usb *touchkit = input->private;
-
-	touchkit->irq->dev = touchkit->udev;
-
-	if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
-		return -EIO;
-
-	return 0;
-}
-
-static void touchkit_close(struct input_dev *input)
-{
-	struct touchkit_usb *touchkit = input->private;
-
-	usb_kill_urb(touchkit->irq);
-}
-
-static int touchkit_alloc_buffers(struct usb_device *udev,
-				  struct touchkit_usb *touchkit)
-{
-	touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE,
-	                                  GFP_ATOMIC, &touchkit->data_dma);
-
-	if (!touchkit->data)
-		return -1;
-
-	return 0;
-}
-
-static void touchkit_free_buffers(struct usb_device *udev,
-				  struct touchkit_usb *touchkit)
-{
-	if (touchkit->data)
-		usb_buffer_free(udev, TOUCHKIT_REPORT_DATA_SIZE,
-		                touchkit->data, touchkit->data_dma);
-}
-
-static int touchkit_probe(struct usb_interface *intf,
-			  const struct usb_device_id *id)
-{
-	struct touchkit_usb *touchkit;
-	struct input_dev *input_dev;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	interface = intf->cur_altsetting;
-	endpoint = &interface->endpoint[0].desc;
-
-	touchkit = kzalloc(sizeof(struct touchkit_usb), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!touchkit || !input_dev)
-		goto out_free;
-
-	if (touchkit_alloc_buffers(udev, touchkit))
-		goto out_free;
-
-	touchkit->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!touchkit->irq) {
-		dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__);
-		goto out_free_buffers;
-	}
-
-	touchkit->udev = udev;
-	touchkit->input = input_dev;
-
-	if (udev->manufacturer)
-		strlcpy(touchkit->name, udev->manufacturer, sizeof(touchkit->name));
-
-	if (udev->product) {
-		if (udev->manufacturer)
-			strlcat(touchkit->name, " ", sizeof(touchkit->name));
-		strlcat(touchkit->name, udev->product, sizeof(touchkit->name));
-	}
-
-	if (!strlen(touchkit->name))
-		snprintf(touchkit->name, sizeof(touchkit->name),
-			"USB Touchscreen %04x:%04x",
-			 le16_to_cpu(udev->descriptor.idVendor),
-			 le16_to_cpu(udev->descriptor.idProduct));
-
-	usb_make_path(udev, touchkit->phys, sizeof(touchkit->phys));
-	strlcpy(touchkit->phys, "/input0", sizeof(touchkit->phys));
-
-	input_dev->name = touchkit->name;
-	input_dev->phys = touchkit->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = touchkit;
-	input_dev->open = touchkit_open;
-	input_dev->close = touchkit_close;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_set_abs_params(input_dev, ABS_X, TOUCHKIT_MIN_XC, TOUCHKIT_MAX_XC,
-				TOUCHKIT_XC_FUZZ, TOUCHKIT_XC_FLAT);
-	input_set_abs_params(input_dev, ABS_Y, TOUCHKIT_MIN_YC, TOUCHKIT_MAX_YC,
-				TOUCHKIT_YC_FUZZ, TOUCHKIT_YC_FLAT);
-
-	usb_fill_int_urb(touchkit->irq, touchkit->udev,
-			 usb_rcvintpipe(touchkit->udev, 0x81),
-			 touchkit->data, TOUCHKIT_REPORT_DATA_SIZE,
-			 touchkit_irq, touchkit, endpoint->bInterval);
-
-	touchkit->irq->transfer_dma = touchkit->data_dma;
-	touchkit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	input_register_device(touchkit->input);
-
-	usb_set_intfdata(intf, touchkit);
-	return 0;
-
-out_free_buffers:
-	touchkit_free_buffers(udev, touchkit);
-out_free:
-	input_free_device(input_dev);
-	kfree(touchkit);
-	return -ENOMEM;
-}
-
-static void touchkit_disconnect(struct usb_interface *intf)
-{
-	struct touchkit_usb *touchkit = usb_get_intfdata(intf);
-
-	dbg("%s - called", __FUNCTION__);
-
-	if (!touchkit)
-		return;
-
-	dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__);
-	usb_set_intfdata(intf, NULL);
-	usb_kill_urb(touchkit->irq);
-	input_unregister_device(touchkit->input);
-	usb_free_urb(touchkit->irq);
-	touchkit_free_buffers(interface_to_usbdev(intf), touchkit);
-	kfree(touchkit);
-}
-
-MODULE_DEVICE_TABLE(usb, touchkit_devices);
-
-static struct usb_driver touchkit_driver = {
-	.name		= "touchkitusb",
-	.probe		= touchkit_probe,
-	.disconnect	= touchkit_disconnect,
-	.id_table	= touchkit_devices,
-};
-
-static int __init touchkit_init(void)
-{
-	return usb_register(&touchkit_driver);
-}
-
-static void __exit touchkit_cleanup(void)
-{
-	usb_deregister(&touchkit_driver);
-}
-
-module_init(touchkit_init);
-module_exit(touchkit_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h
deleted file mode 100644
index 0023f96..0000000
--- a/drivers/usb/input/usbhid.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef __USBHID_H
-#define __USBHID_H
-
-/*
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2006 Jiri Kosina
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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/slab.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-
-/*  API provided by hid-core.c for USB HID drivers */
-int usbhid_wait_io(struct hid_device* hid);
-void usbhid_close(struct hid_device *hid);
-int usbhid_open(struct hid_device *hid);
-void usbhid_init_reports(struct hid_device *hid);
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
-
-/*
- * USB-specific HID struct, to be pointed to
- * from struct hid_device->driver_data
- */
-
-struct usbhid_device {
-	struct hid_device *hid;						/* pointer to corresponding HID dev */
-
-	struct usb_interface *intf;                                     /* USB interface */
-	int ifnum;                                                      /* USB interface number */
-
-	unsigned int bufsize;                                           /* URB buffer size */
-
-	struct urb *urbin;                                              /* Input URB */
-	char *inbuf;                                                    /* Input buffer */
-	dma_addr_t inbuf_dma;                                           /* Input buffer dma */
-	spinlock_t inlock;                                              /* Input fifo spinlock */
-
-	struct urb *urbctrl;                                            /* Control URB */
-	struct usb_ctrlrequest *cr;                                     /* Control request struct */
-	dma_addr_t cr_dma;                                              /* Control request struct dma */
-	struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE];  		/* Control fifo */
-	unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
-	char *ctrlbuf;                                                  /* Control buffer */
-	dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
-	spinlock_t ctrllock;                                            /* Control fifo spinlock */
-
-	struct urb *urbout;                                             /* Output URB */
-	struct hid_report *out[HID_CONTROL_FIFO_SIZE];                  /* Output pipe fifo */
-	unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
-	char *outbuf;                                                   /* Output buffer */
-	dma_addr_t outbuf_dma;                                          /* Output buffer dma */
-	spinlock_t outlock;                                             /* Output fifo spinlock */
-
-	unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
-	struct timer_list io_retry;                                     /* Retry timer */
-	unsigned long stop_retry;                                       /* Time to give up, in jiffies */
-	unsigned int retry_delay;                                       /* Delay length in ms */
-	struct work_struct reset_work;                                  /* Task context for resets */
-
-};
-
-#define	hid_to_usb_dev(hid_dev) \
-	container_of(hid_dev->dev->parent, struct usb_device, dev)
-
-#endif
-
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
deleted file mode 100644
index 3749f4a..0000000
--- a/drivers/usb/input/usbkbd.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  USB HIDBP Keyboard 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
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/hid.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION ""
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB HID Boot Protocol keyboard driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-static unsigned char usb_kbd_keycode[256] = {
-	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
-	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
-	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-	 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
-	191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
-	115,114,  0,  0,  0,121,  0, 89, 93,124, 92, 94, 95,  0,  0,  0,
-	122,123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-	150,158,159,128,136,177,178,176,142,152,173,140
-};
-
-struct usb_kbd {
-	struct input_dev *dev;
-	struct usb_device *usbdev;
-	unsigned char old[8];
-	struct urb *irq, *led;
-	unsigned char newleds;
-	char name[128];
-	char phys[64];
-
-	unsigned char *new;
-	struct usb_ctrlrequest *cr;
-	unsigned char *leds;
-	dma_addr_t cr_dma;
-	dma_addr_t new_dma;
-	dma_addr_t leds_dma;
-};
-
-static void usb_kbd_irq(struct urb *urb)
-{
-	struct usb_kbd *kbd = urb->context;
-	int i;
-
-	switch (urb->status) {
-	case 0:			/* success */
-		break;
-	case -ECONNRESET:	/* unlink */
-	case -ENOENT:
-	case -ESHUTDOWN:
-		return;
-	/* -EPIPE:  should clear the halt */
-	default:		/* error */
-		goto resubmit;
-	}
-
-	for (i = 0; i < 8; i++)
-		input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
-
-	for (i = 2; i < 8; i++) {
-
-		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
-			if (usb_kbd_keycode[kbd->old[i]])
-				input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
-			else
-				info("Unknown key (scancode %#x) released.", kbd->old[i]);
-		}
-
-		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
-			if (usb_kbd_keycode[kbd->new[i]])
-				input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
-			else
-				info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
-		}
-	}
-
-	input_sync(kbd->dev);
-
-	memcpy(kbd->old, kbd->new, 8);
-
-resubmit:
-	i = usb_submit_urb (urb, GFP_ATOMIC);
-	if (i)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
-				kbd->usbdev->bus->bus_name,
-				kbd->usbdev->devpath, i);
-}
-
-static int usb_kbd_event(struct input_dev *dev, unsigned int type,
-			 unsigned int code, int value)
-{
-	struct usb_kbd *kbd = dev->private;
-
-	if (type != EV_LED)
-		return -1;
-
-
-	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
-		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
-		       (!!test_bit(LED_NUML,    dev->led));
-
-	if (kbd->led->status == -EINPROGRESS)
-		return 0;
-
-	if (*(kbd->leds) == kbd->newleds)
-		return 0;
-
-	*(kbd->leds) = kbd->newleds;
-	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-		err("usb_submit_urb(leds) failed");
-
-	return 0;
-}
-
-static void usb_kbd_led(struct urb *urb)
-{
-	struct usb_kbd *kbd = urb->context;
-
-	if (urb->status)
-		warn("led urb status %d received", urb->status);
-
-	if (*(kbd->leds) == kbd->newleds)
-		return;
-
-	*(kbd->leds) = kbd->newleds;
-	kbd->led->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->led, GFP_ATOMIC))
-		err("usb_submit_urb(leds) failed");
-}
-
-static int usb_kbd_open(struct input_dev *dev)
-{
-	struct usb_kbd *kbd = dev->private;
-
-	kbd->irq->dev = kbd->usbdev;
-	if (usb_submit_urb(kbd->irq, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void usb_kbd_close(struct input_dev *dev)
-{
-	struct usb_kbd *kbd = dev->private;
-
-	usb_kill_urb(kbd->irq);
-}
-
-static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
-{
-	if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
-		return -1;
-	if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
-		return -1;
-	if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
-		return -1;
-	if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
-		return -1;
-	if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
-		return -1;
-
-	return 0;
-}
-
-static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
-{
-	usb_free_urb(kbd->irq);
-	usb_free_urb(kbd->led);
-	if (kbd->new)
-		usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
-	if (kbd->cr)
-		usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
-	if (kbd->leds)
-		usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
-}
-
-static int usb_kbd_probe(struct usb_interface *iface,
-			 const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev(iface);
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_kbd *kbd;
-	struct input_dev *input_dev;
-	int i, pipe, maxp;
-
-	interface = iface->cur_altsetting;
-
-	if (interface->desc.bNumEndpoints != 1)
-		return -ENODEV;
-
-	endpoint = &interface->endpoint[0].desc;
-	if (!usb_endpoint_is_int_in(endpoint))
-		return -ENODEV;
-
-	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-	kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!kbd || !input_dev)
-		goto fail1;
-
-	if (usb_kbd_alloc_mem(dev, kbd))
-		goto fail2;
-
-	kbd->usbdev = dev;
-	kbd->dev = input_dev;
-
-	if (dev->manufacturer)
-		strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
-
-	if (dev->product) {
-		if (dev->manufacturer)
-			strlcat(kbd->name, " ", sizeof(kbd->name));
-		strlcat(kbd->name, dev->product, sizeof(kbd->name));
-	}
-
-	if (!strlen(kbd->name))
-		snprintf(kbd->name, sizeof(kbd->name),
-			 "USB HIDBP Keyboard %04x:%04x",
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
-
-	usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
-	strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
-
-	input_dev->name = kbd->name;
-	input_dev->phys = kbd->phys;
-	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &iface->dev;
-	input_dev->private = kbd;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
-	input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
-
-	for (i = 0; i < 255; i++)
-		set_bit(usb_kbd_keycode[i], input_dev->keybit);
-	clear_bit(0, input_dev->keybit);
-
-	input_dev->event = usb_kbd_event;
-	input_dev->open = usb_kbd_open;
-	input_dev->close = usb_kbd_close;
-
-	usb_fill_int_urb(kbd->irq, dev, pipe,
-			 kbd->new, (maxp > 8 ? 8 : maxp),
-			 usb_kbd_irq, kbd, endpoint->bInterval);
-	kbd->irq->transfer_dma = kbd->new_dma;
-	kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-	kbd->cr->bRequest = 0x09;
-	kbd->cr->wValue = cpu_to_le16(0x200);
-	kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
-	kbd->cr->wLength = cpu_to_le16(1);
-
-	usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
-			     (void *) kbd->cr, kbd->leds, 1,
-			     usb_kbd_led, kbd);
-	kbd->led->setup_dma = kbd->cr_dma;
-	kbd->led->transfer_dma = kbd->leds_dma;
-	kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
-
-	input_register_device(kbd->dev);
-
-	usb_set_intfdata(iface, kbd);
-	return 0;
-
-fail2:	usb_kbd_free_mem(dev, kbd);
-fail1:	input_free_device(input_dev);
-	kfree(kbd);
-	return -ENOMEM;
-}
-
-static void usb_kbd_disconnect(struct usb_interface *intf)
-{
-	struct usb_kbd *kbd = usb_get_intfdata (intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (kbd) {
-		usb_kill_urb(kbd->irq);
-		input_unregister_device(kbd->dev);
-		usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
-		kfree(kbd);
-	}
-}
-
-static struct usb_device_id usb_kbd_id_table [] = {
-	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-		USB_INTERFACE_PROTOCOL_KEYBOARD) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
-
-static struct usb_driver usb_kbd_driver = {
-	.name =		"usbkbd",
-	.probe =	usb_kbd_probe,
-	.disconnect =	usb_kbd_disconnect,
-	.id_table =	usb_kbd_id_table,
-};
-
-static int __init usb_kbd_init(void)
-{
-	int result = usb_register(&usb_kbd_driver);
-	if (result == 0)
-		info(DRIVER_VERSION ":" DRIVER_DESC);
-	return result;
-}
-
-static void __exit usb_kbd_exit(void)
-{
-	usb_deregister(&usb_kbd_driver);
-}
-
-module_init(usb_kbd_init);
-module_exit(usb_kbd_exit);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
deleted file mode 100644
index 692fd60..0000000
--- a/drivers/usb/input/usbmouse.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  USB HIDBP Mouse 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
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/hid.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.6"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB HID Boot Protocol mouse driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-struct usb_mouse {
-	char name[128];
-	char phys[64];
-	struct usb_device *usbdev;
-	struct input_dev *dev;
-	struct urb *irq;
-
-	signed char *data;
-	dma_addr_t data_dma;
-};
-
-static void usb_mouse_irq(struct urb *urb)
-{
-	struct usb_mouse *mouse = urb->context;
-	signed char *data = mouse->data;
-	struct input_dev *dev = mouse->dev;
-	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;
-	}
-
-	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);
-	input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
-	input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
-
-	input_report_rel(dev, REL_X,     data[1]);
-	input_report_rel(dev, REL_Y,     data[2]);
-	input_report_rel(dev, REL_WHEEL, data[3]);
-
-	input_sync(dev);
-resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
-				mouse->usbdev->bus->bus_name,
-				mouse->usbdev->devpath, status);
-}
-
-static int usb_mouse_open(struct input_dev *dev)
-{
-	struct usb_mouse *mouse = dev->private;
-
-	mouse->irq->dev = mouse->usbdev;
-	if (usb_submit_urb(mouse->irq, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void usb_mouse_close(struct input_dev *dev)
-{
-	struct usb_mouse *mouse = dev->private;
-
-	usb_kill_urb(mouse->irq);
-}
-
-static int usb_mouse_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 usb_mouse *mouse;
-	struct input_dev *input_dev;
-	int pipe, maxp;
-
-	interface = intf->cur_altsetting;
-
-	if (interface->desc.bNumEndpoints != 1)
-		return -ENODEV;
-
-	endpoint = &interface->endpoint[0].desc;
-	if (!usb_endpoint_is_int_in(endpoint))
-		return -ENODEV;
-
-	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-	mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!mouse || !input_dev)
-		goto fail1;
-
-	mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
-	if (!mouse->data)
-		goto fail1;
-
-	mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!mouse->irq)
-		goto fail2;
-
-	mouse->usbdev = dev;
-	mouse->dev = input_dev;
-
-	if (dev->manufacturer)
-		strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));
-
-	if (dev->product) {
-		if (dev->manufacturer)
-			strlcat(mouse->name, " ", sizeof(mouse->name));
-		strlcat(mouse->name, dev->product, sizeof(mouse->name));
-	}
-
-	if (!strlen(mouse->name))
-		snprintf(mouse->name, sizeof(mouse->name),
-			 "USB HIDBP Mouse %04x:%04x",
-			 le16_to_cpu(dev->descriptor.idVendor),
-			 le16_to_cpu(dev->descriptor.idProduct));
-
-	usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
-	strlcat(mouse->phys, "/input0", sizeof(mouse->phys));
-
-	input_dev->name = mouse->name;
-	input_dev->phys = mouse->phys;
-	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
-	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-	input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-	input_dev->relbit[0] |= BIT(REL_WHEEL);
-
-	input_dev->private = mouse;
-	input_dev->open = usb_mouse_open;
-	input_dev->close = usb_mouse_close;
-
-	usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
-			 (maxp > 8 ? 8 : maxp),
-			 usb_mouse_irq, mouse, endpoint->bInterval);
-	mouse->irq->transfer_dma = mouse->data_dma;
-	mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	input_register_device(mouse->dev);
-
-	usb_set_intfdata(intf, mouse);
-	return 0;
-
-fail2:	usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
-fail1:	input_free_device(input_dev);
-	kfree(mouse);
-	return -ENOMEM;
-}
-
-static void usb_mouse_disconnect(struct usb_interface *intf)
-{
-	struct usb_mouse *mouse = usb_get_intfdata (intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (mouse) {
-		usb_kill_urb(mouse->irq);
-		input_unregister_device(mouse->dev);
-		usb_free_urb(mouse->irq);
-		usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
-		kfree(mouse);
-	}
-}
-
-static struct usb_device_id usb_mouse_id_table [] = {
-	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
-		USB_INTERFACE_PROTOCOL_MOUSE) },
-	{ }	/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
-
-static struct usb_driver usb_mouse_driver = {
-	.name		= "usbmouse",
-	.probe		= usb_mouse_probe,
-	.disconnect	= usb_mouse_disconnect,
-	.id_table	= usb_mouse_id_table,
-};
-
-static int __init usb_mouse_init(void)
-{
-	int retval = usb_register(&usb_mouse_driver);
-	if (retval == 0)
-		info(DRIVER_VERSION ":" DRIVER_DESC);
-	return retval;
-}
-
-static void __exit usb_mouse_exit(void)
-{
-	usb_deregister(&usb_mouse_driver);
-}
-
-module_init(usb_mouse_init);
-module_exit(usb_mouse_exit);
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
deleted file mode 100644
index 86e37a2..0000000
--- a/drivers/usb/input/usbtouchscreen.c
+++ /dev/null
@@ -1,838 +0,0 @@
-/******************************************************************************
- * usbtouchscreen.c
- * Driver for USB Touchscreens, supporting those devices:
- *  - eGalax Touchkit
- *    includes eTurboTouch CT-410/510/700
- *  - 3M/Microtouch  EX II series
- *  - ITM
- *  - PanJit TouchSet
- *  - eTurboTouch
- *  - Gunze AHL61
- *  - DMC TSC-10/25
- *
- * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
- * Copyright (C) by Todd E. Johnson (mtouchusb.c)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Driver is based on touchkitusb.c
- * - ITM parts are from itmtouch.c
- * - 3M parts are from mtouchusb.c
- * - PanJit parts are from an unmerged driver by Lanslott Gish
- * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
- *   driver from Marius Vollmer
- *
- *****************************************************************************/
-
-//#define DEBUG
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-
-
-#define DRIVER_VERSION		"v0.5"
-#define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
-#define DRIVER_DESC		"USB Touchscreen Driver"
-
-static int swap_xy;
-module_param(swap_xy, bool, 0644);
-MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
-
-/* device specifc data/functions */
-struct usbtouch_usb;
-struct usbtouch_device_info {
-	int min_xc, max_xc;
-	int min_yc, max_yc;
-	int min_press, max_press;
-	int rept_size;
-	int flags;
-
-	void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
-	int  (*get_pkt_len) (unsigned char *pkt, int len);
-	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
-	int  (*init)        (struct usbtouch_usb *usbtouch);
-};
-
-#define USBTOUCH_FLG_BUFFER	0x01
-
-
-/* a usbtouch device */
-struct usbtouch_usb {
-	unsigned char *data;
-	dma_addr_t data_dma;
-	unsigned char *buffer;
-	int buf_len;
-	struct urb *irq;
-	struct usb_device *udev;
-	struct input_dev *input;
-	struct usbtouch_device_info *type;
-	char name[128];
-	char phys[64];
-
-	int x, y;
-	int touch, press;
-};
-
-
-#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 {
-	DEVTPYE_DUMMY = -1,
-	DEVTYPE_EGALAX,
-	DEVTYPE_PANJIT,
-	DEVTYPE_3M,
-	DEVTYPE_ITM,
-	DEVTYPE_ETURBO,
-	DEVTYPE_GUNZE,
-	DEVTYPE_DMC_TSC10,
-};
-
-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
-	{USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
-	{USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
-	{USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
-	{USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
-#endif
-
-#ifdef CONFIG_USB_TOUCHSCREEN_3M
-	{USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
-#endif
-
-#ifdef CONFIG_USB_TOUCHSCREEN_ITM
-	{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
-
-#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
-	{USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
-#endif
-
-	{}
-};
-
-
-/*****************************************************************************
- * eGalax part
- */
-
-#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
-
-#define EGALAX_PKT_TYPE_MASK		0xFE
-#define EGALAX_PKT_TYPE_REPT		0x80
-#define EGALAX_PKT_TYPE_DIAG		0x0A
-
-static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
-		return 0;
-
-	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
-	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
-	dev->touch = pkt[0] & 0x01;
-
-	return 1;
-}
-
-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;
-}
-#endif
-
-
-/*****************************************************************************
- * PanJit Part
- */
-#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
-static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
-	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
-	dev->touch = pkt[0] & 0x01;
-
-	return 1;
-}
-#endif
-
-
-/*****************************************************************************
- * 3M/Microtouch Part
- */
-#ifdef CONFIG_USB_TOUCHSCREEN_3M
-
-#define MTOUCHUSB_ASYNC_REPORT          1
-#define MTOUCHUSB_RESET                 7
-#define MTOUCHUSB_REQ_CTRLLR_ID         10
-
-static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	dev->x = (pkt[8] << 8) | pkt[7];
-	dev->y = (pkt[10] << 8) | pkt[9];
-	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
-
-	return 1;
-}
-
-static int mtouch_init(struct usbtouch_usb *usbtouch)
-{
-	int ret, i;
-
-	ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
-	                      MTOUCHUSB_RESET,
-	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
-	    __FUNCTION__, 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;
-}
-#endif
-
-
-/*****************************************************************************
- * ITM Part
- */
-#ifdef CONFIG_USB_TOUCHSCREEN_ITM
-static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	int touch;
-	/*
-	 * ITM devices report invalid x/y data if not touched.
-	 * if the screen was touched before but is not touched any more
-	 * report touch as 0 with the last valid x/y data once. then stop
-	 * reporting data until touched again.
-	 */
-	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
-
-	touch = ~pkt[7] & 0x20;
-	if (!touch) {
-		if (dev->touch) {
-			dev->touch = 0;
-			return 1;
-		}
-
-		return 0;
-	}
-
-	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
-	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
-	dev->touch = touch;
-
-	return 1;
-}
-#endif
-
-
-/*****************************************************************************
- * eTurboTouch part
- */
-#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
-static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	unsigned int shift;
-
-	/* packets should start with sync */
-	if (!(pkt[0] & 0x80))
-		return 0;
-
-	shift = (6 - (pkt[0] & 0x03));
-	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
-	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
-	dev->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(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
-		return 0;
-
-	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
-	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
-	dev->touch = pkt[0] & 0x20;
-
-	return 1;
-}
-#endif
-
-/*****************************************************************************
- * DMC TSC-10/25 Part
- *
- * Documentation about the controller and it's protocol can be found at
- *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
- *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
- */
-#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
-
-/* supported data rates. currently using 130 */
-#define TSC10_RATE_POINT	0x50
-#define TSC10_RATE_30		0x40
-#define TSC10_RATE_50		0x41
-#define TSC10_RATE_80		0x42
-#define TSC10_RATE_100		0x43
-#define TSC10_RATE_130		0x44
-#define TSC10_RATE_150		0x45
-
-/* commands */
-#define TSC10_CMD_RESET		0x55
-#define TSC10_CMD_RATE		0x05
-#define TSC10_CMD_DATA1		0x01
-
-static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
-{
-	struct usb_device *dev = usbtouch->udev;
-	int ret;
-	unsigned char buf[2];
-
-	/* reset */
-	buf[0] = buf[1] = 0xFF;
-	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
-	                      TSC10_CMD_RESET,
-	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
-	if (ret < 0)
-		return ret;
-	if (buf[0] != 0x06 || buf[1] != 0x00)
-		return -ENODEV;
-
-	/* set coordinate output rate */
-	buf[0] = buf[1] = 0xFF;
-	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
-	                      TSC10_CMD_RATE,
-	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
-	if (ret < 0)
-		return ret;
-	if (buf[0] != 0x06 || buf[1] != 0x00)
-		return -ENODEV;
-
-	/* start sending data */
-	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
-	                      TSC10_CMD_DATA1,
-	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
-
-static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
-{
-	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
-	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
-	dev->touch = pkt[0] & 0x01;
-
-	return 1;
-}
-#endif
-
-
-/*****************************************************************************
- * the different device descriptors
- */
-static struct usbtouch_device_info usbtouch_dev_info[] = {
-#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
-	[DEVTYPE_EGALAX] = {
-		.min_xc		= 0x0,
-		.max_xc		= 0x07ff,
-		.min_yc		= 0x0,
-		.max_yc		= 0x07ff,
-		.rept_size	= 16,
-		.flags		= USBTOUCH_FLG_BUFFER,
-		.process_pkt	= usbtouch_process_multi,
-		.get_pkt_len	= egalax_get_pkt_len,
-		.read_data	= egalax_read_data,
-	},
-#endif
-
-#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
-	[DEVTYPE_PANJIT] = {
-		.min_xc		= 0x0,
-		.max_xc		= 0x0fff,
-		.min_yc		= 0x0,
-		.max_yc		= 0x0fff,
-		.rept_size	= 8,
-		.read_data	= panjit_read_data,
-	},
-#endif
-
-#ifdef CONFIG_USB_TOUCHSCREEN_3M
-	[DEVTYPE_3M] = {
-		.min_xc		= 0x0,
-		.max_xc		= 0x4000,
-		.min_yc		= 0x0,
-		.max_yc		= 0x4000,
-		.rept_size	= 11,
-		.read_data	= mtouch_read_data,
-		.init		= mtouch_init,
-	},
-#endif
-
-#ifdef CONFIG_USB_TOUCHSCREEN_ITM
-	[DEVTYPE_ITM] = {
-		.min_xc		= 0x0,
-		.max_xc		= 0x0fff,
-		.min_yc		= 0x0,
-		.max_yc		= 0x0fff,
-		.max_press	= 0xff,
-		.rept_size	= 8,
-		.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
-
-#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10
-	[DEVTYPE_DMC_TSC10] = {
-		.min_xc		= 0x0,
-		.max_xc		= 0x03ff,
-		.min_yc		= 0x0,
-		.max_yc		= 0x03ff,
-		.rept_size	= 5,
-		.init		= dmc_tsc10_init,
-		.read_data	= dmc_tsc10_read_data,
-	},
-#endif
-};
-
-
-/*****************************************************************************
- * Generic Part
- */
-static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
-                                 unsigned char *pkt, int len)
-{
-	struct usbtouch_device_info *type = usbtouch->type;
-
-	if (!type->read_data(usbtouch, pkt))
-			return;
-
-	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
-
-	if (swap_xy) {
-		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
-		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
-	} else {
-		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
-		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
-	}
-	if (type->max_press)
-		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
-	input_sync(usbtouch->input);
-}
-
-
-#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;
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ETIME:
-		/* this urb is timing out */
-		dbg("%s - urb timed out - was the device unplugged?",
-		    __FUNCTION__);
-		return;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-		    __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d",
-		    __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
-
-exit:
-	retval = usb_submit_urb(urb, GFP_ATOMIC);
-	if (retval)
-		err("%s - usb_submit_urb failed with result: %d",
-		    __FUNCTION__, retval);
-}
-
-static int usbtouch_open(struct input_dev *input)
-{
-	struct usbtouch_usb *usbtouch = input->private;
-
-	usbtouch->irq->dev = usbtouch->udev;
-
-	if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void usbtouch_close(struct input_dev *input)
-{
-	struct usbtouch_usb *usbtouch = input->private;
-
-	usb_kill_urb(usbtouch->irq);
-}
-
-
-static void usbtouch_free_buffers(struct usb_device *udev,
-				  struct usbtouch_usb *usbtouch)
-{
-	if (usbtouch->data)
-		usb_buffer_free(udev, usbtouch->type->rept_size,
-		                usbtouch->data, usbtouch->data_dma);
-	kfree(usbtouch->buffer);
-}
-
-
-static int usbtouch_probe(struct usb_interface *intf,
-			  const struct usb_device_id *id)
-{
-	struct usbtouch_usb *usbtouch;
-	struct input_dev *input_dev;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usbtouch_device_info *type;
-	int err = -ENOMEM;
-
-	interface = intf->cur_altsetting;
-	endpoint = &interface->endpoint[0].desc;
-
-	usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!usbtouch || !input_dev)
-		goto out_free;
-
-	type = &usbtouch_dev_info[id->driver_info];
-	usbtouch->type = type;
-	if (!type->process_pkt)
-		type->process_pkt = usbtouch_process_pkt;
-
-	usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
-	                                  GFP_KERNEL, &usbtouch->data_dma);
-	if (!usbtouch->data)
-		goto out_free;
-
-	if (type->flags & USBTOUCH_FLG_BUFFER) {
-		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
-		if (!usbtouch->buffer)
-			goto out_free_buffers;
-	}
-
-	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usbtouch->irq) {
-		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__);
-		goto out_free_buffers;
-	}
-
-	usbtouch->udev = udev;
-	usbtouch->input = input_dev;
-
-	if (udev->manufacturer)
-		strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
-
-	if (udev->product) {
-		if (udev->manufacturer)
-			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
-		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
-	}
-
-	if (!strlen(usbtouch->name))
-		snprintf(usbtouch->name, sizeof(usbtouch->name),
-			"USB Touchscreen %04x:%04x",
-			 le16_to_cpu(udev->descriptor.idVendor),
-			 le16_to_cpu(udev->descriptor.idProduct));
-
-	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
-	strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
-
-	input_dev->name = usbtouch->name;
-	input_dev->phys = usbtouch->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = usbtouch;
-	input_dev->open = usbtouch_open;
-	input_dev->close = usbtouch_close;
-
-	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
-	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
-	if (type->max_press)
-		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
-		                     type->max_press, 0, 0);
-
-	usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
-			 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;
-
-	/* device specific init */
-	if (type->init) {
-		err = type->init(usbtouch);
-		if (err) {
-			dbg("%s - type->init() failed, err: %d", __FUNCTION__, err);
-			goto out_free_buffers;
-		}
-	}
-
-	err = input_register_device(usbtouch->input);
-	if (err) {
-		dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err);
-		goto out_free_buffers;
-	}
-
-	usb_set_intfdata(intf, usbtouch);
-
-	return 0;
-
-out_free_buffers:
-	usbtouch_free_buffers(udev, usbtouch);
-out_free:
-	input_free_device(input_dev);
-	kfree(usbtouch);
-	return err;
-}
-
-static void usbtouch_disconnect(struct usb_interface *intf)
-{
-	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
-
-	dbg("%s - called", __FUNCTION__);
-
-	if (!usbtouch)
-		return;
-
-	dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__);
-	usb_set_intfdata(intf, NULL);
-	usb_kill_urb(usbtouch->irq);
-	input_unregister_device(usbtouch->input);
-	usb_free_urb(usbtouch->irq);
-	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
-	kfree(usbtouch);
-}
-
-MODULE_DEVICE_TABLE(usb, usbtouch_devices);
-
-static struct usb_driver usbtouch_driver = {
-	.name		= "usbtouchscreen",
-	.probe		= usbtouch_probe,
-	.disconnect	= usbtouch_disconnect,
-	.id_table	= usbtouch_devices,
-};
-
-static int __init usbtouch_init(void)
-{
-	return usb_register(&usbtouch_driver);
-}
-
-static void __exit usbtouch_cleanup(void)
-{
-	usb_deregister(&usbtouch_driver);
-}
-
-module_init(usbtouch_init);
-module_exit(usbtouch_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("touchkitusb");
-MODULE_ALIAS("itmtouch");
-MODULE_ALIAS("mtouchusb");
diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h
deleted file mode 100644
index d85abfc..0000000
--- a/drivers/usb/input/wacom.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * drivers/usb/input/wacom.h
- *
- *  USB Wacom Graphire and Wacom Intuos tablet support
- *
- *  Copyright (c) 2000-2004 Vojtech Pavlik	<vojtech@ucw.cz>
- *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
- *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
- *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
- *  Copyright (c) 2000 James E. Blair		<corvus@gnu.org>
- *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
- *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
- *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
- *  Copyright (c) 2002-2006 Ping Cheng		<pingc@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@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_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
deleted file mode 100644
index 12b4274..0000000
--- a/drivers/usb/input/wacom_sys.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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;
-}
-
-static 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, 4096, 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, 4096, 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
deleted file mode 100644
index 4f3e9bc..0000000
--- a/drivers/usb/input/wacom_wac.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * 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] & 0x80) { /* 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;
-		}
-		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);
-		}
-		wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
-		wacom_report_key(wcombo, wacom->tool[0], 1);
-	} else if (!(data[1] & 0x90)) {
-		wacom_report_abs(wcombo, ABS_X, 0);
-		wacom_report_abs(wcombo, ABS_Y, 0);
-		if (wacom->tool[0] == BTN_TOOL_MOUSE) {
-			wacom_report_key(wcombo, BTN_LEFT, 0);
-			wacom_report_key(wcombo, BTN_RIGHT, 0);
-			wacom_report_abs(wcombo, ABS_DISTANCE, 0);
-		} else {
-			wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-			wacom_report_key(wcombo, BTN_TOUCH, 0);
-			wacom_report_key(wcombo, BTN_STYLUS, 0);
-			wacom_report_key(wcombo, BTN_STYLUS2, 0);
-		}
-		wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-		wacom_report_key(wcombo, wacom->tool[0], 0);
-	}
-
-	/* send pad data */
-	if (wacom->features->type == WACOM_G4) {
-		if (data[7] & 0xf8) {
-			wacom_input_sync(wcombo); /* sync last event */
-			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_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
-			wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
-		} else if (wacom->id[1]) {
-			wacom_input_sync(wcombo); /* sync last event */
-			wacom->id[1] = 0;
-			wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
-			wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
-			wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
-			wacom_report_abs(wcombo, ABS_MISC, 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;
-		}
-		return 1;
-	}
-
-	/* Exit report */
-	if ((data[1] & 0xfe) == 0x80) {
-		wacom_report_abs(wcombo, ABS_X, 0);
-		wacom_report_abs(wcombo, ABS_Y, 0);
-		wacom_report_abs(wcombo, ABS_DISTANCE, 0);
-		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
-			wacom_report_key(wcombo, BTN_LEFT, 0);
-			wacom_report_key(wcombo, BTN_MIDDLE, 0);
-			wacom_report_key(wcombo, BTN_RIGHT, 0);
-			wacom_report_key(wcombo, BTN_SIDE, 0);
-			wacom_report_key(wcombo, BTN_EXTRA, 0);
-			wacom_report_abs(wcombo, ABS_THROTTLE, 0);
-			wacom_report_abs(wcombo, ABS_RZ, 0);
- 		} else {
-			wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-			wacom_report_abs(wcombo, ABS_TILT_X, 0);
-			wacom_report_abs(wcombo, ABS_TILT_Y, 0);
-			wacom_report_key(wcombo, BTN_STYLUS, 0);
-			wacom_report_key(wcombo, BTN_STYLUS2, 0);
-			wacom_report_key(wcombo, BTN_TOUCH, 0);
-			wacom_report_abs(wcombo, ABS_WHEEL, 0);
-		}
-		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_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
-		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;
-
-	/* Only large I3 and I1 & I2 support Lense Cursor */
- 	if((wacom->tool[idx] == BTN_TOOL_LENS)
-			&& ((wacom->features->type == INTUOS3)
-		 	|| (wacom->features->type == INTUOS3S)))
-		return 0;
-
-	/* 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 >= INTUOS3S) {
-		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 >= INTUOS3S) {
-				/* 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, 63, GRAPHIRE },
-	{ "Wacom PenStation2",   8,   3250,  2320,  255, 63, GRAPHIRE },
-	{ "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
-	{ "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
-	{ "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
-	{ "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
-	{ "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
-	{ "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
-	{ "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 31, INTUOS },
-	{ "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 31, 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, 31, INTUOS },
-	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
-	{ "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 31, INTUOS },
-	{ "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
-	{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, 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, 63, INTUOS3S },
-	{ "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
-	{ "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, 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
deleted file mode 100644
index a230222..0000000
--- a/drivers/usb/input/wacom_wac.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
-#define PAD_DEVICE_ID		0x0F
-
-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
deleted file mode 100644
index e4bc76e..0000000
--- a/drivers/usb/input/xpad.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * X-Box gamepad - v0.0.6
- *
- * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
- *               2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
- *                    Steven Toth <steve@toth.demon.co.uk>,
- *                    Franz Lehner <franz@caos.at>,
- *                    Ivan Hawkes <blackhawk@ivanhawkes.com>
- *               2005 Dominic Cerquetti <binary1230@yahoo.com>
- *               2006 Adam Buchbinder <adam.buchbinder@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
- *
- *
- * This driver is based on:
- *  - information from     http://euc.jp/periphs/xbox-controller.ja.html
- *  - the iForce driver    drivers/char/joystick/iforce.c
- *  - the skeleton-driver  drivers/usb/usb-skeleton.c
- *
- * Thanks to:
- *  - 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 (especially trigger axes)
- *  - fix "analog" buttons (reported as digital now)
- *  - get rumble working
- *  - need USB IDs for other dance pads
- *
- * History:
- *
- * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
- *
- * 2002-07-02 - 0.0.2 : basic working version
- *  - all axes and 9 of the 10 buttons work (german InterAct device)
- *  - the black button does not work
- *
- * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik
- *  - indentation fixes
- *  - usb + input init sequence fixes
- *
- * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
- *  - verified the lack of HID and report descriptors
- *  - verified that ALL buttons WORK
- *  - 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.6"
-#define DRIVER_AUTHOR "Marko Friedemann <mfr@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 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[] = {
-	BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,	/* "analog" buttons */
-	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
-	-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 */
-	-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 */
-};
-
-static struct usb_device_id xpad_table [] = {
-	{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
-	{ }
-};
-
-MODULE_DEVICE_TABLE (usb, xpad_table);
-
-struct usb_xpad {
-	struct input_dev *dev;		/* input device interface */
-	struct usb_device *udev;	/* usb device */
-
-	struct urb *irq_in;		/* urb for interrupt in report */
-	unsigned char *idata;		/* input data */
-	dma_addr_t idata_dma;
-
-	char phys[65];			/* physical device path */
-
-	int dpad_mapping;		/* map d-pad to buttons or to axes */
-};
-
-/*
- *	xpad_process_packet
- *
- *	Completes a request by converting the data into events for the
- *	input subsystem.
- *
- *	The used report descriptor was taken from ITO Takayukis website:
- *	 http://euc.jp/periphs/xbox-controller.ja.html
- */
-
-static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
-{
-	struct input_dev *dev = xpad->dev;
-
-	/* left stick */
-	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
-	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
-
-	/* right stick */
-	input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
-	input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
-
-	/* triggers left/right */
-	input_report_abs(dev, ABS_Z, data[10]);
-	input_report_abs(dev, ABS_RZ, data[11]);
-
-	/* digital pad */
-	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);
-	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]);
-	input_report_key(dev, BTN_B, data[5]);
-	input_report_key(dev, BTN_X, data[6]);
-	input_report_key(dev, BTN_Y, data[7]);
-
-	/* "analog" buttons black, white */
-	input_report_key(dev, BTN_C, data[8]);
-	input_report_key(dev, BTN_Z, data[9]);
-
-	input_sync(dev);
-}
-
-static void xpad_irq_in(struct urb *urb)
-{
-	struct usb_xpad *xpad = urb->context;
-	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;
-	}
-
-	xpad_process_packet(xpad, 0, xpad->idata);
-
-exit:
-	retval = usb_submit_urb (urb, GFP_ATOMIC);
-	if (retval)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, retval);
-}
-
-static int xpad_open (struct input_dev *dev)
-{
-	struct usb_xpad *xpad = dev->private;
-
-	xpad->irq_in->dev = xpad->udev;
-	if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
-		return -EIO;
-
-	return 0;
-}
-
-static void xpad_close (struct input_dev *dev)
-{
-	struct usb_xpad *xpad = dev->private;
-
-	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);
-	struct usb_xpad *xpad;
-	struct input_dev *input_dev;
-	struct usb_endpoint_descriptor *ep_irq_in;
-	int i;
-
-	for (i = 0; xpad_device[i].idVendor; i++) {
-		if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
-		    (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
-			break;
-	}
-
-	xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!xpad || !input_dev)
-		goto fail1;
-
-	xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
-				       GFP_ATOMIC, &xpad->idata_dma);
-	if (!xpad->idata)
-		goto fail1;
-
-	xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
-	if (!xpad->irq_in)
-		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));
-
-	input_dev->name = xpad_device[i].name;
-	input_dev->phys = xpad->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-	input_dev->private = xpad;
-	input_dev->open = xpad_open;
-	input_dev->close = xpad_close;
-
-	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);
-
-	/* 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,
-			 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
-			 xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
-			 xpad, ep_irq_in->bInterval);
-	xpad->irq_in->transfer_dma = xpad->idata_dma;
-	xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-	input_register_device(xpad->dev);
-
-	usb_set_intfdata(intf, xpad);
-	return 0;
-
-fail2:	usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
-fail1:	input_free_device(input_dev);
-	kfree(xpad);
-	return -ENOMEM;
-
-}
-
-static void xpad_disconnect(struct usb_interface *intf)
-{
-	struct usb_xpad *xpad = usb_get_intfdata (intf);
-
-	usb_set_intfdata(intf, NULL);
-	if (xpad) {
-		usb_kill_urb(xpad->irq_in);
-		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);
-		kfree(xpad);
-	}
-}
-
-static struct usb_driver xpad_driver = {
-	.name		= "xpad",
-	.probe		= xpad_probe,
-	.disconnect	= xpad_disconnect,
-	.id_table	= xpad_table,
-};
-
-static int __init usb_xpad_init(void)
-{
-	int result = usb_register(&xpad_driver);
-	if (result == 0)
-		info(DRIVER_DESC ":" DRIVER_VERSION);
-	return result;
-}
-
-static void __exit usb_xpad_exit(void)
-{
-	usb_deregister(&xpad_driver);
-}
-
-module_init(usb_xpad_init);
-module_exit(usb_xpad_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c
deleted file mode 100644
index caff8e6..0000000
--- a/drivers/usb/input/yealink.c
+++ /dev/null
@@ -1,1002 +0,0 @@
-/*
- * drivers/usb/input/yealink.c
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
- */
-/*
- * Description:
- *   Driver for the USB-P1K voip usb phone.
- *   This device is produced by Yealink Network Technology Co Ltd
- *   but may be branded under several names:
- *	- Yealink usb-p1k
- *	- Tiptel 115
- *	- ...
- *
- * This driver is based on:
- *   - the usbb2k-api	http://savannah.nongnu.org/projects/usbb2k-api/
- *   - information from	http://memeteau.free.fr/usbb2k
- *   - the xpad-driver	drivers/usb/input/xpad.c
- *
- * Thanks to:
- *   - Olivier Vandorpe, for providing the usbb2k-api.
- *   - Martin Diehl, for spotting my memory allocation bug.
- *
- * History:
- *   20050527 henk	First version, functional keyboard. Keyboard events
- *			will pop-up on the ../input/eventX bus.
- *   20050531 henk	Added led, LCD, dialtone and sysfs interface.
- *   20050610 henk	Cleanups, make it ready for public consumption.
- *   20050630 henk	Cleanups, fixes in response to comments.
- *   20050701 henk	sysfs write serialisation, fix potential unload races
- *   20050801 henk	Added ringtone, restructure USB
- *   20050816 henk	Merge 2.6.13-rc6
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/rwsem.h>
-#include <linux/usb/input.h>
-
-#include "map_to_7segment.h"
-#include "yealink.h"
-
-#define DRIVER_VERSION "yld-20051230"
-#define DRIVER_AUTHOR "Henk Vergonet"
-#define DRIVER_DESC "Yealink phone driver"
-
-#define YEALINK_POLLING_FREQUENCY	10	/* in [Hz] */
-
-struct yld_status {
-	u8	lcd[24];
-	u8	led;
-	u8	dialtone;
-	u8	ringtone;
-	u8	keynum;
-} __attribute__ ((packed));
-
-/*
- * Register the LCD segment and icon map
- */
-#define _LOC(k,l)	{ .a = (k), .m = (l) }
-#define _SEG(t, a, am, b, bm, c, cm, d, dm, e, em, f, fm, g, gm)	\
-	{ .type	= (t),							\
-	  .u = { .s = {	_LOC(a, am), _LOC(b, bm), _LOC(c, cm),		\
-		        _LOC(d, dm), _LOC(e, em), _LOC(g, gm),		\
-			_LOC(f, fm) } } }
-#define _PIC(t, h, hm, n)						\
-	{ .type	= (t),							\
- 	  .u = { .p = { .name = (n), .a = (h), .m = (hm) } } }
-
-static const struct lcd_segment_map {
-	char	type;
-	union {
-		struct pictogram_map {
-			u8	a,m;
-			char	name[10];
-		}	p;
-		struct segment_map {
-			u8	a,m;
-		} s[7];
-	} u;
-} lcdMap[] = {
-#include "yealink.h"
-};
-
-struct yealink_dev {
-	struct input_dev *idev;		/* input device */
-	struct usb_device *udev;	/* usb device */
-
-	/* irq input channel */
-	struct yld_ctl_packet	*irq_data;
-	dma_addr_t		irq_dma;
-	struct urb		*urb_irq;
-
-	/* control output channel */
-	struct yld_ctl_packet	*ctl_data;
-	dma_addr_t		ctl_dma;
-	struct usb_ctrlrequest	*ctl_req;
-	dma_addr_t		ctl_req_dma;
-	struct urb		*urb_ctl;
-
-	char phys[64];			/* physical device path */
-
-	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
-	int key_code;			/* last reported key	 */
-
-	int	stat_ix;
-	union {
-		struct yld_status s;
-		u8		  b[sizeof(struct yld_status)];
-	} master, copy;
-};
-
-
-/*******************************************************************************
- * Yealink lcd interface
- ******************************************************************************/
-
-/*
- * Register a default 7 segment character set
- */
-static SEG7_DEFAULT_MAP(map_seg7);
-
- /* Display a char,
-  * char '\9' and '\n' are placeholders and do not overwrite the original text.
-  * A space will always hide an icon.
-  */
-static int setChar(struct yealink_dev *yld, int el, int chr)
-{
-	int i, a, m, val;
-
-	if (el >= ARRAY_SIZE(lcdMap))
-		return -EINVAL;
-
-	if (chr == '\t' || chr == '\n')
-	    return 0;
-
-	yld->lcdMap[el] = chr;
-
-	if (lcdMap[el].type == '.') {
-		a = lcdMap[el].u.p.a;
-		m = lcdMap[el].u.p.m;
-		if (chr != ' ')
-			yld->master.b[a] |= m;
-		else
-			yld->master.b[a] &= ~m;
-		return 0;
-	}
-
-	val = map_to_seg7(&map_seg7, chr);
-	for (i = 0; i < ARRAY_SIZE(lcdMap[0].u.s); i++) {
-		m = lcdMap[el].u.s[i].m;
-
-		if (m == 0)
-			continue;
-
-		a = lcdMap[el].u.s[i].a;
-		if (val & 1)
-			yld->master.b[a] |= m;
-		else
-			yld->master.b[a] &= ~m;
-		val = val >> 1;
-	}
-	return 0;
-};
-
-/*******************************************************************************
- * Yealink key interface
- ******************************************************************************/
-
-/* Map device buttons to internal key events.
- *
- * USB-P1K button layout:
- *
- *             up
- *       IN           OUT
- *            down
- *
- *     pickup   C    hangup
- *       1      2      3
- *       4      5      6
- *       7      8      9
- *       *      0      #
- *
- * The "up" and "down" keys, are symbolised by arrows on the button.
- * The "pickup" and "hangup" keys are symbolised by a green and red phone
- * on the button.
- */
-static int map_p1k_to_key(int scancode)
-{
-	switch(scancode) {		/* phone key:	*/
-	case 0x23: return KEY_LEFT;	/*   IN		*/
-	case 0x33: return KEY_UP;	/*   up		*/
-	case 0x04: return KEY_RIGHT;	/*   OUT	*/
-	case 0x24: return KEY_DOWN;	/*   down	*/
-	case 0x03: return KEY_ENTER;	/*   pickup	*/
-	case 0x14: return KEY_BACKSPACE; /*  C		*/
-	case 0x13: return KEY_ESC;	/*   hangup	*/
-	case 0x00: return KEY_1;	/*   1		*/
-	case 0x01: return KEY_2;	/*   2 		*/
-	case 0x02: return KEY_3;	/*   3		*/
-	case 0x10: return KEY_4;	/*   4		*/
-	case 0x11: return KEY_5;	/*   5		*/
-	case 0x12: return KEY_6;	/*   6		*/
-	case 0x20: return KEY_7;	/*   7		*/
-	case 0x21: return KEY_8;	/*   8		*/
-	case 0x22: return KEY_9;	/*   9		*/
-	case 0x30: return KEY_KPASTERISK; /* *		*/
-	case 0x31: return KEY_0;	/*   0		*/
-	case 0x32: return KEY_LEFTSHIFT |
-			  KEY_3 << 8;	/*   #		*/
-	}
-	return -EINVAL;
-}
-
-/* Completes a request by converting the data into events for the
- * input subsystem.
- *
- * The key parameter can be cascaded: key2 << 8 | key1
- */
-static void report_key(struct yealink_dev *yld, int key)
-{
-	struct input_dev *idev = yld->idev;
-
-	if (yld->key_code >= 0) {
-		/* old key up */
-		input_report_key(idev, yld->key_code & 0xff, 0);
-		if (yld->key_code >> 8)
-			input_report_key(idev, yld->key_code >> 8, 0);
-	}
-
-	yld->key_code = key;
-	if (key >= 0) {
-		/* new valid key */
-		input_report_key(idev, key & 0xff, 1);
-		if (key >> 8)
-			input_report_key(idev, key >> 8, 1);
-	}
-	input_sync(idev);
-}
-
-/*******************************************************************************
- * Yealink usb communication interface
- ******************************************************************************/
-
-static int yealink_cmd(struct yealink_dev *yld, struct yld_ctl_packet *p)
-{
-	u8	*buf = (u8 *)p;
-	int	i;
-	u8	sum = 0;
-
-	for(i=0; i<USB_PKT_LEN-1; i++)
-		sum -= buf[i];
-	p->sum = sum;
-	return usb_control_msg(yld->udev,
-			usb_sndctrlpipe(yld->udev, 0),
-			USB_REQ_SET_CONFIGURATION,
-			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			0x200, 3,
-			p, sizeof(*p),
-			USB_CTRL_SET_TIMEOUT);
-}
-
-static u8 default_ringtone[] = {
-	0xEF,			/* volume [0-255] */
-	0xFB, 0x1E, 0x00, 0x0C,	/* 1250 [hz], 12/100 [s] */
-	0xFC, 0x18, 0x00, 0x0C,	/* 1000 [hz], 12/100 [s] */
-	0xFB, 0x1E, 0x00, 0x0C,
-	0xFC, 0x18, 0x00, 0x0C,
-	0xFB, 0x1E, 0x00, 0x0C,
-	0xFC, 0x18, 0x00, 0x0C,
-	0xFB, 0x1E, 0x00, 0x0C,
-	0xFC, 0x18, 0x00, 0x0C,
-	0xFF, 0xFF, 0x01, 0x90,	/* silent, 400/100 [s] */
-	0x00, 0x00		/* end of sequence */
-};
-
-static int yealink_set_ringtone(struct yealink_dev *yld, u8 *buf, size_t size)
-{
-	struct yld_ctl_packet *p = yld->ctl_data;
-	int	ix, len;
-
-	if (size <= 0)
-		return -EINVAL;
-
-	/* Set the ringtone volume */
-	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-	yld->ctl_data->cmd	= CMD_RING_VOLUME;
-	yld->ctl_data->size	= 1;
-	yld->ctl_data->data[0]	= buf[0];
-	yealink_cmd(yld, p);
-
-	buf++;
-	size--;
-
-	p->cmd = CMD_RING_NOTE;
-	ix = 0;
-	while (size != ix) {
-		len = size - ix;
-		if (len > sizeof(p->data))
-			len = sizeof(p->data);
-		p->size	  = len;
-		p->offset = cpu_to_be16(ix);
-		memcpy(p->data, &buf[ix], len);
-		yealink_cmd(yld, p);
-		ix += len;
-	}
-	return 0;
-}
-
-/* keep stat_master & stat_copy in sync.
- */
-static int yealink_do_idle_tasks(struct yealink_dev *yld)
-{
-	u8 val;
-	int i, ix, len;
-
-	ix = yld->stat_ix;
-
-	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-	yld->ctl_data->cmd  = CMD_KEYPRESS;
-	yld->ctl_data->size = 1;
-	yld->ctl_data->sum  = 0xff - CMD_KEYPRESS;
-
-	/* If state update pointer wraps do a KEYPRESS first. */
-	if (ix >= sizeof(yld->master)) {
-		yld->stat_ix = 0;
-		return 0;
-	}
-
-	/* find update candidates: copy != master */
-	do {
-		val = yld->master.b[ix];
-		if (val != yld->copy.b[ix])
-			goto send_update;
-	} while (++ix < sizeof(yld->master));
-
-	/* nothing todo, wait a bit and poll for a KEYPRESS */
-	yld->stat_ix = 0;
-	/* TODO how can we wait abit. ??
-	 * msleep_interruptible(1000 / YEALINK_POLLING_FREQUENCY);
-	 */
-	return 0;
-
-send_update:
-
-	/* Setup an appropriate update request */
-	yld->copy.b[ix] = val;
-	yld->ctl_data->data[0] = val;
-
-	switch(ix) {
-	case offsetof(struct yld_status, led):
-		yld->ctl_data->cmd	= CMD_LED;
-		yld->ctl_data->sum	= -1 - CMD_LED - val;
-		break;
-	case offsetof(struct yld_status, dialtone):
-		yld->ctl_data->cmd	= CMD_DIALTONE;
-		yld->ctl_data->sum	= -1 - CMD_DIALTONE - val;
-		break;
-	case offsetof(struct yld_status, ringtone):
-		yld->ctl_data->cmd	= CMD_RINGTONE;
-		yld->ctl_data->sum	= -1 - CMD_RINGTONE - val;
-		break;
-	case offsetof(struct yld_status, keynum):
-		val--;
-		val &= 0x1f;
-		yld->ctl_data->cmd	= CMD_SCANCODE;
-		yld->ctl_data->offset	= cpu_to_be16(val);
-		yld->ctl_data->data[0]	= 0;
-		yld->ctl_data->sum	= -1 - CMD_SCANCODE - val;
-		break;
-	default:
-		len = sizeof(yld->master.s.lcd) - ix;
-		if (len > sizeof(yld->ctl_data->data))
-			len = sizeof(yld->ctl_data->data);
-
-		/* Combine up to <len> consecutive LCD bytes in a singe request
-		 */
-		yld->ctl_data->cmd	= CMD_LCD;
-		yld->ctl_data->offset	= cpu_to_be16(ix);
-		yld->ctl_data->size	= len;
-		yld->ctl_data->sum	= -CMD_LCD - ix - val - len;
-		for(i=1; i<len; i++) {
-			ix++;
-			val = yld->master.b[ix];
-			yld->copy.b[ix]		= val;
-			yld->ctl_data->data[i]	= val;
-			yld->ctl_data->sum     -= val;
-		}
-	}
-	yld->stat_ix = ix + 1;
-	return 1;
-}
-
-/* Decide on how to handle responses
- *
- * The state transition diagram is somethhing like:
- *
- *          syncState<--+
- *               |      |
- *               |    idle
- *              \|/     |
- * init --ok--> waitForKey --ok--> getKey
- *  ^               ^                |
- *  |               +-------ok-------+
- * error,start
- *
- */
-static void urb_irq_callback(struct urb *urb)
-{
-	struct yealink_dev *yld = urb->context;
-	int ret;
-
-	if (urb->status)
-		err("%s - urb status %d", __FUNCTION__, urb->status);
-
-	switch (yld->irq_data->cmd) {
-	case CMD_KEYPRESS:
-
-		yld->master.s.keynum = yld->irq_data->data[0];
-		break;
-
-	case CMD_SCANCODE:
-		dbg("get scancode %x", yld->irq_data->data[0]);
-
-		report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
-		break;
-
-	default:
-		err("unexpected response %x", yld->irq_data->cmd);
-	}
-
-	yealink_do_idle_tasks(yld);
-
-	ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
-	if (ret)
-		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
-}
-
-static void urb_ctl_callback(struct urb *urb)
-{
-	struct yealink_dev *yld = urb->context;
-	int ret;
-
-	if (urb->status)
-		err("%s - urb status %d", __FUNCTION__, urb->status);
-
-	switch (yld->ctl_data->cmd) {
-	case CMD_KEYPRESS:
-	case CMD_SCANCODE:
-		/* ask for a response */
-		ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
-		break;
-	default:
-		/* send new command */
-		yealink_do_idle_tasks(yld);
-		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
-	}
-
-	if (ret)
-		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
-}
-
-/*******************************************************************************
- * input event interface
- ******************************************************************************/
-
-/* TODO should we issue a ringtone on a SND_BELL event?
-static int input_ev(struct input_dev *dev, unsigned int type,
-		unsigned int code, int value)
-{
-
-	if (type != EV_SND)
-		return -EINVAL;
-
-	switch (code) {
-	case SND_BELL:
-	case SND_TONE:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-*/
-
-static int input_open(struct input_dev *dev)
-{
-	struct yealink_dev *yld = dev->private;
-	int i, ret;
-
-	dbg("%s", __FUNCTION__);
-
-	/* force updates to device */
-	for (i = 0; i<sizeof(yld->master); i++)
-		yld->copy.b[i] = ~yld->master.b[i];
-	yld->key_code = -1;	/* no keys pressed */
-
-        yealink_set_ringtone(yld, default_ringtone, sizeof(default_ringtone));
-
-	/* issue INIT */
-	memset(yld->ctl_data, 0, sizeof(*(yld->ctl_data)));
-	yld->ctl_data->cmd	= CMD_INIT;
-	yld->ctl_data->size	= 10;
-	yld->ctl_data->sum	= 0x100-CMD_INIT-10;
-	if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
-		dbg("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, ret);
-		return ret;
-	}
-	return 0;
-}
-
-static void input_close(struct input_dev *dev)
-{
-	struct yealink_dev *yld = dev->private;
-
-	usb_kill_urb(yld->urb_ctl);
-	usb_kill_urb(yld->urb_irq);
-}
-
-/*******************************************************************************
- * sysfs interface
- ******************************************************************************/
-
-static DECLARE_RWSEM(sysfs_rwsema);
-
-/* Interface to the 7-segments translation table aka. char set.
- */
-static ssize_t show_map(struct device *dev, struct device_attribute *attr,
-				char *buf)
-{
-	memcpy(buf, &map_seg7, sizeof(map_seg7));
-	return sizeof(map_seg7);
-}
-
-static ssize_t store_map(struct device *dev, struct device_attribute *attr,
-				const char *buf, size_t cnt)
-{
-	if (cnt != sizeof(map_seg7))
-		return -EINVAL;
-	memcpy(&map_seg7, buf, sizeof(map_seg7));
-	return sizeof(map_seg7);
-}
-
-/* Interface to the LCD.
- */
-
-/* Reading /sys/../lineX will return the format string with its settings:
- *
- * Example:
- * cat ./line3
- * 888888888888
- * Linux Rocks!
- */
-static ssize_t show_line(struct device *dev, char *buf, int a, int b)
-{
-	struct yealink_dev *yld;
-	int i;
-
-	down_read(&sysfs_rwsema);
-	yld = dev_get_drvdata(dev);
-	if (yld == NULL) {
-		up_read(&sysfs_rwsema);
-		return -ENODEV;
-	}
-
-	for (i = a; i < b; i++)
-		*buf++ = lcdMap[i].type;
-	*buf++ = '\n';
-	for (i = a; i < b; i++)
-		*buf++ = yld->lcdMap[i];
-	*buf++ = '\n';
-	*buf = 0;
-
-	up_read(&sysfs_rwsema);
-	return 3 + ((b - a) << 1);
-}
-
-static ssize_t show_line1(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	return show_line(dev, buf, LCD_LINE1_OFFSET, LCD_LINE2_OFFSET);
-}
-
-static ssize_t show_line2(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	return show_line(dev, buf, LCD_LINE2_OFFSET, LCD_LINE3_OFFSET);
-}
-
-static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
-}
-
-/* Writing to /sys/../lineX will set the coresponding LCD line.
- * - Excess characters are ignored.
- * - If less characters are written than allowed, the remaining digits are
- *   unchanged.
- * - The '\n' or '\t' char is a placeholder, it does not overwrite the
- *   original content.
- */
-static ssize_t store_line(struct device *dev, const char *buf, size_t count,
-		int el, size_t len)
-{
-	struct yealink_dev *yld;
-	int i;
-
-	down_write(&sysfs_rwsema);
-	yld = dev_get_drvdata(dev);
-	if (yld == NULL) {
-		up_write(&sysfs_rwsema);
-		return -ENODEV;
-	}
-
-	if (len > count)
-		len = count;
-	for (i = 0; i < len; i++)
-		setChar(yld, el++, buf[i]);
-
-	up_write(&sysfs_rwsema);
-	return count;
-}
-
-static ssize_t store_line1(struct device *dev, struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	return store_line(dev, buf, count, LCD_LINE1_OFFSET, LCD_LINE1_SIZE);
-}
-
-static ssize_t store_line2(struct device *dev, struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	return store_line(dev, buf, count, LCD_LINE2_OFFSET, LCD_LINE2_SIZE);
-}
-
-static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	return store_line(dev, buf, count, LCD_LINE3_OFFSET, LCD_LINE3_SIZE);
-}
-
-/* Interface to visible and audible "icons", these include:
- * pictures on the LCD, the LED, and the dialtone signal.
- */
-
-/* Get a list of "switchable elements" with their current state. */
-static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	struct yealink_dev *yld;
-	int i, ret = 1;
-
-	down_read(&sysfs_rwsema);
-	yld = dev_get_drvdata(dev);
-	if (yld == NULL) {
-		up_read(&sysfs_rwsema);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
-		if (lcdMap[i].type != '.')
-			continue;
-		ret += sprintf(&buf[ret], "%s %s\n",
-				yld->lcdMap[i] == ' ' ? "  " : "on",
-				lcdMap[i].u.p.name);
-	}
-	up_read(&sysfs_rwsema);
-	return ret;
-}
-
-/* Change the visibility of a particular element. */
-static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
-			int chr)
-{
-	struct yealink_dev *yld;
-	int i;
-
-	down_write(&sysfs_rwsema);
-	yld = dev_get_drvdata(dev);
-	if (yld == NULL) {
-		up_write(&sysfs_rwsema);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
-		if (lcdMap[i].type != '.')
-			continue;
-		if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) {
-			setChar(yld, i, chr);
-			break;
-		}
-	}
-
-	up_write(&sysfs_rwsema);
-	return count;
-}
-
-static ssize_t show_icon(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	return set_icon(dev, buf, count, buf[0]);
-}
-
-static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	return set_icon(dev, buf, count, ' ');
-}
-
-/* Upload a ringtone to the device.
- */
-
-/* Stores raw ringtone data in the phone */
-static ssize_t store_ringtone(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t count)
-{
-	struct yealink_dev *yld;
-
-	down_write(&sysfs_rwsema);
-	yld = dev_get_drvdata(dev);
-	if (yld == NULL) {
-		up_write(&sysfs_rwsema);
-		return -ENODEV;
-	}
-
-	/* TODO locking with async usb control interface??? */
-	yealink_set_ringtone(yld, (char *)buf, count);
-	up_write(&sysfs_rwsema);
-	return count;
-}
-
-#define _M444	S_IRUGO
-#define _M664	S_IRUGO|S_IWUSR|S_IWGRP
-#define _M220	S_IWUSR|S_IWGRP
-
-static DEVICE_ATTR(map_seg7	, _M664, show_map	, store_map	);
-static DEVICE_ATTR(line1	, _M664, show_line1	, store_line1	);
-static DEVICE_ATTR(line2	, _M664, show_line2	, store_line2	);
-static DEVICE_ATTR(line3	, _M664, show_line3	, store_line3	);
-static DEVICE_ATTR(get_icons	, _M444, get_icons	, NULL		);
-static DEVICE_ATTR(show_icon	, _M220, NULL		, show_icon	);
-static DEVICE_ATTR(hide_icon	, _M220, NULL		, hide_icon	);
-static DEVICE_ATTR(ringtone	, _M220, NULL		, store_ringtone);
-
-static struct attribute *yld_attributes[] = {
-	&dev_attr_line1.attr,
-	&dev_attr_line2.attr,
-	&dev_attr_line3.attr,
-	&dev_attr_get_icons.attr,
-	&dev_attr_show_icon.attr,
-	&dev_attr_hide_icon.attr,
-	&dev_attr_map_seg7.attr,
-	&dev_attr_ringtone.attr,
-	NULL
-};
-
-static struct attribute_group yld_attr_group = {
-	.attrs = yld_attributes
-};
-
-/*******************************************************************************
- * Linux interface and usb initialisation
- ******************************************************************************/
-
-struct driver_info {
-	char *name;
-};
-
-static const struct driver_info info_P1K = {
-	.name	= "Yealink usb-p1k",
-};
-
-static const struct usb_device_id usb_table [] = {
-	{
-		.match_flags		= USB_DEVICE_ID_MATCH_DEVICE |
-						USB_DEVICE_ID_MATCH_INT_INFO,
-		.idVendor		= 0x6993,
-		.idProduct		= 0xb001,
-		.bInterfaceClass	= USB_CLASS_HID,
-		.bInterfaceSubClass	= 0,
-		.bInterfaceProtocol	= 0,
-		.driver_info		= (kernel_ulong_t)&info_P1K
-	},
-	{ }
-};
-
-static int usb_cleanup(struct yealink_dev *yld, int err)
-{
-	if (yld == NULL)
-		return err;
-
-	usb_kill_urb(yld->urb_irq);	/* parameter validation in core/urb */
-	usb_kill_urb(yld->urb_ctl);	/* parameter validation in core/urb */
-
-        if (yld->idev) {
-		if (err)
-			input_free_device(yld->idev);
-		else
-			input_unregister_device(yld->idev);
-	}
-	if (yld->ctl_req)
-		usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
-				yld->ctl_req, yld->ctl_req_dma);
-	if (yld->ctl_data)
-		usb_buffer_free(yld->udev, USB_PKT_LEN,
-				yld->ctl_data, yld->ctl_dma);
-	if (yld->irq_data)
-		usb_buffer_free(yld->udev, USB_PKT_LEN,
-				yld->irq_data, yld->irq_dma);
-
-	usb_free_urb(yld->urb_irq);	/* parameter validation in core/urb */
-	usb_free_urb(yld->urb_ctl);	/* parameter validation in core/urb */
-	kfree(yld);
-	return err;
-}
-
-static void usb_disconnect(struct usb_interface *intf)
-{
-	struct yealink_dev *yld;
-
-	down_write(&sysfs_rwsema);
-	yld = usb_get_intfdata(intf);
-	sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
-	usb_set_intfdata(intf, NULL);
-	up_write(&sysfs_rwsema);
-
-	usb_cleanup(yld, 0);
-}
-
-static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev (intf);
-	struct driver_info *nfo = (struct driver_info *)id->driver_info;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct yealink_dev *yld;
-	struct input_dev *input_dev;
-	int ret, pipe, i;
-
-	interface = intf->cur_altsetting;
-	endpoint = &interface->endpoint[0].desc;
-	if (!usb_endpoint_is_int_in(endpoint))
-		return -ENODEV;
-
-	yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
-	if (!yld)
-		return -ENOMEM;
-
-	yld->udev = udev;
-
-	yld->idev = input_dev = input_allocate_device();
-	if (!input_dev)
-		return usb_cleanup(yld, -ENOMEM);
-
-	/* allocate usb buffers */
-	yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					GFP_ATOMIC, &yld->irq_dma);
-	if (yld->irq_data == NULL)
-		return usb_cleanup(yld, -ENOMEM);
-
-	yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
-					GFP_ATOMIC, &yld->ctl_dma);
-	if (!yld->ctl_data)
-		return usb_cleanup(yld, -ENOMEM);
-
-	yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)),
-					GFP_ATOMIC, &yld->ctl_req_dma);
-	if (yld->ctl_req == NULL)
-		return usb_cleanup(yld, -ENOMEM);
-
-	/* allocate urb structures */
-	yld->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
-        if (yld->urb_irq == NULL)
-		return usb_cleanup(yld, -ENOMEM);
-
-	yld->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
-        if (yld->urb_ctl == NULL)
-		return usb_cleanup(yld, -ENOMEM);
-
-	/* get a handle to the interrupt data pipe */
-	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
-	ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-	if (ret != USB_PKT_LEN)
-		err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
-
-	/* initialise irq urb */
-	usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
-			USB_PKT_LEN,
-			urb_irq_callback,
-			yld, endpoint->bInterval);
-	yld->urb_irq->transfer_dma = yld->irq_dma;
-	yld->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	yld->urb_irq->dev = udev;
-
-	/* initialise ctl urb */
-	yld->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-				      USB_DIR_OUT;
-	yld->ctl_req->bRequest	= USB_REQ_SET_CONFIGURATION;
-	yld->ctl_req->wValue	= cpu_to_le16(0x200);
-	yld->ctl_req->wIndex	= cpu_to_le16(interface->desc.bInterfaceNumber);
-	yld->ctl_req->wLength	= cpu_to_le16(USB_PKT_LEN);
-
-	usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
-			(void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN,
-			urb_ctl_callback, yld);
-	yld->urb_ctl->setup_dma	= yld->ctl_req_dma;
-	yld->urb_ctl->transfer_dma	= yld->ctl_dma;
-	yld->urb_ctl->transfer_flags	|= URB_NO_SETUP_DMA_MAP |
-					URB_NO_TRANSFER_DMA_MAP;
-	yld->urb_ctl->dev = udev;
-
-	/* find out the physical bus location */
-	usb_make_path(udev, yld->phys, sizeof(yld->phys));
-	strlcat(yld->phys,  "/input0", sizeof(yld->phys));
-
-	/* register settings for the input device */
-	input_dev->name = nfo->name;
-	input_dev->phys = yld->phys;
-	usb_to_input_id(udev, &input_dev->id);
-	input_dev->cdev.dev = &intf->dev;
-
-	input_dev->private = yld;
-	input_dev->open = input_open;
-	input_dev->close = input_close;
-	/* input_dev->event = input_ev;	TODO */
-
-	/* register available key events */
-	input_dev->evbit[0] = BIT(EV_KEY);
-	for (i = 0; i < 256; i++) {
-		int k = map_p1k_to_key(i);
-		if (k >= 0) {
-			set_bit(k & 0xff, input_dev->keybit);
-			if (k >> 8)
-				set_bit(k >> 8, input_dev->keybit);
-		}
-	}
-
-	input_register_device(yld->idev);
-
-	usb_set_intfdata(intf, yld);
-
-	/* clear visible elements */
-	for (i = 0; i < ARRAY_SIZE(lcdMap); i++)
-		setChar(yld, i, ' ');
-
-	/* display driver version on LCD line 3 */
-	store_line3(&intf->dev, NULL,
-			DRIVER_VERSION, sizeof(DRIVER_VERSION));
-
-	/* Register sysfs hooks (don't care about failure) */
-	ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
-	return 0;
-}
-
-static struct usb_driver yealink_driver = {
-	.name		= "yealink",
-	.probe		= usb_probe,
-	.disconnect	= usb_disconnect,
-	.id_table	= usb_table,
-};
-
-static int __init yealink_dev_init(void)
-{
-	int ret = usb_register(&yealink_driver);
-	if (ret == 0)
-		info(DRIVER_DESC ":" DRIVER_VERSION);
-	return ret;
-}
-
-static void __exit yealink_dev_exit(void)
-{
-	usb_deregister(&yealink_driver);
-}
-
-module_init(yealink_dev_init);
-module_exit(yealink_dev_exit);
-
-MODULE_DEVICE_TABLE (usb, usb_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/yealink.h b/drivers/usb/input/yealink.h
deleted file mode 100644
index 48af0be..0000000
--- a/drivers/usb/input/yealink.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * drivers/usb/input/yealink.h
- *
- * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@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
- */
-#ifndef INPUT_YEALINK_H
-#define INPUT_YEALINK_H
-
-/* Using the control channel on interface 3 various aspects of the phone
- * can be controlled like LCD, LED, dialtone and the ringtone.
- */
-
-struct yld_ctl_packet {
-	u8	cmd;		/* command code, see below */
-	u8	size;		/* 1-11, size of used data bytes. */
-	u16	offset;		/* internal packet offset */
-	u8	data[11];
-	s8	sum;		/* negative sum of 15 preceding bytes */
-} __attribute__ ((packed));
-
-#define USB_PKT_LEN	sizeof(struct yld_ctl_packet)
-
-/* The following yld_ctl_packet's are available: */
-
-/* Init registers
- *
- * cmd		0x8e
- * size		10
- * offset	0
- * data		0,0,0,0....
- */
-#define CMD_INIT		0x8e
-
-/* Request key scan
- *
- * cmd		0x80
- * size		1
- * offset	0
- * data[0]	on return returns the key number, if it changes there's a new
- * 		key pressed.
- */
-#define CMD_KEYPRESS		0x80
-
-/* Request scancode
- *
- * cmd		0x81
- * size		1
- * offset	key number [0-1f]
- * data[0]	on return returns the scancode
- */
-#define CMD_SCANCODE		0x81
-
-/* Set LCD
- *
- * cmd		0x04
- * size		1-11
- * offset	0-23
- * data		segment bits
- */
-#define CMD_LCD			0x04
-
-/* Set led
- *
- * cmd		0x05
- * size		1
- * offset	0
- * data[0]	0 OFF / 1 ON
- */
-#define CMD_LED			0x05
-
-/* Set ringtone volume
- *
- * cmd		0x11
- * size		1
- * offset	0
- * data[0]	0-0xff  volume
- */
-#define CMD_RING_VOLUME		0x11
-
-/* Set ringtone notes
- *
- * cmd		0x02
- * size		1-11
- * offset	0->
- * data		binary representation LE16(-freq), LE16(duration) ....
- */
-#define CMD_RING_NOTE		0x02
-
-/* Sound ringtone via the speaker on the back
- *
- * cmd		0x03
- * size		1
- * offset	0
- * data[0]	0 OFF / 0x24 ON
- */
-#define CMD_RINGTONE		0x03
-
-/* Sound dial tone via the ear speaker
- *
- * cmd		0x09
- * size		1
- * offset	0
- * data[0]	0 OFF / 1 ON
- */
-#define CMD_DIALTONE		0x09
-
-#endif /* INPUT_YEALINK_H */
-
-
-#if defined(_SEG) && defined(_PIC)
-/* This table maps the LCD segments onto individual bit positions in the
- * yld_status struct.
- */
-
-/* LCD, each segment must be driven seperately.
- *
- * Layout:
- *
- *   |[]   [][]   [][]   [][]   in   |[][]
- *   |[] M [][] D [][] : [][]   out  |[][]
- *                             store
- *
- *    NEW REP         SU MO TU WE TH FR SA
- *
- *    [] [] [] [] [] [] [] [] [] [] [] []
- *    [] [] [] [] [] [] [] [] [] [] [] []
- */
-
-/* Line 1
- *	Format		: 18.e8.M8.88...188
- *	Icon names	: M D : IN OUT STORE
- */
-#define LCD_LINE1_OFFSET	0
-#define LCD_LINE1_SIZE		17
-
-/* Note: first g then f =>			       !      !      */
-/* _SEG(    type    a      b      c      d      e      g      f   )  */
-	_SEG('1',  0,0 , 22,2 , 22,2 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
-	_SEG('8', 20,1 , 20,2 , 20,4 , 20,8 , 21,4 , 21,2 , 21,1	),
-	_PIC('.', 22,1 , "M"						),
-	_SEG('e', 18,1 , 18,2 , 18,4 , 18,1 , 19,2 , 18,1 , 19,1	),
-	_SEG('8', 16,1 , 16,2 , 16,4 , 16,8 , 17,4 , 17,2 , 17,1	),
-	_PIC('.', 15,8 , "D"						),
-	_SEG('M', 14,1 , 14,2 , 14,4 , 14,1 , 15,4 , 15,2 , 15,1	),
-	_SEG('8', 12,1 , 12,2 , 12,4 , 12,8 , 13,4 , 13,2 , 13,1	),
-	_PIC('.', 11,8 , ":"						),
-	_SEG('8', 10,1 , 10,2 , 10,4 , 10,8 , 11,4 , 11,2 , 11,1	),
-	_SEG('8',  8,1 ,  8,2 ,  8,4 ,  8,8 ,  9,4 ,  9,2 ,  9,1	),
-	_PIC('.',  7,1 , "IN"						),
-	_PIC('.',  7,2 , "OUT"						),
-	_PIC('.',  7,4 , "STORE"					),
-	_SEG('1',  0,0 ,  5,1 ,  5,1 ,  0,0 ,  0,0 ,  0,0 ,  0,0	),
-	_SEG('8',  4,1 ,  4,2 ,  4,4 ,  4,8 ,  5,8 ,  5,4 ,  5,2	),
-	_SEG('8',  2,1 ,  2,2 ,  2,4 ,  2,8 ,  3,4 ,  3,2 ,  3,1	),
-
-/* Line 2
- *	Format		: .........
- *	Pict. name	: NEW REP SU MO TU WE TH FR SA
- */
-#define LCD_LINE2_OFFSET	LCD_LINE1_OFFSET + LCD_LINE1_SIZE
-#define LCD_LINE2_SIZE		9
-
-	_PIC('.', 23,2 , "NEW"	),
-	_PIC('.', 23,4 , "REP"	),
-	_PIC('.',  1,8 , "SU"	),
-	_PIC('.',  1,4 , "MO"	),
-	_PIC('.',  1,2 , "TU"	),
-	_PIC('.',  1,1 , "WE"	),
-	_PIC('.',  0,1 , "TH"	),
-	_PIC('.',  0,2 , "FR"	),
-	_PIC('.',  0,4 , "SA"	),
-
-/* Line 3
- *	Format		: 888888888888
- */
-#define LCD_LINE3_OFFSET	LCD_LINE2_OFFSET + LCD_LINE2_SIZE
-#define LCD_LINE3_SIZE		12
-
-	_SEG('8', 22,16, 22,32, 22,64, 22,128, 23,128, 23,64, 23,32  ),
-	_SEG('8', 20,16, 20,32, 20,64, 20,128, 21,128, 21,64, 21,32  ),
-	_SEG('8', 18,16, 18,32, 18,64, 18,128, 19,128, 19,64, 19,32  ),
-	_SEG('8', 16,16, 16,32, 16,64, 16,128, 17,128, 17,64, 17,32  ),
-	_SEG('8', 14,16, 14,32, 14,64, 14,128, 15,128, 15,64, 15,32  ),
-	_SEG('8', 12,16, 12,32, 12,64, 12,128, 13,128, 13,64, 13,32  ),
-	_SEG('8', 10,16, 10,32, 10,64, 10,128, 11,128, 11,64, 11,32  ),
-	_SEG('8',  8,16,  8,32,  8,64,  8,128,  9,128,  9,64,  9,32  ),
-	_SEG('8',  6,16,  6,32,  6,64,  6,128,  7,128,  7,64,  7,32  ),
-	_SEG('8',  4,16,  4,32,  4,64,  4,128,  5,128,  5,64,  5,32  ),
-	_SEG('8',  2,16,  2,32,  2,64,  2,128,  3,128,  3,64,  3,32  ),
-	_SEG('8',  0,16,  0,32,  0,64,  0,128,  1,128,  1,64,  1,32  ),
-
-/* Line 4
- *
- * The LED, DIALTONE and RINGTONE are implemented as icons and use the same
- * sysfs interface.
- */
-#define LCD_LINE4_OFFSET	LCD_LINE3_OFFSET + LCD_LINE3_SIZE
-
-	_PIC('.', offsetof(struct yld_status, led)	, 0x01, "LED" ),
-	_PIC('.', offsetof(struct yld_status, dialtone) , 0x01, "DIALTONE" ),
-	_PIC('.', offsetof(struct yld_status, ringtone) , 0x24, "RINGTONE" ),
-
-#undef _SEG
-#undef _PIC
-#endif /* _SEG && _PIC */
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 75bfab9..77145f9 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -285,23 +285,24 @@ static int adu_open(struct inode *inode,
 	/* 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 */
+	if (dev->open_count == 1) {
+		/* 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;
+		retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+		if (retval)
+			--dev->open_count;
+	}
 	up(&dev->sem);
 
 exit_no_device:
@@ -469,7 +470,7 @@ static ssize_t adu_read(struct file *fil
 							 adu_interrupt_in_callback,
 							 dev,
 							 dev->interrupt_in_endpoint->bInterval);
-					retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+					retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
 					if (!retval) {
 						spin_unlock_irqrestore(&dev->buflock, flags);
 						dbg(2," %s : submitted OK", __FUNCTION__);
@@ -539,7 +540,7 @@ static ssize_t adu_write(struct file *fi
 	size_t bytes_written = 0;
 	size_t bytes_to_write;
 	size_t buffer_size;
-	int retval = 0;
+	int retval;
 	int timeout = 0;
 
 	dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
@@ -547,7 +548,9 @@ static ssize_t adu_write(struct file *fi
 	dev = file->private_data;
 
 	/* lock this object */
-	down_interruptible(&dev->sem);
+	retval = down_interruptible(&dev->sem);
+	if (retval)
+		goto exit_nolock;
 
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL || dev->minor == 0) {
@@ -575,7 +578,11 @@ static ssize_t adu_write(struct file *fi
 			}
 			up(&dev->sem);
 			timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
-			down_interruptible(&dev->sem);
+			retval = down_interruptible(&dev->sem);
+			if (retval) {
+				retval = bytes_written ? bytes_written : retval;
+				goto exit_nolock;
+			}
 			if (timeout > 0) {
 				break;
 			}
@@ -637,6 +644,7 @@ static ssize_t adu_write(struct file *fi
 exit:
 	/* unlock the device */
 	up(&dev->sem);
+exit_nolock:
 
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
 
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index b63b5f3..d721380 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -246,11 +246,13 @@ static void cypress_disconnect(struct us
 	struct cypress *dev;
 
 	dev = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
 
 	/* remove device attribute files */
 	device_remove_file(&interface->dev, &dev_attr_port0);
 	device_remove_file(&interface->dev, &dev_attr_port1);
+	/* the intfdata can be set to NULL only after the
+	 * device files have been removed */
+	usb_set_intfdata(interface, NULL);
 
 	usb_put_dev(dev->udev);
 
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index bc3327e..e2172e5 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2304,7 +2304,6 @@ #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
 #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
 #define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
         OHCI_INTR_WDH)
@@ -2910,24 +2909,28 @@ static int __init ftdi_elan_init(void)
         INIT_LIST_HEAD(&ftdi_static_list);
         status_queue = create_singlethread_workqueue("ftdi-status-control");
 	if (!status_queue)
-		goto err1;
+		goto err_status_queue;
         command_queue = create_singlethread_workqueue("ftdi-command-engine");
 	if (!command_queue)
-		goto err2;
+		goto err_command_queue;
         respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
 	if (!respond_queue)
-		goto err3;
+		goto err_respond_queue;
         result = usb_register(&ftdi_elan_driver);
-        if (result)
+        if (result) {
+		destroy_workqueue(status_queue);
+		destroy_workqueue(command_queue);
+		destroy_workqueue(respond_queue);
                 printk(KERN_ERR "usb_register failed. Error number %d\n",
 		       result);
+	}
         return result;
 
- err3:
+ err_respond_queue:
 	destroy_workqueue(command_queue);
- err2:
+ err_command_queue:
 	destroy_workqueue(status_queue);
- err1:
+ err_status_queue:
 	printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name);
 	return -ENOMEM;
 }
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 15c70bd..8d0e360 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -22,7 +22,6 @@ #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index d69665c..fc51207 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -118,7 +118,7 @@ static int usb_get_report(struct usb_dev
 			       USB_DIR_IN | USB_TYPE_CLASS |
 			       USB_RECIP_INTERFACE, (type << 8) + id,
 			       inter->desc.bInterfaceNumber, buf, size,
-			       GET_TIMEOUT);
+			       GET_TIMEOUT*HZ);
 }
 //#endif
 
@@ -133,7 +133,7 @@ static int usb_set_report(struct usb_int
 			       USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			       (type << 8) + id,
 			       intf->cur_altsetting->desc.bInterfaceNumber, buf,
-			       size, 1);
+			       size, HZ);
 }
 
 /*---------------------*/
@@ -417,14 +417,14 @@ static ssize_t iowarrior_write(struct fi
 		if (!int_out_urb) {
 			retval = -ENOMEM;
 			dbg("%s Unable to allocate urb ", __func__);
-			goto error;
+			goto error_no_urb;
 		}
 		buf = usb_buffer_alloc(dev->udev, dev->report_size,
 				       GFP_KERNEL, &int_out_urb->transfer_dma);
 		if (!buf) {
 			retval = -ENOMEM;
 			dbg("%s Unable to allocate buffer ", __func__);
-			goto error;
+			goto error_no_buffer;
 		}
 		usb_fill_int_urb(int_out_urb, dev->udev,
 				 usb_sndintpipe(dev->udev,
@@ -459,7 +459,9 @@ static ssize_t iowarrior_write(struct fi
 error:
 	usb_buffer_free(dev->udev, dev->report_size, buf,
 			int_out_urb->transfer_dma);
+error_no_buffer:
 	usb_free_urb(int_out_urb);
+error_no_urb:
 	atomic_dec(&dev->write_busy);
 	wake_up_interruptible(&dev->write_wait);
 exit:
@@ -748,7 +750,6 @@ static int iowarrior_probe(struct usb_in
 	struct usb_endpoint_descriptor *endpoint;
 	int i;
 	int retval = -ENOMEM;
-	int idele = 0;
 
 	/* allocate memory for our device state and intialize it */
 	dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
@@ -824,11 +825,10 @@ static int iowarrior_probe(struct usb_in
 
 	/* Set the idle timeout to 0, if this is interface 0 */
 	if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) {
-		idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-					0x0A,
-					USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
-					0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-		dbg("idele = %d", idele);
+	    usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			    0x0A,
+			    USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+			    0, NULL, 0, USB_CTRL_SET_TIMEOUT);
 	}
 	/* allow device read and ioctl */
 	dev->present = 1;
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 788a11e..11555bd 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -62,6 +62,8 @@ #define USB_DEVICE_ID_VERNIER_GOTEMP	0x0
 #define USB_DEVICE_ID_VERNIER_SKIP	0x0003
 #define USB_DEVICE_ID_VERNIER_CYCLOPS	0x0004
 
+#define USB_VENDOR_ID_MICROCHIP		0x04d8
+#define USB_DEVICE_ID_PICDEM		0x000c
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 #define USB_LD_MINOR_BASE	0
@@ -89,6 +91,7 @@ static struct usb_device_id ld_usb_table
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
 	{ USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+	{ USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
 	{ }					/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, ld_usb_table);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 5dce797..1713e19 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -80,7 +80,6 @@ #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index fdf6847..88f6abe 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -39,7 +39,6 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 
 #include "rio500_usb.h"
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 1730d86..5947afb 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -62,7 +62,6 @@ #include <linux/vt_kern.h>
 #include <linux/selection.h>
 #include <linux/spinlock.h>
 #include <linux/kref.h>
-#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
@@ -322,7 +321,7 @@ sisusbcon_deinit(struct vc_data *c)
 /* interface routine */
 static u8
 sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
-			    u8 blink, u8 underline, u8 reverse)
+			    u8 blink, u8 underline, u8 reverse, u8 unused)
 {
 	u8 attr = color;
 
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index ada2ebc..887ef95 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -47,6 +47,7 @@ struct usb_lcd {
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
 static struct usb_driver lcd_driver;
+static DEFINE_MUTEX(usb_lcd_open_mutex);
 
 
 static void lcd_delete(struct kref *kref)
@@ -68,6 +69,7 @@ static int lcd_open(struct inode *inode,
 
 	subminor = iminor(inode);
 
+	mutex_lock(&usb_lcd_open_mutex);
 	interface = usb_find_interface(&lcd_driver, subminor);
 	if (!interface) {
 		err ("USBLCD: %s - error, can't find device for minor %d",
@@ -89,6 +91,7 @@ static int lcd_open(struct inode *inode,
 	file->private_data = dev;
 
 exit:
+	mutex_unlock(&usb_lcd_open_mutex);
 	return retval;
 }
 
@@ -347,7 +350,7 @@ static void lcd_disconnect(struct usb_in
         int minor = interface->minor;
 
         /* prevent skel_open() from racing skel_disconnect() */
-        lock_kernel();
+        mutex_lock(&usb_lcd_open_mutex);
 
         dev = usb_get_intfdata(interface);
         usb_set_intfdata(interface, NULL);
@@ -355,7 +358,7 @@ static void lcd_disconnect(struct usb_in
         /* give back our minor */
         usb_deregister_dev(interface, &lcd_class);
  
-	unlock_kernel();
+	mutex_unlock(&usb_lcd_open_mutex);
 
 	/* decrement our usage count */
 	kref_put(&dev->kref, lcd_delete);
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index b2bedd9..0af11a6 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -356,8 +356,10 @@ static inline char mon_bin_get_setup(uns
 	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
 		return '-';
 
-	if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+	if (urb->dev->bus->uses_dma &&
+	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
 		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+	}
 	if (urb->setup_packet == NULL)
 		return 'Z';
 
@@ -369,7 +371,8 @@ static char mon_bin_get_data(const struc
     unsigned int offset, struct urb *urb, unsigned int length)
 {
 
-	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+	if (urb->dev->bus->uses_dma &&
+	    (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
 		mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
 		return 0;
 	}
@@ -440,7 +443,7 @@ static void mon_bin_event(struct mon_rea
 	/* We use the fact that usb_pipein() returns 0x80 */
 	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
 	ep->devnum = usb_pipedevice(urb->pipe);
-	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_usec = ts.tv_usec;
@@ -500,7 +503,7 @@ static void mon_bin_error(void *data, st
 	/* We use the fact that usb_pipein() returns 0x80 */
 	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
 	ep->devnum = usb_pipedevice(urb->pipe);
-	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->status = error;
 
@@ -515,7 +518,6 @@ static void mon_bin_error(void *data, st
 static int mon_bin_open(struct inode *inode, struct file *file)
 {
 	struct mon_bus *mbus;
-	struct usb_bus *ubus;
 	struct mon_reader_bin *rp;
 	size_t size;
 	int rc;
@@ -525,7 +527,7 @@ static int mon_bin_open(struct inode *in
 		mutex_unlock(&mon_lock);
 		return -ENODEV;
 	}
-	if ((ubus = mbus->u_bus) == NULL) {
+	if (mbus != &mon_bus0 && mbus->u_bus == NULL) {
 		printk(KERN_ERR TAG ": consistency error on open\n");
 		mutex_unlock(&mon_lock);
 		return -ENODEV;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index c9739e7..8977ec0 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,15 +9,12 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
 
 #include "usb_mon.h"
 #include "../core/hcd.h"
 
-static void mon_submit(struct usb_bus *ubus, struct urb *urb);
-static void mon_complete(struct usb_bus *ubus, struct urb *urb);
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
@@ -25,6 +22,7 @@ static void mon_bus_init(struct usb_bus 
 
 DEFINE_MUTEX(mon_lock);
 
+struct mon_bus mon_bus0;		/* Pseudo bus meaning "all buses" */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
 
 /*
@@ -35,22 +33,19 @@ static LIST_HEAD(mon_buses);		/* All bus
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
 {
 	unsigned long flags;
-	struct usb_bus *ubus;
+	struct list_head *p;
 
 	spin_lock_irqsave(&mbus->lock, flags);
 	if (mbus->nreaders == 0) {
-		ubus = mbus->u_bus;
-		if (ubus->monitored) {
-			/*
-			 * Something is really broken, refuse to go on and
-			 * possibly corrupt ops pointers or worse.
-			 */
-			printk(KERN_ERR TAG ": bus %d is already monitored\n",
-			    ubus->busnum);
-			spin_unlock_irqrestore(&mbus->lock, flags);
-			return;
+		if (mbus == &mon_bus0) {
+			list_for_each (p, &mon_buses) {
+				struct mon_bus *m1;
+				m1 = list_entry(p, struct mon_bus, bus_link);
+				m1->u_bus->monitored = 1;
+			}
+		} else {
+			mbus->u_bus->monitored = 1;
 		}
-		ubus->monitored = 1;
 	}
 	mbus->nreaders++;
 	list_add_tail(&r->r_link, &mbus->r_list);
@@ -80,77 +75,79 @@ void mon_reader_del(struct mon_bus *mbus
 
 /*
  */
-static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb)
 {
-	struct mon_bus *mbus;
 	unsigned long flags;
 	struct list_head *pos;
 	struct mon_reader *r;
 
-	mbus = ubus->mon_bus;
-	if (mbus == NULL)
-		goto out_unlocked;
-
 	spin_lock_irqsave(&mbus->lock, flags);
-	if (mbus->nreaders == 0)
-		goto out_locked;
-
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
 		r->rnf_submit(r->r_data, urb);
 	}
-
 	spin_unlock_irqrestore(&mbus->lock, flags);
 	return;
+}
 
-out_locked:
-	spin_unlock_irqrestore(&mbus->lock, flags);
-out_unlocked:
-	return;
+static void mon_submit(struct usb_bus *ubus, struct urb *urb)
+{
+	struct mon_bus *mbus;
+
+	if ((mbus = ubus->mon_bus) != NULL)
+		mon_bus_submit(mbus, urb);
+	mon_bus_submit(&mon_bus0, urb);
 }
 
 /*
  */
-static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
+static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error)
 {
-	struct mon_bus *mbus;
 	unsigned long flags;
 	struct list_head *pos;
 	struct mon_reader *r;
 
-	mbus = ubus->mon_bus;
-	if (mbus == NULL)
-		goto out_unlocked;
-
 	spin_lock_irqsave(&mbus->lock, flags);
-	if (mbus->nreaders == 0)
-		goto out_locked;
-
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
 		r->rnf_error(r->r_data, urb, error);
 	}
-
 	spin_unlock_irqrestore(&mbus->lock, flags);
 	return;
+}
 
-out_locked:
-	spin_unlock_irqrestore(&mbus->lock, flags);
-out_unlocked:
-	return;
+static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
+{
+	struct mon_bus *mbus;
+
+	if ((mbus = ubus->mon_bus) != NULL)
+		mon_bus_submit_error(mbus, urb, error);
+	mon_bus_submit_error(&mon_bus0, urb, error);
 }
 
 /*
  */
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
 {
-	struct mon_bus *mbus;
 	unsigned long flags;
 	struct list_head *pos;
 	struct mon_reader *r;
 
+	spin_lock_irqsave(&mbus->lock, flags);
+	mbus->cnt_events++;
+	list_for_each (pos, &mbus->r_list) {
+		r = list_entry(pos, struct mon_reader, r_link);
+		r->rnf_complete(r->r_data, urb);
+	}
+	spin_unlock_irqrestore(&mbus->lock, flags);
+}
+
+static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+{
+	struct mon_bus *mbus;
+
 	mbus = ubus->mon_bus;
 	if (mbus == NULL) {
 		/*
@@ -162,13 +159,8 @@ static void mon_complete(struct usb_bus 
 		return;
 	}
 
-	spin_lock_irqsave(&mbus->lock, flags);
-	mbus->cnt_events++;
-	list_for_each (pos, &mbus->r_list) {
-		r = list_entry(pos, struct mon_reader, r_link);
-		r->rnf_complete(r->r_data, urb);
-	}
-	spin_unlock_irqrestore(&mbus->lock, flags);
+	mon_bus_complete(mbus, urb);
+	mon_bus_complete(&mon_bus0, urb);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -179,14 +171,26 @@ static void mon_complete(struct usb_bus 
 static void mon_stop(struct mon_bus *mbus)
 {
 	struct usb_bus *ubus = mbus->u_bus;
+	struct list_head *p;
 
-	/*
-	 * A stop can be called for a dissolved mon_bus in case of
-	 * a reader staying across an rmmod foo_hcd.
-	 */
-	if (ubus != NULL) {
-		ubus->monitored = 0;
-		mb();
+	if (mbus == &mon_bus0) {
+		list_for_each (p, &mon_buses) {
+			mbus = list_entry(p, struct mon_bus, bus_link);
+			/*
+			 * We do not change nreaders here, so rely on mon_lock.
+			 */
+			if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL)
+				ubus->monitored = 0;
+		}
+	} else {
+		/*
+		 * A stop can be called for a dissolved mon_bus in case of
+		 * a reader staying across an rmmod foo_hcd, so test ->u_bus.
+		 */
+		if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) {
+			ubus->monitored = 0;
+			mb();
+		}
 	}
 }
 
@@ -199,6 +203,10 @@ static void mon_stop(struct mon_bus *mbu
 static void mon_bus_add(struct usb_bus *ubus)
 {
 	mon_bus_init(ubus);
+	mutex_lock(&mon_lock);
+	if (mon_bus0.nreaders != 0)
+		ubus->monitored = 1;
+	mutex_unlock(&mon_lock);
 }
 
 /*
@@ -250,12 +258,7 @@ static struct usb_mon_operations mon_ops
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
 {
 
-	/*
-	 * Never happens, but...
-	 */
 	if (ubus->monitored) {
-		printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
-		    ubus->busnum);
 		ubus->monitored = 0;
 		mb();
 	}
@@ -263,6 +266,8 @@ static void mon_dissolve(struct mon_bus 
 	ubus->mon_bus = NULL;
 	mbus->u_bus = NULL;
 	mb();
+
+	/* We want synchronize_irq() here, but that needs an argument. */
 }
 
 /*
@@ -295,9 +300,8 @@ static void mon_bus_init(struct usb_bus 
 	 */
 	mbus->u_bus = ubus;
 	ubus->mon_bus = mbus;
-	mbus->uses_dma = ubus->uses_dma;
 
-	mbus->text_inited = mon_text_add(mbus, ubus);
+	mbus->text_inited = mon_text_add(mbus, ubus->busnum);
 	// mon_bin_add(...)
 
 	mutex_lock(&mon_lock);
@@ -309,6 +313,18 @@ err_alloc:
 	return;
 }
 
+static void mon_bus0_init(void)
+{
+	struct mon_bus *mbus = &mon_bus0;
+
+	kref_init(&mbus->ref);
+	spin_lock_init(&mbus->lock);
+	INIT_LIST_HEAD(&mbus->r_list);
+
+	mbus->text_inited = mon_text_add(mbus, 0);
+	// mbus->bin_inited = mon_bin_add(mbus, 0);
+}
+
 /*
  * Search a USB bus by number. Notice that USB bus numbers start from one,
  * which we may later use to identify "all" with zero.
@@ -322,6 +338,9 @@ struct mon_bus *mon_bus_lookup(unsigned 
 	struct list_head *p;
 	struct mon_bus *mbus;
 
+	if (num == 0) {
+		return &mon_bus0;
+	}
 	list_for_each (p, &mon_buses) {
 		mbus = list_entry(p, struct mon_bus, bus_link);
 		if (mbus->u_bus->busnum == num) {
@@ -341,6 +360,8 @@ static int __init mon_init(void)
 	if ((rc = mon_bin_init()) != 0)
 		goto err_bin;
 
+	mon_bus0_init();
+
 	if (usb_mon_register(&mon_ops_0) != 0) {
 		printk(KERN_NOTICE TAG ": unable to register with the core\n");
 		rc = -ENODEV;
@@ -374,6 +395,7 @@ static void __exit mon_exit(void)
 	usb_mon_deregister();
 
 	mutex_lock(&mon_lock);
+
 	while (!list_empty(&mon_buses)) {
 		p = mon_buses.next;
 		mbus = list_entry(p, struct mon_bus, bus_link);
@@ -397,6 +419,11 @@ static void __exit mon_exit(void)
 		mon_dissolve(mbus, mbus->u_bus);
 		kref_put(&mbus->ref, mon_bus_drop);
 	}
+
+	mbus = &mon_bus0;
+	if (mbus->text_inited)
+		mon_text_del(mbus);
+
 	mutex_unlock(&mon_lock);
 
 	mon_text_exit();
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 494ee3b..ec0cc51 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -31,9 +31,21 @@ #define SETUP_MAX  8
  * to a local DoS. But we have to keep to root in order to prevent
  * password sniffing from HID devices.
  */
-#define EVENT_MAX  (2*PAGE_SIZE / sizeof(struct mon_event_text))
+#define EVENT_MAX  (4*PAGE_SIZE / sizeof(struct mon_event_text))
 
-#define PRINTF_DFL  160
+/*
+ * Potentially unlimited number; we limit it for similar allocations.
+ * The usbfs limits this to 128, but we're not quite as generous.
+ */
+#define ISODESC_MAX   5
+
+#define PRINTF_DFL  250   /* with 5 ISOs segs */
+
+struct mon_iso_desc {
+	int status;
+	unsigned int offset;
+	unsigned int length;	/* Unsigned here, signed in URB. Historic. */
+};
 
 struct mon_event_text {
 	struct list_head e_link;
@@ -41,10 +53,16 @@ struct mon_event_text {
 	unsigned int pipe;	/* Pipe */
 	unsigned long id;	/* From pointer, most of the time */
 	unsigned int tstamp;
+	int busnum;
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
+	int interval;
+	int start_frame;
+	int error_count;
 	char setup_flag;
 	char data_flag;
+	int numdesc;		/* Full number */
+	struct mon_iso_desc isodesc[ISODESC_MAX];
 	unsigned char setup[SETUP_MAX];
 	unsigned char data[DATA_MAX];
 };
@@ -68,6 +86,28 @@ static struct dentry *mon_dir;		/* Usual
 
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
+struct mon_text_ptr {
+	int cnt, limit;
+	char *pbuf;
+};
+
+static struct mon_event_text *
+    mon_text_read_wait(struct mon_reader_text *rp, struct file *file);
+static void mon_text_read_head_t(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_head_u(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_statset(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_intstat(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_isostat(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_isodesc(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep);
+static void mon_text_read_data(struct mon_reader_text *rp,
+    struct mon_text_ptr *p, const struct mon_event_text *ep);
+
 /*
  * mon_text_submit
  * mon_text_complete
@@ -84,8 +124,10 @@ static inline char mon_text_get_setup(st
 	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
 		return '-';
 
-	if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+	if (urb->dev->bus->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. */
 
@@ -104,10 +146,10 @@ static inline char mon_text_get_data(str
 		len = DATA_MAX;
 
 	if (usb_pipein(pipe)) {
-		if (ev_type == 'S')
+		if (ev_type != 'C')
 			return '<';
 	} else {
-		if (ev_type == 'C')
+		if (ev_type != 'S')
 			return '>';
 	}
 
@@ -120,8 +162,10 @@ 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 (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+	if (urb->dev->bus->uses_dma &&
+	    (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
 		return mon_dmapeek(ep->data, urb->transfer_dma, len);
+	}
 
 	if (urb->transfer_buffer == NULL)
 		return 'Z';	/* '0' would be not as pretty. */
@@ -146,6 +190,9 @@ static void mon_text_event(struct mon_re
 {
 	struct mon_event_text *ep;
 	unsigned int stamp;
+	struct usb_iso_packet_descriptor *fp;
+	struct mon_iso_desc *dp;
+	int i, ndesc;
 
 	stamp = mon_get_timestamp();
 
@@ -158,12 +205,36 @@ static void mon_text_event(struct mon_re
 	ep->type = ev_type;
 	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
+	ep->busnum = urb->dev->bus->busnum;
 	ep->tstamp = stamp;
 	ep->length = (ev_type == 'S') ?
 	    urb->transfer_buffer_length : urb->actual_length;
 	/* Collecting status makes debugging sense for submits, too */
 	ep->status = urb->status;
 
+	if (usb_pipeint(urb->pipe)) {
+		ep->interval = urb->interval;
+	} else if (usb_pipeisoc(urb->pipe)) {
+		ep->interval = urb->interval;
+		ep->start_frame = urb->start_frame;
+		ep->error_count = urb->error_count;
+	}
+	ep->numdesc = urb->number_of_packets;
+	if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+		if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
+			ndesc = ISODESC_MAX;
+		fp = urb->iso_frame_desc;
+		dp = ep->isodesc;
+		for (i = 0; i < ndesc; i++) {
+			dp->status = fp->status;
+			dp->offset = fp->offset;
+			dp->length = (ev_type == 'S') ?
+			    fp->length : fp->actual_length;
+			fp++;
+			dp++;
+		}
+	}
+
 	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);
@@ -199,6 +270,7 @@ static void mon_text_error(void *data, s
 	ep->type = 'E';
 	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
+	ep->busnum = 0;
 	ep->tstamp = 0;
 	ep->length = 0;
 	ep->status = error;
@@ -237,13 +309,11 @@ static struct mon_event_text *mon_text_f
 static int mon_text_open(struct inode *inode, struct file *file)
 {
 	struct mon_bus *mbus;
-	struct usb_bus *ubus;
 	struct mon_reader_text *rp;
 	int rc;
 
 	mutex_lock(&mon_lock);
 	mbus = inode->i_private;
-	ubus = mbus->u_bus;
 
 	rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
 	if (rp == NULL) {
@@ -267,8 +337,7 @@ static int mon_text_open(struct inode *i
 	rp->r.rnf_error = mon_text_error;
 	rp->r.rnf_complete = mon_text_complete;
 
-	snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum,
-	    (long)rp);
+	snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
 	rp->e_slab = kmem_cache_create(rp->slab_name,
 	    sizeof(struct mon_event_text), sizeof(long), 0,
 	    mon_text_ctor, NULL);
@@ -300,17 +369,75 @@ err_alloc:
  *   dd if=/dbg/usbmon/0t bs=10
  * Also, we do not allow seeks and do not bother advancing the offset.
  */
-static ssize_t mon_text_read(struct file *file, char __user *buf,
+static ssize_t mon_text_read_t(struct file *file, char __user *buf,
 				size_t nbytes, loff_t *ppos)
 {
 	struct mon_reader_text *rp = file->private_data;
+	struct mon_event_text *ep;
+	struct mon_text_ptr ptr;
+
+	if (IS_ERR(ep = mon_text_read_wait(rp, file)))
+		return PTR_ERR(ep);
+	mutex_lock(&rp->printf_lock);
+	ptr.cnt = 0;
+	ptr.pbuf = rp->printf_buf;
+	ptr.limit = rp->printf_size;
+
+	mon_text_read_head_t(rp, &ptr, ep);
+	mon_text_read_statset(rp, &ptr, ep);
+	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+	    " %d", ep->length);
+	mon_text_read_data(rp, &ptr, ep);
+
+	if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
+		ptr.cnt = -EFAULT;
+	mutex_unlock(&rp->printf_lock);
+	kmem_cache_free(rp->e_slab, ep);
+	return ptr.cnt;
+}
+
+static ssize_t mon_text_read_u(struct file *file, char __user *buf,
+				size_t nbytes, loff_t *ppos)
+{
+	struct mon_reader_text *rp = file->private_data;
+	struct mon_event_text *ep;
+	struct mon_text_ptr ptr;
+
+	if (IS_ERR(ep = mon_text_read_wait(rp, file)))
+		return PTR_ERR(ep);
+	mutex_lock(&rp->printf_lock);
+	ptr.cnt = 0;
+	ptr.pbuf = rp->printf_buf;
+	ptr.limit = rp->printf_size;
+
+	mon_text_read_head_u(rp, &ptr, ep);
+	if (ep->type == 'E') {
+		mon_text_read_statset(rp, &ptr, ep);
+	} else if (usb_pipeisoc(ep->pipe)) {
+		mon_text_read_isostat(rp, &ptr, ep);
+		mon_text_read_isodesc(rp, &ptr, ep);
+	} else if (usb_pipeint(ep->pipe)) {
+		mon_text_read_intstat(rp, &ptr, ep);
+	} else {
+		mon_text_read_statset(rp, &ptr, ep);
+	}
+	ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+	    " %d", ep->length);
+	mon_text_read_data(rp, &ptr, ep);
+
+	if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
+		ptr.cnt = -EFAULT;
+	mutex_unlock(&rp->printf_lock);
+	kmem_cache_free(rp->e_slab, ep);
+	return ptr.cnt;
+}
+
+static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
+    struct file *file)
+{
 	struct mon_bus *mbus = rp->r.m_bus;
 	DECLARE_WAITQUEUE(waita, current);
 	struct mon_event_text *ep;
-	int cnt, limit;
-	char *pbuf;
-	char udir, utype;
-	int data_len, i;
 
 	add_wait_queue(&rp->wait, &waita);
 	set_current_state(TASK_INTERRUPTIBLE);
@@ -318,7 +445,7 @@ static ssize_t mon_text_read(struct file
 		if (file->f_flags & O_NONBLOCK) {
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&rp->wait, &waita);
-			return -EWOULDBLOCK;	/* Same as EAGAIN in Linux */
+			return ERR_PTR(-EWOULDBLOCK);
 		}
 		/*
 		 * We do not count nwaiters, because ->release is supposed
@@ -327,17 +454,19 @@ static ssize_t mon_text_read(struct file
 		schedule();
 		if (signal_pending(current)) {
 			remove_wait_queue(&rp->wait, &waita);
-			return -EINTR;
+			return ERR_PTR(-EINTR);
 		}
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&rp->wait, &waita);
+	return ep;
+}
 
-	mutex_lock(&rp->printf_lock);
-	cnt = 0;
-	pbuf = rp->printf_buf;
-	limit = rp->printf_size;
+static void mon_text_read_head_t(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	char udir, utype;
 
 	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
 	switch (usb_pipetype(ep->pipe)) {
@@ -346,13 +475,38 @@ static ssize_t mon_text_read(struct file
 	case PIPE_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
-	cnt += snprintf(pbuf + cnt, limit - cnt,
+	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%03u:%02u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir,
+	    usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+}
+
+static void mon_text_read_head_u(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	char udir, utype;
+
+	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
+	switch (usb_pipetype(ep->pipe)) {
+	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
+	case PIPE_INTERRUPT:	utype = 'I'; break;
+	case PIPE_CONTROL:	utype = 'C'; break;
+	default: /* PIPE_BULK */  utype = 'B';
+	}
+	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+	    "%lx %u %c %c%c:%d:%03u:%u",
+	    ep->id, ep->tstamp, ep->type,
+	    utype, udir,
+	    ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+}
+
+static void mon_text_read_statset(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
 
 	if (ep->setup_flag == 0) {   /* Setup packet is present and captured */
-		cnt += snprintf(pbuf + cnt, limit - cnt,
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 		    " s %02x %02x %04x %04x %04x",
 		    ep->setup[0],
 		    ep->setup[1],
@@ -360,40 +514,86 @@ static ssize_t mon_text_read(struct file
 		    (ep->setup[5] << 8) | ep->setup[4],
 		    (ep->setup[7] << 8) | ep->setup[6]);
 	} else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
-		cnt += snprintf(pbuf + cnt, limit - cnt,
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 		    " %c __ __ ____ ____ ____", ep->setup_flag);
 	} else {                     /* No setup for this kind of URB */
-		cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+		    " %d", ep->status);
 	}
-	cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);
+}
+
+static void mon_text_read_intstat(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+	    " %d:%d", ep->status, ep->interval);
+}
+
+static void mon_text_read_isostat(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	if (ep->type == 'S') {
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+		    " %d:%d:%d", ep->status, ep->interval, ep->start_frame);
+	} else {
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+		    " %d:%d:%d:%d",
+		    ep->status, ep->interval, ep->start_frame, ep->error_count);
+	}
+}
+
+static void mon_text_read_isodesc(struct mon_reader_text *rp,
+	struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	int ndesc;	/* Display this many */
+	int i;
+	const struct mon_iso_desc *dp;
+
+	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+	    " %d", ep->numdesc);
+	ndesc = ep->numdesc;
+	if (ndesc > ISODESC_MAX)
+		ndesc = ISODESC_MAX;
+	if (ndesc < 0)
+		ndesc = 0;
+	dp = ep->isodesc;
+	for (i = 0; i < ndesc; i++) {
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+		    " %d:%u:%u", dp->status, dp->offset, dp->length);
+		dp++;
+	}
+}
+
+static void mon_text_read_data(struct mon_reader_text *rp,
+    struct mon_text_ptr *p, const struct mon_event_text *ep)
+{
+	int data_len, i;
 
 	if ((data_len = ep->length) > 0) {
 		if (ep->data_flag == 0) {
-			cnt += snprintf(pbuf + cnt, limit - cnt, " =");
+			p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+			    " =");
 			if (data_len >= DATA_MAX)
 				data_len = DATA_MAX;
 			for (i = 0; i < data_len; i++) {
 				if (i % 4 == 0) {
-					cnt += snprintf(pbuf + cnt, limit - cnt,
+					p->cnt += snprintf(p->pbuf + p->cnt,
+					    p->limit - p->cnt,
 					    " ");
 				}
-				cnt += snprintf(pbuf + cnt, limit - cnt,
+				p->cnt += snprintf(p->pbuf + p->cnt,
+				    p->limit - p->cnt,
 				    "%02x", ep->data[i]);
 			}
-			cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+			p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+			    "\n");
 		} else {
-			cnt += snprintf(pbuf + cnt, limit - cnt,
+			p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 			    " %c\n", ep->data_flag);
 		}
 	} else {
-		cnt += snprintf(pbuf + cnt, limit - cnt, "\n");
+		p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n");
 	}
-
-	if (copy_to_user(buf, rp->printf_buf, cnt))
-		cnt = -EFAULT;
-	mutex_unlock(&rp->printf_lock);
-	kmem_cache_free(rp->e_slab, ep);
-	return cnt;
 }
 
 static int mon_text_release(struct inode *inode, struct file *file)
@@ -439,34 +639,46 @@ static int mon_text_release(struct inode
 	return 0;
 }
 
-static const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text_t = {
 	.owner =	THIS_MODULE,
 	.open =		mon_text_open,
 	.llseek =	no_llseek,
-	.read =		mon_text_read,
-	/* .write =	mon_text_write, */
-	/* .poll =		mon_text_poll, */
-	/* .ioctl =	mon_text_ioctl, */
+	.read =		mon_text_read_t,
 	.release =	mon_text_release,
 };
 
-int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+static const struct file_operations mon_fops_text_u = {
+	.owner =	THIS_MODULE,
+	.open =		mon_text_open,
+	.llseek =	no_llseek,
+	.read =		mon_text_read_u,
+	.release =	mon_text_release,
+};
+
+int mon_text_add(struct mon_bus *mbus, int busnum)
 {
 	struct dentry *d;
 	enum { NAMESZ = 10 };
 	char name[NAMESZ];
 	int rc;
 
-	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+	rc = snprintf(name, NAMESZ, "%dt", busnum);
 	if (rc <= 0 || rc >= NAMESZ)
 		goto err_print_t;
-	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
 	if (d == NULL)
 		goto err_create_t;
 	mbus->dent_t = d;
 
-	/* XXX The stats do not belong to here (text API), but oh well... */
-	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+	rc = snprintf(name, NAMESZ, "%du", busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_u;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u);
+	if (d == NULL)
+		goto err_create_u;
+	mbus->dent_u = d;
+
+	rc = snprintf(name, NAMESZ, "%ds", busnum);
 	if (rc <= 0 || rc >= NAMESZ)
 		goto err_print_s;
 	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
@@ -478,6 +690,10 @@ int mon_text_add(struct mon_bus *mbus, c
 
 err_create_s:
 err_print_s:
+	debugfs_remove(mbus->dent_u);
+	mbus->dent_u = NULL;
+err_create_u:
+err_print_u:
 	debugfs_remove(mbus->dent_t);
 	mbus->dent_t = NULL;
 err_create_t:
@@ -487,6 +703,7 @@ err_print_t:
 
 void mon_text_del(struct mon_bus *mbus)
 {
+	debugfs_remove(mbus->dent_u);
 	debugfs_remove(mbus->dent_t);
 	debugfs_remove(mbus->dent_s);
 }
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index efdfd89..13d6325 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -22,7 +22,7 @@ struct mon_bus {
 	int text_inited;
 	struct dentry *dent_s;		/* Debugging file */
 	struct dentry *dent_t;		/* Text interface file */
-	int uses_dma;
+	struct dentry *dent_u;		/* Second text interface file */
 
 	/* Ref */
 	int nreaders;			/* Under mon_lock AND mbus->lock */
@@ -52,7 +52,7 @@ void mon_reader_del(struct mon_bus *mbus
 
 struct mon_bus *mon_bus_lookup(unsigned int num);
 
-int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
 void mon_text_del(struct mon_bus *mbus);
 // void mon_bin_add(struct mon_bus *);
 
@@ -81,4 +81,6 @@ extern struct mutex mon_lock;
 
 extern const struct file_operations mon_fops_stat;
 
+extern struct mon_bus mon_bus0;		/* Only for redundant checks */
+
 #endif /* __USB_MON_H */
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 5808ea0..d5ef97b 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -298,7 +298,7 @@ static int asix_rx_fixup(struct usbnet *
 		if (ax_skb) {
 			ax_skb->len = size;
 			ax_skb->data = packet;
-			ax_skb->tail = packet + size;
+			skb_set_tail_pointer(ax_skb, size);
 			usbnet_skb_return(dev, ax_skb);
 		} else {
 			return 0;
@@ -338,7 +338,7 @@ static struct sk_buff *asix_tx_fixup(str
 	    && ((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;
+			skb_set_tail_pointer(skb, skb->len);
 		}
 	} else {
 		struct sk_buff *skb2;
@@ -352,11 +352,11 @@ static struct sk_buff *asix_tx_fixup(str
 	skb_push(skb, 4);
 	packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
 	cpu_to_le32s(&packet_len);
-	memcpy(skb->data, &packet_len, sizeof(packet_len));
+	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
 
 	if ((skb->len % 512) == 0) {
 		cpu_to_le32s(&padbytes);
-		memcpy( skb->tail, &padbytes, sizeof(padbytes));
+		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
 		skb_put(skb, sizeof(padbytes));
 	}
 	return skb;
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
index 4852012..86e90c5 100644
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -255,7 +255,6 @@ static void catc_rx_done(struct urb *urb
 		if (!(skb = dev_alloc_skb(pkt_len)))
 			return;
 
-		skb->dev = catc->netdev;
 		eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0);
 		skb_put(skb, pkt_len);
 
@@ -356,7 +355,7 @@ resubmit:
  * Transmit routines.
  */
 
-static void catc_tx_run(struct catc *catc)
+static int catc_tx_run(struct catc *catc)
 {
 	int status;
 
@@ -374,12 +373,14 @@ static void catc_tx_run(struct catc *cat
 	catc->tx_ptr = 0;
 
 	catc->netdev->trans_start = jiffies;
+	return status;
 }
 
 static void catc_tx_done(struct urb *urb)
 {
 	struct catc *catc = urb->context;
 	unsigned long flags;
+	int r;
 
 	if (urb->status == -ECONNRESET) {
 		dbg("Tx Reset.");
@@ -398,10 +399,13 @@ static void catc_tx_done(struct urb *urb
 
 	spin_lock_irqsave(&catc->tx_lock, flags);
 
-	if (catc->tx_ptr)
-		catc_tx_run(catc);
-	else
+	if (catc->tx_ptr) {
+		r = catc_tx_run(catc);
+		if (unlikely(r < 0))
+			clear_bit(TX_RUNNING, &catc->flags);
+	} else {
 		clear_bit(TX_RUNNING, &catc->flags);
+	}
 
 	netif_wake_queue(catc->netdev);
 
@@ -412,6 +416,7 @@ static int catc_hard_start_xmit(struct s
 {
 	struct catc *catc = netdev_priv(netdev);
 	unsigned long flags;
+	int r = 0;
 	char *tx_buf;
 
 	spin_lock_irqsave(&catc->tx_lock, flags);
@@ -419,11 +424,14 @@ static int catc_hard_start_xmit(struct s
 	catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
 	tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
 	*((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len);
-	memcpy(tx_buf + 2, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, tx_buf + 2, skb->len);
 	catc->tx_ptr += skb->len + 2;
 
-	if (!test_and_set_bit(TX_RUNNING, &catc->flags))
-		catc_tx_run(catc);
+	if (!test_and_set_bit(TX_RUNNING, &catc->flags)) {
+		r = catc_tx_run(catc);
+		if (r < 0)
+			clear_bit(TX_RUNNING, &catc->flags);
+	}
 
 	if ((catc->is_f5u011 && catc->tx_ptr)
 	     || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))))
@@ -431,8 +439,10 @@ static int catc_hard_start_xmit(struct s
 
 	spin_unlock_irqrestore(&catc->tx_lock, flags);
 
-	catc->stats.tx_bytes += skb->len;
-	catc->stats.tx_packets++;
+	if (r >= 0) {
+		catc->stats.tx_bytes += skb->len;
+		catc->stats.tx_packets++;
+	}
 
 	dev_kfree_skb(skb);
 
diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c
index 5130cc7..a676386 100644
--- a/drivers/usb/net/dm9601.c
+++ b/drivers/usb/net/dm9601.c
@@ -12,6 +12,7 @@
 
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -85,7 +86,7 @@ static int dm_write_reg(struct usbnet *d
 			       usb_sndctrlpipe(dev->udev, 0),
 			       DM_WRITE_REG,
 			       USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
-			       value, reg, 0, 0, USB_CTRL_SET_TIMEOUT);
+			       value, reg, NULL, 0, USB_CTRL_SET_TIMEOUT);
 }
 
 static void dm_write_async_callback(struct urb *urb)
@@ -171,7 +172,7 @@ static void dm_write_reg_async(struct us
 
 	usb_fill_control_urb(urb, dev->udev,
 			     usb_sndctrlpipe(dev->udev, 0),
-			     (void *)req, 0, 0, dm_write_async_callback, req);
+			     (void *)req, NULL, 0, dm_write_async_callback, req);
 
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status < 0) {
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index d257a8e..031cf5c 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -157,7 +157,7 @@ genelink_tx_fixup(struct usbnet *dev, st
 		if ((headroom < (4 + 4*1)) || (tailroom < padlen)) {
 			skb->data = memmove(skb->head + (4 + 4*1),
 					     skb->data, skb->len);
-			skb->tail = skb->data + skb->len;
+			skb_set_tail_pointer(skb, skb->len);
 		}
 	} else {
 		struct sk_buff	*skb2;
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index de95268..60d2944 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -55,7 +55,6 @@ #include <linux/etherdevice.h>
 #include <linux/usb.h>
 #include <linux/types.h>
 #include <linux/ethtool.h>
-#include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
@@ -636,8 +635,6 @@ static void kaweth_usb_receive(struct ur
 
 		skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
 
-		skb->dev = net;
-
 		eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
 
 		skb_put(skb, pkt_len);
diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
index ccebfde..19bf8da 100644
--- a/drivers/usb/net/net1080.c
+++ b/drivers/usb/net/net1080.c
@@ -520,7 +520,7 @@ net1080_tx_fixup(struct usbnet *dev, str
 			skb->data = memmove(skb->head
 						+ sizeof (struct nc_header),
 					    skb->data, skb->len);
-			skb->tail = skb->data + len;
+			skb_set_tail_pointer(skb, len);
 			goto encapsulate;
 		}
 	}
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 6d12961..a05fd97 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -575,7 +575,6 @@ static void fill_skb_pool(pegasus_t * pe
 		 */
 		if (pegasus->rx_pool[i] == NULL)
 			return;
-		pegasus->rx_pool[i]->dev = pegasus->net;
 		skb_reserve(pegasus->rx_pool[i], 2);
 	}
 }
@@ -848,16 +847,6 @@ static void intr_callback(struct urb *ur
 		 * d[0].NO_CARRIER kicks in only with failed TX.
 		 * ... so monitoring with MII may be safest.
 		 */
-		if (pegasus->features & TRUST_LINK_STATUS) {
-			if (d[5] & LINK_STATUS)
-				netif_carrier_on(net);
-			else
-				netif_carrier_off(net);
-		} else {
-			/* Never set carrier _on_ based on ! NO_CARRIER */
-			if (d[0] & NO_CARRIER)
-				netif_carrier_off(net);	
-		}
 
 		/* bytes 3-4 == rx_lostpkt, reg 2E/2F */
 		pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
@@ -890,7 +879,7 @@ static int pegasus_start_xmit(struct sk_
 	netif_stop_queue(net);
 
 	((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
-	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
+	skb_copy_from_linear_data(skb, pegasus->tx_buff + 2, skb->len);
 	usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,
 			  usb_sndbulkpipe(pegasus->usb, 2),
 			  pegasus->tx_buff, count,
@@ -1415,8 +1404,10 @@ static void pegasus_disconnect(struct us
 	unlink_all_urbs(pegasus);
 	free_all_urbs(pegasus);
 	free_skb_pool(pegasus);
-	if (pegasus->rx_skb)
+	if (pegasus->rx_skb != NULL) {
 		dev_kfree_skb(pegasus->rx_skb);
+		pegasus->rx_skb = NULL;
+	}
 	free_netdev(pegasus->net);
 }
 
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index c7aadb4..c746782 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -11,7 +11,6 @@ #ifndef	PEGASUS_DEV
 
 #define	PEGASUS_II		0x80000000
 #define	HAS_HOME_PNA		0x40000000
-#define	TRUST_LINK_STATUS	0x20000000
 
 #define	PEGASUS_MTU		1536
 #define	RX_SKBS			4
@@ -204,7 +203,7 @@ PEGASUS_DEV( "AEI USB Fast Ethernet Adap
 PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
-		DEFAULT_GPIO_RESET | PEGASUS_II | TRUST_LINK_STATUS )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index 39a21c7..980e4aa 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -253,6 +253,7 @@ struct rndis_keepalive_c {	/* IN (option
  * of that mess as possible.
  */
 #define OID_802_3_PERMANENT_ADDRESS	ccpu2(0x01010101)
+#define OID_GEN_MAXIMUM_FRAME_SIZE	ccpu2(0x00010106)
 #define OID_GEN_CURRENT_PACKET_FILTER	ccpu2(0x0001010e)
 
 /*
@@ -349,7 +350,7 @@ static int rndis_command(struct usbnet *
 			case RNDIS_MSG_INDICATE: {	/* fault */
 				// struct rndis_indicate *msg = (void *)buf;
 				dev_info(&info->control->dev,
-					 "rndis fault indication\n");
+					"rndis fault indication\n");
 				}
 				break;
 			case RNDIS_MSG_KEEPALIVE: {	/* ping */
@@ -387,6 +388,71 @@ static int rndis_command(struct usbnet *
 	return -ETIMEDOUT;
 }
 
+/*
+ * rndis_query:
+ *
+ * Performs a query for @oid along with 0 or more bytes of payload as
+ * specified by @in_len. If @reply_len is not set to -1 then the reply
+ * length is checked against this value, resulting in an error if it
+ * doesn't match.
+ *
+ * NOTE: Adding a payload exactly or greater than the size of the expected
+ * response payload is an evident requirement MSFT added for ActiveSync.
+ *
+ * The only exception is for OIDs that return a variably sized response,
+ * in which case no payload should be added.  This undocumented (and
+ * nonsensical!) issue was found by sniffing protocol requests from the
+ * ActiveSync 4.1 Windows driver.
+ */
+static int rndis_query(struct usbnet *dev, struct usb_interface *intf,
+		void *buf, u32 oid, u32 in_len,
+		void **reply, int *reply_len)
+{
+	int retval;
+	union {
+		void			*buf;
+		struct rndis_msg_hdr	*header;
+		struct rndis_query	*get;
+		struct rndis_query_c	*get_c;
+	} u;
+	u32 off, len;
+
+	u.buf = buf;
+
+	memset(u.get, 0, sizeof *u.get + in_len);
+	u.get->msg_type = RNDIS_MSG_QUERY;
+	u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len);
+	u.get->oid = oid;
+	u.get->len = cpu_to_le32(in_len);
+	u.get->offset = ccpu2(20);
+
+	retval = rndis_command(dev, u.header);
+	if (unlikely(retval < 0)) {
+		dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n",
+				oid, retval);
+		return retval;
+	}
+
+	off = le32_to_cpu(u.get_c->offset);
+	len = le32_to_cpu(u.get_c->len);
+	if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
+		goto response_error;
+
+	if (*reply_len != -1 && len != *reply_len)
+		goto response_error;
+
+	*reply = (unsigned char *) &u.get_c->request_id + off;
+	*reply_len = len;
+
+	return retval;
+
+response_error:
+	dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) "
+			"invalid response - off %d len %d\n",
+		oid, off, len);
+	return -EDOM;
+}
+
 static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 {
 	int			retval;
@@ -403,6 +469,8 @@ static int rndis_bind(struct usbnet *dev
 		struct rndis_set_c	*set_c;
 	} u;
 	u32			tmp;
+	int			reply_len;
+	unsigned char		*bp;
 
 	/* we can't rely on i/o from stack working, or stack allocation */
 	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
@@ -421,6 +489,12 @@ static int rndis_bind(struct usbnet *dev
 	 * TX we'll stick to one Ethernet packet plus RNDIS framing.
 	 * For RX we handle drivers that zero-pad to end-of-packet.
 	 * Don't let userspace change these settings.
+	 *
+	 * NOTE: there still seems to be wierdness here, as if we need
+	 * to do some more things to make sure WinCE targets accept this.
+	 * They default to jumbograms of 8KB or 16KB, which is absurd
+	 * for such low data rates and which is also more than Linux
+	 * can usually expect to allocate for SKB data...
 	 */
 	net->hard_header_len += sizeof (struct rndis_data_hdr);
 	dev->hard_mtu = net->mtu + net->hard_header_len;
@@ -434,7 +508,7 @@ static int rndis_bind(struct usbnet *dev
 	if (unlikely(retval < 0)) {
 		/* it might not even be an RNDIS device!! */
 		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
- 		goto fail_and_release;
+		goto fail_and_release;
 	}
 	tmp = le32_to_cpu(u.init_c->max_transfer_size);
 	if (tmp < dev->hard_mtu) {
@@ -450,34 +524,15 @@ static int rndis_bind(struct usbnet *dev
 		dev->hard_mtu, tmp, dev->rx_urb_size,
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 
-	/* Get designated host ethernet address.
-	 *
-	 * Adding a payload exactly the same size as the expected response
-	 * payload is an evident requirement MSFT added for ActiveSync.
-	 * This undocumented (and nonsensical) issue was found by sniffing
-	 * protocol requests from the ActiveSync 4.1 Windows driver.
-	 */
-	memset(u.get, 0, sizeof *u.get + 48);
-	u.get->msg_type = RNDIS_MSG_QUERY;
-	u.get->msg_len = ccpu2(sizeof *u.get + 48);
-	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
-	u.get->len = ccpu2(48);
-	u.get->offset = ccpu2(20);
-
-	retval = rndis_command(dev, u.header);
-	if (unlikely(retval < 0)) {
+	/* Get designated host ethernet address */
+	reply_len = ETH_ALEN;
+	retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS,
+			48, (void **) &bp, &reply_len);
+	if (unlikely(retval< 0)) {
 		dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval);
 		goto fail_and_release;
 	}
-	tmp = le32_to_cpu(u.get_c->offset);
-	if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
-			|| u.get_c->len != ccpu2(ETH_ALEN))) {
-		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
-			tmp, le32_to_cpu(u.get_c->len));
-		retval = -EDOM;
-		goto fail_and_release;
-	}
-	memcpy(net->dev_addr, tmp + (char *)&u.get_c->request_id, ETH_ALEN);
+	memcpy(net->dev_addr, bp, ETH_ALEN);
 
 	/* set a nonzero filter to enable data transfers */
 	memset(u.set, 0, sizeof *u.set);
@@ -502,6 +557,7 @@ static int rndis_bind(struct usbnet *dev
 fail_and_release:
 	usb_set_intfdata(info->data, NULL);
 	usb_driver_release_interface(driver_of(intf), info->data);
+	info->data = NULL;
 fail:
 	kfree(u.buf);
 	return retval;
@@ -588,7 +644,7 @@ rndis_tx_fixup(struct usbnet *dev, struc
 		if (likely((sizeof *hdr) <= room)) {
 			skb->data = memmove(skb->head + sizeof *hdr,
 					    skb->data, len);
-			skb->tail = skb->data + len;
+			skb_set_tail_pointer(skb, len);
 			goto fill;
 		}
 	}
@@ -618,7 +674,7 @@ fill:
 
 static const struct driver_info	rndis_info = {
 	.description =	"RNDIS device",
-	.flags =	FLAG_ETHER | FLAG_FRAMING_RN,
+	.flags =	FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT,
 	.bind =		rndis_bind,
 	.unbind =	rndis_unbind,
 	.status =	rndis_status,
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index ea153dc..fa598f0 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -646,7 +646,6 @@ static void fill_skb_pool(rtl8150_t *dev
 		if (!skb) {
 			return;
 		}
-		skb->dev = dev->netdev;
 		skb_reserve(skb, 2);
 		dev->rx_skb_pool[i] = skb;
 	}
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index de69b18..f9cd42d 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -203,7 +203,6 @@ void usbnet_skb_return (struct usbnet *d
 {
 	int	status;
 
-	skb->dev = dev->net;
 	skb->protocol = eth_type_trans (skb, dev->net);
 	dev->stats.rx_packets++;
 	dev->stats.rx_bytes += skb->len;
@@ -735,8 +734,7 @@ void usbnet_get_drvinfo (struct net_devi
 {
 	struct usbnet *dev = netdev_priv(net);
 
-	/* REVISIT don't always return "usbnet" */
-	strncpy (info->driver, driver_name, sizeof info->driver);
+	strncpy (info->driver, dev->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);
@@ -1116,10 +1114,12 @@ usbnet_probe (struct usb_interface *udev
 	struct driver_info		*info;
 	struct usb_device		*xdev;
 	int				status;
+	const char			*name;
 
+	name = udev->dev.driver->name;
 	info = (struct driver_info *) prod->driver_info;
 	if (!info) {
-		dev_dbg (&udev->dev, "blacklisted by %s\n", driver_name);
+		dev_dbg (&udev->dev, "blacklisted by %s\n", name);
 		return -ENODEV;
 	}
 	xdev = interface_to_usbdev (udev);
@@ -1139,6 +1139,7 @@ usbnet_probe (struct usb_interface *udev
 	dev = netdev_priv(net);
 	dev->udev = xdev;
 	dev->driver_info = info;
+	dev->driver_name = name;
 	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
 				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 	skb_queue_head_init (&dev->rxq);
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
index 07c70ab..cbb53e0 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/usb/net/usbnet.h
@@ -29,6 +29,7 @@ struct usbnet {
 	/* housekeeping */
 	struct usb_device	*udev;
 	struct driver_info	*driver_info;
+	const char		*driver_name;
 	wait_queue_head_t	*wait;
 	struct mutex		phy_mutex;
 
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 2f4d303..ba5d1dc 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -423,11 +423,11 @@ config USB_SERIAL_MCT_U232
 	  module will be called mct_u232.
 
 config USB_SERIAL_MOS7720
-	tristate "USB Moschip 7720 Single Port Serial Driver"
+	tristate "USB Moschip 7720 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.
+	  Say Y here if you want to use USB Serial single and double
+	  port adapters from Moschip Semiconductor Tech.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called mos7720.
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 11dad42..b675735 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -209,6 +209,7 @@ static void aircable_send(struct usb_ser
 	int count, result;
 	struct aircable_private *priv = usb_get_serial_port_data(port);
 	unsigned char* buf;
+	u16 *dbuf;
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	if (port->write_urb_busy)
 		return;
@@ -226,8 +227,8 @@ static void aircable_send(struct usb_ser
 
 	buf[0] = TX_HEADER_0;
 	buf[1] = TX_HEADER_1;
-	buf[2] = (unsigned char)count;
-	buf[3] = (unsigned char)(count >> 8);
+	dbuf = (u16 *)&buf[2];
+	*dbuf = cpu_to_le16((u16)count);
 	serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
 
 	memcpy(port->write_urb->transfer_buffer, buf,
@@ -434,7 +435,7 @@ static void aircable_write_bulk_callback
 			    __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);
+			result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 			if (result)
 				dev_err(&urb->dev->dev,
 					"%s - failed resubmitting write urb, error %d\n",
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index edd6857..ea2175b 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -341,7 +341,7 @@ static int ark3116_open(struct usb_seria
 
 	result = usb_serial_generic_open(port, filp);
 	if (result)
-		return result;
+		goto err_out;
 
 	/* open */
 	ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
@@ -372,6 +372,7 @@ static int ark3116_open(struct usb_seria
 	if (port->tty)
 		ark3116_set_termios(port, &tmp_termios);
 
+err_out:
 	kfree(buf);
 
 	return result;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index d7d0ba9..e831cb7 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -58,9 +58,11 @@ static struct usb_device_id id_table [] 
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
 	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
 	{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
+	{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
 	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
 	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
 	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
+	{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
 	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
 	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
 	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8ff9d54..95a1805 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -342,6 +342,7 @@ static struct usb_device_id id_table_com
 	{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
@@ -1433,6 +1434,7 @@ static int ftdi_write (struct usb_serial
 		dbg("%s - write limit hit\n", __FUNCTION__);
 		return 0;
 	}
+	priv->tx_outstanding_urbs++;
 	spin_unlock_irqrestore(&priv->tx_lock, flags);
 
 	data_offset = priv->write_offset;
@@ -1450,14 +1452,15 @@ static int ftdi_write (struct usb_serial
 	buffer = kmalloc (transfer_size, GFP_ATOMIC);
 	if (!buffer) {
 		err("%s ran out of kernel memory for urb ...", __FUNCTION__);
-		return -ENOMEM;
+		count = -ENOMEM;
+		goto error_no_buffer;
 	}
 
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		err("%s - no more free urbs", __FUNCTION__);
-		kfree (buffer);
-		return -ENOMEM;
+		count = -ENOMEM;
+		goto error_no_urb;
 	}
 
 	/* Copy data */
@@ -1499,10 +1502,9 @@ static int ftdi_write (struct usb_serial
 	if (status) {
 		err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
 		count = status;
-		kfree (buffer);
+		goto error;
 	} else {
 		spin_lock_irqsave(&priv->tx_lock, flags);
-		++priv->tx_outstanding_urbs;
 		priv->tx_outstanding_bytes += count;
 		priv->tx_bytes += count;
 		spin_unlock_irqrestore(&priv->tx_lock, flags);
@@ -1510,10 +1512,19 @@ static int ftdi_write (struct usb_serial
 
 	/* we are done with this urb, so let the host driver
 	 * really free it when it is finished with it */
-	usb_free_urb (urb);
+	usb_free_urb(urb);
 
 	dbg("%s write returning: %d", __FUNCTION__, count);
 	return count;
+error:
+	usb_free_urb(urb);
+error_no_urb:
+	kfree (buffer);
+error_no_buffer:
+	spin_lock_irqsave(&priv->tx_lock, flags);
+	priv->tx_outstanding_urbs--;
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	return count;
 } /* ftdi_write */
 
 
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 513cfe1..77ad0a0 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -31,6 +31,7 @@ #define FTDI_232RL_PID  0xFBFA  /* Produ
 #define FTDI_RELAIS_PID	0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
+#define FTDI_USBX_707_PID 0xF857	/* ADSTech IR Blaster USBX-707 */
 
 
 /* www.canusb.com Lawicel CANUSB device */
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 6a26a2e..18f74ac 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -111,7 +111,7 @@ struct edgeport_port {
 
 	struct TxFifo		txfifo;			/* transmit fifo -- size will be maxTxCredits */
 	struct urb		*write_urb;		/* write URB for this port */
-	char			write_in_progress;	/* TRUE while a write URB is outstanding */
+	bool			write_in_progress;	/* 'true' while a write URB is outstanding */
 	spinlock_t		ep_lock;
 
 	__u8			shadowLCR;		/* last LCR value received */
@@ -123,11 +123,11 @@ struct edgeport_port {
 	__u8			validDataMask;
 	__u32			baudRate;
 
-	char			open;
-	char			openPending;
-	char			commandPending;
-	char			closePending;
-	char			chaseResponsePending;
+	bool			open;
+	bool			openPending;
+	bool			commandPending;
+	bool			closePending;
+	bool			chaseResponsePending;
 
 	wait_queue_head_t	wait_chase;		/* for handling sleeping while waiting for chase to finish */
 	wait_queue_head_t	wait_open;		/* for handling sleeping while waiting for open to finish */
@@ -156,7 +156,7 @@ struct edgeport_serial {
 	__u8			bulk_in_endpoint;		/* the bulk in endpoint handle */
 	unsigned char *		bulk_in_buffer;			/* the buffer we use for the bulk in endpoint */
 	struct urb *		read_urb;			/* our bulk read urb */
-	int			read_in_progress;
+	bool			read_in_progress;
 	spinlock_t		es_lock;
 
 	__u8			bulk_out_endpoint;		/* the bulk out endpoint handle */
@@ -212,7 +212,7 @@ static int debug;
 
 static int low_latency = 1;	/* tty low latency flag, on by default */
 
-static int CmdUrbs = 0;		/* Number of outstanding Command Write Urbs */
+static atomic_t CmdUrbs;		/* Number of outstanding Command Write Urbs */
 
 
 /* local function prototypes */
@@ -631,14 +631,14 @@ static void edge_interrupt_callback (str
 				if (edge_serial->rxBytesAvail > 0 &&
 				    !edge_serial->read_in_progress) {
 					dbg("%s - posting a read", __FUNCTION__);
-					edge_serial->read_in_progress = TRUE;
+					edge_serial->read_in_progress = true;
 
 					/* we have pending bytes on the bulk in pipe, send a request */
 					edge_serial->read_urb->dev = edge_serial->serial->dev;
 					result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 					if (result) {
 						dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __FUNCTION__, result);
-						edge_serial->read_in_progress = FALSE;
+						edge_serial->read_in_progress = false;
 					}
 				}
 				spin_unlock(&edge_serial->es_lock);
@@ -695,13 +695,13 @@ static void edge_bulk_in_callback (struc
 
 	if (urb->status) {
 		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
-		edge_serial->read_in_progress = FALSE;
+		edge_serial->read_in_progress = false;
 		return;
 	}
 
 	if (urb->actual_length == 0) {
 		dbg("%s - read bulk callback with no data", __FUNCTION__);
-		edge_serial->read_in_progress = FALSE;
+		edge_serial->read_in_progress = false;
 		return;
 	}
 
@@ -725,10 +725,10 @@ static void edge_bulk_in_callback (struc
 		status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 		if (status) {
 			dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
-			edge_serial->read_in_progress = FALSE;
+			edge_serial->read_in_progress = false;
 		}
 	} else {
-		edge_serial->read_in_progress = FALSE;
+		edge_serial->read_in_progress = false;
 	}
 
 	spin_unlock(&edge_serial->es_lock);
@@ -759,7 +759,7 @@ static void edge_bulk_out_data_callback 
 	}
 
 	// Release the Write URB
-	edge_port->write_in_progress = FALSE;
+	edge_port->write_in_progress = false;
 
 	// Check if more data needs to be sent
 	send_more_port_data((struct edgeport_serial *)(usb_get_serial_data(edge_port->port->serial)), edge_port);
@@ -779,8 +779,8 @@ static void edge_bulk_out_cmd_callback (
 
 	dbg("%s", __FUNCTION__);
 
-	CmdUrbs--;
-	dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
+	atomic_dec(&CmdUrbs);
+	dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
 
 
 	/* clean up the transfer buffer */
@@ -802,7 +802,7 @@ static void edge_bulk_out_cmd_callback (
 		tty_wakeup(tty);
 
 	/* we have completed the command */
-	edge_port->commandPending = FALSE;
+	edge_port->commandPending = false;
 	wake_up(&edge_port->wait_command);
 }
 
@@ -868,7 +868,7 @@ static int edge_open (struct usb_serial_
 				  port0->bulk_in_buffer,
 				  edge_serial->read_urb->transfer_buffer_length,
 				  edge_bulk_in_callback, edge_serial);
-		edge_serial->read_in_progress = FALSE;
+		edge_serial->read_in_progress = false;
 
 		/* start interrupt read for this edgeport
 		 * this interrupt will continue as long as the edgeport is connected */
@@ -890,26 +890,26 @@ static int edge_open (struct usb_serial_
 	/* initialize our port settings */
 	edge_port->txCredits            = 0;			/* Can't send any data yet */
 	edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
-	edge_port->chaseResponsePending = FALSE;
+	edge_port->chaseResponsePending = false;
 
 	/* send a open port command */
-	edge_port->openPending = TRUE;
-	edge_port->open        = FALSE;
+	edge_port->openPending = true;
+	edge_port->open        = false;
 	response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
 
 	if (response < 0) {
 		dev_err(&port->dev, "%s - error sending open port command\n", __FUNCTION__);
-		edge_port->openPending = FALSE;
+		edge_port->openPending = false;
 		return -ENODEV;
 	}
 
 	/* now wait for the port to be completely opened */
-	wait_event_timeout(edge_port->wait_open, (edge_port->openPending != TRUE), OPEN_TIMEOUT);
+	wait_event_timeout(edge_port->wait_open, !edge_port->openPending, OPEN_TIMEOUT);
 
-	if (edge_port->open == FALSE) {
+	if (!edge_port->open) {
 		/* open timed out */
 		dbg("%s - open timedout", __FUNCTION__);
-		edge_port->openPending = FALSE;
+		edge_port->openPending = false;
 		return -ENODEV;
 	}
 
@@ -928,7 +928,7 @@ static int edge_open (struct usb_serial_
 
 	/* Allocate a URB for the write */
 	edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
-	edge_port->write_in_progress = FALSE;
+	edge_port->write_in_progress = false;
 
 	if (!edge_port->write_urb) {
 		dbg("%s - no memory", __FUNCTION__);
@@ -966,7 +966,7 @@ static void block_until_chase_response(s
 		lastCredits = edge_port->txCredits;
 
 		// Did we get our Chase response
-		if (edge_port->chaseResponsePending == FALSE) {
+		if (!edge_port->chaseResponsePending) {
 			dbg("%s - Got Chase Response", __FUNCTION__);
 
 			// did we get all of our credit back?
@@ -985,7 +985,7 @@ static void block_until_chase_response(s
 			// No activity.. count down.
 			loop--;
 			if (loop == 0) {
-				edge_port->chaseResponsePending = FALSE;
+				edge_port->chaseResponsePending = false;
 				dbg("%s - Chase TIMEOUT", __FUNCTION__);
 				return;
 			}
@@ -1068,13 +1068,13 @@ static void edge_close (struct usb_seria
 	// block until tx is empty
 	block_until_tx_empty(edge_port);
 
-	edge_port->closePending = TRUE;
+	edge_port->closePending = true;
 
 	if ((!edge_serial->is_epic) ||
 	    ((edge_serial->is_epic) &&
 	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
 		/* flush and chase */
-		edge_port->chaseResponsePending = TRUE;
+		edge_port->chaseResponsePending = true;
 
 		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
 		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
@@ -1082,7 +1082,7 @@ static void edge_close (struct usb_seria
 			// block until chase finished
 			block_until_chase_response(edge_port);
 		} else {
-			edge_port->chaseResponsePending = FALSE;
+			edge_port->chaseResponsePending = false;
 		}
 	}
 
@@ -1094,10 +1094,10 @@ static void edge_close (struct usb_seria
 		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
 	}
 
-	//port->close = TRUE;
-	edge_port->closePending = FALSE;
-	edge_port->open = FALSE;
-	edge_port->openPending = FALSE;
+	//port->close = true;
+	edge_port->closePending = false;
+	edge_port->open = false;
+	edge_port->openPending = false;
 
 	usb_kill_urb(edge_port->write_urb);
 
@@ -1247,7 +1247,7 @@ static void send_more_port_data(struct e
 	}
 
 	// lock this write
-	edge_port->write_in_progress = TRUE;
+	edge_port->write_in_progress = true;
 
 	// get a pointer to the write_urb
 	urb = edge_port->write_urb;
@@ -1261,7 +1261,7 @@ static void send_more_port_data(struct e
 	buffer = kmalloc (count+2, GFP_ATOMIC);
 	if (buffer == NULL) {
 		dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__);
-		edge_port->write_in_progress = FALSE;
+		edge_port->write_in_progress = false;
 		goto exit_send;
 	}
 	buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count);
@@ -1301,7 +1301,7 @@ static void send_more_port_data(struct e
 	if (status) {
 		/* something went wrong */
 		dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status);
-		edge_port->write_in_progress = FALSE;
+		edge_port->write_in_progress = false;
 
 		/* revert the credits as something bad happened. */
 		edge_port->txCredits += count;
@@ -1332,7 +1332,7 @@ static int edge_write_room (struct usb_s
 
 	if (edge_port == NULL)
 		return -ENODEV;
-	if (edge_port->closePending == TRUE)
+	if (edge_port->closePending)
 		return -ENODEV;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1371,7 +1371,7 @@ static int edge_chars_in_buffer (struct 
 
 	if (edge_port == NULL)
 		return -ENODEV;
-	if (edge_port->closePending == TRUE)
+	if (edge_port->closePending)
 		return -ENODEV;
 
 	if (!edge_port->open) {
@@ -1762,7 +1762,7 @@ static void edge_break (struct usb_seria
 	    ((edge_serial->is_epic) &&
 	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
 		/* flush and chase */
-		edge_port->chaseResponsePending = TRUE;
+		edge_port->chaseResponsePending = true;
 
 		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
 		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
@@ -1770,7 +1770,7 @@ static void edge_break (struct usb_seria
 			// block until chase finished
 			block_until_chase_response(edge_port);
 		} else {
-			edge_port->chaseResponsePending = FALSE;
+			edge_port->chaseResponsePending = false;
 		}
 	}
 
@@ -1952,13 +1952,13 @@ static void process_rcvd_status (struct 
 				// Also, we currently clear flag and close the port regardless of content of above's Byte3.
 				// We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
 				// like wait longer in block_until_chase_response, but for now we don't. 
-				edge_port->chaseResponsePending = FALSE;
+				edge_port->chaseResponsePending = false;
 				wake_up (&edge_port->wait_chase);
 				return;
 
 			case IOSP_EXT_STATUS_RX_CHECK_RSP:
 				dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 );
-				//Port->RxCheckRsp = TRUE;
+				//Port->RxCheckRsp = true;
 				return;
 		}
 	}
@@ -1974,8 +1974,8 @@ static void process_rcvd_status (struct 
 			change_port_settings (edge_port, edge_port->port->tty->termios);
 
 		/* we have completed the open */
-		edge_port->openPending = FALSE;
-		edge_port->open = TRUE;
+		edge_port->openPending = false;
+		edge_port->open = true;
 		wake_up(&edge_port->wait_open);
 		return;
 	}
@@ -1983,7 +1983,7 @@ static void process_rcvd_status (struct 
 	// If port is closed, silently discard all rcvd status. We can
 	// have cases where buffered status is received AFTER the close
 	// port command is sent to the Edgeport.
-	if ((!edge_port->open ) || (edge_port->closePending)) {
+	if (!edge_port->open || edge_port->closePending) {
 		return;
 	}
 
@@ -1991,14 +1991,14 @@ static void process_rcvd_status (struct 
 		// Not currently sent by Edgeport
 		case IOSP_STATUS_LSR:
 			dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2);
-			handle_new_lsr (edge_port, FALSE, byte2, 0);
+			handle_new_lsr(edge_port, false, byte2, 0);
 			break;
 
 		case IOSP_STATUS_LSR_DATA:
 			dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3);
 			// byte2 is LSR Register
 			// byte3 is broken data byte
-			handle_new_lsr (edge_port, TRUE, byte2, byte3);
+			handle_new_lsr(edge_port, true, byte2, byte3);
 			break;
 			//
 			//	case IOSP_EXT_4_STATUS:
@@ -2317,14 +2317,14 @@ static int write_cmd_usb (struct edgepor
 	if (!urb)
 		return -ENOMEM;
 
-	CmdUrbs++;
-	dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, CmdUrbs);
+	atomic_inc(&CmdUrbs);
+	dbg("%s - ALLOCATE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs));
 
 	usb_fill_bulk_urb (urb, edge_serial->serial->dev, 
 		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
 		       buffer, length, edge_bulk_out_cmd_callback, edge_port);
 
-	edge_port->commandPending = TRUE;
+	edge_port->commandPending = true;
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 
 	if (status) {
@@ -2332,16 +2332,16 @@ static int write_cmd_usb (struct edgepor
 		dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write command) failed, status = %d\n", __FUNCTION__, status);
 		usb_kill_urb(urb);
 		usb_free_urb(urb);
-		CmdUrbs--;
+		atomic_dec(&CmdUrbs);
 		return status;
 	}
 
 	// wait for command to finish
 	timeout = COMMAND_TIMEOUT;
 #if 0
-	wait_event (&edge_port->wait_command, (edge_port->commandPending == FALSE));
+	wait_event (&edge_port->wait_command, !edge_port->commandPending);
 
-	if (edge_port->commandPending == TRUE) {
+	if (edge_port->commandPending) {
 		/* command timed out */
 		dbg("%s - command timed out", __FUNCTION__);
 		status = -EINVAL;
@@ -2524,8 +2524,8 @@ static void change_port_settings (struct
 
 	dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
 
-	if ((!edge_port->open) &&
-	    (!edge_port->openPending)) {
+	if (!edge_port->open &&
+	    !edge_port->openPending) {
 		dbg("%s - port not opened", __FUNCTION__);
 		return;
 	}
@@ -2836,9 +2836,9 @@ static int edge_startup (struct usb_seri
 	struct usb_device *dev;
 	int i, j;
 	int response;
-	int interrupt_in_found;
-	int bulk_in_found;
-	int bulk_out_found;
+	bool interrupt_in_found;
+	bool bulk_in_found;
+	bool bulk_out_found;
 	static __u32 descriptor[3] = {	EDGE_COMPATIBILITY_MASK0,
 					EDGE_COMPATIBILITY_MASK1,
 					EDGE_COMPATIBILITY_MASK2 };
@@ -2936,14 +2936,14 @@ static int edge_startup (struct usb_seri
 	if (edge_serial->is_epic) {
 		/* EPIC thing, set up our interrupt polling now and our read urb, so
 		 * that the device knows it really is connected. */
-		interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+		interrupt_in_found = bulk_in_found = bulk_out_found = false;
 		for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
 			struct usb_endpoint_descriptor *endpoint;
 			int buffer_size;
 
 			endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
 			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-			if ((!interrupt_in_found) &&
+			if (!interrupt_in_found &&
 			    (usb_endpoint_is_int_in(endpoint))) {
 				/* we found a interrupt in endpoint */
 				dbg("found interrupt in");
@@ -2972,10 +2972,10 @@ static int edge_startup (struct usb_seri
 						 edge_serial,
 						 endpoint->bInterval);
 
-				interrupt_in_found = TRUE;
+				interrupt_in_found = true;
 			}
 
-			if ((!bulk_in_found) &&
+			if (!bulk_in_found &&
 			    (usb_endpoint_is_bulk_in(endpoint))) {
 				/* we found a bulk in endpoint */
 				dbg("found bulk in");
@@ -3001,19 +3001,19 @@ static int edge_startup (struct usb_seri
 						  endpoint->wMaxPacketSize,
 						  edge_bulk_in_callback,
 						  edge_serial);
-				bulk_in_found = TRUE;
+				bulk_in_found = true;
 			}
 
-			if ((!bulk_out_found) &&
+			if (!bulk_out_found &&
 			    (usb_endpoint_is_bulk_out(endpoint))) {
 				/* we found a bulk out endpoint */
 				dbg("found bulk out");
 				edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
-				bulk_out_found = TRUE;
+				bulk_out_found = true;
 			}
 		}
 
-		if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+		if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) {
 			err ("Error - the proper endpoints were not found!");
 			return -ENODEV;
 		}
@@ -3083,6 +3083,7 @@ static int __init edgeport_init(void)
 	retval = usb_register(&io_driver);
 	if (retval) 
 		goto failed_usb_register;
+	atomic_set(&CmdUrbs, 0);
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 29a913a..cb201c1 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -19,12 +19,6 @@ #define	_IO_EDGEPORT_H_
 #define MAX_RS232_PORTS		8	/* Max # of RS-232 ports per device */
 
 /* typedefs that the insideout headers need */
-#ifndef TRUE
-	#define TRUE		(1)
-#endif
-#ifndef FALSE
-	#define FALSE		(0)
-#endif
 #ifndef LOW8
 	#define LOW8(a)		((unsigned char)(a & 0xff))
 #endif
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index d16e2e1..4df0ec7 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -255,6 +255,7 @@ static struct usb_device_id ipaq_id_tabl
 	{ USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
+	{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
 	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index b2097c4..7b085f3 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -238,7 +238,7 @@ static int klsi_105_get_line_state(struc
 	if (rc < 0)
 		err("Reading line status failed (error = %d)", rc);
 	else {
-		status = status_buf[0] + (status_buf[1]<<8);
+		status = le16_to_cpu(*(u16 *)status_buf);
 
 		info("%s - read status %x %x", __FUNCTION__,
 		     status_buf[0], status_buf[1]);
@@ -257,7 +257,7 @@ static int klsi_105_get_line_state(struc
 static int klsi_105_startup (struct usb_serial *serial)
 {
 	struct klsi_105_private *priv;
-	int i;
+	int i, j;
 
 	/* check if we support the product id (see keyspan.c)
 	 * FIXME
@@ -265,12 +265,12 @@ static int klsi_105_startup (struct usb_
 
 	/* allocate the private data structure */
 	for (i=0; i<serial->num_ports; i++) {
-		int j;
 		priv = kmalloc(sizeof(struct klsi_105_private),
 						   GFP_KERNEL);
 		if (!priv) {
 			dbg("%skmalloc for klsi_105_private failed.", __FUNCTION__);
-			return -ENOMEM;
+			i--;
+			goto err_cleanup;
 		}
 		/* set initial values for control structures */
 		priv->cfg.pktlen    = 5;
@@ -292,15 +292,14 @@ static int klsi_105_startup (struct usb_
 			priv->write_urb_pool[j] = urb;
 			if (urb == NULL) {
 				err("No more urbs???");
-				continue;
+				goto err_cleanup;
 			}
 
-			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;
+				goto err_cleanup;
 			}
 		}
 
@@ -308,7 +307,20 @@ static int klsi_105_startup (struct usb_
 		init_waitqueue_head(&serial->port[i]->write_wait);
 	}
 	
-	return (0);
+	return 0;
+
+err_cleanup:
+	for (; i >= 0; i--) {
+		priv = usb_get_serial_port_data(serial->port[i]);
+		for (j=0; j < NUM_URBS; j++) {
+			if (priv->write_urb_pool[j]) {
+				kfree(priv->write_urb_pool[j]->transfer_buffer);
+				usb_free_urb(priv->write_urb_pool[j]);
+			}
+		}
+		usb_set_serial_port_data(serial->port[i], NULL);
+	}
+	return -ENOMEM;
 } /* klsi_105_startup */
 
 
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 4cd839b..3db1adc 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -438,17 +438,21 @@ static int  mct_u232_open (struct usb_se
 	if (retval) {
 		err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
 		    port->read_urb->pipe, retval);
-		goto exit;
+		goto error;
 	}
 
 	port->interrupt_in_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-	if (retval)
+	if (retval) {
+		usb_kill_urb(port->read_urb);
 		err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
 		    port->interrupt_in_urb->pipe, retval);
-
-exit:
+		goto error;
+	}
 	return 0;
+
+error:
+	return retval;
 } /* mct_u232_open */
 
 
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 19bf403..b563e2a 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -103,11 +103,9 @@ static void mos7720_interrupt_callback(s
 {
 	int result;
 	int length;
-	__u32 *data;
-	unsigned int status;
+	__u8 *data;
 	__u8 sp1;
 	__u8 sp2;
-	__u8 st;
 
 	dbg("%s"," : Entering\n");
 
@@ -141,18 +139,19 @@ static void mos7720_interrupt_callback(s
 	 * Byte 2 IIR Port 2 (port.number is 1)
 	 * Byte 3 --------------
 	 * Byte 4 FIFO status for both */
-	if (length && length > 4) {
+
+	/* the above description is inverted
+	 * 	oneukum 2007-03-14 */
+
+	if (unlikely(length != 4)) {
 		dbg("Wrong data !!!");
 		return;
 	}
 
-	status = *data;
-
-	sp1 = (status & 0xff000000)>>24;
-	sp2 = (status & 0x00ff0000)>>16;
-	st = status & 0x000000ff;
+	sp1 = data[3];
+	sp2 = data[2];
 
-	if ((sp1 & 0x01) || (sp2 & 0x01)) {
+	if ((sp1 | sp2) & 0x01) {
 		/* No Interrupt Pending in both the ports */
 		dbg("No Interrupt !!!");
 	} else {
@@ -333,6 +332,7 @@ static int mos7720_open(struct usb_seria
 	int response;
 	int port_number;
 	char data;
+	int allocated_urbs = 0;
 	int j;
 
 	serial = port->serial;
@@ -353,7 +353,7 @@ static int mos7720_open(struct usb_seria
 
 	/* Initialising the write urb pool */
 	for (j = 0; j < NUM_URBS; ++j) {
-		urb = usb_alloc_urb(0,GFP_ATOMIC);
+		urb = usb_alloc_urb(0,GFP_KERNEL);
 		mos7720_port->write_urb_pool[j] = urb;
 
 		if (urb == NULL) {
@@ -365,10 +365,16 @@ static int mos7720_open(struct usb_seria
 					       GFP_KERNEL);
 		if (!urb->transfer_buffer) {
 			err("%s-out of memory for urb buffers.", __FUNCTION__);
+			usb_free_urb(mos7720_port->write_urb_pool[j]);
+			mos7720_port->write_urb_pool[j] = NULL;
 			continue;
 		}
+		allocated_urbs++;
 	}
 
+	if (!allocated_urbs)
+		return -ENOMEM;
+
 	 /* Initialize MCS7720 -- Write Init values to corresponding Registers
 	  *
 	  * Register Index
@@ -526,7 +532,7 @@ static int mos7720_chars_in_buffer(struc
 	}
 
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
+		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
 			chars += URB_TRANSFER_BUFFER_SIZE;
 	}
 	dbg("%s - returns %d", __FUNCTION__, chars);
@@ -629,7 +635,7 @@ static int mos7720_write_room(struct usb
 	}
 
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
+		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
 			room += URB_TRANSFER_BUFFER_SIZE;
 	}
 
@@ -664,7 +670,7 @@ static int mos7720_write(struct usb_seri
 	urb = NULL;
 
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
+		if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
 			urb = mos7720_port->write_urb_pool[i];
 			dbg("URB:%d",i);
 			break;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c6cca85..2366e7b 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -176,9 +176,12 @@ 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 */
+	struct urb *int_urb;
 	__u8 shadowLCR;		/* last LCR value received */
 	__u8 shadowMCR;		/* last MCR value received */
 	char open;
+	char open_ports;
+	char zombie;
 	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;
@@ -191,17 +194,17 @@ struct moschip_port {
 	__u8 DcrRegOffset;
 	//for processing control URBS in interrupt context
 	struct urb *control_urb;
+	struct usb_ctrlrequest *dr;
 	char *ctrl_buf;
 	int MsrLsr;
 
+	spinlock_t pool_lock;
 	struct urb *write_urb_pool[NUM_URBS];
+	char busy[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
@@ -254,7 +257,7 @@ static int mos7840_set_uart_reg(struct u
 	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) {
+	if (port->serial->num_ports == 4) {
 		val |=
 		    (((__u16) port->number - (__u16) (port->serial->minor)) +
 		     1) << 8;
@@ -294,7 +297,7 @@ static int mos7840_get_uart_reg(struct u
 
 	//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) {
+	if (port->serial->num_ports == 4) {
 		Wval =
 		    (((__u16) port->number - (__u16) (port->serial->minor)) +
 		     1) << 8;
@@ -352,7 +355,7 @@ static inline struct moschip_port *mos78
 	return (struct moschip_port *)usb_get_serial_port_data(port);
 }
 
-static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
+static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
 {
 	struct moschip_port *mos7840_port;
 	struct async_icount *icount;
@@ -366,22 +369,24 @@ static int mos7840_handle_new_msr(struct
 		/* update input line counters */
 		if (new_msr & MOS_MSR_DELTA_CTS) {
 			icount->cts++;
+			smp_wmb();
 		}
 		if (new_msr & MOS_MSR_DELTA_DSR) {
 			icount->dsr++;
+			smp_wmb();
 		}
 		if (new_msr & MOS_MSR_DELTA_CD) {
 			icount->dcd++;
+			smp_wmb();
 		}
 		if (new_msr & MOS_MSR_DELTA_RI) {
 			icount->rng++;
+			smp_wmb();
 		}
 	}
-
-	return 0;
 }
 
-static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
+static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
 {
 	struct async_icount *icount;
 
@@ -400,18 +405,20 @@ static int mos7840_handle_new_lsr(struct
 	icount = &port->icount;
 	if (new_lsr & SERIAL_LSR_BI) {
 		icount->brk++;
+		smp_wmb();
 	}
 	if (new_lsr & SERIAL_LSR_OE) {
 		icount->overrun++;
+		smp_wmb();
 	}
 	if (new_lsr & SERIAL_LSR_PE) {
 		icount->parity++;
+		smp_wmb();
 	}
 	if (new_lsr & SERIAL_LSR_FE) {
 		icount->frame++;
+		smp_wmb();
 	}
-
-	return 0;
 }
 
 /************************************************************************/
@@ -426,12 +433,15 @@ static void mos7840_control_callback(str
 	unsigned char *data;
 	struct moschip_port *mos7840_port;
 	__u8 regval = 0x0;
+	int result = 0;
 
 	if (!urb) {
 		dbg("%s", "Invalid Pointer !!!!:\n");
 		return;
 	}
 
+	mos7840_port = (struct moschip_port *)urb->context;
+
 	switch (urb->status) {
 	case 0:
 		/* success */
@@ -449,8 +459,6 @@ static void mos7840_control_callback(str
 		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);
@@ -462,21 +470,26 @@ static void mos7840_control_callback(str
 	else if (mos7840_port->MsrLsr == 1)
 		mos7840_handle_new_lsr(mos7840_port, regval);
 
-      exit:
-	return;
+exit:
+	spin_lock(&mos7840_port->pool_lock);
+	if (!mos7840_port->zombie)
+		result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC);
+	spin_unlock(&mos7840_port->pool_lock);
+	if (result) {
+		dev_err(&urb->dev->dev,
+			"%s - Error %d submitting interrupt urb\n",
+			__FUNCTION__, result);
+	}
 }
 
 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;
+	struct usb_ctrlrequest *dr = mcs->dr;
+	unsigned char *buffer = mcs->ctrl_buf;
+	int ret;
 
-//      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;
@@ -506,8 +519,8 @@ static void mos7840_interrupt_callback(s
 	__u16 Data;
 	unsigned char *data;
 	__u8 sp[5], st;
-	int i;
-	__u16 wval;
+	int i, rv = 0;
+	__u16 wval, wreg = 0;
 
 	dbg("%s", " : Entering\n");
 	if (!urb) {
@@ -569,31 +582,34 @@ static void mos7840_interrupt_callback(s
 					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);
+					wreg = LINE_STATUS_REGISTER;
 					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);
+					wreg = MODEM_STATUS_REGISTER;
 					break;
 				}
+				spin_lock(&mos7840_port->pool_lock);
+				if (!mos7840_port->zombie) {
+					rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data);
+				} else {
+					spin_unlock(&mos7840_port->pool_lock);
+					return;
+				}
+				spin_unlock(&mos7840_port->pool_lock);
 			}
 		}
 	}
-      exit:
+	if (!(rv < 0)) /* the completion handler for the control urb will resubmit */
+		return;
+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,
@@ -634,7 +650,8 @@ static struct usb_serial *mos7840_get_us
 	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 */
+		/* then say that we don't have a valid usb_serial thing, which will
+		 * end up genrating -ENODEV return values */
 		return NULL;
 	}
 
@@ -699,6 +716,7 @@ static void mos7840_bulk_in_callback(str
 			tty_flip_buffer_push(tty);
 		}
 		mos7840_port->icount.rx += urb->actual_length;
+		smp_wmb();
 		dbg("mos7840_port->icount.rx is %d:\n",
 		    mos7840_port->icount.rx);
 	}
@@ -708,15 +726,14 @@ static void mos7840_bulk_in_callback(str
 		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);
+	mos7840_port->read_urb->dev = serial->dev;
 
-		if (status) {
-			dbg(" usb_submit_urb(read bulk) failed, status = %d",
-			    status);
-		}
+	status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+
+	if (status) {
+		dbg(" usb_submit_urb(read bulk) failed, status = %d",
+		 status);
 	}
 }
 
@@ -730,17 +747,28 @@ static void mos7840_bulk_out_data_callba
 {
 	struct moschip_port *mos7840_port;
 	struct tty_struct *tty;
+	int i;
+
 	if (!urb) {
 		dbg("%s", "Invalid Pointer !!!!:\n");
 		return;
 	}
 
+	mos7840_port = (struct moschip_port *)urb->context;
+	spin_lock(&mos7840_port->pool_lock);
+	for (i = 0; i < NUM_URBS; i++) {
+		if (urb == mos7840_port->write_urb_pool[i]) {
+			mos7840_port->busy[i] = 0;
+			break;
+		}
+	}
+	spin_unlock(&mos7840_port->pool_lock);
+
 	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;
@@ -792,13 +820,13 @@ static int mos7840_open(struct usb_seria
 	__u16 Data;
 	int status;
 	struct moschip_port *mos7840_port;
+	struct moschip_port *port0;
 
 	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__)) {
@@ -807,16 +835,18 @@ static int mos7840_open(struct usb_seria
 	}
 
 	mos7840_port = mos7840_get_port_private(port);
+	port0 = mos7840_get_port_private(serial->port[0]);
 
-	if (mos7840_port == NULL)
+	if (mos7840_port == NULL || port0 == NULL)
 		return -ENODEV;
 
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
+	port0->open_ports++;
 
 	/* Initialising the write urb pool */
 	for (j = 0; j < NUM_URBS; ++j) {
-		urb = usb_alloc_urb(0, GFP_ATOMIC);
+		urb = usb_alloc_urb(0, GFP_KERNEL);
 		mos7840_port->write_urb_pool[j] = urb;
 
 		if (urb == NULL) {
@@ -824,10 +854,10 @@ static int mos7840_open(struct usb_seria
 			continue;
 		}
 
-		urb->transfer_buffer = NULL;
-		urb->transfer_buffer =
-		    kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
 		if (!urb->transfer_buffer) {
+			usb_free_urb(urb);
+			mos7840_port->write_urb_pool[j] = NULL;
 			err("%s-out of memory for urb buffers.", __FUNCTION__);
 			continue;
 		}
@@ -879,9 +909,7 @@ static int mos7840_open(struct usb_seria
 	}
 	Data |= 0x08;		//Driver done bit
 	Data |= 0x20;		//rx_disable
-	status = 0;
-	status =
-	    mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+	status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
 	if (status < 0) {
 		dbg("writing Controlreg failed\n");
 		return -1;
@@ -893,7 +921,6 @@ static int mos7840_open(struct usb_seria
 	////////////////////////////////////
 
 	Data = 0x00;
-	status = 0;
 	status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
 	if (status < 0) {
 		dbg("disableing interrupts failed\n");
@@ -901,7 +928,6 @@ static int mos7840_open(struct usb_seria
 	}
 	// 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");
@@ -909,7 +935,6 @@ static int mos7840_open(struct usb_seria
 	}
 
 	Data = 0xcf;
-	status = 0;
 	status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
 	if (status < 0) {
 		dbg("Writing FIFO_CONTROL_REGISTER  failed\n");
@@ -917,22 +942,18 @@ static int mos7840_open(struct usb_seria
 	}
 
 	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;
@@ -999,7 +1020,7 @@ static int mos7840_open(struct usb_seria
 /* 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 (port0->open_ports == 1) {
 		if (serial->port[0]->interrupt_in_buffer == NULL) {
 
 			/* set up interrupt urb */
@@ -1097,6 +1118,7 @@ static int mos7840_chars_in_buffer(struc
 {
 	int i;
 	int chars = 0;
+	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
 	dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
@@ -1112,13 +1134,15 @@ static int mos7840_chars_in_buffer(struc
 		return -1;
 	}
 
+	spin_lock_irqsave(&mos7840_port->pool_lock,flags);
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) {
+		if (mos7840_port->busy[i]) {
 			chars += URB_TRANSFER_BUFFER_SIZE;
 		}
 	}
+	spin_unlock_irqrestore(&mos7840_port->pool_lock,flags);
 	dbg("%s - returns %d", __FUNCTION__, chars);
-	return (chars);
+	return chars;
 
 }
 
@@ -1172,6 +1196,7 @@ static void mos7840_close(struct usb_ser
 {
 	struct usb_serial *serial;
 	struct moschip_port *mos7840_port;
+	struct moschip_port *port0;
 	int j;
 	__u16 Data;
 
@@ -1189,10 +1214,10 @@ static void mos7840_close(struct usb_ser
 	}
 
 	mos7840_port = mos7840_get_port_private(port);
+	port0 = mos7840_get_port_private(serial->port[0]);
 
-	if (mos7840_port == NULL) {
+	if (mos7840_port == NULL || port0 == NULL)
 		return;
-	}
 
 	for (j = 0; j < NUM_URBS; ++j)
 		usb_kill_urb(mos7840_port->write_urb_pool[j]);
@@ -1234,12 +1259,13 @@ static void mos7840_close(struct usb_ser
 	}
 //              if(mos7840_port->ctrl_buf != NULL)
 //                      kfree(mos7840_port->ctrl_buf);
-	mos7840_num_open_ports--;
+	port0->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) {
+	    port0->open_ports, port->number);
+	if (port0->open_ports == 0) {
 		if (serial->port[0]->interrupt_in_urb) {
 			dbg("%s", "Shutdown interrupt_in_urb\n");
+			usb_kill_urb(serial->port[0]->interrupt_in_urb);
 		}
 	}
 
@@ -1368,6 +1394,7 @@ static int mos7840_write_room(struct usb
 {
 	int i;
 	int room = 0;
+	unsigned long flags;
 	struct moschip_port *mos7840_port;
 
 	dbg("%s \n", " mos7840_write_room:entering ...........");
@@ -1384,14 +1411,17 @@ static int mos7840_write_room(struct usb
 		return -1;
 	}
 
+	spin_lock_irqsave(&mos7840_port->pool_lock, flags);
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+		if (!mos7840_port->busy[i]) {
 			room += URB_TRANSFER_BUFFER_SIZE;
 		}
 	}
+	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 
+	room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1;
 	dbg("%s - returns %d", __FUNCTION__, room);
-	return (room);
+	return room;
 
 }
 
@@ -1410,6 +1440,7 @@ static int mos7840_write(struct usb_seri
 	int i;
 	int bytes_sent = 0;
 	int transfer_size;
+	unsigned long flags;
 
 	struct moschip_port *mos7840_port;
 	struct usb_serial *serial;
@@ -1476,13 +1507,16 @@ #endif
 	/* try to find a free urb in the list */
 	urb = NULL;
 
+	spin_lock_irqsave(&mos7840_port->pool_lock, flags);
 	for (i = 0; i < NUM_URBS; ++i) {
-		if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+		if (!mos7840_port->busy[i]) {
+			mos7840_port->busy[i] = 1;
 			urb = mos7840_port->write_urb_pool[i];
 			dbg("\nURB:%d", i);
 			break;
 		}
 	}
+	spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 
 	if (urb == NULL) {
 		dbg("%s - no more free urbs", __FUNCTION__);
@@ -1518,6 +1552,7 @@ #endif
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 
 	if (status) {
+		mos7840_port->busy[i] = 0;
 		err("%s - usb_submit_urb(write bulk) failed with status = %d",
 		    __FUNCTION__, status);
 		bytes_sent = status;
@@ -1525,6 +1560,7 @@ #endif
 	}
 	bytes_sent = transfer_size;
 	mos7840_port->icount.tx += transfer_size;
+	smp_wmb();
 	dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
       exit:
 
@@ -2490,6 +2526,7 @@ static int mos7840_ioctl(struct usb_seri
 			if (signal_pending(current))
 				return -ERESTARTSYS;
 			cnow = mos7840_port->icount;
+			smp_rmb();
 			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
 			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
 				return -EIO;	/* no change => error */
@@ -2506,6 +2543,7 @@ static int mos7840_ioctl(struct usb_seri
 
 	case TIOCGICOUNT:
 		cnow = mos7840_port->icount;
+		smp_rmb();
 		icount.cts = cnow.cts;
 		icount.dsr = cnow.dsr;
 		icount.rng = cnow.rng;
@@ -2535,19 +2573,18 @@ static int mos7840_ioctl(struct usb_seri
 
 static int mos7840_calc_num_ports(struct usb_serial *serial)
 {
+	int mos7840_num_ports = 0;
 
 	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;
+		mos7840_num_ports = serial->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;
+		serial->num_bulk_in = 4;
+		serial->num_bulk_out = 4;
+		mos7840_num_ports = serial->num_ports = 4;
 	}
 
 	return mos7840_num_ports;
@@ -2583,7 +2620,9 @@ static int mos7840_startup(struct usb_se
 		mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
 		if (mos7840_port == NULL) {
 			err("%s - Out of memory", __FUNCTION__);
-			return -ENOMEM;
+			status = -ENOMEM;
+			i--; /* don't follow NULL pointer cleaning up */
+			goto error;
 		}
 
 		/* Initialize all port interrupt end point to port 0 int endpoint *
@@ -2591,6 +2630,7 @@ static int mos7840_startup(struct usb_se
 
 		mos7840_port->port = serial->port[i];
 		mos7840_set_port_private(serial->port[i], mos7840_port);
+		spin_lock_init(&mos7840_port->pool_lock);
 
 		mos7840_port->port_num = ((serial->port[i]->number -
 					   (serial->port[i]->serial->minor)) +
@@ -2601,22 +2641,22 @@ static int mos7840_startup(struct usb_se
 			mos7840_port->ControlRegOffset = 0x1;
 			mos7840_port->DcrRegOffset = 0x4;
 		} else if ((mos7840_port->port_num == 2)
-			   && (mos7840_num_ports == 4)) {
+			   && (serial->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)) {
+			   && (serial->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)) {
+			   && (serial->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)) {
+			   && (serial->num_ports == 4)) {
 			mos7840_port->SpRegOffset = 0xc;
 			mos7840_port->ControlRegOffset = 0xd;
 			mos7840_port->DcrRegOffset = 0x1c;
@@ -2701,21 +2741,19 @@ static int mos7840_startup(struct usb_se
 			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;
+			goto error;
 		} 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);
@@ -2729,7 +2767,7 @@ static int mos7840_startup(struct usb_se
 
 		//Zero Length flag register
 		if ((mos7840_port->port_num != 1)
-		    && (mos7840_num_ports == 2)) {
+		    && (serial->num_ports == 2)) {
 
 			Data = 0xff;
 			status = 0;
@@ -2770,14 +2808,17 @@ static int mos7840_startup(struct usb_se
 				    i + 1, status);
 
 		}
-		mos7840_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC);
+		mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
 		mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
-
+		mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+		if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || !mos7840_port->dr) {
+			status = -ENOMEM;
+			goto error;
+		}
 	}
 
 	//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);
@@ -2789,6 +2830,17 @@ static int mos7840_startup(struct usb_se
 	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			(__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
 	return 0;
+error:
+	for (/* nothing */; i >= 0; i--) {
+		mos7840_port = mos7840_get_port_private(serial->port[i]);
+
+		kfree(mos7840_port->dr);
+		kfree(mos7840_port->ctrl_buf);
+		usb_free_urb(mos7840_port->control_urb);
+		kfree(mos7840_port);
+		serial->port[i] = NULL;
+	}
+	return status;
 }
 
 /****************************************************************************
@@ -2799,6 +2851,7 @@ static int mos7840_startup(struct usb_se
 static void mos7840_shutdown(struct usb_serial *serial)
 {
 	int i;
+	unsigned long flags;
 	struct moschip_port *mos7840_port;
 	dbg("%s \n", " shutdown :entering..........");
 
@@ -2814,8 +2867,12 @@ static void mos7840_shutdown(struct usb_
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		mos7840_port = mos7840_get_port_private(serial->port[i]);
-		kfree(mos7840_port->ctrl_buf);
+		spin_lock_irqsave(&mos7840_port->pool_lock, flags);
+		mos7840_port->zombie = 1;
+		spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 		usb_kill_urb(mos7840_port->control_urb);
+		kfree(mos7840_port->ctrl_buf);
+		kfree(mos7840_port->dr);
 		kfree(mos7840_port);
 		mos7840_set_port_private(serial->port[i], NULL);
 	}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 0216ac1..4adfab9 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -69,6 +69,7 @@ static void omninet_write_bulk_callback	
 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);
+static int omninet_attach		(struct usb_serial *serial);
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
@@ -99,6 +100,7 @@ static struct usb_serial_driver zyxel_om
 	.num_bulk_in =		1,
 	.num_bulk_out =		2,
 	.num_ports =		1,
+	.attach =		omninet_attach,
 	.open =			omninet_open,
 	.close =		omninet_close,
 	.write =		omninet_write,
@@ -145,22 +147,30 @@ struct omninet_data
 	__u8	od_outseq;	// Sequence number for bulk_out URBs
 };
 
+static int omninet_attach (struct usb_serial *serial)
+{
+	struct omninet_data *od;
+	struct usb_serial_port *port = serial->port[0];
+
+	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+	if( !od ) {
+		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
+		return -ENOMEM;
+	}
+	usb_set_serial_port_data(port, od);
+	return 0;
+}
+
 static int omninet_open (struct usb_serial_port *port, struct file *filp)
 {
 	struct usb_serial	*serial = port->serial;
 	struct usb_serial_port	*wport;
-	struct omninet_data	*od;
+	struct omninet_data	*od = usb_get_serial_port_data(port);
 	int			result = 0;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
-	if( !od ) {
-		err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data));
-		return -ENOMEM;
-	}
-
-	usb_set_serial_port_data(port, od);
 	wport = serial->port[1];
 	wport->tty = port->tty;
 
@@ -170,24 +180,17 @@ static int omninet_open (struct usb_seri
 		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
 		      omninet_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-	if (result)
+	if (result) {
 		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+	}
 
 	return result;
 }
 
 static void omninet_close (struct usb_serial_port *port, struct file * filp)
 {
-	struct usb_serial 	*serial = port->serial;
-	struct usb_serial_port 	*wport;
-
 	dbg("%s - port %d", __FUNCTION__, port->number);
-
-	wport = serial->port[1];
-	usb_kill_urb(wport->write_urb);
 	usb_kill_urb(port->read_urb);
-
-	kfree(usb_get_serial_port_data(port));
 }
 
 
@@ -326,7 +329,12 @@ static void omninet_write_bulk_callback 
 
 static void omninet_shutdown (struct usb_serial *serial)
 {
+	struct usb_serial_port *wport = serial->port[1];
+	struct usb_serial_port *port = serial->port[0];
 	dbg ("%s", __FUNCTION__);
+
+	usb_kill_urb(wport->write_urb);
+	kfree(usb_get_serial_port_data(port));
 }
 
 
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e178e6f..8c3f55b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -113,6 +113,12 @@ #define NOVATELWIRELESS_VENDOR_ID		0x141
 #define ANYDATA_VENDOR_ID			0x16d5
 #define ANYDATA_PRODUCT_ID			0x6501
 
+#define BANDRICH_VENDOR_ID			0x1A8D
+#define BANDRICH_PRODUCT_C100_1			0x1002
+#define BANDRICH_PRODUCT_C100_2			0x1003
+
+#define DELL_VENDOR_ID				0x413C
+
 static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -165,6 +171,9 @@ static struct usb_device_id option_ids[]
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
+	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
+	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) },		/* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -591,12 +600,6 @@ static int option_open(struct usb_serial
 	return (0);
 }
 
-static inline void stop_urb(struct urb *urb)
-{
-	if (urb && urb->status == -EINPROGRESS)
-		usb_kill_urb(urb);
-}
-
 static void option_close(struct usb_serial_port *port, struct file *filp)
 {
 	int i;
@@ -614,9 +617,9 @@ static void option_close(struct usb_seri
 
 		/* Stop reading/writing urbs */
 		for (i = 0; i < N_IN_URB; i++)
-			stop_urb(portdata->in_urbs[i]);
+			usb_kill_urb(portdata->in_urbs[i]);
 		for (i = 0; i < N_OUT_URB; i++)
-			stop_urb(portdata->out_urbs[i]);
+			usb_kill_urb(portdata->out_urbs[i]);
 	}
 	port->tty = NULL;
 }
@@ -747,9 +750,9 @@ static void option_shutdown(struct usb_s
 		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]);
+			usb_kill_urb(portdata->in_urbs[j]);
 		for (j = 0; j < N_OUT_URB; j++)
-			stop_urb(portdata->out_urbs[j]);
+			usb_kill_urb(portdata->out_urbs[j]);
 	}
 
 	/* Now free them */
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index ecedd83..644607d 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -456,12 +456,6 @@ static int sierra_open(struct usb_serial
 	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;
@@ -479,9 +473,9 @@ static void sierra_close(struct usb_seri
 
 		/* Stop reading/writing urbs */
 		for (i = 0; i < N_IN_URB; i++)
-			stop_urb(portdata->in_urbs[i]);
+			usb_unlink_urb(portdata->in_urbs[i]);
 		for (i = 0; i < N_OUT_URB; i++)
-			stop_urb(portdata->out_urbs[i]);
+			usb_unlink_urb(portdata->out_urbs[i]);
 	}
 	port->tty = NULL;
 }
@@ -583,17 +577,26 @@ static void sierra_shutdown(struct usb_s
 	/* Stop reading/writing urbs */
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
+		if (!port)
+			continue;
 		portdata = usb_get_serial_port_data(port);
+		if (!portdata)
+			continue;
+
 		for (j = 0; j < N_IN_URB; j++)
-			stop_urb(portdata->in_urbs[j]);
+			usb_unlink_urb(portdata->in_urbs[j]);
 		for (j = 0; j < N_OUT_URB; j++)
-			stop_urb(portdata->out_urbs[j]);
+			usb_unlink_urb(portdata->out_urbs[j]);
 	}
 
 	/* Now free them */
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
+		if (!port)
+			continue;
 		portdata = usb_get_serial_port_data(port);
+		if (!portdata)
+			continue;
 
 		for (j = 0; j < N_IN_URB; j++) {
 			if (portdata->in_urbs[j]) {
@@ -612,6 +615,8 @@ static void sierra_shutdown(struct usb_s
 	/* Now free per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
+		if (!port)
+			continue;
 		kfree(usb_get_serial_port_data(port));
 	}
 }
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 7639022..87f3788 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -28,7 +28,6 @@ #include <linux/moduleparam.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 2f59ff2..ffbe601 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -384,19 +384,21 @@ static int visor_write (struct usb_seria
 		dbg("%s - write limit hit\n", __FUNCTION__);
 		return 0;
 	}
+	priv->outstanding_urbs++;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	buffer = kmalloc (count, GFP_ATOMIC);
 	if (!buffer) {
 		dev_err(&port->dev, "out of memory\n");
-		return -ENOMEM;
+		count = -ENOMEM;
+		goto error_no_buffer;
 	}
 
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		dev_err(&port->dev, "no more free urbs\n");
-		kfree (buffer);
-		return -ENOMEM;
+		count = -ENOMEM;
+		goto error_no_urb;
 	}
 
 	memcpy (buffer, buf, count);
@@ -415,19 +417,27 @@ static int visor_write (struct usb_seria
 		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
 			__FUNCTION__, status);
 		count = status;
-		kfree (buffer);
+		goto error;
 	} else {
 		spin_lock_irqsave(&priv->lock, flags);
-		++priv->outstanding_urbs;
 		priv->bytes_out += count;
 		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);
+	usb_free_urb(urb);
 
 	return count;
+error:
+	usb_free_urb(urb);
+error_no_urb:
+	kfree(buffer);
+error_no_buffer:
+	spin_lock_irqsave(&priv->lock, flags);
+	--priv->outstanding_urbs;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return count;
 }
 
 
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index bf16e9e..27c5f8f 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -1109,7 +1109,7 @@ static int firm_send_command (struct usb
 	command_port = port->serial->port[COMMAND_PORT];
 	command_info = usb_get_serial_port_data(command_port);
 	spin_lock_irqsave(&command_info->lock, flags);
-	command_info->command_finished = FALSE;
+	command_info->command_finished = false;
 	
 	transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer;
 	transfer_buffer[0] = command;
@@ -1124,12 +1124,12 @@ static int firm_send_command (struct usb
 	spin_unlock_irqrestore(&command_info->lock, flags);
 
 	/* wait for the command to complete */
-	wait_event_interruptible_timeout(command_info->wait_command, 
-		(command_info->command_finished != FALSE), COMMAND_TIMEOUT);
+	wait_event_interruptible_timeout(command_info->wait_command,
+		(bool)command_info->command_finished, COMMAND_TIMEOUT);
 
 	spin_lock_irqsave(&command_info->lock, flags);
 
-	if (command_info->command_finished == FALSE) {
+	if (command_info->command_finished == false) {
 		dbg("%s - command timed out.", __FUNCTION__);
 		retval = -ETIMEDOUT;
 		goto exit;
diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h
index d714eff..f160797 100644
--- a/drivers/usb/serial/whiteheat.h
+++ b/drivers/usb/serial/whiteheat.h
@@ -20,10 +20,6 @@ #ifndef __LINUX_USB_SERIAL_WHITEHEAT_H
 #define __LINUX_USB_SERIAL_WHITEHEAT_H
 
 
-#define FALSE	0
-#define TRUE	1
-
-
 /* WhiteHEAT commands */
 #define WHITEHEAT_OPEN			1	/* open the port */
 #define WHITEHEAT_CLOSE			2	/* close the port */
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index 599ad10..06d1107 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -117,6 +117,7 @@ EXPORT_SYMBOL_GPL(usb_usual_check_type);
 static int usu_probe(struct usb_interface *intf,
 			 const struct usb_device_id *id)
 {
+	int rc;
 	unsigned long type;
 	struct task_struct* task;
 	unsigned long flags;
@@ -135,7 +136,7 @@ static int usu_probe(struct usb_interfac
 
 	task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
 	if (IS_ERR(task)) {
-		int rc = PTR_ERR(task);
+		rc = PTR_ERR(task);
 		printk(KERN_WARNING "libusual: "
 		    "Unable to start the thread for %s: %d\n",
 		    bias_names[type], rc);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 4a9d0d5..8b3145a 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1371,15 +1371,6 @@ UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
-/* This prevents the kernel from detecting the virtual cd-drive with the
- * Windows drivers.  <johann.wilhelm@student.tugraz.at>
-*/
-UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0xffff,
-		"HUAWEI",
-		"E220 USB-UMTS Install",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_IGNORE_DEVICE),
-
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
 UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
 		"Minolta",
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 21f3ddb..6dac1ff 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -47,7 +47,6 @@ #define _USB_H_
 #include <linux/usb.h>
 #include <linux/usb_usual.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
 #include <scsi/scsi_host.h>
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 46929a1..8432bf1 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -34,18 +34,25 @@ static struct usb_device_id skel_table [
 };
 MODULE_DEVICE_TABLE(usb, skel_table);
 
+/* to prevent a race between open and disconnect */
+static DEFINE_MUTEX(skel_open_lock);
+
 
 /* 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)
+/* MAX_TRANSFER is chosen so that the VM is not stressed by
+   allocations > PAGE_SIZE and the number of packets in a page
+   is an integer 512 is the largest possible packet on EHCI */
 #define WRITES_IN_FLIGHT	8
+/* arbitrarily chosen */
 
 /* Structure to hold all of our device specific stuff */
 struct usb_skel {
-	struct usb_device       *dev;			/* the usb device for this device */
-	struct usb_interface    *interface;		/* the interface for this device */
+	struct usb_device	*udev;			/* 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 */
 	size_t			bulk_in_size;		/* the size of the receive buffer */
@@ -76,8 +83,10 @@ static int skel_open(struct inode *inode
 
 	subminor = iminor(inode);
 
+	mutex_lock(&skel_open_lock);
 	interface = usb_find_interface(&skel_driver, subminor);
 	if (!interface) {
+		mutex_unlock(&skel_open_lock);
 		err ("%s - error, can't find device for minor %d",
 		     __FUNCTION__, subminor);
 		retval = -ENODEV;
@@ -86,12 +95,15 @@ static int skel_open(struct inode *inode
 
 	dev = usb_get_intfdata(interface);
 	if (!dev) {
+		mutex_unlock(&skel_open_lock);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	/* increment our usage count for the device */
 	kref_get(&dev->kref);
+	/* now we can drop the lock */
+	mutex_unlock(&skel_open_lock);
 
 	/* prevent the device from being autosuspended */
 	retval = usb_autopm_get_interface(interface);
@@ -201,12 +213,6 @@ 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) {
@@ -225,6 +231,14 @@ static ssize_t skel_write(struct file *f
 		goto error;
 	}
 
+	/* this lock makes sure we don't submit URBs to gone devices */
+	mutex_lock(&dev->io_mutex);
+	if (!dev->interface) {		/* disconnect() was called */
+		mutex_unlock(&dev->io_mutex);
+		retval = -ENODEV;
+		goto error;
+	}
+
 	/* initialize the urb properly */
 	usb_fill_bulk_urb(urb, dev->udev,
 			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
@@ -233,6 +247,7 @@ static ssize_t skel_write(struct file *f
 
 	/* send the data out the bulk port */
 	retval = usb_submit_urb(urb, GFP_KERNEL);
+	mutex_unlock(&dev->io_mutex);
 	if (retval) {
 		err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
 		goto error;
@@ -241,7 +256,7 @@ 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);
 
-	mutex_unlock(&dev->io_mutex);
+
 	return writesize;
 
 error:
@@ -249,7 +264,6 @@ error:
 		usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
 		usb_free_urb(urb);
 	}
-	mutex_unlock(&dev->io_mutex);
 	up(&dev->limit_sem);
 
 exit:
@@ -344,6 +358,7 @@ static int skel_probe(struct usb_interfa
 
 error:
 	if (dev)
+		/* this frees allocated memory */
 		kref_put(&dev->kref, skel_delete);
 	return retval;
 }
@@ -354,20 +369,21 @@ static void skel_disconnect(struct usb_i
 	int minor = interface->minor;
 
 	/* prevent skel_open() from racing skel_disconnect() */
-	lock_kernel();
+	mutex_lock(&skel_open_lock);
 
 	dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 
 	/* give back our minor */
 	usb_deregister_dev(interface, &skel_class);
+	mutex_unlock(&skel_open_lock);
 
 	/* 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 */
 	kref_put(&dev->kref, skel_delete);
@@ -380,6 +396,7 @@ static struct usb_driver skel_driver = {
 	.probe =	skel_probe,
 	.disconnect =	skel_disconnect,
 	.id_table =	skel_table,
+	.supports_autosuspend = 1,
 };
 
 static int __init usb_skel_init(void)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8372ace..1132ba5 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,6 +5,11 @@ #
 menu "Graphics support"
 
 source "drivers/video/backlight/Kconfig"
+source "drivers/video/display/Kconfig"
+
+config VGASTATE
+       tristate
+       default n
 
 config FB
 	tristate "Support for frame buffer devices"
@@ -90,6 +95,43 @@ config FB_CFB_IMAGEBLIT
 	  blitting. This is used by drivers that don't provide their own
 	  (accelerated) version.
 
+config FB_SYS_FILLRECT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the sys_fillrect function for generic software rectangle
+	  filling. This is used by drivers that don't provide their own
+	  (accelerated) version and the framebuffer is in system RAM.
+
+config FB_SYS_COPYAREA
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the sys_copyarea function for generic software area copying.
+	  This is used by drivers that don't provide their own (accelerated)
+	  version and the framebuffer is in system RAM.
+
+config FB_SYS_IMAGEBLIT
+	tristate
+	depends on FB
+	default n
+	---help---
+	  Include the sys_imageblit function for generic software image
+	  blitting. This is used by drivers that don't provide their own
+	  (accelerated) version and the framebuffer is in system RAM.
+
+config FB_SYS_FOPS
+       tristate
+       depends on FB
+       default n
+
+config FB_DEFERRED_IO
+	bool
+	depends on FB
+	default y
+
 config FB_SVGALIB
 	tristate
 	depends on FB
@@ -191,7 +233,7 @@ config FB_ARMCLCD
 
 	  If you want to compile this as a module (=code which can be
 	  inserted into and removed from the running kernel), say M
-	  here and read <file:Documentation/modules.txt>.  The module
+	  here and read <file:Documentation/kbuild/modules.txt>.  The module
 	  will be called amba-clcd.
 
 choice
@@ -375,9 +417,10 @@ config FB_FM2
 config FB_ARC
 	tristate "Arc Monochrome LCD board support"
 	depends on FB && X86
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
 	help
 	  This enables support for the Arc Monochrome LCD board. The board
 	  is based on the KS-108 lcd controller and is typically a matrix
@@ -389,14 +432,17 @@ config FB_ARC
 
 config FB_ATARI
 	bool "Atari native chipset support"
-	depends on (FB = y) && ATARI && BROKEN
+	depends on (FB = y) && ATARI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
 	help
 	  This is the frame buffer device driver for the builtin graphics
 	  chipset found in Ataris.
 
 config FB_OF
 	bool "Open Firmware frame buffer device support"
-	depends on (FB = y) && (PPC64 || PPC_OF)
+	depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -472,6 +518,8 @@ config FB_VGA16
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select VGASTATE
+	select FONT_8x16 if FRAMEBUFFER_CONSOLE
 	help
 	  This is the frame buffer device driver for VGA 16 color graphic
 	  cards. Say Y if you have such a card.
@@ -516,15 +564,25 @@ config FB_HP300
 	default y
 
 config FB_TGA
-	tristate "TGA framebuffer support"
-	depends on FB && ALPHA
+	tristate "TGA/SFB+ framebuffer support"
+	depends on FB && (ALPHA || TC)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select BITREVERSE
-	help
-	  This is the frame buffer device driver for generic TGA graphic
-	  cards. Say Y if you have one of those.
+	---help---
+	  This is the frame buffer device driver for generic TGA and SFB+
+	  graphic cards.  These include DEC ZLXp-E1, -E2 and -E3 PCI cards,
+	  also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3
+	  TURBOchannel cards, also known as PMAGD-A, -B and -C.
+
+	  Due to hardware limitations ZLX-E2 and E3 cards are not supported
+	  for DECstation 5000/200 systems.  Additionally due to firmware
+	  limitations these cards may cause troubles with booting DECstation
+	  5000/240 and /260 systems, but are fully supported under Linux if
+	  you manage to get it going. ;-)
+
+	  Say Y if you have one of those.
 
 config FB_VESA
 	bool "VESA VGA graphics support"
@@ -548,6 +606,21 @@ config FB_IMAC
 	help
 	  This is the frame buffer device driver for the Intel-based Macintosh
 
+config FB_HECUBA
+       tristate "Hecuba board support"
+       depends on FB && X86 && MMU
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select FB_SYS_FOPS
+       select FB_DEFERRED_IO
+       help
+         This enables support for the Hecuba board. This driver was tested
+         with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO
+         interface (8 bit data, 4 bit control). If you anticpate 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.
+
 config FB_HGA
 	tristate "Hercules mono graphics support"
 	depends on FB && X86
@@ -683,6 +756,7 @@ config FB_NVIDIA
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select BITREVERSE
+	select VGASTATE
 	help
 	  This driver supports graphics boards with the nVidia chips, TNT
 	  and newer. For very old chipsets, such as the RIVA128, then use
@@ -721,6 +795,7 @@ config FB_RIVA
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select BITREVERSE
+	select VGASTATE
 	help
 	  This driver supports graphics boards with the nVidia Riva/Geforce
 	  chips.
@@ -767,6 +842,7 @@ config FB_I810
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select VGASTATE
 	help
 	  This driver supports the on-board graphics built in to the Intel 810 
           and 815 chipsets.  Say Y if you have and plan to use such a board.
@@ -806,6 +882,22 @@ config FB_I810_I2C
 	select FB_DDC
 	help
 
+config FB_LE80578
+	tristate "Intel LE80578 (Vermilion) support"
+	depends on FB && PCI && X86
+	select FB_MODE_HELPERS
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This driver supports the LE80578 (Vermilion Range) chipset
+
+config FB_CARILLO_RANCH
+	tristate "Intel Carillo Ranch support"
+	depends on FB_LE80578 && FB && PCI && X86
+	help
+	  This driver supports the LE80578 (Carillo Ranch) board
+
 config FB_INTEL
 	tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
 	depends on FB && EXPERIMENTAL && PCI && X86
@@ -1117,6 +1209,8 @@ config FB_S3
 	select FB_CFB_IMAGEBLIT
 	select FB_TILEBLITTING
 	select FB_SVGALIB
+	select VGASTATE
+	select FONT_8x16 if FRAMEBUFFER_CONSOLE
 	---help---
 	  Driver for graphics boards with S3 Trio / S3 Virge chip.
 
@@ -1127,6 +1221,7 @@ config FB_SAVAGE
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select VGASTATE
 	help
 	  This driver supports notebooks and computers with S3 Savage PCI/AGP
 	  chips.
@@ -1193,6 +1288,7 @@ config FB_NEOMAGIC
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select VGASTATE
 	help
 	  This driver supports notebooks with NeoMagic PCI chips.
 	  Say Y if you have such a graphics card. 
@@ -1380,6 +1476,32 @@ config FB_LEO
 	  This is the frame buffer device driver for the SBUS-based Sun ZX
 	  (leo) frame buffer cards.
 
+config FB_XVR500
+	bool "Sun XVR-500 3DLABS Wildcat support"
+	depends on FB && PCI && SPARC64
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer device for the Sun XVR-500 and similar
+	  graphics cards based upon the 3DLABS Wildcat chipset.  The driver
+	  only works on sparc64 systems where the system firwmare has
+	  mostly initialized the card already.  It is treated as a
+	  completely dumb framebuffer device.
+
+config FB_XVR2500
+	bool "Sun XVR-2500 3DLABS Wildcat support"
+	depends on FB && PCI && SPARC64
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer device for the Sun XVR-2500 and similar
+	  graphics cards based upon the 3DLABS Wildcat chipset.  The driver
+	  only works on sparc64 systems where the system firwmare has
+	  mostly initialized the card already.  It is treated as a
+	  completely dumb framebuffer device.
+
 config FB_PCI
 	bool "PCI framebuffers"
 	depends on (FB = y) && PCI && SPARC
@@ -1491,7 +1613,7 @@ config FB_PXA
 	  This driver is also available as a module ( = code which can be
 	  inserted and removed from the running kernel whenever you want). The
 	  module will be called pxafb. If you want to compile it as a module,
-	  say M here and read <file:Documentation/modules.txt>.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.
 
 	  If unsure, say N.
 
@@ -1544,7 +1666,7 @@ config FB_W100
 	  This driver is also available as a module ( = code which can be
 	  inserted and removed from the running kernel whenever you want). The
 	  module will be called w100fb. If you want to compile it as a module,
-	  say M here and read <file:Documentation/modules.txt>.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.
 
 	  If unsure, say N.
 
@@ -1561,7 +1683,7 @@ config FB_S3C2410
 	  This driver is also available as a module ( = code which can be
 	  inserted and removed from the running kernel whenever you want). The
 	  module will be called s3c2410fb. If you want to compile it as a module,
-	  say M here and read <file:Documentation/modules.txt>.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.
 
 	  If unsure, say N.
 config FB_S3C2410_DEBUG
@@ -1633,13 +1755,25 @@ config FB_PS3_DEFAULT_SIZE_M
 	  The default value can be overridden on the kernel command line
 	  using the "ps3fb" option (e.g. "ps3fb=9M");
 
-config FB_VIRTUAL
-	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
-	depends on FB
+config FB_XILINX
+	tristate "Xilinx frame buffer support"
+	depends on FB && XILINX_VIRTEX
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	---help---
+	  Include support for the Xilinx ML300/ML403 reference design
+	  framebuffer. ML300 carries a 640*480 LCD display on the board,
+	  ML403 uses a standard DB15 VGA connector.
+
+config FB_VIRTUAL
+	tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
+	depends on FB
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	---help---
 	  This is a `virtual' frame buffer device. It operates on a chunk of
 	  unswappable kernel memory instead of on the memory of a graphics
 	  board. This means you cannot see any output sent to this frame
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 760305c..a916c20 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,6 +4,7 @@ # Rewritten to use lists instead of if-s
 
 # Each configuration option enables a list of files.
 
+obj-$(CONFIG_VGASTATE)            += vgastate.o
 obj-y                             += fb_notify.o
 obj-$(CONFIG_FB)                  += fb.o
 fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
@@ -12,14 +13,19 @@ fb-objs                           := $(f
 
 obj-$(CONFIG_VT)		  += console/
 obj-$(CONFIG_LOGO)		  += logo/
-obj-y				  += backlight/
+obj-y				  += backlight/ display/
 
 obj-$(CONFIG_FB_CFB_FILLRECT)  += cfbfillrect.o
 obj-$(CONFIG_FB_CFB_COPYAREA)  += cfbcopyarea.o
 obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SYS_FILLRECT)  += sysfillrect.o
+obj-$(CONFIG_FB_SYS_COPYAREA)  += syscopyarea.o
+obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
+obj-$(CONFIG_FB_SYS_FOPS)      += fb_sys_fops.o
 obj-$(CONFIG_FB_SVGALIB)       += svgalib.o
 obj-$(CONFIG_FB_MACMODES)      += macmodes.o
 obj-$(CONFIG_FB_DDC)           += fb_ddc.o
+obj-$(CONFIG_FB_DEFERRED_IO)   += fb_defio.o
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
@@ -30,7 +36,7 @@ obj-$(CONFIG_FB_PM2)              += pm2
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 
 obj-$(CONFIG_FB_MATROX)		  += matrox/
-obj-$(CONFIG_FB_RIVA)		  += riva/ vgastate.o
+obj-$(CONFIG_FB_RIVA)		  += riva/
 obj-$(CONFIG_FB_NVIDIA)		  += nvidia/
 obj-$(CONFIG_FB_ATY)		  += aty/ macmodes.o
 obj-$(CONFIG_FB_ATY128)		  += aty/ macmodes.o
@@ -40,8 +46,7 @@ obj-$(CONFIG_FB_KYRO)             += kyr
 obj-$(CONFIG_FB_SAVAGE)		  += savage/
 obj-$(CONFIG_FB_GEODE)		  += geode/
 obj-$(CONFIG_FB_MBX)		  += mbx/
-obj-$(CONFIG_FB_I810)             += vgastate.o
-obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o vgastate.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_3DFX)             += tdfxfb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
@@ -51,7 +56,8 @@ obj-$(CONFIG_FB_IMSTT)            += ims
 obj-$(CONFIG_FB_FM2)              += fm2fb.o
 obj-$(CONFIG_FB_CYBLA)            += cyblafb.o
 obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o
-obj-$(CONFIG_FB_S3)               += s3fb.o vgastate.o
+obj-$(CONFIG_FB_LE80578)          += vermilion/
+obj-$(CONFIG_FB_S3)               += s3fb.o
 obj-$(CONFIG_FB_STI)              += stifb.o
 obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o
 obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o
@@ -63,9 +69,13 @@ obj-$(CONFIG_FB_TCX)              += tcx
 obj-$(CONFIG_FB_LEO)              += leo.o sbuslib.o
 obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
 obj-$(CONFIG_FB_ACORN)            += acornfb.o
-obj-$(CONFIG_FB_ATARI)            += atafb.o
+obj-$(CONFIG_FB_ATARI)            += atafb.o c2p.o atafb_mfb.o \
+                                     atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
 obj-$(CONFIG_FB_MAC)              += macfb.o
+obj-$(CONFIG_FB_HECUBA)           += hecubafb.o
 obj-$(CONFIG_FB_HGA)              += hgafb.o
+obj-$(CONFIG_FB_XVR500)           += sunxvr500.o
+obj-$(CONFIG_FB_XVR2500)          += sunxvr2500.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o
 obj-$(CONFIG_FB_Q40)              += q40fb.o
@@ -99,11 +109,12 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx
 obj-$(CONFIG_FB_IBM_GXT4500)	  += gxt4500.o
 obj-$(CONFIG_FB_PS3)		  += ps3fb.o
 obj-$(CONFIG_FB_SM501)            += sm501fb.o
+obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_IMAC)             += imacfb.o
-obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
+obj-$(CONFIG_FB_VGA16)            += vga16fb.o
 obj-$(CONFIG_FB_OF)               += offb.o
 
 # the test framebuffer is last
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 30a8369..db15bac 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -262,7 +262,8 @@ static void arcfb_lcd_update_page(struct
 	ks108_set_yaddr(par, chipindex, upper/8);
 
 	linesize = par->info->var.xres/8;
-	src = par->info->screen_base + (left/8) + (upper * linesize);
+	src = (unsigned char __force *) par->info->screen_base + (left/8) +
+		(upper * linesize);
 	ks108_set_xaddr(par, chipindex, left);
 
 	bitmask=1;
@@ -368,7 +369,7 @@ static void arcfb_fillrect(struct fb_inf
 {
 	struct arcfb_par *par = info->par;
 
-	cfb_fillrect(info, rect);
+	sys_fillrect(info, rect);
 
 	/* update the physical lcd */
 	arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
@@ -379,7 +380,7 @@ static void arcfb_copyarea(struct fb_inf
 {
 	struct arcfb_par *par = info->par;
 
-	cfb_copyarea(info, area);
+	sys_copyarea(info, area);
 
 	/* update the physical lcd */
 	arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
@@ -389,7 +390,7 @@ static void arcfb_imageblit(struct fb_in
 {
 	struct arcfb_par *par = info->par;
 
-	cfb_imageblit(info, image);
+	sys_imageblit(info, image);
 
 	/* update the physical lcd */
 	arcfb_lcd_update(par, image->dx, image->dy, image->width,
@@ -439,14 +440,11 @@ static int arcfb_ioctl(struct fb_info *i
  * the fb. it's inefficient for them to do anything less than 64*8
  * writes since we update the lcd in each write() anyway.
  */
-static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t count,
-				loff_t *ppos)
+static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
+			   size_t count, loff_t *ppos)
 {
 	/* modded from epson 1355 */
 
-	struct inode *inode;
-	int fbidx;
-	struct fb_info *info;
 	unsigned long p;
 	int err=-EINVAL;
 	unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
@@ -454,13 +452,6 @@ static ssize_t arcfb_write(struct file *
 	unsigned int xres;
 
 	p = *ppos;
-	inode = file->f_path.dentry->d_inode;
-	fbidx = iminor(inode);
-	info = registered_fb[fbidx];
-
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
 	par = info->par;
 	xres = info->var.xres;
 	fbmemlength = (xres * info->var.yres)/8;
@@ -477,7 +468,7 @@ static ssize_t arcfb_write(struct file *
 	if (count) {
 		char *base_addr;
 
-		base_addr = info->screen_base;
+		base_addr = (char __force *)info->screen_base;
 		count -= copy_from_user(base_addr + p, buf, count);
 		*ppos += count;
 		err = -EFAULT;
@@ -503,6 +494,7 @@ static ssize_t arcfb_write(struct file *
 static struct fb_ops arcfb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_open	= arcfb_open,
+	.fb_read        = fb_sys_read,
 	.fb_write	= arcfb_write,
 	.fb_release	= arcfb_release,
 	.fb_pan_display	= arcfb_pan_display,
@@ -603,7 +595,7 @@ static int arcfb_remove(struct platform_
 
 	if (info) {
 		unregister_framebuffer(info);
-		vfree(info->screen_base);
+		vfree((void __force *)info->screen_base);
 		framebuffer_release(info);
 	}
 	return 0;
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index bffe2b9..0038a05 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2,7 +2,7 @@
  * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
  *
  *  Copyright (C) 1994 Martin Schaller & Roman Hodek
- *  
+ *
  * 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.
@@ -70,14 +70,8 @@ #include <asm/atari_stram.h>
 #include <linux/fb.h>
 #include <asm/atarikb.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-iplan2p2.h>
-#include <video/fbcon-iplan2p4.h>
-#include <video/fbcon-iplan2p8.h>
-#include <video/fbcon-mfb.h>
-
+#include "c2p.h"
+#include "atafb.h"
 
 #define SWITCH_ACIA 0x01		/* modes for switch on OverScan */
 #define SWITCH_SND6 0x40
@@ -87,22 +81,48 @@ #define SWITCH_NONE 0x00
 
 #define up(x, r) (((x) + (r) - 1) & ~((r)-1))
 
+	/*
+	 * Interface to the world
+	 */
+
+static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int atafb_set_par(struct fb_info *info);
+static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+			   unsigned int blue, unsigned int transp,
+			   struct fb_info *info);
+static int atafb_blank(int blank, struct fb_info *info);
+static int atafb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static void atafb_fillrect(struct fb_info *info,
+			   const struct fb_fillrect *rect);
+static void atafb_copyarea(struct fb_info *info,
+			   const struct fb_copyarea *region);
+static void atafb_imageblit(struct fb_info *info, const struct fb_image *image);
+static int atafb_ioctl(struct fb_info *info, unsigned int cmd,
+		       unsigned long arg);
+
 
-static int default_par=0;	/* default resolution (0=none) */
+static int default_par;		/* default resolution (0=none) */
 
-static unsigned long default_mem_req=0;
+static unsigned long default_mem_req;
 
-static int hwscroll=-1;
+static int hwscroll = -1;
 
 static int use_hwscroll = 1;
 
-static int sttt_xres=640,st_yres=400,tt_yres=480;
-static int sttt_xres_virtual=640,sttt_yres_virtual=400;
-static int ovsc_offset=0, ovsc_addlen=0;
+static int sttt_xres = 640, st_yres = 400, tt_yres = 480;
+static int sttt_xres_virtual = 640, sttt_yres_virtual = 400;
+static int ovsc_offset, ovsc_addlen;
+
+	/*
+	 * Hardware parameters for current mode
+	 */
 
 static struct atafb_par {
 	void *screen_base;
 	int yres_virtual;
+	u_long next_line;
+	u_long next_plane;
 #if defined ATAFB_TT || defined ATAFB_STE
 	union {
 		struct {
@@ -138,7 +158,7 @@ #endif
 /* Don't calculate an own resolution, and thus don't change the one found when
  * booting (currently used for the Falcon to keep settings for internal video
  * hardware extensions (e.g. ScreenBlaster)  */
-static int DontCalcRes = 0; 
+static int DontCalcRes = 0;
 
 #ifdef ATAFB_FALCON
 #define HHT hw.falcon.hht
@@ -163,83 +183,84 @@ #define VMO_INTER		0x02
 #define VMO_PREMASK		0x0c
 #endif
 
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+	.fix = {
+		.id	= "Atari ",
+		.visual	= FB_VISUAL_PSEUDOCOLOR,
+		.accel	= FB_ACCEL_NONE,
+	}
+};
 
 static void *screen_base;	/* base address of screen */
 static void *real_screen_base;	/* (only for Overscan) */
 
 static int screen_len;
 
-static int current_par_valid=0; 
+static int current_par_valid;
 
-static int mono_moni=0;
-
-static struct display disp;
+static int mono_moni;
 
 
 #ifdef ATAFB_EXT
-/* external video handling */
 
-static unsigned			external_xres;
-static unsigned			external_xres_virtual;
-static unsigned			external_yres;
-/* not needed - atafb will never support panning/hardwarescroll with external
- * static unsigned		external_yres_virtual;	
-*/
+/* external video handling */
+static unsigned int external_xres;
+static unsigned int external_xres_virtual;
+static unsigned int external_yres;
 
-static unsigned			external_depth;
-static int				external_pmode;
-static void *external_addr = 0;
-static unsigned long	external_len;
-static unsigned long	external_vgaiobase = 0;
-static unsigned int		external_bitspercol = 6;
-
-/* 
-JOE <joe@amber.dinoco.de>: 
-added card type for external driver, is only needed for
-colormap handling.
-*/
+/*
+ * not needed - atafb will never support panning/hardwarescroll with external
+ * static unsigned int external_yres_virtual;
+ */
+static unsigned int external_depth;
+static int external_pmode;
+static void *external_addr;
+static unsigned long external_len;
+static unsigned long external_vgaiobase;
+static unsigned int external_bitspercol = 6;
 
+/*
+ * JOE <joe@amber.dinoco.de>:
+ * added card type for external driver, is only needed for
+ * colormap handling.
+ */
 enum cardtype { IS_VGA, IS_MV300 };
 static enum cardtype external_card_type = IS_VGA;
 
 /*
-The MV300 mixes the color registers. So we need an array of munged
-indices in order to access the correct reg.
-*/
-static int MV300_reg_1bit[2]={0,1};
-static int MV300_reg_4bit[16]={
-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-static int MV300_reg_8bit[256]={
-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 
-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 
-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 
-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 
-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 
-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 
-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 
-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 
-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 
-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 
-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 
-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 
-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 
-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 
-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 
-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; 
+ * The MV300 mixes the color registers. So we need an array of munged
+ * indices in order to access the correct reg.
+ */
+static int MV300_reg_1bit[2] = {
+	0, 1
+};
+static int MV300_reg_4bit[16] = {
+	0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
+};
+static int MV300_reg_8bit[256] = {
+	0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+	8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+	4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+	12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+	2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+	10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+	6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+	14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+	1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+	9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+	5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+	13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+	3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+	11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+	7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+	15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
 
 static int *MV300_reg = MV300_reg_8bit;
-
-/*
-And on the MV300 it's difficult to read out the hardware palette. So we
-just keep track of the set colors in our own array here, and use that!
-*/
-
-static struct { unsigned char red,green,blue,pad; } ext_color[256];
 #endif /* ATAFB_EXT */
 
 
-static int inverse=0;
+static int inverse;
 
 extern int fontheight_8x8;
 extern int fontwidth_8x8;
@@ -249,96 +270,154 @@ extern int fontheight_8x16;
 extern int fontwidth_8x16;
 extern unsigned char fontdata_8x16[];
 
+/*
+ * struct fb_ops {
+ *	* open/release and usage marking
+ *	struct module *owner;
+ *	int (*fb_open)(struct fb_info *info, int user);
+ *	int (*fb_release)(struct fb_info *info, int user);
+ *
+ *	* For framebuffers with strange non linear layouts or that do not
+ *	* work with normal memory mapped access
+ *	ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
+ *	ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+ *
+ *	* checks var and eventually tweaks it to something supported,
+ *	* DOES NOT MODIFY PAR *
+ *	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
+ *
+ *	* set the video mode according to info->var *
+ *	int (*fb_set_par)(struct fb_info *info);
+ *
+ *	* set color register *
+ *	int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green,
+ *			    unsigned int blue, unsigned int transp, struct fb_info *info);
+ *
+ *	* set color registers in batch *
+ *	int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
+ *
+ *	* blank display *
+ *	int (*fb_blank)(int blank, struct fb_info *info);
+ *
+ *	* pan display *
+ *	int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
+ *
+ *	*** The meat of the drawing engine ***
+ *	* Draws a rectangle *
+ *	void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
+ *	* Copy data from area to another *
+ *	void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
+ *	* Draws a image to the display *
+ *	void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
+ *
+ *	* Draws cursor *
+ *	int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
+ *
+ *	* Rotates the display *
+ *	void (*fb_rotate)(struct fb_info *info, int angle);
+ *
+ *	* wait for blit idle, optional *
+ *	int (*fb_sync)(struct fb_info *info);
+ *
+ *	* perform fb specific ioctl (optional) *
+ *	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
+ *			unsigned long arg);
+ *
+ *	* Handle 32bit compat ioctl (optional) *
+ *	int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
+ *			unsigned long arg);
+ *
+ *	* perform fb specific mmap *
+ *	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
+ *
+ *	* save current hardware state *
+ *	void (*fb_save_state)(struct fb_info *info);
+ *
+ *	* restore saved state *
+ *	void (*fb_restore_state)(struct fb_info *info);
+ * } ;
+ */
+
+
 /* ++roman: This structure abstracts from the underlying hardware (ST(e),
  * TT, or Falcon.
  *
- * int (*detect)( void )
+ * int (*detect)(void)
  *   This function should detect the current video mode settings and
  *   store them in atafb_predefined[0] for later reference by the
  *   user. Return the index+1 of an equivalent predefined mode or 0
  *   if there is no such.
- * 
- * int (*encode_fix)( struct fb_fix_screeninfo *fix,
- *                    struct atafb_par *par )
+ *
+ * int (*encode_fix)(struct fb_fix_screeninfo *fix,
+ *                   struct atafb_par *par)
  *   This function should fill in the 'fix' structure based on the
  *   values in the 'par' structure.
- *   
- * int (*decode_var)( struct fb_var_screeninfo *var,
- *                    struct atafb_par *par )
+ * !!! Obsolete, perhaps !!!
+ *
+ * int (*decode_var)(struct fb_var_screeninfo *var,
+ *                   struct atafb_par *par)
  *   Get the video params out of 'var'. If a value doesn't fit, round
  *   it up, if it's too big, return EINVAL.
- *   Round up in the following order: bits_per_pixel, xres, yres, 
- *   xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
+ *   Round up in the following order: bits_per_pixel, xres, yres,
+ *   xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
  *   horizontal timing, vertical timing.
  *
- * int (*encode_var)( struct fb_var_screeninfo *var,
- *                    struct atafb_par *par );
+ * int (*encode_var)(struct fb_var_screeninfo *var,
+ *                   struct atafb_par *par);
  *   Fill the 'var' structure based on the values in 'par' and maybe
  *   other values read out of the hardware.
- *   
- * void (*get_par)( struct atafb_par *par )
+ *
+ * void (*get_par)(struct atafb_par *par)
  *   Fill the hardware's 'par' structure.
- *   
- * void (*set_par)( struct atafb_par *par )
+ *   !!! Used only by detect() !!!
+ *
+ * void (*set_par)(struct atafb_par *par)
  *   Set the hardware according to 'par'.
- *   
- * int (*getcolreg)( unsigned regno, unsigned *red,
- *                   unsigned *green, unsigned *blue,
- *                   unsigned *transp, struct fb_info *info )
- *   Read a single color register and split it into
- *   colors/transparent. Return != 0 for invalid regno.
  *
  * void (*set_screen_base)(void *s_base)
  *   Set the base address of the displayed frame buffer. Only called
  *   if yres_virtual > yres or xres_virtual > xres.
  *
- * int (*blank)( int blank_mode )
- *   Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
+ * int (*blank)(int blank_mode)
+ *   Blank the screen if blank_mode != 0, else unblank. If blank == NULL then
  *   the caller blanks by setting the CLUT to all black. Return 0 if blanking
  *   succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
  *   doesn't support it. Implements VESA suspend and powerdown modes on
  *   hardware that supports disabling hsync/vsync:
- *       blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
+ *       blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown.
  */
 
 static struct fb_hwswitch {
-	int  (*detect)( void );
-	int  (*encode_fix)( struct fb_fix_screeninfo *fix,
-						struct atafb_par *par );
-	int  (*decode_var)( struct fb_var_screeninfo *var,
-						struct atafb_par *par );
-	int  (*encode_var)( struct fb_var_screeninfo *var,
-						struct atafb_par *par );
-	void (*get_par)( struct atafb_par *par );
-	void (*set_par)( struct atafb_par *par );
-	int  (*getcolreg)( unsigned regno, unsigned *red,
-					   unsigned *green, unsigned *blue,
-					   unsigned *transp, struct fb_info *info );
+	int (*detect)(void);
+	int (*encode_fix)(struct fb_fix_screeninfo *fix,
+			  struct atafb_par *par);
+	int (*decode_var)(struct fb_var_screeninfo *var,
+			  struct atafb_par *par);
+	int (*encode_var)(struct fb_var_screeninfo *var,
+			  struct atafb_par *par);
+	void (*get_par)(struct atafb_par *par);
+	void (*set_par)(struct atafb_par *par);
 	void (*set_screen_base)(void *s_base);
-	int  (*blank)( int blank_mode );
-	int  (*pan_display)( struct fb_var_screeninfo *var,
-						 struct atafb_par *par);
+	int (*blank)(int blank_mode);
+	int (*pan_display)(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
 } *fbhw;
 
-static char *autodetect_names[] = {"autodetect", NULL};
-static char *stlow_names[] = {"stlow", NULL};
-static char *stmid_names[] = {"stmid", "default5", NULL};
-static char *sthigh_names[] = {"sthigh", "default4", NULL};
-static char *ttlow_names[] = {"ttlow", NULL};
-static char *ttmid_names[]= {"ttmid", "default1", NULL};
-static char *tthigh_names[]= {"tthigh", "default2", NULL};
-static char *vga2_names[] = {"vga2", NULL};
-static char *vga4_names[] = {"vga4", NULL};
-static char *vga16_names[] = {"vga16", "default3", NULL};
-static char *vga256_names[] = {"vga256", NULL};
-static char *falh2_names[] = {"falh2", NULL};
-static char *falh16_names[] = {"falh16", NULL};
+static char *autodetect_names[] = { "autodetect", NULL };
+static char *stlow_names[] = { "stlow", NULL };
+static char *stmid_names[] = { "stmid", "default5", NULL };
+static char *sthigh_names[] = { "sthigh", "default4", NULL };
+static char *ttlow_names[] = { "ttlow", NULL };
+static char *ttmid_names[] = { "ttmid", "default1", NULL };
+static char *tthigh_names[] = { "tthigh", "default2", NULL };
+static char *vga2_names[] = { "vga2", NULL };
+static char *vga4_names[] = { "vga4", NULL };
+static char *vga16_names[] = { "vga16", "default3", NULL };
+static char *vga256_names[] = { "vga256", NULL };
+static char *falh2_names[] = { "falh2", NULL };
+static char *falh16_names[] = { "falh16", NULL };
 
 static char **fb_var_names[] = {
-	/* Writing the name arrays directly in this array (via "(char *[]){...}")
-	 * crashes gcc 2.5.8 (sigsegv) if the inner array
-	 * contains more than two items. I've also seen that all elements
-	 * were identical to the last (my cross-gcc) :-(*/
 	autodetect_names,
 	stlow_names,
 	stmid_names,
@@ -353,18 +432,17 @@ static char **fb_var_names[] = {
 	falh2_names,
 	falh16_names,
 	NULL
-	/* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
 };
 
 static struct fb_var_screeninfo atafb_predefined[] = {
- 	/*
- 	 * yres_virtual==0 means use hw-scrolling if possible, else yres
- 	 */
- 	{ /* autodetect */
-	  0, 0, 0, 0, 0, 0, 0, 0,   		/* xres-grayscale */
-	  {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, 	/* red green blue tran*/
+	/*
+	 * yres_virtual == 0 means use hw-scrolling if possible, else yres
+	 */
+	{ /* autodetect */
+	  0, 0, 0, 0, 0, 0, 0, 0,		/* xres-grayscale */
+	  {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},	/* red green blue tran*/
 	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- 	{ /* st low */
+	{ /* st low */
 	  320, 200, 320, 0, 0, 0, 4, 0,
 	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
 	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
@@ -414,27 +492,100 @@ static struct fb_var_screeninfo atafb_pr
 	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
 };
 
-static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
+static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined);
 
+static struct fb_videomode atafb_modedb[] __initdata = {
+	/*
+	 *  Atari Video Modes
+	 *
+	 *  If you change these, make sure to update DEFMODE_* as well!
+	 */
 
-static int
-get_video_mode(char *vname)
+	/*
+	 *  ST/TT Video Modes
+	 */
+
+	{
+		/* 320x200, 15 kHz, 60 Hz (ST low) */
+		"st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 640x200, 15 kHz, 60 Hz (ST medium) */
+		"st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
+		"st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 320x480, 15 kHz, 60 Hz (TT low) */
+		"tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 640x480, 29 kHz, 57 Hz (TT medium) */
+		"tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 1280x960, 29 kHz, 60 Hz (TT high) */
+		"tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	},
+
+	/*
+	 *  VGA Video Modes
+	 */
+
+	{
+		/* 640x480, 31 kHz, 60 Hz (VGA) */
+		"vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	}, {
+		/* 640x400, 31 kHz, 70 Hz (VGA) */
+		"vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3,
+		FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	},
+
+	/*
+	 *  Falcon HiRes Video Modes
+	 */
+
+	{
+		/* 896x608, 31 kHz, 60 Hz (Falcon High) */
+		"falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3,
+		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+	},
+};
+
+#define NUM_TOTAL_MODES  ARRAY_SIZE(atafb_modedb)
+
+static char *mode_option __initdata = NULL;
+
+ /* default modes */
+
+#define DEFMODE_TT	5		/* "tt-high" for TT */
+#define DEFMODE_F30	7		/* "vga70" for Falcon */
+#define DEFMODE_STE	2		/* "st-high" for ST/E */
+#define DEFMODE_EXT	6		/* "vga" for external */
+
+
+static int get_video_mode(char *vname)
 {
-    char ***name_list;
-    char **name;
-    int i;
-    name_list=fb_var_names;
-    for (i = 0 ; i < num_atafb_predefined ; i++) {
-	name=*(name_list++);
-	if (! name || ! *name)
-	    break;
-	while (*name) {
-	    if (! strcmp(vname, *name))
-		return i+1;
-	    name++;
+	char ***name_list;
+	char **name;
+	int i;
+
+	name_list = fb_var_names;
+	for (i = 0; i < num_atafb_predefined; i++) {
+		name = *name_list++;
+		if (!name || !*name)
+			break;
+		while (*name) {
+			if (!strcmp(vname, *name))
+				return i + 1;
+			name++;
+		}
 	}
-    }
-    return 0;
+	return 0;
 }
 
 
@@ -443,93 +594,84 @@ get_video_mode(char *vname)
 
 #ifdef ATAFB_TT
 
-static int tt_encode_fix( struct fb_fix_screeninfo *fix,
-						  struct atafb_par *par )
-
+static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
 {
 	int mode;
 
-	strcpy(fix->id,"Atari Builtin");
+	strcpy(fix->id, "Atari Builtin");
 	fix->smem_start = (unsigned long)real_screen_base;
 	fix->smem_len = screen_len;
-	fix->type=FB_TYPE_INTERLEAVED_PLANES;
-	fix->type_aux=2;
-	fix->visual=FB_VISUAL_PSEUDOCOLOR;
+	fix->type = FB_TYPE_INTERLEAVED_PLANES;
+	fix->type_aux = 2;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
 	mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
 	if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
-		fix->type=FB_TYPE_PACKED_PIXELS;
-		fix->type_aux=0;
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
 		if (mode == TT_SHIFTER_TTHIGH)
-			fix->visual=FB_VISUAL_MONO01;
+			fix->visual = FB_VISUAL_MONO01;
 	}
-	fix->xpanstep=0;
-	fix->ypanstep=1;
-	fix->ywrapstep=0;
+	fix->xpanstep = 0;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
 	fix->line_length = 0;
 	fix->accel = FB_ACCEL_ATARIBLITT;
 	return 0;
 }
 
-
-static int tt_decode_var( struct fb_var_screeninfo *var,
-						  struct atafb_par *par )
+static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
 {
-	int xres=var->xres;
-	int yres=var->yres;
-	int bpp=var->bits_per_pixel;
+	int xres = var->xres;
+	int yres = var->yres;
+	int bpp = var->bits_per_pixel;
 	int linelen;
 	int yres_virtual = var->yres_virtual;
 
 	if (mono_moni) {
-		if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
+		if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2)
 			return -EINVAL;
-		par->hw.tt.mode=TT_SHIFTER_TTHIGH;
-		xres=sttt_xres*2;
-		yres=tt_yres*2;
-		bpp=1;
+		par->hw.tt.mode = TT_SHIFTER_TTHIGH;
+		xres = sttt_xres * 2;
+		yres = tt_yres * 2;
+		bpp = 1;
 	} else {
 		if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
 			return -EINVAL;
 		if (bpp > 4) {
-			if (xres > sttt_xres/2 || yres > tt_yres)
+			if (xres > sttt_xres / 2 || yres > tt_yres)
 				return -EINVAL;
-			par->hw.tt.mode=TT_SHIFTER_TTLOW;
-			xres=sttt_xres/2;
-			yres=tt_yres;
-			bpp=8;
-		}
-		else if (bpp > 2) {
+			par->hw.tt.mode = TT_SHIFTER_TTLOW;
+			xres = sttt_xres / 2;
+			yres = tt_yres;
+			bpp = 8;
+		} else if (bpp > 2) {
 			if (xres > sttt_xres || yres > tt_yres)
 				return -EINVAL;
-			if (xres > sttt_xres/2 || yres > st_yres/2) {
-				par->hw.tt.mode=TT_SHIFTER_TTMID;
-				xres=sttt_xres;
-				yres=tt_yres;
-				bpp=4;
-			}
-			else {
-				par->hw.tt.mode=TT_SHIFTER_STLOW;
-				xres=sttt_xres/2;
-				yres=st_yres/2;
-				bpp=4;
+			if (xres > sttt_xres / 2 || yres > st_yres / 2) {
+				par->hw.tt.mode = TT_SHIFTER_TTMID;
+				xres = sttt_xres;
+				yres = tt_yres;
+				bpp = 4;
+			} else {
+				par->hw.tt.mode = TT_SHIFTER_STLOW;
+				xres = sttt_xres / 2;
+				yres = st_yres / 2;
+				bpp = 4;
 			}
-		}
-		else if (bpp > 1) {
-			if (xres > sttt_xres || yres > st_yres/2)
+		} else if (bpp > 1) {
+			if (xres > sttt_xres || yres > st_yres / 2)
 				return -EINVAL;
-			par->hw.tt.mode=TT_SHIFTER_STMID;
-			xres=sttt_xres;
-			yres=st_yres/2;
-			bpp=2;
-		}
-		else if (var->xres > sttt_xres || var->yres > st_yres) {
+			par->hw.tt.mode = TT_SHIFTER_STMID;
+			xres = sttt_xres;
+			yres = st_yres / 2;
+			bpp = 2;
+		} else if (var->xres > sttt_xres || var->yres > st_yres) {
 			return -EINVAL;
-		}
-		else {
-			par->hw.tt.mode=TT_SHIFTER_STHIGH;
-			xres=sttt_xres;
-			yres=st_yres;
-			bpp=1;
+		} else {
+			par->hw.tt.mode = TT_SHIFTER_STHIGH;
+			xres = sttt_xres;
+			yres = st_yres;
+			bpp = 1;
 		}
 	}
 	if (yres_virtual <= 0)
@@ -537,10 +679,10 @@ static int tt_decode_var( struct fb_var_
 	else if (yres_virtual < yres)
 		yres_virtual = yres;
 	if (var->sync & FB_SYNC_EXT)
-		par->hw.tt.sync=0;
+		par->hw.tt.sync = 0;
 	else
-		par->hw.tt.sync=1;
-	linelen=xres*bpp/8;
+		par->hw.tt.sync = 1;
+	linelen = xres * bpp / 8;
 	if (yres_virtual * linelen > screen_len && screen_len)
 		return -EINVAL;
 	if (yres * linelen > screen_len && screen_len)
@@ -552,154 +694,123 @@ static int tt_decode_var( struct fb_var_
 	return 0;
 }
 
-static int tt_encode_var( struct fb_var_screeninfo *var,
-						  struct atafb_par *par )
+static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
 {
 	int linelen;
 	memset(var, 0, sizeof(struct fb_var_screeninfo));
-	var->red.offset=0;
-	var->red.length=4;
-	var->red.msb_right=0;
-	var->grayscale=0;
-
-	var->pixclock=31041;
-	var->left_margin=120;		/* these may be incorrect 	*/
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
-
-	var->height=-1;
-	var->width=-1;
+	var->red.offset = 0;
+	var->red.length = 4;
+	var->red.msb_right = 0;
+	var->grayscale = 0;
+
+	var->pixclock = 31041;
+	var->left_margin = 120;		/* these may be incorrect */
+	var->right_margin = 100;
+	var->upper_margin = 8;
+	var->lower_margin = 16;
+	var->hsync_len = 140;
+	var->vsync_len = 30;
+
+	var->height = -1;
+	var->width = -1;
 
 	if (par->hw.tt.sync & 1)
-		var->sync=0;
+		var->sync = 0;
 	else
-		var->sync=FB_SYNC_EXT;
+		var->sync = FB_SYNC_EXT;
 
 	switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
 	case TT_SHIFTER_STLOW:
-		var->xres=sttt_xres/2;
-		var->xres_virtual=sttt_xres_virtual/2;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=4;
+		var->xres = sttt_xres / 2;
+		var->xres_virtual = sttt_xres_virtual / 2;
+		var->yres = st_yres / 2;
+		var->bits_per_pixel = 4;
 		break;
 	case TT_SHIFTER_STMID:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=2;
+		var->xres = sttt_xres;
+		var->xres_virtual = sttt_xres_virtual;
+		var->yres = st_yres / 2;
+		var->bits_per_pixel = 2;
 		break;
 	case TT_SHIFTER_STHIGH:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=st_yres;
-		var->bits_per_pixel=1;
+		var->xres = sttt_xres;
+		var->xres_virtual = sttt_xres_virtual;
+		var->yres = st_yres;
+		var->bits_per_pixel = 1;
 		break;
 	case TT_SHIFTER_TTLOW:
-		var->xres=sttt_xres/2;
-		var->xres_virtual=sttt_xres_virtual/2;
-		var->yres=tt_yres;
-		var->bits_per_pixel=8;
+		var->xres = sttt_xres / 2;
+		var->xres_virtual = sttt_xres_virtual / 2;
+		var->yres = tt_yres;
+		var->bits_per_pixel = 8;
 		break;
 	case TT_SHIFTER_TTMID:
-		var->xres=sttt_xres;
-		var->xres_virtual=sttt_xres_virtual;
-		var->yres=tt_yres;
-		var->bits_per_pixel=4;
+		var->xres = sttt_xres;
+		var->xres_virtual = sttt_xres_virtual;
+		var->yres = tt_yres;
+		var->bits_per_pixel = 4;
 		break;
 	case TT_SHIFTER_TTHIGH:
-		var->red.length=0;
-		var->xres=sttt_xres*2;
-		var->xres_virtual=sttt_xres_virtual*2;
-		var->yres=tt_yres*2;
-		var->bits_per_pixel=1;
+		var->red.length = 0;
+		var->xres = sttt_xres * 2;
+		var->xres_virtual = sttt_xres_virtual * 2;
+		var->yres = tt_yres * 2;
+		var->bits_per_pixel = 1;
 		break;
-	}		
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	linelen=var->xres_virtual * var->bits_per_pixel / 8;
-	if (! use_hwscroll)
-		var->yres_virtual=var->yres;
+	}
+	var->blue = var->green = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	linelen = var->xres_virtual * var->bits_per_pixel / 8;
+	if (!use_hwscroll)
+		var->yres_virtual = var->yres;
 	else if (screen_len) {
 		if (par->yres_virtual)
 			var->yres_virtual = par->yres_virtual;
 		else
-			/* yres_virtual==0 means use maximum */
+			/* yres_virtual == 0 means use maximum */
 			var->yres_virtual = screen_len / linelen;
 	} else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
 		else
-			var->yres_virtual=var->yres+hwscroll * 16;
+			var->yres_virtual = var->yres + hwscroll * 16;
 	}
-	var->xoffset=0;
+	var->xoffset = 0;
 	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
+		var->yoffset = (par->screen_base - screen_base) / linelen;
 	else
-		var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
+		var->yoffset = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->vmode = FB_VMODE_NONINTERLACED;
 	return 0;
 }
 
-
-static void tt_get_par( struct atafb_par *par )
+static void tt_get_par(struct atafb_par *par)
 {
 	unsigned long addr;
-	par->hw.tt.mode=shifter_tt.tt_shiftmode;
-	par->hw.tt.sync=shifter.syncmode;
+	par->hw.tt.mode = shifter_tt.tt_shiftmode;
+	par->hw.tt.sync = shifter.syncmode;
 	addr = ((shifter.bas_hi & 0xff) << 16) |
 	       ((shifter.bas_md & 0xff) << 8)  |
 	       ((shifter.bas_lo & 0xff));
 	par->screen_base = phys_to_virt(addr);
 }
 
-static void tt_set_par( struct atafb_par *par )
+static void tt_set_par(struct atafb_par *par)
 {
-	shifter_tt.tt_shiftmode=par->hw.tt.mode;
-	shifter.syncmode=par->hw.tt.sync;
+	shifter_tt.tt_shiftmode = par->hw.tt.mode;
+	shifter.syncmode = par->hw.tt.sync;
 	/* only set screen_base if really necessary */
 	if (current_par.screen_base != par->screen_base)
 		fbhw->set_screen_base(par->screen_base);
 }
 
-
-static int tt_getcolreg(unsigned regno, unsigned *red,
-			unsigned *green, unsigned *blue,
-			unsigned *transp, struct fb_info *info)
-{
-	int t, col;
-
-	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
-		regno += 254;
-	if (regno > 255)
-		return 1;
-	t = tt_palette[regno];
-	col = t & 15;
-	col |= col << 4;
-	col |= col << 8;
-	*blue = col;
-	col = (t >> 4) & 15;
-	col |= col << 4;
-	col |= col << 8;
-	*green = col;
-	col = (t >> 8) & 15;
-	col |= col << 4;
-	col |= col << 8;
-	*red = col;
-	*transp = 0;
-	return 0;
-}
-
-
-static int tt_setcolreg(unsigned regno, unsigned red,
-			unsigned green, unsigned blue,
-			unsigned transp, struct fb_info *info)
+static int tt_setcolreg(unsigned int regno, unsigned int red,
+			unsigned int green, unsigned int blue,
+			unsigned int transp, struct fb_info *info)
 {
 	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
 		regno += 254;
@@ -708,15 +819,14 @@ static int tt_setcolreg(unsigned regno, 
 	tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
 			     (blue >> 12));
 	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
-		TT_SHIFTER_STHIGH && regno == 254)
+	    TT_SHIFTER_STHIGH && regno == 254)
 		tt_palette[0] = 0;
 	return 0;
 }
 
-						  
-static int tt_detect( void )
-
-{	struct atafb_par par;
+static int tt_detect(void)
+{
+	struct atafb_par par;
 
 	/* Determine the connected monitor: The DMA sound must be
 	 * disabled before reading the MFP GPIP, because the Sound
@@ -726,9 +836,9 @@ static int tt_detect( void )
 	 * announced that the Eagle is TT compatible, but only the PCM is
 	 * missing...
 	 */
-	if (ATARIHW_PRESENT(PCM_8BIT)) { 
+	if (ATARIHW_PRESENT(PCM_8BIT)) {
 		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		udelay(20);	/* wait a while for things to settle down */
+		udelay(20);		/* wait a while for things to settle down */
 	}
 	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
 
@@ -755,19 +865,24 @@ static struct pixel_clock {
 	unsigned long f;	/* f/[Hz] */
 	unsigned long t;	/* t/[ps] (=1/f) */
 	int right, hsync, left;	/* standard timing in clock cycles, not pixel */
-		/* hsync initialized in falcon_detect() */
+	/* hsync initialized in falcon_detect() */
 	int sync_mask;		/* or-mask for hw.falcon.sync to set this clock */
 	int control_mask;	/* ditto, for hw.falcon.vid_control */
-}
-f25  = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
-f32  = {32000000, 31250, 18, 0, 42, 0x0, 0},
-fext = {       0,     0, 18, 0, 42, 0x1, 0};
+} f25 = {
+	25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25
+}, f32 = {
+	32000000, 31250, 18, 0, 42, 0x0, 0
+}, fext = {
+	0, 0, 18, 0, 42, 0x1, 0
+};
 
 /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
+static int vdl_prescale[4][3] = {
+	{ 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 }
+};
 
 /* Default hsync timing [mon_type] in picoseconds */
-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
+static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
 
 #ifdef FBCON_HAS_CFB16
 static u16 fbcon_cfb16_cmap[16];
@@ -775,12 +890,12 @@ #endif
 
 static inline int hxx_prescale(struct falcon_hw *hw)
 {
-	return hw->ste_mode ? 16 :
-		   vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
+	return hw->ste_mode ? 16
+			    : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
 }
 
-static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
-							  struct atafb_par *par )
+static int falcon_encode_fix(struct fb_fix_screeninfo *fix,
+			     struct atafb_par *par)
 {
 	strcpy(fix->id, "Atari Builtin");
 	fix->smem_start = (unsigned long)real_screen_base;
@@ -796,8 +911,7 @@ static int falcon_encode_fix( struct fb_
 		fix->type_aux = 0;
 		/* no smooth scrolling with longword aligned video mem */
 		fix->xpanstep = 32;
-	}
-	else if (par->hw.falcon.f_shift & 0x100) {
+	} else if (par->hw.falcon.f_shift & 0x100) {
 		fix->type = FB_TYPE_PACKED_PIXELS;
 		fix->type_aux = 0;
 		/* Is this ok or should it be DIRECTCOLOR? */
@@ -809,9 +923,8 @@ static int falcon_encode_fix( struct fb_
 	return 0;
 }
 
-
-static int falcon_decode_var( struct fb_var_screeninfo *var,
-							  struct atafb_par *par )
+static int falcon_decode_var(struct fb_var_screeninfo *var,
+			     struct atafb_par *par)
 {
 	int bpp = var->bits_per_pixel;
 	int xres = var->xres;
@@ -823,17 +936,19 @@ static int falcon_decode_var( struct fb_
 	int linelen;
 	int interlace = 0, doubleline = 0;
 	struct pixel_clock *pclock;
-	int plen; /* width of pixel in clock cycles */
+	int plen;			/* width of pixel in clock cycles */
 	int xstretch;
 	int prescale;
 	int longoffset = 0;
 	int hfreq, vfreq;
+	int hdb_off, hde_off, base_off;
+	int gstart, gend1, gend2, align;
 
 /*
 	Get the video params out of 'var'. If a value doesn't fit, round
 	it up, if it's too big, return EINVAL.
-	Round up in the following order: bits_per_pixel, xres, yres, 
-	xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, 
+	Round up in the following order: bits_per_pixel, xres, yres,
+	xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
 	horizontal timing, vertical timing.
 
 	There is a maximum of screen resolution determined by pixelclock
@@ -843,11 +958,11 @@ static int falcon_decode_var( struct fb_
 	Frequency range for multisync monitors is given via command line.
 	For TV and SM124 both frequencies are fixed.
 
-	X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
+	X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0)
 	Y % 16 == 0 to fit 8x16 font
 	Y % 8 == 0 if Y<400
 
-	Currently interlace and doubleline mode in var are ignored. 
+	Currently interlace and doubleline mode in var are ignored.
 	On SM124 and TV only the standard resolutions can be used.
 */
 
@@ -855,43 +970,38 @@ static int falcon_decode_var( struct fb_
 	if (!xres || !yres || !bpp)
 		return -EINVAL;
 
-	if (mon_type == F_MON_SM && bpp != 1) {
+	if (mon_type == F_MON_SM && bpp != 1)
 		return -EINVAL;
-	}
-	else if (bpp <= 1) {
+
+	if (bpp <= 1) {
 		bpp = 1;
 		par->hw.falcon.f_shift = 0x400;
 		par->hw.falcon.st_shift = 0x200;
-	}
-	else if (bpp <= 2) {
+	} else if (bpp <= 2) {
 		bpp = 2;
 		par->hw.falcon.f_shift = 0x000;
 		par->hw.falcon.st_shift = 0x100;
-	}
-	else if (bpp <= 4) {
+	} else if (bpp <= 4) {
 		bpp = 4;
 		par->hw.falcon.f_shift = 0x000;
 		par->hw.falcon.st_shift = 0x000;
-	}
-	else if (bpp <= 8) {
+	} else if (bpp <= 8) {
 		bpp = 8;
 		par->hw.falcon.f_shift = 0x010;
-	}
-	else if (bpp <= 16) {
-		bpp = 16; /* packed pixel mode */
-		par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
-	}
-	else
+	} else if (bpp <= 16) {
+		bpp = 16;		/* packed pixel mode */
+		par->hw.falcon.f_shift = 0x100;	/* hicolor, no overlay */
+	} else
 		return -EINVAL;
 	par->hw.falcon.bpp = bpp;
 
 	if (mon_type == F_MON_SM || DontCalcRes) {
 		/* Skip all calculations. VGA/TV/SC1224 only supported. */
 		struct fb_var_screeninfo *myvar = &atafb_predefined[0];
-		
+
 		if (bpp > myvar->bits_per_pixel ||
-			var->xres > myvar->xres ||
-			var->yres > myvar->yres)
+		    var->xres > myvar->xres ||
+		    var->yres > myvar->yres)
 			return -EINVAL;
 		fbhw->get_par(par);	/* Current par will be new par */
 		goto set_screen_base;	/* Don't forget this */
@@ -910,8 +1020,8 @@ static int falcon_decode_var( struct fb_
 		yres = 400;
 
 	/* 2 planes must use STE compatibility mode */
-	par->hw.falcon.ste_mode = bpp==2;
-	par->hw.falcon.mono = bpp==1;
+	par->hw.falcon.ste_mode = bpp == 2;
+	par->hw.falcon.mono = bpp == 1;
 
 	/* Total and visible scanline length must be a multiple of one longword,
 	 * this and the console fontwidth yields the alignment for xres and
@@ -967,8 +1077,7 @@ #if 0 /* SM124 supports only 640x400, th
 		left_margin = hsync_len = 128 / plen;
 		right_margin = 0;
 		/* TODO set all margins */
-	}
-	else
+	} else
 #endif
 	if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
 		plen = 2 * xstretch;
@@ -1002,26 +1111,24 @@ #endif
 				vsync_len *= 2;
 			}
 		}
-	}
-	else
-	{	/* F_MON_VGA */
+	} else {			/* F_MON_VGA */
 		if (bpp == 16)
-			xstretch = 2; /* Double pixel width only for hicolor */
+			xstretch = 2;	/* Double pixel width only for hicolor */
 		/* Default values are used for vert./hor. timing if no pixelclock given. */
 		if (var->pixclock == 0) {
 			int linesize;
 
 			/* Choose master pixelclock depending on hor. timing */
 			plen = 1 * xstretch;
-			if ((plen * xres + f25.right+f25.hsync+f25.left) *
+			if ((plen * xres + f25.right + f25.hsync + f25.left) *
 			    fb_info.monspecs.hfmin < f25.f)
 				pclock = &f25;
-			else if ((plen * xres + f32.right+f32.hsync+f32.left) * 
-			    fb_info.monspecs.hfmin < f32.f)
+			else if ((plen * xres + f32.right + f32.hsync +
+				  f32.left) * fb_info.monspecs.hfmin < f32.f)
 				pclock = &f32;
-			else if ((plen * xres + fext.right+fext.hsync+fext.left) * 
-			    fb_info.monspecs.hfmin < fext.f
-			         && fext.f)
+			else if ((plen * xres + fext.right + fext.hsync +
+				  fext.left) * fb_info.monspecs.hfmin < fext.f &&
+			         fext.f)
 				pclock = &fext;
 			else
 				return -EINVAL;
@@ -1033,22 +1140,24 @@ #endif
 			upper_margin = 31;
 			lower_margin = 11;
 			vsync_len = 3;
-		}
-		else {
+		} else {
 			/* Choose largest pixelclock <= wanted clock */
 			int i;
 			unsigned long pcl = ULONG_MAX;
 			pclock = 0;
-			for (i=1; i <= 4; i *= 2) {
-				if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
+			for (i = 1; i <= 4; i *= 2) {
+				if (f25.t * i >= var->pixclock &&
+				    f25.t * i < pcl) {
 					pcl = f25.t * i;
 					pclock = &f25;
 				}
-				if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
+				if (f32.t * i >= var->pixclock &&
+				    f32.t * i < pcl) {
 					pcl = f32.t * i;
 					pclock = &f32;
 				}
-				if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
+				if (fext.t && fext.t * i >= var->pixclock &&
+				    fext.t * i < pcl) {
 					pcl = fext.t * i;
 					pclock = &fext;
 				}
@@ -1070,8 +1179,7 @@ #endif
 				upper_margin = (upper_margin + 1) / 2;
 				lower_margin = (lower_margin + 1) / 2;
 				vsync_len = (vsync_len + 1) / 2;
-			}
-			else if (var->vmode & FB_VMODE_DOUBLE) {
+			} else if (var->vmode & FB_VMODE_DOUBLE) {
 				/* External unit is [double lines per frame] */
 				upper_margin *= 2;
 				lower_margin *= 2;
@@ -1079,7 +1187,7 @@ #endif
 			}
 		}
 		if (pclock == &fext)
-			longoffset = 1; /* VIDEL doesn't synchronize on short offset */
+			longoffset = 1;	/* VIDEL doesn't synchronize on short offset */
 	}
 	/* Is video bus bandwidth (32MB/s) too low for this resolution? */
 	/* this is definitely wrong if bus clock != 32MHz */
@@ -1098,7 +1206,7 @@ #endif
 	 * between interlace and non-interlace without messing around
 	 * with these.
 	 */
-  again:
+again:
 	/* Set base_offset 128 and video bus width */
 	par->hw.falcon.vid_control = mon_type | f030_bus_width;
 	if (!longoffset)
@@ -1112,37 +1220,34 @@ #endif
 	/* External or internal clock */
 	par->hw.falcon.sync = pclock->sync_mask | 0x2;
 	/* Pixellength and prescale */
-	par->hw.falcon.vid_mode = (2/plen) << 2;
+	par->hw.falcon.vid_mode = (2 / plen) << 2;
 	if (doubleline)
 		par->hw.falcon.vid_mode |= VMO_DOUBLE;
 	if (interlace)
 		par->hw.falcon.vid_mode |= VMO_INTER;
 
 	/*********************
-	Horizontal timing: unit = [master clock cycles]
-	unit of hxx-registers: [master clock cycles * prescale]
-	Hxx-registers are 9 bit wide
-
-	1 line = ((hht + 2) * 2 * prescale) clock cycles
-
-	graphic output = hdb & 0x200 ?
-	       ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
-	       ( hht + 2  - hdb + hde) * prescale - hdboff + hdeoff
-	(this must be a multiple of plen*128/bpp, on VGA pixels
-	 to the right may be cut off with a bigger right margin)
-
-	start of graphics relative to start of 1st halfline = hdb & 0x200 ?
-	       (hdb - hht - 2) * prescale + hdboff :
-	       hdb * prescale + hdboff
-
-	end of graphics relative to start of 1st halfline =
-	       (hde + hht + 2) * prescale + hdeoff
-	*********************/
+	 * Horizontal timing: unit = [master clock cycles]
+	 * unit of hxx-registers: [master clock cycles * prescale]
+	 * Hxx-registers are 9 bit wide
+	 *
+	 * 1 line = ((hht + 2) * 2 * prescale) clock cycles
+	 *
+	 * graphic output = hdb & 0x200 ?
+	 *        ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff:
+	 *        (hht + 2  - hdb + hde) * prescale - hdboff + hdeoff
+	 * (this must be a multiple of plen*128/bpp, on VGA pixels
+	 *  to the right may be cut off with a bigger right margin)
+	 *
+	 * start of graphics relative to start of 1st halfline = hdb & 0x200 ?
+	 *        (hdb - hht - 2) * prescale + hdboff :
+	 *        hdb * prescale + hdboff
+	 *
+	 * end of graphics relative to start of 1st halfline =
+	 *        (hde + hht + 2) * prescale + hdeoff
+	 *********************/
 	/* Calculate VIDEL registers */
-	{
-	int hdb_off, hde_off, base_off;
-	int gstart, gend1, gend2, align;
-
+{
 	prescale = hxx_prescale(&par->hw.falcon);
 	base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
 
@@ -1154,8 +1259,7 @@ #endif
 		align = 1;
 		hde_off = 0;
 		hdb_off = (base_off + 16 * plen) + prescale;
-	}
-	else {
+	} else {
 		align = 128 / bpp;
 		hde_off = ((128 / bpp + 2) * plen);
 		if (par->hw.falcon.ste_mode)
@@ -1164,23 +1268,24 @@ #endif
 			hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
 	}
 
-	gstart = (prescale/2 + plen * left_margin) / prescale;
+	gstart = (prescale / 2 + plen * left_margin) / prescale;
 	/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
-	gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
+	gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale;
 	/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
 	gend2 = gstart + xres * plen / prescale;
 	par->HHT = plen * (left_margin + xres + right_margin) /
 			   (2 * prescale) - 2;
 /*	par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
 
-	par->HDB = gstart - hdb_off/prescale;
+	par->HDB = gstart - hdb_off / prescale;
 	par->HBE = gstart;
-	if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
-	par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
+	if (par->HDB < 0)
+		par->HDB += par->HHT + 2 + 0x200;
+	par->HDE = gend1 - par->HHT - 2 - hde_off / prescale;
 	par->HBB = gend2 - par->HHT - 2;
 #if 0
 	/* One more Videl constraint: data fetch of two lines must not overlap */
-	if ((par->HDB & 0x200)  &&  (par->HDB & ~0x200) - par->HDE <= 5) {
+	if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
 		/* if this happens increase margins, decrease hfreq. */
 	}
 #endif
@@ -1189,11 +1294,11 @@ #endif
 	par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
 	if (par->HSS < par->HBB)
 		par->HSS = par->HBB;
-	}
+}
 
 	/*  check hor. frequency */
-	hfreq = pclock->f / ((par->HHT+2)*prescale*2);
-	if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
+	hfreq = pclock->f / ((par->HHT + 2) * prescale * 2);
+	if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) {
 		/* ++guenther:   ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
 		/* Too high -> enlarge margin */
 		left_margin += 1;
@@ -1213,12 +1318,14 @@ #endif
 	par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
 	par->VDB = par->VBE;
 	par->VDE = yres;
-	if (!interlace) par->VDE <<= 1;
-	if (doubleline) par->VDE <<= 1;  /* VDE now half lines per (half-)frame */
+	if (!interlace)
+		par->VDE <<= 1;
+	if (doubleline)
+		par->VDE <<= 1;		/* VDE now half lines per (half-)frame */
 	par->VDE += par->VDB;
 	par->VBB = par->VDE;
 	par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
-	par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
+	par->VSS = par->VFT + 1 - (vsync_len * 2 - 1);
 	/* vbb,vss,vft must be even in interlace mode */
 	if (interlace) {
 		par->VBB++;
@@ -1229,55 +1336,53 @@ #endif
 	/* V-frequency check, hope I didn't create any loop here. */
 	/* Interlace and doubleline are mutually exclusive. */
 	vfreq = (hfreq * 2) / (par->VFT + 1);
-	if      (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
+	if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
 		/* Too high -> try again with doubleline */
 		doubleline = 1;
 		goto again;
-	}
-	else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
+	} else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
 		/* Too low -> try again with interlace */
 		interlace = 1;
 		goto again;
-	}
-	else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
+	} else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
 		/* Doubleline too low -> clear doubleline and enlarge margins */
 		int lines;
 		doubleline = 0;
-		for (lines=0;
-		     (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
+		for (lines = 0;
+		     (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) >
+		     fb_info.monspecs.vfmax;
 		     lines++)
 			;
 		upper_margin += lines;
 		lower_margin += lines;
 		goto again;
-	}
-	else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
+	} else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
 		/* Doubleline too high -> enlarge margins */
 		int lines;
-		for (lines=0;
-		     (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
-		     lines+=2)
+		for (lines = 0;
+		     (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
+		     fb_info.monspecs.vfmax;
+		     lines += 2)
 			;
 		upper_margin += lines;
 		lower_margin += lines;
 		goto again;
-	}
-	else if (vfreq > fb_info.monspecs.vfmax && interlace) {
+	} else if (vfreq > fb_info.monspecs.vfmax && interlace) {
 		/* Interlace, too high -> enlarge margins */
 		int lines;
-		for (lines=0;
-		     (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+		for (lines = 0;
+		     (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
+		     fb_info.monspecs.vfmax;
 		     lines++)
 			;
 		upper_margin += lines;
 		lower_margin += lines;
 		goto again;
-	}
-	else if (vfreq < fb_info.monspecs.vfmin ||
-		 vfreq > fb_info.monspecs.vfmax)
+	} else if (vfreq < fb_info.monspecs.vfmin ||
+		   vfreq > fb_info.monspecs.vfmax)
 		return -EINVAL;
 
-  set_screen_base:
+set_screen_base:
 	linelen = xres_virtual * bpp / 8;
 	if (yres_virtual * linelen > screen_len && screen_len)
 		return -EINVAL;
@@ -1289,11 +1394,20 @@ #endif
 	par->screen_base = screen_base + var->yoffset * linelen;
 	par->hw.falcon.xoffset = 0;
 
+	// FIXME!!! sort of works, no crash
+	//par->next_line = linelen;
+	//par->next_plane = yres_virtual * linelen;
+	par->next_line = linelen;
+	par->next_plane = 2;
+	// crashes
+	//par->next_plane = linelen;
+	//par->next_line  = yres_virtual * linelen;
+
 	return 0;
 }
 
-static int falcon_encode_var( struct fb_var_screeninfo *var,
-							  struct atafb_par *par )
+static int falcon_encode_var(struct fb_var_screeninfo *var,
+			     struct atafb_par *par)
 {
 /* !!! only for VGA !!! */
 	int linelen;
@@ -1306,10 +1420,10 @@ static int falcon_encode_var( struct fb_
 	var->pixclock = hw->sync & 0x1 ? fext.t :
 	                hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
 
-	var->height=-1;
-	var->width=-1;
+	var->height = -1;
+	var->width = -1;
 
-	var->sync=0;
+	var->sync = 0;
 	if (hw->vid_control & VCO_HSYPOS)
 		var->sync |= FB_SYNC_HOR_HIGH_ACT;
 	if (hw->vid_control & VCO_VSYPOS)
@@ -1320,7 +1434,7 @@ static int falcon_encode_var( struct fb_
 		var->vmode |= FB_VMODE_INTERLACED;
 	if (hw->vid_mode & VMO_DOUBLE)
 		var->vmode |= FB_VMODE_DOUBLE;
-	
+
 	/* visible y resolution:
 	 * Graphics display starts at line VDB and ends at line
 	 * VDE. If interlace mode off unit of VC-registers is
@@ -1332,14 +1446,15 @@ static int falcon_encode_var( struct fb_
 	if (var->vmode & FB_VMODE_DOUBLE)
 		var->yres >>= 1;
 
-	/* to get bpp, we must examine f_shift and st_shift.
+	/*
+	 * to get bpp, we must examine f_shift and st_shift.
 	 * f_shift is valid if any of bits no. 10, 8 or 4
 	 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
 	 * if bit 10 set then bit 8 and bit 4 don't care...
 	 * If all these bits are 0 get display depth from st_shift
 	 * (as for ST and STE)
 	 */
-	if (hw->f_shift & 0x400)		/* 2 colors */
+	if (hw->f_shift & 0x400)	/* 2 colors */
 		var->bits_per_pixel = 1;
 	else if (hw->f_shift & 0x100)	/* hicolor */
 		var->bits_per_pixel = 16;
@@ -1349,7 +1464,7 @@ static int falcon_encode_var( struct fb_
 		var->bits_per_pixel = 4;
 	else if (hw->st_shift == 0x100)
 		var->bits_per_pixel = 2;
-	else /* if (hw->st_shift == 0x200) */
+	else				/* if (hw->st_shift == 0x200) */
 		var->bits_per_pixel = 1;
 
 	var->xres = hw->line_width * 16 / var->bits_per_pixel;
@@ -1358,42 +1473,42 @@ static int falcon_encode_var( struct fb_
 		var->xres_virtual += 16;
 
 	if (var->bits_per_pixel == 16) {
-		var->red.offset=11;
-		var->red.length=5;
-		var->red.msb_right=0;
-		var->green.offset=5;
-		var->green.length=6;
-		var->green.msb_right=0;
-		var->blue.offset=0;
-		var->blue.length=5;
-		var->blue.msb_right=0;
-	}
-	else {
-		var->red.offset=0;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->red.msb_right = 0;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->green.msb_right = 0;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->blue.msb_right = 0;
+	} else {
+		var->red.offset = 0;
 		var->red.length = hw->ste_mode ? 4 : 6;
-		var->red.msb_right=0;
-		var->grayscale=0;
-		var->blue=var->green=var->red;
+		if (var->red.length > var->bits_per_pixel)
+			var->red.length = var->bits_per_pixel;
+		var->red.msb_right = 0;
+		var->grayscale = 0;
+		var->blue = var->green = var->red;
 	}
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
 
 	linelen = var->xres_virtual * var->bits_per_pixel / 8;
 	if (screen_len) {
 		if (par->yres_virtual)
 			var->yres_virtual = par->yres_virtual;
 		else
-			/* yres_virtual==0 means use maximum */
+			/* yres_virtual == 0 means use maximum */
 			var->yres_virtual = screen_len / linelen;
-	}
-	else {
+	} else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
 		else
-			var->yres_virtual=var->yres+hwscroll * 16;
+			var->yres_virtual = var->yres + hwscroll * 16;
 	}
-	var->xoffset=0; /* TODO change this */
+	var->xoffset = 0;		/* TODO change this */
 
 	/* hdX-offsets */
 	prescale = hxx_prescale(hw);
@@ -1402,8 +1517,7 @@ static int falcon_encode_var( struct fb_
 	if (hw->f_shift & 0x100) {
 		hde_off = 0;
 		hdb_off = (base_off + 16 * plen) + prescale;
-	}
-	else {
+	} else {
 		hde_off = ((128 / var->bits_per_pixel + 2) * plen);
 		if (hw->ste_mode)
 			hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
@@ -1415,8 +1529,8 @@ static int falcon_encode_var( struct fb_
 
 	/* Right margin includes hsync */
 	var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
-					   (hw->hdb & 0x200 ? 2+hw->hht : 0));
-	if (hw->ste_mode || mon_type!=F_MON_VGA)
+					   (hw->hdb & 0x200 ? 2 + hw->hht : 0));
+	if (hw->ste_mode || mon_type != F_MON_VGA)
 		var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
 	else
 		/* can't use this in ste_mode, because hbb is +1 off */
@@ -1424,15 +1538,14 @@ static int falcon_encode_var( struct fb_
 	var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
 
 	/* Lower margin includes vsync */
-	var->upper_margin = hw->vdb / 2 ;  /* round down to full lines */
-	var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
-	var->vsync_len    = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
+	var->upper_margin = hw->vdb / 2;	/* round down to full lines */
+	var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2;	/* round up */
+	var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2;	/* round up */
 	if (var->vmode & FB_VMODE_INTERLACED) {
 		var->upper_margin *= 2;
 		var->lower_margin *= 2;
 		var->vsync_len *= 2;
-	}
-	else if (var->vmode & FB_VMODE_DOUBLE) {
+	} else if (var->vmode & FB_VMODE_DOUBLE) {
 		var->upper_margin = (var->upper_margin + 1) / 2;
 		var->lower_margin = (var->lower_margin + 1) / 2;
 		var->vsync_len = (var->vsync_len + 1) / 2;
@@ -1447,20 +1560,19 @@ static int falcon_encode_var( struct fb_
 	var->lower_margin -= var->vsync_len;
 
 	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
+		var->yoffset = (par->screen_base - screen_base) / linelen;
 	else
-		var->yoffset=0;
-	var->nonstd=0;	/* what is this for? */
-	var->activate=0;
+		var->yoffset = 0;
+	var->nonstd = 0;		/* what is this for? */
+	var->activate = 0;
 	return 0;
 }
 
-
-static int f_change_mode = 0;
+static int f_change_mode;
 static struct falcon_hw f_new_mode;
-static int f_pan_display = 0;
+static int f_pan_display;
 
-static void falcon_get_par( struct atafb_par *par )
+static void falcon_get_par(struct atafb_par *par)
 {
 	unsigned long addr;
 	struct falcon_hw *hw = &par->hw.falcon;
@@ -1492,12 +1604,12 @@ static void falcon_get_par( struct atafb
 	par->screen_base = phys_to_virt(addr);
 
 	/* derived parameters */
-	hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
+	hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100;
 	hw->mono = (hw->f_shift & 0x400) ||
-	           ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
+	           ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200);
 }
 
-static void falcon_set_par( struct atafb_par *par )
+static void falcon_set_par(struct atafb_par *par)
 {
 	f_change_mode = 0;
 
@@ -1519,8 +1631,7 @@ static void falcon_set_par( struct atafb
 	f_change_mode = 1;
 }
 
-
-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
+static irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
 {
 	struct falcon_hw *hw = &f_new_mode;
 
@@ -1529,11 +1640,10 @@ static irqreturn_t falcon_vbl_switcher( 
 
 		if (hw->sync & 0x1) {
 			/* Enable external pixelclock. This code only for ScreenWonder */
-			*(volatile unsigned short*)0xffff9202 = 0xffbf;
-		}
-		else {
+			*(volatile unsigned short *)0xffff9202 = 0xffbf;
+		} else {
 			/* Turn off external clocks. Read sets all output bits to 1. */
-			*(volatile unsigned short*)0xffff9202;
+			*(volatile unsigned short *)0xffff9202;
 		}
 		shifter.syncmode = hw->sync;
 
@@ -1550,15 +1660,14 @@ static irqreturn_t falcon_vbl_switcher( 
 		videl.vde = hw->vde;
 		videl.vss = hw->vss;
 
-		videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
+		videl.f_shift = 0;	/* write enables Falcon palette, 0: 4 planes */
 		if (hw->ste_mode) {
-			videl.st_shift = hw->st_shift; /* write enables STE palette */
-		}
-		else {
+			videl.st_shift = hw->st_shift;	/* write enables STE palette */
+		} else {
 			/* IMPORTANT:
-			 * set st_shift 0, so we can tell the screen-depth if f_shift==0.
+			 * set st_shift 0, so we can tell the screen-depth if f_shift == 0.
 			 * Writing 0 to f_shift enables 4 plane Falcon mode but
-			 * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
+			 * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible
 			 * with Falcon palette.
 			 */
 			videl.st_shift = 0;
@@ -1580,12 +1689,13 @@ static irqreturn_t falcon_vbl_switcher( 
 	return IRQ_HANDLED;
 }
 
-
-static int falcon_pan_display( struct fb_var_screeninfo *var,
-							   struct atafb_par *par )
+static int falcon_pan_display(struct fb_var_screeninfo *var,
+			      struct fb_info *info)
 {
+	struct atafb_par *par = (struct atafb_par *)info->par;
+
 	int xoffset;
-	int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
+	int bpp = info->var.bits_per_pixel;
 
 	if (bpp == 1)
 		var->xoffset = up(var->xoffset, 32);
@@ -1596,45 +1706,24 @@ static int falcon_pan_display( struct fb
 		var->xoffset = up(var->xoffset, 2);
 	}
 	par->hw.falcon.line_offset = bpp *
-	       	(fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
+		(info->var.xres_virtual - info->var.xres) / 16;
 	if (par->hw.falcon.xoffset)
 		par->hw.falcon.line_offset -= bpp;
 	xoffset = var->xoffset - par->hw.falcon.xoffset;
 
 	par->screen_base = screen_base +
-	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
+	        (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
 	if (fbhw->set_screen_base)
-		fbhw->set_screen_base (par->screen_base);
+		fbhw->set_screen_base(par->screen_base);
 	else
-		return -EINVAL; /* shouldn't happen */
+		return -EINVAL;		/* shouldn't happen */
 	f_pan_display = 1;
 	return 0;
 }
 
-
-static int falcon_getcolreg( unsigned regno, unsigned *red,
-				 unsigned *green, unsigned *blue,
-				 unsigned *transp, struct fb_info *info )
-{	unsigned long col;
-	
-	if (regno > 255)
-		return 1;
-	/* This works in STE-mode (with 4bit/color) since f030_col-registers
-	 * hold up to 6bit/color.
-	 * Even with hicolor r/g/b=5/6/5 bit!
-	 */
-	col = f030_col[regno];
-	*red = (col >> 16) & 0xff00;
-	*green = (col >> 8) & 0xff00;
-	*blue = (col << 8) & 0xff00;
-	*transp = 0;
-	return 0;
-}
-
-
-static int falcon_setcolreg( unsigned regno, unsigned red,
-							 unsigned green, unsigned blue,
-							 unsigned transp, struct fb_info *info )
+static int falcon_setcolreg(unsigned int regno, unsigned int red,
+			    unsigned int green, unsigned int blue,
+			    unsigned int transp, struct fb_info *info)
 {
 	if (regno > 255)
 		return 1;
@@ -1655,13 +1744,12 @@ #endif
 	return 0;
 }
 
-
-static int falcon_blank( int blank_mode )
+static int falcon_blank(int blank_mode)
 {
-/* ++guenther: we can switch off graphics by changing VDB and VDE,
- * so VIDEL doesn't hog the bus while saving.
- * (this may affect usleep()).
- */
+	/* ++guenther: we can switch off graphics by changing VDB and VDE,
+	 * so VIDEL doesn't hog the bus while saving.
+	 * (this may affect usleep()).
+	 */
 	int vdb, vss, hbe, hss;
 
 	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
@@ -1694,14 +1782,13 @@ static int falcon_blank( int blank_mode 
 	return 0;
 }
 
- 
-static int falcon_detect( void )
+static int falcon_detect(void)
 {
 	struct atafb_par par;
 	unsigned char fhw;
 
 	/* Determine connected monitor and set monitor parameters */
-	fhw = *(unsigned char*)0xffff8006;
+	fhw = *(unsigned char *)0xffff8006;
 	mon_type = fhw >> 6 & 0x3;
 	/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
 	f030_bus_width = fhw << 6 & 0x80;
@@ -1715,7 +1802,7 @@ static int falcon_detect( void )
 	case F_MON_SC:
 	case F_MON_TV:
 		/* PAL...NTSC */
-		fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
+		fb_info.monspecs.vfmin = 49;	/* not 50, since TOS defaults to 49.9x Hz */
 		fb_info.monspecs.vfmax = 60;
 		fb_info.monspecs.hfmin = 15620;
 		fb_info.monspecs.hfmax = 15755;
@@ -1740,13 +1827,12 @@ #endif /* ATAFB_FALCON */
 
 #ifdef ATAFB_STE
 
-static int stste_encode_fix( struct fb_fix_screeninfo *fix,
-							 struct atafb_par *par )
-
+static int stste_encode_fix(struct fb_fix_screeninfo *fix,
+			    struct atafb_par *par)
 {
 	int mode;
 
-	strcpy(fix->id,"Atari Builtin");
+	strcpy(fix->id, "Atari Builtin");
 	fix->smem_start = (unsigned long)real_screen_base;
 	fix->smem_len = screen_len;
 	fix->type = FB_TYPE_INTERLEAVED_PLANES;
@@ -1771,43 +1857,40 @@ static int stste_encode_fix( struct fb_f
 	return 0;
 }
 
-
-static int stste_decode_var( struct fb_var_screeninfo *var,
-						  struct atafb_par *par )
+static int stste_decode_var(struct fb_var_screeninfo *var,
+			    struct atafb_par *par)
 {
-	int xres=var->xres;
-	int yres=var->yres;
-	int bpp=var->bits_per_pixel;
+	int xres = var->xres;
+	int yres = var->yres;
+	int bpp = var->bits_per_pixel;
 	int linelen;
 	int yres_virtual = var->yres_virtual;
 
 	if (mono_moni) {
 		if (bpp > 1 || xres > sttt_xres || yres > st_yres)
 			return -EINVAL;
-		par->hw.st.mode=ST_HIGH;
-		xres=sttt_xres;
-		yres=st_yres;
-		bpp=1;
+		par->hw.st.mode = ST_HIGH;
+		xres = sttt_xres;
+		yres = st_yres;
+		bpp = 1;
 	} else {
 		if (bpp > 4 || xres > sttt_xres || yres > st_yres)
 			return -EINVAL;
 		if (bpp > 2) {
-			if (xres > sttt_xres/2 || yres > st_yres/2)
+			if (xres > sttt_xres / 2 || yres > st_yres / 2)
 				return -EINVAL;
-			par->hw.st.mode=ST_LOW;
-			xres=sttt_xres/2;
-			yres=st_yres/2;
-			bpp=4;
-		}
-		else if (bpp > 1) {
-			if (xres > sttt_xres || yres > st_yres/2)
+			par->hw.st.mode = ST_LOW;
+			xres = sttt_xres / 2;
+			yres = st_yres / 2;
+			bpp = 4;
+		} else if (bpp > 1) {
+			if (xres > sttt_xres || yres > st_yres / 2)
 				return -EINVAL;
-			par->hw.st.mode=ST_MID;
-			xres=sttt_xres;
-			yres=st_yres/2;
-			bpp=2;
-		}
-		else
+			par->hw.st.mode = ST_MID;
+			xres = sttt_xres;
+			yres = st_yres / 2;
+			bpp = 2;
+		} else
 			return -EINVAL;
 	}
 	if (yres_virtual <= 0)
@@ -1815,10 +1898,10 @@ static int stste_decode_var( struct fb_v
 	else if (yres_virtual < yres)
 		yres_virtual = yres;
 	if (var->sync & FB_SYNC_EXT)
-		par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
+		par->hw.st.sync = (par->hw.st.sync & ~1) | 1;
 	else
-		par->hw.st.sync=(par->hw.st.sync & ~1);
-	linelen=xres*bpp/8;
+		par->hw.st.sync = (par->hw.st.sync & ~1);
+	linelen = xres * bpp / 8;
 	if (yres_virtual * linelen > screen_len && screen_len)
 		return -EINVAL;
 	if (yres * linelen > screen_len && screen_len)
@@ -1826,93 +1909,91 @@ static int stste_decode_var( struct fb_v
 	if (var->yoffset + yres > yres_virtual && yres_virtual)
 		return -EINVAL;
 	par->yres_virtual = yres_virtual;
-	par->screen_base=screen_base+ var->yoffset*linelen;
+	par->screen_base = screen_base + var->yoffset * linelen;
 	return 0;
 }
 
-static int stste_encode_var( struct fb_var_screeninfo *var,
-						  struct atafb_par *par )
+static int stste_encode_var(struct fb_var_screeninfo *var,
+			    struct atafb_par *par)
 {
 	int linelen;
 	memset(var, 0, sizeof(struct fb_var_screeninfo));
-	var->red.offset=0;
+	var->red.offset = 0;
 	var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
-	var->red.msb_right=0;
-	var->grayscale=0;
+	var->red.msb_right = 0;
+	var->grayscale = 0;
 
-	var->pixclock=31041;
-	var->left_margin=120;		/* these are incorrect */
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
+	var->pixclock = 31041;
+	var->left_margin = 120;		/* these are incorrect */
+	var->right_margin = 100;
+	var->upper_margin = 8;
+	var->lower_margin = 16;
+	var->hsync_len = 140;
+	var->vsync_len = 30;
 
-	var->height=-1;
-	var->width=-1;
+	var->height = -1;
+	var->width = -1;
 
 	if (!(par->hw.st.sync & 1))
-		var->sync=0;
+		var->sync = 0;
 	else
-		var->sync=FB_SYNC_EXT;
+		var->sync = FB_SYNC_EXT;
 
 	switch (par->hw.st.mode & 3) {
 	case ST_LOW:
-		var->xres=sttt_xres/2;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=4;
+		var->xres = sttt_xres / 2;
+		var->yres = st_yres / 2;
+		var->bits_per_pixel = 4;
 		break;
 	case ST_MID:
-		var->xres=sttt_xres;
-		var->yres=st_yres/2;
-		var->bits_per_pixel=2;
+		var->xres = sttt_xres;
+		var->yres = st_yres / 2;
+		var->bits_per_pixel = 2;
 		break;
 	case ST_HIGH:
-		var->xres=sttt_xres;
-		var->yres=st_yres;
-		var->bits_per_pixel=1;
+		var->xres = sttt_xres;
+		var->yres = st_yres;
+		var->bits_per_pixel = 1;
 		break;
-	}		
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->xres_virtual=sttt_xres_virtual;
-	linelen=var->xres_virtual * var->bits_per_pixel / 8;
-	ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
-	
-	if (! use_hwscroll)
-		var->yres_virtual=var->yres;
+	}
+	var->blue = var->green = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->xres_virtual = sttt_xres_virtual;
+	linelen = var->xres_virtual * var->bits_per_pixel / 8;
+	ovsc_addlen = linelen * (sttt_yres_virtual - st_yres);
+
+	if (!use_hwscroll)
+		var->yres_virtual = var->yres;
 	else if (screen_len) {
 		if (par->yres_virtual)
 			var->yres_virtual = par->yres_virtual;
 		else
-			/* yres_virtual==0 means use maximum */
+			/* yres_virtual == 0 means use maximum */
 			var->yres_virtual = screen_len / linelen;
-	}
-	else {
+	} else {
 		if (hwscroll < 0)
 			var->yres_virtual = 2 * var->yres;
 		else
-			var->yres_virtual=var->yres+hwscroll * 16;
+			var->yres_virtual = var->yres + hwscroll * 16;
 	}
-	var->xoffset=0;
+	var->xoffset = 0;
 	if (screen_base)
-		var->yoffset=(par->screen_base - screen_base)/linelen;
+		var->yoffset = (par->screen_base - screen_base) / linelen;
 	else
-		var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
+		var->yoffset = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->vmode = FB_VMODE_NONINTERLACED;
 	return 0;
 }
 
-
-static void stste_get_par( struct atafb_par *par )
+static void stste_get_par(struct atafb_par *par)
 {
 	unsigned long addr;
-	par->hw.st.mode=shifter_tt.st_shiftmode;
-	par->hw.st.sync=shifter.syncmode;
+	par->hw.st.mode = shifter_tt.st_shiftmode;
+	par->hw.st.sync = shifter.syncmode;
 	addr = ((shifter.bas_hi & 0xff) << 16) |
 	       ((shifter.bas_md & 0xff) << 8);
 	if (ATARIHW_PRESENT(EXTD_SHIFTER))
@@ -1920,55 +2001,18 @@ static void stste_get_par( struct atafb_
 	par->screen_base = phys_to_virt(addr);
 }
 
-static void stste_set_par( struct atafb_par *par )
+static void stste_set_par(struct atafb_par *par)
 {
-	shifter_tt.st_shiftmode=par->hw.st.mode;
-	shifter.syncmode=par->hw.st.sync;
+	shifter_tt.st_shiftmode = par->hw.st.mode;
+	shifter.syncmode = par->hw.st.sync;
 	/* only set screen_base if really necessary */
 	if (current_par.screen_base != par->screen_base)
 		fbhw->set_screen_base(par->screen_base);
 }
 
-
-static int stste_getcolreg(unsigned regno, unsigned *red,
-			   unsigned *green, unsigned *blue,
-			   unsigned *transp, struct fb_info *info)
-{
-	unsigned col, t;
-	
-	if (regno > 15)
-		return 1;
-	col = shifter_tt.color_reg[regno];
-	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
-		t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
-		t |= t << 4;
-		*red = t | (t << 8);
-		t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
-		t |= t << 4;
-		*green = t | (t << 8);
-		t = ((col << 1) & 0xe) | ((col >> 3) & 1);
-		t |= t << 4;
-		*blue = t | (t << 8);
-	}
-	else {
-		t = (col >> 7) & 0xe;
-		t |= t << 4;
-		*red = t | (t << 8);
-		t = (col >> 3) & 0xe;
-		t |= t << 4;
-		*green = t | (t << 8);
-		t = (col << 1) & 0xe;
-		t |= t << 4;
-		*blue = t | (t << 8);
-	}
-	*transp = 0;
-	return 0;
-}
-
-
-static int stste_setcolreg(unsigned regno, unsigned red,
-			   unsigned green, unsigned blue,
-			   unsigned transp, struct fb_info *info)
+static int stste_setcolreg(unsigned int regno, unsigned int red,
+			   unsigned int green, unsigned int blue,
+			   unsigned int transp, struct fb_info *info)
 {
 	if (regno > 15)
 		return 1;
@@ -1988,10 +2032,9 @@ static int stste_setcolreg(unsigned regn
 	return 0;
 }
 
-						  
-static int stste_detect( void )
-
-{	struct atafb_par par;
+static int stste_detect(void)
+{
+	struct atafb_par par;
 
 	/* Determine the connected monitor: The DMA sound must be
 	 * disabled before reading the MFP GPIP, because the Sound
@@ -1999,7 +2042,7 @@ static int stste_detect( void )
 	 */
 	if (ATARIHW_PRESENT(PCM_8BIT)) {
 		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
-		udelay(20);	/* wait a while for things to settle down */
+		udelay(20);		/* wait a while for things to settle down */
 	}
 	mono_moni = (mfp.par_dt_reg & 0x80) == 0;
 
@@ -2014,12 +2057,12 @@ static int stste_detect( void )
 static void stste_set_screen_base(void *s_base)
 {
 	unsigned long addr;
-	addr= virt_to_phys(s_base);
+	addr = virt_to_phys(s_base);
 	/* Setup Screen Memory */
-	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
-  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
+	shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+	shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
 	if (ATARIHW_PRESENT(EXTD_SHIFTER))
-		shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
+		shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
 }
 
 #endif /* ATAFB_STE */
@@ -2045,51 +2088,49 @@ #define SYNC_DELAY  (mono_moni ? 1500 : 
 /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
 static void st_ovsc_switch(void)
 {
-    unsigned long flags;
-    register unsigned char old, new;
+	unsigned long flags;
+	register unsigned char old, new;
 
-    if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
-	return;
-    local_irq_save(flags);
-
-    mfp.tim_ct_b = 0x10;
-    mfp.active_edge |= 8;
-    mfp.tim_ct_b = 0;
-    mfp.tim_dt_b = 0xf0;
-    mfp.tim_ct_b = 8;
-    while (mfp.tim_dt_b > 1)	/* TOS does it this way, don't ask why */
-	;
-    new = mfp.tim_dt_b;
-    do {
-	udelay(LINE_DELAY);
-	old = new;
+	if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
+		return;
+	local_irq_save(flags);
+
+	mfp.tim_ct_b = 0x10;
+	mfp.active_edge |= 8;
+	mfp.tim_ct_b = 0;
+	mfp.tim_dt_b = 0xf0;
+	mfp.tim_ct_b = 8;
+	while (mfp.tim_dt_b > 1)	/* TOS does it this way, don't ask why */
+		;
 	new = mfp.tim_dt_b;
-    } while (old != new);
-    mfp.tim_ct_b = 0x10;
-    udelay(SYNC_DELAY);
-
-    if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
-	acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
-    if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
-	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
-    if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
-	sound_ym.rd_data_reg_sel = 14;
-	sound_ym.wd_data = sound_ym.rd_data_reg_sel |
-			   ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
-			   ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
-    }
-    local_irq_restore(flags);
+	do {
+		udelay(LINE_DELAY);
+		old = new;
+		new = mfp.tim_dt_b;
+	} while (old != new);
+	mfp.tim_ct_b = 0x10;
+	udelay(SYNC_DELAY);
+
+	if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+		acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
+	if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+	if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
+		sound_ym.rd_data_reg_sel = 14;
+		sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+				   ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
+				   ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
+	}
+	local_irq_restore(flags);
 }
 
 /* ------------------- External Video ---------------------- */
 
 #ifdef ATAFB_EXT
 
-static int ext_encode_fix( struct fb_fix_screeninfo *fix,
-						   struct atafb_par *par )
-
+static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
 {
-	strcpy(fix->id,"Unknown Extern");
+	strcpy(fix->id, "Unknown Extern");
 	fix->smem_start = (unsigned long)external_addr;
 	fix->smem_len = PAGE_ALIGN(external_len);
 	if (external_depth == 1) {
@@ -2099,31 +2140,29 @@ static int ext_encode_fix( struct fb_fix
 		fix->visual =
 			(external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
 			 external_pmode == FB_TYPE_PACKED_PIXELS) ?
-				FB_VISUAL_MONO10 :
-					FB_VISUAL_MONO01;
-	}
-	else {
+				FB_VISUAL_MONO10 : FB_VISUAL_MONO01;
+	} else {
 		/* Use STATIC if we don't know how to access color registers */
 		int visual = external_vgaiobase ?
 					 FB_VISUAL_PSEUDOCOLOR :
 					 FB_VISUAL_STATIC_PSEUDOCOLOR;
 		switch (external_pmode) {
-		    case -1:              /* truecolor */
-			fix->type=FB_TYPE_PACKED_PIXELS;
-			fix->visual=FB_VISUAL_TRUECOLOR;
+		case -1:		/* truecolor */
+			fix->type = FB_TYPE_PACKED_PIXELS;
+			fix->visual = FB_VISUAL_TRUECOLOR;
 			break;
-		    case FB_TYPE_PACKED_PIXELS:
-			fix->type=FB_TYPE_PACKED_PIXELS;
-			fix->visual=visual;
+		case FB_TYPE_PACKED_PIXELS:
+			fix->type = FB_TYPE_PACKED_PIXELS;
+			fix->visual = visual;
 			break;
-		    case FB_TYPE_PLANES:
-			fix->type=FB_TYPE_PLANES;
-			fix->visual=visual;
+		case FB_TYPE_PLANES:
+			fix->type = FB_TYPE_PLANES;
+			fix->visual = visual;
 			break;
-		    case FB_TYPE_INTERLEAVED_PLANES:
-			fix->type=FB_TYPE_INTERLEAVED_PLANES;
-			fix->type_aux=2;
-			fix->visual=visual;
+		case FB_TYPE_INTERLEAVED_PLANES:
+			fix->type = FB_TYPE_INTERLEAVED_PLANES;
+			fix->type_aux = 2;
+			fix->visual = visual;
 			break;
 		}
 	}
@@ -2134,137 +2173,112 @@ static int ext_encode_fix( struct fb_fix
 	return 0;
 }
 
-
-static int ext_decode_var( struct fb_var_screeninfo *var,
-						   struct atafb_par *par )
+static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
 {
 	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
-	
+
 	if (var->bits_per_pixel > myvar->bits_per_pixel ||
-		var->xres > myvar->xres ||
-		var->xres_virtual > myvar->xres_virtual ||
-		var->yres > myvar->yres ||
-		var->xoffset > 0 ||
-		var->yoffset > 0)
+	    var->xres > myvar->xres ||
+	    var->xres_virtual > myvar->xres_virtual ||
+	    var->yres > myvar->yres ||
+	    var->xoffset > 0 ||
+	    var->yoffset > 0)
 		return -EINVAL;
 	return 0;
 }
 
-
-static int ext_encode_var( struct fb_var_screeninfo *var,
-						   struct atafb_par *par )
+static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
 {
 	memset(var, 0, sizeof(struct fb_var_screeninfo));
-	var->red.offset=0;
-	var->red.length=(external_pmode == -1) ? external_depth/3 : 
+	var->red.offset = 0;
+	var->red.length = (external_pmode == -1) ? external_depth / 3 :
 			(external_vgaiobase ? external_bitspercol : 0);
-	var->red.msb_right=0;
-	var->grayscale=0;
+	var->red.msb_right = 0;
+	var->grayscale = 0;
 
-	var->pixclock=31041;
-	var->left_margin=120;		/* these are surely incorrect 	*/
-	var->right_margin=100;
-	var->upper_margin=8;
-	var->lower_margin=16;
-	var->hsync_len=140;
-	var->vsync_len=30;
+	var->pixclock = 31041;
+	var->left_margin = 120;		/* these are surely incorrect */
+	var->right_margin = 100;
+	var->upper_margin = 8;
+	var->lower_margin = 16;
+	var->hsync_len = 140;
+	var->vsync_len = 30;
 
-	var->height=-1;
-	var->width=-1;
+	var->height = -1;
+	var->width = -1;
 
-	var->sync=0;
+	var->sync = 0;
 
 	var->xres = external_xres;
 	var->yres = external_yres;
 	var->xres_virtual = external_xres_virtual;
 	var->bits_per_pixel = external_depth;
-	
-	var->blue=var->green=var->red;
-	var->transp.offset=0;
-	var->transp.length=0;
-	var->transp.msb_right=0;
-	var->yres_virtual=var->yres;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
+
+	var->blue = var->green = var->red;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+	var->transp.msb_right = 0;
+	var->yres_virtual = var->yres;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->nonstd = 0;
+	var->activate = 0;
+	var->vmode = FB_VMODE_NONINTERLACED;
 	return 0;
 }
 
-
-static void ext_get_par( struct atafb_par *par )
+static void ext_get_par(struct atafb_par *par)
 {
 	par->screen_base = external_addr;
 }
 
-static void ext_set_par( struct atafb_par *par )
+static void ext_set_par(struct atafb_par *par)
 {
 }
 
 #define OUTB(port,val) \
-	*((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
+	*((unsigned volatile char *) ((port)+external_vgaiobase)) = (val)
 #define INB(port) \
 	(*((unsigned volatile char *) ((port)+external_vgaiobase)))
-#define DACDelay 				\
+#define DACDelay				\
 	do {					\
-		unsigned char tmp=INB(0x3da);	\
-		tmp=INB(0x3da);			\
+		unsigned char tmp = INB(0x3da);	\
+		tmp = INB(0x3da);			\
 	} while (0)
 
-static int ext_getcolreg( unsigned regno, unsigned *red,
-						  unsigned *green, unsigned *blue,
-						  unsigned *transp, struct fb_info *info )
+static int ext_setcolreg(unsigned int regno, unsigned int red,
+			 unsigned int green, unsigned int blue,
+			 unsigned int transp, struct fb_info *info)
 {
-	if (! external_vgaiobase)
+	unsigned char colmask = (1 << external_bitspercol) - 1;
+
+	if (!external_vgaiobase)
 		return 1;
 
-	    *red   = ext_color[regno].red;
-	    *green = ext_color[regno].green;
-	    *blue  = ext_color[regno].blue;
-	    *transp=0;
-	    return 0;
-}
-	
-static int ext_setcolreg( unsigned regno, unsigned red,
-						  unsigned green, unsigned blue,
-						  unsigned transp, struct fb_info *info )
+	switch (external_card_type) {
+	case IS_VGA:
+		OUTB(0x3c8, regno);
+		DACDelay;
+		OUTB(0x3c9, red & colmask);
+		DACDelay;
+		OUTB(0x3c9, green & colmask);
+		DACDelay;
+		OUTB(0x3c9, blue & colmask);
+		DACDelay;
+		return 0;
 
-{	unsigned char colmask = (1 << external_bitspercol) - 1;
+	case IS_MV300:
+		OUTB((MV300_reg[regno] << 2) + 1, red);
+		OUTB((MV300_reg[regno] << 2) + 1, green);
+		OUTB((MV300_reg[regno] << 2) + 1, blue);
+		return 0;
 
-	if (! external_vgaiobase)
+	default:
 		return 1;
-
-	ext_color[regno].red = red;
-	ext_color[regno].green = green;
-	ext_color[regno].blue = blue;
-
-	switch (external_card_type) {
-	  case IS_VGA:
-	    OUTB(0x3c8, regno);
-	    DACDelay;
-	    OUTB(0x3c9, red & colmask);
-	    DACDelay;
-	    OUTB(0x3c9, green & colmask);
-	    DACDelay;
-	    OUTB(0x3c9, blue & colmask);
-	    DACDelay;
-	    return 0;
-
-	  case IS_MV300:
-	    OUTB((MV300_reg[regno] << 2)+1, red);
-	    OUTB((MV300_reg[regno] << 2)+1, green);
-	    OUTB((MV300_reg[regno] << 2)+1, blue);
-	    return 0;
-
-	  default:
-	    return 1;
-	  }
+	}
 }
-	
-
-static int ext_detect( void )
 
+static int ext_detect(void)
 {
 	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
 	struct atafb_par dummy_par;
@@ -2284,213 +2298,182 @@ #endif /* ATAFB_EXT */
 static void set_screen_base(void *s_base)
 {
 	unsigned long addr;
-	addr= virt_to_phys(s_base);
+
+	addr = virt_to_phys(s_base);
 	/* Setup Screen Memory */
-	shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
-  	shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
-  	shifter.bas_lo=(unsigned char)  (addr & 0x0000ff);
+	shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+	shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
+	shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
 }
 
-
-static int pan_display( struct fb_var_screeninfo *var,
-                        struct atafb_par *par )
+static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	struct atafb_par *par = (struct atafb_par *)info->par;
+
 	if (!fbhw->set_screen_base ||
-		(!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
+	    (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
 		return -EINVAL;
 	var->xoffset = up(var->xoffset, 16);
 	par->screen_base = screen_base +
-	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
-	        * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
-	fbhw->set_screen_base (par->screen_base);
+	        (var->yoffset * info->var.xres_virtual + var->xoffset)
+	        * info->var.bits_per_pixel / 8;
+	fbhw->set_screen_base(par->screen_base);
 	return 0;
 }
 
-
 /* ------------ Interfaces to hardware functions ------------ */
 
-
 #ifdef ATAFB_TT
 static struct fb_hwswitch tt_switch = {
-	tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
-	tt_get_par, tt_set_par, tt_getcolreg, 
-	set_screen_base, NULL, pan_display
+	.detect		= tt_detect,
+	.encode_fix	= tt_encode_fix,
+	.decode_var	= tt_decode_var,
+	.encode_var	= tt_encode_var,
+	.get_par	= tt_get_par,
+	.set_par	= tt_set_par,
+	.set_screen_base = set_screen_base,
+	.pan_display	= pan_display,
 };
 #endif
 
 #ifdef ATAFB_FALCON
 static struct fb_hwswitch falcon_switch = {
-	falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
-	falcon_get_par, falcon_set_par, falcon_getcolreg,
-	set_screen_base, falcon_blank, falcon_pan_display
+	.detect		= falcon_detect,
+	.encode_fix	= falcon_encode_fix,
+	.decode_var	= falcon_decode_var,
+	.encode_var	= falcon_encode_var,
+	.get_par	= falcon_get_par,
+	.set_par	= falcon_set_par,
+	.set_screen_base = set_screen_base,
+	.blank		= falcon_blank,
+	.pan_display	= falcon_pan_display,
 };
 #endif
 
 #ifdef ATAFB_STE
 static struct fb_hwswitch st_switch = {
-	stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
-	stste_get_par, stste_set_par, stste_getcolreg,
-	stste_set_screen_base, NULL, pan_display
+	.detect		= stste_detect,
+	.encode_fix	= stste_encode_fix,
+	.decode_var	= stste_decode_var,
+	.encode_var	= stste_encode_var,
+	.get_par	= stste_get_par,
+	.set_par	= stste_set_par,
+	.set_screen_base = stste_set_screen_base,
+	.pan_display	= pan_display
 };
 #endif
 
 #ifdef ATAFB_EXT
 static struct fb_hwswitch ext_switch = {
-	ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
-	ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL
+	.detect		= ext_detect,
+	.encode_fix	= ext_encode_fix,
+	.decode_var	= ext_decode_var,
+	.encode_var	= ext_encode_var,
+	.get_par	= ext_get_par,
+	.set_par	= ext_set_par,
 };
 #endif
 
-
-
-static void atafb_get_par( struct atafb_par *par )
+static void ata_get_par(struct atafb_par *par)
 {
-	if (current_par_valid) {
-		*par=current_par;
-	}
+	if (current_par_valid)
+		*par = current_par;
 	else
 		fbhw->get_par(par);
 }
 
-
-static void atafb_set_par( struct atafb_par *par )
+static void ata_set_par(struct atafb_par *par)
 {
 	fbhw->set_par(par);
-	current_par=*par;
-	current_par_valid=1;
+	current_par = *par;
+	current_par_valid = 1;
 }
 
 
-
 /* =========================================================== */
 /* ============== Hardware Independent Functions ============= */
 /* =========================================================== */
 
-
 /* used for hardware scrolling */
 
-static int
-fb_update_var(int con, struct fb_info *info)
-{
-	int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
-			fb_display[con].var.bits_per_pixel>>3;
-
-	current_par.screen_base=screen_base + off;
-
-	if (fbhw->set_screen_base)
-		fbhw->set_screen_base(current_par.screen_base);
-	return 0;
-}
-
-static int
-do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
 {
-	int err,activate;
+	int err, activate;
 	struct atafb_par par;
-	if ((err=fbhw->decode_var(var, &par)))
+
+	err = fbhw->decode_var(var, &par);
+	if (err)
 		return err;
-	activate=var->activate;
+	activate = var->activate;
 	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
-		atafb_set_par(&par);
+		ata_set_par(&par);
 	fbhw->encode_var(var, &par);
-	var->activate=activate;
+	var->activate = activate;
 	return 0;
 }
 
-static int
-atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
 {
 	struct atafb_par par;
-	if (con == -1)
-		atafb_get_par(&par);
-	else {
-	  int err;
-		if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
-		  return err;
-	}
+	int err;
+	// Get fix directly (case con == -1 before)??
+	err = fbhw->decode_var(&info->var, &par);
+	if (err)
+		return err;
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	return fbhw->encode_fix(fix, &par);
 }
-	
-static int
-atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+
+static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	struct atafb_par par;
-	if (con == -1) {
-		atafb_get_par(&par);
-		fbhw->encode_var(var, &par);
-	}
-	else
-		*var=fb_display[con].var;
+
+	ata_get_par(&par);
+	fbhw->encode_var(var, &par);
+
 	return 0;
 }
 
-static void
-atafb_set_disp(int con, struct fb_info *info)
+// No longer called by fbcon!
+// Still called by set_var internally
+
+static void atafb_set_disp(struct fb_info *info)
 {
-	struct fb_fix_screeninfo fix;
-	struct fb_var_screeninfo var;
-	struct display *display;
+	atafb_get_var(&info->var, info);
+	atafb_get_fix(&info->fix, info);
 
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	atafb_get_fix(&fix, con, info);
-	atafb_get_var(&var, con, info);
-	if (con == -1)
-		con=0;
-	info->screen_base = (void *)fix.smem_start;
-	display->visual = fix.visual;
-	display->type = fix.type;
-	display->type_aux = fix.type_aux;
-	display->ypanstep = fix.ypanstep;
-	display->ywrapstep = fix.ywrapstep;
-	display->line_length = fix.line_length;
-	if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
-		fix.visual != FB_VISUAL_DIRECTCOLOR)
-		display->can_soft_blank = 0;
-	else
-		display->can_soft_blank = 1;
-	display->inverse =
-	    (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
-	switch (fix.type) {
-	    case FB_TYPE_INTERLEAVED_PLANES:
-		switch (var.bits_per_pixel) {
-#ifdef FBCON_HAS_IPLAN2P2
-		    case 2:
-			display->dispsw = &fbcon_iplan2p2;
+	info->screen_base = (void *)info->fix.smem_start;
+
+	switch (info->fix.type) {
+	case FB_TYPE_INTERLEAVED_PLANES:
+		switch (info->var.bits_per_pixel) {
+		case 2:
+			// display->dispsw = &fbcon_iplan2p2;
 			break;
-#endif
-#ifdef FBCON_HAS_IPLAN2P4
-		    case 4:
-			display->dispsw = &fbcon_iplan2p4;
+		case 4:
+			// display->dispsw = &fbcon_iplan2p4;
 			break;
-#endif
-#ifdef FBCON_HAS_IPLAN2P8
-		    case 8:
-			display->dispsw = &fbcon_iplan2p8;
+		case 8:
+			// display->dispsw = &fbcon_iplan2p8;
 			break;
-#endif
 		}
 		break;
-	    case FB_TYPE_PACKED_PIXELS:
-		switch (var.bits_per_pixel) {
+	case FB_TYPE_PACKED_PIXELS:
+		switch (info->var.bits_per_pixel) {
 #ifdef FBCON_HAS_MFB
-		    case 1:
-			display->dispsw = &fbcon_mfb;
+		case 1:
+			// display->dispsw = &fbcon_mfb;
 			break;
 #endif
 #ifdef FBCON_HAS_CFB8
-		    case 8:
-			display->dispsw = &fbcon_cfb8;
+		case 8:
+			// display->dispsw = &fbcon_cfb8;
 			break;
 #endif
 #ifdef FBCON_HAS_CFB16
-		    case 16:
-			display->dispsw = &fbcon_cfb16;
-			display->dispsw_data = fbcon_cfb16_cmap;
+		case 16:
+			// display->dispsw = &fbcon_cfb16;
+			// display->dispsw_data = fbcon_cfb16_cmap;
 			break;
 #endif
 		}
@@ -2498,74 +2481,203 @@ #endif
 	}
 }
 
+static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *info)
+{
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
+}
+
 static int
-atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	int err,oldxres,oldyres,oldbpp,oldxres_virtual,
-	    oldyres_virtual,oldyoffset;
-	if ((err=do_fb_set_var(var, con==info->currcon)))
-		return err;
-	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres=fb_display[con].var.xres;
-		oldyres=fb_display[con].var.yres;
-		oldxres_virtual=fb_display[con].var.xres_virtual;
-		oldyres_virtual=fb_display[con].var.yres_virtual;
-		oldbpp=fb_display[con].var.bits_per_pixel;
-		oldyoffset=fb_display[con].var.yoffset;
-		fb_display[con].var=*var;
-		if (oldxres != var->xres || oldyres != var->yres 
-		    || oldxres_virtual != var->xres_virtual
-		    || oldyres_virtual != var->yres_virtual
-		    || oldbpp != var->bits_per_pixel
-		    || oldyoffset != var->yoffset) {
-			atafb_set_disp(con, info);
-			(*fb_info.changevar)(con);
-			fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
-			do_install_cmap(con, info);
-		}
+	int xoffset = var->xoffset;
+	int yoffset = var->yoffset;
+	int err;
+
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset)
+			return -EINVAL;
+	} else {
+		if (xoffset + info->var.xres > info->var.xres_virtual ||
+		    yoffset + info->var.yres > info->var.yres_virtual)
+			return -EINVAL;
 	}
-	var->activate=0;
+
+	if (fbhw->pan_display) {
+		err = fbhw->pan_display(var, info);
+		if (err)
+			return err;
+	} else
+		return -EINVAL;
+
+	info->var.xoffset = xoffset;
+	info->var.yoffset = yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+
 	return 0;
 }
 
+/*
+ * generic drawing routines; imageblit needs updating for image depth > 1
+ */
 
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG	4
+#define SHIFT_PER_LONG	5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG	8
+#define SHIFT_PER_LONG	6
+#else
+#define Please update me
+#endif
 
-static int
-atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+
+static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-	if (con == info->currcon) /* current console ? */
-		return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
+	struct atafb_par *par = (struct atafb_par *)info->par;
+	int x2, y2;
+	u32 width, height;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 * */
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width = x2 - rect->dx;
+	height = y2 - rect->dy;
+
+	if (info->var.bits_per_pixel == 1)
+		atafb_mfb_fillrect(info, par->next_line, rect->color,
+				   rect->dy, rect->dx, height, width);
+	else if (info->var.bits_per_pixel == 2)
+		atafb_iplan2p2_fillrect(info, par->next_line, rect->color,
+					rect->dy, rect->dx, height, width);
+	else if (info->var.bits_per_pixel == 4)
+		atafb_iplan2p4_fillrect(info, par->next_line, rect->color,
+					rect->dy, rect->dx, height, width);
 	else
-		if (fb_display[con].cmap.len) /* non default colormap ? */
-			fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-		else
-			fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-				     cmap, kspc ? 0 : 2);
-	return 0;
+		atafb_iplan2p8_fillrect(info, par->next_line, rect->color,
+					rect->dy, rect->dx, height, width);
+
+	return;
 }
 
-static int
-atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
-	int xoffset = var->xoffset;
-	int yoffset = var->yoffset;
-	int err;
+	struct atafb_par *par = (struct atafb_par *)info->par;
+	int x2, y2;
+	u32 dx, dy, sx, sy, width, height;
+	int rev_copy = 0;
+
+	/* clip the destination */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	dx = area->dx > 0 ? area->dx : 0;
+	dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width = x2 - dx;
+	height = y2 - dy;
+
+	/* update sx,sy */
+	sx = area->sx + (dx - area->dx);
+	sy = area->sy + (dy - area->dy);
+
+	/* the source must be completely inside the virtual screen */
+	if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
+	    (sy + height) > info->var.yres_virtual)
+		return;
 
-	if (   xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
-	    || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
-		return -EINVAL;
+	if (dy > sy || (dy == sy && dx > sx)) {
+		dy += height;
+		sy += height;
+		rev_copy = 1;
+	}
+
+	if (info->var.bits_per_pixel == 1)
+		atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+	else if (info->var.bits_per_pixel == 2)
+		atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+	else if (info->var.bits_per_pixel == 4)
+		atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+	else
+		atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
 
-	if (con == info->currcon) {
-		if (fbhw->pan_display) {
-			if ((err = fbhw->pan_display(var, &current_par)))
-				return err;
+	return;
+}
+
+static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct atafb_par *par = (struct atafb_par *)info->par;
+	int x2, y2;
+	unsigned long *dst;
+	int dst_idx;
+	const char *src;
+	u32 dx, dy, width, height, pitch;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly like we are
+	 * doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	dx = image->dx;
+	dy = image->dy;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width = x2 - dx;
+	height = y2 - dy;
+
+	if (image->depth == 1) {
+		// used for font data
+		dst = (unsigned long *)
+			((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
+		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
+		dst_idx += dy * par->next_line * 8 + dx;
+		src = image->data;
+		pitch = (image->width + 7) / 8;
+		while (height--) {
+
+			if (info->var.bits_per_pixel == 1)
+				atafb_mfb_linefill(info, par->next_line,
+						   dy, dx, width, src,
+						   image->bg_color, image->fg_color);
+			else if (info->var.bits_per_pixel == 2)
+				atafb_iplan2p2_linefill(info, par->next_line,
+							dy, dx, width, src,
+							image->bg_color, image->fg_color);
+			else if (info->var.bits_per_pixel == 4)
+				atafb_iplan2p4_linefill(info, par->next_line,
+							dy, dx, width, src,
+							image->bg_color, image->fg_color);
+			else
+				atafb_iplan2p8_linefill(info, par->next_line,
+							dy, dx, width, src,
+							image->bg_color, image->fg_color);
+			dy++;
+			src += pitch;
 		}
-		else
-			return -EINVAL;
+	} else {
+		// only used for logo; broken
+		c2p(info->screen_base, image->data, dx, dy, width, height,
+		    par->next_line, par->next_plane, image->width,
+		    info->var.bits_per_pixel);
 	}
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
-	return 0;
 }
 
 static int
@@ -2584,7 +2696,7 @@ #ifdef FBCMD_SET_CURRENTPAR
 		if (copy_from_user((void *)&current_par, (void *)arg,
 				   sizeof(struct atafb_par)))
 			return -EFAULT;
-		atafb_set_par(&current_par);
+		ata_set_par(&current_par);
 		return 0;
 #endif
 	}
@@ -2598,42 +2710,82 @@ #endif
  * 3 = suspend hsync
  * 4 = off
  */
-static int 
-atafb_blank(int blank, struct fb_info *info)
+static int atafb_blank(int blank, struct fb_info *info)
 {
 	unsigned short black[16];
 	struct fb_cmap cmap;
 	if (fbhw->blank && !fbhw->blank(blank))
 		return 1;
 	if (blank) {
-		memset(black, 0, 16*sizeof(unsigned short));
-		cmap.red=black;
-		cmap.green=black;
-		cmap.blue=black;
-		cmap.transp=NULL;
-		cmap.start=0;
-		cmap.len=16;
-		fb_set_cmap(&cmap, 1, info);
+		memset(black, 0, 16 * sizeof(unsigned short));
+		cmap.red = black;
+		cmap.green = black;
+		cmap.blue = black;
+		cmap.transp = NULL;
+		cmap.start = 0;
+		cmap.len = 16;
+		fb_set_cmap(&cmap, info);
 	}
+#if 0
 	else
-		do_install_cmap(info->currcon, info);
+		do_install_cmap(info);
+#endif
+	return 0;
+}
+
+	/*
+	 * New fbcon interface ...
+	 */
+
+	 /* check var by decoding var into hw par, rounding if necessary,
+	  * then encoding hw par back into new, validated var */
+static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int err;
+	struct atafb_par par;
+
+	/* Validate wanted screen parameters */
+	// if ((err = ata_decode_var(var, &par)))
+	err = fbhw->decode_var(var, &par);
+	if (err)
+		return err;
+
+	/* Encode (possibly rounded) screen parameters */
+	fbhw->encode_var(var, &par);
+	return 0;
+}
+
+	/* actually set hw par by decoding var, then setting hardware from
+	 * hw par just decoded */
+static int atafb_set_par(struct fb_info *info)
+{
+	struct atafb_par *par = (struct atafb_par *)info->par;
+
+	/* Decode wanted screen parameters */
+	fbhw->decode_var(&info->var, par);
+	fbhw->encode_fix(&info->fix, par);
+
+	/* Set new videomode */
+	ata_set_par(par);
+
 	return 0;
 }
 
+
 static struct fb_ops atafb_ops = {
 	.owner =	THIS_MODULE,
-	.fb_get_fix =	atafb_get_fix,
-	.fb_get_var =	atafb_get_var,
-	.fb_set_var =	atafb_set_var,
-	.fb_get_cmap =	atafb_get_cmap,
-	.fb_set_cmap =	gen_set_cmap,
-	.fb_pan_display =atafb_pan_display,
+	.fb_check_var	= atafb_check_var,
+	.fb_set_par	= atafb_set_par,
+	.fb_setcolreg	= atafb_setcolreg,
 	.fb_blank =	atafb_blank,
+	.fb_pan_display	= atafb_pan_display,
+	.fb_fillrect	= atafb_fillrect,
+	.fb_copyarea	= atafb_copyarea,
+	.fb_imageblit	= atafb_imageblit,
 	.fb_ioctl =	atafb_ioctl,
 };
 
-static void
-check_default_par( int detected_mode )
+static void check_default_par(int detected_mode)
 {
 	char default_name[10];
 	int i;
@@ -2642,199 +2794,41 @@ check_default_par( int detected_mode )
 
 	/* First try the user supplied mode */
 	if (default_par) {
-		var=atafb_predefined[default_par-1];
+		var = atafb_predefined[default_par - 1];
 		var.activate = FB_ACTIVATE_TEST;
-		if (do_fb_set_var(&var,1))
-			default_par=0;		/* failed */
+		if (do_fb_set_var(&var, 1))
+			default_par = 0;	/* failed */
 	}
 	/* Next is the autodetected one */
-	if (! default_par) {
-		var=atafb_predefined[detected_mode-1]; /* autodetect */
+	if (!default_par) {
+		var = atafb_predefined[detected_mode - 1]; /* autodetect */
 		var.activate = FB_ACTIVATE_TEST;
-		if (!do_fb_set_var(&var,1))
-			default_par=detected_mode;
+		if (!do_fb_set_var(&var, 1))
+			default_par = detected_mode;
 	}
 	/* If that also failed, try some default modes... */
-	if (! default_par) {
+	if (!default_par) {
 		/* try default1, default2... */
-		for (i=1 ; i < 10 ; i++) {
-			sprintf(default_name,"default%d",i);
-			default_par=get_video_mode(default_name);
-			if (! default_par)
+		for (i = 1; i < 10; i++) {
+			sprintf(default_name,"default%d", i);
+			default_par = get_video_mode(default_name);
+			if (!default_par)
 				panic("can't set default video mode");
-			var=atafb_predefined[default_par-1];
+			var = atafb_predefined[default_par - 1];
 			var.activate = FB_ACTIVATE_TEST;
-			if (! do_fb_set_var(&var,1))
+			if (!do_fb_set_var(&var,1))
 				break;	/* ok */
 		}
 	}
-	min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
+	min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8;
 	if (default_mem_req < min_mem)
-		default_mem_req=min_mem;
-}
-
-static int
-atafb_switch(int con, struct fb_info *info)
-{
-	/* Do we have to save the colormap ? */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
-			    info);
-	do_fb_set_var(&fb_display[con].var,1);
-	info->currcon=con;
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	return 0;
-}
-
-int __init atafb_init(void)
-{
-	int pad;
-	int detected_mode;
-	unsigned long mem_req;
-
-	if (!MACH_IS_ATARI)
-	        return -ENXIO;
-
-	do {
-#ifdef ATAFB_EXT
-		if (external_addr) {
-			fbhw = &ext_switch;
-			atafb_ops.fb_setcolreg = &ext_setcolreg;
-			break;
-		}
-#endif
-#ifdef ATAFB_TT
-		if (ATARIHW_PRESENT(TT_SHIFTER)) {
-			fbhw = &tt_switch;
-			atafb_ops.fb_setcolreg = &tt_setcolreg;
-			break;
-		}
-#endif
-#ifdef ATAFB_FALCON
-		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
-			fbhw = &falcon_switch;
-			atafb_ops.fb_setcolreg = &falcon_setcolreg;
-			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
-			            "framebuffer/modeswitch", falcon_vbl_switcher);
-			break;
-		}
-#endif
-#ifdef ATAFB_STE
-		if (ATARIHW_PRESENT(STND_SHIFTER) ||
-		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
-			fbhw = &st_switch;
-			atafb_ops.fb_setcolreg = &stste_setcolreg;
-			break;
-		}
-		fbhw = &st_switch;
-		atafb_ops.fb_setcolreg = &stste_setcolreg;
-		printk("Cannot determine video hardware; defaulting to ST(e)\n");
-#else /* ATAFB_STE */
-		/* no default driver included */
-		/* Nobody will ever see this message :-) */
-		panic("Cannot initialize video hardware");
-#endif
-	} while (0);
-
-	/* Multisync monitor capabilities */
-	/* Atari-TOS defaults if no boot option present */
-	if (fb_info.monspecs.hfmin == 0) {
-	    fb_info.monspecs.hfmin = 31000;
-	    fb_info.monspecs.hfmax = 32000;
-	    fb_info.monspecs.vfmin = 58;
-	    fb_info.monspecs.vfmax = 62;
-	}
-
-	detected_mode = fbhw->detect();
-	check_default_par(detected_mode);
-#ifdef ATAFB_EXT
-	if (!external_addr) {
-#endif /* ATAFB_EXT */
-		mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
-		mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
-		screen_base = atari_stram_alloc(mem_req, "atafb");
-		if (!screen_base)
-			panic("Cannot allocate screen memory");
-		memset(screen_base, 0, mem_req);
-		pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
-		screen_base+=pad;
-		real_screen_base=screen_base+ovsc_offset;
-		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
-		st_ovsc_switch();
-		if (CPU_IS_040_OR_060) {
-			/* On a '040+, the cache mode of video RAM must be set to
-			 * write-through also for internal video hardware! */
-			cache_push(virt_to_phys(screen_base), screen_len);
-			kernel_set_cachemode(screen_base, screen_len,
-					     IOMAP_WRITETHROUGH);
-		}
-#ifdef ATAFB_EXT
-	}
-	else {
-		/* Map the video memory (physical address given) to somewhere
-		 * in the kernel address space.
-		 */
-		external_addr =
-		  ioremap_writethrough((unsigned long)external_addr,
-				       external_len);
-		if (external_vgaiobase)
-			external_vgaiobase =
-			  (unsigned long)ioremap(external_vgaiobase, 0x10000);
-		screen_base      =
-		real_screen_base = external_addr;
-		screen_len       = external_len & PAGE_MASK;
-		memset (screen_base, 0, external_len);
-	}
-#endif /* ATAFB_EXT */
-
-	strcpy(fb_info.modename, "Atari Builtin ");
-	fb_info.changevar = NULL;
-	fb_info.fbops = &atafb_ops;
-	fb_info.disp = &disp;
-	fb_info.currcon = -1;
-	fb_info.switch_con = &atafb_switch;
-	fb_info.updatevar = &fb_update_var;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	do_fb_set_var(&atafb_predefined[default_par-1], 1);
-	strcat(fb_info.modename, fb_var_names[default_par-1][0]);
-
-	atafb_get_var(&disp.var, -1, &fb_info);
-	atafb_set_disp(-1, &fb_info);
-	do_install_cmap(0, &fb_info);
-
-	if (register_framebuffer(&fb_info) < 0) {
-#ifdef ATAFB_EXT
-		if (external_addr) {
-			iounmap(external_addr);
-			external_addr = NULL;
-		}
-		if (external_vgaiobase) {
-			iounmap((void*)external_vgaiobase);
-			external_vgaiobase = 0;
-		}
-#endif
-		return -EINVAL;
-	}
-
-	printk("Determined %dx%d, depth %d\n",
-	       disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
-	if ((disp.var.xres != disp.var.xres_virtual) ||
-	    (disp.var.yres != disp.var.yres_virtual))
-	   printk("   virtual %dx%d\n",
-			  disp.var.xres_virtual, disp.var.yres_virtual);
-	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
-	       fb_info.node, fb_info.modename, screen_len>>10);
-
-	/* TODO: This driver cannot be unloaded yet */
-	return 0;
+		default_mem_req = min_mem;
 }
 
-
 #ifdef ATAFB_EXT
 static void __init atafb_setup_ext(char *spec)
 {
-	int		xres, xres_virtual, yres, depth, planes;
+	int xres, xres_virtual, yres, depth, planes;
 	unsigned long addr, len;
 	char *p;
 
@@ -2848,27 +2842,31 @@ static void __init atafb_setup_ext(char 
 	 *
 	 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
 	 */
-	if (!(p = strsep(&spec, ";")) || !*p)
-	    return;
+	p = strsep(&spec, ";");
+	if (!p || !*p)
+		return;
 	xres_virtual = xres = simple_strtoul(p, NULL, 10);
 	if (xres <= 0)
-	    return;
+		return;
 
-	if (!(p = strsep(&spec, ";")) || !*p)
-	    return;
+	p = strsep(&spec, ";");
+	if (!p || !*p)
+		return;
 	yres = simple_strtoul(p, NULL, 10);
 	if (yres <= 0)
-	    return;
+		return;
 
-	if (!(p = strsep(&spec, ";")) || !*p)
-	    return;
+	p = strsep(&spec, ";");
+	if (!p || !*p)
+		return;
 	depth = simple_strtoul(p, NULL, 10);
 	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
-		depth != 16 && depth != 24)
-	    return;
+	    depth != 16 && depth != 24)
+		return;
 
-	if (!(p = strsep(&spec, ";")) || !*p)
-	    return;
+	p = strsep(&spec, ";");
+	if (!p || !*p)
+		return;
 	if (*p == 'i')
 		planes = FB_TYPE_INTERLEAVED_PLANES;
 	else if (*p == 'p')
@@ -2876,25 +2874,27 @@ static void __init atafb_setup_ext(char 
 	else if (*p == 'n')
 		planes = FB_TYPE_PLANES;
 	else if (*p == 't')
-		planes = -1; /* true color */
+		planes = -1;		/* true color */
 	else
 		return;
 
-
-	if (!(p = strsep(&spec, ";")) || !*p)
+	p = strsep(&spec, ";");
+	if (!p || !*p)
 		return;
 	addr = simple_strtoul(p, NULL, 0);
 
-	if (!(p = strsep(&spec, ";")) || !*p)
-		len = xres*yres*depth/8;
+	p = strsep(&spec, ";");
+	if (!p || !*p)
+		len = xres * yres * depth / 8;
 	else
 		len = simple_strtoul(p, NULL, 0);
 
-	if ((p = strsep(&spec, ";")) && *p) {
-		external_vgaiobase=simple_strtoul(p, NULL, 0);
-	}
+	p = strsep(&spec, ";");
+	if (p && *p)
+		external_vgaiobase = simple_strtoul(p, NULL, 0);
 
-	if ((p = strsep(&spec, ";")) && *p) {
+	p = strsep(&spec, ";");
+	if (p && *p) {
 		external_bitspercol = simple_strtoul(p, NULL, 0);
 		if (external_bitspercol > 8)
 			external_bitspercol = 8;
@@ -2902,59 +2902,61 @@ static void __init atafb_setup_ext(char 
 			external_bitspercol = 1;
 	}
 
-	if ((p = strsep(&spec, ";")) && *p) {
+	p = strsep(&spec, ";");
+	if (p && *p) {
 		if (!strcmp(p, "vga"))
 			external_card_type = IS_VGA;
 		if (!strcmp(p, "mv300"))
 			external_card_type = IS_MV300;
 	}
 
-	if ((p = strsep(&spec, ";")) && *p) {
+	p = strsep(&spec, ";");
+	if (p && *p) {
 		xres_virtual = simple_strtoul(p, NULL, 10);
 		if (xres_virtual < xres)
 			xres_virtual = xres;
-		if (xres_virtual*yres*depth/8 > len)
-			len=xres_virtual*yres*depth/8;
+		if (xres_virtual * yres * depth / 8 > len)
+			len = xres_virtual * yres * depth / 8;
 	}
 
-	external_xres  = xres;
-	external_xres_virtual  = xres_virtual;
-	external_yres  = yres;
+	external_xres = xres;
+	external_xres_virtual = xres_virtual;
+	external_yres = yres;
 	external_depth = depth;
 	external_pmode = planes;
-	external_addr  = (void *)addr;
-	external_len   = len;
-
-	if (external_card_type == IS_MV300)
-	  switch (external_depth) {
-	    case 1:
-	      MV300_reg = MV300_reg_1bit;
-	      break;
-	    case 4:
-	      MV300_reg = MV300_reg_4bit;
-	      break;
-	    case 8:
-	      MV300_reg = MV300_reg_8bit;
-	      break;
-	    }
+	external_addr = (void *)addr;
+	external_len = len;
+
+	if (external_card_type == IS_MV300) {
+		switch (external_depth) {
+		case 1:
+			MV300_reg = MV300_reg_1bit;
+			break;
+		case 4:
+			MV300_reg = MV300_reg_4bit;
+			break;
+		case 8:
+			MV300_reg = MV300_reg_8bit;
+			break;
+		}
+	}
 }
 #endif /* ATAFB_EXT */
 
-
 static void __init atafb_setup_int(char *spec)
 {
 	/* Format to config extended internal video hardware like OverScan:
-	"internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
-	Explanation:
-	<xres>: x-resolution 
-	<yres>: y-resolution
-	The following are only needed if you have an overscan which
-	needs a black border:
-	<xres_max>: max. length of a line in pixels your OverScan hardware would allow
-	<yres_max>: max. number of lines your OverScan hardware would allow
-	<offset>: Offset from physical beginning to visible beginning
-		  of screen in bytes
-	*/
+	 * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+	 * Explanation:
+	 * <xres>: x-resolution
+	 * <yres>: y-resolution
+	 * The following are only needed if you have an overscan which
+	 * needs a black border:
+	 * <xres_max>: max. length of a line in pixels your OverScan hardware would allow
+	 * <yres_max>: max. number of lines your OverScan hardware would allow
+	 * <offset>: Offset from physical beginning to visible beginning
+	 *	  of screen in bytes
+	 */
 	int xres;
 	char *p;
 
@@ -2963,23 +2965,19 @@ static void __init atafb_setup_int(char 
 	xres = simple_strtoul(p, NULL, 10);
 	if (!(p = strsep(&spec, ";")) || !*p)
 		return;
-	sttt_xres=xres;
-	tt_yres=st_yres=simple_strtoul(p, NULL, 10);
-	if ((p=strsep(&spec, ";")) && *p) {
-		sttt_xres_virtual=simple_strtoul(p, NULL, 10);
-	}
-	if ((p=strsep(&spec, ";")) && *p) {
-		sttt_yres_virtual=simple_strtoul(p, NULL, 0);
-	}
-	if ((p=strsep(&spec, ";")) && *p) {
-		ovsc_offset=simple_strtoul(p, NULL, 0);
-	}
+	sttt_xres = xres;
+	tt_yres = st_yres = simple_strtoul(p, NULL, 10);
+	if ((p = strsep(&spec, ";")) && *p)
+		sttt_xres_virtual = simple_strtoul(p, NULL, 10);
+	if ((p = strsep(&spec, ";")) && *p)
+		sttt_yres_virtual = simple_strtoul(p, NULL, 0);
+	if ((p = strsep(&spec, ";")) && *p)
+		ovsc_offset = simple_strtoul(p, NULL, 0);
 
 	if (ovsc_offset || (sttt_yres_virtual != st_yres))
-		use_hwscroll=0;
+		use_hwscroll = 0;
 }
 
-
 #ifdef ATAFB_FALCON
 static void __init atafb_setup_mcap(char *spec)
 {
@@ -3018,7 +3016,6 @@ static void __init atafb_setup_mcap(char
 }
 #endif /* ATAFB_FALCON */
 
-
 static void __init atafb_setup_user(char *spec)
 {
 	/* Format of user defined video mode is: <xres>;<yres>;<depth>
@@ -3026,81 +3023,257 @@ static void __init atafb_setup_user(char
 	char *p;
 	int xres, yres, depth, temp;
 
-	if (!(p = strsep(&spec, ";")) || !*p)
+	p = strsep(&spec, ";");
+	if (!p || !*p)
 		return;
 	xres = simple_strtoul(p, NULL, 10);
-	if (!(p = strsep(&spec, ";")) || !*p)
+	p = strsep(&spec, ";");
+	if (!p || !*p)
 		return;
 	yres = simple_strtoul(p, NULL, 10);
-	if (!(p = strsep(&spec, "")) || !*p)
+	p = strsep(&spec, "");
+	if (!p || !*p)
 		return;
 	depth = simple_strtoul(p, NULL, 10);
-	if ((temp=get_video_mode("user0"))) {
-		default_par=temp;
-		atafb_predefined[default_par-1].xres = xres;
-		atafb_predefined[default_par-1].yres = yres;
-		atafb_predefined[default_par-1].bits_per_pixel = depth;
+	temp = get_video_mode("user0");
+	if (temp) {
+		default_par = temp;
+		atafb_predefined[default_par - 1].xres = xres;
+		atafb_predefined[default_par - 1].yres = yres;
+		atafb_predefined[default_par - 1].bits_per_pixel = depth;
 	}
 }
 
-int __init atafb_setup( char *options )
+int __init atafb_setup(char *options)
 {
-    char *this_opt;
-    int temp;
-
-    fb_info.fontname[0] = '\0';
+	char *this_opt;
+	int temp;
 
-    if (!options || !*options)
+	if (!options || !*options)
 		return 0;
-    
-    while ((this_opt = strsep(&options, ",")) != NULL) {	 
-	if (!*this_opt) continue;
-	if ((temp=get_video_mode(this_opt)))
-		default_par=temp;
-	else if (! strcmp(this_opt, "inverse"))
-		inverse=1;
-	else if (!strncmp(this_opt, "font:", 5))
-	   strcpy(fb_info.fontname, this_opt+5);
-	else if (! strncmp(this_opt, "hwscroll_",9)) {
-		hwscroll=simple_strtoul(this_opt+9, NULL, 10);
-		if (hwscroll < 0)
-			hwscroll = 0;
-		if (hwscroll > 200)
-			hwscroll = 200;
-	}
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		if ((temp = get_video_mode(this_opt))) {
+			default_par = temp;
+			mode_option = this_opt;
+		} else if (!strcmp(this_opt, "inverse"))
+			inverse = 1;
+		else if (!strncmp(this_opt, "hwscroll_", 9)) {
+			hwscroll = simple_strtoul(this_opt + 9, NULL, 10);
+			if (hwscroll < 0)
+				hwscroll = 0;
+			if (hwscroll > 200)
+				hwscroll = 200;
+		}
 #ifdef ATAFB_EXT
-	else if (!strcmp(this_opt,"mv300")) {
-		external_bitspercol = 8;
-		external_card_type = IS_MV300;
+		else if (!strcmp(this_opt, "mv300")) {
+			external_bitspercol = 8;
+			external_card_type = IS_MV300;
+		} else if (!strncmp(this_opt, "external:", 9))
+			atafb_setup_ext(this_opt + 9);
+#endif
+		else if (!strncmp(this_opt, "internal:", 9))
+			atafb_setup_int(this_opt + 9);
+#ifdef ATAFB_FALCON
+		else if (!strncmp(this_opt, "eclock:", 7)) {
+			fext.f = simple_strtoul(this_opt + 7, NULL, 10);
+			/* external pixelclock in kHz --> ps */
+			fext.t = 1000000000 / fext.f;
+			fext.f *= 1000;
+		} else if (!strncmp(this_opt, "monitorcap:", 11))
+			atafb_setup_mcap(this_opt + 11);
+#endif
+		else if (!strcmp(this_opt, "keep"))
+			DontCalcRes = 1;
+		else if (!strncmp(this_opt, "R", 1))
+			atafb_setup_user(this_opt + 1);
 	}
-	else if (!strncmp(this_opt,"external:",9))
-		atafb_setup_ext(this_opt+9);
+	return 0;
+}
+
+int __init atafb_init(void)
+{
+	int pad;
+	int detected_mode;
+	unsigned int defmode = 0;
+	unsigned long mem_req;
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("atafb", &option))
+		return -ENODEV;
+	atafb_setup(option);
+#endif
+	printk("atafb_init: start\n");
+
+	if (!MACH_IS_ATARI)
+		return -ENXIO;
+
+	do {
+#ifdef ATAFB_EXT
+		if (external_addr) {
+			printk("atafb_init: initializing external hw\n");
+			fbhw = &ext_switch;
+			atafb_ops.fb_setcolreg = &ext_setcolreg;
+			defmode = DEFMODE_EXT;
+			break;
+		}
+#endif
+#ifdef ATAFB_TT
+		if (ATARIHW_PRESENT(TT_SHIFTER)) {
+			printk("atafb_init: initializing TT hw\n");
+			fbhw = &tt_switch;
+			atafb_ops.fb_setcolreg = &tt_setcolreg;
+			defmode = DEFMODE_TT;
+			break;
+		}
 #endif
-	else if (!strncmp(this_opt,"internal:",9))
-		atafb_setup_int(this_opt+9);
 #ifdef ATAFB_FALCON
-	else if (!strncmp(this_opt, "eclock:", 7)) {
-		fext.f = simple_strtoul(this_opt+7, NULL, 10);
-		/* external pixelclock in kHz --> ps */
-		fext.t = 1000000000/fext.f;
-		fext.f *= 1000;
+		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
+			printk("atafb_init: initializing Falcon hw\n");
+			fbhw = &falcon_switch;
+			atafb_ops.fb_setcolreg = &falcon_setcolreg;
+			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+			            "framebuffer/modeswitch", falcon_vbl_switcher);
+			defmode = DEFMODE_F30;
+			break;
+		}
+#endif
+#ifdef ATAFB_STE
+		if (ATARIHW_PRESENT(STND_SHIFTER) ||
+		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
+			printk("atafb_init: initializing ST/E hw\n");
+			fbhw = &st_switch;
+			atafb_ops.fb_setcolreg = &stste_setcolreg;
+			defmode = DEFMODE_STE;
+			break;
+		}
+		fbhw = &st_switch;
+		atafb_ops.fb_setcolreg = &stste_setcolreg;
+		printk("Cannot determine video hardware; defaulting to ST(e)\n");
+#else /* ATAFB_STE */
+		/* no default driver included */
+		/* Nobody will ever see this message :-) */
+		panic("Cannot initialize video hardware");
+#endif
+	} while (0);
+
+	/* Multisync monitor capabilities */
+	/* Atari-TOS defaults if no boot option present */
+	if (fb_info.monspecs.hfmin == 0) {
+		fb_info.monspecs.hfmin = 31000;
+		fb_info.monspecs.hfmax = 32000;
+		fb_info.monspecs.vfmin = 58;
+		fb_info.monspecs.vfmax = 62;
 	}
-	else if (!strncmp(this_opt, "monitorcap:", 11))
-		atafb_setup_mcap(this_opt+11);
+
+	detected_mode = fbhw->detect();
+	check_default_par(detected_mode);
+#ifdef ATAFB_EXT
+	if (!external_addr) {
+#endif /* ATAFB_EXT */
+		mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
+		mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
+		screen_base = atari_stram_alloc(mem_req, "atafb");
+		if (!screen_base)
+			panic("Cannot allocate screen memory");
+		memset(screen_base, 0, mem_req);
+		pad = -(unsigned long)screen_base & (PAGE_SIZE - 1);
+		screen_base += pad;
+		real_screen_base = screen_base + ovsc_offset;
+		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
+		st_ovsc_switch();
+		if (CPU_IS_040_OR_060) {
+			/* On a '040+, the cache mode of video RAM must be set to
+			 * write-through also for internal video hardware! */
+			cache_push(virt_to_phys(screen_base), screen_len);
+			kernel_set_cachemode(screen_base, screen_len,
+					     IOMAP_WRITETHROUGH);
+		}
+		printk("atafb: screen_base %p real_screen_base %p screen_len %d\n",
+			screen_base, real_screen_base, screen_len);
+#ifdef ATAFB_EXT
+	} else {
+		/* Map the video memory (physical address given) to somewhere
+		 * in the kernel address space.
+		 */
+		external_addr = ioremap_writethrough((unsigned long)external_addr,
+						     external_len);
+		if (external_vgaiobase)
+			external_vgaiobase =
+			  (unsigned long)ioremap(external_vgaiobase, 0x10000);
+		screen_base =
+		real_screen_base = external_addr;
+		screen_len = external_len & PAGE_MASK;
+		memset (screen_base, 0, external_len);
+	}
+#endif /* ATAFB_EXT */
+
+//	strcpy(fb_info.mode->name, "Atari Builtin ");
+	fb_info.fbops = &atafb_ops;
+	// try to set default (detected; requested) var
+	do_fb_set_var(&atafb_predefined[default_par - 1], 1);
+	// reads hw state into current par, which may not be sane yet
+	ata_get_par(&current_par);
+	fb_info.par = &current_par;
+	// tries to read from HW which may not be initialized yet
+	// so set sane var first, then call atafb_set_par
+	atafb_get_var(&fb_info.var, &fb_info);
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
+			  NUM_TOTAL_MODES, &atafb_modedb[defmode],
+			  fb_info.var.bits_per_pixel)) {
+		return -EINVAL;
+	}
+
+	atafb_set_disp(&fb_info);
+
+	fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
+
+
+	printk("Determined %dx%d, depth %d\n",
+	       fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel);
+	if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
+	    (fb_info.var.yres != fb_info.var.yres_virtual))
+		printk("   virtual %dx%d\n", fb_info.var.xres_virtual,
+		       fb_info.var.yres_virtual);
+
+	if (register_framebuffer(&fb_info) < 0) {
+#ifdef ATAFB_EXT
+		if (external_addr) {
+			iounmap(external_addr);
+			external_addr = NULL;
+		}
+		if (external_vgaiobase) {
+			iounmap((void*)external_vgaiobase);
+			external_vgaiobase = 0;
+		}
 #endif
-	else if (!strcmp(this_opt, "keep"))
-		DontCalcRes = 1;
-	else if (!strncmp(this_opt, "R", 1))
-		atafb_setup_user(this_opt+1);
-    }
-    return 0;
+		return -EINVAL;
+	}
+
+	// FIXME: mode needs setting!
+	//printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+	//       fb_info.node, fb_info.mode->name, screen_len>>10);
+	printk("fb%d: frame buffer device, using %dK of video memory\n",
+	       fb_info.node, screen_len >> 10);
+
+	/* TODO: This driver cannot be unloaded yet */
+	return 0;
 }
 
+module_init(atafb_init);
+
 #ifdef MODULE
 MODULE_LICENSE("GPL");
 
-int init_module(void)
+int cleanup_module(void)
 {
-	return atafb_init();
+	unregister_framebuffer(&fb_info);
+	return atafb_deinit();
 }
 #endif /* MODULE */
diff --git a/drivers/video/atafb.h b/drivers/video/atafb.h
new file mode 100644
index 0000000..014e059
--- /dev/null
+++ b/drivers/video/atafb.h
@@ -0,0 +1,36 @@
+#ifndef _VIDEO_ATAFB_H
+#define _VIDEO_ATAFB_H
+
+void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+			int dx, int height, int width);
+void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
+			int sy, int sx, int height, int width);
+void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
+			int dy, int dx, u32 width,
+			const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+			     int dx, int height, int width);
+void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
+			     int sy, int sx, int height, int width);
+void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
+			     int dy, int dx, u32 width,
+			     const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+			     int dx, int height, int width);
+void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
+			     int sy, int sx, int height, int width);
+void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
+			     int dy, int dx, u32 width,
+			     const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+			     int dx, int height, int width);
+void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
+			     int sy, int sx, int height, int width);
+void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
+			     int dy, int dx, u32 width,
+			     const u8 *data, u32 bgcolor, u32 fgcolor);
+
+#endif /* _VIDEO_ATAFB_H */
diff --git a/drivers/video/atafb_iplan2p2.c b/drivers/video/atafb_iplan2p2.c
new file mode 100644
index 0000000..8cc9c50
--- /dev/null
+++ b/drivers/video/atafb_iplan2p2.c
@@ -0,0 +1,293 @@
+/*
+ *  linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for
+ *				      interleaved bitplanes Ã  la Atari (2
+ *				      planes, 2 bytes interleave)
+ *
+ *	Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL	2
+#include "atafb_utils.h"
+
+void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line,
+			     int sy, int sx, int dy, int dx,
+			     int height, int width)
+{
+	/*  bmove() has to distinguish two major cases: If both, source and
+	 *  destination, start at even addresses or both are at odd
+	 *  addresses, just the first odd and last even column (if present)
+	 *  require special treatment (memmove_col()). The rest between
+	 *  then can be copied by normal operations, because all adjacent
+	 *  bytes are affected and are to be stored in the same order.
+	 *    The pathological case is when the move should go from an odd
+	 *  address to an even or vice versa. Since the bytes in the plane
+	 *  words must be assembled in new order, it seems wisest to make
+	 *  all movements by memmove_col().
+	 */
+
+	u8 *src, *dst;
+	u32 *s, *d;
+	int w, l , i, j;
+	u_int colsize;
+	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+	colsize = height;
+	if (!((sx ^ dx) & 15)) {
+		/* odd->odd or even->even */
+
+		if (upwards) {
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+			if (sx & 15) {
+				memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+				src += BPL * 2;
+				dst += BPL * 2;
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*d++ = *s++;
+					s = (u32 *)((u8 *)s + l);
+					d = (u32 *)((u8 *)d + l);
+				}
+			}
+			if (width & 15)
+				memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+					      0xff00ff00, height, next_line - BPL * 2);
+		} else {
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			if ((sx + width) & 15) {
+				src -= BPL * 2;
+				dst -= BPL * 2;
+				memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*--d = *--s;
+					s = (u32 *)((u8 *)s - l);
+					d = (u32 *)((u8 *)d - l);
+				}
+			}
+			if (sx & 15)
+				memmove32_col(dst - (width - 16) / (8 / BPL),
+					      src - (width - 16) / (8 / BPL),
+					      0xff00ff, colsize, -next_line - BPL * 2);
+		}
+	} else {
+		/* odd->even or even->odd */
+		if (upwards) {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+			mask = 0xff00ff00;
+			f = 0;
+			w = width;
+			if (sx & 15) {
+				f = 1;
+				w += 8;
+			}
+			if ((sx + width) & 15)
+				f |= 2;
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = (*src32++ << 8) & mask;
+				} else {
+					pval[0] = dst32[0] & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[0] | (v1 >> 8);
+					pval[0] = (v ^ v1) << 8;
+				}
+
+				if (f & 2) {
+					dst32[0] = (dst32[0] & mask) | pval[0];
+				}
+
+				src += next_line;
+				dst += next_line;
+			}
+		} else {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			mask = 0xff00ff;
+			f = 0;
+			w = width;
+			if ((dx + width) & 15)
+				f = 1;
+			if (sx & 15) {
+				f |= 2;
+				w += 8;
+			}
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = dst32[-1] & mask;
+				} else {
+					pval[0] = (*--src32 >> 8) & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[0] | (v1 << 8);
+					pval[0] = (v ^ v1) >> 8;
+				}
+
+				if (!(f & 2)) {
+					dst32[-1] = (dst32[-1] & mask) | pval[0];
+				}
+
+				src -= next_line;
+				dst -= next_line;
+			}
+		}
+	}
+}
+
+void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
+                             int sy, int sx, int height, int width)
+{
+	u32 *dest;
+	int rows, i;
+	u32 cval[4];
+
+	dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+	if (sx & 15) {
+		u8 *dest8 = (u8 *)dest + 1;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	expand16_col2mask(color, cval);
+	rows = width >> 4;
+	if (rows) {
+		u32 *d = dest;
+		u32 off = next_line - rows * BPL * 2;
+		for (i = height; i; i--) {
+			d = fill16_col(d, rows, cval);
+			d = (u32 *)((long)d + off);
+		}
+		dest += rows * BPL / 2;
+		width &= 15;
+	}
+
+	if (width) {
+		u8 *dest8 = (u8 *)dest;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+	}
+}
+
+void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
+                             int dy, int dx, u32 width,
+                             const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+	u32 *dest;
+	const u16 *data16;
+	int rows;
+	u32 fgm[4], bgm[4], m;
+
+	dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+	if (dx & 15) {
+		fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	if (width >= 16) {
+		data16 = (const u16 *)data;
+		expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+		for (rows = width / 16; rows; rows--) {
+			u16 d = *data16++;
+			m = d | ((u32)d << 16);
+			*dest++ = (m & fgm[0]) ^ bgm[0];
+		}
+
+		data = (const u8 *)data16;
+		width &= 15;
+	}
+
+	if (width)
+		fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p2_linefill);
diff --git a/drivers/video/atafb_iplan2p4.c b/drivers/video/atafb_iplan2p4.c
new file mode 100644
index 0000000..bee0d89
--- /dev/null
+++ b/drivers/video/atafb_iplan2p4.c
@@ -0,0 +1,308 @@
+/*
+ *  linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for
+ *				      interleaved bitplanes Ã  la Atari (4
+ *				      planes, 2 bytes interleave)
+ *
+ *	Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL	4
+#include "atafb_utils.h"
+
+void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line,
+			     int sy, int sx, int dy, int dx,
+			     int height, int width)
+{
+	/*  bmove() has to distinguish two major cases: If both, source and
+	 *  destination, start at even addresses or both are at odd
+	 *  addresses, just the first odd and last even column (if present)
+	 *  require special treatment (memmove_col()). The rest between
+	 *  then can be copied by normal operations, because all adjacent
+	 *  bytes are affected and are to be stored in the same order.
+	 *    The pathological case is when the move should go from an odd
+	 *  address to an even or vice versa. Since the bytes in the plane
+	 *  words must be assembled in new order, it seems wisest to make
+	 *  all movements by memmove_col().
+	 */
+
+	u8 *src, *dst;
+	u32 *s, *d;
+	int w, l , i, j;
+	u_int colsize;
+	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+	colsize = height;
+	if (!((sx ^ dx) & 15)) {
+		/* odd->odd or even->even */
+
+		if (upwards) {
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+			if (sx & 15) {
+				memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+				src += BPL * 2;
+				dst += BPL * 2;
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*d++ = *s++;
+					s = (u32 *)((u8 *)s + l);
+					d = (u32 *)((u8 *)d + l);
+				}
+			}
+			if (width & 15)
+				memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+					      0xff00ff00, height, next_line - BPL * 2);
+		} else {
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			if ((sx + width) & 15) {
+				src -= BPL * 2;
+				dst -= BPL * 2;
+				memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*--d = *--s;
+					s = (u32 *)((u8 *)s - l);
+					d = (u32 *)((u8 *)d - l);
+				}
+			}
+			if (sx & 15)
+				memmove32_col(dst - (width - 16) / (8 / BPL),
+					      src - (width - 16) / (8 / BPL),
+					      0xff00ff, colsize, -next_line - BPL * 2);
+		}
+	} else {
+		/* odd->even or even->odd */
+		if (upwards) {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+			mask = 0xff00ff00;
+			f = 0;
+			w = width;
+			if (sx & 15) {
+				f = 1;
+				w += 8;
+			}
+			if ((sx + width) & 15)
+				f |= 2;
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = (*src32++ << 8) & mask;
+					pval[1] = (*src32++ << 8) & mask;
+				} else {
+					pval[0] = dst32[0] & mask;
+					pval[1] = dst32[1] & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[0] | (v1 >> 8);
+					pval[0] = (v ^ v1) << 8;
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[1] | (v1 >> 8);
+					pval[1] = (v ^ v1) << 8;
+				}
+
+				if (f & 2) {
+					dst32[0] = (dst32[0] & mask) | pval[0];
+					dst32[1] = (dst32[1] & mask) | pval[1];
+				}
+
+				src += next_line;
+				dst += next_line;
+			}
+		} else {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			mask = 0xff00ff;
+			f = 0;
+			w = width;
+			if ((dx + width) & 15)
+				f = 1;
+			if (sx & 15) {
+				f |= 2;
+				w += 8;
+			}
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = dst32[-1] & mask;
+					pval[1] = dst32[-2] & mask;
+				} else {
+					pval[0] = (*--src32 >> 8) & mask;
+					pval[1] = (*--src32 >> 8) & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[0] | (v1 << 8);
+					pval[0] = (v ^ v1) >> 8;
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[1] | (v1 << 8);
+					pval[1] = (v ^ v1) >> 8;
+				}
+
+				if (!(f & 2)) {
+					dst32[-1] = (dst32[-1] & mask) | pval[0];
+					dst32[-2] = (dst32[-2] & mask) | pval[1];
+				}
+
+				src -= next_line;
+				dst -= next_line;
+			}
+		}
+	}
+}
+
+void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
+                             int sy, int sx, int height, int width)
+{
+	u32 *dest;
+	int rows, i;
+	u32 cval[4];
+
+	dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+	if (sx & 15) {
+		u8 *dest8 = (u8 *)dest + 1;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	expand16_col2mask(color, cval);
+	rows = width >> 4;
+	if (rows) {
+		u32 *d = dest;
+		u32 off = next_line - rows * BPL * 2;
+		for (i = height; i; i--) {
+			d = fill16_col(d, rows, cval);
+			d = (u32 *)((long)d + off);
+		}
+		dest += rows * BPL / 2;
+		width &= 15;
+	}
+
+	if (width) {
+		u8 *dest8 = (u8 *)dest;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+	}
+}
+
+void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
+                             int dy, int dx, u32 width,
+                             const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+	u32 *dest;
+	const u16 *data16;
+	int rows;
+	u32 fgm[4], bgm[4], m;
+
+	dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+	if (dx & 15) {
+		fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	if (width >= 16) {
+		data16 = (const u16 *)data;
+		expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+		for (rows = width / 16; rows; rows--) {
+			u16 d = *data16++;
+			m = d | ((u32)d << 16);
+			*dest++ = (m & fgm[0]) ^ bgm[0];
+			*dest++ = (m & fgm[1]) ^ bgm[1];
+		}
+
+		data = (const u8 *)data16;
+		width &= 15;
+	}
+
+	if (width)
+		fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(atafb_iplan2p4_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p4_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p4_linefill);
diff --git a/drivers/video/atafb_iplan2p8.c b/drivers/video/atafb_iplan2p8.c
new file mode 100644
index 0000000..356fb52
--- /dev/null
+++ b/drivers/video/atafb_iplan2p8.c
@@ -0,0 +1,345 @@
+/*
+ *  linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for
+ *				      interleaved bitplanes Ã  la Atari (8
+ *				      planes, 2 bytes interleave)
+ *
+ *	Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL	8
+#include "atafb_utils.h"
+
+
+/* Copies a 8 plane column from 's', height 'h', to 'd'. */
+
+/* This expands a 8 bit color into two longs for two movepl (8 plane)
+ * operations.
+ */
+
+void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line,
+			     int sy, int sx, int dy, int dx,
+			     int height, int width)
+{
+	/*  bmove() has to distinguish two major cases: If both, source and
+	 *  destination, start at even addresses or both are at odd
+	 *  addresses, just the first odd and last even column (if present)
+	 *  require special treatment (memmove_col()). The rest between
+	 *  then can be copied by normal operations, because all adjacent
+	 *  bytes are affected and are to be stored in the same order.
+	 *    The pathological case is when the move should go from an odd
+	 *  address to an even or vice versa. Since the bytes in the plane
+	 *  words must be assembled in new order, it seems wisest to make
+	 *  all movements by memmove_col().
+	 */
+
+	u8 *src, *dst;
+	u32 *s, *d;
+	int w, l , i, j;
+	u_int colsize;
+	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+	colsize = height;
+	if (!((sx ^ dx) & 15)) {
+		/* odd->odd or even->even */
+
+		if (upwards) {
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+			if (sx & 15) {
+				memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+				src += BPL * 2;
+				dst += BPL * 2;
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*d++ = *s++;
+					s = (u32 *)((u8 *)s + l);
+					d = (u32 *)((u8 *)d + l);
+				}
+			}
+			if (width & 15)
+				memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+					      0xff00ff00, height, next_line - BPL * 2);
+		} else {
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			if ((sx + width) & 15) {
+				src -= BPL * 2;
+				dst -= BPL * 2;
+				memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+				width -= 8;
+			}
+			w = width >> 4;
+			if (w) {
+				s = (u32 *)src;
+				d = (u32 *)dst;
+				w *= BPL / 2;
+				l = next_line - w * 4;
+				for (j = height; j > 0; j--) {
+					for (i = w; i > 0; i--)
+						*--d = *--s;
+					s = (u32 *)((u8 *)s - l);
+					d = (u32 *)((u8 *)d - l);
+				}
+			}
+			if (sx & 15)
+				memmove32_col(dst - (width - 16) / (8 / BPL),
+					      src - (width - 16) / (8 / BPL),
+					      0xff00ff, colsize, -next_line - BPL * 2);
+		}
+	} else {
+		/* odd->even or even->odd */
+		if (upwards) {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+			mask = 0xff00ff00;
+			f = 0;
+			w = width;
+			if (sx & 15) {
+				f = 1;
+				w += 8;
+			}
+			if ((sx + width) & 15)
+				f |= 2;
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = (*src32++ << 8) & mask;
+					pval[1] = (*src32++ << 8) & mask;
+					pval[2] = (*src32++ << 8) & mask;
+					pval[3] = (*src32++ << 8) & mask;
+				} else {
+					pval[0] = dst32[0] & mask;
+					pval[1] = dst32[1] & mask;
+					pval[2] = dst32[2] & mask;
+					pval[3] = dst32[3] & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[0] | (v1 >> 8);
+					pval[0] = (v ^ v1) << 8;
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[1] | (v1 >> 8);
+					pval[1] = (v ^ v1) << 8;
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[2] | (v1 >> 8);
+					pval[2] = (v ^ v1) << 8;
+					v = *src32++;
+					v1 = v & mask;
+					*dst32++ = pval[3] | (v1 >> 8);
+					pval[3] = (v ^ v1) << 8;
+				}
+
+				if (f & 2) {
+					dst32[0] = (dst32[0] & mask) | pval[0];
+					dst32[1] = (dst32[1] & mask) | pval[1];
+					dst32[2] = (dst32[2] & mask) | pval[2];
+					dst32[3] = (dst32[3] & mask) | pval[3];
+				}
+
+				src += next_line;
+				dst += next_line;
+			}
+		} else {
+			u32 *src32, *dst32;
+			u32 pval[4], v, v1, mask;
+			int i, j, w, f;
+
+			src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+			dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+			mask = 0xff00ff;
+			f = 0;
+			w = width;
+			if ((dx + width) & 15)
+				f = 1;
+			if (sx & 15) {
+				f |= 2;
+				w += 8;
+			}
+			w >>= 4;
+			for (i = height; i; i--) {
+				src32 = (u32 *)src;
+				dst32 = (u32 *)dst;
+
+				if (f & 1) {
+					pval[0] = dst32[-1] & mask;
+					pval[1] = dst32[-2] & mask;
+					pval[2] = dst32[-3] & mask;
+					pval[3] = dst32[-4] & mask;
+				} else {
+					pval[0] = (*--src32 >> 8) & mask;
+					pval[1] = (*--src32 >> 8) & mask;
+					pval[2] = (*--src32 >> 8) & mask;
+					pval[3] = (*--src32 >> 8) & mask;
+				}
+
+				for (j = w; j > 0; j--) {
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[0] | (v1 << 8);
+					pval[0] = (v ^ v1) >> 8;
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[1] | (v1 << 8);
+					pval[1] = (v ^ v1) >> 8;
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[2] | (v1 << 8);
+					pval[2] = (v ^ v1) >> 8;
+					v = *--src32;
+					v1 = v & mask;
+					*--dst32 = pval[3] | (v1 << 8);
+					pval[3] = (v ^ v1) >> 8;
+				}
+
+				if (!(f & 2)) {
+					dst32[-1] = (dst32[-1] & mask) | pval[0];
+					dst32[-2] = (dst32[-2] & mask) | pval[1];
+					dst32[-3] = (dst32[-3] & mask) | pval[2];
+					dst32[-4] = (dst32[-4] & mask) | pval[3];
+				}
+
+				src -= next_line;
+				dst -= next_line;
+			}
+		}
+	}
+}
+
+void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
+                             int sy, int sx, int height, int width)
+{
+	u32 *dest;
+	int rows, i;
+	u32 cval[4];
+
+	dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+	if (sx & 15) {
+		u8 *dest8 = (u8 *)dest + 1;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	expand16_col2mask(color, cval);
+	rows = width >> 4;
+	if (rows) {
+		u32 *d = dest;
+		u32 off = next_line - rows * BPL * 2;
+		for (i = height; i; i--) {
+			d = fill16_col(d, rows, cval);
+			d = (u32 *)((long)d + off);
+		}
+		dest += rows * BPL / 2;
+		width &= 15;
+	}
+
+	if (width) {
+		u8 *dest8 = (u8 *)dest;
+
+		expand8_col2mask(color, cval);
+
+		for (i = height; i; i--) {
+			fill8_col(dest8, cval);
+			dest8 += next_line;
+		}
+	}
+}
+
+void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
+			     int dy, int dx, u32 width,
+			     const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+	u32 *dest;
+	const u16 *data16;
+	int rows;
+	u32 fgm[4], bgm[4], m;
+
+	dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+	if (dx & 15) {
+		fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+		dest += BPL / 2;
+		width -= 8;
+	}
+
+	if (width >= 16) {
+		data16 = (const u16 *)data;
+		expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+		for (rows = width / 16; rows; rows--) {
+			u16 d = *data16++;
+			m = d | ((u32)d << 16);
+			*dest++ = (m & fgm[0]) ^ bgm[0];
+			*dest++ = (m & fgm[1]) ^ bgm[1];
+			*dest++ = (m & fgm[2]) ^ bgm[2];
+			*dest++ = (m & fgm[3]) ^ bgm[3];
+		}
+
+		data = (const u8 *)data16;
+		width &= 15;
+	}
+
+	if (width)
+		fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(atafb_iplan2p8_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p8_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p8_linefill);
diff --git a/drivers/video/atafb_mfb.c b/drivers/video/atafb_mfb.c
new file mode 100644
index 0000000..6a352d6
--- /dev/null
+++ b/drivers/video/atafb_mfb.c
@@ -0,0 +1,112 @@
+/*
+ *  linux/drivers/video/mfb.c -- Low level frame buffer operations for
+ *				 monochrome
+ *
+ *	Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+
+#include "atafb.h"
+#include "atafb_utils.h"
+
+
+    /*
+     *  Monochrome
+     */
+
+void atafb_mfb_copyarea(struct fb_info *info, u_long next_line,
+			int sy, int sx, int dy, int dx,
+			int height, int width)
+{
+	u8 *src, *dest;
+	u_int rows;
+
+	if (sx == 0 && dx == 0 && width == next_line) {
+		src = (u8 *)info->screen_base + sy * (width >> 3);
+		dest = (u8 *)info->screen_base + dy * (width >> 3);
+		fb_memmove(dest, src, height * (width >> 3));
+	} else if (dy <= sy) {
+		src = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
+		dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
+		for (rows = height; rows--;) {
+			fb_memmove(dest, src, width >> 3);
+			src += next_line;
+			dest += next_line;
+		}
+	} else {
+		src = (u8 *)info->screen_base + (sy + height - 1) * next_line + (sx >> 3);
+		dest = (u8 *)info->screen_base + (dy + height - 1) * next_line + (dx >> 3);
+		for (rows = height; rows--;) {
+			fb_memmove(dest, src, width >> 3);
+			src -= next_line;
+			dest -= next_line;
+		}
+	}
+}
+
+void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
+			int sy, int sx, int height, int width)
+{
+	u8 *dest;
+	u_int rows;
+
+	dest = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
+
+	if (sx == 0 && width == next_line) {
+		if (color)
+			fb_memset255(dest, height * (width >> 3));
+		else
+			fb_memclear(dest, height * (width >> 3));
+	} else {
+		for (rows = height; rows--; dest += next_line) {
+			if (color)
+				fb_memset255(dest, width >> 3);
+			else
+				fb_memclear_small(dest, width >> 3);
+		}
+	}
+}
+
+void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
+			int dy, int dx, u32 width,
+			const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+	u8 *dest;
+	u_int rows;
+
+	dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
+
+	for (rows = width / 8; rows--; /* check margins */ ) {
+		// use fast_memmove or fb_memmove
+		*dest++ = *data++;
+	}
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+    /*
+     *  Visible symbols for modules
+     */
+
+EXPORT_SYMBOL(atafb_mfb_copyarea);
+EXPORT_SYMBOL(atafb_mfb_fillrect);
+EXPORT_SYMBOL(atafb_mfb_linefill);
diff --git a/drivers/video/atafb_utils.h b/drivers/video/atafb_utils.h
new file mode 100644
index 0000000..ac9e19d
--- /dev/null
+++ b/drivers/video/atafb_utils.h
@@ -0,0 +1,400 @@
+#ifndef _VIDEO_ATAFB_UTILS_H
+#define _VIDEO_ATAFB_UTILS_H
+
+/* ================================================================= */
+/*                      Utility Assembler Functions                  */
+/* ================================================================= */
+
+/* ====================================================================== */
+
+/* Those of a delicate disposition might like to skip the next couple of
+ * pages.
+ *
+ * These functions are drop in replacements for memmove and
+ * memset(_, 0, _). However their five instances add at least a kilobyte
+ * to the object file. You have been warned.
+ *
+ * Not a great fan of assembler for the sake of it, but I think
+ * that these routines are at least 10 times faster than their C
+ * equivalents for large blits, and that's important to the lowest level of
+ * a graphics driver. Question is whether some scheme with the blitter
+ * would be faster. I suspect not for simple text system - not much
+ * asynchrony.
+ *
+ * Code is very simple, just gruesome expansion. Basic strategy is to
+ * increase data moved/cleared at each step to 16 bytes to reduce
+ * instruction per data move overhead. movem might be faster still
+ * For more than 15 bytes, we try to align the write direction on a
+ * longword boundary to get maximum speed. This is even more gruesome.
+ * Unaligned read/write used requires 68020+ - think this is a problem?
+ *
+ * Sorry!
+ */
+
+
+/* ++roman: I've optimized Robert's original versions in some minor
+ * aspects, e.g. moveq instead of movel, let gcc choose the registers,
+ * use movem in some places...
+ * For other modes than 1 plane, lots of more such assembler functions
+ * were needed (e.g. the ones using movep or expanding color values).
+ */
+
+/* ++andreas: more optimizations:
+   subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
+   addal is faster than addaw
+   movep is rather expensive compared to ordinary move's
+   some functions rewritten in C for clarity, no speed loss */
+
+static inline void *fb_memclear_small(void *s, size_t count)
+{
+	if (!count)
+		return 0;
+
+	asm volatile ("\n"
+		"	lsr.l	#1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
+		"1:"
+		: "=a" (s), "=d" (count)
+		: "d" (0), "0" ((char *)s + count), "1" (count));
+	asm volatile ("\n"
+		"	subq.l  #1,%1\n"
+		"	jcs	3f\n"
+		"	move.l	%2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
+		"2:	movem.l	%2/%%d4/%%d5/%%d6,-(%0)\n"
+		"	dbra	%1,2b\n"
+		"3:"
+		: "=a" (s), "=d" (count)
+		: "d" (0), "0" (s), "1" (count)
+		: "d4", "d5", "d6"
+		);
+
+	return 0;
+}
+
+
+static inline void *fb_memclear(void *s, size_t count)
+{
+	if (!count)
+		return 0;
+
+	if (count < 16) {
+		asm volatile ("\n"
+			"	lsr.l	#1,%1 ; jcc 1f ; clr.b (%0)+\n"
+			"1:	lsr.l	#1,%1 ; jcc 1f ; clr.w (%0)+\n"
+			"1:	lsr.l	#1,%1 ; jcc 1f ; clr.l (%0)+\n"
+			"1:	lsr.l	#1,%1 ; jcc 1f ; clr.l (%0)+ ; clr.l (%0)+\n"
+			"1:"
+			: "=a" (s), "=d" (count)
+			: "0" (s), "1" (count));
+	} else {
+		long tmp;
+		asm volatile ("\n"
+			"	move.l	%1,%2\n"
+			"	lsr.l	#1,%2 ; jcc 1f ; clr.b (%0)+ ; subq.w #1,%1\n"
+			"	lsr.l	#1,%2 ; jcs 2f\n"  /* %0 increased=>bit 2 switched*/
+			"	clr.w	(%0)+  ; subq.w  #2,%1 ; jra 2f\n"
+			"1:	lsr.l	#1,%2 ; jcc 2f\n"
+			"	clr.w	(%0)+  ; subq.w  #2,%1\n"
+			"2:	move.w	%1,%2; lsr.l #2,%1 ; jeq 6f\n"
+			"	lsr.l	#1,%1 ; jcc 3f ; clr.l (%0)+\n"
+			"3:	lsr.l	#1,%1 ; jcc 4f ; clr.l (%0)+ ; clr.l (%0)+\n"
+			"4:	subq.l	#1,%1 ; jcs 6f\n"
+			"5:	clr.l	(%0)+; clr.l (%0)+ ; clr.l (%0)+ ; clr.l (%0)+\n"
+			"	dbra	%1,5b ; clr.w %1; subq.l #1,%1; jcc 5b\n"
+			"6:	move.w	%2,%1; btst #1,%1 ; jeq 7f ; clr.w (%0)+\n"
+			"7:	btst	#0,%1 ; jeq 8f ; clr.b (%0)+\n"
+			"8:"
+			: "=a" (s), "=d" (count), "=d" (tmp)
+			: "0" (s), "1" (count));
+	}
+
+	return 0;
+}
+
+
+static inline void *fb_memset255(void *s, size_t count)
+{
+	if (!count)
+		return 0;
+
+	asm volatile ("\n"
+		"	lsr.l	#1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
+		"1:	lsr.l	#1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
+		"1:"
+		: "=a" (s), "=d" (count)
+		: "d" (-1), "0" ((char *)s+count), "1" (count));
+	asm volatile ("\n"
+		"	subq.l	#1,%1 ; jcs 3f\n"
+		"	move.l	%2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
+		"2:	movem.l	%2/%%d4/%%d5/%%d6,-(%0)\n"
+		"	dbra	%1,2b\n"
+		"3:"
+		: "=a" (s), "=d" (count)
+		: "d" (-1), "0" (s), "1" (count)
+		: "d4", "d5", "d6");
+
+	return 0;
+}
+
+
+static inline void *fb_memmove(void *d, const void *s, size_t count)
+{
+	if (d < s) {
+		if (count < 16) {
+			asm volatile ("\n"
+				"	lsr.l	#1,%2 ; jcc 1f ; move.b (%1)+,(%0)+\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.w (%1)+,(%0)+\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.l (%1)+,(%0)+\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
+				"1:"
+				: "=a" (d), "=a" (s), "=d" (count)
+				: "0" (d), "1" (s), "2" (count));
+		} else {
+			long tmp;
+			asm volatile ("\n"
+				"	move.l	%0,%3\n"
+				"	lsr.l	#1,%3 ; jcc 1f ; move.b (%1)+,(%0)+ ; subqw #1,%2\n"
+				"	lsr.l	#1,%3 ; jcs 2f\n"  /* %0 increased=>bit 2 switched*/
+				"	move.w	(%1)+,(%0)+  ; subqw  #2,%2 ; jra 2f\n"
+				"1:	lsr.l   #1,%3 ; jcc 2f\n"
+				"	move.w	(%1)+,(%0)+  ; subqw  #2,%2\n"
+				"2:	move.w	%2,%-; lsr.l #2,%2 ; jeq 6f\n"
+				"	lsr.l	#1,%2 ; jcc 3f ; move.l (%1)+,(%0)+\n"
+				"3:	lsr.l	#1,%2 ; jcc 4f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
+				"4:	subq.l	#1,%2 ; jcs 6f\n"
+				"5:	move.l	(%1)+,(%0)+; move.l (%1)+,(%0)+\n"
+				"	move.l	(%1)+,(%0)+; move.l (%1)+,(%0)+\n"
+				"	dbra	%2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
+				"6:	move.w	%+,%2; btst #1,%2 ; jeq 7f ; move.w (%1)+,(%0)+\n"
+				"7:	btst	#0,%2 ; jeq 8f ; move.b (%1)+,(%0)+\n"
+				"8:"
+				: "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
+				: "0" (d), "1" (s), "2" (count));
+		}
+	} else {
+		if (count < 16) {
+			asm volatile ("\n"
+				"	lsr.l	#1,%2 ; jcc 1f ; move.b -(%1),-(%0)\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.w -(%1),-(%0)\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.l -(%1),-(%0)\n"
+				"1:	lsr.l	#1,%2 ; jcc 1f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
+				"1:"
+				: "=a" (d), "=a" (s), "=d" (count)
+				: "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
+		} else {
+			long tmp;
+
+			asm volatile ("\n"
+				"	move.l	%0,%3\n"
+				"	lsr.l	#1,%3 ; jcc 1f ; move.b -(%1),-(%0) ; subqw #1,%2\n"
+				"	lsr.l	#1,%3 ; jcs 2f\n"  /* %0 increased=>bit 2 switched*/
+				"	move.w	-(%1),-(%0) ; subqw  #2,%2 ; jra 2f\n"
+				"1:	lsr.l	#1,%3 ; jcc 2f\n"
+				"	move.w	-(%1),-(%0) ; subqw  #2,%2\n"
+				"2:	move.w	%2,%-; lsr.l #2,%2 ; jeq 6f\n"
+				"	lsr.l	#1,%2 ; jcc 3f ; move.l -(%1),-(%0)\n"
+				"3:	lsr.l	#1,%2 ; jcc 4f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
+				"4:	subq.l	#1,%2 ; jcs 6f\n"
+				"5:	move.l	-(%1),-(%0); move.l -(%1),-(%0)\n"
+				"	move.l	-(%1),-(%0); move.l -(%1),-(%0)\n"
+				"	dbra	%2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
+				"6:	move.w	%+,%2; btst #1,%2 ; jeq 7f ; move.w -(%1),-(%0)\n"
+				"7:	btst	#0,%2 ; jeq 8f ; move.b -(%1),-(%0)\n"
+				"8:"
+				: "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
+				: "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
+		}
+	}
+
+	return 0;
+}
+
+
+/* ++andreas: Simple and fast version of memmove, assumes size is
+   divisible by 16, suitable for moving the whole screen bitplane */
+static inline void fast_memmove(char *dst, const char *src, size_t size)
+{
+	if (!size)
+		return;
+	if (dst < src)
+		asm volatile ("\n"
+			"1:	movem.l	(%0)+,%%d0/%%d1/%%a0/%%a1\n"
+			"	movem.l	%%d0/%%d1/%%a0/%%a1,%1@\n"
+			"	addq.l	#8,%1; addq.l #8,%1\n"
+			"	dbra	%2,1b\n"
+			"	clr.w	%2; subq.l #1,%2\n"
+			"	jcc	1b"
+			: "=a" (src), "=a" (dst), "=d" (size)
+			: "0" (src), "1" (dst), "2" (size / 16 - 1)
+			: "d0", "d1", "a0", "a1", "memory");
+	else
+		asm volatile ("\n"
+			"1:	subq.l	#8,%0; subq.l #8,%0\n"
+			"	movem.l	%0@,%%d0/%%d1/%%a0/%%a1\n"
+			"	movem.l	%%d0/%%d1/%%a0/%%a1,-(%1)\n"
+			"	dbra	%2,1b\n"
+			"	clr.w	%2; subq.l #1,%2\n"
+			"	jcc 1b"
+			: "=a" (src), "=a" (dst), "=d" (size)
+			: "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
+			: "d0", "d1", "a0", "a1", "memory");
+}
+
+#ifdef BPL
+
+/*
+ * This expands a up to 8 bit color into two longs
+ * for movel operations.
+ */
+static const u32 four2long[] = {
+	0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
+	0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
+	0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
+	0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
+};
+
+static inline void expand8_col2mask(u8 c, u32 m[])
+{
+	m[0] = four2long[c & 15];
+#if BPL > 4
+	m[1] = four2long[c >> 4];
+#endif
+}
+
+static inline void expand8_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
+{
+	fgm[0] = four2long[fg & 15] ^ (bgm[0] = four2long[bg & 15]);
+#if BPL > 4
+	fgm[1] = four2long[fg >> 4] ^ (bgm[1] = four2long[bg >> 4]);
+#endif
+}
+
+/*
+ * set an 8bit value to a color
+ */
+static inline void fill8_col(u8 *dst, u32 m[])
+{
+	u32 tmp = m[0];
+	dst[0] = tmp;
+	dst[2] = (tmp >>= 8);
+#if BPL > 2
+	dst[4] = (tmp >>= 8);
+	dst[6] = tmp >> 8;
+#endif
+#if BPL > 4
+	tmp = m[1];
+	dst[8] = tmp;
+	dst[10] = (tmp >>= 8);
+	dst[12] = (tmp >>= 8);
+	dst[14] = tmp >> 8;
+#endif
+}
+
+/*
+ * set an 8bit value according to foreground/background color
+ */
+static inline void fill8_2col(u8 *dst, u8 fg, u8 bg, u32 mask)
+{
+	u32 fgm[2], bgm[2], tmp;
+
+	expand8_2col2mask(fg, bg, fgm, bgm);
+
+	mask |= mask << 8;
+#if BPL > 2
+	mask |= mask << 16;
+#endif
+	tmp = (mask & fgm[0]) ^ bgm[0];
+	dst[0] = tmp;
+	dst[2] = (tmp >>= 8);
+#if BPL > 2
+	dst[4] = (tmp >>= 8);
+	dst[6] = tmp >> 8;
+#endif
+#if BPL > 4
+	tmp = (mask & fgm[1]) ^ bgm[1];
+	dst[8] = tmp;
+	dst[10] = (tmp >>= 8);
+	dst[12] = (tmp >>= 8);
+	dst[14] = tmp >> 8;
+#endif
+}
+
+static const u32 two2word[] = {
+	0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+};
+
+static inline void expand16_col2mask(u8 c, u32 m[])
+{
+	m[0] = two2word[c & 3];
+#if BPL > 2
+	m[1] = two2word[(c >> 2) & 3];
+#endif
+#if BPL > 4
+	m[2] = two2word[(c >> 4) & 3];
+	m[3] = two2word[c >> 6];
+#endif
+}
+
+static inline void expand16_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
+{
+	bgm[0] = two2word[bg & 3];
+	fgm[0] = two2word[fg & 3] ^ bgm[0];
+#if BPL > 2
+	bgm[1] = two2word[(bg >> 2) & 3];
+	fgm[1] = two2word[(fg >> 2) & 3] ^ bgm[1];
+#endif
+#if BPL > 4
+	bgm[2] = two2word[(bg >> 4) & 3];
+	fgm[2] = two2word[(fg >> 4) & 3] ^ bgm[2];
+	bgm[3] = two2word[bg >> 6];
+	fgm[3] = two2word[fg >> 6] ^ bgm[3];
+#endif
+}
+
+static inline u32 *fill16_col(u32 *dst, int rows, u32 m[])
+{
+	while (rows) {
+		*dst++ = m[0];
+#if BPL > 2
+		*dst++ = m[1];
+#endif
+#if BPL > 4
+		*dst++ = m[2];
+		*dst++ = m[3];
+#endif
+		rows--;
+	}
+	return dst;
+}
+
+static inline void memmove32_col(void *dst, void *src, u32 mask, u32 h, u32 bytes)
+{
+	u32 *s, *d, v;
+
+        s = src;
+        d = dst;
+        do {
+                v = (*s++ & mask) | (*d  & ~mask);
+                *d++ = v;
+#if BPL > 2
+                v = (*s++ & mask) | (*d  & ~mask);
+                *d++ = v;
+#endif
+#if BPL > 4
+                v = (*s++ & mask) | (*d  & ~mask);
+                *d++ = v;
+                v = (*s++ & mask) | (*d  & ~mask);
+                *d++ = v;
+#endif
+                d = (u32 *)((u8 *)d + bytes);
+                s = (u32 *)((u8 *)s + bytes);
+        } while (--h);
+}
+
+#endif
+
+#endif /* _VIDEO_ATAFB_UTILS_H */
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 39ab483..90e7df2 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -209,4 +209,4 @@ #define PCI_CHIP_RV280_5C63		0x5C63
 #define PCI_CHIP_R423_5D57              0x5D57
 #define PCI_CHIP_RS350_7834             0x7834
 #define PCI_CHIP_RS350_7835             0x7835
-
+#define PCI_CHIP_RS480_5955             0x5955
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index e86d7e0..7fea4d8 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -2165,18 +2165,29 @@ #endif /* CONFIG_PCI */
 static int aty128fb_blank(int blank, struct fb_info *fb)
 {
 	struct aty128fb_par *par = fb->par;
-	u8 state = 0;
+	u8 state;
 
 	if (par->lock_blank || par->asleep)
 		return 0;
 
-	if (blank & FB_BLANK_VSYNC_SUSPEND)
-		state |= 2;
-	if (blank & FB_BLANK_HSYNC_SUSPEND)
-		state |= 1;
-	if (blank & FB_BLANK_POWERDOWN)
-		state |= 4;
-
+	switch (blank) {
+	case FB_BLANK_NORMAL:
+		state = 4;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		state = 6;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		state = 5;
+		break;
+	case FB_BLANK_POWERDOWN:
+		state = 7;
+		break;
+	case FB_BLANK_UNBLANK:
+	default:
+		state = 0;
+		break;
+	}
 	aty_st_8(CRTC_EXT_CNTL+1, state);
 
 	if (par->chip_gen == rage_M3) {
@@ -2430,7 +2441,7 @@ #endif /* CONFIG_PPC_PMAC */
 	wait_for_idle(par);
 
 	/* Blank display and LCD */
-	aty128fb_blank(VESA_POWERDOWN, info);
+	aty128fb_blank(FB_BLANK_POWERDOWN, info);
 
 	/* Sleep */
 	par->asleep = 1;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index d7627fc..ea67dd9 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2297,20 +2297,6 @@ #ifdef CONFIG_PPC_PMAC
 		par->pll_limits.xclk = 53;
 	}
 #endif
-	if (pll)
-		par->pll_limits.pll_max = pll;
-	if (mclk)
-		par->pll_limits.mclk = mclk;
-	if (xclk)
-		par->pll_limits.xclk = xclk;
-
-	aty_calc_mem_refresh(par, par->pll_limits.xclk);
-	par->pll_per = 1000000/par->pll_limits.pll_max;
-	par->mclk_per = 1000000/par->pll_limits.mclk;
-	par->xclk_per = 1000000/par->pll_limits.xclk;
-
-	par->ref_clk_per = 1000000000000ULL / 14318180;
-	xtal = "14.31818";
 
 #ifdef CONFIG_FB_ATY_GX
 	if (!M64_HAS(INTEGRATED)) {
@@ -2338,6 +2324,7 @@ #endif
 		case DAC_IBMRGB514:
 			par->dac_ops = &aty_dac_ibm514;
 			break;
+#ifdef CONFIG_ATARI
 		case DAC_ATI68860_B:
 		case DAC_ATI68860_C:
 			par->dac_ops = &aty_dac_ati68860b;
@@ -2346,6 +2333,7 @@ #endif
 		case DAC_ATT21C498:
 			par->dac_ops = &aty_dac_att21c498;
 			break;
+#endif
 		default:
 			PRINTKI("aty_init: DAC type not implemented yet!\n");
 			par->dac_ops = &aty_dac_unsupported;
@@ -2389,8 +2377,29 @@ #ifdef CONFIG_FB_ATY_CT
 		/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
 		if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
 			par->pll_limits.mclk = 63;
+		/* Mobility + 32bit memory interface need halved XCLK. */
+		if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32)
+			par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1;
 	}
+#endif
 
+	/* Allow command line to override clocks. */
+	if (pll)
+		par->pll_limits.pll_max = pll;
+	if (mclk)
+		par->pll_limits.mclk = mclk;
+	if (xclk)
+		par->pll_limits.xclk = xclk;
+
+	aty_calc_mem_refresh(par, par->pll_limits.xclk);
+	par->pll_per = 1000000/par->pll_limits.pll_max;
+	par->mclk_per = 1000000/par->pll_limits.mclk;
+	par->xclk_per = 1000000/par->pll_limits.xclk;
+
+	par->ref_clk_per = 1000000000000ULL / 14318180;
+	xtal = "14.31818";
+
+#ifdef CONFIG_FB_ATY_CT
 	if (M64_HAS(GTB_DSP)) {
 		u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
 
@@ -2899,7 +2908,7 @@ static int __devinit atyfb_setup_sparc(s
 			struct fb_info *info, unsigned long addr)
 {
 	struct atyfb_par *par = info->par;
-	struct pcidev_cookie *pcp;
+	struct device_node *dp;
 	char prop[128];
 	int node, len, i, j, ret;
 	u32 mem, chip_id;
@@ -3037,8 +3046,8 @@ static int __devinit atyfb_setup_sparc(s
 			node = 0;
 	}
 
-	pcp = pdev->sysdata;
-	if (node == pcp->prom_node->node) {
+	dp = pci_device_to_OF_node(pdev);
+	if (node == dp->node) {
 		struct fb_var_screeninfo *var = &default_var;
 		unsigned int N, P, Q, M, T, R;
 		u32 v_total, h_total;
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index 1fdcfdb..cc9e977 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -608,12 +608,10 @@ static void aty_resume_pll_ct(const stru
 		aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
 		aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
 		/*
-		 * The sclk has been started. However, I believe the first clock
-		 * ticks it generates are not very stable. Hope this primitive loop
-		 * helps for Rage Mobilities that sometimes crash when
-		 * we switch to sclk. (Daniel Mantione, 13-05-2003)
+		 * SCLK has been started. Wait for the PLL to lock. 5 ms
+		 * should be enough according to mach64 programmer's guide.
 		 */
-		udelay(500);
+		mdelay(5);
 	}
 
 	aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 1bf6f42..2ce0501 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -100,6 +100,8 @@ #define CHIP_DEF(id, family, flags)					
 	{ PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) }
 
 static struct pci_device_id radeonfb_pci_table[] = {
+        /* Radeon Xpress 200m */
+	CHIP_DEF(PCI_CHIP_RS480_5955,   RS480,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
 	/* Mobility M6 */
 	CHIP_DEF(PCI_CHIP_RADEON_LY, 	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
 	CHIP_DEF(PCI_CHIP_RADEON_LZ,	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -410,7 +412,7 @@ static int  __devinit radeon_find_mem_vb
 }
 #endif
 
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 /*
  * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
  * tree. Hopefully, ATI OF driver is kind enough to fill these
@@ -422,7 +424,7 @@ static int __devinit radeon_read_xtal_OF
 
 	if (dp == NULL)
 		return -ENODEV;
-	val = get_property(dp, "ATY,RefCLK", NULL);
+	val = of_get_property(dp, "ATY,RefCLK", NULL);
 	if (!val || !*val) {
 		printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
 		return -EINVAL;
@@ -430,17 +432,17 @@ static int __devinit radeon_read_xtal_OF
 
 	rinfo->pll.ref_clk = (*val) / 10;
 
-	val = get_property(dp, "ATY,SCLK", NULL);
+	val = of_get_property(dp, "ATY,SCLK", NULL);
 	if (val && *val)
 		rinfo->pll.sclk = (*val) / 10;
 
-	val = get_property(dp, "ATY,MCLK", NULL);
+	val = of_get_property(dp, "ATY,MCLK", NULL);
 	if (val && *val)
 		rinfo->pll.mclk = (*val) / 10;
 
        	return 0;
 }
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 
 /*
  * Read PLL infos from chip registers
@@ -645,7 +647,7 @@ static void __devinit radeon_get_pllinfo
 	rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
 
 
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 	/*
 	 * Retrieve PLL infos from Open Firmware first
 	 */
@@ -653,7 +655,7 @@ #ifdef CONFIG_PPC_OF
        		printk(KERN_INFO "radeonfb: Retrieved PLL infos from Open Firmware\n");
 		goto found;
 	}
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 
 	/*
 	 * Check out if we have an X86 which gave us some PLL informations
@@ -1994,7 +1996,8 @@ static void radeon_identify_vram(struct 
 	/* framebuffer size */
         if ((rinfo->family == CHIP_FAMILY_RS100) ||
             (rinfo->family == CHIP_FAMILY_RS200) ||
-            (rinfo->family == CHIP_FAMILY_RS300)) {
+            (rinfo->family == CHIP_FAMILY_RS300) ||
+	    (rinfo->family == CHIP_FAMILY_RS480) ) {
           u32 tom = INREG(NB_TOM);
           tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
 
@@ -2231,7 +2234,7 @@ static int __devinit radeonfb_pci_regist
 	    rinfo->family == CHIP_FAMILY_RS200)
 		rinfo->errata |= CHIP_ERRATA_PLL_DELAY;
 
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 	/* On PPC, we obtain the OF device-node pointer to the firmware
 	 * data for this chip
 	 */
@@ -2240,6 +2243,8 @@ #ifdef CONFIG_PPC_OF
 		printk(KERN_WARNING "radeonfb (%s): Cannot match card to OF node !\n",
 		       pci_name(rinfo->pdev));
 
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
+#ifdef CONFIG_PPC_OF
 	/* On PPC, the firmware sets up a memory mapping that tends
 	 * to cause lockups when enabling the engine. We reconfigure
 	 * the card internal memory mappings properly
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 5084799..7db9de6 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,7 +1,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
 #include <linux/fb.h>
 
 
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 38c7dbf..2030ed8 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -52,7 +52,7 @@ static char *radeon_get_mon_name(int typ
 }
 
 
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 /*
  * Try to find monitor informations & EDID data out of the Open Firmware
  * device-tree. This also contains some "hacks" to work around a few machine
@@ -70,7 +70,7 @@ static int __devinit radeon_parse_montyp
         int i, mt = MT_NONE;  
 	
 	RTRACE("analyzing OF properties...\n");
-	pmt = get_property(dp, "display-type", NULL);
+	pmt = of_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 = get_property(dp, propnames[i], NULL);
+		pedid = of_get_property(dp, propnames[i], NULL);
 		if (pedid != NULL)
 			break;
 	}
@@ -98,9 +98,10 @@ static int __devinit radeon_parse_montyp
 	 * single-head cards have hdno == -1 and skip this step
 	 */
 	if (pedid == NULL && dp->parent && (hdno != -1))
-		pedid = get_property(dp->parent, (hdno == 0) ? "EDID1" : "EDID2", NULL);
+		pedid = of_get_property(dp->parent,
+				(hdno == 0) ? "EDID1" : "EDID2", NULL);
 	if (pedid == NULL && dp->parent && (hdno == 0))
-		pedid = get_property(dp->parent, "EDID", NULL);
+		pedid = of_get_property(dp->parent, "EDID", NULL);
 	if (pedid == NULL)
 		return mt;
 
@@ -130,7 +131,7 @@ static int __devinit radeon_probe_OF_hea
 		do {
 			if (!dp)
 				return MT_NONE;
-			pname = get_property(dp, "name", NULL);
+			pname = of_get_property(dp, "name", NULL);
 			if (!pname)
 				return MT_NONE;
 			len = strlen(pname);
@@ -156,7 +157,7 @@ static int __devinit radeon_probe_OF_hea
 	}
         return MT_NONE;
 }
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 
 
 static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
@@ -495,11 +496,11 @@ #endif /* DEBUG */
 		 * Old single head cards
 		 */
 		if (!rinfo->has_CRTC2) {
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 			if (rinfo->mon1_type == MT_NONE)
 				rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
 									&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 #ifdef CONFIG_FB_RADEON_I2C
 			if (rinfo->mon1_type == MT_NONE)
 				rinfo->mon1_type =
@@ -544,11 +545,11 @@ #endif /* CONFIG_FB_RADEON_I2C */
 		/*
 		 * Probe primary head (DVI or laptop internal panel)
 		 */
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 		if (rinfo->mon1_type == MT_NONE)
 			rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,
 								&rinfo->mon1_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 #ifdef CONFIG_FB_RADEON_I2C
 		if (rinfo->mon1_type == MT_NONE)
 			rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,
@@ -572,11 +573,11 @@ #endif /* CONFIG_FB_RADEON_I2C */
 		/*
 		 * Probe secondary head (mostly VGA, can be DVI)
 		 */
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 		if (rinfo->mon2_type == MT_NONE)
 			rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,
 								&rinfo->mon2_EDID);
-#endif /* CONFIG_PPC_OF */
+#endif /* CONFIG_PPC_OF || defined(CONFIG_SPARC) */
 #ifdef CONFIG_FB_RADEON_I2C
 		if (rinfo->mon2_type == MT_NONE)
 			rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga,
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 9a2b0d6..be1d57b 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1262,7 +1262,7 @@ static void radeon_pm_full_reset_sdram(s
 	/* This is the code for the Aluminium PowerBooks M10 / iBooks M11 */
 	if (rinfo->family == CHIP_FAMILY_RV350) {
 		u32 sdram_mode_reg = rinfo->save_regs[35];
-		static u32 default_mrtable[] =
+		static const u32 default_mrtable[] =
 			{ 0x21320032,
 			  0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
 			  0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
@@ -1290,7 +1290,7 @@ #ifdef CONFIG_PPC_OF
 		if (rinfo->of_node != NULL) {
 			int size;
 
-			mrtable = get_property(rinfo->of_node, "ATY,MRT", &size);
+			mrtable = of_get_property(rinfo->of_node, "ATY,MRT", &size);
 			if (mrtable)
 				mrtable_size = size >> 2;
 			else
@@ -2826,11 +2826,15 @@ void radeonfb_pm_init(struct radeonfb_in
 	rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
 
 	/* Enable/Disable dynamic clocks: TODO add sysfs access */
-	rinfo->dynclk = dynclk;
-	if (dynclk == 1) {
+	if (rinfo->family == CHIP_FAMILY_RS480)
+		rinfo->dynclk = -1;
+	else
+		rinfo->dynclk = dynclk;
+
+	if (rinfo->dynclk == 1) {
 		radeon_pm_enable_dynamic_mode(rinfo);
 		printk("radeonfb: Dynamic Clock Power Management enabled\n");
-	} else if (dynclk == 0) {
+	} else if (rinfo->dynclk == 0) {
 		radeon_pm_disable_dynamic_mode(rinfo);
 		printk("radeonfb: Dynamic Clock Power Management disabled\n");
 	}
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index d5ff224..7ebffcd 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -16,7 +16,7 @@ #endif
 
 #include <asm/io.h>
 
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 #include <asm/prom.h>
 #endif
 
@@ -48,6 +48,7 @@ enum radeon_family {
 	CHIP_FAMILY_RV350,
 	CHIP_FAMILY_RV380,    /* RV370/RV380/M22/M24 */
 	CHIP_FAMILY_R420,     /* R420/R423/M18 */
+	CHIP_FAMILY_RS480,
 	CHIP_FAMILY_LAST,
 };
 
@@ -64,7 +65,8 @@ #define IS_R300_VARIANT(rinfo) (((rinfo)
 				((rinfo)->family == CHIP_FAMILY_RV350) || \
 				((rinfo)->family == CHIP_FAMILY_R350)  || \
 				((rinfo)->family == CHIP_FAMILY_RV380) || \
-				((rinfo)->family == CHIP_FAMILY_R420))
+				((rinfo)->family == CHIP_FAMILY_R420)  || \
+		                ((rinfo)->family == CHIP_FAMILY_RS480) )
 
 /*
  * Chip flags
@@ -292,7 +294,7 @@ struct radeonfb_info {
 	unsigned long		fb_local_base;
 
 	struct pci_dev		*pdev;
-#ifdef CONFIG_PPC_OF
+#if defined(CONFIG_PPC_OF) || defined(CONFIG_SPARC)
 	struct device_node	*of_node;
 #endif
 
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 47d15b5..fbef663 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -63,3 +63,11 @@ config BACKLIGHT_PROGEAR
 	help
 	  If you have a Frontpath ProGear say Y to enable the
 	  backlight driver.
+
+config BACKLIGHT_CARILLO_RANCH
+	tristate "Intel Carillo Ranch Backlight Driver"
+	depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
+	default n
+	help
+	  If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
+	  backlight driver.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 0c3ce46..c6e2266 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_b
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
 obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
 obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
+obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
new file mode 100644
index 0000000..e9bbc34
--- /dev/null
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Carillo Ranch video subsystem driver.
+ * The Carillo Ranch video subsystem 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Carillo Ranch video subsystem 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 this driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+
+/* The LVDS- and panel power controls sits on the
+ * GPIO port of the ISA bridge.
+ */
+
+#define CRVML_DEVICE_LPC    0x27B8
+#define CRVML_REG_GPIOBAR   0x48
+#define CRVML_REG_GPIOEN    0x4C
+#define CRVML_GPIOEN_BIT    (1 << 4)
+#define CRVML_PANEL_PORT    0x38
+#define CRVML_LVDS_ON       0x00000001
+#define CRVML_PANEL_ON      0x00000002
+#define CRVML_BACKLIGHT_OFF 0x00000004
+
+/* The PLL Clock register sits on Host bridge */
+#define CRVML_DEVICE_MCH   0x5001
+#define CRVML_REG_MCHBAR   0x44
+#define CRVML_REG_MCHEN    0x54
+#define CRVML_MCHEN_BIT    (1 << 28)
+#define CRVML_MCHMAP_SIZE  4096
+#define CRVML_REG_CLOCK    0xc3c
+#define CRVML_CLOCK_SHIFT  8
+#define CRVML_CLOCK_MASK   0x00000f00
+
+static struct pci_dev *lpc_dev;
+static u32 gpio_bar;
+
+struct cr_panel {
+	struct backlight_device *cr_backlight_device;
+	struct lcd_device *cr_lcd_device;
+};
+
+static int cr_backlight_set_intensity(struct backlight_device *bd)
+{
+	int intensity = bd->props.brightness;
+	u32 addr = gpio_bar + CRVML_PANEL_PORT;
+	u32 cur = inl(addr);
+
+	if (bd->props.power == FB_BLANK_UNBLANK)
+		intensity = FB_BLANK_UNBLANK;
+	if (bd->props.fb_blank == FB_BLANK_UNBLANK)
+		intensity = FB_BLANK_UNBLANK;
+	if (bd->props.power == FB_BLANK_POWERDOWN)
+		intensity = FB_BLANK_POWERDOWN;
+	if (bd->props.fb_blank == FB_BLANK_POWERDOWN)
+		intensity = FB_BLANK_POWERDOWN;
+
+	if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */
+		cur &= ~CRVML_BACKLIGHT_OFF;
+		outl(cur, addr);
+	} else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */
+		cur |= CRVML_BACKLIGHT_OFF;
+		outl(cur, addr);
+	} /* anything else, don't bother */
+
+	return 0;
+}
+
+static int cr_backlight_get_intensity(struct backlight_device *bd)
+{
+	u32 addr = gpio_bar + CRVML_PANEL_PORT;
+	u32 cur = inl(addr);
+	u8 intensity;
+
+	if (cur & CRVML_BACKLIGHT_OFF)
+		intensity = FB_BLANK_POWERDOWN;
+	else
+		intensity = FB_BLANK_UNBLANK;
+
+	return intensity;
+}
+
+static struct backlight_ops cr_backlight_ops = {
+	.get_brightness = cr_backlight_get_intensity,
+	.update_status = cr_backlight_set_intensity,
+};
+
+static void cr_panel_on(void)
+{
+	u32 addr = gpio_bar + CRVML_PANEL_PORT;
+	u32 cur = inl(addr);
+
+	if (!(cur & CRVML_PANEL_ON)) {
+		/* Make sure LVDS controller is down. */
+		if (cur & 0x00000001) {
+			cur &= ~CRVML_LVDS_ON;
+			outl(cur, addr);
+		}
+		/* Power up Panel */
+		schedule_timeout(HZ / 10);
+		cur |= CRVML_PANEL_ON;
+		outl(cur, addr);
+	}
+
+	/* Power up LVDS controller */
+
+	if (!(cur & CRVML_LVDS_ON)) {
+		schedule_timeout(HZ / 10);
+		outl(cur | CRVML_LVDS_ON, addr);
+	}
+}
+
+static void cr_panel_off(void)
+{
+	u32 addr = gpio_bar + CRVML_PANEL_PORT;
+	u32 cur = inl(addr);
+
+	/* Power down LVDS controller first to avoid high currents */
+	if (cur & CRVML_LVDS_ON) {
+		cur &= ~CRVML_LVDS_ON;
+		outl(cur, addr);
+	}
+	if (cur & CRVML_PANEL_ON) {
+		schedule_timeout(HZ / 10);
+		outl(cur & ~CRVML_PANEL_ON, addr);
+	}
+}
+
+static int cr_lcd_set_power(struct lcd_device *ld, int power)
+{
+	if (power == FB_BLANK_UNBLANK)
+		cr_panel_on();
+	if (power == FB_BLANK_POWERDOWN)
+		cr_panel_off();
+
+	return 0;
+}
+
+static struct lcd_ops cr_lcd_ops = {
+	.set_power = cr_lcd_set_power,
+};
+
+static int cr_backlight_probe(struct platform_device *pdev)
+{
+	struct cr_panel *crp;
+	u8 dev_en;
+
+	crp = kzalloc(sizeof(crp), GFP_KERNEL);
+	if (crp == NULL)
+		return -ENOMEM;
+
+	lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					CRVML_DEVICE_LPC, NULL);
+	if (!lpc_dev) {
+		printk("INTEL CARILLO RANCH LPC not found.\n");
+		return -ENODEV;
+	}
+
+	pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en);
+	if (!(dev_en & CRVML_GPIOEN_BIT)) {
+		printk(KERN_ERR
+		       "Carillo Ranch GPIO device was not enabled.\n");
+		pci_dev_put(lpc_dev);
+		return -ENODEV;
+	}
+
+	crp->cr_backlight_device = backlight_device_register("cr-backlight",
+							     &pdev->dev, NULL,
+							     &cr_backlight_ops);
+	if (IS_ERR(crp->cr_backlight_device)) {
+		pci_dev_put(lpc_dev);
+		return PTR_ERR(crp->cr_backlight_device);
+	}
+
+	crp->cr_lcd_device = lcd_device_register("cr-lcd",
+							&pdev->dev,
+							&cr_lcd_ops);
+
+	if (IS_ERR(crp->cr_lcd_device)) {
+		pci_dev_put(lpc_dev);
+		return PTR_ERR(crp->cr_backlight_device);
+	}
+
+	pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
+			      &gpio_bar);
+	gpio_bar &= ~0x3F;
+
+	crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
+	crp->cr_backlight_device->props.brightness = 0;
+	crp->cr_backlight_device->props.max_brightness = 0;
+	cr_backlight_set_intensity(crp->cr_backlight_device);
+
+	cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
+
+	platform_set_drvdata(pdev, crp);
+
+	return 0;
+}
+
+static int cr_backlight_remove(struct platform_device *pdev)
+{
+	struct cr_panel *crp = platform_get_drvdata(pdev);
+	crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
+	crp->cr_backlight_device->props.brightness = 0;
+	crp->cr_backlight_device->props.max_brightness = 0;
+	cr_backlight_set_intensity(crp->cr_backlight_device);
+	cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN);
+	backlight_device_unregister(crp->cr_backlight_device);
+	lcd_device_unregister(crp->cr_lcd_device);
+	pci_dev_put(lpc_dev);
+
+	return 0;
+}
+
+static struct platform_driver cr_backlight_driver = {
+	.probe = cr_backlight_probe,
+	.remove = cr_backlight_remove,
+	.driver = {
+		   .name = "cr_backlight",
+		   },
+};
+
+static struct platform_device *crp;
+
+static int __init cr_backlight_init(void)
+{
+	int ret = platform_driver_register(&cr_backlight_driver);
+
+	if (!ret) {
+		crp = platform_device_alloc("cr_backlight", -1);
+		if (!crp)
+			return -ENOMEM;
+
+		ret = platform_device_add(crp);
+
+		if (ret) {
+			platform_device_put(crp);
+			platform_driver_unregister(&cr_backlight_driver);
+		}
+	}
+
+	printk("Carillo Ranch Backlight Driver Initialized.\n");
+
+	return ret;
+}
+
+static void __exit cr_backlight_exit(void)
+{
+	platform_device_unregister(crp);
+	platform_driver_unregister(&cr_backlight_driver);
+}
+
+module_init(cr_backlight_init);
+module_exit(cr_backlight_exit);
+
+MODULE_AUTHOR("Tungsten Graphics Inc.");
+MODULE_DESCRIPTION("Carillo Ranch Backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 6faea40..032210f 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -22,8 +22,6 @@
  *  help moving some redundant computations and branches out of the loop, too.
  */
 
-
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -31,6 +29,7 @@ #include <linux/fb.h>
 #include <linux/slab.h>
 #include <asm/types.h>
 #include <asm/io.h>
+#include "fb_draw.h"
 
 #if BITS_PER_LONG == 32
 #  define FB_WRITEL fb_writel
@@ -41,17 +40,6 @@ #  define FB_READL  fb_readq
 #endif
 
     /*
-     *  Compose two values, using a bitmask as decision value
-     *  This is equivalent to (a & mask) | (b & ~mask)
-     */
-
-static inline unsigned long
-comp(unsigned long a, unsigned long b, unsigned long mask)
-{
-    return ((a ^ b) & mask) ^ b;
-}
-
-    /*
      *  Generic bitwise copy algorithm
      */
 
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index f00b50a..71623b4 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -21,6 +21,7 @@ #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fb.h>
 #include <asm/types.h>
+#include "fb_draw.h"
 
 #if BITS_PER_LONG == 32
 #  define FB_WRITEL fb_writel
@@ -31,73 +32,6 @@ #  define FB_READL  fb_readq
 #endif
 
     /*
-     *  Compose two values, using a bitmask as decision value
-     *  This is equivalent to (a & mask) | (b & ~mask)
-     */
-
-static inline unsigned long
-comp(unsigned long a, unsigned long b, unsigned long mask)
-{
-    return ((a ^ b) & mask) ^ b;
-}
-
-    /*
-     *  Create a pattern with the given pixel's color
-     */
-
-#if BITS_PER_LONG == 64
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
-	switch (bpp) {
-	case 1:
-		return 0xfffffffffffffffful*pixel;
-	case 2:
-		return 0x5555555555555555ul*pixel;
-	case 4:
-		return 0x1111111111111111ul*pixel;
-	case 8:
-		return 0x0101010101010101ul*pixel;
-	case 12:
-		return 0x0001001001001001ul*pixel;
-	case 16:
-		return 0x0001000100010001ul*pixel;
-	case 24:
-		return 0x0000000001000001ul*pixel;
-	case 32:
-		return 0x0000000100000001ul*pixel;
-	default:
-		panic("pixel_to_pat(): unsupported pixelformat\n");
-    }
-}
-#else
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
-	switch (bpp) {
-	case 1:
-		return 0xfffffffful*pixel;
-	case 2:
-		return 0x55555555ul*pixel;
-	case 4:
-		return 0x11111111ul*pixel;
-	case 8:
-		return 0x01010101ul*pixel;
-	case 12:
-		return 0x00001001ul*pixel;
-	case 16:
-		return 0x00010001ul*pixel;
-	case 24:
-		return 0x00000001ul*pixel;
-	case 32:
-		return 0x00000001ul*pixel;
-	default:
-		panic("pixel_to_pat(): unsupported pixelformat\n");
-    }
-}
-#endif
-
-    /*
      *  Aligned pattern fill using 32/64-bit memory accesses
      */
 
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 767c850..f042428 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -266,7 +266,7 @@ static void __devinit cg3_init_fix(struc
 static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
 					      struct device_node *dp)
 {
-	char *params;
+	const char *params;
 	char *p;
 	int ww, hh;
 
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 2c4bc62..8269d70 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -98,15 +98,6 @@ #else
 #define assert(expr)
 #endif
 
-#ifdef TRUE
-#undef TRUE
-#endif
-#ifdef FALSE
-#undef FALSE
-#endif
-#define TRUE  1
-#define FALSE 0
-
 #define MB_ (1024*1024)
 #define KB_ (1024)
 
@@ -146,9 +137,9 @@ static const struct cirrusfb_board_info_
 	char *name;		/* ASCII name of chipset */
 	long maxclock[5];		/* maximum video clock */
 	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
-	unsigned init_sr07 : 1;	/* init SR07 during init_vgachip() */
-	unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
-	unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
+	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
+	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
+	bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
 
 	/* initial SR07 value, then for each mode */
 	unsigned char sr07;
@@ -166,9 +157,9 @@ static const struct cirrusfb_board_info_
 			/* the SD64/P4 have a higher max. videoclock */
 			140000, 140000, 140000, 140000, 140000,
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= TRUE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= true,
 		.sr07			= 0xF0,
 		.sr07_1bpp		= 0xF0,
 		.sr07_8bpp		= 0xF1,
@@ -180,9 +171,9 @@ static const struct cirrusfb_board_info_
 			/* guess */
 			90000, 90000, 90000, 90000, 90000
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= FALSE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= false,
 		.sr07			= 0x80,
 		.sr07_1bpp		= 0x80,
 		.sr07_8bpp		= 0x81,
@@ -194,9 +185,9 @@ static const struct cirrusfb_board_info_
 			/* guess */
 			90000, 90000, 90000, 90000, 90000
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= FALSE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= false,
 		.sr07			= 0x20,
 		.sr07_1bpp		= 0x20,
 		.sr07_8bpp		= 0x21,
@@ -208,9 +199,9 @@ static const struct cirrusfb_board_info_
 			/* guess */
 			90000, 90000, 90000, 90000, 90000
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= FALSE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= false,
 		.sr07			= 0x80,
 		.sr07_1bpp		= 0x80,
 		.sr07_8bpp		= 0x81,
@@ -221,9 +212,9 @@ static const struct cirrusfb_board_info_
 		.maxclock		= {
 			135100, 135100, 85500, 85500, 0
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= FALSE,
-		.scrn_start_bit19	= TRUE,
+		.init_sr07		= true,
+		.init_sr1f		= false,
+		.scrn_start_bit19	= true,
 		.sr07			= 0x20,
 		.sr07_1bpp		= 0x20,
 		.sr07_8bpp		= 0x21,
@@ -235,9 +226,9 @@ static const struct cirrusfb_board_info_
 			/* for the GD5430.  GD5446 can do more... */
 			85500, 85500, 50000, 28500, 0
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= TRUE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= true,
 		.sr07			= 0xA0,
 		.sr07_1bpp		= 0xA1,
 		.sr07_1bpp_mux		= 0xA7,
@@ -250,9 +241,9 @@ static const struct cirrusfb_board_info_
 		.maxclock		= {
 			135100, 200000, 200000, 135100, 135100
 		},
-		.init_sr07		= TRUE,
-		.init_sr1f		= TRUE,
-		.scrn_start_bit19	= TRUE,
+		.init_sr07		= true,
+		.init_sr1f		= true,
+		.scrn_start_bit19	= true,
 		.sr07			= 0x10,
 		.sr07_1bpp		= 0x11,
 		.sr07_8bpp		= 0x11,
@@ -264,9 +255,9 @@ static const struct cirrusfb_board_info_
 			/* guess */
 			135100, 135100, 135100, 135100, 135100,
 		},
-		.init_sr07		= FALSE,
-		.init_sr1f		= FALSE,
-		.scrn_start_bit19	= TRUE,
+		.init_sr07		= false,
+		.init_sr1f		= false,
+		.scrn_start_bit19	= true,
 	}
 };
 
@@ -815,7 +806,7 @@ static int cirrusfb_check_var(struct fb_
 
 	default:
 		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
-		assert (FALSE);
+		assert(false);
 		/* should never occur */
 		break;
 	}
@@ -886,7 +877,7 @@ static int cirrusfb_decode_var (const st
 
 	default:
 		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
-		assert (FALSE);
+		assert(false);
 		/* should never occur */
 		break;
 	}
@@ -3203,7 +3194,7 @@ void cirrusfb_dbg_print_regs (caddr_t re
 			break;
 		default:
 			/* should never occur */
-			assert (FALSE);
+			assert(false);
 			break;
 		}
 
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0429fd2..73813c6 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,7 +107,9 @@ static struct display fb_display[MAX_NR_
 
 static signed char con2fb_map[MAX_NR_CONSOLES];
 static signed char con2fb_map_boot[MAX_NR_CONSOLES];
+#ifndef MODULE
 static int logo_height;
+#endif
 static int logo_lines;
 /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
    enums.  */
@@ -576,6 +578,13 @@ static int fbcon_takeover(int show_logo)
 	return err;
 }
 
+#ifdef MODULE
+static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+			       int cols, int rows, int new_cols, int new_rows)
+{
+	logo_shown = FBCON_LOGO_DONTSHOW;
+}
+#else
 static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
 			       int cols, int rows, int new_cols, int new_rows)
 {
@@ -584,6 +593,11 @@ static void fbcon_prepare_logo(struct vc
 	int cnt, erase = vc->vc_video_erase_char, step;
 	unsigned short *save = NULL, *r, *q;
 
+	if (info->flags & FBINFO_MODULE) {
+		logo_shown = FBCON_LOGO_DONTSHOW;
+		return;
+	}
+
 	/*
 	 * remove underline attribute from erase character
 	 * if black and white framebuffer.
@@ -618,8 +632,13 @@ static void fbcon_prepare_logo(struct vc
 			r -= cols;
 		}
 		if (!save) {
-			vc->vc_y += logo_lines;
-			vc->vc_pos += logo_lines * vc->vc_size_row;
+			int lines;
+			if (vc->vc_y + logo_lines >= rows)
+				lines = rows - vc->vc_y - 1;
+			else
+				lines = logo_lines;
+			vc->vc_y += lines;
+			vc->vc_pos += lines * vc->vc_size_row;
 		}
 	}
 	scr_memsetw((unsigned short *) vc->vc_origin,
@@ -650,6 +669,7 @@ static void fbcon_prepare_logo(struct vc
 		vc->vc_top = logo_lines;
 	}
 }
+#endif /* MODULE */
 
 #ifdef CONFIG_FB_TILEBLITTING
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
@@ -665,6 +685,17 @@ static void set_blitting_type(struct vc_
 		fbcon_set_bitops(ops);
 	}
 }
+
+static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+{
+	int err = 0;
+
+	if (info->flags & FBINFO_MISC_TILEBLITTING &&
+	    info->tileops->fb_get_tilemax(info) < charcount)
+		err = 1;
+
+	return err;
+}
 #else
 static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
 {
@@ -675,6 +706,12 @@ static void set_blitting_type(struct vc_
 	fbcon_set_rotation(info);
 	fbcon_set_bitops(ops);
 }
+
+static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+{
+	return 0;
+}
+
 #endif /* CONFIG_MISC_TILEBLITTING */
 
 
@@ -968,7 +1005,9 @@ static const char *fbcon_startup(void)
 	if (!p->fontdata) {
 		if (!fontname[0] || !(font = find_font(fontname)))
 			font = get_default_font(info->var.xres,
-						info->var.yres);
+						info->var.yres,
+						info->pixmap.blit_x,
+						info->pixmap.blit_y);
 		vc->vc_font.width = font->width;
 		vc->vc_font.height = font->height;
 		vc->vc_font.data = (void *)(p->fontdata = font->data);
@@ -1088,7 +1127,9 @@ static void fbcon_init(struct vc_data *v
 
 			if (!fontname[0] || !(font = find_font(fontname)))
 				font = get_default_font(info->var.xres,
-							info->var.yres);
+							info->var.yres,
+							info->pixmap.blit_x,
+							info->pixmap.blit_y);
 			vc->vc_font.width = font->width;
 			vc->vc_font.height = font->height;
 			vc->vc_font.data = (void *)(p->fontdata = font->data);
@@ -1305,7 +1346,7 @@ static void fbcon_cursor(struct vc_data 
 	int y;
  	int c = scr_readw((u16 *) vc->vc_pos);
 
-	if (fbcon_is_inactive(vc, info))
+	if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
 		return;
 
 	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
@@ -2475,6 +2516,7 @@ static int fbcon_copy_font(struct vc_dat
 
 static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags)
 {
+	struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
 	unsigned charcount = font->charcount;
 	int w = font->width;
 	int h = font->height;
@@ -2488,6 +2530,15 @@ static int fbcon_set_font(struct vc_data
 	if (charcount != 256 && charcount != 512)
 		return -EINVAL;
 
+	/* Make sure drawing engine can handle the font */
+	if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
+	    !(info->pixmap.blit_y & (1 << (font->height - 1))))
+		return -EINVAL;
+
+	/* Make sure driver can handle the font length */
+	if (fbcon_invalid_charcount(info, charcount))
+		return -EINVAL;
+
 	size = h * pitch * charcount;
 
 	new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
@@ -2532,7 +2583,8 @@ static int fbcon_set_def_font(struct vc_
 	const struct font_desc *f;
 
 	if (!name)
-		f = get_default_font(info->var.xres, info->var.yres);
+		f = get_default_font(info->var.xres, info->var.yres,
+				     info->pixmap.blit_x, info->pixmap.blit_y);
 	else if (!(f = find_font(name)))
 		return -ENOENT;
 
@@ -2829,7 +2881,7 @@ static void fbcon_set_all_vcs(struct fb_
 	struct fbcon_ops *ops = info->fbcon_par;
 	struct vc_data *vc;
 	struct display *p;
-	int i, rows, cols;
+	int i, rows, cols, fg = -1;
 
 	if (!ops || ops->currcon < 0)
 		return;
@@ -2840,34 +2892,23 @@ static void fbcon_set_all_vcs(struct fb_
 		    registered_fb[con2fb_map[i]] != info)
 			continue;
 
+		if (CON_IS_VISIBLE(vc)) {
+			fg = i;
+			continue;
+		}
+
 		p = &fb_display[vc->vc_num];
 		set_blitting_type(vc, info);
 		var_to_display(p, &info->var, info);
-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+		cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres);
+		rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres);
 		cols /= vc->vc_font.width;
 		rows /= vc->vc_font.height;
 		vc_resize(vc, cols, rows);
-
-		if (CON_IS_VISIBLE(vc)) {
-			updatescrollmode(p, info, vc);
-			scrollback_max = 0;
-			scrollback_current = 0;
-
-			if (!fbcon_is_inactive(vc, info)) {
-			    ops->var.xoffset = ops->var.yoffset =
-				p->yscroll = 0;
-			    ops->update_start(info);
-			}
-
-			fbcon_set_palette(vc, color_table);
-			update_screen(vc);
-			if (softback_buf)
-				fbcon_update_softback(vc);
-		}
 	}
 
-	ops->p = &fb_display[ops->currcon];
+	if (fg != -1)
+		fbcon_modechanged(info);
 }
 
 static int fbcon_mode_deleted(struct fb_info *info,
@@ -3002,6 +3043,42 @@ static void fbcon_new_modelist(struct fb
 	}
 }
 
+static void fbcon_get_requirement(struct fb_info *info,
+				  struct fb_blit_caps *caps)
+{
+	struct vc_data *vc;
+	struct display *p;
+
+	if (caps->flags) {
+		int i, charcnt;
+
+		for (i = first_fb_vc; i <= last_fb_vc; i++) {
+			vc = vc_cons[i].d;
+			if (vc && vc->vc_mode == KD_TEXT &&
+			    info->node == con2fb_map[i]) {
+				p = &fb_display[i];
+				caps->x |= 1 << (vc->vc_font.width - 1);
+				caps->y |= 1 << (vc->vc_font.height - 1);
+				charcnt = (p->userfont) ?
+					FNTCHARCNT(p->fontdata) : 256;
+				if (caps->len < charcnt)
+					caps->len = charcnt;
+			}
+		}
+	} else {
+		vc = vc_cons[fg_console].d;
+
+		if (vc && vc->vc_mode == KD_TEXT &&
+		    info->node == con2fb_map[fg_console]) {
+			p = &fb_display[fg_console];
+			caps->x = 1 << (vc->vc_font.width - 1);
+			caps->y = 1 << (vc->vc_font.height - 1);
+			caps->len = (p->userfont) ?
+				FNTCHARCNT(p->fontdata) : 256;
+		}
+	}
+}
+
 static int fbcon_event_notify(struct notifier_block *self, 
 			      unsigned long action, void *data)
 {
@@ -3009,6 +3086,7 @@ static int fbcon_event_notify(struct not
 	struct fb_info *info = event->info;
 	struct fb_videomode *mode;
 	struct fb_con2fbmap *con2fb;
+	struct fb_blit_caps *caps;
 	int ret = 0;
 
 	/*
@@ -3057,6 +3135,10 @@ static int fbcon_event_notify(struct not
 	case FB_EVENT_NEW_MODELIST:
 		fbcon_new_modelist(info);
 		break;
+	case FB_EVENT_GET_REQ:
+		caps = event->data;
+		fbcon_get_requirement(info, caps);
+		break;
 	}
 
 done:
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index c960728..a6828d0 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -98,6 +98,8 @@ const struct font_desc *find_font(const 
  *	get_default_font - get default font
  *	@xres: screen size of X
  *	@yres: screen size of Y
+ *      @font_w: bit array of supported widths (1 - 32)
+ *      @font_h: bit array of supported heights (1 - 32)
  *
  *	Get the default font for a specified screen size.
  *	Dimensions are in pixels.
@@ -107,7 +109,8 @@ const struct font_desc *find_font(const 
  *
  */
 
-const struct font_desc *get_default_font(int xres, int yres)
+const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
+					 u32 font_h)
 {
     int i, c, cc;
     const struct font_desc *f, *g;
@@ -129,6 +132,11 @@ #endif
 #endif
 	if ((yres < 400) == (f->height <= 8))
 	    c += 1000;
+
+	if (!(font_w & (1 << (f->width - 1))) ||
+	    !(font_w & (1 << (f->height - 1))))
+	    c += 1000;
+
 	if (c > cc) {
 	    cc = c;
 	    g = f;
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 124ecbe..bd8d995 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -384,7 +384,7 @@ static inline u16 mda_convert_attr(u16 c
 }
 
 static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity, 
-			    u8 blink, u8 underline, u8 reverse)
+			    u8 blink, u8 underline, u8 reverse, u8 italic)
 {
 	/* The attribute is just a bit vector:
 	 *
@@ -397,6 +397,7 @@ static u8 mdacon_build_attr(struct vc_da
 	return (intensity & 3) |
 		((underline & 1) << 2) |
 		((reverse   & 1) << 3) |
+		(!!italic << 4) |
 		((blink     & 1) << 7);
 }
 
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
index b78eac6..ae02e4e 100644
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -548,7 +548,8 @@ promcon_scroll(struct vc_data *conp, int
 }
 
 #if !(PROMCON_COLOR)
-static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity,
+    u8 _blink, u8 _underline, u8 _reverse, u8 _italic)
 {
 	return (_reverse) ? 0xf : 0x7;
 }
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 57b21e5..67a682d 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -314,7 +314,7 @@ static unsigned long sticon_getxy(struct
 }
 
 static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
-			    u8 blink, u8 underline, u8 reverse)
+			    u8 blink, u8 underline, u8 reverse, u8 italic)
 {
     u8 attr = ((color & 0x70) >> 1) | ((color & 7));
 
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 88e7038..717b360 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -495,7 +495,7 @@ sti_select_fbfont(struct sti_cooked_rom 
 		return NULL;
 	fbfont = find_font(fbfont_name);
 	if (!fbfont)
-		fbfont = get_default_font(1024,768);
+		fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0);
 	if (!fbfont)
 		return NULL;
 
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 91a2078..2460b82 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -86,8 +86,6 @@ static int vgacon_set_origin(struct vc_d
 static void vgacon_save_screen(struct vc_data *c);
 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
 			 int lines);
-static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
-			    u8 blink, u8 underline, u8 reverse);
 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
 static unsigned long vgacon_uni_pagedir[2];
 
@@ -371,7 +369,8 @@ #endif
 	}
 
 	/* VGA16 modes are not handled by VGACON */
-	if ((ORIG_VIDEO_MODE == 0x0D) ||	/* 320x200/4 */
+	if ((ORIG_VIDEO_MODE == 0x00) ||	/* SCREEN_INFO not initialized */
+	    (ORIG_VIDEO_MODE == 0x0D) ||	/* 320x200/4 */
 	    (ORIG_VIDEO_MODE == 0x0E) ||	/* 640x200/4 */
 	    (ORIG_VIDEO_MODE == 0x10) ||	/* 640x350/4 */
 	    (ORIG_VIDEO_MODE == 0x12) ||	/* 640x480/4 */
@@ -577,12 +576,14 @@ static void vgacon_deinit(struct vc_data
 }
 
 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
-			    u8 blink, u8 underline, u8 reverse)
+			    u8 blink, u8 underline, u8 reverse, u8 italic)
 {
 	u8 attr = color;
 
 	if (vga_can_do_color) {
-		if (underline)
+		if (italic)
+			attr = (attr & 0xF0) | c->vc_itcolor;
+		else if (underline)
 			attr = (attr & 0xf0) | c->vc_ulcolor;
 		else if (intensity == 0)
 			attr = (attr & 0xf0) | c->vc_halfcolor;
@@ -596,7 +597,9 @@ static u8 vgacon_build_attr(struct vc_da
 	if (intensity == 2)
 		attr ^= 0x08;
 	if (!vga_can_do_color) {
-		if (underline)
+		if (italic)
+			attr = (attr & 0xF8) | 0x02;
+		else if (underline)
 			attr = (attr & 0xf8) | 0x01;
 		else if (intensity == 0)
 			attr = (attr & 0xf0) | 0x08;
@@ -657,6 +660,9 @@ #endif
 
 static void vgacon_cursor(struct vc_data *c, int mode)
 {
+	if (c->vc_mode != KD_TEXT)
+		return;
+
 	vgacon_restore_screen(c);
 
 	switch (mode) {
@@ -1315,7 +1321,7 @@ static int vgacon_scroll(struct vc_data 
 	unsigned long oldo;
 	unsigned int delta;
 
-	if (t || b != c->vc_rows || vga_is_gfx)
+	if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
 		return 0;
 
 	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index fd60dba..8b76273 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -179,12 +179,14 @@ MODULE_LICENSE("GPL");
 int init_module(void)
 {
 	struct device_node *dp;
+	int ret = -ENXIO;
 
-	dp = find_devices("control");
+	dp = of_find_node_by_name(NULL, "control");
 	if (dp != 0 && !control_of_init(dp))
-		return 0;
+		ret = 0;
+	of_node_put(dp);
 
-	return -ENXIO;
+	return ret;
 }
 
 void cleanup_module(void)
@@ -589,16 +591,18 @@ static int __init control_init(void)
 {
 	struct device_node *dp;
 	char *option = NULL;
+	int ret = -ENXIO;
 
 	if (fb_get_options("controlfb", &option))
 		return -ENODEV;
 	control_setup(option);
 
-	dp = find_devices("control");
+	dp = of_find_node_by_name(NULL, "control");
 	if (dp != 0 && !control_of_init(dp))
-		return 0;
+		ret = 0;
+	of_node_put(dp);
 
-	return -ENXIO;
+	return ret;
 }
 
 module_init(control_init);
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
new file mode 100644
index 0000000..f99af93
--- /dev/null
+++ b/drivers/video/display/Kconfig
@@ -0,0 +1,24 @@
+#
+# Display drivers configuration
+#
+
+menu "Display device support"
+
+config DISPLAY_SUPPORT
+	tristate "Display panel/monitor support"
+	---help---
+	  This framework adds support for low-level control of a display.
+	  This includes support for power.
+
+	  Enable this to be able to choose the drivers for controlling the
+	  physical display panel/monitor on some platforms. This not only
+	  covers LCD displays for PDAs but also other types of displays
+	  such as CRT, TVout etc.
+
+	  To have support for your specific display panel you will have to
+	  select the proper drivers which depend on this option.
+
+comment "Display hardware drivers"
+	depends on DISPLAY_SUPPORT
+
+endmenu
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
new file mode 100644
index 0000000..c0ea832
--- /dev/null
+++ b/drivers/video/display/Makefile
@@ -0,0 +1,6 @@
+# Display drivers
+
+display-objs				:= display-sysfs.o
+
+obj-$(CONFIG_DISPLAY_SUPPORT)		+= display.o
+
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
new file mode 100644
index 0000000..3547717
--- /dev/null
+++ b/drivers/video/display/display-sysfs.c
@@ -0,0 +1,217 @@
+/*
+ *  display-sysfs.c - Display output driver sysfs interface
+ *
+ *  Copyright (C) 2007 James Simmons <jsimmons@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.
+ *
+ *  You 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/display.h>
+#include <linux/ctype.h>
+#include <linux/idr.h>
+#include <linux/err.h>
+
+static ssize_t display_show_name(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
+}
+
+static ssize_t display_show_type(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+	return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
+}
+
+static ssize_t display_show_contrast(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+	ssize_t rc = -ENXIO;
+
+	mutex_lock(&dsp->lock);
+	if (likely(dsp->driver) && dsp->driver->get_contrast)
+		rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp));
+	mutex_unlock(&dsp->lock);
+	return rc;
+}
+
+static ssize_t display_store_contrast(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+	ssize_t ret = -EINVAL, size;
+	int contrast;
+	char *endp;
+
+	contrast = simple_strtoul(buf, &endp, 0);
+	size = endp - buf;
+
+	if (*endp && isspace(*endp))
+		size++;
+
+	if (size != count)
+		return ret;
+
+	mutex_lock(&dsp->lock);
+	if (likely(dsp->driver && dsp->driver->set_contrast)) {
+		pr_debug("display: set contrast to %d\n", contrast);
+		dsp->driver->set_contrast(dsp, contrast);
+		ret = count;
+	}
+	mutex_unlock(&dsp->lock);
+	return ret;
+}
+
+static ssize_t display_show_max_contrast(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+	ssize_t rc = -ENXIO;
+
+	mutex_lock(&dsp->lock);
+	if (likely(dsp->driver))
+		rc = sprintf(buf, "%d\n", dsp->driver->max_contrast);
+	mutex_unlock(&dsp->lock);
+	return rc;
+}
+
+static struct device_attribute display_attrs[] = {
+	__ATTR(name, S_IRUGO, display_show_name, NULL),
+	__ATTR(type, S_IRUGO, display_show_type, NULL),
+	__ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast),
+	__ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL),
+};
+
+static int display_suspend(struct device *dev, pm_message_t state)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+
+	mutex_lock(&dsp->lock);
+	if (likely(dsp->driver->suspend))
+		dsp->driver->suspend(dsp, state);
+	mutex_unlock(&dsp->lock);
+	return 0;
+};
+
+static int display_resume(struct device *dev)
+{
+	struct display_device *dsp = dev_get_drvdata(dev);
+
+	mutex_lock(&dsp->lock);
+	if (likely(dsp->driver->resume))
+		dsp->driver->resume(dsp);
+	mutex_unlock(&dsp->lock);
+	return 0;
+};
+
+static struct mutex allocated_dsp_lock;
+static DEFINE_IDR(allocated_dsp);
+static struct class *display_class;
+
+struct display_device *display_device_register(struct display_driver *driver,
+						struct device *parent, void *devdata)
+{
+	struct display_device *new_dev = NULL;
+	int ret = -EINVAL;
+
+	if (unlikely(!driver))
+		return ERR_PTR(ret);
+
+	mutex_lock(&allocated_dsp_lock);
+	ret = idr_pre_get(&allocated_dsp, GFP_KERNEL);
+	mutex_unlock(&allocated_dsp_lock);
+	if (!ret)
+		return ERR_PTR(ret);
+
+	new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL);
+	if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
+		// Reserve the index for this display
+		mutex_lock(&allocated_dsp_lock);
+		ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx);
+		mutex_unlock(&allocated_dsp_lock);
+
+		if (!ret) {
+			new_dev->dev = device_create(display_class, parent, 0,
+						"display%d", new_dev->idx);
+			if (!IS_ERR(new_dev->dev)) {
+				dev_set_drvdata(new_dev->dev, new_dev);
+				new_dev->parent = parent;
+				new_dev->driver = driver;
+				mutex_init(&new_dev->lock);
+				return new_dev;
+			}
+			mutex_lock(&allocated_dsp_lock);
+			idr_remove(&allocated_dsp, new_dev->idx);
+			mutex_unlock(&allocated_dsp_lock);
+			ret = -EINVAL;
+		}
+	}
+	kfree(new_dev);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(display_device_register);
+
+void display_device_unregister(struct display_device *ddev)
+{
+	if (!ddev)
+		return;
+	// Free device
+	mutex_lock(&ddev->lock);
+	device_unregister(ddev->dev);
+	mutex_unlock(&ddev->lock);
+	// Mark device index as avaliable
+	mutex_lock(&allocated_dsp_lock);
+	idr_remove(&allocated_dsp, ddev->idx);
+	mutex_unlock(&allocated_dsp_lock);
+	kfree(ddev);
+}
+EXPORT_SYMBOL(display_device_unregister);
+
+static int __init display_class_init(void)
+{
+	display_class = class_create(THIS_MODULE, "display");
+	if (IS_ERR(display_class)) {
+		printk(KERN_ERR "Failed to create display class\n");
+		display_class = NULL;
+		return -EINVAL;
+	}
+	display_class->dev_attrs = display_attrs;
+	display_class->suspend = display_suspend;
+	display_class->resume = display_resume;
+	mutex_init(&allocated_dsp_lock);
+	return 0;
+}
+
+static void __exit display_class_exit(void)
+{
+	class_destroy(display_class);
+}
+
+module_init(display_class_init);
+module_exit(display_class_exit);
+
+MODULE_DESCRIPTION("Display Hardware handling");
+MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 29e07c1..ca2c54c 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -403,17 +403,10 @@ static inline unsigned long copy_to_user
 
 
 static ssize_t
-epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+epson1355fb_read(struct fb_info *info, char *buf, size_t count, loff_t * ppos)
 {
-	struct inode *inode = file->f_path.dentry->d_inode;
-	int fbidx = iminor(inode);
-	struct fb_info *info = registered_fb[fbidx];
 	unsigned long p = *ppos;
 
-	/* from fbmem.c except for our own copy_*_user */
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
 	if (p >= info->fix.smem_len)
 		return 0;
 	if (count >= info->fix.smem_len)
@@ -434,20 +427,13 @@ epson1355fb_read(struct file *file, char
 }
 
 static ssize_t
-epson1355fb_write(struct file *file, const char *buf,
+epson1355fb_write(struct fb_info *info, const char *buf,
 		  size_t count, loff_t * ppos)
 {
-	struct inode *inode = file->f_path.dentry->d_inode;
-	int fbidx = iminor(inode);
-	struct fb_info *info = registered_fb[fbidx];
 	unsigned long p = *ppos;
 	int err;
 
 	/* from fbmem.c except for our own copy_*_user */
-	if (!info || !info->screen_base)
-		return -ENODEV;
-
-	/* from fbmem.c except for our own copy_*_user */
 	if (p > info->fix.smem_len)
 		return -ENOSPC;
 	if (count >= info->fix.smem_len)
@@ -650,9 +636,10 @@ int __init epson1355fb_probe(struct plat
 	}
 
 	info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev);
-	if (!info)
+	if (!info) {
 		rc = -ENOMEM;
 		goto bail;
+	}
 
 	default_par = info->par;
 	default_par->reg_addr = (unsigned long) ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
new file mode 100644
index 0000000..1a8643f
--- /dev/null
+++ b/drivers/video/fb_defio.c
@@ -0,0 +1,151 @@
+/*
+ *  linux/drivers/video/fb_defio.c
+ *
+ *  Copyright (C) 2006 Jaya Kumar
+ *
+ * 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/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+/* to support deferred IO */
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
+
+/* this is to find and return the vmalloc-ed fb pages */
+static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
+					unsigned long vaddr, int *type)
+{
+	unsigned long offset;
+	struct page *page;
+	struct fb_info *info = vma->vm_private_data;
+	/* info->screen_base is in System RAM */
+	void *screen_base = (void __force *) info->screen_base;
+
+	offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+	if (offset >= info->fix.smem_len)
+		return NOPAGE_SIGBUS;
+
+	page = vmalloc_to_page(screen_base + offset);
+	if (!page)
+		return NOPAGE_OOM;
+
+	get_page(page);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return page;
+}
+
+int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct fb_info *info = file->private_data;
+
+	/* Kill off the delayed work */
+	cancel_rearming_delayed_work(&info->deferred_work);
+
+	/* Run it immediately */
+	return schedule_delayed_work(&info->deferred_work, 0);
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
+
+/* vm_ops->page_mkwrite handler */
+static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
+				  struct page *page)
+{
+	struct fb_info *info = vma->vm_private_data;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	/* this is a callback we get when userspace first tries to
+	write to the page. we schedule a workqueue. that workqueue
+	will eventually mkclean the touched pages and execute the
+	deferred framebuffer IO. then if userspace touches a page
+	again, we repeat the same scheme */
+
+	/* protect against the workqueue changing the page list */
+	mutex_lock(&fbdefio->lock);
+	list_add(&page->lru, &fbdefio->pagelist);
+	mutex_unlock(&fbdefio->lock);
+
+	/* come back after delay to process the deferred IO */
+	schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+	return 0;
+}
+
+static struct vm_operations_struct fb_deferred_io_vm_ops = {
+	.nopage   	= fb_deferred_io_nopage,
+	.page_mkwrite	= fb_deferred_io_mkwrite,
+};
+
+static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	vma->vm_ops = &fb_deferred_io_vm_ops;
+	vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );
+	vma->vm_private_data = info;
+	return 0;
+}
+
+/* workqueue callback */
+static void fb_deferred_io_work(struct work_struct *work)
+{
+	struct fb_info *info = container_of(work, struct fb_info,
+						deferred_work.work);
+	struct list_head *node, *next;
+	struct page *cur;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	/* here we mkclean the pages, then do all deferred IO */
+	mutex_lock(&fbdefio->lock);
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+		lock_page(cur);
+		page_mkclean(cur);
+		unlock_page(cur);
+	}
+
+	/* driver's callback with pagelist */
+	fbdefio->deferred_io(info, &fbdefio->pagelist);
+
+	/* clear the list */
+	list_for_each_safe(node, next, &fbdefio->pagelist) {
+		list_del(node);
+	}
+	mutex_unlock(&fbdefio->lock);
+}
+
+void fb_deferred_io_init(struct fb_info *info)
+{
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	BUG_ON(!fbdefio);
+	mutex_init(&fbdefio->lock);
+	info->fbops->fb_mmap = fb_deferred_io_mmap;
+	INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
+	INIT_LIST_HEAD(&fbdefio->pagelist);
+	if (fbdefio->delay == 0) /* set a default of 1 s */
+		fbdefio->delay = HZ;
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_init);
+
+void fb_deferred_io_cleanup(struct fb_info *info)
+{
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+
+	BUG_ON(!fbdefio);
+	cancel_delayed_work(&info->deferred_work);
+	flush_scheduled_work();
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
new file mode 100644
index 0000000..c5c4520
--- /dev/null
+++ b/drivers/video/fb_draw.h
@@ -0,0 +1,72 @@
+#ifndef _FB_DRAW_H
+#define _FB_DRAW_H
+
+#include <asm/types.h>
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+    return ((a ^ b) & mask) ^ b;
+}
+
+    /*
+     *  Create a pattern with the given pixel's color
+     */
+
+#if BITS_PER_LONG == 64
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+	switch (bpp) {
+	case 1:
+		return 0xfffffffffffffffful*pixel;
+	case 2:
+		return 0x5555555555555555ul*pixel;
+	case 4:
+		return 0x1111111111111111ul*pixel;
+	case 8:
+		return 0x0101010101010101ul*pixel;
+	case 12:
+		return 0x0001001001001001ul*pixel;
+	case 16:
+		return 0x0001000100010001ul*pixel;
+	case 24:
+		return 0x0000000001000001ul*pixel;
+	case 32:
+		return 0x0000000100000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
+    }
+}
+#else
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+	switch (bpp) {
+	case 1:
+		return 0xfffffffful*pixel;
+	case 2:
+		return 0x55555555ul*pixel;
+	case 4:
+		return 0x11111111ul*pixel;
+	case 8:
+		return 0x01010101ul*pixel;
+	case 12:
+		return 0x00001001ul*pixel;
+	case 16:
+		return 0x00010001ul*pixel;
+	case 24:
+		return 0x00000001ul*pixel;
+	case 32:
+		return 0x00000001ul*pixel;
+	default:
+		panic("pixel_to_pat(): unsupported pixelformat\n");
+    }
+}
+#endif
+#endif /* FB_DRAW_H */
diff --git a/drivers/video/fb_sys_fops.c b/drivers/video/fb_sys_fops.c
new file mode 100644
index 0000000..cf2538d
--- /dev/null
+++ b/drivers/video/fb_sys_fops.c
@@ -0,0 +1,104 @@
+/*
+ * linux/drivers/video/fb_sys_read.c - Generic file operations where
+ * framebuffer is in system RAM
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * 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/fb.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
+		    loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	void *src;
+	int err = 0;
+	unsigned long total_size;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p >= total_size)
+		return 0;
+
+	if (count >= total_size)
+		count = total_size;
+
+	if (count + p > total_size)
+		count = total_size - p;
+
+	src = (void __force *)(info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	if (copy_to_user(buf, src, count))
+		err = -EFAULT;
+
+	if  (!err)
+		*ppos += count;
+
+	return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_read);
+
+ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
+		     size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	void *dst;
+	int err = 0;
+	unsigned long total_size;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return -EPERM;
+
+	total_size = info->screen_size;
+
+	if (total_size == 0)
+		total_size = info->fix.smem_len;
+
+	if (p > total_size)
+		return -EFBIG;
+
+	if (count > total_size) {
+		err = -EFBIG;
+		count = total_size;
+	}
+
+	if (count + p > total_size) {
+		if (!err)
+			err = -ENOSPC;
+
+		count = total_size - p;
+	}
+
+	dst = (void __force *) (info->screen_base + p);
+
+	if (info->fbops->fb_sync)
+		info->fbops->fb_sync(info);
+
+	if (copy_from_user(dst, buf, count))
+		err = -EFAULT;
+
+	if  (!err)
+		*ppos += count;
+
+	return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_write);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic file read (fb in system RAM)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 2822526..08d4e11 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -354,59 +354,59 @@ static void fb_rotate_logo(struct fb_inf
 	if (rotate == FB_ROTATE_UD) {
 		fb_rotate_logo_ud(image->data, dst, image->width,
 				  image->height);
-		image->dx = info->var.xres - image->width;
-		image->dy = info->var.yres - image->height;
+		image->dx = info->var.xres - image->width - image->dx;
+		image->dy = info->var.yres - image->height - image->dy;
 	} else if (rotate == FB_ROTATE_CW) {
 		fb_rotate_logo_cw(image->data, dst, image->width,
 				  image->height);
 		tmp = image->width;
 		image->width = image->height;
 		image->height = tmp;
-		image->dx = info->var.xres - image->width;
+		tmp = image->dy;
+		image->dy = image->dx;
+		image->dx = info->var.xres - image->width - tmp;
 	} else if (rotate == FB_ROTATE_CCW) {
 		fb_rotate_logo_ccw(image->data, dst, image->width,
 				   image->height);
 		tmp = image->width;
 		image->width = image->height;
 		image->height = tmp;
-		image->dy = info->var.yres - image->height;
+		tmp = image->dx;
+		image->dx = image->dy;
+		image->dy = info->var.yres - image->height - tmp;
 	}
 
 	image->data = dst;
 }
 
 static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
-			    int rotate)
+			    int rotate, unsigned int num)
 {
-	int x;
+	unsigned int x;
 
 	if (rotate == FB_ROTATE_UR) {
-		for (x = 0; x < num_online_cpus() &&
-			     x * (fb_logo.logo->width + 8) <=
-			     info->var.xres - fb_logo.logo->width; x++) {
+		for (x = 0;
+		     x < num && image->dx + image->width <= info->var.xres;
+		     x++) {
 			info->fbops->fb_imageblit(info, image);
-			image->dx += fb_logo.logo->width + 8;
+			image->dx += image->width + 8;
 		}
 	} else if (rotate == FB_ROTATE_UD) {
-		for (x = 0; x < num_online_cpus() &&
-			     x * (fb_logo.logo->width + 8) <=
-			     info->var.xres - fb_logo.logo->width; x++) {
+		for (x = 0; x < num && image->dx >= 0; x++) {
 			info->fbops->fb_imageblit(info, image);
-			image->dx -= fb_logo.logo->width + 8;
+			image->dx -= image->width + 8;
 		}
 	} else if (rotate == FB_ROTATE_CW) {
-		for (x = 0; x < num_online_cpus() &&
-			     x * (fb_logo.logo->width + 8) <=
-			     info->var.yres - fb_logo.logo->width; x++) {
+		for (x = 0;
+		     x < num && image->dy + image->height <= info->var.yres;
+		     x++) {
 			info->fbops->fb_imageblit(info, image);
-			image->dy += fb_logo.logo->width + 8;
+			image->dy += image->height + 8;
 		}
 	} else if (rotate == FB_ROTATE_CCW) {
-		for (x = 0; x < num_online_cpus() &&
-			     x * (fb_logo.logo->width + 8) <=
-			     info->var.yres - fb_logo.logo->width; x++) {
+		for (x = 0; x < num && image->dy >= 0; x++) {
 			info->fbops->fb_imageblit(info, image);
-			image->dy -= fb_logo.logo->width + 8;
+			image->dy -= image->height + 8;
 		}
 	}
 }
@@ -418,7 +418,8 @@ int fb_prepare_logo(struct fb_info *info
 
 	memset(&fb_logo, 0, sizeof(struct logo_data));
 
-	if (info->flags & FBINFO_MISC_TILEBLITTING)
+	if (info->flags & FBINFO_MISC_TILEBLITTING ||
+	    info->flags & FBINFO_MODULE)
 		return 0;
 
 	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
@@ -483,7 +484,8 @@ int fb_show_logo(struct fb_info *info, i
 	struct fb_image image;
 
 	/* Return if the frame buffer is not mapped or suspended */
-	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
+	if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+	    info->flags & FBINFO_MODULE)
 		return 0;
 
 	image.depth = 8;
@@ -532,7 +534,7 @@ int fb_show_logo(struct fb_info *info, i
 			fb_rotate_logo(info, logo_rotate, &image, rotate);
 	}
 
-	fb_do_show_logo(info, &image, rotate);
+	fb_do_show_logo(info, &image, rotate, num_online_cpus());
 
 	kfree(palette);
 	if (saved_pseudo_palette != NULL)
@@ -586,7 +588,7 @@ fb_read(struct file *file, char __user *
 		return -EPERM;
 
 	if (info->fbops->fb_read)
-		return info->fbops->fb_read(file, buf, count, ppos);
+		return info->fbops->fb_read(info, buf, count, ppos);
 	
 	total_size = info->screen_size;
 
@@ -661,7 +663,7 @@ fb_write(struct file *file, const char _
 		return -EPERM;
 
 	if (info->fbops->fb_write)
-		return info->fbops->fb_write(file, buf, count, ppos);
+		return info->fbops->fb_write(info, buf, count, ppos);
 	
 	total_size = info->screen_size;
 
@@ -771,14 +773,37 @@ fb_pan_display(struct fb_info *info, str
         return 0;
 }
 
+static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
+			 u32 activate)
+{
+	struct fb_event event;
+	struct fb_blit_caps caps, fbcaps;
+	int err = 0;
+
+	memset(&caps, 0, sizeof(caps));
+	memset(&fbcaps, 0, sizeof(fbcaps));
+	caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
+	event.info = info;
+	event.data = &caps;
+	fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
+	info->fbops->fb_get_caps(info, &fbcaps, var);
+
+	if (((fbcaps.x ^ caps.x) & caps.x) ||
+	    ((fbcaps.y ^ caps.y) & caps.y) ||
+	    (fbcaps.len < caps.len))
+		err = -EINVAL;
+
+	return err;
+}
+
 int
 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
 {
-	int err, flags = info->flags;
+	int flags = info->flags;
+	int ret = 0;
 
 	if (var->activate & FB_ACTIVATE_INV_MODE) {
 		struct fb_videomode mode1, mode2;
-		int ret = 0;
 
 		fb_var_to_videomode(&mode1, var);
 		fb_var_to_videomode(&mode2, &info->var);
@@ -796,40 +821,51 @@ fb_set_var(struct fb_info *info, struct 
 		if (!ret)
 		    fb_delete_videomode(&mode1, &info->modelist);
 
-		return ret;
+
+		ret = (ret) ? -EINVAL : 0;
+		goto done;
 	}
 
 	if ((var->activate & FB_ACTIVATE_FORCE) ||
 	    memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
+		u32 activate = var->activate;
+
 		if (!info->fbops->fb_check_var) {
 			*var = info->var;
-			return 0;
+			goto done;
 		}
 
-		if ((err = info->fbops->fb_check_var(var, info)))
-			return err;
+		ret = info->fbops->fb_check_var(var, info);
+
+		if (ret)
+			goto done;
 
 		if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 			struct fb_videomode mode;
-			int err = 0;
+
+			if (info->fbops->fb_get_caps) {
+				ret = fb_check_caps(info, var, activate);
+
+				if (ret)
+					goto done;
+			}
 
 			info->var = *var;
+
 			if (info->fbops->fb_set_par)
 				info->fbops->fb_set_par(info);
 
 			fb_pan_display(info, &info->var);
-
 			fb_set_cmap(&info->cmap, info);
-
 			fb_var_to_videomode(&mode, &info->var);
 
 			if (info->modelist.prev && info->modelist.next &&
 			    !list_empty(&info->modelist))
-				err = fb_add_videomode(&mode, &info->modelist);
+				ret = fb_add_videomode(&mode, &info->modelist);
 
-			if (!err && (flags & FBINFO_MISC_USEREVENT)) {
+			if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
 				struct fb_event event;
-				int evnt = (var->activate & FB_ACTIVATE_ALL) ?
+				int evnt = (activate & FB_ACTIVATE_ALL) ?
 					FB_EVENT_MODE_CHANGE_ALL :
 					FB_EVENT_MODE_CHANGE;
 
@@ -839,7 +875,9 @@ fb_set_var(struct fb_info *info, struct 
 			}
 		}
 	}
-	return 0;
+
+ done:
+	return ret;
 }
 
 int
@@ -1266,6 +1304,9 @@ #endif
 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
 	.get_unmapped_area = get_fb_unmapped_area,
 #endif
+#ifdef CONFIG_FB_DEFERRED_IO
+	.fsync =	fb_deferred_io_fsync,
+#endif
 };
 
 struct class *fb_class;
@@ -1316,6 +1357,12 @@ register_framebuffer(struct fb_info *fb_
 	}	
 	fb_info->pixmap.offset = 0;
 
+	if (!fb_info->pixmap.blit_x)
+		fb_info->pixmap.blit_x = ~(u32)0;
+
+	if (!fb_info->pixmap.blit_y)
+		fb_info->pixmap.blit_y = ~(u32)0;
+
 	if (!fb_info->modelist.prev || !fb_info->modelist.next)
 		INIT_LIST_HEAD(&fb_info->modelist);
 
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 6b385c3..438b941 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -48,8 +48,9 @@ #else
 #define DPRINTK(fmt, args...)
 #endif
 
-#define FBMON_FIX_HEADER 1
-#define FBMON_FIX_INPUT  2
+#define FBMON_FIX_HEADER  1
+#define FBMON_FIX_INPUT   2
+#define FBMON_FIX_TIMINGS 3
 
 #ifdef CONFIG_FB_MODE_HELPERS
 struct broken_edid {
@@ -71,6 +72,12 @@ static const struct broken_edid brokendb
 		.model        = 0x5a44,
 		.fix          = FBMON_FIX_INPUT,
 	},
+	/* Sharp UXGA? */
+	{
+		.manufacturer = "SHP",
+		.model        = 0x138e,
+		.fix          = FBMON_FIX_TIMINGS,
+	},
 };
 
 static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
@@ -87,6 +94,55 @@ static void copy_string(unsigned char *c
   while (i-- && (*--s == 0x20)) *s = 0;
 }
 
+static int edid_is_serial_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) &&
+	    (block[2] == 0x00) && (block[3] == 0xff) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_ascii_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) &&
+	    (block[2] == 0x00) && (block[3] == 0xfe) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_limits_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) &&
+	    (block[2] == 0x00) && (block[3] == 0xfd) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_monitor_block(unsigned char *block)
+{
+	if ((block[0] == 0x00) && (block[1] == 0x00) &&
+	    (block[2] == 0x00) && (block[3] == 0xfc) &&
+	    (block[4] == 0x00))
+		return 1;
+	else
+		return 0;
+}
+
+static int edid_is_timing_block(unsigned char *block)
+{
+	if ((block[0] != 0x00) || (block[1] != 0x00) ||
+	    (block[2] != 0x00) || (block[4] != 0x00))
+		return 1;
+	else
+		return 0;
+}
+
 static int check_edid(unsigned char *edid)
 {
 	unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
@@ -104,9 +160,6 @@ static int check_edid(unsigned char *edi
 	for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
 		if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
 			brokendb[i].model == model) {
-			printk("fbmon: The EDID Block of "
-			       "Manufacturer: %s Model: 0x%x is known to "
-			       "be broken,\n",  manufacturer, model);
  			fix = brokendb[i].fix;
  			break;
 		}
@@ -115,8 +168,10 @@ static int check_edid(unsigned char *edi
 	switch (fix) {
 	case FBMON_FIX_HEADER:
 		for (i = 0; i < 8; i++) {
-			if (edid[i] != edid_v1_header[i])
+			if (edid[i] != edid_v1_header[i]) {
 				ret = fix;
+				break;
+			}
 		}
 		break;
 	case FBMON_FIX_INPUT:
@@ -126,14 +181,34 @@ static int check_edid(unsigned char *edi
 		if (b[4] & 0x01 && b[0] & 0x80)
 			ret = fix;
 		break;
+	case FBMON_FIX_TIMINGS:
+		b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+		ret = fix;
+
+		for (i = 0; i < 4; i++) {
+			if (edid_is_limits_block(b)) {
+				ret = 0;
+				break;
+			}
+
+			b += DETAILED_TIMING_DESCRIPTION_SIZE;
+		}
+
+		break;
 	}
 
+	if (ret)
+		printk("fbmon: The EDID Block of "
+		       "Manufacturer: %s Model: 0x%x is known to "
+		       "be broken,\n",  manufacturer, model);
+
 	return ret;
 }
 
 static void fix_edid(unsigned char *edid, int fix)
 {
-	unsigned char *b;
+	int i;
+	unsigned char *b, csum = 0;
 
 	switch (fix) {
 	case FBMON_FIX_HEADER:
@@ -145,6 +220,37 @@ static void fix_edid(unsigned char *edid
 		b = edid + EDID_STRUCT_DISPLAY;
 		b[0] &= ~0x80;
 		edid[127] += 0x80;
+		break;
+	case FBMON_FIX_TIMINGS:
+		printk("fbmon: trying to fix monitor timings\n");
+		b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+		for (i = 0; i < 4; i++) {
+			if (!(edid_is_serial_block(b) ||
+			      edid_is_ascii_block(b) ||
+			      edid_is_monitor_block(b) ||
+			      edid_is_timing_block(b))) {
+				b[0] = 0x00;
+				b[1] = 0x00;
+				b[2] = 0x00;
+				b[3] = 0xfd;
+				b[4] = 0x00;
+				b[5] = 60;   /* vfmin */
+				b[6] = 60;   /* vfmax */
+				b[7] = 30;   /* hfmin */
+				b[8] = 75;   /* hfmax */
+				b[9] = 17;   /* pixclock - 170 MHz*/
+				b[10] = 0;   /* GTF */
+				break;
+			}
+
+			b += DETAILED_TIMING_DESCRIPTION_SIZE;
+		}
+
+		for (i = 0; i < EDID_LENGTH - 1; i++)
+			csum += edid[i];
+
+		edid[127] = 256 - csum;
+		break;
 	}
 }
 
@@ -273,46 +379,6 @@ static void get_chroma(unsigned char *bl
 	DPRINTK("WhiteY:   0.%03d\n", specs->chroma.whitey);
 }
 
-static int edid_is_serial_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xff) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
-static int edid_is_ascii_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xfe) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
-static int edid_is_limits_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xfd) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
-static int edid_is_monitor_block(unsigned char *block)
-{
-	if ((block[0] == 0x00) && (block[1] == 0x00) && 
-	    (block[2] == 0x00) && (block[3] == 0xfc) &&
-	    (block[4] == 0x00))
-		return 1;
-	else
-		return 0;
-}
-
 static void calc_mode_timings(int xres, int yres, int refresh,
 			      struct fb_videomode *mode)
 {
@@ -795,15 +861,6 @@ static void get_monspecs(unsigned char *
 	}
 }
 
-static int edid_is_timing_block(unsigned char *block)
-{
-	if ((block[0] != 0x00) || (block[1] != 0x00) ||
-	    (block[2] != 0x00) || (block[4] != 0x00))
-		return 1;
-	else
-		return 0;
-}
-
 int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
 {
 	int i;
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 40c80c8..d4a2c11 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -376,7 +376,7 @@ static ssize_t show_pan(struct device *d
 {
 	struct fb_info *fb_info = dev_get_drvdata(device);
 	return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
-			fb_info->var.xoffset);
+			fb_info->var.yoffset);
 }
 
 static ssize_t show_name(struct device *device,
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index ca93a75..b7655c0 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -26,7 +26,6 @@ #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/jazz.h>
 
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
new file mode 100644
index 0000000..abfcb50
--- /dev/null
+++ b/drivers/video/hecubafb.c
@@ -0,0 +1,471 @@
+/*
+ * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller
+ *
+ * Copyright (C) 2006, Jaya Kumar
+ * This work was sponsored by CIS(M) Sdn Bhd
+ *
+ * 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.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ * This work was possible because of apollo display code from E-Ink's website
+ * http://support.eink.com/community
+ * All information used to write this code is from public material made
+ * available by E-Ink on its support site. Some commands such as 0xA4
+ * were found by looping through cmd=0x00 thru 0xFF and supplying random
+ * values. There are other commands that the display is capable of,
+ * beyond the 5 used here but they are more complex.
+ *
+ * This driver is written to be used with the Hecuba display controller
+ * board, and tested with the EInk 800x600 display in 1 bit mode.
+ * The interface between Hecuba and the host is TTL based GPIO. The
+ * GPIO requirements are 8 writable data lines and 6 lines for control.
+ * Only 4 of the controls are actually used here but 6 for future use.
+ * The driver requires the IO addresses for data and control GPIO at
+ * load time. It is also possible to use this display with a standard
+ * PC parallel port.
+ *
+ * General notes:
+ * - User must set hecubafb_enable=1 to enable it
+ * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+/* Apollo controller specific defines */
+#define APOLLO_START_NEW_IMG	0xA0
+#define APOLLO_STOP_IMG_DATA	0xA1
+#define APOLLO_DISPLAY_IMG	0xA2
+#define APOLLO_ERASE_DISPLAY	0xA3
+#define APOLLO_INIT_DISPLAY	0xA4
+
+/* Hecuba interface specific defines */
+/* WUP is inverted, CD is inverted, DS is inverted */
+#define HCB_NWUP_BIT	0x01
+#define HCB_NDS_BIT 	0x02
+#define HCB_RW_BIT 	0x04
+#define HCB_NCD_BIT 	0x08
+#define HCB_ACK_BIT 	0x80
+
+/* Display specific information */
+#define DPY_W 600
+#define DPY_H 800
+
+struct hecubafb_par {
+	unsigned long dio_addr;
+	unsigned long cio_addr;
+	unsigned long c2io_addr;
+	unsigned char ctl;
+	struct fb_info *info;
+	unsigned int irq;
+};
+
+static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
+	.id =		"hecubafb",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_MONO01,
+	.xpanstep =	0,
+	.ypanstep =	0,
+	.ywrapstep =	0,
+	.accel =	FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo hecubafb_var __devinitdata = {
+	.xres		= DPY_W,
+	.yres		= DPY_H,
+	.xres_virtual	= DPY_W,
+	.yres_virtual	= DPY_H,
+	.bits_per_pixel	= 1,
+	.nonstd		= 1,
+};
+
+static unsigned long dio_addr;
+static unsigned long cio_addr;
+static unsigned long c2io_addr;
+static unsigned long splashval;
+static unsigned int nosplash;
+static unsigned int hecubafb_enable;
+static unsigned int irq;
+
+static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq);
+
+static void hcb_set_ctl(struct hecubafb_par *par)
+{
+	outb(par->ctl, par->cio_addr);
+}
+
+static unsigned char hcb_get_ctl(struct hecubafb_par *par)
+{
+	return inb(par->c2io_addr);
+}
+
+static void hcb_set_data(struct hecubafb_par *par, unsigned char value)
+{
+	outb(value, par->dio_addr);
+}
+
+static int __devinit apollo_init_control(struct hecubafb_par *par)
+{
+	unsigned char ctl;
+	/* for init, we want the following setup to be set:
+	WUP = lo
+	ACK = hi
+	DS = hi
+	RW = hi
+	CD = lo
+	*/
+
+	/* write WUP to lo, DS to hi, RW to hi, CD to lo */
+	par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ;
+	par->ctl &= ~HCB_NDS_BIT;
+	hcb_set_ctl(par);
+
+	/* check ACK is not lo */
+	ctl = hcb_get_ctl(par);
+	if ((ctl & HCB_ACK_BIT)) {
+		printk(KERN_ERR "Fail because ACK is already low\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void hcb_wait_for_ack(struct hecubafb_par *par)
+{
+
+	int timeout;
+	unsigned char ctl;
+
+	timeout=500;
+	do {
+		ctl = hcb_get_ctl(par);
+		if ((ctl & HCB_ACK_BIT))
+			return;
+		udelay(1);
+	} while (timeout--);
+	printk(KERN_ERR "timed out waiting for ack\n");
+}
+
+static void hcb_wait_for_ack_clear(struct hecubafb_par *par)
+{
+
+	int timeout;
+	unsigned char ctl;
+
+	timeout=500;
+	do {
+		ctl = hcb_get_ctl(par);
+		if (!(ctl & HCB_ACK_BIT))
+			return;
+		udelay(1);
+	} while (timeout--);
+	printk(KERN_ERR "timed out waiting for clear\n");
+}
+
+static void apollo_send_data(struct hecubafb_par *par, unsigned char data)
+{
+	/* set data */
+	hcb_set_data(par, data);
+
+	/* set DS low */
+	par->ctl |= HCB_NDS_BIT;
+	hcb_set_ctl(par);
+
+	hcb_wait_for_ack(par);
+
+	/* set DS hi */
+	par->ctl &= ~(HCB_NDS_BIT);
+	hcb_set_ctl(par);
+
+	hcb_wait_for_ack_clear(par);
+}
+
+static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
+{
+	/* command so set CD to high */
+	par->ctl &= ~(HCB_NCD_BIT);
+	hcb_set_ctl(par);
+
+	/* actually strobe with command */
+	apollo_send_data(par, data);
+
+	/* clear CD back to low */
+	par->ctl |= (HCB_NCD_BIT);
+	hcb_set_ctl(par);
+}
+
+/* main hecubafb functions */
+
+static void hecubafb_dpy_update(struct hecubafb_par *par)
+{
+	int i;
+	unsigned char *buf = (unsigned char __force *)par->info->screen_base;
+
+	apollo_send_command(par, 0xA0);
+
+	for (i=0; i < (DPY_W*DPY_H/8); i++) {
+		apollo_send_data(par, *(buf++));
+	}
+
+	apollo_send_command(par, 0xA1);
+	apollo_send_command(par, 0xA2);
+}
+
+/* this is called back from the deferred io workqueue */
+static void hecubafb_dpy_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+{
+	hecubafb_dpy_update(info->par);
+}
+
+static void hecubafb_fillrect(struct fb_info *info,
+				   const struct fb_fillrect *rect)
+{
+	struct hecubafb_par *par = info->par;
+
+	sys_fillrect(info, rect);
+
+	hecubafb_dpy_update(par);
+}
+
+static void hecubafb_copyarea(struct fb_info *info,
+				   const struct fb_copyarea *area)
+{
+	struct hecubafb_par *par = info->par;
+
+	sys_copyarea(info, area);
+
+	hecubafb_dpy_update(par);
+}
+
+static void hecubafb_imageblit(struct fb_info *info,
+				const struct fb_image *image)
+{
+	struct hecubafb_par *par = info->par;
+
+	sys_imageblit(info, image);
+
+	hecubafb_dpy_update(par);
+}
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	unsigned long p;
+	int err=-EINVAL;
+	struct hecubafb_par *par;
+	unsigned int xres;
+	unsigned int fbmemlength;
+
+	p = *ppos;
+	par = info->par;
+	xres = info->var.xres;
+	fbmemlength = (xres * info->var.yres)/8;
+
+	if (p > fbmemlength)
+		return -ENOSPC;
+
+	err = 0;
+	if ((count + p) > fbmemlength) {
+		count = fbmemlength - p;
+		err = -ENOSPC;
+	}
+
+	if (count) {
+		char *base_addr;
+
+		base_addr = (char __force *)info->screen_base;
+		count -= copy_from_user(base_addr + p, buf, count);
+		*ppos += count;
+		err = -EFAULT;
+	}
+
+	hecubafb_dpy_update(par);
+
+	if (count)
+		return count;
+
+	return err;
+}
+
+static struct fb_ops hecubafb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_read        = fb_sys_read,
+	.fb_write	= hecubafb_write,
+	.fb_fillrect	= hecubafb_fillrect,
+	.fb_copyarea	= hecubafb_copyarea,
+	.fb_imageblit	= hecubafb_imageblit,
+};
+
+static struct fb_deferred_io hecubafb_defio = {
+	.delay		= HZ,
+	.deferred_io	= hecubafb_dpy_deferred_io,
+};
+
+static int __devinit hecubafb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int retval = -ENOMEM;
+	int videomemorysize;
+	unsigned char *videomemory;
+	struct hecubafb_par *par;
+
+	videomemorysize = (DPY_W*DPY_H)/8;
+
+	if (!(videomemory = vmalloc(videomemorysize)))
+		return retval;
+
+	memset(videomemory, 0, videomemorysize);
+
+	info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
+	if (!info)
+		goto err;
+
+	info->screen_base = (char __iomem *) videomemory;
+	info->fbops = &hecubafb_ops;
+
+	info->var = hecubafb_var;
+	info->fix = hecubafb_fix;
+	info->fix.smem_len = videomemorysize;
+	par = info->par;
+	par->info = info;
+
+	if (!dio_addr || !cio_addr || !c2io_addr) {
+		printk(KERN_WARNING "no IO addresses supplied\n");
+		goto err1;
+	}
+	par->dio_addr = dio_addr;
+	par->cio_addr = cio_addr;
+	par->c2io_addr = c2io_addr;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	info->fbdefio = &hecubafb_defio;
+	fb_deferred_io_init(info);
+
+	retval = register_framebuffer(info);
+	if (retval < 0)
+		goto err1;
+	platform_set_drvdata(dev, info);
+
+	printk(KERN_INFO
+	       "fb%d: Hecuba frame buffer device, using %dK of video memory\n",
+	       info->node, videomemorysize >> 10);
+
+	/* this inits the dpy */
+	apollo_init_control(par);
+
+	apollo_send_command(par, APOLLO_INIT_DISPLAY);
+	apollo_send_data(par, 0x81);
+
+	/* have to wait while display resets */
+	udelay(1000);
+
+	/* if we were told to splash the screen, we just clear it */
+	if (!nosplash) {
+		apollo_send_command(par, APOLLO_ERASE_DISPLAY);
+		apollo_send_data(par, splashval);
+	}
+
+	return 0;
+err1:
+	framebuffer_release(info);
+err:
+	vfree(videomemory);
+	return retval;
+}
+
+static int __devexit hecubafb_remove(struct platform_device *dev)
+{
+	struct fb_info *info = platform_get_drvdata(dev);
+
+	if (info) {
+		fb_deferred_io_cleanup(info);
+		unregister_framebuffer(info);
+		vfree((void __force *)info->screen_base);
+		framebuffer_release(info);
+	}
+	return 0;
+}
+
+static struct platform_driver hecubafb_driver = {
+	.probe	= hecubafb_probe,
+	.remove = hecubafb_remove,
+	.driver	= {
+		.name	= "hecubafb",
+	},
+};
+
+static struct platform_device *hecubafb_device;
+
+static int __init hecubafb_init(void)
+{
+	int ret;
+
+	if (!hecubafb_enable) {
+		printk(KERN_ERR "Use hecubafb_enable to enable the device\n");
+		return -ENXIO;
+	}
+
+	ret = platform_driver_register(&hecubafb_driver);
+	if (!ret) {
+		hecubafb_device = platform_device_alloc("hecubafb", 0);
+		if (hecubafb_device)
+			ret = platform_device_add(hecubafb_device);
+		else
+			ret = -ENOMEM;
+
+		if (ret) {
+			platform_device_put(hecubafb_device);
+			platform_driver_unregister(&hecubafb_driver);
+		}
+	}
+	return ret;
+
+}
+
+static void __exit hecubafb_exit(void)
+{
+	platform_device_unregister(hecubafb_device);
+	platform_driver_unregister(&hecubafb_driver);
+}
+
+module_param(nosplash, uint, 0);
+MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
+module_param(hecubafb_enable, uint, 0);
+MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board");
+module_param(dio_addr, ulong, 0);
+MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
+module_param(cio_addr, ulong, 0);
+MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
+module_param(c2io_addr, ulong, 0);
+MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
+module_param(splashval, ulong, 0);
+MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white");
+module_param(irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ for the Hecuba board");
+
+module_init(hecubafb_init);
+module_exit(hecubafb_exit);
+
+MODULE_DESCRIPTION("fbdev driver for Hecuba board");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
index aa65ffc..889e4ea 100644
--- a/drivers/video/i810/i810.h
+++ b/drivers/video/i810/i810.h
@@ -133,7 +133,7 @@ #define FONTDATAMAX                 8192
 /* Masks (AND ops) and OR's */
 #define FB_START_MASK               (0x3f << (32 - 6))
 #define MMIO_ADDR_MASK              (0x1FFF << (32 - 13))
-#define FREQ_MASK                   0x1EF
+#define FREQ_MASK                   (1 << 4)
 #define SCR_OFF                     0x20
 #define DRAM_ON                     0x08            
 #define DRAM_OFF                    0xE7
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 90592fb..eb1a481 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -44,8 +44,8 @@ #include <linux/nvram.h>
 
 #include <asm/io.h>
 
-#ifdef __sparc__
-#include <asm/pbm.h>
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
 #include <asm/pcic.h>
 #endif
 
@@ -96,7 +96,7 @@ struct fb_var_screeninfo default_var = {
 	.vmode		= FB_VMODE_NONINTERLACED
 };
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 struct fb_var_screeninfo default_var_1024x768 __initdata = {
 	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
 	.xres		= 1024,
@@ -188,7 +188,7 @@ static inline void iga_outb(struct iga_p
         pci_outb(par, val, reg+1);
 }
 
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
 
 /*
  *  Very important functionality for the JavaEngine1 computer:
@@ -217,7 +217,7 @@ #endif
 		iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
 }
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 static int igafb_mmap(struct fb_info *info,
 		      struct vm_area_struct *vma)
 {
@@ -271,7 +271,7 @@ static int igafb_mmap(struct fb_info *in
 	vma->vm_flags |= VM_IO;
 	return 0;
 }
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
 
 static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
                            unsigned blue, unsigned transp,
@@ -323,7 +323,7 @@ static struct fb_ops igafb_ops = {
 	.fb_fillrect	= cfb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 	.fb_mmap 	= igafb_mmap,
 #endif
 };
@@ -424,7 +424,7 @@ int __init igafb_init(void)
 
 	par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 	/*
 	 * The following is sparc specific and this is why:
 	 *
@@ -477,8 +477,8 @@ #ifdef __sparc__
 	 * Set default vmode and cmode from PROM properties.
 	 */
 	{
-                struct pcidev_cookie *cookie = pdev->sysdata;
-                int node = cookie->prom_node;
+		struct device_node *dp = pci_device_to_OF_node(pdev);
+                int node = dp->node;
                 int width = prom_getintdefault(node, "width", 1024);
                 int height = prom_getintdefault(node, "height", 768);
                 int depth = prom_getintdefault(node, "depth", 8);
@@ -534,7 +534,7 @@ #endif
 		kfree(info);
         }
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
 	    /*
 	     * Add /dev/fb mmap values.
 	     */
@@ -552,7 +552,7 @@ #ifdef __sparc__
 	    par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
 	    par->mmap_map[1].prot_mask = SRMMU_CACHE;
 	    par->mmap_map[1].prot_flag = SRMMU_WRITE;
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
 
 	return 0;
 }
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index f4ede5f..61e4c87 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -104,7 +104,8 @@ static int intelfb_setup_i2c_bus(struct 
 
 	chan->dinfo					= dinfo;
 	chan->reg					= reg;
-	snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
+	snprintf(chan->adapter.name, sizeof(chan->adapter.name),
+		 "intelfb %s", name);
 	chan->adapter.owner			= THIS_MODULE;
 	chan->adapter.id			= I2C_HW_B_INTELFB;
 	chan->adapter.algo_data		= &chan->algo;
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index c1eb18b..16bc8d7 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1428,6 +1428,24 @@ static void refresh_ring(struct intelfb_
 static void reset_state(struct intelfb_info *dinfo);
 static void do_flush(struct intelfb_info *dinfo);
 
+static  u32 get_ring_space(struct intelfb_info *dinfo)
+{
+	u32 ring_space;
+
+	if (dinfo->ring_tail >= dinfo->ring_head)
+		ring_space = dinfo->ring.size -
+			(dinfo->ring_tail - dinfo->ring_head);
+	else
+		ring_space = dinfo->ring_head - dinfo->ring_tail;
+
+	if (ring_space > RING_MIN_FREE)
+		ring_space -= RING_MIN_FREE;
+	else
+		ring_space = 0;
+
+	return ring_space;
+}
+
 static int
 wait_ring(struct intelfb_info *dinfo, int n)
 {
@@ -1442,13 +1460,8 @@ #endif
 	end = jiffies + (HZ * 3);
 	while (dinfo->ring_space < n) {
 		dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
-		if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
-			dinfo->ring_space = dinfo->ring_head
-				- (dinfo->ring_tail + RING_MIN_FREE);
-		else
-			dinfo->ring_space = (dinfo->ring.size +
-					     dinfo->ring_head)
-				- (dinfo->ring_tail + RING_MIN_FREE);
+		dinfo->ring_space = get_ring_space(dinfo);
+
 		if (dinfo->ring_head != last_head) {
 			end = jiffies + (HZ * 3);
 			last_head = dinfo->ring_head;
@@ -1513,12 +1526,7 @@ #endif
 
 	dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
 	dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
-	if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
-		dinfo->ring_space = dinfo->ring_head
-			- (dinfo->ring_tail + RING_MIN_FREE);
-	else
-		dinfo->ring_space = (dinfo->ring.size + dinfo->ring_head)
-			- (dinfo->ring_tail + RING_MIN_FREE);
+	dinfo->ring_space = get_ring_space(dinfo);
 }
 
 static void
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index f0e6512..9397bce 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -2,73 +2,69 @@ #
 # Logo configuration
 #
 
-menu "Logo configuration"
-
-config LOGO
+menuconfig LOGO
 	bool "Bootup logo"
 	depends on FB || SGI_NEWPORT_CONSOLE
 	help
 	  Enable and select frame buffer bootup logos.
 
+if LOGO
+
 config LOGO_LINUX_MONO
 	bool "Standard black and white Linux logo"
-	depends on LOGO
 	default y
 
 config LOGO_LINUX_VGA16
 	bool "Standard 16-color Linux logo"
-	depends on LOGO
 	default y
 
 config LOGO_LINUX_CLUT224
 	bool "Standard 224-color Linux logo"
-	depends on LOGO
 	default y
 
 config LOGO_DEC_CLUT224
 	bool "224-color Digital Equipment Corporation Linux logo"
-	depends on LOGO && (MACH_DECSTATION || ALPHA)
+	depends on MACH_DECSTATION || ALPHA
 	default y
 
 config LOGO_MAC_CLUT224
 	bool "224-color Macintosh Linux logo"
-	depends on LOGO && MAC
+	depends on MAC
 	default y
 
 config LOGO_PARISC_CLUT224
 	bool "224-color PA-RISC Linux logo"
-	depends on LOGO && PARISC
+	depends on PARISC
 	default y
 
 config LOGO_SGI_CLUT224
 	bool "224-color SGI Linux logo"
-	depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS)
+	depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS
 	default y
 
 config LOGO_SUN_CLUT224
 	bool "224-color Sun Linux logo"
-	depends on LOGO && SPARC
+	depends on SPARC
 	default y
 
 config LOGO_SUPERH_MONO
 	bool "Black and white SuperH Linux logo"
-	depends on LOGO && SUPERH
+	depends on SUPERH
 	default y
 
 config LOGO_SUPERH_VGA16
 	bool "16-color SuperH Linux logo"
-	depends on LOGO && SUPERH
+	depends on SUPERH
 	default y
 
 config LOGO_SUPERH_CLUT224
 	bool "224-color SuperH Linux logo"
-	depends on LOGO && SUPERH
+	depends on SUPERH
 	default y
 
 config LOGO_M32R_CLUT224
 	bool "224-color M32R Linux logo"
-	depends on LOGO && M32R
+	depends on M32R
 	default y
 
-endmenu
-
+endif # LOGO
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 5ec718a..4baab7b 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -111,7 +111,7 @@ static int i2c_bus_reg(struct i2c_bit_ad
 	b->mask.data = data;
 	b->mask.clock = clock;
 	b->adapter = matrox_i2c_adapter_template;
-	snprintf(b->adapter.name, I2C_NAME_SIZE, name,
+	snprintf(b->adapter.name, sizeof(b->adapter.name), name,
 		minfo->fbcon.node);
 	i2c_set_adapdata(&b->adapter, b);
 	b->adapter.algo_data = &b->bac;
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 3e51794..3741ad7 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -395,7 +395,7 @@ static int my_atoi(const char *name)
 
     for (;; name++) {
 	switch (*name) {
-	    case '0'...'9':
+	    case '0' ... '9':
 		val = 10*val+(*name-'0');
 		break;
 	    default:
@@ -548,7 +548,7 @@ int fb_find_mode(struct fb_var_screeninf
 		    } else
 			goto done;
 		    break;
-		case '0'...'9':
+		case '0' ... '9':
 		    break;
 		case 'M':
 		    if (!yres_specified)
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 395cced..bd30aba 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -665,6 +665,7 @@ neofb_check_var(struct fb_var_screeninfo
 	var->red.msb_right = 0;
 	var->green.msb_right = 0;
 	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
 
 	switch (var->bits_per_pixel) {
 	case 8:		/* PSEUDOCOLOUR, 256 */
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
index 9efb8a3..fa4821c 100644
--- a/drivers/video/nvidia/nv_accel.c
+++ b/drivers/video/nvidia/nv_accel.c
@@ -69,27 +69,38 @@ static const int NVCopyROP_PM[16] = {
 	0x5A,			/* invert */
 };
 
-static inline void NVFlush(struct nvidia_par *par)
+static inline void nvidiafb_safe_mode(struct fb_info *info)
 {
+	struct nvidia_par *par = info->par;
+
+	touch_softlockup_watchdog();
+	info->pixmap.scan_align = 1;
+	par->lockup = 1;
+}
+
+static inline void NVFlush(struct fb_info *info)
+{
+	struct nvidia_par *par = info->par;
 	int count = 1000000000;
 
 	while (--count && READ_GET(par) != par->dmaPut) ;
 
 	if (!count) {
 		printk("nvidiafb: DMA Flush lockup\n");
-		par->lockup = 1;
+		nvidiafb_safe_mode(info);
 	}
 }
 
-static inline void NVSync(struct nvidia_par *par)
+static inline void NVSync(struct fb_info *info)
 {
+	struct nvidia_par *par = info->par;
 	int count = 1000000000;
 
 	while (--count && NV_RD32(par->PGRAPH, 0x0700)) ;
 
 	if (!count) {
 		printk("nvidiafb: DMA Sync lockup\n");
-		par->lockup = 1;
+		nvidiafb_safe_mode(info);
 	}
 }
 
@@ -101,8 +112,9 @@ static void NVDmaKickoff(struct nvidia_p
 	}
 }
 
-static void NVDmaWait(struct nvidia_par *par, int size)
+static void NVDmaWait(struct fb_info *info, int size)
 {
+	struct nvidia_par *par = info->par;
 	int dmaGet;
 	int count = 1000000000, cnt;
 	size++;
@@ -135,34 +147,38 @@ static void NVDmaWait(struct nvidia_par 
 	}
 
 	if (!count) {
-		printk("DMA Wait Lockup\n");
-		par->lockup = 1;
+		printk("nvidiafb: DMA Wait Lockup\n");
+		nvidiafb_safe_mode(info);
 	}
 }
 
-static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1,
+static void NVSetPattern(struct fb_info *info, u32 clr0, u32 clr1,
 			 u32 pat0, u32 pat1)
 {
-	NVDmaStart(par, PATTERN_COLOR_0, 4);
+	struct nvidia_par *par = info->par;
+
+	NVDmaStart(info, par, PATTERN_COLOR_0, 4);
 	NVDmaNext(par, clr0);
 	NVDmaNext(par, clr1);
 	NVDmaNext(par, pat0);
 	NVDmaNext(par, pat1);
 }
 
-static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask)
+static void NVSetRopSolid(struct fb_info *info, u32 rop, u32 planemask)
 {
+	struct nvidia_par *par = info->par;
+
 	if (planemask != ~0) {
-		NVSetPattern(par, 0, planemask, ~0, ~0);
+		NVSetPattern(info, 0, planemask, ~0, ~0);
 		if (par->currentRop != (rop + 32)) {
-			NVDmaStart(par, ROP_SET, 1);
+			NVDmaStart(info, par, ROP_SET, 1);
 			NVDmaNext(par, NVCopyROP_PM[rop]);
 			par->currentRop = rop + 32;
 		}
 	} else if (par->currentRop != rop) {
 		if (par->currentRop >= 16)
-			NVSetPattern(par, ~0, ~0, ~0, ~0);
-		NVDmaStart(par, ROP_SET, 1);
+			NVSetPattern(info, ~0, ~0, ~0, ~0);
+		NVDmaStart(info, par, ROP_SET, 1);
 		NVDmaNext(par, NVCopyROP[rop]);
 		par->currentRop = rop;
 	}
@@ -175,7 +191,7 @@ static void NVSetClippingRectangle(struc
 	int h = y2 - y1 + 1;
 	int w = x2 - x1 + 1;
 
-	NVDmaStart(par, CLIP_POINT, 2);
+	NVDmaStart(info, par, CLIP_POINT, 2);
 	NVDmaNext(par, (y1 << 16) | x1);
 	NVDmaNext(par, (h << 16) | w);
 }
@@ -237,23 +253,23 @@ void NVResetGraphics(struct fb_info *inf
 		break;
 	}
 
-	NVDmaStart(par, SURFACE_FORMAT, 4);
+	NVDmaStart(info, par, SURFACE_FORMAT, 4);
 	NVDmaNext(par, surfaceFormat);
 	NVDmaNext(par, pitch | (pitch << 16));
 	NVDmaNext(par, 0);
 	NVDmaNext(par, 0);
 
-	NVDmaStart(par, PATTERN_FORMAT, 1);
+	NVDmaStart(info, par, PATTERN_FORMAT, 1);
 	NVDmaNext(par, patternFormat);
 
-	NVDmaStart(par, RECT_FORMAT, 1);
+	NVDmaStart(info, par, RECT_FORMAT, 1);
 	NVDmaNext(par, rectFormat);
 
-	NVDmaStart(par, LINE_FORMAT, 1);
+	NVDmaStart(info, par, LINE_FORMAT, 1);
 	NVDmaNext(par, lineFormat);
 
 	par->currentRop = ~0;	/* set to something invalid */
-	NVSetRopSolid(par, ROP_COPY, ~0);
+	NVSetRopSolid(info, ROP_COPY, ~0);
 
 	NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual,
 			       info->var.yres_virtual);
@@ -269,10 +285,10 @@ int nvidiafb_sync(struct fb_info *info)
 		return 0;
 
 	if (!par->lockup)
-		NVFlush(par);
+		NVFlush(info);
 
 	if (!par->lockup)
-		NVSync(par);
+		NVSync(info);
 
 	return 0;
 }
@@ -287,7 +303,7 @@ void nvidiafb_copyarea(struct fb_info *i
 	if (par->lockup)
 		return cfb_copyarea(info, region);
 
-	NVDmaStart(par, BLIT_POINT_SRC, 3);
+	NVDmaStart(info, par, BLIT_POINT_SRC, 3);
 	NVDmaNext(par, (region->sy << 16) | region->sx);
 	NVDmaNext(par, (region->dy << 16) | region->dx);
 	NVDmaNext(par, (region->height << 16) | region->width);
@@ -312,19 +328,19 @@ void nvidiafb_fillrect(struct fb_info *i
 		color = ((u32 *) info->pseudo_palette)[rect->color];
 
 	if (rect->rop != ROP_COPY)
-		NVSetRopSolid(par, rect->rop, ~0);
+		NVSetRopSolid(info, rect->rop, ~0);
 
-	NVDmaStart(par, RECT_SOLID_COLOR, 1);
+	NVDmaStart(info, par, RECT_SOLID_COLOR, 1);
 	NVDmaNext(par, color);
 
-	NVDmaStart(par, RECT_SOLID_RECTS(0), 2);
+	NVDmaStart(info, par, RECT_SOLID_RECTS(0), 2);
 	NVDmaNext(par, (rect->dx << 16) | rect->dy);
 	NVDmaNext(par, (rect->width << 16) | rect->height);
 
 	NVDmaKickoff(par);
 
 	if (rect->rop != ROP_COPY)
-		NVSetRopSolid(par, ROP_COPY, ~0);
+		NVSetRopSolid(info, ROP_COPY, ~0);
 }
 
 static void nvidiafb_mono_color_expand(struct fb_info *info,
@@ -346,7 +362,7 @@ static void nvidiafb_mono_color_expand(s
 		bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask;
 	}
 
-	NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
+	NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
 	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
 	NVDmaNext(par, ((image->dy + image->height) << 16) |
 		  ((image->dx + image->width) & 0xffff));
@@ -357,7 +373,7 @@ static void nvidiafb_mono_color_expand(s
 	NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
 
 	while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) {
-		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0),
+		NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0),
 			   RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS);
 
 		for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) {
@@ -370,7 +386,7 @@ static void nvidiafb_mono_color_expand(s
 	}
 
 	if (dsize) {
-		NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
+		NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
 
 		for (j = dsize; j--;) {
 			tmp = data[k++];
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index ea42611..f297c7b 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -686,7 +686,7 @@ static void nForceUpdateArbitrationSetti
 
 	if ((par->Chipset & 0x0FF0) == 0x01A0) {
 		unsigned int uMClkPostDiv;
-		dev = pci_find_slot(0, 3);
+		dev = pci_get_bus_and_slot(0, 3);
 		pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
 		uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
 
@@ -694,11 +694,11 @@ static void nForceUpdateArbitrationSetti
 			uMClkPostDiv = 4;
 		MClk = 400000 / uMClkPostDiv;
 	} else {
-		dev = pci_find_slot(0, 5);
+		dev = pci_get_bus_and_slot(0, 5);
 		pci_read_config_dword(dev, 0x4c, &MClk);
 		MClk /= 1000;
 	}
-
+	pci_dev_put(dev);
 	pll = NV_RD32(par->PRAMDAC0, 0x0500);
 	M = (pll >> 0) & 0xFF;
 	N = (pll >> 8) & 0xFF;
@@ -707,19 +707,21 @@ static void nForceUpdateArbitrationSetti
 	sim_data.pix_bpp = (char)pixelDepth;
 	sim_data.enable_video = 0;
 	sim_data.enable_mp = 0;
-	pci_find_slot(0, 1);
+	dev = pci_get_bus_and_slot(0, 1);
 	pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+	pci_dev_put(dev);
 	sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
 	sim_data.memory_width = 64;
 
-	dev = pci_find_slot(0, 3);
+	dev = pci_get_bus_and_slot(0, 3);
 	pci_read_config_dword(dev, 0, &memctrl);
+	pci_dev_put(dev);
 	memctrl >>= 16;
 
 	if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
 		int dimm[3];
 
-		pci_find_slot(0, 2);
+		dev = pci_get_bus_and_slot(0, 2);
 		pci_read_config_dword(dev, 0x40, &dimm[0]);
 		dimm[0] = (dimm[0] >> 8) & 0x4f;
 		pci_read_config_dword(dev, 0x44, &dimm[1]);
@@ -731,6 +733,7 @@ static void nForceUpdateArbitrationSetti
 			printk("nvidiafb: your nForce DIMMs are not arranged "
 			       "in optimal banks!\n");
 		}
+		pci_dev_put(dev);
 	}
 
 	sim_data.mem_latency = 3;
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index b858897..afe4567 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -30,16 +30,14 @@ static void nvidia_gpio_setscl(void *dat
 	struct nvidia_par *par = chan->par;
 	u32 val;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
-	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+	val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0;
 
 	if (state)
 		val |= 0x20;
 	else
 		val &= ~0x20;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
-	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+	NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01);
 }
 
 static void nvidia_gpio_setsda(void *data, int state)
@@ -48,16 +46,14 @@ static void nvidia_gpio_setsda(void *dat
 	struct nvidia_par *par = chan->par;
 	u32 val;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
-	val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+	val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0;
 
 	if (state)
 		val |= 0x10;
 	else
 		val &= ~0x10;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
-	VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+	NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01);
 }
 
 static int nvidia_gpio_getscl(void *data)
@@ -66,12 +62,9 @@ static int nvidia_gpio_getscl(void *data
 	struct nvidia_par *par = chan->par;
 	u32 val = 0;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
-	if (VGA_RD08(par->PCIO, 0x3d5) & 0x04)
+	if (NVReadCrtc(par, chan->ddc_base) & 0x04)
 		val = 1;
 
-	val = VGA_RD08(par->PCIO, 0x3d5);
-
 	return val;
 }
 
@@ -81,20 +74,21 @@ static int nvidia_gpio_getsda(void *data
 	struct nvidia_par *par = chan->par;
 	u32 val = 0;
 
-	VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
-	if (VGA_RD08(par->PCIO, 0x3d5) & 0x08)
+	if (NVReadCrtc(par, chan->ddc_base) & 0x08)
 		val = 1;
 
 	return val;
 }
 
-static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
+static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name,
+				unsigned int i2c_class)
 {
 	int rc;
 
 	strcpy(chan->adapter.name, name);
 	chan->adapter.owner = THIS_MODULE;
 	chan->adapter.id = I2C_HW_B_NVIDIA;
+	chan->adapter.class = i2c_class;
 	chan->adapter.algo_data = &chan->algo;
 	chan->adapter.dev.parent = &chan->par->pci_dev->dev;
 	chan->algo.setsda = nvidia_gpio_setsda;
@@ -127,83 +121,39 @@ static int nvidia_setup_i2c_bus(struct n
 
 void nvidia_create_i2c_busses(struct nvidia_par *par)
 {
-	par->bus = 3;
-
 	par->chan[0].par = par;
 	par->chan[1].par = par;
 	par->chan[2].par = par;
 
-	par->chan[0].ddc_base = 0x3e;
-	nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0");
+	par->chan[0].ddc_base = 0x36;
+ 	nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON);
 
-	par->chan[1].ddc_base = 0x36;
-	nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1");
+	par->chan[1].ddc_base = 0x3e;
+ 	nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0);
 
 	par->chan[2].ddc_base = 0x50;
-	nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2");
+ 	nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0);
 }
 
 void nvidia_delete_i2c_busses(struct nvidia_par *par)
 {
-	if (par->chan[0].par)
-		i2c_del_adapter(&par->chan[0].adapter);
-	par->chan[0].par = NULL;
-
-	if (par->chan[1].par)
-		i2c_del_adapter(&par->chan[1].adapter);
-	par->chan[1].par = NULL;
-
-	if (par->chan[2].par)
-		i2c_del_adapter(&par->chan[2].adapter);
-	par->chan[2].par = NULL;
-
-}
+	int i;
 
-static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan)
-{
-	u8 start = 0x0;
-	struct i2c_msg msgs[] = {
-		{
-		 .addr = 0x50,
-		 .len = 1,
-		 .buf = &start,
-		 }, {
-		     .addr = 0x50,
-		     .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->pci_dev->dev, "Out of memory!\n");
-		return NULL;
+	for (i = 0; i < 3; i++) {
+		if (!par->chan[i].par)
+			continue;
+		i2c_del_adapter(&par->chan[i].adapter);
+		par->chan[i].par = NULL;
 	}
-	msgs[1].buf = buf;
-
-	if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
-		return buf;
-	dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n");
-	kfree(buf);
-	return NULL;
 }
 
 int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid)
 {
 	struct nvidia_par *par = info->par;
 	u8 *edid = NULL;
-	int i;
 
-	for (i = 0; i < 3; i++) {
-		/* Do the real work */
-		edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]);
-		if (edid)
-			break;
-	}
+	if (par->chan[conn - 1].par)
+		edid = fb_ddc_read(&par->chan[conn - 1].adapter);
 
 	if (!edid && conn == 1) {
 		/* try to get from firmware */
diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h
index e009d24..68e508d 100644
--- a/drivers/video/nvidia/nv_local.h
+++ b/drivers/video/nvidia/nv_local.h
@@ -73,9 +73,9 @@ #define VGA_RD08(p,i)   (readb((void __i
 #define NVDmaNext(par, data) \
      NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data))
 
-#define NVDmaStart(par, tag, size) {          \
+#define NVDmaStart(info, par, tag, size) {    \
      if((par)->dmaFree <= (size))             \
-        NVDmaWait(par, size);                 \
+        NVDmaWait(info, size);                \
      NVDmaNext(par, ((size) << 18) | (tag));  \
      (par)->dmaFree -= ((size) + 1);          \
 }
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index 163a774..73afd7e 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -46,15 +46,15 @@ int nvidia_probe_of_connector(struct fb_
 
 		for (dp = NULL;
 		     (dp = of_get_next_child(parent, dp)) != NULL;) {
-			pname = get_property(dp, "name", NULL);
+			pname = of_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 = get_property(dp, propnames[i],
-							     NULL);
+					pedid = of_get_property(dp,
+							propnames[i], NULL);
 					if (pedid != NULL)
 						break;
 				}
@@ -65,7 +65,7 @@ int nvidia_probe_of_connector(struct fb_
 	}
 	if (pedid == NULL) {
 		for (i = 0; propnames[i] != NULL; ++i) {
-			pedid = get_property(parent, propnames[i], NULL);
+			pedid = of_get_property(parent, propnames[i], NULL);
 			if (pedid != NULL)
 				break;
 		}
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
index eab3e28..707e2c8 100644
--- a/drivers/video/nvidia/nv_setup.c
+++ b/drivers/video/nvidia/nv_setup.c
@@ -261,7 +261,7 @@ #ifdef __BIG_ENDIAN
 	}
 #endif
 
-	dev = pci_find_slot(0, 1);
+	dev = pci_get_bus_and_slot(0, 1);
 	if ((par->Chipset & 0xffff) == 0x01a0) {
 		int amt = 0;
 
@@ -276,6 +276,7 @@ #endif
 		par->RamAmountKBytes =
 		    (NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
 	}
+	pci_dev_put(dev);
 
 	par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
 	    14318 : 13500;
@@ -656,7 +657,7 @@ int NVCommonSetup(struct fb_info *info)
 	par->LVDS = 0;
 	if (par->FlatPanel && par->twoHeads) {
 		NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
-		if (par->PRAMDAC0[0x08b4] & 1)
+		if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
 			par->LVDS = 1;
 		printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
 	}
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
index 86e65de..38f7cc0 100644
--- a/drivers/video/nvidia/nv_type.h
+++ b/drivers/video/nvidia/nv_type.h
@@ -4,8 +4,9 @@ #define __NV_TYPE_H__
 #include <linux/fb.h>
 #include <linux/types.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/mutex.h>
+#include <video/vga.h>
 
 #define NV_ARCH_04  0x04
 #define NV_ARCH_10  0x10
@@ -94,13 +95,15 @@ struct riva_regs {
 struct nvidia_par {
 	RIVA_HW_STATE SavedReg;
 	RIVA_HW_STATE ModeReg;
+	RIVA_HW_STATE initial_state;
 	RIVA_HW_STATE *CurrentState;
+	struct vgastate vgastate;
+	struct mutex open_lock;
 	u32 pseudo_palette[16];
 	struct pci_dev *pci_dev;
 	u32 Architecture;
 	u32 CursorStart;
 	int Chipset;
-	int bus;
 	unsigned long FbAddress;
 	u8 __iomem *FbStart;
 	u32 FbMapSize;
@@ -143,6 +146,7 @@ struct nvidia_par {
 	int BlendingPossible;
 	u32 paletteEnabled;
 	u32 forceCRTC;
+	u32 open_count;
 	u8 DDCBase;
 #ifdef CONFIG_MTRR
 	struct {
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index b97ec69..7c36b5f 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -200,7 +200,7 @@ static int nvidia_panel_tweak(struct nvi
    return tweak;
 }
 
-static void nvidia_vga_protect(struct nvidia_par *par, int on)
+static void nvidia_screen_off(struct nvidia_par *par, int on)
 {
 	unsigned char tmp;
 
@@ -649,7 +649,7 @@ static int nvidiafb_set_par(struct fb_in
 		NVLockUnlock(par, 0);
 	}
 
-	nvidia_vga_protect(par, 1);
+	nvidia_screen_off(par, 1);
 
 	nvidia_write_regs(par, &par->ModeReg);
 	NVSetStartAddress(par, 0);
@@ -687,7 +687,7 @@ #endif
 
 	par->cursor_reset = 1;
 
-	nvidia_vga_protect(par, 0);
+	nvidia_screen_off(par, 0);
 
 #ifdef CONFIG_BOOTX_TEXT
 	/* Update debug text engine */
@@ -696,6 +696,7 @@ #ifdef CONFIG_BOOTX_TEXT
 			     info->var.bits_per_pixel, info->fix.line_length);
 #endif
 
+	NVLockUnlock(par, 0);
 	NVTRACE_LEAVE();
 	return 0;
 }
@@ -948,8 +949,80 @@ static int nvidiafb_blank(int blank, str
 	return 0;
 }
 
+/*
+ * Because the VGA registers are not mapped linearly in its MMIO space,
+ * restrict VGA register saving and restore to x86 only, where legacy VGA IO
+ * access is legal. Consequently, we must also check if the device is the
+ * primary display.
+ */
+#ifdef CONFIG_X86
+static void save_vga_x86(struct nvidia_par *par)
+{
+	struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
+
+	if (res && res->flags & IORESOURCE_ROM_SHADOW) {
+		memset(&par->vgastate, 0, sizeof(par->vgastate));
+		par->vgastate.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS |
+			VGA_SAVE_CMAP;
+		save_vga(&par->vgastate);
+	}
+}
+
+static void restore_vga_x86(struct nvidia_par *par)
+{
+	struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
+
+	if (res && res->flags & IORESOURCE_ROM_SHADOW)
+		restore_vga(&par->vgastate);
+}
+#else
+#define save_vga_x86(x) do {} while (0)
+#define restore_vga_x86(x) do {} while (0)
+#endif /* X86 */
+
+static int nvidiafb_open(struct fb_info *info, int user)
+{
+	struct nvidia_par *par = info->par;
+
+	mutex_lock(&par->open_lock);
+
+	if (!par->open_count) {
+		save_vga_x86(par);
+		nvidia_save_vga(par, &par->initial_state);
+	}
+
+	par->open_count++;
+	mutex_unlock(&par->open_lock);
+	return 0;
+}
+
+static int nvidiafb_release(struct fb_info *info, int user)
+{
+	struct nvidia_par *par = info->par;
+	int err = 0;
+
+	mutex_lock(&par->open_lock);
+
+	if (!par->open_count) {
+		err = -EINVAL;
+		goto done;
+	}
+
+	if (par->open_count == 1) {
+		nvidia_write_regs(par, &par->initial_state);
+		restore_vga_x86(par);
+	}
+
+	par->open_count--;
+done:
+	mutex_unlock(&par->open_lock);
+	return err;
+}
+
 static struct fb_ops nvidia_fb_ops = {
 	.owner          = THIS_MODULE,
+	.fb_open        = nvidiafb_open,
+	.fb_release     = nvidiafb_release,
 	.fb_check_var   = nvidiafb_check_var,
 	.fb_set_par     = nvidiafb_set_par,
 	.fb_setcolreg   = nvidiafb_setcolreg,
@@ -1207,7 +1280,7 @@ static int __devinit nvidiafb_probe(stru
 
 	par = info->par;
 	par->pci_dev = pd;
-
+	mutex_init(&par->open_lock);
 	info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
 
 	if (info->pixmap.addr == NULL)
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 9576a55..885b428 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -322,8 +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") ||
-				  device_is_compatible(dp, "pci1014,21c"))) {
+		} else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
+				  of_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;
@@ -425,27 +425,27 @@ static void __init offb_init_nodriver(st
 	const u32 *pp, *addrp, *up;
 	u64 asize;
 
-	pp = get_property(dp, "linux,bootx-depth", &len);
+	pp = of_get_property(dp, "linux,bootx-depth", &len);
 	if (pp == NULL)
-		pp = get_property(dp, "depth", &len);
+		pp = of_get_property(dp, "depth", &len);
 	if (pp && len == sizeof(u32))
 		depth = *pp;
 
-	pp = get_property(dp, "linux,bootx-width", &len);
+	pp = of_get_property(dp, "linux,bootx-width", &len);
 	if (pp == NULL)
-		pp = get_property(dp, "width", &len);
+		pp = of_get_property(dp, "width", &len);
 	if (pp && len == sizeof(u32))
 		width = *pp;
 
-	pp = get_property(dp, "linux,bootx-height", &len);
+	pp = of_get_property(dp, "linux,bootx-height", &len);
 	if (pp == NULL)
-		pp = get_property(dp, "height", &len);
+		pp = of_get_property(dp, "height", &len);
 	if (pp && len == sizeof(u32))
 		height = *pp;
 
-	pp = get_property(dp, "linux,bootx-linebytes", &len);
+	pp = of_get_property(dp, "linux,bootx-linebytes", &len);
 	if (pp == NULL)
-		pp = get_property(dp, "linebytes", &len);
+		pp = of_get_property(dp, "linebytes", &len);
 	if (pp && len == sizeof(u32) && (*pp != 0xffffffffu))
 		pitch = *pp;
 	else
@@ -463,9 +463,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 = get_property(dp, "linux,bootx-addr", &len);
+	up = of_get_property(dp, "linux,bootx-addr", &len);
 	if (up == NULL)
-		up = get_property(dp, "address", &len);
+		up = of_get_property(dp, "address", &len);
 	if (up && len == sizeof(u32))
 		addr_prop = *up;
 
@@ -521,7 +521,7 @@ static int __init offb_init(void)
 		return -ENODEV;
 
 	/* Check if we have a MacOS display without a node spec */
-	if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
+	if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
 		/* The old code tried to work out which node was the MacOS
 		 * display based on the address. I'm dropping that since the
 		 * lack of a node spec only happens with old BootX versions
@@ -532,14 +532,14 @@ static int __init offb_init(void)
 	}
 
 	for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
-		if (get_property(dp, "linux,opened", NULL) &&
-		    get_property(dp, "linux,boot-display", NULL)) {
+		if (of_get_property(dp, "linux,opened", NULL) &&
+		    of_get_property(dp, "linux,boot-display", NULL)) {
 			boot_disp = dp;
 			offb_init_nodriver(dp, 0);
 		}
 	}
 	for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
-		if (get_property(dp, "linux,opened", NULL) &&
+		if (of_get_property(dp, "linux,opened", NULL) &&
 		    dp != boot_disp)
 			offb_init_nodriver(dp, 0);
 	}
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 2338716..e64f8b5 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -28,7 +28,6 @@ #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/nvram.h>
 #include <asm/io.h>
 #include <asm/prom.h>
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index a560a22..1ac5264 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -81,8 +81,6 @@ static int lowvsync;
 struct pm2fb_par
 {
 	pm2type_t	type;		/* Board type */
-	u32		fb_size;	/* framebuffer memory size */
-	unsigned char	__iomem *v_fb;  /* virtual address of frame buffer */
 	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
 	u32 	   	memclock;	/* memclock */
 	u32		video;		/* video flags before blanking */
@@ -103,7 +101,7 @@ static struct fb_fix_screeninfo pm2fb_fi
 	.xpanstep =	1,
 	.ypanstep =	1,
 	.ywrapstep =	0, 
-	.accel =	FB_ACCEL_NONE,
+	.accel =	FB_ACCEL_3DLABS_PERMEDIA2,
 };
 
 /*
@@ -206,6 +204,17 @@ static inline void WAIT_FIFO(struct pm2f
 }
 #endif
 
+static void wait_pm2(struct pm2fb_par* par) {
+
+	WAIT_FIFO(par, 1);
+	pm2_WR(par, PM2R_SYNC, 0);
+	mb();
+	do {
+		while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
+		rmb();
+	} while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+}
+
 /*
  * partial products for the supported horizontal resolutions.
  */
@@ -302,10 +311,10 @@ static void pm2v_mnp(u32 clk, unsigned c
 	s32 delta = 1000;
 
 	*mm = *nn = *pp = 0;
-	for (n = 1; n; n++) {
-		for ( m = 1; m; m++) {
+	for ( m = 1; m < 128; m++) {
+		for (n = 2 * m + 1; n; n++) {
 			for ( p = 0; p < 2; p++) {
-				f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1)));
+				f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m;
 				if ( clk > f - delta && clk < f + delta ) {
 					delta = ( clk > f ) ? clk - f : f - clk;
 					*mm=m;
@@ -462,21 +471,43 @@ static void set_memclock(struct pm2fb_pa
 	int i;
 	unsigned char m, n, p;
 
-	pm2_mnp(clk, &m, &n, &p);
-	WAIT_FIFO(par, 10);
-	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
-	wmb();
-	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
-	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
-	wmb();
-	pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
-	wmb();
-	pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
-	rmb();
-	for (i = 256;
-	     i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
-	     i--)
-		;
+	switch (par->type) {
+	case PM2_TYPE_PERMEDIA2V:
+		pm2v_mnp(clk/2, &m, &n, &p);
+		WAIT_FIFO(par, 8);
+		pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
+		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
+		wmb();
+		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
+		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n);
+		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
+		wmb();
+		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
+		rmb();
+		for (i = 256;
+		     i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2);
+		     i--)
+			;
+		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+		break;
+	case PM2_TYPE_PERMEDIA2:
+		pm2_mnp(clk, &m, &n, &p);
+		WAIT_FIFO(par, 10);
+		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
+		wmb();
+		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
+		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
+		wmb();
+		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
+		wmb();
+		pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
+		rmb();
+		for (i = 256;
+		     i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
+		     i--)
+			;
+		break;
+	}
 }
 
 static void set_pixclock(struct pm2fb_par* par, u32 clk)
@@ -623,6 +654,8 @@ static int pm2fb_check_var(struct fb_var
 		return -EINVAL;
 	}
 
+	var->transp.offset = 0;
+	var->transp.length = 0;
 	switch(var->bits_per_pixel) {
 	case 8:
 		var->red.length = var->green.length = var->blue.length = 8;
@@ -1017,6 +1050,117 @@ static int pm2fb_blank(int blank_mode, s
 	return 0;
 }
 
+/*
+ * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
+ */
+static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+				s32 xsrc, s32 ysrc,
+				s32 x, s32 y, s32 w, s32 h,
+				u32 color) {
+
+	if (!w || !h)
+		return;
+	WAIT_FIFO(par, 6);
+	pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
+		PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
+	pm2_WR(par, PM2R_FB_PIXEL_OFFSET, 0);
+	if (copy)
+		pm2_WR(par, PM2R_FB_SOURCE_DELTA,
+			((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff));
+	else
+		pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
+	pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x);
+	pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w);
+	wmb();
+	pm2_WR(par, PM2R_RENDER,PM2F_RENDER_RECTANGLE |
+				(x<xsrc ? PM2F_INCREASE_X : 0) |
+				(y<ysrc ? PM2F_INCREASE_Y : 0) |
+				(copy ? 0 : PM2F_RENDER_FASTFILL));
+	wait_pm2(par);
+}
+
+static void pm2fb_fillrect (struct fb_info *info,
+				const struct fb_fillrect *region)
+{
+	struct pm2fb_par *par = info->par;
+	struct fb_fillrect modded;
+	int vxres, vyres;
+	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+		((u32*)info->pseudo_palette)[region->color] : region->color;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
+		region->rop != ROP_COPY ) {
+		cfb_fillrect(info, region);
+		return;
+	}
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	memcpy(&modded, region, sizeof(struct fb_fillrect));
+
+	if(!modded.width || !modded.height ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+
+	if(modded.dx + modded.width  > vxres)
+		modded.width  = vxres - modded.dx;
+	if(modded.dy + modded.height > vyres)
+		modded.height = vyres - modded.dy;
+
+	if(info->var.bits_per_pixel == 8)
+		color |= color << 8;
+	if(info->var.bits_per_pixel <= 16)
+		color |= color << 16;
+
+	if(info->var.bits_per_pixel != 24)
+		pm2fb_block_op(par, 0, 0, 0,
+				modded.dx, modded.dy,
+				modded.width, modded.height, color);
+	else
+		cfb_fillrect(info, region);
+}
+
+static void pm2fb_copyarea(struct fb_info *info,
+				const struct fb_copyarea *area)
+{
+	struct pm2fb_par *par = info->par;
+	struct fb_copyarea modded;
+	u32 vxres, vyres;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return;
+	if (info->flags & FBINFO_HWACCEL_DISABLED) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	memcpy(&modded, area, sizeof(struct fb_copyarea));
+
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+
+	if(!modded.width || !modded.height ||
+	   modded.sx >= vxres || modded.sy >= vyres ||
+	   modded.dx >= vxres || modded.dy >= vyres)
+		return;
+
+	if(modded.sx + modded.width > vxres)
+		modded.width = vxres - modded.sx;
+	if(modded.dx + modded.width > vxres)
+		modded.width = vxres - modded.dx;
+	if(modded.sy + modded.height > vyres)
+		modded.height = vyres - modded.sy;
+	if(modded.dy + modded.height > vyres)
+		modded.height = vyres - modded.dy;
+
+	pm2fb_block_op(par, 1, modded.sx, modded.sy,
+			modded.dx, modded.dy,
+			modded.width, modded.height, 0);
+}
+
 /* ------------ Hardware Independent Functions ------------ */
 
 /*
@@ -1030,8 +1174,8 @@ static struct fb_ops pm2fb_ops = {
 	.fb_setcolreg	= pm2fb_setcolreg,
 	.fb_blank	= pm2fb_blank,
 	.fb_pan_display	= pm2fb_pan_display,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
+	.fb_fillrect	= pm2fb_fillrect,
+	.fb_copyarea	= pm2fb_copyarea,
 	.fb_imageblit	= cfb_imageblit,
 };
 
@@ -1119,38 +1263,47 @@ #endif
 
 	if(default_par->mem_control == 0 &&
 		default_par->boot_address == 0x31 &&
-		default_par->mem_config == 0x259fffff &&
-		pdev->subsystem_vendor == 0x1048 &&
-		pdev->subsystem_device == 0x0a31) {
-		DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
-			pdev->subsystem_vendor, pdev->subsystem_device);
-		DPRINTK("We have not been initialized by VGA BIOS "
-			"and are running on an Elsa Winner 2000 Office\n");
-		DPRINTK("Initializing card timings manually...\n");
+		default_par->mem_config == 0x259fffff) {
+		default_par->memclock = CVPPC_MEMCLOCK;
 		default_par->mem_control=0;
 		default_par->boot_address=0x20;
 		default_par->mem_config=0xe6002021;
-		default_par->memclock=100000;
+		if (pdev->subsystem_vendor == 0x1048 &&
+			pdev->subsystem_device == 0x0a31) {
+			DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+				pdev->subsystem_vendor, pdev->subsystem_device);
+			DPRINTK("We have not been initialized by VGA BIOS "
+				"and are running on an Elsa Winner 2000 Office\n");
+			DPRINTK("Initializing card timings manually...\n");
+			default_par->memclock=70000;
+		}
+		if (pdev->subsystem_vendor == 0x3d3d &&
+			pdev->subsystem_device == 0x0100) {
+			DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+				pdev->subsystem_vendor, pdev->subsystem_device);
+			DPRINTK("We have not been initialized by VGA BIOS "
+				"and are running on an 3dlabs reference board\n");
+			DPRINTK("Initializing card timings manually...\n");
+			default_par->memclock=74894;
+		}
 	}
 
 	/* Now work out how big lfb is going to be. */
 	switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
 	case PM2F_MEM_BANKS_1:
-		default_par->fb_size=0x200000;
+		pm2fb_fix.smem_len=0x200000;
 		break;
 	case PM2F_MEM_BANKS_2:
-		default_par->fb_size=0x400000;
+		pm2fb_fix.smem_len=0x400000;
 		break;
 	case PM2F_MEM_BANKS_3:
-		default_par->fb_size=0x600000;
+		pm2fb_fix.smem_len=0x600000;
 		break;
 	case PM2F_MEM_BANKS_4:
-		default_par->fb_size=0x800000;
+		pm2fb_fix.smem_len=0x800000;
 		break;
 	}
-	default_par->memclock = CVPPC_MEMCLOCK;
 	pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
-	pm2fb_fix.smem_len = default_par->fb_size;
 
 	/* Linear frame buffer - request region and map it. */
 	if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
@@ -1158,9 +1311,9 @@ #endif
 		printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
 		goto err_exit_mmio;
 	}
-	info->screen_base = default_par->v_fb =
+	info->screen_base =
 		ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
-	if ( !default_par->v_fb ) {
+	if ( !info->screen_base ) {
 		printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
 		release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
 		goto err_exit_mmio;
@@ -1170,7 +1323,9 @@ #endif
 	info->fix		= pm2fb_fix; 	
 	info->pseudo_palette	= default_par->palette;
 	info->flags		= FBINFO_DEFAULT |
-                                  FBINFO_HWACCEL_YPAN;
+                                  FBINFO_HWACCEL_YPAN |
+	                          FBINFO_HWACCEL_COPYAREA |
+	                          FBINFO_HWACCEL_FILLRECT;
 
 	if (!mode)
 		mode = "640x480@60";
@@ -1180,13 +1335,13 @@ #endif
 		info->var = pm2fb_var;
 
 	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
-		goto err_exit_all;
+		goto err_exit_both;
 
 	if (register_framebuffer(info) < 0)
-		goto err_exit_both;
+		goto err_exit_all;
 
 	printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
-	       info->node, info->fix.id, default_par->fb_size / 1024);
+	       info->node, info->fix.id, pm2fb_fix.smem_len / 1024);
 
 	/*
 	 * Our driver data
@@ -1242,6 +1397,9 @@ static struct pci_device_id pm2fb_id_tab
 	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
 	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8,
+	  0xff00, 0 },
 	{ 0, }
 };
 
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 81e43cd..9756a72 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -32,6 +32,8 @@ #include <linux/console.h>
 #include <linux/ioctl.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 #include <linux/fb.h>
@@ -45,7 +47,7 @@ #include <asm/ps3fb.h>
 #include <asm/ps3.h>
 
 #ifdef PS3FB_DEBUG
-#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
@@ -129,7 +131,6 @@ struct ps3fb_priv {
 	u64 context_handle, memory_handle;
 	void *xdr_ea;
 	struct gpu_driver_info *dinfo;
-	struct semaphore sem;
 	u32 res_index;
 
 	u64 vblank_count;	/* frame count */
@@ -139,6 +140,8 @@ struct ps3fb_priv {
 	atomic_t ext_flip;	/* on/off flip with vsync */
 	atomic_t f_count;	/* fb_open count */
 	int is_blanked;
+	int is_kicked;
+	struct task_struct *task;
 };
 static struct ps3fb_priv ps3fb;
 
@@ -294,10 +297,10 @@ #define BPP	4		/* number of bytes per pi
 #define VP_OFF(i)	(WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
 #define FB_OFF(i)	(GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
 
-static int ps3fb_mode = 0;
+static int ps3fb_mode;
 module_param(ps3fb_mode, bool, 0);
 
-static char *mode_option __initdata = NULL;
+static char *mode_option __initdata;
 
 
 static int ps3fb_get_res_table(u32 xres, u32 yres)
@@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame)
 
 	if (frame > ps3fb.num_frames - 1) {
 		printk(KERN_WARNING "%s: invalid frame number (%u)\n",
-		       __FUNCTION__, frame);
+		       __func__, frame);
 		return -EINVAL;
 	}
 	offset = xres * yres * BPP * frame;
@@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame)
 					   (xres << 16) | yres,
 					   xres * BPP);	/* line_length */
 	if (status)
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+		       __func__, status);
 #ifdef HEAD_A
 	status = lv1_gpu_context_attribute(ps3fb.context_handle,
 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
 					   0, offset, 0, 0);
 	if (status)
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+		       __func__, status);
 #endif
 #ifdef HEAD_B
 	status = lv1_gpu_context_attribute(ps3fb.context_handle,
 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
 					   1, offset, 0, 0);
 	if (status)
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+		       __func__, status);
 #endif
 	return 0;
 }
@@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct
 {
 	int retval;
 
-	DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
+	DPRINTK("%s: blank:%d\n", __func__, blank);
 	switch (blank) {
 	case FB_BLANK_POWERDOWN:
 	case FB_BLANK_HSYNC_SUSPEND:
@@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
 
 void ps3fb_flip_ctl(int on)
 {
-	if (on) {
-		if (atomic_read(&ps3fb.ext_flip) > 0) {
-			atomic_dec(&ps3fb.ext_flip);
-		}
-	} else {
+	if (on)
+		atomic_dec_if_positive(&ps3fb.ext_flip);
+	else
 		atomic_inc(&ps3fb.ext_flip);
-	}
 }
 
 EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
@@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *i
 			if (copy_from_user(&val, argp, sizeof(val)))
 				break;
 
+			if (!(val & PS3AV_MODE_MASK)) {
+				u32 id = ps3av_get_auto_mode(0);
+				if (id > 0)
+					val = (val & ~PS3AV_MODE_MASK) | id;
+			}
 			DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
 			retval = -EINVAL;
 			old_mode = ps3fb_mode;
@@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *i
 
 	case PS3FB_IOCTL_OFF:
 		DPRINTK("PS3FB_IOCTL_OFF:\n");
-		if (atomic_read(&ps3fb.ext_flip) > 0)
-			atomic_dec(&ps3fb.ext_flip);
+		atomic_dec_if_positive(&ps3fb.ext_flip);
 		retval = 0;
 		break;
 
@@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *i
 
 static int ps3fbd(void *arg)
 {
-	daemonize("ps3fbd");
-	for (;;) {
-		down(&ps3fb.sem);
-		if (atomic_read(&ps3fb.ext_flip) == 0)
+	while (!kthread_should_stop()) {
+		try_to_freeze();
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (ps3fb.is_kicked) {
+			ps3fb.is_kicked = 0;
 			ps3fb_sync(0);	/* single buffer */
+		}
+		schedule();
 	}
 	return 0;
 }
@@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt
 	status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
 	if (status) {
 		printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
-		       __FUNCTION__, status);
+		       __func__, status);
 		return IRQ_NONE;
 	}
 
 	if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
 		/* VSYNC */
 		ps3fb.vblank_count = head->vblank_count;
-		if (!ps3fb.is_blanked)
-			up(&ps3fb.sem);
+		if (ps3fb.task && !ps3fb.is_blanked &&
+		    !atomic_read(&ps3fb.ext_flip)) {
+			ps3fb.is_kicked = 1;
+			wake_up_process(ps3fb.task);
+		}
 		wake_up_interruptible(&ps3fb.wait_vsync);
 	}
 
@@ -879,16 +892,16 @@ static int ps3fb_vsync_settings(struct g
 		dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
 
 	if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
-		printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
+		printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
 		       dinfo->version_driver);
 		return -EINVAL;
 	}
 
 	ps3fb.dev = dev;
-	error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
-			      &ps3fb.irq_no);
+	error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+				   &ps3fb.irq_no);
 	if (error) {
-		printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
+		printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
 		       error);
 		return error;
 	}
@@ -896,9 +909,9 @@ static int ps3fb_vsync_settings(struct g
 	error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
 			    "ps3fb vsync", ps3fb.dev);
 	if (error) {
-		printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
+		printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
 		       error);
-		ps3_free_irq(ps3fb.irq_no);
+		ps3_irq_plug_destroy(ps3fb.irq_no);
 		return error;
 	}
 
@@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lp
 				       xdr_lpar, ps3fb_videomemory.size, 0);
 	if (status) {
 		printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
-		       __FUNCTION__, status);
+		       __func__, status);
 		return -ENXIO;
 	}
 	DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
@@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lp
 					   xdr_lpar, ps3fb_videomemory.size,
 					   GPU_IOIF, 0);
 	if (status) {
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+		       __func__, status);
 		return -ENXIO;
 	}
 	return 0;
@@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct pla
 	u64 xdr_lpar;
 	int status;
 	unsigned long offset;
+	struct task_struct *task;
 
 	/* get gpu context handle */
 	status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
 					 &ps3fb.memory_handle, &ddr_lpar);
 	if (status) {
 		printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
-		       __FUNCTION__, status);
+		       __func__, status);
 		goto err;
 	}
 	DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
@@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct pla
 					  &lpar_reports, &lpar_reports_size);
 	if (status) {
 		printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
-		       __FUNCTION__, status);
+		       __func__, status);
 		goto err_gpu_memory_free;
 	}
 
 	/* vsync interrupt */
 	ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
 	if (!ps3fb.dinfo) {
-		printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
+		printk(KERN_ERR "%s: ioremap failed\n", __func__);
 		goto err_gpu_context_free;
 	}
 
@@ -1050,16 +1065,25 @@ static int __init ps3fb_probe(struct pla
 	       "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
 	       info->node, ps3fb_videomemory.size >> 10);
 
-	kernel_thread(ps3fbd, info, CLONE_KERNEL);
+	task = kthread_run(ps3fbd, info, "ps3fbd");
+	if (IS_ERR(task)) {
+		retval = PTR_ERR(task);
+		goto err_unregister_framebuffer;
+	}
+
+	ps3fb.task = task;
+
 	return 0;
 
+err_unregister_framebuffer:
+	unregister_framebuffer(info);
 err_fb_dealloc:
 	fb_dealloc_cmap(&info->cmap);
 err_framebuffer_release:
 	framebuffer_release(info);
 err_free_irq:
 	free_irq(ps3fb.irq_no, ps3fb.dev);
-	ps3_free_irq(ps3fb.irq_no);
+	ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
 	iounmap((u8 __iomem *)ps3fb.dinfo);
 err_gpu_context_free:
@@ -1075,7 +1099,7 @@ static void ps3fb_shutdown(struct platfo
 	ps3fb_flip_ctl(0);	/* flip off */
 	ps3fb.dinfo->irq.mask = 0;
 	free_irq(ps3fb.irq_no, ps3fb.dev);
-	ps3_free_irq(ps3fb.irq_no);
+	ps3_irq_plug_destroy(ps3fb.irq_no);
 	iounmap((u8 __iomem *)ps3fb.dinfo);
 }
 
@@ -1083,9 +1107,14 @@ void ps3fb_cleanup(void)
 {
 	int status;
 
+	if (ps3fb.task) {
+		struct task_struct *task = ps3fb.task;
+		ps3fb.task = NULL;
+		kthread_stop(task);
+	}
 	if (ps3fb.irq_no) {
 		free_irq(ps3fb.irq_no, ps3fb.dev);
-		ps3_free_irq(ps3fb.irq_no);
+		ps3_irq_plug_destroy(ps3fb.irq_no);
 	}
 	iounmap((u8 __iomem *)ps3fb.dinfo);
 
@@ -1137,8 +1166,9 @@ #ifdef HEAD_A
 					   L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
 					   0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
 	if (status) {
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
+		       __func__, status);
 		return -1;
 	}
 #endif
@@ -1148,8 +1178,9 @@ #ifdef HEAD_B
 					   1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
 
 	if (status) {
-		printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
-		       __FUNCTION__, status);
+		printk(KERN_ERR
+		       "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
+		       __func__, status);
 		return -1;
 	}
 #endif
@@ -1174,7 +1205,7 @@ #endif
 
 	error = ps3av_dev_open();
 	if (error) {
-		printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
+		printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
 		goto err;
 	}
 
@@ -1195,7 +1226,6 @@ #endif
 
 	atomic_set(&ps3fb.f_count, -1);	/* fbcon opens ps3fb */
 	atomic_set(&ps3fb.ext_flip, 0);	/* for flip with vsync */
-	init_MUTEX(&ps3fb.sem);
 	init_waitqueue_head(&ps3fb.wait_vsync);
 	ps3fb.num_frames = 1;
 
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index a93618b..df2909a 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -214,7 +214,7 @@ 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,
+static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
 			    size_t count, loff_t *ppos);
 #endif
 
@@ -674,7 +674,7 @@ static int pvr2_init_cable(void)
 }
 
 #ifdef CONFIG_SH_DMA
-static ssize_t pvr2fb_write(struct file *file, const char *buf,
+static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
 			    size_t count, loff_t *ppos)
 {
 	unsigned long dst, start, end, len;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index b4947c8..81e571d 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -803,7 +803,7 @@ static void pxafb_enable_controller(stru
 	pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
 
 	/* enable LCD controller clock */
-	pxa_set_cken(CKEN16_LCD, 1);
+	pxa_set_cken(CKEN_LCD, 1);
 
 	/* Sequence from 11.7.10 */
 	LCCR3 = fbi->reg_lccr3;
@@ -840,7 +840,7 @@ static void pxafb_disable_controller(str
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
 
 	/* disable LCD controller clock */
-	pxa_set_cken(CKEN16_LCD, 0);
+	pxa_set_cken(CKEN_LCD, 0);
 }
 
 /*
@@ -1203,7 +1203,7 @@ static int __init pxafb_parse_options(st
 					} else
 						goto done;
 					break;
-				case '0'...'9':
+				case '0' ... '9':
 					break;
 				default:
 					goto done;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index d7ece8d..0fe5478 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -317,15 +317,15 @@ static int riva_bl_update_status(struct 
 	else
 		level = bd->props.brightness;
 
-	tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
-	tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+	tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF;
+	tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC;
 	if(level > 0) {
 		tmp_pcrt |= 0x1;
 		tmp_pmc |= (1 << 31); /* backlight bit */
 		tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
 	}
-	par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
-	par->riva.PMC[0x10F0/4] = tmp_pmc;
+	NV_WR32(par->riva.PCRTC0, 0x081C, tmp_pcrt);
+	NV_WR32(par->riva.PMC, 0x10F0, tmp_pmc);
 
 	return 0;
 }
@@ -1760,13 +1760,13 @@ static int __devinit riva_get_EDID_OF(st
 	NVTRACE_ENTER();
 	dp = pci_device_to_OF_node(pd);
 	for (; dp != NULL; dp = dp->child) {
-		disptype = get_property(dp, "display-type", NULL);
+		disptype = of_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 = get_property(dp, propnames[i], NULL);
+			pedid = of_get_property(dp, propnames[i], NULL);
 			if (pedid != NULL) {
 				par->EDID = (unsigned char *)pedid;
 				NVTRACE("LCD found.\n");
@@ -1788,8 +1788,10 @@ static int __devinit riva_get_EDID_i2c(s
 
 	NVTRACE_ENTER();
 	riva_create_i2c_busses(par);
-	for (i = 0; i < par->bus; i++) {
-		riva_probe_i2c_connector(par, i+1, &par->EDID);
+	for (i = 0; i < 3; i++) {
+		if (!par->chan[i].par)
+			continue;
+		riva_probe_i2c_connector(par, i, &par->EDID);
 		if (par->EDID && !fb_parse_edid(par->EDID, &var)) {
 			printk(PFX "Found EDID Block from BUS %i\n", i);
 			break;
@@ -2104,7 +2106,7 @@ err_ret:
 	return ret;
 }
 
-static void __exit rivafb_remove(struct pci_dev *pd)
+static void __devexit rivafb_remove(struct pci_dev *pd)
 {
 	struct fb_info *info = pci_get_drvdata(pd);
 	struct riva_par *par = info->par;
@@ -2185,7 +2187,7 @@ static struct pci_driver rivafb_driver =
 	.name		= "rivafb",
 	.id_table	= rivafb_pci_tbl,
 	.probe		= rivafb_probe,
-	.remove		= __exit_p(rivafb_remove),
+	.remove		= __devexit_p(rivafb_remove),
 };
 
 
diff --git a/drivers/video/riva/nv4ref.h b/drivers/video/riva/nv4ref.h
deleted file mode 100644
index 3b5f911..0000000
--- a/drivers/video/riva/nv4ref.h
+++ /dev/null
@@ -1,2445 +0,0 @@
- /***************************************************************************\
-|*                                                                           *|
-|*       Copyright 1993-1998 NVIDIA, Corporation.  All rights reserved.      *|
-|*                                                                           *|
-|*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
-|*     international laws.  Users and possessors of this source code are     *|
-|*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
-|*     use this code in individual and commercial software.                  *|
-|*                                                                           *|
-|*     Any use of this source code must include,  in the user documenta-     *|
-|*     tion and  internal comments to the code,  notices to the end user     *|
-|*     as follows:                                                           *|
-|*                                                                           *|
-|*       Copyright 1993-1998 NVIDIA, Corporation.  All rights reserved.      *|
-|*                                                                           *|
-|*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
-|*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
-|*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
-|*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
-|*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
-|*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
-|*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
-|*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
-|*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
-|*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
-|*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
-|*                                                                           *|
-|*     U.S. Government  End  Users.   This source code  is a "commercial     *|
-|*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
-|*     consisting  of "commercial  computer  software"  and  "commercial     *|
-|*     computer  software  documentation,"  as such  terms  are  used in     *|
-|*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
-|*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
-|*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
-|*     all U.S. Government End Users  acquire the source code  with only     *|
-|*     those rights set forth herein.                                        *|
-|*                                                                           *|
- \***************************************************************************/
-
-/*
- * GPL licensing note -- nVidia is allowing a liberal interpretation of
- * the documentation restriction above, to merely say that this nVidia's
- * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
- */
-
- /***************************************************************************\
-|*            Modified 1999 by Fredrik Reite (fredrik@reite.com)             *|
- \***************************************************************************/
-
-
-#ifndef __NV4REF_H__
-#define __NV4REF_H__
-
-/* Magic values to lock/unlock extended regs */
-#define NV_CIO_SR_LOCK_INDEX				     0x0000001F /*       */
-#define NV_CIO_SR_UNLOCK_RW_VALUE                            0x00000057 /*       */
-#define NV_CIO_SR_UNLOCK_RO_VALUE                            0x00000075 /*       */
-#define NV_CIO_SR_LOCK_VALUE                                 0x00000099 /*       */
-
-#define UNLOCK_EXT_MAGIC 0x57
-#define LOCK_EXT_MAGIC 0x99 /* Any value other than 0x57 will do */
-
-#define LOCK_EXT_INDEX 0x6
-
-#define NV_PCRTC_HORIZ_TOTAL                                 0x00
-#define NV_PCRTC_HORIZ_DISPLAY_END                           0x01
-#define NV_PCRTC_HORIZ_BLANK_START                           0x02
-
-#define NV_PCRTC_HORIZ_BLANK_END                             0x03
-#define NV_PCRTC_HORIZ_BLANK_END_EVRA                        7:7
-#define NV_PCRTC_HORIZ_BLANK_END_DISPLAY_END_SKEW            6:5
-#define NV_PCRTC_HORIZ_BLANK_END_HORIZ_BLANK_END             4:0
-
-#define NV_PCRTC_HORIZ_RETRACE_START                         0x04
-
-#define NV_PCRTC_HORIZ_RETRACE_END                           0x05
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_BLANK_END_5         7:7
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_SKEW        6:5
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_END         4:0
-
-#define NV_PCRTC_VERT_TOTAL                                  0x06
-
-#define NV_PCRTC_OVERFLOW                                    0x07
-#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_9               7:7
-#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_9                 6:6
-#define NV_PCRTC_OVERFLOW_VERT_TOTAL_9                       5:5
-#define NV_PCRTC_OVERFLOW_LINE_COMPARE_8                     4:4
-#define NV_PCRTC_OVERFLOW_VERT_BLANK_START_8                 3:3
-#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_8               2:2
-#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_8                 1:1
-#define NV_PCRTC_OVERFLOW_VERT_TOTAL_8                       0:0
-
-#define NV_PCRTC_PRESET_ROW_SCAN                             0x08
-
-#define NV_PCRTC_MAX_SCAN_LINE                               0x09
-#define NV_PCRTC_MAX_SCAN_LINE_DOUBLE_SCAN                   7:7
-#define NV_PCRTC_MAX_SCAN_LINE_LINE_COMPARE_9                6:6
-#define NV_PCRTC_MAX_SCAN_LINE_VERT_BLANK_START_9            5:5
-#define NV_PCRTC_MAX_SCAN_LINE_MAX_SCAN_LINE                 4:0
-
-#define NV_PCRTC_CURSOR_START                                0x0A
-#define NV_PCRTC_CURSOR_END                                  0x0B
-#define NV_PCRTC_START_ADDR_HIGH                             0x0C
-#define NV_PCRTC_START_ADDR_LOW                              0x0D
-#define NV_PCRTC_CURSOR_LOCATION_HIGH                        0x0E
-#define NV_PCRTC_CURSOR_LOCATION_LOW                         0x0F
-
-#define NV_PCRTC_VERT_RETRACE_START                          0x10
-#define NV_PCRTC_VERT_RETRACE_END                            0x11
-#define NV_PCRTC_VERT_DISPLAY_END                            0x12
-#define NV_PCRTC_OFFSET                                      0x13
-#define NV_PCRTC_UNDERLINE_LOCATION                          0x14
-#define NV_PCRTC_VERT_BLANK_START                            0x15
-#define NV_PCRTC_VERT_BLANK_END                              0x16
-#define NV_PCRTC_MODE_CONTROL                                0x17
-#define NV_PCRTC_LINE_COMPARE                                0x18
-
-/* Extended offset and start address */
-#define NV_PCRTC_REPAINT0                                    0x19
-#define NV_PCRTC_REPAINT0_OFFSET_10_8                        7:5 
-#define NV_PCRTC_REPAINT0_START_ADDR_20_16                   4:0
-
-/* Horizonal extended bits */
-#define NV_PCRTC_HORIZ_EXTRA                                 0x2d
-#define NV_PCRTC_HORIZ_EXTRA_INTER_HALF_START_8              4:4
-#define NV_PCRTC_HORIZ_EXTRA_HORIZ_RETRACE_START_8           3:3
-#define NV_PCRTC_HORIZ_EXTRA_HORIZ_BLANK_START_8             2:2
-#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_END_8                   1:1
-#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_TOTAL_8                 0:0
-
-/* Assorted extra bits */
-#define NV_PCRTC_EXTRA                                       0x25
-#define NV_PCRTC_EXTRA_OFFSET_11                             5:5
-#define NV_PCRTC_EXTRA_HORIZ_BLANK_END_6                     4:4
-#define NV_PCRTC_EXTRA_VERT_BLANK_START_10                   3:3
-#define NV_PCRTC_EXTRA_VERT_RETRACE_START_10                 2:2
-#define NV_PCRTC_EXTRA_VERT_DISPLAY_END_10                   1:1
-#define NV_PCRTC_EXTRA_VERT_TOTAL_10                         0:0
-
-/* Controls how much data the refresh fifo requests */
-#define NV_PCRTC_FIFO_CONTROL                                0x1b
-#define NV_PCRTC_FIFO_CONTROL_UNDERFLOW_WARN                 7:7
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH                   2:0
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_8                 0x0
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_32                0x1
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_64                0x2
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_128               0x3
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_256               0x4
-
-/* When the fifo occupancy falls below *twice* the watermark,
- * the refresh fifo will start to be refilled. If this value is 
- * too low, you will get junk on the screen. Too high, and performance
- * will suffer. Watermark in units of 8 bytes
- */
-#define NV_PCRTC_FIFO                                        0x20
-#define NV_PCRTC_FIFO_RESET                                  7:7
-#define NV_PCRTC_FIFO_WATERMARK                              5:0
-
-/* Various flags */
-#define NV_PCRTC_REPAINT1                                    0x1a
-#define NV_PCRTC_REPAINT1_HSYNC                              7:7
-#define NV_PCRTC_REPAINT1_HYSNC_DISABLE                      0x01
-#define NV_PCRTC_REPAINT1_HYSNC_ENABLE                       0x00
-#define NV_PCRTC_REPAINT1_VSYNC                              6:6
-#define NV_PCRTC_REPAINT1_VYSNC_DISABLE                      0x01
-#define NV_PCRTC_REPAINT1_VYSNC_ENABLE                       0x00
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT                    4:4
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_ENABLE             0x01
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_DISABLE            0x00
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN                       2:2 
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN_DISABLE               0x01
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN_ENABLE                0x00 /* >=1280 */
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH                      1:1
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_8BITS                0x00
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_6BITS                0x01
-
-#define NV_PCRTC_GRCURSOR0                                   0x30
-#define NV_PCRTC_GRCURSOR0_START_ADDR_21_16                  5:0
-
-#define NV_PCRTC_GRCURSOR1                                   0x31
-#define NV_PCRTC_GRCURSOR1_START_ADDR_15_11                  7:3
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL                          1:1
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL_DISABLE                  0
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL_ENABLE                   1
-#define NV_PCRTC_GRCURSOR1_CURSOR                            0:0
-#define NV_PCRTC_GRCURSOR1_CURSOR_DISABLE                    0 
-#define NV_PCRTC_GRCURSOR1_CURSOR_ENABLE                     1
-
-/* Controls what the format of the framebuffer is */
-#define NV_PCRTC_PIXEL                       0x28
-#define NV_PCRTC_PIXEL_MODE                  7:7
-#define NV_PCRTC_PIXEL_MODE_TV               0x01
-#define NV_PCRTC_PIXEL_MODE_VGA              0x00
-#define NV_PCRTC_PIXEL_TV_MODE               6:6
-#define NV_PCRTC_PIXEL_TV_MODE_NTSC          0x00
-#define NV_PCRTC_PIXEL_TV_MODE_PAL           0x01
-#define NV_PCRTC_PIXEL_TV_HORIZ_ADJUST       5:3
-#define NV_PCRTC_PIXEL_FORMAT                1:0
-#define NV_PCRTC_PIXEL_FORMAT_VGA            0x00
-#define NV_PCRTC_PIXEL_FORMAT_8BPP           0x01
-#define NV_PCRTC_PIXEL_FORMAT_16BPP          0x02
-#define NV_PCRTC_PIXEL_FORMAT_32BPP          0x03
-
-/* RAMDAC registers and fields */
-#define NV_PRAMDAC                            0x00680FFF:0x00680000 /* RW--D */
-#define NV_PRAMDAC_GRCURSOR_START_POS                    0x00680300 /* RW-4R */
-#define NV_PRAMDAC_GRCURSOR_START_POS_X                        11:0 /* RWXSF */
-#define NV_PRAMDAC_GRCURSOR_START_POS_Y                       27:16 /* RWXSF */
-#define NV_PRAMDAC_NVPLL_COEFF                           0x00680500 /* RW-4R */
-#define NV_PRAMDAC_NVPLL_COEFF_MDIV                             7:0 /* RWIUF */
-#define NV_PRAMDAC_NVPLL_COEFF_NDIV                            15:8 /* RWIUF */
-#define NV_PRAMDAC_NVPLL_COEFF_PDIV                           18:16 /* RWIVF */
-#define NV_PRAMDAC_MPLL_COEFF                            0x00680504 /* RW-4R */
-#define NV_PRAMDAC_MPLL_COEFF_MDIV                              7:0 /* RWIUF */
-#define NV_PRAMDAC_MPLL_COEFF_NDIV                             15:8 /* RWIUF */
-#define NV_PRAMDAC_MPLL_COEFF_PDIV                            18:16 /* RWIVF */
-#define NV_PRAMDAC_VPLL_COEFF                            0x00680508 /* RW-4R */
-#define NV_PRAMDAC_VPLL_COEFF_MDIV                              7:0 /* RWIUF */
-#define NV_PRAMDAC_VPLL_COEFF_NDIV                             15:8 /* RWIUF */
-#define NV_PRAMDAC_VPLL_COEFF_PDIV                            18:16 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT                      0x0068050C /* RW-4R */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS                  4:4 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_FALSE     0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_TRUE      0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE                 8:8 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_DEFAULT  0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_PROG     0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS               12:12 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_FALSE    0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_TRUE     0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE               16:16 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_DEFAULT  0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_PROG     0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS               20:20 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_FALSE    0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_TRUE     0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE               25:24 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VPLL     0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VIP      0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_XTALOSC  0x00000002 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO                28:28 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB1       0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2       0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL                       0x00680600 /* RW-4R */
-#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF                     1:0 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF_DEF          0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE                     4:4 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_GAMMA        0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_INDEX        0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE                    8:8 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_NOTSE       0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL         0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE                   12:12 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_NOTSEL       0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_SEL          0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL                 16:16 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_OFF        0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_ON         0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION                17:17 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_37OHM     0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM     0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC                        20:20 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC_6BITS             0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS             0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP                  24:24 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_DIS         0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_EN          0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK                28:28 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_EN        0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_DIS       0x00000001 /* RW--V */
-
-/* Master Control */
-#define NV_PMC                                0x00000FFF:0x00000000 /* RW--D */
-#define NV_PMC_BOOT_0                                    0x00000000 /* R--4R */
-#define NV_PMC_BOOT_0_MINOR_REVISION                            3:0 /* C--VF */
-#define NV_PMC_BOOT_0_MINOR_REVISION_0                   0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MAJOR_REVISION                            7:4 /* C--VF */
-#define NV_PMC_BOOT_0_MAJOR_REVISION_A                   0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MAJOR_REVISION_B                   0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_IMPLEMENTATION                           11:8 /* C--VF */
-#define NV_PMC_BOOT_0_IMPLEMENTATION_NV4_0               0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_ARCHITECTURE                            15:12 /* C--VF */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV0                   0x00000000 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV1                   0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV2                   0x00000002 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV3                   0x00000003 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV4                   0x00000004 /* C---V */
-#define NV_PMC_BOOT_0_FIB_REVISION                            19:16 /* C--VF */
-#define NV_PMC_BOOT_0_FIB_REVISION_0                     0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MASK_REVISION                           23:20 /* C--VF */
-#define NV_PMC_BOOT_0_MASK_REVISION_A                    0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MASK_REVISION_B                    0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_MANUFACTURER                            27:24 /* C--UF */
-#define NV_PMC_BOOT_0_MANUFACTURER_NVIDIA                0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_FOUNDRY                                 31:28 /* C--VF */
-#define NV_PMC_BOOT_0_FOUNDRY_SGS                        0x00000000 /* ----V */
-#define NV_PMC_BOOT_0_FOUNDRY_HELIOS                     0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_FOUNDRY_TSMC                       0x00000002 /* C---V */
-#define NV_PMC_INTR_0                                    0x00000100 /* RW-4R */
-#define NV_PMC_INTR_0_PMEDIA                                    4:4 /* R--VF */
-#define NV_PMC_INTR_0_PMEDIA_NOT_PENDING                 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PMEDIA_PENDING                     0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PFIFO                                     8:8 /* R--VF */
-#define NV_PMC_INTR_0_PFIFO_NOT_PENDING                  0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PFIFO_PENDING                      0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PGRAPH                                  12:12 /* R--VF */
-#define NV_PMC_INTR_0_PGRAPH_NOT_PENDING                 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PGRAPH_PENDING                     0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PVIDEO                                  16:16 /* R--VF */
-#define NV_PMC_INTR_0_PVIDEO_NOT_PENDING                 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PVIDEO_PENDING                     0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PTIMER                                  20:20 /* R--VF */
-#define NV_PMC_INTR_0_PTIMER_NOT_PENDING                 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PTIMER_PENDING                     0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PCRTC                                   24:24 /* R--VF */
-#define NV_PMC_INTR_0_PCRTC_NOT_PENDING                  0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PCRTC_PENDING                      0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PBUS                                    28:28 /* R--VF */
-#define NV_PMC_INTR_0_PBUS_NOT_PENDING                   0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PBUS_PENDING                       0x00000001 /* R---V */
-#define NV_PMC_INTR_0_SOFTWARE                                31:31 /* RWIVF */
-#define NV_PMC_INTR_0_SOFTWARE_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PMC_INTR_0_SOFTWARE_PENDING                   0x00000001 /* RW--V */
-#define NV_PMC_INTR_EN_0                                 0x00000140 /* RW-4R */
-#define NV_PMC_INTR_EN_0_INTA                                   1:0 /* RWIVF */
-#define NV_PMC_INTR_EN_0_INTA_DISABLED                   0x00000000 /* RWI-V */
-#define NV_PMC_INTR_EN_0_INTA_HARDWARE                   0x00000001 /* RW--V */
-#define NV_PMC_INTR_EN_0_INTA_SOFTWARE                   0x00000002 /* RW--V */
-#define NV_PMC_INTR_READ_0                               0x00000160 /* R--4R */
-#define NV_PMC_INTR_READ_0_INTA                                 0:0 /* R--VF */
-#define NV_PMC_INTR_READ_0_INTA_LOW                      0x00000000 /* R---V */
-#define NV_PMC_INTR_READ_0_INTA_HIGH                     0x00000001 /* R---V */
-#define NV_PMC_ENABLE                                    0x00000200 /* RW-4R */
-#define NV_PMC_ENABLE_PMEDIA                                    4:4 /* RWIVF */
-#define NV_PMC_ENABLE_PMEDIA_DISABLED                    0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PMEDIA_ENABLED                     0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PFIFO                                     8:8 /* RWIVF */
-#define NV_PMC_ENABLE_PFIFO_DISABLED                     0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PFIFO_ENABLED                      0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PGRAPH                                  12:12 /* RWIVF */
-#define NV_PMC_ENABLE_PGRAPH_DISABLED                    0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PGRAPH_ENABLED                     0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PPMI                                    16:16 /* RWIVF */
-#define NV_PMC_ENABLE_PPMI_DISABLED                      0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PPMI_ENABLED                       0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PFB                                     20:20 /* RWIVF */
-#define NV_PMC_ENABLE_PFB_DISABLED                       0x00000000 /* RW--V */
-#define NV_PMC_ENABLE_PFB_ENABLED                        0x00000001 /* RWI-V */
-#define NV_PMC_ENABLE_PCRTC                                   24:24 /* RWIVF */
-#define NV_PMC_ENABLE_PCRTC_DISABLED                     0x00000000 /* RW--V */
-#define NV_PMC_ENABLE_PCRTC_ENABLED                      0x00000001 /* RWI-V */
-#define NV_PMC_ENABLE_PVIDEO                                  28:28 /* RWIVF */
-#define NV_PMC_ENABLE_PVIDEO_DISABLED                    0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PVIDEO_ENABLED                     0x00000001 /* RW--V */
-
-/* dev_timer.ref */
-#define NV_PTIMER                             0x00009FFF:0x00009000 /* RW--D */
-#define NV_PTIMER_INTR_0                                 0x00009100 /* RW-4R */
-#define NV_PTIMER_INTR_0_ALARM                                  0:0 /* RWXVF */
-#define NV_PTIMER_INTR_0_ALARM_NOT_PENDING               0x00000000 /* R---V */
-#define NV_PTIMER_INTR_0_ALARM_PENDING                   0x00000001 /* R---V */
-#define NV_PTIMER_INTR_0_ALARM_RESET                     0x00000001 /* -W--V */
-#define NV_PTIMER_INTR_EN_0                              0x00009140 /* RW-4R */
-#define NV_PTIMER_INTR_EN_0_ALARM                               0:0 /* RWIVF */
-#define NV_PTIMER_INTR_EN_0_ALARM_DISABLED               0x00000000 /* RWI-V */
-#define NV_PTIMER_INTR_EN_0_ALARM_ENABLED                0x00000001 /* RW--V */
-#define NV_PTIMER_NUMERATOR                              0x00009200 /* RW-4R */
-#define NV_PTIMER_NUMERATOR_VALUE                              15:0 /* RWIUF */
-#define NV_PTIMER_NUMERATOR_VALUE_0                      0x00000000 /* RWI-V */
-#define NV_PTIMER_DENOMINATOR                            0x00009210 /* RW-4R */
-#define NV_PTIMER_DENOMINATOR_VALUE                            15:0 /* RWIUF */
-#define NV_PTIMER_DENOMINATOR_VALUE_0                    0x00000000 /* RWI-V */
-#define NV_PTIMER_TIME_0                                 0x00009400 /* RW-4R */
-#define NV_PTIMER_TIME_0_NSEC                                  31:5 /* RWXUF */
-#define NV_PTIMER_TIME_1                                 0x00009410 /* RW-4R */
-#define NV_PTIMER_TIME_1_NSEC                                  28:0 /* RWXUF */
-#define NV_PTIMER_ALARM_0                                0x00009420 /* RW-4R */
-#define NV_PTIMER_ALARM_0_NSEC                                 31:5 /* RWXUF */
-
-/* dev_fifo.ref */
-#define NV_PFIFO                              0x00003FFF:0x00002000 /* RW--D */
-#define NV_PFIFO_DELAY_0                                 0x00002040 /* RW-4R */
-#define NV_PFIFO_DELAY_0_WAIT_RETRY                             9:0 /* RWIUF */
-#define NV_PFIFO_DELAY_0_WAIT_RETRY_0                    0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_TIMESLICE                           0x00002044 /* RW-4R */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT                          16:0 /* RWIUF */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_1                  0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_16K                0x00003fff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_32K                0x00007fff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_64K                0x0000ffff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_128K               0x0001ffff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT                        24:24 /* RWIUF */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_DISABLED          0x00000000 /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_ENABLED           0x00000001 /* RWI-V */
-#define NV_PFIFO_PIO_TIMESLICE                           0x00002048 /* RW-4R */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT                          16:0 /* RWIUF */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_1                  0x00000000 /* RWI-V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_16K                0x00003fff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_32K                0x00007fff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_64K                0x0000ffff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_128K               0x0001ffff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT                        24:24 /* RWIUF */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_DISABLED          0x00000000 /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_ENABLED           0x00000001 /* RWI-V */
-#define NV_PFIFO_TIMESLICE                               0x0000204C /* RW-4R */
-#define NV_PFIFO_TIMESLICE_TIMER                               17:0 /* RWIUF */
-#define NV_PFIFO_TIMESLICE_TIMER_EXPIRED                 0x0003FFFF /* RWI-V */
-#define NV_PFIFO_NEXT_CHANNEL                            0x00002050 /* RW-4R */
-#define NV_PFIFO_NEXT_CHANNEL_CHID                              3:0 /* RWXUF */
-#define NV_PFIFO_NEXT_CHANNEL_MODE                              8:8 /* RWXVF */
-#define NV_PFIFO_NEXT_CHANNEL_MODE_PIO                   0x00000000 /* RW--V */
-#define NV_PFIFO_NEXT_CHANNEL_MODE_DMA                   0x00000001 /* RW--V */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH                          12:12 /* RWIVF */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH_NOT_PENDING         0x00000000 /* RWI-V */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH_PENDING             0x00000001 /* RW--V */
-#define NV_PFIFO_DEBUG_0                                 0x00002080 /* R--4R */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0                           0:0 /* R-XVF */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_NOT_PENDING        0x00000000 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_PENDING            0x00000001 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1                           4:4 /* R-XVF */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_NOT_PENDING        0x00000000 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_PENDING            0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0                                  0x00002100 /* RW-4R */
-#define NV_PFIFO_INTR_0_CACHE_ERROR                             0:0 /* RWXVF */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_NOT_PENDING          0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_PENDING              0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_RESET                0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_RUNOUT                                  4:4 /* RWXVF */
-#define NV_PFIFO_INTR_0_RUNOUT_NOT_PENDING               0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_PENDING                   0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_RESET                     0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW                         8:8 /* RWXVF */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_NOT_PENDING      0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_PENDING          0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_RESET            0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER                            12:12 /* RWXVF */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_NOT_PENDING           0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_PENDING               0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_RESET                 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_DMA_PT                                16:16 /* RWXVF */
-#define NV_PFIFO_INTR_0_DMA_PT_NOT_PENDING               0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PT_PENDING                   0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PT_RESET                     0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_EN_0                               0x00002140 /* RW-4R */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR                          0:0 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_DISABLED          0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_ENABLED           0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT                               4:4 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_DISABLED               0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_ENABLED                0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW                      8:8 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_DISABLED      0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_ENABLED       0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER                         12:12 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_DISABLED           0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_ENABLED            0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_DMA_PT                             16:16 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_DMA_PT_DISABLED               0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_DMA_PT_ENABLED                0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT                                   0x00002210 /* RW-4R */
-#define NV_PFIFO_RAMHT_BASE_ADDRESS                             8:4 /* RWIUF */
-#define NV_PFIFO_RAMHT_BASE_ADDRESS_10000                0x00000010 /* RWI-V */
-#define NV_PFIFO_RAMHT_SIZE                                   17:16 /* RWIUF */
-#define NV_PFIFO_RAMHT_SIZE_4K                           0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMHT_SIZE_8K                           0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT_SIZE_16K                          0x00000002 /* RW--V */
-#define NV_PFIFO_RAMHT_SIZE_32K                          0x00000003 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH                                 25:24 /* RWIUF */
-#define NV_PFIFO_RAMHT_SEARCH_16                         0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMHT_SEARCH_32                         0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH_64                         0x00000002 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH_128                        0x00000003 /* RW--V */
-#define NV_PFIFO_RAMFC                                   0x00002214 /* RW-4R */
-#define NV_PFIFO_RAMFC_BASE_ADDRESS                             8:1 /* RWIUF */
-#define NV_PFIFO_RAMFC_BASE_ADDRESS_11000                0x00000088 /* RWI-V */
-#define NV_PFIFO_RAMRO                                   0x00002218 /* RW-4R */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS                             8:1 /* RWIUF */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS_11200                0x00000089 /* RWI-V */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS_12000                0x00000090 /* RW--V */
-#define NV_PFIFO_RAMRO_SIZE                                   16:16 /* RWIVF */
-#define NV_PFIFO_RAMRO_SIZE_512                          0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMRO_SIZE_8K                           0x00000001 /* RW--V */
-#define NV_PFIFO_CACHES                                  0x00002500 /* RW-4R */
-#define NV_PFIFO_CACHES_REASSIGN                                0:0 /* RWIVF */
-#define NV_PFIFO_CACHES_REASSIGN_DISABLED                0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHES_REASSIGN_ENABLED                 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHES_DMA_SUSPEND                             4:4 /* R--VF */
-#define NV_PFIFO_CACHES_DMA_SUSPEND_IDLE                 0x00000000 /* R---V */
-#define NV_PFIFO_CACHES_DMA_SUSPEND_BUSY                 0x00000001 /* R---V */
-#define NV_PFIFO_MODE                                    0x00002504 /* RW-4R */
-#define NV_PFIFO_MODE_CHANNEL_0                                 0:0 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_0_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_0_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_1                                 1:1 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_1_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_1_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_2                                 2:2 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_2_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_2_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_3                                 3:3 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_3_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_3_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_4                                 4:4 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_4_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_4_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_5                                 5:5 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_5_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_5_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_6                                 6:6 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_6_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_6_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_7                                 7:7 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_7_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_7_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_8                                 8:8 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_8_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_8_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_9                                 9:9 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_9_PIO                      0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_9_DMA                      0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_10                              10:10 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_10_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_10_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_11                              11:11 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_11_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_11_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_12                              12:12 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_12_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_12_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_13                              13:13 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_13_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_13_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_14                              14:14 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_14_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_14_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_15                              15:15 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_15_PIO                     0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_15_DMA                     0x00000001 /* RW--V */
-#define NV_PFIFO_DMA                                     0x00002508 /* RW-4R */
-#define NV_PFIFO_DMA_CHANNEL_0                                  0:0 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_0_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_0_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_1                                  1:1 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_1_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_1_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_2                                  2:2 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_2_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_2_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_3                                  3:3 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_3_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_3_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_4                                  4:4 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_4_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_4_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_5                                  5:5 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_5_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_5_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_6                                  6:6 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_6_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_6_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_7                                  7:7 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_7_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_7_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_8                                  8:8 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_8_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_8_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_9                                  9:9 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_9_NOT_PENDING               0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_9_PENDING                   0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_10                               10:10 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_10_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_10_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_11                               11:11 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_11_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_11_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_12                               12:12 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_12_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_12_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_13                               13:13 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_13_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_13_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_14                               14:14 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_14_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_14_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_15                               15:15 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_15_NOT_PENDING              0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_15_PENDING                  0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE                                    0x0000250C /* RW-4R */
-#define NV_PFIFO_SIZE_CHANNEL_0                                 0:0 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_0_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_0_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_1                                 1:1 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_1_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_1_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_2                                 2:2 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_2_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_2_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_3                                 3:3 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_3_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_3_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_4                                 4:4 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_4_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_4_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_5                                 5:5 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_5_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_5_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_6                                 6:6 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_6_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_6_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_7                                 7:7 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_7_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_7_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_8                                 8:8 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_8_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_8_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_9                                 9:9 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_9_124_BYTES                0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_9_512_BYTES                0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_10                              10:10 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_10_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_10_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_11                              11:11 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_11_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_11_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_12                              12:12 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_12_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_12_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_13                              13:13 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_13_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_13_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_14                              14:14 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_14_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_14_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_15                              15:15 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_15_124_BYTES               0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_15_512_BYTES               0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PUSH0                            0x00003000 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS                            0:0 /* RWIVF */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS_DISABLED            0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS_ENABLED             0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PUSH0                            0x00003200 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS                            0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS_DISABLED            0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS_ENABLED             0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PUSH1                            0x00003004 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUSH1_CHID                              3:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUSH1                            0x00003204 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUSH1_CHID                              3:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUSH1_MODE                              8:8 /* RWIVF */
-#define NV_PFIFO_CACHE1_PUSH1_MODE_PIO                   0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PUSH1_MODE_DMA                   0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUSH                         0x00003220 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS                         0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_DISABLED         0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_ENABLED          0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE                          4:4 /* R--VF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_IDLE              0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_BUSY              0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER                         8:8 /* R--VF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_NOT_EMPTY        0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_EMPTY            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS                       12:12 /* RWIVF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_RUNNING          0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_SUSPENDED        0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH                        0x00003224 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG                          7:3 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES           0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES          0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES          0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES          0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES          0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES          0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES          0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES          0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES          0x00000008 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES          0x00000009 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES          0x0000000A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES          0x0000000B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES         0x0000000C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES         0x0000000D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES         0x0000000E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES         0x0000000F /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES         0x00000010 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES         0x00000011 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES         0x00000012 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES         0x00000013 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES         0x00000014 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES         0x00000015 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES         0x00000016 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES         0x00000017 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES         0x00000018 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES         0x00000019 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES         0x0000001A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES         0x0000001B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES         0x0000001C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES         0x0000001D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES         0x0000001E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES         0x0000001F /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE                        15:13 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES          0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES          0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES          0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES         0x00000003 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES         0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES         0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES         0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES         0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS                    19:16 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0             0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1             0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2             0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3             0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4             0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5             0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6             0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7             0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8             0x00000008 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9             0x00000009 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10            0x0000000A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11            0x0000000B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12            0x0000000C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13            0x0000000D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14            0x0000000E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15            0x0000000F /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUT                          0x00003240 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_PUT_OFFSET                         28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_GET                          0x00003244 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_GET_OFFSET                         28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE                        0x00003228 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD                       12:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL                  15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT                28:18 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT_0         0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR                       31:30 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE             0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NON_CACHE        0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION       0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_INSTANCE                     0x0000322C /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS                   15:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL                          0x00003230 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_CTL_ADJUST                         11:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE                    12:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY                    13:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE                   17:16 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_PCI          0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_AGP          0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO                       31:31 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_INVALID          0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_VALID            0x00000001 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_LIMIT                        0x00003234 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_LIMIT_OFFSET                       28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG                      0x00003238 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_ADDRESS                   28:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE                       0:0 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_INVALID        0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_VALID          0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_TLB_PTE                      0x0000323C /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_TLB_PTE_FRAME_ADDRESS             31:12 /* RWXUF */
-#define NV_PFIFO_CACHE0_PULL0                            0x00003050 /* RW-4R */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS                            0:0 /* RWIVF */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS_DISABLED            0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS_ENABLED             0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL0_HASH                              4:4 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_HASH_SUCCEEDED             0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_FAILED                0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE                            8:8 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE_HARDWARE            0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE_SOFTWARE            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE                      12:12 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_IDLE            0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_BUSY            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0                            0x00003250 /* RW-4R */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS                            0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS_DISABLED            0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS_ENABLED             0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL0_HASH                              4:4 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_HASH_SUCCEEDED             0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_FAILED                0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE                            8:8 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE_HARDWARE            0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE_SOFTWARE            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE                      12:12 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_IDLE            0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_BUSY            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL1                            0x00003054 /* RW-4R */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE                            1:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_SW                  0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_GRAPHICS            0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_DVD                 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1                            0x00003254 /* RW-4R */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE                            1:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_SW                  0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_GRAPHICS            0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_DVD                 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_HASH                             0x00003058 /* RW-4R */
-#define NV_PFIFO_CACHE0_HASH_INSTANCE                          15:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_HASH_VALID                            16:16 /* RWXVF */
-#define NV_PFIFO_CACHE1_HASH                             0x00003258 /* RW-4R */
-#define NV_PFIFO_CACHE1_HASH_INSTANCE                          15:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_HASH_VALID                            16:16 /* RWXVF */
-#define NV_PFIFO_CACHE0_STATUS                           0x00003014 /* R--4R */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK                         4:4 /* R--VF */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK                        8:8 /* R--VF */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS                           0x00003214 /* R--4R */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK                         4:4 /* R--VF */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK                        8:8 /* R--VF */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS1                          0x00003218 /* R--4R */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT                          0:0 /* R-XVF */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT_FALSE             0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT_TRUE              0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PUT                              0x00003010 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUT_ADDRESS                             2:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUT                              0x00003210 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUT_ADDRESS                             9:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_GET                              0x00003070 /* RW-4R */
-#define NV_PFIFO_CACHE0_GET_ADDRESS                             2:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_GET                              0x00003270 /* RW-4R */
-#define NV_PFIFO_CACHE1_GET_ADDRESS                             9:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE                           0x00003080 /* RW-4R */
-#define NV_PFIFO_CACHE0_ENGINE_0                                1:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_0_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_0_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_0_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1                                5:4 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_1_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2                                9:8 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_2_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3                              13:12 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_3_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4                              17:16 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_4_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5                              21:20 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_5_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6                              25:24 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_6_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7                              29:28 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_7_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE                           0x00003280 /* RW-4R */
-#define NV_PFIFO_CACHE1_ENGINE_0                                1:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_0_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_0_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_0_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1                                5:4 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_1_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2                                9:8 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_2_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3                              13:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_3_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4                              17:16 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_4_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5                              21:20 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_5_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6                              25:24 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_6_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7                              29:28 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_7_SW                      0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7_GRAPHICS                0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7_DVD                     0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_METHOD(i)                (0x00003100+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE0_METHOD__SIZE_1                            1 /*       */
-#define NV_PFIFO_CACHE0_METHOD_ADDRESS                         12:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_METHOD_SUBCHANNEL                     15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD(i)                (0x00003800+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_METHOD__SIZE_1                          128 /*       */
-#define NV_PFIFO_CACHE1_METHOD_ADDRESS                         12:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD_SUBCHANNEL                     15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD_ALIAS(i)          (0x00003C00+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_METHOD_ALIAS__SIZE_1                    128 /*       */
-#define NV_PFIFO_CACHE0_DATA(i)                  (0x00003104+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE0_DATA__SIZE_1                              1 /*       */
-#define NV_PFIFO_CACHE0_DATA_VALUE                             31:0 /* RWXVF */
-#define NV_PFIFO_CACHE1_DATA(i)                  (0x00003804+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_DATA__SIZE_1                            128 /*       */
-#define NV_PFIFO_CACHE1_DATA_VALUE                             31:0 /* RWXVF */
-#define NV_PFIFO_CACHE1_DATA_ALIAS(i)            (0x00003C04+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_DATA_ALIAS__SIZE_1                      128 /*       */
-#define NV_PFIFO_DEVICE(i)                       (0x00002800+(i)*4) /* R--4A */
-#define NV_PFIFO_DEVICE__SIZE_1                                 128 /*       */
-#define NV_PFIFO_DEVICE_CHID                                    3:0 /* R--UF */
-#define NV_PFIFO_DEVICE_SWITCH                                24:24 /* R--VF */
-#define NV_PFIFO_DEVICE_SWITCH_UNAVAILABLE               0x00000000 /* R---V */
-#define NV_PFIFO_DEVICE_SWITCH_AVAILABLE                 0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS                           0x00002400 /* R--4R */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT                           0:0 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT_FALSE              0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT_TRUE               0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK                         4:4 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_NOT_EMPTY        0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_EMPTY            0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK                        8:8 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_NOT_FULL        0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_FULL            0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_PUT                              0x00002410 /* RW-4R */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS                            12:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_0                     8:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_1                    12:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_GET                              0x00002420 /* RW-4R */
-#define NV_PFIFO_RUNOUT_GET_ADDRESS                            13:3 /* RWXUF */
-/* dev_graphics.ref */
-#define NV_PGRAPH                             0x00401FFF:0x00400000 /* RW--D */
-#define NV_PGRAPH_DEBUG_0                                0x00400080 /* RW-4R */
-#define NV_PGRAPH_DEBUG_1                                0x00400084 /* RW-4R */
-#define NV_PGRAPH_DEBUG_2                                0x00400088 /* RW-4R */
-#define NV_PGRAPH_DEBUG_3                                0x0040008C /* RW-4R */
-#define NV_PGRAPH_INTR                                   0x00400100 /* RW-4R */
-#define NV_PGRAPH_INTR_NOTIFY                                   0:0 /* RWIVF */
-#define NV_PGRAPH_INTR_NOTIFY_NOT_PENDING                0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_NOTIFY_PENDING                    0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_NOTIFY_RESET                      0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_MISSING_HW                               4:4 /* RWIVF */
-#define NV_PGRAPH_INTR_MISSING_HW_NOT_PENDING            0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_MISSING_HW_PENDING                0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_MISSING_HW_RESET                  0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A                            8:8 /* RWIVF */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_RESET               0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B                            9:9 /* RWIVF */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_RESET               0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH                         12:12 /* RWIVF */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_NOT_PENDING        0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_PENDING            0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_RESET              0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY                          16:16 /* RWIVF */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_RESET               0x00000001 /* -W--C */
-#define NV_PGRAPH_NSTATUS                                0x00400104 /* RW-4R */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE                        11:11 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE_NOT_PENDING       0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE_PENDING           0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE                       12:12 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE_NOT_PENDING      0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE_PENDING          0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT                        13:13 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_NOT_PENDING       0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_PENDING           0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT                    14:14 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_NOT_PENDING   0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_PENDING       0x00000001 /* RW--V */
-#define NV_PGRAPH_NSOURCE                                0x00400108 /* R--4R */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION                          0:0 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION_NOT_PENDING       0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION_PENDING           0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR                            1:1 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR                      2:2 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_NOT_PENDING   0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_PENDING       0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION                       3:3 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_NOT_PENDING    0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_PENDING        0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR                           4:4 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_NOT_PENDING        0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_PENDING            0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_                           5:5 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD                          6:6 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_NOT_PENDING       0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_PENDING           0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION                      7:7 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_NOT_PENDING   0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_PENDING       0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION                      8:8 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_NOT_PENDING   0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_PENDING       0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION                      9:9 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_NOT_PENDING   0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_PENDING       0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION                     10:10 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_NOT_PENDING    0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_PENDING        0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID                       11:11 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID_NOT_PENDING      0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID_PENDING          0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY                       12:12 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_NOT_PENDING      0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_PENDING          0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE                       13:13 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_NOT_PENDING      0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_PENDING          0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT                          14:14 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT_NOT_PENDING         0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT_PENDING             0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION                    15:15 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_NOT_PENDING   0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_PENDING       0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_EN                                0x00400140 /* RW-4R */
-#define NV_PGRAPH_INTR_EN_NOTIFY                                0:0 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_NOTIFY_DISABLED                0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_NOTIFY_ENABLED                 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_MISSING_HW                            4:4 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_MISSING_HW_DISABLED            0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_MISSING_HW_ENABLED             0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A                         8:8 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_DISABLED         0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_ENABLED          0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B                         9:9 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_DISABLED         0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_ENABLED          0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH                      12:12 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_DISABLED        0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_ENABLED         0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY                       16:16 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_DISABLED         0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_ENABLED          0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1                            0x00400160 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH1_GRCLASS                           7:0 /* RWXVF */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY                      12:12 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_DISABLE         0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_ENABLE          0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP                       13:13 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_DISABLE          0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_ENABLE           0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE                         14:14 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_DISABLE            0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_ENABLE             0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG                    17:15 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_AND   0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_ROP_AND       0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_AND     0x00000002 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY       0x00000003 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_PRE   0x00000004 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_PRE     0x00000005 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS                    24:24 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_INVALID       0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_VALID         0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE                 25:25 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_INVALID    0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_VALID      0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET                  31:31 /* CWIVF */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_IGNORE      0x00000000 /* CWI-V */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_ENABLED     0x00000001 /* -W--T */
-#define NV_PGRAPH_CTX_SWITCH2                            0x00400164 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT                       1:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_INVALID              0x00 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_CGA6_M1              0x01 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_LE_M1                0x02 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT                     13:8 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_INVALID             0x00 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y8               0x01 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A8Y8          0x02 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X24Y8            0x03 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A1R5G5B5         0x06 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X1R5G5B5         0x07 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A1R5G5B5      0x08 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X17R5G5B5        0x09 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_R5G6B5           0x0A /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16R5G6B5        0x0B /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16R5G6B5        0x0C /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A8R8G8B8         0x0D /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X8R8G8B8         0x0E /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y16              0x0F /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16Y16           0x10 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16Y16           0x11 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_V8YB8U8YA8       0x12 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_YB8V8YA8U8       0x13 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y32              0x14 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE                 31:16 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE_INVALID        0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH3                            0x00400168 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0                   15:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0_INVALID         0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1                  31:16 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1_INVALID         0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH4                            0x0040016C /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE                    15:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE_INVALID          0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_CACHE1(i)                  (0x00400180+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE1__SIZE_1                              8 /*       */
-#define NV_PGRAPH_CTX_CACHE1_GRCLASS                            7:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_CHROMA_KEY                       12:12 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_USER_CLIP                        13:13 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_SWIZZLE                          14:14 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_PATCH_CONFIG                     19:15 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_SPARE1                           20:20 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_PATCH_STATUS                     24:24 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_CONTEXT_SURFACE                  25:25 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2(i)                  (0x004001a0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE2__SIZE_1                              8 /*       */
-#define NV_PGRAPH_CTX_CACHE2_MONO_FORMAT                        1:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2_COLOR_FORMAT                      13:8 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2_NOTIFY_INSTANCE                  31:16 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE3(i)                  (0x004001c0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE3__SIZE_1                              8 /*       */
-#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_0                    15:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_1                   31:16 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE4(i)                  (0x004001e0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE4__SIZE_1                              8 /*       */
-#define NV_PGRAPH_CTX_CACHE4_USER_INSTANCE                     15:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CONTROL                            0x00400170 /* RW-4R */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME                      1:0 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_33US          0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_262US         0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_2MS           0x00000002 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_17MS          0x00000003 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_TIME                              8:8 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_TIME_EXPIRED               0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_TIME_NOT_EXPIRED           0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_CHID                            16:16 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_CHID_INVALID               0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_CHID_VALID                 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE                          20:20 /* R--VF */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE_UNAVAILABLE         0x00000000 /* R---V */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE_AVAILABLE           0x00000001 /* R---V */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING                       24:24 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING_IDLE             0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING_BUSY             0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE                          28:28 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE_DISABLED            0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE_ENABLED             0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_USER                               0x00400174 /* RW-4R */
-#define NV_PGRAPH_CTX_USER_SUBCH                              15:13 /* RWIVF */
-#define NV_PGRAPH_CTX_USER_SUBCH_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_USER_CHID                               27:24 /* RWIVF */
-#define NV_PGRAPH_CTX_USER_CHID_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_FIFO                                   0x00400720 /* RW-4R */
-#define NV_PGRAPH_FIFO_ACCESS                                   0:0 /* RWIVF */
-#define NV_PGRAPH_FIFO_ACCESS_DISABLED                   0x00000000 /* RW--V */
-#define NV_PGRAPH_FIFO_ACCESS_ENABLED                    0x00000001 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_FIFO_0(i)              (0x00400730+(i)*4) /* RW-4A */
-#define NV_PGRAPH_FFINTFC_FIFO_0__SIZE_1                          4 /*       */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG                            0:0 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_MTHD                0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_CHSW                0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH                          3:1 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_0                 0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_1                 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_2                 0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_3                 0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_4                 0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_5                 0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_6                 0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_7                 0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD                          14:4 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD_CTX_SWITCH         0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_1(i)              (0x00400740+(i)*4) /* RW-4A */
-#define NV_PGRAPH_FFINTFC_FIFO_1__SIZE_1                          4 /*       */
-#define NV_PGRAPH_FFINTFC_FIFO_1_ARGUMENT                      31:0 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR                       0x00400750 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE                        2:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE_0               0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ                         6:4 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ_0                0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2                            0x00400754 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS                            0:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS_INVALID             0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS_VALID               0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_MTHD                             11:1 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_MTHD_CTX_SWITCH            0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH                           14:12 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_0                    0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_1                    0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_2                    0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_3                    0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_4                    0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_5                    0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_6                    0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_7                    0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID                            18:15 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_1                     0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_2                     0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_3                     0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_4                     0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_5                     0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_6                     0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_7                     0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_8                     0x00000008 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_9                     0x00000009 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_10                    0x0000000A /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_11                    0x0000000B /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_12                    0x0000000C /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_13                    0x0000000D /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_14                    0x0000000E /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_15                    0x0000000F /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS                     19:19 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_INVALID        0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_VALID          0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_D                          0x00400758 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT                       31:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT_0               0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATUS                                 0x00400700 /* R--4R */
-#define NV_PGRAPH_STATUS_STATE                                  0:0 /* R-IVF */
-#define NV_PGRAPH_STATUS_STATE_IDLE                      0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_STATE_BUSY                      0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_XY_LOGIC                               4:4 /* R-IVF */
-#define NV_PGRAPH_STATUS_XY_LOGIC_IDLE                   0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_XY_LOGIC_BUSY                   0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_FE                                     5:5 /* R-IVF */
-#define NV_PGRAPH_STATUS_FE_IDLE                         0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_FE_BUSY                         0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_RASTERIZER                             6:6 /* R-IVF */
-#define NV_PGRAPH_STATUS_RASTERIZER_IDLE                 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_RASTERIZER_BUSY                 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY                            8:8 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY_IDLE                0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY_BUSY                0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_REGISTER                        12:12 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_REGISTER_IDLE              0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_REGISTER_BUSY              0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_DMA                             16:16 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_DMA_IDLE                   0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_DMA_BUSY                   0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_ENGINE                           17:17 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_ENGINE_IDLE                 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_ENGINE_BUSY                 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY                           20:20 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY_IDLE                 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY_BUSY                 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY                    21:21 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_IDLE          0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_BUSY          0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_D3D                                  24:24 /* R-IVF */
-#define NV_PGRAPH_STATUS_D3D_IDLE                        0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_D3D_BUSY                        0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_CACHE                                25:25 /* R-IVF */
-#define NV_PGRAPH_STATUS_CACHE_IDLE                      0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_CACHE_BUSY                      0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_LIGHTING                             26:26 /* R-IVF */
-#define NV_PGRAPH_STATUS_LIGHTING_IDLE                   0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_LIGHTING_BUSY                   0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PREROP                               27:27 /* R-IVF */
-#define NV_PGRAPH_STATUS_PREROP_IDLE                     0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PREROP_BUSY                     0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_ROP                                  28:28 /* R-IVF */
-#define NV_PGRAPH_STATUS_ROP_IDLE                        0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_ROP_BUSY                        0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_USER                            29:29 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_USER_IDLE                  0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_USER_BUSY                  0x00000001 /* R---V */
-#define NV_PGRAPH_TRAPPED_ADDR                           0x00400704 /* R--4R */
-#define NV_PGRAPH_TRAPPED_ADDR_MTHD                            12:2 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_ADDR_SUBCH                          15:13 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_ADDR_CHID                           27:24 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_DATA                           0x00400708 /* R--4R */
-#define NV_PGRAPH_TRAPPED_DATA_VALUE                           31:0 /* R-XVF */
-#define NV_PGRAPH_SURFACE                                0x0040070C /* RW-4R */
-#define NV_PGRAPH_SURFACE_TYPE                                  1:0 /* RWIVF */
-#define NV_PGRAPH_SURFACE_TYPE_INVALID                   0x00000000 /* RWI-V */
-#define NV_PGRAPH_SURFACE_TYPE_NON_SWIZZLE               0x00000001 /* RW--V */
-#define NV_PGRAPH_SURFACE_TYPE_SWIZZLE                   0x00000002 /* RW--V */
-#define NV_PGRAPH_NOTIFY                                 0x00400714 /* RW-4R */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ                             0:0 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ_NOT_PENDING          0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ_PENDING              0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE                           8:8 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_ONLY         0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_THEN_AWAKEN  0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_REQ                                  16:16 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_REQ_NOT_PENDING                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_REQ_PENDING                     0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_STYLE                                20:20 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_STYLE_WRITE_ONLY                0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_STYLE_WRITE_THEN_AWAKEN         0x00000001 /* RW--V */
-#define NV_PGRAPH_BOFFSET(i)                     (0x00400640+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BOFFSET__SIZE_1                                 6 /*       */
-#define NV_PGRAPH_BOFFSET_LINADRS                              23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET_LINADRS_0                      0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET0                               0x00400640 /* RW-4R */
-#define NV_PGRAPH_BOFFSET0__ALIAS_1            NV_PGRAPH_BOFFSET(0) /*       */
-#define NV_PGRAPH_BOFFSET0_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET0_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET1                               0x00400644 /* RW-4R */
-#define NV_PGRAPH_BOFFSET1__ALIAS_1            NV_PGRAPH_BOFFSET(1) /*       */
-#define NV_PGRAPH_BOFFSET1_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET1_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET2                               0x00400648 /* RW-4R */
-#define NV_PGRAPH_BOFFSET2__ALIAS_1            NV_PGRAPH_BOFFSET(2) /*       */
-#define NV_PGRAPH_BOFFSET2_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET2_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET3                               0x0040064C /* RW-4R */
-#define NV_PGRAPH_BOFFSET3__ALIAS_1            NV_PGRAPH_BOFFSET(3) /*       */
-#define NV_PGRAPH_BOFFSET3_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET3_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET4                               0x00400650 /* RW-4R */
-#define NV_PGRAPH_BOFFSET4__ALIAS_1            NV_PGRAPH_BOFFSET(4) /*       */
-#define NV_PGRAPH_BOFFSET4_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET4_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET5                               0x00400654 /* RW-4R */
-#define NV_PGRAPH_BOFFSET5__ALIAS_1            NV_PGRAPH_BOFFSET(5) /*       */
-#define NV_PGRAPH_BOFFSET5_LINADRS                             23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET5_LINADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE(i)                       (0x00400658+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BBASE__SIZE_1                                   6 /*       */
-#define NV_PGRAPH_BBASE_LINADRS                                23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE_LINADRS_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE0                                 0x00400658 /* RW-4R */
-#define NV_PGRAPH_BBASE0__ALIAS_1                NV_PGRAPH_BBASE(0) /*       */
-#define NV_PGRAPH_BBASE0_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE0_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE1                                 0x0040065c /* RW-4R */
-#define NV_PGRAPH_BBASE1__ALIAS_1                NV_PGRAPH_BBASE(1) /*       */
-#define NV_PGRAPH_BBASE1_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE1_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE2                                 0x00400660 /* RW-4R */
-#define NV_PGRAPH_BBASE2__ALIAS_1                NV_PGRAPH_BBASE(2) /*       */
-#define NV_PGRAPH_BBASE2_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE2_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE3                                 0x00400664 /* RW-4R */
-#define NV_PGRAPH_BBASE3__ALIAS_1                NV_PGRAPH_BBASE(3) /*       */
-#define NV_PGRAPH_BBASE3_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE3_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE4                                 0x00400668 /* RW-4R */
-#define NV_PGRAPH_BBASE4__ALIAS_1                NV_PGRAPH_BBASE(4) /*       */
-#define NV_PGRAPH_BBASE4_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE4_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE5                                 0x0040066C /* RW-4R */
-#define NV_PGRAPH_BBASE5__ALIAS_1                NV_PGRAPH_BBASE(5) /*       */
-#define NV_PGRAPH_BBASE5_LINADRS                               23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE5_LINADRS_0                       0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH(i)                      (0x00400670+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BPITCH__SIZE_1                                  5 /*       */
-#define NV_PGRAPH_BPITCH_VALUE                                 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH_VALUE_0                         0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH0                                0x00400670 /* RW-4R */
-#define NV_PGRAPH_BPITCH0__ALIAS_1              NV_PGRAPH_BPITCH(0) /*       */
-#define NV_PGRAPH_BPITCH0_VALUE                                12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH0_VALUE_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH1                                0x00400674 /* RW-4R */
-#define NV_PGRAPH_BPITCH1__ALIAS_1              NV_PGRAPH_BPITCH(1) /*       */
-#define NV_PGRAPH_BPITCH1_VALUE                                12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH1_VALUE_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH2                                0x00400678 /* RW-4R */
-#define NV_PGRAPH_BPITCH2__ALIAS_1              NV_PGRAPH_BPITCH(2) /*       */
-#define NV_PGRAPH_BPITCH2_VALUE                                12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH2_VALUE_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH3                                0x0040067C /* RW-4R */
-#define NV_PGRAPH_BPITCH3__ALIAS_1              NV_PGRAPH_BPITCH(3) /*       */
-#define NV_PGRAPH_BPITCH3_VALUE                                12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH3_VALUE_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH4                                0x00400680 /* RW-4R */
-#define NV_PGRAPH_BPITCH4__ALIAS_1              NV_PGRAPH_BPITCH(4) /*       */
-#define NV_PGRAPH_BPITCH4_VALUE                                12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH4_VALUE_0                        0x00000000 /* RWI-V */
-#define NV_PGRAPH_BLIMIT(i)                      (0x00400684+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BLIMIT__SIZE_1                                  6 /*       */
-#define NV_PGRAPH_BLIMIT_VALUE                                 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT_TYPE                                 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT_TYPE_IN_MEMORY                  0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT_TYPE_NULL                       0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT0                                0x00400684 /* RW-4R */
-#define NV_PGRAPH_BLIMIT0__ALIAS_1              NV_PGRAPH_BLIMIT(0) /*       */
-#define NV_PGRAPH_BLIMIT0_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT0_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT0_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT0_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT1                                0x00400688 /* RW-4R */
-#define NV_PGRAPH_BLIMIT1__ALIAS_1              NV_PGRAPH_BLIMIT(1) /*       */
-#define NV_PGRAPH_BLIMIT1_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT1_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT1_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT1_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT2                                0x0040068c /* RW-4R */
-#define NV_PGRAPH_BLIMIT2__ALIAS_1              NV_PGRAPH_BLIMIT(2) /*       */
-#define NV_PGRAPH_BLIMIT2_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT2_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT2_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT2_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT3                                0x00400690 /* RW-4R */
-#define NV_PGRAPH_BLIMIT3__ALIAS_1              NV_PGRAPH_BLIMIT(3) /*       */
-#define NV_PGRAPH_BLIMIT3_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT3_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT3_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT3_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT4                                0x00400694 /* RW-4R */
-#define NV_PGRAPH_BLIMIT4__ALIAS_1              NV_PGRAPH_BLIMIT(4) /*       */
-#define NV_PGRAPH_BLIMIT4_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT4_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT4_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT4_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT5                                0x00400698 /* RW-4R */
-#define NV_PGRAPH_BLIMIT5__ALIAS_1              NV_PGRAPH_BLIMIT(5) /*       */
-#define NV_PGRAPH_BLIMIT5_VALUE                                23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT5_TYPE                                31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT5_TYPE_IN_MEMORY                 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT5_TYPE_NULL                      0x00000001 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE2                              0x0040069c /* RW-4R */
-#define NV_PGRAPH_BSWIZZLE2_WIDTH                             19:16 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE2_WIDTH_0                      0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE2_HEIGHT                            27:24 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE2_HEIGHT_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE5                              0x004006a0 /* RW-4R */
-#define NV_PGRAPH_BSWIZZLE5_WIDTH                             19:16 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE5_WIDTH_0                      0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE5_HEIGHT                            27:24 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE5_HEIGHT_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL                                 0x00400724 /* RW-4R */
-#define NV_PGRAPH_BPIXEL_DEPTH0                                 3:0 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH0_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_BPIXEL_DEPTH1                                 7:4 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH1_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_BPIXEL_DEPTH2                                11:8 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH2_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_BPIXEL_DEPTH3                               15:12 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH3_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_BPIXEL_DEPTH4                               19:16 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH4_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_BPIXEL_DEPTH5                               23:20 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH5_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y8                       0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_Z1R5G5B5        0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_O1R5G5B5        0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_A1R5G5B5                 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_R5G6B5                   0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y16                      0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_Z8R8G8B8        0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O1Z7R8G8B8      0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_Z1A7R8G8B8    0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_O1A7R8G8B8    0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O8R8G8B8        0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_A8R8G8B8                 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y32                      0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_V8YB8U8YA8               0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_YB8V8YA8U8               0x0000000f /* RW--V */ 
-#define NV_PGRAPH_LIMIT_VIOL_PIX                         0x00400610 /* RW-4R */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS                          23:0 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS_0                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT                         29:29 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_NO_VIOL            0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_VIOL               0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT                        30:30 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_NO_VIOL           0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_VIOL              0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW                       31:31 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_NO_VIOL          0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_VIOL             0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_Z                           0x00400614 /* RW-4R */
-#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS                            23:0 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS_0                    0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT                          30:30 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_NO_VIOL             0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_VIOL                0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW                         31:31 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_NO_VIOL            0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_VIOL               0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE                                  0x00400710 /* RW-4R */
-#define NV_PGRAPH_STATE_BUFFER_0                                0:0 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_0_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_0_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_1                                1:1 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_1_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_1_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_2                                2:2 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_2_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_2_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_3                                3:3 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_3_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_3_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_4                                4:4 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_4_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_4_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_5                                5:5 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_5_INVALID                 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_5_VALID                   0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_0                                 8:8 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_0_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_0_VALID                    0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_1                                 9:9 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_1_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_1_VALID                    0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_2                               10:10 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_2_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_2_VALID                    0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_3                               11:11 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_3_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_3_VALID                    0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_4                               12:12 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_4_INVALID                  0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_4_VALID                    0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CHROMA_COLOR                          16:16 /* RWIVF */
-#define NV_PGRAPH_STATE_CHROMA_COLOR_INVALID             0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CHROMA_COLOR_VALID               0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT                       17:17 /* RWIVF */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT_INVALID          0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT_VALID            0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT                     20:20 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_INVALID        0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_VALID          0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT                      21:21 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_INVALID         0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_VALID           0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT                       22:22 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT_INVALID          0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT_VALID            0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0                        24:24 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0_INVALID           0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0_VALID             0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1                        25:25 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1_INVALID           0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1_VALID             0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_PATT0                         26:26 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_PATT0_INVALID            0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_PATT0_VALID              0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_PATT1                         27:27 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_PATT1_INVALID            0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_PATT1_VALID              0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX                            0x00400728 /* RW-4R */
-#define NV_PGRAPH_CACHE_INDEX_BANK                              2:2 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_BANK_10                    0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_BANK_32                    0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_ADRS                             12:3 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_ADRS_0                     0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_ADRS_1024                  0x00000400 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP                              14:13 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_OP_WR_CACHE                0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP_RD_CACHE                0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP_RD_INDEX                0x00000002 /* RW--V */
-#define NV_PGRAPH_CACHE_RAM                              0x0040072c /* RW-4R */
-#define NV_PGRAPH_CACHE_RAM_VALUE                              31:0 /* RWXVF */
-#define NV_PGRAPH_DMA_PITCH                              0x00400760 /* RW-4R */
-#define NV_PGRAPH_DMA_PITCH_S0                                 15:0 /* RWXSF */
-#define NV_PGRAPH_DMA_PITCH_S1                                31:16 /* RWXSF */
-#define NV_PGRAPH_DVD_COLORFMT                           0x00400764 /* RW-4R */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE                            5:0 /* RWNVF */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_INVALID            0x00 /* RWN-V */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_V8YB8U8YA8      0x12 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_YB8V8YA8U8      0x13 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY                             9:8 /* RWNVF */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_INVALID             0x00 /* RWN-V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A8Y8U8V8         0x01 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A4V6YB6A4U6YA6   0x02 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_TRANSPARENT         0x03 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT                          0x00400768 /* RW-4R */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN                        17:16 /* RWIVF */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_INVALID           0x00000000 /* RWI-V */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CENTER            0x00000001 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CORNER            0x00000002 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR                  24:24 /* RWIVF */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_ZOH         0x00000000 /* RWI-V */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_FOH         0x00000001 /* RW--V */
-#define NV_PGRAPH_PATT_COLOR0                            0x00400800 /* RW-4R */
-#define NV_PGRAPH_PATT_COLOR0_VALUE                            31:0 /* RWXUF */
-#define NV_PGRAPH_PATT_COLOR1                            0x00400804 /* RW-4R */
-#define NV_PGRAPH_PATT_COLOR1_VALUE                            31:0 /* RWXUF */
-#define NV_PGRAPH_PATT_COLORRAM(i)               (0x00400900+(i)*4) /* R--4A */
-#define NV_PGRAPH_PATT_COLORRAM__SIZE_1                          64 /*       */
-#define NV_PGRAPH_PATT_COLORRAM_VALUE                          23:0 /* R--UF */
-#define NV_PGRAPH_PATTERN(i)                     (0x00400808+(i)*4) /* RW-4A */
-#define NV_PGRAPH_PATTERN__SIZE_1                                 2 /*       */
-#define NV_PGRAPH_PATTERN_BITMAP                               31:0 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE                          0x00400810 /* RW-4R */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE                           1:0 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_8X_8Y              0x00000000 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_64X_1Y             0x00000001 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_1X_64Y             0x00000002 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT                          4:4 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT_2COLOR            0x00000000 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT_FULLCOLOR         0x00000001 /* RW--V */
-#define NV_PGRAPH_MONO_COLOR0                            0x00400600 /* RW-4R */
-#define NV_PGRAPH_MONO_COLOR0_VALUE                            31:0 /* RWXUF */
-#define NV_PGRAPH_ROP3                                   0x00400604 /* RW-4R */
-#define NV_PGRAPH_ROP3_VALUE                                    7:0 /* RWXVF */
-#define NV_PGRAPH_CHROMA                                 0x00400814 /* RW-4R */
-#define NV_PGRAPH_CHROMA_VALUE                                 31:0 /* RWXUF */
-#define NV_PGRAPH_BETA_AND                               0x00400608 /* RW-4R */
-#define NV_PGRAPH_BETA_AND_VALUE_FRACTION                     30:23 /* RWXUF */
-#define NV_PGRAPH_BETA_PREMULT                           0x0040060c /* RW-4R */
-#define NV_PGRAPH_BETA_PREMULT_VALUE                           31:0 /* RWXUF */
-#define NV_PGRAPH_CONTROL0                               0x00400818 /* RW-4R */
-#define NV_PGRAPH_CONTROL1                               0x0040081c /* RW-4R */
-#define NV_PGRAPH_CONTROL2                               0x00400820 /* RW-4R */
-#define NV_PGRAPH_BLEND                                  0x00400824 /* RW-4R */
-#define NV_PGRAPH_DPRAM_INDEX                            0x00400828 /* RW-4R */
-#define NV_PGRAPH_DPRAM_INDEX_ADRS                              6:0 /* RWIVF */
-#define NV_PGRAPH_DPRAM_INDEX_ADRS_0                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT                           10:8 /* RWIVF */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_0              0x00000000 /* RWI-V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_1              0x00000001 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_0              0x00000002 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_1              0x00000003 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_0                0x00000004 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_1                0x00000005 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_0             0x00000006 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_1             0x00000007 /* RW--V */
-#define NV_PGRAPH_DPRAM_DATA                             0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_VALUE                             31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ADRS_0                           0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ADRS_0__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_ADRS_0_VALUE                           19:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ADRS_1                           0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ADRS_1__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_ADRS_1_VALUE                           19:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_DATA_0                           0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_0__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_DATA_0_VALUE                           31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_DATA_1                           0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_1__ALIAS_1        NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_DATA_1_VALUE                           31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_WE_0                             0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_WE_0__ALIAS_1          NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_WE_0_VALUE                             23:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_WE_1                             0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_WE_1__ALIAS_1          NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_WE_1_VALUE                             23:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ALPHA_0                          0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ALPHA_0__ALIAS_1       NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_ALPHA_0_VALUE                          31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ALPHA_1                          0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ALPHA_1__ALIAS_1       NV_PGRAPH_DPRAM_DATA /*       */
-#define NV_PGRAPH_DPRAM_ALPHA_1_VALUE                          31:0 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT                             0x00400830 /* RW-4R */
-#define NV_PGRAPH_STORED_FMT_MONO0                              5:0 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_PATT0                             13:8 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_PATT1                            21:16 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_CHROMA                           29:24 /* RWXVF */
-#define NV_PGRAPH_FORMATS                                0x00400618 /* RW-4R */
-#define NV_PGRAPH_FORMATS_ROP                                   2:0 /* R-XVF */
-#define NV_PGRAPH_FORMATS_ROP_Y8                         0x00000000 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB15                      0x00000001 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB16                      0x00000002 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_Y16                        0x00000003 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_INVALID                    0x00000004 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB24                      0x00000005 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB30                      0x00000006 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_Y32                        0x00000007 /* -W--V */
-#define NV_PGRAPH_FORMATS_SRC                                   9:4 /* R-XVF */
-#define NV_PGRAPH_FORMATS_SRC_INVALID                    0x00000000 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y8                      0x00000001 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16A8Y8                 0x00000002 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X24Y8                   0x00000003 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A1R5G5B5                0x00000006 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X1R5G5B5                0x00000007 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16A1R5G5B5             0x00000008 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X17R5G5B5               0x00000009 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_R5G6B5                  0x0000000A /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A16R5G6B5               0x0000000B /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16R5G6B5               0x0000000C /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A8R8G8B8                0x0000000D /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X8R8G8B8                0x0000000E /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y16                     0x0000000F /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A16Y16                  0x00000010 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16Y16                  0x00000011 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_V8YB8U8YA8              0x00000012 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_YB8V8YA8U8              0x00000013 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y32                     0x00000014 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB                                  15:12 /* R-XVF */
-#define NV_PGRAPH_FORMATS_FB_INVALID                     0x00000000 /* RWI-V */
-#define NV_PGRAPH_FORMATS_FB_Y8                          0x00000001 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_Z1R5G5B5           0x00000002 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_O1R5G5B5           0x00000003 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_A1R5G5B5                    0x00000004 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_R5G6B5                      0x00000005 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_Y16                         0x00000006 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_Z8R8G8B8           0x00000007 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O1Z7R8G8B8         0x00000008 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_Z1A7R8G8B8       0x00000009 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_O1A7R8G8B8       0x0000000a /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O8R8G8B8           0x0000000b /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_A8R8G8B8                    0x0000000c /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_Y32                         0x0000000d /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_V8YB8U8YA8                  0x0000000e /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_YB8V8YA8U8                  0x0000000f /* RW--V */ 
-#define NV_PGRAPH_ABS_X_RAM(i)                   (0x00400400+(i)*4) /* RW-4A */
-#define NV_PGRAPH_ABS_X_RAM__SIZE_1                              32 /*       */
-#define NV_PGRAPH_ABS_X_RAM_VALUE                              31:0 /* RWXUF */
-#define NV_PGRAPH_X_RAM_BPORT(i)                 (0x00400c00+(i)*4) /* R--4A */
-#define NV_PGRAPH_X_RAM_BPORT__SIZE_1                            32 /*       */
-#define NV_PGRAPH_X_RAM_BPORT_VALUE                            31:0 /* R--UF */
-#define NV_PGRAPH_ABS_Y_RAM(i)                   (0x00400480+(i)*4) /* RW-4A */
-#define NV_PGRAPH_ABS_Y_RAM__SIZE_1                              32 /*       */
-#define NV_PGRAPH_ABS_Y_RAM_VALUE                              31:0 /* RWXUF */
-#define NV_PGRAPH_Y_RAM_BPORT(i)                 (0x00400c80+(i)*4) /* R--4A */
-#define NV_PGRAPH_Y_RAM_BPORT__SIZE_1                            32 /*       */
-#define NV_PGRAPH_Y_RAM_BPORT_VALUE                            31:0 /* R--UF */
-#define NV_PGRAPH_XY_LOGIC_MISC0                         0x00400514 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER                       17:0 /* RWBUF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER_0               0x00000000 /* RWB-V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION                    20:20 /* RWVVF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_NONZERO       0x00000000 /* RWV-V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_ZERO          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX                        31:28 /* RWBUF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX_0                 0x00000000 /* RWB-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1                         0x00400518 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL                        0:0 /* RWNVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_NEEDED          0x00000000 /* RWN-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_DONE            0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX                      4:4 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NOTNULL       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NULL          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY                      5:5 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NOTNULL       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NULL          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX                    12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_UUMAX         0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX                    16:16 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_UUMAX         0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA                    20:20 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_CLIPMAX       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2                         0x0040051C /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF                        0:0 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_DISABLE         0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_ENABLE          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX                      4:4 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NOTNULL       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NULL          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY                      5:5 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NOTNULL       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NULL          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX                    12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_UCMAX         0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX                    16:16 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_UCMAX         0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA                    20:20 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_CLIPMAX       0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_IMAGEMAX      0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3                         0x00400520 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0                     0:0 /* RWXVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_NULL         0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_TRUE         0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY                   4:4 /* RWXVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_NULL       0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_TRUE       0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX                      8:8 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_NULL          0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_TRUE          0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG                     12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_NULL           0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_TRUE           0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX                    22:16 /* RWXUF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX_0             0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX                   30:24 /* RWXUF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX_0            0x00000000 /* RW--V */
-#define NV_PGRAPH_X_MISC                                 0x00400500 /* RW-4R */
-#define NV_PGRAPH_X_MISC_BIT33_0                                0:0 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_0_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_1                                1:1 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_1_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_2                                2:2 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_2_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_3                                3:3 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_3_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_0                                4:4 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_0_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_1                                5:5 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_1_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_2                                6:6 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_2_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_3                                7:7 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_3_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT                         29:28 /* RWXVF */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_EQ_0               0x00000000 /* RW--V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_LT_0               0x00000001 /* RW--V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_GT_0               0x00000002 /* RW--V */
-#define NV_PGRAPH_Y_MISC                                 0x00400504 /* RW-4R */
-#define NV_PGRAPH_Y_MISC_BIT33_0                                0:0 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_0_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_1                                1:1 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_1_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_2                                2:2 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_2_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_3                                3:3 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_3_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_0                                4:4 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_0_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_1                                5:5 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_1_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_2                                6:6 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_2_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_3                                7:7 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_3_0                       0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT                         29:28 /* RWXVF */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_EQ_0               0x00000000 /* RW--V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_LT_0               0x00000001 /* RW--V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_GT_0               0x00000002 /* RW--V */
-#define NV_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_XMIN_VALUE                         15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_XMAX                         0x00400544 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_XMAX_VALUE                         17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_YMIN                         0x00400540 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_YMIN_VALUE                         15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_YMAX                         0x00400548 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_YMAX_VALUE                         17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_XMIN_VALUE                        15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_XMAX_VALUE                        17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_YMIN_VALUE                        15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_YMAX_VALUE                        17:0 /* RWXSF */
-#define NV_PGRAPH_SOURCE_COLOR                           0x0040050C /* RW-4R */
-#define NV_PGRAPH_SOURCE_COLOR_VALUE                           31:0 /* RWNVF */
-#define NV_PGRAPH_SOURCE_COLOR_VALUE_0                   0x00000000 /* RWN-V */
-#define NV_PGRAPH_VALID1                                 0x00400508 /* RW-4R */
-#define NV_PGRAPH_VALID1_VLD                                   22:0 /* RWNVF */
-#define NV_PGRAPH_VALID1_VLD_0                           0x00000000 /* RWN-V */
-#define NV_PGRAPH_VALID1_CLIP_MIN                             28:28 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIP_MIN_NO_ERROR               0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIP_MIN_ONLY                   0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIPA_MIN                            29:29 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIPA_MIN_NO_ERROR              0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIPA_MIN_ONLY                  0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIP_MAX                             30:30 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIP_MAX_NO_ERROR               0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIP_MAX_ONLY                   0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIPA_MAX                            31:31 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIPA_MAX_NO_ERROR              0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIPA_MAX_ONLY                  0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID2                                 0x00400578 /* RW-4R */
-#define NV_PGRAPH_VALID2_VLD2                                  28:0 /* RWNVF */
-#define NV_PGRAPH_VALID2_VLD2_0                          0x00000000 /* RWN-V */
-#define NV_PGRAPH_ABS_ICLIP_XMAX                         0x00400534 /* RW-4R */
-#define NV_PGRAPH_ABS_ICLIP_XMAX_VALUE                         17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_ICLIP_YMAX                         0x00400538 /* RW-4R */
-#define NV_PGRAPH_ABS_ICLIP_YMAX_VALUE                         17:0 /* RWXSF */
-#define NV_PGRAPH_CLIPX_0                                0x00400524 /* RW-4R */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN                             1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX                             3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN                             5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX                             7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN                             9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX                           11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN                           13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX                           15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN                           17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX                           19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN                           21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX                           23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN                           25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX                           27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN                           29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX                           31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1                                0x00400528 /* RW-4R */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN                             1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX                             3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN                             5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX                             7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN                            9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX                          11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN                          13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP11MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX                          15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN                          17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX                          19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN                          21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX                          23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN                          25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX                          27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN                          29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX                          31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0                                0x0040052c /* RW-4R */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN                             1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX                             3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN                             5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX                             7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN                             9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX                           11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN                           13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX                           15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN                           17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX                           19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN                           21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX                           23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN                           25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX                           27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN                           29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX                           31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1                                0x00400530 /* RW-4R */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN                             1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX                             3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN                             5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_GT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_LT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX                             7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_LT                   0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_GT                   0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN                            9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX                          11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN                          13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP11MIN_EQ                   0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX                          15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN                          17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX                          19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN                          21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX                          23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN                          25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX                          27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN                          29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_GT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_LT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX                          31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_LT                  0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_GT                  0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_EQ                  0x00000002 /* RW--V */
-#define NV_PGRAPH_MISC24_0                               0x00400510 /* RW-4R */
-#define NV_PGRAPH_MISC24_0_VALUE                               23:0 /* RWXUF */
-#define NV_PGRAPH_MISC24_1                               0x00400570 /* RW-4R */
-#define NV_PGRAPH_MISC24_1_VALUE                               23:0 /* RWXUF */
-#define NV_PGRAPH_MISC24_2                               0x00400574 /* RW-4R */
-#define NV_PGRAPH_MISC24_2_VALUE                               23:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_0                             0x0040057C /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_0_VALUE                             31:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_1                             0x00400580 /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_1_VALUE                             31:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_2                             0x00400584 /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_2_VALUE                             31:0 /* RWXUF */
-#define NV_PGRAPH_U_RAM(i)                       (0x00400d00+(i)*4) /* RW-4A */
-#define NV_PGRAPH_U_RAM__SIZE_1                                  16 /*       */
-#define NV_PGRAPH_U_RAM_VALUE                                  31:6 /* RWXFF */
-#define NV_PGRAPH_V_RAM(i)                       (0x00400d40+(i)*4) /* RW-4A */
-#define NV_PGRAPH_V_RAM__SIZE_1                                  16 /*       */
-#define NV_PGRAPH_V_RAM_VALUE                                  31:6 /* RWXFF */
-#define NV_PGRAPH_M_RAM(i)                       (0x00400d80+(i)*4) /* RW-4A */
-#define NV_PGRAPH_M_RAM__SIZE_1                                  16 /*       */
-#define NV_PGRAPH_M_RAM_VALUE                                  31:6 /* RWXFF */
-#define NV_PGRAPH_DMA_START_0                            0x00401000 /* RW-4R */
-#define NV_PGRAPH_DMA_START_0_VALUE                            31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_START_1                            0x00401004 /* RW-4R */
-#define NV_PGRAPH_DMA_START_1_VALUE                            31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_LENGTH                             0x00401008 /* RW-4R */
-#define NV_PGRAPH_DMA_LENGTH_VALUE                             21:0 /* RWXUF */
-#define NV_PGRAPH_DMA_MISC                               0x0040100C /* RW-4R */
-#define NV_PGRAPH_DMA_MISC_COUNT                               15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_MISC_FMT_SRC                            18:16 /* RWXVF */
-#define NV_PGRAPH_DMA_MISC_FMT_DST                            22:20 /* RWXVF */
-#define NV_PGRAPH_DMA_DATA_0                             0x00401020 /* RW-4R */
-#define NV_PGRAPH_DMA_DATA_0_VALUE                             31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_DATA_1                             0x00401024 /* RW-4R */
-#define NV_PGRAPH_DMA_DATA_1_VALUE                             31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_RM                                 0x00401030 /* RW-4R */
-#define NV_PGRAPH_DMA_RM_ASSIST_A                               0:0 /* RWIVF */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_NOT_PENDING            0x00000000 /* R-I-V */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_PENDING                0x00000001 /* R---V */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_RESET                  0x00000001 /* -W--C */
-#define NV_PGRAPH_DMA_RM_ASSIST_B                               1:1 /* RWIVF */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_NOT_PENDING            0x00000000 /* R-I-V */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_PENDING                0x00000001 /* R---V */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_RESET                  0x00000001 /* -W--C */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ                              4:4 /* CWIVF */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ_NOT_PENDING           0x00000000 /* CWI-V */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ_PENDING               0x00000001 /* -W--T */
-#define NV_PGRAPH_DMA_A_XLATE_INST                       0x00401040 /* RW-4R */
-#define NV_PGRAPH_DMA_A_XLATE_INST_VALUE                       15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_CONTROL                          0x00401044 /* RW-4R */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE                    12:12 /* RWIVF */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RWI-V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY                    13:13 /* RWXVF */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE                   17:16 /* RWXUF */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_NVM          0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_PCI          0x00000002 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_AGP          0x00000003 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_ADJUST                        31:20 /* RWXUF */
-#define NV_PGRAPH_DMA_A_LIMIT                            0x00401048 /* RW-4R */
-#define NV_PGRAPH_DMA_A_LIMIT_OFFSET                           31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_TLB_PTE                          0x0040104C /* RW-4R */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS                          1:1 /* RWXVF */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_ONLY         0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_WRITE        0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_TLB_PTE_FRAME_ADDRESS                 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_A_TLB_TAG                          0x00401050 /* RW-4R */
-#define NV_PGRAPH_DMA_A_TLB_TAG_ADDRESS                       31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054 /* RW-4R */
-#define NV_PGRAPH_DMA_A_ADJ_OFFSET_VALUE                       31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_OFFSET                           0x00401058 /* RW-4R */
-#define NV_PGRAPH_DMA_A_OFFSET_VALUE                           31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_SIZE                             0x0040105C /* RW-4R */
-#define NV_PGRAPH_DMA_A_SIZE_VALUE                             24:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_Y_SIZE                           0x00401060 /* RW-4R */
-#define NV_PGRAPH_DMA_A_Y_SIZE_VALUE                           10:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_XLATE_INST                       0x00401080 /* RW-4R */
-#define NV_PGRAPH_DMA_B_XLATE_INST_VALUE                       15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_CONTROL                          0x00401084 /* RW-4R */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE                    12:12 /* RWIVF */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_NOT_PRESENT   0x00000000 /* RWI-V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_PRESENT       0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY                    13:13 /* RWXVF */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_NOT_LINEAR    0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_LINEAR        0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE                   17:16 /* RWXUF */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_NVM          0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_PCI          0x00000002 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_AGP          0x00000003 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_ADJUST                        31:20 /* RWXUF */
-#define NV_PGRAPH_DMA_B_LIMIT                            0x00401088 /* RW-4R */
-#define NV_PGRAPH_DMA_B_LIMIT_OFFSET                           31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_TLB_PTE                          0x0040108C /* RW-4R */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS                          1:1 /* RWXVF */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_ONLY         0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_WRITE        0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_TLB_PTE_FRAME_ADDRESS                 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_B_TLB_TAG                          0x00401090 /* RW-4R */
-#define NV_PGRAPH_DMA_B_TLB_TAG_ADDRESS                       31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094 /* RW-4R */
-#define NV_PGRAPH_DMA_B_ADJ_OFFSET_VALUE                       31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_OFFSET                           0x00401098 /* RW-4R */
-#define NV_PGRAPH_DMA_B_OFFSET_VALUE                           31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_SIZE                             0x0040109C /* RW-4R */
-#define NV_PGRAPH_DMA_B_SIZE_VALUE                             24:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_Y_SIZE                           0x004010A0 /* RW-4R */
-#define NV_PGRAPH_DMA_B_Y_SIZE_VALUE                           10:0 /* RWXUF */
-
-/* Framebuffer registers */
-#define NV_PFB                                0x00100FFF:0x00100000 /* RW--D */
-#define NV_PFB_BOOT_0                                    0x00100000 /* RW-4R */
-#define NV_PFB_BOOT_0_RAM_AMOUNT                                1:0 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_32MB                    0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_4MB                     0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_8MB                     0x00000002 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_16MB                    0x00000003 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128                             2:2 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128_OFF                  0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128_ON                   0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE                                  4:3 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_TYPE_256K                      0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_512K_2BANK                0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_512K_4BANK                0x00000002 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_1024K_2BANK               0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0                                  0x00100200 /* RW-4R */
-#define NV_PFB_CONFIG_0_TYPE                                   14:0 /* RWIVF */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_8BPP          0x00000120 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_16BPP         0x00000220 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_32BPP         0x00000320 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_8BPP            0x00004120 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_16BPP           0x00004220 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_32BPP           0x00004320 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_TETRIS                      0x00002000 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_NOTILING                    0x00001114 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE                           17:15 /* RWI-F */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_PASS                 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_1                    0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_2                    0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_3                    0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_4                    0x00000004 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_5                    0x00000005 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_6                    0x00000006 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_7                    0x00000007 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT                          19:18 /* RWI-F */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_0                   0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_1                   0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_2                   0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP                             22:20 /* RWI-F */
-#define NV_PFB_CONFIG_0_BANK_SWAP_OFF                    0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_1M                     0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_2M                     0x00000005 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_4M                     0x00000007 /* RW--V */
-#define NV_PFB_CONFIG_0_UNUSED                                23:23 /* RW-VF */
-#define NV_PFB_CONFIG_0_SCRAMBLE_EN                           29:29 /* RWIVF */
-#define NV_PFB_CONFIG_0_SCRAMBLE_EN_INIT                 0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_SCRAMBLE_ACTIVE                  0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR                             28:28 /* RWIVF */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_INIT                   0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_DISABLED               0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK                        27:24 /* RWIVF */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_INIT              0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_CLEAR             0x0000000f /* RWI-V */
-#define NV_PFB_CONFIG_1                                  0x00100204 /* RW-4R */
-#define NV_PFB_RTL                                       0x00100300 /* RW-4R */
-#define NV_PFB_RTL_H                                            0:0 /* RWIUF */
-#define NV_PFB_RTL_H_DEFAULT                             0x00000000 /* RWI-V */
-#define NV_PFB_RTL_MC                                           1:1 /* RWIUF */
-#define NV_PFB_RTL_MC_DEFAULT                            0x00000000 /* RWI-V */
-#define NV_PFB_RTL_V                                            2:2 /* RWIUF */
-#define NV_PFB_RTL_V_DEFAULT                             0x00000000 /* RWI-V */
-#define NV_PFB_RTL_G                                            3:3 /* RWIUF */
-#define NV_PFB_RTL_G_DEFAULT                             0x00000000 /* RWI-V */
-#define NV_PFB_RTL_GB                                           4:4 /* RWIUF */
-#define NV_PFB_RTL_GB_DEFAULT                            0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_RESOLUTION                              5:0 /* RWIVF */
-#define NV_PFB_CONFIG_0_RESOLUTION_320_PIXELS            0x0000000a /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_400_PIXELS            0x0000000d /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_480_PIXELS            0x0000000f /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_512_PIXELS            0x00000010 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_640_PIXELS            0x00000014 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_800_PIXELS            0x00000019 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_960_PIXELS            0x0000001e /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1024_PIXELS           0x00000020 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1152_PIXELS           0x00000024 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1280_PIXELS           0x00000028 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1600_PIXELS           0x00000032 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_DEFAULT               0x00000014 /* RWI-V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH                             9:8 /* RWIVF */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_8_BITS               0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_16_BITS              0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_32_BITS              0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_DEFAULT              0x00000001 /* RWI-V */
-#define NV_PFB_CONFIG_0_TILING                                12:12 /* RWIVF */
-#define NV_PFB_CONFIG_0_TILING_ENABLED                   0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_TILING_DISABLED                  0x00000001 /* RWI-V */
-#define NV_PFB_CONFIG_1_SGRAM100                                3:3 /* RWIVF */
-#define NV_PFB_CONFIG_1_SGRAM100_ENABLED                 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_1_SGRAM100_DISABLED                0x00000001 /* RW--V */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON                           29:29 /* RWIVF */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON_OFF                  0x00000000 /* RW--V */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON_ON                   0x00000001 /* RWI-V */
-
-#define NV_PEXTDEV                            0x00101FFF:0x00101000 /* RW--D */
-#define NV_PEXTDEV_BOOT_0                                0x00101000 /* R--4R */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED                       0:0 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_33MHZ          0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_66MHZ          0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR                      1:1 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_NO_BIOS       0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_BIOS          0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE                        3:2 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_256K      0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x00000002 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_1024K_2BANK     0x00000003 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH                       4:4 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_64             0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_128            0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE                        5:5 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_PCI             0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_AGP             0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL                         6:6 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_13500K           0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_14318180         0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE                          8:7 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_SECAM             0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_NTSC              0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_PAL               0x00000002 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_DISABLED          0x00000003 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE                     11:11 /* RWIVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_DISABLED       0x00000000 /* RWI-V */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_ENABLED        0x00000001 /* RW--V */
-
-/* Extras */
-#define NV_PRAMIN                             0x007FFFFF:0x00700000 /* RW--M */
-/*#define NV_PRAMIN                             0x00FFFFFF:0x00C00000*/
-#define NV_PNVM                               0x01FFFFFF:0x01000000 /* RW--M */
-/*#define NV_PNVM                               0x00BFFFFF:0x00800000*/
-#define NV_CHAN0                              0x0080ffff:0x00800000
-
-/* FIFO subchannels */
-#define NV_UROP                               0x43
-#define NV_UCHROMA                            0x57
-#define NV_UCLIP                              0x19
-#define NV_UPATT                              0x18
-#define NV_ULIN                               0x5C
-#define NV_UTRI                               0x5D
-#define NV_URECT                              0x5E
-#define NV_UBLIT                              0x5F
-#define NV_UGLYPH                             0x4B
-
-#endif /*__NV4REF_H__*/
-
diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c
index be630a0..a110268 100644
--- a/drivers/video/riva/nv_driver.c
+++ b/drivers/video/riva/nv_driver.c
@@ -231,12 +231,14 @@ unsigned long riva_get_memlen(struct riv
 	case NV_ARCH_30:
 		if(chipset == NV_CHIP_IGEFORCE2) {
 
-			dev = pci_find_slot(0, 1);
+			dev = pci_get_bus_and_slot(0, 1);
 			pci_read_config_dword(dev, 0x7C, &amt);
+			pci_dev_put(dev);
 			memlen = (((amt >> 6) & 31) + 1) * 1024;
 		} else if (chipset == NV_CHIP_0x01F0) {
-			dev = pci_find_slot(0, 1);
+			dev = pci_get_bus_and_slot(0, 1);
 			pci_read_config_dword(dev, 0x84, &amt);
+			pci_dev_put(dev);
 			memlen = (((amt >> 4) & 127) + 1) * 1024;
 		} else {
 			switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) &
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index e0b8c52..70bfd78 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -1118,8 +1118,9 @@ (
     unsigned int uMClkPostDiv;
     struct pci_dev *dev;
 
-    dev = pci_find_slot(0, 3);
+    dev = pci_get_bus_and_slot(0, 3);
     pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
+    pci_dev_put(dev);
     uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
 
     if(!uMClkPostDiv) uMClkPostDiv = 4;
@@ -1132,8 +1133,9 @@ (
     sim_data.enable_video   = 0;
     sim_data.enable_mp      = 0;
 
-    dev = pci_find_slot(0, 1);
+    dev = pci_get_bus_and_slot(0, 1);
     pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+    pci_dev_put(dev);
     sim_data.memory_type    = (sim_data.memory_type >> 12) & 1;
 
     sim_data.memory_width   = 64;
@@ -2112,12 +2114,14 @@ #endif
      * Fill in chip configuration.
      */
     if(chipset == NV_CHIP_IGEFORCE2) {
-        dev = pci_find_slot(0, 1);
+        dev = pci_get_bus_and_slot(0, 1);
         pci_read_config_dword(dev, 0x7C, &amt);
+        pci_dev_put(dev);
         chip->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
     } else if(chipset == NV_CHIP_0x01F0) {
-        dev = pci_find_slot(0, 1);
+        dev = pci_get_bus_and_slot(0, 1);
         pci_read_config_dword(dev, 0x84, &amt);
+        pci_dev_put(dev);
         chip->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
     } else {
         switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) & 0x000000FF)
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 0405e83..76e6ce3 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -88,13 +88,16 @@ static int riva_gpio_getsda(void* data)
 	return val;
 }
 
-static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
+static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
+					const char *name,
+					unsigned int i2c_class)
 {
 	int rc;
 
 	strcpy(chan->adapter.name, name);
 	chan->adapter.owner		= THIS_MODULE;
 	chan->adapter.id		= I2C_HW_B_RIVA;
+	chan->adapter.class		= i2c_class;
 	chan->adapter.algo_data		= &chan->algo;
 	chan->adapter.dev.parent	= &chan->par->pdev->dev;
 	chan->algo.setsda		= riva_gpio_setsda;
@@ -124,42 +127,38 @@ static int riva_setup_i2c_bus(struct riv
 	return rc;
 }
 
-void riva_create_i2c_busses(struct riva_par *par)
+void __devinit riva_create_i2c_busses(struct riva_par *par)
 {
-	par->bus = 3;
-
 	par->chan[0].par	= par;
 	par->chan[1].par	= par;
 	par->chan[2].par        = par;
 
-	par->chan[0].ddc_base = 0x3e;
-	par->chan[1].ddc_base = 0x36;
+	par->chan[0].ddc_base = 0x36;
+	par->chan[1].ddc_base = 0x3e;
 	par->chan[2].ddc_base = 0x50;
-	riva_setup_i2c_bus(&par->chan[0], "BUS1");
-	riva_setup_i2c_bus(&par->chan[1], "BUS2");
-	riva_setup_i2c_bus(&par->chan[2], "BUS3");
+	riva_setup_i2c_bus(&par->chan[0], "BUS1", I2C_CLASS_HWMON);
+	riva_setup_i2c_bus(&par->chan[1], "BUS2", 0);
+	riva_setup_i2c_bus(&par->chan[2], "BUS3", 0);
 }
 
 void riva_delete_i2c_busses(struct riva_par *par)
 {
-	if (par->chan[0].par)
-		i2c_del_adapter(&par->chan[0].adapter);
-	par->chan[0].par = NULL;
-
-	if (par->chan[1].par)
-		i2c_del_adapter(&par->chan[1].adapter);
-	par->chan[1].par = NULL;
+	int i;
 
-	if (par->chan[2].par)
-		i2c_del_adapter(&par->chan[2].adapter);
-	par->chan[2].par = NULL;
+	for (i = 0; i < 3; i++) {
+		if (!par->chan[i].par)
+			continue;
+		i2c_del_adapter(&par->chan[i].adapter);
+		par->chan[i].par = NULL;
+	}
 }
 
-int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
+int __devinit riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
 {
 	u8 *edid = NULL;
 
-	edid = fb_ddc_read(&par->chan[conn-1].adapter);
+	if (par->chan[conn].par)
+		edid = fb_ddc_read(&par->chan[conn].adapter);
 
 	if (out_edid)
 		*out_edid = edid;
diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h
index 48ead6d..d9f107b 100644
--- a/drivers/video/riva/rivafb.h
+++ b/drivers/video/riva/rivafb.h
@@ -4,7 +4,6 @@ #define __RIVAFB_H
 #include <linux/fb.h>
 #include <video/vga.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 
 #include "riva_hw.h"
@@ -61,7 +60,6 @@ #endif
 	Bool SecondCRTC;
 	int FlatPanel;
 	struct pci_dev *pdev;
-	int bus;
 	int cursor_reset;
 #ifdef CONFIG_MTRR
 	struct { int vram; int vram_valid; } mtrr;
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 3091b20..756fafb 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -65,7 +65,7 @@ static const struct svga_fb_format s3fb_
 
 
 static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3,
-	60000, 240000, 14318};
+	35000, 240000, 14318};
 
 static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512};
 
@@ -164,7 +164,7 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fa
 static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
 {
 	const u8 *font = map->data;
-	u8* fb = (u8 *) info->screen_base;
+	u8 __iomem *fb = (u8 __iomem *) info->screen_base;
 	int i, c;
 
 	if ((map->width != 8) || (map->height != 16) ||
@@ -177,20 +177,19 @@ static void s3fb_settile_fast(struct fb_
 	fb += 2;
 	for (i = 0; i < map->height; i++) {
 		for (c = 0; c < map->length; c++) {
-			fb[c * 4] = font[c * map->height + i];
+			fb_writeb(font[c * map->height + i], fb + c * 4);
 		}
 		fb += 1024;
 	}
 }
 
-
-
 static struct fb_tile_ops s3fb_tile_ops = {
 	.fb_settile	= svga_settile,
 	.fb_tilecopy	= svga_tilecopy,
 	.fb_tilefill    = svga_tilefill,
 	.fb_tileblit    = svga_tileblit,
 	.fb_tilecursor  = svga_tilecursor,
+	.fb_get_tilemax = svga_get_tilemax,
 };
 
 static struct fb_tile_ops s3fb_fast_tile_ops = {
@@ -199,6 +198,7 @@ static struct fb_tile_ops s3fb_fast_tile
 	.fb_tilefill    = svga_tilefill,
 	.fb_tileblit    = svga_tileblit,
 	.fb_tilecursor  = svga_tilecursor,
+	.fb_get_tilemax = svga_get_tilemax,
 };
 
 
@@ -326,8 +326,13 @@ static void s3_set_pixclock(struct fb_in
 {
 	u16 m, n, r;
 	u8 regval;
+	int rv;
 
-	svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+	rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+	if (rv < 0) {
+		printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+		return;
+	}
 
 	/* Set VGA misc register  */
 	regval = vga_r(NULL, VGA_MIS_R);
@@ -449,6 +454,10 @@ static int s3fb_set_par(struct fb_info *
 		info->flags &= ~FBINFO_MISC_TILEBLITTING;
 		info->tileops = NULL;
 
+		/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+		info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+		info->pixmap.blit_y = ~(u32)0;
+
 		offset_value = (info->var.xres_virtual * bpp) / 64;
 		screen_size = info->var.yres_virtual * info->fix.line_length;
 	} else {
@@ -458,6 +467,10 @@ static int s3fb_set_par(struct fb_info *
 		info->flags |= FBINFO_MISC_TILEBLITTING;
 		info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops;
 
+		/* supports 8x16 tiles only */
+		info->pixmap.blit_x = 1 << (8 - 1);
+		info->pixmap.blit_y = 1 << (16 - 1);
+
 		offset_value = info->var.xres_virtual / 16;
 		screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
 	}
@@ -656,7 +669,7 @@ static int s3fb_set_par(struct fb_info *
 	value = ((value * hmul) / 8) - 5;
 	vga_wcrt(NULL, 0x3C, (value + 1) / 2);
 
-	memset((u8*)info->screen_base, 0x00, screen_size);
+	memset_io(info->screen_base, 0x00, screen_size);
 	/* Device and screen back on */
 	svga_wcrt_mask(0x17, 0x80, 0x80);
 	svga_wseq_mask(0x01, 0x00, 0x20);
@@ -699,7 +712,7 @@ static int s3fb_setcolreg(u_int regno, u
 		break;
 	case 16:
 		if (regno >= 16)
-			return -EINVAL;
+			return 0;
 
 		if (fb->var.green.length == 5)
 			((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
@@ -712,9 +725,9 @@ static int s3fb_setcolreg(u_int regno, u
 	case 24:
 	case 32:
 		if (regno >= 16)
-			return -EINVAL;
+			return 0;
 
-		((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+		((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
 			(green & 0xFF00) | ((blue & 0xFF00) >> 8);
 		break;
 	default:
@@ -767,12 +780,6 @@ static int s3fb_pan_display(struct fb_va
 
 	unsigned int offset;
 
-	/* Validate the offsets */
-	if ((var->xoffset + var->xres) > var->xres_virtual)
-		return -EINVAL;
-	if ((var->yoffset + var->yres) > var->yres_virtual)
-		return -EINVAL;
-
 	/* Calculate the offset */
 	if (var->bits_per_pixel == 0) {
 		offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
@@ -789,6 +796,23 @@ static int s3fb_pan_display(struct fb_va
 	return 0;
 }
 
+/* Get capabilities of accelerator based on the mode */
+
+static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+			  struct fb_var_screeninfo *var)
+{
+	if (var->bits_per_pixel == 0) {
+		/* can only support 256 8x16 bitmap */
+		caps->x = 1 << (8 - 1);
+		caps->y = 1 << (16 - 1);
+		caps->len = 256;
+	} else {
+		caps->x = ~(u32)0;
+		caps->y = ~(u32)0;
+		caps->len = ~(u32)0;
+	}
+}
+
 /* ------------------------------------------------------------------------- */
 
 /* Frame buffer operations */
@@ -805,6 +829,7 @@ static struct fb_ops s3fb_ops = {
 	.fb_fillrect	= s3fb_fillrect,
 	.fb_copyarea	= cfb_copyarea,
 	.fb_imageblit	= s3fb_imageblit,
+	.fb_get_caps    = s3fb_get_caps,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -1061,6 +1086,7 @@ static int s3_pci_resume(struct pci_dev*
 {
 	struct fb_info *info = pci_get_drvdata(dev);
 	struct s3fb_info *par = info->par;
+	int err;
 
 	dev_info(&(dev->dev), "resume\n");
 
@@ -1075,7 +1101,13 @@ static int s3_pci_resume(struct pci_dev*
 
 	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
-	pci_enable_device(dev);
+	err = pci_enable_device(dev);
+	if (err) {
+		mutex_unlock(&(par->open_lock));
+		release_console_sem();
+		dev_err(&(dev->dev), "error %d enabling device for resume\n", err);
+		return err;
+	}
 	pci_set_master(dev);
 
 	s3fb_set_par(info);
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 8db066c..35c1ce6 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -41,10 +41,6 @@ #define SAVAGE4_I2C_SDA_OUT	0x00000002
 #define SAVAGE4_I2C_SCL_IN	0x00000008
 #define SAVAGE4_I2C_SDA_IN	0x00000010
 
-#define SET_CR_IX(base, val)	writeb((val), base + 0x8000 + VGA_CR_IX)
-#define SET_CR_DATA(base, val)	writeb((val), base + 0x8000 + VGA_CR_DATA)
-#define GET_CR_DATA(base)	readb(base + 0x8000 + VGA_CR_DATA)
-
 static void savage4_gpio_setscl(void *data, int val)
 {
 	struct savagefb_i2c_chan *chan = data;
@@ -92,15 +88,15 @@ static void prosavage_gpio_setscl(void* 
 	struct savagefb_i2c_chan *chan = data;
 	u32			  r;
 
-	SET_CR_IX(chan->ioaddr, chan->reg);
-	r = GET_CR_DATA(chan->ioaddr);
+	r = VGArCR(chan->reg, chan->par);
 	r |= PROSAVAGE_I2C_ENAB;
 	if (val) {
 		r |= PROSAVAGE_I2C_SCL_OUT;
 	} else {
 		r &= ~PROSAVAGE_I2C_SCL_OUT;
 	}
-	SET_CR_DATA(chan->ioaddr, r);
+
+	VGAwCR(chan->reg, r, chan->par);
 }
 
 static void prosavage_gpio_setsda(void* data, int val)
@@ -108,31 +104,29 @@ static void prosavage_gpio_setsda(void* 
 	struct savagefb_i2c_chan *chan = data;
 	unsigned int r;
 
-	SET_CR_IX(chan->ioaddr, chan->reg);
-	r = GET_CR_DATA(chan->ioaddr);
+	r = VGArCR(chan->reg, chan->par);
 	r |= PROSAVAGE_I2C_ENAB;
 	if (val) {
 		r |= PROSAVAGE_I2C_SDA_OUT;
 	} else {
 		r &= ~PROSAVAGE_I2C_SDA_OUT;
 	}
-	SET_CR_DATA(chan->ioaddr, r);
+
+	VGAwCR(chan->reg, r, chan->par);
 }
 
 static int prosavage_gpio_getscl(void* data)
 {
 	struct savagefb_i2c_chan *chan = data;
 
-	SET_CR_IX(chan->ioaddr, chan->reg);
-	return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN));
+	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SCL_IN) ? 1 : 0;
 }
 
 static int prosavage_gpio_getsda(void* data)
 {
 	struct savagefb_i2c_chan *chan = data;
 
-	SET_CR_IX(chan->ioaddr, chan->reg);
-	return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
+	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SDA_IN) ? 1 : 0;
 }
 
 static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index e648a6c..8bfdfc3 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -15,6 +15,8 @@ #define __SAVAGEFB_H__
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/mutex.h>
+#include <video/vga.h>
 #include "../edid.h"
 
 #ifdef SAVAGEFB_DEBUG
@@ -189,8 +191,12 @@ struct savagefb_par {
 	struct savagefb_i2c_chan chan;
 	struct savage_reg state;
 	struct savage_reg save;
+	struct savage_reg initial;
+	struct vgastate vgastate;
+	struct mutex open_lock;
 	unsigned char   *edid;
 	u32 pseudo_palette[16];
+	u32 open_count;
 	int paletteEnabled;
 	int pm_state;
 	int display_type;
@@ -203,7 +209,7 @@ struct savagefb_par {
 	int clock[4];
 	int MCLK, REFCLK, LCDclk;
 	struct {
-		u8   __iomem *vbase;
+		void   __iomem *vbase;
 		u32    pbase;
 		u32    len;
 #ifdef CONFIG_MTRR
@@ -212,7 +218,7 @@ #endif
 	} video;
 
 	struct {
-		volatile u8  __iomem *vbase;
+		void  __iomem *vbase;
 		u32           pbase;
 		u32           len;
 	} mmio;
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 0166ec2..3d7507a 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -1623,8 +1623,46 @@ static void savagefb_restore_state(struc
 	savagefb_blank(FB_BLANK_UNBLANK, info);
 }
 
+static int savagefb_open(struct fb_info *info, int user)
+{
+	struct savagefb_par *par = info->par;
+
+	mutex_lock(&par->open_lock);
+
+	if (!par->open_count) {
+		memset(&par->vgastate, 0, sizeof(par->vgastate));
+		par->vgastate.flags = VGA_SAVE_CMAP | VGA_SAVE_FONTS |
+			VGA_SAVE_MODE;
+		par->vgastate.vgabase = par->mmio.vbase + 0x8000;
+		save_vga(&par->vgastate);
+		savage_get_default_par(par, &par->initial);
+	}
+
+	par->open_count++;
+	mutex_unlock(&par->open_lock);
+	return 0;
+}
+
+static int savagefb_release(struct fb_info *info, int user)
+{
+	struct savagefb_par *par = info->par;
+
+	mutex_lock(&par->open_lock);
+
+	if (par->open_count == 1) {
+		savage_set_default_par(par, &par->initial);
+		restore_vga(&par->vgastate);
+	}
+
+	par->open_count--;
+	mutex_unlock(&par->open_lock);
+	return 0;
+}
+
 static struct fb_ops savagefb_ops = {
 	.owner          = THIS_MODULE,
+	.fb_open        = savagefb_open,
+	.fb_release     = savagefb_release,
 	.fb_check_var   = savagefb_check_var,
 	.fb_set_par     = savagefb_set_par,
 	.fb_setcolreg   = savagefb_setcolreg,
@@ -2173,6 +2211,7 @@ static int __devinit savagefb_probe(stru
 	if (!info)
 		return -ENOMEM;
 	par = info->par;
+	mutex_init(&par->open_lock);
 	err = pci_enable_device(dev);
 	if (err)
 		goto failed_enable;
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
index d048bd3..c149278 100644
--- a/drivers/video/sis/osdef.h
+++ b/drivers/video/sis/osdef.h
@@ -58,9 +58,6 @@ #define _SIS_OSDEF_H_
 #define SIS_LINUX_KERNEL		/* Linux kernel framebuffer */
 #undef  SIS_XORG_XF86			/* XFree86/X.org */
 
-#undef SIS_LINUX_KERNEL_24
-#undef SIS_LINUX_KERNEL_26
-
 #ifdef OutPortByte
 #undef OutPortByte
 #endif
@@ -100,8 +97,6 @@ #ifdef CONFIG_FB_SIS_315
 #define SIS315H
 #endif
 
-#define SIS_LINUX_KERNEL_26
-
 #if !defined(SIS300) && !defined(SIS315H)
 #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
 #warning sisfb will not work!
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index 7d5ee21..d5e2d9c 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -27,11 +27,7 @@ #define _SIS_H_
 #include <linux/version.h>
 
 #include "osdef.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 #include <video/sisfb.h>
-#else
-#include <linux/sisfb.h>
-#endif
 
 #include "vgatypes.h"
 #include "vstruct.h"
@@ -40,33 +36,17 @@ #define VER_MAJOR		1
 #define VER_MINOR		8
 #define VER_LEVEL		9
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 #include <linux/spinlock.h>
-#define SIS_PCI_GET_CLASS(a, b) pci_get_class(a, b)
-#define SIS_PCI_GET_DEVICE(a,b,c) pci_get_device(a,b,c)
-#define SIS_PCI_GET_SLOT(a,b) pci_get_slot(a,b)
-#define SIS_PCI_PUT_DEVICE(a) pci_dev_put(a)
+
 #ifdef CONFIG_COMPAT
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
 #include <linux/ioctl32.h>
 #define SIS_OLD_CONFIG_COMPAT
 #else
-#include <linux/smp_lock.h>
 #define SIS_NEW_CONFIG_COMPAT
 #endif
 #endif	/* CONFIG_COMPAT */
-#else  /* 2.4 */
-#define SIS_PCI_GET_CLASS(a, b) pci_find_class(a, b)
-#define SIS_PCI_GET_DEVICE(a,b,c) pci_find_device(a,b,c)
-#define SIS_PCI_GET_SLOT(a,b) pci_find_slot(a,b)
-#define SIS_PCI_PUT_DEVICE(a)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
-#ifdef __x86_64__	/* Shouldn't we check for CONFIG_IA32_EMULATION here? */
-#include <asm/ioctl32.h>
-#define SIS_OLD_CONFIG_COMPAT
-#endif
-#endif
-#endif /* 2.4 */
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
 #define SIS_IOTYPE1 void __iomem
 #define SIS_IOTYPE2 __iomem
@@ -498,26 +478,8 @@ struct sis_video_info {
 
 	struct fb_var_screeninfo default_var;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	struct fb_fix_screeninfo sisfb_fix;
 	u32		pseudo_palette[17];
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	struct display		 sis_disp;
-	struct display_switch 	 sisfb_sw;
-	struct {
-		u16 red, green, blue, pad;
-	}		sis_palette[256];
-	union {
-#ifdef FBCON_HAS_CFB16
-		u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-		u32 cfb32[16];
-#endif
-	}		sis_fbcon_cmap;
-#endif
 
 	struct sisfb_monitor {
 		u16 hmin;
@@ -538,10 +500,6 @@ #endif
 
 	int		mni;	/* Mode number index */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	int		currcon;
-#endif
-
 	unsigned long	video_size;
 	unsigned long	video_base;
 	unsigned long	mmio_size;
@@ -578,9 +536,6 @@ #endif
 	int		sisfb_tvplug;
 	int		sisfb_tvstd;
 	int		sisfb_nocrt2rate;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	int		sisfb_inverse;
-#endif
 
 	u32		heapstart;		/* offset  */
 	SIS_IOTYPE1	*sisfb_heap_start;	/* address */
@@ -646,9 +601,7 @@ #endif
 	int		modechanged;
 	unsigned char	modeprechange;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 	u8		sisfb_lastrates[128];
-#endif
 
 	int		newrom;
 	int		haveXGIROM;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 01197d7..a30e1e1 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -37,7 +37,6 @@ #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -1948,7 +1947,7 @@ #endif
 	default:	return NULL;
 	}
 	for(i = 0; i < nbridgenum; i++) {
-		if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
+		if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
 				nbridgeids[nbridgeidx+i], NULL)))
 			break;
 	}
@@ -4613,9 +4612,9 @@ sisfb_find_host_bridge(struct sis_video_
 	unsigned short temp;
 	int ret = 0;
 
-	while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
+	while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
 		temp = pdev->vendor;
-		SIS_PCI_PUT_DEVICE(pdev);
+		pci_dev_put(pdev);
 		if(temp == pcivendor) {
 			ret = 1;
 			break;
@@ -5154,24 +5153,24 @@ sisfb_post_xgi(struct pci_dev *pdev)
 			if(reg & 0x80) v2 |= 0x80;
 			v2 |= 0x01;
 
-			if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
-				SIS_PCI_PUT_DEVICE(mypdev);
+			if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
+				pci_dev_put(mypdev);
 				if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
 					v2 &= 0xf9;
 				v2 |= 0x08;
 				v1 &= 0xfe;
 			} else {
-				mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
+				mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
 				if(!mypdev)
-					mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
+					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
 				if(!mypdev)
-					mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
+					mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
 				if(mypdev) {
 					pci_read_config_dword(mypdev, 0x94, &regd);
 					regd &= 0xfffffeff;
 					pci_write_config_dword(mypdev, 0x94, regd);
 					v1 &= 0xfe;
-					SIS_PCI_PUT_DEVICE(mypdev);
+					pci_dev_put(mypdev);
 				} else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
 					v1 &= 0xfe;
 				} else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
@@ -5194,13 +5193,13 @@ sisfb_post_xgi(struct pci_dev *pdev)
 			if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
 				setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
 
-			if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
+			if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
 				/* TODO: set CR5f &0xf1 | 0x01 for version 6570
 				 * of nforce 2 ROM
 				 */
 				if(0)
 					setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
-				SIS_PCI_PUT_DEVICE(mypdev);
+				pci_dev_put(mypdev);
 			}
 		}
 
@@ -5236,9 +5235,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
 		setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
 		setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
 		v1 = bios[0x501];
-		if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
+		if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
 			v1 = 0xf0;
-			SIS_PCI_PUT_DEVICE(mypdev);
+			pci_dev_put(mypdev);
 		}
 		outSISIDXREG(SISCR, 0x77, v1);
 	}
@@ -5947,7 +5946,7 @@ #endif
 
 	if(!ivideo->sisvga_enabled) {
 		if(pci_enable_device(pdev)) {
-			if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+			if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
 			pci_set_drvdata(pdev, NULL);
 			kfree(sis_fb_info);
 			return -EIO;
@@ -5974,7 +5973,7 @@ #ifdef CONFIG_FB_SIS_300
 					"requiring Chrontel/GPIO setup\n",
 					mychswtable[i].vendorName,
 					mychswtable[i].cardName);
-				ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
+				ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
 				break;
 			}
 			i++;
@@ -5984,7 +5983,7 @@ #endif
 
 #ifdef CONFIG_FB_SIS_315
 	if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
-		ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
+		ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
 	}
 #endif
 
@@ -6149,9 +6148,9 @@ error_1:	release_mem_region(ivideo->vide
 error_2:	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
 error_3:	vfree(ivideo->bios_abase);
 		if(ivideo->lpcdev)
-			SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+			pci_dev_put(ivideo->lpcdev);
 		if(ivideo->nbridge)
-			SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+			pci_dev_put(ivideo->nbridge);
 		pci_set_drvdata(pdev, NULL);
 		if(!ivideo->sisvga_enabled)
 			pci_disable_device(pdev);
@@ -6331,70 +6330,6 @@ error_3:	vfree(ivideo->bios_abase);
 
 		sisfb_set_vparms(ivideo);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-		/* ---------------- For 2.4: Now switch the mode ------------------ */
-
-		printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
-			ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
-			ivideo->refresh_rate);
-
-		/* Determine whether or not acceleration is to be
-		 * used. Need to know before pre/post_set_mode()
-		 */
-		ivideo->accel = 0;
-		ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
-		if(ivideo->sisfb_accel) {
-			ivideo->accel = -1;
-			ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
-		}
-
-		/* Now switch the mode */
-		sisfb_pre_setmode(ivideo);
-
-		if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
-			printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
-									ivideo->mode_no);
-			ret = -EINVAL;
-			iounmap(ivideo->mmio_vbase);
-			goto error_0;
-		}
-
-		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
-
-		sisfb_post_setmode(ivideo);
-
-		/* Maximize regardless of sisfb_max at startup */
-		ivideo->default_var.yres_virtual = 32767;
-
-		/* Force reset of x virtual in crtc_to_var */
-		ivideo->default_var.xres_virtual = 0;
-
-		/* Copy mode timing to var */
-		sisfb_crtc_to_var(ivideo, &ivideo->default_var);
-
-		/* Find out about screen pitch */
-		sisfb_calc_pitch(ivideo, &ivideo->default_var);
-		sisfb_set_pitch(ivideo);
-
-		/* Init the accelerator (does nothing currently) */
-		sisfb_initaccel(ivideo);
-
-		/* Init some fbinfo entries */
-		sis_fb_info->node  = -1;
-		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
-		sis_fb_info->fbops = &sisfb_ops;
-		sis_fb_info->disp  = &ivideo->sis_disp;
-		sis_fb_info->blank = &sisfb_blank;
-		sis_fb_info->switch_con = &sisfb_switch;
-		sis_fb_info->updatevar  = &sisfb_update_var;
-		sis_fb_info->changevar  = NULL;
-		strcpy(sis_fb_info->fontname, sisfb_fontname);
-
-		sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
-
-#else		/* --------- For 2.6: Setup a somewhat sane default var ------------ */
-
 		printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
 			ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
 			ivideo->refresh_rate);
@@ -6454,7 +6389,6 @@ #endif
 		sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
 
 		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
-#endif		/* 2.6 */
 
 		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
 
@@ -6564,10 +6498,10 @@ #endif
 	vfree(ivideo->bios_abase);
 
 	if(ivideo->lpcdev)
-		SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+		pci_dev_put(ivideo->lpcdev);
 
 	if(ivideo->nbridge)
-		SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+		pci_dev_put(ivideo->nbridge);
 
 #ifdef CONFIG_MTRR
 	/* Release MTRR region */
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index bb96cb6..842b5cd 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -51,6 +51,7 @@ #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 
     /*
      *  This is just simple sample code.
@@ -60,6 +61,11 @@ #include <linux/init.h>
      */
 
 /*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
+
+/*
  *  If your driver supports multiple boards, you should make the  
  *  below data types arrays, or allocate them dynamically (using kmalloc()). 
  */ 
@@ -78,7 +84,7 @@ struct xxx_par;
  * if we don't use modedb. If we do use modedb see xxxfb_init how to use it
  * to get a fb_var_screeninfo. Otherwise define a default var as well. 
  */
-static struct fb_fix_screeninfo xxxfb_fix __initdata = {
+static struct fb_fix_screeninfo xxxfb_fix __devinitdata = {
 	.id =		"FB's name", 
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_PSEUDOCOLOR,
@@ -142,7 +148,7 @@ int xxxfb_setup(char*);
  *
  *	Returns negative errno on error, or zero on success.
  */
-static int xxxfb_open(const struct fb_info *info, int user)
+static int xxxfb_open(struct fb_info *info, int user)
 {
     return 0;
 }
@@ -161,7 +167,7 @@ static int xxxfb_open(const struct fb_in
  *
  *	Returns negative errno on error, or zero on success.
  */
-static int xxxfb_release(const struct fb_info *info, int user)
+static int xxxfb_release(struct fb_info *info, int user)
 {
     return 0;
 }
@@ -278,7 +284,7 @@ static int xxxfb_set_par(struct fb_info 
  */
 static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
-			   const struct fb_info *info)
+			   struct fb_info *info)
 {
     if (regno >= 256)  /* no. of hw registers */
        return -EINVAL;
@@ -416,7 +422,7 @@ #undef CNVT_TOHW
  *      Returns negative errno on error, or zero on success.
  */
 static int xxxfb_pan_display(struct fb_var_screeninfo *var,
-			     const struct fb_info *info)
+			     struct fb_info *info)
 {
     /*
      * If your hardware does not support panning, _do_ _not_ implement this
@@ -454,7 +460,7 @@ static int xxxfb_pan_display(struct fb_v
  *      Return !0 for any modes that are unimplemented.
  *
  */
-static int xxxfb_blank(int blank_mode, const struct fb_info *info)
+static int xxxfb_blank(int blank_mode, struct fb_info *info)
 {
     /* ... */
     return 0;
@@ -483,7 +489,7 @@ static int xxxfb_blank(int blank_mode, c
  *	depending on the rastering operation with the value of color which
  *	is in the current color depth format.
  */
-void xxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
+void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
 {
 /*	Meaning of struct fb_fillrect
  *
@@ -623,19 +629,6 @@ void xxxfb_rotate(struct fb_info *info, 
 }
 
 /**
- *	xxxfb_poll - NOT a required function. The purpose of this
- *		     function is to provide a way for some process
- *		     to wait until a specific hardware event occurs
- *		     for the framebuffer device.
- * 				 
- *      @info: frame buffer structure that represents a single frame buffer
- *	@wait: poll table where we store process that await a event.     
- */
-void xxxfb_poll(struct fb_info *info, poll_table *wait)
-{
-}
-
-/**
  *	xxxfb_sync - NOT a required function. Normally the accel engine 
  *		     for a graphics card take a specific amount of time.
  *		     Often we have to wait for the accelerator to finish
@@ -647,21 +640,49 @@ void xxxfb_poll(struct fb_info *info, po
  *      If the driver has implemented its own hardware-based drawing function,
  *      implementing this function is highly recommended.
  */
-void xxxfb_sync(struct fb_info *info)
+int xxxfb_sync(struct fb_info *info)
 {
+	return 0;
 }
 
     /*
+     *  Frame buffer operations
+     */
+
+static struct fb_ops xxxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_open	= xxxfb_open,
+	.fb_read	= xxxfb_read,
+	.fb_write	= xxxfb_write,
+	.fb_release	= xxxfb_release,
+	.fb_check_var	= xxxfb_check_var,
+	.fb_set_par	= xxxfb_set_par,
+	.fb_setcolreg	= xxxfb_setcolreg,
+	.fb_blank	= xxxfb_blank,
+	.fb_pan_display	= xxxfb_pan_display,
+	.fb_fillrect	= xxxfb_fillrect, 	/* Needed !!! */
+	.fb_copyarea	= xxxfb_copyarea,	/* Needed !!! */
+	.fb_imageblit	= xxxfb_imageblit,	/* Needed !!! */
+	.fb_cursor	= xxxfb_cursor,		/* Optional !!! */
+	.fb_rotate	= xxxfb_rotate,
+	.fb_sync	= xxxfb_sync,
+	.fb_ioctl	= xxxfb_ioctl,
+	.fb_mmap	= xxxfb_mmap,
+};
+
+/* ------------------------------------------------------------------------- */
+
+    /*
      *  Initialization
      */
 
 /* static int __init xxfb_probe (struct device *device) -- for platform devs */
-static int __init xxxfb_probe(struct pci_dev *dev,
-			      const_struct pci_device_id *ent)
+static int __devinit xxxfb_probe(struct pci_dev *dev,
+			      const struct pci_device_id *ent)
 {
     struct fb_info *info;
     struct xxx_par *par;
-    struct device = &dev->dev; /* for pci drivers */
+    struct device* device = &dev->dev; /* for pci drivers */
     int cmap_len, retval;	
    
     /*
@@ -684,7 +705,7 @@ static int __init xxxfb_probe(struct pci
     info->screen_base = framebuffer_virtual_memory;
     info->fbops = &xxxfb_ops;
     info->fix = xxxfb_fix; /* this will be the only time xxxfb_fix will be
-			    * used, so mark it as __initdata
+			    * used, so mark it as __devinitdata
 			    */
     info->pseudo_palette = pseudo_palette; /* The pseudopalette is an
 					    * 16-member array
@@ -760,7 +781,7 @@ static int __init xxxfb_probe(struct pci
      *
      * NOTE: This field is currently unused.
      */
-    info->pixmap.scan_align = 32
+    info->pixmap.scan_align = 32;
 /***************************** End optional stage ***************************/
 
     /*
@@ -770,13 +791,13 @@ static int __init xxxfb_probe(struct pci
     if (!mode_option)
 	mode_option = "640x480@60";	 	
 
-    retval = fb_find_mode(info->var, info, mode_option, NULL, 0, NULL, 8);
+    retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
   
     if (!retval || retval == 4)
 	return -EINVAL;			
 
     /* This has to been done !!! */	
-    fb_alloc_cmap(info->cmap, cmap_len, 0);
+    fb_alloc_cmap(&info->cmap, cmap_len, 0);
 	
     /* 
      * The following is done in the case of having hardware with a static 
@@ -811,34 +832,77 @@ static int __init xxxfb_probe(struct pci
     /*
      *  Cleanup
      */
-/* static void __exit xxxfb_remove(struct device *device) */
-static void __exit xxxfb_remove(struct pci_dev *dev)
+/* static void __devexit xxxfb_remove(struct device *device) */
+static void __devexit xxxfb_remove(struct pci_dev *dev)
 {
-	struct fb_info *info = pci_get_drv_data(dev);
-	/* or dev_get_drv_data(device); */
+	struct fb_info *info = pci_get_drvdata(dev);
+	/* or dev_get_drvdata(device); */
 
 	if (info) {
 		unregister_framebuffer(info);
-		fb_dealloc_cmap(&info.cmap);
+		fb_dealloc_cmap(&info->cmap);
 		/* ... */
 		framebuffer_release(info);
 	}
+}
+
+#ifdef CONFIG_PCI
+#ifdef CONFIG_PM
+/**
+ *	xxxfb_suspend - Optional but recommended function. Suspend the device.
+ *	@dev: PCI device
+ *	@msg: the suspend event code.
+ *
+ *      See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct xxxfb_par *par = info->par;
+
+	/* suspend here */
+	return 0;
+}
+
+/**
+ *	xxxfb_resume - Optional but recommended function. Resume the device.
+ *	@dev: PCI device
+ *
+ *      See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_resume(struct pci_dev *dev)
+{
+	struct fb_info *info = pci_get_drvdata(dev);
+	struct xxxfb_par *par = info->par;
 
+	/* resume here */
 	return 0;
 }
+#else
+#define xxxfb_suspend NULL
+#define xxxfb_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pci_device_id xxxfb_id_table[] = {
+	{ PCI_VENDOR_ID_XXX, PCI_DEVICE_ID_XXX,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  PCI_CLASS_MASK, 0 },
+	{ 0, }
+};
 
-#if CONFIG_PCI
 /* For PCI drivers */
 static struct pci_driver xxxfb_driver = {
 	.name =		"xxxfb",
-	.id_table =	xxxfb_devices,
+	.id_table =	xxxfb_id_table,
 	.probe =	xxxfb_probe,
 	.remove =	__devexit_p(xxxfb_remove),
-	.suspend =      xxxfb_suspend, /* optional */
-	.resume =       xxxfb_resume,  /* optional */
+	.suspend =      xxxfb_suspend, /* optional but recommended */
+	.resume =       xxxfb_resume,  /* optional but recommended */
 };
 
-static int __init xxxfb_init(void)
+MODULE_DEVICE_TABLE(pci, xxxfb_id_table);
+
+int __init xxxfb_init(void)
 {
 	/*
 	 *  For kernel boot options (in 'video=xxxfb:<options>' format)
@@ -858,16 +922,53 @@ static void __exit xxxfb_exit(void)
 {
 	pci_unregister_driver(&xxxfb_driver);
 }
-#else
+#else /* non PCI, platform drivers */
 #include <linux/platform_device.h>
 /* for platform devices */
+
+#ifdef CONFIG_PM
+/**
+ *	xxxfb_suspend - Optional but recommended function. Suspend the device.
+ *	@dev: platform device
+ *	@msg: the suspend event code.
+ *
+ *      See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_suspend(struct platform_device *dev, pm_message_t msg)
+{
+	struct fb_info *info = platform_get_drvdata(dev);
+	struct xxxfb_par *par = info->par;
+
+	/* suspend here */
+	return 0;
+}
+
+/**
+ *	xxxfb_resume - Optional but recommended function. Resume the device.
+ *	@dev: platform device
+ *
+ *      See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_resume(struct platform_dev *dev)
+{
+	struct fb_info *info = platform_get_drvdata(dev);
+	struct xxxfb_par *par = info->par;
+
+	/* resume here */
+	return 0;
+}
+#else
+#define xxxfb_suspend NULL
+#define xxxfb_resume NULL
+#endif /* CONFIG_PM */
+
 static struct device_driver xxxfb_driver = {
 	.name = "xxxfb",
 	.bus  = &platform_bus_type,
 	.probe = xxxfb_probe,
 	.remove = xxxfb_remove,
-	.suspend = xxxfb_suspend, /* optional */
-	.resume = xxxfb_resume,   /* optional */
+	.suspend = xxxfb_suspend, /* optional but recommended */
+	.resume = xxxfb_resume,   /* optional but recommended */
 };
 
 static struct platform_device xxxfb_device = {
@@ -903,8 +1004,9 @@ static void __exit xxxfb_exit(void)
 	platform_device_unregister(&xxxfb_device);
 	driver_unregister(&xxxfb_driver);
 }
-#endif
+#endif /* CONFIG_PCI */
 
+#ifdef MODULE
     /*
      *  Setup
      */
@@ -917,34 +1019,7 @@ int __init xxxfb_setup(char *options)
 {
     /* Parse user speficied options (`video=xxxfb:') */
 }
-
-/* ------------------------------------------------------------------------- */
-
-    /*
-     *  Frame buffer operations
-     */
-
-static struct fb_ops xxxfb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_open	= xxxfb_open,
-	.fb_read	= xxxfb_read,
-	.fb_write	= xxxfb_write,
-	.fb_release	= xxxfb_release,
-	.fb_check_var	= xxxfb_check_var,
-	.fb_set_par	= xxxfb_set_par,	
-	.fb_setcolreg	= xxxfb_setcolreg,
-	.fb_blank	= xxxfb_blank,
-	.fb_pan_display	= xxxfb_pan_display,	
-	.fb_fillrect	= xxxfb_fillrect, 	/* Needed !!! */ 
-	.fb_copyarea	= xxxfb_copyarea,	/* Needed !!! */ 
-	.fb_imageblit	= xxxfb_imageblit,	/* Needed !!! */
-	.fb_cursor	= xxxfb_cursor,		/* Optional !!! */
-	.fb_rotate	= xxxfb_rotate,
-	.fb_poll	= xxxfb_poll,
-	.fb_sync	= xxxfb_sync,
-	.fb_ioctl	= xxxfb_ioctl,
-	.fb_mmap	= xxxfb_mmap,	
-};
+#endif /* MODULE */
 
 /* ------------------------------------------------------------------------- */
 
@@ -954,6 +1029,6 @@ static struct fb_ops xxxfb_ops = {
      */
 
 module_init(xxxfb_init);
-module_exit(xxxfb_cleanup);
+module_exit(xxxfb_remove);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 0a44c44..c86df12 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -989,7 +989,7 @@ static int sm501fb_cursor(struct fb_info
 			((info->cmap.green[fg_col] & 0xFC) << 3) |
 			((info->cmap.blue[fg_col] & 0xF8) >> 3);
 
-		dev_dbg(fbi->dev, "fgcol %08x, bgcol %08x\n", fg, bg);
+		dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
 
 		writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
 		writel(fg, base + SM501_OFF_HWC_COLOR_3);
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 69f3b26..c97709e 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -64,7 +64,6 @@ #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/pci.h>
 
 #include <asm/grfioctl.h>	/* for HP-UX compatibility */
 #include <asm/uaccess.h>
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
new file mode 100644
index 0000000..4316c7f
--- /dev/null
+++ b/drivers/video/sunxvr2500.c
@@ -0,0 +1,277 @@
+/* s3d.c: Sun 3DLABS XVR-2500 et al. driver for sparc64 systems
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+
+struct s3d_info {
+	struct fb_info		*info;
+	struct pci_dev		*pdev;
+
+	char __iomem		*fb_base;
+	unsigned long		fb_base_phys;
+
+	struct device_node	*of_node;
+
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		depth;
+	unsigned int		fb_size;
+
+	u32			pseudo_palette[256];
+};
+
+static int __devinit s3d_get_props(struct s3d_info *sp)
+{
+	sp->width = of_getintprop_default(sp->of_node, "width", 0);
+	sp->height = of_getintprop_default(sp->of_node, "height", 0);
+	sp->depth = of_getintprop_default(sp->of_node, "depth", 8);
+
+	if (!sp->width || !sp->height) {
+		printk(KERN_ERR "s3d: Critical properties missing for %s\n",
+		       pci_name(sp->pdev));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int s3d_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	u32 value;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	value = (blue << 24) | (green << 16) | (red << 8);
+	((u32 *)info->pseudo_palette)[regno] = value;
+
+	return 0;
+}
+
+static struct fb_ops s3d_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= s3d_setcolreg,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+};
+
+static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
+{
+	struct fb_info *info = sp->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &s3d_ops;
+	info->screen_base = sp->fb_base;
+	info->screen_size = sp->fb_size;
+
+	info->pseudo_palette = sp->pseudo_palette;
+
+	/* Fill fix common fields */
+	strlcpy(info->fix.id, "s3d", sizeof(info->fix.id));
+        info->fix.smem_start = sp->fb_base_phys;
+        info->fix.smem_len = sp->fb_size;
+        info->fix.type = FB_TYPE_PACKED_PIXELS;
+	if (sp->depth == 32 || sp->depth == 24)
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	else
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	var->xres = sp->width;
+	var->yres = sp->height;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+	var->bits_per_pixel = sp->depth;
+
+	var->red.offset = 8;
+	var->red.length = 8;
+	var->green.offset = 16;
+	var->green.length = 8;
+	var->blue.offset = 24;
+	var->blue.length = 8;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+		printk(KERN_ERR "s3d: Cannot allocate color map.\n");
+		return -ENOMEM;
+	}
+
+        return 0;
+}
+
+static int __devinit s3d_pci_register(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct s3d_info *sp;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err < 0) {
+		printk(KERN_ERR "s3d: Cannot enable PCI device %s\n",
+		       pci_name(pdev));
+		goto err_out;
+	}
+
+	info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);
+	if (!info) {
+		printk(KERN_ERR "s3d: Cannot allocate fb_info\n");
+		err = -ENOMEM;
+		goto err_disable;
+	}
+
+	sp = info->par;
+	sp->info = info;
+	sp->pdev = pdev;
+	sp->of_node = pci_device_to_OF_node(pdev);
+	if (!sp->of_node) {
+		printk(KERN_ERR "s3d: Cannot find OF node of %s\n",
+		       pci_name(pdev));
+		err = -ENODEV;
+		goto err_release_fb;
+	}
+
+	sp->fb_base_phys = pci_resource_start (pdev, 1);
+
+	err = pci_request_region(pdev, 1, "s3d framebuffer");
+	if (err < 0) {
+		printk("s3d: Cannot request region 1 for %s\n",
+		       pci_name(pdev));
+		goto err_release_fb;
+	}
+
+	err = s3d_get_props(sp);
+	if (err)
+		goto err_release_pci;
+
+	/* XXX 'linebytes' is often wrong, it is equal to the width
+	 * XXX with depth of 32 on my XVR-2500 which is clearly not
+	 * XXX right.  So we don't try to use it.
+	 */
+	switch (sp->depth) {
+	case 8:
+		info->fix.line_length = sp->width;
+		break;
+	case 16:
+		info->fix.line_length = sp->width * 2;
+		break;
+	case 24:
+		info->fix.line_length = sp->width * 3;
+		break;
+	case 32:
+		info->fix.line_length = sp->width * 4;
+		break;
+	}
+	sp->fb_size = info->fix.line_length * sp->height;
+
+	sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
+	if (!sp->fb_base)
+		goto err_release_pci;
+
+	err = s3d_set_fbinfo(sp);
+	if (err)
+		goto err_unmap_fb;
+
+	pci_set_drvdata(pdev, info);
+
+	printk("s3d: Found device at %s\n", pci_name(pdev));
+
+	err = register_framebuffer(info);
+	if (err < 0) {
+		printk(KERN_ERR "s3d: Could not register framebuffer %s\n",
+		       pci_name(pdev));
+		goto err_unmap_fb;
+	}
+
+	return 0;
+
+err_unmap_fb:
+	iounmap(sp->fb_base);
+
+err_release_pci:
+	pci_release_region(pdev, 1);
+
+err_release_fb:
+        framebuffer_release(info);
+
+err_disable:
+	pci_disable_device(pdev);
+
+err_out:
+	return err;
+}
+
+static void __devexit s3d_pci_unregister(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct s3d_info *sp = info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap(sp->fb_base);
+
+	pci_release_region(pdev, 1);
+
+        framebuffer_release(info);
+
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id s3d_pci_table[] = {
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002c),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002d),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002e),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002f),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0030),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0031),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0032),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0033),	},
+	{ 0, }
+};
+
+static struct pci_driver s3d_driver = {
+	.name		= "s3d",
+	.id_table	= s3d_pci_table,
+	.probe		= s3d_pci_register,
+	.remove		= __devexit_p(s3d_pci_unregister),
+};
+
+static int __init s3d_init(void)
+{
+	if (fb_get_options("s3d", NULL))
+		return -ENODEV;
+
+	return pci_register_driver(&s3d_driver);
+}
+
+static void __exit s3d_exit(void)
+{
+	pci_unregister_driver(&s3d_driver);
+}
+
+module_init(s3d_init);
+module_exit(s3d_exit);
+
+MODULE_DESCRIPTION("framebuffer driver for Sun XVR-2500 graphics");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
new file mode 100644
index 0000000..08880a6
--- /dev/null
+++ b/drivers/video/sunxvr500.c
@@ -0,0 +1,443 @@
+/* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D driver for sparc64 systems
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+
+/* XXX This device has a 'dev-comm' property which aparently is
+ * XXX a pointer into the openfirmware's address space which is
+ * XXX a shared area the kernel driver can use to keep OBP
+ * XXX informed about the current resolution setting.  The idea
+ * XXX is that the kernel can change resolutions, and as long
+ * XXX as the values in the 'dev-comm' area are accurate then
+ * XXX OBP can still render text properly to the console.
+ * XXX
+ * XXX I'm still working out the layout of this and whether there
+ * XXX are any signatures we need to look for etc.
+ */
+struct e3d_info {
+	struct fb_info		*info;
+	struct pci_dev		*pdev;
+
+	spinlock_t		lock;
+
+	char __iomem		*fb_base;
+	unsigned long		fb_base_phys;
+
+	unsigned long		fb8_buf_diff;
+	unsigned long		regs_base_phys;
+
+	void __iomem		*ramdac;
+
+	struct device_node	*of_node;
+
+	unsigned int		width;
+	unsigned int		height;
+	unsigned int		depth;
+	unsigned int		fb_size;
+
+	u32			fb_base_reg;
+	u32			fb8_0_off;
+	u32			fb8_1_off;
+
+	u32			pseudo_palette[256];
+};
+
+static int __devinit e3d_get_props(struct e3d_info *ep)
+{
+	ep->width = of_getintprop_default(ep->of_node, "width", 0);
+	ep->height = of_getintprop_default(ep->of_node, "height", 0);
+	ep->depth = of_getintprop_default(ep->of_node, "depth", 8);
+
+	if (!ep->width || !ep->height) {
+		printk(KERN_ERR "e3d: Critical properties missing for %s\n",
+		       pci_name(ep->pdev));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* My XVR-500 comes up, at 1280x768 and a FB base register value of
+ * 0x04000000, the following video layout register values:
+ *
+ * RAMDAC_VID_WH	0x03ff04ff
+ * RAMDAC_VID_CFG	0x1a0b0088
+ * RAMDAC_VID_32FB_0	0x04000000
+ * RAMDAC_VID_32FB_1	0x04800000
+ * RAMDAC_VID_8FB_0	0x05000000
+ * RAMDAC_VID_8FB_1	0x05200000
+ * RAMDAC_VID_XXXFB	0x05400000
+ * RAMDAC_VID_YYYFB	0x05c00000
+ * RAMDAC_VID_ZZZFB	0x05e00000
+ */
+/* Video layout registers */
+#define RAMDAC_VID_WH		0x00000070UL /* (height-1)<<16 | (width-1) */
+#define RAMDAC_VID_CFG		0x00000074UL /* 0x1a000088|(linesz_log2<<16) */
+#define RAMDAC_VID_32FB_0	0x00000078UL /* PCI base 32bpp FB buffer 0 */
+#define RAMDAC_VID_32FB_1	0x0000007cUL /* PCI base 32bpp FB buffer 1 */
+#define RAMDAC_VID_8FB_0	0x00000080UL /* PCI base 8bpp FB buffer 0 */
+#define RAMDAC_VID_8FB_1	0x00000084UL /* PCI base 8bpp FB buffer 1 */
+#define RAMDAC_VID_XXXFB	0x00000088UL /* PCI base of XXX FB */
+#define RAMDAC_VID_YYYFB	0x0000008cUL /* PCI base of YYY FB */
+#define RAMDAC_VID_ZZZFB	0x00000090UL /* PCI base of ZZZ FB */
+
+/* CLUT registers */
+#define RAMDAC_INDEX		0x000000bcUL
+#define RAMDAC_DATA		0x000000c0UL
+
+static void e3d_clut_write(struct e3d_info *ep, int index, u32 val)
+{
+	void __iomem *ramdac = ep->ramdac;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ep->lock, flags);
+
+	writel(index, ramdac + RAMDAC_INDEX);
+	writel(val, ramdac + RAMDAC_DATA);
+
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static int e3d_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct e3d_info *ep = info->par;
+	u32 red_8, green_8, blue_8;
+	u32 red_10, green_10, blue_10;
+	u32 value;
+
+	if (regno >= 256)
+		return 1;
+
+	red_8 = red >> 8;
+	green_8 = green >> 8;
+	blue_8 = blue >> 8;
+
+	value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8);
+	((u32 *)info->pseudo_palette)[regno] = value;
+
+
+	red_10 = red >> 6;
+	green_10 = green >> 6;
+	blue_10 = blue >> 6;
+
+	value = (blue_10 << 20) | (green_10 << 10) | (red_10 << 0);
+	e3d_clut_write(ep, regno, value);
+
+	return 0;
+}
+
+/* XXX This is a bit of a hack.  I can't figure out exactly how the
+ * XXX two 8bpp areas of the framebuffer work.  I imagine there is
+ * XXX a WID attribute somewhere else in the framebuffer which tells
+ * XXX the ramdac which of the two 8bpp framebuffer regions to take
+ * XXX the pixel from.  So, for now, render into both regions to make
+ * XXX sure the pixel shows up.
+ */
+static void e3d_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct e3d_info *ep = info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ep->lock, flags);
+	cfb_imageblit(info, image);
+	info->screen_base += ep->fb8_buf_diff;
+	cfb_imageblit(info, image);
+	info->screen_base -= ep->fb8_buf_diff;
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void e3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+	struct e3d_info *ep = info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ep->lock, flags);
+	cfb_fillrect(info, rect);
+	info->screen_base += ep->fb8_buf_diff;
+	cfb_fillrect(info, rect);
+	info->screen_base -= ep->fb8_buf_diff;
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void e3d_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+	struct e3d_info *ep = info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ep->lock, flags);
+	cfb_copyarea(info, area);
+	info->screen_base += ep->fb8_buf_diff;
+	cfb_copyarea(info, area);
+	info->screen_base -= ep->fb8_buf_diff;
+	spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static struct fb_ops e3d_ops = {
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= e3d_setcolreg,
+	.fb_fillrect		= e3d_fillrect,
+	.fb_copyarea		= e3d_copyarea,
+	.fb_imageblit		= e3d_imageblit,
+};
+
+static int __devinit e3d_set_fbinfo(struct e3d_info *ep)
+{
+	struct fb_info *info = ep->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &e3d_ops;
+	info->screen_base = ep->fb_base;
+	info->screen_size = ep->fb_size;
+
+	info->pseudo_palette = ep->pseudo_palette;
+
+	/* Fill fix common fields */
+	strlcpy(info->fix.id, "e3d", sizeof(info->fix.id));
+        info->fix.smem_start = ep->fb_base_phys;
+        info->fix.smem_len = ep->fb_size;
+        info->fix.type = FB_TYPE_PACKED_PIXELS;
+	if (ep->depth == 32 || ep->depth == 24)
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+	else
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	var->xres = ep->width;
+	var->yres = ep->height;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+	var->bits_per_pixel = ep->depth;
+
+	var->red.offset = 8;
+	var->red.length = 8;
+	var->green.offset = 16;
+	var->green.length = 8;
+	var->blue.offset = 24;
+	var->blue.length = 8;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+		printk(KERN_ERR "e3d: Cannot allocate color map.\n");
+		return -ENOMEM;
+	}
+
+        return 0;
+}
+
+static int __devinit e3d_pci_register(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	struct fb_info *info;
+	struct e3d_info *ep;
+	unsigned int line_length;
+	int err;
+
+	err = pci_enable_device(pdev);
+	if (err < 0) {
+		printk(KERN_ERR "e3d: Cannot enable PCI device %s\n",
+		       pci_name(pdev));
+		goto err_out;
+	}
+
+	info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev);
+	if (!info) {
+		printk(KERN_ERR "e3d: Cannot allocate fb_info\n");
+		err = -ENOMEM;
+		goto err_disable;
+	}
+
+	ep = info->par;
+	ep->info = info;
+	ep->pdev = pdev;
+	spin_lock_init(&ep->lock);
+	ep->of_node = pci_device_to_OF_node(pdev);
+	if (!ep->of_node) {
+		printk(KERN_ERR "e3d: Cannot find OF node of %s\n",
+		       pci_name(pdev));
+		err = -ENODEV;
+		goto err_release_fb;
+	}
+
+	/* Read the PCI base register of the frame buffer, which we
+	 * need in order to interpret the RAMDAC_VID_*FB* values in
+	 * the ramdac correctly.
+	 */
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
+			      &ep->fb_base_reg);
+	ep->fb_base_reg &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	ep->regs_base_phys = pci_resource_start (pdev, 1);
+	err = pci_request_region(pdev, 1, "e3d regs");
+	if (err < 0) {
+		printk("e3d: Cannot request region 1 for %s\n",
+		       pci_name(pdev));
+		goto err_release_fb;
+	}
+	ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
+	if (!ep->ramdac)
+		goto err_release_pci1;
+
+	ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
+	ep->fb8_0_off -= ep->fb_base_reg;
+
+	ep->fb8_1_off = readl(ep->ramdac + RAMDAC_VID_8FB_1);
+	ep->fb8_1_off -= ep->fb_base_reg;
+
+	ep->fb8_buf_diff = ep->fb8_1_off - ep->fb8_0_off;
+
+	ep->fb_base_phys = pci_resource_start (pdev, 0);
+	ep->fb_base_phys += ep->fb8_0_off;
+
+	err = pci_request_region(pdev, 0, "e3d framebuffer");
+	if (err < 0) {
+		printk("e3d: Cannot request region 0 for %s\n",
+		       pci_name(pdev));
+		goto err_unmap_ramdac;
+	}
+
+	err = e3d_get_props(ep);
+	if (err)
+		goto err_release_pci0;
+
+	line_length = (readl(ep->ramdac + RAMDAC_VID_CFG) >> 16) & 0xff;
+	line_length = 1 << line_length;
+
+	switch (ep->depth) {
+	case 8:
+		info->fix.line_length = line_length;
+		break;
+	case 16:
+		info->fix.line_length = line_length * 2;
+		break;
+	case 24:
+		info->fix.line_length = line_length * 3;
+		break;
+	case 32:
+		info->fix.line_length = line_length * 4;
+		break;
+	}
+	ep->fb_size = info->fix.line_length * ep->height;
+
+	ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
+	if (!ep->fb_base)
+		goto err_release_pci0;
+
+	err = e3d_set_fbinfo(ep);
+	if (err)
+		goto err_unmap_fb;
+
+	pci_set_drvdata(pdev, info);
+
+	printk("e3d: Found device at %s\n", pci_name(pdev));
+
+	err = register_framebuffer(info);
+	if (err < 0) {
+		printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
+		       pci_name(pdev));
+		goto err_unmap_fb;
+	}
+
+	return 0;
+
+err_unmap_fb:
+	iounmap(ep->fb_base);
+
+err_release_pci0:
+	pci_release_region(pdev, 0);
+
+err_unmap_ramdac:
+	iounmap(ep->ramdac);
+
+err_release_pci1:
+	pci_release_region(pdev, 1);
+
+err_release_fb:
+        framebuffer_release(info);
+
+err_disable:
+	pci_disable_device(pdev);
+
+err_out:
+	return err;
+}
+
+static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct e3d_info *ep = info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap(ep->ramdac);
+	iounmap(ep->fb_base);
+
+	pci_release_region(pdev, 0);
+	pci_release_region(pdev, 1);
+
+        framebuffer_release(info);
+
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id e3d_pci_table[] = {
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0),	},
+	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2),	},
+	{	.vendor = PCI_VENDOR_ID_3DLABS,
+		.device = PCI_ANY_ID,
+		.subvendor = PCI_VENDOR_ID_3DLABS,
+		.subdevice = 0x0108,
+	},
+	{	.vendor = PCI_VENDOR_ID_3DLABS,
+		.device = PCI_ANY_ID,
+		.subvendor = PCI_VENDOR_ID_3DLABS,
+		.subdevice = 0x0140,
+	},
+	{	.vendor = PCI_VENDOR_ID_3DLABS,
+		.device = PCI_ANY_ID,
+		.subvendor = PCI_VENDOR_ID_3DLABS,
+		.subdevice = 0x1024,
+	},
+	{ 0, }
+};
+
+static struct pci_driver e3d_driver = {
+	.name		= "e3d",
+	.id_table	= e3d_pci_table,
+	.probe		= e3d_pci_register,
+	.remove		= __devexit_p(e3d_pci_unregister),
+};
+
+static int __init e3d_init(void)
+{
+	if (fb_get_options("e3d", NULL))
+		return -ENODEV;
+
+	return pci_register_driver(&e3d_driver);
+}
+
+static void __exit e3d_exit(void)
+{
+	pci_unregister_driver(&e3d_driver);
+}
+
+module_init(e3d_init);
+module_exit(e3d_exit);
+
+MODULE_DESCRIPTION("framebuffer driver for Sun XVR-500 graphics");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 68b30d9..079cdc9 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -194,7 +194,7 @@ #endif  /*  0  */
 void svga_settile(struct fb_info *info, struct fb_tilemap *map)
 {
 	const u8 *font = map->data;
-	u8* fb = (u8 *) info->screen_base;
+	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
 	int i, c;
 
 	if ((map->width != 8) || (map->height != 16) ||
@@ -207,7 +207,8 @@ void svga_settile(struct fb_info *info, 
 	fb += 2;
 	for (c = 0; c < map->length; c++) {
 		for (i = 0; i < map->height; i++) {
-			fb[i * 4] = font[i];
+			fb_writeb(font[i], fb + i * 4);
+//			fb[i * 4] = font[i];
 		}
 		fb += 128;
 		font += map->height;
@@ -221,8 +222,8 @@ void svga_tilecopy(struct fb_info *info,
 	/*  colstride is halved in this function because u16 are used */
 	int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
 	int rowstride = colstride * (info->var.xres_virtual / 8);
-	u16 *fb = (u16 *) info->screen_base;
-	u16 *src, *dst;
+	u16 __iomem *fb = (u16 __iomem *) info->screen_base;
+	u16 __iomem *src, *dst;
 
 	if ((area->sy > area->dy) ||
 	    ((area->sy == area->dy) && (area->sx > area->dx))) {
@@ -239,10 +240,11 @@ void svga_tilecopy(struct fb_info *info,
 	    }
 
 	for (dy = 0; dy < area->height; dy++) {
-		u16* src2 = src;
-		u16* dst2 = dst;
+		u16 __iomem *src2 = src;
+		u16 __iomem *dst2 = dst;
 		for (dx = 0; dx < area->width; dx++) {
-			*dst2 = *src2;
+			fb_writew(fb_readw(src2), dst2);
+//			*dst2 = *src2;
 			src2 += colstride;
 			dst2 += colstride;
 		}
@@ -258,14 +260,14 @@ void svga_tilefill(struct fb_info *info,
 	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
 	int rowstride = colstride * (info->var.xres_virtual / 8);
 	int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
-	u8  *fb = (u8 *) info->screen_base;
+	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
 	fb += rect->sx * colstride + rect->sy * rowstride;
 
 	for (dy = 0; dy < rect->height; dy++) {
-		u8* fb2 = fb;
+		u8 __iomem *fb2 = fb;
 		for (dx = 0; dx < rect->width; dx++) {
-			fb2[0] = rect->index;
-			fb2[1] = attr;
+			fb_writeb(rect->index, fb2);
+			fb_writeb(attr, fb2 + 1);
 			fb2 += colstride;
 		}
 		fb += rowstride;
@@ -279,15 +281,15 @@ void svga_tileblit(struct fb_info *info,
 	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
 	int rowstride = colstride * (info->var.xres_virtual / 8);
 	int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
-	u8* fb = (u8 *) info->screen_base;
+	u8 __iomem *fb = (u8 __iomem *)info->screen_base;
 	fb += blit->sx * colstride + blit->sy * rowstride;
 
 	i=0;
 	for (dy=0; dy < blit->height; dy ++) {
-		u8* fb2 = fb;
+		u8 __iomem *fb2 = fb;
 		for (dx = 0; dx < blit->width; dx ++) {
-			fb2[0] = blit->indices[i];
-			fb2[1] = attr;
+			fb_writeb(blit->indices[i], fb2);
+			fb_writeb(attr, fb2 + 1);
 			fb2 += colstride;
 			i ++;
 			if (i == blit->length) return;
@@ -340,6 +342,11 @@ void svga_tilecursor(struct fb_info *inf
 	vga_wcrt(NULL, 0x0A, cs); /* set cursor start and enable it */
 }
 
+int svga_get_tilemax(struct fb_info *info)
+{
+	return 256;
+}
+
 
 /* ------------------------------------------------------------------------- */
 
@@ -621,6 +628,7 @@ EXPORT_SYMBOL(svga_tilecopy);
 EXPORT_SYMBOL(svga_tilefill);
 EXPORT_SYMBOL(svga_tileblit);
 EXPORT_SYMBOL(svga_tilecursor);
+EXPORT_SYMBOL(svga_get_tilemax);
 
 EXPORT_SYMBOL(svga_compute_pll);
 EXPORT_SYMBOL(svga_check_timings);
diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c
new file mode 100644
index 0000000..37af10a
--- /dev/null
+++ b/drivers/video/syscopyarea.c
@@ -0,0 +1,378 @@
+/*
+ *  Generic Bit Block Transfer for frame buffers located in system RAM with
+ *  packed pixels of any depth.
+ *
+ *  Based almost entirely from cfbcopyarea.c (which is based almost entirely
+ *  on Geert Uytterhoeven's copyarea routine)
+ *
+ *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "fb_draw.h"
+
+    /*
+     *  Generic bitwise copy algorithm
+     */
+
+static void
+bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+	int src_idx, int bits, unsigned n)
+{
+	unsigned long first, last;
+	int const shift = dst_idx-src_idx;
+	int left, right;
+
+	first = FB_SHIFT_HIGH(~0UL, dst_idx);
+	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+	if (!shift) {
+		/* Same alignment for source and dest */
+		if (dst_idx+n <= bits) {
+			/* Single word */
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			/* Multiple destination words */
+			/* Leading bits */
+ 			if (first != ~0UL) {
+				*dst = comp(*src, *dst, first);
+				dst++;
+				src++;
+				n -= bits - dst_idx;
+			}
+
+			/* Main chunk */
+			n /= bits;
+			while (n >= 8) {
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = *src++;
+
+			/* Trailing bits */
+			if (last)
+				*dst = comp(*src, *dst, last);
+		}
+	} else {
+		unsigned long d0, d1;
+		int m;
+
+		/* Different alignment for source and dest */
+		right = shift & (bits - 1);
+		left = -shift & (bits - 1);
+
+		if (dst_idx+n <= bits) {
+			/* Single destination word */
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				/* Single source word */
+				*dst = comp(*src >> right, *dst, first);
+			} else if (src_idx+n <= bits) {
+				/* Single source word */
+				*dst = comp(*src << left, *dst, first);
+			} else {
+				/* 2 source words */
+				d0 = *src++;
+				d1 = *src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			/* Multiple destination words */
+			/** We must always remember the last value read,
+			    because in case SRC and DST overlap bitwise (e.g.
+			    when moving just one pixel in 1bpp), we always
+			    collect one full long for DST and that might
+			    overlap with the current long from SRC. We store
+			    this value in 'd0'. */
+			d0 = *src++;
+			/* Leading bits */
+			if (shift > 0) {
+				/* Single source word */
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= bits - dst_idx;
+			} else {
+				/* 2 source words */
+				d1 = *src++;
+				*dst = comp(d0 << left | *dst >> right, *dst, first);
+				d0 = d1;
+				dst++;
+				n -= bits - dst_idx;
+			}
+
+			/* Main chunk */
+			m = n % bits;
+			n /= bits;
+			while (n >= 4) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			/* Trailing bits */
+			if (last) {
+				if (m <= right) {
+					/* Single source word */
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					/* 2 source words */
+ 					d1 = *src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
+			}
+		}
+	}
+}
+
+    /*
+     *  Generic bitwise copy algorithm, operating backward
+     */
+
+static void
+bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
+	   int src_idx, int bits, unsigned n)
+{
+	unsigned long first, last;
+	int shift;
+
+	dst += (n-1)/bits;
+	src += (n-1)/bits;
+	if ((n-1) % bits) {
+		dst_idx += (n-1) % bits;
+		dst += dst_idx >> (ffs(bits) - 1);
+		dst_idx &= bits - 1;
+		src_idx += (n-1) % bits;
+		src += src_idx >> (ffs(bits) - 1);
+		src_idx &= bits - 1;
+	}
+
+	shift = dst_idx-src_idx;
+
+	first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
+	last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
+
+	if (!shift) {
+		/* Same alignment for source and dest */
+		if ((unsigned long)dst_idx+1 >= n) {
+			/* Single word */
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			/* Multiple destination words */
+
+			/* Leading bits */
+			if (first != ~0UL) {
+				*dst = comp(*src, *dst, first);
+				dst--;
+				src--;
+				n -= dst_idx+1;
+			}
+
+			/* Main chunk */
+			n /= bits;
+			while (n >= 8) {
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				n -= 8;
+			}
+			while (n--)
+				*dst-- = *src--;
+			/* Trailing bits */
+			if (last)
+				*dst = comp(*src, *dst, last);
+		}
+	} else {
+		/* Different alignment for source and dest */
+
+		int const left = -shift & (bits-1);
+		int const right = shift & (bits-1);
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			/* Single destination word */
+			if (last)
+				first &= last;
+			if (shift < 0) {
+				/* Single source word */
+				*dst = comp(*src << left, *dst, first);
+			} else if (1+(unsigned long)src_idx >= n) {
+				/* Single source word */
+				*dst = comp(*src >> right, *dst, first);
+			} else {
+				/* 2 source words */
+				*dst = comp(*src >> right | *(src-1) << left,
+					    *dst, first);
+			}
+		} else {
+			/* Multiple destination words */
+			/** We must always remember the last value read,
+			    because in case SRC and DST overlap bitwise (e.g.
+			    when moving just one pixel in 1bpp), we always
+			    collect one full long for DST and that might
+			    overlap with the current long from SRC. We store
+			    this value in 'd0'. */
+			unsigned long d0, d1;
+			int m;
+
+			d0 = *src--;
+			/* Leading bits */
+			if (shift < 0) {
+				/* Single source word */
+				*dst = comp(d0 << left, *dst, first);
+			} else {
+				/* 2 source words */
+				d1 = *src--;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+				d0 = d1;
+			}
+			dst--;
+			n -= dst_idx+1;
+
+			/* Main chunk */
+			m = n % bits;
+			n /= bits;
+			while (n >= 4) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+			}
+
+			/* Trailing bits */
+			if (last) {
+				if (m <= left) {
+					/* Single source word */
+					*dst = comp(d0 >> right, *dst, last);
+				} else {
+					/* 2 source words */
+					d1 = *src;
+					*dst = comp(d0 >> right | d1 << left,
+						    *dst, last);
+				}
+			}
+		}
+	}
+}
+
+void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+	u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+	u32 height = area->height, width = area->width;
+	unsigned long const bits_per_line = p->fix.line_length*8u;
+	unsigned long *dst = NULL, *src = NULL;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
+	int dst_idx = 0, src_idx = 0, rev_copy = 0;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	/* if the beginning of the target area might overlap with the end of
+	the source area, be have to copy the area reverse. */
+	if ((dy == sy && dx > sx) || (dy > sy)) {
+		dy += height;
+		sy += height;
+		rev_copy = 1;
+	}
+
+	/* split the base of the framebuffer into a long-aligned address and
+	   the index of the first bit */
+	dst = src = (unsigned long *)((unsigned long)p->screen_base &
+				      ~(bytes-1));
+	dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+	/* add offset of source and target area */
+	dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+	src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+
+	if (rev_copy) {
+		while (height--) {
+			dst_idx -= bits_per_line;
+			src_idx -= bits_per_line;
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+		}
+	} else {
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bytes - 1);
+			src += src_idx >> (ffs(bits) - 1);
+			src_idx &= (bytes - 1);
+			bitcpy(dst, dst_idx, src, src_idx, bits,
+				width*p->var.bits_per_pixel);
+			dst_idx += bits_per_line;
+			src_idx += bits_per_line;
+		}
+	}
+}
+
+EXPORT_SYMBOL(sys_copyarea);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
new file mode 100644
index 0000000..a261e9e
--- /dev/null
+++ b/drivers/video/sysfillrect.c
@@ -0,0 +1,334 @@
+/*
+ *  Generic fillrect for frame buffers in system RAM with packed pixels of
+ *  any depth.
+ *
+ *  Based almost entirely from cfbfillrect.c (which is based almost entirely
+ *  on Geert Uytterhoeven's fillrect routine)
+ *
+ *      Copyright (C)  2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include "fb_draw.h"
+
+    /*
+     *  Aligned pattern fill using 32/64-bit memory accesses
+     */
+
+static void
+bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
+		unsigned n, int bits)
+{
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = FB_SHIFT_HIGH(~0UL, dst_idx);
+	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		/* Single word */
+		if (last)
+			first &= last;
+		*dst = comp(pat, *dst, first);
+	} else {
+		/* Multiple destination words */
+
+		/* Leading bits */
+ 		if (first!= ~0UL) {
+			*dst = comp(pat, *dst, first);
+			dst++;
+			n -= bits - dst_idx;
+		}
+
+		/* Main chunk */
+		n /= bits;
+		while (n >= 8) {
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			*dst++ = pat;
+			n -= 8;
+		}
+		while (n--)
+			*dst++ = pat;
+		/* Trailing bits */
+		if (last)
+			*dst = comp(pat, *dst, last);
+	}
+}
+
+
+    /*
+     *  Unaligned generic pattern fill using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
+		  int left, int right, unsigned n, int bits)
+{
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = FB_SHIFT_HIGH(~0UL, dst_idx);
+	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		/* Single word */
+		if (last)
+			first &= last;
+		*dst = comp(pat, *dst, first);
+	} else {
+		/* Multiple destination words */
+		/* Leading bits */
+		if (first) {
+			*dst = comp(pat, *dst, first);
+			dst++;
+			pat = pat << left | pat >> right;
+			n -= bits - dst_idx;
+		}
+
+		/* Main chunk */
+		n /= bits;
+		while (n >= 4) {
+			*dst++ = pat;
+			pat = pat << left | pat >> right;
+			*dst++ = pat;
+			pat = pat << left | pat >> right;
+			*dst++ = pat;
+			pat = pat << left | pat >> right;
+			*dst++ = pat;
+			pat = pat << left | pat >> right;
+			n -= 4;
+		}
+		while (n--) {
+			*dst++ = pat;
+			pat = pat << left | pat >> right;
+		}
+
+		/* Trailing bits */
+		if (last)
+			*dst = comp(pat, *dst, first);
+	}
+}
+
+    /*
+     *  Aligned pattern invert using 32/64-bit memory accesses
+     */
+static void
+bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
+		    unsigned n, int bits)
+{
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = FB_SHIFT_HIGH(~0UL, dst_idx);
+	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		/* Single word */
+		if (last)
+			first &= last;
+		*dst = comp(*dst ^ val, *dst, first);
+	} else {
+		/* Multiple destination words */
+		/* Leading bits */
+		if (first!=0UL) {
+			*dst = comp(*dst ^ val, *dst, first);
+			dst++;
+			n -= bits - dst_idx;
+		}
+
+		/* Main chunk */
+		n /= bits;
+		while (n >= 8) {
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			n -= 8;
+		}
+		while (n--)
+			*dst++ ^= val;
+		/* Trailing bits */
+		if (last)
+			*dst = comp(*dst ^ val, *dst, last);
+	}
+}
+
+
+    /*
+     *  Unaligned generic pattern invert using 32/64-bit memory accesses
+     *  The pattern must have been expanded to a full 32/64-bit value
+     *  Left/right are the appropriate shifts to convert to the pattern to be
+     *  used for the next 32/64-bit word
+     */
+
+static void
+bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
+			int left, int right, unsigned n, int bits)
+{
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+	first = FB_SHIFT_HIGH(~0UL, dst_idx);
+	last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+	if (dst_idx+n <= bits) {
+		/* Single word */
+		if (last)
+			first &= last;
+		*dst = comp(*dst ^ pat, *dst, first);
+	} else {
+		/* Multiple destination words */
+
+		/* Leading bits */
+		if (first != 0UL) {
+			*dst = comp(*dst ^ pat, *dst, first);
+			dst++;
+			pat = pat << left | pat >> right;
+			n -= bits - dst_idx;
+		}
+
+		/* Main chunk */
+		n /= bits;
+		while (n >= 4) {
+			*dst++ ^= pat;
+			pat = pat << left | pat >> right;
+			*dst++ ^= pat;
+			pat = pat << left | pat >> right;
+			*dst++ ^= pat;
+			pat = pat << left | pat >> right;
+			*dst++ ^= pat;
+			pat = pat << left | pat >> right;
+			n -= 4;
+		}
+		while (n--) {
+			*dst ^= pat;
+			pat = pat << left | pat >> right;
+		}
+
+		/* Trailing bits */
+		if (last)
+			*dst = comp(*dst ^ pat, *dst, last);
+	}
+}
+
+void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+	unsigned long pat, fg;
+	unsigned long width = rect->width, height = rect->height;
+	int bits = BITS_PER_LONG, bytes = bits >> 3;
+	u32 bpp = p->var.bits_per_pixel;
+	unsigned long *dst;
+	int dst_idx, left;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+	    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+		fg = ((u32 *) (p->pseudo_palette))[rect->color];
+	else
+		fg = rect->color;
+
+	pat = pixel_to_pat( bpp, fg);
+
+	dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
+	dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
+	dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
+	/* FIXME For now we support 1-32 bpp only */
+	left = bits % bpp;
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+	if (!left) {
+		void (*fill_op32)(unsigned long *dst, int dst_idx,
+		                  unsigned long pat, unsigned n, int bits) =
+			NULL;
+
+		switch (rect->rop) {
+		case ROP_XOR:
+			fill_op32 = bitfill_aligned_rev;
+			break;
+		case ROP_COPY:
+			fill_op32 = bitfill_aligned;
+			break;
+		default:
+			printk( KERN_ERR "cfb_fillrect(): unknown rop, "
+				"defaulting to ROP_COPY\n");
+			fill_op32 = bitfill_aligned;
+			break;
+		}
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op32(dst, dst_idx, pat, width*bpp, bits);
+			dst_idx += p->fix.line_length*8;
+		}
+	} else {
+		int right;
+		int r;
+		int rot = (left-dst_idx) % bpp;
+		void (*fill_op)(unsigned long *dst, int dst_idx,
+		                unsigned long pat, int left, int right,
+		                unsigned n, int bits) = NULL;
+
+		/* rotate pattern to correct start position */
+		pat = pat << rot | pat >> (bpp-rot);
+
+		right = bpp-left;
+		switch (rect->rop) {
+		case ROP_XOR:
+			fill_op = bitfill_unaligned_rev;
+			break;
+		case ROP_COPY:
+			fill_op = bitfill_unaligned;
+			break;
+		default:
+			printk(KERN_ERR "cfb_fillrect(): unknown rop, "
+				"defaulting to ROP_COPY\n");
+			fill_op = bitfill_unaligned;
+			break;
+		}
+		while (height--) {
+			dst += dst_idx >> (ffs(bits) - 1);
+			dst_idx &= (bits - 1);
+			fill_op(dst, dst_idx, pat, left, right,
+				width*bpp, bits);
+			r = (p->fix.line_length*8) % bpp;
+			pat = pat << (bpp-r) | pat >> r;
+			dst_idx += p->fix.line_length*8;
+		}
+	}
+}
+
+EXPORT_SYMBOL(sys_fillrect);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c
new file mode 100644
index 0000000..bd7e7e9
--- /dev/null
+++ b/drivers/video/sysimgblt.c
@@ -0,0 +1,291 @@
+/*
+ *  Generic 1-bit or 8-bit source to 1-32 bit destination expansion
+ *  for frame buffer located in system RAM with packed pixels of any depth.
+ *
+ *  Based almost entirely on cfbimgblt.c
+ *
+ *      Copyright (C)  April 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ *  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/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+static const u32 cfb_tab8[] = {
+#if defined(__BIG_ENDIAN)
+    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000,0xff000000,0x00ff0000,0xffff0000,
+    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static const u32 cfb_tab16[] = {
+#if defined(__BIG_ENDIAN)
+    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static const u32 cfb_tab32[] = {
+	0x00000000, 0xffffffff
+};
+
+static void color_imageblit(const struct fb_image *image, struct fb_info *p,
+			    void *dst1, u32 start_index, u32 pitch_index)
+{
+	/* Draw the penguin */
+	u32 *dst, *dst2;
+	u32 color = 0, val, shift;
+	int i, n, bpp = p->var.bits_per_pixel;
+	u32 null_bits = 32 - bpp;
+	u32 *palette = (u32 *) p->pseudo_palette;
+	const u8 *src = image->data;
+
+	dst2 = dst1;
+	for (i = image->height; i--; ) {
+		n = image->width;
+		dst = dst1;
+		shift = 0;
+		val = 0;
+
+		if (start_index) {
+			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,
+							 start_index));
+			val = *dst & start_mask;
+			shift = start_index;
+		}
+		while (n--) {
+			if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+			    p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+				color = palette[*src];
+			else
+				color = *src;
+			color <<= FB_LEFT_POS(bpp);
+			val |= FB_SHIFT_HIGH(color, shift);
+			if (shift >= null_bits) {
+				*dst++ = val;
+
+				val = (shift == null_bits) ? 0 :
+					FB_SHIFT_LOW(color, 32 - shift);
+			}
+			shift += bpp;
+			shift &= (32 - 1);
+			src++;
+		}
+		if (shift) {
+			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+
+			*dst &= end_mask;
+			*dst |= val;
+		}
+		dst1 += p->fix.line_length;
+		if (pitch_index) {
+			dst2 += p->fix.line_length;
+			dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+
+			start_index += pitch_index;
+			start_index &= 32 - 1;
+		}
+	}
+}
+
+static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
+				  void *dst1, u32 fgcolor, u32 bgcolor,
+				  u32 start_index, u32 pitch_index)
+{
+	u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+	u32 *dst, *dst2;
+	u32 val, pitch = p->fix.line_length;
+	u32 null_bits = 32 - bpp;
+	u32 spitch = (image->width+7)/8;
+	const u8 *src = image->data, *s;
+	u32 i, j, l;
+
+	dst2 = dst1;
+	fgcolor <<= FB_LEFT_POS(bpp);
+	bgcolor <<= FB_LEFT_POS(bpp);
+
+	for (i = image->height; i--; ) {
+		shift = val = 0;
+		l = 8;
+		j = image->width;
+		dst = dst1;
+		s = src;
+
+		/* write leading bits */
+		if (start_index) {
+			u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
+			val = *dst & start_mask;
+			shift = start_index;
+		}
+
+		while (j--) {
+			l--;
+			color = (*s & (1 << l)) ? fgcolor : bgcolor;
+			val |= FB_SHIFT_HIGH(color, shift);
+
+			/* Did the bitshift spill bits to the next long? */
+			if (shift >= null_bits) {
+				*dst++ = val;
+				val = (shift == null_bits) ? 0 :
+					FB_SHIFT_LOW(color,32 - shift);
+			}
+			shift += bpp;
+			shift &= (32 - 1);
+			if (!l) { l = 8; s++; };
+		}
+
+		/* write trailing bits */
+ 		if (shift) {
+			u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+
+			*dst &= end_mask;
+			*dst |= val;
+		}
+
+		dst1 += pitch;
+		src += spitch;
+		if (pitch_index) {
+			dst2 += pitch;
+			dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+			start_index += pitch_index;
+			start_index &= 32 - 1;
+		}
+
+	}
+}
+
+/*
+ * fast_imageblit - optimized monochrome color expansion
+ *
+ * Only if:  bits_per_pixel == 8, 16, or 32
+ *           image->width is divisible by pixel/dword (ppw);
+ *           fix->line_legth is divisible by 4;
+ *           beginning and end of a scanline is dword aligned
+ */
+static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
+				  void *dst1, u32 fgcolor, u32 bgcolor)
+{
+	u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+	u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+	u32 bit_mask, end_mask, eorx, shift;
+	const char *s = image->data, *src;
+	u32 *dst;
+	const u32 *tab = NULL;
+	int i, j, k;
+
+	switch (bpp) {
+	case 8:
+		tab = cfb_tab8;
+		break;
+	case 16:
+		tab = cfb_tab16;
+		break;
+	case 32:
+	default:
+		tab = cfb_tab32;
+		break;
+	}
+
+	for (i = ppw-1; i--; ) {
+		fgx <<= bpp;
+		bgx <<= bpp;
+		fgx |= fgcolor;
+		bgx |= bgcolor;
+	}
+
+	bit_mask = (1 << ppw) - 1;
+	eorx = fgx ^ bgx;
+	k = image->width/ppw;
+
+	for (i = image->height; i--; ) {
+		dst = dst1;
+		shift = 8;
+		src = s;
+
+		for (j = k; j--; ) {
+			shift -= ppw;
+			end_mask = tab[(*src >> shift) & bit_mask];
+			*dst++ = (end_mask & eorx) ^ bgx;
+			if (!shift) {
+				shift = 8;
+				src++;
+			}
+		}
+		dst1 += p->fix.line_length;
+		s += spitch;
+	}
+}
+
+void sys_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+	u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+	u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
+	u32 width = image->width;
+	u32 dx = image->dx, dy = image->dy;
+	void *dst1;
+
+	if (p->state != FBINFO_STATE_RUNNING)
+		return;
+
+	bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
+	start_index = bitstart & (32 - 1);
+	pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
+
+	bitstart /= 8;
+	bitstart &= ~(bpl - 1);
+	dst1 = (void __force *)p->screen_base + bitstart;
+
+	if (p->fbops->fb_sync)
+		p->fbops->fb_sync(p);
+
+	if (image->depth == 1) {
+		if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+		    p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+			fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
+			bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
+		} else {
+			fgcolor = image->fg_color;
+			bgcolor = image->bg_color;
+		}
+
+		if (32 % bpp == 0 && !start_index && !pitch_index &&
+		    ((width & (32/bpp-1)) == 0) &&
+		    bpp >= 8 && bpp <= 32)
+			fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+		else
+			slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+					start_index, pitch_index);
+	} else
+		color_imageblit(image, p, dst1, start_index, pitch_index);
+}
+
+EXPORT_SYMBOL(sys_imageblit);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 7478d0e..f0fde6e 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -5,27 +5,45 @@
  *	Copyright (C) 1997 Geert Uytterhoeven
  *	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
  *	Copyright (C) 2002 Richard Henderson
+ *	Copyright (C) 2006 Maciej W. Rozycki
  *
  *  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/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+#include <linux/bitrev.h>
 #include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
 #include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/selection.h>
-#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
+
 #include <asm/io.h>
+
 #include <video/tgafb.h>
 
+#ifdef CONFIG_PCI
+#define TGA_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define TGA_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define TGA_BUS_TC(dev) 0
+#endif
+
 /*
  * Local functions.
  */
@@ -41,14 +59,19 @@ static void tgafb_init_fix(struct fb_inf
 static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
 static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
 
-static int __devinit tgafb_pci_register(struct pci_dev *,
-					const struct pci_device_id *);
-static void __devexit tgafb_pci_unregister(struct pci_dev *);
+static int __devinit tgafb_register(struct device *dev);
+static void __devexit tgafb_unregister(struct device *dev);
 
-static const char *mode_option = "640x480@60";
+static const char *mode_option;
+static const char *mode_option_pci = "640x480@60";
+static const char *mode_option_tc = "1280x1024@72";
 
 
+static struct pci_driver tgafb_pci_driver;
+static struct tc_driver tgafb_tc_driver;
+
 /*
  *  Frame buffer operations
  */
@@ -59,15 +82,20 @@ static struct fb_ops tgafb_ops = {
 	.fb_set_par		= tgafb_set_par,
 	.fb_setcolreg		= tgafb_setcolreg,
 	.fb_blank		= tgafb_blank,
+	.fb_pan_display		= tgafb_pan_display,
 	.fb_fillrect		= tgafb_fillrect,
 	.fb_copyarea		= tgafb_copyarea,
 	.fb_imageblit		= tgafb_imageblit,
 };
 
 
+#ifdef CONFIG_PCI
 /*
  *  PCI registration operations
  */
+static int __devinit tgafb_pci_register(struct pci_dev *,
+					const struct pci_device_id *);
+static void __devexit tgafb_pci_unregister(struct pci_dev *);
 
 static struct pci_device_id const tgafb_pci_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },
@@ -75,13 +103,68 @@ static struct pci_device_id const tgafb_
 };
 MODULE_DEVICE_TABLE(pci, tgafb_pci_table);
 
-static struct pci_driver tgafb_driver = {
+static struct pci_driver tgafb_pci_driver = {
 	.name			= "tgafb",
 	.id_table		= tgafb_pci_table,
 	.probe			= tgafb_pci_register,
 	.remove			= __devexit_p(tgafb_pci_unregister),
 };
 
+static int __devinit
+tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	return tgafb_register(&pdev->dev);
+}
+
+static void __devexit
+tgafb_pci_unregister(struct pci_dev *pdev)
+{
+	tgafb_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_TC
+/*
+ *  TC registration operations
+ */
+static int __devinit tgafb_tc_register(struct device *);
+static int __devexit tgafb_tc_unregister(struct device *);
+
+static struct tc_device_id const tgafb_tc_table[] = {
+	{ "DEC     ", "PMAGD-AA" },
+	{ "DEC     ", "PMAGD   " },
+	{ }
+};
+MODULE_DEVICE_TABLE(tc, tgafb_tc_table);
+
+static struct tc_driver tgafb_tc_driver = {
+	.id_table		= tgafb_tc_table,
+	.driver			= {
+		.name		= "tgafb",
+		.bus		= &tc_bus_type,
+		.probe		= tgafb_tc_register,
+		.remove		= __devexit_p(tgafb_tc_unregister),
+	},
+};
+
+static int __devinit
+tgafb_tc_register(struct device *dev)
+{
+	int status = tgafb_register(dev);
+	if (!status)
+		get_device(dev);
+	return status;
+}
+
+static int __devexit
+tgafb_tc_unregister(struct device *dev)
+{
+	put_device(dev);
+	tgafb_unregister(dev);
+	return 0;
+}
+#endif /* CONFIG_TC */
+
 
 /**
  *      tgafb_check_var - Optional function.  Validates a var passed in.
@@ -132,10 +215,10 @@ static int
 tgafb_set_par(struct fb_info *info)
 {
 	static unsigned int const deep_presets[4] = {
-		0x00014000,
-		0x0001440d,
+		0x00004000,
+		0x0000440d,
 		0xffffffff,
-		0x0001441d
+		0x0000441d
 	};
 	static unsigned int const rasterop_presets[4] = {
 		0x00000003,
@@ -157,6 +240,8 @@ tgafb_set_par(struct fb_info *info)
 	};
 
 	struct tga_par *par = (struct tga_par *) info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 	u32 htimings, vtimings, pll_freq;
 	u8 tga_type;
 	int i;
@@ -221,7 +306,7 @@ tgafb_set_par(struct fb_info *info)
 	TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
 
 	/* Initalise RAMDAC. */
-	if (tga_type == TGA_TYPE_8PLANE) {
+	if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
 
 		/* Init BT485 RAMDAC registers.  */
 		BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
@@ -236,21 +321,7 @@ tgafb_set_par(struct fb_info *info)
 		BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
 		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
 
-#ifdef CONFIG_HW_CONSOLE
-		for (i = 0; i < 16; i++) {
-			int j = color_table[i];
-
-			TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
-				      TGA_RAMDAC_REG);
-			TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
-				      TGA_RAMDAC_REG);
-			TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
-				      TGA_RAMDAC_REG);
-		}
-		for (i = 0; i < 240 * 3; i += 4) {
-#else
 		for (i = 0; i < 256 * 3; i += 4) {
-#endif
 			TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),
 				      TGA_RAMDAC_REG);
 			TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
@@ -261,6 +332,27 @@ #endif
 				      TGA_RAMDAC_REG);
 		}
 
+	} else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+
+		/* Init BT459 RAMDAC registers.  */
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40);
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00);
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2,
+			    (par->sync_on_green ? 0xc0 : 0x40));
+
+		BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00);
+
+		/* Fill the palette.  */
+		BT459_LOAD_ADDR(par, 0x0000);
+		TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+
+		for (i = 0; i < 256 * 3; i += 4) {
+			TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+		}
+
 	} else { /* 24-plane or 24plusZ */
 
 		/* Init BT463 RAMDAC registers.  */
@@ -431,6 +523,8 @@ tgafb_setcolreg(unsigned regno, unsigned
 		unsigned transp, struct fb_info *info)
 {
 	struct tga_par *par = (struct tga_par *) info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 
 	if (regno > 255)
 		return 1;
@@ -438,12 +532,18 @@ tgafb_setcolreg(unsigned regno, unsigned
 	green >>= 8;
 	blue >>= 8;
 
-	if (par->tga_type == TGA_TYPE_8PLANE) {
+	if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
 		BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
 		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
 		TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
 		TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
 		TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+	} else if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+		BT459_LOAD_ADDR(par, regno);
+		TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+		TGA_WRITE_REG(par, red, TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, green, TGA_RAMDAC_REG);
+		TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG);
 	} else {
 		if (regno < 16) {
 			u32 value = (regno << 16) | (regno << 8) | regno;
@@ -523,16 +623,8 @@ tgafb_blank(int blank, struct fb_info *i
  *  Acceleration.
  */
 
-/**
- *      tgafb_imageblit - REQUIRED function. Can use generic routines if
- *                        non acclerated hardware and packed pixel based.
- *                        Copies a image from system memory to the screen. 
- *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @image: structure defining the image.
- */
 static void
-tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
 {
 	struct tga_par *par = (struct tga_par *) info->par;
 	u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
@@ -542,6 +634,17 @@ tgafb_imageblit(struct fb_info *info, co
 	void __iomem *regs_base;
 	void __iomem *fb_base;
 
+	is8bpp = info->var.bits_per_pixel == 8;
+
+	/* For copies that aren't pixel expansion, there's little we
+	   can do better than the generic code.  */
+	/* ??? There is a DMA write mode; I wonder if that could be
+	   made to pull the data from the image buffer...  */
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
 	dx = image->dx;
 	dy = image->dy;
 	width = image->width;
@@ -559,18 +662,8 @@ tgafb_imageblit(struct fb_info *info, co
 	if (dy + height > vyres)
 		height = vyres - dy;
 
-	/* For copies that aren't pixel expansion, there's little we
-	   can do better than the generic code.  */
-	/* ??? There is a DMA write mode; I wonder if that could be
-	   made to pull the data from the image buffer...  */
-	if (image->depth > 1) {
-		cfb_imageblit(info, image);
-		return;
-	}
-
 	regs_base = par->tga_regs_base;
 	fb_base = par->tga_fb_base;
-	is8bpp = info->var.bits_per_pixel == 8;
 
 	/* Expand the color values to fill 32-bits.  */
 	/* ??? Would be nice to notice colour changes elsewhere, so
@@ -748,6 +841,85 @@ tgafb_imageblit(struct fb_info *info, co
 		     regs_base + TGA_MODE_REG);
 }
 
+static void
+tgafb_clut_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	struct tga_par *par = (struct tga_par *) info->par;
+	u32 color, dx, dy, width, height, vxres, vyres;
+	u32 *palette = ((u32 *)info->pseudo_palette);
+	unsigned long pos, line_length, i, j;
+	const unsigned char *data;
+	void *regs_base, *fb_base;
+
+	dx = image->dx;
+	dy = image->dy;
+	width = image->width;
+	height = image->height;
+	vxres = info->var.xres_virtual;
+	vyres = info->var.yres_virtual;
+	line_length = info->fix.line_length;
+
+	/* Crop the image to the screen.  */
+	if (dx > vxres || dy > vyres)
+		return;
+	if (dx + width > vxres)
+		width = vxres - dx;
+	if (dy + height > vyres)
+		height = vyres - dy;
+
+	regs_base = par->tga_regs_base;
+	fb_base = par->tga_fb_base;
+
+	pos = dy * line_length + (dx * 4);
+	data = image->data;
+
+	/* Now copy the image, color_expanding via the palette. */
+	for (i = 0; i < height; i++) {
+		for (j = 0; j < width; j++) {
+			color = palette[*data++];
+			__raw_writel(color, fb_base + pos + j*4);
+		}
+		pos += line_length;
+	}
+}
+
+/**
+ *      tgafb_imageblit - REQUIRED function. Can use generic routines if
+ *                        non acclerated hardware and packed pixel based.
+ *                        Copies a image from system memory to the screen.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void
+tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+	unsigned int is8bpp = info->var.bits_per_pixel == 8;
+
+	/* If a mono image, regardless of FB depth, go do it. */
+	if (image->depth == 1) {
+		tgafb_mono_imageblit(info, image);
+		return;
+	}
+
+	/* For copies that aren't pixel expansion, there's little we
+	   can do better than the generic code.  */
+	/* ??? There is a DMA write mode; I wonder if that could be
+	   made to pull the data from the image buffer...  */
+	if (image->depth == info->var.bits_per_pixel) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	/* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */
+	if (!is8bpp && image->depth == 8) {
+		tgafb_clut_imageblit(info, image);
+		return;
+	}
+
+	/* Silently return... */
+}
+
 /**
  *      tgafb_fillrect - REQUIRED function. Can use generic routines if 
  *                       non acclerated hardware and packed pixel based.
@@ -1309,18 +1481,29 @@ static void
 tgafb_init_fix(struct fb_info *info)
 {
 	struct tga_par *par = (struct tga_par *)info->par;
+	int tga_bus_pci = TGA_BUS_PCI(par->dev);
+	int tga_bus_tc = TGA_BUS_TC(par->dev);
 	u8 tga_type = par->tga_type;
-	const char *tga_type_name;
+	const char *tga_type_name = NULL;
 
 	switch (tga_type) {
 	case TGA_TYPE_8PLANE:
-		tga_type_name = "Digital ZLXp-E1";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E1";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E1";
 		break;
 	case TGA_TYPE_24PLANE:
-		tga_type_name = "Digital ZLXp-E2";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E2";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E2";
 		break;
 	case TGA_TYPE_24PLUSZ:
-		tga_type_name = "Digital ZLXp-E3";
+		if (tga_bus_pci)
+			tga_type_name = "Digital ZLXp-E3";
+		if (tga_bus_tc)
+			tga_type_name = "Digital ZLX-E3";
 		break;
 	default:
 		tga_type_name = "Unknown";
@@ -1346,11 +1529,37 @@ tgafb_init_fix(struct fb_info *info)
 	info->fix.ywrapstep = 0;
 
 	info->fix.accel = FB_ACCEL_DEC_TGA;
+
+	/*
+	 * These are needed by fb_set_logo_truepalette(), so we
+	 * set them here for 24-plane cards.
+	 */
+	if (tga_type != TGA_TYPE_8PLANE) {
+		info->var.red.length = 8;
+		info->var.green.length = 8;
+		info->var.blue.length = 8;
+		info->var.red.offset = 16;
+		info->var.green.offset = 8;
+		info->var.blue.offset = 0;
+	}
 }
 
-static __devinit int
-tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	/* We just use this to catch switches out of graphics mode. */
+	tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */
+	return 0;
+}
+
+static int __devinit
+tgafb_register(struct device *dev)
 {
+	static const struct fb_videomode modedb_tc = {
+		/* 1280x1024 @ 72 Hz, 76.8 kHz hsync */
+		"1280x1024@72", 0, 1280, 1024, 7645, 224, 28, 33, 3, 160, 3,
+		FB_SYNC_ON_GREEN, FB_VMODE_NONINTERLACED
+	};
+
 	static unsigned int const fb_offset_presets[4] = {
 		TGA_8PLANE_FB_OFFSET,
 		TGA_24PLANE_FB_OFFSET,
@@ -1358,40 +1567,51 @@ tgafb_pci_register(struct pci_dev *pdev,
 		TGA_24PLUSZ_FB_OFFSET
 	};
 
+	const struct fb_videomode *modedb_tga = NULL;
+	resource_size_t bar0_start = 0, bar0_len = 0;
+	const char *mode_option_tga = NULL;
+	int tga_bus_pci = TGA_BUS_PCI(dev);
+	int tga_bus_tc = TGA_BUS_TC(dev);
+	unsigned int modedbsize_tga = 0;
 	void __iomem *mem_base;
-	unsigned long bar0_start, bar0_len;
 	struct fb_info *info;
 	struct tga_par *par;
 	u8 tga_type;
-	int ret;
+	int ret = 0;
 
 	/* Enable device in PCI config.  */
-	if (pci_enable_device(pdev)) {
+	if (tga_bus_pci && pci_enable_device(to_pci_dev(dev))) {
 		printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
 		return -ENODEV;
 	}
 
 	/* Allocate the fb and par structures.  */
-	info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev);
+	info = framebuffer_alloc(sizeof(struct tga_par), dev);
 	if (!info) {
 		printk(KERN_ERR "tgafb: Cannot allocate memory\n");
 		return -ENOMEM;
 	}
 
 	par = info->par;
-	pci_set_drvdata(pdev, info);
+	dev_set_drvdata(dev, info);
 
 	/* Request the mem regions.  */
-	bar0_start = pci_resource_start(pdev, 0);
-	bar0_len = pci_resource_len(pdev, 0);
 	ret = -ENODEV;
+	if (tga_bus_pci) {
+		bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+		bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+	}
+	if (tga_bus_tc) {
+		bar0_start = to_tc_dev(dev)->resource.start;
+		bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+	}
 	if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
 		printk(KERN_ERR "tgafb: cannot reserve FB region\n");
 		goto err0;
 	}
 
 	/* Map the framebuffer.  */
-	mem_base = ioremap(bar0_start, bar0_len);
+	mem_base = ioremap_nocache(bar0_start, bar0_len);
 	if (!mem_base) {
 		printk(KERN_ERR "tgafb: Cannot map MMIO\n");
 		goto err1;
@@ -1399,12 +1619,16 @@ tgafb_pci_register(struct pci_dev *pdev,
 
 	/* Grab info about the card.  */
 	tga_type = (readl(mem_base) >> 12) & 0x0f;
-	par->pdev = pdev;
+	par->dev = dev;
 	par->tga_mem_base = mem_base;
 	par->tga_fb_base = mem_base + fb_offset_presets[tga_type];
 	par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
 	par->tga_type = tga_type;
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev);
+	if (tga_bus_pci)
+		pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID,
+				     &par->tga_chip_rev);
+	if (tga_bus_tc)
+		par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff;
 
 	/* Setup framebuffer.  */
 	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
@@ -1414,8 +1638,17 @@ tgafb_pci_register(struct pci_dev *pdev,
 	info->pseudo_palette = (void *)(par + 1);
 
 	/* This should give a reasonable default video mode.  */
-
-	ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL,
+	if (tga_bus_pci) {
+		mode_option_tga = mode_option_pci;
+	}
+	if (tga_bus_tc) {
+		mode_option_tga = mode_option_tc;
+		modedb_tga = &modedb_tc;
+		modedbsize_tga = 1;
+	}
+	ret = fb_find_mode(&info->var, info,
+			   mode_option ? mode_option : mode_option_tga,
+			   modedb_tga, modedbsize_tga, NULL,
 			   tga_type == TGA_TYPE_8PLANE ? 8 : 32);
 	if (ret == 0 || ret == 4) {
 		printk(KERN_ERR "tgafb: Could not find valid video mode\n");
@@ -1438,13 +1671,19 @@ tgafb_pci_register(struct pci_dev *pdev,
 		goto err1;
 	}
 
-	printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
-	       par->tga_chip_rev);
-	printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
-	       pdev->bus->number, PCI_SLOT(pdev->devfn),
-	       PCI_FUNC(pdev->devfn));
-	printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
-	       info->node, info->fix.id, bar0_start);
+	if (tga_bus_pci) {
+		pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
+			par->tga_chip_rev);
+		pr_info("tgafb: at PCI bus %d, device %d, function %d\n",
+			to_pci_dev(dev)->bus->number,
+			PCI_SLOT(to_pci_dev(dev)->devfn),
+			PCI_FUNC(to_pci_dev(dev)->devfn));
+	}
+	if (tga_bus_tc)
+		pr_info("tgafb: SFB+ detected, rev=0x%02x\n",
+			par->tga_chip_rev);
+	pr_info("fb%d: %s frame buffer device at 0x%lx\n",
+		info->node, info->fix.id, (long)bar0_start);
 
 	return 0;
 
@@ -1458,25 +1697,39 @@ tgafb_pci_register(struct pci_dev *pdev,
 }
 
 static void __devexit
-tgafb_pci_unregister(struct pci_dev *pdev)
+tgafb_unregister(struct device *dev)
 {
-	struct fb_info *info = pci_get_drvdata(pdev);
-	struct tga_par *par = info->par;
+	resource_size_t bar0_start = 0, bar0_len = 0;
+	int tga_bus_pci = TGA_BUS_PCI(dev);
+	int tga_bus_tc = TGA_BUS_TC(dev);
+	struct fb_info *info = NULL;
+	struct tga_par *par;
 
+	info = dev_get_drvdata(dev);
 	if (!info)
 		return;
+
+	par = info->par;
 	unregister_framebuffer(info);
 	fb_dealloc_cmap(&info->cmap);
 	iounmap(par->tga_mem_base);
-	release_mem_region(pci_resource_start(pdev, 0),
-			   pci_resource_len(pdev, 0));
+	if (tga_bus_pci) {
+		bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+		bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+	}
+	if (tga_bus_tc) {
+		bar0_start = to_tc_dev(dev)->resource.start;
+		bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+	}
+	release_mem_region(bar0_start, bar0_len);
 	framebuffer_release(info);
 }
 
 static void __devexit
 tgafb_exit(void)
 {
-	pci_unregister_driver(&tgafb_driver);
+	tc_unregister_driver(&tgafb_tc_driver);
+	pci_unregister_driver(&tgafb_pci_driver);
 }
 
 #ifndef MODULE
@@ -1505,6 +1758,7 @@ #endif /* !MODULE */
 static int __devinit
 tgafb_init(void)
 {
+	int status;
 #ifndef MODULE
 	char *option = NULL;
 
@@ -1512,7 +1766,10 @@ #ifndef MODULE
 		return -ENODEV;
 	tgafb_setup(option);
 #endif
-	return pci_register_driver(&tgafb_driver);
+	status = pci_register_driver(&tgafb_pci_driver);
+	if (!status)
+		status = tc_register_driver(&tgafb_tc_driver);
+	return status;
 }
 
 /*
@@ -1522,5 +1779,5 @@ #endif
 module_init(tgafb_init);
 module_exit(tgafb_exit);
 
-MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
+MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset");
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 06fc19a..ad66f07 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -51,7 +51,6 @@ #include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/selection.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <linux/nvram.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
diff --git a/drivers/video/vermilion/Makefile b/drivers/video/vermilion/Makefile
new file mode 100644
index 0000000..cc21a65
--- /dev/null
+++ b/drivers/video/vermilion/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_FB_LE80578) += vmlfb.o
+obj-$(CONFIG_FB_CARILLO_RANCH) += crvml.o
+
+vmlfb-objs := vermilion.o
+crvml-objs := cr_pll.o
diff --git a/drivers/video/vermilion/cr_pll.c b/drivers/video/vermilion/cr_pll.c
new file mode 100644
index 0000000..ebc6e6e
--- /dev/null
+++ b/drivers/video/vermilion/cr_pll.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Carillo Ranch video subsystem driver.
+ * The Carillo Ranch video subsystem 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Carillo Ranch video subsystem 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 this driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include "vermilion.h"
+
+/* The PLL Clock register sits on Host bridge */
+#define CRVML_DEVICE_MCH   0x5001
+#define CRVML_REG_MCHBAR   0x44
+#define CRVML_REG_MCHEN    0x54
+#define CRVML_MCHEN_BIT    (1 << 28)
+#define CRVML_MCHMAP_SIZE  4096
+#define CRVML_REG_CLOCK    0xc3c
+#define CRVML_CLOCK_SHIFT  8
+#define CRVML_CLOCK_MASK   0x00000f00
+
+static struct pci_dev *mch_dev;
+static u32 mch_bar;
+static void __iomem *mch_regs_base;
+static u32 saved_clock;
+
+static const unsigned crvml_clocks[] = {
+	6750,
+	13500,
+	27000,
+	29700,
+	37125,
+	54000,
+	59400,
+	74250,
+	120000
+	    /*
+	     * There are more clocks, but they are disabled on the CR board.
+	     */
+};
+
+static const u32 crvml_clock_bits[] = {
+	0x0a,
+	0x09,
+	0x08,
+	0x07,
+	0x06,
+	0x05,
+	0x04,
+	0x03,
+	0x0b
+};
+
+static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
+
+static int crvml_sys_restore(struct vml_sys *sys)
+{
+	void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+
+	iowrite32(saved_clock, clock_reg);
+	ioread32(clock_reg);
+
+	return 0;
+}
+
+static int crvml_sys_save(struct vml_sys *sys)
+{
+	void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+
+	saved_clock = ioread32(clock_reg);
+
+	return 0;
+}
+
+static int crvml_nearest_index(const struct vml_sys *sys, int clock)
+{
+	int i;
+	int cur_index = 0;
+	int cur_diff;
+	int diff;
+
+	cur_diff = clock - crvml_clocks[0];
+	cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
+	for (i = 1; i < crvml_num_clocks; ++i) {
+		diff = clock - crvml_clocks[i];
+		diff = (diff < 0) ? -diff : diff;
+		if (diff < cur_diff) {
+			cur_index = i;
+			cur_diff = diff;
+		}
+	}
+	return cur_index;
+}
+
+static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
+{
+	return crvml_clocks[crvml_nearest_index(sys, clock)];
+}
+
+static int crvml_set_clock(struct vml_sys *sys, int clock)
+{
+	void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+	int index;
+	u32 clock_val;
+
+	index = crvml_nearest_index(sys, clock);
+
+	if (crvml_clocks[index] != clock)
+		return -EINVAL;
+
+	clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
+	clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
+	iowrite32(clock_val, clock_reg);
+	ioread32(clock_reg);
+
+	return 0;
+}
+
+static struct vml_sys cr_pll_ops = {
+	.name = "Carillo Ranch",
+	.save = crvml_sys_save,
+	.restore = crvml_sys_restore,
+	.set_clock = crvml_set_clock,
+	.nearest_clock = crvml_nearest_clock,
+};
+
+static int __init cr_pll_init(void)
+{
+	int err;
+	u32 dev_en;
+
+	mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					CRVML_DEVICE_MCH, NULL);
+	if (!mch_dev) {
+		printk(KERN_ERR
+		       "Could not find Carillo Ranch MCH device.\n");
+		return -ENODEV;
+	}
+
+	pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
+	if (!(dev_en & CRVML_MCHEN_BIT)) {
+		printk(KERN_ERR
+		       "Carillo Ranch MCH device was not enabled.\n");
+		pci_dev_put(mch_dev);
+		return -ENODEV;
+	}
+
+	pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
+			      &mch_bar);
+	mch_regs_base =
+	    ioremap_nocache(mch_bar, CRVML_MCHMAP_SIZE);
+	if (!mch_regs_base) {
+		printk(KERN_ERR
+		       "Carillo Ranch MCH device was not enabled.\n");
+		pci_dev_put(mch_dev);
+		return -ENODEV;
+	}
+
+	err = vmlfb_register_subsys(&cr_pll_ops);
+	if (err) {
+		printk(KERN_ERR
+		       "Carillo Ranch failed to initialize vml_sys.\n");
+		pci_dev_put(mch_dev);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit cr_pll_exit(void)
+{
+	vmlfb_unregister_subsys(&cr_pll_ops);
+
+	iounmap(mch_regs_base);
+	pci_dev_put(mch_dev);
+}
+
+module_init(cr_pll_init);
+module_exit(cr_pll_exit);
+
+MODULE_AUTHOR("Tungsten Graphics Inc.");
+MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
new file mode 100644
index 0000000..de531c9
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.c
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Vermilion Range fb driver.
+ * The Vermilion Range fb 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Vermilion Range fb 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 this driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ *   Michel Dänzer <michel-at-tungstengraphics-dot-com>
+ *   Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <linux/mmzone.h>
+#include <asm/uaccess.h>
+
+/* #define VERMILION_DEBUG */
+
+#include "vermilion.h"
+
+#define MODULE_NAME "vmlfb"
+
+#define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
+
+static struct mutex vml_mutex;
+static struct list_head global_no_mode;
+static struct list_head global_has_mode;
+static struct fb_ops vmlfb_ops;
+static struct vml_sys *subsys = NULL;
+static char *vml_default_mode = "1024x768@60";
+static struct fb_videomode defaultmode = {
+	NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+};
+
+static u32 vml_mem_requested = (10 * 1024 * 1024);
+static u32 vml_mem_contig = (4 * 1024 * 1024);
+static u32 vml_mem_min = (4 * 1024 * 1024);
+
+static u32 vml_clocks[] = {
+	6750,
+	13500,
+	27000,
+	29700,
+	37125,
+	54000,
+	59400,
+	74250,
+	120000,
+	148500
+};
+
+static u32 vml_num_clocks = ARRAY_SIZE(vml_clocks);
+
+/*
+ * Allocate a contiguous vram area and make its linear kernel map
+ * uncached.
+ */
+
+static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
+				 unsigned min_order)
+{
+	gfp_t flags;
+	unsigned long i;
+	pgprot_t wc_pageprot;
+
+	wc_pageprot = PAGE_KERNEL_NOCACHE;
+	max_order++;
+	do {
+		/*
+		 * Really try hard to get the needed memory.
+		 * We need memory below the first 32MB, so we
+		 * add the __GFP_DMA flag that guarantees that we are
+		 * below the first 16MB.
+		 */
+
+		flags = __GFP_DMA | __GFP_HIGH;
+		va->logical =
+			 __get_free_pages(flags, --max_order);
+	} while (va->logical == 0 && max_order > min_order);
+
+	if (!va->logical)
+		return -ENOMEM;
+
+	va->phys = virt_to_phys((void *)va->logical);
+	va->size = PAGE_SIZE << max_order;
+	va->order = max_order;
+
+	/*
+	 * It seems like __get_free_pages only ups the usage count
+	 * of the first page. This doesn't work with nopage mapping, so
+	 * up the usage count once more.
+	 */
+
+	memset((void *)va->logical, 0x00, va->size);
+	for (i = va->logical; i < va->logical + va->size; i += PAGE_SIZE) {
+		get_page(virt_to_page(i));
+	}
+
+	/*
+	 * Change caching policy of the linear kernel map to avoid
+	 * mapping type conflicts with user-space mappings.
+	 * The first global_flush_tlb() is really only there to do a global
+	 * wbinvd().
+	 */
+
+	global_flush_tlb();
+	change_page_attr(virt_to_page(va->logical), va->size >> PAGE_SHIFT,
+			 wc_pageprot);
+	global_flush_tlb();
+
+	printk(KERN_DEBUG MODULE_NAME
+	       ": Allocated %ld bytes vram area at 0x%08lx\n",
+	       va->size, va->phys);
+
+	return 0;
+}
+
+/*
+ * Free a contiguous vram area and reset its linear kernel map
+ * mapping type.
+ */
+
+static void vmlfb_free_vram_area(struct vram_area *va)
+{
+	unsigned long j;
+
+	if (va->logical) {
+
+		/*
+		 * Reset the linear kernel map caching policy.
+		 */
+
+		change_page_attr(virt_to_page(va->logical),
+				 va->size >> PAGE_SHIFT, PAGE_KERNEL);
+		global_flush_tlb();
+
+		/*
+		 * Decrease the usage count on the pages we've used
+		 * to compensate for upping when allocating.
+		 */
+
+		for (j = va->logical; j < va->logical + va->size;
+		     j += PAGE_SIZE) {
+			(void)put_page_testzero(virt_to_page(j));
+		}
+
+		printk(KERN_DEBUG MODULE_NAME
+		       ": Freeing %ld bytes vram area at 0x%08lx\n",
+		       va->size, va->phys);
+		free_pages(va->logical, va->order);
+
+		va->logical = 0;
+	}
+}
+
+/*
+ * Free allocated vram.
+ */
+
+static void vmlfb_free_vram(struct vml_info *vinfo)
+{
+	int i;
+
+	for (i = 0; i < vinfo->num_areas; ++i) {
+		vmlfb_free_vram_area(&vinfo->vram[i]);
+	}
+	vinfo->num_areas = 0;
+}
+
+/*
+ * Allocate vram. Currently we try to allocate contiguous areas from the
+ * __GFP_DMA zone and puzzle them together. A better approach would be to
+ * allocate one contiguous area for scanout and use one-page allocations for
+ * offscreen areas. This requires user-space and GPU virtual mappings.
+ */
+
+static int vmlfb_alloc_vram(struct vml_info *vinfo,
+			    size_t requested,
+			    size_t min_total, size_t min_contig)
+{
+	int i, j;
+	int order;
+	int contiguous;
+	int err;
+	struct vram_area *va;
+	struct vram_area *va2;
+
+	vinfo->num_areas = 0;
+	for (i = 0; i < VML_VRAM_AREAS; ++i) {
+		va = &vinfo->vram[i];
+		order = 0;
+
+		while (requested > (PAGE_SIZE << order) && order < MAX_ORDER)
+			order++;
+
+		err = vmlfb_alloc_vram_area(va, order, 0);
+
+		if (err)
+			break;
+
+		if (i == 0) {
+			vinfo->vram_start = va->phys;
+			vinfo->vram_logical = (void __iomem *) va->logical;
+			vinfo->vram_contig_size = va->size;
+			vinfo->num_areas = 1;
+		} else {
+			contiguous = 0;
+
+			for (j = 0; j < i; ++j) {
+				va2 = &vinfo->vram[j];
+				if (va->phys + va->size == va2->phys ||
+				    va2->phys + va2->size == va->phys) {
+					contiguous = 1;
+					break;
+				}
+			}
+
+			if (contiguous) {
+				vinfo->num_areas++;
+				if (va->phys < vinfo->vram_start) {
+					vinfo->vram_start = va->phys;
+					vinfo->vram_logical =
+						(void __iomem *)va->logical;
+				}
+				vinfo->vram_contig_size += va->size;
+			} else {
+				vmlfb_free_vram_area(va);
+				break;
+			}
+		}
+
+		if (requested < va->size)
+			break;
+		else
+			requested -= va->size;
+	}
+
+	if (vinfo->vram_contig_size > min_total &&
+	    vinfo->vram_contig_size > min_contig) {
+
+		printk(KERN_DEBUG MODULE_NAME
+		       ": Contiguous vram: %ld bytes at physical 0x%08lx.\n",
+		       (unsigned long)vinfo->vram_contig_size,
+		       (unsigned long)vinfo->vram_start);
+
+		return 0;
+	}
+
+	printk(KERN_ERR MODULE_NAME
+	       ": Could not allocate requested minimal amount of vram.\n");
+
+	vmlfb_free_vram(vinfo);
+
+	return -ENOMEM;
+}
+
+/*
+ * Find the GPU to use with our display controller.
+ */
+
+static int vmlfb_get_gpu(struct vml_par *par)
+{
+	mutex_lock(&vml_mutex);
+
+	par->gpu = pci_get_device(PCI_VENDOR_ID_INTEL, VML_DEVICE_GPU, NULL);
+
+	if (!par->gpu) {
+		mutex_unlock(&vml_mutex);
+		return -ENODEV;
+	}
+
+	mutex_unlock(&vml_mutex);
+
+	if (pci_enable_device(par->gpu) < 0)
+		return -ENODEV;
+
+	return 0;
+}
+
+/*
+ * Find a contiguous vram area that contains a given offset from vram start.
+ */
+static int vmlfb_vram_offset(struct vml_info *vinfo, unsigned long offset)
+{
+	unsigned long aoffset;
+	unsigned i;
+
+	for (i = 0; i < vinfo->num_areas; ++i) {
+		aoffset = offset - (vinfo->vram[i].phys - vinfo->vram_start);
+
+		if (aoffset < vinfo->vram[i].size) {
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Remap the MMIO register spaces of the VDC and the GPU.
+ */
+
+static int vmlfb_enable_mmio(struct vml_par *par)
+{
+	int err;
+
+	par->vdc_mem_base = pci_resource_start(par->vdc, 0);
+	par->vdc_mem_size = pci_resource_len(par->vdc, 0);
+	if (!request_mem_region(par->vdc_mem_base, par->vdc_mem_size, "vmlfb")) {
+		printk(KERN_ERR MODULE_NAME
+		       ": Could not claim display controller MMIO.\n");
+		return -EBUSY;
+	}
+	par->vdc_mem = ioremap_nocache(par->vdc_mem_base, par->vdc_mem_size);
+	if (par->vdc_mem == NULL) {
+		printk(KERN_ERR MODULE_NAME
+		       ": Could not map display controller MMIO.\n");
+		err = -ENOMEM;
+		goto out_err_0;
+	}
+
+	par->gpu_mem_base = pci_resource_start(par->gpu, 0);
+	par->gpu_mem_size = pci_resource_len(par->gpu, 0);
+	if (!request_mem_region(par->gpu_mem_base, par->gpu_mem_size, "vmlfb")) {
+		printk(KERN_ERR MODULE_NAME ": Could not claim GPU MMIO.\n");
+		err = -EBUSY;
+		goto out_err_1;
+	}
+	par->gpu_mem = ioremap_nocache(par->gpu_mem_base, par->gpu_mem_size);
+	if (par->gpu_mem == NULL) {
+		printk(KERN_ERR MODULE_NAME ": Could not map GPU MMIO.\n");
+		err = -ENOMEM;
+		goto out_err_2;
+	}
+
+	return 0;
+
+out_err_2:
+	release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
+out_err_1:
+	iounmap(par->vdc_mem);
+out_err_0:
+	release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
+	return err;
+}
+
+/*
+ * Unmap the VDC and GPU register spaces.
+ */
+
+static void vmlfb_disable_mmio(struct vml_par *par)
+{
+	iounmap(par->gpu_mem);
+	release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
+	iounmap(par->vdc_mem);
+	release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
+}
+
+/*
+ * Release and uninit the VDC and GPU.
+ */
+
+static void vmlfb_release_devices(struct vml_par *par)
+{
+	if (atomic_dec_and_test(&par->refcount)) {
+		pci_set_drvdata(par->vdc, NULL);
+		pci_disable_device(par->gpu);
+		pci_disable_device(par->vdc);
+	}
+}
+
+/*
+ * Free up allocated resources for a device.
+ */
+
+static void __devexit vml_pci_remove(struct pci_dev *dev)
+{
+	struct fb_info *info;
+	struct vml_info *vinfo;
+	struct vml_par *par;
+
+	info = pci_get_drvdata(dev);
+	if (info) {
+		vinfo = container_of(info, struct vml_info, info);
+		par = vinfo->par;
+		mutex_lock(&vml_mutex);
+		unregister_framebuffer(info);
+		fb_dealloc_cmap(&info->cmap);
+		vmlfb_free_vram(vinfo);
+		vmlfb_disable_mmio(par);
+		vmlfb_release_devices(par);
+		kfree(vinfo);
+		kfree(par);
+		mutex_unlock(&vml_mutex);
+	}
+}
+
+static void vmlfb_set_pref_pixel_format(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	case 16:
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->green.offset = 5;
+		var->green.length = 5;
+		var->red.offset = 10;
+		var->red.length = 5;
+		var->transp.offset = 15;
+		var->transp.length = 1;
+		break;
+	case 32:
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 0;
+		break;
+	default:
+		break;
+	}
+
+	var->blue.msb_right = var->green.msb_right =
+	    var->red.msb_right = var->transp.msb_right = 0;
+}
+
+/*
+ * Device initialization.
+ * We initialize one vml_par struct per device and one vml_info
+ * struct per pipe. Currently we have only one pipe.
+ */
+
+static int __devinit vml_pci_probe(struct pci_dev *dev,
+				   const struct pci_device_id *id)
+{
+	struct vml_info *vinfo;
+	struct fb_info *info;
+	struct vml_par *par;
+	int err = 0;
+
+	par = kzalloc(sizeof(*par), GFP_KERNEL);
+	if (par == NULL)
+		return -ENOMEM;
+
+	vinfo = kzalloc(sizeof(*vinfo), GFP_KERNEL);
+	if (vinfo == NULL) {
+		err = -ENOMEM;
+		goto out_err_0;
+	}
+
+	vinfo->par = par;
+	par->vdc = dev;
+	atomic_set(&par->refcount, 1);
+
+	switch (id->device) {
+	case VML_DEVICE_VDC:
+		if ((err = vmlfb_get_gpu(par)))
+			goto out_err_1;
+		pci_set_drvdata(dev, &vinfo->info);
+		break;
+	default:
+		err = -ENODEV;
+		goto out_err_1;
+		break;
+	}
+
+	info = &vinfo->info;
+	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK;
+
+	err = vmlfb_enable_mmio(par);
+	if (err)
+		goto out_err_2;
+
+	err = vmlfb_alloc_vram(vinfo, vml_mem_requested,
+			       vml_mem_contig, vml_mem_min);
+	if (err)
+		goto out_err_3;
+
+	strcpy(info->fix.id, "Vermilion Range");
+	info->fix.mmio_start = 0;
+	info->fix.mmio_len = 0;
+	info->fix.smem_start = vinfo->vram_start;
+	info->fix.smem_len = vinfo->vram_contig_size;
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+	info->fix.ypanstep = 1;
+	info->fix.xpanstep = 1;
+	info->fix.ywrapstep = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->screen_base = vinfo->vram_logical;
+	info->pseudo_palette = vinfo->pseudo_palette;
+	info->par = par;
+	info->fbops = &vmlfb_ops;
+	info->device = &dev->dev;
+
+	INIT_LIST_HEAD(&vinfo->head);
+	vinfo->pipe_disabled = 1;
+	vinfo->cur_blank_mode = FB_BLANK_UNBLANK;
+
+	info->var.grayscale = 0;
+	info->var.bits_per_pixel = 16;
+	vmlfb_set_pref_pixel_format(&info->var);
+
+	if (!fb_find_mode
+	    (&info->var, info, vml_default_mode, NULL, 0, &defaultmode, 16)) {
+		printk(KERN_ERR MODULE_NAME ": Could not find initial mode\n");
+	}
+
+	if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
+		err = -ENOMEM;
+		goto out_err_4;
+	}
+
+	err = register_framebuffer(info);
+	if (err) {
+		printk(KERN_ERR MODULE_NAME ": Register framebuffer error.\n");
+		goto out_err_5;
+	}
+
+	printk("Initialized vmlfb\n");
+
+	return 0;
+
+out_err_5:
+	fb_dealloc_cmap(&info->cmap);
+out_err_4:
+	vmlfb_free_vram(vinfo);
+out_err_3:
+	vmlfb_disable_mmio(par);
+out_err_2:
+	vmlfb_release_devices(par);
+out_err_1:
+	kfree(vinfo);
+out_err_0:
+	kfree(par);
+	return err;
+}
+
+static int vmlfb_open(struct fb_info *info, int user)
+{
+	/*
+	 * Save registers here?
+	 */
+	return 0;
+}
+
+static int vmlfb_release(struct fb_info *info, int user)
+{
+	/*
+	 * Restore registers here.
+	 */
+
+	return 0;
+}
+
+static int vml_nearest_clock(int clock)
+{
+
+	int i;
+	int cur_index;
+	int cur_diff;
+	int diff;
+
+	cur_index = 0;
+	cur_diff = clock - vml_clocks[0];
+	cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
+	for (i = 1; i < vml_num_clocks; ++i) {
+		diff = clock - vml_clocks[i];
+		diff = (diff < 0) ? -diff : diff;
+		if (diff < cur_diff) {
+			cur_index = i;
+			cur_diff = diff;
+		}
+	}
+	return vml_clocks[cur_index];
+}
+
+static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
+				  struct vml_info *vinfo)
+{
+	u32 pitch;
+	u64 mem;
+	int nearest_clock;
+	int clock;
+	int clock_diff;
+	struct fb_var_screeninfo v;
+
+	v = *var;
+	clock = PICOS2KHZ(var->pixclock);
+
+	if (subsys && subsys->nearest_clock) {
+		nearest_clock = subsys->nearest_clock(subsys, clock);
+	} else {
+		nearest_clock = vml_nearest_clock(clock);
+	}
+
+	/*
+	 * Accept a 20% diff.
+	 */
+
+	clock_diff = nearest_clock - clock;
+	clock_diff = (clock_diff < 0) ? -clock_diff : clock_diff;
+	if (clock_diff > clock / 5) {
+#if 0
+		printk(KERN_DEBUG MODULE_NAME ": Diff failure. %d %d\n",clock_diff,clock);
+#endif
+		return -EINVAL;
+	}
+
+	v.pixclock = KHZ2PICOS(nearest_clock);
+
+	if (var->xres > VML_MAX_XRES || var->yres > VML_MAX_YRES) {
+		printk(KERN_DEBUG MODULE_NAME ": Resolution failure.\n");
+		return -EINVAL;
+	}
+	if (var->xres_virtual > VML_MAX_XRES_VIRTUAL) {
+		printk(KERN_DEBUG MODULE_NAME
+		       ": Virtual resolution failure.\n");
+		return -EINVAL;
+	}
+	switch (v.bits_per_pixel) {
+	case 0 ... 16:
+		v.bits_per_pixel = 16;
+		break;
+	case 17 ... 32:
+		v.bits_per_pixel = 32;
+		break;
+	default:
+		printk(KERN_DEBUG MODULE_NAME ": Invalid bpp: %d.\n",
+		       var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+	mem = pitch * var->yres_virtual;
+	if (mem > vinfo->vram_contig_size) {
+		return -ENOMEM;
+	}
+
+	switch (v.bits_per_pixel) {
+	case 16:
+		if (var->blue.offset != 0 ||
+		    var->blue.length != 5 ||
+		    var->green.offset != 5 ||
+		    var->green.length != 5 ||
+		    var->red.offset != 10 ||
+		    var->red.length != 5 ||
+		    var->transp.offset != 15 || var->transp.length != 1) {
+			vmlfb_set_pref_pixel_format(&v);
+		}
+		break;
+	case 32:
+		if (var->blue.offset != 0 ||
+		    var->blue.length != 8 ||
+		    var->green.offset != 8 ||
+		    var->green.length != 8 ||
+		    var->red.offset != 16 ||
+		    var->red.length != 8 ||
+		    (var->transp.length != 0 && var->transp.length != 8) ||
+		    (var->transp.length == 8 && var->transp.offset != 24)) {
+			vmlfb_set_pref_pixel_format(&v);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*var = v;
+
+	return 0;
+}
+
+static int vmlfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct vml_info *vinfo = container_of(info, struct vml_info, info);
+	int ret;
+
+	mutex_lock(&vml_mutex);
+	ret = vmlfb_check_var_locked(var, vinfo);
+	mutex_unlock(&vml_mutex);
+
+	return ret;
+}
+
+static void vml_wait_vblank(struct vml_info *vinfo)
+{
+	/* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
+	mdelay(20);
+}
+
+static void vmlfb_disable_pipe(struct vml_info *vinfo)
+{
+	struct vml_par *par = vinfo->par;
+
+	/* Disable the MDVO pad */
+	VML_WRITE32(par, VML_RCOMPSTAT, 0);
+	while (!(VML_READ32(par, VML_RCOMPSTAT) & VML_MDVO_VDC_I_RCOMP)) ;
+
+	/* Disable display planes */
+	VML_WRITE32(par, VML_DSPCCNTR,
+		    VML_READ32(par, VML_DSPCCNTR) & ~VML_GFX_ENABLE);
+	(void)VML_READ32(par, VML_DSPCCNTR);
+	/* Wait for vblank for the disable to take effect */
+	vml_wait_vblank(vinfo);
+
+	/* Next, disable display pipes */
+	VML_WRITE32(par, VML_PIPEACONF, 0);
+	(void)VML_READ32(par, VML_PIPEACONF);
+
+	vinfo->pipe_disabled = 1;
+}
+
+#ifdef VERMILION_DEBUG
+static void vml_dump_regs(struct vml_info *vinfo)
+{
+	struct vml_par *par = vinfo->par;
+
+	printk(KERN_DEBUG MODULE_NAME ": Modesetting register dump:\n");
+	printk(KERN_DEBUG MODULE_NAME ": \tHTOTAL_A         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_HTOTAL_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tHBLANK_A         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_HBLANK_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tHSYNC_A          : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_HSYNC_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tVTOTAL_A         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_VTOTAL_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tVBLANK_A         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_VBLANK_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tVSYNC_A          : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_VSYNC_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPCSTRIDE       : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPCSTRIDE));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPCSIZE         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPCSIZE));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPCPOS          : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPCPOS));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPARB           : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPARB));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPCADDR         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPCADDR));
+	printk(KERN_DEBUG MODULE_NAME ": \tBCLRPAT_A        : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_BCLRPAT_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tCANVSCLR_A       : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_CANVSCLR_A));
+	printk(KERN_DEBUG MODULE_NAME ": \tPIPEASRC         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_PIPEASRC));
+	printk(KERN_DEBUG MODULE_NAME ": \tPIPEACONF        : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_PIPEACONF));
+	printk(KERN_DEBUG MODULE_NAME ": \tDSPCCNTR         : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_DSPCCNTR));
+	printk(KERN_DEBUG MODULE_NAME ": \tRCOMPSTAT        : 0x%08x\n",
+	       (unsigned)VML_READ32(par, VML_RCOMPSTAT));
+	printk(KERN_DEBUG MODULE_NAME ": End of modesetting register dump.\n");
+}
+#endif
+
+static int vmlfb_set_par_locked(struct vml_info *vinfo)
+{
+	struct vml_par *par = vinfo->par;
+	struct fb_info *info = &vinfo->info;
+	struct fb_var_screeninfo *var = &info->var;
+	u32 htotal, hactive, hblank_start, hblank_end, hsync_start, hsync_end;
+	u32 vtotal, vactive, vblank_start, vblank_end, vsync_start, vsync_end;
+	u32 dspcntr;
+	int clock;
+
+	vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
+	vinfo->stride =
+	    __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+	info->fix.line_length = vinfo->stride;
+
+	if (!subsys)
+		return 0;
+
+	htotal =
+	    var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	hactive = var->xres;
+	hblank_start = var->xres;
+	hblank_end = htotal;
+	hsync_start = hactive + var->right_margin;
+	hsync_end = hsync_start + var->hsync_len;
+
+	vtotal =
+	    var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+	vactive = var->yres;
+	vblank_start = var->yres;
+	vblank_end = vtotal;
+	vsync_start = vactive + var->lower_margin;
+	vsync_end = vsync_start + var->vsync_len;
+
+	dspcntr = VML_GFX_ENABLE | VML_GFX_GAMMABYPASS;
+	clock = PICOS2KHZ(var->pixclock);
+
+	if (subsys->nearest_clock) {
+		clock = subsys->nearest_clock(subsys, clock);
+	} else {
+		clock = vml_nearest_clock(clock);
+	}
+	printk(KERN_DEBUG MODULE_NAME
+	       ": Set mode Hfreq : %d kHz, Vfreq : %d Hz.\n", clock / htotal,
+	       ((clock / htotal) * 1000) / vtotal);
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		dspcntr |= VML_GFX_ARGB1555;
+		break;
+	case 32:
+		if (var->transp.length == 8)
+			dspcntr |= VML_GFX_ARGB8888 | VML_GFX_ALPHAMULT;
+		else
+			dspcntr |= VML_GFX_RGB0888;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	vmlfb_disable_pipe(vinfo);
+	mb();
+
+	if (subsys->set_clock)
+		subsys->set_clock(subsys, clock);
+	else
+		return -EINVAL;
+
+	VML_WRITE32(par, VML_HTOTAL_A, ((htotal - 1) << 16) | (hactive - 1));
+	VML_WRITE32(par, VML_HBLANK_A,
+		    ((hblank_end - 1) << 16) | (hblank_start - 1));
+	VML_WRITE32(par, VML_HSYNC_A,
+		    ((hsync_end - 1) << 16) | (hsync_start - 1));
+	VML_WRITE32(par, VML_VTOTAL_A, ((vtotal - 1) << 16) | (vactive - 1));
+	VML_WRITE32(par, VML_VBLANK_A,
+		    ((vblank_end - 1) << 16) | (vblank_start - 1));
+	VML_WRITE32(par, VML_VSYNC_A,
+		    ((vsync_end - 1) << 16) | (vsync_start - 1));
+	VML_WRITE32(par, VML_DSPCSTRIDE, vinfo->stride);
+	VML_WRITE32(par, VML_DSPCSIZE,
+		    ((var->yres - 1) << 16) | (var->xres - 1));
+	VML_WRITE32(par, VML_DSPCPOS, 0x00000000);
+	VML_WRITE32(par, VML_DSPARB, VML_FIFO_DEFAULT);
+	VML_WRITE32(par, VML_BCLRPAT_A, 0x00000000);
+	VML_WRITE32(par, VML_CANVSCLR_A, 0x00000000);
+	VML_WRITE32(par, VML_PIPEASRC,
+		    ((var->xres - 1) << 16) | (var->yres - 1));
+
+	wmb();
+	VML_WRITE32(par, VML_PIPEACONF, VML_PIPE_ENABLE);
+	wmb();
+	VML_WRITE32(par, VML_DSPCCNTR, dspcntr);
+	wmb();
+	VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
+		    var->yoffset * vinfo->stride +
+		    var->xoffset * vinfo->bytes_per_pixel);
+
+	VML_WRITE32(par, VML_RCOMPSTAT, VML_MDVO_PAD_ENABLE);
+
+	while (!(VML_READ32(par, VML_RCOMPSTAT) &
+		 (VML_MDVO_VDC_I_RCOMP | VML_MDVO_PAD_ENABLE))) ;
+
+	vinfo->pipe_disabled = 0;
+#ifdef VERMILION_DEBUG
+	vml_dump_regs(vinfo);
+#endif
+
+	return 0;
+}
+
+static int vmlfb_set_par(struct fb_info *info)
+{
+	struct vml_info *vinfo = container_of(info, struct vml_info, info);
+	int ret;
+
+	mutex_lock(&vml_mutex);
+	list_del(&vinfo->head);
+	list_add(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
+	ret = vmlfb_set_par_locked(vinfo);
+
+	mutex_unlock(&vml_mutex);
+	return ret;
+}
+
+static int vmlfb_blank_locked(struct vml_info *vinfo)
+{
+	struct vml_par *par = vinfo->par;
+	u32 cur = VML_READ32(par, VML_PIPEACONF);
+
+	switch (vinfo->cur_blank_mode) {
+	case FB_BLANK_UNBLANK:
+		if (vinfo->pipe_disabled) {
+			vmlfb_set_par_locked(vinfo);
+		}
+		VML_WRITE32(par, VML_PIPEACONF, cur & ~VML_PIPE_FORCE_BORDER);
+		(void)VML_READ32(par, VML_PIPEACONF);
+		break;
+	case FB_BLANK_NORMAL:
+		if (vinfo->pipe_disabled) {
+			vmlfb_set_par_locked(vinfo);
+		}
+		VML_WRITE32(par, VML_PIPEACONF, cur | VML_PIPE_FORCE_BORDER);
+		(void)VML_READ32(par, VML_PIPEACONF);
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+		if (!vinfo->pipe_disabled) {
+			vmlfb_disable_pipe(vinfo);
+		}
+		break;
+	case FB_BLANK_POWERDOWN:
+		if (!vinfo->pipe_disabled) {
+			vmlfb_disable_pipe(vinfo);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vmlfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct vml_info *vinfo = container_of(info, struct vml_info, info);
+	int ret;
+
+	mutex_lock(&vml_mutex);
+	vinfo->cur_blank_mode = blank_mode;
+	ret = vmlfb_blank_locked(vinfo);
+	mutex_unlock(&vml_mutex);
+	return ret;
+}
+
+static int vmlfb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct vml_info *vinfo = container_of(info, struct vml_info, info);
+	struct vml_par *par = vinfo->par;
+
+	mutex_lock(&vml_mutex);
+	VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
+		    var->yoffset * vinfo->stride +
+		    var->xoffset * vinfo->bytes_per_pixel);
+	(void)VML_READ32(par, VML_DSPCADDR);
+	mutex_unlock(&vml_mutex);
+
+	return 0;
+}
+
+static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *info)
+{
+	u32 v;
+
+	if (regno >= 16)
+		return -EINVAL;
+
+	if (info->var.grayscale) {
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	if (info->fix.visual != FB_VISUAL_TRUECOLOR)
+		return -EINVAL;
+
+	red = VML_TOHW(red, info->var.red.length);
+	blue = VML_TOHW(blue, info->var.blue.length);
+	green = VML_TOHW(green, info->var.green.length);
+	transp = VML_TOHW(transp, info->var.transp.length);
+
+	v = (red << info->var.red.offset) |
+	    (green << info->var.green.offset) |
+	    (blue << info->var.blue.offset) |
+	    (transp << info->var.transp.offset);
+
+	switch (info->var.bits_per_pixel) {
+	case 16:
+		((u32 *) info->pseudo_palette)[regno] = v;
+		break;
+	case 24:
+	case 32:
+		((u32 *) info->pseudo_palette)[regno] = v;
+		break;
+	}
+	return 0;
+}
+
+static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct vml_info *vinfo = container_of(info, struct vml_info, info);
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	int ret;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+	if (offset + size > vinfo->vram_contig_size)
+		return -EINVAL;
+	ret = vmlfb_vram_offset(vinfo, offset);
+	if (ret)
+		return -EINVAL;
+	offset += vinfo->vram_start;
+	pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+	pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+	vma->vm_flags |= VM_RESERVED | VM_IO;
+	if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+						size, vma->vm_page_prot))
+		return -EAGAIN;
+	return 0;
+}
+
+static int vmlfb_sync(struct fb_info *info)
+{
+	return 0;
+}
+
+static int vmlfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+	return -EINVAL;	/* just to force soft_cursor() call */
+}
+
+static struct fb_ops vmlfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = vmlfb_open,
+	.fb_release = vmlfb_release,
+	.fb_check_var = vmlfb_check_var,
+	.fb_set_par = vmlfb_set_par,
+	.fb_blank = vmlfb_blank,
+	.fb_pan_display = vmlfb_pan_display,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_cursor = vmlfb_cursor,
+	.fb_sync = vmlfb_sync,
+	.fb_mmap = vmlfb_mmap,
+	.fb_setcolreg = vmlfb_setcolreg
+};
+
+static struct pci_device_id vml_ids[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)},
+	{0}
+};
+
+static struct pci_driver vmlfb_pci_driver = {
+	.name = "vmlfb",
+	.id_table = vml_ids,
+	.probe = vml_pci_probe,
+	.remove = __devexit_p(vml_pci_remove)
+};
+
+static void __exit vmlfb_cleanup(void)
+{
+	pci_unregister_driver(&vmlfb_pci_driver);
+}
+
+static int __init vmlfb_init(void)
+{
+
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options(MODULE_NAME, &option))
+		return -ENODEV;
+#endif
+
+	printk(KERN_DEBUG MODULE_NAME ": initializing\n");
+	mutex_init(&vml_mutex);
+	INIT_LIST_HEAD(&global_no_mode);
+	INIT_LIST_HEAD(&global_has_mode);
+
+	return pci_register_driver(&vmlfb_pci_driver);
+}
+
+int vmlfb_register_subsys(struct vml_sys *sys)
+{
+	struct vml_info *entry;
+	struct list_head *list;
+	u32 save_activate;
+
+	mutex_lock(&vml_mutex);
+	if (subsys != NULL) {
+		subsys->restore(subsys);
+	}
+	subsys = sys;
+	subsys->save(subsys);
+
+	/*
+	 * We need to restart list traversal for each item, since we
+	 * release the list mutex in the loop.
+	 */
+
+	list = global_no_mode.next;
+	while (list != &global_no_mode) {
+		list_del_init(list);
+		entry = list_entry(list, struct vml_info, head);
+
+		/*
+		 * First, try the current mode which might not be
+		 * completely validated with respect to the pixel clock.
+		 */
+
+		if (!vmlfb_check_var_locked(&entry->info.var, entry)) {
+			vmlfb_set_par_locked(entry);
+			list_add_tail(list, &global_has_mode);
+		} else {
+
+			/*
+			 * Didn't work. Try to find another mode,
+			 * that matches this subsys.
+			 */
+
+			mutex_unlock(&vml_mutex);
+			save_activate = entry->info.var.activate;
+			entry->info.var.bits_per_pixel = 16;
+			vmlfb_set_pref_pixel_format(&entry->info.var);
+			if (fb_find_mode(&entry->info.var,
+					 &entry->info,
+					 vml_default_mode, NULL, 0, NULL, 16)) {
+				entry->info.var.activate |=
+				    FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+				fb_set_var(&entry->info, &entry->info.var);
+			} else {
+				printk(KERN_ERR MODULE_NAME
+				       ": Sorry. no mode found for this subsys.\n");
+			}
+			entry->info.var.activate = save_activate;
+			mutex_lock(&vml_mutex);
+		}
+		vmlfb_blank_locked(entry);
+		list = global_no_mode.next;
+	}
+	mutex_unlock(&vml_mutex);
+
+	printk(KERN_DEBUG MODULE_NAME ": Registered %s subsystem.\n",
+				subsys->name ? subsys->name : "unknown");
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(vmlfb_register_subsys);
+
+void vmlfb_unregister_subsys(struct vml_sys *sys)
+{
+	struct vml_info *entry, *next;
+
+	mutex_lock(&vml_mutex);
+	if (subsys != sys) {
+		mutex_unlock(&vml_mutex);
+		return;
+	}
+	subsys->restore(subsys);
+	subsys = NULL;
+	list_for_each_entry_safe(entry, next, &global_has_mode, head) {
+		printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
+		vmlfb_disable_pipe(entry);
+		list_del(&entry->head);
+		list_add_tail(&entry->head, &global_no_mode);
+	}
+	mutex_unlock(&vml_mutex);
+}
+
+EXPORT_SYMBOL_GPL(vmlfb_unregister_subsys);
+
+module_init(vmlfb_init);
+module_exit(vmlfb_cleanup);
+
+MODULE_AUTHOR("Tungsten Graphics");
+MODULE_DESCRIPTION("Initialization of the Vermilion display devices");
+MODULE_VERSION("1.0.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.h b/drivers/video/vermilion/vermilion.h
new file mode 100644
index 0000000..1fc6695
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Vermilion Range fb driver.
+ * The Vermilion Range fb 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Vermilion Range fb 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 this driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef _VERMILION_H_
+#define _VERMILION_H_
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <asm/atomic.h>
+#include <linux/mutex.h>
+
+#define VML_DEVICE_GPU 0x5002
+#define VML_DEVICE_VDC 0x5009
+
+#define VML_VRAM_AREAS 3
+#define VML_MAX_XRES 1024
+#define VML_MAX_YRES 768
+#define VML_MAX_XRES_VIRTUAL 1040
+
+/*
+ * Display controller registers:
+ */
+
+/* Display controller 10-bit color representation */
+
+#define VML_R_MASK                   0x3FF00000
+#define VML_R_SHIFT                  20
+#define VML_G_MASK                   0x000FFC00
+#define VML_G_SHIFT                  10
+#define VML_B_MASK                   0x000003FF
+#define VML_B_SHIFT                  0
+
+/* Graphics plane control */
+#define VML_DSPCCNTR                 0x00072180
+#define VML_GFX_ENABLE               0x80000000
+#define VML_GFX_GAMMABYPASS          0x40000000
+#define VML_GFX_ARGB1555             0x0C000000
+#define VML_GFX_RGB0888              0x18000000
+#define VML_GFX_ARGB8888             0x1C000000
+#define VML_GFX_ALPHACONST           0x02000000
+#define VML_GFX_ALPHAMULT            0x01000000
+#define VML_GFX_CONST_ALPHA          0x000000FF
+
+/* Graphics plane start address. Pixel aligned. */
+#define VML_DSPCADDR                 0x00072184
+
+/* Graphics plane stride register. */
+#define VML_DSPCSTRIDE               0x00072188
+
+/* Graphics plane position register. */
+#define VML_DSPCPOS                  0x0007218C
+#define VML_POS_YMASK                0x0FFF0000
+#define VML_POS_YSHIFT               16
+#define VML_POS_XMASK                0x00000FFF
+#define VML_POS_XSHIFT               0
+
+/* Graphics plane height and width */
+#define VML_DSPCSIZE                 0x00072190
+#define VML_SIZE_HMASK               0x0FFF0000
+#define VML_SIZE_HSHIFT              16
+#define VML_SISE_WMASK               0x00000FFF
+#define VML_SIZE_WSHIFT              0
+
+/* Graphics plane gamma correction lookup table registers (129 * 32 bits) */
+#define VML_DSPCGAMLUT               0x00072200
+
+/* Pixel video output configuration register */
+#define VML_PVOCONFIG                0x00061140
+#define VML_CONFIG_BASE              0x80000000
+#define VML_CONFIG_PIXEL_SWAP        0x04000000
+#define VML_CONFIG_DE_INV            0x01000000
+#define VML_CONFIG_HREF_INV          0x00400000
+#define VML_CONFIG_VREF_INV          0x00100000
+#define VML_CONFIG_CLK_INV           0x00040000
+#define VML_CONFIG_CLK_DIV2          0x00010000
+#define VML_CONFIG_ESTRB_INV         0x00008000
+
+/* Pipe A Horizontal total register */
+#define VML_HTOTAL_A                 0x00060000
+#define VML_HTOTAL_MASK              0x1FFF0000
+#define VML_HTOTAL_SHIFT             16
+#define VML_HTOTAL_VAL               8192
+#define VML_HACTIVE_MASK             0x000007FF
+#define VML_HACTIVE_SHIFT            0
+#define VML_HACTIVE_VAL              4096
+
+/* Pipe A Horizontal Blank register */
+#define VML_HBLANK_A                 0x00060004
+#define VML_HBLANK_END_MASK          0x1FFF0000
+#define VML_HBLANK_END_SHIFT         16
+#define VML_HBLANK_END_VAL           8192
+#define VML_HBLANK_START_MASK        0x00001FFF
+#define VML_HBLANK_START_SHIFT       0
+#define VML_HBLANK_START_VAL         8192
+
+/* Pipe A Horizontal Sync register */
+#define VML_HSYNC_A                  0x00060008
+#define VML_HSYNC_END_MASK           0x1FFF0000
+#define VML_HSYNC_END_SHIFT          16
+#define VML_HSYNC_END_VAL            8192
+#define VML_HSYNC_START_MASK         0x00001FFF
+#define VML_HSYNC_START_SHIFT        0
+#define VML_HSYNC_START_VAL          8192
+
+/* Pipe A Vertical total register */
+#define VML_VTOTAL_A                 0x0006000C
+#define VML_VTOTAL_MASK              0x1FFF0000
+#define VML_VTOTAL_SHIFT             16
+#define VML_VTOTAL_VAL               8192
+#define VML_VACTIVE_MASK             0x000007FF
+#define VML_VACTIVE_SHIFT            0
+#define VML_VACTIVE_VAL              4096
+
+/* Pipe A Vertical Blank register */
+#define VML_VBLANK_A                 0x00060010
+#define VML_VBLANK_END_MASK          0x1FFF0000
+#define VML_VBLANK_END_SHIFT         16
+#define VML_VBLANK_END_VAL           8192
+#define VML_VBLANK_START_MASK        0x00001FFF
+#define VML_VBLANK_START_SHIFT       0
+#define VML_VBLANK_START_VAL         8192
+
+/* Pipe A Vertical Sync register */
+#define VML_VSYNC_A                  0x00060014
+#define VML_VSYNC_END_MASK           0x1FFF0000
+#define VML_VSYNC_END_SHIFT          16
+#define VML_VSYNC_END_VAL            8192
+#define VML_VSYNC_START_MASK         0x00001FFF
+#define VML_VSYNC_START_SHIFT        0
+#define VML_VSYNC_START_VAL          8192
+
+/* Pipe A Source Image size (minus one - equal to active size)
+ * Programmable while pipe is enabled.
+ */
+#define VML_PIPEASRC                 0x0006001C
+#define VML_PIPEASRC_HMASK           0x0FFF0000
+#define VML_PIPEASRC_HSHIFT          16
+#define VML_PIPEASRC_VMASK           0x00000FFF
+#define VML_PIPEASRC_VSHIFT          0
+
+/* Pipe A Border Color Pattern register (10 bit color) */
+#define VML_BCLRPAT_A                0x00060020
+
+/* Pipe A Canvas Color register  (10 bit color) */
+#define VML_CANVSCLR_A               0x00060024
+
+/* Pipe A Configuration register */
+#define VML_PIPEACONF                0x00070008
+#define VML_PIPE_BASE                0x00000000
+#define VML_PIPE_ENABLE              0x80000000
+#define VML_PIPE_FORCE_BORDER        0x02000000
+#define VML_PIPE_PLANES_OFF          0x00080000
+#define VML_PIPE_ARGB_OUTPUT_MODE    0x00040000
+
+/* Pipe A FIFO setting */
+#define VML_DSPARB                   0x00070030
+#define VML_FIFO_DEFAULT             0x00001D9C
+
+/* MDVO rcomp status & pads control register */
+#define VML_RCOMPSTAT                0x00070048
+#define VML_MDVO_VDC_I_RCOMP         0x80000000
+#define VML_MDVO_POWERSAVE_OFF       0x00000008
+#define VML_MDVO_PAD_ENABLE          0x00000004
+#define VML_MDVO_PULLDOWN_ENABLE     0x00000001
+
+struct vml_par {
+	struct pci_dev *vdc;
+	u64 vdc_mem_base;
+	u64 vdc_mem_size;
+	char __iomem *vdc_mem;
+
+	struct pci_dev *gpu;
+	u64 gpu_mem_base;
+	u64 gpu_mem_size;
+	char __iomem *gpu_mem;
+
+	atomic_t refcount;
+};
+
+struct vram_area {
+	unsigned long logical;
+	unsigned long phys;
+	unsigned long size;
+	unsigned order;
+};
+
+struct vml_info {
+	struct fb_info info;
+	struct vml_par *par;
+	struct list_head head;
+	struct vram_area vram[VML_VRAM_AREAS];
+	u64 vram_start;
+	u64 vram_contig_size;
+	u32 num_areas;
+	void __iomem *vram_logical;
+	u32 pseudo_palette[16];
+	u32 stride;
+	u32 bytes_per_pixel;
+	atomic_t vmas;
+	int cur_blank_mode;
+	int pipe_disabled;
+};
+
+/*
+ * Subsystem
+ */
+
+struct vml_sys {
+	char *name;
+
+	/*
+	 * Save / Restore;
+	 */
+
+	int (*save) (struct vml_sys * sys);
+	int (*restore) (struct vml_sys * sys);
+
+	/*
+	 * PLL programming;
+	 */
+
+	int (*set_clock) (struct vml_sys * sys, int clock);
+	int (*nearest_clock) (const struct vml_sys * sys, int clock);
+};
+
+extern int vmlfb_register_subsys(struct vml_sys *sys);
+extern void vmlfb_unregister_subsys(struct vml_sys *sys);
+
+#define VML_READ32(_par, _offset) \
+	(ioread32((_par)->vdc_mem + (_offset)))
+#define VML_WRITE32(_par, _offset, _value)				\
+	iowrite32(_value, (_par)->vdc_mem + (_offset))
+
+#endif
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index a9b99b0..64ee78c 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -84,13 +84,15 @@ static int vfb_mmap(struct fb_info *info
 		    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
+	.fb_read        = fb_sys_read,
+	.fb_write       = fb_sys_write,
 	.fb_check_var	= vfb_check_var,
 	.fb_set_par	= vfb_set_par,
 	.fb_setcolreg	= vfb_setcolreg,
 	.fb_pan_display	= vfb_pan_display,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+	.fb_imageblit	= sys_imageblit,
 	.fb_mmap	= vfb_mmap,
 };
 
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index ec4c7dc..2a14d28 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1378,6 +1378,8 @@ static int __init vga16fb_probe(struct p
 	info->fbops = &vga16fb_ops;
 	info->var = vga16fb_defined;
 	info->fix = vga16fb_fix;
+	/* supports rectangles with widths of multiples of 8 */
+	info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
 	info->flags = FBINFO_FLAG_DEFAULT |
 		FBINFO_HWACCEL_YPAN;
 
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index d94efaf..b91c466 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -50,23 +50,28 @@ static void save_vga_text(struct vgastat
 	struct regstate *saved = (struct regstate *) state->vidstate;
 	int i;
 	u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4;
+	unsigned short iobase;
 
 	/* if in graphics mode, no need to save */
+	misc = vga_r(state->vgabase, VGA_MIS_R);
+	iobase = (misc & 1) ? 0x3d0 : 0x3b0;
+
+	vga_r(state->vgabase, iobase + 0xa);
+	vga_w(state->vgabase, VGA_ATT_W, 0x00);
 	attr10 = vga_rattr(state->vgabase, 0x10);
+	vga_r(state->vgabase, iobase + 0xa);
+	vga_w(state->vgabase, VGA_ATT_W, 0x20);
+
 	if (attr10 & 1)
 		return;
-	
+
 	/* save regs */
-	misc = vga_r(state->vgabase, VGA_MIS_R);
 	gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
 	gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
 	gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
 	seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
 	seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
 	
-	/* force graphics mode */
-	vga_w(state->vgabase, VGA_MIS_W, misc | 1);
-
 	/* blank screen */
 	seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -115,15 +120,12 @@ static void save_vga_text(struct vgastat
 	}
 
 	/* restore regs */
-	vga_wattr(state->vgabase, 0x10, attr10);
-
 	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
 	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
 
 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
 	vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
 	vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
-	vga_w(state->vgabase, VGA_MIS_W, misc);
 
 	/* unblank screen */
 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -137,11 +139,10 @@ static void restore_vga_text(struct vgas
 {
 	struct regstate *saved = (struct regstate *) state->vidstate;
 	int i;
-	u8 misc, gr1, gr3, gr4, gr5, gr6, gr8; 
+	u8 gr1, gr3, gr4, gr5, gr6, gr8;
 	u8 seq1, seq2, seq4;
 
 	/* save regs */
-	misc = vga_r(state->vgabase, VGA_MIS_R);
 	gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE);
 	gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE);
 	gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
@@ -151,9 +152,6 @@ static void restore_vga_text(struct vgas
 	seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
 	seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
 	
-	/* force graphics mode */
-	vga_w(state->vgabase, VGA_MIS_W, misc | 1);
-
 	/* blank screen */
 	seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -213,8 +211,6 @@ static void restore_vga_text(struct vgas
 	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
 
 	/* restore regs */
-	vga_w(state->vgabase, VGA_MIS_W, misc);
-
 	vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1);
 	vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3);
 	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
new file mode 100644
index 0000000..1d29a89
--- /dev/null
+++ b/drivers/video/xilinxfb.c
@@ -0,0 +1,381 @@
+/*
+ * xilinxfb.c
+ *
+ * Xilinx TFT LCD frame buffer driver
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *
+ * 2002-2007 (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.
+ */
+
+/*
+ * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
+ * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
+ * was based on skeletonfb.c, Skeleton for a frame buffer device by
+ * Geert Uytterhoeven.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <syslib/virtex_devices.h>
+
+#define DRIVER_NAME		"xilinxfb"
+#define DRIVER_DESCRIPTION	"Xilinx TFT LCD frame buffer driver"
+
+/*
+ * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
+ * the VGA port on the Xilinx ML40x board. This is a hardware display controller
+ * for a 640x480 resolution TFT or VGA screen.
+ *
+ * The interface to the framebuffer is nice and simple.  There are two
+ * control registers.  The first tells the LCD interface where in memory
+ * the frame buffer is (only the 11 most significant bits are used, so
+ * don't start thinking about scrolling).  The second allows the LCD to
+ * be turned on or off as well as rotated 180 degrees.
+ */
+#define NUM_REGS	2
+#define REG_FB_ADDR	0
+#define REG_CTRL	1
+#define REG_CTRL_ENABLE	 0x0001
+#define REG_CTRL_ROTATE	 0x0002
+
+/*
+ * The hardware only handles a single mode: 640x480 24 bit true
+ * color. Each pixel gets a word (32 bits) of memory.  Within each word,
+ * the 8 most significant bits are ignored, the next 8 bits are the red
+ * level, the next 8 bits are the green level and the 8 least
+ * significant bits are the blue level.  Each row of the LCD uses 1024
+ * words, but only the first 640 pixels are displayed with the other 384
+ * words being ignored.  There are 480 rows.
+ */
+#define BYTES_PER_PIXEL	4
+#define BITS_PER_PIXEL	(BYTES_PER_PIXEL * 8)
+#define XRES		640
+#define YRES		480
+#define XRES_VIRTUAL	1024
+#define YRES_VIRTUAL	YRES
+#define LINE_LENGTH	(XRES_VIRTUAL * BYTES_PER_PIXEL)
+#define FB_SIZE		(YRES_VIRTUAL * LINE_LENGTH)
+
+#define RED_SHIFT	16
+#define GREEN_SHIFT	8
+#define BLUE_SHIFT	0
+
+#define PALETTE_ENTRIES_NO	16	/* passed to fb_alloc_cmap() */
+
+/*
+ * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
+ */
+static struct fb_fix_screeninfo xilinx_fb_fix __initdata = {
+	.id =		"Xilinx",
+	.type =		FB_TYPE_PACKED_PIXELS,
+	.visual =	FB_VISUAL_TRUECOLOR,
+	.smem_len =	FB_SIZE,
+	.line_length =	LINE_LENGTH,
+	.accel =	FB_ACCEL_NONE
+};
+
+static struct fb_var_screeninfo xilinx_fb_var __initdata = {
+	.xres =			XRES,
+	.yres =			YRES,
+	.xres_virtual =		XRES_VIRTUAL,
+	.yres_virtual =		YRES_VIRTUAL,
+
+	.bits_per_pixel =	BITS_PER_PIXEL,
+
+	.red =		{ RED_SHIFT, 8, 0 },
+	.green =	{ GREEN_SHIFT, 8, 0 },
+	.blue =		{ BLUE_SHIFT, 8, 0 },
+	.transp =	{ 0, 0, 0 },
+
+	.activate =	FB_ACTIVATE_NOW
+};
+
+struct xilinxfb_drvdata {
+
+	struct fb_info	info;		/* FB driver info record */
+
+	u32		regs_phys;	/* phys. address of the control registers */
+	u32 __iomem	*regs;		/* virt. address of the control registers */
+
+	unsigned char __iomem	*fb_virt;	/* virt. address of the frame buffer */
+	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */
+
+	u32		reg_ctrl_default;
+
+	u32		pseudo_palette[PALETTE_ENTRIES_NO];
+					/* Fake palette of 16 colors */
+};
+
+#define to_xilinxfb_drvdata(_info) \
+	container_of(_info, struct xilinxfb_drvdata, info)
+
+/*
+ * The LCD controller has DCR interface to its registers, but all
+ * the boards and configurations the driver has been tested with
+ * use opb2dcr bridge. So the registers are seen as memory mapped.
+ * This macro is to make it simple to add the direct DCR access
+ * when it's needed.
+ */
+#define xilinx_fb_out_be32(driverdata, offset, val) \
+	out_be32(driverdata->regs + offset, val)
+
+static int
+xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+	unsigned transp, struct fb_info *fbi)
+{
+	u32 *palette = fbi->pseudo_palette;
+
+	if (regno >= PALETTE_ENTRIES_NO)
+		return -EINVAL;
+
+	if (fbi->var.grayscale) {
+		/* Convert color to grayscale.
+		 * grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+			(red * 77 + green * 151 + blue * 28 + 127) >> 8;
+	}
+
+	/* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
+
+	/* We only handle 8 bits of each color. */
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+	palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
+			 (blue << BLUE_SHIFT);
+
+	return 0;
+}
+
+static int
+xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		/* turn on panel */
+		xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+		break;
+
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		/* turn off panel */
+		xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+	default:
+		break;
+
+	}
+	return 0; /* success */
+}
+
+static struct fb_ops xilinxfb_ops =
+{
+	.owner			= THIS_MODULE,
+	.fb_setcolreg		= xilinx_fb_setcolreg,
+	.fb_blank		= xilinx_fb_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+};
+
+/* === The device driver === */
+
+static int
+xilinxfb_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev;
+	struct xilinxfb_platform_data *pdata;
+	struct xilinxfb_drvdata *drvdata;
+	struct resource *regs_res;
+	int retval;
+
+	if (!dev)
+		return -EINVAL;
+
+	pdev = to_platform_device(dev);
+	pdata = pdev->dev.platform_data;
+
+	if (pdata == NULL) {
+		printk(KERN_ERR "Couldn't find platform data.\n");
+		return -EFAULT;
+	}
+
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata) {
+		printk(KERN_ERR "Couldn't allocate device private record\n");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(dev, drvdata);
+
+	/* Map the control registers in */
+	regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
+		printk(KERN_ERR "Couldn't get registers resource\n");
+		retval = -EFAULT;
+		goto failed1;
+	}
+
+	if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
+		printk(KERN_ERR
+		       "Couldn't lock memory region at 0x%08X\n",
+		       regs_res->start);
+		retval = -EBUSY;
+		goto failed1;
+	}
+	drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
+	drvdata->regs_phys = regs_res->start;
+
+	/* Allocate the framebuffer memory */
+	drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
+				&drvdata->fb_phys, GFP_KERNEL);
+	if (!drvdata->fb_virt) {
+		printk(KERN_ERR "Could not allocate frame buffer memory\n");
+		retval = -ENOMEM;
+		goto failed2;
+	}
+
+	/* Clear (turn to black) the framebuffer */
+	memset_io((void *) drvdata->fb_virt, 0, FB_SIZE);
+
+	/* Tell the hardware where the frame buffer is */
+	xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
+
+	/* Turn on the display */
+	if (pdata->rotate_screen) {
+		drvdata->reg_ctrl_default = REG_CTRL_ENABLE | REG_CTRL_ROTATE;
+	} else {
+		drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
+	}
+	xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+
+	/* Fill struct fb_info */
+	drvdata->info.device = dev;
+	drvdata->info.screen_base = drvdata->fb_virt;
+	drvdata->info.fbops = &xilinxfb_ops;
+	drvdata->info.fix = xilinx_fb_fix;
+	drvdata->info.fix.smem_start = drvdata->fb_phys;
+	drvdata->info.pseudo_palette = drvdata->pseudo_palette;
+
+	if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
+		printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
+			PALETTE_ENTRIES_NO);
+		retval = -EFAULT;
+		goto failed3;
+	}
+
+	drvdata->info.flags = FBINFO_DEFAULT;
+	xilinx_fb_var.height = pdata->screen_height_mm;
+	xilinx_fb_var.width = pdata->screen_width_mm;
+	drvdata->info.var = xilinx_fb_var;
+
+	/* Register new frame buffer */
+	if (register_framebuffer(&drvdata->info) < 0) {
+		printk(KERN_ERR "Could not register frame buffer\n");
+		retval = -EINVAL;
+		goto failed4;
+	}
+
+	return 0;	/* success */
+
+failed4:
+	fb_dealloc_cmap(&drvdata->info.cmap);
+
+failed3:
+	dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
+		drvdata->fb_phys);
+
+	/* Turn off the display */
+	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+	iounmap(drvdata->regs);
+
+failed2:
+	release_mem_region(regs_res->start, 8);
+
+failed1:
+	kfree(drvdata);
+	dev_set_drvdata(dev, NULL);
+
+	return retval;
+}
+
+static int
+xilinxfb_drv_remove(struct device *dev)
+{
+	struct xilinxfb_drvdata *drvdata;
+
+	if (!dev)
+		return -ENODEV;
+
+	drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+	xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
+#endif
+
+	unregister_framebuffer(&drvdata->info);
+
+	fb_dealloc_cmap(&drvdata->info.cmap);
+
+	dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
+		drvdata->fb_phys);
+
+	/* Turn off the display */
+	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+	iounmap(drvdata->regs);
+
+	release_mem_region(drvdata->regs_phys, 8);
+
+	kfree(drvdata);
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+
+static struct device_driver xilinxfb_driver = {
+	.name		= DRIVER_NAME,
+	.bus		= &platform_bus_type,
+
+	.probe		= xilinxfb_drv_probe,
+	.remove		= xilinxfb_drv_remove
+};
+
+static int __init
+xilinxfb_init(void)
+{
+	/*
+	 * No kernel boot options used,
+	 * so we just need to register the driver
+	 */
+	return driver_register(&xilinxfb_driver);
+}
+
+static void __exit
+xilinxfb_cleanup(void)
+{
+	driver_unregister(&xilinxfb_driver);
+}
+
+module_init(xilinxfb_init);
+module_exit(xilinxfb_cleanup);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 2fb4255..8f77933 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -35,5 +35,13 @@ config W1_MASTER_DS2482
 	  This driver can also be built as a module.  If so, the module
 	  will be called ds2482.
 
+config W1_MASTER_DS1WM
+	tristate "Maxim DS1WM 1-wire busmaster"
+	depends on W1 && ARM
+	help
+	  Say Y here to enable the DS1WM 1-wire driver, such as that
+	  in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
+	  hx4700.
+
 endmenu
 
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 4cee256..11551b3 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -5,4 +5,4 @@ #
 obj-$(CONFIG_W1_MASTER_MATROX)		+= matrox_w1.o
 obj-$(CONFIG_W1_MASTER_DS2490)		+= ds2490.o
 obj-$(CONFIG_W1_MASTER_DS2482)		+= ds2482.o
-
+obj-$(CONFIG_W1_MASTER_DS1WM)		+= ds1wm.o
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
new file mode 100644
index 0000000..763bc73
--- /dev/null
+++ b/drivers/w1/masters/ds1wm.c
@@ -0,0 +1,468 @@
+/*
+ * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs
+ * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3
+ * like hx4700).
+ *
+ * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
+ * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/ds1wm.h>
+
+#include <asm/io.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+
+#define DS1WM_CMD	0x00	/* R/W 4 bits command */
+#define DS1WM_DATA	0x01	/* R/W 8 bits, transmit/receive buffer */
+#define DS1WM_INT	0x02	/* R/W interrupt status */
+#define DS1WM_INT_EN	0x03	/* R/W interrupt enable */
+#define DS1WM_CLKDIV	0x04	/* R/W 5 bits of divisor and pre-scale */
+
+#define DS1WM_CMD_1W_RESET  (1 << 0)	/* force reset on 1-wire bus */
+#define DS1WM_CMD_SRA	    (1 << 1)	/* enable Search ROM accelerator mode */
+#define DS1WM_CMD_DQ_OUTPUT (1 << 2)	/* write only - forces bus low */
+#define DS1WM_CMD_DQ_INPUT  (1 << 3)	/* read only - reflects state of bus */
+#define DS1WM_CMD_RST	    (1 << 5)	/* software reset */
+#define DS1WM_CMD_OD	    (1 << 7)	/* overdrive */
+
+#define DS1WM_INT_PD	    (1 << 0)	/* presence detect */
+#define DS1WM_INT_PDR	    (1 << 1)	/* presence detect result */
+#define DS1WM_INT_TBE	    (1 << 2)	/* tx buffer empty */
+#define DS1WM_INT_TSRE	    (1 << 3)	/* tx shift register empty */
+#define DS1WM_INT_RBF	    (1 << 4)	/* rx buffer full */
+#define DS1WM_INT_RSRF	    (1 << 5)	/* rx shift register full */
+
+#define DS1WM_INTEN_EPD	    (1 << 0)	/* enable presence detect int */
+#define DS1WM_INTEN_IAS	    (1 << 1)	/* INTR active state */
+#define DS1WM_INTEN_ETBE    (1 << 2)	/* enable tx buffer empty int */
+#define DS1WM_INTEN_ETMT    (1 << 3)	/* enable tx shift register empty int */
+#define DS1WM_INTEN_ERBF    (1 << 4)	/* enable rx buffer full int */
+#define DS1WM_INTEN_ERSRF   (1 << 5)	/* enable rx shift register full int */
+#define DS1WM_INTEN_DQO	    (1 << 6)	/* enable direct bus driving ops */
+
+
+#define DS1WM_TIMEOUT (HZ * 5)
+
+static struct {
+	unsigned long freq;
+	unsigned long divisor;
+} freq[] = {
+	{ 4000000, 0x8 },
+	{ 5000000, 0x2 },
+	{ 6000000, 0x5 },
+	{ 7000000, 0x3 },
+	{ 8000000, 0xc },
+	{ 10000000, 0x6 },
+	{ 12000000, 0x9 },
+	{ 14000000, 0x7 },
+	{ 16000000, 0x10 },
+	{ 20000000, 0xa },
+	{ 24000000, 0xd },
+	{ 28000000, 0xb },
+	{ 32000000, 0x14 },
+	{ 40000000, 0xe },
+	{ 48000000, 0x11 },
+	{ 56000000, 0xf },
+	{ 64000000, 0x18 },
+	{ 80000000, 0x12 },
+	{ 96000000, 0x15 },
+	{ 112000000, 0x13 },
+	{ 128000000, 0x1c },
+};
+
+struct ds1wm_data {
+	void		*map;
+	int		bus_shift; /* # of shifts to calc register offsets */
+	struct platform_device *pdev;
+	struct ds1wm_platform_data *pdata;
+	int		irq;
+	int		active_high;
+	struct clk	*clk;
+	int		slave_present;
+	void		*reset_complete;
+	void		*read_complete;
+	void		*write_complete;
+	u8		read_byte; /* last byte received */
+};
+
+static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg,
+					u8 val)
+{
+        __raw_writeb(val, ds1wm_data->map + (reg << ds1wm_data->bus_shift));
+}
+
+static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg)
+{
+        return __raw_readb(ds1wm_data->map + (reg << ds1wm_data->bus_shift));
+}
+
+
+static irqreturn_t ds1wm_isr(int isr, void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+	u8 intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
+
+	ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+
+	if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete)
+		complete(ds1wm_data->reset_complete);
+
+	if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete)
+		complete(ds1wm_data->write_complete);
+
+	if (intr & DS1WM_INT_RBF) {
+		ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data,
+							    DS1WM_DATA);
+		if (ds1wm_data->read_complete)
+			complete(ds1wm_data->read_complete);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
+{
+	unsigned long timeleft;
+	DECLARE_COMPLETION_ONSTACK(reset_done);
+
+	ds1wm_data->reset_complete = &reset_done;
+
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD |
+		(ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+
+	ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET);
+
+	timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT);
+	ds1wm_data->reset_complete = NULL;
+	if (!timeleft) {
+                dev_dbg(&ds1wm_data->pdev->dev, "reset failed\n");
+                return 1;
+	}
+
+	/* Wait for the end of the reset. According to the specs, the time
+	 * from when the interrupt is asserted to the end of the reset is:
+	 *     tRSTH  - tPDH  - tPDL - tPDI
+	 *     625 us - 60 us - 240 us - 100 ns = 324.9 us
+	 *
+	 * We'll wait a bit longer just to be sure.
+	 */
+	udelay(500);
+
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+		DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
+		(ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+
+	if (!ds1wm_data->slave_present) {
+                dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n");
+                return 1;
+        }
+
+        return 0;
+}
+
+static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data)
+{
+	DECLARE_COMPLETION_ONSTACK(write_done);
+	ds1wm_data->write_complete = &write_done;
+
+	ds1wm_write_register(ds1wm_data, DS1WM_DATA, data);
+
+	wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+	ds1wm_data->write_complete = NULL;
+
+	return 0;
+}
+
+static int ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
+{
+	DECLARE_COMPLETION_ONSTACK(read_done);
+	ds1wm_data->read_complete = &read_done;
+
+	ds1wm_write(ds1wm_data, write_data);
+	wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
+	ds1wm_data->read_complete = NULL;
+
+	return ds1wm_data->read_byte;
+}
+
+static int ds1wm_find_divisor(int gclk)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(freq); i++)
+		if (gclk <= freq[i].freq)
+			return freq[i].divisor;
+
+	return 0;
+}
+
+static void ds1wm_up(struct ds1wm_data *ds1wm_data)
+{
+	int gclk, divisor;
+
+	if (ds1wm_data->pdata->enable)
+		ds1wm_data->pdata->enable(ds1wm_data->pdev);
+
+	gclk = clk_get_rate(ds1wm_data->clk);
+	clk_enable(ds1wm_data->clk);
+	divisor = ds1wm_find_divisor(gclk);
+	if (divisor == 0) {
+		dev_err(&ds1wm_data->pdev->dev,
+			"no suitable divisor for %dHz clock\n", gclk);
+		return;
+	}
+	ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor);
+
+	/* Let the w1 clock stabilize. */
+	msleep(1);
+
+	ds1wm_reset(ds1wm_data);
+}
+
+static void ds1wm_down(struct ds1wm_data *ds1wm_data)
+{
+	ds1wm_reset(ds1wm_data);
+
+	/* Disable interrupts. */
+	ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+			     ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0);
+
+	if (ds1wm_data->pdata->disable)
+		ds1wm_data->pdata->disable(ds1wm_data->pdev);
+
+	clk_disable(ds1wm_data->clk);
+}
+
+/* --------------------------------------------------------------------- */
+/* w1 methods */
+
+static u8 ds1wm_read_byte(void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	return ds1wm_read(ds1wm_data, 0xff);
+}
+
+static void ds1wm_write_byte(void *data, u8 byte)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	ds1wm_write(ds1wm_data, byte);
+}
+
+static u8 ds1wm_reset_bus(void *data)
+{
+	struct ds1wm_data *ds1wm_data = data;
+
+	ds1wm_reset(ds1wm_data);
+
+	return 0;
+}
+
+static void ds1wm_search(void *data, u8 search_type,
+			 w1_slave_found_callback slave_found)
+{
+	struct ds1wm_data *ds1wm_data = data;
+	int i;
+	unsigned long long rom_id;
+
+	/* XXX We need to iterate for multiple devices per the DS1WM docs.
+	 * See http://www.maxim-ic.com/appnotes.cfm/appnote_number/120. */
+	if (ds1wm_reset(ds1wm_data))
+		return;
+
+	ds1wm_write(ds1wm_data, search_type);
+	ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
+
+	for (rom_id = 0, i = 0; i < 16; i++) {
+
+		unsigned char resp, r, d;
+
+		resp = ds1wm_read(ds1wm_data, 0x00);
+
+		r = ((resp & 0x02) >> 1) |
+		    ((resp & 0x08) >> 2) |
+		    ((resp & 0x20) >> 3) |
+		    ((resp & 0x80) >> 4);
+
+		d = ((resp & 0x01) >> 0) |
+		    ((resp & 0x04) >> 1) |
+		    ((resp & 0x10) >> 2) |
+		    ((resp & 0x40) >> 3);
+
+		rom_id |= (unsigned long long) r << (i * 4);
+
+	}
+	dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX", rom_id);
+
+	ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
+	ds1wm_reset(ds1wm_data);
+
+	slave_found(ds1wm_data, rom_id);
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct w1_bus_master ds1wm_master = {
+	.read_byte  = ds1wm_read_byte,
+	.write_byte = ds1wm_write_byte,
+	.reset_bus  = ds1wm_reset_bus,
+	.search	    = ds1wm_search,
+};
+
+static int ds1wm_probe(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data;
+	struct ds1wm_platform_data *plat;
+	struct resource *res;
+	int ret;
+
+	if (!pdev)
+		return -ENODEV;
+
+	ds1wm_data = kzalloc(sizeof (*ds1wm_data), GFP_KERNEL);
+	if (!ds1wm_data)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, ds1wm_data);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENXIO;
+		goto err0;
+	}
+	ds1wm_data->map = ioremap(res->start, res->end - res->start + 1);
+	if (!ds1wm_data->map) {
+		ret = -ENOMEM;
+		goto err0;
+	}
+	plat = pdev->dev.platform_data;
+	ds1wm_data->bus_shift = plat->bus_shift;
+	ds1wm_data->pdev = pdev;
+	ds1wm_data->pdata = plat;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		ret = -ENXIO;
+		goto err1;
+	}
+	ds1wm_data->irq = res->start;
+	ds1wm_data->active_high = (res->flags & IORESOURCE_IRQ_HIGHEDGE) ?
+		1 : 0;
+
+	set_irq_type(ds1wm_data->irq, ds1wm_data->active_high ?
+			IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING);
+
+	ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED,
+			  "ds1wm", ds1wm_data);
+	if (ret)
+		goto err1;
+
+	ds1wm_data->clk = clk_get(&pdev->dev, "ds1wm");
+	if (!ds1wm_data->clk) {
+		ret = -ENOENT;
+		goto err2;
+	}
+
+	ds1wm_up(ds1wm_data);
+
+	ds1wm_master.data = (void *)ds1wm_data;
+
+	ret = w1_add_master_device(&ds1wm_master);
+	if (ret)
+		goto err3;
+
+	return 0;
+
+err3:
+	ds1wm_down(ds1wm_data);
+	clk_put(ds1wm_data->clk);
+err2:
+	free_irq(ds1wm_data->irq, ds1wm_data);
+err1:
+	iounmap(ds1wm_data->map);
+err0:
+	kfree(ds1wm_data);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int ds1wm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	ds1wm_down(ds1wm_data);
+
+	return 0;
+}
+
+static int ds1wm_resume(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	ds1wm_up(ds1wm_data);
+
+	return 0;
+}
+#else
+#define ds1wm_suspend NULL
+#define ds1wm_resume NULL
+#endif
+
+static int ds1wm_remove(struct platform_device *pdev)
+{
+	struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+	w1_remove_master_device(&ds1wm_master);
+	ds1wm_down(ds1wm_data);
+	clk_put(ds1wm_data->clk);
+	free_irq(ds1wm_data->irq, ds1wm_data);
+	iounmap(ds1wm_data->map);
+	kfree(ds1wm_data);
+
+	return 0;
+}
+
+static struct platform_driver ds1wm_driver = {
+	.driver   = {
+		.name = "ds1wm",
+	},
+	.probe    = ds1wm_probe,
+	.remove   = ds1wm_remove,
+	.suspend  = ds1wm_suspend,
+	.resume   = ds1wm_resume
+};
+
+static int __init ds1wm_init(void)
+{
+	printk("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n");
+	return platform_driver_register(&ds1wm_driver);
+}
+
+static void __exit ds1wm_exit(void)
+{
+	platform_driver_unregister(&ds1wm_driver);
+}
+
+module_init(ds1wm_init);
+module_exit(ds1wm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
+	      "Matt Reimer <mreimer@vpop.net>");
+MODULE_DESCRIPTION("DS1WM w1 busmaster driver");
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 63c0724..7d6876d 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -459,7 +459,7 @@ static int __w1_attach_slave_device(stru
 		 (unsigned long long) sl->reg_num.id);
 
 	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
-		&sl->dev.bus_id[0]);
+		&sl->dev.bus_id[0], sl);
 
 	err = device_register(&sl->dev);
 	if (err < 0) {
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 357a2e0..258defd 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -100,7 +100,8 @@ int w1_add_master_device(struct w1_bus_m
 
         /* validate minimum functionality */
         if (!(master->touch_bit && master->reset_bus) &&
-            !(master->write_bit && master->read_bit)) {
+            !(master->write_bit && master->read_bit) &&
+	    !(master->write_byte && master->read_byte && master->reset_bus)) {
 		printk(KERN_ERR "w1_add_master_device: invalid function set\n");
 		return(-EINVAL);
         }
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index b3ce885..2ce4ceb 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -90,8 +90,9 @@ get_zorro_dev_info(char *buf, char **sta
 	for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
 		struct zorro_dev *z = &zorro_autocon[slot];
 		len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot,
-			      z->id, zorro_resource_start(z),
-			      zorro_resource_len(z), z->rom.er_Type);
+			      z->id, (unsigned long)zorro_resource_start(z),
+			      (unsigned long)zorro_resource_len(z),
+			      z->rom.er_Type);
 		at += len;
 		if (at >= pos) {
 			if (!*start) {
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 87c29d7..c3ba0ec 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -42,7 +42,8 @@ static ssize_t zorro_show_resource(struc
 	struct zorro_dev *z = to_zorro_dev(dev);
 
 	return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
-		       zorro_resource_start(z), zorro_resource_end(z),
+		       (unsigned long)zorro_resource_start(z),
+		       (unsigned long)zorro_resource_end(z),
 		       zorro_resource_flags(z));
 }
 
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index 0f2b406..4cc42b6 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -164,7 +164,8 @@ static int __init zorro_init(void)
 	if (request_resource(zorro_find_parent_resource(z), &z->resource))
 	    printk(KERN_ERR "Zorro: Address space collision on device %s "
 		   "[%lx:%lx]\n",
-		   z->name, zorro_resource_start(z), zorro_resource_end(z));
+		   z->name, (unsigned long)zorro_resource_start(z),
+		   (unsigned long)zorro_resource_end(z));
 	sprintf(z->dev.bus_id, "%02x", i);
 	z->dev.parent = &zorro_bus.dev;
 	z->dev.bus = &zorro_bus_type;
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index bed48fa..3128aa9 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -29,7 +29,6 @@ #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/pagemap.h>
 #include <linux/idr.h>
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index ddffd8a..775e26e 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -30,7 +30,6 @@ #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/namei.h>
 #include <linux/idr.h>
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 3129688..1dd86ee 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -29,7 +29,6 @@ #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/inet.h>
 #include <linux/idr.h>
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index c7b6772..6e7678e 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -30,7 +30,6 @@ #include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index b01b0a4..7624821 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -30,7 +30,6 @@ #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/namei.h>
 #include <linux/idr.h>
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 0ec42f6..8eb9263 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -31,7 +31,6 @@ #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/stat.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
diff --git a/fs/Kconfig b/fs/Kconfig
index 3c4886b..4622dab 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -314,7 +314,7 @@ config REISERFS_CHECK
 
 config REISERFS_PROC_INFO
 	bool "Stats in /proc/fs/reiserfs"
-	depends on REISERFS_FS
+	depends on REISERFS_FS && PROC_FS
 	help
 	  Create under /proc/fs/reiserfs a hierarchy of files, displaying
 	  various ReiserFS statistics and internal data at the expense of
@@ -1734,6 +1734,18 @@ config SUNRPC
 config SUNRPC_GSS
 	tristate
 
+config SUNRPC_BIND34
+	bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
+	depends on SUNRPC && EXPERIMENTAL
+	help
+	  Provides kernel support for querying rpcbind servers via versions 3
+	  and 4 of the rpcbind protocol.  The kernel automatically falls back
+	  to version 2 if a remote rpcbind service does not support versions
+	  3 or 4.
+
+	  If unsure, say N to get traditional behavior (version 2 rpcbind
+	  requests only).
+
 config RPCSEC_GSS_KRB5
 	tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
 	depends on SUNRPC && EXPERIMENTAL
@@ -2019,7 +2031,7 @@ config CODA_FS_OLD_API
 config AFS_FS
 	tristate "Andrew File System support (AFS) (EXPERIMENTAL)"
 	depends on INET && EXPERIMENTAL
-	select RXRPC
+	select AF_RXRPC
 	help
 	  If you say Y here, you will get an experimental Andrew File System
 	  driver. It currently only supports unsecured read-only AFS access.
@@ -2028,8 +2040,15 @@ config AFS_FS
 
 	  If unsure, say N.
 
-config RXRPC
-	tristate
+config AFS_DEBUG
+	bool "AFS dynamic debugging"
+	depends on AFS_FS
+	help
+	  Say Y here to make runtime controllable debugging messages appear.
+
+	  See <file:Documentation/filesystems/afs.txt> for more information.
+
+	  If unsure, say N.
 
 config 9P_FS
 	tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index f3d3d81..74c6440 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -26,7 +26,7 @@ config BINFMT_ELF
 config BINFMT_ELF_FDPIC
 	bool "Kernel support for FDPIC ELF binaries"
 	default y
-	depends on FRV
+	depends on (FRV || BLACKFIN)
 	help
 	  ELF FDPIC binaries are based on ELF, but allow the individual load
 	  segments of a binary to be located in memory independently of each
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 2e5f2c8..30c2965 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -232,8 +232,7 @@ static void init_once(void * foo, struct
 {
 	struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/affs/super.c b/fs/affs/super.c
index c3986a1..beff7d2 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -87,8 +87,7 @@ static void init_once(void * foo, struct
 {
 	struct affs_inode_info *ei = (struct affs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		init_MUTEX(&ei->i_link_lock);
 		init_MUTEX(&ei->i_ext_lock);
 		inode_init_once(&ei->vfs_inode);
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 4029c9d..cf83e5d 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -2,8 +2,6 @@ #
 # Makefile for Red Hat Linux AFS client.
 #
 
-#CFLAGS += -finstrument-functions
-
 kafs-objs := \
 	callback.o \
 	cell.o \
@@ -12,14 +10,15 @@ kafs-objs := \
 	file.o \
 	fsclient.o \
 	inode.o \
-	kafsasyncd.o \
-	kafstimod.o \
 	main.o \
 	misc.o \
 	mntpt.o \
 	proc.o \
+	rxrpc.o \
+	security.o \
 	server.o \
 	super.o \
+	netdevices.o \
 	vlclient.o \
 	vlocation.o \
 	vnode.o \
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
new file mode 100644
index 0000000..52d0752
--- /dev/null
+++ b/fs/afs/afs.h
@@ -0,0 +1,146 @@
+/* AFS common types
+ *
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_H
+#define AFS_H
+
+#include <linux/in.h>
+
+#define AFS_MAXCELLNAME	64		/* maximum length of a cell name */
+#define AFS_MAXVOLNAME	64		/* maximum length of a volume name */
+
+typedef unsigned			afs_volid_t;
+typedef unsigned			afs_vnodeid_t;
+typedef unsigned long long		afs_dataversion_t;
+
+typedef enum {
+	AFSVL_RWVOL,			/* read/write volume */
+	AFSVL_ROVOL,			/* read-only volume */
+	AFSVL_BACKVOL,			/* backup volume */
+} __attribute__((packed)) afs_voltype_t;
+
+typedef enum {
+	AFS_FTYPE_INVALID	= 0,
+	AFS_FTYPE_FILE		= 1,
+	AFS_FTYPE_DIR		= 2,
+	AFS_FTYPE_SYMLINK	= 3,
+} afs_file_type_t;
+
+/*
+ * AFS file identifier
+ */
+struct afs_fid {
+	afs_volid_t	vid;		/* volume ID */
+	afs_vnodeid_t	vnode;		/* file index within volume */
+	unsigned	unique;		/* unique ID number (file index version) */
+};
+
+/*
+ * AFS callback notification
+ */
+typedef enum {
+	AFSCM_CB_UNTYPED	= 0,	/* no type set on CB break */
+	AFSCM_CB_EXCLUSIVE	= 1,	/* CB exclusive to CM [not implemented] */
+	AFSCM_CB_SHARED		= 2,	/* CB shared by other CM's */
+	AFSCM_CB_DROPPED	= 3,	/* CB promise cancelled by file server */
+} afs_callback_type_t;
+
+struct afs_callback {
+	struct afs_fid		fid;		/* file identifier */
+	unsigned		version;	/* callback version */
+	unsigned		expiry;		/* time at which expires */
+	afs_callback_type_t	type;		/* type of callback */
+};
+
+#define AFSCBMAX 50	/* maximum callbacks transferred per bulk op */
+
+/*
+ * AFS volume information
+ */
+struct afs_volume_info {
+	afs_volid_t		vid;		/* volume ID */
+	afs_voltype_t		type;		/* type of this volume */
+	afs_volid_t		type_vids[5];	/* volume ID's for possible types for this vol */
+
+	/* list of fileservers serving this volume */
+	size_t			nservers;	/* number of entries used in servers[] */
+	struct {
+		struct in_addr	addr;		/* fileserver address */
+	} servers[8];
+};
+
+/*
+ * AFS security ACE access mask
+ */
+typedef u32 afs_access_t;
+#define AFS_ACE_READ		0x00000001U	/* - permission to read a file/dir */
+#define AFS_ACE_WRITE		0x00000002U	/* - permission to write/chmod a file */
+#define AFS_ACE_INSERT		0x00000004U	/* - permission to create dirent in a dir */
+#define AFS_ACE_LOOKUP		0x00000008U	/* - permission to lookup a file/dir in a dir */
+#define AFS_ACE_DELETE		0x00000010U	/* - permission to delete a dirent from a dir */
+#define AFS_ACE_LOCK		0x00000020U	/* - permission to lock a file */
+#define AFS_ACE_ADMINISTER	0x00000040U	/* - permission to change ACL */
+#define AFS_ACE_USER_A		0x01000000U	/* - 'A' user-defined permission */
+#define AFS_ACE_USER_B		0x02000000U	/* - 'B' user-defined permission */
+#define AFS_ACE_USER_C		0x04000000U	/* - 'C' user-defined permission */
+#define AFS_ACE_USER_D		0x08000000U	/* - 'D' user-defined permission */
+#define AFS_ACE_USER_E		0x10000000U	/* - 'E' user-defined permission */
+#define AFS_ACE_USER_F		0x20000000U	/* - 'F' user-defined permission */
+#define AFS_ACE_USER_G		0x40000000U	/* - 'G' user-defined permission */
+#define AFS_ACE_USER_H		0x80000000U	/* - 'H' user-defined permission */
+
+/*
+ * AFS file status information
+ */
+struct afs_file_status {
+	unsigned		if_version;	/* interface version */
+#define AFS_FSTATUS_VERSION	1
+
+	afs_file_type_t		type;		/* file type */
+	unsigned		nlink;		/* link count */
+	u64			size;		/* file size */
+	afs_dataversion_t	data_version;	/* current data version */
+	u32			author;		/* author ID */
+	u32			owner;		/* owner ID */
+	u32			group;		/* group ID */
+	afs_access_t		caller_access;	/* access rights for authenticated caller */
+	afs_access_t		anon_access;	/* access rights for unauthenticated caller */
+	umode_t			mode;		/* UNIX mode */
+	struct afs_fid		parent;		/* parent dir ID for non-dirs only */
+	time_t			mtime_client;	/* last time client changed data */
+	time_t			mtime_server;	/* last time server changed data */
+};
+
+/*
+ * AFS file status change request
+ */
+struct afs_store_status {
+	u32			mask;		/* which bits of the struct are set */
+	u32			mtime_client;	/* last time client changed data */
+	u32			owner;		/* owner ID */
+	u32			group;		/* group ID */
+	umode_t			mode;		/* UNIX mode */
+};
+
+#define AFS_SET_MTIME		0x01		/* set the mtime */
+#define AFS_SET_OWNER		0x02		/* set the owner ID */
+#define AFS_SET_GROUP		0x04		/* set the group ID (unsupported?) */
+#define AFS_SET_MODE		0x08		/* set the UNIX mode */
+#define AFS_SET_SEG_SIZE	0x10		/* set the segment size (unsupported) */
+
+/*
+ * AFS volume synchronisation information
+ */
+struct afs_volsync {
+	time_t			creation;	/* volume creation time */
+};
+
+#endif /* AFS_H */
diff --git a/fs/afs/afs_cm.h b/fs/afs/afs_cm.h
new file mode 100644
index 0000000..7b4d4fa
--- /dev/null
+++ b/fs/afs/afs_cm.h
@@ -0,0 +1,32 @@
+/* AFS Cache Manager definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_CM_H
+#define AFS_CM_H
+
+#define AFS_CM_PORT		7001	/* AFS file server port */
+#define CM_SERVICE		1	/* AFS File Service ID */
+
+enum AFS_CM_Operations {
+	CBCallBack		= 204,	/* break callback promises */
+	CBInitCallBackState	= 205,	/* initialise callback state */
+	CBProbe			= 206,	/* probe client */
+	CBGetLock		= 207,	/* get contents of CM lock table */
+	CBGetCE			= 208,	/* get cache file description */
+	CBGetXStatsVersion	= 209,	/* get version of extended statistics */
+	CBGetXStats		= 210,	/* get contents of extended statistics data */
+	CBInitCallBackState3	= 213,	/* initialise callback state, version 3 */
+	CBGetCapabilities	= 65538, /* get client capabilities */
+};
+
+#define AFS_CAP_ERROR_TRANSLATION	0x1
+
+#endif /* AFS_FS_H */
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
new file mode 100644
index 0000000..89e0d16
--- /dev/null
+++ b/fs/afs/afs_fs.h
@@ -0,0 +1,48 @@
+/* AFS File Service definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_FS_H
+#define AFS_FS_H
+
+#define AFS_FS_PORT		7000	/* AFS file server port */
+#define FS_SERVICE		1	/* AFS File Service ID */
+
+enum AFS_FS_Operations {
+	FSFETCHDATA		= 130,	/* AFS Fetch file data */
+	FSFETCHSTATUS		= 132,	/* AFS Fetch file status */
+	FSREMOVEFILE		= 136,	/* AFS Remove a file */
+	FSCREATEFILE		= 137,	/* AFS Create a file */
+	FSRENAME		= 138,	/* AFS Rename or move a file or directory */
+	FSSYMLINK		= 139,	/* AFS Create a symbolic link */
+	FSLINK			= 140,	/* AFS Create a hard link */
+	FSMAKEDIR		= 141,	/* AFS Create a directory */
+	FSREMOVEDIR		= 142,	/* AFS Remove a directory */
+	FSGIVEUPCALLBACKS	= 147,	/* AFS Discard callback promises */
+	FSGETVOLUMEINFO		= 148,	/* AFS Get root volume information */
+	FSGETROOTVOLUME		= 151,	/* AFS Get root volume name */
+	FSLOOKUP		= 161,	/* AFS lookup file in directory */
+};
+
+enum AFS_FS_Errors {
+	VSALVAGE	= 101,	/* volume needs salvaging */
+	VNOVNODE	= 102,	/* no such file/dir (vnode) */
+	VNOVOL		= 103,	/* no such volume or volume unavailable */
+	VVOLEXISTS	= 104,	/* volume name already exists */
+	VNOSERVICE	= 105,	/* volume not currently in service */
+	VOFFLINE	= 106,	/* volume is currently offline (more info available [VVL-spec]) */
+	VONLINE		= 107,	/* volume is already online */
+	VDISKFULL	= 108,	/* disk partition is full */
+	VOVERQUOTA	= 109,	/* volume's maximum quota exceeded */
+	VBUSY		= 110,	/* volume is temporarily unavailable */
+	VMOVED		= 111,	/* volume moved to new server - ask this FS where */
+};
+
+#endif /* AFS_FS_H */
diff --git a/fs/afs/afs_vl.h b/fs/afs/afs_vl.h
new file mode 100644
index 0000000..8bbefe0
--- /dev/null
+++ b/fs/afs/afs_vl.h
@@ -0,0 +1,84 @@
+/* AFS Volume Location Service client interface
+ *
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_VL_H
+#define AFS_VL_H
+
+#include "afs.h"
+
+#define AFS_VL_PORT		7003	/* volume location service port */
+#define VL_SERVICE		52	/* RxRPC service ID for the Volume Location service */
+
+enum AFSVL_Operations {
+	VLGETENTRYBYID		= 503,	/* AFS Get Cache Entry By ID operation ID */
+	VLGETENTRYBYNAME	= 504,	/* AFS Get Cache Entry By Name operation ID */
+	VLPROBE			= 514,	/* AFS Probe Volume Location Service operation ID */
+};
+
+enum AFSVL_Errors {
+	AFSVL_IDEXIST 		= 363520,	/* Volume Id entry exists in vl database */
+	AFSVL_IO 		= 363521,	/* I/O related error */
+	AFSVL_NAMEEXIST 	= 363522,	/* Volume name entry exists in vl database */
+	AFSVL_CREATEFAIL 	= 363523,	/* Internal creation failure */
+	AFSVL_NOENT 		= 363524,	/* No such entry */
+	AFSVL_EMPTY 		= 363525,	/* Vl database is empty */
+	AFSVL_ENTDELETED 	= 363526,	/* Entry is deleted (soft delete) */
+	AFSVL_BADNAME 		= 363527,	/* Volume name is illegal */
+	AFSVL_BADINDEX 		= 363528,	/* Index is out of range */
+	AFSVL_BADVOLTYPE 	= 363529,	/* Bad volume type */
+	AFSVL_BADSERVER 	= 363530,	/* Illegal server number (out of range) */
+	AFSVL_BADPARTITION 	= 363531,	/* Bad partition number */
+	AFSVL_REPSFULL 		= 363532,	/* Run out of space for Replication sites */
+	AFSVL_NOREPSERVER 	= 363533,	/* No such Replication server site exists */
+	AFSVL_DUPREPSERVER 	= 363534,	/* Replication site already exists */
+	AFSVL_RWNOTFOUND 	= 363535,	/* Parent R/W entry not found */
+	AFSVL_BADREFCOUNT 	= 363536,	/* Illegal Reference Count number */
+	AFSVL_SIZEEXCEEDED 	= 363537,	/* Vl size for attributes exceeded */
+	AFSVL_BADENTRY 		= 363538,	/* Bad incoming vl entry */
+	AFSVL_BADVOLIDBUMP 	= 363539,	/* Illegal max volid increment */
+	AFSVL_IDALREADYHASHED 	= 363540,	/* RO/BACK id already hashed */
+	AFSVL_ENTRYLOCKED 	= 363541,	/* Vl entry is already locked */
+	AFSVL_BADVOLOPER 	= 363542,	/* Bad volume operation code */
+	AFSVL_BADRELLOCKTYPE 	= 363543,	/* Bad release lock type */
+	AFSVL_RERELEASE 	= 363544,	/* Status report: last release was aborted */
+	AFSVL_BADSERVERFLAG 	= 363545,	/* Invalid replication site server Â°ag */
+	AFSVL_PERM 		= 363546,	/* No permission access */
+	AFSVL_NOMEM 		= 363547,	/* malloc/realloc failed to alloc enough memory */
+};
+
+/*
+ * maps to "struct vldbentry" in vvl-spec.pdf
+ */
+struct afs_vldbentry {
+	char		name[65];		/* name of volume (with NUL char) */
+	afs_voltype_t	type;			/* volume type */
+	unsigned	num_servers;		/* num servers that hold instances of this vol */
+	unsigned	clone_id;		/* cloning ID */
+
+	unsigned	flags;
+#define AFS_VLF_RWEXISTS	0x1000		/* R/W volume exists */
+#define AFS_VLF_ROEXISTS	0x2000		/* R/O volume exists */
+#define AFS_VLF_BACKEXISTS	0x4000		/* backup volume exists */
+
+	afs_volid_t	volume_ids[3];		/* volume IDs */
+
+	struct {
+		struct in_addr	addr;		/* server address */
+		unsigned	partition;	/* partition ID on this server */
+		unsigned	flags;		/* server specific flags */
+#define AFS_VLSF_NEWREPSITE	0x0001	/* unused */
+#define AFS_VLSF_ROVOL		0x0002	/* this server holds a R/O instance of the volume */
+#define AFS_VLSF_RWVOL		0x0004	/* this server holds a R/W instance of the volume */
+#define AFS_VLSF_BACKVOL	0x0008	/* this server holds a backup instance of the volume */
+	} servers[8];
+};
+
+#endif /* AFS_VL_H */
diff --git a/fs/afs/cache.c b/fs/afs/cache.c
new file mode 100644
index 0000000..de0d7de
--- /dev/null
+++ b/fs/afs/cache.c
@@ -0,0 +1,256 @@
+/* AFS caching stuff
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_cell_cache_match(void *target,
+						const void *entry);
+static void afs_cell_cache_update(void *source, void *entry);
+
+struct cachefs_index_def afs_cache_cell_index_def = {
+	.name			= "cell_ix",
+	.data_size		= sizeof(struct afs_cache_cell),
+	.keys[0]		= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
+	.match			= afs_cell_cache_match,
+	.update			= afs_cell_cache_update,
+};
+#endif
+
+/*
+ * match a cell record obtained from the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_cell_cache_match(void *target,
+						const void *entry)
+{
+	const struct afs_cache_cell *ccell = entry;
+	struct afs_cell *cell = target;
+
+	_enter("{%s},{%s}", ccell->name, cell->name);
+
+	if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
+		_leave(" = SUCCESS");
+		return CACHEFS_MATCH_SUCCESS;
+	}
+
+	_leave(" = FAILED");
+	return CACHEFS_MATCH_FAILED;
+}
+#endif
+
+/*
+ * update a cell record in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static void afs_cell_cache_update(void *source, void *entry)
+{
+	struct afs_cache_cell *ccell = entry;
+	struct afs_cell *cell = source;
+
+	_enter("%p,%p", source, entry);
+
+	strncpy(ccell->name, cell->name, sizeof(ccell->name));
+
+	memcpy(ccell->vl_servers,
+	       cell->vl_addrs,
+	       min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
+
+}
+#endif
+
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_vlocation_cache_match(void *target,
+						     const void *entry);
+static void afs_vlocation_cache_update(void *source, void *entry);
+
+struct cachefs_index_def afs_vlocation_cache_index_def = {
+	.name		= "vldb",
+	.data_size	= sizeof(struct afs_cache_vlocation),
+	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
+	.match		= afs_vlocation_cache_match,
+	.update		= afs_vlocation_cache_update,
+};
+#endif
+
+/*
+ * match a VLDB record stored in the cache
+ * - may also load target from entry
+ */
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_vlocation_cache_match(void *target,
+						     const void *entry)
+{
+	const struct afs_cache_vlocation *vldb = entry;
+	struct afs_vlocation *vlocation = target;
+
+	_enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
+
+	if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
+	    ) {
+		if (!vlocation->valid ||
+		    vlocation->vldb.rtime == vldb->rtime
+		    ) {
+			vlocation->vldb = *vldb;
+			vlocation->valid = 1;
+			_leave(" = SUCCESS [c->m]");
+			return CACHEFS_MATCH_SUCCESS;
+		} else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
+			/* delete if VIDs for this name differ */
+			if (memcmp(&vlocation->vldb.vid,
+				   &vldb->vid,
+				   sizeof(vldb->vid)) != 0) {
+				_leave(" = DELETE");
+				return CACHEFS_MATCH_SUCCESS_DELETE;
+			}
+
+			_leave(" = UPDATE");
+			return CACHEFS_MATCH_SUCCESS_UPDATE;
+		} else {
+			_leave(" = SUCCESS");
+			return CACHEFS_MATCH_SUCCESS;
+		}
+	}
+
+	_leave(" = FAILED");
+	return CACHEFS_MATCH_FAILED;
+}
+#endif
+
+/*
+ * update a VLDB record stored in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static void afs_vlocation_cache_update(void *source, void *entry)
+{
+	struct afs_cache_vlocation *vldb = entry;
+	struct afs_vlocation *vlocation = source;
+
+	_enter("");
+
+	*vldb = vlocation->vldb;
+}
+#endif
+
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_volume_cache_match(void *target,
+						  const void *entry);
+static void afs_volume_cache_update(void *source, void *entry);
+
+struct cachefs_index_def afs_volume_cache_index_def = {
+	.name		= "volume",
+	.data_size	= sizeof(struct afs_cache_vhash),
+	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 1 },
+	.keys[1]	= { CACHEFS_INDEX_KEYS_BIN, 1 },
+	.match		= afs_volume_cache_match,
+	.update		= afs_volume_cache_update,
+};
+#endif
+
+/*
+ * match a volume hash record stored in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_volume_cache_match(void *target,
+						  const void *entry)
+{
+	const struct afs_cache_vhash *vhash = entry;
+	struct afs_volume *volume = target;
+
+	_enter("{%u},{%u}", volume->type, vhash->vtype);
+
+	if (volume->type == vhash->vtype) {
+		_leave(" = SUCCESS");
+		return CACHEFS_MATCH_SUCCESS;
+	}
+
+	_leave(" = FAILED");
+	return CACHEFS_MATCH_FAILED;
+}
+#endif
+
+/*
+ * update a volume hash record stored in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static void afs_volume_cache_update(void *source, void *entry)
+{
+	struct afs_cache_vhash *vhash = entry;
+	struct afs_volume *volume = source;
+
+	_enter("");
+
+	vhash->vtype = volume->type;
+}
+#endif
+
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_vnode_cache_match(void *target,
+						 const void *entry);
+static void afs_vnode_cache_update(void *source, void *entry);
+
+struct cachefs_index_def afs_vnode_cache_index_def = {
+	.name		= "vnode",
+	.data_size	= sizeof(struct afs_cache_vnode),
+	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 4 },
+	.match		= afs_vnode_cache_match,
+	.update		= afs_vnode_cache_update,
+};
+#endif
+
+/*
+ * match a vnode record stored in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static cachefs_match_val_t afs_vnode_cache_match(void *target,
+						 const void *entry)
+{
+	const struct afs_cache_vnode *cvnode = entry;
+	struct afs_vnode *vnode = target;
+
+	_enter("{%x,%x,%Lx},{%x,%x,%Lx}",
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       vnode->status.version,
+	       cvnode->vnode_id,
+	       cvnode->vnode_unique,
+	       cvnode->data_version);
+
+	if (vnode->fid.vnode != cvnode->vnode_id) {
+		_leave(" = FAILED");
+		return CACHEFS_MATCH_FAILED;
+	}
+
+	if (vnode->fid.unique != cvnode->vnode_unique ||
+	    vnode->status.version != cvnode->data_version) {
+		_leave(" = DELETE");
+		return CACHEFS_MATCH_SUCCESS_DELETE;
+	}
+
+	_leave(" = SUCCESS");
+	return CACHEFS_MATCH_SUCCESS;
+}
+#endif
+
+/*
+ * update a vnode record stored in the cache
+ */
+#ifdef AFS_CACHING_SUPPORT
+static void afs_vnode_cache_update(void *source, void *entry)
+{
+	struct afs_cache_vnode *cvnode = entry;
+	struct afs_vnode *vnode = source;
+
+	_enter("");
+
+	cvnode->vnode_id	= vnode->fid.vnode;
+	cvnode->vnode_unique	= vnode->fid.unique;
+	cvnode->data_version	= vnode->status.version;
+}
+#endif
diff --git a/fs/afs/cache.h b/fs/afs/cache.h
index 9eb7722..36a3642 100644
--- a/fs/afs/cache.h
+++ b/fs/afs/cache.h
@@ -1,4 +1,4 @@
-/* cache.h: AFS local cache management interface
+/* AFS local cache management interface
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -9,8 +9,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef _LINUX_AFS_CACHE_H
-#define _LINUX_AFS_CACHE_H
+#ifndef AFS_CACHE_H
+#define AFS_CACHE_H
 
 #undef AFS_CACHING_SUPPORT
 
@@ -20,8 +20,4 @@ #include <linux/cachefs.h>
 #endif
 #include "types.h"
 
-#ifdef __KERNEL__
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_AFS_CACHE_H */
+#endif /* AFS_CACHE_H */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 9cb206e..9bdbf36 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved.
  *
  * This software may be freely redistributed under the terms of the
  * GNU General Public License.
@@ -16,85 +16,187 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include "server.h"
-#include "vnode.h"
+#include <linux/circ_buf.h>
 #include "internal.h"
-#include "cmservice.h"
 
-/*****************************************************************************/
+unsigned afs_vnode_update_timeout = 10;
+
+#define afs_breakring_space(server) \
+	CIRC_SPACE((server)->cb_break_head, (server)->cb_break_tail,	\
+		   ARRAY_SIZE((server)->cb_break))
+
+//static void afs_callback_updater(struct work_struct *);
+
+static struct workqueue_struct *afs_callback_update_worker;
+
 /*
  * allow the fileserver to request callback state (re-)initialisation
  */
-int SRXAFSCM_InitCallBackState(struct afs_server *server)
+void afs_init_callback_state(struct afs_server *server)
 {
-	struct list_head callbacks;
+	struct afs_vnode *vnode;
 
-	_enter("%p", server);
+	_enter("{%p}", server);
 
-	INIT_LIST_HEAD(&callbacks);
-
-	/* transfer the callback list from the server to a temp holding area */
 	spin_lock(&server->cb_lock);
 
-	list_add(&callbacks, &server->cb_promises);
-	list_del_init(&server->cb_promises);
+	/* kill all the promises on record from this server */
+	while (!RB_EMPTY_ROOT(&server->cb_promises)) {
+		vnode = rb_entry(server->cb_promises.rb_node,
+				 struct afs_vnode, cb_promise);
+		_debug("UNPROMISE { vid=%x vn=%u uq=%u}",
+		       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
+		rb_erase(&vnode->cb_promise, &server->cb_promises);
+		vnode->cb_promised = false;
+	}
 
-	/* munch our way through the list, grabbing the inode, dropping all the
-	 * locks and regetting them in the right order
-	 */
-	while (!list_empty(&callbacks)) {
-		struct afs_vnode *vnode;
-		struct inode *inode;
+	spin_unlock(&server->cb_lock);
+	_leave("");
+}
 
-		vnode = list_entry(callbacks.next, struct afs_vnode, cb_link);
-		list_del_init(&vnode->cb_link);
+/*
+ * handle the data invalidation side of a callback being broken
+ */
+void afs_broken_callback_work(struct work_struct *work)
+{
+	struct afs_vnode *vnode =
+		container_of(work, struct afs_vnode, cb_broken_work);
 
-		/* try and grab the inode - may fail */
-		inode = igrab(AFS_VNODE_TO_I(vnode));
-		if (inode) {
-			int release = 0;
+	_enter("");
 
-			spin_unlock(&server->cb_lock);
-			spin_lock(&vnode->lock);
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
+		return;
 
-			if (vnode->cb_server == server) {
-				vnode->cb_server = NULL;
-				afs_kafstimod_del_timer(&vnode->cb_timeout);
-				spin_lock(&afs_cb_hash_lock);
-				list_del_init(&vnode->cb_hash_link);
-				spin_unlock(&afs_cb_hash_lock);
-				release = 1;
-			}
+	/* we're only interested in dealing with a broken callback on *this*
+	 * vnode and only if no-one else has dealt with it yet */
+	if (!mutex_trylock(&vnode->validate_lock))
+		return; /* someone else is dealing with it */
 
-			spin_unlock(&vnode->lock);
+	if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
+		if (S_ISDIR(vnode->vfs_inode.i_mode))
+			afs_clear_permits(vnode);
 
-			iput(inode);
-			afs_put_server(server);
+		if (afs_vnode_fetch_status(vnode, NULL, NULL) < 0)
+			goto out;
 
-			spin_lock(&server->cb_lock);
+		if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
+			goto out;
+
+		/* if the vnode's data version number changed then its contents
+		 * are different */
+		if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
+			_debug("zap data {%x:%u}",
+			       vnode->fid.vid, vnode->fid.vnode);
+			invalidate_remote_inode(&vnode->vfs_inode);
 		}
 	}
 
-	spin_unlock(&server->cb_lock);
+out:
+	mutex_unlock(&vnode->validate_lock);
 
-	_leave(" = 0");
-	return 0;
-} /* end SRXAFSCM_InitCallBackState() */
+	/* avoid the potential race whereby the mutex_trylock() in this
+	 * function happens again between the clear_bit() and the
+	 * mutex_unlock() */
+	if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
+		_debug("requeue");
+		queue_work(afs_callback_update_worker, &vnode->cb_broken_work);
+	}
+	_leave("");
+}
+
+/*
+ * actually break a callback
+ */
+static void afs_break_callback(struct afs_server *server,
+			       struct afs_vnode *vnode)
+{
+	_enter("");
+
+	set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+
+	if (vnode->cb_promised) {
+		spin_lock(&vnode->lock);
+
+		_debug("break callback");
+
+		spin_lock(&server->cb_lock);
+		if (vnode->cb_promised) {
+			rb_erase(&vnode->cb_promise, &server->cb_promises);
+			vnode->cb_promised = false;
+		}
+		spin_unlock(&server->cb_lock);
+
+		queue_work(afs_callback_update_worker, &vnode->cb_broken_work);
+		spin_unlock(&vnode->lock);
+	}
+}
+
+/*
+ * allow the fileserver to explicitly break one callback
+ * - happens when
+ *   - the backing file is changed
+ *   - a lock is released
+ */
+static void afs_break_one_callback(struct afs_server *server,
+				   struct afs_fid *fid)
+{
+	struct afs_vnode *vnode;
+	struct rb_node *p;
+
+	_debug("find");
+	spin_lock(&server->fs_lock);
+	p = server->fs_vnodes.rb_node;
+	while (p) {
+		vnode = rb_entry(p, struct afs_vnode, server_rb);
+		if (fid->vid < vnode->fid.vid)
+			p = p->rb_left;
+		else if (fid->vid > vnode->fid.vid)
+			p = p->rb_right;
+		else if (fid->vnode < vnode->fid.vnode)
+			p = p->rb_left;
+		else if (fid->vnode > vnode->fid.vnode)
+			p = p->rb_right;
+		else if (fid->unique < vnode->fid.unique)
+			p = p->rb_left;
+		else if (fid->unique > vnode->fid.unique)
+			p = p->rb_right;
+		else
+			goto found;
+	}
+
+	/* not found so we just ignore it (it may have moved to another
+	 * server) */
+not_available:
+	_debug("not avail");
+	spin_unlock(&server->fs_lock);
+	_leave("");
+	return;
+
+found:
+	_debug("found");
+	ASSERTCMP(server, ==, vnode->server);
+
+	if (!igrab(AFS_VNODE_TO_I(vnode)))
+		goto not_available;
+	spin_unlock(&server->fs_lock);
+
+	afs_break_callback(server, vnode);
+	iput(&vnode->vfs_inode);
+	_leave("");
+}
 
-/*****************************************************************************/
 /*
  * allow the fileserver to break callback promises
  */
-int SRXAFSCM_CallBack(struct afs_server *server, size_t count,
-		      struct afs_callback callbacks[])
+void afs_break_callbacks(struct afs_server *server, size_t count,
+			 struct afs_callback callbacks[])
 {
-	_enter("%p,%u,", server, count);
+	_enter("%p,%zu,", server, count);
 
-	for (; count > 0; callbacks++, count--) {
-		struct afs_vnode *vnode = NULL;
-		struct inode *inode = NULL;
-		int valid = 0;
+	ASSERT(server != NULL);
+	ASSERTCMP(count, <=, AFSCBMAX);
 
+	for (; count > 0; callbacks++, count--) {
 		_debug("- Fid { vl=%08x n=%u u=%u }  CB { v=%u x=%u t=%u }",
 		       callbacks->fid.vid,
 		       callbacks->fid.vnode,
@@ -103,67 +205,270 @@ int SRXAFSCM_CallBack(struct afs_server 
 		       callbacks->expiry,
 		       callbacks->type
 		       );
+		afs_break_one_callback(server, &callbacks->fid);
+	}
 
-		/* find the inode for this fid */
-		spin_lock(&afs_cb_hash_lock);
+	_leave("");
+	return;
+}
 
-		list_for_each_entry(vnode,
-				    &afs_cb_hash(server, &callbacks->fid),
-				    cb_hash_link) {
-			if (memcmp(&vnode->fid, &callbacks->fid,
-				   sizeof(struct afs_fid)) != 0)
-				continue;
+/*
+ * record the callback for breaking
+ * - the caller must hold server->cb_lock
+ */
+static void afs_do_give_up_callback(struct afs_server *server,
+				    struct afs_vnode *vnode)
+{
+	struct afs_callback *cb;
 
-			/* right vnode, but is it same server? */
-			if (vnode->cb_server != server)
-				break; /* no */
+	_enter("%p,%p", server, vnode);
 
-			/* try and nail the inode down */
-			inode = igrab(AFS_VNODE_TO_I(vnode));
-			break;
+	cb = &server->cb_break[server->cb_break_head];
+	cb->fid		= vnode->fid;
+	cb->version	= vnode->cb_version;
+	cb->expiry	= vnode->cb_expiry;
+	cb->type	= vnode->cb_type;
+	smp_wmb();
+	server->cb_break_head =
+		(server->cb_break_head + 1) &
+		(ARRAY_SIZE(server->cb_break) - 1);
+
+	/* defer the breaking of callbacks to try and collect as many as
+	 * possible to ship in one operation */
+	switch (atomic_inc_return(&server->cb_break_n)) {
+	case 1 ... AFSCBMAX - 1:
+		queue_delayed_work(afs_callback_update_worker,
+				   &server->cb_break_work, HZ * 2);
+		break;
+	case AFSCBMAX:
+		afs_flush_callback_breaks(server);
+		break;
+	default:
+		break;
+	}
+
+	ASSERT(server->cb_promises.rb_node != NULL);
+	rb_erase(&vnode->cb_promise, &server->cb_promises);
+	vnode->cb_promised = false;
+	_leave("");
+}
+
+/*
+ * discard the callback on a deleted item
+ */
+void afs_discard_callback_on_delete(struct afs_vnode *vnode)
+{
+	struct afs_server *server = vnode->server;
+
+	_enter("%d", vnode->cb_promised);
+
+	if (!vnode->cb_promised) {
+		_leave(" [not promised]");
+		return;
+	}
+
+	ASSERT(server != NULL);
+
+	spin_lock(&server->cb_lock);
+	if (vnode->cb_promised) {
+		ASSERT(server->cb_promises.rb_node != NULL);
+		rb_erase(&vnode->cb_promise, &server->cb_promises);
+		vnode->cb_promised = false;
+	}
+	spin_unlock(&server->cb_lock);
+	_leave("");
+}
+
+/*
+ * give up the callback registered for a vnode on the file server when the
+ * inode is being cleared
+ */
+void afs_give_up_callback(struct afs_vnode *vnode)
+{
+	struct afs_server *server = vnode->server;
+
+	DECLARE_WAITQUEUE(myself, current);
+
+	_enter("%d", vnode->cb_promised);
+
+	_debug("GIVE UP INODE %p", &vnode->vfs_inode);
+
+	if (!vnode->cb_promised) {
+		_leave(" [not promised]");
+		return;
+	}
+
+	ASSERT(server != NULL);
+
+	spin_lock(&server->cb_lock);
+	if (vnode->cb_promised && afs_breakring_space(server) == 0) {
+		add_wait_queue(&server->cb_break_waitq, &myself);
+		for (;;) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			if (!vnode->cb_promised ||
+			    afs_breakring_space(server) != 0)
+				break;
+			spin_unlock(&server->cb_lock);
+			schedule();
+			spin_lock(&server->cb_lock);
 		}
+		remove_wait_queue(&server->cb_break_waitq, &myself);
+		__set_current_state(TASK_RUNNING);
+	}
+
+	/* of course, it's always possible for the server to break this vnode's
+	 * callback first... */
+	if (vnode->cb_promised)
+		afs_do_give_up_callback(server, vnode);
+
+	spin_unlock(&server->cb_lock);
+	_leave("");
+}
+
+/*
+ * dispatch a deferred give up callbacks operation
+ */
+void afs_dispatch_give_up_callbacks(struct work_struct *work)
+{
+	struct afs_server *server =
+		container_of(work, struct afs_server, cb_break_work.work);
+
+	_enter("");
+
+	/* tell the fileserver to discard the callback promises it has
+	 * - in the event of ENOMEM or some other error, we just forget that we
+	 *   had callbacks entirely, and the server will call us later to break
+	 *   them
+	 */
+	afs_fs_give_up_callbacks(server, &afs_async_call);
+}
+
+/*
+ * flush the outstanding callback breaks on a server
+ */
+void afs_flush_callback_breaks(struct afs_server *server)
+{
+	cancel_delayed_work(&server->cb_break_work);
+	queue_delayed_work(afs_callback_update_worker,
+			   &server->cb_break_work, 0);
+}
 
-		spin_unlock(&afs_cb_hash_lock);
-
-		if (inode) {
-			/* we've found the record for this vnode */
-			spin_lock(&vnode->lock);
-			if (vnode->cb_server == server) {
-				/* the callback _is_ on the calling server */
-				vnode->cb_server = NULL;
-				valid = 1;
-
-				afs_kafstimod_del_timer(&vnode->cb_timeout);
-				vnode->flags |= AFS_VNODE_CHANGED;
-
-				spin_lock(&server->cb_lock);
-				list_del_init(&vnode->cb_link);
-				spin_unlock(&server->cb_lock);
-
-				spin_lock(&afs_cb_hash_lock);
-				list_del_init(&vnode->cb_hash_link);
-				spin_unlock(&afs_cb_hash_lock);
-			}
-			spin_unlock(&vnode->lock);
-
-			if (valid) {
-				invalidate_remote_inode(inode);
-				afs_put_server(server);
-			}
-			iput(inode);
+#if 0
+/*
+ * update a bunch of callbacks
+ */
+static void afs_callback_updater(struct work_struct *work)
+{
+	struct afs_server *server;
+	struct afs_vnode *vnode, *xvnode;
+	time_t now;
+	long timeout;
+	int ret;
+
+	server = container_of(work, struct afs_server, updater);
+
+	_enter("");
+
+	now = get_seconds();
+
+	/* find the first vnode to update */
+	spin_lock(&server->cb_lock);
+	for (;;) {
+		if (RB_EMPTY_ROOT(&server->cb_promises)) {
+			spin_unlock(&server->cb_lock);
+			_leave(" [nothing]");
+			return;
 		}
+
+		vnode = rb_entry(rb_first(&server->cb_promises),
+				 struct afs_vnode, cb_promise);
+		if (atomic_read(&vnode->usage) > 0)
+			break;
+		rb_erase(&vnode->cb_promise, &server->cb_promises);
+		vnode->cb_promised = false;
 	}
 
-	_leave(" = 0");
-	return 0;
-} /* end SRXAFSCM_CallBack() */
+	timeout = vnode->update_at - now;
+	if (timeout > 0) {
+		queue_delayed_work(afs_vnode_update_worker,
+				   &afs_vnode_update, timeout * HZ);
+		spin_unlock(&server->cb_lock);
+		_leave(" [nothing]");
+		return;
+	}
+
+	list_del_init(&vnode->update);
+	atomic_inc(&vnode->usage);
+	spin_unlock(&server->cb_lock);
+
+	/* we can now perform the update */
+	_debug("update %s", vnode->vldb.name);
+	vnode->state = AFS_VL_UPDATING;
+	vnode->upd_rej_cnt = 0;
+	vnode->upd_busy_cnt = 0;
+
+	ret = afs_vnode_update_record(vl, &vldb);
+	switch (ret) {
+	case 0:
+		afs_vnode_apply_update(vl, &vldb);
+		vnode->state = AFS_VL_UPDATING;
+		break;
+	case -ENOMEDIUM:
+		vnode->state = AFS_VL_VOLUME_DELETED;
+		break;
+	default:
+		vnode->state = AFS_VL_UNCERTAIN;
+		break;
+	}
+
+	/* and then reschedule */
+	_debug("reschedule");
+	vnode->update_at = get_seconds() + afs_vnode_update_timeout;
+
+	spin_lock(&server->cb_lock);
+
+	if (!list_empty(&server->cb_promises)) {
+		/* next update in 10 minutes, but wait at least 1 second more
+		 * than the newest record already queued so that we don't spam
+		 * the VL server suddenly with lots of requests
+		 */
+		xvnode = list_entry(server->cb_promises.prev,
+				    struct afs_vnode, update);
+		if (vnode->update_at <= xvnode->update_at)
+			vnode->update_at = xvnode->update_at + 1;
+		xvnode = list_entry(server->cb_promises.next,
+				    struct afs_vnode, update);
+		timeout = xvnode->update_at - now;
+		if (timeout < 0)
+			timeout = 0;
+	} else {
+		timeout = afs_vnode_update_timeout;
+	}
+
+	list_add_tail(&vnode->update, &server->cb_promises);
+
+	_debug("timeout %ld", timeout);
+	queue_delayed_work(afs_vnode_update_worker,
+			   &afs_vnode_update, timeout * HZ);
+	spin_unlock(&server->cb_lock);
+	afs_put_vnode(vl);
+}
+#endif
+
+/*
+ * initialise the callback update process
+ */
+int __init afs_callback_update_init(void)
+{
+	afs_callback_update_worker =
+		create_singlethread_workqueue("kafs_callbackd");
+	return afs_callback_update_worker ? 0 : -ENOMEM;
+}
 
-/*****************************************************************************/
 /*
- * allow the fileserver to see if the cache manager is still alive
+ * shut down the callback update process
  */
-int SRXAFSCM_Probe(struct afs_server *server)
+void afs_callback_update_kill(void)
 {
-	_debug("SRXAFSCM_Probe(%p)\n", server);
-	return 0;
-} /* end SRXAFSCM_Probe() */
+	destroy_workqueue(afs_callback_update_worker);
+}
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 1fc5783..9b1311a 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -1,4 +1,4 @@
-/* cell.c: AFS cell and server record management
+/* AFS cell and server record management
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -11,15 +11,9 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include "volume.h"
-#include "cell.h"
-#include "server.h"
-#include "transport.h"
-#include "vlclient.h"
-#include "kafstimod.h"
-#include "super.h"
+#include <linux/key.h>
+#include <linux/ctype.h>
+#include <keys/rxrpc-type.h>
 #include "internal.h"
 
 DECLARE_RWSEM(afs_proc_cells_sem);
@@ -28,66 +22,47 @@ LIST_HEAD(afs_proc_cells);
 static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
 static DEFINE_RWLOCK(afs_cells_lock);
 static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
+static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
 static struct afs_cell *afs_cell_root;
 
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
-						const void *entry);
-static void afs_cell_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_cache_cell_index_def = {
-	.name			= "cell_ix",
-	.data_size		= sizeof(struct afs_cache_cell),
-	.keys[0]		= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
-	.match			= afs_cell_cache_match,
-	.update			= afs_cell_cache_update,
-};
-#endif
-
-/*****************************************************************************/
 /*
- * create a cell record
- * - "name" is the name of the cell
- * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ * allocate a cell record and fill in its name, VL server address list and
+ * allocate an anonymous key
  */
-int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell)
+static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
 {
 	struct afs_cell *cell;
-	char *next;
+	size_t namelen;
+	char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
 	int ret;
 
-	_enter("%s", name);
+	_enter("%s,%s", name, vllist);
 
 	BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
 
+	namelen = strlen(name);
+	if (namelen > AFS_MAXCELLNAME)
+		return ERR_PTR(-ENAMETOOLONG);
+
 	/* allocate and initialise a cell record */
-	cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
+	cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
 	if (!cell) {
 		_leave(" = -ENOMEM");
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
-	down_write(&afs_cells_sem);
-
-	memset(cell, 0, sizeof(struct afs_cell));
-	atomic_set(&cell->usage, 0);
+	memcpy(cell->name, name, namelen);
+	cell->name[namelen] = 0;
 
+	atomic_set(&cell->usage, 1);
 	INIT_LIST_HEAD(&cell->link);
-
-	rwlock_init(&cell->sv_lock);
-	INIT_LIST_HEAD(&cell->sv_list);
-	INIT_LIST_HEAD(&cell->sv_graveyard);
-	spin_lock_init(&cell->sv_gylock);
-
+	rwlock_init(&cell->servers_lock);
+	INIT_LIST_HEAD(&cell->servers);
 	init_rwsem(&cell->vl_sem);
 	INIT_LIST_HEAD(&cell->vl_list);
-	INIT_LIST_HEAD(&cell->vl_graveyard);
-	spin_lock_init(&cell->vl_gylock);
-
-	strcpy(cell->name,name);
+	spin_lock_init(&cell->vl_lock);
 
 	/* fill in the VL server list from the rest of the string */
-	ret = -EINVAL;
 	do {
 		unsigned a, b, c, d;
 
@@ -96,20 +71,75 @@ int afs_cell_create(const char *name, ch
 			*next++ = 0;
 
 		if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
-			goto badaddr;
+			goto bad_address;
 
 		if (a > 255 || b > 255 || c > 255 || d > 255)
-			goto badaddr;
+			goto bad_address;
 
 		cell->vl_addrs[cell->vl_naddrs++].s_addr =
 			htonl((a << 24) | (b << 16) | (c << 8) | d);
 
-		if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
-			break;
+	} while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
+
+	/* create a key to represent an anonymous user */
+	memcpy(keyname, "afs@", 4);
+	dp = keyname + 4;
+	cp = cell->name;
+	do {
+		*dp++ = toupper(*cp);
+	} while (*cp++);
+	cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
+					KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(cell->anonymous_key)) {
+		_debug("no key");
+		ret = PTR_ERR(cell->anonymous_key);
+		goto error;
+	}
+
+	ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
+				       NULL, NULL);
+	if (ret < 0) {
+		_debug("instantiate failed");
+		goto error;
+	}
+
+	_debug("anon key %p{%x}",
+	       cell->anonymous_key, key_serial(cell->anonymous_key));
+
+	_leave(" = %p", cell);
+	return cell;
+
+bad_address:
+	printk(KERN_ERR "kAFS: bad VL server IP address\n");
+	ret = -EINVAL;
+error:
+	key_put(cell->anonymous_key);
+	kfree(cell);
+	_leave(" = %d", ret);
+	return ERR_PTR(ret);
+}
+
+/*
+ * create a cell record
+ * - "name" is the name of the cell
+ * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ */
+struct afs_cell *afs_cell_create(const char *name, char *vllist)
+{
+	struct afs_cell *cell;
+	int ret;
+
+	_enter("%s,%s", name, vllist);
 
-	} while(vllist = next, vllist);
+	cell = afs_cell_alloc(name, vllist);
+	if (IS_ERR(cell)) {
+		_leave(" = %ld", PTR_ERR(cell));
+		return cell;
+	}
+
+	down_write(&afs_cells_sem);
 
-	/* add a proc dir for this cell */
+	/* add a proc directory for this cell */
 	ret = afs_proc_cell_setup(cell);
 	if (ret < 0)
 		goto error;
@@ -130,31 +160,28 @@ #endif
 	down_write(&afs_proc_cells_sem);
 	list_add_tail(&cell->proc_link, &afs_proc_cells);
 	up_write(&afs_proc_cells_sem);
-
-	*_cell = cell;
 	up_write(&afs_cells_sem);
 
-	_leave(" = 0 (%p)", cell);
-	return 0;
+	_leave(" = %p", cell);
+	return cell;
 
- badaddr:
-	printk(KERN_ERR "kAFS: bad VL server IP address: '%s'\n", vllist);
- error:
+error:
 	up_write(&afs_cells_sem);
+	key_put(cell->anonymous_key);
 	kfree(cell);
 	_leave(" = %d", ret);
-	return ret;
-} /* end afs_cell_create() */
+	return ERR_PTR(ret);
+}
 
-/*****************************************************************************/
 /*
- * initialise the cell database from module parameters
+ * set the root cell information
+ * - can be called with a module parameter string
+ * - can be called from a write to /proc/fs/afs/rootcell
  */
 int afs_cell_init(char *rootcell)
 {
 	struct afs_cell *old_root, *new_root;
 	char *cp;
-	int ret;
 
 	_enter("");
 
@@ -162,82 +189,60 @@ int afs_cell_init(char *rootcell)
 		/* module is loaded with no parameters, or built statically.
 		 * - in the future we might initialize cell DB here.
 		 */
-		_leave(" = 0 (but no root)");
+		_leave(" = 0 [no root]");
 		return 0;
 	}
 
 	cp = strchr(rootcell, ':');
 	if (!cp) {
 		printk(KERN_ERR "kAFS: no VL server IP addresses specified\n");
-		_leave(" = %d (no colon)", -EINVAL);
+		_leave(" = -EINVAL");
 		return -EINVAL;
 	}
 
 	/* allocate a cell record for the root cell */
 	*cp++ = 0;
-	ret = afs_cell_create(rootcell, cp, &new_root);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
+	new_root = afs_cell_create(rootcell, cp);
+	if (IS_ERR(new_root)) {
+		_leave(" = %ld", PTR_ERR(new_root));
+		return PTR_ERR(new_root);
 	}
 
-	/* as afs_put_cell() takes locks by itself, we have to do
-	 * a little gymnastics to be race-free.
-	 */
-	afs_get_cell(new_root);
-
+	/* install the new cell */
 	write_lock(&afs_cells_lock);
-	while (afs_cell_root) {
-		old_root = afs_cell_root;
-		afs_cell_root = NULL;
-		write_unlock(&afs_cells_lock);
-		afs_put_cell(old_root);
-		write_lock(&afs_cells_lock);
-	}
+	old_root = afs_cell_root;
 	afs_cell_root = new_root;
 	write_unlock(&afs_cells_lock);
+	afs_put_cell(old_root);
 
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end afs_cell_init() */
+	_leave(" = 0");
+	return 0;
+}
 
-/*****************************************************************************/
 /*
  * lookup a cell record
  */
-int afs_cell_lookup(const char *name, unsigned namesz, struct afs_cell **_cell)
+struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
 {
 	struct afs_cell *cell;
-	int ret;
 
 	_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
 
-	*_cell = NULL;
+	down_read(&afs_cells_sem);
+	read_lock(&afs_cells_lock);
 
 	if (name) {
 		/* if the cell was named, look for it in the cell record list */
-		ret = -ENOENT;
-		cell = NULL;
-		read_lock(&afs_cells_lock);
-
 		list_for_each_entry(cell, &afs_cells, link) {
 			if (strncmp(cell->name, name, namesz) == 0) {
 				afs_get_cell(cell);
 				goto found;
 			}
 		}
-		cell = NULL;
+		cell = ERR_PTR(-ENOENT);
 	found:
-
-		read_unlock(&afs_cells_lock);
-
-		if (cell)
-			ret = 0;
-	}
-	else {
-		read_lock(&afs_cells_lock);
-
+		;
+	} else {
 		cell = afs_cell_root;
 		if (!cell) {
 			/* this should not happen unless user tries to mount
@@ -246,44 +251,35 @@ int afs_cell_lookup(const char *name, un
 			 * ENOENT might be "more appropriate" but they happen
 			 * for other reasons.
 			 */
-			ret = -EDESTADDRREQ;
-		}
-		else {
+			cell = ERR_PTR(-EDESTADDRREQ);
+		} else {
 			afs_get_cell(cell);
-			ret = 0;
 		}
 
-		read_unlock(&afs_cells_lock);
 	}
 
-	*_cell = cell;
-	_leave(" = %d (%p)", ret, cell);
-	return ret;
-
-} /* end afs_cell_lookup() */
+	read_unlock(&afs_cells_lock);
+	up_read(&afs_cells_sem);
+	_leave(" = %p", cell);
+	return cell;
+}
 
-/*****************************************************************************/
 /*
  * try and get a cell record
  */
-struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell)
+struct afs_cell *afs_get_cell_maybe(struct afs_cell *cell)
 {
-	struct afs_cell *cell;
-
 	write_lock(&afs_cells_lock);
 
-	cell = *_cell;
 	if (cell && !list_empty(&cell->link))
 		afs_get_cell(cell);
 	else
 		cell = NULL;
 
 	write_unlock(&afs_cells_lock);
-
 	return cell;
-} /* end afs_get_cell_maybe() */
+}
 
-/*****************************************************************************/
 /*
  * destroy a cell record
  */
@@ -294,8 +290,7 @@ void afs_put_cell(struct afs_cell *cell)
 
 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
 
-	/* sanity check */
-	BUG_ON(atomic_read(&cell->usage) <= 0);
+	ASSERTCMP(atomic_read(&cell->usage), >, 0);
 
 	/* to prevent a race, the decrement and the dequeue must be effectively
 	 * atomic */
@@ -307,36 +302,49 @@ void afs_put_cell(struct afs_cell *cell)
 		return;
 	}
 
+	ASSERT(list_empty(&cell->servers));
+	ASSERT(list_empty(&cell->vl_list));
+
 	write_unlock(&afs_cells_lock);
 
-	BUG_ON(!list_empty(&cell->sv_list));
-	BUG_ON(!list_empty(&cell->sv_graveyard));
-	BUG_ON(!list_empty(&cell->vl_list));
-	BUG_ON(!list_empty(&cell->vl_graveyard));
+	wake_up(&afs_cells_freeable_wq);
 
 	_leave(" [unused]");
-} /* end afs_put_cell() */
+}
 
-/*****************************************************************************/
 /*
  * destroy a cell record
+ * - must be called with the afs_cells_sem write-locked
+ * - cell->link should have been broken by the caller
  */
 static void afs_cell_destroy(struct afs_cell *cell)
 {
 	_enter("%p{%d,%s}", cell, atomic_read(&cell->usage), cell->name);
 
-	/* to prevent a race, the decrement and the dequeue must be effectively
-	 * atomic */
-	write_lock(&afs_cells_lock);
+	ASSERTCMP(atomic_read(&cell->usage), >=, 0);
+	ASSERT(list_empty(&cell->link));
 
-	/* sanity check */
-	BUG_ON(atomic_read(&cell->usage) != 0);
+	/* wait for everyone to stop using the cell */
+	if (atomic_read(&cell->usage) > 0) {
+		DECLARE_WAITQUEUE(myself, current);
 
-	list_del_init(&cell->link);
+		_debug("wait for cell %s", cell->name);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&afs_cells_freeable_wq, &myself);
 
-	write_unlock(&afs_cells_lock);
+		while (atomic_read(&cell->usage) > 0) {
+			schedule();
+			set_current_state(TASK_UNINTERRUPTIBLE);
+		}
 
-	down_write(&afs_cells_sem);
+		remove_wait_queue(&afs_cells_freeable_wq, &myself);
+		set_current_state(TASK_RUNNING);
+	}
+
+	_debug("cell dead");
+	ASSERTCMP(atomic_read(&cell->usage), ==, 0);
+	ASSERT(list_empty(&cell->servers));
+	ASSERT(list_empty(&cell->vl_list));
 
 	afs_proc_cell_remove(cell);
 
@@ -348,104 +356,26 @@ #ifdef AFS_CACHING_SUPPORT
 	cachefs_relinquish_cookie(cell->cache, 0);
 #endif
 
-	up_write(&afs_cells_sem);
-
-	BUG_ON(!list_empty(&cell->sv_list));
-	BUG_ON(!list_empty(&cell->sv_graveyard));
-	BUG_ON(!list_empty(&cell->vl_list));
-	BUG_ON(!list_empty(&cell->vl_graveyard));
-
-	/* finish cleaning up the cell */
+	key_put(cell->anonymous_key);
 	kfree(cell);
 
 	_leave(" [destroyed]");
-} /* end afs_cell_destroy() */
-
-/*****************************************************************************/
-/*
- * lookup the server record corresponding to an Rx RPC peer
- */
-int afs_server_find_by_peer(const struct rxrpc_peer *peer,
-			    struct afs_server **_server)
-{
-	struct afs_server *server;
-	struct afs_cell *cell;
-
-	_enter("%p{a=%08x},", peer, ntohl(peer->addr.s_addr));
-
-	/* search the cell list */
-	read_lock(&afs_cells_lock);
-
-	list_for_each_entry(cell, &afs_cells, link) {
-
-		_debug("? cell %s",cell->name);
-
-		write_lock(&cell->sv_lock);
-
-		/* check the active list */
-		list_for_each_entry(server, &cell->sv_list, link) {
-			_debug("?? server %08x", ntohl(server->addr.s_addr));
-
-			if (memcmp(&server->addr, &peer->addr,
-				   sizeof(struct in_addr)) == 0)
-				goto found_server;
-		}
+}
 
-		/* check the inactive list */
-		spin_lock(&cell->sv_gylock);
-		list_for_each_entry(server, &cell->sv_graveyard, link) {
-			_debug("?? dead server %08x",
-			       ntohl(server->addr.s_addr));
-
-			if (memcmp(&server->addr, &peer->addr,
-				   sizeof(struct in_addr)) == 0)
-				goto found_dead_server;
-		}
-		spin_unlock(&cell->sv_gylock);
-
-		write_unlock(&cell->sv_lock);
-	}
-	read_unlock(&afs_cells_lock);
-
-	_leave(" = -ENOENT");
-	return -ENOENT;
-
-	/* we found it in the graveyard - resurrect it */
- found_dead_server:
-	list_move_tail(&server->link, &cell->sv_list);
-	afs_get_server(server);
-	afs_kafstimod_del_timer(&server->timeout);
-	spin_unlock(&cell->sv_gylock);
-	goto success;
-
-	/* we found it - increment its ref count and return it */
- found_server:
-	afs_get_server(server);
-
- success:
-	write_unlock(&cell->sv_lock);
-	read_unlock(&afs_cells_lock);
-
-	*_server = server;
-	_leave(" = 0 (s=%p c=%p)", server, cell);
-	return 0;
-
-} /* end afs_server_find_by_peer() */
-
-/*****************************************************************************/
 /*
  * purge in-memory cell database on module unload or afs_init() failure
  * - the timeout daemon is stopped before calling this
  */
 void afs_cell_purge(void)
 {
-	struct afs_vlocation *vlocation;
 	struct afs_cell *cell;
 
 	_enter("");
 
 	afs_put_cell(afs_cell_root);
 
+	down_write(&afs_cells_sem);
+
 	while (!list_empty(&afs_cells)) {
 		cell = NULL;
 
@@ -464,104 +394,11 @@ void afs_cell_purge(void)
 			_debug("PURGING CELL %s (%d)",
 			       cell->name, atomic_read(&cell->usage));
 
-			BUG_ON(!list_empty(&cell->sv_list));
-			BUG_ON(!list_empty(&cell->vl_list));
-
-			/* purge the cell's VL graveyard list */
-			_debug(" - clearing VL graveyard");
-
-			spin_lock(&cell->vl_gylock);
-
-			while (!list_empty(&cell->vl_graveyard)) {
-				vlocation = list_entry(cell->vl_graveyard.next,
-						       struct afs_vlocation,
-						       link);
-				list_del_init(&vlocation->link);
-
-				afs_kafstimod_del_timer(&vlocation->timeout);
-
-				spin_unlock(&cell->vl_gylock);
-
-				afs_vlocation_do_timeout(vlocation);
-				/* TODO: race if move to use krxtimod instead
-				 * of kafstimod */
-
-				spin_lock(&cell->vl_gylock);
-			}
-
-			spin_unlock(&cell->vl_gylock);
-
-			/* purge the cell's server graveyard list */
-			_debug(" - clearing server graveyard");
-
-			spin_lock(&cell->sv_gylock);
-
-			while (!list_empty(&cell->sv_graveyard)) {
-				struct afs_server *server;
-
-				server = list_entry(cell->sv_graveyard.next,
-						    struct afs_server, link);
-				list_del_init(&server->link);
-
-				afs_kafstimod_del_timer(&server->timeout);
-
-				spin_unlock(&cell->sv_gylock);
-
-				afs_server_do_timeout(server);
-
-				spin_lock(&cell->sv_gylock);
-			}
-
-			spin_unlock(&cell->sv_gylock);
-
 			/* now the cell should be left with no references */
 			afs_cell_destroy(cell);
 		}
 	}
 
+	up_write(&afs_cells_sem);
 	_leave("");
-} /* end afs_cell_purge() */
-
-/*****************************************************************************/
-/*
- * match a cell record obtained from the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
-						const void *entry)
-{
-	const struct afs_cache_cell *ccell = entry;
-	struct afs_cell *cell = target;
-
-	_enter("{%s},{%s}", ccell->name, cell->name);
-
-	if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
-		_leave(" = SUCCESS");
-		return CACHEFS_MATCH_SUCCESS;
-	}
-
-	_leave(" = FAILED");
-	return CACHEFS_MATCH_FAILED;
-} /* end afs_cell_cache_match() */
-#endif
-
-/*****************************************************************************/
-/*
- * update a cell record in the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_cell_cache_update(void *source, void *entry)
-{
-	struct afs_cache_cell *ccell = entry;
-	struct afs_cell *cell = source;
-
-	_enter("%p,%p", source, entry);
-
-	strncpy(ccell->name, cell->name, sizeof(ccell->name));
-
-	memcpy(ccell->vl_servers,
-	       cell->vl_addrs,
-	       min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
-
-} /* end afs_cell_cache_update() */
-#endif
+}
diff --git a/fs/afs/cell.h b/fs/afs/cell.h
deleted file mode 100644
index 4834910..0000000
--- a/fs/afs/cell.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* cell.h: AFS cell record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_CELL_H
-#define _LINUX_AFS_CELL_H
-
-#include "types.h"
-#include "cache.h"
-
-#define AFS_CELL_MAX_ADDRS 15
-
-extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */
-
-/*****************************************************************************/
-/*
- * entry in the cached cell catalogue
- */
-struct afs_cache_cell
-{
-	char			name[64];	/* cell name (padded with NULs) */
-	struct in_addr		vl_servers[15];	/* cached cell VL servers */
-};
-
-/*****************************************************************************/
-/*
- * AFS cell record
- */
-struct afs_cell
-{
-	atomic_t		usage;
-	struct list_head	link;		/* main cell list link */
-	struct list_head	proc_link;	/* /proc cell list link */
-	struct proc_dir_entry	*proc_dir;	/* /proc dir for this cell */
-#ifdef AFS_CACHING_SUPPORT
-	struct cachefs_cookie	*cache;		/* caching cookie */
-#endif
-
-	/* server record management */
-	rwlock_t		sv_lock;	/* active server list lock */
-	struct list_head	sv_list;	/* active server list */
-	struct list_head	sv_graveyard;	/* inactive server list */
-	spinlock_t		sv_gylock;	/* inactive server list lock */
-
-	/* volume location record management */
-	struct rw_semaphore	vl_sem;		/* volume management serialisation semaphore */
-	struct list_head	vl_list;	/* cell's active VL record list */
-	struct list_head	vl_graveyard;	/* cell's inactive VL record list */
-	spinlock_t		vl_gylock;	/* graveyard lock */
-	unsigned short		vl_naddrs;	/* number of VL servers in addr list */
-	unsigned short		vl_curr_svix;	/* current server index */
-	struct in_addr		vl_addrs[AFS_CELL_MAX_ADDRS];	/* cell VL server addresses */
-
-	char			name[0];	/* cell name - must go last */
-};
-
-extern int afs_cell_init(char *rootcell);
-
-extern int afs_cell_create(const char *name, char *vllist, struct afs_cell **_cell);
-
-extern int afs_cell_lookup(const char *name, unsigned nmsize, struct afs_cell **_cell);
-
-#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
-
-extern struct afs_cell *afs_get_cell_maybe(struct afs_cell **_cell);
-
-extern void afs_put_cell(struct afs_cell *cell);
-
-extern void afs_cell_purge(void);
-
-#endif /* _LINUX_AFS_CELL_H */
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 3d097fd..d5b2ad6 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -1,4 +1,4 @@
-/* cmservice.c: AFS Cache Manager Service
+/* AFS Cache Manager Service
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -12,641 +12,464 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/completion.h>
-#include "server.h"
-#include "cell.h"
-#include "transport.h"
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include "cmservice.h"
+#include <linux/ip.h>
 #include "internal.h"
+#include "afs_cm.h"
 
-static unsigned afscm_usage;		/* AFS cache manager usage count */
-static struct rw_semaphore afscm_sem;	/* AFS cache manager start/stop semaphore */
-
-static int afscm_new_call(struct rxrpc_call *call);
-static void afscm_attention(struct rxrpc_call *call);
-static void afscm_error(struct rxrpc_call *call);
-static void afscm_aemap(struct rxrpc_call *call);
-
-static void _SRXAFSCM_CallBack(struct rxrpc_call *call);
-static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call);
-static void _SRXAFSCM_Probe(struct rxrpc_call *call);
-
-typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call);
-
-static const struct rxrpc_operation AFSCM_ops[] = {
-	{
-		.id	= 204,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "CallBack",
-		.user	= _SRXAFSCM_CallBack,
-	},
-	{
-		.id	= 205,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "InitCallBackState",
-		.user	= _SRXAFSCM_InitCallBackState,
-	},
-	{
-		.id	= 206,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "Probe",
-		.user	= _SRXAFSCM_Probe,
-	},
-#if 0
-	{
-		.id	= 207,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "GetLock",
-		.user	= _SRXAFSCM_GetLock,
-	},
-	{
-		.id	= 208,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "GetCE",
-		.user	= _SRXAFSCM_GetCE,
-	},
-	{
-		.id	= 209,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "GetXStatsVersion",
-		.user	= _SRXAFSCM_GetXStatsVersion,
-	},
-	{
-		.id	= 210,
-		.asize	= RXRPC_APP_MARK_EOF,
-		.name	= "GetXStats",
-		.user	= _SRXAFSCM_GetXStats,
-	}
-#endif
-};
+struct workqueue_struct *afs_cm_workqueue;
 
-static struct rxrpc_service AFSCM_service = {
-	.name		= "AFS/CM",
-	.owner		= THIS_MODULE,
-	.link		= LIST_HEAD_INIT(AFSCM_service.link),
-	.new_call	= afscm_new_call,
-	.service_id	= 1,
-	.attn_func	= afscm_attention,
-	.error_func	= afscm_error,
-	.aemap_func	= afscm_aemap,
-	.ops_begin	= &AFSCM_ops[0],
-	.ops_end	= &AFSCM_ops[ARRAY_SIZE(AFSCM_ops)],
-};
+static int afs_deliver_cb_init_call_back_state(struct afs_call *,
+					       struct sk_buff *, bool);
+static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
+						struct sk_buff *, bool);
+static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
+					   bool);
+static void afs_cm_destructor(struct afs_call *);
 
-static DECLARE_COMPLETION(kafscmd_alive);
-static DECLARE_COMPLETION(kafscmd_dead);
-static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq);
-static LIST_HEAD(kafscmd_attention_list);
-static LIST_HEAD(afscm_calls);
-static DEFINE_SPINLOCK(afscm_calls_lock);
-static DEFINE_SPINLOCK(kafscmd_attention_lock);
-static int kafscmd_die;
-
-/*****************************************************************************/
 /*
- * AFS Cache Manager kernel thread
+ * CB.CallBack operation type
  */
-static int kafscmd(void *arg)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	struct rxrpc_call *call;
-	_SRXAFSCM_xxxx_t func;
-	int die;
-
-	printk(KERN_INFO "kAFS: Started kafscmd %d\n", current->pid);
-
-	daemonize("kafscmd");
-
-	complete(&kafscmd_alive);
-
-	/* loop around looking for things to attend to */
-	do {
-		if (list_empty(&kafscmd_attention_list)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			add_wait_queue(&kafscmd_sleepq, &myself);
-
-			for (;;) {
-				set_current_state(TASK_INTERRUPTIBLE);
-				if (!list_empty(&kafscmd_attention_list) ||
-				    signal_pending(current) ||
-				    kafscmd_die)
-					break;
-
-				schedule();
-			}
-
-			remove_wait_queue(&kafscmd_sleepq, &myself);
-			set_current_state(TASK_RUNNING);
-		}
-
-		die = kafscmd_die;
-
-		/* dequeue the next call requiring attention */
-		call = NULL;
-		spin_lock(&kafscmd_attention_lock);
-
-		if (!list_empty(&kafscmd_attention_list)) {
-			call = list_entry(kafscmd_attention_list.next,
-					  struct rxrpc_call,
-					  app_attn_link);
-			list_del_init(&call->app_attn_link);
-			die = 0;
-		}
-
-		spin_unlock(&kafscmd_attention_lock);
-
-		if (call) {
-			/* act upon it */
-			_debug("@@@ Begin Attend Call %p", call);
-
-			func = call->app_user;
-			if (func)
-				func(call);
-
-			rxrpc_put_call(call);
-
-			_debug("@@@ End Attend Call %p", call);
-		}
-
-	} while(!die);
-
-	/* and that's all */
-	complete_and_exit(&kafscmd_dead, 0);
-
-} /* end kafscmd() */
+static const struct afs_call_type afs_SRXCBCallBack = {
+	.name		= "CB.CallBack",
+	.deliver	= afs_deliver_cb_callback,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_cm_destructor,
+};
 
-/*****************************************************************************/
 /*
- * handle a call coming in to the cache manager
- * - if I want to keep the call, I must increment its usage count
- * - the return value will be negated and passed back in an abort packet if
- *   non-zero
- * - serialised by virtue of there only being one krxiod
+ * CB.InitCallBackState operation type
  */
-static int afscm_new_call(struct rxrpc_call *call)
-{
-	_enter("%p{cid=%u u=%d}",
-	       call, ntohl(call->call_id), atomic_read(&call->usage));
-
-	rxrpc_get_call(call);
-
-	/* add to my current call list */
-	spin_lock(&afscm_calls_lock);
-	list_add(&call->app_link,&afscm_calls);
-	spin_unlock(&afscm_calls_lock);
-
-	_leave(" = 0");
-	return 0;
-
-} /* end afscm_new_call() */
+static const struct afs_call_type afs_SRXCBInitCallBackState = {
+	.name		= "CB.InitCallBackState",
+	.deliver	= afs_deliver_cb_init_call_back_state,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_cm_destructor,
+};
 
-/*****************************************************************************/
 /*
- * queue on the kafscmd queue for attention
+ * CB.InitCallBackState3 operation type
  */
-static void afscm_attention(struct rxrpc_call *call)
-{
-	_enter("%p{cid=%u u=%d}",
-	       call, ntohl(call->call_id), atomic_read(&call->usage));
-
-	spin_lock(&kafscmd_attention_lock);
-
-	if (list_empty(&call->app_attn_link)) {
-		list_add_tail(&call->app_attn_link, &kafscmd_attention_list);
-		rxrpc_get_call(call);
-	}
-
-	spin_unlock(&kafscmd_attention_lock);
-
-	wake_up(&kafscmd_sleepq);
-
-	_leave(" {u=%d}", atomic_read(&call->usage));
-} /* end afscm_attention() */
+static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
+	.name		= "CB.InitCallBackState3",
+	.deliver	= afs_deliver_cb_init_call_back_state3,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_cm_destructor,
+};
 
-/*****************************************************************************/
 /*
- * handle my call being aborted
- * - clean up, dequeue and put my ref to the call
+ * CB.Probe operation type
  */
-static void afscm_error(struct rxrpc_call *call)
-{
-	int removed;
-
-	_enter("%p{est=%s ac=%u er=%d}",
-	       call,
-	       rxrpc_call_error_states[call->app_err_state],
-	       call->app_abort_code,
-	       call->app_errno);
-
-	spin_lock(&kafscmd_attention_lock);
-
-	if (list_empty(&call->app_attn_link)) {
-		list_add_tail(&call->app_attn_link, &kafscmd_attention_list);
-		rxrpc_get_call(call);
-	}
-
-	spin_unlock(&kafscmd_attention_lock);
-
-	removed = 0;
-	spin_lock(&afscm_calls_lock);
-	if (!list_empty(&call->app_link)) {
-		list_del_init(&call->app_link);
-		removed = 1;
-	}
-	spin_unlock(&afscm_calls_lock);
-
-	if (removed)
-		rxrpc_put_call(call);
-
-	wake_up(&kafscmd_sleepq);
+static const struct afs_call_type afs_SRXCBProbe = {
+	.name		= "CB.Probe",
+	.deliver	= afs_deliver_cb_probe,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_cm_destructor,
+};
 
-	_leave("");
-} /* end afscm_error() */
+/*
+ * CB.GetCapabilities operation type
+ */
+static const struct afs_call_type afs_SRXCBGetCapabilites = {
+	.name		= "CB.GetCapabilities",
+	.deliver	= afs_deliver_cb_get_capabilities,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_cm_destructor,
+};
 
-/*****************************************************************************/
 /*
- * map afs abort codes to/from Linux error codes
- * - called with call->lock held
+ * route an incoming cache manager call
+ * - return T if supported, F if not
  */
-static void afscm_aemap(struct rxrpc_call *call)
+bool afs_cm_incoming_call(struct afs_call *call)
 {
-	switch (call->app_err_state) {
-	case RXRPC_ESTATE_LOCAL_ABORT:
-		call->app_abort_code = -call->app_errno;
-		break;
-	case RXRPC_ESTATE_PEER_ABORT:
-		call->app_errno = -ECONNABORTED;
-		break;
+	u32 operation_id = ntohl(call->operation_ID);
+
+	_enter("{CB.OP %u}", operation_id);
+
+	switch (operation_id) {
+	case CBCallBack:
+		call->type = &afs_SRXCBCallBack;
+		return true;
+	case CBInitCallBackState:
+		call->type = &afs_SRXCBInitCallBackState;
+		return true;
+	case CBInitCallBackState3:
+		call->type = &afs_SRXCBInitCallBackState3;
+		return true;
+	case CBProbe:
+		call->type = &afs_SRXCBProbe;
+		return true;
+	case CBGetCapabilities:
+		call->type = &afs_SRXCBGetCapabilites;
+		return true;
 	default:
-		break;
+		return false;
 	}
-} /* end afscm_aemap() */
+}
 
-/*****************************************************************************/
 /*
- * start the cache manager service if not already started
+ * clean up a cache manager call
  */
-int afscm_start(void)
+static void afs_cm_destructor(struct afs_call *call)
 {
-	int ret;
-
-	down_write(&afscm_sem);
-	if (!afscm_usage) {
-		ret = kernel_thread(kafscmd, NULL, 0);
-		if (ret < 0)
-			goto out;
-
-		wait_for_completion(&kafscmd_alive);
-
-		ret = rxrpc_add_service(afs_transport, &AFSCM_service);
-		if (ret < 0)
-			goto kill;
-
-		afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
-					afs_mntpt_expiry_timeout * HZ);
-	}
-
-	afscm_usage++;
-	up_write(&afscm_sem);
-
-	return 0;
-
- kill:
-	kafscmd_die = 1;
-	wake_up(&kafscmd_sleepq);
-	wait_for_completion(&kafscmd_dead);
-
- out:
-	up_write(&afscm_sem);
-	return ret;
+	_enter("");
 
-} /* end afscm_start() */
+	afs_put_server(call->server);
+	call->server = NULL;
+	kfree(call->buffer);
+	call->buffer = NULL;
+}
 
-/*****************************************************************************/
 /*
- * stop the cache manager service
+ * allow the fileserver to see if the cache manager is still alive
  */
-void afscm_stop(void)
+static void SRXAFSCB_CallBack(struct work_struct *work)
 {
-	struct rxrpc_call *call;
+	struct afs_call *call = container_of(work, struct afs_call, work);
 
-	down_write(&afscm_sem);
+	_enter("");
 
-	BUG_ON(afscm_usage == 0);
-	afscm_usage--;
+	/* be sure to send the reply *before* attempting to spam the AFS server
+	 * with FSFetchStatus requests on the vnodes with broken callbacks lest
+	 * the AFS server get into a vicious cycle of trying to break further
+	 * callbacks because it hadn't received completion of the CBCallBack op
+	 * yet */
+	afs_send_empty_reply(call);
 
-	if (afscm_usage == 0) {
-		/* don't want more incoming calls */
-		rxrpc_del_service(afs_transport, &AFSCM_service);
-
-		/* abort any calls I've still got open (the afscm_error() will
-		 * dequeue them) */
-		spin_lock(&afscm_calls_lock);
-		while (!list_empty(&afscm_calls)) {
-			call = list_entry(afscm_calls.next,
-					  struct rxrpc_call,
-					  app_link);
+	afs_break_callbacks(call->server, call->count, call->request);
+	_leave("");
+}
 
-			list_del_init(&call->app_link);
-			rxrpc_get_call(call);
-			spin_unlock(&afscm_calls_lock);
+/*
+ * deliver request data to a CB.CallBack call
+ */
+static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
+				   bool last)
+{
+	struct afs_callback *cb;
+	struct afs_server *server;
+	struct in_addr addr;
+	__be32 *bp;
+	u32 tmp;
+	int ret, loop;
+
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+	switch (call->unmarshall) {
+	case 0:
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the FID array and its count in two steps */
+	case 1:
+		_debug("extract FID count");
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-			rxrpc_call_abort(call, -ESRCH); /* abort, dequeue and
-							 * put */
+		call->count = ntohl(call->tmp);
+		_debug("FID count: %u", call->count);
+		if (call->count > AFSCBMAX)
+			return -EBADMSG;
+
+		call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
+		if (!call->buffer)
+			return -ENOMEM;
+		call->offset = 0;
+		call->unmarshall++;
+
+	case 2:
+		_debug("extract FID array");
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       call->count * 3 * 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-			_debug("nuking active call %08x.%d",
-			       ntohl(call->conn->conn_id),
-			       ntohl(call->call_id));
-			rxrpc_put_call(call);
-			rxrpc_put_call(call);
+		_debug("unmarshall FID array");
+		call->request = kcalloc(call->count,
+					sizeof(struct afs_callback),
+					GFP_KERNEL);
+		if (!call->request)
+			return -ENOMEM;
+
+		cb = call->request;
+		bp = call->buffer;
+		for (loop = call->count; loop > 0; loop--, cb++) {
+			cb->fid.vid	= ntohl(*bp++);
+			cb->fid.vnode	= ntohl(*bp++);
+			cb->fid.unique	= ntohl(*bp++);
+			cb->type	= AFSCM_CB_UNTYPED;
+		}
 
-			spin_lock(&afscm_calls_lock);
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the callback array and its count in two steps */
+	case 3:
+		_debug("extract CB count");
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
 		}
-		spin_unlock(&afscm_calls_lock);
 
-		/* get rid of my daemon */
-		kafscmd_die = 1;
-		wake_up(&kafscmd_sleepq);
-		wait_for_completion(&kafscmd_dead);
+		tmp = ntohl(call->tmp);
+		_debug("CB count: %u", tmp);
+		if (tmp != call->count && tmp != 0)
+			return -EBADMSG;
+		call->offset = 0;
+		call->unmarshall++;
+		if (tmp == 0)
+			goto empty_cb_array;
+
+	case 4:
+		_debug("extract CB array");
+		ret = afs_extract_data(call, skb, last, call->request,
+				       call->count * 3 * 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-		/* dispose of any calls waiting for attention */
-		spin_lock(&kafscmd_attention_lock);
-		while (!list_empty(&kafscmd_attention_list)) {
-			call = list_entry(kafscmd_attention_list.next,
-					  struct rxrpc_call,
-					  app_attn_link);
+		_debug("unmarshall CB array");
+		cb = call->request;
+		bp = call->buffer;
+		for (loop = call->count; loop > 0; loop--, cb++) {
+			cb->version	= ntohl(*bp++);
+			cb->expiry	= ntohl(*bp++);
+			cb->type	= ntohl(*bp++);
+		}
 
-			list_del_init(&call->app_attn_link);
-			spin_unlock(&kafscmd_attention_lock);
+	empty_cb_array:
+		call->offset = 0;
+		call->unmarshall++;
 
-			rxrpc_put_call(call);
+	case 5:
+		_debug("trailer");
+		if (skb->len != 0)
+			return -EBADMSG;
+		break;
+	}
 
-			spin_lock(&kafscmd_attention_lock);
-		}
-		spin_unlock(&kafscmd_attention_lock);
+	if (!last)
+		return 0;
 
-		afs_kafstimod_del_timer(&afs_mntpt_expiry_timer);
-	}
+	call->state = AFS_CALL_REPLYING;
 
-	up_write(&afscm_sem);
+	/* we'll need the file server record as that tells us which set of
+	 * vnodes to operate upon */
+	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
+	server = afs_find_server(&addr);
+	if (!server)
+		return -ENOTCONN;
+	call->server = server;
 
-} /* end afscm_stop() */
+	INIT_WORK(&call->work, SRXAFSCB_CallBack);
+	schedule_work(&call->work);
+	return 0;
+}
 
-/*****************************************************************************/
 /*
- * handle the fileserver breaking a set of callbacks
+ * allow the fileserver to request callback state (re-)initialisation
  */
-static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
+static void SRXAFSCB_InitCallBackState(struct work_struct *work)
 {
-	struct afs_server *server;
-	size_t count, qty, tmp;
-	int ret = 0, removed;
-
-	_enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]);
-
-	server = afs_server_get_from_peer(call->conn->peer);
-
-	switch (call->app_call_state) {
-		/* we've received the last packet
-		 * - drain all the data from the call and send the reply
-		 */
-	case RXRPC_CSTATE_SRVR_GOT_ARGS:
-		ret = -EBADMSG;
-		qty = call->app_ready_qty;
-		if (qty < 8 || qty > 50 * (6 * 4) + 8)
-			break;
-
-		{
-			struct afs_callback *cb, *pcb;
-			int loop;
-			__be32 *fp, *bp;
-
-			fp = rxrpc_call_alloc_scratch(call, qty);
-
-			/* drag the entire argument block out to the scratch
-			 * space */
-			ret = rxrpc_call_read_data(call, fp, qty, 0);
-			if (ret < 0)
-				break;
-
-			/* and unmarshall the parameter block */
-			ret = -EBADMSG;
-			count = ntohl(*fp++);
-			if (count>AFSCBMAX ||
-			    (count * (3 * 4) + 8 != qty &&
-			     count * (6 * 4) + 8 != qty))
-				break;
-
-			bp = fp + count*3;
-			tmp = ntohl(*bp++);
-			if (tmp > 0 && tmp != count)
-				break;
-			if (tmp == 0)
-				bp = NULL;
-
-			pcb = cb = rxrpc_call_alloc_scratch_s(
-				call, struct afs_callback);
-
-			for (loop = count - 1; loop >= 0; loop--) {
-				pcb->fid.vid	= ntohl(*fp++);
-				pcb->fid.vnode	= ntohl(*fp++);
-				pcb->fid.unique	= ntohl(*fp++);
-				if (bp) {
-					pcb->version	= ntohl(*bp++);
-					pcb->expiry	= ntohl(*bp++);
-					pcb->type	= ntohl(*bp++);
-				}
-				else {
-					pcb->version	= 0;
-					pcb->expiry	= 0;
-					pcb->type	= AFSCM_CB_UNTYPED;
-				}
-				pcb++;
-			}
-
-			/* invoke the actual service routine */
-			ret = SRXAFSCM_CallBack(server, count, cb);
-			if (ret < 0)
-				break;
-		}
+	struct afs_call *call = container_of(work, struct afs_call, work);
 
-		/* send the reply */
-		ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET,
-					    GFP_KERNEL, 0, &count);
-		if (ret < 0)
-			break;
-		break;
-
-		/* operation complete */
-	case RXRPC_CSTATE_COMPLETE:
-		call->app_user = NULL;
-		removed = 0;
-		spin_lock(&afscm_calls_lock);
-		if (!list_empty(&call->app_link)) {
-			list_del_init(&call->app_link);
-			removed = 1;
-		}
-		spin_unlock(&afscm_calls_lock);
+	_enter("{%p}", call->server);
 
-		if (removed)
-			rxrpc_put_call(call);
-		break;
+	afs_init_callback_state(call->server);
+	afs_send_empty_reply(call);
+	_leave("");
+}
 
-		/* operation terminated on error */
-	case RXRPC_CSTATE_ERROR:
-		call->app_user = NULL;
-		break;
+/*
+ * deliver request data to a CB.InitCallBackState call
+ */
+static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
+					       struct sk_buff *skb,
+					       bool last)
+{
+	struct afs_server *server;
+	struct in_addr addr;
 
-	default:
-		break;
-	}
+	_enter(",{%u},%d", skb->len, last);
 
-	if (ret < 0)
-		rxrpc_call_abort(call, ret);
+	if (skb->len > 0)
+		return -EBADMSG;
+	if (!last)
+		return 0;
 
-	afs_put_server(server);
+	/* no unmarshalling required */
+	call->state = AFS_CALL_REPLYING;
 
-	_leave(" = %d", ret);
+	/* we'll need the file server record as that tells us which set of
+	 * vnodes to operate upon */
+	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
+	server = afs_find_server(&addr);
+	if (!server)
+		return -ENOTCONN;
+	call->server = server;
 
-} /* end _SRXAFSCM_CallBack() */
+	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
+	schedule_work(&call->work);
+	return 0;
+}
 
-/*****************************************************************************/
 /*
- * handle the fileserver asking us to initialise our callback state
+ * deliver request data to a CB.InitCallBackState3 call
  */
-static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
+static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
+						struct sk_buff *skb,
+						bool last)
 {
 	struct afs_server *server;
-	size_t count;
-	int ret = 0, removed;
+	struct in_addr addr;
 
-	_enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]);
+	_enter(",{%u},%d", skb->len, last);
 
-	server = afs_server_get_from_peer(call->conn->peer);
+	if (!last)
+		return 0;
 
-	switch (call->app_call_state) {
-		/* we've received the last packet - drain all the data from the
-		 * call */
-	case RXRPC_CSTATE_SRVR_GOT_ARGS:
-		/* shouldn't be any args */
-		ret = -EBADMSG;
-		break;
-
-		/* send the reply when asked for it */
-	case RXRPC_CSTATE_SRVR_SND_REPLY:
-		/* invoke the actual service routine */
-		ret = SRXAFSCM_InitCallBackState(server);
-		if (ret < 0)
-			break;
-
-		ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET,
-					    GFP_KERNEL, 0, &count);
-		if (ret < 0)
-			break;
-		break;
+	/* no unmarshalling required */
+	call->state = AFS_CALL_REPLYING;
 
-		/* operation complete */
-	case RXRPC_CSTATE_COMPLETE:
-		call->app_user = NULL;
-		removed = 0;
-		spin_lock(&afscm_calls_lock);
-		if (!list_empty(&call->app_link)) {
-			list_del_init(&call->app_link);
-			removed = 1;
-		}
-		spin_unlock(&afscm_calls_lock);
+	/* we'll need the file server record as that tells us which set of
+	 * vnodes to operate upon */
+	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
+	server = afs_find_server(&addr);
+	if (!server)
+		return -ENOTCONN;
+	call->server = server;
 
-		if (removed)
-			rxrpc_put_call(call);
-		break;
-
-		/* operation terminated on error */
-	case RXRPC_CSTATE_ERROR:
-		call->app_user = NULL;
-		break;
-
-	default:
-		break;
-	}
-
-	if (ret < 0)
-		rxrpc_call_abort(call, ret);
-
-	afs_put_server(server);
+	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
+	schedule_work(&call->work);
+	return 0;
+}
 
-	_leave(" = %d", ret);
+/*
+ * allow the fileserver to see if the cache manager is still alive
+ */
+static void SRXAFSCB_Probe(struct work_struct *work)
+{
+	struct afs_call *call = container_of(work, struct afs_call, work);
 
-} /* end _SRXAFSCM_InitCallBackState() */
+	_enter("");
+	afs_send_empty_reply(call);
+	_leave("");
+}
 
-/*****************************************************************************/
 /*
- * handle a probe from a fileserver
+ * deliver request data to a CB.Probe call
  */
-static void _SRXAFSCM_Probe(struct rxrpc_call *call)
+static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
+				bool last)
 {
-	struct afs_server *server;
-	size_t count;
-	int ret = 0, removed;
-
-	_enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]);
+	_enter(",{%u},%d", skb->len, last);
 
-	server = afs_server_get_from_peer(call->conn->peer);
+	if (skb->len > 0)
+		return -EBADMSG;
+	if (!last)
+		return 0;
 
-	switch (call->app_call_state) {
-		/* we've received the last packet - drain all the data from the
-		 * call */
-	case RXRPC_CSTATE_SRVR_GOT_ARGS:
-		/* shouldn't be any args */
-		ret = -EBADMSG;
-		break;
+	/* no unmarshalling required */
+	call->state = AFS_CALL_REPLYING;
 
-		/* send the reply when asked for it */
-	case RXRPC_CSTATE_SRVR_SND_REPLY:
-		/* invoke the actual service routine */
-		ret = SRXAFSCM_Probe(server);
-		if (ret < 0)
-			break;
-
-		ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET,
-					    GFP_KERNEL, 0, &count);
-		if (ret < 0)
-			break;
-		break;
+	INIT_WORK(&call->work, SRXAFSCB_Probe);
+	schedule_work(&call->work);
+	return 0;
+}
 
-		/* operation complete */
-	case RXRPC_CSTATE_COMPLETE:
-		call->app_user = NULL;
-		removed = 0;
-		spin_lock(&afscm_calls_lock);
-		if (!list_empty(&call->app_link)) {
-			list_del_init(&call->app_link);
-			removed = 1;
+/*
+ * allow the fileserver to ask about the cache manager's capabilities
+ */
+static void SRXAFSCB_GetCapabilities(struct work_struct *work)
+{
+	struct afs_interface *ifs;
+	struct afs_call *call = container_of(work, struct afs_call, work);
+	int loop, nifs;
+
+	struct {
+		struct /* InterfaceAddr */ {
+			__be32 nifs;
+			__be32 uuid[11];
+			__be32 ifaddr[32];
+			__be32 netmask[32];
+			__be32 mtu[32];
+		} ia;
+		struct /* Capabilities */ {
+			__be32 capcount;
+			__be32 caps[1];
+		} cap;
+	} reply;
+
+	_enter("");
+
+	nifs = 0;
+	ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
+	if (ifs) {
+		nifs = afs_get_ipv4_interfaces(ifs, 32, false);
+		if (nifs < 0) {
+			kfree(ifs);
+			ifs = NULL;
+			nifs = 0;
 		}
-		spin_unlock(&afscm_calls_lock);
+	}
 
-		if (removed)
-			rxrpc_put_call(call);
-		break;
+	memset(&reply, 0, sizeof(reply));
+	reply.ia.nifs = htonl(nifs);
+
+	reply.ia.uuid[0] = htonl(afs_uuid.time_low);
+	reply.ia.uuid[1] = htonl(afs_uuid.time_mid);
+	reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version);
+	reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
+	reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
+	for (loop = 0; loop < 6; loop++)
+		reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
+
+	if (ifs) {
+		for (loop = 0; loop < nifs; loop++) {
+			reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
+			reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
+			reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
+		}
+		kfree(ifs);
+	}
 
-		/* operation terminated on error */
-	case RXRPC_CSTATE_ERROR:
-		call->app_user = NULL;
-		break;
+	reply.cap.capcount = htonl(1);
+	reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
+	afs_send_simple_reply(call, &reply, sizeof(reply));
 
-	default:
-		break;
-	}
+	_leave("");
+}
 
-	if (ret < 0)
-		rxrpc_call_abort(call, ret);
+/*
+ * deliver request data to a CB.GetCapabilities call
+ */
+static int afs_deliver_cb_get_capabilities(struct afs_call *call,
+					   struct sk_buff *skb, bool last)
+{
+	_enter(",{%u},%d", skb->len, last);
 
-	afs_put_server(server);
+	if (skb->len > 0)
+		return -EBADMSG;
+	if (!last)
+		return 0;
 
-	_leave(" = %d", ret);
+	/* no unmarshalling required */
+	call->state = AFS_CALL_REPLYING;
 
-} /* end _SRXAFSCM_Probe() */
+	INIT_WORK(&call->work, SRXAFSCB_GetCapabilities);
+	schedule_work(&call->work);
+	return 0;
+}
diff --git a/fs/afs/cmservice.h b/fs/afs/cmservice.h
deleted file mode 100644
index af8d4d6..0000000
--- a/fs/afs/cmservice.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* cmservice.h: AFS Cache Manager Service declarations
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_CMSERVICE_H
-#define _LINUX_AFS_CMSERVICE_H
-
-#include <rxrpc/transport.h>
-#include "types.h"
-
-/* cache manager start/stop */
-extern int afscm_start(void);
-extern void afscm_stop(void);
-
-/* cache manager server functions */
-extern int SRXAFSCM_InitCallBackState(struct afs_server *server);
-extern int SRXAFSCM_CallBack(struct afs_server *server,
-			     size_t count,
-			     struct afs_callback callbacks[]);
-extern int SRXAFSCM_Probe(struct afs_server *server);
-
-#endif /* _LINUX_AFS_CMSERVICE_H */
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index b6dc2eb..0c1e902 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -15,45 +15,53 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
-#include "vnode.h"
-#include "volume.h"
-#include <rxrpc/call.h>
-#include "super.h"
+#include <linux/ctype.h>
 #include "internal.h"
 
-static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
-				     struct nameidata *nd);
+static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
+				 struct nameidata *nd);
 static int afs_dir_open(struct inode *inode, struct file *file);
-static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
+static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
 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,
+static void afs_d_release(struct dentry *dentry);
+static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
 				  loff_t fpos, u64 ino, unsigned dtype);
+static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
+		      struct nameidata *nd);
+static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static int afs_rmdir(struct inode *dir, struct dentry *dentry);
+static int afs_unlink(struct inode *dir, struct dentry *dentry);
+static int afs_link(struct dentry *from, struct inode *dir,
+		    struct dentry *dentry);
+static int afs_symlink(struct inode *dir, struct dentry *dentry,
+		       const char *content);
+static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		      struct inode *new_dir, struct dentry *new_dentry);
 
 const struct file_operations afs_dir_file_operations = {
 	.open		= afs_dir_open,
-	.readdir	= afs_dir_readdir,
+	.release	= afs_release,
+	.readdir	= afs_readdir,
 };
 
 const struct inode_operations afs_dir_inode_operations = {
-	.lookup		= afs_dir_lookup,
+	.create		= afs_create,
+	.lookup		= afs_lookup,
+	.link		= afs_link,
+	.unlink		= afs_unlink,
+	.symlink	= afs_symlink,
+	.mkdir		= afs_mkdir,
+	.rmdir		= afs_rmdir,
+	.rename		= afs_rename,
+	.permission	= afs_permission,
 	.getattr	= afs_inode_getattr,
-#if 0 /* TODO */
-	.create		= afs_dir_create,
-	.link		= afs_dir_link,
-	.unlink		= afs_dir_unlink,
-	.symlink	= afs_dir_symlink,
-	.mkdir		= afs_dir_mkdir,
-	.rmdir		= afs_dir_rmdir,
-	.mknod		= afs_dir_mknod,
-	.rename		= afs_dir_rename,
-#endif
 };
 
 static struct dentry_operations afs_fs_dentry_operations = {
 	.d_revalidate	= afs_d_revalidate,
 	.d_delete	= afs_d_delete,
+	.d_release	= afs_d_release,
 };
 
 #define AFS_DIR_HASHTBL_SIZE	128
@@ -105,14 +113,13 @@ struct afs_dir_page {
 	union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
 };
 
-struct afs_dir_lookup_cookie {
+struct afs_lookup_cookie {
 	struct afs_fid	fid;
 	const char	*name;
 	size_t		nlen;
 	int		found;
 };
 
-/*****************************************************************************/
 /*
  * check that a directory page is valid
  */
@@ -128,9 +135,10 @@ #if 0
 	if (qty == 0)
 		goto error;
 
-	if (page->index==0 && qty!=ntohs(dbuf->blocks[0].pagehdr.npages)) {
+	if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
 		printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
-		       __FUNCTION__,dir->i_ino,qty,ntohs(dbuf->blocks[0].pagehdr.npages));
+		       __FUNCTION__, dir->i_ino, qty,
+		       ntohs(dbuf->blocks[0].pagehdr.npages));
 		goto error;
 	}
 #endif
@@ -157,13 +165,11 @@ #endif
 	SetPageChecked(page);
 	return;
 
- error:
+error:
 	SetPageChecked(page);
 	SetPageError(page);
+}
 
-} /* end afs_dir_check_page() */
-
-/*****************************************************************************/
 /*
  * discard a page cached in the pagecache
  */
@@ -171,25 +177,24 @@ static inline void afs_dir_put_page(stru
 {
 	kunmap(page);
 	page_cache_release(page);
+}
 
-} /* end afs_dir_put_page() */
-
-/*****************************************************************************/
 /*
  * get a page into the pagecache
  */
-static struct page *afs_dir_get_page(struct inode *dir, unsigned long index)
+static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
+				     struct key *key)
 {
 	struct page *page;
+	struct file file = {
+		.private_data = key,
+	};
 
 	_enter("{%lu},%lu", dir->i_ino, index);
 
-	page = read_mapping_page(dir->i_mapping, index, NULL);
+	page = read_mapping_page(dir->i_mapping, index, &file);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
-		if (!PageUptodate(page))
-			goto fail;
 		if (!PageChecked(page))
 			afs_dir_check_page(dir, page);
 		if (PageError(page))
@@ -197,12 +202,12 @@ static struct page *afs_dir_get_page(str
 	}
 	return page;
 
- fail:
+fail:
 	afs_dir_put_page(page);
+	_leave(" = -EIO");
 	return ERR_PTR(-EIO);
-} /* end afs_dir_get_page() */
+}
 
-/*****************************************************************************/
 /*
  * open an AFS directory file
  */
@@ -213,15 +218,12 @@ static int afs_dir_open(struct inode *in
 	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)
+	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
 		return -ENOENT;
 
-	_leave(" = 0");
-	return 0;
+	return afs_open(inode, file);
+}
 
-} /* end afs_dir_open() */
-
-/*****************************************************************************/
 /*
  * deal with one block in an AFS directory
  */
@@ -250,7 +252,7 @@ static int afs_dir_iterate_block(unsigne
 		/* skip entries marked unused in the bitmap */
 		if (!(block->pagehdr.bitmap[offset / 8] &
 		      (1 << (offset % 8)))) {
-			_debug("ENT[%Zu.%u]: unused\n",
+			_debug("ENT[%Zu.%u]: unused",
 			       blkoff / sizeof(union afs_dir_block), offset);
 			if (offset >= curr)
 				*fpos = blkoff +
@@ -264,7 +266,7 @@ static int afs_dir_iterate_block(unsigne
 			       sizeof(*block) -
 			       offset * sizeof(union afs_dirent));
 
-		_debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n",
+		_debug("ENT[%Zu.%u]: %s %Zu \"%s\"",
 		       blkoff / sizeof(union afs_dir_block), offset,
 		       (offset < curr ? "skip" : "fill"),
 		       nlen, dire->u.name);
@@ -274,7 +276,7 @@ static int afs_dir_iterate_block(unsigne
 			if (next >= AFS_DIRENT_PER_BLOCK) {
 				_debug("ENT[%Zu.%u]:"
 				       " %u travelled beyond end dir block"
-				       " (len %u/%Zu)\n",
+				       " (len %u/%Zu)",
 				       blkoff / sizeof(union afs_dir_block),
 				       offset, next, tmp, nlen);
 				return -EIO;
@@ -282,13 +284,13 @@ static int afs_dir_iterate_block(unsigne
 			if (!(block->pagehdr.bitmap[next / 8] &
 			      (1 << (next % 8)))) {
 				_debug("ENT[%Zu.%u]:"
-				       " %u unmarked extension (len %u/%Zu)\n",
+				       " %u unmarked extension (len %u/%Zu)",
 				       blkoff / sizeof(union afs_dir_block),
 				       offset, next, tmp, nlen);
 				return -EIO;
 			}
 
-			_debug("ENT[%Zu.%u]: ext %u/%Zu\n",
+			_debug("ENT[%Zu.%u]: ext %u/%Zu",
 			       blkoff / sizeof(union afs_dir_block),
 			       next, tmp, nlen);
 			next++;
@@ -304,7 +306,7 @@ static int afs_dir_iterate_block(unsigne
 			      nlen,
 			      blkoff + offset * sizeof(union afs_dirent),
 			      ntohl(dire->u.vnode),
-			      filldir == afs_dir_lookup_filldir ?
+			      filldir == afs_lookup_filldir ?
 			      ntohl(dire->u.unique) : DT_UNKNOWN);
 		if (ret < 0) {
 			_leave(" = 0 [full]");
@@ -316,16 +318,15 @@ static int afs_dir_iterate_block(unsigne
 
 	_leave(" = 1 [more]");
 	return 1;
-} /* end afs_dir_iterate_block() */
+}
 
-/*****************************************************************************/
 /*
- * read an AFS directory
+ * iterate through the data blob that lists the contents of an AFS directory
  */
 static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
-			   filldir_t filldir)
+			   filldir_t filldir, struct key *key)
 {
-	union afs_dir_block	*dblock;
+	union afs_dir_block *dblock;
 	struct afs_dir_page *dbuf;
 	struct page *page;
 	unsigned blkoff, limit;
@@ -333,7 +334,7 @@ static int afs_dir_iterate(struct inode 
 
 	_enter("{%lu},%u,,", dir->i_ino, *fpos);
 
-	if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
 		_leave(" = -ESTALE");
 		return -ESTALE;
 	}
@@ -348,7 +349,7 @@ static int afs_dir_iterate(struct inode 
 		blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1);
 
 		/* fetch the appropriate page from the directory */
-		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE);
+		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
 		if (IS_ERR(page)) {
 			ret = PTR_ERR(page);
 			break;
@@ -377,43 +378,50 @@ static int afs_dir_iterate(struct inode 
 		ret = 0;
 	}
 
- out:
+out:
 	_leave(" = %d", ret);
 	return ret;
-} /* end afs_dir_iterate() */
+}
 
-/*****************************************************************************/
 /*
  * read an AFS directory
  */
-static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
+static int afs_readdir(struct file *file, void *cookie, filldir_t filldir)
 {
 	unsigned fpos;
 	int ret;
 
-	_enter("{%Ld,{%lu}}", file->f_pos, file->f_path.dentry->d_inode->i_ino);
+	_enter("{%Ld,{%lu}}",
+	       file->f_pos, file->f_path.dentry->d_inode->i_ino);
+
+	ASSERT(file->private_data != NULL);
 
 	fpos = file->f_pos;
-	ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, cookie, filldir);
+	ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos,
+			      cookie, filldir, file->private_data);
 	file->f_pos = fpos;
 
 	_leave(" = %d", ret);
 	return ret;
-} /* end afs_dir_readdir() */
+}
 
-/*****************************************************************************/
 /*
  * search the directory for a name
  * - if afs_dir_iterate_block() spots this function, it'll pass the FID
  *   uniquifier through dtype
  */
-static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
-				  loff_t fpos, u64 ino, unsigned dtype)
+static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
+			      loff_t fpos, u64 ino, unsigned dtype)
 {
-	struct afs_dir_lookup_cookie *cookie = _cookie;
+	struct afs_lookup_cookie *cookie = _cookie;
+
+	_enter("{%s,%Zu},%s,%u,,%llu,%u",
+	       cookie->name, cookie->nlen, name, nlen,
+	       (unsigned long long) ino, dtype);
 
-	_enter("{%s,%Zu},%s,%u,,%lu,%u",
-	       cookie->name, cookie->nlen, name, nlen, ino, dtype);
+	/* insanity checks first */
+	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
+	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
 
 	if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) {
 		_leave(" = 0 [no]");
@@ -426,216 +434,254 @@ static int afs_dir_lookup_filldir(void *
 
 	_leave(" = -1 [found]");
 	return -1;
-} /* end afs_dir_lookup_filldir() */
+}
 
-/*****************************************************************************/
 /*
- * look up an entry in a directory
+ * do a lookup in a directory
+ * - just returns the FID the dentry name maps to if found
  */
-static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
-				     struct nameidata *nd)
+static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
+			 struct afs_fid *fid, struct key *key)
 {
-	struct afs_dir_lookup_cookie cookie;
+	struct afs_lookup_cookie cookie;
 	struct afs_super_info *as;
+	unsigned fpos;
+	int ret;
+
+	_enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name);
+
+	as = dir->i_sb->s_fs_info;
+
+	/* search the directory */
+	cookie.name	= dentry->d_name.name;
+	cookie.nlen	= dentry->d_name.len;
+	cookie.fid.vid	= as->volume->vid;
+	cookie.found	= 0;
+
+	fpos = 0;
+	ret = afs_dir_iterate(dir, &fpos, &cookie, afs_lookup_filldir,
+			      key);
+	if (ret < 0) {
+		_leave(" = %d [iter]", ret);
+		return ret;
+	}
+
+	ret = -ENOENT;
+	if (!cookie.found) {
+		_leave(" = -ENOENT [not found]");
+		return -ENOENT;
+	}
+
+	*fid = cookie.fid;
+	_leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique);
+	return 0;
+}
+
+/*
+ * look up an entry in a directory
+ */
+static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
+				 struct nameidata *nd)
+{
 	struct afs_vnode *vnode;
+	struct afs_fid fid;
 	struct inode *inode;
-	unsigned fpos;
+	struct key *key;
 	int ret;
 
-	_enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name);
+	vnode = AFS_FS_I(dir);
 
-	/* insanity checks first */
-	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
-	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
+	_enter("{%x:%d},%p{%s},",
+	       vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
+
+	ASSERTCMP(dentry->d_inode, ==, NULL);
 
 	if (dentry->d_name.len > 255) {
 		_leave(" = -ENAMETOOLONG");
 		return ERR_PTR(-ENAMETOOLONG);
 	}
 
-	vnode = AFS_FS_I(dir);
-	if (vnode->flags & AFS_VNODE_DELETED) {
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
 		_leave(" = -ESTALE");
 		return ERR_PTR(-ESTALE);
 	}
 
-	as = dir->i_sb->s_fs_info;
-
-	/* search the directory */
-	cookie.name	= dentry->d_name.name;
-	cookie.nlen	= dentry->d_name.len;
-	cookie.fid.vid	= as->volume->vid;
-	cookie.found	= 0;
+	key = afs_request_key(vnode->volume->cell);
+	if (IS_ERR(key)) {
+		_leave(" = %ld [key]", PTR_ERR(key));
+		return ERR_PTR(PTR_ERR(key));
+	}
 
-	fpos = 0;
-	ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir);
+	ret = afs_validate(vnode, key);
 	if (ret < 0) {
-		_leave(" = %d", ret);
+		key_put(key);
+		_leave(" = %d [val]", ret);
 		return ERR_PTR(ret);
 	}
 
-	ret = -ENOENT;
-	if (!cookie.found) {
-		_leave(" = %d", ret);
+	ret = afs_do_lookup(dir, dentry, &fid, key);
+	if (ret < 0) {
+		key_put(key);
+		if (ret == -ENOENT) {
+			d_add(dentry, NULL);
+			_leave(" = NULL [negative]");
+			return NULL;
+		}
+		_leave(" = %d [do]", ret);
 		return ERR_PTR(ret);
 	}
+	dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version;
 
 	/* instantiate the dentry */
-	ret = afs_iget(dir->i_sb, &cookie.fid, &inode);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ERR_PTR(ret);
+	inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL);
+	key_put(key);
+	if (IS_ERR(inode)) {
+		_leave(" = %ld", PTR_ERR(inode));
+		return ERR_PTR(PTR_ERR(inode));
 	}
 
 	dentry->d_op = &afs_fs_dentry_operations;
-	dentry->d_fsdata = (void *) (unsigned long) vnode->status.version;
 
 	d_add(dentry, inode);
 	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }",
-	       cookie.fid.vnode,
-	       cookie.fid.unique,
+	       fid.vnode,
+	       fid.unique,
 	       dentry->d_inode->i_ino,
 	       dentry->d_inode->i_version);
 
 	return NULL;
-} /* end afs_dir_lookup() */
+}
 
-/*****************************************************************************/
 /*
  * check that a dentry lookup hit has found a valid entry
  * - NOTE! the hit can be a negative hit too, so we can't assume we have an
  *   inode
- * (derived from nfs_lookup_revalidate)
  */
 static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-	struct afs_dir_lookup_cookie cookie;
+	struct afs_vnode *vnode, *dir;
+	struct afs_fid fid;
 	struct dentry *parent;
-	struct inode *inode, *dir;
-	unsigned fpos;
+	struct key *key;
+	void *dir_version;
 	int ret;
 
-	_enter("{sb=%p n=%s},", dentry->d_sb, dentry->d_name.name);
+	vnode = AFS_FS_I(dentry->d_inode);
 
-	/* lock down the parent dentry so we can peer at it */
-	parent = dget_parent(dentry->d_parent);
+	if (dentry->d_inode)
+		_enter("{v={%x:%u} n=%s fl=%lx},",
+		       vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+		       vnode->flags);
+	else
+		_enter("{neg n=%s}", dentry->d_name.name);
 
-	dir = parent->d_inode;
-	inode = dentry->d_inode;
+	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
+	if (IS_ERR(key))
+		key = NULL;
 
-	/* handle a negative dentry */
-	if (!inode)
+	/* lock down the parent dentry so we can peer at it */
+	parent = dget_parent(dentry);
+	if (!parent->d_inode)
 		goto out_bad;
 
-	/* handle a bad inode */
-	if (is_bad_inode(inode)) {
-		printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
-		       dentry->d_parent->d_name.name, dentry->d_name.name);
-		goto out_bad;
-	}
+	dir = AFS_FS_I(parent->d_inode);
 
-	/* force a full look up if the parent directory changed since last the
-	 * server was consulted
-	 * - otherwise this inode must still exist, even if the inode details
-	 *   themselves have changed
-	 */
-	if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED)
-		afs_vnode_fetch_status(AFS_FS_I(dir));
+	/* validate the parent directory */
+	if (test_bit(AFS_VNODE_MODIFIED, &dir->flags))
+		afs_validate(dir, key);
 
-	if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
 		_debug("%s: parent dir deleted", dentry->d_name.name);
 		goto out_bad;
 	}
 
-	if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) {
-		_debug("%s: file already deleted", dentry->d_name.name);
-		goto out_bad;
-	}
-
-	if ((unsigned long) dentry->d_fsdata !=
-	    (unsigned long) AFS_FS_I(dir)->status.version) {
-		_debug("%s: parent changed %lu -> %u",
-		       dentry->d_name.name,
-		       (unsigned long) dentry->d_fsdata,
-		       (unsigned) AFS_FS_I(dir)->status.version);
+	dir_version = (void *) (unsigned long) dir->status.data_version;
+	if (dentry->d_fsdata == dir_version)
+		goto out_valid; /* the dir contents are unchanged */
 
-		/* search the directory for this vnode */
-		cookie.name	= dentry->d_name.name;
-		cookie.nlen	= dentry->d_name.len;
-		cookie.fid.vid	= AFS_FS_I(inode)->volume->vid;
-		cookie.found	= 0;
+	_debug("dir modified");
 
-		fpos = 0;
-		ret = afs_dir_iterate(dir, &fpos, &cookie,
-				      afs_dir_lookup_filldir);
-		if (ret < 0) {
-			_debug("failed to iterate dir %s: %d",
-			       parent->d_name.name, ret);
+	/* search the directory for this vnode */
+	ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
+	switch (ret) {
+	case 0:
+		/* the filename maps to something */
+		if (!dentry->d_inode)
+			goto out_bad;
+		if (is_bad_inode(dentry->d_inode)) {
+			printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
+			       parent->d_name.name, dentry->d_name.name);
 			goto out_bad;
-		}
-
-		if (!cookie.found) {
-			_debug("%s: dirent not found", dentry->d_name.name);
-			goto not_found;
 		}
 
 		/* if the vnode ID has changed, then the dirent points to a
 		 * different file */
-		if (cookie.fid.vnode != AFS_FS_I(inode)->fid.vnode) {
-			_debug("%s: dirent changed", dentry->d_name.name);
+		if (fid.vnode != vnode->fid.vnode) {
+			_debug("%s: dirent changed [%u != %u]",
+			       dentry->d_name.name, fid.vnode,
+			       vnode->fid.vnode);
 			goto not_found;
 		}
 
 		/* if the vnode ID uniqifier has changed, then the file has
-		 * been deleted */
-		if (cookie.fid.unique != AFS_FS_I(inode)->fid.unique) {
+		 * been deleted and replaced, and the original vnode ID has
+		 * been reused */
+		if (fid.unique != vnode->fid.unique) {
 			_debug("%s: file deleted (uq %u -> %u I:%lu)",
-			       dentry->d_name.name,
-			       cookie.fid.unique,
-			       AFS_FS_I(inode)->fid.unique,
-			       inode->i_version);
-			spin_lock(&AFS_FS_I(inode)->lock);
-			AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED;
-			spin_unlock(&AFS_FS_I(inode)->lock);
-			invalidate_remote_inode(inode);
-			goto out_bad;
+			       dentry->d_name.name, fid.unique,
+			       vnode->fid.unique, dentry->d_inode->i_version);
+			spin_lock(&vnode->lock);
+			set_bit(AFS_VNODE_DELETED, &vnode->flags);
+			spin_unlock(&vnode->lock);
+			goto not_found;
 		}
+		goto out_valid;
 
-		dentry->d_fsdata =
-			(void *) (unsigned long) AFS_FS_I(dir)->status.version;
+	case -ENOENT:
+		/* the filename is unknown */
+		_debug("%s: dirent not found", dentry->d_name.name);
+		if (dentry->d_inode)
+			goto not_found;
+		goto out_valid;
+
+	default:
+		_debug("failed to iterate dir %s: %d",
+		       parent->d_name.name, ret);
+		goto out_bad;
 	}
 
- out_valid:
+out_valid:
+	dentry->d_fsdata = dir_version;
+out_skip:
 	dput(parent);
+	key_put(key);
 	_leave(" = 1 [valid]");
 	return 1;
 
 	/* the dirent, if it exists, now points to a different vnode */
- not_found:
+not_found:
 	spin_lock(&dentry->d_lock);
 	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
 	spin_unlock(&dentry->d_lock);
 
- out_bad:
-	if (inode) {
+out_bad:
+	if (dentry->d_inode) {
 		/* don't unhash if we have submounts */
 		if (have_submounts(dentry))
-			goto out_valid;
+			goto out_skip;
 	}
 
-	shrink_dcache_parent(dentry);
-
 	_debug("dropping dentry %s/%s",
-	       dentry->d_parent->d_name.name, dentry->d_name.name);
+	       parent->d_name.name, dentry->d_name.name);
+	shrink_dcache_parent(dentry);
 	d_drop(dentry);
-
 	dput(parent);
+	key_put(key);
 
 	_leave(" = 0 [bad]");
 	return 0;
-} /* end afs_d_revalidate() */
+}
 
-/*****************************************************************************/
 /*
  * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
  * sleep)
@@ -649,15 +695,444 @@ static int afs_d_delete(struct dentry *d
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
 		goto zap;
 
-	if (dentry->d_inode) {
-		if (AFS_FS_I(dentry->d_inode)->flags & AFS_VNODE_DELETED)
+	if (dentry->d_inode &&
+	    test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags))
 			goto zap;
-	}
 
 	_leave(" = 0 [keep]");
 	return 0;
 
- zap:
+zap:
 	_leave(" = 1 [zap]");
 	return 1;
-} /* end afs_d_delete() */
+}
+
+/*
+ * handle dentry release
+ */
+static void afs_d_release(struct dentry *dentry)
+{
+	_enter("%s", dentry->d_name.name);
+}
+
+/*
+ * create a directory on an AFS filesystem
+ */
+static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct afs_file_status status;
+	struct afs_callback cb;
+	struct afs_server *server;
+	struct afs_vnode *dvnode, *vnode;
+	struct afs_fid fid;
+	struct inode *inode;
+	struct key *key;
+	int ret;
+
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%s},%o",
+	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	mode |= S_IFDIR;
+	ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
+			       mode, &fid, &status, &cb, &server);
+	if (ret < 0)
+		goto mkdir_error;
+
+	inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
+	if (IS_ERR(inode)) {
+		/* ENOMEM at a really inconvenient time - just abandon the new
+		 * directory on the server */
+		ret = PTR_ERR(inode);
+		goto iget_error;
+	}
+
+	/* apply the status report we've got for the new vnode */
+	vnode = AFS_FS_I(inode);
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+	afs_vnode_finalise_status_update(vnode, server);
+	afs_put_server(server);
+
+	d_instantiate(dentry, inode);
+	if (d_unhashed(dentry)) {
+		_debug("not hashed");
+		d_rehash(dentry);
+	}
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+iget_error:
+	afs_put_server(server);
+mkdir_error:
+	key_put(key);
+error:
+	d_drop(dentry);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * remove a directory from an AFS filesystem
+ */
+static int afs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	struct afs_vnode *dvnode, *vnode;
+	struct key *key;
+	int ret;
+
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%s}",
+	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, true);
+	if (ret < 0)
+		goto rmdir_error;
+
+	if (dentry->d_inode) {
+		vnode = AFS_FS_I(dentry->d_inode);
+		clear_nlink(&vnode->vfs_inode);
+		set_bit(AFS_VNODE_DELETED, &vnode->flags);
+		afs_discard_callback_on_delete(vnode);
+	}
+
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+rmdir_error:
+	key_put(key);
+error:
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * remove a file from an AFS filesystem
+ */
+static int afs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct afs_vnode *dvnode, *vnode;
+	struct key *key;
+	int ret;
+
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%s}",
+	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	if (dentry->d_inode) {
+		vnode = AFS_FS_I(dentry->d_inode);
+
+		/* make sure we have a callback promise on the victim */
+		ret = afs_validate(vnode, key);
+		if (ret < 0)
+			goto error;
+	}
+
+	ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, false);
+	if (ret < 0)
+		goto remove_error;
+
+	if (dentry->d_inode) {
+		/* if the file wasn't deleted due to excess hard links, the
+		 * fileserver will break the callback promise on the file - if
+		 * it had one - before it returns to us, and if it was deleted,
+		 * it won't
+		 *
+		 * however, if we didn't have a callback promise outstanding,
+		 * or it was outstanding on a different server, then it won't
+		 * break it either...
+		 */
+		vnode = AFS_FS_I(dentry->d_inode);
+		if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
+			_debug("AFS_VNODE_DELETED");
+		if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
+			_debug("AFS_VNODE_CB_BROKEN");
+		set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+		ret = afs_validate(vnode, key);
+		_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
+	}
+
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+remove_error:
+	key_put(key);
+error:
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * create a regular file on an AFS filesystem
+ */
+static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
+		      struct nameidata *nd)
+{
+	struct afs_file_status status;
+	struct afs_callback cb;
+	struct afs_server *server;
+	struct afs_vnode *dvnode, *vnode;
+	struct afs_fid fid;
+	struct inode *inode;
+	struct key *key;
+	int ret;
+
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%s},%o,",
+	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	mode |= S_IFREG;
+	ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
+			       mode, &fid, &status, &cb, &server);
+	if (ret < 0)
+		goto create_error;
+
+	inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
+	if (IS_ERR(inode)) {
+		/* ENOMEM at a really inconvenient time - just abandon the new
+		 * directory on the server */
+		ret = PTR_ERR(inode);
+		goto iget_error;
+	}
+
+	/* apply the status report we've got for the new vnode */
+	vnode = AFS_FS_I(inode);
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+	afs_vnode_finalise_status_update(vnode, server);
+	afs_put_server(server);
+
+	d_instantiate(dentry, inode);
+	if (d_unhashed(dentry)) {
+		_debug("not hashed");
+		d_rehash(dentry);
+	}
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+iget_error:
+	afs_put_server(server);
+create_error:
+	key_put(key);
+error:
+	d_drop(dentry);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * create a hard link between files in an AFS filesystem
+ */
+static int afs_link(struct dentry *from, struct inode *dir,
+		    struct dentry *dentry)
+{
+	struct afs_vnode *dvnode, *vnode;
+	struct key *key;
+	int ret;
+
+	vnode = AFS_FS_I(from->d_inode);
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%x:%d},{%s}",
+	       vnode->fid.vid, vnode->fid.vnode,
+	       dvnode->fid.vid, dvnode->fid.vnode,
+	       dentry->d_name.name);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	ret = afs_vnode_link(dvnode, vnode, key, dentry->d_name.name);
+	if (ret < 0)
+		goto link_error;
+
+	atomic_inc(&vnode->vfs_inode.i_count);
+	d_instantiate(dentry, &vnode->vfs_inode);
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+link_error:
+	key_put(key);
+error:
+	d_drop(dentry);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * create a symlink in an AFS filesystem
+ */
+static int afs_symlink(struct inode *dir, struct dentry *dentry,
+		       const char *content)
+{
+	struct afs_file_status status;
+	struct afs_server *server;
+	struct afs_vnode *dvnode, *vnode;
+	struct afs_fid fid;
+	struct inode *inode;
+	struct key *key;
+	int ret;
+
+	dvnode = AFS_FS_I(dir);
+
+	_enter("{%x:%d},{%s},%s",
+	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
+	       content);
+
+	ret = -ENAMETOOLONG;
+	if (dentry->d_name.len > 255)
+		goto error;
+
+	ret = -EINVAL;
+	if (strlen(content) > 1023)
+		goto error;
+
+	key = afs_request_key(dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content,
+				&fid, &status, &server);
+	if (ret < 0)
+		goto create_error;
+
+	inode = afs_iget(dir->i_sb, key, &fid, &status, NULL);
+	if (IS_ERR(inode)) {
+		/* ENOMEM at a really inconvenient time - just abandon the new
+		 * directory on the server */
+		ret = PTR_ERR(inode);
+		goto iget_error;
+	}
+
+	/* apply the status report we've got for the new vnode */
+	vnode = AFS_FS_I(inode);
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+	afs_vnode_finalise_status_update(vnode, server);
+	afs_put_server(server);
+
+	d_instantiate(dentry, inode);
+	if (d_unhashed(dentry)) {
+		_debug("not hashed");
+		d_rehash(dentry);
+	}
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+iget_error:
+	afs_put_server(server);
+create_error:
+	key_put(key);
+error:
+	d_drop(dentry);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * rename a file in an AFS filesystem and/or move it between directories
+ */
+static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		      struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
+	struct key *key;
+	int ret;
+
+	vnode = AFS_FS_I(old_dentry->d_inode);
+	orig_dvnode = AFS_FS_I(old_dir);
+	new_dvnode = AFS_FS_I(new_dir);
+
+	_enter("{%x:%d},{%x:%d},{%x:%d},{%s}",
+	       orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
+	       vnode->fid.vid, vnode->fid.vnode,
+	       new_dvnode->fid.vid, new_dvnode->fid.vnode,
+	       new_dentry->d_name.name);
+
+	ret = -ENAMETOOLONG;
+	if (new_dentry->d_name.len > 255)
+		goto error;
+
+	key = afs_request_key(orig_dvnode->volume->cell);
+	if (IS_ERR(key)) {
+		ret = PTR_ERR(key);
+		goto error;
+	}
+
+	ret = afs_vnode_rename(orig_dvnode, new_dvnode, key,
+			       old_dentry->d_name.name,
+			       new_dentry->d_name.name);
+	if (ret < 0)
+		goto rename_error;
+	key_put(key);
+	_leave(" = 0");
+	return 0;
+
+rename_error:
+	key_put(key);
+error:
+	d_drop(new_dentry);
+	_leave(" = %d", ret);
+	return ret;
+}
diff --git a/fs/afs/errors.h b/fs/afs/errors.h
deleted file mode 100644
index 574d94a..0000000
--- a/fs/afs/errors.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* errors.h: AFS abort/error codes
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_ERRORS_H
-#define _LINUX_AFS_ERRORS_H
-
-#include "types.h"
-
-/* file server abort codes */
-typedef enum {
-	VSALVAGE	= 101,	/* volume needs salvaging */
-	VNOVNODE	= 102,	/* no such file/dir (vnode) */
-	VNOVOL		= 103,	/* no such volume or volume unavailable */
-	VVOLEXISTS	= 104,	/* volume name already exists */
-	VNOSERVICE	= 105,	/* volume not currently in service */
-	VOFFLINE	= 106,	/* volume is currently offline (more info available [VVL-spec]) */
-	VONLINE		= 107,	/* volume is already online */
-	VDISKFULL	= 108,	/* disk partition is full */
-	VOVERQUOTA	= 109,	/* volume's maximum quota exceeded */
-	VBUSY		= 110,	/* volume is temporarily unavailable */
-	VMOVED		= 111,	/* volume moved to new server - ask this FS where */
-} afs_rxfs_abort_t;
-
-extern int afs_abort_to_error(int abortcode);
-
-#endif /* _LINUX_AFS_ERRORS_H */
diff --git a/fs/afs/file.c b/fs/afs/file.c
index b176345..ae25649 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -1,6 +1,6 @@
-/* file.c: AFS filesystem file handling
+/* AFS filesystem file handling
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -15,22 +15,25 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include "volume.h"
-#include "vnode.h"
-#include <rxrpc/call.h>
 #include "internal.h"
 
-#if 0
-static int afs_file_open(struct inode *inode, struct file *file);
-static int afs_file_release(struct inode *inode, struct file *file);
-#endif
-
 static int afs_file_readpage(struct file *file, struct page *page);
 static void afs_file_invalidatepage(struct page *page, unsigned long offset);
 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
 
+const struct file_operations afs_file_operations = {
+	.open		= afs_open,
+	.release	= afs_release,
+	.llseek		= generic_file_llseek,
+	.read		= do_sync_read,
+	.aio_read	= generic_file_aio_read,
+	.mmap		= generic_file_readonly_mmap,
+	.sendfile	= generic_file_sendfile,
+};
+
 const struct inode_operations afs_file_inode_operations = {
 	.getattr	= afs_inode_getattr,
+	.permission	= afs_permission,
 };
 
 const struct address_space_operations afs_fs_aops = {
@@ -40,7 +43,48 @@ const struct address_space_operations af
 	.invalidatepage	= afs_file_invalidatepage,
 };
 
-/*****************************************************************************/
+/*
+ * open an AFS file or directory and attach a key to it
+ */
+int afs_open(struct inode *inode, struct file *file)
+{
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+	struct key *key;
+	int ret;
+
+	_enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+
+	key = afs_request_key(vnode->volume->cell);
+	if (IS_ERR(key)) {
+		_leave(" = %ld [key]", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	ret = afs_validate(vnode, key);
+	if (ret < 0) {
+		_leave(" = %d [val]", ret);
+		return ret;
+	}
+
+	file->private_data = key;
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * release an AFS file or directory and discard its key
+ */
+int afs_release(struct inode *inode, struct file *file)
+{
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+
+	_enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+
+	key_put(file->private_data);
+	_leave(" = 0");
+	return 0;
+}
+
 /*
  * deal with notification that a page was read from the cache
  */
@@ -58,10 +102,9 @@ static void afs_file_readpage_read_compl
 		SetPageUptodate(page);
 	unlock_page(page);
 
-} /* end afs_file_readpage_read_complete() */
+}
 #endif
 
-/*****************************************************************************/
 /*
  * deal with notification that a page was written to the cache
  */
@@ -74,41 +117,38 @@ static void afs_file_readpage_write_comp
 	_enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
 	unlock_page(page);
-
-} /* end afs_file_readpage_write_complete() */
+}
 #endif
 
-/*****************************************************************************/
 /*
  * AFS read page from file (or symlink)
  */
 static int afs_file_readpage(struct file *file, struct page *page)
 {
-	struct afs_rxfs_fetch_descriptor desc;
-#ifdef AFS_CACHING_SUPPORT
-	struct cachefs_page *pageio;
-#endif
 	struct afs_vnode *vnode;
 	struct inode *inode;
+	struct key *key;
+	size_t len;
+	off_t offset;
 	int ret;
 
 	inode = page->mapping->host;
 
-	_enter("{%lu},{%lu}", inode->i_ino, page->index);
+	ASSERT(file != NULL);
+	key = file->private_data;
+	ASSERT(key != NULL);
+
+	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 
 	vnode = AFS_FS_I(inode);
 
 	BUG_ON(!PageLocked(page));
 
 	ret = -ESTALE;
-	if (vnode->flags & AFS_VNODE_DELETED)
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
 		goto error;
 
 #ifdef AFS_CACHING_SUPPORT
-	ret = cachefs_page_get_private(page, &pageio, GFP_NOIO);
-	if (ret < 0)
-		goto error;
-
 	/* is it cached? */
 	ret = cachefs_read_or_alloc_page(vnode->cache,
 					 page,
@@ -132,26 +172,19 @@ #endif
 	case -ENOBUFS:
 	case -ENODATA:
 	default:
-		desc.fid	= vnode->fid;
-		desc.offset	= page->index << PAGE_CACHE_SHIFT;
-		desc.size	= min((size_t) (inode->i_size - desc.offset),
-				      (size_t) PAGE_SIZE);
-		desc.buffer	= kmap(page);
-
-		clear_page(desc.buffer);
+		offset = page->index << PAGE_CACHE_SHIFT;
+		len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
 
 		/* read the contents of the file from the server into the
 		 * page */
-		ret = afs_vnode_fetch_data(vnode, &desc);
-		kunmap(page);
+		ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
 		if (ret < 0) {
-			if (ret==-ENOENT) {
+			if (ret == -ENOENT) {
 				_debug("got NOENT from server"
 				       " - marking file deleted and stale");
-				vnode->flags |= AFS_VNODE_DELETED;
+				set_bit(AFS_VNODE_DELETED, &vnode->flags);
 				ret = -ESTALE;
 			}
-
 #ifdef AFS_CACHING_SUPPORT
 			cachefs_uncache_page(vnode->cache, page);
 #endif
@@ -178,16 +211,13 @@ #endif
 	_leave(" = 0");
 	return 0;
 
- error:
+error:
 	SetPageError(page);
 	unlock_page(page);
-
 	_leave(" = %d", ret);
 	return ret;
+}
 
-} /* end afs_file_readpage() */
-
-/*****************************************************************************/
 /*
  * get a page cookie for the specified page
  */
@@ -202,10 +232,9 @@ int afs_cache_get_page_cookie(struct pag
 
 	_leave(" = %d", ret);
 	return ret;
-} /* end afs_cache_get_page_cookie() */
+}
 #endif
 
-/*****************************************************************************/
 /*
  * invalidate part or all of a page
  */
@@ -240,9 +269,8 @@ #endif
 	}
 
 	_leave(" = %d", ret);
-} /* end afs_file_invalidatepage() */
+}
 
-/*****************************************************************************/
 /*
  * release a page and cleanup its private data
  */
@@ -267,4 +295,4 @@ #endif
 
 	_leave(" = 0");
 	return 0;
-} /* end afs_file_releasepage() */
+}
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 61bc371..e54e6c2 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -1,6 +1,6 @@
-/* fsclient.c: AFS File Server client stubs
+/* AFS File Server client stubs
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -11,827 +11,928 @@
 
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include "fsclient.h"
-#include "cmservice.h"
-#include "vnode.h"
-#include "server.h"
-#include "errors.h"
+#include <linux/circ_buf.h>
 #include "internal.h"
+#include "afs_fs.h"
 
-#define FSFETCHSTATUS		132	/* AFS Fetch file status */
-#define FSFETCHDATA		130	/* AFS Fetch file data */
-#define FSGIVEUPCALLBACKS	147	/* AFS Discard callback promises */
-#define FSGETVOLUMEINFO		148	/* AFS Get root volume information */
-#define FSGETROOTVOLUME		151	/* AFS Get root volume name */
-#define FSLOOKUP		161	/* AFS lookup file in directory */
-
-/*****************************************************************************/
 /*
- * map afs abort codes to/from Linux error codes
- * - called with call->lock held
+ * decode an AFSFid block
  */
-static void afs_rxfs_aemap(struct rxrpc_call *call)
+static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
 {
-	switch (call->app_err_state) {
-	case RXRPC_ESTATE_LOCAL_ABORT:
-		call->app_abort_code = -call->app_errno;
-		break;
-	case RXRPC_ESTATE_PEER_ABORT:
-		call->app_errno = afs_abort_to_error(call->app_abort_code);
-		break;
-	default:
-		break;
-	}
-} /* end afs_rxfs_aemap() */
+	const __be32 *bp = *_bp;
+
+	fid->vid		= ntohl(*bp++);
+	fid->vnode		= ntohl(*bp++);
+	fid->unique		= ntohl(*bp++);
+	*_bp = bp;
+}
 
-/*****************************************************************************/
 /*
- * get the root volume name from a fileserver
- * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ * decode an AFSFetchStatus block
  */
-#if 0
-int afs_rxfs_get_root_volume(struct afs_server *server,
-			     char *buf, size_t *buflen)
+static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
+				      struct afs_file_status *status,
+				      struct afs_vnode *vnode)
 {
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[2];
-	size_t sent;
-	int ret;
-	u32 param[1];
+	const __be32 *bp = *_bp;
+	umode_t mode;
+	u64 data_version, size;
+	u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
+
+#define EXTRACT(DST)				\
+	do {					\
+		u32 x = ntohl(*bp++);		\
+		changed |= DST - x;		\
+		DST = x;			\
+	} while (0)
+
+	status->if_version = ntohl(*bp++);
+	EXTRACT(status->type);
+	EXTRACT(status->nlink);
+	size = ntohl(*bp++);
+	data_version = ntohl(*bp++);
+	EXTRACT(status->author);
+	EXTRACT(status->owner);
+	EXTRACT(status->caller_access); /* call ticket dependent */
+	EXTRACT(status->anon_access);
+	EXTRACT(status->mode);
+	EXTRACT(status->parent.vnode);
+	EXTRACT(status->parent.unique);
+	bp++; /* seg size */
+	status->mtime_client = ntohl(*bp++);
+	status->mtime_server = ntohl(*bp++);
+	EXTRACT(status->group);
+	bp++; /* sync counter */
+	data_version |= (u64) ntohl(*bp++) << 32;
+	bp++; /* lock count */
+	size |= (u64) ntohl(*bp++) << 32;
+	bp++; /* spare 4 */
+	*_bp = bp;
+
+	if (size != status->size) {
+		status->size = size;
+		changed |= true;
+	}
+	status->mode &= S_IALLUGO;
+
+	_debug("vnode time %lx, %lx",
+	       status->mtime_client, status->mtime_server);
+
+	if (vnode) {
+		status->parent.vid = vnode->fid.vid;
+		if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
+			_debug("vnode changed");
+			i_size_write(&vnode->vfs_inode, size);
+			vnode->vfs_inode.i_uid = status->owner;
+			vnode->vfs_inode.i_gid = status->group;
+			vnode->vfs_inode.i_version = vnode->fid.unique;
+			vnode->vfs_inode.i_nlink = status->nlink;
+
+			mode = vnode->vfs_inode.i_mode;
+			mode &= ~S_IALLUGO;
+			mode |= status->mode;
+			barrier();
+			vnode->vfs_inode.i_mode = mode;
+		}
 
-	DECLARE_WAITQUEUE(myself, current);
+		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server;
+		vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime;
+		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime;
+	}
 
-	kenter("%p,%p,%u",server, buf, *buflen);
+	if (status->data_version != data_version) {
+		status->data_version = data_version;
+		if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
+			_debug("vnode modified %llx on {%x:%u}",
+			       (unsigned long long) data_version,
+			       vnode->fid.vid, vnode->fid.vnode);
+			set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
+			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
+		}
+	}
+}
 
-	/* get hold of the fileserver connection */
-	ret = afs_server_get_fsconn(server, &conn);
-	if (ret < 0)
-		goto out;
+/*
+ * decode an AFSCallBack block
+ */
+static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
+{
+	const __be32 *bp = *_bp;
 
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = FSGETROOTVOLUME;
+	vnode->cb_version	= ntohl(*bp++);
+	vnode->cb_expiry	= ntohl(*bp++);
+	vnode->cb_type		= ntohl(*bp++);
+	vnode->cb_expires	= vnode->cb_expiry + get_seconds();
+	*_bp = bp;
+}
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
+				       struct afs_callback *cb)
+{
+	const __be32 *bp = *_bp;
 
-	/* marshall the parameters */
-	param[0] = htonl(FSGETROOTVOLUME);
-
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
-		    signal_pending(current))
-			break;
-		schedule();
-	}
-	set_current_state(TASK_RUNNING);
+	cb->version	= ntohl(*bp++);
+	cb->expiry	= ntohl(*bp++);
+	cb->type	= ntohl(*bp++);
+	*_bp = bp;
+}
 
-	ret = -EINTR;
-	if (signal_pending(current))
-		goto abort;
+/*
+ * decode an AFSVolSync block
+ */
+static void xdr_decode_AFSVolSync(const __be32 **_bp,
+				  struct afs_volsync *volsync)
+{
+	const __be32 *bp = *_bp;
 
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_ERROR:
-		ret = call->app_errno;
-		kdebug("Got Error: %d", ret);
-		goto out_unwait;
+	volsync->creation = ntohl(*bp++);
+	bp++; /* spare2 */
+	bp++; /* spare3 */
+	bp++; /* spare4 */
+	bp++; /* spare5 */
+	bp++; /* spare6 */
+	*_bp = bp;
+}
 
-	case RXRPC_CSTATE_CLNT_GOT_REPLY:
-		/* read the reply */
-		kdebug("Got Reply: qty=%d", call->app_ready_qty);
+/*
+ * deliver reply data to an FS.FetchStatus
+ */
+static int afs_deliver_fs_fetch_status(struct afs_call *call,
+				       struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
 
-		ret = -EBADMSG;
-		if (call->app_ready_qty <= 4)
-			goto abort;
+	_enter(",,%u", last);
 
-		ret = rxrpc_call_read_data(call, NULL, call->app_ready_qty, 0);
-		if (ret < 0)
-			goto abort;
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
 
-#if 0
-		/* unmarshall the reply */
-		bp = buffer;
-		for (loop = 0; loop < 65; loop++)
-			entry->name[loop] = ntohl(*bp++);
-		entry->name[64] = 0;
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
 
-		entry->type = ntohl(*bp++);
-		entry->num_servers = ntohl(*bp++);
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSCallBack(&bp, vnode);
+	if (call->reply2)
+		xdr_decode_AFSVolSync(&bp, call->reply2);
 
-		for (loop = 0; loop < 8; loop++)
-			entry->servers[loop].addr.s_addr = *bp++;
+	_leave(" = 0 [done]");
+	return 0;
+}
 
-		for (loop = 0; loop < 8; loop++)
-			entry->servers[loop].partition = ntohl(*bp++);
+/*
+ * FS.FetchStatus operation type
+ */
+static const struct afs_call_type afs_RXFSFetchStatus = {
+	.name		= "FS.FetchStatus",
+	.deliver	= afs_deliver_fs_fetch_status,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
 
-		for (loop = 0; loop < 8; loop++)
-			entry->servers[loop].flags = ntohl(*bp++);
+/*
+ * fetch the status information for a file
+ */
+int afs_fs_fetch_file_status(struct afs_server *server,
+			     struct key *key,
+			     struct afs_vnode *vnode,
+			     struct afs_volsync *volsync,
+			     const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	__be32 *bp;
 
-		for (loop = 0; loop < 3; loop++)
-			entry->volume_ids[loop] = ntohl(*bp++);
+	_enter(",%x,{%x:%d},,",
+	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
 
-		entry->clone_id = ntohl(*bp++);
-		entry->flags = ntohl(*bp);
-#endif
+	call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
 
-		/* success */
-		ret = 0;
-		goto out_unwait;
+	call->key = key;
+	call->reply = vnode;
+	call->reply2 = volsync;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
 
-	default:
-		BUG();
-	}
+	/* marshall the parameters */
+	bp = call->request;
+	bp[0] = htonl(FSFETCHSTATUS);
+	bp[1] = htonl(vnode->fid.vid);
+	bp[2] = htonl(vnode->fid.vnode);
+	bp[3] = htonl(vnode->fid.unique);
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_fsconn(server, conn);
- out:
-	kleave("");
-	return ret;
-} /* end afs_rxfs_get_root_volume() */
-#endif
-
-/*****************************************************************************/
 /*
- * get information about a volume
+ * deliver reply data to an FS.FetchData
  */
-#if 0
-int afs_rxfs_get_volume_info(struct afs_server *server,
-			     const char *name,
-			     struct afs_volume_info *vinfo)
+static int afs_deliver_fs_fetch_data(struct afs_call *call,
+				     struct sk_buff *skb, bool last)
 {
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[3];
-	size_t sent;
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
+	struct page *page;
+	void *buffer;
 	int ret;
-	u32 param[2], *bp, zero;
 
-	DECLARE_WAITQUEUE(myself, current);
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+	switch (call->unmarshall) {
+	case 0:
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the returned data length */
+	case 1:
+		_debug("extract data length");
+		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-	_enter("%p,%s,%p", server, name, vinfo);
+		call->count = ntohl(call->tmp);
+		_debug("DATA length: %u", call->count);
+		if (call->count > PAGE_SIZE)
+			return -EBADMSG;
+		call->offset = 0;
+		call->unmarshall++;
+
+		if (call->count < PAGE_SIZE) {
+			page = call->reply3;
+			buffer = kmap_atomic(page, KM_USER0);
+			memset(buffer + PAGE_SIZE - call->count, 0,
+			       call->count);
+			kunmap_atomic(buffer, KM_USER0);
+		}
 
-	/* get hold of the fileserver connection */
-	ret = afs_server_get_fsconn(server, &conn);
-	if (ret < 0)
-		goto out;
+		/* extract the returned data */
+	case 2:
+		_debug("extract data");
+		page = call->reply3;
+		buffer = kmap_atomic(page, KM_USER0);
+		ret = afs_extract_data(call, skb, last, buffer, call->count);
+		kunmap_atomic(buffer, KM_USER0);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = FSGETVOLUMEINFO;
+		call->offset = 0;
+		call->unmarshall++;
+
+		/* extract the metadata */
+	case 3:
+		ret = afs_extract_data(call, skb, last, call->buffer,
+				       (21 + 3 + 6) * 4);
+		switch (ret) {
+		case 0:		break;
+		case -EAGAIN:	return 0;
+		default:	return ret;
+		}
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+		bp = call->buffer;
+		xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+		xdr_decode_AFSCallBack(&bp, vnode);
+		if (call->reply2)
+			xdr_decode_AFSVolSync(&bp, call->reply2);
 
-	/* marshall the parameters */
-	piov[1].iov_len = strlen(name);
-	piov[1].iov_base = (char *) name;
-
-	zero = 0;
-	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
-	piov[2].iov_base = &zero;
-
-	param[0] = htonl(FSGETVOLUMEINFO);
-	param[1] = htonl(piov[1].iov_len);
-
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	bp = rxrpc_call_alloc_scratch(call, 64);
-
-	ret = rxrpc_call_read_data(call, bp, 64,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0) {
-		if (ret == -ECONNABORTED) {
-			ret = call->app_errno;
-			goto out_unwait;
-		}
-		goto abort;
+		call->offset = 0;
+		call->unmarshall++;
+
+	case 4:
+		_debug("trailer");
+		if (skb->len != 0)
+			return -EBADMSG;
+		break;
 	}
 
-	/* unmarshall the reply */
-	vinfo->vid = ntohl(*bp++);
-	vinfo->type = ntohl(*bp++);
-
-	vinfo->type_vids[0] = ntohl(*bp++);
-	vinfo->type_vids[1] = ntohl(*bp++);
-	vinfo->type_vids[2] = ntohl(*bp++);
-	vinfo->type_vids[3] = ntohl(*bp++);
-	vinfo->type_vids[4] = ntohl(*bp++);
-
-	vinfo->nservers = ntohl(*bp++);
-	vinfo->servers[0].addr.s_addr = *bp++;
-	vinfo->servers[1].addr.s_addr = *bp++;
-	vinfo->servers[2].addr.s_addr = *bp++;
-	vinfo->servers[3].addr.s_addr = *bp++;
-	vinfo->servers[4].addr.s_addr = *bp++;
-	vinfo->servers[5].addr.s_addr = *bp++;
-	vinfo->servers[6].addr.s_addr = *bp++;
-	vinfo->servers[7].addr.s_addr = *bp++;
-
-	ret = -EBADMSG;
-	if (vinfo->nservers > 8)
-		goto abort;
-
-	/* success */
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_fsconn(server, conn);
- out:
-	_leave("");
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-
-} /* end afs_rxfs_get_volume_info() */
-#endif
-
-/*****************************************************************************/
+	if (!last)
+		return 0;
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
 /*
- * fetch the status information for a file
+ * FS.FetchData operation type
+ */
+static const struct afs_call_type afs_RXFSFetchData = {
+	.name		= "FS.FetchData",
+	.deliver	= afs_deliver_fs_fetch_data,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * fetch data from a file
  */
-int afs_rxfs_fetch_file_status(struct afs_server *server,
-			       struct afs_vnode *vnode,
-			       struct afs_volsync *volsync)
+int afs_fs_fetch_data(struct afs_server *server,
+		      struct key *key,
+		      struct afs_vnode *vnode,
+		      off_t offset, size_t length,
+		      struct page *buffer,
+		      const struct afs_wait_mode *wait_mode)
 {
-	struct afs_server_callslot callslot;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	size_t sent;
-	int ret;
+	struct afs_call *call;
 	__be32 *bp;
 
-	DECLARE_WAITQUEUE(myself, current);
+	_enter("");
 
-	_enter("%p,{%u,%u,%u}",
-	       server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
+	call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
 
-	/* get hold of the fileserver connection */
-	ret = afs_server_request_callslot(server, &callslot);
-	if (ret < 0)
-		goto out;
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap,
-				&call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = FSFETCHSTATUS;
-
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+	call->key = key;
+	call->reply = vnode;
+	call->reply2 = NULL; /* volsync */
+	call->reply3 = buffer;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
 
 	/* marshall the parameters */
-	bp = rxrpc_call_alloc_scratch(call, 16);
-	bp[0] = htonl(FSFETCHSTATUS);
+	bp = call->request;
+	bp[0] = htonl(FSFETCHDATA);
 	bp[1] = htonl(vnode->fid.vid);
 	bp[2] = htonl(vnode->fid.vnode);
 	bp[3] = htonl(vnode->fid.unique);
+	bp[4] = htonl(offset);
+	bp[5] = htonl(length);
 
-	piov[0].iov_len = 16;
-	piov[0].iov_base = bp;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	bp = rxrpc_call_alloc_scratch(call, 120);
-
-	ret = rxrpc_call_read_data(call, bp, 120,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0) {
-		if (ret == -ECONNABORTED) {
-			ret = call->app_errno;
-			goto out_unwait;
-		}
-		goto abort;
-	}
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
-	/* unmarshall the reply */
-	vnode->status.if_version	= ntohl(*bp++);
-	vnode->status.type		= ntohl(*bp++);
-	vnode->status.nlink		= ntohl(*bp++);
-	vnode->status.size		= ntohl(*bp++);
-	vnode->status.version		= ntohl(*bp++);
-	vnode->status.author		= ntohl(*bp++);
-	vnode->status.owner		= ntohl(*bp++);
-	vnode->status.caller_access	= ntohl(*bp++);
-	vnode->status.anon_access	= ntohl(*bp++);
-	vnode->status.mode		= ntohl(*bp++);
-	vnode->status.parent.vid	= vnode->fid.vid;
-	vnode->status.parent.vnode	= ntohl(*bp++);
-	vnode->status.parent.unique	= ntohl(*bp++);
-	bp++; /* seg size */
-	vnode->status.mtime_client	= ntohl(*bp++);
-	vnode->status.mtime_server	= ntohl(*bp++);
-	bp++; /* group */
-	bp++; /* sync counter */
-	vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
-	bp++; /* spare2 */
-	bp++; /* spare3 */
-	bp++; /* spare4 */
+/*
+ * deliver reply data to an FS.GiveUpCallBacks
+ */
+static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
+					    struct sk_buff *skb, bool last)
+{
+	_enter(",{%u},%d", skb->len, last);
 
-	vnode->cb_version		= ntohl(*bp++);
-	vnode->cb_expiry		= ntohl(*bp++);
-	vnode->cb_type			= ntohl(*bp++);
-
-	if (volsync) {
-		volsync->creation	= ntohl(*bp++);
-		bp++; /* spare2 */
-		bp++; /* spare3 */
-		bp++; /* spare4 */
-		bp++; /* spare5 */
-		bp++; /* spare6 */
-	}
+	if (skb->len > 0)
+		return -EBADMSG; /* shouldn't be any reply data */
+	return 0;
+}
 
-	/* success */
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_callslot(server, &callslot);
- out:
-	_leave("");
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-} /* end afs_rxfs_fetch_file_status() */
-
-/*****************************************************************************/
 /*
- * fetch the contents of a file or directory
+ * FS.GiveUpCallBacks operation type
  */
-int afs_rxfs_fetch_file_data(struct afs_server *server,
-			     struct afs_vnode *vnode,
-			     struct afs_rxfs_fetch_descriptor *desc,
-			     struct afs_volsync *volsync)
+static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
+	.name		= "FS.GiveUpCallBacks",
+	.deliver	= afs_deliver_fs_give_up_callbacks,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * give up a set of callbacks
+ * - the callbacks are held in the server->cb_break ring
+ */
+int afs_fs_give_up_callbacks(struct afs_server *server,
+			     const struct afs_wait_mode *wait_mode)
 {
-	struct afs_server_callslot callslot;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	size_t sent;
-	int ret;
-	__be32 *bp;
+	struct afs_call *call;
+	size_t ncallbacks;
+	__be32 *bp, *tp;
+	int loop;
 
-	DECLARE_WAITQUEUE(myself, current);
-
-	_enter("%p,{fid={%u,%u,%u},sz=%Zu,of=%lu}",
-	       server,
-	       desc->fid.vid,
-	       desc->fid.vnode,
-	       desc->fid.unique,
-	       desc->size,
-	       desc->offset);
-
-	/* get hold of the fileserver connection */
-	ret = afs_server_request_callslot(server, &callslot);
-	if (ret < 0)
-		goto out;
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = FSFETCHDATA;
+	ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
+			      ARRAY_SIZE(server->cb_break));
+
+	_enter("{%zu},", ncallbacks);
+
+	if (ncallbacks == 0)
+		return 0;
+	if (ncallbacks > AFSCBMAX)
+		ncallbacks = AFSCBMAX;
+
+	_debug("break %zu callbacks", ncallbacks);
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+	call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
+				   12 + ncallbacks * 6 * 4, 0);
+	if (!call)
+		return -ENOMEM;
+
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
 
 	/* marshall the parameters */
-	bp = rxrpc_call_alloc_scratch(call, 24);
-	bp[0] = htonl(FSFETCHDATA);
-	bp[1] = htonl(desc->fid.vid);
-	bp[2] = htonl(desc->fid.vnode);
-	bp[3] = htonl(desc->fid.unique);
-	bp[4] = htonl(desc->offset);
-	bp[5] = htonl(desc->size);
-
-	piov[0].iov_len = 24;
-	piov[0].iov_base = bp;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the data count to arrive */
-	ret = rxrpc_call_read_data(call, bp, 4, RXRPC_CALL_READ_BLOCK);
-	if (ret < 0)
-		goto read_failed;
-
-	desc->actual = ntohl(bp[0]);
-	if (desc->actual != desc->size) {
-		ret = -EBADMSG;
-		goto abort;
+	bp = call->request;
+	tp = bp + 2 + ncallbacks * 3;
+	*bp++ = htonl(FSGIVEUPCALLBACKS);
+	*bp++ = htonl(ncallbacks);
+	*tp++ = htonl(ncallbacks);
+
+	atomic_sub(ncallbacks, &server->cb_break_n);
+	for (loop = ncallbacks; loop > 0; loop--) {
+		struct afs_callback *cb =
+			&server->cb_break[server->cb_break_tail];
+
+		*bp++ = htonl(cb->fid.vid);
+		*bp++ = htonl(cb->fid.vnode);
+		*bp++ = htonl(cb->fid.unique);
+		*tp++ = htonl(cb->version);
+		*tp++ = htonl(cb->expiry);
+		*tp++ = htonl(cb->type);
+		smp_mb();
+		server->cb_break_tail =
+			(server->cb_break_tail + 1) &
+			(ARRAY_SIZE(server->cb_break) - 1);
 	}
 
-	/* call the app to read the actual data */
-	rxrpc_call_reset_scratch(call);
-
-	ret = rxrpc_call_read_data(call, desc->buffer, desc->actual,
-				   RXRPC_CALL_READ_BLOCK);
-	if (ret < 0)
-		goto read_failed;
-
-	/* wait for the rest of the reply to completely arrive */
-	rxrpc_call_reset_scratch(call);
-	bp = rxrpc_call_alloc_scratch(call, 120);
-
-	ret = rxrpc_call_read_data(call, bp, 120,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0)
-		goto read_failed;
-
-	/* unmarshall the reply */
-	vnode->status.if_version	= ntohl(*bp++);
-	vnode->status.type		= ntohl(*bp++);
-	vnode->status.nlink		= ntohl(*bp++);
-	vnode->status.size		= ntohl(*bp++);
-	vnode->status.version		= ntohl(*bp++);
-	vnode->status.author		= ntohl(*bp++);
-	vnode->status.owner		= ntohl(*bp++);
-	vnode->status.caller_access	= ntohl(*bp++);
-	vnode->status.anon_access	= ntohl(*bp++);
-	vnode->status.mode		= ntohl(*bp++);
-	vnode->status.parent.vid	= desc->fid.vid;
-	vnode->status.parent.vnode	= ntohl(*bp++);
-	vnode->status.parent.unique	= ntohl(*bp++);
-	bp++; /* seg size */
-	vnode->status.mtime_client	= ntohl(*bp++);
-	vnode->status.mtime_server	= ntohl(*bp++);
-	bp++; /* group */
-	bp++; /* sync counter */
-	vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
-	bp++; /* spare2 */
-	bp++; /* spare3 */
-	bp++; /* spare4 */
+	ASSERT(ncallbacks > 0);
+	wake_up_nr(&server->cb_break_waitq, ncallbacks);
 
-	vnode->cb_version		= ntohl(*bp++);
-	vnode->cb_expiry		= ntohl(*bp++);
-	vnode->cb_type			= ntohl(*bp++);
-
-	if (volsync) {
-		volsync->creation	= ntohl(*bp++);
-		bp++; /* spare2 */
-		bp++; /* spare3 */
-		bp++; /* spare4 */
-		bp++; /* spare5 */
-		bp++; /* spare6 */
-	}
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
-	/* success */
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq,&myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_callslot(server, &callslot);
- out:
-	_leave(" = %d", ret);
-	return ret;
-
- read_failed:
-	if (ret == -ECONNABORTED) {
-		ret = call->app_errno;
-		goto out_unwait;
-	}
+/*
+ * deliver reply data to an FS.CreateFile or an FS.MakeDir
+ */
+static int afs_deliver_fs_create_vnode(struct afs_call *call,
+				       struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
+
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
 
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
 
-} /* end afs_rxfs_fetch_file_data() */
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFid(&bp, call->reply2);
+	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSCallBack_raw(&bp, call->reply4);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.CreateFile and FS.MakeDir operation type
+ */
+static const struct afs_call_type afs_RXFSCreateXXXX = {
+	.name		= "FS.CreateXXXX",
+	.deliver	= afs_deliver_fs_create_vnode,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
 
-/*****************************************************************************/
 /*
- * ask the AFS fileserver to discard a callback request on a file
+ * create a file or make a directory
  */
-int afs_rxfs_give_up_callback(struct afs_server *server,
-			      struct afs_vnode *vnode)
+int afs_fs_create(struct afs_server *server,
+		  struct key *key,
+		  struct afs_vnode *vnode,
+		  const char *name,
+		  umode_t mode,
+		  struct afs_fid *newfid,
+		  struct afs_file_status *newstatus,
+		  struct afs_callback *newcb,
+		  const struct afs_wait_mode *wait_mode)
 {
-	struct afs_server_callslot callslot;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	size_t sent;
-	int ret;
+	struct afs_call *call;
+	size_t namesz, reqsz, padsz;
 	__be32 *bp;
 
-	DECLARE_WAITQUEUE(myself, current);
+	_enter("");
 
-	_enter("%p,{%u,%u,%u}",
-	       server, vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
+	namesz = strlen(name);
+	padsz = (4 - (namesz & 3)) & 3;
+	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
 
-	/* get hold of the fileserver connection */
-	ret = afs_server_request_callslot(server, &callslot);
-	if (ret < 0)
-		goto out;
+	call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
+				   (3 + 21 + 21 + 3 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
 
-	/* create a call through that connection */
-	ret = rxrpc_create_call(callslot.conn, NULL, NULL, afs_rxfs_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
+	call->key = key;
+	call->reply = vnode;
+	call->reply2 = newfid;
+	call->reply3 = newstatus;
+	call->reply4 = newcb;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+	*bp++ = htonl(namesz);
+	memcpy(bp, name, namesz);
+	bp = (void *) bp + namesz;
+	if (padsz > 0) {
+		memset(bp, 0, padsz);
+		bp = (void *) bp + padsz;
 	}
-	call->app_opcode = FSGIVEUPCALLBACKS;
+	*bp++ = htonl(AFS_SET_MODE);
+	*bp++ = 0; /* mtime */
+	*bp++ = 0; /* owner */
+	*bp++ = 0; /* group */
+	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
+	*bp++ = 0; /* segment size */
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
-	/* marshall the parameters */
-	bp = rxrpc_call_alloc_scratch(call, (1 + 4 + 4) * 4);
+/*
+ * deliver reply data to an FS.RemoveFile or FS.RemoveDir
+ */
+static int afs_deliver_fs_remove(struct afs_call *call,
+				 struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
 
-	piov[0].iov_len = (1 + 4 + 4) * 4;
-	piov[0].iov_base = bp;
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
 
-	*bp++ = htonl(FSGIVEUPCALLBACKS);
-	*bp++ = htonl(1);
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
+
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.RemoveDir/FS.RemoveFile operation type
+ */
+static const struct afs_call_type afs_RXFSRemoveXXXX = {
+	.name		= "FS.RemoveXXXX",
+	.deliver	= afs_deliver_fs_remove,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * remove a file or directory
+ */
+int afs_fs_remove(struct afs_server *server,
+		  struct key *key,
+		  struct afs_vnode *vnode,
+		  const char *name,
+		  bool isdir,
+		  const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	size_t namesz, reqsz, padsz;
+	__be32 *bp;
+
+	_enter("");
+
+	namesz = strlen(name);
+	padsz = (4 - (namesz & 3)) & 3;
+	reqsz = (5 * 4) + namesz + padsz;
+
+	call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->key = key;
+	call->reply = vnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
 	*bp++ = htonl(vnode->fid.vid);
 	*bp++ = htonl(vnode->fid.vnode);
 	*bp++ = htonl(vnode->fid.unique);
-	*bp++ = htonl(1);
-	*bp++ = htonl(vnode->cb_version);
-	*bp++ = htonl(vnode->cb_expiry);
-	*bp++ = htonl(vnode->cb_type);
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
-		    signal_pending(current))
-			break;
-		schedule();
+	*bp++ = htonl(namesz);
+	memcpy(bp, name, namesz);
+	bp = (void *) bp + namesz;
+	if (padsz > 0) {
+		memset(bp, 0, padsz);
+		bp = (void *) bp + padsz;
 	}
-	set_current_state(TASK_RUNNING);
 
-	ret = -EINTR;
-	if (signal_pending(current))
-		goto abort;
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_ERROR:
-		ret = call->app_errno;
-		goto out_unwait;
+/*
+ * deliver reply data to an FS.Link
+ */
+static int afs_deliver_fs_link(struct afs_call *call,
+			       struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
+	const __be32 *bp;
 
-	case RXRPC_CSTATE_CLNT_GOT_REPLY:
-		ret = 0;
-		goto out_unwait;
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
 
-	default:
-		BUG();
-	}
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
+
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.Link operation type
+ */
+static const struct afs_call_type afs_RXFSLink = {
+	.name		= "FS.Link",
+	.deliver	= afs_deliver_fs_link,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
 
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_callslot(server, &callslot);
- out:
-	_leave("");
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-} /* end afs_rxfs_give_up_callback() */
-
-/*****************************************************************************/
 /*
- * look a filename up in a directory
- * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ * make a hard link
  */
-#if 0
-int afs_rxfs_lookup(struct afs_server *server,
-		    struct afs_vnode *dir,
-		    const char *filename,
-		    struct afs_vnode *vnode,
-		    struct afs_volsync *volsync)
+int afs_fs_link(struct afs_server *server,
+		struct key *key,
+		struct afs_vnode *dvnode,
+		struct afs_vnode *vnode,
+		const char *name,
+		const struct afs_wait_mode *wait_mode)
 {
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[3];
-	size_t sent;
-	int ret;
-	u32 *bp, zero;
+	struct afs_call *call;
+	size_t namesz, reqsz, padsz;
+	__be32 *bp;
 
-	DECLARE_WAITQUEUE(myself, current);
+	_enter("");
 
-	kenter("%p,{%u,%u,%u},%s",
-	       server, fid->vid, fid->vnode, fid->unique, filename);
+	namesz = strlen(name);
+	padsz = (4 - (namesz & 3)) & 3;
+	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
 
-	/* get hold of the fileserver connection */
-	ret = afs_server_get_fsconn(server, &conn);
-	if (ret < 0)
-		goto out;
+	call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
 
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxfs_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
+	call->key = key;
+	call->reply = dvnode;
+	call->reply2 = vnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(FSLINK);
+	*bp++ = htonl(dvnode->fid.vid);
+	*bp++ = htonl(dvnode->fid.vnode);
+	*bp++ = htonl(dvnode->fid.unique);
+	*bp++ = htonl(namesz);
+	memcpy(bp, name, namesz);
+	bp = (void *) bp + namesz;
+	if (padsz > 0) {
+		memset(bp, 0, padsz);
+		bp = (void *) bp + padsz;
 	}
-	call->app_opcode = FSLOOKUP;
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * deliver reply data to an FS.Symlink
+ */
+static int afs_deliver_fs_symlink(struct afs_call *call,
+				  struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *vnode = call->reply;
+	const __be32 *bp;
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq,&myself);
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
+
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFid(&bp, call->reply2);
+	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
+	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.Symlink operation type
+ */
+static const struct afs_call_type afs_RXFSSymlink = {
+	.name		= "FS.Symlink",
+	.deliver	= afs_deliver_fs_symlink,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * create a symbolic link
+ */
+int afs_fs_symlink(struct afs_server *server,
+		   struct key *key,
+		   struct afs_vnode *vnode,
+		   const char *name,
+		   const char *contents,
+		   struct afs_fid *newfid,
+		   struct afs_file_status *newstatus,
+		   const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
+	__be32 *bp;
+
+	_enter("");
+
+	namesz = strlen(name);
+	padsz = (4 - (namesz & 3)) & 3;
+
+	c_namesz = strlen(contents);
+	c_padsz = (4 - (c_namesz & 3)) & 3;
+
+	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
+
+	call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
+				   (3 + 21 + 21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->key = key;
+	call->reply = vnode;
+	call->reply2 = newfid;
+	call->reply3 = newstatus;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
 
 	/* marshall the parameters */
-	bp = rxrpc_call_alloc_scratch(call, 20);
-
-	zero = 0;
-
-	piov[0].iov_len = 20;
-	piov[0].iov_base = bp;
-	piov[1].iov_len = strlen(filename);
-	piov[1].iov_base = (char *) filename;
-	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
-	piov[2].iov_base = &zero;
-
-	*bp++ = htonl(FSLOOKUP);
-	*bp++ = htonl(dirfid->vid);
-	*bp++ = htonl(dirfid->vnode);
-	*bp++ = htonl(dirfid->unique);
-	*bp++ = htonl(piov[1].iov_len);
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	bp = rxrpc_call_alloc_scratch(call, 220);
-
-	ret = rxrpc_call_read_data(call, bp, 220,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0) {
-		if (ret == -ECONNABORTED) {
-			ret = call->app_errno;
-			goto out_unwait;
-		}
-		goto abort;
+	bp = call->request;
+	*bp++ = htonl(FSSYMLINK);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+	*bp++ = htonl(namesz);
+	memcpy(bp, name, namesz);
+	bp = (void *) bp + namesz;
+	if (padsz > 0) {
+		memset(bp, 0, padsz);
+		bp = (void *) bp + padsz;
 	}
+	*bp++ = htonl(c_namesz);
+	memcpy(bp, contents, c_namesz);
+	bp = (void *) bp + c_namesz;
+	if (c_padsz > 0) {
+		memset(bp, 0, c_padsz);
+		bp = (void *) bp + c_padsz;
+	}
+	*bp++ = htonl(AFS_SET_MODE);
+	*bp++ = 0; /* mtime */
+	*bp++ = 0; /* owner */
+	*bp++ = 0; /* group */
+	*bp++ = htonl(S_IRWXUGO); /* unix mode */
+	*bp++ = 0; /* segment size */
 
-	/* unmarshall the reply */
-	fid->vid		= ntohl(*bp++);
-	fid->vnode		= ntohl(*bp++);
-	fid->unique		= ntohl(*bp++);
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
 
-	vnode->status.if_version	= ntohl(*bp++);
-	vnode->status.type		= ntohl(*bp++);
-	vnode->status.nlink		= ntohl(*bp++);
-	vnode->status.size		= ntohl(*bp++);
-	vnode->status.version		= ntohl(*bp++);
-	vnode->status.author		= ntohl(*bp++);
-	vnode->status.owner		= ntohl(*bp++);
-	vnode->status.caller_access	= ntohl(*bp++);
-	vnode->status.anon_access	= ntohl(*bp++);
-	vnode->status.mode		= ntohl(*bp++);
-	vnode->status.parent.vid	= dirfid->vid;
-	vnode->status.parent.vnode	= ntohl(*bp++);
-	vnode->status.parent.unique	= ntohl(*bp++);
-	bp++; /* seg size */
-	vnode->status.mtime_client	= ntohl(*bp++);
-	vnode->status.mtime_server	= ntohl(*bp++);
-	bp++; /* group */
-	bp++; /* sync counter */
-	vnode->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
-	bp++; /* spare2 */
-	bp++; /* spare3 */
-	bp++; /* spare4 */
+/*
+ * deliver reply data to an FS.Rename
+ */
+static int afs_deliver_fs_rename(struct afs_call *call,
+				  struct sk_buff *skb, bool last)
+{
+	struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
+	const __be32 *bp;
 
-	dir->status.if_version		= ntohl(*bp++);
-	dir->status.type		= ntohl(*bp++);
-	dir->status.nlink		= ntohl(*bp++);
-	dir->status.size		= ntohl(*bp++);
-	dir->status.version		= ntohl(*bp++);
-	dir->status.author		= ntohl(*bp++);
-	dir->status.owner		= ntohl(*bp++);
-	dir->status.caller_access	= ntohl(*bp++);
-	dir->status.anon_access		= ntohl(*bp++);
-	dir->status.mode		= ntohl(*bp++);
-	dir->status.parent.vid		= dirfid->vid;
-	dir->status.parent.vnode	= ntohl(*bp++);
-	dir->status.parent.unique	= ntohl(*bp++);
-	bp++; /* seg size */
-	dir->status.mtime_client	= ntohl(*bp++);
-	dir->status.mtime_server	= ntohl(*bp++);
-	bp++; /* group */
-	bp++; /* sync counter */
-	dir->status.version |= ((unsigned long long) ntohl(*bp++)) << 32;
-	bp++; /* spare2 */
-	bp++; /* spare3 */
-	bp++; /* spare4 */
+	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
+
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
+
+	/* unmarshall the reply once we've received all of it */
+	bp = call->buffer;
+	xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
+	if (new_dvnode != orig_dvnode)
+		xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
+	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+	_leave(" = 0 [done]");
+	return 0;
+}
+
+/*
+ * FS.Rename operation type
+ */
+static const struct afs_call_type afs_RXFSRename = {
+	.name		= "FS.Rename",
+	.deliver	= afs_deliver_fs_rename,
+	.abort_to_error	= afs_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
+
+/*
+ * create a symbolic link
+ */
+int afs_fs_rename(struct afs_server *server,
+		  struct key *key,
+		  struct afs_vnode *orig_dvnode,
+		  const char *orig_name,
+		  struct afs_vnode *new_dvnode,
+		  const char *new_name,
+		  const struct afs_wait_mode *wait_mode)
+{
+	struct afs_call *call;
+	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
+	__be32 *bp;
+
+	_enter("");
+
+	o_namesz = strlen(orig_name);
+	o_padsz = (4 - (o_namesz & 3)) & 3;
+
+	n_namesz = strlen(new_name);
+	n_padsz = (4 - (n_namesz & 3)) & 3;
+
+	reqsz = (4 * 4) +
+		4 + o_namesz + o_padsz +
+		(3 * 4) +
+		4 + n_namesz + n_padsz;
+
+	call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
+	if (!call)
+		return -ENOMEM;
+
+	call->key = key;
+	call->reply = orig_dvnode;
+	call->reply2 = new_dvnode;
+	call->service_id = FS_SERVICE;
+	call->port = htons(AFS_FS_PORT);
+
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(FSRENAME);
+	*bp++ = htonl(orig_dvnode->fid.vid);
+	*bp++ = htonl(orig_dvnode->fid.vnode);
+	*bp++ = htonl(orig_dvnode->fid.unique);
+	*bp++ = htonl(o_namesz);
+	memcpy(bp, orig_name, o_namesz);
+	bp = (void *) bp + o_namesz;
+	if (o_padsz > 0) {
+		memset(bp, 0, o_padsz);
+		bp = (void *) bp + o_padsz;
+	}
 
-	callback->fid		= *fid;
-	callback->version	= ntohl(*bp++);
-	callback->expiry	= ntohl(*bp++);
-	callback->type		= ntohl(*bp++);
-
-	if (volsync) {
-		volsync->creation	= ntohl(*bp++);
-		bp++; /* spare2 */
-		bp++; /* spare3 */
-		bp++; /* spare4 */
-		bp++; /* spare5 */
-		bp++; /* spare6 */
+	*bp++ = htonl(new_dvnode->fid.vid);
+	*bp++ = htonl(new_dvnode->fid.vnode);
+	*bp++ = htonl(new_dvnode->fid.unique);
+	*bp++ = htonl(n_namesz);
+	memcpy(bp, new_name, n_namesz);
+	bp = (void *) bp + n_namesz;
+	if (n_padsz > 0) {
+		memset(bp, 0, n_padsz);
+		bp = (void *) bp + n_padsz;
 	}
 
-	/* success */
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	afs_server_release_fsconn(server, conn);
- out:
-	kleave("");
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-} /* end afs_rxfs_lookup() */
-#endif
+	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/fsclient.h b/fs/afs/fsclient.h
deleted file mode 100644
index 8ba3e74..0000000
--- a/fs/afs/fsclient.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* fsclient.h: AFS File Server client stub declarations
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_FSCLIENT_H
-#define _LINUX_AFS_FSCLIENT_H
-
-#include "server.h"
-
-extern int afs_rxfs_get_volume_info(struct afs_server *server,
-				    const char *name,
-				    struct afs_volume_info *vinfo);
-
-extern int afs_rxfs_fetch_file_status(struct afs_server *server,
-				      struct afs_vnode *vnode,
-				      struct afs_volsync *volsync);
-
-struct afs_rxfs_fetch_descriptor {
-	struct afs_fid	fid;		/* file ID to fetch */
-	size_t		size;		/* total number of bytes to fetch */
-	off_t		offset;		/* offset in file to start from */
-	void		*buffer;	/* read buffer */
-	size_t		actual;		/* actual size sent back by server */
-};
-
-extern int afs_rxfs_fetch_file_data(struct afs_server *server,
-				    struct afs_vnode *vnode,
-				    struct afs_rxfs_fetch_descriptor *desc,
-				    struct afs_volsync *volsync);
-
-extern int afs_rxfs_give_up_callback(struct afs_server *server,
-				     struct afs_vnode *vnode);
-
-/* this doesn't appear to work in OpenAFS server */
-extern int afs_rxfs_lookup(struct afs_server *server,
-			   struct afs_vnode *dir,
-			   const char *filename,
-			   struct afs_vnode *vnode,
-			   struct afs_volsync *volsync);
-
-/* this is apparently mis-implemented in OpenAFS server */
-extern int afs_rxfs_get_root_volume(struct afs_server *server,
-				    char *buf,
-				    size_t *buflen);
-
-
-#endif /* _LINUX_AFS_FSCLIENT_H */
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 9d9bca6..c184a4e 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -19,9 +19,6 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include "volume.h"
-#include "vnode.h"
-#include "super.h"
 #include "internal.h"
 
 struct afs_iget_data {
@@ -29,26 +26,25 @@ struct afs_iget_data {
 	struct afs_volume	*volume;	/* volume on which resides */
 };
 
-/*****************************************************************************/
 /*
  * map the AFS file status to the inode member variables
  */
-static int afs_inode_map_status(struct afs_vnode *vnode)
+static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 {
 	struct inode *inode = AFS_VNODE_TO_I(vnode);
 
-	_debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu",
+	_debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
 	       vnode->status.type,
 	       vnode->status.nlink,
-	       vnode->status.size,
-	       vnode->status.version,
+	       (unsigned long long) vnode->status.size,
+	       vnode->status.data_version,
 	       vnode->status.mode);
 
 	switch (vnode->status.type) {
 	case AFS_FTYPE_FILE:
 		inode->i_mode	= S_IFREG | vnode->status.mode;
 		inode->i_op	= &afs_file_inode_operations;
-		inode->i_fop	= &generic_ro_fops;
+		inode->i_fop	= &afs_file_operations;
 		break;
 	case AFS_FTYPE_DIR:
 		inode->i_mode	= S_IFDIR | vnode->status.mode;
@@ -77,9 +73,9 @@ static int afs_inode_map_status(struct a
 
 	/* check to see whether a symbolic link is really a mountpoint */
 	if (vnode->status.type == AFS_FTYPE_SYMLINK) {
-		afs_mntpt_check_symlink(vnode);
+		afs_mntpt_check_symlink(vnode, key);
 
-		if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
+		if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
 			inode->i_mode	= S_IFDIR | vnode->status.mode;
 			inode->i_op	= &afs_mntpt_inode_operations;
 			inode->i_fop	= &afs_mntpt_file_operations;
@@ -87,30 +83,8 @@ static int afs_inode_map_status(struct a
 	}
 
 	return 0;
-} /* end afs_inode_map_status() */
+}
 
-/*****************************************************************************/
-/*
- * attempt to fetch the status of an inode, coelescing multiple simultaneous
- * fetches
- */
-static int afs_inode_fetch_status(struct inode *inode)
-{
-	struct afs_vnode *vnode;
-	int ret;
-
-	vnode = AFS_FS_I(inode);
-
-	ret = afs_vnode_fetch_status(vnode);
-
-	if (ret == 0)
-		ret = afs_inode_map_status(vnode);
-
-	return ret;
-
-} /* end afs_inode_fetch_status() */
-
-/*****************************************************************************/
 /*
  * iget5() comparator
  */
@@ -120,9 +94,8 @@ static int afs_iget5_test(struct inode *
 
 	return inode->i_ino == data->fid.vnode &&
 		inode->i_version == data->fid.unique;
-} /* end afs_iget5_test() */
+}
 
-/*****************************************************************************/
 /*
  * iget5() inode initialiser
  */
@@ -137,14 +110,14 @@ static int afs_iget5_set(struct inode *i
 	vnode->volume = data->volume;
 
 	return 0;
-} /* end afs_iget5_set() */
+}
 
-/*****************************************************************************/
 /*
  * inode retrieval
  */
-inline int afs_iget(struct super_block *sb, struct afs_fid *fid,
-		    struct inode **_inode)
+struct inode *afs_iget(struct super_block *sb, struct key *key,
+		       struct afs_fid *fid, struct afs_file_status *status,
+		       struct afs_callback *cb)
 {
 	struct afs_iget_data data = { .fid = *fid };
 	struct afs_super_info *as;
@@ -161,20 +134,18 @@ inline int afs_iget(struct super_block *
 			     &data);
 	if (!inode) {
 		_leave(" = -ENOMEM");
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	}
 
+	_debug("GOT INODE %p { vl=%x vn=%x, u=%x }",
+	       inode, fid->vid, fid->vnode, fid->unique);
+
 	vnode = AFS_FS_I(inode);
 
 	/* deal with an existing inode */
 	if (!(inode->i_state & I_NEW)) {
-		ret = afs_vnode_fetch_status(vnode);
-		if (ret==0)
-			*_inode = inode;
-		else
-			iput(inode);
-		_leave(" = %d", ret);
-		return ret;
+		_leave(" = %p", inode);
+		return inode;
 	}
 
 #ifdef AFS_CACHING_SUPPORT
@@ -186,100 +157,185 @@ #ifdef AFS_CACHING_SUPPORT
 			       &vnode->cache);
 #endif
 
-	/* okay... it's a new inode */
-	inode->i_flags |= S_NOATIME;
-	vnode->flags |= AFS_VNODE_CHANGED;
-	ret = afs_inode_fetch_status(inode);
-	if (ret<0)
+	if (!status) {
+		/* it's a remotely extant inode */
+		set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+		ret = afs_vnode_fetch_status(vnode, NULL, key);
+		if (ret < 0)
+			goto bad_inode;
+	} else {
+		/* it's an inode we just created */
+		memcpy(&vnode->status, status, sizeof(vnode->status));
+
+		if (!cb) {
+			/* it's a symlink we just created (the fileserver
+			 * didn't give us a callback) */
+			vnode->cb_version = 0;
+			vnode->cb_expiry = 0;
+			vnode->cb_type = 0;
+			vnode->cb_expires = get_seconds();
+		} else {
+			vnode->cb_version = cb->version;
+			vnode->cb_expiry = cb->expiry;
+			vnode->cb_type = cb->type;
+			vnode->cb_expires = vnode->cb_expiry + get_seconds();
+		}
+	}
+
+	ret = afs_inode_map_status(vnode, key);
+	if (ret < 0)
 		goto bad_inode;
 
 	/* success */
+	clear_bit(AFS_VNODE_UNSET, &vnode->flags);
+	inode->i_flags |= S_NOATIME;
 	unlock_new_inode(inode);
-
-	*_inode = inode;
-	_leave(" = 0 [CB { v=%u x=%lu t=%u }]",
-	       vnode->cb_version,
-	       vnode->cb_timeout.timo_jif,
-	       vnode->cb_type);
-	return 0;
+	_leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
+	return inode;
 
 	/* failure */
- bad_inode:
+bad_inode:
 	make_bad_inode(inode);
 	unlock_new_inode(inode);
 	iput(inode);
 
 	_leave(" = %d [bad]", ret);
+	return ERR_PTR(ret);
+}
+
+/*
+ * validate a vnode/inode
+ * - there are several things we need to check
+ *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
+ *     symlink)
+ *   - parent dir metadata changed (security changes)
+ *   - dentry data changed (write, truncate)
+ *   - dentry metadata changed (security changes)
+ */
+int afs_validate(struct afs_vnode *vnode, struct key *key)
+{
+	int ret;
+
+	_enter("{v={%x:%u} fl=%lx},%x",
+	       vnode->fid.vid, vnode->fid.vnode, vnode->flags,
+	       key_serial(key));
+
+	if (vnode->cb_promised &&
+	    !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
+	    !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
+	    !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
+		if (vnode->cb_expires < get_seconds() + 10) {
+			_debug("callback expired");
+			set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+		} else {
+			goto valid;
+		}
+	}
+
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
+		goto valid;
+
+	mutex_lock(&vnode->validate_lock);
+
+	/* if the promise has expired, we need to check the server again to get
+	 * a new promise - note that if the (parent) directory's metadata was
+	 * changed then the security may be different and we may no longer have
+	 * access */
+	if (!vnode->cb_promised ||
+	    test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
+		_debug("not promised");
+		ret = afs_vnode_fetch_status(vnode, NULL, key);
+		if (ret < 0)
+			goto error_unlock;
+		_debug("new promise [fl=%lx]", vnode->flags);
+	}
+
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
+		_debug("file already deleted");
+		ret = -ESTALE;
+		goto error_unlock;
+	}
+
+	/* if the vnode's data version number changed then its contents are
+	 * different */
+	if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
+		_debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
+		invalidate_remote_inode(&vnode->vfs_inode);
+	}
+
+	clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
+	mutex_unlock(&vnode->validate_lock);
+valid:
+	_leave(" = 0");
+	return 0;
+
+error_unlock:
+	mutex_unlock(&vnode->validate_lock);
+	_leave(" = %d", ret);
 	return ret;
-} /* end afs_iget() */
+}
 
-/*****************************************************************************/
 /*
  * read the attributes of an inode
  */
 int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		      struct kstat *stat)
 {
-	struct afs_vnode *vnode;
 	struct inode *inode;
-	int ret;
 
 	inode = dentry->d_inode;
 
 	_enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version);
 
-	vnode = AFS_FS_I(inode);
-
-	ret = afs_inode_fetch_status(inode);
-	if (ret == -ENOENT) {
-		_leave(" = %d [%d %p]",
-		       ret, atomic_read(&dentry->d_count), dentry->d_inode);
-		return ret;
-	}
-	else if (ret < 0) {
-		make_bad_inode(inode);
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* transfer attributes from the inode structure to the stat
-	 * structure */
 	generic_fillattr(inode, stat);
-
-	_leave(" = 0 CB { v=%u x=%u t=%u }",
-	       vnode->cb_version,
-	       vnode->cb_expiry,
-	       vnode->cb_type);
-
 	return 0;
-} /* end afs_inode_getattr() */
+}
 
-/*****************************************************************************/
 /*
  * clear an AFS inode
  */
 void afs_clear_inode(struct inode *inode)
 {
+	struct afs_permits *permits;
 	struct afs_vnode *vnode;
 
 	vnode = AFS_FS_I(inode);
 
-	_enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
-	       inode->i_ino,
+	_enter("{%x:%d.%d} v=%u x=%u t=%u }",
+	       vnode->fid.vid,
 	       vnode->fid.vnode,
+	       vnode->fid.unique,
 	       vnode->cb_version,
 	       vnode->cb_expiry,
-	       vnode->cb_type
-	       );
+	       vnode->cb_type);
 
-	BUG_ON(inode->i_ino != vnode->fid.vnode);
+	_debug("CLEAR INODE %p", inode);
 
-	afs_vnode_give_up_callback(vnode);
+	ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
+
+	afs_give_up_callback(vnode);
+
+	if (vnode->server) {
+		spin_lock(&vnode->server->fs_lock);
+		rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
+		spin_unlock(&vnode->server->fs_lock);
+		afs_put_server(vnode->server);
+		vnode->server = NULL;
+	}
+
+	ASSERT(!vnode->cb_promised);
 
 #ifdef AFS_CACHING_SUPPORT
 	cachefs_relinquish_cookie(vnode->cache, 0);
 	vnode->cache = NULL;
 #endif
 
+	mutex_lock(&vnode->permits_lock);
+	permits = vnode->permits;
+	rcu_assign_pointer(vnode->permits, NULL);
+	mutex_unlock(&vnode->permits_lock);
+	if (permits)
+		call_rcu(&permits->rcu, afs_zap_permits);
+
 	_leave("");
-} /* end afs_clear_inode() */
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5151d5d..d90c158 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -1,6 +1,6 @@
-/* internal.h: internal AFS stuff
+/* internal AFS stuff
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -9,48 +9,390 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef AFS_INTERNAL_H
-#define AFS_INTERNAL_H
-
 #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/skbuff.h>
+#include <linux/rxrpc.h>
+#include <linux/key.h>
+#include "afs.h"
+#include "afs_vl.h"
+
+#define AFS_CELL_MAX_ADDRS 15
+
+struct afs_call;
+
+typedef enum {
+	AFS_VL_NEW,			/* new, uninitialised record */
+	AFS_VL_CREATING,		/* creating record */
+	AFS_VL_VALID,			/* record is pending */
+	AFS_VL_NO_VOLUME,		/* no such volume available */
+	AFS_VL_UPDATING,		/* update in progress */
+	AFS_VL_VOLUME_DELETED,		/* volume was deleted */
+	AFS_VL_UNCERTAIN,		/* uncertain state (update failed) */
+} __attribute__((packed)) afs_vlocation_state_t;
+
+struct afs_mount_params {
+	bool			rwpath;		/* T if the parent should be considered R/W */
+	bool			force;		/* T to force cell type */
+	afs_voltype_t		type;		/* type of volume requested */
+	int			volnamesz;	/* size of volume name */
+	const char		*volname;	/* name of volume to mount */
+	struct afs_cell		*cell;		/* cell in which to find volume */
+	struct afs_volume	*volume;	/* volume record */
+	struct key		*key;		/* key to use for secure mounting */
+};
 
 /*
- * debug tracing
+ * definition of how to wait for the completion of an operation
  */
-#define kenter(FMT, a...)	printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
-#define kleave(FMT, a...)	printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
-#define kdebug(FMT, a...)	printk(FMT"\n" , ## a)
-#define kproto(FMT, a...)	printk("### "FMT"\n" , ## a)
-#define knet(FMT, a...)		printk(FMT"\n" , ## a)
-
-#ifdef __KDEBUG
-#define _enter(FMT, a...)	kenter(FMT , ## a)
-#define _leave(FMT, a...)	kleave(FMT , ## a)
-#define _debug(FMT, a...)	kdebug(FMT , ## a)
-#define _proto(FMT, a...)	kproto(FMT , ## a)
-#define _net(FMT, a...)		knet(FMT , ## a)
-#else
-#define _enter(FMT, a...)	do { } while(0)
-#define _leave(FMT, a...)	do { } while(0)
-#define _debug(FMT, a...)	do { } while(0)
-#define _proto(FMT, a...)	do { } while(0)
-#define _net(FMT, a...)		do { } while(0)
-#endif
+struct afs_wait_mode {
+	/* RxRPC received message notification */
+	void (*rx_wakeup)(struct afs_call *call);
 
-static inline void afs_discard_my_signals(void)
-{
-	while (signal_pending(current)) {
-		siginfo_t sinfo;
+	/* synchronous call waiter and call dispatched notification */
+	int (*wait)(struct afs_call *call);
+
+	/* asynchronous call completion */
+	void (*async_complete)(void *reply, int error);
+};
+
+extern const struct afs_wait_mode afs_sync_call;
+extern const struct afs_wait_mode afs_async_call;
 
-		spin_lock_irq(&current->sighand->siglock);
-		dequeue_signal(current,&current->blocked, &sinfo);
-		spin_unlock_irq(&current->sighand->siglock);
-	}
+/*
+ * a record of an in-progress RxRPC call
+ */
+struct afs_call {
+	const struct afs_call_type *type;	/* type of call */
+	const struct afs_wait_mode *wait_mode;	/* completion wait mode */
+	wait_queue_head_t	waitq;		/* processes awaiting completion */
+	struct work_struct	async_work;	/* asynchronous work processor */
+	struct work_struct	work;		/* actual work processor */
+	struct sk_buff_head	rx_queue;	/* received packets */
+	struct rxrpc_call	*rxcall;	/* RxRPC call handle */
+	struct key		*key;		/* security for this call */
+	struct afs_server	*server;	/* server affected by incoming CM call */
+	void			*request;	/* request data (first part) */
+	void			*request2;	/* request data (second part) */
+	void			*buffer;	/* reply receive buffer */
+	void			*reply;		/* reply buffer (first part) */
+	void			*reply2;	/* reply buffer (second part) */
+	void			*reply3;	/* reply buffer (third part) */
+	void			*reply4;	/* reply buffer (fourth part) */
+	enum {					/* call state */
+		AFS_CALL_REQUESTING,	/* request is being sent for outgoing call */
+		AFS_CALL_AWAIT_REPLY,	/* awaiting reply to outgoing call */
+		AFS_CALL_AWAIT_OP_ID,	/* awaiting op ID on incoming call */
+		AFS_CALL_AWAIT_REQUEST,	/* awaiting request data on incoming call */
+		AFS_CALL_REPLYING,	/* replying to incoming call */
+		AFS_CALL_AWAIT_ACK,	/* awaiting final ACK of incoming call */
+		AFS_CALL_COMPLETE,	/* successfully completed */
+		AFS_CALL_BUSY,		/* server was busy */
+		AFS_CALL_ABORTED,	/* call was aborted */
+		AFS_CALL_ERROR,		/* call failed due to error */
+	}			state;
+	int			error;		/* error code */
+	unsigned		request_size;	/* size of request data */
+	unsigned		reply_max;	/* maximum size of reply */
+	unsigned		reply_size;	/* current size of reply */
+	unsigned short		offset;		/* offset into received data store */
+	unsigned char		unmarshall;	/* unmarshalling phase */
+	bool			incoming;	/* T if incoming call */
+	u16			service_id;	/* RxRPC service ID to call */
+	__be16			port;		/* target UDP port */
+	__be32			operation_ID;	/* operation ID for an incoming call */
+	u32			count;		/* count for use in unmarshalling */
+	__be32			tmp;		/* place to extract temporary data */
+};
+
+struct afs_call_type {
+	const char *name;
+
+	/* deliver request or reply data to an call
+	 * - returning an error will cause the call to be aborted
+	 */
+	int (*deliver)(struct afs_call *call, struct sk_buff *skb,
+		       bool last);
+
+	/* map an abort code to an error number */
+	int (*abort_to_error)(u32 abort_code);
+
+	/* clean up a call */
+	void (*destructor)(struct afs_call *call);
+};
+
+/*
+ * AFS superblock private data
+ * - there's one superblock per volume
+ */
+struct afs_super_info {
+	struct afs_volume	*volume;	/* volume record */
+	char			rwparent;	/* T if parent is R/W AFS volume */
+};
+
+static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
+{
+	return sb->s_fs_info;
 }
 
+extern struct file_system_type afs_fs_type;
+
+/*
+ * entry in the cached cell catalogue
+ */
+struct afs_cache_cell {
+	char		name[AFS_MAXCELLNAME];	/* cell name (padded with NULs) */
+	struct in_addr	vl_servers[15];		/* cached cell VL servers */
+};
+
+/*
+ * AFS cell record
+ */
+struct afs_cell {
+	atomic_t		usage;
+	struct list_head	link;		/* main cell list link */
+	struct key		*anonymous_key;	/* anonymous user key for this cell */
+	struct list_head	proc_link;	/* /proc cell list link */
+	struct proc_dir_entry	*proc_dir;	/* /proc dir for this cell */
+#ifdef AFS_CACHING_SUPPORT
+	struct cachefs_cookie	*cache;		/* caching cookie */
+#endif
+
+	/* server record management */
+	rwlock_t		servers_lock;	/* active server list lock */
+	struct list_head	servers;	/* active server list */
+
+	/* volume location record management */
+	struct rw_semaphore	vl_sem;		/* volume management serialisation semaphore */
+	struct list_head	vl_list;	/* cell's active VL record list */
+	spinlock_t		vl_lock;	/* vl_list lock */
+	unsigned short		vl_naddrs;	/* number of VL servers in addr list */
+	unsigned short		vl_curr_svix;	/* current server index */
+	struct in_addr		vl_addrs[AFS_CELL_MAX_ADDRS];	/* cell VL server addresses */
+
+	char			name[0];	/* cell name - must go last */
+};
+
+/*
+ * entry in the cached volume location catalogue
+ */
+struct afs_cache_vlocation {
+	/* volume name (lowercase, padded with NULs) */
+	uint8_t			name[AFS_MAXVOLNAME + 1];
+
+	uint8_t			nservers;	/* number of entries used in servers[] */
+	uint8_t			vidmask;	/* voltype mask for vid[] */
+	uint8_t			srvtmask[8];	/* voltype masks for servers[] */
+#define AFS_VOL_VTM_RW	0x01 /* R/W version of the volume is available (on this server) */
+#define AFS_VOL_VTM_RO	0x02 /* R/O version of the volume is available (on this server) */
+#define AFS_VOL_VTM_BAK	0x04 /* backup version of the volume is available (on this server) */
+
+	afs_volid_t		vid[3];		/* volume IDs for R/W, R/O and Bak volumes */
+	struct in_addr		servers[8];	/* fileserver addresses */
+	time_t			rtime;		/* last retrieval time */
+};
+
+/*
+ * volume -> vnode hash table entry
+ */
+struct afs_cache_vhash {
+	afs_voltype_t		vtype;		/* which volume variation */
+	uint8_t			hash_bucket;	/* which hash bucket this represents */
+} __attribute__((packed));
+
+/*
+ * AFS volume location record
+ */
+struct afs_vlocation {
+	atomic_t		usage;
+	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	struct list_head	link;		/* link in cell volume location list */
+	struct list_head	grave;		/* link in master graveyard list */
+	struct list_head	update;		/* link in master update list */
+	struct afs_cell		*cell;		/* cell to which volume belongs */
+#ifdef AFS_CACHING_SUPPORT
+	struct cachefs_cookie	*cache;		/* caching cookie */
+#endif
+	struct afs_cache_vlocation vldb;	/* volume information DB record */
+	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
+	wait_queue_head_t	waitq;		/* status change waitqueue */
+	time_t			update_at;	/* time at which record should be updated */
+	spinlock_t		lock;		/* access lock */
+	afs_vlocation_state_t	state;		/* volume location state */
+	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
+	unsigned short		upd_busy_cnt;	/* EBUSY count during update */
+	bool			valid;		/* T if valid */
+};
+
+/*
+ * AFS fileserver record
+ */
+struct afs_server {
+	atomic_t		usage;
+	time_t			time_of_death;	/* time at which put reduced usage to 0 */
+	struct in_addr		addr;		/* server address */
+	struct afs_cell		*cell;		/* cell in which server resides */
+	struct list_head	link;		/* link in cell's server list */
+	struct list_head	grave;		/* link in master graveyard list */
+	struct rb_node		master_rb;	/* link in master by-addr tree */
+	struct rw_semaphore	sem;		/* access lock */
+
+	/* file service access */
+	struct rb_root		fs_vnodes;	/* vnodes backed by this server (ordered by FID) */
+	unsigned long		fs_act_jif;	/* time at which last activity occurred */
+	unsigned long		fs_dead_jif;	/* time at which no longer to be considered dead */
+	spinlock_t		fs_lock;	/* access lock */
+	int			fs_state;      	/* 0 or reason FS currently marked dead (-errno) */
+
+	/* callback promise management */
+	struct rb_root		cb_promises;	/* vnode expiration list (ordered earliest first) */
+	struct delayed_work	cb_updater;	/* callback updater */
+	struct delayed_work	cb_break_work;	/* collected break dispatcher */
+	wait_queue_head_t	cb_break_waitq;	/* space available in cb_break waitqueue */
+	spinlock_t		cb_lock;	/* access lock */
+	struct afs_callback	cb_break[64];	/* ring of callbacks awaiting breaking */
+	atomic_t		cb_break_n;	/* number of pending breaks */
+	u8			cb_break_head;	/* head of callback breaking ring */
+	u8			cb_break_tail;	/* tail of callback breaking ring */
+};
+
+/*
+ * AFS volume access record
+ */
+struct afs_volume {
+	atomic_t		usage;
+	struct afs_cell		*cell;		/* cell to which belongs (unrefd ptr) */
+	struct afs_vlocation	*vlocation;	/* volume location */
+#ifdef AFS_CACHING_SUPPORT
+	struct cachefs_cookie	*cache;		/* caching cookie */
+#endif
+	afs_volid_t		vid;		/* volume ID */
+	afs_voltype_t		type;		/* type of volume */
+	char			type_force;	/* force volume type (suppress R/O -> R/W) */
+	unsigned short		nservers;	/* number of server slots filled */
+	unsigned short		rjservers;	/* number of servers discarded due to -ENOMEDIUM */
+	struct afs_server	*servers[8];	/* servers on which volume resides (ordered) */
+	struct rw_semaphore	server_sem;	/* lock for accessing current server */
+};
+
+/*
+ * vnode catalogue entry
+ */
+struct afs_cache_vnode {
+	afs_vnodeid_t		vnode_id;	/* vnode ID */
+	unsigned		vnode_unique;	/* vnode ID uniquifier */
+	afs_dataversion_t	data_version;	/* data version */
+};
+
+/*
+ * AFS inode private data
+ */
+struct afs_vnode {
+	struct inode		vfs_inode;	/* the VFS's inode record */
+
+	struct afs_volume	*volume;	/* volume on which vnode resides */
+	struct afs_server	*server;	/* server currently supplying this file */
+	struct afs_fid		fid;		/* the file identifier for this inode */
+	struct afs_file_status	status;		/* AFS status info for this file */
+#ifdef AFS_CACHING_SUPPORT
+	struct cachefs_cookie	*cache;		/* caching cookie */
+#endif
+	struct afs_permits	*permits;	/* cache of permits so far obtained */
+	struct mutex		permits_lock;	/* lock for altering permits list */
+	struct mutex		validate_lock;	/* lock for validating this vnode */
+	wait_queue_head_t	update_waitq;	/* status fetch waitqueue */
+	int			update_cnt;	/* number of outstanding ops that will update the
+						 * status */
+	spinlock_t		lock;		/* waitqueue/flags lock */
+	unsigned long		flags;
+#define AFS_VNODE_CB_BROKEN	0		/* set if vnode's callback was broken */
+#define AFS_VNODE_UNSET		1		/* set if vnode attributes not yet set */
+#define AFS_VNODE_MODIFIED	2		/* set if vnode's data modified */
+#define AFS_VNODE_ZAP_DATA	3		/* set if vnode's data should be invalidated */
+#define AFS_VNODE_DELETED	4		/* set if vnode deleted on server */
+#define AFS_VNODE_MOUNTPOINT	5		/* set if vnode is a mountpoint symlink */
+
+	long			acl_order;	/* ACL check count (callback break count) */
+
+	/* outstanding callback notification on this file */
+	struct rb_node		server_rb;	/* link in server->fs_vnodes */
+	struct rb_node		cb_promise;	/* link in server->cb_promises */
+	struct work_struct	cb_broken_work;	/* work to be done on callback break */
+	time_t			cb_expires;	/* time at which callback expires */
+	time_t			cb_expires_at;	/* time used to order cb_promise */
+	unsigned		cb_version;	/* callback version */
+	unsigned		cb_expiry;	/* callback expiry time */
+	afs_callback_type_t	cb_type;	/* type of callback */
+	bool			cb_promised;	/* true if promise still holds */
+};
+
+/*
+ * cached security record for one user's attempt to access a vnode
+ */
+struct afs_permit {
+	struct key		*key;		/* RxRPC ticket holding a security context */
+	afs_access_t		access_mask;	/* access mask for this key */
+};
+
+/*
+ * cache of security records from attempts to access a vnode
+ */
+struct afs_permits {
+	struct rcu_head		rcu;		/* disposal procedure */
+	int			count;		/* number of records */
+	struct afs_permit	permits[0];	/* the permits so far examined */
+};
+
+/*
+ * record of one of a system's set of network interfaces
+ */
+struct afs_interface {
+	struct in_addr	address;	/* IPv4 address bound to interface */
+	struct in_addr	netmask;	/* netmask applied to address */
+	unsigned	mtu;		/* MTU of interface */
+};
+
+/*
+ * UUID definition [internet draft]
+ * - the timestamp is a 60-bit value, split 32/16/12, and goes in 100ns
+ *   increments since midnight 15th October 1582
+ *   - add AFS_UUID_TO_UNIX_TIME to convert unix time in 100ns units to UUID
+ *     time
+ * - the clock sequence is a 14-bit counter to avoid duplicate times
+ */
+struct afs_uuid {
+	u32		time_low;			/* low part of timestamp */
+	u16		time_mid;			/* mid part of timestamp */
+	u16		time_hi_and_version;		/* high part of timestamp and version  */
+#define AFS_UUID_TO_UNIX_TIME	0x01b21dd213814000ULL
+#define AFS_UUID_TIMEHI_MASK	0x0fff
+#define AFS_UUID_VERSION_TIME	0x1000	/* time-based UUID */
+#define AFS_UUID_VERSION_NAME	0x3000	/* name-based UUID */
+#define AFS_UUID_VERSION_RANDOM	0x4000	/* (pseudo-)random generated UUID */
+	u8		clock_seq_hi_and_reserved;	/* clock seq hi and variant */
+#define AFS_UUID_CLOCKHI_MASK	0x3f
+#define AFS_UUID_VARIANT_STD	0x80
+	u8		clock_seq_low;			/* clock seq low */
+	u8		node[6];			/* spatially unique node ID (MAC addr) */
+};
+
+/*****************************************************************************/
+/*
+ * callback.c
+ */
+extern void afs_init_callback_state(struct afs_server *);
+extern void afs_broken_callback_work(struct work_struct *);
+extern void afs_break_callbacks(struct afs_server *, size_t,
+				struct afs_callback[]);
+extern void afs_discard_callback_on_delete(struct afs_vnode *);
+extern void afs_give_up_callback(struct afs_vnode *);
+extern void afs_dispatch_give_up_callbacks(struct work_struct *);
+extern void afs_flush_callback_breaks(struct afs_server *);
+extern int __init afs_callback_update_init(void);
+extern void afs_callback_update_kill(void);
+
 /*
  * cell.c
  */
@@ -60,57 +402,156 @@ #ifdef AFS_CACHING_SUPPORT
 extern struct cachefs_index_def afs_cache_cell_index_def;
 #endif
 
+#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
+extern int afs_cell_init(char *);
+extern struct afs_cell *afs_cell_create(const char *, char *);
+extern struct afs_cell *afs_cell_lookup(const char *, unsigned);
+extern struct afs_cell *afs_grab_cell(struct afs_cell *);
+extern void afs_put_cell(struct afs_cell *);
+extern void afs_cell_purge(void);
+
+/*
+ * cmservice.c
+ */
+extern bool afs_cm_incoming_call(struct afs_call *);
+
 /*
  * dir.c
  */
 extern const struct inode_operations afs_dir_inode_operations;
 extern const struct file_operations afs_dir_file_operations;
 
+extern int afs_permission(struct inode *, int, struct nameidata *);
+
 /*
  * file.c
  */
 extern const struct address_space_operations afs_fs_aops;
 extern const struct inode_operations afs_file_inode_operations;
+extern const struct file_operations afs_file_operations;
+
+extern int afs_open(struct inode *, struct file *);
+extern int afs_release(struct inode *, struct file *);
 
 #ifdef AFS_CACHING_SUPPORT
-extern int afs_cache_get_page_cookie(struct page *page,
-				     struct cachefs_page **_page_cookie);
+extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
 #endif
 
 /*
- * inode.c
+ * fsclient.c
  */
-extern int afs_iget(struct super_block *sb, struct afs_fid *fid,
-		    struct inode **_inode);
-extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
-			     struct kstat *stat);
-extern void afs_clear_inode(struct inode *inode);
+extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
+				    struct afs_vnode *, struct afs_volsync *,
+				    const struct afs_wait_mode *);
+extern int afs_fs_give_up_callbacks(struct afs_server *,
+				    const struct afs_wait_mode *);
+extern int afs_fs_fetch_data(struct afs_server *, struct key *,
+			     struct afs_vnode *, off_t, size_t, struct page *,
+			     const struct afs_wait_mode *);
+extern int afs_fs_create(struct afs_server *, struct key *,
+			 struct afs_vnode *, const char *, umode_t,
+			 struct afs_fid *, struct afs_file_status *,
+			 struct afs_callback *,
+			 const struct afs_wait_mode *);
+extern int afs_fs_remove(struct afs_server *, struct key *,
+			 struct afs_vnode *, const char *, bool,
+			 const struct afs_wait_mode *);
+extern int afs_fs_link(struct afs_server *, struct key *, struct afs_vnode *,
+		       struct afs_vnode *, const char *,
+		       const struct afs_wait_mode *);
+extern int afs_fs_symlink(struct afs_server *, struct key *,
+			  struct afs_vnode *, const char *, const char *,
+			  struct afs_fid *, struct afs_file_status *,
+			  const struct afs_wait_mode *);
+extern int afs_fs_rename(struct afs_server *, struct key *,
+			 struct afs_vnode *, const char *,
+			 struct afs_vnode *, const char *,
+			 const struct afs_wait_mode *);
 
 /*
- * key_afs.c
+ * inode.c
  */
-#ifdef CONFIG_KEYS
-extern int afs_key_register(void);
-extern void afs_key_unregister(void);
-#endif
+extern struct inode *afs_iget(struct super_block *, struct key *,
+			      struct afs_fid *, struct afs_file_status *,
+			      struct afs_callback *);
+extern int afs_validate(struct afs_vnode *, struct key *);
+extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
+			     struct kstat *);
+extern void afs_zap_permits(struct rcu_head *);
+extern void afs_clear_inode(struct inode *);
 
 /*
  * main.c
  */
+extern struct afs_uuid afs_uuid;
 #ifdef AFS_CACHING_SUPPORT
 extern struct cachefs_netfs afs_cache_netfs;
 #endif
 
 /*
+ * misc.c
+ */
+extern int afs_abort_to_error(u32);
+
+/*
  * mntpt.c
  */
 extern const struct inode_operations afs_mntpt_inode_operations;
 extern const struct file_operations afs_mntpt_file_operations;
-extern struct afs_timer afs_mntpt_expiry_timer;
-extern struct afs_timer_ops afs_mntpt_expiry_timer_ops;
 extern unsigned long afs_mntpt_expiry_timeout;
 
-extern int afs_mntpt_check_symlink(struct afs_vnode *vnode);
+extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
+extern void afs_mntpt_kill_timer(void);
+extern void afs_umount_begin(struct vfsmount *, int);
+
+/*
+ * proc.c
+ */
+extern int afs_proc_init(void);
+extern void afs_proc_cleanup(void);
+extern int afs_proc_cell_setup(struct afs_cell *);
+extern void afs_proc_cell_remove(struct afs_cell *);
+
+/*
+ * rxrpc.c
+ */
+extern int afs_open_socket(void);
+extern void afs_close_socket(void);
+extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t,
+			 const struct afs_wait_mode *);
+extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *,
+					    size_t, size_t);
+extern void afs_flat_call_destructor(struct afs_call *);
+extern void afs_transfer_reply(struct afs_call *, struct sk_buff *);
+extern void afs_send_empty_reply(struct afs_call *);
+extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
+extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
+			    size_t);
+
+/*
+ * security.c
+ */
+extern void afs_clear_permits(struct afs_vnode *);
+extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
+extern struct key *afs_request_key(struct afs_cell *);
+extern int afs_permission(struct inode *, int, struct nameidata *);
+
+/*
+ * server.c
+ */
+extern spinlock_t afs_server_peer_lock;
+
+#define afs_get_server(S)					\
+do {								\
+	_debug("GET SERVER %d", atomic_read(&(S)->usage));	\
+	atomic_inc(&(S)->usage);				\
+} while(0)
+
+extern struct afs_server *afs_lookup_server(struct afs_cell *,
+					    const struct in_addr *);
+extern struct afs_server *afs_find_server(const struct in_addr *);
+extern void afs_put_server(struct afs_server *);
+extern void __exit afs_purge_servers(void);
 
 /*
  * super.c
@@ -118,22 +559,211 @@ extern int afs_mntpt_check_symlink(struc
 extern int afs_fs_init(void);
 extern void afs_fs_exit(void);
 
-#define AFS_CB_HASH_COUNT (PAGE_SIZE / sizeof(struct list_head))
+/*
+ * use-rtnetlink.c
+ */
+extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
+extern int afs_get_MAC_address(u8 *, size_t);
 
-extern struct list_head afs_cb_hash_tbl[];
-extern spinlock_t afs_cb_hash_lock;
+/*
+ * vlclient.c
+ */
+#ifdef AFS_CACHING_SUPPORT
+extern struct cachefs_index_def afs_vlocation_cache_index_def;
+#endif
 
-#define afs_cb_hash(SRV,FID) \
-	afs_cb_hash_tbl[((unsigned long)(SRV) + \
-			(FID)->vid + (FID)->vnode + (FID)->unique) % \
-			AFS_CB_HASH_COUNT]
+extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *,
+				    const char *, struct afs_cache_vlocation *,
+				    const struct afs_wait_mode *);
+extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *,
+				  afs_volid_t, afs_voltype_t,
+				  struct afs_cache_vlocation *,
+				  const struct afs_wait_mode *);
 
 /*
- * proc.c
+ * vlocation.c
  */
-extern int afs_proc_init(void);
-extern void afs_proc_cleanup(void);
-extern int afs_proc_cell_setup(struct afs_cell *cell);
-extern void afs_proc_cell_remove(struct afs_cell *cell);
+#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern int __init afs_vlocation_update_init(void);
+extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *,
+						  struct key *,
+						  const char *, size_t);
+extern void afs_put_vlocation(struct afs_vlocation *);
+extern void afs_vlocation_purge(void);
+
+/*
+ * vnode.c
+ */
+#ifdef AFS_CACHING_SUPPORT
+extern struct cachefs_index_def afs_vnode_cache_index_def;
+#endif
+
+extern struct afs_timer_ops afs_vnode_cb_timed_out_ops;
+
+static inline struct afs_vnode *AFS_FS_I(struct inode *inode)
+{
+	return container_of(inode, struct afs_vnode, vfs_inode);
+}
+
+static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
+{
+	return &vnode->vfs_inode;
+}
+
+extern void afs_vnode_finalise_status_update(struct afs_vnode *,
+					     struct afs_server *);
+extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
+				  struct key *);
+extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
+				off_t, size_t, struct page *);
+extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
+			    umode_t, struct afs_fid *, struct afs_file_status *,
+			    struct afs_callback *, struct afs_server **);
+extern int afs_vnode_remove(struct afs_vnode *, struct key *, const char *,
+			    bool);
+extern int afs_vnode_link(struct afs_vnode *, struct afs_vnode *, struct key *,
+			  const char *);
+extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *,
+			     const char *, struct afs_fid *,
+			     struct afs_file_status *, struct afs_server **);
+extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
+			    struct key *, const char *, const char *);
+
+/*
+ * volume.c
+ */
+#ifdef AFS_CACHING_SUPPORT
+extern struct cachefs_index_def afs_volume_cache_index_def;
+#endif
+
+#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern void afs_put_volume(struct afs_volume *);
+extern struct afs_volume *afs_volume_lookup(struct afs_mount_params *);
+extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *);
+extern int afs_volume_release_fileserver(struct afs_vnode *,
+					 struct afs_server *, int);
+
+/*****************************************************************************/
+/*
+ * debug tracing
+ */
+extern unsigned afs_debug;
+
+#define dbgprintk(FMT,...) \
+	printk("[%x%-6.6s] "FMT"\n", smp_processor_id(), current->comm ,##__VA_ARGS__)
+
+/* make sure we maintain the format strings, even when debugging is disabled */
+static inline __attribute__((format(printf,1,2)))
+void _dbprintk(const char *fmt, ...)
+{
+}
+
+#define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kdebug(FMT,...)	dbgprintk("    "FMT ,##__VA_ARGS__)
+
+
+#if defined(__KDEBUG)
+#define _enter(FMT,...)	kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...)	kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...)	kdebug(FMT,##__VA_ARGS__)
+
+#elif defined(CONFIG_AFS_DEBUG)
+#define AFS_DEBUG_KENTER	0x01
+#define AFS_DEBUG_KLEAVE	0x02
+#define AFS_DEBUG_KDEBUG	0x04
+
+#define _enter(FMT,...)					\
+do {							\
+	if (unlikely(afs_debug & AFS_DEBUG_KENTER))	\
+		kenter(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _leave(FMT,...)					\
+do {							\
+	if (unlikely(afs_debug & AFS_DEBUG_KLEAVE))	\
+		kleave(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _debug(FMT,...)					\
+do {							\
+	if (unlikely(afs_debug & AFS_DEBUG_KDEBUG))	\
+		kdebug(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#else
+#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _debug(FMT,...)	_dbprintk("    "FMT ,##__VA_ARGS__)
+#endif
+
+/*
+ * debug assertion checking
+ */
+#if 1 // defined(__KDEBUGALL)
+
+#define ASSERT(X)						\
+do {								\
+	if (unlikely(!(X))) {					\
+		printk(KERN_ERR "\n");				\
+		printk(KERN_ERR "AFS: Assertion failed\n");	\
+		BUG();						\
+	}							\
+} while(0)
+
+#define ASSERTCMP(X, OP, Y)						\
+do {									\
+	if (unlikely(!((X) OP (Y)))) {					\
+		printk(KERN_ERR "\n");					\
+		printk(KERN_ERR "AFS: Assertion failed\n");		\
+		printk(KERN_ERR "%lu " #OP " %lu is false\n",		\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",	\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		BUG();							\
+	}								\
+} while(0)
+
+#define ASSERTIF(C, X)						\
+do {								\
+	if (unlikely((C) && !(X))) {				\
+		printk(KERN_ERR "\n");				\
+		printk(KERN_ERR "AFS: Assertion failed\n");	\
+		BUG();						\
+	}							\
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y)					\
+do {									\
+	if (unlikely((C) && !((X) OP (Y)))) {				\
+		printk(KERN_ERR "\n");					\
+		printk(KERN_ERR "AFS: Assertion failed\n");		\
+		printk(KERN_ERR "%lu " #OP " %lu is false\n",		\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",	\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		BUG();							\
+	}								\
+} while(0)
+
+#else
+
+#define ASSERT(X)				\
+do {						\
+} while(0)
+
+#define ASSERTCMP(X, OP, Y)			\
+do {						\
+} while(0)
+
+#define ASSERTIF(C, X)				\
+do {						\
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y)		\
+do {						\
+} while(0)
 
-#endif /* AFS_INTERNAL_H */
+#endif /* __KDEBUGALL */
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
deleted file mode 100644
index 615df24..0000000
--- a/fs/afs/kafsasyncd.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* kafsasyncd.c: AFS asynchronous operation daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- *
- * The AFS async daemon is used to the following:
- * - probe "dead" servers to see whether they've come back to life yet.
- * - probe "live" servers that we haven't talked to for a while to see if they are better
- *   candidates for serving than what we're currently using
- * - poll volume location servers to keep up to date volume location lists
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/freezer.h>
-#include "cell.h"
-#include "server.h"
-#include "volume.h"
-#include "kafsasyncd.h"
-#include "kafstimod.h"
-#include <rxrpc/call.h>
-#include <asm/errno.h>
-#include "internal.h"
-
-static DECLARE_COMPLETION(kafsasyncd_alive);
-static DECLARE_COMPLETION(kafsasyncd_dead);
-static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
-static struct task_struct *kafsasyncd_task;
-static int kafsasyncd_die;
-
-static int kafsasyncd(void *arg);
-
-static LIST_HEAD(kafsasyncd_async_attnq);
-static LIST_HEAD(kafsasyncd_async_busyq);
-static DEFINE_SPINLOCK(kafsasyncd_async_lock);
-
-static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
-{
-}
-
-static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
-{
-}
-
-/*****************************************************************************/
-/*
- * start the async daemon
- */
-int afs_kafsasyncd_start(void)
-{
-	int ret;
-
-	ret = kernel_thread(kafsasyncd, NULL, 0);
-	if (ret < 0)
-		return ret;
-
-	wait_for_completion(&kafsasyncd_alive);
-
-	return ret;
-} /* end afs_kafsasyncd_start() */
-
-/*****************************************************************************/
-/*
- * stop the async daemon
- */
-void afs_kafsasyncd_stop(void)
-{
-	/* get rid of my daemon */
-	kafsasyncd_die = 1;
-	wake_up(&kafsasyncd_sleepq);
-	wait_for_completion(&kafsasyncd_dead);
-
-} /* end afs_kafsasyncd_stop() */
-
-/*****************************************************************************/
-/*
- * probing daemon
- */
-static int kafsasyncd(void *arg)
-{
-	struct afs_async_op *op;
-	int die;
-
-	DECLARE_WAITQUEUE(myself, current);
-
-	kafsasyncd_task = current;
-
-	printk("kAFS: Started kafsasyncd %d\n", current->pid);
-
-	daemonize("kafsasyncd");
-
-	complete(&kafsasyncd_alive);
-
-	/* loop around looking for things to attend to */
-	do {
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&kafsasyncd_sleepq, &myself);
-
-		for (;;) {
-			if (!list_empty(&kafsasyncd_async_attnq) ||
-			    signal_pending(current) ||
-			    kafsasyncd_die)
-				break;
-
-			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
-		}
-
-		remove_wait_queue(&kafsasyncd_sleepq, &myself);
-		set_current_state(TASK_RUNNING);
-
-		try_to_freeze();
-
-		/* discard pending signals */
-		afs_discard_my_signals();
-
-		die = kafsasyncd_die;
-
-		/* deal with the next asynchronous operation requiring
-		 * attention */
-		if (!list_empty(&kafsasyncd_async_attnq)) {
-			struct afs_async_op *op;
-
-			_debug("@@@ Begin Asynchronous Operation");
-
-			op = NULL;
-			spin_lock(&kafsasyncd_async_lock);
-
-			if (!list_empty(&kafsasyncd_async_attnq)) {
-				op = list_entry(kafsasyncd_async_attnq.next,
-						struct afs_async_op, link);
-				list_move_tail(&op->link,
-					      &kafsasyncd_async_busyq);
-			}
-
-			spin_unlock(&kafsasyncd_async_lock);
-
-			_debug("@@@ Operation %p {%p}\n",
-			       op, op ? op->ops : NULL);
-
-			if (op)
-				op->ops->attend(op);
-
-			_debug("@@@ End Asynchronous Operation");
-		}
-
-	} while(!die);
-
-	/* need to kill all outstanding asynchronous operations before
-	 * exiting */
-	kafsasyncd_task = NULL;
-	spin_lock(&kafsasyncd_async_lock);
-
-	/* fold the busy and attention queues together */
-	list_splice_init(&kafsasyncd_async_busyq,
-			 &kafsasyncd_async_attnq);
-
-	/* dequeue kafsasyncd from all their wait queues */
-	list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
-		op->call->app_attn_func = kafsasyncd_null_call_attn_func;
-		op->call->app_error_func = kafsasyncd_null_call_error_func;
-		remove_wait_queue(&op->call->waitq, &op->waiter);
-	}
-
-	spin_unlock(&kafsasyncd_async_lock);
-
-	/* abort all the operations */
-	while (!list_empty(&kafsasyncd_async_attnq)) {
-		op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
-		list_del_init(&op->link);
-
-		rxrpc_call_abort(op->call, -EIO);
-		rxrpc_put_call(op->call);
-		op->call = NULL;
-
-		op->ops->discard(op);
-	}
-
-	/* and that's all */
-	_leave("");
-	complete_and_exit(&kafsasyncd_dead, 0);
-
-} /* end kafsasyncd() */
-
-/*****************************************************************************/
-/*
- * begin an operation
- * - place operation on busy queue
- */
-void afs_kafsasyncd_begin_op(struct afs_async_op *op)
-{
-	_enter("");
-
-	spin_lock(&kafsasyncd_async_lock);
-
-	init_waitqueue_entry(&op->waiter, kafsasyncd_task);
-	add_wait_queue(&op->call->waitq, &op->waiter);
-
-	list_move_tail(&op->link, &kafsasyncd_async_busyq);
-
-	spin_unlock(&kafsasyncd_async_lock);
-
-	_leave("");
-} /* end afs_kafsasyncd_begin_op() */
-
-/*****************************************************************************/
-/*
- * request attention for an operation
- * - move to attention queue
- */
-void afs_kafsasyncd_attend_op(struct afs_async_op *op)
-{
-	_enter("");
-
-	spin_lock(&kafsasyncd_async_lock);
-
-	list_move_tail(&op->link, &kafsasyncd_async_attnq);
-
-	spin_unlock(&kafsasyncd_async_lock);
-
-	wake_up(&kafsasyncd_sleepq);
-
-	_leave("");
-} /* end afs_kafsasyncd_attend_op() */
-
-/*****************************************************************************/
-/*
- * terminate an operation
- * - remove from either queue
- */
-void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
-{
-	_enter("");
-
-	spin_lock(&kafsasyncd_async_lock);
-
-	if (!list_empty(&op->link)) {
-		list_del_init(&op->link);
-		remove_wait_queue(&op->call->waitq, &op->waiter);
-	}
-
-	spin_unlock(&kafsasyncd_async_lock);
-
-	wake_up(&kafsasyncd_sleepq);
-
-	_leave("");
-} /* end afs_kafsasyncd_terminate_op() */
diff --git a/fs/afs/kafsasyncd.h b/fs/afs/kafsasyncd.h
deleted file mode 100644
index 791803f..0000000
--- a/fs/afs/kafsasyncd.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* kafsasyncd.h: AFS asynchronous operation daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_KAFSASYNCD_H
-#define _LINUX_AFS_KAFSASYNCD_H
-
-#include "types.h"
-
-struct afs_async_op;
-
-struct afs_async_op_ops {
-	void (*attend)(struct afs_async_op *op);
-	void (*discard)(struct afs_async_op *op);
-};
-
-/*****************************************************************************/
-/*
- * asynchronous operation record
- */
-struct afs_async_op
-{
-	struct list_head		link;
-	struct afs_server		*server;	/* server being contacted */
-	struct rxrpc_call		*call;		/* RxRPC call performing op */
-	wait_queue_t			waiter;		/* wait queue for kafsasyncd */
-	const struct afs_async_op_ops	*ops;		/* operations */
-};
-
-static inline void afs_async_op_init(struct afs_async_op *op,
-				     const struct afs_async_op_ops *ops)
-{
-	INIT_LIST_HEAD(&op->link);
-	op->call = NULL;
-	op->ops = ops;
-}
-
-extern int afs_kafsasyncd_start(void);
-extern void afs_kafsasyncd_stop(void);
-
-extern void afs_kafsasyncd_begin_op(struct afs_async_op *op);
-extern void afs_kafsasyncd_attend_op(struct afs_async_op *op);
-extern void afs_kafsasyncd_terminate_op(struct afs_async_op *op);
-
-#endif /* _LINUX_AFS_KAFSASYNCD_H */
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
deleted file mode 100644
index 694344e..0000000
--- a/fs/afs/kafstimod.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/* kafstimod.c: AFS timeout daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/freezer.h>
-#include "cell.h"
-#include "volume.h"
-#include "kafstimod.h"
-#include <asm/errno.h>
-#include "internal.h"
-
-static DECLARE_COMPLETION(kafstimod_alive);
-static DECLARE_COMPLETION(kafstimod_dead);
-static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
-static int kafstimod_die;
-
-static LIST_HEAD(kafstimod_list);
-static DEFINE_SPINLOCK(kafstimod_lock);
-
-static int kafstimod(void *arg);
-
-/*****************************************************************************/
-/*
- * start the timeout daemon
- */
-int afs_kafstimod_start(void)
-{
-	int ret;
-
-	ret = kernel_thread(kafstimod, NULL, 0);
-	if (ret < 0)
-		return ret;
-
-	wait_for_completion(&kafstimod_alive);
-
-	return ret;
-} /* end afs_kafstimod_start() */
-
-/*****************************************************************************/
-/*
- * stop the timeout daemon
- */
-void afs_kafstimod_stop(void)
-{
-	/* get rid of my daemon */
-	kafstimod_die = 1;
-	wake_up(&kafstimod_sleepq);
-	wait_for_completion(&kafstimod_dead);
-
-} /* end afs_kafstimod_stop() */
-
-/*****************************************************************************/
-/*
- * timeout processing daemon
- */
-static int kafstimod(void *arg)
-{
-	struct afs_timer *timer;
-
-	DECLARE_WAITQUEUE(myself, current);
-
-	printk("kAFS: Started kafstimod %d\n", current->pid);
-
-	daemonize("kafstimod");
-
-	complete(&kafstimod_alive);
-
-	/* loop around looking for things to attend to */
- loop:
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&kafstimod_sleepq, &myself);
-
-	for (;;) {
-		unsigned long jif;
-		signed long timeout;
-
-		/* deal with the server being asked to die */
-		if (kafstimod_die) {
-			remove_wait_queue(&kafstimod_sleepq, &myself);
-			_leave("");
-			complete_and_exit(&kafstimod_dead, 0);
-		}
-
-		try_to_freeze();
-
-		/* discard pending signals */
-		afs_discard_my_signals();
-
-		/* work out the time to elapse before the next event */
-		spin_lock(&kafstimod_lock);
-		if (list_empty(&kafstimod_list)) {
-			timeout = MAX_SCHEDULE_TIMEOUT;
-		}
-		else {
-			timer = list_entry(kafstimod_list.next,
-					   struct afs_timer, link);
-			timeout = timer->timo_jif;
-			jif = jiffies;
-
-			if (time_before_eq((unsigned long) timeout, jif))
-				goto immediate;
-
-			else {
-				timeout = (long) timeout - (long) jiffies;
-			}
-		}
-		spin_unlock(&kafstimod_lock);
-
-		schedule_timeout(timeout);
-
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-
-	/* the thing on the front of the queue needs processing
-	 * - we come here with the lock held and timer pointing to the expired
-	 *   entry
-	 */
- immediate:
-	remove_wait_queue(&kafstimod_sleepq, &myself);
-	set_current_state(TASK_RUNNING);
-
-	_debug("@@@ Begin Timeout of %p", timer);
-
-	/* dequeue the timer */
-	list_del_init(&timer->link);
-	spin_unlock(&kafstimod_lock);
-
-	/* call the timeout function */
-	timer->ops->timed_out(timer);
-
-	_debug("@@@ End Timeout");
-	goto loop;
-
-} /* end kafstimod() */
-
-/*****************************************************************************/
-/*
- * (re-)queue a timer
- */
-void afs_kafstimod_add_timer(struct afs_timer *timer, unsigned long timeout)
-{
-	struct afs_timer *ptimer;
-	struct list_head *_p;
-
-	_enter("%p,%lu", timer, timeout);
-
-	spin_lock(&kafstimod_lock);
-
-	list_del(&timer->link);
-
-	/* the timer was deferred or reset - put it back in the queue at the
-	 * right place */
-	timer->timo_jif = jiffies + timeout;
-
-	list_for_each(_p, &kafstimod_list) {
-		ptimer = list_entry(_p, struct afs_timer, link);
-		if (time_before(timer->timo_jif, ptimer->timo_jif))
-			break;
-	}
-
-	list_add_tail(&timer->link, _p); /* insert before stopping point */
-
-	spin_unlock(&kafstimod_lock);
-
-	wake_up(&kafstimod_sleepq);
-
-	_leave("");
-} /* end afs_kafstimod_add_timer() */
-
-/*****************************************************************************/
-/*
- * dequeue a timer
- * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
- */
-int afs_kafstimod_del_timer(struct afs_timer *timer)
-{
-	int ret = 0;
-
-	_enter("%p", timer);
-
-	spin_lock(&kafstimod_lock);
-
-	if (list_empty(&timer->link))
-		ret = -ENOENT;
-	else
-		list_del_init(&timer->link);
-
-	spin_unlock(&kafstimod_lock);
-
-	wake_up(&kafstimod_sleepq);
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end afs_kafstimod_del_timer() */
diff --git a/fs/afs/kafstimod.h b/fs/afs/kafstimod.h
deleted file mode 100644
index e312f1a..0000000
--- a/fs/afs/kafstimod.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* kafstimod.h: AFS timeout daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_KAFSTIMOD_H
-#define _LINUX_AFS_KAFSTIMOD_H
-
-#include "types.h"
-
-struct afs_timer;
-
-struct afs_timer_ops {
-	/* called when the front of the timer queue has timed out */
-	void (*timed_out)(struct afs_timer *timer);
-};
-
-/*****************************************************************************/
-/*
- * AFS timer/timeout record
- */
-struct afs_timer
-{
-	struct list_head		link;		/* link in timer queue */
-	unsigned long			timo_jif;	/* timeout time */
-	const struct afs_timer_ops	*ops;		/* timeout expiry function */
-};
-
-static inline void afs_timer_init(struct afs_timer *timer,
-				  const struct afs_timer_ops *ops)
-{
-	INIT_LIST_HEAD(&timer->link);
-	timer->ops = ops;
-}
-
-extern int afs_kafstimod_start(void);
-extern void afs_kafstimod_stop(void);
-
-extern void afs_kafstimod_add_timer(struct afs_timer *timer,
-				    unsigned long timeout);
-extern int afs_kafstimod_del_timer(struct afs_timer *timer);
-
-#endif /* _LINUX_AFS_KAFSTIMOD_H */
diff --git a/fs/afs/main.c b/fs/afs/main.c
index f2704ba..80ec6fd 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -1,4 +1,4 @@
-/* main.c: AFS client file system
+/* AFS client file system
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -13,43 +13,21 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/completion.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/call.h>
-#include <rxrpc/peer.h>
-#include "cache.h"
-#include "cell.h"
-#include "server.h"
-#include "fsclient.h"
-#include "cmservice.h"
-#include "kafstimod.h"
-#include "kafsasyncd.h"
 #include "internal.h"
 
-struct rxrpc_transport *afs_transport;
-
-static int afs_adding_peer(struct rxrpc_peer *peer);
-static void afs_discarding_peer(struct rxrpc_peer *peer);
-
-
 MODULE_DESCRIPTION("AFS Client File System");
 MODULE_AUTHOR("Red Hat, Inc.");
 MODULE_LICENSE("GPL");
 
+unsigned afs_debug;
+module_param_named(debug, afs_debug, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(afs_debug, "AFS debugging mask");
+
 static char *rootcell;
 
 module_param(rootcell, charp, 0);
 MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
 
-
-static struct rxrpc_peer_ops afs_peer_ops = {
-	.adding		= afs_adding_peer,
-	.discarding	= afs_discarding_peer,
-};
-
-struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
-DEFINE_SPINLOCK(afs_cb_hash_lock);
-
 #ifdef AFS_CACHING_SUPPORT
 static struct cachefs_netfs_operations afs_cache_ops = {
 	.get_page_cookie	= afs_cache_get_page_cookie,
@@ -62,20 +40,63 @@ struct cachefs_netfs afs_cache_netfs = {
 };
 #endif
 
-/*****************************************************************************/
+struct afs_uuid afs_uuid;
+
+/*
+ * get a client UUID
+ */
+static int __init afs_get_client_UUID(void)
+{
+	struct timespec ts;
+	u64 uuidtime;
+	u16 clockseq;
+	int ret;
+
+	/* read the MAC address of one of the external interfaces and construct
+	 * a UUID from it */
+	ret = afs_get_MAC_address(afs_uuid.node, sizeof(afs_uuid.node));
+	if (ret < 0)
+		return ret;
+
+	getnstimeofday(&ts);
+	uuidtime = (u64) ts.tv_sec * 1000 * 1000 * 10;
+	uuidtime += ts.tv_nsec / 100;
+	uuidtime += AFS_UUID_TO_UNIX_TIME;
+	afs_uuid.time_low = uuidtime;
+	afs_uuid.time_mid = uuidtime >> 32;
+	afs_uuid.time_hi_and_version = (uuidtime >> 48) & AFS_UUID_TIMEHI_MASK;
+	afs_uuid.time_hi_and_version = AFS_UUID_VERSION_TIME;
+
+	get_random_bytes(&clockseq, 2);
+	afs_uuid.clock_seq_low = clockseq;
+	afs_uuid.clock_seq_hi_and_reserved =
+		(clockseq >> 8) & AFS_UUID_CLOCKHI_MASK;
+	afs_uuid.clock_seq_hi_and_reserved = AFS_UUID_VARIANT_STD;
+
+	_debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+	       afs_uuid.time_low,
+	       afs_uuid.time_mid,
+	       afs_uuid.time_hi_and_version,
+	       afs_uuid.clock_seq_hi_and_reserved,
+	       afs_uuid.clock_seq_low,
+	       afs_uuid.node[0], afs_uuid.node[1], afs_uuid.node[2],
+	       afs_uuid.node[3], afs_uuid.node[4], afs_uuid.node[5]);
+
+	return 0;
+}
+
 /*
  * initialise the AFS client FS module
  */
 static int __init afs_init(void)
 {
-	int loop, ret;
+	int ret;
 
 	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
 
-	/* initialise the callback hash table */
-	spin_lock_init(&afs_cb_hash_lock);
-	for (loop = AFS_CB_HASH_COUNT - 1; loop >= 0; loop--)
-		INIT_LIST_HEAD(&afs_cb_hash_tbl[loop]);
+	ret = afs_get_client_UUID();
+	if (ret < 0)
+		return ret;
 
 	/* register the /proc stuff */
 	ret = afs_proc_init();
@@ -87,70 +108,56 @@ #ifdef AFS_CACHING_SUPPORT
 	ret = cachefs_register_netfs(&afs_cache_netfs,
 				     &afs_cache_cell_index_def);
 	if (ret < 0)
-		goto error;
-#endif
-
-#ifdef CONFIG_KEYS_TURNED_OFF
-	ret = afs_key_register();
-	if (ret < 0)
 		goto error_cache;
 #endif
 
 	/* initialise the cell DB */
 	ret = afs_cell_init(rootcell);
 	if (ret < 0)
-		goto error_keys;
+		goto error_cell_init;
 
-	/* start the timeout daemon */
-	ret = afs_kafstimod_start();
+	/* initialise the VL update process */
+	ret = afs_vlocation_update_init();
 	if (ret < 0)
-		goto error_keys;
+		goto error_vl_update_init;
 
-	/* start the async operation daemon */
-	ret = afs_kafsasyncd_start();
-	if (ret < 0)
-		goto error_kafstimod;
+	/* initialise the callback update process */
+	ret = afs_callback_update_init();
 
 	/* create the RxRPC transport */
-	ret = rxrpc_create_transport(7001, &afs_transport);
+	ret = afs_open_socket();
 	if (ret < 0)
-		goto error_kafsasyncd;
-
-	afs_transport->peer_ops = &afs_peer_ops;
+		goto error_open_socket;
 
 	/* register the filesystems */
 	ret = afs_fs_init();
 	if (ret < 0)
-		goto error_transport;
+		goto error_fs;
 
 	return ret;
 
- error_transport:
-	rxrpc_put_transport(afs_transport);
- error_kafsasyncd:
-	afs_kafsasyncd_stop();
- error_kafstimod:
-	afs_kafstimod_stop();
- error_keys:
-#ifdef CONFIG_KEYS_TURNED_OFF
-	afs_key_unregister();
- error_cache:
-#endif
+error_fs:
+	afs_close_socket();
+error_open_socket:
+error_vl_update_init:
+error_cell_init:
 #ifdef AFS_CACHING_SUPPORT
 	cachefs_unregister_netfs(&afs_cache_netfs);
- error:
+error_cache:
 #endif
+	afs_callback_update_kill();
+	afs_vlocation_purge();
 	afs_cell_purge();
 	afs_proc_cleanup();
 	printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
 	return ret;
-} /* end afs_init() */
+}
 
 /* XXX late_initcall is kludgy, but the only alternative seems to create
  * a transport upon the first mount, which is worse. Or is it?
  */
 late_initcall(afs_init);	/* must be called after net/ to create socket */
-/*****************************************************************************/
+
 /*
  * clean up on module removal
  */
@@ -159,127 +166,16 @@ static void __exit afs_exit(void)
 	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
 
 	afs_fs_exit();
-	rxrpc_put_transport(afs_transport);
-	afs_kafstimod_stop();
-	afs_kafsasyncd_stop();
+	afs_close_socket();
+	afs_purge_servers();
+	afs_callback_update_kill();
+	afs_vlocation_purge();
+	flush_scheduled_work();
 	afs_cell_purge();
-#ifdef CONFIG_KEYS_TURNED_OFF
-	afs_key_unregister();
-#endif
 #ifdef AFS_CACHING_SUPPORT
 	cachefs_unregister_netfs(&afs_cache_netfs);
 #endif
 	afs_proc_cleanup();
-
-} /* end afs_exit() */
-
-module_exit(afs_exit);
-
-/*****************************************************************************/
-/*
- * notification that new peer record is being added
- * - called from krxsecd
- * - return an error to induce an abort
- * - mustn't sleep (caller holds an rwlock)
- */
-static int afs_adding_peer(struct rxrpc_peer *peer)
-{
-	struct afs_server *server;
-	int ret;
-
-	_debug("kAFS: Adding new peer %08x\n", ntohl(peer->addr.s_addr));
-
-	/* determine which server the peer resides in (if any) */
-	ret = afs_server_find_by_peer(peer, &server);
-	if (ret < 0)
-		return ret; /* none that we recognise, so abort */
-
-	_debug("Server %p{u=%d}\n", server, atomic_read(&server->usage));
-
-	_debug("Cell %p{u=%d}\n",
-	       server->cell, atomic_read(&server->cell->usage));
-
-	/* cross-point the structs under a global lock */
-	spin_lock(&afs_server_peer_lock);
-	peer->user = server;
-	server->peer = peer;
-	spin_unlock(&afs_server_peer_lock);
-
-	afs_put_server(server);
-
-	return 0;
-} /* end afs_adding_peer() */
-
-/*****************************************************************************/
-/*
- * notification that a peer record is being discarded
- * - called from krxiod or krxsecd
- */
-static void afs_discarding_peer(struct rxrpc_peer *peer)
-{
-	struct afs_server *server;
-
-	_enter("%p",peer);
-
-	_debug("Discarding peer %08x (rtt=%lu.%lumS)\n",
-	       ntohl(peer->addr.s_addr),
-	       (long) (peer->rtt / 1000),
-	       (long) (peer->rtt % 1000));
-
-	/* uncross-point the structs under a global lock */
-	spin_lock(&afs_server_peer_lock);
-	server = peer->user;
-	if (server) {
-		peer->user = NULL;
-		server->peer = NULL;
-	}
-	spin_unlock(&afs_server_peer_lock);
-
-	_leave("");
-
-} /* end afs_discarding_peer() */
-
-/*****************************************************************************/
-/*
- * clear the dead space between task_struct and kernel stack
- * - called by supplying -finstrument-functions to gcc
- */
-#if 0
-void __cyg_profile_func_enter (void *this_fn, void *call_site)
-__attribute__((no_instrument_function));
-
-void __cyg_profile_func_enter (void *this_fn, void *call_site)
-{
-       asm volatile("  movl    %%esp,%%edi     \n"
-                    "  andl    %0,%%edi        \n"
-                    "  addl    %1,%%edi        \n"
-                    "  movl    %%esp,%%ecx     \n"
-                    "  subl    %%edi,%%ecx     \n"
-                    "  shrl    $2,%%ecx        \n"
-                    "  movl    $0xedededed,%%eax     \n"
-                    "  rep stosl               \n"
-                    :
-                    : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info))
-                    : "eax", "ecx", "edi", "memory", "cc"
-                    );
 }
 
-void __cyg_profile_func_exit(void *this_fn, void *call_site)
-__attribute__((no_instrument_function));
-
-void __cyg_profile_func_exit(void *this_fn, void *call_site)
-{
-       asm volatile("  movl    %%esp,%%edi     \n"
-                    "  andl    %0,%%edi        \n"
-                    "  addl    %1,%%edi        \n"
-                    "  movl    %%esp,%%ecx     \n"
-                    "  subl    %%edi,%%ecx     \n"
-                    "  shrl    $2,%%ecx        \n"
-                    "  movl    $0xdadadada,%%eax     \n"
-                    "  rep stosl               \n"
-                    :
-                    : "i"(~(THREAD_SIZE - 1)), "i"(sizeof(struct thread_info))
-                    : "eax", "ecx", "edi", "memory", "cc"
-                    );
-}
-#endif
+module_exit(afs_exit);
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index e4fce66..cdb9792 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -1,6 +1,6 @@
-/* misc.c: miscellaneous bits
+/* miscellaneous bits
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -12,19 +12,20 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
-#include "errors.h"
 #include "internal.h"
+#include "afs_fs.h"
 
-/*****************************************************************************/
 /*
  * convert an AFS abort code to a Linux error number
  */
-int afs_abort_to_error(int abortcode)
+int afs_abort_to_error(u32 abort_code)
 {
-	switch (abortcode) {
+	switch (abort_code) {
+	case 13:		return -EACCES;
+	case 30:		return -EROFS;
 	case VSALVAGE:		return -EIO;
 	case VNOVNODE:		return -ENOENT;
-	case VNOVOL:		return -ENXIO;
+	case VNOVOL:		return -ENOMEDIUM;
 	case VVOLEXISTS:	return -EEXIST;
 	case VNOSERVICE:	return -EIO;
 	case VOFFLINE:		return -ENOENT;
@@ -33,7 +34,24 @@ int afs_abort_to_error(int abortcode)
 	case VOVERQUOTA:	return -EDQUOT;
 	case VBUSY:		return -EBUSY;
 	case VMOVED:		return -ENXIO;
-	default:		return -EIO;
+	case 0x2f6df0c:		return -EACCES;
+	case 0x2f6df0f:		return -EBUSY;
+	case 0x2f6df10:		return -EEXIST;
+	case 0x2f6df11:		return -EXDEV;
+	case 0x2f6df13:		return -ENOTDIR;
+	case 0x2f6df14:		return -EISDIR;
+	case 0x2f6df15:		return -EINVAL;
+	case 0x2f6df1a:		return -EFBIG;
+	case 0x2f6df1b:		return -ENOSPC;
+	case 0x2f6df1d:		return -EROFS;
+	case 0x2f6df1e:		return -EMLINK;
+	case 0x2f6df20:		return -EDOM;
+	case 0x2f6df21:		return -ERANGE;
+	case 0x2f6df22:		return -EDEADLK;
+	case 0x2f6df23:		return -ENAMETOOLONG;
+	case 0x2f6df24:		return -ENOLCK;
+	case 0x2f6df26:		return -ENOTEMPTY;
+	case 0x2f6df78:		return -EDQUOT;
+	default:		return -EREMOTEIO;
 	}
-
-} /* end afs_abort_to_error() */
+}
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 68495f0..034fcfd 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -1,4 +1,4 @@
-/* mntpt.c: mountpoint management
+/* mountpoint management
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -18,10 +18,6 @@ #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/mnt_namespace.h>
-#include "super.h"
-#include "cell.h"
-#include "volume.h"
-#include "vnode.h"
 #include "internal.h"
 
 
@@ -30,6 +26,7 @@ static struct dentry *afs_mntpt_lookup(s
 				       struct nameidata *nd);
 static int afs_mntpt_open(struct inode *inode, struct file *file);
 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
+static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
 const struct file_operations afs_mntpt_file_operations = {
 	.open		= afs_mntpt_open,
@@ -43,24 +40,19 @@ const struct inode_operations afs_mntpt_
 };
 
 static LIST_HEAD(afs_vfsmounts);
+static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
 
-static void afs_mntpt_expiry_timed_out(struct afs_timer *timer);
+unsigned long afs_mntpt_expiry_timeout = 10 * 60;
 
-struct afs_timer_ops afs_mntpt_expiry_timer_ops = {
-	.timed_out	= afs_mntpt_expiry_timed_out,
-};
-
-struct afs_timer afs_mntpt_expiry_timer;
-
-unsigned long afs_mntpt_expiry_timeout = 20;
-
-/*****************************************************************************/
 /*
  * check a symbolic link to see whether it actually encodes a mountpoint
  * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
  */
-int afs_mntpt_check_symlink(struct afs_vnode *vnode)
+int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
 {
+	struct file file = {
+		.private_data = key,
+	};
 	struct page *page;
 	size_t size;
 	char *buf;
@@ -69,23 +61,21 @@ int afs_mntpt_check_symlink(struct afs_v
 	_enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique);
 
 	/* read the contents of the symlink into the pagecache */
-	page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL);
+	page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
 	if (IS_ERR(page)) {
 		ret = PTR_ERR(page);
 		goto out;
 	}
 
 	ret = -EIO;
-	wait_on_page_locked(page);
-	buf = kmap(page);
-	if (!PageUptodate(page))
-		goto out_free;
 	if (PageError(page))
 		goto out_free;
 
+	buf = kmap(page);
+
 	/* examine the symlink's contents */
 	size = vnode->status.size;
-	_debug("symlink to %*.*s", size, (int) size, buf);
+	_debug("symlink to %*.*s", (int) size, (int) size, buf);
 
 	if (size > 2 &&
 	    (buf[0] == '%' || buf[0] == '#') &&
@@ -93,22 +83,20 @@ int afs_mntpt_check_symlink(struct afs_v
 	    ) {
 		_debug("symlink is a mountpoint");
 		spin_lock(&vnode->lock);
-		vnode->flags |= AFS_VNODE_MOUNTPOINT;
+		set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
 		spin_unlock(&vnode->lock);
 	}
 
 	ret = 0;
 
- out_free:
 	kunmap(page);
+out_free:
 	page_cache_release(page);
- out:
+out:
 	_leave(" = %d", ret);
 	return ret;
+}
 
-} /* end afs_mntpt_check_symlink() */
-
-/*****************************************************************************/
 /*
  * no valid lookup procedure on this sort of dir
  */
@@ -116,7 +104,7 @@ static struct dentry *afs_mntpt_lookup(s
 				       struct dentry *dentry,
 				       struct nameidata *nd)
 {
-	kenter("%p,%p{%p{%s},%s}",
+	_enter("%p,%p{%p{%s},%s}",
 	       dir,
 	       dentry,
 	       dentry->d_parent,
@@ -125,15 +113,14 @@ static struct dentry *afs_mntpt_lookup(s
 	       dentry->d_name.name);
 
 	return ERR_PTR(-EREMOTE);
-} /* end afs_mntpt_lookup() */
+}
 
-/*****************************************************************************/
 /*
  * no valid open procedure on this sort of dir
  */
 static int afs_mntpt_open(struct inode *inode, struct file *file)
 {
-	kenter("%p,%p{%p{%s},%s}",
+	_enter("%p,%p{%p{%s},%s}",
 	       inode, file,
 	       file->f_path.dentry->d_parent,
 	       file->f_path.dentry->d_parent ?
@@ -142,9 +129,8 @@ static int afs_mntpt_open(struct inode *
 	       file->f_path.dentry->d_name.name);
 
 	return -EREMOTE;
-} /* end afs_mntpt_open() */
+}
 
-/*****************************************************************************/
 /*
  * create a vfsmount to be automounted
  */
@@ -157,7 +143,7 @@ static struct vfsmount *afs_mntpt_do_aut
 	char *buf, *devname = NULL, *options = NULL;
 	int ret;
 
-	kenter("{%s}", mntpt->d_name.name);
+	_enter("{%s}", mntpt->d_name.name);
 
 	BUG_ON(!mntpt->d_inode);
 
@@ -183,8 +169,7 @@ static struct vfsmount *afs_mntpt_do_aut
 	}
 
 	ret = -EIO;
-	wait_on_page_locked(page);
-	if (!PageUptodate(page) || PageError(page))
+	if (PageError(page))
 		goto error;
 
 	buf = kmap(page);
@@ -201,79 +186,108 @@ static struct vfsmount *afs_mntpt_do_aut
 		strcat(options, ",rwpath");
 
 	/* try and do the mount */
-	kdebug("--- attempting mount %s -o %s ---", devname, options);
+	_debug("--- attempting mount %s -o %s ---", devname, options);
 	mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
-	kdebug("--- mount result %p ---", mnt);
+	_debug("--- mount result %p ---", mnt);
 
 	free_page((unsigned long) devname);
 	free_page((unsigned long) options);
-	kleave(" = %p", mnt);
+	_leave(" = %p", mnt);
 	return mnt;
 
- error:
+error:
 	if (page)
 		page_cache_release(page);
 	if (devname)
 		free_page((unsigned long) devname);
 	if (options)
 		free_page((unsigned long) options);
-	kleave(" = %d", ret);
+	_leave(" = %d", ret);
 	return ERR_PTR(ret);
-} /* end afs_mntpt_do_automount() */
+}
 
-/*****************************************************************************/
 /*
  * follow a link from a mountpoint directory, thus causing it to be mounted
  */
 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct vfsmount *newmnt;
-	struct dentry *old_dentry;
 	int err;
 
-	kenter("%p{%s},{%s:%p{%s}}",
+	_enter("%p{%s},{%s:%p{%s},}",
 	       dentry,
 	       dentry->d_name.name,
 	       nd->mnt->mnt_devname,
 	       dentry,
 	       nd->dentry->d_name.name);
 
-	newmnt = afs_mntpt_do_automount(dentry);
+	dput(nd->dentry);
+	nd->dentry = dget(dentry);
+
+	newmnt = afs_mntpt_do_automount(nd->dentry);
 	if (IS_ERR(newmnt)) {
 		path_release(nd);
 		return (void *)newmnt;
 	}
 
-	old_dentry = nd->dentry;
-	nd->dentry = dentry;
-	err = do_add_mount(newmnt, nd, 0, &afs_vfsmounts);
-	nd->dentry = old_dentry;
-
-	path_release(nd);
-
-	if (!err) {
-		mntget(newmnt);
+	mntget(newmnt);
+	err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts);
+	switch (err) {
+	case 0:
+		mntput(nd->mnt);
+		dput(nd->dentry);
 		nd->mnt = newmnt;
-		dget(newmnt->mnt_root);
-		nd->dentry = newmnt->mnt_root;
+		nd->dentry = dget(newmnt->mnt_root);
+		schedule_delayed_work(&afs_mntpt_expiry_timer,
+				      afs_mntpt_expiry_timeout * HZ);
+		break;
+	case -EBUSY:
+		/* someone else made a mount here whilst we were busy */
+		while (d_mountpoint(nd->dentry) &&
+		       follow_down(&nd->mnt, &nd->dentry))
+			;
+		err = 0;
+	default:
+		mntput(newmnt);
+		break;
 	}
 
-	kleave(" = %d", err);
+	_leave(" = %d", err);
 	return ERR_PTR(err);
-} /* end afs_mntpt_follow_link() */
+}
 
-/*****************************************************************************/
 /*
  * handle mountpoint expiry timer going off
  */
-static void afs_mntpt_expiry_timed_out(struct afs_timer *timer)
+static void afs_mntpt_expiry_timed_out(struct work_struct *work)
 {
-	kenter("");
+	_enter("");
 
-	mark_mounts_for_expiry(&afs_vfsmounts);
+	if (!list_empty(&afs_vfsmounts)) {
+		mark_mounts_for_expiry(&afs_vfsmounts);
+		schedule_delayed_work(&afs_mntpt_expiry_timer,
+				      afs_mntpt_expiry_timeout * HZ);
+	}
 
-	afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
-				afs_mntpt_expiry_timeout * HZ);
+	_leave("");
+}
 
-	kleave("");
-} /* end afs_mntpt_expiry_timed_out() */
+/*
+ * kill the AFS mountpoint timer if it's still running
+ */
+void afs_mntpt_kill_timer(void)
+{
+	_enter("");
+
+	ASSERT(list_empty(&afs_vfsmounts));
+	cancel_delayed_work(&afs_mntpt_expiry_timer);
+	flush_scheduled_work();
+}
+
+/*
+ * begin unmount by attempting to remove all automounted mountpoints we added
+ */
+void afs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+	shrink_submounts(vfsmnt, &afs_vfsmounts);
+}
diff --git a/fs/afs/mount.h b/fs/afs/mount.h
deleted file mode 100644
index 9d2f46e..0000000
--- a/fs/afs/mount.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* mount.h: mount parameters
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_MOUNT_H
-#define _LINUX_AFS_MOUNT_H
-
-struct afs_mountdata {
-	const char		*volume;	/* name of volume */
-	const char		*cell;		/* name of cell containing volume */
-	const char		*cache;		/* name of cache block device */
-	size_t			nservers;	/* number of server addresses listed */
-	uint32_t		servers[10];	/* IP addresses of servers in this cell */
-};
-
-#endif /* _LINUX_AFS_MOUNT_H */
diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c
new file mode 100644
index 0000000..fc27d4b
--- /dev/null
+++ b/fs/afs/netdevices.c
@@ -0,0 +1,68 @@
+/* AFS network device helpers
+ *
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ */
+
+#include <linux/string.h>
+#include <linux/rtnetlink.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include "internal.h"
+
+/*
+ * get a MAC address from a random ethernet interface that has a real one
+ * - the buffer will normally be 6 bytes in size
+ */
+int afs_get_MAC_address(u8 *mac, size_t maclen)
+{
+	struct net_device *dev;
+	int ret = -ENODEV;
+
+	if (maclen != ETH_ALEN)
+		BUG();
+
+	rtnl_lock();
+	dev = __dev_getfirstbyhwtype(ARPHRD_ETHER);
+	if (dev) {
+		memcpy(mac, dev->dev_addr, maclen);
+		ret = 0;
+	}
+	rtnl_unlock();
+	return ret;
+}
+
+/*
+ * get a list of this system's interface IPv4 addresses, netmasks and MTUs
+ * - maxbufs must be at least 1
+ * - returns the number of interface records in the buffer
+ */
+int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
+			    bool wantloopback)
+{
+	struct net_device *dev;
+	struct in_device *idev;
+	int n = 0;
+
+	ASSERT(maxbufs > 0);
+
+	rtnl_lock();
+	for_each_netdev(dev) {
+		if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
+			continue;
+		idev = __in_dev_get_rtnl(dev);
+		if (!idev)
+			continue;
+		for_primary_ifa(idev) {
+			bufs[n].address.s_addr = ifa->ifa_address;
+			bufs[n].netmask.s_addr = ifa->ifa_mask;
+			bufs[n].mtu = dev->mtu;
+			n++;
+			if (n >= maxbufs)
+				goto out;
+		} endfor_ifa(idev);
+	}
+out:
+	rtnl_unlock();
+	return n;
+}
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index ae6b85b..d5601f6 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -1,4 +1,4 @@
-/* proc.c: /proc interface for AFS
+/* /proc interface for AFS
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -13,8 +13,6 @@ #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include "cell.h"
-#include "volume.h"
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -130,7 +128,6 @@ static const struct file_operations afs_
 	.release	= afs_proc_cell_servers_release,
 };
 
-/*****************************************************************************/
 /*
  * initialise the /proc/fs/afs/ directory
  */
@@ -142,47 +139,43 @@ int afs_proc_init(void)
 
 	proc_afs = proc_mkdir("fs/afs", NULL);
 	if (!proc_afs)
-		goto error;
+		goto error_dir;
 	proc_afs->owner = THIS_MODULE;
 
 	p = create_proc_entry("cells", 0, proc_afs);
 	if (!p)
-		goto error_proc;
+		goto error_cells;
 	p->proc_fops = &afs_proc_cells_fops;
 	p->owner = THIS_MODULE;
 
 	p = create_proc_entry("rootcell", 0, proc_afs);
 	if (!p)
-		goto error_cells;
+		goto error_rootcell;
 	p->proc_fops = &afs_proc_rootcell_fops;
 	p->owner = THIS_MODULE;
 
 	_leave(" = 0");
 	return 0;
 
- error_cells:
+error_rootcell:
  	remove_proc_entry("cells", proc_afs);
- error_proc:
+error_cells:
 	remove_proc_entry("fs/afs", NULL);
- error:
+error_dir:
 	_leave(" = -ENOMEM");
 	return -ENOMEM;
+}
 
-} /* end afs_proc_init() */
-
-/*****************************************************************************/
 /*
  * clean up the /proc/fs/afs/ directory
  */
 void afs_proc_cleanup(void)
 {
+	remove_proc_entry("rootcell", proc_afs);
 	remove_proc_entry("cells", proc_afs);
-
 	remove_proc_entry("fs/afs", NULL);
+}
 
-} /* end afs_proc_cleanup() */
-
-/*****************************************************************************/
 /*
  * open "/proc/fs/afs/cells" which provides a summary of extant cells
  */
@@ -199,9 +192,8 @@ static int afs_proc_cells_open(struct in
 	m->private = PDE(inode)->data;
 
 	return 0;
-} /* end afs_proc_cells_open() */
+}
 
-/*****************************************************************************/
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -225,9 +217,8 @@ static void *afs_proc_cells_start(struct
 			break;
 
 	return _p != &afs_proc_cells ? _p : NULL;
-} /* end afs_proc_cells_start() */
+}
 
-/*****************************************************************************/
 /*
  * move to next cell in cells list
  */
@@ -241,19 +232,16 @@ static void *afs_proc_cells_next(struct 
 	_p = v == (void *) 1 ? afs_proc_cells.next : _p->next;
 
 	return _p != &afs_proc_cells ? _p : NULL;
-} /* end afs_proc_cells_next() */
+}
 
-/*****************************************************************************/
 /*
  * clean up after reading from the cells list
  */
 static void afs_proc_cells_stop(struct seq_file *p, void *v)
 {
 	up_read(&afs_proc_cells_sem);
+}
 
-} /* end afs_proc_cells_stop() */
-
-/*****************************************************************************/
 /*
  * display a header line followed by a load of cell lines
  */
@@ -261,19 +249,18 @@ static int afs_proc_cells_show(struct se
 {
 	struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
 
-	/* display header on line 1 */
 	if (v == (void *) 1) {
+		/* display header on line 1 */
 		seq_puts(m, "USE NAME\n");
 		return 0;
 	}
 
 	/* display one cell per line on subsequent lines */
-	seq_printf(m, "%3d %s\n", atomic_read(&cell->usage), cell->name);
-
+	seq_printf(m, "%3d %s\n",
+		   atomic_read(&cell->usage), cell->name);
 	return 0;
-} /* end afs_proc_cells_show() */
+}
 
-/*****************************************************************************/
 /*
  * handle writes to /proc/fs/afs/cells
  * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]"
@@ -326,30 +313,32 @@ static ssize_t afs_proc_cells_write(stru
 
 	if (strcmp(kbuf, "add") == 0) {
 		struct afs_cell *cell;
-		ret = afs_cell_create(name, args, &cell);
-		if (ret < 0)
+
+		cell = afs_cell_create(name, args);
+		if (IS_ERR(cell)) {
+			ret = PTR_ERR(cell);
 			goto done;
+		}
 
+		afs_put_cell(cell);
 		printk("kAFS: Added new cell '%s'\n", name);
-	}
-	else {
+	} else {
 		goto inval;
 	}
 
 	ret = size;
 
- done:
+done:
 	kfree(kbuf);
 	_leave(" = %d", ret);
 	return ret;
 
- inval:
+inval:
 	ret = -EINVAL;
 	printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
 	goto done;
-} /* end afs_proc_cells_write() */
+}
 
-/*****************************************************************************/
 /*
  * Stubs for /proc/fs/afs/rootcell
  */
@@ -369,7 +358,6 @@ static ssize_t afs_proc_rootcell_read(st
 	return 0;
 }
 
-/*****************************************************************************/
 /*
  * handle writes to /proc/fs/afs/rootcell
  * - to initialize rootcell: echo "cell.name:192.168.231.14"
@@ -407,14 +395,13 @@ static ssize_t afs_proc_rootcell_write(s
 	if (ret >= 0)
 		ret = size;	/* consume everything, always */
 
- infault:
+infault:
 	kfree(kbuf);
- nomem:
+nomem:
 	_leave(" = %d", ret);
 	return ret;
-} /* end afs_proc_rootcell_write() */
+}
 
-/*****************************************************************************/
 /*
  * initialise /proc/fs/afs/<cell>/
  */
@@ -426,25 +413,25 @@ int afs_proc_cell_setup(struct afs_cell 
 
 	cell->proc_dir = proc_mkdir(cell->name, proc_afs);
 	if (!cell->proc_dir)
-		return -ENOMEM;
+		goto error_dir;
 
 	p = create_proc_entry("servers", 0, cell->proc_dir);
 	if (!p)
-		goto error_proc;
+		goto error_servers;
 	p->proc_fops = &afs_proc_cell_servers_fops;
 	p->owner = THIS_MODULE;
 	p->data = cell;
 
 	p = create_proc_entry("vlservers", 0, cell->proc_dir);
 	if (!p)
-		goto error_servers;
+		goto error_vlservers;
 	p->proc_fops = &afs_proc_cell_vlservers_fops;
 	p->owner = THIS_MODULE;
 	p->data = cell;
 
 	p = create_proc_entry("volumes", 0, cell->proc_dir);
 	if (!p)
-		goto error_vlservers;
+		goto error_volumes;
 	p->proc_fops = &afs_proc_cell_volumes_fops;
 	p->owner = THIS_MODULE;
 	p->data = cell;
@@ -452,17 +439,17 @@ int afs_proc_cell_setup(struct afs_cell 
 	_leave(" = 0");
 	return 0;
 
- error_vlservers:
+error_volumes:
 	remove_proc_entry("vlservers", cell->proc_dir);
- error_servers:
+error_vlservers:
 	remove_proc_entry("servers", cell->proc_dir);
- error_proc:
+error_servers:
 	remove_proc_entry(cell->name, proc_afs);
+error_dir:
 	_leave(" = -ENOMEM");
 	return -ENOMEM;
-} /* end afs_proc_cell_setup() */
+}
 
-/*****************************************************************************/
 /*
  * remove /proc/fs/afs/<cell>/
  */
@@ -476,9 +463,8 @@ void afs_proc_cell_remove(struct afs_cel
 	remove_proc_entry(cell->name, proc_afs);
 
 	_leave("");
-} /* end afs_proc_cell_remove() */
+}
 
-/*****************************************************************************/
 /*
  * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
  */
@@ -488,7 +474,7 @@ static int afs_proc_cell_volumes_open(st
 	struct seq_file *m;
 	int ret;
 
-	cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
+	cell = PDE(inode)->data;
 	if (!cell)
 		return -ENOENT;
 
@@ -500,25 +486,16 @@ static int afs_proc_cell_volumes_open(st
 	m->private = cell;
 
 	return 0;
-} /* end afs_proc_cell_volumes_open() */
+}
 
-/*****************************************************************************/
 /*
  * close the file and release the ref to the cell
  */
 static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
 {
-	struct afs_cell *cell = PDE(inode)->data;
-	int ret;
-
-	ret = seq_release(inode,file);
-
-	afs_put_cell(cell);
-
-	return ret;
-} /* end afs_proc_cell_volumes_release() */
+	return seq_release(inode, file);
+}
 
-/*****************************************************************************/
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -545,9 +522,8 @@ static void *afs_proc_cell_volumes_start
 			break;
 
 	return _p != &cell->vl_list ? _p : NULL;
-} /* end afs_proc_cell_volumes_start() */
+}
 
-/*****************************************************************************/
 /*
  * move to next cell in cells list
  */
@@ -562,12 +538,11 @@ static void *afs_proc_cell_volumes_next(
 	(*_pos)++;
 
 	_p = v;
-	_p = v == (void *) 1 ? cell->vl_list.next : _p->next;
+	_p = (v == (void *) 1) ? cell->vl_list.next : _p->next;
 
-	return _p != &cell->vl_list ? _p : NULL;
-} /* end afs_proc_cell_volumes_next() */
+	return (_p != &cell->vl_list) ? _p : NULL;
+}
 
-/*****************************************************************************/
 /*
  * clean up after reading from the cells list
  */
@@ -576,10 +551,18 @@ static void afs_proc_cell_volumes_stop(s
 	struct afs_cell *cell = p->private;
 
 	up_read(&cell->vl_sem);
+}
 
-} /* end afs_proc_cell_volumes_stop() */
+const char afs_vlocation_states[][4] = {
+	[AFS_VL_NEW]			= "New",
+	[AFS_VL_CREATING]		= "Crt",
+	[AFS_VL_VALID]			= "Val",
+	[AFS_VL_NO_VOLUME]		= "NoV",
+	[AFS_VL_UPDATING]		= "Upd",
+	[AFS_VL_VOLUME_DELETED]		= "Del",
+	[AFS_VL_UNCERTAIN]		= "Unc",
+};
 
-/*****************************************************************************/
 /*
  * display a header line followed by a load of volume lines
  */
@@ -590,23 +573,22 @@ static int afs_proc_cell_volumes_show(st
 
 	/* display header on line 1 */
 	if (v == (void *) 1) {
-		seq_puts(m, "USE VLID[0]  VLID[1]  VLID[2]  NAME\n");
+		seq_puts(m, "USE STT VLID[0]  VLID[1]  VLID[2]  NAME\n");
 		return 0;
 	}
 
 	/* display one cell per line on subsequent lines */
-	seq_printf(m, "%3d %08x %08x %08x %s\n",
+	seq_printf(m, "%3d %s %08x %08x %08x %s\n",
 		   atomic_read(&vlocation->usage),
+		   afs_vlocation_states[vlocation->state],
 		   vlocation->vldb.vid[0],
 		   vlocation->vldb.vid[1],
 		   vlocation->vldb.vid[2],
-		   vlocation->vldb.name
-		   );
+		   vlocation->vldb.name);
 
 	return 0;
-} /* end afs_proc_cell_volumes_show() */
+}
 
-/*****************************************************************************/
 /*
  * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume
  * location server
@@ -617,11 +599,11 @@ static int afs_proc_cell_vlservers_open(
 	struct seq_file *m;
 	int ret;
 
-	cell = afs_get_cell_maybe((struct afs_cell**)&PDE(inode)->data);
+	cell = PDE(inode)->data;
 	if (!cell)
 		return -ENOENT;
 
-	ret = seq_open(file,&afs_proc_cell_vlservers_ops);
+	ret = seq_open(file, &afs_proc_cell_vlservers_ops);
 	if (ret<0)
 		return ret;
 
@@ -629,26 +611,17 @@ static int afs_proc_cell_vlservers_open(
 	m->private = cell;
 
 	return 0;
-} /* end afs_proc_cell_vlservers_open() */
+}
 
-/*****************************************************************************/
 /*
  * close the file and release the ref to the cell
  */
 static int afs_proc_cell_vlservers_release(struct inode *inode,
 					   struct file *file)
 {
-	struct afs_cell *cell = PDE(inode)->data;
-	int ret;
-
-	ret = seq_release(inode,file);
-
-	afs_put_cell(cell);
-
-	return ret;
-} /* end afs_proc_cell_vlservers_release() */
+	return seq_release(inode, file);
+}
 
-/*****************************************************************************/
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -672,9 +645,8 @@ static void *afs_proc_cell_vlservers_sta
 		return NULL;
 
 	return &cell->vl_addrs[pos];
-} /* end afs_proc_cell_vlservers_start() */
+}
 
-/*****************************************************************************/
 /*
  * move to next cell in cells list
  */
@@ -692,9 +664,8 @@ static void *afs_proc_cell_vlservers_nex
 		return NULL;
 
 	return &cell->vl_addrs[pos];
-} /* end afs_proc_cell_vlservers_next() */
+}
 
-/*****************************************************************************/
 /*
  * clean up after reading from the cells list
  */
@@ -703,10 +674,8 @@ static void afs_proc_cell_vlservers_stop
 	struct afs_cell *cell = p->private;
 
 	up_read(&cell->vl_sem);
+}
 
-} /* end afs_proc_cell_vlservers_stop() */
-
-/*****************************************************************************/
 /*
  * display a header line followed by a load of volume lines
  */
@@ -722,11 +691,9 @@ static int afs_proc_cell_vlservers_show(
 
 	/* display one cell per line on subsequent lines */
 	seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr));
-
 	return 0;
-} /* end afs_proc_cell_vlservers_show() */
+}
 
-/*****************************************************************************/
 /*
  * open "/proc/fs/afs/<cell>/servers" which provides a summary of active
  * servers
@@ -737,7 +704,7 @@ static int afs_proc_cell_servers_open(st
 	struct seq_file *m;
 	int ret;
 
-	cell = afs_get_cell_maybe((struct afs_cell **) &PDE(inode)->data);
+	cell = PDE(inode)->data;
 	if (!cell)
 		return -ENOENT;
 
@@ -747,34 +714,24 @@ static int afs_proc_cell_servers_open(st
 
 	m = file->private_data;
 	m->private = cell;
-
 	return 0;
-} /* end afs_proc_cell_servers_open() */
+}
 
-/*****************************************************************************/
 /*
  * close the file and release the ref to the cell
  */
 static int afs_proc_cell_servers_release(struct inode *inode,
 					 struct file *file)
 {
-	struct afs_cell *cell = PDE(inode)->data;
-	int ret;
-
-	ret = seq_release(inode, file);
-
-	afs_put_cell(cell);
-
-	return ret;
-} /* end afs_proc_cell_servers_release() */
+	return seq_release(inode, file);
+}
 
-/*****************************************************************************/
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
  */
 static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
-	__acquires(m->private->sv_lock)
+	__acquires(m->private->servers_lock)
 {
 	struct list_head *_p;
 	struct afs_cell *cell = m->private;
@@ -783,7 +740,7 @@ static void *afs_proc_cell_servers_start
 	_enter("cell=%p pos=%Ld", cell, *_pos);
 
 	/* lock the list against modification */
-	read_lock(&cell->sv_lock);
+	read_lock(&cell->servers_lock);
 
 	/* allow for the header line */
 	if (!pos)
@@ -791,14 +748,13 @@ static void *afs_proc_cell_servers_start
 	pos--;
 
 	/* find the n'th element in the list */
-	list_for_each(_p, &cell->sv_list)
+	list_for_each(_p, &cell->servers)
 		if (!pos--)
 			break;
 
-	return _p != &cell->sv_list ? _p : NULL;
-} /* end afs_proc_cell_servers_start() */
+	return _p != &cell->servers ? _p : NULL;
+}
 
-/*****************************************************************************/
 /*
  * move to next cell in cells list
  */
@@ -813,25 +769,22 @@ static void *afs_proc_cell_servers_next(
 	(*_pos)++;
 
 	_p = v;
-	_p = v == (void *) 1 ? cell->sv_list.next : _p->next;
+	_p = v == (void *) 1 ? cell->servers.next : _p->next;
 
-	return _p != &cell->sv_list ? _p : NULL;
-} /* end afs_proc_cell_servers_next() */
+	return _p != &cell->servers ? _p : NULL;
+}
 
-/*****************************************************************************/
 /*
  * 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)
+	__releases(p->private->servers_lock)
 {
 	struct afs_cell *cell = p->private;
 
-	read_unlock(&cell->sv_lock);
-
-} /* end afs_proc_cell_servers_stop() */
+	read_unlock(&cell->servers_lock);
+}
 
-/*****************************************************************************/
 /*
  * display a header line followed by a load of volume lines
  */
@@ -849,10 +802,7 @@ static int afs_proc_cell_servers_show(st
 	/* display one cell per line on subsequent lines */
 	sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr));
 	seq_printf(m, "%3d %-15.15s %5d\n",
-		   atomic_read(&server->usage),
-		   ipaddr,
-		   server->fs_state
-		   );
+		   atomic_read(&server->usage), ipaddr, server->fs_state);
 
 	return 0;
-} /* end afs_proc_cell_servers_show() */
+}
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
new file mode 100644
index 0000000..222c1a3
--- /dev/null
+++ b/fs/afs/rxrpc.c
@@ -0,0 +1,782 @@
+/* Maintain an RxRPC server socket to do AFS communications through
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <rxrpc/packet.h>
+#include "internal.h"
+#include "afs_cm.h"
+
+static struct socket *afs_socket; /* my RxRPC socket */
+static struct workqueue_struct *afs_async_calls;
+static atomic_t afs_outstanding_calls;
+static atomic_t afs_outstanding_skbs;
+
+static void afs_wake_up_call_waiter(struct afs_call *);
+static int afs_wait_for_call_to_complete(struct afs_call *);
+static void afs_wake_up_async_call(struct afs_call *);
+static int afs_dont_wait_for_call_to_complete(struct afs_call *);
+static void afs_process_async_call(struct work_struct *);
+static void afs_rx_interceptor(struct sock *, unsigned long, struct sk_buff *);
+static int afs_deliver_cm_op_id(struct afs_call *, struct sk_buff *, bool);
+
+/* synchronous call management */
+const struct afs_wait_mode afs_sync_call = {
+	.rx_wakeup	= afs_wake_up_call_waiter,
+	.wait		= afs_wait_for_call_to_complete,
+};
+
+/* asynchronous call management */
+const struct afs_wait_mode afs_async_call = {
+	.rx_wakeup	= afs_wake_up_async_call,
+	.wait		= afs_dont_wait_for_call_to_complete,
+};
+
+/* asynchronous incoming call management */
+static const struct afs_wait_mode afs_async_incoming_call = {
+	.rx_wakeup	= afs_wake_up_async_call,
+};
+
+/* asynchronous incoming call initial processing */
+static const struct afs_call_type afs_RXCMxxxx = {
+	.name		= "CB.xxxx",
+	.deliver	= afs_deliver_cm_op_id,
+	.abort_to_error	= afs_abort_to_error,
+};
+
+static void afs_collect_incoming_call(struct work_struct *);
+
+static struct sk_buff_head afs_incoming_calls;
+static DECLARE_WORK(afs_collect_incoming_call_work, afs_collect_incoming_call);
+
+/*
+ * open an RxRPC socket and bind it to be a server for callback notifications
+ * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT
+ */
+int afs_open_socket(void)
+{
+	struct sockaddr_rxrpc srx;
+	struct socket *socket;
+	int ret;
+
+	_enter("");
+
+	skb_queue_head_init(&afs_incoming_calls);
+
+	afs_async_calls = create_singlethread_workqueue("kafsd");
+	if (!afs_async_calls) {
+		_leave(" = -ENOMEM [wq]");
+		return -ENOMEM;
+	}
+
+	ret = sock_create_kern(AF_RXRPC, SOCK_DGRAM, PF_INET, &socket);
+	if (ret < 0) {
+		destroy_workqueue(afs_async_calls);
+		_leave(" = %d [socket]", ret);
+		return ret;
+	}
+
+	socket->sk->sk_allocation = GFP_NOFS;
+
+	/* bind the callback manager's address to make this a server socket */
+	srx.srx_family			= AF_RXRPC;
+	srx.srx_service			= CM_SERVICE;
+	srx.transport_type		= SOCK_DGRAM;
+	srx.transport_len		= sizeof(srx.transport.sin);
+	srx.transport.sin.sin_family	= AF_INET;
+	srx.transport.sin.sin_port	= htons(AFS_CM_PORT);
+	memset(&srx.transport.sin.sin_addr, 0,
+	       sizeof(srx.transport.sin.sin_addr));
+
+	ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
+	if (ret < 0) {
+		sock_release(socket);
+		_leave(" = %d [bind]", ret);
+		return ret;
+	}
+
+	rxrpc_kernel_intercept_rx_messages(socket, afs_rx_interceptor);
+
+	afs_socket = socket;
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * close the RxRPC socket AFS was using
+ */
+void afs_close_socket(void)
+{
+	_enter("");
+
+	sock_release(afs_socket);
+
+	_debug("dework");
+	destroy_workqueue(afs_async_calls);
+
+	ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0);
+	ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0);
+	_leave("");
+}
+
+/*
+ * note that the data in a socket buffer is now delivered and that the buffer
+ * should be freed
+ */
+static void afs_data_delivered(struct sk_buff *skb)
+{
+	if (!skb) {
+		_debug("DLVR NULL [%d]", atomic_read(&afs_outstanding_skbs));
+		dump_stack();
+	} else {
+		_debug("DLVR %p{%u} [%d]",
+		       skb, skb->mark, atomic_read(&afs_outstanding_skbs));
+		if (atomic_dec_return(&afs_outstanding_skbs) == -1)
+			BUG();
+		rxrpc_kernel_data_delivered(skb);
+	}
+}
+
+/*
+ * free a socket buffer
+ */
+static void afs_free_skb(struct sk_buff *skb)
+{
+	if (!skb) {
+		_debug("FREE NULL [%d]", atomic_read(&afs_outstanding_skbs));
+		dump_stack();
+	} else {
+		_debug("FREE %p{%u} [%d]",
+		       skb, skb->mark, atomic_read(&afs_outstanding_skbs));
+		if (atomic_dec_return(&afs_outstanding_skbs) == -1)
+			BUG();
+		rxrpc_kernel_free_skb(skb);
+	}
+}
+
+/*
+ * free a call
+ */
+static void afs_free_call(struct afs_call *call)
+{
+	_debug("DONE %p{%s} [%d]",
+	       call, call->type->name, atomic_read(&afs_outstanding_calls));
+	if (atomic_dec_return(&afs_outstanding_calls) == -1)
+		BUG();
+
+	ASSERTCMP(call->rxcall, ==, NULL);
+	ASSERT(!work_pending(&call->async_work));
+	ASSERT(skb_queue_empty(&call->rx_queue));
+	ASSERT(call->type->name != NULL);
+
+	kfree(call->request);
+	kfree(call);
+}
+
+/*
+ * allocate a call with flat request and reply buffers
+ */
+struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type,
+				     size_t request_size, size_t reply_size)
+{
+	struct afs_call *call;
+
+	call = kzalloc(sizeof(*call), GFP_NOFS);
+	if (!call)
+		goto nomem_call;
+
+	_debug("CALL %p{%s} [%d]",
+	       call, type->name, atomic_read(&afs_outstanding_calls));
+	atomic_inc(&afs_outstanding_calls);
+
+	call->type = type;
+	call->request_size = request_size;
+	call->reply_max = reply_size;
+
+	if (request_size) {
+		call->request = kmalloc(request_size, GFP_NOFS);
+		if (!call->request)
+			goto nomem_free;
+	}
+
+	if (reply_size) {
+		call->buffer = kmalloc(reply_size, GFP_NOFS);
+		if (!call->buffer)
+			goto nomem_free;
+	}
+
+	init_waitqueue_head(&call->waitq);
+	skb_queue_head_init(&call->rx_queue);
+	return call;
+
+nomem_free:
+	afs_free_call(call);
+nomem_call:
+	return NULL;
+}
+
+/*
+ * clean up a call with flat buffer
+ */
+void afs_flat_call_destructor(struct afs_call *call)
+{
+	_enter("");
+
+	kfree(call->request);
+	call->request = NULL;
+	kfree(call->buffer);
+	call->buffer = NULL;
+}
+
+/*
+ * initiate a call
+ */
+int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
+		  const struct afs_wait_mode *wait_mode)
+{
+	struct sockaddr_rxrpc srx;
+	struct rxrpc_call *rxcall;
+	struct msghdr msg;
+	struct kvec iov[1];
+	int ret;
+
+	_enter("%x,{%d},", addr->s_addr, ntohs(call->port));
+
+	ASSERT(call->type != NULL);
+	ASSERT(call->type->name != NULL);
+
+	_debug("MAKE %p{%s} [%d]",
+	       call, call->type->name, atomic_read(&afs_outstanding_calls));
+
+	call->wait_mode = wait_mode;
+	INIT_WORK(&call->async_work, afs_process_async_call);
+
+	memset(&srx, 0, sizeof(srx));
+	srx.srx_family = AF_RXRPC;
+	srx.srx_service = call->service_id;
+	srx.transport_type = SOCK_DGRAM;
+	srx.transport_len = sizeof(srx.transport.sin);
+	srx.transport.sin.sin_family = AF_INET;
+	srx.transport.sin.sin_port = call->port;
+	memcpy(&srx.transport.sin.sin_addr, addr, 4);
+
+	/* create a call */
+	rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key,
+					 (unsigned long) call, gfp);
+	call->key = NULL;
+	if (IS_ERR(rxcall)) {
+		ret = PTR_ERR(rxcall);
+		goto error_kill_call;
+	}
+
+	call->rxcall = rxcall;
+
+	/* send the request */
+	iov[0].iov_base	= call->request;
+	iov[0].iov_len	= call->request_size;
+
+	msg.msg_name		= NULL;
+	msg.msg_namelen		= 0;
+	msg.msg_iov		= (struct iovec *) iov;
+	msg.msg_iovlen		= 1;
+	msg.msg_control		= NULL;
+	msg.msg_controllen	= 0;
+	msg.msg_flags		= 0;
+
+	/* have to change the state *before* sending the last packet as RxRPC
+	 * might give us the reply before it returns from sending the
+	 * request */
+	call->state = AFS_CALL_AWAIT_REPLY;
+	ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size);
+	if (ret < 0)
+		goto error_do_abort;
+
+	/* at this point, an async call may no longer exist as it may have
+	 * already completed */
+	return wait_mode->wait(call);
+
+error_do_abort:
+	rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT);
+	rxrpc_kernel_end_call(rxcall);
+	call->rxcall = NULL;
+error_kill_call:
+	call->type->destructor(call);
+	afs_free_call(call);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * handles intercepted messages that were arriving in the socket's Rx queue
+ * - called with the socket receive queue lock held to ensure message ordering
+ * - called with softirqs disabled
+ */
+static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,
+			       struct sk_buff *skb)
+{
+	struct afs_call *call = (struct afs_call *) user_call_ID;
+
+	_enter("%p,,%u", call, skb->mark);
+
+	_debug("ICPT %p{%u} [%d]",
+	       skb, skb->mark, atomic_read(&afs_outstanding_skbs));
+
+	ASSERTCMP(sk, ==, afs_socket->sk);
+	atomic_inc(&afs_outstanding_skbs);
+
+	if (!call) {
+		/* its an incoming call for our callback service */
+		skb_queue_tail(&afs_incoming_calls, skb);
+		schedule_work(&afs_collect_incoming_call_work);
+	} else {
+		/* route the messages directly to the appropriate call */
+		skb_queue_tail(&call->rx_queue, skb);
+		call->wait_mode->rx_wakeup(call);
+	}
+
+	_leave("");
+}
+
+/*
+ * deliver messages to a call
+ */
+static void afs_deliver_to_call(struct afs_call *call)
+{
+	struct sk_buff *skb;
+	bool last;
+	u32 abort_code;
+	int ret;
+
+	_enter("");
+
+	while ((call->state == AFS_CALL_AWAIT_REPLY ||
+		call->state == AFS_CALL_AWAIT_OP_ID ||
+		call->state == AFS_CALL_AWAIT_REQUEST ||
+		call->state == AFS_CALL_AWAIT_ACK) &&
+	       (skb = skb_dequeue(&call->rx_queue))) {
+		switch (skb->mark) {
+		case RXRPC_SKB_MARK_DATA:
+			_debug("Rcv DATA");
+			last = rxrpc_kernel_is_data_last(skb);
+			ret = call->type->deliver(call, skb, last);
+			switch (ret) {
+			case 0:
+				if (last &&
+				    call->state == AFS_CALL_AWAIT_REPLY)
+					call->state = AFS_CALL_COMPLETE;
+				break;
+			case -ENOTCONN:
+				abort_code = RX_CALL_DEAD;
+				goto do_abort;
+			case -ENOTSUPP:
+				abort_code = RX_INVALID_OPERATION;
+				goto do_abort;
+			default:
+				abort_code = RXGEN_CC_UNMARSHAL;
+				if (call->state != AFS_CALL_AWAIT_REPLY)
+					abort_code = RXGEN_SS_UNMARSHAL;
+			do_abort:
+				rxrpc_kernel_abort_call(call->rxcall,
+							abort_code);
+				call->error = ret;
+				call->state = AFS_CALL_ERROR;
+				break;
+			}
+			afs_data_delivered(skb);
+			skb = NULL;
+			continue;
+		case RXRPC_SKB_MARK_FINAL_ACK:
+			_debug("Rcv ACK");
+			call->state = AFS_CALL_COMPLETE;
+			break;
+		case RXRPC_SKB_MARK_BUSY:
+			_debug("Rcv BUSY");
+			call->error = -EBUSY;
+			call->state = AFS_CALL_BUSY;
+			break;
+		case RXRPC_SKB_MARK_REMOTE_ABORT:
+			abort_code = rxrpc_kernel_get_abort_code(skb);
+			call->error = call->type->abort_to_error(abort_code);
+			call->state = AFS_CALL_ABORTED;
+			_debug("Rcv ABORT %u -> %d", abort_code, call->error);
+			break;
+		case RXRPC_SKB_MARK_NET_ERROR:
+			call->error = -rxrpc_kernel_get_error_number(skb);
+			call->state = AFS_CALL_ERROR;
+			_debug("Rcv NET ERROR %d", call->error);
+			break;
+		case RXRPC_SKB_MARK_LOCAL_ERROR:
+			call->error = -rxrpc_kernel_get_error_number(skb);
+			call->state = AFS_CALL_ERROR;
+			_debug("Rcv LOCAL ERROR %d", call->error);
+			break;
+		default:
+			BUG();
+			break;
+		}
+
+		afs_free_skb(skb);
+	}
+
+	/* make sure the queue is empty if the call is done with (we might have
+	 * aborted the call early because of an unmarshalling error) */
+	if (call->state >= AFS_CALL_COMPLETE) {
+		while ((skb = skb_dequeue(&call->rx_queue)))
+			afs_free_skb(skb);
+		if (call->incoming) {
+			rxrpc_kernel_end_call(call->rxcall);
+			call->rxcall = NULL;
+			call->type->destructor(call);
+			afs_free_call(call);
+		}
+	}
+
+	_leave("");
+}
+
+/*
+ * wait synchronously for a call to complete
+ */
+static int afs_wait_for_call_to_complete(struct afs_call *call)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	DECLARE_WAITQUEUE(myself, current);
+
+	_enter("");
+
+	add_wait_queue(&call->waitq, &myself);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		/* deliver any messages that are in the queue */
+		if (!skb_queue_empty(&call->rx_queue)) {
+			__set_current_state(TASK_RUNNING);
+			afs_deliver_to_call(call);
+			continue;
+		}
+
+		ret = call->error;
+		if (call->state >= AFS_CALL_COMPLETE)
+			break;
+		ret = -EINTR;
+		if (signal_pending(current))
+			break;
+		schedule();
+	}
+
+	remove_wait_queue(&call->waitq, &myself);
+	__set_current_state(TASK_RUNNING);
+
+	/* kill the call */
+	if (call->state < AFS_CALL_COMPLETE) {
+		_debug("call incomplete");
+		rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD);
+		while ((skb = skb_dequeue(&call->rx_queue)))
+			afs_free_skb(skb);
+	}
+
+	_debug("call complete");
+	rxrpc_kernel_end_call(call->rxcall);
+	call->rxcall = NULL;
+	call->type->destructor(call);
+	afs_free_call(call);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * wake up a waiting call
+ */
+static void afs_wake_up_call_waiter(struct afs_call *call)
+{
+	wake_up(&call->waitq);
+}
+
+/*
+ * wake up an asynchronous call
+ */
+static void afs_wake_up_async_call(struct afs_call *call)
+{
+	_enter("");
+	queue_work(afs_async_calls, &call->async_work);
+}
+
+/*
+ * put a call into asynchronous mode
+ * - mustn't touch the call descriptor as the call my have completed by the
+ *   time we get here
+ */
+static int afs_dont_wait_for_call_to_complete(struct afs_call *call)
+{
+	_enter("");
+	return -EINPROGRESS;
+}
+
+/*
+ * delete an asynchronous call
+ */
+static void afs_delete_async_call(struct work_struct *work)
+{
+	struct afs_call *call =
+		container_of(work, struct afs_call, async_work);
+
+	_enter("");
+
+	afs_free_call(call);
+
+	_leave("");
+}
+
+/*
+ * perform processing on an asynchronous call
+ * - on a multiple-thread workqueue this work item may try to run on several
+ *   CPUs at the same time
+ */
+static void afs_process_async_call(struct work_struct *work)
+{
+	struct afs_call *call =
+		container_of(work, struct afs_call, async_work);
+
+	_enter("");
+
+	if (!skb_queue_empty(&call->rx_queue))
+		afs_deliver_to_call(call);
+
+	if (call->state >= AFS_CALL_COMPLETE && call->wait_mode) {
+		if (call->wait_mode->async_complete)
+			call->wait_mode->async_complete(call->reply,
+							call->error);
+		call->reply = NULL;
+
+		/* kill the call */
+		rxrpc_kernel_end_call(call->rxcall);
+		call->rxcall = NULL;
+		if (call->type->destructor)
+			call->type->destructor(call);
+
+		/* we can't just delete the call because the work item may be
+		 * queued */
+		PREPARE_WORK(&call->async_work, afs_delete_async_call);
+		queue_work(afs_async_calls, &call->async_work);
+	}
+
+	_leave("");
+}
+
+/*
+ * empty a socket buffer into a flat reply buffer
+ */
+void afs_transfer_reply(struct afs_call *call, struct sk_buff *skb)
+{
+	size_t len = skb->len;
+
+	if (skb_copy_bits(skb, 0, call->buffer + call->reply_size, len) < 0)
+		BUG();
+	call->reply_size += len;
+}
+
+/*
+ * accept the backlog of incoming calls
+ */
+static void afs_collect_incoming_call(struct work_struct *work)
+{
+	struct rxrpc_call *rxcall;
+	struct afs_call *call = NULL;
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&afs_incoming_calls))) {
+		_debug("new call");
+
+		/* don't need the notification */
+		afs_free_skb(skb);
+
+		if (!call) {
+			call = kzalloc(sizeof(struct afs_call), GFP_KERNEL);
+			if (!call) {
+				rxrpc_kernel_reject_call(afs_socket);
+				return;
+			}
+
+			INIT_WORK(&call->async_work, afs_process_async_call);
+			call->wait_mode = &afs_async_incoming_call;
+			call->type = &afs_RXCMxxxx;
+			init_waitqueue_head(&call->waitq);
+			skb_queue_head_init(&call->rx_queue);
+			call->state = AFS_CALL_AWAIT_OP_ID;
+
+			_debug("CALL %p{%s} [%d]",
+			       call, call->type->name,
+			       atomic_read(&afs_outstanding_calls));
+			atomic_inc(&afs_outstanding_calls);
+		}
+
+		rxcall = rxrpc_kernel_accept_call(afs_socket,
+						  (unsigned long) call);
+		if (!IS_ERR(rxcall)) {
+			call->rxcall = rxcall;
+			call = NULL;
+		}
+	}
+
+	if (call)
+		afs_free_call(call);
+}
+
+/*
+ * grab the operation ID from an incoming cache manager call
+ */
+static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb,
+				bool last)
+{
+	size_t len = skb->len;
+	void *oibuf = (void *) &call->operation_ID;
+
+	_enter("{%u},{%zu},%d", call->offset, len, last);
+
+	ASSERTCMP(call->offset, <, 4);
+
+	/* the operation ID forms the first four bytes of the request data */
+	len = min_t(size_t, len, 4 - call->offset);
+	if (skb_copy_bits(skb, 0, oibuf + call->offset, len) < 0)
+		BUG();
+	if (!pskb_pull(skb, len))
+		BUG();
+	call->offset += len;
+
+	if (call->offset < 4) {
+		if (last) {
+			_leave(" = -EBADMSG [op ID short]");
+			return -EBADMSG;
+		}
+		_leave(" = 0 [incomplete]");
+		return 0;
+	}
+
+	call->state = AFS_CALL_AWAIT_REQUEST;
+
+	/* ask the cache manager to route the call (it'll change the call type
+	 * if successful) */
+	if (!afs_cm_incoming_call(call))
+		return -ENOTSUPP;
+
+	/* pass responsibility for the remainer of this message off to the
+	 * cache manager op */
+	return call->type->deliver(call, skb, last);
+}
+
+/*
+ * send an empty reply
+ */
+void afs_send_empty_reply(struct afs_call *call)
+{
+	struct msghdr msg;
+	struct iovec iov[1];
+
+	_enter("");
+
+	iov[0].iov_base		= NULL;
+	iov[0].iov_len		= 0;
+	msg.msg_name		= NULL;
+	msg.msg_namelen		= 0;
+	msg.msg_iov		= iov;
+	msg.msg_iovlen		= 0;
+	msg.msg_control		= NULL;
+	msg.msg_controllen	= 0;
+	msg.msg_flags		= 0;
+
+	call->state = AFS_CALL_AWAIT_ACK;
+	switch (rxrpc_kernel_send_data(call->rxcall, &msg, 0)) {
+	case 0:
+		_leave(" [replied]");
+		return;
+
+	case -ENOMEM:
+		_debug("oom");
+		rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
+	default:
+		rxrpc_kernel_end_call(call->rxcall);
+		call->rxcall = NULL;
+		call->type->destructor(call);
+		afs_free_call(call);
+		_leave(" [error]");
+		return;
+	}
+}
+
+/*
+ * send a simple reply
+ */
+void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
+{
+	struct msghdr msg;
+	struct iovec iov[1];
+
+	_enter("");
+
+	iov[0].iov_base		= (void *) buf;
+	iov[0].iov_len		= len;
+	msg.msg_name		= NULL;
+	msg.msg_namelen		= 0;
+	msg.msg_iov		= iov;
+	msg.msg_iovlen		= 1;
+	msg.msg_control		= NULL;
+	msg.msg_controllen	= 0;
+	msg.msg_flags		= 0;
+
+	call->state = AFS_CALL_AWAIT_ACK;
+	switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
+	case 0:
+		_leave(" [replied]");
+		return;
+
+	case -ENOMEM:
+		_debug("oom");
+		rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
+	default:
+		rxrpc_kernel_end_call(call->rxcall);
+		call->rxcall = NULL;
+		call->type->destructor(call);
+		afs_free_call(call);
+		_leave(" [error]");
+		return;
+	}
+}
+
+/*
+ * extract a piece of data from the received data socket buffers
+ */
+int afs_extract_data(struct afs_call *call, struct sk_buff *skb,
+		     bool last, void *buf, size_t count)
+{
+	size_t len = skb->len;
+
+	_enter("{%u},{%zu},%d,,%zu", call->offset, len, last, count);
+
+	ASSERTCMP(call->offset, <, count);
+
+	len = min_t(size_t, len, count - call->offset);
+	if (skb_copy_bits(skb, 0, buf + call->offset, len) < 0 ||
+	    !pskb_pull(skb, len))
+		BUG();
+	call->offset += len;
+
+	if (call->offset < count) {
+		if (last) {
+			_leave(" = -EBADMSG [%d < %zu]", call->offset, count);
+			return -EBADMSG;
+		}
+		_leave(" = -EAGAIN");
+		return -EAGAIN;
+	}
+	return 0;
+}
diff --git a/fs/afs/security.c b/fs/afs/security.c
new file mode 100644
index 0000000..f9f424d
--- /dev/null
+++ b/fs/afs/security.c
@@ -0,0 +1,356 @@
+/* AFS security handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <keys/rxrpc-type.h>
+#include "internal.h"
+
+/*
+ * get a key
+ */
+struct key *afs_request_key(struct afs_cell *cell)
+{
+	struct key *key;
+
+	_enter("{%x}", key_serial(cell->anonymous_key));
+
+	_debug("key %s", cell->anonymous_key->description);
+	key = request_key(&key_type_rxrpc, cell->anonymous_key->description,
+			  NULL);
+	if (IS_ERR(key)) {
+		if (PTR_ERR(key) != -ENOKEY) {
+			_leave(" = %ld", PTR_ERR(key));
+			return key;
+		}
+
+		/* act as anonymous user */
+		_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
+		return key_get(cell->anonymous_key);
+	} else {
+		/* act as authorised user */
+		_leave(" = {%x} [auth]", key_serial(key));
+		return key;
+	}
+}
+
+/*
+ * dispose of a permits list
+ */
+void afs_zap_permits(struct rcu_head *rcu)
+{
+	struct afs_permits *permits =
+		container_of(rcu, struct afs_permits, rcu);
+	int loop;
+
+	_enter("{%d}", permits->count);
+
+	for (loop = permits->count - 1; loop >= 0; loop--)
+		key_put(permits->permits[loop].key);
+	kfree(permits);
+}
+
+/*
+ * dispose of a permits list in which all the key pointers have been copied
+ */
+static void afs_dispose_of_permits(struct rcu_head *rcu)
+{
+	struct afs_permits *permits =
+		container_of(rcu, struct afs_permits, rcu);
+
+	_enter("{%d}", permits->count);
+
+	kfree(permits);
+}
+
+/*
+ * get the authorising vnode - this is the specified inode itself if it's a
+ * directory or it's the parent directory if the specified inode is a file or
+ * symlink
+ * - the caller must release the ref on the inode
+ */
+static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
+					    struct key *key)
+{
+	struct afs_vnode *auth_vnode;
+	struct inode *auth_inode;
+
+	_enter("");
+
+	if (S_ISDIR(vnode->vfs_inode.i_mode)) {
+		auth_inode = igrab(&vnode->vfs_inode);
+		ASSERT(auth_inode != NULL);
+	} else {
+		auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
+				      &vnode->status.parent, NULL, NULL);
+		if (IS_ERR(auth_inode))
+			return ERR_PTR(PTR_ERR(auth_inode));
+	}
+
+	auth_vnode = AFS_FS_I(auth_inode);
+	_leave(" = {%x}", auth_vnode->fid.vnode);
+	return auth_vnode;
+}
+
+/*
+ * clear the permit cache on a directory vnode
+ */
+void afs_clear_permits(struct afs_vnode *vnode)
+{
+	struct afs_permits *permits;
+
+	_enter("{%x}", vnode->fid.vnode);
+
+	mutex_lock(&vnode->permits_lock);
+	permits = vnode->permits;
+	rcu_assign_pointer(vnode->permits, NULL);
+	mutex_unlock(&vnode->permits_lock);
+
+	if (permits)
+		call_rcu(&permits->rcu, afs_zap_permits);
+	_leave("");
+}
+
+/*
+ * add the result obtained for a vnode to its or its parent directory's cache
+ * for the key used to access it
+ */
+void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order)
+{
+	struct afs_permits *permits, *xpermits;
+	struct afs_permit *permit;
+	struct afs_vnode *auth_vnode;
+	int count, loop;
+
+	_enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order);
+
+	auth_vnode = afs_get_auth_inode(vnode, key);
+	if (IS_ERR(auth_vnode)) {
+		_leave(" [get error %ld]", PTR_ERR(auth_vnode));
+		return;
+	}
+
+	mutex_lock(&auth_vnode->permits_lock);
+
+	/* guard against a rename being detected whilst we waited for the
+	 * lock */
+	if (memcmp(&auth_vnode->fid, &vnode->status.parent,
+		   sizeof(struct afs_fid)) != 0) {
+		_debug("renamed");
+		goto out_unlock;
+	}
+
+	/* have to be careful as the directory's callback may be broken between
+	 * us receiving the status we're trying to cache and us getting the
+	 * lock to update the cache for the status */
+	if (auth_vnode->acl_order - acl_order > 0) {
+		_debug("ACL changed?");
+		goto out_unlock;
+	}
+
+	/* always update the anonymous mask */
+	_debug("anon access %x", vnode->status.anon_access);
+	auth_vnode->status.anon_access = vnode->status.anon_access;
+	if (key == vnode->volume->cell->anonymous_key)
+		goto out_unlock;
+
+	xpermits = auth_vnode->permits;
+	count = 0;
+	if (xpermits) {
+		/* see if the permit is already in the list
+		 * - if it is then we just amend the list
+		 */
+		count = xpermits->count;
+		permit = xpermits->permits;
+		for (loop = count; loop > 0; loop--) {
+			if (permit->key == key) {
+				permit->access_mask =
+					vnode->status.caller_access;
+				goto out_unlock;
+			}
+			permit++;
+		}
+	}
+
+	permits = kmalloc(sizeof(*permits) + sizeof(*permit) * (count + 1),
+			  GFP_NOFS);
+	if (!permits)
+		goto out_unlock;
+
+	memcpy(permits->permits, xpermits->permits,
+	       count * sizeof(struct afs_permit));
+
+	_debug("key %x access %x",
+	       key_serial(key), vnode->status.caller_access);
+	permits->permits[count].access_mask = vnode->status.caller_access;
+	permits->permits[count].key = key_get(key);
+	permits->count = count + 1;
+
+	rcu_assign_pointer(auth_vnode->permits, permits);
+	if (xpermits)
+		call_rcu(&xpermits->rcu, afs_dispose_of_permits);
+
+out_unlock:
+	mutex_unlock(&auth_vnode->permits_lock);
+	iput(&auth_vnode->vfs_inode);
+	_leave("");
+}
+
+/*
+ * check with the fileserver to see if the directory or parent directory is
+ * permitted to be accessed with this authorisation, and if so, what access it
+ * is granted
+ */
+static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
+			    afs_access_t *_access)
+{
+	struct afs_permits *permits;
+	struct afs_permit *permit;
+	struct afs_vnode *auth_vnode;
+	bool valid;
+	int loop, ret;
+
+	_enter("");
+
+	auth_vnode = afs_get_auth_inode(vnode, key);
+	if (IS_ERR(auth_vnode)) {
+		*_access = 0;
+		_leave(" = %ld", PTR_ERR(auth_vnode));
+		return PTR_ERR(auth_vnode);
+	}
+
+	ASSERT(S_ISDIR(auth_vnode->vfs_inode.i_mode));
+
+	/* check the permits to see if we've got one yet */
+	if (key == auth_vnode->volume->cell->anonymous_key) {
+		_debug("anon");
+		*_access = auth_vnode->status.anon_access;
+		valid = true;
+	} else {
+		valid = false;
+		rcu_read_lock();
+		permits = rcu_dereference(auth_vnode->permits);
+		if (permits) {
+			permit = permits->permits;
+			for (loop = permits->count; loop > 0; loop--) {
+				if (permit->key == key) {
+					_debug("found in cache");
+					*_access = permit->access_mask;
+					valid = true;
+					break;
+				}
+				permit++;
+			}
+		}
+		rcu_read_unlock();
+	}
+
+	if (!valid) {
+		/* check the status on the file we're actually interested in
+		 * (the post-processing will cache the result on auth_vnode) */
+		_debug("no valid permit");
+
+		set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+		ret = afs_vnode_fetch_status(vnode, auth_vnode, key);
+		if (ret < 0) {
+			iput(&auth_vnode->vfs_inode);
+			*_access = 0;
+			_leave(" = %d", ret);
+			return ret;
+		}
+	}
+
+	*_access = vnode->status.caller_access;
+	iput(&auth_vnode->vfs_inode);
+	_leave(" = 0 [access %x]", *_access);
+	return 0;
+}
+
+/*
+ * check the permissions on an AFS file
+ * - AFS ACLs are attached to directories only, and a file is controlled by its
+ *   parent directory's ACL
+ */
+int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+	afs_access_t access;
+	struct key *key;
+	int ret;
+
+	_enter("{{%x:%x},%lx},%x,",
+	       vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
+
+	key = afs_request_key(vnode->volume->cell);
+	if (IS_ERR(key)) {
+		_leave(" = %ld [key]", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	/* if the promise has expired, we need to check the server again */
+	if (!vnode->cb_promised) {
+		_debug("not promised");
+		ret = afs_vnode_fetch_status(vnode, NULL, key);
+		if (ret < 0)
+			goto error;
+		_debug("new promise [fl=%lx]", vnode->flags);
+	}
+
+	/* check the permits to see if we've got one yet */
+	ret = afs_check_permit(vnode, key, &access);
+	if (ret < 0)
+		goto error;
+
+	/* interpret the access mask */
+	_debug("REQ %x ACC %x on %s",
+	       mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file");
+
+	if (S_ISDIR(inode->i_mode)) {
+		if (mask & MAY_EXEC) {
+			if (!(access & AFS_ACE_LOOKUP))
+				goto permission_denied;
+		} else if (mask & MAY_READ) {
+			if (!(access & AFS_ACE_READ))
+				goto permission_denied;
+		} else if (mask & MAY_WRITE) {
+			if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */
+					AFS_ACE_INSERT | /* create, mkdir, symlink, rename to */
+					AFS_ACE_WRITE))) /* chmod */
+				goto permission_denied;
+		} else {
+			BUG();
+		}
+	} else {
+		if (!(access & AFS_ACE_LOOKUP))
+			goto permission_denied;
+		if (mask & (MAY_EXEC | MAY_READ)) {
+			if (!(access & AFS_ACE_READ))
+				goto permission_denied;
+		} else if (mask & MAY_WRITE) {
+			if (!(access & AFS_ACE_WRITE))
+				goto permission_denied;
+		}
+	}
+
+	key_put(key);
+	ret = generic_permission(inode, mask, NULL);
+	_leave(" = %d", ret);
+	return ret;
+
+permission_denied:
+	ret = -EACCES;
+error:
+	key_put(key);
+	_leave(" = %d", ret);
+	return ret;
+}
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 44aff81..96bb23b 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -1,6 +1,6 @@
-/* server.c: AFS server record management
+/* AFS server record management
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -11,489 +11,314 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include "volume.h"
-#include "cell.h"
-#include "server.h"
-#include "transport.h"
-#include "vlclient.h"
-#include "kafstimod.h"
 #include "internal.h"
 
-DEFINE_SPINLOCK(afs_server_peer_lock);
+unsigned afs_server_timeout = 10;	/* server timeout in seconds */
 
-#define FS_SERVICE_ID		1	/* AFS Volume Location Service ID */
-#define VL_SERVICE_ID		52	/* AFS Volume Location Service ID */
+static void afs_reap_server(struct work_struct *);
 
-static void __afs_server_timeout(struct afs_timer *timer)
+/* tree of all the servers, indexed by IP address */
+static struct rb_root afs_servers = RB_ROOT;
+static DEFINE_RWLOCK(afs_servers_lock);
+
+/* LRU list of all the servers not currently in use */
+static LIST_HEAD(afs_server_graveyard);
+static DEFINE_SPINLOCK(afs_server_graveyard_lock);
+static DECLARE_DELAYED_WORK(afs_server_reaper, afs_reap_server);
+
+/*
+ * install a server record in the master tree
+ */
+static int afs_install_server(struct afs_server *server)
 {
-	struct afs_server *server =
-		list_entry(timer, struct afs_server, timeout);
+	struct afs_server *xserver;
+	struct rb_node **pp, *p;
+	int ret;
 
-	_debug("SERVER TIMEOUT [%p{u=%d}]",
-	       server, atomic_read(&server->usage));
+	_enter("%p", server);
 
-	afs_server_do_timeout(server);
-}
+	write_lock(&afs_servers_lock);
+
+	ret = -EEXIST;
+	pp = &afs_servers.rb_node;
+	p = NULL;
+	while (*pp) {
+		p = *pp;
+		_debug("- consider %p", p);
+		xserver = rb_entry(p, struct afs_server, master_rb);
+		if (server->addr.s_addr < xserver->addr.s_addr)
+			pp = &(*pp)->rb_left;
+		else if (server->addr.s_addr > xserver->addr.s_addr)
+			pp = &(*pp)->rb_right;
+		else
+			goto error;
+	}
 
-static const struct afs_timer_ops afs_server_timer_ops = {
-	.timed_out	= __afs_server_timeout,
-};
+	rb_link_node(&server->master_rb, p, pp);
+	rb_insert_color(&server->master_rb, &afs_servers);
+	ret = 0;
+
+error:
+	write_unlock(&afs_servers_lock);
+	return ret;
+}
 
-/*****************************************************************************/
 /*
- * lookup a server record in a cell
- * - TODO: search the cell's server list
+ * allocate a new server record
  */
-int afs_server_lookup(struct afs_cell *cell, const struct in_addr *addr,
-		      struct afs_server **_server)
+static struct afs_server *afs_alloc_server(struct afs_cell *cell,
+					   const struct in_addr *addr)
 {
-	struct afs_server *server, *active, *zombie;
-	int loop;
+	struct afs_server *server;
 
-	_enter("%p,%08x,", cell, ntohl(addr->s_addr));
+	_enter("");
 
-	/* allocate and initialise a server record */
 	server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);
-	if (!server) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
+	if (server) {
+		atomic_set(&server->usage, 1);
+		server->cell = cell;
+
+		INIT_LIST_HEAD(&server->link);
+		INIT_LIST_HEAD(&server->grave);
+		init_rwsem(&server->sem);
+		spin_lock_init(&server->fs_lock);
+		server->fs_vnodes = RB_ROOT;
+		server->cb_promises = RB_ROOT;
+		spin_lock_init(&server->cb_lock);
+		init_waitqueue_head(&server->cb_break_waitq);
+		INIT_DELAYED_WORK(&server->cb_break_work,
+				  afs_dispatch_give_up_callbacks);
+
+		memcpy(&server->addr, addr, sizeof(struct in_addr));
+		server->addr.s_addr = addr->s_addr;
 	}
 
-	atomic_set(&server->usage, 1);
-
-	INIT_LIST_HEAD(&server->link);
-	init_rwsem(&server->sem);
-	INIT_LIST_HEAD(&server->fs_callq);
-	spin_lock_init(&server->fs_lock);
-	INIT_LIST_HEAD(&server->cb_promises);
-	spin_lock_init(&server->cb_lock);
-
-	for (loop = 0; loop < AFS_SERVER_CONN_LIST_SIZE; loop++)
-		server->fs_conn_cnt[loop] = 4;
+	_leave(" = %p{%d}", server, atomic_read(&server->usage));
+	return server;
+}
 
-	memcpy(&server->addr, addr, sizeof(struct in_addr));
-	server->addr.s_addr = addr->s_addr;
+/*
+ * get an FS-server record for a cell
+ */
+struct afs_server *afs_lookup_server(struct afs_cell *cell,
+				     const struct in_addr *addr)
+{
+	struct afs_server *server, *candidate;
 
-	afs_timer_init(&server->timeout, &afs_server_timer_ops);
+	_enter("%p,"NIPQUAD_FMT, cell, NIPQUAD(addr->s_addr));
 
-	/* add to the cell */
-	write_lock(&cell->sv_lock);
+	/* quick scan of the list to see if we already have the server */
+	read_lock(&cell->servers_lock);
 
-	/* check the active list */
-	list_for_each_entry(active, &cell->sv_list, link) {
-		if (active->addr.s_addr == addr->s_addr)
-			goto use_active_server;
+	list_for_each_entry(server, &cell->servers, link) {
+		if (server->addr.s_addr == addr->s_addr)
+			goto found_server_quickly;
 	}
+	read_unlock(&cell->servers_lock);
 
-	/* check the inactive list */
-	spin_lock(&cell->sv_gylock);
-	list_for_each_entry(zombie, &cell->sv_graveyard, link) {
-		if (zombie->addr.s_addr == addr->s_addr)
-			goto resurrect_server;
+	candidate = afs_alloc_server(cell, addr);
+	if (!candidate) {
+		_leave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
 	}
-	spin_unlock(&cell->sv_gylock);
 
-	afs_get_cell(cell);
-	server->cell = cell;
-	list_add_tail(&server->link, &cell->sv_list);
+	write_lock(&cell->servers_lock);
 
-	write_unlock(&cell->sv_lock);
+	/* check the cell's server list again */
+	list_for_each_entry(server, &cell->servers, link) {
+		if (server->addr.s_addr == addr->s_addr)
+			goto found_server;
+	}
 
-	*_server = server;
-	_leave(" = 0 (%p)", server);
-	return 0;
+	_debug("new");
+	server = candidate;
+	if (afs_install_server(server) < 0)
+		goto server_in_two_cells;
 
-	/* found a matching active server */
- use_active_server:
-	_debug("active server");
-	afs_get_server(active);
-	write_unlock(&cell->sv_lock);
+	afs_get_cell(cell);
+	list_add_tail(&server->link, &cell->servers);
+
+	write_unlock(&cell->servers_lock);
+	_leave(" = %p{%d}", server, atomic_read(&server->usage));
+	return server;
+
+	/* found a matching server quickly */
+found_server_quickly:
+	_debug("found quickly");
+	afs_get_server(server);
+	read_unlock(&cell->servers_lock);
+no_longer_unused:
+	if (!list_empty(&server->grave)) {
+		spin_lock(&afs_server_graveyard_lock);
+		list_del_init(&server->grave);
+		spin_unlock(&afs_server_graveyard_lock);
+	}
+	_leave(" = %p{%d}", server, atomic_read(&server->usage));
+	return server;
+
+	/* found a matching server on the second pass */
+found_server:
+	_debug("found");
+	afs_get_server(server);
+	write_unlock(&cell->servers_lock);
+	kfree(candidate);
+	goto no_longer_unused;
+
+	/* found a server that seems to be in two cells */
+server_in_two_cells:
+	write_unlock(&cell->servers_lock);
+	kfree(candidate);
+	printk(KERN_NOTICE "kAFS:"
+	       " Server "NIPQUAD_FMT" appears to be in two cells\n",
+	       NIPQUAD(*addr));
+	_leave(" = -EEXIST");
+	return ERR_PTR(-EEXIST);
+}
 
-	kfree(server);
+/*
+ * look up a server by its IP address
+ */
+struct afs_server *afs_find_server(const struct in_addr *_addr)
+{
+	struct afs_server *server = NULL;
+	struct rb_node *p;
+	struct in_addr addr = *_addr;
 
-	*_server = active;
-	_leave(" = 0 (%p)", active);
-	return 0;
+	_enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr));
 
-	/* found a matching server in the graveyard, so resurrect it and
-	 * dispose of the new record */
- resurrect_server:
-	_debug("resurrecting server");
+	read_lock(&afs_servers_lock);
 
-	list_move_tail(&zombie->link, &cell->sv_list);
-	afs_get_server(zombie);
-	afs_kafstimod_del_timer(&zombie->timeout);
-	spin_unlock(&cell->sv_gylock);
-	write_unlock(&cell->sv_lock);
+	p = afs_servers.rb_node;
+	while (p) {
+		server = rb_entry(p, struct afs_server, master_rb);
 
-	kfree(server);
+		_debug("- consider %p", p);
 
-	*_server = zombie;
-	_leave(" = 0 (%p)", zombie);
-	return 0;
+		if (addr.s_addr < server->addr.s_addr) {
+			p = p->rb_left;
+		} else if (addr.s_addr > server->addr.s_addr) {
+			p = p->rb_right;
+		} else {
+			afs_get_server(server);
+			goto found;
+		}
+	}
 
-} /* end afs_server_lookup() */
+	server = NULL;
+found:
+	read_unlock(&afs_servers_lock);
+	ASSERTIFCMP(server, server->addr.s_addr, ==, addr.s_addr);
+	_leave(" = %p", server);
+	return server;
+}
 
-/*****************************************************************************/
 /*
  * destroy a server record
  * - removes from the cell list
  */
 void afs_put_server(struct afs_server *server)
 {
-	struct afs_cell *cell;
-
 	if (!server)
 		return;
 
-	_enter("%p", server);
-
-	cell = server->cell;
+	_enter("%p{%d}", server, atomic_read(&server->usage));
 
-	/* sanity check */
-	BUG_ON(atomic_read(&server->usage) <= 0);
+	_debug("PUT SERVER %d", atomic_read(&server->usage));
 
-	/* to prevent a race, the decrement and the dequeue must be effectively
-	 * atomic */
-	write_lock(&cell->sv_lock);
+	ASSERTCMP(atomic_read(&server->usage), >, 0);
 
 	if (likely(!atomic_dec_and_test(&server->usage))) {
-		write_unlock(&cell->sv_lock);
 		_leave("");
 		return;
 	}
 
-	spin_lock(&cell->sv_gylock);
-	list_move_tail(&server->link, &cell->sv_graveyard);
+	afs_flush_callback_breaks(server);
 
-	/* time out in 10 secs */
-	afs_kafstimod_add_timer(&server->timeout, 10 * HZ);
-
-	spin_unlock(&cell->sv_gylock);
-	write_unlock(&cell->sv_lock);
-
-	_leave(" [killed]");
-} /* end afs_put_server() */
+	spin_lock(&afs_server_graveyard_lock);
+	if (atomic_read(&server->usage) == 0) {
+		list_move_tail(&server->grave, &afs_server_graveyard);
+		server->time_of_death = get_seconds();
+		schedule_delayed_work(&afs_server_reaper,
+				      afs_server_timeout * HZ);
+	}
+	spin_unlock(&afs_server_graveyard_lock);
+	_leave(" [dead]");
+}
 
-/*****************************************************************************/
 /*
- * timeout server record
- * - removes from the cell's graveyard if the usage count is zero
+ * destroy a dead server
  */
-void afs_server_do_timeout(struct afs_server *server)
+static void afs_destroy_server(struct afs_server *server)
 {
-	struct rxrpc_peer *peer;
-	struct afs_cell *cell;
-	int loop;
-
 	_enter("%p", server);
 
-	cell = server->cell;
-
-	BUG_ON(atomic_read(&server->usage) < 0);
-
-	/* remove from graveyard if still dead */
-	spin_lock(&cell->vl_gylock);
-	if (atomic_read(&server->usage) == 0)
-		list_del_init(&server->link);
-	else
-		server = NULL;
-	spin_unlock(&cell->vl_gylock);
-
-	if (!server) {
-		_leave("");
-		return; /* resurrected */
-	}
-
-	/* we can now destroy it properly */
-	afs_put_cell(cell);
-
-	/* uncross-point the structs under a global lock */
-	spin_lock(&afs_server_peer_lock);
-	peer = server->peer;
-	if (peer) {
-		server->peer = NULL;
-		peer->user = NULL;
-	}
-	spin_unlock(&afs_server_peer_lock);
-
-	/* finish cleaning up the server */
-	for (loop = AFS_SERVER_CONN_LIST_SIZE - 1; loop >= 0; loop--)
-		if (server->fs_conn[loop])
-			rxrpc_put_connection(server->fs_conn[loop]);
-
-	if (server->vlserver)
-		rxrpc_put_connection(server->vlserver);
+	ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
+	ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
+	ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
+	ASSERTCMP(atomic_read(&server->cb_break_n), ==, 0);
 
+	afs_put_cell(server->cell);
 	kfree(server);
+}
 
-	_leave(" [destroyed]");
-} /* end afs_server_do_timeout() */
-
-/*****************************************************************************/
 /*
- * get a callslot on a connection to the fileserver on the specified server
+ * reap dead server records
  */
-int afs_server_request_callslot(struct afs_server *server,
-				struct afs_server_callslot *callslot)
+static void afs_reap_server(struct work_struct *work)
 {
-	struct afs_server_callslot *pcallslot;
-	struct rxrpc_connection *conn;
-	int nconn, ret;
-
-	_enter("%p,",server);
-
-	INIT_LIST_HEAD(&callslot->link);
-	callslot->task = current;
-	callslot->conn = NULL;
-	callslot->nconn = -1;
-	callslot->ready = 0;
-
-	ret = 0;
-	conn = NULL;
-
-	/* get hold of a callslot first */
-	spin_lock(&server->fs_lock);
-
-	/* resurrect the server if it's death timeout has expired */
-	if (server->fs_state) {
-		if (time_before(jiffies, server->fs_dead_jif)) {
-			ret = server->fs_state;
-			spin_unlock(&server->fs_lock);
-			_leave(" = %d [still dead]", ret);
-			return ret;
+	LIST_HEAD(corpses);
+	struct afs_server *server;
+	unsigned long delay, expiry;
+	time_t now;
+
+	now = get_seconds();
+	spin_lock(&afs_server_graveyard_lock);
+
+	while (!list_empty(&afs_server_graveyard)) {
+		server = list_entry(afs_server_graveyard.next,
+				    struct afs_server, grave);
+
+		/* the queue is ordered most dead first */
+		expiry = server->time_of_death + afs_server_timeout;
+		if (expiry > now) {
+			delay = (expiry - now) * HZ;
+			if (!schedule_delayed_work(&afs_server_reaper, delay)) {
+				cancel_delayed_work(&afs_server_reaper);
+				schedule_delayed_work(&afs_server_reaper,
+						      delay);
+			}
+			break;
 		}
 
-		server->fs_state = 0;
-	}
-
-	/* try and find a connection that has spare callslots */
-	for (nconn = 0; nconn < AFS_SERVER_CONN_LIST_SIZE; nconn++) {
-		if (server->fs_conn_cnt[nconn] > 0) {
-			server->fs_conn_cnt[nconn]--;
-			spin_unlock(&server->fs_lock);
-			callslot->nconn = nconn;
-			goto obtained_slot;
+		write_lock(&server->cell->servers_lock);
+		write_lock(&afs_servers_lock);
+		if (atomic_read(&server->usage) > 0) {
+			list_del_init(&server->grave);
+		} else {
+			list_move_tail(&server->grave, &corpses);
+			list_del_init(&server->link);
+			rb_erase(&server->master_rb, &afs_servers);
 		}
+		write_unlock(&afs_servers_lock);
+		write_unlock(&server->cell->servers_lock);
 	}
 
-	/* none were available - wait interruptibly for one to become
-	 * available */
-	set_current_state(TASK_INTERRUPTIBLE);
-	list_add_tail(&callslot->link, &server->fs_callq);
-	spin_unlock(&server->fs_lock);
-
-	while (!callslot->ready && !signal_pending(current)) {
-		schedule();
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-
-	set_current_state(TASK_RUNNING);
-
-	/* even if we were interrupted we may still be queued */
-	if (!callslot->ready) {
-		spin_lock(&server->fs_lock);
-		list_del_init(&callslot->link);
-		spin_unlock(&server->fs_lock);
-	}
-
-	nconn = callslot->nconn;
+	spin_unlock(&afs_server_graveyard_lock);
 
-	/* if interrupted, we must release any slot we also got before
-	 * returning an error */
-	if (signal_pending(current)) {
-		ret = -EINTR;
-		goto error_release;
+	/* now reap the corpses we've extracted */
+	while (!list_empty(&corpses)) {
+		server = list_entry(corpses.next, struct afs_server, grave);
+		list_del(&server->grave);
+		afs_destroy_server(server);
 	}
+}
 
-	/* if we were woken up with an error, then pass that error back to the
-	 * called */
-	if (nconn < 0) {
-		_leave(" = %d", callslot->errno);
-		return callslot->errno;
-	}
-
-	/* were we given a connection directly? */
-	if (callslot->conn) {
-		/* yes - use it */
-		_leave(" = 0 (nc=%d)", nconn);
-		return 0;
-	}
-
-	/* got a callslot, but no connection */
- obtained_slot:
-
-	/* need to get hold of the RxRPC connection */
-	down_write(&server->sem);
-
-	/* quick check to see if there's an outstanding error */
-	ret = server->fs_state;
-	if (ret)
-		goto error_release_upw;
-
-	if (server->fs_conn[nconn]) {
-		/* reuse an existing connection */
-		rxrpc_get_connection(server->fs_conn[nconn]);
-		callslot->conn = server->fs_conn[nconn];
-	}
-	else {
-		/* create a new connection */
-		ret = rxrpc_create_connection(afs_transport,
-					      htons(7000),
-					      server->addr.s_addr,
-					      FS_SERVICE_ID,
-					      NULL,
-					      &server->fs_conn[nconn]);
-
-		if (ret < 0)
-			goto error_release_upw;
-
-		callslot->conn = server->fs_conn[0];
-		rxrpc_get_connection(callslot->conn);
-	}
-
-	up_write(&server->sem);
-
- 	_leave(" = 0");
-	return 0;
-
-	/* handle an error occurring */
- error_release_upw:
-	up_write(&server->sem);
-
- error_release:
-	/* either release the callslot or pass it along to another deserving
-	 * task */
-	spin_lock(&server->fs_lock);
-
-	if (nconn < 0) {
-		/* no callslot allocated */
-	}
-	else if (list_empty(&server->fs_callq)) {
-		/* no one waiting */
-		server->fs_conn_cnt[nconn]++;
-		spin_unlock(&server->fs_lock);
-	}
-	else {
-		/* someone's waiting - dequeue them and wake them up */
-		pcallslot = list_entry(server->fs_callq.next,
-				       struct afs_server_callslot, link);
-		list_del_init(&pcallslot->link);
-
-		pcallslot->errno = server->fs_state;
-		if (!pcallslot->errno) {
-			/* pass them out callslot details */
-			callslot->conn = xchg(&pcallslot->conn,
-					      callslot->conn);
-			pcallslot->nconn = nconn;
-			callslot->nconn = nconn = -1;
-		}
-		pcallslot->ready = 1;
-		wake_up_process(pcallslot->task);
-		spin_unlock(&server->fs_lock);
-	}
-
-	rxrpc_put_connection(callslot->conn);
-	callslot->conn = NULL;
-
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end afs_server_request_callslot() */
-
-/*****************************************************************************/
-/*
- * release a callslot back to the server
- * - transfers the RxRPC connection to the next pending callslot if possible
- */
-void afs_server_release_callslot(struct afs_server *server,
-				 struct afs_server_callslot *callslot)
-{
-	struct afs_server_callslot *pcallslot;
-
-	_enter("{ad=%08x,cnt=%u},{%d}",
-	       ntohl(server->addr.s_addr),
-	       server->fs_conn_cnt[callslot->nconn],
-	       callslot->nconn);
-
-	BUG_ON(callslot->nconn < 0);
-
-	spin_lock(&server->fs_lock);
-
-	if (list_empty(&server->fs_callq)) {
-		/* no one waiting */
-		server->fs_conn_cnt[callslot->nconn]++;
-		spin_unlock(&server->fs_lock);
-	}
-	else {
-		/* someone's waiting - dequeue them and wake them up */
-		pcallslot = list_entry(server->fs_callq.next,
-				       struct afs_server_callslot, link);
-		list_del_init(&pcallslot->link);
-
-		pcallslot->errno = server->fs_state;
-		if (!pcallslot->errno) {
-			/* pass them out callslot details */
-			callslot->conn = xchg(&pcallslot->conn, callslot->conn);
-			pcallslot->nconn = callslot->nconn;
-			callslot->nconn = -1;
-		}
-
-		pcallslot->ready = 1;
-		wake_up_process(pcallslot->task);
-		spin_unlock(&server->fs_lock);
-	}
-
-	rxrpc_put_connection(callslot->conn);
-
-	_leave("");
-} /* end afs_server_release_callslot() */
-
-/*****************************************************************************/
 /*
- * get a handle to a connection to the vlserver (volume location) on the
- * specified server
+ * discard all the server records for rmmod
  */
-int afs_server_get_vlconn(struct afs_server *server,
-			  struct rxrpc_connection **_conn)
+void __exit afs_purge_servers(void)
 {
-	struct rxrpc_connection *conn;
-	int ret;
-
-	_enter("%p,", server);
-
-	ret = 0;
-	conn = NULL;
-	down_read(&server->sem);
-
-	if (server->vlserver) {
-		/* reuse an existing connection */
-		rxrpc_get_connection(server->vlserver);
-		conn = server->vlserver;
-		up_read(&server->sem);
-	}
-	else {
-		/* create a new connection */
-		up_read(&server->sem);
-		down_write(&server->sem);
-		if (!server->vlserver) {
-			ret = rxrpc_create_connection(afs_transport,
-						      htons(7003),
-						      server->addr.s_addr,
-						      VL_SERVICE_ID,
-						      NULL,
-						      &server->vlserver);
-		}
-		if (ret == 0) {
-			rxrpc_get_connection(server->vlserver);
-			conn = server->vlserver;
-		}
-		up_write(&server->sem);
-	}
-
-	*_conn = conn;
-	_leave(" = %d", ret);
-	return ret;
-} /* end afs_server_get_vlconn() */
+	afs_server_timeout = 0;
+	cancel_delayed_work(&afs_server_reaper);
+	schedule_delayed_work(&afs_server_reaper, 0);
+}
diff --git a/fs/afs/server.h b/fs/afs/server.h
deleted file mode 100644
index c3d2411..0000000
--- a/fs/afs/server.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* server.h: AFS server record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_SERVER_H
-#define _LINUX_AFS_SERVER_H
-
-#include "types.h"
-#include "kafstimod.h"
-#include <rxrpc/peer.h>
-#include <linux/rwsem.h>
-
-extern spinlock_t afs_server_peer_lock;
-
-/*****************************************************************************/
-/*
- * AFS server record
- */
-struct afs_server
-{
-	atomic_t		usage;
-	struct afs_cell		*cell;		/* cell in which server resides */
-	struct list_head	link;		/* link in cell's server list */
-	struct rw_semaphore	sem;		/* access lock */
-	struct afs_timer	timeout;	/* graveyard timeout */
-	struct in_addr		addr;		/* server address */
-	struct rxrpc_peer	*peer;		/* peer record for this server */
-	struct rxrpc_connection	*vlserver;	/* connection to the volume location service */
-
-	/* file service access */
-#define AFS_SERVER_CONN_LIST_SIZE 2
-	struct rxrpc_connection	*fs_conn[AFS_SERVER_CONN_LIST_SIZE]; /* FS connections */
-	unsigned		fs_conn_cnt[AFS_SERVER_CONN_LIST_SIZE];	/* per conn call count */
-	struct list_head	fs_callq;	/* queue of processes waiting to make a call */
-	spinlock_t		fs_lock;	/* access lock */
-	int			fs_state;      	/* 0 or reason FS currently marked dead (-errno) */
-	unsigned		fs_rtt;		/* FS round trip time */
-	unsigned long		fs_act_jif;	/* time at which last activity occurred */
-	unsigned long		fs_dead_jif;	/* time at which no longer to be considered dead */
-
-	/* callback promise management */
-	struct list_head	cb_promises;	/* as yet unbroken promises from this server */
-	spinlock_t		cb_lock;	/* access lock */
-};
-
-extern int afs_server_lookup(struct afs_cell *cell,
-			     const struct in_addr *addr,
-			     struct afs_server **_server);
-
-#define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0)
-
-extern void afs_put_server(struct afs_server *server);
-extern void afs_server_do_timeout(struct afs_server *server);
-
-extern int afs_server_find_by_peer(const struct rxrpc_peer *peer,
-				   struct afs_server **_server);
-
-extern int afs_server_get_vlconn(struct afs_server *server,
-				 struct rxrpc_connection **_conn);
-
-static inline
-struct afs_server *afs_server_get_from_peer(struct rxrpc_peer *peer)
-{
-	struct afs_server *server;
-
-	spin_lock(&afs_server_peer_lock);
-	server = peer->user;
-	if (server)
-		afs_get_server(server);
-	spin_unlock(&afs_server_peer_lock);
-
-	return server;
-}
-
-/*****************************************************************************/
-/*
- * AFS server callslot grant record
- */
-struct afs_server_callslot
-{
-	struct list_head	link;		/* link in server's list */
-	struct task_struct	*task;		/* process waiting to make call */
-	struct rxrpc_connection	*conn;		/* connection to use (or NULL on error) */
-	short			nconn;		/* connection slot number (-1 on error) */
-	char			ready;		/* T when ready */
-	int			errno;		/* error number if nconn==-1 */
-};
-
-extern int afs_server_request_callslot(struct afs_server *server,
-				       struct afs_server_callslot *callslot);
-
-extern void afs_server_release_callslot(struct afs_server *server,
-					struct afs_server_callslot *callslot);
-
-#endif /* _LINUX_AFS_SERVER_H */
diff --git a/fs/afs/super.c b/fs/afs/super.c
index eb7e323..7030d76 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -1,5 +1,6 @@
-/*
- * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+/* AFS superblock handling
+ *
+ * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved.
  *
  * This software may be freely redistributed under the terms of the
  * GNU General Public License.
@@ -9,7 +10,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * Authors: David Howells <dhowells@redhat.com>
- *          David Woodhouse <dwmw2@cambridge.redhat.com>
+ *          David Woodhouse <dwmw2@redhat.com>
  *
  */
 
@@ -19,22 +20,11 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include "vnode.h"
-#include "volume.h"
-#include "cell.h"
-#include "cmservice.h"
-#include "fsclient.h"
-#include "super.h"
+#include <linux/parser.h>
 #include "internal.h"
 
 #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
 
-struct afs_mount_params {
-	int			rwpath;
-	struct afs_cell		*default_cell;
-	struct afs_volume	*volume;
-};
-
 static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
 			    unsigned long flags);
 
@@ -53,7 +43,7 @@ struct file_system_type afs_fs_type = {
 	.name		= "afs",
 	.get_sb		= afs_get_sb,
 	.kill_sb	= kill_anon_super,
-	.fs_flags	= FS_BINARY_MOUNTDATA,
+	.fs_flags	= 0,
 };
 
 static const struct super_operations afs_super_ops = {
@@ -62,13 +52,27 @@ static const struct super_operations afs
 	.drop_inode	= generic_delete_inode,
 	.destroy_inode	= afs_destroy_inode,
 	.clear_inode	= afs_clear_inode,
+	.umount_begin	= afs_umount_begin,
 	.put_super	= afs_put_super,
 };
 
 static struct kmem_cache *afs_inode_cachep;
 static atomic_t afs_count_active_inodes;
 
-/*****************************************************************************/
+enum {
+	afs_no_opt,
+	afs_opt_cell,
+	afs_opt_rwpath,
+	afs_opt_vol,
+};
+
+static const match_table_t afs_options_list = {
+	{ afs_opt_cell,		"cell=%s"	},
+	{ afs_opt_rwpath,	"rwpath"	},
+	{ afs_opt_vol,		"vol=%s"	},
+	{ afs_no_opt,		NULL		},
+};
+
 /*
  * initialise the filesystem
  */
@@ -78,8 +82,6 @@ int __init afs_fs_init(void)
 
 	_enter("");
 
-	afs_timer_init(&afs_mntpt_expiry_timer, &afs_mntpt_expiry_timer_ops);
-
 	/* create ourselves an inode cache */
 	atomic_set(&afs_count_active_inodes, 0);
 
@@ -99,20 +101,22 @@ int __init afs_fs_init(void)
 	ret = register_filesystem(&afs_fs_type);
 	if (ret < 0) {
 		kmem_cache_destroy(afs_inode_cachep);
-		kleave(" = %d", ret);
+		_leave(" = %d", ret);
 		return ret;
 	}
 
-	kleave(" = 0");
+	_leave(" = 0");
 	return 0;
-} /* end afs_fs_init() */
+}
 
-/*****************************************************************************/
 /*
  * clean up the filesystem
  */
 void __exit afs_fs_exit(void)
 {
+	_enter("");
+
+	afs_mntpt_kill_timer();
 	unregister_filesystem(&afs_fs_type);
 
 	if (atomic_read(&afs_count_active_inodes) != 0) {
@@ -122,99 +126,153 @@ void __exit afs_fs_exit(void)
 	}
 
 	kmem_cache_destroy(afs_inode_cachep);
+	_leave("");
+}
 
-} /* end afs_fs_exit() */
-
-/*****************************************************************************/
-/*
- * check that an argument has a value
- */
-static int want_arg(char **_value, const char *option)
-{
-	if (!_value || !*_value || !**_value) {
-		printk(KERN_NOTICE "kAFS: %s: argument missing\n", option);
-		return 0;
-	}
-	return 1;
-} /* end want_arg() */
-
-/*****************************************************************************/
-/*
- * check that there's no subsequent value
- */
-static int want_no_value(char *const *_value, const char *option)
-{
-	if (*_value && **_value) {
-		printk(KERN_NOTICE "kAFS: %s: Invalid argument: %s\n",
-		       option, *_value);
-		return 0;
-	}
-	return 1;
-} /* end want_no_value() */
-
-/*****************************************************************************/
 /*
  * parse the mount options
  * - this function has been shamelessly adapted from the ext3 fs which
  *   shamelessly adapted it from the msdos fs
  */
-static int afs_super_parse_options(struct afs_mount_params *params,
-				   char *options,
-				   const char **devname)
+static int afs_parse_options(struct afs_mount_params *params,
+			     char *options, const char **devname)
 {
-	char *key, *value;
-	int ret;
+	struct afs_cell *cell;
+	substring_t args[MAX_OPT_ARGS];
+	char *p;
+	int token;
 
 	_enter("%s", options);
 
 	options[PAGE_SIZE - 1] = 0;
 
-	ret = 0;
-	while ((key = strsep(&options, ",")) != 0)
-	{
-		value = strchr(key, '=');
-		if (value)
-			*value++ = 0;
-
-		printk("kAFS: KEY: %s, VAL:%s\n", key, value ?: "-");
+	while ((p = strsep(&options, ","))) {
+		if (!*p)
+			continue;
 
-		if (strcmp(key, "rwpath") == 0) {
-			if (!want_no_value(&value, "rwpath"))
-				return -EINVAL;
+		token = match_token(p, afs_options_list, args);
+		switch (token) {
+		case afs_opt_cell:
+			cell = afs_cell_lookup(args[0].from,
+					       args[0].to - args[0].from);
+			if (IS_ERR(cell))
+				return PTR_ERR(cell);
+			afs_put_cell(params->cell);
+			params->cell = cell;
+			break;
+
+		case afs_opt_rwpath:
 			params->rwpath = 1;
-			continue;
-		}
-		else if (strcmp(key, "vol") == 0) {
-			if (!want_arg(&value, "vol"))
-				return -EINVAL;
-			*devname = value;
-			continue;
+			break;
+
+		case afs_opt_vol:
+			*devname = args[0].from;
+			break;
+
+		default:
+			printk(KERN_ERR "kAFS:"
+			       " Unknown or invalid mount option: '%s'\n", p);
+			return -EINVAL;
 		}
-		else if (strcmp(key, "cell") == 0) {
-			if (!want_arg(&value, "cell"))
-				return -EINVAL;
-			afs_put_cell(params->default_cell);
-			ret = afs_cell_lookup(value,
-					      strlen(value),
-					      &params->default_cell);
-			if (ret < 0)
-				return -EINVAL;
-			continue;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * parse a device name to get cell name, volume name, volume type and R/W
+ * selector
+ * - this can be one of the following:
+ *	"%[cell:]volume[.]"		R/W volume
+ *	"#[cell:]volume[.]"		R/O or R/W volume (rwpath=0),
+ *					 or R/W (rwpath=1) volume
+ *	"%[cell:]volume.readonly"	R/O volume
+ *	"#[cell:]volume.readonly"	R/O volume
+ *	"%[cell:]volume.backup"		Backup volume
+ *	"#[cell:]volume.backup"		Backup volume
+ */
+static int afs_parse_device_name(struct afs_mount_params *params,
+				 const char *name)
+{
+	struct afs_cell *cell;
+	const char *cellname, *suffix;
+	int cellnamesz;
+
+	_enter(",%s", name);
+
+	if (!name) {
+		printk(KERN_ERR "kAFS: no volume name specified\n");
+		return -EINVAL;
+	}
+
+	if ((name[0] != '%' && name[0] != '#') || !name[1]) {
+		printk(KERN_ERR "kAFS: unparsable volume name\n");
+		return -EINVAL;
+	}
+
+	/* determine the type of volume we're looking for */
+	params->type = AFSVL_ROVOL;
+	params->force = false;
+	if (params->rwpath || name[0] == '%') {
+		params->type = AFSVL_RWVOL;
+		params->force = true;
+	}
+	name++;
+
+	/* split the cell name out if there is one */
+	params->volname = strchr(name, ':');
+	if (params->volname) {
+		cellname = name;
+		cellnamesz = params->volname - name;
+		params->volname++;
+	} else {
+		params->volname = name;
+		cellname = NULL;
+		cellnamesz = 0;
+	}
+
+	/* the volume type is further affected by a possible suffix */
+	suffix = strrchr(params->volname, '.');
+	if (suffix) {
+		if (strcmp(suffix, ".readonly") == 0) {
+			params->type = AFSVL_ROVOL;
+			params->force = true;
+		} else if (strcmp(suffix, ".backup") == 0) {
+			params->type = AFSVL_BACKVOL;
+			params->force = true;
+		} else if (suffix[1] == 0) {
+		} else {
+			suffix = NULL;
 		}
+	}
 
-		printk("kAFS: Unknown mount option: '%s'\n",  key);
-		ret = -EINVAL;
-		goto error;
+	params->volnamesz = suffix ?
+		suffix - params->volname : strlen(params->volname);
+
+	_debug("cell %*.*s [%p]",
+	       cellnamesz, cellnamesz, cellname ?: "", params->cell);
+
+	/* lookup the cell record */
+	if (cellname || !params->cell) {
+		cell = afs_cell_lookup(cellname, cellnamesz);
+		if (IS_ERR(cell)) {
+			printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n",
+			       cellname ?: "");
+			return PTR_ERR(cell);
+		}
+		afs_put_cell(params->cell);
+		params->cell = cell;
 	}
 
-	ret = 0;
+	_debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
+	       params->cell->name, params->cell,
+	       params->volnamesz, params->volnamesz, params->volname,
+	       suffix ?: "-", params->type, params->force ? " FORCE" : "");
 
- error:
-	_leave(" = %d", ret);
-	return ret;
-} /* end afs_super_parse_options() */
+	return 0;
+}
 
-/*****************************************************************************/
 /*
  * check a superblock to see if it's the one we're looking for
  */
@@ -224,13 +282,12 @@ static int afs_test_super(struct super_b
 	struct afs_super_info *as = sb->s_fs_info;
 
 	return as->volume == params->volume;
-} /* end afs_test_super() */
+}
 
-/*****************************************************************************/
 /*
  * fill in the superblock
  */
-static int afs_fill_super(struct super_block *sb, void *data, int silent)
+static int afs_fill_super(struct super_block *sb, void *data)
 {
 	struct afs_mount_params *params = data;
 	struct afs_super_info *as = NULL;
@@ -239,7 +296,7 @@ static int afs_fill_super(struct super_b
 	struct inode *inode = NULL;
 	int ret;
 
-	kenter("");
+	_enter("");
 
 	/* allocate a superblock info record */
 	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
@@ -262,9 +319,9 @@ static int afs_fill_super(struct super_b
 	fid.vid		= as->volume->vid;
 	fid.vnode	= 1;
 	fid.unique	= 1;
-	ret = afs_iget(sb, &fid, &inode);
-	if (ret < 0)
-		goto error;
+	inode = afs_iget(sb, params->key, &fid, NULL, NULL);
+	if (IS_ERR(inode))
+		goto error_inode;
 
 	ret = -ENOMEM;
 	root = d_alloc_root(inode);
@@ -273,24 +330,25 @@ static int afs_fill_super(struct super_b
 
 	sb->s_root = root;
 
-	kleave(" = 0");
+	_leave(" = 0");
 	return 0;
 
- error:
+error_inode:
+	ret = PTR_ERR(inode);
+	inode = NULL;
+error:
 	iput(inode);
 	afs_put_volume(as->volume);
 	kfree(as);
 
 	sb->s_fs_info = NULL;
 
-	kleave(" = %d", ret);
+	_leave(" = %d", ret);
 	return ret;
-} /* end afs_fill_super() */
+}
 
-/*****************************************************************************/
 /*
  * get an AFS superblock
- * - TODO: don't use get_sb_nodev(), but rather call sget() directly
  */
 static int afs_get_sb(struct file_system_type *fs_type,
 		      int flags,
@@ -300,69 +358,79 @@ static int afs_get_sb(struct file_system
 {
 	struct afs_mount_params params;
 	struct super_block *sb;
+	struct afs_volume *vol;
+	struct key *key;
 	int ret;
 
 	_enter(",,%s,%p", dev_name, options);
 
 	memset(&params, 0, sizeof(params));
 
-	/* start the cache manager */
-	ret = afscm_start();
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* parse the options */
+	/* parse the options and device name */
 	if (options) {
-		ret = afs_super_parse_options(&params, options, &dev_name);
+		ret = afs_parse_options(&params, options, &dev_name);
 		if (ret < 0)
 			goto error;
-		if (!dev_name) {
-			printk("kAFS: no volume name specified\n");
-			ret = -EINVAL;
-			goto error;
-		}
 	}
 
-	/* parse the device name */
-	ret = afs_volume_lookup(dev_name,
-				params.default_cell,
-				params.rwpath,
-				&params.volume);
+	ret = afs_parse_device_name(&params, dev_name);
 	if (ret < 0)
 		goto error;
 
-	/* allocate a deviceless superblock */
-	sb = sget(fs_type, afs_test_super, set_anon_super, &params);
-	if (IS_ERR(sb))
+	/* try and do the mount securely */
+	key = afs_request_key(params.cell);
+	if (IS_ERR(key)) {
+		_leave(" = %ld [key]", PTR_ERR(key));
+		ret = PTR_ERR(key);
 		goto error;
+	}
+	params.key = key;
 
-	sb->s_flags = flags;
+	/* parse the device name */
+	vol = afs_volume_lookup(&params);
+	if (IS_ERR(vol)) {
+		ret = PTR_ERR(vol);
+		goto error;
+	}
+	params.volume = vol;
 
-	ret = afs_fill_super(sb, &params, flags & MS_SILENT ? 1 : 0);
-	if (ret < 0) {
-		up_write(&sb->s_umount);
-		deactivate_super(sb);
+	/* allocate a deviceless superblock */
+	sb = sget(fs_type, afs_test_super, set_anon_super, &params);
+	if (IS_ERR(sb)) {
+		ret = PTR_ERR(sb);
 		goto error;
 	}
-	sb->s_flags |= MS_ACTIVE;
-	simple_set_mnt(mnt, sb);
 
+	if (!sb->s_root) {
+		/* initial superblock/root creation */
+		_debug("create");
+		sb->s_flags = flags;
+		ret = afs_fill_super(sb, &params);
+		if (ret < 0) {
+			up_write(&sb->s_umount);
+			deactivate_super(sb);
+			goto error;
+		}
+		sb->s_flags |= MS_ACTIVE;
+	} else {
+		_debug("reuse");
+		ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
+	}
+
+	simple_set_mnt(mnt, sb);
 	afs_put_volume(params.volume);
-	afs_put_cell(params.default_cell);
-	_leave(" = 0 [%p]", 0, sb);
+	afs_put_cell(params.cell);
+	_leave(" = 0 [%p]", sb);
 	return 0;
 
- error:
+error:
 	afs_put_volume(params.volume);
-	afs_put_cell(params.default_cell);
-	afscm_stop();
+	afs_put_cell(params.cell);
+	key_put(params.key);
 	_leave(" = %d", ret);
 	return ret;
-} /* end afs_get_sb() */
+}
 
-/*****************************************************************************/
 /*
  * finish the unmounting process on the superblock
  */
@@ -373,35 +441,29 @@ static void afs_put_super(struct super_b
 	_enter("");
 
 	afs_put_volume(as->volume);
-	afscm_stop();
 
 	_leave("");
-} /* end afs_put_super() */
+}
 
-/*****************************************************************************/
 /*
  * initialise an inode cache slab element prior to any use
  */
 static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
 			    unsigned long flags)
 {
-	struct afs_vnode *vnode = (struct afs_vnode *) _vnode;
+	struct afs_vnode *vnode = _vnode;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		memset(vnode, 0, sizeof(*vnode));
 		inode_init_once(&vnode->vfs_inode);
 		init_waitqueue_head(&vnode->update_waitq);
+		mutex_init(&vnode->permits_lock);
+		mutex_init(&vnode->validate_lock);
 		spin_lock_init(&vnode->lock);
-		INIT_LIST_HEAD(&vnode->cb_link);
-		INIT_LIST_HEAD(&vnode->cb_hash_link);
-		afs_timer_init(&vnode->cb_timeout,
-			       &afs_vnode_cb_timed_out_ops);
+		INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
 	}
+}
 
-} /* end afs_i_init_once() */
-
-/*****************************************************************************/
 /*
  * allocate an AFS inode struct from our slab cache
  */
@@ -409,8 +471,7 @@ static struct inode *afs_alloc_inode(str
 {
 	struct afs_vnode *vnode;
 
-	vnode = (struct afs_vnode *)
-		kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL);
+	vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL);
 	if (!vnode)
 		return NULL;
 
@@ -421,21 +482,25 @@ static struct inode *afs_alloc_inode(str
 
 	vnode->volume		= NULL;
 	vnode->update_cnt	= 0;
-	vnode->flags		= 0;
+	vnode->flags		= 1 << AFS_VNODE_UNSET;
+	vnode->cb_promised	= false;
 
 	return &vnode->vfs_inode;
-} /* end afs_alloc_inode() */
+}
 
-/*****************************************************************************/
 /*
  * destroy an AFS inode struct
  */
 static void afs_destroy_inode(struct inode *inode)
 {
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+
 	_enter("{%lu}", inode->i_ino);
 
-	kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode));
+	_debug("DESTROY INODE %p", inode);
 
-	atomic_dec(&afs_count_active_inodes);
+	ASSERTCMP(vnode->server, ==, NULL);
 
-} /* end afs_destroy_inode() */
+	kmem_cache_free(afs_inode_cachep, vnode);
+	atomic_dec(&afs_count_active_inodes);
+}
diff --git a/fs/afs/super.h b/fs/afs/super.h
deleted file mode 100644
index 32de8cc..0000000
--- a/fs/afs/super.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* super.h: AFS filesystem internal private data
- *
- * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
- *
- * This software may be freely redistributed under the terms of the
- * GNU General Public License.
- *
- * You 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.
- *
- * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
- *          David Howells <dhowells@redhat.com>
- *
- */
-
-#ifndef _LINUX_AFS_SUPER_H
-#define _LINUX_AFS_SUPER_H
-
-#include <linux/fs.h>
-#include "server.h"
-
-#ifdef __KERNEL__
-
-/*****************************************************************************/
-/*
- * AFS superblock private data
- * - there's one superblock per volume
- */
-struct afs_super_info
-{
-	struct afs_volume	*volume;	/* volume record */
-	char			rwparent;	/* T if parent is R/W AFS volume */
-};
-
-static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
-{
-	return sb->s_fs_info;
-}
-
-extern struct file_system_type afs_fs_type;
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_AFS_SUPER_H */
diff --git a/fs/afs/transport.h b/fs/afs/transport.h
deleted file mode 100644
index 7013ae6..0000000
--- a/fs/afs/transport.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* transport.h: AFS transport management
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_TRANSPORT_H
-#define _LINUX_AFS_TRANSPORT_H
-
-#include "types.h"
-#include <rxrpc/transport.h>
-
-/* the cache manager transport endpoint */
-extern struct rxrpc_transport *afs_transport;
-
-#endif /* _LINUX_AFS_TRANSPORT_H */
diff --git a/fs/afs/types.h b/fs/afs/types.h
deleted file mode 100644
index b1a2367..0000000
--- a/fs/afs/types.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/* types.h: AFS types
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_TYPES_H
-#define _LINUX_AFS_TYPES_H
-
-#ifdef __KERNEL__
-#include <rxrpc/types.h>
-#endif /* __KERNEL__ */
-
-typedef unsigned			afs_volid_t;
-typedef unsigned			afs_vnodeid_t;
-typedef unsigned long long		afs_dataversion_t;
-
-typedef enum {
-	AFSVL_RWVOL,			/* read/write volume */
-	AFSVL_ROVOL,			/* read-only volume */
-	AFSVL_BACKVOL,			/* backup volume */
-} __attribute__((packed)) afs_voltype_t;
-
-typedef enum {
-	AFS_FTYPE_INVALID	= 0,
-	AFS_FTYPE_FILE		= 1,
-	AFS_FTYPE_DIR		= 2,
-	AFS_FTYPE_SYMLINK	= 3,
-} afs_file_type_t;
-
-#ifdef __KERNEL__
-
-struct afs_cell;
-struct afs_vnode;
-
-/*****************************************************************************/
-/*
- * AFS file identifier
- */
-struct afs_fid
-{
-	afs_volid_t	vid;		/* volume ID */
-	afs_vnodeid_t	vnode;		/* file index within volume */
-	unsigned	unique;		/* unique ID number (file index version) */
-};
-
-/*****************************************************************************/
-/*
- * AFS callback notification
- */
-typedef enum {
-	AFSCM_CB_UNTYPED	= 0,	/* no type set on CB break */
-	AFSCM_CB_EXCLUSIVE	= 1,	/* CB exclusive to CM [not implemented] */
-	AFSCM_CB_SHARED		= 2,	/* CB shared by other CM's */
-	AFSCM_CB_DROPPED	= 3,	/* CB promise cancelled by file server */
-} afs_callback_type_t;
-
-struct afs_callback
-{
-	struct afs_server	*server;	/* server that made the promise */
-	struct afs_fid		fid;		/* file identifier */
-	unsigned		version;	/* callback version */
-	unsigned		expiry;		/* time at which expires */
-	afs_callback_type_t	type;		/* type of callback */
-};
-
-#define AFSCBMAX 50
-
-/*****************************************************************************/
-/*
- * AFS volume information
- */
-struct afs_volume_info
-{
-	afs_volid_t		vid;		/* volume ID */
-	afs_voltype_t		type;		/* type of this volume */
-	afs_volid_t		type_vids[5];	/* volume ID's for possible types for this vol */
-	
-	/* list of fileservers serving this volume */
-	size_t			nservers;	/* number of entries used in servers[] */
-	struct {
-		struct in_addr	addr;		/* fileserver address */
-	} servers[8];
-};
-
-/*****************************************************************************/
-/*
- * AFS file status information
- */
-struct afs_file_status
-{
-	unsigned		if_version;	/* interface version */
-#define AFS_FSTATUS_VERSION	1
-
-	afs_file_type_t		type;		/* file type */
-	unsigned		nlink;		/* link count */
-	size_t			size;		/* file size */
-	afs_dataversion_t	version;	/* current data version */
-	unsigned		author;		/* author ID */
-	unsigned		owner;		/* owner ID */
-	unsigned		caller_access;	/* access rights for authenticated caller */
-	unsigned		anon_access;	/* access rights for unauthenticated caller */
-	umode_t			mode;		/* UNIX mode */
-	struct afs_fid		parent;		/* parent file ID */
-	time_t			mtime_client;	/* last time client changed data */
-	time_t			mtime_server;	/* last time server changed data */
-};
-
-/*****************************************************************************/
-/*
- * AFS volume synchronisation information
- */
-struct afs_volsync
-{
-	time_t			creation;	/* volume creation time */
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_AFS_TYPES_H */
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c
index 7b0e319..36c1306 100644
--- a/fs/afs/vlclient.c
+++ b/fs/afs/vlclient.c
@@ -1,4 +1,4 @@
-/* vlclient.c: AFS Volume Location Service client
+/* AFS Volume Location Service client
  *
  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
@@ -11,247 +11,76 @@
 
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include "server.h"
-#include "volume.h"
-#include "vlclient.h"
-#include "kafsasyncd.h"
-#include "kafstimod.h"
-#include "errors.h"
 #include "internal.h"
 
-#define VLGETENTRYBYID		503	/* AFS Get Cache Entry By ID operation ID */
-#define VLGETENTRYBYNAME	504	/* AFS Get Cache Entry By Name operation ID */
-#define VLPROBE			514	/* AFS Probe Volume Location Service operation ID */
-
-static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
-static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
-
-/*****************************************************************************/
 /*
- * map afs VL abort codes to/from Linux error codes
- * - called with call->lock held
+ * map volume locator abort codes to error codes
  */
-static void afs_rxvl_aemap(struct rxrpc_call *call)
+static int afs_vl_abort_to_error(u32 abort_code)
 {
-	int err;
-
-	_enter("{%u,%u,%d}",
-	       call->app_err_state, call->app_abort_code, call->app_errno);
-
-	switch (call->app_err_state) {
-	case RXRPC_ESTATE_LOCAL_ABORT:
-		call->app_abort_code = -call->app_errno;
-		return;
-
-	case RXRPC_ESTATE_PEER_ABORT:
-		switch (call->app_abort_code) {
-		case AFSVL_IDEXIST:		err = -EEXIST;		break;
-		case AFSVL_IO:			err = -EREMOTEIO;	break;
-		case AFSVL_NAMEEXIST:		err = -EEXIST;		break;
-		case AFSVL_CREATEFAIL:		err = -EREMOTEIO;	break;
-		case AFSVL_NOENT:		err = -ENOMEDIUM;	break;
-		case AFSVL_EMPTY:		err = -ENOMEDIUM;	break;
-		case AFSVL_ENTDELETED:		err = -ENOMEDIUM;	break;
-		case AFSVL_BADNAME:		err = -EINVAL;		break;
-		case AFSVL_BADINDEX:		err = -EINVAL;		break;
-		case AFSVL_BADVOLTYPE:		err = -EINVAL;		break;
-		case AFSVL_BADSERVER:		err = -EINVAL;		break;
-		case AFSVL_BADPARTITION:	err = -EINVAL;		break;
-		case AFSVL_REPSFULL:		err = -EFBIG;		break;
-		case AFSVL_NOREPSERVER:		err = -ENOENT;		break;
-		case AFSVL_DUPREPSERVER:	err = -EEXIST;		break;
-		case AFSVL_RWNOTFOUND:		err = -ENOENT;		break;
-		case AFSVL_BADREFCOUNT:		err = -EINVAL;		break;
-		case AFSVL_SIZEEXCEEDED:	err = -EINVAL;		break;
-		case AFSVL_BADENTRY:		err = -EINVAL;		break;
-		case AFSVL_BADVOLIDBUMP:	err = -EINVAL;		break;
-		case AFSVL_IDALREADYHASHED:	err = -EINVAL;		break;
-		case AFSVL_ENTRYLOCKED:		err = -EBUSY;		break;
-		case AFSVL_BADVOLOPER:		err = -EBADRQC;		break;
-		case AFSVL_BADRELLOCKTYPE:	err = -EINVAL;		break;
-		case AFSVL_RERELEASE:		err = -EREMOTEIO;	break;
-		case AFSVL_BADSERVERFLAG:	err = -EINVAL;		break;
-		case AFSVL_PERM:		err = -EACCES;		break;
-		case AFSVL_NOMEM:		err = -EREMOTEIO;	break;
-		default:
-			err = afs_abort_to_error(call->app_abort_code);
-			break;
-		}
-		call->app_errno = err;
-		return;
-
+	_enter("%u", abort_code);
+
+	switch (abort_code) {
+	case AFSVL_IDEXIST:		return -EEXIST;
+	case AFSVL_IO:			return -EREMOTEIO;
+	case AFSVL_NAMEEXIST:		return -EEXIST;
+	case AFSVL_CREATEFAIL:		return -EREMOTEIO;
+	case AFSVL_NOENT:		return -ENOMEDIUM;
+	case AFSVL_EMPTY:		return -ENOMEDIUM;
+	case AFSVL_ENTDELETED:		return -ENOMEDIUM;
+	case AFSVL_BADNAME:		return -EINVAL;
+	case AFSVL_BADINDEX:		return -EINVAL;
+	case AFSVL_BADVOLTYPE:		return -EINVAL;
+	case AFSVL_BADSERVER:		return -EINVAL;
+	case AFSVL_BADPARTITION:	return -EINVAL;
+	case AFSVL_REPSFULL:		return -EFBIG;
+	case AFSVL_NOREPSERVER:		return -ENOENT;
+	case AFSVL_DUPREPSERVER:	return -EEXIST;
+	case AFSVL_RWNOTFOUND:		return -ENOENT;
+	case AFSVL_BADREFCOUNT:		return -EINVAL;
+	case AFSVL_SIZEEXCEEDED:	return -EINVAL;
+	case AFSVL_BADENTRY:		return -EINVAL;
+	case AFSVL_BADVOLIDBUMP:	return -EINVAL;
+	case AFSVL_IDALREADYHASHED:	return -EINVAL;
+	case AFSVL_ENTRYLOCKED:		return -EBUSY;
+	case AFSVL_BADVOLOPER:		return -EBADRQC;
+	case AFSVL_BADRELLOCKTYPE:	return -EINVAL;
+	case AFSVL_RERELEASE:		return -EREMOTEIO;
+	case AFSVL_BADSERVERFLAG:	return -EINVAL;
+	case AFSVL_PERM:		return -EACCES;
+	case AFSVL_NOMEM:		return -EREMOTEIO;
 	default:
-		return;
+		return afs_abort_to_error(abort_code);
 	}
-} /* end afs_rxvl_aemap() */
+}
 
-#if 0
-/*****************************************************************************/
 /*
- * probe a volume location server to see if it is still alive -- unused
+ * deliver reply data to a VL.GetEntryByXXX call
  */
-static int afs_rxvl_probe(struct afs_server *server, int alloc_flags)
+static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call,
+					   struct sk_buff *skb, bool last)
 {
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	size_t sent;
-	int ret;
-	__be32 param[1];
-
-	DECLARE_WAITQUEUE(myself, current);
-
-	/* get hold of the vlserver connection */
-	ret = afs_server_get_vlconn(server, &conn);
-	if (ret < 0)
-		goto out;
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = VLPROBE;
-
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
-
-	/* marshall the parameters */
-	param[0] = htonl(VLPROBE);
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET,
-				    alloc_flags, 0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (call->app_call_state != RXRPC_CSTATE_CLNT_RCV_REPLY ||
-		    signal_pending(current))
-			break;
-		schedule();
-	}
-	set_current_state(TASK_RUNNING);
-
-	ret = -EINTR;
-	if (signal_pending(current))
-		goto abort;
-
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_ERROR:
-		ret = call->app_errno;
-		goto out_unwait;
-
-	case RXRPC_CSTATE_CLNT_GOT_REPLY:
-		ret = 0;
-		goto out_unwait;
-
-	default:
-		BUG();
-	}
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	rxrpc_put_connection(conn);
- out:
-	return ret;
+	struct afs_cache_vlocation *entry;
+	__be32 *bp;
+	u32 tmp;
+	int loop;
 
-} /* end afs_rxvl_probe() */
-#endif
+	_enter(",,%u", last);
 
-/*****************************************************************************/
-/*
- * look up a volume location database entry by name
- */
-int afs_rxvl_get_entry_by_name(struct afs_server *server,
-			       const char *volname,
-			       unsigned volnamesz,
-			       struct afs_cache_vlocation *entry)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[3];
-	unsigned tmp;
-	size_t sent;
-	int ret, loop;
-	__be32 *bp, param[2], zero;
-
-	_enter(",%*.*s,%u,", volnamesz, volnamesz, volname, volnamesz);
-
-	memset(entry, 0, sizeof(*entry));
-
-	/* get hold of the vlserver connection */
-	ret = afs_server_get_vlconn(server, &conn);
-	if (ret < 0)
-		goto out;
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = VLGETENTRYBYNAME;
+	afs_transfer_reply(call, skb);
+	if (!last)
+		return 0;
 
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
+	if (call->reply_size != call->reply_max)
+		return -EBADMSG;
 
-	/* marshall the parameters */
-	piov[1].iov_len = volnamesz;
-	piov[1].iov_base = (char *) volname;
-
-	zero = 0;
-	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
-	piov[2].iov_base = &zero;
-
-	param[0] = htonl(VLGETENTRYBYNAME);
-	param[1] = htonl(piov[1].iov_len);
-
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 3, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	bp = rxrpc_call_alloc_scratch(call, 384);
-
-	ret = rxrpc_call_read_data(call, bp, 384,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0) {
-		if (ret == -ECONNABORTED) {
-			ret = call->app_errno;
-			goto out_unwait;
-		}
-		goto abort;
-	}
+	/* unmarshall the reply once we've received all of it */
+	entry = call->reply;
+	bp = call->buffer;
 
-	/* unmarshall the reply */
 	for (loop = 0; loop < 64; loop++)
 		entry->name[loop] = ntohl(*bp++);
+	entry->name[loop] = 0;
 	bp++; /* final NUL */
 
 	bp++; /* type */
@@ -264,6 +93,7 @@ int afs_rxvl_get_entry_by_name(struct af
 
 	for (loop = 0; loop < 8; loop++) {
 		tmp = ntohl(*bp++);
+		entry->srvtmask[loop] = 0;
 		if (tmp & AFS_VLSF_RWVOL)
 			entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
 		if (tmp & AFS_VLSF_ROVOL)
@@ -279,417 +109,110 @@ int afs_rxvl_get_entry_by_name(struct af
 	bp++; /* clone ID */
 
 	tmp = ntohl(*bp++); /* flags */
+	entry->vidmask = 0;
 	if (tmp & AFS_VLF_RWEXISTS)
 		entry->vidmask |= AFS_VOL_VTM_RW;
 	if (tmp & AFS_VLF_ROEXISTS)
 		entry->vidmask |= AFS_VOL_VTM_RO;
 	if (tmp & AFS_VLF_BACKEXISTS)
 		entry->vidmask |= AFS_VOL_VTM_BAK;
-
-	ret = -ENOMEDIUM;
 	if (!entry->vidmask)
-		goto abort;
-
-	/* success */
-	entry->rtime = get_seconds();
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	rxrpc_put_connection(conn);
- out:
-	_leave(" = %d", ret);
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-} /* end afs_rxvl_get_entry_by_name() */
-
-/*****************************************************************************/
-/*
- * look up a volume location database entry by ID
- */
-int afs_rxvl_get_entry_by_id(struct afs_server *server,
-			     afs_volid_t volid,
-			     afs_voltype_t voltype,
-			     struct afs_cache_vlocation *entry)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	unsigned tmp;
-	size_t sent;
-	int ret, loop;
-	__be32 *bp, param[3];
-
-	_enter(",%x,%d,", volid, voltype);
-
-	memset(entry, 0, sizeof(*entry));
-
-	/* get hold of the vlserver connection */
-	ret = afs_server_get_vlconn(server, &conn);
-	if (ret < 0)
-		goto out;
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn, NULL, NULL, afs_rxvl_aemap, &call);
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		goto out_put_conn;
-	}
-	call->app_opcode = VLGETENTRYBYID;
-
-	/* we want to get event notifications from the call */
-	add_wait_queue(&call->waitq, &myself);
-
-	/* marshall the parameters */
-	param[0] = htonl(VLGETENTRYBYID);
-	param[1] = htonl(volid);
-	param[2] = htonl(voltype);
-
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0)
-		goto abort;
-
-	/* wait for the reply to completely arrive */
-	bp = rxrpc_call_alloc_scratch(call, 384);
-
-	ret = rxrpc_call_read_data(call, bp, 384,
-				   RXRPC_CALL_READ_BLOCK |
-				   RXRPC_CALL_READ_ALL);
-	if (ret < 0) {
-		if (ret == -ECONNABORTED) {
-			ret = call->app_errno;
-			goto out_unwait;
-		}
-		goto abort;
-	}
-
-	/* unmarshall the reply */
-	for (loop = 0; loop < 64; loop++)
-		entry->name[loop] = ntohl(*bp++);
-	bp++; /* final NUL */
+		return -EBADMSG;
 
-	bp++; /* type */
-	entry->nservers = ntohl(*bp++);
-
-	for (loop = 0; loop < 8; loop++)
-		entry->servers[loop].s_addr = *bp++;
-
-	bp += 8; /* partition IDs */
+	_leave(" = 0 [done]");
+	return 0;
+}
 
-	for (loop = 0; loop < 8; loop++) {
-		tmp = ntohl(*bp++);
-		if (tmp & AFS_VLSF_RWVOL)
-			entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
-		if (tmp & AFS_VLSF_ROVOL)
-			entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
-		if (tmp & AFS_VLSF_BACKVOL)
-			entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
-	}
-
-	entry->vid[0] = ntohl(*bp++);
-	entry->vid[1] = ntohl(*bp++);
-	entry->vid[2] = ntohl(*bp++);
-
-	bp++; /* clone ID */
-
-	tmp = ntohl(*bp++); /* flags */
-	if (tmp & AFS_VLF_RWEXISTS)
-		entry->vidmask |= AFS_VOL_VTM_RW;
-	if (tmp & AFS_VLF_ROEXISTS)
-		entry->vidmask |= AFS_VOL_VTM_RO;
-	if (tmp & AFS_VLF_BACKEXISTS)
-		entry->vidmask |= AFS_VOL_VTM_BAK;
-
-	ret = -ENOMEDIUM;
-	if (!entry->vidmask)
-		goto abort;
-
-#if 0 /* TODO: remove */
-	entry->nservers = 3;
-	entry->servers[0].s_addr = htonl(0xac101249);
-	entry->servers[1].s_addr = htonl(0xac101243);
-	entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
-
-	entry->srvtmask[0] = AFS_VOL_VTM_RO;
-	entry->srvtmask[1] = AFS_VOL_VTM_RO;
-	entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
-#endif
-
-	/* success */
-	entry->rtime = get_seconds();
-	ret = 0;
-
- out_unwait:
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&call->waitq, &myself);
-	rxrpc_put_call(call);
- out_put_conn:
-	rxrpc_put_connection(conn);
- out:
-	_leave(" = %d", ret);
-	return ret;
-
- abort:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	rxrpc_call_abort(call, ret);
-	schedule();
-	goto out_unwait;
-} /* end afs_rxvl_get_entry_by_id() */
-
-/*****************************************************************************/
 /*
- * look up a volume location database entry by ID asynchronously
+ * VL.GetEntryByName operation type
  */
-int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
-				   afs_volid_t volid,
-				   afs_voltype_t voltype)
-{
-	struct rxrpc_connection *conn;
-	struct rxrpc_call *call;
-	struct kvec piov[1];
-	size_t sent;
-	int ret;
-	__be32 param[3];
-
-	_enter(",%x,%d,", volid, voltype);
-
-	/* get hold of the vlserver connection */
-	ret = afs_server_get_vlconn(op->server, &conn);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* create a call through that connection */
-	ret = rxrpc_create_call(conn,
-				afs_rxvl_get_entry_by_id_attn,
-				afs_rxvl_get_entry_by_id_error,
-				afs_rxvl_aemap,
-				&op->call);
-	rxrpc_put_connection(conn);
-
-	if (ret < 0) {
-		printk("kAFS: Unable to create call: %d\n", ret);
-		_leave(" = %d", ret);
-		return ret;
-	}
+static const struct afs_call_type afs_RXVLGetEntryByName = {
+	.name		= "VL.GetEntryByName",
+	.deliver	= afs_deliver_vl_get_entry_by_xxx,
+	.abort_to_error	= afs_vl_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
 
-	op->call->app_opcode = VLGETENTRYBYID;
-	op->call->app_user = op;
-
-	call = op->call;
-	rxrpc_get_call(call);
-
-	/* send event notifications from the call to kafsasyncd */
-	afs_kafsasyncd_begin_op(op);
-
-	/* marshall the parameters */
-	param[0] = htonl(VLGETENTRYBYID);
-	param[1] = htonl(volid);
-	param[2] = htonl(voltype);
-
-	piov[0].iov_len = sizeof(param);
-	piov[0].iov_base = param;
-
-	/* allocate result read buffer in scratch space */
-	call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call, 384);
-
-	/* send the parameters to the server */
-	ret = rxrpc_call_write_data(call, 1, piov, RXRPC_LAST_PACKET, GFP_NOFS,
-				    0, &sent);
-	if (ret < 0) {
-		rxrpc_call_abort(call, ret); /* handle from kafsasyncd */
-		ret = 0;
-		goto out;
-	}
-
-	/* wait for the reply to completely arrive */
-	ret = rxrpc_call_read_data(call, call->app_scr_ptr, 384, 0);
-	switch (ret) {
-	case 0:
-	case -EAGAIN:
-	case -ECONNABORTED:
-		ret = 0;
-		break;	/* all handled by kafsasyncd */
-
-	default:
-		rxrpc_call_abort(call, ret); /* make kafsasyncd handle it */
-		ret = 0;
-		break;
-	}
-
- out:
-	rxrpc_put_call(call);
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end afs_rxvl_get_entry_by_id_async() */
+/*
+ * VL.GetEntryById operation type
+ */
+static const struct afs_call_type afs_RXVLGetEntryById = {
+	.name		= "VL.GetEntryById",
+	.deliver	= afs_deliver_vl_get_entry_by_xxx,
+	.abort_to_error	= afs_vl_abort_to_error,
+	.destructor	= afs_flat_call_destructor,
+};
 
-/*****************************************************************************/
 /*
- * attend to the asynchronous get VLDB entry by ID
+ * dispatch a get volume entry by name operation
  */
-int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
-				    struct afs_cache_vlocation *entry)
+int afs_vl_get_entry_by_name(struct in_addr *addr,
+			     struct key *key,
+			     const char *volname,
+			     struct afs_cache_vlocation *entry,
+			     const struct afs_wait_mode *wait_mode)
 {
+	struct afs_call *call;
+	size_t volnamesz, reqsz, padsz;
 	__be32 *bp;
-	__u32 tmp;
-	int loop, ret;
-
-	_enter("{op=%p cst=%u}", op, op->call->app_call_state);
-
-	memset(entry, 0, sizeof(*entry));
-
-	if (op->call->app_call_state == RXRPC_CSTATE_COMPLETE) {
-		/* operation finished */
-		afs_kafsasyncd_terminate_op(op);
-
-		bp = op->call->app_scr_ptr;
-
-		/* unmarshall the reply */
-		for (loop = 0; loop < 64; loop++)
-			entry->name[loop] = ntohl(*bp++);
-		bp++; /* final NUL */
-
-		bp++; /* type */
-		entry->nservers = ntohl(*bp++);
-
-		for (loop = 0; loop < 8; loop++)
-			entry->servers[loop].s_addr = *bp++;
-
-		bp += 8; /* partition IDs */
-
-		for (loop = 0; loop < 8; loop++) {
-			tmp = ntohl(*bp++);
-			if (tmp & AFS_VLSF_RWVOL)
-				entry->srvtmask[loop] |= AFS_VOL_VTM_RW;
-			if (tmp & AFS_VLSF_ROVOL)
-				entry->srvtmask[loop] |= AFS_VOL_VTM_RO;
-			if (tmp & AFS_VLSF_BACKVOL)
-				entry->srvtmask[loop] |= AFS_VOL_VTM_BAK;
-		}
-
-		entry->vid[0] = ntohl(*bp++);
-		entry->vid[1] = ntohl(*bp++);
-		entry->vid[2] = ntohl(*bp++);
-
-		bp++; /* clone ID */
-
-		tmp = ntohl(*bp++); /* flags */
-		if (tmp & AFS_VLF_RWEXISTS)
-			entry->vidmask |= AFS_VOL_VTM_RW;
-		if (tmp & AFS_VLF_ROEXISTS)
-			entry->vidmask |= AFS_VOL_VTM_RO;
-		if (tmp & AFS_VLF_BACKEXISTS)
-			entry->vidmask |= AFS_VOL_VTM_BAK;
-
-		ret = -ENOMEDIUM;
-		if (!entry->vidmask) {
-			rxrpc_call_abort(op->call, ret);
-			goto done;
-		}
-
-#if 0 /* TODO: remove */
-		entry->nservers = 3;
-		entry->servers[0].s_addr = htonl(0xac101249);
-		entry->servers[1].s_addr = htonl(0xac101243);
-		entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
-
-		entry->srvtmask[0] = AFS_VOL_VTM_RO;
-		entry->srvtmask[1] = AFS_VOL_VTM_RO;
-		entry->srvtmask[2] = AFS_VOL_VTM_RO | AFS_VOL_VTM_RW;
-#endif
-
-		/* success */
-		entry->rtime = get_seconds();
-		ret = 0;
-		goto done;
-	}
 
-	if (op->call->app_call_state == RXRPC_CSTATE_ERROR) {
-		/* operation error */
-		ret = op->call->app_errno;
-		goto done;
-	}
+	_enter("");
 
-	_leave(" = -EAGAIN");
-	return -EAGAIN;
+	volnamesz = strlen(volname);
+	padsz = (4 - (volnamesz & 3)) & 3;
+	reqsz = 8 + volnamesz + padsz;
 
- done:
-	rxrpc_put_call(op->call);
-	op->call = NULL;
-	_leave(" = %d", ret);
-	return ret;
-} /* end afs_rxvl_get_entry_by_id_async2() */
+	call = afs_alloc_flat_call(&afs_RXVLGetEntryByName, reqsz, 384);
+	if (!call)
+		return -ENOMEM;
 
-/*****************************************************************************/
-/*
- * handle attention events on an async get-entry-by-ID op
- * - called from krxiod
- */
-static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
-{
-	struct afs_async_op *op = call->app_user;
-
-	_enter("{op=%p cst=%u}", op, call->app_call_state);
-
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_COMPLETE:
-		afs_kafsasyncd_attend_op(op);
-		break;
-	case RXRPC_CSTATE_CLNT_RCV_REPLY:
-		if (call->app_async_read)
-			break;
-	case RXRPC_CSTATE_CLNT_GOT_REPLY:
-		if (call->app_read_count == 0)
-			break;
-		printk("kAFS: Reply bigger than expected"
-		       " {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}",
-		       call->app_call_state,
-		       call->app_async_read,
-		       call->app_mark,
-		       call->app_ready_qty,
-		       call->pkt_rcv_count,
-		       call->app_last_rcv ? " last" : "");
-
-		rxrpc_call_abort(call, -EBADMSG);
-		break;
-	default:
-		BUG();
-	}
+	call->key = key;
+	call->reply = entry;
+	call->service_id = VL_SERVICE;
+	call->port = htons(AFS_VL_PORT);
 
-	_leave("");
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(VLGETENTRYBYNAME);
+	*bp++ = htonl(volnamesz);
+	memcpy(bp, volname, volnamesz);
+	if (padsz > 0)
+		memset((void *) bp + volnamesz, 0, padsz);
 
-} /* end afs_rxvl_get_entry_by_id_attn() */
+	/* initiate the call */
+	return afs_make_call(addr, call, GFP_KERNEL, wait_mode);
+}
 
-/*****************************************************************************/
 /*
- * handle error events on an async get-entry-by-ID op
- * - called from krxiod
+ * dispatch a get volume entry by ID operation
  */
-static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
+int afs_vl_get_entry_by_id(struct in_addr *addr,
+			   struct key *key,
+			   afs_volid_t volid,
+			   afs_voltype_t voltype,
+			   struct afs_cache_vlocation *entry,
+			   const struct afs_wait_mode *wait_mode)
 {
-	struct afs_async_op *op = call->app_user;
+	struct afs_call *call;
+	__be32 *bp;
 
-	_enter("{op=%p cst=%u}", op, call->app_call_state);
+	_enter("");
 
-	afs_kafsasyncd_attend_op(op);
+	call = afs_alloc_flat_call(&afs_RXVLGetEntryById, 12, 384);
+	if (!call)
+		return -ENOMEM;
 
-	_leave("");
+	call->key = key;
+	call->reply = entry;
+	call->service_id = VL_SERVICE;
+	call->port = htons(AFS_VL_PORT);
 
-} /* end afs_rxvl_get_entry_by_id_error() */
+	/* marshall the parameters */
+	bp = call->request;
+	*bp++ = htonl(VLGETENTRYBYID);
+	*bp++ = htonl(volid);
+	*bp   = htonl(voltype);
+
+	/* initiate the call */
+	return afs_make_call(addr, call, GFP_KERNEL, wait_mode);
+}
diff --git a/fs/afs/vlclient.h b/fs/afs/vlclient.h
deleted file mode 100644
index e3d6011..0000000
--- a/fs/afs/vlclient.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* vlclient.h: Volume Location Service client interface
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_VLCLIENT_H
-#define _LINUX_AFS_VLCLIENT_H
-
-#include "types.h"
-
-enum AFSVL_Errors {
-	AFSVL_IDEXIST 		= 363520,	/* Volume Id entry exists in vl database */
-	AFSVL_IO 		= 363521,	/* I/O related error */
-	AFSVL_NAMEEXIST 	= 363522,	/* Volume name entry exists in vl database */
-	AFSVL_CREATEFAIL 	= 363523,	/* Internal creation failure */
-	AFSVL_NOENT 		= 363524,	/* No such entry */
-	AFSVL_EMPTY 		= 363525,	/* Vl database is empty */
-	AFSVL_ENTDELETED 	= 363526,	/* Entry is deleted (soft delete) */
-	AFSVL_BADNAME 		= 363527,	/* Volume name is illegal */
-	AFSVL_BADINDEX 		= 363528,	/* Index is out of range */
-	AFSVL_BADVOLTYPE 	= 363529,	/* Bad volume type */
-	AFSVL_BADSERVER 	= 363530,	/* Illegal server number (out of range) */
-	AFSVL_BADPARTITION 	= 363531,	/* Bad partition number */
-	AFSVL_REPSFULL 		= 363532,	/* Run out of space for Replication sites */
-	AFSVL_NOREPSERVER 	= 363533,	/* No such Replication server site exists */
-	AFSVL_DUPREPSERVER 	= 363534,	/* Replication site already exists */
-	AFSVL_RWNOTFOUND 	= 363535,	/* Parent R/W entry not found */
-	AFSVL_BADREFCOUNT 	= 363536,	/* Illegal Reference Count number */
-	AFSVL_SIZEEXCEEDED 	= 363537,	/* Vl size for attributes exceeded */
-	AFSVL_BADENTRY 		= 363538,	/* Bad incoming vl entry */
-	AFSVL_BADVOLIDBUMP 	= 363539,	/* Illegal max volid increment */
-	AFSVL_IDALREADYHASHED 	= 363540,	/* RO/BACK id already hashed */
-	AFSVL_ENTRYLOCKED 	= 363541,	/* Vl entry is already locked */
-	AFSVL_BADVOLOPER 	= 363542,	/* Bad volume operation code */
-	AFSVL_BADRELLOCKTYPE 	= 363543,	/* Bad release lock type */
-	AFSVL_RERELEASE 	= 363544,	/* Status report: last release was aborted */
-	AFSVL_BADSERVERFLAG 	= 363545,	/* Invalid replication site server °ag */
-	AFSVL_PERM 		= 363546,	/* No permission access */
-	AFSVL_NOMEM 		= 363547,	/* malloc/realloc failed to alloc enough memory */
-};
-
-/* maps to "struct vldbentry" in vvl-spec.pdf */
-struct afs_vldbentry {
-	char		name[65];		/* name of volume (including NUL char) */
-	afs_voltype_t	type;			/* volume type */
-	unsigned	num_servers;		/* num servers that hold instances of this vol */
-	unsigned	clone_id;		/* cloning ID */
-
-	unsigned	flags;
-#define AFS_VLF_RWEXISTS	0x1000		/* R/W volume exists */
-#define AFS_VLF_ROEXISTS	0x2000		/* R/O volume exists */
-#define AFS_VLF_BACKEXISTS	0x4000		/* backup volume exists */
-
-	afs_volid_t	volume_ids[3];		/* volume IDs */
-
-	struct {
-		struct in_addr	addr;		/* server address */
-		unsigned	partition;	/* partition ID on this server */
-		unsigned	flags;		/* server specific flags */
-#define AFS_VLSF_NEWREPSITE	0x0001	/* unused */
-#define AFS_VLSF_ROVOL		0x0002	/* this server holds a R/O instance of the volume */
-#define AFS_VLSF_RWVOL		0x0004	/* this server holds a R/W instance of the volume */
-#define AFS_VLSF_BACKVOL	0x0008	/* this server holds a backup instance of the volume */
-	} servers[8];
-
-};
-
-/* look up a volume location database entry by name */
-extern int afs_rxvl_get_entry_by_name(struct afs_server *server,
-				      const char *volname,
-				      unsigned volnamesz,
-				      struct afs_cache_vlocation *entry);
-
-/* look up a volume location database entry by ID */
-extern int afs_rxvl_get_entry_by_id(struct afs_server *server,
-				    afs_volid_t	volid,
-				    afs_voltype_t voltype,
-				    struct afs_cache_vlocation *entry);
-
-extern int afs_rxvl_get_entry_by_id_async(struct afs_async_op *op,
-					  afs_volid_t volid,
-					  afs_voltype_t voltype);
-
-extern int afs_rxvl_get_entry_by_id_async2(struct afs_async_op *op,
-					   struct afs_cache_vlocation *entry);
-
-#endif /* _LINUX_AFS_VLCLIENT_H */
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index 782ee7c..3370cdb 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -1,6 +1,6 @@
-/* vlocation.c: volume location management
+/* AFS volume location management
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -12,131 +12,61 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include "volume.h"
-#include "cell.h"
-#include "cmservice.h"
-#include "fsclient.h"
-#include "vlclient.h"
-#include "kafstimod.h"
-#include <rxrpc/connection.h>
 #include "internal.h"
 
-#define AFS_VLDB_TIMEOUT HZ*1000
+unsigned afs_vlocation_timeout = 10;	/* volume location timeout in seconds */
+unsigned afs_vlocation_update_timeout = 10 * 60;
 
-static void afs_vlocation_update_timer(struct afs_timer *timer);
-static void afs_vlocation_update_attend(struct afs_async_op *op);
-static void afs_vlocation_update_discard(struct afs_async_op *op);
-static void __afs_put_vlocation(struct afs_vlocation *vlocation);
+static void afs_vlocation_reaper(struct work_struct *);
+static void afs_vlocation_updater(struct work_struct *);
 
-static void __afs_vlocation_timeout(struct afs_timer *timer)
-{
-	struct afs_vlocation *vlocation =
-		list_entry(timer, struct afs_vlocation, timeout);
-
-	_debug("VL TIMEOUT [%s{u=%d}]",
-	       vlocation->vldb.name, atomic_read(&vlocation->usage));
-
-	afs_vlocation_do_timeout(vlocation);
-}
-
-static const struct afs_timer_ops afs_vlocation_timer_ops = {
-	.timed_out	= __afs_vlocation_timeout,
-};
+static LIST_HEAD(afs_vlocation_updates);
+static LIST_HEAD(afs_vlocation_graveyard);
+static DEFINE_SPINLOCK(afs_vlocation_updates_lock);
+static DEFINE_SPINLOCK(afs_vlocation_graveyard_lock);
+static DECLARE_DELAYED_WORK(afs_vlocation_reap, afs_vlocation_reaper);
+static DECLARE_DELAYED_WORK(afs_vlocation_update, afs_vlocation_updater);
+static struct workqueue_struct *afs_vlocation_update_worker;
 
-static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
-	.timed_out	= afs_vlocation_update_timer,
-};
-
-static const struct afs_async_op_ops afs_vlocation_update_op_ops = {
-	.attend		= afs_vlocation_update_attend,
-	.discard	= afs_vlocation_update_discard,
-};
-
-static LIST_HEAD(afs_vlocation_update_pendq);	/* queue of VLs awaiting update */
-static struct afs_vlocation *afs_vlocation_update;	/* VL currently being updated */
-static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */
-
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
-						     const void *entry);
-static void afs_vlocation_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_vlocation_cache_index_def = {
-	.name		= "vldb",
-	.data_size	= sizeof(struct afs_cache_vlocation),
-	.keys[0]	= { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
-	.match		= afs_vlocation_cache_match,
-	.update		= afs_vlocation_cache_update,
-};
-#endif
-
-/*****************************************************************************/
 /*
  * iterate through the VL servers in a cell until one of them admits knowing
  * about the volume in question
- * - caller must have cell->vl_sem write-locked
  */
-static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation,
-					   const char *name,
-					   unsigned namesz,
+static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl,
+					   struct key *key,
 					   struct afs_cache_vlocation *vldb)
 {
-	struct afs_server *server = NULL;
-	struct afs_cell *cell = vlocation->cell;
+	struct afs_cell *cell = vl->cell;
+	struct in_addr addr;
 	int count, ret;
 
-	_enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz);
+	_enter("%s,%s", cell->name, vl->vldb.name);
 
+	down_write(&vl->cell->vl_sem);
 	ret = -ENOMEDIUM;
 	for (count = cell->vl_naddrs; count > 0; count--) {
-		_debug("CellServ[%hu]: %08x",
-		       cell->vl_curr_svix,
-		       cell->vl_addrs[cell->vl_curr_svix].s_addr);
-
-		/* try and create a server */
-		ret = afs_server_lookup(cell,
-					&cell->vl_addrs[cell->vl_curr_svix],
-					&server);
-		switch (ret) {
-		case 0:
-			break;
-		case -ENOMEM:
-		case -ENONET:
-			goto out;
-		default:
-			goto rotate;
-		}
+		addr = cell->vl_addrs[cell->vl_curr_svix];
+
+		_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);
 
 		/* attempt to access the VL server */
-		ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb);
+		ret = afs_vl_get_entry_by_name(&addr, key, vl->vldb.name, vldb,
+					       &afs_sync_call);
 		switch (ret) {
 		case 0:
-			afs_put_server(server);
 			goto out;
 		case -ENOMEM:
 		case -ENONET:
 		case -ENETUNREACH:
 		case -EHOSTUNREACH:
 		case -ECONNREFUSED:
-			down_write(&server->sem);
-			if (server->vlserver) {
-				rxrpc_put_connection(server->vlserver);
-				server->vlserver = NULL;
-			}
-			up_write(&server->sem);
-			afs_put_server(server);
 			if (ret == -ENOMEM || ret == -ENONET)
 				goto out;
 			goto rotate;
 		case -ENOMEDIUM:
-			afs_put_server(server);
 			goto out;
 		default:
-			afs_put_server(server);
-			ret = -ENOMEDIUM;
+			ret = -EIO;
 			goto rotate;
 		}
 
@@ -146,76 +76,66 @@ static int afs_vlocation_access_vl_by_na
 		cell->vl_curr_svix %= cell->vl_naddrs;
 	}
 
- out:
+out:
+	up_write(&vl->cell->vl_sem);
 	_leave(" = %d", ret);
 	return ret;
+}
 
-} /* end afs_vlocation_access_vl_by_name() */
-
-/*****************************************************************************/
 /*
  * iterate through the VL servers in a cell until one of them admits knowing
  * about the volume in question
- * - caller must have cell->vl_sem write-locked
  */
-static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation,
+static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vl,
+					 struct key *key,
 					 afs_volid_t volid,
 					 afs_voltype_t voltype,
 					 struct afs_cache_vlocation *vldb)
 {
-	struct afs_server *server = NULL;
-	struct afs_cell *cell = vlocation->cell;
+	struct afs_cell *cell = vl->cell;
+	struct in_addr addr;
 	int count, ret;
 
 	_enter("%s,%x,%d,", cell->name, volid, voltype);
 
+	down_write(&vl->cell->vl_sem);
 	ret = -ENOMEDIUM;
 	for (count = cell->vl_naddrs; count > 0; count--) {
-		_debug("CellServ[%hu]: %08x",
-		       cell->vl_curr_svix,
-		       cell->vl_addrs[cell->vl_curr_svix].s_addr);
-
-		/* try and create a server */
-		ret = afs_server_lookup(cell,
-					&cell->vl_addrs[cell->vl_curr_svix],
-					&server);
-		switch (ret) {
-		case 0:
-			break;
-		case -ENOMEM:
-		case -ENONET:
-			goto out;
-		default:
-			goto rotate;
-		}
+		addr = cell->vl_addrs[cell->vl_curr_svix];
+
+		_debug("CellServ[%hu]: %08x", cell->vl_curr_svix, addr.s_addr);
 
 		/* attempt to access the VL server */
-		ret = afs_rxvl_get_entry_by_id(server, volid, voltype, vldb);
+		ret = afs_vl_get_entry_by_id(&addr, key, volid, voltype, vldb,
+					     &afs_sync_call);
 		switch (ret) {
 		case 0:
-			afs_put_server(server);
 			goto out;
 		case -ENOMEM:
 		case -ENONET:
 		case -ENETUNREACH:
 		case -EHOSTUNREACH:
 		case -ECONNREFUSED:
-			down_write(&server->sem);
-			if (server->vlserver) {
-				rxrpc_put_connection(server->vlserver);
-				server->vlserver = NULL;
-			}
-			up_write(&server->sem);
-			afs_put_server(server);
 			if (ret == -ENOMEM || ret == -ENONET)
 				goto out;
 			goto rotate;
+		case -EBUSY:
+			vl->upd_busy_cnt++;
+			if (vl->upd_busy_cnt <= 3) {
+				if (vl->upd_busy_cnt > 1) {
+					/* second+ BUSY - sleep a little bit */
+					set_current_state(TASK_UNINTERRUPTIBLE);
+					schedule_timeout(1);
+					__set_current_state(TASK_RUNNING);
+				}
+				continue;
+			}
+			break;
 		case -ENOMEDIUM:
-			afs_put_server(server);
-			goto out;
+			vl->upd_rej_cnt++;
+			goto rotate;
 		default:
-			afs_put_server(server);
-			ret = -ENOMEDIUM;
+			ret = -EIO;
 			goto rotate;
 		}
 
@@ -223,729 +143,579 @@ static int afs_vlocation_access_vl_by_id
 	rotate:
 		cell->vl_curr_svix++;
 		cell->vl_curr_svix %= cell->vl_naddrs;
+		vl->upd_busy_cnt = 0;
 	}
 
- out:
+out:
+	if (ret < 0 && vl->upd_rej_cnt > 0) {
+		printk(KERN_NOTICE "kAFS:"
+		       " Active volume no longer valid '%s'\n",
+		       vl->vldb.name);
+		vl->valid = 0;
+		ret = -ENOMEDIUM;
+	}
+
+	up_write(&vl->cell->vl_sem);
 	_leave(" = %d", ret);
 	return ret;
+}
 
-} /* end afs_vlocation_access_vl_by_id() */
-
-/*****************************************************************************/
 /*
- * lookup volume location
- * - caller must have cell->vol_sem write-locked
- * - iterate through the VL servers in a cell until one of them admits knowing
- *   about the volume in question
- * - lookup in the local cache if not able to find on the VL server
- * - insert/update in the local cache if did get a VL response
+ * allocate a volume location record
  */
-int afs_vlocation_lookup(struct afs_cell *cell,
-			 const char *name,
-			 unsigned namesz,
-			 struct afs_vlocation **_vlocation)
+static struct afs_vlocation *afs_vlocation_alloc(struct afs_cell *cell,
+						 const char *name,
+						 size_t namesz)
 {
-	struct afs_cache_vlocation vldb;
-	struct afs_vlocation *vlocation;
-	afs_voltype_t voltype;
-	afs_volid_t vid;
-	int active = 0, ret;
-
-	_enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz);
-
-	if (namesz > sizeof(vlocation->vldb.name)) {
-		_leave(" = -ENAMETOOLONG");
-		return -ENAMETOOLONG;
-	}
-
-	/* search the cell's active list first */
-	list_for_each_entry(vlocation, &cell->vl_list, link) {
-		if (namesz < sizeof(vlocation->vldb.name) &&
-		    vlocation->vldb.name[namesz] != '\0')
-			continue;
-
-		if (memcmp(vlocation->vldb.name, name, namesz) == 0)
-			goto found_in_memory;
-	}
-
-	/* search the cell's graveyard list second */
-	spin_lock(&cell->vl_gylock);
-	list_for_each_entry(vlocation, &cell->vl_graveyard, link) {
-		if (namesz < sizeof(vlocation->vldb.name) &&
-		    vlocation->vldb.name[namesz] != '\0')
-			continue;
-
-		if (memcmp(vlocation->vldb.name, name, namesz) == 0)
-			goto found_in_graveyard;
-	}
-	spin_unlock(&cell->vl_gylock);
-
-	/* not in the cell's in-memory lists - create a new record */
-	vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
-	if (!vlocation)
-		return -ENOMEM;
-
-	atomic_set(&vlocation->usage, 1);
-	INIT_LIST_HEAD(&vlocation->link);
-	rwlock_init(&vlocation->lock);
-	memcpy(vlocation->vldb.name, name, namesz);
-
-	afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops);
-	afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops);
-	afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops);
-
-	afs_get_cell(cell);
-	vlocation->cell = cell;
-
-	list_add_tail(&vlocation->link, &cell->vl_list);
-
-#ifdef AFS_CACHING_SUPPORT
-	/* we want to store it in the cache, plus it might already be
-	 * encached */
-	cachefs_acquire_cookie(cell->cache,
-			       &afs_volume_cache_index_def,
-			       vlocation,
-			       &vlocation->cache);
-
-	if (vlocation->valid)
-		goto found_in_cache;
-#endif
-
-	/* try to look up an unknown volume in the cell VL databases by name */
-	ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb);
-	if (ret < 0) {
-		printk("kAFS: failed to locate '%*.*s' in cell '%s'\n",
-		       namesz, namesz, name, cell->name);
-		goto error;
+	struct afs_vlocation *vl;
+
+	vl = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
+	if (vl) {
+		vl->cell = cell;
+		vl->state = AFS_VL_NEW;
+		atomic_set(&vl->usage, 1);
+		INIT_LIST_HEAD(&vl->link);
+		INIT_LIST_HEAD(&vl->grave);
+		INIT_LIST_HEAD(&vl->update);
+		init_waitqueue_head(&vl->waitq);
+		spin_lock_init(&vl->lock);
+		memcpy(vl->vldb.name, name, namesz);
 	}
 
-	goto found_on_vlserver;
-
- found_in_graveyard:
-	/* found in the graveyard - resurrect */
-	_debug("found in graveyard");
-	atomic_inc(&vlocation->usage);
-	list_move_tail(&vlocation->link, &cell->vl_list);
-	spin_unlock(&cell->vl_gylock);
-
-	afs_kafstimod_del_timer(&vlocation->timeout);
-	goto active;
-
- found_in_memory:
-	/* found in memory - check to see if it's active */
-	_debug("found in memory");
-	atomic_inc(&vlocation->usage);
+	_leave(" = %p", vl);
+	return vl;
+}
 
- active:
-	active = 1;
+/*
+ * update record if we found it in the cache
+ */
+static int afs_vlocation_update_record(struct afs_vlocation *vl,
+				       struct key *key,
+				       struct afs_cache_vlocation *vldb)
+{
+	afs_voltype_t voltype;
+	afs_volid_t vid;
+	int ret;
 
-#ifdef AFS_CACHING_SUPPORT
- found_in_cache:
-#endif
 	/* try to look up a cached volume in the cell VL databases by ID */
-	_debug("found in cache");
-
 	_debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
-	       vlocation->vldb.name,
-	       vlocation->vldb.vidmask,
-	       ntohl(vlocation->vldb.servers[0].s_addr),
-	       vlocation->vldb.srvtmask[0],
-	       ntohl(vlocation->vldb.servers[1].s_addr),
-	       vlocation->vldb.srvtmask[1],
-	       ntohl(vlocation->vldb.servers[2].s_addr),
-	       vlocation->vldb.srvtmask[2]
-	       );
+	       vl->vldb.name,
+	       vl->vldb.vidmask,
+	       ntohl(vl->vldb.servers[0].s_addr),
+	       vl->vldb.srvtmask[0],
+	       ntohl(vl->vldb.servers[1].s_addr),
+	       vl->vldb.srvtmask[1],
+	       ntohl(vl->vldb.servers[2].s_addr),
+	       vl->vldb.srvtmask[2]);
 
 	_debug("Vids: %08x %08x %08x",
-	       vlocation->vldb.vid[0],
-	       vlocation->vldb.vid[1],
-	       vlocation->vldb.vid[2]);
+	       vl->vldb.vid[0],
+	       vl->vldb.vid[1],
+	       vl->vldb.vid[2]);
 
-	if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
-		vid = vlocation->vldb.vid[0];
+	if (vl->vldb.vidmask & AFS_VOL_VTM_RW) {
+		vid = vl->vldb.vid[0];
 		voltype = AFSVL_RWVOL;
-	}
-	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
-		vid = vlocation->vldb.vid[1];
+	} else if (vl->vldb.vidmask & AFS_VOL_VTM_RO) {
+		vid = vl->vldb.vid[1];
 		voltype = AFSVL_ROVOL;
-	}
-	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
-		vid = vlocation->vldb.vid[2];
+	} else if (vl->vldb.vidmask & AFS_VOL_VTM_BAK) {
+		vid = vl->vldb.vid[2];
 		voltype = AFSVL_BACKVOL;
-	}
-	else {
+	} else {
 		BUG();
 		vid = 0;
 		voltype = 0;
 	}
 
-	ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb);
+	/* contact the server to make sure the volume is still available
+	 * - TODO: need to handle disconnected operation here
+	 */
+	ret = afs_vlocation_access_vl_by_id(vl, key, vid, voltype, vldb);
 	switch (ret) {
 		/* net error */
 	default:
-		printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n",
-		       namesz, namesz, name, vid, cell->name, ret);
-		goto error;
+		printk(KERN_WARNING "kAFS:"
+		       " failed to update volume '%s' (%x) up in '%s': %d\n",
+		       vl->vldb.name, vid, vl->cell->name, ret);
+		_leave(" = %d", ret);
+		return ret;
 
 		/* pulled from local cache into memory */
 	case 0:
-		goto found_on_vlserver;
+		_leave(" = 0");
+		return 0;
 
 		/* uh oh... looks like the volume got deleted */
 	case -ENOMEDIUM:
-		printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n",
-		       namesz, namesz, name, vid, cell->name);
+		printk(KERN_ERR "kAFS:"
+		       " volume '%s' (%x) does not exist '%s'\n",
+		       vl->vldb.name, vid, vl->cell->name);
 
 		/* TODO: make existing record unavailable */
-		goto error;
+		_leave(" = %d", ret);
+		return ret;
 	}
+}
 
- found_on_vlserver:
-	_debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }",
-	       namesz, namesz, name,
-	       vldb.vidmask,
-	       ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
-	       ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
-	       ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
-	       );
-
-	_debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]);
+/*
+ * apply the update to a VL record
+ */
+static void afs_vlocation_apply_update(struct afs_vlocation *vl,
+				       struct afs_cache_vlocation *vldb)
+{
+	_debug("Done VL Lookup: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
+	       vldb->name, vldb->vidmask,
+	       ntohl(vldb->servers[0].s_addr), vldb->srvtmask[0],
+	       ntohl(vldb->servers[1].s_addr), vldb->srvtmask[1],
+	       ntohl(vldb->servers[2].s_addr), vldb->srvtmask[2]);
 
-	if ((namesz < sizeof(vlocation->vldb.name) &&
-	     vlocation->vldb.name[namesz] != '\0') ||
-	    memcmp(vldb.name, name, namesz) != 0)
-		printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n",
-		       namesz, namesz, name, vldb.name);
+	_debug("Vids: %08x %08x %08x",
+	       vldb->vid[0], vldb->vid[1], vldb->vid[2]);
 
-	memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
+	if (strcmp(vldb->name, vl->vldb.name) != 0)
+		printk(KERN_NOTICE "kAFS:"
+		       " name of volume '%s' changed to '%s' on server\n",
+		       vl->vldb.name, vldb->name);
 
-	afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ);
+	vl->vldb = *vldb;
 
 #ifdef AFS_CACHING_SUPPORT
 	/* update volume entry in local cache */
-	cachefs_update_cookie(vlocation->cache);
-#endif
-
-	*_vlocation = vlocation;
-	_leave(" = 0 (%p)",vlocation);
-	return 0;
-
- error:
-	if (vlocation) {
-		if (active) {
-			__afs_put_vlocation(vlocation);
-		}
-		else {
-			list_del(&vlocation->link);
-#ifdef AFS_CACHING_SUPPORT
-			cachefs_relinquish_cookie(vlocation->cache, 0);
+	cachefs_update_cookie(vl->cache);
 #endif
-			afs_put_cell(vlocation->cell);
-			kfree(vlocation);
-		}
-	}
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end afs_vlocation_lookup() */
+}
 
-/*****************************************************************************/
 /*
- * finish using a volume location record
- * - caller must have cell->vol_sem write-locked
+ * fill in a volume location record, consulting the cache and the VL server
+ * both
  */
-static void __afs_put_vlocation(struct afs_vlocation *vlocation)
+static int afs_vlocation_fill_in_record(struct afs_vlocation *vl,
+					struct key *key)
 {
-	struct afs_cell *cell;
+	struct afs_cache_vlocation vldb;
+	int ret;
 
-	if (!vlocation)
-		return;
+	_enter("");
 
-	_enter("%s", vlocation->vldb.name);
+	ASSERTCMP(vl->valid, ==, 0);
 
-	cell = vlocation->cell;
+	memset(&vldb, 0, sizeof(vldb));
 
-	/* sanity check */
-	BUG_ON(atomic_read(&vlocation->usage) <= 0);
+	/* see if we have an in-cache copy (will set vl->valid if there is) */
+#ifdef AFS_CACHING_SUPPORT
+	cachefs_acquire_cookie(cell->cache,
+			       &afs_volume_cache_index_def,
+			       vlocation,
+			       &vl->cache);
+#endif
 
-	spin_lock(&cell->vl_gylock);
-	if (likely(!atomic_dec_and_test(&vlocation->usage))) {
-		spin_unlock(&cell->vl_gylock);
-		_leave("");
-		return;
+	if (vl->valid) {
+		/* try to update a known volume in the cell VL databases by
+		 * ID as the name may have changed */
+		_debug("found in cache");
+		ret = afs_vlocation_update_record(vl, key, &vldb);
+	} else {
+		/* try to look up an unknown volume in the cell VL databases by
+		 * name */
+		ret = afs_vlocation_access_vl_by_name(vl, key, &vldb);
+		if (ret < 0) {
+			printk("kAFS: failed to locate '%s' in cell '%s'\n",
+			       vl->vldb.name, vl->cell->name);
+			return ret;
+		}
 	}
 
-	/* move to graveyard queue */
-	list_move_tail(&vlocation->link,&cell->vl_graveyard);
-
-	/* remove from pending timeout queue (refcounted if actually being
-	 * updated) */
-	list_del_init(&vlocation->upd_op.link);
-
-	/* time out in 10 secs */
-	afs_kafstimod_del_timer(&vlocation->upd_timer);
-	afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ);
-
-	spin_unlock(&cell->vl_gylock);
-
-	_leave(" [killed]");
-} /* end __afs_put_vlocation() */
-
-/*****************************************************************************/
-/*
- * finish using a volume location record
- */
-void afs_put_vlocation(struct afs_vlocation *vlocation)
-{
-	if (vlocation) {
-		struct afs_cell *cell = vlocation->cell;
-
-		down_write(&cell->vl_sem);
-		__afs_put_vlocation(vlocation);
-		up_write(&cell->vl_sem);
-	}
-} /* end afs_put_vlocation() */
+	afs_vlocation_apply_update(vl, &vldb);
+	_leave(" = 0");
+	return 0;
+}
 
-/*****************************************************************************/
 /*
- * timeout vlocation record
- * - removes from the cell's graveyard if the usage count is zero
+ * queue a vlocation record for updates
  */
-void afs_vlocation_do_timeout(struct afs_vlocation *vlocation)
+void afs_vlocation_queue_for_updates(struct afs_vlocation *vl)
 {
-	struct afs_cell *cell;
+	struct afs_vlocation *xvl;
 
-	_enter("%s", vlocation->vldb.name);
+	/* wait at least 10 minutes before updating... */
+	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
 
-	cell = vlocation->cell;
+	spin_lock(&afs_vlocation_updates_lock);
 
-	BUG_ON(atomic_read(&vlocation->usage) < 0);
-
-	/* remove from graveyard if still dead */
-	spin_lock(&cell->vl_gylock);
-	if (atomic_read(&vlocation->usage) == 0)
-		list_del_init(&vlocation->link);
-	else
-		vlocation = NULL;
-	spin_unlock(&cell->vl_gylock);
-
-	if (!vlocation) {
-		_leave("");
-		return; /* resurrected */
+	if (!list_empty(&afs_vlocation_updates)) {
+		/* ... but wait at least 1 second more than the newest record
+		 * already queued so that we don't spam the VL server suddenly
+		 * with lots of requests
+		 */
+		xvl = list_entry(afs_vlocation_updates.prev,
+				 struct afs_vlocation, update);
+		if (vl->update_at <= xvl->update_at)
+			vl->update_at = xvl->update_at + 1;
+	} else {
+		queue_delayed_work(afs_vlocation_update_worker,
+				   &afs_vlocation_update,
+				   afs_vlocation_update_timeout * HZ);
 	}
 
-	/* we can now destroy it properly */
-#ifdef AFS_CACHING_SUPPORT
-	cachefs_relinquish_cookie(vlocation->cache, 0);
-#endif
-	afs_put_cell(cell);
-
-	kfree(vlocation);
-
-	_leave(" [destroyed]");
-} /* end afs_vlocation_do_timeout() */
+	list_add_tail(&vl->update, &afs_vlocation_updates);
+	spin_unlock(&afs_vlocation_updates_lock);
+}
 
-/*****************************************************************************/
 /*
- * send an update operation to the currently selected server
+ * lookup volume location
+ * - iterate through the VL servers in a cell until one of them admits knowing
+ *   about the volume in question
+ * - lookup in the local cache if not able to find on the VL server
+ * - insert/update in the local cache if did get a VL response
  */
-static int afs_vlocation_update_begin(struct afs_vlocation *vlocation)
+struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *cell,
+					   struct key *key,
+					   const char *name,
+					   size_t namesz)
 {
-	afs_voltype_t voltype;
-	afs_volid_t vid;
+	struct afs_vlocation *vl;
 	int ret;
 
-	_enter("%s{ufs=%u ucs=%u}",
-	       vlocation->vldb.name,
-	       vlocation->upd_first_svix,
-	       vlocation->upd_curr_svix);
+	_enter("{%s},{%x},%*.*s,%zu",
+	       cell->name, key_serial(key),
+	       (int) namesz, (int) namesz, name, namesz);
 
-	/* try to look up a cached volume in the cell VL databases by ID */
-	if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
-		vid = vlocation->vldb.vid[0];
-		voltype = AFSVL_RWVOL;
-	}
-	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
-		vid = vlocation->vldb.vid[1];
-		voltype = AFSVL_ROVOL;
+	if (namesz > sizeof(vl->vldb.name)) {
+		_leave(" = -ENAMETOOLONG");
+		return ERR_PTR(-ENAMETOOLONG);
 	}
-	else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
-		vid = vlocation->vldb.vid[2];
-		voltype = AFSVL_BACKVOL;
+
+	/* see if we have an in-memory copy first */
+	down_write(&cell->vl_sem);
+	spin_lock(&cell->vl_lock);
+	list_for_each_entry(vl, &cell->vl_list, link) {
+		if (vl->vldb.name[namesz] != '\0')
+			continue;
+		if (memcmp(vl->vldb.name, name, namesz) == 0)
+			goto found_in_memory;
 	}
-	else {
-		BUG();
-		vid = 0;
-		voltype = 0;
+	spin_unlock(&cell->vl_lock);
+
+	/* not in the cell's in-memory lists - create a new record */
+	vl = afs_vlocation_alloc(cell, name, namesz);
+	if (!vl) {
+		up_write(&cell->vl_sem);
+		return ERR_PTR(-ENOMEM);
 	}
 
-	/* contact the chosen server */
-	ret = afs_server_lookup(
-		vlocation->cell,
-		&vlocation->cell->vl_addrs[vlocation->upd_curr_svix],
-		&vlocation->upd_op.server);
+	afs_get_cell(cell);
 
-	switch (ret) {
-	case 0:
-		break;
-	case -ENOMEM:
-	case -ENONET:
-	default:
-		_leave(" = %d", ret);
-		return ret;
-	}
+	list_add_tail(&vl->link, &cell->vl_list);
+	vl->state = AFS_VL_CREATING;
+	up_write(&cell->vl_sem);
 
-	/* initiate the update operation */
-	ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
+fill_in_record:
+	ret = afs_vlocation_fill_in_record(vl, key);
+	if (ret < 0)
+		goto error_abandon;
+	spin_lock(&vl->lock);
+	vl->state = AFS_VL_VALID;
+	spin_unlock(&vl->lock);
+	wake_up(&vl->waitq);
+
+	/* schedule for regular updates */
+	afs_vlocation_queue_for_updates(vl);
+	goto success;
+
+found_in_memory:
+	/* found in memory */
+	_debug("found in memory");
+	atomic_inc(&vl->usage);
+	spin_unlock(&cell->vl_lock);
+	if (!list_empty(&vl->grave)) {
+		spin_lock(&afs_vlocation_graveyard_lock);
+		list_del_init(&vl->grave);
+		spin_unlock(&afs_vlocation_graveyard_lock);
 	}
+	up_write(&cell->vl_sem);
+
+	/* see if it was an abandoned record that we might try filling in */
+	spin_lock(&vl->lock);
+	while (vl->state != AFS_VL_VALID) {
+		afs_vlocation_state_t state = vl->state;
+
+		_debug("invalid [state %d]", state);
+
+		if (state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME) {
+			vl->state = AFS_VL_CREATING;
+			spin_unlock(&vl->lock);
+			goto fill_in_record;
+		}
+
+		/* must now wait for creation or update by someone else to
+		 * complete */
+		_debug("wait");
 
+		spin_unlock(&vl->lock);
+		ret = wait_event_interruptible(vl->waitq,
+					       vl->state == AFS_VL_NEW ||
+					       vl->state == AFS_VL_VALID ||
+					       vl->state == AFS_VL_NO_VOLUME);
+		if (ret < 0)
+			goto error;
+		spin_lock(&vl->lock);
+	}
+	spin_unlock(&vl->lock);
+
+success:
+	_leave(" = %p",vl);
+	return vl;
+
+error_abandon:
+	spin_lock(&vl->lock);
+	vl->state = AFS_VL_NEW;
+	spin_unlock(&vl->lock);
+	wake_up(&vl->waitq);
+error:
+	ASSERT(vl != NULL);
+	afs_put_vlocation(vl);
 	_leave(" = %d", ret);
-	return ret;
-} /* end afs_vlocation_update_begin() */
+	return ERR_PTR(ret);
+}
 
-/*****************************************************************************/
 /*
- * abandon updating a VL record
- * - does not restart the update timer
+ * finish using a volume location record
  */
-static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation,
-					 afs_vlocation_upd_t state,
-					 int ret)
+void afs_put_vlocation(struct afs_vlocation *vl)
 {
-	_enter("%s,%u", vlocation->vldb.name, state);
-
-	if (ret < 0)
-		printk("kAFS: Abandoning VL update '%s': %d\n",
-		       vlocation->vldb.name, ret);
-
-	/* discard the server record */
-	afs_put_server(vlocation->upd_op.server);
-	vlocation->upd_op.server = NULL;
+	if (!vl)
+		return;
 
-	spin_lock(&afs_vlocation_update_lock);
-	afs_vlocation_update = NULL;
-	vlocation->upd_state = state;
+	_enter("%s", vl->vldb.name);
 
-	/* TODO: start updating next VL record on pending list */
+	ASSERTCMP(atomic_read(&vl->usage), >, 0);
 
-	spin_unlock(&afs_vlocation_update_lock);
+	if (likely(!atomic_dec_and_test(&vl->usage))) {
+		_leave("");
+		return;
+	}
 
-	_leave("");
-} /* end afs_vlocation_update_abandon() */
+	spin_lock(&afs_vlocation_graveyard_lock);
+	if (atomic_read(&vl->usage) == 0) {
+		_debug("buried");
+		list_move_tail(&vl->grave, &afs_vlocation_graveyard);
+		vl->time_of_death = get_seconds();
+		schedule_delayed_work(&afs_vlocation_reap,
+				      afs_vlocation_timeout * HZ);
+
+		/* suspend updates on this record */
+		if (!list_empty(&vl->update)) {
+			spin_lock(&afs_vlocation_updates_lock);
+			list_del_init(&vl->update);
+			spin_unlock(&afs_vlocation_updates_lock);
+		}
+	}
+	spin_unlock(&afs_vlocation_graveyard_lock);
+	_leave(" [killed?]");
+}
 
-/*****************************************************************************/
 /*
- * handle periodic update timeouts and busy retry timeouts
- * - called from kafstimod
+ * destroy a dead volume location record
  */
-static void afs_vlocation_update_timer(struct afs_timer *timer)
+static void afs_vlocation_destroy(struct afs_vlocation *vl)
 {
-	struct afs_vlocation *vlocation =
-		list_entry(timer, struct afs_vlocation, upd_timer);
-	int ret;
+	_enter("%p", vl);
 
-	_enter("%s", vlocation->vldb.name);
+#ifdef AFS_CACHING_SUPPORT
+	cachefs_relinquish_cookie(vl->cache, 0);
+#endif
 
-	/* only update if not in the graveyard (defend against putting too) */
-	spin_lock(&vlocation->cell->vl_gylock);
+	afs_put_cell(vl->cell);
+	kfree(vl);
+}
 
-	if (!atomic_read(&vlocation->usage))
-		goto out_unlock1;
+/*
+ * reap dead volume location records
+ */
+static void afs_vlocation_reaper(struct work_struct *work)
+{
+	LIST_HEAD(corpses);
+	struct afs_vlocation *vl;
+	unsigned long delay, expiry;
+	time_t now;
 
-	spin_lock(&afs_vlocation_update_lock);
+	_enter("");
 
-	/* if we were woken up due to EBUSY sleep then restart immediately if
-	 * possible or else jump to front of pending queue */
-	if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) {
-		if (afs_vlocation_update) {
-			list_add(&vlocation->upd_op.link,
-				 &afs_vlocation_update_pendq);
+	now = get_seconds();
+	spin_lock(&afs_vlocation_graveyard_lock);
+
+	while (!list_empty(&afs_vlocation_graveyard)) {
+		vl = list_entry(afs_vlocation_graveyard.next,
+				struct afs_vlocation, grave);
+
+		_debug("check %p", vl);
+
+		/* the queue is ordered most dead first */
+		expiry = vl->time_of_death + afs_vlocation_timeout;
+		if (expiry > now) {
+			delay = (expiry - now) * HZ;
+			_debug("delay %lu", delay);
+			if (!schedule_delayed_work(&afs_vlocation_reap,
+						   delay)) {
+				cancel_delayed_work(&afs_vlocation_reap);
+				schedule_delayed_work(&afs_vlocation_reap,
+						      delay);
+			}
+			break;
 		}
-		else {
-			afs_get_vlocation(vlocation);
-			afs_vlocation_update = vlocation;
-			vlocation->upd_state = AFS_VLUPD_INPROGRESS;
+
+		spin_lock(&vl->cell->vl_lock);
+		if (atomic_read(&vl->usage) > 0) {
+			_debug("no reap");
+			list_del_init(&vl->grave);
+		} else {
+			_debug("reap");
+			list_move_tail(&vl->grave, &corpses);
+			list_del_init(&vl->link);
 		}
-		goto out_unlock2;
+		spin_unlock(&vl->cell->vl_lock);
 	}
 
-	/* put on pending queue if there's already another update in progress */
-	if (afs_vlocation_update) {
-		vlocation->upd_state = AFS_VLUPD_PENDING;
-		list_add_tail(&vlocation->upd_op.link,
-			      &afs_vlocation_update_pendq);
-		goto out_unlock2;
-	}
+	spin_unlock(&afs_vlocation_graveyard_lock);
 
-	/* hold a ref on it while actually updating */
-	afs_get_vlocation(vlocation);
-	afs_vlocation_update = vlocation;
-	vlocation->upd_state = AFS_VLUPD_INPROGRESS;
-
-	spin_unlock(&afs_vlocation_update_lock);
-	spin_unlock(&vlocation->cell->vl_gylock);
-
-	/* okay... we can start the update */
-	_debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name);
-	vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;
-	vlocation->upd_curr_svix = vlocation->upd_first_svix;
-	vlocation->upd_rej_cnt = 0;
-	vlocation->upd_busy_cnt = 0;
-
-	ret = afs_vlocation_update_begin(vlocation);
-	if (ret < 0) {
-		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
-		afs_kafstimod_add_timer(&vlocation->upd_timer,
-					AFS_VLDB_TIMEOUT);
-		afs_put_vlocation(vlocation);
+	/* now reap the corpses we've extracted */
+	while (!list_empty(&corpses)) {
+		vl = list_entry(corpses.next, struct afs_vlocation, grave);
+		list_del(&vl->grave);
+		afs_vlocation_destroy(vl);
 	}
 
 	_leave("");
-	return;
+}
 
- out_unlock2:
-	spin_unlock(&afs_vlocation_update_lock);
- out_unlock1:
-	spin_unlock(&vlocation->cell->vl_gylock);
-	_leave("");
-	return;
+/*
+ * initialise the VL update process
+ */
+int __init afs_vlocation_update_init(void)
+{
+	afs_vlocation_update_worker =
+		create_singlethread_workqueue("kafs_vlupdated");
+	return afs_vlocation_update_worker ? 0 : -ENOMEM;
+}
 
-} /* end afs_vlocation_update_timer() */
+/*
+ * discard all the volume location records for rmmod
+ */
+void afs_vlocation_purge(void)
+{
+	afs_vlocation_timeout = 0;
+
+	spin_lock(&afs_vlocation_updates_lock);
+	list_del_init(&afs_vlocation_updates);
+	spin_unlock(&afs_vlocation_updates_lock);
+	cancel_delayed_work(&afs_vlocation_update);
+	queue_delayed_work(afs_vlocation_update_worker,
+			   &afs_vlocation_update, 0);
+	destroy_workqueue(afs_vlocation_update_worker);
+
+	cancel_delayed_work(&afs_vlocation_reap);
+	schedule_delayed_work(&afs_vlocation_reap, 0);
+}
 
-/*****************************************************************************/
 /*
- * attend to an update operation upon which an event happened
- * - called in kafsasyncd context
+ * update a volume location
  */
-static void afs_vlocation_update_attend(struct afs_async_op *op)
+static void afs_vlocation_updater(struct work_struct *work)
 {
 	struct afs_cache_vlocation vldb;
-	struct afs_vlocation *vlocation =
-		list_entry(op, struct afs_vlocation, upd_op);
-	unsigned tmp;
+	struct afs_vlocation *vl, *xvl;
+	time_t now;
+	long timeout;
 	int ret;
 
-	_enter("%s", vlocation->vldb.name);
-
-	ret = afs_rxvl_get_entry_by_id_async2(op, &vldb);
-	switch (ret) {
-	case -EAGAIN:
-		_leave(" [unfinished]");
-		return;
-
-	case 0:
-		_debug("END VL UPDATE: %d\n", ret);
-		vlocation->valid = 1;
-
-		_debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",
-		       vldb.vidmask,
-		       ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
-		       ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
-		       ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
-		       );
-
-		_debug("Vids: %08x %08x %08x",
-		       vldb.vid[0], vldb.vid[1], vldb.vid[2]);
-
-		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
-
-		down_write(&vlocation->cell->vl_sem);
-
-		/* actually update the cache */
-		if (strncmp(vldb.name, vlocation->vldb.name,
-			    sizeof(vlocation->vldb.name)) != 0)
-			printk("kAFS: name of volume '%s'"
-			       " changed to '%s' on server\n",
-			       vlocation->vldb.name, vldb.name);
-
-		memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
-
-#if 0
-		/* TODO update volume entry in local cache */
-#endif
-
-		up_write(&vlocation->cell->vl_sem);
-
-		if (ret < 0)
-			printk("kAFS: failed to update local cache: %d\n", ret);
-
-		afs_kafstimod_add_timer(&vlocation->upd_timer,
-					AFS_VLDB_TIMEOUT);
-		afs_put_vlocation(vlocation);
-		_leave(" [found]");
-		return;
-
-	case -ENOMEDIUM:
-		vlocation->upd_rej_cnt++;
-		goto try_next;
-
-		/* the server is locked - retry in a very short while */
-	case -EBUSY:
-		vlocation->upd_busy_cnt++;
-		if (vlocation->upd_busy_cnt > 3)
-			goto try_next; /* too many retries */
-
-		afs_vlocation_update_abandon(vlocation,
-					     AFS_VLUPD_BUSYSLEEP, 0);
-		afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2);
-		afs_put_vlocation(vlocation);
-		_leave(" [busy]");
-		return;
-
-	case -ENETUNREACH:
-	case -EHOSTUNREACH:
-	case -ECONNREFUSED:
-	case -EREMOTEIO:
-		/* record bad vlserver info in the cell too
-		 * - TODO: use down_write_trylock() if available
-		 */
-		if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)
-			vlocation->cell->vl_curr_svix =
-				vlocation->cell->vl_curr_svix %
-				vlocation->cell->vl_naddrs;
-
-	case -EBADRQC:
-	case -EINVAL:
-	case -EACCES:
-	case -EBADMSG:
-		goto try_next;
-
-	default:
-		goto abandon;
-	}
-
-	/* try contacting the next server */
- try_next:
-	vlocation->upd_busy_cnt = 0;
-
-	/* discard the server record */
-	afs_put_server(vlocation->upd_op.server);
-	vlocation->upd_op.server = NULL;
+	_enter("");
 
-	tmp = vlocation->cell->vl_naddrs;
-	if (tmp == 0)
-		goto abandon;
+	now = get_seconds();
 
-	vlocation->upd_curr_svix++;
-	if (vlocation->upd_curr_svix >= tmp)
-		vlocation->upd_curr_svix = 0;
-	if (vlocation->upd_first_svix >= tmp)
-		vlocation->upd_first_svix = tmp - 1;
+	/* find a record to update */
+	spin_lock(&afs_vlocation_updates_lock);
+	for (;;) {
+		if (list_empty(&afs_vlocation_updates)) {
+			spin_unlock(&afs_vlocation_updates_lock);
+			_leave(" [nothing]");
+			return;
+		}
 
-	/* move to the next server */
-	if (vlocation->upd_curr_svix != vlocation->upd_first_svix) {
-		afs_vlocation_update_begin(vlocation);
-		_leave(" [next]");
-		return;
+		vl = list_entry(afs_vlocation_updates.next,
+				struct afs_vlocation, update);
+		if (atomic_read(&vl->usage) > 0)
+			break;
+		list_del_init(&vl->update);
 	}
 
-	/* run out of servers to try - was the volume rejected? */
-	if (vlocation->upd_rej_cnt > 0) {
-		printk("kAFS: Active volume no longer valid '%s'\n",
-		       vlocation->vldb.name);
-		vlocation->valid = 0;
-		afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
-		afs_kafstimod_add_timer(&vlocation->upd_timer,
-					AFS_VLDB_TIMEOUT);
-		afs_put_vlocation(vlocation);
-		_leave(" [invalidated]");
+	timeout = vl->update_at - now;
+	if (timeout > 0) {
+		queue_delayed_work(afs_vlocation_update_worker,
+				   &afs_vlocation_update, timeout * HZ);
+		spin_unlock(&afs_vlocation_updates_lock);
+		_leave(" [nothing]");
 		return;
 	}
 
-	/* abandon the update */
- abandon:
-	afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
-	afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10);
-	afs_put_vlocation(vlocation);
-	_leave(" [abandoned]");
-
-} /* end afs_vlocation_update_attend() */
-
-/*****************************************************************************/
-/*
- * deal with an update operation being discarded
- * - called in kafsasyncd context when it's dying due to rmmod
- * - the call has already been aborted and put()'d
- */
-static void afs_vlocation_update_discard(struct afs_async_op *op)
-{
-	struct afs_vlocation *vlocation =
-		list_entry(op, struct afs_vlocation, upd_op);
+	list_del_init(&vl->update);
+	atomic_inc(&vl->usage);
+	spin_unlock(&afs_vlocation_updates_lock);
 
-	_enter("%s", vlocation->vldb.name);
+	/* we can now perform the update */
+	_debug("update %s", vl->vldb.name);
+	vl->state = AFS_VL_UPDATING;
+	vl->upd_rej_cnt = 0;
+	vl->upd_busy_cnt = 0;
 
-	afs_put_server(op->server);
-	op->server = NULL;
+	ret = afs_vlocation_update_record(vl, NULL, &vldb);
+	spin_lock(&vl->lock);
+	switch (ret) {
+	case 0:
+		afs_vlocation_apply_update(vl, &vldb);
+		vl->state = AFS_VL_VALID;
+		break;
+	case -ENOMEDIUM:
+		vl->state = AFS_VL_VOLUME_DELETED;
+		break;
+	default:
+		vl->state = AFS_VL_UNCERTAIN;
+		break;
+	}
+	spin_unlock(&vl->lock);
+	wake_up(&vl->waitq);
 
-	afs_put_vlocation(vlocation);
+	/* and then reschedule */
+	_debug("reschedule");
+	vl->update_at = get_seconds() + afs_vlocation_update_timeout;
 
-	_leave("");
-} /* end afs_vlocation_update_discard() */
+	spin_lock(&afs_vlocation_updates_lock);
 
-/*****************************************************************************/
-/*
- * match a VLDB record stored in the cache
- * - may also load target from entry
- */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
-						     const void *entry)
-{
-	const struct afs_cache_vlocation *vldb = entry;
-	struct afs_vlocation *vlocation = target;
-
-	_enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
-
-	if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
-	    ) {
-		if (!vlocation->valid ||
-		    vlocation->vldb.rtime == vldb->rtime
-		    ) {
-			vlocation->vldb = *vldb;
-			vlocation->valid = 1;
-			_leave(" = SUCCESS [c->m]");
-			return CACHEFS_MATCH_SUCCESS;
-		}
-		/* need to update cache if cached info differs */
-		else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
-			/* delete if VIDs for this name differ */
-			if (memcmp(&vlocation->vldb.vid,
-				   &vldb->vid,
-				   sizeof(vldb->vid)) != 0) {
-				_leave(" = DELETE");
-				return CACHEFS_MATCH_SUCCESS_DELETE;
-			}
-
-			_leave(" = UPDATE");
-			return CACHEFS_MATCH_SUCCESS_UPDATE;
-		}
-		else {
-			_leave(" = SUCCESS");
-			return CACHEFS_MATCH_SUCCESS;
-		}
+	if (!list_empty(&afs_vlocation_updates)) {
+		/* next update in 10 minutes, but wait at least 1 second more
+		 * than the newest record already queued so that we don't spam
+		 * the VL server suddenly with lots of requests
+		 */
+		xvl = list_entry(afs_vlocation_updates.prev,
+				 struct afs_vlocation, update);
+		if (vl->update_at <= xvl->update_at)
+			vl->update_at = xvl->update_at + 1;
+		xvl = list_entry(afs_vlocation_updates.next,
+				 struct afs_vlocation, update);
+		timeout = xvl->update_at - now;
+		if (timeout < 0)
+			timeout = 0;
+	} else {
+		timeout = afs_vlocation_update_timeout;
 	}
 
-	_leave(" = FAILED");
-	return CACHEFS_MATCH_FAILED;
-} /* end afs_vlocation_cache_match() */
-#endif
-
-/*****************************************************************************/
-/*
- * update a VLDB record stored in the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vlocation_cache_update(void *source, void *entry)
-{
-	struct afs_cache_vlocation *vldb = entry;
-	struct afs_vlocation *vlocation = source;
+	ASSERT(list_empty(&vl->update));
 
-	_enter("");
-
-	*vldb = vlocation->vldb;
+	list_add_tail(&vl->update, &afs_vlocation_updates);
 
-} /* end afs_vlocation_cache_update() */
-#endif
+	_debug("timeout %ld", timeout);
+	queue_delayed_work(afs_vlocation_update_worker,
+			   &afs_vlocation_update, timeout * HZ);
+	spin_unlock(&afs_vlocation_updates_lock);
+	afs_put_vlocation(vl);
+}
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index cf62da5..a1904ab 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -1,6 +1,6 @@
-/* vnode.c: AFS vnode management
+/* AFS vnode management
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -14,142 +14,237 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
-#include <linux/pagemap.h>
-#include "volume.h"
-#include "cell.h"
-#include "cmservice.h"
-#include "fsclient.h"
-#include "vlclient.h"
-#include "vnode.h"
 #include "internal.h"
 
-static void afs_vnode_cb_timed_out(struct afs_timer *timer);
+#if 0
+static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent,
+				   int depth, char lr)
+{
+	struct afs_vnode *vnode;
+	bool bad = false;
+
+	if (!node)
+		return false;
+
+	if (node->rb_left)
+		bad = dump_tree_aux(node->rb_left, node, depth + 2, '/');
+
+	vnode = rb_entry(node, struct afs_vnode, cb_promise);
+	_debug("%c %*.*s%c%p {%d}",
+	       rb_is_red(node) ? 'R' : 'B',
+	       depth, depth, "", lr,
+	       vnode, vnode->cb_expires_at);
+	if (rb_parent(node) != parent) {
+		printk("BAD: %p != %p\n", rb_parent(node), parent);
+		bad = true;
+	}
 
-struct afs_timer_ops afs_vnode_cb_timed_out_ops = {
-	.timed_out	= afs_vnode_cb_timed_out,
-};
+	if (node->rb_right)
+		bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\');
 
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
-						 const void *entry);
-static void afs_vnode_cache_update(void *source, void *entry);
+	return bad;
+}
 
-struct cachefs_index_def afs_vnode_cache_index_def = {
-	.name		= "vnode",
-	.data_size	= sizeof(struct afs_cache_vnode),
-	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 4 },
-	.match		= afs_vnode_cache_match,
-	.update		= afs_vnode_cache_update,
-};
+static noinline void dump_tree(const char *name, struct afs_server *server)
+{
+	_enter("%s", name);
+	if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-'))
+		BUG();
+}
 #endif
 
-/*****************************************************************************/
 /*
- * handle a callback timing out
- * TODO: retain a ref to vnode struct for an outstanding callback timeout
+ * insert a vnode into the backing server's vnode tree
  */
-static void afs_vnode_cb_timed_out(struct afs_timer *timer)
+static void afs_install_vnode(struct afs_vnode *vnode,
+			      struct afs_server *server)
 {
-	struct afs_server *oldserver;
-	struct afs_vnode *vnode;
+	struct afs_server *old_server = vnode->server;
+	struct afs_vnode *xvnode;
+	struct rb_node *parent, **p;
 
-	vnode = list_entry(timer, struct afs_vnode, cb_timeout);
+	_enter("%p,%p", vnode, server);
 
-	_enter("%p", vnode);
+	if (old_server) {
+		spin_lock(&old_server->fs_lock);
+		rb_erase(&vnode->server_rb, &old_server->fs_vnodes);
+		spin_unlock(&old_server->fs_lock);
+	}
 
-	/* set the changed flag in the vnode and release the server */
-	spin_lock(&vnode->lock);
+	afs_get_server(server);
+	vnode->server = server;
+	afs_put_server(old_server);
+
+	/* insert into the server's vnode tree in FID order */
+	spin_lock(&server->fs_lock);
+
+	parent = NULL;
+	p = &server->fs_vnodes.rb_node;
+	while (*p) {
+		parent = *p;
+		xvnode = rb_entry(parent, struct afs_vnode, server_rb);
+		if (vnode->fid.vid < xvnode->fid.vid)
+			p = &(*p)->rb_left;
+		else if (vnode->fid.vid > xvnode->fid.vid)
+			p = &(*p)->rb_right;
+		else if (vnode->fid.vnode < xvnode->fid.vnode)
+			p = &(*p)->rb_left;
+		else if (vnode->fid.vnode > xvnode->fid.vnode)
+			p = &(*p)->rb_right;
+		else if (vnode->fid.unique < xvnode->fid.unique)
+			p = &(*p)->rb_left;
+		else if (vnode->fid.unique > xvnode->fid.unique)
+			p = &(*p)->rb_right;
+		else
+			BUG(); /* can't happen unless afs_iget() malfunctions */
+	}
+
+	rb_link_node(&vnode->server_rb, parent, p);
+	rb_insert_color(&vnode->server_rb, &server->fs_vnodes);
 
-	oldserver = xchg(&vnode->cb_server, NULL);
-	if (oldserver) {
-		vnode->flags |= AFS_VNODE_CHANGED;
+	spin_unlock(&server->fs_lock);
+	_leave("");
+}
 
-		spin_lock(&afs_cb_hash_lock);
-		list_del_init(&vnode->cb_hash_link);
-		spin_unlock(&afs_cb_hash_lock);
+/*
+ * insert a vnode into the promising server's update/expiration tree
+ * - caller must hold vnode->lock
+ */
+static void afs_vnode_note_promise(struct afs_vnode *vnode,
+				   struct afs_server *server)
+{
+	struct afs_server *old_server;
+	struct afs_vnode *xvnode;
+	struct rb_node *parent, **p;
 
-		spin_lock(&oldserver->cb_lock);
-		list_del_init(&vnode->cb_link);
-		spin_unlock(&oldserver->cb_lock);
+	_enter("%p,%p", vnode, server);
+
+	ASSERT(server != NULL);
+
+	old_server = vnode->server;
+	if (vnode->cb_promised) {
+		if (server == old_server &&
+		    vnode->cb_expires == vnode->cb_expires_at) {
+			_leave(" [no change]");
+			return;
+		}
+
+		spin_lock(&old_server->cb_lock);
+		if (vnode->cb_promised) {
+			_debug("delete");
+			rb_erase(&vnode->cb_promise, &old_server->cb_promises);
+			vnode->cb_promised = false;
+		}
+		spin_unlock(&old_server->cb_lock);
 	}
 
-	spin_unlock(&vnode->lock);
+	if (vnode->server != server)
+		afs_install_vnode(vnode, server);
+
+	vnode->cb_expires_at = vnode->cb_expires;
+	_debug("PROMISE on %p {%lu}",
+	       vnode, (unsigned long) vnode->cb_expires_at);
+
+	/* abuse an RB-tree to hold the expiration order (we may have multiple
+	 * items with the same expiration time) */
+	spin_lock(&server->cb_lock);
+
+	parent = NULL;
+	p = &server->cb_promises.rb_node;
+	while (*p) {
+		parent = *p;
+		xvnode = rb_entry(parent, struct afs_vnode, cb_promise);
+		if (vnode->cb_expires_at < xvnode->cb_expires_at)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
 
-	afs_put_server(oldserver);
+	rb_link_node(&vnode->cb_promise, parent, p);
+	rb_insert_color(&vnode->cb_promise, &server->cb_promises);
+	vnode->cb_promised = true;
 
+	spin_unlock(&server->cb_lock);
 	_leave("");
-} /* end afs_vnode_cb_timed_out() */
+}
 
-/*****************************************************************************/
 /*
- * finish off updating the recorded status of a file
+ * handle remote file deletion by discarding the callback promise
+ */
+static void afs_vnode_deleted_remotely(struct afs_vnode *vnode)
+{
+	struct afs_server *server;
+
+	set_bit(AFS_VNODE_DELETED, &vnode->flags);
+
+	server = vnode->server;
+	if (vnode->cb_promised) {
+		spin_lock(&server->cb_lock);
+		if (vnode->cb_promised) {
+			rb_erase(&vnode->cb_promise, &server->cb_promises);
+			vnode->cb_promised = false;
+		}
+		spin_unlock(&server->cb_lock);
+	}
+
+	spin_lock(&vnode->server->fs_lock);
+	rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
+	spin_unlock(&vnode->server->fs_lock);
+
+	vnode->server = NULL;
+	afs_put_server(server);
+}
+
+/*
+ * finish off updating the recorded status of a file after a successful
+ * operation completion
  * - starts callback expiry timer
  * - adds to server's callback list
  */
-static void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
-					     struct afs_server *server,
-					     int ret)
+void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
+				      struct afs_server *server)
 {
 	struct afs_server *oldserver = NULL;
 
-	_enter("%p,%p,%d", vnode, server, ret);
+	_enter("%p,%p", vnode, server);
 
 	spin_lock(&vnode->lock);
+	clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
+	afs_vnode_note_promise(vnode, server);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+
+	wake_up_all(&vnode->update_waitq);
+	afs_put_server(oldserver);
+	_leave("");
+}
 
-	vnode->flags &= ~AFS_VNODE_CHANGED;
+/*
+ * finish off updating the recorded status of a file after an operation failed
+ */
+static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
+{
+	_enter("%p,%d", vnode, ret);
 
-	if (ret == 0) {
-		/* adjust the callback timeout appropriately */
-		afs_kafstimod_add_timer(&vnode->cb_timeout,
-					vnode->cb_expiry * HZ);
-
-		spin_lock(&afs_cb_hash_lock);
-		list_move_tail(&vnode->cb_hash_link,
-			      &afs_cb_hash(server, &vnode->fid));
-		spin_unlock(&afs_cb_hash_lock);
-
-		/* swap ref to old callback server with that for new callback
-		 * server */
-		oldserver = xchg(&vnode->cb_server, server);
-		if (oldserver != server) {
-			if (oldserver) {
-				spin_lock(&oldserver->cb_lock);
-				list_del_init(&vnode->cb_link);
-				spin_unlock(&oldserver->cb_lock);
-			}
+	spin_lock(&vnode->lock);
 
-			afs_get_server(server);
-			spin_lock(&server->cb_lock);
-			list_add_tail(&vnode->cb_link, &server->cb_promises);
-			spin_unlock(&server->cb_lock);
-		}
-		else {
-			/* same server */
-			oldserver = NULL;
-		}
-	}
-	else if (ret == -ENOENT) {
-		/* the file was deleted - clear the callback timeout */
-		oldserver = xchg(&vnode->cb_server, NULL);
-		afs_kafstimod_del_timer(&vnode->cb_timeout);
+	clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 
+	if (ret == -ENOENT) {
+		/* the file was deleted on the server */
 		_debug("got NOENT from server - marking file deleted");
-		vnode->flags |= AFS_VNODE_DELETED;
+		afs_vnode_deleted_remotely(vnode);
 	}
 
 	vnode->update_cnt--;
-
+	ASSERTCMP(vnode->update_cnt, >=, 0);
 	spin_unlock(&vnode->lock);
 
 	wake_up_all(&vnode->update_waitq);
-
-	afs_put_server(oldserver);
-
 	_leave("");
+}
 
-} /* end afs_vnode_finalise_status_update() */
-
-/*****************************************************************************/
 /*
  * fetch file status from the volume
  * - don't issue a fetch if:
@@ -157,9 +252,11 @@ static void afs_vnode_finalise_status_up
  *   - there are any outstanding ops that will fetch the status
  * - TODO implement local caching
  */
-int afs_vnode_fetch_status(struct afs_vnode *vnode)
+int afs_vnode_fetch_status(struct afs_vnode *vnode,
+			   struct afs_vnode *auth_vnode, struct key *key)
 {
 	struct afs_server *server;
+	unsigned long acl_order;
 	int ret;
 
 	DECLARE_WAITQUEUE(myself, current);
@@ -168,38 +265,49 @@ int afs_vnode_fetch_status(struct afs_vn
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
-	if (!(vnode->flags & AFS_VNODE_CHANGED) && vnode->cb_server) {
+	if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
+	    vnode->cb_promised) {
 		_leave(" [unchanged]");
 		return 0;
 	}
 
-	if (vnode->flags & AFS_VNODE_DELETED) {
+	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
 		_leave(" [deleted]");
 		return -ENOENT;
 	}
 
+	acl_order = 0;
+	if (auth_vnode)
+		acl_order = auth_vnode->acl_order;
+
 	spin_lock(&vnode->lock);
 
-	if (!(vnode->flags & AFS_VNODE_CHANGED)) {
+	if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
+	    vnode->cb_promised) {
 		spin_unlock(&vnode->lock);
 		_leave(" [unchanged]");
 		return 0;
 	}
 
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+
 	if (vnode->update_cnt > 0) {
 		/* someone else started a fetch */
+		_debug("wait on fetch %d", vnode->update_cnt);
+
 		set_current_state(TASK_UNINTERRUPTIBLE);
+		ASSERT(myself.func != NULL);
 		add_wait_queue(&vnode->update_waitq, &myself);
 
 		/* wait for the status to be updated */
 		for (;;) {
-			if (!(vnode->flags & AFS_VNODE_CHANGED))
+			if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
 				break;
-			if (vnode->flags & AFS_VNODE_DELETED)
+			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
 				break;
 
-			/* it got updated and invalidated all before we saw
-			 * it */
+			/* check to see if it got updated and invalidated all
+			 * before we saw it */
 			if (vnode->update_cnt == 0) {
 				remove_wait_queue(&vnode->update_waitq,
 						  &myself);
@@ -219,10 +327,11 @@ int afs_vnode_fetch_status(struct afs_vn
 		spin_unlock(&vnode->lock);
 		set_current_state(TASK_RUNNING);
 
-		return vnode->flags & AFS_VNODE_DELETED ? -ENOENT : 0;
+		return test_bit(AFS_VNODE_DELETED, &vnode->flags) ?
+			-ENOENT : 0;
 	}
 
- get_anyway:
+get_anyway:
 	/* okay... we're going to have to initiate the op */
 	vnode->update_cnt++;
 
@@ -232,39 +341,60 @@ int afs_vnode_fetch_status(struct afs_vn
 	 * vnode */
 	do {
 		/* pick a server to query */
-		ret = afs_volume_pick_fileserver(vnode->volume, &server);
-		if (ret<0)
-			return ret;
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
 
-		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+		_debug("USING SERVER: %p{%08x}",
+		       server, ntohl(server->addr.s_addr));
 
-		ret = afs_rxfs_fetch_file_status(server, vnode, NULL);
+		ret = afs_fs_fetch_file_status(server, key, vnode, NULL,
+					       &afs_sync_call);
 
-	} while (!afs_volume_release_fileserver(vnode->volume, server, ret));
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
 
 	/* adjust the flags */
-	afs_vnode_finalise_status_update(vnode, server, ret);
+	if (ret == 0) {
+		_debug("adjust");
+		if (auth_vnode)
+			afs_cache_permit(vnode, key, acl_order);
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_put_server(server);
+	} else {
+		_debug("failed [%d]", ret);
+		afs_vnode_status_update_failed(vnode, ret);
+	}
 
-	_leave(" = %d", ret);
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+
+	_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
 	return ret;
-} /* end afs_vnode_fetch_status() */
 
-/*****************************************************************************/
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
+	return PTR_ERR(server);
+}
+
 /*
  * fetch file data from the volume
- * - TODO implement caching and server failover
+ * - TODO implement caching
  */
-int afs_vnode_fetch_data(struct afs_vnode *vnode,
-			 struct afs_rxfs_fetch_descriptor *desc)
+int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
+			 off_t offset, size_t length, struct page *page)
 {
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s,{%u,%u,%u}",
+	_enter("%s{%u,%u,%u},%x,,,",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
-	       vnode->fid.unique);
+	       vnode->fid.unique,
+	       key_serial(key));
 
 	/* this op will fetch the status */
 	spin_lock(&vnode->lock);
@@ -275,120 +405,351 @@ int afs_vnode_fetch_data(struct afs_vnod
 	 * vnode */
 	do {
 		/* pick a server to query */
-		ret = afs_volume_pick_fileserver(vnode->volume, &server);
-		if (ret < 0)
-			return ret;
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
 
 		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
 
-		ret = afs_rxfs_fetch_file_data(server, vnode, desc, NULL);
+		ret = afs_fs_fetch_data(server, key, vnode, offset, length,
+					page, &afs_sync_call);
 
-	} while (!afs_volume_release_fileserver(vnode->volume, server, ret));
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
 
 	/* adjust the flags */
-	afs_vnode_finalise_status_update(vnode, server, ret);
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+	}
 
 	_leave(" = %d", ret);
 	return ret;
 
-} /* end afs_vnode_fetch_data() */
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	return PTR_ERR(server);
+}
 
-/*****************************************************************************/
 /*
- * break any outstanding callback on a vnode
- * - only relevent to server that issued it
+ * make a file or a directory
  */
-int afs_vnode_give_up_callback(struct afs_vnode *vnode)
+int afs_vnode_create(struct afs_vnode *vnode, struct key *key,
+		     const char *name, umode_t mode, struct afs_fid *newfid,
+		     struct afs_file_status *newstatus,
+		     struct afs_callback *newcb, struct afs_server **_server)
 {
 	struct afs_server *server;
 	int ret;
 
-	_enter("%s,{%u,%u,%u}",
+	_enter("%s{%u,%u,%u},%x,%s,,",
 	       vnode->volume->vlocation->vldb.name,
 	       vnode->fid.vid,
 	       vnode->fid.vnode,
-	       vnode->fid.unique);
-
-	spin_lock(&afs_cb_hash_lock);
-	list_del_init(&vnode->cb_hash_link);
-	spin_unlock(&afs_cb_hash_lock);
+	       vnode->fid.unique,
+	       key_serial(key),
+	       name);
 
-	/* set the changed flag in the vnode and release the server */
+	/* this op will fetch the status on the directory we're creating in */
 	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
 
-	afs_kafstimod_del_timer(&vnode->cb_timeout);
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
 
-	server = xchg(&vnode->cb_server, NULL);
-	if (server) {
-		vnode->flags |= AFS_VNODE_CHANGED;
+		ret = afs_fs_create(server, key, vnode, name, mode, newfid,
+				    newstatus, newcb, &afs_sync_call);
 
-		spin_lock(&server->cb_lock);
-		list_del_init(&vnode->cb_link);
-		spin_unlock(&server->cb_lock);
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		*_server = server;
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+		*_server = NULL;
 	}
 
+	_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
 	spin_unlock(&vnode->lock);
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
+	return PTR_ERR(server);
+}
 
-	ret = 0;
-	if (server) {
-		ret = afs_rxfs_give_up_callback(server, vnode);
+/*
+ * remove a file or directory
+ */
+int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
+		     bool isdir)
+{
+	struct afs_server *server;
+	int ret;
+
+	_enter("%s{%u,%u,%u},%x,%s",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       key_serial(key),
+	       name);
+
+	/* this op will fetch the status on the directory we're removing from */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_remove(server, key, vnode, name, isdir,
+				    &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
 		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
 	}
 
-	_leave(" = %d", ret);
+	_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
 	return ret;
-} /* end afs_vnode_give_up_callback() */
 
-/*****************************************************************************/
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
+	return PTR_ERR(server);
+}
+
 /*
- * match a vnode record stored in the cache
+ * create a hard link
  */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
-						 const void *entry)
+extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
+			  struct key *key, const char *name)
 {
-	const struct afs_cache_vnode *cvnode = entry;
-	struct afs_vnode *vnode = target;
+	struct afs_server *server;
+	int ret;
 
-	_enter("{%x,%x,%Lx},{%x,%x,%Lx}",
+	_enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
+	       dvnode->volume->vlocation->vldb.name,
+	       dvnode->fid.vid,
+	       dvnode->fid.vnode,
+	       dvnode->fid.unique,
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
 	       vnode->fid.vnode,
 	       vnode->fid.unique,
-	       vnode->status.version,
-	       cvnode->vnode_id,
-	       cvnode->vnode_unique,
-	       cvnode->data_version);
-
-	if (vnode->fid.vnode != cvnode->vnode_id) {
-		_leave(" = FAILED");
-		return CACHEFS_MATCH_FAILED;
+	       key_serial(key),
+	       name);
+
+	/* this op will fetch the status on the directory we're removing from */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+	spin_lock(&dvnode->lock);
+	dvnode->update_cnt++;
+	spin_unlock(&dvnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(dvnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_link(server, key, dvnode, vnode, name,
+				  &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(dvnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		afs_vnode_finalise_status_update(dvnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+		afs_vnode_status_update_failed(dvnode, ret);
 	}
 
-	if (vnode->fid.unique != cvnode->vnode_unique ||
-	    vnode->status.version != cvnode->data_version) {
-		_leave(" = DELETE");
-		return CACHEFS_MATCH_SUCCESS_DELETE;
+	_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	spin_lock(&dvnode->lock);
+	dvnode->update_cnt--;
+	ASSERTCMP(dvnode->update_cnt, >=, 0);
+	spin_unlock(&dvnode->lock);
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
+	return PTR_ERR(server);
+}
+
+/*
+ * create a symbolic link
+ */
+int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key,
+		      const char *name, const char *content,
+		      struct afs_fid *newfid,
+		      struct afs_file_status *newstatus,
+		      struct afs_server **_server)
+{
+	struct afs_server *server;
+	int ret;
+
+	_enter("%s{%u,%u,%u},%x,%s,%s,,,",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique,
+	       key_serial(key),
+	       name, content);
+
+	/* this op will fetch the status on the directory we're creating in */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(vnode);
+		if (IS_ERR(server))
+			goto no_server;
+
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_symlink(server, key, vnode, name, content,
+				     newfid, newstatus, &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(vnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(vnode, server);
+		*_server = server;
+	} else {
+		afs_vnode_status_update_failed(vnode, ret);
+		*_server = NULL;
 	}
 
-	_leave(" = SUCCESS");
-	return CACHEFS_MATCH_SUCCESS;
-} /* end afs_vnode_cache_match() */
-#endif
+	_leave(" = %d [cnt %d]", ret, vnode->update_cnt);
+	return ret;
+
+no_server:
+	spin_lock(&vnode->lock);
+	vnode->update_cnt--;
+	ASSERTCMP(vnode->update_cnt, >=, 0);
+	spin_unlock(&vnode->lock);
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt);
+	return PTR_ERR(server);
+}
 
-/*****************************************************************************/
 /*
- * update a vnode record stored in the cache
+ * rename a file
  */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vnode_cache_update(void *source, void *entry)
+int afs_vnode_rename(struct afs_vnode *orig_dvnode,
+		     struct afs_vnode *new_dvnode,
+		     struct key *key,
+		     const char *orig_name,
+		     const char *new_name)
 {
-	struct afs_cache_vnode *cvnode = entry;
-	struct afs_vnode *vnode = source;
+	struct afs_server *server;
+	int ret;
 
-	_enter("");
+	_enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
+	       orig_dvnode->volume->vlocation->vldb.name,
+	       orig_dvnode->fid.vid,
+	       orig_dvnode->fid.vnode,
+	       orig_dvnode->fid.unique,
+	       new_dvnode->volume->vlocation->vldb.name,
+	       new_dvnode->fid.vid,
+	       new_dvnode->fid.vnode,
+	       new_dvnode->fid.unique,
+	       key_serial(key),
+	       orig_name,
+	       new_name);
+
+	/* this op will fetch the status on both the directories we're dealing
+	 * with */
+	spin_lock(&orig_dvnode->lock);
+	orig_dvnode->update_cnt++;
+	spin_unlock(&orig_dvnode->lock);
+	if (new_dvnode != orig_dvnode) {
+		spin_lock(&new_dvnode->lock);
+		new_dvnode->update_cnt++;
+		spin_unlock(&new_dvnode->lock);
+	}
 
-	cvnode->vnode_id	= vnode->fid.vnode;
-	cvnode->vnode_unique	= vnode->fid.unique;
-	cvnode->data_version	= vnode->status.version;
+	do {
+		/* pick a server to query */
+		server = afs_volume_pick_fileserver(orig_dvnode);
+		if (IS_ERR(server))
+			goto no_server;
 
-} /* end afs_vnode_cache_update() */
-#endif
+		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+		ret = afs_fs_rename(server, key, orig_dvnode, orig_name,
+				    new_dvnode, new_name, &afs_sync_call);
+
+	} while (!afs_volume_release_fileserver(orig_dvnode, server, ret));
+
+	/* adjust the flags */
+	if (ret == 0) {
+		afs_vnode_finalise_status_update(orig_dvnode, server);
+		if (new_dvnode != orig_dvnode)
+			afs_vnode_finalise_status_update(new_dvnode, server);
+		afs_put_server(server);
+	} else {
+		afs_vnode_status_update_failed(orig_dvnode, ret);
+		if (new_dvnode != orig_dvnode)
+			afs_vnode_status_update_failed(new_dvnode, ret);
+	}
+
+	_leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt);
+	return ret;
+
+no_server:
+	spin_lock(&orig_dvnode->lock);
+	orig_dvnode->update_cnt--;
+	ASSERTCMP(orig_dvnode->update_cnt, >=, 0);
+	spin_unlock(&orig_dvnode->lock);
+	if (new_dvnode != orig_dvnode) {
+		spin_lock(&new_dvnode->lock);
+		new_dvnode->update_cnt--;
+		ASSERTCMP(new_dvnode->update_cnt, >=, 0);
+		spin_unlock(&new_dvnode->lock);
+	}
+	_leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
+	return PTR_ERR(server);
+}
diff --git a/fs/afs/vnode.h b/fs/afs/vnode.h
deleted file mode 100644
index b86a971..0000000
--- a/fs/afs/vnode.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* vnode.h: AFS vnode record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_VNODE_H
-#define _LINUX_AFS_VNODE_H
-
-#include <linux/fs.h>
-#include "server.h"
-#include "kafstimod.h"
-#include "cache.h"
-
-#ifdef __KERNEL__
-
-struct afs_rxfs_fetch_descriptor;
-
-/*****************************************************************************/
-/*
- * vnode catalogue entry
- */
-struct afs_cache_vnode
-{
-	afs_vnodeid_t		vnode_id;	/* vnode ID */
-	unsigned		vnode_unique;	/* vnode ID uniquifier */
-	afs_dataversion_t	data_version;	/* data version */
-};
-
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vnode_cache_index_def;
-#endif
-
-/*****************************************************************************/
-/*
- * AFS inode private data
- */
-struct afs_vnode
-{
-	struct inode		vfs_inode;	/* the VFS's inode record */
-
-	struct afs_volume	*volume;	/* volume on which vnode resides */
-	struct afs_fid		fid;		/* the file identifier for this inode */
-	struct afs_file_status	status;		/* AFS status info for this file */
-#ifdef AFS_CACHING_SUPPORT
-	struct cachefs_cookie	*cache;		/* caching cookie */
-#endif
-
-	wait_queue_head_t	update_waitq;	/* status fetch waitqueue */
-	unsigned		update_cnt;	/* number of outstanding ops that will update the
-						 * status */
-	spinlock_t		lock;		/* waitqueue/flags lock */
-	unsigned		flags;
-#define AFS_VNODE_CHANGED	0x00000001	/* set if vnode reported changed by callback */
-#define AFS_VNODE_DELETED	0x00000002	/* set if vnode deleted on server */
-#define AFS_VNODE_MOUNTPOINT	0x00000004	/* set if vnode is a mountpoint symlink */
-
-	/* outstanding callback notification on this file */
-	struct afs_server	*cb_server;	/* server that made the current promise */
-	struct list_head	cb_link;	/* link in server's promises list */
-	struct list_head	cb_hash_link;	/* link in master callback hash */
-	struct afs_timer	cb_timeout;	/* timeout on promise */
-	unsigned		cb_version;	/* callback version */
-	unsigned		cb_expiry;	/* callback expiry time */
-	afs_callback_type_t	cb_type;	/* type of callback */
-};
-
-static inline struct afs_vnode *AFS_FS_I(struct inode *inode)
-{
-	return container_of(inode,struct afs_vnode,vfs_inode);
-}
-
-static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
-{
-	return &vnode->vfs_inode;
-}
-
-extern int afs_vnode_fetch_status(struct afs_vnode *vnode);
-
-extern int afs_vnode_fetch_data(struct afs_vnode *vnode,
-				struct afs_rxfs_fetch_descriptor *desc);
-
-extern int afs_vnode_give_up_callback(struct afs_vnode *vnode);
-
-extern struct afs_timer_ops afs_vnode_cb_timed_out_ops;
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_AFS_VNODE_H */
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 768c6db..dd160ca 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -1,6 +1,6 @@
-/* volume.c: AFS volume management
+/* AFS volume management
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -15,35 +15,10 @@ #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include "volume.h"
-#include "vnode.h"
-#include "cell.h"
-#include "cache.h"
-#include "cmservice.h"
-#include "fsclient.h"
-#include "vlclient.h"
 #include "internal.h"
 
-#ifdef __KDEBUG
 static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
-#endif
-
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
-						  const void *entry);
-static void afs_volume_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_volume_cache_index_def = {
-	.name		= "volume",
-	.data_size	= sizeof(struct afs_cache_vhash),
-	.keys[0]	= { CACHEFS_INDEX_KEYS_BIN, 1 },
-	.keys[1]	= { CACHEFS_INDEX_KEYS_BIN, 1 },
-	.match		= afs_volume_cache_match,
-	.update		= afs_volume_cache_update,
-};
-#endif
 
-/*****************************************************************************/
 /*
  * lookup a volume by name
  * - this can be one of the following:
@@ -66,118 +41,52 @@ #endif
  * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
  *           explicitly told otherwise
  */
-int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
-		      struct afs_volume **_volume)
+struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
 {
 	struct afs_vlocation *vlocation = NULL;
 	struct afs_volume *volume = NULL;
-	afs_voltype_t type;
-	const char *cellname, *volname, *suffix;
+	struct afs_server *server = NULL;
 	char srvtmask;
-	int force, ret, loop, cellnamesz, volnamesz;
-
-	_enter("%s,,%d,", name, rwpath);
-
-	if (!name || (name[0] != '%' && name[0] != '#') || !name[1]) {
-		printk("kAFS: unparsable volume name\n");
-		return -EINVAL;
-	}
-
-	/* determine the type of volume we're looking for */
-	force = 0;
-	type = AFSVL_ROVOL;
-
-	if (rwpath || name[0] == '%') {
-		type = AFSVL_RWVOL;
-		force = 1;
-	}
-
-	suffix = strrchr(name, '.');
-	if (suffix) {
-		if (strcmp(suffix, ".readonly") == 0) {
-			type = AFSVL_ROVOL;
-			force = 1;
-		}
-		else if (strcmp(suffix, ".backup") == 0) {
-			type = AFSVL_BACKVOL;
-			force = 1;
-		}
-		else if (suffix[1] == 0) {
-		}
-		else {
-			suffix = NULL;
-		}
-	}
+	int ret, loop;
 
-	/* split the cell and volume names */
-	name++;
-	volname = strchr(name, ':');
-	if (volname) {
-		cellname = name;
-		cellnamesz = volname - name;
-		volname++;
-	}
-	else {
-		volname = name;
-		cellname = NULL;
-		cellnamesz = 0;
-	}
-
-	volnamesz = suffix ? suffix - volname : strlen(volname);
-
-	_debug("CELL:%*.*s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
-	       cellnamesz, cellnamesz, cellname ?: "", cell,
-	       volnamesz, volnamesz, volname, suffix ?: "-",
-	       type,
-	       force ? " FORCE" : "");
-
-	/* lookup the cell record */
-	if (cellname || !cell) {
-		ret = afs_cell_lookup(cellname, cellnamesz, &cell);
-		if (ret<0) {
-			printk("kAFS: unable to lookup cell '%s'\n",
-			       cellname ?: "");
-			goto error;
-		}
-	}
-	else {
-		afs_get_cell(cell);
-	}
+	_enter("{%*.*s,%d}",
+	       params->volnamesz, params->volnamesz, params->volname, params->rwpath);
 
 	/* lookup the volume location record */
-	ret = afs_vlocation_lookup(cell, volname, volnamesz, &vlocation);
-	if (ret < 0)
+	vlocation = afs_vlocation_lookup(params->cell, params->key,
+					 params->volname, params->volnamesz);
+	if (IS_ERR(vlocation)) {
+		ret = PTR_ERR(vlocation);
+		vlocation = NULL;
 		goto error;
+	}
 
 	/* make the final decision on the type we want */
 	ret = -ENOMEDIUM;
-	if (force && !(vlocation->vldb.vidmask & (1 << type)))
+	if (params->force && !(vlocation->vldb.vidmask & (1 << params->type)))
 		goto error;
 
 	srvtmask = 0;
 	for (loop = 0; loop < vlocation->vldb.nservers; loop++)
 		srvtmask |= vlocation->vldb.srvtmask[loop];
 
-	if (force) {
-		if (!(srvtmask & (1 << type)))
+	if (params->force) {
+		if (!(srvtmask & (1 << params->type)))
 			goto error;
-	}
-	else if (srvtmask & AFS_VOL_VTM_RO) {
-		type = AFSVL_ROVOL;
-	}
-	else if (srvtmask & AFS_VOL_VTM_RW) {
-		type = AFSVL_RWVOL;
-	}
-	else {
+	} else if (srvtmask & AFS_VOL_VTM_RO) {
+		params->type = AFSVL_ROVOL;
+	} else if (srvtmask & AFS_VOL_VTM_RW) {
+		params->type = AFSVL_RWVOL;
+	} else {
 		goto error;
 	}
 
-	down_write(&cell->vl_sem);
+	down_write(&params->cell->vl_sem);
 
 	/* is the volume already active? */
-	if (vlocation->vols[type]) {
+	if (vlocation->vols[params->type]) {
 		/* yes - re-use it */
-		volume = vlocation->vols[type];
+		volume = vlocation->vols[params->type];
 		afs_get_volume(volume);
 		goto success;
 	}
@@ -191,23 +100,24 @@ int afs_volume_lookup(const char *name, 
 		goto error_up;
 
 	atomic_set(&volume->usage, 1);
-	volume->type		= type;
-	volume->type_force	= force;
-	volume->cell		= cell;
-	volume->vid		= vlocation->vldb.vid[type];
+	volume->type		= params->type;
+	volume->type_force	= params->force;
+	volume->cell		= params->cell;
+	volume->vid		= vlocation->vldb.vid[params->type];
 
 	init_rwsem(&volume->server_sem);
 
 	/* look up all the applicable server records */
 	for (loop = 0; loop < 8; loop++) {
 		if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
-			ret = afs_server_lookup(
-				volume->cell,
-				&vlocation->vldb.servers[loop],
-				&volume->servers[volume->nservers]);
-			if (ret < 0)
+			server = afs_lookup_server(
+			       volume->cell, &vlocation->vldb.servers[loop]);
+			if (IS_ERR(server)) {
+				ret = PTR_ERR(server);
 				goto error_discard;
+			}
 
+			volume->servers[volume->nservers] = server;
 			volume->nservers++;
 		}
 	}
@@ -223,35 +133,34 @@ #endif
 	afs_get_vlocation(vlocation);
 	volume->vlocation = vlocation;
 
-	vlocation->vols[type] = volume;
+	vlocation->vols[volume->type] = volume;
 
- success:
+success:
 	_debug("kAFS selected %s volume %08x",
 	       afs_voltypes[volume->type], volume->vid);
-	*_volume = volume;
-	ret = 0;
+	up_write(&params->cell->vl_sem);
+	afs_put_vlocation(vlocation);
+	_leave(" = %p", volume);
+	return volume;
 
 	/* clean up */
- error_up:
-	up_write(&cell->vl_sem);
- error:
+error_up:
+	up_write(&params->cell->vl_sem);
+error:
 	afs_put_vlocation(vlocation);
-	afs_put_cell(cell);
-
-	_leave(" = %d (%p)", ret, volume);
-	return ret;
+	_leave(" = %d", ret);
+	return ERR_PTR(ret);
 
- error_discard:
-	up_write(&cell->vl_sem);
+error_discard:
+	up_write(&params->cell->vl_sem);
 
 	for (loop = volume->nservers - 1; loop >= 0; loop--)
 		afs_put_server(volume->servers[loop]);
 
 	kfree(volume);
 	goto error;
-} /* end afs_volume_lookup() */
+}
 
-/*****************************************************************************/
 /*
  * destroy a volume record
  */
@@ -265,10 +174,9 @@ void afs_put_volume(struct afs_volume *v
 
 	_enter("%p", volume);
 
-	vlocation = volume->vlocation;
+	ASSERTCMP(atomic_read(&volume->usage), >, 0);
 
-	/* sanity check */
-	BUG_ON(atomic_read(&volume->usage) <= 0);
+	vlocation = volume->vlocation;
 
 	/* to prevent a race, the decrement and the dequeue must be effectively
 	 * atomic */
@@ -296,21 +204,27 @@ #endif
 	kfree(volume);
 
 	_leave(" [destroyed]");
-} /* end afs_put_volume() */
+}
 
-/*****************************************************************************/
 /*
  * pick a server to use to try accessing this volume
  * - returns with an elevated usage count on the server chosen
  */
-int afs_volume_pick_fileserver(struct afs_volume *volume,
-			       struct afs_server **_server)
+struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
 {
+	struct afs_volume *volume = vnode->volume;
 	struct afs_server *server;
 	int ret, state, loop;
 
 	_enter("%s", volume->vlocation->vldb.name);
 
+	/* stick with the server we're already using if we can */
+	if (vnode->server && vnode->server->fs_state == 0) {
+		afs_get_server(vnode->server);
+		_leave(" = %p [current]", vnode->server);
+		return vnode->server;
+	}
+
 	down_read(&volume->server_sem);
 
 	/* handle the no-server case */
@@ -318,7 +232,7 @@ int afs_volume_pick_fileserver(struct af
 		ret = volume->rjservers ? -ENOMEDIUM : -ESTALE;
 		up_read(&volume->server_sem);
 		_leave(" = %d [no servers]", ret);
-		return ret;
+		return ERR_PTR(ret);
 	}
 
 	/* basically, just search the list for the first live server and use
@@ -328,15 +242,16 @@ int afs_volume_pick_fileserver(struct af
 		server = volume->servers[loop];
 		state = server->fs_state;
 
+		_debug("consider %d [%d]", loop, state);
+
 		switch (state) {
 			/* found an apparently healthy server */
 		case 0:
 			afs_get_server(server);
 			up_read(&volume->server_sem);
-			*_server = server;
-			_leave(" = 0 (picked %08x)",
-			       ntohl(server->addr.s_addr));
-			return 0;
+			_leave(" = %p (picked %08x)",
+			       server, ntohl(server->addr.s_addr));
+			return server;
 
 		case -ENETUNREACH:
 			if (ret == 0)
@@ -372,20 +287,21 @@ int afs_volume_pick_fileserver(struct af
 	 */
 	up_read(&volume->server_sem);
 	_leave(" = %d", ret);
-	return ret;
-} /* end afs_volume_pick_fileserver() */
+	return ERR_PTR(ret);
+}
 
-/*****************************************************************************/
 /*
  * release a server after use
  * - releases the ref on the server struct that was acquired by picking
  * - records result of using a particular server to access a volume
  * - return 0 to try again, 1 if okay or to issue error
+ * - the caller must release the server struct if result was 0
  */
-int afs_volume_release_fileserver(struct afs_volume *volume,
+int afs_volume_release_fileserver(struct afs_vnode *vnode,
 				  struct afs_server *server,
 				  int result)
 {
+	struct afs_volume *volume = vnode->volume;
 	unsigned loop;
 
 	_enter("%s,%08x,%d",
@@ -396,14 +312,16 @@ int afs_volume_release_fileserver(struct
 		/* success */
 	case 0:
 		server->fs_act_jif = jiffies;
-		break;
+		server->fs_state = 0;
+		_leave("");
+		return 1;
 
 		/* the fileserver denied all knowledge of the volume */
 	case -ENOMEDIUM:
 		server->fs_act_jif = jiffies;
 		down_write(&volume->server_sem);
 
-		/* first, find where the server is in the active list (if it
+		/* firstly, find where the server is in the active list (if it
 		 * is) */
 		for (loop = 0; loop < volume->nservers; loop++)
 			if (volume->servers[loop] == server)
@@ -441,6 +359,7 @@ int afs_volume_release_fileserver(struct
 	case -ENETUNREACH:
 	case -EHOSTUNREACH:
 	case -ECONNREFUSED:
+	case -ETIME:
 	case -ETIMEDOUT:
 	case -EREMOTEIO:
 		/* mark the server as dead
@@ -460,60 +379,17 @@ int afs_volume_release_fileserver(struct
 		server->fs_act_jif = jiffies;
 	case -ENOMEM:
 	case -ENONET:
-		break;
+		/* tell the caller to accept the result */
+		afs_put_server(server);
+		_leave(" [local failure]");
+		return 1;
 	}
 
-	/* tell the caller to accept the result */
-	afs_put_server(server);
-	_leave("");
-	return 1;
-
 	/* tell the caller to loop around and try the next server */
- try_next_server_upw:
+try_next_server_upw:
 	up_write(&volume->server_sem);
- try_next_server:
+try_next_server:
 	afs_put_server(server);
 	_leave(" [try next server]");
 	return 0;
-
-} /* end afs_volume_release_fileserver() */
-
-/*****************************************************************************/
-/*
- * match a volume hash record stored in the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
-						  const void *entry)
-{
-	const struct afs_cache_vhash *vhash = entry;
-	struct afs_volume *volume = target;
-
-	_enter("{%u},{%u}", volume->type, vhash->vtype);
-
-	if (volume->type == vhash->vtype) {
-		_leave(" = SUCCESS");
-		return CACHEFS_MATCH_SUCCESS;
-	}
-
-	_leave(" = FAILED");
-	return CACHEFS_MATCH_FAILED;
-} /* end afs_volume_cache_match() */
-#endif
-
-/*****************************************************************************/
-/*
- * update a volume hash record stored in the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_volume_cache_update(void *source, void *entry)
-{
-	struct afs_cache_vhash *vhash = entry;
-	struct afs_volume *volume = source;
-
-	_enter("");
-
-	vhash->vtype = volume->type;
-
-} /* end afs_volume_cache_update() */
-#endif
+}
diff --git a/fs/afs/volume.h b/fs/afs/volume.h
deleted file mode 100644
index bfdcf19..0000000
--- a/fs/afs/volume.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/* volume.h: AFS volume management
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_AFS_VOLUME_H
-#define _LINUX_AFS_VOLUME_H
-
-#include "types.h"
-#include "fsclient.h"
-#include "kafstimod.h"
-#include "kafsasyncd.h"
-#include "cache.h"
-
-typedef enum {
-	AFS_VLUPD_SLEEP,		/* sleeping waiting for update timer to fire */
-	AFS_VLUPD_PENDING,		/* on pending queue */
-	AFS_VLUPD_INPROGRESS,		/* op in progress */
-	AFS_VLUPD_BUSYSLEEP,		/* sleeping because server returned EBUSY */
-	
-} __attribute__((packed)) afs_vlocation_upd_t;
-
-/*****************************************************************************/
-/*
- * entry in the cached volume location catalogue
- */
-struct afs_cache_vlocation
-{
-	uint8_t			name[64];	/* volume name (lowercase, padded with NULs) */
-	uint8_t			nservers;	/* number of entries used in servers[] */
-	uint8_t			vidmask;	/* voltype mask for vid[] */
-	uint8_t			srvtmask[8];	/* voltype masks for servers[] */
-#define AFS_VOL_VTM_RW	0x01 /* R/W version of the volume is available (on this server) */
-#define AFS_VOL_VTM_RO	0x02 /* R/O version of the volume is available (on this server) */
-#define AFS_VOL_VTM_BAK	0x04 /* backup version of the volume is available (on this server) */
-
-	afs_volid_t		vid[3];		/* volume IDs for R/W, R/O and Bak volumes */
-	struct in_addr		servers[8];	/* fileserver addresses */
-	time_t			rtime;		/* last retrieval time */
-};
-
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vlocation_cache_index_def;
-#endif
-
-/*****************************************************************************/
-/*
- * volume -> vnode hash table entry
- */
-struct afs_cache_vhash
-{
-	afs_voltype_t		vtype;		/* which volume variation */
-	uint8_t			hash_bucket;	/* which hash bucket this represents */
-} __attribute__((packed));
-
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_volume_cache_index_def;
-#endif
-
-/*****************************************************************************/
-/*
- * AFS volume location record
- */
-struct afs_vlocation
-{
-	atomic_t		usage;
-	struct list_head	link;		/* link in cell volume location list */
-	struct afs_timer	timeout;	/* decaching timer */
-	struct afs_cell		*cell;		/* cell to which volume belongs */
-#ifdef AFS_CACHING_SUPPORT
-	struct cachefs_cookie	*cache;		/* caching cookie */
-#endif
-	struct afs_cache_vlocation vldb;	/* volume information DB record */
-	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
-	rwlock_t		lock;		/* access lock */
-	unsigned long		read_jif;	/* time at which last read from vlserver */
-	struct afs_timer	upd_timer;	/* update timer */
-	struct afs_async_op	upd_op;		/* update operation */
-	afs_vlocation_upd_t	upd_state;	/* update state */
-	unsigned short		upd_first_svix;	/* first server index during update */
-	unsigned short		upd_curr_svix;	/* current server index during update */
-	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
-	unsigned short		upd_busy_cnt;	/* EBUSY count during update */
-	unsigned short		valid;		/* T if valid */
-};
-
-extern int afs_vlocation_lookup(struct afs_cell *cell,
-				const char *name,
-				unsigned namesz,
-				struct afs_vlocation **_vlocation);
-
-#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)
-
-extern void afs_put_vlocation(struct afs_vlocation *vlocation);
-extern void afs_vlocation_do_timeout(struct afs_vlocation *vlocation);
-
-/*****************************************************************************/
-/*
- * AFS volume access record
- */
-struct afs_volume
-{
-	atomic_t		usage;
-	struct afs_cell		*cell;		/* cell to which belongs (unrefd ptr) */
-	struct afs_vlocation	*vlocation;	/* volume location */
-#ifdef AFS_CACHING_SUPPORT
-	struct cachefs_cookie	*cache;		/* caching cookie */
-#endif
-	afs_volid_t		vid;		/* volume ID */
-	afs_voltype_t		type;		/* type of volume */
-	char			type_force;	/* force volume type (suppress R/O -> R/W) */
-	unsigned short		nservers;	/* number of server slots filled */
-	unsigned short		rjservers;	/* number of servers discarded due to -ENOMEDIUM */
-	struct afs_server	*servers[8];	/* servers on which volume resides (ordered) */
-	struct rw_semaphore	server_sem;	/* lock for accessing current server */
-};
-
-extern int afs_volume_lookup(const char *name,
-			     struct afs_cell *cell,
-			     int rwpath,
-			     struct afs_volume **_volume);
-
-#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
-
-extern void afs_put_volume(struct afs_volume *volume);
-
-extern int afs_volume_pick_fileserver(struct afs_volume *volume,
-				      struct afs_server **_server);
-
-extern int afs_volume_release_fileserver(struct afs_volume *volume,
-					 struct afs_server *server,
-					 int result);
-
-#endif /* _LINUX_AFS_VOLUME_H */
diff --git a/fs/aio.c b/fs/aio.c
index e4598d6..b97ab80 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -68,10 +68,8 @@ static void aio_queue_work(struct kioctx
  */
 static int __init aio_setup(void)
 {
-	kiocb_cachep = kmem_cache_create("kiocb", sizeof(struct kiocb),
-				0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
-	kioctx_cachep = kmem_cache_create("kioctx", sizeof(struct kioctx),
-				0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+	kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+	kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
 	aio_wq = create_workqueue("aio");
 
diff --git a/fs/attr.c b/fs/attr.c
index 97de946..a0a0c7b 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -9,7 +9,6 @@ #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/capability.h>
 #include <linux/fsnotify.h>
 #include <linux/fcntl.h>
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 26063dc..5769a2f 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -18,7 +18,6 @@ #include <linux/seq_file.h>
 #include <linux/pagemap.h>
 #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>
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index d0e9b3a..15170f4 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -17,7 +17,6 @@ #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/param.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include "autofs_i.h"
 
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index efeab2f..329ee47 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -12,7 +12,6 @@ #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
 
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index cc6cc8e..fe96108 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -293,8 +293,7 @@ static void init_once(void * foo, struct
 {
         struct befs_inode_info *bi = (struct befs_inode_info *) foo;
 	
-	        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-		            SLAB_CTOR_CONSTRUCTOR) {
+	        if (flags & SLAB_CTOR_CONSTRUCTOR) {
 			inode_init_once(&bi->vfs_inode);
 		}
 }
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 93d6219..edc08d8 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -248,8 +248,7 @@ static void init_once(void * foo, struct
 {
 	struct bfs_inode_info *bi = foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&bi->vfs_inode);
 }
  
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9cc4f0a..fa8ea33 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -31,7 +31,6 @@ #include <linux/elfcore.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/compiler.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
@@ -39,6 +38,7 @@ #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/random.h>
 #include <linux/elf.h>
+#include <linux/utsname.h>
 #include <asm/uaccess.h>
 #include <asm/param.h>
 #include <asm/page.h>
@@ -871,6 +871,8 @@ static int load_elf_binary(struct linux_
 				elf_prot, elf_flags);
 		if (BAD_ADDR(error)) {
 			send_sig(SIGKILL, current, 0);
+			retval = IS_ERR((void *)error) ?
+				PTR_ERR((void*)error) : -EINVAL;
 			goto out_free_dentry;
 		}
 
@@ -900,6 +902,7 @@ static int load_elf_binary(struct linux_
 		    TASK_SIZE - elf_ppnt->p_memsz < k) {
 			/* set_brk can never work. Avoid overflows. */
 			send_sig(SIGKILL, current, 0);
+			retval = -EINVAL;
 			goto out_free_dentry;
 		}
 
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index f3ddca4..9d62fba 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -30,7 +30,6 @@ #include <linux/highuid.h>
 #include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/elf.h>
 #include <linux/elf-fdpic.h>
 #include <linux/elfcore.h>
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 1f2d1ad..576dd7d 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -12,7 +12,6 @@ #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/binfmts.h>
 #include <linux/elf.h>
 #include <linux/init.h>
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index e6f5799..18657f0 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -727,8 +727,8 @@ static const struct super_operations s_o
 static int bm_fill_super(struct super_block * sb, void * data, int silent)
 {
 	static struct tree_descr bm_files[] = {
-		[1] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
-		[2] = {"register", &bm_register_operations, S_IWUSR},
+		[2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
+		[3] = {"register", &bm_register_operations, S_IWUSR},
 		/* last one */ {""}
 	};
 	int err = simple_fill_super(sb, 0x42494e4d, bm_files);
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 1edbcca..304c885 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -12,7 +12,6 @@ #include <linux/slab.h>
 #include <linux/binfmts.h>
 #include <linux/init.h>
 #include <linux/file.h>
-#include <linux/smp_lock.h>
 #include <linux/err.h>
 #include <linux/fs.h>
 
diff --git a/fs/bio.c b/fs/bio.c
index 7618bcb..093345f 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -28,7 +28,7 @@ #include <linux/workqueue.h>
 #include <linux/blktrace_api.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
 
-#define BIO_POOL_SIZE 256
+#define BIO_POOL_SIZE 2
 
 static struct kmem_cache *bio_slab __read_mostly;
 
@@ -38,7 +38,7 @@ #define BIOVEC_NR_POOLS 6
  * a small number of entries is fine, not going to be performance critical.
  * basically we just need to survive
  */
-#define BIO_SPLIT_ENTRIES 8	
+#define BIO_SPLIT_ENTRIES 2
 mempool_t *bio_split_pool __read_mostly;
 
 struct biovec_slab {
@@ -1120,7 +1120,7 @@ struct bio_pair *bio_split(struct bio *b
  * create memory pools for biovec's in a bio_set.
  * use the global biovec slabs created for general use.
  */
-static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
+static int biovec_create_pools(struct bio_set *bs, int pool_entries)
 {
 	int i;
 
@@ -1128,9 +1128,6 @@ static int biovec_create_pools(struct bi
 		struct biovec_slab *bp = bvec_slabs + i;
 		mempool_t **bvp = bs->bvec_pools + i;
 
-		if (pool_entries > 1 && i >= scale)
-			pool_entries >>= 1;
-
 		*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
 		if (!*bvp)
 			return -ENOMEM;
@@ -1161,7 +1158,7 @@ void bioset_free(struct bio_set *bs)
 	kfree(bs);
 }
 
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
+struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
 {
 	struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
 
@@ -1172,7 +1169,7 @@ struct bio_set *bioset_create(int bio_po
 	if (!bs->bio_pool)
 		goto bad;
 
-	if (!biovec_create_pools(bs, bvec_pool_size, scale))
+	if (!biovec_create_pools(bs, bvec_pool_size))
 		return bs;
 
 bad:
@@ -1196,38 +1193,11 @@ static void __init biovec_init_slabs(voi
 
 static int __init init_bio(void)
 {
-	int megabytes, bvec_pool_entries;
-	int scale = BIOVEC_NR_POOLS;
-
-	bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
-				SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+	bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
 	biovec_init_slabs();
 
-	megabytes = nr_free_pages() >> (20 - PAGE_SHIFT);
-
-	/*
-	 * find out where to start scaling
-	 */
-	if (megabytes <= 16)
-		scale = 0;
-	else if (megabytes <= 32)
-		scale = 1;
-	else if (megabytes <= 64)
-		scale = 2;
-	else if (megabytes <= 96)
-		scale = 3;
-	else if (megabytes <= 128)
-		scale = 4;
-
-	/*
-	 * Limit number of entries reserved -- mempools are only used when
-	 * the system is completely unable to allocate memory, so we only
-	 * need enough to make progress.
-	 */
-	bvec_pool_entries = 1 + scale;
-
-	fs_bio_set = bioset_create(BIO_POOL_SIZE, bvec_pool_entries, scale);
+	fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
 	if (!fs_bio_set)
 		panic("bio: can't allocate bios\n");
 
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 575076c..7428992 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -22,6 +22,7 @@ #include <linux/mpage.h>
 #include <linux/mount.h>
 #include <linux/uio.h>
 #include <linux/namei.h>
+#include <linux/log2.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -55,17 +56,19 @@ static sector_t max_block(struct block_d
 	return retval;
 }
 
-/* Kill _all_ buffers, dirty or not.. */
+/* Kill _all_ buffers and pagecache , dirty or not.. */
 static void kill_bdev(struct block_device *bdev)
 {
-	invalidate_bdev(bdev, 1);
+	if (bdev->bd_inode->i_mapping->nrpages == 0)
+		return;
+	invalidate_bh_lrus();
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 }	
 
 int set_blocksize(struct block_device *bdev, int size)
 {
 	/* Size must be a power of two, and between 512 and PAGE_SIZE */
-	if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
+	if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size))
 		return -EINVAL;
 
 	/* Size cannot be smaller than the size supported by the device */
@@ -455,9 +458,7 @@ static void init_once(void * foo, struct
 	struct bdev_inode *ei = (struct bdev_inode *) foo;
 	struct block_device *bdev = &ei->bdev;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
-	{
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		memset(bdev, 0, sizeof(*bdev));
 		mutex_init(&bdev->bd_mutex);
 		sema_init(&bdev->bd_mount_sem, 1);
@@ -1478,7 +1479,7 @@ int __invalidate_device(struct block_dev
 		res = invalidate_inodes(sb);
 		drop_super(sb);
 	}
-	invalidate_bdev(bdev, 0);
+	invalidate_bdev(bdev);
 	return res;
 }
 EXPORT_SYMBOL(__invalidate_device);
diff --git a/fs/buffer.c b/fs/buffer.c
index 1d0852f..eb820b8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -24,7 +24,6 @@ #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/capability.h>
 #include <linux/blkdev.h>
 #include <linux/file.h>
@@ -44,7 +43,6 @@ #include <linux/mpage.h>
 #include <linux/bit_spinlock.h>
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
-static void invalidate_bh_lrus(void);
 
 #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
 
@@ -333,7 +331,7 @@ out:
    we think the disk contains more recent information than the buffercache.
    The update == 1 pass marks the buffers we need to update, the update == 2
    pass does the actual I/O. */
-void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
+void invalidate_bdev(struct block_device *bdev)
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
 
@@ -341,11 +339,6 @@ void invalidate_bdev(struct block_device
 		return;
 
 	invalidate_bh_lrus();
-	/*
-	 * FIXME: what about destroy_dirty_buffers?
-	 * We really want to use invalidate_inode_pages2() for
-	 * that, but not until that's cleaned up.
-	 */
 	invalidate_mapping_pages(mapping, 0, -1);
 }
 
@@ -1408,7 +1401,7 @@ static void invalidate_bh_lru(void *arg)
 	put_cpu_var(bh_lrus);
 }
 	
-static void invalidate_bh_lrus(void)
+void invalidate_bh_lrus(void)
 {
 	on_each_cpu(invalidate_bh_lru, NULL, 1, 1);
 }
@@ -1700,17 +1693,8 @@ done:
 		 * clean.  Someone wrote them back by hand with
 		 * ll_rw_block/submit_bh.  A rare case.
 		 */
-		int uptodate = 1;
-		do {
-			if (!buffer_uptodate(bh)) {
-				uptodate = 0;
-				break;
-			}
-			bh = bh->b_this_page;
-		} while (bh != head);
-		if (uptodate)
-			SetPageUptodate(page);
 		end_page_writeback(page);
+
 		/*
 		 * The page and buffer_heads can be released at any time from
 		 * here on.
@@ -1742,6 +1726,7 @@ recover:
 	} while ((bh = bh->b_this_page) != head);
 	SetPageError(page);
 	BUG_ON(PageWriteback(page));
+	mapping_set_error(page->mapping, err);
 	set_page_writeback(page);
 	do {
 		struct buffer_head *next = bh->b_this_page;
@@ -2968,8 +2953,7 @@ EXPORT_SYMBOL(free_buffer_head);
 static void
 init_buffer_head(void *data, struct kmem_cache *cachep, unsigned long flags)
 {
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-			    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		struct buffer_head * bh = (struct buffer_head *)data;
 
 		memset(bh, 0, sizeof(*bh));
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 5d1f487..a9b6bc5 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,4 +1,16 @@
-Verison 1.48
+Version 1.49
+------------
+IPv6 support.  Enable ipv6 addresses to be passed on mount (put the ipv6
+address after the "ip=" mount option, at least until mount.cifs is fixed to
+handle DNS host to ipv6 name translation).  Accept override of uid or gid
+on mount even when Unix Extensions are negotiated (it used to be ignored
+when Unix Extensions were ignored).  This allows users to override the
+default uid and gid for files when they are certain that the uids or
+gids on the server do not match those of the client.  Make "sec=none"
+mount override username (so that null user connection is attempted)
+to match what documentation said.
+
+Version 1.48
 ------------
 Fix mtime bouncing around from local idea of last write times to remote time.
 Fix hang (in i_size_read) when simultaneous size update of same remote file
@@ -9,7 +21,13 @@ from read-only back to read-write, refle
 (we had been leaving a file's mode read-only until the inode were reloaded).
 Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute
 when archive dos attribute not set and we are changing mode back to writeable
-on server which does not support the Unix Extensions).
+on server which does not support the Unix Extensions).  Remove read only dos
+attribute on chmod when adding any write permission (ie on any of
+user/group/other (not all of user/group/other ie  0222) when
+mounted to windows.  Add support for POSIX MkDir (slight performance
+enhancement and eliminates the network race between the mkdir and set 
+path info of the mode).
+
 
 Version 1.47
 ------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 080c5eb..4d01697 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -257,13 +257,19 @@ A partial list of the supported mount op
 		mount.	
   domain	Set the SMB/CIFS workgroup name prepended to the
 		username during CIFS session establishment
-  uid		If CIFS Unix extensions are not supported by the server
-		this overrides the default uid for inodes. For mounts to
-		servers which do support the CIFS Unix extensions, such
-		as a properly configured Samba server, the server provides
-		the uid, gid and mode.  For servers which do not support
-		the Unix extensions, the default uid (and gid) returned on
-		lookup of existing files is the uid (gid) of the person
+  uid		Set the default uid for inodes. For mounts to servers
+		which do support the CIFS Unix extensions, such as a
+		properly configured Samba server, the server provides
+		the uid, gid and mode so this parameter should  not be
+		specified unless the server and clients uid and gid
+		numbering differ.  If the server and client are in the
+		same domain (e.g. running winbind or nss_ldap) and
+		the server supports the Unix Extensions then the uid
+		and gid can be retrieved from the server (and uid
+		and gid would not have to be specifed on the mount. 
+		For servers which do not support the CIFS Unix
+		extensions, the default uid (and gid) returned on lookup
+		of existing files will be the uid (gid) of the person
 		who executed the mount (root, except when mount.cifs
 		is configured setuid for user mounts) unless the "uid=" 
 		(gid) mount option is specified.  For the uid (gid) of newly
@@ -281,8 +287,7 @@ A partial list of the supported mount op
 		the client.  Note that the mount.cifs helper must be
 		at version 1.10 or higher to support specifying the uid
 		(or gid) in non-numberic form.
-  gid		If CIFS Unix extensions are not supported by the server
-		this overrides the default gid for inodes.
+  gid		Set the default gid for inodes (similar to above).
   file_mode     If CIFS Unix extensions are not supported by the server
 		this overrides the default mode for file inodes.
   dir_mode      If CIFS Unix extensions are not supported by the server 
@@ -467,7 +472,7 @@ including:
 	-V      print mount.cifs version
 	-?      display simple usage information
 
-With recent 2.6 kernel versions of modutils, the version of the cifs kernel
+With most 2.6 kernel versions of modutils, the version of the cifs kernel
 module can be displayed via modinfo.
 
 Misc /proc/fs/cifs Flags and Debug Info
@@ -516,8 +521,22 @@ SecurityFlags		Flags which control secur
 			must use plaintext passwords			0x20020
 			(reserved for future packet encryption)		0x00040
 
-cifsFYI			If set to one, additional debug information is
-			logged to the system error log. (default 0)
+cifsFYI			If set to non-zero value, additional debug information
+			will be logged to the system error log.  This field
+			contains three flags controlling different classes of
+			debugging entries.  The maximum value it can be set
+			to is 7 which enables all debugging points (default 0).
+			Some debugging statements are not compiled into the
+			cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the
+			kernel configuration. cifsFYI may be set to one or
+			nore of the following flags (7 sets them all):
+
+			log cifs informational messages			0x01
+			log return codes from cifs entry points		0x02
+			log slow responses (ie which take longer than 1 second)
+			  CONFIG_CIFS_STATS2 must be enabled in .config	0x04
+				
+				
 traceSMB		If set to one, debug information is logged to the
 			system error log with the start of smb requests
 			and responses (default 0)
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index d7b9c27..78b620e 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-Version 1.39 November 30, 2005
+Version 1.49 April 26, 2007
 
 A Partial List of Missing Features
 ==================================
@@ -18,7 +18,7 @@ better)
 
 d) Kerberos/SPNEGO session setup support - (started)
 
-e) NTLMv2 authentication (mostly implemented - double check
+e) More testing of NTLMv2 authentication (mostly implemented - double check
 that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in
 fs/cifs/connect.c)
 
@@ -27,55 +27,44 @@ used (Kerberos or NTLMSSP). Signing alre
 and raw NTLMSSP already. This is important when enabling
 extended security and mounting to Windows 2003 Servers
 
-f) Directory entry caching relies on a 1 second timer, rather than 
+g) Directory entry caching relies on a 1 second timer, rather than 
 using FindNotify or equivalent.  - (started)
 
-g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
-style byte range lock differences.  Save byte range locks so
-reconnect can replay them.  
-
-h) Support unlock all (unlock 0,MAX_OFFSET)
-by unlocking all known byte range locks that we locked on the file.
-
-i) quota support (needs minor kernel change since quota calls
+h) quota support (needs minor kernel change since quota calls
 to make it to network filesystems or deviceless filesystems)
 
-j) investigate sync behavior (including syncpage) and check  
+i) investigate sync behavior (including syncpage) and check  
 for proper behavior of intr/nointr
 
-k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
+j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
 extra copy in/out of the socket buffers in some cases.
 
-l) finish support for IPv6.  This is mostly complete but
-needs a simple conversion of ipv6 to sin6_addr from the
-address in string representation.
-
-m) Better optimize open (and pathbased setfilesize) to reduce the
+k) Better optimize open (and pathbased setfilesize) to reduce the
 oplock breaks coming from windows srv.  Piggyback identical file
 opens on top of each other by incrementing reference count rather
 than resending (helps reduce server resource utilization and avoid
 spurious oplock breaks).
 
-o) Improve performance of readpages by sending more than one read
+l) Improve performance of readpages by sending more than one read
 at a time when 8 pages or more are requested. In conjuntion
 add support for async_cifs_readpages.
 
-p) Add support for storing symlink info to Windows servers 
+m) Add support for storing symlink info to Windows servers 
 in the Extended Attribute format their SFU clients would recognize.
 
-q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
+n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
 will autorefresh (partially complete by Asser). Needs minor kernel
 vfs change to support removing D_NOTIFY on a file.   
 
-r) Add GUI tool to configure /proc/fs/cifs settings and for display of
+o) Add GUI tool to configure /proc/fs/cifs settings and for display of
 the CIFS statistics (started)
 
-s) implement support for security and trusted categories of xattrs
+p) implement support for security and trusted categories of xattrs
 (requires minor protocol extension) to enable better support for SELINUX
 
-t) Implement O_DIRECT flag on open (already supported on mount)
+q) Implement O_DIRECT flag on open (already supported on mount)
 
-u) Create UID mapping facility so server UIDs can be mapped on a per
+r) Create UID mapping facility so server UIDs can be mapped on a per
 mount or a per server basis to client UIDs or nobody if no mapping
 exists.  This is helpful when Unix extensions are negotiated to
 allow better permission checking when UIDs differ on the server
@@ -83,19 +72,26 @@ and client.  Add new protocol request to
 standard for asking the server for the corresponding name of a
 particular uid.
 
-v) Add support for CIFS Unix and also the newer POSIX extensions to the
+s) Add support for CIFS Unix and also the newer POSIX extensions to the
 server side for Samba 4.
 
-w) Finish up the dos time conversion routines needed to return old server
-time to the client (default time, of now or time 0 is used now for these 
-very old servers)
-
-x) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) 
+t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) 
 need to add ability to set time to server (utimes command)
 
-y) Finish testing of Windows 9x/Windows ME server support (started).
+u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
+
+v) mount check for unmatched uids
+
+w) Add mount option for Linux extension disable per mount, and partial
+disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
 
-KNOWN BUGS (updated February 26, 2007)
+x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
+processes can proceed better in parallel (on the server)
+
+y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
+restriction of wsize max being 127K) 
+
+KNOWN BUGS (updated April 24, 2007)
 ====================================
 See http://bugzilla.samba.org - search on product "CifsVFS" for
 current bug list.
@@ -127,10 +123,3 @@ negotiated size) and send larger write s
 4) More exhaustively test against less common servers.  More testing
 against Windows 9x, Windows ME servers.
 
-DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
-
-mount check for unmatched uids - and uid override
-
-Add mount option for Linux extension disable per mount, and partial disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?) 
-
-Free threads at umount --force that are stuck on the sesSem
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index fd1e52e..4cc2012 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -22,12 +22,14 @@ #define CIFS_MOUNT_NO_PERM      1 /* do 
 #define CIFS_MOUNT_SET_UID      2 /* set current->euid in create etc. */
 #define CIFS_MOUNT_SERVER_INUM  4 /* inode numbers from uniqueid from server */
 #define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
-#define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
-#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
-#define CIFS_MOUNT_POSIX_PATHS	0x40 /* Negotiate posix pathnames if possible. */
-#define CIFS_MOUNT_UNX_EMUL	0x80 /* Network compat with SFUnix emulation */
-#define CIFS_MOUNT_NO_BRL	0x100 /* No sending byte range locks to srv */
-#define CIFS_MOUNT_CIFS_ACL	0x200 /* send ACL requests to non-POSIX srv */
+#define CIFS_MOUNT_NO_XATTR     0x10  /* if set - disable xattr support       */
+#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames   */
+#define CIFS_MOUNT_POSIX_PATHS  0x40  /* Negotiate posix pathnames if possible*/
+#define CIFS_MOUNT_UNX_EMUL     0x80  /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_NO_BRL       0x100 /* No sending byte range locks to srv   */
+#define CIFS_MOUNT_CIFS_ACL     0x200 /* send ACL requests to non-POSIX srv   */
+#define CIFS_MOUNT_OVERR_UID    0x400 /* override uid returned from server    */
+#define CIFS_MOUNT_OVERR_GID    0x800 /* override gid returned from server    */
 
 struct cifs_sb_info {
 	struct cifsTconInfo *tcon;	/* primary mount */
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index d2a8b29..793c4b9 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -74,8 +74,8 @@ cifs_strtoUCS(__le16 * to, const char *f
 		charlen = codepage->char2uni(from, len, &wchar_to[i]);
 		if (charlen < 1) {
 			cERROR(1,
-			       ("cifs_strtoUCS: char2uni returned %d",
-				charlen));
+			       ("strtoUCS: char2uni of %d returned %d",
+				(int)*from, charlen));
 			/* A question mark */
 			to[i] = cpu_to_le16(0x003f);
 			charlen = 1;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index faba4d6..8568e10 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -100,7 +100,7 @@ cifs_read_super(struct super_block *sb, 
 	sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
 	sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
 	cifs_sb = CIFS_SB(sb);
-	if(cifs_sb == NULL)
+	if (cifs_sb == NULL)
 		return -ENOMEM;
 
 	rc = cifs_mount(sb, cifs_sb, data, devname);
@@ -115,10 +115,10 @@ cifs_read_super(struct super_block *sb, 
 	sb->s_magic = CIFS_MAGIC_NUMBER;
 	sb->s_op = &cifs_super_ops;
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-	if(experimEnabled != 0)
+	if (experimEnabled != 0)
 		sb->s_export_op = &cifs_export_ops;
 #endif /* EXPERIMENTAL */	
-/*	if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+/*	if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
 	    sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
 #ifdef CONFIG_CIFS_QUOTA
 	sb->s_qcop = &cifs_quotactl_ops;
@@ -147,8 +147,8 @@ out_no_root:
 		iput(inode);
 
 out_mount_failed:
-	if(cifs_sb) {
-		if(cifs_sb->local_nls)
+	if (cifs_sb) {
+		if (cifs_sb->local_nls)
 			unload_nls(cifs_sb->local_nls);	
 		kfree(cifs_sb);
 	}
@@ -163,7 +163,7 @@ cifs_put_super(struct super_block *sb)
 
 	cFYI(1, ("In cifs_put_super"));
 	cifs_sb = CIFS_SB(sb);
-	if(cifs_sb == NULL) {
+	if (cifs_sb == NULL) {
 		cFYI(1,("Empty cifs superblock info passed to unmount"));
 		return;
 	}
@@ -208,14 +208,14 @@ cifs_statfs(struct dentry *dentry, struc
 
     /* Only need to call the old QFSInfo if failed
     on newer one */
-    if(rc)
-	if(pTcon->ses->capabilities & CAP_NT_SMBS)
+    if (rc)
+	if (pTcon->ses->capabilities & CAP_NT_SMBS)
 		rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
 
 	/* 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)
+	if (rc)
 		rc = SMBOldQFSInfo(xid, pTcon, buf);
 	/*     
 	   int f_type;
@@ -301,11 +301,19 @@ cifs_show_options(struct seq_file *s, st
 				if (cifs_sb->tcon->ses->userName)
 					seq_printf(s, ",username=%s",
 					   cifs_sb->tcon->ses->userName);
-				if(cifs_sb->tcon->ses->domainName)
+				if (cifs_sb->tcon->ses->domainName)
 					seq_printf(s, ",domain=%s",
 					   cifs_sb->tcon->ses->domainName);
 			}
 		}
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+			seq_printf(s, ",posixpaths");
+		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
+		   !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+			seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
+		   !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+			seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
 		seq_printf(s, ",rsize=%d",cifs_sb->rsize);
 		seq_printf(s, ",wsize=%d",cifs_sb->wsize);
 	}
@@ -321,14 +329,14 @@ int cifs_xquota_set(struct super_block *
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifsTconInfo *pTcon;
 	
-	if(cifs_sb)
+	if (cifs_sb)
 		pTcon = cifs_sb->tcon;
 	else
 		return -EIO;
 
 
 	xid = GetXid();
-	if(pTcon) {
+	if (pTcon) {
 		cFYI(1,("set type: 0x%x id: %d",quota_type,qid));		
 	} else {
 		return -EIO;
@@ -346,13 +354,13 @@ int cifs_xquota_get(struct super_block *
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifsTconInfo *pTcon;
 
-	if(cifs_sb)
+	if (cifs_sb)
 		pTcon = cifs_sb->tcon;
 	else
 		return -EIO;
 
 	xid = GetXid();
-	if(pTcon) {
+	if (pTcon) {
                 cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
 	} else {
 		rc = -EIO;
@@ -369,13 +377,13 @@ int cifs_xstate_set(struct super_block *
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifsTconInfo *pTcon;
 
-	if(cifs_sb)
+	if (cifs_sb)
 		pTcon = cifs_sb->tcon;
 	else
 		return -EIO;
 
 	xid = GetXid();
-	if(pTcon) {
+	if (pTcon) {
                 cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
 	} else {
 		rc = -EIO;
@@ -392,13 +400,13 @@ int cifs_xstate_get(struct super_block *
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifsTconInfo *pTcon;
 
-	if(cifs_sb) {
+	if (cifs_sb) {
 		pTcon = cifs_sb->tcon;
 	} else {
 		return -EIO;
 	}
 	xid = GetXid();
-	if(pTcon) {
+	if (pTcon) {
 		cFYI(1,("pqstats %p",qstats));		
 	} else {
 		rc = -EIO;
@@ -424,11 +432,11 @@ static void cifs_umount_begin(struct vfs
 	if (!(flags & MNT_FORCE))
 		return;
 	cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
-	if(cifs_sb == NULL)
+	if (cifs_sb == NULL)
 		return;
 
 	tcon = cifs_sb->tcon;
-	if(tcon == NULL)
+	if (tcon == NULL)
 		return;
 	down(&tcon->tconSem);
 	if (atomic_read(&tcon->useCount) == 1)
@@ -437,7 +445,7 @@ static void cifs_umount_begin(struct vfs
 
 	/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
 	/* cancel_notify_requests(tcon); */
-	if(tcon->ses && tcon->ses->server)
+	if (tcon->ses && tcon->ses->server)
 	{
 		cFYI(1,("wake up tasks now - umount begin not complete"));
 		wake_up_all(&tcon->ses->server->request_q);
@@ -529,8 +537,7 @@ static loff_t cifs_llseek(struct file *f
 		/* some applications poll for the file length in this strange
 		   way so we must seek to end on non-oplocked files by
 		   setting the revalidate time to zero */
-		if(file->f_path.dentry->d_inode)		
-			CIFS_I(file->f_path.dentry->d_inode)->time = 0;
+		CIFS_I(file->f_path.dentry->d_inode)->time = 0;
 
 		retval = cifs_revalidate(file->f_path.dentry);
 		if (retval < 0)
@@ -694,8 +701,7 @@ cifs_init_once(void *inode, struct kmem_
 {
 	struct cifsInodeInfo *cifsi = inode;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&cifsi->vfs_inode);
 		INIT_LIST_HEAD(&cifsi->lockList);
 	}
@@ -724,7 +730,7 @@ cifs_destroy_inodecache(void)
 static int
 cifs_init_request_bufs(void)
 {
-	if(CIFSMaxBufSize < 8192) {
+	if (CIFSMaxBufSize < 8192) {
 	/* Buffer size can not be smaller than 2 * PATH_MAX since maximum
 	Unicode path name has to fit in any SMB/CIFS path based frames */
 		CIFSMaxBufSize = 8192;
@@ -741,7 +747,7 @@ cifs_init_request_bufs(void)
 	if (cifs_req_cachep == NULL)
 		return -ENOMEM;
 
-	if(cifs_min_rcv < 1)
+	if (cifs_min_rcv < 1)
 		cifs_min_rcv = 1;
 	else if (cifs_min_rcv > 64) {
 		cifs_min_rcv = 64;
@@ -751,7 +757,7 @@ cifs_init_request_bufs(void)
 	cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
 						  cifs_req_cachep);
 
-	if(cifs_req_poolp == NULL) {
+	if (cifs_req_poolp == NULL) {
 		kmem_cache_destroy(cifs_req_cachep);
 		return -ENOMEM;
 	}
@@ -772,7 +778,7 @@ cifs_init_request_bufs(void)
 		return -ENOMEM;              
 	}
 
-	if(cifs_min_small < 2)
+	if (cifs_min_small < 2)
 		cifs_min_small = 2;
 	else if (cifs_min_small > 256) {
 		cifs_min_small = 256;
@@ -782,7 +788,7 @@ cifs_init_request_bufs(void)
 	cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
 						     cifs_sm_req_cachep);
 
-	if(cifs_sm_req_poolp == NULL) {
+	if (cifs_sm_req_poolp == NULL) {
 		mempool_destroy(cifs_req_poolp);
 		kmem_cache_destroy(cifs_req_cachep);
 		kmem_cache_destroy(cifs_sm_req_cachep);
@@ -812,7 +818,7 @@ cifs_init_mids(void)
 
 	/* 3 is a reasonable minimum number of simultaneous operations */
 	cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
-	if(cifs_mid_poolp == NULL) {
+	if (cifs_mid_poolp == NULL) {
 		kmem_cache_destroy(cifs_mid_cachep);
 		return -ENOMEM;
 	}
@@ -850,14 +856,14 @@ static int cifs_oplock_thread(void * dum
 			continue;
 		
 		spin_lock(&GlobalMid_Lock);
-		if(list_empty(&GlobalOplock_Q)) {
+		if (list_empty(&GlobalOplock_Q)) {
 			spin_unlock(&GlobalMid_Lock);
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(39*HZ);
 		} else {
 			oplock_item = list_entry(GlobalOplock_Q.next, 
 				struct oplock_q_entry, qhead);
-			if(oplock_item) {
+			if (oplock_item) {
 				cFYI(1,("found oplock item to write out")); 
 				pTcon = oplock_item->tcon;
 				inode = oplock_item->pinode;
@@ -871,7 +877,7 @@ static int cifs_oplock_thread(void * dum
 				/* mutex_lock(&inode->i_mutex);*/
 				if (S_ISREG(inode->i_mode)) {
 					rc = filemap_fdatawrite(inode->i_mapping);
-					if(CIFS_I(inode)->clientCanCacheRead == 0) {
+					if (CIFS_I(inode)->clientCanCacheRead == 0) {
 						filemap_fdatawait(inode->i_mapping);
 						invalidate_remote_inode(inode);
 					}
@@ -888,7 +894,7 @@ static int cifs_oplock_thread(void * dum
 				not bother sending an oplock release if session 
 				to server still is disconnected since oplock 
 				already released by the server in that case */
-				if(pTcon->tidStatus != CifsNeedReconnect) {
+				if (pTcon->tidStatus != CifsNeedReconnect) {
 				    rc = CIFSSMBLock(0, pTcon, netfid,
 					    0 /* len */ , 0 /* offset */, 0, 
 					    0, LOCKING_ANDX_OPLOCK_RELEASE,
@@ -922,7 +928,7 @@ static int cifs_dnotify_thread(void * du
 		list_for_each(tmp, &GlobalSMBSessionList) {
 			ses = list_entry(tmp, struct cifsSesInfo, 
 				cifsSessionList);
-			if(ses && ses->server && 
+			if (ses && ses->server && 
 			     atomic_read(&ses->server->inFlight))
 				wake_up_all(&ses->server->response_q);
 		}
@@ -971,10 +977,10 @@ #endif /* CONFIG_CIFS_STATS2 */
 	rwlock_init(&GlobalSMBSeslock);
 	spin_lock_init(&GlobalMid_Lock);
 
-	if(cifs_max_pending < 2) {
+	if (cifs_max_pending < 2) {
 		cifs_max_pending = 2;
 		cFYI(1,("cifs_max_pending set to min of 2"));
-	} else if(cifs_max_pending > 256) {
+	} else if (cifs_max_pending > 256) {
 		cifs_max_pending = 256;
 		cFYI(1,("cifs_max_pending set to max of 256"));
 	}
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 2c2c384..c235d32 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -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.48"
+#define CIFS_VERSION   "1.49"
 #endif				/* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e4de8eb..23655de 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -311,7 +311,7 @@ struct cifsFileInfo {
 	/* lock scope id (0 if none) */
 	struct file * pfile; /* needed for writepage */
 	struct inode * pInode; /* needed for oplock break */
-	struct semaphore lock_sem;
+	struct mutex lock_mutex;
 	struct list_head llist; /* list of byte range locks we have. */
 	unsigned closePend:1;	/* file is marked to close */
 	unsigned invalidHandle:1;  /* file closed via session abend */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 4d8948e..d619ca7 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1388,7 +1388,7 @@ #define SMB_SET_ATTR_FLAGS              
 #define SMB_SET_POSIX_LOCK              0x208
 #define SMB_POSIX_OPEN                  0x209
 #define SMB_POSIX_UNLINK                0x20a
-#define SMB_SET_FILE_UNIX_INFO2
+#define SMB_SET_FILE_UNIX_INFO2         0x20b
 #define SMB_SET_FILE_BASIC_INFO2        0x3ec
 #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
 #define SMB_FILE_ALL_INFO2              0x3fa
@@ -2109,22 +2109,40 @@ #define CIFS_POSIX_ACL_READ	     0x04 */
 
 /* end of POSIX ACL definitions */
 
+/* POSIX Open Flags */
+#define SMB_O_RDONLY 	 0x1
+#define SMB_O_WRONLY 	0x2
+#define SMB_O_RDWR 	0x4
+#define SMB_O_CREAT 	0x10
+#define SMB_O_EXCL 	0x20
+#define SMB_O_TRUNC 	0x40
+#define SMB_O_APPEND 	0x80
+#define SMB_O_SYNC 	0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 	0x400
+#define SMB_O_DIRECT 	0x800
+
 typedef struct {
-	__u32 OpenFlags; /* same as NT CreateX */
-	__u32 PosixOpenFlags;
-	__u32 Mode;
-	__u16 Level; /* reply level requested (see QPathInfo levels) */
-	__u16 Pad;  /* reserved - MBZ */
+	__le32 OpenFlags; /* same as NT CreateX */
+	__le32 PosixOpenFlags;
+	__le64 Permissions;
+	__le16 Level; /* reply level requested (see QPathInfo levels) */
 } __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
 
 typedef struct {
-	/* reply varies based on requested level */
+	__le16 OplockFlags;
+	__u16 Fid;
+	__le32 CreateAction;
+	__le16 ReturnedLevel;
+	__le16 Pad;
+	/* struct following varies based on requested level */
 } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
 
 
 struct file_internal_info {
 	__u64  UniqueId; /* inode number */
 } __attribute__((packed));      /* level 0x3ee */
+
 struct file_mode_info {
 	__le32	Mode;
 } __attribute__((packed));      /* level 0x3f8 */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 32eb1ac..5d163e2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifsproto.h
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2006
+ *   Copyright (c) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -244,6 +244,11 @@ extern int SMBLegacyOpen(const int xid, 
 			const int access_flags, const int omode,
 			__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
 			const struct nls_table *nls_codepage, int remap);
+extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, 
+			u32 posix_flags, __u64 mode, __u16 * netfid,
+			FILE_UNIX_BASIC_INFO *pRetData,
+			__u32 *pOplock, const char *name,
+			const struct nls_table *nls_codepage, int remap);			
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
 			const int smb_file_id);
 
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 48fc0c2..14de58f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/cifssmb.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2006
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   Contains the routines for constructing the SMB PDUs themselves
@@ -24,8 +24,8 @@
  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
  /* These are mostly routines that operate on a pathname, or on a tree id     */
  /* (mounted volume), but there are eight handle based routines which must be */
- /* treated slightly different for reconnection purposes since we never want  */
- /* to reuse a stale file handle and the caller knows the file handle */
+ /* treated slightly differently for reconnection purposes since we never     */
+ /* want to reuse a stale file handle and only the caller knows the file info */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -913,6 +913,130 @@ MkDirRetry:
 	return rc;
 }
 
+int
+CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
+		__u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
+		__u32 *pOplock, const char *name, 
+		const struct nls_table *nls_codepage, int remap)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	char *data_offset;
+	__u16 params, param_offset, offset, byte_count, count;
+	OPEN_PSX_REQ * pdata;
+	OPEN_PSX_RSP * psx_rsp;
+
+	cFYI(1, ("In POSIX Create"));
+PsxCreat:
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifsConvertToUCS((__le16 *) pSMB->FileName, name,
+				     PATH_MAX, nls_codepage, remap);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {	/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(name, PATH_MAX);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, name, name_len);
+	}
+
+	params = 6 + name_len;
+	count = sizeof(OPEN_PSX_REQ);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* large enough */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	param_offset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+	offset = param_offset + params;
+	data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+	pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
+	pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
+	pdata->Permissions = cpu_to_le64(mode);
+	pdata->PosixOpenFlags = cpu_to_le32(posix_flags); 
+	pdata->OpenFlags =  cpu_to_le32(*pOplock);
+	pSMB->ParameterOffset = cpu_to_le16(param_offset);
+	pSMB->DataOffset = cpu_to_le16(offset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	byte_count = 3 /* pad */  + params + count;
+
+	pSMB->DataCount = cpu_to_le16(count);
+	pSMB->ParameterCount = cpu_to_le16(params);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += byte_count; 
+	pSMB->ByteCount = cpu_to_le16(byte_count);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Posix create returned %d", rc));
+		goto psx_create_err;
+	}
+
+	cFYI(1,("copying inode info"));
+	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+	if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
+		rc = -EIO;	/* bad smb */
+		goto psx_create_err;
+	}
+
+	/* copy return information to pRetData */
+	psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol 
+			+ le16_to_cpu(pSMBr->t2.DataOffset));
+		
+	*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
+	if(netfid)
+		*netfid = psx_rsp->Fid;   /* cifs fid stays in le */
+	/* Let caller know file was created so we can set the mode. */
+	/* Do we care about the CreateAction in any other cases? */
+	if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
+		*pOplock |= CIFS_CREATE_ACTION;
+	/* check to make sure response data is there */
+	if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
+		pRetData->Type = -1; /* unknown */
+#ifdef CONFIG_CIFS_DEBUG2
+		cFYI(1,("unknown type"));
+#endif
+	} else {
+		if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) 
+					+ sizeof(FILE_UNIX_BASIC_INFO)) {
+			cERROR(1,("Open response data too small"));
+			pRetData->Type = -1;
+			goto psx_create_err;
+		}
+		memcpy((char *) pRetData, 
+			(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
+			sizeof (FILE_UNIX_BASIC_INFO));
+	}
+			
+
+psx_create_err:
+	cifs_buf_release(pSMB);
+
+	cifs_stats_inc(&tcon->num_mkdirs);
+
+	if (rc == -EAGAIN)
+		goto PsxCreat;
+
+	return rc;	
+}
+
 static __u16 convert_disposition(int disposition)
 {
 	__u16 ofun = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 20ba7dc..216fb62 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -30,6 +30,7 @@ #include <linux/utsname.h>
 #include <linux/mempool.h>
 #include <linux/delay.h>
 #include <linux/completion.h>
+#include <linux/kthread.h>
 #include <linux/pagevec.h>
 #include <linux/freezer.h>
 #include <asm/uaccess.h>
@@ -74,6 +75,8 @@ struct smb_vol {
 	unsigned retry:1;
 	unsigned intr:1;
 	unsigned setuids:1;
+	unsigned override_uid:1;
+	unsigned override_gid:1;
 	unsigned noperm:1;
 	unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
 	unsigned cifs_acl:1;
@@ -120,7 +123,7 @@ cifs_reconnect(struct TCP_Server_Info *s
 	struct mid_q_entry * mid_entry;
 	
 	spin_lock(&GlobalMid_Lock);
-	if(server->tcpStatus == CifsExiting) {
+	if( kthread_should_stop() ) {
 		/* the demux thread will exit normally 
 		next time through the loop */
 		spin_unlock(&GlobalMid_Lock);
@@ -182,7 +185,7 @@ cifs_reconnect(struct TCP_Server_Info *s
 	spin_unlock(&GlobalMid_Lock);
 	up(&server->tcpSem); 
 
-	while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
+	while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood))
 	{
 		try_to_freeze();
 		if(server->protocolType == IPV6) {
@@ -199,7 +202,7 @@ cifs_reconnect(struct TCP_Server_Info *s
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
 			spin_lock(&GlobalMid_Lock);
-			if(server->tcpStatus != CifsExiting)
+			if( !kthread_should_stop() )
 				server->tcpStatus = CifsGood;
 			server->sequence_number = 0;
 			spin_unlock(&GlobalMid_Lock);			
@@ -345,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Serve
 	int isMultiRsp;
 	int reconnect;
 
-	daemonize("cifsd");
 	allow_signal(SIGKILL);
 	current->flags |= PF_MEMALLOC;
 	server->tsk = current;	/* save process info to wake at shutdown */
@@ -361,7 +363,7 @@ cifs_demultiplex_thread(struct TCP_Serve
 			GFP_KERNEL);
 	}
 
-	while (server->tcpStatus != CifsExiting) {
+	while (!kthread_should_stop()) {
 		if (try_to_freeze())
 			continue;
 		if (bigbuf == NULL) {
@@ -400,7 +402,7 @@ cifs_demultiplex_thread(struct TCP_Serve
 		    kernel_recvmsg(csocket, &smb_msg,
 				 &iov, 1, 4, 0 /* BB see socket.h flags */);
 
-		if (server->tcpStatus == CifsExiting) {
+		if ( kthread_should_stop() ) {
 			break;
 		} else if (server->tcpStatus == CifsNeedReconnect) {
 			cFYI(1, ("Reconnect after server stopped responding"));
@@ -524,7 +526,7 @@ cifs_demultiplex_thread(struct TCP_Serve
 		     total_read += length) {
 			length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
 						pdu_length - total_read, 0);
-			if((server->tcpStatus == CifsExiting) ||
+			if( kthread_should_stop() ||
 			    (length == -EINTR)) {
 				/* then will exit */
 				reconnect = 2;
@@ -757,7 +759,6 @@ #endif /* CIFS_DEBUG2 */
 			GFP_KERNEL);
 	}
 	
-	complete_and_exit(&cifsd_complete, 0);
 	return 0;
 }
 
@@ -973,7 +974,7 @@ #endif
 			}
 			if ((temp_len = strnlen(value, 300)) < 300) {
 				vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
-				if(vol->UNC == NULL)
+				if (vol->UNC == NULL)
 					return 1;
 				strcpy(vol->UNC,value);
 				if (strncmp(vol->UNC, "//", 2) == 0) {
@@ -1010,12 +1011,12 @@ #endif
                                 return 1;       /* needs_arg; */
                         }
                         if ((temp_len = strnlen(value, 1024)) < 1024) {
-				if(value[0] != '/')
+				if (value[0] != '/')
 					temp_len++;  /* missing leading slash */
                                 vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
-                                if(vol->prepath == NULL)
+                                if (vol->prepath == NULL)
                                         return 1;
-				if(value[0] != '/') {
+				if (value[0] != '/') {
 					vol->prepath[0] = '/';
 	                                strcpy(vol->prepath+1,value);
 				} else
@@ -1031,7 +1032,7 @@ #endif
 				return 1;	/* needs_arg; */
 			}
 			if (strnlen(value, 65) < 65) {
-				if(strnicmp(value,"default",7))
+				if (strnicmp(value,"default",7))
 					vol->iocharset = value;
 				/* if iocharset not set load_nls_default used by caller */
 				cFYI(1, ("iocharset set to %s",value));
@@ -1043,11 +1044,13 @@ #endif
 			if (value && *value) {
 				vol->linux_uid =
 					simple_strtoul(value, &value, 0);
+				vol->override_uid = 1;
 			}
 		} else if (strnicmp(data, "gid", 3) == 0) {
 			if (value && *value) {
 				vol->linux_gid =
 					simple_strtoul(value, &value, 0);
+				vol->override_gid = 1;
 			}
 		} else if (strnicmp(data, "file_mode", 4) == 0) {
 			if (value && *value) {
@@ -1102,7 +1105,7 @@ #endif
 				}
 				/* The string has 16th byte zero still from
 				set at top of the function  */
-				if((i==15) && (value[i] != 0))
+				if ((i==15) && (value[i] != 0))
 					printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
 			}
 		} else if (strnicmp(data, "servern", 7) == 0) {
@@ -1126,7 +1129,7 @@ #endif
 				}
 				/* The string has 16th byte zero still from
 				   set at top of the function  */
-				if((i==15) && (value[i] != 0))
+				if ((i==15) && (value[i] != 0))
 					printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
 			}
 		} else if (strnicmp(data, "credentials", 4) == 0) {
@@ -1233,13 +1236,13 @@ #endif
 			printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
 	}
 	if (vol->UNC == NULL) {
-		if(devname == NULL) {
+		if (devname == NULL) {
 			printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
 			return 1;
 		}
 		if ((temp_len = strnlen(devname, 300)) < 300) {
 			vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
-			if(vol->UNC == NULL)
+			if (vol->UNC == NULL)
 				return 1;
 			strcpy(vol->UNC,devname);
 			if (strncmp(vol->UNC, "//", 2) == 0) {
@@ -1663,7 +1666,13 @@ void reset_cifs_unix_caps(int xid, struc
 				CIFS_SB(sb)->mnt_cifs_flags |= 
 					CIFS_MOUNT_POSIX_PATHS;
 		}
-			
+	
+		/* We might be setting the path sep back to a different
+		form if we are reconnecting and the server switched its
+		posix path capability for this share */	
+		if(sb && (CIFS_SB(sb)->prepathlen > 0))
+			CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
+	
 		cFYI(1,("Negotiate caps 0x%x",(int)cap));
 #ifdef CONFIG_CIFS_DEBUG2
 		if(cap & CIFS_UNIX_FCNTL_CAP)
@@ -1712,12 +1721,12 @@ cifs_mount(struct super_block *sb, struc
 		return -EINVAL;
 	}
 
-	if (volume_info.username) {
+	if (volume_info.nullauth) {
+		cFYI(1,("null user"));
+		volume_info.username = NULL;
+	} else if (volume_info.username) {
 		/* 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
@@ -1791,11 +1800,12 @@ cifs_mount(struct super_block *sb, struc
 		existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
 			NULL /* no ipv6 addr */,
 			volume_info.username, &srvTcp);
-	else if(address_type == AF_INET6)
+	else if(address_type == AF_INET6) {
+		cFYI(1,("looking for ipv6 address"));
 		existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
 			&sin_server6.sin6_addr,
 			volume_info.username, &srvTcp);
-	else {
+	} else {
 		kfree(volume_info.UNC);
 		kfree(volume_info.password);
 		kfree(volume_info.prepath);
@@ -1807,17 +1817,23 @@ cifs_mount(struct super_block *sb, struc
 	if (srvTcp) {
 		cFYI(1, ("Existing tcp session with server found"));                
 	} else {	/* create socket */
-		if(volume_info.port)
+		if (volume_info.port)
 			sin_server.sin_port = htons(volume_info.port);
 		else
 			sin_server.sin_port = 0;
-		rc = ipv4_connect(&sin_server,&csocket,
+		if (address_type == AF_INET6) {
+			cFYI(1,("attempting ipv6 connect"));
+			/* BB should we allow ipv6 on port 139? */
+			/* other OS never observed in Wild doing 139 with v6 */
+			rc = ipv6_connect(&sin_server6,&csocket);
+		} else 
+			rc = ipv4_connect(&sin_server,&csocket,
 				  volume_info.source_rfc1001_name,
 				  volume_info.target_rfc1001_name);
 		if (rc < 0) {
 			cERROR(1,
-			       ("Error connecting to IPv4 socket. Aborting operation"));
-			if(csocket != NULL)
+			       ("Error connecting to IPv4 socket. Aborting operation"));			       
+			if (csocket != NULL)
 				sock_release(csocket);
 			kfree(volume_info.UNC);
 			kfree(volume_info.password);
@@ -1850,10 +1866,11 @@ cifs_mount(struct super_block *sb, struc
 			so no need to spinlock this init of tcpStatus */
 			srvTcp->tcpStatus = CifsNew;
 			init_MUTEX(&srvTcp->tcpSem);
-			rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
-				      CLONE_FS | CLONE_FILES | CLONE_VM);
-			if(rc < 0) {
-				rc = -ENOMEM;
+			srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
+			if ( IS_ERR(srvTcp->tsk) ) {
+				rc = PTR_ERR(srvTcp->tsk);
+				cERROR(1,("error %d create cifsd thread", rc));
+				srvTcp->tsk = NULL;
 				sock_release(csocket);
 				kfree(volume_info.UNC);
 				kfree(volume_info.password);
@@ -1896,7 +1913,7 @@ cifs_mount(struct super_block *sb, struc
 				int len = strlen(volume_info.domainname);
 				pSesInfo->domainName = 
 					kmalloc(len + 1, GFP_KERNEL);
-				if(pSesInfo->domainName)
+				if (pSesInfo->domainName)
 					strcpy(pSesInfo->domainName,
 						volume_info.domainname);
 			}
@@ -1906,7 +1923,7 @@ cifs_mount(struct super_block *sb, struc
 			/* BB FIXME need to pass vol->secFlgs BB */
 			rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
 			up(&pSesInfo->sesSem);
-			if(!rc)
+			if (!rc)
 				atomic_inc(&srvTcp->socketUseCount);
 		} else
 			kfree(volume_info.password);
@@ -1914,7 +1931,7 @@ cifs_mount(struct super_block *sb, struc
     
 	/* search for existing tcon to this server share */
 	if (!rc) {
-		if(volume_info.rsize > CIFSMaxBufSize) {
+		if (volume_info.rsize > CIFSMaxBufSize) {
 			cERROR(1,("rsize %d too large, using MaxBufSize",
 				volume_info.rsize));
 			cifs_sb->rsize = CIFSMaxBufSize;
@@ -1923,11 +1940,11 @@ cifs_mount(struct super_block *sb, struc
 		else /* default */
 			cifs_sb->rsize = CIFSMaxBufSize;
 
-		if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+		if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
 			cERROR(1,("wsize %d too large using 4096 instead",
 				  volume_info.wsize));
 			cifs_sb->wsize = 4096;
-		} else if(volume_info.wsize)
+		} else if (volume_info.wsize)
 			cifs_sb->wsize = volume_info.wsize;
 		else
 			cifs_sb->wsize = 
@@ -1940,14 +1957,14 @@ cifs_mount(struct super_block *sb, struc
 			   conjunction with 52K kvec constraint on arch with 4K
 			   page size  */
 
-		if(cifs_sb->rsize < 2048) {
+		if (cifs_sb->rsize < 2048) {
 			cifs_sb->rsize = 2048; 
 			/* Windows ME may prefer this */
 			cFYI(1,("readsize set to minimum 2048"));
 		}
 		/* calculate prepath */
 		cifs_sb->prepath = volume_info.prepath;
-		if(cifs_sb->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;
@@ -1960,24 +1977,27 @@ cifs_mount(struct super_block *sb, struc
 		cFYI(1,("file mode: 0x%x  dir mode: 0x%x",
 			cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
 
-		if(volume_info.noperm)
+		if (volume_info.noperm)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
-		if(volume_info.setuids)
+		if (volume_info.setuids)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
-		if(volume_info.server_ino)
+		if (volume_info.server_ino)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
-		if(volume_info.remap)
+		if (volume_info.remap)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
-		if(volume_info.no_xattr)
+		if (volume_info.no_xattr)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
-		if(volume_info.sfu_emul)
+		if (volume_info.sfu_emul)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
-		if(volume_info.nobrl)
+		if (volume_info.nobrl)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
-		if(volume_info.cifs_acl)
+		if (volume_info.cifs_acl)
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
-
-		if(volume_info.direct_io) {
+		if (volume_info.override_uid)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+		if (volume_info.override_gid)
+			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+		if (volume_info.direct_io) {
 			cFYI(1,("mounting share using direct i/o"));
 			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
 		}
@@ -2030,7 +2050,7 @@ cifs_mount(struct super_block *sb, struc
 			}
 		}
 	}
-	if(pSesInfo) {
+	if (pSesInfo) {
 		if (pSesInfo->capabilities & CAP_LARGE_FILES) {
 			sb->s_maxbytes = (u64) 1 << 63;
 		} else
@@ -2044,13 +2064,13 @@ cifs_mount(struct super_block *sb, struc
 	if (rc) {
 		/* if session setup failed, use count is zero but
 		we still need to free cifsd thread */
-		if(atomic_read(&srvTcp->socketUseCount) == 0) {
+		if (atomic_read(&srvTcp->socketUseCount) == 0) {
 			spin_lock(&GlobalMid_Lock);
 			srvTcp->tcpStatus = CifsExiting;
 			spin_unlock(&GlobalMid_Lock);
-			if(srvTcp->tsk) {
+			if (srvTcp->tsk) {
 				send_sig(SIGKILL,srvTcp->tsk,1);
-				wait_for_completion(&cifsd_complete);
+				kthread_stop(srvTcp->tsk);
 			}
 		}
 		 /* If find_unc succeeded then rc == 0 so we can not end */
@@ -2063,10 +2083,10 @@ cifs_mount(struct super_block *sb, struc
 					int temp_rc;
 					temp_rc = CIFSSMBLogoff(xid, pSesInfo);
 					/* if the socketUseCount is now zero */
-					if((temp_rc == -ESHUTDOWN) &&
-					   (pSesInfo->server->tsk)) {
+					if ((temp_rc == -ESHUTDOWN) &&
+					   (pSesInfo->server) && (pSesInfo->server->tsk)) {
 						send_sig(SIGKILL,pSesInfo->server->tsk,1);
-						wait_for_completion(&cifsd_complete);
+						kthread_stop(pSesInfo->server->tsk);
 					}
 				} else
 					cFYI(1, ("No session or bad tcon"));
@@ -2127,7 +2147,7 @@ CIFSSessSetup(unsigned int xid, struct c
 	__u16 count;
 
 	cFYI(1, ("In sesssetup"));
-	if(ses == NULL)
+	if (ses == NULL)
 		return -EINVAL;
 	user = ses->userName;
 	domain = ses->domainName;
@@ -2182,7 +2202,7 @@ CIFSSessSetup(unsigned int xid, struct c
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
-		if(user == NULL)
+		if (user == NULL)
 			bytes_returned = 0; /* skip null user */
 	        else
 			bytes_returned =
@@ -2216,7 +2236,7 @@ CIFSSessSetup(unsigned int xid, struct c
 		bcc_ptr += 2 * bytes_returned;
 		bcc_ptr += 2;
 	} else {
-		if(user != NULL) {                
+		if (user != NULL) {                
 		    strncpy(bcc_ptr, user, 200);
 		    bcc_ptr += strnlen(user, 200);
 		}
@@ -3316,7 +3336,7 @@ cifs_umount(struct super_block *sb, stru
 				cFYI(1,("Waking up socket by sending it signal"));
 				if(cifsd_task) {
 					send_sig(SIGKILL,cifsd_task,1);
-					wait_for_completion(&cifsd_complete);
+					kthread_stop(cifsd_task);
 				}
 				rc = 0;
 			} /* else - we have an smb session
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3fad638..e521051 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -274,7 +274,7 @@ cifs_create(struct inode *inode, struct 
 			pCifsFile->invalidHandle = FALSE;
 			pCifsFile->closePend     = FALSE;
 			init_MUTEX(&pCifsFile->fh_sem);
-			init_MUTEX(&pCifsFile->lock_sem);
+			mutex_init(&pCifsFile->lock_mutex);
 			INIT_LIST_HEAD(&pCifsFile->llist);
 			atomic_set(&pCifsFile->wrtPending,0);
 
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2d3275b..94d5b49 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -27,7 +27,6 @@ #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
-#include <linux/smp_lock.h>
 #include <linux/writeback.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/delay.h>
@@ -48,7 +47,7 @@ static inline struct cifsFileInfo *cifs_
 	private_data->netfid = netfid;
 	private_data->pid = current->tgid;	
 	init_MUTEX(&private_data->fh_sem);
-	init_MUTEX(&private_data->lock_sem);
+	mutex_init(&private_data->lock_mutex);
 	INIT_LIST_HEAD(&private_data->llist);
 	private_data->pfile = file; /* needed for writepage */
 	private_data->pInode = inode;
@@ -338,8 +337,7 @@ static int cifs_relock_file(struct cifsF
 	return rc;
 }
 
-static int cifs_reopen_file(struct inode *inode, struct file *file, 
-	int can_flush)
+static int cifs_reopen_file(struct file *file, int can_flush)
 {
 	int rc = -EACCES;
 	int xid, oplock;
@@ -347,13 +345,12 @@ static int cifs_reopen_file(struct inode
 	struct cifsTconInfo *pTcon;
 	struct cifsFileInfo *pCifsFile;
 	struct cifsInodeInfo *pCifsInode;
+	struct inode * inode;
 	char *full_path = NULL;
 	int desiredAccess;
 	int disposition = FILE_OPEN;
 	__u16 netfid;
 
-	if (inode == NULL)
-		return -EBADF;
 	if (file->private_data) {
 		pCifsFile = (struct cifsFileInfo *)file->private_data;
 	} else
@@ -368,25 +365,37 @@ static int cifs_reopen_file(struct inode
 	}
 
 	if (file->f_path.dentry == NULL) {
-		up(&pCifsFile->fh_sem);
-		cFYI(1, ("failed file reopen, no valid name if dentry freed"));
-		FreeXid(xid);
-		return -EBADF;
+		cERROR(1, ("no valid name if dentry freed"));
+		dump_stack();
+		rc = -EBADF;
+		goto reopen_error_exit;
 	}
+
+	inode = file->f_path.dentry->d_inode;
+	if(inode == NULL) {
+		cERROR(1, ("inode not valid"));
+		dump_stack();
+		rc = -EBADF;
+		goto reopen_error_exit;
+	}
+		
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
+
 /* can not grab rename sem here because various ops, including
    those that already have the rename sem can end up causing writepage
    to get called and if the server was down that means we end up here,
    and we can never tell if the caller already has the rename_sem */
 	full_path = build_path_from_dentry(file->f_path.dentry);
 	if (full_path == NULL) {
+		rc = -ENOMEM;
+reopen_error_exit:
 		up(&pCifsFile->fh_sem);
 		FreeXid(xid);
-		return -ENOMEM;
+		return rc;
 	}
 
-	cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+	cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
 		 inode, file->f_flags,full_path));
 	desiredAccess = cifs_convert_flags(file->f_flags);
 
@@ -401,13 +410,6 @@ static int cifs_reopen_file(struct inode
 	   and server version of file size can be stale. If we knew for sure
 	   that inode was not dirty locally we could do this */
 
-/*	buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-	if (buf == 0) {
-		up(&pCifsFile->fh_sem);
-		kfree(full_path);
-		FreeXid(xid);
-		return -ENOMEM;
-	} */
 	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
 			 CREATE_NOT_DIR, &netfid, &oplock, NULL,
 			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
@@ -508,12 +510,12 @@ #endif /* DEBUG2 */
 
 		/* Delete any outstanding lock records.
 		   We'll lose them when the file is closed anyway. */
-		down(&pSMBFile->lock_sem);
+		mutex_lock(&pSMBFile->lock_mutex);
 		list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
 			list_del(&li->llist);
 			kfree(li);
 		}
-		up(&pSMBFile->lock_sem);
+		mutex_unlock(&pSMBFile->lock_mutex);
 
 		write_lock(&GlobalSMBSeslock);
 		list_del(&pSMBFile->flist);
@@ -598,9 +600,9 @@ static int store_file_lock(struct cifsFi
 	li->offset = offset;
 	li->length = len;
 	li->type = lockType;
-	down(&fid->lock_sem);
+	mutex_lock(&fid->lock_mutex);
 	list_add(&li->llist, &fid->llist);
-	up(&fid->lock_sem);
+	mutex_unlock(&fid->lock_mutex);
 	return 0;
 }
 
@@ -757,7 +759,7 @@ int cifs_lock(struct file *file, int cmd
 			struct cifsLockInfo *li, *tmp;
 
 			rc = 0;
-			down(&fid->lock_sem);
+			mutex_lock(&fid->lock_mutex);
 			list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
 				if (pfLock->fl_start <= li->offset &&
 						length >= li->length) {
@@ -771,7 +773,7 @@ int cifs_lock(struct file *file, int cmd
 					kfree(li);
 				}
 			}
-			up(&fid->lock_sem);
+			mutex_unlock(&fid->lock_mutex);
 		}
 	}
 
@@ -792,12 +794,7 @@ ssize_t cifs_user_write(struct file *fil
 	int xid, long_op;
 	struct cifsFileInfo *open_file;
 
-	if (file->f_path.dentry == NULL)
-		return -EBADF;
-
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	if (cifs_sb == NULL)
-		return -EBADF;
 
 	pTcon = cifs_sb->tcon;
 
@@ -807,14 +804,9 @@ ssize_t cifs_user_write(struct file *fil
 
 	if (file->private_data == NULL)
 		return -EBADF;
-	else
-		open_file = (struct cifsFileInfo *) file->private_data;
+	open_file = (struct cifsFileInfo *) file->private_data;
 	
 	xid = GetXid();
-	if (file->f_path.dentry->d_inode == NULL) {
-		FreeXid(xid);
-		return -EBADF;
-	}
 
 	if (*poffset > file->f_path.dentry->d_inode->i_size)
 		long_op = 2; /* writes past end of file can take a long time */
@@ -841,17 +833,11 @@ ssize_t cifs_user_write(struct file *fil
 					return -EBADF;
 			}
 			if (open_file->invalidHandle) {
-				if ((file->f_path.dentry == NULL) ||
-				    (file->f_path.dentry->d_inode == NULL)) {
-					FreeXid(xid);
-					return total_written;
-				}
 				/* we could deadlock if we called
 				   filemap_fdatawait from here so tell
 				   reopen_file not to flush data to server
 				   now */
-				rc = cifs_reopen_file(file->f_path.dentry->d_inode,
-					file, FALSE);
+				rc = cifs_reopen_file(file, FALSE);
 				if (rc != 0)
 					break;
 			}
@@ -908,12 +894,7 @@ static ssize_t cifs_write(struct file *f
 	int xid, long_op;
 	struct cifsFileInfo *open_file;
 
-	if (file->f_path.dentry == NULL)
-		return -EBADF;
-
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	if (cifs_sb == NULL)
-		return -EBADF;
 
 	pTcon = cifs_sb->tcon;
 
@@ -922,14 +903,9 @@ static ssize_t cifs_write(struct file *f
 
 	if (file->private_data == NULL)
 		return -EBADF;
-	else
-		open_file = (struct cifsFileInfo *)file->private_data;
+	open_file = (struct cifsFileInfo *)file->private_data;
 	
 	xid = GetXid();
-	if (file->f_path.dentry->d_inode == NULL) {
-		FreeXid(xid);
-		return -EBADF;
-	}
 
 	if (*poffset > file->f_path.dentry->d_inode->i_size)
 		long_op = 2; /* writes past end of file can take a long time */
@@ -957,17 +933,11 @@ static ssize_t cifs_write(struct file *f
 					return -EBADF;
 			}
 			if (open_file->invalidHandle) {
-				if ((file->f_path.dentry == NULL) ||
-				   (file->f_path.dentry->d_inode == NULL)) {
-					FreeXid(xid);
-					return total_written;
-				}
 				/* we could deadlock if we called
 				   filemap_fdatawait from here so tell
 				   reopen_file not to flush data to 
 				   server now */
-				rc = cifs_reopen_file(file->f_path.dentry->d_inode,
-					file, FALSE);
+				rc = cifs_reopen_file(file, FALSE);
 				if (rc != 0)
 					break;
 			}
@@ -1056,8 +1026,7 @@ struct cifsFileInfo *find_writable_file(
 			read_unlock(&GlobalSMBSeslock);
 			if((open_file->invalidHandle) && 
 			   (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
-				rc = cifs_reopen_file(&cifs_inode->vfs_inode, 
-						      open_file->pfile, FALSE);
+				rc = cifs_reopen_file(open_file->pfile, FALSE);
 				/* if it fails, try another handle - might be */
 				/* dangerous to hold up writepages with retry */
 				if(rc) {
@@ -1404,32 +1373,6 @@ static int cifs_commit_write(struct file
 	spin_lock(&inode->i_lock);
 	if (position > inode->i_size) {
 		i_size_write(inode, position);
-		/* if (file->private_data == NULL) {
-			rc = -EBADF;
-		} else {
-			open_file = (struct cifsFileInfo *)file->private_data;
-			cifs_sb = CIFS_SB(inode->i_sb);
-			rc = -EAGAIN;
-			while (rc == -EAGAIN) {
-				if ((open_file->invalidHandle) && 
-				    (!open_file->closePend)) {
-					rc = cifs_reopen_file(
-						file->f_path.dentry->d_inode, file);
-					if (rc != 0)
-						break;
-				}
-				if (!open_file->closePend) {
-					rc = CIFSSMBSetFileSize(xid,
-						cifs_sb->tcon, position,
-						open_file->netfid,
-						open_file->pid, FALSE);
-				} else {
-					rc = -EBADF;
-					break;
-				}
-			}
-			cFYI(1, (" SetEOF (commit write) rc = %d", rc));
-		} */
 	}
 	spin_unlock(&inode->i_lock);
 	if (!PageUptodate(page)) {
@@ -1573,8 +1516,7 @@ ssize_t cifs_user_read(struct file *file
 			int buf_type = CIFS_NO_BUFFER;
 			if ((open_file->invalidHandle) && 
 			    (!open_file->closePend)) {
-				rc = cifs_reopen_file(file->f_path.dentry->d_inode,
-					file, TRUE);
+				rc = cifs_reopen_file(file, TRUE);
 				if (rc != 0)
 					break;
 			}
@@ -1660,8 +1602,7 @@ static ssize_t cifs_read(struct file *fi
 		while (rc == -EAGAIN) {
 			if ((open_file->invalidHandle) && 
 			    (!open_file->closePend)) {
-				rc = cifs_reopen_file(file->f_path.dentry->d_inode,
-					file, TRUE);
+				rc = cifs_reopen_file(file, TRUE);
 				if (rc != 0)
 					break;
 			}
@@ -1817,8 +1758,7 @@ static int cifs_readpages(struct file *f
 		while (rc == -EAGAIN) {
 			if ((open_file->invalidHandle) && 
 			    (!open_file->closePend)) {
-				rc = cifs_reopen_file(file->f_path.dentry->d_inode,
-					file, TRUE);
+				rc = cifs_reopen_file(file, TRUE);
 				if (rc != 0)
 					break;
 			}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f414526..3e87dad 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/inode.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2005
+ *   Copyright (C) International Business Machines  Corp., 2002,2007
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -90,7 +90,7 @@ int cifs_get_inode_info_unix(struct inod
 				(*pinode)->i_ino =
 					(unsigned long)findData.UniqueId;
 			} /* note ino incremented to unique num in new_inode */
-			if(sb->s_flags & MS_NOATIME)
+			if (sb->s_flags & MS_NOATIME)
 				(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
 				
 			insert_inode_hash(*pinode);
@@ -139,8 +139,17 @@ int cifs_get_inode_info_unix(struct inod
 			inode->i_mode |= S_IFREG;
 			cFYI(1,("unknown type %d",type));
 		}
-		inode->i_uid = le64_to_cpu(findData.Uid);
-		inode->i_gid = le64_to_cpu(findData.Gid);
+		
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+			inode->i_uid = cifs_sb->mnt_uid;
+		else
+			inode->i_uid = le64_to_cpu(findData.Uid);
+
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+			inode->i_gid = cifs_sb->mnt_gid;
+		else
+			inode->i_gid = le64_to_cpu(findData.Gid);
+			
 		inode->i_nlink = le64_to_cpu(findData.Nlinks);
 
 		spin_lock(&inode->i_lock);
@@ -178,13 +187,13 @@ int cifs_get_inode_info_unix(struct inod
 						&cifs_file_direct_nobrl_ops;
 				else
 					inode->i_fop = &cifs_file_direct_ops;
-			} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				inode->i_fop = &cifs_file_nobrl_ops;
 			else /* not direct, send byte range locks */ 
 				inode->i_fop = &cifs_file_ops;
 
 			/* check if server can support readpages */
-			if(pTcon->ses->server->maxBuf < 
+			if (pTcon->ses->server->maxBuf < 
 			    PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
 				inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 			else
@@ -220,7 +229,7 @@ static int decode_sfu_inode(struct inode
 
 	pbuf = buf;
 
-	if(size == 0) {
+	if (size == 0) {
 		inode->i_mode |= S_IFIFO;
 		return 0;
 	} else if (size < 8) {
@@ -239,11 +248,11 @@ static int decode_sfu_inode(struct inode
 			         netfid,
 				 24 /* length */, 0 /* offset */,
 				 &bytes_read, &pbuf, &buf_type);
-		if((rc == 0) && (bytes_read >= 8)) {
-			if(memcmp("IntxBLK", pbuf, 8) == 0) {
+		if ((rc == 0) && (bytes_read >= 8)) {
+			if (memcmp("IntxBLK", pbuf, 8) == 0) {
 				cFYI(1,("Block device"));
 				inode->i_mode |= S_IFBLK;
-				if(bytes_read == 24) {
+				if (bytes_read == 24) {
 					/* we have enough to decode dev num */
 					__u64 mjr; /* major */
 					__u64 mnr; /* minor */
@@ -251,10 +260,10 @@ static int decode_sfu_inode(struct inode
 					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
 					inode->i_rdev = MKDEV(mjr, mnr);
 				}
-			} else if(memcmp("IntxCHR", pbuf, 8) == 0) {
+			} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
 				cFYI(1,("Char device"));
 				inode->i_mode |= S_IFCHR;
-				if(bytes_read == 24) {
+				if (bytes_read == 24) {
 					/* we have enough to decode dev num */
 					__u64 mjr; /* major */
 					__u64 mnr; /* minor */
@@ -262,7 +271,7 @@ static int decode_sfu_inode(struct inode
 					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
 					inode->i_rdev = MKDEV(mjr, mnr);
                                 }
-			} else if(memcmp("IntxLNK", pbuf, 7) == 0) {
+			} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
 				cFYI(1,("Symlink"));
 				inode->i_mode |= S_IFLNK;
 			} else {
@@ -293,7 +302,7 @@ #ifdef CONFIG_CIFS_XATTR
 	rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
 			ea_value, 4 /* size of buf */, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-	if(rc < 0)
+	if (rc < 0)
 		return (int)rc;
 	else if (rc > 3) {
 		mode = le32_to_cpu(*((__le32 *)ea_value));
@@ -348,7 +357,7 @@ int cifs_get_inode_info(struct inode **p
 		/* BB optimize code so we do not make the above call
 		when server claims no NT SMB support and the above call
 		failed at least once - set flag in tcon or mount */
-		if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+		if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
 			rc = SMBQueryInformation(xid, pTcon, search_path,
 					pfindData, cifs_sb->local_nls, 
 					cifs_sb->mnt_cifs_flags &
@@ -425,7 +434,7 @@ int cifs_get_inode_info(struct inode **p
 				} else /* do we need cast or hash to ino? */
 					(*pinode)->i_ino = inode_num;
 			} /* else ino incremented to unique num in new_inode*/
-			if(sb->s_flags & MS_NOATIME)
+			if (sb->s_flags & MS_NOATIME)
 				(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
 			insert_inode_hash(*pinode);
 		}
@@ -442,7 +451,7 @@ 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 */
-		if(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 */
@@ -452,7 +461,7 @@ int cifs_get_inode_info(struct inode **p
 		inode->i_ctime =
 		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
 		cFYI(0, ("Attributes came in as 0x%x", attr));
-		if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
+		if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
 			inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
 	                inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
 		}
@@ -521,8 +530,10 @@ int cifs_get_inode_info(struct inode **p
 
 		/* BB fill in uid and gid here? with help from winbind? 
 		   or retrieve from NTFS stream extended attribute */
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
 			/* fill in uid, gid, mode from server ACL */
+			/* BB FIXME this should also take into account the
+			 * default uid specified on mount if present */
 			get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
 		} else if (atomic_read(&cifsInfo->inUse) == 0) {
 			inode->i_uid = cifs_sb->mnt_uid;
@@ -541,12 +552,12 @@ int cifs_get_inode_info(struct inode **p
 						&cifs_file_direct_nobrl_ops;
 				else
 					inode->i_fop = &cifs_file_direct_ops;
-			} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				inode->i_fop = &cifs_file_nobrl_ops;
 			else /* not direct, send byte range locks */
 				inode->i_fop = &cifs_file_ops;
 
-			if(pTcon->ses->server->maxBuf < 
+			if (pTcon->ses->server->maxBuf < 
 			     PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
 				inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 			else
@@ -597,7 +608,7 @@ int cifs_unlink(struct inode *inode, str
 
 	xid = GetXid();
 
-	if(inode)
+	if (inode)
 		cifs_sb = CIFS_SB(inode->i_sb);
 	else
 		cifs_sb = CIFS_SB(direntry->d_sb);
@@ -723,7 +734,7 @@ int cifs_unlink(struct inode *inode, str
 					   when needed */
 		direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
 	}
-	if(inode) {
+	if (inode) {
 		inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
 		cifsInode = CIFS_I(inode);
 		cifsInode->time = 0;	/* force revalidate of dir as well */
@@ -734,6 +745,136 @@ int cifs_unlink(struct inode *inode, str
 	return rc;
 }
 
+static void posix_fill_in_inode(struct inode *tmp_inode,
+	FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
+{
+	loff_t local_size;
+	struct timespec local_mtime;
+
+	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+
+	__u32 type = le32_to_cpu(pData->Type);
+	__u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
+	__u64 end_of_file = le64_to_cpu(pData->EndOfFile);
+	cifsInfo->time = jiffies;
+	atomic_inc(&cifsInfo->inUse);
+
+	/* save mtime and size */
+	local_mtime = tmp_inode->i_mtime;
+	local_size  = tmp_inode->i_size;
+
+	tmp_inode->i_atime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
+	tmp_inode->i_mtime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
+	tmp_inode->i_ctime =
+	    cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
+
+	tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
+	/* since we set the inode type below we need to mask off type
+           to avoid strange results if bits above were corrupt */
+        tmp_inode->i_mode &= ~S_IFMT;
+	if (type == UNIX_FILE) {
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+	} else if (type == UNIX_SYMLINK) {
+		*pobject_type = DT_LNK;
+		tmp_inode->i_mode |= S_IFLNK;
+	} else if (type == UNIX_DIR) {
+		*pobject_type = DT_DIR;
+		tmp_inode->i_mode |= S_IFDIR;
+	} else if (type == UNIX_CHARDEV) {
+		*pobject_type = DT_CHR;
+		tmp_inode->i_mode |= S_IFCHR;
+		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+				le64_to_cpu(pData->DevMinor) & MINORMASK);
+	} else if (type == UNIX_BLOCKDEV) {
+		*pobject_type = DT_BLK;
+		tmp_inode->i_mode |= S_IFBLK;
+		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+				le64_to_cpu(pData->DevMinor) & MINORMASK);
+	} else if (type == UNIX_FIFO) {
+		*pobject_type = DT_FIFO;
+		tmp_inode->i_mode |= S_IFIFO;
+	} else if (type == UNIX_SOCKET) {
+		*pobject_type = DT_SOCK;
+		tmp_inode->i_mode |= S_IFSOCK;
+	} else {
+		/* safest to just call it a file */
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+		cFYI(1,("unknown inode type %d",type)); 
+	}
+
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1,("object type: %d", type));
+#endif
+	tmp_inode->i_uid = le64_to_cpu(pData->Uid);
+	tmp_inode->i_gid = le64_to_cpu(pData->Gid);
+	tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
+
+	spin_lock(&tmp_inode->i_lock);
+	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
+		/* can not safely change the file size here if the 
+		client is writing to it due to potential races */
+		i_size_write(tmp_inode, end_of_file);
+
+	/* 512 bytes (2**9) is the fake blocksize that must be used */
+	/* for this calculation, not the real blocksize */
+		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
+	}
+	spin_unlock(&tmp_inode->i_lock);
+
+	if (S_ISREG(tmp_inode->i_mode)) {
+		cFYI(1, ("File inode"));
+		tmp_inode->i_op = &cifs_file_inode_ops;
+
+		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
+			else
+				tmp_inode->i_fop = &cifs_file_direct_ops;
+		
+		} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+			tmp_inode->i_fop = &cifs_file_nobrl_ops;
+		else
+			tmp_inode->i_fop = &cifs_file_ops;
+
+		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		   (cifs_sb->tcon->ses->server->maxBuf < 
+			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+		else
+			tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+		if(isNewInode)
+			return; /* No sense invalidating pages for new inode since we
+					   have not started caching readahead file data yet */
+
+		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+			(local_size == tmp_inode->i_size)) {
+			cFYI(1, ("inode exists but unchanged"));
+		} else {
+			/* file may have changed on server */
+			cFYI(1, ("invalidate inode, readdir detected change"));
+			invalidate_remote_inode(tmp_inode);
+		}
+	} else if (S_ISDIR(tmp_inode->i_mode)) {
+		cFYI(1, ("Directory inode"));
+		tmp_inode->i_op = &cifs_dir_inode_ops;
+		tmp_inode->i_fop = &cifs_dir_ops;
+	} else if (S_ISLNK(tmp_inode->i_mode)) {
+		cFYI(1, ("Symbolic Link inode"));
+		tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+	} else {
+		cFYI(1, ("Special inode")); 
+		init_special_inode(tmp_inode, tmp_inode->i_mode,
+				   tmp_inode->i_rdev);
+	}	
+}
+
 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
 {
 	int rc = 0;
@@ -755,6 +896,71 @@ int cifs_mkdir(struct inode *inode, stru
 		FreeXid(xid);
 		return -ENOMEM;
 	}
+	
+	if((pTcon->ses->capabilities & CAP_UNIX) && 
+		(CIFS_UNIX_POSIX_PATH_OPS_CAP &	
+			le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+		u32 oplock = 0;
+		FILE_UNIX_BASIC_INFO * pInfo = 
+			kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+		if(pInfo == NULL) {
+			rc = -ENOMEM;
+			goto mkdir_out;
+		}
+			
+		rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+				mode, NULL /* netfid */, pInfo, &oplock,
+				full_path, cifs_sb->local_nls, 
+				cifs_sb->mnt_cifs_flags & 
+					CIFS_MOUNT_MAP_SPECIAL_CHR);
+		if (rc) {
+			cFYI(1, ("posix mkdir returned 0x%x", rc));
+			d_drop(direntry);
+		} else {
+			int obj_type;
+			if (pInfo->Type == -1) /* no return info - go query */
+				goto mkdir_get_info; 
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
+			inc_nlink(inode);
+			if (pTcon->nocase)
+				direntry->d_op = &cifs_ci_dentry_ops;
+			else
+				direntry->d_op = &cifs_dentry_ops;
+
+			newinode = new_inode(inode->i_sb);
+			if (newinode == NULL)
+				goto mkdir_get_info;
+			/* Is an i_ino of zero legal? */
+			/* Are there sanity checks we can use to ensure that
+			   the server is really filling in that field? */
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+				newinode->i_ino =
+					(unsigned long)pInfo->UniqueId;
+			} /* note ino incremented to unique num in new_inode */
+			if(inode->i_sb->s_flags & MS_NOATIME)
+				newinode->i_flags |= S_NOATIME | S_NOCMTIME;
+			newinode->i_nlink = 2;
+
+			insert_inode_hash(newinode);
+			d_instantiate(direntry, newinode);
+
+			/* we already checked in POSIXCreate whether
+			   frame was long enough */
+			posix_fill_in_inode(direntry->d_inode,
+					pInfo, &obj_type, 1 /* NewInode */);
+#ifdef CONFIG_CIFS_DEBUG2
+			cFYI(1,("instantiated dentry %p %s to inode %p",
+				direntry, direntry->d_name.name, newinode));
+
+			if(newinode->i_nlink != 2)
+				cFYI(1,("unexpected number of links %d",
+					newinode->i_nlink));
+#endif
+		}
+		kfree(pInfo);
+		goto mkdir_out;
+	}	
+	
 	/* BB add setting the equivalent of mode via CreateX w/ACLs */
 	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -762,6 +968,7 @@ int cifs_mkdir(struct inode *inode, stru
 		cFYI(1, ("cifs_mkdir returned 0x%x", rc));
 		d_drop(direntry);
 	} else {
+mkdir_get_info:		
 		inc_nlink(inode);
 		if (pTcon->ses->capabilities & CAP_UNIX)
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -775,8 +982,10 @@ int cifs_mkdir(struct inode *inode, stru
 		else
 			direntry->d_op = &cifs_dentry_ops;
 		d_instantiate(direntry, newinode);
-		if (direntry->d_inode)
-			direntry->d_inode->i_nlink = 2;
+		 /* setting nlink not necessary except in cases where we
+		  * failed to get it from the server or was set bogus */ 
+		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
+				direntry->d_inode->i_nlink = 2; 
 		if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
 			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
 				CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -812,6 +1021,7 @@ int cifs_mkdir(struct inode *inode, stru
 			}
 		}
 	}
+mkdir_out:	
 	kfree(full_path);
 	FreeXid(xid);
 	return rc;
@@ -1339,17 +1549,17 @@ int cifs_setattr(struct dentry *direntry
 					cpu_to_le32(cifsInode->cifsAttrs |
 						    ATTR_READONLY);
 			}
-		} else if ((mode & S_IWUGO) == S_IWUGO) {
-			if (cifsInode->cifsAttrs & ATTR_READONLY) {
-				set_dosattr = TRUE;
-				time_buf.Attributes =
-					cpu_to_le32(cifsInode->cifsAttrs &
-						    (~ATTR_READONLY));
-				/* Windows ignores set to zero */
-				if(time_buf.Attributes == 0)
-					time_buf.Attributes |= 
-						cpu_to_le32(ATTR_NORMAL);
-			}
+		} else if (cifsInode->cifsAttrs & ATTR_READONLY) {
+			/* If file is readonly on server, we would
+			not be able to write to it - so if any write
+			bit is enabled for user or group or other we
+			need to at least try to remove r/o dos attr */
+			set_dosattr = TRUE;
+			time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
+					    (~ATTR_READONLY));
+			/* Windows ignores set to zero */
+			if(time_buf.Attributes == 0)
+				time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
 		}
 		/* BB to be implemented -
 		   via Windows security descriptors or streams */
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 992e80e..53e304d 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -30,6 +30,9 @@ #include <linux/ctype.h>
 #include <linux/fs.h>
 #include <asm/div64.h>
 #include <asm/byteorder.h>
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+#include <linux/inet.h>
+#endif
 #include "cifsfs.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
@@ -129,11 +132,27 @@ static const struct smb_to_posix_error m
 /* Convert string containing dotted ip address to binary form */
 /* returns 0 if invalid address */
 
-/* BB add address family, change rc to status flag and return union or for ipv6 */
-/*  will need parent to call something like inet_pton to convert ipv6 address  BB */
 int
 cifs_inet_pton(int address_family, char *cp,void *dst)
 {
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+	int ret = 0;
+
+	/* calculate length by finding first slash or NULL */
+	/* BB Should we convert '/' slash to '\' here since it seems already done
+	   before this */
+	if( address_family == AF_INET ){
+		ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);	
+	} else if( address_family == AF_INET6 ){
+		ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
+	}
+#ifdef CONFIG_CIFS_DEBUG2
+	cFYI(1,("address conversion returned %d for %s", ret, cp));
+#endif
+	if (ret > 0)
+		ret = 1;
+	return ret;
+#else
 	int value;
 	int digit;
 	int i;
@@ -192,6 +211,7 @@ cifs_inet_pton(int address_family, char 
 
 	*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
 	return 1; /* success */
+#endif /* EXPERIMENTAL */	
 }
 
 /*****************************************************************************
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 2a374d5..c08bda9 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -23,7 +23,6 @@
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/stat.h>
-#include <linux/smp_lock.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -37,19 +36,19 @@ static void dump_cifs_file_struct(struct
 {
 	struct cifsFileInfo * cf;
 
-	if(file) {
+	if (file) {
 		cf = file->private_data;
-		if(cf == NULL) {
+		if (cf == NULL) {
 			cFYI(1,("empty cifs private file data"));
 			return;
 		}
-		if(cf->invalidHandle) {
+		if (cf->invalidHandle) {
 			cFYI(1,("invalid handle"));
 		}
-		if(cf->srch_inf.endOfSearch) {
+		if (cf->srch_inf.endOfSearch) {
 			cFYI(1,("end of search"));
 		}
-		if(cf->srch_inf.emptyDir) {
+		if (cf->srch_inf.emptyDir) {
 			cFYI(1,("empty dir"));
 		}
 		
@@ -77,17 +76,17 @@ static int construct_dentry(struct qstr 
 		cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
 		*ptmp_inode = tmp_dentry->d_inode;
 /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
-		if(*ptmp_inode == NULL) {
+		if (*ptmp_inode == NULL) {
 			*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
-			if(*ptmp_inode == NULL)
+			if (*ptmp_inode == NULL)
 				return rc;
 			rc = 1;
 		}
-		if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+		if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
 			(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
 	} else {
 		tmp_dentry = d_alloc(file->f_path.dentry, qstring);
-		if(tmp_dentry == NULL) {
+		if (tmp_dentry == NULL) {
 			cERROR(1,("Failed allocating dentry"));
 			*ptmp_inode = NULL;
 			return rc;
@@ -98,9 +97,9 @@ static int construct_dentry(struct qstr 
 			tmp_dentry->d_op = &cifs_ci_dentry_ops;
 		else
 			tmp_dentry->d_op = &cifs_dentry_ops;
-		if(*ptmp_inode == NULL)
+		if (*ptmp_inode == NULL)
 			return rc;
-		if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+		if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
 			(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;			
 		rc = 2;
 	}
@@ -112,7 +111,7 @@ static int construct_dentry(struct qstr 
 
 static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
 {
-	if((tcon) && (tcon->ses) && (tcon->ses->server)) {
+	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;
@@ -137,7 +136,7 @@ static void fill_in_inode(struct inode *
 	local_mtime = tmp_inode->i_mtime;
 	local_size  = tmp_inode->i_size;
 
-	if(new_buf_type) {
+	if (new_buf_type) {
 		FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
 
 		attr = le32_to_cpu(pfindData->ExtFileAttributes);
@@ -193,7 +192,7 @@ static void fill_in_inode(struct inode *
 	if (attr & ATTR_DIRECTORY) {
 		*pobject_type = DT_DIR;
 		/* override default perms since we do not lock dirs */
-		if(atomic_read(&cifsInfo->inUse) == 0) {
+		if (atomic_read(&cifsInfo->inUse) == 0) {
 			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
 		}
 		tmp_inode->i_mode |= S_IFDIR;
@@ -250,25 +249,25 @@ static void fill_in_inode(struct inode *
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
 			else
 				tmp_inode->i_fop = &cifs_file_direct_ops;
 		
-		} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 			tmp_inode->i_fop = &cifs_file_nobrl_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
 
-		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
 		   (cifs_sb->tcon->ses->server->maxBuf <
 			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
 			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 		else
 			tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
-		if(isNewInode)
+		if (isNewInode)
 			return; /* No sense invalidating pages for new inode
 				   since have not started caching readahead file
 				   data yet */
@@ -357,8 +356,14 @@ static void unix_fill_in_inode(struct in
 		cFYI(1,("unknown inode type %d",type)); 
 	}
 
-	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
-	tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+		tmp_inode->i_uid = cifs_sb->mnt_uid;
+	else
+		tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+		tmp_inode->i_gid = cifs_sb->mnt_gid;
+	else
+		tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
 	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
 
 	spin_lock(&tmp_inode->i_lock);
@@ -377,25 +382,24 @@ static void unix_fill_in_inode(struct in
 		cFYI(1, ("File inode"));
 		tmp_inode->i_op = &cifs_file_inode_ops;
 
-		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-			if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
 			else
 				tmp_inode->i_fop = &cifs_file_direct_ops;
-		
-		} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
 			tmp_inode->i_fop = &cifs_file_nobrl_ops;
 		else
 			tmp_inode->i_fop = &cifs_file_ops;
 
-		if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
 		   (cifs_sb->tcon->ses->server->maxBuf < 
 			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
 			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
 		else
 			tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
-		if(isNewInode)
+		if (isNewInode)
 			return; /* No sense invalidating pages for new inode since we
 					   have not started caching readahead file data yet */
 
@@ -430,34 +434,28 @@ static int initiate_cifs_search(const in
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 
-	if(file->private_data == NULL) {
+	if (file->private_data == NULL) {
 		file->private_data = 
-			kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+			kzalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
 	}
 
-	if(file->private_data == NULL) {
+	if (file->private_data == NULL)
 		return -ENOMEM;
-	} else {
-		memset(file->private_data,0,sizeof(struct cifsFileInfo));
-	}
 	cifsFile = file->private_data;
 	cifsFile->invalidHandle = TRUE;
 	cifsFile->srch_inf.endOfSearch = FALSE;
 
-	if(file->f_path.dentry == NULL)
-		return -ENOENT;
-
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-	if(cifs_sb == NULL)
+	if (cifs_sb == NULL)
 		return -EINVAL;
 
 	pTcon = cifs_sb->tcon;
-	if(pTcon == NULL)
+	if (pTcon == NULL)
 		return -EINVAL;
 
 	full_path = build_path_from_dentry(file->f_path.dentry);
 
-	if(full_path == NULL) {
+	if (full_path == NULL) {
 		return -ENOMEM;
 	}
 
@@ -480,9 +478,9 @@ ffirst_retry:
 		&cifsFile->netfid, &cifsFile->srch_inf,
 		cifs_sb->mnt_cifs_flags & 
 			CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
-	if(rc == 0)
+	if (rc == 0)
 		cifsFile->invalidHandle = FALSE;
-	if((rc == -EOPNOTSUPP) && 
+	if ((rc == -EOPNOTSUPP) && 
 		(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
 		goto ffirst_retry;
@@ -498,7 +496,7 @@ static int cifs_unicode_bytelen(char *st
 	__le16 * ustr = (__le16 *)str;
 
 	for(len=0;len <= PATH_MAX;len++) {
-		if(ustr[len] == 0)
+		if (ustr[len] == 0)
 			return len << 1;
 	}
 	cFYI(1,("Unicode string longer than PATH_MAX found"));
@@ -510,7 +508,7 @@ static char *nxt_dir_entry(char *old_ent
 	char * new_entry;
 	FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
 
-	if(level == SMB_FIND_FILE_INFO_STANDARD) {
+	if (level == SMB_FIND_FILE_INFO_STANDARD) {
 		FIND_FILE_STANDARD_INFO * pfData;
 		pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
 
@@ -520,12 +518,12 @@ static char *nxt_dir_entry(char *old_ent
 		new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
 	cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
 	/* validate that new_entry is not past end of SMB */
-	if(new_entry >= end_of_smb) {
+	if (new_entry >= end_of_smb) {
 		cERROR(1,
 		      ("search entry %p began after end of SMB %p old entry %p",
 			new_entry, end_of_smb, old_entry)); 
 		return NULL;
-	} else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+	} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
 		   (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
 		  ((level != SMB_FIND_FILE_INFO_STANDARD) &&
 		   (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb)))  {
@@ -546,39 +544,39 @@ static int cifs_entry_is_dot(char *curre
 	char * filename = NULL;
 	int len = 0; 
 
-	if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+	if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
 		FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
-		if(cfile->srch_inf.unicode) {
+		if (cfile->srch_inf.unicode) {
 			len = cifs_unicode_bytelen(filename);
 		} else {
 			/* BB should we make this strnlen of PATH_MAX? */
 			len = strnlen(filename, 5);
 		}
-	} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
+	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
 		FILE_DIRECTORY_INFO * pFindData = 
 			(FILE_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == 
+	} else if (cfile->srch_inf.info_level == 
 			SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
 		FILE_FULL_DIRECTORY_INFO * pFindData = 
 			(FILE_FULL_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level ==
+	} else if (cfile->srch_inf.info_level ==
 			SMB_FIND_FILE_ID_FULL_DIR_INFO) {
 		SEARCH_ID_FULL_DIR_INFO * pFindData = 
 			(SEARCH_ID_FULL_DIR_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == 
+	} else if (cfile->srch_inf.info_level == 
 			SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
 		FILE_BOTH_DIRECTORY_INFO * pFindData = 
 			(FILE_BOTH_DIRECTORY_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
 		len = le32_to_cpu(pFindData->FileNameLength);
-	} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+	} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
 		FIND_FILE_STANDARD_INFO * pFindData =
 			(FIND_FILE_STANDARD_INFO *)current_entry;
 		filename = &pFindData->FileName[0];
@@ -587,25 +585,25 @@ static int cifs_entry_is_dot(char *curre
 		cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
 	}
 
-	if(filename) {
-		if(cfile->srch_inf.unicode) {
+	if (filename) {
+		if (cfile->srch_inf.unicode) {
 			__le16 *ufilename = (__le16 *)filename;
-			if(len == 2) {
+			if (len == 2) {
 				/* check for . */
-				if(ufilename[0] == UNICODE_DOT)
+				if (ufilename[0] == UNICODE_DOT)
 					rc = 1;
-			} else if(len == 4) {
+			} else if (len == 4) {
 				/* check for .. */
-				if((ufilename[0] == UNICODE_DOT)
+				if ((ufilename[0] == UNICODE_DOT)
 				   &&(ufilename[1] == UNICODE_DOT))
 					rc = 2;
 			}
 		} else /* ASCII */ {
-			if(len == 1) {
-				if(filename[0] == '.') 
+			if (len == 1) {
+				if (filename[0] == '.') 
 					rc = 1;
-			} else if(len == 2) {
-				if((filename[0] == '.') && (filename[1] == '.')) 
+			} else if (len == 2) {
+				if((filename[0] == '.') && (filename[1] == '.'))
 					rc = 2;
 			}
 		}
@@ -618,20 +616,10 @@ static int cifs_entry_is_dot(char *curre
    whether we can use the cached search results from the previous search */
 static int is_dir_changed(struct file * file)
 {
-	struct inode * inode;
-	struct cifsInodeInfo *cifsInfo;
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
 
-	if(file->f_path.dentry == NULL)
-		return 0;
-
-	inode = file->f_path.dentry->d_inode;
-
-	if(inode == NULL)
-		return 0;
-
-	cifsInfo = CIFS_I(inode);
-
-	if(cifsInfo->time == 0)
+	if (cifsInfo->time == 0)
 		return 1; /* directory was changed, perhaps due to unlink */
 	else
 		return 0;
@@ -654,7 +642,7 @@ static int find_cifs_entry(const int xid
 	struct cifsFileInfo * cifsFile = file->private_data;
 	/* check if index in the buffer */
 	
-	if((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
+	if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || 
 	   (num_to_ret == NULL))
 		return -ENOENT;
 	
@@ -672,7 +660,7 @@ static int find_cifs_entry(const int xid
 #ifdef CONFIG_CIFS_DEBUG2
 	dump_cifs_file_struct(file, "In fce ");
 #endif
-	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
+	if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
 	     is_dir_changed(file)) || 
 	   (index_to_find < first_entry_in_buffer)) {
 		/* close and restart search */
@@ -681,9 +669,9 @@ #endif
 		CIFSFindClose(xid, pTcon, cifsFile->netfid);
 		kfree(cifsFile->search_resume_name);
 		cifsFile->search_resume_name = NULL;
-		if(cifsFile->srch_inf.ntwrk_buf_start) {
+		if (cifsFile->srch_inf.ntwrk_buf_start) {
 			cFYI(1,("freeing SMB ff cache buf on search rewind"));
-			if(cifsFile->srch_inf.smallBuf)
+			if (cifsFile->srch_inf.smallBuf)
 				cifs_small_buf_release(cifsFile->srch_inf.
 						ntwrk_buf_start);
 			else
@@ -691,7 +679,7 @@ #endif
 						ntwrk_buf_start);
 		}
 		rc = initiate_cifs_search(xid,file);
-		if(rc) {
+		if (rc) {
 			cFYI(1,("error %d reinitiating a search on rewind",rc));
 			return rc;
 		}
@@ -702,10 +690,10 @@ #endif
 	 	cFYI(1,("calling findnext2"));
 		rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 
 				  &cifsFile->srch_inf);
-		if(rc)
+		if (rc)
 			return -ENOENT;
 	}
-	if(index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+	if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
 		/* we found the buffer that contains the entry */
 		/* scan and find it */
 		int i;
@@ -851,9 +839,6 @@ static int cifs_filldir(char *pfindEntry
 	if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
 		return -ENOENT;
 
-	if(file->f_path.dentry == NULL)
-		return -ENOENT;
-
 	rc = cifs_entry_is_dot(pfindEntry,pCifsF);
 	/* skip . and .. since we added them first */
 	if(rc != 0) 
@@ -997,11 +982,6 @@ int cifs_readdir(struct file *file, void
 
 	xid = GetXid();
 
-	if(file->f_path.dentry == NULL) {
-		FreeXid(xid);
-		return -EIO;
-	}
-
 	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 	pTcon = cifs_sb->tcon;
 	if(pTcon == NULL)
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 614175a..0aaff36 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -62,8 +62,7 @@ static void init_once(void * foo, struct
 {
 	struct coda_inode_info *ei = (struct coda_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/compat.c b/fs/compat.c
index 040a8be..9cf75df 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -15,6 +15,7 @@
  *  published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/compat.h>
 #include <linux/errno.h>
@@ -24,10 +25,8 @@ #include <linux/fcntl.h>
 #include <linux/namei.h>
 #include <linux/file.h>
 #include <linux/vfs.h>
-#include <linux/ioctl32.h>
 #include <linux/ioctl.h>
 #include <linux/init.h>
-#include <linux/sockios.h>	/* for SIOCDEVPRIVATE */
 #include <linux/smb.h>
 #include <linux/smb_mount.h>
 #include <linux/ncp_mount.h>
@@ -45,13 +44,12 @@ #include <linux/nfsd/syscall.h>
 #include <linux/personality.h>
 #include <linux/rwsem.h>
 #include <linux/tsacct_kern.h>
+#include <linux/security.h>
 #include <linux/highmem.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/eventpoll.h>
 
-#include <net/sock.h>		/* siocdevprivate_ioctl */
-
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/ioctls.h>
@@ -79,30 +77,57 @@ #include "read_write.h"
  */
 asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
 {
-	struct timeval tv[2];
+	struct timespec tv[2];
 
 	if (t) {
 		if (get_user(tv[0].tv_sec, &t->actime) ||
 		    get_user(tv[1].tv_sec, &t->modtime))
 			return -EFAULT;
-		tv[0].tv_usec = 0;
-		tv[1].tv_usec = 0;
+		tv[0].tv_nsec = 0;
+		tv[1].tv_nsec = 0;
+	}
+	return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
+}
+
+asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, struct compat_timespec __user *t, int flags)
+{
+	struct timespec tv[2];
+
+	if  (t) {
+		if (get_compat_timespec(&tv[0], &t[0]) ||
+		    get_compat_timespec(&tv[1], &t[1]))
+			return -EFAULT;
+
+		if ((tv[0].tv_nsec == UTIME_OMIT || tv[0].tv_nsec == UTIME_NOW)
+		    && tv[0].tv_sec != 0)
+			return -EINVAL;
+		if ((tv[1].tv_nsec == UTIME_OMIT || tv[1].tv_nsec == UTIME_NOW)
+		    && tv[1].tv_sec != 0)
+			return -EINVAL;
+
+		if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
+			return 0;
 	}
-	return do_utimes(AT_FDCWD, filename, t ? tv : NULL);
+	return do_utimes(dfd, filename, t ? tv : NULL, flags);
 }
 
 asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t)
 {
-	struct timeval tv[2];
+	struct timespec tv[2];
 
 	if (t) {
 		if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
-		    get_user(tv[0].tv_usec, &t[0].tv_usec) ||
+		    get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
 		    get_user(tv[1].tv_sec, &t[1].tv_sec) ||
-		    get_user(tv[1].tv_usec, &t[1].tv_usec))
+		    get_user(tv[1].tv_nsec, &t[1].tv_usec))
 			return -EFAULT;
+		if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
+		    tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
+			return -EINVAL;
+		tv[0].tv_nsec *= 1000;
+		tv[1].tv_nsec *= 1000;
 	}
-	return do_utimes(dfd, filename, t ? tv : NULL);
+	return do_utimes(dfd, filename, t ? tv : NULL, 0);
 }
 
 asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
@@ -312,162 +337,6 @@ out:
 	return error;
 }
 
-/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */
-
-#define IOCTL_HASHSIZE 256
-static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
-
-static inline unsigned long ioctl32_hash(unsigned long cmd)
-{
-	return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
-}
-
-static void ioctl32_insert_translation(struct ioctl_trans *trans)
-{
-	unsigned long hash;
-	struct ioctl_trans *t;
-
-	hash = ioctl32_hash (trans->cmd);
-	if (!ioctl32_hash_table[hash])
-		ioctl32_hash_table[hash] = trans;
-	else {
-		t = ioctl32_hash_table[hash];
-		while (t->next)
-			t = t->next;
-		trans->next = NULL;
-		t->next = trans;
-	}
-}
-
-static int __init init_sys32_ioctl(void)
-{
-	int i;
-
-	for (i = 0; i < ioctl_table_size; i++) {
-		if (ioctl_start[i].next != 0) { 
-			printk("ioctl translation %d bad\n",i); 
-			return -1;
-		}
-
-		ioctl32_insert_translation(&ioctl_start[i]);
-	}
-	return 0;
-}
-
-__initcall(init_sys32_ioctl);
-
-static void compat_ioctl_error(struct file *filp, unsigned int fd,
-		unsigned int cmd, unsigned long arg)
-{
-	char buf[10];
-	char *fn = "?";
-	char *path;
-
-	/* find the name of the device. */
-	path = (char *)__get_free_page(GFP_KERNEL);
-	if (path) {
-		fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
-		if (IS_ERR(fn))
-			fn = "?";
-	}
-
-	sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
-	if (!isprint(buf[1]))
-		sprintf(buf, "%02x", buf[1]);
-	compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
-			"cmd(%08x){%s} arg(%08x) on %s\n",
-			current->comm, current->pid,
-			(int)fd, (unsigned int)cmd, buf,
-			(unsigned int)arg, fn);
-
-	if (path)
-		free_page((unsigned long)path);
-}
-
-asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
-				unsigned long arg)
-{
-	struct file *filp;
-	int error = -EBADF;
-	struct ioctl_trans *t;
-	int fput_needed;
-
-	filp = fget_light(fd, &fput_needed);
-	if (!filp)
-		goto out;
-
-	/* RED-PEN how should LSM module know it's handling 32bit? */
-	error = security_file_ioctl(filp, cmd, arg);
-	if (error)
-		goto out_fput;
-
-	/*
-	 * To allow the compat_ioctl handlers to be self contained
-	 * we need to check the common ioctls here first.
-	 * Just handle them with the standard handlers below.
-	 */
-	switch (cmd) {
-	case FIOCLEX:
-	case FIONCLEX:
-	case FIONBIO:
-	case FIOASYNC:
-	case FIOQSIZE:
-		break;
-
-	case FIBMAP:
-	case FIGETBSZ:
-	case FIONREAD:
-		if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
-			break;
-		/*FALL THROUGH*/
-
-	default:
-		if (filp->f_op && filp->f_op->compat_ioctl) {
-			error = filp->f_op->compat_ioctl(filp, cmd, arg);
-			if (error != -ENOIOCTLCMD)
-				goto out_fput;
-		}
-
-		if (!filp->f_op ||
-		    (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl))
-			goto do_ioctl;
-		break;
-	}
-
-	for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
-		if (t->cmd == cmd)
-			goto found_handler;
-	}
-
-	if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
-	    cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
-		error = siocdevprivate_ioctl(fd, cmd, arg);
-	} else {
-		static int count;
-
-		if (++count <= 50)
-			compat_ioctl_error(filp, fd, cmd, arg);
-		error = -EINVAL;
-	}
-
-	goto out_fput;
-
- found_handler:
-	if (t->handler) {
-		lock_kernel();
-		error = t->handler(fd, cmd, arg, filp);
-		unlock_kernel();
-		goto out_fput;
-	}
-
- do_ioctl:
-	error = vfs_ioctl(filp, fd, cmd, arg);
- out_fput:
-	fput_light(filp, fput_needed);
- out:
-	return error;
-}
-
 static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 {
 	if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
@@ -901,8 +770,6 @@ asmlinkage long compat_sys_mount(char __
 }
 
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
-				~(sizeof(compat_long_t)-1))
 
 struct compat_old_linux_dirent {
 	compat_ulong_t	d_ino;
@@ -990,7 +857,7 @@ static int compat_filldir(void *__buf, c
 	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);
+	int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(compat_long_t));
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
@@ -1065,7 +932,6 @@ out:
 }
 
 #ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
-#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
 
 struct compat_getdents_callback64 {
 	struct linux_dirent64 __user *current_dir;
@@ -1080,7 +946,7 @@ static int compat_filldir64(void * __buf
 	struct linux_dirent64 __user *dirent;
 	struct compat_getdents_callback64 *buf = __buf;
 	int jj = NAME_OFFSET(dirent);
-	int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
+	int reclen = ALIGN(jj + namlen + 1, sizeof(u64));
 	u64 off;
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
@@ -1593,8 +1459,6 @@ out_ret:
 
 #define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
 
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
 /*
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
  * 64-bit unsigned longs.
@@ -1603,7 +1467,7 @@ static
 int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
 			unsigned long *fdset)
 {
-	nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+	nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
 	if (ufdset) {
 		unsigned long odd;
 
@@ -1637,7 +1501,7 @@ int compat_set_fd_set(unsigned long nr, 
 		      unsigned long *fdset)
 {
 	unsigned long odd;
-	nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+	nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
 
 	if (!ufdset)
 		return 0;
@@ -1759,7 +1623,7 @@ asmlinkage long compat_sys_select(int n,
 		if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(tv.tv_usec, 1000000/HZ);
+			timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ);
 			timeout += tv.tv_sec * HZ;
 		}
 	}
@@ -1827,7 +1691,7 @@ asmlinkage long compat_sys_pselect7(int 
 	do {
 		if (tsp) {
 			if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
-				timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+				timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
 				timeout += ts.tv_sec * (unsigned long)HZ;
 				ts.tv_sec = 0;
 				ts.tv_nsec = 0;
@@ -1923,7 +1787,7 @@ asmlinkage long compat_sys_ppoll(struct 
 		/* We assume that ts.tv_sec is always lower than
 		   the number of seconds that can be expressed in
 		   an s64. Otherwise the compiler bitches at us */
-		timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+		timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
 		timeout += ts.tv_sec * HZ;
 	}
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 8b1c5d8..d92bc3e 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -17,7 +17,6 @@ #include <linux/capability.h>
 #include <linux/compiler.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_bridge.h>
@@ -58,7 +57,6 @@ #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/if_tun.h>
 #include <linux/ctype.h>
-#include <linux/ioctl32.h>
 #include <linux/syscalls.h>
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
@@ -66,7 +64,6 @@ #include <linux/wireless.h>
 #include <linux/atalk.h>
 #include <linux/blktrace_api.h>
 
-#include <net/sock.h>          /* siocdevprivate_ioctl */
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci.h>
 #include <net/bluetooth/rfcomm.h>
@@ -266,6 +263,23 @@ static int do_siocgstamp(unsigned int fd
 	return err;
 }
 
+static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct compat_timespec __user *up = compat_ptr(arg);
+	struct timespec kts;
+	mm_segment_t old_fs = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kts);
+	set_fs(old_fs);
+	if (!err) {
+		err = put_user(kts.tv_sec, &up->tv_sec);
+		err |= __put_user(kts.tv_nsec, &up->tv_nsec);
+	}
+	return err;
+}
+
 struct ifmap32 {
 	compat_ulong_t mem_start;
 	compat_ulong_t mem_end;
@@ -458,7 +472,7 @@ static int bond_ioctl(unsigned int fd, u
 	};
 }
 
-int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq __user *u_ifreq64;
 	struct ifreq32 __user *u_ifreq32 = compat_ptr(arg);
@@ -670,8 +684,10 @@ static int hdio_getgeo(unsigned int fd, 
 	if (!err) {
 		err = copy_to_user (ugeo, &geo, 4);
 		err |= __put_user (geo.start, &ugeo->start);
+		if (err)
+			err = -EFAULT;
 	}
-	return err ? -EFAULT : 0;
+	return err;
 }
 
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -2368,6 +2384,16 @@ lp_timeout_trans(unsigned int fd, unsign
 	return sys_ioctl(fd, cmd, (unsigned long)tn);
 }
 
+
+typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
+					unsigned long, struct file *);
+
+struct ioctl_trans {
+	unsigned long cmd;
+	ioctl_trans_handler_t handler;
+	struct ioctl_trans *next;
+};
+
 #define HANDLE_IOCTL(cmd,handler) \
 	{ (cmd), (ioctl_trans_handler_t)(handler) },
 
@@ -2379,9 +2405,844 @@ #define COMPATIBLE_IOCTL(cmd) \
 #define ULONG_IOCTL(cmd) \
 	{ (cmd), (ioctl_trans_handler_t)sys_ioctl },
 
-
-struct ioctl_trans ioctl_start[] = {
-#include <linux/compat_ioctl.h>
+/* ioctl should not be warned about even if it's not implemented.
+   Valid reasons to use this:
+   - It is implemented with ->compat_ioctl on some device, but programs
+   call it on others too.
+   - The ioctl is not implemented in the native kernel, but programs
+   call it commonly anyways.
+   Most other reasons are not valid. */
+#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
+
+static struct ioctl_trans ioctl_start[] = {
+/* compatible ioctls first */
+COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
+
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA)
+COMPATIBLE_IOCTL(TCSETA)
+COMPATIBLE_IOCTL(TCSETAW)
+COMPATIBLE_IOCTL(TCSETAF)
+COMPATIBLE_IOCTL(TCSBRK)
+ULONG_IOCTL(TCSBRKP)
+COMPATIBLE_IOCTL(TCXONC)
+COMPATIBLE_IOCTL(TCFLSH)
+COMPATIBLE_IOCTL(TCGETS)
+COMPATIBLE_IOCTL(TCSETS)
+COMPATIBLE_IOCTL(TCSETSW)
+COMPATIBLE_IOCTL(TCSETSF)
+COMPATIBLE_IOCTL(TIOCLINUX)
+COMPATIBLE_IOCTL(TIOCSBRK)
+COMPATIBLE_IOCTL(TIOCCBRK)
+ULONG_IOCTL(TIOCMIWAIT)
+COMPATIBLE_IOCTL(TIOCGICOUNT)
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD)
+COMPATIBLE_IOCTL(TIOCSETD)
+COMPATIBLE_IOCTL(TIOCEXCL)
+COMPATIBLE_IOCTL(TIOCNXCL)
+COMPATIBLE_IOCTL(TIOCCONS)
+COMPATIBLE_IOCTL(TIOCGSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSWINSZ)
+COMPATIBLE_IOCTL(TIOCGWINSZ)
+COMPATIBLE_IOCTL(TIOCMGET)
+COMPATIBLE_IOCTL(TIOCMBIC)
+COMPATIBLE_IOCTL(TIOCMBIS)
+COMPATIBLE_IOCTL(TIOCMSET)
+COMPATIBLE_IOCTL(TIOCPKT)
+COMPATIBLE_IOCTL(TIOCNOTTY)
+COMPATIBLE_IOCTL(TIOCSTI)
+COMPATIBLE_IOCTL(TIOCOUTQ)
+COMPATIBLE_IOCTL(TIOCSPGRP)
+COMPATIBLE_IOCTL(TIOCGPGRP)
+ULONG_IOCTL(TIOCSCTTY)
+COMPATIBLE_IOCTL(TIOCGPTN)
+COMPATIBLE_IOCTL(TIOCSPTLCK)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX)
+COMPATIBLE_IOCTL(FIONCLEX)
+COMPATIBLE_IOCTL(FIOASYNC)
+COMPATIBLE_IOCTL(FIONBIO)
+COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP)
+COMPATIBLE_IOCTL(FIGETBSZ)
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ *         Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
+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)
+COMPATIBLE_IOCTL(FDSETEMSGTRESH)
+COMPATIBLE_IOCTL(FDFLUSH)
+COMPATIBLE_IOCTL(FDWERRORCLR)
+COMPATIBLE_IOCTL(FDSETMAXERRS)
+COMPATIBLE_IOCTL(FDGETMAXERRS)
+COMPATIBLE_IOCTL(FDGETDRVTYP)
+COMPATIBLE_IOCTL(FDEJECT)
+COMPATIBLE_IOCTL(FDCLRPRM)
+COMPATIBLE_IOCTL(FDFMTBEG)
+COMPATIBLE_IOCTL(FDFMTEND)
+COMPATIBLE_IOCTL(FDRESET)
+COMPATIBLE_IOCTL(FDTWADDLE)
+COMPATIBLE_IOCTL(FDFMTTRK)
+COMPATIBLE_IOCTL(FDRAWCMD)
+/* 0x12 */
+#ifdef CONFIG_BLOCK
+COMPATIBLE_IOCTL(BLKRASET)
+COMPATIBLE_IOCTL(BLKROSET)
+COMPATIBLE_IOCTL(BLKROGET)
+COMPATIBLE_IOCTL(BLKRRPART)
+COMPATIBLE_IOCTL(BLKFLSBUF)
+COMPATIBLE_IOCTL(BLKSECTSET)
+COMPATIBLE_IOCTL(BLKSSZGET)
+COMPATIBLE_IOCTL(BLKTRACESTART)
+COMPATIBLE_IOCTL(BLKTRACESTOP)
+COMPATIBLE_IOCTL(BLKTRACESETUP)
+COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
+ULONG_IOCTL(BLKRASET)
+ULONG_IOCTL(BLKFRASET)
+#endif
+/* RAID */
+COMPATIBLE_IOCTL(RAID_VERSION)
+COMPATIBLE_IOCTL(GET_ARRAY_INFO)
+COMPATIBLE_IOCTL(GET_DISK_INFO)
+COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
+COMPATIBLE_IOCTL(RAID_AUTORUN)
+COMPATIBLE_IOCTL(CLEAR_ARRAY)
+COMPATIBLE_IOCTL(ADD_NEW_DISK)
+ULONG_IOCTL(HOT_REMOVE_DISK)
+COMPATIBLE_IOCTL(SET_ARRAY_INFO)
+COMPATIBLE_IOCTL(SET_DISK_INFO)
+COMPATIBLE_IOCTL(WRITE_RAID_INFO)
+COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
+COMPATIBLE_IOCTL(PROTECT_ARRAY)
+ULONG_IOCTL(HOT_ADD_DISK)
+ULONG_IOCTL(SET_DISK_FAULTY)
+COMPATIBLE_IOCTL(RUN_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)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES_32)
+COMPATIBLE_IOCTL(DM_DEV_CREATE_32)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE_32)
+COMPATIBLE_IOCTL(DM_DEV_RENAME_32)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND_32)
+COMPATIBLE_IOCTL(DM_DEV_STATUS_32)
+COMPATIBLE_IOCTL(DM_DEV_WAIT_32)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD_32)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR_32)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS_32)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
+COMPATIBLE_IOCTL(DM_TARGET_MSG_32)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32)
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_DEV_WAIT)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
+COMPATIBLE_IOCTL(DM_TARGET_MSG)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY)
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT)
+COMPATIBLE_IOCTL(GIO_FONT)
+ULONG_IOCTL(KDSIGACCEPT)
+COMPATIBLE_IOCTL(KDGETKEYCODE)
+COMPATIBLE_IOCTL(KDSETKEYCODE)
+ULONG_IOCTL(KIOCSOUND)
+ULONG_IOCTL(KDMKTONE)
+COMPATIBLE_IOCTL(KDGKBTYPE)
+ULONG_IOCTL(KDSETMODE)
+COMPATIBLE_IOCTL(KDGETMODE)
+ULONG_IOCTL(KDSKBMODE)
+COMPATIBLE_IOCTL(KDGKBMODE)
+ULONG_IOCTL(KDSKBMETA)
+COMPATIBLE_IOCTL(KDGKBMETA)
+COMPATIBLE_IOCTL(KDGKBENT)
+COMPATIBLE_IOCTL(KDSKBENT)
+COMPATIBLE_IOCTL(KDGKBSENT)
+COMPATIBLE_IOCTL(KDSKBSENT)
+COMPATIBLE_IOCTL(KDGKBDIACR)
+COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDKBDREP)
+COMPATIBLE_IOCTL(KDGKBLED)
+ULONG_IOCTL(KDSKBLED)
+COMPATIBLE_IOCTL(KDGETLED)
+ULONG_IOCTL(KDSETLED)
+COMPATIBLE_IOCTL(GIO_SCRNMAP)
+COMPATIBLE_IOCTL(PIO_SCRNMAP)
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_FONTRESET)
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM)
+COMPATIBLE_IOCTL(TUNSETDEBUG)
+COMPATIBLE_IOCTL(TUNSETPERSIST)
+COMPATIBLE_IOCTL(TUNSETOWNER)
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE)
+COMPATIBLE_IOCTL(VT_GETMODE)
+COMPATIBLE_IOCTL(VT_GETSTATE)
+COMPATIBLE_IOCTL(VT_OPENQRY)
+ULONG_IOCTL(VT_ACTIVATE)
+ULONG_IOCTL(VT_WAITACTIVE)
+ULONG_IOCTL(VT_RELDISP)
+ULONG_IOCTL(VT_DISALLOCATE)
+COMPATIBLE_IOCTL(VT_RESIZE)
+COMPATIBLE_IOCTL(VT_RESIZEX)
+COMPATIBLE_IOCTL(VT_LOCKSWITCH)
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
+COMPATIBLE_IOCTL(VT_GETHIFONTMASK)
+/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
+/*
+ * These two are only for the sbus rtc driver, but
+ * hwclock tries them on every rtc device first when
+ * running on sparc.  On other architectures the entries
+ * are useless but harmless.
+ */
+COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
+COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP)
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOQSIZE)
+COMPATIBLE_IOCTL(FIOSETOWN)
+COMPATIBLE_IOCTL(SIOCSPGRP)
+COMPATIBLE_IOCTL(FIOGETOWN)
+COMPATIBLE_IOCTL(SIOCGPGRP)
+COMPATIBLE_IOCTL(SIOCATMARK)
+COMPATIBLE_IOCTL(SIOCSIFLINK)
+COMPATIBLE_IOCTL(SIOCSIFENCAP)
+COMPATIBLE_IOCTL(SIOCGIFENCAP)
+COMPATIBLE_IOCTL(SIOCSIFNAME)
+COMPATIBLE_IOCTL(SIOCSARP)
+COMPATIBLE_IOCTL(SIOCGARP)
+COMPATIBLE_IOCTL(SIOCDARP)
+COMPATIBLE_IOCTL(SIOCSRARP)
+COMPATIBLE_IOCTL(SIOCGRARP)
+COMPATIBLE_IOCTL(SIOCDRARP)
+COMPATIBLE_IOCTL(SIOCADDDLCI)
+COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
+COMPATIBLE_IOCTL(SIOCBRADDBR)
+COMPATIBLE_IOCTL(SIOCBRDELBR)
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_EMULATED_HOST)
+ULONG_IOCTL(SG_SET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS)
+COMPATIBLE_IOCTL(PPPIOCSFLAGS)
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGUNIT)
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGMRU)
+COMPATIBLE_IOCTL(PPPIOCSMRU)
+COMPATIBLE_IOCTL(PPPIOCSMAXCID)
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
+COMPATIBLE_IOCTL(PPPIOCGNPMODE)
+COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+COMPATIBLE_IOCTL(PPPIOCGDEBUG)
+COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
+/* PPPIOCGIDLE is translated */
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
+COMPATIBLE_IOCTL(PPPIOCATTACH)
+COMPATIBLE_IOCTL(PPPIOCDETACH)
+COMPATIBLE_IOCTL(PPPIOCSMRRU)
+COMPATIBLE_IOCTL(PPPIOCCONNECT)
+COMPATIBLE_IOCTL(PPPIOCDISCONN)
+COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+COMPATIBLE_IOCTL(PPPIOCGCHAN)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
+/* ppdev */
+COMPATIBLE_IOCTL(PPSETMODE)
+COMPATIBLE_IOCTL(PPRSTATUS)
+COMPATIBLE_IOCTL(PPRCONTROL)
+COMPATIBLE_IOCTL(PPWCONTROL)
+COMPATIBLE_IOCTL(PPFCONTROL)
+COMPATIBLE_IOCTL(PPRDATA)
+COMPATIBLE_IOCTL(PPWDATA)
+COMPATIBLE_IOCTL(PPCLAIM)
+COMPATIBLE_IOCTL(PPRELEASE)
+COMPATIBLE_IOCTL(PPYIELD)
+COMPATIBLE_IOCTL(PPEXCL)
+COMPATIBLE_IOCTL(PPDATADIR)
+COMPATIBLE_IOCTL(PPNEGOT)
+COMPATIBLE_IOCTL(PPWCTLONIRQ)
+COMPATIBLE_IOCTL(PPCLRIRQ)
+COMPATIBLE_IOCTL(PPSETPHASE)
+COMPATIBLE_IOCTL(PPGETMODES)
+COMPATIBLE_IOCTL(PPGETMODE)
+COMPATIBLE_IOCTL(PPGETPHASE)
+COMPATIBLE_IOCTL(PPGETFLAGS)
+COMPATIBLE_IOCTL(PPSETFLAGS)
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+COMPATIBLE_IOCTL(CDROMREADTOCHDR)
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
+COMPATIBLE_IOCTL(CDROMSTOP)
+COMPATIBLE_IOCTL(CDROMSTART)
+COMPATIBLE_IOCTL(CDROMEJECT)
+COMPATIBLE_IOCTL(CDROMVOLCTRL)
+COMPATIBLE_IOCTL(CDROMSUBCHNL)
+ULONG_IOCTL(CDROMEJECT_SW)
+COMPATIBLE_IOCTL(CDROMMULTISESSION)
+COMPATIBLE_IOCTL(CDROM_GET_MCN)
+COMPATIBLE_IOCTL(CDROMRESET)
+COMPATIBLE_IOCTL(CDROMVOLREAD)
+COMPATIBLE_IOCTL(CDROMSEEK)
+COMPATIBLE_IOCTL(CDROMPLAYBLK)
+COMPATIBLE_IOCTL(CDROMCLOSETRAY)
+ULONG_IOCTL(CDROM_SET_OPTIONS)
+ULONG_IOCTL(CDROM_CLEAR_OPTIONS)
+ULONG_IOCTL(CDROM_SELECT_SPEED)
+ULONG_IOCTL(CDROM_SELECT_DISC)
+ULONG_IOCTL(CDROM_MEDIA_CHANGED)
+ULONG_IOCTL(CDROM_DRIVE_STATUS)
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
+ULONG_IOCTL(CDROM_LOCKDOOR)
+ULONG_IOCTL(CDROM_DEBUG)
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
+ * not take a struct cdrom_read, instead they take a struct cdrom_msf
+ * which is compatible.
+ */
+COMPATIBLE_IOCTL(CDROMREADMODE2)
+COMPATIBLE_IOCTL(CDROMREADMODE1)
+COMPATIBLE_IOCTL(CDROMREADRAW)
+COMPATIBLE_IOCTL(CDROMREADCOOKED)
+COMPATIBLE_IOCTL(CDROMREADALL)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
+/* pktcdvd */
+COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
+/* Big A */
+/* sparc only */
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_START)
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
+/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
+/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
+/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
+COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
+COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
+COMPATIBLE_IOCTL(OSS_GETVERSION)
+/* AUTOFS */
+ULONG_IOCTL(AUTOFS_IOC_READY)
+ULONG_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
+/* Raw devices */
+COMPATIBLE_IOCTL(RAW_SETBIND)
+COMPATIBLE_IOCTL(RAW_GETBIND)
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+COMPATIBLE_IOCTL(ATMARPD_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_MCAST)
+COMPATIBLE_IOCTL(ATMLEC_DATA)
+COMPATIBLE_IOCTL(ATM_SETSC)
+COMPATIBLE_IOCTL(SIOCSIFATMTCP)
+COMPATIBLE_IOCTL(SIOCMKCLIP)
+COMPATIBLE_IOCTL(ATMARP_MKIP)
+COMPATIBLE_IOCTL(ATMARP_SETENTRY)
+COMPATIBLE_IOCTL(ATMARP_ENCAP)
+COMPATIBLE_IOCTL(ATMTCP_CREATE)
+COMPATIBLE_IOCTL(ATMTCP_REMOVE)
+COMPATIBLE_IOCTL(ATMMPC_CTRL)
+COMPATIBLE_IOCTL(ATMMPC_DATA)
+/* Watchdog */
+COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETTEMP)
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
+COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
+COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT)
+COMPATIBLE_IOCTL(RNDADDTOENTCNT)
+COMPATIBLE_IOCTL(RNDGETPOOL)
+COMPATIBLE_IOCTL(RNDADDENTROPY)
+COMPATIBLE_IOCTL(RNDZAPENTCNT)
+COMPATIBLE_IOCTL(RNDCLEARPOOL)
+/* Bluetooth */
+COMPATIBLE_IOCTL(HCIDEVUP)
+COMPATIBLE_IOCTL(HCIDEVDOWN)
+COMPATIBLE_IOCTL(HCIDEVRESET)
+COMPATIBLE_IOCTL(HCIDEVRESTAT)
+COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+COMPATIBLE_IOCTL(CMTPCONNADD)
+COMPATIBLE_IOCTL(CMTPCONNDEL)
+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
+COMPATIBLE_IOCTL(HIDPCONNADD)
+COMPATIBLE_IOCTL(HIDPCONNDEL)
+COMPATIBLE_IOCTL(HIDPGETCONNLIST)
+COMPATIBLE_IOCTL(HIDPGETCONNINFO)
+/* CAPI */
+COMPATIBLE_IOCTL(CAPI_REGISTER)
+COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
+COMPATIBLE_IOCTL(CAPI_GET_VERSION)
+COMPATIBLE_IOCTL(CAPI_GET_SERIAL)
+COMPATIBLE_IOCTL(CAPI_GET_PROFILE)
+COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD)
+COMPATIBLE_IOCTL(CAPI_GET_ERRCODE)
+COMPATIBLE_IOCTL(CAPI_INSTALLED)
+COMPATIBLE_IOCTL(CAPI_GET_FLAGS)
+COMPATIBLE_IOCTL(CAPI_SET_FLAGS)
+COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
+COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
+COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
+/* Siemens Gigaset */
+COMPATIBLE_IOCTL(GIGASET_REDIR)
+COMPATIBLE_IOCTL(GIGASET_CONFIG)
+COMPATIBLE_IOCTL(GIGASET_BRKCHARS)
+COMPATIBLE_IOCTL(GIGASET_VERSION)
+/* Misc. */
+COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
+COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
+COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
+COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
+COMPATIBLE_IOCTL(MEMGETBADBLOCK)
+COMPATIBLE_IOCTL(MEMSETBADBLOCK)
+/* NBD */
+ULONG_IOCTL(NBD_SET_SOCK)
+ULONG_IOCTL(NBD_SET_BLKSIZE)
+ULONG_IOCTL(NBD_SET_SIZE)
+COMPATIBLE_IOCTL(NBD_DO_IT)
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
+ULONG_IOCTL(NBD_SET_SIZE_BLOCKS)
+COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* i2c */
+COMPATIBLE_IOCTL(I2C_SLAVE)
+COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
+COMPATIBLE_IOCTL(I2C_TENBIT)
+COMPATIBLE_IOCTL(I2C_PEC)
+COMPATIBLE_IOCTL(I2C_RETRIES)
+COMPATIBLE_IOCTL(I2C_TIMEOUT)
+/* wireless */
+COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
+COMPATIBLE_IOCTL(SIOCGIWNAME)
+COMPATIBLE_IOCTL(SIOCSIWNWID)
+COMPATIBLE_IOCTL(SIOCGIWNWID)
+COMPATIBLE_IOCTL(SIOCSIWFREQ)
+COMPATIBLE_IOCTL(SIOCGIWFREQ)
+COMPATIBLE_IOCTL(SIOCSIWMODE)
+COMPATIBLE_IOCTL(SIOCGIWMODE)
+COMPATIBLE_IOCTL(SIOCSIWSENS)
+COMPATIBLE_IOCTL(SIOCGIWSENS)
+COMPATIBLE_IOCTL(SIOCSIWRANGE)
+COMPATIBLE_IOCTL(SIOCSIWPRIV)
+COMPATIBLE_IOCTL(SIOCGIWPRIV)
+COMPATIBLE_IOCTL(SIOCSIWSTATS)
+COMPATIBLE_IOCTL(SIOCGIWSTATS)
+COMPATIBLE_IOCTL(SIOCSIWAP)
+COMPATIBLE_IOCTL(SIOCGIWAP)
+COMPATIBLE_IOCTL(SIOCSIWSCAN)
+COMPATIBLE_IOCTL(SIOCSIWRATE)
+COMPATIBLE_IOCTL(SIOCGIWRATE)
+COMPATIBLE_IOCTL(SIOCSIWRTS)
+COMPATIBLE_IOCTL(SIOCGIWRTS)
+COMPATIBLE_IOCTL(SIOCSIWFRAG)
+COMPATIBLE_IOCTL(SIOCGIWFRAG)
+COMPATIBLE_IOCTL(SIOCSIWTXPOW)
+COMPATIBLE_IOCTL(SIOCGIWTXPOW)
+COMPATIBLE_IOCTL(SIOCSIWRETRY)
+COMPATIBLE_IOCTL(SIOCGIWRETRY)
+COMPATIBLE_IOCTL(SIOCSIWPOWER)
+COMPATIBLE_IOCTL(SIOCGIWPOWER)
+/* hiddev */
+COMPATIBLE_IOCTL(HIDIOCGVERSION)
+COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
+COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
+COMPATIBLE_IOCTL(HIDIOCGSTRING)
+COMPATIBLE_IOCTL(HIDIOCINITREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORT)
+COMPATIBLE_IOCTL(HIDIOCSREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
+COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
+COMPATIBLE_IOCTL(HIDIOCGUSAGE)
+COMPATIBLE_IOCTL(HIDIOCSUSAGE)
+COMPATIBLE_IOCTL(HIDIOCGUCODE)
+COMPATIBLE_IOCTL(HIDIOCGFLAG)
+COMPATIBLE_IOCTL(HIDIOCSFLAG)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
+/* dvb */
+COMPATIBLE_IOCTL(AUDIO_STOP)
+COMPATIBLE_IOCTL(AUDIO_PLAY)
+COMPATIBLE_IOCTL(AUDIO_PAUSE)
+COMPATIBLE_IOCTL(AUDIO_CONTINUE)
+COMPATIBLE_IOCTL(AUDIO_SELECT_SOURCE)
+COMPATIBLE_IOCTL(AUDIO_SET_MUTE)
+COMPATIBLE_IOCTL(AUDIO_SET_AV_SYNC)
+COMPATIBLE_IOCTL(AUDIO_SET_BYPASS_MODE)
+COMPATIBLE_IOCTL(AUDIO_CHANNEL_SELECT)
+COMPATIBLE_IOCTL(AUDIO_GET_STATUS)
+COMPATIBLE_IOCTL(AUDIO_GET_CAPABILITIES)
+COMPATIBLE_IOCTL(AUDIO_CLEAR_BUFFER)
+COMPATIBLE_IOCTL(AUDIO_SET_ID)
+COMPATIBLE_IOCTL(AUDIO_SET_MIXER)
+COMPATIBLE_IOCTL(AUDIO_SET_STREAMTYPE)
+COMPATIBLE_IOCTL(AUDIO_SET_EXT_ID)
+COMPATIBLE_IOCTL(AUDIO_SET_ATTRIBUTES)
+COMPATIBLE_IOCTL(AUDIO_SET_KARAOKE)
+COMPATIBLE_IOCTL(DMX_START)
+COMPATIBLE_IOCTL(DMX_STOP)
+COMPATIBLE_IOCTL(DMX_SET_FILTER)
+COMPATIBLE_IOCTL(DMX_SET_PES_FILTER)
+COMPATIBLE_IOCTL(DMX_SET_BUFFER_SIZE)
+COMPATIBLE_IOCTL(DMX_GET_PES_PIDS)
+COMPATIBLE_IOCTL(DMX_GET_CAPS)
+COMPATIBLE_IOCTL(DMX_SET_SOURCE)
+COMPATIBLE_IOCTL(DMX_GET_STC)
+COMPATIBLE_IOCTL(FE_GET_INFO)
+COMPATIBLE_IOCTL(FE_DISEQC_RESET_OVERLOAD)
+COMPATIBLE_IOCTL(FE_DISEQC_SEND_MASTER_CMD)
+COMPATIBLE_IOCTL(FE_DISEQC_RECV_SLAVE_REPLY)
+COMPATIBLE_IOCTL(FE_DISEQC_SEND_BURST)
+COMPATIBLE_IOCTL(FE_SET_TONE)
+COMPATIBLE_IOCTL(FE_SET_VOLTAGE)
+COMPATIBLE_IOCTL(FE_ENABLE_HIGH_LNB_VOLTAGE)
+COMPATIBLE_IOCTL(FE_READ_STATUS)
+COMPATIBLE_IOCTL(FE_READ_BER)
+COMPATIBLE_IOCTL(FE_READ_SIGNAL_STRENGTH)
+COMPATIBLE_IOCTL(FE_READ_SNR)
+COMPATIBLE_IOCTL(FE_READ_UNCORRECTED_BLOCKS)
+COMPATIBLE_IOCTL(FE_SET_FRONTEND)
+COMPATIBLE_IOCTL(FE_GET_FRONTEND)
+COMPATIBLE_IOCTL(FE_GET_EVENT)
+COMPATIBLE_IOCTL(FE_DISHNETWORK_SEND_LEGACY_CMD)
+COMPATIBLE_IOCTL(VIDEO_STOP)
+COMPATIBLE_IOCTL(VIDEO_PLAY)
+COMPATIBLE_IOCTL(VIDEO_FREEZE)
+COMPATIBLE_IOCTL(VIDEO_CONTINUE)
+COMPATIBLE_IOCTL(VIDEO_SELECT_SOURCE)
+COMPATIBLE_IOCTL(VIDEO_SET_BLANK)
+COMPATIBLE_IOCTL(VIDEO_GET_STATUS)
+COMPATIBLE_IOCTL(VIDEO_SET_DISPLAY_FORMAT)
+COMPATIBLE_IOCTL(VIDEO_FAST_FORWARD)
+COMPATIBLE_IOCTL(VIDEO_SLOWMOTION)
+COMPATIBLE_IOCTL(VIDEO_GET_CAPABILITIES)
+COMPATIBLE_IOCTL(VIDEO_CLEAR_BUFFER)
+COMPATIBLE_IOCTL(VIDEO_SET_ID)
+COMPATIBLE_IOCTL(VIDEO_SET_STREAMTYPE)
+COMPATIBLE_IOCTL(VIDEO_SET_FORMAT)
+COMPATIBLE_IOCTL(VIDEO_SET_SYSTEM)
+COMPATIBLE_IOCTL(VIDEO_SET_HIGHLIGHT)
+COMPATIBLE_IOCTL(VIDEO_SET_SPU)
+COMPATIBLE_IOCTL(VIDEO_GET_NAVI)
+COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES)
+COMPATIBLE_IOCTL(VIDEO_GET_SIZE)
+COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE)
+
+/* now things that need handlers */
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 #ifdef CONFIG_NET
@@ -2437,6 +3298,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns)
 #endif
 #ifdef CONFIG_BLOCK
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
@@ -2576,6 +3438,8 @@ HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wirele
 HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
 HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
 HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
+/* Not implemented in the native kernel */
+IGNORE_IOCTL(SIOCGIFCOUNT)
 HANDLE_IOCTL(RTC_IRQP_READ32, rtc_ioctl)
 HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl)
 HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl)
@@ -2599,6 +3463,167 @@ COMPATIBLE_IOCTL(LPRESET)
 /*LPGETSTATS not implemented, but no kernels seem to compile it in anyways*/
 COMPATIBLE_IOCTL(LPGETFLAGS)
 HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
+
+/* fat 'r' ioctls. These are handled by fat with ->compat_ioctl,
+   but we don't want warnings on other file systems. So declare
+   them as compatible here. */
+#define VFAT_IOCTL_READDIR_BOTH32       _IOR('r', 1, struct compat_dirent[2])
+#define VFAT_IOCTL_READDIR_SHORT32      _IOR('r', 2, struct compat_dirent[2])
+
+IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
+IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
 };
 
-int ioctl_table_size = ARRAY_SIZE(ioctl_start);
+#define IOCTL_HASHSIZE 256
+static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
+
+static inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+	return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
+}
+
+static void compat_ioctl_error(struct file *filp, unsigned int fd,
+		unsigned int cmd, unsigned long arg)
+{
+	char buf[10];
+	char *fn = "?";
+	char *path;
+
+	/* find the name of the device. */
+	path = (char *)__get_free_page(GFP_KERNEL);
+	if (path) {
+		fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
+		if (IS_ERR(fn))
+			fn = "?";
+	}
+
+	 sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK);
+	if (!isprint(buf[1]))
+		sprintf(buf, "%02x", buf[1]);
+	compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+			"cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n",
+			current->comm, current->pid,
+			(int)fd, (unsigned int)cmd, buf,
+			(cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK,
+			(unsigned int)arg, fn);
+
+	if (path)
+		free_page((unsigned long)path);
+}
+
+asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
+				unsigned long arg)
+{
+	struct file *filp;
+	int error = -EBADF;
+	struct ioctl_trans *t;
+	int fput_needed;
+
+	filp = fget_light(fd, &fput_needed);
+	if (!filp)
+		goto out;
+
+	/* RED-PEN how should LSM module know it's handling 32bit? */
+	error = security_file_ioctl(filp, cmd, arg);
+	if (error)
+		goto out_fput;
+
+	/*
+	 * To allow the compat_ioctl handlers to be self contained
+	 * we need to check the common ioctls here first.
+	 * Just handle them with the standard handlers below.
+	 */
+	switch (cmd) {
+	case FIOCLEX:
+	case FIONCLEX:
+	case FIONBIO:
+	case FIOASYNC:
+	case FIOQSIZE:
+		break;
+
+	case FIBMAP:
+	case FIGETBSZ:
+	case FIONREAD:
+		if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
+			break;
+		/*FALL THROUGH*/
+
+	default:
+		if (filp->f_op && filp->f_op->compat_ioctl) {
+			error = filp->f_op->compat_ioctl(filp, cmd, arg);
+			if (error != -ENOIOCTLCMD)
+				goto out_fput;
+		}
+
+		if (!filp->f_op ||
+		    (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl))
+			goto do_ioctl;
+		break;
+	}
+
+	for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
+		if (t->cmd == cmd)
+			goto found_handler;
+	}
+
+	if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
+	    cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
+		error = siocdevprivate_ioctl(fd, cmd, arg);
+	} else {
+		static int count;
+
+		if (++count <= 50)
+			compat_ioctl_error(filp, fd, cmd, arg);
+		error = -EINVAL;
+	}
+
+	goto out_fput;
+
+ found_handler:
+	if (t->handler) {
+		lock_kernel();
+		error = t->handler(fd, cmd, arg, filp);
+		unlock_kernel();
+		goto out_fput;
+	}
+
+ do_ioctl:
+	error = vfs_ioctl(filp, fd, cmd, arg);
+ out_fput:
+	fput_light(filp, fput_needed);
+ out:
+	return error;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+	unsigned long hash;
+	struct ioctl_trans *t;
+
+	hash = ioctl32_hash (trans->cmd);
+	if (!ioctl32_hash_table[hash])
+		ioctl32_hash_table[hash] = trans;
+	else {
+		t = ioctl32_hash_table[hash];
+		while (t->next)
+			t = t->next;
+		trans->next = NULL;
+		t->next = trans;
+	}
+}
+
+static int __init init_sys32_ioctl(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
+		if (ioctl_start[i].next != 0) {
+			printk("ioctl translation %d bad\n",i);
+			return -1;
+		}
+
+		ioctl32_insert_translation(&ioctl_start[i]);
+	}
+	return 0;
+}
+__initcall(init_sys32_ioctl);
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 6f57300..b00d962 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -140,7 +140,7 @@ static int __init configfs_init(void)
 	if (!configfs_dir_cachep)
 		goto out;
 
-	kset_set_kset_s(&config_subsys, kernel_subsys);
+	kobj_set_kset_s(&config_subsys, kernel_subsys);
 	err = subsystem_register(&config_subsys);
 	if (err) {
 		kmem_cache_destroy(configfs_dir_cachep);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index facd0c8..3d194a2 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -180,7 +180,8 @@ static void *cramfs_read(struct super_bl
 		struct page *page = NULL;
 
 		if (blocknr + i < devsize) {
-			page = read_mapping_page(mapping, blocknr + i, NULL);
+			page = read_mapping_page_async(mapping, blocknr + i,
+									NULL);
 			/* synchronous error? */
 			if (IS_ERR(page))
 				page = NULL;
diff --git a/fs/dcache.c b/fs/dcache.c
index d68631f..0e73aa0 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -21,7 +21,6 @@ #include <linux/fs.h>
 #include <linux/fsnotify.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/hash.h>
 #include <linux/cache.h>
 #include <linux/module.h>
@@ -121,6 +120,28 @@ static void dentry_iput(struct dentry * 
 	}
 }
 
+/**
+ * d_kill - kill dentry and return parent
+ * @dentry: dentry to kill
+ *
+ * Called with dcache_lock and d_lock, releases both.  The dentry must
+ * already be unhashed and removed from the LRU.
+ *
+ * If this is the root of the dentry tree, return NULL.
+ */
+static struct dentry *d_kill(struct dentry *dentry)
+{
+	struct dentry *parent;
+
+	list_del(&dentry->d_u.d_child);
+	dentry_stat.nr_dentry--;	/* For d_free, below */
+	/*drops the locks, at that point nobody can reach this dentry */
+	dentry_iput(dentry);
+	parent = dentry->d_parent;
+	d_free(dentry);
+	return dentry == parent ? NULL : parent;
+}
+
 /* 
  * This is dput
  *
@@ -189,28 +210,17 @@ repeat:
 
 unhash_it:
 	__d_drop(dentry);
-
-kill_it: {
-		struct dentry *parent;
-
-		/* If dentry was on d_lru list
-		 * delete it from there
-		 */
-  		if (!list_empty(&dentry->d_lru)) {
-  			list_del(&dentry->d_lru);
-  			dentry_stat.nr_unused--;
-  		}
-  		list_del(&dentry->d_u.d_child);
-		dentry_stat.nr_dentry--;	/* For d_free, below */
-		/*drops the locks, at that point nobody can reach this dentry */
-		dentry_iput(dentry);
-		parent = dentry->d_parent;
-		d_free(dentry);
-		if (dentry == parent)
-			return;
-		dentry = parent;
-		goto repeat;
+kill_it:
+	/* If dentry was on d_lru list
+	 * delete it from there
+	 */
+	if (!list_empty(&dentry->d_lru)) {
+		list_del(&dentry->d_lru);
+		dentry_stat.nr_unused--;
 	}
+	dentry = d_kill(dentry);
+	if (dentry)
+		goto repeat;
 }
 
 /**
@@ -371,22 +381,40 @@ restart:
  * Throw away a dentry - free the inode, dput the parent.  This requires that
  * the LRU list has already been removed.
  *
+ * If prune_parents is true, try to prune ancestors as well.
+ *
  * Called with dcache_lock, drops it and then regains.
  * Called with dentry->d_lock held, drops it.
  */
-static void prune_one_dentry(struct dentry * dentry)
+static void prune_one_dentry(struct dentry * dentry, int prune_parents)
 {
-	struct dentry * parent;
-
 	__d_drop(dentry);
-	list_del(&dentry->d_u.d_child);
-	dentry_stat.nr_dentry--;	/* For d_free, below */
-	dentry_iput(dentry);
-	parent = dentry->d_parent;
-	d_free(dentry);
-	if (parent != dentry)
-		dput(parent);
+	dentry = d_kill(dentry);
+	if (!prune_parents) {
+		dput(dentry);
+		spin_lock(&dcache_lock);
+		return;
+	}
+
+	/*
+	 * Prune ancestors.  Locking is simpler than in dput(),
+	 * because dcache_lock needs to be taken anyway.
+	 */
 	spin_lock(&dcache_lock);
+	while (dentry) {
+		if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
+			return;
+
+		if (dentry->d_op && dentry->d_op->d_delete)
+			dentry->d_op->d_delete(dentry);
+		if (!list_empty(&dentry->d_lru)) {
+			list_del(&dentry->d_lru);
+			dentry_stat.nr_unused--;
+		}
+		__d_drop(dentry);
+		dentry = d_kill(dentry);
+		spin_lock(&dcache_lock);
+	}
 }
 
 /**
@@ -394,6 +422,7 @@ static void prune_one_dentry(struct dent
  * @count: number of entries to try and free
  * @sb: if given, ignore dentries for other superblocks
  *         which are being unmounted.
+ * @prune_parents: if true, try to prune ancestors as well in one go
  *
  * Shrink the dcache. This is done when we need
  * more memory, or simply when we need to unmount
@@ -404,7 +433,7 @@ static void prune_one_dentry(struct dent
  * all the dentries are in use.
  */
  
-static void prune_dcache(int count, struct super_block *sb)
+static void prune_dcache(int count, struct super_block *sb, int prune_parents)
 {
 	spin_lock(&dcache_lock);
 	for (; count ; count--) {
@@ -464,7 +493,7 @@ static void prune_dcache(int count, stru
 		 * without taking the s_umount lock (I already hold it).
 		 */
 		if (sb && dentry->d_sb == sb) {
-			prune_one_dentry(dentry);
+			prune_one_dentry(dentry, prune_parents);
 			continue;
 		}
 		/*
@@ -479,7 +508,7 @@ static void prune_dcache(int count, stru
 		s_umount = &dentry->d_sb->s_umount;
 		if (down_read_trylock(s_umount)) {
 			if (dentry->d_sb->s_root != NULL) {
-				prune_one_dentry(dentry);
+				prune_one_dentry(dentry, prune_parents);
 				up_read(s_umount);
 				continue;
 			}
@@ -550,7 +579,7 @@ repeat:
 			spin_unlock(&dentry->d_lock);
 			continue;
 		}
-		prune_one_dentry(dentry);
+		prune_one_dentry(dentry, 1);
 		cond_resched_lock(&dcache_lock);
 		goto repeat;
 	}
@@ -829,7 +858,7 @@ void shrink_dcache_parent(struct dentry 
 	int found;
 
 	while ((found = select_parent(parent)) != 0)
-		prune_dcache(found, parent->d_sb);
+		prune_dcache(found, parent->d_sb, 1);
 }
 
 /*
@@ -849,7 +878,7 @@ static int shrink_dcache_memory(int nr, 
 	if (nr) {
 		if (!(gfp_mask & __GFP_FS))
 			return -1;
-		prune_dcache(nr, NULL);
+		prune_dcache(nr, NULL, 1);
 	}
 	return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
 }
@@ -1823,6 +1852,16 @@ char * d_path(struct dentry *dentry, str
 	struct vfsmount *rootmnt;
 	struct dentry *root;
 
+	/*
+	 * We have various synthetic filesystems that never get mounted.  On
+	 * these filesystems dentries are never used for lookup purposes, and
+	 * thus don't need to be hashed.  They also don't need a name until a
+	 * user wants to identify the object in /proc/pid/fd/.  The little hack
+	 * below allows us to generate a name for these objects on demand:
+	 */
+	if (dentry->d_op && dentry->d_op->d_dname)
+		return dentry->d_op->d_dname(dentry, buf, buflen);
+
 	read_lock(&current->fs->lock);
 	rootmnt = mntget(current->fs->rootmnt);
 	root = dget(current->fs->root);
@@ -1836,6 +1875,27 @@ char * d_path(struct dentry *dentry, str
 }
 
 /*
+ * Helper function for dentry_operations.d_dname() members
+ */
+char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
+			const char *fmt, ...)
+{
+	va_list args;
+	char temp[64];
+	int sz;
+
+	va_start(args, fmt);
+	sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
+	va_end(args);
+
+	if (sz > sizeof(temp) || sz > buflen)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	buffer += buflen - sz;
+	return memcpy(buffer, temp, sz);
+}
+
+/*
  * NOTE! The user-level library version returns a
  * character pointer. The kernel system call just
  * returns the length of the buffer filled (which
@@ -2052,12 +2112,8 @@ static void __init dcache_init(unsigned 
 	 * but it is probably not worth it because of the cache nature
 	 * of the dcache. 
 	 */
-	dentry_cache = kmem_cache_create("dentry_cache",
-					 sizeof(struct dentry),
-					 0,
-					 (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
-					 SLAB_MEM_SPREAD),
-					 NULL, NULL);
+	dentry_cache = KMEM_CACHE(dentry,
+		SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
 	
 	set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
 
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 682f928..2e124e0 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -179,6 +179,48 @@ struct dentry *debugfs_create_u32(const 
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
 
+static void debugfs_u64_set(void *data, u64 val)
+{
+	*(u64 *)data = val;
+}
+
+static u64 debugfs_u64_get(void *data)
+{
+	return *(u64 *)data;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+
+/**
+ * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-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 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.
+ *
+ * This function creates a file in debugfs with the given name that
+ * contains the value of the variable @value.  If the @mode variable is so
+ * set, it can be read from, and written to.
+ *
+ * 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.
+ *
+ * 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
+ * code.
+ */
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+				 struct dentry *parent, u64 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_u64);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_u64);
+
 static ssize_t read_file_bool(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 7b324cf..ec8896b 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -374,7 +374,7 @@ static int __init debugfs_init(void)
 {
 	int retval;
 
-	kset_set_kset_s(&debug_subsys, kernel_subsys);
+	kobj_set_kset_s(&debug_subsys, kernel_subsys);
 	retval = subsystem_register(&debug_subsys);
 	if (retval)
 		return retval;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 643e57b..06ef9a2 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -19,6 +19,7 @@ #include <linux/mount.h>
 #include <linux/tty.h>
 #include <linux/devpts_fs.h>
 #include <linux/parser.h>
+#include <linux/fsnotify.h>
 
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
@@ -178,8 +179,10 @@ int devpts_pty_new(struct tty_struct *tt
 	inode->i_private = tty;
 
 	dentry = get_node(number);
-	if (!IS_ERR(dentry) && !dentry->d_inode)
+	if (!IS_ERR(dentry) && !dentry->d_inode) {
 		d_instantiate(dentry, inode);
+		fsnotify_create(devpts_root->d_inode, dentry);
+	}
 
 	mutex_unlock(&devpts_root->d_inode->i_mutex);
 
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
index 6fa7b0d..69a9469 100644
--- a/fs/dlm/Kconfig
+++ b/fs/dlm/Kconfig
@@ -3,36 +3,19 @@ menu "Distributed Lock Manager"
 
 config DLM
 	tristate "Distributed Lock Manager (DLM)"
-	depends on SYSFS && (IPV6 || IPV6=n)
+	depends on IPV6 || IPV6=n
 	select CONFIGFS_FS
-	select IP_SCTP if DLM_SCTP
+	select IP_SCTP
 	help
-	  A general purpose distributed lock manager for kernel or userspace
-	  applications.
-
-choice
-	prompt "Select DLM communications protocol"
-	depends on DLM
-	default DLM_TCP
-	help
-	  The DLM Can use TCP or SCTP for it's network communications.
-	  SCTP supports multi-homed operations whereas TCP doesn't.
-	  However, SCTP seems to have stability problems at the moment.
-
-config DLM_TCP
-	bool "TCP/IP"
-
-config DLM_SCTP
-	bool "SCTP"
-
-endchoice
+	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.
+	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
index 6538894..604cf7d 100644
--- a/fs/dlm/Makefile
+++ b/fs/dlm/Makefile
@@ -8,14 +8,12 @@ dlm-y :=			ast.o \
 				member.o \
 				memory.o \
 				midcomms.o \
+				lowcomms.o \
 				rcom.o \
 				recover.o \
 				recoverd.o \
 				requestqueue.o \
 				user.o \
-				util.o
+				util.o 
 dlm-$(CONFIG_DLM_DEBUG) +=	debug_fs.o
 
-dlm-$(CONFIG_DLM_TCP)   += lowcomms-tcp.o
-
-dlm-$(CONFIG_DLM_SCTP)  += lowcomms-sctp.o
\ No newline at end of file
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index f91d39c..6308122 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -14,6 +14,7 @@
 #include "dlm_internal.h"
 #include "lock.h"
 #include "user.h"
+#include "ast.h"
 
 #define WAKE_ASTS  0
 
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 8665c88..822abdc 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 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
@@ -89,6 +89,7 @@ struct cluster {
 	unsigned int cl_toss_secs;
 	unsigned int cl_scan_secs;
 	unsigned int cl_log_debug;
+	unsigned int cl_protocol;
 };
 
 enum {
@@ -101,6 +102,7 @@ enum {
 	CLUSTER_ATTR_TOSS_SECS,
 	CLUSTER_ATTR_SCAN_SECS,
 	CLUSTER_ATTR_LOG_DEBUG,
+	CLUSTER_ATTR_PROTOCOL,
 };
 
 struct cluster_attribute {
@@ -159,6 +161,7 @@ CLUSTER_ATTR(recover_timer, 1);
 CLUSTER_ATTR(toss_secs, 1);
 CLUSTER_ATTR(scan_secs, 1);
 CLUSTER_ATTR(log_debug, 0);
+CLUSTER_ATTR(protocol, 0);
 
 static struct configfs_attribute *cluster_attrs[] = {
 	[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -170,6 +173,7 @@ static struct configfs_attribute *cluste
 	[CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
 	[CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
 	[CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
+	[CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
 	NULL,
 };
 
@@ -904,6 +908,7 @@ #define DEFAULT_RECOVER_TIMER      5
 #define DEFAULT_TOSS_SECS         10
 #define DEFAULT_SCAN_SECS          5
 #define DEFAULT_LOG_DEBUG          0
+#define DEFAULT_PROTOCOL           0
 
 struct dlm_config_info dlm_config = {
 	.ci_tcp_port = DEFAULT_TCP_PORT,
@@ -914,6 +919,7 @@ struct dlm_config_info dlm_config = {
 	.ci_recover_timer = DEFAULT_RECOVER_TIMER,
 	.ci_toss_secs = DEFAULT_TOSS_SECS,
 	.ci_scan_secs = DEFAULT_SCAN_SECS,
-	.ci_log_debug = DEFAULT_LOG_DEBUG
+	.ci_log_debug = DEFAULT_LOG_DEBUG,
+	.ci_protocol = DEFAULT_PROTOCOL
 };
 
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 1e97861..967cc3d 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 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
@@ -26,6 +26,7 @@ struct dlm_config_info {
 	int ci_toss_secs;
 	int ci_scan_secs;
 	int ci_log_debug;
+	int ci_protocol;
 };
 
 extern struct dlm_config_info dlm_config;
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 61d9320..30994d6 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 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
@@ -210,6 +210,9 @@ #define DLM_LKSTS_CONVERT	3
 #define DLM_IFL_MSTCPY		0x00010000
 #define DLM_IFL_RESEND		0x00020000
 #define DLM_IFL_DEAD		0x00040000
+#define DLM_IFL_OVERLAP_UNLOCK  0x00080000
+#define DLM_IFL_OVERLAP_CANCEL  0x00100000
+#define DLM_IFL_ENDOFLIFE	0x00200000
 #define DLM_IFL_USER		0x00000001
 #define DLM_IFL_ORPHAN		0x00000002
 
@@ -230,8 +233,8 @@ struct dlm_lkb {
 	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_wait_count;
 	int8_t			lkb_ast_type;	/* type of ast queued for */
 
 	struct list_head	lkb_idtbl_list;	/* lockspace lkbtbl */
@@ -339,6 +342,7 @@ #define DLM_MSG_BAST		10
 #define DLM_MSG_LOOKUP		11
 #define DLM_MSG_REMOVE		12
 #define DLM_MSG_LOOKUP_REPLY	13
+#define DLM_MSG_PURGE		14
 
 struct dlm_message {
 	struct dlm_header	m_header;
@@ -440,6 +444,9 @@ struct dlm_ls {
 	struct mutex		ls_waiters_mutex;
 	struct list_head	ls_waiters;	/* lkbs needing a reply */
 
+	struct mutex		ls_orphans_mutex;
+	struct list_head	ls_orphans;
+
 	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 */
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index e725005..d8d6e72 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 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
@@ -85,6 +85,7 @@ static int _request_lock(struct dlm_rsb 
 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);
+static void do_purge(struct dlm_ls *ls, int nodeid, int pid);
 
 /*
  * Lock compatibilty matrix - thanks Steve
@@ -223,6 +224,16 @@ static inline int is_demoted(struct dlm_
 	return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
 }
 
+static inline int is_altmode(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_sbflags & DLM_SBF_ALTMODE);
+}
+
+static inline int is_granted(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_status == DLM_LKSTS_GRANTED);
+}
+
 static inline int is_remote(struct dlm_rsb *r)
 {
 	DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
@@ -254,6 +265,22 @@ static inline int down_conversion(struct
 	return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
 }
 
+static inline int is_overlap_unlock(struct dlm_lkb *lkb)
+{
+	return lkb->lkb_flags & DLM_IFL_OVERLAP_UNLOCK;
+}
+
+static inline int is_overlap_cancel(struct dlm_lkb *lkb)
+{
+	return lkb->lkb_flags & DLM_IFL_OVERLAP_CANCEL;
+}
+
+static inline int is_overlap(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_flags & (DLM_IFL_OVERLAP_UNLOCK |
+				  DLM_IFL_OVERLAP_CANCEL));
+}
+
 static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
 {
 	if (is_master_copy(lkb))
@@ -267,6 +294,12 @@ static void queue_cast(struct dlm_rsb *r
 	dlm_add_ast(lkb, AST_COMP);
 }
 
+static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	queue_cast(r, lkb,
+		   is_overlap_unlock(lkb) ? -DLM_EUNLOCK : -DLM_ECANCEL);
+}
+
 static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
 {
 	if (is_master_copy(lkb))
@@ -547,6 +580,7 @@ static int create_lkb(struct dlm_ls *ls,
 	lkb->lkb_grmode = DLM_LOCK_IV;
 	kref_init(&lkb->lkb_ref);
 	INIT_LIST_HEAD(&lkb->lkb_ownqueue);
+	INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
 
 	get_random_bytes(&bucket, sizeof(bucket));
 	bucket &= (ls->ls_lkbtbl_size - 1);
@@ -556,7 +590,7 @@ static int create_lkb(struct dlm_ls *ls,
 	/* counter can roll over so we must verify lkid is not in use */
 
 	while (lkid == 0) {
-		lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
+		lkid = (bucket << 16) | ls->ls_lkbtbl[bucket].counter++;
 
 		list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
 				    lkb_idtbl_list) {
@@ -577,8 +611,8 @@ static int create_lkb(struct dlm_ls *ls,
 
 static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
 {
-	uint16_t bucket = lkid & 0xFFFF;
 	struct dlm_lkb *lkb;
+	uint16_t bucket = (lkid >> 16);
 
 	list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
 		if (lkb->lkb_id == lkid)
@@ -590,7 +624,7 @@ static struct dlm_lkb *__find_lkb(struct
 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;
+	uint16_t bucket = (lkid >> 16);
 
 	if (bucket >= ls->ls_lkbtbl_size)
 		return -EBADSLT;
@@ -620,7 +654,7 @@ static void kill_lkb(struct kref *kref)
 
 static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
 {
-	uint16_t bucket = lkb->lkb_id & 0xFFFF;
+	uint16_t bucket = (lkb->lkb_id >> 16);
 
 	write_lock(&ls->ls_lkbtbl[bucket].lock);
 	if (kref_put(&lkb->lkb_ref, kill_lkb)) {
@@ -735,23 +769,75 @@ static void move_lkb(struct dlm_rsb *r, 
 	unhold_lkb(lkb);
 }
 
+static int msg_reply_type(int mstype)
+{
+	switch (mstype) {
+	case DLM_MSG_REQUEST:
+		return DLM_MSG_REQUEST_REPLY;
+	case DLM_MSG_CONVERT:
+		return DLM_MSG_CONVERT_REPLY;
+	case DLM_MSG_UNLOCK:
+		return DLM_MSG_UNLOCK_REPLY;
+	case DLM_MSG_CANCEL:
+		return DLM_MSG_CANCEL_REPLY;
+	case DLM_MSG_LOOKUP:
+		return DLM_MSG_LOOKUP_REPLY;
+	}
+	return -1;
+}
+
 /* 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)
+static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
 {
 	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	int error = 0;
 
 	mutex_lock(&ls->ls_waiters_mutex);
-	if (lkb->lkb_wait_type) {
-		log_print("add_to_waiters error %d", lkb->lkb_wait_type);
+
+	if (is_overlap_unlock(lkb) ||
+	    (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL))) {
+		error = -EINVAL;
+		goto out;
+	}
+
+	if (lkb->lkb_wait_type || is_overlap_cancel(lkb)) {
+		switch (mstype) {
+		case DLM_MSG_UNLOCK:
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+			break;
+		case DLM_MSG_CANCEL:
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+			break;
+		default:
+			error = -EBUSY;
+			goto out;
+		}
+		lkb->lkb_wait_count++;
+		hold_lkb(lkb);
+
+		log_debug(ls, "add overlap %x cur %d new %d count %d flags %x",
+			  lkb->lkb_id, lkb->lkb_wait_type, mstype,
+			  lkb->lkb_wait_count, lkb->lkb_flags);
 		goto out;
 	}
+
+	DLM_ASSERT(!lkb->lkb_wait_count,
+		   dlm_print_lkb(lkb);
+		   printk("wait_count %d\n", lkb->lkb_wait_count););
+
+	lkb->lkb_wait_count++;
 	lkb->lkb_wait_type = mstype;
-	kref_get(&lkb->lkb_ref);
+	hold_lkb(lkb);
 	list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
  out:
+	if (error)
+		log_error(ls, "add_to_waiters %x error %d flags %x %d %d %s",
+			  lkb->lkb_id, error, lkb->lkb_flags, mstype,
+			  lkb->lkb_wait_type, lkb->lkb_resource->res_name);
 	mutex_unlock(&ls->ls_waiters_mutex);
+	return error;
 }
 
 /* We clear the RESEND flag because we might be taking an lkb off the waiters
@@ -759,34 +845,85 @@ static void add_to_waiters(struct dlm_lk
    request reply on the requestqueue) between dlm_recover_waiters_pre() which
    set RESEND and dlm_recover_waiters_post() */
 
-static int _remove_from_waiters(struct dlm_lkb *lkb)
+static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype)
 {
-	int error = 0;
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	int overlap_done = 0;
 
-	if (!lkb->lkb_wait_type) {
-		log_print("remove_from_waiters error");
-		error = -EINVAL;
-		goto out;
+	if (is_overlap_unlock(lkb) && (mstype == DLM_MSG_UNLOCK_REPLY)) {
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+		overlap_done = 1;
+		goto out_del;
+	}
+
+	if (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL_REPLY)) {
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+		overlap_done = 1;
+		goto out_del;
+	}
+
+	/* N.B. type of reply may not always correspond to type of original
+	   msg due to lookup->request optimization, verify others? */
+
+	if (lkb->lkb_wait_type) {
+		lkb->lkb_wait_type = 0;
+		goto out_del;
+	}
+
+	log_error(ls, "remove_from_waiters lkid %x flags %x types %d %d",
+		  lkb->lkb_id, lkb->lkb_flags, mstype, lkb->lkb_wait_type);
+	return -1;
+
+ out_del:
+	/* the force-unlock/cancel has completed and we haven't recvd a reply
+	   to the op that was in progress prior to the unlock/cancel; we
+	   give up on any reply to the earlier op.  FIXME: not sure when/how
+	   this would happen */
+
+	if (overlap_done && lkb->lkb_wait_type) {
+		log_error(ls, "remove_from_waiters %x reply %d give up on %d",
+			  lkb->lkb_id, mstype, lkb->lkb_wait_type);
+		lkb->lkb_wait_count--;
+		lkb->lkb_wait_type = 0;
 	}
-	lkb->lkb_wait_type = 0;
+
+	DLM_ASSERT(lkb->lkb_wait_count, dlm_print_lkb(lkb););
+
 	lkb->lkb_flags &= ~DLM_IFL_RESEND;
-	list_del(&lkb->lkb_wait_reply);
+	lkb->lkb_wait_count--;
+	if (!lkb->lkb_wait_count)
+		list_del_init(&lkb->lkb_wait_reply);
 	unhold_lkb(lkb);
- out:
-	return error;
+	return 0;
 }
 
-static int remove_from_waiters(struct dlm_lkb *lkb)
+static int remove_from_waiters(struct dlm_lkb *lkb, int mstype)
 {
 	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
 	int error;
 
 	mutex_lock(&ls->ls_waiters_mutex);
-	error = _remove_from_waiters(lkb);
+	error = _remove_from_waiters(lkb, mstype);
 	mutex_unlock(&ls->ls_waiters_mutex);
 	return error;
 }
 
+/* Handles situations where we might be processing a "fake" or "stub" reply in
+   which we can't try to take waiters_mutex again. */
+
+static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	int error;
+
+	if (ms != &ls->ls_stub_ms)
+		mutex_lock(&ls->ls_waiters_mutex);
+	error = _remove_from_waiters(lkb, ms->m_type);
+	if (ms != &ls->ls_stub_ms)
+		mutex_unlock(&ls->ls_waiters_mutex);
+	return error;
+}
+
 static void dir_remove(struct dlm_rsb *r)
 {
 	int to_nodeid;
@@ -988,8 +1125,14 @@ static void remove_lock_pc(struct dlm_rs
 	_remove_lock(r, lkb);
 }
 
-static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+/* returns: 0 did nothing
+	    1 moved lock to granted
+	   -1 removed lock */
+
+static int revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
+	int rv = 0;
+
 	lkb->lkb_rqmode = DLM_LOCK_IV;
 
 	switch (lkb->lkb_status) {
@@ -997,6 +1140,7 @@ static void revert_lock(struct dlm_rsb *
 		break;
 	case DLM_LKSTS_CONVERT:
 		move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+		rv = 1;
 		break;
 	case DLM_LKSTS_WAITING:
 		del_lkb(r, lkb);
@@ -1004,15 +1148,17 @@ static void revert_lock(struct dlm_rsb *
 		/* this unhold undoes the original ref from create_lkb()
 		   so this leads to the lkb being freed */
 		unhold_lkb(lkb);
+		rv = -1;
 		break;
 	default:
 		log_print("invalid status for revert %d", lkb->lkb_status);
 	}
+	return rv;
 }
 
-static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+static int revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
 {
-	revert_lock(r, lkb);
+	return revert_lock(r, lkb);
 }
 
 static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -1055,6 +1201,50 @@ static void grant_lock_pending(struct dl
 		queue_cast(r, lkb, 0);
 }
 
+/* The special CONVDEADLK, ALTPR and ALTCW flags allow the master to
+   change the granted/requested modes.  We're munging things accordingly in
+   the process copy.
+   CONVDEADLK: our grmode may have been forced down to NL to resolve a
+   conversion deadlock
+   ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
+   compatible with other granted locks */
+
+static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	if (ms->m_type != DLM_MSG_CONVERT_REPLY) {
+		log_print("munge_demoted %x invalid reply type %d",
+			  lkb->lkb_id, ms->m_type);
+		return;
+	}
+
+	if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
+		log_print("munge_demoted %x invalid modes gr %d rq %d",
+			  lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
+		return;
+	}
+
+	lkb->lkb_grmode = DLM_LOCK_NL;
+}
+
+static void munge_altmode(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	if (ms->m_type != DLM_MSG_REQUEST_REPLY &&
+	    ms->m_type != DLM_MSG_GRANT) {
+		log_print("munge_altmode %x invalid reply type %d",
+			  lkb->lkb_id, ms->m_type);
+		return;
+	}
+
+	if (lkb->lkb_exflags & DLM_LKF_ALTPR)
+		lkb->lkb_rqmode = DLM_LOCK_PR;
+	else if (lkb->lkb_exflags & DLM_LKF_ALTCW)
+		lkb->lkb_rqmode = DLM_LOCK_CW;
+	else {
+		log_print("munge_altmode invalid exflags %x", lkb->lkb_exflags);
+		dlm_print_lkb(lkb);
+	}
+}
+
 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,
@@ -1499,7 +1689,7 @@ static void process_lookup_list(struct d
 	struct dlm_lkb *lkb, *safe;
 
 	list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
-		list_del(&lkb->lkb_rsb_lookup);
+		list_del_init(&lkb->lkb_rsb_lookup);
 		_request_lock(r, lkb);
 		schedule();
 	}
@@ -1530,7 +1720,7 @@ static void confirm_master(struct dlm_rs
 		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);
+			list_del_init(&lkb->lkb_rsb_lookup);
 			r->res_first_lkid = lkb->lkb_id;
 			_request_lock(r, lkb);
 		} else
@@ -1614,6 +1804,9 @@ static int set_unlock_args(uint32_t flag
  		      DLM_LKF_FORCEUNLOCK))
 		return -EINVAL;
 
+	if (flags & DLM_LKF_CANCEL && flags & DLM_LKF_FORCEUNLOCK)
+		return -EINVAL;
+
 	args->flags = flags;
 	args->astparam = (long) astarg;
 	return 0;
@@ -1638,6 +1831,9 @@ static int validate_lock_args(struct dlm
 
 		if (lkb->lkb_wait_type)
 			goto out;
+
+		if (is_overlap(lkb))
+			goto out;
 	}
 
 	lkb->lkb_exflags = args->flags;
@@ -1654,35 +1850,126 @@ static int validate_lock_args(struct dlm
 	return rv;
 }
 
+/* when dlm_unlock() sees -EBUSY with CANCEL/FORCEUNLOCK it returns 0
+   for success */
+
+/* note: it's valid for lkb_nodeid/res_nodeid to be -1 when we get here
+   because there may be a lookup in progress and it's valid to do
+   cancel/unlockf on it */
+
 static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
 {
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
 	int rv = -EINVAL;
 
-	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+	if (lkb->lkb_flags & DLM_IFL_MSTCPY) {
+		log_error(ls, "unlock on MSTCPY %x", lkb->lkb_id);
+		dlm_print_lkb(lkb);
 		goto out;
+	}
 
-	if (args->flags & DLM_LKF_FORCEUNLOCK)
-		goto out_ok;
+	/* an lkb may still exist even though the lock is EOL'ed due to a
+	   cancel, unlock or failed noqueue request; an app can't use these
+	   locks; return same error as if the lkid had not been found at all */
 
-	if (args->flags & DLM_LKF_CANCEL &&
-	    lkb->lkb_status == DLM_LKSTS_GRANTED)
+	if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
+		log_debug(ls, "unlock on ENDOFLIFE %x", lkb->lkb_id);
+		rv = -ENOENT;
 		goto out;
+	}
 
-	if (!(args->flags & DLM_LKF_CANCEL) &&
-	    lkb->lkb_status != DLM_LKSTS_GRANTED)
-		goto out;
+	/* an lkb may be waiting for an rsb lookup to complete where the
+	   lookup was initiated by another lock */
+
+	if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {
+		if (!list_empty(&lkb->lkb_rsb_lookup)) {
+			log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id);
+			list_del_init(&lkb->lkb_rsb_lookup);
+			queue_cast(lkb->lkb_resource, lkb,
+				   args->flags & DLM_LKF_CANCEL ?
+				   -DLM_ECANCEL : -DLM_EUNLOCK);
+			unhold_lkb(lkb); /* undoes create_lkb() */
+			rv = -EBUSY;
+			goto out;
+		}
+	}
+
+	/* cancel not allowed with another cancel/unlock in progress */
+
+	if (args->flags & DLM_LKF_CANCEL) {
+		if (lkb->lkb_exflags & DLM_LKF_CANCEL)
+			goto out;
+
+		if (is_overlap(lkb))
+			goto out;
+
+		if (lkb->lkb_flags & DLM_IFL_RESEND) {
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+			rv = -EBUSY;
+			goto out;
+		}
+
+		switch (lkb->lkb_wait_type) {
+		case DLM_MSG_LOOKUP:
+		case DLM_MSG_REQUEST:
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+			rv = -EBUSY;
+			goto out;
+		case DLM_MSG_UNLOCK:
+		case DLM_MSG_CANCEL:
+			goto out;
+		}
+		/* add_to_waiters() will set OVERLAP_CANCEL */
+		goto out_ok;
+	}
+
+	/* do we need to allow a force-unlock if there's a normal unlock
+	   already in progress?  in what conditions could the normal unlock
+	   fail such that we'd want to send a force-unlock to be sure? */
+
+	if (args->flags & DLM_LKF_FORCEUNLOCK) {
+		if (lkb->lkb_exflags & DLM_LKF_FORCEUNLOCK)
+			goto out;
+
+		if (is_overlap_unlock(lkb))
+			goto out;
 
+		if (lkb->lkb_flags & DLM_IFL_RESEND) {
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+			rv = -EBUSY;
+			goto out;
+		}
+
+		switch (lkb->lkb_wait_type) {
+		case DLM_MSG_LOOKUP:
+		case DLM_MSG_REQUEST:
+			lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+			rv = -EBUSY;
+			goto out;
+		case DLM_MSG_UNLOCK:
+			goto out;
+		}
+		/* add_to_waiters() will set OVERLAP_UNLOCK */
+		goto out_ok;
+	}
+
+	/* normal unlock not allowed if there's any op in progress */
 	rv = -EBUSY;
-	if (lkb->lkb_wait_type)
+	if (lkb->lkb_wait_type || lkb->lkb_wait_count)
 		goto out;
 
  out_ok:
-	lkb->lkb_exflags = args->flags;
+	/* an overlapping op shouldn't blow away exflags from other op */
+	lkb->lkb_exflags |= args->flags;
 	lkb->lkb_sbflags = 0;
 	lkb->lkb_astparam = args->astparam;
-
 	rv = 0;
  out:
+	if (rv)
+		log_debug(ls, "validate_unlock_args %d %x %x %x %x %d %s", rv,
+			  lkb->lkb_id, lkb->lkb_flags, lkb->lkb_exflags,
+			  args->flags, lkb->lkb_wait_type,
+			  lkb->lkb_resource->res_name);
 	return rv;
 }
 
@@ -1732,9 +2019,24 @@ static int do_convert(struct dlm_rsb *r,
 		goto out;
 	}
 
-	if (can_be_queued(lkb)) {
-		if (is_demoted(lkb))
+	/* is_demoted() means the can_be_granted() above set the grmode
+	   to NL, and left us on the granted queue.  This auto-demotion
+	   (due to CONVDEADLK) might mean other locks, and/or this lock, are
+	   now grantable.  We have to try to grant other converting locks
+	   before we try again to grant this one. */
+
+	if (is_demoted(lkb)) {
+		grant_pending_convert(r, DLM_LOCK_IV);
+		if (_can_be_granted(r, lkb, 1)) {
+			grant_lock(r, lkb);
+			queue_cast(r, lkb, 0);
 			grant_pending_locks(r);
+			goto out;
+		}
+		/* else fall through and move to convert queue */
+	}
+
+	if (can_be_queued(lkb)) {
 		error = -EINPROGRESS;
 		del_lkb(r, lkb);
 		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
@@ -1759,17 +2061,19 @@ static int do_unlock(struct dlm_rsb *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. */
+/* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
  
 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;
+	int error;
+
+	error = revert_lock(r, lkb);
+	if (error) {
+		queue_cast(r, lkb, -DLM_ECANCEL);
+		grant_pending_locks(r);
+		return -DLM_ECANCEL;
+	}
+	return 0;
 }
 
 /*
@@ -2035,6 +2339,8 @@ int dlm_unlock(dlm_lockspace_t *lockspac
 
 	if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
 		error = 0;
+	if (error == -EBUSY && (flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)))
+		error = 0;
  out_put:
 	dlm_put_lkb(lkb);
  out:
@@ -2065,31 +2371,14 @@ int dlm_unlock(dlm_lockspace_t *lockspac
  * 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)
+static int _create_message(struct dlm_ls *ls, int mb_len,
+			   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
@@ -2104,7 +2393,7 @@ static int create_message(struct dlm_rsb
 	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_lockspace = 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;
@@ -2116,6 +2405,33 @@ static int create_message(struct dlm_rsb
 	return 0;
 }
 
+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)
+{
+	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;
+	}
+
+	return _create_message(r->res_ls, mb_len, to_nodeid, mstype,
+			       ms_ret, mh_ret);
+}
+
 /* further lowcomms enhancements or alternate implementations may make
    the return value from this function useful at some point */
 
@@ -2176,7 +2492,9 @@ static int send_common(struct dlm_rsb *r
 	struct dlm_mhandle *mh;
 	int to_nodeid, error;
 
-	add_to_waiters(lkb, mstype);
+	error = add_to_waiters(lkb, mstype);
+	if (error)
+		return error;
 
 	to_nodeid = r->res_nodeid;
 
@@ -2192,7 +2510,7 @@ static int send_common(struct dlm_rsb *r
 	return 0;
 
  fail:
-	remove_from_waiters(lkb);
+	remove_from_waiters(lkb, msg_reply_type(mstype));
 	return error;
 }
 
@@ -2209,7 +2527,8 @@ static int send_convert(struct dlm_rsb *
 
 	/* down conversions go without a reply from the master */
 	if (!error && down_conversion(lkb)) {
-		remove_from_waiters(lkb);
+		remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);
+		r->res_ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
 		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);
@@ -2280,7 +2599,9 @@ static int send_lookup(struct dlm_rsb *r
 	struct dlm_mhandle *mh;
 	int to_nodeid, error;
 
-	add_to_waiters(lkb, DLM_MSG_LOOKUP);
+	error = add_to_waiters(lkb, DLM_MSG_LOOKUP);
+	if (error)
+		return error;
 
 	to_nodeid = dlm_dir_nodeid(r);
 
@@ -2296,7 +2617,7 @@ static int send_lookup(struct dlm_rsb *r
 	return 0;
 
  fail:
-	remove_from_waiters(lkb);
+	remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
 	return error;
 }
 
@@ -2656,6 +2977,8 @@ static void receive_grant(struct dlm_ls 
 	lock_rsb(r);
 
 	receive_flags_reply(lkb, ms);
+	if (is_altmode(lkb))
+		munge_altmode(lkb, ms);
 	grant_lock_pc(r, lkb, ms);
 	queue_cast(r, lkb, 0);
 
@@ -2736,11 +3059,16 @@ static void receive_remove(struct dlm_ls
 	dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
 }
 
+static void receive_purge(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	do_purge(ls, ms->m_nodeid, ms->m_pid);
+}
+
 static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
-	int error, mstype;
+	int error, mstype, result;
 
 	error = find_lkb(ls, ms->m_remid, &lkb);
 	if (error) {
@@ -2749,20 +3077,15 @@ static void receive_request_reply(struct
 	}
 	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);
 
+	mstype = lkb->lkb_wait_type;
+	error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
+	if (error)
+		goto out;
+
 	/* 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) {
@@ -2770,14 +3093,15 @@ static void receive_request_reply(struct
 		lkb->lkb_nodeid = r->res_nodeid;
 	}
 
-	switch (error) {
+	/* this is the value returned from do_request() on the master */
+	result = ms->m_result;
+
+	switch (result) {
 	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 */
+		/* request would block (be queued) on remote master */
 		queue_cast(r, lkb, -EAGAIN);
 		confirm_master(r, -EAGAIN);
-		unhold_lkb(lkb);
+		unhold_lkb(lkb); /* undoes create_lkb() */
 		break;
 
 	case -EINPROGRESS:
@@ -2785,41 +3109,64 @@ static void receive_request_reply(struct
 		/* request was queued or granted on remote master */
 		receive_flags_reply(lkb, ms);
 		lkb->lkb_remid = ms->m_lkid;
-		if (error)
+		if (is_altmode(lkb))
+			munge_altmode(lkb, ms);
+		if (result)
 			add_lkb(r, lkb, DLM_LKSTS_WAITING);
 		else {
 			grant_lock_pc(r, lkb, ms);
 			queue_cast(r, lkb, 0);
 		}
-		confirm_master(r, error);
+		confirm_master(r, result);
 		break;
 
 	case -EBADR:
 	case -ENOTBLK:
 		/* find_rsb failed to find rsb or rsb wasn't master */
+		log_debug(ls, "receive_request_reply %x %x master diff %d %d",
+			  lkb->lkb_id, lkb->lkb_flags, r->res_nodeid, result);
 		r->res_nodeid = -1;
 		lkb->lkb_nodeid = -1;
-		_request_lock(r, lkb);
+
+		if (is_overlap(lkb)) {
+			/* we'll ignore error in cancel/unlock reply */
+			queue_cast_overlap(r, lkb);
+			unhold_lkb(lkb); /* undoes create_lkb() */
+		} else
+			_request_lock(r, lkb);
 		break;
 
 	default:
-		log_error(ls, "receive_request_reply error %d", error);
+		log_error(ls, "receive_request_reply %x error %d",
+			  lkb->lkb_id, result);
 	}
 
+	if (is_overlap_unlock(lkb) && (result == 0 || result == -EINPROGRESS)) {
+		log_debug(ls, "receive_request_reply %x result %d unlock",
+			  lkb->lkb_id, result);
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+		send_unlock(r, lkb);
+	} else if (is_overlap_cancel(lkb) && (result == -EINPROGRESS)) {
+		log_debug(ls, "receive_request_reply %x cancel", lkb->lkb_id);
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+		send_cancel(r, lkb);
+	} else {
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+	}
+ out:
 	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) {
+	switch (ms->m_result) {
 	case -EAGAIN:
 		/* convert would block (be queued) on remote master */
 		queue_cast(r, lkb, -EAGAIN);
@@ -2827,6 +3174,9 @@ static void __receive_convert_reply(stru
 
 	case -EINPROGRESS:
 		/* convert was queued on remote master */
+		receive_flags_reply(lkb, ms);
+		if (is_demoted(lkb))
+			munge_demoted(lkb, ms);
 		del_lkb(r, lkb);
 		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
 		break;
@@ -2834,24 +3184,33 @@ static void __receive_convert_reply(stru
 	case 0:
 		/* convert was granted on remote master */
 		receive_flags_reply(lkb, ms);
+		if (is_demoted(lkb))
+			munge_demoted(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);
+		log_error(r->res_ls, "receive_convert_reply %x error %d",
+			  lkb->lkb_id, ms->m_result);
 	}
 }
 
 static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
 {
 	struct dlm_rsb *r = lkb->lkb_resource;
+	int error;
 
 	hold_rsb(r);
 	lock_rsb(r);
 
-	__receive_convert_reply(r, lkb, ms);
+	/* stub reply can happen with waiters_mutex held */
+	error = remove_from_waiters_ms(lkb, ms);
+	if (error)
+		goto out;
 
+	__receive_convert_reply(r, lkb, ms);
+ out:
 	unlock_rsb(r);
 	put_rsb(r);
 }
@@ -2868,37 +3227,38 @@ static void receive_convert_reply(struct
 	}
 	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;
+	int error;
 
 	hold_rsb(r);
 	lock_rsb(r);
 
+	/* stub reply can happen with waiters_mutex held */
+	error = remove_from_waiters_ms(lkb, ms);
+	if (error)
+		goto out;
+
 	/* this is the value returned from do_unlock() on the master */
 
-	switch (error) {
+	switch (ms->m_result) {
 	case -DLM_EUNLOCK:
 		receive_flags_reply(lkb, ms);
 		remove_lock_pc(r, lkb);
 		queue_cast(r, lkb, -DLM_EUNLOCK);
 		break;
+	case -ENOENT:
+		break;
 	default:
-		log_error(r->res_ls, "receive_unlock_reply error %d", error);
+		log_error(r->res_ls, "receive_unlock_reply %x error %d",
+			  lkb->lkb_id, ms->m_result);
 	}
-
+ out:
 	unlock_rsb(r);
 	put_rsb(r);
 }
@@ -2915,37 +3275,39 @@ static void receive_unlock_reply(struct 
 	}
 	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;
+	int error;
 
 	hold_rsb(r);
 	lock_rsb(r);
 
+	/* stub reply can happen with waiters_mutex held */
+	error = remove_from_waiters_ms(lkb, ms);
+	if (error)
+		goto out;
+
 	/* this is the value returned from do_cancel() on the master */
 
-	switch (error) {
+	switch (ms->m_result) {
 	case -DLM_ECANCEL:
 		receive_flags_reply(lkb, ms);
 		revert_lock_pc(r, lkb);
-		queue_cast(r, lkb, -DLM_ECANCEL);
+		if (ms->m_result)
+			queue_cast(r, lkb, -DLM_ECANCEL);
+		break;
+	case 0:
 		break;
 	default:
-		log_error(r->res_ls, "receive_cancel_reply error %d", error);
+		log_error(r->res_ls, "receive_cancel_reply %x error %d",
+			  lkb->lkb_id, ms->m_result);
 	}
-
+ out:
 	unlock_rsb(r);
 	put_rsb(r);
 }
@@ -2962,14 +3324,7 @@ static void receive_cancel_reply(struct 
 	}
 	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);
 }
 
@@ -2985,20 +3340,17 @@ static void receive_lookup_reply(struct 
 		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
+	/* ms->m_result 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);
 
+	error = remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
+	if (error)
+		goto out;
+
 	ret_nodeid = ms->m_nodeid;
 	if (ret_nodeid == dlm_our_nodeid()) {
 		r->res_nodeid = 0;
@@ -3009,14 +3361,22 @@ static void receive_lookup_reply(struct 
 		r->res_nodeid = ret_nodeid;
 	}
 
+	if (is_overlap(lkb)) {
+		log_debug(ls, "receive_lookup_reply %x unlock %x",
+			  lkb->lkb_id, lkb->lkb_flags);
+		queue_cast_overlap(r, lkb);
+		unhold_lkb(lkb); /* undoes create_lkb() */
+		goto out_list;
+	}
+
 	_request_lock(r, lkb);
 
+ out_list:
 	if (!ret_nodeid)
 		process_lookup_list(r);
-
+ out:
 	unlock_rsb(r);
 	put_rsb(r);
- out:
 	dlm_put_lkb(lkb);
 }
 
@@ -3133,6 +3493,12 @@ int dlm_receive_message(struct dlm_heade
 		receive_lookup_reply(ls, ms);
 		break;
 
+	/* other messages */
+
+	case DLM_MSG_PURGE:
+		receive_purge(ls, ms);
+		break;
+
 	default:
 		log_error(ls, "unknown message type %d", ms->m_type);
 	}
@@ -3153,9 +3519,9 @@ static void recover_convert_waiter(struc
 {
 	if (middle_conversion(lkb)) {
 		hold_lkb(lkb);
+		ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
 		ls->ls_stub_ms.m_result = -EINPROGRESS;
 		ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-		_remove_from_waiters(lkb);
 		_receive_convert_reply(lkb, &ls->ls_stub_ms);
 
 		/* Same special case as in receive_rcom_lock_args() */
@@ -3227,18 +3593,18 @@ void dlm_recover_waiters_pre(struct dlm_
 
 		case DLM_MSG_UNLOCK:
 			hold_lkb(lkb);
+			ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;
 			ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
 			ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-			_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_type = DLM_MSG_CANCEL_REPLY;
 			ls->ls_stub_ms.m_result = -DLM_ECANCEL;
 			ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-			_remove_from_waiters(lkb);
 			_receive_cancel_reply(lkb, &ls->ls_stub_ms);
 			dlm_put_lkb(lkb);
 			break;
@@ -3252,37 +3618,47 @@ void dlm_recover_waiters_pre(struct dlm_
 	mutex_unlock(&ls->ls_waiters_mutex);
 }
 
-static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
 {
 	struct dlm_lkb *lkb;
-	int rv = 0;
+	int found = 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;
+			hold_lkb(lkb);
+			found = 1;
 			break;
 		}
 	}
 	mutex_unlock(&ls->ls_waiters_mutex);
 
-	if (!rv)
+	if (!found)
 		lkb = NULL;
-	*lkb_ret = lkb;
-	return rv;
+	return lkb;
 }
 
 /* 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. */
 
+/* We do this after normal locking has been enabled and any saved messages
+   (in requestqueue) have been processed.  We should be confident that at
+   this point we won't get or process a reply to any of these waiting
+   operations.  But, new ops may be coming in on the rsbs/locks here from
+   userspace or remotely. */
+
+/* there may have been an overlap unlock/cancel prior to recovery or after
+   recovery.  if before, the lkb may still have a pos wait_count; if after, the
+   overlap flag would just have been set and nothing new sent.  we can be
+   confident here than any replies to either the initial op or overlap ops
+   prior to recovery have been received. */
+
 int dlm_recover_waiters_post(struct dlm_ls *ls)
 {
 	struct dlm_lkb *lkb;
 	struct dlm_rsb *r;
-	int error = 0, mstype;
+	int error = 0, mstype, err, oc, ou;
 
 	while (1) {
 		if (dlm_locking_stopped(ls)) {
@@ -3291,48 +3667,78 @@ int dlm_recover_waiters_post(struct dlm_
 			break;
 		}
 
-		mstype = remove_resend_waiter(ls, &lkb);
-		if (!mstype)
+		lkb = find_resend_waiter(ls);
+		if (!lkb)
 			break;
 
 		r = lkb->lkb_resource;
+		hold_rsb(r);
+		lock_rsb(r);
+
+		mstype = lkb->lkb_wait_type;
+		oc = is_overlap_cancel(lkb);
+		ou = is_overlap_unlock(lkb);
+		err = 0;
 
 		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);
+		/* At this point we assume that we won't get a reply to any
+		   previous op or overlap op on this lock.  First, do a big
+		   remove_from_waiters() for all previous ops. */
+
+		lkb->lkb_flags &= ~DLM_IFL_RESEND;
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+		lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+		lkb->lkb_wait_type = 0;
+		lkb->lkb_wait_count = 0;
+		mutex_lock(&ls->ls_waiters_mutex);
+		list_del_init(&lkb->lkb_wait_reply);
+		mutex_unlock(&ls->ls_waiters_mutex);
+		unhold_lkb(lkb); /* for waiters list */
+
+		if (oc || ou) {
+			/* do an unlock or cancel instead of resending */
+			switch (mstype) {
+			case DLM_MSG_LOOKUP:
+			case DLM_MSG_REQUEST:
+				queue_cast(r, lkb, ou ? -DLM_EUNLOCK :
+							-DLM_ECANCEL);
+				unhold_lkb(lkb); /* undoes create_lkb() */
+				break;
+			case DLM_MSG_CONVERT:
+				if (oc) {
+					queue_cast(r, lkb, -DLM_ECANCEL);
+				} else {
+					lkb->lkb_exflags |= DLM_LKF_FORCEUNLOCK;
+					_unlock_lock(r, lkb);
+				}
+				break;
+			default:
+				err = 1;
+			}
+		} else {
+			switch (mstype) {
+			case DLM_MSG_LOOKUP:
+			case DLM_MSG_REQUEST:
+				_request_lock(r, lkb);
+				if (is_master(r))
+					confirm_master(r, 0);
+				break;
+			case DLM_MSG_CONVERT:
+				_convert_lock(r, lkb);
+				break;
+			default:
+				err = 1;
+			}
 		}
+
+		if (err)
+			log_error(ls, "recover_waiters_post %x %d %x %d %d",
+			  	  lkb->lkb_id, mstype, lkb->lkb_flags, oc, ou);
+		unlock_rsb(r);
+		put_rsb(r);
+		dlm_put_lkb(lkb);
 	}
 
 	return error;
@@ -3684,7 +4090,7 @@ int dlm_user_request(struct dlm_ls *ls, 
 
 	/* add this new lkb to the per-process list of locks */
 	spin_lock(&ua->proc->locks_spin);
-	kref_get(&lkb->lkb_ref);
+	hold_lkb(lkb);
 	list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
 	spin_unlock(&ua->proc->locks_spin);
  out:
@@ -3774,6 +4180,9 @@ int dlm_user_unlock(struct dlm_ls *ls, s
 
 	if (error == -DLM_EUNLOCK)
 		error = 0;
+	/* from validate_unlock_args() */
+	if (error == -EBUSY && (flags & DLM_LKF_FORCEUNLOCK))
+		error = 0;
 	if (error)
 		goto out_put;
 
@@ -3786,6 +4195,7 @@ int dlm_user_unlock(struct dlm_ls *ls, s
 	dlm_put_lkb(lkb);
  out:
 	unlock_recovery(ls);
+	kfree(ua_tmp);
 	return error;
 }
 
@@ -3815,33 +4225,37 @@ int dlm_user_cancel(struct dlm_ls *ls, s
 
 	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_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
-		spin_unlock(&ua->proc->locks_spin);
-	}
+	/* from validate_unlock_args() */
+	if (error == -EBUSY)
+		error = 0;
  out_put:
 	dlm_put_lkb(lkb);
  out:
 	unlock_recovery(ls);
+	kfree(ua_tmp);
 	return error;
 }
 
+/* lkb's that are removed from the waiters list by revert are just left on the
+   orphans list with the granted orphan locks, to be freed by purge */
+
 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;
+	struct dlm_args args;
+	int error;
 
-	if (ua->lksb.sb_lvbptr)
-		kfree(ua->lksb.sb_lvbptr);
-	kfree(ua);
-	lkb->lkb_astparam = (long)NULL;
+	hold_lkb(lkb);
+	mutex_lock(&ls->ls_orphans_mutex);
+	list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
+	mutex_unlock(&ls->ls_orphans_mutex);
 
-	/* TODO: propogate to master if needed */
-	return 0;
+	set_unlock_args(0, ua, &args);
+
+	error = cancel_lock(ls, lkb, &args);
+	if (error == -DLM_ECANCEL)
+		error = 0;
+	return error;
 }
 
 /* The force flag allows the unlock to go ahead even if the lkb isn't granted.
@@ -3853,10 +4267,6 @@ static int unlock_proc_lock(struct dlm_l
 	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);
@@ -3865,6 +4275,31 @@ static int unlock_proc_lock(struct dlm_l
 	return error;
 }
 
+/* We have to release clear_proc_locks mutex before calling unlock_proc_lock()
+   (which does lock_rsb) due to deadlock with receiving a message that does
+   lock_rsb followed by dlm_user_add_ast() */
+
+static struct dlm_lkb *del_proc_lock(struct dlm_ls *ls,
+				     struct dlm_user_proc *proc)
+{
+	struct dlm_lkb *lkb = NULL;
+
+	mutex_lock(&ls->ls_clear_proc_locks);
+	if (list_empty(&proc->locks))
+		goto out;
+
+	lkb = list_entry(proc->locks.next, struct dlm_lkb, lkb_ownqueue);
+	list_del_init(&lkb->lkb_ownqueue);
+
+	if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
+		lkb->lkb_flags |= DLM_IFL_ORPHAN;
+	else
+		lkb->lkb_flags |= DLM_IFL_DEAD;
+ out:
+	mutex_unlock(&ls->ls_clear_proc_locks);
+	return lkb;
+}
+
 /* 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. */
@@ -3880,18 +4315,15 @@ void dlm_clear_proc_locks(struct dlm_ls 
 	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) {
-		list_del_init(&lkb->lkb_ownqueue);
-
-		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
-			lkb->lkb_flags |= DLM_IFL_ORPHAN;
+	while (1) {
+		lkb = del_proc_lock(ls, proc);
+		if (!lkb)
+			break;
+		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
 			orphan_proc_lock(ls, lkb);
-		} else {
-			lkb->lkb_flags |= DLM_IFL_DEAD;
+		else
 			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
@@ -3900,6 +4332,8 @@ void dlm_clear_proc_locks(struct dlm_ls 
 		dlm_put_lkb(lkb);
 	}
 
+	mutex_lock(&ls->ls_clear_proc_locks);
+
 	/* in-progress unlocks */
 	list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
 		list_del_init(&lkb->lkb_ownqueue);
@@ -3916,3 +4350,92 @@ void dlm_clear_proc_locks(struct dlm_ls 
 	unlock_recovery(ls);
 }
 
+static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	while (1) {
+		lkb = NULL;
+		spin_lock(&proc->locks_spin);
+		if (!list_empty(&proc->locks)) {
+			lkb = list_entry(proc->locks.next, struct dlm_lkb,
+					 lkb_ownqueue);
+			list_del_init(&lkb->lkb_ownqueue);
+		}
+		spin_unlock(&proc->locks_spin);
+
+		if (!lkb)
+			break;
+
+		lkb->lkb_flags |= DLM_IFL_DEAD;
+		unlock_proc_lock(ls, lkb);
+		dlm_put_lkb(lkb); /* ref from proc->locks list */
+	}
+
+	spin_lock(&proc->locks_spin);
+	list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
+		list_del_init(&lkb->lkb_ownqueue);
+		lkb->lkb_flags |= DLM_IFL_DEAD;
+		dlm_put_lkb(lkb);
+	}
+	spin_unlock(&proc->locks_spin);
+
+	spin_lock(&proc->asts_spin);
+	list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
+		list_del(&lkb->lkb_astqueue);
+		dlm_put_lkb(lkb);
+	}
+	spin_unlock(&proc->asts_spin);
+}
+
+/* pid of 0 means purge all orphans */
+
+static void do_purge(struct dlm_ls *ls, int nodeid, int pid)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	mutex_lock(&ls->ls_orphans_mutex);
+	list_for_each_entry_safe(lkb, safe, &ls->ls_orphans, lkb_ownqueue) {
+		if (pid && lkb->lkb_ownpid != pid)
+			continue;
+		unlock_proc_lock(ls, lkb);
+		list_del_init(&lkb->lkb_ownqueue);
+		dlm_put_lkb(lkb);
+	}
+	mutex_unlock(&ls->ls_orphans_mutex);
+}
+
+static int send_purge(struct dlm_ls *ls, int nodeid, int pid)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int error;
+
+	error = _create_message(ls, sizeof(struct dlm_message), nodeid,
+				DLM_MSG_PURGE, &ms, &mh);
+	if (error)
+		return error;
+	ms->m_nodeid = nodeid;
+	ms->m_pid = pid;
+
+	return send_message(mh, ms);
+}
+
+int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
+		   int nodeid, int pid)
+{
+	int error = 0;
+
+	if (nodeid != dlm_our_nodeid()) {
+		error = send_purge(ls, nodeid, pid);
+	} else {
+		lock_recovery(ls);
+		if (pid == current->pid)
+			purge_proc_locks(ls, proc);
+		else
+			do_purge(ls, nodeid, pid);
+		unlock_recovery(ls);
+	}
+	return error;
+}
+
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 0843a30..64fc4ec 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -41,6 +41,8 @@ int dlm_user_unlock(struct dlm_ls *ls, s
 	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);
+int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
+	int nodeid, int pid);
 void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
 
 static inline int is_master(struct dlm_rsb *r)
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index f40817b..a677b2a 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 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
@@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = {
 };
 
 static struct kset dlm_kset = {
-	.subsys = &kernel_subsys,
 	.kobj   = {.name = "dlm",},
 	.ktype  = &dlm_ktype,
 };
@@ -218,6 +217,7 @@ int dlm_lockspace_init(void)
 	INIT_LIST_HEAD(&lslist);
 	spin_lock_init(&lslist_lock);
 
+	kobj_set_kset_s(&dlm_kset, kernel_subsys);
 	error = kset_register(&dlm_kset);
 	if (error)
 		printk("dlm_lockspace_init: cannot register kset %d\n", error);
@@ -459,6 +459,8 @@ static int new_lockspace(char *name, int
 
 	INIT_LIST_HEAD(&ls->ls_waiters);
 	mutex_init(&ls->ls_waiters_mutex);
+	INIT_LIST_HEAD(&ls->ls_orphans);
+	mutex_init(&ls->ls_orphans_mutex);
 
 	INIT_LIST_HEAD(&ls->ls_nodes);
 	INIT_LIST_HEAD(&ls->ls_nodes_gone);
diff --git a/fs/dlm/lowcomms-sctp.c b/fs/dlm/lowcomms-sctp.c
deleted file mode 100644
index dc83a9d..0000000
--- a/fs/dlm/lowcomms-sctp.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/******************************************************************************
-*******************************************************************************
-**
-**  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.
-**
-*******************************************************************************
-******************************************************************************/
-
-/*
- * 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;
-	struct work_struct      swork; /* Send workqueue */
-	struct work_struct      lwork; /* Locking workqueue */
-};
-
-static DEFINE_IDR(nodeinfo_idr);
-static DECLARE_RWSEM(nodeinfo_lock);
-static int max_nodeid;
-
-struct cbuf {
-	unsigned int base;
-	unsigned int len;
-	unsigned int 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;
-	struct work_struct      work; /* Send workqueue */
-};
-
-/* 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;
-};
-
-static void cbuf_add(struct cbuf *cb, int n)
-{
-	cb->len += n;
-}
-
-static int cbuf_data(struct cbuf *cb)
-{
-	return ((cb->base + cb->len) & cb->mask);
-}
-
-static void cbuf_init(struct cbuf *cb, int size)
-{
-	cb->base = cb->len = 0;
-	cb->mask = size-1;
-}
-
-static void cbuf_eat(struct cbuf *cb, int n)
-{
-	cb->len  -= n;
-	cb->base += n;
-	cb->base &= cb->mask;
-}
-
-/* List of nodes which have writes pending */
-static LIST_HEAD(write_nodes);
-static DEFINE_SPINLOCK(write_nodes_lock);
-
-
-/* Maximum number of incoming messages to process before
- * doing a schedule()
- */
-#define MAX_RX_MSG_COUNT 25
-
-/* Work queues */
-static struct workqueue_struct *recv_workqueue;
-static struct workqueue_struct *send_workqueue;
-static struct workqueue_struct *lock_workqueue;
-
-/* The SCTP connection */
-static struct connection sctp_con;
-
-static void process_send_sockets(struct work_struct *work);
-static void process_recv_sockets(struct work_struct *work);
-static void process_lock_request(struct work_struct *work);
-
-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;
-}
-
-/* If alloc is 0 here we will not attempt to allocate a new
-   nodeinfo struct */
-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)
-		return ni;
-
-	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);
-	INIT_WORK(&ni->lwork, process_lock_request);
-	INIT_WORK(&ni->swork, process_send_sockets);
-	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)
-{
-	if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
-		queue_work(recv_workqueue, &sctp_con.work);
-}
-
-
-/* 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 = 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);
-				queue_work(send_workqueue, &ni->swork);
-			}
-		}
-	}
-}
-
-/* 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 */
-			ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
-
-			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);
-				queue_work(send_workqueue, &ni->swork);
-			}
-		}
-		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));
-
-	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 = 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);
-				queue_work(send_workqueue, &ni->swork);
-			}
-		}
-	}
-
-	/* INIT sends a message with length of 1 - ignore it */
-	if (r == 1)
-		return 0;
-
-	cbuf_add(&sctp_con.cb, ret);
-	// PJC: TODO: Add to node's workqueue....can we ??
-	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;
-	cond_resched();
-	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.ci_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.ci_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;
-
-	ni = nodeid2nodeinfo(nodeid, allocation);
-	if (!ni)
-		return NULL;
-
-	spin_lock(&ni->writequeue_lock);
-	e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
-	if ((&e->list == &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;
-
-	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);
-
-		queue_work(send_workqueue, &ni->swork);
-	}
-	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.ci_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 = 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 void 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;
-	}
-	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 = 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 */
-			cond_resched();
-		}
-
-		spin_lock(&ni->writequeue_lock);
-		e->offset += ret;
-		e->len -= ret;
-
-		if (e->len == 0 && e->users == 0) {
-			list_del(&e->list);
-			kunmap(e->page);
-			free_entry(e);
-			continue;
-		}
-	}
-	spin_unlock(&ni->writequeue_lock);
-out:
-	return;
-
-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;
-}
-
-/* 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;
-}
-
-// PJC: The work queue function for receiving.
-static void process_recv_sockets(struct work_struct *work)
-{
-	if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
-		int ret;
-		int count = 0;
-
-		do {
-			ret = receive_from_sock();
-
-			/* Don't starve out everyone else */
-			if (++count >= MAX_RX_MSG_COUNT) {
-				cond_resched();
-				count = 0;
-			}
-		} while (!kthread_should_stop() && ret >=0);
-	}
-	cond_resched();
-}
-
-// PJC: the work queue function for sending
-static void process_send_sockets(struct work_struct *work)
-{
-	if (sctp_con.eagain_flag) {
-		sctp_con.eagain_flag = 0;
-		refill_write_queue();
-	}
-	process_output_queue();
-}
-
-// PJC: Process lock requests from a particular node.
-// TODO: can we optimise this out on UP ??
-static void process_lock_request(struct work_struct *work)
-{
-}
-
-static void daemons_stop(void)
-{
-	destroy_workqueue(recv_workqueue);
-	destroy_workqueue(send_workqueue);
-	destroy_workqueue(lock_workqueue);
-}
-
-static int daemons_start(void)
-{
-	int error;
-	recv_workqueue = create_workqueue("dlm_recv");
-	error = IS_ERR(recv_workqueue);
-	if (error) {
-		log_print("can't start dlm_recv %d", error);
-		return error;
-	}
-
-	send_workqueue = create_singlethread_workqueue("dlm_send");
-	error = IS_ERR(send_workqueue);
-	if (error) {
-		log_print("can't start dlm_send %d", error);
-		destroy_workqueue(recv_workqueue);
-		return error;
-	}
-
-	lock_workqueue = create_workqueue("dlm_rlock");
-	error = IS_ERR(lock_workqueue);
-	if (error) {
-		log_print("can't start dlm_rlock %d", error);
-		destroy_workqueue(send_workqueue);
-		destroy_workqueue(recv_workqueue);
-		return error;
-	}
-
-	return 0;
-}
-
-/*
- * This is quite likely to sleep...
- */
-int dlm_lowcomms_start(void)
-{
-	int error;
-
-	INIT_WORK(&sctp_con.work, process_recv_sockets);
-
-	error = init_sock();
-	if (error)
-		goto fail_sock;
-	error = daemons_start();
-	if (error)
-		goto fail_sock;
-	return 0;
-
-fail_sock:
-	close_connection();
-	return error;
-}
-
-void dlm_lowcomms_stop(void)
-{
-	int i;
-
-	sctp_con.flags = 0x7;
-	daemons_stop();
-	clean_writequeues();
-	close_connection();
-	dealloc_nodeinfo();
-	max_nodeid = 0;
-
-	dlm_local_count = 0;
-	dlm_local_nodeid = 0;
-
-	for (i = 0; i < dlm_local_count; i++)
-		kfree(dlm_local_addr[i]);
-}
diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms-tcp.c
deleted file mode 100644
index 07e0a12..0000000
--- a/fs/dlm/lowcomms-tcp.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/******************************************************************************
-*******************************************************************************
-**
-**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2007 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 waits.
- *
- */
-
-
-#include <asm/ioctls.h>
-#include <net/sock.h>
-#include <net/tcp.h>
-#include <linux/pagemap.h>
-
-#include "dlm_internal.h"
-#include "lowcomms.h"
-#include "midcomms.h"
-#include "config.h"
-
-struct cbuf {
-	unsigned int base;
-	unsigned int len;
-	unsigned int mask;
-};
-
-#define NODE_INCREMENT 32
-static void cbuf_add(struct cbuf *cb, int n)
-{
-	cb->len += n;
-}
-
-static int cbuf_data(struct cbuf *cb)
-{
-	return ((cb->base + cb->len) & cb->mask);
-}
-
-static void cbuf_init(struct cbuf *cb, int size)
-{
-	cb->base = cb->len = 0;
-	cb->mask = size-1;
-}
-
-static void cbuf_eat(struct cbuf *cb, int n)
-{
-	cb->len  -= n;
-	cb->base += n;
-	cb->base &= cb->mask;
-}
-
-static bool cbuf_empty(struct cbuf *cb)
-{
-	return cb->len == 0;
-}
-
-/* Maximum number of incoming messages to process before
-   doing a cond_resched()
-*/
-#define MAX_RX_MSG_COUNT 25
-
-struct connection {
-	struct socket *sock;	/* NULL if not connected */
-	uint32_t nodeid;	/* So we know who we are in the list */
-	struct mutex sock_mutex;
-	unsigned long flags;	/* bit 1,2 = We are on the read/write lists */
-#define CF_READ_PENDING 1
-#define CF_WRITE_PENDING 2
-#define CF_CONNECT_PENDING 3
-#define CF_IS_OTHERCON 4
-	struct list_head writequeue;  /* List of outgoing writequeue_entries */
-	struct list_head listenlist;  /* List of allocated listening sockets */
-	spinlock_t writequeue_lock;
-	int (*rx_action) (struct connection *);	/* What to do when active */
-	struct page *rx_page;
-	struct cbuf cb;
-	int retries;
-#define MAX_CONNECT_RETRIES 3
-	struct connection *othercon;
-	struct work_struct rwork; /* Receive workqueue */
-	struct work_struct swork; /* Send workqueue */
-};
-#define sock2con(x) ((struct connection *)(x)->sk_user_data)
-
-/* 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 connection *con;
-};
-
-static struct sockaddr_storage dlm_local_addr;
-
-/* Work queues */
-static struct workqueue_struct *recv_workqueue;
-static struct workqueue_struct *send_workqueue;
-
-/* An array of pointers to connections, indexed by NODEID */
-static struct connection **connections;
-static DECLARE_MUTEX(connections_lock);
-static struct kmem_cache *con_cache;
-static int conn_array_size;
-
-static void process_recv_sockets(struct work_struct *work);
-static void process_send_sockets(struct work_struct *work);
-
-static struct connection *nodeid2con(int nodeid, gfp_t allocation)
-{
-	struct connection *con = NULL;
-
-	down(&connections_lock);
-	if (nodeid >= conn_array_size) {
-		int new_size = nodeid + NODE_INCREMENT;
-		struct connection **new_conns;
-
-		new_conns = kzalloc(sizeof(struct connection *) *
-				    new_size, allocation);
-		if (!new_conns)
-			goto finish;
-
-		memcpy(new_conns, connections,  sizeof(struct connection *) * conn_array_size);
-		conn_array_size = new_size;
-		kfree(connections);
-		connections = new_conns;
-
-	}
-
-	con = connections[nodeid];
-	if (con == NULL && allocation) {
-		con = kmem_cache_zalloc(con_cache, allocation);
-		if (!con)
-			goto finish;
-
-		con->nodeid = nodeid;
-		mutex_init(&con->sock_mutex);
-		INIT_LIST_HEAD(&con->writequeue);
-		spin_lock_init(&con->writequeue_lock);
-		INIT_WORK(&con->swork, process_send_sockets);
-		INIT_WORK(&con->rwork, process_recv_sockets);
-
-		connections[nodeid] = con;
-	}
-
-finish:
-	up(&connections_lock);
-	return con;
-}
-
-/* Data available on socket or listen socket received a connect */
-static void lowcomms_data_ready(struct sock *sk, int count_unused)
-{
-	struct connection *con = sock2con(sk);
-
-	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
-		queue_work(recv_workqueue, &con->rwork);
-}
-
-static void lowcomms_write_space(struct sock *sk)
-{
-	struct connection *con = sock2con(sk);
-
-	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
-		queue_work(send_workqueue, &con->swork);
-}
-
-static inline void lowcomms_connect_sock(struct connection *con)
-{
-	if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
-		queue_work(send_workqueue, &con->swork);
-}
-
-static void lowcomms_state_change(struct sock *sk)
-{
-	if (sk->sk_state == TCP_ESTABLISHED)
-		lowcomms_write_space(sk);
-}
-
-/* Make a socket active */
-static int add_sock(struct socket *sock, struct connection *con)
-{
-	con->sock = sock;
-
-	/* Install a data_ready callback */
-	con->sock->sk->sk_data_ready = lowcomms_data_ready;
-	con->sock->sk->sk_write_space = lowcomms_write_space;
-	con->sock->sk->sk_state_change = lowcomms_state_change;
-
-	return 0;
-}
-
-/* Add the port number to an IP6 or 4 sockaddr and return the address
-   length */
-static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
-			  int *addr_len)
-{
-	saddr->ss_family =  dlm_local_addr.ss_family;
-	if (saddr->ss_family == AF_INET) {
-		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
-		in4_addr->sin_port = cpu_to_be16(port);
-		*addr_len = sizeof(struct sockaddr_in);
-	} else {
-		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
-		in6_addr->sin6_port = cpu_to_be16(port);
-		*addr_len = sizeof(struct sockaddr_in6);
-	}
-}
-
-/* Close a remote connection and tidy up */
-static void close_connection(struct connection *con, bool and_other)
-{
-	mutex_lock(&con->sock_mutex);
-
-	if (con->sock) {
-		sock_release(con->sock);
-		con->sock = NULL;
-	}
-	if (con->othercon && and_other) {
-		/* Will only re-enter once. */
-		close_connection(con->othercon, false);
-	}
-	if (con->rx_page) {
-		__free_page(con->rx_page);
-		con->rx_page = NULL;
-	}
-	con->retries = 0;
-	mutex_unlock(&con->sock_mutex);
-}
-
-/* Data received from remote end */
-static int receive_from_sock(struct connection *con)
-{
-	int ret = 0;
-	struct msghdr msg = {};
-	struct kvec iov[2];
-	unsigned len;
-	int r;
-	int call_again_soon = 0;
-	int nvec;
-
-	mutex_lock(&con->sock_mutex);
-
-	if (con->sock == NULL) {
-		ret = -EAGAIN;
-		goto out_close;
-	}
-
-	if (con->rx_page == NULL) {
-		/*
-		 * This doesn't need to be atomic, but I think it should
-		 * improve performance if it is.
-		 */
-		con->rx_page = alloc_page(GFP_ATOMIC);
-		if (con->rx_page == NULL)
-			goto out_resched;
-		cbuf_init(&con->cb, PAGE_CACHE_SIZE);
-	}
-
-	/*
-	 * 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 = con->cb.base - cbuf_data(&con->cb);
-	iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
-	nvec = 1;
-
-	/*
-	 * 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(&con->cb) >= con->cb.base) {
-		iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&con->cb);
-		iov[1].iov_len = con->cb.base;
-		iov[1].iov_base = page_address(con->rx_page);
-		nvec = 2;
-	}
-	len = iov[0].iov_len + iov[1].iov_len;
-
-	r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
-			       MSG_DONTWAIT | MSG_NOSIGNAL);
-
-	if (ret <= 0)
-		goto out_close;
-	if (ret == -EAGAIN)
-		goto out_resched;
-
-	if (ret == len)
-		call_again_soon = 1;
-	cbuf_add(&con->cb, ret);
-	ret = dlm_process_incoming_buffer(con->nodeid,
-					  page_address(con->rx_page),
-					  con->cb.base, con->cb.len,
-					  PAGE_CACHE_SIZE);
-	if (ret == -EBADMSG) {
-		printk(KERN_INFO "dlm: lowcomms: addr=%p, base=%u, len=%u, "
-		       "iov_len=%u, iov_base[0]=%p, read=%d\n",
-		       page_address(con->rx_page), con->cb.base, con->cb.len,
-		       len, iov[0].iov_base, r);
-	}
-	if (ret < 0)
-		goto out_close;
-	cbuf_eat(&con->cb, ret);
-
-	if (cbuf_empty(&con->cb) && !call_again_soon) {
-		__free_page(con->rx_page);
-		con->rx_page = NULL;
-	}
-
-	if (call_again_soon)
-		goto out_resched;
-	mutex_unlock(&con->sock_mutex);
-	return 0;
-
-out_resched:
-	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
-		queue_work(recv_workqueue, &con->rwork);
-	mutex_unlock(&con->sock_mutex);
-	return -EAGAIN;
-
-out_close:
-	mutex_unlock(&con->sock_mutex);
-	if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) {
-		close_connection(con, false);
-		/* Reconnect when there is something to send */
-	}
-	/* Don't return success if we really got EOF */
-	if (ret == 0)
-		ret = -EAGAIN;
-
-	return ret;
-}
-
-/* Listening socket is busy, accept a connection */
-static int accept_from_sock(struct connection *con)
-{
-	int result;
-	struct sockaddr_storage peeraddr;
-	struct socket *newsock;
-	int len;
-	int nodeid;
-	struct connection *newcon;
-	struct connection *addcon;
-
-	memset(&peeraddr, 0, sizeof(peeraddr));
-	result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
-				  IPPROTO_TCP, &newsock);
-	if (result < 0)
-		return -ENOMEM;
-
-	mutex_lock_nested(&con->sock_mutex, 0);
-
-	result = -ENOTCONN;
-	if (con->sock == NULL)
-		goto accept_err;
-
-	newsock->type = con->sock->type;
-	newsock->ops = con->sock->ops;
-
-	result = con->sock->ops->accept(con->sock, newsock, O_NONBLOCK);
-	if (result < 0)
-		goto accept_err;
-
-	/* Get the connected socket's peer */
-	memset(&peeraddr, 0, sizeof(peeraddr));
-	if (newsock->ops->getname(newsock, (struct sockaddr *)&peeraddr,
-				  &len, 2)) {
-		result = -ECONNABORTED;
-		goto accept_err;
-	}
-
-	/* Get the new node's NODEID */
-	make_sockaddr(&peeraddr, 0, &len);
-	if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
-		printk("dlm: connect from non cluster node\n");
-		sock_release(newsock);
-		mutex_unlock(&con->sock_mutex);
-		return -1;
-	}
-
-	log_print("got connection from %d", nodeid);
-
-	/*  Check to see if we already have a connection to this node. This
-	 *  could happen if the two nodes initiate a connection at roughly
-	 *  the same time and the connections cross on the wire.
-	 * TEMPORARY FIX:
-	 *  In this case we store the incoming one in "othercon"
-	 */
-	newcon = nodeid2con(nodeid, GFP_KERNEL);
-	if (!newcon) {
-		result = -ENOMEM;
-		goto accept_err;
-	}
-	mutex_lock_nested(&newcon->sock_mutex, 1);
-	if (newcon->sock) {
-		struct connection *othercon = newcon->othercon;
-
-		if (!othercon) {
-			othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
-			if (!othercon) {
-				printk("dlm: failed to allocate incoming socket\n");
-				mutex_unlock(&newcon->sock_mutex);
-				result = -ENOMEM;
-				goto accept_err;
-			}
-			othercon->nodeid = nodeid;
-			othercon->rx_action = receive_from_sock;
-			mutex_init(&othercon->sock_mutex);
-			INIT_WORK(&othercon->swork, process_send_sockets);
-			INIT_WORK(&othercon->rwork, process_recv_sockets);
-			set_bit(CF_IS_OTHERCON, &othercon->flags);
-			newcon->othercon = othercon;
-		}
-		othercon->sock = newsock;
-		newsock->sk->sk_user_data = othercon;
-		add_sock(newsock, othercon);
-		addcon = othercon;
-	}
-	else {
-		newsock->sk->sk_user_data = newcon;
-		newcon->rx_action = receive_from_sock;
-		add_sock(newsock, newcon);
-		addcon = newcon;
-	}
-
-	mutex_unlock(&newcon->sock_mutex);
-
-	/*
-	 * Add it to the active queue in case we got data
-	 * beween processing the accept adding the socket
-	 * to the read_sockets list
-	 */
-	if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
-		queue_work(recv_workqueue, &addcon->rwork);
-	mutex_unlock(&con->sock_mutex);
-
-	return 0;
-
-accept_err:
-	mutex_unlock(&con->sock_mutex);
-	sock_release(newsock);
-
-	if (result != -EAGAIN)
-		printk("dlm: error accepting connection from node: %d\n", result);
-	return result;
-}
-
-/* Connect a new socket to its peer */
-static void connect_to_sock(struct connection *con)
-{
-	int result = -EHOSTUNREACH;
-	struct sockaddr_storage saddr;
-	int addr_len;
-	struct socket *sock;
-
-	if (con->nodeid == 0) {
-		log_print("attempt to connect sock 0 foiled");
-		return;
-	}
-
-	mutex_lock(&con->sock_mutex);
-	if (con->retries++ > MAX_CONNECT_RETRIES)
-		goto out;
-
-	/* Some odd races can cause double-connects, ignore them */
-	if (con->sock) {
-		result = 0;
-		goto out;
-	}
-
-	/* Create a socket to communicate with */
-	result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
-				  IPPROTO_TCP, &sock);
-	if (result < 0)
-		goto out_err;
-
-	memset(&saddr, 0, sizeof(saddr));
-	if (dlm_nodeid_to_addr(con->nodeid, &saddr))
-		goto out_err;
-
-	sock->sk->sk_user_data = con;
-	con->rx_action = receive_from_sock;
-
-	make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
-
-	add_sock(sock, con);
-
-	log_print("connecting to %d", con->nodeid);
-	result =
-		sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
-				   O_NONBLOCK);
-	if (result == -EINPROGRESS)
-		result = 0;
-	if (result == 0)
-		goto out;
-
-out_err:
-	if (con->sock) {
-		sock_release(con->sock);
-		con->sock = NULL;
-	}
-	/*
-	 * Some errors are fatal and this list might need adjusting. For other
-	 * errors we try again until the max number of retries is reached.
-	 */
-	if (result != -EHOSTUNREACH && result != -ENETUNREACH &&
-	    result != -ENETDOWN && result != EINVAL
-	    && result != -EPROTONOSUPPORT) {
-		lowcomms_connect_sock(con);
-		result = 0;
-	}
-out:
-	mutex_unlock(&con->sock_mutex);
-	return;
-}
-
-static struct socket *create_listen_sock(struct connection *con,
-					 struct sockaddr_storage *saddr)
-{
-	struct socket *sock = NULL;
-	mm_segment_t fs;
-	int result = 0;
-	int one = 1;
-	int addr_len;
-
-	if (dlm_local_addr.ss_family == AF_INET)
-		addr_len = sizeof(struct sockaddr_in);
-	else
-		addr_len = sizeof(struct sockaddr_in6);
-
-	/* Create a socket to communicate with */
-	result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM, IPPROTO_TCP, &sock);
-	if (result < 0) {
-		printk("dlm: Can't create listening comms socket\n");
-		goto create_out;
-	}
-
-	fs = get_fs();
-	set_fs(get_ds());
-	result = sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-				 (char *)&one, sizeof(one));
-	set_fs(fs);
-	if (result < 0) {
-		printk("dlm: Failed to set SO_REUSEADDR on socket: result=%d\n",
-		       result);
-	}
-	sock->sk->sk_user_data = con;
-	con->rx_action = accept_from_sock;
-	con->sock = sock;
-
-	/* Bind to our port */
-	make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
-	result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
-	if (result < 0) {
-		printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port);
-		sock_release(sock);
-		sock = NULL;
-		con->sock = NULL;
-		goto create_out;
-	}
-
-	fs = get_fs();
-	set_fs(get_ds());
-
-	result = sock_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
-				 (char *)&one, sizeof(one));
-	set_fs(fs);
-	if (result < 0) {
-		printk("dlm: Set keepalive failed: %d\n", result);
-	}
-
-	result = sock->ops->listen(sock, 5);
-	if (result < 0) {
-		printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port);
-		sock_release(sock);
-		sock = NULL;
-		goto create_out;
-	}
-
-create_out:
-	return sock;
-}
-
-
-/* Listen on all interfaces */
-static int listen_for_all(void)
-{
-	struct socket *sock = NULL;
-	struct connection *con = nodeid2con(0, GFP_KERNEL);
-	int result = -EINVAL;
-
-	/* We don't support multi-homed hosts */
-	set_bit(CF_IS_OTHERCON, &con->flags);
-
-	sock = create_listen_sock(con, &dlm_local_addr);
-	if (sock) {
-		add_sock(sock, con);
-		result = 0;
-	}
-	else {
-		result = -EADDRINUSE;
-	}
-
-	return result;
-}
-
-
-
-static struct writequeue_entry *new_writequeue_entry(struct connection *con,
-						     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;
-	entry->con = con;
-
-	return entry;
-}
-
-void *dlm_lowcomms_get_buffer(int nodeid, int len,
-			      gfp_t allocation, char **ppc)
-{
-	struct connection *con;
-	struct writequeue_entry *e;
-	int offset = 0;
-	int users = 0;
-
-	con = nodeid2con(nodeid, allocation);
-	if (!con)
-		return NULL;
-
-	spin_lock(&con->writequeue_lock);
-	e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
-	if ((&e->list == &con->writequeue) ||
-	    (PAGE_CACHE_SIZE - e->end < len)) {
-		e = NULL;
-	} else {
-		offset = e->end;
-		e->end += len;
-		users = e->users++;
-	}
-	spin_unlock(&con->writequeue_lock);
-
-	if (e) {
-	got_one:
-		if (users == 0)
-			kmap(e->page);
-		*ppc = page_address(e->page) + offset;
-		return e;
-	}
-
-	e = new_writequeue_entry(con, allocation);
-	if (e) {
-		spin_lock(&con->writequeue_lock);
-		offset = e->end;
-		e->end += len;
-		users = e->users++;
-		list_add_tail(&e->list, &con->writequeue);
-		spin_unlock(&con->writequeue_lock);
-		goto got_one;
-	}
-	return NULL;
-}
-
-void dlm_lowcomms_commit_buffer(void *mh)
-{
-	struct writequeue_entry *e = (struct writequeue_entry *)mh;
-	struct connection *con = e->con;
-	int users;
-
-	spin_lock(&con->writequeue_lock);
-	users = --e->users;
-	if (users)
-		goto out;
-	e->len = e->end - e->offset;
-	kunmap(e->page);
-	spin_unlock(&con->writequeue_lock);
-
-	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
-		queue_work(send_workqueue, &con->swork);
-	}
-	return;
-
-out:
-	spin_unlock(&con->writequeue_lock);
-	return;
-}
-
-static void free_entry(struct writequeue_entry *e)
-{
-	__free_page(e->page);
-	kfree(e);
-}
-
-/* Send a message */
-static void send_to_sock(struct connection *con)
-{
-	int ret = 0;
-	ssize_t(*sendpage) (struct socket *, struct page *, int, size_t, int);
-	const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
-	struct writequeue_entry *e;
-	int len, offset;
-
-	mutex_lock(&con->sock_mutex);
-	if (con->sock == NULL)
-		goto out_connect;
-
-	sendpage = con->sock->ops->sendpage;
-
-	spin_lock(&con->writequeue_lock);
-	for (;;) {
-		e = list_entry(con->writequeue.next, struct writequeue_entry,
-			       list);
-		if ((struct list_head *) e == &con->writequeue)
-			break;
-
-		len = e->len;
-		offset = e->offset;
-		BUG_ON(len == 0 && e->users == 0);
-		spin_unlock(&con->writequeue_lock);
-		kmap(e->page);
-
-		ret = 0;
-		if (len) {
-			ret = sendpage(con->sock, e->page, offset, len,
-				       msg_flags);
-			if (ret == -EAGAIN || ret == 0)
-				goto out;
-			if (ret <= 0)
-				goto send_error;
-		}
-		else {
-			/* Don't starve people filling buffers */
-			cond_resched();
-		}
-
-		spin_lock(&con->writequeue_lock);
-		e->offset += ret;
-		e->len -= ret;
-
-		if (e->len == 0 && e->users == 0) {
-			list_del(&e->list);
-			kunmap(e->page);
-			free_entry(e);
-			continue;
-		}
-	}
-	spin_unlock(&con->writequeue_lock);
-out:
-	mutex_unlock(&con->sock_mutex);
-	return;
-
-send_error:
-	mutex_unlock(&con->sock_mutex);
-	close_connection(con, false);
-	lowcomms_connect_sock(con);
-	return;
-
-out_connect:
-	mutex_unlock(&con->sock_mutex);
-	connect_to_sock(con);
-	return;
-}
-
-static void clean_one_writequeue(struct connection *con)
-{
-	struct list_head *list;
-	struct list_head *temp;
-
-	spin_lock(&con->writequeue_lock);
-	list_for_each_safe(list, temp, &con->writequeue) {
-		struct writequeue_entry *e =
-			list_entry(list, struct writequeue_entry, list);
-		list_del(&e->list);
-		free_entry(e);
-	}
-	spin_unlock(&con->writequeue_lock);
-}
-
-/* Called from recovery when it knows that a node has
-   left the cluster */
-int dlm_lowcomms_close(int nodeid)
-{
-	struct connection *con;
-
-	if (!connections)
-		goto out;
-
-	log_print("closing connection to node %d", nodeid);
-	con = nodeid2con(nodeid, 0);
-	if (con) {
-		clean_one_writequeue(con);
-		close_connection(con, true);
-	}
-	return 0;
-
-out:
-	return -1;
-}
-
-/* Look for activity on active sockets */
-static void process_recv_sockets(struct work_struct *work)
-{
-	struct connection *con = container_of(work, struct connection, rwork);
-	int err;
-
-	clear_bit(CF_READ_PENDING, &con->flags);
-	do {
-		err = con->rx_action(con);
-	} while (!err);
-}
-
-
-static void process_send_sockets(struct work_struct *work)
-{
-	struct connection *con = container_of(work, struct connection, swork);
-
-	if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
-		connect_to_sock(con);
-	}
-
-	clear_bit(CF_WRITE_PENDING, &con->flags);
-	send_to_sock(con);
-}
-
-
-/* Discard all entries on the write queues */
-static void clean_writequeues(void)
-{
-	int nodeid;
-
-	for (nodeid = 1; nodeid < conn_array_size; nodeid++) {
-		struct connection *con = nodeid2con(nodeid, 0);
-
-		if (con)
-			clean_one_writequeue(con);
-	}
-}
-
-static void work_stop(void)
-{
-	destroy_workqueue(recv_workqueue);
-	destroy_workqueue(send_workqueue);
-}
-
-static int work_start(void)
-{
-	int error;
-	recv_workqueue = create_workqueue("dlm_recv");
-	error = IS_ERR(recv_workqueue);
-	if (error) {
-		log_print("can't start dlm_recv %d", error);
-		return error;
-	}
-
-	send_workqueue = create_singlethread_workqueue("dlm_send");
-	error = IS_ERR(send_workqueue);
-	if (error) {
-		log_print("can't start dlm_send %d", error);
-		destroy_workqueue(recv_workqueue);
-		return error;
-	}
-
-	return 0;
-}
-
-void dlm_lowcomms_stop(void)
-{
-	int i;
-
-	/* Set all the flags to prevent any
-	   socket activity.
-	*/
-	for (i = 0; i < conn_array_size; i++) {
-		if (connections[i])
-			connections[i]->flags |= 0xFF;
-	}
-
-	work_stop();
-	clean_writequeues();
-
-	for (i = 0; i < conn_array_size; i++) {
-		if (connections[i]) {
-			close_connection(connections[i], true);
-			if (connections[i]->othercon)
-				kmem_cache_free(con_cache, connections[i]->othercon);
-			kmem_cache_free(con_cache, connections[i]);
-		}
-	}
-
-	kfree(connections);
-	connections = NULL;
-
-	kmem_cache_destroy(con_cache);
-}
-
-/* This is quite likely to sleep... */
-int dlm_lowcomms_start(void)
-{
-	int error = 0;
-
-	error = -ENOMEM;
-	connections = kzalloc(sizeof(struct connection *) *
-			      NODE_INCREMENT, GFP_KERNEL);
-	if (!connections)
-		goto out;
-
-	conn_array_size = NODE_INCREMENT;
-
-	if (dlm_our_addr(&dlm_local_addr, 0)) {
-		log_print("no local IP address has been set");
-		goto fail_free_conn;
-	}
-	if (!dlm_our_addr(&dlm_local_addr, 1)) {
-		log_print("This dlm comms module does not support multi-homed clustering");
-		goto fail_free_conn;
-	}
-
-	con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
-				      __alignof__(struct connection), 0,
-				      NULL, NULL);
-	if (!con_cache)
-		goto fail_free_conn;
-
-
-	/* Start listening */
-	error = listen_for_all();
-	if (error)
-		goto fail_unlisten;
-
-	error = work_start();
-	if (error)
-		goto fail_unlisten;
-
-	return 0;
-
-fail_unlisten:
-	close_connection(connections[0], false);
-	kmem_cache_free(con_cache, connections[0]);
-	kmem_cache_destroy(con_cache);
-
-fail_free_conn:
-	kfree(connections);
-
-out:
-	return error;
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
new file mode 100644
index 0000000..27970a5
--- /dev/null
+++ b/fs/dlm/lowcomms.c
@@ -0,0 +1,1475 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2007 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.
+ *
+ * lowcomms will choose to use wither TCP or SCTP as its transport layer
+ * depending on the configuration variable 'protocol'. This should be set
+ * to 0 (default) for TCP or 1 for SCTP. It shouldbe configured using a
+ * cluster-wide mechanism as it must be the same on all nodes of the cluster
+ * for the DLM to function.
+ *
+ */
+
+#include <asm/ioctls.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <linux/pagemap.h>
+#include <linux/idr.h>
+#include <linux/file.h>
+#include <linux/sctp.h>
+#include <net/sctp/user.h>
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "midcomms.h"
+#include "config.h"
+
+#define NEEDED_RMEM (4*1024*1024)
+
+struct cbuf {
+	unsigned int base;
+	unsigned int len;
+	unsigned int mask;
+};
+
+static void cbuf_add(struct cbuf *cb, int n)
+{
+	cb->len += n;
+}
+
+static int cbuf_data(struct cbuf *cb)
+{
+	return ((cb->base + cb->len) & cb->mask);
+}
+
+static void cbuf_init(struct cbuf *cb, int size)
+{
+	cb->base = cb->len = 0;
+	cb->mask = size-1;
+}
+
+static void cbuf_eat(struct cbuf *cb, int n)
+{
+	cb->len  -= n;
+	cb->base += n;
+	cb->base &= cb->mask;
+}
+
+static bool cbuf_empty(struct cbuf *cb)
+{
+	return cb->len == 0;
+}
+
+struct connection {
+	struct socket *sock;	/* NULL if not connected */
+	uint32_t nodeid;	/* So we know who we are in the list */
+	struct mutex sock_mutex;
+	unsigned long flags;
+#define CF_READ_PENDING 1
+#define CF_WRITE_PENDING 2
+#define CF_CONNECT_PENDING 3
+#define CF_INIT_PENDING 4
+#define CF_IS_OTHERCON 5
+	struct list_head writequeue;  /* List of outgoing writequeue_entries */
+	spinlock_t writequeue_lock;
+	int (*rx_action) (struct connection *);	/* What to do when active */
+	void (*connect_action) (struct connection *);	/* What to do to connect */
+	struct page *rx_page;
+	struct cbuf cb;
+	int retries;
+#define MAX_CONNECT_RETRIES 3
+	int sctp_assoc;
+	struct connection *othercon;
+	struct work_struct rwork; /* Receive workqueue */
+	struct work_struct swork; /* Send workqueue */
+};
+#define sock2con(x) ((struct connection *)(x)->sk_user_data)
+
+/* 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 connection *con;
+};
+
+static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
+static int dlm_local_count;
+
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
+
+static DEFINE_IDR(connections_idr);
+static DECLARE_MUTEX(connections_lock);
+static int max_nodeid;
+static struct kmem_cache *con_cache;
+
+static void process_recv_sockets(struct work_struct *work);
+static void process_send_sockets(struct work_struct *work);
+
+/*
+ * If 'allocation' is zero then we don't attempt to create a new
+ * connection structure for this node.
+ */
+static struct connection *__nodeid2con(int nodeid, gfp_t alloc)
+{
+	struct connection *con = NULL;
+	int r;
+	int n;
+
+	con = idr_find(&connections_idr, nodeid);
+	if (con || !alloc)
+		return con;
+
+	r = idr_pre_get(&connections_idr, alloc);
+	if (!r)
+		return NULL;
+
+	con = kmem_cache_zalloc(con_cache, alloc);
+	if (!con)
+		return NULL;
+
+	r = idr_get_new_above(&connections_idr, con, nodeid, &n);
+	if (r) {
+		kmem_cache_free(con_cache, con);
+		return NULL;
+	}
+
+	if (n != nodeid) {
+		idr_remove(&connections_idr, n);
+		kmem_cache_free(con_cache, con);
+		return NULL;
+	}
+
+	con->nodeid = nodeid;
+	mutex_init(&con->sock_mutex);
+	INIT_LIST_HEAD(&con->writequeue);
+	spin_lock_init(&con->writequeue_lock);
+	INIT_WORK(&con->swork, process_send_sockets);
+	INIT_WORK(&con->rwork, process_recv_sockets);
+
+	/* Setup action pointers for child sockets */
+	if (con->nodeid) {
+		struct connection *zerocon = idr_find(&connections_idr, 0);
+
+		con->connect_action = zerocon->connect_action;
+		if (!con->rx_action)
+			con->rx_action = zerocon->rx_action;
+	}
+
+	if (nodeid > max_nodeid)
+		max_nodeid = nodeid;
+
+	return con;
+}
+
+static struct connection *nodeid2con(int nodeid, gfp_t allocation)
+{
+	struct connection *con;
+
+	down(&connections_lock);
+	con = __nodeid2con(nodeid, allocation);
+	up(&connections_lock);
+
+	return con;
+}
+
+/* This is a bit drastic, but only called when things go wrong */
+static struct connection *assoc2con(int assoc_id)
+{
+	int i;
+	struct connection *con;
+
+	down(&connections_lock);
+	for (i=0; i<=max_nodeid; i++) {
+		con = __nodeid2con(i, 0);
+		if (con && con->sctp_assoc == assoc_id) {
+			up(&connections_lock);
+			return con;
+		}
+	}
+	up(&connections_lock);
+	return NULL;
+}
+
+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;
+}
+
+/* Data available on socket or listen socket received a connect */
+static void lowcomms_data_ready(struct sock *sk, int count_unused)
+{
+	struct connection *con = sock2con(sk);
+	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+		queue_work(recv_workqueue, &con->rwork);
+}
+
+static void lowcomms_write_space(struct sock *sk)
+{
+	struct connection *con = sock2con(sk);
+
+	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
+		queue_work(send_workqueue, &con->swork);
+}
+
+static inline void lowcomms_connect_sock(struct connection *con)
+{
+	if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
+		queue_work(send_workqueue, &con->swork);
+}
+
+static void lowcomms_state_change(struct sock *sk)
+{
+	if (sk->sk_state == TCP_ESTABLISHED)
+		lowcomms_write_space(sk);
+}
+
+/* Make a socket active */
+static int add_sock(struct socket *sock, struct connection *con)
+{
+	con->sock = sock;
+
+	/* Install a data_ready callback */
+	con->sock->sk->sk_data_ready = lowcomms_data_ready;
+	con->sock->sk->sk_write_space = lowcomms_write_space;
+	con->sock->sk->sk_state_change = lowcomms_state_change;
+	con->sock->sk->sk_user_data = con;
+	return 0;
+}
+
+/* Add the port number to an IPv6 or 4 sockaddr and return the address
+   length */
+static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
+			  int *addr_len)
+{
+	saddr->ss_family =  dlm_local_addr[0]->ss_family;
+	if (saddr->ss_family == AF_INET) {
+		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
+		in4_addr->sin_port = cpu_to_be16(port);
+		*addr_len = sizeof(struct sockaddr_in);
+		memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
+	} else {
+		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
+		in6_addr->sin6_port = cpu_to_be16(port);
+		*addr_len = sizeof(struct sockaddr_in6);
+	}
+}
+
+/* Close a remote connection and tidy up */
+static void close_connection(struct connection *con, bool and_other)
+{
+	mutex_lock(&con->sock_mutex);
+
+	if (con->sock) {
+		sock_release(con->sock);
+		con->sock = NULL;
+	}
+	if (con->othercon && and_other) {
+		/* Will only re-enter once. */
+		close_connection(con->othercon, false);
+	}
+	if (con->rx_page) {
+		__free_page(con->rx_page);
+		con->rx_page = NULL;
+	}
+	con->retries = 0;
+	mutex_unlock(&con->sock_mutex);
+}
+
+/* We only send shutdown messages to nodes that are not part of the cluster */
+static void sctp_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;
+	struct connection *con;
+
+	con = nodeid2con(0,0);
+	BUG_ON(con == NULL);
+
+	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 = CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+	sinfo->sinfo_flags |= MSG_EOF;
+	sinfo->sinfo_assoc_id = associd;
+
+	ret = kernel_sendmsg(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 sctp_init_failed(void)
+{
+	int i;
+	struct connection *con;
+
+	down(&connections_lock);
+	for (i=1; i<=max_nodeid; i++) {
+		con = __nodeid2con(i, 0);
+		if (!con)
+			continue;
+		con->sctp_assoc = 0;
+		if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
+			if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+				queue_work(send_workqueue, &con->swork);
+			}
+		}
+	}
+	up(&connections_lock);
+}
+
+/* Something happened to an association */
+static void process_sctp_notification(struct connection *con,
+				      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;
+			int nodeid;
+			int prim_len, ret;
+			int addr_len;
+			struct connection *new_con;
+			struct file *file;
+			sctp_peeloff_arg_t parg;
+			int parglen = sizeof(parg);
+
+			/*
+			 * We get this before any data for an association.
+			 * We verify that the node is in the cluster and
+			 * then peel off a socket for it.
+			 */
+			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);
+				sctp_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;
+
+			ret = kernel_getsockopt(con->sock,
+						IPPROTO_SCTP,
+						SCTP_PRIMARY_ADDR,
+						(char*)&prim,
+						&prim_len);
+			if (ret < 0) {
+				log_print("getsockopt/sctp_primary_addr on "
+					  "new assoc %d failed : %d",
+					  (int)sn->sn_assoc_change.sac_assoc_id,
+					  ret);
+
+				/* Retry INIT later */
+				new_con = assoc2con(sn->sn_assoc_change.sac_assoc_id);
+				if (new_con)
+					clear_bit(CF_CONNECT_PENDING, &con->flags);
+				return;
+			}
+			make_sockaddr(&prim.ssp_addr, 0, &addr_len);
+			if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+				int i;
+				unsigned char *b=(unsigned char *)&prim.ssp_addr;
+				log_print("reject connect from unknown addr");
+				for (i=0; i<sizeof(struct sockaddr_storage);i++)
+					printk("%02x ", b[i]);
+				printk("\n");
+				sctp_send_shutdown(prim.ssp_assoc_id);
+				return;
+			}
+
+			new_con = nodeid2con(nodeid, GFP_KERNEL);
+			if (!new_con)
+				return;
+
+			/* Peel off a new sock */
+			parg.associd = sn->sn_assoc_change.sac_assoc_id;
+			ret = kernel_getsockopt(con->sock, IPPROTO_SCTP,
+						SCTP_SOCKOPT_PEELOFF,
+						(void *)&parg, &parglen);
+			if (ret) {
+				log_print("Can't peel off a socket for "
+					  "connection %d to node %d: err=%d\n",
+					  parg.associd, nodeid, ret);
+			}
+			file = fget(parg.sd);
+			new_con->sock = SOCKET_I(file->f_dentry->d_inode);
+			add_sock(new_con->sock, new_con);
+			fput(file);
+			put_unused_fd(parg.sd);
+
+			log_print("got new/restarted association %d nodeid %d",
+				 (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+
+			/* Send any pending writes */
+			clear_bit(CF_CONNECT_PENDING, &new_con->flags);
+			clear_bit(CF_INIT_PENDING, &con->flags);
+			if (!test_and_set_bit(CF_WRITE_PENDING, &new_con->flags)) {
+				queue_work(send_workqueue, &new_con->swork);
+			}
+			if (!test_and_set_bit(CF_READ_PENDING, &new_con->flags))
+				queue_work(recv_workqueue, &new_con->rwork);
+		}
+		break;
+
+		case SCTP_COMM_LOST:
+		case SCTP_SHUTDOWN_COMP:
+		{
+			con = assoc2con(sn->sn_assoc_change.sac_assoc_id);
+			if (con) {
+				con->sctp_assoc = 0;
+			}
+		}
+		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");
+			sctp_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(struct connection *con)
+{
+	int ret = 0;
+	struct msghdr msg = {};
+	struct kvec iov[2];
+	unsigned len;
+	int r;
+	int call_again_soon = 0;
+	int nvec;
+	char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+
+	mutex_lock(&con->sock_mutex);
+
+	if (con->sock == NULL) {
+		ret = -EAGAIN;
+		goto out_close;
+	}
+
+	if (con->rx_page == NULL) {
+		/*
+		 * This doesn't need to be atomic, but I think it should
+		 * improve performance if it is.
+		 */
+		con->rx_page = alloc_page(GFP_ATOMIC);
+		if (con->rx_page == NULL)
+			goto out_resched;
+		cbuf_init(&con->cb, PAGE_CACHE_SIZE);
+	}
+
+	/* Only SCTP needs these really */
+	memset(&incmsg, 0, sizeof(incmsg));
+	msg.msg_control = incmsg;
+	msg.msg_controllen = sizeof(incmsg);
+
+	/*
+	 * 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 = con->cb.base - cbuf_data(&con->cb);
+	iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
+	iov[1].iov_len = 0;
+	nvec = 1;
+
+	/*
+	 * 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(&con->cb) >= con->cb.base) {
+		iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&con->cb);
+		iov[1].iov_len = con->cb.base;
+		iov[1].iov_base = page_address(con->rx_page);
+		nvec = 2;
+	}
+	len = iov[0].iov_len + iov[1].iov_len;
+
+	r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
+			       MSG_DONTWAIT | MSG_NOSIGNAL);
+	if (ret <= 0)
+		goto out_close;
+
+	/* Process SCTP notifications */
+	if (msg.msg_flags & MSG_NOTIFICATION) {
+		msg.msg_control = incmsg;
+		msg.msg_controllen = sizeof(incmsg);
+
+		process_sctp_notification(con, &msg,
+				page_address(con->rx_page) + con->cb.base);
+		mutex_unlock(&con->sock_mutex);
+		return 0;
+	}
+	BUG_ON(con->nodeid == 0);
+
+	if (ret == len)
+		call_again_soon = 1;
+	cbuf_add(&con->cb, ret);
+	ret = dlm_process_incoming_buffer(con->nodeid,
+					  page_address(con->rx_page),
+					  con->cb.base, con->cb.len,
+					  PAGE_CACHE_SIZE);
+	if (ret == -EBADMSG) {
+		log_print("lowcomms: addr=%p, base=%u, len=%u, "
+			  "iov_len=%u, iov_base[0]=%p, read=%d",
+			  page_address(con->rx_page), con->cb.base, con->cb.len,
+			  len, iov[0].iov_base, r);
+	}
+	if (ret < 0)
+		goto out_close;
+	cbuf_eat(&con->cb, ret);
+
+	if (cbuf_empty(&con->cb) && !call_again_soon) {
+		__free_page(con->rx_page);
+		con->rx_page = NULL;
+	}
+
+	if (call_again_soon)
+		goto out_resched;
+	mutex_unlock(&con->sock_mutex);
+	return 0;
+
+out_resched:
+	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+		queue_work(recv_workqueue, &con->rwork);
+	mutex_unlock(&con->sock_mutex);
+	return -EAGAIN;
+
+out_close:
+	mutex_unlock(&con->sock_mutex);
+	if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) {
+		close_connection(con, false);
+		/* Reconnect when there is something to send */
+	}
+	/* Don't return success if we really got EOF */
+	if (ret == 0)
+		ret = -EAGAIN;
+
+	return ret;
+}
+
+/* Listening socket is busy, accept a connection */
+static int tcp_accept_from_sock(struct connection *con)
+{
+	int result;
+	struct sockaddr_storage peeraddr;
+	struct socket *newsock;
+	int len;
+	int nodeid;
+	struct connection *newcon;
+	struct connection *addcon;
+
+	memset(&peeraddr, 0, sizeof(peeraddr));
+	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
+				  IPPROTO_TCP, &newsock);
+	if (result < 0)
+		return -ENOMEM;
+
+	mutex_lock_nested(&con->sock_mutex, 0);
+
+	result = -ENOTCONN;
+	if (con->sock == NULL)
+		goto accept_err;
+
+	newsock->type = con->sock->type;
+	newsock->ops = con->sock->ops;
+
+	result = con->sock->ops->accept(con->sock, newsock, O_NONBLOCK);
+	if (result < 0)
+		goto accept_err;
+
+	/* Get the connected socket's peer */
+	memset(&peeraddr, 0, sizeof(peeraddr));
+	if (newsock->ops->getname(newsock, (struct sockaddr *)&peeraddr,
+				  &len, 2)) {
+		result = -ECONNABORTED;
+		goto accept_err;
+	}
+
+	/* Get the new node's NODEID */
+	make_sockaddr(&peeraddr, 0, &len);
+	if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
+		log_print("connect from non cluster node");
+		sock_release(newsock);
+		mutex_unlock(&con->sock_mutex);
+		return -1;
+	}
+
+	log_print("got connection from %d", nodeid);
+
+	/*  Check to see if we already have a connection to this node. This
+	 *  could happen if the two nodes initiate a connection at roughly
+	 *  the same time and the connections cross on the wire.
+	 *  In this case we store the incoming one in "othercon"
+	 */
+	newcon = nodeid2con(nodeid, GFP_KERNEL);
+	if (!newcon) {
+		result = -ENOMEM;
+		goto accept_err;
+	}
+	mutex_lock_nested(&newcon->sock_mutex, 1);
+	if (newcon->sock) {
+		struct connection *othercon = newcon->othercon;
+
+		if (!othercon) {
+			othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
+			if (!othercon) {
+				log_print("failed to allocate incoming socket");
+				mutex_unlock(&newcon->sock_mutex);
+				result = -ENOMEM;
+				goto accept_err;
+			}
+			othercon->nodeid = nodeid;
+			othercon->rx_action = receive_from_sock;
+			mutex_init(&othercon->sock_mutex);
+			INIT_WORK(&othercon->swork, process_send_sockets);
+			INIT_WORK(&othercon->rwork, process_recv_sockets);
+			set_bit(CF_IS_OTHERCON, &othercon->flags);
+			newcon->othercon = othercon;
+		}
+		othercon->sock = newsock;
+		newsock->sk->sk_user_data = othercon;
+		add_sock(newsock, othercon);
+		addcon = othercon;
+	}
+	else {
+		newsock->sk->sk_user_data = newcon;
+		newcon->rx_action = receive_from_sock;
+		add_sock(newsock, newcon);
+		addcon = newcon;
+	}
+
+	mutex_unlock(&newcon->sock_mutex);
+
+	/*
+	 * Add it to the active queue in case we got data
+	 * beween processing the accept adding the socket
+	 * to the read_sockets list
+	 */
+	if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
+		queue_work(recv_workqueue, &addcon->rwork);
+	mutex_unlock(&con->sock_mutex);
+
+	return 0;
+
+accept_err:
+	mutex_unlock(&con->sock_mutex);
+	sock_release(newsock);
+
+	if (result != -EAGAIN)
+		log_print("error accepting connection from node: %d", result);
+	return result;
+}
+
+static void free_entry(struct writequeue_entry *e)
+{
+	__free_page(e->page);
+	kfree(e);
+}
+
+/* Initiate an SCTP association.
+   This is a special case of send_to_sock() in that we don't yet have a
+   peeled-off socket for this association, so we use the listening socket
+   and add the primary IP address of the remote node.
+ */
+static void sctp_init_assoc(struct connection *con)
+{
+	struct sockaddr_storage rem_addr;
+	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct msghdr outmessage;
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	struct connection *base_con;
+	struct writequeue_entry *e;
+	int len, offset;
+	int ret;
+	int addrlen;
+	struct kvec iov[1];
+
+	if (test_and_set_bit(CF_INIT_PENDING, &con->flags))
+		return;
+
+	if (con->retries++ > MAX_CONNECT_RETRIES)
+		return;
+
+	log_print("Initiating association with node %d", con->nodeid);
+
+	if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&rem_addr)) {
+		log_print("no address for nodeid %d", con->nodeid);
+		return;
+	}
+	base_con = nodeid2con(0, 0);
+	BUG_ON(base_con == NULL);
+
+	make_sockaddr(&rem_addr, dlm_config.ci_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;
+
+	spin_lock(&con->writequeue_lock);
+	e = list_entry(con->writequeue.next, struct writequeue_entry,
+		       list);
+
+	BUG_ON((struct list_head *) e == &con->writequeue);
+
+	len = e->len;
+	offset = e->offset;
+	spin_unlock(&con->writequeue_lock);
+	kmap(e->page);
+
+	/* Send the first block off the write queue */
+	iov[0].iov_base = page_address(e->page)+offset;
+	iov[0].iov_len = len;
+
+	cmsg = CMSG_FIRSTHDR(&outmessage);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	sinfo = CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = cpu_to_le32(dlm_our_nodeid());
+	outmessage.msg_controllen = cmsg->cmsg_len;
+
+	ret = kernel_sendmsg(base_con->sock, &outmessage, iov, 1, len);
+	if (ret < 0) {
+		log_print("Send first packet to node %d failed: %d",
+			  con->nodeid, ret);
+
+		/* Try again later */
+		clear_bit(CF_CONNECT_PENDING, &con->flags);
+		clear_bit(CF_INIT_PENDING, &con->flags);
+	}
+	else {
+		spin_lock(&con->writequeue_lock);
+		e->offset += ret;
+		e->len -= ret;
+
+		if (e->len == 0 && e->users == 0) {
+			list_del(&e->list);
+			kunmap(e->page);
+			free_entry(e);
+		}
+		spin_unlock(&con->writequeue_lock);
+	}
+}
+
+/* Connect a new socket to its peer */
+static void tcp_connect_to_sock(struct connection *con)
+{
+	int result = -EHOSTUNREACH;
+	struct sockaddr_storage saddr;
+	int addr_len;
+	struct socket *sock;
+
+	if (con->nodeid == 0) {
+		log_print("attempt to connect sock 0 foiled");
+		return;
+	}
+
+	mutex_lock(&con->sock_mutex);
+	if (con->retries++ > MAX_CONNECT_RETRIES)
+		goto out;
+
+	/* Some odd races can cause double-connects, ignore them */
+	if (con->sock) {
+		result = 0;
+		goto out;
+	}
+
+	/* Create a socket to communicate with */
+	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
+				  IPPROTO_TCP, &sock);
+	if (result < 0)
+		goto out_err;
+
+	memset(&saddr, 0, sizeof(saddr));
+	if (dlm_nodeid_to_addr(con->nodeid, &saddr))
+		goto out_err;
+
+	sock->sk->sk_user_data = con;
+	con->rx_action = receive_from_sock;
+	con->connect_action = tcp_connect_to_sock;
+	add_sock(sock, con);
+
+	make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
+
+	log_print("connecting to %d", con->nodeid);
+	result =
+		sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
+				   O_NONBLOCK);
+	if (result == -EINPROGRESS)
+		result = 0;
+	if (result == 0)
+		goto out;
+
+out_err:
+	if (con->sock) {
+		sock_release(con->sock);
+		con->sock = NULL;
+	}
+	/*
+	 * Some errors are fatal and this list might need adjusting. For other
+	 * errors we try again until the max number of retries is reached.
+	 */
+	if (result != -EHOSTUNREACH && result != -ENETUNREACH &&
+	    result != -ENETDOWN && result != EINVAL
+	    && result != -EPROTONOSUPPORT) {
+		lowcomms_connect_sock(con);
+		result = 0;
+	}
+out:
+	mutex_unlock(&con->sock_mutex);
+	return;
+}
+
+static struct socket *tcp_create_listen_sock(struct connection *con,
+					     struct sockaddr_storage *saddr)
+{
+	struct socket *sock = NULL;
+	int result = 0;
+	int one = 1;
+	int addr_len;
+
+	if (dlm_local_addr[0]->ss_family == AF_INET)
+		addr_len = sizeof(struct sockaddr_in);
+	else
+		addr_len = sizeof(struct sockaddr_in6);
+
+	/* Create a socket to communicate with */
+	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
+				  IPPROTO_TCP, &sock);
+	if (result < 0) {
+		log_print("Can't create listening comms socket");
+		goto create_out;
+	}
+
+	result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+				   (char *)&one, sizeof(one));
+
+	if (result < 0) {
+		log_print("Failed to set SO_REUSEADDR on socket: %d", result);
+	}
+	sock->sk->sk_user_data = con;
+	con->rx_action = tcp_accept_from_sock;
+	con->connect_action = tcp_connect_to_sock;
+	con->sock = sock;
+
+	/* Bind to our port */
+	make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
+	result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
+	if (result < 0) {
+		log_print("Can't bind to port %d", dlm_config.ci_tcp_port);
+		sock_release(sock);
+		sock = NULL;
+		con->sock = NULL;
+		goto create_out;
+	}
+	result = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+				 (char *)&one, sizeof(one));
+	if (result < 0) {
+		log_print("Set keepalive failed: %d", result);
+	}
+
+	result = sock->ops->listen(sock, 5);
+	if (result < 0) {
+		log_print("Can't listen on port %d", dlm_config.ci_tcp_port);
+		sock_release(sock);
+		sock = NULL;
+		goto create_out;
+	}
+
+create_out:
+	return sock;
+}
+
+/* Get local addresses */
+static void init_local(void)
+{
+	struct sockaddr_storage sas, *addr;
+	int i;
+
+	dlm_local_count = 0;
+	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;
+	}
+}
+
+/* Bind to an IP address. SCTP allows multiple address so it can do
+   multi-homing */
+static int add_sctp_bind_addr(struct connection *sctp_con,
+			      struct sockaddr_storage *addr,
+			      int addr_len, int num)
+{
+	int result = 0;
+
+	if (num == 1)
+		result = kernel_bind(sctp_con->sock,
+				     (struct sockaddr *) addr,
+				     addr_len);
+	else
+		result = kernel_setsockopt(sctp_con->sock, SOL_SCTP,
+					   SCTP_SOCKOPT_BINDX_ADD,
+					   (char *)addr, addr_len);
+
+	if (result < 0)
+		log_print("Can't bind to port %d addr number %d",
+			  dlm_config.ci_tcp_port, num);
+
+	return result;
+}
+
+/* Initialise SCTP socket and bind to all interfaces */
+static int sctp_listen_for_all(void)
+{
+	struct socket *sock = NULL;
+	struct sockaddr_storage localaddr;
+	struct sctp_event_subscribe subscribe;
+	int result = -EINVAL, num = 1, i, addr_len;
+	struct connection *con = nodeid2con(0, GFP_KERNEL);
+	int bufsize = NEEDED_RMEM;
+
+	if (!con)
+		return -ENOMEM;
+
+	log_print("Using SCTP for communications");
+
+	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;
+
+	result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+				 (char *)&bufsize, sizeof(bufsize));
+	if (result)
+		log_print("Error increasing buffer space on socket %d", result);
+
+	result = kernel_setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
+				   (char *)&subscribe, sizeof(subscribe));
+	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 = con;
+	con->sock = sock;
+	con->sock->sk->sk_data_ready = lowcomms_data_ready;
+	con->rx_action = receive_from_sock;
+	con->connect_action = sctp_init_assoc;
+
+	/* 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.ci_tcp_port, &addr_len);
+
+		result = add_sctp_bind_addr(con, &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);
+	con->sock = NULL;
+out:
+	return result;
+}
+
+static int tcp_listen_for_all(void)
+{
+	struct socket *sock = NULL;
+	struct connection *con = nodeid2con(0, GFP_KERNEL);
+	int result = -EINVAL;
+
+	if (!con)
+		return -ENOMEM;
+
+	/* We don't support multi-homed hosts */
+	if (dlm_local_addr[1] != NULL) {
+		log_print("TCP protocol can't handle multi-homed hosts, "
+			  "try SCTP");
+		return -EINVAL;
+	}
+
+	log_print("Using TCP for communications");
+
+	set_bit(CF_IS_OTHERCON, &con->flags);
+
+	sock = tcp_create_listen_sock(con, dlm_local_addr[0]);
+	if (sock) {
+		add_sock(sock, con);
+		result = 0;
+	}
+	else {
+		result = -EADDRINUSE;
+	}
+
+	return result;
+}
+
+
+
+static struct writequeue_entry *new_writequeue_entry(struct connection *con,
+						     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;
+	entry->con = con;
+
+	return entry;
+}
+
+void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
+{
+	struct connection *con;
+	struct writequeue_entry *e;
+	int offset = 0;
+	int users = 0;
+
+	con = nodeid2con(nodeid, allocation);
+	if (!con)
+		return NULL;
+
+	spin_lock(&con->writequeue_lock);
+	e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
+	if ((&e->list == &con->writequeue) ||
+	    (PAGE_CACHE_SIZE - e->end < len)) {
+		e = NULL;
+	} else {
+		offset = e->end;
+		e->end += len;
+		users = e->users++;
+	}
+	spin_unlock(&con->writequeue_lock);
+
+	if (e) {
+	got_one:
+		if (users == 0)
+			kmap(e->page);
+		*ppc = page_address(e->page) + offset;
+		return e;
+	}
+
+	e = new_writequeue_entry(con, allocation);
+	if (e) {
+		spin_lock(&con->writequeue_lock);
+		offset = e->end;
+		e->end += len;
+		users = e->users++;
+		list_add_tail(&e->list, &con->writequeue);
+		spin_unlock(&con->writequeue_lock);
+		goto got_one;
+	}
+	return NULL;
+}
+
+void dlm_lowcomms_commit_buffer(void *mh)
+{
+	struct writequeue_entry *e = (struct writequeue_entry *)mh;
+	struct connection *con = e->con;
+	int users;
+
+	spin_lock(&con->writequeue_lock);
+	users = --e->users;
+	if (users)
+		goto out;
+	e->len = e->end - e->offset;
+	kunmap(e->page);
+	spin_unlock(&con->writequeue_lock);
+
+	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+		queue_work(send_workqueue, &con->swork);
+	}
+	return;
+
+out:
+	spin_unlock(&con->writequeue_lock);
+	return;
+}
+
+/* Send a message */
+static void send_to_sock(struct connection *con)
+{
+	int ret = 0;
+	ssize_t(*sendpage) (struct socket *, struct page *, int, size_t, int);
+	const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
+	struct writequeue_entry *e;
+	int len, offset;
+
+	mutex_lock(&con->sock_mutex);
+	if (con->sock == NULL)
+		goto out_connect;
+
+	sendpage = con->sock->ops->sendpage;
+
+	spin_lock(&con->writequeue_lock);
+	for (;;) {
+		e = list_entry(con->writequeue.next, struct writequeue_entry,
+			       list);
+		if ((struct list_head *) e == &con->writequeue)
+			break;
+
+		len = e->len;
+		offset = e->offset;
+		BUG_ON(len == 0 && e->users == 0);
+		spin_unlock(&con->writequeue_lock);
+		kmap(e->page);
+
+		ret = 0;
+		if (len) {
+			ret = sendpage(con->sock, e->page, offset, len,
+				       msg_flags);
+			if (ret == -EAGAIN || ret == 0)
+				goto out;
+			if (ret <= 0)
+				goto send_error;
+		} else {
+			/* Don't starve people filling buffers */
+			cond_resched();
+		}
+
+		spin_lock(&con->writequeue_lock);
+		e->offset += ret;
+		e->len -= ret;
+
+		if (e->len == 0 && e->users == 0) {
+			list_del(&e->list);
+			kunmap(e->page);
+			free_entry(e);
+			continue;
+		}
+	}
+	spin_unlock(&con->writequeue_lock);
+out:
+	mutex_unlock(&con->sock_mutex);
+	return;
+
+send_error:
+	mutex_unlock(&con->sock_mutex);
+	close_connection(con, false);
+	lowcomms_connect_sock(con);
+	return;
+
+out_connect:
+	mutex_unlock(&con->sock_mutex);
+	if (!test_bit(CF_INIT_PENDING, &con->flags))
+		lowcomms_connect_sock(con);
+	return;
+}
+
+static void clean_one_writequeue(struct connection *con)
+{
+	struct list_head *list;
+	struct list_head *temp;
+
+	spin_lock(&con->writequeue_lock);
+	list_for_each_safe(list, temp, &con->writequeue) {
+		struct writequeue_entry *e =
+			list_entry(list, struct writequeue_entry, list);
+		list_del(&e->list);
+		free_entry(e);
+	}
+	spin_unlock(&con->writequeue_lock);
+}
+
+/* Called from recovery when it knows that a node has
+   left the cluster */
+int dlm_lowcomms_close(int nodeid)
+{
+	struct connection *con;
+
+	log_print("closing connection to node %d", nodeid);
+	con = nodeid2con(nodeid, 0);
+	if (con) {
+		clean_one_writequeue(con);
+		close_connection(con, true);
+	}
+	return 0;
+}
+
+/* Receive workqueue function */
+static void process_recv_sockets(struct work_struct *work)
+{
+	struct connection *con = container_of(work, struct connection, rwork);
+	int err;
+
+	clear_bit(CF_READ_PENDING, &con->flags);
+	do {
+		err = con->rx_action(con);
+	} while (!err);
+}
+
+/* Send workqueue function */
+static void process_send_sockets(struct work_struct *work)
+{
+	struct connection *con = container_of(work, struct connection, swork);
+
+	if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
+		con->connect_action(con);
+	}
+	clear_bit(CF_WRITE_PENDING, &con->flags);
+	send_to_sock(con);
+}
+
+
+/* Discard all entries on the write queues */
+static void clean_writequeues(void)
+{
+	int nodeid;
+
+	for (nodeid = 1; nodeid <= max_nodeid; nodeid++) {
+		struct connection *con = __nodeid2con(nodeid, 0);
+
+		if (con)
+			clean_one_writequeue(con);
+	}
+}
+
+static void work_stop(void)
+{
+	destroy_workqueue(recv_workqueue);
+	destroy_workqueue(send_workqueue);
+}
+
+static int work_start(void)
+{
+	int error;
+	recv_workqueue = create_workqueue("dlm_recv");
+	error = IS_ERR(recv_workqueue);
+	if (error) {
+		log_print("can't start dlm_recv %d", error);
+		return error;
+	}
+
+	send_workqueue = create_singlethread_workqueue("dlm_send");
+	error = IS_ERR(send_workqueue);
+	if (error) {
+		log_print("can't start dlm_send %d", error);
+		destroy_workqueue(recv_workqueue);
+		return error;
+	}
+
+	return 0;
+}
+
+void dlm_lowcomms_stop(void)
+{
+	int i;
+	struct connection *con;
+
+	/* Set all the flags to prevent any
+	   socket activity.
+	*/
+	down(&connections_lock);
+	for (i = 0; i <= max_nodeid; i++) {
+		con = __nodeid2con(i, 0);
+		if (con)
+			con->flags |= 0xFF;
+	}
+	up(&connections_lock);
+
+	work_stop();
+
+	down(&connections_lock);
+	clean_writequeues();
+
+	for (i = 0; i <= max_nodeid; i++) {
+		con = __nodeid2con(i, 0);
+		if (con) {
+			close_connection(con, true);
+			if (con->othercon)
+				kmem_cache_free(con_cache, con->othercon);
+			kmem_cache_free(con_cache, con);
+		}
+	}
+	max_nodeid = 0;
+	up(&connections_lock);
+	kmem_cache_destroy(con_cache);
+	idr_init(&connections_idr);
+}
+
+int dlm_lowcomms_start(void)
+{
+	int error = -EINVAL;
+	struct connection *con;
+
+	init_local();
+	if (!dlm_local_count) {
+		error = -ENOTCONN;
+		log_print("no local IP address has been set");
+		goto out;
+	}
+
+	error = -ENOMEM;
+	con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
+				      __alignof__(struct connection), 0,
+				      NULL, NULL);
+	if (!con_cache)
+		goto out;
+
+	/* Set some sysctl minima */
+	if (sysctl_rmem_max < NEEDED_RMEM)
+		sysctl_rmem_max = NEEDED_RMEM;
+
+	/* Start listening */
+	if (dlm_config.ci_protocol == 0)
+		error = tcp_listen_for_all();
+	else
+		error = sctp_listen_for_all();
+	if (error)
+		goto fail_unlisten;
+
+	error = work_start();
+	if (error)
+		goto fail_unlisten;
+
+	return 0;
+
+fail_unlisten:
+	con = nodeid2con(0,0);
+	if (con) {
+		close_connection(con, false);
+		kmem_cache_free(con_cache, con);
+	}
+	kmem_cache_destroy(con_cache);
+
+out:
+	return error;
+}
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 3870150..b0201ec 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2006-2007 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
@@ -56,6 +56,7 @@ struct dlm_write_request32 {
 	union  {
 		struct dlm_lock_params32 lock;
 		struct dlm_lspace_params lspace;
+		struct dlm_purge_params purge;
 	} i;
 };
 
@@ -92,6 +93,9 @@ static void compat_input(struct dlm_writ
 		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 if (kb->cmd == DLM_USER_PURGE) {
+		kb->i.purge.nodeid = kb32->i.purge.nodeid;
+		kb->i.purge.pid = kb32->i.purge.pid;
 	} else {
 		kb->i.lock.mode = kb32->i.lock.mode;
 		kb->i.lock.namelen = kb32->i.lock.namelen;
@@ -111,8 +115,6 @@ static void compat_input(struct dlm_writ
 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;
@@ -128,35 +130,30 @@ static void compat_output(struct dlm_loc
 }
 #endif
 
+/* we could possibly check if the cancel of an orphan has resulted in the lkb
+   being removed and then remove that lkb from the orphans list and free it */
 
 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;
+	int eol = 0, ast_type;
 
-	/* 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); */
+	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
 		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. */
+	   lkb->ua so we can't try to use it.  This second check is necessary
+	   for cases where a completion ast is received for an operation that
+	   began before clear_proc_locks did its cancel/unlock. */
 
-	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
-		/* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
+	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
 		goto out;
-	}
 
 	DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
 	ua = (struct dlm_user_args *)lkb->lkb_astparam;
@@ -166,28 +163,42 @@ void dlm_user_add_ast(struct dlm_lkb *lk
 		goto out;
 
 	spin_lock(&proc->asts_spin);
-	if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+
+	ast_type = lkb->lkb_ast_type;
+	lkb->lkb_ast_type |= type;
+
+	if (!ast_type) {
 		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;
-
-	/* unlocks or cancels of waiting requests need to be removed from the
-	   proc's unlocking list, again there must be a better way...  */
-
-	if (ua->lksb.sb_status == -DLM_EUNLOCK ||
+	if (type == AST_COMP && (ast_type & AST_COMP))
+		log_debug(ls, "ast overlap %x status %x %x",
+			  lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
+
+	/* Figure out if this lock is at the end of its life and no longer
+	   available for the application to use.  The lkb still exists until
+	   the final ast is read.  A lock becomes EOL in three situations:
+	     1. a noqueue request fails with EAGAIN
+	     2. an unlock completes with EUNLOCK
+	     3. a cancel of a waiting request completes with ECANCEL
+	   An EOL lock needs to be removed from the process's list of locks.
+	   And we can't allow any new operation on an EOL lock.  This is
+	   not related to the lifetime of the lkb struct which is managed
+	   entirely by refcount. */
+
+	if (type == AST_COMP &&
+	    lkb->lkb_grmode == DLM_LOCK_IV &&
+	    ua->lksb.sb_status == -EAGAIN)
+		eol = 1;
+	else if (ua->lksb.sb_status == -DLM_EUNLOCK ||
 	    (ua->lksb.sb_status == -DLM_ECANCEL &&
 	     lkb->lkb_grmode == DLM_LOCK_IV))
-		remove_ownqueue = 1;
+		eol = 1;
+	if (eol) {
+		lkb->lkb_ast_type &= ~AST_BAST;
+		lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
+	}
 
 	/* 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
@@ -204,11 +215,13 @@ void dlm_user_add_ast(struct dlm_lkb *lk
 
 	spin_unlock(&proc->asts_spin);
 
-	if (remove_ownqueue) {
+	if (eol) {
 		spin_lock(&ua->proc->locks_spin);
-		list_del_init(&lkb->lkb_ownqueue);
+		if (!list_empty(&lkb->lkb_ownqueue)) {
+			list_del_init(&lkb->lkb_ownqueue);
+			dlm_put_lkb(lkb);
+		}
 		spin_unlock(&ua->proc->locks_spin);
-		dlm_put_lkb(lkb);
 	}
  out:
 	mutex_unlock(&ls->ls_clear_proc_locks);
@@ -286,47 +299,71 @@ static int device_user_unlock(struct dlm
 	return error;
 }
 
-static int device_create_lockspace(struct dlm_lspace_params *params)
+static int create_misc_device(struct dlm_ls *ls, char *name)
 {
-	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;
+	len = strlen(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);
+		 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;
 	}
+fail:
+	return error;
+}
+
+static int device_user_purge(struct dlm_user_proc *proc,
+			     struct dlm_purge_params *params)
+{
+	struct dlm_ls *ls;
+	int error;
+
+	ls = dlm_find_lockspace_local(proc->lockspace);
+	if (!ls)
+		return -ENOENT;
+
+	error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
 
-	error = ls->ls_device.minor;
 	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;
 
- fail:
+	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 = create_misc_device(ls, params->name);
 	dlm_put_lockspace(ls);
-	dlm_release_lockspace(lockspace, 0);
+
+	if (error)
+		dlm_release_lockspace(lockspace, 0);
+	else
+		error = ls->ls_device.minor;
+
 	return error;
 }
 
@@ -343,6 +380,10 @@ static int device_remove_lockspace(struc
 	if (!ls)
 		return -ENOENT;
 
+	/* Deregister the misc device first, so we don't have
+	 * a device that's not attached to a lockspace. If
+	 * dlm_release_lockspace fails then we can recreate it
+	 */
 	error = misc_deregister(&ls->ls_device);
 	if (error) {
 		dlm_put_lockspace(ls);
@@ -361,6 +402,8 @@ static int device_remove_lockspace(struc
 
 	dlm_put_lockspace(ls);
 	error = dlm_release_lockspace(lockspace, force);
+	if (error)
+		create_misc_device(ls, ls->ls_name);
  out:
 	return error;
 }
@@ -497,6 +540,14 @@ #endif
 		error = device_remove_lockspace(&kbuf->i.lspace);
 		break;
 
+	case DLM_USER_PURGE:
+		if (!proc) {
+			log_print("no locking on control device");
+			goto out_sig;
+		}
+		error = device_user_purge(proc, &kbuf->i.purge);
+		break;
+
 	default:
 		log_print("Unknown command passed to DLM device : %d\n",
 			  kbuf->cmd);
diff --git a/fs/dquot.c b/fs/dquot.c
index b16f991..3a99584 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -69,7 +69,6 @@ #include <linux/tty.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/sysctl.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
@@ -475,7 +474,7 @@ int vfs_quota_sync(struct super_block *s
 		spin_lock(&dq_list_lock);
 		dirty = &dqopt->info[cnt].dqi_dirty_list;
 		while (!list_empty(dirty)) {
-			dquot = list_entry(dirty->next, struct dquot, dq_dirty);
+			dquot = list_first_entry(dirty, struct dquot, dq_dirty);
 			/* Dirty and inactive can be only bad dquot... */
 			if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
 				clear_dquot_dirty(dquot);
@@ -721,7 +720,8 @@ static inline int dqput_blocks(struct dq
 
 /* Remove references to dquots from inode - add dquot to list for freeing if needed */
 /* We can't race with anybody because we hold dqptr_sem for writing... */
-int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head)
+static int remove_inode_dquot_ref(struct inode *inode, int type,
+				  struct list_head *tofree_head)
 {
 	struct dquot *dquot = inode->i_dquot[type];
 
@@ -1432,7 +1432,7 @@ int vfs_quota_off(struct super_block *sb
 			mutex_unlock(&dqopt->dqonoff_mutex);
 		}
 	if (sb->s_bdev)
-		invalidate_bdev(sb->s_bdev, 0);
+		invalidate_bdev(sb->s_bdev);
 	return 0;
 }
 
@@ -1468,7 +1468,7 @@ static int vfs_quota_on_inode(struct ino
 	 * we see all the changes from userspace... */
 	write_inode_now(inode, 1);
 	/* And now flush the block cache so that kernel sees the changes */
-	invalidate_bdev(sb->s_bdev, 0);
+	invalidate_bdev(sb->s_bdev);
 	mutex_lock(&inode->i_mutex);
 	mutex_lock(&dqopt->dqonoff_mutex);
 	if (sb_has_quota_enabled(sb, type)) {
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 7a7d25d..9881b5c 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -28,7 +28,6 @@ #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 <linux/fs_stack.h>
 #include "ecryptfs_kernel.h"
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index fc4a3a2..8cbf3f6 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -583,8 +583,7 @@ inode_info_init_once(void *vptr, struct 
 {
 	struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
 
@@ -793,7 +792,7 @@ static int do_sysfs_registration(void)
 		       "Unable to register ecryptfs sysfs subsystem\n");
 		goto out;
 	}
-	rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+	rc = sysfs_create_file(&ecryptfs_subsys.kobj,
 			       &sysfs_attr_version.attr);
 	if (rc) {
 		printk(KERN_ERR
@@ -801,12 +800,12 @@ static int do_sysfs_registration(void)
 		subsystem_unregister(&ecryptfs_subsys);
 		goto out;
 	}
-	rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+	rc = sysfs_create_file(&ecryptfs_subsys.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_remove_file(&ecryptfs_subsys.kobj,
 				  &sysfs_attr_version.attr);
 		subsystem_unregister(&ecryptfs_subsys);
 		goto out;
@@ -841,7 +840,7 @@ static int __init ecryptfs_init(void)
 		ecryptfs_free_kmem_caches();
 		goto out;
 	}
-	kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
+	kobj_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();
@@ -862,9 +861,9 @@ out:
 
 static void __exit ecryptfs_exit(void)
 {
-	sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+	sysfs_remove_file(&ecryptfs_subsys.kobj,
 			  &sysfs_attr_version.attr);
-	sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+	sysfs_remove_file(&ecryptfs_subsys.kobj,
 			  &sysfs_attr_version_str.attr);
 	subsystem_unregister(&ecryptfs_subsys);
 	ecryptfs_release_messaging(ecryptfs_transport);
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index b731b09..0770c4b 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -46,7 +46,6 @@ struct kmem_cache *ecryptfs_lower_page_c
  */
 static struct page *ecryptfs_get1page(struct file *file, int index)
 {
-	struct page *page;
 	struct dentry *dentry;
 	struct inode *inode;
 	struct address_space *mapping;
@@ -54,14 +53,7 @@ static struct page *ecryptfs_get1page(st
 	dentry = file->f_path.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;
+	return read_mapping_page(mapping, index, (void *)file);
 }
 
 static
@@ -233,7 +225,6 @@ int ecryptfs_do_readpage(struct file *fi
 		ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
 		goto out;
 	}
-	wait_on_page_locked(lower_page);
 	page_data = kmap_atomic(page, KM_USER0);
 	lower_page_data = kmap_atomic(lower_page, KM_USER1);
 	memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c
index e3aa225..fe91863 100644
--- a/fs/ecryptfs/netlink.c
+++ b/fs/ecryptfs/netlink.c
@@ -97,7 +97,7 @@ out:
  */
 static int ecryptfs_process_nl_response(struct sk_buff *skb)
 {
-	struct nlmsghdr *nlh = (struct nlmsghdr*)skb->data;
+	struct nlmsghdr *nlh = nlmsg_hdr(skb);
 	struct ecryptfs_message *msg = NLMSG_DATA(nlh);
 	int rc;
 
@@ -181,7 +181,7 @@ receive:
 				"rc = [%d]\n", rc);
 		return;
 	}
-	nlh = (struct nlmsghdr *)skb->data;
+	nlh = nlmsg_hdr(skb);
 	if (!NLMSG_OK(nlh, skb->len)) {
 		ecryptfs_printk(KERN_ERR, "Received corrupt netlink "
 				"message\n");
@@ -229,7 +229,7 @@ int ecryptfs_init_netlink(void)
 
 	ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0,
 						 ecryptfs_receive_nl_message,
-						 THIS_MODULE);
+						 NULL, THIS_MODULE);
 	if (!ecryptfs_nl_sock) {
 		rc = -EIO;
 		ecryptfs_printk(KERN_ERR, "Failed to create netlink socket\n");
diff --git a/fs/efs/super.c b/fs/efs/super.c
index c2235e4..ba7a8b9 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -72,8 +72,7 @@ static void init_once(void * foo, struct
 {
 	struct efs_inode_info *ei = (struct efs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 3ae644e..b5c7ca5 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -22,7 +22,6 @@ #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/hash.h>
@@ -185,7 +184,7 @@ struct eppoll_entry {
 
 /*
  * Each file descriptor added to the eventpoll interface will
- * have an entry of this type linked to the hash.
+ * have an entry of this type linked to the "rbr" RB tree.
  */
 struct epitem {
 	/* RB-Tree node used to link this structure to the eventpoll rb-tree */
@@ -217,15 +216,6 @@ struct epitem {
 
 	/* List header used to link this item to the "struct file" items list */
 	struct list_head fllink;
-
-	/* List header used to link the item to the transfer list */
-	struct list_head txlink;
-
-	/*
-	 * This is used during the collection/transfer of events to userspace
-	 * to pin items empty events set.
-	 */
-	unsigned int revents;
 };
 
 /* Wrapper struct used by poll queueing */
@@ -258,11 +248,8 @@ static int ep_remove(struct eventpoll *e
 static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key);
 static int ep_eventpoll_close(struct inode *inode, struct file *file);
 static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_collect_ready_items(struct eventpoll *ep,
-				  struct list_head *txlist, int maxevents);
 static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
-			  struct epoll_event __user *events);
-static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist);
+			  struct epoll_event __user *events, int maxevents);
 static int ep_events_transfer(struct eventpoll *ep,
 			      struct epoll_event __user *events,
 			      int maxevents);
@@ -355,17 +342,6 @@ static inline int ep_rb_linked(struct rb
 	return rb_parent(n) != n;
 }
 
-/*
- * Remove the item from the list and perform its initialization.
- * This is useful for us because we can test if the item is linked
- * using "ep_is_linked(p)".
- */
-static inline void ep_list_del(struct list_head *p)
-{
-	list_del(p);
-	INIT_LIST_HEAD(p);
-}
-
 /* Tells us if the item is currently linked */
 static inline int ep_is_linked(struct list_head *p)
 {
@@ -385,7 +361,7 @@ static inline struct epitem * ep_item_fr
 }
 
 /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
-static inline int ep_op_hash_event(int op)
+static inline int ep_op_has_event(int op)
 {
 	return op != EPOLL_CTL_DEL;
 }
@@ -477,10 +453,10 @@ void eventpoll_release_file(struct file 
 	mutex_lock(&epmutex);
 
 	while (!list_empty(lsthead)) {
-		epi = list_entry(lsthead->next, struct epitem, fllink);
+		epi = list_first_entry(lsthead, struct epitem, fllink);
 
 		ep = epi->ep;
-		ep_list_del(&epi->fllink);
+		list_del_init(&epi->fllink);
 		down_write(&ep->sem);
 		ep_remove(ep, epi);
 		up_write(&ep->sem);
@@ -557,7 +533,7 @@ sys_epoll_ctl(int epfd, int op, int fd, 
 		     current, epfd, op, fd, event));
 
 	error = -EFAULT;
-	if (ep_op_hash_event(op) &&
+	if (ep_op_has_event(op) &&
 	    copy_from_user(&epds, event, sizeof(struct epoll_event)))
 		goto eexit_1;
 
@@ -594,7 +570,7 @@ sys_epoll_ctl(int epfd, int op, int fd, 
 
 	down_write(&ep->sem);
 
-	/* Try to lookup the file inside our hash table */
+	/* Try to lookup the file inside our RB tree */
 	epi = ep_find(ep, tfile, fd);
 
 	error = -EINVAL;
@@ -876,7 +852,7 @@ static void ep_free(struct eventpoll *ep
 	}
 
 	/*
-	 * Walks through the whole hash by freeing each "struct epitem". At this
+	 * Walks through the whole tree by freeing each "struct epitem". At this
 	 * point we are sure no poll callbacks will be lingering around, and also by
 	 * write-holding "sem" we can be sure that no file cleanup code will hit
 	 * us during this operation. So we can avoid the lock on "ep->lock".
@@ -891,7 +867,7 @@ static void ep_free(struct eventpoll *ep
 
 
 /*
- * Search the file inside the eventpoll hash. It add usage count to
+ * Search the file inside the eventpoll tree. It add usage count to
  * the returned item, so the caller must call ep_release_epitem()
  * after finished using the "struct epitem".
  */
@@ -1011,7 +987,6 @@ static int ep_insert(struct eventpoll *e
 	ep_rb_initnode(&epi->rbn);
 	INIT_LIST_HEAD(&epi->rdllink);
 	INIT_LIST_HEAD(&epi->fllink);
-	INIT_LIST_HEAD(&epi->txlink);
 	INIT_LIST_HEAD(&epi->pwqlist);
 	epi->ep = ep;
 	ep_set_ffd(&epi->ffd, tfile, fd);
@@ -1080,7 +1055,7 @@ eexit_2:
 	 */
 	write_lock_irqsave(&ep->lock, flags);
 	if (ep_is_linked(&epi->rdllink))
-		ep_list_del(&epi->rdllink);
+		list_del_init(&epi->rdllink);
 	write_unlock_irqrestore(&ep->lock, flags);
 
 	kmem_cache_free(epi_cache, epi);
@@ -1119,7 +1094,7 @@ static int ep_modify(struct eventpoll *e
 	epi->event.data = event->data;
 
 	/*
-	 * If the item is not linked to the hash it means that it's on its
+	 * If the item is not linked to the RB tree it means that it's on its
 	 * way toward the removal. Do nothing in this case.
 	 */
 	if (ep_rb_linked(&epi->rbn)) {
@@ -1168,9 +1143,9 @@ static void ep_unregister_pollwait(struc
 
 	if (nwait) {
 		while (!list_empty(lsthead)) {
-			pwq = list_entry(lsthead->next, struct eppoll_entry, llink);
+			pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
 
-			ep_list_del(&pwq->llink);
+			list_del_init(&pwq->llink);
 			remove_wait_queue(pwq->whead, &pwq->wait);
 			kmem_cache_free(pwq_cache, pwq);
 		}
@@ -1213,7 +1188,7 @@ static int ep_unlink(struct eventpoll *e
 	 * we want to remove it from this list to avoid stale events.
 	 */
 	if (ep_is_linked(&epi->rdllink))
-		ep_list_del(&epi->rdllink);
+		list_del_init(&epi->rdllink);
 
 	error = 0;
 eexit_1:
@@ -1226,7 +1201,7 @@ eexit_1:
 
 
 /*
- * Removes a "struct epitem" from the eventpoll hash and deallocates
+ * Removes a "struct epitem" from the eventpoll RB tree and deallocates
  * all the associated resources.
  */
 static int ep_remove(struct eventpoll *ep, struct epitem *epi)
@@ -1248,13 +1223,13 @@ static int ep_remove(struct eventpoll *e
 	/* Remove the current item from the list of epoll hooks */
 	spin_lock(&file->f_ep_lock);
 	if (ep_is_linked(&epi->fllink))
-		ep_list_del(&epi->fllink);
+		list_del_init(&epi->fllink);
 	spin_unlock(&file->f_ep_lock);
 
 	/* We need to acquire the write IRQ lock before calling ep_unlink() */
 	write_lock_irqsave(&ep->lock, flags);
 
-	/* Really unlink the item from the hash */
+	/* Really unlink the item from the RB tree */
 	error = ep_unlink(ep, epi);
 
 	write_unlock_irqrestore(&ep->lock, flags);
@@ -1362,71 +1337,30 @@ static unsigned int ep_eventpoll_poll(st
 
 
 /*
- * Since we have to release the lock during the __copy_to_user() operation and
- * during the f_op->poll() call, we try to collect the maximum number of items
- * by reducing the irqlock/irqunlock switching rate.
- */
-static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist, int maxevents)
-{
-	int nepi;
-	unsigned long flags;
-	struct list_head *lsthead = &ep->rdllist, *lnk;
-	struct epitem *epi;
-
-	write_lock_irqsave(&ep->lock, flags);
-
-	for (nepi = 0, lnk = lsthead->next; lnk != lsthead && nepi < maxevents;) {
-		epi = list_entry(lnk, struct epitem, rdllink);
-
-		lnk = lnk->next;
-
-		/* If this file is already in the ready list we exit soon */
-		if (!ep_is_linked(&epi->txlink)) {
-			/*
-			 * This is initialized in this way so that the default
-			 * behaviour of the reinjecting code will be to push back
-			 * the item inside the ready list.
-			 */
-			epi->revents = epi->event.events;
-
-			/* Link the ready item into the transfer list */
-			list_add(&epi->txlink, txlist);
-			nepi++;
-
-			/*
-			 * Unlink the item from the ready list.
-			 */
-			ep_list_del(&epi->rdllink);
-		}
-	}
-
-	write_unlock_irqrestore(&ep->lock, flags);
-
-	return nepi;
-}
-
-
-/*
  * This function is called without holding the "ep->lock" since the call to
  * __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
  * because of the way poll() is traditionally implemented in Linux.
  */
 static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
-			  struct epoll_event __user *events)
+			  struct epoll_event __user *events, int maxevents)
 {
-	int eventcnt = 0;
+	int eventcnt, error = -EFAULT, pwake = 0;
 	unsigned int revents;
-	struct list_head *lnk;
+	unsigned long flags;
 	struct epitem *epi;
+	struct list_head injlist;
+
+	INIT_LIST_HEAD(&injlist);
 
 	/*
 	 * We can loop without lock because this is a task private list.
-	 * The test done during the collection loop will guarantee us that
-	 * another task will not try to collect this file. Also, items
-	 * cannot vanish during the loop because we are holding "sem".
+	 * We just splice'd out the ep->rdllist in ep_collect_ready_items().
+	 * Items cannot vanish during the loop because we are holding "sem" in
+	 * read.
 	 */
-	list_for_each(lnk, txlist) {
-		epi = list_entry(lnk, struct epitem, txlink);
+	for (eventcnt = 0; !list_empty(txlist) && eventcnt < maxevents;) {
+		epi = list_first_entry(txlist, struct epitem, rdllink);
+		prefetch(epi->rdllink.next);
 
 		/*
 		 * Get the ready file event set. We can safely use the file
@@ -1434,64 +1368,65 @@ static int ep_send_events(struct eventpo
 		 * guarantee that both the file and the item will not vanish.
 		 */
 		revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
+		revents &= epi->event.events;
 
 		/*
-		 * Set the return event set for the current file descriptor.
-		 * Note that only the task task was successfully able to link
-		 * the item to its "txlist" will write this field.
+		 * Is the event mask intersect the caller-requested one,
+		 * deliver the event to userspace. Again, we are holding
+		 * "sem" in read, so no operations coming from userspace
+		 * can change the item.
 		 */
-		epi->revents = revents & epi->event.events;
-
-		if (epi->revents) {
-			if (__put_user(epi->revents,
+		if (revents) {
+			if (__put_user(revents,
 				       &events[eventcnt].events) ||
 			    __put_user(epi->event.data,
 				       &events[eventcnt].data))
-				return -EFAULT;
+				goto errxit;
 			if (epi->event.events & EPOLLONESHOT)
 				epi->event.events &= EP_PRIVATE_BITS;
 			eventcnt++;
 		}
-	}
-	return eventcnt;
-}
-
-
-/*
- * Walk through the transfer list we collected with ep_collect_ready_items()
- * and, if 1) the item is still "alive" 2) its event set is not empty 3) it's
- * not already linked, links it to the ready list. Same as above, we are holding
- * "sem" so items cannot vanish underneath our nose.
- */
-static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
-{
-	int ricnt = 0, pwake = 0;
-	unsigned long flags;
-	struct epitem *epi;
-
-	write_lock_irqsave(&ep->lock, flags);
-
-	while (!list_empty(txlist)) {
-		epi = list_entry(txlist->next, struct epitem, txlink);
-
-		/* Unlink the current item from the transfer list */
-		ep_list_del(&epi->txlink);
 
 		/*
-		 * If the item is no more linked to the interest set, we don't
-		 * have to push it inside the ready list because the following
-		 * ep_release_epitem() is going to drop it. Also, if the current
-		 * item is set to have an Edge Triggered behaviour, we don't have
-		 * to push it back either.
+		 * This is tricky. We are holding the "sem" in read, and this
+		 * means that the operations that can change the "linked" status
+		 * of the epoll item (epi->rbn and epi->rdllink), cannot touch
+		 * them.  Also, since we are "linked" from a epi->rdllink POV
+		 * (the item is linked to our transmission list we just
+		 * spliced), the ep_poll_callback() cannot touch us either,
+		 * because of the check present in there. Another parallel
+		 * epoll_wait() will not get the same result set, since we
+		 * spliced the ready list before.  Note that list_del() still
+		 * shows the item as linked to the test in ep_poll_callback().
 		 */
-		if (ep_rb_linked(&epi->rbn) && !(epi->event.events & EPOLLET) &&
-		    (epi->revents & epi->event.events) && !ep_is_linked(&epi->rdllink)) {
-			list_add_tail(&epi->rdllink, &ep->rdllist);
-			ricnt++;
+		list_del(&epi->rdllink);
+		if (!(epi->event.events & EPOLLET) &&
+				(revents & epi->event.events))
+			list_add_tail(&epi->rdllink, &injlist);
+		else {
+			/*
+			 * Be sure the item is totally detached before re-init
+			 * the list_head. After INIT_LIST_HEAD() is committed,
+			 * the ep_poll_callback() can requeue the item again,
+			 * but we don't care since we are already past it.
+			 */
+			smp_mb();
+			INIT_LIST_HEAD(&epi->rdllink);
 		}
 	}
+	error = 0;
 
-	if (ricnt) {
+	errxit:
+
+	/*
+	 * If the re-injection list or the txlist are not empty, re-splice
+	 * them to the ready list and do proper wakeups.
+	 */
+	if (!list_empty(&injlist) || !list_empty(txlist)) {
+		write_lock_irqsave(&ep->lock, flags);
+
+		list_splice(txlist, &ep->rdllist);
+		list_splice(&injlist, &ep->rdllist);
 		/*
 		 * Wake up ( if active ) both the eventpoll wait list and the ->poll()
 		 * wait list.
@@ -1501,13 +1436,15 @@ static void ep_reinject_items(struct eve
 					 TASK_INTERRUPTIBLE);
 		if (waitqueue_active(&ep->poll_wait))
 			pwake++;
-	}
 
-	write_unlock_irqrestore(&ep->lock, flags);
+		write_unlock_irqrestore(&ep->lock, flags);
+	}
 
 	/* We have to call this outside the lock */
 	if (pwake)
 		ep_poll_safewake(&psw, &ep->poll_wait);
+
+	return eventcnt == 0 ? error: eventcnt;
 }
 
 
@@ -1517,7 +1454,8 @@ static void ep_reinject_items(struct eve
 static int ep_events_transfer(struct eventpoll *ep,
 			      struct epoll_event __user *events, int maxevents)
 {
-	int eventcnt = 0;
+	int eventcnt;
+	unsigned long flags;
 	struct list_head txlist;
 
 	INIT_LIST_HEAD(&txlist);
@@ -1528,14 +1466,17 @@ static int ep_events_transfer(struct eve
 	 */
 	down_read(&ep->sem);
 
-	/* Collect/extract ready items */
-	if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) {
-		/* Build result set in userspace */
-		eventcnt = ep_send_events(ep, &txlist, events);
+	/*
+	 * Steal the ready list, and re-init the original one to the
+	 * empty list.
+	 */
+	write_lock_irqsave(&ep->lock, flags);
+	list_splice(&ep->rdllist, &txlist);
+	INIT_LIST_HEAD(&ep->rdllist);
+	write_unlock_irqrestore(&ep->lock, flags);
 
-		/* Reinject ready items into the ready list */
-		ep_reinject_items(ep, &txlist);
-	}
+	/* Build result set in userspace */
+	eventcnt = ep_send_events(ep, &txlist, events, maxevents);
 
 	up_read(&ep->sem);
 
@@ -1612,14 +1553,12 @@ retry:
 	return res;
 }
 
-
 static int eventpollfs_delete_dentry(struct dentry *dentry)
 {
 
 	return 1;
 }
 
-
 static struct inode *ep_eventpoll_inode(void)
 {
 	int error = -ENOMEM;
@@ -1647,7 +1586,6 @@ eexit_1:
 	return ERR_PTR(error);
 }
 
-
 static int
 eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
 		   const char *dev_name, void *data, struct vfsmount *mnt)
diff --git a/fs/exec.c b/fs/exec.c
index 3155e91..1ba85c7 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -100,6 +100,7 @@ int unregister_binfmt(struct linux_binfm
 	while (*tmp) {
 		if (fmt == *tmp) {
 			*tmp = fmt->next;
+			fmt->next = NULL;
 			write_unlock(&binfmt_lock);
 			return 0;
 		}
@@ -982,33 +983,51 @@ void compute_creds(struct linux_binprm *
 	task_unlock(current);
 	security_bprm_post_apply_creds(bprm);
 }
-
 EXPORT_SYMBOL(compute_creds);
 
+/*
+ * Arguments are '\0' separated strings found at the location bprm->p
+ * points to; chop off the first by relocating brpm->p to right after
+ * the first '\0' encountered.
+ */
 void remove_arg_zero(struct linux_binprm *bprm)
 {
 	if (bprm->argc) {
-		unsigned long offset;
-		char * kaddr;
-		struct page *page;
+		char ch;
 
-		offset = bprm->p % PAGE_SIZE;
-		goto inside;
+		do {
+			unsigned long offset;
+			unsigned long index;
+			char *kaddr;
+			struct page *page;
 
-		while (bprm->p++, *(kaddr+offset++)) {
-			if (offset != PAGE_SIZE)
-				continue;
-			offset = 0;
-			kunmap_atomic(kaddr, KM_USER0);
-inside:
-			page = bprm->page[bprm->p/PAGE_SIZE];
+			offset = bprm->p & ~PAGE_MASK;
+			index = bprm->p >> PAGE_SHIFT;
+
+			page = bprm->page[index];
 			kaddr = kmap_atomic(page, KM_USER0);
-		}
-		kunmap_atomic(kaddr, KM_USER0);
+
+			/* run through page until we reach end or find NUL */
+			do {
+				ch = *(kaddr + offset);
+
+				/* discard that character... */
+				bprm->p++;
+				offset++;
+			} while (offset < PAGE_SIZE && ch != '\0');
+
+			kunmap_atomic(kaddr, KM_USER0);
+
+			/* free the old page */
+			if (offset == PAGE_SIZE) {
+				__free_page(page);
+				bprm->page[index] = NULL;
+			}
+		} while (ch != '\0');
+
 		bprm->argc--;
 	}
 }
-
 EXPORT_SYMBOL(remove_arg_zero);
 
 /*
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 93e77c3..e98f6cd 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -2,7 +2,6 @@
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/namei.h>
 
 struct export_operations export_op_default;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index e89bfc8..2bf49d7 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -23,7 +23,6 @@
 
 #include "ext2.h"
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 
 typedef struct ext2_dir_entry_2 ext2_dirent;
 
@@ -161,10 +160,7 @@ static struct page * ext2_get_page(struc
 	struct address_space *mapping = dir->i_mapping;
 	struct page *page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
-		if (!PageUptodate(page))
-			goto fail;
 		if (!PageChecked(page))
 			ext2_check_page(page);
 		if (PageError(page))
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index e2a0ea5..9fd0ec5 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -133,6 +133,7 @@ extern int ext2_get_block(struct inode *
 extern void ext2_truncate (struct inode *);
 extern int ext2_setattr (struct dentry *, struct iattr *);
 extern void ext2_set_inode_flags(struct inode *inode);
+extern void ext2_get_inode_flags(struct ext2_inode_info *);
 
 /* ioctl.c */
 extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 7806b9e..fc66c93 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -23,7 +23,6 @@
  */
 
 #include "ext2.h"
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>		/* for sync_mapping_buffers() */
 
 
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index dd4e14c..0079b2c 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1055,6 +1055,25 @@ void ext2_set_inode_flags(struct inode *
 		inode->i_flags |= S_DIRSYNC;
 }
 
+/* Propagate flags from i_flags to EXT2_I(inode)->i_flags */
+void ext2_get_inode_flags(struct ext2_inode_info *ei)
+{
+	unsigned int flags = ei->vfs_inode.i_flags;
+
+	ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL|
+			EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL);
+	if (flags & S_SYNC)
+		ei->i_flags |= EXT2_SYNC_FL;
+	if (flags & S_APPEND)
+		ei->i_flags |= EXT2_APPEND_FL;
+	if (flags & S_IMMUTABLE)
+		ei->i_flags |= EXT2_IMMUTABLE_FL;
+	if (flags & S_NOATIME)
+		ei->i_flags |= EXT2_NOATIME_FL;
+	if (flags & S_DIRSYNC)
+		ei->i_flags |= EXT2_DIRSYNC_FL;
+}
+
 void ext2_read_inode (struct inode * inode)
 {
 	struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1079,9 +1098,9 @@ #endif
 	}
 	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_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+	inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+	inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
 	inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 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.
@@ -1188,6 +1207,7 @@ static int ext2_update_inode(struct inod
 	if (ei->i_state & EXT2_STATE_NEW)
 		memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size);
 
+	ext2_get_inode_flags(ei);
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	if (!(test_opt(sb, NO_UID32))) {
 		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 4b099d3..e85c482 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -27,6 +27,7 @@ int ext2_ioctl (struct inode * inode, st
 
 	switch (cmd) {
 	case EXT2_IOC_GETFLAGS:
+		ext2_get_inode_flags(ei);
 		flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
 		return put_user(flags, (int __user *) arg);
 	case EXT2_IOC_SETFLAGS: {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index a046a41..685a1c2 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -160,8 +160,7 @@ static void init_once(void * foo, struct
 {
 	struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		rwlock_init(&ei->i_meta_lock);
 #ifdef CONFIG_EXT2_FS_XATTR
 		init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index a266127..eaa23d2 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -6,7 +6,6 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/ext2_fs.h>
 #include <linux/security.h>
 #include "xattr.h"
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index f28a6a4..83ee149 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -9,7 +9,6 @@ #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/ext2_fs.h>
 #include "xattr.h"
 
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 665adee..8528698 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -25,7 +25,6 @@ #include <linux/fs.h>
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/rbtree.h>
 
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index a5b150f..e1bb031 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -27,7 +27,6 @@ #include <linux/fs.h>
 #include <linux/time.h>
 #include <linux/ext3_jbd.h>
 #include <linux/jbd.h>
-#include <linux/smp_lock.h>
 #include <linux/highuid.h>
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
@@ -2581,6 +2580,25 @@ void ext3_set_inode_flags(struct inode *
 		inode->i_flags |= S_DIRSYNC;
 }
 
+/* Propagate flags from i_flags to EXT3_I(inode)->i_flags */
+void ext3_get_inode_flags(struct ext3_inode_info *ei)
+{
+	unsigned int flags = ei->vfs_inode.i_flags;
+
+	ei->i_flags &= ~(EXT3_SYNC_FL|EXT3_APPEND_FL|
+			EXT3_IMMUTABLE_FL|EXT3_NOATIME_FL|EXT3_DIRSYNC_FL);
+	if (flags & S_SYNC)
+		ei->i_flags |= EXT3_SYNC_FL;
+	if (flags & S_APPEND)
+		ei->i_flags |= EXT3_APPEND_FL;
+	if (flags & S_IMMUTABLE)
+		ei->i_flags |= EXT3_IMMUTABLE_FL;
+	if (flags & S_NOATIME)
+		ei->i_flags |= EXT3_NOATIME_FL;
+	if (flags & S_DIRSYNC)
+		ei->i_flags |= EXT3_DIRSYNC_FL;
+}
+
 void ext3_read_inode(struct inode * inode)
 {
 	struct ext3_iloc iloc;
@@ -2608,9 +2626,9 @@ #endif
 	}
 	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_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+	inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+	inode->i_mtime.tv_sec = (signed)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;
@@ -2736,6 +2754,7 @@ static int ext3_do_update_inode(handle_t
 	if (ei->i_state & EXT3_STATE_NEW)
 		memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size);
 
+	ext3_get_inode_flags(ei);
 	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));
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 9b8090d..965006d 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -28,6 +28,7 @@ int ext3_ioctl (struct inode * inode, st
 
 	switch (cmd) {
 	case EXT3_IOC_GETFLAGS:
+		ext3_get_inode_flags(ei);
 		flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
 		return put_user(flags, (int __user *) arg);
 	case EXT3_IOC_SETFLAGS: {
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 49159f1..9bb046d 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -36,7 +36,6 @@ #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"
@@ -969,6 +968,7 @@ static struct buffer_head * ext3_dx_find
 				  (block<<EXT3_BLOCK_SIZE_BITS(sb))
 					  +((char *)de - bh->b_data))) {
 				brelse (bh);
+				*err = ERR_BAD_DX_DIR;
 				goto errout;
 			}
 			*res_dir = de;
@@ -1134,9 +1134,9 @@ static struct ext3_dir_entry_2 *do_split
 	char *data1 = (*bh)->b_data, *data2;
 	unsigned split;
 	struct ext3_dir_entry_2 *de = NULL, *de2;
-	int	err;
+	int	err = 0;
 
-	bh2 = ext3_append (handle, dir, &newblock, error);
+	bh2 = ext3_append (handle, dir, &newblock, &err);
 	if (!(bh2)) {
 		brelse(*bh);
 		*bh = NULL;
@@ -1145,14 +1145,9 @@ static struct ext3_dir_entry_2 *do_split
 
 	BUFFER_TRACE(*bh, "get_write_access");
 	err = ext3_journal_get_write_access(handle, *bh);
-	if (err) {
-	journal_error:
-		brelse(*bh);
-		brelse(bh2);
-		*bh = NULL;
-		ext3_std_error(dir->i_sb, err);
-		goto errout;
-	}
+	if (err)
+		goto journal_error;
+
 	BUFFER_TRACE(frame->bh, "get_write_access");
 	err = ext3_journal_get_write_access(handle, frame->bh);
 	if (err)
@@ -1195,8 +1190,16 @@ static struct ext3_dir_entry_2 *do_split
 		goto journal_error;
 	brelse (bh2);
 	dxtrace(dx_show_index ("frame", frame->entries));
-errout:
 	return de;
+
+journal_error:
+	brelse(*bh);
+	brelse(bh2);
+	*bh = NULL;
+	ext3_std_error(dir->i_sb, err);
+errout:
+	*error = err;
+	return NULL;
 }
 #endif
 
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index ecf8990..2c97e09 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -11,7 +11,6 @@
 
 #define EXT3FS_DEBUG
 
-#include <linux/smp_lock.h>
 #include <linux/ext3_jbd.h>
 
 #include <linux/errno.h>
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 4a4fcd6..54d3c90 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -420,7 +420,7 @@ #endif
 		dump_orphan_list(sb, sbi);
 	J_ASSERT(list_empty(&sbi->s_orphan));
 
-	invalidate_bdev(sb->s_bdev, 0);
+	invalidate_bdev(sb->s_bdev);
 	if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
 		/*
 		 * Invalidate the journal device's buffers.  We don't want them
@@ -428,7 +428,7 @@ #endif
 		 * hotswapped, and it breaks the `ro-after' testing code.
 		 */
 		sync_blockdev(sbi->journal_bdev);
-		invalidate_bdev(sbi->journal_bdev, 0);
+		invalidate_bdev(sbi->journal_bdev);
 		ext3_blkdev_remove(sbi);
 	}
 	sb->s_fs_info = NULL;
@@ -466,8 +466,7 @@ static void init_once(void * foo, struct
 {
 	struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&ei->i_orphan);
 #ifdef CONFIG_EXT3_FS_XATTR
 		init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index b9c40c1..821efaf 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -6,7 +6,6 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/security.h>
diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c
index 86d91f1..0327497 100644
--- a/fs/ext3/xattr_trusted.c
+++ b/fs/ext3/xattr_trusted.c
@@ -9,7 +9,6 @@ #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
 #include "xattr.h"
diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c
index a85a0a1..1abd8f9 100644
--- a/fs/ext3/xattr_user.c
+++ b/fs/ext3/xattr_user.c
@@ -8,7 +8,6 @@
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
 #include "xattr.h"
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index da80368..e8ad06e 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -25,7 +25,6 @@ #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>
 
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7916b50..a0f0c04 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -34,7 +34,6 @@ #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>
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 810b6d6..b34182b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -27,7 +27,6 @@ #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>
@@ -2611,9 +2610,9 @@ #endif
 	}
 	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_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+	inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+	inode->i_mtime.tv_sec = (signed)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;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index e7e1d79..4ec57be 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -36,7 +36,6 @@ #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"
@@ -967,6 +966,7 @@ static struct buffer_head * ext4_dx_find
 				  (block<<EXT4_BLOCK_SIZE_BITS(sb))
 					  +((char *)de - bh->b_data))) {
 				brelse (bh);
+				*err = ERR_BAD_DX_DIR;
 				goto errout;
 			}
 			*res_dir = de;
@@ -1132,9 +1132,9 @@ static struct ext4_dir_entry_2 *do_split
 	char *data1 = (*bh)->b_data, *data2;
 	unsigned split;
 	struct ext4_dir_entry_2 *de = NULL, *de2;
-	int	err;
+	int	err = 0;
 
-	bh2 = ext4_append (handle, dir, &newblock, error);
+	bh2 = ext4_append (handle, dir, &newblock, &err);
 	if (!(bh2)) {
 		brelse(*bh);
 		*bh = NULL;
@@ -1143,14 +1143,9 @@ static struct ext4_dir_entry_2 *do_split
 
 	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;
-	}
+	if (err)
+		goto journal_error;
+
 	BUFFER_TRACE(frame->bh, "get_write_access");
 	err = ext4_journal_get_write_access(handle, frame->bh);
 	if (err)
@@ -1193,8 +1188,16 @@ static struct ext4_dir_entry_2 *do_split
 		goto journal_error;
 	brelse (bh2);
 	dxtrace(dx_show_index ("frame", frame->entries));
-errout:
 	return de;
+
+journal_error:
+	brelse(*bh);
+	brelse(bh2);
+	*bh = NULL;
+	ext4_std_error(dir->i_sb, err);
+errout:
+	*error = err;
+	return NULL;
 }
 #endif
 
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index ea99f6c..aa11d7d 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -11,7 +11,6 @@
 
 #define EXT4FS_DEBUG
 
-#include <linux/smp_lock.h>
 #include <linux/ext4_jbd2.h>
 
 #include <linux/errno.h>
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 61c4718..7191269 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -470,7 +470,7 @@ #endif
 		dump_orphan_list(sb, sbi);
 	J_ASSERT(list_empty(&sbi->s_orphan));
 
-	invalidate_bdev(sb->s_bdev, 0);
+	invalidate_bdev(sb->s_bdev);
 	if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
 		/*
 		 * Invalidate the journal device's buffers.  We don't want them
@@ -478,7 +478,7 @@ #endif
 		 * hotswapped, and it breaks the `ro-after' testing code.
 		 */
 		sync_blockdev(sbi->journal_bdev);
-		invalidate_bdev(sbi->journal_bdev, 0);
+		invalidate_bdev(sbi->journal_bdev);
 		ext4_blkdev_remove(sbi);
 	}
 	sb->s_fs_info = NULL;
@@ -517,8 +517,7 @@ static void init_once(void * foo, struct
 {
 	struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&ei->i_orphan);
 #ifdef CONFIG_EXT4DEV_FS_XATTR
 		init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index b6a6861..f17eaf2 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -6,7 +6,6 @@
 #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>
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
index b76f2db..e0f05ac 100644
--- a/fs/ext4/xattr_trusted.c
+++ b/fs/ext4/xattr_trusted.c
@@ -9,7 +9,6 @@ #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"
diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
index c53cded..7ed3d8e 100644
--- a/fs/ext4/xattr_user.c
+++ b/fs/ext4/xattr_user.c
@@ -8,7 +8,6 @@
 #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"
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 05c2941..1959143 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -40,8 +40,7 @@ static void init_once(void *foo, struct 
 {
 	struct fat_cache *cache = (struct fat_cache *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		INIT_LIST_HEAD(&cache->cache_list);
 }
 
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index c16af24..ccf161d 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -422,7 +422,7 @@ EODir:
 EXPORT_SYMBOL_GPL(fat_search_long);
 
 struct fat_ioctl_filldir_callback {
-	struct dirent __user *dirent;
+	void __user *dirent;
 	int result;
 	/* for dir ioctl */
 	const char *longname;
@@ -647,62 +647,85 @@ static int fat_readdir(struct file *filp
 	return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
 }
 
-static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
-			     loff_t offset, u64 ino, unsigned int d_type)
+#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type)			   \
+static int func(void *__buf, const char *name, int name_len,		   \
+			     loff_t offset, u64 ino, unsigned int d_type)  \
+{									   \
+	struct fat_ioctl_filldir_callback *buf = __buf;			   \
+	struct dirent_type __user *d1 = buf->dirent;			   \
+	struct dirent_type __user *d2 = d1 + 1;				   \
+									   \
+	if (buf->result)						   \
+		return -EINVAL;						   \
+	buf->result++;							   \
+									   \
+	if (name != NULL) {						   \
+		/* dirent has only short name */			   \
+		if (name_len >= sizeof(d1->d_name))			   \
+			name_len = sizeof(d1->d_name) - 1;		   \
+									   \
+		if (put_user(0, d2->d_name)			||	   \
+		    put_user(0, &d2->d_reclen)			||	   \
+		    copy_to_user(d1->d_name, name, name_len)	||	   \
+		    put_user(0, d1->d_name + name_len)		||	   \
+		    put_user(name_len, &d1->d_reclen))			   \
+			goto efault;					   \
+	} else {							   \
+		/* dirent has short and long name */			   \
+		const char *longname = buf->longname;			   \
+		int long_len = buf->long_len;				   \
+		const char *shortname = buf->shortname;			   \
+		int short_len = buf->short_len;				   \
+									   \
+		if (long_len >= sizeof(d1->d_name))			   \
+			long_len = sizeof(d1->d_name) - 1;		   \
+		if (short_len >= sizeof(d1->d_name))			   \
+			short_len = sizeof(d1->d_name) - 1;		   \
+									   \
+		if (copy_to_user(d2->d_name, longname, long_len)	|| \
+		    put_user(0, d2->d_name + long_len)			|| \
+		    put_user(long_len, &d2->d_reclen)			|| \
+		    put_user(ino, &d2->d_ino)				|| \
+		    put_user(offset, &d2->d_off)			|| \
+		    copy_to_user(d1->d_name, shortname, short_len)	|| \
+		    put_user(0, d1->d_name + short_len)			|| \
+		    put_user(short_len, &d1->d_reclen))			   \
+			goto efault;					   \
+	}								   \
+	return 0;							   \
+efault:									   \
+	buf->result = -EFAULT;						   \
+	return -EFAULT;							   \
+}
+
+FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, dirent)
+
+static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
+			     void __user *dirent, filldir_t filldir,
+			     int short_only, int both)
 {
-	struct fat_ioctl_filldir_callback *buf = __buf;
-	struct dirent __user *d1 = buf->dirent;
-	struct dirent __user *d2 = d1 + 1;
-
-	if (buf->result)
-		return -EINVAL;
-	buf->result++;
-
-	if (name != NULL) {
-		/* dirent has only short name */
-		if (name_len >= sizeof(d1->d_name))
-			name_len = sizeof(d1->d_name) - 1;
-
-		if (put_user(0, d2->d_name)			||
-		    put_user(0, &d2->d_reclen)			||
-		    copy_to_user(d1->d_name, name, name_len)	||
-		    put_user(0, d1->d_name + name_len)		||
-		    put_user(name_len, &d1->d_reclen))
-			goto efault;
-	} else {
-		/* dirent has short and long name */
-		const char *longname = buf->longname;
-		int long_len = buf->long_len;
-		const char *shortname = buf->shortname;
-		int short_len = buf->short_len;
-
-		if (long_len >= sizeof(d1->d_name))
-			long_len = sizeof(d1->d_name) - 1;
-		if (short_len >= sizeof(d1->d_name))
-			short_len = sizeof(d1->d_name) - 1;
-
-		if (copy_to_user(d2->d_name, longname, long_len)	||
-		    put_user(0, d2->d_name + long_len)			||
-		    put_user(long_len, &d2->d_reclen)			||
-		    put_user(ino, &d2->d_ino)				||
-		    put_user(offset, &d2->d_off)			||
-		    copy_to_user(d1->d_name, shortname, short_len)	||
-		    put_user(0, d1->d_name + short_len)			||
-		    put_user(short_len, &d1->d_reclen))
-			goto efault;
+	struct fat_ioctl_filldir_callback buf;
+	int ret;
+
+	buf.dirent = dirent;
+	buf.result = 0;
+	mutex_lock(&inode->i_mutex);
+	ret = -ENOENT;
+	if (!IS_DEADDIR(inode)) {
+		ret = __fat_readdir(inode, filp, &buf, filldir,
+				    short_only, both);
 	}
-	return 0;
-efault:
-	buf->result = -EFAULT;
-	return -EFAULT;
+	mutex_unlock(&inode->i_mutex);
+	if (ret >= 0)
+		ret = buf.result;
+	return ret;
 }
 
-static int fat_dir_ioctl(struct inode * inode, struct file * filp,
-		  unsigned int cmd, unsigned long arg)
+static int fat_dir_ioctl(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg)
 {
-	struct fat_ioctl_filldir_callback buf;
-	struct dirent __user *d1;
-	int ret, short_only, both;
+	struct dirent __user *d1 = (struct dirent __user *)arg;
+	int short_only, both;
 
 	switch (cmd) {
 	case VFAT_IOCTL_READDIR_SHORT:
@@ -717,7 +740,6 @@ static int fat_dir_ioctl(struct inode * 
 		return fat_generic_ioctl(inode, filp, cmd, arg);
 	}
 
-	d1 = (struct dirent __user *)arg;
 	if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
 		return -EFAULT;
 	/*
@@ -728,69 +750,48 @@ static int fat_dir_ioctl(struct inode * 
 	if (put_user(0, &d1->d_reclen))
 		return -EFAULT;
 
-	buf.dirent = d1;
-	buf.result = 0;
-	mutex_lock(&inode->i_mutex);
-	ret = -ENOENT;
-	if (!IS_DEADDIR(inode)) {
-		ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir,
-				    short_only, both);
-	}
-	mutex_unlock(&inode->i_mutex);
-	if (ret >= 0)
-		ret = buf.result;
-	return ret;
+	return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,
+				 short_only, both);
 }
 
 #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;
+FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent)
 
-        return 0;
-}
-
-static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
+static long fat_compat_dir_ioctl(struct file *filp, 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];
+	struct inode *inode = filp->f_path.dentry->d_inode;
+	struct compat_dirent __user *d1 = compat_ptr(arg);
+	int short_only, both;
 
 	switch (cmd) {
-	case VFAT_IOCTL_READDIR_BOTH32:
-		cmd = VFAT_IOCTL_READDIR_BOTH;
-		break;
 	case VFAT_IOCTL_READDIR_SHORT32:
-		cmd = VFAT_IOCTL_READDIR_SHORT;
+		short_only = 1;
+		both = 0;
+		break;
+	case VFAT_IOCTL_READDIR_BOTH32:
+		short_only = 0;
+		both = 1;
 		break;
 	default:
 		return -ENOIOCTLCMD;
 	}
 
-	set_fs(KERNEL_DS);
-	lock_kernel();
-	ret = fat_dir_ioctl(file->f_path.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;
+	if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2])))
+		return -EFAULT;
+	/*
+	 * Yes, we don't need this put_user() absolutely. However old
+	 * code didn't return the right value. So, app use this value,
+	 * in order to check whether it is EOF.
+	 */
+	if (put_user(0, &d1->d_reclen))
+		return -EFAULT;
+
+	return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir,
+				 short_only, both);
 }
 #endif /* CONFIG_COMPAT */
 
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 9bfe607..2c55e8d 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -25,6 +25,7 @@ #include <linux/vfs.h>
 #include <linux/parser.h>
 #include <linux/uio.h>
 #include <linux/writeback.h>
+#include <linux/log2.h>
 #include <asm/unaligned.h>
 
 #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -499,8 +500,7 @@ static void init_once(void * foo, struct
 {
 	struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		spin_lock_init(&ei->cache_lru_lock);
 		ei->nr_caches = 0;
 		ei->cache_valid_id = FAT_CACHE_VALID + 1;
@@ -825,6 +825,8 @@ static int fat_show_options(struct seq_f
 	}
 	if (opts->name_check != 'n')
 		seq_printf(m, ",check=%c", opts->name_check);
+	if (opts->usefree)
+		seq_puts(m, ",usefree");
 	if (opts->quiet)
 		seq_puts(m, ",quiet");
 	if (opts->showexec)
@@ -850,7 +852,7 @@ static int fat_show_options(struct seq_f
 
 enum {
 	Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
-	Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase,
+	Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
 	Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
 	Opt_dots, Opt_nodots,
 	Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
@@ -872,6 +874,7 @@ static match_table_t fat_tokens = {
 	{Opt_dmask, "dmask=%o"},
 	{Opt_fmask, "fmask=%o"},
 	{Opt_codepage, "codepage=%u"},
+	{Opt_usefree, "usefree"},
 	{Opt_nocase, "nocase"},
 	{Opt_quiet, "quiet"},
 	{Opt_showexec, "showexec"},
@@ -951,7 +954,7 @@ static int parse_options(char *options, 
 	opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK =  0;
 	opts->utf8 = opts->unicode_xlate = 0;
 	opts->numtail = 1;
-	opts->nocase = 0;
+	opts->usefree = opts->nocase = 0;
 	*debug = 0;
 
 	if (!options)
@@ -979,6 +982,9 @@ static int parse_options(char *options, 
 		case Opt_check_n:
 			opts->name_check = 'n';
 			break;
+		case Opt_usefree:
+			opts->usefree = 1;
+			break;
 		case Opt_nocase:
 			if (!is_vfat)
 				opts->nocase = 1;
@@ -1218,8 +1224,7 @@ int fat_fill_super(struct super_block *s
 	}
 	logical_sector_size =
 		le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
-	if (!logical_sector_size
-	    || (logical_sector_size & (logical_sector_size - 1))
+	if (!is_power_of_2(logical_sector_size)
 	    || (logical_sector_size < 512)
 	    || (PAGE_CACHE_SIZE < logical_sector_size)) {
 		if (!silent)
@@ -1229,8 +1234,7 @@ int fat_fill_super(struct super_block *s
 		goto out_invalid;
 	}
 	sbi->sec_per_clus = b->sec_per_clus;
-	if (!sbi->sec_per_clus
-	    || (sbi->sec_per_clus & (sbi->sec_per_clus - 1))) {
+	if (!is_power_of_2(sbi->sec_per_clus)) {
 		if (!silent)
 			printk(KERN_ERR "FAT: bogus sectors per cluster %u\n",
 			       sbi->sec_per_clus);
@@ -1306,7 +1310,9 @@ int fat_fill_super(struct super_block *s
 			       le32_to_cpu(fsinfo->signature2),
 			       sbi->fsinfo_sector);
 		} else {
-			sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
+			if (sbi->options.usefree)
+				sbi->free_clusters =
+					le32_to_cpu(fsinfo->free_clusters);
 			sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
 		}
 
diff --git a/fs/fifo.c b/fs/fifo.c
index 49035b1..6e7df72 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -11,7 +11,6 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/pipe_fs_i.h>
 
diff --git a/fs/file_table.c b/fs/file_table.c
index 4c17a18..d17fd69 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -10,7 +10,6 @@ #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/security.h>
 #include <linux/eventpoll.h>
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 7a4f61a..f37f872 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -41,11 +41,12 @@ void put_filesystem(struct file_system_t
 	module_put(fs->owner);
 }
 
-static struct file_system_type **find_filesystem(const char *name)
+static struct file_system_type **find_filesystem(const char *name, unsigned len)
 {
 	struct file_system_type **p;
 	for (p=&file_systems; *p; p=&(*p)->next)
-		if (strcmp((*p)->name,name) == 0)
+		if (strlen((*p)->name) == len &&
+		    strncmp((*p)->name, name, len) == 0)
 			break;
 	return p;
 }
@@ -68,11 +69,12 @@ int register_filesystem(struct file_syst
 	int res = 0;
 	struct file_system_type ** p;
 
+	BUG_ON(strchr(fs->name, '.'));
 	if (fs->next)
 		return -EBUSY;
 	INIT_LIST_HEAD(&fs->fs_supers);
 	write_lock(&file_systems_lock);
-	p = find_filesystem(fs->name);
+	p = find_filesystem(fs->name, strlen(fs->name));
 	if (*p)
 		res = -EBUSY;
 	else
@@ -215,19 +217,26 @@ int get_filesystem_list(char * buf)
 struct file_system_type *get_fs_type(const char *name)
 {
 	struct file_system_type *fs;
+	const char *dot = strchr(name, '.');
+	unsigned len = dot ? dot - name : strlen(name);
 
 	read_lock(&file_systems_lock);
-	fs = *(find_filesystem(name));
+	fs = *(find_filesystem(name, len));
 	if (fs && !try_module_get(fs->owner))
 		fs = NULL;
 	read_unlock(&file_systems_lock);
-	if (!fs && (request_module("%s", name) == 0)) {
+	if (!fs && (request_module("%.*s", len, name) == 0)) {
 		read_lock(&file_systems_lock);
-		fs = *(find_filesystem(name));
+		fs = *(find_filesystem(name, len));
 		if (fs && !try_module_get(fs->owner))
 			fs = NULL;
 		read_unlock(&file_systems_lock);
 	}
+
+	if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
+		put_filesystem(fs);
+		fs = NULL;
+	}
 	return fs;
 }
 
diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
index 2d71128..f86fd3c 100644
--- a/fs/freevxfs/vxfs_bmap.c
+++ b/fs/freevxfs/vxfs_bmap.c
@@ -137,7 +137,7 @@ vxfs_bmap_indir(struct inode *ip, long i
 
 		bp = sb_bread(ip->i_sb,
 				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
-		if (!buffer_mapped(bp))
+		if (!bp || !buffer_mapped(bp))
 			return 0;
 
 		typ = ((struct vxfs_typed *)bp->b_data) +
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 098a915..d1f7c5b 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -99,7 +99,7 @@ vxfs_blkiget(struct super_block *sbp, u_
 	offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
 	bp = sb_bread(sbp, block);
 
-	if (buffer_mapped(bp)) {
+	if (bp && buffer_mapped(bp)) {
 		struct vxfs_inode_info	*vip;
 		struct vxfs_dinode	*dip;
 
diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
index decac62..ed8f0b0 100644
--- a/fs/freevxfs/vxfs_subr.c
+++ b/fs/freevxfs/vxfs_subr.c
@@ -74,10 +74,7 @@ vxfs_get_page(struct address_space *mapp
 	pp = read_mapping_page(mapping, n, NULL);
 
 	if (!IS_ERR(pp)) {
-		wait_on_page_locked(pp);
 		kmap(pp);
-		if (!PageUptodate(pp))
-			goto fail;
 		/** if (!PageChecked(pp)) **/
 			/** vxfs_check_page(pp); **/
 		if (PageError(pp))
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2fd0692..acfad65 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -738,8 +738,7 @@ static int fuse_file_lock(struct file *f
 
 	if (cmd == F_GETLK) {
 		if (fc->no_lock) {
-			if (!posix_test_lock(file, fl, fl))
-				fl->fl_type = F_UNLCK;
+			posix_test_lock(file, fl);
 			err = 0;
 		} else
 			err = fuse_getlk(file, fl);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 608db81..1397018 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -636,6 +636,7 @@ static int fuse_get_sb(struct file_syste
 static struct file_system_type fuse_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuse",
+	.fs_flags	= FS_HAS_SUBTYPE,
 	.get_sb		= fuse_get_sb,
 	.kill_sb	= kill_anon_super,
 };
@@ -652,6 +653,7 @@ static int fuse_get_sb_blk(struct file_s
 static struct file_system_type fuseblk_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "fuseblk",
+	.fs_flags	= FS_HAS_SUBTYPE,
 	.get_sb		= fuse_get_sb_blk,
 	.kill_sb	= kill_block_super,
 	.fs_flags	= FS_REQUIRES_DEV,
@@ -685,8 +687,7 @@ static void fuse_inode_init_once(void *f
 {
 	struct inode * inode = foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(inode);
 }
 
@@ -731,12 +732,12 @@ static int fuse_sysfs_init(void)
 {
 	int err;
 
-	kset_set_kset_s(&fuse_subsys, fs_subsys);
+	kobj_set_kset_s(&fuse_subsys, fs_subsys);
 	err = subsystem_register(&fuse_subsys);
 	if (err)
 		goto out_err;
 
-	kset_set_kset_s(&connections_subsys, fuse_subsys);
+	kobj_set_kset_s(&connections_subsys, fuse_subsys);
 	err = subsystem_register(&connections_subsys);
 	if (err)
 		goto out_fuse_unregister;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 82a1ac7..a96fa07 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1262,9 +1262,10 @@ static int gfs2_dir_read_leaf(struct ino
 			      u64 leaf_no)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct buffer_head *bh;
 	struct gfs2_leaf *lf;
-	unsigned entries = 0;
+	unsigned entries = 0, entries2 = 0;
 	unsigned leaves = 0;
 	const struct gfs2_dirent **darr, *dent;
 	struct dirent_gather g;
@@ -1290,7 +1291,13 @@ static int gfs2_dir_read_leaf(struct ino
 		return 0;
 
 	error = -ENOMEM;
-	larr = vmalloc((leaves + entries) * sizeof(void *));
+	/*
+	 * The extra 99 entries are not normally used, but are a buffer
+	 * zone in case the number of entries in the leaf is corrupt.
+	 * 99 is the maximum number of entries that can fit in a single
+	 * leaf block.
+	 */
+	larr = vmalloc((leaves + entries + 99) * sizeof(void *));
 	if (!larr)
 		goto out;
 	darr = (const struct gfs2_dirent **)(larr + leaves);
@@ -1305,10 +1312,20 @@ static int gfs2_dir_read_leaf(struct ino
 		lf = (struct gfs2_leaf *)bh->b_data;
 		lfn = be64_to_cpu(lf->lf_next);
 		if (lf->lf_entries) {
+			entries2 += be16_to_cpu(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)) {
+			if (IS_ERR(dent))
+				goto out_kfree;
+			if (entries2 != g.offset) {
+				fs_warn(sdp, "Number of entries corrupt in dir "
+						"leaf %llu, entries2 (%u) != "
+						"g.offset (%u)\n",
+					(unsigned long long)bh->b_blocknr,
+					entries2, g.offset);
+					
+				error = -EIO;
 				goto out_kfree;
 			}
 			error = 0;
@@ -1318,6 +1335,7 @@ static int gfs2_dir_read_leaf(struct ino
 		}
 	} while(lfn);
 
+	BUG_ON(entries2 != entries);
 	error = do_filldir_main(ip, offset, opaque, filldir, darr,
 				entries, copied);
 out_kfree:
@@ -1401,6 +1419,7 @@ int gfs2_dir_read(struct inode *inode, u
 		  filldir_t filldir)
 {
 	struct gfs2_inode *dip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct dirent_gather g;
 	const struct gfs2_dirent **darr, *dent;
 	struct buffer_head *dibh;
@@ -1423,8 +1442,8 @@ int gfs2_dir_read(struct inode *inode, u
 		return error;
 
 	error = -ENOMEM;
-	darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
-		       GFP_KERNEL);
+	/* 96 is max number of dirents which can be stuffed into an inode */
+	darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL);
 	if (darr) {
 		g.pdent = darr;
 		g.offset = 0;
@@ -1434,6 +1453,15 @@ int gfs2_dir_read(struct inode *inode, u
 			error = PTR_ERR(dent);
 			goto out;
 		}
+		if (dip->i_di.di_entries != g.offset) {
+			fs_warn(sdp, "Number of entries corrupt in dir %llu, "
+				"ip->i_di.di_entries (%u) != g.offset (%u)\n",
+				(unsigned long long)dip->i_num.no_addr,
+				dip->i_di.di_entries,
+				g.offset);
+			error = -EIO;
+			goto out;
+		}
 		error = do_filldir_main(dip, offset, opaque, filldir, darr,
 					dip->i_di.di_entries, &copied);
 out:
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 12accb0..1815429 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -23,6 +23,10 @@ #include <linux/wait.h>
 #include <linux/module.h>
 #include <linux/rwsem.h>
 #include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -40,20 +44,30 @@ struct gfs2_gl_hash_bucket {
         struct hlist_head hb_list;
 };
 
+struct glock_iter {
+	int hash;                     /* hash bucket index         */
+	struct gfs2_sbd *sdp;         /* incore superblock         */
+	struct gfs2_glock *gl;        /* current glock struct      */
+	struct hlist_head *hb_list;   /* current hash bucket ptr   */
+	struct seq_file *seq;         /* sequence file for debugfs */
+	char string[512];             /* scratch space             */
+};
+
 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);
-static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
+static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
 static void gfs2_glock_drop_th(struct gfs2_glock *gl);
 static DECLARE_RWSEM(gfs2_umount_flush_sem);
+static struct dentry *gfs2_root;
 
 #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];
+static struct dentry *gfs2_root;
 
 /*
  * Despite what you might think, the numbers below are not arbitrary :-)
@@ -202,7 +216,6 @@ int gfs2_glock_put(struct gfs2_glock *gl
 		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;
@@ -303,7 +316,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp,
 	atomic_set(&gl->gl_ref, 1);
 	gl->gl_state = LM_ST_UNLOCKED;
 	gl->gl_hash = hash;
-	gl->gl_owner = NULL;
+	gl->gl_owner_pid = 0;
 	gl->gl_ip = 0;
 	gl->gl_ops = glops;
 	gl->gl_req_gh = NULL;
@@ -367,7 +380,7 @@ void gfs2_holder_init(struct gfs2_glock 
 	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_owner_pid = current->pid;
 	gh->gh_state = state;
 	gh->gh_flags = flags;
 	gh->gh_error = 0;
@@ -389,7 +402,7 @@ void gfs2_holder_reinit(unsigned int sta
 {
 	gh->gh_state = state;
 	gh->gh_flags = flags;
-	gh->gh_iflags &= 1 << HIF_ALLOCED;
+	gh->gh_iflags = 0;
 	gh->gh_ip = (unsigned long)__builtin_return_address(0);
 }
 
@@ -406,54 +419,8 @@ void gfs2_holder_uninit(struct gfs2_hold
 	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)
+static void gfs2_holder_wake(struct gfs2_holder *gh)
 {
-	gfs2_holder_uninit(gh);
-	kfree(gh);
-}
-
-static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
-{
-	if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
-		gfs2_holder_put(gh);
-		return;
-	}
 	clear_bit(HIF_WAIT, &gh->gh_iflags);
 	smp_mb();
 	wake_up_bit(&gh->gh_iflags, HIF_WAIT);
@@ -519,7 +486,7 @@ static int rq_promote(struct gfs2_holder
 				gfs2_reclaim_glock(sdp);
 			}
 
-			gfs2_glock_xmote_th(gh);
+			gfs2_glock_xmote_th(gh->gh_gl, gh);
 			spin_lock(&gl->gl_spin);
 		}
 		return 1;
@@ -542,7 +509,7 @@ static int rq_promote(struct gfs2_holder
 	gh->gh_error = 0;
 	set_bit(HIF_HOLDER, &gh->gh_iflags);
 
-	gfs2_holder_dispose_or_wake(gh);
+	gfs2_holder_wake(gh);
 
 	return 0;
 }
@@ -554,32 +521,24 @@ static int rq_promote(struct gfs2_holder
  * Returns: 1 if the queue is blocked
  */
 
-static int rq_demote(struct gfs2_holder *gh)
+static int rq_demote(struct gfs2_glock *gl)
 {
-	struct gfs2_glock *gl = gh->gh_gl;
-
 	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);
-		gfs2_holder_dispose_or_wake(gh);
-		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)
-			gfs2_glock_drop_th(gl);
-		else
-			gfs2_glock_xmote_th(gh);
-
-		spin_lock(&gl->gl_spin);
+	if (gl->gl_state == gl->gl_demote_state ||
+	    gl->gl_state == LM_ST_UNLOCKED) {
+		clear_bit(GLF_DEMOTE, &gl->gl_flags);
+		return 0;
 	}
+	set_bit(GLF_LOCK, &gl->gl_flags);
+	spin_unlock(&gl->gl_spin);
+	if (gl->gl_demote_state == LM_ST_UNLOCKED ||
+	    gl->gl_state != LM_ST_EXCLUSIVE)
+		gfs2_glock_drop_th(gl);
+	else
+		gfs2_glock_xmote_th(gl, NULL);
+	spin_lock(&gl->gl_spin);
 
 	return 0;
 }
@@ -607,16 +566,8 @@ static void run_queue(struct gfs2_glock 
 			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
-				gfs2_assert_warn(gl->gl_sbd, 0);
-
+		} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+			blocked = rq_demote(gl);
 		} else if (!list_empty(&gl->gl_waiters3)) {
 			gh = list_entry(gl->gl_waiters3.next,
 					struct gfs2_holder, gh_list);
@@ -654,7 +605,7 @@ static void gfs2_glmutex_lock(struct gfs
 	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_owner_pid = current->pid;
 		gl->gl_ip = (unsigned long)__builtin_return_address(0);
 		clear_bit(HIF_WAIT, &gh.gh_iflags);
 		smp_mb();
@@ -681,7 +632,7 @@ static int gfs2_glmutex_trylock(struct g
 	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
 		acquired = 0;
 	} else {
-		gl->gl_owner = current;
+		gl->gl_owner_pid = current->pid;
 		gl->gl_ip = (unsigned long)__builtin_return_address(0);
 	}
 	spin_unlock(&gl->gl_spin);
@@ -699,7 +650,7 @@ static void gfs2_glmutex_unlock(struct g
 {
 	spin_lock(&gl->gl_spin);
 	clear_bit(GLF_LOCK, &gl->gl_flags);
-	gl->gl_owner = NULL;
+	gl->gl_owner_pid = 0;
 	gl->gl_ip = 0;
 	run_queue(gl);
 	BUG_ON(!spin_is_locked(&gl->gl_spin));
@@ -707,50 +658,24 @@ static void gfs2_glmutex_unlock(struct g
 }
 
 /**
- * handle_callback - add a demote request to a lock's queue
+ * handle_callback - process a demote request
  * @gl: the glock
  * @state: the state the caller wants us to change to
  *
- * Note: This may fail sliently if we are out of memory.
+ * There are only two requests that we are going to see in actual
+ * practise: LM_ST_SHARED and LM_ST_UNLOCKED
  */
 
 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_NOFS);
-		if (!new_gh)
-			return;
-		set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
-		set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
-		set_bit(HIF_WAIT, &new_gh->gh_iflags);
-
-		goto restart;
+	if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+		gl->gl_demote_state = state;
+		gl->gl_demote_time = jiffies;
+	} else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
+		gl->gl_demote_state = state;
 	}
-
-out:
 	spin_unlock(&gl->gl_spin);
-
-	if (new_gh)
-		gfs2_holder_put(new_gh);
 }
 
 /**
@@ -810,56 +735,37 @@ static void xmote_bh(struct gfs2_glock *
 
 	/*  Deal with each possible exit condition  */
 
-	if (!gh)
+	if (!gh) {
 		gl->gl_stamp = jiffies;
-	else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+		if (ret & LM_OUT_CANCELED)
+			op_done = 0;
+		else
+			clear_bit(GLF_DEMOTE, &gl->gl_flags);
+	} else {
 		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) {
+		if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) 
+			goto out;
+		gh->gh_error = GLR_CANCELED;
+		if (ret & LM_OUT_CANCELED) 
+			goto out;
+		if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+			list_add_tail(&gh->gh_list, &gl->gl_holders);
 			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;
+			set_bit(HIF_HOLDER, &gh->gh_iflags);
+			set_bit(HIF_FIRST, &gh->gh_iflags);
+			op_done = 0;
+			goto out;
 		}
-		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 (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
+			goto out;
+		gh->gh_error = -EINVAL;
 		if (gfs2_assert_withdraw(sdp, 0) == -1)
 			fs_err(sdp, "ret = 0x%.8X\n", ret);
+out:
+		spin_unlock(&gl->gl_spin);
 	}
 
 	if (glops->go_xmote_bh)
@@ -877,7 +783,7 @@ static void xmote_bh(struct gfs2_glock *
 	gfs2_glock_put(gl);
 
 	if (gh)
-		gfs2_holder_dispose_or_wake(gh);
+		gfs2_holder_wake(gh);
 }
 
 /**
@@ -888,12 +794,11 @@ static void xmote_bh(struct gfs2_glock *
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_holder *gh)
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
 {
-	struct gfs2_glock *gl = gh->gh_gl;
 	struct gfs2_sbd *sdp = gl->gl_sbd;
-	int flags = gh->gh_flags;
-	unsigned state = gh->gh_state;
+	int flags = gh ? gh->gh_flags : 0;
+	unsigned state = gh ? gh->gh_state : gl->gl_demote_state;
 	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 |
@@ -943,6 +848,7 @@ static void drop_bh(struct gfs2_glock *g
 	gfs2_assert_warn(sdp, !ret);
 
 	state_change(gl, LM_ST_UNLOCKED);
+	clear_bit(GLF_DEMOTE, &gl->gl_flags);
 
 	if (glops->go_inval)
 		glops->go_inval(gl, DIO_METADATA);
@@ -964,7 +870,7 @@ static void drop_bh(struct gfs2_glock *g
 	gfs2_glock_put(gl);
 
 	if (gh)
-		gfs2_holder_dispose_or_wake(gh);
+		gfs2_holder_wake(gh);
 }
 
 /**
@@ -1097,18 +1003,32 @@ static int glock_wait_internal(struct gf
 }
 
 static inline struct gfs2_holder *
-find_holder_by_owner(struct list_head *head, struct task_struct *owner)
+find_holder_by_owner(struct list_head *head, pid_t pid)
 {
 	struct gfs2_holder *gh;
 
 	list_for_each_entry(gh, head, gh_list) {
-		if (gh->gh_owner == owner)
+		if (gh->gh_owner_pid == pid)
 			return gh;
 	}
 
 	return NULL;
 }
 
+static void print_dbg(struct glock_iter *gi, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	if (gi) {
+		vsprintf(gi->string, fmt, args);
+		seq_printf(gi->seq, gi->string);
+	}
+	else
+		vprintk(fmt, args);
+	va_end(args);
+}
+
 /**
  * add_to_queue - Add a holder to the wait queue (but look for recursion)
  * @gh: the holder structure to add
@@ -1120,24 +1040,24 @@ static void add_to_queue(struct gfs2_hol
 	struct gfs2_glock *gl = gh->gh_gl;
 	struct gfs2_holder *existing;
 
-	BUG_ON(!gh->gh_owner);
+	BUG_ON(!gh->gh_owner_pid);
 	if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
 		BUG();
 
-	existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
+	existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
 	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 "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 "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);
+	existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
 	if (existing) {
 		print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
 		print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
@@ -1267,9 +1187,8 @@ void gfs2_glock_dq(struct gfs2_holder *g
 		if (glops->go_unlock)
 			glops->go_unlock(gh);
 
-		gl->gl_stamp = jiffies;
-
 		spin_lock(&gl->gl_spin);
+		gl->gl_stamp = jiffies;
 	}
 
 	clear_bit(GLF_LOCK, &gl->gl_flags);
@@ -1841,6 +1760,15 @@ void gfs2_gl_hash_clear(struct gfs2_sbd 
  *  Diagnostic routines to help debug distributed deadlock
  */
 
+static void gfs2_print_symbol(struct glock_iter *gi, const char *fmt,
+                              unsigned long address)
+{
+	char buffer[KSYM_SYMBOL_LEN];
+
+	sprint_symbol(buffer, address);
+	print_dbg(gi, fmt, buffer);
+}
+
 /**
  * dump_holder - print information about a glock holder
  * @str: a string naming the type of holder
@@ -1849,31 +1777,37 @@ void gfs2_gl_hash_clear(struct gfs2_sbd 
  * Returns: 0 on success, -ENOBUFS when we run out of space
  */
 
-static int dump_holder(char *str, struct gfs2_holder *gh)
+static int dump_holder(struct glock_iter *gi, 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 =");
+	struct task_struct *gh_owner;
+
+	print_dbg(gi, "  %s\n", str);
+	if (gh->gh_owner_pid) {
+		print_dbg(gi, "    owner = %ld ", (long)gh->gh_owner_pid);
+		gh_owner = find_task_by_pid(gh->gh_owner_pid);
+		if (gh_owner)
+			print_dbg(gi, "(%s)\n", gh_owner->comm);
+		else
+			print_dbg(gi, "(ended)\n");
+	} else
+		print_dbg(gi, "    owner = -1\n");
+	print_dbg(gi, "    gh_state = %u\n", gh->gh_state);
+	print_dbg(gi, "    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 =");
+			print_dbg(gi, " %u", x);
+	print_dbg(gi, " \n");
+	print_dbg(gi, "    error = %d\n", gh->gh_error);
+	print_dbg(gi, "    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;
+			print_dbg(gi, " %u", x);
+	print_dbg(gi, " \n");
+        gfs2_print_symbol(gi, "    initialized at: %s\n", gh->gh_ip);
 
-	return error;
+	return 0;
 }
 
 /**
@@ -1883,25 +1817,20 @@ static int dump_holder(char *str, struct
  * Returns: 0 on success, -ENOBUFS when we run out of space
  */
 
-static int dump_inode(struct gfs2_inode *ip)
+static int dump_inode(struct glock_iter *gi, 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_inode.i_mode));
-	printk(KERN_INFO "    i_flags =");
+	print_dbg(gi, "  Inode:\n");
+	print_dbg(gi, "    num = %llu/%llu\n",
+		    ip->i_num.no_formal_ino, ip->i_num.no_addr);
+	print_dbg(gi, "    type = %u\n", IF2DT(ip->i_inode.i_mode));
+	print_dbg(gi, "    i_flags =");
 	for (x = 0; x < 32; x++)
 		if (test_bit(x, &ip->i_flags))
-			printk(" %u", x);
-	printk(" \n");
-
-	error = 0;
-
-	return error;
+			print_dbg(gi, " %u", x);
+	print_dbg(gi, " \n");
+	return 0;
 }
 
 /**
@@ -1912,74 +1841,86 @@ static int dump_inode(struct gfs2_inode 
  * Returns: 0 on success, -ENOBUFS when we run out of space
  */
 
-static int dump_glock(struct gfs2_glock *gl)
+static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
 {
 	struct gfs2_holder *gh;
 	unsigned int x;
 	int error = -ENOBUFS;
+	struct task_struct *gl_owner;
 
 	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 =");
+	print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+		   (unsigned long long)gl->gl_name.ln_number);
+	print_dbg(gi, "  gl_flags =");
 	for (x = 0; x < 32; x++) {
 		if (test_bit(x, &gl->gl_flags))
-			printk(" %u", x);
+			print_dbg(gi, " %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",
+	if (!test_bit(GLF_LOCK, &gl->gl_flags))
+		print_dbg(gi, " (unlocked)");
+	print_dbg(gi, " \n");
+	print_dbg(gi, "  gl_ref = %d\n", atomic_read(&gl->gl_ref));
+	print_dbg(gi, "  gl_state = %u\n", gl->gl_state);
+	if (gl->gl_owner_pid) {
+		gl_owner = find_task_by_pid(gl->gl_owner_pid);
+		if (gl_owner)
+			print_dbg(gi, "  gl_owner = pid %d (%s)\n",
+				  gl->gl_owner_pid, gl_owner->comm);
+		else
+			print_dbg(gi, "  gl_owner = %d (ended)\n",
+				  gl->gl_owner_pid);
+	} else
+		print_dbg(gi, "  gl_owner = -1\n");
+	print_dbg(gi, "  gl_ip = %lu\n", gl->gl_ip);
+	print_dbg(gi, "  req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
+	print_dbg(gi, "  req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
+	print_dbg(gi, "  lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
+	print_dbg(gi, "  object = %s\n", (gl->gl_object) ? "yes" : "no");
+	print_dbg(gi, "  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");
+	print_dbg(gi, "  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);
+		print_dbg(gi, "  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));
+		print_dbg(gi, "  aspace = no\n");
+	print_dbg(gi, "  ail = %d\n", atomic_read(&gl->gl_ail_count));
 	if (gl->gl_req_gh) {
-		error = dump_holder("Request", gl->gl_req_gh);
+		error = dump_holder(gi, "Request", gl->gl_req_gh);
 		if (error)
 			goto out;
 	}
 	list_for_each_entry(gh, &gl->gl_holders, gh_list) {
-		error = dump_holder("Holder", gh);
+		error = dump_holder(gi, "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);
+		error = dump_holder(gi, "Waiter1", gh);
 		if (error)
 			goto out;
 	}
 	list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
-		error = dump_holder("Waiter3", gh);
+		error = dump_holder(gi, "Waiter3", gh);
 		if (error)
 			goto out;
 	}
+	if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+		print_dbg(gi, "  Demotion req to state %u (%llu uS ago)\n",
+			  gl->gl_demote_state,
+			  (u64)(jiffies - gl->gl_demote_time)*(1000000/HZ));
+	}
 	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);
+			list_empty(&gl->gl_holders)) {
+			error = dump_inode(gi, gl->gl_object);
 			if (error)
 				goto out;
 		} else {
 			error = -ENOBUFS;
-			printk(KERN_INFO "  Inode: busy\n");
+			print_dbg(gi, "  Inode: busy\n");
 		}
 	}
 
@@ -2014,7 +1955,7 @@ static int gfs2_dump_lockstate(struct gf
 			if (gl->gl_sbd != sdp)
 				continue;
 
-			error = dump_glock(gl);
+			error = dump_glock(NULL, gl);
 			if (error)
 				break;
 		}
@@ -2043,3 +1984,189 @@ #endif
 	return 0;
 }
 
+static int gfs2_glock_iter_next(struct glock_iter *gi)
+{
+	read_lock(gl_lock_addr(gi->hash));
+	while (1) {
+		if (!gi->hb_list) {  /* If we don't have a hash bucket yet */
+			gi->hb_list = &gl_hash_table[gi->hash].hb_list;
+			if (hlist_empty(gi->hb_list)) {
+				read_unlock(gl_lock_addr(gi->hash));
+				gi->hash++;
+				read_lock(gl_lock_addr(gi->hash));
+				gi->hb_list = NULL;
+				if (gi->hash >= GFS2_GL_HASH_SIZE) {
+					read_unlock(gl_lock_addr(gi->hash));
+					return 1;
+				}
+				else
+					continue;
+			}
+			if (!hlist_empty(gi->hb_list)) {
+				gi->gl = list_entry(gi->hb_list->first,
+						    struct gfs2_glock,
+						    gl_list);
+			}
+		} else {
+			if (gi->gl->gl_list.next == NULL) {
+				read_unlock(gl_lock_addr(gi->hash));
+				gi->hash++;
+				read_lock(gl_lock_addr(gi->hash));
+				gi->hb_list = NULL;
+				continue;
+			}
+			gi->gl = list_entry(gi->gl->gl_list.next,
+					    struct gfs2_glock, gl_list);
+		}
+		if (gi->gl)
+			break;
+	}
+	read_unlock(gl_lock_addr(gi->hash));
+	return 0;
+}
+
+static void gfs2_glock_iter_free(struct glock_iter *gi)
+{
+	kfree(gi);
+}
+
+static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)
+{
+	struct glock_iter *gi;
+
+	gi = kmalloc(sizeof (*gi), GFP_KERNEL);
+	if (!gi)
+		return NULL;
+
+	gi->sdp = sdp;
+	gi->hash = 0;
+	gi->gl = NULL;
+	gi->hb_list = NULL;
+	gi->seq = NULL;
+	memset(gi->string, 0, sizeof(gi->string));
+
+	if (gfs2_glock_iter_next(gi)) {
+		gfs2_glock_iter_free(gi);
+		return NULL;
+	}
+
+	return gi;
+}
+
+static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)
+{
+	struct glock_iter *gi;
+	loff_t n = *pos;
+
+	gi = gfs2_glock_iter_init(file->private);
+	if (!gi)
+		return NULL;
+
+	while (n--) {
+		if (gfs2_glock_iter_next(gi)) {
+			gfs2_glock_iter_free(gi);
+			return NULL;
+		}
+	}
+
+	return gi;
+}
+
+static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,
+				 loff_t *pos)
+{
+	struct glock_iter *gi = iter_ptr;
+
+	(*pos)++;
+
+	if (gfs2_glock_iter_next(gi)) {
+		gfs2_glock_iter_free(gi);
+		return NULL;
+	}
+
+	return gi;
+}
+
+static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
+{
+	/* nothing for now */
+}
+
+static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
+{
+	struct glock_iter *gi = iter_ptr;
+
+	gi->seq = file;
+	dump_glock(gi, gi->gl);
+
+	return 0;
+}
+
+static struct seq_operations gfs2_glock_seq_ops = {
+	.start = gfs2_glock_seq_start,
+	.next  = gfs2_glock_seq_next,
+	.stop  = gfs2_glock_seq_stop,
+	.show  = gfs2_glock_seq_show,
+};
+
+static int gfs2_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int ret;
+
+	ret = seq_open(file, &gfs2_glock_seq_ops);
+	if (ret)
+		return ret;
+
+	seq = file->private_data;
+	seq->private = inode->i_private;
+
+	return 0;
+}
+
+static const struct file_operations gfs2_debug_fops = {
+	.owner   = THIS_MODULE,
+	.open    = gfs2_debugfs_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
+int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
+{
+	sdp->debugfs_dir = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
+	if (!sdp->debugfs_dir)
+		return -ENOMEM;
+	sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
+							 S_IFREG | S_IRUGO,
+							 sdp->debugfs_dir, sdp,
+							 &gfs2_debug_fops);
+	if (!sdp->debugfs_dentry_glocks)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
+{
+	if (sdp && sdp->debugfs_dir) {
+		if (sdp->debugfs_dentry_glocks) {
+			debugfs_remove(sdp->debugfs_dentry_glocks);
+			sdp->debugfs_dentry_glocks = NULL;
+		}
+		debugfs_remove(sdp->debugfs_dir);
+		sdp->debugfs_dir = NULL;
+	}
+}
+
+int gfs2_register_debugfs(void)
+{
+	gfs2_root = debugfs_create_dir("gfs2", NULL);
+	return gfs2_root ? 0 : -ENOMEM;
+}
+
+void gfs2_unregister_debugfs(void)
+{
+	debugfs_remove(gfs2_root);
+	gfs2_root = NULL;
+}
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index f50e40c..11477ca 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -38,7 +38,7 @@ static inline int gfs2_glock_is_locked_b
 	/* 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) {
+		if (gh->gh_owner_pid == current->pid) {
 			locked = 1;
 			break;
 		}
@@ -67,7 +67,7 @@ static inline int gfs2_glock_is_blocking
 {
 	int ret;
 	spin_lock(&gl->gl_spin);
-	ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
+	ret = test_bit(GLF_DEMOTE, &gl->gl_flags) || !list_empty(&gl->gl_waiters3);
 	spin_unlock(&gl->gl_spin);
 	return ret;
 }
@@ -135,5 +135,9 @@ void gfs2_scand_internal(struct gfs2_sbd
 void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
 
 int __init gfs2_glock_init(void);
+int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
+void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
+int gfs2_register_debugfs(void);
+void gfs2_unregister_debugfs(void);
 
 #endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 39c8ae2..7b82657 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -163,10 +163,7 @@ static void inode_go_sync(struct gfs2_gl
 		if (ip) {
 			struct address_space *mapping = ip->i_inode.i_mapping;
 			int error = filemap_fdatawait(mapping);
-			if (error == -ENOSPC)
-				set_bit(AS_ENOSPC, &mapping->flags);
-			else if (error)
-				set_bit(AS_EIO, &mapping->flags);
+			mapping_set_error(mapping, error);
 		}
 		clear_bit(GLF_DIRTY, &gl->gl_flags);
 		gfs2_ail_empty_gl(gl);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 49f0dbf..d995441 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -115,11 +115,8 @@ enum {
 	/* Actions */
 	HIF_MUTEX		= 0,
 	HIF_PROMOTE		= 1,
-	HIF_DEMOTE		= 2,
 
 	/* States */
-	HIF_ALLOCED		= 4,
-	HIF_DEALLOC		= 5,
 	HIF_HOLDER		= 6,
 	HIF_FIRST		= 7,
 	HIF_ABORTED		= 9,
@@ -130,7 +127,7 @@ struct gfs2_holder {
 	struct list_head gh_list;
 
 	struct gfs2_glock *gh_gl;
-	struct task_struct *gh_owner;
+	pid_t gh_owner_pid;
 	unsigned int gh_state;
 	unsigned gh_flags;
 
@@ -142,8 +139,8 @@ struct gfs2_holder {
 enum {
 	GLF_LOCK		= 1,
 	GLF_STICKY		= 2,
+	GLF_DEMOTE		= 3,
 	GLF_DIRTY		= 5,
-	GLF_SKIP_WAITERS2	= 6,
 };
 
 struct gfs2_glock {
@@ -156,11 +153,12 @@ struct gfs2_glock {
 
 	unsigned int gl_state;
 	unsigned int gl_hash;
-	struct task_struct *gl_owner;
+	unsigned int gl_demote_state; /* state requested by remote node */
+	unsigned long gl_demote_time; /* time of first demote request */
+	pid_t gl_owner_pid;
 	unsigned long gl_ip;
 	struct list_head gl_holders;
 	struct list_head gl_waiters1;	/* HIF_MUTEX */
-	struct list_head gl_waiters2;	/* HIF_DEMOTE */
 	struct list_head gl_waiters3;	/* HIF_PROMOTE */
 
 	const struct gfs2_glock_operations *gl_ops;
@@ -611,6 +609,8 @@ struct gfs2_sbd {
 
 	unsigned long sd_last_warning;
 	struct vfsmount *sd_gfs2mnt;
+	struct dentry *debugfs_dir;    /* debugfs directory */
+	struct dentry *debugfs_dentry_glocks; /* for debugfs */
 };
 
 #endif /* __INCORE_DOT_H__ */
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
index b167add..c305255 100644
--- a/fs/gfs2/locking/dlm/lock.c
+++ b/fs/gfs2/locking/dlm/lock.c
@@ -151,7 +151,7 @@ static inline unsigned int make_flags(st
 
 /* make_strname - convert GFS lock numbers to a string */
 
-static inline void make_strname(struct lm_lockname *lockname,
+static inline void make_strname(const struct lm_lockname *lockname,
 				struct gdlm_strname *str)
 {
 	sprintf(str->name, "%8x%16llx", lockname->ln_type,
@@ -169,6 +169,7 @@ static int gdlm_create_lp(struct gdlm_ls
 		return -ENOMEM;
 
 	lp->lockname = *name;
+	make_strname(name, &lp->strname);
 	lp->ls = ls;
 	lp->cur = DLM_LOCK_IV;
 	lp->lvb = NULL;
@@ -227,7 +228,6 @@ void gdlm_put_lock(void *lock)
 unsigned int gdlm_do_lock(struct gdlm_lock *lp)
 {
 	struct gdlm_ls *ls = lp->ls;
-	struct gdlm_strname str;
 	int error, bast = 1;
 
 	/*
@@ -249,8 +249,6 @@ unsigned int gdlm_do_lock(struct gdlm_lo
 	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,
@@ -258,8 +256,8 @@ unsigned int gdlm_do_lock(struct gdlm_lo
 		  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);
+			 lp->strname.name, lp->strname.namelen, 0, gdlm_ast,
+			 lp, bast ? gdlm_bast : NULL);
 
 	if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
 		lp->lksb.sb_status = -EAGAIN;
@@ -268,7 +266,7 @@ unsigned int gdlm_do_lock(struct gdlm_lo
 	}
 
 	if (error) {
-		log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
+		log_error("%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);
@@ -296,7 +294,7 @@ static unsigned int gdlm_do_unlock(struc
 	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 "
+		log_error("%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);
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index a87c7bf..d074c6e 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -36,7 +36,7 @@ #include <linux/lm_interface.h>
 
 #define GDLM_STRNAME_BYTES	24
 #define GDLM_LVB_SIZE		32
-#define GDLM_DROP_COUNT		200000
+#define GDLM_DROP_COUNT		0
 #define GDLM_DROP_PERIOD	60
 #define GDLM_NAME_LEN		128
 
@@ -106,6 +106,7 @@ enum {
 struct gdlm_lock {
 	struct gdlm_ls		*ls;
 	struct lm_lockname	lockname;
+	struct gdlm_strname	strname;
 	char			*lvb;
 	struct dlm_lksb		lksb;
 
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index 1dd4215..f82495e 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -25,6 +25,15 @@ struct plock_op {
 	struct gdlm_plock_info info;
 };
 
+struct plock_xop {
+	struct plock_op xop;
+	void *callback;
+	void *fl;
+	void *file;
+	struct file_lock flc;
+};
+
+
 static inline void set_version(struct gdlm_plock_info *info)
 {
 	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct l
 {
 	struct gdlm_ls *ls = lockspace;
 	struct plock_op *op;
+	struct plock_xop *xop;
 	int rv;
 
-	op = kzalloc(sizeof(*op), GFP_KERNEL);
-	if (!op)
+	xop = kzalloc(sizeof(*xop), GFP_KERNEL);
+	if (!xop)
 		return -ENOMEM;
 
+	op = &xop->xop;
 	op->info.optype		= GDLM_PLOCK_OP_LOCK;
 	op->info.pid		= fl->fl_pid;
 	op->info.ex		= (fl->fl_type == F_WRLCK);
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct l
 	op->info.start		= fl->fl_start;
 	op->info.end		= fl->fl_end;
 	op->info.owner		= (__u64)(long) fl->fl_owner;
+	if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+		xop->callback	= fl->fl_lmops->fl_grant;
+		locks_init_lock(&xop->flc);
+		locks_copy_lock(&xop->flc, fl);
+		xop->fl		= fl;
+		xop->file	= file;
+	} else
+		xop->callback	= NULL;
 
 	send_op(op);
-	wait_event(recv_wq, (op->done != 0));
+
+	if (xop->callback == NULL)
+		wait_event(recv_wq, (op->done != 0));
+	else
+		return -EINPROGRESS;
 
 	spin_lock(&ops_lock);
 	if (!list_empty(&op->list)) {
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct l
 				  (unsigned long long)name->ln_number);
 	}
 
-	kfree(op);
+	kfree(xop);
+	return rv;
+}
+
+/* Returns failure iff a succesful lock operation should be canceled */
+static int gdlm_plock_callback(struct plock_op *op)
+{
+	struct file *file;
+	struct file_lock *fl;
+	struct file_lock *flc;
+	int (*notify)(void *, void *, int) = NULL;
+	struct plock_xop *xop = (struct plock_xop *)op;
+	int rv = 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);
+
+	/* check if the following 2 are still valid or make a copy */
+	file = xop->file;
+	flc = &xop->flc;
+	fl = xop->fl;
+	notify = xop->callback;
+
+	if (op->info.rv) {
+		notify(flc, NULL, op->info.rv);
+		goto out;
+	}
+
+	/* got fs lock; bookkeep locally as well: */
+	flc->fl_flags &= ~FL_SLEEP;
+	if (posix_lock_file(file, flc, NULL)) {
+		/*
+		 * This can only happen in the case of kmalloc() failure.
+		 * The filesystem's own lock is the authoritative lock,
+		 * so a failure to get the lock locally is not a disaster.
+		 * As long as GFS cannot reliably cancel locks (especially
+		 * in a low-memory situation), we're better off ignoring
+		 * this failure than trying to recover.
+		 */
+		log_error("gdlm_plock: vfs lock error file %p fl %p",
+				file, fl);
+	}
+
+	rv = notify(flc, NULL, 0);
+	if (rv) {
+		/* XXX: We need to cancel the fs lock here: */
+		printk("gfs2 lock granted after lock request failed;"
+						" dangling lock!\n");
+		goto out;
+	}
+
+out:
+	kfree(xop);
 	return rv;
 }
 
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct
 
 	rv = op->info.rv;
 
+	if (rv == -ENOENT)
+		rv = 0;
+
 	kfree(op);
 	return rv;
 }
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, stru
 	op->info.start		= fl->fl_start;
 	op->info.end		= fl->fl_end;
 
+
 	send_op(op);
 	wait_event(recv_wq, (op->done != 0));
 
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, stru
 
 	rv = op->info.rv;
 
-	if (rv == 0)
-		fl->fl_type = F_UNLCK;
-	else if (rv > 0) {
+	fl->fl_type = F_UNLCK;
+	if (rv == -ENOENT)
+		rv = 0;
+	else if (rv == 0 && op->info.pid != fl->fl_pid) {
 		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
 		fl->fl_pid = op->info.pid;
 		fl->fl_start = op->info.start;
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *fi
 	}
 	spin_unlock(&ops_lock);
 
-	if (found)
-		wake_up(&recv_wq);
-	else
+	if (found) {
+		struct plock_xop *xop;
+		xop = (struct plock_xop *)op;
+		if (xop->callback)
+			count = gdlm_plock_callback(op);
+		else
+			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;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 4746b88..d9fe3ca 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = {
 };
 
 static struct kset gdlm_kset = {
-	.subsys = &kernel_subsys,
 	.kobj   = {.name = "lock_dlm",},
 	.ktype  = &gdlm_ktype,
 };
@@ -225,6 +224,7 @@ int gdlm_sysfs_init(void)
 {
 	int error;
 
+	kobj_set_kset_s(&gdlm_kset, kernel_subsys);
 	error = kset_register(&gdlm_kset);
 	if (error)
 		printk("lock_dlm: cannot register kset %d\n", error);
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
index acfbc94..0d149c8 100644
--- a/fs/gfs2/locking/nolock/main.c
+++ b/fs/gfs2/locking/nolock/main.c
@@ -13,7 +13,6 @@ #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 {
@@ -164,13 +163,7 @@ static void nolock_unhold_lvb(void *lock
 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));
+	posix_test_lock(file, fl);
 
 	return 0;
 }
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 16bb4b4..f82d84d 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -33,16 +33,17 @@ static void glock_lo_add(struct gfs2_sbd
 
 	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);
+	if (!list_empty(&le->le_list)){
+		gfs2_log_unlock(sdp);
+		return;
+	}
+	gfs2_glock_hold(gl);
+	set_bit(GLF_DIRTY, &gl->gl_flags);
 	sdp->sd_log_num_gl++;
 	list_add(&le->le_list, &sdp->sd_log_le_gl);
 	gfs2_log_unlock(sdp);
@@ -415,13 +416,14 @@ static void rg_lo_add(struct gfs2_sbd *s
 
 	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);
+	if (!list_empty(&le->le_list)){
+		gfs2_log_unlock(sdp);
+		return;
+	}
+	gfs2_rgrp_bh_hold(rgd);
 	sdp->sd_log_num_rg++;
 	list_add(&le->le_list, &sdp->sd_log_le_rg);
 	gfs2_log_unlock(sdp);
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 6e8a598..e460487 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -27,8 +27,7 @@ #include "glock.h"
 static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
 {
 	struct gfs2_inode *ip = foo;
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&ip->i_inode);
 		spin_lock_init(&ip->i_spin);
 		init_rwsem(&ip->i_rw_mutex);
@@ -39,13 +38,11 @@ static void gfs2_init_inode_once(void *f
 static void gfs2_init_glock_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
 {
 	struct gfs2_glock *gl = foo;
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & 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);
@@ -103,6 +100,8 @@ static int __init init_gfs2_fs(void)
 	if (error)
 		goto fail_unregister;
 
+	gfs2_register_debugfs();
+
 	printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
 
 	return 0;
@@ -130,6 +129,7 @@ fail:
 
 static void __exit exit_gfs2_fs(void)
 {
+	gfs2_unregister_debugfs();
 	unregister_filesystem(&gfs2_fs_type);
 	unregister_filesystem(&gfs2meta_fs_type);
 
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index 32caecd..4864659 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -13,6 +13,7 @@ #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/lm_interface.h>
+#include <linux/parser.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -20,6 +21,52 @@ #include "mount.h"
 #include "sys.h"
 #include "util.h"
 
+enum {
+	Opt_lockproto,
+	Opt_locktable,
+	Opt_hostdata,
+	Opt_spectator,
+	Opt_ignore_local_fs,
+	Opt_localflocks,
+	Opt_localcaching,
+	Opt_debug,
+	Opt_nodebug,
+	Opt_upgrade,
+	Opt_num_glockd,
+	Opt_acl,
+	Opt_noacl,
+	Opt_quota_off,
+	Opt_quota_account,
+	Opt_quota_on,
+	Opt_suiddir,
+	Opt_nosuiddir,
+	Opt_data_writeback,
+	Opt_data_ordered,
+};
+
+static match_table_t tokens = {
+	{Opt_lockproto, "lockproto=%s"},
+	{Opt_locktable, "locktable=%s"},
+	{Opt_hostdata, "hostdata=%s"},
+	{Opt_spectator, "spectator"},
+	{Opt_ignore_local_fs, "ignore_local_fs"},
+	{Opt_localflocks, "localflocks"},
+	{Opt_localcaching, "localcaching"},
+	{Opt_debug, "debug"},
+	{Opt_nodebug, "nodebug"},
+	{Opt_upgrade, "upgrade"},
+	{Opt_num_glockd, "num_glockd=%d"},
+	{Opt_acl, "acl"},
+	{Opt_noacl, "noacl"},
+	{Opt_quota_off, "quota=off"},
+	{Opt_quota_account, "quota=account"},
+	{Opt_quota_on, "quota=on"},
+	{Opt_suiddir, "suiddir"},
+	{Opt_nosuiddir, "nosuiddir"},
+	{Opt_data_writeback, "data=writeback"},
+	{Opt_data_ordered, "data=ordered"}
+};
+
 /**
  * gfs2_mount_args - Parse mount options
  * @sdp:
@@ -54,146 +101,150 @@ int gfs2_mount_args(struct gfs2_sbd *sdp
 	   process them */
 
 	for (options = data; (o = strsep(&options, ",")); ) {
+		int token, option;
+		substring_t tmp[MAX_OPT_ARGS];
+
 		if (!*o)
 			continue;
 
-		v = strchr(o, '=');
-		if (v)
-			*v++ = 0;
+		token = match_token(o, tokens, tmp);
+		switch (token) {
+		case Opt_lockproto:
+			v = match_strdup(&tmp[0]);
+			if (!v) {
+				fs_info(sdp, "no memory for lockproto\n");
+				error = -ENOMEM;
+				goto out_error;
+			}
 
-		if (!strcmp(o, "lockproto")) {
-			if (!v)
-				goto need_value;
-			if (remount && strcmp(v, args->ar_lockproto))
+			if (remount && strcmp(v, args->ar_lockproto)) {
+				kfree(v);
 				goto cant_remount;
+			}
+			
 			strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
 			args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
-		}
+			kfree(v);
+			break;
+		case Opt_locktable:
+			v = match_strdup(&tmp[0]);
+			if (!v) {
+				fs_info(sdp, "no memory for locktable\n");
+				error = -ENOMEM;
+				goto out_error;
+			}
 
-		else if (!strcmp(o, "locktable")) {
-			if (!v)
-				goto need_value;
-			if (remount && strcmp(v, args->ar_locktable))
+			if (remount && strcmp(v, args->ar_locktable)) {
+				kfree(v);
 				goto cant_remount;
+			}
+
 			strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
-			args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
-		}
+			args->ar_locktable[GFS2_LOCKNAME_LEN - 1]  = 0;
+			kfree(v);
+			break;
+		case Opt_hostdata:
+			v = match_strdup(&tmp[0]);
+			if (!v) {
+				fs_info(sdp, "no memory for hostdata\n");
+				error = -ENOMEM;
+				goto out_error;
+			}
 
-		else if (!strcmp(o, "hostdata")) {
-			if (!v)
-				goto need_value;
-			if (remount && strcmp(v, args->ar_hostdata))
+			if (remount && strcmp(v, args->ar_hostdata)) {
+				kfree(v);
 				goto cant_remount;
+			}
+
 			strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
 			args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
-		}
-
-		else if (!strcmp(o, "spectator")) {
+			kfree(v);
+			break;
+		case Opt_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")) {
+			break;
+		case Opt_ignore_local_fs:
 			if (remount && !args->ar_ignore_local_fs)
 				goto cant_remount;
 			args->ar_ignore_local_fs = 1;
-		}
-
-		else if (!strcmp(o, "localflocks")) {
+			break;
+		case Opt_localflocks:
 			if (remount && !args->ar_localflocks)
 				goto cant_remount;
 			args->ar_localflocks = 1;
-		}
-
-		else if (!strcmp(o, "localcaching")) {
+			break;
+		case Opt_localcaching:
 			if (remount && !args->ar_localcaching)
 				goto cant_remount;
 			args->ar_localcaching = 1;
-		}
-
-		else if (!strcmp(o, "debug"))
+			break;
+		case Opt_debug:
 			args->ar_debug = 1;
-
-		else if (!strcmp(o, "nodebug"))
+			break;
+		case Opt_nodebug:
 			args->ar_debug = 0;
-
-		else if (!strcmp(o, "upgrade")) {
+			break;
+		case Opt_upgrade:
 			if (remount && !args->ar_upgrade)
 				goto cant_remount;
 			args->ar_upgrade = 1;
-		}
+			break;
+		case Opt_num_glockd:
+			if ((error = match_int(&tmp[0], &option))) {
+				fs_info(sdp, "problem getting num_glockd\n");
+				goto out_error;
+			}
 
-		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)
+			if (remount && option != args->ar_num_glockd)
 				goto cant_remount;
-			if (!x || x > GFS2_GLOCKD_MAX) {
+			if (!option || option > GFS2_GLOCKD_MAX) {
 				fs_info(sdp, "0 < num_glockd <= %u  (not %u)\n",
-				        GFS2_GLOCKD_MAX, x);
+				        GFS2_GLOCKD_MAX, option);
 				error = -EINVAL;
-				break;
+				goto out_error;
 			}
-			args->ar_num_glockd = x;
-		}
-
-		else if (!strcmp(o, "acl")) {
+			args->ar_num_glockd = option;
+			break;
+		case Opt_acl:
 			args->ar_posix_acl = 1;
 			sdp->sd_vfs->s_flags |= MS_POSIXACL;
-		}
-
-		else if (!strcmp(o, "noacl")) {
+			break;
+		case Opt_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"))
+			break;
+		case Opt_quota_off:
+			args->ar_quota = GFS2_QUOTA_OFF;
+			break;
+		case Opt_quota_account:
+			args->ar_quota = GFS2_QUOTA_ACCOUNT;
+			break;
+		case Opt_quota_on:
+			args->ar_quota = GFS2_QUOTA_ON;
+			break;
+		case Opt_suiddir:
 			args->ar_suiddir = 1;
-
-		else if (!strcmp(o, "nosuiddir"))
+			break;
+		case Opt_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 {
+			break;
+		case Opt_data_writeback:
+			args->ar_data = GFS2_DATA_WRITEBACK;
+			break;
+		case Opt_data_ordered:
+			args->ar_data = GFS2_DATA_ORDERED;
+			break;
+		default:
 			fs_info(sdp, "unknown option: %s\n", o);
 			error = -EINVAL;
-			break;
+			goto out_error;
 		}
 	}
 
+out_error:
 	if (error)
 		fs_info(sdp, "invalid mount option(s)\n");
 
@@ -202,10 +253,6 @@ int gfs2_mount_args(struct gfs2_sbd *sdp
 
 	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/ops_address.c b/fs/gfs2/ops_address.c
index b3b7e84..30c1562 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -197,7 +197,19 @@ static int stuffed_readpage(struct gfs2_
 	void *kaddr;
 	int error;
 
-	BUG_ON(page->index);
+	/*
+	 * Due to the order of unstuffing files and ->nopage(), we can be
+	 * asked for a zero page in the case of a stuffed file being extended,
+	 * so we need to supply one here. It doesn't happen often.
+	 */
+	if (unlikely(page->index)) {
+		kaddr = kmap_atomic(page, KM_USER0);
+		memset(kaddr, 0, PAGE_CACHE_SIZE);
+		kunmap_atomic(kaddr, KM_USER0);
+		flush_dcache_page(page);
+		SetPageUptodate(page);
+		return 0;
+	}
 
 	error = gfs2_meta_inode_buffer(ip, &dibh);
 	if (error)
@@ -208,9 +220,8 @@ static int stuffed_readpage(struct gfs2_
 	       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);
-
+	flush_dcache_page(page);
 	brelse(dibh);
-
 	SetPageUptodate(page);
 
 	return 0;
@@ -507,7 +518,9 @@ static int gfs2_commit_write(struct file
 		gfs2_quota_unlock(ip);
 		gfs2_alloc_put(ip);
 	}
+	unlock_page(page);
 	gfs2_glock_dq_m(1, &ip->i_gh);
+	lock_page(page);
 	gfs2_holder_uninit(&ip->i_gh);
 	return 0;
 
@@ -520,7 +533,9 @@ fail_endtrans:
 		gfs2_quota_unlock(ip);
 		gfs2_alloc_put(ip);
 	}
+	unlock_page(page);
 	gfs2_glock_dq_m(1, &ip->i_gh);
+	lock_page(page);
 	gfs2_holder_uninit(&ip->i_gh);
 fail_nounlock:
 	ClearPageUptodate(page);
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
index c6bac6b..a6fdc52 100644
--- a/fs/gfs2/ops_dentry.c
+++ b/fs/gfs2/ops_dentry.c
@@ -11,7 +11,6 @@ #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>
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index b50180e..064df88 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -15,7 +15,6 @@ #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>
@@ -513,18 +512,18 @@ static int gfs2_lock(struct file *file, 
 
 	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));
+			posix_test_lock(file, fl);
 			return 0;
 		} else {
 			return posix_lock_file_wait(file, fl);
 		}
 	}
 
+	if (cmd == F_CANCELLK) {
+		/* Hack: */
+		cmd = F_SETLK;
+		fl->fl_type = F_UNLCK;
+	}
 	if (IS_GETLK(cmd))
 		return gfs2_lm_plock_get(sdp, &name, file, fl);
 	else if (fl->fl_type == F_UNLCK)
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index ee54cb6..2c5f8e7 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -690,6 +690,8 @@ static int fill_super(struct super_block
 	if (error)
 		goto fail;
 
+	gfs2_create_debugfs_file(sdp);
+
 	error = gfs2_sys_fs_add(sdp);
 	if (error)
 		goto fail;
@@ -754,6 +756,7 @@ fail_lm:
 fail_sys:
 	gfs2_sys_fs_del(sdp);
 fail:
+	gfs2_delete_debugfs_file(sdp);
 	kfree(sdp);
 	sb->s_fs_info = NULL;
 	return error;
@@ -896,6 +899,7 @@ error:
 
 static void gfs2_kill_sb(struct super_block *sb)
 {
+	gfs2_delete_debugfs_file(sb->s_fs_info);
 	kill_block_super(sb);
 }
 
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index b89999d..485ce3d 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -284,6 +284,31 @@ static int gfs2_remount_fs(struct super_
 }
 
 /**
+ * gfs2_drop_inode - Drop an inode (test for remote unlink)
+ * @inode: The inode to drop
+ *
+ * If we've received a callback on an iopen lock then its because a
+ * remote node tried to deallocate the inode but failed due to this node
+ * still having the inode open. Here we mark the link count zero
+ * since we know that it must have reached zero if the GLF_DEMOTE flag
+ * is set on the iopen glock. If we didn't do a disk read since the
+ * remote node removed the final link then we might otherwise miss
+ * this event. This check ensures that this node will deallocate the
+ * inode's blocks, or alternatively pass the baton on to another
+ * node for later deallocation.
+ */
+static void gfs2_drop_inode(struct inode *inode)
+{
+	if (inode->i_private && inode->i_nlink) {
+		struct gfs2_inode *ip = GFS2_I(inode);
+		struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
+		if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
+			clear_nlink(inode);
+	}
+	generic_drop_inode(inode);
+}
+
+/**
  * gfs2_clear_inode - Deallocate an inode when VFS is done with it
  * @inode: The VFS inode
  *
@@ -441,7 +466,7 @@ out_unlock:
 out_uninit:
 	gfs2_holder_uninit(&ip->i_iopen_gh);
 	gfs2_glock_dq_uninit(&gh);
-	if (error)
+	if (error && error != GLR_TRYFAILED)
 		fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
 out:
 	truncate_inode_pages(&inode->i_data, 0);
@@ -481,6 +506,7 @@ const struct super_operations gfs2_super
 	.statfs			= gfs2_statfs,
 	.remount_fs		= gfs2_remount_fs,
 	.clear_inode		= gfs2_clear_inode,
+	.drop_inode		= gfs2_drop_inode,
 	.show_options		= gfs2_show_options,
 };
 
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 8d9c08b..1727f50 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -27,6 +27,7 @@ #include "super.h"
 #include "trans.h"
 #include "ops_file.h"
 #include "util.h"
+#include "log.h"
 
 #define BFITNOENT ((u32)~0)
 
@@ -697,8 +698,6 @@ struct gfs2_alloc *gfs2_alloc_get(struct
  * @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)
@@ -709,6 +708,9 @@ static int try_rgrp_fit(struct gfs2_rgrp
 	struct gfs2_sbd *sdp = rgd->rd_sbd;
 	int ret = 0;
 
+	if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC)
+		return 0;
+
 	spin_lock(&sdp->sd_rindex_spin);
 	if (rgd->rd_free_clone >= al->al_requested) {
 		al->al_rgd = rgd;
@@ -941,9 +943,13 @@ static int get_local_rgrp(struct gfs2_in
 			rgd = gfs2_rgrpd_get_first(sdp);
 
 		if (rgd == begin) {
-			if (++loops >= 2 || !skipped)
+			if (++loops >= 3)
 				return -ENOSPC;
+			if (!skipped)
+				loops++;
 			flags = 0;
+			if (loops == 2)
+				gfs2_log_flush(sdp, NULL);
 		}
 	}
 
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index d01f9f0..c26c21b 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = {
 };
 
 static struct kset gfs2_kset = {
-	.subsys = &fs_subsys,
 	.kobj   = {.name = "gfs2"},
 	.ktype  = &gfs2_ktype,
 };
@@ -554,6 +553,7 @@ int gfs2_sys_init(void)
 {
 	gfs2_sys_margs = NULL;
 	spin_lock_init(&gfs2_sys_margs_lock);
+	kobj_set_kset_s(&gfs2_kset, fs_subsys);
 	return kset_register(&gfs2_kset);
 }
 
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 5fd0ed7..8a3a650 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/pagemap.h>
+#include <linux/log2.h>
 
 #include "btree.h"
 
@@ -76,7 +77,7 @@ struct hfs_btree *hfs_btree_open(struct 
 	tree->depth = be16_to_cpu(head->depth);
 
 	size = tree->node_size;
-	if (!size || size & (size - 1))
+	if (!is_power_of_2(size))
 		goto fail_page;
 	if (!tree->node_count)
 		goto fail_page;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 623f509..4f1888f 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -434,7 +434,7 @@ static void hfs_init_once(void *p, struc
 {
 	struct hfs_inode_info *i = p;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&i->vfs_inode);
 }
 
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index a9b9e87..90ebab7 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -10,6 +10,7 @@
 
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/log2.h>
 
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
@@ -69,7 +70,7 @@ struct hfs_btree *hfs_btree_open(struct 
 	}
 
 	size = tree->node_size;
-	if (!size || size & (size - 1))
+	if (!is_power_of_2(size))
 		goto fail_page;
 	if (!tree->node_count)
 		goto fail_page;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 1a97f92..37afbec 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -470,7 +470,7 @@ static void hfsplus_init_once(void *p, s
 {
 	struct hfsplus_inode_info *i = p;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&i->vfs_inode);
 }
 
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 70543b1..06e5930 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -55,7 +55,7 @@ extern int stat_file(const char *path, u
 		     int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
 		     unsigned long long *size_out, struct timespec *atime_out,
 		     struct timespec *mtime_out, struct timespec *ctime_out,
-		     int *blksize_out, unsigned long long *blocks_out);
+		     int *blksize_out, unsigned long long *blocks_out, int fd);
 extern int access_file(char *path, int r, int w, int x);
 extern int open_file(char *path, int r, int w, int append);
 extern int file_type(const char *path, int *maj, int *min);
@@ -71,7 +71,7 @@ extern int lseek_file(int fd, long long 
 extern int fsync_file(int fd, int datasync);
 extern int file_create(char *name, int ur, int uw, int ux, int gr,
 		       int gw, int gx, int or, int ow, int ox);
-extern int set_attr(const char *file, struct hostfs_iattr *attrs);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd);
 extern int make_symlink(const char *from, const char *to);
 extern int unlink_file(const char *file);
 extern int do_mkdir(const char *file, int mode);
@@ -87,14 +87,3 @@ extern int do_statfs(char *root, long *b
 		     long *spare_out);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index fd301a9..8286491 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  *
  * Ported the filesystem routines to 2.5.
@@ -31,14 +31,14 @@ struct hostfs_inode_info {
 
 static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
 {
-	return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
+	return list_entry(inode, struct hostfs_inode_info, vfs_inode);
 }
 
 #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
 
 int hostfs_d_delete(struct dentry *dentry)
 {
-	return(1);
+	return 1;
 }
 
 struct dentry_operations hostfs_dentry_ops = {
@@ -79,7 +79,7 @@ static int __init hostfs_args(char *opti
 		}
 		options = ptr;
 	}
-	return(0);
+	return 0;
 }
 
 __uml_setup("hostfs=", hostfs_args,
@@ -110,7 +110,8 @@ static char *dentry_name(struct dentry *
 	root = HOSTFS_I(parent->d_inode)->host_filename;
 	len += strlen(root);
 	name = kmalloc(len + extra + 1, GFP_KERNEL);
-	if(name == NULL) return(NULL);
+	if(name == NULL)
+		return NULL;
 
 	name[len] = '\0';
 	parent = dentry;
@@ -122,7 +123,7 @@ static char *dentry_name(struct dentry *
 		parent = parent->d_parent;
 	}
 	strncpy(name, root, strlen(root));
-	return(name);
+	return name;
 }
 
 static char *inode_name(struct inode *ino, int extra)
@@ -130,7 +131,7 @@ static char *inode_name(struct inode *in
 	struct dentry *dentry;
 
 	dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
-	return(dentry_name(dentry, extra));
+	return dentry_name(dentry, extra);
 }
 
 static int read_name(struct inode *ino, char *name)
@@ -147,16 +148,16 @@ static int read_name(struct inode *ino, 
 
 	err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
 			&ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
-			&ino->i_ctime, &i_blksize, &i_blocks);
+			&ino->i_ctime, &i_blksize, &i_blocks, -1);
 	if(err)
-		return(err);
+		return err;
 
 	ino->i_ino = i_ino;
 	ino->i_mode = i_mode;
 	ino->i_nlink = i_nlink;
 	ino->i_size = i_size;
 	ino->i_blocks = i_blocks;
-	return(0);
+	return 0;
 }
 
 static char *follow_link(char *link)
@@ -181,11 +182,11 @@ static char *follow_link(char *link)
 		goto out_free;
 
 	if(*name == '/')
-		return(name);
+		return name;
 
 	end = strrchr(link, '/');
 	if(end == NULL)
-		return(name);
+		return name;
 
 	*(end + 1) = '\0';
 	len = strlen(link) + strlen(name) + 1;
@@ -199,12 +200,12 @@ static char *follow_link(char *link)
 	sprintf(resolved, "%s%s", link, name);
 	kfree(name);
 	kfree(link);
-	return(resolved);
+	return resolved;
 
  out_free:
 	kfree(name);
  out:
-	return(ERR_PTR(n));
+	return ERR_PTR(n);
 }
 
 static int read_inode(struct inode *ino)
@@ -234,7 +235,7 @@ static int read_inode(struct inode *ino)
 	err = read_name(ino, name);
 	kfree(name);
  out:
-	return(err);
+	return err;
 }
 
 int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
@@ -254,14 +255,15 @@ int hostfs_statfs(struct dentry *dentry,
 			&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
 			&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
 			&sf->f_namelen, sf->f_spare);
-	if(err) return(err);
+	if(err)
+		return err;
 	sf->f_blocks = f_blocks;
 	sf->f_bfree = f_bfree;
 	sf->f_bavail = f_bavail;
 	sf->f_files = f_files;
 	sf->f_ffree = f_ffree;
 	sf->f_type = HOSTFS_SUPER_MAGIC;
-	return(0);
+	return 0;
 }
 
 static struct inode *hostfs_alloc_inode(struct super_block *sb)
@@ -270,13 +272,13 @@ static struct inode *hostfs_alloc_inode(
 
 	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
 	if(hi == NULL)
-		return(NULL);
+		return NULL;
 
 	*hi = ((struct hostfs_inode_info) { .host_filename	= NULL,
 					    .fd			= -1,
 					    .mode		= 0 });
 	inode_init_once(&hi->vfs_inode);
-	return(&hi->vfs_inode);
+	return &hi->vfs_inode;
 }
 
 static void hostfs_delete_inode(struct inode *inode)
@@ -325,10 +327,12 @@ int hostfs_readdir(struct file *file, vo
 	int error, len;
 
 	name = dentry_name(file->f_path.dentry, 0);
-	if(name == NULL) return(-ENOMEM);
+	if(name == NULL)
+		return -ENOMEM;
 	dir = open_dir(name, &error);
 	kfree(name);
-	if(dir == NULL) return(-error);
+	if(dir == NULL)
+		return -error;
 	next = file->f_pos;
 	while((name = read_dir(dir, &next, &ino, &len)) != NULL){
 		error = (*filldir)(ent, name, len, file->f_pos,
@@ -337,7 +341,7 @@ int hostfs_readdir(struct file *file, vo
 		file->f_pos = next;
 	}
 	close_dir(dir);
-	return(0);
+	return 0;
 }
 
 int hostfs_file_open(struct inode *ino, struct file *file)
@@ -347,7 +351,7 @@ int hostfs_file_open(struct inode *ino, 
 
 	mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
 	if((mode & HOSTFS_I(ino)->mode) == mode)
-		return(0);
+		return 0;
 
 	/* The file may already have been opened, but with the wrong access,
 	 * so this resets things and reopens the file with the new access.
@@ -367,14 +371,15 @@ int hostfs_file_open(struct inode *ino, 
 
 	name = dentry_name(file->f_path.dentry, 0);
 	if(name == NULL)
-		return(-ENOMEM);
+		return -ENOMEM;
 
 	fd = open_file(name, r, w, append);
 	kfree(name);
-	if(fd < 0) return(fd);
+	if(fd < 0)
+		return fd;
 	FILE_HOSTFS_I(file)->fd = fd;
 
-	return(0);
+	return 0;
 }
 
 int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -458,7 +463,7 @@ int hostfs_readpage(struct file *file, s
  out:
 	kunmap(page);
 	unlock_page(page);
-	return(err);
+	return err;
 }
 
 int hostfs_prepare_write(struct file *file, struct page *page,
@@ -485,7 +490,7 @@ int hostfs_prepare_write(struct file *fi
 	err = 0;
  out:
 	kunmap(page);
-	return(err);
+	return err;
 }
 
 int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
@@ -511,7 +516,7 @@ int hostfs_commit_write(struct file *fil
 		inode->i_size = start;
 
 	kunmap(page);
-	return(err);
+	return err;
 }
 
 static const struct address_space_operations hostfs_aops = {
@@ -569,7 +574,7 @@ static int init_inode(struct inode *inod
 		break;
 	}
  out:
-	return(err);
+	return err;
 }
 
 int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
@@ -607,16 +612,16 @@ int hostfs_create(struct inode *dir, str
 	HOSTFS_I(inode)->fd = fd;
 	HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
 	d_instantiate(dentry, inode);
-	return(0);
+	return 0;
 
  out_put:
 	iput(inode);
  out:
-	return(error);
+	return error;
 }
 
 struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
-                            struct nameidata *nd)
+			     struct nameidata *nd)
 {
 	struct inode *inode;
 	char *name;
@@ -647,44 +652,45 @@ struct dentry *hostfs_lookup(struct inod
 
 	d_add(dentry, inode);
 	dentry->d_op = &hostfs_dentry_ops;
-	return(NULL);
+	return NULL;
 
  out_put:
 	iput(inode);
  out:
-	return(ERR_PTR(err));
+	return ERR_PTR(err);
 }
 
 static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
 {
-        char *file;
+	char *file;
 	int len;
 
 	file = inode_name(ino, dentry->d_name.len + 1);
-	if(file == NULL) return(NULL);
-        strcat(file, "/");
+	if(file == NULL)
+		return NULL;
+	strcat(file, "/");
 	len = strlen(file);
-        strncat(file, dentry->d_name.name, dentry->d_name.len);
+	strncat(file, dentry->d_name.name, dentry->d_name.len);
 	file[len + dentry->d_name.len] = '\0';
-        return(file);
+	return file;
 }
 
 int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
 {
-        char *from_name, *to_name;
-        int err;
+	char *from_name, *to_name;
+	int err;
 
-        if((from_name = inode_dentry_name(ino, from)) == NULL)
-                return(-ENOMEM);
-        to_name = dentry_name(to, 0);
+	if((from_name = inode_dentry_name(ino, from)) == NULL)
+		return -ENOMEM;
+	to_name = dentry_name(to, 0);
 	if(to_name == NULL){
 		kfree(from_name);
-		return(-ENOMEM);
+		return -ENOMEM;
 	}
-        err = link_file(to_name, from_name);
-        kfree(from_name);
-        kfree(to_name);
-        return(err);
+	err = link_file(to_name, from_name);
+	kfree(from_name);
+	kfree(to_name);
+	return err;
 }
 
 int hostfs_unlink(struct inode *ino, struct dentry *dentry)
@@ -692,13 +698,14 @@ int hostfs_unlink(struct inode *ino, str
 	char *file;
 	int err;
 
-	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	if((file = inode_dentry_name(ino, dentry)) == NULL)
+		return -ENOMEM;
 	if(append)
-		return(-EPERM);
+		return -EPERM;
 
 	err = unlink_file(file);
 	kfree(file);
-	return(err);
+	return err;
 }
 
 int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
@@ -706,10 +713,11 @@ int hostfs_symlink(struct inode *ino, st
 	char *file;
 	int err;
 
-	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	if((file = inode_dentry_name(ino, dentry)) == NULL)
+		return -ENOMEM;
 	err = make_symlink(file, to);
 	kfree(file);
-	return(err);
+	return err;
 }
 
 int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
@@ -717,10 +725,11 @@ int hostfs_mkdir(struct inode *ino, stru
 	char *file;
 	int err;
 
-	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	if((file = inode_dentry_name(ino, dentry)) == NULL)
+		return -ENOMEM;
 	err = do_mkdir(file, mode);
 	kfree(file);
-	return(err);
+	return err;
 }
 
 int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
@@ -728,10 +737,11 @@ int hostfs_rmdir(struct inode *ino, stru
 	char *file;
 	int err;
 
-	if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+	if((file = inode_dentry_name(ino, dentry)) == NULL)
+		return -ENOMEM;
 	err = do_rmdir(file);
 	kfree(file);
-	return(err);
+	return err;
 }
 
 int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -764,14 +774,14 @@ int hostfs_mknod(struct inode *dir, stru
 		goto out_put;
 
 	d_instantiate(dentry, inode);
-	return(0);
+	return 0;
 
  out_free:
 	kfree(name);
  out_put:
 	iput(inode);
  out:
-	return(err);
+	return err;
 }
 
 int hostfs_rename(struct inode *from_ino, struct dentry *from,
@@ -781,15 +791,15 @@ int hostfs_rename(struct inode *from_ino
 	int err;
 
 	if((from_name = inode_dentry_name(from_ino, from)) == NULL)
-		return(-ENOMEM);
+		return -ENOMEM;
 	if((to_name = inode_dentry_name(to_ino, to)) == NULL){
 		kfree(from_name);
-		return(-ENOMEM);
+		return -ENOMEM;
 	}
 	err = rename_file(from_name, to_name);
 	kfree(from_name);
 	kfree(to_name);
-	return(err);
+	return err;
 }
 
 int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
@@ -801,7 +811,8 @@ int hostfs_permission(struct inode *ino,
 	if (desired & MAY_WRITE) w = 1;
 	if (desired & MAY_EXEC) x = 1;
 	name = inode_name(ino, 0);
-	if (name == NULL) return(-ENOMEM);
+	if (name == NULL)
+		return -ENOMEM;
 
 	if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
 			S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
@@ -820,6 +831,8 @@ int hostfs_setattr(struct dentry *dentry
 	char *name;
 	int err;
 
+	int fd = HOSTFS_I(dentry->d_inode)->fd;
+
 	err = inode_change_ok(dentry->d_inode, attr);
 	if (err)
 		return err;
@@ -863,20 +876,21 @@ int hostfs_setattr(struct dentry *dentry
 		attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
 	}
 	name = dentry_name(dentry, 0);
-	if(name == NULL) return(-ENOMEM);
-	err = set_attr(name, &attrs);
+	if(name == NULL)
+		return -ENOMEM;
+	err = set_attr(name, &attrs, fd);
 	kfree(name);
 	if(err)
-		return(err);
+		return err;
 
-	return(inode_setattr(dentry->d_inode, attr));
+	return inode_setattr(dentry->d_inode, attr);
 }
 
 int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 	   struct kstat *stat)
 {
 	generic_fillattr(dentry->d_inode, stat);
-	return(0);
+	return 0;
 }
 
 static const struct inode_operations hostfs_iops = {
@@ -915,7 +929,8 @@ int hostfs_link_readpage(struct file *fi
 
 	buffer = kmap(page);
 	name = inode_name(page->mapping->host, 0);
-	if(name == NULL) return(-ENOMEM);
+	if(name == NULL)
+		return -ENOMEM;
 	err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
 	kfree(name);
 	if(err == PAGE_CACHE_SIZE)
@@ -928,7 +943,7 @@ int hostfs_link_readpage(struct file *fi
 	}
 	kunmap(page);
 	unlock_page(page);
-	return(err);
+	return err;
 }
 
 static const struct address_space_operations hostfs_link_aops = {
@@ -978,20 +993,20 @@ static int hostfs_fill_sb_common(struct 
 
 	err = read_inode(root_inode);
 	if(err){
-                /* No iput in this case because the dput does that for us */
-                dput(sb->s_root);
-                sb->s_root = NULL;
+		/* No iput in this case because the dput does that for us */
+		dput(sb->s_root);
+		sb->s_root = NULL;
 		goto out;
-        }
+	}
 
-	return(0);
+	return 0;
 
- out_put:
-        iput(root_inode);
- out_free:
+out_put:
+	iput(root_inode);
+out_free:
 	kfree(host_root_path);
- out:
-	return(err);
+out:
+	return err;
 }
 
 static int hostfs_read_sb(struct file_system_type *type,
@@ -1011,7 +1026,7 @@ static struct file_system_type hostfs_ty
 
 static int __init init_hostfs(void)
 {
-	return(register_filesystem(&hostfs_type));
+	return register_filesystem(&hostfs_type);
 }
 
 static void __exit exit_hostfs(void)
@@ -1022,14 +1037,3 @@ static void __exit exit_hostfs(void)
 module_init(init_hostfs)
 module_exit(exit_hostfs)
 MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 1ed5ea3..5625e24 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
@@ -21,12 +21,16 @@ int stat_file(const char *path, unsigned
 	      int *nlink_out, int *uid_out, int *gid_out,
 	      unsigned long long *size_out, struct timespec *atime_out,
 	      struct timespec *mtime_out, struct timespec *ctime_out,
-	      int *blksize_out, unsigned long long *blocks_out)
+	      int *blksize_out, unsigned long long *blocks_out, int fd)
 {
 	struct stat64 buf;
 
-	if(lstat64(path, &buf) < 0)
-		return(-errno);
+	if(fd >= 0) {
+		if (fstat64(fd, &buf) < 0)
+			return -errno;
+	} else if(lstat64(path, &buf) < 0) {
+		return -errno;
+	}
 
 	if(inode_out != NULL) *inode_out = buf.st_ino;
 	if(mode_out != NULL) *mode_out = buf.st_mode;
@@ -48,7 +52,7 @@ int stat_file(const char *path, unsigned
 	}
 	if(blksize_out != NULL) *blksize_out = buf.st_blksize;
 	if(blocks_out != NULL) *blocks_out = buf.st_blocks;
-	return(0);
+	return 0;
 }
 
 int file_type(const char *path, int *maj, int *min)
@@ -56,7 +60,7 @@ int file_type(const char *path, int *maj
  	struct stat64 buf;
 
 	if(lstat64(path, &buf) < 0)
-		return(-errno);
+		return -errno;
 	/*We cannot pass rdev as is because glibc and the kernel disagree
 	 *about its definition.*/
 	if(maj != NULL)
@@ -64,13 +68,13 @@ int file_type(const char *path, int *maj
 	if(min != NULL)
 		*min = minor(buf.st_rdev);
 
-	if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
-	else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
-	else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
-	else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
-	else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
-	else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
-	else return(OS_TYPE_FILE);
+	if(S_ISDIR(buf.st_mode)) return OS_TYPE_DIR;
+	else if(S_ISLNK(buf.st_mode)) return OS_TYPE_SYMLINK;
+	else if(S_ISCHR(buf.st_mode)) return OS_TYPE_CHARDEV;
+	else if(S_ISBLK(buf.st_mode)) return OS_TYPE_BLOCKDEV;
+	else if(S_ISFIFO(buf.st_mode))return OS_TYPE_FIFO;
+	else if(S_ISSOCK(buf.st_mode))return OS_TYPE_SOCK;
+	else return OS_TYPE_FILE;
 }
 
 int access_file(char *path, int r, int w, int x)
@@ -80,8 +84,9 @@ int access_file(char *path, int r, int w
 	if(r) mode = R_OK;
 	if(w) mode |= W_OK;
 	if(x) mode |= X_OK;
-	if(access(path, mode) != 0) return(-errno);
-	else return(0);
+	if(access(path, mode) != 0)
+		return -errno;
+	else return 0;
 }
 
 int open_file(char *path, int r, int w, int append)
@@ -99,8 +104,9 @@ int open_file(char *path, int r, int w, 
 	if(append)
 		mode |= O_APPEND;
 	fd = open64(path, mode);
-	if(fd < 0) return(-errno);
-	else return(fd);
+	if(fd < 0)
+		return -errno;
+	else return fd;
 }
 
 void *open_dir(char *path, int *err_out)
@@ -109,8 +115,9 @@ void *open_dir(char *path, int *err_out)
 
 	dir = opendir(path);
 	*err_out = errno;
-	if(dir == NULL) return(NULL);
-	return(dir);
+	if(dir == NULL)
+		return NULL;
+	return dir;
 }
 
 char *read_dir(void *stream, unsigned long long *pos,
@@ -121,11 +128,12 @@ char *read_dir(void *stream, unsigned lo
 
 	seekdir(dir, *pos);
 	ent = readdir(dir);
-	if(ent == NULL) return(NULL);
+	if(ent == NULL)
+		return NULL;
 	*len_out = strlen(ent->d_name);
 	*ino_out = ent->d_ino;
 	*pos = telldir(dir);
-	return(ent->d_name);
+	return ent->d_name;
 }
 
 int read_file(int fd, unsigned long long *offset, char *buf, int len)
@@ -133,9 +141,10 @@ int read_file(int fd, unsigned long long
 	int n;
 
 	n = pread64(fd, buf, len, *offset);
-	if(n < 0) return(-errno);
+	if(n < 0)
+		return -errno;
 	*offset += n;
-	return(n);
+	return n;
 }
 
 int write_file(int fd, unsigned long long *offset, const char *buf, int len)
@@ -143,9 +152,10 @@ int write_file(int fd, unsigned long lon
 	int n;
 
 	n = pwrite64(fd, buf, len, *offset);
-	if(n < 0) return(-errno);
+	if(n < 0)
+		return -errno;
 	*offset += n;
-	return(n);
+	return n;
 }
 
 int lseek_file(int fd, long long offset, int whence)
@@ -154,8 +164,8 @@ int lseek_file(int fd, long long offset,
 
 	ret = lseek64(fd, offset, whence);
 	if(ret < 0)
-		return(-errno);
-	return(0);
+		return -errno;
+	return 0;
 }
 
 int fsync_file(int fd, int datasync)
@@ -198,65 +208,90 @@ int file_create(char *name, int ur, int 
 	mode |= ox ? S_IXOTH : 0;
 	fd = open64(name, O_CREAT | O_RDWR, mode);
 	if(fd < 0)
-		return(-errno);
-	return(fd);
+		return -errno;
+	return fd;
 }
 
-int set_attr(const char *file, struct hostfs_iattr *attrs)
+int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
 {
-	struct utimbuf buf;
+	struct timeval times[2];
+	struct timespec atime_ts, mtime_ts;
 	int err, ma;
 
-	if(attrs->ia_valid & HOSTFS_ATTR_MODE){
-		if(chmod(file, attrs->ia_mode) != 0) return(-errno);
-	}
-	if(attrs->ia_valid & HOSTFS_ATTR_UID){
-		if(chown(file, attrs->ia_uid, -1)) return(-errno);
+	if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
+		if (fd >= 0) {
+			if (fchmod(fd, attrs->ia_mode) != 0)
+				return (-errno);
+		} else if (chmod(file, attrs->ia_mode) != 0) {
+			return -errno;
+		}
 	}
-	if(attrs->ia_valid & HOSTFS_ATTR_GID){
-		if(chown(file, -1, attrs->ia_gid)) return(-errno);
+	if (attrs->ia_valid & HOSTFS_ATTR_UID) {
+		if (fd >= 0) {
+			if (fchown(fd, attrs->ia_uid, -1))
+				return -errno;
+		} else if(chown(file, attrs->ia_uid, -1)) {
+			return -errno;
+		}
 	}
-	if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
-		if(truncate(file, attrs->ia_size)) return(-errno);
+	if (attrs->ia_valid & HOSTFS_ATTR_GID) {
+		if (fd >= 0) {
+			if (fchown(fd, -1, attrs->ia_gid))
+				return -errno;
+		} else if (chown(file, -1, attrs->ia_gid)) {
+			return -errno;
+		}
 	}
-	ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
-	if((attrs->ia_valid & ma) == ma){
-		buf.actime = attrs->ia_atime.tv_sec;
-		buf.modtime = attrs->ia_mtime.tv_sec;
-		if(utime(file, &buf) != 0) return(-errno);
+	if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
+		if (fd >= 0) {
+			if (ftruncate(fd, attrs->ia_size))
+				return -errno;
+		} else if (truncate(file, attrs->ia_size)) {
+			return -errno;
+		}
 	}
-	else {
-		struct timespec ts;
-
-		if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
-			err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
-					NULL, NULL, &ts, NULL, NULL, NULL);
-			if(err != 0)
-				return(err);
-			buf.actime = attrs->ia_atime.tv_sec;
-			buf.modtime = ts.tv_sec;
-			if(utime(file, &buf) != 0)
-				return(-errno);
+
+	/* Update accessed and/or modified time, in two parts: first set
+	 * times according to the changes to perform, and then call futimes()
+	 * or utimes() to apply them. */
+	ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
+	if (attrs->ia_valid & ma) {
+		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
+				&atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
+		if (err != 0)
+			return err;
+
+		times[0].tv_sec = atime_ts.tv_sec;
+		times[0].tv_usec = atime_ts.tv_nsec * 1000;
+		times[1].tv_sec = mtime_ts.tv_sec;
+		times[1].tv_usec = mtime_ts.tv_nsec * 1000;
+
+		if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
+			times[0].tv_sec = attrs->ia_atime.tv_sec;
+			times[0].tv_usec = attrs->ia_atime.tv_nsec * 1000;
+		}
+		if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
+			times[1].tv_sec = attrs->ia_mtime.tv_sec;
+			times[1].tv_usec = attrs->ia_mtime.tv_nsec * 1000;
 		}
-		if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
-			err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
-					NULL, &ts, NULL, NULL, NULL, NULL);
-			if(err != 0)
-				return(err);
-			buf.actime = ts.tv_sec;
-			buf.modtime = attrs->ia_mtime.tv_sec;
-			if(utime(file, &buf) != 0)
-				return(-errno);
+
+		if (fd >= 0) {
+			if (futimes(fd, times) != 0)
+				return -errno;
+		} else if (utimes(file, times) != 0) {
+			return -errno;
 		}
 	}
+
 	if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
 	if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
 		err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
 				&attrs->ia_atime, &attrs->ia_mtime, NULL,
-				NULL, NULL);
-		if(err != 0) return(err);
+				NULL, NULL, fd);
+		if(err != 0)
+			return err;
 	}
-	return(0);
+	return 0;
 }
 
 int make_symlink(const char *from, const char *to)
@@ -264,8 +299,9 @@ int make_symlink(const char *from, const
 	int err;
 
 	err = symlink(to, from);
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int unlink_file(const char *file)
@@ -273,8 +309,9 @@ int unlink_file(const char *file)
 	int err;
 
 	err = unlink(file);
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int do_mkdir(const char *file, int mode)
@@ -282,8 +319,9 @@ int do_mkdir(const char *file, int mode)
 	int err;
 
 	err = mkdir(file, mode);
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int do_rmdir(const char *file)
@@ -291,8 +329,9 @@ int do_rmdir(const char *file)
 	int err;
 
 	err = rmdir(file);
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
@@ -300,8 +339,9 @@ int do_mknod(const char *file, int mode,
 	int err;
 
 	err = mknod(file, mode, makedev(major, minor));
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int link_file(const char *to, const char *from)
@@ -309,8 +349,9 @@ int link_file(const char *to, const char
 	int err;
 
 	err = link(to, from);
-	if(err) return(-errno);
-	return(0);
+	if(err)
+		return -errno;
+	return 0;
 }
 
 int do_readlink(char *file, char *buf, int size)
@@ -319,10 +360,10 @@ int do_readlink(char *file, char *buf, i
 
 	n = readlink(file, buf, size);
 	if(n < 0)
-		return(-errno);
+		return -errno;
 	if(n < size)
 		buf[n] = '\0';
-	return(n);
+	return n;
 }
 
 int rename_file(char *from, char *to)
@@ -330,8 +371,9 @@ int rename_file(char *from, char *to)
 	int err;
 
 	err = rename(from, to);
-	if(err < 0) return(-errno);
-	return(0);
+	if(err < 0)
+		return -errno;
+	return 0;
 }
 
 int do_statfs(char *root, long *bsize_out, long long *blocks_out,
@@ -344,7 +386,9 @@ int do_statfs(char *root, long *bsize_ou
 	int err;
 
 	err = statfs64(root, &buf);
-	if(err < 0) return(-errno);
+	if(err < 0)
+		return -errno;
+
 	*bsize_out = buf.f_bsize;
 	*blocks_out = buf.f_blocks;
 	*bfree_out = buf.f_bfree;
@@ -360,16 +404,5 @@ int do_statfs(char *root, long *bsize_ou
 	spare_out[2] = buf.f_spare[2];
 	spare_out[3] = buf.f_spare[3];
 	spare_out[4] = buf.f_spare[4];
-	return(0);
+	return 0;
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index e0174e3..1b95f39 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -176,8 +176,7 @@ static void init_once(void * foo, struct
 {
 	struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		mutex_init(&ei->i_mutex);
 		mutex_init(&ei->i_parent_mutex);
 		inode_init_once(&ei->vfs_inode);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 8c718a3..98959b8 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -22,6 +22,7 @@ #include <linux/capability.h>
 #include <linux/backing-dev.h>
 #include <linux/hugetlb.h>
 #include <linux/pagevec.h>
+#include <linux/mman.h>
 #include <linux/quotaops.h>
 #include <linux/slab.h>
 #include <linux/dnotify.h>
@@ -98,10 +99,7 @@ out:
  * Called under down_write(mmap_sem).
  */
 
-#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
-		unsigned long len, unsigned long pgoff, unsigned long flags);
-#else
+#ifndef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 static unsigned long
 hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 		unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -115,6 +113,12 @@ hugetlb_get_unmapped_area(struct file *f
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED) {
+		if (prepare_hugepage_range(addr, len, pgoff))
+			return -EINVAL;
+		return addr;
+	}
+
 	if (addr) {
 		addr = ALIGN(addr, HPAGE_SIZE);
 		vma = find_vma(mm, addr);
@@ -453,7 +457,7 @@ static int hugetlbfs_symlink(struct inod
  */
 static int hugetlbfs_set_page_dirty(struct page *page)
 {
-	struct page *head = (struct page *)page_private(page);
+	struct page *head = compound_head(page);
 
 	SetPageDirty(head);
 	return 0;
@@ -552,8 +556,7 @@ static void init_once(void *foo, struct 
 {
 	struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
 
@@ -744,6 +747,9 @@ struct file *hugetlb_zero_setup(size_t s
 	char buf[16];
 	static atomic_t counter;
 
+	if (!hugetlbfs_vfsmount)
+		return ERR_PTR(-ENOENT);
+
 	if (!can_do_hugetlb_shm())
 		return ERR_PTR(-EPERM);
 
diff --git a/fs/inode.c b/fs/inode.c
index 5abb097..df2ef15 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -213,8 +213,7 @@ static void init_once(void * foo, struct
 {
 	struct inode * inode = (struct inode *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(inode);
 }
 
@@ -251,7 +250,7 @@ void clear_inode(struct inode *inode)
 	BUG_ON(inode->i_state & I_CLEAR);
 	wait_on_inode(inode);
 	DQUOT_DROP(inode);
-	if (inode->i_sb && inode->i_sb->s_op->clear_inode)
+	if (inode->i_sb->s_op->clear_inode)
 		inode->i_sb->s_op->clear_inode(inode);
 	if (S_ISBLK(inode->i_mode) && inode->i_bdev)
 		bd_forget(inode);
@@ -276,7 +275,7 @@ static void dispose_list(struct list_hea
 	while (!list_empty(head)) {
 		struct inode *inode;
 
-		inode = list_entry(head->next, struct inode, i_list);
+		inode = list_first_entry(head, struct inode, i_list);
 		list_del(&inode->i_list);
 
 		if (inode->i_data.nrpages)
@@ -525,7 +524,12 @@ repeat:
  */
 struct inode *new_inode(struct super_block *sb)
 {
-	static unsigned long last_ino;
+	/*
+	 * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+	 * error if st_ino won't fit in target struct field. Use 32bit counter
+	 * here to attempt to avoid that.
+	 */
+	static unsigned int last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
@@ -684,27 +688,28 @@ static unsigned long hash(struct super_b
  */
 ino_t iunique(struct super_block *sb, ino_t max_reserved)
 {
-	static ino_t counter;
+	/*
+	 * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+	 * error if st_ino won't fit in target struct field. Use 32bit counter
+	 * here to attempt to avoid that.
+	 */
+	static unsigned int counter;
 	struct inode *inode;
-	struct hlist_head * head;
+	struct hlist_head *head;
 	ino_t res;
+
 	spin_lock(&inode_lock);
-retry:
-	if (counter > max_reserved) {
-		head = inode_hashtable + hash(sb,counter);
+	do {
+		if (counter <= max_reserved)
+			counter = max_reserved + 1;
 		res = counter++;
+		head = inode_hashtable + hash(sb, res);
 		inode = find_inode_fast(sb, head, res);
-		if (!inode) {
-			spin_unlock(&inode_lock);
-			return res;
-		}
-	} else {
-		counter = max_reserved + 1;
-	}
-	goto retry;
-	
-}
+	} while (inode != NULL);
+	spin_unlock(&inode_lock);
 
+	return res;
+}
 EXPORT_SYMBOL(iunique);
 
 struct inode *igrab(struct inode *inode)
@@ -1041,7 +1046,7 @@ static void generic_forget_inode(struct 
 		if (!(inode->i_state & (I_DIRTY|I_LOCK)))
 			list_move(&inode->i_list, &inode_unused);
 		inodes_stat.nr_unused++;
-		if (!sb || (sb->s_flags & MS_ACTIVE)) {
+		if (sb->s_flags & MS_ACTIVE) {
 			spin_unlock(&inode_lock);
 			return;
 		}
diff --git a/fs/inotify.c b/fs/inotify.c
index f5099d8..7457501 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -509,7 +509,7 @@ void inotify_destroy(struct inotify_hand
 			mutex_unlock(&ih->mutex);
 			break;
 		}
-		watch = list_entry(watches->next, struct inotify_watch, h_list);
+		watch = list_first_entry(watches, struct inotify_watch, h_list);
 		get_inotify_watch(watch);
 		mutex_unlock(&ih->mutex);
 
diff --git a/fs/internal.h b/fs/internal.h
index ea00126..392e8cc 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -9,8 +9,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/ioctl32.h>
-
 struct super_block;
 
 /*
@@ -42,14 +40,6 @@ #endif
 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/ioctl.c b/fs/ioctl.c
index ff61772..479c103 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -67,8 +67,6 @@ static int file_ioctl(struct file *filp,
 			return put_user(res, p);
 		}
 		case FIGETBSZ:
-			if (inode->i_sb == NULL)
-				return -EBADF;
 			return put_user(inode->i_sb->s_blocksize, p);
 		case FIONREAD:
 			return put_user(i_size_read(inode) - filp->f_pos, p);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 64a96cd..e99f7ff 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -77,8 +77,7 @@ static void init_once(void *foo, struct 
 {
 	struct iso_inode_info *ei = foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index be4648b..1facfaf 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -20,7 +20,6 @@ #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.
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 10fff94..46fe743 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -28,7 +28,6 @@ #include <linux/fs.h>
 #include <linux/jbd.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/freezer.h>
@@ -211,10 +210,16 @@ end_loop:
 	return 0;
 }
 
-static void journal_start_thread(journal_t *journal)
+static int journal_start_thread(journal_t *journal)
 {
-	kthread_run(kjournald, journal, "kjournald");
+	struct task_struct *t;
+
+	t = kthread_run(kjournald, journal, "kjournald");
+	if (IS_ERR(t))
+		return PTR_ERR(t);
+
 	wait_event(journal->j_wait_done_commit, journal->j_task != 0);
+	return 0;
 }
 
 static void journal_kill_thread(journal_t *journal)
@@ -840,8 +845,7 @@ static int journal_reset(journal_t *jour
 
 	/* Add the dynamic fields and write it to disk. */
 	journal_update_superblock(journal, 1);
-	journal_start_thread(journal);
-	return 0;
+	return journal_start_thread(journal);
 }
 
 /**
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index d204ab3..a68cbb6 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -66,7 +66,6 @@ #include <linux/jbd.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/list.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #endif
 
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index cceaf57..f9822fc 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -23,7 +23,6 @@ #include <linux/jbd.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>
 
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 6bd8005..2856e11 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -20,7 +20,6 @@ #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.
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 44fc32b..78d63b8 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -28,7 +28,6 @@ #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/freezer.h>
@@ -211,10 +210,16 @@ end_loop:
 	return 0;
 }
 
-static void jbd2_journal_start_thread(journal_t *journal)
+static int jbd2_journal_start_thread(journal_t *journal)
 {
-	kthread_run(kjournald2, journal, "kjournald2");
+	struct task_struct *t;
+
+	t = kthread_run(kjournald2, journal, "kjournald2");
+	if (IS_ERR(t))
+		return PTR_ERR(t);
+
 	wait_event(journal->j_wait_done_commit, journal->j_task != 0);
+	return 0;
 }
 
 static void journal_kill_thread(journal_t *journal)
@@ -840,8 +845,7 @@ static int journal_reset(journal_t *jour
 
 	/* Add the dynamic fields and write it to disk. */
 	jbd2_journal_update_superblock(journal, 1);
-	jbd2_journal_start_thread(journal);
-	return 0;
+	return jbd2_journal_start_thread(journal);
 }
 
 /**
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index f506646..1e864dc 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -66,7 +66,6 @@ #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
 
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 3a87001..e347d8c 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -23,7 +23,6 @@ #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>
 
diff --git a/fs/jffs2/LICENCE b/fs/jffs2/LICENCE
index cd81d83..5628859 100644
--- a/fs/jffs2/LICENCE
+++ b/fs/jffs2/LICENCE
@@ -1,7 +1,7 @@
 The files in this directory and elsewhere which refer to this LICENCE
 file are part of JFFS2, the Journalling Flash File System v2.
 
-	Copyright (C) 2001, 2002 Red Hat, Inc.
+	Copyright Â© 2001-2007 Red Hat, Inc. and others
 
 JFFS2 is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -28,8 +28,3 @@ of the GNU General Public License.
 This exception does not invalidate any other reasons why a work based on
 this file might be covered by the GNU General Public License.
 
-For information on obtaining alternative licences for JFFS2, see 
-http://sources.redhat.com/jffs2/jffs2-licence.html
-
-
-	$Id: LICENCE,v 1.1 2002/05/20 14:56:37 dwmw2 Exp $
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index 7f28ee0..c32b241 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,7 +1,6 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking
index c8f0bd6..d14d5a4 100644
--- a/fs/jffs2/README.Locking
+++ b/fs/jffs2/README.Locking
@@ -1,4 +1,3 @@
-	$Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
 
 	JFFS2 LOCKING DOCUMENTATION
 	---------------------------
diff --git a/fs/jffs2/TODO b/fs/jffs2/TODO
index d0e23b2..5d3ea40 100644
--- a/fs/jffs2/TODO
+++ b/fs/jffs2/TODO
@@ -1,4 +1,3 @@
-$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $
 
  - support asynchronous operation -- add a per-fs 'reserved_space' count,
    let each outstanding write reserve the _maximum_ amount of physical
@@ -30,8 +29,6 @@
      the full dirent, we only need to go to the flash in lookup() when we think we've
      got a match, and in readdir(). 
    - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
-   - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
-	jffs2_mark_node_obsolete(). Can all callers work it out?
    - Remove size from jffs2_raw_node_frag. 
 
 dedekind:
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 73f0d60..a46101e 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index fa327db..c84378c 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 struct jffs2_acl_entry {
 	jint16_t	e_tag;
 	jint16_t	e_perm;
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 888f236..0c82dfc 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 07119c4..0ca2fff 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index 7001ba2..485d065 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -1,16 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * Copyright Â© 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
  *                    University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $
- *
  */
 
 #include "compr.h"
@@ -268,144 +266,6 @@ int jffs2_unregister_compressor(struct j
         return 0;
 }
 
-#ifdef CONFIG_JFFS2_PROC
-
-#define JFFS2_STAT_BUF_SIZE 16000
-
-char *jffs2_list_compressors(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"disabled");
-                else
-                        act_buf += sprintf(act_buf,"enabled");
-                act_buf += sprintf(act_buf,"\n");
-        }
-        return buf;
-}
-
-char *jffs2_stats(void)
-{
-        struct jffs2_compressor *this;
-        char *buf, *act_buf;
-
-        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
-
-        act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
-        act_buf += sprintf(act_buf,"%10s   ","none");
-        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
-                           none_stat_compr_size, none_stat_decompr_blocks);
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                act_buf += sprintf(act_buf,"%10s ",this->name);
-                if ((this->disabled)||(!this->compress))
-                        act_buf += sprintf(act_buf,"- ");
-                else
-                        act_buf += sprintf(act_buf,"+ ");
-                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
-                                   this->stat_compr_new_size, this->stat_compr_orig_size,
-                                   this->stat_decompr_blocks);
-                act_buf += sprintf(act_buf,"\n");
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-
-        return buf;
-}
-
-char *jffs2_get_compression_mode_name(void)
-{
-        switch (jffs2_compression_mode) {
-        case JFFS2_COMPR_MODE_NONE:
-                return "none";
-        case JFFS2_COMPR_MODE_PRIORITY:
-                return "priority";
-        case JFFS2_COMPR_MODE_SIZE:
-                return "size";
-        }
-        return "unkown";
-}
-
-int jffs2_set_compression_mode_name(const char *name)
-{
-        if (!strcmp("none",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
-                return 0;
-        }
-        if (!strcmp("priority",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
-                return 0;
-        }
-        if (!strcmp("size",name)) {
-                jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
-                return 0;
-        }
-        return 1;
-}
-
-static int jffs2_compressor_Xable(const char *name, int disabled)
-{
-        struct jffs2_compressor *this;
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->disabled = disabled;
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        return 0;
-                }
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-        return 1;
-}
-
-int jffs2_enable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 0);
-}
-
-int jffs2_disable_compressor_name(const char *name)
-{
-        return jffs2_compressor_Xable(name, 1);
-}
-
-int jffs2_set_compressor_priority(const char *name, int priority)
-{
-        struct jffs2_compressor *this,*comp;
-        spin_lock(&jffs2_compressor_list_lock);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (!strcmp(this->name, name)) {
-                        this->priority = priority;
-                        comp = this;
-                        goto reinsert;
-                }
-        }
-        spin_unlock(&jffs2_compressor_list_lock);
-        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
-        return 1;
-reinsert:
-        /* list is sorted in the order of priority, so if
-           we change it we have to reinsert it into the
-           good place */
-        list_del(&comp->list);
-        list_for_each_entry(this, &jffs2_compressor_list, list) {
-                if (this->priority < comp->priority) {
-                        list_add(&comp->list, this->list.prev);
-                        spin_unlock(&jffs2_compressor_list_lock);
-                        return 0;
-                }
-        }
-        list_add_tail(&comp->list, &jffs2_compressor_list);
-        spin_unlock(&jffs2_compressor_list_lock);
-        return 0;
-}
-
-#endif
-
 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
 {
         if (orig != comprbuf)
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h
index 509b8b1..68cc701 100644
--- a/fs/jffs2/compr.h
+++ b/fs/jffs2/compr.h
@@ -1,13 +1,10 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ * Copyright Â© 2004   Ferenc Havasi <havasi@inf.u-szeged.hu>,
  *                    University of Szeged, Hungary
  *
- * For licensing information, see the file 'LICENCE' in the
- * jffs2 directory.
- *
- * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $
+ * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
 
@@ -76,16 +73,6 @@ int jffs2_decompress(struct jffs2_sb_inf
 
 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
 
-#ifdef CONFIG_JFFS2_PROC
-int jffs2_enable_compressor_name(const char *name);
-int jffs2_disable_compressor_name(const char *name);
-int jffs2_set_compression_mode_name(const char *mode_name);
-char *jffs2_get_compression_mode_name(void);
-int jffs2_set_compressor_priority(const char *mode_name, int priority);
-char *jffs2_list_compressors(void);
-char *jffs2_stats(void);
-#endif
-
 /* Compressor modules */
 /* These functions will be called by jffs2_compressors_init/exit */
 
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
index 2eb1b74..0d0bfd2 100644
--- a/fs/jffs2/compr_rtime.c
+++ b/fs/jffs2/compr_rtime.c
@@ -1,13 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
  *
  *
  * Very simple lz77-ish encoder.
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c
index e792e67..ea0431e 100644
--- a/fs/jffs2/compr_rubin.c
+++ b/fs/jffs2/compr_rubin.c
@@ -1,23 +1,94 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
- *
  */
 
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/jffs2.h>
-#include "compr_rubin.h"
-#include "histo_mips.h"
+#include <linux/errno.h>
 #include "compr.h"
 
+
+#define RUBIN_REG_SIZE   16
+#define UPPER_BIT_RUBIN    (((long) 1)<<(RUBIN_REG_SIZE-1))
+#define LOWER_BITS_RUBIN   ((((long) 1)<<(RUBIN_REG_SIZE-1))-1)
+
+
+#define BIT_DIVIDER_MIPS 1043
+static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
+
+#include <linux/errno.h>
+
+struct pushpull {
+	unsigned char *buf;
+	unsigned int buflen;
+	unsigned int ofs;
+	unsigned int reserve;
+};
+
+struct rubin_state {
+	unsigned long p;
+	unsigned long q;
+	unsigned long rec_q;
+	long bit_number;
+	struct pushpull pp;
+	int bit_divider;
+	int bits[8];
+};
+
+static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
+{
+	pp->buf = buf;
+	pp->buflen = buflen;
+	pp->ofs = ofs;
+	pp->reserve = reserve;
+}
+
+static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
+{
+	if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
+		return -ENOSPC;
+	}
+
+	if (bit) {
+		pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
+	}
+	else {
+		pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
+	}
+	pp->ofs++;
+
+	return 0;
+}
+
+static inline int pushedbits(struct pushpull *pp)
+{
+	return pp->ofs;
+}
+
+static inline int pullbit(struct pushpull *pp)
+{
+	int bit;
+
+	bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1;
+
+	pp->ofs++;
+	return bit;
+}
+
+static inline int pulledbits(struct pushpull *pp)
+{
+	return pp->ofs;
+}
+
+
 static void init_rubin(struct rubin_state *rs, int div, int *bits)
 {
 	int c;
diff --git a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h
deleted file mode 100644
index bf1a934..0000000
--- a/fs/jffs2/compr_rubin.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Rubin encoder/decoder header       */
-/* work started at   : aug   3, 1994  */
-/* last modification : aug  15, 1994  */
-/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */
-
-#include "pushpull.h"
-
-#define RUBIN_REG_SIZE   16
-#define UPPER_BIT_RUBIN    (((long) 1)<<(RUBIN_REG_SIZE-1))
-#define LOWER_BITS_RUBIN   ((((long) 1)<<(RUBIN_REG_SIZE-1))-1)
-
-
-struct rubin_state {
-	unsigned long p;
-	unsigned long q;
-	unsigned long rec_q;
-	long bit_number;
-	struct pushpull pp;
-	int bit_divider;
-	int bits[8];
-};
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 0c1fc6e..2b87fcc 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $
- *
  */
 
 #if !defined(__KERNEL__) && !defined(__ECOS)
diff --git a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c
deleted file mode 100644
index f0fb8be..0000000
--- a/fs/jffs2/comprtest.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <asm/types.h>
-#if 0
-#define TESTDATA_LEN 512
-static unsigned char testdata[TESTDATA_LEN] = {
- 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00,
- 0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00,
- 0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08,
- 0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08,
- 0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08,
- 0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08,
- 0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08,
- 0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08,
- 0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75,
- 0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
- 0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
- 0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
- 0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
- 0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
- 0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67,
- 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63,
- 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63};
-#else
-#define TESTDATA_LEN 3481
-static unsigned char testdata[TESTDATA_LEN] = {
- 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68,
- 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58,
- 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61,
- 0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30,
- 0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61,
- 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e,
- 0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c,
- 0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f,
- 0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
- 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e,
- 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72,
- 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75,
- 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20,
- 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28,
- 0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61,
- 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09,
- 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75,
- 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72,
- 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a,
- 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66,
- 0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a,
- 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a,
- 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66,
- 0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09,
- 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73,
- 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a,
- 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70,
- 0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20,
- 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c,
- 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d,
- 0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b,
- 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74,
- 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f,
- 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28,
- 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69,
- 0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c,
- 0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20,
- 0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c,
- 0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
- 0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
- 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e,
- 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22,
- 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65,
- 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28,
- 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c,
- 0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65,
- 0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b,
- 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64,
- 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f,
- 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66,
- 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74,
- 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65,
- 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69,
- 0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74,
- 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74,
- 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
- 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67,
- 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25,
- 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e,
- 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09,
- 0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69,
- 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69,
- 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20,
- 0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66,
- 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
- 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69,
- 0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f,
- 0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b,
- 0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
- 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65,
- 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09,
- 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30,
- 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e,
- 0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76,
- 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74,
- 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a,
- 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b,
- 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62,
- 0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73,
- 0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f,
- 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28,
- 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b,
- 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d,
- 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a,
- 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58,
- 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a,
- 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64,
- 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20,
- 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20,
- 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e,
- 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a,
- 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b,
- 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c,
- 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20,
- 0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d,
- 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20,
- 0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65,
- 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69,
- 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29,
- 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20,
- 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53,
- 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d,
- 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b,
- 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41,
- 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69,
- 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61,
- 0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73,
- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25,
- 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
- 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c,
- 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73,
- 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09,
- 0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66,
- 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
- 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69,
- 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b,
- 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29,
- 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b,
- 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e,
- 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09,
- 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c,
- 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
- 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68,
- 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74,
- 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20,
- 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20,
- 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b,
- 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
- 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61,
- 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72,
- 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d,
- 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a,
- 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20,
- 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e,
- 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61,
- 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72,
- 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a,
- 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72,
- 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29,
- 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e,
- 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70,
- 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20,
- 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20,
- 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c,
- 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29,
- 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f,
- 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c,
- 0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a,
- 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a,
- 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64,
- 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09,
- 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20,
- 0x25, 0x73, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73,
- 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72,
- 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d,
- 0x0a, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x28,
- 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
- 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75,
- 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69,
- 0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x26,
- 0x73, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72,
- 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74,
- 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x25,
- 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
- 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f,
- 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x53, 0x5f, 0x49,
- 0x53, 0x44, 0x49, 0x52, 0x28, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29,
- 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28,
- 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69,
- 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22,
- 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73,
- 0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x25, 0x64, 0x20, 0x25,
- 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d,
- 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69,
- 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a,
- 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28,
- 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74,
- 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65,
- 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x35, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x73,
- 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28,
- 0x35, 0x30, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a
-};
-#endif
-static unsigned char comprbuf[TESTDATA_LEN];
-static unsigned char decomprbuf[TESTDATA_LEN];
-
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
-		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
-			     uint32_t *datalen, uint32_t *cdatalen);
-
-int init_module(void ) {
-	unsigned char comprtype;
-	uint32_t c, d;
-	int ret;
-
-	printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       testdata[0],testdata[1],testdata[2],testdata[3],
-	       testdata[4],testdata[5],testdata[6],testdata[7],
-	       testdata[8],testdata[9],testdata[10],testdata[11],
-	       testdata[12],testdata[13],testdata[14],testdata[15]);
-	d = TESTDATA_LEN;
-	c = TESTDATA_LEN;
-	comprtype = jffs2_compress(testdata, comprbuf, &d, &c);
-
-	printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n",
-	       comprtype, c, d);
-	printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3],
-	       comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7],
-	       comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11],
-	       comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]);
-
-	ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d);
-	printk("jffs2_decompress returned %d\n", ret);
-	printk("Decompressed data:  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3],
-	       decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7],
-	       decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11],
-	       decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]);
-	if (memcmp(decomprbuf, testdata, d))
-		printk("Compression and decompression corrupted data\n");
-	else
-		printk("Compression good for %d bytes\n", d);
-	return 1;
-}
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
index 4189e4a..3a32c64 100644
--- a/fs/jffs2/debug.c
+++ b/fs/jffs2/debug.c
@@ -1,15 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $
- *
  */
+
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pagemap.h>
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index f89c85d..2a49f2c 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -1,15 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $
- *
  */
+
 #ifndef _JFFS2_DEBUG_H_
 #define _JFFS2_DEBUG_H_
 
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 9fa2e27..c1dfca3 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index ad01210..66e7c2f 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -333,7 +331,7 @@ static int jffs2_block_check_erase(struc
 
 		*bad_offset = ofs;
 
-		ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
+		ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
 		if (ret) {
 			printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
 			goto fail;
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index e82eeaf..9987127 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index abb90c0..1d3b7a9 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $
- *
  */
 
 #include <linux/capability.h>
@@ -672,6 +670,13 @@ static int jffs2_flash_setup(struct jffs
 			return ret;
 	}
 
+	/* and an UBI volume */
+	if (jffs2_ubivol(c)) {
+		ret = jffs2_ubivol_setup(c);
+		if (ret)
+			return ret;
+	}
+
 	return ret;
 }
 
@@ -690,4 +695,9 @@ void jffs2_flash_cleanup(struct jffs2_sb
 	if (jffs2_nor_wbuf_flash(c)) {
 		jffs2_nor_wbuf_flash_cleanup(c);
 	}
+
+	/* and an UBI volume */
+	if (jffs2_ubivol(c)) {
+		jffs2_ubivol_cleanup(c);
+	}
 }
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 3a3cf22..2d99e06 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -144,7 +142,8 @@ int jffs2_garbage_collect_pass(struct jf
 			       c->unchecked_size);
 			jffs2_dbg_dump_block_lists_nolock(c);
 			spin_unlock(&c->erase_completion_lock);
-			BUG();
+			up(&c->alloc_sem);
+			return -ENOSPC;
 		}
 
 		spin_unlock(&c->erase_completion_lock);
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c
index 6909983..f4d525b 100644
--- a/fs/jffs2/ioctl.c
+++ b/fs/jffs2/ioctl.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $
- *
  */
 
 #include <linux/fs.h>
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h
index 3a56607..0b78fdc 100644
--- a/fs/jffs2/jffs2_fs_i.h
+++ b/fs/jffs2/jffs2_fs_i.h
@@ -1,4 +1,13 @@
-/* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright Â© 2001-2007 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
 
 #ifndef _JFFS2_FS_I
 #define _JFFS2_FS_I
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index ea88f69..b13298a 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -1,4 +1,13 @@
-/* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright Â© 2001-2007 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 83f9881..35c1a5e 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 5a6b4d6..4bf8608 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -54,7 +52,7 @@ void jffs2_add_fd_to_list(struct jffs2_s
 	*prev = new;
 }
 
-void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
+uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
 {
 	struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
 
@@ -76,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs
 	}
 
 	if (size == 0)
-		return;
+		return 0;
 
-	/*
-	 * If the last fragment starts at the RAM page boundary, it is
-	 * REF_PRISTINE irrespective of its size.
-	 */
 	frag = frag_last(list);
+
+	/* Sanity check for truncation to longer than we started with... */
+	if (!frag)
+		return 0;
+	if (frag->ofs + frag->size < size)
+		return frag->ofs + frag->size;
+
+	/* If the last fragment starts at the RAM page boundary, it is
+	 * REF_PRISTINE irrespective of its size. */
 	if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
 		dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
 			frag->ofs, frag->ofs + frag->size);
 		frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
 	}
+	return size;
 }
 
 static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
@@ -397,466 +401,6 @@ int jffs2_add_full_dnode_to_inode(struct
 	return 0;
 }
 
-/*
- * Check the data CRC of the node.
- *
- * Returns: 0 if the data CRC is correct;
- * 	    1 - if incorrect;
- *	    error code if an error occured.
- */
-static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
-{
-	struct jffs2_raw_node_ref *ref = tn->fn->raw;
-	int err = 0, pointed = 0;
-	struct jffs2_eraseblock *jeb;
-	unsigned char *buffer;
-	uint32_t crc, ofs, len;
-	size_t retlen;
-
-	BUG_ON(tn->csize == 0);
-
-	if (!jffs2_is_writebuffered(c))
-		goto adj_acc;
-
-	/* Calculate how many bytes were already checked */
-	ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
-	len = ofs % c->wbuf_pagesize;
-	if (likely(len))
-		len = c->wbuf_pagesize - len;
-
-	if (len >= tn->csize) {
-		dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
-			ref_offset(ref), tn->csize, ofs);
-		goto adj_acc;
-	}
-
-	ofs += len;
-	len = tn->csize - len;
-
-	dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
-		ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
-
-#ifndef __ECOS
-	/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
-	 * adding and jffs2_flash_read_end() interface. */
-	if (c->mtd->point) {
-		err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
-		if (!err && retlen < tn->csize) {
-			JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
-			c->mtd->unpoint(c->mtd, buffer, ofs, len);
-		} else if (err)
-			JFFS2_WARNING("MTD point failed: error code %d.\n", err);
-		else
-			pointed = 1; /* succefully pointed to device */
-	}
-#endif
-
-	if (!pointed) {
-		buffer = kmalloc(len, GFP_KERNEL);
-		if (unlikely(!buffer))
-			return -ENOMEM;
-
-		/* TODO: this is very frequent pattern, make it a separate
-		 * routine */
-		err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
-		if (err) {
-			JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
-			goto free_out;
-		}
-
-		if (retlen != len) {
-			JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
-			err = -EIO;
-			goto free_out;
-		}
-	}
-
-	/* Continue calculating CRC */
-	crc = crc32(tn->partial_crc, buffer, len);
-	if(!pointed)
-		kfree(buffer);
-#ifndef __ECOS
-	else
-		c->mtd->unpoint(c->mtd, buffer, ofs, len);
-#endif
-
-	if (crc != tn->data_crc) {
-		JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
-			ofs, tn->data_crc, crc);
-		return 1;
-	}
-
-adj_acc:
-	jeb = &c->blocks[ref->flash_offset / c->sector_size];
-	len = ref_totlen(c, jeb, ref);
-
-	/*
-	 * Mark the node as having been checked and fix the
-	 * accounting accordingly.
-	 */
-	spin_lock(&c->erase_completion_lock);
-	jeb->used_size += len;
-	jeb->unchecked_size -= len;
-	c->used_size += len;
-	c->unchecked_size -= len;
-	spin_unlock(&c->erase_completion_lock);
-
-	return 0;
-
-free_out:
-	if(!pointed)
-		kfree(buffer);
-#ifndef __ECOS
-	else
-		c->mtd->unpoint(c->mtd, buffer, ofs, len);
-#endif
-	return err;
-}
-
-/*
- * Helper function for jffs2_add_older_frag_to_fragtree().
- *
- * Checks the node if we are in the checking stage.
- */
-static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
-{
-	int ret;
-
-	BUG_ON(ref_obsolete(tn->fn->raw));
-
-	/* We only check the data CRC of unchecked nodes */
-	if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
-		return 0;
-
-	dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n",
-		tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw));
-
-	ret = check_node_data(c, tn);
-	if (unlikely(ret < 0)) {
-		JFFS2_ERROR("check_node_data() returned error: %d.\n",
-			ret);
-	} else if (unlikely(ret > 0)) {
-		dbg_fragtree2("CRC error, mark it obsolete.\n");
-		jffs2_mark_node_obsolete(c, tn->fn->raw);
-	}
-
-	return ret;
-}
-
-/*
- * Helper function for jffs2_add_older_frag_to_fragtree().
- *
- * Called when the new fragment that is being inserted
- * splits a hole fragment.
- */
-static int split_hole(struct jffs2_sb_info *c, struct rb_root *root,
-		      struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole)
-{
-	dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n",
-		newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size);
-
-	if (hole->ofs == newfrag->ofs) {
-		/*
-		 * Well, the new fragment actually starts at the same offset as
-		 * the hole.
-		 */
-		if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
-			/*
-			 * We replace the overlapped left part of the hole by
-			 * the new node.
-			 */
-
-			dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n",
-				newfrag->ofs, newfrag->ofs + newfrag->size);
-			rb_replace_node(&hole->rb, &newfrag->rb, root);
-
-			hole->ofs += newfrag->size;
-			hole->size -= newfrag->size;
-
-			/*
-			 * We know that 'hole' should be the right hand
-			 * fragment.
-			 */
-			jffs2_fragtree_insert(hole, newfrag);
-			rb_insert_color(&hole->rb, root);
-		} else {
-			/*
-			 * Ah, the new fragment is of the same size as the hole.
-			 * Relace the hole by it.
-			 */
-			dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n",
-				newfrag->ofs, newfrag->ofs + newfrag->size);
-			rb_replace_node(&hole->rb, &newfrag->rb, root);
-			jffs2_free_node_frag(hole);
-		}
-	} else {
-		/* The new fragment lefts some hole space at the left */
-
-		struct jffs2_node_frag * newfrag2 = NULL;
-
-		if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
-			/* The new frag also lefts some space at the right */
-			newfrag2 = new_fragment(NULL, newfrag->ofs +
-				newfrag->size, hole->ofs + hole->size
-				- newfrag->ofs - newfrag->size);
-			if (unlikely(!newfrag2)) {
-				jffs2_free_node_frag(newfrag);
-				return -ENOMEM;
-			}
-		}
-
-		hole->size = newfrag->ofs - hole->ofs;
-		dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n",
-			hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size);
-
-		jffs2_fragtree_insert(newfrag, hole);
-		rb_insert_color(&newfrag->rb, root);
-
-		if (newfrag2) {
-			dbg_fragtree2("left the hole %#04x-%#04x at the right\n",
-				newfrag2->ofs, newfrag2->ofs + newfrag2->size);
-			jffs2_fragtree_insert(newfrag2, newfrag);
-			rb_insert_color(&newfrag2->rb, root);
-		}
-	}
-
-	return 0;
-}
-
-/*
- * This function is used when we build inode. It expects the nodes are passed
- * in the decreasing version order. The whole point of this is to improve the
- * inodes checking on NAND: we check the nodes' data CRC only when they are not
- * obsoleted. Previously, add_frag_to_fragtree() function was used and
- * nodes were passed to it in the increasing version ordes and CRCs of all
- * nodes were checked.
- *
- * Note: tn->fn->size shouldn't be zero.
- *
- * Returns 0 if the node was inserted
- *         1 if it wasn't inserted (since it is obsolete)
- *         < 0 an if error occured
- */
-int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-				     struct jffs2_tmp_dnode_info *tn)
-{
-	struct jffs2_node_frag *this, *newfrag;
-	uint32_t lastend;
-	struct jffs2_full_dnode *fn = tn->fn;
-	struct rb_root *root = &f->fragtree;
-	uint32_t fn_size = fn->size, fn_ofs = fn->ofs;
-	int err, checked = 0;
-	int ref_flag;
-
-	dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version);
-
-	/* Skip all the nodes which are completed before this one starts */
-	this = jffs2_lookup_node_frag(root, fn_ofs);
-	if (this)
-		dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole");
-
-	if (this)
-		lastend = this->ofs + this->size;
-	else
-		lastend = 0;
-
-	/* Detect the preliminary type of node */
-	if (fn->size >= PAGE_CACHE_SIZE)
-		ref_flag = REF_PRISTINE;
-	else
-		ref_flag = REF_NORMAL;
-
-	/* See if we ran off the end of the root */
-	if (lastend <= fn_ofs) {
-		/* We did */
-
-		/*
-		 * We are going to insert the new node into the
-		 * fragment tree, so check it.
-		 */
-		err = check_node(c, f, tn);
-		if (err != 0)
-			return err;
-
-		fn->frags = 1;
-
-		newfrag = new_fragment(fn, fn_ofs, fn_size);
-		if (unlikely(!newfrag))
-			return -ENOMEM;
-
-		err = no_overlapping_node(c, root, newfrag, this, lastend);
-		if (unlikely(err != 0)) {
-			jffs2_free_node_frag(newfrag);
-			return err;
-		}
-
-		goto out_ok;
-	}
-
-	fn->frags = 0;
-
-	while (1) {
-		/*
-		 * Here we have:
-		 * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs.
-		 *
-		 * Remember, 'this' has higher version, any non-hole node
-		 * which is already in the fragtree is newer then the newly
-		 * inserted.
-		 */
-		if (!this->node) {
-			/*
-			 * 'this' is the hole fragment, so at least the
-			 * beginning of the new fragment is valid.
-			 */
-
-			/*
-			 * We are going to insert the new node into the
-			 * fragment tree, so check it.
-			 */
-			if (!checked) {
-				err = check_node(c, f, tn);
-				if (unlikely(err != 0))
-					return err;
-				checked = 1;
-			}
-
-			if (this->ofs + this->size >= fn_ofs + fn_size) {
-				/* We split the hole on two parts */
-
-				fn->frags += 1;
-				newfrag = new_fragment(fn, fn_ofs, fn_size);
-				if (unlikely(!newfrag))
-					return -ENOMEM;
-
-				err = split_hole(c, root, newfrag, this);
-				if (unlikely(err))
-					return err;
-				goto out_ok;
-			}
-
-			/*
-			 * The beginning of the new fragment is valid since it
-			 * overlaps the hole node.
-			 */
-
-			ref_flag = REF_NORMAL;
-
-			fn->frags += 1;
-			newfrag = new_fragment(fn, fn_ofs,
-					this->ofs + this->size - fn_ofs);
-			if (unlikely(!newfrag))
-				return -ENOMEM;
-
-			if (fn_ofs == this->ofs) {
-				/*
-				 * The new node starts at the same offset as
-				 * the hole and supersieds the hole.
-				 */
-				dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n",
-					fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
-
-				rb_replace_node(&this->rb, &newfrag->rb, root);
-				jffs2_free_node_frag(this);
-			} else {
-				/*
-				 * The hole becomes shorter as its right part
-				 * is supersieded by the new fragment.
-				 */
-				dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n",
-					this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size);
-
-				dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs,
-					fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
-
-				this->size -= newfrag->size;
-				jffs2_fragtree_insert(newfrag, this);
-				rb_insert_color(&newfrag->rb, root);
-			}
-
-			fn_ofs += newfrag->size;
-			fn_size -= newfrag->size;
-			this = rb_entry(rb_next(&newfrag->rb),
-					struct jffs2_node_frag, rb);
-
-			dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
-				this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
-		}
-
-		/*
-		 * 'This' node is not the hole so it obsoletes the new fragment
-		 * either fully or partially.
-		 */
-		if (this->ofs + this->size >= fn_ofs + fn_size) {
-			/* The new node is obsolete, drop it */
-			if (fn->frags == 0) {
-				dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size);
-				ref_flag = REF_OBSOLETE;
-			}
-			goto out_ok;
-		} else {
-			struct jffs2_node_frag *new_this;
-
-			/* 'This' node obsoletes the beginning of the new node */
-			dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size);
-
-			ref_flag = REF_NORMAL;
-
-			fn_size -= this->ofs + this->size - fn_ofs;
-			fn_ofs = this->ofs + this->size;
-			dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size);
-
-			new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb);
-			if (!new_this) {
-				/*
-				 * There is no next fragment. Add the rest of
-				 * the new node as the right-hand child.
-				 */
-				if (!checked) {
-					err = check_node(c, f, tn);
-					if (unlikely(err != 0))
-						return err;
-					checked = 1;
-				}
-
-				fn->frags += 1;
-				newfrag = new_fragment(fn, fn_ofs, fn_size);
-				if (unlikely(!newfrag))
-					return -ENOMEM;
-
-				dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n",
-					newfrag->ofs, newfrag->ofs + newfrag->size);
-				rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
-				rb_insert_color(&newfrag->rb, root);
-				goto out_ok;
-			} else {
-				this = new_this;
-				dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
-					this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
-			}
-		}
-	}
-
-out_ok:
-	BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE);
-
-	if (ref_flag == REF_OBSOLETE) {
-		dbg_fragtree2("the node is obsolete now\n");
-		/* jffs2_mark_node_obsolete() will adjust space accounting */
-		jffs2_mark_node_obsolete(c, fn->raw);
-		return 1;
-	}
-
-	dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE");
-
-	/* Space accounting was adjusted at check_node_data() */
-	spin_lock(&c->erase_completion_lock);
-	fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag;
-	spin_unlock(&c->erase_completion_lock);
-
-	return 0;
-}
-
 void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
 {
 	spin_lock(&c->inocache_lock);
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 4178b4b..25126a0 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $
- *
  */
 
 #ifndef __JFFS2_NODELIST_H__
@@ -40,6 +38,9 @@ #define cpu_to_je16(x) ((jint16_t){x})
 #define cpu_to_je32(x) ((jint32_t){x})
 #define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
 
+#define constant_cpu_to_je16(x) ((jint16_t){x})
+#define constant_cpu_to_je32(x) ((jint32_t){x})
+
 #define je16_to_cpu(x) ((x).v16)
 #define je32_to_cpu(x) ((x).v32)
 #define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
@@ -48,6 +49,9 @@ #define cpu_to_je16(x) ((jint16_t){cpu_t
 #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
 #define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
 
+#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_be16(x)})
+#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_be32(x)})
+
 #define je16_to_cpu(x) (be16_to_cpu(x.v16))
 #define je32_to_cpu(x) (be32_to_cpu(x.v32))
 #define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
@@ -56,6 +60,9 @@ #define cpu_to_je16(x) ((jint16_t){cpu_t
 #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
 #define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
 
+#define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_le16(x)})
+#define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_le32(x)})
+
 #define je16_to_cpu(x) (le16_to_cpu(x.v16))
 #define je32_to_cpu(x) (le32_to_cpu(x.v32))
 #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
@@ -216,7 +223,20 @@ struct jffs2_tmp_dnode_info
 	uint32_t version;
 	uint32_t data_crc;
 	uint32_t partial_crc;
-	uint32_t csize;
+	uint16_t csize;
+	uint16_t overlapped;
+};
+
+/* Temporary data structure used during readinode. */
+struct jffs2_readinode_info
+{
+	struct rb_root tn_root;
+	struct jffs2_tmp_dnode_info *mdata_tn;
+	uint32_t highest_version;
+	uint32_t latest_mctime;
+	uint32_t mctime_ver;
+	struct jffs2_full_dirent *fds;
+	struct jffs2_raw_node_ref *latest_ref;
 };
 
 struct jffs2_full_dirent
@@ -319,6 +339,15 @@ #define frag_left(frag) rb_entry((frag)-
 #define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
 #define frag_erase(frag, list) rb_erase(&frag->rb, list);
 
+#define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
+#define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
+#define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
+#define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb)
+#define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb)
+#define tn_erase(tn, list) rb_erase(&tn->rb, list);
+#define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb)
+#define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb)
+
 /* nodelist.c */
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
 void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
@@ -333,8 +362,7 @@ struct rb_node *rb_next(struct rb_node *
 struct rb_node *rb_prev(struct rb_node *);
 void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
 int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
-void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
-int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn);
+uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
 struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
 					       struct jffs2_eraseblock *jeb,
 					       uint32_t ofs, uint32_t len,
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index d883769..dbc908a 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -172,6 +170,11 @@ int jffs2_reserve_space_gc(struct jffs2_
 static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 
+	if (c->nextblock == NULL) {
+		D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n",
+		  jeb->offset));
+		return;
+	}
 	/* Check, if we have a dirty block now, or if it was dirty already */
 	if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
 		c->dirty_size += jeb->wasted_size;
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index e07a0ed..80daea9 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2002-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $
- *
  */
 
 #ifndef __JFFS2_OS_LINUX_H__
@@ -98,6 +96,9 @@ #define jffs2_dataflash_cleanup(c) do {}
 #define jffs2_nor_wbuf_flash(c) (0)
 #define jffs2_nor_wbuf_flash_setup(c) (0)
 #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0)
+#define jffs2_ubivol(c) (0)
+#define jffs2_ubivol_setup(c) (0)
+#define jffs2_ubivol_cleanup(c) do {} while (0)
 
 #else /* NAND and/or ECC'd NOR support present */
 
@@ -133,6 +134,9 @@ void jffs2_nand_flash_cleanup(struct jff
 #define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
 int jffs2_dataflash_setup(struct jffs2_sb_info *c);
 void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+#define jffs2_ubivol(c) (c->mtd->type == MTD_UBIVOLUME)
+int jffs2_ubivol_setup(struct jffs2_sb_info *c);
+void jffs2_ubivol_cleanup(struct jffs2_sb_info *c);
 
 #define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && ! (c->mtd->flags & MTD_BIT_WRITEABLE))
 int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c);
diff --git a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h
deleted file mode 100644
index c0c2a91..0000000
--- a/fs/jffs2/pushpull.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * JFFS2 -- Journalling Flash File System, Version 2.
- *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
- *
- * Created by David Woodhouse <dwmw2@infradead.org>
- *
- * For licensing information, see the file 'LICENCE' in this directory.
- *
- * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
- *
- */
-
-#ifndef __PUSHPULL_H__
-#define __PUSHPULL_H__
-
-#include <linux/errno.h>
-
-struct pushpull {
-	unsigned char *buf;
-	unsigned int buflen;
-	unsigned int ofs;
-	unsigned int reserve;
-};
-
-
-static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
-{
-	pp->buf = buf;
-	pp->buflen = buflen;
-	pp->ofs = ofs;
-	pp->reserve = reserve;
-}
-
-static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
-{
-	if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
-		return -ENOSPC;
-	}
-
-	if (bit) {
-		pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
-	}
-	else {
-		pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
-	}
-	pp->ofs++;
-
-	return 0;
-}
-
-static inline int pushedbits(struct pushpull *pp)
-{
-	return pp->ofs;
-}
-
-static inline int pullbit(struct pushpull *pp)
-{
-	int bit;
-
-	bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1;
-
-	pp->ofs++;
-	return bit;
-}
-
-static inline int pulledbits(struct pushpull *pp)
-{
-	return pp->ofs;
-}
-
-#endif /* __PUSHPULL_H__ */
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index f3b86da..cfe05c1 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 717a48c..6aff389 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -22,30 +20,510 @@ #include <linux/compiler.h>
 #include "nodelist.h"
 
 /*
- * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in
- * order of increasing version.
+ * Check the data CRC of the node.
+ *
+ * Returns: 0 if the data CRC is correct;
+ * 	    1 - if incorrect;
+ *	    error code if an error occured.
  */
-static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
+static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
 {
-	struct rb_node **p = &list->rb_node;
-	struct rb_node * parent = NULL;
-	struct jffs2_tmp_dnode_info *this;
-
-	while (*p) {
-		parent = *p;
-		this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
-
-		/* There may actually be a collision here, but it doesn't
-		   actually matter. As long as the two nodes with the same
-		   version are together, it's all fine. */
-		if (tn->version > this->version)
-			p = &(*p)->rb_left;
+	struct jffs2_raw_node_ref *ref = tn->fn->raw;
+	int err = 0, pointed = 0;
+	struct jffs2_eraseblock *jeb;
+	unsigned char *buffer;
+	uint32_t crc, ofs, len;
+	size_t retlen;
+
+	BUG_ON(tn->csize == 0);
+
+	if (!jffs2_is_writebuffered(c))
+		goto adj_acc;
+
+	/* Calculate how many bytes were already checked */
+	ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
+	len = ofs % c->wbuf_pagesize;
+	if (likely(len))
+		len = c->wbuf_pagesize - len;
+
+	if (len >= tn->csize) {
+		dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
+			ref_offset(ref), tn->csize, ofs);
+		goto adj_acc;
+	}
+
+	ofs += len;
+	len = tn->csize - len;
+
+	dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
+		ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
+
+#ifndef __ECOS
+	/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
+	 * adding and jffs2_flash_read_end() interface. */
+	if (c->mtd->point) {
+		err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
+		if (!err && retlen < tn->csize) {
+			JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
+			c->mtd->unpoint(c->mtd, buffer, ofs, len);
+		} else if (err)
+			JFFS2_WARNING("MTD point failed: error code %d.\n", err);
 		else
-			p = &(*p)->rb_right;
+			pointed = 1; /* succefully pointed to device */
+	}
+#endif
+
+	if (!pointed) {
+		buffer = kmalloc(len, GFP_KERNEL);
+		if (unlikely(!buffer))
+			return -ENOMEM;
+
+		/* TODO: this is very frequent pattern, make it a separate
+		 * routine */
+		err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
+		if (err) {
+			JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
+			goto free_out;
+		}
+
+		if (retlen != len) {
+			JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
+			err = -EIO;
+			goto free_out;
+		}
+	}
+
+	/* Continue calculating CRC */
+	crc = crc32(tn->partial_crc, buffer, len);
+	if(!pointed)
+		kfree(buffer);
+#ifndef __ECOS
+	else
+		c->mtd->unpoint(c->mtd, buffer, ofs, len);
+#endif
+
+	if (crc != tn->data_crc) {
+		JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
+			ofs, tn->data_crc, crc);
+		return 1;
 	}
 
-	rb_link_node(&tn->rb, parent, p);
-	rb_insert_color(&tn->rb, list);
+adj_acc:
+	jeb = &c->blocks[ref->flash_offset / c->sector_size];
+	len = ref_totlen(c, jeb, ref);
+	/* If it should be REF_NORMAL, it'll get marked as such when
+	   we build the fragtree, shortly. No need to worry about GC
+	   moving it while it's marked REF_PRISTINE -- GC won't happen
+	   till we've finished checking every inode anyway. */
+	ref->flash_offset |= REF_PRISTINE;
+	/*
+	 * Mark the node as having been checked and fix the
+	 * accounting accordingly.
+	 */
+	spin_lock(&c->erase_completion_lock);
+	jeb->used_size += len;
+	jeb->unchecked_size -= len;
+	c->used_size += len;
+	c->unchecked_size -= len;
+	jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+	spin_unlock(&c->erase_completion_lock);
+
+	return 0;
+
+free_out:
+	if(!pointed)
+		kfree(buffer);
+#ifndef __ECOS
+	else
+		c->mtd->unpoint(c->mtd, buffer, ofs, len);
+#endif
+	return err;
+}
+
+/*
+ * Helper function for jffs2_add_older_frag_to_fragtree().
+ *
+ * Checks the node if we are in the checking stage.
+ */
+static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
+{
+	int ret;
+
+	BUG_ON(ref_obsolete(tn->fn->raw));
+
+	/* We only check the data CRC of unchecked nodes */
+	if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
+		return 0;
+
+	dbg_readinode("check node %#04x-%#04x, phys offs %#08x\n",
+		      tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw));
+
+	ret = check_node_data(c, tn);
+	if (unlikely(ret < 0)) {
+		JFFS2_ERROR("check_node_data() returned error: %d.\n",
+			ret);
+	} else if (unlikely(ret > 0)) {
+		dbg_readinode("CRC error, mark it obsolete.\n");
+		jffs2_mark_node_obsolete(c, tn->fn->raw);
+	}
+
+	return ret;
+}
+
+static struct jffs2_tmp_dnode_info *jffs2_lookup_tn(struct rb_root *tn_root, uint32_t offset)
+{
+	struct rb_node *next;
+	struct jffs2_tmp_dnode_info *tn = NULL;
+
+	dbg_readinode("root %p, offset %d\n", tn_root, offset);
+
+	next = tn_root->rb_node;
+
+	while (next) {
+		tn = rb_entry(next, struct jffs2_tmp_dnode_info, rb);
+
+		if (tn->fn->ofs < offset)
+			next = tn->rb.rb_right;
+		else if (tn->fn->ofs >= offset)
+			next = tn->rb.rb_left;
+		else
+			break;
+	}
+
+	return tn;
+}
+
+
+static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
+{
+	jffs2_mark_node_obsolete(c, tn->fn->raw);
+	jffs2_free_full_dnode(tn->fn);
+	jffs2_free_tmp_dnode_info(tn);
+}
+/*
+ * This function is used when we read an inode. Data nodes arrive in
+ * arbitrary order -- they may be older or newer than the nodes which
+ * are already in the tree. Where overlaps occur, the older node can
+ * be discarded as long as the newer passes the CRC check. We don't
+ * bother to keep track of holes in this rbtree, and neither do we deal
+ * with frags -- we can have multiple entries starting at the same
+ * offset, and the one with the smallest length will come first in the
+ * ordering.
+ *
+ * Returns 0 if the node was inserted
+ *         1 if the node is obsolete (because we can't mark it so yet)
+ *         < 0 an if error occurred
+ */
+static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
+				struct jffs2_readinode_info *rii,
+				struct jffs2_tmp_dnode_info *tn)
+{
+	uint32_t fn_end = tn->fn->ofs + tn->fn->size;
+	struct jffs2_tmp_dnode_info *insert_point = NULL, *this;
+
+	dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version);
+
+	/* If a node has zero dsize, we only have to keep if it if it might be the
+	   node with highest version -- i.e. the one which will end up as f->metadata.
+	   Note that such nodes won't be REF_UNCHECKED since there are no data to
+	   check anyway. */
+	if (!tn->fn->size) {
+		if (rii->mdata_tn) {
+			/* We had a candidate mdata node already */
+			dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
+			jffs2_kill_tn(c, rii->mdata_tn);
+		}
+		rii->mdata_tn = tn;
+		dbg_readinode("keep new mdata with ver %d\n", tn->version);
+		return 0;
+	}
+
+	/* Find the earliest node which _may_ be relevant to this one */
+	this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
+	if (!this) {
+		/* First addition to empty tree. $DEITY how I love the easy cases */
+		rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node);
+		rb_insert_color(&tn->rb, &rii->tn_root);
+		dbg_readinode("keep new frag\n");
+		return 0;
+	}
+
+	/* If we add a new node it'll be somewhere under here. */
+	insert_point = this;
+
+	/* If the node is coincident with another at a lower address,
+	   back up until the other node is found. It may be relevant */
+	while (tn->overlapped)
+		tn = tn_prev(tn);
+
+	dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+
+	while (this) {
+		if (this->fn->ofs > fn_end)
+			break;
+		dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n",
+			      this->version, this->fn->ofs, this->fn->size);
+
+		if (this->version == tn->version) {
+			/* Version number collision means REF_PRISTINE GC. Accept either of them
+			   as long as the CRC is correct. Check the one we have already...  */
+			if (!check_tn_node(c, this)) {
+				/* The one we already had was OK. Keep it and throw away the new one */
+				dbg_readinode("Like old node. Throw away new\n");
+				jffs2_kill_tn(c, tn);
+				return 0;
+			} else {
+				/* Who cares if the new one is good; keep it for now anyway. */
+				rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
+				/* Same overlapping from in front and behind */
+				tn->overlapped = this->overlapped;
+				jffs2_kill_tn(c, this);
+				dbg_readinode("Like new node. Throw away old\n");
+				return 0;
+			}
+		}
+		if (this->version < tn->version &&
+		    this->fn->ofs >= tn->fn->ofs &&
+		    this->fn->ofs + this->fn->size <= fn_end) {
+			/* New node entirely overlaps 'this' */
+			if (check_tn_node(c, tn)) {
+				dbg_readinode("new node bad CRC\n");
+				jffs2_kill_tn(c, tn);
+				return 0;
+			}
+			/* ... and is good. Kill 'this'... */
+			rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
+			tn->overlapped = this->overlapped;
+			jffs2_kill_tn(c, this);
+			/* ... and any subsequent nodes which are also overlapped */
+			this = tn_next(tn);
+			while (this && this->fn->ofs + this->fn->size < fn_end) {
+				struct jffs2_tmp_dnode_info *next = tn_next(this);
+				if (this->version < tn->version) {
+					tn_erase(this, &rii->tn_root);
+					dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n",
+						      this->version, this->fn->ofs,
+						      this->fn->ofs+this->fn->size);
+					jffs2_kill_tn(c, this);
+				}
+				this = next;
+			}
+			dbg_readinode("Done inserting new\n");
+			return 0;
+		}
+		if (this->version > tn->version &&
+		    this->fn->ofs <= tn->fn->ofs &&
+		    this->fn->ofs+this->fn->size >= fn_end) {
+			/* New node entirely overlapped by 'this' */
+			if (!check_tn_node(c, this)) {
+				dbg_readinode("Good CRC on old node. Kill new\n");
+				jffs2_kill_tn(c, tn);
+				return 0;
+			}
+			/* ... but 'this' was bad. Replace it... */
+			rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
+			dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
+			jffs2_kill_tn(c, this);
+			return 0;
+		}
+		/* We want to be inserted under the last node which is
+		   either at a lower offset _or_ has a smaller range */
+		if (this->fn->ofs < tn->fn->ofs ||
+		    (this->fn->ofs == tn->fn->ofs &&
+		     this->fn->size <= tn->fn->size))
+			insert_point = this;
+
+		this = tn_next(this);
+	}
+	dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n",
+		      insert_point, insert_point->version, insert_point->fn->ofs,
+		      insert_point->fn->ofs+insert_point->fn->size,
+		      insert_point->overlapped);
+	/* We neither completely obsoleted nor were completely
+	   obsoleted by an earlier node. Insert under insert_point */
+	{
+		struct rb_node *parent = &insert_point->rb;
+		struct rb_node **link = &parent;
+
+		while (*link) {
+			parent = *link;
+			insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
+			if (tn->fn->ofs > insert_point->fn->ofs)
+				link = &insert_point->rb.rb_right;
+			else if (tn->fn->ofs < insert_point->fn->ofs ||
+				 tn->fn->size < insert_point->fn->size)
+				link = &insert_point->rb.rb_left;
+			else
+				link = &insert_point->rb.rb_right;
+		}
+		rb_link_node(&tn->rb, &insert_point->rb, link);
+		rb_insert_color(&tn->rb, &rii->tn_root);
+	}
+	/* If there's anything behind that overlaps us, note it */
+	this = tn_prev(tn);
+	if (this) {
+		while (1) {
+			if (this->fn->ofs + this->fn->size > tn->fn->ofs) {
+				dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n",
+					      this, this->version, this->fn->ofs,
+					      this->fn->ofs+this->fn->size);
+				tn->overlapped = 1;
+				break;
+			}
+			if (!this->overlapped)
+				break;
+			this = tn_prev(this);
+		}
+	}
+
+	/* If the new node overlaps anything ahead, note it */
+	this = tn_next(tn);
+	while (this && this->fn->ofs < fn_end) {
+		this->overlapped = 1;
+		dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n",
+			      this->version, this->fn->ofs,
+			      this->fn->ofs+this->fn->size);
+		this = tn_next(this);
+	}
+	return 0;
+}
+
+/* Trivial function to remove the last node in the tree. Which by definition
+   has no right-hand -- so can be removed just by making its only child (if
+   any) take its place under its parent. */
+static void eat_last(struct rb_root *root, struct rb_node *node)
+{
+	struct rb_node *parent = rb_parent(node);
+	struct rb_node **link;
+
+	/* LAST! */
+	BUG_ON(node->rb_right);
+
+	if (!parent)
+		link = &root->rb_node;
+	else if (node == parent->rb_left)
+		link = &parent->rb_left;
+	else
+		link = &parent->rb_right;
+
+	*link = node->rb_left;
+	/* Colour doesn't matter now. Only the parent pointer. */
+	if (node->rb_left)
+		node->rb_left->rb_parent_color = node->rb_parent_color;
+}
+
+/* We put this in reverse order, so we can just use eat_last */
+static void ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn)
+{
+	struct rb_node **link = &ver_root->rb_node;
+	struct rb_node *parent = NULL;
+	struct jffs2_tmp_dnode_info *this_tn;
+
+	while (*link) {
+		parent = *link;
+		this_tn = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
+
+		if (tn->version > this_tn->version)
+			link = &parent->rb_left;
+		else
+			link = &parent->rb_right;
+	}
+	dbg_readinode("Link new node at %p (root is %p)\n", link, ver_root);
+	rb_link_node(&tn->rb, parent, link);
+	rb_insert_color(&tn->rb, ver_root);
+}
+
+/* Build final, normal fragtree from tn tree. It doesn't matter which order
+   we add nodes to the real fragtree, as long as they don't overlap. And
+   having thrown away the majority of overlapped nodes as we went, there
+   really shouldn't be many sets of nodes which do overlap. If we start at
+   the end, we can use the overlap markers -- we can just eat nodes which
+   aren't overlapped, and when we encounter nodes which _do_ overlap we
+   sort them all into a temporary tree in version order before replaying them. */
+static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
+				      struct jffs2_inode_info *f,
+				      struct jffs2_readinode_info *rii)
+{
+	struct jffs2_tmp_dnode_info *pen, *last, *this;
+	struct rb_root ver_root = RB_ROOT;
+	uint32_t high_ver = 0;
+
+	if (rii->mdata_tn) {
+		dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn);
+		high_ver = rii->mdata_tn->version;
+		rii->latest_ref = rii->mdata_tn->fn->raw;
+	}
+#ifdef JFFS2_DBG_READINODE_MESSAGES
+	this = tn_last(&rii->tn_root);
+	while (this) {
+		dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs,
+			     this->fn->ofs+this->fn->size, this->overlapped);
+		this = tn_prev(this);
+	}
+#endif
+	pen = tn_last(&rii->tn_root);
+	while ((last = pen)) {
+		pen = tn_prev(last);
+
+		eat_last(&rii->tn_root, &last->rb);
+		ver_insert(&ver_root, last);
+
+		if (unlikely(last->overlapped))
+			continue;
+
+		/* Now we have a bunch of nodes in reverse version
+		   order, in the tree at ver_root. Most of the time,
+		   there'll actually be only one node in the 'tree',
+		   in fact. */
+		this = tn_last(&ver_root);
+
+		while (this) {
+			struct jffs2_tmp_dnode_info *vers_next;
+			int ret;
+			vers_next = tn_prev(this);
+			eat_last(&ver_root, &this->rb);
+			if (check_tn_node(c, this)) {
+				dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n",
+					     this->version, this->fn->ofs,
+					     this->fn->ofs+this->fn->size);
+				jffs2_kill_tn(c, this);
+			} else {
+				if (this->version > high_ver) {
+					/* Note that this is different from the other
+					   highest_version, because this one is only
+					   counting _valid_ nodes which could give the
+					   latest inode metadata */
+					high_ver = this->version;
+					rii->latest_ref = this->fn->raw;
+				}
+				dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n",
+					     this, this->version, this->fn->ofs,
+					     this->fn->ofs+this->fn->size, this->overlapped);
+
+				ret = jffs2_add_full_dnode_to_inode(c, f, this->fn);
+				if (ret) {
+					/* Free the nodes in vers_root; let the caller
+					   deal with the rest */
+					JFFS2_ERROR("Add node to tree failed %d\n", ret);
+					while (1) {
+						vers_next = tn_prev(this);
+						if (check_tn_node(c, this))
+							jffs2_mark_node_obsolete(c, this->fn->raw);
+						jffs2_free_full_dnode(this->fn);
+						jffs2_free_tmp_dnode_info(this);
+						this = vers_next;
+						if (!this)
+							break;
+						eat_last(&ver_root, &vers_next->rb);
+					}
+					return ret;
+				}
+				jffs2_free_tmp_dnode_info(this);
+			}
+			this = vers_next;
+		}
+	}
+	return 0;
 }
 
 static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
@@ -112,8 +590,8 @@ static struct jffs2_raw_node_ref *jffs2_
  * 	    negative error code on failure.
  */
 static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
-				struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp,
-				uint32_t *latest_mctime, uint32_t *mctime_ver)
+				struct jffs2_raw_dirent *rd, size_t read,
+				struct jffs2_readinode_info *rii)
 {
 	struct jffs2_full_dirent *fd;
 	uint32_t crc;
@@ -125,7 +603,8 @@ static inline int read_direntry(struct j
 	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
 		JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n",
 			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
-		return 1;
+		jffs2_mark_node_obsolete(c, ref);
+		return 0;
 	}
 
 	/* If we've never checked the CRCs on this node, check them now */
@@ -137,7 +616,8 @@ static inline int read_direntry(struct j
 		if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
 			JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
 				    ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
-			return 1;
+			jffs2_mark_node_obsolete(c, ref);
+			return 0;
 		}
 
 		jeb = &c->blocks[ref->flash_offset / c->sector_size];
@@ -161,10 +641,13 @@ static inline int read_direntry(struct j
 	fd->ino = je32_to_cpu(rd->ino);
 	fd->type = rd->type;
 
+	if (fd->version > rii->highest_version)
+		rii->highest_version = fd->version;
+
 	/* Pick out the mctime of the latest dirent */
-	if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) {
-		*mctime_ver = fd->version;
-		*latest_mctime = je32_to_cpu(rd->mctime);
+	if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) {
+		rii->mctime_ver = fd->version;
+		rii->latest_mctime = je32_to_cpu(rd->mctime);
 	}
 
 	/*
@@ -201,7 +684,7 @@ static inline int read_direntry(struct j
 	 * Wheee. We now have a complete jffs2_full_dirent structure, with
 	 * the name in it and everything. Link it into the list
 	 */
-	jffs2_add_fd_to_list(c, fd, fdp);
+	jffs2_add_fd_to_list(c, fd, &rii->fds);
 
 	return 0;
 }
@@ -210,13 +693,13 @@ static inline int read_direntry(struct j
  * Helper function for jffs2_get_inode_nodes().
  * It is called every time an inode node is found.
  *
- * Returns: 0 on succes;
+ * Returns: 0 on success;
  * 	    1 if the node should be marked obsolete;
  * 	    negative error code on failure.
  */
 static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
-			     struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen,
-			     uint32_t *latest_mctime, uint32_t *mctime_ver)
+			     struct jffs2_raw_inode *rd, int rdlen,
+			     struct jffs2_readinode_info *rii)
 {
 	struct jffs2_tmp_dnode_info *tn;
 	uint32_t len, csize;
@@ -230,7 +713,8 @@ static inline int read_dnode(struct jffs
 	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
 		JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n",
 			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
-		return 1;
+		jffs2_mark_node_obsolete(c, ref);
+		return 0;
 	}
 
 	tn = jffs2_alloc_tmp_dnode_info();
@@ -342,6 +826,10 @@ static inline int read_dnode(struct jffs
 	tn->data_crc = je32_to_cpu(rd->data_crc);
 	tn->csize = csize;
 	tn->fn->raw = ref;
+	tn->overlapped = 0;
+
+	if (tn->version > rii->highest_version)
+		rii->highest_version = tn->version;
 
 	/* There was a bug where we wrote hole nodes out with
 	   csize/dsize swapped. Deal with it */
@@ -353,13 +841,25 @@ static inline int read_dnode(struct jffs
 	dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
 		  ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);
 
-	jffs2_add_tn_to_tree(tn, tnp);
+	ret = jffs2_add_tn_to_tree(c, rii, tn);
 
+	if (ret) {
+		jffs2_free_full_dnode(tn->fn);
+	free_out:
+		jffs2_free_tmp_dnode_info(tn);
+		return ret;
+	}
+#ifdef JFFS2_DBG_READINODE_MESSAGES
+	dbg_readinode("After adding ver %d:\n", tn->version);
+	tn = tn_first(&rii->tn_root);
+	while (tn) {
+		dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",
+			     tn, tn->version, tn->fn->ofs,
+			     tn->fn->ofs+tn->fn->size, tn->overlapped);
+		tn = tn_next(tn);
+	}
+#endif
 	return 0;
-
-free_out:
-	jffs2_free_tmp_dnode_info(tn);
-	return ret;
 }
 
 /*
@@ -379,7 +879,8 @@ static inline int read_unknown(struct jf
 		JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n",
                             je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
                             je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
-		return 1;
+		jffs2_mark_node_obsolete(c, ref);
+		return 0;
 	}
 
 	un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
@@ -407,7 +908,8 @@ static inline int read_unknown(struct jf
 	case JFFS2_FEATURE_RWCOMPAT_DELETE:
 		JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
 			     je16_to_cpu(un->nodetype), ref_offset(ref));
-		return 1;
+		jffs2_mark_node_obsolete(c, ref);
+		return 0;
 	}
 
 	return 0;
@@ -421,92 +923,62 @@ static inline int read_unknown(struct jf
  * 	    negative error code on failure.
  */
 static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
-		     int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart)
+		     int needed_len, int *rdlen, unsigned char *buf)
 {
-	int right_len, err, len;
+	int err, to_read = needed_len - *rdlen;
 	size_t retlen;
 	uint32_t offs;
 
 	if (jffs2_is_writebuffered(c)) {
-		right_len = c->wbuf_pagesize - (bufstart - buf);
-		if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize)
-			right_len += c->wbuf_pagesize;
-	} else
-		right_len = right_size;
+		int rem = to_read % c->wbuf_pagesize;
 
-	if (*rdlen == right_len)
-		return 0;
+		if (rem)
+			to_read += c->wbuf_pagesize - rem;
+	}
 
 	/* We need to read more data */
 	offs = ref_offset(ref) + *rdlen;
-	if (jffs2_is_writebuffered(c)) {
-		bufstart = buf + c->wbuf_pagesize;
-		len = c->wbuf_pagesize;
-	} else {
-		bufstart = buf + *rdlen;
-		len = right_size - *rdlen;
-	}
 
-	dbg_readinode("read more %d bytes\n", len);
+	dbg_readinode("read more %d bytes\n", to_read);
 
-	err = jffs2_flash_read(c, offs, len, &retlen, bufstart);
+	err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen);
 	if (err) {
 		JFFS2_ERROR("can not read %d bytes from 0x%08x, "
-			"error code: %d.\n", len, offs, err);
+			"error code: %d.\n", to_read, offs, err);
 		return err;
 	}
 
-	if (retlen < len) {
+	if (retlen < to_read) {
 		JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n",
-				offs, retlen, len);
+				offs, retlen, to_read);
 		return -EIO;
 	}
 
-	*rdlen = right_len;
-
+	*rdlen += to_read;
 	return 0;
 }
 
 /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
-   with this ino, returning the former in order of version */
+   with this ino. Perform a preliminary ordering on data nodes, throwing away
+   those which are completely obsoleted by newer ones. The naÃ¯ve approach we
+   use to take of just returning them _all_ in version order will cause us to
+   run out of memory in certain degenerate cases. */
 static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-				 struct rb_root *tnp, struct jffs2_full_dirent **fdp,
-				 uint32_t *highest_version, uint32_t *latest_mctime,
-				 uint32_t *mctime_ver)
+				 struct jffs2_readinode_info *rii)
 {
 	struct jffs2_raw_node_ref *ref, *valid_ref;
-	struct rb_root ret_tn = RB_ROOT;
-	struct jffs2_full_dirent *ret_fd = NULL;
 	unsigned char *buf = NULL;
 	union jffs2_node_union *node;
 	size_t retlen;
 	int len, err;
 
-	*mctime_ver = 0;
+	rii->mctime_ver = 0;
 
 	dbg_readinode("ino #%u\n", f->inocache->ino);
 
-	if (jffs2_is_writebuffered(c)) {
-		/*
-		 * If we have the write buffer, we assume the minimal I/O unit
-		 * is c->wbuf_pagesize. We implement some optimizations which in
-		 * this case and we need a temporary buffer of size =
-		 * 2*c->wbuf_pagesize bytes (see comments in read_dnode()).
-		 * Basically, we want to read not only the node header, but the
-		 * whole wbuf (NAND page in case of NAND) or 2, if the node
-		 * header overlaps the border between the 2 wbufs.
-		 */
-		len = 2*c->wbuf_pagesize;
-	} else {
-		/*
-		 * When there is no write buffer, the size of the temporary
-		 * buffer is the size of the larges node header.
-		 */
-		len = sizeof(union jffs2_node_union);
-	}
-
 	/* FIXME: in case of NOR and available ->point() this
 	 * needs to be fixed. */
+	len = sizeof(union jffs2_node_union) + c->wbuf_pagesize;
 	buf = kmalloc(len, GFP_KERNEL);
 	if (!buf)
 		return -ENOMEM;
@@ -516,8 +988,6 @@ static int jffs2_get_inode_nodes(struct 
 	if (!valid_ref && f->inocache->ino != 1)
 		JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino);
 	while (valid_ref) {
-		unsigned char *bufstart;
-
 		/* We can hold a pointer to a non-obsolete node without the spinlock,
 		   but _obsolete_ nodes may disappear at any time, if the block
 		   they're in gets erased. So if we mark 'ref' obsolete while we're
@@ -533,32 +1003,31 @@ static int jffs2_get_inode_nodes(struct 
 		/*
 		 * At this point we don't know the type of the node we're going
 		 * to read, so we do not know the size of its header. In order
-		 * to minimize the amount of flash IO we assume the node has
-		 * size = JFFS2_MIN_NODE_HEADER.
+		 * to minimize the amount of flash IO we assume the header is
+		 * of size = JFFS2_MIN_NODE_HEADER.
 		 */
+		len = JFFS2_MIN_NODE_HEADER;
 		if (jffs2_is_writebuffered(c)) {
+			int end, rem;
+
 			/*
-			 * We treat 'buf' as 2 adjacent wbufs. We want to
-			 * adjust bufstart such as it points to the
-			 * beginning of the node within this wbuf.
+			 * We are about to read JFFS2_MIN_NODE_HEADER bytes,
+			 * but this flash has some minimal I/O unit. It is
+			 * possible that we'll need to read more soon, so read
+			 * up to the next min. I/O unit, in order not to
+			 * re-read the same min. I/O unit twice.
 			 */
-			bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize);
-			/* We will read either one wbuf or 2 wbufs. */
-			len = c->wbuf_pagesize - (bufstart - buf);
-			if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) {
-				/* The header spans the border of the first wbuf */
-				len += c->wbuf_pagesize;
-			}
-		} else {
-			bufstart = buf;
-			len = JFFS2_MIN_NODE_HEADER;
+			end = ref_offset(ref) + len;
+			rem = end % c->wbuf_pagesize;
+			if (rem)
+				end += c->wbuf_pagesize - rem;
+			len = end - ref_offset(ref);
 		}
 
 		dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref));
 
 		/* FIXME: point() */
-		err = jffs2_flash_read(c, ref_offset(ref), len,
-				       &retlen, bufstart);
+		err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf);
 		if (err) {
 			JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err);
 			goto free_out;
@@ -570,7 +1039,7 @@ static int jffs2_get_inode_nodes(struct 
 			goto free_out;
 		}
 
-		node = (union jffs2_node_union *)bufstart;
+		node = (union jffs2_node_union *)buf;
 
 		/* No need to mask in the valid bit; it shouldn't be invalid */
 		if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) {
@@ -583,10 +1052,10 @@ static int jffs2_get_inode_nodes(struct 
 			jffs2_mark_node_obsolete(c, ref);
 			goto cont;
 		}
-		/* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */
-		if (!je32_to_cpu(node->u.hdr_crc) && !je16_to_cpu(node->u.nodetype) &&
-		    !je16_to_cpu(node->u.magic) && !je32_to_cpu(node->u.totlen)) {
-			JFFS2_NOTICE("All zero node header at %#08x.\n", ref_offset(ref));
+		if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) {
+			/* Not a JFFS2 node, whinge and move on */
+			JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n",
+				     je16_to_cpu(node->u.magic), ref_offset(ref));
 			jffs2_mark_node_obsolete(c, ref);
 			goto cont;
 		}
@@ -596,46 +1065,34 @@ static int jffs2_get_inode_nodes(struct 
 		case JFFS2_NODETYPE_DIRENT:
 
 			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) {
-				err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart);
+				err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf);
 				if (unlikely(err))
 					goto free_out;
 			}
 
-			err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver);
-			if (err == 1) {
-				jffs2_mark_node_obsolete(c, ref);
-				break;
-			} else if (unlikely(err))
+			err = read_direntry(c, ref, &node->d, retlen, rii);
+			if (unlikely(err))
 				goto free_out;
 
-			if (je32_to_cpu(node->d.version) > *highest_version)
-				*highest_version = je32_to_cpu(node->d.version);
-
 			break;
 
 		case JFFS2_NODETYPE_INODE:
 
 			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) {
-				err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart);
+				err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf);
 				if (unlikely(err))
 					goto free_out;
 			}
 
-			err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver);
-			if (err == 1) {
-				jffs2_mark_node_obsolete(c, ref);
-				break;
-			} else if (unlikely(err))
+			err = read_dnode(c, ref, &node->i, len, rii);
+			if (unlikely(err))
 				goto free_out;
 
-			if (je32_to_cpu(node->i.version) > *highest_version)
-				*highest_version = je32_to_cpu(node->i.version);
-
 			break;
 
 		default:
 			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) {
-				err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart);
+				err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf);
 				if (unlikely(err))
 					goto free_out;
 			}
@@ -653,17 +1110,19 @@ static int jffs2_get_inode_nodes(struct 
 	}
 
 	spin_unlock(&c->erase_completion_lock);
-	*tnp = ret_tn;
-	*fdp = ret_fd;
 	kfree(buf);
 
+	f->highest_version = rii->highest_version;
+
 	dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n",
-			f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver);
+		      f->inocache->ino, rii->highest_version, rii->latest_mctime,
+		      rii->mctime_ver);
 	return 0;
 
  free_out:
-	jffs2_free_tmp_dnode_info_list(&ret_tn);
-	jffs2_free_full_dirent_list(ret_fd);
+	jffs2_free_tmp_dnode_info_list(&rii->tn_root);
+	jffs2_free_full_dirent_list(rii->fds);
+	rii->fds = NULL;
 	kfree(buf);
 	return err;
 }
@@ -672,20 +1131,17 @@ static int jffs2_do_read_inode_internal(
 					struct jffs2_inode_info *f,
 					struct jffs2_raw_inode *latest_node)
 {
-	struct jffs2_tmp_dnode_info *tn;
-	struct rb_root tn_list;
-	struct rb_node *rb, *repl_rb;
-	struct jffs2_full_dirent *fd_list;
-	struct jffs2_full_dnode *fn, *first_fn = NULL;
-	uint32_t crc;
-	uint32_t latest_mctime, mctime_ver;
+	struct jffs2_readinode_info rii;
+	uint32_t crc, new_size;
 	size_t retlen;
 	int ret;
 
 	dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
 
+	memset(&rii, 0, sizeof(rii));
+
 	/* Grab all nodes relevant to this ino */
-	ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
+	ret = jffs2_get_inode_nodes(c, f, &rii);
 
 	if (ret) {
 		JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret);
@@ -693,74 +1149,42 @@ static int jffs2_do_read_inode_internal(
 			jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 		return ret;
 	}
-	f->dents = fd_list;
-
-	rb = rb_first(&tn_list);
 
-	while (rb) {
-		cond_resched();
-		tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb);
-		fn = tn->fn;
-		ret = 1;
-		dbg_readinode("consider node ver %u, phys offset "
-			"%#08x(%d), range %u-%u.\n", tn->version,
-			ref_offset(fn->raw), ref_flags(fn->raw),
-			fn->ofs, fn->ofs + fn->size);
-
-		if (fn->size) {
-			ret = jffs2_add_older_frag_to_fragtree(c, f, tn);
-			/* TODO: the error code isn't checked, check it */
-			jffs2_dbg_fragtree_paranoia_check_nolock(f);
-			BUG_ON(ret < 0);
-			if (!first_fn && ret == 0)
-				first_fn = fn;
-		} else if (!first_fn) {
-			first_fn = fn;
-			f->metadata = fn;
-			ret = 0; /* Prevent freeing the metadata update node */
-		} else
-			jffs2_mark_node_obsolete(c, fn->raw);
-
-		BUG_ON(rb->rb_left);
-		if (rb_parent(rb) && rb_parent(rb)->rb_left == rb) {
-			/* We were then left-hand child of our parent. We need
-			 * to move our own right-hand child into our place. */
-			repl_rb = rb->rb_right;
-			if (repl_rb)
-				rb_set_parent(repl_rb, rb_parent(rb));
-		} else
-			repl_rb = NULL;
-
-		rb = rb_next(rb);
-
-		/* Remove the spent tn from the tree; don't bother rebalancing
-		 * but put our right-hand child in our own place. */
-		if (rb_parent(&tn->rb)) {
-			if (rb_parent(&tn->rb)->rb_left == &tn->rb)
-				rb_parent(&tn->rb)->rb_left = repl_rb;
-			else if (rb_parent(&tn->rb)->rb_right == &tn->rb)
-				rb_parent(&tn->rb)->rb_right = repl_rb;
-			else BUG();
-		} else if (tn->rb.rb_right)
-			rb_set_parent(tn->rb.rb_right, NULL);
+	ret = jffs2_build_inode_fragtree(c, f, &rii);
+	if (ret) {
+		JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n",
+			    f->inocache->ino, ret);
+		if (f->inocache->state == INO_STATE_READING)
+			jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
+		jffs2_free_tmp_dnode_info_list(&rii.tn_root);
+		/* FIXME: We could at least crc-check them all */
+		if (rii.mdata_tn) {
+			jffs2_free_full_dnode(rii.mdata_tn->fn);
+			jffs2_free_tmp_dnode_info(rii.mdata_tn);
+			rii.mdata_tn = NULL;
+		}
+		return ret;
+	}
 
-		jffs2_free_tmp_dnode_info(tn);
-		if (ret) {
-			dbg_readinode("delete dnode %u-%u.\n",
-				fn->ofs, fn->ofs + fn->size);
-			jffs2_free_full_dnode(fn);
+	if (rii.mdata_tn) {
+		if (rii.mdata_tn->fn->raw == rii.latest_ref) {
+			f->metadata = rii.mdata_tn->fn;
+			jffs2_free_tmp_dnode_info(rii.mdata_tn);
+		} else {
+			jffs2_kill_tn(c, rii.mdata_tn);
 		}
+		rii.mdata_tn = NULL;
 	}
-	jffs2_dbg_fragtree_paranoia_check_nolock(f);
 
-	BUG_ON(first_fn && ref_obsolete(first_fn->raw));
+	f->dents = rii.fds;
 
-	fn = first_fn;
-	if (unlikely(!first_fn)) {
+	jffs2_dbg_fragtree_paranoia_check_nolock(f);
+
+	if (unlikely(!rii.latest_ref)) {
 		/* No data nodes for this inode. */
 		if (f->inocache->ino != 1) {
 			JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino);
-			if (!fd_list) {
+			if (!rii.fds) {
 				if (f->inocache->state == INO_STATE_READING)
 					jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 				return -EIO;
@@ -778,7 +1202,7 @@ static int jffs2_do_read_inode_internal(
 		return 0;
 	}
 
-	ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
+	ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node);
 	if (ret || retlen != sizeof(*latest_node)) {
 		JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
 			ret, retlen, sizeof(*latest_node));
@@ -791,7 +1215,7 @@ static int jffs2_do_read_inode_internal(
 	crc = crc32(0, latest_node, sizeof(*latest_node)-8);
 	if (crc != je32_to_cpu(latest_node->node_crc)) {
 		JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
-			f->inocache->ino, ref_offset(fn->raw));
+			f->inocache->ino, ref_offset(rii.latest_ref));
 		up(&f->sem);
 		jffs2_do_clear_inode(c, f);
 		return -EIO;
@@ -799,17 +1223,22 @@ static int jffs2_do_read_inode_internal(
 
 	switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
 	case S_IFDIR:
-		if (mctime_ver > je32_to_cpu(latest_node->version)) {
+		if (rii.mctime_ver > je32_to_cpu(latest_node->version)) {
 			/* The times in the latest_node are actually older than
 			   mctime in the latest dirent. Cheat. */
-			latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime);
+			latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime);
 		}
 		break;
 
 
 	case S_IFREG:
 		/* If it was a regular file, truncate it to the latest node's isize */
-		jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
+		new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
+		if (new_size != je32_to_cpu(latest_node->isize)) {
+			JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n",
+				      f->inocache->ino, je32_to_cpu(latest_node->isize), new_size);
+			latest_node->isize = cpu_to_je32(new_size);
+		}
 		break;
 
 	case S_IFLNK:
@@ -832,7 +1261,7 @@ static int jffs2_do_read_inode_internal(
 				return -ENOMEM;
 			}
 
-			ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
+			ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
 						je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);
 
 			if (ret  || retlen != je32_to_cpu(latest_node->csize)) {
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 7fb45bd..2a1c976 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -1,15 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $
- *
  */
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -636,16 +635,17 @@ scan_more:
 
 		if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
 			uint32_t inbuf_ofs;
-			uint32_t empty_start;
+			uint32_t empty_start, scan_end;
 
 			empty_start = ofs;
 			ofs += 4;
+			scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);
 
 			D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
 		more_empty:
 			inbuf_ofs = ofs - buf_ofs;
-			while (inbuf_ofs < buf_len) {
-				if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
+			while (inbuf_ofs < scan_end) {
+				if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) {
 					printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
 					       empty_start, ofs);
 					if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
@@ -666,7 +666,11 @@ scan_more:
 				D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
 				return BLK_STATE_CLEANMARKER;
 			}
-
+			if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */
+				scan_end = buf_len;
+				goto more_empty;
+			}
+			
 			/* See how much more there is to read in this eraseblock... */
 			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 			if (!buf_len) {
@@ -676,6 +680,8 @@ scan_more:
 					  empty_start));
 				break;
 			}
+			/* point never reaches here */
+			scan_end = buf_len;
 			D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
 			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 			if (err)
@@ -734,18 +740,8 @@ scan_more:
 			ofs += 4;
 			continue;
 		}
-		/* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */
-		if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) &&
-		    !je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) {
-			noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs);
-			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
-				return err;
-			ofs += 4;
-			continue;
-		}
 
-		if (ofs + je32_to_cpu(node->totlen) >
-		    jeb->offset + c->sector_size) {
+		if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
 			/* Eep. Node goes over the end of the erase block. */
 			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
 			       ofs, je32_to_cpu(node->totlen));
@@ -952,8 +948,7 @@ static int jffs2_scan_inode_node(struct 
 				 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
 {
 	struct jffs2_inode_cache *ic;
-	uint32_t ino = je32_to_cpu(ri->ino);
-	int err;
+	uint32_t crc, ino = je32_to_cpu(ri->ino);
 
 	D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
 
@@ -966,21 +961,22 @@ static int jffs2_scan_inode_node(struct 
 	   Which means that the _full_ amount of time to get to proper write mode with GC
 	   operational may actually be _longer_ than before. Sucks to be me. */
 
+	/* Check the node CRC in any case. */
+	crc = crc32(0, ri, sizeof(*ri)-8);
+	if (crc != je32_to_cpu(ri->node_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on "
+		       "node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(ri->node_crc), crc);
+		/*
+		 * We believe totlen because the CRC on the node
+		 * _header_ was OK, just the node itself failed.
+		 */
+		return jffs2_scan_dirty_space(c, jeb,
+					      PAD(je32_to_cpu(ri->totlen)));
+	}
+
 	ic = jffs2_get_ino_cache(c, ino);
 	if (!ic) {
-		/* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
-		   first node we found for this inode. Do a CRC check to protect against the former
-		   case */
-		uint32_t crc = crc32(0, ri, sizeof(*ri)-8);
-
-		if (crc != je32_to_cpu(ri->node_crc)) {
-			printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-			       ofs, je32_to_cpu(ri->node_crc), crc);
-			/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
-			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen)))))
-				return err;
-			return 0;
-		}
 		ic = jffs2_scan_make_ino_cache(c, ino);
 		if (!ic)
 			return -ENOMEM;
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index 52a9894..bc9f6ba 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 30f8884..d828b29 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -1,16 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
- *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
- *                     University of Szeged, Hungary
- *               2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright Â© 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                   Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                   Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                   University of Szeged, Hungary
+ *             2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
index 6bf1f6a..0c6669e 100644
--- a/fs/jffs2/summary.h
+++ b/fs/jffs2/summary.h
@@ -1,15 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
- *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
- *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
- *                     University of Szeged, Hungary
+ * Copyright Â© 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                   Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                   Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                   University of Szeged, Hungary
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $
- *
  */
 
 #ifndef JFFS2_SUMMARY_H
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index cc7e8e7..45368f8 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -49,8 +47,7 @@ static void jffs2_i_init_once(void * foo
 {
 	struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		init_MUTEX(&ei->sem);
 		inode_init_once(&ei->vfs_inode);
 	}
@@ -347,7 +344,7 @@ #endif
 #ifdef CONFIG_JFFS2_SUMMARY
 	       " (SUMMARY) "
 #endif
-	       " (C) 2001-2006 Red Hat, Inc.\n");
+	       " Â© 2001-2006 Red Hat, Inc.\n");
 
 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
 					     sizeof(struct jffs2_inode_info),
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 7e4882c..b7339c3 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -1,17 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $
- *
  */
 
-
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 4fac6dd..c556e85 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1,16 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
- * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
+ * Copyright Â© 2001-2007 Red Hat, Inc.
+ * Copyright Â© 2004 Thomas Gleixner <tglx@linutronix.de>
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -345,6 +343,9 @@ static void jffs2_wbuf_recover(struct jf
 		return;
 	}
 
+	/* The summary is not recovered, so it must be disabled for this erase block */
+	jffs2_sum_disable_collecting(c->summary);
+
 	ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
 	if (ret) {
 		printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
@@ -967,9 +968,9 @@ #define OOB_CM_SIZE 12
 
 static const struct jffs2_unknown_node oob_cleanmarker =
 {
-	.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
-	.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
-	.totlen = cpu_to_je32(8)
+	.magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK),
+	.nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
+	.totlen = constant_cpu_to_je32(8)
 };
 
 /*
@@ -1208,3 +1209,27 @@ int jffs2_nor_wbuf_flash_setup(struct jf
 void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
 	kfree(c->wbuf);
 }
+
+int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
+	c->cleanmarker_size = 0;
+
+	if (c->mtd->writesize == 1)
+		/* We do not need write-buffer */
+		return 0;
+
+	init_rwsem(&c->wbuf_sem);
+
+	c->wbuf_pagesize =  c->mtd->writesize;
+	c->wbuf_ofs = 0xFFFFFFFF;
+	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+	if (!c->wbuf)
+		return -ENOMEM;
+
+	printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
+
+	return 0;
+}
+
+void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) {
+	kfree(c->wbuf);
+}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 6717679..c9fe0ab 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $
- *
  */
 
 #include <linux/kernel.h>
@@ -507,8 +505,7 @@ int jffs2_do_unlink(struct jffs2_sb_info
 	uint32_t alloclen;
 	int ret;
 
-	if (1 /* alternative branch needs testing */ ||
-	    !jffs2_can_mark_obsolete(c)) {
+	if (!jffs2_can_mark_obsolete(c)) {
 		/* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
 
 		rd = jffs2_alloc_raw_dirent();
diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c
index c638ae1..b9276b1 100644
--- a/fs/jffs2/writev.c
+++ b/fs/jffs2/writev.c
@@ -1,14 +1,12 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright Â© 2001-2007 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $
- *
  */
 
 #include <linux/kernel.h>
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 4bb3f18..78fc088 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 06a5c69..3b0ff29 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #ifndef _JFFS2_FS_XATTR_H_
 #define _JFFS2_FS_XATTR_H_
 
diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c
index ed046e1..8ec5765 100644
--- a/fs/jffs2/xattr_trusted.c
+++ b/fs/jffs2/xattr_trusted.c
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/jffs2.h>
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c
index 2f8e9aa..40942bc 100644
--- a/fs/jffs2/xattr_user.c
+++ b/fs/jffs2/xattr_user.c
@@ -1,13 +1,14 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2006  NEC Corporation
+ * Copyright Â© 2006  NEC Corporation
  *
  * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
  */
+
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/jffs2.h>
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index e285022..3467dde 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -55,7 +55,6 @@ void jfs_read_inode(struct inode *inode)
 		inode->i_op = &jfs_file_inode_operations;
 		init_special_inode(inode, inode->i_mode, inode->i_rdev);
 	}
-	jfs_set_inode_flags(inode);
 }
 
 /*
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
index ed814b1..fe063af 100644
--- a/fs/jfs/ioctl.c
+++ b/fs/jfs/ioctl.c
@@ -59,6 +59,7 @@ int jfs_ioctl(struct inode * inode, stru
 
 	switch (cmd) {
 	case JFS_IOC_GETFLAGS:
+		jfs_get_inode_flags(jfs_inode);
 		flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
 		flags = jfs_map_ext2(flags, 0);
 		return put_user(flags, (int __user *) arg);
@@ -78,6 +79,7 @@ int jfs_ioctl(struct inode * inode, stru
 		if (!S_ISDIR(inode->i_mode))
 			flags &= ~JFS_DIRSYNC_FL;
 
+		jfs_get_inode_flags(jfs_inode);
 		oldflags = jfs_inode->mode2;
 
 		/*
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index aa5124b..c465607 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -3078,6 +3078,7 @@ static int copy_from_dinode(struct dinod
 
 	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
 	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
+	jfs_set_inode_flags(ip);
 
 	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
 	if (sbi->umask != -1) {
@@ -3174,6 +3175,7 @@ static void copy_to_dinode(struct dinode
 		dip->di_gid = cpu_to_le32(ip->i_gid);
 	else
 		dip->di_gid = cpu_to_le32(jfs_ip->saved_gid);
+	jfs_get_inode_flags(jfs_ip);
 	/*
 	 * mode2 is only needed for storing the higher order bits.
 	 * Trust i_mode for the lower order ones
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 4c67ed9..ed6574b 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -45,6 +45,24 @@ void jfs_set_inode_flags(struct inode *i
 		inode->i_flags |= S_SYNC;
 }
 
+void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip)
+{
+	unsigned int flags = jfs_ip->vfs_inode.i_flags;
+
+	jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_APPEND_FL | JFS_NOATIME_FL |
+			   JFS_DIRSYNC_FL | JFS_SYNC_FL);
+	if (flags & S_IMMUTABLE)
+		jfs_ip->mode2 |= JFS_IMMUTABLE_FL;
+	if (flags & S_APPEND)
+		jfs_ip->mode2 |= JFS_APPEND_FL;
+	if (flags & S_NOATIME)
+		jfs_ip->mode2 |= JFS_NOATIME_FL;
+	if (flags & S_DIRSYNC)
+		jfs_ip->mode2 |= JFS_DIRSYNC_FL;
+	if (flags & S_SYNC)
+		jfs_ip->mode2 |= JFS_SYNC_FL;
+}
+
 /*
  * NAME:	ialloc()
  *
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 6802837..2374b59 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -31,6 +31,7 @@ extern void jfs_truncate(struct inode *)
 extern void jfs_truncate_nolock(struct inode *, loff_t);
 extern void jfs_free_zero_link(struct inode *);
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
+extern void jfs_get_inode_flags(struct jfs_inode_info *);
 extern void jfs_set_inode_flags(struct inode *);
 extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index df48ece..ecf0488 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -45,7 +45,7 @@ do {							\
 		io_schedule();				\
 		lock_cmd;				\
 	}						\
-	current->state = TASK_RUNNING;			\
+	__set_current_state(TASK_RUNNING);			\
 	remove_wait_queue(&wq, &__wait);		\
 } while (0)
 
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 5065baa..6a3f00d 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -62,7 +62,6 @@
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/kthread.h>
 #include <linux/buffer_head.h>		/* for sync_blockdev() */
@@ -1590,7 +1589,7 @@ void jfs_flush_journal(struct jfs_log *l
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		LOGGC_UNLOCK(log);
 		schedule();
-		current->state = TASK_RUNNING;
+		__set_current_state(TASK_RUNNING);
 		LOGGC_LOCK(log);
 		remove_wait_queue(&target->gcwait, &__wait);
 	}
@@ -2354,14 +2353,15 @@ int jfsIOWait(void *arg)
 			lbmStartIO(bp);
 			spin_lock_irq(&log_redrive_lock);
 		}
-		spin_unlock_irq(&log_redrive_lock);
 
 		if (freezing(current)) {
+			spin_unlock_irq(&log_redrive_lock);
 			refrigerator();
 		} else {
 			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&log_redrive_lock);
 			schedule();
-			current->state = TASK_RUNNING;
+			__set_current_state(TASK_RUNNING);
 		}
 	} while (!kthread_should_stop());
 
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 58deae0..6b3acb0 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -184,8 +184,7 @@ static void init_once(void *foo, struct 
 {
 	struct metapage *mp = (struct metapage *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		mp->lid = 0;
 		mp->lsn = 0;
 		mp->flag = 0;
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 03893ac..25430d0 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -44,7 +44,6 @@
 
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/freezer.h>
 #include <linux/module.h>
@@ -136,7 +135,7 @@ static inline void TXN_SLEEP_DROP_LOCK(w
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	TXN_UNLOCK();
 	io_schedule();
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(event, &wait);
 }
 
@@ -2798,7 +2797,7 @@ int jfs_lazycommit(void *arg)
 			set_current_state(TASK_INTERRUPTIBLE);
 			LAZY_UNLOCK(flags);
 			schedule();
-			current->state = TASK_RUNNING;
+			__set_current_state(TASK_RUNNING);
 			remove_wait_queue(&jfs_commit_thread_wait, &wq);
 		}
 	} while (!kthread_should_stop());
@@ -2990,7 +2989,7 @@ int jfs_sync(void *arg)
 			set_current_state(TASK_INTERRUPTIBLE);
 			TXN_UNLOCK();
 			schedule();
-			current->state = TASK_RUNNING;
+			__set_current_state(TASK_RUNNING);
 		}
 	} while (!kthread_should_stop());
 
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 52d73d5..ea9dc3e 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -752,8 +752,7 @@ static void init_once(void *foo, struct 
 {
 	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
 		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
 		init_rwsem(&jfs_ip->rdwrlock);
diff --git a/fs/libfs.c b/fs/libfs.c
index d93842d..1247ee9 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -220,6 +220,12 @@ int get_sb_pseudo(struct file_system_typ
 	root = new_inode(s);
 	if (!root)
 		goto Enomem;
+	/*
+	 * since this is the first inode, make it number 1. New inodes created
+	 * after this must take care not to collide with it (by passing
+	 * max_reserved of 1 to iunique).
+	 */
+	root->i_ino = 1;
 	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
 	root->i_uid = root->i_gid = 0;
 	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
@@ -360,6 +366,11 @@ int simple_commit_write(struct file *fil
 	return 0;
 }
 
+/*
+ * the inodes created here are not hashed. If you use iunique to generate
+ * unique inode values later for this filesystem, then you must take care
+ * to pass it an appropriate max_reserved value to avoid collisions.
+ */
 int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files)
 {
 	struct inode *inode;
@@ -376,6 +387,11 @@ int simple_fill_super(struct super_block
 	inode = new_inode(s);
 	if (!inode)
 		return -ENOMEM;
+	/*
+	 * because the root inode is 1, the files array must not contain an
+	 * entry at index 1
+	 */
+	inode->i_ino = 1;
 	inode->i_mode = S_IFDIR | 0755;
 	inode->i_uid = inode->i_gid = 0;
 	inode->i_blocks = 0;
@@ -391,6 +407,13 @@ int simple_fill_super(struct super_block
 	for (i = 0; !files->name || files->name[0]; i++, files++) {
 		if (!files->name)
 			continue;
+
+		/* warn if it tries to conflict with the root inode */
+		if (unlikely(i == 1))
+			printk(KERN_WARNING "%s: %s passed in a files array"
+				"with an index of 1!\n", __func__,
+				s->s_type->name);
+
 		dentry = d_alloc_name(root, files->name);
 		if (!dentry)
 			goto out;
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index a5c019e..a10343b 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -12,7 +12,6 @@ #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/nfs_fs.h>
 #include <linux/utsname.h>
-#include <linux/smp_lock.h>
 #include <linux/freezer.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index eb243ed..2102e2d 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -225,16 +225,13 @@ #define SM_mon_sz	(SM_mon_id_sz+4)
 #define SM_monres_sz	2
 #define SM_unmonres_sz	1
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
-
 static struct rpc_procinfo	nsm_procedures[] = {
 [SM_MON] = {
 		.p_proc		= SM_MON,
 		.p_encode	= (kxdrproc_t) xdr_encode_mon,
 		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
-		.p_bufsiz	= MAX(SM_mon_sz, SM_monres_sz) << 2,
+		.p_arglen	= SM_mon_sz,
+		.p_replen	= SM_monres_sz,
 		.p_statidx	= SM_MON,
 		.p_name		= "MONITOR",
 	},
@@ -242,7 +239,8 @@ static struct rpc_procinfo	nsm_procedure
 		.p_proc		= SM_UNMON,
 		.p_encode	= (kxdrproc_t) xdr_encode_unmon,
 		.p_decode	= (kxdrproc_t) xdr_decode_stat,
-		.p_bufsiz	= MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
+		.p_arglen	= SM_mon_id_sz,
+		.p_replen	= SM_unmonres_sz,
 		.p_statidx	= SM_UNMON,
 		.p_name		= "UNMONITOR",
 	},
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 47a66aa..bf27b6c 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -99,7 +99,9 @@ nlm4svc_proc_test(struct svc_rqst *rqstp
 		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);
+	resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -143,6 +145,8 @@ #endif
 	/* Now try to lock the file */
 	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
 					argp->block, &argp->cookie);
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf51f84..b3efa45 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -173,7 +173,7 @@ found:
  */
 static inline struct nlm_block *
 nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
-				struct nlm_lock *lock, struct nlm_cookie *cookie)
+		struct nlm_lock *lock, struct nlm_cookie *cookie)
 {
 	struct nlm_block	*block;
 	struct nlm_host		*host;
@@ -210,6 +210,7 @@ nlmsvc_create_block(struct svc_rqst *rqs
 	block->b_daemon = rqstp->rq_server;
 	block->b_host   = host;
 	block->b_file   = file;
+	block->b_fl = NULL;
 	file->f_count++;
 
 	/* Add to file's list of blocks */
@@ -261,6 +262,7 @@ static void nlmsvc_free_block(struct kre
 	nlmsvc_freegrantargs(block->b_call);
 	nlm_release_call(block->b_call);
 	nlm_release_file(block->b_file);
+	kfree(block->b_fl);
 	kfree(block);
 }
 
@@ -331,6 +333,31 @@ static void nlmsvc_freegrantargs(struct 
 }
 
 /*
+ * Deferred lock request handling for non-blocking lock
+ */
+static u32
+nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
+{
+	u32 status = nlm_lck_denied_nolocks;
+
+	block->b_flags |= B_QUEUED;
+
+	nlmsvc_insert_block(block, NLM_TIMEOUT);
+
+	block->b_cache_req = &rqstp->rq_chandle;
+	if (rqstp->rq_chandle.defer) {
+		block->b_deferred_req =
+			rqstp->rq_chandle.defer(block->b_cache_req);
+		if (block->b_deferred_req != NULL)
+			status = nlm_drop_reply;
+	}
+	dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
+		block, block->b_flags, status);
+
+	return status;
+}
+
+/*
  * Attempt to establish a lock, and if it can't be granted, block it
  * if required.
  */
@@ -338,7 +365,7 @@ __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;
+	struct nlm_block	*block = NULL;
 	int			error;
 	__be32			ret;
 
@@ -351,29 +378,58 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
 				wait);
 
 
-	lock->fl.fl_flags &= ~FL_SLEEP;
-again:
 	/* Lock file against concurrent access */
 	mutex_lock(&file->f_mutex);
-	/* Get existing block (in case client is busy-waiting) */
+	/* Get existing block (in case client is busy-waiting)
+	 * or create new block
+	 */
 	block = nlmsvc_lookup_block(file, lock);
 	if (block == NULL) {
-		if (newblock != NULL)
-			lock = &newblock->b_call->a_args.lock;
-	} else
+		block = nlmsvc_create_block(rqstp, file, lock, cookie);
+		ret = nlm_lck_denied_nolocks;
+		if (block == NULL)
+			goto out;
 		lock = &block->b_call->a_args.lock;
+	} else
+		lock->fl.fl_flags &= ~FL_SLEEP;
 
-	error = posix_lock_file(file->f_file, &lock->fl);
-	lock->fl.fl_flags &= ~FL_SLEEP;
+	if (block->b_flags & B_QUEUED) {
+		dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
+							block, block->b_flags);
+		if (block->b_granted) {
+			nlmsvc_unlink_block(block);
+			ret = nlm_granted;
+			goto out;
+		}
+		if (block->b_flags & B_TIMED_OUT) {
+			nlmsvc_unlink_block(block);
+			ret = nlm_lck_denied;
+			goto out;
+		}
+		ret = nlm_drop_reply;
+		goto out;
+	}
 
-	dprintk("lockd: posix_lock_file returned %d\n", error);
+	if (!wait)
+		lock->fl.fl_flags &= ~FL_SLEEP;
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
+	lock->fl.fl_flags &= ~FL_SLEEP;
 
+	dprintk("lockd: vfs_lock_file returned %d\n", error);
 	switch(error) {
 		case 0:
 			ret = nlm_granted;
 			goto out;
 		case -EAGAIN:
+			ret = nlm_lck_denied;
 			break;
+		case -EINPROGRESS:
+			if (wait)
+				break;
+			/* Filesystem lock operation is in progress
+			   Add it to the queue waiting for callback */
+			ret = nlmsvc_defer_lock_rqst(rqstp, block);
+			goto out;
 		case -EDEADLK:
 			ret = nlm_deadlock;
 			goto out;
@@ -387,26 +443,11 @@ again:
 		goto out;
 
 	ret = nlm_lck_blocked;
-	if (block != NULL)
-		goto out;
-
-	/* 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_mutex as nlmsvc_create_block may try to
-	 * to claim it while doing host garbage collection */
-	if (newblock == NULL) {
-		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;
-		goto again;
-	}
 
 	/* Append to list of blocked */
-	nlmsvc_insert_block(newblock, NLM_NEVER);
+	nlmsvc_insert_block(block, NLM_NEVER);
 out:
 	mutex_unlock(&file->f_mutex);
-	nlmsvc_release_block(newblock);
 	nlmsvc_release_block(block);
 	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
 	return ret;
@@ -416,9 +457,14 @@ out:
  * Test for presence of a conflicting lock.
  */
 __be32
-nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
-				       struct nlm_lock *conflock)
+nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+		struct nlm_lock *lock, struct nlm_lock *conflock,
+		struct nlm_cookie *cookie)
 {
+	struct nlm_block 	*block = NULL;
+	int			error;
+	__be32			ret;
+
 	dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
 				file->f_file->f_path.dentry->d_inode->i_sb->s_id,
 				file->f_file->f_path.dentry->d_inode->i_ino,
@@ -426,19 +472,70 @@ nlmsvc_testlock(struct nlm_file *file, s
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end);
 
-	if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) {
-		dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
-				conflock->fl.fl_type,
-				(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;
+	/* Get existing block (in case client is busy-waiting) */
+	block = nlmsvc_lookup_block(file, lock);
+
+	if (block == NULL) {
+		struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+
+		if (conf == NULL)
+			return nlm_granted;
+		block = nlmsvc_create_block(rqstp, file, lock, cookie);
+		if (block == NULL) {
+			kfree(conf);
+			return nlm_granted;
+		}
+		block->b_fl = conf;
+	}
+	if (block->b_flags & B_QUEUED) {
+		dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
+			block, block->b_flags, block->b_fl);
+		if (block->b_flags & B_TIMED_OUT) {
+			nlmsvc_unlink_block(block);
+			return nlm_lck_denied;
+		}
+		if (block->b_flags & B_GOT_CALLBACK) {
+			if (block->b_fl != NULL
+					&& block->b_fl->fl_type != F_UNLCK) {
+				lock->fl = *block->b_fl;
+				goto conf_lock;
+			}
+			else {
+				nlmsvc_unlink_block(block);
+				return nlm_granted;
+			}
+		}
+		return nlm_drop_reply;
 	}
 
-	return nlm_granted;
+	error = vfs_test_lock(file->f_file, &lock->fl);
+	if (error == -EINPROGRESS)
+		return nlmsvc_defer_lock_rqst(rqstp, block);
+	if (error) {
+		ret = nlm_lck_denied_nolocks;
+		goto out;
+	}
+	if (lock->fl.fl_type == F_UNLCK) {
+		ret = nlm_granted;
+		goto out;
+	}
+
+conf_lock:
+	dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+		lock->fl.fl_type, (long long)lock->fl.fl_start,
+		(long long)lock->fl.fl_end);
+	conflock->caller = "somehost";	/* FIXME */
+	conflock->len = strlen(conflock->caller);
+	conflock->oh.len = 0;		/* don't return OH info */
+	conflock->svid = lock->fl.fl_pid;
+	conflock->fl.fl_type = lock->fl.fl_type;
+	conflock->fl.fl_start = lock->fl.fl_start;
+	conflock->fl.fl_end = lock->fl.fl_end;
+	ret = nlm_lck_denied;
+out:
+	if (block)
+		nlmsvc_release_block(block);
+	return ret;
 }
 
 /*
@@ -464,7 +561,7 @@ nlmsvc_unlock(struct nlm_file *file, str
 	nlmsvc_cancel_blocked(file, lock);
 
 	lock->fl.fl_type = F_UNLCK;
-	error = posix_lock_file(file->f_file, &lock->fl);
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 
 	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
 }
@@ -493,6 +590,8 @@ nlmsvc_cancel_blocked(struct nlm_file *f
 	block = nlmsvc_lookup_block(file, lock);
 	mutex_unlock(&file->f_mutex);
 	if (block != NULL) {
+		vfs_cancel_lock(block->b_file->f_file,
+				&block->b_call->a_args.lock.fl);
 		status = nlmsvc_unlink_block(block);
 		nlmsvc_release_block(block);
 	}
@@ -500,6 +599,63 @@ nlmsvc_cancel_blocked(struct nlm_file *f
 }
 
 /*
+ * This is a callback from the filesystem for VFS file lock requests.
+ * It will be used if fl_grant is defined and the filesystem can not
+ * respond to the request immediately.
+ * For GETLK request it will copy the reply to the nlm_block.
+ * For SETLK or SETLKW request it will get the local posix lock.
+ * In all cases it will move the block to the head of nlm_blocked q where
+ * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
+ * deferred rpc for GETLK and SETLK.
+ */
+static void
+nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
+			     int result)
+{
+	block->b_flags |= B_GOT_CALLBACK;
+	if (result == 0)
+		block->b_granted = 1;
+	else
+		block->b_flags |= B_TIMED_OUT;
+	if (conf) {
+		if (block->b_fl)
+			locks_copy_lock(block->b_fl, conf);
+	}
+}
+
+static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
+					int result)
+{
+	struct nlm_block *block;
+	int rc = -ENOENT;
+
+	lock_kernel();
+	list_for_each_entry(block, &nlm_blocked, b_list) {
+		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
+			dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
+							block, block->b_flags);
+			if (block->b_flags & B_QUEUED) {
+				if (block->b_flags & B_TIMED_OUT) {
+					rc = -ENOLCK;
+					break;
+				}
+				nlmsvc_update_deferred_block(block, conf, result);
+			} else if (result == 0)
+				block->b_granted = 1;
+
+			nlmsvc_insert_block(block, 0);
+			svc_wake_up(block->b_daemon);
+			rc = 0;
+			break;
+		}
+	}
+	unlock_kernel();
+	if (rc == -ENOENT)
+		printk(KERN_WARNING "lockd: grant for unknown block\n");
+	return rc;
+}
+
+/*
  * Unblock a blocked lock request. This is a callback invoked from the
  * VFS layer when a lock on which we blocked is removed.
  *
@@ -531,6 +687,7 @@ static int nlmsvc_same_owner(struct file
 struct lock_manager_operations nlmsvc_lock_operations = {
 	.fl_compare_owner = nlmsvc_same_owner,
 	.fl_notify = nlmsvc_notify_blocked,
+	.fl_grant = nlmsvc_grant_deferred,
 };
 
 /*
@@ -553,6 +710,8 @@ nlmsvc_grant_blocked(struct nlm_block *b
 
 	dprintk("lockd: grant blocked lock %p\n", block);
 
+	kref_get(&block->b_count);
+
 	/* Unlink block request from list */
 	nlmsvc_unlink_block(block);
 
@@ -566,20 +725,23 @@ nlmsvc_grant_blocked(struct nlm_block *b
 
 	/* Try the lock operation again */
 	lock->fl.fl_flags |= FL_SLEEP;
-	error = posix_lock_file(file->f_file, &lock->fl);
+	error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
 	lock->fl.fl_flags &= ~FL_SLEEP;
 
 	switch (error) {
 	case 0:
 		break;
 	case -EAGAIN:
-		dprintk("lockd: lock still blocked\n");
+	case -EINPROGRESS:
+		dprintk("lockd: lock still blocked error %d\n", error);
 		nlmsvc_insert_block(block, NLM_NEVER);
+		nlmsvc_release_block(block);
 		return;
 	default:
 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 				-error, __FUNCTION__);
 		nlmsvc_insert_block(block, 10 * HZ);
+		nlmsvc_release_block(block);
 		return;
 	}
 
@@ -592,7 +754,6 @@ callback:
 	nlmsvc_insert_block(block, 30 * HZ);
 
 	/* Call the client */
-	kref_get(&block->b_count);
 	nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops);
 }
 
@@ -665,6 +826,23 @@ nlmsvc_grant_reply(struct nlm_cookie *co
 	nlmsvc_release_block(block);
 }
 
+/* Helper function to handle retry of a deferred block.
+ * If it is a blocking lock, call grant_blocked.
+ * For a non-blocking lock or test lock, revisit the request.
+ */
+static void
+retry_deferred_block(struct nlm_block *block)
+{
+	if (!(block->b_flags & B_GOT_CALLBACK))
+		block->b_flags |= B_TIMED_OUT;
+	nlmsvc_insert_block(block, NLM_TIMEOUT);
+	dprintk("revisit block %p flags %d\n",	block, block->b_flags);
+	if (block->b_deferred_req) {
+		block->b_deferred_req->revisit(block->b_deferred_req, 0);
+		block->b_deferred_req = NULL;
+	}
+}
+
 /*
  * Retry all blocked locks that have been notified. This is where lockd
  * picks up locks that can be granted, or grant notifications that must
@@ -688,9 +866,12 @@ nlmsvc_retry_blocked(void)
 
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			block, block->b_when);
-		kref_get(&block->b_count);
-		nlmsvc_grant_blocked(block);
-		nlmsvc_release_block(block);
+		if (block->b_flags & B_QUEUED) {
+			dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
+				block, block->b_granted, block->b_flags);
+			retry_deferred_block(block);
+		} else
+			nlmsvc_grant_blocked(block);
 	}
 
 	return timeout;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 31cb484..9cd5c8b 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -33,6 +33,7 @@ cast_to_nlm(__be32 status, u32 vers)
 		case nlm_lck_denied_nolocks:
 		case nlm_lck_blocked:
 		case nlm_lck_denied_grace_period:
+		case nlm_drop_reply:
 			break;
 		case nlm4_deadlock:
 			status = nlm_lck_denied;
@@ -127,7 +128,9 @@ nlmsvc_proc_test(struct svc_rqst *rqstp,
 		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));
+	resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: TEST          status %d vers %d\n",
 		ntohl(resp->status), rqstp->rq_vers);
@@ -172,6 +175,8 @@ #endif
 	/* Now try to lock the file */
 	resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
 					       argp->block, &argp->cookie));
+	if (resp->status == nlm_drop_reply)
+		return rpc_drop_reply;
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c0df00c..84ebba3 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -182,7 +182,7 @@ again:
 			lock.fl_type  = F_UNLCK;
 			lock.fl_start = 0;
 			lock.fl_end   = OFFSET_MAX;
-			if (posix_lock_file(file->f_file, &lock) < 0) {
+			if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
 				return 1;
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 34dae5d..9702956 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -510,17 +510,20 @@ nlmclt_decode_res(struct rpc_rqst *req, 
 	return 0;
 }
 
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
 /*
  * Buffer requirements for NLM
  */
 #define NLM_void_sz		0
 #define NLM_cookie_sz		1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#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_caller_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM_owner_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 #define NLM_fhandle_sz		1+XDR_QUADLEN(NFS2_FHSIZE)
-#define NLM_lock_sz		3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
-#define NLM_holder_sz		4+NLM_netobj_sz
+#define NLM_lock_sz		3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
+#define NLM_holder_sz		4+NLM_owner_sz
 
 #define NLM_testargs_sz		NLM_cookie_sz+1+NLM_lock_sz
 #define NLM_lockargs_sz		NLM_cookie_sz+4+NLM_lock_sz
@@ -531,10 +534,6 @@ #define NLM_testres_sz		NLM_cookie_sz+1+
 #define NLM_res_sz		NLM_cookie_sz+1
 #define NLM_norep_sz		0
 
-#ifndef MAX
-# define MAX(a, b)		(((a) > (b))? (a) : (b))
-#endif
-
 /*
  * For NLM, a void procedure really returns nothing
  */
@@ -545,7 +544,8 @@ #define PROC(proc, argtype, restype)	\
 	.p_proc      = NLMPROC_##proc,					\
 	.p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,		\
 	.p_decode    = (kxdrproc_t) nlmclt_decode_##restype,		\
-	.p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,	\
+	.p_arglen    = NLM_##argtype##_sz,				\
+	.p_replen    = NLM_##restype##_sz,				\
 	.p_statidx   = NLMPROC_##proc,					\
 	.p_name      = #proc,						\
 	}
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index a782405..ce1efdb 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -516,17 +516,24 @@ nlm4clt_decode_res(struct rpc_rqst *req,
 	return 0;
 }
 
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+#  error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
+#if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
+#  error "NLM host name cannot be larger than NLM's maximum string length!"
+#endif
+
 /*
  * Buffer requirements for NLM
  */
 #define NLM4_void_sz		0
 #define NLM4_cookie_sz		1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM4_caller_sz		1+XDR_QUADLEN(NLM_MAXSTRLEN)
-#define NLM4_netobj_sz		1+XDR_QUADLEN(XDR_MAX_NETOBJ)
-/* #define NLM4_owner_sz		1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_caller_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM4_owner_sz		1+XDR_QUADLEN(NLMCLNT_OHSIZE)
 #define NLM4_fhandle_sz		1+XDR_QUADLEN(NFS3_FHSIZE)
-#define NLM4_lock_sz		5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
-#define NLM4_holder_sz		6+NLM4_netobj_sz
+#define NLM4_lock_sz		5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz		6+NLM4_owner_sz
 
 #define NLM4_testargs_sz	NLM4_cookie_sz+1+NLM4_lock_sz
 #define NLM4_lockargs_sz	NLM4_cookie_sz+4+NLM4_lock_sz
@@ -537,10 +544,6 @@ #define NLM4_testres_sz		NLM4_cookie_sz+
 #define NLM4_res_sz		NLM4_cookie_sz+1
 #define NLM4_norep_sz		0
 
-#ifndef MAX
-# define MAX(a,b)		(((a) > (b))? (a) : (b))
-#endif
-
 /*
  * For NLM, a void procedure really returns nothing
  */
@@ -551,7 +554,8 @@ #define PROC(proc, argtype, restype)				
 	.p_proc      = NLMPROC_##proc,					\
 	.p_encode    = (kxdrproc_t) nlm4clt_encode_##argtype,		\
 	.p_decode    = (kxdrproc_t) nlm4clt_decode_##restype,		\
-	.p_bufsiz    = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,	\
+	.p_arglen    = NLM4_##argtype##_sz,				\
+	.p_replen    = NLM4_##restype##_sz,				\
 	.p_statidx   = NLMPROC_##proc,					\
 	.p_name      = #proc,						\
 	}
diff --git a/fs/locks.c b/fs/locks.c
index 52a8100..671a034 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -203,8 +203,7 @@ static void init_once(void *foo, struct 
 {
 	struct file_lock *lock = (struct file_lock *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
-					SLAB_CTOR_CONSTRUCTOR)
+	if (!(flags & SLAB_CTOR_CONSTRUCTOR))
 		return;
 
 	locks_init_lock(lock);
@@ -666,11 +665,11 @@ static int locks_block_on_timeout(struct
 }
 
 int
-posix_test_lock(struct file *filp, struct file_lock *fl,
-		struct file_lock *conflock)
+posix_test_lock(struct file *filp, struct file_lock *fl)
 {
 	struct file_lock *cfl;
 
+	fl->fl_type = F_UNLCK;
 	lock_kernel();
 	for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
 		if (!IS_POSIX(cfl))
@@ -679,7 +678,7 @@ posix_test_lock(struct file *filp, struc
 			break;
 	}
 	if (cfl) {
-		__locks_copy_lock(conflock, cfl);
+		__locks_copy_lock(fl, cfl);
 		unlock_kernel();
 		return 1;
 	}
@@ -801,7 +800,7 @@ out:
 	return error;
 }
 
-static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
+static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
 {
 	struct file_lock *fl;
 	struct file_lock *new_fl = NULL;
@@ -1007,6 +1006,7 @@ static int __posix_lock_file_conf(struct
  * posix_lock_file - Apply a POSIX-style lock to a file
  * @filp: The file to apply the lock to
  * @fl: The lock to be applied
+ * @conflock: Place to return a copy of the conflicting lock, if found.
  *
  * Add a POSIX style lock to a file.
  * We merge adjacent & overlapping locks whenever possible.
@@ -1016,26 +1016,12 @@ static int __posix_lock_file_conf(struct
  * whether or not a lock was successfully freed by testing the return
  * value for -ENOENT.
  */
-int posix_lock_file(struct file *filp, struct file_lock *fl)
-{
-	return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
-}
-EXPORT_SYMBOL(posix_lock_file);
-
-/**
- * posix_lock_file_conf - Apply a POSIX-style lock to a file
- * @filp: The file to apply the lock to
- * @fl: The lock to be applied
- * @conflock: Place to return a copy of the conflicting lock, if found.
- *
- * Except for the conflock parameter, acts just like posix_lock_file.
- */
-int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
+int posix_lock_file(struct file *filp, struct file_lock *fl,
 			struct file_lock *conflock)
 {
-	return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock);
+	return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
 }
-EXPORT_SYMBOL(posix_lock_file_conf);
+EXPORT_SYMBOL(posix_lock_file);
 
 /**
  * posix_lock_file_wait - Apply a POSIX-style lock to a file
@@ -1051,7 +1037,7 @@ int posix_lock_file_wait(struct file *fi
 	int error;
 	might_sleep ();
 	for (;;) {
-		error = posix_lock_file(filp, fl);
+		error = posix_lock_file(filp, fl, NULL);
 		if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
 			break;
 		error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1123,7 +1109,7 @@ int locks_mandatory_area(int read_write,
 	fl.fl_end = offset + count - 1;
 
 	for (;;) {
-		error = __posix_lock_file_conf(inode, &fl, NULL);
+		error = __posix_lock_file(inode, &fl, NULL);
 		if (error != -EAGAIN)
 			break;
 		if (!(fl.fl_flags & FL_SLEEP))
@@ -1611,12 +1597,62 @@ asmlinkage long sys_flock(unsigned int f
 	return error;
 }
 
+/**
+ * vfs_test_lock - test file byte range lock
+ * @filp: The file to test lock for
+ * @fl: The lock to test
+ * @conf: Place to return a copy of the conflicting lock, if found
+ *
+ * Returns -ERRNO on failure.  Indicates presence of conflicting lock by
+ * setting conf->fl_type to something other than F_UNLCK.
+ */
+int vfs_test_lock(struct file *filp, struct file_lock *fl)
+{
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, F_GETLK, fl);
+	posix_test_lock(filp, fl);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vfs_test_lock);
+
+static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
+{
+	flock->l_pid = fl->fl_pid;
+#if BITS_PER_LONG == 32
+	/*
+	 * Make sure we can represent the posix lock via
+	 * legacy 32bit flock.
+	 */
+	if (fl->fl_start > OFFT_OFFSET_MAX)
+		return -EOVERFLOW;
+	if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX)
+		return -EOVERFLOW;
+#endif
+	flock->l_start = fl->fl_start;
+	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
+		fl->fl_end - fl->fl_start + 1;
+	flock->l_whence = 0;
+	return 0;
+}
+
+#if BITS_PER_LONG == 32
+static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
+{
+	flock->l_pid = fl->fl_pid;
+	flock->l_start = fl->fl_start;
+	flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
+		fl->fl_end - fl->fl_start + 1;
+	flock->l_whence = 0;
+	flock->l_type = fl->fl_type;
+}
+#endif
+
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
 int fcntl_getlk(struct file *filp, struct flock __user *l)
 {
-	struct file_lock *fl, cfl, file_lock;
+	struct file_lock file_lock;
 	struct flock flock;
 	int error;
 
@@ -1631,38 +1667,15 @@ int fcntl_getlk(struct file *filp, struc
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-		if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-			file_lock.fl_ops->fl_release_private(&file_lock);
-		if (error < 0)
-			goto out;
-		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-	} else {
-		fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
-	}
+	error = vfs_test_lock(filp, &file_lock);
+	if (error)
+		goto out;
  
-	flock.l_type = F_UNLCK;
-	if (fl != NULL) {
-		flock.l_pid = fl->fl_pid;
-#if BITS_PER_LONG == 32
-		/*
-		 * Make sure we can represent the posix lock via
-		 * legacy 32bit flock.
-		 */
-		error = -EOVERFLOW;
-		if (fl->fl_start > OFFT_OFFSET_MAX)
-			goto out;
-		if ((fl->fl_end != OFFSET_MAX)
-		    && (fl->fl_end > OFFT_OFFSET_MAX))
+	flock.l_type = file_lock.fl_type;
+	if (file_lock.fl_type != F_UNLCK) {
+		error = posix_lock_to_flock(&flock, &file_lock);
+		if (error)
 			goto out;
-#endif
-		flock.l_start = fl->fl_start;
-		flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-			fl->fl_end - fl->fl_start + 1;
-		flock.l_whence = 0;
-		flock.l_type = fl->fl_type;
 	}
 	error = -EFAULT;
 	if (!copy_to_user(l, &flock, sizeof(flock)))
@@ -1671,6 +1684,48 @@ out:
 	return error;
 }
 
+/**
+ * vfs_lock_file - file byte range lock
+ * @filp: The file to apply the lock to
+ * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
+ * @fl: The lock to be applied
+ * @conf: Place to return a copy of the conflicting lock, if found.
+ *
+ * A caller that doesn't care about the conflicting lock may pass NULL
+ * as the final argument.
+ *
+ * If the filesystem defines a private ->lock() method, then @conf will
+ * be left unchanged; so a caller that cares should initialize it to
+ * some acceptable default.
+ *
+ * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
+ * locks, the ->lock() interface may return asynchronously, before the lock has
+ * been granted or denied by the underlying filesystem, if (and only if)
+ * fl_grant is set. Callers expecting ->lock() to return asynchronously
+ * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
+ * the request is for a blocking lock. When ->lock() does return asynchronously,
+ * it must return -EINPROGRESS, and call ->fl_grant() when the lock
+ * request completes.
+ * If the request is for non-blocking lock the file system should return
+ * -EINPROGRESS then try to get the lock and call the callback routine with
+ * the result. If the request timed out the callback routine will return a
+ * nonzero return code and the file system should release the lock. The file
+ * system is also responsible to keep a corresponding posix lock when it
+ * grants a lock so the VFS can find out which locks are locally held and do
+ * the correct lock cleanup when required.
+ * The underlying filesystem must not drop the kernel lock or call
+ * ->fl_grant() before returning to the caller with a -EINPROGRESS
+ * return code.
+ */
+int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
+{
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, cmd, fl);
+	else
+		return posix_lock_file(filp, fl, conf);
+}
+EXPORT_SYMBOL_GPL(vfs_lock_file);
+
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
@@ -1733,21 +1788,17 @@ again:
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		error = filp->f_op->lock(filp, cmd, file_lock);
-	else {
-		for (;;) {
-			error = posix_lock_file(filp, file_lock);
-			if ((error != -EAGAIN) || (cmd == F_SETLK))
-				break;
-			error = wait_event_interruptible(file_lock->fl_wait,
-					!file_lock->fl_next);
-			if (!error)
-				continue;
-
-			locks_delete_block(file_lock);
+	for (;;) {
+		error = vfs_lock_file(filp, cmd, file_lock, NULL);
+		if (error != -EAGAIN || cmd == F_SETLK)
 			break;
-		}
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		locks_delete_block(file_lock);
+		break;
 	}
 
 	/*
@@ -1770,7 +1821,7 @@ #if BITS_PER_LONG == 32
  */
 int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 {
-	struct file_lock *fl, cfl, file_lock;
+	struct file_lock file_lock;
 	struct flock64 flock;
 	int error;
 
@@ -1785,27 +1836,14 @@ int fcntl_getlk64(struct file *filp, str
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-		if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-			file_lock.fl_ops->fl_release_private(&file_lock);
-		if (error < 0)
-			goto out;
-		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-	} else {
-		fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
-	}
- 
-	flock.l_type = F_UNLCK;
-	if (fl != NULL) {
-		flock.l_pid = fl->fl_pid;
-		flock.l_start = fl->fl_start;
-		flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-			fl->fl_end - fl->fl_start + 1;
-		flock.l_whence = 0;
-		flock.l_type = fl->fl_type;
-	}
+	error = vfs_test_lock(filp, &file_lock);
+	if (error)
+		goto out;
+
+	flock.l_type = file_lock.fl_type;
+	if (file_lock.fl_type != F_UNLCK)
+		posix_lock_to_flock64(&flock, &file_lock);
+
 	error = -EFAULT;
 	if (!copy_to_user(l, &flock, sizeof(flock)))
 		error = 0;
@@ -1876,21 +1914,17 @@ again:
 	if (error)
 		goto out;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		error = filp->f_op->lock(filp, cmd, file_lock);
-	else {
-		for (;;) {
-			error = posix_lock_file(filp, file_lock);
-			if ((error != -EAGAIN) || (cmd == F_SETLK64))
-				break;
-			error = wait_event_interruptible(file_lock->fl_wait,
-					!file_lock->fl_next);
-			if (!error)
-				continue;
-
-			locks_delete_block(file_lock);
+	for (;;) {
+		error = vfs_lock_file(filp, cmd, file_lock, NULL);
+		if (error != -EAGAIN || cmd == F_SETLK64)
 			break;
-		}
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		locks_delete_block(file_lock);
+		break;
 	}
 
 	/*
@@ -1935,10 +1969,7 @@ void locks_remove_posix(struct file *fil
 	lock.fl_ops = NULL;
 	lock.fl_lmops = NULL;
 
-	if (filp->f_op && filp->f_op->lock != NULL)
-		filp->f_op->lock(filp, F_SETLK, &lock);
-	else
-		posix_lock_file(filp, &lock);
+	vfs_lock_file(filp, F_SETLK, &lock, NULL);
 
 	if (lock.fl_ops && lock.fl_ops->fl_release_private)
 		lock.fl_ops->fl_release_private(&lock);
@@ -2015,6 +2046,22 @@ posix_unblock_lock(struct file *filp, st
 
 EXPORT_SYMBOL(posix_unblock_lock);
 
+/**
+ * vfs_cancel_lock - file byte range unblock lock
+ * @filp: The file to apply the unblock to
+ * @fl: The lock to be unblocked
+ *
+ * Used by lock managers to cancel blocked requests
+ */
+int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
+{
+	if (filp->f_op && filp->f_op->lock)
+		return filp->f_op->lock(filp, F_CANCELLK, fl);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(vfs_cancel_lock);
+
 static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
 {
 	struct inode *inode = NULL;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index cb4cb57..e207cbe 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -65,7 +65,6 @@ static struct page * dir_get_page(struct
 	struct address_space *mapping = dir->i_mapping;
 	struct page *page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
 		if (!PageUptodate(page))
 			goto fail;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 92e383a..2f4d43a 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -73,8 +73,7 @@ static void init_once(void * foo, struct
 {
 	struct minix_inode_info *ei = (struct minix_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/mpage.c b/fs/mpage.c
index 692a3e5..fa2441f 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -663,12 +663,7 @@ confused:
 	/*
 	 * The caller has a ref on the inode, so *mapping is stable
 	 */
-	if (*ret) {
-		if (*ret == -ENOSPC)
-			set_bit(AS_ENOSPC, &mapping->flags);
-		else
-			set_bit(AS_EIO, &mapping->flags);
-	}
+	mapping_set_error(mapping, *ret);
 out:
 	return bio;
 }
@@ -776,14 +771,7 @@ retry:
 
 			if (writepage) {
 				ret = (*writepage)(page, wbc);
-				if (ret) {
-					if (ret == -ENOSPC)
-						set_bit(AS_ENOSPC,
-							&mapping->flags);
-					else
-						set_bit(AS_EIO,
-							&mapping->flags);
-				}
+				mapping_set_error(mapping, ret);
 			} else {
 				bio = __mpage_writepage(bio, page, get_block,
 						&last_block_in_bio, &ret, wbc,
diff --git a/fs/namei.c b/fs/namei.c
index ee60cc4..856b2f5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -22,7 +22,6 @@ #include <linux/namei.h>
 #include <linux/quotaops.h>
 #include <linux/pagemap.h>
 #include <linux/fsnotify.h>
-#include <linux/smp_lock.h>
 #include <linux/personality.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
@@ -1243,22 +1242,13 @@ int __user_path_lookup_open(const char _
 	return err;
 }
 
-/*
- * Restricted form of lookup. Doesn't follow links, single-component only,
- * needs parent already locked. Doesn't follow mounts.
- * SMP-safe.
- */
-static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
+static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
 {
-	struct dentry * dentry;
+	struct dentry *dentry;
 	struct inode *inode;
 	int err;
 
 	inode = base->d_inode;
-	err = permission(inode, MAY_EXEC, nd);
-	dentry = ERR_PTR(err);
-	if (err)
-		goto out;
 
 	/*
 	 * See if the low-level filesystem might want
@@ -1287,48 +1277,78 @@ out:
 	return dentry;
 }
 
+/*
+ * Restricted form of lookup. Doesn't follow links, single-component only,
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+	int err;
+
+	inode = base->d_inode;
+
+	err = permission(inode, MAY_EXEC, nd);
+	dentry = ERR_PTR(err);
+	if (err)
+		goto out;
+
+	dentry = __lookup_hash_kern(name, base, nd);
+out:
+	return dentry;
+}
+
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
 	return __lookup_hash(&nd->last, nd->dentry, nd);
 }
 
 /* SMP-safe */
-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
 {
 	unsigned long hash;
-	struct qstr this;
 	unsigned int c;
 
-	this.name = name;
-	this.len = len;
+	this->name = name;
+	this->len = len;
 	if (!len)
-		goto access;
+		return -EACCES;
 
 	hash = init_name_hash();
 	while (len--) {
 		c = *(const unsigned char *)name++;
 		if (c == '/' || c == '\0')
-			goto access;
+			return -EACCES;
 		hash = partial_name_hash(c, hash);
 	}
-	this.hash = end_name_hash(hash);
+	this->hash = end_name_hash(hash);
+	return 0;
+}
 
+struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+{
+	int err;
+	struct qstr this;
+
+	err = __lookup_one_len(name, &this, base, len);
+	if (err)
+		return ERR_PTR(err);
 	return __lookup_hash(&this, base, NULL);
-access:
-	return ERR_PTR(-EACCES);
 }
 
-/*
- *	namei()
- *
- * is used by most simple commands to get the inode of a specified name.
- * Open, link etc use their own routines, but this is enough for things
- * like 'chmod' etc.
- *
- * namei exists in two versions: namei/lnamei. The only difference is
- * that namei follows links, while lnamei does not.
- * SMP-safe
- */
+struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len)
+{
+	int err;
+	struct qstr this;
+
+	err = __lookup_one_len(name, &this, base, len);
+	if (err)
+		return ERR_PTR(err);
+	return __lookup_hash_kern(&this, base, NULL);
+}
+
 int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
 			    struct nameidata *nd)
 {
@@ -2639,19 +2659,9 @@ static char *page_getlink(struct dentry 
 	struct address_space *mapping = dentry->d_inode->i_mapping;
 	page = read_mapping_page(mapping, 0, NULL);
 	if (IS_ERR(page))
-		goto sync_fail;
-	wait_on_page_locked(page);
-	if (!PageUptodate(page))
-		goto async_fail;
+		return (char*)page;
 	*ppage = page;
 	return kmap(page);
-
-async_fail:
-	page_cache_release(page);
-	return ERR_PTR(-EIO);
-
-sync_fail:
-	return (char*)page;
 }
 
 int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
diff --git a/fs/namespace.c b/fs/namespace.c
index fd999ca..b696e3a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -377,6 +377,10 @@ static int show_vfsmnt(struct seq_file *
 	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
 	seq_putc(m, ' ');
 	mangle(m, mnt->mnt_sb->s_type->name);
+	if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) {
+		seq_putc(m, '.');
+		mangle(m, mnt->mnt_sb->s_subtype);
+	}
 	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
 	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
 		if (mnt->mnt_sb->s_flags & fs_infop->flag)
@@ -495,7 +499,7 @@ void release_mounts(struct list_head *he
 {
 	struct vfsmount *mnt;
 	while (!list_empty(head)) {
-		mnt = list_entry(head->next, struct vfsmount, mnt_hash);
+		mnt = list_first_entry(head, struct vfsmount, mnt_hash);
 		list_del_init(&mnt->mnt_hash);
 		if (mnt->mnt_parent != mnt) {
 			struct dentry *dentry;
@@ -882,6 +886,9 @@ static int do_change_type(struct nameida
 	int recurse = flag & MS_REC;
 	int type = flag & ~MS_REC;
 
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
 	if (nd->dentry != nd->mnt->mnt_root)
 		return -EINVAL;
 
@@ -1173,7 +1180,7 @@ static void expire_mount_list(struct lis
 
 	while (!list_empty(graveyard)) {
 		LIST_HEAD(umounts);
-		mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
+		mnt = list_first_entry(graveyard, struct vfsmount, mnt_expire);
 		list_del_init(&mnt->mnt_expire);
 
 		/* don't do anything if the namespace is dead - all the
@@ -1441,10 +1448,9 @@ dput_out:
  * Allocate a new namespace structure and populate it with contents
  * copied from the namespace of the passed in task structure.
  */
-struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
+static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
 		struct fs_struct *fs)
 {
-	struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns;
 	struct mnt_namespace *new_ns;
 	struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
 	struct vfsmount *p, *q;
@@ -1509,36 +1515,21 @@ struct mnt_namespace *dup_mnt_ns(struct 
 	return new_ns;
 }
 
-int copy_mnt_ns(int flags, struct task_struct *tsk)
+struct mnt_namespace *copy_mnt_ns(int flags, struct mnt_namespace *ns,
+		struct fs_struct *new_fs)
 {
-	struct mnt_namespace *ns = tsk->nsproxy->mnt_ns;
 	struct mnt_namespace *new_ns;
-	int err = 0;
-
-	if (!ns)
-		return 0;
 
+	BUG_ON(!ns);
 	get_mnt_ns(ns);
 
 	if (!(flags & CLONE_NEWNS))
-		return 0;
+		return ns;
 
-	if (!capable(CAP_SYS_ADMIN)) {
-		err = -EPERM;
-		goto out;
-	}
-
-	new_ns = dup_mnt_ns(tsk, tsk->fs);
-	if (!new_ns) {
-		err = -ENOMEM;
-		goto out;
-	}
+	new_ns = dup_mnt_ns(ns, new_fs);
 
-	tsk->nsproxy->mnt_ns = new_ns;
-
-out:
 	put_mnt_ns(ns);
-	return err;
+	return new_ns;
 }
 
 asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 6b1f6d2..addfd31 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -17,7 +17,6 @@ #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
 
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 7285c94..c29f00a 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -60,8 +60,7 @@ static void init_once(void * foo, struct
 {
 	struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		mutex_init(&ei->open_mutex);
 		inode_init_once(&ei->vfs_inode);
 	}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 2190e6c..50c6821 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -27,7 +27,6 @@ #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>
@@ -618,7 +617,8 @@ #endif
 	if (clp->cl_nfsversion == 3) {
 		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
 			server->namelen = NFS3_MAXNAMLEN;
-		server->caps |= NFS_CAP_READDIRPLUS;
+		if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+			server->caps |= NFS_CAP_READDIRPLUS;
 	} else {
 		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
 			server->namelen = NFS2_MAXNAMLEN;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index cd34697..625d8e5 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -154,6 +154,8 @@ typedef struct {
 	decode_dirent_t	decode;
 	int		plus;
 	int		error;
+	unsigned long	timestamp;
+	int		timestamp_valid;
 } nfs_readdir_descriptor_t;
 
 /* Now we cache directories properly, by stuffing the dirent
@@ -195,6 +197,8 @@ int nfs_readdir_filler(nfs_readdir_descr
 		}
 		goto error;
 	}
+	desc->timestamp = timestamp;
+	desc->timestamp_valid = 1;
 	SetPageUptodate(page);
 	spin_lock(&inode->i_lock);
 	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -225,6 +229,10 @@ int dir_decode(nfs_readdir_descriptor_t 
 	if (IS_ERR(p))
 		return PTR_ERR(p);
 	desc->ptr = p;
+	if (desc->timestamp_valid)
+		desc->entry->fattr->time_start = desc->timestamp;
+	else
+		desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
 	return 0;
 }
 
@@ -316,14 +324,16 @@ int find_dirent_page(nfs_readdir_descrip
 			__FUNCTION__, desc->page_index,
 			(long long) *desc->dir_cookie);
 
+	/* If we find the page in the page_cache, we cannot be sure
+	 * how fresh the data is, so we will ignore readdir_plus attributes.
+	 */
+	desc->timestamp_valid = 0;
 	page = read_cache_page(inode->i_mapping, desc->page_index,
 			       (filler_t *)nfs_readdir_filler, desc);
 	if (IS_ERR(page)) {
 		status = PTR_ERR(page);
 		goto out;
 	}
-	if (!PageUptodate(page))
-		goto read_error;
 
 	/* NOTE: Someone else may have changed the READDIRPLUS flag */
 	desc->page = page;
@@ -337,9 +347,6 @@ int find_dirent_page(nfs_readdir_descrip
  out:
 	dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status);
 	return status;
- read_error:
-	page_cache_release(page);
-	return -EIO;
 }
 
 /*
@@ -468,6 +475,7 @@ int uncached_readdir(nfs_readdir_descrip
 	struct rpc_cred	*cred = nfs_file_cred(file);
 	struct page	*page = NULL;
 	int		status;
+	unsigned long	timestamp;
 
 	dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
 			(unsigned long long)*desc->dir_cookie);
@@ -477,6 +485,7 @@ int uncached_readdir(nfs_readdir_descrip
 		status = -ENOMEM;
 		goto out;
 	}
+	timestamp = jiffies;
 	desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
 						page,
 						NFS_SERVER(inode)->dtsize,
@@ -487,6 +496,8 @@ int uncached_readdir(nfs_readdir_descrip
 	desc->page = page;
 	desc->ptr = kmap(page);		/* matching kunmap in nfs_do_filldir */
 	if (desc->error >= 0) {
+		desc->timestamp = timestamp;
+		desc->timestamp_valid = 1;
 		if ((status = dir_decode(desc)) == 0)
 			desc->entry->prev_cookie = *desc->dir_cookie;
 	} else
@@ -849,6 +860,10 @@ static int nfs_dentry_delete(struct dent
 static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 {
 	nfs_inode_return_delegation(inode);
+	if (S_ISDIR(inode->i_mode))
+		/* drop any readdir cache as it could easily be old */
+		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
 		lock_kernel();
 		drop_nlink(inode);
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 2877744..345aa5c 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -41,7 +41,6 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/kref.h>
@@ -54,6 +53,7 @@ #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 
+#include "internal.h"
 #include "iostat.h"
 
 #define NFSDBG_FACILITY		NFSDBG_VFS
@@ -271,7 +271,7 @@ static ssize_t nfs_direct_read_schedule(
 		bytes = min(rsize,count);
 
 		result = -ENOMEM;
-		data = nfs_readdata_alloc(pgbase + bytes);
+		data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes));
 		if (unlikely(!data))
 			break;
 
@@ -602,7 +602,7 @@ static ssize_t nfs_direct_write_schedule
 		bytes = min(wsize,count);
 
 		result = -ENOMEM;
-		data = nfs_writedata_alloc(pgbase + bytes);
+		data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes));
 		if (unlikely(!data))
 			break;
 
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 8e66b5a..5eaee6d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -391,17 +391,12 @@ out_swapfile:
 
 static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
 {
-	struct file_lock cfl;
 	struct inode *inode = filp->f_mapping->host;
 	int status = 0;
 
 	lock_kernel();
 	/* Try local locking first */
-	if (posix_test_lock(filp, fl, &cfl)) {
-		fl->fl_start = cfl.fl_start;
-		fl->fl_end = cfl.fl_end;
-		fl->fl_type = cfl.fl_type;
-		fl->fl_pid = cfl.fl_pid;
+	if (posix_test_lock(filp, fl)) {
 		goto out;
 	}
 
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 6ef268f..2347785 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -25,7 +25,6 @@ #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>
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 44aa9b7..1e9a915 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1167,8 +1167,7 @@ static void init_once(void * foo, struct
 {
 	struct nfs_inode *nfsi = (struct nfs_inode *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&nfsi->vfs_inode);
 		spin_lock_init(&nfsi->req_lock);
 		INIT_LIST_HEAD(&nfsi->dirty);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 6610f2b..ad2b40d 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -231,3 +231,15 @@ unsigned int nfs_page_length(struct page
 	}
 	return 0;
 }
+
+/*
+ * Determine the number of pages in an array of length 'len' and
+ * with a base offset of 'base'
+ */
+static inline
+unsigned int nfs_page_array_len(unsigned int base, size_t len)
+{
+	return ((unsigned long)len + (unsigned long)base +
+		PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index f75fe72..ca5a266 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -133,13 +133,15 @@ xdr_decode_fhstatus3(struct rpc_rqst *re
 
 #define MNT_dirpath_sz		(1 + 256)
 #define MNT_fhstatus_sz		(1 + 8)
+#define MNT_fhstatus3_sz	(1 + 16)
 
 static struct rpc_procinfo	mnt_procedures[] = {
 [MNTPROC_MNT] = {
 	  .p_proc		= MNTPROC_MNT,
 	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,	
 	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus,
-	  .p_bufsiz		= MNT_dirpath_sz << 2,
+	  .p_arglen		= MNT_dirpath_sz,
+	  .p_replen		= MNT_fhstatus_sz,
 	  .p_statidx		= MNTPROC_MNT,
 	  .p_name		= "MOUNT",
 	},
@@ -150,7 +152,8 @@ static struct rpc_procinfo mnt3_procedur
 	  .p_proc		= MOUNTPROC3_MNT,
 	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,
 	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus3,
-	  .p_bufsiz		= MNT_dirpath_sz << 2,
+	  .p_arglen		= MNT_dirpath_sz,
+	  .p_replen		= MNT_fhstatus3_sz,
 	  .p_statidx		= MOUNTPROC3_MNT,
 	  .p_name		= "MOUNT",
 	},
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 3be4e72..abd9f8b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -687,16 +687,13 @@ nfs_stat_to_errno(int stat)
 	return nfs_errtbl[i].errno;
 }
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype, timer)				\
 [NFSPROC_##proc] = {							\
 	.p_proc	    =  NFSPROC_##proc,					\
 	.p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
 	.p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
-	.p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
+	.p_arglen   =  NFS_##argtype##_sz,				\
+	.p_replen   =  NFS_##restype##_sz,				\
 	.p_timer    =  timer,						\
 	.p_statidx  =  NFSPROC_##proc,					\
 	.p_name     =  #proc,						\
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 7d0371e..45268d6 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -16,7 +16,6 @@ #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
 #include <linux/nfs_mount.h>
 
 #include "iostat.h"
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 0ace092..b51df8e 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -1102,16 +1102,13 @@ nfs3_xdr_setaclres(struct rpc_rqst *req,
 }
 #endif  /* CONFIG_NFS_V3_ACL */
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype, timer)				\
 [NFS3PROC_##proc] = {							\
 	.p_proc      = NFS3PROC_##proc,					\
 	.p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,			\
 	.p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
-	.p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
+	.p_arglen    = NFS3_##argtype##_sz,				\
+	.p_replen    = NFS3_##restype##_sz,				\
 	.p_timer     = timer,						\
 	.p_statidx   = NFS3PROC_##proc,					\
 	.p_name      = #proc,						\
@@ -1153,7 +1150,8 @@ static struct rpc_procinfo	nfs3_acl_proc
 		.p_proc = ACLPROC3_GETACL,
 		.p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
 		.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
-		.p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
+		.p_arglen = ACL3_getaclargs_sz,
+		.p_replen = ACL3_getaclres_sz,
 		.p_timer = 1,
 		.p_name = "GETACL",
 	},
@@ -1161,7 +1159,8 @@ static struct rpc_procinfo	nfs3_acl_proc
 		.p_proc = ACLPROC3_SETACL,
 		.p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
 		.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
-		.p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
+		.p_arglen = ACL3_setaclargs_sz,
+		.p_replen = ACL3_setaclres_sz,
 		.p_timer = 0,
 		.p_name = "SETACL",
 	},
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f52cf5c..d6a30e9 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2647,8 +2647,7 @@ static int __nfs4_proc_set_acl(struct in
 	nfs_inode_return_delegation(inode);
 	buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
 	ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
-	if (ret == 0)
-		nfs4_write_cached_acl(inode, buf, buflen);
+	nfs_zap_caches(inode);
 	return ret;
 }
 
@@ -3018,6 +3017,7 @@ static int _nfs4_proc_getlk(struct nfs4_
 		case -NFS4ERR_DENIED:
 			status = 0;
 	}
+	request->fl_ops->fl_release_private(request);
 out:
 	up_read(&clp->cl_sem);
 	return status;
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index f5f4430..0505ca1 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -43,7 +43,6 @@
  * child task framework of the RPC layer?
  */
 
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/sched.h>
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index f02d522..b8c28f2 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4546,16 +4546,13 @@ nfs4_stat_to_errno(int stat)
 	return stat;
 }
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, argtype, restype)				\
 [NFSPROC4_CLNT_##proc] = {					\
 	.p_proc   = NFSPROC4_COMPOUND,				\
 	.p_encode = (kxdrproc_t) nfs4_xdr_##argtype,		\
 	.p_decode = (kxdrproc_t) nfs4_xdr_##restype,		\
-	.p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,	\
+	.p_arglen = NFS4_##argtype##_sz,			\
+	.p_replen = NFS4_##restype##_sz,			\
 	.p_statidx = NFSPROC4_CLNT_##proc,			\
 	.p_name   = #proc,					\
     }
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 75f819d..49d1008 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int p
 	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
 		program, version, NIPQUAD(servaddr));
 	set_sockaddr(&sin, servaddr, 0);
-	return rpc_getport_external(&sin, program, version, proto);
+	return rpcb_getport_external(&sin, program, version, proto);
 }
 
 
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index ca4b1d4..3889501 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -17,7 +17,8 @@ #include <linux/nfs4.h>
 #include <linux/nfs_page.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
-#include <linux/writeback.h>
+
+#include "internal.h"
 
 #define NFS_PARANOIA 1
 
@@ -50,9 +51,7 @@ nfs_page_free(struct nfs_page *p)
  * @count: number of bytes to read/write
  *
  * The page must be locked by the caller. This makes sure we never
- * create two different requests for the same page, and avoids
- * a possible deadlock when we reach the hard limit on the number
- * of dirty pages.
+ * create two different requests for the same page.
  * User should ensure it is safe to sleep in this function.
  */
 struct nfs_page *
@@ -63,16 +62,12 @@ nfs_create_request(struct nfs_open_conte
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs_page		*req;
 
-	/* Deal with hard limits.  */
 	for (;;) {
 		/* try to allocate the request struct */
 		req = nfs_page_alloc();
 		if (req != NULL)
 			break;
 
-		/* Try to free up at least one request in order to stay
-		 * below the hard limit
-		 */
 		if (signalled() && (server->flags & NFS_MOUNT_INTR))
 			return ERR_PTR(-ERESTARTSYS);
 		yield();
@@ -223,124 +218,151 @@ out:
 }
 
 /**
- * nfs_coalesce_requests - Split coalesced requests out from a list.
- * @head: source list
- * @dst: destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Moves a maximum of 'nmax' elements from one list to another.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that the RPC credentials are the same.
+ * nfs_pageio_init - initialise a page io descriptor
+ * @desc: pointer to descriptor
+ * @inode: pointer to inode
+ * @doio: pointer to io function
+ * @bsize: io block size
+ * @io_flags: extra parameters for the io function
  */
-int
-nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
-		      unsigned int nmax)
+void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+		     struct inode *inode,
+		     int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+		     size_t bsize,
+		     int io_flags)
 {
-	struct nfs_page		*req = NULL;
-	unsigned int		npages = 0;
-
-	while (!list_empty(head)) {
-		struct nfs_page	*prev = req;
-
-		req = nfs_list_entry(head->next);
-		if (prev) {
-			if (req->wb_context->cred != prev->wb_context->cred)
-				break;
-			if (req->wb_context->lockowner != prev->wb_context->lockowner)
-				break;
-			if (req->wb_context->state != prev->wb_context->state)
-				break;
-			if (req->wb_index != (prev->wb_index + 1))
-				break;
-
-			if (req->wb_pgbase != 0)
-				break;
-		}
-		nfs_list_remove_request(req);
-		nfs_list_add_request(req, dst);
-		npages++;
-		if (req->wb_pgbase + req->wb_bytes != PAGE_CACHE_SIZE)
-			break;
-		if (npages >= nmax)
-			break;
-	}
-	return npages;
+	INIT_LIST_HEAD(&desc->pg_list);
+	desc->pg_bytes_written = 0;
+	desc->pg_count = 0;
+	desc->pg_bsize = bsize;
+	desc->pg_base = 0;
+	desc->pg_inode = inode;
+	desc->pg_doio = doio;
+	desc->pg_ioflags = io_flags;
+	desc->pg_error = 0;
 }
 
-#define NFS_SCAN_MAXENTRIES 16
 /**
- * nfs_scan_dirty - Scan the radix tree for dirty requests
- * @mapping: pointer to address space
- * @wbc: writeback_control structure
- * @dst: Destination list
+ * nfs_can_coalesce_requests - test two requests for compatibility
+ * @prev: pointer to nfs_page
+ * @req: pointer to nfs_page
  *
- * Moves elements from one of the inode request lists.
- * If the number of requests is set to 0, the entire address_space
- * starting at index idx_start, is scanned.
- * The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's req_lock when calling this function
+ * The nfs_page structures 'prev' and 'req' are compared to ensure that the
+ * page data area they describe is contiguous, and that their RPC
+ * credentials, NFSv4 open state, and lockowners are the same.
+ *
+ * Return 'true' if this is the case, else return 'false'.
  */
-long nfs_scan_dirty(struct address_space *mapping,
-			struct writeback_control *wbc,
-			struct list_head *dst)
+static int nfs_can_coalesce_requests(struct nfs_page *prev,
+				     struct nfs_page *req)
 {
-	struct nfs_inode *nfsi = NFS_I(mapping->host);
-	struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
-	struct nfs_page *req;
-	pgoff_t idx_start, idx_end;
-	long res = 0;
-	int found, i;
-
-	if (nfsi->ndirty == 0)
+	if (req->wb_context->cred != prev->wb_context->cred)
 		return 0;
-	if (wbc->range_cyclic) {
-		idx_start = 0;
-		idx_end = ULONG_MAX;
-	} else if (wbc->range_end == 0) {
-		idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
-		idx_end = ULONG_MAX;
-	} else {
-		idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
-		idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
-	}
+	if (req->wb_context->lockowner != prev->wb_context->lockowner)
+		return 0;
+	if (req->wb_context->state != prev->wb_context->state)
+		return 0;
+	if (req->wb_index != (prev->wb_index + 1))
+		return 0;
+	if (req->wb_pgbase != 0)
+		return 0;
+	if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
+		return 0;
+	return 1;
+}
 
-	for (;;) {
-		unsigned int toscan = NFS_SCAN_MAXENTRIES;
+/**
+ * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
+				     struct nfs_page *req)
+{
+	size_t newlen = req->wb_bytes;
 
-		found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
-				(void **)&pgvec[0], idx_start, toscan,
-				NFS_PAGE_TAG_DIRTY);
+	if (desc->pg_count != 0) {
+		struct nfs_page *prev;
 
-		/* Did we make progress? */
-		if (found <= 0)
-			break;
+		/*
+		 * FIXME: ideally we should be able to coalesce all requests
+		 * that are not block boundary aligned, but currently this
+		 * is problematic for the case of bsize < PAGE_CACHE_SIZE,
+		 * since nfs_flush_multi and nfs_pagein_multi assume you
+		 * can have only one struct nfs_page.
+		 */
+		if (desc->pg_bsize < PAGE_SIZE)
+			return 0;
+		newlen += desc->pg_count;
+		if (newlen > desc->pg_bsize)
+			return 0;
+		prev = nfs_list_entry(desc->pg_list.prev);
+		if (!nfs_can_coalesce_requests(prev, req))
+			return 0;
+	} else
+		desc->pg_base = req->wb_pgbase;
+	nfs_list_remove_request(req);
+	nfs_list_add_request(req, &desc->pg_list);
+	desc->pg_count = newlen;
+	return 1;
+}
 
-		for (i = 0; i < found; i++) {
-			req = pgvec[i];
-			if (!wbc->range_cyclic && req->wb_index > idx_end)
-				goto out;
+/*
+ * Helper for nfs_pageio_add_request and nfs_pageio_complete
+ */
+static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
+{
+	if (!list_empty(&desc->pg_list)) {
+		int error = desc->pg_doio(desc->pg_inode,
+					  &desc->pg_list,
+					  nfs_page_array_len(desc->pg_base,
+							     desc->pg_count),
+					  desc->pg_count,
+					  desc->pg_ioflags);
+		if (error < 0)
+			desc->pg_error = error;
+		else
+			desc->pg_bytes_written += desc->pg_count;
+	}
+	if (list_empty(&desc->pg_list)) {
+		desc->pg_count = 0;
+		desc->pg_base = 0;
+	}
+}
 
-			/* Try to lock request and mark it for writeback */
-			if (!nfs_set_page_writeback_locked(req))
-				goto next;
-			radix_tree_tag_clear(&nfsi->nfs_page_tree,
-					req->wb_index, NFS_PAGE_TAG_DIRTY);
-			nfsi->ndirty--;
-			nfs_list_remove_request(req);
-			nfs_list_add_request(req, dst);
-			res++;
-			if (res == LONG_MAX)
-				goto out;
-next:
-			idx_start = req->wb_index + 1;
-		}
+/**
+ * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+			   struct nfs_page *req)
+{
+	while (!nfs_pageio_do_add_request(desc, req)) {
+		nfs_pageio_doio(desc);
+		if (desc->pg_error < 0)
+			return 0;
 	}
-out:
-	WARN_ON ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty));
-	return res;
+	return 1;
 }
 
 /**
+ * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
+ * @desc: pointer to io descriptor
+ */
+void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
+{
+	nfs_pageio_doio(desc);
+}
+
+#define NFS_SCAN_MAXENTRIES 16
+/**
  * nfs_scan_list - Scan a list for matching requests
  * @nfsi: NFS inode
  * @head: One of the NFS inode request lists
@@ -355,12 +377,12 @@ out:
  * You must be holding the inode's req_lock when calling this function
  */
 int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
-		struct list_head *dst, unsigned long idx_start,
+		struct list_head *dst, pgoff_t idx_start,
 		unsigned int npages)
 {
 	struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
 	struct nfs_page *req;
-	unsigned long idx_end;
+	pgoff_t idx_end;
 	int found, i;
 	int res;
 
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 1dcf56d..7be0ee2 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -43,7 +43,6 @@ #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
 #include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
 #include "internal.h"
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 6ab4d5a..9a55807 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -27,7 +27,8 @@ #include "iostat.h"
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
-static int nfs_pagein_one(struct list_head *, struct inode *);
+static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
 static const struct rpc_call_ops nfs_read_partial_ops;
 static const struct rpc_call_ops nfs_read_full_ops;
 
@@ -36,9 +37,8 @@ static mempool_t *nfs_rdata_mempool;
 
 #define MIN_POOL_READ	(32)
 
-struct nfs_read_data *nfs_readdata_alloc(size_t len)
+struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
 {
-	unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS);
 
 	if (p) {
@@ -133,7 +133,10 @@ static int nfs_readpage_async(struct nfs
 		memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
 
 	nfs_list_add_request(new, &one_request);
-	nfs_pagein_one(&one_request, inode);
+	if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
+		nfs_pagein_multi(inode, &one_request, 1, len, 0);
+	else
+		nfs_pagein_one(inode, &one_request, 1, len, 0);
 	return 0;
 }
 
@@ -230,7 +233,7 @@ static void nfs_execute_read(struct nfs_
  * won't see the new data until our attribute cache is updated.  This is more
  * or less conventional NFS client behavior.
  */
-static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
+static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
 	struct nfs_page *req = nfs_list_entry(head->next);
 	struct page *page = req->wb_page;
@@ -242,11 +245,11 @@ static int nfs_pagein_multi(struct list_
 
 	nfs_list_remove_request(req);
 
-	nbytes = req->wb_bytes;
+	nbytes = count;
 	do {
 		size_t len = min(nbytes,rsize);
 
-		data = nfs_readdata_alloc(len);
+		data = nfs_readdata_alloc(1);
 		if (!data)
 			goto out_bad;
 		INIT_LIST_HEAD(&data->pages);
@@ -258,23 +261,19 @@ static int nfs_pagein_multi(struct list_
 
 	ClearPageError(page);
 	offset = 0;
-	nbytes = req->wb_bytes;
+	nbytes = count;
 	do {
 		data = list_entry(list.next, struct nfs_read_data, pages);
 		list_del_init(&data->pages);
 
 		data->pagevec[0] = page;
 
-		if (nbytes > rsize) {
-			nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-					rsize, offset);
-			offset += rsize;
-			nbytes -= rsize;
-		} else {
-			nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-					nbytes, offset);
-			nbytes = 0;
-		}
+		if (nbytes < rsize)
+			rsize = nbytes;
+		nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
+				  rsize, offset);
+		offset += rsize;
+		nbytes -= rsize;
 		nfs_execute_read(data);
 	} while (nbytes != 0);
 
@@ -291,30 +290,24 @@ out_bad:
 	return -ENOMEM;
 }
 
-static int nfs_pagein_one(struct list_head *head, struct inode *inode)
+static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
 {
 	struct nfs_page		*req;
 	struct page		**pages;
 	struct nfs_read_data	*data;
-	unsigned int		count;
 
-	if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
-		return nfs_pagein_multi(head, inode);
-
-	data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize);
+	data = nfs_readdata_alloc(npages);
 	if (!data)
 		goto out_bad;
 
 	INIT_LIST_HEAD(&data->pages);
 	pages = data->pagevec;
-	count = 0;
 	while (!list_empty(head)) {
 		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
 		ClearPageError(req->wb_page);
 		*pages++ = req->wb_page;
-		count += req->wb_bytes;
 	}
 	req = nfs_list_entry(data->pages.next);
 
@@ -327,28 +320,6 @@ out_bad:
 	return -ENOMEM;
 }
 
-static int
-nfs_pagein_list(struct list_head *head, int rpages)
-{
-	LIST_HEAD(one_request);
-	struct nfs_page		*req;
-	int			error = 0;
-	unsigned int		pages = 0;
-
-	while (!list_empty(head)) {
-		pages += nfs_coalesce_requests(head, &one_request, rpages);
-		req = nfs_list_entry(one_request.next);
-		error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
-		if (error < 0)
-			break;
-	}
-	if (error >= 0)
-		return pages;
-
-	nfs_async_read_error(head);
-	return error;
-}
-
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -538,7 +509,7 @@ out_error:
 }
 
 struct nfs_readdesc {
-	struct list_head *head;
+	struct nfs_pageio_descriptor *pgio;
 	struct nfs_open_context *ctx;
 };
 
@@ -562,19 +533,21 @@ readpage_async_filler(void *data, struct
 	}
 	if (len < PAGE_CACHE_SIZE)
 		memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
-	nfs_list_add_request(new, desc->head);
+	nfs_pageio_add_request(desc->pgio, new);
 	return 0;
 }
 
 int nfs_readpages(struct file *filp, struct address_space *mapping,
 		struct list_head *pages, unsigned nr_pages)
 {
-	LIST_HEAD(head);
+	struct nfs_pageio_descriptor pgio;
 	struct nfs_readdesc desc = {
-		.head		= &head,
+		.pgio = &pgio,
 	};
 	struct inode *inode = mapping->host;
 	struct nfs_server *server = NFS_SERVER(inode);
+	size_t rsize = server->rsize;
+	unsigned long npages;
 	int ret = -ESTALE;
 
 	dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
@@ -593,13 +566,16 @@ int nfs_readpages(struct file *filp, str
 	} else
 		desc.ctx = get_nfs_open_context((struct nfs_open_context *)
 				filp->private_data);
+	if (rsize < PAGE_CACHE_SIZE)
+		nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
+	else
+		nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0);
+
 	ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
-	if (!list_empty(&head)) {
-		int err = nfs_pagein_list(&head, server->rpages);
-		if (!ret)
-			nfs_add_stats(inode, NFSIOS_READPAGES, err);
-			ret = err;
-	}
+
+	nfs_pageio_complete(&pgio);
+	npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	nfs_add_stats(inode, NFSIOS_READPAGES, npages);
 	put_nfs_open_context(desc.ctx);
 out:
 	return ret;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f1eae44..ca20d3c 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -204,9 +204,9 @@ static int nfs_statfs(struct dentry *den
 	lock_kernel();
 
 	error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
-	buf->f_type = NFS_SUPER_MAGIC;
 	if (error < 0)
 		goto out_err;
+	buf->f_type = NFS_SUPER_MAGIC;
 
 	/*
 	 * Current versions of glibc do not correctly handle the
@@ -233,15 +233,14 @@ static int nfs_statfs(struct dentry *den
 	buf->f_ffree = res.afiles;
 
 	buf->f_namelen = server->namelen;
- out:
+
 	unlock_kernel();
 	return 0;
 
  out_err:
 	dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
-	buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
-	goto out;
-
+	unlock_kernel();
+	return error;
 }
 
 /*
@@ -291,6 +290,7 @@ static void nfs_show_mount_options(struc
 		{ NFS_MOUNT_NOAC, ",noac", "" },
 		{ NFS_MOUNT_NONLM, ",nolock", "" },
 		{ NFS_MOUNT_NOACL, ",noacl", "" },
+		{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
 		{ 0, NULL, NULL }
 	};
 	const struct proc_nfs_info *nfs_infop;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index f4a0548..83e865a 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -22,7 +22,6 @@ #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/namei.h>
 
 /* Symlink caching in the page cache is even more simplistic
@@ -61,15 +60,9 @@ static void *nfs_follow_link(struct dent
 		err = page;
 		goto read_failed;
 	}
-	if (!PageUptodate(page)) {
-		err = ERR_PTR(-EIO);
-		goto getlink_read_error;
-	}
 	nd_set_link(nd, kmap(page));
 	return page;
 
-getlink_read_error:
-	page_cache_release(page);
 read_failed:
 	nd_set_link(nd, err);
 	return NULL;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 7975589..de92b95 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -21,7 +21,6 @@ #include <linux/nfs_page.h>
 #include <linux/backing-dev.h>
 
 #include <asm/uaccess.h>
-#include <linux/smp_lock.h>
 
 #include "delegation.h"
 #include "internal.h"
@@ -38,7 +37,8 @@ #define MIN_POOL_COMMIT		(4)
 static struct nfs_page * nfs_update_request(struct nfs_open_context*,
 					    struct page *,
 					    unsigned int, unsigned int);
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how);
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
+				  struct inode *inode, int ioflags);
 static const struct rpc_call_ops nfs_write_partial_ops;
 static const struct rpc_call_ops nfs_write_full_ops;
 static const struct rpc_call_ops nfs_commit_ops;
@@ -71,9 +71,8 @@ void nfs_commit_free(struct nfs_write_da
 	call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free);
 }
 
-struct nfs_write_data *nfs_writedata_alloc(size_t len)
+struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
 {
-	unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
 
 	if (p) {
@@ -139,7 +138,7 @@ static void nfs_grow_file(struct page *p
 {
 	struct inode *inode = page->mapping->host;
 	loff_t end, i_size = i_size_read(inode);
-	unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+	pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
 
 	if (i_size > 0 && page->index < end_index)
 		return;
@@ -201,7 +200,7 @@ static int nfs_writepage_setup(struct nf
 static int wb_priority(struct writeback_control *wbc)
 {
 	if (wbc->for_reclaim)
-		return FLUSH_HIGHPRI;
+		return FLUSH_HIGHPRI | FLUSH_STABLE;
 	if (wbc->for_kupdate)
 		return FLUSH_LOWPRI;
 	return 0;
@@ -225,7 +224,7 @@ static int nfs_set_page_writeback(struct
 		struct inode *inode = page->mapping->host;
 		struct nfs_server *nfss = NFS_SERVER(inode);
 
-		if (atomic_inc_return(&nfss->writeback) >
+		if (atomic_long_inc_return(&nfss->writeback) >
 				NFS_CONGESTION_ON_THRESH)
 			set_bdi_congested(&nfss->backing_dev_info, WRITE);
 	}
@@ -238,7 +237,7 @@ static void nfs_end_page_writeback(struc
 	struct nfs_server *nfss = NFS_SERVER(inode);
 
 	end_page_writeback(page);
-	if (atomic_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) {
+	if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) {
 		clear_bdi_congested(&nfss->backing_dev_info, WRITE);
 		congestion_end(WRITE);
 	}
@@ -251,7 +250,8 @@ static void nfs_end_page_writeback(struc
  * was not tagged.
  * May also return an error if the user signalled nfs_wait_on_request().
  */
-static int nfs_page_mark_flush(struct page *page)
+static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
+				struct page *page)
 {
 	struct nfs_page *req;
 	struct nfs_inode *nfsi = NFS_I(page->mapping->host);
@@ -273,6 +273,8 @@ static int nfs_page_mark_flush(struct pa
 		 *	 request as dirty (in which case we don't care).
 		 */
 		spin_unlock(req_lock);
+		/* Prevent deadlock! */
+		nfs_pageio_complete(pgio);
 		ret = nfs_wait_on_request(req);
 		nfs_release_request(req);
 		if (ret != 0)
@@ -283,21 +285,18 @@ static int nfs_page_mark_flush(struct pa
 		/* This request is marked for commit */
 		spin_unlock(req_lock);
 		nfs_unlock_request(req);
+		nfs_pageio_complete(pgio);
 		return 1;
 	}
-	if (nfs_set_page_writeback(page) == 0) {
-		nfs_list_remove_request(req);
-		/* add the request to the inode's dirty list. */
-		radix_tree_tag_set(&nfsi->nfs_page_tree,
-				req->wb_index, NFS_PAGE_TAG_DIRTY);
-		nfs_list_add_request(req, &nfsi->dirty);
-		nfsi->ndirty++;
-		spin_unlock(req_lock);
-		__mark_inode_dirty(page->mapping->host, I_DIRTY_PAGES);
-	} else
+	if (nfs_set_page_writeback(page) != 0) {
 		spin_unlock(req_lock);
+		BUG();
+	}
+	radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
+			NFS_PAGE_TAG_WRITEBACK);
 	ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
-	nfs_unlock_request(req);
+	spin_unlock(req_lock);
+	nfs_pageio_add_request(pgio, req);
 	return ret;
 }
 
@@ -306,6 +305,7 @@ static int nfs_page_mark_flush(struct pa
  */
 static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
 {
+	struct nfs_pageio_descriptor mypgio, *pgio;
 	struct nfs_open_context *ctx;
 	struct inode *inode = page->mapping->host;
 	unsigned offset;
@@ -314,7 +314,14 @@ static int nfs_writepage_locked(struct p
 	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
 	nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
-	err = nfs_page_mark_flush(page);
+	if (wbc->for_writepages)
+		pgio = wbc->fs_private;
+	else {
+		nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
+		pgio = &mypgio;
+	}
+
+	err = nfs_page_async_flush(pgio, page);
 	if (err <= 0)
 		goto out;
 	err = 0;
@@ -331,12 +338,12 @@ static int nfs_writepage_locked(struct p
 	put_nfs_open_context(ctx);
 	if (err != 0)
 		goto out;
-	err = nfs_page_mark_flush(page);
+	err = nfs_page_async_flush(pgio, page);
 	if (err > 0)
 		err = 0;
 out:
 	if (!wbc->for_writepages)
-		nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc));
+		nfs_pageio_complete(pgio);
 	return err;
 }
 
@@ -352,20 +359,20 @@ int nfs_writepage(struct page *page, str
 int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
 	struct inode *inode = mapping->host;
+	struct nfs_pageio_descriptor pgio;
 	int err;
 
 	nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
 
+	nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
+	wbc->fs_private = &pgio;
 	err = generic_writepages(mapping, wbc);
+	nfs_pageio_complete(&pgio);
 	if (err)
 		return err;
-	err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc));
-	if (err < 0)
-		goto out;
-	nfs_add_stats(inode, NFSIOS_WRITEPAGES, err);
-	err = 0;
-out:
-	return err;
+	if (pgio.pg_error)
+		return pgio.pg_error;
+	return 0;
 }
 
 /*
@@ -503,11 +510,11 @@ #endif
  *
  * Interruptible by signals only if mounted with intr flag.
  */
-static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_start, unsigned int npages)
+static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page *req;
-	unsigned long		idx_end, next;
+	pgoff_t idx_end, next;
 	unsigned int		res = 0;
 	int			error;
 
@@ -536,18 +543,6 @@ static int nfs_wait_on_requests_locked(s
 	return res;
 }
 
-static void nfs_cancel_dirty_list(struct list_head *head)
-{
-	struct nfs_page *req;
-	while(!list_empty(head)) {
-		req = nfs_list_entry(head->next);
-		nfs_list_remove_request(req);
-		nfs_end_page_writeback(req->wb_page);
-		nfs_inode_remove_request(req);
-		nfs_clear_page_writeback(req);
-	}
-}
-
 static void nfs_cancel_commit_list(struct list_head *head)
 {
 	struct nfs_page *req;
@@ -574,7 +569,7 @@ #if defined(CONFIG_NFS_V3) || defined(CO
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int res = 0;
@@ -588,40 +583,12 @@ nfs_scan_commit(struct inode *inode, str
 	return res;
 }
 #else
-static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
 {
 	return 0;
 }
 #endif
 
-static int nfs_wait_on_write_congestion(struct address_space *mapping)
-{
-	struct inode *inode = mapping->host;
-	struct backing_dev_info *bdi = mapping->backing_dev_info;
-	int ret = 0;
-
-	might_sleep();
-
-	if (!bdi_write_congested(bdi))
-		return 0;
-
-	nfs_inc_stats(inode, NFSIOS_CONGESTIONWAIT);
-
-	do {
-		struct rpc_clnt *clnt = NFS_CLIENT(inode);
-		sigset_t oldset;
-
-		rpc_clnt_sigmask(clnt, &oldset);
-		ret = congestion_wait_interruptible(WRITE, HZ/10);
-		rpc_clnt_sigunmask(clnt, &oldset);
-		if (ret == -ERESTARTSYS)
-			break;
-		ret = 0;
-	} while (bdi_write_congested(bdi));
-
-	return ret;
-}
-
 /*
  * Try to update any existing write request, or create one if there is none.
  * In order to match, the request's credentials must match those of
@@ -636,12 +603,10 @@ static struct nfs_page * nfs_update_requ
 	struct inode *inode = mapping->host;
 	struct nfs_inode *nfsi = NFS_I(inode);
 	struct nfs_page		*req, *new = NULL;
-	unsigned long		rqend, end;
+	pgoff_t		rqend, end;
 
 	end = offset + bytes;
 
-	if (nfs_wait_on_write_congestion(mapping))
-		return ERR_PTR(-ERESTARTSYS);
 	for (;;) {
 		/* Loop over all inode entries and see if we find
 		 * A request for the page we wish to update
@@ -865,7 +830,7 @@ static void nfs_execute_write(struct nfs
  * Generate multiple small requests to write out a single
  * contiguous dirty area on one page.
  */
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
 	struct nfs_page *req = nfs_list_entry(head->next);
 	struct page *page = req->wb_page;
@@ -877,11 +842,11 @@ static int nfs_flush_multi(struct inode 
 
 	nfs_list_remove_request(req);
 
-	nbytes = req->wb_bytes;
+	nbytes = count;
 	do {
 		size_t len = min(nbytes, wsize);
 
-		data = nfs_writedata_alloc(len);
+		data = nfs_writedata_alloc(1);
 		if (!data)
 			goto out_bad;
 		list_add(&data->pages, &list);
@@ -892,23 +857,19 @@ static int nfs_flush_multi(struct inode 
 
 	ClearPageError(page);
 	offset = 0;
-	nbytes = req->wb_bytes;
+	nbytes = count;
 	do {
 		data = list_entry(list.next, struct nfs_write_data, pages);
 		list_del_init(&data->pages);
 
 		data->pagevec[0] = page;
 
-		if (nbytes > wsize) {
-			nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
-					wsize, offset, how);
-			offset += wsize;
-			nbytes -= wsize;
-		} else {
-			nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
-					nbytes, offset, how);
-			nbytes = 0;
-		}
+		if (nbytes < wsize)
+			wsize = nbytes;
+		nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
+				   wsize, offset, how);
+		offset += wsize;
+		nbytes -= wsize;
 		nfs_execute_write(data);
 	} while (nbytes != 0);
 
@@ -934,26 +895,23 @@ out_bad:
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
 {
 	struct nfs_page		*req;
 	struct page		**pages;
 	struct nfs_write_data	*data;
-	unsigned int		count;
 
-	data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize);
+	data = nfs_writedata_alloc(npages);
 	if (!data)
 		goto out_bad;
 
 	pages = data->pagevec;
-	count = 0;
 	while (!list_empty(head)) {
 		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
 		ClearPageError(req->wb_page);
 		*pages++ = req->wb_page;
-		count += req->wb_bytes;
 	}
 	req = nfs_list_entry(data->pages.next);
 
@@ -973,40 +931,15 @@ static int nfs_flush_one(struct inode *i
 	return -ENOMEM;
 }
 
-static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how)
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+				  struct inode *inode, int ioflags)
 {
-	LIST_HEAD(one_request);
-	int (*flush_one)(struct inode *, struct list_head *, int);
-	struct nfs_page	*req;
-	int wpages = NFS_SERVER(inode)->wpages;
 	int wsize = NFS_SERVER(inode)->wsize;
-	int error;
 
-	flush_one = nfs_flush_one;
 	if (wsize < PAGE_CACHE_SIZE)
-		flush_one = nfs_flush_multi;
-	/* For single writes, FLUSH_STABLE is more efficient */
-	if (npages <= wpages && npages == NFS_I(inode)->npages
-			&& nfs_list_entry(head->next)->wb_bytes <= wsize)
-		how |= FLUSH_STABLE;
-
-	do {
-		nfs_coalesce_requests(head, &one_request, wpages);
-		req = nfs_list_entry(one_request.next);
-		error = flush_one(inode, &one_request, how);
-		if (error < 0)
-			goto out_err;
-	} while (!list_empty(head));
-	return 0;
-out_err:
-	while (!list_empty(head)) {
-		req = nfs_list_entry(head->next);
-		nfs_list_remove_request(req);
-		nfs_redirty_request(req);
-		nfs_end_page_writeback(req->wb_page);
-		nfs_clear_page_writeback(req);
-	}
-	return error;
+		nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
+	else
+		nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags);
 }
 
 /*
@@ -1330,31 +1263,7 @@ static const struct rpc_call_ops nfs_com
 	.rpc_call_done = nfs_commit_done,
 	.rpc_release = nfs_commit_release,
 };
-#else
-static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
-{
-	return 0;
-}
-#endif
-
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
-{
-	struct nfs_inode *nfsi = NFS_I(mapping->host);
-	LIST_HEAD(head);
-	long res;
-
-	spin_lock(&nfsi->req_lock);
-	res = nfs_scan_dirty(mapping, wbc, &head);
-	spin_unlock(&nfsi->req_lock);
-	if (res) {
-		int error = nfs_flush_list(mapping->host, &head, res, how);
-		if (error < 0)
-			return error;
-	}
-	return res;
-}
 
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 int nfs_commit_inode(struct inode *inode, int how)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
@@ -1371,13 +1280,18 @@ int nfs_commit_inode(struct inode *inode
 	}
 	return res;
 }
+#else
+static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
+{
+	return 0;
+}
 #endif
 
 long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how)
 {
 	struct inode *inode = mapping->host;
 	struct nfs_inode *nfsi = NFS_I(inode);
-	unsigned long idx_start, idx_end;
+	pgoff_t idx_start, idx_end;
 	unsigned int npages = 0;
 	LIST_HEAD(head);
 	int nocommit = how & FLUSH_NOCOMMIT;
@@ -1390,41 +1304,24 @@ long nfs_sync_mapping_wait(struct addres
 		idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
 		idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
 		if (idx_end > idx_start) {
-			unsigned long l_npages = 1 + idx_end - idx_start;
+			pgoff_t l_npages = 1 + idx_end - idx_start;
 			npages = l_npages;
 			if (sizeof(npages) != sizeof(l_npages) &&
-					(unsigned long)npages != l_npages)
+					(pgoff_t)npages != l_npages)
 				npages = 0;
 		}
 	}
 	how &= ~FLUSH_NOCOMMIT;
 	spin_lock(&nfsi->req_lock);
 	do {
-		wbc->pages_skipped = 0;
 		ret = nfs_wait_on_requests_locked(inode, idx_start, npages);
 		if (ret != 0)
 			continue;
-		pages = nfs_scan_dirty(mapping, wbc, &head);
-		if (pages != 0) {
-			spin_unlock(&nfsi->req_lock);
-			if (how & FLUSH_INVALIDATE) {
-				nfs_cancel_dirty_list(&head);
-				ret = pages;
-			} else
-				ret = nfs_flush_list(inode, &head, pages, how);
-			spin_lock(&nfsi->req_lock);
-			continue;
-		}
-		if (wbc->pages_skipped != 0)
-			continue;
 		if (nocommit)
 			break;
 		pages = nfs_scan_commit(inode, &head, idx_start, npages);
-		if (pages == 0) {
-			if (wbc->pages_skipped != 0)
-				continue;
+		if (pages == 0)
 			break;
-		}
 		if (how & FLUSH_INVALIDATE) {
 			spin_unlock(&nfsi->req_lock);
 			nfs_cancel_commit_list(&head);
@@ -1456,7 +1353,7 @@ int nfs_wb_all(struct inode *inode)
 	};
 	int ret;
 
-	ret = generic_writepages(mapping, &wbc);
+	ret = nfs_writepages(mapping, &wbc);
 	if (ret < 0)
 		goto out;
 	ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
@@ -1479,11 +1376,9 @@ int nfs_sync_mapping_range(struct addres
 	};
 	int ret;
 
-	if (!(how & FLUSH_NOWRITEPAGE)) {
-		ret = generic_writepages(mapping, &wbc);
-		if (ret < 0)
-			goto out;
-	}
+	ret = nfs_writepages(mapping, &wbc);
+	if (ret < 0)
+		goto out;
 	ret = nfs_sync_mapping_wait(mapping, &wbc, how);
 	if (ret >= 0)
 		return 0;
@@ -1506,7 +1401,7 @@ int nfs_wb_page_priority(struct inode *i
 	int ret;
 
 	BUG_ON(!PageLocked(page));
-	if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) {
+	if (clear_page_dirty_for_io(page)) {
 		ret = nfs_writepage_locked(page, &wbc);
 		if (ret < 0)
 			goto out;
@@ -1531,10 +1426,18 @@ int nfs_wb_page(struct inode *inode, str
 
 int nfs_set_page_dirty(struct page *page)
 {
-	spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
+	struct address_space *mapping = page->mapping;
+	struct inode *inode;
+	spinlock_t *req_lock;
 	struct nfs_page *req;
 	int ret;
 
+	if (!mapping)
+		goto out_raced;
+	inode = mapping->host;
+	if (!inode)
+		goto out_raced;
+	req_lock = &NFS_I(inode)->req_lock;
 	spin_lock(req_lock);
 	req = nfs_page_find_request_locked(page);
 	if (req != NULL) {
@@ -1547,6 +1450,8 @@ int nfs_set_page_dirty(struct page *page
 	ret = __set_page_dirty_nobuffers(page);
 	spin_unlock(req_lock);
 	return ret;
+out_raced:
+	return !TestSetPageDirty(page);
 }
 
 
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index fb14d68..32ffea0 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -315,16 +315,13 @@ out:
 /*
  * RPC procedure tables
  */
-#ifndef MAX
-# define MAX(a, b)      (((a) > (b))? (a) : (b))
-#endif
-
 #define PROC(proc, call, argtype, restype)                              \
 [NFSPROC4_CLNT_##proc] = {                                      	\
         .p_proc   = NFSPROC4_CB_##call,					\
         .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,                    \
         .p_decode = (kxdrproc_t) nfs4_xdr_##restype,                    \
-        .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
+        .p_arglen = NFS4_##argtype##_sz,                                \
+        .p_replen = NFS4_##restype##_sz,                                \
         .p_statidx = NFSPROC4_CB_##call,				\
 	.p_name   = #proc,                                              \
 }
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index e4a83d7..45aa21c 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -46,7 +46,6 @@ #include <linux/nfs.h>
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
 #include <linux/sunrpc/cache.h>
 #include <linux/nfsd_idmap.h>
 #include <linux/list.h>
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index af36070..678f3be 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -50,6 +50,7 @@ #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/namei.h>
 #include <linux/mutex.h>
+#include <linux/lockd/bind.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -2657,6 +2658,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 	struct file_lock conflock;
 	__be32 status = 0;
 	unsigned int strhashval;
+	unsigned int cmd;
 	int err;
 
 	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -2739,10 +2741,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 		case NFS4_READ_LT:
 		case NFS4_READW_LT:
 			file_lock.fl_type = F_RDLCK;
+			cmd = F_SETLK;
 		break;
 		case NFS4_WRITE_LT:
 		case NFS4_WRITEW_LT:
 			file_lock.fl_type = F_WRLCK;
+			cmd = F_SETLK;
 		break;
 		default:
 			status = nfserr_inval;
@@ -2769,9 +2773,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 
 	/* XXX?: Just to divert the locks_release_private at the start of
 	 * locks_copy_lock: */
-	conflock.fl_ops = NULL;
-	conflock.fl_lmops = NULL;
-	err = posix_lock_file_conf(filp, &file_lock, &conflock);
+	locks_init_lock(&conflock);
+	err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
 	switch (-err) {
 	case 0: /* success! */
 		update_stateid(&lock_stp->st_stateid);
@@ -2788,7 +2791,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",err);
+		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
 		status = nfserr_resource;
 		break;
 	}
@@ -2813,7 +2816,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 	struct inode *inode;
 	struct file file;
 	struct file_lock file_lock;
-	struct file_lock conflock;
+	int error;
 	__be32 status;
 
 	if (nfs4_in_grace())
@@ -2869,18 +2872,23 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 
 	nfs4_transform_lock_offset(&file_lock);
 
-	/* posix_test_lock uses the struct file _only_ to resolve the inode.
+	/* vfs_test_lock uses the struct file _only_ to resolve the inode.
 	 * since LOCKT doesn't require an OPEN, and therefore a struct
-	 * file may not exist, pass posix_test_lock a struct file with
+	 * file may not exist, pass vfs_test_lock a struct file with
 	 * only the dentry:inode set.
 	 */
 	memset(&file, 0, sizeof (struct file));
 	file.f_path.dentry = cstate->current_fh.fh_dentry;
 
 	status = nfs_ok;
-	if (posix_test_lock(&file, &file_lock, &conflock)) {
+	error = vfs_test_lock(&file, &file_lock);
+	if (error) {
+		status = nfserrno(error);
+		goto out;
+	}
+	if (file_lock.fl_type != F_UNLCK) {
 		status = nfserr_denied;
-		nfs4_set_lock_denied(&conflock, &lockt->lt_denied);
+		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
 	}
 out:
 	nfs4_unlock_state();
@@ -2933,9 +2941,9 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
 	/*
 	*  Try to unlock the file in the VFS.
 	*/
-	err = posix_lock_file(filp, &file_lock);
+	err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
 	if (err) {
-		dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
 		goto out_nfserr;
 	}
 	/*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5d090f1..15809df 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -44,7 +44,6 @@
 
 #include <linux/param.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/vfs.h>
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 8d995bc..739dd3c 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/string.h>
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 9393f4b..caecc58 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -89,9 +89,8 @@ static inline struct page *ntfs_map_page
 	struct page *page = read_mapping_page(mapping, index, NULL);
 
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
-		if (PageUptodate(page) && !PageError(page))
+		if (!PageError(page))
 			return page;
 		ntfs_unmap_page(page);
 		return ERR_PTR(-EIO);
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 7659cc1..1c08fef 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -2532,14 +2532,7 @@ int ntfs_attr_set(ntfs_inode *ni, const 
 		page = read_mapping_page(mapping, idx, NULL);
 		if (IS_ERR(page)) {
 			ntfs_error(vol->sb, "Failed to read first partial "
-					"page (sync error, index 0x%lx).", idx);
-			return PTR_ERR(page);
-		}
-		wait_on_page_locked(page);
-		if (unlikely(!PageUptodate(page))) {
-			ntfs_error(vol->sb, "Failed to read first partial page "
-					"(async error, index 0x%lx).", idx);
-			page_cache_release(page);
+					"page (error, index 0x%lx).", idx);
 			return PTR_ERR(page);
 		}
 		/*
@@ -2602,14 +2595,7 @@ int ntfs_attr_set(ntfs_inode *ni, const 
 		page = read_mapping_page(mapping, idx, NULL);
 		if (IS_ERR(page)) {
 			ntfs_error(vol->sb, "Failed to read last partial page "
-					"(sync error, index 0x%lx).", idx);
-			return PTR_ERR(page);
-		}
-		wait_on_page_locked(page);
-		if (unlikely(!PageUptodate(page))) {
-			ntfs_error(vol->sb, "Failed to read last partial page "
-					"(async error, index 0x%lx).", idx);
-			page_cache_release(page);
+					"(error, index 0x%lx).", idx);
 			return PTR_ERR(page);
 		}
 		kaddr = kmap_atomic(page, KM_USER0);
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 74f99a6..34314b3 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -20,7 +20,6 @@
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 
 #include "dir.h"
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index d69c459..621de36 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -236,8 +236,7 @@ do_non_resident_extend:
 			err = PTR_ERR(page);
 			goto init_err_out;
 		}
-		wait_on_page_locked(page);
-		if (unlikely(!PageUptodate(page) || PageError(page))) {
+		if (unlikely(PageError(page))) {
 			page_cache_release(page);
 			err = -EIO;
 			goto init_err_out;
@@ -2130,28 +2129,13 @@ static ssize_t ntfs_file_aio_write_noloc
 	struct address_space *mapping = file->f_mapping;
 	struct inode *inode = mapping->host;
 	loff_t pos;
-	unsigned long seg;
 	size_t count;		/* after file limit checks */
 	ssize_t written, err;
 
 	count = 0;
-	for (seg = 0; seg < nr_segs; seg++) {
-		const struct iovec *iv = &iov[seg];
-		/*
-		 * If any segment has a negative length, or the cumulative
-		 * length ever wraps negative then return -EINVAL.
-		 */
-		count += iv->iov_len;
-		if (unlikely((ssize_t)(count|iv->iov_len) < 0))
-			return -EINVAL;
-		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
-			continue;
-		if (!seg)
-			return -EFAULT;
-		nr_segs = seg;
-		count -= iv->iov_len;	/* This segment is no good */
-		break;
-	}
+	err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
+	if (err)
+		return err;
 	pos = *ppos;
 	vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
 	/* We can write back this queue in page reclaim. */
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index f8bf8da..074791c 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -27,7 +27,6 @@ #include <linux/mutex.h>
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 #include "aops.h"
 #include "attrib.h"
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 1594c90..21d834e 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2471,7 +2471,6 @@ static s64 get_nr_free_clusters(ntfs_vol
 	s64 nr_free = vol->nr_clusters;
 	u32 *kaddr;
 	struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
-	filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
 	struct page *page;
 	pgoff_t index, max_index;
 
@@ -2494,24 +2493,14 @@ static s64 get_nr_free_clusters(ntfs_vol
 		 * Read the page from page cache, getting it from backing store
 		 * if necessary, and increment the use count.
 		 */
-		page = read_cache_page(mapping, index, (filler_t*)readpage,
-				NULL);
+		page = read_mapping_page(mapping, index, NULL);
 		/* Ignore pages which errored synchronously. */
 		if (IS_ERR(page)) {
-			ntfs_debug("Sync read_cache_page() error. Skipping "
+			ntfs_debug("read_mapping_page() error. Skipping "
 					"page (index 0x%lx).", index);
 			nr_free -= PAGE_CACHE_SIZE * 8;
 			continue;
 		}
-		wait_on_page_locked(page);
-		/* Ignore pages which errored asynchronously. */
-		if (!PageUptodate(page)) {
-			ntfs_debug("Async read_cache_page() error. Skipping "
-					"page (index 0x%lx).", index);
-			page_cache_release(page);
-			nr_free -= PAGE_CACHE_SIZE * 8;
-			continue;
-		}
 		kaddr = (u32*)kmap_atomic(page, KM_USER0);
 		/*
 		 * For each 4 bytes, subtract the number of set bits. If this
@@ -2562,7 +2551,6 @@ static unsigned long __get_nr_free_mft_r
 {
 	u32 *kaddr;
 	struct address_space *mapping = vol->mftbmp_ino->i_mapping;
-	filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
 	struct page *page;
 	pgoff_t index;
 
@@ -2576,21 +2564,11 @@ static unsigned long __get_nr_free_mft_r
 		 * Read the page from page cache, getting it from backing store
 		 * if necessary, and increment the use count.
 		 */
-		page = read_cache_page(mapping, index, (filler_t*)readpage,
-				NULL);
+		page = read_mapping_page(mapping, index, NULL);
 		/* Ignore pages which errored synchronously. */
 		if (IS_ERR(page)) {
-			ntfs_debug("Sync read_cache_page() error. Skipping "
-					"page (index 0x%lx).", index);
-			nr_free -= PAGE_CACHE_SIZE * 8;
-			continue;
-		}
-		wait_on_page_locked(page);
-		/* Ignore pages which errored asynchronously. */
-		if (!PageUptodate(page)) {
-			ntfs_debug("Async read_cache_page() error. Skipping "
+			ntfs_debug("read_mapping_page() error. Skipping "
 					"page (index 0x%lx).", index);
-			page_cache_release(page);
 			nr_free -= PAGE_CACHE_SIZE * 8;
 			continue;
 		}
@@ -3107,8 +3085,7 @@ static void ntfs_big_inode_init_once(voi
 {
 	ntfs_inode *ni = (ntfs_inode *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-			SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(VFS_I(ni));
 }
 
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index f27e537..19712a7 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -27,6 +27,7 @@ #include <linux/fs.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
+#include <linux/swap.h>
 
 #define MLOG_MASK_PREFIX ML_DISK_ALLOC
 #include <cluster/masklog.h>
@@ -34,6 +35,7 @@ #include <cluster/masklog.h>
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "aops.h"
 #include "dlmglue.h"
 #include "extent_map.h"
 #include "inode.h"
@@ -47,63 +49,243 @@ #include "uptodate.h"
 
 #include "buffer_head_io.h"
 
-static int ocfs2_extent_contig(struct inode *inode,
-			       struct ocfs2_extent_rec *ext,
-			       u64 blkno);
+static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
 
-static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb,
-				     handle_t *handle,
-				     struct inode *inode,
-				     int wanted,
-				     struct ocfs2_alloc_context *meta_ac,
-				     struct buffer_head *bhs[]);
+/*
+ * Structures which describe a path through a btree, and functions to
+ * manipulate them.
+ *
+ * The idea here is to be as generic as possible with the tree
+ * manipulation code.
+ */
+struct ocfs2_path_item {
+	struct buffer_head		*bh;
+	struct ocfs2_extent_list	*el;
+};
 
-static int ocfs2_add_branch(struct ocfs2_super *osb,
-			    handle_t *handle,
-			    struct inode *inode,
-			    struct buffer_head *fe_bh,
-			    struct buffer_head *eb_bh,
-			    struct buffer_head *last_eb_bh,
-			    struct ocfs2_alloc_context *meta_ac);
+#define OCFS2_MAX_PATH_DEPTH	5
 
-static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
-				  handle_t *handle,
-				  struct inode *inode,
-				  struct buffer_head *fe_bh,
-				  struct ocfs2_alloc_context *meta_ac,
-				  struct buffer_head **ret_new_eb_bh);
+struct ocfs2_path {
+	int			p_tree_depth;
+	struct ocfs2_path_item	p_node[OCFS2_MAX_PATH_DEPTH];
+};
 
-static int ocfs2_do_insert_extent(struct ocfs2_super *osb,
-				  handle_t *handle,
-				  struct inode *inode,
-				  struct buffer_head *fe_bh,
-				  u64 blkno,
-				  u32 new_clusters);
+#define path_root_bh(_path) ((_path)->p_node[0].bh)
+#define path_root_el(_path) ((_path)->p_node[0].el)
+#define path_leaf_bh(_path) ((_path)->p_node[(_path)->p_tree_depth].bh)
+#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
+#define path_num_items(_path) ((_path)->p_tree_depth + 1)
 
-static int ocfs2_find_branch_target(struct ocfs2_super *osb,
-				    struct inode *inode,
-				    struct buffer_head *fe_bh,
-				    struct buffer_head **target_bh);
+/*
+ * Reset the actual path elements so that we can re-use the structure
+ * to build another path. Generally, this involves freeing the buffer
+ * heads.
+ */
+static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root)
+{
+	int i, start = 0, depth = 0;
+	struct ocfs2_path_item *node;
 
-static int ocfs2_find_new_last_ext_blk(struct ocfs2_super *osb,
-				       struct inode *inode,
-				       struct ocfs2_dinode *fe,
-				       unsigned int new_i_clusters,
-				       struct buffer_head *old_last_eb,
-				       struct buffer_head **new_last_eb);
+	if (keep_root)
+		start = 1;
+
+	for(i = start; i < path_num_items(path); i++) {
+		node = &path->p_node[i];
+
+		brelse(node->bh);
+		node->bh = NULL;
+		node->el = NULL;
+	}
+
+	/*
+	 * Tree depth may change during truncate, or insert. If we're
+	 * keeping the root extent list, then make sure that our path
+	 * structure reflects the proper depth.
+	 */
+	if (keep_root)
+		depth = le16_to_cpu(path_root_el(path)->l_tree_depth);
+
+	path->p_tree_depth = depth;
+}
+
+static void ocfs2_free_path(struct ocfs2_path *path)
+{
+	if (path) {
+		ocfs2_reinit_path(path, 0);
+		kfree(path);
+	}
+}
+
+/*
+ * Make the *dest path the same as src and re-initialize src path to
+ * have a root only.
+ */
+static void ocfs2_mv_path(struct ocfs2_path *dest, struct ocfs2_path *src)
+{
+	int i;
+
+	BUG_ON(path_root_bh(dest) != path_root_bh(src));
+
+	for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) {
+		brelse(dest->p_node[i].bh);
+
+		dest->p_node[i].bh = src->p_node[i].bh;
+		dest->p_node[i].el = src->p_node[i].el;
+
+		src->p_node[i].bh = NULL;
+		src->p_node[i].el = NULL;
+	}
+}
+
+/*
+ * Insert an extent block at given index.
+ *
+ * This will not take an additional reference on eb_bh.
+ */
+static inline void ocfs2_path_insert_eb(struct ocfs2_path *path, int index,
+					struct buffer_head *eb_bh)
+{
+	struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *)eb_bh->b_data;
+
+	/*
+	 * Right now, no root bh is an extent block, so this helps
+	 * catch code errors with dinode trees. The assertion can be
+	 * safely removed if we ever need to insert extent block
+	 * structures at the root.
+	 */
+	BUG_ON(index == 0);
+
+	path->p_node[index].bh = eb_bh;
+	path->p_node[index].el = &eb->h_list;
+}
+
+static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh,
+					 struct ocfs2_extent_list *root_el)
+{
+	struct ocfs2_path *path;
+
+	BUG_ON(le16_to_cpu(root_el->l_tree_depth) >= OCFS2_MAX_PATH_DEPTH);
+
+	path = kzalloc(sizeof(*path), GFP_NOFS);
+	if (path) {
+		path->p_tree_depth = le16_to_cpu(root_el->l_tree_depth);
+		get_bh(root_bh);
+		path_root_bh(path) = root_bh;
+		path_root_el(path) = root_el;
+	}
+
+	return path;
+}
+
+/*
+ * Allocate and initialize a new path based on a disk inode tree.
+ */
+static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh)
+{
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_extent_list *el = &di->id2.i_list;
+
+	return ocfs2_new_path(di_bh, el);
+}
+
+/*
+ * Convenience function to journal all components in a path.
+ */
+static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,
+				     struct ocfs2_path *path)
+{
+	int i, ret = 0;
+
+	if (!path)
+		goto out;
+
+	for(i = 0; i < path_num_items(path); i++) {
+		ret = ocfs2_journal_access(handle, inode, path->p_node[i].bh,
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+
+enum ocfs2_contig_type {
+	CONTIG_NONE = 0,
+	CONTIG_LEFT,
+	CONTIG_RIGHT
+};
 
-static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
 
-static int ocfs2_extent_contig(struct inode *inode,
-			       struct ocfs2_extent_rec *ext,
-			       u64 blkno)
+/*
+ * NOTE: ocfs2_block_extent_contig(), ocfs2_extents_adjacent() and
+ * ocfs2_extent_contig only work properly against leaf nodes!
+ */
+static int ocfs2_block_extent_contig(struct super_block *sb,
+				     struct ocfs2_extent_rec *ext,
+				     u64 blkno)
+{
+	u64 blk_end = le64_to_cpu(ext->e_blkno);
+
+	blk_end += ocfs2_clusters_to_blocks(sb,
+				    le16_to_cpu(ext->e_leaf_clusters));
+
+	return blkno == blk_end;
+}
+
+static int ocfs2_extents_adjacent(struct ocfs2_extent_rec *left,
+				  struct ocfs2_extent_rec *right)
+{
+	u32 left_range;
+
+	left_range = le32_to_cpu(left->e_cpos) +
+		le16_to_cpu(left->e_leaf_clusters);
+
+	return (left_range == le32_to_cpu(right->e_cpos));
+}
+
+static enum ocfs2_contig_type
+	ocfs2_extent_contig(struct inode *inode,
+			    struct ocfs2_extent_rec *ext,
+			    struct ocfs2_extent_rec *insert_rec)
 {
-	return blkno == (le64_to_cpu(ext->e_blkno) +
-			 ocfs2_clusters_to_blocks(inode->i_sb,
-						  le32_to_cpu(ext->e_clusters)));
+	u64 blkno = le64_to_cpu(insert_rec->e_blkno);
+
+	if (ocfs2_extents_adjacent(ext, insert_rec) &&
+	    ocfs2_block_extent_contig(inode->i_sb, ext, blkno))
+			return CONTIG_RIGHT;
+
+	blkno = le64_to_cpu(ext->e_blkno);
+	if (ocfs2_extents_adjacent(insert_rec, ext) &&
+	    ocfs2_block_extent_contig(inode->i_sb, insert_rec, blkno))
+		return CONTIG_LEFT;
+
+	return CONTIG_NONE;
 }
 
 /*
+ * NOTE: We can have pretty much any combination of contiguousness and
+ * appending.
+ *
+ * The usefulness of APPEND_TAIL is more in that it lets us know that
+ * we'll have to update the path to that leaf.
+ */
+enum ocfs2_append_type {
+	APPEND_NONE = 0,
+	APPEND_TAIL,
+};
+
+struct ocfs2_insert_type {
+	enum ocfs2_append_type	ins_appending;
+	enum ocfs2_contig_type	ins_contig;
+	int			ins_contig_index;
+	int			ins_free_records;
+	int			ins_tree_depth;
+};
+
+/*
  * How many free extents have we got before we need more meta data?
  */
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
@@ -242,6 +424,28 @@ bail:
 }
 
 /*
+ * Helper function for ocfs2_add_branch() and ocfs2_shift_tree_depth().
+ *
+ * Returns the sum of the rightmost extent rec logical offset and
+ * cluster count.
+ *
+ * ocfs2_add_branch() uses this to determine what logical cluster
+ * value should be populated into the leftmost new branch records.
+ *
+ * ocfs2_shift_tree_depth() uses this to determine the # clusters
+ * value for the new topmost tree record.
+ */
+static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list  *el)
+{
+	int i;
+
+	i = le16_to_cpu(el->l_next_free_rec) - 1;
+
+	return le32_to_cpu(el->l_recs[i].e_cpos) +
+		ocfs2_rec_clusters(el, &el->l_recs[i]);
+}
+
+/*
  * Add an entire tree branch to our inode. eb_bh is the extent block
  * to start at, if we don't want to start the branch at the dinode
  * structure.
@@ -250,7 +454,7 @@ bail:
  * for the new last extent block.
  *
  * the new branch will be 'empty' in the sense that every block will
- * contain a single record with e_clusters == 0.
+ * contain a single record with cluster count == 0.
  */
 static int ocfs2_add_branch(struct ocfs2_super *osb,
 			    handle_t *handle,
@@ -268,6 +472,7 @@ static int ocfs2_add_branch(struct ocfs2
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list  *eb_el;
 	struct ocfs2_extent_list  *el;
+	u32 new_cpos;
 
 	mlog_entry_void();
 
@@ -302,6 +507,9 @@ static int ocfs2_add_branch(struct ocfs2
 		goto bail;
 	}
 
+	eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
+	new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
+
 	/* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
 	 * linked with the rest of the tree.
 	 * conversly, new_eb_bhs[0] is the new bottommost leaf.
@@ -330,9 +538,18 @@ static int ocfs2_add_branch(struct ocfs2
 		eb->h_next_leaf_blk = 0;
 		eb_el->l_tree_depth = cpu_to_le16(i);
 		eb_el->l_next_free_rec = cpu_to_le16(1);
-		eb_el->l_recs[0].e_cpos = fe->i_clusters;
+		/*
+		 * This actually counts as an empty extent as
+		 * c_clusters == 0
+		 */
+		eb_el->l_recs[0].e_cpos = cpu_to_le32(new_cpos);
 		eb_el->l_recs[0].e_blkno = cpu_to_le64(next_blkno);
-		eb_el->l_recs[0].e_clusters = cpu_to_le32(0);
+		/*
+		 * eb_el isn't always an interior node, but even leaf
+		 * nodes want a zero'd flags and reserved field so
+		 * this gets the whole 32 bits regardless of use.
+		 */
+		eb_el->l_recs[0].e_int_clusters = cpu_to_le32(0);
 		if (!eb_el->l_tree_depth)
 			new_last_eb_blk = le64_to_cpu(eb->h_blkno);
 
@@ -376,8 +593,8 @@ static int ocfs2_add_branch(struct ocfs2
 	 * either be on the fe, or the extent block passed in. */
 	i = le16_to_cpu(el->l_next_free_rec);
 	el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);
-	el->l_recs[i].e_cpos = fe->i_clusters;
-	el->l_recs[i].e_clusters = 0;
+	el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);
+	el->l_recs[i].e_int_clusters = 0;
 	le16_add_cpu(&el->l_next_free_rec, 1);
 
 	/* fe needs a new last extent block pointer, as does the
@@ -425,6 +642,7 @@ static int ocfs2_shift_tree_depth(struct
 				  struct buffer_head **ret_new_eb_bh)
 {
 	int status, i;
+	u32 new_clusters;
 	struct buffer_head *new_eb_bh = NULL;
 	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
@@ -461,11 +679,8 @@ static int ocfs2_shift_tree_depth(struct
 	/* copy the fe data into the new extent block */
 	eb_el->l_tree_depth = fe_el->l_tree_depth;
 	eb_el->l_next_free_rec = fe_el->l_next_free_rec;
-	for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++) {
-		eb_el->l_recs[i].e_cpos = fe_el->l_recs[i].e_cpos;
-		eb_el->l_recs[i].e_clusters = fe_el->l_recs[i].e_clusters;
-		eb_el->l_recs[i].e_blkno = fe_el->l_recs[i].e_blkno;
-	}
+	for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
+		eb_el->l_recs[i] = fe_el->l_recs[i];
 
 	status = ocfs2_journal_dirty(handle, new_eb_bh);
 	if (status < 0) {
@@ -480,16 +695,15 @@ static int ocfs2_shift_tree_depth(struct
 		goto bail;
 	}
 
+	new_clusters = ocfs2_sum_rightmost_rec(eb_el);
+
 	/* update fe now */
 	le16_add_cpu(&fe_el->l_tree_depth, 1);
 	fe_el->l_recs[0].e_cpos = 0;
 	fe_el->l_recs[0].e_blkno = eb->h_blkno;
-	fe_el->l_recs[0].e_clusters = fe->i_clusters;
-	for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++) {
-		fe_el->l_recs[i].e_cpos = 0;
-		fe_el->l_recs[i].e_clusters = 0;
-		fe_el->l_recs[i].e_blkno = 0;
-	}
+	fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
+	for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
+		memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
 	fe_el->l_next_free_rec = cpu_to_le16(1);
 
 	/* If this is our 1st tree depth shift, then last_eb_blk
@@ -515,199 +729,6 @@ bail:
 }
 
 /*
- * Expects the tree to already have room in the rightmost leaf for the
- * extent.  Updates all the extent blocks (and the dinode) on the way
- * down.
- */
-static int ocfs2_do_insert_extent(struct ocfs2_super *osb,
-				  handle_t *handle,
-				  struct inode *inode,
-				  struct buffer_head *fe_bh,
-				  u64 start_blk,
-				  u32 new_clusters)
-{
-	int status, i, num_bhs = 0;
-	u64 next_blkno;
-	u16 next_free;
-	struct buffer_head **eb_bhs = NULL;
-	struct ocfs2_dinode *fe;
-	struct ocfs2_extent_block *eb;
-	struct ocfs2_extent_list  *el;
-
-	mlog_entry_void();
-
-	status = ocfs2_journal_access(handle, inode, fe_bh,
-				      OCFS2_JOURNAL_ACCESS_WRITE);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
-	el = &fe->id2.i_list;
-	if (el->l_tree_depth) {
-		/* This is another operation where we want to be
-		 * careful about our tree updates. An error here means
-		 * none of the previous changes we made should roll
-		 * forward. As a result, we have to record the buffers
-		 * for this part of the tree in an array and reserve a
-		 * journal write to them before making any changes. */
-		num_bhs = le16_to_cpu(fe->id2.i_list.l_tree_depth);
-		eb_bhs = kcalloc(num_bhs, sizeof(struct buffer_head *),
-				 GFP_KERNEL);
-		if (!eb_bhs) {
-			status = -ENOMEM;
-			mlog_errno(status);
-			goto bail;
-		}
-
-		i = 0;
-		while(el->l_tree_depth) {
-			next_free = le16_to_cpu(el->l_next_free_rec);
-			if (next_free == 0) {
-				ocfs2_error(inode->i_sb,
-					    "Dinode %llu has a bad extent list",
-					    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-				status = -EIO;
-				goto bail;
-			}
-			next_blkno = le64_to_cpu(el->l_recs[next_free - 1].e_blkno);
-
-			BUG_ON(i >= num_bhs);
-			status = ocfs2_read_block(osb, next_blkno, &eb_bhs[i],
-						  OCFS2_BH_CACHED, inode);
-			if (status < 0) {
-				mlog_errno(status);
-				goto bail;
-			}
-			eb = (struct ocfs2_extent_block *) eb_bhs[i]->b_data;
-			if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-				OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb,
-								 eb);
-				status = -EIO;
-				goto bail;
-			}
-
-			status = ocfs2_journal_access(handle, inode, eb_bhs[i],
-						      OCFS2_JOURNAL_ACCESS_WRITE);
-			if (status < 0) {
-				mlog_errno(status);
-				goto bail;
-			}
-
-			el = &eb->h_list;
-			i++;
-			/* When we leave this loop, eb_bhs[num_bhs - 1] will
-			 * hold the bottom-most leaf extent block. */
-		}
-		BUG_ON(el->l_tree_depth);
-
-		el = &fe->id2.i_list;
-		/* If we have tree depth, then the fe update is
-		 * trivial, and we want to switch el out for the
-		 * bottom-most leaf in order to update it with the
-		 * actual extent data below. */
-		next_free = le16_to_cpu(el->l_next_free_rec);
-		if (next_free == 0) {
-			ocfs2_error(inode->i_sb,
-				    "Dinode %llu has a bad extent list",
-				    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-			status = -EIO;
-			goto bail;
-		}
-		le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
-			     new_clusters);
-		/* (num_bhs - 1) to avoid the leaf */
-		for(i = 0; i < (num_bhs - 1); i++) {
-			eb = (struct ocfs2_extent_block *) eb_bhs[i]->b_data;
-			el = &eb->h_list;
-
-			/* finally, make our actual change to the
-			 * intermediate extent blocks. */
-			next_free = le16_to_cpu(el->l_next_free_rec);
-			le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
-				     new_clusters);
-
-			status = ocfs2_journal_dirty(handle, eb_bhs[i]);
-			if (status < 0)
-				mlog_errno(status);
-		}
-		BUG_ON(i != (num_bhs - 1));
-		/* note that the leaf block wasn't touched in
-		 * the loop above */
-		eb = (struct ocfs2_extent_block *) eb_bhs[num_bhs - 1]->b_data;
-		el = &eb->h_list;
-		BUG_ON(el->l_tree_depth);
-	}
-
-	/* yay, we can finally add the actual extent now! */
-	i = le16_to_cpu(el->l_next_free_rec) - 1;
-	if (le16_to_cpu(el->l_next_free_rec) &&
-	    ocfs2_extent_contig(inode, &el->l_recs[i], start_blk)) {
-		le32_add_cpu(&el->l_recs[i].e_clusters, new_clusters);
-	} else if (le16_to_cpu(el->l_next_free_rec) &&
-		   (le32_to_cpu(el->l_recs[i].e_clusters) == 0)) {
-		/* having an empty extent at eof is legal. */
-		if (el->l_recs[i].e_cpos != fe->i_clusters) {
-			ocfs2_error(inode->i_sb,
-				    "Dinode %llu trailing extent is bad: "
-				    "cpos (%u) != number of clusters (%u)",
-				    (unsigned long long)OCFS2_I(inode)->ip_blkno,
-				    le32_to_cpu(el->l_recs[i].e_cpos),
-				    le32_to_cpu(fe->i_clusters));
-			status = -EIO;
-			goto bail;
-		}
-		el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
-		el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
-	} else {
-		/* No contiguous record, or no empty record at eof, so
-		 * we add a new one. */
-
-		BUG_ON(le16_to_cpu(el->l_next_free_rec) >=
-		       le16_to_cpu(el->l_count));
-		i = le16_to_cpu(el->l_next_free_rec);
-
-		el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
-		el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
-		el->l_recs[i].e_cpos = fe->i_clusters;
-		le16_add_cpu(&el->l_next_free_rec, 1);
-	}
-
-	/*
-	 * extent_map errors are not fatal, so they are ignored outside
-	 * of flushing the thing.
-	 */
-	status = ocfs2_extent_map_append(inode, &el->l_recs[i],
-					 new_clusters);
-	if (status) {
-		mlog_errno(status);
-		ocfs2_extent_map_drop(inode, le32_to_cpu(fe->i_clusters));
-	}
-
-	status = ocfs2_journal_dirty(handle, fe_bh);
-	if (status < 0)
-		mlog_errno(status);
-	if (fe->id2.i_list.l_tree_depth) {
-		status = ocfs2_journal_dirty(handle, eb_bhs[num_bhs - 1]);
-		if (status < 0)
-			mlog_errno(status);
-	}
-
-	status = 0;
-bail:
-	if (eb_bhs) {
-		for (i = 0; i < num_bhs; i++)
-			if (eb_bhs[i])
-				brelse(eb_bhs[i]);
-		kfree(eb_bhs);
-	}
-
-	mlog_exit(status);
-	return status;
-}
-
-/*
  * Should only be called when there is no space left in any of the
  * leaf nodes. What we want to do is find the lowest tree depth
  * non-leaf extent block with room for new records. There are three
@@ -807,53 +828,1548 @@ bail:
 	return status;
 }
 
-/* the caller needs to update fe->i_clusters */
-int ocfs2_insert_extent(struct ocfs2_super *osb,
-			handle_t *handle,
-			struct inode *inode,
-			struct buffer_head *fe_bh,
-			u64 start_blk,
-			u32 new_clusters,
-			struct ocfs2_alloc_context *meta_ac)
+/*
+ * This is only valid for leaf nodes, which are the only ones that can
+ * have empty extents anyway.
+ */
+static inline int ocfs2_is_empty_extent(struct ocfs2_extent_rec *rec)
 {
-	int status, i, shift;
-	struct buffer_head *last_eb_bh = NULL;
+	return !rec->e_leaf_clusters;
+}
+
+/*
+ * This function will discard the rightmost extent record.
+ */
+static void ocfs2_shift_records_right(struct ocfs2_extent_list *el)
+{
+	int next_free = le16_to_cpu(el->l_next_free_rec);
+	int count = le16_to_cpu(el->l_count);
+	unsigned int num_bytes;
+
+	BUG_ON(!next_free);
+	/* This will cause us to go off the end of our extent list. */
+	BUG_ON(next_free >= count);
+
+	num_bytes = sizeof(struct ocfs2_extent_rec) * next_free;
+
+	memmove(&el->l_recs[1], &el->l_recs[0], num_bytes);
+}
+
+static void ocfs2_rotate_leaf(struct ocfs2_extent_list *el,
+			      struct ocfs2_extent_rec *insert_rec)
+{
+	int i, insert_index, next_free, has_empty, num_bytes;
+	u32 insert_cpos = le32_to_cpu(insert_rec->e_cpos);
+	struct ocfs2_extent_rec *rec;
+
+	next_free = le16_to_cpu(el->l_next_free_rec);
+	has_empty = ocfs2_is_empty_extent(&el->l_recs[0]);
+
+	BUG_ON(!next_free);
+
+	/* The tree code before us didn't allow enough room in the leaf. */
+	if (el->l_next_free_rec == el->l_count && !has_empty)
+		BUG();
+
+	/*
+	 * The easiest way to approach this is to just remove the
+	 * empty extent and temporarily decrement next_free.
+	 */
+	if (has_empty) {
+		/*
+		 * If next_free was 1 (only an empty extent), this
+		 * loop won't execute, which is fine. We still want
+		 * the decrement above to happen.
+		 */
+		for(i = 0; i < (next_free - 1); i++)
+			el->l_recs[i] = el->l_recs[i+1];
+
+		next_free--;
+	}
+
+	/*
+	 * Figure out what the new record index should be.
+	 */
+	for(i = 0; i < next_free; i++) {
+		rec = &el->l_recs[i];
+
+		if (insert_cpos < le32_to_cpu(rec->e_cpos))
+			break;
+	}
+	insert_index = i;
+
+	mlog(0, "ins %u: index %d, has_empty %d, next_free %d, count %d\n",
+	     insert_cpos, insert_index, has_empty, next_free, le16_to_cpu(el->l_count));
+
+	BUG_ON(insert_index < 0);
+	BUG_ON(insert_index >= le16_to_cpu(el->l_count));
+	BUG_ON(insert_index > next_free);
+
+	/*
+	 * No need to memmove if we're just adding to the tail.
+	 */
+	if (insert_index != next_free) {
+		BUG_ON(next_free >= le16_to_cpu(el->l_count));
+
+		num_bytes = next_free - insert_index;
+		num_bytes *= sizeof(struct ocfs2_extent_rec);
+		memmove(&el->l_recs[insert_index + 1],
+			&el->l_recs[insert_index],
+			num_bytes);
+	}
+
+	/*
+	 * Either we had an empty extent, and need to re-increment or
+	 * there was no empty extent on a non full rightmost leaf node,
+	 * in which case we still need to increment.
+	 */
+	next_free++;
+	el->l_next_free_rec = cpu_to_le16(next_free);
+	/*
+	 * Make sure none of the math above just messed up our tree.
+	 */
+	BUG_ON(le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count));
+
+	el->l_recs[insert_index] = *insert_rec;
+
+}
+
+/*
+ * Create an empty extent record .
+ *
+ * l_next_free_rec may be updated.
+ *
+ * If an empty extent already exists do nothing.
+ */
+static void ocfs2_create_empty_extent(struct ocfs2_extent_list *el)
+{
+	int next_free = le16_to_cpu(el->l_next_free_rec);
+
+	BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
+
+	if (next_free == 0)
+		goto set_and_inc;
+
+	if (ocfs2_is_empty_extent(&el->l_recs[0]))
+		return;
+
+	mlog_bug_on_msg(el->l_count == el->l_next_free_rec,
+			"Asked to create an empty extent in a full list:\n"
+			"count = %u, tree depth = %u",
+			le16_to_cpu(el->l_count),
+			le16_to_cpu(el->l_tree_depth));
+
+	ocfs2_shift_records_right(el);
+
+set_and_inc:
+	le16_add_cpu(&el->l_next_free_rec, 1);
+	memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
+}
+
+/*
+ * For a rotation which involves two leaf nodes, the "root node" is
+ * the lowest level tree node which contains a path to both leafs. This
+ * resulting set of information can be used to form a complete "subtree"
+ *
+ * This function is passed two full paths from the dinode down to a
+ * pair of adjacent leaves. It's task is to figure out which path
+ * index contains the subtree root - this can be the root index itself
+ * in a worst-case rotation.
+ *
+ * The array index of the subtree root is passed back.
+ */
+static int ocfs2_find_subtree_root(struct inode *inode,
+				   struct ocfs2_path *left,
+				   struct ocfs2_path *right)
+{
+	int i = 0;
+
+	/*
+	 * Check that the caller passed in two paths from the same tree.
+	 */
+	BUG_ON(path_root_bh(left) != path_root_bh(right));
+
+	do {
+		i++;
+
+		/*
+		 * The caller didn't pass two adjacent paths.
+		 */
+		mlog_bug_on_msg(i > left->p_tree_depth,
+				"Inode %lu, left depth %u, right depth %u\n"
+				"left leaf blk %llu, right leaf blk %llu\n",
+				inode->i_ino, left->p_tree_depth,
+				right->p_tree_depth,
+				(unsigned long long)path_leaf_bh(left)->b_blocknr,
+				(unsigned long long)path_leaf_bh(right)->b_blocknr);
+	} while (left->p_node[i].bh->b_blocknr ==
+		 right->p_node[i].bh->b_blocknr);
+
+	return i - 1;
+}
+
+typedef void (path_insert_t)(void *, struct buffer_head *);
+
+/*
+ * Traverse a btree path in search of cpos, starting at root_el.
+ *
+ * This code can be called with a cpos larger than the tree, in which
+ * case it will return the rightmost path.
+ */
+static int __ocfs2_find_path(struct inode *inode,
+			     struct ocfs2_extent_list *root_el, u32 cpos,
+			     path_insert_t *func, void *data)
+{
+	int i, ret = 0;
+	u32 range;
+	u64 blkno;
 	struct buffer_head *bh = NULL;
-	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
-	struct ocfs2_extent_list  *el;
+	struct ocfs2_extent_list *el;
+	struct ocfs2_extent_rec *rec;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	mlog_entry_void();
+	el = root_el;
+	while (el->l_tree_depth) {
+		if (le16_to_cpu(el->l_next_free_rec) == 0) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %llu has empty extent list at "
+				    "depth %u\n",
+				    (unsigned long long)oi->ip_blkno,
+				    le16_to_cpu(el->l_tree_depth));
+			ret = -EROFS;
+			goto out;
 
-	mlog(0, "add %u clusters starting at block %llu to inode %llu\n",
-	     new_clusters, (unsigned long long)start_blk,
-	     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+		}
 
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
-	el = &fe->id2.i_list;
+		for(i = 0; i < le16_to_cpu(el->l_next_free_rec) - 1; i++) {
+			rec = &el->l_recs[i];
+
+			/*
+			 * In the case that cpos is off the allocation
+			 * tree, this should just wind up returning the
+			 * rightmost record.
+			 */
+			range = le32_to_cpu(rec->e_cpos) +
+				ocfs2_rec_clusters(el, rec);
+			if (cpos >= le32_to_cpu(rec->e_cpos) && cpos < range)
+			    break;
+		}
 
-	if (el->l_tree_depth) {
-		/* jump to end of tree */
-		status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
-					  &last_eb_bh, OCFS2_BH_CACHED, inode);
-		if (status < 0) {
-			mlog_exit(status);
-			goto bail;
+		blkno = le64_to_cpu(el->l_recs[i].e_blkno);
+		if (blkno == 0) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %llu has bad blkno in extent list "
+				    "at depth %u (index %d)\n",
+				    (unsigned long long)oi->ip_blkno,
+				    le16_to_cpu(el->l_tree_depth), i);
+			ret = -EROFS;
+			goto out;
 		}
-		eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
+
+		brelse(bh);
+		bh = NULL;
+		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
+				       &bh, OCFS2_BH_CACHED, inode);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		eb = (struct ocfs2_extent_block *) bh->b_data;
 		el = &eb->h_list;
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+			ret = -EIO;
+			goto out;
+		}
+
+		if (le16_to_cpu(el->l_next_free_rec) >
+		    le16_to_cpu(el->l_count)) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %llu has bad count in extent list "
+				    "at block %llu (next free=%u, count=%u)\n",
+				    (unsigned long long)oi->ip_blkno,
+				    (unsigned long long)bh->b_blocknr,
+				    le16_to_cpu(el->l_next_free_rec),
+				    le16_to_cpu(el->l_count));
+			ret = -EROFS;
+			goto out;
+		}
+
+		if (func)
+			func(data, bh);
+	}
+
+out:
+	/*
+	 * Catch any trailing bh that the loop didn't handle.
+	 */
+	brelse(bh);
+
+	return ret;
+}
+
+/*
+ * Given an initialized path (that is, it has a valid root extent
+ * list), this function will traverse the btree in search of the path
+ * which would contain cpos.
+ *
+ * The path traveled is recorded in the path structure.
+ *
+ * Note that this will not do any comparisons on leaf node extent
+ * records, so it will work fine in the case that we just added a tree
+ * branch.
+ */
+struct find_path_data {
+	int index;
+	struct ocfs2_path *path;
+};
+static void find_path_ins(void *data, struct buffer_head *bh)
+{
+	struct find_path_data *fp = data;
+
+	get_bh(bh);
+	ocfs2_path_insert_eb(fp->path, fp->index, bh);
+	fp->index++;
+}
+static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path,
+			   u32 cpos)
+{
+	struct find_path_data data;
+
+	data.index = 1;
+	data.path = path;
+	return __ocfs2_find_path(inode, path_root_el(path), cpos,
+				 find_path_ins, &data);
+}
+
+static void find_leaf_ins(void *data, struct buffer_head *bh)
+{
+	struct ocfs2_extent_block *eb =(struct ocfs2_extent_block *)bh->b_data;
+	struct ocfs2_extent_list *el = &eb->h_list;
+	struct buffer_head **ret = data;
+
+	/* We want to retain only the leaf block. */
+	if (le16_to_cpu(el->l_tree_depth) == 0) {
+		get_bh(bh);
+		*ret = bh;
+	}
+}
+/*
+ * Find the leaf block in the tree which would contain cpos. No
+ * checking of the actual leaf is done.
+ *
+ * Some paths want to call this instead of allocating a path structure
+ * and calling ocfs2_find_path().
+ *
+ * This function doesn't handle non btree extent lists.
+ */
+int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
+		    u32 cpos, struct buffer_head **leaf_bh)
+{
+	int ret;
+	struct buffer_head *bh = NULL;
+
+	ret = __ocfs2_find_path(inode, root_el, cpos, find_leaf_ins, &bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	*leaf_bh = bh;
+out:
+	return ret;
+}
+
+/*
+ * Adjust the adjacent records (left_rec, right_rec) involved in a rotation.
+ *
+ * Basically, we've moved stuff around at the bottom of the tree and
+ * we need to fix up the extent records above the changes to reflect
+ * the new changes.
+ *
+ * left_rec: the record on the left.
+ * left_child_el: is the child list pointed to by left_rec
+ * right_rec: the record to the right of left_rec
+ * right_child_el: is the child list pointed to by right_rec
+ *
+ * By definition, this only works on interior nodes.
+ */
+static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec,
+				  struct ocfs2_extent_list *left_child_el,
+				  struct ocfs2_extent_rec *right_rec,
+				  struct ocfs2_extent_list *right_child_el)
+{
+	u32 left_clusters, right_end;
+
+	/*
+	 * Interior nodes never have holes. Their cpos is the cpos of
+	 * the leftmost record in their child list. Their cluster
+	 * count covers the full theoretical range of their child list
+	 * - the range between their cpos and the cpos of the record
+	 * immediately to their right.
+	 */
+	left_clusters = le32_to_cpu(right_child_el->l_recs[0].e_cpos);
+	left_clusters -= le32_to_cpu(left_rec->e_cpos);
+	left_rec->e_int_clusters = cpu_to_le32(left_clusters);
+
+	/*
+	 * Calculate the rightmost cluster count boundary before
+	 * moving cpos - we will need to adjust clusters after
+	 * updating e_cpos to keep the same highest cluster count.
+	 */
+	right_end = le32_to_cpu(right_rec->e_cpos);
+	right_end += le32_to_cpu(right_rec->e_int_clusters);
+
+	right_rec->e_cpos = left_rec->e_cpos;
+	le32_add_cpu(&right_rec->e_cpos, left_clusters);
+
+	right_end -= le32_to_cpu(right_rec->e_cpos);
+	right_rec->e_int_clusters = cpu_to_le32(right_end);
+}
+
+/*
+ * Adjust the adjacent root node records involved in a
+ * rotation. left_el_blkno is passed in as a key so that we can easily
+ * find it's index in the root list.
+ */
+static void ocfs2_adjust_root_records(struct ocfs2_extent_list *root_el,
+				      struct ocfs2_extent_list *left_el,
+				      struct ocfs2_extent_list *right_el,
+				      u64 left_el_blkno)
+{
+	int i;
+
+	BUG_ON(le16_to_cpu(root_el->l_tree_depth) <=
+	       le16_to_cpu(left_el->l_tree_depth));
+
+	for(i = 0; i < le16_to_cpu(root_el->l_next_free_rec) - 1; i++) {
+		if (le64_to_cpu(root_el->l_recs[i].e_blkno) == left_el_blkno)
+			break;
+	}
+
+	/*
+	 * The path walking code should have never returned a root and
+	 * two paths which are not adjacent.
+	 */
+	BUG_ON(i >= (le16_to_cpu(root_el->l_next_free_rec) - 1));
+
+	ocfs2_adjust_adjacent_records(&root_el->l_recs[i], left_el,
+				      &root_el->l_recs[i + 1], right_el);
+}
+
+/*
+ * We've changed a leaf block (in right_path) and need to reflect that
+ * change back up the subtree.
+ *
+ * This happens in multiple places:
+ *   - When we've moved an extent record from the left path leaf to the right
+ *     path leaf to make room for an empty extent in the left path leaf.
+ *   - When our insert into the right path leaf is at the leftmost edge
+ *     and requires an update of the path immediately to it's left. This
+ *     can occur at the end of some types of rotation and appending inserts.
+ */
+static void ocfs2_complete_edge_insert(struct inode *inode, handle_t *handle,
+				       struct ocfs2_path *left_path,
+				       struct ocfs2_path *right_path,
+				       int subtree_index)
+{
+	int ret, i, idx;
+	struct ocfs2_extent_list *el, *left_el, *right_el;
+	struct ocfs2_extent_rec *left_rec, *right_rec;
+	struct buffer_head *root_bh = left_path->p_node[subtree_index].bh;
+
+	/*
+	 * Update the counts and position values within all the
+	 * interior nodes to reflect the leaf rotation we just did.
+	 *
+	 * The root node is handled below the loop.
+	 *
+	 * We begin the loop with right_el and left_el pointing to the
+	 * leaf lists and work our way up.
+	 *
+	 * NOTE: within this loop, left_el and right_el always refer
+	 * to the *child* lists.
+	 */
+	left_el = path_leaf_el(left_path);
+	right_el = path_leaf_el(right_path);
+	for(i = left_path->p_tree_depth - 1; i > subtree_index; i--) {
+		mlog(0, "Adjust records at index %u\n", i);
+
+		/*
+		 * One nice property of knowing that all of these
+		 * nodes are below the root is that we only deal with
+		 * the leftmost right node record and the rightmost
+		 * left node record.
+		 */
+		el = left_path->p_node[i].el;
+		idx = le16_to_cpu(left_el->l_next_free_rec) - 1;
+		left_rec = &el->l_recs[idx];
+
+		el = right_path->p_node[i].el;
+		right_rec = &el->l_recs[0];
+
+		ocfs2_adjust_adjacent_records(left_rec, left_el, right_rec,
+					      right_el);
+
+		ret = ocfs2_journal_dirty(handle, left_path->p_node[i].bh);
+		if (ret)
+			mlog_errno(ret);
+
+		ret = ocfs2_journal_dirty(handle, right_path->p_node[i].bh);
+		if (ret)
+			mlog_errno(ret);
+
+		/*
+		 * Setup our list pointers now so that the current
+		 * parents become children in the next iteration.
+		 */
+		left_el = left_path->p_node[i].el;
+		right_el = right_path->p_node[i].el;
+	}
+
+	/*
+	 * At the root node, adjust the two adjacent records which
+	 * begin our path to the leaves.
+	 */
+
+	el = left_path->p_node[subtree_index].el;
+	left_el = left_path->p_node[subtree_index + 1].el;
+	right_el = right_path->p_node[subtree_index + 1].el;
+
+	ocfs2_adjust_root_records(el, left_el, right_el,
+				  left_path->p_node[subtree_index + 1].bh->b_blocknr);
+
+	root_bh = left_path->p_node[subtree_index].bh;
+
+	ret = ocfs2_journal_dirty(handle, root_bh);
+	if (ret)
+		mlog_errno(ret);
+}
+
+static int ocfs2_rotate_subtree_right(struct inode *inode,
+				      handle_t *handle,
+				      struct ocfs2_path *left_path,
+				      struct ocfs2_path *right_path,
+				      int subtree_index)
+{
+	int ret, i;
+	struct buffer_head *right_leaf_bh;
+	struct buffer_head *left_leaf_bh = NULL;
+	struct buffer_head *root_bh;
+	struct ocfs2_extent_list *right_el, *left_el;
+	struct ocfs2_extent_rec move_rec;
+
+	left_leaf_bh = path_leaf_bh(left_path);
+	left_el = path_leaf_el(left_path);
+
+	if (left_el->l_next_free_rec != left_el->l_count) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %llu has non-full interior leaf node %llu"
+			    "(next free = %u)",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+			    (unsigned long long)left_leaf_bh->b_blocknr,
+			    le16_to_cpu(left_el->l_next_free_rec));
+		return -EROFS;
+	}
+
+	/*
+	 * This extent block may already have an empty record, so we
+	 * return early if so.
+	 */
+	if (ocfs2_is_empty_extent(&left_el->l_recs[0]))
+		return 0;
+
+	root_bh = left_path->p_node[subtree_index].bh;
+	BUG_ON(root_bh != right_path->p_node[subtree_index].bh);
+
+	ret = ocfs2_journal_access(handle, inode, root_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	for(i = subtree_index + 1; i < path_num_items(right_path); i++) {
+		ret = ocfs2_journal_access(handle, inode,
+					   right_path->p_node[i].bh,
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_journal_access(handle, inode,
+					   left_path->p_node[i].bh,
+					   OCFS2_JOURNAL_ACCESS_WRITE);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	right_leaf_bh = path_leaf_bh(right_path);
+	right_el = path_leaf_el(right_path);
+
+	/* This is a code error, not a disk corruption. */
+	mlog_bug_on_msg(!right_el->l_next_free_rec, "Inode %llu: Rotate fails "
+			"because rightmost leaf block %llu is empty\n",
+			(unsigned long long)OCFS2_I(inode)->ip_blkno,
+			(unsigned long long)right_leaf_bh->b_blocknr);
+
+	ocfs2_create_empty_extent(right_el);
+
+	ret = ocfs2_journal_dirty(handle, right_leaf_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/* Do the copy now. */
+	i = le16_to_cpu(left_el->l_next_free_rec) - 1;
+	move_rec = left_el->l_recs[i];
+	right_el->l_recs[0] = move_rec;
+
+	/*
+	 * Clear out the record we just copied and shift everything
+	 * over, leaving an empty extent in the left leaf.
+	 *
+	 * We temporarily subtract from next_free_rec so that the
+	 * shift will lose the tail record (which is now defunct).
+	 */
+	le16_add_cpu(&left_el->l_next_free_rec, -1);
+	ocfs2_shift_records_right(left_el);
+	memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
+	le16_add_cpu(&left_el->l_next_free_rec, 1);
+
+	ret = ocfs2_journal_dirty(handle, left_leaf_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ocfs2_complete_edge_insert(inode, handle, left_path, right_path,
+				subtree_index);
+
+out:
+	return ret;
+}
+
+/*
+ * Given a full path, determine what cpos value would return us a path
+ * containing the leaf immediately to the left of the current one.
+ *
+ * Will return zero if the path passed in is already the leftmost path.
+ */
+static int ocfs2_find_cpos_for_left_leaf(struct super_block *sb,
+					 struct ocfs2_path *path, u32 *cpos)
+{
+	int i, j, ret = 0;
+	u64 blkno;
+	struct ocfs2_extent_list *el;
+
+	BUG_ON(path->p_tree_depth == 0);
+
+	*cpos = 0;
+
+	blkno = path_leaf_bh(path)->b_blocknr;
+
+	/* Start at the tree node just above the leaf and work our way up. */
+	i = path->p_tree_depth - 1;
+	while (i >= 0) {
+		el = path->p_node[i].el;
+
+		/*
+		 * Find the extent record just before the one in our
+		 * path.
+		 */
+		for(j = 0; j < le16_to_cpu(el->l_next_free_rec); j++) {
+			if (le64_to_cpu(el->l_recs[j].e_blkno) == blkno) {
+				if (j == 0) {
+					if (i == 0) {
+						/*
+						 * We've determined that the
+						 * path specified is already
+						 * the leftmost one - return a
+						 * cpos of zero.
+						 */
+						goto out;
+					}
+					/*
+					 * The leftmost record points to our
+					 * leaf - we need to travel up the
+					 * tree one level.
+					 */
+					goto next_node;
+				}
+
+				*cpos = le32_to_cpu(el->l_recs[j - 1].e_cpos);
+				*cpos = *cpos + ocfs2_rec_clusters(el,
+							   &el->l_recs[j - 1]);
+				*cpos = *cpos - 1;
+				goto out;
+			}
+		}
+
+		/*
+		 * If we got here, we never found a valid node where
+		 * the tree indicated one should be.
+		 */
+		ocfs2_error(sb,
+			    "Invalid extent tree at extent block %llu\n",
+			    (unsigned long long)blkno);
+		ret = -EROFS;
+		goto out;
+
+next_node:
+		blkno = path->p_node[i].bh->b_blocknr;
+		i--;
+	}
+
+out:
+	return ret;
+}
+
+static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth,
+					   struct ocfs2_path *path)
+{
+	int credits = (path->p_tree_depth - subtree_depth) * 2 + 1;
+
+	if (handle->h_buffer_credits < credits)
+		return ocfs2_extend_trans(handle, credits);
+
+	return 0;
+}
+
+/*
+ * Trap the case where we're inserting into the theoretical range past
+ * the _actual_ left leaf range. Otherwise, we'll rotate a record
+ * whose cpos is less than ours into the right leaf.
+ *
+ * It's only necessary to look at the rightmost record of the left
+ * leaf because the logic that calls us should ensure that the
+ * theoretical ranges in the path components above the leaves are
+ * correct.
+ */
+static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path,
+						 u32 insert_cpos)
+{
+	struct ocfs2_extent_list *left_el;
+	struct ocfs2_extent_rec *rec;
+	int next_free;
+
+	left_el = path_leaf_el(left_path);
+	next_free = le16_to_cpu(left_el->l_next_free_rec);
+	rec = &left_el->l_recs[next_free - 1];
+
+	if (insert_cpos > le32_to_cpu(rec->e_cpos))
+		return 1;
+	return 0;
+}
+
+/*
+ * Rotate all the records in a btree right one record, starting at insert_cpos.
+ *
+ * The path to the rightmost leaf should be passed in.
+ *
+ * The array is assumed to be large enough to hold an entire path (tree depth).
+ *
+ * Upon succesful return from this function:
+ *
+ * - The 'right_path' array will contain a path to the leaf block
+ *   whose range contains e_cpos.
+ * - That leaf block will have a single empty extent in list index 0.
+ * - In the case that the rotation requires a post-insert update,
+ *   *ret_left_path will contain a valid path which can be passed to
+ *   ocfs2_insert_path().
+ */
+static int ocfs2_rotate_tree_right(struct inode *inode,
+				   handle_t *handle,
+				   u32 insert_cpos,
+				   struct ocfs2_path *right_path,
+				   struct ocfs2_path **ret_left_path)
+{
+	int ret, start;
+	u32 cpos;
+	struct ocfs2_path *left_path = NULL;
+
+	*ret_left_path = NULL;
+
+	left_path = ocfs2_new_path(path_root_bh(right_path),
+				   path_root_el(right_path));
+	if (!left_path) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path, &cpos);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	mlog(0, "Insert: %u, first left path cpos: %u\n", insert_cpos, cpos);
+
+	/*
+	 * What we want to do here is:
+	 *
+	 * 1) Start with the rightmost path.
+	 *
+	 * 2) Determine a path to the leaf block directly to the left
+	 *    of that leaf.
+	 *
+	 * 3) Determine the 'subtree root' - the lowest level tree node
+	 *    which contains a path to both leaves.
+	 *
+	 * 4) Rotate the subtree.
+	 *
+	 * 5) Find the next subtree by considering the left path to be
+	 *    the new right path.
+	 *
+	 * The check at the top of this while loop also accepts
+	 * insert_cpos == cpos because cpos is only a _theoretical_
+	 * value to get us the left path - insert_cpos might very well
+	 * be filling that hole.
+	 *
+	 * Stop at a cpos of '0' because we either started at the
+	 * leftmost branch (i.e., a tree with one branch and a
+	 * rotation inside of it), or we've gone as far as we can in
+	 * rotating subtrees.
+	 */
+	while (cpos && insert_cpos <= cpos) {
+		mlog(0, "Rotating a tree: ins. cpos: %u, left path cpos: %u\n",
+		     insert_cpos, cpos);
+
+		ret = ocfs2_find_path(inode, left_path, cpos);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		mlog_bug_on_msg(path_leaf_bh(left_path) ==
+				path_leaf_bh(right_path),
+				"Inode %lu: error during insert of %u "
+				"(left path cpos %u) results in two identical "
+				"paths ending at %llu\n",
+				inode->i_ino, insert_cpos, cpos,
+				(unsigned long long)
+				path_leaf_bh(left_path)->b_blocknr);
+
+		if (ocfs2_rotate_requires_path_adjustment(left_path,
+							  insert_cpos)) {
+			mlog(0, "Path adjustment required\n");
+
+			/*
+			 * We've rotated the tree as much as we
+			 * should. The rest is up to
+			 * ocfs2_insert_path() to complete, after the
+			 * record insertion. We indicate this
+			 * situation by returning the left path.
+			 *
+			 * The reason we don't adjust the records here
+			 * before the record insert is that an error
+			 * later might break the rule where a parent
+			 * record e_cpos will reflect the actual
+			 * e_cpos of the 1st nonempty record of the
+			 * child list.
+			 */
+			*ret_left_path = left_path;
+			goto out_ret_path;
+		}
+
+		start = ocfs2_find_subtree_root(inode, left_path, right_path);
+
+		mlog(0, "Subtree root at index %d (blk %llu, depth %d)\n",
+		     start,
+		     (unsigned long long) right_path->p_node[start].bh->b_blocknr,
+		     right_path->p_tree_depth);
+
+		ret = ocfs2_extend_rotate_transaction(handle, start,
+						      right_path);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_rotate_subtree_right(inode, handle, left_path,
+						 right_path, start);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		/*
+		 * There is no need to re-read the next right path
+		 * as we know that it'll be our current left
+		 * path. Optimize by copying values instead.
+		 */
+		ocfs2_mv_path(right_path, left_path);
+
+		ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path,
+						    &cpos);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+out:
+	ocfs2_free_path(left_path);
+
+out_ret_path:
+	return ret;
+}
+
+/*
+ * Do the final bits of extent record insertion at the target leaf
+ * list. If this leaf is part of an allocation tree, it is assumed
+ * that the tree above has been prepared.
+ */
+static void ocfs2_insert_at_leaf(struct ocfs2_extent_rec *insert_rec,
+				 struct ocfs2_extent_list *el,
+				 struct ocfs2_insert_type *insert,
+				 struct inode *inode)
+{
+	int i = insert->ins_contig_index;
+	unsigned int range;
+	struct ocfs2_extent_rec *rec;
+
+	BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
+
+	/*
+	 * Contiguous insert - either left or right.
+	 */
+	if (insert->ins_contig != CONTIG_NONE) {
+		rec = &el->l_recs[i];
+		if (insert->ins_contig == CONTIG_LEFT) {
+			rec->e_blkno = insert_rec->e_blkno;
+			rec->e_cpos = insert_rec->e_cpos;
+		}
+		le16_add_cpu(&rec->e_leaf_clusters,
+			     le16_to_cpu(insert_rec->e_leaf_clusters));
+		return;
+	}
+
+	/*
+	 * Handle insert into an empty leaf.
+	 */
+	if (le16_to_cpu(el->l_next_free_rec) == 0 ||
+	    ((le16_to_cpu(el->l_next_free_rec) == 1) &&
+	     ocfs2_is_empty_extent(&el->l_recs[0]))) {
+		el->l_recs[0] = *insert_rec;
+		el->l_next_free_rec = cpu_to_le16(1);
+		return;
+	}
+
+	/*
+	 * Appending insert.
+	 */
+	if (insert->ins_appending == APPEND_TAIL) {
+		i = le16_to_cpu(el->l_next_free_rec) - 1;
+		rec = &el->l_recs[i];
+		range = le32_to_cpu(rec->e_cpos)
+			+ le16_to_cpu(rec->e_leaf_clusters);
+		BUG_ON(le32_to_cpu(insert_rec->e_cpos) < range);
+
+		mlog_bug_on_msg(le16_to_cpu(el->l_next_free_rec) >=
+				le16_to_cpu(el->l_count),
+				"inode %lu, depth %u, count %u, next free %u, "
+				"rec.cpos %u, rec.clusters %u, "
+				"insert.cpos %u, insert.clusters %u\n",
+				inode->i_ino,
+				le16_to_cpu(el->l_tree_depth),
+				le16_to_cpu(el->l_count),
+				le16_to_cpu(el->l_next_free_rec),
+				le32_to_cpu(el->l_recs[i].e_cpos),
+				le16_to_cpu(el->l_recs[i].e_leaf_clusters),
+				le32_to_cpu(insert_rec->e_cpos),
+				le16_to_cpu(insert_rec->e_leaf_clusters));
+		i++;
+		el->l_recs[i] = *insert_rec;
+		le16_add_cpu(&el->l_next_free_rec, 1);
+		return;
+	}
+
+	/*
+	 * Ok, we have to rotate.
+	 *
+	 * At this point, it is safe to assume that inserting into an
+	 * empty leaf and appending to a leaf have both been handled
+	 * above.
+	 *
+	 * This leaf needs to have space, either by the empty 1st
+	 * extent record, or by virtue of an l_next_rec < l_count.
+	 */
+	ocfs2_rotate_leaf(el, insert_rec);
+}
+
+static inline void ocfs2_update_dinode_clusters(struct inode *inode,
+						struct ocfs2_dinode *di,
+						u32 clusters)
+{
+	le32_add_cpu(&di->i_clusters, clusters);
+	spin_lock(&OCFS2_I(inode)->ip_lock);
+	OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
+	spin_unlock(&OCFS2_I(inode)->ip_lock);
+}
+
+static int ocfs2_append_rec_to_path(struct inode *inode, handle_t *handle,
+				    struct ocfs2_extent_rec *insert_rec,
+				    struct ocfs2_path *right_path,
+				    struct ocfs2_path **ret_left_path)
+{
+	int ret, i, next_free;
+	struct buffer_head *bh;
+	struct ocfs2_extent_list *el;
+	struct ocfs2_path *left_path = NULL;
+
+	*ret_left_path = NULL;
+
+	/*
+	 * This shouldn't happen for non-trees. The extent rec cluster
+	 * count manipulation below only works for interior nodes.
+	 */
+	BUG_ON(right_path->p_tree_depth == 0);
+
+	/*
+	 * If our appending insert is at the leftmost edge of a leaf,
+	 * then we might need to update the rightmost records of the
+	 * neighboring path.
+	 */
+	el = path_leaf_el(right_path);
+	next_free = le16_to_cpu(el->l_next_free_rec);
+	if (next_free == 0 ||
+	    (next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0]))) {
+		u32 left_cpos;
+
+		ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, right_path,
+						    &left_cpos);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		mlog(0, "Append may need a left path update. cpos: %u, "
+		     "left_cpos: %u\n", le32_to_cpu(insert_rec->e_cpos),
+		     left_cpos);
+
+		/*
+		 * No need to worry if the append is already in the
+		 * leftmost leaf.
+		 */
+		if (left_cpos) {
+			left_path = ocfs2_new_path(path_root_bh(right_path),
+						   path_root_el(right_path));
+			if (!left_path) {
+				ret = -ENOMEM;
+				mlog_errno(ret);
+				goto out;
+			}
+
+			ret = ocfs2_find_path(inode, left_path, left_cpos);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+
+			/*
+			 * ocfs2_insert_path() will pass the left_path to the
+			 * journal for us.
+			 */
+		}
+	}
+
+	ret = ocfs2_journal_access_path(inode, handle, right_path);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	el = path_root_el(right_path);
+	bh = path_root_bh(right_path);
+	i = 0;
+	while (1) {
+		struct ocfs2_extent_rec *rec;
+
+		next_free = le16_to_cpu(el->l_next_free_rec);
+		if (next_free == 0) {
+			ocfs2_error(inode->i_sb,
+				    "Dinode %llu has a bad extent list",
+				    (unsigned long long)OCFS2_I(inode)->ip_blkno);
+			ret = -EIO;
+			goto out;
+		}
+
+		rec = &el->l_recs[next_free - 1];
+
+		rec->e_int_clusters = insert_rec->e_cpos;
+		le32_add_cpu(&rec->e_int_clusters,
+			     le16_to_cpu(insert_rec->e_leaf_clusters));
+		le32_add_cpu(&rec->e_int_clusters,
+			     -le32_to_cpu(rec->e_cpos));
+
+		ret = ocfs2_journal_dirty(handle, bh);
+		if (ret)
+			mlog_errno(ret);
+
+		/* Don't touch the leaf node */
+		if (++i >= right_path->p_tree_depth)
+			break;
+
+		bh = right_path->p_node[i].bh;
+		el = right_path->p_node[i].el;
+	}
+
+	*ret_left_path = left_path;
+	ret = 0;
+out:
+	if (ret != 0)
+		ocfs2_free_path(left_path);
+
+	return ret;
+}
+
+/*
+ * This function only does inserts on an allocation b-tree. For dinode
+ * lists, ocfs2_insert_at_leaf() is called directly.
+ *
+ * right_path is the path we want to do the actual insert
+ * in. left_path should only be passed in if we need to update that
+ * portion of the tree after an edge insert.
+ */
+static int ocfs2_insert_path(struct inode *inode,
+			     handle_t *handle,
+			     struct ocfs2_path *left_path,
+			     struct ocfs2_path *right_path,
+			     struct ocfs2_extent_rec *insert_rec,
+			     struct ocfs2_insert_type *insert)
+{
+	int ret, subtree_index;
+	struct buffer_head *leaf_bh = path_leaf_bh(right_path);
+	struct ocfs2_extent_list *el;
+
+	/*
+	 * Pass both paths to the journal. The majority of inserts
+	 * will be touching all components anyway.
+	 */
+	ret = ocfs2_journal_access_path(inode, handle, right_path);
+	if (ret < 0) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (left_path) {
+		int credits = handle->h_buffer_credits;
+
+		/*
+		 * There's a chance that left_path got passed back to
+		 * us without being accounted for in the
+		 * journal. Extend our transaction here to be sure we
+		 * can change those blocks.
+		 */
+		credits += left_path->p_tree_depth;
+
+		ret = ocfs2_extend_trans(handle, credits);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_journal_access_path(inode, handle, left_path);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	el = path_leaf_el(right_path);
+
+	ocfs2_insert_at_leaf(insert_rec, el, insert, inode);
+	ret = ocfs2_journal_dirty(handle, leaf_bh);
+	if (ret)
+		mlog_errno(ret);
+
+	if (left_path) {
+		/*
+		 * The rotate code has indicated that we need to fix
+		 * up portions of the tree after the insert.
+		 *
+		 * XXX: Should we extend the transaction here?
+		 */
+		subtree_index = ocfs2_find_subtree_root(inode, left_path,
+							right_path);
+		ocfs2_complete_edge_insert(inode, handle, left_path,
+					   right_path, subtree_index);
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
+static int ocfs2_do_insert_extent(struct inode *inode,
+				  handle_t *handle,
+				  struct buffer_head *di_bh,
+				  struct ocfs2_extent_rec *insert_rec,
+				  struct ocfs2_insert_type *type)
+{
+	int ret, rotate = 0;
+	u32 cpos;
+	struct ocfs2_path *right_path = NULL;
+	struct ocfs2_path *left_path = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_extent_list *el;
+
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+	el = &di->id2.i_list;
+
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (le16_to_cpu(el->l_tree_depth) == 0) {
+		ocfs2_insert_at_leaf(insert_rec, el, type, inode);
+		goto out_update_clusters;
+	}
+
+	right_path = ocfs2_new_inode_path(di_bh);
+	if (!right_path) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * Determine the path to start with. Rotations need the
+	 * rightmost path, everything else can go directly to the
+	 * target leaf.
+	 */
+	cpos = le32_to_cpu(insert_rec->e_cpos);
+	if (type->ins_appending == APPEND_NONE &&
+	    type->ins_contig == CONTIG_NONE) {
+		rotate = 1;
+		cpos = UINT_MAX;
+	}
+
+	ret = ocfs2_find_path(inode, right_path, cpos);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * Rotations and appends need special treatment - they modify
+	 * parts of the tree's above them.
+	 *
+	 * Both might pass back a path immediate to the left of the
+	 * one being inserted to. This will be cause
+	 * ocfs2_insert_path() to modify the rightmost records of
+	 * left_path to account for an edge insert.
+	 *
+	 * XXX: When modifying this code, keep in mind that an insert
+	 * can wind up skipping both of these two special cases...
+	 */
+	if (rotate) {
+		ret = ocfs2_rotate_tree_right(inode, handle,
+					      le32_to_cpu(insert_rec->e_cpos),
+					      right_path, &left_path);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	} else if (type->ins_appending == APPEND_TAIL
+		   && type->ins_contig != CONTIG_LEFT) {
+		ret = ocfs2_append_rec_to_path(inode, handle, insert_rec,
+					       right_path, &left_path);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	ret = ocfs2_insert_path(inode, handle, left_path, right_path,
+				insert_rec, type);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+out_update_clusters:
+	ocfs2_update_dinode_clusters(inode, di,
+				     le16_to_cpu(insert_rec->e_leaf_clusters));
+
+	ret = ocfs2_journal_dirty(handle, di_bh);
+	if (ret)
+		mlog_errno(ret);
+
+out:
+	ocfs2_free_path(left_path);
+	ocfs2_free_path(right_path);
+
+	return ret;
+}
+
+static void ocfs2_figure_contig_type(struct inode *inode,
+				     struct ocfs2_insert_type *insert,
+				     struct ocfs2_extent_list *el,
+				     struct ocfs2_extent_rec *insert_rec)
+{
+	int i;
+	enum ocfs2_contig_type contig_type = CONTIG_NONE;
+
+	BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
+
+	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
+		contig_type = ocfs2_extent_contig(inode, &el->l_recs[i],
+						  insert_rec);
+		if (contig_type != CONTIG_NONE) {
+			insert->ins_contig_index = i;
+			break;
+		}
+	}
+	insert->ins_contig = contig_type;
+}
+
+/*
+ * This should only be called against the righmost leaf extent list.
+ *
+ * ocfs2_figure_appending_type() will figure out whether we'll have to
+ * insert at the tail of the rightmost leaf.
+ *
+ * This should also work against the dinode list for tree's with 0
+ * depth. If we consider the dinode list to be the rightmost leaf node
+ * then the logic here makes sense.
+ */
+static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert,
+					struct ocfs2_extent_list *el,
+					struct ocfs2_extent_rec *insert_rec)
+{
+	int i;
+	u32 cpos = le32_to_cpu(insert_rec->e_cpos);
+	struct ocfs2_extent_rec *rec;
+
+	insert->ins_appending = APPEND_NONE;
+
+	BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
+
+	if (!el->l_next_free_rec)
+		goto set_tail_append;
+
+	if (ocfs2_is_empty_extent(&el->l_recs[0])) {
+		/* Were all records empty? */
+		if (le16_to_cpu(el->l_next_free_rec) == 1)
+			goto set_tail_append;
 	}
 
-	/* Can we allocate without adding/shifting tree bits? */
 	i = le16_to_cpu(el->l_next_free_rec) - 1;
-	if (le16_to_cpu(el->l_next_free_rec) == 0
-	    || (le16_to_cpu(el->l_next_free_rec) < le16_to_cpu(el->l_count))
-	    || le32_to_cpu(el->l_recs[i].e_clusters) == 0
-	    || ocfs2_extent_contig(inode, &el->l_recs[i], start_blk))
-		goto out_add;
+	rec = &el->l_recs[i];
+
+	if (cpos >=
+	    (le32_to_cpu(rec->e_cpos) + le16_to_cpu(rec->e_leaf_clusters)))
+		goto set_tail_append;
+
+	return;
+
+set_tail_append:
+	insert->ins_appending = APPEND_TAIL;
+}
+
+/*
+ * Helper function called at the begining of an insert.
+ *
+ * This computes a few things that are commonly used in the process of
+ * inserting into the btree:
+ *   - Whether the new extent is contiguous with an existing one.
+ *   - The current tree depth.
+ *   - Whether the insert is an appending one.
+ *   - The total # of free records in the tree.
+ *
+ * All of the information is stored on the ocfs2_insert_type
+ * structure.
+ */
+static int ocfs2_figure_insert_type(struct inode *inode,
+				    struct buffer_head *di_bh,
+				    struct buffer_head **last_eb_bh,
+				    struct ocfs2_extent_rec *insert_rec,
+				    struct ocfs2_insert_type *insert)
+{
+	int ret;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_list *el;
+	struct ocfs2_path *path = NULL;
+	struct buffer_head *bh = NULL;
+
+	el = &di->id2.i_list;
+	insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth);
+
+	if (el->l_tree_depth) {
+		/*
+		 * If we have tree depth, we read in the
+		 * rightmost extent block ahead of time as
+		 * ocfs2_figure_insert_type() and ocfs2_add_branch()
+		 * may want it later.
+		 */
+		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+				       le64_to_cpu(di->i_last_eb_blk), &bh,
+				       OCFS2_BH_CACHED, inode);
+		if (ret) {
+			mlog_exit(ret);
+			goto out;
+		}
+		eb = (struct ocfs2_extent_block *) bh->b_data;
+		el = &eb->h_list;
+	}
+
+	/*
+	 * Unless we have a contiguous insert, we'll need to know if
+	 * there is room left in our allocation tree for another
+	 * extent record.
+	 *
+	 * XXX: This test is simplistic, we can search for empty
+	 * extent records too.
+	 */
+	insert->ins_free_records = le16_to_cpu(el->l_count) -
+		le16_to_cpu(el->l_next_free_rec);
+
+	if (!insert->ins_tree_depth) {
+		ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+		ocfs2_figure_appending_type(insert, el, insert_rec);
+		return 0;
+	}
+
+	path = ocfs2_new_inode_path(di_bh);
+	if (!path) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * In the case that we're inserting past what the tree
+	 * currently accounts for, ocfs2_find_path() will return for
+	 * us the rightmost tree path. This is accounted for below in
+	 * the appending code.
+	 */
+	ret = ocfs2_find_path(inode, path, le32_to_cpu(insert_rec->e_cpos));
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	el = path_leaf_el(path);
+
+	/*
+	 * Now that we have the path, there's two things we want to determine:
+	 * 1) Contiguousness (also set contig_index if this is so)
+	 *
+	 * 2) Are we doing an append? We can trivially break this up
+         *     into two types of appends: simple record append, or a
+         *     rotate inside the tail leaf.
+	 */
+	ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+
+	/*
+	 * The insert code isn't quite ready to deal with all cases of
+	 * left contiguousness. Specifically, if it's an insert into
+	 * the 1st record in a leaf, it will require the adjustment of
+	 * cluster count on the last record of the path directly to it's
+	 * left. For now, just catch that case and fool the layers
+	 * above us. This works just fine for tree_depth == 0, which
+	 * is why we allow that above.
+	 */
+	if (insert->ins_contig == CONTIG_LEFT &&
+	    insert->ins_contig_index == 0)
+		insert->ins_contig = CONTIG_NONE;
+
+	/*
+	 * Ok, so we can simply compare against last_eb to figure out
+	 * whether the path doesn't exist. This will only happen in
+	 * the case that we're doing a tail append, so maybe we can
+	 * take advantage of that information somehow.
+	 */
+	if (le64_to_cpu(di->i_last_eb_blk) == path_leaf_bh(path)->b_blocknr) {
+		/*
+		 * Ok, ocfs2_find_path() returned us the rightmost
+		 * tree path. This might be an appending insert. There are
+		 * two cases:
+		 *    1) We're doing a true append at the tail:
+		 *	-This might even be off the end of the leaf
+		 *    2) We're "appending" by rotating in the tail
+		 */
+		ocfs2_figure_appending_type(insert, el, insert_rec);
+	}
+
+out:
+	ocfs2_free_path(path);
+
+	if (ret == 0)
+		*last_eb_bh = bh;
+	else
+		brelse(bh);
+	return ret;
+}
+
+/*
+ * Insert an extent into an inode btree.
+ *
+ * The caller needs to update fe->i_clusters
+ */
+int ocfs2_insert_extent(struct ocfs2_super *osb,
+			handle_t *handle,
+			struct inode *inode,
+			struct buffer_head *fe_bh,
+			u32 cpos,
+			u64 start_blk,
+			u32 new_clusters,
+			struct ocfs2_alloc_context *meta_ac)
+{
+	int status, shift;
+	struct buffer_head *last_eb_bh = NULL;
+	struct buffer_head *bh = NULL;
+	struct ocfs2_insert_type insert = {0, };
+	struct ocfs2_extent_rec rec;
+
+	mlog(0, "add %u clusters at position %u to inode %llu\n",
+	     new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
+			(OCFS2_I(inode)->ip_clusters != cpos),
+			"Device %s, asking for sparse allocation: inode %llu, "
+			"cpos %u, clusters %u\n",
+			osb->dev_str,
+			(unsigned long long)OCFS2_I(inode)->ip_blkno, cpos,
+			OCFS2_I(inode)->ip_clusters);
+
+	memset(&rec, 0, sizeof(rec));
+	rec.e_cpos = cpu_to_le32(cpos);
+	rec.e_blkno = cpu_to_le64(start_blk);
+	rec.e_leaf_clusters = cpu_to_le16(new_clusters);
+
+	status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
+					  &insert);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
 
-	mlog(0, "ocfs2_allocate_extent: couldn't do a simple add, traversing "
-	     "tree now.\n");
+	mlog(0, "Insert.appending: %u, Insert.Contig: %u, "
+	     "Insert.contig_index: %d, Insert.free_records: %d, "
+	     "Insert.tree_depth: %d\n",
+	     insert.ins_appending, insert.ins_contig, insert.ins_contig_index,
+	     insert.ins_free_records, insert.ins_tree_depth);
+
+	/*
+	 * Avoid growing the tree unless we're out of records and the
+	 * insert type requres one.
+	 */
+	if (insert.ins_contig != CONTIG_NONE || insert.ins_free_records)
+		goto out_add;
 
 	shift = ocfs2_find_branch_target(osb, inode, fe_bh, &bh);
 	if (shift < 0) {
@@ -866,13 +2382,9 @@ int ocfs2_insert_extent(struct ocfs2_sup
 	 * and didn't find room for any more extents - we need to add
 	 * another tree level */
 	if (shift) {
-		/* if we hit a leaf, we'd better be empty :) */
-		BUG_ON(le16_to_cpu(el->l_next_free_rec) !=
-		       le16_to_cpu(el->l_count));
 		BUG_ON(bh);
-		mlog(0, "ocfs2_allocate_extent: need to shift tree depth "
-		     "(current = %u)\n",
-		     le16_to_cpu(fe->id2.i_list.l_tree_depth));
+		mlog(0, "need to shift tree depth "
+		     "(current = %d)\n", insert.ins_tree_depth);
 
 		/* ocfs2_shift_tree_depth will return us a buffer with
 		 * the new extent block (so we can pass that to
@@ -883,15 +2395,16 @@ int ocfs2_insert_extent(struct ocfs2_sup
 			mlog_errno(status);
 			goto bail;
 		}
+		insert.ins_tree_depth++;
 		/* Special case: we have room now if we shifted from
 		 * tree_depth 0 */
-		if (fe->id2.i_list.l_tree_depth == cpu_to_le16(1))
+		if (insert.ins_tree_depth == 1)
 			goto out_add;
 	}
 
 	/* call ocfs2_add_branch to add the final part of the tree with
 	 * the new data. */
-	mlog(0, "ocfs2_allocate_extent: add branch. bh = %p\n", bh);
+	mlog(0, "add branch. bh = %p\n", bh);
 	status = ocfs2_add_branch(osb, handle, inode, fe_bh, bh, last_eb_bh,
 				  meta_ac);
 	if (status < 0) {
@@ -900,11 +2413,12 @@ int ocfs2_insert_extent(struct ocfs2_sup
 	}
 
 out_add:
-	/* Finally, we can add clusters. */
-	status = ocfs2_do_insert_extent(osb, handle, inode, fe_bh,
-					start_blk, new_clusters);
+	/* Finally, we can add clusters. This might rotate the tree for us. */
+	status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert);
 	if (status < 0)
 		mlog_errno(status);
+	else
+		ocfs2_extent_map_insert_rec(inode, &rec);
 
 bail:
 	if (bh)
@@ -1355,7 +2869,7 @@ int ocfs2_complete_truncate_log_recovery
 	tl = &tl_copy->id2.i_dealloc;
 	num_recs = le16_to_cpu(tl->tl_used);
 	mlog(0, "cleanup %u records from %llu\n", num_recs,
-	     (unsigned long long)tl_copy->i_blkno);
+	     (unsigned long long)le64_to_cpu(tl_copy->i_blkno));
 
 	mutex_lock(&tl_inode->i_mutex);
 	for(i = 0; i < num_recs; i++) {
@@ -1447,168 +2961,389 @@ int ocfs2_truncate_log_init(struct ocfs2
  * block will be deleted, and if it will, what the new last extent
  * block will be so we can update his h_next_leaf_blk field, as well
  * as the dinodes i_last_eb_blk */
-static int ocfs2_find_new_last_ext_blk(struct ocfs2_super *osb,
-				       struct inode *inode,
-				       struct ocfs2_dinode *fe,
-				       u32 new_i_clusters,
-				       struct buffer_head *old_last_eb,
+static int ocfs2_find_new_last_ext_blk(struct inode *inode,
+				       unsigned int clusters_to_del,
+				       struct ocfs2_path *path,
 				       struct buffer_head **new_last_eb)
 {
-	int i, status = 0;
-	u64 block = 0;
+	int next_free, ret = 0;
+	u32 cpos;
+	struct ocfs2_extent_rec *rec;
 	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_list *el;
 	struct buffer_head *bh = NULL;
 
 	*new_last_eb = NULL;
 
-	if (!OCFS2_IS_VALID_DINODE(fe)) {
-		OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
-		status = -EIO;
-		goto bail;
-	}
-
 	/* we have no tree, so of course, no last_eb. */
-	if (!fe->id2.i_list.l_tree_depth)
-		goto bail;
+	if (!path->p_tree_depth)
+		goto out;
 
 	/* trunc to zero special case - this makes tree_depth = 0
 	 * regardless of what it is.  */
-	if (!new_i_clusters)
-		goto bail;
+	if (OCFS2_I(inode)->ip_clusters == clusters_to_del)
+		goto out;
 
-	eb = (struct ocfs2_extent_block *) old_last_eb->b_data;
-	el = &(eb->h_list);
+	el = path_leaf_el(path);
 	BUG_ON(!el->l_next_free_rec);
 
-	/* Make sure that this guy will actually be empty after we
-	 * clear away the data. */
-	if (le32_to_cpu(el->l_recs[0].e_cpos) < new_i_clusters)
-		goto bail;
+	/*
+	 * Make sure that this extent list will actually be empty
+	 * after we clear away the data. We can shortcut out if
+	 * there's more than one non-empty extent in the
+	 * list. Otherwise, a check of the remaining extent is
+	 * necessary.
+	 */
+	next_free = le16_to_cpu(el->l_next_free_rec);
+	rec = NULL;
+	if (ocfs2_is_empty_extent(&el->l_recs[0])) {
+		if (next_free > 2)
+			goto out;
 
-	/* Ok, at this point, we know that last_eb will definitely
-	 * change, so lets traverse the tree and find the second to
-	 * last extent block. */
-	el = &(fe->id2.i_list);
-	/* go down the tree, */
-	do {
-		for(i = (le16_to_cpu(el->l_next_free_rec) - 1); i >= 0; i--) {
-			if (le32_to_cpu(el->l_recs[i].e_cpos) <
-			    new_i_clusters) {
-				block = le64_to_cpu(el->l_recs[i].e_blkno);
-				break;
-			}
+		/* We may have a valid extent in index 1, check it. */
+		if (next_free == 2)
+			rec = &el->l_recs[1];
+
+		/*
+		 * Fall through - no more nonempty extents, so we want
+		 * to delete this leaf.
+		 */
+	} else {
+		if (next_free > 1)
+			goto out;
+
+		rec = &el->l_recs[0];
+	}
+
+	if (rec) {
+		/*
+		 * Check it we'll only be trimming off the end of this
+		 * cluster.
+		 */
+		if (le16_to_cpu(rec->e_leaf_clusters) > clusters_to_del)
+			goto out;
+	}
+
+	ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path, &cpos);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_find_leaf(inode, path_root_el(path), cpos, &bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	eb = (struct ocfs2_extent_block *) bh->b_data;
+	el = &eb->h_list;
+	if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+		OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+		ret = -EROFS;
+		goto out;
+	}
+
+	*new_last_eb = bh;
+	get_bh(*new_last_eb);
+	mlog(0, "returning block %llu, (cpos: %u)\n",
+	     (unsigned long long)le64_to_cpu(eb->h_blkno), cpos);
+out:
+	brelse(bh);
+
+	return ret;
+}
+
+/*
+ * Trim some clusters off the rightmost edge of a tree. Only called
+ * during truncate.
+ *
+ * The caller needs to:
+ *   - start journaling of each path component.
+ *   - compute and fully set up any new last ext block
+ */
+static int ocfs2_trim_tree(struct inode *inode, struct ocfs2_path *path,
+			   handle_t *handle, struct ocfs2_truncate_context *tc,
+			   u32 clusters_to_del, u64 *delete_start)
+{
+	int ret, i, index = path->p_tree_depth;
+	u32 new_edge = 0;
+	u64 deleted_eb = 0;
+	struct buffer_head *bh;
+	struct ocfs2_extent_list *el;
+	struct ocfs2_extent_rec *rec;
+
+	*delete_start = 0;
+
+	while (index >= 0) {
+		bh = path->p_node[index].bh;
+		el = path->p_node[index].el;
+
+		mlog(0, "traveling tree (index = %d, block = %llu)\n",
+		     index,  (unsigned long long)bh->b_blocknr);
+
+		BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);
+
+		if (index !=
+		    (path->p_tree_depth - le16_to_cpu(el->l_tree_depth))) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %lu has invalid ext. block %llu",
+				    inode->i_ino,
+				    (unsigned long long)bh->b_blocknr);
+			ret = -EROFS;
+			goto out;
 		}
-		BUG_ON(i < 0);
 
-		if (bh) {
-			brelse(bh);
-			bh = NULL;
+find_tail_record:
+		i = le16_to_cpu(el->l_next_free_rec) - 1;
+		rec = &el->l_recs[i];
+
+		mlog(0, "Extent list before: record %d: (%u, %u, %llu), "
+		     "next = %u\n", i, le32_to_cpu(rec->e_cpos),
+		     ocfs2_rec_clusters(el, rec),
+		     (unsigned long long)le64_to_cpu(rec->e_blkno),
+		     le16_to_cpu(el->l_next_free_rec));
+
+		BUG_ON(ocfs2_rec_clusters(el, rec) < clusters_to_del);
+
+		if (le16_to_cpu(el->l_tree_depth) == 0) {
+			/*
+			 * If the leaf block contains a single empty
+			 * extent and no records, we can just remove
+			 * the block.
+			 */
+			if (i == 0 && ocfs2_is_empty_extent(rec)) {
+				memset(rec, 0,
+				       sizeof(struct ocfs2_extent_rec));
+				el->l_next_free_rec = cpu_to_le16(0);
+
+				goto delete;
+			}
+
+			/*
+			 * Remove any empty extents by shifting things
+			 * left. That should make life much easier on
+			 * the code below. This condition is rare
+			 * enough that we shouldn't see a performance
+			 * hit.
+			 */
+			if (ocfs2_is_empty_extent(&el->l_recs[0])) {
+				le16_add_cpu(&el->l_next_free_rec, -1);
+
+				for(i = 0;
+				    i < le16_to_cpu(el->l_next_free_rec); i++)
+					el->l_recs[i] = el->l_recs[i + 1];
+
+				memset(&el->l_recs[i], 0,
+				       sizeof(struct ocfs2_extent_rec));
+
+				/*
+				 * We've modified our extent list. The
+				 * simplest way to handle this change
+				 * is to being the search from the
+				 * start again.
+				 */
+				goto find_tail_record;
+			}
+
+			le16_add_cpu(&rec->e_leaf_clusters, -clusters_to_del);
+
+			/*
+			 * We'll use "new_edge" on our way back up the
+			 * tree to know what our rightmost cpos is.
+			 */
+			new_edge = le16_to_cpu(rec->e_leaf_clusters);
+			new_edge += le32_to_cpu(rec->e_cpos);
+
+			/*
+			 * The caller will use this to delete data blocks.
+			 */
+			*delete_start = le64_to_cpu(rec->e_blkno)
+				+ ocfs2_clusters_to_blocks(inode->i_sb,
+					le16_to_cpu(rec->e_leaf_clusters));
+
+			/*
+			 * If it's now empty, remove this record.
+			 */
+			if (le16_to_cpu(rec->e_leaf_clusters) == 0) {
+				memset(rec, 0,
+				       sizeof(struct ocfs2_extent_rec));
+				le16_add_cpu(&el->l_next_free_rec, -1);
+			}
+		} else {
+			if (le64_to_cpu(rec->e_blkno) == deleted_eb) {
+				memset(rec, 0,
+				       sizeof(struct ocfs2_extent_rec));
+				le16_add_cpu(&el->l_next_free_rec, -1);
+
+				goto delete;
+			}
+
+			/* Can this actually happen? */
+			if (le16_to_cpu(el->l_next_free_rec) == 0)
+				goto delete;
+
+			/*
+			 * We never actually deleted any clusters
+			 * because our leaf was empty. There's no
+			 * reason to adjust the rightmost edge then.
+			 */
+			if (new_edge == 0)
+				goto delete;
+
+			rec->e_int_clusters = cpu_to_le32(new_edge);
+			le32_add_cpu(&rec->e_int_clusters,
+				     -le32_to_cpu(rec->e_cpos));
+
+			 /*
+			  * A deleted child record should have been
+			  * caught above.
+			  */
+			 BUG_ON(le32_to_cpu(rec->e_int_clusters) == 0);
 		}
 
-		status = ocfs2_read_block(osb, block, &bh, OCFS2_BH_CACHED,
-					 inode);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
+delete:
+		ret = ocfs2_journal_dirty(handle, bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
 		}
-		eb = (struct ocfs2_extent_block *) bh->b_data;
-		el = &eb->h_list;
-		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
-			status = -EIO;
-			goto bail;
+
+		mlog(0, "extent list container %llu, after: record %d: "
+		     "(%u, %u, %llu), next = %u.\n",
+		     (unsigned long long)bh->b_blocknr, i,
+		     le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec),
+		     (unsigned long long)le64_to_cpu(rec->e_blkno),
+		     le16_to_cpu(el->l_next_free_rec));
+
+		/*
+		 * We must be careful to only attempt delete of an
+		 * extent block (and not the root inode block).
+		 */
+		if (index > 0 && le16_to_cpu(el->l_next_free_rec) == 0) {
+			struct ocfs2_extent_block *eb =
+				(struct ocfs2_extent_block *)bh->b_data;
+
+			/*
+			 * Save this for use when processing the
+			 * parent block.
+			 */
+			deleted_eb = le64_to_cpu(eb->h_blkno);
+
+			mlog(0, "deleting this extent block.\n");
+
+			ocfs2_remove_from_cache(inode, bh);
+
+			BUG_ON(ocfs2_rec_clusters(el, &el->l_recs[0]));
+			BUG_ON(le32_to_cpu(el->l_recs[0].e_cpos));
+			BUG_ON(le64_to_cpu(el->l_recs[0].e_blkno));
+
+			if (le16_to_cpu(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.
+				 */
+				ret = ocfs2_free_extent_block(handle,
+							      tc->tc_ext_alloc_inode,
+							      tc->tc_ext_alloc_bh,
+							      eb);
+
+				/* An error here is not fatal. */
+				if (ret < 0)
+					mlog_errno(ret);
+			}
+		} else {
+			deleted_eb = 0;
 		}
-	} while (el->l_tree_depth);
 
-	*new_last_eb = bh;
-	get_bh(*new_last_eb);
-	mlog(0, "returning block %llu\n",
-	     (unsigned long long)le64_to_cpu(eb->h_blkno));
-bail:
-	if (bh)
-		brelse(bh);
+		index--;
+	}
 
-	return status;
+	ret = 0;
+out:
+	return ret;
 }
 
 static int ocfs2_do_truncate(struct ocfs2_super *osb,
 			     unsigned int clusters_to_del,
 			     struct inode *inode,
 			     struct buffer_head *fe_bh,
-			     struct buffer_head *old_last_eb_bh,
 			     handle_t *handle,
-			     struct ocfs2_truncate_context *tc)
+			     struct ocfs2_truncate_context *tc,
+			     struct ocfs2_path *path)
 {
-	int status, i, depth;
+	int status;
 	struct ocfs2_dinode *fe;
-	struct ocfs2_extent_block *eb;
 	struct ocfs2_extent_block *last_eb = NULL;
 	struct ocfs2_extent_list *el;
-	struct buffer_head *eb_bh = NULL;
 	struct buffer_head *last_eb_bh = NULL;
-	u64 next_eb = 0;
 	u64 delete_blk = 0;
 
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
-	status = ocfs2_find_new_last_ext_blk(osb,
-					     inode,
-					     fe,
-					     le32_to_cpu(fe->i_clusters) -
-					     		clusters_to_del,
-					     old_last_eb_bh,
-					     &last_eb_bh);
+	status = ocfs2_find_new_last_ext_blk(inode, clusters_to_del,
+					     path, &last_eb_bh);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
 	}
-	if (last_eb_bh)
-		last_eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
 
-	status = ocfs2_journal_access(handle, inode, fe_bh,
-				      OCFS2_JOURNAL_ACCESS_WRITE);
+	/*
+	 * Each component will be touched, so we might as well journal
+	 * here to avoid having to handle errors later.
+	 */
+	status = ocfs2_journal_access_path(inode, handle, path);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
 	}
+
+	if (last_eb_bh) {
+		status = ocfs2_journal_access(handle, inode, last_eb_bh,
+					      OCFS2_JOURNAL_ACCESS_WRITE);
+		if (status < 0) {
+			mlog_errno(status);
+			goto bail;
+		}
+
+		last_eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
+	}
+
 	el = &(fe->id2.i_list);
 
+	/*
+	 * Lower levels depend on this never happening, but it's best
+	 * to check it up here before changing the tree.
+	 */
+	if (el->l_tree_depth && el->l_recs[0].e_int_clusters == 0) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %lu has an empty extent record, depth %u\n",
+			    inode->i_ino, le16_to_cpu(el->l_tree_depth));
+		status = -EROFS;
+		goto bail;
+	}
+
 	spin_lock(&OCFS2_I(inode)->ip_lock);
 	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) -
 				      clusters_to_del;
 	spin_unlock(&OCFS2_I(inode)->ip_lock);
 	le32_add_cpu(&fe->i_clusters, -clusters_to_del);
-	fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec);
-	fe->i_mtime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec);
 
-	i = le16_to_cpu(el->l_next_free_rec) - 1;
-
-	BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del);
-	le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del);
-	/* tree depth zero, we can just delete the clusters, otherwise
-	 * we need to record the offset of the next level extent block
-	 * as we may overwrite it. */
-	if (!el->l_tree_depth)
-		delete_blk = le64_to_cpu(el->l_recs[i].e_blkno)
-			+ ocfs2_clusters_to_blocks(osb->sb,
-					le32_to_cpu(el->l_recs[i].e_clusters));
-	else
-		next_eb = le64_to_cpu(el->l_recs[i].e_blkno);
-
-	if (!el->l_recs[i].e_clusters) {
-		/* if we deleted the whole extent record, then clear
-		 * out the other fields and update the extent
-		 * list. For depth > 0 trees, we've already recorded
-		 * the extent block in 'next_eb' */
-		el->l_recs[i].e_cpos = 0;
-		el->l_recs[i].e_blkno = 0;
-		BUG_ON(!el->l_next_free_rec);
-		le16_add_cpu(&el->l_next_free_rec, -1);
+	status = ocfs2_trim_tree(inode, path, handle, tc,
+				 clusters_to_del, &delete_blk);
+	if (status) {
+		mlog_errno(status);
+		goto bail;
 	}
 
-	depth = le16_to_cpu(el->l_tree_depth);
-	if (!fe->i_clusters) {
+	if (le32_to_cpu(fe->i_clusters) == 0) {
 		/* trunc to zero is a special case. */
 		el->l_tree_depth = 0;
 		fe->i_last_eb_blk = 0;
@@ -1625,12 +3360,6 @@ static int ocfs2_do_truncate(struct ocfs
 		/* If there will be a new last extent block, then by
 		 * definition, there cannot be any leaves to the right of
 		 * him. */
-		status = ocfs2_journal_access(handle, inode, last_eb_bh,
-					      OCFS2_JOURNAL_ACCESS_WRITE);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
-		}
 		last_eb->h_next_leaf_blk = 0;
 		status = ocfs2_journal_dirty(handle, last_eb_bh);
 		if (status < 0) {
@@ -1639,123 +3368,247 @@ static int ocfs2_do_truncate(struct ocfs
 		}
 	}
 
-	/* if our tree depth > 0, update all the tree blocks below us. */
-	while (depth) {
-		mlog(0, "traveling tree (depth = %d, next_eb = %llu)\n",
-		     depth,  (unsigned long long)next_eb);
-		status = ocfs2_read_block(osb, next_eb, &eb_bh,
-					  OCFS2_BH_CACHED, inode);
+	if (delete_blk) {
+		status = ocfs2_truncate_log_append(osb, handle, delete_blk,
+						   clusters_to_del);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
 		}
-		eb = (struct ocfs2_extent_block *)eb_bh->b_data;
-		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
-			status = -EIO;
-			goto bail;
+	}
+	status = 0;
+bail:
+
+	mlog_exit(status);
+	return status;
+}
+
+static int ocfs2_writeback_zero_func(handle_t *handle, struct buffer_head *bh)
+{
+	set_buffer_uptodate(bh);
+	mark_buffer_dirty(bh);
+	return 0;
+}
+
+static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
+{
+	set_buffer_uptodate(bh);
+	mark_buffer_dirty(bh);
+	return ocfs2_journal_dirty_data(handle, bh);
+}
+
+static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
+				     struct page **pages, int numpages,
+				     u64 phys, handle_t *handle)
+{
+	int i, ret, partial = 0;
+	void *kaddr;
+	struct page *page;
+	unsigned int from, to = PAGE_CACHE_SIZE;
+	struct super_block *sb = inode->i_sb;
+
+	BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
+
+	if (numpages == 0)
+		goto out;
+
+	from = isize & (PAGE_CACHE_SIZE - 1); /* 1st page offset */
+	if (PAGE_CACHE_SHIFT > OCFS2_SB(sb)->s_clustersize_bits) {
+		/*
+		 * Since 'from' has been capped to a value below page
+		 * size, this calculation won't be able to overflow
+		 * 'to'
+		 */
+		to = ocfs2_align_bytes_to_clusters(sb, from);
+
+		/*
+		 * The truncate tail in this case should never contain
+		 * more than one page at maximum. The loop below also
+		 * assumes this.
+		 */
+		BUG_ON(numpages != 1);
+	}
+
+	for(i = 0; i < numpages; i++) {
+		page = pages[i];
+
+		BUG_ON(from > PAGE_CACHE_SIZE);
+		BUG_ON(to > PAGE_CACHE_SIZE);
+
+		ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0);
+		if (ret)
+			mlog_errno(ret);
+
+		kaddr = kmap_atomic(page, KM_USER0);
+		memset(kaddr + from, 0, to - from);
+		kunmap_atomic(kaddr, KM_USER0);
+
+		/*
+		 * Need to set the buffers we zero'd into uptodate
+		 * here if they aren't - ocfs2_map_page_blocks()
+		 * might've skipped some
+		 */
+		if (ocfs2_should_order_data(inode)) {
+			ret = walk_page_buffers(handle,
+						page_buffers(page),
+						from, to, &partial,
+						ocfs2_ordered_zero_func);
+			if (ret < 0)
+				mlog_errno(ret);
+		} else {
+			ret = walk_page_buffers(handle, page_buffers(page),
+						from, to, &partial,
+						ocfs2_writeback_zero_func);
+			if (ret < 0)
+				mlog_errno(ret);
 		}
-		el = &(eb->h_list);
 
-		status = ocfs2_journal_access(handle, inode, eb_bh,
-					      OCFS2_JOURNAL_ACCESS_WRITE);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
+		if (!partial)
+			SetPageUptodate(page);
+
+		flush_dcache_page(page);
+
+		/*
+		 * Every page after the 1st one should be completely zero'd.
+		 */
+		from = 0;
+	}
+out:
+	if (pages) {
+		for (i = 0; i < numpages; i++) {
+			page = pages[i];
+			unlock_page(page);
+			mark_page_accessed(page);
+			page_cache_release(page);
 		}
+	}
+}
 
-		BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);
-		BUG_ON(depth != (le16_to_cpu(el->l_tree_depth) + 1));
+static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page **pages,
+				int *num, u64 *phys)
+{
+	int i, numpages = 0, ret = 0;
+	unsigned int csize = OCFS2_SB(inode->i_sb)->s_clustersize;
+	unsigned int ext_flags;
+	struct super_block *sb = inode->i_sb;
+	struct address_space *mapping = inode->i_mapping;
+	unsigned long index;
+	u64 next_cluster_bytes;
+
+	BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
+
+	/* Cluster boundary, so we don't need to grab any pages. */
+	if ((isize & (csize - 1)) == 0)
+		goto out;
 
-		i = le16_to_cpu(el->l_next_free_rec) - 1;
+	ret = ocfs2_extent_map_get_blocks(inode, isize >> sb->s_blocksize_bits,
+					  phys, NULL, &ext_flags);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
 
-		mlog(0, "extent block %llu, before: record %d: "
-		     "(%u, %u, %llu), next = %u\n",
-		     (unsigned long long)le64_to_cpu(eb->h_blkno), i,
-		     le32_to_cpu(el->l_recs[i].e_cpos),
-		     le32_to_cpu(el->l_recs[i].e_clusters),
-		     (unsigned long long)le64_to_cpu(el->l_recs[i].e_blkno),
-		     le16_to_cpu(el->l_next_free_rec));
+	/* Tail is a hole. */
+	if (*phys == 0)
+		goto out;
 
-		BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del);
-		le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del);
-
-		next_eb = le64_to_cpu(el->l_recs[i].e_blkno);
-		/* bottom-most block requires us to delete data.*/
-		if (!el->l_tree_depth)
-			delete_blk = le64_to_cpu(el->l_recs[i].e_blkno)
-				+ ocfs2_clusters_to_blocks(osb->sb,
-					le32_to_cpu(el->l_recs[i].e_clusters));
-		if (!el->l_recs[i].e_clusters) {
-			el->l_recs[i].e_cpos = 0;
-			el->l_recs[i].e_blkno = 0;
-			BUG_ON(!el->l_next_free_rec);
-			le16_add_cpu(&el->l_next_free_rec, -1);
-		}
-		mlog(0, "extent block %llu, after: record %d: "
-		     "(%u, %u, %llu), next = %u\n",
-		     (unsigned long long)le64_to_cpu(eb->h_blkno), i,
-		     le32_to_cpu(el->l_recs[i].e_cpos),
-		     le32_to_cpu(el->l_recs[i].e_clusters),
-		     (unsigned long long)le64_to_cpu(el->l_recs[i].e_blkno),
-		     le16_to_cpu(el->l_next_free_rec));
+	/* Tail is marked as unwritten, we can count on write to zero
+	 * in that case. */
+	if (ext_flags & OCFS2_EXT_UNWRITTEN)
+		goto out;
 
-		status = ocfs2_journal_dirty(handle, eb_bh);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
+	next_cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, isize);
+	index = isize >> PAGE_CACHE_SHIFT;
+	do {
+		pages[numpages] = grab_cache_page(mapping, index);
+		if (!pages[numpages]) {
+			ret = -ENOMEM;
+			mlog_errno(ret);
+			goto out;
 		}
 
-		if (!el->l_next_free_rec) {
-			mlog(0, "deleting this extent block.\n");
-
-			ocfs2_remove_from_cache(inode, eb_bh);
+		numpages++;
+		index++;
+	} while (index < (next_cluster_bytes >> PAGE_CACHE_SHIFT));
 
-			BUG_ON(el->l_recs[0].e_clusters);
-			BUG_ON(el->l_recs[0].e_cpos);
-			BUG_ON(el->l_recs[0].e_blkno);
-			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;
+out:
+	if (ret != 0) {
+		if (pages) {
+			for (i = 0; i < numpages; i++) {
+				if (pages[i]) {
+					unlock_page(pages[i]);
+					page_cache_release(pages[i]);
 				}
 			}
 		}
-		brelse(eb_bh);
-		eb_bh = NULL;
-		depth--;
+		numpages = 0;
 	}
 
-	BUG_ON(!delete_blk);
-	status = ocfs2_truncate_log_append(osb, handle, delete_blk,
-					   clusters_to_del);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
+	*num = numpages;
+
+	return ret;
+}
+
+/*
+ * Zero the area past i_size but still within an allocated
+ * cluster. This avoids exposing nonzero data on subsequent file
+ * extends.
+ *
+ * We need to call this before i_size is updated on the inode because
+ * otherwise block_write_full_page() will skip writeout of pages past
+ * i_size. The new_i_size parameter is passed for this reason.
+ */
+int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
+				 u64 new_i_size)
+{
+	int ret, numpages;
+	loff_t endbyte;
+	struct page **pages = NULL;
+	u64 phys;
+
+	/*
+	 * File systems which don't support sparse files zero on every
+	 * extend.
+	 */
+	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+		return 0;
+
+	pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb),
+			sizeof(struct page *), GFP_NOFS);
+	if (pages == NULL) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
 	}
-	status = 0;
-bail:
-	if (!status)
-		ocfs2_extent_map_trunc(inode, le32_to_cpu(fe->i_clusters));
-	else
-		ocfs2_extent_map_drop(inode, 0);
-	mlog_exit(status);
-	return status;
+
+	ret = ocfs2_grab_eof_pages(inode, new_i_size, pages, &numpages, &phys);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (numpages == 0)
+		goto out;
+
+	ocfs2_zero_cluster_pages(inode, new_i_size, pages, numpages, phys,
+				 handle);
+
+	/*
+	 * Initiate writeout of the pages we zero'd here. We don't
+	 * wait on them - the truncate_inode_pages() call later will
+	 * do that for us.
+	 */
+	endbyte = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size);
+	ret = do_sync_mapping_range(inode->i_mapping, new_i_size,
+				    endbyte - 1, SYNC_FILE_RANGE_WRITE);
+	if (ret)
+		mlog_errno(ret);
+
+out:
+	if (pages)
+		kfree(pages);
+
+	return ret;
 }
 
 /*
@@ -1770,82 +3623,90 @@ int ocfs2_commit_truncate(struct ocfs2_s
 			  struct ocfs2_truncate_context *tc)
 {
 	int status, i, credits, tl_sem = 0;
-	u32 clusters_to_del, target_i_clusters;
-	u64 last_eb = 0;
-	struct ocfs2_dinode *fe;
-	struct ocfs2_extent_block *eb;
+	u32 clusters_to_del, new_highest_cpos, range;
 	struct ocfs2_extent_list *el;
-	struct buffer_head *last_eb_bh;
 	handle_t *handle = NULL;
 	struct inode *tl_inode = osb->osb_tl_inode;
+	struct ocfs2_path *path = NULL;
 
 	mlog_entry_void();
 
 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-	target_i_clusters = ocfs2_clusters_for_bytes(osb->sb,
+	new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
 						     i_size_read(inode));
 
-	last_eb_bh = tc->tc_last_eb_bh;
-	tc->tc_last_eb_bh = NULL;
+	path = ocfs2_new_inode_path(fe_bh);
+	if (!path) {
+		status = -ENOMEM;
+		mlog_errno(status);
+		goto bail;
+	}
 
-	fe = (struct ocfs2_dinode *) fe_bh->b_data;
+	ocfs2_extent_map_trunc(inode, new_highest_cpos);
 
-	if (fe->id2.i_list.l_tree_depth) {
-		eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
-		el = &eb->h_list;
-	} else
-		el = &fe->id2.i_list;
-	last_eb = le64_to_cpu(fe->i_last_eb_blk);
 start:
-	mlog(0, "ocfs2_commit_truncate: fe->i_clusters = %u, "
-	     "last_eb = %llu, fe->i_last_eb_blk = %llu, "
-	     "fe->id2.i_list.l_tree_depth = %u last_eb_bh = %p\n",
-	     le32_to_cpu(fe->i_clusters), (unsigned long long)last_eb,
-	     (unsigned long long)le64_to_cpu(fe->i_last_eb_blk),
-	     le16_to_cpu(fe->id2.i_list.l_tree_depth), last_eb_bh);
-
-	if (last_eb != le64_to_cpu(fe->i_last_eb_blk)) {
-		mlog(0, "last_eb changed!\n");
-		BUG_ON(!fe->id2.i_list.l_tree_depth);
-		last_eb = le64_to_cpu(fe->i_last_eb_blk);
-		/* i_last_eb_blk may have changed, read it if
-		 * necessary. We don't have to worry about the
-		 * truncate to zero case here (where there becomes no
-		 * last_eb) because we never loop back after our work
-		 * is done. */
-		if (last_eb_bh) {
-			brelse(last_eb_bh);
-			last_eb_bh = NULL;
-		}
+	/*
+	 * Check that we still have allocation to delete.
+	 */
+	if (OCFS2_I(inode)->ip_clusters == 0) {
+		status = 0;
+		goto bail;
+	}
 
-		status = ocfs2_read_block(osb, last_eb,
-					  &last_eb_bh, OCFS2_BH_CACHED,
-					  inode);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
-		}
-		eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
-		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
-			status = -EIO;
-			goto bail;
-		}
-		el = &(eb->h_list);
+	/*
+	 * Truncate always works against the rightmost tree branch.
+	 */
+	status = ocfs2_find_path(inode, path, UINT_MAX);
+	if (status) {
+		mlog_errno(status);
+		goto bail;
+	}
+
+	mlog(0, "inode->ip_clusters = %u, tree_depth = %u\n",
+	     OCFS2_I(inode)->ip_clusters, path->p_tree_depth);
+
+	/*
+	 * By now, el will point to the extent list on the bottom most
+	 * portion of this tree. Only the tail record is considered in
+	 * each pass.
+	 *
+	 * We handle the following cases, in order:
+	 * - empty extent: delete the remaining branch
+	 * - remove the entire record
+	 * - remove a partial record
+	 * - no record needs to be removed (truncate has completed)
+	 */
+	el = path_leaf_el(path);
+	if (le16_to_cpu(el->l_next_free_rec) == 0) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %llu has empty extent block at %llu\n",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+			    (unsigned long long)path_leaf_bh(path)->b_blocknr);
+		status = -EROFS;
+		goto bail;
 	}
 
-	/* by now, el will point to the extent list on the bottom most
-	 * portion of this tree. */
 	i = le16_to_cpu(el->l_next_free_rec) - 1;
-	if (le32_to_cpu(el->l_recs[i].e_cpos) >= target_i_clusters)
-		clusters_to_del = le32_to_cpu(el->l_recs[i].e_clusters);
-	else
-		clusters_to_del = (le32_to_cpu(el->l_recs[i].e_clusters) +
+	range = le32_to_cpu(el->l_recs[i].e_cpos) +
+		ocfs2_rec_clusters(el, &el->l_recs[i]);
+	if (i == 0 && ocfs2_is_empty_extent(&el->l_recs[i])) {
+		clusters_to_del = 0;
+	} else if (le32_to_cpu(el->l_recs[i].e_cpos) >= new_highest_cpos) {
+		clusters_to_del = ocfs2_rec_clusters(el, &el->l_recs[i]);
+	} else if (range > new_highest_cpos) {
+		clusters_to_del = (ocfs2_rec_clusters(el, &el->l_recs[i]) +
 				   le32_to_cpu(el->l_recs[i].e_cpos)) -
-				  target_i_clusters;
+				  new_highest_cpos;
+	} else {
+		status = 0;
+		goto bail;
+	}
+
+	mlog(0, "clusters_to_del = %u in this pass, tail blk=%llu\n",
+	     clusters_to_del, (unsigned long long)path_leaf_bh(path)->b_blocknr);
 
-	mlog(0, "clusters_to_del = %u in this pass\n", clusters_to_del);
+	BUG_ON(clusters_to_del == 0);
 
 	mutex_lock(&tl_inode->i_mutex);
 	tl_sem = 1;
@@ -1861,7 +3722,8 @@ start:
 	}
 
 	credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
-						fe, el);
+						(struct ocfs2_dinode *)fe_bh->b_data,
+						el);
 	handle = ocfs2_start_trans(osb, credits);
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
@@ -1870,13 +3732,8 @@ start:
 		goto bail;
 	}
 
-	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
-	if (status < 0)
-		mlog_errno(status);
-
-	status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh,
-				   last_eb_bh, handle, tc);
+	status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh, handle,
+				   tc, path);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -1888,9 +3745,14 @@ start:
 	ocfs2_commit_trans(osb, handle);
 	handle = NULL;
 
-	BUG_ON(le32_to_cpu(fe->i_clusters) < target_i_clusters);
-	if (le32_to_cpu(fe->i_clusters) > target_i_clusters)
-		goto start;
+	ocfs2_reinit_path(path, 1);
+
+	/*
+	 * The check above will catch the case where we've truncated
+	 * away all allocation.
+	 */
+	goto start;
+
 bail:
 	up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
@@ -1902,8 +3764,7 @@ bail:
 	if (handle)
 		ocfs2_commit_trans(osb, handle);
 
-	if (last_eb_bh)
-		brelse(last_eb_bh);
+	ocfs2_free_path(path);
 
 	/* This will drop the ext_alloc cluster lock for us */
 	ocfs2_free_truncate_context(tc);
@@ -1912,7 +3773,6 @@ bail:
 	return status;
 }
 
-
 /*
  * Expects the inode to already be locked. This will figure out which
  * inodes need to be locked and will put them on the returned truncate
@@ -1923,7 +3783,7 @@ int ocfs2_prepare_truncate(struct ocfs2_
 			   struct buffer_head *fe_bh,
 			   struct ocfs2_truncate_context **tc)
 {
-	int status, metadata_delete;
+	int status, metadata_delete, i;
 	unsigned int new_i_clusters;
 	struct ocfs2_dinode *fe;
 	struct ocfs2_extent_block *eb;
@@ -1941,23 +3801,8 @@ int ocfs2_prepare_truncate(struct ocfs2_
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
 	mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size ="
-	     "%llu\n", fe->i_clusters, new_i_clusters,
-	     (unsigned long long)fe->i_size);
-
-	if (le32_to_cpu(fe->i_clusters) <= new_i_clusters) {
-		ocfs2_error(inode->i_sb, "Dinode %llu has cluster count "
-			    "%u and size %llu whereas struct inode has "
-			    "cluster count %u and size %llu which caused an "
-			    "invalid truncate to %u clusters.",
-			    (unsigned long long)le64_to_cpu(fe->i_blkno),
-			    le32_to_cpu(fe->i_clusters),
-			    (unsigned long long)le64_to_cpu(fe->i_size),
-			    OCFS2_I(inode)->ip_clusters, i_size_read(inode),
-			    new_i_clusters);
-		mlog_meta_lvb(ML_ERROR, &OCFS2_I(inode)->ip_meta_lockres);
-		status = -EIO;
-		goto bail;
-	}
+	     "%llu\n", le32_to_cpu(fe->i_clusters), new_i_clusters,
+	     (unsigned long long)le64_to_cpu(fe->i_size));
 
 	*tc = kzalloc(sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
 	if (!(*tc)) {
@@ -1986,7 +3831,15 @@ int ocfs2_prepare_truncate(struct ocfs2_
 			goto bail;
 		}
 		el = &(eb->h_list);
-		if (le32_to_cpu(el->l_recs[0].e_cpos) >= new_i_clusters)
+
+		i = 0;
+		if (ocfs2_is_empty_extent(&el->l_recs[0]))
+			i = 1;
+		/*
+		 * XXX: Should we check that next_free_rec contains
+		 * the extent?
+		 */
+		if (le32_to_cpu(el->l_recs[i].e_cpos) >= new_i_clusters)
 			metadata_delete = 1;
 	}
 
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 0b82e80..fbcb593 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -31,7 +31,8 @@ int ocfs2_insert_extent(struct ocfs2_sup
 			handle_t *handle,
 			struct inode *inode,
 			struct buffer_head *fe_bh,
-			u64 blkno,
+			u32 cpos,
+			u64 start_blk,
 			u32 new_clusters,
 			struct ocfs2_alloc_context *meta_ac);
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
@@ -70,6 +71,8 @@ struct ocfs2_truncate_context {
 	struct buffer_head *tc_last_eb_bh;
 };
 
+int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
+				 u64 new_i_size);
 int ocfs2_prepare_truncate(struct ocfs2_super *osb,
 			   struct inode *inode,
 			   struct buffer_head *fe_bh,
@@ -79,4 +82,26 @@ int ocfs2_commit_truncate(struct ocfs2_s
 			  struct buffer_head *fe_bh,
 			  struct ocfs2_truncate_context *tc);
 
+int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
+		    u32 cpos, struct buffer_head **leaf_bh);
+
+/*
+ * Helper function to look at the # of clusters in an extent record.
+ */
+static inline unsigned int ocfs2_rec_clusters(struct ocfs2_extent_list *el,
+					      struct ocfs2_extent_rec *rec)
+{
+	/*
+	 * Cluster count in extent records is slightly different
+	 * between interior nodes and leaf nodes. This is to support
+	 * unwritten extents which need a flags field in leaf node
+	 * records, thus shrinking the available space for a clusters
+	 * field.
+	 */
+	if (el->l_tree_depth)
+		return le32_to_cpu(rec->e_int_clusters);
+	else
+		return le16_to_cpu(rec->e_leaf_clusters);
+}
+
 #endif /* OCFS2_ALLOC_H */
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 875c114..8e7cafb 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -24,6 +24,8 @@ #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <asm/byteorder.h>
+#include <linux/swap.h>
+#include <linux/pipe_fs_i.h>
 
 #define MLOG_MASK_PREFIX ML_FILE_IO
 #include <cluster/masklog.h>
@@ -37,6 +39,7 @@ #include "extent_map.h"
 #include "file.h"
 #include "inode.h"
 #include "journal.h"
+#include "suballoc.h"
 #include "super.h"
 #include "symlink.h"
 
@@ -75,7 +78,8 @@ static int ocfs2_symlink_get_block(struc
 
 	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);
+		     (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
+		     fe->i_signature);
 		goto bail;
 	}
 
@@ -134,7 +138,9 @@ static int ocfs2_get_block(struct inode 
 			   struct buffer_head *bh_result, int create)
 {
 	int err = 0;
+	unsigned int ext_flags;
 	u64 p_blkno, past_eof;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
 	mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
 		   (unsigned long long)iblock, bh_result, create);
@@ -149,17 +155,8 @@ static int ocfs2_get_block(struct inode 
 		goto bail;
 	}
 
-	/* this can happen if another node truncs after our extend! */
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	if (iblock >= ocfs2_clusters_to_blocks(inode->i_sb,
-					       OCFS2_I(inode)->ip_clusters))
-		err = -EIO;
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-	if (err)
-		goto bail;
-
-	err = ocfs2_extent_map_get_blocks(inode, iblock, 1, &p_blkno,
-					  NULL);
+	err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL,
+					  &ext_flags);
 	if (err) {
 		mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
 		     "%llu, NULL)\n", err, inode, (unsigned long long)iblock,
@@ -167,22 +164,39 @@ static int ocfs2_get_block(struct inode 
 		goto bail;
 	}
 
-	map_bh(bh_result, inode->i_sb, p_blkno);
-
-	if (bh_result->b_blocknr == 0) {
-		err = -EIO;
-		mlog(ML_ERROR, "iblock = %llu p_blkno = %llu blkno=(%llu)\n",
-		     (unsigned long long)iblock,
-		     (unsigned long long)p_blkno,
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
-	}
+	/*
+	 * ocfs2 never allocates in this function - the only time we
+	 * need to use BH_New is when we're extending i_size on a file
+	 * system which doesn't support holes, in which case BH_New
+	 * allows block_prepare_write() to zero.
+	 */
+	mlog_bug_on_msg(create && p_blkno == 0 && ocfs2_sparse_alloc(osb),
+			"ino %lu, iblock %llu\n", inode->i_ino,
+			(unsigned long long)iblock);
+
+	/* Treat the unwritten extent as a hole for zeroing purposes. */
+	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
+		map_bh(bh_result, inode->i_sb, p_blkno);
+
+	if (!ocfs2_sparse_alloc(osb)) {
+		if (p_blkno == 0) {
+			err = -EIO;
+			mlog(ML_ERROR,
+			     "iblock = %llu p_blkno = %llu blkno=(%llu)\n",
+			     (unsigned long long)iblock,
+			     (unsigned long long)p_blkno,
+			     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+			mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters);
+			dump_stack();
+		}
 
-	past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
-	mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
-	     (unsigned long long)past_eof);
+		past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
+		mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
+		     (unsigned long long)past_eof);
 
-	if (create && (iblock >= past_eof))
-		set_buffer_new(bh_result);
+		if (create && (iblock >= past_eof))
+			set_buffer_new(bh_result);
+	}
 
 bail:
 	if (err < 0)
@@ -276,8 +290,11 @@ static int ocfs2_writepage(struct page *
 	return ret;
 }
 
-/* This can also be called from ocfs2_write_zero_page() which has done
- * it's own cluster locking. */
+/*
+ * This is called from ocfs2_write_zero_page() which has handled it's
+ * own cluster locking and has ensured allocation exists for those
+ * blocks to be written.
+ */
 int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page,
 			       unsigned from, unsigned to)
 {
@@ -292,44 +309,17 @@ int ocfs2_prepare_write_nolock(struct in
 	return ret;
 }
 
-/*
- * ocfs2_prepare_write() can be an outer-most ocfs2 call when it is called
- * from loopback.  It must be able to perform its own locking around
- * ocfs2_get_block().
- */
-static int ocfs2_prepare_write(struct file *file, struct page *page,
-			       unsigned from, unsigned to)
-{
-	struct inode *inode = page->mapping->host;
-	int ret;
-
-	mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to);
-
-	ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page);
-	if (ret != 0) {
-		mlog_errno(ret);
-		goto out;
-	}
-
-	ret = ocfs2_prepare_write_nolock(inode, page, from, to);
-
-	ocfs2_meta_unlock(inode, 0);
-out:
-	mlog_exit(ret);
-	return ret;
-}
-
 /* Taken from ext3. We don't necessarily need the full blown
  * functionality yet, but IMHO it's better to cut and paste the whole
  * thing so we can avoid introducing our own bugs (and easily pick up
  * their fixes when they happen) --Mark */
-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))
+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;
@@ -388,95 +378,6 @@ out:
 	return handle;
 }
 
-static int ocfs2_commit_write(struct file *file, struct page *page,
-			      unsigned from, unsigned to)
-{
-	int ret;
-	struct buffer_head *di_bh = NULL;
-	struct inode *inode = page->mapping->host;
-	handle_t *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 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, 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).
-	 */
-
-	ret = ocfs2_meta_lock_with_page(inode, &di_bh, 1, page);
-	if (ret != 0) {
-		mlog_errno(ret);
-		goto out;
-	}
-
-	ret = ocfs2_data_lock_with_page(inode, 1, page);
-	if (ret != 0) {
-		mlog_errno(ret);
-		goto out_unlock_meta;
-	}
-
-	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;
-	}
-
-	/* might update i_size */
-	ret = generic_commit_write(file, page, from, to);
-	if (ret < 0) {
-		mlog_errno(ret);
-		goto out_commit;
-	}
-
-	di = (struct ocfs2_dinode *)di_bh->b_data;
-
-	/* 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);
-
-	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;
-	}
-
-out_commit:
-	ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
-out_unlock_data:
-	ocfs2_data_unlock(inode, 1);
-out_unlock_meta:
-	ocfs2_meta_unlock(inode, 1);
-out:
-	if (di_bh)
-		brelse(di_bh);
-
-	mlog_exit(ret);
-	return ret;
-}
-
 static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
 {
 	sector_t status;
@@ -499,8 +400,7 @@ static sector_t ocfs2_bmap(struct addres
 		down_read(&OCFS2_I(inode)->ip_alloc_sem);
 	}
 
-	err = ocfs2_extent_map_get_blocks(inode, block, 1, &p_blkno,
-					  NULL);
+	err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL);
 
 	if (!INODE_JOURNAL(inode)) {
 		up_read(&OCFS2_I(inode)->ip_alloc_sem);
@@ -540,8 +440,8 @@ static int ocfs2_direct_IO_get_blocks(st
 				     struct buffer_head *bh_result, int create)
 {
 	int ret;
-	u64 p_blkno, inode_blocks;
-	int contig_blocks;
+	u64 p_blkno, inode_blocks, contig_blocks;
+	unsigned int ext_flags;
 	unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
 	unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
 
@@ -549,33 +449,20 @@ static int ocfs2_direct_IO_get_blocks(st
 	 * nicely aligned and of the right size, so there's no need
 	 * for us to check any of that. */
 
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	inode_blocks = ocfs2_clusters_to_blocks(inode->i_sb,
-						OCFS2_I(inode)->ip_clusters);
-
-	/*
-	 * For a read which begins past the end of file, we return a hole.
-	 */
-	if (!create && (iblock >= inode_blocks)) {
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
-		ret = 0;
-		goto bail;
-	}
+	inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
 
 	/*
 	 * Any write past EOF is not allowed because we'd be extending.
 	 */
 	if (create && (iblock + max_blocks) > inode_blocks) {
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
 		ret = -EIO;
 		goto bail;
 	}
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
 
 	/* This figures out the size of the next contiguous block, and
 	 * our logical offset */
-	ret = ocfs2_extent_map_get_blocks(inode, iblock, 1, &p_blkno,
-					  &contig_blocks);
+	ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno,
+					  &contig_blocks, &ext_flags);
 	if (ret) {
 		mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n",
 		     (unsigned long long)iblock);
@@ -583,7 +470,37 @@ static int ocfs2_direct_IO_get_blocks(st
 		goto bail;
 	}
 
-	map_bh(bh_result, inode->i_sb, p_blkno);
+	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %llu has a hole at block %llu\n",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+			    (unsigned long long)iblock);
+		ret = -EROFS;
+		goto bail;
+	}
+
+	/*
+	 * get_more_blocks() expects us to describe a hole by clearing
+	 * the mapped bit on bh_result().
+	 *
+	 * Consider an unwritten extent as a hole.
+	 */
+	if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN))
+		map_bh(bh_result, inode->i_sb, p_blkno);
+	else {
+		/*
+		 * ocfs2_prepare_inode_for_write() should have caught
+		 * the case where we'd be filling a hole and triggered
+		 * a buffered write instead.
+		 */
+		if (create) {
+			ret = -EIO;
+			mlog_errno(ret);
+			goto bail;
+		}
+
+		clear_buffer_mapped(bh_result);
+	}
 
 	/* make sure we don't map more than max_blocks blocks here as
 	   that's all the kernel will handle at this point. */
@@ -606,12 +523,17 @@ static void ocfs2_dio_end_io(struct kioc
 			     void *private)
 {
 	struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+	int level;
 
 	/* this io's submitter should not have unlocked this before we could */
 	BUG_ON(!ocfs2_iocb_is_rw_locked(iocb));
+
 	ocfs2_iocb_clear_rw_locked(iocb);
-	up_read(&inode->i_alloc_sem);
-	ocfs2_rw_unlock(inode, 0);
+
+	level = ocfs2_iocb_rw_locked_level(iocb);
+	if (!level)
+		up_read(&inode->i_alloc_sem);
+	ocfs2_rw_unlock(inode, level);
 }
 
 /*
@@ -647,23 +569,27 @@ static ssize_t ocfs2_direct_IO(int rw,
 
 	mlog_entry_void();
 
-	/*
-	 * We get PR data locks even for O_DIRECT.  This allows
-	 * concurrent O_DIRECT I/O but doesn't let O_DIRECT with
-	 * extending and buffered zeroing writes race.  If they did
-	 * race then the buffered zeroing could be written back after
-	 * the O_DIRECT I/O.  It's one thing to tell people not to mix
-	 * buffered and O_DIRECT writes, but expecting them to
-	 * understand that file extension is also an implicit buffered
-	 * write is too much.  By getting the PR we force writeback of
-	 * the buffered zeroing before proceeding.
-	 */
-	ret = ocfs2_data_lock(inode, 0);
-	if (ret < 0) {
-		mlog_errno(ret);
-		goto out;
+	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
+		/*
+		 * We get PR data locks even for O_DIRECT.  This
+		 * allows concurrent O_DIRECT I/O but doesn't let
+		 * O_DIRECT with extending and buffered zeroing writes
+		 * race.  If they did race then the buffered zeroing
+		 * could be written back after the O_DIRECT I/O.  It's
+		 * one thing to tell people not to mix buffered and
+		 * O_DIRECT writes, but expecting them to understand
+		 * that file extension is also an implicit buffered
+		 * write is too much.  By getting the PR we force
+		 * writeback of the buffered zeroing before
+		 * proceeding.
+		 */
+		ret = ocfs2_data_lock(inode, 0);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+		ocfs2_data_unlock(inode, 0);
 	}
-	ocfs2_data_unlock(inode, 0);
 
 	ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
 					    inode->i_sb->s_bdev, iov, offset,
@@ -675,11 +601,715 @@ out:
 	return ret;
 }
 
+static void ocfs2_figure_cluster_boundaries(struct ocfs2_super *osb,
+					    u32 cpos,
+					    unsigned int *start,
+					    unsigned int *end)
+{
+	unsigned int cluster_start = 0, cluster_end = PAGE_CACHE_SIZE;
+
+	if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits)) {
+		unsigned int cpp;
+
+		cpp = 1 << (PAGE_CACHE_SHIFT - osb->s_clustersize_bits);
+
+		cluster_start = cpos % cpp;
+		cluster_start = cluster_start << osb->s_clustersize_bits;
+
+		cluster_end = cluster_start + osb->s_clustersize;
+	}
+
+	BUG_ON(cluster_start > PAGE_SIZE);
+	BUG_ON(cluster_end > PAGE_SIZE);
+
+	if (start)
+		*start = cluster_start;
+	if (end)
+		*end = cluster_end;
+}
+
+/*
+ * 'from' and 'to' are the region in the page to avoid zeroing.
+ *
+ * If pagesize > clustersize, this function will avoid zeroing outside
+ * of the cluster boundary.
+ *
+ * from == to == 0 is code for "zero the entire cluster region"
+ */
+static void ocfs2_clear_page_regions(struct page *page,
+				     struct ocfs2_super *osb, u32 cpos,
+				     unsigned from, unsigned to)
+{
+	void *kaddr;
+	unsigned int cluster_start, cluster_end;
+
+	ocfs2_figure_cluster_boundaries(osb, cpos, &cluster_start, &cluster_end);
+
+	kaddr = kmap_atomic(page, KM_USER0);
+
+	if (from || to) {
+		if (from > cluster_start)
+			memset(kaddr + cluster_start, 0, from - cluster_start);
+		if (to < cluster_end)
+			memset(kaddr + to, 0, cluster_end - to);
+	} else {
+		memset(kaddr + cluster_start, 0, cluster_end - cluster_start);
+	}
+
+	kunmap_atomic(kaddr, KM_USER0);
+}
+
+/*
+ * Some of this taken from block_prepare_write(). We already have our
+ * mapping by now though, and the entire write will be allocating or
+ * it won't, so not much need to use BH_New.
+ *
+ * This will also skip zeroing, which is handled externally.
+ */
+int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
+			  struct inode *inode, unsigned int from,
+			  unsigned int to, int new)
+{
+	int ret = 0;
+	struct buffer_head *head, *bh, *wait[2], **wait_bh = wait;
+	unsigned int block_end, block_start;
+	unsigned int bsize = 1 << inode->i_blkbits;
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, bsize, 0);
+
+	head = page_buffers(page);
+	for (bh = head, block_start = 0; bh != head || !block_start;
+	     bh = bh->b_this_page, block_start += bsize) {
+		block_end = block_start + bsize;
+
+		/*
+		 * Ignore blocks outside of our i/o range -
+		 * they may belong to unallocated clusters.
+		 */
+		if (block_start >= to || block_end <= from) {
+			if (PageUptodate(page))
+				set_buffer_uptodate(bh);
+			continue;
+		}
+
+		/*
+		 * For an allocating write with cluster size >= page
+		 * size, we always write the entire page.
+		 */
+
+		if (buffer_new(bh))
+			clear_buffer_new(bh);
+
+		if (!buffer_mapped(bh)) {
+			map_bh(bh, inode->i_sb, *p_blkno);
+			unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
+		}
+
+		if (PageUptodate(page)) {
+			if (!buffer_uptodate(bh))
+				set_buffer_uptodate(bh);
+		} else if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
+		     (block_start < from || block_end > to)) {
+			ll_rw_block(READ, 1, &bh);
+			*wait_bh++=bh;
+		}
+
+		*p_blkno = *p_blkno + 1;
+	}
+
+	/*
+	 * If we issued read requests - let them complete.
+	 */
+	while(wait_bh > wait) {
+		wait_on_buffer(*--wait_bh);
+		if (!buffer_uptodate(*wait_bh))
+			ret = -EIO;
+	}
+
+	if (ret == 0 || !new)
+		return ret;
+
+	/*
+	 * If we get -EIO above, zero out any newly allocated blocks
+	 * to avoid exposing stale data.
+	 */
+	bh = head;
+	block_start = 0;
+	do {
+		void *kaddr;
+
+		block_end = block_start + bsize;
+		if (block_end <= from)
+			goto next_bh;
+		if (block_start >= to)
+			break;
+
+		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);
+
+next_bh:
+		block_start = block_end;
+		bh = bh->b_this_page;
+	} while (bh != head);
+
+	return ret;
+}
+
+/*
+ * This will copy user data from the buffer page in the splice
+ * context.
+ *
+ * For now, we ignore SPLICE_F_MOVE as that would require some extra
+ * communication out all the way to ocfs2_write().
+ */
+int ocfs2_map_and_write_splice_data(struct inode *inode,
+				  struct ocfs2_write_ctxt *wc, u64 *p_blkno,
+				  unsigned int *ret_from, unsigned int *ret_to)
+{
+	int ret;
+	unsigned int to, from, cluster_start, cluster_end;
+	char *src, *dst;
+	struct ocfs2_splice_write_priv *sp = wc->w_private;
+	struct pipe_buffer *buf = sp->s_buf;
+	unsigned long bytes, src_from;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	ocfs2_figure_cluster_boundaries(osb, wc->w_cpos, &cluster_start,
+					&cluster_end);
+
+	from = sp->s_offset;
+	src_from = sp->s_buf_offset;
+	bytes = wc->w_count;
+
+	if (wc->w_large_pages) {
+		/*
+		 * For cluster size < page size, we have to
+		 * calculate pos within the cluster and obey
+		 * the rightmost boundary.
+		 */
+		bytes = min(bytes, (unsigned long)(osb->s_clustersize
+				   - (wc->w_pos & (osb->s_clustersize - 1))));
+	}
+	to = from + bytes;
+
+	if (wc->w_this_page_new)
+		ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
+					    cluster_start, cluster_end, 1);
+	else
+		ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
+					    from, to, 0);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	BUG_ON(from > PAGE_CACHE_SIZE);
+	BUG_ON(to > PAGE_CACHE_SIZE);
+	BUG_ON(from > osb->s_clustersize);
+	BUG_ON(to > osb->s_clustersize);
+
+	src = buf->ops->map(sp->s_pipe, buf, 1);
+	dst = kmap_atomic(wc->w_this_page, KM_USER1);
+	memcpy(dst + from, src + src_from, bytes);
+	kunmap_atomic(wc->w_this_page, KM_USER1);
+	buf->ops->unmap(sp->s_pipe, buf, src);
+
+	wc->w_finished_copy = 1;
+
+	*ret_from = from;
+	*ret_to = to;
+out:
+
+	return bytes ? (unsigned int)bytes : ret;
+}
+
+/*
+ * This will copy user data from the iovec in the buffered write
+ * context.
+ */
+int ocfs2_map_and_write_user_data(struct inode *inode,
+				  struct ocfs2_write_ctxt *wc, u64 *p_blkno,
+				  unsigned int *ret_from, unsigned int *ret_to)
+{
+	int ret;
+	unsigned int to, from, cluster_start, cluster_end;
+	unsigned long bytes, src_from;
+	char *dst;
+	struct ocfs2_buffered_write_priv *bp = wc->w_private;
+	const struct iovec *cur_iov = bp->b_cur_iov;
+	char __user *buf;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	ocfs2_figure_cluster_boundaries(osb, wc->w_cpos, &cluster_start,
+					&cluster_end);
+
+	buf = cur_iov->iov_base + bp->b_cur_off;
+	src_from = (unsigned long)buf & ~PAGE_CACHE_MASK;
+
+	from = wc->w_pos & (PAGE_CACHE_SIZE - 1);
+
+	/*
+	 * This is a lot of comparisons, but it reads quite
+	 * easily, which is important here.
+	 */
+	/* Stay within the src page */
+	bytes = PAGE_SIZE - src_from;
+	/* Stay within the vector */
+	bytes = min(bytes,
+		    (unsigned long)(cur_iov->iov_len - bp->b_cur_off));
+	/* Stay within count */
+	bytes = min(bytes, (unsigned long)wc->w_count);
+	/*
+	 * For clustersize > page size, just stay within
+	 * target page, otherwise we have to calculate pos
+	 * within the cluster and obey the rightmost
+	 * boundary.
+	 */
+	if (wc->w_large_pages) {
+		/*
+		 * For cluster size < page size, we have to
+		 * calculate pos within the cluster and obey
+		 * the rightmost boundary.
+		 */
+		bytes = min(bytes, (unsigned long)(osb->s_clustersize
+				   - (wc->w_pos & (osb->s_clustersize - 1))));
+	} else {
+		/*
+		 * cluster size > page size is the most common
+		 * case - we just stay within the target page
+		 * boundary.
+		 */
+		bytes = min(bytes, PAGE_CACHE_SIZE - from);
+	}
+
+	to = from + bytes;
+
+	if (wc->w_this_page_new)
+		ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
+					    cluster_start, cluster_end, 1);
+	else
+		ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
+					    from, to, 0);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	BUG_ON(from > PAGE_CACHE_SIZE);
+	BUG_ON(to > PAGE_CACHE_SIZE);
+	BUG_ON(from > osb->s_clustersize);
+	BUG_ON(to > osb->s_clustersize);
+
+	dst = kmap(wc->w_this_page);
+	memcpy(dst + from, bp->b_src_buf + src_from, bytes);
+	kunmap(wc->w_this_page);
+
+	/*
+	 * XXX: This is slow, but simple. The caller of
+	 * ocfs2_buffered_write_cluster() is responsible for
+	 * passing through the iovecs, so it's difficult to
+	 * predict what our next step is in here after our
+	 * initial write. A future version should be pushing
+	 * that iovec manipulation further down.
+	 *
+	 * By setting this, we indicate that a copy from user
+	 * data was done, and subsequent calls for this
+	 * cluster will skip copying more data.
+	 */
+	wc->w_finished_copy = 1;
+
+	*ret_from = from;
+	*ret_to = to;
+out:
+
+	return bytes ? (unsigned int)bytes : ret;
+}
+
+/*
+ * Map, fill and write a page to disk.
+ *
+ * The work of copying data is done via callback.  Newly allocated
+ * pages which don't take user data will be zero'd (set 'new' to
+ * indicate an allocating write)
+ *
+ * Returns a negative error code or the number of bytes copied into
+ * the page.
+ */
+static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
+				 u64 *p_blkno, struct page *page,
+				 struct ocfs2_write_ctxt *wc, int new)
+{
+	int ret, copied = 0;
+	unsigned int from = 0, to = 0;
+	unsigned int cluster_start, cluster_end;
+	unsigned int zero_from = 0, zero_to = 0;
+
+	ocfs2_figure_cluster_boundaries(OCFS2_SB(inode->i_sb), wc->w_cpos,
+					&cluster_start, &cluster_end);
+
+	if ((wc->w_pos >> PAGE_CACHE_SHIFT) == page->index
+	    && !wc->w_finished_copy) {
+
+		wc->w_this_page = page;
+		wc->w_this_page_new = new;
+		ret = wc->w_write_data_page(inode, wc, p_blkno, &from, &to);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		copied = ret;
+
+		zero_from = from;
+		zero_to = to;
+		if (new) {
+			from = cluster_start;
+			to = cluster_end;
+		}
+	} else {
+		/*
+		 * If we haven't allocated the new page yet, we
+		 * shouldn't be writing it out without copying user
+		 * data. This is likely a math error from the caller.
+		 */
+		BUG_ON(!new);
+
+		from = cluster_start;
+		to = cluster_end;
+
+		ret = ocfs2_map_page_blocks(page, p_blkno, inode,
+					    cluster_start, cluster_end, 1);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	/*
+	 * Parts of newly allocated pages need to be zero'd.
+	 *
+	 * Above, we have also rewritten 'to' and 'from' - as far as
+	 * the rest of the function is concerned, the entire cluster
+	 * range inside of a page needs to be written.
+	 *
+	 * We can skip this if the page is up to date - it's already
+	 * been zero'd from being read in as a hole.
+	 */
+	if (new && !PageUptodate(page))
+		ocfs2_clear_page_regions(page, OCFS2_SB(inode->i_sb),
+					 wc->w_cpos, zero_from, zero_to);
+
+	flush_dcache_page(page);
+
+	if (ocfs2_should_order_data(inode)) {
+		ret = walk_page_buffers(handle,
+					page_buffers(page),
+					from, to, NULL,
+					ocfs2_journal_dirty_data);
+		if (ret < 0)
+			mlog_errno(ret);
+	}
+
+	/*
+	 * We don't use generic_commit_write() because we need to
+	 * handle our own i_size update.
+	 */
+	ret = block_commit_write(page, from, to);
+	if (ret)
+		mlog_errno(ret);
+out:
+
+	return copied ? copied : ret;
+}
+
+/*
+ * Do the actual write of some data into an inode. Optionally allocate
+ * in order to fulfill the write.
+ *
+ * cpos is the logical cluster offset within the file to write at
+ *
+ * 'phys' is the physical mapping of that offset. a 'phys' value of
+ * zero indicates that allocation is required. In this case, data_ac
+ * and meta_ac should be valid (meta_ac can be null if metadata
+ * allocation isn't required).
+ */
+static ssize_t ocfs2_write(struct file *file, u32 phys, handle_t *handle,
+			   struct buffer_head *di_bh,
+			   struct ocfs2_alloc_context *data_ac,
+			   struct ocfs2_alloc_context *meta_ac,
+			   struct ocfs2_write_ctxt *wc)
+{
+	int ret, i, numpages = 1, new;
+	unsigned int copied = 0;
+	u32 tmp_pos;
+	u64 v_blkno, p_blkno;
+	struct address_space *mapping = file->f_mapping;
+	struct inode *inode = mapping->host;
+	unsigned long index, start;
+	struct page **cpages;
+
+	new = phys == 0 ? 1 : 0;
+
+	/*
+	 * Figure out how many pages we'll be manipulating here. For
+	 * non allocating write, we just change the one
+	 * page. Otherwise, we'll need a whole clusters worth.
+	 */
+	if (new)
+		numpages = ocfs2_pages_per_cluster(inode->i_sb);
+
+	cpages = kzalloc(sizeof(*cpages) * numpages, GFP_NOFS);
+	if (!cpages) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		return ret;
+	}
+
+	/*
+	 * Fill our page array first. That way we've grabbed enough so
+	 * that we can zero and flush if we error after adding the
+	 * extent.
+	 */
+	if (new) {
+		start = ocfs2_align_clusters_to_page_index(inode->i_sb,
+							   wc->w_cpos);
+		v_blkno = ocfs2_clusters_to_blocks(inode->i_sb, wc->w_cpos);
+	} else {
+		start = wc->w_pos >> PAGE_CACHE_SHIFT;
+		v_blkno = wc->w_pos >> inode->i_sb->s_blocksize_bits;
+	}
+
+	for(i = 0; i < numpages; i++) {
+		index = start + i;
+
+		cpages[i] = find_or_create_page(mapping, index, GFP_NOFS);
+		if (!cpages[i]) {
+			ret = -ENOMEM;
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	if (new) {
+		/*
+		 * This is safe to call with the page locks - it won't take
+		 * any additional semaphores or cluster locks.
+		 */
+		tmp_pos = wc->w_cpos;
+		ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode,
+						 &tmp_pos, 1, di_bh, handle,
+						 data_ac, meta_ac, NULL);
+		/*
+		 * This shouldn't happen because we must have already
+		 * calculated the correct meta data allocation required. The
+		 * internal tree allocation code should know how to increase
+		 * transaction credits itself.
+		 *
+		 * If need be, we could handle -EAGAIN for a
+		 * RESTART_TRANS here.
+		 */
+		mlog_bug_on_msg(ret == -EAGAIN,
+				"Inode %llu: EAGAIN return during allocation.\n",
+				(unsigned long long)OCFS2_I(inode)->ip_blkno);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	ret = ocfs2_extent_map_get_blocks(inode, v_blkno, &p_blkno, NULL,
+					  NULL);
+	if (ret < 0) {
+
+		/*
+		 * XXX: Should we go readonly here?
+		 */
+
+		mlog_errno(ret);
+		goto out;
+	}
+
+	BUG_ON(p_blkno == 0);
+
+	for(i = 0; i < numpages; i++) {
+		ret = ocfs2_write_data_page(inode, handle, &p_blkno, cpages[i],
+					    wc, new);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		copied += ret;
+	}
+
+out:
+	for(i = 0; i < numpages; i++) {
+		unlock_page(cpages[i]);
+		mark_page_accessed(cpages[i]);
+		page_cache_release(cpages[i]);
+	}
+	kfree(cpages);
+
+	return copied ? copied : ret;
+}
+
+static void ocfs2_write_ctxt_init(struct ocfs2_write_ctxt *wc,
+				  struct ocfs2_super *osb, loff_t pos,
+				  size_t count, ocfs2_page_writer *cb,
+				  void *cb_priv)
+{
+	wc->w_count = count;
+	wc->w_pos = pos;
+	wc->w_cpos = wc->w_pos >> osb->s_clustersize_bits;
+	wc->w_finished_copy = 0;
+
+	if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits))
+		wc->w_large_pages = 1;
+	else
+		wc->w_large_pages = 0;
+
+	wc->w_write_data_page = cb;
+	wc->w_private = cb_priv;
+}
+
+/*
+ * Write a cluster to an inode. The cluster may not be allocated yet,
+ * in which case it will be. This only exists for buffered writes -
+ * O_DIRECT takes a more "traditional" path through the kernel.
+ *
+ * The caller is responsible for incrementing pos, written counts, etc
+ *
+ * For file systems that don't support sparse files, pre-allocation
+ * and page zeroing up until cpos should be done prior to this
+ * function call.
+ *
+ * Callers should be holding i_sem, and the rw cluster lock.
+ *
+ * Returns the number of user bytes written, or less than zero for
+ * error.
+ */
+ssize_t ocfs2_buffered_write_cluster(struct file *file, loff_t pos,
+				     size_t count, ocfs2_page_writer *actor,
+				     void *priv)
+{
+	int ret, credits = OCFS2_INODE_UPDATE_CREDITS;
+	ssize_t written = 0;
+	u32 phys;
+	struct inode *inode = file->f_mapping->host;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_alloc_context *data_ac = NULL;
+	struct ocfs2_alloc_context *meta_ac = NULL;
+	handle_t *handle;
+	struct ocfs2_write_ctxt wc;
+
+	ocfs2_write_ctxt_init(&wc, osb, pos, count, actor, priv);
+
+	ret = ocfs2_meta_lock(inode, &di_bh, 1);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	/*
+	 * Take alloc sem here to prevent concurrent lookups. That way
+	 * the mapping, zeroing and tree manipulation within
+	 * ocfs2_write() will be safe against ->readpage(). This
+	 * should also serve to lock out allocation from a shared
+	 * writeable region.
+	 */
+	down_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+	ret = ocfs2_get_clusters(inode, wc.w_cpos, &phys, NULL, NULL);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_meta;
+	}
+
+	/* phys == 0 means that allocation is required. */
+	if (phys == 0) {
+		ret = ocfs2_lock_allocators(inode, di, 1, &data_ac, &meta_ac);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_meta;
+		}
+
+		credits = ocfs2_calc_extend_credits(inode->i_sb, di, 1);
+	}
+
+	ret = ocfs2_data_lock(inode, 1);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_meta;
+	}
+
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out_data;
+	}
+
+	written = ocfs2_write(file, phys, handle, di_bh, data_ac,
+			      meta_ac, &wc);
+	if (written < 0) {
+		ret = written;
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	pos += written;
+	if (pos > inode->i_size) {
+		i_size_write(inode, pos);
+		mark_inode_dirty(inode);
+	}
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
+	di->i_size = cpu_to_le64((u64)i_size_read(inode));
+	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);
+
+	ret = ocfs2_journal_dirty(handle, di_bh);
+	if (ret)
+		mlog_errno(ret);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+
+out_data:
+	ocfs2_data_unlock(inode, 1);
+
+out_meta:
+	up_write(&OCFS2_I(inode)->ip_alloc_sem);
+	ocfs2_meta_unlock(inode, 1);
+
+out:
+	brelse(di_bh);
+	if (data_ac)
+		ocfs2_free_alloc_context(data_ac);
+	if (meta_ac)
+		ocfs2_free_alloc_context(meta_ac);
+
+	return written ? written : ret;
+}
+
 const struct address_space_operations ocfs2_aops = {
 	.readpage	= ocfs2_readpage,
 	.writepage	= ocfs2_writepage,
-	.prepare_write	= ocfs2_prepare_write,
-	.commit_write	= ocfs2_commit_write,
 	.bmap		= ocfs2_bmap,
 	.sync_page	= block_sync_page,
 	.direct_IO	= ocfs2_direct_IO,
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index f446a15..45821d4 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -30,12 +30,83 @@ handle_t *ocfs2_start_walk_page_trans(st
 							 unsigned from,
 							 unsigned to);
 
+int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
+			  struct inode *inode, unsigned int from,
+			  unsigned int to, int new);
+
+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 ocfs2_write_ctxt;
+typedef int (ocfs2_page_writer)(struct inode *, struct ocfs2_write_ctxt *,
+				u64 *, unsigned int *, unsigned int *);
+
+ssize_t ocfs2_buffered_write_cluster(struct file *file, loff_t pos,
+				     size_t count, ocfs2_page_writer *actor,
+				     void *priv);
+
+struct ocfs2_write_ctxt {
+	size_t				w_count;
+	loff_t				w_pos;
+	u32				w_cpos;
+	unsigned int			w_finished_copy;
+
+	/* This is true if page_size > cluster_size */
+	unsigned int			w_large_pages;
+
+	/* Filler callback and private data */
+	ocfs2_page_writer		*w_write_data_page;
+	void				*w_private;
+
+	/* Only valid for the filler callback */
+	struct page			*w_this_page;
+	unsigned int			w_this_page_new;
+};
+
+struct ocfs2_buffered_write_priv {
+	char				*b_src_buf;
+	const struct iovec		*b_cur_iov; /* Current iovec */
+	size_t				b_cur_off; /* Offset in the
+						    * current iovec */
+};
+int ocfs2_map_and_write_user_data(struct inode *inode,
+				  struct ocfs2_write_ctxt *wc,
+				  u64 *p_blkno,
+				  unsigned int *ret_from,
+				  unsigned int *ret_to);
+
+struct ocfs2_splice_write_priv {
+	struct splice_desc		*s_sd;
+	struct pipe_buffer		*s_buf;
+	struct pipe_inode_info		*s_pipe;
+	/* Neither offset value is ever larger than one page */
+	unsigned int			s_offset;
+	unsigned int			s_buf_offset;
+};
+int ocfs2_map_and_write_splice_data(struct inode *inode,
+				    struct ocfs2_write_ctxt *wc,
+				    u64 *p_blkno,
+				    unsigned int *ret_from,
+				    unsigned int *ret_to);
+
 /* all ocfs2_dio_end_io()'s fault */
 #define ocfs2_iocb_is_rw_locked(iocb) \
 	test_bit(0, (unsigned long *)&iocb->private)
-#define ocfs2_iocb_set_rw_locked(iocb) \
-	set_bit(0, (unsigned long *)&iocb->private)
+static inline void ocfs2_iocb_set_rw_locked(struct kiocb *iocb, int level)
+{
+	set_bit(0, (unsigned long *)&iocb->private);
+	if (level)
+		set_bit(1, (unsigned long *)&iocb->private);
+	else
+		clear_bit(1, (unsigned long *)&iocb->private);
+}
 #define ocfs2_iocb_clear_rw_locked(iocb) \
 	clear_bit(0, (unsigned long *)&iocb->private)
-
+#define ocfs2_iocb_rw_locked_level(iocb) \
+	test_bit(1, (unsigned long *)&iocb->private)
 #endif /* OCFS2_FILE_H */
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index eba282d..9791134 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -438,7 +438,7 @@ static inline void o2hb_prepare_block(st
 								   hb_block));
 
 	mlog(ML_HB_BIO, "our node generation = 0x%llx, cksum = 0x%x\n",
-	     (long long)cpu_to_le64(generation),
+	     (long long)generation,
 	     le32_to_cpu(hb_block->hb_cksum));
 }
 
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 636593b..2e975c0 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -147,7 +147,7 @@ static struct kset mlog_kset = {
 	.kobj   = {.name = "logmask", .ktype = &mlog_ktype},
 };
 
-int mlog_sys_init(struct subsystem *o2cb_subsys)
+int mlog_sys_init(struct kset *o2cb_subsys)
 {
 	int i = 0;
 
@@ -157,7 +157,7 @@ int mlog_sys_init(struct subsystem *o2cb
 	}
 	mlog_attr_ptrs[i] = NULL;
 
-	mlog_kset.subsys = o2cb_subsys;
+	kobj_set_kset_s(&mlog_kset, o2cb_subsys);
 	return kset_register(&mlog_kset);
 }
 
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h
index a42628b..75cd877 100644
--- a/fs/ocfs2/cluster/masklog.h
+++ b/fs/ocfs2/cluster/masklog.h
@@ -278,7 +278,7 @@ #define mlog_bug_on_msg(cond, fmt, args.
 
 #include <linux/kobject.h>
 #include <linux/sysfs.h>
-int mlog_sys_init(struct subsystem *o2cb_subsys);
+int mlog_sys_init(struct kset *o2cb_subsys);
 void mlog_sys_shutdown(void);
 
 #endif /* O2CLUSTER_MASKLOG_H */
diff --git a/fs/ocfs2/cluster/quorum.c b/fs/ocfs2/cluster/quorum.c
index 4705d65..bbacf7d 100644
--- a/fs/ocfs2/cluster/quorum.c
+++ b/fs/ocfs2/cluster/quorum.c
@@ -46,6 +46,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/reboot.h>
 
 #include "heartbeat.h"
 #include "nodemanager.h"
@@ -72,7 +73,9 @@ static void o2quo_fence_self(void)
 	/* panic spins with interrupts enabled.  with preempt
 	 * threads can still schedule, etc, etc */
 	o2hb_stop_all_regions();
-	panic("ocfs2 is very sorry to be fencing this system by panicing\n");
+
+	printk("ocfs2 is very sorry to be fencing this system by restarting\n");
+	emergency_restart();
 }
 
 /* Indicate that a timeout occured on a hearbeat region write. The
diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
index 1d9f6ac..64f6f37 100644
--- a/fs/ocfs2/cluster/sys.c
+++ b/fs/ocfs2/cluster/sys.c
@@ -42,7 +42,6 @@ struct o2cb_attribute {
 #define O2CB_ATTR(_name, _mode, _show, _store)	\
 struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
-#define to_o2cb_subsys(k) container_of(to_kset(k), struct subsystem, kset)
 #define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr)
 
 static ssize_t o2cb_interface_revision_show(char *buf)
@@ -79,7 +78,7 @@ static ssize_t
 o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer)
 {
 	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
-	struct subsystem *sbs = to_o2cb_subsys(kobj);
+	struct kset *sbs = to_kset(kobj);
 
 	BUG_ON(sbs != &o2cb_subsys);
 
@@ -93,7 +92,7 @@ o2cb_store(struct kobject * kobj, struct
 	     const char * buffer, size_t count)
 {
 	struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
-	struct subsystem *sbs = to_o2cb_subsys(kobj);
+	struct kset *sbs = to_kset(kobj);
 
 	BUG_ON(sbs != &o2cb_subsys);
 
@@ -112,7 +111,7 @@ int o2cb_sys_init(void)
 {
 	int ret;
 
-	o2cb_subsys.kset.kobj.ktype = &o2cb_subsys_type;
+	o2cb_subsys.kobj.ktype = &o2cb_subsys_type;
 	ret = subsystem_register(&o2cb_subsys);
 	if (ret)
 		return ret;
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 69caf3e..0b229a9 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1496,7 +1496,7 @@ static void o2net_start_connect(struct w
 	sock->sk->sk_allocation = GFP_ATOMIC;
 
 	myaddr.sin_family = AF_INET;
-	myaddr.sin_addr.s_addr = (__force u32)mynode->nd_ipv4_address;
+	myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
 	myaddr.sin_port = (__force u16)htons(0); /* any port */
 
 	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
@@ -1521,8 +1521,8 @@ static void o2net_start_connect(struct w
 	spin_unlock(&nn->nn_lock);
 
 	remoteaddr.sin_family = AF_INET;
-	remoteaddr.sin_addr.s_addr = (__force u32)node->nd_ipv4_address;
-	remoteaddr.sin_port = (__force u16)node->nd_ipv4_port;
+	remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
+	remoteaddr.sin_port = node->nd_ipv4_port;
 
 	ret = sc->sc_sock->ops->connect(sc->sc_sock,
 					(struct sockaddr *)&remoteaddr,
@@ -1810,8 +1810,8 @@ static int o2net_open_listening_sock(__b
 	int ret;
 	struct sockaddr_in sin = {
 		.sin_family = PF_INET,
-		.sin_addr = { .s_addr = (__force u32)addr },
-		.sin_port = (__force u16)port,
+		.sin_addr = { .s_addr = addr },
+		.sin_port = port,
 	};
 
 	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
index 4dae5df..9606111 100644
--- a/fs/ocfs2/cluster/tcp_internal.h
+++ b/fs/ocfs2/cluster/tcp_internal.h
@@ -38,6 +38,9 @@ #define O2NET_QUORUM_DELAY_MS	((o2hb_dea
  * 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 8:
+ * 	- Replace delete inode votes with a cluster lock
+ *
  * New in version 7:
  * 	- DLM join domain includes the live nodemap
  *
@@ -57,7 +60,7 @@ #define O2NET_QUORUM_DELAY_MS	((o2hb_dea
  * 	- full 64 bit i_size in the metadata lock lvbs
  * 	- introduction of "rw" lock and pushing meta/data locking down
  */
-#define O2NET_PROTOCOL_VERSION 7ULL
+#define O2NET_PROTOCOL_VERSION 8ULL
 struct o2net_handshake {
 	__be64	protocol_version;
 	__be64	connector_id;
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 66821e1..c441ef1 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -358,15 +358,17 @@ int ocfs2_do_extend_dir(struct super_blo
 {
 	int status;
 	int extend;
-	u64 p_blkno;
+	u64 p_blkno, v_blkno;
 
 	spin_lock(&OCFS2_I(dir)->ip_lock);
 	extend = (i_size_read(dir) == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters));
 	spin_unlock(&OCFS2_I(dir)->ip_lock);
 
 	if (extend) {
-		status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, 1,
-						    parent_fe_bh, handle,
+		u32 offset = OCFS2_I(dir)->ip_clusters;
+
+		status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset,
+						    1, parent_fe_bh, handle,
 						    data_ac, meta_ac, NULL);
 		BUG_ON(status == -EAGAIN);
 		if (status < 0) {
@@ -375,9 +377,8 @@ int ocfs2_do_extend_dir(struct super_blo
 		}
 	}
 
-	status = ocfs2_extent_map_get_blocks(dir, (dir->i_blocks >>
-						   (sb->s_blocksize_bits - 9)),
-					     1, &p_blkno, NULL);
+	v_blkno = ocfs2_blocks_for_bytes(sb, i_size_read(dir));
+	status = ocfs2_extent_map_get_blocks(dir, v_blkno, &p_blkno, NULL, NULL);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -402,7 +403,7 @@ static int ocfs2_extend_dir(struct ocfs2
 			    struct buffer_head **new_de_bh)
 {
 	int status = 0;
-	int credits, num_free_extents;
+	int credits, num_free_extents, drop_alloc_sem = 0;
 	loff_t dir_i_size;
 	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
 	struct ocfs2_alloc_context *data_ac = NULL;
@@ -451,6 +452,9 @@ static int ocfs2_extend_dir(struct ocfs2
 		credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
 	}
 
+	down_write(&OCFS2_I(dir)->ip_alloc_sem);
+	drop_alloc_sem = 1;
+
 	handle = ocfs2_start_trans(osb, credits);
 	if (IS_ERR(handle)) {
 		status = PTR_ERR(handle);
@@ -486,7 +490,7 @@ static int ocfs2_extend_dir(struct ocfs2
 
 	dir_i_size += dir->i_sb->s_blocksize;
 	i_size_write(dir, dir_i_size);
-	dir->i_blocks = ocfs2_align_bytes_to_sectors(dir_i_size);
+	dir->i_blocks = ocfs2_inode_sector_count(dir);
 	status = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
 	if (status < 0) {
 		mlog_errno(status);
@@ -496,6 +500,8 @@ static int ocfs2_extend_dir(struct ocfs2
 	*new_de_bh = new_bh;
 	get_bh(*new_de_bh);
 bail:
+	if (drop_alloc_sem)
+		up_write(&OCFS2_I(dir)->ip_alloc_sem);
 	if (handle)
 		ocfs2_commit_trans(osb, handle);
 
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index 241cad3..2fd8bde 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -312,8 +312,8 @@ int dlm_proxy_ast_handler(struct o2net_m
 	    past->type != DLM_BAST) {
 		mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu"
 		     "name=%.*s\n", past->type, 
-		     dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
-		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+		     dlm_get_lock_cookie_node(cookie),
+		     dlm_get_lock_cookie_seq(cookie),
 		     locklen, name);
 		ret = DLM_IVLOCKID;
 		goto leave;
@@ -324,8 +324,8 @@ int dlm_proxy_ast_handler(struct o2net_m
 		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(be64_to_cpu(cookie)),
-		     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+		     dlm_get_lock_cookie_node(cookie),
+		     dlm_get_lock_cookie_seq(cookie),
 		     locklen, name, locklen);
 		ret = DLM_IVLOCKID;
 		goto leave;
@@ -370,8 +370,8 @@ int dlm_proxy_ast_handler(struct o2net_m
 
 	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(be64_to_cpu(cookie)),
-	     dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+	     dlm_get_lock_cookie_node(cookie),
+	     dlm_get_lock_cookie_seq(cookie),
 	     locklen, name, locklen);
 
 	ret = DLM_NORMAL;
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index c558442..d836b98 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -430,11 +430,10 @@ redo_bucket:
 
 			dlm_lockres_put(res);
 
-			cond_resched_lock(&dlm->spinlock);
-
 			if (dropped)
 				goto redo_bucket;
 		}
+		cond_resched_lock(&dlm->spinlock);
 		num += n;
 		mlog(0, "%s: touched %d lockreses in bucket %d "
 		     "(tot=%d)\n", dlm->name, n, i, num);
@@ -1035,7 +1034,7 @@ static int dlm_try_to_join_domain(struct
 {
 	int status = 0, tmpstat, node;
 	struct domain_join_ctxt *ctxt;
-	enum dlm_query_join_response response;
+	enum dlm_query_join_response response = JOIN_DISALLOW;
 
 	mlog_entry("%p", dlm);
 
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index de952eb..5671cf9 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -42,7 +42,6 @@ #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 
 #include <asm/uaccess.h>
@@ -263,8 +262,7 @@ static void dlmfs_init_once(void *foo,
 	struct dlmfs_inode_private *ip =
 		(struct dlmfs_inode_private *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		ip->ip_dlm = NULL;
 		ip->ip_parent = NULL;
 
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 6d4a83d..671c4ed 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -611,6 +611,7 @@ static int dlm_remaster_locks(struct dlm
 			}
 		} while (status != 0);
 
+		spin_lock(&dlm_reco_state_lock);
 		switch (ndata->state) {
 			case DLM_RECO_NODE_DATA_INIT:
 			case DLM_RECO_NODE_DATA_FINALIZE_SENT:
@@ -641,6 +642,7 @@ static int dlm_remaster_locks(struct dlm
 				     ndata->node_num, dead_node);
 				break;
 		}
+		spin_unlock(&dlm_reco_state_lock);
 	}
 
 	mlog(0, "done requesting all lock info\n");
@@ -1767,7 +1769,7 @@ static int dlm_process_recovery_data(str
 			/* lock is always created locally first, and
 			 * destroyed locally last.  it must be on the list */
 			if (!lock) {
-				u64 c = ml->cookie;
+				__be64 c = ml->cookie;
 				mlog(ML_ERROR, "could not find local lock "
 					       "with cookie %u:%llu!\n",
 				     dlm_get_lock_cookie_node(be64_to_cpu(c)),
@@ -1876,7 +1878,7 @@ skip_lvb:
 		spin_lock(&res->spinlock);
 		list_for_each_entry(lock, queue, list) {
 			if (lock->ml.cookie == ml->cookie) {
-				u64 c = lock->ml.cookie;
+				__be64 c = lock->ml.cookie;
 				mlog(ML_ERROR, "%s:%.*s: %u:%llu: lock already "
 				     "exists on this lockres!\n", dlm->name,
 				     res->lockname.len, res->lockname.name,
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index 2b264c6..cebd089 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -76,7 +76,7 @@ repeat:
 		goto repeat;
 	}
 	remove_wait_queue(&res->wq, &wait);
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 }
 
 int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index e335541..d1bd305 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -27,7 +27,6 @@ #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/crc32.h>
 #include <linux/kthread.h>
 #include <linux/pagemap.h>
@@ -104,6 +103,35 @@ static int ocfs2_dentry_convert_worker(s
 static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
 				     struct ocfs2_lock_res *lockres);
 
+
+#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
+
+/* This aids in debugging situations where a bad LVB might be involved. */
+static void ocfs2_dump_meta_lvb_info(u64 level,
+				     const char *function,
+				     unsigned int line,
+				     struct ocfs2_lock_res *lockres)
+{
+	struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
+
+	mlog(level, "LVB information for %s (called from %s:%u):\n",
+	     lockres->l_name, function, line);
+	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 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),
+	     be32_to_cpu(lvb->lvb_iattr));
+}
+
+
 /*
  * OCFS2 Lock Resource Operations
  *
@@ -225,11 +253,17 @@ static struct ocfs2_lock_res_ops ocfs2_d
 	.flags		= 0,
 };
 
+static struct ocfs2_lock_res_ops ocfs2_inode_open_lops = {
+	.get_osb	= ocfs2_get_inode_osb,
+	.flags		= 0,
+};
+
 static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres)
 {
 	return lockres->l_type == OCFS2_LOCK_TYPE_META ||
 		lockres->l_type == OCFS2_LOCK_TYPE_DATA ||
-		lockres->l_type == OCFS2_LOCK_TYPE_RW;
+		lockres->l_type == OCFS2_LOCK_TYPE_RW ||
+		lockres->l_type == OCFS2_LOCK_TYPE_OPEN;
 }
 
 static inline struct inode *ocfs2_lock_res_inode(struct ocfs2_lock_res *lockres)
@@ -373,6 +407,9 @@ void ocfs2_inode_lock_res_init(struct oc
 		case OCFS2_LOCK_TYPE_DATA:
 			ops = &ocfs2_inode_data_lops;
 			break;
+		case OCFS2_LOCK_TYPE_OPEN:
+			ops = &ocfs2_inode_open_lops;
+			break;
 		default:
 			mlog_bug_on_msg(1, "type: %d\n", type);
 			ops = NULL; /* thanks, gcc */
@@ -1129,6 +1166,12 @@ int ocfs2_create_new_inode_locks(struct 
 		goto bail;
 	}
 
+	ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_open_lockres, 0, 0);
+	if (ret) {
+		mlog_errno(ret);
+		goto bail;
+	}
+
 bail:
 	mlog_exit(ret);
 	return ret;
@@ -1182,6 +1225,99 @@ void ocfs2_rw_unlock(struct inode *inode
 	mlog_exit_void();
 }
 
+/*
+ * ocfs2_open_lock always get PR mode lock.
+ */
+int ocfs2_open_lock(struct inode *inode)
+{
+	int status = 0;
+	struct ocfs2_lock_res *lockres;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	BUG_ON(!inode);
+
+	mlog_entry_void();
+
+	mlog(0, "inode %llu take PRMODE open lock\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	if (ocfs2_mount_local(osb))
+		goto out;
+
+	lockres = &OCFS2_I(inode)->ip_open_lockres;
+
+	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres,
+				    LKM_PRMODE, 0, 0);
+	if (status < 0)
+		mlog_errno(status);
+
+out:
+	mlog_exit(status);
+	return status;
+}
+
+int ocfs2_try_open_lock(struct inode *inode, int write)
+{
+	int status = 0, level;
+	struct ocfs2_lock_res *lockres;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	BUG_ON(!inode);
+
+	mlog_entry_void();
+
+	mlog(0, "inode %llu try to take %s open lock\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno,
+	     write ? "EXMODE" : "PRMODE");
+
+	if (ocfs2_mount_local(osb))
+		goto out;
+
+	lockres = &OCFS2_I(inode)->ip_open_lockres;
+
+	level = write ? LKM_EXMODE : LKM_PRMODE;
+
+	/*
+	 * The file system may already holding a PRMODE/EXMODE open lock.
+	 * Since we pass LKM_NOQUEUE, the request won't block waiting on
+	 * other nodes and the -EAGAIN will indicate to the caller that
+	 * this inode is still in use.
+	 */
+	status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres,
+				    level, LKM_NOQUEUE, 0);
+
+out:
+	mlog_exit(status);
+	return status;
+}
+
+/*
+ * ocfs2_open_unlock unlock PR and EX mode open locks.
+ */
+void ocfs2_open_unlock(struct inode *inode)
+{
+	struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_open_lockres;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	mlog_entry_void();
+
+	mlog(0, "inode %llu drop open lock\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	if (ocfs2_mount_local(osb))
+		goto out;
+
+	if(lockres->l_ro_holders)
+		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres,
+				     LKM_PRMODE);
+	if(lockres->l_ex_holders)
+		ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres,
+				     LKM_EXMODE);
+
+out:
+	mlog_exit_void();
+}
+
 int ocfs2_data_lock_full(struct inode *inode,
 			 int write,
 			 int arg_flags)
@@ -1387,8 +1523,7 @@ static void ocfs2_refresh_inode_from_lvb
 	if (S_ISLNK(inode->i_mode) && !oi->ip_clusters)
 		inode->i_blocks = 0;
 	else
-		inode->i_blocks =
-			ocfs2_align_bytes_to_sectors(i_size_read(inode));
+		inode->i_blocks = ocfs2_inode_sector_count(inode);
 
 	inode->i_uid     = be32_to_cpu(lvb->lvb_iuid);
 	inode->i_gid     = be32_to_cpu(lvb->lvb_igid);
@@ -1479,12 +1614,15 @@ static int ocfs2_meta_lock_update(struct
 {
 	int status = 0;
 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
-	struct ocfs2_lock_res *lockres = NULL;
+	struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres;
 	struct ocfs2_dinode *fe;
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
 	mlog_entry_void();
 
+	if (ocfs2_mount_local(osb))
+		goto bail;
+
 	spin_lock(&oi->ip_lock);
 	if (oi->ip_flags & OCFS2_INODE_DELETED) {
 		mlog(0, "Orphaned inode %llu was deleted while we "
@@ -1496,22 +1634,16 @@ static int ocfs2_meta_lock_update(struct
 	}
 	spin_unlock(&oi->ip_lock);
 
-	if (!ocfs2_mount_local(osb)) {
-		lockres = &oi->ip_meta_lockres;
-
-		if (!ocfs2_should_refresh_lock_res(lockres))
-			goto bail;
-	}
+	if (!ocfs2_should_refresh_lock_res(lockres))
+		goto bail;
 
 	/* This will discard any caching information we might have had
 	 * for the inode metadata. */
 	ocfs2_metadata_cache_purge(inode);
 
-	/* will do nothing for inode types that don't use the extent
-	 * map (directories, bitmap files, etc) */
 	ocfs2_extent_map_trunc(inode, 0);
 
-	if (lockres && ocfs2_meta_lvb_is_trustable(inode, 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);
@@ -1558,8 +1690,7 @@ static int ocfs2_meta_lock_update(struct
 
 	status = 0;
 bail_refresh:
-	if (lockres)
-		ocfs2_complete_lock_res_refresh(lockres, status);
+	ocfs2_complete_lock_res_refresh(lockres, status);
 bail:
 	mlog_exit(status);
 	return status;
@@ -1630,7 +1761,6 @@ int ocfs2_meta_lock_full(struct inode *i
 		wait_event(osb->recovery_event,
 			   ocfs2_node_map_is_empty(osb, &osb->recovery_map));
 
-	acquired = 0;
 	lockres = &OCFS2_I(inode)->ip_meta_lockres;
 	level = ex ? LKM_EXMODE : LKM_PRMODE;
 	dlm_flags = 0;
@@ -2458,13 +2588,20 @@ 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);
+			      &OCFS2_I(inode)->ip_open_lockres);
 	if (err < 0)
 		mlog_errno(err);
 
 	status = err;
 
 	err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb),
+			      &OCFS2_I(inode)->ip_data_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_meta_lockres);
 	if (err < 0)
 		mlog_errno(err);
@@ -2969,28 +3106,3 @@ static void ocfs2_schedule_blocked_lock(
 
 	mlog_exit_void();
 }
-
-/* This aids in debugging situations where a bad LVB might be involved. */
-void ocfs2_dump_meta_lvb_info(u64 level,
-			      const char *function,
-			      unsigned int line,
-			      struct ocfs2_lock_res *lockres)
-{
-	struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
-
-	mlog(level, "LVB information for %s (called from %s:%u):\n",
-	     lockres->l_name, function, line);
-	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 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),
-	     be32_to_cpu(lvb->lvb_iattr));
-}
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
index c343fca..492bad3 100644
--- a/fs/ocfs2/dlmglue.h
+++ b/fs/ocfs2/dlmglue.h
@@ -80,6 +80,9 @@ void ocfs2_data_unlock(struct inode *ino
 		       int write);
 int ocfs2_rw_lock(struct inode *inode, int write);
 void ocfs2_rw_unlock(struct inode *inode, int write);
+int ocfs2_open_lock(struct inode *inode);
+int ocfs2_try_open_lock(struct inode *inode, int write);
+void ocfs2_open_unlock(struct inode *inode);
 int ocfs2_meta_lock_atime(struct inode *inode,
 			  struct vfsmount *vfsmnt,
 			  int *level);
@@ -116,11 +119,4 @@ void ocfs2_process_blocked_lock(struct o
 struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void);
 void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug);
 
-/* aids in debugging and tracking lvbs */
-void ocfs2_dump_meta_lvb_info(u64 level,
-			      const char *function,
-			      unsigned int line,
-			      struct ocfs2_lock_res *lockres);
-#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
-
 #endif	/* DLMGLUE_H */
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index 56e1fef..bc48177 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -140,7 +140,7 @@ bail:
 	return parent;
 }
 
-static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len,
+static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
 			   int connectable)
 {
 	struct inode *inode = dentry->d_inode;
@@ -148,6 +148,7 @@ static int ocfs2_encode_fh(struct dentry
 	int type = 1;
 	u64 blkno;
 	u32 generation;
+	__le32 *fh = (__force __le32 *) fh_in;
 
 	mlog_entry("(0x%p, '%.*s', 0x%p, %d, %d)\n", dentry,
 		   dentry->d_name.len, dentry->d_name.name,
@@ -199,7 +200,7 @@ bail:
 	return type;
 }
 
-static struct dentry *ocfs2_decode_fh(struct super_block *sb, __be32 *fh,
+static struct dentry *ocfs2_decode_fh(struct super_block *sb, u32 *fh_in,
 				      int fh_len, int fileid_type,
 				      int (*acceptable)(void *context,
 						        struct dentry *de),
@@ -207,6 +208,7 @@ static struct dentry *ocfs2_decode_fh(st
 {
 	struct ocfs2_inode_handle handle, parent;
 	struct dentry *ret = NULL;
+	__le32 *fh = (__force __le32 *) fh_in;
 
 	mlog_entry("(0x%p, 0x%p, %d, %d, 0x%p, 0x%p)\n",
 		   sb, fh, fh_len, fileid_type, acceptable, context);
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index 80ac69f..ba2b2ab 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -3,8 +3,7 @@
  *
  * extent_map.c
  *
- * In-memory extent map for OCFS2.  Man, this code was prettier in
- * the library.
+ * Block/Cluster mapping functions
  *
  * Copyright (C) 2004 Oracle.  All rights reserved.
  *
@@ -26,1016 +25,528 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/rbtree.h>
 
 #define MLOG_MASK_PREFIX ML_EXTENT_MAP
 #include <cluster/masklog.h>
 
 #include "ocfs2.h"
 
+#include "alloc.h"
 #include "extent_map.h"
 #include "inode.h"
 #include "super.h"
 
 #include "buffer_head_io.h"
 
-
 /*
- * SUCK SUCK SUCK
- * Our headers are so bad that struct ocfs2_extent_map is in ocfs.h
- */
-
-struct ocfs2_extent_map_entry {
-	struct rb_node e_node;
-	int e_tree_depth;
-	struct ocfs2_extent_rec e_rec;
-};
-
-struct ocfs2_em_insert_context {
-	int need_left;
-	int need_right;
-	struct ocfs2_extent_map_entry *new_ent;
-	struct ocfs2_extent_map_entry *old_ent;
-	struct ocfs2_extent_map_entry *left_ent;
-	struct ocfs2_extent_map_entry *right_ent;
-};
-
-static struct kmem_cache *ocfs2_em_ent_cachep = NULL;
-
-
-static struct ocfs2_extent_map_entry *
-ocfs2_extent_map_lookup(struct ocfs2_extent_map *em,
-			u32 cpos, u32 clusters,
-			struct rb_node ***ret_p,
-			struct rb_node **ret_parent);
-static int ocfs2_extent_map_insert(struct inode *inode,
-				   struct ocfs2_extent_rec *rec,
-				   int tree_depth);
-static int ocfs2_extent_map_insert_entry(struct ocfs2_extent_map *em,
-					 struct ocfs2_extent_map_entry *ent);
-static int ocfs2_extent_map_find_leaf(struct inode *inode,
-				      u32 cpos, u32 clusters,
-				      struct ocfs2_extent_list *el);
-static int ocfs2_extent_map_lookup_read(struct inode *inode,
-					u32 cpos, u32 clusters,
-					struct ocfs2_extent_map_entry **ret_ent);
-static int ocfs2_extent_map_try_insert(struct inode *inode,
-				       struct ocfs2_extent_rec *rec,
-				       int tree_depth,
-				       struct ocfs2_em_insert_context *ctxt);
-
-/* returns 1 only if the rec contains all the given clusters -- that is that
- * rec's cpos is <= the cluster cpos and that the rec endpoint (cpos +
- * clusters) is >= the argument's endpoint */
-static int ocfs2_extent_rec_contains_clusters(struct ocfs2_extent_rec *rec,
-					      u32 cpos, u32 clusters)
-{
-	if (le32_to_cpu(rec->e_cpos) > cpos)
-		return 0;
-	if (cpos + clusters > le32_to_cpu(rec->e_cpos) + 
-			      le32_to_cpu(rec->e_clusters))
-		return 0;
-	return 1;
-}
-
-
-/*
- * Find an entry in the tree that intersects the region passed in.
- * Note that this will find straddled intervals, it is up to the
- * callers to enforce any boundary conditions.
- *
- * Callers must hold ip_lock.  This lookup is not guaranteed to return
- * a tree_depth 0 match, and as such can race inserts if the lock
- * were not held.
+ * The extent caching implementation is intentionally trivial.
  *
- * The rb_node garbage lets insertion share the search.  Trivial
- * callers pass NULL.
+ * We only cache a small number of extents stored directly on the
+ * inode, so linear order operations are acceptable. If we ever want
+ * to increase the size of the extent map, then these algorithms must
+ * get smarter.
  */
-static struct ocfs2_extent_map_entry *
-ocfs2_extent_map_lookup(struct ocfs2_extent_map *em,
-			u32 cpos, u32 clusters,
-			struct rb_node ***ret_p,
-			struct rb_node **ret_parent)
+
+void ocfs2_extent_map_init(struct inode *inode)
 {
-	struct rb_node **p = &em->em_extents.rb_node;
-	struct rb_node *parent = NULL;
-	struct ocfs2_extent_map_entry *ent = NULL;
-
-	while (*p)
-	{
-		parent = *p;
-		ent = rb_entry(parent, struct ocfs2_extent_map_entry,
-			       e_node);
-		if ((cpos + clusters) <= le32_to_cpu(ent->e_rec.e_cpos)) {
-			p = &(*p)->rb_left;
-			ent = NULL;
-		} else if (cpos >= (le32_to_cpu(ent->e_rec.e_cpos) +
-				    le32_to_cpu(ent->e_rec.e_clusters))) {
-			p = &(*p)->rb_right;
-			ent = NULL;
-		} else
-			break;
-	}
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	if (ret_p != NULL)
-		*ret_p = p;
-	if (ret_parent != NULL)
-		*ret_parent = parent;
-	return ent;
+	oi->ip_extent_map.em_num_items = 0;
+	INIT_LIST_HEAD(&oi->ip_extent_map.em_list);
 }
 
-/*
- * Find the leaf containing the interval we want.  While we're on our
- * way down the tree, fill in every record we see at any depth, because
- * we might want it later.
- *
- * Note that this code is run without ip_lock.  That's because it
- * sleeps while reading.  If someone is also filling the extent list at
- * the same time we are, we might have to restart.
- */
-static int ocfs2_extent_map_find_leaf(struct inode *inode,
-				      u32 cpos, u32 clusters,
-				      struct ocfs2_extent_list *el)
+static void __ocfs2_extent_map_lookup(struct ocfs2_extent_map *em,
+				      unsigned int cpos,
+				      struct ocfs2_extent_map_item **ret_emi)
 {
-	int i, ret;
-	struct buffer_head *eb_bh = NULL;
-	u64 blkno;
-	u32 rec_end;
-	struct ocfs2_extent_block *eb;
-	struct ocfs2_extent_rec *rec;
-
-	/*
-	 * The bh data containing the el cannot change here, because
-	 * we hold alloc_sem.  So we can do this without other
-	 * locks.
-	 */
-	while (el->l_tree_depth)
-	{
-		blkno = 0;
-		for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
-			rec = &el->l_recs[i];
-			rec_end = (le32_to_cpu(rec->e_cpos) +
-				   le32_to_cpu(rec->e_clusters));
-
-			ret = -EBADR;
-			if (rec_end > OCFS2_I(inode)->ip_clusters) {
-				mlog_errno(ret);
-				ocfs2_error(inode->i_sb,
-					    "Extent %d at e_blkno %llu of inode %llu goes past ip_clusters of %u\n",
-					    i,
-					    (unsigned long long)le64_to_cpu(rec->e_blkno),
-					    (unsigned long long)OCFS2_I(inode)->ip_blkno,
-					    OCFS2_I(inode)->ip_clusters);
-				goto out_free;
-			}
-
-			if (rec_end <= cpos) {
-				ret = ocfs2_extent_map_insert(inode, rec,
-						le16_to_cpu(el->l_tree_depth));
-				if (ret && (ret != -EEXIST)) {
-					mlog_errno(ret);
-					goto out_free;
-				}
-				continue;
-			}
-			if ((cpos + clusters) <= le32_to_cpu(rec->e_cpos)) {
-				ret = ocfs2_extent_map_insert(inode, rec,
-						le16_to_cpu(el->l_tree_depth));
-				if (ret && (ret != -EEXIST)) {
-					mlog_errno(ret);
-					goto out_free;
-				}
-				continue;
-			}
+	unsigned int range;
+	struct ocfs2_extent_map_item *emi;
 
-			/*
-			 * We've found a record that matches our
-			 * interval.  We don't insert it because we're
-			 * about to traverse it.
-			 */
-
-			/* Check to see if we're stradling */
-			ret = -ESRCH;
-			if (!ocfs2_extent_rec_contains_clusters(rec,
-							        cpos,
-								clusters)) {
-				mlog_errno(ret);
-				goto out_free;
-			}
+	*ret_emi = NULL;
 
-			/*
-			 * If we've already found a record, the el has
-			 * two records covering the same interval.
-			 * EEEK!
-			 */
-			ret = -EBADR;
-			if (blkno) {
-				mlog_errno(ret);
-				ocfs2_error(inode->i_sb,
-					    "Multiple extents for (cpos = %u, clusters = %u) on inode %llu; e_blkno %llu and rec %d at e_blkno %llu\n",
-					    cpos, clusters,
-					    (unsigned long long)OCFS2_I(inode)->ip_blkno,
-					    (unsigned long long)blkno, i,
-					    (unsigned long long)le64_to_cpu(rec->e_blkno));
-				goto out_free;
-			}
+	list_for_each_entry(emi, &em->em_list, ei_list) {
+		range = emi->ei_cpos + emi->ei_clusters;
 
-			blkno = le64_to_cpu(rec->e_blkno);
-		}
+		if (cpos >= emi->ei_cpos && cpos < range) {
+			list_move(&emi->ei_list, &em->em_list);
 
-		/*
-		 * We don't support holes, and we're still up
-		 * in the branches, so we'd better have found someone
-		 */
-		ret = -EBADR;
-		if (!blkno) {
-			ocfs2_error(inode->i_sb,
-				    "No record found for (cpos = %u, clusters = %u) on inode %llu\n",
-				    cpos, clusters,
-				    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-			mlog_errno(ret);
-			goto out_free;
-		}
-
-		if (eb_bh) {
-			brelse(eb_bh);
-			eb_bh = NULL;
-		}
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       blkno, &eb_bh, OCFS2_BH_CACHED,
-				       inode);
-		if (ret) {
-			mlog_errno(ret);
-			goto out_free;
-		}
-		eb = (struct ocfs2_extent_block *)eb_bh->b_data;
-		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
-			ret = -EIO;
-			goto out_free;
+			*ret_emi = emi;
+			break;
 		}
-		el = &eb->h_list;
 	}
+}
 
-	BUG_ON(el->l_tree_depth);
-
-	for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
-		rec = &el->l_recs[i];
-
-		if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) >
-		    OCFS2_I(inode)->ip_clusters) {
-			ret = -EBADR;
-			mlog_errno(ret);
-			ocfs2_error(inode->i_sb,
-				    "Extent %d at e_blkno %llu of inode %llu goes past ip_clusters of %u\n",
-				    i,
-				    (unsigned long long)le64_to_cpu(rec->e_blkno),
-				    (unsigned long long)OCFS2_I(inode)->ip_blkno,
-				    OCFS2_I(inode)->ip_clusters);
-			return ret;
-		}
-
-		ret = ocfs2_extent_map_insert(inode, rec,
-					      le16_to_cpu(el->l_tree_depth));
-		if (ret && (ret != -EEXIST)) {
-			mlog_errno(ret);
-			goto out_free;
-		}
+static int ocfs2_extent_map_lookup(struct inode *inode, unsigned int cpos,
+				   unsigned int *phys, unsigned int *len,
+				   unsigned int *flags)
+{
+	unsigned int coff;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_extent_map_item *emi;
+
+	spin_lock(&oi->ip_lock);
+
+	__ocfs2_extent_map_lookup(&oi->ip_extent_map, cpos, &emi);
+	if (emi) {
+		coff = cpos - emi->ei_cpos;
+		*phys = emi->ei_phys + coff;
+		if (len)
+			*len = emi->ei_clusters - coff;
+		if (flags)
+			*flags = emi->ei_flags;
 	}
 
-	ret = 0;
+	spin_unlock(&oi->ip_lock);
 
-out_free:
-	if (eb_bh)
-		brelse(eb_bh);
+	if (emi == NULL)
+		return -ENOENT;
 
-	return ret;
+	return 0;
 }
 
 /*
- * This lookup actually will read from disk.  It has one invariant:
- * It will never re-traverse blocks.  This means that all inserts should
- * be new regions or more granular regions (both allowed by insert).
+ * Forget about all clusters equal to or greater than cpos.
  */
-static int ocfs2_extent_map_lookup_read(struct inode *inode,
-					u32 cpos,
-					u32 clusters,
-					struct ocfs2_extent_map_entry **ret_ent)
+void ocfs2_extent_map_trunc(struct inode *inode, unsigned int cpos)
 {
-	int ret;
-	u64 blkno;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent;
-	struct buffer_head *bh = NULL;
-	struct ocfs2_extent_block *eb;
-	struct ocfs2_dinode *di;
-	struct ocfs2_extent_list *el;
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	ent = ocfs2_extent_map_lookup(em, cpos, clusters, NULL, NULL);
-	if (ent) {
-		if (!ent->e_tree_depth) {
-			spin_unlock(&OCFS2_I(inode)->ip_lock);
-			*ret_ent = ent;
-			return 0;
-		}
-		blkno = le64_to_cpu(ent->e_rec.e_blkno);
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno, &bh,
-				       OCFS2_BH_CACHED, inode);
-		if (ret) {
-			mlog_errno(ret);
-			if (bh)
-				brelse(bh);
-			return ret;
+	struct list_head *p, *n;
+	struct ocfs2_extent_map_item *emi;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_extent_map *em = &oi->ip_extent_map;
+	LIST_HEAD(tmp_list);
+	unsigned int range;
+
+	spin_lock(&oi->ip_lock);
+	list_for_each_safe(p, n, &em->em_list) {
+		emi = list_entry(p, struct ocfs2_extent_map_item, ei_list);
+
+		if (emi->ei_cpos >= cpos) {
+			/* Full truncate of this record. */
+			list_move(&emi->ei_list, &tmp_list);
+			BUG_ON(em->em_num_items == 0);
+			em->em_num_items--;
+			continue;
 		}
-		eb = (struct ocfs2_extent_block *)bh->b_data;
-		if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
-			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
-			brelse(bh);
-			return -EIO;
-		}
-		el = &eb->h_list;
-	} else {
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
 
-		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-				       OCFS2_I(inode)->ip_blkno, &bh,
-				       OCFS2_BH_CACHED, inode);
-		if (ret) {
-			mlog_errno(ret);
-			if (bh)
-				brelse(bh);
-			return ret;
+		range = emi->ei_cpos + emi->ei_clusters;
+		if (range > cpos) {
+			/* Partial truncate */
+			emi->ei_clusters = cpos - emi->ei_cpos;
 		}
-		di = (struct ocfs2_dinode *)bh->b_data;
-		if (!OCFS2_IS_VALID_DINODE(di)) {
-			brelse(bh);
-			OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, di);
-			return -EIO;
-		}
-		el = &di->id2.i_list;
-	}
-
-	ret = ocfs2_extent_map_find_leaf(inode, cpos, clusters, el);
-	brelse(bh);
-	if (ret) {
-		mlog_errno(ret);
-		return ret;
 	}
+	spin_unlock(&oi->ip_lock);
 
-	ent = ocfs2_extent_map_lookup(em, cpos, clusters, NULL, NULL);
-	if (!ent) {
-		ret = -ESRCH;
-		mlog_errno(ret);
-		return ret;
+	list_for_each_safe(p, n, &tmp_list) {
+		emi = list_entry(p, struct ocfs2_extent_map_item, ei_list);
+		list_del(&emi->ei_list);
+		kfree(emi);
 	}
-
-	/* FIXME: Make sure this isn't a corruption */
-	BUG_ON(ent->e_tree_depth);
-
-	*ret_ent = ent;
-
-	return 0;
 }
 
 /*
- * Callers must hold ip_lock.  This can insert pieces of the tree,
- * thus racing lookup if the lock weren't held.
+ * Is any part of emi2 contained within emi1
  */
-static int ocfs2_extent_map_insert_entry(struct ocfs2_extent_map *em,
-					 struct ocfs2_extent_map_entry *ent)
+static int ocfs2_ei_is_contained(struct ocfs2_extent_map_item *emi1,
+				 struct ocfs2_extent_map_item *emi2)
 {
-	struct rb_node **p, *parent;
-	struct ocfs2_extent_map_entry *old_ent;
+	unsigned int range1, range2;
 
-	old_ent = ocfs2_extent_map_lookup(em, le32_to_cpu(ent->e_rec.e_cpos),
-					  le32_to_cpu(ent->e_rec.e_clusters),
-					  &p, &parent);
-	if (old_ent)
-		return -EEXIST;
+	/*
+	 * Check if logical start of emi2 is inside emi1
+	 */
+	range1 = emi1->ei_cpos + emi1->ei_clusters;
+	if (emi2->ei_cpos >= emi1->ei_cpos && emi2->ei_cpos < range1)
+		return 1;
 
-	rb_link_node(&ent->e_node, parent, p);
-	rb_insert_color(&ent->e_node, &em->em_extents);
+	/*
+	 * Check if logical end of emi2 is inside emi1
+	 */
+	range2 = emi2->ei_cpos + emi2->ei_clusters;
+	if (range2 > emi1->ei_cpos && range2 <= range1)
+		return 1;
 
 	return 0;
 }
 
+static void ocfs2_copy_emi_fields(struct ocfs2_extent_map_item *dest,
+				  struct ocfs2_extent_map_item *src)
+{
+	dest->ei_cpos = src->ei_cpos;
+	dest->ei_phys = src->ei_phys;
+	dest->ei_clusters = src->ei_clusters;
+	dest->ei_flags = src->ei_flags;
+}
 
 /*
- * Simple rule: on any return code other than -EAGAIN, anything left
- * in the insert_context will be freed.
- *
- * Simple rule #2: A return code of -EEXIST from this function or
- * its calls to ocfs2_extent_map_insert_entry() signifies that another
- * thread beat us to the insert.  It is not an actual error, but it
- * tells the caller we have no more work to do.
+ * Try to merge emi with ins. Returns 1 if merge succeeds, zero
+ * otherwise.
  */
-static int ocfs2_extent_map_try_insert(struct inode *inode,
-				       struct ocfs2_extent_rec *rec,
-				       int tree_depth,
-				       struct ocfs2_em_insert_context *ctxt)
+static int ocfs2_try_to_merge_extent_map(struct ocfs2_extent_map_item *emi,
+					 struct ocfs2_extent_map_item *ins)
 {
-	int ret;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *old_ent;
-
-	ctxt->need_left = 0;
-	ctxt->need_right = 0;
-	ctxt->old_ent = NULL;
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	ret = ocfs2_extent_map_insert_entry(em, ctxt->new_ent);
-	if (!ret) {
-		ctxt->new_ent = NULL;
-		goto out_unlock;
-	}
-
-	/* Since insert_entry failed, the map MUST have old_ent */
-	old_ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos),
-					  le32_to_cpu(rec->e_clusters),
-					  NULL, NULL);
-
-	BUG_ON(!old_ent);
-
-	if (old_ent->e_tree_depth < tree_depth) {
-		/* Another thread beat us to the lower tree_depth */
-		ret = -EEXIST;
-		goto out_unlock;
-	}
-
-	if (old_ent->e_tree_depth == tree_depth) {
-		/*
-		 * Another thread beat us to this tree_depth.
-		 * Let's make sure we agree with that thread (the
-		 * extent_rec should be identical).
-		 */
-		if (!memcmp(rec, &old_ent->e_rec,
-			    sizeof(struct ocfs2_extent_rec)))
-			ret = 0;
-		else
-			/* FIXME: Should this be ESRCH/EBADR??? */
-			ret = -EEXIST;
-
-		goto out_unlock;
-	}
-
 	/*
-	 * We do it in this order specifically so that no actual tree
-	 * changes occur until we have all the pieces we need.  We
-	 * don't want malloc failures to leave an inconsistent tree.
-	 * Whenever we drop the lock, another process could be
-	 * inserting.  Also note that, if another process just beat us
-	 * to an insert, we might not need the same pieces we needed
-	 * the first go round.  In the end, the pieces we need will
-	 * be used, and the pieces we don't will be freed.
+	 * Handle contiguousness
 	 */
-	ctxt->need_left = !!(le32_to_cpu(rec->e_cpos) >
-			     le32_to_cpu(old_ent->e_rec.e_cpos));
-	ctxt->need_right = !!((le32_to_cpu(old_ent->e_rec.e_cpos) +
-			       le32_to_cpu(old_ent->e_rec.e_clusters)) >
-			      (le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)));
-	ret = -EAGAIN;
-	if (ctxt->need_left) {
-		if (!ctxt->left_ent)
-			goto out_unlock;
-		*(ctxt->left_ent) = *old_ent;
-		ctxt->left_ent->e_rec.e_clusters =
-			cpu_to_le32(le32_to_cpu(rec->e_cpos) -
-				    le32_to_cpu(ctxt->left_ent->e_rec.e_cpos));
-	}
-	if (ctxt->need_right) {
-		if (!ctxt->right_ent)
-			goto out_unlock;
-		*(ctxt->right_ent) = *old_ent;
-		ctxt->right_ent->e_rec.e_cpos =
-			cpu_to_le32(le32_to_cpu(rec->e_cpos) +
-				    le32_to_cpu(rec->e_clusters));
-		ctxt->right_ent->e_rec.e_clusters =
-			cpu_to_le32((le32_to_cpu(old_ent->e_rec.e_cpos) +
-				     le32_to_cpu(old_ent->e_rec.e_clusters)) -
-				    le32_to_cpu(ctxt->right_ent->e_rec.e_cpos));
-	}
-
-	rb_erase(&old_ent->e_node, &em->em_extents);
-	/* Now that he's erased, set him up for deletion */
-	ctxt->old_ent = old_ent;
-
-	if (ctxt->need_left) {
-		ret = ocfs2_extent_map_insert_entry(em,
-						    ctxt->left_ent);
-		if (ret)
-			goto out_unlock;
-		ctxt->left_ent = NULL;
+	if (ins->ei_phys == (emi->ei_phys + emi->ei_clusters) &&
+	    ins->ei_cpos == (emi->ei_cpos + emi->ei_clusters) &&
+	    ins->ei_flags == emi->ei_flags) {
+		emi->ei_clusters += ins->ei_clusters;
+		return 1;
+	} else if ((ins->ei_phys + ins->ei_clusters) == emi->ei_phys &&
+		   (ins->ei_cpos + ins->ei_clusters) == emi->ei_phys &&
+		   ins->ei_flags == emi->ei_flags) {
+		emi->ei_phys = ins->ei_phys;
+		emi->ei_cpos = ins->ei_cpos;
+		emi->ei_clusters += ins->ei_clusters;
+		return 1;
 	}
 
-	if (ctxt->need_right) {
-		ret = ocfs2_extent_map_insert_entry(em,
-						    ctxt->right_ent);
-		if (ret)
-			goto out_unlock;
-		ctxt->right_ent = NULL;
+	/*
+	 * Overlapping extents - this shouldn't happen unless we've
+	 * split an extent to change it's flags. That is exceedingly
+	 * rare, so there's no sense in trying to optimize it yet.
+	 */
+	if (ocfs2_ei_is_contained(emi, ins) ||
+	    ocfs2_ei_is_contained(ins, emi)) {
+		ocfs2_copy_emi_fields(emi, ins);
+		return 1;
 	}
 
-	ret = ocfs2_extent_map_insert_entry(em, ctxt->new_ent);
-
-	if (!ret)
-		ctxt->new_ent = NULL;
-
-out_unlock:
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	return ret;
+	/* No merge was possible. */
+	return 0;
 }
 
-
-static int ocfs2_extent_map_insert(struct inode *inode,
-				   struct ocfs2_extent_rec *rec,
-				   int tree_depth)
+/*
+ * In order to reduce complexity on the caller, this insert function
+ * is intentionally liberal in what it will accept.
+ *
+ * The only rule is that the truncate call *must* be used whenever
+ * records have been deleted. This avoids inserting overlapping
+ * records with different physical mappings.
+ */
+void ocfs2_extent_map_insert_rec(struct inode *inode,
+				 struct ocfs2_extent_rec *rec)
 {
-	int ret;
-	struct ocfs2_em_insert_context ctxt = {0, };
-
-	if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) >
-	    OCFS2_I(inode)->ip_map.em_clusters) {
-		ret = -EBADR;
-		mlog_errno(ret);
-		return ret;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_extent_map *em = &oi->ip_extent_map;
+	struct ocfs2_extent_map_item *emi, *new_emi = NULL;
+	struct ocfs2_extent_map_item ins;
+
+	ins.ei_cpos = le32_to_cpu(rec->e_cpos);
+	ins.ei_phys = ocfs2_blocks_to_clusters(inode->i_sb,
+					       le64_to_cpu(rec->e_blkno));
+	ins.ei_clusters = le16_to_cpu(rec->e_leaf_clusters);
+	ins.ei_flags = rec->e_flags;
+
+search:
+	spin_lock(&oi->ip_lock);
+
+	list_for_each_entry(emi, &em->em_list, ei_list) {
+		if (ocfs2_try_to_merge_extent_map(emi, &ins)) {
+			list_move(&emi->ei_list, &em->em_list);
+			spin_unlock(&oi->ip_lock);
+			goto out;
+		}
 	}
 
-	/* Zero e_clusters means a truncated tail record.  It better be EOF */
-	if (!rec->e_clusters) {
-		if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) !=
-		    OCFS2_I(inode)->ip_map.em_clusters) {
-			ret = -EBADR;
-			mlog_errno(ret);
-			ocfs2_error(inode->i_sb,
-				    "Zero e_clusters on non-tail extent record at e_blkno %llu on inode %llu\n",
-				    (unsigned long long)le64_to_cpu(rec->e_blkno),
-				    (unsigned long long)OCFS2_I(inode)->ip_blkno);
-			return ret;
-		}
+	/*
+	 * No item could be merged.
+	 *
+	 * Either allocate and add a new item, or overwrite the last recently
+	 * inserted.
+	 */
 
-		/* Ignore the truncated tail */
-		return 0;
-	}
+	if (em->em_num_items < OCFS2_MAX_EXTENT_MAP_ITEMS) {
+		if (new_emi == NULL) {
+			spin_unlock(&oi->ip_lock);
 
-	ret = -ENOMEM;
-	ctxt.new_ent = kmem_cache_alloc(ocfs2_em_ent_cachep,
-					GFP_NOFS);
-	if (!ctxt.new_ent) {
-		mlog_errno(ret);
-		return ret;
-	}
+			new_emi = kmalloc(sizeof(*new_emi), GFP_NOFS);
+			if (new_emi == NULL)
+				goto out;
 
-	ctxt.new_ent->e_rec = *rec;
-	ctxt.new_ent->e_tree_depth = tree_depth;
-
-	do {
-		ret = -ENOMEM;
-		if (ctxt.need_left && !ctxt.left_ent) {
-			ctxt.left_ent =
-				kmem_cache_alloc(ocfs2_em_ent_cachep,
-						 GFP_NOFS);
-			if (!ctxt.left_ent)
-				break;
-		}
-		if (ctxt.need_right && !ctxt.right_ent) {
-			ctxt.right_ent =
-				kmem_cache_alloc(ocfs2_em_ent_cachep,
-						 GFP_NOFS);
-			if (!ctxt.right_ent)
-				break;
+			goto search;
 		}
 
-		ret = ocfs2_extent_map_try_insert(inode, rec,
-						  tree_depth, &ctxt);
-	} while (ret == -EAGAIN);
-
-	if ((ret < 0) && (ret != -EEXIST))
-		mlog_errno(ret);
+		ocfs2_copy_emi_fields(new_emi, &ins);
+		list_add(&new_emi->ei_list, &em->em_list);
+		em->em_num_items++;
+		new_emi = NULL;
+	} else {
+		BUG_ON(list_empty(&em->em_list) || em->em_num_items == 0);
+		emi = list_entry(em->em_list.prev,
+				 struct ocfs2_extent_map_item, ei_list);
+		list_move(&emi->ei_list, &em->em_list);
+		ocfs2_copy_emi_fields(emi, &ins);
+	}
 
-	if (ctxt.left_ent)
-		kmem_cache_free(ocfs2_em_ent_cachep, ctxt.left_ent);
-	if (ctxt.right_ent)
-		kmem_cache_free(ocfs2_em_ent_cachep, ctxt.right_ent);
-	if (ctxt.old_ent)
-		kmem_cache_free(ocfs2_em_ent_cachep, ctxt.old_ent);
-	if (ctxt.new_ent)
-		kmem_cache_free(ocfs2_em_ent_cachep, ctxt.new_ent);
+	spin_unlock(&oi->ip_lock);
 
-	return ret;
+out:
+	if (new_emi)
+		kfree(new_emi);
 }
 
 /*
- * Append this record to the tail of the extent map.  It must be
- * tree_depth 0.  The record might be an extension of an existing
- * record, and as such that needs to be handled.  eg:
- *
- * Existing record in the extent map:
- *
- *	cpos = 10, len = 10
- *	|---------|
- *
- * New Record:
- *
- *	cpos = 10, len = 20
- *	|------------------|
- *
- * The passed record is the new on-disk record.  The new_clusters value
- * is how many clusters were added to the file.  If the append is a
- * contiguous append, the new_clusters has been added to
- * rec->e_clusters.  If the append is an entirely new extent, then
- * rec->e_clusters is == new_clusters.
+ * Return the 1st index within el which contains an extent start
+ * larger than v_cluster.
  */
-int ocfs2_extent_map_append(struct inode *inode,
-			    struct ocfs2_extent_rec *rec,
-			    u32 new_clusters)
+static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el,
+				       u32 v_cluster)
 {
-	int ret;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent;
-	struct ocfs2_extent_rec *old;
-
-	BUG_ON(!new_clusters);
-	BUG_ON(le32_to_cpu(rec->e_clusters) < new_clusters);
+	int i;
+	struct ocfs2_extent_rec *rec;
 
-	if (em->em_clusters < OCFS2_I(inode)->ip_clusters) {
-		/*
-		 * Size changed underneath us on disk.  Drop any
-		 * straddling records and update our idea of
-		 * i_clusters
-		 */
-		ocfs2_extent_map_drop(inode, em->em_clusters - 1);
-		em->em_clusters = OCFS2_I(inode)->ip_clusters;
-	}
+	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
+		rec = &el->l_recs[i];
 
-	mlog_bug_on_msg((le32_to_cpu(rec->e_cpos) +
-			 le32_to_cpu(rec->e_clusters)) !=
-			(em->em_clusters + new_clusters),
-			"Inode %llu:\n"
-			"rec->e_cpos = %u + rec->e_clusters = %u = %u\n"
-			"em->em_clusters = %u + new_clusters = %u = %u\n",
-			(unsigned long long)OCFS2_I(inode)->ip_blkno,
-			le32_to_cpu(rec->e_cpos), le32_to_cpu(rec->e_clusters),
-			le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters),
-			em->em_clusters, new_clusters,
-			em->em_clusters + new_clusters);
-
-	em->em_clusters += new_clusters;
-
-	ret = -ENOENT;
-	if (le32_to_cpu(rec->e_clusters) > new_clusters) {
-		/* This is a contiguous append */
-		ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos), 1,
-					      NULL, NULL);
-		if (ent) {
-			old = &ent->e_rec;
-			BUG_ON((le32_to_cpu(rec->e_cpos) +
-				le32_to_cpu(rec->e_clusters)) !=
-				 (le32_to_cpu(old->e_cpos) +
-				  le32_to_cpu(old->e_clusters) +
-				  new_clusters));
-			if (ent->e_tree_depth == 0) {
-				BUG_ON(le32_to_cpu(old->e_cpos) !=
-				       le32_to_cpu(rec->e_cpos));
-				BUG_ON(le64_to_cpu(old->e_blkno) !=
-				       le64_to_cpu(rec->e_blkno));
-				ret = 0;
-			}
-			/*
-			 * Let non-leafs fall through as -ENOENT to
-			 * force insertion of the new leaf.
-			 */
-			le32_add_cpu(&old->e_clusters, new_clusters);
-		}
+		if (v_cluster < le32_to_cpu(rec->e_cpos))
+			break;
 	}
 
-	if (ret == -ENOENT)
-		ret = ocfs2_extent_map_insert(inode, rec, 0);
-	if (ret < 0)
-		mlog_errno(ret);
-	return ret;
+	return i;
 }
 
-#if 0
-/* Code here is included but defined out as it completes the extent
- * map api and may be used in the future. */
-
 /*
- * Look up the record containing this cluster offset.  This record is
- * part of the extent map.  Do not free it.  Any changes you make to
- * it will reflect in the extent map.  So, if your last extent
- * is (cpos = 10, clusters = 10) and you truncate the file by 5
- * clusters, you can do:
+ * Figure out the size of a hole which starts at v_cluster within the given
+ * extent list.
  *
- * ret = ocfs2_extent_map_get_rec(em, orig_size - 5, &rec);
- * rec->e_clusters -= 5;
+ * If there is no more allocation past v_cluster, we return the maximum
+ * cluster size minus v_cluster.
  *
- * The lookup does not read from disk.  If the map isn't filled in for
- * an entry, you won't find it.
- *
- * Also note that the returned record is valid until alloc_sem is
- * dropped.  After that, truncate and extend can happen.  Caveat Emptor.
+ * If we have in-inode extents, then el points to the dinode list and
+ * eb_bh is NULL. Otherwise, eb_bh should point to the extent block
+ * containing el.
  */
-int ocfs2_extent_map_get_rec(struct inode *inode, u32 cpos,
-			     struct ocfs2_extent_rec **rec,
-			     int *tree_depth)
+static int ocfs2_figure_hole_clusters(struct inode *inode,
+				      struct ocfs2_extent_list *el,
+				      struct buffer_head *eb_bh,
+				      u32 v_cluster,
+				      u32 *num_clusters)
 {
-	int ret = -ENOENT;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent;
+	int ret, i;
+	struct buffer_head *next_eb_bh = NULL;
+	struct ocfs2_extent_block *eb, *next_eb;
 
-	*rec = NULL;
+	i = ocfs2_search_for_hole_index(el, v_cluster);
 
-	if (cpos >= OCFS2_I(inode)->ip_clusters)
-		return -EINVAL;
+	if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) {
+		eb = (struct ocfs2_extent_block *)eb_bh->b_data;
 
-	if (cpos >= em->em_clusters) {
 		/*
-		 * Size changed underneath us on disk.  Drop any
-		 * straddling records and update our idea of
-		 * i_clusters
+		 * Check the next leaf for any extents.
 		 */
-		ocfs2_extent_map_drop(inode, em->em_clusters - 1);
-		em->em_clusters = OCFS2_I(inode)->ip_clusters ;
-	}
-
-	ent = ocfs2_extent_map_lookup(&OCFS2_I(inode)->ip_map, cpos, 1,
-				      NULL, NULL);
 
-	if (ent) {
-		*rec = &ent->e_rec;
-		if (tree_depth)
-			*tree_depth = ent->e_tree_depth;
-		ret = 0;
-	}
+		if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
+			goto no_more_extents;
 
-	return ret;
-}
+		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+				       le64_to_cpu(eb->h_next_leaf_blk),
+				       &next_eb_bh, OCFS2_BH_CACHED, inode);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+		next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;
 
-int ocfs2_extent_map_get_clusters(struct inode *inode,
-				  u32 v_cpos, int count,
-				  u32 *p_cpos, int *ret_count)
-{
-	int ret;
-	u32 coff, ccount;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent = NULL;
+		if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) {
+			ret = -EROFS;
+			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb);
+			goto out;
+		}
 
-	*p_cpos = ccount = 0;
+		el = &next_eb->h_list;
 
-	if ((v_cpos + count) > OCFS2_I(inode)->ip_clusters)
-		return -EINVAL;
+		i = ocfs2_search_for_hole_index(el, v_cluster);
+	}
 
-	if ((v_cpos + count) > em->em_clusters) {
+no_more_extents:
+	if (i == le16_to_cpu(el->l_next_free_rec)) {
 		/*
-		 * Size changed underneath us on disk.  Drop any
-		 * straddling records and update our idea of
-		 * i_clusters
+		 * We're at the end of our existing allocation. Just
+		 * return the maximum number of clusters we could
+		 * possibly allocate.
 		 */
-		ocfs2_extent_map_drop(inode, em->em_clusters - 1);
-		em->em_clusters = OCFS2_I(inode)->ip_clusters;
+		*num_clusters = UINT_MAX - v_cluster;
+	} else {
+		*num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster;
 	}
 
+	ret = 0;
+out:
+	brelse(next_eb_bh);
+	return ret;
+}
 
-	ret = ocfs2_extent_map_lookup_read(inode, v_cpos, count, &ent);
-	if (ret)
-		return ret;
+/*
+ * Return the index of the extent record which contains cluster #v_cluster.
+ * -1 is returned if it was not found.
+ *
+ * Should work fine on interior and exterior nodes.
+ */
+static int ocfs2_search_extent_list(struct ocfs2_extent_list *el,
+				    u32 v_cluster)
+{
+	int ret = -1;
+	int i;
+	struct ocfs2_extent_rec *rec;
+	u32 rec_end, rec_start, clusters;
 
-	if (ent) {
-		/* We should never find ourselves straddling an interval */
-		if (!ocfs2_extent_rec_contains_clusters(&ent->e_rec,
-							v_cpos,
-							count))
-			return -ESRCH;
+	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
+		rec = &el->l_recs[i];
 
-		coff = v_cpos - le32_to_cpu(ent->e_rec.e_cpos);
-		*p_cpos = ocfs2_blocks_to_clusters(inode->i_sb,
-				le64_to_cpu(ent->e_rec.e_blkno)) +
-			  coff;
+		rec_start = le32_to_cpu(rec->e_cpos);
+		clusters = ocfs2_rec_clusters(el, rec);
 
-		if (ret_count)
-			*ret_count = le32_to_cpu(ent->e_rec.e_clusters) - coff;
+		rec_end = rec_start + clusters;
 
-		return 0;
+		if (v_cluster >= rec_start && v_cluster < rec_end) {
+			ret = i;
+			break;
+		}
 	}
 
-
-	return -ENOENT;
+	return ret;
 }
 
-#endif  /*  0  */
-
-int ocfs2_extent_map_get_blocks(struct inode *inode,
-				u64 v_blkno, int count,
-				u64 *p_blkno, int *ret_count)
+int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
+		       u32 *p_cluster, u32 *num_clusters,
+		       unsigned int *extent_flags)
 {
-	int ret;
-	u64 boff;
-	u32 cpos, clusters;
-	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
-	struct ocfs2_extent_map_entry *ent = NULL;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
+	int ret, i;
+	unsigned int flags = 0;
+	struct buffer_head *di_bh = NULL;
+	struct buffer_head *eb_bh = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_extent_block *eb;
+	struct ocfs2_extent_list *el;
 	struct ocfs2_extent_rec *rec;
+	u32 coff;
 
-	*p_blkno = 0;
-
-	cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno);
-	clusters = ocfs2_blocks_to_clusters(inode->i_sb,
-					    (u64)count + bpc - 1);
-	if ((cpos + clusters) > OCFS2_I(inode)->ip_clusters) {
-		ret = -EINVAL;
-		mlog_errno(ret);
-		return ret;
-	}
-
-	if ((cpos + clusters) > em->em_clusters) {
-		/*
-		 * Size changed underneath us on disk.  Drop any
-		 * straddling records and update our idea of
-		 * i_clusters
-		 */
-		ocfs2_extent_map_drop(inode, em->em_clusters - 1);
-		em->em_clusters = OCFS2_I(inode)->ip_clusters;
-	}
+	ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
+				      num_clusters, extent_flags);
+	if (ret == 0)
+		goto out;
 
-	ret = ocfs2_extent_map_lookup_read(inode, cpos, clusters, &ent);
+	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
+			       &di_bh, OCFS2_BH_CACHED, inode);
 	if (ret) {
 		mlog_errno(ret);
-		return ret;
+		goto out;
 	}
 
-	if (ent)
-	{
-		rec = &ent->e_rec;
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+	el = &di->id2.i_list;
 
-		/* We should never find ourselves straddling an interval */
-		if (!ocfs2_extent_rec_contains_clusters(rec, cpos, clusters)) {
-			ret = -ESRCH;
+	if (el->l_tree_depth) {
+		ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
+		if (ret) {
 			mlog_errno(ret);
-			return ret;
+			goto out;
 		}
 
-		boff = ocfs2_clusters_to_blocks(inode->i_sb, cpos -
-						le32_to_cpu(rec->e_cpos));
-		boff += (v_blkno & (u64)(bpc - 1));
-		*p_blkno = le64_to_cpu(rec->e_blkno) + boff;
+		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+		el = &eb->h_list;
 
-		if (ret_count) {
-			*ret_count = ocfs2_clusters_to_blocks(inode->i_sb,
-					le32_to_cpu(rec->e_clusters)) - boff;
+		if (el->l_tree_depth) {
+			ocfs2_error(inode->i_sb,
+				    "Inode %lu has non zero tree depth in "
+				    "leaf block %llu\n", inode->i_ino,
+				    (unsigned long long)eb_bh->b_blocknr);
+			ret = -EROFS;
+			goto out;
 		}
-
-		return 0;
 	}
 
-	return -ENOENT;
-}
-
-int ocfs2_extent_map_init(struct inode *inode)
-{
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-
-	em->em_extents = RB_ROOT;
-	em->em_clusters = 0;
-
-	return 0;
-}
-
-/* Needs the lock */
-static void __ocfs2_extent_map_drop(struct inode *inode,
-				    u32 new_clusters,
-				    struct rb_node **free_head,
-				    struct ocfs2_extent_map_entry **tail_ent)
-{
-	struct rb_node *node, *next;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent;
+	i = ocfs2_search_extent_list(el, v_cluster);
+	if (i == -1) {
+		/*
+		 * A hole was found. Return some canned values that
+		 * callers can key on. If asked for, num_clusters will
+		 * be populated with the size of the hole.
+		 */
+		*p_cluster = 0;
+		if (num_clusters) {
+			ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
+							 v_cluster,
+							 num_clusters);
+			if (ret) {
+				mlog_errno(ret);
+				goto out;
+			}
+		}
+	} else {
+		rec = &el->l_recs[i];
 
-	*free_head = NULL;
+		BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
 
-	ent = NULL;
-	node = rb_last(&em->em_extents);
-	while (node)
-	{
-		next = rb_prev(node);
+		if (!rec->e_blkno) {
+			ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+				    "record (%u, %u, 0)", inode->i_ino,
+				    le32_to_cpu(rec->e_cpos),
+				    ocfs2_rec_clusters(el, rec));
+			ret = -EROFS;
+			goto out;
+		}
 
-		ent = rb_entry(node, struct ocfs2_extent_map_entry,
-			       e_node);
-		if (le32_to_cpu(ent->e_rec.e_cpos) < new_clusters)
-			break;
+		coff = v_cluster - le32_to_cpu(rec->e_cpos);
 
-		rb_erase(&ent->e_node, &em->em_extents);
+		*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
+						    le64_to_cpu(rec->e_blkno));
+		*p_cluster = *p_cluster + coff;
 
-		node->rb_right = *free_head;
-		*free_head = node;
+		if (num_clusters)
+			*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
 
-		ent = NULL;
-		node = next;
-	}
+		flags = rec->e_flags;
 
-	/* Do we have an entry straddling new_clusters? */
-	if (tail_ent) {
-		if (ent &&
-		    ((le32_to_cpu(ent->e_rec.e_cpos) +
-		      le32_to_cpu(ent->e_rec.e_clusters)) > new_clusters))
-			*tail_ent = ent;
-		else
-			*tail_ent = NULL;
+		ocfs2_extent_map_insert_rec(inode, rec);
 	}
-}
-
-static void __ocfs2_extent_map_drop_cleanup(struct rb_node *free_head)
-{
-	struct rb_node *node;
-	struct ocfs2_extent_map_entry *ent;
 
-	while (free_head) {
-		node = free_head;
-		free_head = node->rb_right;
+	if (extent_flags)
+		*extent_flags = flags;
 
-		ent = rb_entry(node, struct ocfs2_extent_map_entry,
-			       e_node);
-		kmem_cache_free(ocfs2_em_ent_cachep, ent);
-	}
+out:
+	brelse(di_bh);
+	brelse(eb_bh);
+	return ret;
 }
 
 /*
- * Remove all entries past new_clusters, inclusive of an entry that
- * contains new_clusters.  This is effectively a cache forget.
- *
- * If you want to also clip the last extent by some number of clusters,
- * you need to call ocfs2_extent_map_trunc().
- * This code does not check or modify ip_clusters.
+ * This expects alloc_sem to be held. The allocation cannot change at
+ * all while the map is in the process of being updated.
  */
-int ocfs2_extent_map_drop(struct inode *inode, u32 new_clusters)
+int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
+				u64 *ret_count, unsigned int *extent_flags)
 {
-	struct rb_node *free_head = NULL;
-	struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map;
-	struct ocfs2_extent_map_entry *ent;
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
+	int ret;
+	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+	u32 cpos, num_clusters, p_cluster;
+	u64 boff = 0;
 
-	__ocfs2_extent_map_drop(inode, new_clusters, &free_head, &ent);
+	cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno);
 
-	if (ent) {
-		rb_erase(&ent->e_node, &em->em_extents);
-		ent->e_node.rb_right = free_head;
-		free_head = &ent->e_node;
+	ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters,
+				 extent_flags);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
 	}
 
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	if (free_head)
-		__ocfs2_extent_map_drop_cleanup(free_head);
-
-	return 0;
-}
-
-/*
- * Remove all entries past new_clusters and also clip any extent
- * straddling new_clusters, if there is one.  This does not check
- * or modify ip_clusters
- */
-int ocfs2_extent_map_trunc(struct inode *inode, u32 new_clusters)
-{
-	struct rb_node *free_head = NULL;
-	struct ocfs2_extent_map_entry *ent = NULL;
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-
-	__ocfs2_extent_map_drop(inode, new_clusters, &free_head, &ent);
-
-	if (ent)
-		ent->e_rec.e_clusters = cpu_to_le32(new_clusters -
-					       le32_to_cpu(ent->e_rec.e_cpos));
-
-	OCFS2_I(inode)->ip_map.em_clusters = new_clusters;
-
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	if (free_head)
-		__ocfs2_extent_map_drop_cleanup(free_head);
-
-	return 0;
-}
+	/*
+	 * p_cluster == 0 indicates a hole.
+	 */
+	if (p_cluster) {
+		boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+		boff += (v_blkno & (u64)(bpc - 1));
+	}
 
-int __init init_ocfs2_extent_maps(void)
-{
-	ocfs2_em_ent_cachep =
-		kmem_cache_create("ocfs2_em_ent",
-				  sizeof(struct ocfs2_extent_map_entry),
-				  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!ocfs2_em_ent_cachep)
-		return -ENOMEM;
+	*p_blkno = boff;
 
-	return 0;
-}
+	if (ret_count) {
+		*ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters);
+		*ret_count -= v_blkno & (u64)(bpc - 1);
+	}
 
-void exit_ocfs2_extent_maps(void)
-{
-	kmem_cache_destroy(ocfs2_em_ent_cachep);
+out:
+	return ret;
 }
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h
index fa3745e..de91e3e 100644
--- a/fs/ocfs2/extent_map.h
+++ b/fs/ocfs2/extent_map.h
@@ -25,22 +25,29 @@
 #ifndef _EXTENT_MAP_H
 #define _EXTENT_MAP_H
 
-int init_ocfs2_extent_maps(void);
-void exit_ocfs2_extent_maps(void);
+struct ocfs2_extent_map_item {
+	unsigned int			ei_cpos;
+	unsigned int			ei_phys;
+	unsigned int			ei_clusters;
+	unsigned int			ei_flags;
 
-/*
- * EVERY CALL here except _init, _trunc, and _drop expects alloc_sem
- * to be held.  The allocation cannot change at all while the map is
- * in the process of being updated.
- */
-int ocfs2_extent_map_init(struct inode *inode);
-int ocfs2_extent_map_append(struct inode *inode,
-			    struct ocfs2_extent_rec *rec,
-			    u32 new_clusters);
-int ocfs2_extent_map_get_blocks(struct inode *inode,
-				u64 v_blkno, int count,
-				u64 *p_blkno, int *ret_count);
-int ocfs2_extent_map_drop(struct inode *inode, u32 new_clusters);
-int ocfs2_extent_map_trunc(struct inode *inode, u32 new_clusters);
+	struct list_head		ei_list;
+};
+
+#define OCFS2_MAX_EXTENT_MAP_ITEMS			3
+struct ocfs2_extent_map {
+	unsigned int			em_num_items;
+	struct list_head		em_list;
+};
+
+void ocfs2_extent_map_init(struct inode *inode);
+void ocfs2_extent_map_trunc(struct inode *inode, unsigned int cluster);
+void ocfs2_extent_map_insert_rec(struct inode *inode,
+				 struct ocfs2_extent_rec *rec);
+
+int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, u32 *p_cluster,
+		       u32 *num_clusters, unsigned int *extent_flags);
+int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
+				u64 *ret_count, unsigned int *extent_flags);
 
 #endif  /* _EXTENT_MAP_H */
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index f2cd3bf..9395b4f 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -33,6 +33,7 @@ #include <linux/uio.h>
 #include <linux/sched.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/mount.h>
+#include <linux/writeback.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
@@ -206,16 +207,16 @@ out:
 	return ret;
 }
 
-int ocfs2_set_inode_size(handle_t *handle,
-			 struct inode *inode,
-			 struct buffer_head *fe_bh,
-			 u64 new_i_size)
+static int ocfs2_set_inode_size(handle_t *handle,
+				struct inode *inode,
+				struct buffer_head *fe_bh,
+				u64 new_i_size)
 {
 	int status;
 
 	mlog_entry_void();
 	i_size_write(inode, new_i_size);
-	inode->i_blocks = ocfs2_align_bytes_to_sectors(new_i_size);
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 
 	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
@@ -261,6 +262,7 @@ static int ocfs2_orphan_for_truncate(str
 {
 	int status;
 	handle_t *handle;
+	struct ocfs2_dinode *di;
 
 	mlog_entry_void();
 
@@ -274,12 +276,39 @@ static int ocfs2_orphan_for_truncate(str
 		goto out;
 	}
 
-	status = ocfs2_set_inode_size(handle, inode, fe_bh, new_i_size);
+	status = ocfs2_journal_access(handle, inode, fe_bh,
+				      OCFS2_JOURNAL_ACCESS_WRITE);
+	if (status < 0) {
+		mlog_errno(status);
+		goto out_commit;
+	}
+
+	/*
+	 * Do this before setting i_size.
+	 */
+	status = ocfs2_zero_tail_for_truncate(inode, handle, new_i_size);
+	if (status) {
+		mlog_errno(status);
+		goto out_commit;
+	}
+
+	i_size_write(inode, new_i_size);
+	inode->i_blocks = ocfs2_align_bytes_to_sectors(new_i_size);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
+	di = (struct ocfs2_dinode *) fe_bh->b_data;
+	di->i_size = cpu_to_le64(new_i_size);
+	di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
+	di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+	status = ocfs2_journal_dirty(handle, fe_bh);
 	if (status < 0)
 		mlog_errno(status);
 
+out_commit:
 	ocfs2_commit_trans(osb, handle);
 out:
+
 	mlog_exit(status);
 	return status;
 }
@@ -342,19 +371,6 @@ static int ocfs2_truncate_file(struct in
 		mlog_errno(status);
 		goto bail;
 	}
-	ocfs2_data_unlock(inode, 1);
-
-	if (le32_to_cpu(fe->i_clusters) ==
-	    ocfs2_clusters_for_bytes(osb->sb, new_i_size)) {
-		mlog(0, "fe->i_clusters = %u, so we do a simple truncate\n",
-		     fe->i_clusters);
-		/* No allocation change is required, so lets fast path
-		 * this truncate. */
-		status = ocfs2_simple_size_update(inode, di_bh, new_i_size);
-		if (status < 0)
-			mlog_errno(status);
-		goto bail;
-	}
 
 	/* alright, we're going to need to do a full blown alloc size
 	 * change. Orphan the inode so that recovery can complete the
@@ -363,22 +379,25 @@ static int ocfs2_truncate_file(struct in
 	status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto bail_unlock_data;
 	}
 
 	status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto bail_unlock_data;
 	}
 
 	status = ocfs2_commit_truncate(osb, inode, di_bh, tc);
 	if (status < 0) {
 		mlog_errno(status);
-		goto bail;
+		goto bail_unlock_data;
 	}
 
 	/* TODO: orphan dir cleanup here. */
+bail_unlock_data:
+	ocfs2_data_unlock(inode, 1);
+
 bail:
 
 	mlog_exit(status);
@@ -397,6 +416,7 @@ bail:
  */
 int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
 			       struct inode *inode,
+			       u32 *logical_offset,
 			       u32 clusters_to_add,
 			       struct buffer_head *fe_bh,
 			       handle_t *handle,
@@ -460,18 +480,14 @@ int ocfs2_do_extend_allocation(struct oc
 	block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
 	mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
 	     num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
-	status = ocfs2_insert_extent(osb, handle, inode, fe_bh, block,
-				     num_bits, meta_ac);
+	status = ocfs2_insert_extent(osb, handle, inode, fe_bh,
+				     *logical_offset, block, num_bits,
+				     meta_ac);
 	if (status < 0) {
 		mlog_errno(status);
 		goto leave;
 	}
 
-	le32_add_cpu(&fe->i_clusters, num_bits);
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
 	status = ocfs2_journal_dirty(handle, fe_bh);
 	if (status < 0) {
 		mlog_errno(status);
@@ -479,6 +495,7 @@ int ocfs2_do_extend_allocation(struct oc
 	}
 
 	clusters_to_add -= num_bits;
+	*logical_offset += num_bits;
 
 	if (clusters_to_add) {
 		mlog(0, "need to alloc once more, clusters = %u, wanted = "
@@ -494,14 +511,87 @@ leave:
 	return status;
 }
 
+/*
+ * For a given allocation, determine which allocators will need to be
+ * accessed, and lock them, reserving the appropriate number of bits.
+ *
+ * Called from ocfs2_extend_allocation() for file systems which don't
+ * support holes, and from ocfs2_write() for file systems which
+ * understand sparse inodes.
+ */
+int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
+			  u32 clusters_to_add,
+			  struct ocfs2_alloc_context **data_ac,
+			  struct ocfs2_alloc_context **meta_ac)
+{
+	int ret, num_free_extents;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	*meta_ac = NULL;
+	*data_ac = NULL;
+
+	mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
+	     "clusters_to_add = %u\n",
+	     (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode),
+	     le32_to_cpu(di->i_clusters), clusters_to_add);
+
+	num_free_extents = ocfs2_num_free_extents(osb, inode, di);
+	if (num_free_extents < 0) {
+		ret = num_free_extents;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * Sparse allocation file systems need to be more conservative
+	 * with reserving room for expansion - the actual allocation
+	 * happens while we've got a journal handle open so re-taking
+	 * a cluster lock (because we ran out of room for another
+	 * extent) will violate ordering rules.
+	 *
+	 * Most of the time we'll only be seeing this 1 cluster at a time
+	 * anyway.
+	 */
+	if (!num_free_extents ||
+	    (ocfs2_sparse_alloc(osb) && num_free_extents < clusters_to_add)) {
+		ret = ocfs2_reserve_new_metadata(osb, di, meta_ac);
+		if (ret < 0) {
+			if (ret != -ENOSPC)
+				mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
+	if (ret < 0) {
+		if (ret != -ENOSPC)
+			mlog_errno(ret);
+		goto out;
+	}
+
+out:
+	if (ret) {
+		if (*meta_ac) {
+			ocfs2_free_alloc_context(*meta_ac);
+			*meta_ac = NULL;
+		}
+
+		/*
+		 * We cannot have an error and a non null *data_ac.
+		 */
+	}
+
+	return ret;
+}
+
 static int ocfs2_extend_allocation(struct inode *inode,
 				   u32 clusters_to_add)
 {
 	int status = 0;
 	int restart_func = 0;
 	int drop_alloc_sem = 0;
-	int credits, num_free_extents;
-	u32 prev_clusters;
+	int credits;
+	u32 prev_clusters, logical_start;
 	struct buffer_head *bh = NULL;
 	struct ocfs2_dinode *fe = NULL;
 	handle_t *handle = NULL;
@@ -512,6 +602,12 @@ static int ocfs2_extend_allocation(struc
 
 	mlog_entry("(clusters_to_add = %u)\n", clusters_to_add);
 
+	/*
+	 * This function only exists for file systems which don't
+	 * support holes.
+	 */
+	BUG_ON(ocfs2_sparse_alloc(osb));
+
 	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
 				  OCFS2_BH_CACHED, inode);
 	if (status < 0) {
@@ -526,39 +622,11 @@ static int ocfs2_extend_allocation(struc
 		goto leave;
 	}
 
+	logical_start = OCFS2_I(inode)->ip_clusters;
+
 restart_all:
 	BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
 
-	mlog(0, "extend inode %llu, i_size = %lld, fe->i_clusters = %u, "
-	     "clusters_to_add = %u\n",
-	     (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode),
-	     fe->i_clusters, clusters_to_add);
-
-	num_free_extents = ocfs2_num_free_extents(osb,
-						  inode,
-						  fe);
-	if (num_free_extents < 0) {
-		status = num_free_extents;
-		mlog_errno(status);
-		goto leave;
-	}
-
-	if (!num_free_extents) {
-		status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac);
-		if (status < 0) {
-			if (status != -ENOSPC)
-				mlog_errno(status);
-			goto leave;
-		}
-	}
-
-	status = ocfs2_reserve_clusters(osb, clusters_to_add, &data_ac);
-	if (status < 0) {
-		if (status != -ENOSPC)
-			mlog_errno(status);
-		goto leave;
-	}
-
 	/* blocks peope in read/write from reading our allocation
 	 * until we're done changing it. We depend on i_mutex to block
 	 * other extend/truncate calls while we're here. Ordering wrt
@@ -566,6 +634,13 @@ restart_all:
 	down_write(&OCFS2_I(inode)->ip_alloc_sem);
 	drop_alloc_sem = 1;
 
+	status = ocfs2_lock_allocators(inode, fe, clusters_to_add, &data_ac,
+				       &meta_ac);
+	if (status) {
+		mlog_errno(status);
+		goto leave;
+	}
+
 	credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
 	handle = ocfs2_start_trans(osb, credits);
 	if (IS_ERR(handle)) {
@@ -590,6 +665,7 @@ restarted_transaction:
 
 	status = ocfs2_do_extend_allocation(osb,
 					    inode,
+					    &logical_start,
 					    clusters_to_add,
 					    bh,
 					    handle,
@@ -637,7 +713,8 @@ restarted_transaction:
 	}
 
 	mlog(0, "fe: i_clusters = %u, i_size=%llu\n",
-	     fe->i_clusters, (unsigned long long)fe->i_size);
+	     le32_to_cpu(fe->i_clusters),
+	     (unsigned long long)le64_to_cpu(fe->i_size));
 	mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
 	     OCFS2_I(inode)->ip_clusters, i_size_read(inode));
 
@@ -778,7 +855,7 @@ static int ocfs2_extend_file(struct inod
 			     size_t tail_to_skip)
 {
 	int ret = 0;
-	u32 clusters_to_add;
+	u32 clusters_to_add = 0;
 
 	BUG_ON(!tail_to_skip && !di_bh);
 
@@ -790,6 +867,11 @@ static int ocfs2_extend_file(struct inod
   		goto out;
 	BUG_ON(new_i_size < i_size_read(inode));
 
+	if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
+		BUG_ON(tail_to_skip != 0);
+		goto out_update_size;
+	}
+
 	clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - 
 		OCFS2_I(inode)->ip_clusters;
 
@@ -825,6 +907,7 @@ static int ocfs2_extend_file(struct inod
 		goto out_unlock;
 	}
 
+out_update_size:
 	if (!tail_to_skip) {
 		/* We're being called from ocfs2_setattr() which wants
 		 * us to update i_size */
@@ -834,7 +917,8 @@ static int ocfs2_extend_file(struct inod
 	}
 
 out_unlock:
-	ocfs2_data_unlock(inode, 1);
+	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+		ocfs2_data_unlock(inode, 1);
 
 out:
 	return ret;
@@ -972,7 +1056,8 @@ int ocfs2_permission(struct inode *inode
 
 	ret = ocfs2_meta_lock(inode, NULL, 0);
 	if (ret) {
-		mlog_errno(ret);
+		if (ret != -ENOENT)
+			mlog_errno(ret);
 		goto out;
 	}
 
@@ -1035,10 +1120,49 @@ out:
 	return ret;
 }
 
+/*
+ * Will look for holes and unwritten extents in the range starting at
+ * pos for count bytes (inclusive).
+ */
+static int ocfs2_check_range_for_holes(struct inode *inode, loff_t pos,
+				       size_t count)
+{
+	int ret = 0;
+	unsigned int extent_flags;
+	u32 cpos, clusters, extent_len, phys_cpos;
+	struct super_block *sb = inode->i_sb;
+
+	cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
+	clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos;
+
+	while (clusters) {
+		ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len,
+					 &extent_flags);
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		if (phys_cpos == 0 || (extent_flags & OCFS2_EXT_UNWRITTEN)) {
+			ret = 1;
+			break;
+		}
+
+		if (extent_len > clusters)
+			extent_len = clusters;
+
+		clusters -= extent_len;
+		cpos += extent_len;
+	}
+out:
+	return ret;
+}
+
 static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
 					 loff_t *ppos,
 					 size_t count,
-					 int appending)
+					 int appending,
+					 int *direct_io)
 {
 	int ret = 0, meta_level = appending;
 	struct inode *inode = dentry->d_inode;
@@ -1089,6 +1213,49 @@ static int ocfs2_prepare_inode_for_write
 		} else {
 			saved_pos = *ppos;
 		}
+
+		if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
+			loff_t end = saved_pos + count;
+
+			/*
+			 * Skip the O_DIRECT checks if we don't need
+			 * them.
+			 */
+			if (!direct_io || !(*direct_io))
+				break;
+
+			/*
+			 * Allowing concurrent direct writes means
+			 * i_size changes wouldn't be synchronized, so
+			 * one node could wind up truncating another
+			 * nodes writes.
+			 */
+			if (end > i_size_read(inode)) {
+				*direct_io = 0;
+				break;
+			}
+
+			/*
+			 * We don't fill holes during direct io, so
+			 * check for them here. If any are found, the
+			 * caller will have to retake some cluster
+			 * locks and initiate the io as buffered.
+			 */
+			ret = ocfs2_check_range_for_holes(inode, saved_pos,
+							  count);
+			if (ret == 1) {
+				*direct_io = 0;
+				ret = 0;
+			} else if (ret < 0)
+				mlog_errno(ret);
+			break;
+		}
+
+		/*
+		 * The rest of this loop is concerned with legacy file
+		 * systems which don't support sparse files.
+		 */
+
 		newsize = count + saved_pos;
 
 		mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
@@ -1141,55 +1308,264 @@ out:
 	return ret;
 }
 
+static inline void
+ocfs2_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
+{
+	const struct iovec *iov = *iovp;
+	size_t base = *basep;
+
+	do {
+		int copy = min(bytes, iov->iov_len - base);
+
+		bytes -= copy;
+		base += copy;
+		if (iov->iov_len == base) {
+			iov++;
+			base = 0;
+		}
+	} while (bytes);
+	*iovp = iov;
+	*basep = base;
+}
+
+static struct page * ocfs2_get_write_source(struct ocfs2_buffered_write_priv *bp,
+					    const struct iovec *cur_iov,
+					    size_t iov_offset)
+{
+	int ret;
+	char *buf;
+	struct page *src_page = NULL;
+
+	buf = cur_iov->iov_base + iov_offset;
+
+	if (!segment_eq(get_fs(), KERNEL_DS)) {
+		/*
+		 * Pull in the user page. We want to do this outside
+		 * of the meta data locks in order to preserve locking
+		 * order in case of page fault.
+		 */
+		ret = get_user_pages(current, current->mm,
+				     (unsigned long)buf & PAGE_CACHE_MASK, 1,
+				     0, 0, &src_page, NULL);
+		if (ret == 1)
+			bp->b_src_buf = kmap(src_page);
+		else
+			src_page = ERR_PTR(-EFAULT);
+	} else {
+		bp->b_src_buf = buf;
+	}
+
+	return src_page;
+}
+
+static void ocfs2_put_write_source(struct ocfs2_buffered_write_priv *bp,
+				   struct page *page)
+{
+	if (page) {
+		kunmap(page);
+		page_cache_release(page);
+	}
+}
+
+static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
+					 const struct iovec *iov,
+					 unsigned long nr_segs,
+					 size_t count,
+					 ssize_t o_direct_written)
+{
+	int ret = 0;
+	ssize_t copied, total = 0;
+	size_t iov_offset = 0;
+	const struct iovec *cur_iov = iov;
+	struct ocfs2_buffered_write_priv bp;
+	struct page *page;
+
+	/*
+	 * handle partial DIO write.  Adjust cur_iov if needed.
+	 */
+	ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written);
+
+	do {
+		bp.b_cur_off = iov_offset;
+		bp.b_cur_iov = cur_iov;
+
+		page = ocfs2_get_write_source(&bp, cur_iov, iov_offset);
+		if (IS_ERR(page)) {
+			ret = PTR_ERR(page);
+			goto out;
+		}
+
+		copied = ocfs2_buffered_write_cluster(file, *ppos, count,
+						      ocfs2_map_and_write_user_data,
+						      &bp);
+
+		ocfs2_put_write_source(&bp, page);
+
+		if (copied < 0) {
+			mlog_errno(copied);
+			ret = copied;
+			goto out;
+		}
+
+		total += copied;
+		*ppos = *ppos + copied;
+		count -= copied;
+
+		ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied);
+	} while(count);
+
+out:
+	return total ? total : ret;
+}
+
+static int ocfs2_check_iovec(const struct iovec *iov, size_t *counted,
+			     unsigned long *nr_segs)
+{
+	size_t ocount;		/* original count */
+	unsigned long seg;
+
+	ocount = 0;
+	for (seg = 0; seg < *nr_segs; seg++) {
+		const struct iovec *iv = &iov[seg];
+
+		/*
+		 * If any segment has a negative length, or the cumulative
+		 * length ever wraps negative then return -EINVAL.
+		 */
+		ocount += iv->iov_len;
+		if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
+			return -EINVAL;
+		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
+			continue;
+		if (seg == 0)
+			return -EFAULT;
+		*nr_segs = seg;
+		ocount -= iv->iov_len;	/* This segment is no good */
+		break;
+	}
+
+	*counted = ocount;
+	return 0;
+}
+
 static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
 				    const struct iovec *iov,
 				    unsigned long nr_segs,
 				    loff_t pos)
 {
-	int ret, rw_level, have_alloc_sem = 0;
-	struct file *filp = iocb->ki_filp;
-	struct inode *inode = filp->f_path.dentry->d_inode;
-	int appending = filp->f_flags & O_APPEND ? 1 : 0;
-
-	mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+	int ret, direct_io, appending, rw_level, have_alloc_sem  = 0;
+	int can_do_direct, sync = 0;
+	ssize_t written = 0;
+	size_t ocount;		/* original count */
+	size_t count;		/* after file limit checks */
+	loff_t *ppos = &iocb->ki_pos;
+	struct file *file = iocb->ki_filp;
+	struct inode *inode = file->f_path.dentry->d_inode;
+
+	mlog_entry("(0x%p, %u, '%.*s')\n", file,
 		   (unsigned int)nr_segs,
-		   filp->f_path.dentry->d_name.len,
-		   filp->f_path.dentry->d_name.name);
+		   file->f_path.dentry->d_name.len,
+		   file->f_path.dentry->d_name.name);
 
-	/* happy write of zero bytes */
 	if (iocb->ki_left == 0)
 		return 0;
 
+	ret = ocfs2_check_iovec(iov, &ocount, &nr_segs);
+	if (ret)
+		return ret;
+
+	count = ocount;
+
+	vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+	appending = file->f_flags & O_APPEND ? 1 : 0;
+	direct_io = file->f_flags & O_DIRECT ? 1 : 0;
+
 	mutex_lock(&inode->i_mutex);
+
+relock:
 	/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
-	if (filp->f_flags & O_DIRECT) {
-		have_alloc_sem = 1;
+	if (direct_io) {
 		down_read(&inode->i_alloc_sem);
+		have_alloc_sem = 1;
 	}
 
 	/* concurrent O_DIRECT writes are allowed */
-	rw_level = (filp->f_flags & O_DIRECT) ? 0 : 1;
+	rw_level = !direct_io;
 	ret = ocfs2_rw_lock(inode, rw_level);
 	if (ret < 0) {
-		rw_level = -1;
 		mlog_errno(ret);
-		goto out;
+		goto out_sems;
 	}
 
-	ret = ocfs2_prepare_inode_for_write(filp->f_path.dentry, &iocb->ki_pos,
-					    iocb->ki_left, appending);
+	can_do_direct = direct_io;
+	ret = ocfs2_prepare_inode_for_write(file->f_path.dentry, ppos,
+					    iocb->ki_left, appending,
+					    &can_do_direct);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out;
 	}
 
-	/* communicate with ocfs2_dio_end_io */
-	ocfs2_iocb_set_rw_locked(iocb);
+	/*
+	 * We can't complete the direct I/O as requested, fall back to
+	 * buffered I/O.
+	 */
+	if (direct_io && !can_do_direct) {
+		ocfs2_rw_unlock(inode, rw_level);
+		up_read(&inode->i_alloc_sem);
+
+		have_alloc_sem = 0;
+		rw_level = -1;
 
-	ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos);
+		direct_io = 0;
+		sync = 1;
+		goto relock;
+	}
+
+	if (!sync && ((file->f_flags & O_SYNC) || IS_SYNC(inode)))
+		sync = 1;
+
+	/*
+	 * XXX: Is it ok to execute these checks a second time?
+	 */
+	ret = generic_write_checks(file, ppos, &count, S_ISBLK(inode->i_mode));
+	if (ret)
+		goto out;
+
+	/*
+	 * Set pos so that sync_page_range_nolock() below understands
+	 * where to start from. We might've moved it around via the
+	 * calls above. The range we want to actually sync starts from
+	 * *ppos here.
+	 *
+	 */
+	pos = *ppos;
+
+	/* communicate with ocfs2_dio_end_io */
+	ocfs2_iocb_set_rw_locked(iocb, rw_level);
+
+	if (direct_io) {
+		written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos,
+						    ppos, count, ocount);
+		if (written < 0) {
+			ret = written;
+			goto out_dio;
+		}
+	} else {
+		written = ocfs2_file_buffered_write(file, ppos, iov, nr_segs,
+						    count, written);
+		if (written < 0) {
+			ret = written;
+			if (ret != -EFAULT || ret != -ENOSPC)
+				mlog_errno(ret);
+			goto out;
+		}
+	}
 
+out_dio:
 	/* buffered aio wouldn't have proper lock coverage today */
-	BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
+	BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
 
 	/* 
 	 * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io
@@ -1207,13 +1583,102 @@ static ssize_t ocfs2_file_aio_write(stru
 	}
 
 out:
+	if (rw_level != -1)
+		ocfs2_rw_unlock(inode, rw_level);
+
+out_sems:
 	if (have_alloc_sem)
 		up_read(&inode->i_alloc_sem);
-	if (rw_level != -1) 
-		ocfs2_rw_unlock(inode, rw_level);
+
+	if (written > 0 && sync) {
+		ssize_t err;
+
+		err = sync_page_range_nolock(inode, file->f_mapping, pos, count);
+		if (err < 0)
+			written = err;
+	}
+
 	mutex_unlock(&inode->i_mutex);
 
 	mlog_exit(ret);
+	return written ? written : ret;
+}
+
+static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe,
+				    struct pipe_buffer *buf,
+				    struct splice_desc *sd)
+{
+	int ret, count, total = 0;
+	ssize_t copied = 0;
+	struct ocfs2_splice_write_priv sp;
+
+	ret = buf->ops->pin(pipe, buf);
+	if (ret)
+		goto out;
+
+	sp.s_sd = sd;
+	sp.s_buf = buf;
+	sp.s_pipe = pipe;
+	sp.s_offset = sd->pos & ~PAGE_CACHE_MASK;
+	sp.s_buf_offset = buf->offset;
+
+	count = sd->len;
+	if (count + sp.s_offset > PAGE_CACHE_SIZE)
+		count = PAGE_CACHE_SIZE - sp.s_offset;
+
+	do {
+		/*
+		 * splice wants us to copy up to one page at a
+		 * time. For pagesize > cluster size, this means we
+		 * might enter ocfs2_buffered_write_cluster() more
+		 * than once, so keep track of our progress here.
+		 */
+		copied = ocfs2_buffered_write_cluster(sd->file,
+						      (loff_t)sd->pos + total,
+						      count,
+						      ocfs2_map_and_write_splice_data,
+						      &sp);
+		if (copied < 0) {
+			mlog_errno(copied);
+			ret = copied;
+			goto out;
+		}
+
+		count -= copied;
+		sp.s_offset += copied;
+		sp.s_buf_offset += copied;
+		total += copied;
+	} while (count);
+
+	ret = 0;
+out:
+
+	return total ? total : ret;
+}
+
+static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe,
+					 struct file *out,
+					 loff_t *ppos,
+					 size_t len,
+					 unsigned int flags)
+{
+	int ret, err;
+	struct address_space *mapping = out->f_mapping;
+	struct inode *inode = mapping->host;
+
+	ret = __splice_from_pipe(pipe, out, ppos, len, flags,
+				 ocfs2_splice_write_actor);
+	if (ret > 0) {
+		*ppos += ret;
+
+		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;
 }
 
@@ -1239,14 +1704,15 @@ static ssize_t ocfs2_file_splice_write(s
 		goto out;
 	}
 
-	ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0);
+	ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0,
+					    NULL);
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out_unlock;
 	}
 
 	/* ok, we're done with i_size and alloc work */
-	ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags);
+	ret = __ocfs2_file_splice_write(pipe, out, ppos, len, flags);
 
 out_unlock:
 	ocfs2_rw_unlock(inode, 1);
@@ -1323,7 +1789,7 @@ static ssize_t ocfs2_file_aio_read(struc
 		}
 		rw_level = 0;
 		/* communicate with ocfs2_dio_end_io */
-		ocfs2_iocb_set_rw_locked(iocb);
+		ocfs2_iocb_set_rw_locked(iocb, rw_level);
 	}
 
 	/*
@@ -1388,6 +1854,9 @@ const struct file_operations ocfs2_fops 
 	.aio_read	= ocfs2_file_aio_read,
 	.aio_write	= ocfs2_file_aio_write,
 	.ioctl		= ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = ocfs2_compat_ioctl,
+#endif
 	.splice_read	= ocfs2_file_splice_read,
 	.splice_write	= ocfs2_file_splice_write,
 };
@@ -1397,4 +1866,7 @@ const struct file_operations ocfs2_dops 
 	.readdir	= ocfs2_readdir,
 	.fsync		= ocfs2_sync_file,
 	.ioctl		= ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = ocfs2_compat_ioctl,
+#endif
 };
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index cc973f0..a4dd1fa 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -39,23 +39,23 @@ enum ocfs2_alloc_restarted {
 };
 int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
 			       struct inode *inode,
+			       u32 *cluster_start,
 			       u32 clusters_to_add,
 			       struct buffer_head *fe_bh,
 			       handle_t *handle,
 			       struct ocfs2_alloc_context *data_ac,
 			       struct ocfs2_alloc_context *meta_ac,
 			       enum ocfs2_alloc_restarted *reason);
+int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
+			  u32 clusters_to_add,
+			  struct ocfs2_alloc_context **data_ac,
+			  struct ocfs2_alloc_context **meta_ac);
 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
 int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		  struct kstat *stat);
 int ocfs2_permission(struct inode *inode, int mask,
 		     struct nameidata *nd);
 
-int ocfs2_set_inode_size(handle_t *handle,
-			 struct inode *inode,
-			 struct buffer_head *fe_bh,
-			 u64 new_i_size);
-
 int ocfs2_should_update_atime(struct inode *inode,
 			      struct vfsmount *vfsmnt);
 int ocfs2_update_inode_atime(struct inode *inode,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 28ab56f..c53a676 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -28,7 +28,6 @@ #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 
 #include <asm/byteorder.h>
 
@@ -89,22 +88,23 @@ void ocfs2_set_inode_flags(struct inode 
 		inode->i_flags |= S_DIRSYNC;
 }
 
-struct inode *ocfs2_ilookup_for_vote(struct ocfs2_super *osb,
-				     u64 blkno,
-				     int delete_vote)
+/* Propagate flags from i_flags to OCFS2_I(inode)->ip_attr */
+void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
 {
-	struct ocfs2_find_inode_args args;
-
-	/* ocfs2_ilookup_for_vote should *only* be called from the
-	 * vote thread */
-	BUG_ON(current != osb->vote_task);
-
-	args.fi_blkno = blkno;
-	args.fi_flags = OCFS2_FI_FLAG_NOWAIT;
-	if (delete_vote)
-		args.fi_flags |= OCFS2_FI_FLAG_DELETE;
-	args.fi_ino = ino_from_blkno(osb->sb, blkno);
-	return ilookup5(osb->sb, args.fi_ino, ocfs2_find_actor, &args);
+	unsigned int flags = oi->vfs_inode.i_flags;
+
+	oi->ip_attr &= ~(OCFS2_SYNC_FL|OCFS2_APPEND_FL|
+			OCFS2_IMMUTABLE_FL|OCFS2_NOATIME_FL|OCFS2_DIRSYNC_FL);
+	if (flags & S_SYNC)
+		oi->ip_attr |= OCFS2_SYNC_FL;
+	if (flags & S_APPEND)
+		oi->ip_attr |= OCFS2_APPEND_FL;
+	if (flags & S_IMMUTABLE)
+		oi->ip_attr |= OCFS2_IMMUTABLE_FL;
+	if (flags & S_NOATIME)
+		oi->ip_attr |= OCFS2_NOATIME_FL;
+	if (flags & S_DIRSYNC)
+		oi->ip_attr |= OCFS2_DIRSYNC_FL;
 }
 
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
@@ -182,28 +182,6 @@ static int ocfs2_find_actor(struct inode
 	if (oi->ip_blkno != args->fi_blkno)
 		goto bail;
 
-	/* OCFS2_FI_FLAG_NOWAIT is *only* set from
-	 * ocfs2_ilookup_for_vote which won't create an inode for one
-	 * that isn't found. The vote thread which doesn't want to get
-	 * an inode which is in the process of going away - otherwise
-	 * the call to __wait_on_freeing_inode in find_inode_fast will
-	 * cause it to deadlock on an inode which may be waiting on a
-	 * vote (or lock release) in delete_inode */
-	if ((args->fi_flags & OCFS2_FI_FLAG_NOWAIT) &&
-	    (inode->i_state & (I_FREEING|I_CLEAR))) {
-		/* As stated above, we're not going to return an
-		 * inode.  In the case of a delete vote, the voting
-		 * code is going to signal the other node to go
-		 * ahead. Mark that state here, so this freeing inode
-		 * has the state when it gets to delete_inode. */
-		if (args->fi_flags & OCFS2_FI_FLAG_DELETE) {
-			spin_lock(&oi->ip_lock);
-			ocfs2_mark_inode_remotely_deleted(inode);
-			spin_unlock(&oi->ip_lock);
-		}
-		goto bail;
-	}
-
 	ret = 1;
 bail:
 	mlog_exit(ret);
@@ -236,7 +214,7 @@ int ocfs2_populate_inode(struct inode *i
 	int status = -EINVAL;
 
 	mlog_entry("(0x%p, size:%llu)\n", inode,
-		   (unsigned long long)fe->i_size);
+		   (unsigned long long)le64_to_cpu(fe->i_size));
 
 	sb = inode->i_sb;
 	osb = OCFS2_SB(sb);
@@ -261,6 +239,9 @@ int ocfs2_populate_inode(struct inode *i
 		goto bail;
 	}
 
+	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
+	OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+
 	inode->i_version = 1;
 	inode->i_generation = le32_to_cpu(fe->i_generation);
 	inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev));
@@ -272,8 +253,7 @@ int ocfs2_populate_inode(struct inode *i
 	if (S_ISLNK(inode->i_mode) && !fe->i_clusters)
 		inode->i_blocks = 0;
 	else
-		inode->i_blocks =
-			ocfs2_align_bytes_to_sectors(le64_to_cpu(fe->i_size));
+		inode->i_blocks = ocfs2_inode_sector_count(inode);
 	inode->i_mapping->a_ops = &ocfs2_aops;
 	inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime);
 	inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec);
@@ -286,11 +266,7 @@ int ocfs2_populate_inode(struct inode *i
 		mlog(ML_ERROR,
 		     "ip_blkno %llu != i_blkno %llu!\n",
 		     (unsigned long long)OCFS2_I(inode)->ip_blkno,
-		     (unsigned long long)fe->i_blkno);
-
-	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
-	OCFS2_I(inode)->ip_orphaned_slot = OCFS2_INVALID_SLOT;
-	OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+		     (unsigned long long)le64_to_cpu(fe->i_blkno));
 
 	inode->i_nlink = le16_to_cpu(fe->i_links_count);
 
@@ -343,10 +319,13 @@ int ocfs2_populate_inode(struct inode *i
 		 * the generation argument to
 		 * ocfs2_inode_lock_res_init() will have to change.
 		 */
-		BUG_ON(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL));
+		BUG_ON(le32_to_cpu(fe->i_flags) & 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_open_lockres,
+					  OCFS2_LOCK_TYPE_OPEN, 0, inode);
 	}
 
 	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_rw_lockres,
@@ -421,7 +400,7 @@ static int ocfs2_read_locked_inode(struc
 	 * cluster lock before trusting anything anyway.
 	 */
 	can_lock = !(args->fi_flags & OCFS2_FI_FLAG_SYSFILE)
-		&& !(args->fi_flags & OCFS2_FI_FLAG_NOLOCK)
+		&& !(args->fi_flags & OCFS2_FI_FLAG_ORPHAN_RECOVERY)
 		&& !ocfs2_mount_local(osb);
 
 	/*
@@ -438,7 +417,17 @@ static int ocfs2_read_locked_inode(struc
 				  OCFS2_LOCK_TYPE_META,
 				  generation, inode);
 
+	ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres,
+				  OCFS2_LOCK_TYPE_OPEN,
+				  0, inode);
+
 	if (can_lock) {
+		status = ocfs2_open_lock(inode);
+		if (status) {
+			make_bad_inode(inode);
+			mlog_errno(status);
+			return status;
+		}
 		status = ocfs2_meta_lock(inode, NULL, 0);
 		if (status) {
 			make_bad_inode(inode);
@@ -447,6 +436,14 @@ static int ocfs2_read_locked_inode(struc
 		}
 	}
 
+	if (args->fi_flags & OCFS2_FI_FLAG_ORPHAN_RECOVERY) {
+		status = ocfs2_try_open_lock(inode, 0);
+		if (status) {
+			make_bad_inode(inode);	
+			return status;
+		}
+	}
+
 	status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0,
 				  can_lock ? inode : NULL);
 	if (status < 0) {
@@ -458,7 +455,8 @@ static int ocfs2_read_locked_inode(struc
 	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);
+		     (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
+		     fe->i_signature);
 		goto bail;
 	}
 
@@ -507,50 +505,56 @@ static int ocfs2_truncate_for_delete(str
 				     struct buffer_head *fe_bh)
 {
 	int status = 0;
-	handle_t *handle = NULL;
 	struct ocfs2_truncate_context *tc = NULL;
 	struct ocfs2_dinode *fe;
+	handle_t *handle = NULL;
 
 	mlog_entry_void();
 
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
-	/* zero allocation, zero truncate :) */
-	if (!fe->i_clusters)
-		goto bail;
+	if (fe->i_clusters) {
+		handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+		if (IS_ERR(handle)) {
+			status = PTR_ERR(handle);
+			mlog_errno(status);
+			goto out;
+		}
 
-	handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
-	if (IS_ERR(handle)) {
-		status = PTR_ERR(handle);
-		handle = NULL;
-		mlog_errno(status);
-		goto bail;
-	}
+		status = ocfs2_journal_access(handle, inode, fe_bh,
+					      OCFS2_JOURNAL_ACCESS_WRITE);
+		if (status < 0) {
+			mlog_errno(status);
+			goto out;
+		}
 
-	status = ocfs2_set_inode_size(handle, inode, fe_bh, 0ULL);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
+		i_size_write(inode, 0);
 
-	ocfs2_commit_trans(osb, handle);
-	handle = NULL;
+		status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
+		if (status < 0) {
+			mlog_errno(status);
+			goto out;
+		}
 
-	status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
+		ocfs2_commit_trans(osb, handle);
+		handle = NULL;
 
-	status = ocfs2_commit_truncate(osb, inode, fe_bh, tc);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
+		status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc);
+		if (status < 0) {
+			mlog_errno(status);
+			goto out;
+		}
+
+		status = ocfs2_commit_truncate(osb, inode, fe_bh, tc);
+		if (status < 0) {
+			mlog_errno(status);
+			goto out;
+		}
 	}
-bail:
+
+out:
 	if (handle)
 		ocfs2_commit_trans(osb, handle);
-
 	mlog_exit(status);
 	return status;
 }
@@ -678,10 +682,10 @@ static int ocfs2_wipe_inode(struct inode
 	struct inode *orphan_dir_inode = NULL;
 	struct buffer_head *orphan_dir_bh = NULL;
 	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_dinode *di;
 
-	/* We've already voted on this so it should be readonly - no
-	 * spinlock needed. */
-	orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot;
+	di = (struct ocfs2_dinode *) di_bh->b_data;
+	orphaned_slot = le16_to_cpu(di->i_orphaned_slot);
 
 	status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot);
 	if (status)
@@ -827,8 +831,8 @@ static int ocfs2_query_inode_wipe(struct
 		     "Inode %llu (on-disk %llu) not orphaned! "
 		     "Disk flags  0x%x, inode flags 0x%x\n",
 		     (unsigned long long)oi->ip_blkno,
-		     (unsigned long long)di->i_blkno, di->i_flags,
-		     oi->ip_flags);
+		     (unsigned long long)le64_to_cpu(di->i_blkno),
+		     le32_to_cpu(di->i_flags), oi->ip_flags);
 		goto bail;
 	}
 
@@ -839,11 +843,20 @@ static int ocfs2_query_inode_wipe(struct
 		goto bail;
 	}
 
-	status = ocfs2_request_delete_vote(inode);
-	/* -EBUSY means that other nodes are still using the
-	 * inode. We're done here though, so avoid doing anything on
-	 * disk and let them worry about deleting it. */
-	if (status == -EBUSY) {
+	/*
+	 * This is how ocfs2 determines whether an inode is still live
+	 * within the cluster. Every node takes a shared read lock on
+	 * the inode open lock in ocfs2_read_locked_inode(). When we
+	 * get to ->delete_inode(), each node tries to convert it's
+	 * lock to an exclusive. Trylocks are serialized by the inode
+	 * meta data lock. If the upconvert suceeds, we know the inode
+	 * is no longer live and can be deleted.
+	 *
+	 * Though we call this with the meta data lock held, the
+	 * trylock keeps us from ABBA deadlock.
+	 */
+	status = ocfs2_try_open_lock(inode, 1);
+	if (status == -EAGAIN) {
 		status = 0;
 		mlog(0, "Skipping delete of %llu because it is in use on"
 		     "other nodes\n", (unsigned long long)oi->ip_blkno);
@@ -854,21 +867,10 @@ static int ocfs2_query_inode_wipe(struct
 		goto bail;
 	}
 
-	spin_lock(&oi->ip_lock);
-	if (oi->ip_orphaned_slot == OCFS2_INVALID_SLOT) {
-		/* Nobody knew which slot this inode was orphaned
-		 * into. This may happen during node death and
-		 * recovery knows how to clean it up so we can safely
-		 * ignore this inode for now on. */
-		mlog(0, "Nobody knew where inode %llu was orphaned!\n",
-		     (unsigned long long)oi->ip_blkno);
-	} else {
-		*wipe = 1;
-
-		mlog(0, "Inode %llu is ok to wipe from orphan dir %d\n",
-		     (unsigned long long)oi->ip_blkno, oi->ip_orphaned_slot);
-	}
-	spin_unlock(&oi->ip_lock);
+	*wipe = 1;
+	mlog(0, "Inode %llu is ok to wipe from orphan dir %u\n",
+	     (unsigned long long)oi->ip_blkno,
+	     le16_to_cpu(di->i_orphaned_slot));
 
 bail:
 	return status;
@@ -1001,11 +1003,16 @@ void ocfs2_clear_inode(struct inode *ino
 	mlog_bug_on_msg(OCFS2_SB(inode->i_sb) == NULL,
 			"Inode=%lu\n", inode->i_ino);
 
+	/* For remove delete_inode vote, we hold open lock before,
+	 * now it is time to unlock PR and EX open locks. */
+	ocfs2_open_unlock(inode);
+
 	/* Do these before all the other work so that we don't bounce
 	 * the vote thread while waiting to destroy the locks. */
 	ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres);
 	ocfs2_mark_lockres_freeing(&oi->ip_meta_lockres);
 	ocfs2_mark_lockres_freeing(&oi->ip_data_lockres);
+	ocfs2_mark_lockres_freeing(&oi->ip_open_lockres);
 
 	/* We very well may get a clear_inode before all an inodes
 	 * metadata has hit disk. Of course, we can't drop any cluster
@@ -1020,8 +1027,7 @@ void ocfs2_clear_inode(struct inode *ino
 			"Clear inode of %llu, inode has io markers\n",
 			(unsigned long long)oi->ip_blkno);
 
-	ocfs2_extent_map_drop(inode, 0);
-	ocfs2_extent_map_init(inode);
+	ocfs2_extent_map_trunc(inode, 0);
 
 	status = ocfs2_drop_inode_locks(inode);
 	if (status < 0)
@@ -1030,6 +1036,7 @@ void ocfs2_clear_inode(struct inode *ino
 	ocfs2_lock_res_free(&oi->ip_rw_lockres);
 	ocfs2_lock_res_free(&oi->ip_meta_lockres);
 	ocfs2_lock_res_free(&oi->ip_data_lockres);
+	ocfs2_lock_res_free(&oi->ip_open_lockres);
 
 	ocfs2_metadata_cache_purge(inode);
 
@@ -1086,9 +1093,6 @@ void ocfs2_drop_inode(struct inode *inod
 	mlog(0, "Drop inode %llu, nlink = %u, ip_flags = 0x%x\n",
 	     (unsigned long long)oi->ip_blkno, inode->i_nlink, oi->ip_flags);
 
-	/* 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)
 		generic_delete_inode(inode);
 	else
@@ -1121,8 +1125,10 @@ struct buffer_head *ocfs2_bread(struct i
 		return NULL;
 	}
 
-	tmperr = ocfs2_extent_map_get_blocks(inode, block, 1,
-					     &p_blkno, NULL);
+	down_read(&OCFS2_I(inode)->ip_alloc_sem);
+	tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+					     NULL);
+	up_read(&OCFS2_I(inode)->ip_alloc_sem);
 	if (tmperr < 0) {
 		mlog_errno(tmperr);
 		goto fail;
@@ -1212,6 +1218,7 @@ int ocfs2_mark_inode_dirty(handle_t *han
 
 	spin_lock(&OCFS2_I(inode)->ip_lock);
 	fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
+	ocfs2_get_inode_flags(OCFS2_I(inode));
 	fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
 	spin_unlock(&OCFS2_I(inode)->ip_lock);
 
@@ -1259,7 +1266,7 @@ void ocfs2_refresh_inode(struct inode *i
 	if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0)
 		inode->i_blocks = 0;
 	else
-		inode->i_blocks = ocfs2_align_bytes_to_sectors(i_size_read(inode));
+		inode->i_blocks = ocfs2_inode_sector_count(inode);
 	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);
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 1a7dd29..a41d081 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -26,6 +26,8 @@
 #ifndef OCFS2_INODE_H
 #define OCFS2_INODE_H
 
+#include "extent_map.h"
+
 /* OCFS2 Inode Private Data */
 struct ocfs2_inode_info
 {
@@ -34,6 +36,7 @@ struct ocfs2_inode_info
 	struct ocfs2_lock_res		ip_rw_lockres;
 	struct ocfs2_lock_res		ip_meta_lockres;
 	struct ocfs2_lock_res		ip_data_lockres;
+	struct ocfs2_lock_res		ip_open_lockres;
 
 	/* protects allocation changes on this inode. */
 	struct rw_semaphore		ip_alloc_sem;
@@ -42,9 +45,7 @@ struct ocfs2_inode_info
 	spinlock_t			ip_lock;
 	u32				ip_open_count;
 	u32				ip_clusters;
-	struct ocfs2_extent_map		ip_map;
 	struct list_head		ip_io_markers;
-	int				ip_orphaned_slot;
 
 	struct mutex			ip_io_mutex;
 
@@ -64,6 +65,8 @@ struct ocfs2_inode_info
 
 	struct ocfs2_caching_info	ip_metadata_cache;
 
+	struct ocfs2_extent_map		ip_extent_map;
+
 	struct inode			vfs_inode;
 };
 
@@ -117,14 +120,9 @@ void ocfs2_delete_inode(struct inode *in
 void ocfs2_drop_inode(struct inode *inode);
 
 /* 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
+#define OCFS2_FI_FLAG_SYSFILE		0x4
+#define OCFS2_FI_FLAG_ORPHAN_RECOVERY	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);
 int ocfs2_inode_init_private(struct inode *inode);
 int ocfs2_inode_revalidate(struct dentry *dentry);
 int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
@@ -143,5 +141,13 @@ int ocfs2_aio_read(struct file *file, st
 int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
 
 void ocfs2_set_inode_flags(struct inode *inode);
+void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi);
+
+static inline blkcnt_t ocfs2_inode_sector_count(struct inode *inode)
+{
+	int c_to_s_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits - 9;
+
+	return (blkcnt_t)(OCFS2_I(inode)->ip_clusters << c_to_s_bits);
+}
 
 #endif /* OCFS2_INODE_H */
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 4768be5..f3ad21a 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -31,6 +31,7 @@ static int ocfs2_get_inode_attr(struct i
 		mlog_errno(status);
 		return status;
 	}
+	ocfs2_get_inode_flags(OCFS2_I(inode));
 	*flags = OCFS2_I(inode)->ip_attr;
 	ocfs2_meta_unlock(inode, 0);
 
@@ -134,3 +135,26 @@ int ocfs2_ioctl(struct inode * inode, st
 	}
 }
 
+#ifdef CONFIG_COMPAT
+long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	int ret;
+
+	switch (cmd) {
+	case OCFS2_IOC32_GETFLAGS:
+		cmd = OCFS2_IOC_GETFLAGS;
+		break;
+	case OCFS2_IOC32_SETFLAGS:
+		cmd = OCFS2_IOC_SETFLAGS;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	lock_kernel();
+	ret = ocfs2_ioctl(inode, file, cmd, arg);
+	unlock_kernel();
+	return ret;
+}
+#endif
diff --git a/fs/ocfs2/ioctl.h b/fs/ocfs2/ioctl.h
index 4a7c829..4d6c4f4 100644
--- a/fs/ocfs2/ioctl.h
+++ b/fs/ocfs2/ioctl.h
@@ -12,5 +12,6 @@ #define OCFS2_IOCTL_H
 
 int ocfs2_ioctl(struct inode * inode, struct file * filp,
 	unsigned int cmd, unsigned long arg);
+long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg);
 
 #endif /* OCFS2_IOCTL_H */
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 825cb0a..dc11880 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -435,7 +435,8 @@ static int ocfs2_journal_toggle_dirty(st
 		 * handle the errors in a specific manner, so no need
 		 * to call ocfs2_error() here. */
 		mlog(ML_ERROR, "Journal dinode %llu  has invalid "
-		     "signature: %.*s", (unsigned long long)fe->i_blkno, 7,
+		     "signature: %.*s",
+		     (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
 		     fe->i_signature);
 		status = -EIO;
 		goto out;
@@ -649,29 +650,20 @@ bail:
 static int ocfs2_force_read_journal(struct inode *inode)
 {
 	int status = 0;
-	int i, p_blocks;
-	u64 v_blkno, p_blkno;
-#define CONCURRENT_JOURNAL_FILL 32
+	int i;
+	u64 v_blkno, p_blkno, p_blocks, num_blocks;
+#define CONCURRENT_JOURNAL_FILL 32ULL
 	struct buffer_head *bhs[CONCURRENT_JOURNAL_FILL];
 
 	mlog_entry_void();
 
-	BUG_ON(inode->i_blocks !=
-		     ocfs2_align_bytes_to_sectors(i_size_read(inode)));
-
 	memset(bhs, 0, sizeof(struct buffer_head *) * CONCURRENT_JOURNAL_FILL);
 
-	mlog(0, "Force reading %llu blocks\n",
-		(unsigned long long)(inode->i_blocks >>
-			(inode->i_sb->s_blocksize_bits - 9)));
-
+	num_blocks = ocfs2_blocks_for_bytes(inode->i_sb, inode->i_size);
 	v_blkno = 0;
-	while (v_blkno <
-	       (inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9))) {
-
+	while (v_blkno < num_blocks) {
 		status = ocfs2_extent_map_get_blocks(inode, v_blkno,
-						     1, &p_blkno,
-						     &p_blocks);
+						     &p_blkno, &p_blocks, NULL);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
@@ -751,7 +743,7 @@ void ocfs2_complete_recovery(struct work
 		la_dinode = item->lri_la_dinode;
 		if (la_dinode) {
 			mlog(0, "Clean up local alloc %llu\n",
-			     (unsigned long long)la_dinode->i_blkno);
+			     (unsigned long long)le64_to_cpu(la_dinode->i_blkno));
 
 			ret = ocfs2_complete_local_alloc_recovery(osb,
 								  la_dinode);
@@ -764,7 +756,7 @@ void ocfs2_complete_recovery(struct work
 		tl_dinode = item->lri_tl_dinode;
 		if (tl_dinode) {
 			mlog(0, "Clean up truncate log %llu\n",
-			     (unsigned long long)tl_dinode->i_blkno);
+			     (unsigned long long)le64_to_cpu(tl_dinode->i_blkno));
 
 			ret = ocfs2_complete_truncate_log_recovery(osb,
 								   tl_dinode);
@@ -1306,7 +1298,7 @@ static int ocfs2_queue_orphans(struct oc
 				continue;
 
 			iter = ocfs2_iget(osb, le64_to_cpu(de->inode),
-					  OCFS2_FI_FLAG_NOLOCK);
+					  OCFS2_FI_FLAG_ORPHAN_RECOVERY);
 			if (IS_ERR(iter))
 				continue;
 
@@ -1418,7 +1410,6 @@ static int ocfs2_recover_orphans(struct 
 		/* Set the proper information to get us going into
 		 * ocfs2_delete_inode. */
 		oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED;
-		oi->ip_orphaned_slot = slot;
 		spin_unlock(&oi->ip_lock);
 
 		iput(inode);
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index d026b4f..3db5de4 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -390,7 +390,7 @@ static inline int ocfs2_calc_tree_trunc_
 	/* We may be deleting metadata blocks, so metadata alloc dinode +
 	   one desc. block for each possible delete. */
 	if (tree_depth && next_free == 1 &&
-	    le32_to_cpu(last_el->l_recs[i].e_clusters) == clusters_to_del)
+	    ocfs2_rec_clusters(last_el, &last_el->l_recs[i]) == clusters_to_del)
 		credits += 1 + tree_depth;
 
 	/* update to the truncate log. */
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index 51b0204..af01158 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -85,8 +85,11 @@ int ocfs2_mmap(struct file *file, struct
 	int ret = 0, lock_level = 0;
 	struct ocfs2_super *osb = OCFS2_SB(file->f_dentry->d_inode->i_sb);
 
-	/* We don't want to support shared writable mappings yet. */
-	if (!ocfs2_mount_local(osb) &&
+	/*
+	 * Only support shared writeable mmap for local mounts which
+	 * don't know about holes.
+	 */
+	if ((!ocfs2_mount_local(osb) || ocfs2_sparse_alloc(osb)) &&
 	    ((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE)) &&
 	    ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) {
 		mlog(0, "disallow shared writable mmaps %lx\n", vma->vm_flags);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 28dd757..36289e6 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -175,8 +175,6 @@ static struct dentry *ocfs2_lookup(struc
 
 	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);
 		ret = ERR_PTR(-EACCES);
 		goto bail_unlock;
 	}
@@ -189,7 +187,6 @@ static struct dentry *ocfs2_lookup(struc
 	 * unlink. */
 	spin_lock(&oi->ip_lock);
 	oi->ip_flags &= ~OCFS2_INODE_MAYBE_ORPHANED;
-	oi->ip_orphaned_slot = OCFS2_INVALID_SLOT;
 	spin_unlock(&oi->ip_lock);
 
 bail_add:
@@ -288,7 +285,7 @@ static int ocfs2_fill_new_dir(struct ocf
 
 	i_size_write(inode, inode->i_sb->s_blocksize);
 	inode->i_nlink = 2;
-	inode->i_blocks = ocfs2_align_bytes_to_sectors(inode->i_sb->s_blocksize);
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
 	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
 	if (status < 0) {
 		mlog_errno(status);
@@ -581,8 +578,9 @@ static int ocfs2_mknod_locked(struct ocf
 	if (ocfs2_populate_inode(inode, fe, 1) < 0) {
 		mlog(ML_ERROR, "populate inode failed! bh->b_blocknr=%llu, "
 		     "i_blkno=%llu, i_ino=%lu\n",
-		     (unsigned long long) (*new_fe_bh)->b_blocknr,
-		     (unsigned long long)fe->i_blkno, inode->i_ino);
+		     (unsigned long long)(*new_fe_bh)->b_blocknr,
+		     (unsigned long long)le64_to_cpu(fe->i_blkno),
+		     inode->i_ino);
 		BUG();
 	}
 
@@ -1486,8 +1484,7 @@ static int ocfs2_create_symlink_data(str
 	struct buffer_head **bhs = NULL;
 	const char *c;
 	struct super_block *sb = osb->sb;
-	u64 p_blkno;
-	int p_blocks;
+	u64 p_blkno, p_blocks;
 	int virtual, blocks, status, i, bytes_left;
 
 	bytes_left = i_size_read(inode) + 1;
@@ -1514,8 +1511,8 @@ static int ocfs2_create_symlink_data(str
 		goto bail;
 	}
 
-	status = ocfs2_extent_map_get_blocks(inode, 0, 1, &p_blkno,
-					     &p_blocks);
+	status = ocfs2_extent_map_get_blocks(inode, 0, &p_blkno, &p_blocks,
+					     NULL);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -1674,8 +1671,11 @@ static int ocfs2_symlink(struct inode *d
 	inode->i_rdev = 0;
 	newsize = l - 1;
 	if (l > ocfs2_fast_symlink_chars(sb)) {
+		u32 offset = 0;
+
 		inode->i_op = &ocfs2_symlink_inode_operations;
-		status = ocfs2_do_extend_allocation(osb, inode, 1, new_fe_bh,
+		status = ocfs2_do_extend_allocation(osb, inode, &offset, 1,
+						    new_fe_bh,
 						    handle, data_ac, NULL,
 						    NULL);
 		if (status < 0) {
@@ -1689,7 +1689,7 @@ static int ocfs2_symlink(struct inode *d
 			goto bail;
 		}
 		i_size_write(inode, newsize);
-		inode->i_blocks = ocfs2_align_bytes_to_sectors(newsize);
+		inode->i_blocks = ocfs2_inode_sector_count(inode);
 	} else {
 		inode->i_op = &ocfs2_fast_symlink_inode_operations;
 		memcpy((char *) fe->id2.i_symlink, symname, l);
@@ -2222,9 +2222,7 @@ static int ocfs2_orphan_add(struct ocfs2
 	/* Record which orphan dir our inode now resides
 	 * in. delete_inode will use this to determine which orphan
 	 * dir to lock. */
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	OCFS2_I(inode)->ip_orphaned_slot = osb->slot_num;
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
+	fe->i_orphaned_slot = cpu_to_le16(osb->slot_num);
 
 	mlog(0, "Inode %llu orphaned in slot %d\n",
 	     (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index db8e77c..a860633 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -46,11 +46,6 @@ #include "ocfs2_fs.h"
 #include "endian.h"
 #include "ocfs2_lockid.h"
 
-struct ocfs2_extent_map {
-	u32		em_clusters;
-	struct rb_root	em_extents;
-};
-
 /* Most user visible OCFS2 inodes will have very few pieces of
  * metadata, but larger files (including bitmaps, etc) must be taken
  * into account when designing an access scheme. We allow a small
@@ -303,6 +298,13 @@ static inline int ocfs2_should_order_dat
 	return 1;
 }
 
+static inline int ocfs2_sparse_alloc(struct ocfs2_super *osb)
+{
+	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
+		return 1;
+	return 0;
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
@@ -361,9 +363,9 @@ #define OCFS2_RO_ON_INVALID_DINODE(__sb,
 	typeof(__di) ____di = (__di);					\
 	ocfs2_error((__sb), 						\
 		"Dinode # %llu has bad signature %.*s",			\
-		(unsigned long long)(____di)->i_blkno, 7,		\
+		(unsigned long long)le64_to_cpu((____di)->i_blkno), 7, 	\
 		(____di)->i_signature);					\
-} while (0);
+} while (0)
 
 #define OCFS2_IS_VALID_EXTENT_BLOCK(ptr)				\
 	(!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE))
@@ -372,9 +374,9 @@ #define OCFS2_RO_ON_INVALID_EXTENT_BLOCK
 	typeof(__eb) ____eb = (__eb);					\
 	ocfs2_error((__sb), 						\
 		"Extent Block # %llu has bad signature %.*s",		\
-		(unsigned long long)(____eb)->h_blkno, 7,		\
+		(unsigned long long)le64_to_cpu((____eb)->h_blkno), 7,	\
 		(____eb)->h_signature);					\
-} while (0);
+} while (0)
 
 #define OCFS2_IS_VALID_GROUP_DESC(ptr)					\
 	(!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE))
@@ -383,9 +385,9 @@ #define OCFS2_RO_ON_INVALID_GROUP_DESC(_
 	typeof(__gd) ____gd = (__gd);					\
 		ocfs2_error((__sb),					\
 		"Group Descriptor # %llu has bad signature %.*s",	\
-		(unsigned long long)(____gd)->bg_blkno, 7,		\
+		(unsigned long long)le64_to_cpu((____gd)->bg_blkno), 7, \
 		(____gd)->bg_signature);				\
-} while (0);
+} while (0)
 
 static inline unsigned long ino_from_blkno(struct super_block *sb,
 					   u64 blkno)
@@ -461,6 +463,49 @@ static inline unsigned long ocfs2_align_
 	return (unsigned long)((bytes + 511) >> 9);
 }
 
+static inline unsigned int ocfs2_page_index_to_clusters(struct super_block *sb,
+							unsigned long pg_index)
+{
+	u32 clusters = pg_index;
+	unsigned int cbits = OCFS2_SB(sb)->s_clustersize_bits;
+
+	if (unlikely(PAGE_CACHE_SHIFT > cbits))
+		clusters = pg_index << (PAGE_CACHE_SHIFT - cbits);
+	else if (PAGE_CACHE_SHIFT < cbits)
+		clusters = pg_index >> (cbits - PAGE_CACHE_SHIFT);
+
+	return clusters;
+}
+
+/*
+ * Find the 1st page index which covers the given clusters.
+ */
+static inline unsigned long ocfs2_align_clusters_to_page_index(struct super_block *sb,
+							u32 clusters)
+{
+	unsigned int cbits = OCFS2_SB(sb)->s_clustersize_bits;
+	unsigned long index = clusters;
+
+	if (PAGE_CACHE_SHIFT > cbits) {
+		index = clusters >> (PAGE_CACHE_SHIFT - cbits);
+	} else if (PAGE_CACHE_SHIFT < cbits) {
+		index = clusters << (cbits - PAGE_CACHE_SHIFT);
+	}
+
+	return index;
+}
+
+static inline unsigned int ocfs2_pages_per_cluster(struct super_block *sb)
+{
+	unsigned int cbits = OCFS2_SB(sb)->s_clustersize_bits;
+	unsigned int pages_per_cluster = 1;
+
+	if (PAGE_CACHE_SHIFT < cbits)
+		pages_per_cluster = 1 << (cbits - PAGE_CACHE_SHIFT);
+
+	return pages_per_cluster;
+}
+
 #define ocfs2_set_bit ext2_set_bit
 #define ocfs2_clear_bit ext2_clear_bit
 #define ocfs2_test_bit ext2_test_bit
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index e61e218..f0d9eb0 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -86,7 +86,8 @@ #define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,
 	OCFS2_SB(sb)->s_feature_incompat &= ~(mask)
 
 #define OCFS2_FEATURE_COMPAT_SUPP	OCFS2_FEATURE_COMPAT_BACKUP_SB
-#define OCFS2_FEATURE_INCOMPAT_SUPP	OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT
+#define OCFS2_FEATURE_INCOMPAT_SUPP	(OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
+					 | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP	0
 
 /*
@@ -155,10 +156,18 @@ #define OCFS2_FL_VISIBLE	(0x000100FF)	/*
 #define OCFS2_FL_MODIFIABLE	(0x000100FF)	/* User modifiable flags */
 
 /*
+ * Extent record flags (e_node.leaf.flags)
+ */
+#define OCFS2_EXT_UNWRITTEN	(0x01)	/* Extent is allocated but
+					 * unwritten */
+
+/*
  * ioctl commands
  */
 #define OCFS2_IOC_GETFLAGS	_IOR('f', 1, long)
 #define OCFS2_IOC_SETFLAGS	_IOW('f', 2, long)
+#define OCFS2_IOC32_GETFLAGS	_IOR('f', 1, int)
+#define OCFS2_IOC32_SETFLAGS	_IOW('f', 2, int)
 
 /*
  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
@@ -282,10 +291,21 @@ #define OCFS2_RAW_SB(dinode)		(&((dinode
 /*
  * On disk extent record for OCFS2
  * It describes a range of clusters on disk.
+ *
+ * Length fields are divided into interior and leaf node versions.
+ * This leaves room for a flags field (OCFS2_EXT_*) in the leaf nodes.
  */
 struct ocfs2_extent_rec {
 /*00*/	__le32 e_cpos;		/* Offset into the file, in clusters */
-	__le32 e_clusters;	/* Clusters covered by this extent */
+	union {
+		__le32 e_int_clusters; /* Clusters covered by all children */
+		struct {
+			__le16 e_leaf_clusters; /* Clusters covered by this
+						   extent */
+			__u8 e_reserved1;
+			__u8 e_flags; /* Extent flags */
+		};
+	};
 	__le64 e_blkno;		/* Physical disk offset, in blocks */
 /*10*/
 };
@@ -311,7 +331,10 @@ struct ocfs2_extent_list {
 /*00*/	__le16 l_tree_depth;		/* Extent tree depth from this
 					   point.  0 means data extents
 					   hang directly off this
-					   header (a leaf) */
+					   header (a leaf)
+					   NOTE: The high 8 bits cannot be
+					   used - tree_depth is never that big.
+					*/
 	__le16 l_count;			/* Number of extent records */
 	__le16 l_next_free_rec;		/* Next unused extent slot */
 	__le16 l_reserved1;
@@ -446,7 +469,9 @@ struct ocfs2_dinode {
 	__le32 i_ctime_nsec;
 	__le32 i_mtime_nsec;
 	__le32 i_attr;
-	__le32 i_reserved1;
+	__le16 i_orphaned_slot;		/* Only valid when OCFS2_ORPHANED_FL
+					   was set in i_flags */
+	__le16 i_reserved1;
 /*70*/	__le64 i_reserved2[8];
 /*B8*/	union {
 		__le64 i_pad1;		/* Generic way to refer to this
diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h
index 4d5d565..4ca02b1 100644
--- a/fs/ocfs2/ocfs2_lockid.h
+++ b/fs/ocfs2/ocfs2_lockid.h
@@ -44,6 +44,7 @@ enum ocfs2_lock_type {
 	OCFS2_LOCK_TYPE_RENAME,
 	OCFS2_LOCK_TYPE_RW,
 	OCFS2_LOCK_TYPE_DENTRY,
+	OCFS2_LOCK_TYPE_OPEN,
 	OCFS2_NUM_LOCK_TYPES
 };
 
@@ -69,6 +70,9 @@ static inline char ocfs2_lock_type_char(
 		case OCFS2_LOCK_TYPE_DENTRY:
 			c = 'N';
 			break;
+		case OCFS2_LOCK_TYPE_OPEN:
+			c = 'O';
+			break;
 		default:
 			c = '\0';
 	}
@@ -85,6 +89,7 @@ static char *ocfs2_lock_type_strings[] =
 	 * important job it does, anyway. */
 	[OCFS2_LOCK_TYPE_RW] = "Write/Read",
 	[OCFS2_LOCK_TYPE_DENTRY] = "Dentry",
+	[OCFS2_LOCK_TYPE_OPEN] = "Open",
 };
 
 static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index 2d3ac32..d8b7906 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
 
 #define MLOG_MASK_PREFIX ML_SUPER
 #include <cluster/masklog.h>
@@ -197,7 +196,7 @@ int ocfs2_init_slot_info(struct ocfs2_su
 		goto bail;
 	}
 
-	status = ocfs2_extent_map_get_blocks(inode, 0ULL, 1, &blkno, NULL);
+	status = ocfs2_extent_map_get_blocks(inode, 0ULL, &blkno, NULL, NULL);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 6dbb117..e343762 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -381,8 +381,7 @@ static int ocfs2_block_group_alloc(struc
 					     le32_to_cpu(fe->i_clusters)));
 	spin_unlock(&OCFS2_I(alloc_inode)->ip_lock);
 	i_size_write(alloc_inode, le64_to_cpu(fe->i_size));
-	alloc_inode->i_blocks =
-		ocfs2_align_bytes_to_sectors(i_size_read(alloc_inode));
+	alloc_inode->i_blocks = ocfs2_inode_sector_count(alloc_inode);
 
 	status = 0;
 bail:
@@ -850,9 +849,9 @@ static int ocfs2_relink_block_group(hand
 	}
 
 	mlog(0, "Suballoc %llu, chain %u, move group %llu to top, prev = %llu\n",
-	     (unsigned long long)fe->i_blkno, chain,
-	     (unsigned long long)bg->bg_blkno,
-	     (unsigned long long)prev_bg->bg_blkno);
+	     (unsigned long long)le64_to_cpu(fe->i_blkno), chain,
+	     (unsigned long long)le64_to_cpu(bg->bg_blkno),
+	     (unsigned long long)le64_to_cpu(prev_bg->bg_blkno));
 
 	fe_ptr = le64_to_cpu(fe->id2.i_chain.cl_recs[chain].c_blkno);
 	bg_ptr = le64_to_cpu(bg->bg_next_group);
@@ -1163,7 +1162,7 @@ static int ocfs2_search_chain(struct ocf
 	}
 
 	mlog(0, "alloc succeeds: we give %u bits from block group %llu\n",
-	     tmp_bits, (unsigned long long)bg->bg_blkno);
+	     tmp_bits, (unsigned long long)le64_to_cpu(bg->bg_blkno));
 
 	*num_bits = tmp_bits;
 
@@ -1228,7 +1227,7 @@ static int ocfs2_search_chain(struct ocf
 	}
 
 	mlog(0, "Allocated %u bits from suballocator %llu\n", *num_bits,
-	     (unsigned long long)fe->i_blkno);
+	     (unsigned long long)le64_to_cpu(fe->i_blkno));
 
 	*bg_blkno = le64_to_cpu(bg->bg_blkno);
 	*bits_left = le16_to_cpu(bg->bg_free_bits_count);
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 6534f92..7c5e3f5 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -806,9 +806,6 @@ static int __init ocfs2_init(void)
 
 	ocfs2_print_version();
 
-	if (init_ocfs2_extent_maps())
-		return -ENOMEM;
-
 	status = init_ocfs2_uptodate_cache();
 	if (status < 0) {
 		mlog_errno(status);
@@ -837,7 +834,6 @@ leave:
 	if (status < 0) {
 		ocfs2_free_mem_caches();
 		exit_ocfs2_uptodate_cache();
-		exit_ocfs2_extent_maps();
 	}
 
 	mlog_exit(status);
@@ -863,8 +859,6 @@ static void __exit ocfs2_exit(void)
 
 	unregister_filesystem(&ocfs2_fs_type);
 
-	exit_ocfs2_extent_maps();
-
 	exit_ocfs2_uptodate_cache();
 
 	mlog_exit_void();
@@ -943,8 +937,7 @@ static void ocfs2_inode_init_once(void *
 {
 	struct ocfs2_inode_info *oi = data;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		oi->ip_flags = 0;
 		oi->ip_open_count = 0;
 		spin_lock_init(&oi->ip_lock);
@@ -963,6 +956,7 @@ static void ocfs2_inode_init_once(void *
 		ocfs2_lock_res_init_once(&oi->ip_rw_lockres);
 		ocfs2_lock_res_init_once(&oi->ip_meta_lockres);
 		ocfs2_lock_res_init_once(&oi->ip_data_lockres);
+		ocfs2_lock_res_init_once(&oi->ip_open_lockres);
 
 		ocfs2_metadata_cache_init(&oi->vfs_inode);
 
@@ -1543,7 +1537,7 @@ static int ocfs2_verify_volume(struct oc
 		} else if (bh->b_blocknr != le64_to_cpu(di->i_blkno)) {
 			mlog(ML_ERROR, "bad block number on superblock: "
 			     "found %llu, should be %llu\n",
-			     (unsigned long long)di->i_blkno,
+			     (unsigned long long)le64_to_cpu(di->i_blkno),
 			     (unsigned long long)bh->b_blocknr);
 		} else if (le32_to_cpu(di->id2.i_super.s_clustersize_bits) < 12 ||
 			    le32_to_cpu(di->id2.i_super.s_clustersize_bits) > 20) {
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 40dc1a5..7134007 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -67,16 +67,9 @@ static char *ocfs2_page_getlink(struct d
 	page = read_mapping_page(mapping, 0, NULL);
 	if (IS_ERR(page))
 		goto sync_fail;
-	wait_on_page_locked(page);
-	if (!PageUptodate(page))
-		goto async_fail;
 	*ppage = page;
 	return kmap(page);
 
-async_fail:
-	page_cache_release(page);
-	return ERR_PTR(-EIO);
-
 sync_fail:
 	return (char*)page;
 }
diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
index f30e63b..66a13ee 100644
--- a/fs/ocfs2/vote.c
+++ b/fs/ocfs2/vote.c
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
 #include <linux/kthread.h>
 
 #include <cluster/heartbeat.h>
@@ -63,17 +62,10 @@ struct ocfs2_msg_hdr
 	__be32 h_node_num;    /* node sending this particular message. */
 };
 
-/* OCFS2_MAX_FILENAME_LEN is 255 characters, but we want to align this
- * for the network. */
-#define OCFS2_VOTE_FILENAME_LEN 256
 struct ocfs2_vote_msg
 {
 	struct ocfs2_msg_hdr v_hdr;
-	union {
-		__be32 v_generic1;
-		__be32 v_orphaned_slot;	/* Used during delete votes */
-		__be32 v_nlink;		/* Used during unlink votes */
-	} md1;				/* Message type dependant 1 */
+	__be32 v_reserved1;
 };
 
 /* Responses are given these values to maintain backwards
@@ -86,7 +78,6 @@ struct ocfs2_response_msg
 {
 	struct ocfs2_msg_hdr r_hdr;
 	__be32 r_response;
-	__be32 r_orphaned_slot;
 };
 
 struct ocfs2_vote_work {
@@ -96,7 +87,6 @@ struct ocfs2_vote_work {
 
 enum ocfs2_vote_request {
 	OCFS2_VOTE_REQ_INVALID = 0,
-	OCFS2_VOTE_REQ_DELETE,
 	OCFS2_VOTE_REQ_MOUNT,
 	OCFS2_VOTE_REQ_UMOUNT,
 	OCFS2_VOTE_REQ_LAST
@@ -151,135 +141,23 @@ static void ocfs2_process_umount_request
 	ocfs2_node_map_set_bit(osb, &osb->umount_map, node_num);
 }
 
-void ocfs2_mark_inode_remotely_deleted(struct inode *inode)
-{
-	struct ocfs2_inode_info *oi = OCFS2_I(inode);
-
-	assert_spin_locked(&oi->ip_lock);
-	/* We set the SKIP_DELETE flag on the inode so we don't try to
-	 * delete it in delete_inode ourselves, thus avoiding
-	 * unecessary lock pinging. If the other node failed to wipe
-	 * the inode as a result of a crash, then recovery will pick
-	 * up the slack. */
-	oi->ip_flags |= OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE;
-}
-
-static int ocfs2_process_delete_request(struct inode *inode,
-					int *orphaned_slot)
-{
-	int response = OCFS2_RESPONSE_BUSY;
-
-	mlog(0, "DELETE vote on inode %lu, read lnk_cnt = %u, slot = %d\n",
-	     inode->i_ino, inode->i_nlink, *orphaned_slot);
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-
-	/* Whatever our vote response is, we want to make sure that
-	 * the orphaned slot is recorded properly on this node *and*
-	 * on the requesting node. Technically, if the requesting node
-	 * did not know which slot the inode is orphaned in but we
-	 * respond with BUSY he doesn't actually need the orphaned
-	 * slot, but it doesn't hurt to do it here anyway. */
-	if ((*orphaned_slot) != OCFS2_INVALID_SLOT) {
-		mlog_bug_on_msg(OCFS2_I(inode)->ip_orphaned_slot !=
-				OCFS2_INVALID_SLOT &&
-				OCFS2_I(inode)->ip_orphaned_slot !=
-				(*orphaned_slot),
-				"Inode %llu: This node thinks it's "
-				"orphaned in slot %d, messaged it's in %d\n",
-				(unsigned long long)OCFS2_I(inode)->ip_blkno,
-				OCFS2_I(inode)->ip_orphaned_slot,
-				*orphaned_slot);
-
-		mlog(0, "Setting orphaned slot for inode %llu to %d\n",
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno,
-		     *orphaned_slot);
-
-		OCFS2_I(inode)->ip_orphaned_slot = *orphaned_slot;
-	} else {
-		mlog(0, "Sending back orphaned slot %d for inode %llu\n",
-		     OCFS2_I(inode)->ip_orphaned_slot,
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
-
-		*orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot;
-	}
-
-	/* vote no if the file is still open. */
-	if (OCFS2_I(inode)->ip_open_count) {
-		mlog(0, "open count = %u\n",
-		     OCFS2_I(inode)->ip_open_count);
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
-		goto done;
-	}
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	/* directories are a bit ugly... What if someone is sitting in
-	 * it? We want to make sure the inode is removed completely as
-	 * a result of the iput in process_vote. */
-	if (S_ISDIR(inode->i_mode) && (atomic_read(&inode->i_count) != 1)) {
-		mlog(0, "i_count = %u\n", atomic_read(&inode->i_count));
-		goto done;
-	}
-
-	if (filemap_fdatawrite(inode->i_mapping)) {
-		mlog(ML_ERROR, "Could not sync inode %llu for delete!\n",
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
-		goto done;
-	}
-	sync_mapping_buffers(inode->i_mapping);
-	truncate_inode_pages(inode->i_mapping, 0);
-	ocfs2_extent_map_trunc(inode, 0);
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	/* double check open count - someone might have raced this
-	 * thread into ocfs2_file_open while we were writing out
-	 * data. If we're to allow a wipe of this inode now, we *must*
-	 * hold the spinlock until we've marked it. */
-	if (OCFS2_I(inode)->ip_open_count) {
-		mlog(0, "Raced to wipe! open count = %u\n",
-		     OCFS2_I(inode)->ip_open_count);
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
-		goto done;
-	}
-
-	/* Mark the inode as being wiped from disk. */
-	ocfs2_mark_inode_remotely_deleted(inode);
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	/* Not sure this is necessary anymore. */
-	d_prune_aliases(inode);
-
-	/* If we get here, then we're voting 'yes', so commit the
-	 * delete on our side. */
-	response = OCFS2_RESPONSE_OK;
-done:
-	return response;
-}
-
 static void ocfs2_process_vote(struct ocfs2_super *osb,
 			       struct ocfs2_vote_msg *msg)
 {
 	int net_status, vote_response;
-	int orphaned_slot = 0;
-	unsigned int node_num, generation;
+	unsigned int node_num;
 	u64 blkno;
 	enum ocfs2_vote_request request;
-	struct inode *inode = NULL;
 	struct ocfs2_msg_hdr *hdr = &msg->v_hdr;
 	struct ocfs2_response_msg response;
 
 	/* decode the network mumbo jumbo into local variables. */
 	request = be32_to_cpu(hdr->h_request);
 	blkno = be64_to_cpu(hdr->h_blkno);
-	generation = be32_to_cpu(hdr->h_generation);
 	node_num = be32_to_cpu(hdr->h_node_num);
-	if (request == OCFS2_VOTE_REQ_DELETE)
-		orphaned_slot = be32_to_cpu(msg->md1.v_orphaned_slot);
 
-	mlog(0, "processing vote: request = %u, blkno = %llu, "
-	     "generation = %u, node_num = %u, priv1 = %u\n", request,
-	     (unsigned long long)blkno, generation, node_num,
-	     be32_to_cpu(msg->md1.v_generic1));
+	mlog(0, "processing vote: request = %u, blkno = %llu, node_num = %u\n",
+	     request, (unsigned long long)blkno, node_num);
 
 	if (!ocfs2_is_valid_vote_request(request)) {
 		mlog(ML_ERROR, "Invalid vote request %d from node %u\n",
@@ -302,52 +180,6 @@ static void ocfs2_process_vote(struct oc
 		break;
 	}
 
-	/* We cannot process the remaining message types before we're
-	 * fully mounted. It's perfectly safe however to send a 'yes'
-	 * response as we can't possibly have any of the state they're
-	 * asking us to modify yet. */
-	if (atomic_read(&osb->vol_state) == VOLUME_INIT)
-		goto respond;
-
-	/* If we get here, then the request is against an inode. */
-	inode = ocfs2_ilookup_for_vote(osb, blkno,
-				       request == OCFS2_VOTE_REQ_DELETE);
-
-	/* Not finding the inode is perfectly valid - it means we're
-	 * not interested in what the other node is about to do to it
-	 * so in those cases we automatically respond with an
-	 * affirmative. Cluster locking ensures that we won't race
-	 * interest in the inode with this vote request. */
-	if (!inode)
-		goto respond;
-
-	/* Check generation values. It's possible for us to get a
-	 * request against a stale inode. If so then we proceed as if
-	 * we had not found an inode in the first place. */
-	if (inode->i_generation != generation) {
-		mlog(0, "generation passed %u != inode generation = %u, "
-		     "ip_flags = %x, ip_blkno = %llu, msg %llu, i_count = %u, "
-		     "message type = %u\n", generation, inode->i_generation,
-		     OCFS2_I(inode)->ip_flags,
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno,
-		     (unsigned long long)blkno, atomic_read(&inode->i_count),
-		     request);
-		iput(inode);
-		inode = NULL;
-		goto respond;
-	}
-
-	switch (request) {
-	case OCFS2_VOTE_REQ_DELETE:
-		vote_response = ocfs2_process_delete_request(inode,
-							     &orphaned_slot);
-		break;
-	default:
-		mlog(ML_ERROR, "node %u, invalid request: %u\n",
-		     node_num, request);
-		vote_response = OCFS2_RESPONSE_BAD_MSG;
-	}
-
 respond:
 	/* Response struture is small so we just put it on the stack
 	 * and stuff it inline. */
@@ -357,7 +189,6 @@ respond:
 	response.r_hdr.h_generation = hdr->h_generation;
 	response.r_hdr.h_node_num = cpu_to_be32(osb->node_num);
 	response.r_response = cpu_to_be32(vote_response);
-	response.r_orphaned_slot = cpu_to_be32(orphaned_slot);
 
 	net_status = o2net_send_message(OCFS2_MESSAGE_TYPE_RESPONSE,
 					osb->net_key,
@@ -373,9 +204,6 @@ respond:
 	    && net_status != -ENOTCONN)
 		mlog(ML_ERROR, "message to node %u fails with error %d!\n",
 		     node_num, net_status);
-
-	if (inode)
-		iput(inode);
 }
 
 static void ocfs2_vote_thread_do_work(struct ocfs2_super *osb)
@@ -634,8 +462,7 @@ bail:
 static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb,
 						      u64 blkno,
 						      unsigned int generation,
-						      enum ocfs2_vote_request type,
-						      u32 priv)
+						      enum ocfs2_vote_request type)
 {
 	struct ocfs2_vote_msg *request;
 	struct ocfs2_msg_hdr *hdr;
@@ -651,8 +478,6 @@ static struct ocfs2_vote_msg * ocfs2_new
 		hdr->h_request = cpu_to_be32(type);
 		hdr->h_blkno = cpu_to_be64(blkno);
 		hdr->h_generation = cpu_to_be32(generation);
-
-		request->md1.v_generic1 = cpu_to_be32(priv);
 	}
 
 	return request;
@@ -664,7 +489,7 @@ static int ocfs2_do_request_vote(struct 
 				 struct ocfs2_vote_msg *request,
 				 struct ocfs2_net_response_cb *callback)
 {
-	int status, response;
+	int status, response = -EBUSY;
 	unsigned int response_id;
 	struct ocfs2_msg_hdr *hdr;
 
@@ -686,109 +511,12 @@ bail:
 	return status;
 }
 
-static int ocfs2_request_vote(struct inode *inode,
-			      struct ocfs2_vote_msg *request,
-			      struct ocfs2_net_response_cb *callback)
-{
-	int status;
-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
-	if (ocfs2_inode_is_new(inode))
-		return 0;
-
-	status = -EAGAIN;
-	while (status == -EAGAIN) {
-		if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) &&
-		    signal_pending(current))
-			return -ERESTARTSYS;
-
-		status = ocfs2_super_lock(osb, 0);
-		if (status < 0) {
-			mlog_errno(status);
-			break;
-		}
-
-		status = 0;
-		if (!ocfs2_node_map_is_only(osb, &osb->mounted_map,
-					   osb->node_num))
-			status = ocfs2_do_request_vote(osb, request, callback);
-
-		ocfs2_super_unlock(osb, 0);
-	}
-	return status;
-}
-
-static void ocfs2_delete_response_cb(void *priv,
-				     struct ocfs2_response_msg *resp)
-{
-	int orphaned_slot, node;
-	struct inode *inode = priv;
-
-	orphaned_slot = be32_to_cpu(resp->r_orphaned_slot);
-	node = be32_to_cpu(resp->r_hdr.h_node_num);
-	mlog(0, "node %d tells us that inode %llu is orphaned in slot %d\n",
-	     node, (unsigned long long)OCFS2_I(inode)->ip_blkno,
-	     orphaned_slot);
-
-	/* The other node may not actually know which slot the inode
-	 * is orphaned in. */
-	if (orphaned_slot == OCFS2_INVALID_SLOT)
-		return;
-
-	/* Ok, the responding node knows which slot this inode is
-	 * orphaned in. We verify that the information is correct and
-	 * then record this in the inode. ocfs2_delete_inode will use
-	 * this information to determine which lock to take. */
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	mlog_bug_on_msg(OCFS2_I(inode)->ip_orphaned_slot != orphaned_slot &&
-			OCFS2_I(inode)->ip_orphaned_slot
-			!= OCFS2_INVALID_SLOT, "Inode %llu: Node %d says it's "
-			"orphaned in slot %d, we think it's in %d\n",
-			(unsigned long long)OCFS2_I(inode)->ip_blkno,
-			be32_to_cpu(resp->r_hdr.h_node_num),
-			orphaned_slot, OCFS2_I(inode)->ip_orphaned_slot);
-
-	OCFS2_I(inode)->ip_orphaned_slot = orphaned_slot;
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-}
-
-int ocfs2_request_delete_vote(struct inode *inode)
-{
-	int orphaned_slot, status;
-	struct ocfs2_net_response_cb delete_cb;
-	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-	struct ocfs2_vote_msg *request;
-
-	spin_lock(&OCFS2_I(inode)->ip_lock);
-	orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot;
-	spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-	delete_cb.rc_cb = ocfs2_delete_response_cb;
-	delete_cb.rc_priv = inode;
-
-	mlog(0, "Inode %llu, we start thinking orphaned slot is %d\n",
-	     (unsigned long long)OCFS2_I(inode)->ip_blkno, orphaned_slot);
-
-	status = -ENOMEM;
-	request = ocfs2_new_vote_request(osb, OCFS2_I(inode)->ip_blkno,
-					 inode->i_generation,
-					 OCFS2_VOTE_REQ_DELETE, orphaned_slot);
-	if (request) {
-		status = ocfs2_request_vote(inode, request, &delete_cb);
-
-		kfree(request);
-	}
-
-	return status;
-}
-
 int ocfs2_request_mount_vote(struct ocfs2_super *osb)
 {
 	int status;
 	struct ocfs2_vote_msg *request = NULL;
 
-	request = ocfs2_new_vote_request(osb, 0ULL, 0,
-					 OCFS2_VOTE_REQ_MOUNT, 0);
+	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_MOUNT);
 	if (!request) {
 		status = -ENOMEM;
 		goto bail;
@@ -821,8 +549,7 @@ int ocfs2_request_umount_vote(struct ocf
 	int status;
 	struct ocfs2_vote_msg *request = NULL;
 
-	request = ocfs2_new_vote_request(osb, 0ULL, 0,
-					 OCFS2_VOTE_REQ_UMOUNT, 0);
+	request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_UMOUNT);
 	if (!request) {
 		status = -ENOMEM;
 		goto bail;
@@ -969,7 +696,6 @@ static int ocfs2_handle_vote_message(str
 	     be32_to_cpu(work->w_msg.v_hdr.h_generation));
 	mlog(0, "h_node_num = %u\n",
 	     be32_to_cpu(work->w_msg.v_hdr.h_node_num));
-	mlog(0, "v_generic1 = %u\n", be32_to_cpu(work->w_msg.md1.v_generic1));
 
 	spin_lock(&osb->vote_task_lock);
 	list_add_tail(&work->w_list, &osb->vote_list);
diff --git a/fs/ocfs2/vote.h b/fs/ocfs2/vote.h
index 53ebc1c..9ea46f6 100644
--- a/fs/ocfs2/vote.h
+++ b/fs/ocfs2/vote.h
@@ -38,14 +38,11 @@ static inline void ocfs2_kick_vote_threa
 	wake_up(&osb->vote_event);
 }
 
-int ocfs2_request_delete_vote(struct inode *inode);
 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);
 void ocfs2_unregister_net_handlers(struct ocfs2_super *osb);
 
-void ocfs2_mark_inode_remotely_deleted(struct inode *inode);
-
 void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb,
 					int node_num);
 #endif
diff --git a/fs/open.c b/fs/open.c
index c989fb4..ca9981c 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -7,7 +7,6 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/file.h>
-#include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 #include <linux/fsnotify.h>
 #include <linux/module.h>
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index bde1c16..731a90e 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -419,8 +419,7 @@ static void op_inode_init_once(void *dat
 {
 	struct op_inode_info *oi = (struct op_inode_info *) data;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&oi->vfs_inode);
 }
 
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index 6e8bb66..0120704 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -236,3 +236,12 @@ config EFI_PARTITION
 	help
 	  Say Y here if you would like to use hard disks under Linux which
 	  were partitioned using EFI GPT.
+
+config SYSV68_PARTITION
+	bool "SYSV68 partition table support" if PARTITION_ADVANCED
+	default y if M68K
+	help
+	  Say Y here if you would like to be able to read the hard disk
+	  partition table format used by Motorola Delta machines (using
+	  sysv68).
+	  Otherwise, say N.
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 67e665f..03af8ea 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_ULTRIX_PARTITION) += ultrix
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
 obj-$(CONFIG_KARMA_PARTITION) += karma.o
+obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index 1bc9f37..e349132 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -271,7 +271,7 @@ #ifdef CONFIG_BLK_DEV_MFM
 		extern void xd_set_geometry(struct block_device *,
 			unsigned char, unsigned char, unsigned int);
 		xd_set_geometry(bdev, dr->secspertrack, heads, 1);
-		invalidate_bdev(bdev, 1);
+		invalidate_bh_lrus();
 		truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 	}
 #endif
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 8a7d003..9a3a058 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -34,6 +34,7 @@ #include "ibm.h"
 #include "ultrix.h"
 #include "efi.h"
 #include "karma.h"
+#include "sysv68.h"
 
 #ifdef CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(dev_t dev);
@@ -105,6 +106,9 @@ #endif
 #ifdef CONFIG_KARMA_PARTITION
 	karma_partition,
 #endif
+#ifdef CONFIG_SYSV68_PARTITION
+	sysv68_partition,
+#endif
 	NULL
 };
  
@@ -312,7 +316,7 @@ #endif
 	NULL,
 };
 
-extern struct subsystem block_subsys;
+extern struct kset block_subsys;
 
 static void part_release(struct kobject *kobj)
 {
@@ -388,7 +392,7 @@ void add_partition(struct gendisk *disk,
 	kobject_add(&p->kobj);
 	if (!disk->part_uevent_suppress)
 		kobject_uevent(&p->kobj, KOBJ_ADD);
-	sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem");
+	sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem");
 	if (flags & ADDPART_FLAG_WHOLEDISK) {
 		static struct attribute addpartattr = {
 			.name = "whole_disk",
@@ -444,7 +448,7 @@ static int disk_sysfs_symlinks(struct ge
 			goto err_out_dev_link;
 	}
 
-	err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj,
+	err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,
 				"subsystem");
 	if (err)
 		goto err_out_disk_name_lnk;
@@ -569,9 +573,6 @@ unsigned char *read_dev_sector(struct bl
 	page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
 				 NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
-		if (!PageUptodate(page))
-			goto fail;
 		if (PageError(page))
 			goto fail;
 		p->v = page;
diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c
new file mode 100644
index 0000000..4eba27b
--- /dev/null
+++ b/fs/partitions/sysv68.c
@@ -0,0 +1,92 @@
+/*
+ *  fs/partitions/sysv68.c
+ *
+ *  Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
+ */
+
+#include "check.h"
+#include "sysv68.h"
+
+/*
+ *	Volume ID structure: on first 256-bytes sector of disk
+ */
+
+struct volumeid {
+	u8	vid_unused[248];
+	u8	vid_mac[8];	/* ASCII string "MOTOROLA" */
+};
+
+/*
+ *	config block: second 256-bytes sector on disk
+ */
+
+struct dkconfig {
+	u8	ios_unused0[128];
+	__be32	ios_slcblk;	/* Slice table block number */
+	__be16	ios_slccnt;	/* Number of entries in slice table */
+	u8	ios_unused1[122];
+};
+
+/*
+ *	combined volumeid and dkconfig block
+ */
+
+struct dkblk0 {
+	struct volumeid dk_vid;
+	struct dkconfig dk_ios;
+};
+
+/*
+ *	Slice Table Structure
+ */
+
+struct slice {
+	__be32	nblocks;		/* slice size (in blocks) */
+	__be32	blkoff;			/* block offset of slice */
+};
+
+
+int sysv68_partition(struct parsed_partitions *state, struct block_device *bdev)
+{
+	int i, slices;
+	int slot = 1;
+	Sector sect;
+	unsigned char *data;
+	struct dkblk0 *b;
+	struct slice *slice;
+
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
+		return -1;
+
+	b = (struct dkblk0 *)data;
+	if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
+		put_dev_sector(sect);
+		return 0;
+	}
+	slices = be16_to_cpu(b->dk_ios.ios_slccnt);
+	i = be32_to_cpu(b->dk_ios.ios_slcblk);
+	put_dev_sector(sect);
+
+	data = read_dev_sector(bdev, i, &sect);
+	if (!data)
+		return -1;
+
+	slices -= 1; /* last slice is the whole disk */
+	printk("sysV68: %s(s%u)", state->name, slices);
+	slice = (struct slice *)data;
+	for (i = 0; i < slices; i++, slice++) {
+		if (slot == state->limit)
+			break;
+		if (be32_to_cpu(slice->nblocks)) {
+			put_partition(state, slot,
+				be32_to_cpu(slice->blkoff),
+				be32_to_cpu(slice->nblocks));
+			printk("(s%u)", i);
+		}
+		slot++;
+	}
+	printk("\n");
+	put_dev_sector(sect);
+	return 1;
+}
diff --git a/fs/partitions/sysv68.h b/fs/partitions/sysv68.h
new file mode 100644
index 0000000..fa733f6
--- /dev/null
+++ b/fs/partitions/sysv68.h
@@ -0,0 +1 @@
+extern int sysv68_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/pipe.c b/fs/pipe.c
index ebafde7..3a89592 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -841,8 +841,18 @@ static int pipefs_delete_dentry(struct d
 	return 0;
 }
 
+/*
+ * pipefs_dname() is called from d_path().
+ */
+static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+	return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+				dentry->d_inode->i_ino);
+}
+
 static struct dentry_operations pipefs_dentry_operations = {
 	.d_delete	= pipefs_delete_dentry,
+	.d_dname	= pipefs_dname,
 };
 
 static struct inode * get_pipe_inode(void)
@@ -888,8 +898,7 @@ struct file *create_write_pipe(void)
 	struct inode *inode;
 	struct file *f;
 	struct dentry *dentry;
-	char name[32];
-	struct qstr this;
+	struct qstr name = { .name = "" };
 
 	f = get_empty_filp();
 	if (!f)
@@ -899,11 +908,8 @@ struct file *create_write_pipe(void)
 	if (!inode)
 		goto err_file;
 
-	this.len = sprintf(name, "[%lu]", inode->i_ino);
-	this.name = name;
-	this.hash = 0;
 	err = -ENOMEM;
-	dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
+	dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
 	if (!dentry)
 		goto err_inode;
 
diff --git a/fs/pnode.c b/fs/pnode.c
index 56aacea..89940f2 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -59,7 +59,7 @@ static int do_make_slave(struct vfsmount
 	} else {
 		struct list_head *p = &mnt->mnt_slave_list;
 		while (!list_empty(p)) {
-                        slave_mnt = list_entry(p->next,
+                        slave_mnt = list_first_entry(p,
 					struct vfsmount, mnt_slave);
 			list_del_init(&slave_mnt->mnt_slave);
 			slave_mnt->mnt_master = NULL;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 07c9cdb..74f30e0 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -410,9 +410,9 @@ static int do_task_stat(struct task_stru
 	/* convert nsec -> ticks */
 	start_time = nsec_to_clock_t(start_time);
 
-	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n",
 		task->pid,
 		tcomm,
 		state,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 989af5e..3c41149 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -61,9 +61,9 @@ #include <linux/seq_file.h>
 #include <linux/namei.h>
 #include <linux/mnt_namespace.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
+#include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
@@ -90,8 +90,8 @@ #include "internal.h"
 #define PROC_NUMBUF 13
 
 struct pid_entry {
-	int len;
 	char *name;
+	int len;
 	mode_t mode;
 	const struct inode_operations *iop;
 	const struct file_operations *fop;
@@ -99,8 +99,8 @@ struct pid_entry {
 };
 
 #define NOD(NAME, MODE, IOP, FOP, OP) {			\
-	.len  = sizeof(NAME) - 1,			\
 	.name = (NAME),					\
+	.len  = sizeof(NAME) - 1,			\
 	.mode = MODE,					\
 	.iop  = IOP,					\
 	.fop  = FOP,					\
@@ -123,6 +123,9 @@ #define INF(NAME, MODE, OTYPE)				\
 		NULL, &proc_info_file_operations,	\
 		{ .proc_read = &proc_##OTYPE } )
 
+int maps_protect;
+EXPORT_SYMBOL(maps_protect);
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
 	struct fs_struct *fs;
@@ -275,17 +278,15 @@ #ifdef CONFIG_KALLSYMS
  */
 static int proc_pid_wchan(struct task_struct *task, char *buffer)
 {
-	char *modname;
-	const char *sym_name;
-	unsigned long wchan, size, offset;
-	char namebuf[KSYM_NAME_LEN+1];
+	unsigned long wchan;
+	char symname[KSYM_NAME_LEN+1];
 
 	wchan = get_wchan(task);
 
-	sym_name = kallsyms_lookup(wchan, &size, &offset, &modname, namebuf);
-	if (sym_name)
-		return sprintf(buffer, "%s", sym_name);
-	return sprintf(buffer, "%lu", wchan);
+	if (lookup_symbol_name(wchan, symname) < 0)
+		return sprintf(buffer, "%lu", wchan);
+	else
+		return sprintf(buffer, "%s", symname);
 }
 #endif /* CONFIG_KALLSYMS */
 
@@ -310,7 +311,9 @@ static int proc_oom_score(struct task_st
 	struct timespec uptime;
 
 	do_posix_clock_monotonic_gettime(&uptime);
+	read_lock(&tasklist_lock);
 	points = badness(task, uptime.tv_sec);
+	read_unlock(&tasklist_lock);
 	return sprintf(buffer, "%lu\n", points);
 }
 
@@ -344,11 +347,8 @@ static int proc_setattr(struct dentry *d
 		return -EPERM;
 
 	error = inode_change_ok(inode, attr);
-	if (!error) {
-		error = security_inode_setattr(dentry, attr);
-		if (!error)
-			error = inode_setattr(inode, attr);
-	}
+	if (!error)
+		error = inode_setattr(inode, attr);
 	return error;
 }
 
@@ -660,7 +660,6 @@ static ssize_t oom_adjust_read(struct fi
 	char buffer[PROC_NUMBUF];
 	size_t len;
 	int oom_adjust;
-	loff_t __ppos = *ppos;
 
 	if (!task)
 		return -ESRCH;
@@ -668,14 +667,8 @@ static ssize_t oom_adjust_read(struct fi
 	put_task_struct(task);
 
 	len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
-	if (__ppos >= len)
-		return 0;
-	if (count > len-__ppos)
-		count = len-__ppos;
-	if (copy_to_user(buf, buffer + __ppos, count))
-		return -EFAULT;
-	*ppos = __ppos + count;
-	return count;
+
+	return simple_read_from_buffer(buf, count, ppos, buffer, len);
 }
 
 static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
@@ -715,6 +708,40 @@ static const struct file_operations proc
 	.write		= oom_adjust_write,
 };
 
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct task_struct *task;
+	char buffer[PROC_NUMBUF], *end;
+	struct mm_struct *mm;
+
+	memset(buffer, 0, sizeof(buffer));
+	if (count > sizeof(buffer) - 1)
+		count = sizeof(buffer) - 1;
+	if (copy_from_user(buffer, buf, count))
+		return -EFAULT;
+	if (!simple_strtol(buffer, &end, 0))
+		return -EINVAL;
+	if (*end == '\n')
+		end++;
+	task = get_proc_task(file->f_path.dentry->d_inode);
+	if (!task)
+		return -ESRCH;
+	mm = get_task_mm(task);
+	if (mm) {
+		clear_refs_smap(mm);
+		mmput(mm);
+	}
+	put_task_struct(task);
+	if (end - buffer == 0)
+		return -EIO;
+	return end - buffer;
+}
+
+static struct file_operations proc_clear_refs_operations = {
+	.write		= clear_refs_write,
+};
+
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -789,7 +816,6 @@ static ssize_t seccomp_read(struct file 
 {
 	struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
 	char __buf[20];
-	loff_t __ppos = *ppos;
 	size_t len;
 
 	if (!tsk)
@@ -797,14 +823,8 @@ static ssize_t seccomp_read(struct file 
 	/* no need to print the trailing zero, so use only len */
 	len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
 	put_task_struct(tsk);
-	if (__ppos >= len)
-		return 0;
-	if (count > len - __ppos)
-		count = len - __ppos;
-	if (copy_to_user(buf, __buf + __ppos, count))
-		return -EFAULT;
-	*ppos = __ppos + count;
-	return count;
+
+	return simple_read_from_buffer(buf, count, ppos, __buf, len);
 }
 
 static ssize_t seccomp_write(struct file *file, const char __user *buf,
@@ -863,7 +883,6 @@ static ssize_t proc_fault_inject_read(st
 	char buffer[PROC_NUMBUF];
 	size_t len;
 	int make_it_fail;
-	loff_t __ppos = *ppos;
 
 	if (!task)
 		return -ESRCH;
@@ -871,14 +890,8 @@ static ssize_t proc_fault_inject_read(st
 	put_task_struct(task);
 
 	len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
-	if (__ppos >= len)
-		return 0;
-	if (count > len-__ppos)
-		count = len-__ppos;
-	if (copy_to_user(buf, buffer + __ppos, count))
-		return -EFAULT;
-	*ppos = __ppos + count;
-	return count;
+
+	return simple_read_from_buffer(buf, count, ppos, buffer, len);
 }
 
 static ssize_t proc_fault_inject_write(struct file * file,
@@ -941,7 +954,7 @@ static int do_proc_readlink(struct dentr
 
 	if (!tmp)
 		return -ENOMEM;
-		
+
 	inode = dentry->d_inode;
 	path = d_path(dentry, mnt, tmp, PAGE_SIZE);
 	len = PTR_ERR(path);
@@ -1121,7 +1134,8 @@ static struct dentry_operations pid_dent
 
 /* Lookups */
 
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+				struct task_struct *, const void *);
 
 /*
  * Fill a directory entry.
@@ -1137,7 +1151,7 @@ typedef struct dentry *instantiate_t(str
  */
 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)
+	instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
 	struct dentry *child, *dir = filp->f_path.dentry;
 	struct inode *inode;
@@ -1199,7 +1213,10 @@ out:
 	return ~0U;
 }
 
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+#define PROC_FDINFO_MAX 64
+
+static int proc_fd_info(struct inode *inode, struct dentry **dentry,
+			struct vfsmount **mnt, char *info)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct files_struct *files = NULL;
@@ -1218,8 +1235,16 @@ static int proc_fd_link(struct inode *in
 		spin_lock(&files->file_lock);
 		file = fcheck_files(files, fd);
 		if (file) {
-			*mnt = mntget(file->f_path.mnt);
-			*dentry = dget(file->f_path.dentry);
+			if (mnt)
+				*mnt = mntget(file->f_path.mnt);
+			if (dentry)
+				*dentry = dget(file->f_path.dentry);
+			if (info)
+				snprintf(info, PROC_FDINFO_MAX,
+					 "pos:\t%lli\n"
+					 "flags:\t0%o\n",
+					 (long long) file->f_pos,
+					 file->f_flags);
 			spin_unlock(&files->file_lock);
 			put_files_struct(files);
 			return 0;
@@ -1230,6 +1255,12 @@ static int proc_fd_link(struct inode *in
 	return -ENOENT;
 }
 
+static int proc_fd_link(struct inode *inode, struct dentry **dentry,
+			struct vfsmount **mnt)
+{
+	return proc_fd_info(inode, dentry, mnt, NULL);
+}
+
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
 	struct inode *inode = dentry->d_inode;
@@ -1272,9 +1303,9 @@ static struct dentry_operations tid_fd_d
 };
 
 static struct dentry *proc_fd_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, void *ptr)
+	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
-	unsigned fd = *(unsigned *)ptr;
+	unsigned fd = *(const unsigned *)ptr;
 	struct file *file;
 	struct files_struct *files;
  	struct inode *inode;
@@ -1325,7 +1356,9 @@ out_iput:
 	goto out;
 }
 
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_lookupfd_common(struct inode *dir,
+					   struct dentry *dentry,
+					   instantiate_t instantiate)
 {
 	struct task_struct *task = get_proc_task(dir);
 	unsigned fd = name_to_int(dentry);
@@ -1336,23 +1369,15 @@ static struct dentry *proc_lookupfd(stru
 	if (fd == ~0U)
 		goto out;
 
-	result = proc_fd_instantiate(dir, dentry, task, &fd);
+	result = 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)
+static int proc_readfd_common(struct file * filp, void * dirent,
+			      filldir_t filldir, instantiate_t instantiate)
 {
 	struct dentry *dentry = filp->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
@@ -1388,12 +1413,17 @@ static int proc_readfd(struct file * fil
 			for (fd = filp->f_pos-2;
 			     fd < fdt->max_fds;
 			     fd++, filp->f_pos++) {
+				char name[PROC_NUMBUF];
+				int len;
 
 				if (!fcheck_files(files, fd))
 					continue;
 				rcu_read_unlock();
 
-				if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
+				len = snprintf(name, sizeof(name), "%d", fd);
+				if (proc_fill_cache(filp, dirent, filldir,
+						    name, len, instantiate,
+						    p, &fd) < 0) {
 					rcu_read_lock();
 					break;
 				}
@@ -1408,23 +1438,119 @@ out_no_task:
 	return retval;
 }
 
+static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
+				    struct nameidata *nd)
+{
+	return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
+}
+
+static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
+{
+	return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
+}
+
+static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
+				      size_t len, loff_t *ppos)
+{
+	char tmp[PROC_FDINFO_MAX];
+	int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, NULL, tmp);
+	if (!err)
+		err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
+	return err;
+}
+
+static const struct file_operations proc_fdinfo_file_operations = {
+	.open		= nonseekable_open,
+	.read		= proc_fdinfo_read,
+};
+
 static const struct file_operations proc_fd_operations = {
 	.read		= generic_read_dir,
 	.readdir	= proc_readfd,
 };
 
 /*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+static int proc_fd_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	int rv;
+
+	rv = generic_permission(inode, mask, NULL);
+	if (rv == 0)
+		return 0;
+	if (task_pid(current) == proc_pid(inode))
+		rv = 0;
+	return rv;
+}
+
+/*
  * proc directories can do almost nothing..
  */
 static const struct inode_operations proc_fd_inode_operations = {
 	.lookup		= proc_lookupfd,
+	.permission	= proc_fd_permission,
 	.setattr	= proc_setattr,
 };
 
+static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
+	struct dentry *dentry, struct task_struct *task, const void *ptr)
+{
+	unsigned fd = *(unsigned *)ptr;
+ 	struct inode *inode;
+ 	struct proc_inode *ei;
+	struct dentry *error = ERR_PTR(-ENOENT);
+
+	inode = proc_pid_make_inode(dir->i_sb, task);
+	if (!inode)
+		goto out;
+	ei = PROC_I(inode);
+	ei->fd = fd;
+	inode->i_mode = S_IFREG | S_IRUSR;
+	inode->i_fop = &proc_fdinfo_file_operations;
+	dentry->d_op = &tid_fd_dentry_operations;
+	d_add(dentry, inode);
+	/* Close the race of the process dying before we return the dentry */
+	if (tid_fd_revalidate(dentry, NULL))
+		error = NULL;
+
+ out:
+	return error;
+}
+
+static struct dentry *proc_lookupfdinfo(struct inode *dir,
+					struct dentry *dentry,
+					struct nameidata *nd)
+{
+	return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
+}
+
+static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+{
+	return proc_readfd_common(filp, dirent, filldir,
+				  proc_fdinfo_instantiate);
+}
+
+static const struct file_operations proc_fdinfo_operations = {
+	.read		= generic_read_dir,
+	.readdir	= proc_readfdinfo,
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+static const struct inode_operations proc_fdinfo_inode_operations = {
+	.lookup		= proc_lookupfdinfo,
+	.setattr	= proc_setattr,
+};
+
+
 static struct dentry *proc_pident_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, void *ptr)
+	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
-	struct pid_entry *p = ptr;
+	const struct pid_entry *p = ptr;
 	struct inode *inode;
 	struct proc_inode *ei;
 	struct dentry *error = ERR_PTR(-EINVAL);
@@ -1453,13 +1579,13 @@ out:
 
 static struct dentry *proc_pident_lookup(struct inode *dir, 
 					 struct dentry *dentry,
-					 struct pid_entry *ents,
+					 const 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;
+	const struct pid_entry *p, *last;
 
 	error = ERR_PTR(-ENOENT);
 	inode = NULL;
@@ -1488,8 +1614,8 @@ 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)
+static int proc_pident_fill_cache(struct file *filp, void *dirent,
+	filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
 {
 	return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
 				proc_pident_instantiate, task, p);
@@ -1497,14 +1623,14 @@ static int proc_pident_fill_cache(struct
 
 static int proc_pident_readdir(struct file *filp,
 		void *dirent, filldir_t filldir,
-		struct pid_entry *ents, unsigned int nents)
+		const struct pid_entry *ents, unsigned int nents)
 {
 	int i;
 	int pid;
 	struct dentry *dentry = filp->f_path.dentry;
 	struct inode *inode = dentry->d_inode;
 	struct task_struct *task = get_proc_task(inode);
-	struct pid_entry *p, *last;
+	const struct pid_entry *p, *last;
 	ino_t ino;
 	int ret;
 
@@ -1619,7 +1745,7 @@ static const struct file_operations proc
 	.write		= proc_pid_attr_write,
 };
 
-static struct pid_entry attr_dir_stuff[] = {
+static const 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),
@@ -1685,7 +1811,7 @@ static const struct inode_operations pro
  * that properly belong to the /proc filesystem, as they describe
  * describe something that is process related.
  */
-static struct pid_entry proc_base_stuff[] = {
+static const struct pid_entry proc_base_stuff[] = {
 	NOD("self", S_IFLNK|S_IRWXUGO,
 		&proc_self_inode_operations, NULL, {}),
 };
@@ -1714,9 +1840,9 @@ static struct dentry_operations proc_bas
 };
 
 static struct dentry *proc_base_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, void *ptr)
+	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
-	struct pid_entry *p = ptr;
+	const struct pid_entry *p = ptr;
 	struct inode *inode;
 	struct proc_inode *ei;
 	struct dentry *error = ERR_PTR(-EINVAL);
@@ -1764,7 +1890,7 @@ static struct dentry *proc_base_lookup(s
 {
 	struct dentry *error;
 	struct task_struct *task = get_proc_task(dir);
-	struct pid_entry *p, *last;
+	const struct pid_entry *p, *last;
 
 	error = ERR_PTR(-ENOENT);
 
@@ -1790,8 +1916,8 @@ 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)
+static int proc_base_fill_cache(struct file *filp, void *dirent,
+	filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
 {
 	return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
 				proc_base_instantiate, task, p);
@@ -1828,9 +1954,10 @@ #endif
 static const struct file_operations proc_task_operations;
 static const struct inode_operations proc_task_inode_operations;
 
-static struct pid_entry tgid_base_stuff[] = {
+static const struct pid_entry tgid_base_stuff[] = {
 	DIR("task",       S_IRUGO|S_IXUGO, task),
 	DIR("fd",         S_IRUSR|S_IXUSR, fd),
+	DIR("fdinfo",     S_IRUSR|S_IXUSR, fdinfo),
 	INF("environ",    S_IRUSR, pid_environ),
 	INF("auxv",       S_IRUSR, pid_auxv),
 	INF("status",     S_IRUGO, pid_status),
@@ -1851,6 +1978,7 @@ #endif
 	REG("mounts",     S_IRUGO, mounts),
 	REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_MMU
+	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",      S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
@@ -1970,7 +2098,7 @@ out:
 
 static struct dentry *proc_pid_instantiate(struct inode *dir,
 					   struct dentry * dentry,
-					   struct task_struct *task, void *ptr)
+					   struct task_struct *task, const void *ptr)
 {
 	struct dentry *error = ERR_PTR(-ENOENT);
 	struct inode *inode;
@@ -1983,7 +2111,7 @@ static struct dentry *proc_pid_instantia
 	inode->i_op = &proc_tgid_base_inode_operations;
 	inode->i_fop = &proc_tgid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
-	inode->i_nlink = 4;
+	inode->i_nlink = 5;
 #ifdef CONFIG_SECURITY
 	inode->i_nlink += 1;
 #endif
@@ -2085,7 +2213,7 @@ int proc_pid_readdir(struct file * filp,
 		goto out_no_task;
 
 	for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
-		struct pid_entry *p = &proc_base_stuff[nr];
+		const struct pid_entry *p = &proc_base_stuff[nr];
 		if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
 			goto out;
 	}
@@ -2111,8 +2239,9 @@ out_no_task:
 /*
  * Tasks
  */
-static struct pid_entry tid_base_stuff[] = {
+static const struct pid_entry tid_base_stuff[] = {
 	DIR("fd",        S_IRUSR|S_IXUSR, fd),
+	DIR("fdinfo",    S_IRUSR|S_IXUSR, fdinfo),
 	INF("environ",   S_IRUSR, pid_environ),
 	INF("auxv",      S_IRUSR, pid_auxv),
 	INF("status",    S_IRUGO, pid_status),
@@ -2132,6 +2261,7 @@ #endif
 	LNK("exe",       exe),
 	REG("mounts",    S_IRUGO, mounts),
 #ifdef CONFIG_MMU
+	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",     S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
@@ -2180,7 +2310,7 @@ static const struct inode_operations pro
 };
 
 static struct dentry *proc_task_instantiate(struct inode *dir,
-	struct dentry *dentry, struct task_struct *task, void *ptr)
+	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
 	struct dentry *error = ERR_PTR(-ENOENT);
 	struct inode *inode;
@@ -2192,7 +2322,7 @@ static struct dentry *proc_task_instanti
 	inode->i_op = &proc_tid_base_inode_operations;
 	inode->i_fop = &proc_tid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
-	inode->i_nlink = 3;
+	inode->i_nlink = 4;
 #ifdef CONFIG_SECURITY
 	inode->i_nlink += 1;
 #endif
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 775fb21..8a40e15 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -398,6 +398,7 @@ struct dentry *proc_lookup(struct inode 
 			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
 				unsigned int ino = de->low_ino;
 
+				de_get(de);
 				spin_unlock(&proc_subdir_lock);
 				error = -EINVAL;
 				inode = proc_get_inode(dir->i_sb, ino, de);
@@ -414,6 +415,7 @@ struct dentry *proc_lookup(struct inode 
 		d_add(dentry, inode);
 		return NULL;
 	}
+	de_put(de);
 	return ERR_PTR(error);
 }
 
@@ -476,14 +478,21 @@ int proc_readdir(struct file * filp,
 			}
 
 			do {
+				struct proc_dir_entry *next;
+
 				/* filldir passes info to user space */
+				de_get(de);
 				spin_unlock(&proc_subdir_lock);
 				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
-					    de->low_ino, de->mode >> 12) < 0)
+					    de->low_ino, de->mode >> 12) < 0) {
+					de_put(de);
 					goto out;
+				}
 				spin_lock(&proc_subdir_lock);
 				filp->f_pos++;
-				de = de->next;
+				next = de->next;
+				de_put(de);
+				de = next;
 			} while (de);
 			spin_unlock(&proc_subdir_lock);
 	}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index c372eb1..b817190 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -21,7 +21,7 @@ #include <asm/uaccess.h>
 
 #include "internal.h"
 
-static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
+struct proc_dir_entry *de_get(struct proc_dir_entry *de)
 {
 	if (de)
 		atomic_inc(&de->count);
@@ -31,7 +31,7 @@ static inline struct proc_dir_entry * de
 /*
  * Decrements the use count and checks for deferred deletion.
  */
-static void de_put(struct proc_dir_entry *de)
+void de_put(struct proc_dir_entry *de)
 {
 	if (de) {	
 		lock_kernel();		
@@ -109,8 +109,7 @@ static void init_once(void * foo, struct
 {
 	struct proc_inode *ei = (struct proc_inode *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
@@ -147,13 +146,6 @@ struct inode *proc_get_inode(struct supe
 {
 	struct inode * inode;
 
-	/*
-	 * Increment the use count so the dir entry can't disappear.
-	 */
-	de_get(de);
-
-	WARN_ON(de && de->deleted);
-
 	if (de != NULL && !try_module_get(de->owner))
 		goto out_mod;
 
@@ -185,7 +177,6 @@ out_ino:
 	if (de != NULL)
 		module_put(de->owner);
 out_mod:
-	de_put(de);
 	return NULL;
 }			
 
@@ -200,6 +191,7 @@ int proc_fill_super(struct super_block *
 	s->s_op = &proc_sops;
 	s->s_time_gran = 1;
 	
+	de_get(&proc_root);
 	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
 	if (!root_inode)
 		goto out_no_root;
@@ -213,6 +205,7 @@ int proc_fill_super(struct super_block *
 out_no_root:
 	printk("proc_read_super: get root inode failed\n");
 	iput(root_inode);
+	de_put(&proc_root);
 	return -ENOMEM;
 }
 MODULE_LICENSE("GPL");
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index f771889..b215c35 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -37,6 +37,8 @@ do {						\
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
+extern int maps_protect;
+
 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index abdf068..eca471b 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -38,7 +38,7 @@ static int property_read_proc(char *page
 		n = count;
 	else
 		*eof = 1;
-	memcpy(page, pp->value + off, n);
+	memcpy(page, (char *)pp->value + off, n);
 	*start = page;
 	return n;
 }
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index e2c4c0a..5fd49e4 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -35,7 +35,6 @@ #include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/times.h>
 #include <linux/profile.h>
@@ -398,8 +397,6 @@ static const struct file_operations proc
 #endif
 
 #ifdef CONFIG_SLAB
-extern struct seq_operations slabinfo_op;
-extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
 static int slabinfo_open(struct inode *inode, struct file *file)
 {
 	return seq_open(file, &slabinfo_op);
@@ -431,18 +428,11 @@ static int slabstats_open(struct inode *
 	return ret;
 }
 
-static int slabstats_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *m = file->private_data;
-	kfree(m->private);
-	return seq_release(inode, file);
-}
-
 static const struct file_operations proc_slabstats_operations = {
 	.open		= slabstats_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= slabstats_release,
+	.release	= seq_release_private,
 };
 #endif
 #endif
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 20e8cbb..680c429 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -429,11 +429,8 @@ static int proc_sys_setattr(struct dentr
 		return -EPERM;
 
 	error = inode_change_ok(inode, attr);
-	if (!error) {
-		error = security_inode_setattr(dentry, attr);
-		if (!error)
-			error = inode_setattr(inode, attr);
-	}
+	if (!error)
+		error = inode_setattr(inode, attr);
 
 	return error;
 }
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index c1bbfbe..b3a473b 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -108,6 +108,8 @@ static void *t_start(struct seq_file *m,
 {
 	struct list_head *p;
 	loff_t l = *pos;
+
+	mutex_lock(&tty_mutex);
 	list_for_each(p, &tty_drivers)
 		if (!l--)
 			return list_entry(p, struct tty_driver, tty_drivers);
@@ -124,6 +126,7 @@ static void *t_next(struct seq_file *m, 
 
 static void t_stop(struct seq_file *m, void *v)
 {
+	mutex_unlock(&tty_mutex);
 }
 
 static struct seq_operations tty_drivers_op = {
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7445980..c24d81a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -3,6 +3,7 @@ #include <linux/hugetlb.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/highmem.h>
+#include <linux/ptrace.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
 
@@ -120,6 +121,14 @@ struct mem_size_stats
 	unsigned long shared_dirty;
 	unsigned long private_clean;
 	unsigned long private_dirty;
+	unsigned long referenced;
+};
+
+struct pmd_walker {
+	struct vm_area_struct *vma;
+	void *private;
+	void (*action)(struct vm_area_struct *, pmd_t *, unsigned long,
+		       unsigned long, void *);
 };
 
 static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
@@ -134,6 +143,9 @@ static int show_map_internal(struct seq_
 	dev_t dev = 0;
 	int len;
 
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -181,18 +193,20 @@ static int show_map_internal(struct seq_
 
 	if (mss)
 		seq_printf(m,
-			   "Size:          %8lu kB\n"
-			   "Rss:           %8lu kB\n"
-			   "Shared_Clean:  %8lu kB\n"
-			   "Shared_Dirty:  %8lu kB\n"
-			   "Private_Clean: %8lu kB\n"
-			   "Private_Dirty: %8lu kB\n",
+			   "Size:           %8lu kB\n"
+			   "Rss:            %8lu kB\n"
+			   "Shared_Clean:   %8lu kB\n"
+			   "Shared_Dirty:   %8lu kB\n"
+			   "Private_Clean:  %8lu kB\n"
+			   "Private_Dirty:  %8lu kB\n"
+			   "Referenced:     %8lu kB\n",
 			   (vma->vm_end - vma->vm_start) >> 10,
 			   mss->resident >> 10,
 			   mss->shared_clean  >> 10,
 			   mss->shared_dirty  >> 10,
 			   mss->private_clean >> 10,
-			   mss->private_dirty >> 10);
+			   mss->private_dirty >> 10,
+			   mss->referenced >> 10);
 
 	if (m->count < m->size)  /* vma is copied successfully */
 		m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
@@ -205,15 +219,16 @@ static int show_map(struct seq_file *m, 
 }
 
 static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
-				unsigned long addr, unsigned long end,
-				struct mem_size_stats *mss)
+			    unsigned long addr, unsigned long end,
+			    void *private)
 {
+	struct mem_size_stats *mss = private;
 	pte_t *pte, ptent;
 	spinlock_t *ptl;
 	struct page *page;
 
 	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-	do {
+	for (; addr != end; pte++, addr += PAGE_SIZE) {
 		ptent = *pte;
 		if (!pte_present(ptent))
 			continue;
@@ -224,6 +239,9 @@ static void smaps_pte_range(struct vm_ar
 		if (!page)
 			continue;
 
+		/* Accumulate the size in pages that have been accessed. */
+		if (pte_young(ptent) || PageReferenced(page))
+			mss->referenced += PAGE_SIZE;
 		if (page_mapcount(page) >= 2) {
 			if (pte_dirty(ptent))
 				mss->shared_dirty += PAGE_SIZE;
@@ -235,57 +253,99 @@ static void smaps_pte_range(struct vm_ar
 			else
 				mss->private_clean += PAGE_SIZE;
 		}
-	} while (pte++, addr += PAGE_SIZE, addr != end);
+	}
 	pte_unmap_unlock(pte - 1, ptl);
 	cond_resched();
 }
 
-static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud,
-				unsigned long addr, unsigned long end,
-				struct mem_size_stats *mss)
+static void clear_refs_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+				 unsigned long addr, unsigned long end,
+				 void *private)
+{
+	pte_t *pte, ptent;
+	spinlock_t *ptl;
+	struct page *page;
+
+	pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+	for (; addr != end; pte++, addr += PAGE_SIZE) {
+		ptent = *pte;
+		if (!pte_present(ptent))
+			continue;
+
+		page = vm_normal_page(vma, addr, ptent);
+		if (!page)
+			continue;
+
+		/* Clear accessed and referenced bits. */
+		ptep_test_and_clear_young(vma, addr, pte);
+		ClearPageReferenced(page);
+	}
+	pte_unmap_unlock(pte - 1, ptl);
+	cond_resched();
+}
+
+static inline void walk_pmd_range(struct pmd_walker *walker, pud_t *pud,
+				  unsigned long addr, unsigned long end)
 {
 	pmd_t *pmd;
 	unsigned long next;
 
-	pmd = pmd_offset(pud, addr);
-	do {
+	for (pmd = pmd_offset(pud, addr); addr != end;
+	     pmd++, addr = next) {
 		next = pmd_addr_end(addr, end);
 		if (pmd_none_or_clear_bad(pmd))
 			continue;
-		smaps_pte_range(vma, pmd, addr, next, mss);
-	} while (pmd++, addr = next, addr != end);
+		walker->action(walker->vma, pmd, addr, next, walker->private);
+	}
 }
 
-static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
-				unsigned long addr, unsigned long end,
-				struct mem_size_stats *mss)
+static inline void walk_pud_range(struct pmd_walker *walker, pgd_t *pgd,
+				  unsigned long addr, unsigned long end)
 {
 	pud_t *pud;
 	unsigned long next;
 
-	pud = pud_offset(pgd, addr);
-	do {
+	for (pud = pud_offset(pgd, addr); addr != end;
+	     pud++, addr = next) {
 		next = pud_addr_end(addr, end);
 		if (pud_none_or_clear_bad(pud))
 			continue;
-		smaps_pmd_range(vma, pud, addr, next, mss);
-	} while (pud++, addr = next, addr != end);
+		walk_pmd_range(walker, pud, addr, next);
+	}
 }
 
-static inline void smaps_pgd_range(struct vm_area_struct *vma,
-				unsigned long addr, unsigned long end,
-				struct mem_size_stats *mss)
+/*
+ * walk_page_range - walk the page tables of a VMA with a callback
+ * @vma - VMA to walk
+ * @action - callback invoked for every bottom-level (PTE) page table
+ * @private - private data passed to the callback function
+ *
+ * Recursively walk the page table for the memory area in a VMA, calling
+ * a callback for every bottom-level (PTE) page table.
+ */
+static inline void walk_page_range(struct vm_area_struct *vma,
+				   void (*action)(struct vm_area_struct *,
+						  pmd_t *, unsigned long,
+						  unsigned long, void *),
+				   void *private)
 {
+	unsigned long addr = vma->vm_start;
+	unsigned long end = vma->vm_end;
+	struct pmd_walker walker = {
+		.vma		= vma,
+		.private	= private,
+		.action		= action,
+	};
 	pgd_t *pgd;
 	unsigned long next;
 
-	pgd = pgd_offset(vma->vm_mm, addr);
-	do {
+	for (pgd = pgd_offset(vma->vm_mm, addr); addr != end;
+	     pgd++, addr = next) {
 		next = pgd_addr_end(addr, end);
 		if (pgd_none_or_clear_bad(pgd))
 			continue;
-		smaps_pud_range(vma, pgd, addr, next, mss);
-	} while (pgd++, addr = next, addr != end);
+		walk_pud_range(&walker, pgd, addr, next);
+	}
 }
 
 static int show_smap(struct seq_file *m, void *v)
@@ -295,10 +355,22 @@ static int show_smap(struct seq_file *m,
 
 	memset(&mss, 0, sizeof mss);
 	if (vma->vm_mm && !is_vm_hugetlb_page(vma))
-		smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
+		walk_page_range(vma, smaps_pte_range, &mss);
 	return show_map_internal(m, v, &mss);
 }
 
+void clear_refs_smap(struct mm_struct *mm)
+{
+	struct vm_area_struct *vma;
+
+	down_read(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next)
+		if (vma->vm_mm && !is_vm_hugetlb_page(vma))
+			walk_page_range(vma, clear_refs_pte_range, NULL);
+	flush_tlb_mm(mm);
+	up_read(&mm->mmap_sem);
+}
+
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
 	struct proc_maps_private *priv = m->private;
@@ -444,11 +516,22 @@ const struct file_operations proc_maps_o
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 7cddf6b..d8b8c71 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -2,6 +2,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/mount.h>
+#include <linux/ptrace.h>
 #include <linux/seq_file.h>
 #include "internal.h"
 
@@ -143,6 +144,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	return nommu_vma_show(m, vml->vma);
 }
 
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index d960507..523e109 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -514,7 +514,7 @@ static int __init parse_crash_elf64_head
 	/* Do some basic Verification. */
 	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
 		(ehdr.e_type != ET_CORE) ||
-		!elf_check_arch(&ehdr) ||
+		!vmcore_elf_check_arch(&ehdr) ||
 		ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
 		ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
 		ehdr.e_version != EV_CURRENT ||
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 83bc8e7..75fc849 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -536,8 +536,7 @@ static void init_once(void *foo, struct 
 {
 	struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
 
diff --git a/fs/quota.c b/fs/quota.c
index b9dae76..e9d88fd 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -11,7 +11,6 @@ #include <linux/slab.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h>
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index d3fd7c6..3b481d5 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -16,7 +16,6 @@ #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
 #include <linux/quotaops.h>
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index ff1f763..4ace5d7 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -30,7 +30,6 @@ #include <linux/highmem.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
 
diff --git a/fs/read_write.c b/fs/read_write.c
index 1f8dc37..4d03008 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -37,10 +37,10 @@ loff_t generic_file_llseek(struct file *
 
 	mutex_lock(&inode->i_mutex);
 	switch (origin) {
-		case 2:
+		case SEEK_END:
 			offset += inode->i_size;
 			break;
-		case 1:
+		case SEEK_CUR:
 			offset += file->f_pos;
 	}
 	retval = -EINVAL;
@@ -63,10 +63,10 @@ loff_t remote_llseek(struct file *file, 
 
 	lock_kernel();
 	switch (origin) {
-		case 2:
+		case SEEK_END:
 			offset += i_size_read(file->f_path.dentry->d_inode);
 			break;
-		case 1:
+		case SEEK_CUR:
 			offset += file->f_pos;
 	}
 	retval = -EINVAL;
@@ -94,10 +94,10 @@ loff_t default_llseek(struct file *file,
 
 	lock_kernel();
 	switch (origin) {
-		case 2:
+		case SEEK_END:
 			offset += i_size_read(file->f_path.dentry->d_inode);
 			break;
-		case 1:
+		case SEEK_CUR:
 			offset += file->f_pos;
 	}
 	retval = -EINVAL;
@@ -139,7 +139,7 @@ asmlinkage off_t sys_lseek(unsigned int 
 		goto bad;
 
 	retval = -EINVAL;
-	if (origin <= 2) {
+	if (origin <= SEEK_MAX) {
 		loff_t res = vfs_llseek(file, offset, origin);
 		retval = res;
 		if (res != (loff_t)retval)
@@ -166,7 +166,7 @@ asmlinkage long sys_llseek(unsigned int 
 		goto bad;
 
 	retval = -EINVAL;
-	if (origin > 2)
+	if (origin > SEEK_MAX)
 		goto out_putf;
 
 	offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
diff --git a/fs/readdir.c b/fs/readdir.c
index f39f5b3..efe52e6 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -4,13 +4,13 @@
  *  Copyright (C) 1995  Linus Torvalds
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/file.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/dirent.h>
 #include <linux/security.h>
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(vfs_readdir);
  * case (the low-level handlers don't need to care about this).
  */
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
 
 #ifdef __ARCH_WANT_OLD_READDIR
 
@@ -147,7 +146,7 @@ static int filldir(void * __buf, const c
 	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);
+	int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(long));
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
@@ -220,8 +219,6 @@ out:
 	return error;
 }
 
-#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
-
 struct getdents_callback64 {
 	struct linux_dirent64 __user * current_dir;
 	struct linux_dirent64 __user * previous;
@@ -234,7 +231,7 @@ static int filldir64(void * __buf, const
 {
 	struct linux_dirent64 __user *dirent;
 	struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
-	int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
+	int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(u64));
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 96a2f88..9c23fee 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -7,7 +7,6 @@ #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/stat.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <asm/uaccess.h>
 
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index abfada2..ab45db5 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -6,7 +6,6 @@ #include <linux/time.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 7280a23..e073fd8 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2918,7 +2918,7 @@ static void queue_log_writer(struct supe
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
 		schedule();
-	current->state = TASK_RUNNING;
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&journal->j_join_wait, &wait);
 }
 
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index a216184..b378eea 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -16,7 +16,6 @@ #include <linux/bitops.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
 #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; }
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index ecc9943..9aa7a06 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -16,11 +16,10 @@ #include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_fs_sb.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
-#if defined( REISERFS_PROC_INFO )
+#ifdef CONFIG_REISERFS_PROC_INFO
 
 /*
  * LOCKING:
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 3156847..976cc78 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -131,6 +131,10 @@ int reiserfs_resize(struct super_block *
 			/* don't use read_bitmap_block since it will cache
 			 * the uninitialized bitmap */
 			bh = sb_bread(s, i * s->s_blocksize * 8);
+			if (!bh) {
+				vfree(bitmap);
+				return -EIO;
+			}
 			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);
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index afb21ea..b6f1259 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -53,7 +53,6 @@ #include <linux/time.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/reiserfs_fs.h>
-#include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/quotaops.h>
 
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index f13a7f1..c776214 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -18,7 +18,6 @@ #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_acl.h>
 #include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
@@ -433,12 +432,13 @@ int remove_save_link(struct inode *inode
 static void reiserfs_kill_sb(struct super_block *s)
 {
 	if (REISERFS_SB(s)) {
+#ifdef CONFIG_REISERFS_FS_XATTR
 		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;
 		}
-
+#endif
 		if (REISERFS_SB(s)->priv_root) {
 			d_invalidate(REISERFS_SB(s)->priv_root);
 			dput(REISERFS_SB(s)->priv_root);
@@ -511,8 +511,7 @@ static void init_once(void *foo, struct 
 {
 	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&ei->i_prealloc_list);
 		inode_init_once(&ei->vfs_inode);
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
@@ -1563,9 +1562,10 @@ static int reiserfs_fill_super(struct su
 	REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
 	/* Preallocate by 16 blocks (17-1) at once */
 	REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
+#ifdef CONFIG_REISERFS_FS_XATTR
 	/* Initialize the rwsem for xattr dir */
 	init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
-
+#endif
 	/* setup default block allocator options */
 	reiserfs_init_alloc_options(s);
 
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index c8178b7..bf6e582 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -68,7 +68,7 @@ static struct dentry *get_xa_root(struct
 	if (!privroot)
 		return ERR_PTR(-ENODATA);
 
-	mutex_lock(&privroot->d_inode->i_mutex);
+	mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);
 	if (REISERFS_SB(sb)->xattr_root) {
 		xaroot = dget(REISERFS_SB(sb)->xattr_root);
 		goto out;
@@ -410,11 +410,7 @@ static struct page *reiserfs_get_page(st
 	mapping_set_gfp_mask(mapping, GFP_NOFS);
 	page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
-		if (!PageUptodate(page))
-			goto fail;
-
 		if (PageError(page))
 			goto fail;
 	}
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index fd60101..8042851 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -570,8 +570,7 @@ static void init_once(void * foo, struct
 {
 	struct romfs_inode_info *ei = (struct romfs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/select.c b/fs/select.c
index fe0893a..d862241 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -14,10 +14,10 @@
  *     of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian).
  */
 
+#include <linux/kernel.h>
 #include <linux/syscalls.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
@@ -26,7 +26,6 @@ #include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
 
 struct poll_table_page {
@@ -399,7 +398,7 @@ asmlinkage long sys_select(int n, fd_set
 		if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
+			timeout = DIV_ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
 			timeout += tv.tv_sec * HZ;
 		}
 	}
@@ -454,7 +453,7 @@ asmlinkage long sys_pselect7(int n, fd_s
 		if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
+			timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
 			timeout += ts.tv_sec * HZ;
 		}
 	}
@@ -776,7 +775,7 @@ asmlinkage long sys_ppoll(struct pollfd 
 		if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
 			timeout = -1;	/* infinite */
 		else {
-			timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
+			timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
 			timeout += ts.tv_sec * HZ;
 		}
 	}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 5faba4f..424a3dd 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -69,9 +69,8 @@ static void smb_destroy_inode(struct ino
 static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
 {
 	struct smb_inode_info *ei = (struct smb_inode_info *) foo;
-	unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR;
 
-	if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index 723f7c6..c288fbe 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -6,6 +6,7 @@
  *  Please add a note about your changes to smbfs in the ChangeLog file.
  */
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
@@ -22,8 +23,6 @@ #include "proto.h"
 /* #define SMB_SLAB_DEBUG	(SLAB_RED_ZONE | SLAB_POISON) */
 #define SMB_SLAB_DEBUG	0
 
-#define ROUND_UP(x) (((x)+3) & ~3)
-
 /* cache for request structures */
 static struct kmem_cache *req_cachep;
 
@@ -200,8 +199,8 @@ static int smb_setup_trans2request(struc
 
 	const int smb_parameters = 15;
 	const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2;
-	const int oparam = ROUND_UP(header + 3);
-	const int odata  = ROUND_UP(oparam + req->rq_lparm);
+	const int oparam = ALIGN(header + 3, sizeof(u32));
+	const int odata  = ALIGN(oparam + req->rq_lparm, sizeof(u32));
 	const int bcc = (req->rq_data ? odata + req->rq_ldata :
 					oparam + req->rq_lparm) - header;
 
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index 89eaf31..67176af 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -16,7 +16,6 @@ #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/dcache.h>
-#include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/kthread.h>
@@ -299,8 +298,6 @@ out:
  */
 static int smbiod(void *unused)
 {
-	allow_signal(SIGKILL);
-
 	VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
 
 	for (;;) {
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 92ea6b2..e48bd82 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -17,7 +17,6 @@ #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
 #include <linux/netdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/workqueue.h>
 #include <net/scm.h>
 #include <net/tcp_states.h>
diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c
index fea20ce..00b2909 100644
--- a/fs/smbfs/symlink.c
+++ b/fs/smbfs/symlink.c
@@ -13,7 +13,6 @@ #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/net.h>
 #include <linux/namei.h>
 
diff --git a/fs/splice.c b/fs/splice.c
index 5428b0f..12f2828 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -289,12 +289,10 @@ __generic_file_splice_read(struct file *
 		nr_pages = PIPE_BUFFERS;
 
 	/*
-	 * Initiate read-ahead on this page range. however, don't call into
-	 * read-ahead if this is a non-zero offset (we are likely doing small
-	 * chunk splice and the page is already there) for a single page.
+	 * Don't try to 2nd guess the read-ahead logic, call into
+	 * page_cache_readahead() like the page cache reads would do.
 	 */
-	if (!loff || nr_pages > 1)
-		page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
+	page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
 
 	/*
 	 * Now fill in the holes:
@@ -378,10 +376,11 @@ __generic_file_splice_read(struct file *
 			 * If in nonblock mode then dont block on waiting
 			 * for an in-flight io page
 			 */
-			if (flags & SPLICE_F_NONBLOCK)
-				break;
-
-			lock_page(page);
+			if (flags & SPLICE_F_NONBLOCK) {
+				if (TestSetPageLocked(page))
+					break;
+			} else
+				lock_page(page);
 
 			/*
 			 * page was truncated, stop here. if this isn't the
diff --git a/fs/stat.c b/fs/stat.c
index 38a8cb2..6851006 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -8,7 +8,6 @@ #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/file.h>
-#include <linux/smp_lock.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
diff --git a/fs/super.c b/fs/super.c
index 60b1e50..5260d62 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -107,6 +107,7 @@ out:
 static inline void destroy_super(struct super_block *s)
 {
 	security_sb_free(s);
+	kfree(s->s_subtype);
 	kfree(s);
 }
 
@@ -725,16 +726,6 @@ static int test_bdev_super(struct super_
 	return (void *)s->s_bdev == data;
 }
 
-static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
-{
-	if (bdev->bd_disk) {
-		if (bdev->bd_part)
-			kobject_uevent(&bdev->bd_part->kobj, action);
-		else
-			kobject_uevent(&bdev->bd_disk->kobj, action);
-	}
-}
-
 int get_sb_bdev(struct file_system_type *fs_type,
 	int flags, const char *dev_name, void *data,
 	int (*fill_super)(struct super_block *, void *, int),
@@ -782,7 +773,6 @@ int get_sb_bdev(struct file_system_type 
 		}
 
 		s->s_flags |= MS_ACTIVE;
-		bdev_uevent(bdev, KOBJ_MOUNT);
 	}
 
 	return simple_set_mnt(mnt, s);
@@ -801,7 +791,6 @@ void kill_block_super(struct super_block
 {
 	struct block_device *bdev = sb->s_bdev;
 
-	bdev_uevent(bdev, KOBJ_UMOUNT);
 	generic_shutdown_super(sb);
 	sync_blockdev(bdev);
 	close_bdev_excl(bdev);
@@ -919,6 +908,29 @@ out:
 
 EXPORT_SYMBOL_GPL(vfs_kern_mount);
 
+static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
+{
+	int err;
+	const char *subtype = strchr(fstype, '.');
+	if (subtype) {
+		subtype++;
+		err = -EINVAL;
+		if (!subtype[0])
+			goto err;
+	} else
+		subtype = "";
+
+	mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
+	err = -ENOMEM;
+	if (!mnt->mnt_sb->s_subtype)
+		goto err;
+	return mnt;
+
+ err:
+	mntput(mnt);
+	return ERR_PTR(err);
+}
+
 struct vfsmount *
 do_kern_mount(const char *fstype, int flags, const char *name, void *data)
 {
@@ -927,6 +939,9 @@ do_kern_mount(const char *fstype, int fl
 	if (!type)
 		return ERR_PTR(-ENODEV);
 	mnt = vfs_kern_mount(type, flags, name, data);
+	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
+	    !mnt->mnt_sb->s_subtype)
+		mnt = fs_set_subtype(mnt, fstype);
 	put_filesystem(type);
 	return mnt;
 }
diff --git a/fs/sync.c b/fs/sync.c
index d0feff6..2f97576 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -229,7 +229,7 @@ asmlinkage long sys_sync_file_range(int 
 			!S_ISLNK(i_mode))
 		goto out_put;
 
-	ret = do_sync_file_range(file, offset, endbyte, flags);
+	ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
 out_put:
 	fput_light(file, fput_needed);
 out:
@@ -239,13 +239,11 @@ out:
 /*
  * `endbyte' is inclusive
  */
-int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte,
-			unsigned int flags)
+int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
+			  loff_t endbyte, unsigned int flags)
 {
 	int ret;
-	struct address_space *mapping;
 
-	mapping = file->f_mapping;
 	if (!mapping) {
 		ret = -EINVAL;
 		goto out;
@@ -275,4 +273,4 @@ int do_sync_file_range(struct file *file
 out:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(do_sync_file_range);
+EXPORT_SYMBOL_GPL(do_sync_mapping_range);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index fc46333..0e637ad 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -13,8 +13,7 @@ #include <asm/semaphore.h>
 
 #include "sysfs.h"
 
-#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
-#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
+#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
 
 /*
  * Subsystem file operations.
@@ -24,12 +23,12 @@ #define to_sattr(a) container_of(a,struc
 static ssize_t 
 subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
 {
-	struct subsystem * s = to_subsys(kobj);
+	struct kset *kset = to_kset(kobj);
 	struct subsys_attribute * sattr = to_sattr(attr);
 	ssize_t ret = -EIO;
 
 	if (sattr->show)
-		ret = sattr->show(s,page);
+		ret = sattr->show(kset, page);
 	return ret;
 }
 
@@ -37,12 +36,12 @@ static ssize_t 
 subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
 		  const char * page, size_t count)
 {
-	struct subsystem * s = to_subsys(kobj);
+	struct kset *kset = to_kset(kobj);
 	struct subsys_attribute * sattr = to_sattr(attr);
 	ssize_t ret = -EIO;
 
 	if (sattr->store)
-		ret = sattr->store(s,page,count);
+		ret = sattr->store(kset, page, count);
 	return ret;
 }
 
@@ -633,6 +632,7 @@ struct sysfs_schedule_callback_struct {
 	struct kobject 		*kobj;
 	void			(*func)(void *);
 	void			*data;
+	struct module		*owner;
 	struct work_struct	work;
 };
 
@@ -643,6 +643,7 @@ static void sysfs_schedule_callback_work
 
 	(ss->func)(ss->data);
 	kobject_put(ss->kobj);
+	module_put(ss->owner);
 	kfree(ss);
 }
 
@@ -651,6 +652,7 @@ static void sysfs_schedule_callback_work
  * @kobj: object we're acting for.
  * @func: callback function to invoke later.
  * @data: argument to pass to @func.
+ * @owner: module owning the callback code
  *
  * sysfs attribute methods must not unregister themselves or their parent
  * kobject (which would amount to the same thing).  Attempts to do so will
@@ -663,20 +665,25 @@ static void sysfs_schedule_callback_work
  * until @func returns.
  *
  * Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated.
+ * be allocated, -ENODEV if a reference to @owner isn't available.
  */
 int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
-		void *data)
+		void *data, struct module *owner)
 {
 	struct sysfs_schedule_callback_struct *ss;
 
+	if (!try_module_get(owner))
+		return -ENODEV;
 	ss = kmalloc(sizeof(*ss), GFP_KERNEL);
-	if (!ss)
+	if (!ss) {
+		module_put(owner);
 		return -ENOMEM;
+	}
 	kobject_get(kobj);
 	ss->kobj = kobj;
 	ss->func = func;
 	ss->data = data;
+	ss->owner = owner;
 	INIT_WORK(&ss->work, sysfs_schedule_callback_work);
 	schedule_work(&ss->work);
 	return 0;
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index b20951c..52eed2a 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject *
 {
 	struct dentry * dir;
 
-	if (grp->name)
-		dir = lookup_one_len(grp->name, kobj->dentry,
+	if (grp->name) {
+		dir = lookup_one_len_kern(grp->name, kobj->dentry,
 				strlen(grp->name));
+		BUG_ON(IS_ERR(dir));
+	}
 	else
 		dir = dget(kobj->dentry);
 
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index ebf7007..e566b38 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -54,17 +54,9 @@ static struct page * dir_get_page(struct
 {
 	struct address_space *mapping = dir->i_mapping;
 	struct page *page = read_mapping_page(mapping, n, NULL);
-	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
+	if (!IS_ERR(page))
 		kmap(page);
-		if (!PageUptodate(page))
-			goto fail;
-	}
 	return page;
-
-fail:
-	dir_put_page(page);
-	return ERR_PTR(-EIO);
 }
 
 static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 9311cac..3152d74 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -322,8 +322,7 @@ static void init_once(void *p, struct km
 {
 	struct sysv_inode_info *si = (struct sysv_inode_info *)p;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-			SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&si->vfs_inode);
 }
 
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 4e48abb..6bd850b 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -13,7 +13,6 @@
  */
 
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include "sysv.h"
 
 static int add_nondir(struct dentry *dentry, struct inode *inode)
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index ea521f8..4cec910 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -427,9 +427,9 @@ static void udf_table_free_blocks(struct
 {
 	struct udf_sb_info *sbi = UDF_SB(sb);
 	uint32_t start, end;
-	uint32_t nextoffset, oextoffset, elen;
-	kernel_lb_addr nbloc, obloc, eloc;
-	struct buffer_head *obh, *nbh;
+	uint32_t elen;
+	kernel_lb_addr eloc;
+	struct extent_position oepos, epos;
 	int8_t etype;
 	int i;
 
@@ -457,14 +457,13 @@ static void udf_table_free_blocks(struct
 	start = bloc.logicalBlockNum + offset;
 	end = bloc.logicalBlockNum + offset + count - 1;
 
-	oextoffset = nextoffset = sizeof(struct unallocSpaceEntry);
+	epos.offset = oepos.offset = sizeof(struct unallocSpaceEntry);
 	elen = 0;
-	obloc = nbloc = UDF_I_LOCATION(table);
-
-	obh = nbh = NULL;
+	epos.block = oepos.block = UDF_I_LOCATION(table);
+	epos.bh = oepos.bh = NULL;
 
 	while (count && (etype =
-		udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+		udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
 	{
 		if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
 			start))
@@ -482,7 +481,7 @@ static void udf_table_free_blocks(struct
 				start += count;
 				count = 0;
 			}
-			udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+			udf_write_aext(table, &oepos, eloc, elen, 1);
 		}
 		else if (eloc.logicalBlockNum == (end + 1))
 		{
@@ -502,20 +501,20 @@ static void udf_table_free_blocks(struct
 				end -= count;
 				count = 0;
 			}
-			udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+			udf_write_aext(table, &oepos, eloc, elen, 1);
 		}
 
-		if (nbh != obh)
+		if (epos.bh != oepos.bh)
 		{
 			i = -1;
-			obloc = nbloc;
-			udf_release_data(obh);
-			atomic_inc(&nbh->b_count);
-			obh = nbh;
-			oextoffset = 0;
+			oepos.block = epos.block;
+			brelse(oepos.bh);
+			get_bh(epos.bh);
+			oepos.bh = epos.bh;
+			oepos.offset = 0;
 		}
 		else
-			oextoffset = nextoffset;
+			oepos.offset = epos.offset;
 	}
 
 	if (count)
@@ -547,55 +546,53 @@ static void udf_table_free_blocks(struct
 			adsize = sizeof(long_ad);
 		else
 		{
-			udf_release_data(obh);
-			udf_release_data(nbh);
+			brelse(oepos.bh);
+			brelse(epos.bh);
 			goto error_return;
 		}
 
-		if (nextoffset + (2 * adsize) > sb->s_blocksize)
+		if (epos.offset + (2 * adsize) > sb->s_blocksize)
 		{
 			char *sptr, *dptr;
 			int loffset;
 	
-			udf_release_data(obh);
-			obh = nbh;
-			obloc = nbloc;
-			oextoffset = nextoffset;
+			brelse(oepos.bh);
+			oepos = epos;
 
 			/* Steal a block from the extent being free'd */
-			nbloc.logicalBlockNum = eloc.logicalBlockNum;
+			epos.block.logicalBlockNum = eloc.logicalBlockNum;
 			eloc.logicalBlockNum ++;
 			elen -= sb->s_blocksize;
 
-			if (!(nbh = udf_tread(sb,
-				udf_get_lb_pblock(sb, nbloc, 0))))
+			if (!(epos.bh = udf_tread(sb,
+				udf_get_lb_pblock(sb, epos.block, 0))))
 			{
-				udf_release_data(obh);
+				brelse(oepos.bh);
 				goto error_return;
 			}
-			aed = (struct allocExtDesc *)(nbh->b_data);
-			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
-			if (nextoffset + adsize > sb->s_blocksize)
+			aed = (struct allocExtDesc *)(epos.bh->b_data);
+			aed->previousAllocExtLocation = cpu_to_le32(oepos.block.logicalBlockNum);
+			if (epos.offset + adsize > sb->s_blocksize)
 			{
-				loffset = nextoffset;
+				loffset = epos.offset;
 				aed->lengthAllocDescs = cpu_to_le32(adsize);
-				sptr = UDF_I_DATA(inode) + nextoffset -
+				sptr = UDF_I_DATA(inode) + epos.offset -
 					udf_file_entry_alloc_offset(inode) +
 					UDF_I_LENEATTR(inode) - adsize;
-				dptr = nbh->b_data + sizeof(struct allocExtDesc);
+				dptr = epos.bh->b_data + sizeof(struct allocExtDesc);
 				memcpy(dptr, sptr, adsize);
-				nextoffset = sizeof(struct allocExtDesc) + adsize;
+				epos.offset = sizeof(struct allocExtDesc) + adsize;
 			}
 			else
 			{
-				loffset = nextoffset + adsize;
+				loffset = epos.offset + adsize;
 				aed->lengthAllocDescs = cpu_to_le32(0);
-				sptr = (obh)->b_data + nextoffset;
-				nextoffset = sizeof(struct allocExtDesc);
+				sptr = oepos.bh->b_data + epos.offset;
+				epos.offset = sizeof(struct allocExtDesc);
 
-				if (obh)
+				if (oepos.bh)
 				{
-					aed = (struct allocExtDesc *)(obh)->b_data;
+					aed = (struct allocExtDesc *)oepos.bh->b_data;
 					aed->lengthAllocDescs =
 						cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 				}
@@ -606,11 +603,11 @@ static void udf_table_free_blocks(struct
 				}
 			}
 			if (UDF_SB_UDFREV(sb) >= 0x0200)
-				udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
-					nbloc.logicalBlockNum, sizeof(tag));
+				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1,
+					epos.block.logicalBlockNum, sizeof(tag));
 			else
-				udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
-					nbloc.logicalBlockNum, sizeof(tag));
+				udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2, 1,
+					epos.block.logicalBlockNum, sizeof(tag));
 			switch (UDF_I_ALLOCTYPE(table))
 			{
 				case ICBTAG_FLAG_AD_SHORT:
@@ -619,7 +616,7 @@ static void udf_table_free_blocks(struct
 					sad->extLength = cpu_to_le32(
 						EXT_NEXT_EXTENT_ALLOCDECS |
 						sb->s_blocksize);
-					sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum);
+					sad->extPosition = cpu_to_le32(epos.block.logicalBlockNum);
 					break;
 				}
 				case ICBTAG_FLAG_AD_LONG:
@@ -628,14 +625,14 @@ static void udf_table_free_blocks(struct
 					lad->extLength = cpu_to_le32(
 						EXT_NEXT_EXTENT_ALLOCDECS |
 						sb->s_blocksize);
-					lad->extLocation = cpu_to_lelb(nbloc);
+					lad->extLocation = cpu_to_lelb(epos.block);
 					break;
 				}
 			}
-			if (obh)
+			if (oepos.bh)
 			{
-				udf_update_tag(obh->b_data, loffset);
-				mark_buffer_dirty(obh);
+				udf_update_tag(oepos.bh->b_data, loffset);
+				mark_buffer_dirty(oepos.bh);
 			}
 			else
 				mark_inode_dirty(table);
@@ -643,26 +640,26 @@ static void udf_table_free_blocks(struct
 
 		if (elen) /* It's possible that stealing the block emptied the extent */
 		{
-			udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1);
+			udf_write_aext(table, &epos, eloc, elen, 1);
 
-			if (!nbh)
+			if (!epos.bh)
 			{
 				UDF_I_LENALLOC(table) += adsize;
 				mark_inode_dirty(table);
 			}
 			else
 			{
-				aed = (struct allocExtDesc *)nbh->b_data;
+				aed = (struct allocExtDesc *)epos.bh->b_data;
 				aed->lengthAllocDescs =
 					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
-				udf_update_tag(nbh->b_data, nextoffset);
-				mark_buffer_dirty(nbh);
+				udf_update_tag(epos.bh->b_data, epos.offset);
+				mark_buffer_dirty(epos.bh);
 			}
 		}
 	}
 
-	udf_release_data(nbh);
-	udf_release_data(obh);
+	brelse(epos.bh);
+	brelse(oepos.bh);
 
 error_return:
 	sb->s_dirt = 1;
@@ -677,9 +674,9 @@ static int udf_table_prealloc_blocks(str
 {
 	struct udf_sb_info *sbi = UDF_SB(sb);
 	int alloc_count = 0;
-	uint32_t extoffset, elen, adsize;
-	kernel_lb_addr bloc, eloc;
-	struct buffer_head *bh;
+	uint32_t elen, adsize;
+	kernel_lb_addr eloc;
+	struct extent_position epos;
 	int8_t etype = -1;
 
 	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
@@ -693,14 +690,13 @@ static int udf_table_prealloc_blocks(str
 		return 0;
 
 	mutex_lock(&sbi->s_alloc_mutex);
-	extoffset = sizeof(struct unallocSpaceEntry);
-	bloc = UDF_I_LOCATION(table);
-
-	bh = NULL;
+	epos.offset = sizeof(struct unallocSpaceEntry);
+	epos.block = UDF_I_LOCATION(table);
+	epos.bh = NULL;
 	eloc.logicalBlockNum = 0xFFFFFFFF;
 
 	while (first_block != eloc.logicalBlockNum && (etype =
-		udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+		udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
 	{
 		udf_debug("eloc=%d, elen=%d, first_block=%d\n",
 			eloc.logicalBlockNum, elen, first_block);
@@ -709,7 +705,7 @@ static int udf_table_prealloc_blocks(str
 
 	if (first_block == eloc.logicalBlockNum)
 	{
-		extoffset -= adsize;
+		epos.offset -= adsize;
 
 		alloc_count = (elen >> sb->s_blocksize_bits);
 		if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
@@ -719,15 +715,15 @@ static int udf_table_prealloc_blocks(str
 			alloc_count = block_count;
 			eloc.logicalBlockNum += alloc_count;
 			elen -= (alloc_count << sb->s_blocksize_bits);
-			udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1);
+			udf_write_aext(table, &epos, eloc, (etype << 30) | elen, 1);
 		}
 		else
-			udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh);
+			udf_delete_aext(table, epos, eloc, (etype << 30) | elen);
 	}
 	else
 		alloc_count = 0;
 
-	udf_release_data(bh);
+	brelse(epos.bh);
 
 	if (alloc_count && UDF_SB_LVIDBH(sb))
 	{
@@ -747,9 +743,9 @@ static int udf_table_new_block(struct su
 	struct udf_sb_info *sbi = UDF_SB(sb);
 	uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
 	uint32_t newblock = 0, adsize;
-	uint32_t extoffset, goal_extoffset, elen, goal_elen = 0;
-	kernel_lb_addr bloc, goal_bloc, eloc, goal_eloc;
-	struct buffer_head *bh, *goal_bh;
+	uint32_t elen, goal_elen = 0;
+	kernel_lb_addr eloc, goal_eloc;
+	struct extent_position epos, goal_epos;
 	int8_t etype;
 
 	*err = -ENOSPC;
@@ -770,14 +766,12 @@ static int udf_table_new_block(struct su
 	   We store the buffer_head, bloc, and extoffset of the current closest
 	   match and use that when we are done.
 	*/
-
-	extoffset = sizeof(struct unallocSpaceEntry);
-	bloc = UDF_I_LOCATION(table);
-
-	goal_bh = bh = NULL;
+	epos.offset = sizeof(struct unallocSpaceEntry);
+	epos.block = UDF_I_LOCATION(table);
+	epos.bh = goal_epos.bh = NULL;
 
 	while (spread && (etype =
-		udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+		udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
 	{
 		if (goal >= eloc.logicalBlockNum)
 		{
@@ -793,24 +787,24 @@ static int udf_table_new_block(struct su
 		if (nspread < spread)
 		{
 			spread = nspread;
-			if (goal_bh != bh)
+			if (goal_epos.bh != epos.bh)
 			{
-				udf_release_data(goal_bh);
-				goal_bh = bh;
-				atomic_inc(&goal_bh->b_count);
+				brelse(goal_epos.bh);
+				goal_epos.bh = epos.bh;
+				get_bh(goal_epos.bh);
 			}
-			goal_bloc = bloc;
-			goal_extoffset = extoffset - adsize;
+			goal_epos.block = epos.block;
+			goal_epos.offset = epos.offset - adsize;
 			goal_eloc = eloc;
 			goal_elen = (etype << 30) | elen;
 		}
 	}
 
-	udf_release_data(bh);
+	brelse(epos.bh);
 
 	if (spread == 0xFFFFFFFF)
 	{
-		udf_release_data(goal_bh);
+		brelse(goal_epos.bh);
 		mutex_unlock(&sbi->s_alloc_mutex);
 		return 0;
 	}
@@ -826,17 +820,17 @@ static int udf_table_new_block(struct su
 
 	if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
 	{
-		udf_release_data(goal_bh);
+		brelse(goal_epos.bh);
 		mutex_unlock(&sbi->s_alloc_mutex);
 		*err = -EDQUOT;
 		return 0;
 	}
 
 	if (goal_elen)
-		udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
+		udf_write_aext(table, &goal_epos, goal_eloc, goal_elen, 1);
 	else
-		udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh);
-	udf_release_data(goal_bh);
+		udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
+	brelse(goal_epos.bh);
 
 	if (UDF_SB_LVIDBH(sb))
 	{
@@ -921,11 +915,14 @@ inline int udf_new_block(struct super_bl
 	struct inode * inode,
 	uint16_t partition, uint32_t goal, int *err)
 {
+	int ret;
+
 	if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
 	{
-		return udf_bitmap_new_block(sb, inode,
+		ret = udf_bitmap_new_block(sb, inode,
 			UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
 			partition, goal, err);
+		return ret;
 	}
 	else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
 	{
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 2391c91..e45f86b 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -111,11 +111,13 @@ do_udf_readdir(struct inode * dir, struc
 	uint16_t liu;
 	uint8_t lfi;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
-	struct buffer_head * bh = NULL, * tmp, * bha[16];
-	kernel_lb_addr bloc, eloc;
-	uint32_t extoffset, elen, offset;
+	struct buffer_head *tmp, *bha[16];
+	kernel_lb_addr eloc;
+	uint32_t elen;
+	sector_t offset;
 	int i, num;
 	unsigned int dt_type;
+	struct extent_position epos = { NULL, 0, {0, 0}};
 
 	if (nf_pos >= size)
 		return 0;
@@ -127,23 +129,22 @@ do_udf_readdir(struct inode * dir, struc
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
 		fibh.sbh = fibh.ebh = NULL;
 	else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
-		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+		&epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
 	{
-		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
-				extoffset -= sizeof(short_ad);
+				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
-				extoffset -= sizeof(long_ad);
+				epos.offset -= sizeof(long_ad);
 		}
 		else
 			offset = 0;
 
 		if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
 		{
-			udf_release_data(bh);
+			brelse(epos.bh);
 			return -EIO;
 		}
 	
@@ -171,7 +172,7 @@ do_udf_readdir(struct inode * dir, struc
 	}
 	else
 	{
-		udf_release_data(bh);
+		brelse(epos.bh);
 		return -ENOENT;
 	}
 
@@ -179,14 +180,14 @@ do_udf_readdir(struct inode * dir, struc
 	{
 		filp->f_pos = nf_pos + 1;
 
-		fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+		fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
 
 		if (!fi)
 		{
 			if (fibh.sbh != fibh.ebh)
-				udf_release_data(fibh.ebh);
-			udf_release_data(fibh.sbh);
-			udf_release_data(bh);
+				brelse(fibh.ebh);
+			brelse(fibh.sbh);
+			brelse(epos.bh);
 			return 0;
 		}
 
@@ -244,9 +245,9 @@ do_udf_readdir(struct inode * dir, struc
 			if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
 			{
 				if (fibh.sbh != fibh.ebh)
-					udf_release_data(fibh.ebh);
-				udf_release_data(fibh.sbh);
-				udf_release_data(bh);
+					brelse(fibh.ebh);
+				brelse(fibh.sbh);
+				brelse(epos.bh);
 	 			return 0;
 			}
 		}
@@ -255,9 +256,9 @@ do_udf_readdir(struct inode * dir, struc
 	filp->f_pos = nf_pos + 1;
 
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
-	udf_release_data(bh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
+	brelse(epos.bh);
 
 	return 0;
 }
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index fe751a2..198caa3 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -36,14 +36,14 @@ udf_filead_read(struct inode *dir, uint8
 
 	if (!ad)
 	{
-		udf_release_data(*bh);
+		brelse(*bh);
 		*error = 1;
 		return NULL;
 	}
 
 	if (*offset == dir->i_sb->s_blocksize)
 	{
-		udf_release_data(*bh);
+		brelse(*bh);
 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
 		if (!block)
 			return NULL;
@@ -57,7 +57,7 @@ udf_filead_read(struct inode *dir, uint8
 		remainder = dir->i_sb->s_blocksize - loffset;
 		memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
 
-		udf_release_data(*bh);
+		brelse(*bh);
 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
 		if (!block)
 			return NULL;
@@ -75,9 +75,9 @@ struct fileIdentDesc *
 udf_fileident_read(struct inode *dir, loff_t *nf_pos,
 	struct udf_fileident_bh *fibh,
 	struct fileIdentDesc *cfi,
-	kernel_lb_addr *bloc, uint32_t *extoffset, 
+	struct extent_position *epos,
 	kernel_lb_addr *eloc, uint32_t *elen,
-	uint32_t *offset, struct buffer_head **bh)
+	sector_t *offset)
 {
 	struct fileIdentDesc *fi;
 	int i, num, block;
@@ -105,13 +105,11 @@ udf_fileident_read(struct inode *dir, lo
 
 	if (fibh->eoffset == dir->i_sb->s_blocksize)
 	{
-		int lextoffset = *extoffset;
+		int lextoffset = epos->offset;
 
-		if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
 			(EXT_RECORDED_ALLOCATED >> 30))
-		{
 			return NULL;
-		}
 
 		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
 
@@ -120,9 +118,9 @@ udf_fileident_read(struct inode *dir, lo
 		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
 			*offset = 0;
 		else
-			*extoffset = lextoffset;
+			epos->offset = lextoffset;
 
-		udf_release_data(fibh->sbh);
+		brelse(fibh->sbh);
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 			return NULL;
 		fibh->soffset = fibh->eoffset = 0;
@@ -151,7 +149,7 @@ udf_fileident_read(struct inode *dir, lo
 	}
 	else if (fibh->sbh != fibh->ebh)
 	{
-		udf_release_data(fibh->sbh);
+		brelse(fibh->sbh);
 		fibh->sbh = fibh->ebh;
 	}
 
@@ -169,13 +167,11 @@ udf_fileident_read(struct inode *dir, lo
 	}
 	else if (fibh->eoffset > dir->i_sb->s_blocksize)
 	{
-		int lextoffset = *extoffset;
+		int lextoffset = epos->offset;
 
-		if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
 			(EXT_RECORDED_ALLOCATED >> 30))
-		{
 			return NULL;
-		}
 
 		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
 
@@ -184,7 +180,7 @@ udf_fileident_read(struct inode *dir, lo
 		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
 			*offset = 0;
 		else
-			*extoffset = lextoffset;
+			epos->offset = lextoffset;
 
 		fibh->soffset -= dir->i_sb->s_blocksize;
 		fibh->eoffset -= dir->i_sb->s_blocksize;
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index 5887d78..6ded93e 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -21,7 +21,6 @@
 #include "udfdecl.h"
 
 #include <linux/fs.h>
-#include <linux/smp_lock.h>
 
 static int udf_fsync_inode(struct inode *, int);
 
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index ae21a0e..c846155 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -49,10 +49,10 @@ #define EXTENT_MERGE_SIZE 5
 static mode_t udf_convert_permissions(struct fileEntry *);
 static int udf_update_inode(struct inode *, int);
 static void udf_fill_inode(struct inode *, struct buffer_head *);
-static struct buffer_head *inode_getblk(struct inode *, long, int *,
+static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
 	long *, int *);
-static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int,
-	kernel_lb_addr, uint32_t, struct buffer_head *);
+static int8_t udf_insert_aext(struct inode *, struct extent_position,
+	kernel_lb_addr, uint32_t);
 static void udf_split_extents(struct inode *, int *, int, int,
 	kernel_long_ad [EXTENT_MERGE_SIZE], int *);
 static void udf_prealloc_extents(struct inode *, int, int,
@@ -61,7 +61,7 @@ static void udf_merge_extents(struct ino
 	 kernel_long_ad [EXTENT_MERGE_SIZE], int *);
 static void udf_update_extents(struct inode *,
 	kernel_long_ad [EXTENT_MERGE_SIZE], int, int,
-	kernel_lb_addr, uint32_t, struct buffer_head **);
+	struct extent_position *);
 static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 /*
@@ -194,10 +194,11 @@ void udf_expand_file_adinicb(struct inod
 struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
 {
 	int newblock;
-	struct buffer_head *sbh = NULL, *dbh = NULL;
-	kernel_lb_addr bloc, eloc;
-	uint32_t elen, extoffset;
+	struct buffer_head *dbh = NULL;
+	kernel_lb_addr eloc;
+	uint32_t elen;
 	uint8_t alloctype;
+	struct extent_position epos;
 
 	struct udf_fileident_bh sfibh, dfibh;
 	loff_t f_pos = udf_ext0_offset(inode) >> 2;
@@ -237,16 +238,16 @@ struct buffer_head * udf_expand_dir_adin
 	mark_buffer_dirty_inode(dbh, inode);
 
 	sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
-	sbh = sfibh.sbh = sfibh.ebh = NULL;
+	sfibh.sbh = sfibh.ebh = NULL;
 	dfibh.soffset = dfibh.eoffset = 0;
 	dfibh.sbh = dfibh.ebh = dbh;
 	while ( (f_pos < size) )
 	{
 		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
-		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL);
+		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
 		if (!sfi)
 		{
-			udf_release_data(dbh);
+			brelse(dbh);
 			return NULL;
 		}
 		UDF_I_ALLOCTYPE(inode) = alloctype;
@@ -258,7 +259,7 @@ struct buffer_head * udf_expand_dir_adin
 			sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))
 		{
 			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
-			udf_release_data(dbh);
+			brelse(dbh);
 			return NULL;
 		}
 	}
@@ -266,16 +267,17 @@ struct buffer_head * udf_expand_dir_adin
 
 	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));
 	UDF_I_LENALLOC(inode) = 0;
-	bloc = UDF_I_LOCATION(inode);
 	eloc.logicalBlockNum = *block;
 	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 	elen = inode->i_size;
 	UDF_I_LENEXTENTS(inode) = elen;
-	extoffset = udf_file_entry_alloc_offset(inode);
-	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);
+	epos.bh = NULL;
+	epos.block = UDF_I_LOCATION(inode);
+	epos.offset = udf_file_entry_alloc_offset(inode);
+	udf_add_aext(inode, &epos, eloc, elen, 0);
 	/* UniqueID stuff */
 
-	udf_release_data(sbh);
+	brelse(epos.bh);
 	mark_inode_dirty(inode);
 	return dbh;
 }
@@ -354,53 +356,153 @@ udf_getblk(struct inode *inode, long blo
 	return NULL;
 }
 
-static struct buffer_head * inode_getblk(struct inode * inode, long block,
+/* Extend the file by 'blocks' blocks, return the number of extents added */
+int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
+	kernel_long_ad *last_ext, sector_t blocks)
+{
+	sector_t add;
+	int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+	struct super_block *sb = inode->i_sb;
+	kernel_lb_addr prealloc_loc = {0, 0};
+	int prealloc_len = 0;
+
+	/* The previous extent is fake and we should not extend by anything
+	 * - there's nothing to do... */
+	if (!blocks && fake)
+		return 0;
+	/* Round the last extent up to a multiple of block size */
+	if (last_ext->extLength & (sb->s_blocksize - 1)) {
+		last_ext->extLength =
+			(last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
+			(((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
+				sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+		UDF_I_LENEXTENTS(inode) =
+			(UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
+				~(sb->s_blocksize - 1);
+	}
+	/* Last extent are just preallocated blocks? */
+	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
+		/* Save the extent so that we can reattach it to the end */
+		prealloc_loc = last_ext->extLocation;
+		prealloc_len = last_ext->extLength;
+		/* Mark the extent as a hole */
+		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+			(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+		last_ext->extLocation.logicalBlockNum = 0;
+       		last_ext->extLocation.partitionReferenceNum = 0;
+	}
+	/* Can we merge with the previous extent? */
+	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
+		add = ((1<<30) - sb->s_blocksize - (last_ext->extLength &
+			UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
+		if (add > blocks)
+			add = blocks;
+		blocks -= add;
+		last_ext->extLength += add << sb->s_blocksize_bits;
+	}
+
+	if (fake) {
+		udf_add_aext(inode, last_pos, last_ext->extLocation,
+			last_ext->extLength, 1);
+		count++;
+	}
+	else
+		udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
+	/* Managed to do everything necessary? */
+	if (!blocks)
+		goto out;
+
+	/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
+	last_ext->extLocation.logicalBlockNum = 0;
+       	last_ext->extLocation.partitionReferenceNum = 0;
+	add = (1 << (30-sb->s_blocksize_bits)) - 1;
+	last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+	/* Create enough extents to cover the whole hole */
+	while (blocks > add) {
+		blocks -= add;
+		if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+			last_ext->extLength, 1) == -1)
+			return -1;
+		count++;
+	}
+	if (blocks) {
+		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+			(blocks << sb->s_blocksize_bits);
+		if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+			last_ext->extLength, 1) == -1)
+			return -1;
+		count++;
+	}
+out:
+	/* Do we have some preallocated blocks saved? */
+	if (prealloc_len) {
+		if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1)
+			return -1;
+		last_ext->extLocation = prealloc_loc;
+		last_ext->extLength = prealloc_len;
+		count++;
+	}
+	/* last_pos should point to the last written extent... */
+	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
+		last_pos->offset -= sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
+		last_pos->offset -= sizeof(long_ad);
+	else
+		return -1;
+	return count;
+}
+
+static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
 	int *err, long *phys, int *new)
 {
-	struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;
+	static sector_t last_block;
+	struct buffer_head *result = NULL;
 	kernel_long_ad laarr[EXTENT_MERGE_SIZE];
-	uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0;
+	struct extent_position prev_epos, cur_epos, next_epos;
 	int count = 0, startnum = 0, endnum = 0;
 	uint32_t elen = 0;
-	kernel_lb_addr eloc, pbloc, cbloc, nbloc;
+	kernel_lb_addr eloc;
 	int c = 1;
-	uint64_t lbcount = 0, b_off = 0;
-	uint32_t newblocknum, newblock, offset = 0;
+	loff_t lbcount = 0, b_off = 0;
+	uint32_t newblocknum, newblock;
+	sector_t offset = 0;
 	int8_t etype;
 	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
-	char lastblock = 0;
+	int lastblock = 0;
 
-	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
-	b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits;
-	pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);
+	prev_epos.offset = udf_file_entry_alloc_offset(inode);
+	prev_epos.block = UDF_I_LOCATION(inode);
+	prev_epos.bh = NULL;
+	cur_epos = next_epos = prev_epos;
+	b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
 
 	/* find the extent which contains the block we are looking for.
        alternate between laarr[0] and laarr[1] for locations of the
        current extent, and the previous extent */
 	do
 	{
-		if (pbh != cbh)
+		if (prev_epos.bh != cur_epos.bh)
 		{
-			udf_release_data(pbh);
-			atomic_inc(&cbh->b_count);
-			pbh = cbh;
+			brelse(prev_epos.bh);
+			get_bh(cur_epos.bh);
+			prev_epos.bh = cur_epos.bh;
 		}
-		if (cbh != nbh)
+		if (cur_epos.bh != next_epos.bh)
 		{
-			udf_release_data(cbh);
-			atomic_inc(&nbh->b_count);
-			cbh = nbh;
+			brelse(cur_epos.bh);
+			get_bh(next_epos.bh);
+			cur_epos.bh = next_epos.bh;
 		}
 
 		lbcount += elen;
 
-		pbloc = cbloc;
-		cbloc = nbloc;
+		prev_epos.block = cur_epos.block;
+		cur_epos.block = next_epos.block;
 
-		pextoffset = cextoffset;
-		cextoffset = nextoffset;
+		prev_epos.offset = cur_epos.offset;
+		cur_epos.offset = next_epos.offset;
 
-		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1)
+		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1)
 			break;
 
 		c = !c;
@@ -418,6 +520,8 @@ static struct buffer_head * inode_getblk
 
 	b_off -= lbcount;
 	offset = b_off >> inode->i_sb->s_blocksize_bits;
+	/* Move into indirect extent if we are at a pointer to it */
+	udf_next_aext(inode, &prev_epos, &eloc, &elen, 0);
 
 	/* if the extent is allocated and recorded, return the block
        if the extent is not a multiple of the blocksize, round up */
@@ -429,54 +533,77 @@ static struct buffer_head * inode_getblk
 			elen = EXT_RECORDED_ALLOCATED |
 				((elen + inode->i_sb->s_blocksize - 1) &
 				~(inode->i_sb->s_blocksize - 1));
-			etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1);
+			etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
 		}
-		udf_release_data(pbh);
-		udf_release_data(cbh);
-		udf_release_data(nbh);
+		brelse(prev_epos.bh);
+		brelse(cur_epos.bh);
+		brelse(next_epos.bh);
 		newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
 		*phys = newblock;
 		return NULL;
 	}
 
+	last_block = block;
+	/* Are we beyond EOF? */
 	if (etype == -1)
 	{
-		endnum = startnum = ((count > 1) ? 1 : count);
-		if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1))
-		{
-			laarr[c].extLength =
-				(laarr[c].extLength & UDF_EXTENT_FLAG_MASK) |
-				(((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) +
-					inode->i_sb->s_blocksize - 1) &
-				~(inode->i_sb->s_blocksize - 1));
-			UDF_I_LENEXTENTS(inode) =
-				(UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) &
-					~(inode->i_sb->s_blocksize - 1);
+		int ret;
+
+		if (count) {
+			if (c)
+				laarr[0] = laarr[1];
+			startnum = 1;
+		}
+		else {
+			/* Create a fake extent when there's not one */
+			memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
+			laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
+			/* Will udf_extend_file() create real extent from a fake one? */
+			startnum = (offset > 0);
+		}
+		/* Create extents for the hole between EOF and offset */
+		ret = udf_extend_file(inode, &prev_epos, laarr, offset);
+		if (ret == -1) {
+			brelse(prev_epos.bh);
+			brelse(cur_epos.bh);
+			brelse(next_epos.bh);
+			/* We don't really know the error here so we just make
+			 * something up */
+			*err = -ENOSPC;
+			return NULL;
 		}
-		c = !c;
-		laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
-			((offset + 1) << inode->i_sb->s_blocksize_bits);
-		memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
-		count ++;
-		endnum ++;
+		c = 0;
+		offset = 0;
+		count += ret;
+		/* We are not covered by a preallocated extent? */
+		if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) {
+			/* Is there any real extent? - otherwise we overwrite
+			 * the fake one... */
+			if (count)
+				c = !c;
+			laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+				inode->i_sb->s_blocksize;
+			memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
+			count ++;
+			endnum ++;
+		}
+		endnum = c+1;
 		lastblock = 1;
 	}
-	else
+	else {
 		endnum = startnum = ((count > 2) ? 2 : count);
 
-	/* if the current extent is in position 0, swap it with the previous */
-	if (!c && count != 1)
-	{
-		laarr[2] = laarr[0];
-		laarr[0] = laarr[1];
-		laarr[1] = laarr[2];
-		c = 1;
-	}
+		/* if the current extent is in position 0, swap it with the previous */
+		if (!c && count != 1)
+		{
+			laarr[2] = laarr[0];
+			laarr[0] = laarr[1];
+			laarr[1] = laarr[2];
+			c = 1;
+		}
 
-	/* if the current block is located in a extent, read the next extent */
-	if (etype != -1)
-	{
-		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1)
+		/* if the current block is located in an extent, read the next extent */
+		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)
 		{
 			laarr[c+1].extLength = (etype << 30) | elen;
 			laarr[c+1].extLocation = eloc;
@@ -484,11 +611,10 @@ static struct buffer_head * inode_getblk
 			startnum ++;
 			endnum ++;
 		}
-		else
+		else {
 			lastblock = 1;
+		}
 	}
-	udf_release_data(cbh);
-	udf_release_data(nbh);
 
 	/* if the current extent is not recorded but allocated, get the
 		block in the extent corresponding to the requested block */
@@ -508,7 +634,7 @@ static struct buffer_head * inode_getblk
 		if (!(newblocknum = udf_new_block(inode->i_sb, inode,
 			UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
 		{
-			udf_release_data(pbh);
+			brelse(prev_epos.bh);
 			*err = -ENOSPC;
 			return NULL;
 		}
@@ -529,11 +655,11 @@ #endif
 	udf_merge_extents(inode, laarr, &endnum);
 
 	/* write back the new extents, inserting new extents if the new number
-       of extents is greater than the old number, and deleting extents if
-       the new number of extents is less than the old number */
-	udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
+	of extents is greater than the old number, and deleting extents if
+	the new number of extents is less than the old number */
+	udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
 
-	udf_release_data(pbh);
+	brelse(prev_epos.bh);
 
 	if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
 		UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
@@ -795,7 +921,7 @@ static void udf_merge_extents(struct ino
 
 static void udf_update_extents(struct inode *inode,
 	kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
-	kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh)
+	struct extent_position *epos)
 {
 	int start = 0, i;
 	kernel_lb_addr tmploc;
@@ -804,28 +930,26 @@ static void udf_update_extents(struct in
 	if (startnum > endnum)
 	{
 		for (i=0; i<(startnum-endnum); i++)
-		{
-			udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
-				laarr[i].extLength, *pbh);
-		}
+			udf_delete_aext(inode, *epos, laarr[i].extLocation,
+				laarr[i].extLength);
 	}
 	else if (startnum < endnum)
 	{
 		for (i=0; i<(endnum-startnum); i++)
 		{
-			udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
-				laarr[i].extLength, *pbh);
-			udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation,
-				&laarr[i].extLength, pbh, 1);
+			udf_insert_aext(inode, *epos, laarr[i].extLocation,
+				laarr[i].extLength);
+			udf_next_aext(inode, epos, &laarr[i].extLocation,
+				&laarr[i].extLength, 1);
 			start ++;
 		}
 	}
 
 	for (i=start; i<endnum; i++)
 	{
-		udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
-		udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
-			laarr[i].extLength, *pbh, 1);
+		udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
+		udf_write_aext(inode, epos, laarr[i].extLocation,
+			laarr[i].extLength, 1);
 	}
 }
 
@@ -931,7 +1055,7 @@ __udf_read_inode(struct inode *inode)
 	{
 		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
 			inode->i_ino, ident);
-		udf_release_data(bh);
+		brelse(bh);
 		make_bad_inode(inode);
 		return;
 	}
@@ -960,35 +1084,36 @@ __udf_read_inode(struct inode *inode)
 						ident == TAG_IDENT_EFE)
 					{
 						memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr));
-						udf_release_data(bh);
-						udf_release_data(ibh);
-						udf_release_data(nbh);
+						brelse(bh);
+						brelse(ibh);
+						brelse(nbh);
 						__udf_read_inode(inode);
 						return;
 					}
 					else
 					{
-						udf_release_data(nbh);
-						udf_release_data(ibh);
+						brelse(nbh);
+						brelse(ibh);
 					}
 				}
 				else
-					udf_release_data(ibh);
+					brelse(ibh);
 			}
 		}
 		else
-			udf_release_data(ibh);
+			brelse(ibh);
 	}
 	else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
 	{
 		printk(KERN_ERR "udf: unsupported strategy type: %d\n",
 			le16_to_cpu(fe->icbTag.strategyType));
-		udf_release_data(bh);
+		brelse(bh);
 		make_bad_inode(inode);
 		return;
 	}
 	udf_fill_inode(inode, bh);
-	udf_release_data(bh);
+
+	brelse(bh);
 }
 
 static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
@@ -1331,7 +1456,7 @@ udf_update_inode(struct inode *inode, in
 				use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
 
 		mark_buffer_dirty(bh);
-		udf_release_data(bh);
+		brelse(bh);
 		return err;
 	}
 
@@ -1520,7 +1645,7 @@ udf_update_inode(struct inode *inode, in
 			err = -EIO;
 		}
 	}
-	udf_release_data(bh);
+	brelse(bh);
 	return err;
 }
 
@@ -1556,8 +1681,8 @@ udf_iget(struct super_block *sb, kernel_
 	return NULL;
 }
 
-int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
-	kernel_lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc)
+int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
+	kernel_lb_addr eloc, uint32_t elen, int inc)
 {
 	int adsize;
 	short_ad *sad = NULL;
@@ -1566,10 +1691,10 @@ int8_t udf_add_aext(struct inode *inode,
 	int8_t etype;
 	uint8_t *ptr;
 
-	if (!*bh)
-		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+	if (!epos->bh)
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
 	else
-		ptr = (*bh)->b_data + *extoffset;
+		ptr = epos->bh->b_data + epos->offset;
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
 		adsize = sizeof(short_ad);
@@ -1578,20 +1703,20 @@ int8_t udf_add_aext(struct inode *inode,
 	else
 		return -1;
 
-	if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize)
+	if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize)
 	{
 		char *sptr, *dptr;
 		struct buffer_head *nbh;
 		int err, loffset;
-		kernel_lb_addr obloc = *bloc;
+		kernel_lb_addr obloc = epos->block;
 
-		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL,
+		if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
 			obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
 		{
 			return -1;
 		}
 		if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
-			*bloc, 0))))
+			epos->block, 0))))
 		{
 			return -1;
 		}
@@ -1604,25 +1729,25 @@ int8_t udf_add_aext(struct inode *inode,
 		aed = (struct allocExtDesc *)(nbh->b_data);
 		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
 			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
-		if (*extoffset + adsize > inode->i_sb->s_blocksize)
+		if (epos->offset + adsize > inode->i_sb->s_blocksize)
 		{
-			loffset = *extoffset;
+			loffset = epos->offset;
 			aed->lengthAllocDescs = cpu_to_le32(adsize);
 			sptr = ptr - adsize;
 			dptr = nbh->b_data + sizeof(struct allocExtDesc);
 			memcpy(dptr, sptr, adsize);
-			*extoffset = sizeof(struct allocExtDesc) + adsize;
+			epos->offset = sizeof(struct allocExtDesc) + adsize;
 		}
 		else
 		{
-			loffset = *extoffset + adsize;
+			loffset = epos->offset + adsize;
 			aed->lengthAllocDescs = cpu_to_le32(0);
 			sptr = ptr;
-			*extoffset = sizeof(struct allocExtDesc);
+			epos->offset = sizeof(struct allocExtDesc);
 
-			if (*bh)
+			if (epos->bh)
 			{
-				aed = (struct allocExtDesc *)(*bh)->b_data;
+				aed = (struct allocExtDesc *)epos->bh->b_data;
 				aed->lengthAllocDescs =
 					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 			}
@@ -1634,10 +1759,10 @@ int8_t udf_add_aext(struct inode *inode,
 		}
 		if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
 			udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
-				bloc->logicalBlockNum, sizeof(tag));
+				epos->block.logicalBlockNum, sizeof(tag));
 		else
 			udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
-				bloc->logicalBlockNum, sizeof(tag));
+				epos->block.logicalBlockNum, sizeof(tag));
 		switch (UDF_I_ALLOCTYPE(inode))
 		{
 			case ICBTAG_FLAG_AD_SHORT:
@@ -1646,7 +1771,7 @@ int8_t udf_add_aext(struct inode *inode,
 				sad->extLength = cpu_to_le32(
 					EXT_NEXT_EXTENT_ALLOCDECS |
 					inode->i_sb->s_blocksize);
-				sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
+				sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
 				break;
 			}
 			case ICBTAG_FLAG_AD_LONG:
@@ -1655,60 +1780,57 @@ int8_t udf_add_aext(struct inode *inode,
 				lad->extLength = cpu_to_le32(
 					EXT_NEXT_EXTENT_ALLOCDECS |
 					inode->i_sb->s_blocksize);
-				lad->extLocation = cpu_to_lelb(*bloc);
+				lad->extLocation = cpu_to_lelb(epos->block);
 				memset(lad->impUse, 0x00, sizeof(lad->impUse));
 				break;
 			}
 		}
-		if (*bh)
+		if (epos->bh)
 		{
 			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag((*bh)->b_data, loffset);
+				udf_update_tag(epos->bh->b_data, loffset);
 			else
-				udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
-			mark_buffer_dirty_inode(*bh, inode);
-			udf_release_data(*bh);
+				udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(epos->bh, inode);
+			brelse(epos->bh);
 		}
 		else
 			mark_inode_dirty(inode);
-		*bh = nbh;
+		epos->bh = nbh;
 	}
 
-	etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc);
+	etype = udf_write_aext(inode, epos, eloc, elen, inc);
 
-	if (!*bh)
+	if (!epos->bh)
 	{
 		UDF_I_LENALLOC(inode) += adsize;
 		mark_inode_dirty(inode);
 	}
 	else
 	{
-		aed = (struct allocExtDesc *)(*bh)->b_data;
+		aed = (struct allocExtDesc *)epos->bh->b_data;
 		aed->lengthAllocDescs =
 			cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
 		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-			udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+			udf_update_tag(epos->bh->b_data, epos->offset + (inc ? 0 : adsize));
 		else
-			udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
-		mark_buffer_dirty_inode(*bh, inode);
+			udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
+		mark_buffer_dirty_inode(epos->bh, inode);
 	}
 
 	return etype;
 }
 
-int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset,
-    kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc)
+int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
+    kernel_lb_addr eloc, uint32_t elen, int inc)
 {
 	int adsize;
 	uint8_t *ptr;
 
-	if (!bh)
-		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+	if (!epos->bh)
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
 	else
-	{
-		ptr = bh->b_data + *extoffset;
-		atomic_inc(&bh->b_count);
-	}
+		ptr = epos->bh->b_data + epos->offset;
 
 	switch (UDF_I_ALLOCTYPE(inode))
 	{
@@ -1733,40 +1855,39 @@ int8_t udf_write_aext(struct inode *inod
 			return -1;
 	}
 
-	if (bh)
+	if (epos->bh)
 	{
 		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
 		{
-			struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data;
-			udf_update_tag((bh)->b_data,
+			struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data;
+			udf_update_tag(epos->bh->b_data,
 				le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
 		}
-		mark_buffer_dirty_inode(bh, inode);
-		udf_release_data(bh);
+		mark_buffer_dirty_inode(epos->bh, inode);
 	}
 	else
 		mark_inode_dirty(inode);
 
 	if (inc)
-		*extoffset += adsize;
+		epos->offset += adsize;
 	return (elen >> 30);
 }
 
-int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
-	kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
+	kernel_lb_addr *eloc, uint32_t *elen, int inc)
 {
 	int8_t etype;
 
-	while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) ==
+	while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
 		(EXT_NEXT_EXTENT_ALLOCDECS >> 30))
 	{
-		*bloc = *eloc;
-		*extoffset = sizeof(struct allocExtDesc);
-		udf_release_data(*bh);
-		if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
+		epos->block = *eloc;
+		epos->offset = sizeof(struct allocExtDesc);
+		brelse(epos->bh);
+		if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0))))
 		{
 			udf_debug("reading block %d failed!\n",
-				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+				udf_get_lb_pblock(inode->i_sb, epos->block, 0));
 			return -1;
 		}
 	}
@@ -1774,26 +1895,26 @@ int8_t udf_next_aext(struct inode *inode
 	return etype;
 }
 
-int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
-	kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
+	kernel_lb_addr *eloc, uint32_t *elen, int inc)
 {
 	int alen;
 	int8_t etype;
 	uint8_t *ptr;
 
-	if (!*bh)
+	if (!epos->bh)
 	{
-		if (!(*extoffset))
-			*extoffset = udf_file_entry_alloc_offset(inode);
-		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+		if (!epos->offset)
+			epos->offset = udf_file_entry_alloc_offset(inode);
+		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
 		alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
 	}
 	else
 	{
-		if (!(*extoffset))
-			*extoffset = sizeof(struct allocExtDesc);
-		ptr = (*bh)->b_data + *extoffset;
-		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
+		if (!epos->offset)
+			epos->offset = sizeof(struct allocExtDesc);
+		ptr = epos->bh->b_data + epos->offset;
+		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
 	}
 
 	switch (UDF_I_ALLOCTYPE(inode))
@@ -1802,7 +1923,7 @@ int8_t udf_current_aext(struct inode *in
 		{
 			short_ad *sad;
 
-			if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc)))
+			if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
 				return -1;
 
 			etype = le32_to_cpu(sad->extLength) >> 30;
@@ -1815,7 +1936,7 @@ int8_t udf_current_aext(struct inode *in
 		{
 			long_ad *lad;
 
-			if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc)))
+			if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
 				return -1;
 
 			etype = le32_to_cpu(lad->extLength) >> 30;
@@ -1834,41 +1955,40 @@ int8_t udf_current_aext(struct inode *in
 }
 
 static int8_t
-udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset,
-		kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh)
+udf_insert_aext(struct inode *inode, struct extent_position epos,
+		kernel_lb_addr neloc, uint32_t nelen)
 {
 	kernel_lb_addr oeloc;
 	uint32_t oelen;
 	int8_t etype;
 
-	if (bh)
-		atomic_inc(&bh->b_count);
+	if (epos.bh)
+		get_bh(epos.bh);
 
-	while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
+	while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1)
 	{
-		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
+		udf_write_aext(inode, &epos, neloc, nelen, 1);
 
 		neloc = oeloc;
 		nelen = (etype << 30) | oelen;
 	}
-	udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
-	udf_release_data(bh);
+	udf_add_aext(inode, &epos, neloc, nelen, 1);
+	brelse(epos.bh);
 	return (nelen >> 30);
 }
 
-int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset,
-	kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh)
+int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
+	kernel_lb_addr eloc, uint32_t elen)
 {
-	struct buffer_head *obh;
-	kernel_lb_addr obloc;
-	int oextoffset, adsize;
+	struct extent_position oepos;
+	int adsize;
 	int8_t etype;
 	struct allocExtDesc *aed;
 
-	if (nbh)
+	if (epos.bh)
 	{
-		atomic_inc(&nbh->b_count);
-		atomic_inc(&nbh->b_count);
+		get_bh(epos.bh);
+		get_bh(epos.bh);
 	}
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -1878,80 +1998,77 @@ int8_t udf_delete_aext(struct inode *ino
 	else
 		adsize = 0;
 
-	obh = nbh;
-	obloc = nbloc;
-	oextoffset = nextoffset;
-
-	if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
+	oepos = epos;
+	if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)
 		return -1;
 
-	while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+	while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
 	{
-		udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1);
-		if (obh != nbh)
+		udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1);
+		if (oepos.bh != epos.bh)
 		{
-			obloc = nbloc;
-			udf_release_data(obh);
-			atomic_inc(&nbh->b_count);
-			obh = nbh;
-			oextoffset = nextoffset - adsize;
+			oepos.block = epos.block;
+			brelse(oepos.bh);
+			get_bh(epos.bh);
+			oepos.bh = epos.bh;
+			oepos.offset = epos.offset - adsize;
 		}
 	}
 	memset(&eloc, 0x00, sizeof(kernel_lb_addr));
 	elen = 0;
 
-	if (nbh != obh)
+	if (epos.bh != oepos.bh)
 	{
-		udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1);
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
-		if (!obh)
+		udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1);
+		udf_write_aext(inode, &oepos, eloc, elen, 1);
+		udf_write_aext(inode, &oepos, eloc, elen, 1);
+		if (!oepos.bh)
 		{
 			UDF_I_LENALLOC(inode) -= (adsize * 2);
 			mark_inode_dirty(inode);
 		}
 		else
 		{
-			aed = (struct allocExtDesc *)(obh)->b_data;
+			aed = (struct allocExtDesc *)oepos.bh->b_data;
 			aed->lengthAllocDescs =
 				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
 			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+				udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize));
 			else
-				udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
-			mark_buffer_dirty_inode(obh, inode);
+				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(oepos.bh, inode);
 		}
 	}
 	else
 	{
-		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
-		if (!obh)
+		udf_write_aext(inode, &oepos, eloc, elen, 1);
+		if (!oepos.bh)
 		{
 			UDF_I_LENALLOC(inode) -= adsize;
 			mark_inode_dirty(inode);
 		}
 		else
 		{
-			aed = (struct allocExtDesc *)(obh)->b_data;
+			aed = (struct allocExtDesc *)oepos.bh->b_data;
 			aed->lengthAllocDescs =
 				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
 			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag((obh)->b_data, oextoffset - adsize);
+				udf_update_tag(oepos.bh->b_data, epos.offset - adsize);
 			else
-				udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
-			mark_buffer_dirty_inode(obh, inode);
+				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(oepos.bh, inode);
 		}
 	}
 	
-	udf_release_data(nbh);
-	udf_release_data(obh);
+	brelse(epos.bh);
+	brelse(oepos.bh);
 	return (elen >> 30);
 }
 
-int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset,
-	kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh)
+int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
+	kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)
 {
-	uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits;
+	loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits;
 	int8_t etype;
 
 	if (block < 0)
@@ -1960,42 +2077,44 @@ int8_t inode_bmap(struct inode *inode, i
 		return -1;
 	}
 
-	*extoffset = 0;
+	pos->offset = 0;
+	pos->block = UDF_I_LOCATION(inode);
+	pos->bh = NULL;
 	*elen = 0;
-	*bloc = UDF_I_LOCATION(inode);
 
 	do
 	{
-		if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
+		if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1)
 		{
-			*offset = bcount - lbcount;
+			*offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
 			UDF_I_LENEXTENTS(inode) = lbcount;
 			return -1;
 		}
 		lbcount += *elen;
 	} while (lbcount <= bcount);
 
-	*offset = bcount + *elen - lbcount;
+	*offset = (bcount + *elen - lbcount) >> inode->i_sb->s_blocksize_bits;
 
 	return etype;
 }
 
-long udf_block_map(struct inode *inode, long block)
+long udf_block_map(struct inode *inode, sector_t block)
 {
-	kernel_lb_addr eloc, bloc;
-	uint32_t offset, extoffset, elen;
-	struct buffer_head *bh = NULL;
+	kernel_lb_addr eloc;
+	uint32_t elen;
+	sector_t offset;
+	struct extent_position epos = { NULL, 0, { 0, 0}};
 	int ret;
 
 	lock_kernel();
 
-	if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
-		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits);
+	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
+		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
 	else
 		ret = 0;
 
 	unlock_kernel();
-	udf_release_data(bh);
+	brelse(epos.bh);
 
 	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
 		return udf_fixed_to_variable(ret);
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index cc8ca32..a2b2a98 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -274,12 +274,6 @@ udf_read_ptagged(struct super_block *sb,
 		loc.logicalBlockNum + offset, ident);
 }
 
-void udf_release_data(struct buffer_head *bh)
-{
-	if (bh)
-		brelse(bh);
-}
-
 void udf_update_tag(char *data, int length)
 {
 	tag *tptr = (tag *)data;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index fe361cd..91df492 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -155,9 +155,10 @@ udf_find_entry(struct inode *dir, struct
 	uint8_t lfi;
 	uint16_t liu;
 	loff_t size;
-	kernel_lb_addr bloc, eloc;
-	uint32_t extoffset, elen, offset;
-	struct buffer_head *bh = NULL;
+	kernel_lb_addr eloc;
+	uint32_t elen;
+	sector_t offset;
+	struct extent_position epos = { NULL, 0, { 0, 0}};
 
 	size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	f_pos = (udf_ext0_offset(dir) >> 2);
@@ -166,42 +167,41 @@ udf_find_entry(struct inode *dir, struct
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
 		fibh->sbh = fibh->ebh = NULL;
 	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+		&epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
 	{
-		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
-				extoffset -= sizeof(short_ad);
+				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
-				extoffset -= sizeof(long_ad);
+				epos.offset -= sizeof(long_ad);
 		}
 		else
 			offset = 0;
 
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 		{
-			udf_release_data(bh);
+			brelse(epos.bh);
 			return NULL;
 		}
 	}
 	else
 	{
-		udf_release_data(bh);
+		brelse(epos.bh);
 		return NULL;
 	}
 
 	while ( (f_pos < size) )
 	{
-		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
 
 		if (!fi)
 		{
 			if (fibh->sbh != fibh->ebh)
-				udf_release_data(fibh->ebh);
-			udf_release_data(fibh->sbh);
-			udf_release_data(bh);
+				brelse(fibh->ebh);
+			brelse(fibh->sbh);
+			brelse(epos.bh);
 			return NULL;
 		}
 
@@ -247,15 +247,15 @@ udf_find_entry(struct inode *dir, struct
 		{
 			if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
 			{
-				udf_release_data(bh);
+				brelse(epos.bh);
 				return fi;
 			}
 		}
 	}
 	if (fibh->sbh != fibh->ebh)
-		udf_release_data(fibh->ebh);
-	udf_release_data(fibh->sbh);
-	udf_release_data(bh);
+		brelse(fibh->ebh);
+	brelse(fibh->sbh);
+	brelse(epos.bh);
 	return NULL;
 }
 
@@ -321,8 +321,8 @@ #endif /* UDF_RECOVERY */
 	if (udf_find_entry(dir, dentry, &fibh, &cfi))
 	{
 		if (fibh.sbh != fibh.ebh)
-			udf_release_data(fibh.ebh);
-		udf_release_data(fibh.sbh);
+			brelse(fibh.ebh);
+		brelse(fibh.sbh);
 
 		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
 		if ( !inode )
@@ -353,9 +353,10 @@ udf_add_entry(struct inode *dir, struct 
 	uint8_t lfi;
 	uint16_t liu;
 	int block;
-	kernel_lb_addr bloc, eloc;
-	uint32_t extoffset, elen, offset;
-	struct buffer_head *bh = NULL;
+	kernel_lb_addr eloc;
+	uint32_t elen;
+	sector_t offset;
+	struct extent_position epos = { NULL, 0, { 0, 0 }};
 
 	sb = dir->i_sb;
 
@@ -384,23 +385,22 @@ udf_add_entry(struct inode *dir, struct 
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
 		fibh->sbh = fibh->ebh = NULL;
 	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+		&epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
 	{
-		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
-				extoffset -= sizeof(short_ad);
+				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
-				extoffset -= sizeof(long_ad);
+				epos.offset -= sizeof(long_ad);
 		}
 		else
 			offset = 0;
 
 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
 		{
-			udf_release_data(bh);
+			brelse(epos.bh);
 			*err = -EIO;
 			return NULL;
 		}
@@ -418,14 +418,14 @@ udf_add_entry(struct inode *dir, struct 
 
 	while ( (f_pos < size) )
 	{
-		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
 
 		if (!fi)
 		{
 			if (fibh->sbh != fibh->ebh)
-				udf_release_data(fibh->ebh);
-			udf_release_data(fibh->sbh);
-			udf_release_data(bh);
+				brelse(fibh->ebh);
+			brelse(fibh->sbh);
+			brelse(epos.bh);
 			*err = -EIO;
 			return NULL;
 		}
@@ -455,7 +455,7 @@ udf_add_entry(struct inode *dir, struct 
 		{
 			if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
 			{
-				udf_release_data(bh);
+				brelse(epos.bh);
 				cfi->descTag.tagSerialNum = cpu_to_le16(1);
 				cfi->fileVersionNum = cpu_to_le16(1);
 				cfi->fileCharacteristics = 0;
@@ -478,9 +478,9 @@ udf_add_entry(struct inode *dir, struct 
 			udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
 		{
 			if (fibh->sbh != fibh->ebh)
-				udf_release_data(fibh->ebh);
-			udf_release_data(fibh->sbh);
-			udf_release_data(bh);
+				brelse(fibh->ebh);
+			brelse(fibh->sbh);
+			brelse(epos.bh);
 			*err = -EEXIST;
 			return NULL;
 		}
@@ -492,25 +492,25 @@ add:
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
 		sb->s_blocksize - fibh->eoffset < nfidlen)
 	{
-		udf_release_data(bh);
-		bh = NULL;
+		brelse(epos.bh);
+		epos.bh = NULL;
 		fibh->soffset -= udf_ext0_offset(dir);
 		fibh->eoffset -= udf_ext0_offset(dir);
 		f_pos -= (udf_ext0_offset(dir) >> 2);
 		if (fibh->sbh != fibh->ebh)
-			udf_release_data(fibh->ebh);
-		udf_release_data(fibh->sbh);
+			brelse(fibh->ebh);
+		brelse(fibh->sbh);
 		if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
 			return NULL;
-		bloc = UDF_I_LOCATION(dir);
+		epos.block = UDF_I_LOCATION(dir);
 		eloc.logicalBlockNum = block;
 		eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
 		elen = dir->i_sb->s_blocksize;
-		extoffset = udf_file_entry_alloc_offset(dir);
+		epos.offset = udf_file_entry_alloc_offset(dir);
 		if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
-			extoffset += sizeof(short_ad);
+			epos.offset += sizeof(short_ad);
 		else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
-			extoffset += sizeof(long_ad);
+			epos.offset += sizeof(long_ad);
 	}
 
 	if (sb->s_blocksize - fibh->eoffset >= nfidlen)
@@ -519,7 +519,7 @@ add:
 		fibh->eoffset += nfidlen;
 		if (fibh->sbh != fibh->ebh)
 		{
-			udf_release_data(fibh->sbh);
+			brelse(fibh->sbh);
 			fibh->sbh = fibh->ebh;
 		}
 
@@ -541,7 +541,7 @@ add:
 		fibh->eoffset += nfidlen - sb->s_blocksize;
 		if (fibh->sbh != fibh->ebh)
 		{
-			udf_release_data(fibh->sbh);
+			brelse(fibh->sbh);
 			fibh->sbh = fibh->ebh;
 		}
 
@@ -550,14 +550,14 @@ add:
 
 		if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
 		{
-			udf_release_data(bh);
-			udf_release_data(fibh->sbh);
+			brelse(epos.bh);
+			brelse(fibh->sbh);
 			return NULL;
 		}
 
 		if (!(fibh->soffset))
 		{
-			if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) ==
+			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
 				(EXT_RECORDED_ALLOCATED >> 30))
 			{
 				block = eloc.logicalBlockNum + ((elen - 1) >>
@@ -566,7 +566,7 @@ add:
 			else
 				block ++;
 
-			udf_release_data(fibh->sbh);
+			brelse(fibh->sbh);
 			fibh->sbh = fibh->ebh;
 			fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
 		}
@@ -587,7 +587,7 @@ add:
 	cfi->lengthOfImpUse = cpu_to_le16(0);
 	if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
 	{
-		udf_release_data(bh);
+		brelse(epos.bh);
 		dir->i_size += nfidlen;
 		if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
 			UDF_I_LENALLOC(dir) += nfidlen;
@@ -596,10 +596,10 @@ add:
 	}
 	else
 	{
-		udf_release_data(bh);
+		brelse(epos.bh);
 		if (fibh->sbh != fibh->ebh)
-			udf_release_data(fibh->ebh);
-		udf_release_data(fibh->sbh);
+			brelse(fibh->ebh);
+		brelse(fibh->sbh);
 		*err = -EIO;
 		return NULL;
 	}
@@ -656,8 +656,8 @@ static int udf_create(struct inode *dir,
 		mark_inode_dirty(dir);
 	}
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 	unlock_kernel();
 	d_instantiate(dentry, inode);
 	return 0;
@@ -701,8 +701,8 @@ static int udf_mknod(struct inode * dir,
 	mark_inode_dirty(inode);
 
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 	d_instantiate(dentry, inode);
 	err = 0;
 out:
@@ -743,7 +743,7 @@ static int udf_mkdir(struct inode * dir,
 		cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
 	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
-	udf_release_data(fibh.sbh);
+	brelse(fibh.sbh);
 	inode->i_mode = S_IFDIR | mode;
 	if (dir->i_mode & S_ISGID)
 		inode->i_mode |= S_ISGID;
@@ -766,8 +766,8 @@ static int udf_mkdir(struct inode * dir,
 	mark_inode_dirty(dir);
 	d_instantiate(dentry, inode);
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 	err = 0;
 out:
 	unlock_kernel();
@@ -781,9 +781,10 @@ static int empty_dir(struct inode *dir)
 	loff_t f_pos;
 	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
 	int block;
-	kernel_lb_addr bloc, eloc;
-	uint32_t extoffset, elen, offset;
-	struct buffer_head *bh = NULL;
+	kernel_lb_addr eloc;
+	uint32_t elen;
+	sector_t offset;
+	struct extent_position epos = { NULL, 0, { 0, 0}};
 
 	f_pos = (udf_ext0_offset(dir) >> 2);
 
@@ -792,59 +793,58 @@ static int empty_dir(struct inode *dir)
 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
 		fibh.sbh = fibh.ebh = NULL;
 	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+		&epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
 	{
-		offset >>= dir->i_sb->s_blocksize_bits;
 		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
 		if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
 		{
 			if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
-				extoffset -= sizeof(short_ad);
+				epos.offset -= sizeof(short_ad);
 			else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
-				extoffset -= sizeof(long_ad);
+				epos.offset -= sizeof(long_ad);
 		}
 		else
 			offset = 0;
 
 		if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
 		{
-			udf_release_data(bh);
+			brelse(epos.bh);
 			return 0;
 		}
 	}
 	else
 	{
-		udf_release_data(bh);
+		brelse(epos.bh);
 		return 0;
 	}
 
 
 	while ( (f_pos < size) )
 	{
-		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
 
 		if (!fi)
 		{
 			if (fibh.sbh != fibh.ebh)
-				udf_release_data(fibh.ebh);
-			udf_release_data(fibh.sbh);
-			udf_release_data(bh);
+				brelse(fibh.ebh);
+			brelse(fibh.sbh);
+			brelse(epos.bh);
 			return 0;
 		}
 
 		if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
 		{
 			if (fibh.sbh != fibh.ebh)
-				udf_release_data(fibh.ebh);
-			udf_release_data(fibh.sbh);
-			udf_release_data(bh);
+				brelse(fibh.ebh);
+			brelse(fibh.sbh);
+			brelse(epos.bh);
 			return 0;
 		}
 	}
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
-	udf_release_data(bh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
+	brelse(epos.bh);
 	return 1;
 }
 
@@ -878,14 +878,14 @@ static int udf_rmdir(struct inode * dir,
 			inode->i_nlink);
 	clear_nlink(inode);
 	inode->i_size = 0;
-	inode_dec_link_count(inode);
+	inode_dec_link_count(dir);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
 	mark_inode_dirty(dir);
 
 end_rmdir:
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 out:
 	unlock_kernel();
 	return retval;
@@ -928,8 +928,8 @@ static int udf_unlink(struct inode * dir
 
 end_unlink:
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 out:
 	unlock_kernel();
 	return retval;
@@ -941,7 +941,7 @@ static int udf_symlink(struct inode * di
 	struct pathComponent *pc;
 	char *compstart;
 	struct udf_fileident_bh fibh;
-	struct buffer_head *bh = NULL;
+	struct extent_position epos = { NULL,  0, {0, 0}};
 	int eoffset, elen = 0;
 	struct fileIdentDesc *fi;
 	struct fileIdentDesc cfi;
@@ -961,33 +961,33 @@ static int udf_symlink(struct inode * di
 
 	if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
 	{
-		struct buffer_head *bh = NULL;
-		kernel_lb_addr bloc, eloc;
-		uint32_t elen, extoffset;
+		kernel_lb_addr eloc;
+		uint32_t elen;
 
 		block = udf_new_block(inode->i_sb, inode,
 			UDF_I_LOCATION(inode).partitionReferenceNum,
 			UDF_I_LOCATION(inode).logicalBlockNum, &err);
 		if (!block)
 			goto out_no_entry;
-		bloc = UDF_I_LOCATION(inode);
+		epos.block = UDF_I_LOCATION(inode);
+		epos.offset = udf_file_entry_alloc_offset(inode);
+		epos.bh = NULL;
 		eloc.logicalBlockNum = block;
 		eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
 		elen = inode->i_sb->s_blocksize;
 		UDF_I_LENEXTENTS(inode) = elen;
-		extoffset = udf_file_entry_alloc_offset(inode);
-		udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
-		udf_release_data(bh);
+		udf_add_aext(inode, &epos, eloc, elen, 0);
+		brelse(epos.bh);
 
 		block = udf_get_pblock(inode->i_sb, block,
 			UDF_I_LOCATION(inode).partitionReferenceNum, 0);
-		bh = udf_tread(inode->i_sb, block);
-		lock_buffer(bh);
-		memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
-		set_buffer_uptodate(bh);
-		unlock_buffer(bh);
-		mark_buffer_dirty_inode(bh, inode);
-		ea = bh->b_data + udf_ext0_offset(inode);
+		epos.bh = udf_tread(inode->i_sb, block);
+		lock_buffer(epos.bh);
+		memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
+		set_buffer_uptodate(epos.bh);
+		unlock_buffer(epos.bh);
+		mark_buffer_dirty_inode(epos.bh, inode);
+		ea = epos.bh->b_data + udf_ext0_offset(inode);
 	}
 	else
 		ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
@@ -1060,7 +1060,7 @@ static int udf_symlink(struct inode * di
 		}
 	}
 
-	udf_release_data(bh);
+	brelse(epos.bh);
 	inode->i_size = elen;
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
 		UDF_I_LENALLOC(inode) = inode->i_size;
@@ -1089,8 +1089,8 @@ static int udf_symlink(struct inode * di
 		mark_inode_dirty(dir);
 	}
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 	d_instantiate(dentry, inode);
 	err = 0;
 
@@ -1145,8 +1145,8 @@ static int udf_link(struct dentry * old_
 		mark_inode_dirty(dir);
 	}
 	if (fibh.sbh != fibh.ebh)
-		udf_release_data(fibh.ebh);
-	udf_release_data(fibh.sbh);
+		brelse(fibh.ebh);
+	brelse(fibh.sbh);
 	inc_nlink(inode);
 	inode->i_ctime = current_fs_time(inode->i_sb);
 	mark_inode_dirty(inode);
@@ -1174,8 +1174,8 @@ static int udf_rename (struct inode * ol
 	if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
 	{
 		if (ofibh.sbh != ofibh.ebh)
-			udf_release_data(ofibh.ebh);
-		udf_release_data(ofibh.sbh);
+			brelse(ofibh.ebh);
+		brelse(ofibh.sbh);
 	}
 	tloc = lelb_to_cpu(ocfi.icb.extLocation);
 	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
@@ -1188,8 +1188,8 @@ static int udf_rename (struct inode * ol
 		if (!new_inode)
 		{
 			if (nfibh.sbh != nfibh.ebh)
-				udf_release_data(nfibh.ebh);
-			udf_release_data(nfibh.sbh);
+				brelse(nfibh.ebh);
+			brelse(nfibh.sbh);
 			nfi = NULL;
 		}
 	}
@@ -1290,19 +1290,19 @@ static int udf_rename (struct inode * ol
 	if (ofi)
 	{
 		if (ofibh.sbh != ofibh.ebh)
-			udf_release_data(ofibh.ebh);
-		udf_release_data(ofibh.sbh);
+			brelse(ofibh.ebh);
+		brelse(ofibh.sbh);
 	}
 
 	retval = 0;
 
 end_rename:
-	udf_release_data(dir_bh);
+	brelse(dir_bh);
 	if (nfi)
 	{
 		if (nfibh.sbh != nfibh.ebh)
-			udf_release_data(nfibh.ebh);
-		udf_release_data(nfibh.sbh);
+			brelse(nfibh.ebh);
+		brelse(nfibh.sbh);
 	}
 	unlock_kernel();
 	return retval;
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index dabf2b8..467a261 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -81,7 +81,7 @@ uint32_t udf_get_pblock_virt15(struct su
 
 	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
 
-	udf_release_data(bh);
+	brelse(bh);
 
 	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
 	{
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 8672b88..9b8644a 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -134,9 +134,7 @@ static void init_once(void * foo, struct
 {
 	struct udf_inode_info *ei = (struct udf_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
-	{
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		ei->i_ext.i_data = NULL;
 		inode_init_once(&ei->vfs_inode);
 	}
@@ -565,7 +563,7 @@ udf_vrs(struct super_block *sb, int sile
 
 		if (vsd->stdIdent[0] == 0)
 		{
-			udf_release_data(bh);
+			brelse(bh);
 			break;
 		}
 		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN))
@@ -598,7 +596,7 @@ udf_vrs(struct super_block *sb, int sile
 		}
 		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN))
 		{
-			udf_release_data(bh);
+			brelse(bh);
 			break;
 		}
 		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
@@ -609,7 +607,7 @@ udf_vrs(struct super_block *sb, int sile
 		{
 			nsr03 = sector;
 		}
-		udf_release_data(bh);
+		brelse(bh);
 	}
 
 	if (nsr03)
@@ -675,7 +673,7 @@ udf_find_anchor(struct super_block *sb)
 			{
 				ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
 				location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
-				udf_release_data(bh);
+				brelse(bh);
 			}
 
 			if (ident == TAG_IDENT_AVDP)
@@ -710,7 +708,7 @@ udf_find_anchor(struct super_block *sb)
 				{
 					ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
 					location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
-					udf_release_data(bh);
+					brelse(bh);
 				}
 	
 				if (ident == TAG_IDENT_AVDP &&
@@ -729,7 +727,7 @@ udf_find_anchor(struct super_block *sb)
 					{
 						ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
 						location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
-						udf_release_data(bh);
+						brelse(bh);
 					}
 	
 					if (ident == TAG_IDENT_AVDP &&
@@ -751,7 +749,7 @@ udf_find_anchor(struct super_block *sb)
 		{
 			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
 			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
-			udf_release_data(bh);
+			brelse(bh);
 
 			if (ident == TAG_IDENT_AVDP && location == 256)
 				UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
@@ -768,7 +766,7 @@ udf_find_anchor(struct super_block *sb)
 			}
 			else
 			{
-				udf_release_data(bh);
+				brelse(bh);
 				if ((ident != TAG_IDENT_AVDP) && (i ||
 					(ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE)))
 				{
@@ -797,7 +795,7 @@ udf_find_fileset(struct super_block *sb,
 			return 1;
 		else if (ident != TAG_IDENT_FSD)
 		{
-			udf_release_data(bh);
+			brelse(bh);
 			return 1;
 		}
 			
@@ -836,7 +834,7 @@ udf_find_fileset(struct super_block *sb,
 						newfileset.logicalBlockNum += 1 +
 							((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1)
 								>> sb->s_blocksize_bits);
-						udf_release_data(bh);
+						brelse(bh);
 						break;
 					}
 					case TAG_IDENT_FSD:
@@ -847,7 +845,7 @@ udf_find_fileset(struct super_block *sb,
 					default:
 					{
 						newfileset.logicalBlockNum ++;
-						udf_release_data(bh);
+						brelse(bh);
 						bh = NULL;
 						break;
 					}
@@ -867,7 +865,7 @@ udf_find_fileset(struct super_block *sb,
 
 		UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
 		udf_load_fileset(sb, bh, root);
-		udf_release_data(bh);
+		brelse(bh);
 		return 0;
 	}
 	return 1;
@@ -1085,7 +1083,7 @@ udf_load_logicalvol(struct super_block *
 						if (ident != 0 ||
 							strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
 						{
-							udf_release_data(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
+							brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
 							UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
 						}
 					}
@@ -1139,12 +1137,12 @@ udf_load_logicalvolint(struct super_bloc
 			udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
 		
 		if (UDF_SB_LVIDBH(sb) != bh)
-			udf_release_data(bh);
+			brelse(bh);
 		loc.extLength -= sb->s_blocksize;
 		loc.extLocation ++;
 	}
 	if (UDF_SB_LVIDBH(sb) != bh)
-		udf_release_data(bh);
+		brelse(bh);
 }
 
 /*
@@ -1247,7 +1245,7 @@ udf_process_sequence(struct super_block 
 					done = 1;
 				break;
 		}
-		udf_release_data(bh);
+		brelse(bh);
 	}
 	for (i=0; i<VDS_POS_LENGTH; i++)
 	{
@@ -1269,10 +1267,10 @@ udf_process_sequence(struct super_block 
 					gd = (struct generic_desc *)bh2->b_data;
 					if (ident == TAG_IDENT_PD)
 						udf_load_partdesc(sb, bh2);
-					udf_release_data(bh2);
+					brelse(bh2);
 				}
 			}
-			udf_release_data(bh);
+			brelse(bh);
 		}
 	}
 
@@ -1335,7 +1333,7 @@ udf_load_partition(struct super_block *s
 			reserve_e = reserve_e >> sb->s_blocksize_bits;
 			reserve_e += reserve_s;
 
-			udf_release_data(bh);
+			brelse(bh);
 
 			/* Process the main & reserve sequences */
 			/* responsible for finding the PartitionDesc(s) */
@@ -1405,12 +1403,14 @@ udf_load_partition(struct super_block *s
 
 					pos = udf_block_map(UDF_SB_VAT(sb), 0);
 					bh = sb_bread(sb, pos);
+					if (!bh)
+						return 1;
 					UDF_SB_TYPEVIRT(sb,i).s_start_offset =
 						le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
 							udf_ext0_offset(UDF_SB_VAT(sb));
 					UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
 						UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
-					udf_release_data(bh);
+					brelse(bh);
 				}
 				UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
 				UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
@@ -1663,7 +1663,7 @@ #endif
 		iput(inode);
 		goto error_out;
 	}
-	sb->s_maxbytes = 1<<30;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	return 0;
 
 error_out:
@@ -1682,7 +1682,7 @@ error_out:
 		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
 		{
 			for (i=0; i<4; i++)
-				udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+				brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
 		}
 	}
 #ifdef CONFIG_UDF_NLS
@@ -1691,7 +1691,7 @@ #ifdef CONFIG_UDF_NLS
 #endif
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_close_lvid(sb);
-	udf_release_data(UDF_SB_LVIDBH(sb));
+	brelse(UDF_SB_LVIDBH(sb));
 	UDF_SB_FREE(sb);
 	kfree(sbi);
 	sb->s_fs_info = NULL;
@@ -1760,7 +1760,7 @@ udf_put_super(struct super_block *sb)
 		if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
 		{
 			for (i=0; i<4; i++)
-				udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+				brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
 		}
 	}
 #ifdef CONFIG_UDF_NLS
@@ -1769,7 +1769,7 @@ #ifdef CONFIG_UDF_NLS
 #endif
 	if (!(sb->s_flags & MS_RDONLY))
 		udf_close_lvid(sb);
-	udf_release_data(UDF_SB_LVIDBH(sb));
+	brelse(UDF_SB_LVIDBH(sb));
 	UDF_SB_FREE(sb);
 	kfree(sb->s_fs_info);
 	sb->s_fs_info = NULL;
@@ -1839,7 +1839,7 @@ udf_count_free_bitmap(struct super_block
 	}
 	else if (ident != TAG_IDENT_SBD)
 	{
-		udf_release_data(bh);
+		brelse(bh);
 		printk(KERN_ERR "udf: udf_count_free failed\n");
 		goto out;
 	}
@@ -1861,7 +1861,7 @@ udf_count_free_bitmap(struct super_block
 		}
 		if ( bytes )
 		{
-			udf_release_data(bh);
+			brelse(bh);
 			newblock = udf_get_lb_pblock(sb, loc, ++block);
 			bh = udf_tread(sb, newblock);
 			if (!bh)
@@ -1873,7 +1873,7 @@ udf_count_free_bitmap(struct super_block
 			ptr = (uint8_t *)bh->b_data;
 		}
 	}
-	udf_release_data(bh);
+	brelse(bh);
 
 out:
 	unlock_kernel();
@@ -1885,21 +1885,20 @@ static unsigned int
 udf_count_free_table(struct super_block *sb, struct inode * table)
 {
 	unsigned int accum = 0;
-	uint32_t extoffset, elen;
-	kernel_lb_addr bloc, eloc;
+	uint32_t elen;
+	kernel_lb_addr eloc;
 	int8_t etype;
-	struct buffer_head *bh = NULL;
+	struct extent_position epos;
 
 	lock_kernel();
 
-	bloc = UDF_I_LOCATION(table);
-	extoffset = sizeof(struct unallocSpaceEntry);
+	epos.block = UDF_I_LOCATION(table);
+	epos.offset = sizeof(struct unallocSpaceEntry);
+	epos.bh = NULL;
 
-	while ((etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
-	{
+	while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
 		accum += (elen >> table->i_sb->s_blocksize_bits);
-	}
-	udf_release_data(bh);
+	brelse(epos.bh);
 
 	unlock_kernel();
 
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index ba068a7..12613b6 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -95,7 +95,7 @@ static int udf_symlink_filler(struct fil
 	}
 
 	udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
-	udf_release_data(bh);
+	brelse(bh);
 
 	unlock_kernel();
 	SetPageUptodate(page);
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 0abd66c..77975ae 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -28,8 +28,8 @@ #include <linux/buffer_head.h>
 #include "udf_i.h"
 #include "udf_sb.h"
 
-static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset,
-	kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen)
+static void extent_trunc(struct inode * inode, struct extent_position *epos,
+	kernel_lb_addr eloc, int8_t etype, uint32_t elen, uint32_t nelen)
 {
 	kernel_lb_addr neloc = { 0, 0 };
 	int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
@@ -49,7 +49,7 @@ static void extent_trunc(struct inode * 
 
 	if (elen != nelen)
 	{
-		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
+		udf_write_aext(inode, epos, neloc, nelen, 0);
 		if (last_block - first_block > 0)
 		{
 			if (etype == (EXT_RECORDED_ALLOCATED >> 30))
@@ -63,18 +63,16 @@ static void extent_trunc(struct inode * 
 
 void udf_discard_prealloc(struct inode * inode)
 {
-	kernel_lb_addr bloc, eloc;
-	uint32_t extoffset = 0, elen, nelen;
+	struct extent_position epos = { NULL, 0, {0, 0}};
+	kernel_lb_addr eloc;
+	uint32_t elen, nelen;
 	uint64_t lbcount = 0;
 	int8_t etype = -1, netype;
-	struct buffer_head *bh = NULL;
 	int adsize;
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
 		inode->i_size == UDF_I_LENEXTENTS(inode))
-	{
 		return;
-	}
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
 		adsize = sizeof(short_ad);
@@ -83,52 +81,58 @@ void udf_discard_prealloc(struct inode *
 	else
 		adsize = 0;
 
-	bloc = UDF_I_LOCATION(inode);
+	epos.block = UDF_I_LOCATION(inode);
 
-	while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+	/* Find the last extent in the file */
+	while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
 	{
 		etype = netype;
 		lbcount += elen;
-		if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
+		if (lbcount > inode->i_size && lbcount - elen < inode->i_size)
 		{
+			WARN_ON(lbcount - inode->i_size >= inode->i_sb->s_blocksize);
 			nelen = elen - (lbcount - inode->i_size);
-			extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
+			epos.offset -= adsize;
+			extent_trunc(inode, &epos, eloc, etype, elen, nelen);
+			epos.offset += adsize;
 			lbcount = inode->i_size;
 		}
 	}
-	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-	{
-		extoffset -= adsize;
+	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+		epos.offset -= adsize;
 		lbcount -= elen;
-		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
-		if (!bh)
+		extent_trunc(inode, &epos, eloc, etype, elen, 0);
+		if (!epos.bh)
 		{
-			UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
+			UDF_I_LENALLOC(inode) = epos.offset - udf_file_entry_alloc_offset(inode);
 			mark_inode_dirty(inode);
 		}
 		else
 		{
-			struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
-			aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
+			struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
+			aed->lengthAllocDescs = cpu_to_le32(epos.offset - sizeof(struct allocExtDesc));
 			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-				udf_update_tag(bh->b_data, extoffset);
+				udf_update_tag(epos.bh->b_data, epos.offset);
 			else
-				udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
-			mark_buffer_dirty_inode(bh, inode);
+				udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+			mark_buffer_dirty_inode(epos.bh, inode);
 		}
 	}
 	UDF_I_LENEXTENTS(inode) = lbcount;
 
-	udf_release_data(bh);
+	WARN_ON(lbcount != inode->i_size);
+	brelse(epos.bh);
 }
 
 void udf_truncate_extents(struct inode * inode)
 {
-	kernel_lb_addr bloc, eloc, neloc = { 0, 0 };
-	uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
+	struct extent_position epos;
+	kernel_lb_addr eloc, neloc = { 0, 0 };
+	uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
 	int8_t etype;
-	int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
-	struct buffer_head *bh = NULL;
+	struct super_block *sb = inode->i_sb;
+	sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
+	loff_t byte_offset;
 	int adsize;
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -136,158 +140,130 @@ void udf_truncate_extents(struct inode *
 	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
 		adsize = sizeof(long_ad);
 	else
-		adsize = 0;
+		BUG();
 
-	etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
-	offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
+	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+	byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1));
 	if (etype != -1)
 	{
-		extoffset -= adsize;
-		extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
-		extoffset += adsize;
-
-		if (offset)
-			lenalloc = extoffset;
+		epos.offset -= adsize;
+		extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
+		epos.offset += adsize;
+		if (byte_offset)
+			lenalloc = epos.offset;
 		else
-			lenalloc = extoffset - adsize;
+			lenalloc = epos.offset - adsize;
 
-		if (!bh)
+		if (!epos.bh)
 			lenalloc -= udf_file_entry_alloc_offset(inode);
 		else
 			lenalloc -= sizeof(struct allocExtDesc);
 
-		while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
+		while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1)
 		{
 			if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
 			{
-				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
-				extoffset = 0;
-				if (lelen)
+				udf_write_aext(inode, &epos, neloc, nelen, 0);
+				if (indirect_ext_len)
 				{
-					if (!bh)
+					/* We managed to free all extents in the
+					 * indirect extent - free it too */
+					if (!epos.bh)
 						BUG();
-					else
-						memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
-					udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
+					udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
 				}
 				else
 				{
-					if (!bh)
+					if (!epos.bh)
 					{
 						UDF_I_LENALLOC(inode) = lenalloc;
 						mark_inode_dirty(inode);
 					}
 					else
 					{
-						struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+						struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
 						aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-						if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-							udf_update_tag(bh->b_data, lenalloc +
+						if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
+							udf_update_tag(epos.bh->b_data, lenalloc +
 								sizeof(struct allocExtDesc));
 						else
-							udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
-						mark_buffer_dirty_inode(bh, inode);
+							udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+						mark_buffer_dirty_inode(epos.bh, inode);
 					}
 				}
-
-				udf_release_data(bh);
-				extoffset = sizeof(struct allocExtDesc);
-				bloc = eloc;
-				bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0));
+				brelse(epos.bh);
+				epos.offset = sizeof(struct allocExtDesc);
+				epos.block = eloc;
+				epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
 				if (elen)
-					lelen = (elen + inode->i_sb->s_blocksize - 1) >>
-						inode->i_sb->s_blocksize_bits;
+					indirect_ext_len = (elen +
+						sb->s_blocksize - 1) >>
+						sb->s_blocksize_bits;
 				else
-					lelen = 1;
+					indirect_ext_len = 1;
 			}
 			else
 			{
-				extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
-				extoffset += adsize;
+				extent_trunc(inode, &epos, eloc, etype, elen, 0);
+				epos.offset += adsize;
 			}
 		}
 
-		if (lelen)
+		if (indirect_ext_len)
 		{
-			if (!bh)
+			if (!epos.bh)
 				BUG();
-			else
-				memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
-			udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
+			udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
 		}
 		else
 		{
-			if (!bh)
+			if (!epos.bh)
 			{
 				UDF_I_LENALLOC(inode) = lenalloc;
 				mark_inode_dirty(inode);
 			}
 			else
 			{
-				struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+				struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
 				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-				if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
-					udf_update_tag(bh->b_data, lenalloc +
+				if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
+					udf_update_tag(epos.bh->b_data, lenalloc +
 						sizeof(struct allocExtDesc));
 				else
-					udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
-				mark_buffer_dirty_inode(bh, inode);
+					udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+				mark_buffer_dirty_inode(epos.bh, inode);
 			}
 		}
 	}
 	else if (inode->i_size)
 	{
-		if (offset)
+		if (byte_offset)
 		{
+			kernel_long_ad extent;
+
 			/*
 			 *  OK, there is not extent covering inode->i_size and
 			 *  no extent above inode->i_size => truncate is
-			 *  extending the file by 'offset'.
+			 *  extending the file by 'offset' blocks.
 			 */
-			if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
-			    (bh && extoffset == sizeof(struct allocExtDesc))) {
-				/* File has no extents at all! */
-				memset(&eloc, 0x00, sizeof(kernel_lb_addr));
-				elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
-				udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
+			if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+			    (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
+				/* File has no extents at all or has empty last
+				 * indirect extent! Create a fake extent... */
+				extent.extLocation.logicalBlockNum = 0;
+				extent.extLocation.partitionReferenceNum = 0;
+				extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
 			}
 			else {
-				extoffset -= adsize;
-				etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
-				if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
-				{
-					extoffset -= adsize;
-					elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
-					udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
-				}
-				else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
-				{
-					kernel_lb_addr neloc = { 0, 0 };
-					extoffset -= adsize;
-					nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
-						((elen + offset + inode->i_sb->s_blocksize - 1) &
-						~(inode->i_sb->s_blocksize - 1));
-					udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
-					udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
-				}
-				else
-				{
-					if (elen & (inode->i_sb->s_blocksize - 1))
-					{
-						extoffset -= adsize;
-						elen = EXT_RECORDED_ALLOCATED |
-							((elen + inode->i_sb->s_blocksize - 1) &
-							~(inode->i_sb->s_blocksize - 1));
-						udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
-					}
-					memset(&eloc, 0x00, sizeof(kernel_lb_addr));
-					elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
-					udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
-				}
+				epos.offset -= adsize;
+				etype = udf_next_aext(inode, &epos,
+					&extent.extLocation, &extent.extLength, 0);
+				extent.extLength |= etype << 30;
 			}
+			udf_extend_file(inode, &epos, &extent, offset+((inode->i_size & (sb->s_blocksize-1)) != 0));
 		}
 	}
 	UDF_I_LENEXTENTS(inode) = inode->i_size;
 
-	udf_release_data(bh);
+	brelse(epos.bh);
 }
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 110f8d6..3b2e6c8 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -93,7 +93,7 @@ #define UDF_SB_FREE_BITMAP(X,Y,Z)\
 	for (i=0; i<nr_groups; i++)\
 	{\
 		if (UDF_SB_BITMAP(X,Y,Z,i))\
-			udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
+			brelse(UDF_SB_BITMAP(X,Y,Z,i));\
 	}\
 	if (size <= PAGE_SIZE)\
 		kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index ee1dece..67ded28 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -77,6 +77,13 @@ struct ustr
 	uint8_t u_len;
 };
 
+struct extent_position {
+	struct buffer_head *bh;
+	uint32_t offset;
+	kernel_lb_addr block;
+};
+
+
 /* super.c */
 extern void udf_error(struct super_block *, const char *, const char *, ...);
 extern void udf_warning(struct super_block *, const char *, const char *, ...);
@@ -98,13 +105,14 @@ extern void udf_read_inode(struct inode 
 extern void udf_delete_inode(struct inode *);
 extern void udf_clear_inode(struct inode *);
 extern int udf_write_inode(struct inode *, int);
-extern long udf_block_map(struct inode *, long);
-extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
-extern int8_t udf_add_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr, uint32_t, struct buffer_head **, int);
-extern int8_t udf_write_aext(struct inode *, kernel_lb_addr, int *, kernel_lb_addr, uint32_t, struct buffer_head *, int);
-extern int8_t udf_delete_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *);
-extern int8_t udf_next_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
-extern int8_t udf_current_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
+extern long udf_block_map(struct inode *, sector_t);
+extern int udf_extend_file(struct inode *, struct extent_position *, kernel_long_ad *, sector_t);
+extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
+extern int8_t udf_add_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
+extern int8_t udf_write_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position, kernel_lb_addr, uint32_t);
+extern int8_t udf_next_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
+extern int8_t udf_current_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
 
 /* misc.c */
 extern struct buffer_head *udf_tgetblk(struct super_block *, int);
@@ -113,7 +121,6 @@ extern struct genericFormat *udf_add_ext
 extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
 extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
 extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
-extern void udf_release_data(struct buffer_head *);
 extern void udf_update_tag(char *, int);
 extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
 
@@ -151,7 +158,7 @@ extern int udf_new_block(struct super_bl
 extern int udf_fsync_file(struct file *, struct dentry *, int);
 
 /* directory.c */
-extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
+extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
 extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
 extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
 extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 4890ddf..1544521 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -19,7 +19,6 @@
 #include <linux/time.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
-#include <linux/smp_lock.h>
 
 #include "swab.h"
 #include "util.h"
@@ -180,13 +179,9 @@ fail:
 static struct page *ufs_get_page(struct inode *dir, unsigned long n)
 {
 	struct address_space *mapping = dir->i_mapping;
-	struct page *page = read_cache_page(mapping, n,
-				(filler_t*)mapping->a_ops->readpage, NULL);
+	struct page *page = read_mapping_page(mapping, n, NULL);
 	if (!IS_ERR(page)) {
-		wait_on_page_locked(page);
 		kmap(page);
-		if (!PageUptodate(page))
-			goto fail;
 		if (!PageChecked(page))
 			ufs_check_page(page);
 		if (PageError(page))
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index b5a6461..be7c48c 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1237,8 +1237,7 @@ static void init_once(void * foo, struct
 {
 	struct ufs_inode_info *ei = (struct ufs_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
  
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 1743757..84357f1 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -251,13 +251,11 @@ struct page *ufs_get_locked_page(struct 
 
 	page = find_lock_page(mapping, index);
 	if (!page) {
-		page = read_cache_page(mapping, index,
-				       (filler_t*)mapping->a_ops->readpage,
-				       NULL);
+		page = read_mapping_page(mapping, index, NULL);
 
 		if (IS_ERR(page)) {
 			printk(KERN_ERR "ufs_change_blocknr: "
-			       "read_cache_page error: ino %lu, index: %lu\n",
+			       "read_mapping_page error: ino %lu, index: %lu\n",
 			       mapping->host->i_ino, index);
 			goto out;
 		}
diff --git a/fs/utimes.c b/fs/utimes.c
index 99cf2cb..480f7c8 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -1,8 +1,10 @@
 #include <linux/compiler.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/linkage.h>
 #include <linux/namei.h>
 #include <linux/sched.h>
+#include <linux/stat.h>
 #include <linux/utime.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -20,54 +22,18 @@ #ifdef __ARCH_WANT_SYS_UTIME
  * 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)
+asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
 {
-	int error;
-	struct nameidata nd;
-	struct inode * inode;
-	struct iattr newattrs;
+	struct timespec tv[2];
 
-	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, &times->actime);
-		newattrs.ia_atime.tv_nsec = 0;
-		if (!error)
-			error = get_user(newattrs.ia_mtime.tv_sec, &times->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;
+		if (get_user(tv[0].tv_sec, &times->actime) ||
+		    get_user(tv[1].tv_sec, &times->modtime))
+			return -EFAULT;
+		tv[0].tv_nsec = 0;
+		tv[1].tv_nsec = 0;
 	}
-	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;
+	return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
 }
 
 #endif
@@ -76,18 +42,38 @@ #endif
  * 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)
+long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
 {
 	int error;
 	struct nameidata nd;
-	struct inode * inode;
+	struct dentry *dentry;
+	struct inode *inode;
 	struct iattr newattrs;
+	struct file *f = NULL;
 
-	error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
-
-	if (error)
+	error = -EINVAL;
+	if (flags & ~AT_SYMLINK_NOFOLLOW)
 		goto out;
-	inode = nd.dentry->d_inode;
+
+	if (filename == NULL && dfd != AT_FDCWD) {
+		error = -EINVAL;
+		if (flags & AT_SYMLINK_NOFOLLOW)
+			goto out;
+
+		error = -EBADF;
+		f = fget(dfd);
+		if (!f)
+			goto out;
+		dentry = f->f_path.dentry;
+	} else {
+		error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
+		if (error)
+			goto out;
+
+		dentry = nd.dentry;
+	}
+
+	inode = dentry->d_inode;
 
 	error = -EROFS;
 	if (IS_RDONLY(inode))
@@ -100,11 +86,21 @@ long do_utimes(int dfd, char __user *fil
                 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;
+		if (times[0].tv_nsec == UTIME_OMIT)
+			newattrs.ia_valid &= ~ATTR_ATIME;
+		else if (times[0].tv_nsec != UTIME_NOW) {
+			newattrs.ia_atime.tv_sec = times[0].tv_sec;
+			newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
+			newattrs.ia_valid |= ATTR_ATIME_SET;
+		}
+
+		if (times[1].tv_nsec == UTIME_OMIT)
+			newattrs.ia_valid &= ~ATTR_MTIME;
+		else if (times[1].tv_nsec != UTIME_NOW) {
+			newattrs.ia_mtime.tv_sec = times[1].tv_sec;
+			newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
+			newattrs.ia_valid |= ATTR_MTIME_SET;
+		}
 	} else {
 		error = -EACCES;
                 if (IS_IMMUTABLE(inode))
@@ -115,21 +111,67 @@ long do_utimes(int dfd, char __user *fil
 			goto dput_and_out;
 	}
 	mutex_lock(&inode->i_mutex);
-	error = notify_change(nd.dentry, &newattrs);
+	error = notify_change(dentry, &newattrs);
 	mutex_unlock(&inode->i_mutex);
 dput_and_out:
-	path_release(&nd);
+	if (f)
+		fput(f);
+	else
+		path_release(&nd);
 out:
 	return error;
 }
 
+asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags)
+{
+	struct timespec tstimes[2];
+
+	if (utimes) {
+		if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
+			return -EFAULT;
+		if ((tstimes[0].tv_nsec == UTIME_OMIT ||
+		     tstimes[0].tv_nsec == UTIME_NOW) &&
+		    tstimes[0].tv_sec != 0)
+			return -EINVAL;
+		if ((tstimes[1].tv_nsec == UTIME_OMIT ||
+		     tstimes[1].tv_nsec == UTIME_NOW) &&
+		    tstimes[1].tv_sec != 0)
+			return -EINVAL;
+
+		/* Nothing to do, we must not even check the path.  */
+		if (tstimes[0].tv_nsec == UTIME_OMIT &&
+		    tstimes[1].tv_nsec == UTIME_OMIT)
+			return 0;
+	}
+
+	return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
+}
+
 asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
 {
 	struct timeval times[2];
+	struct timespec tstimes[2];
+
+	if (utimes) {
+		if (copy_from_user(&times, utimes, sizeof(times)))
+			return -EFAULT;
+
+		/* This test is needed to catch all invalid values.  If we
+		   would test only in do_utimes we would miss those invalid
+		   values truncated by the multiplication with 1000.  Note
+		   that we also catch UTIME_{NOW,OMIT} here which are only
+		   valid for utimensat.  */
+		if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
+		    times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
+			return -EINVAL;
+
+		tstimes[0].tv_sec = times[0].tv_sec;
+		tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
+		tstimes[1].tv_sec = times[1].tv_sec;
+		tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
+	}
 
-	if (utimes && copy_from_user(&times, utimes, sizeof(times)))
-		return -EFAULT;
-	return do_utimes(dfd, filename, utimes ? times : NULL);
+	return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
 }
 
 asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
diff --git a/fs/xattr.c b/fs/xattr.c
index 3864613..9f4568b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -9,7 +9,6 @@
  */
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/xattr.h>
 #include <linux/namei.h>
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h
index af168a1..c110bb0 100644
--- a/fs/xfs/linux-2.6/mrlock.h
+++ b/fs/xfs/linux-2.6/mrlock.h
@@ -43,6 +43,18 @@ static inline void mrupdate(mrlock_t *mr
 	mrp->mr_writer = 1;
 }
 
+static inline void mraccess_nested(mrlock_t *mrp, int subclass)
+{
+	down_read_nested(&mrp->mr_lock, subclass);
+}
+
+static inline void mrupdate_nested(mrlock_t *mrp, int subclass)
+{
+	down_write_nested(&mrp->mr_lock, subclass);
+	mrp->mr_writer = 1;
+}
+
+
 static inline int mrtryaccess(mrlock_t *mrp)
 {
 	return down_read_trylock(&mrp->mr_lock);
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 143ffc8..4475588 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -141,9 +141,46 @@ xfs_destroy_ioend(
 }
 
 /*
+ * Update on-disk file size now that data has been written to disk.
+ * The current in-memory file size is i_size.  If a write is beyond
+ * eof io_new_size will be the intended file size until i_size is
+ * updated.  If this write does not extend all the way to the valid
+ * file size then restrict this update to the end of the write.
+ */
+STATIC void
+xfs_setfilesize(
+	xfs_ioend_t		*ioend)
+{
+	xfs_inode_t		*ip;
+	xfs_fsize_t		isize;
+	xfs_fsize_t		bsize;
+
+	ip = xfs_vtoi(ioend->io_vnode);
+
+	ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
+	ASSERT(ioend->io_type != IOMAP_READ);
+
+	if (unlikely(ioend->io_error))
+		return;
+
+	bsize = ioend->io_offset + ioend->io_size;
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+	isize = MAX(ip->i_size, ip->i_iocore.io_new_size);
+	isize = MIN(isize, bsize);
+
+	if (ip->i_d.di_size < isize) {
+		ip->i_d.di_size = isize;
+		ip->i_update_core = 1;
+		ip->i_update_size = 1;
+	}
+
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+}
+
+/*
  * Buffered IO write completion for delayed allocate extents.
- * TODO: Update ondisk isize now that we know the file data
- * has been flushed (i.e. the notorious "NULL file" problem).
  */
 STATIC void
 xfs_end_bio_delalloc(
@@ -152,6 +189,7 @@ xfs_end_bio_delalloc(
 	xfs_ioend_t		*ioend =
 		container_of(work, xfs_ioend_t, io_work);
 
+	xfs_setfilesize(ioend);
 	xfs_destroy_ioend(ioend);
 }
 
@@ -165,6 +203,7 @@ xfs_end_bio_written(
 	xfs_ioend_t		*ioend =
 		container_of(work, xfs_ioend_t, io_work);
 
+	xfs_setfilesize(ioend);
 	xfs_destroy_ioend(ioend);
 }
 
@@ -184,8 +223,23 @@ xfs_end_bio_unwritten(
 	xfs_off_t		offset = ioend->io_offset;
 	size_t			size = ioend->io_size;
 
-	if (likely(!ioend->io_error))
+	if (likely(!ioend->io_error)) {
 		bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL);
+		xfs_setfilesize(ioend);
+	}
+	xfs_destroy_ioend(ioend);
+}
+
+/*
+ * IO read completion for regular, written extents.
+ */
+STATIC void
+xfs_end_bio_read(
+	struct work_struct	*work)
+{
+	xfs_ioend_t		*ioend =
+		container_of(work, xfs_ioend_t, io_work);
+
 	xfs_destroy_ioend(ioend);
 }
 
@@ -224,6 +278,8 @@ xfs_alloc_ioend(
 		INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten);
 	else if (type == IOMAP_DELAY)
 		INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc);
+	else if (type == IOMAP_READ)
+		INIT_WORK(&ioend->io_work, xfs_end_bio_read);
 	else
 		INIT_WORK(&ioend->io_work, xfs_end_bio_written);
 
@@ -913,7 +969,7 @@ xfs_page_state_convert(
 	bh = head = page_buffers(page);
 	offset = page_offset(page);
 	flags = -1;
-	type = 0;
+	type = IOMAP_READ;
 
 	/* TODO: cleanup count and page_dirty */
 
@@ -999,7 +1055,7 @@ xfs_page_state_convert(
 			 * That means it must already have extents allocated
 			 * underneath it. Map the extent by reading it.
 			 */
-			if (!iomap_valid || type != 0) {
+			if (!iomap_valid || type != IOMAP_READ) {
 				flags = BMAPI_READ;
 				size = xfs_probe_cluster(inode, page, bh,
 								head, 1);
@@ -1010,7 +1066,7 @@ xfs_page_state_convert(
 				iomap_valid = xfs_iomap_valid(&iomap, offset);
 			}
 
-			type = 0;
+			type = IOMAP_READ;
 			if (!test_and_set_bit(BH_Lock, &bh->b_state)) {
 				ASSERT(buffer_mapped(bh));
 				if (iomap_valid)
@@ -1356,12 +1412,21 @@ xfs_end_io_direct(
 	 * completion handler in the future, in which case all this can
 	 * go away.
 	 */
-	if (private && size > 0) {
-		ioend->io_offset = offset;
-		ioend->io_size = size;
+	ioend->io_offset = offset;
+	ioend->io_size = size;
+	if (ioend->io_type == IOMAP_READ) {
+		xfs_finish_ioend(ioend);
+	} else if (private && size > 0) {
 		xfs_finish_ioend(ioend);
 	} else {
-		xfs_destroy_ioend(ioend);
+		/*
+		 * A direct I/O write ioend starts it's life in unwritten
+		 * state in case they map an unwritten extent.  This write
+		 * didn't map an unwritten extent so switch it's completion
+		 * handler.
+		 */
+		INIT_WORK(&ioend->io_work, xfs_end_bio_written);
+		xfs_finish_ioend(ioend);
 	}
 
 	/*
@@ -1392,15 +1457,15 @@ xfs_vm_direct_IO(
 	if (error)
 		return -error;
 
-	iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
-
 	if (rw == WRITE) {
+		iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
 		ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
 			iomap.iomap_target->bt_bdev,
 			iov, offset, nr_segs,
 			xfs_get_blocks_direct,
 			xfs_end_io_direct);
 	} else {
+		iocb->private = xfs_alloc_ioend(inode, IOMAP_READ);
 		ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
 			iomap.iomap_target->bt_bdev,
 			iov, offset, nr_segs,
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 69e9e80..fe4f66a 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1426,7 +1426,7 @@ xfs_free_bufhash(
 /*
  *	buftarg list for delwrite queue processing
  */
-LIST_HEAD(xfs_buftarg_list);
+static LIST_HEAD(xfs_buftarg_list);
 static DEFINE_SPINLOCK(xfs_buftarg_lock);
 
 STATIC void
@@ -1867,3 +1867,11 @@ #ifdef XFS_BUF_TRACE
 	ktrace_free(xfs_buf_trace_buf);
 #endif
 }
+
+#ifdef CONFIG_KDB_MODULES
+struct list_head *
+xfs_get_buftarg_list(void)
+{
+	return &xfs_buftarg_list;
+}
+#endif
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 9e8ef8f..b6241f6 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -411,6 +411,9 @@ extern void xfs_free_buftarg(xfs_buftarg
 extern void xfs_wait_buftarg(xfs_buftarg_t *);
 extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
 extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
+#ifdef CONFIG_KDB_MODULES
+extern struct list_head *xfs_get_buftarg_list(void);
+#endif
 
 #define xfs_getsize_buftarg(buftarg)	block_size((buftarg)->bt_bdev)
 #define xfs_readonly_buftarg(buftarg)	bdev_read_only((buftarg)->bt_bdev)
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c
index dc05628..2eb87cd 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.c
+++ b/fs/xfs/linux-2.6/xfs_fs_subr.c
@@ -35,7 +35,7 @@ fs_tosspages(
 		truncate_inode_pages(ip->i_mapping, first);
 }
 
-void
+int
 fs_flushinval_pages(
 	bhv_desc_t	*bdp,
 	xfs_off_t	first,
@@ -44,13 +44,16 @@ fs_flushinval_pages(
 {
 	bhv_vnode_t	*vp = BHV_TO_VNODE(bdp);
 	struct inode	*ip = vn_to_inode(vp);
+	int		ret = 0;
 
 	if (VN_CACHED(vp)) {
 		if (VN_TRUNC(vp))
 			VUNTRUNCATE(vp);
-		filemap_write_and_wait(ip->i_mapping);
-		truncate_inode_pages(ip->i_mapping, first);
+		ret = filemap_write_and_wait(ip->i_mapping);
+		if (!ret)
+			truncate_inode_pages(ip->i_mapping, first);
 	}
+	return ret;
 }
 
 int
@@ -63,14 +66,18 @@ fs_flush_pages(
 {
 	bhv_vnode_t	*vp = BHV_TO_VNODE(bdp);
 	struct inode	*ip = vn_to_inode(vp);
+	int		ret = 0;
+	int		ret2;
 
 	if (VN_DIRTY(vp)) {
 		if (VN_TRUNC(vp))
 			VUNTRUNCATE(vp);
-		filemap_fdatawrite(ip->i_mapping);
+		ret = filemap_fdatawrite(ip->i_mapping);
 		if (flags & XFS_B_ASYNC)
-			return 0;
-		filemap_fdatawait(ip->i_mapping);
+			return ret;
+		ret2 = filemap_fdatawait(ip->i_mapping);
+		if (!ret)
+			ret = ret2;
 	}
-	return 0;
+	return ret;
 }
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h
index aee9ccd..c1b5311 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.h
+++ b/fs/xfs/linux-2.6/xfs_fs_subr.h
@@ -23,7 +23,7 @@ extern int  fs_noerr(void);
 extern int  fs_nosys(void);
 extern void fs_noval(void);
 extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
-extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+extern int  fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 extern int  fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int);
 
 #endif	/* __XFS_FS_SUBR_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index ff8d64e..86fb671 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -191,7 +191,7 @@ xfs_read(
 	struct file		*file = iocb->ki_filp;
 	struct inode		*inode = file->f_mapping->host;
 	size_t			size = 0;
-	ssize_t			ret;
+	ssize_t			ret = 0;
 	xfs_fsize_t		n;
 	xfs_inode_t		*ip;
 	xfs_mount_t		*mp;
@@ -224,7 +224,7 @@ xfs_read(
 				mp->m_rtdev_targp : mp->m_ddev_targp;
 		if ((*offset & target->bt_smask) ||
 		    (size & target->bt_smask)) {
-			if (*offset == ip->i_d.di_size) {
+			if (*offset == ip->i_size) {
 				return (0);
 			}
 			return -XFS_ERROR(EINVAL);
@@ -263,9 +263,13 @@ xfs_read(
 
 	if (unlikely(ioflags & IO_ISDIRECT)) {
 		if (VN_CACHED(vp))
-			bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
+			ret = bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
 						 -1, FI_REMAPF_LOCKED);
 		mutex_unlock(&inode->i_mutex);
+		if (ret) {
+			xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+			return ret;
+		}
 	}
 
 	xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
@@ -383,9 +387,10 @@ xfs_splice_write(
 {
 	xfs_inode_t		*ip = XFS_BHVTOI(bdp);
 	xfs_mount_t		*mp = ip->i_mount;
+	xfs_iocore_t		*io = &ip->i_iocore;
 	ssize_t			ret;
 	struct inode		*inode = outfilp->f_mapping->host;
-	xfs_fsize_t		isize;
+	xfs_fsize_t		isize, new_size;
 
 	XFS_STATS_INC(xs_write_calls);
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -406,6 +411,14 @@ xfs_splice_write(
 			return -error;
 		}
 	}
+
+	new_size = *ppos + count;
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	if (new_size > ip->i_size)
+		io->io_new_size = new_size;
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
 	xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore,
 			   pipe, count, *ppos, ioflags);
 	ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
@@ -416,14 +429,18 @@ xfs_splice_write(
 	if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
 		*ppos = isize;
 
-	if (*ppos > ip->i_d.di_size) {
+	if (*ppos > ip->i_size) {
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
-		if (*ppos > ip->i_d.di_size) {
-			ip->i_d.di_size = *ppos;
-			i_size_write(inode, *ppos);
-			ip->i_update_core = 1;
-			ip->i_update_size = 1;
-		}
+		if (*ppos > ip->i_size)
+			ip->i_size = *ppos;
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+	}
+
+	if (io->io_new_size) {
+		xfs_ilock(ip, XFS_ILOCK_EXCL);
+		io->io_new_size = 0;
+		if (ip->i_d.di_size > ip->i_size)
+			ip->i_d.di_size = ip->i_size;
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	}
 	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
@@ -639,37 +656,21 @@ xfs_write(
 	xfs_fsize_t		isize, new_size;
 	xfs_iocore_t		*io;
 	bhv_vnode_t		*vp;
-	unsigned long		seg;
 	int			iolock;
 	int			eventsent = 0;
 	bhv_vrwlock_t		locktype;
 	size_t			ocount = 0, count;
 	loff_t			pos;
-	int			need_i_mutex = 1, need_flush = 0;
+	int			need_i_mutex;
 
 	XFS_STATS_INC(xs_write_calls);
 
 	vp = BHV_TO_VNODE(bdp);
 	xip = XFS_BHVTOI(bdp);
 
-	for (seg = 0; seg < segs; seg++) {
-		const struct iovec *iv = &iovp[seg];
-
-		/*
-		 * If any segment has a negative length, or the cumulative
-		 * length ever wraps negative then return -EINVAL.
-		 */
-		ocount += iv->iov_len;
-		if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
-			return -EINVAL;
-		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
-			continue;
-		if (seg == 0)
-			return -EFAULT;
-		segs = seg;
-		ocount -= iv->iov_len;  /* This segment is no good */
-		break;
-	}
+	error = generic_segment_checks(iovp, &segs, &ocount, VERIFY_READ);
+	if (error)
+		return error;
 
 	count = ocount;
 	pos = *offset;
@@ -685,39 +686,20 @@ xfs_write(
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
 
-	if (ioflags & IO_ISDIRECT) {
-		xfs_buftarg_t	*target =
-			(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
-				mp->m_rtdev_targp : mp->m_ddev_targp;
-
-		if ((pos & target->bt_smask) || (count & target->bt_smask))
-			return XFS_ERROR(-EINVAL);
-
-		if (!VN_CACHED(vp) && pos < i_size_read(inode))
-			need_i_mutex = 0;
-
-		if (VN_CACHED(vp))
-			need_flush = 1;
-	}
-
 relock:
-	if (need_i_mutex) {
+	if (ioflags & IO_ISDIRECT) {
+		iolock = XFS_IOLOCK_SHARED;
+		locktype = VRWLOCK_WRITE_DIRECT;
+		need_i_mutex = 0;
+	} else {
 		iolock = XFS_IOLOCK_EXCL;
 		locktype = VRWLOCK_WRITE;
-
+		need_i_mutex = 1;
 		mutex_lock(&inode->i_mutex);
-	} else {
-		iolock = XFS_IOLOCK_SHARED;
-		locktype = VRWLOCK_WRITE_DIRECT;
 	}
 
 	xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
 
-	isize = i_size_read(inode);
-
-	if (file->f_flags & O_APPEND)
-		*offset = isize;
-
 start:
 	error = -generic_write_checks(file, &pos, &count,
 					S_ISBLK(inode->i_mode));
@@ -726,13 +708,8 @@ start:
 		goto out_unlock_mutex;
 	}
 
-	new_size = pos + count;
-	if (new_size > isize)
-		io->io_new_size = new_size;
-
 	if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
 	    !(ioflags & IO_INVIS) && !eventsent)) {
-		loff_t		savedsize = pos;
 		int		dmflags = FILP_DELAY_FLAG(file);
 
 		if (need_i_mutex)
@@ -743,8 +720,7 @@ start:
 				      pos, count,
 				      dmflags, &locktype);
 		if (error) {
-			xfs_iunlock(xip, iolock);
-			goto out_unlock_mutex;
+			goto out_unlock_internal;
 		}
 		xfs_ilock(xip, XFS_ILOCK_EXCL);
 		eventsent = 1;
@@ -756,12 +732,35 @@ start:
 		 * event prevents another call to XFS_SEND_DATA, which is
 		 * what allows the size to change in the first place.
 		 */
-		if ((file->f_flags & O_APPEND) && savedsize != isize) {
-			pos = isize = xip->i_d.di_size;
+		if ((file->f_flags & O_APPEND) && pos != xip->i_size)
+			goto start;
+	}
+
+	if (ioflags & IO_ISDIRECT) {
+		xfs_buftarg_t	*target =
+			(xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
+				mp->m_rtdev_targp : mp->m_ddev_targp;
+
+		if ((pos & target->bt_smask) || (count & target->bt_smask)) {
+			xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+			return XFS_ERROR(-EINVAL);
+		}
+
+		if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
+			xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+			iolock = XFS_IOLOCK_EXCL;
+			locktype = VRWLOCK_WRITE;
+			need_i_mutex = 1;
+			mutex_lock(&inode->i_mutex);
+			xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
 			goto start;
 		}
 	}
 
+	new_size = pos + count;
+	if (new_size > xip->i_size)
+		io->io_new_size = new_size;
+
 	if (likely(!(ioflags & IO_INVIS))) {
 		file_update_time(file);
 		xfs_ichgtime_fast(xip, inode,
@@ -777,11 +776,11 @@ start:
 	 * to zero it out up to the new size.
 	 */
 
-	if (pos > isize) {
-		error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
+	if (pos > xip->i_size) {
+		error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, xip->i_size);
 		if (error) {
-			xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
-			goto out_unlock_mutex;
+			xfs_iunlock(xip, XFS_ILOCK_EXCL);
+			goto out_unlock_internal;
 		}
 	}
 	xfs_iunlock(xip, XFS_ILOCK_EXCL);
@@ -801,8 +800,7 @@ start:
 		if (likely(!error))
 			error = -remove_suid(file->f_path.dentry);
 		if (unlikely(error)) {
-			xfs_iunlock(xip, iolock);
-			goto out_unlock_mutex;
+			goto out_unlock_internal;
 		}
 	}
 
@@ -811,11 +809,14 @@ retry:
 	current->backing_dev_info = mapping->backing_dev_info;
 
 	if ((ioflags & IO_ISDIRECT)) {
-		if (need_flush) {
+		if (VN_CACHED(vp)) {
+			WARN_ON(need_i_mutex == 0);
 			xfs_inval_cached_trace(io, pos, -1,
 					ctooff(offtoct(pos)), -1);
-			bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)),
+			error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)),
 					-1, FI_REMAPF_LOCKED);
+			if (error)
+				goto out_unlock_internal;
 		}
 
 		if (need_i_mutex) {
@@ -843,7 +844,6 @@ retry:
 			pos += ret;
 			count -= ret;
 
-			need_i_mutex = 1;
 			ioflags &= ~IO_ISDIRECT;
 			xfs_iunlock(xip, iolock);
 			goto relock;
@@ -870,12 +870,12 @@ retry:
 		error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
 				DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
 				0, 0, 0); /* Delay flag intentionally  unused */
-		if (error)
-			goto out_nounlocks;
 		if (need_i_mutex)
 			mutex_lock(&inode->i_mutex);
 		xfs_rwlock(bdp, locktype);
-		pos = xip->i_d.di_size;
+		if (error)
+			goto out_unlock_internal;
+		pos = xip->i_size;
 		ret = 0;
 		goto retry;
 	}
@@ -884,14 +884,10 @@ retry:
 	if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
 		*offset = isize;
 
-	if (*offset > xip->i_d.di_size) {
+	if (*offset > xip->i_size) {
 		xfs_ilock(xip, XFS_ILOCK_EXCL);
-		if (*offset > xip->i_d.di_size) {
-			xip->i_d.di_size = *offset;
-			i_size_write(inode, *offset);
-			xip->i_update_core = 1;
-			xip->i_update_size = 1;
-		}
+		if (*offset > xip->i_size)
+			xip->i_size = *offset;
 		xfs_iunlock(xip, XFS_ILOCK_EXCL);
 	}
 
@@ -913,16 +909,31 @@ retry:
 
 		error = sync_page_range(inode, mapping, pos, ret);
 		if (!error)
-			error = ret;
-		return error;
+			error = -ret;
+		if (need_i_mutex)
+			mutex_lock(&inode->i_mutex);
+		xfs_rwlock(bdp, locktype);
 	}
 
  out_unlock_internal:
+	if (io->io_new_size) {
+		xfs_ilock(xip, XFS_ILOCK_EXCL);
+		io->io_new_size = 0;
+		/*
+		 * If this was a direct or synchronous I/O that failed (such
+		 * as ENOSPC) then part of the I/O may have been written to
+		 * disk before the error occured.  In this case the on-disk
+		 * file size may have been adjusted beyond the in-memory file
+		 * size and now needs to be truncated back.
+		 */
+		if (xip->i_d.di_size > xip->i_size)
+			xip->i_d.di_size = xip->i_size;
+		xfs_iunlock(xip, XFS_ILOCK_EXCL);
+	}
 	xfs_rwunlock(bdp, locktype);
  out_unlock_mutex:
 	if (need_i_mutex)
 		mutex_unlock(&inode->i_mutex);
- out_nounlocks:
 	return -error;
 }
 
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 2f2c40d..14e2cbe 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -360,8 +360,7 @@ xfs_fs_inode_init_once(
 	kmem_zone_t		*zonep,
 	unsigned long		flags)
 {
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-		      SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(vn_to_inode((bhv_vnode_t *)vnode));
 }
 
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index b76118c..d1b2d01 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -194,7 +194,7 @@ typedef	int	(*vop_attr_list_t)(bhv_desc_
 typedef void	(*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int);
 typedef void	(*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t);
 typedef void	(*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
-typedef void	(*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+typedef int	(*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
 typedef int	(*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t,
 				uint64_t, int);
 typedef int	(*vop_iflush_t)(bhv_desc_t *, int);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index 4adaf13..cfdd35e 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -753,8 +753,7 @@ xfs_qm_idtodq(
 		goto error0;
 	}
 	if (tp) {
-		if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-					     NULL)))
+		if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES)))
 			goto error1;
 	}
 
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 1de2acd..3e4a8ad 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -388,6 +388,17 @@ xfs_qm_mount_quotas(
 			return XFS_ERROR(error);
 		}
 	}
+	/* 
+	 * If one type of quotas is off, then it will lose its
+	 * quotachecked status, since we won't be doing accounting for
+	 * that type anymore.
+	 */
+	if (!XFS_IS_UQUOTA_ON(mp)) {
+		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
+	}
+	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp))) {
+		mp->m_qflags &= ~XFS_OQUOTA_CHKD;
+	}
 
  write_changes:
 	/*
@@ -1453,8 +1464,7 @@ #endif
 	XFS_SB_UNLOCK(mp, s);
 	xfs_mod_sb(tp, sbfields);
 
-	if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-				     NULL))) {
+	if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) {
 		xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
 		return error;
 	}
@@ -2405,7 +2415,7 @@ #endif
 	}
 
 	xfs_mod_sb(tp, flags);
-	(void) xfs_trans_commit(tp, 0, NULL);
+	(void) xfs_trans_commit(tp, 0);
 
 	return 0;
 }
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 716f562..2df67fd 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -456,9 +456,7 @@ xfs_qm_scall_quotaon(
 	    ||
 	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
 	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
-	    (flags & XFS_OQUOTA_ENFD))
-	    ||
-	    ((flags & XFS_GQUOTA_ACCT) == 0 &&
+	    (flags & XFS_GQUOTA_ACCT) == 0 &&
 	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
 	    (flags & XFS_OQUOTA_ENFD))) {
 		qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
@@ -735,7 +733,7 @@ xfs_qm_scall_setqlim(
 	xfs_trans_log_dquot(tp, dqp);
 
 	xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
-	xfs_trans_commit(tp, 0, NULL);
+	xfs_trans_commit(tp, 0);
 	xfs_qm_dqprint(dqp);
 	xfs_qm_dqrele(dqp);
 	mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
@@ -809,7 +807,7 @@ xfs_qm_log_quotaoff_end(
 	 * We don't care about quotoff's performance.
 	 */
 	xfs_trans_set_sync(tp);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 	return (error);
 }
 
@@ -852,7 +850,7 @@ xfs_qm_log_quotaoff(
 	 * We don't care about quotoff's performance.
 	 */
 	xfs_trans_set_sync(tp);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 
 error0:
 	if (error) {
@@ -911,14 +909,19 @@ xfs_qm_export_dquot(
 	 * gets turned off. No need to confuse the user level code,
 	 * so return zeroes in that case.
 	 */
-	if (! XFS_IS_QUOTA_ENFORCED(mp)) {
+	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && src->d_flags == XFS_DQ_USER) ||
+	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
+			(src->d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
 		dst->d_btimer = 0;
 		dst->d_itimer = 0;
 		dst->d_rtbtimer = 0;
 	}
 
 #ifdef DEBUG
-	if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
+	if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == XFS_USER_QUOTA) ||
+	     (XFS_IS_OQUOTA_ENFORCED(mp) &&
+			(dst->d_flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)))) &&
+	    dst->d_id != 0) {
 		if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
 		    (dst->d_blk_softlimit > 0)) {
 			ASSERT(dst->d_btimer != 0);
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index d7491e7..7de6874 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -656,7 +656,9 @@ xfs_trans_dqresv(
 
 	if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
 	    dqp->q_core.d_id &&
-	    XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
+	    ((XFS_IS_UQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISUDQ(dqp)) ||
+	     (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
+	      (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
 #ifdef QUOTADEBUG
 		cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
 			  " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 08bbd3c..f45a49f 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -81,20 +81,3 @@ assfail(char *expr, char *file, int line
 	printk("Assertion failed: %s, file: %s, line: %d\n", expr, file, line);
 	BUG();
 }
-
-#if ((defined(DEBUG) || defined(INDUCE_IO_ERRROR)) && !defined(NO_WANT_RANDOM))
-unsigned long random(void)
-{
-	static unsigned long	RandomValue = 1;
-	/* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */
-	register long	rv = RandomValue;
-	register long	lo;
-	register long	hi;
-
-	hi = rv / 127773;
-	lo = rv % 127773;
-	rv = 16807 * lo - 2836 * hi;
-	if (rv <= 0) rv += 2147483647;
-	return RandomValue = rv;
-}
-#endif /* DEBUG || INDUCE_IO_ERRROR || !NO_WANT_RANDOM */
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h
index 2a70cc6..a27a7c8 100644
--- a/fs/xfs/support/debug.h
+++ b/fs/xfs/support/debug.h
@@ -50,7 +50,7 @@ #endif
 #else /* DEBUG */
 
 # define ASSERT(expr)	ASSERT_ALWAYS(expr)
-extern unsigned long random(void);
+# include <linux/random.h>
 
 #ifndef STATIC
 # define STATIC noinline
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index e80dda3..8e9a40a 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -764,7 +764,7 @@ #if defined(DEBUG) && defined(__KERNEL__
 	 */
 	int		dofirst;	/* set to do first algorithm */
 
-	dofirst = random() & 1;
+	dofirst = random32() & 1;
 #endif
 	/*
 	 * Get a cursor for the by-size btree.
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 9d358ff..7ce44a7 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -328,8 +328,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const 
 				xfs_trans_set_sync(args.trans);
 			}
 			err2 = xfs_trans_commit(args.trans,
-						 XFS_TRANS_RELEASE_LOG_RES,
-						 NULL);
+						 XFS_TRANS_RELEASE_LOG_RES);
 			xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
 			/*
@@ -397,8 +396,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const 
 	 * Commit the last in the sequence of transactions.
 	 */
 	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
-	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
-				 NULL);
+	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
 	/*
@@ -544,8 +542,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, con
 	 * Commit the last in the sequence of transactions.
 	 */
 	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
-	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
-				 NULL);
+	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
 	/*
@@ -859,8 +856,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
 	 * Commit the last in the sequence of transactions.
 	 */
 	xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
-	error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,
-				 NULL);
+	error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
 	xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
 	return(error);
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 8eab73e..81f45da 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -3053,7 +3053,7 @@ xfs_attr_rolltrans(xfs_trans_t **transp,
 	 * is in progress. The caller takes the responsibility to cancel
 	 * the duplicate transaction that gets returned.
 	 */
-	if ((error = xfs_trans_commit(trans, 0, NULL)))
+	if ((error = xfs_trans_commit(trans, 0)))
 		return (error);
 
 	trans = *transp;
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 8779518..b1ea26e 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -130,7 +130,6 @@ STATIC int				/* error */
 xfs_bmap_add_extent_hole_delay(
 	xfs_inode_t		*ip,	/* incore inode pointer */
 	xfs_extnum_t		idx,	/* extent number to update/insert */
-	xfs_btree_cur_t		*cur,	/* if null, not a btree */
 	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
 	int			*logflagsp,/* inode logging flags */
 	xfs_extdelta_t		*delta, /* Change made to incore extents */
@@ -399,7 +398,6 @@ xfs_bmap_count_leaves(
 
 STATIC int
 xfs_bmap_disk_count_leaves(
-	xfs_ifork_t		*ifp,
 	xfs_extnum_t		idx,
 	xfs_bmbt_block_t	*block,
 	int			numrecs,
@@ -580,7 +578,7 @@ #endif
 		if (cur)
 			ASSERT((cur->bc_private.b.flags &
 				XFS_BTCUR_BPRV_WASDEL) == 0);
-		if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new,
+		if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
 				&logflags, delta, rsvd)))
 			goto done;
 	}
@@ -1841,7 +1839,6 @@ STATIC int				/* error */
 xfs_bmap_add_extent_hole_delay(
 	xfs_inode_t		*ip,	/* incore inode pointer */
 	xfs_extnum_t		idx,	/* extent number to update/insert */
-	xfs_btree_cur_t		*cur,	/* if null, not a btree */
 	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */
 	int			*logflagsp, /* inode logging flags */
 	xfs_extdelta_t		*delta, /* Change made to incore extents */
@@ -4071,7 +4068,7 @@ xfs_bmap_add_attrfork(
 	}
 	if ((error = xfs_bmap_finish(&tp, &flist, &committed)))
 		goto error2;
-	error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES);
 	ASSERT(ip->i_df.if_ext_max ==
 	       XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
 	return error;
@@ -4227,7 +4224,7 @@ xfs_bmap_finish(
 	logres = ntp->t_log_res;
 	logcount = ntp->t_log_count;
 	ntp = xfs_trans_dup(*tp);
-	error = xfs_trans_commit(*tp, 0, NULL);
+	error = xfs_trans_commit(*tp, 0);
 	*tp = ntp;
 	*committed = 1;
 	/*
@@ -4447,8 +4444,11 @@ xfs_bmap_one_block(
 	xfs_bmbt_irec_t	s;		/* internal version of extent */
 
 #ifndef DEBUG
-	if (whichfork == XFS_DATA_FORK)
-		return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize;
+	if (whichfork == XFS_DATA_FORK) {
+		return ((ip->i_d.di_mode & S_IFMT) == S_IFREG) ?
+			(ip->i_size == ip->i_mount->m_sb.sb_blocksize) :
+			(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
+	}
 #endif	/* !DEBUG */
 	if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
 		return 0;
@@ -4460,7 +4460,7 @@ #endif	/* !DEBUG */
 	xfs_bmbt_get_all(ep, &s);
 	rval = s.br_startoff == 0 && s.br_blockcount == 1;
 	if (rval && whichfork == XFS_DATA_FORK)
-		ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
+		ASSERT(ip->i_size == ip->i_mount->m_sb.sb_blocksize);
 	return rval;
 }
 
@@ -5820,7 +5820,7 @@ xfs_getbmap(
 			fixlen = XFS_MAXIOFFSET(mp);
 		} else {
 			prealloced = 0;
-			fixlen = ip->i_d.di_size;
+			fixlen = ip->i_size;
 		}
 	} else {
 		prealloced = 0;
@@ -5844,7 +5844,8 @@ xfs_getbmap(
 
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-	if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) {
+	if (whichfork == XFS_DATA_FORK &&
+		(ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) {
 		/* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */
 		error = bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF);
 	}
@@ -6425,8 +6426,8 @@ xfs_bmap_count_tree(
 		for (;;) {
 			nextbno = be64_to_cpu(block->bb_rightsib);
 			numrecs = be16_to_cpu(block->bb_numrecs);
-			if (unlikely(xfs_bmap_disk_count_leaves(ifp,
-					0, block, numrecs, count) < 0)) {
+			if (unlikely(xfs_bmap_disk_count_leaves(0,
+					block, numrecs, count) < 0)) {
 				xfs_trans_brelse(tp, bp);
 				XFS_ERROR_REPORT("xfs_bmap_count_tree(2)",
 						 XFS_ERRLEVEL_LOW, mp);
@@ -6472,7 +6473,6 @@ xfs_bmap_count_leaves(
  */
 int
 xfs_bmap_disk_count_leaves(
-	xfs_ifork_t		*ifp,
 	xfs_extnum_t		idx,
 	xfs_bmbt_block_t	*block,
 	int			numrecs,
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index b847e6a..de35d18 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -199,7 +199,9 @@ xfs_swap_extents(
 
 	if (VN_CACHED(tvp) != 0) {
 		xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1);
-		bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED);
+		error = bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED);
+		if (error)
+			goto error0;
 	}
 
 	/* Verify O_DIRECT for ftmp */
@@ -382,7 +384,7 @@ xfs_swap_extents(
 		xfs_trans_set_sync(tp);
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
 	locked = 0;
 
  error0:
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 9d7438b..3accc1d 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -282,8 +282,7 @@ xfs_dir2_block_addname(
 		 * This needs to happen before the next call to use_free.
 		 */
 		if (needscan) {
-			xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
-				&needlog, NULL);
+			xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
 			needscan = 0;
 		}
 	}
@@ -333,7 +332,7 @@ xfs_dir2_block_addname(
 		 */
 		if (needscan) {
 			xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
-				&needlog, NULL);
+				&needlog);
 			needscan = 0;
 		}
 		/*
@@ -418,8 +417,7 @@ xfs_dir2_block_addname(
 	 * Clean up the bestfree array and log the header, tail, and entry.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-			NULL);
+		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
 	if (needlog)
 		xfs_dir2_data_log_header(tp, bp);
 	xfs_dir2_block_log_tail(tp, bp);
@@ -798,8 +796,7 @@ xfs_dir2_block_removename(
 	 * Fix up bestfree, log the header if necessary.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-			NULL);
+		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
 	if (needlog)
 		xfs_dir2_data_log_header(tp, bp);
 	xfs_dir2_data_check(dp, bp);
@@ -996,8 +993,7 @@ xfs_dir2_leaf_to_block(
 	 * Scan the bestfree if we need it and log the data block header.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-			NULL);
+		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
 	if (needlog)
 		xfs_dir2_data_log_header(tp, dbp);
 	/*
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index f7c7992..c211c37 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -324,8 +324,7 @@ void
 xfs_dir2_data_freescan(
 	xfs_mount_t		*mp,		/* filesystem mount point */
 	xfs_dir2_data_t		*d,		/* data block pointer */
-	int			*loghead,	/* out: log data header */
-	char			*aendp)		/* in: caller's endp */
+	int			*loghead)	/* out: log data header */
 {
 	xfs_dir2_block_tail_t	*btp;		/* block tail */
 	xfs_dir2_data_entry_t	*dep;		/* active data entry */
@@ -346,9 +345,7 @@ #endif
 	 * Set up pointers.
 	 */
 	p = (char *)d->u;
-	if (aendp)
-		endp = aendp;
-	else if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
+	if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
 		btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
 		endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
 	} else
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h
index a6ae2d2..c94c909 100644
--- a/fs/xfs/xfs_dir2_data.h
+++ b/fs/xfs/xfs_dir2_data.h
@@ -166,7 +166,7 @@ extern xfs_dir2_data_free_t *xfs_dir2_da
 extern xfs_dir2_data_free_t *xfs_dir2_data_freeinsert(xfs_dir2_data_t *d,
 				xfs_dir2_data_unused_t *dup, int *loghead);
 extern void xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d,
-				int *loghead, char *aendp);
+				int *loghead);
 extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
 				struct xfs_dabuf **bpp);
 extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp,
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index b1cf1fb..db14ea7 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -133,8 +133,7 @@ xfs_dir2_block_to_leaf(
 	 */
 	block->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 	if (needscan)
-		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
-			NULL);
+		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
 	/*
 	 * Set up leaf tail and bests table.
 	 */
@@ -414,7 +413,7 @@ xfs_dir2_leaf_addname(
 	 * Need to scan fix up the bestfree table.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+		xfs_dir2_data_freescan(mp, data, &needlog);
 	/*
 	 * Need to log the data block's header.
 	 */
@@ -1496,7 +1495,7 @@ xfs_dir2_leaf_removename(
 	 * log the data block header if necessary.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+		xfs_dir2_data_freescan(mp, data, &needlog);
 	if (needlog)
 		xfs_dir2_data_log_header(tp, dbp);
 	/*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 9ca7171..d083c38 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -904,7 +904,7 @@ xfs_dir2_leafn_remove(
 	 * Log the data block header if needed.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+		xfs_dir2_data_freescan(mp, data, &needlog);
 	if (needlog)
 		xfs_dir2_data_log_header(tp, dbp);
 	xfs_dir2_data_check(dp, dbp);
@@ -1705,7 +1705,7 @@ xfs_dir2_node_addname_int(
 	 * Rescan the block for bestfree if needed.
 	 */
 	if (needscan)
-		xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+		xfs_dir2_data_freescan(mp, data, &needlog);
 	/*
 	 * Log the data block header if needed.
 	 */
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index b1af544..8c43316 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -80,7 +80,7 @@ xfs_error_test(int error_tag, int *fsidp
 	int i;
 	int64_t fsid;
 
-	if (random() % randfactor)
+	if (random32() % randfactor)
 		return 0;
 
 	memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 32c37c1..b599e6b 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -346,7 +346,7 @@ xfs_growfs_data_private(
 		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
 	if (dpct)
 		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 	if (error) {
 		return error;
 	}
@@ -605,7 +605,7 @@ xfs_fs_log_dummy(
 	xfs_trans_ihold(tp, ip);
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	xfs_trans_set_sync(tp);
-	xfs_trans_commit(tp, 0, NULL);
+	xfs_trans_commit(tp, 0);
 
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 }
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index c1c89da..114433a 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -879,17 +879,17 @@ xfs_ilock(xfs_inode_t	*ip,
 	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
 	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
 	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-	ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
 
 	if (lock_flags & XFS_IOLOCK_EXCL) {
-		mrupdate(&ip->i_iolock);
+		mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
 	} else if (lock_flags & XFS_IOLOCK_SHARED) {
-		mraccess(&ip->i_iolock);
+		mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
 	}
 	if (lock_flags & XFS_ILOCK_EXCL) {
-		mrupdate(&ip->i_lock);
+		mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
 	} else if (lock_flags & XFS_ILOCK_SHARED) {
-		mraccess(&ip->i_lock);
+		mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
 	}
 	xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
 }
@@ -923,7 +923,7 @@ xfs_ilock_nowait(xfs_inode_t	*ip,
 	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
 	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
 	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-	ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
 
 	iolocked = 0;
 	if (lock_flags & XFS_IOLOCK_EXCL) {
@@ -983,7 +983,8 @@ xfs_iunlock(xfs_inode_t	*ip,
 	       (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
 	ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
 	       (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0);
+	ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
+			XFS_LOCK_DEP_MASK)) == 0);
 	ASSERT(lock_flags != 0);
 
 	if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) {
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3da9829..3ca5d43 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -442,6 +442,7 @@ xfs_iformat(
 			return XFS_ERROR(EFSCORRUPTED);
 		}
 		ip->i_d.di_size = 0;
+		ip->i_size = 0;
 		ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT);
 		break;
 
@@ -980,6 +981,7 @@ #endif /* DEBUG */
 	}
 
 	ip->i_delayed_blks = 0;
+	ip->i_size = ip->i_d.di_size;
 
 	/*
 	 * Mark the buffer containing the inode as something to keep
@@ -1170,6 +1172,7 @@ xfs_ialloc(
 	}
 
 	ip->i_d.di_size = 0;
+	ip->i_size = 0;
 	ip->i_d.di_nextents = 0;
 	ASSERT(ip->i_d.di_nblocks == 0);
 	xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD);
@@ -1340,7 +1343,7 @@ xfs_file_last_byte(
 	} else {
 		last_block = 0;
 	}
-	size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_d.di_size);
+	size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size);
 	last_block = XFS_FILEOFF_MAX(last_block, size_last_block);
 
 	last_byte = XFS_FSB_TO_B(mp, last_block);
@@ -1421,7 +1424,7 @@ #endif
  * must be called again with all the same restrictions as the initial
  * call.
  */
-void
+int
 xfs_itruncate_start(
 	xfs_inode_t	*ip,
 	uint		flags,
@@ -1431,9 +1434,10 @@ xfs_itruncate_start(
 	xfs_off_t	toss_start;
 	xfs_mount_t	*mp;
 	bhv_vnode_t	*vp;
+	int		error = 0;
 
 	ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
-	ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size));
+	ASSERT((new_size == 0) || (new_size <= ip->i_size));
 	ASSERT((flags == XFS_ITRUNC_DEFINITE) ||
 	       (flags == XFS_ITRUNC_MAYBE));
 
@@ -1468,7 +1472,7 @@ xfs_itruncate_start(
 		 * file size, so there is no way that the data extended
 		 * out there.
 		 */
-		return;
+		return 0;
 	}
 	last_byte = xfs_file_last_byte(ip);
 	xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start,
@@ -1477,7 +1481,7 @@ xfs_itruncate_start(
 		if (flags & XFS_ITRUNC_DEFINITE) {
 			bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
 		} else {
-			bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
+			error = bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
 		}
 	}
 
@@ -1486,6 +1490,7 @@ #ifdef DEBUG
 		ASSERT(VN_CACHED(vp) == 0);
 	}
 #endif
+	return error;
 }
 
 /*
@@ -1556,7 +1561,7 @@ xfs_itruncate_finish(
 
 	ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
 	ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
-	ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size));
+	ASSERT((new_size == 0) || (new_size <= ip->i_size));
 	ASSERT(*tp != NULL);
 	ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
 	ASSERT(ip->i_transp == *tp);
@@ -1630,8 +1635,20 @@ xfs_itruncate_finish(
 	 */
 	if (fork == XFS_DATA_FORK) {
 		if (ip->i_d.di_nextents > 0) {
-			ip->i_d.di_size = new_size;
-			xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
+			/*
+			 * If we are not changing the file size then do
+			 * not update the on-disk file size - we may be
+			 * called from xfs_inactive_free_eofblocks().  If we
+			 * update the on-disk file size and then the system
+			 * crashes before the contents of the file are
+			 * flushed to disk then the files may be full of
+			 * holes (ie NULL files bug).
+			 */
+			if (ip->i_size != new_size) {
+				ip->i_d.di_size = new_size;
+				ip->i_size = new_size;
+				xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
+			}
 		}
 	} else if (sync) {
 		ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC));
@@ -1746,7 +1763,7 @@ xfs_itruncate_finish(
 			xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
 		}
 		ntp = xfs_trans_dup(ntp);
-		(void) xfs_trans_commit(*tp, 0, NULL);
+		(void) xfs_trans_commit(*tp, 0);
 		*tp = ntp;
 		error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
 					  XFS_TRANS_PERM_LOG_RES,
@@ -1767,7 +1784,19 @@ xfs_itruncate_finish(
 	 */
 	if (fork == XFS_DATA_FORK) {
 		xfs_isize_check(mp, ip, new_size);
-		ip->i_d.di_size = new_size;
+		/*
+		 * If we are not changing the file size then do
+		 * not update the on-disk file size - we may be
+		 * called from xfs_inactive_free_eofblocks().  If we
+		 * update the on-disk file size and then the system
+		 * crashes before the contents of the file are
+		 * flushed to disk then the files may be full of
+		 * holes (ie NULL files bug).
+		 */
+		if (ip->i_size != new_size) {
+			ip->i_d.di_size = new_size;
+			ip->i_size = new_size;
+		}
 	}
 	xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
 	ASSERT((new_size != 0) ||
@@ -1800,7 +1829,7 @@ xfs_igrow_start(
 
 	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
 	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
-	ASSERT(new_size > ip->i_d.di_size);
+	ASSERT(new_size > ip->i_size);
 
 	/*
 	 * Zero any pages that may have been created by
@@ -1808,7 +1837,7 @@ xfs_igrow_start(
 	 * and any blocks between the old and new file sizes.
 	 */
 	error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,
-			     ip->i_d.di_size);
+			     ip->i_size);
 	return error;
 }
 
@@ -1832,13 +1861,14 @@ xfs_igrow_finish(
 	ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
 	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
 	ASSERT(ip->i_transp == tp);
-	ASSERT(new_size > ip->i_d.di_size);
+	ASSERT(new_size > ip->i_size);
 
 	/*
 	 * Update the file size.  Update the inode change timestamp
 	 * if change_flag set.
 	 */
 	ip->i_d.di_size = new_size;
+	ip->i_size = new_size;
 	if (change_flag)
 		xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -2321,7 +2351,7 @@ xfs_ifree(
 	ASSERT(ip->i_d.di_nlink == 0);
 	ASSERT(ip->i_d.di_nextents == 0);
 	ASSERT(ip->i_d.di_anextents == 0);
-	ASSERT((ip->i_d.di_size == 0) ||
+	ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||
 	       ((ip->i_d.di_mode & S_IFMT) != S_IFREG));
 	ASSERT(ip->i_d.di_nblocks == 0);
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index bc82372..f75afec 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -287,6 +287,7 @@ #endif
 	struct xfs_inode	*i_cnext;	/* cluster hash link forward */
 	struct xfs_inode	*i_cprev;	/* cluster hash link backward */
 
+	xfs_fsize_t		i_size;		/* in-memory size */
 	/* Trace buffers per inode. */
 #ifdef XFS_BMAP_TRACE
 	struct ktrace		*i_xtrace;	/* inode extent list trace */
@@ -305,6 +306,8 @@ #ifdef XFS_DIR2_TRACE
 #endif
 } xfs_inode_t;
 
+#define XFS_ISIZE(ip)	(((ip)->i_d.di_mode & S_IFMT) == S_IFREG) ? \
+				(ip)->i_size : (ip)->i_d.di_size;
 
 /*
  * i_flags helper functions
@@ -379,26 +382,58 @@ #define XFS_INEW	0x0040
 
 /*
  * Flags for inode locking.
+ * Bit ranges:	1<<1  - 1<<16-1 -- iolock/ilock modes (bitfield)
+ *		1<<16 - 1<<32-1 -- lockdep annotation (integers)
  */
-#define	XFS_IOLOCK_EXCL		0x001
-#define	XFS_IOLOCK_SHARED	0x002
-#define	XFS_ILOCK_EXCL		0x004
-#define	XFS_ILOCK_SHARED	0x008
-#define	XFS_IUNLOCK_NONOTIFY	0x010
-/*	XFS_IOLOCK_NESTED	0x020 */
-#define XFS_EXTENT_TOKEN_RD	0x040
-#define XFS_SIZE_TOKEN_RD	0x080
+#define	XFS_IOLOCK_EXCL		(1<<0)
+#define	XFS_IOLOCK_SHARED	(1<<1)
+#define	XFS_ILOCK_EXCL		(1<<2)
+#define	XFS_ILOCK_SHARED	(1<<3)
+#define	XFS_IUNLOCK_NONOTIFY	(1<<4)
+/*	#define XFS_IOLOCK_NESTED	(1<<5)	*/
+#define XFS_EXTENT_TOKEN_RD	(1<<6)
+#define XFS_SIZE_TOKEN_RD	(1<<7)
 #define XFS_EXTSIZE_RD		(XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD)
-#define XFS_WILLLEND		0x100	/* Always acquire tokens for lending */
+#define XFS_WILLLEND		(1<<8)	/* Always acquire tokens for lending */
 #define XFS_EXTENT_TOKEN_WR	(XFS_EXTENT_TOKEN_RD | XFS_WILLLEND)
 #define XFS_SIZE_TOKEN_WR       (XFS_SIZE_TOKEN_RD | XFS_WILLLEND)
 #define XFS_EXTSIZE_WR		(XFS_EXTSIZE_RD | XFS_WILLLEND)
-/*	XFS_SIZE_TOKEN_WANT	0x200 */
+/* TODO:XFS_SIZE_TOKEN_WANT	(1<<9) */
 
-#define XFS_LOCK_MASK	\
-	(XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \
-	 XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \
-	 XFS_WILLLEND)
+#define XFS_LOCK_MASK		(XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
+				| XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \
+				| XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD \
+				| XFS_WILLLEND)
+
+/*
+ * Flags for lockdep annotations.
+ *
+ * XFS_I[O]LOCK_PARENT - for operations that require locking two inodes
+ * (ie directory operations that require locking a directory inode and
+ * an entry inode).  The first inode gets locked with this flag so it
+ * gets a lockdep subclass of 1 and the second lock will have a lockdep
+ * subclass of 0.
+ *
+ * XFS_I[O]LOCK_INUMORDER - for locking several inodes at the some time
+ * with xfs_lock_inodes().  This flag is used as the starting subclass
+ * and each subsequent lock acquired will increment the subclass by one.
+ * So the first lock acquired will have a lockdep subclass of 2, the
+ * second lock will have a lockdep subclass of 3, and so on.
+ */
+#define XFS_IOLOCK_SHIFT	16
+#define	XFS_IOLOCK_PARENT	(1 << XFS_IOLOCK_SHIFT)
+#define	XFS_IOLOCK_INUMORDER	(2 << XFS_IOLOCK_SHIFT)
+
+#define XFS_ILOCK_SHIFT		24
+#define	XFS_ILOCK_PARENT	(1 << XFS_ILOCK_SHIFT)
+#define	XFS_ILOCK_INUMORDER	(2 << XFS_ILOCK_SHIFT)
+
+#define XFS_IOLOCK_DEP_MASK	0x00ff0000
+#define XFS_ILOCK_DEP_MASK	0xff000000
+#define XFS_LOCK_DEP_MASK	(XFS_IOLOCK_DEP_MASK | XFS_ILOCK_DEP_MASK)
+
+#define XFS_IOLOCK_DEP(flags)	(((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT)
+#define XFS_ILOCK_DEP(flags)	(((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT)
 
 /*
  * Flags for xfs_iflush()
@@ -481,7 +516,7 @@ uint		xfs_ip2xflags(struct xfs_inode *);
 uint		xfs_dic2xflags(struct xfs_dinode_core *);
 int		xfs_ifree(struct xfs_trans *, xfs_inode_t *,
 			   struct xfs_bmap_free *);
-void		xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
+int		xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
 int		xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
 				     xfs_fsize_t, int, int);
 int		xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
diff --git a/fs/xfs/xfs_iocore.c b/fs/xfs/xfs_iocore.c
index 06d710c..81548ec 100644
--- a/fs/xfs/xfs_iocore.c
+++ b/fs/xfs/xfs_iocore.c
@@ -52,7 +52,7 @@ STATIC xfs_fsize_t
 xfs_size_fn(
 	xfs_inode_t		*ip)
 {
-	return (ip->i_d.di_size);
+	return XFS_ISIZE(ip);
 }
 
 STATIC int
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index cc6a7b5..3f2b9f2 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -458,7 +458,7 @@ xfs_iomap_write_direct(
 		extsz = ip->i_d.di_extsize;
 	}
 
-	isize = ip->i_d.di_size;
+	isize = ip->i_size;
 	if (io->io_new_size > isize)
 		isize = io->io_new_size;
 
@@ -524,7 +524,7 @@ xfs_iomap_write_direct(
 	xfs_trans_ihold(tp, ip);
 
 	bmapi_flag = XFS_BMAPI_WRITE;
-	if ((flags & BMAPI_DIRECT) && (offset < ip->i_d.di_size || extsz))
+	if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz))
 		bmapi_flag |= XFS_BMAPI_PREALLOC;
 
 	/*
@@ -543,7 +543,7 @@ xfs_iomap_write_direct(
 	error = xfs_bmap_finish(&tp, &free_list, &committed);
 	if (error)
 		goto error0;
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (error)
 		goto error_out;
 
@@ -676,7 +676,7 @@ xfs_iomap_write_delay(
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
 
 retry:
-	isize = ip->i_d.di_size;
+	isize = ip->i_size;
 	if (io->io_new_size > isize)
 		isize = io->io_new_size;
 
@@ -817,7 +817,7 @@ xfs_iomap_write_allocate(
 			 * we dropped the ilock in the interim.
 			 */
 
-			end_fsb = XFS_B_TO_FSB(mp, ip->i_d.di_size);
+			end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
 			xfs_bmap_last_offset(NULL, ip, &last_block,
 				XFS_DATA_FORK);
 			last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
@@ -840,8 +840,7 @@ xfs_iomap_write_allocate(
 			if (error)
 				goto trans_cancel;
 
-			error = xfs_trans_commit(tp,
-					XFS_TRANS_RELEASE_LOG_RES, NULL);
+			error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 			if (error)
 				goto error0;
 
@@ -948,7 +947,7 @@ xfs_iomap_write_unwritten(
 		if (error)
 			goto error_on_bmapi_transaction;
 
-		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 		if (error)
 			return XFS_ERROR(error);
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
index 3ce204a..df441ee 100644
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -22,6 +22,7 @@ #define IOMAP_DADDR_NULL ((xfs_daddr_t) 
 
 
 typedef enum {				/* iomap_flags values */
+	IOMAP_READ =		0,	/* mapping for a read */
 	IOMAP_EOF =		0x01,	/* mapping contains EOF   */
 	IOMAP_HOLE =		0x02,	/* mapping covers a hole  */
 	IOMAP_DELAY =		0x04,	/* mapping covers delalloc region  */
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index ca74d3f..080fabf 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1509,7 +1509,6 @@ xlog_recover_insert_item_frontq(
 
 STATIC int
 xlog_recover_reorder_trans(
-	xlog_t			*log,
 	xlog_recover_t		*trans)
 {
 	xlog_recover_item_t	*first_item, *itemq, *itemq_next;
@@ -1867,7 +1866,6 @@ xlog_recover_do_inode_buffer(
 /*ARGSUSED*/
 STATIC void
 xlog_recover_do_reg_buffer(
-	xfs_mount_t		*mp,
 	xlog_recover_item_t	*item,
 	xfs_buf_t		*bp,
 	xfs_buf_log_format_t	*buf_f)
@@ -2083,7 +2081,7 @@ xlog_recover_do_dquot_buffer(
 	if (log->l_quotaoffs_flag & type)
 		return;
 
-	xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
+	xlog_recover_do_reg_buffer(item, bp, buf_f);
 }
 
 /*
@@ -2184,7 +2182,7 @@ xlog_recover_do_buffer_trans(
 		  (XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
 		xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
 	} else {
-		xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
+		xlog_recover_do_reg_buffer(item, bp, buf_f);
 	}
 	if (error)
 		return XFS_ERROR(error);
@@ -2765,7 +2763,7 @@ xlog_recover_do_trans(
 	int			error = 0;
 	xlog_recover_item_t	*item, *first_item;
 
-	if ((error = xlog_recover_reorder_trans(log, trans)))
+	if ((error = xlog_recover_reorder_trans(trans)))
 		return error;
 	first_item = item = trans->r_itemq;
 	do {
@@ -3016,7 +3014,7 @@ xlog_recover_process_efi(
 	}
 
 	efip->efi_flags |= XFS_EFI_RECOVERED;
-	xfs_trans_commit(tp, 0, NULL);
+	xfs_trans_commit(tp, 0);
 }
 
 /*
@@ -3143,7 +3141,7 @@ xlog_recover_clear_agi_bucket(
 	xfs_trans_log_buf(tp, agibp, offset,
 			  (offset + sizeof(xfs_agino_t) - 1));
 
-	(void) xfs_trans_commit(tp, 0, NULL);
+	(void) xfs_trans_commit(tp, 0);
 }
 
 /*
@@ -3886,8 +3884,7 @@ xlog_recover(
 		 * under the vfs layer, so we can get away with it unless
 		 * the device itself is read-only, in which case we fail.
 		 */
-		if ((error = xfs_dev_is_read_only(log->l_mp,
-						"recovery required"))) {
+		if ((error = xfs_dev_is_read_only(log->l_mp, "recovery"))) {
 			return error;
 		}
 
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 3bed0cf..f5aa3ef 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1653,7 +1653,7 @@ xfs_mount_log_sbunit(
 		return;
 	}
 	xfs_mod_sb(tp, fields);
-	xfs_trans_commit(tp, 0, NULL);
+	xfs_trans_commit(tp, 0);
 }
 
 
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c
index 320d63f..0d594ed 100644
--- a/fs/xfs/xfs_qmops.c
+++ b/fs/xfs/xfs_qmops.c
@@ -78,7 +78,7 @@ #endif
 		return error;
 	}
 	xfs_mod_sb(tp, XFS_SB_QFLAGS);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 	return error;
 }
 
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 9dcb32a..6f14df9 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -154,10 +154,11 @@ #define XFS_ALL_QUOTA_ENFD	(XFS_UQUOTA_E
 #define XFS_ALL_QUOTA_CHKD	(XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
 
 #define XFS_IS_QUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_QUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
 #define XFS_IS_UQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_UQUOTA_ACCT)
 #define XFS_IS_PQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_PQUOTA_ACCT)
 #define XFS_IS_GQUOTA_RUNNING(mp)	((mp)->m_qflags & XFS_GQUOTA_ACCT)
+#define XFS_IS_UQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_UQUOTA_ENFD)
+#define XFS_IS_OQUOTA_ENFORCED(mp)	((mp)->m_qflags & XFS_OQUOTA_ENFD)
 
 /*
  * Incore only flags for quotaoff - these bits get cleared when quota(s)
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index 4c6573d..7679d7a 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -584,7 +584,7 @@ xfs_rename(
 	 * trans_commit will unlock src_ip, target_ip & decrement
 	 * the vnode references.
 	 */
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (target_ip != NULL) {
 		xfs_refcache_purge_ip(target_ip);
 		IRELE(target_ip);
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 6fff19d..b3a5f07 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -150,7 +150,7 @@ xfs_growfs_rt_alloc(
 		error = xfs_bmap_finish(&tp, &flist, &committed);
 		if (error)
 			goto error_exit;
-		xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+		xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 		/*
 		 * Now we need to clear the allocated blocks.
 		 * Do this one block per transaction, to keep it simple.
@@ -187,7 +187,7 @@ xfs_growfs_rt_alloc(
 			/*
 			 * Commit the transaction.
 			 */
-			xfs_trans_commit(tp, 0, NULL);
+			xfs_trans_commit(tp, 0);
 		}
 		/*
 		 * Go on to the next extent, if any.
@@ -2042,7 +2042,7 @@ xfs_growfs_rt(
 		/*
 		 * Commit the transaction.
 		 */
-		xfs_trans_commit(tp, 0, NULL);
+		xfs_trans_commit(tp, 0);
 	}
 
 	if (error)
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
index 1ea7c0c..905d1c0 100644
--- a/fs/xfs/xfs_rw.c
+++ b/fs/xfs/xfs_rw.c
@@ -83,7 +83,7 @@ xfs_write_clear_setuid(
 	}
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	xfs_trans_set_sync(tp);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	return 0;
 }
@@ -164,7 +164,7 @@ xfs_write_sync_logforce(
 			xfs_trans_ihold(tp, ip);
 			xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 			xfs_trans_set_sync(tp);
-			error = xfs_trans_commit(tp, 0, NULL);
+			error = xfs_trans_commit(tp, 0);
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
 		}
 	}
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 301ff94..cc2d609 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -753,7 +753,6 @@ int
 _xfs_trans_commit(
 	xfs_trans_t	*tp,
 	uint		flags,
-	xfs_lsn_t	*commit_lsn_p,
 	int		*log_flushed)
 {
 	xfs_log_iovec_t		*log_vector;
@@ -812,8 +811,6 @@ shut_us_down:
 		xfs_trans_free_busy(tp);
 		xfs_trans_free(tp);
 		XFS_STATS_INC(xs_trans_empty);
-		if (commit_lsn_p)
-			*commit_lsn_p = commit_lsn;
 		return (shutdown);
 	}
 	ASSERT(tp->t_ticket != NULL);
@@ -864,9 +861,6 @@ shut_us_down:
 		kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
 	}
 
-	if (commit_lsn_p)
-		*commit_lsn_p = commit_lsn;
-
 	/*
 	 * If we got a log write error. Unpin the logitems that we
 	 * had pinned, clean up, free trans structure, and return error.
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index f1d7ab2..7dfcc45 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -988,10 +988,8 @@ void		xfs_trans_log_efd_extent(xfs_trans
 					 xfs_extlen_t);
 int		_xfs_trans_commit(xfs_trans_t *,
 				  uint flags,
-				  xfs_lsn_t *,
 				  int *);
-#define xfs_trans_commit(tp, flags, lsn) \
-	_xfs_trans_commit(tp, flags, lsn, NULL)
+#define xfs_trans_commit(tp, flags)	_xfs_trans_commit(tp, flags, NULL)
 void		xfs_trans_cancel(xfs_trans_t *, int);
 void		xfs_trans_ail_init(struct xfs_mount *);
 xfs_lsn_t	xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t);
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 9014d7e..20ffec3 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -222,7 +222,7 @@ xfs_dir_ialloc(
 		}
 
 		ntp = xfs_trans_dup(tp);
-		code = xfs_trans_commit(tp, 0, NULL);
+		code = xfs_trans_commit(tp, 0);
 		tp = ntp;
 		if (committed != NULL) {
 			*committed = 1;
@@ -420,7 +420,11 @@ #endif
 	 * in a transaction.
 	 */
 	xfs_ilock(ip, XFS_IOLOCK_EXCL);
-	xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
+	error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
+	if (error) {
+		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+		return error;
+	}
 
 	tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
 	if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
@@ -460,8 +464,7 @@ #endif
 				 XFS_TRANS_ABORT);
 	} else {
 		xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
-					 NULL);
+		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	}
 	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
 
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 29f72f6..65c5612 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -696,7 +696,7 @@ xfs_unmount_flush(
 	bhv_vnode_t	*rvp = XFS_ITOV(rip);
 	int		error;
 
-	xfs_ilock(rip, XFS_ILOCK_EXCL);
+	xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 	xfs_iflock(rip);
 
 	/*
@@ -1147,7 +1147,7 @@ #define XFS_PREEMPT_MASK	0x7f
 			if (XFS_FORCED_SHUTDOWN(mp)) {
 				bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
 			} else {
-				bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
+				error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
 			}
 
 			xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1539,7 +1539,7 @@ xfs_syncsub(
 		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
 		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-		error = xfs_trans_commit(tp, 0, NULL);
+		error = xfs_trans_commit(tp, 0);
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 		xfs_log_force(mp, (xfs_lsn_t)0, log_flags);
 	}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 52c4171..de17aed 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -133,7 +133,7 @@ xfs_getattr(
 	if (!(flags & ATTR_LAZY))
 		xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-	vap->va_size = ip->i_d.di_size;
+	vap->va_size = XFS_ISIZE(ip);
 	if (vap->va_mask == XFS_AT_SIZE)
 		goto all_done;
 
@@ -496,7 +496,7 @@ #endif
 	if (mask & XFS_AT_SIZE) {
 		/* Short circuit the truncate case for zero length files */
 		if ((vap->va_size == 0) &&
-		   (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) {
+		   (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
 			lock_flags &= ~XFS_ILOCK_EXCL;
 			if (mask & XFS_AT_CTIME)
@@ -614,7 +614,7 @@ #endif
 	 */
 	if (mask & XFS_AT_SIZE) {
 		code = 0;
-		if ((vap->va_size > ip->i_d.di_size) && 
+		if ((vap->va_size > ip->i_size) &&
 		    (flags & ATTR_NOSIZETOK) == 0) {
 			code = xfs_igrow_start(ip, vap->va_size, credp);
 		}
@@ -654,10 +654,10 @@ #endif
 	 * Truncate file.  Must have write permission and not be a directory.
 	 */
 	if (mask & XFS_AT_SIZE) {
-		if (vap->va_size > ip->i_d.di_size) {
+		if (vap->va_size > ip->i_size) {
 			xfs_igrow_finish(tp, ip, vap->va_size,
 			    !(flags & ATTR_DMI));
-		} else if ((vap->va_size <= ip->i_d.di_size) ||
+		} else if ((vap->va_size <= ip->i_size) ||
 			   ((vap->va_size == 0) && ip->i_d.di_nextents)) {
 			/*
 			 * signal a sync transaction unless
@@ -873,7 +873,7 @@ #endif
 		if (mp->m_flags & XFS_MOUNT_WSYNC)
 			xfs_trans_set_sync(tp);
 
-		code = xfs_trans_commit(tp, commit_flags, NULL);
+		code = xfs_trans_commit(tp, commit_flags);
 	}
 
 	/*
@@ -1176,7 +1176,7 @@ xfs_fsync(
 		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 		if (flag & FSYNC_WAIT)
 			xfs_trans_set_sync(tp);
-		error = _xfs_trans_commit(tp, 0, NULL, &log_flushed);
+		error = _xfs_trans_commit(tp, 0, &log_flushed);
 
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	}
@@ -1221,7 +1221,7 @@ xfs_inactive_free_eofblocks(
 	 * Figure out if there are any blocks beyond the end
 	 * of the file.  If not, then there is nothing to do.
 	 */
-	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_d.di_size));
+	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
 	last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
 	map_len = last_fsb - end_fsb;
 	if (map_len <= 0)
@@ -1257,8 +1257,12 @@ xfs_inactive_free_eofblocks(
 		 * do that within a transaction.
 		 */
 		xfs_ilock(ip, XFS_IOLOCK_EXCL);
-		xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
-				    ip->i_d.di_size);
+		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
+				    ip->i_size);
+		if (error) {
+			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+			return error;
+		}
 
 		error = xfs_trans_reserve(tp, 0,
 					  XFS_ITRUNCATE_LOG_RES(mp),
@@ -1278,7 +1282,7 @@ xfs_inactive_free_eofblocks(
 		xfs_trans_ihold(tp, ip);
 
 		error = xfs_itruncate_finish(&tp, ip,
-					     ip->i_d.di_size,
+					     ip->i_size,
 					     XFS_DATA_FORK,
 					     0);
 		/*
@@ -1291,8 +1295,7 @@ xfs_inactive_free_eofblocks(
 					  XFS_TRANS_ABORT));
 		} else {
 			error = xfs_trans_commit(tp,
-						XFS_TRANS_RELEASE_LOG_RES,
-						NULL);
+						XFS_TRANS_RELEASE_LOG_RES);
 		}
 		xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
 	}
@@ -1406,7 +1409,7 @@ xfs_inactive_symlink_rmt(
 	 * we need to unlock the inode since the new transaction doesn't
 	 * have the inode attached.
 	 */
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 	tp = ntp;
 	if (error) {
 		ASSERT(XFS_FORCED_SHUTDOWN(mp));
@@ -1503,7 +1506,7 @@ xfs_inactive_attrs(
 	tp = *tpp;
 	mp = ip->i_mount;
 	ASSERT(ip->i_d.di_forkoff != 0);
-	xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
 	error = xfs_attr_inactive(ip);
@@ -1565,7 +1568,7 @@ #endif
 
 	if (ip->i_d.di_nlink != 0) {
 		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
-		     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+		     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||
 		       ip->i_delayed_blks > 0)) &&
 		     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
 		    (!(ip->i_d.di_flags &
@@ -1626,8 +1629,8 @@ xfs_inactive(
 	 * only one with a reference to the inode.
 	 */
 	truncate = ((ip->i_d.di_nlink == 0) &&
-            ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0) ||
-             (ip->i_delayed_blks > 0)) &&
+	    ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
+	     (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
 	    ((ip->i_d.di_mode & S_IFMT) == S_IFREG));
 
 	mp = ip->i_mount;
@@ -1645,7 +1648,7 @@ xfs_inactive(
 
 	if (ip->i_d.di_nlink != 0) {
 		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
-                     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+                     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||
                        ip->i_delayed_blks > 0)) &&
 		      (ip->i_df.if_flags & XFS_IFEXTENTS) &&
 		     (!(ip->i_d.di_flags &
@@ -1675,7 +1678,11 @@ xfs_inactive(
 		 */
 		xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
-		xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
+		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
+		if (error) {
+			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+			return VN_INACTIVE_CACHE;
+		}
 
 		error = xfs_trans_reserve(tp, 0,
 					  XFS_ITRUNCATE_LOG_RES(mp),
@@ -1790,7 +1797,7 @@ xfs_inactive(
 		 * nothing we can do except to try to keep going.
 		 */
 		(void) xfs_bmap_finish(&tp,  &free_list, &committed);
-		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	}
 	/*
 	 * Release the dquots held by inode, if any.
@@ -1940,7 +1947,7 @@ xfs_create(
 		goto error_return;
 	}
 
-	xfs_ilock(dp, XFS_ILOCK_EXCL);
+	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
 	XFS_BMAP_INIT(&free_list, &first_block);
 
@@ -2026,7 +2033,7 @@ xfs_create(
 		goto abort_rele;
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (error) {
 		IRELE(ip);
 		tp = NULL;
@@ -2121,7 +2128,6 @@ #endif
 STATIC int
 xfs_lock_dir_and_entry(
 	xfs_inode_t	*dp,
-	bhv_vname_t	*dentry,
 	xfs_inode_t	*ip)	/* inode of entry 'name' */
 {
 	int		attempts;
@@ -2135,7 +2141,7 @@ #endif
 	attempts = 0;
 
 again:
-	xfs_ilock(dp, XFS_ILOCK_EXCL);
+	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
 	e_inum = ip->i_ino;
 
@@ -2204,6 +2210,21 @@ int xfs_lock_delays;
 #endif
 
 /*
+ * Bump the subclass so xfs_lock_inodes() acquires each lock with
+ * a different value
+ */
+static inline int
+xfs_lock_inumorder(int lock_mode, int subclass)
+{
+	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+		lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+	if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
+		lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+
+	return lock_mode;
+}
+
+/*
  * The following routine will lock n inodes in exclusive mode.
  * We assume the caller calls us with the inodes in i_ino order.
  *
@@ -2270,7 +2291,7 @@ again:
 			 * that is in the AIL.
 			 */
 			ASSERT(i != 0);
-			if (!xfs_ilock_nowait(ips[i], lock_mode)) {
+			if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
 				attempts++;
 
 				/*
@@ -2305,7 +2326,7 @@ #endif
 				goto again;
 			}
 		} else {
-			xfs_ilock(ips[i], lock_mode);
+			xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
 		}
 	}
 
@@ -2440,7 +2461,7 @@ xfs_remove(
 		return error;
 	}
 
-	error = xfs_lock_dir_and_entry(dp, dentry, ip);
+	error = xfs_lock_dir_and_entry(dp, ip);
 	if (error) {
 		REMOVE_DEBUG_TRACE(__LINE__);
 		xfs_trans_cancel(tp, cancel_flags);
@@ -2511,7 +2532,7 @@ xfs_remove(
 		goto error_rele;
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (error) {
 		IRELE(ip);
 		goto std_return;
@@ -2719,7 +2740,7 @@ xfs_link(
 		goto abort_return;
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (error)
 		goto std_return;
 
@@ -2839,7 +2860,7 @@ xfs_mkdir(
 		goto error_return;
 	}
 
-	xfs_ilock(dp, XFS_ILOCK_EXCL);
+	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
 	/*
 	 * Check for directory link count overflow.
@@ -2936,7 +2957,7 @@ xfs_mkdir(
 		goto error2;
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	XFS_QM_DQRELE(mp, udqp);
 	XFS_QM_DQRELE(mp, gdqp);
 	if (error) {
@@ -3096,7 +3117,7 @@ xfs_rmdir(
 	 * that the directory entry for the child directory inode has
 	 * not changed while we were obtaining a log reservation.
 	 */
-	error = xfs_lock_dir_and_entry(dp, dentry, cdp);
+	error = xfs_lock_dir_and_entry(dp, cdp);
 	if (error) {
 		xfs_trans_cancel(tp, cancel_flags);
 		IRELE(cdp);
@@ -3190,7 +3211,7 @@ xfs_rmdir(
 		goto std_return;
 	}
 
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	if (error) {
 		IRELE(cdp);
 		goto std_return;
@@ -3393,7 +3414,7 @@ xfs_symlink(
 		goto error_return;
 	}
 
-	xfs_ilock(dp, XFS_ILOCK_EXCL);
+	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
 	/*
 	 * Check whether the directory allows new symlinks or not.
@@ -3535,7 +3556,7 @@ xfs_symlink(
 	if (error) {
 		goto error2;
 	}
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 	XFS_QM_DQRELE(mp, udqp);
 	XFS_QM_DQRELE(mp, gdqp);
 
@@ -3790,7 +3811,7 @@ xfs_set_dmattrs (
 
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	IHOLD(ip);
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 
 	return error;
 }
@@ -4049,14 +4070,14 @@ xfs_alloc_file_space(
 	allocatesize_fsb = XFS_B_TO_FSB(mp, count);
 
 	/*	Generate a DMAPI event if needed.	*/
-	if (alloc_type != 0 && offset < ip->i_d.di_size &&
+	if (alloc_type != 0 && offset < ip->i_size &&
 			(attr_flags&ATTR_DMI) == 0  &&
 			DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
 		xfs_off_t           end_dmi_offset;
 
 		end_dmi_offset = offset+len;
-		if (end_dmi_offset > ip->i_d.di_size)
-			end_dmi_offset = ip->i_d.di_size;
+		if (end_dmi_offset > ip->i_size)
+			end_dmi_offset = ip->i_size;
 		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
 			offset, end_dmi_offset - offset,
 			0, NULL);
@@ -4148,7 +4169,7 @@ retry:
 			goto error0;
 		}
 
-		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 		if (error) {
 			break;
@@ -4283,7 +4304,6 @@ xfs_free_file_space(
 	int			error;
 	xfs_fsblock_t		firstfsb;
 	xfs_bmap_free_t		free_list;
-	xfs_off_t		ilen;
 	xfs_bmbt_irec_t		imap;
 	xfs_off_t		ioffset;
 	xfs_extlen_t		mod=0;
@@ -4312,11 +4332,11 @@ xfs_free_file_space(
 	end_dmi_offset = offset + len;
 	endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
 
-	if (offset < ip->i_d.di_size &&
+	if (offset < ip->i_size &&
 	    (attr_flags & ATTR_DMI) == 0 &&
 	    DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
-		if (end_dmi_offset > ip->i_d.di_size)
-			end_dmi_offset = ip->i_d.di_size;
+		if (end_dmi_offset > ip->i_size)
+			end_dmi_offset = ip->i_size;
 		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp,
 				offset, end_dmi_offset - offset,
 				AT_DELAY_FLAG(attr_flags), NULL);
@@ -4332,16 +4352,15 @@ xfs_free_file_space(
 	}
 
 	rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP);
-	ilen = len + (offset & (rounding - 1));
 	ioffset = offset & ~(rounding - 1);
-	if (ilen & (rounding - 1))
-		ilen = (ilen + rounding) & ~(rounding - 1);
 
 	if (VN_CACHED(vp) != 0) {
 		xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,
 				ctooff(offtoct(ioffset)), -1);
-		bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),
+		error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),
 				-1, FI_REMAPF_LOCKED);
+		if (error)
+			goto out_unlock_iolock;
 	}
 
 	/*
@@ -4455,7 +4474,7 @@ xfs_free_file_space(
 			goto error0;
 		}
 
-		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	}
 
@@ -4533,7 +4552,7 @@ xfs_change_file_space(
 		bf->l_start += offset;
 		break;
 	case 2: /*SEEK_END*/
-		bf->l_start += ip->i_d.di_size;
+		bf->l_start += ip->i_size;
 		break;
 	default:
 		return XFS_ERROR(EINVAL);
@@ -4550,7 +4569,7 @@ xfs_change_file_space(
 	bf->l_whence = 0;
 
 	startoffset = bf->l_start;
-	fsize = ip->i_d.di_size;
+	fsize = ip->i_size;
 
 	/*
 	 * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
@@ -4649,7 +4668,7 @@ xfs_change_file_space(
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	xfs_trans_set_sync(tp);
 
-	error = xfs_trans_commit(tp, 0, NULL);
+	error = xfs_trans_commit(tp, 0);
 
 	xfs_iunlock(ip, XFS_ILOCK_EXCL);
 
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 0d9f984..9cfd5b1 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -303,6 +303,9 @@ #define acpi_driver_data(d)	((d)->driver
 #define to_acpi_device(d)	container_of(d, struct acpi_device, dev)
 #define to_acpi_driver(d)	container_of(d, struct acpi_driver, drv)
 
+/* acpi_device.dev.bus == &acpi_bus_type */
+extern struct bus_type acpi_bus_type;
+
 /*
  * Events
  * ------
@@ -316,7 +319,7 @@ struct acpi_bus_event {
 	u32 data;
 };
 
-extern struct subsystem acpi_subsys;
+extern struct kset acpi_subsys;
 
 /*
  * External Functions
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 09469e7..955adfb 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -276,6 +276,7 @@ enum acpi_prefered_pm_profiles {
 
 #define BAF_LEGACY_DEVICES              0x0001
 #define BAF_8042_KEYBOARD_CONTROLLER    0x0002
+#define BAF_MSI_NOT_SUPPORTED           0x0008
 
 #define FADT2_REVISION_ID               3
 #define FADT2_MINUS_REVISION_ID         2
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index fc77f74..f5cb7b8 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -2,6 +2,7 @@ #ifndef _ALPHA_ATOMIC_H
 #define _ALPHA_ATOMIC_H
 
 #include <asm/barrier.h>
+#include <asm/system.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -175,19 +176,64 @@ static __inline__ long atomic64_sub_retu
 	return result;
 }
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+/**
+ * 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.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
 #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
 
diff --git a/include/asm-alpha/kdebug.h b/include/asm-alpha/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-alpha/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-alpha/local.h b/include/asm-alpha/local.h
index 90a510f..6ad3ea6 100644
--- a/include/asm-alpha/local.h
+++ b/include/asm-alpha/local.h
@@ -4,37 +4,115 @@ #define _ALPHA_LOCAL_H
 #include <linux/percpu.h>
 #include <asm/atomic.h>
 
-typedef atomic64_t local_t;
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
 
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
 
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
+static __inline__ long local_add_return(long i, local_t * l)
+{
+	long temp, result;
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%1\n"
+	"	addq %0,%3,%2\n"
+	"	addq %0,%3,%0\n"
+	"	stq_c %0,%1\n"
+	"	beq %0,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+	:"Ir" (i), "m" (l->a.counter) : "memory");
+	return result;
+}
 
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter++)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+	long temp, result;
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%1\n"
+	"	subq %0,%3,%2\n"
+	"	subq %0,%3,%0\n"
+	"	stq_c %0,%1\n"
+	"	beq %0,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	:"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+	:"Ir" (i), "m" (l->a.counter) : "memory");
+	return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+
+#define local_inc_return(l) local_add_return(1,(l))
+
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+#define local_inc_and_test(l) (local_add_return(1, (l)) == 0)
+
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/* Verify if faster than atomic ops */
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
 
 /* Use these for per-cpu local_t variables: on some archs they are
  * much more efficient than these naive implementations.  Note they take
  * a variable, not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l)	local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i)	local_set(&__get_cpu_var(l), (i))
+
+#define cpu_local_inc(l)	local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l)	local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l)	local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l)	local_sub((i), &__get_cpu_var(l))
+
+#define __cpu_local_inc(l)	__local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l)	__local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l)	__local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l)	__local_sub((i), &__get_cpu_var(l))
 
 #endif /* _ALPHA_LOCAL_H */
diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
index fe249e9..0bd7bd2 100644
--- a/include/asm-alpha/mmu_context.h
+++ b/include/asm-alpha/mmu_context.h
@@ -10,6 +10,7 @@ #define __ALPHA_MMU_CONTEXT_H
 #include <asm/system.h>
 #include <asm/machvec.h>
 #include <asm/compiler.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * Force a context reload. This is needed when we change the page
diff --git a/include/asm-alpha/percpu.h b/include/asm-alpha/percpu.h
index 651ebb1..48348fe 100644
--- a/include/asm-alpha/percpu.h
+++ b/include/asm-alpha/percpu.h
@@ -1,20 +1,6 @@
 #ifndef __ALPHA_PERCPU_H
 #define __ALPHA_PERCPU_H
 
-/*
- * Increase the per cpu area for Alpha so that
- * modules using percpu area can load.
- */
-#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)
-
 #include <asm-generic/percpu.h>
 
 #endif /* __ALPHA_PERCPU_H */
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 49ac9be..616d206 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -345,10 +345,6 @@ #endif
 #define io_remap_pfn_range(vma, start, pfn, size, prot)	\
 		remap_pfn_range(vma, start, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
diff --git a/include/asm-alpha/scatterlist.h b/include/asm-alpha/scatterlist.h
index 6afb8bd..9173654 100644
--- a/include/asm-alpha/scatterlist.h
+++ b/include/asm-alpha/scatterlist.h
@@ -2,6 +2,7 @@ #ifndef _ALPHA_SCATTERLIST_H
 #define _ALPHA_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
   
 struct scatterlist {
 	struct page *page;
diff --git a/include/asm-alpha/socket.h b/include/asm-alpha/socket.h
index d22ab97..1fede7f 100644
--- a/include/asm-alpha/socket.h
+++ b/include/asm-alpha/socket.h
@@ -52,6 +52,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		30
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		19
diff --git a/include/asm-alpha/sockios.h b/include/asm-alpha/sockios.h
index e4961a7..7932c7a 100644
--- a/include/asm-alpha/sockios.h
+++ b/include/asm-alpha/sockios.h
@@ -10,6 +10,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_ALPHA_SOCKIOS_H */
diff --git a/include/asm-alpha/string.h b/include/asm-alpha/string.h
index 9e44fea..b02b8a2 100644
--- a/include/asm-alpha/string.h
+++ b/include/asm-alpha/string.h
@@ -61,8 +61,6 @@ (__builtin_constant_p(c)						 \
  ? __constant_c_memset((s),0x0001000100010001UL*(unsigned short)(c),(n)) \
  : __memsetw((s),(c),(n)))
 
-extern int strcasecmp(const char *, const char *);
-
 #endif /* __KERNEL__ */
 
 #endif /* __ALPHA_STRING_H__ */
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 03e9c0e..cf1021a 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -443,8 +443,110 @@ #define xchg(ptr,x)							     \
      (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
   })
 
-#define tas(ptr) (xchg((ptr),1))
+static inline unsigned long
+__xchg_u8_local(volatile char *m, unsigned long val)
+{
+	unsigned long ret, tmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%4,7,%3\n"
+	"	insbl	%1,%4,%1\n"
+	"1:	ldq_l	%2,0(%3)\n"
+	"	extbl	%2,%4,%0\n"
+	"	mskbl	%2,%4,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%3)\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+	: "r" ((long)m), "1" (val) : "memory");
 
+	return ret;
+}
+
+static inline unsigned long
+__xchg_u16_local(volatile short *m, unsigned long val)
+{
+	unsigned long ret, tmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%4,7,%3\n"
+	"	inswl	%1,%4,%1\n"
+	"1:	ldq_l	%2,0(%3)\n"
+	"	extwl	%2,%4,%0\n"
+	"	mskwl	%2,%4,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%3)\n"
+	"	beq	%2,2f\n"
+	".subsection 2\n"
+	"2:	br	1b\n"
+	".previous"
+	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+	: "r" ((long)m), "1" (val) : "memory");
+
+	return ret;
+}
+
+static inline unsigned long
+__xchg_u32_local(volatile int *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%4\n"
+	"	bis $31,%3,%1\n"
+	"	stl_c %1,%2\n"
+	"	beq %1,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	: "=&r" (val), "=&r" (dummy), "=m" (*m)
+	: "rI" (val), "m" (*m) : "memory");
+
+	return val;
+}
+
+static inline unsigned long
+__xchg_u64_local(volatile long *m, unsigned long val)
+{
+	unsigned long dummy;
+
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%4\n"
+	"	bis $31,%3,%1\n"
+	"	stq_c %1,%2\n"
+	"	beq %1,2f\n"
+	".subsection 2\n"
+	"2:	br 1b\n"
+	".previous"
+	: "=&r" (val), "=&r" (dummy), "=m" (*m)
+	: "rI" (val), "m" (*m) : "memory");
+
+	return val;
+}
+
+#define __xchg_local(ptr, x, size) \
+({ \
+	unsigned long __xchg__res; \
+	volatile void *__xchg__ptr = (ptr); \
+	switch (size) { \
+		case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
+		case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
+		case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
+		case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
+		default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
+	} \
+	__xchg__res; \
+})
+
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_,	     \
+     		sizeof(*(ptr))); \
+  })
 
 /* 
  * Atomic compare and exchange.  Compare OLD with MEM, if identical,
@@ -596,6 +698,128 @@ #define cmpxchg(ptr,o,n)						 \
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+static inline unsigned long
+__cmpxchg_u8_local(volatile char *m, long old, long new)
+{
+	unsigned long prev, tmp, cmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%5,7,%4\n"
+	"	insbl	%1,%5,%1\n"
+	"1:	ldq_l	%2,0(%4)\n"
+	"	extbl	%2,%5,%0\n"
+	"	cmpeq	%0,%6,%3\n"
+	"	beq	%3,2f\n"
+	"	mskbl	%2,%5,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%4)\n"
+	"	beq	%2,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br	1b\n"
+	".previous"
+	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u16_local(volatile short *m, long old, long new)
+{
+	unsigned long prev, tmp, cmp, addr64;
+
+	__asm__ __volatile__(
+	"	andnot	%5,7,%4\n"
+	"	inswl	%1,%5,%1\n"
+	"1:	ldq_l	%2,0(%4)\n"
+	"	extwl	%2,%5,%0\n"
+	"	cmpeq	%0,%6,%3\n"
+	"	beq	%3,2f\n"
+	"	mskwl	%2,%5,%2\n"
+	"	or	%1,%2,%2\n"
+	"	stq_c	%2,0(%4)\n"
+	"	beq	%2,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br	1b\n"
+	".previous"
+	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u32_local(volatile int *m, int old, int new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldl_l %0,%5\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stl_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+	return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
+{
+	unsigned long prev, cmp;
+
+	__asm__ __volatile__(
+	"1:	ldq_l %0,%5\n"
+	"	cmpeq %0,%3,%1\n"
+	"	beq %1,2f\n"
+	"	mov %4,%1\n"
+	"	stq_c %1,%2\n"
+	"	beq %1,3f\n"
+	"2:\n"
+	".subsection 2\n"
+	"3:	br 1b\n"
+	".previous"
+	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
+	: "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+	return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+		int size)
+{
+	switch (size) {
+		case 1:
+			return __cmpxchg_u8_local(ptr, old, new);
+		case 2:
+			return __cmpxchg_u16_local(ptr, old, new);
+		case 4:
+			return __cmpxchg_u32_local(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64_local(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg_local(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 #endif /* __ASSEMBLY__ */
 
 #define arch_align_stack(x) (x)
diff --git a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h
index 69ffd93..eeb3bef 100644
--- a/include/asm-alpha/thread_info.h
+++ b/include/asm-alpha/thread_info.h
@@ -92,5 +92,27 @@ #define _TIF_WORK_MASK		(_TIF_NOTIFY_RES
 #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 */
diff --git a/include/asm-arm/arch-at91/at91_adc.h b/include/asm-arm/arch-at91/at91_adc.h
new file mode 100644
index 0000000..1ed66ea
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * include/asm-arm/arch-at91/at91_adc.h
+ *
+ * Copyright (C) SAN People
+ *
+ * Analog-to-Digital Converter (ADC) registers.
+ * Based on AT91SAM9260 datasheet revision D.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AT91_ADC_H
+#define AT91_ADC_H
+
+#define AT91_ADC_CR		0x00		/* Control Register */
+#define		AT91_ADC_SWRST		(1 << 0)	/* Software Reset */
+#define		AT91_ADC_START		(1 << 1)	/* Start Conversion */
+
+#define AT91_ADC_MR		0x04		/* Mode Register */
+#define		AT91_ADC_TRGEN		(1 << 0)	/* Trigger Enable */
+#define		AT91_ADC_TRGSEL		(7 << 1)	/* Trigger Selection */
+#define			AT91_ADC_TRGSEL_TC0		(0 << 1)
+#define			AT91_ADC_TRGSEL_TC1		(1 << 1)
+#define			AT91_ADC_TRGSEL_TC2		(2 << 1)
+#define			AT91_ADC_TRGSEL_EXTERNAL	(6 << 1)
+#define		AT91_ADC_LOWRES		(1 << 4)	/* Low Resolution */
+#define		AT91_ADC_SLEEP		(1 << 5)	/* Sleep Mode */
+#define		AT91_ADC_PRESCAL	(0x3f << 8)	/* Prescalar Rate Selection */
+#define			AT91_ADC_PRESCAL_(x)	((x) << 8)
+#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define			AT91_ADC_STARTUP_(x)	((x) << 16)
+#define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
+#define			AT91_ADC_SHTIM_(x)	((x) << 24)
+
+#define AT91_ADC_CHER		0x10		/* Channel Enable Register */
+#define AT91_ADC_CHDR		0x14		/* Channel Disable Register */
+#define AT91_ADC_CHSR		0x18		/* Channel Status Register */
+#define		AT91_ADC_CH(n)		(1 << (n))	/* Channel Number */
+
+#define AT91_ADC_SR		0x1C		/* Status Register */
+#define		AT91_ADC_EOC(n)		(1 << (n))	/* End of Conversion on Channel N */
+#define		AT91_ADC_OVRE(n)	(1 << ((n) + 8))/* Overrun Error on Channel N */
+#define		AT91_ADC_DRDY		(1 << 16)	/* Data Ready */
+#define		AT91_ADC_GOVRE		(1 << 17)	/* General Overrun Error */
+#define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */
+#define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */
+
+#define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */
+#define		AT91_ADC_LDATA		(0x3ff)
+
+#define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
+#define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
+#define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
+
+#define AT91_ADC_CHR(n)		(0x30 + ((n) * 4)	/* Channel Data Register N */
+#define		AT91_ADC_DATA		(0x3ff)
+
+#endif
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 7b9903c..7a34a5b 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -62,7 +62,7 @@ struct at91_mmc_data {
 };
 extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
 
- /* Ethernet */
+ /* Ethernet (EMAC & MACB) */
 struct at91_eth_data {
 	u8		phy_irq_pin;	/* PHY IRQ */
 	u8		is_rmii;	/* using RMII interface? */
@@ -114,6 +114,16 @@ struct atmel_uart_data {
 };
 extern void __init at91_add_device_serial(void);
 
+ /* LCD Controller */
+struct atmel_lcdfb_info;
+extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+
+ /* AC97 */
+struct atmel_ac97_data {
+	u8		reset_pin;	/* reset */
+}
+extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
+
  /* LEDs */
 extern u8 at91_leds_cpu;
 extern u8 at91_leds_timer;
diff --git a/include/asm-arm/arch-ebsa110/io.h b/include/asm-arm/arch-ebsa110/io.h
index 722c5e0..44a4001 100644
--- a/include/asm-arm/arch-ebsa110/io.h
+++ b/include/asm-arm/arch-ebsa110/io.h
@@ -81,4 +81,12 @@ extern void outsb(unsigned int port, con
 extern void outsw(unsigned int port, const void *buf, int sz);
 extern void outsl(unsigned int port, const void *buf, int sz);
 
+/* can't support writesb atm */
+extern void writesw(void __iomem *addr, const void *data, int wordlen);
+extern void writesl(void __iomem *addr, const void *data, int longlen);
+
+/* can't support readsb atm */
+extern void readsw(const void __iomem *addr, void *data, int wordlen);
+extern void readsl(const void __iomem *addr, void *data, int longlen);
+
 #endif
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
index e56a4e2..de6494a 100644
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -477,122 +477,4 @@ #define LCDISR_ERR_RES (1<<2)
 #define LCDISR_EOF     (1<<1)
 #define LCDISR_BOF     (1<<0)
 
-/*
- *  UART Module. Takes the UART base address as argument
- */
-#define URXD0(x) __REG( 0x0 + (x)) /* Receiver Register */
-#define URTX0(x) __REG( 0x40 + (x)) /* Transmitter Register */
-#define UCR1(x)  __REG( 0x80 + (x)) /* Control Register 1 */
-#define UCR2(x)  __REG( 0x84 + (x)) /* Control Register 2 */
-#define UCR3(x)  __REG( 0x88 + (x)) /* Control Register 3 */
-#define UCR4(x)  __REG( 0x8c + (x)) /* Control Register 4 */
-#define UFCR(x)  __REG( 0x90 + (x)) /* FIFO Control Register */
-#define USR1(x)  __REG( 0x94 + (x)) /* Status Register 1 */
-#define USR2(x)  __REG( 0x98 + (x)) /* Status Register 2 */
-#define UESC(x)  __REG( 0x9c + (x)) /* Escape Character Register */
-#define UTIM(x)  __REG( 0xa0 + (x)) /* Escape Timer Register */
-#define UBIR(x)  __REG( 0xa4 + (x)) /* BRM Incremental Register */
-#define UBMR(x)  __REG( 0xa8 + (x)) /* BRM Modulator Register */
-#define UBRC(x)  __REG( 0xac + (x)) /* Baud Rate Count Register */
-#define BIPR1(x) __REG( 0xb0 + (x)) /* Incremental Preset Register 1 */
-#define BIPR2(x) __REG( 0xb4 + (x)) /* Incremental Preset Register 2 */
-#define BIPR3(x) __REG( 0xb8 + (x)) /* Incremental Preset Register 3 */
-#define BIPR4(x) __REG( 0xbc + (x)) /* Incremental Preset Register 4 */
-#define BMPR1(x) __REG( 0xc0 + (x)) /* BRM Modulator Register 1 */
-#define BMPR2(x) __REG( 0xc4 + (x)) /* BRM Modulator Register 2 */
-#define BMPR3(x) __REG( 0xc8 + (x)) /* BRM Modulator Register 3 */
-#define BMPR4(x) __REG( 0xcc + (x)) /* BRM Modulator Register 4 */
-#define UTS(x)   __REG( 0xd0 + (x)) /* UART Test Register */
-
-/* UART Control Register Bit Fields.*/
-#define  URXD_CHARRDY    (1<<15)
-#define  URXD_ERR        (1<<14)
-#define  URXD_OVRRUN     (1<<13)
-#define  URXD_FRMERR     (1<<12)
-#define  URXD_BRK        (1<<11)
-#define  URXD_PRERR      (1<<10)
-#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
-#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
-#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
-#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
-#define  UCR1_RRDYEN     (1<<9)	 /* Recv ready interrupt enable */
-#define  UCR1_RDMAEN     (1<<8)	 /* Recv ready DMA enable */
-#define  UCR1_IREN       (1<<7)	 /* Infrared interface enable */
-#define  UCR1_TXMPTYEN   (1<<6)	 /* Transimitter empty interrupt enable */
-#define  UCR1_RTSDEN     (1<<5)	 /* RTS delta interrupt enable */
-#define  UCR1_SNDBRK     (1<<4)	 /* Send break */
-#define  UCR1_TDMAEN     (1<<3)	 /* Transmitter ready DMA enable */
-#define  UCR1_UARTCLKEN  (1<<2)	 /* UART clock enabled */
-#define  UCR1_DOZE       (1<<1)	 /* Doze */
-#define  UCR1_UARTEN     (1<<0)	 /* UART enabled */
-#define  UCR2_ESCI     	 (1<<15) /* Escape seq interrupt enable */
-#define  UCR2_IRTS  	 (1<<14) /* Ignore RTS pin */
-#define  UCR2_CTSC  	 (1<<13) /* CTS pin control */
-#define  UCR2_CTS        (1<<12) /* Clear to send */
-#define  UCR2_ESCEN      (1<<11) /* Escape enable */
-#define  UCR2_PREN       (1<<8)  /* Parity enable */
-#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
-#define  UCR2_STPB       (1<<6)	 /* Stop */
-#define  UCR2_WS         (1<<5)	 /* Word size */
-#define  UCR2_RTSEN      (1<<4)	 /* Request to send interrupt enable */
-#define  UCR2_TXEN       (1<<2)	 /* Transmitter enabled */
-#define  UCR2_RXEN       (1<<1)	 /* Receiver enabled */
-#define  UCR2_SRST 	 (1<<0)	 /* SW reset */
-#define  UCR3_DTREN 	 (1<<13) /* DTR interrupt enable */
-#define  UCR3_PARERREN   (1<<12) /* Parity enable */
-#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
-#define  UCR3_DSR        (1<<10) /* Data set ready */
-#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
-#define  UCR3_RI         (1<<8)  /* Ring indicator */
-#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
-#define  UCR3_RXDSEN	 (1<<6)  /* Receive status interrupt enable */
-#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
-#define  UCR3_AWAKEN	 (1<<4)  /* Async wake interrupt enable */
-#define  UCR3_REF25 	 (1<<3)  /* Ref freq 25 MHz */
-#define  UCR3_REF30 	 (1<<2)  /* Ref Freq 30 MHz */
-#define  UCR3_INVT  	 (1<<1)  /* Inverted Infrared transmission */
-#define  UCR3_BPEN  	 (1<<0)  /* Preset registers enable */
-#define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
-#define  UCR4_INVR  	 (1<<9)  /* Inverted infrared reception */
-#define  UCR4_ENIRI 	 (1<<8)  /* Serial infrared interrupt enable */
-#define  UCR4_WKEN  	 (1<<7)  /* Wake interrupt enable */
-#define  UCR4_REF16 	 (1<<6)  /* Ref freq 16 MHz */
-#define  UCR4_IRSC  	 (1<<5)  /* IR special case */
-#define  UCR4_TCEN  	 (1<<3)  /* Transmit complete interrupt enable */
-#define  UCR4_BKEN  	 (1<<2)  /* Break condition interrupt enable */
-#define  UCR4_OREN  	 (1<<1)  /* Receiver overrun interrupt enable */
-#define  UCR4_DREN  	 (1<<0)  /* Recv data ready interrupt enable */
-#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
-#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
-#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
-#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
-#define  USR1_RTSS  	 (1<<14) /* RTS pin status */
-#define  USR1_TRDY  	 (1<<13) /* Transmitter ready interrupt/dma flag */
-#define  USR1_RTSD  	 (1<<12) /* RTS delta */
-#define  USR1_ESCF  	 (1<<11) /* Escape seq interrupt flag */
-#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
-#define  USR1_RRDY       (1<<9)	 /* Receiver ready interrupt/dma flag */
-#define  USR1_TIMEOUT    (1<<7)	 /* Receive timeout interrupt status */
-#define  USR1_RXDS  	 (1<<6)	 /* Receiver idle interrupt flag */
-#define  USR1_AIRINT	 (1<<5)	 /* Async IR wake interrupt flag */
-#define  USR1_AWAKE 	 (1<<4)	 /* Aysnc wake interrupt flag */
-#define  USR2_ADET  	 (1<<15) /* Auto baud rate detect complete */
-#define  USR2_TXFE  	 (1<<14) /* Transmit buffer FIFO empty */
-#define  USR2_DTRF  	 (1<<13) /* DTR edge interrupt flag */
-#define  USR2_IDLE  	 (1<<12) /* Idle condition */
-#define  USR2_IRINT 	 (1<<8)	 /* Serial infrared interrupt flag */
-#define  USR2_WAKE  	 (1<<7)	 /* Wake */
-#define  USR2_RTSF  	 (1<<4)	 /* RTS edge interrupt flag */
-#define  USR2_TXDC  	 (1<<3)	 /* Transmitter complete */
-#define  USR2_BRCD  	 (1<<2)	 /* Break condition */
-#define  USR2_ORE        (1<<1)	 /* Overrun error */
-#define  USR2_RDR        (1<<0)	 /* Recv data ready */
-#define  UTS_FRCPERR	 (1<<13) /* Force parity error */
-#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
-#define  UTS_TXEMPTY	 (1<<6)	 /* TxFIFO empty */
-#define  UTS_RXEMPTY	 (1<<5)	 /* RxFIFO empty */
-#define  UTS_TXFULL 	 (1<<4)	 /* TxFIFO full */
-#define  UTS_RXFULL 	 (1<<3)	 /* RxFIFO full */
-#define  UTS_SOFTRST	 (1<<0)	 /* Software reset */
-
 #endif				// _IMX_REGS_H
diff --git a/include/asm-arm/arch-imx/mmc.h b/include/asm-arm/arch-imx/mmc.h
index 1937151..84c7269 100644
--- a/include/asm-arm/arch-imx/mmc.h
+++ b/include/asm-arm/arch-imx/mmc.h
@@ -1,7 +1,7 @@
 #ifndef ASMARM_ARCH_MMC_H
 #define ASMARM_ARCH_MMC_H
 
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
 
 struct imxmmc_platform_data {
 	int (*card_present)(void);
diff --git a/include/asm-arm/arch-iop13xx/io.h b/include/asm-arm/arch-iop13xx/io.h
index 5a7bdb5..7dfff4a 100644
--- a/include/asm-arm/arch-iop13xx/io.h
+++ b/include/asm-arm/arch-iop13xx/io.h
@@ -26,7 +26,6 @@ #define __mem_pci(a) (a)
 #define __mem_isa(a) (a)
 
 extern void __iomem * __iop13xx_io(unsigned long io_addr);
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
 extern void __iomem *__iop13xx_ioremap(unsigned long cookie, size_t size,
 	unsigned long flags);
 extern void __iop13xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop13xx/iop13xx.h b/include/asm-arm/arch-iop13xx/iop13xx.h
index d26b755..85707e9 100644
--- a/include/asm-arm/arch-iop13xx/iop13xx.h
+++ b/include/asm-arm/arch-iop13xx/iop13xx.h
@@ -8,6 +8,7 @@ extern u32 iop13xx_atue_pmmr_offset;
 void iop13xx_init_irq(void);
 void iop13xx_map_io(void);
 void iop13xx_platform_init(void);
+void iop13xx_add_tpmi_devices(void);
 void iop13xx_init_irq(void);
 
 /* CPUID CP6 R0 Page 0 */
@@ -27,19 +28,24 @@ #define IOP13XX_MAX_RAM_SIZE    0x800000
 #define IOP13XX_PCI_OFFSET	 IOP13XX_MAX_RAM_SIZE
 
 /* PCI MAP
- * 0x0000.0000 - 0x8000.0000           1:1 mapping with Physical RAM
- * 0x8000.0000 - 0x8800.0000           PCIX/PCIE memory window (128MB)
-*/
+ * bus range		cpu phys	cpu virt	note
+ * 0x0000.0000 + 2GB	(n/a)		(n/a)		inbound, 1:1 mapping with Physical RAM
+ * 0x8000.0000 + 928M	0x1.8000.0000   (ioremap)	PCIX outbound memory window
+ * 0x8000.0000 + 928M	0x2.8000.0000   (ioremap)	PCIE outbound memory window
+ *
+ * IO MAP
+ * 0x1000 + 64K	0x0.fffb.1000	0xfec6.1000	PCIX outbound i/o window
+ * 0x1000 + 64K	0x0.fffd.1000	0xfed7.1000	PCIE outbound i/o window
+ */
 #define IOP13XX_PCIX_IO_WINDOW_SIZE   0x10000UL
 #define IOP13XX_PCIX_LOWER_IO_PA      0xfffb0000UL
 #define IOP13XX_PCIX_LOWER_IO_VA      0xfec60000UL
-#define IOP13XX_PCIX_LOWER_IO_BA      0x0fff0000UL
+#define IOP13XX_PCIX_LOWER_IO_BA      0x0UL /* OIOTVR */
+#define IOP13XX_PCIX_IO_BUS_OFFSET    0x1000UL
 #define IOP13XX_PCIX_UPPER_IO_PA      (IOP13XX_PCIX_LOWER_IO_PA +\
 				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
 #define IOP13XX_PCIX_UPPER_IO_VA      (IOP13XX_PCIX_LOWER_IO_VA +\
 				       IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_IO_OFFSET        (IOP13XX_PCIX_LOWER_IO_VA -\
-				       IOP13XX_PCIX_LOWER_IO_BA)
 #define IOP13XX_PCIX_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
 					   (IOP13XX_PCIX_LOWER_IO_PA\
 					   - IOP13XX_PCIX_LOWER_IO_VA))
@@ -65,15 +71,14 @@ #define IOP13XX_PCIX_MEM_OFFSET        (
 #define IOP13XX_PCIE_IO_WINDOW_SIZE   	 0x10000UL
 #define IOP13XX_PCIE_LOWER_IO_PA      	 0xfffd0000UL
 #define IOP13XX_PCIE_LOWER_IO_VA      	 0xfed70000UL
-#define IOP13XX_PCIE_LOWER_IO_BA      	 0x0fff0000UL
+#define IOP13XX_PCIE_LOWER_IO_BA      	 0x0UL  /* OIOTVR */
+#define IOP13XX_PCIE_IO_BUS_OFFSET	 0x1000UL
 #define IOP13XX_PCIE_UPPER_IO_PA      	 (IOP13XX_PCIE_LOWER_IO_PA +\
 					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
 #define IOP13XX_PCIE_UPPER_IO_VA      	 (IOP13XX_PCIE_LOWER_IO_VA +\
 					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
 #define IOP13XX_PCIE_UPPER_IO_BA      	 (IOP13XX_PCIE_LOWER_IO_BA +\
 					 IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_IO_OFFSET        	 (IOP13XX_PCIE_LOWER_IO_VA -\
-					 IOP13XX_PCIE_LOWER_IO_BA)
 #define IOP13XX_PCIE_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
 					   (IOP13XX_PCIE_LOWER_IO_PA\
 					   - IOP13XX_PCIE_LOWER_IO_VA))
@@ -451,4 +456,5 @@ #define IOP13XX_PBI_LR0       		IOP13XX_
 #define IOP13XX_PBI_BAR1      		IOP13XX_PBI_OFFSET(0x10)
 #define IOP13XX_PBI_LR1       		IOP13XX_PBI_OFFSET(0x14)
 
+#define IOP13XX_PROCESSOR_FREQ		IOP13XX_REG_ADDR32(0x2180)
 #endif /* _IOP13XX_HW_H_ */
diff --git a/include/asm-arm/arch-iop13xx/time.h b/include/asm-arm/arch-iop13xx/time.h
index 77a837a..49213d9 100644
--- a/include/asm-arm/arch-iop13xx/time.h
+++ b/include/asm-arm/arch-iop13xx/time.h
@@ -7,9 +7,65 @@ #define IOP_TMR_RELOAD	    0x04
 #define IOP_TMR_PRIVILEGED 0x08
 #define IOP_TMR_RATIO_1_1  0x00
 
+#define IOP13XX_XSI_FREQ_RATIO_MASK	(3 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_2   	(0 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_3	(1 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_4	(2 << 19)
+#define IOP13XX_CORE_FREQ_MASK		(7 << 16)
+#define IOP13XX_CORE_FREQ_600		(0 << 16)
+#define IOP13XX_CORE_FREQ_667		(1 << 16)
+#define IOP13XX_CORE_FREQ_800		(2 << 16)
+#define IOP13XX_CORE_FREQ_933		(3 << 16)
+#define IOP13XX_CORE_FREQ_1000		(4 << 16)
+#define IOP13XX_CORE_FREQ_1200		(5 << 16)
+
 void iop_init_time(unsigned long tickrate);
 unsigned long iop_gettimeoffset(void);
 
+static inline unsigned long iop13xx_core_freq(void)
+{
+	unsigned long freq = __raw_readl(IOP13XX_PROCESSOR_FREQ);
+	freq &= IOP13XX_CORE_FREQ_MASK;
+	switch (freq) {
+	case IOP13XX_CORE_FREQ_600:
+		return 600000000;
+	case IOP13XX_CORE_FREQ_667:
+		return 667000000;
+	case IOP13XX_CORE_FREQ_800:
+		return 800000000;
+	case IOP13XX_CORE_FREQ_933:
+		return 933000000;
+	case IOP13XX_CORE_FREQ_1000:
+		return 1000000000;
+	case IOP13XX_CORE_FREQ_1200:
+		return 1200000000;
+	default:
+		printk("%s: warning unknown frequency, defaulting to 800Mhz\n",
+			__FUNCTION__);
+	}
+
+	return 800000000;
+}
+
+static inline unsigned long iop13xx_xsi_bus_ratio(void)
+{
+	unsigned long  ratio = __raw_readl(IOP13XX_PROCESSOR_FREQ);
+	ratio &= IOP13XX_XSI_FREQ_RATIO_MASK;
+	switch (ratio) {
+	case IOP13XX_XSI_FREQ_RATIO_2:
+		return 2;
+	case IOP13XX_XSI_FREQ_RATIO_3:
+		return 3;
+	case IOP13XX_XSI_FREQ_RATIO_4:
+		return 4;
+	default:
+		printk("%s: warning unknown ratio, defaulting to 2\n",
+			__FUNCTION__);
+	}
+
+	return 2;
+}
+
 static inline void write_tmr0(u32 val)
 {
 	asm volatile("mcr p6, 0, %0, c0, c9, 0" : : "r" (val));
diff --git a/include/asm-arm/arch-iop32x/io.h b/include/asm-arm/arch-iop32x/io.h
index 5f570a5..994f16a 100644
--- a/include/asm-arm/arch-iop32x/io.h
+++ b/include/asm-arm/arch-iop32x/io.h
@@ -13,7 +13,6 @@ #define __IO_H
 
 #include <asm/hardware.h>
 
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
 extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
 	unsigned long flags);
 extern void __iop3xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
index 2e94690..0d8af57 100644
--- a/include/asm-arm/arch-iop32x/iop32x.h
+++ b/include/asm-arm/arch-iop32x/iop32x.h
@@ -24,5 +24,14 @@ #define IOP3XX_TIMER_REG(reg)	(IOP3XX_PE
 
 #include <asm/hardware/iop3xx.h>
 
+/* ATU Parameters
+ * set up a 1:1 bus to physical ram relationship
+ * w/ physical ram on top of pci in the memory map
+ */
+#define IOP32X_MAX_RAM_SIZE            0x40000000UL
+#define IOP3XX_MAX_RAM_SIZE            IOP32X_MAX_RAM_SIZE
+#define IOP3XX_PCI_LOWER_MEM_BA        0x80000000
+#define IOP32X_PCI_MEM_WINDOW_SIZE     0x04000000
+#define IOP3XX_PCI_MEM_WINDOW_SIZE     IOP32X_PCI_MEM_WINDOW_SIZE
 
 #endif
diff --git a/include/asm-arm/arch-iop32x/memory.h b/include/asm-arm/arch-iop32x/memory.h
index 764cd3f..c51072a 100644
--- a/include/asm-arm/arch-iop32x/memory.h
+++ b/include/asm-arm/arch-iop32x/memory.h
@@ -19,8 +19,8 @@ #define PHYS_OFFSET	UL(0xa0000000)
  * 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)))
+#define __virt_to_bus(x)	(__virt_to_phys(x))
+#define __bus_to_virt(x)	(__phys_to_virt(x))
 
 
 #endif
diff --git a/include/asm-arm/arch-iop33x/io.h b/include/asm-arm/arch-iop33x/io.h
index 1bb5071..993f758 100644
--- a/include/asm-arm/arch-iop33x/io.h
+++ b/include/asm-arm/arch-iop33x/io.h
@@ -13,7 +13,6 @@ #define __IO_H
 
 #include <asm/hardware.h>
 
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
 extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
 	unsigned long flags);
 extern void __iop3xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop33x/iop33x.h b/include/asm-arm/arch-iop33x/iop33x.h
index 7ac6e93..766985b 100644
--- a/include/asm-arm/arch-iop33x/iop33x.h
+++ b/include/asm-arm/arch-iop33x/iop33x.h
@@ -29,5 +29,15 @@ #define IOP33X_UART0_VIRT	(IOP3XX_PERIPH
 #define IOP33X_UART1_PHYS	(IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740)
 #define IOP33X_UART1_VIRT	(IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740)
 
+/* ATU Parameters
+ * set up a 1:1 bus to physical ram relationship
+ * w/ pci on top of physical ram in memory map
+ */
+#define IOP33X_MAX_RAM_SIZE		0x80000000UL
+#define IOP3XX_MAX_RAM_SIZE		IOP33X_MAX_RAM_SIZE
+#define IOP3XX_PCI_LOWER_MEM_BA	(PHYS_OFFSET + IOP33X_MAX_RAM_SIZE)
+#define IOP33X_PCI_MEM_WINDOW_SIZE	0x08000000
+#define IOP3XX_PCI_MEM_WINDOW_SIZE	IOP33X_PCI_MEM_WINDOW_SIZE
+
 
 #endif
diff --git a/include/asm-arm/arch-iop33x/memory.h b/include/asm-arm/arch-iop33x/memory.h
index 0d39139..c874912 100644
--- a/include/asm-arm/arch-iop33x/memory.h
+++ b/include/asm-arm/arch-iop33x/memory.h
@@ -19,8 +19,8 @@ #define PHYS_OFFSET	UL(0x00000000)
  * 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)))
+#define __virt_to_bus(x)	(__virt_to_phys(x))
+#define __bus_to_virt(x)	(__phys_to_virt(x))
 
 
 #endif
diff --git a/include/asm-arm/arch-ixp23xx/io.h b/include/asm-arm/arch-ixp23xx/io.h
index 18415a8..66f5baf 100644
--- a/include/asm-arm/arch-ixp23xx/io.h
+++ b/include/asm-arm/arch-ixp23xx/io.h
@@ -23,7 +23,7 @@ #define __mem_pci(a)	(a)
 #include <linux/kernel.h>	/* For BUG */
 
 static inline void __iomem *
-ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned int mtype)
 {
 	if (addr >= IXP23XX_PCI_MEM_START &&
 		addr <= IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE) {
@@ -34,7 +34,7 @@ ixp23xx_ioremap(unsigned long addr, unsi
  			((addr - IXP23XX_PCI_MEM_START) + IXP23XX_PCI_MEM_VIRT);
 	}
 
-	return __ioremap(addr, size, flags);
+	return __arm_ioremap(addr, size, mtype);
 }
 
 static inline void
diff --git a/include/asm-arm/arch-ixp4xx/cpu.h b/include/asm-arm/arch-ixp4xx/cpu.h
new file mode 100644
index 0000000..d2523b3
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/cpu.h
@@ -0,0 +1,31 @@
+/*
+ * include/asm-arm/arch-ixp4xx/cpu.h
+ *
+ * IXP4XX cpu type detection
+ *
+ * Copyright (C) 2007 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_ARCH_CPU_H__
+#define __ASM_ARCH_CPU_H__
+
+extern unsigned int processor_id;
+/* Processor id value in CP15 Register 0 */
+#define IXP425_PROCESSOR_ID_VALUE	0x690541c0
+#define IXP435_PROCESSOR_ID_VALUE	0x69054040
+#define IXP465_PROCESSOR_ID_VALUE	0x69054200
+#define IXP4XX_PROCESSOR_ID_MASK	0xfffffff0
+
+#define cpu_is_ixp42x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+			  IXP425_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+			  IXP435_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x()	((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+			  IXP465_PROCESSOR_ID_VALUE)
+
+#endif  /* _ASM_ARCH_CPU_H */
diff --git a/include/asm-arm/arch-ixp4xx/dma.h b/include/asm-arm/arch-ixp4xx/dma.h
index 789f7f5..2c7f532 100644
--- a/include/asm-arm/arch-ixp4xx/dma.h
+++ b/include/asm-arm/arch-ixp4xx/dma.h
@@ -12,7 +12,6 @@ #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
 #include <linux/device.h>
-#include <linux/pci.h>
 #include <asm/page.h>
 #include <asm/sizes.h>
 #include <asm/hardware.h>
diff --git a/include/asm-arm/arch-ixp4xx/dsmg600.h b/include/asm-arm/arch-ixp4xx/dsmg600.h
new file mode 100644
index 0000000..a19605a
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/dsmg600.h
@@ -0,0 +1,57 @@
+/*
+ * DSM-G600 platform specific definitions
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on ixdp425.h:
+ *	Copyright 2004 (C) MontaVista, Software, Inc.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H__
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
+#define DSMG600_SDA_PIN		5
+#define DSMG600_SCL_PIN		4
+
+/*
+ * DSMG600 PCI IRQs
+ */
+#define DSMG600_PCI_MAX_DEV	4
+#define DSMG600_PCI_IRQ_LINES	3
+
+
+/* PCI controller GPIO to IRQ pin mappings */
+#define DSMG600_PCI_INTA_PIN	11
+#define DSMG600_PCI_INTB_PIN	10
+#define DSMG600_PCI_INTC_PIN	9
+#define DSMG600_PCI_INTD_PIN	8
+#define DSMG600_PCI_INTE_PIN	7
+#define DSMG600_PCI_INTF_PIN	6
+
+/* DSM-G600 Timer Setting */
+#define DSMG600_FREQ 66000000
+
+/* Buttons */
+
+#define DSMG600_PB_GPIO		15	/* power button */
+#define DSMG600_PB_BM		(1L << DSMG600_PB_GPIO)
+
+#define DSMG600_RB_GPIO		3	/* reset button */
+
+#define DSMG600_RB_IRQ		IRQ_IXP4XX_GPIO3
+
+#define DSMG600_PO_GPIO		2	/* power off */
+
+/* LEDs */
+
+#define DSMG600_LED_PWR_GPIO	0
+#define DSMG600_LED_PWR_BM	(1L << DSMG600_LED_PWR_GPIO)
+
+#define DSMG600_LED_WLAN_GPIO	14
+#define DSMG600_LED_WLAN_BM	(1L << DSMG600_LED_WLAN_GPIO)
diff --git a/include/asm-arm/arch-ixp4xx/entry-macro.S b/include/asm-arm/arch-ixp4xx/entry-macro.S
index dadb568..f144a00 100644
--- a/include/asm-arm/arch-ixp4xx/entry-macro.S
+++ b/include/asm-arm/arch-ixp4xx/entry-macro.S
@@ -31,9 +31,9 @@ #include <asm/hardware.h>
 
 1001:
 		/*
-		 * IXP465 has an upper IRQ status register
+		 * IXP465/IXP435 has an upper IRQ status register
 		 */
-#if defined(CONFIG_CPU_IXP46X)
+#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
 		ldr	\irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP2_OFFSET)
 		ldr	\irqstat, [\irqstat]		@ get upper interrupts
 		mov	\irqnr, #63
diff --git a/include/asm-arm/arch-ixp4xx/gpio.h b/include/asm-arm/arch-ixp4xx/gpio.h
new file mode 100644
index 0000000..3a4c5b8
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/gpio.h
@@ -0,0 +1,73 @@
+/*
+ * linux/include/asm-arm/arch-ixp4xx/gpio.h
+ *
+ * IXP4XX GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Milan Svoboda <msvoboda@ra.rockwell.com>
+ * Based on PXA implementation by Philipp Zabel <philipp.zabel@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
+ *
+ */
+
+#ifndef __ASM_ARCH_IXP4XX_GPIO_H
+#define __ASM_ARCH_IXP4XX_GPIO_H
+
+#include <asm/hardware.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+	return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+	return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+	gpio_line_config(gpio, IXP4XX_GPIO_IN);
+	return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int level)
+{
+	gpio_line_set(gpio, level);
+	gpio_line_config(gpio, IXP4XX_GPIO_OUT);
+	return 0;
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	int value;
+
+	gpio_line_get(gpio, &value);
+
+	return value;
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	gpio_line_set(gpio, value);
+}
+
+#include <asm-generic/gpio.h>			/* cansleep wrappers */
+
+extern int gpio_to_irq(int gpio);
+extern int irq_to_gpio(int gpio);
+
+#endif
+
diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h
index 88fd087..297ceda 100644
--- a/include/asm-arm/arch-ixp4xx/hardware.h
+++ b/include/asm-arm/arch-ixp4xx/hardware.h
@@ -17,8 +17,8 @@
 #ifndef __ASM_ARCH_HARDWARE_H__
 #define __ASM_ARCH_HARDWARE_H__
 
-#define PCIBIOS_MIN_IO			0x00001000
-#define PCIBIOS_MIN_MEM			0x48000000
+#define PCIBIOS_MIN_IO		0x00001000
+#define PCIBIOS_MIN_MEM		(cpu_is_ixp43x() ? 0x40000000 : 0x48000000)
 
 /*
  * We override the standard dma-mask routines for bouncing.
@@ -27,11 +27,8 @@ #define	HAVE_ARCH_PCI_SET_DMA_MASK
 
 #define pcibios_assign_all_busses()	1
 
-#if defined(CONFIG_CPU_IXP46X) && !defined(__ASSEMBLY__)
-extern unsigned int processor_id;
-#define cpu_is_ixp465() ((processor_id & 0xffffffc0) == 0x69054200)
-#else
-#define	cpu_is_ixp465()	(0)
+#ifndef __ASSEMBLER__
+#include <asm/arch/cpu.h>
 #endif
 
 /* Register locations and bits */
@@ -47,5 +44,6 @@ #include "coyote.h"
 #include "prpmc1100.h"
 #include "nslu2.h"
 #include "nas100d.h"
+#include "dsmg600.h"
 
 #endif  /* _ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index a41ba22..c72f9d7 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -59,10 +59,10 @@ #include <linux/mm.h>
  * fallback to the default.
  */
 static inline void __iomem *
-__ixp4xx_ioremap(unsigned long addr, size_t size, unsigned long flags)
+__ixp4xx_ioremap(unsigned long addr, size_t size, unsigned int mtype)
 {
-	if((addr < 0x48000000) || (addr > 0x4fffffff))
-		return __ioremap(addr, size, flags);
+	if((addr < PCIBIOS_MIN_MEM) || (addr > 0x4fffffff))
+		return __arm_ioremap(addr, size, mtype);
 
 	return (void *)addr;
 }
diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h
index e44a563..1180160 100644
--- a/include/asm-arm/arch-ixp4xx/irqs.h
+++ b/include/asm-arm/arch-ixp4xx/irqs.h
@@ -62,10 +62,10 @@ #define IRQ_IXP4XX_EXP_PE	62
 /*
  * Only first 32 sources are valid if running on IXP42x systems
  */
-#ifndef	CONFIG_CPU_IXP46X
-#define NR_IRQS			32
-#else
+#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
 #define NR_IRQS			64
+#else
+#define NR_IRQS			32
 #endif
 
 #define	XSCALE_PMU_IRQ		(IRQ_IXP4XX_XSCALE_PMU)
@@ -118,4 +118,14 @@ #define        IRQ_NAS100D_PCI_INTC    I
 #define        IRQ_NAS100D_PCI_INTD    IRQ_IXP4XX_GPIO8
 #define        IRQ_NAS100D_PCI_INTE    IRQ_IXP4XX_GPIO7
 
+/*
+ * D-Link DSM-G600 RevA board IRQs
+ */
+#define        IRQ_DSMG600_PCI_INTA    IRQ_IXP4XX_GPIO11
+#define        IRQ_DSMG600_PCI_INTB    IRQ_IXP4XX_GPIO10
+#define        IRQ_DSMG600_PCI_INTC    IRQ_IXP4XX_GPIO9
+#define        IRQ_DSMG600_PCI_INTD    IRQ_IXP4XX_GPIO8
+#define        IRQ_DSMG600_PCI_INTE    IRQ_IXP4XX_GPIO7
+#define        IRQ_DSMG600_PCI_INTF    IRQ_IXP4XX_GPIO6
+
 #endif
diff --git a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
index ed35e5c..5d949d7 100644
--- a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+++ b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
@@ -607,19 +607,4 @@ #define USIR1_IR15	(1 << 7)	/* Interrup 
 
 #define DCMD_LENGTH	0x01fff		/* length mask (max = 8K - 1) */
 
-#ifndef __ASSEMBLY__
-static inline int cpu_is_ixp46x(void)
-{
-#ifdef CONFIG_CPU_IXP46X
-	unsigned int processor_id;
-
-	asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
-
-	if ((processor_id & 0xffffff00) == 0x69054200)
-		return 1;
-#endif
-	return 0;
-}
-#endif
-
 #endif
diff --git a/include/asm-arm/arch-netx/netx-regs.h b/include/asm-arm/arch-netx/netx-regs.h
index 8ab45be..fc9aa21 100644
--- a/include/asm-arm/arch-netx/netx-regs.h
+++ b/include/asm-arm/arch-netx/netx-regs.h
@@ -121,8 +121,8 @@ #define NETX_SYSTEM_IOC_CR          NETX
 #define NETX_SYSTEM_IOC_MR          NETX_SYSTEM_REG(0x08)
 
 /* FIXME: Docs are not consistent */
-#define NETX_SYSTEM_RES_CR          NETX_SYSTEM_REG(0x08)
-/* #define NETX_SYSTEM_RES_CR          NETX_SYSTEM_REG(0x0c) */
+/* #define NETX_SYSTEM_RES_CR          NETX_SYSTEM_REG(0x08) */
+#define NETX_SYSTEM_RES_CR          NETX_SYSTEM_REG(0x0c)
 
 #define NETX_SYSTEM_PHY_CONTROL     NETX_SYSTEM_REG(0x10)
 #define NETX_SYSTEM_REV             NETX_SYSTEM_REG(0x34)
diff --git a/include/asm-arm/arch-ns9xxx/board.h b/include/asm-arm/arch-ns9xxx/board.h
index 91dc8fb..716f34f 100644
--- a/include/asm-arm/arch-ns9xxx/board.h
+++ b/include/asm-arm/arch-ns9xxx/board.h
@@ -15,4 +15,6 @@ #include <asm/mach-types.h>
 
 #define board_is_a9m9750dev()	(machine_is_cc9p9360dev())
 
+#define board_is_jscc9p9360()	(machine_is_cc9p9360js())
+
 #endif /* ifndef __ASM_ARCH_BOARD_H */
diff --git a/include/asm-arm/arch-ns9xxx/clock.h b/include/asm-arm/arch-ns9xxx/clock.h
index a7c5ab3..bf30cbd 100644
--- a/include/asm-arm/arch-ns9xxx/clock.h
+++ b/include/asm-arm/arch-ns9xxx/clock.h
@@ -11,13 +11,43 @@
 #ifndef __ASM_ARCH_CLOCK_H
 #define __ASM_ARCH_CLOCK_H
 
+#include <asm/arch-ns9xxx/regs-sys.h>
+
+#define CRYSTAL 29491200 /* Hz */
+
+/* The HRM calls this value f_vco */
 static inline u32 ns9xxx_systemclock(void) __attribute__((const));
 static inline u32 ns9xxx_systemclock(void)
 {
+	u32 pll = SYS_PLL;
+
 	/*
-	 * This should be a multiple of HZ * TIMERCLOCKSELECT (in time.c)
+	 * The system clock should be a multiple of HZ * TIMERCLOCKSELECT (in
+	 * time.c).
+	 *
+	 * The following values are given:
+	 *   - TIMERCLOCKSELECT == 2^i for an i in {0 .. 6}
+	 *   - CRYSTAL == 29491200 == 2^17 * 3^2 * 5^2
+	 *   - ND in {0 .. 31}
+	 *   - FS in {0 .. 3}
+	 *
+	 * Assuming the worst, we consider:
+	 *   - TIMERCLOCKSELECT == 64
+	 *   - ND == 0
+	 *   - FS == 3
+	 *
+	 * So HZ should be a divisor of:
+	 *      (CRYSTAL * (ND + 1) >> FS) / TIMERCLOCKSELECT
+	 *   == (2^17 * 3^2 * 5^2 * 1 >> 3) / 64
+	 *   == 2^8 * 3^2 * 5^2
+	 *   == 57600
+	 *
+	 * Currently HZ is defined to be 100 for this platform.
+	 *
+	 * Fine.
 	 */
-	return 353894400;
+	return CRYSTAL * (REGGET(pll, SYS_PLL, ND) + 1)
+		>> REGGET(pll, SYS_PLL, FS);
 }
 
 static inline u32 ns9xxx_cpuclock(void) __attribute__((const));
diff --git a/include/asm-arm/arch-ns9xxx/hardware.h b/include/asm-arm/arch-ns9xxx/hardware.h
index 6819da7..2560055 100644
--- a/include/asm-arm/arch-ns9xxx/hardware.h
+++ b/include/asm-arm/arch-ns9xxx/hardware.h
@@ -51,8 +51,9 @@ #  define REGSETIM(var, reg, field, valu
 		       ~(__REGVAL(reg ## _ ## field, value))))		\
 		  | (__REGVAL(reg ## _ ## field, value))))
 
-#  define REGGET(reg, field)						\
-	((reg & (reg ## _ ## field)) / (field & (-field)))
+#  define REGGET(var, reg, field)					\
+	((var & (reg ## _ ## field)) /					\
+	 ((reg ## _ ## field) & (-(reg ## _ ## field))))
 
 #else
 
diff --git a/include/asm-arm/arch-ns9xxx/processor.h b/include/asm-arm/arch-ns9xxx/processor.h
index 716c106..223e51b 100644
--- a/include/asm-arm/arch-ns9xxx/processor.h
+++ b/include/asm-arm/arch-ns9xxx/processor.h
@@ -13,6 +13,7 @@ #define __ASM_ARCH_PROCESSOR_H
 
 #include <asm/mach-types.h>
 
-#define processor_is_ns9360()	(machine_is_cc9p9360dev())
+#define processor_is_ns9360()	(machine_is_cc9p9360dev()		\
+		|| machine_is_cc9p9360js())
 
 #endif /* ifndef __ASM_ARCH_PROCESSOR_H */
diff --git a/include/asm-arm/arch-ns9xxx/regs-sys.h b/include/asm-arm/arch-ns9xxx/regs-sys.h
index 8162a50..a42546a 100644
--- a/include/asm-arm/arch-ns9xxx/regs-sys.h
+++ b/include/asm-arm/arch-ns9xxx/regs-sys.h
@@ -48,6 +48,12 @@ #define SYS_TIS		__REG(0xa0900170)
 /* PLL Configuration register */
 #define SYS_PLL		__REG(0xa0900188)
 
+/* PLL FS status */
+#define SYS_PLL_FS		__REGBITS(24, 23)
+
+/* PLL ND status */
+#define SYS_PLL_ND		__REGBITS(20, 16)
+
 /* PLL Configuration register: PLL SW change */
 #define SYS_PLL_SWC		__REGBIT(15)
 #define SYS_PLL_SWC_NO			__REGVAL(SYS_PLL_SWC, 0)
diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
index 46ec224..e404b23 100644
--- a/include/asm-arm/arch-pxa/i2c.h
+++ b/include/asm-arm/arch-pxa/i2c.h
@@ -64,6 +64,7 @@ struct i2c_slave_client;
 struct i2c_pxa_platform_data {
 	unsigned int		slave_addr;
 	struct i2c_slave_client	*slave;
+	unsigned int		class;
 };
 
 extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
index a38a28c..ef4f570 100644
--- a/include/asm-arm/arch-pxa/mmc.h
+++ b/include/asm-arm/arch-pxa/mmc.h
@@ -1,7 +1,7 @@
 #ifndef ASMARM_ARCH_MMC_H
 #define ASMARM_ARCH_MMC_H
 
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
 #include <linux/interrupt.h>
 
 struct device;
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 139c9d9..dbcc929 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1801,35 +1801,35 @@ #define CCCR_N_MASK	0x0380		/* Run Mode 
 #define CCCR_M_MASK	0x0060		/* Memory Frequency to Run Mode Frequency Multiplier */
 #define CCCR_L_MASK	0x001f		/* Crystal Frequency to Memory Frequency Multiplier */
 
-#define CKEN24_CAMERA	(1 << 24)	/* Camera Interface Clock Enable */
-#define CKEN23_SSP1	(1 << 23)	/* SSP1 Unit Clock Enable */
-#define CKEN22_MEMC	(1 << 22)	/* Memory Controller Clock Enable */
-#define CKEN21_MEMSTK	(1 << 21)	/* Memory Stick Host Controller */
-#define CKEN20_IM	(1 << 20)	/* Internal Memory Clock Enable */
-#define CKEN19_KEYPAD	(1 << 19)	/* Keypad Interface Clock Enable */
-#define CKEN18_USIM	(1 << 18)	/* USIM Unit Clock Enable */
-#define CKEN17_MSL	(1 << 17)	/* MSL Unit Clock Enable */
-#define CKEN16_LCD	(1 << 16)	/* LCD Unit Clock Enable */
-#define CKEN15_PWRI2C	(1 << 15)	/* PWR I2C Unit Clock Enable */
-#define CKEN14_I2C	(1 << 14)	/* I2C Unit Clock Enable */
-#define CKEN13_FICP	(1 << 13)	/* FICP Unit Clock Enable */
-#define CKEN12_MMC	(1 << 12)	/* MMC Unit Clock Enable */
-#define CKEN11_USB	(1 << 11)	/* USB Unit Clock Enable */
-#define CKEN10_ASSP	(1 << 10)	/* ASSP (SSP3) Clock Enable */
-#define CKEN10_USBHOST	(1 << 10)	/* USB Host Unit Clock Enable */
-#define CKEN9_OSTIMER	(1 << 9)	/* OS Timer Unit Clock Enable */
-#define CKEN9_NSSP	(1 << 9)	/* NSSP (SSP2) Clock Enable */
-#define CKEN8_I2S	(1 << 8)	/* I2S Unit Clock Enable */
-#define CKEN7_BTUART	(1 << 7)	/* BTUART Unit Clock Enable */
-#define CKEN6_FFUART	(1 << 6)	/* FFUART Unit Clock Enable */
-#define CKEN5_STUART	(1 << 5)	/* STUART Unit Clock Enable */
-#define CKEN4_HWUART	(1 << 4)	/* HWUART Unit Clock Enable */
-#define CKEN4_SSP3	(1 << 4)	/* SSP3 Unit Clock Enable */
-#define CKEN3_SSP	(1 << 3)	/* SSP Unit Clock Enable */
-#define CKEN3_SSP2	(1 << 3)	/* SSP2 Unit Clock Enable */
-#define CKEN2_AC97	(1 << 2)	/* AC97 Unit Clock Enable */
-#define CKEN1_PWM1	(1 << 1)	/* PWM1 Clock Enable */
-#define CKEN0_PWM0	(1 << 0)	/* PWM0 Clock Enable */
+#define CKEN_CAMERA	(24)	/* Camera Interface Clock Enable */
+#define CKEN_SSP1	(23)	/* SSP1 Unit Clock Enable */
+#define CKEN_MEMC	(22)	/* Memory Controller Clock Enable */
+#define CKEN_MEMSTK	(21)	/* Memory Stick Host Controller */
+#define CKEN_IM		(20)	/* Internal Memory Clock Enable */
+#define CKEN_KEYPAD	(19)	/* Keypad Interface Clock Enable */
+#define CKEN_USIM	(18)	/* USIM Unit Clock Enable */
+#define CKEN_MSL	(17)	/* MSL Unit Clock Enable */
+#define CKEN_LCD	(16)	/* LCD Unit Clock Enable */
+#define CKEN_PWRI2C	(15)	/* PWR I2C Unit Clock Enable */
+#define CKEN_I2C	(14)	/* I2C Unit Clock Enable */
+#define CKEN_FICP	(13)	/* FICP Unit Clock Enable */
+#define CKEN_MMC	(12)	/* MMC Unit Clock Enable */
+#define CKEN_USB	(11)	/* USB Unit Clock Enable */
+#define CKEN_ASSP	(10)	/* ASSP (SSP3) Clock Enable */
+#define CKEN_USBHOST	(10)	/* USB Host Unit Clock Enable */
+#define CKEN_OSTIMER	(9)	/* OS Timer Unit Clock Enable */
+#define CKEN_NSSP	(9)	/* NSSP (SSP2) Clock Enable */
+#define CKEN_I2S	(8)	/* I2S Unit Clock Enable */
+#define CKEN_BTUART	(7)	/* BTUART Unit Clock Enable */
+#define CKEN_FFUART	(6)	/* FFUART Unit Clock Enable */
+#define CKEN_STUART	(5)	/* STUART Unit Clock Enable */
+#define CKEN_HWUART	(4)	/* HWUART Unit Clock Enable */
+#define CKEN_SSP3	(4)	/* SSP3 Unit Clock Enable */
+#define CKEN_SSP	(3)	/* SSP Unit Clock Enable */
+#define CKEN_SSP2	(3)	/* SSP2 Unit Clock Enable */
+#define CKEN_AC97	(2)	/* AC97 Unit Clock Enable */
+#define CKEN_PWM1	(1)	/* PWM1 Clock Enable */
+#define CKEN_PWM0	(0)	/* PWM0 Clock Enable */
 
 #define OSCC_OON	(1 << 1)	/* 32.768kHz OON (write-once only bit) */
 #define OSCC_OOK	(1 << 0)	/* 32.768kHz OOK (read-only bit) */
diff --git a/include/asm-arm/arch-pxa/pxa27x_keyboard.h b/include/asm-arm/arch-pxa/pxa27x_keyboard.h
new file mode 100644
index 0000000..3aaff92
--- /dev/null
+++ b/include/asm-arm/arch-pxa/pxa27x_keyboard.h
@@ -0,0 +1,13 @@
+#define PXAKBD_MAXROW		8
+#define PXAKBD_MAXCOL		8
+
+struct pxa27x_keyboard_platform_data {
+	int nr_rows, nr_cols;
+	int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+	int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+
+#ifdef CONFIG_PM
+	u32 reg_kpc;
+	u32 reg_kprec;
+#endif
+};
diff --git a/include/asm-arm/arch-s3c2410/regs-ac97.h b/include/asm-arm/arch-s3c2410/regs-ac97.h
index bdd6a4f..b004dee 100644
--- a/include/asm-arm/arch-s3c2410/regs-ac97.h
+++ b/include/asm-arm/arch-s3c2410/regs-ac97.h
@@ -13,11 +13,55 @@
 #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)
+#define S3C_AC97_GLBCTRL				(0x00)
+
+#define S3C_AC97_GLBCTRL_CODECREADYIE			(1<<22)
+#define S3C_AC97_GLBCTRL_PCMOUTURIE			(1<<21)
+#define S3C_AC97_GLBCTRL_PCMINORIE			(1<<20)
+#define S3C_AC97_GLBCTRL_MICINORIE			(1<<19)
+#define S3C_AC97_GLBCTRL_PCMOUTTIE			(1<<18)
+#define S3C_AC97_GLBCTRL_PCMINTIE			(1<<17)
+#define S3C_AC97_GLBCTRL_MICINTIE			(1<<16)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF			(0<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO			(1<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA			(2<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK			(3<<12)
+#define S3C_AC97_GLBCTRL_PCMINTM_OFF			(0<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_PIO			(1<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_DMA			(2<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_MASK			(3<<10)
+#define S3C_AC97_GLBCTRL_MICINTM_OFF			(0<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_PIO			(1<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_DMA			(2<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_MASK			(3<<8)
+#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE		(1<<3)
+#define S3C_AC97_GLBCTRL_ACLINKON			(1<<2)
+#define S3C_AC97_GLBCTRL_WARMRESET			(1<<1)
+#define S3C_AC97_GLBCTRL_COLDRESET			(1<<0)
+
+#define S3C_AC97_GLBSTAT				(0x04)
+
+#define S3C_AC97_GLBSTAT_CODECREADY			(1<<22)
+#define S3C_AC97_GLBSTAT_PCMOUTUR			(1<<21)
+#define S3C_AC97_GLBSTAT_PCMINORI			(1<<20)
+#define S3C_AC97_GLBSTAT_MICINORI			(1<<19)
+#define S3C_AC97_GLBSTAT_PCMOUTTI			(1<<18)
+#define S3C_AC97_GLBSTAT_PCMINTI			(1<<17)
+#define S3C_AC97_GLBSTAT_MICINTI			(1<<16)
+#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE			(0<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_INIT			(1<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_READY		(2<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE		(3<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_LP			(4<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_WARM			(5<<0)
+
+#define S3C_AC97_CODEC_CMD				(0x08)
+
+#define S3C_AC97_CODEC_CMD_READ				(1<<23)
+
+#define S3C_AC97_STAT					(0x0c)
+#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-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
index 3c83546..e1e9805 100644
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/arch-s3c2410/regs-udc.h
@@ -75,7 +75,7 @@ #define S3C2410_UDC_OUT_CSR2_REG	S3C2410
 #define S3C2410_UDC_OUT_FIFO_CNT1_REG	S3C2410_USBDREG(0x0198)
 #define S3C2410_UDC_OUT_FIFO_CNT2_REG	S3C2410_USBDREG(0x019c)
 
-
+#define S3C2410_UDC_FUNCADDR_UPDATE	(1<<7)
 
 #define S3C2410_UDC_PWR_ISOUP		(1<<7) // R/W
 #define S3C2410_UDC_PWR_RESET		(1<<3) // R
@@ -135,10 +135,6 @@ #define S3C2410_UDC_OCSR2_AUTOCLR	(1<<7)
 #define S3C2410_UDC_OCSR2_ISO		(1<<6) // R/W
 #define S3C2410_UDC_OCSR2_DMAIEN	(1<<5) // R/W
 
-#define S3C2410_UDC_SETIX(base,x)	    \
-	writel(S3C2410_UDC_INDEX_ ## x, base+S3C2410_UDC_INDEX_REG);
-
-
 #define S3C2410_UDC_EP0_CSR_OPKRDY	(1<<0)
 #define S3C2410_UDC_EP0_CSR_IPKRDY	(1<<1)
 #define S3C2410_UDC_EP0_CSR_SENTSTL	(1<<2)
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index f266c27..3b59f94 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -12,6 +12,7 @@ #ifndef __ASM_ARM_ATOMIC_H
 #define __ASM_ARM_ATOMIC_H
 
 #include <linux/compiler.h>
+#include <asm/system.h>
 
 typedef struct { volatile int counter; } atomic_t;
 
diff --git a/include/asm-arm/div64.h b/include/asm-arm/div64.h
index 37e0a96..0b5f881 100644
--- a/include/asm-arm/div64.h
+++ b/include/asm-arm/div64.h
@@ -2,6 +2,7 @@ #ifndef __ASM_ARM_DIV64
 #define __ASM_ARM_DIV64
 
 #include <asm/system.h>
+#include <linux/types.h>
 
 /*
  * The semantics of do_div() are:
@@ -223,4 +224,6 @@ ({									\
 
 #endif
 
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
+
 #endif
diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h
index a0ae2b9..3a6d3eb 100644
--- a/include/asm-arm/ecard.h
+++ b/include/asm-arm/ecard.h
@@ -160,6 +160,7 @@ struct expansion_card {
 	unsigned char		irqmask;	/* IRQ mask			*/
 	unsigned char		fiqmask;	/* FIQ mask			*/
 	unsigned char  		claimed;	/* Card claimed?		*/
+	unsigned char		easi;		/* EASI card			*/
 
 	void			*irq_data;	/* Data for use for IRQ by card	*/
 	void			*fiq_data;	/* Data for use for FIQ by card	*/
@@ -169,7 +170,6 @@ struct expansion_card {
 	CONST unsigned int	dma;		/* DMA number (for request_dma)	*/
 	CONST unsigned int	irq;		/* IRQ number (for request_irq)	*/
 	CONST unsigned int	fiq;		/* FIQ number (for request_irq)	*/
-	CONST card_type_t	type;		/* Type of card			*/
 	CONST struct in_ecid	cid;		/* Card Identification		*/
 
 	/* Private internal data */
@@ -224,56 +224,6 @@ ecard_address(struct expansion_card *ec,
 extern int ecard_request_resources(struct expansion_card *ec);
 extern void ecard_release_resources(struct expansion_card *ec);
 
-#ifdef ECARD_C
-/* Definitions internal to ecard.c - for it's use only!!
- *
- * External expansion card header as read from the card
- */
-struct ex_ecid {
-	unsigned char	r_irq:1;
-	unsigned char	r_zero:1;
-	unsigned char	r_fiq:1;
-	unsigned char	r_id:4;
-	unsigned char	r_a:1;
-
-	unsigned char	r_cd:1;
-	unsigned char	r_is:1;
-	unsigned char	r_w:2;
-	unsigned char	r_r1:4;
-
-	unsigned char	r_r2:8;
-
-	unsigned char	r_prod[2];
-
-	unsigned char	r_manu[2];
-
-	unsigned char	r_country;
-
-	unsigned char	r_fiqmask;
-	unsigned char	r_fiqoff[3];
-
-	unsigned char	r_irqmask;
-	unsigned char	r_irqoff[3];
-};
-
-/*
- * Chunk directory entry as read from the card
- */
-struct ex_chunk_dir {
-	unsigned char r_id;
-	unsigned char r_len[3];
-	unsigned long r_start;
-	union {
-		char string[256];
-		char data[1];
-	} d;
-#define c_id(x)		((x)->r_id)
-#define c_len(x)	((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
-#define c_start(x)	((x)->r_start)
-};
-
-#endif
-
 extern struct bus_type ecard_bus_type;
 
 #define ECARD_DEV(_d)	container_of((_d), struct expansion_card, dev)
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
index 15141a9..63feceb 100644
--- a/include/asm-arm/hardware/iop3xx.h
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -28,6 +28,7 @@ #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);
+extern int init_atu;
 #endif
 
 
@@ -41,7 +42,7 @@ #define IOP3XX_PERIPHERAL_UPPER_PA (IOP3
 					IOP3XX_PERIPHERAL_SIZE - 1)
 #define IOP3XX_PERIPHERAL_UPPER_VA (IOP3XX_PERIPHERAL_VIRT_BASE +\
 					IOP3XX_PERIPHERAL_SIZE - 1)
-#define IOP3XX_PMMR_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
+#define IOP3XX_PMMR_PHYS_TO_VIRT(addr) (u32) ((u32) (addr) -\
 					(IOP3XX_PERIPHERAL_PHYS_BASE\
 					- IOP3XX_PERIPHERAL_VIRT_BASE))
 #define IOP3XX_REG_ADDR(reg)		(IOP3XX_PERIPHERAL_VIRT_BASE + (reg))
@@ -103,6 +104,21 @@ #define IOP3XX_PCIXNEXT		(volatile u8  *
 #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)
+#define IOP3XX_PCSR_OUT_Q_BUSY (1 << 15)
+#define IOP3XX_PCSR_IN_Q_BUSY	(1 << 14)
+#define IOP3XX_ATUCR_OUT_EN	(1 << 1)
+
+#define IOP3XX_INIT_ATU_DEFAULT 0
+#define IOP3XX_INIT_ATU_DISABLE -1
+#define IOP3XX_INIT_ATU_ENABLE	 1
+
+#ifdef CONFIG_IOP3XX_ATU
+#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\
+				IOP3XX_INIT_ATU_ENABLE : init_atu)
+#else
+#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\
+				IOP3XX_INIT_ATU_DISABLE : init_atu)
+#endif
 
 /* Messaging Unit  */
 #define IOP3XX_IMR0		(volatile u32 *)IOP3XX_REG_ADDR(0x0310)
@@ -253,14 +269,12 @@ #define IOP3XX_IBMR1		(volatile u32 *)IO
 /*
  * 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_LOWER_MEM_PA	0x80000000
 
 #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)
+#define IOP3XX_PCI_LOWER_IO_BA		0x90000000
 #define IOP3XX_PCI_UPPER_IO_PA		(IOP3XX_PCI_LOWER_IO_PA +\
 					IOP3XX_PCI_IO_WINDOW_SIZE - 1)
 #define IOP3XX_PCI_UPPER_IO_VA		(IOP3XX_PCI_LOWER_IO_VA +\
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 5f60b42..8261ff9 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -56,13 +56,22 @@ #define __raw_readl(a)		(__chk_io_ptr(a)
 
 /*
  * Architecture ioremap implementation.
- *
- * __ioremap takes CPU physical address.
- *
- * __ioremap_pfn takes a Page Frame Number and an offset into that page
  */
-extern void __iomem * __ioremap_pfn(unsigned long, unsigned long, size_t, unsigned long);
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
+#define MT_DEVICE		0
+#define MT_DEVICE_NONSHARED	1
+#define MT_DEVICE_CACHED	2
+#define MT_DEVICE_IXP2000	3
+/*
+ * types 4 onwards can be found in asm/mach/map.h and are undefined
+ * for ioremap
+ */
+
+/*
+ * __arm_ioremap takes CPU physical address.
+ * __arm_ioremap_pfn takes a Page Frame Number and an offset into that page
+ */
+extern void __iomem * __arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
+extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int);
 extern void __iounmap(volatile void __iomem *addr);
 
 /*
@@ -203,14 +212,14 @@ #endif	/* __mem_pci */
  *
  */
 #ifndef __arch_ioremap
-#define ioremap(cookie,size)		__ioremap(cookie,size,0)
-#define ioremap_nocache(cookie,size)	__ioremap(cookie,size,0)
-#define ioremap_cached(cookie,size)	__ioremap(cookie,size,L_PTE_CACHEABLE)
+#define ioremap(cookie,size)		__arm_ioremap(cookie, size, MT_DEVICE)
+#define ioremap_nocache(cookie,size)	__arm_ioremap(cookie, size, MT_DEVICE)
+#define ioremap_cached(cookie,size)	__arm_ioremap(cookie, size, MT_DEVICE_CACHED)
 #define iounmap(cookie)			__iounmap(cookie)
 #else
-#define ioremap(cookie,size)		__arch_ioremap((cookie),(size),0)
-#define ioremap_nocache(cookie,size)	__arch_ioremap((cookie),(size),0)
-#define ioremap_cached(cookie,size)	__arch_ioremap((cookie),(size),L_PTE_CACHEABLE)
+#define ioremap(cookie,size)		__arch_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_nocache(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_cached(cookie,size)	__arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
 #define iounmap(cookie)			__arch_iounmap(cookie)
 #endif
 
diff --git a/include/asm-arm/kdebug.h b/include/asm-arm/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-arm/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h
index 8c1c616..b5b030e 100644
--- a/include/asm-arm/kexec.h
+++ b/include/asm-arm/kexec.h
@@ -16,8 +16,6 @@ #define KEXEC_ARCH KEXEC_ARCH_ARM
 
 #ifndef __ASSEMBLY__
 
-#define MAX_NOTE_BYTES 1024
-
 struct kimage;
 /* Provide a dummy definition to avoid build failures. */
 static inline void crash_setup_regs(struct pt_regs *newregs,
diff --git a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h
index cef5364..7ef3c83 100644
--- a/include/asm-arm/mach/map.h
+++ b/include/asm-arm/mach/map.h
@@ -9,6 +9,8 @@
  *
  *  Page table mapping constructs and function prototypes
  */
+#include <asm/io.h>
+
 struct map_desc {
 	unsigned long virtual;
 	unsigned long pfn;
@@ -16,15 +18,16 @@ struct map_desc {
 	unsigned int type;
 };
 
-#define MT_DEVICE		0
-#define MT_CACHECLEAN		1
-#define MT_MINICLEAN		2
-#define MT_LOW_VECTORS		3
-#define MT_HIGH_VECTORS		4
-#define MT_MEMORY		5
-#define MT_ROM			6
-#define MT_IXP2000_DEVICE	7
-#define MT_NONSHARED_DEVICE	8
+/* types 0-3 are defined in asm/io.h */
+#define MT_CACHECLEAN		4
+#define MT_MINICLEAN		5
+#define MT_LOW_VECTORS		6
+#define MT_HIGH_VECTORS		7
+#define MT_MEMORY		8
+#define MT_ROM			9
+
+#define MT_NONSHARED_DEVICE	MT_DEVICE_NONSHARED
+#define MT_IXP2000_DEVICE	MT_DEVICE_IXP2000
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
diff --git a/include/asm-arm/mach/mmc.h b/include/asm-arm/mach/mmc.h
index 1b3555d..eb91145 100644
--- a/include/asm-arm/mach/mmc.h
+++ b/include/asm-arm/mach/mmc.h
@@ -4,7 +4,7 @@
 #ifndef ASMARM_MACH_MMC_H
 #define ASMARM_MACH_MMC_H
 
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
 
 struct mmc_platform_data {
 	unsigned int ocr_mask;			/* available voltages */
diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
index d1a65b1..f8755c8 100644
--- a/include/asm-arm/mmu_context.h
+++ b/include/asm-arm/mmu_context.h
@@ -16,6 +16,7 @@ #define __ASM_ARM_MMU_CONTEXT_H
 #include <linux/compiler.h>
 #include <asm/cacheflush.h>
 #include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
 
 void __check_kvm_seq(struct mm_struct *mm);
 
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index 7b1c9ac..0c8be19 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -83,10 +83,6 @@ #define pgtable_cache_init()	do { } whil
 #define io_remap_page_range	remap_page_range
 #define io_remap_pfn_range	remap_pfn_range
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 
 /*
  * All 32bit addresses are effectively valid for vmalloc...
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 7b2bafc..21dec9f 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -395,10 +395,6 @@ #define HAVE_ARCH_UNMAPPED_AREA
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
 		remap_pfn_range(vma, from, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define pgtable_cache_init() do { } while (0)
 
 #endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm/plat-s3c24xx/clock.h b/include/asm-arm/plat-s3c24xx/clock.h
index f6135db..235b753 100644
--- a/include/asm-arm/plat-s3c24xx/clock.h
+++ b/include/asm-arm/plat-s3c24xx/clock.h
@@ -56,6 +56,7 @@ extern struct mutex clocks_mutex;
 extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
 
 extern int s3c24xx_register_clock(struct clk *clk);
+extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
 
 extern int s3c24xx_setup_clocks(unsigned long xtal,
 				unsigned long fclk,
diff --git a/include/asm-arm/plat-s3c24xx/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h
index 15dd188..23e420e 100644
--- a/include/asm-arm/plat-s3c24xx/cpu.h
+++ b/include/asm-arm/plat-s3c24xx/cpu.h
@@ -40,22 +40,6 @@ extern void s3c24xx_init_uartdevs(char *
 				  struct s3c24xx_uart_resources *res,
 				  struct s3c2410_uartcfg *cfg, int no);
 
-/* the board structure is used at first initialsation time
- * to get info such as the devices to register for this
- * board. This is done because platfrom_add_devices() cannot
- * be called from the map_io entry.
-*/
-
-struct s3c24xx_board {
-	struct platform_device  **devices;
-	unsigned int              devices_count;
-
-	struct clk		**clocks;
-	unsigned int		  clocks_count;
-};
-
-extern void s3c24xx_set_board(struct s3c24xx_board *board);
-
 /* timer for 2410/2440 */
 
 struct sys_timer;
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
index 5a8ef78..2d0dad8 100644
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -10,23 +10,19 @@
 #ifndef __ASM_ARM_PTRACE_H
 #define __ASM_ARM_PTRACE_H
 
-
 #define PTRACE_GETREGS		12
 #define PTRACE_SETREGS		13
 #define PTRACE_GETFPREGS	14
 #define PTRACE_SETFPREGS	15
-
+/* PTRACE_ATTACH is 16 */
+/* PTRACE_DETACH is 17 */
 #define PTRACE_GETWMMXREGS	18
 #define PTRACE_SETWMMXREGS	19
-
+/* 20 is unused */
 #define PTRACE_OLDSETOPTIONS	21
-
 #define PTRACE_GET_THREAD_AREA	22
-
 #define PTRACE_SET_SYSCALL	23
-
 /* PTRACE_SYSCALL is 24 */
-
 #define PTRACE_GETCRUNCHREGS	25
 #define PTRACE_SETCRUNCHREGS	26
 
diff --git a/include/asm-arm/socket.h b/include/asm-arm/socket.h
index 19f7df7..65a1a64 100644
--- a/include/asm-arm/socket.h
+++ b/include/asm-arm/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-arm/sockios.h b/include/asm-arm/sockios.h
index 77c3408..a2588a2 100644
--- a/include/asm-arm/sockios.h
+++ b/include/asm-arm/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 69134c7..f2da3b6 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -76,6 +76,8 @@ #ifndef __ASSEMBLY__
 #include <linux/linkage.h>
 #include <linux/irqflags.h>
 
+#define __exception	__attribute__((section(".exception.text")))
+
 struct thread_info;
 struct task_struct;
 
@@ -91,7 +93,7 @@ void die(const char *msg, struct pt_regs
 		__attribute__((noreturn));
 
 struct siginfo;
-void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
 		unsigned long err, unsigned long trap);
 
 void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
@@ -101,8 +103,6 @@ void hook_fault_code(int nr, int (*fn)(u
 #define xchg(ptr,x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
-#define tas(ptr) (xchg((ptr),1))
-
 extern asmlinkage void __backtrace(void);
 extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
 
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index 5014794..eae85b0 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -57,6 +57,7 @@ struct thread_info {
 	__u32			cpu;		/* cpu */
 	__u32			cpu_domain;	/* cpu domain */
 	struct cpu_context_save	cpu_context;	/* cpu context */
+	__u32			syscall;	/* syscall number */
 	__u8			used_cp[16];	/* thread used copro */
 	unsigned long		tp_value;
 	struct crunch_state	crunchstate;
diff --git a/include/asm-arm26/atomic.h b/include/asm-arm26/atomic.h
index 97e944f..d6dd423 100644
--- a/include/asm-arm26/atomic.h
+++ b/include/asm-arm26/atomic.h
@@ -20,7 +20,6 @@
 #ifndef __ASM_ARM_ATOMIC_H
 #define __ASM_ARM_ATOMIC_H
 
-
 #ifdef CONFIG_SMP
 #error SMP is NOT supported
 #endif
diff --git a/include/asm-arm26/kdebug.h b/include/asm-arm26/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-arm26/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-arm26/mmu_context.h b/include/asm-arm26/mmu_context.h
index 1a929bf..16c821f 100644
--- a/include/asm-arm26/mmu_context.h
+++ b/include/asm-arm26/mmu_context.h
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARM_MMU_CONTEXT_H
 #define __ASM_ARM_MMU_CONTEXT_H
 
+#include <asm-generic/mm_hooks.h>
+
 #define init_new_context(tsk,mm)	0
 #define destroy_context(mm)		do { } while(0)
 
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
index 63a8881..2b20e9f 100644
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -297,10 +297,6 @@ #include <asm-generic/pgtable.h>
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
 		remap_pfn_range(vma, from, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASMARM_PGTABLE_H */
diff --git a/include/asm-arm26/socket.h b/include/asm-arm26/socket.h
index 19f7df7..65a1a64 100644
--- a/include/asm-arm26/socket.h
+++ b/include/asm-arm26/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-arm26/sockios.h b/include/asm-arm26/sockios.h
index 77c3408..a2588a2 100644
--- a/include/asm-arm26/sockios.h
+++ b/include/asm-arm26/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h
index 00ae32a..4703593 100644
--- a/include/asm-arm26/system.h
+++ b/include/asm-arm26/system.h
@@ -52,8 +52,6 @@ #include <asm/proc-fns.h>
 #define xchg(ptr,x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
-#define tas(ptr) (xchg((ptr),1))
-
 extern asmlinkage void __backtrace(void);
 
 #define set_cr(x)					\
diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
new file mode 100644
index 0000000..ee59e40
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/io.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
+#define __ASM_AVR32_ARCH_AT32AP_IO_H
+
+/* For "bizarre" halfword swapping */
+#include <linux/byteorder/swabb.h>
+
+#if defined(CONFIG_AP7000_32_BIT_SMC)
+# define __swizzle_addr_b(addr)	(addr ^ 3UL)
+# define __swizzle_addr_w(addr)	(addr ^ 2UL)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		(x)
+# define ioswabl(a, x)		(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	swab16(x)
+# define __mem_ioswabl(a, x)	swab32(x)
+#elif defined(CONFIG_AP7000_16_BIT_SMC)
+# define __swizzle_addr_b(addr)	(addr ^ 1UL)
+# define __swizzle_addr_w(addr)	(addr)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		(x)
+# define ioswabl(a, x)		swahw32(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	swab16(x)
+# define __mem_ioswabl(a, x)	swahb32(x)
+#else
+# define __swizzle_addr_b(addr)	(addr)
+# define __swizzle_addr_w(addr)	(addr)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		swab16(x)
+# define ioswabl(a, x)		swab32(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	(x)
+# define __mem_ioswabl(a, x)	(x)
+#endif
+
+#endif /* __ASM_AVR32_ARCH_AT32AP_IO_H */
diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h
index 3732b32..07152b7 100644
--- a/include/asm-avr32/arch-at32ap/smc.h
+++ b/include/asm-avr32/arch-at32ap/smc.h
@@ -48,10 +48,32 @@ struct smc_config {
 	unsigned int	nwe_controlled:1;
 
 	/*
+	 * 0: NWAIT is disabled
+	 * 1: Reserved
+	 * 2: NWAIT is frozen mode
+	 * 3: NWAIT in ready mode
+	 */
+	unsigned int	nwait_mode:2;
+
+	/*
 	 * 0: Byte select access type
 	 * 1: Byte write access type
 	 */
 	unsigned int	byte_write:1;
+
+	/*
+	 * Number of clock cycles before data is released after
+	 * the rising edge of the read controlling signal
+	 *
+	 * Total cycles from SMC is tdf_cycles + 1
+	 */
+	unsigned int	tdf_cycles:4;
+
+	/*
+	 * 0: TDF optimization disabled
+	 * 1: TDF optimization enabled
+	 */
+	unsigned int	tdf_mode:1;
 };
 
 extern int smc_set_configuration(int cs, const struct smc_config *config);
diff --git a/include/asm-avr32/arch-at32ap/time.h b/include/asm-avr32/arch-at32ap/time.h
new file mode 100644
index 0000000..cc8a434
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/time.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 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_ARCH_AT32AP_TIME_H
+#define _ASM_AVR32_ARCH_AT32AP_TIME_H
+
+#include <linux/platform_device.h>
+
+extern struct irqaction timer_irqaction;
+extern struct platform_device at32_systc0_device;
+extern void local_timer_interrupt(int irq, void *dev_id);
+
+#define TIMER_BCR					0x000000c0
+#define TIMER_BCR_SYNC						 0
+#define TIMER_BMR					0x000000c4
+#define TIMER_BMR_TC0XC0S					 0
+#define TIMER_BMR_TC1XC1S					 2
+#define TIMER_BMR_TC2XC2S					 4
+#define TIMER_CCR					0x00000000
+#define TIMER_CCR_CLKDIS					 1
+#define TIMER_CCR_CLKEN						 0
+#define TIMER_CCR_SWTRG						 2
+#define TIMER_CMR					0x00000004
+#define TIMER_CMR_ABETRG					10
+#define TIMER_CMR_ACPA						16
+#define TIMER_CMR_ACPC						18
+#define TIMER_CMR_AEEVT						20
+#define TIMER_CMR_ASWTRG					22
+#define TIMER_CMR_BCPB						24
+#define TIMER_CMR_BCPC						26
+#define TIMER_CMR_BEEVT						28
+#define TIMER_CMR_BSWTRG					30
+#define TIMER_CMR_BURST						 4
+#define TIMER_CMR_CLKI						 3
+#define TIMER_CMR_CPCDIS					 7
+#define TIMER_CMR_CPCSTOP					 6
+#define TIMER_CMR_CPCTRG					14
+#define TIMER_CMR_EEVT						10
+#define TIMER_CMR_EEVTEDG					 8
+#define TIMER_CMR_ENETRG					12
+#define TIMER_CMR_ETRGEDG					 8
+#define TIMER_CMR_LDBDIS					 7
+#define TIMER_CMR_LDBSTOP					 6
+#define TIMER_CMR_LDRA						16
+#define TIMER_CMR_LDRB						18
+#define TIMER_CMR_TCCLKS					 0
+#define TIMER_CMR_WAVE						15
+#define TIMER_CMR_WAVSEL					13
+#define TIMER_CV					0x00000010
+#define TIMER_CV_CV						 0
+#define TIMER_IDR					0x00000028
+#define TIMER_IDR_COVFS						 0
+#define TIMER_IDR_CPAS						 2
+#define TIMER_IDR_CPBS						 3
+#define TIMER_IDR_CPCS						 4
+#define TIMER_IDR_ETRGS						 7
+#define TIMER_IDR_LDRAS						 5
+#define TIMER_IDR_LDRBS						 6
+#define TIMER_IDR_LOVRS						 1
+#define TIMER_IER					0x00000024
+#define TIMER_IER_COVFS						 0
+#define TIMER_IER_CPAS						 2
+#define TIMER_IER_CPBS						 3
+#define TIMER_IER_CPCS						 4
+#define TIMER_IER_ETRGS						 7
+#define TIMER_IER_LDRAS						 5
+#define TIMER_IER_LDRBS						 6
+#define TIMER_IER_LOVRS						 1
+#define TIMER_IMR					0x0000002c
+#define TIMER_IMR_COVFS						 0
+#define TIMER_IMR_CPAS						 2
+#define TIMER_IMR_CPBS						 3
+#define TIMER_IMR_CPCS						 4
+#define TIMER_IMR_ETRGS						 7
+#define TIMER_IMR_LDRAS						 5
+#define TIMER_IMR_LDRBS						 6
+#define TIMER_IMR_LOVRS						 1
+#define TIMER_RA					0x00000014
+#define TIMER_RA_RA						 0
+#define TIMER_RB					0x00000018
+#define TIMER_RB_RB						 0
+#define TIMER_RC					0x0000001c
+#define TIMER_RC_RC						 0
+#define TIMER_SR					0x00000020
+#define TIMER_SR_CLKSTA						16
+#define TIMER_SR_COVFS						 0
+#define TIMER_SR_CPAS						 2
+#define TIMER_SR_CPBS						 3
+#define TIMER_SR_CPCS						 4
+#define TIMER_SR_ETRGS						 7
+#define TIMER_SR_LDRAS						 5
+#define TIMER_SR_LDRBS						 6
+#define TIMER_SR_LOVRS						 1
+#define TIMER_SR_MTIOA						17
+#define TIMER_SR_MTIOB						18
+
+/* Bit manipulation macros */
+#define TIMER_BIT(name)		(1 << TIMER_##name)
+#define TIMER_BF(name,value)	((value) << TIMER_##name)
+
+/* Register access macros */
+#define timer_read(port,instance,reg) \
+	__raw_readl(port + (0x40 * instance) + TIMER_##reg)
+#define timer_write(port,instance,reg,value) \
+	__raw_writel((value), port + (0x40 * instance) + TIMER_##reg)
+
+#endif /* _ASM_AVR32_ARCH_AT32AP_TIME_H */
diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
index c40b603..b9c2548 100644
--- a/include/asm-avr32/atomic.h
+++ b/include/asm-avr32/atomic.h
@@ -173,7 +173,7 @@ static inline int atomic_sub_if_positive
 }
 
 #define atomic_xchg(v, new)	(xchg(&((v)->counter), new))
-#define atomic_cmpxchg(v, o, n)	((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n)	(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)
diff --git a/include/asm-avr32/bug.h b/include/asm-avr32/bug.h
index 521766b..afdcd79 100644
--- a/include/asm-avr32/bug.h
+++ b/include/asm-avr32/bug.h
@@ -18,27 +18,53 @@ #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)
+#define _BUG_OR_WARN(flags)						\
+	asm volatile(							\
+		"1:	.hword	%0\n"					\
+		"	.section __bug_table,\"a\",@progbits\n"		\
+		"2:	.long	1b\n"					\
+		"	.long	%1\n"					\
+		"	.short	%2\n"					\
+		"	.short	%3\n"					\
+		"	.org	2b + %4\n"				\
+		"	.previous"					\
+		:							\
+		: "i"(AVR32_BUG_OPCODE), "i"(__FILE__),			\
+		  "i"(__LINE__), "i"(flags),				\
+		  "i"(sizeof(struct bug_entry)))
 
 #else
 
+#define _BUG_OR_WARN(flags)						\
+	asm volatile(							\
+		"1:	.hword	%0\n"					\
+		"	.section __bug_table,\"a\",@progbits\n"		\
+		"2:	.long	1b\n"					\
+		"	.short	%1\n"					\
+		"	.org	2b + %2\n"				\
+		"	.previous"					\
+		:							\
+		: "i"(AVR32_BUG_OPCODE), "i"(flags),			\
+		  "i"(sizeof(struct bug_entry)))
+
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
 #define BUG()								\
 	do {								\
-		asm volatile(".hword	%0\n\t"				\
-			     : : "n"(AVR32_BUG_OPCODE));		\
+		_BUG_OR_WARN(0);					\
+		for (;;);						\
 	} while (0)
 
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#define WARN_ON(condition)							\
+	({								\
+		typeof(condition) __ret_warn_on = (condition);		\
+		if (unlikely(__ret_warn_on))				\
+			_BUG_OR_WARN(BUGFLAG_WARNING);			\
+		unlikely(__ret_warn_on);				\
+	})
 
 #define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
 
 #endif /* CONFIG_BUG */
 
diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h
index c08e810..e30d4b3 100644
--- a/include/asm-avr32/io.h
+++ b/include/asm-avr32/io.h
@@ -1,13 +1,15 @@
 #ifndef __ASM_AVR32_IO_H
 #define __ASM_AVR32_IO_H
 
+#include <linux/kernel.h>
 #include <linux/string.h>
-
-#ifdef __KERNEL__
+#include <linux/types.h>
 
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
+#include <asm/arch/io.h>
+
 /* virt_to_phys will only work when address is in P1 or P2 */
 static __inline__ unsigned long virt_to_phys(volatile void *address)
 {
@@ -36,104 +38,215 @@ extern void __raw_readsb(const void __io
 extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
 extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
+static inline void __raw_writeb(u8 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned char __force *)addr = b;
+	*(volatile u8 __force *)addr = v;
 }
-static inline void writew(unsigned short b, volatile void __iomem *addr)
+static inline void __raw_writew(u16 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned short __force *)addr = b;
+	*(volatile u16 __force *)addr = v;
 }
-static inline void writel(unsigned int b, volatile void __iomem *addr)
+static inline void __raw_writel(u32 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned int __force *)addr = b;
+	*(volatile u32 __force *)addr = v;
 }
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
 
-static inline unsigned char readb(const volatile void __iomem *addr)
+static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned char __force *)addr;
+	return *(const volatile u8 __force *)addr;
 }
-static inline unsigned short readw(const volatile void __iomem *addr)
+static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned short __force *)addr;
+	return *(const volatile u16 __force *)addr;
 }
-static inline unsigned int readl(const volatile void __iomem *addr)
+static inline u32 __raw_readl(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned int __force *)addr;
+	return *(const volatile u32 __force *)addr;
+}
+
+/* Convert I/O port address to virtual address */
+#ifndef __io
+# define __io(p)	((void *)phys_to_uncached(p))
+#endif
+
+/*
+ * Not really sure about the best way to slow down I/O on
+ * AVR32. Defining it as a no-op until we have an actual test case.
+ */
+#define SLOW_DOWN_IO	do { } while (0)
+
+#define __BUILD_MEMORY_SINGLE(pfx, bwl, type)				\
+static inline void							\
+pfx##write##bwl(type val, volatile void __iomem *addr)			\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr));	\
+	__val = pfx##ioswab##bwl(__addr, val);				\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	*__addr = __val;						\
+}									\
+									\
+static inline type pfx##read##bwl(const volatile void __iomem *addr)	\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr));	\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	__val = *__addr;						\
+	return pfx##ioswab##bwl(__addr, __val);				\
+}
+
+#define __BUILD_IOPORT_SINGLE(pfx, bwl, type, p, slow)			\
+static inline void pfx##out##bwl##p(type val, unsigned long port)	\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = __io(__swizzle_addr_##bwl(port));			\
+	__val = pfx##ioswab##bwl(__addr, val);				\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	*__addr = __val;						\
+	slow;								\
+}									\
+									\
+static inline type pfx##in##bwl##p(unsigned long port)			\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = __io(__swizzle_addr_##bwl(port));			\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	__val = *__addr;						\
+	slow;								\
+									\
+	return pfx##ioswab##bwl(__addr, __val);				\
+}
+
+#define __BUILD_MEMORY_PFX(bus, bwl, type)				\
+	__BUILD_MEMORY_SINGLE(bus, bwl, type)
+
+#define BUILDIO_MEM(bwl, type)						\
+	__BUILD_MEMORY_PFX(, bwl, type)					\
+	__BUILD_MEMORY_PFX(__mem_, bwl, type)
+
+#define __BUILD_IOPORT_PFX(bus, bwl, type)				\
+	__BUILD_IOPORT_SINGLE(bus, bwl, type, ,)			\
+	__BUILD_IOPORT_SINGLE(bus, bwl, type, _p, SLOW_DOWN_IO)
+
+#define BUILDIO_IOPORT(bwl, type)					\
+	__BUILD_IOPORT_PFX(, bwl, type)					\
+	__BUILD_IOPORT_PFX(__mem_, bwl, type)
+
+BUILDIO_MEM(b, u8)
+BUILDIO_MEM(w, u16)
+BUILDIO_MEM(l, u32)
+
+BUILDIO_IOPORT(b, u8)
+BUILDIO_IOPORT(w, u16)
+BUILDIO_IOPORT(l, u32)
+
+#define readb_relaxed			readb
+#define readw_relaxed			readw
+#define readl_relaxed			readl
+
+#define __BUILD_MEMORY_STRING(bwl, type)				\
+static inline void writes##bwl(volatile void __iomem *addr,		\
+			       const void *data, unsigned int count)	\
+{									\
+	const type *__data = data;					\
+									\
+	while (count--)							\
+		__mem_write##bwl(*__data++, addr);			\
+}									\
+									\
+static inline void reads##bwl(const volatile void __iomem *addr,	\
+			      void *data, unsigned int count)		\
+{									\
+	type *__data = data;						\
+									\
+	while (count--)							\
+		*__data++ = __mem_read##bwl(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 __BUILD_IOPORT_STRING(bwl, type)				\
+static inline void outs##bwl(unsigned long port, const void *data,	\
+			     unsigned int count)			\
+{									\
+	const type *__data = data;					\
+									\
+	while (count--)							\
+		__mem_out##bwl(*__data++, port);			\
+}									\
+									\
+static inline void ins##bwl(unsigned long port, void *data,		\
+			   unsigned int count)				\
+{									\
+	type *__data = data;						\
+									\
+	while (count--)							\
+		*__data++ = __mem_in##bwl(port);			\
+}
 
-#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)
+#define BUILDSTRING(bwl, type)						\
+	__BUILD_MEMORY_STRING(bwl, type)				\
+	__BUILD_IOPORT_STRING(bwl, type)
 
+BUILDSTRING(b, u8)
+BUILDSTRING(w, u16)
+BUILDSTRING(l, u32)
 
 /*
  * 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 ioread8(p)		((unsigned int)readb(p))
 
-#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 ioread16(p)		((unsigned int)readw(p))
+#define ioread16be(p)		((unsigned int)__raw_readw(p))
 
-#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 ioread32(p)		((unsigned int)readl(p))
+#define ioread32be(p)		((unsigned int)__raw_readl(p))
 
-#define iowrite8(v,p)	__raw_writeb(v, p)
+#define iowrite8(v,p)		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 iowrite16(v,p)		writew(v, p)
+#define iowrite16be(v,p)	__raw_writew(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 iowrite32(v,p)		writel(v, p)
+#define iowrite32be(v,p)	__raw_writel(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 ioread8_rep(p,d,c)	readsb(p,d,c)
+#define ioread16_rep(p,d,c)	readsw(p,d,c)
+#define ioread32_rep(p,d,c)	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)
+#define iowrite8_rep(p,s,c)	writesb(p,s,c)
+#define iowrite16_rep(p,s,c)	writesw(p,s,c)
+#define iowrite32_rep(p,s,c)	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++;
-	}
+	memcpy(to, (const void __force *)from, count);
 }
 
 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++;
-	}
+	memcpy((void __force *)to, from, count);
 }
 
 static inline void memset_io(volatile void __iomem *addr, unsigned char val,
@@ -142,99 +255,8 @@ static inline void memset_io(volatile vo
 	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);
@@ -292,6 +314,4 @@ #define xlate_dev_mem_ptr(p)    __va(p)
  */
 #define xlate_dev_kmem_ptr(p)   p
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_AVR32_IO_H */
diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
index f583b64..de41927 100644
--- a/include/asm-avr32/kdebug.h
+++ b/include/asm-avr32/kdebug.h
@@ -3,19 +3,6 @@ #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,
@@ -24,15 +11,7 @@ enum die_val {
 	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);
-}
+int register_page_fault_notifier(struct notifier_block *nb);
+int unregister_page_fault_notifier(struct notifier_block *nb);
 
 #endif /* __ASM_AVR32_KDEBUG_H */
diff --git a/include/asm-avr32/mmu_context.h b/include/asm-avr32/mmu_context.h
index 31add1a..c37c391 100644
--- a/include/asm-avr32/mmu_context.h
+++ b/include/asm-avr32/mmu_context.h
@@ -15,6 +15,7 @@ #define __ASM_AVR32_MMU_CONTEXT_H
 #include <asm/tlbflush.h>
 #include <asm/pgalloc.h>
 #include <asm/sysreg.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * The MMU "context" consists of two things:
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index 6b8ca9d..f6cc2b0 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -394,10 +394,6 @@ #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)
 
diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
index f691377..6a64833 100644
--- a/include/asm-avr32/processor.h
+++ b/include/asm-avr32/processor.h
@@ -40,6 +40,14 @@ enum tlb_config {
 	TLB_INVALID
 };
 
+#define AVR32_FEATURE_RMW	(1 << 0)
+#define AVR32_FEATURE_DSP	(1 << 1)
+#define AVR32_FEATURE_SIMD	(1 << 2)
+#define AVR32_FEATURE_OCD	(1 << 3)
+#define AVR32_FEATURE_PCTR	(1 << 4)
+#define AVR32_FEATURE_JAVA	(1 << 5)
+#define AVR32_FEATURE_FPU	(1 << 6)
+
 struct avr32_cpuinfo {
 	struct clk *clk;
 	unsigned long loops_per_jiffy;
@@ -48,6 +56,7 @@ struct avr32_cpuinfo {
 	unsigned short arch_revision;
 	unsigned short cpu_revision;
 	enum tlb_config tlb_config;
+	unsigned long features;
 
 	struct cache_info icache;
 	struct cache_info dcache;
@@ -125,10 +134,10 @@ #define prepare_to_copy(tsk) do { } whil
 #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);
+extern void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl);
+extern void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
+			       struct pt_regs *regs, const char *log_lvl);
 
 #define KSTK_EIP(tsk)	((tsk)->thread.cpu_context.pc)
 #define KSTK_ESP(tsk)	((tsk)->thread.cpu_context.ksp)
diff --git a/include/asm-avr32/scatterlist.h b/include/asm-avr32/scatterlist.h
index bfe7d75..c6d5ce3 100644
--- a/include/asm-avr32/scatterlist.h
+++ b/include/asm-avr32/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_AVR32_SCATTERLIST_H
 #define __ASM_AVR32_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-avr32/setup.h b/include/asm-avr32/setup.h
index 0a52242..1ff1a21 100644
--- a/include/asm-avr32/setup.h
+++ b/include/asm-avr32/setup.h
@@ -124,19 +124,12 @@ #define tag_size(type)	((sizeof(struct t
 #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);
+extern resource_size_t fbmem_start;
+extern resource_size_t fbmem_size;
 
-/* Chip-specific hook to enable the use of SDRAM */
-void chip_enable_sdram(void);
+void setup_processor(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/include/asm-avr32/socket.h b/include/asm-avr32/socket.h
index 543229d..a0d0507 100644
--- a/include/asm-avr32/socket.h
+++ b/include/asm-avr32/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_AVR32_SOCKET_H */
diff --git a/include/asm-avr32/sockios.h b/include/asm-avr32/sockios.h
index 84f3d65..0802d74 100644
--- a/include/asm-avr32/sockios.h
+++ b/include/asm-avr32/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ASM_AVR32_SOCKIOS_H */
diff --git a/include/asm-avr32/sysreg.h b/include/asm-avr32/sysreg.h
index f91975f..c02bc83 100644
--- a/include/asm-avr32/sysreg.h
+++ b/include/asm-avr32/sysreg.h
@@ -7,326 +7,281 @@
  * 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__
+#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
+#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
+#define SYSREG_SABAL				0x0300
+#define SYSREG_SABAH				0x0304
+#define SYSREG_SABD				0x0308
 
 /* 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 */
+#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_L_OFFSET				5
+#define SYSREG_L_SIZE				1
+#define SYSREG_T_OFFSET				14
+#define SYSREG_T_SIZE				1
+#define SYSREG_SR_R_OFFSET			15
+#define SYSREG_SR_R_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_H_OFFSET				29
+#define SYSREG_H_SIZE				1
 
 /* 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 */
+#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 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
+#define SYSREG_CONFIG0_R_OFFSET			0
+#define SYSREG_CONFIG0_R_SIZE			1
+#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_CONFIG0_O_OFFSET			3
+#define SYSREG_CONFIG0_O_SIZE			1
+#define SYSREG_CONFIG0_P_OFFSET			4
+#define SYSREG_CONFIG0_P_SIZE			1
+#define SYSREG_CONFIG0_J_OFFSET			5
+#define SYSREG_CONFIG0_J_SIZE			1
+#define SYSREG_CONFIG0_F_OFFSET			6
+#define SYSREG_CONFIG0_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 */
+#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			3
+#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 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
+#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 */
+#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 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 */
+#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 PCCR */
-
-/* Bitfields in BEAR */
+#define SYSREG_PCCR_R_OFFSET			1
+#define SYSREG_PCCR_R_SIZE			1
+#define SYSREG_PCCR_C_OFFSET			2
+#define SYSREG_PCCR_C_SIZE			1
+#define SYSREG_PCCR_S_OFFSET			3
+#define SYSREG_PCCR_S_SIZE			1
+#define SYSREG_IEC_OFFSET			4
+#define SYSREG_IEC_SIZE				1
+#define SYSREG_IE0_OFFSET			5
+#define SYSREG_IE0_SIZE				1
+#define SYSREG_IE1_OFFSET			6
+#define SYSREG_IE1_SIZE				1
+#define SYSREG_FC_OFFSET			8
+#define SYSREG_FC_SIZE				1
+#define SYSREG_F0_OFFSET			9
+#define SYSREG_F0_SIZE				1
+#define SYSREG_F1_OFFSET			10
+#define SYSREG_F1_SIZE				1
+#define SYSREG_CONF0_OFFSET			12
+#define SYSREG_CONF0_SIZE			6
+#define SYSREG_CONF1_OFFSET			18
+#define SYSREG_CONF1_SIZE			6
 
 /* 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
+#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))
+#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))
 
+/* Register access macros */
 #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)
+#define sysreg_read(reg)		__builtin_mfsr(SYSREG_##reg)
+#define sysreg_write(reg, value)	__builtin_mtsr(SYSREG_##reg, value)
 
-#endif /* __ASM_AVR32_SYSREG_H__ */
+#endif /* __ASM_AVR32_SYSREG_H */
diff --git a/include/asm-avr32/system.h b/include/asm-avr32/system.h
index ac59605..a8236ba 100644
--- a/include/asm-avr32/system.h
+++ b/include/asm-avr32/system.h
@@ -9,6 +9,7 @@ #ifndef __ASM_AVR32_SYSTEM_H
 #define __ASM_AVR32_SYSTEM_H
 
 #include <linux/compiler.h>
+#include <linux/linkage.h>
 #include <linux/types.h>
 
 #include <asm/ptrace.h>
@@ -140,15 +141,9 @@ #define cmpxchg(ptr, old, 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__)
+void NORET_TYPE die(const char *str, struct pt_regs *regs, long err);
+void _exception(long signr, struct pt_regs *regs, int code,
+		unsigned long addr);
 
 #define arch_align_stack(x)	(x)
 
diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
index d1f5b35..a2e606d 100644
--- a/include/asm-avr32/thread_info.h
+++ b/include/asm-avr32/thread_info.h
@@ -83,6 +83,7 @@ #define TIF_BREAKPOINT		5	/* true if we 
 #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_CPU_GOING_TO_SLEEP	9	/* CPU is entering sleep 0 mode */
 #define TIF_USERSPACE		31      /* true if FS sets userspace */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
@@ -94,6 +95,7 @@ #define _TIF_BREAKPOINT		(1 << TIF_BREAK
 #define _TIF_SINGLE_STEP	(1 << TIF_SINGLE_STEP)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
+#define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
 
 /* XXX: These two masks must never span more than 16 bits! */
 /* work to do on interrupt/exception return */
diff --git a/include/asm-avr32/uaccess.h b/include/asm-avr32/uaccess.h
index 74a679e..ed09239 100644
--- a/include/asm-avr32/uaccess.h
+++ b/include/asm-avr32/uaccess.h
@@ -181,24 +181,23 @@ extern int __put_user_bad(void);
 
 #define __get_user_nocheck(x, ptr, size)				\
 ({									\
-	typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0;		\
+	unsigned long __gu_val = 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;							\
+	x = (typeof(*(ptr)))__gu_val;					\
 	__gu_err;							\
 })
 
 #define __get_user_check(x, ptr, size)					\
 ({									\
-	typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0;		\
+	unsigned long __gu_val = 0;					\
 	const typeof(*(ptr)) __user * __gu_addr = (ptr);		\
 	int __gu_err = 0;						\
 									\
@@ -216,10 +215,6 @@ ({									\
 			__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;						\
@@ -227,7 +222,7 @@ ({									\
 	} else {							\
 		__gu_err = -EFAULT;					\
 	}								\
-	x = __gu_val;							\
+	x = (typeof(*(ptr)))__gu_val;					\
 	__gu_err;							\
 })
 
diff --git a/include/asm-blackfin/Kbuild b/include/asm-blackfin/Kbuild
new file mode 100644
index 0000000..c68e168
--- /dev/null
+++ b/include/asm-blackfin/Kbuild
@@ -0,0 +1 @@
+include include/asm-generic/Kbuild.asm
diff --git a/include/asm-blackfin/a.out.h b/include/asm-blackfin/a.out.h
new file mode 100644
index 0000000..d37a684
--- /dev/null
+++ b/include/asm-blackfin/a.out.h
@@ -0,0 +1,25 @@
+#ifndef __BFIN_A_OUT_H__
+#define __BFIN_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				/* __BFIN_A_OUT_H__ */
diff --git a/include/asm-blackfin/atomic.h b/include/asm-blackfin/atomic.h
new file mode 100644
index 0000000..7cf5087
--- /dev/null
+++ b/include/asm-blackfin/atomic.h
@@ -0,0 +1,144 @@
+#ifndef __ARCH_BLACKFIN_ATOMIC__
+#define __ARCH_BLACKFIN_ATOMIC__
+
+#include <asm/system.h>	/* local_irq_XXX() */
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ *
+ * Generally we do not concern about SMP BFIN systems, so we don't have
+ * to deal with that.
+ *
+ * Tony Kou (tonyko@lineo.ca)   Lineo Inc.   2001
+ */
+
+typedef struct {
+	int counter;
+} atomic_t;
+#define ATOMIC_INIT(i)	{ (i) }
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v, i)	(((v)->counter) = i)
+
+static __inline__ void atomic_add(int i, atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter += i;
+	local_irq_restore(flags);
+}
+
+static __inline__ void atomic_sub(int i, atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter -= i;
+	local_irq_restore(flags);
+
+}
+
+static inline int atomic_add_return(int i, atomic_t * v)
+{
+	int __temp = 0;
+	long flags;
+
+	local_irq_save(flags);
+	v->counter += i;
+	__temp = v->counter;
+	local_irq_restore(flags);
+
+
+	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)
+{
+	int __temp = 0;
+	long flags;
+
+	local_irq_save(flags);
+	v->counter -= i;
+	__temp = v->counter;
+	local_irq_restore(flags);
+
+	return __temp;
+}
+
+static __inline__ void atomic_inc(volatile atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter++;
+	local_irq_restore(flags);
+}
+
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+static __inline__ void atomic_dec(volatile atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter--;
+	local_irq_restore(flags);
+}
+
+static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter &= ~mask;
+	local_irq_restore(flags);
+}
+
+static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v)
+{
+	long flags;
+
+	local_irq_save(flags);
+	v->counter |= mask;
+	local_irq_restore(flags);
+}
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+/*
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+
+#include <asm-generic/atomic.h>
+
+#endif				/* __ARCH_BLACKFIN_ATOMIC __ */
diff --git a/include/asm-blackfin/auxvec.h b/include/asm-blackfin/auxvec.h
new file mode 100644
index 0000000..215506c
--- /dev/null
+++ b/include/asm-blackfin/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMBFIN_AUXVEC_H
+#define __ASMBFIN_AUXVEC_H
+
+#endif
diff --git a/include/asm-blackfin/bf5xx_timers.h b/include/asm-blackfin/bf5xx_timers.h
new file mode 100644
index 0000000..86c7703
--- /dev/null
+++ b/include/asm-blackfin/bf5xx_timers.h
@@ -0,0 +1,209 @@
+/*
+ * include/asm/bf5xx_timers.h
+ *
+ * This file contains the major Data structures and constants
+ * used for General Purpose Timer Implementation in BF5xx
+ *
+ * Copyright (C) 2005 John DeHority
+ * Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
+ *
+ */
+
+#ifndef _BLACKFIN_TIMERS_H_
+#define _BLACKFIN_TIMERS_H_
+
+#undef MAX_BLACKFIN_GPTIMERS
+/*
+ * BF537: 8 timers:
+ */
+#if defined(CONFIG_BF537)
+#  define MAX_BLACKFIN_GPTIMERS 8
+#  define TIMER0_GROUP_REG     TIMER_ENABLE
+#endif
+/*
+ * BF561: 12 timers:
+ */
+#if defined(CONFIG_BF561)
+#  define MAX_BLACKFIN_GPTIMERS 12
+#  define TIMER0_GROUP_REG     TMRS8_ENABLE
+#  define TIMER8_GROUP_REG     TMRS4_ENABLE
+#endif
+/*
+ * All others: 3 timers:
+ */
+#if !defined(MAX_BLACKFIN_GPTIMERS)
+#  define MAX_BLACKFIN_GPTIMERS 3
+#  define TIMER0_GROUP_REG     TIMER_ENABLE
+#endif
+
+#define BLACKFIN_GPTIMER_IDMASK ((1UL << MAX_BLACKFIN_GPTIMERS) - 1)
+#define BFIN_TIMER_OCTET(x) ((x) >> 3)
+
+/* used in masks for timer_enable() and timer_disable() */
+#define TIMER0bit  0x0001  /*  0001b */
+#define TIMER1bit  0x0002  /*  0010b */
+#define TIMER2bit  0x0004  /*  0100b */
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+#  define TIMER3bit  0x0008
+#  define TIMER4bit  0x0010
+#  define TIMER5bit  0x0020
+#  define TIMER6bit  0x0040
+#  define TIMER7bit  0x0080
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+#  define TIMER8bit  0x0100
+#  define TIMER9bit  0x0200
+#  define TIMER10bit 0x0400
+#  define TIMER11bit 0x0800
+#endif
+
+#define TIMER0_id   0
+#define TIMER1_id   1
+#define TIMER2_id   2
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+#  define TIMER3_id   3
+#  define TIMER4_id   4
+#  define TIMER5_id   5
+#  define TIMER6_id   6
+#  define TIMER7_id   7
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+#  define TIMER8_id   8
+#  define TIMER9_id   9
+#  define TIMER10_id 10
+#  define TIMER11_id 11
+#endif
+
+/* associated timers for ppi framesync: */
+
+#if defined(CONFIG_BF561)
+#  define FS0_1_TIMER_ID   TIMER8_id
+#  define FS0_2_TIMER_ID   TIMER9_id
+#  define FS1_1_TIMER_ID   TIMER10_id
+#  define FS1_2_TIMER_ID   TIMER11_id
+#  define FS0_1_TIMER_BIT  TIMER8bit
+#  define FS0_2_TIMER_BIT  TIMER9bit
+#  define FS1_1_TIMER_BIT  TIMER10bit
+#  define FS1_2_TIMER_BIT  TIMER11bit
+#  undef FS1_TIMER_ID
+#  undef FS2_TIMER_ID
+#  undef FS1_TIMER_BIT
+#  undef FS2_TIMER_BIT
+#else
+#  define FS1_TIMER_ID  TIMER0_id
+#  define FS2_TIMER_ID  TIMER1_id
+#  define FS1_TIMER_BIT TIMER0bit
+#  define FS2_TIMER_BIT TIMER1bit
+#endif
+
+/*
+** Timer Configuration Register Bits
+*/
+#define TIMER_ERR           0xC000
+#define TIMER_ERR_OVFL      0x4000
+#define TIMER_ERR_PROG_PER  0x8000
+#define TIMER_ERR_PROG_PW   0xC000
+#define TIMER_EMU_RUN       0x0200
+#define	TIMER_TOGGLE_HI     0x0100
+#define	TIMER_CLK_SEL       0x0080
+#define TIMER_OUT_DIS       0x0040
+#define TIMER_TIN_SEL       0x0020
+#define TIMER_IRQ_ENA       0x0010
+#define TIMER_PERIOD_CNT    0x0008
+#define TIMER_PULSE_HI      0x0004
+#define TIMER_MODE          0x0003
+#define TIMER_MODE_PWM      0x0001
+#define TIMER_MODE_WDTH     0x0002
+#define TIMER_MODE_EXT_CLK  0x0003
+
+/*
+** Timer Status Register Bits
+*/
+#define TIMER_STATUS_TIMIL0 0x0001
+#define TIMER_STATUS_TIMIL1 0x0002
+#define TIMER_STATUS_TIMIL2 0x0004
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+#  define TIMER_STATUS_TIMIL3 0x00000008
+#  define TIMER_STATUS_TIMIL4 0x00010000
+#  define TIMER_STATUS_TIMIL5 0x00020000
+#  define TIMER_STATUS_TIMIL6 0x00040000
+#  define TIMER_STATUS_TIMIL7 0x00080000
+#  if (MAX_BLACKFIN_GPTIMERS > 8)
+#    define TIMER_STATUS_TIMIL8  0x0001
+#    define TIMER_STATUS_TIMIL9  0x0002
+#    define TIMER_STATUS_TIMIL10 0x0004
+#    define TIMER_STATUS_TIMIL11 0x0008
+#  endif
+#  define TIMER_STATUS_INTR   0x000F000F
+#else
+#  define TIMER_STATUS_INTR   0x0007	/* any timer interrupt */
+#endif
+
+#define TIMER_STATUS_TOVF0  0x0010	/* timer 0 overflow error */
+#define TIMER_STATUS_TOVF1  0x0020
+#define TIMER_STATUS_TOVF2  0x0040
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+#  define TIMER_STATUS_TOVF3  0x00000080
+#  define TIMER_STATUS_TOVF4  0x00100000
+#  define TIMER_STATUS_TOVF5  0x00200000
+#  define TIMER_STATUS_TOVF6  0x00400000
+#  define TIMER_STATUS_TOVF7  0x00800000
+#  if (MAX_BLACKFIN_GPTIMERS > 8)
+#    define TIMER_STATUS_TOVF8   0x0010
+#    define TIMER_STATUS_TOVF9   0x0020
+#    define TIMER_STATUS_TOVF10  0x0040
+#    define TIMER_STATUS_TOVF11  0x0080
+#  endif
+#  define TIMER_STATUS_OFLOW  0x00F000F0
+#else
+#  define TIMER_STATUS_OFLOW  0x0070	/* any timer overflow */
+#endif
+
+/*
+** Timer Slave Enable Status : write 1 to clear
+*/
+#define TIMER_STATUS_TRUN0  0x1000
+#define TIMER_STATUS_TRUN1  0x2000
+#define TIMER_STATUS_TRUN2  0x4000
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+#  define TIMER_STATUS_TRUN3  0x00008000
+#  define TIMER_STATUS_TRUN4  0x10000000
+#  define TIMER_STATUS_TRUN5  0x20000000
+#  define TIMER_STATUS_TRUN6  0x40000000
+#  define TIMER_STATUS_TRUN7  0x80000000
+#  define TIMER_STATUS_TRUN   0xF000F000
+#  if (MAX_BLACKFIN_GPTIMERS > 8)
+#    define TIMER_STATUS_TRUN8  0x1000
+#    define TIMER_STATUS_TRUN9  0x2000
+#    define TIMER_STATUS_TRUN10 0x4000
+#    define TIMER_STATUS_TRUN11 0x8000
+#  endif
+#else
+#  define TIMER_STATUS_TRUN   0x7000
+#endif
+
+/*******************************************************************************
+*	GP_TIMER API's
+*******************************************************************************/
+
+void  set_gptimer_pwidth    (int timer_id, int width);
+int   get_gptimer_pwidth    (int timer_id);
+void  set_gptimer_period    (int timer_id, int period);
+int   get_gptimer_period    (int timer_id);
+int   get_gptimer_count     (int timer_id);
+short get_gptimer_intr      (int timer_id);
+void  set_gptimer_config    (int timer_id, short config);
+short get_gptimer_config    (int timer_id);
+void  set_gptimer_pulse_hi  (int timer_id);
+void  clear_gptimer_pulse_hi(int timer_id);
+void  enable_gptimers       (short mask);
+void  disable_gptimers      (short mask);
+short get_enabled_timers    (void);
+int   get_gptimer_status    (int octet);
+void  set_gptimer_status    (int octet, int value);
+
+#endif
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
new file mode 100644
index 0000000..e37f816
--- /dev/null
+++ b/include/asm-blackfin/bfin-global.h
@@ -0,0 +1,120 @@
+/*
+ * File:         include/asm-blackfin/bfin-global.h
+ * Based on:
+ * Author: *
+ * Created:
+ * Description:  Global extern defines for blackfin
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _BFIN_GLOBAL_H_
+#define _BFIN_GLOBAL_H_
+
+#ifndef __ASSEMBLY__
+
+#include <asm-generic/sections.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_DMA_UNCACHED_2M)
+# define DMA_UNCACHED_REGION (2 * 1024 * 1024)
+#elif defined(CONFIG_DMA_UNCACHED_1M)
+# define DMA_UNCACHED_REGION (1024 * 1024)
+#else
+# define DMA_UNCACHED_REGION (0)
+#endif
+
+extern unsigned long get_cclk(void);
+extern unsigned long get_sclk(void);
+
+extern void dump_thread(struct pt_regs *regs, struct user *dump);
+extern void dump_bfin_regs(struct pt_regs *fp, void *retaddr);
+extern void dump_bfin_trace_buffer(void);
+
+extern int init_arch_irq(void);
+extern void bfin_reset(void);
+extern void _cplb_hdr(void);
+/* Blackfin cache functions */
+extern void bfin_icache_init(void);
+extern void bfin_dcache_init(void);
+extern int read_iloc(void);
+extern int bfin_console_init(void);
+extern asmlinkage void lower_to_irq14(void);
+extern void init_dma(void);
+extern void program_IAR(void);
+extern void evt14_softirq(void);
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type);
+
+extern void *l1_data_A_sram_alloc(size_t);
+extern void *l1_data_B_sram_alloc(size_t);
+extern void *l1_inst_sram_alloc(size_t);
+extern void *l1_data_sram_alloc(size_t);
+extern void *l1_data_sram_zalloc(size_t);
+extern int l1_data_A_sram_free(const void*);
+extern int l1_data_B_sram_free(const void*);
+extern int l1_inst_sram_free(const void*);
+extern int l1_data_sram_free(const void*);
+extern int sram_free(const void*);
+
+#define L1_INST_SRAM		0x00000001
+#define L1_DATA_A_SRAM		0x00000002
+#define L1_DATA_B_SRAM		0x00000004
+#define L1_DATA_SRAM		0x00000006
+extern void *sram_alloc_with_lsl(size_t, unsigned long);
+extern int sram_free_with_lsl(const void*);
+
+extern void led_on(int);
+extern void led_off(int);
+extern void led_toggle(int);
+extern void led_disp_num(int);
+extern void led_toggle_num(int);
+extern void init_leds(void);
+
+extern char *bfin_board_name __attribute__ ((weak));
+extern unsigned long wall_jiffies;
+extern unsigned long ipdt_table[];
+extern unsigned long dpdt_table[];
+extern unsigned long icplb_table[];
+extern unsigned long dcplb_table[];
+
+extern unsigned long ipdt_swapcount_table[];
+extern unsigned long dpdt_swapcount_table[];
+
+extern unsigned long table_start, table_end;
+
+extern struct file_operations dpmc_fops;
+extern char _start;
+extern unsigned long _ramstart, _ramend, _rambase;
+extern unsigned long memory_start, memory_end, physical_mem_end;
+extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
+    _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _ebss_b_l1[];
+
+#ifdef CONFIG_MTD_UCLINUX
+extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
+#endif
+
+#endif
+
+#endif				/* _BLACKFIN_H_ */
diff --git a/include/asm-blackfin/bfin5xx_spi.h b/include/asm-blackfin/bfin5xx_spi.h
new file mode 100644
index 0000000..95c1c95
--- /dev/null
+++ b/include/asm-blackfin/bfin5xx_spi.h
@@ -0,0 +1,170 @@
+/************************************************************
+*
+* Copyright (C) 2004, Analog Devices. All Rights Reserved
+*
+* FILE bfin5xx_spi.h
+* PROGRAMMER(S): Luke Yang (Analog Devices Inc.)
+*
+*
+* DATE OF CREATION: March. 10th 2006
+*
+* SYNOPSIS:
+*
+* DESCRIPTION: header file for SPI controller driver for Blackfin5xx.
+**************************************************************
+
+* MODIFICATION HISTORY:
+* March 10, 2006  bfin5xx_spi.h Created. (Luke Yang)
+
+************************************************************/
+
+#ifndef _SPI_CHANNEL_H_
+#define _SPI_CHANNEL_H_
+
+#define SPI0_REGBASE       0xffc00500
+
+#define SPI_READ              0
+#define SPI_WRITE             1
+
+#define SPI_CTRL_OFF            0x0
+#define SPI_FLAG_OFF            0x4
+#define SPI_STAT_OFF            0x8
+#define SPI_TXBUFF_OFF          0xc
+#define SPI_RXBUFF_OFF          0x10
+#define SPI_BAUD_OFF            0x14
+#define SPI_SHAW_OFF            0x18
+
+#define CMD_SPI_OUT_ENABLE    1
+#define CMD_SPI_SET_BAUDRATE  2
+#define CMD_SPI_SET_POLAR     3
+#define CMD_SPI_SET_PHASE     4
+#define CMD_SPI_SET_MASTER    5
+#define CMD_SPI_SET_SENDOPT   6
+#define CMD_SPI_SET_RECVOPT   7
+#define CMD_SPI_SET_ORDER     8
+#define CMD_SPI_SET_LENGTH16  9
+#define CMD_SPI_GET_STAT      11
+#define CMD_SPI_GET_CFG       12
+#define CMD_SPI_SET_CSAVAIL   13
+#define CMD_SPI_SET_CSHIGH    14	/* CS unavail */
+#define CMD_SPI_SET_CSLOW     15	/* CS avail */
+#define CMD_SPI_MISO_ENABLE   16
+#define CMD_SPI_SET_CSENABLE  17
+#define CMD_SPI_SET_CSDISABLE 18
+
+#define CMD_SPI_SET_TRIGGER_MODE  19
+#define CMD_SPI_SET_TRIGGER_SENSE 20
+#define CMD_SPI_SET_TRIGGER_EDGE  21
+#define CMD_SPI_SET_TRIGGER_LEVEL 22
+
+#define CMD_SPI_SET_TIME_SPS 	  23
+#define CMD_SPI_SET_TIME_SAMPLES  24
+#define CMD_SPI_GET_SYSTEMCLOCK   25
+
+#define CMD_SPI_SET_WRITECONTINUOUS     26
+#define CMD_SPI_SET_SKFS    		27
+
+#define CMD_SPI_GET_ALLCONFIG 32	/* For debug */
+
+#define SPI_DEFAULT_BARD    0x0100
+
+#define SPI0_IRQ_NUM        IRQ_SPI
+#define SPI_ERR_TRIG	   -1
+
+#define BIT_CTL_ENABLE      0x4000
+#define BIT_CTL_OPENDRAIN   0x2000
+#define BIT_CTL_MASTER      0x1000
+#define BIT_CTL_POLAR       0x0800
+#define BIT_CTL_PHASE       0x0400
+#define BIT_CTL_BITORDER    0x0200
+#define BIT_CTL_WORDSIZE    0x0100
+#define BIT_CTL_MISOENABLE  0x0020
+#define BIT_CTL_RXMOD       0x0000
+#define BIT_CTL_TXMOD       0x0001
+#define BIT_CTL_TIMOD_DMA_TX 0x0003
+#define BIT_CTL_TIMOD_DMA_RX 0x0002
+#define BIT_CTL_SENDOPT     0x0004
+#define BIT_CTL_TIMOD       0x0003
+
+#define BIT_STAT_SPIF       0x0001
+#define BIT_STAT_MODF       0x0002
+#define BIT_STAT_TXE        0x0004
+#define BIT_STAT_TXS        0x0008
+#define BIT_STAT_RBSY       0x0010
+#define BIT_STAT_RXS        0x0020
+#define BIT_STAT_TXCOL      0x0040
+#define BIT_STAT_CLR        0xFFFF
+
+#define BIT_STU_SENDOVER    0x0001
+#define BIT_STU_RECVFULL    0x0020
+
+#define CFG_SPI_ENABLE      1
+#define CFG_SPI_DISABLE     0
+
+#define CFG_SPI_OUTENABLE   1
+#define CFG_SPI_OUTDISABLE  0
+
+#define CFG_SPI_ACTLOW      1
+#define CFG_SPI_ACTHIGH     0
+
+#define CFG_SPI_PHASESTART  1
+#define CFG_SPI_PHASEMID    0
+
+#define CFG_SPI_MASTER      1
+#define CFG_SPI_SLAVE       0
+
+#define CFG_SPI_SENELAST    0
+#define CFG_SPI_SENDZERO    1
+
+#define CFG_SPI_RCVFLUSH    1
+#define CFG_SPI_RCVDISCARD  0
+
+#define CFG_SPI_LSBFIRST    1
+#define CFG_SPI_MSBFIRST    0
+
+#define CFG_SPI_WORDSIZE16  1
+#define CFG_SPI_WORDSIZE8   0
+
+#define CFG_SPI_MISOENABLE   1
+#define CFG_SPI_MISODISABLE  0
+
+#define CFG_SPI_READ      0x00
+#define CFG_SPI_WRITE     0x01
+#define CFG_SPI_DMAREAD   0x02
+#define CFG_SPI_DMAWRITE  0x03
+
+#define CFG_SPI_CSCLEARALL  0
+#define CFG_SPI_CHIPSEL1    1
+#define CFG_SPI_CHIPSEL2    2
+#define CFG_SPI_CHIPSEL3    3
+#define CFG_SPI_CHIPSEL4    4
+#define CFG_SPI_CHIPSEL5    5
+#define CFG_SPI_CHIPSEL6    6
+#define CFG_SPI_CHIPSEL7    7
+
+#define CFG_SPI_CS1VALUE    1
+#define CFG_SPI_CS2VALUE    2
+#define CFG_SPI_CS3VALUE    3
+#define CFG_SPI_CS4VALUE    4
+#define CFG_SPI_CS5VALUE    5
+#define CFG_SPI_CS6VALUE    6
+#define CFG_SPI_CS7VALUE    7
+
+/* device.platform_data for SSP controller devices */
+struct bfin5xx_spi_master {
+	u16 num_chipselect;
+	u8 enable_dma;
+};
+
+/* spi_board_info.controller_data for SPI slave devices,
+ * copied to spi_device.platform_data ... mostly for dma tuning
+ */
+struct bfin5xx_spi_chip {
+	u16 ctl_reg;
+	u8 enable_dma;
+	u8 bits_per_word;
+	u8 cs_change_per_word;
+	u8 cs_chg_udelay;
+};
+
+#endif /* _SPI_CHANNEL_H_ */
diff --git a/include/asm-blackfin/bfin_simple_timer.h b/include/asm-blackfin/bfin_simple_timer.h
new file mode 100644
index 0000000..fccbb59
--- /dev/null
+++ b/include/asm-blackfin/bfin_simple_timer.h
@@ -0,0 +1,13 @@
+#ifndef _bfin_simple_timer_h_
+#define _bfin_simple_timer_h_
+
+#include <linux/ioctl.h>
+
+#define BFIN_SIMPLE_TIMER_IOCTL_MAGIC 't'
+
+#define BFIN_SIMPLE_TIMER_SET_PERIOD _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  2)
+#define BFIN_SIMPLE_TIMER_START      _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  6)
+#define BFIN_SIMPLE_TIMER_STOP       _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC,  8)
+#define BFIN_SIMPLE_TIMER_READ       _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 10)
+
+#endif
diff --git a/include/asm-blackfin/bfin_sport.h b/include/asm-blackfin/bfin_sport.h
new file mode 100644
index 0000000..c76ed8d
--- /dev/null
+++ b/include/asm-blackfin/bfin_sport.h
@@ -0,0 +1,175 @@
+/*
+ * File:         include/asm-blackfin/bfin_sport.h
+ * Based on:
+ * Author:       Roy Huang (roy.huang@analog.com)
+ *
+ * Created:      Thu Aug. 24 2006
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __BFIN_SPORT_H__
+#define __BFIN_SPORT_H__
+
+#define SPORT_MAJOR	237
+#define SPORT_NR_DEVS	2
+
+/* Sport mode: it can be set to TDM, i2s or others */
+#define NORM_MODE	0x0
+#define TDM_MODE	0x1
+#define I2S_MODE	0x2
+
+/* Data format, normal, a-law or u-law */
+#define NORM_FORMAT	0x0
+#define ALAW_FORMAT	0x2
+#define ULAW_FORMAT	0x3
+struct sport_register;
+
+/* Function driver which use sport must initialize the structure */
+struct sport_config {
+	/*TDM (multichannels), I2S or other mode */
+	unsigned int mode:3;
+
+	/* if TDM mode is selected, channels must be set */
+	int channels;		/* Must be in 8 units */
+	unsigned int frame_delay:4;	/* Delay between frame sync pulse and first bit */
+
+	/* I2S mode */
+	unsigned int right_first:1;	/* Right stereo channel first */
+
+	/* In mormal mode, the following item need to be set */
+	unsigned int lsb_first:1;	/* order of transmit or receive data */
+	unsigned int fsync:1;	/* Frame sync required */
+	unsigned int data_indep:1;	/* data independent frame sync generated */
+	unsigned int act_low:1;	/* Active low TFS */
+	unsigned int late_fsync:1;	/* Late frame sync */
+	unsigned int tckfe:1;
+	unsigned int sec_en:1;	/* Secondary side enabled */
+
+	/* Choose clock source */
+	unsigned int int_clk:1;	/* Internal or external clock */
+
+	/* If external clock is used, the following fields are ignored */
+	int serial_clk;
+	int fsync_clk;
+
+	unsigned int data_format:2;	/*Normal, u-law or a-law */
+
+	int word_len;		/* How length of the word in bits, 3-32 bits */
+	int dma_enabled;
+};
+
+struct sport_register {
+	unsigned short tcr1;
+	unsigned short reserved0;
+	unsigned short tcr2;
+	unsigned short reserved1;
+	unsigned short tclkdiv;
+	unsigned short reserved2;
+	unsigned short tfsdiv;
+	unsigned short reserved3;
+	unsigned long tx;
+	unsigned long reserved_l0;
+	unsigned long rx;
+	unsigned long reserved_l1;
+	unsigned short rcr1;
+	unsigned short reserved4;
+	unsigned short rcr2;
+	unsigned short reserved5;
+	unsigned short rclkdiv;
+	unsigned short reserved6;
+	unsigned short rfsdiv;
+	unsigned short reserved7;
+	unsigned short stat;
+	unsigned short reserved8;
+	unsigned short chnl;
+	unsigned short reserved9;
+	unsigned short mcmc1;
+	unsigned short reserved10;
+	unsigned short mcmc2;
+	unsigned short reserved11;
+	unsigned long mtcs0;
+	unsigned long mtcs1;
+	unsigned long mtcs2;
+	unsigned long mtcs3;
+	unsigned long mrcs0;
+	unsigned long mrcs1;
+	unsigned long mrcs2;
+	unsigned long mrcs3;
+};
+
+#define SPORT_IOC_MAGIC		'P'
+#define SPORT_IOC_CONFIG	_IOWR('P', 0x01, struct sport_config)
+
+/* Test purpose */
+#define ENABLE_AD73311		_IOWR('P', 0x02, int)
+
+struct sport_dev {
+	struct cdev cdev;	/* Char device structure */
+
+	int sport_num;
+
+	int dma_rx_chan;
+	int dma_tx_chan;
+
+	int rx_irq;
+	unsigned char *rx_buf;	/* Buffer store the received data */
+	int rx_len;		/* How many bytes will be received */
+	int rx_received;	/* How many bytes has been received */
+
+	int tx_irq;
+	const unsigned char *tx_buf;
+	int tx_len;
+	int tx_sent;
+
+	int sport_err_irq;
+
+	struct mutex mutex;	/* mutual exclusion semaphore */
+	struct task_struct *task;
+
+	wait_queue_head_t waitq;
+	int	wait_con;
+	struct sport_register *regs;
+	struct sport_config config;
+};
+
+#define SPORT_TCR1	0
+#define	SPORT_TCR2	1
+#define	SPORT_TCLKDIV	2
+#define	SPORT_TFSDIV	3
+#define	SPORT_RCR1	8
+#define	SPORT_RCR2	9
+#define SPORT_RCLKDIV	10
+#define	SPORT_RFSDIV	11
+#define SPORT_CHANNEL	13
+#define SPORT_MCMC1	14
+#define SPORT_MCMC2	15
+#define SPORT_MTCS0	16
+#define SPORT_MTCS1	17
+#define SPORT_MTCS2	18
+#define SPORT_MTCS3	19
+#define SPORT_MRCS0	20
+#define SPORT_MRCS1	21
+#define SPORT_MRCS2	22
+#define SPORT_MRCS3	23
+
+#endif				/*__BFIN_SPORT_H__*/
diff --git a/include/asm-blackfin/bitops.h b/include/asm-blackfin/bitops.h
new file mode 100644
index 0000000..27c2d0e
--- /dev/null
+++ b/include/asm-blackfin/bitops.h
@@ -0,0 +1,213 @@
+#ifndef _BLACKFIN_BITOPS_H
+#define _BLACKFIN_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+#include <linux/compiler.h>
+#include <asm/byteorder.h>	/* swab32 */
+#include <asm/system.h>		/* save_flags */
+
+#ifdef __KERNEL__
+
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffz.h>
+
+static __inline__ void set_bit(int nr, volatile unsigned long *addr)
+{
+	int *a = (int *)addr;
+	int mask;
+	unsigned long flags;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	local_irq_save(flags);
+	*a |= mask;
+	local_irq_restore(flags);
+}
+
+static __inline__ void __set_bit(int nr, volatile unsigned long *addr)
+{
+	int *a = (int *)addr;
+	int mask;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*a |= mask;
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit()	barrier()
+#define smp_mb__after_clear_bit()	barrier()
+
+static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
+{
+	int *a = (int *)addr;
+	int mask;
+	unsigned long flags;
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	local_irq_save(flags);
+	*a &= ~mask;
+	local_irq_restore(flags);
+}
+
+static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	int *a = (int *)addr;
+	int mask;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*a &= ~mask;
+}
+
+static __inline__ void change_bit(int nr, volatile unsigned long *addr)
+{
+	int mask, flags;
+	unsigned long *ADDR = (unsigned long *)addr;
+
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	local_irq_save(flags);
+	*ADDR ^= mask;
+	local_irq_restore(flags);
+}
+
+static __inline__ void __change_bit(int nr, volatile unsigned long *addr)
+{
+	int mask;
+	unsigned long *ADDR = (unsigned long *)addr;
+
+	ADDR += nr >> 5;
+	mask = 1 << (nr & 31);
+	*ADDR ^= mask;
+}
+
+static __inline__ int test_and_set_bit(int nr, void *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+	unsigned long flags;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	local_irq_save(flags);
+	retval = (mask & *a) != 0;
+	*a |= mask;
+	local_irq_restore(flags);
+
+	return retval;
+}
+
+static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a |= mask;
+	return retval;
+}
+
+static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+	unsigned long flags;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	local_irq_save(flags);
+	retval = (mask & *a) != 0;
+	*a &= ~mask;
+	local_irq_restore(flags);
+
+	return retval;
+}
+
+static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a &= ~mask;
+	return retval;
+}
+
+static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+	unsigned long flags;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	local_irq_save(flags);
+	retval = (mask & *a) != 0;
+	*a ^= mask;
+	local_irq_restore(flags);
+	return retval;
+}
+
+static __inline__ int __test_and_change_bit(int nr,
+					    volatile unsigned long *addr)
+{
+	int mask, retval;
+	volatile unsigned int *a = (volatile unsigned int *)addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a ^= mask;
+	return retval;
+}
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+static __inline__ int __constant_test_bit(int nr, const void *addr)
+{
+	return ((1UL << (nr & 31)) &
+		(((const volatile unsigned int *)addr)[nr >> 5])) != 0;
+}
+
+static __inline__ int __test_bit(int nr, const void *addr)
+{
+	int *a = (int *)addr;
+	int mask;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	return ((mask & *a) != 0);
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)))
+
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/hweight.h>
+
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+
+#include <asm-generic/bitops/minix.h>
+
+#endif				/* __KERNEL__ */
+
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+
+#endif				/* _BLACKFIN_BITOPS_H */
diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h
new file mode 100644
index 0000000..14e58de
--- /dev/null
+++ b/include/asm-blackfin/blackfin.h
@@ -0,0 +1,81 @@
+/*
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _BLACKFIN_H_
+#define _BLACKFIN_H_
+
+#include <asm/macros.h>
+#include <asm/mach/blackfin.h>
+#include <asm/bfin-global.h>
+
+#ifndef __ASSEMBLY__
+
+/* SSYNC implementation for C file */
+#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+	int _tmp;
+	__asm__ __volatile__ ("cli %0;\n\t"
+			"nop;nop;\n\t"
+			"ssync;\n\t"
+			"sti %0;\n\t"
+			:"=d"(_tmp):);
+}
+#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+	int _tmp;
+	__asm__ __volatile__ ("cli %0;\n\t"
+			"ssync;\n\t"
+			"sti %0;\n\t"
+			:"=d"(_tmp):);
+}
+#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+	__builtin_bfin_ssync();
+}
+#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+	__asm__ __volatile__ ("ssync;\n\t");
+}
+#endif
+
+/* CSYNC implementation for C file */
+#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+	int _tmp;
+	__asm__ __volatile__ ("cli %0;\n\t"
+			"nop;nop;\n\t"
+			"csync;\n\t"
+			"sti %0;\n\t"
+			:"=d"(_tmp):);
+}
+#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+	int _tmp;
+	__asm__ __volatile__ ("cli %0;\n\t"
+			"csync;\n\t"
+			"sti %0;\n\t"
+			:"=d"(_tmp):);
+}
+#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+	__builtin_bfin_csync();
+}
+#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+	__asm__ __volatile__ ("csync;\n\t");
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif				/* _BLACKFIN_H_ */
diff --git a/include/asm-blackfin/bug.h b/include/asm-blackfin/bug.h
new file mode 100644
index 0000000..41e53b2
--- /dev/null
+++ b/include/asm-blackfin/bug.h
@@ -0,0 +1,4 @@
+#ifndef _BLACKFIN_BUG_H
+#define _BLACKFIN_BUG_H
+#include <asm-generic/bug.h>
+#endif
diff --git a/include/asm-blackfin/bugs.h b/include/asm-blackfin/bugs.h
new file mode 100644
index 0000000..9093c9c
--- /dev/null
+++ b/include/asm-blackfin/bugs.h
@@ -0,0 +1,16 @@
+/*
+ *  include/asm-blackfin/bugs.h
+ *
+ *  Copyright (C) 1994  Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *	void check_bugs(void);
+ */
+
+static void check_bugs(void)
+{
+}
diff --git a/include/asm-blackfin/byteorder.h b/include/asm-blackfin/byteorder.h
new file mode 100644
index 0000000..6a673d4
--- /dev/null
+++ b/include/asm-blackfin/byteorder.h
@@ -0,0 +1,48 @@
+#ifndef _BLACKFIN_BYTEORDER_H
+#define _BLACKFIN_BYTEORDER_H
+
+#include <asm/types.h>
+#include <linux/compiler.h>
+
+#ifdef __GNUC__
+
+static __inline__ __attribute_const__ __u32 ___arch__swahb32(__u32 xx)
+{
+	__u32 tmp;
+	__asm__("%1 = %0 >> 8 (V);\n\t"
+		"%0 = %0 << 8 (V);\n\t"
+		"%0 = %0 | %1;\n\t"
+		: "+d"(xx), "=&d"(tmp));
+	return xx;
+}
+
+static __inline__ __attribute_const__ __u32 ___arch__swahw32(__u32 xx)
+{
+	__u32 rv;
+	__asm__("%0 = PACK(%1.L, %1.H);\n\t": "=d"(rv): "d"(xx));
+	return rv;
+}
+
+#define __arch__swahb32(x) ___arch__swahb32(x)
+#define __arch__swahw32(x) ___arch__swahw32(x)
+#define __arch__swab32(x) ___arch__swahb32(___arch__swahw32(x))
+
+static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 xx)
+{
+	__u32 xw = xx;
+	__asm__("%0 <<= 8;\n	%0.L = %0.L + %0.H (NS);\n": "+d"(xw));
+	return (__u16)xw;
+}
+
+#define __arch__swab16(x) ___arch__swab16(x)
+
+#endif
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#include <linux/byteorder/little_endian.h>
+
+#endif				/* _BLACKFIN_BYTEORDER_H */
diff --git a/include/asm-blackfin/cache.h b/include/asm-blackfin/cache.h
new file mode 100644
index 0000000..023d721
--- /dev/null
+++ b/include/asm-blackfin/cache.h
@@ -0,0 +1,29 @@
+/*
+ * include/asm-blackfin/cache.h
+ */
+#ifndef __ARCH_BLACKFIN_CACHE_H
+#define __ARCH_BLACKFIN_CACHE_H
+
+/*
+ * Bytes per L1 cache line
+ * Blackfin loads 32 bytes for cache
+ */
+#define L1_CACHE_SHIFT	5
+#define L1_CACHE_BYTES	(1 << L1_CACHE_SHIFT)
+#define SMP_CACHE_BYTES	L1_CACHE_BYTES
+
+/*
+ * Put cacheline_aliged data to L1 data memory
+ */
+#ifdef CONFIG_CACHELINE_ALIGNED_L1
+#define __cacheline_aligned				\
+	  __attribute__((__aligned__(L1_CACHE_BYTES),	\
+		__section__(".data_l1.cacheline_aligned")))
+#endif
+
+/*
+ * largest L1 which this arch supports
+ */
+#define L1_CACHE_SHIFT_MAX	5
+
+#endif
diff --git a/include/asm-blackfin/cacheflush.h b/include/asm-blackfin/cacheflush.h
new file mode 100644
index 0000000..e5e000d
--- /dev/null
+++ b/include/asm-blackfin/cacheflush.h
@@ -0,0 +1,90 @@
+/*
+ * File:         include/asm-blackfin/cacheflush.h
+ * Based on:	 include/asm-m68knommu/cacheflush.h
+ * Author:       LG Soft India
+ *               Copyright (C) 2004 Analog Devices Inc.
+ * Created:      Tue Sep 21 2004
+ * Description:  Blackfin low-level cache routines adapted from the i386
+ * 		 and PPC versions by Greg Ungerer (gerg@snapgear.com)
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_CACHEFLUSH_H
+#define _BLACKFIN_CACHEFLUSH_H
+
+#include <asm/cplb.h>
+
+extern void blackfin_icache_dcache_flush_range(unsigned int, unsigned int);
+extern void blackfin_icache_flush_range(unsigned int, unsigned int);
+extern void blackfin_dcache_flush_range(unsigned int, unsigned int);
+extern void blackfin_dcache_invalidate_range(unsigned int, unsigned int);
+extern void blackfin_dflush_page(void *);
+
+#define flush_dcache_mmap_lock(mapping)		do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)	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)		do { } while (0)
+#define flush_cache_vmap(start, end)		do { } while (0)
+#define flush_cache_vunmap(start, end)		do { } while (0)
+
+static inline void flush_icache_range(unsigned start, unsigned end)
+{
+#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_CACHE)
+
+# if defined(CONFIG_BLKFIN_WT)
+	blackfin_icache_flush_range((start), (end));
+# else
+	blackfin_icache_dcache_flush_range((start), (end));
+# endif
+
+#else
+
+# if defined(CONFIG_BLKFIN_CACHE)
+	blackfin_icache_flush_range((start), (end));
+# endif
+# if defined(CONFIG_BLKFIN_DCACHE)
+	blackfin_dcache_flush_range((start), (end));
+# endif
+
+#endif
+}
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+do { memcpy(dst, src, len); \
+     flush_icache_range ((unsigned) (dst), (unsigned) (dst) + (len)); \
+} while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len)	memcpy(dst, src, len)
+
+#if defined(CONFIG_BLKFIN_DCACHE)
+# define invalidate_dcache_range(start,end)	blackfin_dcache_invalidate_range((start), (end))
+#else
+# define invalidate_dcache_range(start,end)	do { } while (0)
+#endif
+#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_WB)
+# define flush_dcache_range(start,end)		blackfin_dcache_flush_range((start), (end))
+# define flush_dcache_page(page)			blackfin_dflush_page(page_address(page))
+#else
+# define flush_dcache_range(start,end)		do { } while (0)
+# define flush_dcache_page(page)			do { } while (0)
+#endif
+
+#endif				/* _BLACKFIN_CACHEFLUSH_H */
diff --git a/include/asm-blackfin/checksum.h b/include/asm-blackfin/checksum.h
new file mode 100644
index 0000000..2638f25
--- /dev/null
+++ b/include/asm-blackfin/checksum.h
@@ -0,0 +1,101 @@
+#ifndef _BFIN_CHECKSUM_H
+#define _BFIN_CHECKSUM_H
+
+/*
+ * MODIFIED FOR BFIN April 30, 2001 akbar.hussain@lineo.com
+ *
+ * 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
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+			       int len, int sum);
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern unsigned int csum_partial_copy_from_user(const unsigned char *src,
+						unsigned char *dst, int len,
+						int sum, int *csum_err);
+
+#define csum_partial_copy_nocheck(src, dst, len, sum)	\
+	csum_partial_copy((src), (dst), (len), (sum))
+
+unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl);
+
+/*
+ *	Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+	while (sum >> 16)
+		sum = (sum & 0xffff) + (sum >> 16);
+	return ((~(sum << 16)) >> 16);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
+		   unsigned short proto, unsigned int sum)
+{
+
+	__asm__ ("%0 = %0 + %1;\n\t"
+		 "CC = AC0;\n\t"
+		 "if !CC jump 4;\n\t"
+		 "%0 = %0 + %4;\n\t"
+		 "%0 = %0 + %2;\n\t"
+		 "CC = AC0;\n\t"
+                 "if !CC jump 4;\n\t"
+                 "%0 = %0 + %4;\n\t"
+ 		 "%0 = %0 + %3;\n\t"
+		 "CC = AC0;\n\t"
+                 "if !CC jump 4;\n\t"
+                 "%0 = %0 + %4;\n\t"
+                 "NOP;\n\t"
+ 		 : "=d" (sum)
+		 : "d" (daddr), "d" (saddr), "d" ((ntohs(len)<<16)+proto*256), "d" (1), "0"(sum));
+
+	return (sum);
+}
+
+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
+ */
+
+extern unsigned short ip_compute_csum(const unsigned char *buff, int len);
+
+#endif				/* _BFIN_CHECKSUM_H */
diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
new file mode 100644
index 0000000..e0dd56b
--- /dev/null
+++ b/include/asm-blackfin/cplb.h
@@ -0,0 +1,51 @@
+/************************************************************************
+ *
+ * cplb.h
+ *
+ * (c) Copyright 2002-2003 Analog Devices, Inc.  All rights reserved.
+ *
+ ************************************************************************/
+
+/* Defines necessary for cplb initialisation routines. */
+
+#ifndef _CPLB_H
+#define _CPLB_H
+
+# include <asm/blackfin.h>
+
+#define CPLB_ENABLE_ICACHE_P	0
+#define CPLB_ENABLE_DCACHE_P	1
+#define CPLB_ENABLE_DCACHE2_P	2
+#define CPLB_ENABLE_CPLBS_P	3	/* Deprecated! */
+#define CPLB_ENABLE_ICPLBS_P	4
+#define CPLB_ENABLE_DCPLBS_P	5
+
+#define CPLB_ENABLE_ICACHE	(1<<CPLB_ENABLE_ICACHE_P)
+#define CPLB_ENABLE_DCACHE	(1<<CPLB_ENABLE_DCACHE_P)
+#define CPLB_ENABLE_DCACHE2	(1<<CPLB_ENABLE_DCACHE2_P)
+#define CPLB_ENABLE_CPLBS	(1<<CPLB_ENABLE_CPLBS_P)
+#define CPLB_ENABLE_ICPLBS	(1<<CPLB_ENABLE_ICPLBS_P)
+#define CPLB_ENABLE_DCPLBS	(1<<CPLB_ENABLE_DCPLBS_P)
+#define CPLB_ENABLE_ANY_CPLBS	CPLB_ENABLE_CPLBS | \
+				CPLB_ENABLE_ICPLBS | \
+				CPLB_ENABLE_DCPLBS
+
+#define CPLB_RELOADED		0x0000
+#define CPLB_NO_UNLOCKED	0x0001
+#define CPLB_NO_ADDR_MATCH	0x0002
+#define CPLB_PROT_VIOL		0x0003
+#define CPLB_UNKNOWN_ERR	0x0004
+
+#define CPLB_DEF_CACHE		CPLB_L1_CHBL | CPLB_WT
+#define CPLB_CACHE_ENABLED	CPLB_L1_CHBL | CPLB_DIRTY
+
+#define CPLB_ALL_ACCESS	CPLB_SUPV_WR | CPLB_USER_RD | CPLB_USER_WR
+
+#define CPLB_I_PAGE_MGMT	CPLB_LOCK | CPLB_VALID
+#define CPLB_D_PAGE_MGMT	CPLB_LOCK | CPLB_ALL_ACCESS | CPLB_VALID
+#define CPLB_DNOCACHE		CPLB_ALL_ACCESS | CPLB_VALID
+#define CPLB_DDOCACHE		CPLB_DNOCACHE | CPLB_DEF_CACHE
+#define CPLB_INOCACHE   	CPLB_USER_RD | CPLB_VALID
+#define CPLB_IDOCACHE   	CPLB_INOCACHE | CPLB_L1_CHBL
+
+#endif				/* _CPLB_H */
diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
new file mode 100644
index 0000000..3bad2d1
--- /dev/null
+++ b/include/asm-blackfin/cplbinit.h
@@ -0,0 +1,203 @@
+/*
+ * File:         include/asm-blackfin/cplbinit.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+
+#define INITIAL_T 0x1
+#define SWITCH_T  0x2
+#define I_CPLB    0x4
+#define D_CPLB    0x8
+
+#define IN_KERNEL 1
+
+enum
+{ZERO_P, L1I_MEM, L1D_MEM, SDRAM_KERN , SDRAM_RAM_MTD, SDRAM_DMAZ, RES_MEM, ASYNC_MEM, L2_MEM};
+
+struct cplb_desc {
+	u32 start; /* start address */
+	u32 end; /* end address */
+	u32 psize; /* prefered size if any otherwise 1MB or 4MB*/
+	u16 attr;/* attributes */
+	u16 i_conf;/* I-CPLB DATA */
+	u16 d_conf;/* D-CPLB DATA */
+	u16 valid;/* valid */
+	const s8 name[30];/* name */
+};
+
+struct cplb_tab {
+  u_long *tab;
+	u16 pos;
+	u16 size;
+};
+
+u_long icplb_table[MAX_CPLBS+1];
+u_long dcplb_table[MAX_CPLBS+1];
+
+/* Till here we are discussing about the static memory management model.
+ * However, the operating envoronments commonly define more CPLB
+ * descriptors to cover the entire addressable memory than will fit into
+ * the available on-chip 16 CPLB MMRs. When this happens, the below table
+ * will be used which will hold all the potentially required CPLB descriptors
+ *
+ * This is how Page descriptor Table is implemented in uClinux/Blackfin.
+ */
+
+#ifdef CONFIG_CPLB_SWITCH_TAB_L1
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1]__attribute__((l1_data));
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1]__attribute__((l1_data));
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS]__attribute__((l1_data));
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS]__attribute__((l1_data));
+#endif /* CONFIG_CPLB_INFO */
+
+#else
+
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
+#endif /* CONFIG_CPLB_INFO */
+
+#endif /*CONFIG_CPLB_SWITCH_TAB_L1*/
+
+struct s_cplb {
+	struct cplb_tab init_i;
+	struct cplb_tab init_d;
+	struct cplb_tab switch_i;
+	struct cplb_tab switch_d;
+};
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+static struct cplb_desc cplb_data[] = {
+	{
+		.start = 0,
+		.end = SIZE_4K,
+		.psize = SIZE_4K,
+		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+		.i_conf = SDRAM_OOPS,
+		.d_conf = SDRAM_OOPS,
+#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
+		.valid = 1,
+#else
+		.valid = 0,
+#endif
+		.name = "ZERO Pointer Saveguard",
+	},
+	{
+		.start = L1_CODE_START,
+		.end = L1_CODE_START + L1_CODE_LENGTH,
+		.psize = SIZE_4M,
+		.attr = INITIAL_T | SWITCH_T | I_CPLB,
+		.i_conf = L1_IMEMORY,
+		.d_conf = 0,
+		.valid = 1,
+		.name = "L1 I-Memory",
+	},
+	{
+		.start = L1_DATA_A_START,
+		.end = L1_DATA_B_START + L1_DATA_B_LENGTH,
+		.psize = SIZE_4M,
+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+		.i_conf = 0,
+		.d_conf = L1_DMEMORY,
+#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
+		.valid = 1,
+#else
+		.valid = 0,
+#endif
+		.name = "L1 D-Memory",
+	},
+	{
+		.start = 0,
+		.end = 0,  /* dynamic */
+		.psize = 0,
+		.attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+		.i_conf =  SDRAM_IGENERIC,
+		.d_conf =  SDRAM_DGENERIC,
+		.valid = 1,
+		.name = "SDRAM Kernel",
+	},
+	{
+		.start = 0, /* dynamic */
+		.end = 0, /* dynamic */
+		.psize = 0,
+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+		.i_conf =  SDRAM_IGENERIC,
+		.d_conf =  SDRAM_DNON_CHBL,
+		.valid = 1,
+		.name = "SDRAM RAM MTD",
+	},
+	{
+		.start = 0, /* dynamic */
+		.end = 0,   /* dynamic */
+		.psize = SIZE_1M,
+		.attr = INITIAL_T | SWITCH_T | D_CPLB,
+		.d_conf = SDRAM_DNON_CHBL,
+		.valid = 1,//(DMA_UNCACHED_REGION > 0),
+		.name = "SDRAM Uncached DMA ZONE",
+	},
+	{
+		.start = 0, /* dynamic */
+		.end = 0, /* dynamic */
+		.psize = 0,
+		.attr = SWITCH_T | D_CPLB,
+		.i_conf = 0, /* dynamic */
+		.d_conf = 0, /* dynamic */
+		.valid = 1,
+		.name = "SDRAM Reserved Memory",
+	},
+	{
+		.start = ASYNC_BANK0_BASE,
+		.end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
+		.psize = 0,
+		.attr = SWITCH_T | D_CPLB,
+		.d_conf = SDRAM_EBIU,
+		.valid = 1,
+		.name = "ASYNC Memory",
+	},
+	{
+#if defined(CONFIG_BF561)
+		.start = L2_SRAM,
+		.end = L2_SRAM_END,
+		.psize = SIZE_1M,
+		.attr = SWITCH_T | D_CPLB,
+		.i_conf = L2_MEMORY,
+		.d_conf = L2_MEMORY,
+		.valid = 1,
+#else
+		.valid = 0,
+#endif
+		.name = "L2 Memory",
+	}
+};
+#endif
diff --git a/include/asm-blackfin/cpumask.h b/include/asm-blackfin/cpumask.h
new file mode 100644
index 0000000..b20a8e9
--- /dev/null
+++ b/include/asm-blackfin/cpumask.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_BLACKFIN_CPUMASK_H
+#define _ASM_BLACKFIN_CPUMASK_H
+
+#include <asm-generic/cpumask.h>
+
+#endif				/* _ASM_BLACKFIN_CPUMASK_H */
diff --git a/include/asm-blackfin/cputime.h b/include/asm-blackfin/cputime.h
new file mode 100644
index 0000000..2b19705
--- /dev/null
+++ b/include/asm-blackfin/cputime.h
@@ -0,0 +1,6 @@
+#ifndef __BLACKFIN_CPUTIME_H
+#define __BLACKFIN_CPUTIME_H
+
+#include <asm-generic/cputime.h>
+
+#endif				/* __BLACKFIN_CPUTIME_H */
diff --git a/include/asm-blackfin/current.h b/include/asm-blackfin/current.h
new file mode 100644
index 0000000..31918d2
--- /dev/null
+++ b/include/asm-blackfin/current.h
@@ -0,0 +1,23 @@
+#ifndef _BLACKFIN_CURRENT_H
+#define _BLACKFIN_CURRENT_H
+/*
+ *	current.h
+ *	(C) Copyright 2000, Lineo, David McCullough <davidm@lineo.com>
+ *
+ *	rather than dedicate a register (as the m68k source does), we
+ *	just keep a global,  we should probably just change it all to be
+ *	current and lose _current_task.
+ */
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void) __attribute__ ((__const__));
+static inline struct task_struct *get_current(void)
+{
+	return (current_thread_info()->task);
+}
+
+#define	current	(get_current())
+
+#endif				/* _BLACKFIN_CURRENT_H */
diff --git a/include/asm-blackfin/delay.h b/include/asm-blackfin/delay.h
new file mode 100644
index 0000000..52e7a10
--- /dev/null
+++ b/include/asm-blackfin/delay.h
@@ -0,0 +1,44 @@
+#ifndef _BLACKFIN_DELAY_H
+#define _BLACKFIN_DELAY_H
+
+static inline void __delay(unsigned long loops)
+{
+
+/* FIXME: Currently the assembler doesn't recognize Loop Register Clobbers,
+   uncomment this as soon those are implemented */
+/*
+      __asm__ __volatile__ (  "\t LSETUP (1f,1f) LC0= %0\n\t"
+                              "1:\t NOP;\n\t"
+                              : :"a" (loops)
+                              : "LT0","LB0","LC0");
+
+*/
+
+	__asm__ __volatile__("[--SP] = LC0;\n\t"
+			     "[--SP] = LT0;\n\t"
+			     "[--SP] = LB0;\n\t"
+			     "LSETUP (1f,1f) LC0 = %0;\n\t"
+			     "1:\t NOP;\n\t"
+			     "LB0 = [SP++];\n\t"
+				"LT0 = [SP++];\n\t"
+				"LC0 = [SP++];\n"
+				:
+				:"a" (loops));
+}
+
+#include <linux/param.h>	/* needed for HZ */
+
+/*
+ * Use only for very small delays ( < 1 msec).  Should probably use a
+ * lookup table, really, as the multiplications take much too long with
+ * short delays.  This is a "reasonable" implementation, though (and the
+ * first constant multiplications gets optimized away if the delay is
+ * a constant)
+ */
+static inline void udelay(unsigned long usecs)
+{
+	extern unsigned long loops_per_jiffy;
+	__delay(usecs * loops_per_jiffy / (1000000 / HZ));
+}
+
+#endif				/* defined(_BLACKFIN_DELAY_H) */
diff --git a/include/asm-blackfin/device.h b/include/asm-blackfin/device.h
new file mode 100644
index 0000000..d8f9872
--- /dev/null
+++ b/include/asm-blackfin/device.h
@@ -0,0 +1,7 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ */
+#include <asm-generic/device.h>
+
diff --git a/include/asm-blackfin/div64.h b/include/asm-blackfin/div64.h
new file mode 100644
index 0000000..6cd978c
--- /dev/null
+++ b/include/asm-blackfin/div64.h
@@ -0,0 +1 @@
+#include <asm-generic/div64.h>
diff --git a/include/asm-blackfin/dma-mapping.h b/include/asm-blackfin/dma-mapping.h
new file mode 100644
index 0000000..7a77d7f
--- /dev/null
+++ b/include/asm-blackfin/dma-mapping.h
@@ -0,0 +1,66 @@
+#ifndef _BLACKFIN_DMA_MAPPING_H
+#define _BLACKFIN_DMA_MAPPING_H
+
+#include <asm/scatterlist.h>
+
+void dma_alloc_init(unsigned long start, unsigned long end);
+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);
+
+/*
+ * 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)
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+				 enum dma_data_direction direction);
+
+/*
+ * Unmap a single streaming mode DMA translation.  The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+			  enum dma_data_direction direction);
+
+/*
+ * Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-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.
+ */
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+		      enum dma_data_direction 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.
+ */
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+		      int nhwentries, enum dma_data_direction direction);
+
+#endif				/* _BLACKFIN_DMA_MAPPING_H */
diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
new file mode 100644
index 0000000..be0d913
--- /dev/null
+++ b/include/asm-blackfin/dma.h
@@ -0,0 +1,188 @@
+/*
+ * File:         include/asm-blackfin/simple_bf533_dma.h
+ * Based on:     none - original work
+ * Author:       LG Soft India
+ *               Copyright (C) 2004-2005 Analog Devices Inc.
+ * Created:      Tue Sep 21 2004
+ * Description:  This file contains the major Data structures and constants
+ * 		 used for DMA Implementation in BF533
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_DMA_H_
+#define _BLACKFIN_DMA_H_
+
+#include <asm/io.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <asm/signal.h>
+#include <asm/semaphore.h>
+
+#include <linux/kernel.h>
+#include <asm/mach/dma.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/blackfin.h>
+
+#define MAX_DMA_ADDRESS PAGE_OFFSET
+
+/*****************************************************************************
+*        Generic DMA  Declarations
+*
+****************************************************************************/
+enum dma_chan_status {
+	DMA_CHANNEL_FREE,
+	DMA_CHANNEL_REQUESTED,
+	DMA_CHANNEL_ENABLED,
+};
+
+/*-------------------------
+ * config reg bits value
+ *-------------------------*/
+#define DATA_SIZE_8 		0
+#define DATA_SIZE_16 		1
+#define DATA_SIZE_32 		2
+
+#define DMA_FLOW_STOP 		0
+#define DMA_FLOW_AUTO 		1
+#define DMA_FLOW_ARRAY 		4
+#define DMA_FLOW_SMALL 		6
+#define DMA_FLOW_LARGE 		7
+
+#define DIMENSION_LINEAR    0
+#define DIMENSION_2D           1
+
+#define DIR_READ     0
+#define DIR_WRITE    1
+
+#define INTR_DISABLE   0
+#define INTR_ON_BUF    2
+#define INTR_ON_ROW    3
+
+struct dmasg {
+	unsigned long next_desc_addr;
+	unsigned long start_addr;
+	unsigned short cfg;
+	unsigned short x_count;
+	short x_modify;
+	unsigned short y_count;
+	short y_modify;
+} __attribute__((packed));
+
+struct dma_register {
+	unsigned long next_desc_ptr;	/* DMA Next Descriptor Pointer register */
+	unsigned long start_addr;	/* DMA Start address  register */
+
+	unsigned short cfg;	/* DMA Configuration register */
+	unsigned short dummy1;	/* DMA Configuration register */
+
+	unsigned long reserved;
+
+	unsigned short x_count;	/* DMA x_count register */
+	unsigned short dummy2;
+
+	short x_modify;	/* DMA x_modify register */
+	unsigned short dummy3;
+
+	unsigned short y_count;	/* DMA y_count register */
+	unsigned short dummy4;
+
+	short y_modify;	/* DMA y_modify register */
+	unsigned short dummy5;
+
+	unsigned long curr_desc_ptr;	/* DMA Current Descriptor Pointer
+					   register */
+	unsigned short curr_addr_ptr_lo;	/* DMA Current Address Pointer
+						   register */
+	unsigned short curr_addr_ptr_hi;	/* DMA Current Address Pointer
+						   register */
+	unsigned short irq_status;	/* DMA irq status register */
+	unsigned short dummy6;
+
+	unsigned short peripheral_map;	/* DMA peripheral map register */
+	unsigned short dummy7;
+
+	unsigned short curr_x_count;	/* DMA Current x-count register */
+	unsigned short dummy8;
+
+	unsigned long reserved2;
+
+	unsigned short curr_y_count;	/* DMA Current y-count register */
+	unsigned short dummy9;
+
+	unsigned long reserved3;
+
+};
+
+typedef irqreturn_t(*dma_interrupt_t) (int irq, void *dev_id);
+
+struct dma_channel {
+	struct mutex dmalock;
+	char *device_id;
+	enum dma_chan_status chan_status;
+	struct dma_register *regs;
+	struct dmasg *sg;		/* large mode descriptor */
+	unsigned int ctrl_num;	/* controller number */
+	dma_interrupt_t irq_callback;
+	void *data;
+	unsigned int dma_enable_flag;
+	unsigned int loopback_flag;
+};
+
+/*******************************************************************************
+*	DMA API's
+*******************************************************************************/
+/* functions to set register mode */
+void set_dma_start_addr(unsigned int channel, unsigned long addr);
+void set_dma_next_desc_addr(unsigned int channel, unsigned long addr);
+void set_dma_x_count(unsigned int channel, unsigned short x_count);
+void set_dma_x_modify(unsigned int channel, short x_modify);
+void set_dma_y_count(unsigned int channel, unsigned short y_count);
+void set_dma_y_modify(unsigned int channel, short y_modify);
+void set_dma_config(unsigned int channel, unsigned short config);
+unsigned short set_bfin_dma_config(char direction, char flow_mode,
+				   char intr_mode, char dma_mode, char width);
+
+/* get curr status for polling */
+unsigned short get_dma_curr_irqstat(unsigned int channel);
+unsigned short get_dma_curr_xcount(unsigned int channel);
+unsigned short get_dma_curr_ycount(unsigned int channel);
+
+/* set large DMA mode descriptor */
+void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg);
+
+/* check if current channel is in use */
+int dma_channel_active(unsigned int channel);
+
+/* common functions must be called in any mode */
+void free_dma(unsigned int channel);
+int dma_channel_active(unsigned int channel); /* check if a channel is in use */
+void disable_dma(unsigned int channel);
+void enable_dma(unsigned int channel);
+int request_dma(unsigned int channel, char *device_id);
+int set_dma_callback(unsigned int channel, dma_interrupt_t callback,
+		     void *data);
+void dma_disable_irq(unsigned int channel);
+void dma_enable_irq(unsigned int channel);
+void clear_dma_irqstat(unsigned int channel);
+void *dma_memcpy(void *dest, const void *src, size_t count);
+void *safe_dma_memcpy(void *dest, const void *src, size_t count);
+
+#endif
diff --git a/include/asm-blackfin/dpmc.h b/include/asm-blackfin/dpmc.h
new file mode 100644
index 0000000..f162edb
--- /dev/null
+++ b/include/asm-blackfin/dpmc.h
@@ -0,0 +1,70 @@
+/*
+ * include/asm-blackfin/dpmc.h -  Miscellaneous IOCTL commands for Dynamic Power
+ *   			 	Management Controller Driver.
+ * Copyright (C) 2004 Analog Device Inc.
+ *
+ */
+#ifndef _BLACKFIN_DPMC_H_
+#define _BLACKFIN_DPMC_H_
+
+#define SLEEP_MODE		1
+#define DEEP_SLEEP_MODE		2
+#define ACTIVE_PLL_DISABLED	3
+#define FULLON_MODE		4
+#define ACTIVE_PLL_ENABLED	5
+#define HIBERNATE_MODE		6
+
+#define IOCTL_FULL_ON_MODE	_IO('s', 0xA0)
+#define IOCTL_ACTIVE_MODE	_IO('s', 0xA1)
+#define IOCTL_SLEEP_MODE	_IO('s', 0xA2)
+#define IOCTL_DEEP_SLEEP_MODE	_IO('s', 0xA3)
+#define IOCTL_HIBERNATE_MODE	_IO('s', 0xA4)
+#define IOCTL_CHANGE_FREQUENCY	_IOW('s', 0xA5, unsigned long)
+#define IOCTL_CHANGE_VOLTAGE	_IOW('s', 0xA6, unsigned long)
+#define IOCTL_SET_CCLK		_IOW('s', 0xA7, unsigned long)
+#define IOCTL_SET_SCLK		_IOW('s', 0xA8, unsigned long)
+#define IOCTL_GET_PLLSTATUS	_IOW('s', 0xA9, unsigned long)
+#define IOCTL_GET_CORECLOCK	_IOW('s', 0xAA, unsigned long)
+#define IOCTL_GET_SYSTEMCLOCK	_IOW('s', 0xAB, unsigned long)
+#define IOCTL_GET_VCO		_IOW('s', 0xAC, unsigned long)
+#define IOCTL_DISABLE_WDOG_TIMER _IO('s', 0xAD)
+#define IOCTL_UNMASK_WDOG_WAKEUP_EVENT _IO('s',0xAE)
+#define IOCTL_PROGRAM_WDOG_TIMER _IOW('s',0xAF,unsigned long)
+#define IOCTL_CLEAR_WDOG_WAKEUP_EVENT _IO('s',0xB0)
+#define IOCTL_SLEEP_DEEPER_MODE _IO('s',0xB1)
+
+#define DPMC_MINOR		254
+
+#define ON	0
+#define OFF	1
+
+#ifdef __KERNEL__
+
+unsigned long calc_volt(void);
+int calc_vlev(int vlt);
+unsigned long change_voltage(unsigned long volt);
+int calc_msel(int vco_hz);
+unsigned long change_frequency(unsigned long vco_mhz);
+int set_pll_div(unsigned short sel, unsigned char flag);
+int get_vco(void);
+unsigned long change_system_clock(unsigned long clock);
+unsigned long change_core_clock(unsigned long clock);
+unsigned long get_pll_status(void);
+void change_baud(int baud);
+void fullon_mode(void);
+void active_mode(void);
+void sleep_mode(u32 sic_iwr);
+void deep_sleep(u32 sic_iwr);
+void hibernate_mode(u32 sic_iwr);
+void sleep_deeper(u32 sic_iwr);
+void program_wdog_timer(unsigned long);
+void unmask_wdog_wakeup_evt(void);
+void clear_wdog_wakeup_evt(void);
+void disable_wdog_timer(void);
+
+extern unsigned long get_cclk(void);
+extern unsigned long get_sclk(void);
+
+#endif	/* __KERNEL__ */
+
+#endif	/*_BLACKFIN_DPMC_H_*/
diff --git a/include/asm-blackfin/elf.h b/include/asm-blackfin/elf.h
new file mode 100644
index 0000000..5264b55
--- /dev/null
+++ b/include/asm-blackfin/elf.h
@@ -0,0 +1,127 @@
+/* Changes made by  LG Soft Oct 2004*/
+
+#ifndef __ASMBFIN_ELF_H
+#define __ASMBFIN_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_BFIN_PIC		0x00000001	/* -fpic */
+#define EF_BFIN_FDPIC		0x00000002	/* -mfdpic */
+#define EF_BFIN_CODE_IN_L1	0x00000010	/* --code-in-l1 */
+#define EF_BFIN_DATA_IN_L1	0x00000020	/* --data-in-l1 */
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_bfinfp_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_BLACKFIN)
+
+#define elf_check_fdpic(x) ((x)->e_flags & EF_BFIN_FDPIC /* && !((x)->e_flags & EF_FRV_NON_PIC_RELOCS) */)
+#define elf_check_const_displacement(x) ((x)->e_flags & EF_BFIN_PIC)
+
+/* EM_BLACKFIN defined in linux/elf.h	*/
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2LSB
+#define ELF_ARCH	EM_BLACKFIN
+
+#define ELF_PLAT_INIT(_r)	_r->p1 = 0
+
+#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr, _dynamic_addr)	\
+do {											\
+	_regs->r7	= 0;						\
+	_regs->p0	= _exec_map_addr;				\
+	_regs->p1	= _interp_map_addr;				\
+	_regs->p2	= _dynamic_addr;				\
+} while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_FDPIC_CORE_EFLAGS	EF_BFIN_FDPIC
+#define ELF_EXEC_PAGESIZE	4096
+
+#define	R_unused0	0	/* relocation type 0 is not defined */
+#define R_pcrel5m2	1	/*LSETUP part a */
+#define R_unused1	2	/* relocation type 2 is not defined */
+#define R_pcrel10	3	/* type 3, if cc jump <target>  */
+#define R_pcrel12_jump	4	/* type 4, jump <target> */
+#define R_rimm16	5	/* type 0x5, rN = <target> */
+#define R_luimm16	6	/* # 0x6, preg.l=<target> Load imm 16 to lower half */
+#define R_huimm16  	7	/* # 0x7, preg.h=<target> Load imm 16 to upper half */
+#define R_pcrel12_jump_s 8	/* # 0x8 jump.s <target> */
+#define R_pcrel24_jump_x 9	/* # 0x9 jump.x <target> */
+#define R_pcrel24       10	/* # 0xa call <target> , not expandable */
+#define R_unusedb       11	/* # 0xb not generated */
+#define R_unusedc       12	/* # 0xc  not used */
+#define R_pcrel24_jump_l 13	/*0xd jump.l <target> */
+#define R_pcrel24_call_x 14	/* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
+#define R_var_eq_symb    15	/* 0xf, linker should treat it same as 0x12 */
+#define R_byte_data      16	/* 0x10, .byte var = symbol */
+#define R_byte2_data     17	/* 0x11, .byte2 var = symbol */
+#define R_byte4_data     18	/* 0x12, .byte4 var = symbol and .var var=symbol */
+#define R_pcrel11        19	/* 0x13, lsetup part b */
+#define R_unused14      20	/* 0x14, undefined */
+#define R_unused15       21	/* not generated by VDSP 3.5 */
+
+/* arithmetic relocations */
+#define R_push		 0xE0
+#define R_const		 0xE1
+#define R_add		 0xE2
+#define R_sub		 0xE3
+#define R_mult		 0xE4
+#define R_div		 0xE5
+#define R_mod		 0xE6
+#define R_lshift	 0xE7
+#define R_rshift	 0xE8
+#define R_and		 0xE9
+#define R_or		 0xEA
+#define R_xor		 0xEB
+#define R_land		 0xEC
+#define R_lor		 0xED
+#define R_len		 0xEE
+#define R_neg		 0xEF
+#define R_comp		 0xF0
+#define R_page		 0xF1
+#define R_hwpage	 0xF2
+#define R_addr		 0xF3
+
+/* 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         0xD0000000UL
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs)	\
+        memcpy((char *) &pr_reg, (char *)regs,  \
+               sizeof(struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  */
+
+#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.  */
+
+#define ELF_PLATFORM  (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#endif
+
+#endif
diff --git a/include/asm-blackfin/emergency-restart.h b/include/asm-blackfin/emergency-restart.h
new file mode 100644
index 0000000..27f6c78
--- /dev/null
+++ b/include/asm-blackfin/emergency-restart.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_EMERGENCY_RESTART_H
+#define _ASM_EMERGENCY_RESTART_H
+
+#include <asm-generic/emergency-restart.h>
+
+#endif				/* _ASM_EMERGENCY_RESTART_H */
diff --git a/include/asm-blackfin/entry.h b/include/asm-blackfin/entry.h
new file mode 100644
index 0000000..562c6d3
--- /dev/null
+++ b/include/asm-blackfin/entry.h
@@ -0,0 +1,56 @@
+#ifndef __BFIN_ENTRY_H
+#define __BFIN_ENTRY_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#ifdef __ASSEMBLY__
+
+#define	LFLUSH_I_AND_D	0x00000808
+#define	LSIGTRAP	5
+
+/* process bits for task_struct.flags */
+#define	PF_TRACESYS_OFF	3
+#define	PF_TRACESYS_BIT	5
+#define	PF_PTRACED_OFF	3
+#define	PF_PTRACED_BIT	4
+#define	PF_DTRACE_OFF	1
+#define	PF_DTRACE_BIT	5
+
+/* This one is used for exceptions, emulation, and NMI.  It doesn't push
+   RETI and doesn't do cli.  */
+#define SAVE_ALL_SYS		save_context_no_interrupts
+/* This is used for all normal interrupts.  It saves a minimum of registers
+   to the stack, loads the IRQ number, and jumps to common code.  */
+#define INTERRUPT_ENTRY(N)						\
+    [--sp] = SYSCFG;							\
+									\
+    [--sp] = P0;	/*orig_p0*/					\
+    [--sp] = R0;	/*orig_r0*/					\
+    [--sp] = (R7:0,P5:0);						\
+    R0 = (N);								\
+    jump __common_int_entry;
+
+/* For timer interrupts, we need to save IPEND, since the user_mode
+	   macro accesses it to determine where to account time.  */
+#define TIMER_INTERRUPT_ENTRY(N)					\
+    [--sp] = SYSCFG;							\
+									\
+    [--sp] = P0;	/*orig_p0*/					\
+    [--sp] = R0;	/*orig_r0*/					\
+    [--sp] = (R7:0,P5:0);						\
+    p0.l = lo(IPEND);							\
+    p0.h = hi(IPEND);							\
+    r1 = [p0];								\
+    R0 = (N);								\
+    jump __common_int_entry;
+
+/* This one pushes RETI without using CLI.  Interrupts are enabled.  */
+#define SAVE_CONTEXT_SYSCALL	save_context_syscall
+#define SAVE_CONTEXT		save_context_with_interrupts
+
+#define RESTORE_ALL_SYS		restore_context_no_interrupts
+#define RESTORE_CONTEXT		restore_context_with_interrupts
+
+#endif				/* __ASSEMBLY__ */
+#endif				/* __BFIN_ENTRY_H */
diff --git a/include/asm-blackfin/errno.h b/include/asm-blackfin/errno.h
new file mode 100644
index 0000000..164e4f3
--- /dev/null
+++ b/include/asm-blackfin/errno.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_ERRNO_H
+#define _BFIN_ERRNO_H
+
+#include<asm-generic/errno.h>
+
+#endif				/* _BFIN_ERRNO_H */
diff --git a/include/asm-blackfin/fcntl.h b/include/asm-blackfin/fcntl.h
new file mode 100644
index 0000000..9c40371
--- /dev/null
+++ b/include/asm-blackfin/fcntl.h
@@ -0,0 +1,13 @@
+#ifndef _BFIN_FCNTL_H
+#define _BFIN_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_DIRECTORY	 040000	/* must be a directory */
+#define O_NOFOLLOW	0100000	/* don't follow links */
+#define O_DIRECT	0200000	/* direct disk access hint - currently ignored */
+#define O_LARGEFILE	0400000
+
+#include <asm-generic/fcntl.h>
+
+#endif
diff --git a/include/asm-blackfin/flat.h b/include/asm-blackfin/flat.h
new file mode 100644
index 0000000..e70074e
--- /dev/null
+++ b/include/asm-blackfin/flat.h
@@ -0,0 +1,58 @@
+/*
+ * include/asm-blackfin/flat.h -- uClinux flat-format executables
+ *
+ * Copyright (C) 2003,
+ *
+ */
+
+#ifndef __BLACKFIN_FLAT_H__
+#define __BLACKFIN_FLAT_H__
+
+#include <asm/unaligned.h>
+
+#define	flat_stack_align(sp)	/* nothing needed */
+#define	flat_argvp_envp_on_stack()		0
+#define	flat_old_ram_flag(flags)		(flags)
+
+extern unsigned long bfin_get_addr_from_rp (unsigned long *ptr,
+					unsigned long relval,
+					unsigned long flags,
+					unsigned long *persistent);
+
+extern void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
+		                unsigned long relval);
+
+/* The amount by which a relocation can exceed the program image limits
+   without being regarded as an error.  */
+
+#define	flat_reloc_valid(reloc, size)	((reloc) <= (size))
+
+#define	flat_get_addr_from_rp(rp, relval, flags, persistent)	\
+	bfin_get_addr_from_rp(rp, relval, flags, persistent)
+#define	flat_put_addr_at_rp(rp, val, relval)	\
+	bfin_put_addr_at_rp(rp, val, relval)
+
+/* Convert a relocation entry into an address.  */
+static inline unsigned long
+flat_get_relocate_addr (unsigned long relval)
+{
+	return relval & 0x03ffffff; /* Mask out top 6 bits */
+}
+
+static inline int flat_set_persistent(unsigned long relval,
+				      unsigned long *persistent)
+{
+	int type = (relval >> 26) & 7;
+	if (type == 3) {
+		*persistent = relval << 16;
+		return 1;
+	}
+	return 0;
+}
+
+static inline int flat_addr_absolute(unsigned long relval)
+{
+	return (relval & (1 << 29)) != 0;
+}
+
+#endif				/* __BLACKFIN_FLAT_H__ */
diff --git a/include/asm-blackfin/futex.h b/include/asm-blackfin/futex.h
new file mode 100644
index 0000000..6a332a9
--- /dev/null
+++ b/include/asm-blackfin/futex.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#include <asm-generic/futex.h>
+
+#endif
diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
new file mode 100644
index 0000000..d16fe3c
--- /dev/null
+++ b/include/asm-blackfin/gpio.h
@@ -0,0 +1,367 @@
+/*
+ * File:         arch/blackfin/kernel/bfin_gpio.h
+ * Based on:
+ * Author:	 Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+*  Number     BF537/6/4    BF561    BF533/2/1
+*
+*  GPIO_0       PF0         PF0        PF0
+*  GPIO_1       PF1         PF1        PF1
+*  GPIO_2       PF2         PF2        PF2
+*  GPIO_3       PF3         PF3        PF3
+*  GPIO_4       PF4         PF4        PF4
+*  GPIO_5       PF5         PF5        PF5
+*  GPIO_6       PF6         PF6        PF6
+*  GPIO_7       PF7         PF7        PF7
+*  GPIO_8       PF8         PF8        PF8
+*  GPIO_9       PF9         PF9        PF9
+*  GPIO_10      PF10        PF10       PF10
+*  GPIO_11      PF11        PF11       PF11
+*  GPIO_12      PF12        PF12       PF12
+*  GPIO_13      PF13        PF13       PF13
+*  GPIO_14      PF14        PF14       PF14
+*  GPIO_15      PF15        PF15       PF15
+*  GPIO_16      PG0         PF16
+*  GPIO_17      PG1         PF17
+*  GPIO_18      PG2         PF18
+*  GPIO_19      PG3         PF19
+*  GPIO_20      PG4         PF20
+*  GPIO_21      PG5         PF21
+*  GPIO_22      PG6         PF22
+*  GPIO_23      PG7         PF23
+*  GPIO_24      PG8         PF24
+*  GPIO_25      PG9         PF25
+*  GPIO_26      PG10        PF26
+*  GPIO_27      PG11        PF27
+*  GPIO_28      PG12        PF28
+*  GPIO_29      PG13        PF29
+*  GPIO_30      PG14        PF30
+*  GPIO_31      PG15        PF31
+*  GPIO_32      PH0         PF32
+*  GPIO_33      PH1         PF33
+*  GPIO_34      PH2         PF34
+*  GPIO_35      PH3         PF35
+*  GPIO_36      PH4         PF36
+*  GPIO_37      PH5         PF37
+*  GPIO_38      PH6         PF38
+*  GPIO_39      PH7         PF39
+*  GPIO_40      PH8         PF40
+*  GPIO_41      PH9         PF41
+*  GPIO_42      PH10        PF42
+*  GPIO_43      PH11        PF43
+*  GPIO_44      PH12        PF44
+*  GPIO_45      PH13        PF45
+*  GPIO_46      PH14        PF46
+*  GPIO_47      PH15        PF47
+*/
+
+#ifndef __ARCH_BLACKFIN_GPIO_H__
+#define __ARCH_BLACKFIN_GPIO_H__
+
+#define gpio_bank(x) ((x) >> 4)
+#define gpio_bit(x)  (1<<((x) & 0xF))
+#define gpio_sub_n(x) ((x) & 0xF)
+
+#define GPIO_BANKSIZE 16
+
+#define	GPIO_0	0
+#define	GPIO_1	1
+#define	GPIO_2	2
+#define	GPIO_3	3
+#define	GPIO_4	4
+#define	GPIO_5	5
+#define	GPIO_6	6
+#define	GPIO_7	7
+#define	GPIO_8	8
+#define	GPIO_9	9
+#define	GPIO_10	10
+#define	GPIO_11	11
+#define	GPIO_12	12
+#define	GPIO_13	13
+#define	GPIO_14	14
+#define	GPIO_15	15
+#define	GPIO_16	16
+#define	GPIO_17	17
+#define	GPIO_18	18
+#define	GPIO_19	19
+#define	GPIO_20	20
+#define	GPIO_21	21
+#define	GPIO_22	22
+#define	GPIO_23	23
+#define	GPIO_24	24
+#define	GPIO_25	25
+#define	GPIO_26	26
+#define	GPIO_27	27
+#define	GPIO_28	28
+#define	GPIO_29	29
+#define	GPIO_30	30
+#define	GPIO_31	31
+#define	GPIO_32	32
+#define	GPIO_33	33
+#define	GPIO_34	34
+#define	GPIO_35	35
+#define	GPIO_36	36
+#define	GPIO_37	37
+#define	GPIO_38	38
+#define	GPIO_39	39
+#define	GPIO_40	40
+#define	GPIO_41	41
+#define	GPIO_42	42
+#define	GPIO_43	43
+#define	GPIO_44	44
+#define	GPIO_45	45
+#define	GPIO_46	46
+#define	GPIO_47	47
+
+
+#define PERIPHERAL_USAGE 1
+#define GPIO_USAGE 0
+
+#ifdef BF533_FAMILY
+#define MAX_BLACKFIN_GPIOS 16
+#endif
+
+#ifdef BF537_FAMILY
+#define MAX_BLACKFIN_GPIOS 48
+#define PORT_F 0
+#define PORT_G 1
+#define PORT_H 2
+#define PORT_J 3
+
+#define	GPIO_PF0	0
+#define	GPIO_PF1	1
+#define	GPIO_PF2	2
+#define	GPIO_PF3	3
+#define	GPIO_PF4	4
+#define	GPIO_PF5	5
+#define	GPIO_PF6	6
+#define	GPIO_PF7	7
+#define	GPIO_PF8	8
+#define	GPIO_PF9	9
+#define	GPIO_PF10	10
+#define	GPIO_PF11	11
+#define	GPIO_PF12	12
+#define	GPIO_PF13	13
+#define	GPIO_PF14	14
+#define	GPIO_PF15	15
+#define	GPIO_PG0	16
+#define	GPIO_PG1	17
+#define	GPIO_PG2	18
+#define	GPIO_PG3	19
+#define	GPIO_PG4	20
+#define	GPIO_PG5	21
+#define	GPIO_PG6	22
+#define	GPIO_PG7	23
+#define	GPIO_PG8	24
+#define	GPIO_PG9	25
+#define	GPIO_PG10      	26
+#define	GPIO_PG11      	27
+#define	GPIO_PG12      	28
+#define	GPIO_PG13      	29
+#define	GPIO_PG14      	30
+#define	GPIO_PG15      	31
+#define	GPIO_PH0	32
+#define	GPIO_PH1	33
+#define	GPIO_PH2	34
+#define	GPIO_PH3	35
+#define	GPIO_PH4	36
+#define	GPIO_PH5	37
+#define	GPIO_PH6	38
+#define	GPIO_PH7	39
+#define	GPIO_PH8	40
+#define	GPIO_PH9	41
+#define	GPIO_PH10      	42
+#define	GPIO_PH11      	43
+#define	GPIO_PH12      	44
+#define	GPIO_PH13      	45
+#define	GPIO_PH14      	46
+#define	GPIO_PH15      	47
+
+#endif
+
+#ifdef BF561_FAMILY
+#define MAX_BLACKFIN_GPIOS 48
+#define PORT_FIO0 0
+#define PORT_FIO1 1
+#define PORT_FIO2 2
+#endif
+
+#ifndef __ASSEMBLY__
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin General Purpose Ports Access Functions
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: These functions abstract direct register access
+*              to Blackfin processor General Purpose
+*              Ports Regsiters
+*
+* CAUTION: These functions do not belong to the GPIO Driver API
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+void set_gpio_dir(unsigned short, unsigned short);
+void set_gpio_inen(unsigned short, unsigned short);
+void set_gpio_polar(unsigned short, unsigned short);
+void set_gpio_edge(unsigned short, unsigned short);
+void set_gpio_both(unsigned short, unsigned short);
+void set_gpio_data(unsigned short, unsigned short);
+void set_gpio_maska(unsigned short, unsigned short);
+void set_gpio_maskb(unsigned short, unsigned short);
+void set_gpio_toggle(unsigned short);
+void set_gpiop_dir(unsigned short, unsigned short);
+void set_gpiop_inen(unsigned short, unsigned short);
+void set_gpiop_polar(unsigned short, unsigned short);
+void set_gpiop_edge(unsigned short, unsigned short);
+void set_gpiop_both(unsigned short, unsigned short);
+void set_gpiop_data(unsigned short, unsigned short);
+void set_gpiop_maska(unsigned short, unsigned short);
+void set_gpiop_maskb(unsigned short, unsigned short);
+unsigned short get_gpio_dir(unsigned short);
+unsigned short get_gpio_inen(unsigned short);
+unsigned short get_gpio_polar(unsigned short);
+unsigned short get_gpio_edge(unsigned short);
+unsigned short get_gpio_both(unsigned short);
+unsigned short get_gpio_maska(unsigned short);
+unsigned short get_gpio_maskb(unsigned short);
+unsigned short get_gpio_data(unsigned short);
+unsigned short get_gpiop_dir(unsigned short);
+unsigned short get_gpiop_inen(unsigned short);
+unsigned short get_gpiop_polar(unsigned short);
+unsigned short get_gpiop_edge(unsigned short);
+unsigned short get_gpiop_both(unsigned short);
+unsigned short get_gpiop_maska(unsigned short);
+unsigned short get_gpiop_maskb(unsigned short);
+unsigned short get_gpiop_data(unsigned short);
+
+struct gpio_port_t {
+	unsigned short data;
+	unsigned short dummy1;
+	unsigned short data_clear;
+	unsigned short dummy2;
+	unsigned short data_set;
+	unsigned short dummy3;
+	unsigned short toggle;
+	unsigned short dummy4;
+	unsigned short maska;
+	unsigned short dummy5;
+	unsigned short maska_clear;
+	unsigned short dummy6;
+	unsigned short maska_set;
+	unsigned short dummy7;
+	unsigned short maska_toggle;
+	unsigned short dummy8;
+	unsigned short maskb;
+	unsigned short dummy9;
+	unsigned short maskb_clear;
+	unsigned short dummy10;
+	unsigned short maskb_set;
+	unsigned short dummy11;
+	unsigned short maskb_toggle;
+	unsigned short dummy12;
+	unsigned short dir;
+	unsigned short dummy13;
+	unsigned short polar;
+	unsigned short dummy14;
+	unsigned short edge;
+	unsigned short dummy15;
+	unsigned short both;
+	unsigned short dummy16;
+	unsigned short inen;
+};
+
+#ifdef CONFIG_PM
+#define PM_WAKE_RISING	0x1
+#define PM_WAKE_FALLING	0x2
+#define PM_WAKE_HIGH	0x4
+#define PM_WAKE_LOW	0x8
+#define PM_WAKE_BOTH_EDGES	(PM_WAKE_RISING | PM_WAKE_FALLING)
+
+int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type);
+void gpio_pm_wakeup_free(unsigned short gpio);
+unsigned int gpio_pm_setup(void);
+void gpio_pm_restore(void);
+
+struct gpio_port_s {
+	unsigned short data;
+	unsigned short data_clear;
+	unsigned short data_set;
+	unsigned short toggle;
+	unsigned short maska;
+	unsigned short maska_clear;
+	unsigned short maska_set;
+	unsigned short maska_toggle;
+	unsigned short maskb;
+	unsigned short maskb_clear;
+	unsigned short maskb_set;
+	unsigned short maskb_toggle;
+	unsigned short dir;
+	unsigned short polar;
+	unsigned short edge;
+	unsigned short both;
+	unsigned short inen;
+
+	unsigned short fer;
+};
+#endif /*CONFIG_PM*/
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: Blackfin GPIO Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+int gpio_request(unsigned short, const char *);
+void gpio_free(unsigned short);
+
+void gpio_set_value(unsigned short gpio, unsigned short arg);
+unsigned short gpio_get_value(unsigned short gpio);
+
+#define gpio_get_value(gpio) 		get_gpio_data(gpio)
+#define gpio_set_value(gpio, value)	set_gpio_data(gpio, value)
+
+void gpio_direction_input(unsigned short gpio);
+void gpio_direction_output(unsigned short gpio);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_BLACKFIN_GPIO_H__ */
diff --git a/include/asm-blackfin/hardirq.h b/include/asm-blackfin/hardirq.h
new file mode 100644
index 0000000..0cab0d3
--- /dev/null
+++ b/include/asm-blackfin/hardirq.h
@@ -0,0 +1,41 @@
+#ifndef __BFIN_HARDIRQ_H
+#define __BFIN_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+
+typedef struct {
+	unsigned int __softirq_pending;
+	unsigned int __syscall_count;
+	struct task_struct *__ksoftirqd_task;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
+
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * HARDIRQ_MASK: 0x0000ff00
+ * SOFTIRQ_MASK: 0x00ff0000
+ */
+
+#define HARDIRQ_BITS	8
+
+#ifdef NR_IRQS
+# if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+# endif
+#endif
+
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
+
+#endif
diff --git a/include/asm-blackfin/hw_irq.h b/include/asm-blackfin/hw_irq.h
new file mode 100644
index 0000000..5b51eae
--- /dev/null
+++ b/include/asm-blackfin/hw_irq.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_BFIN_HW_IRQ_H
+#define __ASM_BFIN_HW_IRQ_H
+
+/* Dummy include. */
+
+#endif
diff --git a/include/asm-blackfin/ide.h b/include/asm-blackfin/ide.h
new file mode 100644
index 0000000..41b2db4
--- /dev/null
+++ b/include/asm-blackfin/ide.h
@@ -0,0 +1,32 @@
+/****************************************************************************/
+
+/*
+ *  linux/include/asm-blackfin/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ *  Copyright (C) 2001       Lineo Inc., davidm@snapgear.com
+ *  Copyright (C) 2002       Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 2002       Yoshinori Sato (ysato@users.sourceforge.jp)
+ *  Copyright (C) 2005       Hennerich Michael (hennerich@blackfin.uclinux.org)
+ */
+
+/****************************************************************************/
+#ifndef _BLACKFIN_IDE_H
+#define _BLACKFIN_IDE_H
+/****************************************************************************/
+#ifdef __KERNEL__
+/****************************************************************************/
+
+#define MAX_HWIFS	1
+
+/* Legacy ... BLK_DEV_IDECS */
+#define IDE_ARCH_OBSOLETE_INIT
+#define ide_default_io_ctl(base)	((base) + 0x206) /* obsolete */
+
+
+#include <asm-generic/ide_iops.h>
+
+/****************************************************************************/
+#endif				/* __KERNEL__ */
+#endif				/* _BLACKFIN_IDE_H */
+/****************************************************************************/
diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h
new file mode 100644
index 0000000..7e6995e
--- /dev/null
+++ b/include/asm-blackfin/io.h
@@ -0,0 +1,207 @@
+#ifndef _BFIN_IO_H
+#define _BFIN_IO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#endif
+#include <linux/compiler.h>
+
+/*
+ * These are for ISA/PCI shared memory _only_ and should never be used
+ * on any other type of memory, including Zorro memory. They are meant to
+ * access the bus in the bus byte order which is little-endian!.
+ *
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the bfin architecture, we just read/write the
+ * memory location directly.
+ */
+#ifndef __ASSEMBLY__
+
+static inline unsigned char readb(void __iomem *addr)
+{
+	unsigned int val;
+	int tmp;
+
+	__asm__ __volatile__ ("cli %1;\n\t"
+			"NOP; NOP; SSYNC;\n\t"
+			"%0 = b [%2] (z);\n\t"
+			"sti %1;\n\t"
+			: "=d"(val), "=d"(tmp): "a"(addr)
+			);
+
+	return (unsigned char) val;
+}
+
+static inline unsigned short readw(void __iomem *addr)
+{
+	unsigned int val;
+	int tmp;
+
+	__asm__ __volatile__ ("cli %1;\n\t"
+			"NOP; NOP; SSYNC;\n\t"
+			"%0 = w [%2] (z);\n\t"
+			"sti %1;\n\t"
+		      	: "=d"(val), "=d"(tmp): "a"(addr)
+			);
+
+	return (unsigned short) val;
+}
+
+static inline unsigned int readl(void __iomem *addr)
+{
+	unsigned int val;
+	int tmp;
+
+	__asm__ __volatile__ ("cli %1;\n\t"
+			"NOP; NOP; SSYNC;\n\t"
+			"%0 = [%2];\n\t"
+			"sti %1;\n\t"
+		      	: "=d"(val), "=d"(tmp): "a"(addr)
+			);
+	return val;
+}
+
+#endif /*  __ASSEMBLY__ */
+
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
+
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+#define memset_io(a,b,c)	memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+#define inb(addr)    readb(addr)
+#define inw(addr)    readw(addr)
+#define inl(addr)    readl(addr)
+#define outb(x,addr) ((void) writeb(x,addr))
+#define outw(x,addr) ((void) writew(x,addr))
+#define outl(x,addr) ((void) writel(x,addr))
+
+#define inb_p(addr)    inb(addr)
+#define inw_p(addr)    inw(addr)
+#define inl_p(addr)    inl(addr)
+#define outb_p(x,addr) outb(x,addr)
+#define outw_p(x,addr) outw(x,addr)
+#define outl_p(x,addr) outl(x,addr)
+
+#define ioread8_rep(a,d,c)	insb(a,d,c)
+#define ioread16_rep(a,d,c)	insw(a,d,c)
+#define ioread32_rep(a,d,c)	insl(a,d,c)
+#define iowrite8_rep(a,s,c)	outsb(a,s,c)
+#define iowrite16_rep(a,s,c)	outsw(a,s,c)
+#define iowrite32_rep(a,s,c)	outsl(a,s,c)
+
+#define ioread8(X)			readb(X)
+#define ioread16(X)			readw(X)
+#define ioread32(X)			readl(X)
+#define iowrite8(val,X)			writeb(val,X)
+#define iowrite16(val,X)		writew(val,X)
+#define iowrite32(val,X)		writel(val,X)
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/* Values for nocacheflag and cmode */
+#define IOMAP_NOCACHE_SER		1
+
+#ifndef __ASSEMBLY__
+
+extern void outsb(void __iomem *port, const void *addr, unsigned long count);
+extern void outsw(void __iomem *port, const void *addr, unsigned long count);
+extern void outsl(void __iomem *port, const void *addr, unsigned long count);
+
+extern void insb(const void __iomem *port, void *addr, unsigned long count);
+extern void insw(const void __iomem *port, void *addr, unsigned long count);
+extern void insl(const void __iomem *port, void *addr, unsigned long count);
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+static inline void __iomem *__ioremap(unsigned long physaddr, unsigned long size,
+				int cacheflag)
+{
+	return (void __iomem *)physaddr;
+}
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+static inline void iounmap(void *addr)
+{
+}
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+static inline void __iounmap(void *addr, unsigned long size)
+{
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+static inline void kernel_set_cachemode(void *addr, unsigned long size,
+					int cmode)
+{
+}
+
+static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+static inline void __iomem *ioremap_nocache(unsigned long physaddr,
+					    unsigned long size)
+{
+	return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+
+extern void blkfin_inv_cache_all(void);
+
+#endif
+
+#define	ioport_map(port, nr)		((void __iomem*)(port))
+#define	ioport_unmap(addr)
+
+#define dma_cache_inv(_start,_size) do { blkfin_inv_cache_all();} while (0)
+#define dma_cache_wback(_start,_size) do { } while (0)
+#define dma_cache_wback_inv(_start,_size) do { blkfin_inv_cache_all();} while (0)
+
+/* Pages to physical address... */
+#define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
+#define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
+
+#define mm_ptov(vaddr)		((void *) (vaddr))
+#define mm_vtop(vaddr)		((unsigned long) (vaddr))
+#define phys_to_virt(vaddr)	((void *) (vaddr))
+#define virt_to_phys(vaddr)	((unsigned long) (vaddr))
+
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * 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				/* _BFIN_IO_H */
diff --git a/include/asm-blackfin/ioctl.h b/include/asm-blackfin/ioctl.h
new file mode 100644
index 0000000..b279fe0
--- /dev/null
+++ b/include/asm-blackfin/ioctl.h
@@ -0,0 +1 @@
+#include <asm-generic/ioctl.h>
diff --git a/include/asm-blackfin/ioctls.h b/include/asm-blackfin/ioctls.h
new file mode 100644
index 0000000..8356204
--- /dev/null
+++ b/include/asm-blackfin/ioctls.h
@@ -0,0 +1,82 @@
+#ifndef __ARCH_BFIN_IOCTLS_H__
+#define __ARCH_BFIN_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS		0x5401
+#define TCSETS		0x5402
+#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	/* For debugging only */
+#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	/* these numbers need to be adjusted. */
+#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 FIOQSIZE	0x545E
+
+/* 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				/* __ARCH_BFIN_IOCTLS_H__ */
diff --git a/include/asm-blackfin/ipc.h b/include/asm-blackfin/ipc.h
new file mode 100644
index 0000000..a46e3d9
--- /dev/null
+++ b/include/asm-blackfin/ipc.h
@@ -0,0 +1 @@
+#include <asm-generic/ipc.h>
diff --git a/include/asm-blackfin/ipcbuf.h b/include/asm-blackfin/ipcbuf.h
new file mode 100644
index 0000000..8f0899c
--- /dev/null
+++ b/include/asm-blackfin/ipcbuf.h
@@ -0,0 +1,30 @@
+/* Changes origined from m68k version.    Lineo Inc.  May 2001   */
+
+#ifndef __BFIN_IPCBUF_H__
+#define __BFIN_IPCBUF_H__
+
+/*
+ * The user_ipc_perm structure for m68k 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				/* __BFIN_IPCBUF_H__ */
diff --git a/include/asm-blackfin/irq.h b/include/asm-blackfin/irq.h
new file mode 100644
index 0000000..65480da
--- /dev/null
+++ b/include/asm-blackfin/irq.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * Changed by HuTao Apr18, 2003
+ *
+ * Copyright was missing when I got the code so took from MIPS arch ...MaTed---
+ * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
+ * Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001 by Ralf Baechle
+ *
+ * Adapted for BlackFin (ADI) by Ted Ma <mated@sympatico.ca>
+ * Copyright (c) 2002 Arcturus Networks Inc. (www.arcturusnetworks.com)
+ * Copyright (c) 2002 Lineo, Inc. <mattw@lineo.com>
+ */
+
+#ifndef _BFIN_IRQ_H_
+#define _BFIN_IRQ_H_
+
+#include <asm/mach/irq.h>
+#include <asm/ptrace.h>
+
+/*******************************************************************************
+ *****   INTRODUCTION ***********
+ *   On the Blackfin, the interrupt structure allows remmapping of the hardware
+ *   levels.
+ * - I'm going to assume that the H/W level is going to stay at the default
+ *   settings. If someone wants to go through and abstart this out, feel free
+ *   to mod the interrupt numbering scheme.
+ * - I'm abstracting the interrupts so that uClinux does not know anything
+ *   about the H/W levels. If you want to change the H/W AND keep the abstracted
+ *   levels that uClinux sees, you should be able to do most of it here.
+ * - I've left the "abstract" numbering sparce in case someone wants to pull the
+ *   interrupts apart (just the TX/RX for the various devices)
+ *******************************************************************************/
+
+/* SYS_IRQS and NR_IRQS are defined in <asm/mach-bf5xx/irq.h>*/
+
+/*
+ * Machine specific interrupt sources.
+ *
+ * Adding an interrupt service routine for a source with this bit
+ * set indicates a special machine specific interrupt source.
+ * The machine specific files define these sources.
+ *
+ * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
+ * introduce unnecessary overhead.
+ *
+ * All interrupt handling is actually machine specific so it is better
+ * to use function pointers, as used by the Sparc port, and select the
+ * interrupt handling functions when initializing the kernel. This way
+ * we save some unnecessary overhead at run-time.
+ *                                                      01/11/97 - Jes
+ */
+
+extern void ack_bad_irq(unsigned int irq);
+
+static __inline__ int irq_canonicalize(int irq)
+{
+	return irq;
+}
+
+/* count of spurious interrupts */
+/* extern volatile unsigned int num_spurious; */
+
+#ifndef NO_IRQ
+#define NO_IRQ ((unsigned int)(-1))
+#endif
+
+#endif				/* _BFIN_IRQ_H_ */
diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h
new file mode 100644
index 0000000..d830f0a
--- /dev/null
+++ b/include/asm-blackfin/irq_handler.h
@@ -0,0 +1,22 @@
+#ifndef _IRQ_HANDLER_H
+#define _IRQ_HANDLER_H
+
+/* BASE LEVEL interrupt handler routines */
+asmlinkage void evt_emulation(void);
+asmlinkage void evt_exception(void);
+asmlinkage void trap(void);
+asmlinkage void evt_ivhw(void);
+asmlinkage void evt_timer(void);
+asmlinkage void evt_evt2(void);
+asmlinkage void evt_evt7(void);
+asmlinkage void evt_evt8(void);
+asmlinkage void evt_evt9(void);
+asmlinkage void evt_evt10(void);
+asmlinkage void evt_evt11(void);
+asmlinkage void evt_evt12(void);
+asmlinkage void evt_evt13(void);
+asmlinkage void evt_soft_int1(void);
+asmlinkage void evt_system_call(void);
+asmlinkage void init_exception_buff(void);
+
+#endif
diff --git a/include/asm-blackfin/irq_regs.h b/include/asm-blackfin/irq_regs.h
new file mode 100644
index 0000000..3dd9c0b
--- /dev/null
+++ b/include/asm-blackfin/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-blackfin/kdebug.h b/include/asm-blackfin/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-blackfin/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-blackfin/kmap_types.h b/include/asm-blackfin/kmap_types.h
new file mode 100644
index 0000000..e215f71
--- /dev/null
+++ b/include/asm-blackfin/kmap_types.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_KMAP_TYPES_H
+#define _ASM_KMAP_TYPES_H
+
+enum km_type {
+	KM_BOUNCE_READ,
+	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
+	KM_BIO_SRC_IRQ,
+	KM_BIO_DST_IRQ,
+	KM_PTE0,
+	KM_PTE1,
+	KM_IRQ0,
+	KM_IRQ1,
+	KM_SOFTIRQ0,
+	KM_SOFTIRQ1,
+	KM_TYPE_NR
+};
+
+#endif
diff --git a/include/asm-blackfin/l1layout.h b/include/asm-blackfin/l1layout.h
new file mode 100644
index 0000000..c13ded7
--- /dev/null
+++ b/include/asm-blackfin/l1layout.h
@@ -0,0 +1,31 @@
+/*
+ * l1layout.h
+ * Defines a layout of L1 scratchpad memory that userspace can rely on.
+ */
+
+#ifndef _L1LAYOUT_H_
+#define _L1LAYOUT_H_
+
+#include <asm/blackfin.h>
+
+#ifndef __ASSEMBLY__
+
+/* Data that is "mapped" into the process VM at the start of the L1 scratch
+   memory, so that each process can access it at a fixed address.  Used for
+   stack checking.  */
+struct l1_scratch_task_info
+{
+	/* Points to the start of the stack.  */
+	void *stack_start;
+	/* Not updated by the kernel; a user process can modify this to
+	   keep track of the lowest address of the stack pointer during its
+	   runtime.  */
+	void *lowest_sp;
+};
+
+/* A pointer to the structure in memory.  */
+#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)L1_SCRATCH_START)
+
+#endif
+
+#endif
diff --git a/include/asm-blackfin/linkage.h b/include/asm-blackfin/linkage.h
new file mode 100644
index 0000000..5a822bb
--- /dev/null
+++ b/include/asm-blackfin/linkage.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+
+#endif
diff --git a/include/asm-blackfin/local.h b/include/asm-blackfin/local.h
new file mode 100644
index 0000000..75afffb
--- /dev/null
+++ b/include/asm-blackfin/local.h
@@ -0,0 +1,6 @@
+#ifndef __BLACKFIN_LOCAL_H
+#define __BLACKFIN_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif				/* __BLACKFIN_LOCAL_H */
diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
new file mode 100644
index 0000000..a84d390
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/anomaly.h
@@ -0,0 +1,175 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ *  - Revision U, May 17, 2006; ADSP-BF533 Blackfin Processor Anomaly List
+ *  - Revision Y, May 17, 2006; ADSP-BF532 Blackfin Processor Anomaly List
+ *  - Revision T, May 17, 2006; ADSP-BF531 Blackfin Processor Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 or 0.2 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2))
+#error Kernel will not work on BF533 Version 0.1 or 0.2
+#endif
+
+/* Issues that are common to 0.5, 0.4, and 0.3 silicon */
+#if  (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+                            slot1 and store of a P register in slot 2 is not
+                            supported */
+#define ANOMALY_05000105 /* Watchpoint Status Register (WPSTAT) bits are set on
+                            every corresponding match */
+#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive
+                            Channel DMA stops */
+#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR
+                            registers. */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+                            upper bits*/
+#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+                            syncs */
+#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not
+                            functional */
+#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable
+                            state */
+#define ANOMALY_05000229 /* SPI Slave Boot Mode modifies registers */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+                            VDDint <=0.9V */
+#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+                            an edge is detected may clear interrupt */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+                            DMA system instability */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+                            not restored */
+#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic
+                            control */
+#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when
+                            killed in a particular stage*/
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+			    registers are interrupted */
+#define ANOMALY_05000311 /* Erroneous flag pin operations under specific sequences*/
+
+#endif
+
+/* These issues only occur on 0.3 or 0.4 BF533 */
+#if (defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not
+                            updated at the same time. */
+#define ANOMALY_05000158 /* Boot fails when data cache enabled: Data from a Data
+        		    Cache Fill can be corrupted after or during
+                            Instruction DMA if certain core stalls exist */
+#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General
+                            Purpose TX or RX modes */
+#define ANOMALY_05000198 /* Failing SYSTEM MMR accesses when stalled by
+                            preceding memory read */
+#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during
+                            inactive channels in certain conditions */
+#define ANOMALY_05000202 /* Possible infinite stall with specific dual dag
+                            situation */
+#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */
+#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */
+#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect
+                            data*/
+#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate
+                            Differences in certain Conditions */
+#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */
+#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to
+                            hardware reset */
+#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or
+                            IDLE around a Change of Control causes
+                            unpredictable results */
+#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the
+                            shadow of a conditional branch */
+#define ANOMALY_05000246 /* Data CPLB's should prevent spurious hardware
+                            errors */
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event
+                            interrupt not functional */
+#define ANOMALY_05000257 /* An interrupt or exception during short Hardware
+                            loops may cause the instruction fetch unit to
+                            malfunction */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of
+                            the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */
+#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE
+                            instruction will cause an infinite stall in the
+                            second to last instruction in a hardware loop */
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+                            SPORT external receive and transmit clocks. */
+#define ANOMALY_05000269 /* High I/O activity causes the output voltage of the
+                            internal voltage regulator (VDDint) to increase. */
+#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the
+                            internal voltage regulator (VDDint) to decrease */
+#endif
+
+/* These issues are only on 0.4 silicon */
+#if (defined(CONFIG_BF_REV_0_4))
+#define ANOMALY_05000234 /* Incorrect Revision Number in DSPID Register */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+                            (TDM) */
+#endif
+
+/* These issues are only on 0.3 silicon */
+#if defined(CONFIG_BF_REV_0_3)
+#define ANOMALY_05000183 /* Timer Pin limitations for PPI TX Modes with
+                            External Frame Syncs */
+#define ANOMALY_05000189 /* False Protection Exceptions caused by Speculative
+                            Instruction or Data Fetches, or by Fetches at the
+                            boundary of reserved memory space */
+#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs
+                            when polarity setting is changed */
+#define ANOMALY_05000194 /* Sport Restarting in specific modes may cause data
+                            corruption */
+#define ANOMALY_05000199 /* DMA current address shows wrong value during carry
+                            fix */
+#define ANOMALY_05000201 /* Receive frame sync not ignored during active
+                            frames in sport MCM */
+#define ANOMALY_05000203 /* Specific sequence that can cause DMA error or DMA
+                            stopping */
+#if defined(CONFIG_BF533)
+#define ANOMALY_05000204 /* Incorrect data read with write-through cache and
+                            allocate cache lines on reads only mode */
+#endif /* CONFIG_BF533 */
+#define ANOMALY_05000207 /* Recovery from "brown-out" condition */
+#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain
+                            instructions */
+#define ANOMALY_05000233 /* PPI_FS3 is not driven in 2 or 3 internal Frame
+                            Sync Transmit Mode */
+#define ANOMALY_05000271 /* Spontaneous reset of Internal Voltage Regulator */
+#endif
+
+#endif /*  _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h
new file mode 100644
index 0000000..185fc12
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/bf533.h
@@ -0,0 +1,306 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/bf533.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MACH_BF533_H__
+#define __MACH_BF533_H__
+
+#define SUPPORTED_REVID 2
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15		0x8000
+#define IMASK_IVG14		0x4000
+#define IMASK_IVG13		0x2000
+#define IMASK_IVG12		0x1000
+
+#define IMASK_IVG11		0x0800
+#define IMASK_IVG10		0x0400
+#define IMASK_IVG9		0x0200
+#define IMASK_IVG8		0x0100
+
+#define IMASK_IVG7		0x0080
+#define IMASK_IVGTMR		0x0040
+#define IMASK_IVGHW		0x0020
+
+/***************************/
+
+
+#define BLKFIN_DSUBBANKS	4
+#define BLKFIN_DWAYS		2
+#define BLKFIN_DLINES		64
+#define BLKFIN_ISUBBANKS	4
+#define BLKFIN_IWAYS		4
+#define BLKFIN_ILINES		32
+
+#define WAY0_L			0x1
+#define WAY1_L			0x2
+#define WAY01_L			0x3
+#define WAY2_L			0x4
+#define WAY02_L			0x5
+#define	WAY12_L			0x6
+#define	WAY012_L		0x7
+
+#define	WAY3_L			0x8
+#define	WAY03_L			0x9
+#define	WAY13_L			0xA
+#define	WAY013_L		0xB
+
+#define	WAY32_L			0xC
+#define	WAY320_L		0xD
+#define	WAY321_L		0xE
+#define	WAYALL_L		0xF
+
+#define DMC_ENABLE (2<<2)	/*yes, 2, not 1 */
+
+/* IAR0 BIT FIELDS*/
+#define RTC_ERROR_BIT			0x0FFFFFFF
+#define UART_ERROR_BIT			0xF0FFFFFF
+#define SPORT1_ERROR_BIT		0xFF0FFFFF
+#define SPI_ERROR_BIT			0xFFF0FFFF
+#define SPORT0_ERROR_BIT		0xFFFF0FFF
+#define PPI_ERROR_BIT			0xFFFFF0FF
+#define DMA_ERROR_BIT			0xFFFFFF0F
+#define PLLWAKE_ERROR_BIT		0xFFFFFFFF
+
+/* IAR1 BIT FIELDS*/
+#define DMA7_UARTTX_BIT			0x0FFFFFFF
+#define DMA6_UARTRX_BIT			0xF0FFFFFF
+#define DMA5_SPI_BIT			0xFF0FFFFF
+#define DMA4_SPORT1TX_BIT		0xFFF0FFFF
+#define DMA3_SPORT1RX_BIT		0xFFFF0FFF
+#define DMA2_SPORT0TX_BIT		0xFFFFF0FF
+#define DMA1_SPORT0RX_BIT		0xFFFFFF0F
+#define DMA0_PPI_BIT			0xFFFFFFFF
+
+/* IAR2 BIT FIELDS*/
+#define WDTIMER_BIT			0x0FFFFFFF
+#define MEMDMA1_BIT			0xF0FFFFFF
+#define MEMDMA0_BIT			0xFF0FFFFF
+#define PFB_BIT				0xFFF0FFFF
+#define PFA_BIT				0xFFFF0FFF
+#define TIMER2_BIT			0xFFFFF0FF
+#define TIMER1_BIT			0xFFFFFF0F
+#define TIMER0_BIT		        0xFFFFFFFF
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL	((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL	((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL	(V_AMBEN | V_AMCKEN | V_CDPRIO)
+
+#define MAX_VC	650000000
+#define MIN_VC	50000000
+
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+/********************************PLL Settings **************************************/
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT > 64)
+#error "VCO Multiplier is more than 64. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ	(CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ	((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ	(CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ	(CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ	CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ	CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ > CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV   CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif				/* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF533
+#define CPU "BF533"
+#define CPUID 0x027a5000
+#endif
+#ifdef CONFIG_BF532
+#define CPU "BF532"
+#define CPUID 0x0275A000
+#endif
+#ifdef CONFIG_BF531
+#define CPU "BF531"
+#define CPUID 0x027a5000
+#endif
+#ifndef CPU
+#define	CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM mem size must be multible of 4MB"
+#endif
+
+#define SDRAM_IGENERIC    (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL     (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY        (               CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL   (               CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND		0x200
+#ifdef CONFIG_BLKFIN_WB		/*Write Back Policy */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_DIRTY \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else				/*Write Through */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW  | CPLB_DIRTY \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#endif
+
+#define L1_DMEMORY       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+#define SDRAM_DNON_CHBL  (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_EBIU       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_OOPS  	 (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+
+#define SIZE_1K 0x00000400	/* 1K */
+#define SIZE_4K 0x00001000	/* 4K */
+#define SIZE_1M 0x00100000	/* 1M */
+#define SIZE_4M 0x00400000	/* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)
+
+#endif				/* __MACH_BF533_H__  */
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
new file mode 100644
index 0000000..23bf76a
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -0,0 +1,108 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS                1
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
+
+#define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+# define CONFIG_SERIAL_BFIN_CTSRTS
+# ifndef CONFIG_UART0_CTS_PIN
+#  define CONFIG_UART0_CTS_PIN -1
+# endif
+# ifndef CONFIG_UART0_RTS_PIN
+#  define CONFIG_UART0_RTS_PIN -1
+# endif
+#endif
+
+struct bfin_serial_port {
+        struct uart_port        port;
+        unsigned int            old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	int			tx_done;
+	int			tx_count;
+	struct circ_buf		rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int			rx_dma_nrows;
+	unsigned int		tx_dma_channel;
+	unsigned int		rx_dma_channel;
+	struct work_struct	tx_dma_workqueue;
+#else
+	struct work_struct 	cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int			cts_pin;
+	int			rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+	unsigned long	uart_base_addr;
+	int		uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	unsigned int	uart_tx_dma_channel;
+	unsigned int	uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int		uart_cts_pin;
+	int		uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+	0xFFC00400,
+	IRQ_UART_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	CH_UART_TX,
+	CH_UART_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+	CONFIG_UART0_CTS_PIN,
+	CONFIG_UART0_RTS_PIN,
+#endif
+};
+
+
+int nr_ports = NR_PORTS;
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	if (uart->cts_pin >= 0) {
+		gpio_request(uart->cts_pin, NULL);
+		gpio_direction_input(uart->cts_pin);
+	}
+	if (uart->rts_pin >= 0) {
+		gpio_request(uart->rts_pin, NULL);
+		gpio_direction_input(uart->rts_pin);
+	}
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf533/blackfin.h b/include/asm-blackfin/mach-bf533/blackfin.h
new file mode 100644
index 0000000..e438449
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/blackfin.h
@@ -0,0 +1,45 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF533_FAMILY
+
+#include "bf533.h"
+#include "mem_map.h"
+#include "defBF532.h"
+#include "anomaly.h"
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF532.h"
+#endif
+
+#endif				/* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h
new file mode 100644
index 0000000..1d7c494
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/cdefBF532.h
@@ -0,0 +1,706 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/cdefBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF532_H
+#define _CDEF_BF532_H
+/*
+#if !defined(__ADSPLPBLACKFIN__)
+#warning cdefBF532.h should only be included for 532 compatible chips.
+#endif
+*/
+/*include all Core registers and bit definitions*/
+#include "defBF532.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/* Clock and System Control (0xFFC0 0400-0xFFC0 07FF) */
+#define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT()              bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val)          bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID()                   bfin_read32(CHIPID)
+#define bfin_read_SWRST()                    bfin_read16(SWRST)
+#define bfin_write_SWRST(val)                bfin_write16(SWRST,val)
+#define bfin_read_SYSCR()                    bfin_read16(SYSCR)
+#define bfin_write_SYSCR(val)                bfin_write16(SYSCR,val)
+#define bfin_read_PLL_DIV()                  bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val)              bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL()                   bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	bfin_write16(VR_CTL, val);
+	__builtin_bfin_ssync();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+	local_irq_save(flags);
+	asm("IDLE;");
+	local_irq_restore(flags);
+	bfin_write32(SIC_IWR, iwr);
+}
+
+/* System Interrupt Controller (0xFFC0 0C00-0xFFC0 0FFF) */
+#define bfin_read_SIC_IAR0()                 bfin_read32(SIC_IAR0)
+#define bfin_write_SIC_IAR0(val)             bfin_write32(SIC_IAR0,val)
+#define bfin_read_SIC_IAR1()                 bfin_read32(SIC_IAR1)
+#define bfin_write_SIC_IAR1(val)             bfin_write32(SIC_IAR1,val)
+#define bfin_read_SIC_IAR2()                 bfin_read32(SIC_IAR2)
+#define bfin_write_SIC_IAR2(val)             bfin_write32(SIC_IAR2,val)
+#define bfin_read_SIC_IAR3()                 bfin_read32(SIC_IAR3)
+#define bfin_write_SIC_IAR3(val)             bfin_write32(SIC_IAR3,val)
+#define bfin_read_SIC_IMASK()                bfin_read32(SIC_IMASK)
+#define bfin_write_SIC_IMASK(val)            bfin_write32(SIC_IMASK,val)
+#define bfin_read_SIC_ISR()                  bfin_read32(SIC_ISR)
+#define bfin_write_SIC_ISR(val)              bfin_write32(SIC_ISR,val)
+#define bfin_read_SIC_IWR()                  bfin_read32(SIC_IWR)
+#define bfin_write_SIC_IWR(val)              bfin_write32(SIC_IWR,val)
+
+/* Watchdog Timer (0xFFC0 1000-0xFFC0 13FF) */
+#define bfin_read_WDOG_CTL()                 bfin_read16(WDOG_CTL)
+#define bfin_write_WDOG_CTL(val)             bfin_write16(WDOG_CTL,val)
+#define bfin_read_WDOG_CNT()                 bfin_read32(WDOG_CNT)
+#define bfin_write_WDOG_CNT(val)             bfin_write32(WDOG_CNT,val)
+#define bfin_read_WDOG_STAT()                bfin_read32(WDOG_STAT)
+#define bfin_write_WDOG_STAT(val)            bfin_write32(WDOG_STAT,val)
+
+/* Real Time Clock (0xFFC0 1400-0xFFC0 17FF) */
+#define bfin_read_RTC_STAT()                 bfin_read32(RTC_STAT)
+#define bfin_write_RTC_STAT(val)             bfin_write32(RTC_STAT,val)
+#define bfin_read_RTC_ICTL()                 bfin_read16(RTC_ICTL)
+#define bfin_write_RTC_ICTL(val)             bfin_write16(RTC_ICTL,val)
+#define bfin_read_RTC_ISTAT()                bfin_read16(RTC_ISTAT)
+#define bfin_write_RTC_ISTAT(val)            bfin_write16(RTC_ISTAT,val)
+#define bfin_read_RTC_SWCNT()                bfin_read16(RTC_SWCNT)
+#define bfin_write_RTC_SWCNT(val)            bfin_write16(RTC_SWCNT,val)
+#define bfin_read_RTC_ALARM()                bfin_read32(RTC_ALARM)
+#define bfin_write_RTC_ALARM(val)            bfin_write32(RTC_ALARM,val)
+#define bfin_read_RTC_FAST()                 bfin_read16(RTC_FAST)
+#define bfin_write_RTC_FAST(val)             bfin_write16(RTC_FAST,val)
+#define bfin_read_RTC_PREN()                 bfin_read16(RTC_PREN)
+#define bfin_write_RTC_PREN(val)             bfin_write16(RTC_PREN,val)
+
+/* General Purpose IO (0xFFC0 2400-0xFFC0 27FF) */
+#define bfin_read_FIO_DIR()                  bfin_read16(FIO_DIR)
+#define bfin_write_FIO_DIR(val)              bfin_write16(FIO_DIR,val)
+#define bfin_read_FIO_FLAG_C()               bfin_read16(FIO_FLAG_C)
+#define bfin_write_FIO_FLAG_C(val)           bfin_write16(FIO_FLAG_C,val)
+#define bfin_read_FIO_FLAG_S()               bfin_read16(FIO_FLAG_S)
+#define bfin_write_FIO_FLAG_S(val)           bfin_write16(FIO_FLAG_S,val)
+#define bfin_read_FIO_MASKA_C()              bfin_read16(FIO_MASKA_C)
+#define bfin_write_FIO_MASKA_C(val)          bfin_write16(FIO_MASKA_C,val)
+#define bfin_read_FIO_MASKA_S()              bfin_read16(FIO_MASKA_S)
+#define bfin_write_FIO_MASKA_S(val)          bfin_write16(FIO_MASKA_S,val)
+#define bfin_read_FIO_MASKB_C()              bfin_read16(FIO_MASKB_C)
+#define bfin_write_FIO_MASKB_C(val)          bfin_write16(FIO_MASKB_C,val)
+#define bfin_read_FIO_MASKB_S()              bfin_read16(FIO_MASKB_S)
+#define bfin_write_FIO_MASKB_S(val)          bfin_write16(FIO_MASKB_S,val)
+#define bfin_read_FIO_POLAR()                bfin_read16(FIO_POLAR)
+#define bfin_write_FIO_POLAR(val)            bfin_write16(FIO_POLAR,val)
+#define bfin_read_FIO_EDGE()                 bfin_read16(FIO_EDGE)
+#define bfin_write_FIO_EDGE(val)             bfin_write16(FIO_EDGE,val)
+#define bfin_read_FIO_BOTH()                 bfin_read16(FIO_BOTH)
+#define bfin_write_FIO_BOTH(val)             bfin_write16(FIO_BOTH,val)
+#define bfin_read_FIO_INEN()                 bfin_read16(FIO_INEN)
+#define bfin_write_FIO_INEN(val)             bfin_write16(FIO_INEN,val)
+#define bfin_read_FIO_FLAG_D()               bfin_read16(FIO_FLAG_D)
+#define bfin_write_FIO_FLAG_D(val)           bfin_write16(FIO_FLAG_D,val)
+#define bfin_read_FIO_FLAG_T()               bfin_read16(FIO_FLAG_T)
+#define bfin_write_FIO_FLAG_T(val)           bfin_write16(FIO_FLAG_T,val)
+#define bfin_read_FIO_MASKA_D()              bfin_read16(FIO_MASKA_D)
+#define bfin_write_FIO_MASKA_D(val)          bfin_write16(FIO_MASKA_D,val)
+#define bfin_read_FIO_MASKA_T()              bfin_read16(FIO_MASKA_T)
+#define bfin_write_FIO_MASKA_T(val)          bfin_write16(FIO_MASKA_T,val)
+#define bfin_read_FIO_MASKB_D()              bfin_read16(FIO_MASKB_D)
+#define bfin_write_FIO_MASKB_D(val)          bfin_write16(FIO_MASKB_D,val)
+#define bfin_read_FIO_MASKB_T()              bfin_read16(FIO_MASKB_T)
+#define bfin_write_FIO_MASKB_T(val)          bfin_write16(FIO_MASKB_T,val)
+
+/* DMA Traffic controls */
+#define bfin_read_DMA_TCPER()                bfin_read16(DMA_TCPER)
+#define bfin_write_DMA_TCPER(val)            bfin_write16(DMA_TCPER,val)
+#define bfin_read_DMA_TCCNT()                bfin_read16(DMA_TCCNT)
+#define bfin_write_DMA_TCCNT(val)            bfin_write16(DMA_TCCNT,val)
+#define bfin_read_DMA_TC_PER()               bfin_read16(DMA_TC_PER)
+#define bfin_write_DMA_TC_PER(val)           bfin_write16(DMA_TC_PER,val)
+#define bfin_read_DMA_TC_CNT()               bfin_read16(DMA_TC_CNT)
+#define bfin_write_DMA_TC_CNT(val)           bfin_write16(DMA_TC_CNT,val)
+
+/* DMA Controller */
+#define bfin_read_DMA0_CONFIG()              bfin_read16(DMA0_CONFIG)
+#define bfin_write_DMA0_CONFIG(val)          bfin_write16(DMA0_CONFIG,val)
+#define bfin_read_DMA0_NEXT_DESC_PTR()       bfin_read32(DMA0_NEXT_DESC_PTR)
+#define bfin_write_DMA0_NEXT_DESC_PTR(val)   bfin_write32(DMA0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA0_START_ADDR()          bfin_read32(DMA0_START_ADDR)
+#define bfin_write_DMA0_START_ADDR(val)      bfin_write32(DMA0_START_ADDR,val)
+#define bfin_read_DMA0_X_COUNT()             bfin_read16(DMA0_X_COUNT)
+#define bfin_write_DMA0_X_COUNT(val)         bfin_write16(DMA0_X_COUNT,val)
+#define bfin_read_DMA0_Y_COUNT()             bfin_read16(DMA0_Y_COUNT)
+#define bfin_write_DMA0_Y_COUNT(val)         bfin_write16(DMA0_Y_COUNT,val)
+#define bfin_read_DMA0_X_MODIFY()            bfin_read16(DMA0_X_MODIFY)
+#define bfin_write_DMA0_X_MODIFY(val)        bfin_write16(DMA0_X_MODIFY,val)
+#define bfin_read_DMA0_Y_MODIFY()            bfin_read16(DMA0_Y_MODIFY)
+#define bfin_write_DMA0_Y_MODIFY(val)        bfin_write16(DMA0_Y_MODIFY,val)
+#define bfin_read_DMA0_CURR_DESC_PTR()       bfin_read32(DMA0_CURR_DESC_PTR)
+#define bfin_write_DMA0_CURR_DESC_PTR(val)   bfin_write32(DMA0_CURR_DESC_PTR,val)
+#define bfin_read_DMA0_CURR_ADDR()           bfin_read32(DMA0_CURR_ADDR)
+#define bfin_write_DMA0_CURR_ADDR(val)       bfin_write32(DMA0_CURR_ADDR,val)
+#define bfin_read_DMA0_CURR_X_COUNT()        bfin_read16(DMA0_CURR_X_COUNT)
+#define bfin_write_DMA0_CURR_X_COUNT(val)    bfin_write16(DMA0_CURR_X_COUNT,val)
+#define bfin_read_DMA0_CURR_Y_COUNT()        bfin_read16(DMA0_CURR_Y_COUNT)
+#define bfin_write_DMA0_CURR_Y_COUNT(val)    bfin_write16(DMA0_CURR_Y_COUNT,val)
+#define bfin_read_DMA0_IRQ_STATUS()          bfin_read16(DMA0_IRQ_STATUS)
+#define bfin_write_DMA0_IRQ_STATUS(val)      bfin_write16(DMA0_IRQ_STATUS,val)
+#define bfin_read_DMA0_PERIPHERAL_MAP()      bfin_read16(DMA0_PERIPHERAL_MAP)
+#define bfin_write_DMA0_PERIPHERAL_MAP(val)  bfin_write16(DMA0_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA1_CONFIG()              bfin_read16(DMA1_CONFIG)
+#define bfin_write_DMA1_CONFIG(val)          bfin_write16(DMA1_CONFIG,val)
+#define bfin_read_DMA1_NEXT_DESC_PTR()       bfin_read32(DMA1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_NEXT_DESC_PTR(val)   bfin_write32(DMA1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_START_ADDR()          bfin_read32(DMA1_START_ADDR)
+#define bfin_write_DMA1_START_ADDR(val)      bfin_write32(DMA1_START_ADDR,val)
+#define bfin_read_DMA1_X_COUNT()             bfin_read16(DMA1_X_COUNT)
+#define bfin_write_DMA1_X_COUNT(val)         bfin_write16(DMA1_X_COUNT,val)
+#define bfin_read_DMA1_Y_COUNT()             bfin_read16(DMA1_Y_COUNT)
+#define bfin_write_DMA1_Y_COUNT(val)         bfin_write16(DMA1_Y_COUNT,val)
+#define bfin_read_DMA1_X_MODIFY()            bfin_read16(DMA1_X_MODIFY)
+#define bfin_write_DMA1_X_MODIFY(val)        bfin_write16(DMA1_X_MODIFY,val)
+#define bfin_read_DMA1_Y_MODIFY()            bfin_read16(DMA1_Y_MODIFY)
+#define bfin_write_DMA1_Y_MODIFY(val)        bfin_write16(DMA1_Y_MODIFY,val)
+#define bfin_read_DMA1_CURR_DESC_PTR()       bfin_read32(DMA1_CURR_DESC_PTR)
+#define bfin_write_DMA1_CURR_DESC_PTR(val)   bfin_write32(DMA1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_CURR_ADDR()           bfin_read32(DMA1_CURR_ADDR)
+#define bfin_write_DMA1_CURR_ADDR(val)       bfin_write32(DMA1_CURR_ADDR,val)
+#define bfin_read_DMA1_CURR_X_COUNT()        bfin_read16(DMA1_CURR_X_COUNT)
+#define bfin_write_DMA1_CURR_X_COUNT(val)    bfin_write16(DMA1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_CURR_Y_COUNT()        bfin_read16(DMA1_CURR_Y_COUNT)
+#define bfin_write_DMA1_CURR_Y_COUNT(val)    bfin_write16(DMA1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_IRQ_STATUS()          bfin_read16(DMA1_IRQ_STATUS)
+#define bfin_write_DMA1_IRQ_STATUS(val)      bfin_write16(DMA1_IRQ_STATUS,val)
+#define bfin_read_DMA1_PERIPHERAL_MAP()      bfin_read16(DMA1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_PERIPHERAL_MAP(val)  bfin_write16(DMA1_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA2_CONFIG()              bfin_read16(DMA2_CONFIG)
+#define bfin_write_DMA2_CONFIG(val)          bfin_write16(DMA2_CONFIG,val)
+#define bfin_read_DMA2_NEXT_DESC_PTR()       bfin_read32(DMA2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_NEXT_DESC_PTR(val)   bfin_write32(DMA2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_START_ADDR()          bfin_read32(DMA2_START_ADDR)
+#define bfin_write_DMA2_START_ADDR(val)      bfin_write32(DMA2_START_ADDR,val)
+#define bfin_read_DMA2_X_COUNT()             bfin_read16(DMA2_X_COUNT)
+#define bfin_write_DMA2_X_COUNT(val)         bfin_write16(DMA2_X_COUNT,val)
+#define bfin_read_DMA2_Y_COUNT()             bfin_read16(DMA2_Y_COUNT)
+#define bfin_write_DMA2_Y_COUNT(val)         bfin_write16(DMA2_Y_COUNT,val)
+#define bfin_read_DMA2_X_MODIFY()            bfin_read16(DMA2_X_MODIFY)
+#define bfin_write_DMA2_X_MODIFY(val)        bfin_write16(DMA2_X_MODIFY,val)
+#define bfin_read_DMA2_Y_MODIFY()            bfin_read16(DMA2_Y_MODIFY)
+#define bfin_write_DMA2_Y_MODIFY(val)        bfin_write16(DMA2_Y_MODIFY,val)
+#define bfin_read_DMA2_CURR_DESC_PTR()       bfin_read32(DMA2_CURR_DESC_PTR)
+#define bfin_write_DMA2_CURR_DESC_PTR(val)   bfin_write32(DMA2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_CURR_ADDR()           bfin_read32(DMA2_CURR_ADDR)
+#define bfin_write_DMA2_CURR_ADDR(val)       bfin_write32(DMA2_CURR_ADDR,val)
+#define bfin_read_DMA2_CURR_X_COUNT()        bfin_read16(DMA2_CURR_X_COUNT)
+#define bfin_write_DMA2_CURR_X_COUNT(val)    bfin_write16(DMA2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_CURR_Y_COUNT()        bfin_read16(DMA2_CURR_Y_COUNT)
+#define bfin_write_DMA2_CURR_Y_COUNT(val)    bfin_write16(DMA2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_IRQ_STATUS()          bfin_read16(DMA2_IRQ_STATUS)
+#define bfin_write_DMA2_IRQ_STATUS(val)      bfin_write16(DMA2_IRQ_STATUS,val)
+#define bfin_read_DMA2_PERIPHERAL_MAP()      bfin_read16(DMA2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_PERIPHERAL_MAP(val)  bfin_write16(DMA2_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA3_CONFIG()              bfin_read16(DMA3_CONFIG)
+#define bfin_write_DMA3_CONFIG(val)          bfin_write16(DMA3_CONFIG,val)
+#define bfin_read_DMA3_NEXT_DESC_PTR()       bfin_read32(DMA3_NEXT_DESC_PTR)
+#define bfin_write_DMA3_NEXT_DESC_PTR(val)   bfin_write32(DMA3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA3_START_ADDR()          bfin_read32(DMA3_START_ADDR)
+#define bfin_write_DMA3_START_ADDR(val)      bfin_write32(DMA3_START_ADDR,val)
+#define bfin_read_DMA3_X_COUNT()             bfin_read16(DMA3_X_COUNT)
+#define bfin_write_DMA3_X_COUNT(val)         bfin_write16(DMA3_X_COUNT,val)
+#define bfin_read_DMA3_Y_COUNT()             bfin_read16(DMA3_Y_COUNT)
+#define bfin_write_DMA3_Y_COUNT(val)         bfin_write16(DMA3_Y_COUNT,val)
+#define bfin_read_DMA3_X_MODIFY()            bfin_read16(DMA3_X_MODIFY)
+#define bfin_write_DMA3_X_MODIFY(val)        bfin_write16(DMA3_X_MODIFY,val)
+#define bfin_read_DMA3_Y_MODIFY()            bfin_read16(DMA3_Y_MODIFY)
+#define bfin_write_DMA3_Y_MODIFY(val)        bfin_write16(DMA3_Y_MODIFY,val)
+#define bfin_read_DMA3_CURR_DESC_PTR()       bfin_read32(DMA3_CURR_DESC_PTR)
+#define bfin_write_DMA3_CURR_DESC_PTR(val)   bfin_write32(DMA3_CURR_DESC_PTR,val)
+#define bfin_read_DMA3_CURR_ADDR()           bfin_read32(DMA3_CURR_ADDR)
+#define bfin_write_DMA3_CURR_ADDR(val)       bfin_write32(DMA3_CURR_ADDR,val)
+#define bfin_read_DMA3_CURR_X_COUNT()        bfin_read16(DMA3_CURR_X_COUNT)
+#define bfin_write_DMA3_CURR_X_COUNT(val)    bfin_write16(DMA3_CURR_X_COUNT,val)
+#define bfin_read_DMA3_CURR_Y_COUNT()        bfin_read16(DMA3_CURR_Y_COUNT)
+#define bfin_write_DMA3_CURR_Y_COUNT(val)    bfin_write16(DMA3_CURR_Y_COUNT,val)
+#define bfin_read_DMA3_IRQ_STATUS()          bfin_read16(DMA3_IRQ_STATUS)
+#define bfin_write_DMA3_IRQ_STATUS(val)      bfin_write16(DMA3_IRQ_STATUS,val)
+#define bfin_read_DMA3_PERIPHERAL_MAP()      bfin_read16(DMA3_PERIPHERAL_MAP)
+#define bfin_write_DMA3_PERIPHERAL_MAP(val)  bfin_write16(DMA3_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA4_CONFIG()              bfin_read16(DMA4_CONFIG)
+#define bfin_write_DMA4_CONFIG(val)          bfin_write16(DMA4_CONFIG,val)
+#define bfin_read_DMA4_NEXT_DESC_PTR()       bfin_read32(DMA4_NEXT_DESC_PTR)
+#define bfin_write_DMA4_NEXT_DESC_PTR(val)   bfin_write32(DMA4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA4_START_ADDR()          bfin_read32(DMA4_START_ADDR)
+#define bfin_write_DMA4_START_ADDR(val)      bfin_write32(DMA4_START_ADDR,val)
+#define bfin_read_DMA4_X_COUNT()             bfin_read16(DMA4_X_COUNT)
+#define bfin_write_DMA4_X_COUNT(val)         bfin_write16(DMA4_X_COUNT,val)
+#define bfin_read_DMA4_Y_COUNT()             bfin_read16(DMA4_Y_COUNT)
+#define bfin_write_DMA4_Y_COUNT(val)         bfin_write16(DMA4_Y_COUNT,val)
+#define bfin_read_DMA4_X_MODIFY()            bfin_read16(DMA4_X_MODIFY)
+#define bfin_write_DMA4_X_MODIFY(val)        bfin_write16(DMA4_X_MODIFY,val)
+#define bfin_read_DMA4_Y_MODIFY()            bfin_read16(DMA4_Y_MODIFY)
+#define bfin_write_DMA4_Y_MODIFY(val)        bfin_write16(DMA4_Y_MODIFY,val)
+#define bfin_read_DMA4_CURR_DESC_PTR()       bfin_read32(DMA4_CURR_DESC_PTR)
+#define bfin_write_DMA4_CURR_DESC_PTR(val)   bfin_write32(DMA4_CURR_DESC_PTR,val)
+#define bfin_read_DMA4_CURR_ADDR()           bfin_read32(DMA4_CURR_ADDR)
+#define bfin_write_DMA4_CURR_ADDR(val)       bfin_write32(DMA4_CURR_ADDR,val)
+#define bfin_read_DMA4_CURR_X_COUNT()        bfin_read16(DMA4_CURR_X_COUNT)
+#define bfin_write_DMA4_CURR_X_COUNT(val)    bfin_write16(DMA4_CURR_X_COUNT,val)
+#define bfin_read_DMA4_CURR_Y_COUNT()        bfin_read16(DMA4_CURR_Y_COUNT)
+#define bfin_write_DMA4_CURR_Y_COUNT(val)    bfin_write16(DMA4_CURR_Y_COUNT,val)
+#define bfin_read_DMA4_IRQ_STATUS()          bfin_read16(DMA4_IRQ_STATUS)
+#define bfin_write_DMA4_IRQ_STATUS(val)      bfin_write16(DMA4_IRQ_STATUS,val)
+#define bfin_read_DMA4_PERIPHERAL_MAP()      bfin_read16(DMA4_PERIPHERAL_MAP)
+#define bfin_write_DMA4_PERIPHERAL_MAP(val)  bfin_write16(DMA4_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA5_CONFIG()              bfin_read16(DMA5_CONFIG)
+#define bfin_write_DMA5_CONFIG(val)          bfin_write16(DMA5_CONFIG,val)
+#define bfin_read_DMA5_NEXT_DESC_PTR()       bfin_read32(DMA5_NEXT_DESC_PTR)
+#define bfin_write_DMA5_NEXT_DESC_PTR(val)   bfin_write32(DMA5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA5_START_ADDR()          bfin_read32(DMA5_START_ADDR)
+#define bfin_write_DMA5_START_ADDR(val)      bfin_write32(DMA5_START_ADDR,val)
+#define bfin_read_DMA5_X_COUNT()             bfin_read16(DMA5_X_COUNT)
+#define bfin_write_DMA5_X_COUNT(val)         bfin_write16(DMA5_X_COUNT,val)
+#define bfin_read_DMA5_Y_COUNT()             bfin_read16(DMA5_Y_COUNT)
+#define bfin_write_DMA5_Y_COUNT(val)         bfin_write16(DMA5_Y_COUNT,val)
+#define bfin_read_DMA5_X_MODIFY()            bfin_read16(DMA5_X_MODIFY)
+#define bfin_write_DMA5_X_MODIFY(val)        bfin_write16(DMA5_X_MODIFY,val)
+#define bfin_read_DMA5_Y_MODIFY()            bfin_read16(DMA5_Y_MODIFY)
+#define bfin_write_DMA5_Y_MODIFY(val)        bfin_write16(DMA5_Y_MODIFY,val)
+#define bfin_read_DMA5_CURR_DESC_PTR()       bfin_read32(DMA5_CURR_DESC_PTR)
+#define bfin_write_DMA5_CURR_DESC_PTR(val)   bfin_write32(DMA5_CURR_DESC_PTR,val)
+#define bfin_read_DMA5_CURR_ADDR()           bfin_read32(DMA5_CURR_ADDR)
+#define bfin_write_DMA5_CURR_ADDR(val)       bfin_write32(DMA5_CURR_ADDR,val)
+#define bfin_read_DMA5_CURR_X_COUNT()        bfin_read16(DMA5_CURR_X_COUNT)
+#define bfin_write_DMA5_CURR_X_COUNT(val)    bfin_write16(DMA5_CURR_X_COUNT,val)
+#define bfin_read_DMA5_CURR_Y_COUNT()        bfin_read16(DMA5_CURR_Y_COUNT)
+#define bfin_write_DMA5_CURR_Y_COUNT(val)    bfin_write16(DMA5_CURR_Y_COUNT,val)
+#define bfin_read_DMA5_IRQ_STATUS()          bfin_read16(DMA5_IRQ_STATUS)
+#define bfin_write_DMA5_IRQ_STATUS(val)      bfin_write16(DMA5_IRQ_STATUS,val)
+#define bfin_read_DMA5_PERIPHERAL_MAP()      bfin_read16(DMA5_PERIPHERAL_MAP)
+#define bfin_write_DMA5_PERIPHERAL_MAP(val)  bfin_write16(DMA5_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA6_CONFIG()              bfin_read16(DMA6_CONFIG)
+#define bfin_write_DMA6_CONFIG(val)          bfin_write16(DMA6_CONFIG,val)
+#define bfin_read_DMA6_NEXT_DESC_PTR()       bfin_read32(DMA6_NEXT_DESC_PTR)
+#define bfin_write_DMA6_NEXT_DESC_PTR(val)   bfin_write32(DMA6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA6_START_ADDR()          bfin_read32(DMA6_START_ADDR)
+#define bfin_write_DMA6_START_ADDR(val)      bfin_write32(DMA6_START_ADDR,val)
+#define bfin_read_DMA6_X_COUNT()             bfin_read16(DMA6_X_COUNT)
+#define bfin_write_DMA6_X_COUNT(val)         bfin_write16(DMA6_X_COUNT,val)
+#define bfin_read_DMA6_Y_COUNT()             bfin_read16(DMA6_Y_COUNT)
+#define bfin_write_DMA6_Y_COUNT(val)         bfin_write16(DMA6_Y_COUNT,val)
+#define bfin_read_DMA6_X_MODIFY()            bfin_read16(DMA6_X_MODIFY)
+#define bfin_write_DMA6_X_MODIFY(val)        bfin_write16(DMA6_X_MODIFY,val)
+#define bfin_read_DMA6_Y_MODIFY()            bfin_read16(DMA6_Y_MODIFY)
+#define bfin_write_DMA6_Y_MODIFY(val)        bfin_write16(DMA6_Y_MODIFY,val)
+#define bfin_read_DMA6_CURR_DESC_PTR()       bfin_read32(DMA6_CURR_DESC_PTR)
+#define bfin_write_DMA6_CURR_DESC_PTR(val)   bfin_write32(DMA6_CURR_DESC_PTR,val)
+#define bfin_read_DMA6_CURR_ADDR()           bfin_read32(DMA6_CURR_ADDR)
+#define bfin_write_DMA6_CURR_ADDR(val)       bfin_write32(DMA6_CURR_ADDR,val)
+#define bfin_read_DMA6_CURR_X_COUNT()        bfin_read16(DMA6_CURR_X_COUNT)
+#define bfin_write_DMA6_CURR_X_COUNT(val)    bfin_write16(DMA6_CURR_X_COUNT,val)
+#define bfin_read_DMA6_CURR_Y_COUNT()        bfin_read16(DMA6_CURR_Y_COUNT)
+#define bfin_write_DMA6_CURR_Y_COUNT(val)    bfin_write16(DMA6_CURR_Y_COUNT,val)
+#define bfin_read_DMA6_IRQ_STATUS()          bfin_read16(DMA6_IRQ_STATUS)
+#define bfin_write_DMA6_IRQ_STATUS(val)      bfin_write16(DMA6_IRQ_STATUS,val)
+#define bfin_read_DMA6_PERIPHERAL_MAP()      bfin_read16(DMA6_PERIPHERAL_MAP)
+#define bfin_write_DMA6_PERIPHERAL_MAP(val)  bfin_write16(DMA6_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA7_CONFIG()              bfin_read16(DMA7_CONFIG)
+#define bfin_write_DMA7_CONFIG(val)          bfin_write16(DMA7_CONFIG,val)
+#define bfin_read_DMA7_NEXT_DESC_PTR()       bfin_read32(DMA7_NEXT_DESC_PTR)
+#define bfin_write_DMA7_NEXT_DESC_PTR(val)   bfin_write32(DMA7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA7_START_ADDR()          bfin_read32(DMA7_START_ADDR)
+#define bfin_write_DMA7_START_ADDR(val)      bfin_write32(DMA7_START_ADDR,val)
+#define bfin_read_DMA7_X_COUNT()             bfin_read16(DMA7_X_COUNT)
+#define bfin_write_DMA7_X_COUNT(val)         bfin_write16(DMA7_X_COUNT,val)
+#define bfin_read_DMA7_Y_COUNT()             bfin_read16(DMA7_Y_COUNT)
+#define bfin_write_DMA7_Y_COUNT(val)         bfin_write16(DMA7_Y_COUNT,val)
+#define bfin_read_DMA7_X_MODIFY()            bfin_read16(DMA7_X_MODIFY)
+#define bfin_write_DMA7_X_MODIFY(val)        bfin_write16(DMA7_X_MODIFY,val)
+#define bfin_read_DMA7_Y_MODIFY()            bfin_read16(DMA7_Y_MODIFY)
+#define bfin_write_DMA7_Y_MODIFY(val)        bfin_write16(DMA7_Y_MODIFY,val)
+#define bfin_read_DMA7_CURR_DESC_PTR()       bfin_read32(DMA7_CURR_DESC_PTR)
+#define bfin_write_DMA7_CURR_DESC_PTR(val)   bfin_write32(DMA7_CURR_DESC_PTR,val)
+#define bfin_read_DMA7_CURR_ADDR()           bfin_read32(DMA7_CURR_ADDR)
+#define bfin_write_DMA7_CURR_ADDR(val)       bfin_write32(DMA7_CURR_ADDR,val)
+#define bfin_read_DMA7_CURR_X_COUNT()        bfin_read16(DMA7_CURR_X_COUNT)
+#define bfin_write_DMA7_CURR_X_COUNT(val)    bfin_write16(DMA7_CURR_X_COUNT,val)
+#define bfin_read_DMA7_CURR_Y_COUNT()        bfin_read16(DMA7_CURR_Y_COUNT)
+#define bfin_write_DMA7_CURR_Y_COUNT(val)    bfin_write16(DMA7_CURR_Y_COUNT,val)
+#define bfin_read_DMA7_IRQ_STATUS()          bfin_read16(DMA7_IRQ_STATUS)
+#define bfin_write_DMA7_IRQ_STATUS(val)      bfin_write16(DMA7_IRQ_STATUS,val)
+#define bfin_read_DMA7_PERIPHERAL_MAP()      bfin_read16(DMA7_PERIPHERAL_MAP)
+#define bfin_write_DMA7_PERIPHERAL_MAP(val)  bfin_write16(DMA7_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D1_CONFIG()           bfin_read16(MDMA_D1_CONFIG)
+#define bfin_write_MDMA_D1_CONFIG(val)       bfin_write16(MDMA_D1_CONFIG,val)
+#define bfin_read_MDMA_D1_NEXT_DESC_PTR()    bfin_read32(MDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D1_START_ADDR()       bfin_read32(MDMA_D1_START_ADDR)
+#define bfin_write_MDMA_D1_START_ADDR(val)   bfin_write32(MDMA_D1_START_ADDR,val)
+#define bfin_read_MDMA_D1_X_COUNT()          bfin_read16(MDMA_D1_X_COUNT)
+#define bfin_write_MDMA_D1_X_COUNT(val)      bfin_write16(MDMA_D1_X_COUNT,val)
+#define bfin_read_MDMA_D1_Y_COUNT()          bfin_read16(MDMA_D1_Y_COUNT)
+#define bfin_write_MDMA_D1_Y_COUNT(val)      bfin_write16(MDMA_D1_Y_COUNT,val)
+#define bfin_read_MDMA_D1_X_MODIFY()         bfin_read16(MDMA_D1_X_MODIFY)
+#define bfin_write_MDMA_D1_X_MODIFY(val)     bfin_write16(MDMA_D1_X_MODIFY,val)
+#define bfin_read_MDMA_D1_Y_MODIFY()         bfin_read16(MDMA_D1_Y_MODIFY)
+#define bfin_write_MDMA_D1_Y_MODIFY(val)     bfin_write16(MDMA_D1_Y_MODIFY,val)
+#define bfin_read_MDMA_D1_CURR_DESC_PTR()    bfin_read32(MDMA_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D1_CURR_ADDR()        bfin_read32(MDMA_D1_CURR_ADDR)
+#define bfin_write_MDMA_D1_CURR_ADDR(val)    bfin_write32(MDMA_D1_CURR_ADDR,val)
+#define bfin_read_MDMA_D1_CURR_X_COUNT()     bfin_read16(MDMA_D1_CURR_X_COUNT)
+#define bfin_write_MDMA_D1_CURR_X_COUNT(val) bfin_write16(MDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D1_CURR_Y_COUNT()     bfin_read16(MDMA_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA_D1_CURR_Y_COUNT(val) bfin_write16(MDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()       bfin_read16(MDMA_D1_IRQ_STATUS)
+#define bfin_write_MDMA_D1_IRQ_STATUS(val)   bfin_write16(MDMA_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA_D1_PERIPHERAL_MAP()   bfin_read16(MDMA_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA_D1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S1_CONFIG()           bfin_read16(MDMA_S1_CONFIG)
+#define bfin_write_MDMA_S1_CONFIG(val)       bfin_write16(MDMA_S1_CONFIG,val)
+#define bfin_read_MDMA_S1_NEXT_DESC_PTR()    bfin_read32(MDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S1_START_ADDR()       bfin_read32(MDMA_S1_START_ADDR)
+#define bfin_write_MDMA_S1_START_ADDR(val)   bfin_write32(MDMA_S1_START_ADDR,val)
+#define bfin_read_MDMA_S1_X_COUNT()          bfin_read16(MDMA_S1_X_COUNT)
+#define bfin_write_MDMA_S1_X_COUNT(val)      bfin_write16(MDMA_S1_X_COUNT,val)
+#define bfin_read_MDMA_S1_Y_COUNT()          bfin_read16(MDMA_S1_Y_COUNT)
+#define bfin_write_MDMA_S1_Y_COUNT(val)      bfin_write16(MDMA_S1_Y_COUNT,val)
+#define bfin_read_MDMA_S1_X_MODIFY()         bfin_read16(MDMA_S1_X_MODIFY)
+#define bfin_write_MDMA_S1_X_MODIFY(val)     bfin_write16(MDMA_S1_X_MODIFY,val)
+#define bfin_read_MDMA_S1_Y_MODIFY()         bfin_read16(MDMA_S1_Y_MODIFY)
+#define bfin_write_MDMA_S1_Y_MODIFY(val)     bfin_write16(MDMA_S1_Y_MODIFY,val)
+#define bfin_read_MDMA_S1_CURR_DESC_PTR()    bfin_read32(MDMA_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S1_CURR_ADDR()        bfin_read32(MDMA_S1_CURR_ADDR)
+#define bfin_write_MDMA_S1_CURR_ADDR(val)    bfin_write32(MDMA_S1_CURR_ADDR,val)
+#define bfin_read_MDMA_S1_CURR_X_COUNT()     bfin_read16(MDMA_S1_CURR_X_COUNT)
+#define bfin_write_MDMA_S1_CURR_X_COUNT(val) bfin_write16(MDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S1_CURR_Y_COUNT()     bfin_read16(MDMA_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA_S1_CURR_Y_COUNT(val) bfin_write16(MDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()       bfin_read16(MDMA_S1_IRQ_STATUS)
+#define bfin_write_MDMA_S1_IRQ_STATUS(val)   bfin_write16(MDMA_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA_S1_PERIPHERAL_MAP()   bfin_read16(MDMA_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA_S1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D0_CONFIG()           bfin_read16(MDMA_D0_CONFIG)
+#define bfin_write_MDMA_D0_CONFIG(val)       bfin_write16(MDMA_D0_CONFIG,val)
+#define bfin_read_MDMA_D0_NEXT_DESC_PTR()    bfin_read32(MDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D0_START_ADDR()       bfin_read32(MDMA_D0_START_ADDR)
+#define bfin_write_MDMA_D0_START_ADDR(val)   bfin_write32(MDMA_D0_START_ADDR,val)
+#define bfin_read_MDMA_D0_X_COUNT()          bfin_read16(MDMA_D0_X_COUNT)
+#define bfin_write_MDMA_D0_X_COUNT(val)      bfin_write16(MDMA_D0_X_COUNT,val)
+#define bfin_read_MDMA_D0_Y_COUNT()          bfin_read16(MDMA_D0_Y_COUNT)
+#define bfin_write_MDMA_D0_Y_COUNT(val)      bfin_write16(MDMA_D0_Y_COUNT,val)
+#define bfin_read_MDMA_D0_X_MODIFY()         bfin_read16(MDMA_D0_X_MODIFY)
+#define bfin_write_MDMA_D0_X_MODIFY(val)     bfin_write16(MDMA_D0_X_MODIFY,val)
+#define bfin_read_MDMA_D0_Y_MODIFY()         bfin_read16(MDMA_D0_Y_MODIFY)
+#define bfin_write_MDMA_D0_Y_MODIFY(val)     bfin_write16(MDMA_D0_Y_MODIFY,val)
+#define bfin_read_MDMA_D0_CURR_DESC_PTR()    bfin_read32(MDMA_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D0_CURR_ADDR()        bfin_read32(MDMA_D0_CURR_ADDR)
+#define bfin_write_MDMA_D0_CURR_ADDR(val)    bfin_write32(MDMA_D0_CURR_ADDR,val)
+#define bfin_read_MDMA_D0_CURR_X_COUNT()     bfin_read16(MDMA_D0_CURR_X_COUNT)
+#define bfin_write_MDMA_D0_CURR_X_COUNT(val) bfin_write16(MDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D0_CURR_Y_COUNT()     bfin_read16(MDMA_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA_D0_CURR_Y_COUNT(val) bfin_write16(MDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D0_IRQ_STATUS()       bfin_read16(MDMA_D0_IRQ_STATUS)
+#define bfin_write_MDMA_D0_IRQ_STATUS(val)   bfin_write16(MDMA_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA_D0_PERIPHERAL_MAP()   bfin_read16(MDMA_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA_D0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S0_CONFIG()           bfin_read16(MDMA_S0_CONFIG)
+#define bfin_write_MDMA_S0_CONFIG(val)       bfin_write16(MDMA_S0_CONFIG,val)
+#define bfin_read_MDMA_S0_NEXT_DESC_PTR()    bfin_read32(MDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S0_START_ADDR()       bfin_read32(MDMA_S0_START_ADDR)
+#define bfin_write_MDMA_S0_START_ADDR(val)   bfin_write32(MDMA_S0_START_ADDR,val)
+#define bfin_read_MDMA_S0_X_COUNT()          bfin_read16(MDMA_S0_X_COUNT)
+#define bfin_write_MDMA_S0_X_COUNT(val)      bfin_write16(MDMA_S0_X_COUNT,val)
+#define bfin_read_MDMA_S0_Y_COUNT()          bfin_read16(MDMA_S0_Y_COUNT)
+#define bfin_write_MDMA_S0_Y_COUNT(val)      bfin_write16(MDMA_S0_Y_COUNT,val)
+#define bfin_read_MDMA_S0_X_MODIFY()         bfin_read16(MDMA_S0_X_MODIFY)
+#define bfin_write_MDMA_S0_X_MODIFY(val)     bfin_write16(MDMA_S0_X_MODIFY,val)
+#define bfin_read_MDMA_S0_Y_MODIFY()         bfin_read16(MDMA_S0_Y_MODIFY)
+#define bfin_write_MDMA_S0_Y_MODIFY(val)     bfin_write16(MDMA_S0_Y_MODIFY,val)
+#define bfin_read_MDMA_S0_CURR_DESC_PTR()    bfin_read32(MDMA_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S0_CURR_ADDR()        bfin_read32(MDMA_S0_CURR_ADDR)
+#define bfin_write_MDMA_S0_CURR_ADDR(val)    bfin_write32(MDMA_S0_CURR_ADDR,val)
+#define bfin_read_MDMA_S0_CURR_X_COUNT()     bfin_read16(MDMA_S0_CURR_X_COUNT)
+#define bfin_write_MDMA_S0_CURR_X_COUNT(val) bfin_write16(MDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S0_CURR_Y_COUNT()     bfin_read16(MDMA_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA_S0_CURR_Y_COUNT(val) bfin_write16(MDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S0_IRQ_STATUS()       bfin_read16(MDMA_S0_IRQ_STATUS)
+#define bfin_write_MDMA_S0_IRQ_STATUS(val)   bfin_write16(MDMA_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA_S0_PERIPHERAL_MAP()   bfin_read16(MDMA_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA_S0_PERIPHERAL_MAP,val)
+
+/* Aysnchronous Memory Controller - External Bus Interface Unit (0xFFC0 3C00-0xFFC0 3FFF) */
+#define bfin_read_EBIU_AMGCTL()              bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val)          bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0()             bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val)         bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1()             bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val)         bfin_write32(EBIU_AMBCTL1,val)
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC0 4C00-0xFFC0 4FFF) */
+#define bfin_read_EBIU_SDGCTL()              bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val)          bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDRRC()               bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val)           bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT()              bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val)          bfin_write16(EBIU_SDSTAT,val)
+#define bfin_read_EBIU_SDBCTL()              bfin_read16(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val)          bfin_write16(EBIU_SDBCTL,val)
+
+/* UART Controller */
+#define bfin_read_UART_THR()                 bfin_read16(UART_THR)
+#define bfin_write_UART_THR(val)             bfin_write16(UART_THR,val)
+#define bfin_read_UART_RBR()                 bfin_read16(UART_RBR)
+#define bfin_write_UART_RBR(val)             bfin_write16(UART_RBR,val)
+#define bfin_read_UART_DLL()                 bfin_read16(UART_DLL)
+#define bfin_write_UART_DLL(val)             bfin_write16(UART_DLL,val)
+#define bfin_read_UART_IER()                 bfin_read16(UART_IER)
+#define bfin_write_UART_IER(val)             bfin_write16(UART_IER,val)
+#define bfin_read_UART_DLH()                 bfin_read16(UART_DLH)
+#define bfin_write_UART_DLH(val)             bfin_write16(UART_DLH,val)
+#define bfin_read_UART_IIR()                 bfin_read16(UART_IIR)
+#define bfin_write_UART_IIR(val)             bfin_write16(UART_IIR,val)
+#define bfin_read_UART_LCR()                 bfin_read16(UART_LCR)
+#define bfin_write_UART_LCR(val)             bfin_write16(UART_LCR,val)
+#define bfin_read_UART_MCR()                 bfin_read16(UART_MCR)
+#define bfin_write_UART_MCR(val)             bfin_write16(UART_MCR,val)
+#define bfin_read_UART_LSR()                 bfin_read16(UART_LSR)
+#define bfin_write_UART_LSR(val)             bfin_write16(UART_LSR,val)
+/*
+#define UART_MSR
+*/
+#define bfin_read_UART_SCR()                 bfin_read16(UART_SCR)
+#define bfin_write_UART_SCR(val)             bfin_write16(UART_SCR,val)
+#define bfin_read_UART_GCTL()                bfin_read16(UART_GCTL)
+#define bfin_write_UART_GCTL(val)            bfin_write16(UART_GCTL,val)
+
+/* SPI Controller */
+#define bfin_read_SPI_CTL()                  bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val)              bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG()                  bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val)              bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT()                 bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val)             bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR()                 bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val)             bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR()                 bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val)             bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD()                 bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val)             bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW()               bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val)           bfin_write16(SPI_SHADOW,val)
+
+/* TIMER 0, 1, 2 Registers */
+#define bfin_read_TIMER0_CONFIG()            bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val)        bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER()           bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val)       bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD()            bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val)        bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH()             bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val)         bfin_write32(TIMER0_WIDTH,val)
+
+#define bfin_read_TIMER1_CONFIG()            bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val)        bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER()           bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val)       bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD()            bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val)        bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH()             bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val)         bfin_write32(TIMER1_WIDTH,val)
+
+#define bfin_read_TIMER2_CONFIG()            bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val)        bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER()           bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val)       bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD()            bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val)        bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH()             bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val)         bfin_write32(TIMER2_WIDTH,val)
+
+#define bfin_read_TIMER_ENABLE()             bfin_read16(TIMER_ENABLE)
+#define bfin_write_TIMER_ENABLE(val)         bfin_write16(TIMER_ENABLE,val)
+#define bfin_read_TIMER_DISABLE()            bfin_read16(TIMER_DISABLE)
+#define bfin_write_TIMER_DISABLE(val)        bfin_write16(TIMER_DISABLE,val)
+#define bfin_read_TIMER_STATUS()             bfin_read16(TIMER_STATUS)
+#define bfin_write_TIMER_STATUS(val)         bfin_write16(TIMER_STATUS,val)
+
+/* SPORT0 Controller */
+#define bfin_read_SPORT0_TCR1()              bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val)          bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2()              bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val)          bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV()           bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val)       bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV()            bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val)        bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX()                bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val)            bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX()                bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val)            bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32()              bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val)          bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32()              bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val)          bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16()              bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val)          bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16()              bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val)          bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1()              bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val)          bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2()              bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val)          bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV()           bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val)       bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV()            bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val)        bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT()              bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val)          bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL()              bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val)          bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1()             bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val)         bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2()             bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val)         bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0()             bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val)         bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1()             bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val)         bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2()             bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val)         bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3()             bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val)         bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0()             bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val)         bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1()             bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val)         bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2()             bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val)         bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3()             bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val)         bfin_write32(SPORT0_MRCS3,val)
+
+/* SPORT1 Controller */
+#define bfin_read_SPORT1_TCR1()              bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val)          bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2()              bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val)          bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV()           bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val)       bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV()            bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val)        bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX()                bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val)            bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX()                bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val)            bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32()              bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val)          bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32()              bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val)          bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16()              bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val)          bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16()              bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val)          bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1()              bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val)          bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2()              bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val)          bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV()           bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val)       bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV()            bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val)        bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT()              bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val)          bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL()              bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val)          bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1()             bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val)         bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2()             bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val)         bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0()             bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val)         bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1()             bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val)         bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2()             bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val)         bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3()             bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val)         bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0()             bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val)         bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1()             bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val)         bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2()             bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val)         bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3()             bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val)         bfin_write32(SPORT1_MRCS3,val)
+
+/* Parallel Peripheral Interface (PPI) */
+#define bfin_read_PPI_CONTROL()              bfin_read16(PPI_CONTROL)
+#define bfin_write_PPI_CONTROL(val)          bfin_write16(PPI_CONTROL,val)
+#define bfin_read_PPI_STATUS()               bfin_read16(PPI_STATUS)
+#define bfin_write_PPI_STATUS(val)           bfin_write16(PPI_STATUS,val)
+#define bfin_clear_PPI_STATUS()              bfin_read_PPI_STATUS()
+#define bfin_read_PPI_DELAY()                bfin_read16(PPI_DELAY)
+#define bfin_write_PPI_DELAY(val)            bfin_write16(PPI_DELAY,val)
+#define bfin_read_PPI_COUNT()                bfin_read16(PPI_COUNT)
+#define bfin_write_PPI_COUNT(val)            bfin_write16(PPI_COUNT,val)
+#define bfin_read_PPI_FRAME()                bfin_read16(PPI_FRAME)
+#define bfin_write_PPI_FRAME(val)            bfin_write16(PPI_FRAME,val)
+
+#endif				/* _CDEF_BF532_H */
diff --git a/include/asm-blackfin/mach-bf533/defBF532.h b/include/asm-blackfin/mach-bf533/defBF532.h
new file mode 100644
index 0000000..b240a08
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/defBF532.h
@@ -0,0 +1,1175 @@
+/************************************************************************
+ *
+ * This file is subject to the terms and conditions of the GNU Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Non-GPL License also available as part of VisualDSP++
+ * http://www.analog.com/processors/resources/crosscore/visualDspDevSoftware.html
+ *
+ * (c) Copyright 2001-2005 Analog Devices, Inc. All rights reserved
+ *
+ * This file under source code control, please send bugs or changes to:
+ * dsptools.support@analog.com
+ *
+ ************************************************************************/
+/*
+ * File:         include/asm-blackfin/mach-bf533/defBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/* SYSTEM & MM REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532 */
+
+#ifndef _DEF_BF532_H
+#define _DEF_BF532_H
+/*
+#if !defined(__ADSPLPBLACKFIN__)
+#warning defBF532.h should only be included for 532 compatible chips
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+
+#define PLL_CTL                0xFFC00000	/* PLL Control register (16-bit) */
+#define PLL_DIV			 0xFFC00004	/* PLL Divide Register (16-bit) */
+#define VR_CTL			 0xFFC00008	/* Voltage Regulator Control Register (16-bit) */
+#define PLL_STAT               0xFFC0000C	/* PLL Status register (16-bit) */
+#define PLL_LOCKCNT            0xFFC00010	/* PLL Lock Count register (16-bit) */
+#define CHIPID                 0xFFC00014       /* Chip ID Register */
+#define SWRST                  0xFFC00100	/* Software Reset Register (16-bit) */
+#define SYSCR                  0xFFC00104	/* System Configuration registe */
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF) */
+#define SIC_RVECT             		0xFFC00108	/* Interrupt Reset Vector Address Register */
+#define SIC_IMASK             		0xFFC0010C	/* Interrupt Mask Register */
+#define SIC_IAR0               		0xFFC00110	/* Interrupt Assignment Register 0 */
+#define SIC_IAR1               		0xFFC00114	/* Interrupt Assignment Register 1 */
+#define SIC_IAR2              		0xFFC00118	/* Interrupt Assignment Register 2 */
+#define SIC_ISR                		0xFFC00120	/* Interrupt Status Register */
+#define SIC_IWR                		0xFFC00124	/* Interrupt Wakeup Register */
+
+/* Watchdog Timer (0xFFC00200 - 0xFFC002FF) */
+#define WDOG_CTL                	0xFFC00200	/* Watchdog Control Register */
+#define WDOG_CNT                	0xFFC00204	/* Watchdog Count Register */
+#define WDOG_STAT               	0xFFC00208	/* Watchdog Status Register */
+
+/* Real Time Clock (0xFFC00300 - 0xFFC003FF) */
+#define RTC_STAT                	0xFFC00300	/* RTC Status Register */
+#define RTC_ICTL                	0xFFC00304	/* RTC Interrupt Control Register */
+#define RTC_ISTAT               	0xFFC00308	/* RTC Interrupt Status Register */
+#define RTC_SWCNT               	0xFFC0030C	/* RTC Stopwatch Count Register */
+#define RTC_ALARM               	0xFFC00310	/* RTC Alarm Time Register */
+#define RTC_FAST                	0xFFC00314	/* RTC Prescaler Enable Register */
+#define RTC_PREN			0xFFC00314	/* RTC Prescaler Enable Register (alternate macro) */
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define UART_THR             		 0xFFC00400	/* Transmit Holding register */
+#define UART_RBR             		 0xFFC00400	/* Receive Buffer register */
+#define UART_DLL              		 0xFFC00400	/* Divisor Latch (Low-Byte) */
+#define UART_IER              		 0xFFC00404	/* Interrupt Enable Register */
+#define UART_DLH              		 0xFFC00404	/* Divisor Latch (High-Byte) */
+#define UART_IIR              		 0xFFC00408	/* Interrupt Identification Register */
+#define UART_LCR              		 0xFFC0040C	/* Line Control Register */
+#define UART_MCR			 0xFFC00410	/* Modem Control Register */
+#define UART_LSR              		 0xFFC00414	/* Line Status Register */
+#if 0
+#define UART_MSR            		 0xFFC00418   /* Modem Status Register (UNUSED in ADSP-BF532) */
+#endif
+#define UART_SCR              		 0xFFC0041C	/* SCR Scratch Register */
+#define UART_GCTL      	      		 0xFFC00424	/* Global Control Register */
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define SPI_CTL               		0xFFC00500	/* SPI Control Register */
+#define SPI_FLG               		0xFFC00504	/* SPI Flag register */
+#define SPI_STAT              		0xFFC00508	/* SPI Status register */
+#define SPI_TDBR              		0xFFC0050C	/* SPI Transmit Data Buffer Register */
+#define SPI_RDBR              		0xFFC00510	/* SPI Receive Data Buffer Register */
+#define SPI_BAUD              		0xFFC00514	/* SPI Baud rate Register */
+#define SPI_SHADOW            		0xFFC00518	/* SPI_RDBR Shadow Register */
+
+/* TIMER 0, 1, 2 Registers (0xFFC00600 - 0xFFC006FF) */
+
+#define TIMER0_CONFIG          		0xFFC00600	/* Timer 0 Configuration Register */
+#define TIMER0_COUNTER			0xFFC00604	/* Timer 0 Counter Register */
+#define TIMER0_PERIOD       		0xFFC00608	/* Timer 0 Period Register */
+#define TIMER0_WIDTH        		0xFFC0060C	/* Timer 0 Width Register */
+
+#define TIMER1_CONFIG          		0xFFC00610	/*  Timer 1 Configuration Register   */
+#define TIMER1_COUNTER         		0xFFC00614	/*  Timer 1 Counter Register         */
+#define TIMER1_PERIOD          		0xFFC00618	/*  Timer 1 Period Register          */
+#define TIMER1_WIDTH           		0xFFC0061C	/*  Timer 1 Width Register           */
+
+#define TIMER2_CONFIG          		0xFFC00620	/* Timer 2 Configuration Register   */
+#define TIMER2_COUNTER         		0xFFC00624	/* Timer 2 Counter Register         */
+#define TIMER2_PERIOD          		0xFFC00628	/* Timer 2 Period Register          */
+#define TIMER2_WIDTH           		0xFFC0062C	/* Timer 2 Width Register           */
+
+#define TIMER_ENABLE			0xFFC00640	/* Timer Enable Register */
+#define TIMER_DISABLE			0xFFC00644	/* Timer Disable Register */
+#define TIMER_STATUS			0xFFC00648	/* Timer Status Register */
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) */
+
+#define FIO_FLAG_D	       		0xFFC00700	/* Flag Mask to directly specify state of pins */
+#define FIO_FLAG_C             		0xFFC00704	/* Peripheral Interrupt Flag Register (clear) */
+#define FIO_FLAG_S             		0xFFC00708	/* Peripheral Interrupt Flag Register (set) */
+#define FIO_FLAG_T			0xFFC0070C	/* Flag Mask to directly toggle state of pins */
+#define FIO_MASKA_D            		0xFFC00710	/* Flag Mask Interrupt A Register (set directly) */
+#define FIO_MASKA_C            		0xFFC00714	/* Flag Mask Interrupt A Register (clear) */
+#define FIO_MASKA_S            		0xFFC00718	/* Flag Mask Interrupt A Register (set) */
+#define FIO_MASKA_T            		0xFFC0071C	/* Flag Mask Interrupt A Register (toggle) */
+#define FIO_MASKB_D            		0xFFC00720	/* Flag Mask Interrupt B Register (set directly) */
+#define FIO_MASKB_C            		0xFFC00724	/* Flag Mask Interrupt B Register (clear) */
+#define FIO_MASKB_S            		0xFFC00728	/* Flag Mask Interrupt B Register (set) */
+#define FIO_MASKB_T            		0xFFC0072C	/* Flag Mask Interrupt B Register (toggle) */
+#define FIO_DIR                		0xFFC00730	/* Peripheral Flag Direction Register */
+#define FIO_POLAR              		0xFFC00734	/* Flag Source Polarity Register */
+#define FIO_EDGE               		0xFFC00738	/* Flag Source Sensitivity Register */
+#define FIO_BOTH               		0xFFC0073C	/* Flag Set on BOTH Edges Register */
+#define FIO_INEN					0xFFC00740	/* Flag Input Enable Register  */
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define SPORT0_TCR1     	 	0xFFC00800	/* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_TCR2      	 	0xFFC00804	/* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_TCLKDIV        		0xFFC00808	/* SPORT0 Transmit Clock Divider */
+#define SPORT0_TFSDIV          		0xFFC0080C	/* SPORT0 Transmit Frame Sync Divider */
+#define SPORT0_TX	             	0xFFC00810	/* SPORT0 TX Data Register */
+#define SPORT0_RX	            	0xFFC00818	/* SPORT0 RX Data Register */
+#define SPORT0_RCR1      	 	0xFFC00820	/* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_RCR2      	 	0xFFC00824	/* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_RCLKDIV        		0xFFC00828	/* SPORT0 Receive Clock Divider */
+#define SPORT0_RFSDIV          		0xFFC0082C	/* SPORT0 Receive Frame Sync Divider */
+#define SPORT0_STAT            		0xFFC00830	/* SPORT0 Status Register */
+#define SPORT0_CHNL            		0xFFC00834	/* SPORT0 Current Channel Register */
+#define SPORT0_MCMC1           		0xFFC00838	/* SPORT0 Multi-Channel Configuration Register 1 */
+#define SPORT0_MCMC2           		0xFFC0083C	/* SPORT0 Multi-Channel Configuration Register 2 */
+#define SPORT0_MTCS0           		0xFFC00840	/* SPORT0 Multi-Channel Transmit Select Register 0 */
+#define SPORT0_MTCS1           		0xFFC00844	/* SPORT0 Multi-Channel Transmit Select Register 1 */
+#define SPORT0_MTCS2           		0xFFC00848	/* SPORT0 Multi-Channel Transmit Select Register 2 */
+#define SPORT0_MTCS3           		0xFFC0084C	/* SPORT0 Multi-Channel Transmit Select Register 3 */
+#define SPORT0_MRCS0           		0xFFC00850	/* SPORT0 Multi-Channel Receive Select Register 0 */
+#define SPORT0_MRCS1           		0xFFC00854	/* SPORT0 Multi-Channel Receive Select Register 1 */
+#define SPORT0_MRCS2           		0xFFC00858	/* SPORT0 Multi-Channel Receive Select Register 2 */
+#define SPORT0_MRCS3           		0xFFC0085C	/* SPORT0 Multi-Channel Receive Select Register 3 */
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define SPORT1_TCR1     	 	0xFFC00900	/* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_TCR2      	 	0xFFC00904	/* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_TCLKDIV        		0xFFC00908	/* SPORT1 Transmit Clock Divider */
+#define SPORT1_TFSDIV          		0xFFC0090C	/* SPORT1 Transmit Frame Sync Divider */
+#define SPORT1_TX	             	0xFFC00910	/* SPORT1 TX Data Register */
+#define SPORT1_RX	            	0xFFC00918	/* SPORT1 RX Data Register */
+#define SPORT1_RCR1      	 	0xFFC00920	/* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_RCR2      	 	0xFFC00924	/* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_RCLKDIV        		0xFFC00928	/* SPORT1 Receive Clock Divider */
+#define SPORT1_RFSDIV          		0xFFC0092C	/* SPORT1 Receive Frame Sync Divider */
+#define SPORT1_STAT            		0xFFC00930	/* SPORT1 Status Register */
+#define SPORT1_CHNL            		0xFFC00934	/* SPORT1 Current Channel Register */
+#define SPORT1_MCMC1           		0xFFC00938	/* SPORT1 Multi-Channel Configuration Register 1 */
+#define SPORT1_MCMC2           		0xFFC0093C	/* SPORT1 Multi-Channel Configuration Register 2 */
+#define SPORT1_MTCS0           		0xFFC00940	/* SPORT1 Multi-Channel Transmit Select Register 0 */
+#define SPORT1_MTCS1           		0xFFC00944	/* SPORT1 Multi-Channel Transmit Select Register 1 */
+#define SPORT1_MTCS2           		0xFFC00948	/* SPORT1 Multi-Channel Transmit Select Register 2 */
+#define SPORT1_MTCS3           		0xFFC0094C	/* SPORT1 Multi-Channel Transmit Select Register 3 */
+#define SPORT1_MRCS0           		0xFFC00950	/* SPORT1 Multi-Channel Receive Select Register 0 */
+#define SPORT1_MRCS1           		0xFFC00954	/* SPORT1 Multi-Channel Receive Select Register 1 */
+#define SPORT1_MRCS2           		0xFFC00958	/* SPORT1 Multi-Channel Receive Select Register 2 */
+#define SPORT1_MRCS3           		0xFFC0095C	/* SPORT1 Multi-Channel Receive Select Register 3 */
+
+/* Asynchronous Memory Controller - External Bus Interface Unit  */
+#define EBIU_AMGCTL			0xFFC00A00	/* Asynchronous Memory Global Control Register */
+#define EBIU_AMBCTL0			0xFFC00A04	/* Asynchronous Memory Bank Control Register 0 */
+#define EBIU_AMBCTL1			0xFFC00A08	/* Asynchronous Memory Bank Control Register 1 */
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+
+#define EBIU_SDGCTL			0xFFC00A10	/* SDRAM Global Control Register */
+#define EBIU_SDBCTL			0xFFC00A14	/* SDRAM Bank Control Register */
+#define EBIU_SDRRC 			0xFFC00A18	/* SDRAM Refresh Rate Control Register */
+#define EBIU_SDSTAT			0xFFC00A1C	/* SDRAM Status Register */
+
+/* DMA Traffic controls */
+#define DMA_TCPER 0xFFC00B0C	/* Traffic Control Periods Register */
+#define DMA_TCCNT 0xFFC00B10	/* Traffic Control Current Counts Register */
+#define DMA_TC_PER 0xFFC00B0C	/* Traffic Control Periods Register */
+#define DMA_TC_CNT 0xFFC00B10	/* Traffic Control Current Counts Register */
+
+/* DMA Controller (0xFFC00C00 - 0xFFC00FFF) */
+#define DMA0_CONFIG		0xFFC00C08	/* DMA Channel 0 Configuration Register */
+#define DMA0_NEXT_DESC_PTR	0xFFC00C00	/* DMA Channel 0 Next Descriptor Pointer Register */
+#define DMA0_START_ADDR		0xFFC00C04	/* DMA Channel 0 Start Address Register */
+#define DMA0_X_COUNT		0xFFC00C10	/* DMA Channel 0 X Count Register */
+#define DMA0_Y_COUNT		0xFFC00C18	/* DMA Channel 0 Y Count Register */
+#define DMA0_X_MODIFY		0xFFC00C14	/* DMA Channel 0 X Modify Register */
+#define DMA0_Y_MODIFY		0xFFC00C1C	/* DMA Channel 0 Y Modify Register */
+#define DMA0_CURR_DESC_PTR	0xFFC00C20	/* DMA Channel 0 Current Descriptor Pointer Register */
+#define DMA0_CURR_ADDR		0xFFC00C24	/* DMA Channel 0 Current Address Register */
+#define DMA0_CURR_X_COUNT	0xFFC00C30	/* DMA Channel 0 Current X Count Register */
+#define DMA0_CURR_Y_COUNT	0xFFC00C38	/* DMA Channel 0 Current Y Count Register */
+#define DMA0_IRQ_STATUS		0xFFC00C28	/* DMA Channel 0 Interrupt/Status Register */
+#define DMA0_PERIPHERAL_MAP	0xFFC00C2C	/* DMA Channel 0 Peripheral Map Register */
+
+#define DMA1_CONFIG		0xFFC00C48	/* DMA Channel 1 Configuration Register */
+#define DMA1_NEXT_DESC_PTR	0xFFC00C40	/* DMA Channel 1 Next Descriptor Pointer Register */
+#define DMA1_START_ADDR		0xFFC00C44	/* DMA Channel 1 Start Address Register */
+#define DMA1_X_COUNT		0xFFC00C50	/* DMA Channel 1 X Count Register */
+#define DMA1_Y_COUNT		0xFFC00C58	/* DMA Channel 1 Y Count Register */
+#define DMA1_X_MODIFY		0xFFC00C54	/* DMA Channel 1 X Modify Register */
+#define DMA1_Y_MODIFY		0xFFC00C5C	/* DMA Channel 1 Y Modify Register */
+#define DMA1_CURR_DESC_PTR	0xFFC00C60	/* DMA Channel 1 Current Descriptor Pointer Register */
+#define DMA1_CURR_ADDR		0xFFC00C64	/* DMA Channel 1 Current Address Register */
+#define DMA1_CURR_X_COUNT	0xFFC00C70	/* DMA Channel 1 Current X Count Register */
+#define DMA1_CURR_Y_COUNT	0xFFC00C78	/* DMA Channel 1 Current Y Count Register */
+#define DMA1_IRQ_STATUS		0xFFC00C68	/* DMA Channel 1 Interrupt/Status Register */
+#define DMA1_PERIPHERAL_MAP	0xFFC00C6C	/* DMA Channel 1 Peripheral Map Register */
+
+#define DMA2_CONFIG		0xFFC00C88	/* DMA Channel 2 Configuration Register */
+#define DMA2_NEXT_DESC_PTR	0xFFC00C80	/* DMA Channel 2 Next Descriptor Pointer Register */
+#define DMA2_START_ADDR		0xFFC00C84	/* DMA Channel 2 Start Address Register */
+#define DMA2_X_COUNT		0xFFC00C90	/* DMA Channel 2 X Count Register */
+#define DMA2_Y_COUNT		0xFFC00C98	/* DMA Channel 2 Y Count Register */
+#define DMA2_X_MODIFY		0xFFC00C94	/* DMA Channel 2 X Modify Register */
+#define DMA2_Y_MODIFY		0xFFC00C9C	/* DMA Channel 2 Y Modify Register */
+#define DMA2_CURR_DESC_PTR	0xFFC00CA0	/* DMA Channel 2 Current Descriptor Pointer Register */
+#define DMA2_CURR_ADDR		0xFFC00CA4	/* DMA Channel 2 Current Address Register */
+#define DMA2_CURR_X_COUNT	0xFFC00CB0	/* DMA Channel 2 Current X Count Register */
+#define DMA2_CURR_Y_COUNT	0xFFC00CB8	/* DMA Channel 2 Current Y Count Register */
+#define DMA2_IRQ_STATUS		0xFFC00CA8	/* DMA Channel 2 Interrupt/Status Register */
+#define DMA2_PERIPHERAL_MAP	0xFFC00CAC	/* DMA Channel 2 Peripheral Map Register */
+
+#define DMA3_CONFIG		0xFFC00CC8	/* DMA Channel 3 Configuration Register */
+#define DMA3_NEXT_DESC_PTR	0xFFC00CC0	/* DMA Channel 3 Next Descriptor Pointer Register */
+#define DMA3_START_ADDR		0xFFC00CC4	/* DMA Channel 3 Start Address Register */
+#define DMA3_X_COUNT		0xFFC00CD0	/* DMA Channel 3 X Count Register */
+#define DMA3_Y_COUNT		0xFFC00CD8	/* DMA Channel 3 Y Count Register */
+#define DMA3_X_MODIFY		0xFFC00CD4	/* DMA Channel 3 X Modify Register */
+#define DMA3_Y_MODIFY		0xFFC00CDC	/* DMA Channel 3 Y Modify Register */
+#define DMA3_CURR_DESC_PTR	0xFFC00CE0	/* DMA Channel 3 Current Descriptor Pointer Register */
+#define DMA3_CURR_ADDR		0xFFC00CE4	/* DMA Channel 3 Current Address Register */
+#define DMA3_CURR_X_COUNT	0xFFC00CF0	/* DMA Channel 3 Current X Count Register */
+#define DMA3_CURR_Y_COUNT	0xFFC00CF8	/* DMA Channel 3 Current Y Count Register */
+#define DMA3_IRQ_STATUS		0xFFC00CE8	/* DMA Channel 3 Interrupt/Status Register */
+#define DMA3_PERIPHERAL_MAP	0xFFC00CEC	/* DMA Channel 3 Peripheral Map Register */
+
+#define DMA4_CONFIG		0xFFC00D08	/* DMA Channel 4 Configuration Register */
+#define DMA4_NEXT_DESC_PTR	0xFFC00D00	/* DMA Channel 4 Next Descriptor Pointer Register */
+#define DMA4_START_ADDR		0xFFC00D04	/* DMA Channel 4 Start Address Register */
+#define DMA4_X_COUNT		0xFFC00D10	/* DMA Channel 4 X Count Register */
+#define DMA4_Y_COUNT		0xFFC00D18	/* DMA Channel 4 Y Count Register */
+#define DMA4_X_MODIFY		0xFFC00D14	/* DMA Channel 4 X Modify Register */
+#define DMA4_Y_MODIFY		0xFFC00D1C	/* DMA Channel 4 Y Modify Register */
+#define DMA4_CURR_DESC_PTR	0xFFC00D20	/* DMA Channel 4 Current Descriptor Pointer Register */
+#define DMA4_CURR_ADDR		0xFFC00D24	/* DMA Channel 4 Current Address Register */
+#define DMA4_CURR_X_COUNT	0xFFC00D30	/* DMA Channel 4 Current X Count Register */
+#define DMA4_CURR_Y_COUNT	0xFFC00D38	/* DMA Channel 4 Current Y Count Register */
+#define DMA4_IRQ_STATUS		0xFFC00D28	/* DMA Channel 4 Interrupt/Status Register */
+#define DMA4_PERIPHERAL_MAP	0xFFC00D2C	/* DMA Channel 4 Peripheral Map Register */
+
+#define DMA5_CONFIG		0xFFC00D48	/* DMA Channel 5 Configuration Register */
+#define DMA5_NEXT_DESC_PTR	0xFFC00D40	/* DMA Channel 5 Next Descriptor Pointer Register */
+#define DMA5_START_ADDR		0xFFC00D44	/* DMA Channel 5 Start Address Register */
+#define DMA5_X_COUNT		0xFFC00D50	/* DMA Channel 5 X Count Register */
+#define DMA5_Y_COUNT		0xFFC00D58	/* DMA Channel 5 Y Count Register */
+#define DMA5_X_MODIFY		0xFFC00D54	/* DMA Channel 5 X Modify Register */
+#define DMA5_Y_MODIFY		0xFFC00D5C	/* DMA Channel 5 Y Modify Register */
+#define DMA5_CURR_DESC_PTR	0xFFC00D60	/* DMA Channel 5 Current Descriptor Pointer Register */
+#define DMA5_CURR_ADDR		0xFFC00D64	/* DMA Channel 5 Current Address Register */
+#define DMA5_CURR_X_COUNT	0xFFC00D70	/* DMA Channel 5 Current X Count Register */
+#define DMA5_CURR_Y_COUNT	0xFFC00D78	/* DMA Channel 5 Current Y Count Register */
+#define DMA5_IRQ_STATUS		0xFFC00D68	/* DMA Channel 5 Interrupt/Status Register */
+#define DMA5_PERIPHERAL_MAP	0xFFC00D6C	/* DMA Channel 5 Peripheral Map Register */
+
+#define DMA6_CONFIG		0xFFC00D88	/* DMA Channel 6 Configuration Register */
+#define DMA6_NEXT_DESC_PTR	0xFFC00D80	/* DMA Channel 6 Next Descriptor Pointer Register */
+#define DMA6_START_ADDR		0xFFC00D84	/* DMA Channel 6 Start Address Register */
+#define DMA6_X_COUNT		0xFFC00D90	/* DMA Channel 6 X Count Register */
+#define DMA6_Y_COUNT		0xFFC00D98	/* DMA Channel 6 Y Count Register */
+#define DMA6_X_MODIFY		0xFFC00D94	/* DMA Channel 6 X Modify Register */
+#define DMA6_Y_MODIFY		0xFFC00D9C	/* DMA Channel 6 Y Modify Register */
+#define DMA6_CURR_DESC_PTR	0xFFC00DA0	/* DMA Channel 6 Current Descriptor Pointer Register */
+#define DMA6_CURR_ADDR		0xFFC00DA4	/* DMA Channel 6 Current Address Register */
+#define DMA6_CURR_X_COUNT	0xFFC00DB0	/* DMA Channel 6 Current X Count Register */
+#define DMA6_CURR_Y_COUNT	0xFFC00DB8	/* DMA Channel 6 Current Y Count Register */
+#define DMA6_IRQ_STATUS		0xFFC00DA8	/* DMA Channel 6 Interrupt/Status Register */
+#define DMA6_PERIPHERAL_MAP	0xFFC00DAC	/* DMA Channel 6 Peripheral Map Register */
+
+#define DMA7_CONFIG		0xFFC00DC8	/* DMA Channel 7 Configuration Register */
+#define DMA7_NEXT_DESC_PTR	0xFFC00DC0	/* DMA Channel 7 Next Descriptor Pointer Register */
+#define DMA7_START_ADDR		0xFFC00DC4	/* DMA Channel 7 Start Address Register */
+#define DMA7_X_COUNT		0xFFC00DD0	/* DMA Channel 7 X Count Register */
+#define DMA7_Y_COUNT		0xFFC00DD8	/* DMA Channel 7 Y Count Register */
+#define DMA7_X_MODIFY		0xFFC00DD4	/* DMA Channel 7 X Modify Register */
+#define DMA7_Y_MODIFY		0xFFC00DDC	/* DMA Channel 7 Y Modify Register */
+#define DMA7_CURR_DESC_PTR	0xFFC00DE0	/* DMA Channel 7 Current Descriptor Pointer Register */
+#define DMA7_CURR_ADDR		0xFFC00DE4	/* DMA Channel 7 Current Address Register */
+#define DMA7_CURR_X_COUNT	0xFFC00DF0	/* DMA Channel 7 Current X Count Register */
+#define DMA7_CURR_Y_COUNT	0xFFC00DF8	/* DMA Channel 7 Current Y Count Register */
+#define DMA7_IRQ_STATUS		0xFFC00DE8	/* DMA Channel 7 Interrupt/Status Register */
+#define DMA7_PERIPHERAL_MAP	0xFFC00DEC	/* DMA Channel 7 Peripheral Map Register */
+
+#define MDMA_D1_CONFIG		0xFFC00E88	/* MemDMA Stream 1 Destination Configuration Register */
+#define MDMA_D1_NEXT_DESC_PTR	0xFFC00E80	/* MemDMA Stream 1 Destination Next Descriptor Pointer Register */
+#define MDMA_D1_START_ADDR	0xFFC00E84	/* MemDMA Stream 1 Destination Start Address Register */
+#define MDMA_D1_X_COUNT		0xFFC00E90	/* MemDMA Stream 1 Destination X Count Register */
+#define MDMA_D1_Y_COUNT		0xFFC00E98	/* MemDMA Stream 1 Destination Y Count Register */
+#define MDMA_D1_X_MODIFY	0xFFC00E94	/* MemDMA Stream 1 Destination X Modify Register */
+#define MDMA_D1_Y_MODIFY	0xFFC00E9C	/* MemDMA Stream 1 Destination Y Modify Register */
+#define MDMA_D1_CURR_DESC_PTR	0xFFC00EA0	/* MemDMA Stream 1 Destination Current Descriptor Pointer Register */
+#define MDMA_D1_CURR_ADDR	0xFFC00EA4	/* MemDMA Stream 1 Destination Current Address Register */
+#define MDMA_D1_CURR_X_COUNT	0xFFC00EB0	/* MemDMA Stream 1 Destination Current X Count Register */
+#define MDMA_D1_CURR_Y_COUNT	0xFFC00EB8	/* MemDMA Stream 1 Destination Current Y Count Register */
+#define MDMA_D1_IRQ_STATUS	0xFFC00EA8	/* MemDMA Stream 1 Destination Interrupt/Status Register */
+#define MDMA_D1_PERIPHERAL_MAP	0xFFC00EAC	/* MemDMA Stream 1 Destination Peripheral Map Register */
+
+#define MDMA_S1_CONFIG		0xFFC00EC8	/* MemDMA Stream 1 Source Configuration Register */
+#define MDMA_S1_NEXT_DESC_PTR	0xFFC00EC0	/* MemDMA Stream 1 Source Next Descriptor Pointer Register */
+#define MDMA_S1_START_ADDR	0xFFC00EC4	/* MemDMA Stream 1 Source Start Address Register */
+#define MDMA_S1_X_COUNT		0xFFC00ED0	/* MemDMA Stream 1 Source X Count Register */
+#define MDMA_S1_Y_COUNT		0xFFC00ED8	/* MemDMA Stream 1 Source Y Count Register */
+#define MDMA_S1_X_MODIFY	0xFFC00ED4	/* MemDMA Stream 1 Source X Modify Register */
+#define MDMA_S1_Y_MODIFY	0xFFC00EDC	/* MemDMA Stream 1 Source Y Modify Register */
+#define MDMA_S1_CURR_DESC_PTR	0xFFC00EE0	/* MemDMA Stream 1 Source Current Descriptor Pointer Register */
+#define MDMA_S1_CURR_ADDR	0xFFC00EE4	/* MemDMA Stream 1 Source Current Address Register */
+#define MDMA_S1_CURR_X_COUNT	0xFFC00EF0	/* MemDMA Stream 1 Source Current X Count Register */
+#define MDMA_S1_CURR_Y_COUNT	0xFFC00EF8	/* MemDMA Stream 1 Source Current Y Count Register */
+#define MDMA_S1_IRQ_STATUS	0xFFC00EE8	/* MemDMA Stream 1 Source Interrupt/Status Register */
+#define MDMA_S1_PERIPHERAL_MAP	0xFFC00EEC	/* MemDMA Stream 1 Source Peripheral Map Register */
+
+#define MDMA_D0_CONFIG		0xFFC00E08	/* MemDMA Stream 0 Destination Configuration Register */
+#define MDMA_D0_NEXT_DESC_PTR	0xFFC00E00	/* MemDMA Stream 0 Destination Next Descriptor Pointer Register */
+#define MDMA_D0_START_ADDR	0xFFC00E04	/* MemDMA Stream 0 Destination Start Address Register */
+#define MDMA_D0_X_COUNT		0xFFC00E10	/* MemDMA Stream 0 Destination X Count Register */
+#define MDMA_D0_Y_COUNT		0xFFC00E18	/* MemDMA Stream 0 Destination Y Count Register */
+#define MDMA_D0_X_MODIFY	0xFFC00E14	/* MemDMA Stream 0 Destination X Modify Register */
+#define MDMA_D0_Y_MODIFY	0xFFC00E1C	/* MemDMA Stream 0 Destination Y Modify Register */
+#define MDMA_D0_CURR_DESC_PTR	0xFFC00E20	/* MemDMA Stream 0 Destination Current Descriptor Pointer Register */
+#define MDMA_D0_CURR_ADDR	0xFFC00E24	/* MemDMA Stream 0 Destination Current Address Register */
+#define MDMA_D0_CURR_X_COUNT	0xFFC00E30	/* MemDMA Stream 0 Destination Current X Count Register */
+#define MDMA_D0_CURR_Y_COUNT	0xFFC00E38	/* MemDMA Stream 0 Destination Current Y Count Register */
+#define MDMA_D0_IRQ_STATUS	0xFFC00E28	/* MemDMA Stream 0 Destination Interrupt/Status Register */
+#define MDMA_D0_PERIPHERAL_MAP	0xFFC00E2C	/* MemDMA Stream 0 Destination Peripheral Map Register */
+
+#define MDMA_S0_CONFIG		0xFFC00E48	/* MemDMA Stream 0 Source Configuration Register */
+#define MDMA_S0_NEXT_DESC_PTR	0xFFC00E40	/* MemDMA Stream 0 Source Next Descriptor Pointer Register */
+#define MDMA_S0_START_ADDR	0xFFC00E44	/* MemDMA Stream 0 Source Start Address Register */
+#define MDMA_S0_X_COUNT		0xFFC00E50	/* MemDMA Stream 0 Source X Count Register */
+#define MDMA_S0_Y_COUNT		0xFFC00E58	/* MemDMA Stream 0 Source Y Count Register */
+#define MDMA_S0_X_MODIFY	0xFFC00E54	/* MemDMA Stream 0 Source X Modify Register */
+#define MDMA_S0_Y_MODIFY	0xFFC00E5C	/* MemDMA Stream 0 Source Y Modify Register */
+#define MDMA_S0_CURR_DESC_PTR	0xFFC00E60	/* MemDMA Stream 0 Source Current Descriptor Pointer Register */
+#define MDMA_S0_CURR_ADDR	0xFFC00E64	/* MemDMA Stream 0 Source Current Address Register */
+#define MDMA_S0_CURR_X_COUNT	0xFFC00E70	/* MemDMA Stream 0 Source Current X Count Register */
+#define MDMA_S0_CURR_Y_COUNT	0xFFC00E78	/* MemDMA Stream 0 Source Current Y Count Register */
+#define MDMA_S0_IRQ_STATUS	0xFFC00E68	/* MemDMA Stream 0 Source Interrupt/Status Register */
+#define MDMA_S0_PERIPHERAL_MAP	0xFFC00E6C	/* MemDMA Stream 0 Source Peripheral Map Register */
+
+/* Parallel Peripheral Interface (PPI) (0xFFC01000 - 0xFFC010FF) */
+
+#define PPI_CONTROL			0xFFC01000	/* PPI Control Register */
+#define PPI_STATUS			0xFFC01004	/* PPI Status Register */
+#define PPI_COUNT			0xFFC01008	/* PPI Transfer Count Register */
+#define PPI_DELAY			0xFFC0100C	/* PPI Delay Count Register */
+#define PPI_FRAME			0xFFC01010	/* PPI Frame Length Register */
+
+/*********************************************************************************** */
+/* System MMR Register Bits */
+/******************************************************************************* */
+
+/* ********************* PLL AND RESET MASKS ************************ */
+
+/* PLL_CTL Masks */
+#define PLL_CLKIN              0x00000000	/* Pass CLKIN to PLL */
+#define PLL_CLKIN_DIV2         0x00000001	/* Pass CLKIN/2 to PLL */
+#define PLL_OFF                0x00000002	/* Shut off PLL clocks */
+#define STOPCK_OFF             0x00000008	/* Core clock off */
+#define PDWN                   0x00000020	/* Put the PLL in a Deep Sleep state */
+#define BYPASS                 0x00000100	/* Bypass the PLL */
+
+/* PLL_DIV Masks */
+
+#define SCLK_DIV(x)  (x)	/* SCLK = VCO / x */
+
+#define CCLK_DIV1              0x00000000	/* CCLK = VCO / 1 */
+#define CCLK_DIV2              0x00000010	/* CCLK = VCO / 2 */
+#define CCLK_DIV4              0x00000020	/* CCLK = VCO / 4 */
+#define CCLK_DIV8              0x00000030	/* CCLK = VCO / 8 */
+
+/* PLL_STAT Masks																	*/
+#define ACTIVE_PLLENABLED	0x0001	/* Processor In Active Mode With PLL Enabled    */
+#define	FULL_ON				0x0002	/* Processor In Full On Mode                                    */
+#define ACTIVE_PLLDISABLED	0x0004	/* Processor In Active Mode With PLL Disabled   */
+#define	PLL_LOCKED			0x0020	/* PLL_LOCKCNT Has Been Reached                                 */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION         0xF0000000
+#define CHIPID_FAMILY          0x0FFFF000
+#define CHIPID_MANUFACTURE     0x00000FFE
+
+/* SWRST Mask */
+#define SYSTEM_RESET           0x00000007	/* Initiates a system software reset */
+
+/* *************  SYSTEM INTERRUPT CONTROLLER MASKS ***************** */
+
+    /* SIC_IAR0 Masks */
+
+#define P0_IVG(x)    ((x)-7)	/* Peripheral #0 assigned IVG #x  */
+#define P1_IVG(x)    ((x)-7) << 0x4	/* Peripheral #1 assigned IVG #x  */
+#define P2_IVG(x)    ((x)-7) << 0x8	/* Peripheral #2 assigned IVG #x  */
+#define P3_IVG(x)    ((x)-7) << 0xC	/* Peripheral #3 assigned IVG #x  */
+#define P4_IVG(x)    ((x)-7) << 0x10	/* Peripheral #4 assigned IVG #x  */
+#define P5_IVG(x)    ((x)-7) << 0x14	/* Peripheral #5 assigned IVG #x  */
+#define P6_IVG(x)    ((x)-7) << 0x18	/* Peripheral #6 assigned IVG #x  */
+#define P7_IVG(x)    ((x)-7) << 0x1C	/* Peripheral #7 assigned IVG #x  */
+
+/* SIC_IAR1 Masks */
+
+#define P8_IVG(x)     ((x)-7)	/* Peripheral #8 assigned IVG #x  */
+#define P9_IVG(x)     ((x)-7) << 0x4	/* Peripheral #9 assigned IVG #x  */
+#define P10_IVG(x)    ((x)-7) << 0x8	/* Peripheral #10 assigned IVG #x  */
+#define P11_IVG(x)    ((x)-7) << 0xC	/* Peripheral #11 assigned IVG #x  */
+#define P12_IVG(x)    ((x)-7) << 0x10	/* Peripheral #12 assigned IVG #x  */
+#define P13_IVG(x)    ((x)-7) << 0x14	/* Peripheral #13 assigned IVG #x  */
+#define P14_IVG(x)    ((x)-7) << 0x18	/* Peripheral #14 assigned IVG #x  */
+#define P15_IVG(x)    ((x)-7) << 0x1C	/* Peripheral #15 assigned IVG #x  */
+
+/* SIC_IAR2 Masks */
+#define P16_IVG(x)    ((x)-7)	/* Peripheral #16 assigned IVG #x  */
+#define P17_IVG(x)    ((x)-7) << 0x4	/* Peripheral #17 assigned IVG #x  */
+#define P18_IVG(x)    ((x)-7) << 0x8	/* Peripheral #18 assigned IVG #x  */
+#define P19_IVG(x)    ((x)-7) << 0xC	/* Peripheral #19 assigned IVG #x  */
+#define P20_IVG(x)    ((x)-7) << 0x10	/* Peripheral #20 assigned IVG #x  */
+#define P21_IVG(x)    ((x)-7) << 0x14	/* Peripheral #21 assigned IVG #x  */
+#define P22_IVG(x)    ((x)-7) << 0x18	/* Peripheral #22 assigned IVG #x  */
+#define P23_IVG(x)    ((x)-7) << 0x1C	/* Peripheral #23 assigned IVG #x  */
+
+/* SIC_IMASK Masks */
+#define SIC_UNMASK_ALL         0x00000000	/* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL           0xFFFFFFFF	/* Mask all peripheral interrupts */
+#define SIC_MASK(x)	       (1 << (x))	/* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << (x)))	/* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL        0x00000000	/* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL         0xFFFFFFFF	/* Wakeup Enable all peripherals */
+#define IWR_ENABLE(x)	       (1 << (x))	/* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << (x)))	/* Wakeup Disable Peripheral #x */
+
+/* *********  WATCHDOG TIMER MASKS  ********************8 */
+
+/* Watchdog Timer WDOG_CTL Register */
+#define ICTL(x) ((x<<1) & 0x0006)
+#define ENABLE_RESET     0x00000000	/* Set Watchdog Timer to generate reset */
+#define ENABLE_NMI       0x00000002	/* Set Watchdog Timer to generate non-maskable interrupt */
+#define ENABLE_GPI       0x00000004	/* Set Watchdog Timer to generate general-purpose interrupt */
+#define DISABLE_EVT      0x00000006	/* Disable Watchdog Timer interrupts */
+
+#define TMR_EN		0x0000
+#define TMR_DIS		0x0AD0
+#define TRO		0x8000
+
+#define ICTL_P0		0x01
+#define ICTL_P1		0x02
+#define TRO_P		0x0F
+
+/* ***************************** UART CONTROLLER MASKS ********************** */
+
+/* UART_LCR Register */
+
+#define DLAB	0x80
+#define SB      0x40
+#define STP      0x20
+#define EPS     0x10
+#define PEN	0x08
+#define STB	0x04
+#define WLS(x)	((x-5) & 0x03)
+
+#define DLAB_P	0x07
+#define SB_P	0x06
+#define STP_P	0x05
+#define EPS_P	0x04
+#define PEN_P	0x03
+#define STB_P	0x02
+#define WLS_P1	0x01
+#define WLS_P0	0x00
+
+/* UART_MCR Register */
+#define LOOP_ENA	0x10
+#define LOOP_ENA_P	0x04
+
+/* UART_LSR Register */
+#define TEMT	0x40
+#define THRE	0x20
+#define BI	0x10
+#define FE	0x08
+#define PE	0x04
+#define OE	0x02
+#define DR	0x01
+
+#define TEMP_P	0x06
+#define THRE_P	0x05
+#define BI_P	0x04
+#define FE_P	0x03
+#define PE_P	0x02
+#define OE_P	0x01
+#define DR_P	0x00
+
+/* UART_IER Register */
+#define ELSI	0x04
+#define ETBEI	0x02
+#define ERBFI	0x01
+
+#define ELSI_P	0x02
+#define ETBEI_P	0x01
+#define ERBFI_P	0x00
+
+/* UART_IIR Register */
+#define STATUS(x)	((x << 1) & 0x06)
+#define NINT		0x01
+#define STATUS_P1	0x02
+#define STATUS_P0	0x01
+#define NINT_P		0x00
+#define IIR_TX_READY    0x02	/* UART_THR empty                               */
+#define IIR_RX_READY    0x04	/* Receive data ready                           */
+#define IIR_LINE_CHANGE 0x06	/* Receive line status                          */
+#define IIR_STATUS	0x06
+
+/* UART_GCTL Register */
+#define FFE	0x20
+#define FPE	0x10
+#define RPOLC	0x08
+#define TPOLC	0x04
+#define IREN	0x02
+#define UCEN	0x01
+
+#define FFE_P	0x05
+#define FPE_P	0x04
+#define RPOLC_P	0x03
+#define TPOLC_P	0x02
+#define IREN_P	0x01
+#define UCEN_P	0x00
+
+/* **********  SERIAL PORT MASKS  ********************** */
+
+/* SPORTx_TCR1 Masks */
+#define TSPEN    0x0001		/* TX enable  */
+#define ITCLK    0x0002		/* Internal TX Clock Select  */
+#define TDTYPE   0x000C		/* TX Data Formatting Select */
+#define TLSBIT   0x0010		/* TX Bit Order */
+#define ITFS     0x0200		/* Internal TX Frame Sync Select  */
+#define TFSR     0x0400		/* TX Frame Sync Required Select  */
+#define DITFS    0x0800		/* Data Independent TX Frame Sync Select  */
+#define LTFS     0x1000		/* Low TX Frame Sync Select  */
+#define LATFS    0x2000		/* Late TX Frame Sync Select  */
+#define TCKFE    0x4000		/* TX Clock Falling Edge Select  */
+
+/* SPORTx_TCR2 Masks */
+#define SLEN	    0x001F	/*TX Word Length  */
+#define TXSE        0x0100	/*TX Secondary Enable */
+#define TSFSE       0x0200	/*TX Stereo Frame Sync Enable */
+#define TRFST       0x0400	/*TX Right-First Data Order  */
+
+/* SPORTx_RCR1 Masks */
+#define RSPEN    0x0001		/* RX enable  */
+#define IRCLK    0x0002		/* Internal RX Clock Select  */
+#define RDTYPE   0x000C		/* RX Data Formatting Select */
+#define RULAW    0x0008		/* u-Law enable  */
+#define RALAW    0x000C		/* A-Law enable  */
+#define RLSBIT   0x0010		/* RX Bit Order */
+#define IRFS     0x0200		/* Internal RX Frame Sync Select  */
+#define RFSR     0x0400		/* RX Frame Sync Required Select  */
+#define LRFS     0x1000		/* Low RX Frame Sync Select  */
+#define LARFS    0x2000		/* Late RX Frame Sync Select  */
+#define RCKFE    0x4000		/* RX Clock Falling Edge Select  */
+
+/* SPORTx_RCR2 Masks */
+#define SLEN	    0x001F	/*RX Word Length  */
+#define RXSE        0x0100	/*RX Secondary Enable */
+#define RSFSE       0x0200	/*RX Stereo Frame Sync Enable */
+#define RRFST       0x0400	/*Right-First Data Order  */
+
+/*SPORTx_STAT Masks */
+#define RXNE		0x0001	/*RX FIFO Not Empty Status */
+#define RUVF	    	0x0002	/*RX Underflow Status */
+#define ROVF		0x0004	/*RX Overflow Status */
+#define TXF		0x0008	/*TX FIFO Full Status */
+#define TUVF         	0x0010	/*TX Underflow Status */
+#define TOVF         	0x0020	/*TX Overflow Status */
+#define TXHRE        	0x0040	/*TX Hold Register Empty */
+
+/*SPORTx_MCMC1 Masks */
+#define SP_WSIZE		0x0000F000	/*Multichannel Window Size Field */
+#define SP_WOFF		0x000003FF	/*Multichannel Window Offset Field */
+
+/*SPORTx_MCMC2 Masks */
+#define MCCRM		0x00000003	/*Multichannel Clock Recovery Mode */
+#define MCDTXPE		0x00000004	/*Multichannel DMA Transmit Packing */
+#define MCDRXPE		0x00000008	/*Multichannel DMA Receive Packing */
+#define MCMEN		0x00000010	/*Multichannel Frame Mode Enable */
+#define FSDR		0x00000080	/*Multichannel Frame Sync to Data Relationship */
+#define MFD		0x0000F000	/*Multichannel Frame Delay    */
+
+/*  *********  PARALLEL PERIPHERAL INTERFACE (PPI) MASKS ****************   */
+
+/*  PPI_CONTROL Masks         */
+#define PORT_EN              0x00000001	/* PPI Port Enable  */
+#define PORT_DIR             0x00000002	/* PPI Port Direction       */
+#define XFR_TYPE             0x0000000C	/* PPI Transfer Type  */
+#define PORT_CFG             0x00000030	/* PPI Port Configuration */
+#define FLD_SEL              0x00000040	/* PPI Active Field Select */
+#define PACK_EN              0x00000080	/* PPI Packing Mode */
+#define DMA32                0x00000100	/* PPI 32-bit DMA Enable */
+#define SKIP_EN              0x00000200	/* PPI Skip Element Enable */
+#define SKIP_EO              0x00000400	/* PPI Skip Even/Odd Elements */
+#define DLENGTH              0x00003800	/* PPI Data Length  */
+#define DLEN_8			0x0000	/* Data Length = 8 Bits                         */
+#define DLEN_10			0x0800	/* Data Length = 10 Bits                        */
+#define DLEN_11			0x1000	/* Data Length = 11 Bits                        */
+#define DLEN_12			0x1800	/* Data Length = 12 Bits                        */
+#define DLEN_13			0x2000	/* Data Length = 13 Bits                        */
+#define DLEN_14			0x2800	/* Data Length = 14 Bits                        */
+#define DLEN_15			0x3000	/* Data Length = 15 Bits                        */
+#define DLEN_16			0x3800	/* Data Length = 16 Bits                        */
+#define DLEN(x)	(((x-9) & 0x07) << 11)	/* PPI Data Length (only works for x=10-->x=16) */
+#define POL                  0x0000C000	/* PPI Signal Polarities       */
+
+/* PPI_STATUS Masks                                          */
+#define FLD	             0x00000400	/* Field Indicator   */
+#define FT_ERR	             0x00000800	/* Frame Track Error */
+#define OVR	             0x00001000	/* FIFO Overflow Error */
+#define UNDR	             0x00002000	/* FIFO Underrun Error */
+#define ERR_DET	      	     0x00004000	/* Error Detected Indicator */
+#define ERR_NCOR	     0x00008000	/* Error Not Corrected Indicator */
+
+/* **********  DMA CONTROLLER MASKS  *********************8 */
+
+/*DMAx_CONFIG, MDMA_yy_CONFIG Masks */
+#define DMAEN	        0x00000001	/* Channel Enable */
+#define WNR	   	0x00000002	/* Channel Direction (W/R*) */
+#define WDSIZE_8	0x00000000	/* Word Size 8 bits */
+#define WDSIZE_16	0x00000004	/* Word Size 16 bits */
+#define WDSIZE_32	0x00000008	/* Word Size 32 bits */
+#define DMA2D	        0x00000010	/* 2D/1D* Mode */
+#define RESTART         0x00000020	/* Restart */
+#define DI_SEL	        0x00000040	/* Data Interrupt Select */
+#define DI_EN	        0x00000080	/* Data Interrupt Enable */
+#define NDSIZE_0		0x0000	/* Next Descriptor Size = 0 (Stop/Autobuffer)   */
+#define NDSIZE_1		0x0100	/* Next Descriptor Size = 1                                             */
+#define NDSIZE_2		0x0200	/* Next Descriptor Size = 2                                             */
+#define NDSIZE_3		0x0300	/* Next Descriptor Size = 3                                             */
+#define NDSIZE_4		0x0400	/* Next Descriptor Size = 4                                             */
+#define NDSIZE_5		0x0500	/* Next Descriptor Size = 5                                             */
+#define NDSIZE_6		0x0600	/* Next Descriptor Size = 6                                             */
+#define NDSIZE_7		0x0700	/* Next Descriptor Size = 7                                             */
+#define NDSIZE_8		0x0800	/* Next Descriptor Size = 8                                             */
+#define NDSIZE_9		0x0900	/* Next Descriptor Size = 9                                             */
+#define NDSIZE	        0x00000900	/* Next Descriptor Size */
+#define DMAFLOW	        0x00007000	/* Flow Control */
+#define DMAFLOW_STOP		0x0000	/* Stop Mode */
+#define DMAFLOW_AUTO		0x1000	/* Autobuffer Mode */
+#define DMAFLOW_ARRAY		0x4000	/* Descriptor Array Mode */
+#define DMAFLOW_SMALL		0x6000	/* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE		0x7000	/* Large Model Descriptor List Mode */
+
+#define DMAEN_P	            	0	/* Channel Enable */
+#define WNR_P	            	1	/* Channel Direction (W/R*) */
+#define DMA2D_P	        	4	/* 2D/1D* Mode */
+#define RESTART_P	      	5	/* Restart */
+#define DI_SEL_P	     	6	/* Data Interrupt Select */
+#define DI_EN_P	            	7	/* Data Interrupt Enable */
+
+/*DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS Masks */
+
+#define DMA_DONE		0x00000001	/* DMA Done Indicator */
+#define DMA_ERR	        	0x00000002	/* DMA Error Indicator */
+#define DFETCH	            	0x00000004	/* Descriptor Fetch Indicator */
+#define DMA_RUN	            	0x00000008	/* DMA Running Indicator */
+
+#define DMA_DONE_P	    	0	/* DMA Done Indicator */
+#define DMA_ERR_P     		1	/* DMA Error Indicator */
+#define DFETCH_P     		2	/* Descriptor Fetch Indicator */
+#define DMA_RUN_P     		3	/* DMA Running Indicator */
+
+/*DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP Masks */
+
+#define CTYPE	            0x00000040	/* DMA Channel Type Indicator */
+#define CTYPE_P             6	/* DMA Channel Type Indicator BIT POSITION */
+#define PCAP8	            0x00000080	/* DMA 8-bit Operation Indicator   */
+#define PCAP16	            0x00000100	/* DMA 16-bit Operation Indicator */
+#define PCAP32	            0x00000200	/* DMA 32-bit Operation Indicator */
+#define PCAPWR	            0x00000400	/* DMA Write Operation Indicator */
+#define PCAPRD	            0x00000800	/* DMA Read Operation Indicator */
+#define PMAP	            0x00007000	/* DMA Peripheral Map Field */
+
+/*  *************  GENERAL PURPOSE TIMER MASKS  ******************** */
+
+/* PWM Timer bit definitions */
+
+/* TIMER_ENABLE Register */
+#define TIMEN0	0x0001
+#define TIMEN1	0x0002
+#define TIMEN2	0x0004
+
+#define TIMEN0_P	0x00
+#define TIMEN1_P	0x01
+#define TIMEN2_P	0x02
+
+/* TIMER_DISABLE Register */
+#define TIMDIS0	0x0001
+#define TIMDIS1	0x0002
+#define TIMDIS2	0x0004
+
+#define TIMDIS0_P	0x00
+#define TIMDIS1_P	0x01
+#define TIMDIS2_P	0x02
+
+/* TIMER_STATUS Register */
+#define TIMIL0		0x0001
+#define TIMIL1		0x0002
+#define TIMIL2		0x0004
+#define TOVL_ERR0	0x0010
+#define TOVL_ERR1	0x0020
+#define TOVL_ERR2	0x0040
+#define TRUN0		0x1000
+#define TRUN1		0x2000
+#define TRUN2		0x4000
+
+#define TIMIL0_P	0x00
+#define TIMIL1_P	0x01
+#define TIMIL2_P	0x02
+#define TOVL_ERR0_P	0x04
+#define TOVL_ERR1_P	0x05
+#define TOVL_ERR2_P	0x06
+#define TRUN0_P		0x0C
+#define TRUN1_P		0x0D
+#define TRUN2_P		0x0E
+
+/* TIMERx_CONFIG Registers */
+#define PWM_OUT		0x0001
+#define WDTH_CAP	0x0002
+#define EXT_CLK		0x0003
+#define PULSE_HI	0x0004
+#define PERIOD_CNT	0x0008
+#define IRQ_ENA		0x0010
+#define TIN_SEL		0x0020
+#define OUT_DIS		0x0040
+#define CLK_SEL		0x0080
+#define TOGGLE_HI	0x0100
+#define EMU_RUN		0x0200
+#define ERR_TYP(x)	((x & 0x03) << 14)
+
+#define TMODE_P0		0x00
+#define TMODE_P1		0x01
+#define PULSE_HI_P		0x02
+#define PERIOD_CNT_P		0x03
+#define IRQ_ENA_P		0x04
+#define TIN_SEL_P		0x05
+#define OUT_DIS_P		0x06
+#define CLK_SEL_P		0x07
+#define TOGGLE_HI_P		0x08
+#define EMU_RUN_P		0x09
+#define ERR_TYP_P0		0x0E
+#define ERR_TYP_P1		0x0F
+
+/*/ ******************   PROGRAMMABLE FLAG MASKS  ********************* */
+
+/*  General Purpose IO (0xFFC00700 - 0xFFC007FF)  Masks */
+#define PF0         0x0001
+#define PF1         0x0002
+#define PF2         0x0004
+#define PF3         0x0008
+#define PF4         0x0010
+#define PF5         0x0020
+#define PF6         0x0040
+#define PF7         0x0080
+#define PF8         0x0100
+#define PF9         0x0200
+#define PF10        0x0400
+#define PF11        0x0800
+#define PF12        0x1000
+#define PF13        0x2000
+#define PF14        0x4000
+#define PF15        0x8000
+
+/*  General Purpose IO (0xFFC00700 - 0xFFC007FF)  BIT POSITIONS */
+#define PF0_P         0
+#define PF1_P         1
+#define PF2_P         2
+#define PF3_P         3
+#define PF4_P         4
+#define PF5_P         5
+#define PF6_P         6
+#define PF7_P         7
+#define PF8_P         8
+#define PF9_P         9
+#define PF10_P        10
+#define PF11_P        11
+#define PF12_P        12
+#define PF13_P        13
+#define PF14_P        14
+#define PF15_P        15
+
+/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  **************** */
+
+/* SPI_CTL Masks */
+#define TIMOD                  0x00000003	/* Transfer initiation mode and interrupt generation */
+#define SZ                     0x00000004	/* Send Zero (=0) or last (=1) word when TDBR empty. */
+#define GM                     0x00000008	/* When RDBR full, get more (=1) data or discard (=0) incoming Data */
+#define PSSE                   0x00000010	/* Enable (=1) Slave-Select input for Master. */
+#define EMISO                  0x00000020	/* Enable (=1) MISO pin as an output. */
+#define SPI_LEN                0x00000100	/* Word length (0 => 8 bits, 1 => 16 bits) */
+#define LSBF                   0x00000200	/* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
+#define CPHA                   0x00000400	/* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
+#define CPOL                   0x00000800	/* Clock polarity (0 => active-high, 1 => active-low) */
+#define MSTR                   0x00001000	/* Configures SPI as master (=1) or slave (=0) */
+#define WOM                    0x00002000	/* Open drain (=1) data output enable (for MOSI and MISO) */
+#define SPE                    0x00004000	/* SPI module enable (=1), disable (=0) */
+
+/* SPI_FLG Masks */
+#define FLS1                   0x00000002	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2                   0x00000004	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3                   0x00000008	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4                   0x00000010	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5                   0x00000020	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6                   0x00000040	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7                   0x00000080	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1                   0x00000200	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
+#define FLG2                   0x00000400	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3                   0x00000800	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
+#define FLG4                   0x00001000	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
+#define FLG5                   0x00002000	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
+#define FLG6                   0x00004000	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
+#define FLG7                   0x00008000	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_FLG Bit Positions */
+#define FLS1_P                 0x00000001	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2_P                 0x00000002	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3_P                 0x00000003	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4_P                 0x00000004	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5_P                 0x00000005	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6_P                 0x00000006	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7_P                 0x00000007	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1_P                 0x00000009	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
+#define FLG2_P                 0x0000000A	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3_P                 0x0000000B	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
+#define FLG4_P                 0x0000000C	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
+#define FLG5_P                 0x0000000D	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
+#define FLG6_P                 0x0000000E	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
+#define FLG7_P                 0x0000000F	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_STAT Masks */
+#define SPIF                   0x00000001	/* Set (=1) when SPI single-word transfer complete */
+#define MODF                   0x00000002	/* Set (=1) in a master device when some other device tries to become master */
+#define TXE                    0x00000004	/* Set (=1) when transmission occurs with no new data in SPI_TDBR */
+#define TXS                    0x00000008	/* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
+#define RBSY                   0x00000010	/* Set (=1) when data is received with RDBR full */
+#define RXS                    0x00000020	/* SPI_RDBR Data Buffer Status (0=Empty, 1=Full)  */
+#define TXCOL                  0x00000040	/* When set (=1), corrupt data may have been transmitted  */
+
+/* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS  ************* */
+
+/* AMGCTL Masks */
+#define AMCKEN			0x00000001	/* Enable CLKOUT */
+#define AMBEN_B0		0x00000002	/* Enable Asynchronous Memory Bank 0 only */
+#define AMBEN_B0_B1		0x00000004	/* Enable Asynchronous Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2		0x00000006	/* Enable Asynchronous Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL		0x00000008	/* Enable Asynchronous Memory Banks (all) 0, 1, 2, and 3 */
+
+/* AMGCTL Bit Positions */
+#define AMCKEN_P		0x00000000	/* Enable CLKOUT */
+#define AMBEN_P0		0x00000001	/* Asynchronous Memory Enable, 000 - banks 0-3 disabled, 001 - Bank 0 enabled */
+#define AMBEN_P1		0x00000002	/* Asynchronous Memory Enable, 010 - banks 0&1 enabled,  011 - banks 0-3 enabled */
+#define AMBEN_P2		0x00000003	/* Asynchronous Memory Enable, 1xx - All banks (bank 0, 1, 2, and 3) enabled */
+
+/* AMBCTL0 Masks */
+#define B0RDYEN	0x00000001	/* Bank 0 RDY Enable, 0=disable, 1=enable */
+#define B0RDYPOL 0x00000002	/* Bank 0 RDY Active high, 0=active low, 1=active high */
+#define B0TT_1	0x00000004	/* Bank 0 Transition Time from Read to Write = 1 cycle */
+#define B0TT_2	0x00000008	/* Bank 0 Transition Time from Read to Write = 2 cycles */
+#define B0TT_3	0x0000000C	/* Bank 0 Transition Time from Read to Write = 3 cycles */
+#define B0TT_4	0x00000000	/* Bank 0 Transition Time from Read to Write = 4 cycles */
+#define B0ST_1	0x00000010	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=1 cycle */
+#define B0ST_2	0x00000020	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=2 cycles */
+#define B0ST_3	0x00000030	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=3 cycles */
+#define B0ST_4	0x00000000	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=4 cycles */
+#define B0HT_1	0x00000040	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 1 cycle */
+#define B0HT_2	0x00000080	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 2 cycles */
+#define B0HT_3	0x000000C0	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 3 cycles */
+#define B0HT_0	0x00000000	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 0 cycles */
+#define B0RAT_1			0x00000100	/* Bank 0 Read Access Time = 1 cycle */
+#define B0RAT_2			0x00000200	/* Bank 0 Read Access Time = 2 cycles */
+#define B0RAT_3			0x00000300	/* Bank 0 Read Access Time = 3 cycles */
+#define B0RAT_4			0x00000400	/* Bank 0 Read Access Time = 4 cycles */
+#define B0RAT_5			0x00000500	/* Bank 0 Read Access Time = 5 cycles */
+#define B0RAT_6			0x00000600	/* Bank 0 Read Access Time = 6 cycles */
+#define B0RAT_7			0x00000700	/* Bank 0 Read Access Time = 7 cycles */
+#define B0RAT_8			0x00000800	/* Bank 0 Read Access Time = 8 cycles */
+#define B0RAT_9			0x00000900	/* Bank 0 Read Access Time = 9 cycles */
+#define B0RAT_10		0x00000A00	/* Bank 0 Read Access Time = 10 cycles */
+#define B0RAT_11		0x00000B00	/* Bank 0 Read Access Time = 11 cycles */
+#define B0RAT_12		0x00000C00	/* Bank 0 Read Access Time = 12 cycles */
+#define B0RAT_13		0x00000D00	/* Bank 0 Read Access Time = 13 cycles */
+#define B0RAT_14		0x00000E00	/* Bank 0 Read Access Time = 14 cycles */
+#define B0RAT_15		0x00000F00	/* Bank 0 Read Access Time = 15 cycles */
+#define B0WAT_1			0x00001000	/* Bank 0 Write Access Time = 1 cycle */
+#define B0WAT_2			0x00002000	/* Bank 0 Write Access Time = 2 cycles */
+#define B0WAT_3			0x00003000	/* Bank 0 Write Access Time = 3 cycles */
+#define B0WAT_4			0x00004000	/* Bank 0 Write Access Time = 4 cycles */
+#define B0WAT_5			0x00005000	/* Bank 0 Write Access Time = 5 cycles */
+#define B0WAT_6			0x00006000	/* Bank 0 Write Access Time = 6 cycles */
+#define B0WAT_7			0x00007000	/* Bank 0 Write Access Time = 7 cycles */
+#define B0WAT_8			0x00008000	/* Bank 0 Write Access Time = 8 cycles */
+#define B0WAT_9			0x00009000	/* Bank 0 Write Access Time = 9 cycles */
+#define B0WAT_10		0x0000A000	/* Bank 0 Write Access Time = 10 cycles */
+#define B0WAT_11		0x0000B000	/* Bank 0 Write Access Time = 11 cycles */
+#define B0WAT_12		0x0000C000	/* Bank 0 Write Access Time = 12 cycles */
+#define B0WAT_13		0x0000D000	/* Bank 0 Write Access Time = 13 cycles */
+#define B0WAT_14		0x0000E000	/* Bank 0 Write Access Time = 14 cycles */
+#define B0WAT_15		0x0000F000	/* Bank 0 Write Access Time = 15 cycles */
+#define B1RDYEN			0x00010000	/* Bank 1 RDY enable, 0=disable, 1=enable */
+#define B1RDYPOL		0x00020000	/* Bank 1 RDY Active high, 0=active low, 1=active high */
+#define B1TT_1			0x00040000	/* Bank 1 Transition Time from Read to Write = 1 cycle */
+#define B1TT_2			0x00080000	/* Bank 1 Transition Time from Read to Write = 2 cycles */
+#define B1TT_3			0x000C0000	/* Bank 1 Transition Time from Read to Write = 3 cycles */
+#define B1TT_4			0x00000000	/* Bank 1 Transition Time from Read to Write = 4 cycles */
+#define B1ST_1			0x00100000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B1ST_2			0x00200000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B1ST_3			0x00300000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B1ST_4			0x00000000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B1HT_1			0x00400000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B1HT_2			0x00800000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B1HT_3			0x00C00000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B1HT_0			0x00000000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B1RAT_1			0x01000000	/* Bank 1 Read Access Time = 1 cycle */
+#define B1RAT_2			0x02000000	/* Bank 1 Read Access Time = 2 cycles */
+#define B1RAT_3			0x03000000	/* Bank 1 Read Access Time = 3 cycles */
+#define B1RAT_4			0x04000000	/* Bank 1 Read Access Time = 4 cycles */
+#define B1RAT_5			0x05000000	/* Bank 1 Read Access Time = 5 cycles */
+#define B1RAT_6			0x06000000	/* Bank 1 Read Access Time = 6 cycles */
+#define B1RAT_7			0x07000000	/* Bank 1 Read Access Time = 7 cycles */
+#define B1RAT_8			0x08000000	/* Bank 1 Read Access Time = 8 cycles */
+#define B1RAT_9			0x09000000	/* Bank 1 Read Access Time = 9 cycles */
+#define B1RAT_10		0x0A000000	/* Bank 1 Read Access Time = 10 cycles */
+#define B1RAT_11		0x0B000000	/* Bank 1 Read Access Time = 11 cycles */
+#define B1RAT_12		0x0C000000	/* Bank 1 Read Access Time = 12 cycles */
+#define B1RAT_13		0x0D000000	/* Bank 1 Read Access Time = 13 cycles */
+#define B1RAT_14		0x0E000000	/* Bank 1 Read Access Time = 14 cycles */
+#define B1RAT_15		0x0F000000	/* Bank 1 Read Access Time = 15 cycles */
+#define B1WAT_1			0x10000000	/* Bank 1 Write Access Time = 1 cycle */
+#define B1WAT_2			0x20000000	/* Bank 1 Write Access Time = 2 cycles */
+#define B1WAT_3			0x30000000	/* Bank 1 Write Access Time = 3 cycles */
+#define B1WAT_4			0x40000000	/* Bank 1 Write Access Time = 4 cycles */
+#define B1WAT_5			0x50000000	/* Bank 1 Write Access Time = 5 cycles */
+#define B1WAT_6			0x60000000	/* Bank 1 Write Access Time = 6 cycles */
+#define B1WAT_7			0x70000000	/* Bank 1 Write Access Time = 7 cycles */
+#define B1WAT_8			0x80000000	/* Bank 1 Write Access Time = 8 cycles */
+#define B1WAT_9			0x90000000	/* Bank 1 Write Access Time = 9 cycles */
+#define B1WAT_10		0xA0000000	/* Bank 1 Write Access Time = 10 cycles */
+#define B1WAT_11		0xB0000000	/* Bank 1 Write Access Time = 11 cycles */
+#define B1WAT_12		0xC0000000	/* Bank 1 Write Access Time = 12 cycles */
+#define B1WAT_13		0xD0000000	/* Bank 1 Write Access Time = 13 cycles */
+#define B1WAT_14		0xE0000000	/* Bank 1 Write Access Time = 14 cycles */
+#define B1WAT_15		0xF0000000	/* Bank 1 Write Access Time = 15 cycles */
+
+/* AMBCTL1 Masks */
+#define B2RDYEN			0x00000001	/* Bank 2 RDY Enable, 0=disable, 1=enable */
+#define B2RDYPOL		0x00000002	/* Bank 2 RDY Active high, 0=active low, 1=active high */
+#define B2TT_1			0x00000004	/* Bank 2 Transition Time from Read to Write = 1 cycle */
+#define B2TT_2			0x00000008	/* Bank 2 Transition Time from Read to Write = 2 cycles */
+#define B2TT_3			0x0000000C	/* Bank 2 Transition Time from Read to Write = 3 cycles */
+#define B2TT_4			0x00000000	/* Bank 2 Transition Time from Read to Write = 4 cycles */
+#define B2ST_1			0x00000010	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B2ST_2			0x00000020	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B2ST_3			0x00000030	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B2ST_4			0x00000000	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B2HT_1			0x00000040	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B2HT_2			0x00000080	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B2HT_3			0x000000C0	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B2HT_0			0x00000000	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B2RAT_1			0x00000100	/* Bank 2 Read Access Time = 1 cycle */
+#define B2RAT_2			0x00000200	/* Bank 2 Read Access Time = 2 cycles */
+#define B2RAT_3			0x00000300	/* Bank 2 Read Access Time = 3 cycles */
+#define B2RAT_4			0x00000400	/* Bank 2 Read Access Time = 4 cycles */
+#define B2RAT_5			0x00000500	/* Bank 2 Read Access Time = 5 cycles */
+#define B2RAT_6			0x00000600	/* Bank 2 Read Access Time = 6 cycles */
+#define B2RAT_7			0x00000700	/* Bank 2 Read Access Time = 7 cycles */
+#define B2RAT_8			0x00000800	/* Bank 2 Read Access Time = 8 cycles */
+#define B2RAT_9			0x00000900	/* Bank 2 Read Access Time = 9 cycles */
+#define B2RAT_10		0x00000A00	/* Bank 2 Read Access Time = 10 cycles */
+#define B2RAT_11		0x00000B00	/* Bank 2 Read Access Time = 11 cycles */
+#define B2RAT_12		0x00000C00	/* Bank 2 Read Access Time = 12 cycles */
+#define B2RAT_13		0x00000D00	/* Bank 2 Read Access Time = 13 cycles */
+#define B2RAT_14		0x00000E00	/* Bank 2 Read Access Time = 14 cycles */
+#define B2RAT_15		0x00000F00	/* Bank 2 Read Access Time = 15 cycles */
+#define B2WAT_1			0x00001000	/* Bank 2 Write Access Time = 1 cycle */
+#define B2WAT_2			0x00002000	/* Bank 2 Write Access Time = 2 cycles */
+#define B2WAT_3			0x00003000	/* Bank 2 Write Access Time = 3 cycles */
+#define B2WAT_4			0x00004000	/* Bank 2 Write Access Time = 4 cycles */
+#define B2WAT_5			0x00005000	/* Bank 2 Write Access Time = 5 cycles */
+#define B2WAT_6			0x00006000	/* Bank 2 Write Access Time = 6 cycles */
+#define B2WAT_7			0x00007000	/* Bank 2 Write Access Time = 7 cycles */
+#define B2WAT_8			0x00008000	/* Bank 2 Write Access Time = 8 cycles */
+#define B2WAT_9			0x00009000	/* Bank 2 Write Access Time = 9 cycles */
+#define B2WAT_10		0x0000A000	/* Bank 2 Write Access Time = 10 cycles */
+#define B2WAT_11		0x0000B000	/* Bank 2 Write Access Time = 11 cycles */
+#define B2WAT_12		0x0000C000	/* Bank 2 Write Access Time = 12 cycles */
+#define B2WAT_13		0x0000D000	/* Bank 2 Write Access Time = 13 cycles */
+#define B2WAT_14		0x0000E000	/* Bank 2 Write Access Time = 14 cycles */
+#define B2WAT_15		0x0000F000	/* Bank 2 Write Access Time = 15 cycles */
+#define B3RDYEN			0x00010000	/* Bank 3 RDY enable, 0=disable, 1=enable */
+#define B3RDYPOL		0x00020000	/* Bank 3 RDY Active high, 0=active low, 1=active high */
+#define B3TT_1			0x00040000	/* Bank 3 Transition Time from Read to Write = 1 cycle */
+#define B3TT_2			0x00080000	/* Bank 3 Transition Time from Read to Write = 2 cycles */
+#define B3TT_3			0x000C0000	/* Bank 3 Transition Time from Read to Write = 3 cycles */
+#define B3TT_4			0x00000000	/* Bank 3 Transition Time from Read to Write = 4 cycles */
+#define B3ST_1			0x00100000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B3ST_2			0x00200000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B3ST_3			0x00300000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B3ST_4			0x00000000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B3HT_1			0x00400000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B3HT_2			0x00800000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B3HT_3			0x00C00000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B3HT_0			0x00000000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B3RAT_1			0x01000000	/* Bank 3 Read Access Time = 1 cycle */
+#define B3RAT_2			0x02000000	/* Bank 3 Read Access Time = 2 cycles */
+#define B3RAT_3			0x03000000	/* Bank 3 Read Access Time = 3 cycles */
+#define B3RAT_4			0x04000000	/* Bank 3 Read Access Time = 4 cycles */
+#define B3RAT_5			0x05000000	/* Bank 3 Read Access Time = 5 cycles */
+#define B3RAT_6			0x06000000	/* Bank 3 Read Access Time = 6 cycles */
+#define B3RAT_7			0x07000000	/* Bank 3 Read Access Time = 7 cycles */
+#define B3RAT_8			0x08000000	/* Bank 3 Read Access Time = 8 cycles */
+#define B3RAT_9			0x09000000	/* Bank 3 Read Access Time = 9 cycles */
+#define B3RAT_10		0x0A000000	/* Bank 3 Read Access Time = 10 cycles */
+#define B3RAT_11		0x0B000000	/* Bank 3 Read Access Time = 11 cycles */
+#define B3RAT_12		0x0C000000	/* Bank 3 Read Access Time = 12 cycles */
+#define B3RAT_13		0x0D000000	/* Bank 3 Read Access Time = 13 cycles */
+#define B3RAT_14		0x0E000000	/* Bank 3 Read Access Time = 14 cycles */
+#define B3RAT_15		0x0F000000	/* Bank 3 Read Access Time = 15 cycles */
+#define B3WAT_1			0x10000000	/* Bank 3 Write Access Time = 1 cycle */
+#define B3WAT_2			0x20000000	/* Bank 3 Write Access Time = 2 cycles */
+#define B3WAT_3			0x30000000	/* Bank 3 Write Access Time = 3 cycles */
+#define B3WAT_4			0x40000000	/* Bank 3 Write Access Time = 4 cycles */
+#define B3WAT_5			0x50000000	/* Bank 3 Write Access Time = 5 cycles */
+#define B3WAT_6			0x60000000	/* Bank 3 Write Access Time = 6 cycles */
+#define B3WAT_7			0x70000000	/* Bank 3 Write Access Time = 7 cycles */
+#define B3WAT_8			0x80000000	/* Bank 3 Write Access Time = 8 cycles */
+#define B3WAT_9			0x90000000	/* Bank 3 Write Access Time = 9 cycles */
+#define B3WAT_10		0xA0000000	/* Bank 3 Write Access Time = 10 cycles */
+#define B3WAT_11		0xB0000000	/* Bank 3 Write Access Time = 11 cycles */
+#define B3WAT_12		0xC0000000	/* Bank 3 Write Access Time = 12 cycles */
+#define B3WAT_13		0xD0000000	/* Bank 3 Write Access Time = 13 cycles */
+#define B3WAT_14		0xE0000000	/* Bank 3 Write Access Time = 14 cycles */
+#define B3WAT_15		0xF0000000	/* Bank 3 Write Access Time = 15 cycles */
+
+/* **********************  SDRAM CONTROLLER MASKS  *************************** */
+
+/* SDGCTL Masks */
+#define SCTLE			0x00000001	/* Enable SCLK[0], /SRAS, /SCAS, /SWE, SDQM[3:0] */
+#define CL_2			0x00000008	/* SDRAM CAS latency = 2 cycles */
+#define CL_3			0x0000000C	/* SDRAM CAS latency = 3 cycles */
+#define PFE			0x00000010	/* Enable SDRAM prefetch */
+#define PFP			0x00000020	/* Prefetch has priority over AMC requests */
+#define TRAS_1			0x00000040	/* SDRAM tRAS = 1 cycle */
+#define TRAS_2			0x00000080	/* SDRAM tRAS = 2 cycles */
+#define TRAS_3			0x000000C0	/* SDRAM tRAS = 3 cycles */
+#define TRAS_4			0x00000100	/* SDRAM tRAS = 4 cycles */
+#define TRAS_5			0x00000140	/* SDRAM tRAS = 5 cycles */
+#define TRAS_6			0x00000180	/* SDRAM tRAS = 6 cycles */
+#define TRAS_7			0x000001C0	/* SDRAM tRAS = 7 cycles */
+#define TRAS_8			0x00000200	/* SDRAM tRAS = 8 cycles */
+#define TRAS_9			0x00000240	/* SDRAM tRAS = 9 cycles */
+#define TRAS_10			0x00000280	/* SDRAM tRAS = 10 cycles */
+#define TRAS_11			0x000002C0	/* SDRAM tRAS = 11 cycles */
+#define TRAS_12			0x00000300	/* SDRAM tRAS = 12 cycles */
+#define TRAS_13			0x00000340	/* SDRAM tRAS = 13 cycles */
+#define TRAS_14			0x00000380	/* SDRAM tRAS = 14 cycles */
+#define TRAS_15			0x000003C0	/* SDRAM tRAS = 15 cycles */
+#define TRP_1			0x00000800	/* SDRAM tRP = 1 cycle */
+#define TRP_2			0x00001000	/* SDRAM tRP = 2 cycles */
+#define TRP_3			0x00001800	/* SDRAM tRP = 3 cycles */
+#define TRP_4			0x00002000	/* SDRAM tRP = 4 cycles */
+#define TRP_5			0x00002800	/* SDRAM tRP = 5 cycles */
+#define TRP_6			0x00003000	/* SDRAM tRP = 6 cycles */
+#define TRP_7			0x00003800	/* SDRAM tRP = 7 cycles */
+#define TRCD_1			0x00008000	/* SDRAM tRCD = 1 cycle */
+#define TRCD_2			0x00010000	/* SDRAM tRCD = 2 cycles */
+#define TRCD_3			0x00018000	/* SDRAM tRCD = 3 cycles */
+#define TRCD_4			0x00020000	/* SDRAM tRCD = 4 cycles */
+#define TRCD_5			0x00028000	/* SDRAM tRCD = 5 cycles */
+#define TRCD_6			0x00030000	/* SDRAM tRCD = 6 cycles */
+#define TRCD_7			0x00038000	/* SDRAM tRCD = 7 cycles */
+#define TWR_1			0x00080000	/* SDRAM tWR = 1 cycle */
+#define TWR_2			0x00100000	/* SDRAM tWR = 2 cycles */
+#define TWR_3			0x00180000	/* SDRAM tWR = 3 cycles */
+#define PUPSD			0x00200000	/*Power-up start delay */
+#define PSM			0x00400000	/* SDRAM power-up sequence = Precharge, mode register set, 8 CBR refresh cycles */
+#define PSS				0x00800000	/* enable SDRAM power-up sequence on next SDRAM access */
+#define SRFS			0x01000000	/* Start SDRAM self-refresh mode */
+#define EBUFE			0x02000000	/* Enable external buffering timing */
+#define FBBRW			0x04000000	/* Fast back-to-back read write enable */
+#define EMREN			0x10000000	/* Extended mode register enable */
+#define TCSR			0x20000000	/* Temp compensated self refresh value 85 deg C */
+#define CDDBG			0x40000000	/* Tristate SDRAM controls during bus grant */
+
+/* EBIU_SDBCTL Masks */
+#define EBE			0x00000001	/* Enable SDRAM external bank */
+#define EBSZ_16			0x00000000	/* SDRAM external bank size = 16MB */
+#define EBSZ_32			0x00000002	/* SDRAM external bank size = 32MB */
+#define EBSZ_64			0x00000004	/* SDRAM external bank size = 64MB */
+#define EBSZ_128			0x00000006	/* SDRAM external bank size = 128MB */
+#define EBCAW_8			0x00000000	/* SDRAM external bank column address width = 8 bits */
+#define EBCAW_9			0x00000010	/* SDRAM external bank column address width = 9 bits */
+#define EBCAW_10			0x00000020	/* SDRAM external bank column address width = 9 bits */
+#define EBCAW_11			0x00000030	/* SDRAM external bank column address width = 9 bits */
+
+/* EBIU_SDSTAT Masks */
+#define SDCI			0x00000001	/* SDRAM controller is idle  */
+#define SDSRA			0x00000002	/* SDRAM SDRAM self refresh is active */
+#define SDPUA			0x00000004	/* SDRAM power up active  */
+#define SDRS			0x00000008	/* SDRAM is in reset state */
+#define SDEASE		      0x00000010	/* SDRAM EAB sticky error status - W1C */
+#define BGSTAT			0x00000020	/* Bus granted */
+
+/*VR_CTL Masks*/
+#define WAKE                    0x100
+#define VLEV_6                  0x60
+#define VLEV_7                  0x70
+#define VLEV_8                  0x80
+#define VLEV_9                  0x90
+#define VLEV_10                 0xA0
+#define VLEV_11                 0xB0
+#define VLEV_12                 0xC0
+#define VLEV_13                 0xD0
+#define VLEV_14                 0xE0
+#define VLEV_15                 0xF0
+#define FREQ_3                  0x03
+
+#endif				/* _DEF_BF532_H */
diff --git a/include/asm-blackfin/mach-bf533/dma.h b/include/asm-blackfin/mach-bf533/dma.h
new file mode 100644
index 0000000..bd9d5e9
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/dma.h
@@ -0,0 +1,54 @@
+/*****************************************************************************
+*
+*        BF-533/2/1 Specific Declarations
+*
+****************************************************************************/
+/*
+ * File:         include/asm-blackfin/mach-bf533/dma.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 12
+
+#define CH_PPI          0
+#define CH_SPORT0_RX    1
+#define CH_SPORT0_TX    2
+#define CH_SPORT1_RX    3
+#define CH_SPORT1_TX    4
+#define CH_SPI          5
+#define CH_UART_RX      6
+#define CH_UART_TX      7
+#define CH_MEM_STREAM0_DEST     8	 /* TX */
+#define CH_MEM_STREAM0_SRC      9	 /* RX */
+#define CH_MEM_STREAM1_DEST     10	 /* TX */
+#define CH_MEM_STREAM1_SRC      11	 /* RX */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf533/irq.h b/include/asm-blackfin/mach-bf533/irq.h
new file mode 100644
index 0000000..9879e68
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/irq.h
@@ -0,0 +1,177 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/defBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BF533_IRQ_H_
+#define _BF533_IRQ_H_
+
+/*
+ * Interrupt source definitions
+             Event Source    Core Event Name
+Core        Emulation               **
+ Events         (highest priority)  EMU         0
+            Reset                   RST         1
+            NMI                     NMI         2
+            Exception               EVX         3
+            Reserved                --          4
+            Hardware Error          IVHW        5
+            Core Timer              IVTMR       6 *
+	    PLL Wakeup Interrupt    IVG7	7
+	    DMA Error (generic)	    IVG7	8
+	    PPI Error Interrupt     IVG7	9
+	    SPORT0 Error Interrupt  IVG7	10
+	    SPORT1 Error Interrupt  IVG7	11
+	    SPI Error Interrupt	    IVG7	12
+	    UART Error Interrupt    IVG7	13
+	    RTC Interrupt	    IVG8        14
+	    DMA0 Interrupt (PPI)    IVG8	15
+	    DMA1 (SPORT0 RX)	    IVG9	16
+	    DMA2 (SPORT0 TX)	    IVG9        17
+	    DMA3 (SPORT1 RX)        IVG9	18
+	    DMA4 (SPORT1 TX)	    IVG9	19
+	    DMA5 (PPI)		    IVG10	20
+	    DMA6 (UART RX)	    IVG10	21
+	    DMA7 (UART TX)	    IVG10	22
+	    Timer0		    IVG11	23
+	    Timer1		    IVG11	24
+	    Timer2		    IVG11	25
+	    PF Interrupt A	    IVG12	26
+	    PF Interrupt B	    IVG12	27
+	    DMA8/9 Interrupt	    IVG13	28
+	    DMA10/11 Interrupt	    IVG13	29
+	    Watchdog Timer	    IVG13	30
+            Software Interrupt 1    IVG14       31
+            Software Interrupt 2    --
+                 (lowest priority)  IVG15       32 *
+ */
+#define SYS_IRQS		32
+#define NR_PERI_INTS    24
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define	IRQ_EMU			0	/*Emulation */
+#define	IRQ_RST			1	/*reset */
+#define	IRQ_NMI			2	/*Non Maskable */
+#define	IRQ_EVX			3	/*Exception */
+#define	IRQ_UNUSED		4	/*- unused interrupt*/
+#define	IRQ_HWERR		5	/*Hardware Error */
+#define	IRQ_CORETMR		6	/*Core timer */
+
+#define	IRQ_PLL_WAKEUP		7	/*PLL Wakeup Interrupt */
+#define	IRQ_DMA_ERROR		8	/*DMA Error (general) */
+#define	IRQ_PPI_ERROR		9	/*PPI Error Interrupt */
+#define	IRQ_SPORT0_ERROR	10	/*SPORT0 Error Interrupt */
+#define	IRQ_SPORT1_ERROR	11	/*SPORT1 Error Interrupt */
+#define	IRQ_SPI_ERROR		12	/*SPI Error Interrupt */
+#define	IRQ_UART_ERROR		13	/*UART Error Interrupt */
+#define	IRQ_RTC			14	/*RTC Interrupt */
+#define	IRQ_PPI			15	/*DMA0 Interrupt (PPI) */
+#define	IRQ_SPORT0_RX		16	/*DMA1 Interrupt (SPORT0 RX) */
+#define	IRQ_SPORT0_TX		17	/*DMA2 Interrupt (SPORT0 TX) */
+#define	IRQ_SPORT1_RX		18	/*DMA3 Interrupt (SPORT1 RX) */
+#define	IRQ_SPORT1_TX		19	/*DMA4 Interrupt (SPORT1 TX) */
+#define IRQ_SPI			20	/*DMA5 Interrupt (SPI) */
+#define	IRQ_UART_RX		21	/*DMA6 Interrupt (UART RX) */
+#define	IRQ_UART_TX		22	/*DMA7 Interrupt (UART TX) */
+#define	IRQ_TMR0		23	/*Timer 0 */
+#define	IRQ_TMR1		24	/*Timer 1 */
+#define	IRQ_TMR2		25	/*Timer 2 */
+#define	IRQ_PROG_INTA		26	/*Programmable Flags A (8) */
+#define	IRQ_PROG_INTB		27	/*Programmable Flags B (8) */
+#define	IRQ_MEM_DMA0		28	/*DMA8/9 Interrupt (Memory DMA Stream 0) */
+#define	IRQ_MEM_DMA1		29	/*DMA10/11 Interrupt (Memory DMA Stream 1) */
+#define	IRQ_WATCH	   	30	/*Watch Dog Timer */
+
+#define	IRQ_SW_INT1		31	/*Software Int 1 */
+#define	IRQ_SW_INT2		32	/*Software Int 2 (reserved for SYSCALL) */
+
+#define IRQ_PF0			33
+#define IRQ_PF1			34
+#define IRQ_PF2			35
+#define IRQ_PF3			36
+#define IRQ_PF4			37
+#define IRQ_PF5			38
+#define IRQ_PF6			39
+#define IRQ_PF7			40
+#define IRQ_PF8			41
+#define IRQ_PF9			42
+#define IRQ_PF10		43
+#define IRQ_PF11		44
+#define IRQ_PF12		45
+#define IRQ_PF13		46
+#define IRQ_PF14		47
+#define IRQ_PF15		48
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define	NR_IRQS		(IRQ_PF15+1)
+#else
+#define	NR_IRQS		SYS_IRQS
+#endif
+
+#define IVG7			7
+#define IVG8			8
+#define IVG9			9
+#define IVG10			10
+#define IVG11			11
+#define IVG12			12
+#define IVG13			13
+#define IVG14			14
+#define IVG15			15
+
+/* IAR0 BIT FIELDS*/
+#define RTC_ERROR_POS			28
+#define UART_ERROR_POS			24
+#define SPORT1_ERROR_POS		20
+#define SPI_ERROR_POS			16
+#define SPORT0_ERROR_POS		12
+#define PPI_ERROR_POS			8
+#define DMA_ERROR_POS			4
+#define PLLWAKE_ERROR_POS		0
+
+/* IAR1 BIT FIELDS*/
+#define DMA7_UARTTX_POS			28
+#define DMA6_UARTRX_POS			24
+#define DMA5_SPI_POS			20
+#define DMA4_SPORT1TX_POS		16
+#define DMA3_SPORT1RX_POS		12
+#define DMA2_SPORT0TX_POS		8
+#define DMA1_SPORT0RX_POS		4
+#define DMA0_PPI_POS			0
+
+/* IAR2 BIT FIELDS*/
+#define WDTIMER_POS			28
+#define MEMDMA1_POS			24
+#define MEMDMA0_POS			20
+#define PFB_POS				16
+#define PFA_POS				12
+#define TIMER2_POS			8
+#define TIMER1_POS			4
+#define TIMER0_POS			0
+
+#endif				/* _BF533_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf533/mem_init.h b/include/asm-blackfin/mach-bf533/mem_init.h
new file mode 100644
index 0000000..1620dae
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/mem_init.h
@@ -0,0 +1,316 @@
+/*
+ * File:         include/asm-blackfin/mach-bf533/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_GENERIC_BOARD)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_7
+#define SDRAM_tRAS_num  7
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_6
+#define SDRAM_tRAS_num  6
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 8955223) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_5
+#define SDRAM_tRAS_num  5
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  4
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_2
+#define SDRAM_tRAS_num  2
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_1
+#define SDRAM_tRAS_num  1
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+  /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE      EBSZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE      EBSZ_64
+#endif
+#if (CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE      EBSZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE      EBSZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH     EBCAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH     EBCAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH     EBCAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH     EBCAW_8
+#endif
+
+#define mem_SDBCTL      (SDRAM_WIDTH | SDRAM_SIZE | EBE)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC       (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref)  / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL        (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF       1
+#else
+#define CLKIN_HALF       0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS      1
+#else
+#define PLL_BYPASS       0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT  ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT  ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT   ((CONFIG_FLASH_SPEED_BHT  * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST   ((CONFIG_FLASH_SPEED_BST  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT   ((CONFIG_FLASH_SPEED_BTT  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0  \
+	(flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+	 flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf533/mem_map.h b/include/asm-blackfin/mach-bf533/mem_map.h
new file mode 100644
index 0000000..e84baa3
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/mem_map.h
@@ -0,0 +1,168 @@
+
+/*
+ * File:         include/asm-blackfin/mach-bf533/mem_map.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MEM_MAP_533_H_
+#define _MEM_MAP_533_H_
+
+#define COREMMR_BASE           0xFFE00000	 /* Core MMRs */
+#define SYSMMR_BASE            0xFFC00000	 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE	0x20300000	 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK2_BASE	0x20200000	 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK1_BASE	0x20100000	 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK0_BASE	0x20000000	 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE	0x00100000	/* 1M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START		0xEF000000
+
+/* Level 1 Memory */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE	(16*1024)
+#else
+#define BLKFIN_ICACHESIZE	(0*1024)
+#endif
+
+/* Memory Map for ADSP-BF533 processors */
+
+#ifdef CONFIG_BF533
+#define L1_CODE_START       0xFFA00000
+#define L1_DATA_A_START     0xFF800000
+#define L1_DATA_B_START     0xFF900000
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define L1_CODE_LENGTH      (0x14000 - 0x4000)
+#else
+#define L1_CODE_LENGTH      0x14000
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x8000
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Memory Map for ADSP-BF532 processors */
+
+#ifdef CONFIG_BF532
+#define L1_CODE_START       0xFFA08000
+#define L1_DATA_A_START     0xFF804000
+#define L1_DATA_B_START     0xFF904000
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define L1_CODE_LENGTH      (0xC000 - 0x4000)
+#else
+#define L1_CODE_LENGTH      0xC000
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x4000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x4000
+#define L1_DATA_B_LENGTH      0x4000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Memory Map for ADSP-BF531 processors */
+
+#ifdef CONFIG_BF531
+#define L1_CODE_START       0xFFA08000
+#define L1_DATA_A_START     0xFF804000
+#define L1_DATA_B_START     0xFF904000
+#define L1_CODE_LENGTH      0x4000
+#define L1_DATA_B_LENGTH      0x0000
+
+
+#ifdef CONFIG_BLKFIN_DCACHE
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB  | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB  | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x4000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif
+
+#endif
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF533) || defined(CONFIG_BF532) || defined(CONFIG_BF531)
+#define L1_SCRATCH_START	0xFFB00000
+#define L1_SCRATCH_LENGTH	0x1000
+#endif
+
+#endif				/* _MEM_MAP_533_H_ */
diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
new file mode 100644
index 0000000..7f040f5
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/anomaly.h
@@ -0,0 +1,120 @@
+
+/*
+ * File:         include/asm-blackfin/mach-bf537/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ *  - Revision J, June 1, 2006; ADSP-BF537 Blackfin Processor Anomaly List
+ *  - Revision I, June 1, 2006; ADSP-BF536 Blackfin Processor Anomaly List
+ *  - Revision J, June 1, 2006; ADSP-BF534 Blackfin Processor Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1))
+#error Kernel will not work on BF537/6/4 Version 0.1
+#endif
+
+#if (defined(CONFIG_BF_REV_0_3) || defined(CONFIG_BF_REV_0_2))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+                            slot1 and store of a P register in slot 2 is not
+                            supported */
+#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive
+                            Channel DMA stops */
+#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR
+                            registers. */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+                            upper bits*/
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+                            syncs */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000247 /* CLKIN Buffer Output Enable Reset Behavior Is
+                            Changed */
+#endif
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+                            SPORT external receive and transmit clocks. */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+                            VDDint <=0.9V */
+#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+                            an edge is detected may clear interrupt */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+                            not restored */
+#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic
+                            control */
+#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when
+                            killed in a particular stage*/
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+			    registers are interrupted */
+#endif
+
+#if defined(CONFIG_BF_REV_0_2)
+#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or
+                            IDLE around a Change of Control causes
+                            unpredictable results */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+                            (TDM) */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000252 /* EMAC Tx DMA error after an early frame abort */
+#endif
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event
+                            interrupt not functional */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000256 /* EMAC MDIO input latched on wrong MDC edge */
+#endif
+#define ANOMALY_05000257 /* An interrupt or exception during short Hardware
+                            loops may cause the instruction fetch unit to
+                            malfunction */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of
+                            the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */
+#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE
+                            instruction will cause an infinite stall in the
+                            second to last instruction in a hardware loop */
+#define ANOMALY_05000268 /* Memory DMA error when peripheral DMA is running
+                            and non-zero DEB_TRAFFIC_PERIOD value */
+#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the
+                            internal voltage regulator (VDDint) to decrease */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+                            an edge is detected may clear interrupt */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+                            DMA system instability */
+#define ANOMALY_05000280 /* SPI Master boot mode does not work well with
+                            Atmel Dataflash devices */
+
+#endif  /* CONFIG_BF_REV_0_2 */
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf537/bf537.h b/include/asm-blackfin/mach-bf537/bf537.h
new file mode 100644
index 0000000..b8924cd
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/bf537.h
@@ -0,0 +1,287 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/bf537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF537
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MACH_BF537_H__
+#define __MACH_BF537_H__
+
+#define SUPPORTED_REVID 2
+
+/* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */
+
+#define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE)	/* SPI_STAT */
+#define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF)	/* SPORTx_STAT */
+#define PPI_ERR_MASK (0xFFFF & ~FLD)	/* PPI_STATUS */
+#define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE)	/* EMAC_SYSTAT */
+#define UART_ERR_MASK_STAT1 (0x4)	/* UARTx_IIR */
+#define UART_ERR_MASK_STAT0 (0x2)	/* UARTx_IIR */
+#define CAN_ERR_MASK  (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF)	/* CAN_GIF */
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15		0x8000
+#define IMASK_IVG14		0x4000
+#define IMASK_IVG13		0x2000
+#define IMASK_IVG12		0x1000
+
+#define IMASK_IVG11		0x0800
+#define IMASK_IVG10		0x0400
+#define IMASK_IVG9		0x0200
+#define IMASK_IVG8		0x0100
+
+#define IMASK_IVG7		0x0080
+#define IMASK_IVGTMR	0x0040
+#define IMASK_IVGHW		0x0020
+
+/***************************/
+
+
+#define BLKFIN_DSUBBANKS	4
+#define BLKFIN_DWAYS		2
+#define BLKFIN_DLINES		64
+#define BLKFIN_ISUBBANKS	4
+#define BLKFIN_IWAYS		4
+#define BLKFIN_ILINES		32
+
+#define WAY0_L			0x1
+#define WAY1_L			0x2
+#define WAY01_L			0x3
+#define WAY2_L			0x4
+#define WAY02_L			0x5
+#define	WAY12_L			0x6
+#define	WAY012_L		0x7
+
+#define	WAY3_L			0x8
+#define	WAY03_L			0x9
+#define	WAY13_L			0xA
+#define	WAY013_L		0xB
+
+#define	WAY32_L			0xC
+#define	WAY320_L		0xD
+#define	WAY321_L		0xE
+#define	WAYALL_L		0xF
+
+#define DMC_ENABLE (2<<2)	/*yes, 2, not 1 */
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL	((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL	((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL	(V_AMBEN | V_AMCKEN | V_CDPRIO)
+
+#define MAX_VC	650000000
+#define MIN_VC	50000000
+
+/********************************PLL Settings **************************************/
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT > 64)
+#error "VCO Multiplier is more than 64. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ	(CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ	((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ	(CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ	(CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ	CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ	CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV   CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif				/* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF537
+#define CPU "BF537"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF536
+#define CPU "BF536"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF534
+#define CPU "BF534"
+#define CPUID 0x027c6000
+#endif
+#ifndef CPU
+#define	CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM mem size must be multible of 4MB"
+#endif
+
+#define SDRAM_IGENERIC    (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL     (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY        (               CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL   (               CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND		0x200
+#ifdef CONFIG_BLKFIN_WB		/*Write Back Policy */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_DIRTY \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else				/*Write Through */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#endif
+
+
+#define L1_DMEMORY       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+#define SDRAM_DNON_CHBL  (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_EBIU       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_OOPS  	 (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+
+#define SIZE_1K 0x00000400	/* 1K */
+#define SIZE_4K 0x00001000	/* 4K */
+#define SIZE_1M 0x00100000	/* 1M */
+#define SIZE_4M 0x00400000	/* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)
+
+#endif				/* __MACH_BF537_H__  */
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
new file mode 100644
index 0000000..8f5d9c4
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -0,0 +1,147 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS		2
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
+
+#define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
+# define CONFIG_SERIAL_BFIN_CTSRTS
+
+# ifndef CONFIG_UART0_CTS_PIN
+#  define CONFIG_UART0_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART0_RTS_PIN
+#  define CONFIG_UART0_RTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_CTS_PIN
+#  define CONFIG_UART1_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_RTS_PIN
+#  define CONFIG_UART1_RTS_PIN -1
+# endif
+#endif
+/*
+ * The pin configuration is different from schematic
+ */
+struct bfin_serial_port {
+        struct uart_port        port;
+        unsigned int            old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	int			tx_done;
+	int			tx_count;
+	struct circ_buf		rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int			rx_dma_nrows;
+	unsigned int		tx_dma_channel;
+	unsigned int		rx_dma_channel;
+	struct work_struct	tx_dma_workqueue;
+#else
+	struct work_struct 	cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int		cts_pin;
+	int 		rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+	unsigned long	uart_base_addr;
+	int		uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	unsigned int	uart_tx_dma_channel;
+	unsigned int	uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int	uart_cts_pin;
+	int	uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	{
+	0xFFC00400,
+	IRQ_UART0_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	CH_UART0_TX,
+	CH_UART0_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+	CONFIG_UART0_CTS_PIN,
+	CONFIG_UART0_RTS_PIN,
+#endif
+	},
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	{
+	0xFFC02000,
+	IRQ_UART1_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	CH_UART1_TX,
+	CH_UART1_RX,
+#endif
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	CONFIG_UART1_CTS_PIN,
+	CONFIG_UART1_RTS_PIN,
+#endif
+	},
+#endif
+};
+
+int nr_ports = ARRAY_SIZE(bfin_serial_resource);
+
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+	unsigned short val;
+	val = bfin_read16(BFIN_PORT_MUX);
+	val &= ~(PFDE | PFTE);
+	bfin_write16(BFIN_PORT_MUX, val);
+
+	val = bfin_read16(PORTF_FER);
+	val |= 0xF;
+	bfin_write16(PORTF_FER, val);
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	if (uart->cts_pin >= 0) {
+		gpio_request(uart->cts_pin, NULL);
+		gpio_direction_input(uart->cts_pin);
+	}
+
+	if (uart->rts_pin >= 0) {
+		gpio_request(uart->rts_pin, NULL);
+		gpio_direction_output(uart->rts_pin);
+	}
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf537/blackfin.h b/include/asm-blackfin/mach-bf537/blackfin.h
new file mode 100644
index 0000000..bbd9705
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/blackfin.h
@@ -0,0 +1,430 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF537_FAMILY
+
+#include "bf537.h"
+#include "mem_map.h"
+#include "defBF534.h"
+#include "anomaly.h"
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+#include "defBF537.h"
+#endif
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF534.h"
+
+/* UART 0*/
+#define bfin_read_UART_THR() bfin_read_UART0_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART0_THR(val)
+#define bfin_read_UART_RBR() bfin_read_UART0_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART0_RBR(val)
+#define bfin_read_UART_DLL() bfin_read_UART0_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART0_DLL(val)
+#define bfin_read_UART_IER() bfin_read_UART0_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART0_IER(val)
+#define bfin_read_UART_DLH() bfin_read_UART0_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART0_DLH(val)
+#define bfin_read_UART_IIR() bfin_read_UART0_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART0_IIR(val)
+#define bfin_read_UART_LCR() bfin_read_UART0_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART0_LCR(val)
+#define bfin_read_UART_MCR() bfin_read_UART0_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART0_MCR(val)
+#define bfin_read_UART_LSR() bfin_read_UART0_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART0_LSR(val)
+#define bfin_read_UART_SCR() bfin_read_UART0_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART0_SCR(val)
+#define bfin_read_UART_GCTL() bfin_read_UART0_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART0_GCTL(val)
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+#include "cdefBF537.h"
+#endif
+#endif
+
+/* MAP used DEFINES from BF533 to BF537 - so we don't need to change them in the driver, kernel, etc. */
+
+/* UART_IIR Register */
+#define STATUS(x)	((x << 1) & 0x06)
+#define STATUS_P1	0x02
+#define STATUS_P0	0x01
+
+/* UART 0*/
+
+/* DMA Channnel */
+#define bfin_read_CH_UART_RX() bfin_read_CH_UART0_RX()
+#define bfin_write_CH_UART_RX(val) bfin_write_CH_UART0_RX(val)
+#define CH_UART_RX CH_UART0_RX
+#define bfin_read_CH_UART_TX() bfin_read_CH_UART0_TX()
+#define bfin_write_CH_UART_TX(val) bfin_write_CH_UART0_TX(val)
+#define CH_UART_TX CH_UART0_TX
+
+/* System Interrupt Controller */
+#define bfin_read_IRQ_UART_RX() bfin_read_IRQ_UART0_RX()
+#define bfin_write_IRQ_UART_RX(val) bfin_write_IRQ_UART0_RX(val)
+#define IRQ_UART_RX IRQ_UART0_RX
+#define bfin_read_IRQ_UART_TX() bfin_read_IRQ_UART0_TX()
+#define bfin_write_IRQ_UART_TX(val) bfin_write_IRQ_UART0_TX(val)
+#define	IRQ_UART_TX IRQ_UART0_TX
+#define bfin_read_IRQ_UART_ERROR() bfin_read_IRQ_UART0_ERROR()
+#define bfin_write_IRQ_UART_ERROR(val) bfin_write_IRQ_UART0_ERROR(val)
+#define	IRQ_UART_ERROR IRQ_UART0_ERROR
+
+/* MMR Registers*/
+#define bfin_read_UART_THR() bfin_read_UART0_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART0_THR(val)
+#define UART_THR UART0_THR
+#define bfin_read_UART_RBR() bfin_read_UART0_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART0_RBR(val)
+#define UART_RBR UART0_RBR
+#define bfin_read_UART_DLL() bfin_read_UART0_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART0_DLL(val)
+#define UART_DLL UART0_DLL
+#define bfin_read_UART_IER() bfin_read_UART0_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART0_IER(val)
+#define UART_IER UART0_IER
+#define bfin_read_UART_DLH() bfin_read_UART0_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART0_DLH(val)
+#define UART_DLH UART0_DLH
+#define bfin_read_UART_IIR() bfin_read_UART0_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART0_IIR(val)
+#define UART_IIR UART0_IIR
+#define bfin_read_UART_LCR() bfin_read_UART0_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART0_LCR(val)
+#define UART_LCR UART0_LCR
+#define bfin_read_UART_MCR() bfin_read_UART0_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART0_MCR(val)
+#define UART_MCR UART0_MCR
+#define bfin_read_UART_LSR() bfin_read_UART0_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART0_LSR(val)
+#define UART_LSR UART0_LSR
+#define bfin_read_UART_SCR() bfin_read_UART0_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART0_SCR(val)
+#define UART_SCR  UART0_SCR
+#define bfin_read_UART_GCTL() bfin_read_UART0_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART0_GCTL(val)
+#define UART_GCTL UART0_GCTL
+
+/* DPMC*/
+#define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
+#define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
+#define STOPCK_OFF STOPCK
+
+/* FIO USE PORT F*/
+#ifdef CONFIG_BF537_PORT_F
+#define bfin_read_PORT_FER() bfin_read_PORTF_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTF_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val)
+#define FIO_FLAG_D		PORTFIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val)
+#define FIO_FLAG_C		PORTFIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val)
+#define FIO_FLAG_S		PORTFIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val)
+#define FIO_FLAG_T		PORTFIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val)
+#define FIO_MASKA_D	    PORTFIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C     PORTFIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val)
+#define FIO_MASKA_S     PORTFIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T     PORTFIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val)
+#define FIO_MASKB_D     PORTFIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C     PORTFIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val)
+#define FIO_MASKB_S     PORTFIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T     PORTFIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val)
+#define FIO_DIR		    PORTFIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val)
+#define FIO_POLAR		PORTFIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val)
+#define FIO_EDGE		PORTFIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val)
+#define FIO_BOTH		PORTFIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val)
+#define FIO_INEN		PORTFIO_INEN
+#endif
+
+/* FIO USE PORT G*/
+#ifdef CONFIG_BF537_PORT_G
+#define bfin_read_PORT_FER() bfin_read_PORTG_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTG_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val)
+#define FIO_FLAG_D		PORTGIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val)
+#define FIO_FLAG_C		PORTGIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val)
+#define FIO_FLAG_S		PORTGIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val)
+#define FIO_FLAG_T		PORTGIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val)
+#define FIO_MASKA_D	    PORTGIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C	    PORTGIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val)
+#define FIO_MASKA_S	    PORTGIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T	    PORTGIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val)
+#define FIO_MASKB_D	    PORTGIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C	    PORTGIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val)
+#define FIO_MASKB_S	    PORTGIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T	    PORTGIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val)
+#define FIO_DIR		    PORTGIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val)
+#define FIO_POLAR		PORTGIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val)
+#define FIO_EDGE		PORTGIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val)
+#define FIO_BOTH		PORTGIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val)
+#define FIO_INEN		PORTGIO_INEN
+
+#endif
+
+/* FIO USE PORT H*/
+#ifdef CONFIG_BF537_PORT_H
+#define bfin_read_PORT_FER() bfin_read_PORTH_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTH_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val)
+#define FIO_FLAG_D		PORTHIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val)
+#define FIO_FLAG_C		PORTHIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val)
+#define FIO_FLAG_S		PORTHIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val)
+#define FIO_FLAG_T		PORTHIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val)
+#define FIO_MASKA_D	    PORTHIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C	    PORTHIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val)
+#define FIO_MASKA_S	    PORTHIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T	    PORTHIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val)
+#define FIO_MASKB_D	    PORTHIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C	    PORTHIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val)
+#define FIO_MASKB_S	    PORTHIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T	    PORTHIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val)
+#define FIO_DIR		    PORTHIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val)
+#define FIO_POLAR		PORTHIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val)
+#define FIO_EDGE		PORTHIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val)
+#define FIO_BOTH		PORTHIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val)
+#define FIO_INEN		PORTHIO_INEN
+
+#endif
+
+/* PLL_DIV Masks													*/
+#define CCLK_DIV1 CSEL_DIV1	/*          CCLK = VCO / 1                                  */
+#define CCLK_DIV2 CSEL_DIV2	/*          CCLK = VCO / 2                                  */
+#define CCLK_DIV4 CSEL_DIV4	/*          CCLK = VCO / 4                                  */
+#define CCLK_DIV8 CSEL_DIV8	/*          CCLK = VCO / 8                                  */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf537/cdefBF534.h b/include/asm-blackfin/mach-bf537/cdefBF534.h
new file mode 100644
index 0000000..7b658c1
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/cdefBF534.h
@@ -0,0 +1,1823 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/cdefbf534.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  system mmr register map
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF534_H
+#define _CDEF_BF534_H
+
+/* Include all Core registers and bit definitions 									*/
+#include "defBF534.h"
+
+/* Include core specific register pointer definitions 								*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/* Clock and System Control	(0xFFC00000 - 0xFFC000FF)								*/
+#define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_DIV()                  bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val)              bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL()                   bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	bfin_write16(VR_CTL, val);
+	__builtin_bfin_ssync();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+	local_irq_save(flags);
+	asm("IDLE;");
+	local_irq_restore(flags);
+	bfin_write32(SIC_IWR, iwr);
+}
+#define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT()              bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val)          bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID()                   bfin_read32(CHIPID)
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF)							*/
+#define bfin_read_SWRST()                    bfin_read16(SWRST)
+#define bfin_write_SWRST(val)                bfin_write16(SWRST,val)
+#define bfin_read_SYSCR()                    bfin_read16(SYSCR)
+#define bfin_write_SYSCR(val)                bfin_write16(SYSCR,val)
+#define	pSIC_RVECT			((void * volatile *)SIC_RVECT)
+#define bfin_read_SIC_RVECT()                bfin_read32(SIC_RVECT)
+#define bfin_write_SIC_RVECT(val)            bfin_write32(SIC_RVECT,val)
+#define bfin_read_SIC_IMASK()                bfin_read32(SIC_IMASK)
+#define bfin_write_SIC_IMASK(val)            bfin_write32(SIC_IMASK,val)
+#define bfin_read_SIC_IAR0()                 bfin_read32(SIC_IAR0)
+#define bfin_write_SIC_IAR0(val)             bfin_write32(SIC_IAR0,val)
+#define bfin_read_SIC_IAR1()                 bfin_read32(SIC_IAR1)
+#define bfin_write_SIC_IAR1(val)             bfin_write32(SIC_IAR1,val)
+#define bfin_read_SIC_IAR2()                 bfin_read32(SIC_IAR2)
+#define bfin_write_SIC_IAR2(val)             bfin_write32(SIC_IAR2,val)
+#define bfin_read_SIC_IAR3()                 bfin_read32(SIC_IAR3)
+#define bfin_write_SIC_IAR3(val)             bfin_write32(SIC_IAR3,val)
+#define bfin_read_SIC_ISR()                  bfin_read32(SIC_ISR)
+#define bfin_write_SIC_ISR(val)              bfin_write32(SIC_ISR,val)
+#define bfin_read_SIC_IWR()                  bfin_read32(SIC_IWR)
+#define bfin_write_SIC_IWR(val)              bfin_write32(SIC_IWR,val)
+
+/* Watchdog Timer		(0xFFC00200 - 0xFFC002FF)									*/
+#define bfin_read_WDOG_CTL()                 bfin_read16(WDOG_CTL)
+#define bfin_write_WDOG_CTL(val)             bfin_write16(WDOG_CTL,val)
+#define bfin_read_WDOG_CNT()                 bfin_read32(WDOG_CNT)
+#define bfin_write_WDOG_CNT(val)             bfin_write32(WDOG_CNT,val)
+#define bfin_read_WDOG_STAT()                bfin_read32(WDOG_STAT)
+#define bfin_write_WDOG_STAT(val)            bfin_write32(WDOG_STAT,val)
+
+/* Real Time Clock		(0xFFC00300 - 0xFFC003FF)									*/
+#define bfin_read_RTC_STAT()                 bfin_read32(RTC_STAT)
+#define bfin_write_RTC_STAT(val)             bfin_write32(RTC_STAT,val)
+#define bfin_read_RTC_ICTL()                 bfin_read16(RTC_ICTL)
+#define bfin_write_RTC_ICTL(val)             bfin_write16(RTC_ICTL,val)
+#define bfin_read_RTC_ISTAT()                bfin_read16(RTC_ISTAT)
+#define bfin_write_RTC_ISTAT(val)            bfin_write16(RTC_ISTAT,val)
+#define bfin_read_RTC_SWCNT()                bfin_read16(RTC_SWCNT)
+#define bfin_write_RTC_SWCNT(val)            bfin_write16(RTC_SWCNT,val)
+#define bfin_read_RTC_ALARM()                bfin_read32(RTC_ALARM)
+#define bfin_write_RTC_ALARM(val)            bfin_write32(RTC_ALARM,val)
+#define bfin_read_RTC_FAST()                 bfin_read16(RTC_FAST)
+#define bfin_write_RTC_FAST(val)             bfin_write16(RTC_FAST,val)
+#define bfin_read_RTC_PREN()                 bfin_read16(RTC_PREN)
+#define bfin_write_RTC_PREN(val)             bfin_write16(RTC_PREN,val)
+
+/* UART0 Controller		(0xFFC00400 - 0xFFC004FF)									*/
+#define bfin_read_UART0_THR()                bfin_read16(UART0_THR)
+#define bfin_write_UART0_THR(val)            bfin_write16(UART0_THR,val)
+#define bfin_read_UART0_RBR()                bfin_read16(UART0_RBR)
+#define bfin_write_UART0_RBR(val)            bfin_write16(UART0_RBR,val)
+#define bfin_read_UART0_DLL()                bfin_read16(UART0_DLL)
+#define bfin_write_UART0_DLL(val)            bfin_write16(UART0_DLL,val)
+#define bfin_read_UART0_IER()                bfin_read16(UART0_IER)
+#define bfin_write_UART0_IER(val)            bfin_write16(UART0_IER,val)
+#define bfin_read_UART0_DLH()                bfin_read16(UART0_DLH)
+#define bfin_write_UART0_DLH(val)            bfin_write16(UART0_DLH,val)
+#define bfin_read_UART0_IIR()                bfin_read16(UART0_IIR)
+#define bfin_write_UART0_IIR(val)            bfin_write16(UART0_IIR,val)
+#define bfin_read_UART0_LCR()                bfin_read16(UART0_LCR)
+#define bfin_write_UART0_LCR(val)            bfin_write16(UART0_LCR,val)
+#define bfin_read_UART0_MCR()                bfin_read16(UART0_MCR)
+#define bfin_write_UART0_MCR(val)            bfin_write16(UART0_MCR,val)
+#define bfin_read_UART0_LSR()                bfin_read16(UART0_LSR)
+#define bfin_write_UART0_LSR(val)            bfin_write16(UART0_LSR,val)
+#define bfin_read_UART0_MSR()                bfin_read16(UART0_MSR)
+#define bfin_write_UART0_MSR(val)            bfin_write16(UART0_MSR,val)
+#define bfin_read_UART0_SCR()                bfin_read16(UART0_SCR)
+#define bfin_write_UART0_SCR(val)            bfin_write16(UART0_SCR,val)
+#define bfin_read_UART0_GCTL()               bfin_read16(UART0_GCTL)
+#define bfin_write_UART0_GCTL(val)           bfin_write16(UART0_GCTL,val)
+
+/* SPI Controller		(0xFFC00500 - 0xFFC005FF)									*/
+#define bfin_read_SPI_CTL()                  bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val)              bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG()                  bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val)              bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT()                 bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val)             bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR()                 bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val)             bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR()                 bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val)             bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD()                 bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val)             bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW()               bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val)           bfin_write16(SPI_SHADOW,val)
+
+/* TIMER0-7 Registers		(0xFFC00600 - 0xFFC006FF)								*/
+#define bfin_read_TIMER0_CONFIG()            bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val)        bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER()           bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val)       bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD()            bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val)        bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH()             bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val)         bfin_write32(TIMER0_WIDTH,val)
+
+#define bfin_read_TIMER1_CONFIG()            bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val)        bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER()           bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val)       bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD()            bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val)        bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH()             bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val)         bfin_write32(TIMER1_WIDTH,val)
+
+#define bfin_read_TIMER2_CONFIG()            bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val)        bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER()           bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val)       bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD()            bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val)        bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH()             bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val)         bfin_write32(TIMER2_WIDTH,val)
+
+#define bfin_read_TIMER3_CONFIG()            bfin_read16(TIMER3_CONFIG)
+#define bfin_write_TIMER3_CONFIG(val)        bfin_write16(TIMER3_CONFIG,val)
+#define bfin_read_TIMER3_COUNTER()           bfin_read32(TIMER3_COUNTER)
+#define bfin_write_TIMER3_COUNTER(val)       bfin_write32(TIMER3_COUNTER,val)
+#define bfin_read_TIMER3_PERIOD()            bfin_read32(TIMER3_PERIOD)
+#define bfin_write_TIMER3_PERIOD(val)        bfin_write32(TIMER3_PERIOD,val)
+#define bfin_read_TIMER3_WIDTH()             bfin_read32(TIMER3_WIDTH)
+#define bfin_write_TIMER3_WIDTH(val)         bfin_write32(TIMER3_WIDTH,val)
+
+#define bfin_read_TIMER4_CONFIG()            bfin_read16(TIMER4_CONFIG)
+#define bfin_write_TIMER4_CONFIG(val)        bfin_write16(TIMER4_CONFIG,val)
+#define bfin_read_TIMER4_COUNTER()           bfin_read32(TIMER4_COUNTER)
+#define bfin_write_TIMER4_COUNTER(val)       bfin_write32(TIMER4_COUNTER,val)
+#define bfin_read_TIMER4_PERIOD()            bfin_read32(TIMER4_PERIOD)
+#define bfin_write_TIMER4_PERIOD(val)        bfin_write32(TIMER4_PERIOD,val)
+#define bfin_read_TIMER4_WIDTH()             bfin_read32(TIMER4_WIDTH)
+#define bfin_write_TIMER4_WIDTH(val)         bfin_write32(TIMER4_WIDTH,val)
+
+#define bfin_read_TIMER5_CONFIG()            bfin_read16(TIMER5_CONFIG)
+#define bfin_write_TIMER5_CONFIG(val)        bfin_write16(TIMER5_CONFIG,val)
+#define bfin_read_TIMER5_COUNTER()           bfin_read32(TIMER5_COUNTER)
+#define bfin_write_TIMER5_COUNTER(val)       bfin_write32(TIMER5_COUNTER,val)
+#define bfin_read_TIMER5_PERIOD()            bfin_read32(TIMER5_PERIOD)
+#define bfin_write_TIMER5_PERIOD(val)        bfin_write32(TIMER5_PERIOD,val)
+#define bfin_read_TIMER5_WIDTH()             bfin_read32(TIMER5_WIDTH)
+#define bfin_write_TIMER5_WIDTH(val)         bfin_write32(TIMER5_WIDTH,val)
+
+#define bfin_read_TIMER6_CONFIG()            bfin_read16(TIMER6_CONFIG)
+#define bfin_write_TIMER6_CONFIG(val)        bfin_write16(TIMER6_CONFIG,val)
+#define bfin_read_TIMER6_COUNTER()           bfin_read32(TIMER6_COUNTER)
+#define bfin_write_TIMER6_COUNTER(val)       bfin_write32(TIMER6_COUNTER,val)
+#define bfin_read_TIMER6_PERIOD()            bfin_read32(TIMER6_PERIOD)
+#define bfin_write_TIMER6_PERIOD(val)        bfin_write32(TIMER6_PERIOD,val)
+#define bfin_read_TIMER6_WIDTH()             bfin_read32(TIMER6_WIDTH)
+#define bfin_write_TIMER6_WIDTH(val)         bfin_write32(TIMER6_WIDTH,val)
+
+#define bfin_read_TIMER7_CONFIG()            bfin_read16(TIMER7_CONFIG)
+#define bfin_write_TIMER7_CONFIG(val)        bfin_write16(TIMER7_CONFIG,val)
+#define bfin_read_TIMER7_COUNTER()           bfin_read32(TIMER7_COUNTER)
+#define bfin_write_TIMER7_COUNTER(val)       bfin_write32(TIMER7_COUNTER,val)
+#define bfin_read_TIMER7_PERIOD()            bfin_read32(TIMER7_PERIOD)
+#define bfin_write_TIMER7_PERIOD(val)        bfin_write32(TIMER7_PERIOD,val)
+#define bfin_read_TIMER7_WIDTH()             bfin_read32(TIMER7_WIDTH)
+#define bfin_write_TIMER7_WIDTH(val)         bfin_write32(TIMER7_WIDTH,val)
+
+#define bfin_read_TIMER_ENABLE()             bfin_read16(TIMER_ENABLE)
+#define bfin_write_TIMER_ENABLE(val)         bfin_write16(TIMER_ENABLE,val)
+#define bfin_read_TIMER_DISABLE()            bfin_read16(TIMER_DISABLE)
+#define bfin_write_TIMER_DISABLE(val)        bfin_write16(TIMER_DISABLE,val)
+#define bfin_read_TIMER_STATUS()             bfin_read32(TIMER_STATUS)
+#define bfin_write_TIMER_STATUS(val)         bfin_write32(TIMER_STATUS,val)
+
+/* General Purpose I/O Port F (0xFFC00700 - 0xFFC007FF)								*/
+#define bfin_read_PORTFIO()                  bfin_read16(PORTFIO)
+#define bfin_write_PORTFIO(val)              bfin_write16(PORTFIO,val)
+#define bfin_read_PORTFIO_CLEAR()            bfin_read16(PORTFIO_CLEAR)
+#define bfin_write_PORTFIO_CLEAR(val)        bfin_write16(PORTFIO_CLEAR,val)
+#define bfin_read_PORTFIO_SET()              bfin_read16(PORTFIO_SET)
+#define bfin_write_PORTFIO_SET(val)          bfin_write16(PORTFIO_SET,val)
+#define bfin_read_PORTFIO_TOGGLE()           bfin_read16(PORTFIO_TOGGLE)
+#define bfin_write_PORTFIO_TOGGLE(val)       bfin_write16(PORTFIO_TOGGLE,val)
+#define bfin_read_PORTFIO_MASKA()            bfin_read16(PORTFIO_MASKA)
+#define bfin_write_PORTFIO_MASKA(val)        bfin_write16(PORTFIO_MASKA,val)
+#define bfin_read_PORTFIO_MASKA_CLEAR()      bfin_read16(PORTFIO_MASKA_CLEAR)
+#define bfin_write_PORTFIO_MASKA_CLEAR(val)  bfin_write16(PORTFIO_MASKA_CLEAR,val)
+#define bfin_read_PORTFIO_MASKA_SET()        bfin_read16(PORTFIO_MASKA_SET)
+#define bfin_write_PORTFIO_MASKA_SET(val)    bfin_write16(PORTFIO_MASKA_SET,val)
+#define bfin_read_PORTFIO_MASKA_TOGGLE()     bfin_read16(PORTFIO_MASKA_TOGGLE)
+#define bfin_write_PORTFIO_MASKA_TOGGLE(val) bfin_write16(PORTFIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTFIO_MASKB()            bfin_read16(PORTFIO_MASKB)
+#define bfin_write_PORTFIO_MASKB(val)        bfin_write16(PORTFIO_MASKB,val)
+#define bfin_read_PORTFIO_MASKB_CLEAR()      bfin_read16(PORTFIO_MASKB_CLEAR)
+#define bfin_write_PORTFIO_MASKB_CLEAR(val)  bfin_write16(PORTFIO_MASKB_CLEAR,val)
+#define bfin_read_PORTFIO_MASKB_SET()        bfin_read16(PORTFIO_MASKB_SET)
+#define bfin_write_PORTFIO_MASKB_SET(val)    bfin_write16(PORTFIO_MASKB_SET,val)
+#define bfin_read_PORTFIO_MASKB_TOGGLE()     bfin_read16(PORTFIO_MASKB_TOGGLE)
+#define bfin_write_PORTFIO_MASKB_TOGGLE(val) bfin_write16(PORTFIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTFIO_DIR()              bfin_read16(PORTFIO_DIR)
+#define bfin_write_PORTFIO_DIR(val)          bfin_write16(PORTFIO_DIR,val)
+#define bfin_read_PORTFIO_POLAR()            bfin_read16(PORTFIO_POLAR)
+#define bfin_write_PORTFIO_POLAR(val)        bfin_write16(PORTFIO_POLAR,val)
+#define bfin_read_PORTFIO_EDGE()             bfin_read16(PORTFIO_EDGE)
+#define bfin_write_PORTFIO_EDGE(val)         bfin_write16(PORTFIO_EDGE,val)
+#define bfin_read_PORTFIO_BOTH()             bfin_read16(PORTFIO_BOTH)
+#define bfin_write_PORTFIO_BOTH(val)         bfin_write16(PORTFIO_BOTH,val)
+#define bfin_read_PORTFIO_INEN()             bfin_read16(PORTFIO_INEN)
+#define bfin_write_PORTFIO_INEN(val)         bfin_write16(PORTFIO_INEN,val)
+
+/* SPORT0 Controller		(0xFFC00800 - 0xFFC008FF)								*/
+#define bfin_read_SPORT0_TCR1()              bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val)          bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2()              bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val)          bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV()           bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val)       bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV()            bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val)        bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX()                bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val)            bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX()                bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val)            bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32()              bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val)          bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32()              bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val)          bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16()              bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val)          bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16()              bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val)          bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1()              bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val)          bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2()              bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val)          bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV()           bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val)       bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV()            bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val)        bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT()              bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val)          bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL()              bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val)          bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1()             bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val)         bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2()             bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val)         bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0()             bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val)         bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1()             bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val)         bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2()             bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val)         bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3()             bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val)         bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0()             bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val)         bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1()             bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val)         bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2()             bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val)         bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3()             bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val)         bfin_write32(SPORT0_MRCS3,val)
+
+/* SPORT1 Controller		(0xFFC00900 - 0xFFC009FF)								*/
+#define bfin_read_SPORT1_TCR1()              bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val)          bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2()              bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val)          bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV()           bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val)       bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV()            bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val)        bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX()                bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val)            bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX()                bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val)            bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32()              bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val)          bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32()              bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val)          bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16()              bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val)          bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16()              bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val)          bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1()              bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val)          bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2()              bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val)          bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV()           bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val)       bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV()            bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val)        bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT()              bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val)          bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL()              bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val)          bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1()             bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val)         bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2()             bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val)         bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0()             bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val)         bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1()             bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val)         bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2()             bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val)         bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3()             bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val)         bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0()             bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val)         bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1()             bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val)         bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2()             bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val)         bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3()             bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val)         bfin_write32(SPORT1_MRCS3,val)
+
+/* External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF)							*/
+#define bfin_read_EBIU_AMGCTL()              bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val)          bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0()             bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val)         bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1()             bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val)         bfin_write32(EBIU_AMBCTL1,val)
+#define bfin_read_EBIU_SDGCTL()              bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val)          bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDBCTL()              bfin_read16(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val)          bfin_write16(EBIU_SDBCTL,val)
+#define bfin_read_EBIU_SDRRC()               bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val)           bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT()              bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val)          bfin_write16(EBIU_SDSTAT,val)
+
+/* DMA Traffic Control Registers													*/
+#define	pDMA_TCPER			((volatile unsigned short *)DMA_TCPER)
+#define bfin_read_DMA_TCPER()                bfin_read16(DMA_TCPER)
+#define bfin_write_DMA_TCPER(val)            bfin_write16(DMA_TCPER,val)
+#define	pDMA_TCCNT			((volatile unsigned short *)DMA_TCCNT)
+#define bfin_read_DMA_TCCNT()                bfin_read16(DMA_TCCNT)
+#define bfin_write_DMA_TCCNT(val)            bfin_write16(DMA_TCCNT,val)
+
+/* DMA Controller																	*/
+#define bfin_read_DMA0_CONFIG()              bfin_read16(DMA0_CONFIG)
+#define bfin_write_DMA0_CONFIG(val)          bfin_write16(DMA0_CONFIG,val)
+#define bfin_read_DMA0_NEXT_DESC_PTR()       bfin_read32(DMA0_NEXT_DESC_PTR)
+#define bfin_write_DMA0_NEXT_DESC_PTR(val)   bfin_write32(DMA0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA0_START_ADDR()          bfin_read32(DMA0_START_ADDR)
+#define bfin_write_DMA0_START_ADDR(val)      bfin_write32(DMA0_START_ADDR,val)
+#define bfin_read_DMA0_X_COUNT()             bfin_read16(DMA0_X_COUNT)
+#define bfin_write_DMA0_X_COUNT(val)         bfin_write16(DMA0_X_COUNT,val)
+#define bfin_read_DMA0_Y_COUNT()             bfin_read16(DMA0_Y_COUNT)
+#define bfin_write_DMA0_Y_COUNT(val)         bfin_write16(DMA0_Y_COUNT,val)
+#define bfin_read_DMA0_X_MODIFY()            bfin_read16(DMA0_X_MODIFY)
+#define bfin_write_DMA0_X_MODIFY(val)        bfin_write16(DMA0_X_MODIFY,val)
+#define bfin_read_DMA0_Y_MODIFY()            bfin_read16(DMA0_Y_MODIFY)
+#define bfin_write_DMA0_Y_MODIFY(val)        bfin_write16(DMA0_Y_MODIFY,val)
+#define bfin_read_DMA0_CURR_DESC_PTR()       bfin_read32(DMA0_CURR_DESC_PTR)
+#define bfin_write_DMA0_CURR_DESC_PTR(val)   bfin_write32(DMA0_CURR_DESC_PTR,val)
+#define bfin_read_DMA0_CURR_ADDR()           bfin_read32(DMA0_CURR_ADDR)
+#define bfin_write_DMA0_CURR_ADDR(val)       bfin_write32(DMA0_CURR_ADDR,val)
+#define bfin_read_DMA0_CURR_X_COUNT()        bfin_read16(DMA0_CURR_X_COUNT)
+#define bfin_write_DMA0_CURR_X_COUNT(val)    bfin_write16(DMA0_CURR_X_COUNT,val)
+#define bfin_read_DMA0_CURR_Y_COUNT()        bfin_read16(DMA0_CURR_Y_COUNT)
+#define bfin_write_DMA0_CURR_Y_COUNT(val)    bfin_write16(DMA0_CURR_Y_COUNT,val)
+#define bfin_read_DMA0_IRQ_STATUS()          bfin_read16(DMA0_IRQ_STATUS)
+#define bfin_write_DMA0_IRQ_STATUS(val)      bfin_write16(DMA0_IRQ_STATUS,val)
+#define bfin_read_DMA0_PERIPHERAL_MAP()      bfin_read16(DMA0_PERIPHERAL_MAP)
+#define bfin_write_DMA0_PERIPHERAL_MAP(val)  bfin_write16(DMA0_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA1_CONFIG()              bfin_read16(DMA1_CONFIG)
+#define bfin_write_DMA1_CONFIG(val)          bfin_write16(DMA1_CONFIG,val)
+#define bfin_read_DMA1_NEXT_DESC_PTR()       bfin_read32(DMA1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_NEXT_DESC_PTR(val)   bfin_write32(DMA1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_START_ADDR()          bfin_read32(DMA1_START_ADDR)
+#define bfin_write_DMA1_START_ADDR(val)      bfin_write32(DMA1_START_ADDR,val)
+#define bfin_read_DMA1_X_COUNT()             bfin_read16(DMA1_X_COUNT)
+#define bfin_write_DMA1_X_COUNT(val)         bfin_write16(DMA1_X_COUNT,val)
+#define bfin_read_DMA1_Y_COUNT()             bfin_read16(DMA1_Y_COUNT)
+#define bfin_write_DMA1_Y_COUNT(val)         bfin_write16(DMA1_Y_COUNT,val)
+#define bfin_read_DMA1_X_MODIFY()            bfin_read16(DMA1_X_MODIFY)
+#define bfin_write_DMA1_X_MODIFY(val)        bfin_write16(DMA1_X_MODIFY,val)
+#define bfin_read_DMA1_Y_MODIFY()            bfin_read16(DMA1_Y_MODIFY)
+#define bfin_write_DMA1_Y_MODIFY(val)        bfin_write16(DMA1_Y_MODIFY,val)
+#define bfin_read_DMA1_CURR_DESC_PTR()       bfin_read32(DMA1_CURR_DESC_PTR)
+#define bfin_write_DMA1_CURR_DESC_PTR(val)   bfin_write32(DMA1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_CURR_ADDR()           bfin_read32(DMA1_CURR_ADDR)
+#define bfin_write_DMA1_CURR_ADDR(val)       bfin_write32(DMA1_CURR_ADDR,val)
+#define bfin_read_DMA1_CURR_X_COUNT()        bfin_read16(DMA1_CURR_X_COUNT)
+#define bfin_write_DMA1_CURR_X_COUNT(val)    bfin_write16(DMA1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_CURR_Y_COUNT()        bfin_read16(DMA1_CURR_Y_COUNT)
+#define bfin_write_DMA1_CURR_Y_COUNT(val)    bfin_write16(DMA1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_IRQ_STATUS()          bfin_read16(DMA1_IRQ_STATUS)
+#define bfin_write_DMA1_IRQ_STATUS(val)      bfin_write16(DMA1_IRQ_STATUS,val)
+#define bfin_read_DMA1_PERIPHERAL_MAP()      bfin_read16(DMA1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_PERIPHERAL_MAP(val)  bfin_write16(DMA1_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA2_CONFIG()              bfin_read16(DMA2_CONFIG)
+#define bfin_write_DMA2_CONFIG(val)          bfin_write16(DMA2_CONFIG,val)
+#define bfin_read_DMA2_NEXT_DESC_PTR()       bfin_read32(DMA2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_NEXT_DESC_PTR(val)   bfin_write32(DMA2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_START_ADDR()          bfin_read32(DMA2_START_ADDR)
+#define bfin_write_DMA2_START_ADDR(val)      bfin_write32(DMA2_START_ADDR,val)
+#define bfin_read_DMA2_X_COUNT()             bfin_read16(DMA2_X_COUNT)
+#define bfin_write_DMA2_X_COUNT(val)         bfin_write16(DMA2_X_COUNT,val)
+#define bfin_read_DMA2_Y_COUNT()             bfin_read16(DMA2_Y_COUNT)
+#define bfin_write_DMA2_Y_COUNT(val)         bfin_write16(DMA2_Y_COUNT,val)
+#define bfin_read_DMA2_X_MODIFY()            bfin_read16(DMA2_X_MODIFY)
+#define bfin_write_DMA2_X_MODIFY(val)        bfin_write16(DMA2_X_MODIFY,val)
+#define bfin_read_DMA2_Y_MODIFY()            bfin_read16(DMA2_Y_MODIFY)
+#define bfin_write_DMA2_Y_MODIFY(val)        bfin_write16(DMA2_Y_MODIFY,val)
+#define bfin_read_DMA2_CURR_DESC_PTR()       bfin_read32(DMA2_CURR_DESC_PTR)
+#define bfin_write_DMA2_CURR_DESC_PTR(val)   bfin_write32(DMA2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_CURR_ADDR()           bfin_read32(DMA2_CURR_ADDR)
+#define bfin_write_DMA2_CURR_ADDR(val)       bfin_write32(DMA2_CURR_ADDR,val)
+#define bfin_read_DMA2_CURR_X_COUNT()        bfin_read16(DMA2_CURR_X_COUNT)
+#define bfin_write_DMA2_CURR_X_COUNT(val)    bfin_write16(DMA2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_CURR_Y_COUNT()        bfin_read16(DMA2_CURR_Y_COUNT)
+#define bfin_write_DMA2_CURR_Y_COUNT(val)    bfin_write16(DMA2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_IRQ_STATUS()          bfin_read16(DMA2_IRQ_STATUS)
+#define bfin_write_DMA2_IRQ_STATUS(val)      bfin_write16(DMA2_IRQ_STATUS,val)
+#define bfin_read_DMA2_PERIPHERAL_MAP()      bfin_read16(DMA2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_PERIPHERAL_MAP(val)  bfin_write16(DMA2_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA3_CONFIG()              bfin_read16(DMA3_CONFIG)
+#define bfin_write_DMA3_CONFIG(val)          bfin_write16(DMA3_CONFIG,val)
+#define bfin_read_DMA3_NEXT_DESC_PTR()       bfin_read32(DMA3_NEXT_DESC_PTR)
+#define bfin_write_DMA3_NEXT_DESC_PTR(val)   bfin_write32(DMA3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA3_START_ADDR()          bfin_read32(DMA3_START_ADDR)
+#define bfin_write_DMA3_START_ADDR(val)      bfin_write32(DMA3_START_ADDR,val)
+#define bfin_read_DMA3_X_COUNT()             bfin_read16(DMA3_X_COUNT)
+#define bfin_write_DMA3_X_COUNT(val)         bfin_write16(DMA3_X_COUNT,val)
+#define bfin_read_DMA3_Y_COUNT()             bfin_read16(DMA3_Y_COUNT)
+#define bfin_write_DMA3_Y_COUNT(val)         bfin_write16(DMA3_Y_COUNT,val)
+#define bfin_read_DMA3_X_MODIFY()            bfin_read16(DMA3_X_MODIFY)
+#define bfin_write_DMA3_X_MODIFY(val)        bfin_write16(DMA3_X_MODIFY,val)
+#define bfin_read_DMA3_Y_MODIFY()            bfin_read16(DMA3_Y_MODIFY)
+#define bfin_write_DMA3_Y_MODIFY(val)        bfin_write16(DMA3_Y_MODIFY,val)
+#define bfin_read_DMA3_CURR_DESC_PTR()       bfin_read32(DMA3_CURR_DESC_PTR)
+#define bfin_write_DMA3_CURR_DESC_PTR(val)   bfin_write32(DMA3_CURR_DESC_PTR,val)
+#define bfin_read_DMA3_CURR_ADDR()           bfin_read32(DMA3_CURR_ADDR)
+#define bfin_write_DMA3_CURR_ADDR(val)       bfin_write32(DMA3_CURR_ADDR,val)
+#define bfin_read_DMA3_CURR_X_COUNT()        bfin_read16(DMA3_CURR_X_COUNT)
+#define bfin_write_DMA3_CURR_X_COUNT(val)    bfin_write16(DMA3_CURR_X_COUNT,val)
+#define bfin_read_DMA3_CURR_Y_COUNT()        bfin_read16(DMA3_CURR_Y_COUNT)
+#define bfin_write_DMA3_CURR_Y_COUNT(val)    bfin_write16(DMA3_CURR_Y_COUNT,val)
+#define bfin_read_DMA3_IRQ_STATUS()          bfin_read16(DMA3_IRQ_STATUS)
+#define bfin_write_DMA3_IRQ_STATUS(val)      bfin_write16(DMA3_IRQ_STATUS,val)
+#define bfin_read_DMA3_PERIPHERAL_MAP()      bfin_read16(DMA3_PERIPHERAL_MAP)
+#define bfin_write_DMA3_PERIPHERAL_MAP(val)  bfin_write16(DMA3_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA4_CONFIG()              bfin_read16(DMA4_CONFIG)
+#define bfin_write_DMA4_CONFIG(val)          bfin_write16(DMA4_CONFIG,val)
+#define bfin_read_DMA4_NEXT_DESC_PTR()       bfin_read32(DMA4_NEXT_DESC_PTR)
+#define bfin_write_DMA4_NEXT_DESC_PTR(val)   bfin_write32(DMA4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA4_START_ADDR()          bfin_read32(DMA4_START_ADDR)
+#define bfin_write_DMA4_START_ADDR(val)      bfin_write32(DMA4_START_ADDR,val)
+#define bfin_read_DMA4_X_COUNT()             bfin_read16(DMA4_X_COUNT)
+#define bfin_write_DMA4_X_COUNT(val)         bfin_write16(DMA4_X_COUNT,val)
+#define bfin_read_DMA4_Y_COUNT()             bfin_read16(DMA4_Y_COUNT)
+#define bfin_write_DMA4_Y_COUNT(val)         bfin_write16(DMA4_Y_COUNT,val)
+#define bfin_read_DMA4_X_MODIFY()            bfin_read16(DMA4_X_MODIFY)
+#define bfin_write_DMA4_X_MODIFY(val)        bfin_write16(DMA4_X_MODIFY,val)
+#define bfin_read_DMA4_Y_MODIFY()            bfin_read16(DMA4_Y_MODIFY)
+#define bfin_write_DMA4_Y_MODIFY(val)        bfin_write16(DMA4_Y_MODIFY,val)
+#define bfin_read_DMA4_CURR_DESC_PTR()       bfin_read32(DMA4_CURR_DESC_PTR)
+#define bfin_write_DMA4_CURR_DESC_PTR(val)   bfin_write32(DMA4_CURR_DESC_PTR,val)
+#define bfin_read_DMA4_CURR_ADDR()           bfin_read32(DMA4_CURR_ADDR)
+#define bfin_write_DMA4_CURR_ADDR(val)       bfin_write32(DMA4_CURR_ADDR,val)
+#define bfin_read_DMA4_CURR_X_COUNT()        bfin_read16(DMA4_CURR_X_COUNT)
+#define bfin_write_DMA4_CURR_X_COUNT(val)    bfin_write16(DMA4_CURR_X_COUNT,val)
+#define bfin_read_DMA4_CURR_Y_COUNT()        bfin_read16(DMA4_CURR_Y_COUNT)
+#define bfin_write_DMA4_CURR_Y_COUNT(val)    bfin_write16(DMA4_CURR_Y_COUNT,val)
+#define bfin_read_DMA4_IRQ_STATUS()          bfin_read16(DMA4_IRQ_STATUS)
+#define bfin_write_DMA4_IRQ_STATUS(val)      bfin_write16(DMA4_IRQ_STATUS,val)
+#define bfin_read_DMA4_PERIPHERAL_MAP()      bfin_read16(DMA4_PERIPHERAL_MAP)
+#define bfin_write_DMA4_PERIPHERAL_MAP(val)  bfin_write16(DMA4_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA5_CONFIG()              bfin_read16(DMA5_CONFIG)
+#define bfin_write_DMA5_CONFIG(val)          bfin_write16(DMA5_CONFIG,val)
+#define bfin_read_DMA5_NEXT_DESC_PTR()       bfin_read32(DMA5_NEXT_DESC_PTR)
+#define bfin_write_DMA5_NEXT_DESC_PTR(val)   bfin_write32(DMA5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA5_START_ADDR()          bfin_read32(DMA5_START_ADDR)
+#define bfin_write_DMA5_START_ADDR(val)      bfin_write32(DMA5_START_ADDR,val)
+#define bfin_read_DMA5_X_COUNT()             bfin_read16(DMA5_X_COUNT)
+#define bfin_write_DMA5_X_COUNT(val)         bfin_write16(DMA5_X_COUNT,val)
+#define bfin_read_DMA5_Y_COUNT()             bfin_read16(DMA5_Y_COUNT)
+#define bfin_write_DMA5_Y_COUNT(val)         bfin_write16(DMA5_Y_COUNT,val)
+#define bfin_read_DMA5_X_MODIFY()            bfin_read16(DMA5_X_MODIFY)
+#define bfin_write_DMA5_X_MODIFY(val)        bfin_write16(DMA5_X_MODIFY,val)
+#define bfin_read_DMA5_Y_MODIFY()            bfin_read16(DMA5_Y_MODIFY)
+#define bfin_write_DMA5_Y_MODIFY(val)        bfin_write16(DMA5_Y_MODIFY,val)
+#define bfin_read_DMA5_CURR_DESC_PTR()       bfin_read32(DMA5_CURR_DESC_PTR)
+#define bfin_write_DMA5_CURR_DESC_PTR(val)   bfin_write32(DMA5_CURR_DESC_PTR,val)
+#define bfin_read_DMA5_CURR_ADDR()           bfin_read32(DMA5_CURR_ADDR)
+#define bfin_write_DMA5_CURR_ADDR(val)       bfin_write32(DMA5_CURR_ADDR,val)
+#define bfin_read_DMA5_CURR_X_COUNT()        bfin_read16(DMA5_CURR_X_COUNT)
+#define bfin_write_DMA5_CURR_X_COUNT(val)    bfin_write16(DMA5_CURR_X_COUNT,val)
+#define bfin_read_DMA5_CURR_Y_COUNT()        bfin_read16(DMA5_CURR_Y_COUNT)
+#define bfin_write_DMA5_CURR_Y_COUNT(val)    bfin_write16(DMA5_CURR_Y_COUNT,val)
+#define bfin_read_DMA5_IRQ_STATUS()          bfin_read16(DMA5_IRQ_STATUS)
+#define bfin_write_DMA5_IRQ_STATUS(val)      bfin_write16(DMA5_IRQ_STATUS,val)
+#define bfin_read_DMA5_PERIPHERAL_MAP()      bfin_read16(DMA5_PERIPHERAL_MAP)
+#define bfin_write_DMA5_PERIPHERAL_MAP(val)  bfin_write16(DMA5_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA6_CONFIG()              bfin_read16(DMA6_CONFIG)
+#define bfin_write_DMA6_CONFIG(val)          bfin_write16(DMA6_CONFIG,val)
+#define bfin_read_DMA6_NEXT_DESC_PTR()       bfin_read32(DMA6_NEXT_DESC_PTR)
+#define bfin_write_DMA6_NEXT_DESC_PTR(val)   bfin_write32(DMA6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA6_START_ADDR()          bfin_read32(DMA6_START_ADDR)
+#define bfin_write_DMA6_START_ADDR(val)      bfin_write32(DMA6_START_ADDR,val)
+#define bfin_read_DMA6_X_COUNT()             bfin_read16(DMA6_X_COUNT)
+#define bfin_write_DMA6_X_COUNT(val)         bfin_write16(DMA6_X_COUNT,val)
+#define bfin_read_DMA6_Y_COUNT()             bfin_read16(DMA6_Y_COUNT)
+#define bfin_write_DMA6_Y_COUNT(val)         bfin_write16(DMA6_Y_COUNT,val)
+#define bfin_read_DMA6_X_MODIFY()            bfin_read16(DMA6_X_MODIFY)
+#define bfin_write_DMA6_X_MODIFY(val)        bfin_write16(DMA6_X_MODIFY,val)
+#define bfin_read_DMA6_Y_MODIFY()            bfin_read16(DMA6_Y_MODIFY)
+#define bfin_write_DMA6_Y_MODIFY(val)        bfin_write16(DMA6_Y_MODIFY,val)
+#define bfin_read_DMA6_CURR_DESC_PTR()       bfin_read32(DMA6_CURR_DESC_PTR)
+#define bfin_write_DMA6_CURR_DESC_PTR(val)   bfin_write32(DMA6_CURR_DESC_PTR,val)
+#define bfin_read_DMA6_CURR_ADDR()           bfin_read32(DMA6_CURR_ADDR)
+#define bfin_write_DMA6_CURR_ADDR(val)       bfin_write32(DMA6_CURR_ADDR,val)
+#define bfin_read_DMA6_CURR_X_COUNT()        bfin_read16(DMA6_CURR_X_COUNT)
+#define bfin_write_DMA6_CURR_X_COUNT(val)    bfin_write16(DMA6_CURR_X_COUNT,val)
+#define bfin_read_DMA6_CURR_Y_COUNT()        bfin_read16(DMA6_CURR_Y_COUNT)
+#define bfin_write_DMA6_CURR_Y_COUNT(val)    bfin_write16(DMA6_CURR_Y_COUNT,val)
+#define bfin_read_DMA6_IRQ_STATUS()          bfin_read16(DMA6_IRQ_STATUS)
+#define bfin_write_DMA6_IRQ_STATUS(val)      bfin_write16(DMA6_IRQ_STATUS,val)
+#define bfin_read_DMA6_PERIPHERAL_MAP()      bfin_read16(DMA6_PERIPHERAL_MAP)
+#define bfin_write_DMA6_PERIPHERAL_MAP(val)  bfin_write16(DMA6_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA7_CONFIG()              bfin_read16(DMA7_CONFIG)
+#define bfin_write_DMA7_CONFIG(val)          bfin_write16(DMA7_CONFIG,val)
+#define bfin_read_DMA7_NEXT_DESC_PTR()       bfin_read32(DMA7_NEXT_DESC_PTR)
+#define bfin_write_DMA7_NEXT_DESC_PTR(val)   bfin_write32(DMA7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA7_START_ADDR()          bfin_read32(DMA7_START_ADDR)
+#define bfin_write_DMA7_START_ADDR(val)      bfin_write32(DMA7_START_ADDR,val)
+#define bfin_read_DMA7_X_COUNT()             bfin_read16(DMA7_X_COUNT)
+#define bfin_write_DMA7_X_COUNT(val)         bfin_write16(DMA7_X_COUNT,val)
+#define bfin_read_DMA7_Y_COUNT()             bfin_read16(DMA7_Y_COUNT)
+#define bfin_write_DMA7_Y_COUNT(val)         bfin_write16(DMA7_Y_COUNT,val)
+#define bfin_read_DMA7_X_MODIFY()            bfin_read16(DMA7_X_MODIFY)
+#define bfin_write_DMA7_X_MODIFY(val)        bfin_write16(DMA7_X_MODIFY,val)
+#define bfin_read_DMA7_Y_MODIFY()            bfin_read16(DMA7_Y_MODIFY)
+#define bfin_write_DMA7_Y_MODIFY(val)        bfin_write16(DMA7_Y_MODIFY,val)
+#define bfin_read_DMA7_CURR_DESC_PTR()       bfin_read32(DMA7_CURR_DESC_PTR)
+#define bfin_write_DMA7_CURR_DESC_PTR(val)   bfin_write32(DMA7_CURR_DESC_PTR,val)
+#define bfin_read_DMA7_CURR_ADDR()           bfin_read32(DMA7_CURR_ADDR)
+#define bfin_write_DMA7_CURR_ADDR(val)       bfin_write32(DMA7_CURR_ADDR,val)
+#define bfin_read_DMA7_CURR_X_COUNT()        bfin_read16(DMA7_CURR_X_COUNT)
+#define bfin_write_DMA7_CURR_X_COUNT(val)    bfin_write16(DMA7_CURR_X_COUNT,val)
+#define bfin_read_DMA7_CURR_Y_COUNT()        bfin_read16(DMA7_CURR_Y_COUNT)
+#define bfin_write_DMA7_CURR_Y_COUNT(val)    bfin_write16(DMA7_CURR_Y_COUNT,val)
+#define bfin_read_DMA7_IRQ_STATUS()          bfin_read16(DMA7_IRQ_STATUS)
+#define bfin_write_DMA7_IRQ_STATUS(val)      bfin_write16(DMA7_IRQ_STATUS,val)
+#define bfin_read_DMA7_PERIPHERAL_MAP()      bfin_read16(DMA7_PERIPHERAL_MAP)
+#define bfin_write_DMA7_PERIPHERAL_MAP(val)  bfin_write16(DMA7_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA8_CONFIG()              bfin_read16(DMA8_CONFIG)
+#define bfin_write_DMA8_CONFIG(val)          bfin_write16(DMA8_CONFIG,val)
+#define bfin_read_DMA8_NEXT_DESC_PTR()       bfin_read32(DMA8_NEXT_DESC_PTR)
+#define bfin_write_DMA8_NEXT_DESC_PTR(val)   bfin_write32(DMA8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA8_START_ADDR()          bfin_read32(DMA8_START_ADDR)
+#define bfin_write_DMA8_START_ADDR(val)      bfin_write32(DMA8_START_ADDR,val)
+#define bfin_read_DMA8_X_COUNT()             bfin_read16(DMA8_X_COUNT)
+#define bfin_write_DMA8_X_COUNT(val)         bfin_write16(DMA8_X_COUNT,val)
+#define bfin_read_DMA8_Y_COUNT()             bfin_read16(DMA8_Y_COUNT)
+#define bfin_write_DMA8_Y_COUNT(val)         bfin_write16(DMA8_Y_COUNT,val)
+#define bfin_read_DMA8_X_MODIFY()            bfin_read16(DMA8_X_MODIFY)
+#define bfin_write_DMA8_X_MODIFY(val)        bfin_write16(DMA8_X_MODIFY,val)
+#define bfin_read_DMA8_Y_MODIFY()            bfin_read16(DMA8_Y_MODIFY)
+#define bfin_write_DMA8_Y_MODIFY(val)        bfin_write16(DMA8_Y_MODIFY,val)
+#define bfin_read_DMA8_CURR_DESC_PTR()       bfin_read32(DMA8_CURR_DESC_PTR)
+#define bfin_write_DMA8_CURR_DESC_PTR(val)   bfin_write32(DMA8_CURR_DESC_PTR,val)
+#define bfin_read_DMA8_CURR_ADDR()           bfin_read32(DMA8_CURR_ADDR)
+#define bfin_write_DMA8_CURR_ADDR(val)       bfin_write32(DMA8_CURR_ADDR,val)
+#define bfin_read_DMA8_CURR_X_COUNT()        bfin_read16(DMA8_CURR_X_COUNT)
+#define bfin_write_DMA8_CURR_X_COUNT(val)    bfin_write16(DMA8_CURR_X_COUNT,val)
+#define bfin_read_DMA8_CURR_Y_COUNT()        bfin_read16(DMA8_CURR_Y_COUNT)
+#define bfin_write_DMA8_CURR_Y_COUNT(val)    bfin_write16(DMA8_CURR_Y_COUNT,val)
+#define bfin_read_DMA8_IRQ_STATUS()          bfin_read16(DMA8_IRQ_STATUS)
+#define bfin_write_DMA8_IRQ_STATUS(val)      bfin_write16(DMA8_IRQ_STATUS,val)
+#define bfin_read_DMA8_PERIPHERAL_MAP()      bfin_read16(DMA8_PERIPHERAL_MAP)
+#define bfin_write_DMA8_PERIPHERAL_MAP(val)  bfin_write16(DMA8_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA9_CONFIG()              bfin_read16(DMA9_CONFIG)
+#define bfin_write_DMA9_CONFIG(val)          bfin_write16(DMA9_CONFIG,val)
+#define bfin_read_DMA9_NEXT_DESC_PTR()       bfin_read32(DMA9_NEXT_DESC_PTR)
+#define bfin_write_DMA9_NEXT_DESC_PTR(val)   bfin_write32(DMA9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA9_START_ADDR()          bfin_read32(DMA9_START_ADDR)
+#define bfin_write_DMA9_START_ADDR(val)      bfin_write32(DMA9_START_ADDR,val)
+#define bfin_read_DMA9_X_COUNT()             bfin_read16(DMA9_X_COUNT)
+#define bfin_write_DMA9_X_COUNT(val)         bfin_write16(DMA9_X_COUNT,val)
+#define bfin_read_DMA9_Y_COUNT()             bfin_read16(DMA9_Y_COUNT)
+#define bfin_write_DMA9_Y_COUNT(val)         bfin_write16(DMA9_Y_COUNT,val)
+#define bfin_read_DMA9_X_MODIFY()            bfin_read16(DMA9_X_MODIFY)
+#define bfin_write_DMA9_X_MODIFY(val)        bfin_write16(DMA9_X_MODIFY,val)
+#define bfin_read_DMA9_Y_MODIFY()            bfin_read16(DMA9_Y_MODIFY)
+#define bfin_write_DMA9_Y_MODIFY(val)        bfin_write16(DMA9_Y_MODIFY,val)
+#define bfin_read_DMA9_CURR_DESC_PTR()       bfin_read32(DMA9_CURR_DESC_PTR)
+#define bfin_write_DMA9_CURR_DESC_PTR(val)   bfin_write32(DMA9_CURR_DESC_PTR,val)
+#define bfin_read_DMA9_CURR_ADDR()           bfin_read32(DMA9_CURR_ADDR)
+#define bfin_write_DMA9_CURR_ADDR(val)       bfin_write32(DMA9_CURR_ADDR,val)
+#define bfin_read_DMA9_CURR_X_COUNT()        bfin_read16(DMA9_CURR_X_COUNT)
+#define bfin_write_DMA9_CURR_X_COUNT(val)    bfin_write16(DMA9_CURR_X_COUNT,val)
+#define bfin_read_DMA9_CURR_Y_COUNT()        bfin_read16(DMA9_CURR_Y_COUNT)
+#define bfin_write_DMA9_CURR_Y_COUNT(val)    bfin_write16(DMA9_CURR_Y_COUNT,val)
+#define bfin_read_DMA9_IRQ_STATUS()          bfin_read16(DMA9_IRQ_STATUS)
+#define bfin_write_DMA9_IRQ_STATUS(val)      bfin_write16(DMA9_IRQ_STATUS,val)
+#define bfin_read_DMA9_PERIPHERAL_MAP()      bfin_read16(DMA9_PERIPHERAL_MAP)
+#define bfin_write_DMA9_PERIPHERAL_MAP(val)  bfin_write16(DMA9_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA10_CONFIG()             bfin_read16(DMA10_CONFIG)
+#define bfin_write_DMA10_CONFIG(val)         bfin_write16(DMA10_CONFIG,val)
+#define bfin_read_DMA10_NEXT_DESC_PTR()      bfin_read32(DMA10_NEXT_DESC_PTR)
+#define bfin_write_DMA10_NEXT_DESC_PTR(val)  bfin_write32(DMA10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA10_START_ADDR()         bfin_read32(DMA10_START_ADDR)
+#define bfin_write_DMA10_START_ADDR(val)     bfin_write32(DMA10_START_ADDR,val)
+#define bfin_read_DMA10_X_COUNT()            bfin_read16(DMA10_X_COUNT)
+#define bfin_write_DMA10_X_COUNT(val)        bfin_write16(DMA10_X_COUNT,val)
+#define bfin_read_DMA10_Y_COUNT()            bfin_read16(DMA10_Y_COUNT)
+#define bfin_write_DMA10_Y_COUNT(val)        bfin_write16(DMA10_Y_COUNT,val)
+#define bfin_read_DMA10_X_MODIFY()           bfin_read16(DMA10_X_MODIFY)
+#define bfin_write_DMA10_X_MODIFY(val)       bfin_write16(DMA10_X_MODIFY,val)
+#define bfin_read_DMA10_Y_MODIFY()           bfin_read16(DMA10_Y_MODIFY)
+#define bfin_write_DMA10_Y_MODIFY(val)       bfin_write16(DMA10_Y_MODIFY,val)
+#define bfin_read_DMA10_CURR_DESC_PTR()      bfin_read32(DMA10_CURR_DESC_PTR)
+#define bfin_write_DMA10_CURR_DESC_PTR(val)  bfin_write32(DMA10_CURR_DESC_PTR,val)
+#define bfin_read_DMA10_CURR_ADDR()          bfin_read32(DMA10_CURR_ADDR)
+#define bfin_write_DMA10_CURR_ADDR(val)      bfin_write32(DMA10_CURR_ADDR,val)
+#define bfin_read_DMA10_CURR_X_COUNT()       bfin_read16(DMA10_CURR_X_COUNT)
+#define bfin_write_DMA10_CURR_X_COUNT(val)   bfin_write16(DMA10_CURR_X_COUNT,val)
+#define bfin_read_DMA10_CURR_Y_COUNT()       bfin_read16(DMA10_CURR_Y_COUNT)
+#define bfin_write_DMA10_CURR_Y_COUNT(val)   bfin_write16(DMA10_CURR_Y_COUNT,val)
+#define bfin_read_DMA10_IRQ_STATUS()         bfin_read16(DMA10_IRQ_STATUS)
+#define bfin_write_DMA10_IRQ_STATUS(val)     bfin_write16(DMA10_IRQ_STATUS,val)
+#define bfin_read_DMA10_PERIPHERAL_MAP()     bfin_read16(DMA10_PERIPHERAL_MAP)
+#define bfin_write_DMA10_PERIPHERAL_MAP(val) bfin_write16(DMA10_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA11_CONFIG()             bfin_read16(DMA11_CONFIG)
+#define bfin_write_DMA11_CONFIG(val)         bfin_write16(DMA11_CONFIG,val)
+#define bfin_read_DMA11_NEXT_DESC_PTR()      bfin_read32(DMA11_NEXT_DESC_PTR)
+#define bfin_write_DMA11_NEXT_DESC_PTR(val)  bfin_write32(DMA11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA11_START_ADDR()         bfin_read32(DMA11_START_ADDR)
+#define bfin_write_DMA11_START_ADDR(val)     bfin_write32(DMA11_START_ADDR,val)
+#define bfin_read_DMA11_X_COUNT()            bfin_read16(DMA11_X_COUNT)
+#define bfin_write_DMA11_X_COUNT(val)        bfin_write16(DMA11_X_COUNT,val)
+#define bfin_read_DMA11_Y_COUNT()            bfin_read16(DMA11_Y_COUNT)
+#define bfin_write_DMA11_Y_COUNT(val)        bfin_write16(DMA11_Y_COUNT,val)
+#define bfin_read_DMA11_X_MODIFY()           bfin_read16(DMA11_X_MODIFY)
+#define bfin_write_DMA11_X_MODIFY(val)       bfin_write16(DMA11_X_MODIFY,val)
+#define bfin_read_DMA11_Y_MODIFY()           bfin_read16(DMA11_Y_MODIFY)
+#define bfin_write_DMA11_Y_MODIFY(val)       bfin_write16(DMA11_Y_MODIFY,val)
+#define bfin_read_DMA11_CURR_DESC_PTR()      bfin_read32(DMA11_CURR_DESC_PTR)
+#define bfin_write_DMA11_CURR_DESC_PTR(val)  bfin_write32(DMA11_CURR_DESC_PTR,val)
+#define bfin_read_DMA11_CURR_ADDR()          bfin_read32(DMA11_CURR_ADDR)
+#define bfin_write_DMA11_CURR_ADDR(val)      bfin_write32(DMA11_CURR_ADDR,val)
+#define bfin_read_DMA11_CURR_X_COUNT()       bfin_read16(DMA11_CURR_X_COUNT)
+#define bfin_write_DMA11_CURR_X_COUNT(val)   bfin_write16(DMA11_CURR_X_COUNT,val)
+#define bfin_read_DMA11_CURR_Y_COUNT()       bfin_read16(DMA11_CURR_Y_COUNT)
+#define bfin_write_DMA11_CURR_Y_COUNT(val)   bfin_write16(DMA11_CURR_Y_COUNT,val)
+#define bfin_read_DMA11_IRQ_STATUS()         bfin_read16(DMA11_IRQ_STATUS)
+#define bfin_write_DMA11_IRQ_STATUS(val)     bfin_write16(DMA11_IRQ_STATUS,val)
+#define bfin_read_DMA11_PERIPHERAL_MAP()     bfin_read16(DMA11_PERIPHERAL_MAP)
+#define bfin_write_DMA11_PERIPHERAL_MAP(val) bfin_write16(DMA11_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D0_CONFIG()           bfin_read16(MDMA_D0_CONFIG)
+#define bfin_write_MDMA_D0_CONFIG(val)       bfin_write16(MDMA_D0_CONFIG,val)
+#define bfin_read_MDMA_D0_NEXT_DESC_PTR()    bfin_read32(MDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D0_START_ADDR()       bfin_read32(MDMA_D0_START_ADDR)
+#define bfin_write_MDMA_D0_START_ADDR(val)   bfin_write32(MDMA_D0_START_ADDR,val)
+#define bfin_read_MDMA_D0_X_COUNT()          bfin_read16(MDMA_D0_X_COUNT)
+#define bfin_write_MDMA_D0_X_COUNT(val)      bfin_write16(MDMA_D0_X_COUNT,val)
+#define bfin_read_MDMA_D0_Y_COUNT()          bfin_read16(MDMA_D0_Y_COUNT)
+#define bfin_write_MDMA_D0_Y_COUNT(val)      bfin_write16(MDMA_D0_Y_COUNT,val)
+#define bfin_read_MDMA_D0_X_MODIFY()         bfin_read16(MDMA_D0_X_MODIFY)
+#define bfin_write_MDMA_D0_X_MODIFY(val)     bfin_write16(MDMA_D0_X_MODIFY,val)
+#define bfin_read_MDMA_D0_Y_MODIFY()         bfin_read16(MDMA_D0_Y_MODIFY)
+#define bfin_write_MDMA_D0_Y_MODIFY(val)     bfin_write16(MDMA_D0_Y_MODIFY,val)
+#define bfin_read_MDMA_D0_CURR_DESC_PTR()    bfin_read32(MDMA_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D0_CURR_ADDR()        bfin_read32(MDMA_D0_CURR_ADDR)
+#define bfin_write_MDMA_D0_CURR_ADDR(val)    bfin_write32(MDMA_D0_CURR_ADDR,val)
+#define bfin_read_MDMA_D0_CURR_X_COUNT()     bfin_read16(MDMA_D0_CURR_X_COUNT)
+#define bfin_write_MDMA_D0_CURR_X_COUNT(val) bfin_write16(MDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D0_CURR_Y_COUNT()     bfin_read16(MDMA_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA_D0_CURR_Y_COUNT(val) bfin_write16(MDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D0_IRQ_STATUS()       bfin_read16(MDMA_D0_IRQ_STATUS)
+#define bfin_write_MDMA_D0_IRQ_STATUS(val)   bfin_write16(MDMA_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA_D0_PERIPHERAL_MAP()   bfin_read16(MDMA_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA_D0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S0_CONFIG()           bfin_read16(MDMA_S0_CONFIG)
+#define bfin_write_MDMA_S0_CONFIG(val)       bfin_write16(MDMA_S0_CONFIG,val)
+#define bfin_read_MDMA_S0_NEXT_DESC_PTR()    bfin_read32(MDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S0_START_ADDR()       bfin_read32(MDMA_S0_START_ADDR)
+#define bfin_write_MDMA_S0_START_ADDR(val)   bfin_write32(MDMA_S0_START_ADDR,val)
+#define bfin_read_MDMA_S0_X_COUNT()          bfin_read16(MDMA_S0_X_COUNT)
+#define bfin_write_MDMA_S0_X_COUNT(val)      bfin_write16(MDMA_S0_X_COUNT,val)
+#define bfin_read_MDMA_S0_Y_COUNT()          bfin_read16(MDMA_S0_Y_COUNT)
+#define bfin_write_MDMA_S0_Y_COUNT(val)      bfin_write16(MDMA_S0_Y_COUNT,val)
+#define bfin_read_MDMA_S0_X_MODIFY()         bfin_read16(MDMA_S0_X_MODIFY)
+#define bfin_write_MDMA_S0_X_MODIFY(val)     bfin_write16(MDMA_S0_X_MODIFY,val)
+#define bfin_read_MDMA_S0_Y_MODIFY()         bfin_read16(MDMA_S0_Y_MODIFY)
+#define bfin_write_MDMA_S0_Y_MODIFY(val)     bfin_write16(MDMA_S0_Y_MODIFY,val)
+#define bfin_read_MDMA_S0_CURR_DESC_PTR()    bfin_read32(MDMA_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S0_CURR_ADDR()        bfin_read32(MDMA_S0_CURR_ADDR)
+#define bfin_write_MDMA_S0_CURR_ADDR(val)    bfin_write32(MDMA_S0_CURR_ADDR,val)
+#define bfin_read_MDMA_S0_CURR_X_COUNT()     bfin_read16(MDMA_S0_CURR_X_COUNT)
+#define bfin_write_MDMA_S0_CURR_X_COUNT(val) bfin_write16(MDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S0_CURR_Y_COUNT()     bfin_read16(MDMA_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA_S0_CURR_Y_COUNT(val) bfin_write16(MDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S0_IRQ_STATUS()       bfin_read16(MDMA_S0_IRQ_STATUS)
+#define bfin_write_MDMA_S0_IRQ_STATUS(val)   bfin_write16(MDMA_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA_S0_PERIPHERAL_MAP()   bfin_read16(MDMA_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA_S0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D1_CONFIG()           bfin_read16(MDMA_D1_CONFIG)
+#define bfin_write_MDMA_D1_CONFIG(val)       bfin_write16(MDMA_D1_CONFIG,val)
+#define bfin_read_MDMA_D1_NEXT_DESC_PTR()    bfin_read32(MDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D1_START_ADDR()       bfin_read32(MDMA_D1_START_ADDR)
+#define bfin_write_MDMA_D1_START_ADDR(val)   bfin_write32(MDMA_D1_START_ADDR,val)
+#define bfin_read_MDMA_D1_X_COUNT()          bfin_read16(MDMA_D1_X_COUNT)
+#define bfin_write_MDMA_D1_X_COUNT(val)      bfin_write16(MDMA_D1_X_COUNT,val)
+#define bfin_read_MDMA_D1_Y_COUNT()          bfin_read16(MDMA_D1_Y_COUNT)
+#define bfin_write_MDMA_D1_Y_COUNT(val)      bfin_write16(MDMA_D1_Y_COUNT,val)
+#define bfin_read_MDMA_D1_X_MODIFY()         bfin_read16(MDMA_D1_X_MODIFY)
+#define bfin_write_MDMA_D1_X_MODIFY(val)     bfin_write16(MDMA_D1_X_MODIFY,val)
+#define bfin_read_MDMA_D1_Y_MODIFY()         bfin_read16(MDMA_D1_Y_MODIFY)
+#define bfin_write_MDMA_D1_Y_MODIFY(val)     bfin_write16(MDMA_D1_Y_MODIFY,val)
+#define bfin_read_MDMA_D1_CURR_DESC_PTR()    bfin_read32(MDMA_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D1_CURR_ADDR()        bfin_read32(MDMA_D1_CURR_ADDR)
+#define bfin_write_MDMA_D1_CURR_ADDR(val)    bfin_write32(MDMA_D1_CURR_ADDR,val)
+#define bfin_read_MDMA_D1_CURR_X_COUNT()     bfin_read16(MDMA_D1_CURR_X_COUNT)
+#define bfin_write_MDMA_D1_CURR_X_COUNT(val) bfin_write16(MDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D1_CURR_Y_COUNT()     bfin_read16(MDMA_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA_D1_CURR_Y_COUNT(val) bfin_write16(MDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D1_IRQ_STATUS()       bfin_read16(MDMA_D1_IRQ_STATUS)
+#define bfin_write_MDMA_D1_IRQ_STATUS(val)   bfin_write16(MDMA_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA_D1_PERIPHERAL_MAP()   bfin_read16(MDMA_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA_D1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S1_CONFIG()           bfin_read16(MDMA_S1_CONFIG)
+#define bfin_write_MDMA_S1_CONFIG(val)       bfin_write16(MDMA_S1_CONFIG,val)
+#define bfin_read_MDMA_S1_NEXT_DESC_PTR()    bfin_read32(MDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S1_START_ADDR()       bfin_read32(MDMA_S1_START_ADDR)
+#define bfin_write_MDMA_S1_START_ADDR(val)   bfin_write32(MDMA_S1_START_ADDR,val)
+#define bfin_read_MDMA_S1_X_COUNT()          bfin_read16(MDMA_S1_X_COUNT)
+#define bfin_write_MDMA_S1_X_COUNT(val)      bfin_write16(MDMA_S1_X_COUNT,val)
+#define bfin_read_MDMA_S1_Y_COUNT()          bfin_read16(MDMA_S1_Y_COUNT)
+#define bfin_write_MDMA_S1_Y_COUNT(val)      bfin_write16(MDMA_S1_Y_COUNT,val)
+#define bfin_read_MDMA_S1_X_MODIFY()         bfin_read16(MDMA_S1_X_MODIFY)
+#define bfin_write_MDMA_S1_X_MODIFY(val)     bfin_write16(MDMA_S1_X_MODIFY,val)
+#define bfin_read_MDMA_S1_Y_MODIFY()         bfin_read16(MDMA_S1_Y_MODIFY)
+#define bfin_write_MDMA_S1_Y_MODIFY(val)     bfin_write16(MDMA_S1_Y_MODIFY,val)
+#define bfin_read_MDMA_S1_CURR_DESC_PTR()    bfin_read32(MDMA_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S1_CURR_ADDR()        bfin_read32(MDMA_S1_CURR_ADDR)
+#define bfin_write_MDMA_S1_CURR_ADDR(val)    bfin_write32(MDMA_S1_CURR_ADDR,val)
+#define bfin_read_MDMA_S1_CURR_X_COUNT()     bfin_read16(MDMA_S1_CURR_X_COUNT)
+#define bfin_write_MDMA_S1_CURR_X_COUNT(val) bfin_write16(MDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S1_CURR_Y_COUNT()     bfin_read16(MDMA_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA_S1_CURR_Y_COUNT(val) bfin_write16(MDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S1_IRQ_STATUS()       bfin_read16(MDMA_S1_IRQ_STATUS)
+#define bfin_write_MDMA_S1_IRQ_STATUS(val)   bfin_write16(MDMA_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA_S1_PERIPHERAL_MAP()   bfin_read16(MDMA_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA_S1_PERIPHERAL_MAP,val)
+
+/* Parallel Peripheral Interface (0xFFC01000 - 0xFFC010FF)							*/
+#define bfin_read_PPI_CONTROL()              bfin_read16(PPI_CONTROL)
+#define bfin_write_PPI_CONTROL(val)          bfin_write16(PPI_CONTROL,val)
+#define bfin_read_PPI_STATUS()               bfin_read16(PPI_STATUS)
+#define bfin_write_PPI_STATUS(val)           bfin_write16(PPI_STATUS,val)
+#define bfin_clear_PPI_STATUS()              bfin_write_PPI_STATUS(0xFFFF)
+#define bfin_read_PPI_DELAY()                bfin_read16(PPI_DELAY)
+#define bfin_write_PPI_DELAY(val)            bfin_write16(PPI_DELAY,val)
+#define bfin_read_PPI_COUNT()                bfin_read16(PPI_COUNT)
+#define bfin_write_PPI_COUNT(val)            bfin_write16(PPI_COUNT,val)
+#define bfin_read_PPI_FRAME()                bfin_read16(PPI_FRAME)
+#define bfin_write_PPI_FRAME(val)            bfin_write16(PPI_FRAME,val)
+
+/* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF)								*/
+#define bfin_read_TWI_CLKDIV()               bfin_read16(TWI_CLKDIV)
+#define bfin_write_TWI_CLKDIV(val)           bfin_write16(TWI_CLKDIV,val)
+#define bfin_read_TWI_CONTROL()              bfin_read16(TWI_CONTROL)
+#define bfin_write_TWI_CONTROL(val)          bfin_write16(TWI_CONTROL,val)
+#define bfin_read_TWI_SLAVE_CTL()            bfin_read16(TWI_SLAVE_CTL)
+#define bfin_write_TWI_SLAVE_CTL(val)        bfin_write16(TWI_SLAVE_CTL,val)
+#define bfin_read_TWI_SLAVE_STAT()           bfin_read16(TWI_SLAVE_STAT)
+#define bfin_write_TWI_SLAVE_STAT(val)       bfin_write16(TWI_SLAVE_STAT,val)
+#define bfin_read_TWI_SLAVE_ADDR()           bfin_read16(TWI_SLAVE_ADDR)
+#define bfin_write_TWI_SLAVE_ADDR(val)       bfin_write16(TWI_SLAVE_ADDR,val)
+#define bfin_read_TWI_MASTER_CTL()           bfin_read16(TWI_MASTER_CTL)
+#define bfin_write_TWI_MASTER_CTL(val)       bfin_write16(TWI_MASTER_CTL,val)
+#define bfin_read_TWI_MASTER_STAT()          bfin_read16(TWI_MASTER_STAT)
+#define bfin_write_TWI_MASTER_STAT(val)      bfin_write16(TWI_MASTER_STAT,val)
+#define bfin_read_TWI_MASTER_ADDR()          bfin_read16(TWI_MASTER_ADDR)
+#define bfin_write_TWI_MASTER_ADDR(val)      bfin_write16(TWI_MASTER_ADDR,val)
+#define bfin_read_TWI_INT_STAT()             bfin_read16(TWI_INT_STAT)
+#define bfin_write_TWI_INT_STAT(val)         bfin_write16(TWI_INT_STAT,val)
+#define bfin_read_TWI_INT_MASK()             bfin_read16(TWI_INT_MASK)
+#define bfin_write_TWI_INT_MASK(val)         bfin_write16(TWI_INT_MASK,val)
+#define bfin_read_TWI_FIFO_CTL()             bfin_read16(TWI_FIFO_CTL)
+#define bfin_write_TWI_FIFO_CTL(val)         bfin_write16(TWI_FIFO_CTL,val)
+#define bfin_read_TWI_FIFO_STAT()            bfin_read16(TWI_FIFO_STAT)
+#define bfin_write_TWI_FIFO_STAT(val)        bfin_write16(TWI_FIFO_STAT,val)
+#define bfin_read_TWI_XMT_DATA8()            bfin_read16(TWI_XMT_DATA8)
+#define bfin_write_TWI_XMT_DATA8(val)        bfin_write16(TWI_XMT_DATA8,val)
+#define bfin_read_TWI_XMT_DATA16()           bfin_read16(TWI_XMT_DATA16)
+#define bfin_write_TWI_XMT_DATA16(val)       bfin_write16(TWI_XMT_DATA16,val)
+#define bfin_read_TWI_RCV_DATA8()            bfin_read16(TWI_RCV_DATA8)
+#define bfin_write_TWI_RCV_DATA8(val)        bfin_write16(TWI_RCV_DATA8,val)
+#define bfin_read_TWI_RCV_DATA16()           bfin_read16(TWI_RCV_DATA16)
+#define bfin_write_TWI_RCV_DATA16(val)       bfin_write16(TWI_RCV_DATA16,val)
+
+/* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF)								*/
+#define bfin_read_PORTGIO()                  bfin_read16(PORTGIO)
+#define bfin_write_PORTGIO(val)              bfin_write16(PORTGIO,val)
+#define bfin_read_PORTGIO_CLEAR()            bfin_read16(PORTGIO_CLEAR)
+#define bfin_write_PORTGIO_CLEAR(val)        bfin_write16(PORTGIO_CLEAR,val)
+#define bfin_read_PORTGIO_SET()              bfin_read16(PORTGIO_SET)
+#define bfin_write_PORTGIO_SET(val)          bfin_write16(PORTGIO_SET,val)
+#define bfin_read_PORTGIO_TOGGLE()           bfin_read16(PORTGIO_TOGGLE)
+#define bfin_write_PORTGIO_TOGGLE(val)       bfin_write16(PORTGIO_TOGGLE,val)
+#define bfin_read_PORTGIO_MASKA()            bfin_read16(PORTGIO_MASKA)
+#define bfin_write_PORTGIO_MASKA(val)        bfin_write16(PORTGIO_MASKA,val)
+#define bfin_read_PORTGIO_MASKA_CLEAR()      bfin_read16(PORTGIO_MASKA_CLEAR)
+#define bfin_write_PORTGIO_MASKA_CLEAR(val)  bfin_write16(PORTGIO_MASKA_CLEAR,val)
+#define bfin_read_PORTGIO_MASKA_SET()        bfin_read16(PORTGIO_MASKA_SET)
+#define bfin_write_PORTGIO_MASKA_SET(val)    bfin_write16(PORTGIO_MASKA_SET,val)
+#define bfin_read_PORTGIO_MASKA_TOGGLE()     bfin_read16(PORTGIO_MASKA_TOGGLE)
+#define bfin_write_PORTGIO_MASKA_TOGGLE(val) bfin_write16(PORTGIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTGIO_MASKB()            bfin_read16(PORTGIO_MASKB)
+#define bfin_write_PORTGIO_MASKB(val)        bfin_write16(PORTGIO_MASKB,val)
+#define bfin_read_PORTGIO_MASKB_CLEAR()      bfin_read16(PORTGIO_MASKB_CLEAR)
+#define bfin_write_PORTGIO_MASKB_CLEAR(val)  bfin_write16(PORTGIO_MASKB_CLEAR,val)
+#define bfin_read_PORTGIO_MASKB_SET()        bfin_read16(PORTGIO_MASKB_SET)
+#define bfin_write_PORTGIO_MASKB_SET(val)    bfin_write16(PORTGIO_MASKB_SET,val)
+#define bfin_read_PORTGIO_MASKB_TOGGLE()     bfin_read16(PORTGIO_MASKB_TOGGLE)
+#define bfin_write_PORTGIO_MASKB_TOGGLE(val) bfin_write16(PORTGIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTGIO_DIR()              bfin_read16(PORTGIO_DIR)
+#define bfin_write_PORTGIO_DIR(val)          bfin_write16(PORTGIO_DIR,val)
+#define bfin_read_PORTGIO_POLAR()            bfin_read16(PORTGIO_POLAR)
+#define bfin_write_PORTGIO_POLAR(val)        bfin_write16(PORTGIO_POLAR,val)
+#define bfin_read_PORTGIO_EDGE()             bfin_read16(PORTGIO_EDGE)
+#define bfin_write_PORTGIO_EDGE(val)         bfin_write16(PORTGIO_EDGE,val)
+#define bfin_read_PORTGIO_BOTH()             bfin_read16(PORTGIO_BOTH)
+#define bfin_write_PORTGIO_BOTH(val)         bfin_write16(PORTGIO_BOTH,val)
+#define bfin_read_PORTGIO_INEN()             bfin_read16(PORTGIO_INEN)
+#define bfin_write_PORTGIO_INEN(val)         bfin_write16(PORTGIO_INEN,val)
+
+/* General Purpose I/O Port H (0xFFC01700 - 0xFFC017FF)								*/
+#define bfin_read_PORTHIO()                  bfin_read16(PORTHIO)
+#define bfin_write_PORTHIO(val)              bfin_write16(PORTHIO,val)
+#define bfin_read_PORTHIO_CLEAR()            bfin_read16(PORTHIO_CLEAR)
+#define bfin_write_PORTHIO_CLEAR(val)        bfin_write16(PORTHIO_CLEAR,val)
+#define bfin_read_PORTHIO_SET()              bfin_read16(PORTHIO_SET)
+#define bfin_write_PORTHIO_SET(val)          bfin_write16(PORTHIO_SET,val)
+#define bfin_read_PORTHIO_TOGGLE()           bfin_read16(PORTHIO_TOGGLE)
+#define bfin_write_PORTHIO_TOGGLE(val)       bfin_write16(PORTHIO_TOGGLE,val)
+#define bfin_read_PORTHIO_MASKA()            bfin_read16(PORTHIO_MASKA)
+#define bfin_write_PORTHIO_MASKA(val)        bfin_write16(PORTHIO_MASKA,val)
+#define bfin_read_PORTHIO_MASKA_CLEAR()      bfin_read16(PORTHIO_MASKA_CLEAR)
+#define bfin_write_PORTHIO_MASKA_CLEAR(val)  bfin_write16(PORTHIO_MASKA_CLEAR,val)
+#define bfin_read_PORTHIO_MASKA_SET()        bfin_read16(PORTHIO_MASKA_SET)
+#define bfin_write_PORTHIO_MASKA_SET(val)    bfin_write16(PORTHIO_MASKA_SET,val)
+#define bfin_read_PORTHIO_MASKA_TOGGLE()     bfin_read16(PORTHIO_MASKA_TOGGLE)
+#define bfin_write_PORTHIO_MASKA_TOGGLE(val) bfin_write16(PORTHIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTHIO_MASKB()            bfin_read16(PORTHIO_MASKB)
+#define bfin_write_PORTHIO_MASKB(val)        bfin_write16(PORTHIO_MASKB,val)
+#define bfin_read_PORTHIO_MASKB_CLEAR()      bfin_read16(PORTHIO_MASKB_CLEAR)
+#define bfin_write_PORTHIO_MASKB_CLEAR(val)  bfin_write16(PORTHIO_MASKB_CLEAR,val)
+#define bfin_read_PORTHIO_MASKB_SET()        bfin_read16(PORTHIO_MASKB_SET)
+#define bfin_write_PORTHIO_MASKB_SET(val)    bfin_write16(PORTHIO_MASKB_SET,val)
+#define bfin_read_PORTHIO_MASKB_TOGGLE()     bfin_read16(PORTHIO_MASKB_TOGGLE)
+#define bfin_write_PORTHIO_MASKB_TOGGLE(val) bfin_write16(PORTHIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTHIO_DIR()              bfin_read16(PORTHIO_DIR)
+#define bfin_write_PORTHIO_DIR(val)          bfin_write16(PORTHIO_DIR,val)
+#define bfin_read_PORTHIO_POLAR()            bfin_read16(PORTHIO_POLAR)
+#define bfin_write_PORTHIO_POLAR(val)        bfin_write16(PORTHIO_POLAR,val)
+#define bfin_read_PORTHIO_EDGE()             bfin_read16(PORTHIO_EDGE)
+#define bfin_write_PORTHIO_EDGE(val)         bfin_write16(PORTHIO_EDGE,val)
+#define bfin_read_PORTHIO_BOTH()             bfin_read16(PORTHIO_BOTH)
+#define bfin_write_PORTHIO_BOTH(val)         bfin_write16(PORTHIO_BOTH,val)
+#define bfin_read_PORTHIO_INEN()             bfin_read16(PORTHIO_INEN)
+#define bfin_write_PORTHIO_INEN(val)         bfin_write16(PORTHIO_INEN,val)
+
+/* UART1 Controller		(0xFFC02000 - 0xFFC020FF)								*/
+#define bfin_read_UART1_THR()                bfin_read16(UART1_THR)
+#define bfin_write_UART1_THR(val)            bfin_write16(UART1_THR,val)
+#define bfin_read_UART1_RBR()                bfin_read16(UART1_RBR)
+#define bfin_write_UART1_RBR(val)            bfin_write16(UART1_RBR,val)
+#define bfin_read_UART1_DLL()                bfin_read16(UART1_DLL)
+#define bfin_write_UART1_DLL(val)            bfin_write16(UART1_DLL,val)
+#define bfin_read_UART1_IER()                bfin_read16(UART1_IER)
+#define bfin_write_UART1_IER(val)            bfin_write16(UART1_IER,val)
+#define bfin_read_UART1_DLH()                bfin_read16(UART1_DLH)
+#define bfin_write_UART1_DLH(val)            bfin_write16(UART1_DLH,val)
+#define bfin_read_UART1_IIR()                bfin_read16(UART1_IIR)
+#define bfin_write_UART1_IIR(val)            bfin_write16(UART1_IIR,val)
+#define bfin_read_UART1_LCR()                bfin_read16(UART1_LCR)
+#define bfin_write_UART1_LCR(val)            bfin_write16(UART1_LCR,val)
+#define bfin_read_UART1_MCR()                bfin_read16(UART1_MCR)
+#define bfin_write_UART1_MCR(val)            bfin_write16(UART1_MCR,val)
+#define bfin_read_UART1_LSR()                bfin_read16(UART1_LSR)
+#define bfin_write_UART1_LSR(val)            bfin_write16(UART1_LSR,val)
+#define bfin_read_UART1_MSR()                bfin_read16(UART1_MSR)
+#define bfin_write_UART1_MSR(val)            bfin_write16(UART1_MSR,val)
+#define bfin_read_UART1_SCR()                bfin_read16(UART1_SCR)
+#define bfin_write_UART1_SCR(val)            bfin_write16(UART1_SCR,val)
+#define bfin_read_UART1_GCTL()               bfin_read16(UART1_GCTL)
+#define bfin_write_UART1_GCTL(val)           bfin_write16(UART1_GCTL,val)
+
+/* CAN Controller		(0xFFC02A00 - 0xFFC02FFF)								*/
+/* For Mailboxes 0-15 */
+#define bfin_read_CAN_MC1()                  bfin_read16(CAN_MC1)
+#define bfin_write_CAN_MC1(val)              bfin_write16(CAN_MC1,val)
+#define bfin_read_CAN_MD1()                  bfin_read16(CAN_MD1)
+#define bfin_write_CAN_MD1(val)              bfin_write16(CAN_MD1,val)
+#define bfin_read_CAN_TRS1()                 bfin_read16(CAN_TRS1)
+#define bfin_write_CAN_TRS1(val)             bfin_write16(CAN_TRS1,val)
+#define bfin_read_CAN_TRR1()                 bfin_read16(CAN_TRR1)
+#define bfin_write_CAN_TRR1(val)             bfin_write16(CAN_TRR1,val)
+#define bfin_read_CAN_TA1()                  bfin_read16(CAN_TA1)
+#define bfin_write_CAN_TA1(val)              bfin_write16(CAN_TA1,val)
+#define bfin_read_CAN_AA1()                  bfin_read16(CAN_AA1)
+#define bfin_write_CAN_AA1(val)              bfin_write16(CAN_AA1,val)
+#define bfin_read_CAN_RMP1()                 bfin_read16(CAN_RMP1)
+#define bfin_write_CAN_RMP1(val)             bfin_write16(CAN_RMP1,val)
+#define bfin_read_CAN_RML1()                 bfin_read16(CAN_RML1)
+#define bfin_write_CAN_RML1(val)             bfin_write16(CAN_RML1,val)
+#define bfin_read_CAN_MBTIF1()               bfin_read16(CAN_MBTIF1)
+#define bfin_write_CAN_MBTIF1(val)           bfin_write16(CAN_MBTIF1,val)
+#define bfin_read_CAN_MBRIF1()               bfin_read16(CAN_MBRIF1)
+#define bfin_write_CAN_MBRIF1(val)           bfin_write16(CAN_MBRIF1,val)
+#define bfin_read_CAN_MBIM1()                bfin_read16(CAN_MBIM1)
+#define bfin_write_CAN_MBIM1(val)            bfin_write16(CAN_MBIM1,val)
+#define bfin_read_CAN_RFH1()                 bfin_read16(CAN_RFH1)
+#define bfin_write_CAN_RFH1(val)             bfin_write16(CAN_RFH1,val)
+#define bfin_read_CAN_OPSS1()                bfin_read16(CAN_OPSS1)
+#define bfin_write_CAN_OPSS1(val)            bfin_write16(CAN_OPSS1,val)
+
+/* For Mailboxes 16-31 */
+#define bfin_read_CAN_MC2()                  bfin_read16(CAN_MC2)
+#define bfin_write_CAN_MC2(val)              bfin_write16(CAN_MC2,val)
+#define bfin_read_CAN_MD2()                  bfin_read16(CAN_MD2)
+#define bfin_write_CAN_MD2(val)              bfin_write16(CAN_MD2,val)
+#define bfin_read_CAN_TRS2()                 bfin_read16(CAN_TRS2)
+#define bfin_write_CAN_TRS2(val)             bfin_write16(CAN_TRS2,val)
+#define bfin_read_CAN_TRR2()                 bfin_read16(CAN_TRR2)
+#define bfin_write_CAN_TRR2(val)             bfin_write16(CAN_TRR2,val)
+#define bfin_read_CAN_TA2()                  bfin_read16(CAN_TA2)
+#define bfin_write_CAN_TA2(val)              bfin_write16(CAN_TA2,val)
+#define bfin_read_CAN_AA2()                  bfin_read16(CAN_AA2)
+#define bfin_write_CAN_AA2(val)              bfin_write16(CAN_AA2,val)
+#define bfin_read_CAN_RMP2()                 bfin_read16(CAN_RMP2)
+#define bfin_write_CAN_RMP2(val)             bfin_write16(CAN_RMP2,val)
+#define bfin_read_CAN_RML2()                 bfin_read16(CAN_RML2)
+#define bfin_write_CAN_RML2(val)             bfin_write16(CAN_RML2,val)
+#define bfin_read_CAN_MBTIF2()               bfin_read16(CAN_MBTIF2)
+#define bfin_write_CAN_MBTIF2(val)           bfin_write16(CAN_MBTIF2,val)
+#define bfin_read_CAN_MBRIF2()               bfin_read16(CAN_MBRIF2)
+#define bfin_write_CAN_MBRIF2(val)           bfin_write16(CAN_MBRIF2,val)
+#define bfin_read_CAN_MBIM2()                bfin_read16(CAN_MBIM2)
+#define bfin_write_CAN_MBIM2(val)            bfin_write16(CAN_MBIM2,val)
+#define bfin_read_CAN_RFH2()                 bfin_read16(CAN_RFH2)
+#define bfin_write_CAN_RFH2(val)             bfin_write16(CAN_RFH2,val)
+#define bfin_read_CAN_OPSS2()                bfin_read16(CAN_OPSS2)
+#define bfin_write_CAN_OPSS2(val)            bfin_write16(CAN_OPSS2,val)
+
+#define bfin_read_CAN_CLOCK()                bfin_read16(CAN_CLOCK)
+#define bfin_write_CAN_CLOCK(val)            bfin_write16(CAN_CLOCK,val)
+#define bfin_read_CAN_TIMING()               bfin_read16(CAN_TIMING)
+#define bfin_write_CAN_TIMING(val)           bfin_write16(CAN_TIMING,val)
+#define bfin_read_CAN_DEBUG()                bfin_read16(CAN_DEBUG)
+#define bfin_write_CAN_DEBUG(val)            bfin_write16(CAN_DEBUG,val)
+#define bfin_read_CAN_STATUS()               bfin_read16(CAN_STATUS)
+#define bfin_write_CAN_STATUS(val)           bfin_write16(CAN_STATUS,val)
+#define bfin_read_CAN_CEC()                  bfin_read16(CAN_CEC)
+#define bfin_write_CAN_CEC(val)              bfin_write16(CAN_CEC,val)
+#define bfin_read_CAN_GIS()                  bfin_read16(CAN_GIS)
+#define bfin_write_CAN_GIS(val)              bfin_write16(CAN_GIS,val)
+#define bfin_read_CAN_GIM()                  bfin_read16(CAN_GIM)
+#define bfin_write_CAN_GIM(val)              bfin_write16(CAN_GIM,val)
+#define bfin_read_CAN_GIF()                  bfin_read16(CAN_GIF)
+#define bfin_write_CAN_GIF(val)              bfin_write16(CAN_GIF,val)
+#define bfin_read_CAN_CONTROL()              bfin_read16(CAN_CONTROL)
+#define bfin_write_CAN_CONTROL(val)          bfin_write16(CAN_CONTROL,val)
+#define bfin_read_CAN_INTR()                 bfin_read16(CAN_INTR)
+#define bfin_write_CAN_INTR(val)             bfin_write16(CAN_INTR,val)
+#define bfin_read_CAN_SFCMVER()              bfin_read16(CAN_SFCMVER)
+#define bfin_write_CAN_SFCMVER(val)          bfin_write16(CAN_SFCMVER,val)
+#define bfin_read_CAN_MBTD()                 bfin_read16(CAN_MBTD)
+#define bfin_write_CAN_MBTD(val)             bfin_write16(CAN_MBTD,val)
+#define bfin_read_CAN_EWR()                  bfin_read16(CAN_EWR)
+#define bfin_write_CAN_EWR(val)              bfin_write16(CAN_EWR,val)
+#define bfin_read_CAN_ESR()                  bfin_read16(CAN_ESR)
+#define bfin_write_CAN_ESR(val)              bfin_write16(CAN_ESR,val)
+#define bfin_read_CAN_UCREG()                bfin_read16(CAN_UCREG)
+#define bfin_write_CAN_UCREG(val)            bfin_write16(CAN_UCREG,val)
+#define bfin_read_CAN_UCCNT()                bfin_read16(CAN_UCCNT)
+#define bfin_write_CAN_UCCNT(val)            bfin_write16(CAN_UCCNT,val)
+#define bfin_read_CAN_UCRC()                 bfin_read16(CAN_UCRC)
+#define bfin_write_CAN_UCRC(val)             bfin_write16(CAN_UCRC,val)
+#define bfin_read_CAN_UCCNF()                bfin_read16(CAN_UCCNF)
+#define bfin_write_CAN_UCCNF(val)            bfin_write16(CAN_UCCNF,val)
+#define bfin_read_CAN_SFCMVER2()             bfin_read16(CAN_SFCMVER2)
+#define bfin_write_CAN_SFCMVER2(val)         bfin_write16(CAN_SFCMVER2,val)
+
+/* Mailbox Acceptance Masks */
+#define bfin_read_CAN_AM00L()                bfin_read16(CAN_AM00L)
+#define bfin_write_CAN_AM00L(val)            bfin_write16(CAN_AM00L,val)
+#define bfin_read_CAN_AM00H()                bfin_read16(CAN_AM00H)
+#define bfin_write_CAN_AM00H(val)            bfin_write16(CAN_AM00H,val)
+#define bfin_read_CAN_AM01L()                bfin_read16(CAN_AM01L)
+#define bfin_write_CAN_AM01L(val)            bfin_write16(CAN_AM01L,val)
+#define bfin_read_CAN_AM01H()                bfin_read16(CAN_AM01H)
+#define bfin_write_CAN_AM01H(val)            bfin_write16(CAN_AM01H,val)
+#define bfin_read_CAN_AM02L()                bfin_read16(CAN_AM02L)
+#define bfin_write_CAN_AM02L(val)            bfin_write16(CAN_AM02L,val)
+#define bfin_read_CAN_AM02H()                bfin_read16(CAN_AM02H)
+#define bfin_write_CAN_AM02H(val)            bfin_write16(CAN_AM02H,val)
+#define bfin_read_CAN_AM03L()                bfin_read16(CAN_AM03L)
+#define bfin_write_CAN_AM03L(val)            bfin_write16(CAN_AM03L,val)
+#define bfin_read_CAN_AM03H()                bfin_read16(CAN_AM03H)
+#define bfin_write_CAN_AM03H(val)            bfin_write16(CAN_AM03H,val)
+#define bfin_read_CAN_AM04L()                bfin_read16(CAN_AM04L)
+#define bfin_write_CAN_AM04L(val)            bfin_write16(CAN_AM04L,val)
+#define bfin_read_CAN_AM04H()                bfin_read16(CAN_AM04H)
+#define bfin_write_CAN_AM04H(val)            bfin_write16(CAN_AM04H,val)
+#define bfin_read_CAN_AM05L()                bfin_read16(CAN_AM05L)
+#define bfin_write_CAN_AM05L(val)            bfin_write16(CAN_AM05L,val)
+#define bfin_read_CAN_AM05H()                bfin_read16(CAN_AM05H)
+#define bfin_write_CAN_AM05H(val)            bfin_write16(CAN_AM05H,val)
+#define bfin_read_CAN_AM06L()                bfin_read16(CAN_AM06L)
+#define bfin_write_CAN_AM06L(val)            bfin_write16(CAN_AM06L,val)
+#define bfin_read_CAN_AM06H()                bfin_read16(CAN_AM06H)
+#define bfin_write_CAN_AM06H(val)            bfin_write16(CAN_AM06H,val)
+#define bfin_read_CAN_AM07L()                bfin_read16(CAN_AM07L)
+#define bfin_write_CAN_AM07L(val)            bfin_write16(CAN_AM07L,val)
+#define bfin_read_CAN_AM07H()                bfin_read16(CAN_AM07H)
+#define bfin_write_CAN_AM07H(val)            bfin_write16(CAN_AM07H,val)
+#define bfin_read_CAN_AM08L()                bfin_read16(CAN_AM08L)
+#define bfin_write_CAN_AM08L(val)            bfin_write16(CAN_AM08L,val)
+#define bfin_read_CAN_AM08H()                bfin_read16(CAN_AM08H)
+#define bfin_write_CAN_AM08H(val)            bfin_write16(CAN_AM08H,val)
+#define bfin_read_CAN_AM09L()                bfin_read16(CAN_AM09L)
+#define bfin_write_CAN_AM09L(val)            bfin_write16(CAN_AM09L,val)
+#define bfin_read_CAN_AM09H()                bfin_read16(CAN_AM09H)
+#define bfin_write_CAN_AM09H(val)            bfin_write16(CAN_AM09H,val)
+#define bfin_read_CAN_AM10L()                bfin_read16(CAN_AM10L)
+#define bfin_write_CAN_AM10L(val)            bfin_write16(CAN_AM10L,val)
+#define bfin_read_CAN_AM10H()                bfin_read16(CAN_AM10H)
+#define bfin_write_CAN_AM10H(val)            bfin_write16(CAN_AM10H,val)
+#define bfin_read_CAN_AM11L()                bfin_read16(CAN_AM11L)
+#define bfin_write_CAN_AM11L(val)            bfin_write16(CAN_AM11L,val)
+#define bfin_read_CAN_AM11H()                bfin_read16(CAN_AM11H)
+#define bfin_write_CAN_AM11H(val)            bfin_write16(CAN_AM11H,val)
+#define bfin_read_CAN_AM12L()                bfin_read16(CAN_AM12L)
+#define bfin_write_CAN_AM12L(val)            bfin_write16(CAN_AM12L,val)
+#define bfin_read_CAN_AM12H()                bfin_read16(CAN_AM12H)
+#define bfin_write_CAN_AM12H(val)            bfin_write16(CAN_AM12H,val)
+#define bfin_read_CAN_AM13L()                bfin_read16(CAN_AM13L)
+#define bfin_write_CAN_AM13L(val)            bfin_write16(CAN_AM13L,val)
+#define bfin_read_CAN_AM13H()                bfin_read16(CAN_AM13H)
+#define bfin_write_CAN_AM13H(val)            bfin_write16(CAN_AM13H,val)
+#define bfin_read_CAN_AM14L()                bfin_read16(CAN_AM14L)
+#define bfin_write_CAN_AM14L(val)            bfin_write16(CAN_AM14L,val)
+#define bfin_read_CAN_AM14H()                bfin_read16(CAN_AM14H)
+#define bfin_write_CAN_AM14H(val)            bfin_write16(CAN_AM14H,val)
+#define bfin_read_CAN_AM15L()                bfin_read16(CAN_AM15L)
+#define bfin_write_CAN_AM15L(val)            bfin_write16(CAN_AM15L,val)
+#define bfin_read_CAN_AM15H()                bfin_read16(CAN_AM15H)
+#define bfin_write_CAN_AM15H(val)            bfin_write16(CAN_AM15H,val)
+
+#define bfin_read_CAN_AM16L()                bfin_read16(CAN_AM16L)
+#define bfin_write_CAN_AM16L(val)            bfin_write16(CAN_AM16L,val)
+#define bfin_read_CAN_AM16H()                bfin_read16(CAN_AM16H)
+#define bfin_write_CAN_AM16H(val)            bfin_write16(CAN_AM16H,val)
+#define bfin_read_CAN_AM17L()                bfin_read16(CAN_AM17L)
+#define bfin_write_CAN_AM17L(val)            bfin_write16(CAN_AM17L,val)
+#define bfin_read_CAN_AM17H()                bfin_read16(CAN_AM17H)
+#define bfin_write_CAN_AM17H(val)            bfin_write16(CAN_AM17H,val)
+#define bfin_read_CAN_AM18L()                bfin_read16(CAN_AM18L)
+#define bfin_write_CAN_AM18L(val)            bfin_write16(CAN_AM18L,val)
+#define bfin_read_CAN_AM18H()                bfin_read16(CAN_AM18H)
+#define bfin_write_CAN_AM18H(val)            bfin_write16(CAN_AM18H,val)
+#define bfin_read_CAN_AM19L()                bfin_read16(CAN_AM19L)
+#define bfin_write_CAN_AM19L(val)            bfin_write16(CAN_AM19L,val)
+#define bfin_read_CAN_AM19H()                bfin_read16(CAN_AM19H)
+#define bfin_write_CAN_AM19H(val)            bfin_write16(CAN_AM19H,val)
+#define bfin_read_CAN_AM20L()                bfin_read16(CAN_AM20L)
+#define bfin_write_CAN_AM20L(val)            bfin_write16(CAN_AM20L,val)
+#define bfin_read_CAN_AM20H()                bfin_read16(CAN_AM20H)
+#define bfin_write_CAN_AM20H(val)            bfin_write16(CAN_AM20H,val)
+#define bfin_read_CAN_AM21L()                bfin_read16(CAN_AM21L)
+#define bfin_write_CAN_AM21L(val)            bfin_write16(CAN_AM21L,val)
+#define bfin_read_CAN_AM21H()                bfin_read16(CAN_AM21H)
+#define bfin_write_CAN_AM21H(val)            bfin_write16(CAN_AM21H,val)
+#define bfin_read_CAN_AM22L()                bfin_read16(CAN_AM22L)
+#define bfin_write_CAN_AM22L(val)            bfin_write16(CAN_AM22L,val)
+#define bfin_read_CAN_AM22H()                bfin_read16(CAN_AM22H)
+#define bfin_write_CAN_AM22H(val)            bfin_write16(CAN_AM22H,val)
+#define bfin_read_CAN_AM23L()                bfin_read16(CAN_AM23L)
+#define bfin_write_CAN_AM23L(val)            bfin_write16(CAN_AM23L,val)
+#define bfin_read_CAN_AM23H()                bfin_read16(CAN_AM23H)
+#define bfin_write_CAN_AM23H(val)            bfin_write16(CAN_AM23H,val)
+#define bfin_read_CAN_AM24L()                bfin_read16(CAN_AM24L)
+#define bfin_write_CAN_AM24L(val)            bfin_write16(CAN_AM24L,val)
+#define bfin_read_CAN_AM24H()                bfin_read16(CAN_AM24H)
+#define bfin_write_CAN_AM24H(val)            bfin_write16(CAN_AM24H,val)
+#define bfin_read_CAN_AM25L()                bfin_read16(CAN_AM25L)
+#define bfin_write_CAN_AM25L(val)            bfin_write16(CAN_AM25L,val)
+#define bfin_read_CAN_AM25H()                bfin_read16(CAN_AM25H)
+#define bfin_write_CAN_AM25H(val)            bfin_write16(CAN_AM25H,val)
+#define bfin_read_CAN_AM26L()                bfin_read16(CAN_AM26L)
+#define bfin_write_CAN_AM26L(val)            bfin_write16(CAN_AM26L,val)
+#define bfin_read_CAN_AM26H()                bfin_read16(CAN_AM26H)
+#define bfin_write_CAN_AM26H(val)            bfin_write16(CAN_AM26H,val)
+#define bfin_read_CAN_AM27L()                bfin_read16(CAN_AM27L)
+#define bfin_write_CAN_AM27L(val)            bfin_write16(CAN_AM27L,val)
+#define bfin_read_CAN_AM27H()                bfin_read16(CAN_AM27H)
+#define bfin_write_CAN_AM27H(val)            bfin_write16(CAN_AM27H,val)
+#define bfin_read_CAN_AM28L()                bfin_read16(CAN_AM28L)
+#define bfin_write_CAN_AM28L(val)            bfin_write16(CAN_AM28L,val)
+#define bfin_read_CAN_AM28H()                bfin_read16(CAN_AM28H)
+#define bfin_write_CAN_AM28H(val)            bfin_write16(CAN_AM28H,val)
+#define bfin_read_CAN_AM29L()                bfin_read16(CAN_AM29L)
+#define bfin_write_CAN_AM29L(val)            bfin_write16(CAN_AM29L,val)
+#define bfin_read_CAN_AM29H()                bfin_read16(CAN_AM29H)
+#define bfin_write_CAN_AM29H(val)            bfin_write16(CAN_AM29H,val)
+#define bfin_read_CAN_AM30L()                bfin_read16(CAN_AM30L)
+#define bfin_write_CAN_AM30L(val)            bfin_write16(CAN_AM30L,val)
+#define bfin_read_CAN_AM30H()                bfin_read16(CAN_AM30H)
+#define bfin_write_CAN_AM30H(val)            bfin_write16(CAN_AM30H,val)
+#define bfin_read_CAN_AM31L()                bfin_read16(CAN_AM31L)
+#define bfin_write_CAN_AM31L(val)            bfin_write16(CAN_AM31L,val)
+#define bfin_read_CAN_AM31H()                bfin_read16(CAN_AM31H)
+#define bfin_write_CAN_AM31H(val)            bfin_write16(CAN_AM31H,val)
+
+/* CAN Acceptance Mask Area Macros	*/
+#define bfin_read_CAN_AM_L(x)()              bfin_read16(CAN_AM_L(x))
+#define bfin_write_CAN_AM_L(x)(val)          bfin_write16(CAN_AM_L(x),val)
+#define bfin_read_CAN_AM_H(x)()              bfin_read16(CAN_AM_H(x))
+#define bfin_write_CAN_AM_H(x)(val)          bfin_write16(CAN_AM_H(x),val)
+
+/* Mailbox Registers */
+#define bfin_read_CAN_MB00_ID1()             bfin_read16(CAN_MB00_ID1)
+#define bfin_write_CAN_MB00_ID1(val)         bfin_write16(CAN_MB00_ID1,val)
+#define bfin_read_CAN_MB00_ID0()             bfin_read16(CAN_MB00_ID0)
+#define bfin_write_CAN_MB00_ID0(val)         bfin_write16(CAN_MB00_ID0,val)
+#define bfin_read_CAN_MB00_TIMESTAMP()       bfin_read16(CAN_MB00_TIMESTAMP)
+#define bfin_write_CAN_MB00_TIMESTAMP(val)   bfin_write16(CAN_MB00_TIMESTAMP,val)
+#define bfin_read_CAN_MB00_LENGTH()          bfin_read16(CAN_MB00_LENGTH)
+#define bfin_write_CAN_MB00_LENGTH(val)      bfin_write16(CAN_MB00_LENGTH,val)
+#define bfin_read_CAN_MB00_DATA3()           bfin_read16(CAN_MB00_DATA3)
+#define bfin_write_CAN_MB00_DATA3(val)       bfin_write16(CAN_MB00_DATA3,val)
+#define bfin_read_CAN_MB00_DATA2()           bfin_read16(CAN_MB00_DATA2)
+#define bfin_write_CAN_MB00_DATA2(val)       bfin_write16(CAN_MB00_DATA2,val)
+#define bfin_read_CAN_MB00_DATA1()           bfin_read16(CAN_MB00_DATA1)
+#define bfin_write_CAN_MB00_DATA1(val)       bfin_write16(CAN_MB00_DATA1,val)
+#define bfin_read_CAN_MB00_DATA0()           bfin_read16(CAN_MB00_DATA0)
+#define bfin_write_CAN_MB00_DATA0(val)       bfin_write16(CAN_MB00_DATA0,val)
+
+#define bfin_read_CAN_MB01_ID1()             bfin_read16(CAN_MB01_ID1)
+#define bfin_write_CAN_MB01_ID1(val)         bfin_write16(CAN_MB01_ID1,val)
+#define bfin_read_CAN_MB01_ID0()             bfin_read16(CAN_MB01_ID0)
+#define bfin_write_CAN_MB01_ID0(val)         bfin_write16(CAN_MB01_ID0,val)
+#define bfin_read_CAN_MB01_TIMESTAMP()       bfin_read16(CAN_MB01_TIMESTAMP)
+#define bfin_write_CAN_MB01_TIMESTAMP(val)   bfin_write16(CAN_MB01_TIMESTAMP,val)
+#define bfin_read_CAN_MB01_LENGTH()          bfin_read16(CAN_MB01_LENGTH)
+#define bfin_write_CAN_MB01_LENGTH(val)      bfin_write16(CAN_MB01_LENGTH,val)
+#define bfin_read_CAN_MB01_DATA3()           bfin_read16(CAN_MB01_DATA3)
+#define bfin_write_CAN_MB01_DATA3(val)       bfin_write16(CAN_MB01_DATA3,val)
+#define bfin_read_CAN_MB01_DATA2()           bfin_read16(CAN_MB01_DATA2)
+#define bfin_write_CAN_MB01_DATA2(val)       bfin_write16(CAN_MB01_DATA2,val)
+#define bfin_read_CAN_MB01_DATA1()           bfin_read16(CAN_MB01_DATA1)
+#define bfin_write_CAN_MB01_DATA1(val)       bfin_write16(CAN_MB01_DATA1,val)
+#define bfin_read_CAN_MB01_DATA0()           bfin_read16(CAN_MB01_DATA0)
+#define bfin_write_CAN_MB01_DATA0(val)       bfin_write16(CAN_MB01_DATA0,val)
+
+#define bfin_read_CAN_MB02_ID1()             bfin_read16(CAN_MB02_ID1)
+#define bfin_write_CAN_MB02_ID1(val)         bfin_write16(CAN_MB02_ID1,val)
+#define bfin_read_CAN_MB02_ID0()             bfin_read16(CAN_MB02_ID0)
+#define bfin_write_CAN_MB02_ID0(val)         bfin_write16(CAN_MB02_ID0,val)
+#define bfin_read_CAN_MB02_TIMESTAMP()       bfin_read16(CAN_MB02_TIMESTAMP)
+#define bfin_write_CAN_MB02_TIMESTAMP(val)   bfin_write16(CAN_MB02_TIMESTAMP,val)
+#define bfin_read_CAN_MB02_LENGTH()          bfin_read16(CAN_MB02_LENGTH)
+#define bfin_write_CAN_MB02_LENGTH(val)      bfin_write16(CAN_MB02_LENGTH,val)
+#define bfin_read_CAN_MB02_DATA3()           bfin_read16(CAN_MB02_DATA3)
+#define bfin_write_CAN_MB02_DATA3(val)       bfin_write16(CAN_MB02_DATA3,val)
+#define bfin_read_CAN_MB02_DATA2()           bfin_read16(CAN_MB02_DATA2)
+#define bfin_write_CAN_MB02_DATA2(val)       bfin_write16(CAN_MB02_DATA2,val)
+#define bfin_read_CAN_MB02_DATA1()           bfin_read16(CAN_MB02_DATA1)
+#define bfin_write_CAN_MB02_DATA1(val)       bfin_write16(CAN_MB02_DATA1,val)
+#define bfin_read_CAN_MB02_DATA0()           bfin_read16(CAN_MB02_DATA0)
+#define bfin_write_CAN_MB02_DATA0(val)       bfin_write16(CAN_MB02_DATA0,val)
+
+#define bfin_read_CAN_MB03_ID1()             bfin_read16(CAN_MB03_ID1)
+#define bfin_write_CAN_MB03_ID1(val)         bfin_write16(CAN_MB03_ID1,val)
+#define bfin_read_CAN_MB03_ID0()             bfin_read16(CAN_MB03_ID0)
+#define bfin_write_CAN_MB03_ID0(val)         bfin_write16(CAN_MB03_ID0,val)
+#define bfin_read_CAN_MB03_TIMESTAMP()       bfin_read16(CAN_MB03_TIMESTAMP)
+#define bfin_write_CAN_MB03_TIMESTAMP(val)   bfin_write16(CAN_MB03_TIMESTAMP,val)
+#define bfin_read_CAN_MB03_LENGTH()          bfin_read16(CAN_MB03_LENGTH)
+#define bfin_write_CAN_MB03_LENGTH(val)      bfin_write16(CAN_MB03_LENGTH,val)
+#define bfin_read_CAN_MB03_DATA3()           bfin_read16(CAN_MB03_DATA3)
+#define bfin_write_CAN_MB03_DATA3(val)       bfin_write16(CAN_MB03_DATA3,val)
+#define bfin_read_CAN_MB03_DATA2()           bfin_read16(CAN_MB03_DATA2)
+#define bfin_write_CAN_MB03_DATA2(val)       bfin_write16(CAN_MB03_DATA2,val)
+#define bfin_read_CAN_MB03_DATA1()           bfin_read16(CAN_MB03_DATA1)
+#define bfin_write_CAN_MB03_DATA1(val)       bfin_write16(CAN_MB03_DATA1,val)
+#define bfin_read_CAN_MB03_DATA0()           bfin_read16(CAN_MB03_DATA0)
+#define bfin_write_CAN_MB03_DATA0(val)       bfin_write16(CAN_MB03_DATA0,val)
+
+#define bfin_read_CAN_MB04_ID1()             bfin_read16(CAN_MB04_ID1)
+#define bfin_write_CAN_MB04_ID1(val)         bfin_write16(CAN_MB04_ID1,val)
+#define bfin_read_CAN_MB04_ID0()             bfin_read16(CAN_MB04_ID0)
+#define bfin_write_CAN_MB04_ID0(val)         bfin_write16(CAN_MB04_ID0,val)
+#define bfin_read_CAN_MB04_TIMESTAMP()       bfin_read16(CAN_MB04_TIMESTAMP)
+#define bfin_write_CAN_MB04_TIMESTAMP(val)   bfin_write16(CAN_MB04_TIMESTAMP,val)
+#define bfin_read_CAN_MB04_LENGTH()          bfin_read16(CAN_MB04_LENGTH)
+#define bfin_write_CAN_MB04_LENGTH(val)      bfin_write16(CAN_MB04_LENGTH,val)
+#define bfin_read_CAN_MB04_DATA3()           bfin_read16(CAN_MB04_DATA3)
+#define bfin_write_CAN_MB04_DATA3(val)       bfin_write16(CAN_MB04_DATA3,val)
+#define bfin_read_CAN_MB04_DATA2()           bfin_read16(CAN_MB04_DATA2)
+#define bfin_write_CAN_MB04_DATA2(val)       bfin_write16(CAN_MB04_DATA2,val)
+#define bfin_read_CAN_MB04_DATA1()           bfin_read16(CAN_MB04_DATA1)
+#define bfin_write_CAN_MB04_DATA1(val)       bfin_write16(CAN_MB04_DATA1,val)
+#define bfin_read_CAN_MB04_DATA0()           bfin_read16(CAN_MB04_DATA0)
+#define bfin_write_CAN_MB04_DATA0(val)       bfin_write16(CAN_MB04_DATA0,val)
+
+#define bfin_read_CAN_MB05_ID1()             bfin_read16(CAN_MB05_ID1)
+#define bfin_write_CAN_MB05_ID1(val)         bfin_write16(CAN_MB05_ID1,val)
+#define bfin_read_CAN_MB05_ID0()             bfin_read16(CAN_MB05_ID0)
+#define bfin_write_CAN_MB05_ID0(val)         bfin_write16(CAN_MB05_ID0,val)
+#define bfin_read_CAN_MB05_TIMESTAMP()       bfin_read16(CAN_MB05_TIMESTAMP)
+#define bfin_write_CAN_MB05_TIMESTAMP(val)   bfin_write16(CAN_MB05_TIMESTAMP,val)
+#define bfin_read_CAN_MB05_LENGTH()          bfin_read16(CAN_MB05_LENGTH)
+#define bfin_write_CAN_MB05_LENGTH(val)      bfin_write16(CAN_MB05_LENGTH,val)
+#define bfin_read_CAN_MB05_DATA3()           bfin_read16(CAN_MB05_DATA3)
+#define bfin_write_CAN_MB05_DATA3(val)       bfin_write16(CAN_MB05_DATA3,val)
+#define bfin_read_CAN_MB05_DATA2()           bfin_read16(CAN_MB05_DATA2)
+#define bfin_write_CAN_MB05_DATA2(val)       bfin_write16(CAN_MB05_DATA2,val)
+#define bfin_read_CAN_MB05_DATA1()           bfin_read16(CAN_MB05_DATA1)
+#define bfin_write_CAN_MB05_DATA1(val)       bfin_write16(CAN_MB05_DATA1,val)
+#define bfin_read_CAN_MB05_DATA0()           bfin_read16(CAN_MB05_DATA0)
+#define bfin_write_CAN_MB05_DATA0(val)       bfin_write16(CAN_MB05_DATA0,val)
+
+#define bfin_read_CAN_MB06_ID1()             bfin_read16(CAN_MB06_ID1)
+#define bfin_write_CAN_MB06_ID1(val)         bfin_write16(CAN_MB06_ID1,val)
+#define bfin_read_CAN_MB06_ID0()             bfin_read16(CAN_MB06_ID0)
+#define bfin_write_CAN_MB06_ID0(val)         bfin_write16(CAN_MB06_ID0,val)
+#define bfin_read_CAN_MB06_TIMESTAMP()       bfin_read16(CAN_MB06_TIMESTAMP)
+#define bfin_write_CAN_MB06_TIMESTAMP(val)   bfin_write16(CAN_MB06_TIMESTAMP,val)
+#define bfin_read_CAN_MB06_LENGTH()          bfin_read16(CAN_MB06_LENGTH)
+#define bfin_write_CAN_MB06_LENGTH(val)      bfin_write16(CAN_MB06_LENGTH,val)
+#define bfin_read_CAN_MB06_DATA3()           bfin_read16(CAN_MB06_DATA3)
+#define bfin_write_CAN_MB06_DATA3(val)       bfin_write16(CAN_MB06_DATA3,val)
+#define bfin_read_CAN_MB06_DATA2()           bfin_read16(CAN_MB06_DATA2)
+#define bfin_write_CAN_MB06_DATA2(val)       bfin_write16(CAN_MB06_DATA2,val)
+#define bfin_read_CAN_MB06_DATA1()           bfin_read16(CAN_MB06_DATA1)
+#define bfin_write_CAN_MB06_DATA1(val)       bfin_write16(CAN_MB06_DATA1,val)
+#define bfin_read_CAN_MB06_DATA0()           bfin_read16(CAN_MB06_DATA0)
+#define bfin_write_CAN_MB06_DATA0(val)       bfin_write16(CAN_MB06_DATA0,val)
+
+#define bfin_read_CAN_MB07_ID1()             bfin_read16(CAN_MB07_ID1)
+#define bfin_write_CAN_MB07_ID1(val)         bfin_write16(CAN_MB07_ID1,val)
+#define bfin_read_CAN_MB07_ID0()             bfin_read16(CAN_MB07_ID0)
+#define bfin_write_CAN_MB07_ID0(val)         bfin_write16(CAN_MB07_ID0,val)
+#define bfin_read_CAN_MB07_TIMESTAMP()       bfin_read16(CAN_MB07_TIMESTAMP)
+#define bfin_write_CAN_MB07_TIMESTAMP(val)   bfin_write16(CAN_MB07_TIMESTAMP,val)
+#define bfin_read_CAN_MB07_LENGTH()          bfin_read16(CAN_MB07_LENGTH)
+#define bfin_write_CAN_MB07_LENGTH(val)      bfin_write16(CAN_MB07_LENGTH,val)
+#define bfin_read_CAN_MB07_DATA3()           bfin_read16(CAN_MB07_DATA3)
+#define bfin_write_CAN_MB07_DATA3(val)       bfin_write16(CAN_MB07_DATA3,val)
+#define bfin_read_CAN_MB07_DATA2()           bfin_read16(CAN_MB07_DATA2)
+#define bfin_write_CAN_MB07_DATA2(val)       bfin_write16(CAN_MB07_DATA2,val)
+#define bfin_read_CAN_MB07_DATA1()           bfin_read16(CAN_MB07_DATA1)
+#define bfin_write_CAN_MB07_DATA1(val)       bfin_write16(CAN_MB07_DATA1,val)
+#define bfin_read_CAN_MB07_DATA0()           bfin_read16(CAN_MB07_DATA0)
+#define bfin_write_CAN_MB07_DATA0(val)       bfin_write16(CAN_MB07_DATA0,val)
+
+#define bfin_read_CAN_MB08_ID1()             bfin_read16(CAN_MB08_ID1)
+#define bfin_write_CAN_MB08_ID1(val)         bfin_write16(CAN_MB08_ID1,val)
+#define bfin_read_CAN_MB08_ID0()             bfin_read16(CAN_MB08_ID0)
+#define bfin_write_CAN_MB08_ID0(val)         bfin_write16(CAN_MB08_ID0,val)
+#define bfin_read_CAN_MB08_TIMESTAMP()       bfin_read16(CAN_MB08_TIMESTAMP)
+#define bfin_write_CAN_MB08_TIMESTAMP(val)   bfin_write16(CAN_MB08_TIMESTAMP,val)
+#define bfin_read_CAN_MB08_LENGTH()          bfin_read16(CAN_MB08_LENGTH)
+#define bfin_write_CAN_MB08_LENGTH(val)      bfin_write16(CAN_MB08_LENGTH,val)
+#define bfin_read_CAN_MB08_DATA3()           bfin_read16(CAN_MB08_DATA3)
+#define bfin_write_CAN_MB08_DATA3(val)       bfin_write16(CAN_MB08_DATA3,val)
+#define bfin_read_CAN_MB08_DATA2()           bfin_read16(CAN_MB08_DATA2)
+#define bfin_write_CAN_MB08_DATA2(val)       bfin_write16(CAN_MB08_DATA2,val)
+#define bfin_read_CAN_MB08_DATA1()           bfin_read16(CAN_MB08_DATA1)
+#define bfin_write_CAN_MB08_DATA1(val)       bfin_write16(CAN_MB08_DATA1,val)
+#define bfin_read_CAN_MB08_DATA0()           bfin_read16(CAN_MB08_DATA0)
+#define bfin_write_CAN_MB08_DATA0(val)       bfin_write16(CAN_MB08_DATA0,val)
+
+#define bfin_read_CAN_MB09_ID1()             bfin_read16(CAN_MB09_ID1)
+#define bfin_write_CAN_MB09_ID1(val)         bfin_write16(CAN_MB09_ID1,val)
+#define bfin_read_CAN_MB09_ID0()             bfin_read16(CAN_MB09_ID0)
+#define bfin_write_CAN_MB09_ID0(val)         bfin_write16(CAN_MB09_ID0,val)
+#define bfin_read_CAN_MB09_TIMESTAMP()       bfin_read16(CAN_MB09_TIMESTAMP)
+#define bfin_write_CAN_MB09_TIMESTAMP(val)   bfin_write16(CAN_MB09_TIMESTAMP,val)
+#define bfin_read_CAN_MB09_LENGTH()          bfin_read16(CAN_MB09_LENGTH)
+#define bfin_write_CAN_MB09_LENGTH(val)      bfin_write16(CAN_MB09_LENGTH,val)
+#define bfin_read_CAN_MB09_DATA3()           bfin_read16(CAN_MB09_DATA3)
+#define bfin_write_CAN_MB09_DATA3(val)       bfin_write16(CAN_MB09_DATA3,val)
+#define bfin_read_CAN_MB09_DATA2()           bfin_read16(CAN_MB09_DATA2)
+#define bfin_write_CAN_MB09_DATA2(val)       bfin_write16(CAN_MB09_DATA2,val)
+#define bfin_read_CAN_MB09_DATA1()           bfin_read16(CAN_MB09_DATA1)
+#define bfin_write_CAN_MB09_DATA1(val)       bfin_write16(CAN_MB09_DATA1,val)
+#define bfin_read_CAN_MB09_DATA0()           bfin_read16(CAN_MB09_DATA0)
+#define bfin_write_CAN_MB09_DATA0(val)       bfin_write16(CAN_MB09_DATA0,val)
+
+#define bfin_read_CAN_MB10_ID1()             bfin_read16(CAN_MB10_ID1)
+#define bfin_write_CAN_MB10_ID1(val)         bfin_write16(CAN_MB10_ID1,val)
+#define bfin_read_CAN_MB10_ID0()             bfin_read16(CAN_MB10_ID0)
+#define bfin_write_CAN_MB10_ID0(val)         bfin_write16(CAN_MB10_ID0,val)
+#define bfin_read_CAN_MB10_TIMESTAMP()       bfin_read16(CAN_MB10_TIMESTAMP)
+#define bfin_write_CAN_MB10_TIMESTAMP(val)   bfin_write16(CAN_MB10_TIMESTAMP,val)
+#define bfin_read_CAN_MB10_LENGTH()          bfin_read16(CAN_MB10_LENGTH)
+#define bfin_write_CAN_MB10_LENGTH(val)      bfin_write16(CAN_MB10_LENGTH,val)
+#define bfin_read_CAN_MB10_DATA3()           bfin_read16(CAN_MB10_DATA3)
+#define bfin_write_CAN_MB10_DATA3(val)       bfin_write16(CAN_MB10_DATA3,val)
+#define bfin_read_CAN_MB10_DATA2()           bfin_read16(CAN_MB10_DATA2)
+#define bfin_write_CAN_MB10_DATA2(val)       bfin_write16(CAN_MB10_DATA2,val)
+#define bfin_read_CAN_MB10_DATA1()           bfin_read16(CAN_MB10_DATA1)
+#define bfin_write_CAN_MB10_DATA1(val)       bfin_write16(CAN_MB10_DATA1,val)
+#define bfin_read_CAN_MB10_DATA0()           bfin_read16(CAN_MB10_DATA0)
+#define bfin_write_CAN_MB10_DATA0(val)       bfin_write16(CAN_MB10_DATA0,val)
+
+#define bfin_read_CAN_MB11_ID1()             bfin_read16(CAN_MB11_ID1)
+#define bfin_write_CAN_MB11_ID1(val)         bfin_write16(CAN_MB11_ID1,val)
+#define bfin_read_CAN_MB11_ID0()             bfin_read16(CAN_MB11_ID0)
+#define bfin_write_CAN_MB11_ID0(val)         bfin_write16(CAN_MB11_ID0,val)
+#define bfin_read_CAN_MB11_TIMESTAMP()       bfin_read16(CAN_MB11_TIMESTAMP)
+#define bfin_write_CAN_MB11_TIMESTAMP(val)   bfin_write16(CAN_MB11_TIMESTAMP,val)
+#define bfin_read_CAN_MB11_LENGTH()          bfin_read16(CAN_MB11_LENGTH)
+#define bfin_write_CAN_MB11_LENGTH(val)      bfin_write16(CAN_MB11_LENGTH,val)
+#define bfin_read_CAN_MB11_DATA3()           bfin_read16(CAN_MB11_DATA3)
+#define bfin_write_CAN_MB11_DATA3(val)       bfin_write16(CAN_MB11_DATA3,val)
+#define bfin_read_CAN_MB11_DATA2()           bfin_read16(CAN_MB11_DATA2)
+#define bfin_write_CAN_MB11_DATA2(val)       bfin_write16(CAN_MB11_DATA2,val)
+#define bfin_read_CAN_MB11_DATA1()           bfin_read16(CAN_MB11_DATA1)
+#define bfin_write_CAN_MB11_DATA1(val)       bfin_write16(CAN_MB11_DATA1,val)
+#define bfin_read_CAN_MB11_DATA0()           bfin_read16(CAN_MB11_DATA0)
+#define bfin_write_CAN_MB11_DATA0(val)       bfin_write16(CAN_MB11_DATA0,val)
+
+#define bfin_read_CAN_MB12_ID1()             bfin_read16(CAN_MB12_ID1)
+#define bfin_write_CAN_MB12_ID1(val)         bfin_write16(CAN_MB12_ID1,val)
+#define bfin_read_CAN_MB12_ID0()             bfin_read16(CAN_MB12_ID0)
+#define bfin_write_CAN_MB12_ID0(val)         bfin_write16(CAN_MB12_ID0,val)
+#define bfin_read_CAN_MB12_TIMESTAMP()       bfin_read16(CAN_MB12_TIMESTAMP)
+#define bfin_write_CAN_MB12_TIMESTAMP(val)   bfin_write16(CAN_MB12_TIMESTAMP,val)
+#define bfin_read_CAN_MB12_LENGTH()          bfin_read16(CAN_MB12_LENGTH)
+#define bfin_write_CAN_MB12_LENGTH(val)      bfin_write16(CAN_MB12_LENGTH,val)
+#define bfin_read_CAN_MB12_DATA3()           bfin_read16(CAN_MB12_DATA3)
+#define bfin_write_CAN_MB12_DATA3(val)       bfin_write16(CAN_MB12_DATA3,val)
+#define bfin_read_CAN_MB12_DATA2()           bfin_read16(CAN_MB12_DATA2)
+#define bfin_write_CAN_MB12_DATA2(val)       bfin_write16(CAN_MB12_DATA2,val)
+#define bfin_read_CAN_MB12_DATA1()           bfin_read16(CAN_MB12_DATA1)
+#define bfin_write_CAN_MB12_DATA1(val)       bfin_write16(CAN_MB12_DATA1,val)
+#define bfin_read_CAN_MB12_DATA0()           bfin_read16(CAN_MB12_DATA0)
+#define bfin_write_CAN_MB12_DATA0(val)       bfin_write16(CAN_MB12_DATA0,val)
+
+#define bfin_read_CAN_MB13_ID1()             bfin_read16(CAN_MB13_ID1)
+#define bfin_write_CAN_MB13_ID1(val)         bfin_write16(CAN_MB13_ID1,val)
+#define bfin_read_CAN_MB13_ID0()             bfin_read16(CAN_MB13_ID0)
+#define bfin_write_CAN_MB13_ID0(val)         bfin_write16(CAN_MB13_ID0,val)
+#define bfin_read_CAN_MB13_TIMESTAMP()       bfin_read16(CAN_MB13_TIMESTAMP)
+#define bfin_write_CAN_MB13_TIMESTAMP(val)   bfin_write16(CAN_MB13_TIMESTAMP,val)
+#define bfin_read_CAN_MB13_LENGTH()          bfin_read16(CAN_MB13_LENGTH)
+#define bfin_write_CAN_MB13_LENGTH(val)      bfin_write16(CAN_MB13_LENGTH,val)
+#define bfin_read_CAN_MB13_DATA3()           bfin_read16(CAN_MB13_DATA3)
+#define bfin_write_CAN_MB13_DATA3(val)       bfin_write16(CAN_MB13_DATA3,val)
+#define bfin_read_CAN_MB13_DATA2()           bfin_read16(CAN_MB13_DATA2)
+#define bfin_write_CAN_MB13_DATA2(val)       bfin_write16(CAN_MB13_DATA2,val)
+#define bfin_read_CAN_MB13_DATA1()           bfin_read16(CAN_MB13_DATA1)
+#define bfin_write_CAN_MB13_DATA1(val)       bfin_write16(CAN_MB13_DATA1,val)
+#define bfin_read_CAN_MB13_DATA0()           bfin_read16(CAN_MB13_DATA0)
+#define bfin_write_CAN_MB13_DATA0(val)       bfin_write16(CAN_MB13_DATA0,val)
+
+#define bfin_read_CAN_MB14_ID1()             bfin_read16(CAN_MB14_ID1)
+#define bfin_write_CAN_MB14_ID1(val)         bfin_write16(CAN_MB14_ID1,val)
+#define bfin_read_CAN_MB14_ID0()             bfin_read16(CAN_MB14_ID0)
+#define bfin_write_CAN_MB14_ID0(val)         bfin_write16(CAN_MB14_ID0,val)
+#define bfin_read_CAN_MB14_TIMESTAMP()       bfin_read16(CAN_MB14_TIMESTAMP)
+#define bfin_write_CAN_MB14_TIMESTAMP(val)   bfin_write16(CAN_MB14_TIMESTAMP,val)
+#define bfin_read_CAN_MB14_LENGTH()          bfin_read16(CAN_MB14_LENGTH)
+#define bfin_write_CAN_MB14_LENGTH(val)      bfin_write16(CAN_MB14_LENGTH,val)
+#define bfin_read_CAN_MB14_DATA3()           bfin_read16(CAN_MB14_DATA3)
+#define bfin_write_CAN_MB14_DATA3(val)       bfin_write16(CAN_MB14_DATA3,val)
+#define bfin_read_CAN_MB14_DATA2()           bfin_read16(CAN_MB14_DATA2)
+#define bfin_write_CAN_MB14_DATA2(val)       bfin_write16(CAN_MB14_DATA2,val)
+#define bfin_read_CAN_MB14_DATA1()           bfin_read16(CAN_MB14_DATA1)
+#define bfin_write_CAN_MB14_DATA1(val)       bfin_write16(CAN_MB14_DATA1,val)
+#define bfin_read_CAN_MB14_DATA0()           bfin_read16(CAN_MB14_DATA0)
+#define bfin_write_CAN_MB14_DATA0(val)       bfin_write16(CAN_MB14_DATA0,val)
+
+#define bfin_read_CAN_MB15_ID1()             bfin_read16(CAN_MB15_ID1)
+#define bfin_write_CAN_MB15_ID1(val)         bfin_write16(CAN_MB15_ID1,val)
+#define bfin_read_CAN_MB15_ID0()             bfin_read16(CAN_MB15_ID0)
+#define bfin_write_CAN_MB15_ID0(val)         bfin_write16(CAN_MB15_ID0,val)
+#define bfin_read_CAN_MB15_TIMESTAMP()       bfin_read16(CAN_MB15_TIMESTAMP)
+#define bfin_write_CAN_MB15_TIMESTAMP(val)   bfin_write16(CAN_MB15_TIMESTAMP,val)
+#define bfin_read_CAN_MB15_LENGTH()          bfin_read16(CAN_MB15_LENGTH)
+#define bfin_write_CAN_MB15_LENGTH(val)      bfin_write16(CAN_MB15_LENGTH,val)
+#define bfin_read_CAN_MB15_DATA3()           bfin_read16(CAN_MB15_DATA3)
+#define bfin_write_CAN_MB15_DATA3(val)       bfin_write16(CAN_MB15_DATA3,val)
+#define bfin_read_CAN_MB15_DATA2()           bfin_read16(CAN_MB15_DATA2)
+#define bfin_write_CAN_MB15_DATA2(val)       bfin_write16(CAN_MB15_DATA2,val)
+#define bfin_read_CAN_MB15_DATA1()           bfin_read16(CAN_MB15_DATA1)
+#define bfin_write_CAN_MB15_DATA1(val)       bfin_write16(CAN_MB15_DATA1,val)
+#define bfin_read_CAN_MB15_DATA0()           bfin_read16(CAN_MB15_DATA0)
+#define bfin_write_CAN_MB15_DATA0(val)       bfin_write16(CAN_MB15_DATA0,val)
+
+#define bfin_read_CAN_MB16_ID1()             bfin_read16(CAN_MB16_ID1)
+#define bfin_write_CAN_MB16_ID1(val)         bfin_write16(CAN_MB16_ID1,val)
+#define bfin_read_CAN_MB16_ID0()             bfin_read16(CAN_MB16_ID0)
+#define bfin_write_CAN_MB16_ID0(val)         bfin_write16(CAN_MB16_ID0,val)
+#define bfin_read_CAN_MB16_TIMESTAMP()       bfin_read16(CAN_MB16_TIMESTAMP)
+#define bfin_write_CAN_MB16_TIMESTAMP(val)   bfin_write16(CAN_MB16_TIMESTAMP,val)
+#define bfin_read_CAN_MB16_LENGTH()          bfin_read16(CAN_MB16_LENGTH)
+#define bfin_write_CAN_MB16_LENGTH(val)      bfin_write16(CAN_MB16_LENGTH,val)
+#define bfin_read_CAN_MB16_DATA3()           bfin_read16(CAN_MB16_DATA3)
+#define bfin_write_CAN_MB16_DATA3(val)       bfin_write16(CAN_MB16_DATA3,val)
+#define bfin_read_CAN_MB16_DATA2()           bfin_read16(CAN_MB16_DATA2)
+#define bfin_write_CAN_MB16_DATA2(val)       bfin_write16(CAN_MB16_DATA2,val)
+#define bfin_read_CAN_MB16_DATA1()           bfin_read16(CAN_MB16_DATA1)
+#define bfin_write_CAN_MB16_DATA1(val)       bfin_write16(CAN_MB16_DATA1,val)
+#define bfin_read_CAN_MB16_DATA0()           bfin_read16(CAN_MB16_DATA0)
+#define bfin_write_CAN_MB16_DATA0(val)       bfin_write16(CAN_MB16_DATA0,val)
+
+#define bfin_read_CAN_MB17_ID1()             bfin_read16(CAN_MB17_ID1)
+#define bfin_write_CAN_MB17_ID1(val)         bfin_write16(CAN_MB17_ID1,val)
+#define bfin_read_CAN_MB17_ID0()             bfin_read16(CAN_MB17_ID0)
+#define bfin_write_CAN_MB17_ID0(val)         bfin_write16(CAN_MB17_ID0,val)
+#define bfin_read_CAN_MB17_TIMESTAMP()       bfin_read16(CAN_MB17_TIMESTAMP)
+#define bfin_write_CAN_MB17_TIMESTAMP(val)   bfin_write16(CAN_MB17_TIMESTAMP,val)
+#define bfin_read_CAN_MB17_LENGTH()          bfin_read16(CAN_MB17_LENGTH)
+#define bfin_write_CAN_MB17_LENGTH(val)      bfin_write16(CAN_MB17_LENGTH,val)
+#define bfin_read_CAN_MB17_DATA3()           bfin_read16(CAN_MB17_DATA3)
+#define bfin_write_CAN_MB17_DATA3(val)       bfin_write16(CAN_MB17_DATA3,val)
+#define bfin_read_CAN_MB17_DATA2()           bfin_read16(CAN_MB17_DATA2)
+#define bfin_write_CAN_MB17_DATA2(val)       bfin_write16(CAN_MB17_DATA2,val)
+#define bfin_read_CAN_MB17_DATA1()           bfin_read16(CAN_MB17_DATA1)
+#define bfin_write_CAN_MB17_DATA1(val)       bfin_write16(CAN_MB17_DATA1,val)
+#define bfin_read_CAN_MB17_DATA0()           bfin_read16(CAN_MB17_DATA0)
+#define bfin_write_CAN_MB17_DATA0(val)       bfin_write16(CAN_MB17_DATA0,val)
+
+#define bfin_read_CAN_MB18_ID1()             bfin_read16(CAN_MB18_ID1)
+#define bfin_write_CAN_MB18_ID1(val)         bfin_write16(CAN_MB18_ID1,val)
+#define bfin_read_CAN_MB18_ID0()             bfin_read16(CAN_MB18_ID0)
+#define bfin_write_CAN_MB18_ID0(val)         bfin_write16(CAN_MB18_ID0,val)
+#define bfin_read_CAN_MB18_TIMESTAMP()       bfin_read16(CAN_MB18_TIMESTAMP)
+#define bfin_write_CAN_MB18_TIMESTAMP(val)   bfin_write16(CAN_MB18_TIMESTAMP,val)
+#define bfin_read_CAN_MB18_LENGTH()          bfin_read16(CAN_MB18_LENGTH)
+#define bfin_write_CAN_MB18_LENGTH(val)      bfin_write16(CAN_MB18_LENGTH,val)
+#define bfin_read_CAN_MB18_DATA3()           bfin_read16(CAN_MB18_DATA3)
+#define bfin_write_CAN_MB18_DATA3(val)       bfin_write16(CAN_MB18_DATA3,val)
+#define bfin_read_CAN_MB18_DATA2()           bfin_read16(CAN_MB18_DATA2)
+#define bfin_write_CAN_MB18_DATA2(val)       bfin_write16(CAN_MB18_DATA2,val)
+#define bfin_read_CAN_MB18_DATA1()           bfin_read16(CAN_MB18_DATA1)
+#define bfin_write_CAN_MB18_DATA1(val)       bfin_write16(CAN_MB18_DATA1,val)
+#define bfin_read_CAN_MB18_DATA0()           bfin_read16(CAN_MB18_DATA0)
+#define bfin_write_CAN_MB18_DATA0(val)       bfin_write16(CAN_MB18_DATA0,val)
+
+#define bfin_read_CAN_MB19_ID1()             bfin_read16(CAN_MB19_ID1)
+#define bfin_write_CAN_MB19_ID1(val)         bfin_write16(CAN_MB19_ID1,val)
+#define bfin_read_CAN_MB19_ID0()             bfin_read16(CAN_MB19_ID0)
+#define bfin_write_CAN_MB19_ID0(val)         bfin_write16(CAN_MB19_ID0,val)
+#define bfin_read_CAN_MB19_TIMESTAMP()       bfin_read16(CAN_MB19_TIMESTAMP)
+#define bfin_write_CAN_MB19_TIMESTAMP(val)   bfin_write16(CAN_MB19_TIMESTAMP,val)
+#define bfin_read_CAN_MB19_LENGTH()          bfin_read16(CAN_MB19_LENGTH)
+#define bfin_write_CAN_MB19_LENGTH(val)      bfin_write16(CAN_MB19_LENGTH,val)
+#define bfin_read_CAN_MB19_DATA3()           bfin_read16(CAN_MB19_DATA3)
+#define bfin_write_CAN_MB19_DATA3(val)       bfin_write16(CAN_MB19_DATA3,val)
+#define bfin_read_CAN_MB19_DATA2()           bfin_read16(CAN_MB19_DATA2)
+#define bfin_write_CAN_MB19_DATA2(val)       bfin_write16(CAN_MB19_DATA2,val)
+#define bfin_read_CAN_MB19_DATA1()           bfin_read16(CAN_MB19_DATA1)
+#define bfin_write_CAN_MB19_DATA1(val)       bfin_write16(CAN_MB19_DATA1,val)
+#define bfin_read_CAN_MB19_DATA0()           bfin_read16(CAN_MB19_DATA0)
+#define bfin_write_CAN_MB19_DATA0(val)       bfin_write16(CAN_MB19_DATA0,val)
+
+#define bfin_read_CAN_MB20_ID1()             bfin_read16(CAN_MB20_ID1)
+#define bfin_write_CAN_MB20_ID1(val)         bfin_write16(CAN_MB20_ID1,val)
+#define bfin_read_CAN_MB20_ID0()             bfin_read16(CAN_MB20_ID0)
+#define bfin_write_CAN_MB20_ID0(val)         bfin_write16(CAN_MB20_ID0,val)
+#define bfin_read_CAN_MB20_TIMESTAMP()       bfin_read16(CAN_MB20_TIMESTAMP)
+#define bfin_write_CAN_MB20_TIMESTAMP(val)   bfin_write16(CAN_MB20_TIMESTAMP,val)
+#define bfin_read_CAN_MB20_LENGTH()          bfin_read16(CAN_MB20_LENGTH)
+#define bfin_write_CAN_MB20_LENGTH(val)      bfin_write16(CAN_MB20_LENGTH,val)
+#define bfin_read_CAN_MB20_DATA3()           bfin_read16(CAN_MB20_DATA3)
+#define bfin_write_CAN_MB20_DATA3(val)       bfin_write16(CAN_MB20_DATA3,val)
+#define bfin_read_CAN_MB20_DATA2()           bfin_read16(CAN_MB20_DATA2)
+#define bfin_write_CAN_MB20_DATA2(val)       bfin_write16(CAN_MB20_DATA2,val)
+#define bfin_read_CAN_MB20_DATA1()           bfin_read16(CAN_MB20_DATA1)
+#define bfin_write_CAN_MB20_DATA1(val)       bfin_write16(CAN_MB20_DATA1,val)
+#define bfin_read_CAN_MB20_DATA0()           bfin_read16(CAN_MB20_DATA0)
+#define bfin_write_CAN_MB20_DATA0(val)       bfin_write16(CAN_MB20_DATA0,val)
+
+#define bfin_read_CAN_MB21_ID1()             bfin_read16(CAN_MB21_ID1)
+#define bfin_write_CAN_MB21_ID1(val)         bfin_write16(CAN_MB21_ID1,val)
+#define bfin_read_CAN_MB21_ID0()             bfin_read16(CAN_MB21_ID0)
+#define bfin_write_CAN_MB21_ID0(val)         bfin_write16(CAN_MB21_ID0,val)
+#define bfin_read_CAN_MB21_TIMESTAMP()       bfin_read16(CAN_MB21_TIMESTAMP)
+#define bfin_write_CAN_MB21_TIMESTAMP(val)   bfin_write16(CAN_MB21_TIMESTAMP,val)
+#define bfin_read_CAN_MB21_LENGTH()          bfin_read16(CAN_MB21_LENGTH)
+#define bfin_write_CAN_MB21_LENGTH(val)      bfin_write16(CAN_MB21_LENGTH,val)
+#define bfin_read_CAN_MB21_DATA3()           bfin_read16(CAN_MB21_DATA3)
+#define bfin_write_CAN_MB21_DATA3(val)       bfin_write16(CAN_MB21_DATA3,val)
+#define bfin_read_CAN_MB21_DATA2()           bfin_read16(CAN_MB21_DATA2)
+#define bfin_write_CAN_MB21_DATA2(val)       bfin_write16(CAN_MB21_DATA2,val)
+#define bfin_read_CAN_MB21_DATA1()           bfin_read16(CAN_MB21_DATA1)
+#define bfin_write_CAN_MB21_DATA1(val)       bfin_write16(CAN_MB21_DATA1,val)
+#define bfin_read_CAN_MB21_DATA0()           bfin_read16(CAN_MB21_DATA0)
+#define bfin_write_CAN_MB21_DATA0(val)       bfin_write16(CAN_MB21_DATA0,val)
+
+#define bfin_read_CAN_MB22_ID1()             bfin_read16(CAN_MB22_ID1)
+#define bfin_write_CAN_MB22_ID1(val)         bfin_write16(CAN_MB22_ID1,val)
+#define bfin_read_CAN_MB22_ID0()             bfin_read16(CAN_MB22_ID0)
+#define bfin_write_CAN_MB22_ID0(val)         bfin_write16(CAN_MB22_ID0,val)
+#define bfin_read_CAN_MB22_TIMESTAMP()       bfin_read16(CAN_MB22_TIMESTAMP)
+#define bfin_write_CAN_MB22_TIMESTAMP(val)   bfin_write16(CAN_MB22_TIMESTAMP,val)
+#define bfin_read_CAN_MB22_LENGTH()          bfin_read16(CAN_MB22_LENGTH)
+#define bfin_write_CAN_MB22_LENGTH(val)      bfin_write16(CAN_MB22_LENGTH,val)
+#define bfin_read_CAN_MB22_DATA3()           bfin_read16(CAN_MB22_DATA3)
+#define bfin_write_CAN_MB22_DATA3(val)       bfin_write16(CAN_MB22_DATA3,val)
+#define bfin_read_CAN_MB22_DATA2()           bfin_read16(CAN_MB22_DATA2)
+#define bfin_write_CAN_MB22_DATA2(val)       bfin_write16(CAN_MB22_DATA2,val)
+#define bfin_read_CAN_MB22_DATA1()           bfin_read16(CAN_MB22_DATA1)
+#define bfin_write_CAN_MB22_DATA1(val)       bfin_write16(CAN_MB22_DATA1,val)
+#define bfin_read_CAN_MB22_DATA0()           bfin_read16(CAN_MB22_DATA0)
+#define bfin_write_CAN_MB22_DATA0(val)       bfin_write16(CAN_MB22_DATA0,val)
+
+#define bfin_read_CAN_MB23_ID1()             bfin_read16(CAN_MB23_ID1)
+#define bfin_write_CAN_MB23_ID1(val)         bfin_write16(CAN_MB23_ID1,val)
+#define bfin_read_CAN_MB23_ID0()             bfin_read16(CAN_MB23_ID0)
+#define bfin_write_CAN_MB23_ID0(val)         bfin_write16(CAN_MB23_ID0,val)
+#define bfin_read_CAN_MB23_TIMESTAMP()       bfin_read16(CAN_MB23_TIMESTAMP)
+#define bfin_write_CAN_MB23_TIMESTAMP(val)   bfin_write16(CAN_MB23_TIMESTAMP,val)
+#define bfin_read_CAN_MB23_LENGTH()          bfin_read16(CAN_MB23_LENGTH)
+#define bfin_write_CAN_MB23_LENGTH(val)      bfin_write16(CAN_MB23_LENGTH,val)
+#define bfin_read_CAN_MB23_DATA3()           bfin_read16(CAN_MB23_DATA3)
+#define bfin_write_CAN_MB23_DATA3(val)       bfin_write16(CAN_MB23_DATA3,val)
+#define bfin_read_CAN_MB23_DATA2()           bfin_read16(CAN_MB23_DATA2)
+#define bfin_write_CAN_MB23_DATA2(val)       bfin_write16(CAN_MB23_DATA2,val)
+#define bfin_read_CAN_MB23_DATA1()           bfin_read16(CAN_MB23_DATA1)
+#define bfin_write_CAN_MB23_DATA1(val)       bfin_write16(CAN_MB23_DATA1,val)
+#define bfin_read_CAN_MB23_DATA0()           bfin_read16(CAN_MB23_DATA0)
+#define bfin_write_CAN_MB23_DATA0(val)       bfin_write16(CAN_MB23_DATA0,val)
+
+#define bfin_read_CAN_MB24_ID1()             bfin_read16(CAN_MB24_ID1)
+#define bfin_write_CAN_MB24_ID1(val)         bfin_write16(CAN_MB24_ID1,val)
+#define bfin_read_CAN_MB24_ID0()             bfin_read16(CAN_MB24_ID0)
+#define bfin_write_CAN_MB24_ID0(val)         bfin_write16(CAN_MB24_ID0,val)
+#define bfin_read_CAN_MB24_TIMESTAMP()       bfin_read16(CAN_MB24_TIMESTAMP)
+#define bfin_write_CAN_MB24_TIMESTAMP(val)   bfin_write16(CAN_MB24_TIMESTAMP,val)
+#define bfin_read_CAN_MB24_LENGTH()          bfin_read16(CAN_MB24_LENGTH)
+#define bfin_write_CAN_MB24_LENGTH(val)      bfin_write16(CAN_MB24_LENGTH,val)
+#define bfin_read_CAN_MB24_DATA3()           bfin_read16(CAN_MB24_DATA3)
+#define bfin_write_CAN_MB24_DATA3(val)       bfin_write16(CAN_MB24_DATA3,val)
+#define bfin_read_CAN_MB24_DATA2()           bfin_read16(CAN_MB24_DATA2)
+#define bfin_write_CAN_MB24_DATA2(val)       bfin_write16(CAN_MB24_DATA2,val)
+#define bfin_read_CAN_MB24_DATA1()           bfin_read16(CAN_MB24_DATA1)
+#define bfin_write_CAN_MB24_DATA1(val)       bfin_write16(CAN_MB24_DATA1,val)
+#define bfin_read_CAN_MB24_DATA0()           bfin_read16(CAN_MB24_DATA0)
+#define bfin_write_CAN_MB24_DATA0(val)       bfin_write16(CAN_MB24_DATA0,val)
+
+#define bfin_read_CAN_MB25_ID1()             bfin_read16(CAN_MB25_ID1)
+#define bfin_write_CAN_MB25_ID1(val)         bfin_write16(CAN_MB25_ID1,val)
+#define bfin_read_CAN_MB25_ID0()             bfin_read16(CAN_MB25_ID0)
+#define bfin_write_CAN_MB25_ID0(val)         bfin_write16(CAN_MB25_ID0,val)
+#define bfin_read_CAN_MB25_TIMESTAMP()       bfin_read16(CAN_MB25_TIMESTAMP)
+#define bfin_write_CAN_MB25_TIMESTAMP(val)   bfin_write16(CAN_MB25_TIMESTAMP,val)
+#define bfin_read_CAN_MB25_LENGTH()          bfin_read16(CAN_MB25_LENGTH)
+#define bfin_write_CAN_MB25_LENGTH(val)      bfin_write16(CAN_MB25_LENGTH,val)
+#define bfin_read_CAN_MB25_DATA3()           bfin_read16(CAN_MB25_DATA3)
+#define bfin_write_CAN_MB25_DATA3(val)       bfin_write16(CAN_MB25_DATA3,val)
+#define bfin_read_CAN_MB25_DATA2()           bfin_read16(CAN_MB25_DATA2)
+#define bfin_write_CAN_MB25_DATA2(val)       bfin_write16(CAN_MB25_DATA2,val)
+#define bfin_read_CAN_MB25_DATA1()           bfin_read16(CAN_MB25_DATA1)
+#define bfin_write_CAN_MB25_DATA1(val)       bfin_write16(CAN_MB25_DATA1,val)
+#define bfin_read_CAN_MB25_DATA0()           bfin_read16(CAN_MB25_DATA0)
+#define bfin_write_CAN_MB25_DATA0(val)       bfin_write16(CAN_MB25_DATA0,val)
+
+#define bfin_read_CAN_MB26_ID1()             bfin_read16(CAN_MB26_ID1)
+#define bfin_write_CAN_MB26_ID1(val)         bfin_write16(CAN_MB26_ID1,val)
+#define bfin_read_CAN_MB26_ID0()             bfin_read16(CAN_MB26_ID0)
+#define bfin_write_CAN_MB26_ID0(val)         bfin_write16(CAN_MB26_ID0,val)
+#define bfin_read_CAN_MB26_TIMESTAMP()       bfin_read16(CAN_MB26_TIMESTAMP)
+#define bfin_write_CAN_MB26_TIMESTAMP(val)   bfin_write16(CAN_MB26_TIMESTAMP,val)
+#define bfin_read_CAN_MB26_LENGTH()          bfin_read16(CAN_MB26_LENGTH)
+#define bfin_write_CAN_MB26_LENGTH(val)      bfin_write16(CAN_MB26_LENGTH,val)
+#define bfin_read_CAN_MB26_DATA3()           bfin_read16(CAN_MB26_DATA3)
+#define bfin_write_CAN_MB26_DATA3(val)       bfin_write16(CAN_MB26_DATA3,val)
+#define bfin_read_CAN_MB26_DATA2()           bfin_read16(CAN_MB26_DATA2)
+#define bfin_write_CAN_MB26_DATA2(val)       bfin_write16(CAN_MB26_DATA2,val)
+#define bfin_read_CAN_MB26_DATA1()           bfin_read16(CAN_MB26_DATA1)
+#define bfin_write_CAN_MB26_DATA1(val)       bfin_write16(CAN_MB26_DATA1,val)
+#define bfin_read_CAN_MB26_DATA0()           bfin_read16(CAN_MB26_DATA0)
+#define bfin_write_CAN_MB26_DATA0(val)       bfin_write16(CAN_MB26_DATA0,val)
+
+#define bfin_read_CAN_MB27_ID1()             bfin_read16(CAN_MB27_ID1)
+#define bfin_write_CAN_MB27_ID1(val)         bfin_write16(CAN_MB27_ID1,val)
+#define bfin_read_CAN_MB27_ID0()             bfin_read16(CAN_MB27_ID0)
+#define bfin_write_CAN_MB27_ID0(val)         bfin_write16(CAN_MB27_ID0,val)
+#define bfin_read_CAN_MB27_TIMESTAMP()       bfin_read16(CAN_MB27_TIMESTAMP)
+#define bfin_write_CAN_MB27_TIMESTAMP(val)   bfin_write16(CAN_MB27_TIMESTAMP,val)
+#define bfin_read_CAN_MB27_LENGTH()          bfin_read16(CAN_MB27_LENGTH)
+#define bfin_write_CAN_MB27_LENGTH(val)      bfin_write16(CAN_MB27_LENGTH,val)
+#define bfin_read_CAN_MB27_DATA3()           bfin_read16(CAN_MB27_DATA3)
+#define bfin_write_CAN_MB27_DATA3(val)       bfin_write16(CAN_MB27_DATA3,val)
+#define bfin_read_CAN_MB27_DATA2()           bfin_read16(CAN_MB27_DATA2)
+#define bfin_write_CAN_MB27_DATA2(val)       bfin_write16(CAN_MB27_DATA2,val)
+#define bfin_read_CAN_MB27_DATA1()           bfin_read16(CAN_MB27_DATA1)
+#define bfin_write_CAN_MB27_DATA1(val)       bfin_write16(CAN_MB27_DATA1,val)
+#define bfin_read_CAN_MB27_DATA0()           bfin_read16(CAN_MB27_DATA0)
+#define bfin_write_CAN_MB27_DATA0(val)       bfin_write16(CAN_MB27_DATA0,val)
+
+#define bfin_read_CAN_MB28_ID1()             bfin_read16(CAN_MB28_ID1)
+#define bfin_write_CAN_MB28_ID1(val)         bfin_write16(CAN_MB28_ID1,val)
+#define bfin_read_CAN_MB28_ID0()             bfin_read16(CAN_MB28_ID0)
+#define bfin_write_CAN_MB28_ID0(val)         bfin_write16(CAN_MB28_ID0,val)
+#define bfin_read_CAN_MB28_TIMESTAMP()       bfin_read16(CAN_MB28_TIMESTAMP)
+#define bfin_write_CAN_MB28_TIMESTAMP(val)   bfin_write16(CAN_MB28_TIMESTAMP,val)
+#define bfin_read_CAN_MB28_LENGTH()          bfin_read16(CAN_MB28_LENGTH)
+#define bfin_write_CAN_MB28_LENGTH(val)      bfin_write16(CAN_MB28_LENGTH,val)
+#define bfin_read_CAN_MB28_DATA3()           bfin_read16(CAN_MB28_DATA3)
+#define bfin_write_CAN_MB28_DATA3(val)       bfin_write16(CAN_MB28_DATA3,val)
+#define bfin_read_CAN_MB28_DATA2()           bfin_read16(CAN_MB28_DATA2)
+#define bfin_write_CAN_MB28_DATA2(val)       bfin_write16(CAN_MB28_DATA2,val)
+#define bfin_read_CAN_MB28_DATA1()           bfin_read16(CAN_MB28_DATA1)
+#define bfin_write_CAN_MB28_DATA1(val)       bfin_write16(CAN_MB28_DATA1,val)
+#define bfin_read_CAN_MB28_DATA0()           bfin_read16(CAN_MB28_DATA0)
+#define bfin_write_CAN_MB28_DATA0(val)       bfin_write16(CAN_MB28_DATA0,val)
+
+#define bfin_read_CAN_MB29_ID1()             bfin_read16(CAN_MB29_ID1)
+#define bfin_write_CAN_MB29_ID1(val)         bfin_write16(CAN_MB29_ID1,val)
+#define bfin_read_CAN_MB29_ID0()             bfin_read16(CAN_MB29_ID0)
+#define bfin_write_CAN_MB29_ID0(val)         bfin_write16(CAN_MB29_ID0,val)
+#define bfin_read_CAN_MB29_TIMESTAMP()       bfin_read16(CAN_MB29_TIMESTAMP)
+#define bfin_write_CAN_MB29_TIMESTAMP(val)   bfin_write16(CAN_MB29_TIMESTAMP,val)
+#define bfin_read_CAN_MB29_LENGTH()          bfin_read16(CAN_MB29_LENGTH)
+#define bfin_write_CAN_MB29_LENGTH(val)      bfin_write16(CAN_MB29_LENGTH,val)
+#define bfin_read_CAN_MB29_DATA3()           bfin_read16(CAN_MB29_DATA3)
+#define bfin_write_CAN_MB29_DATA3(val)       bfin_write16(CAN_MB29_DATA3,val)
+#define bfin_read_CAN_MB29_DATA2()           bfin_read16(CAN_MB29_DATA2)
+#define bfin_write_CAN_MB29_DATA2(val)       bfin_write16(CAN_MB29_DATA2,val)
+#define bfin_read_CAN_MB29_DATA1()           bfin_read16(CAN_MB29_DATA1)
+#define bfin_write_CAN_MB29_DATA1(val)       bfin_write16(CAN_MB29_DATA1,val)
+#define bfin_read_CAN_MB29_DATA0()           bfin_read16(CAN_MB29_DATA0)
+#define bfin_write_CAN_MB29_DATA0(val)       bfin_write16(CAN_MB29_DATA0,val)
+
+#define bfin_read_CAN_MB30_ID1()             bfin_read16(CAN_MB30_ID1)
+#define bfin_write_CAN_MB30_ID1(val)         bfin_write16(CAN_MB30_ID1,val)
+#define bfin_read_CAN_MB30_ID0()             bfin_read16(CAN_MB30_ID0)
+#define bfin_write_CAN_MB30_ID0(val)         bfin_write16(CAN_MB30_ID0,val)
+#define bfin_read_CAN_MB30_TIMESTAMP()       bfin_read16(CAN_MB30_TIMESTAMP)
+#define bfin_write_CAN_MB30_TIMESTAMP(val)   bfin_write16(CAN_MB30_TIMESTAMP,val)
+#define bfin_read_CAN_MB30_LENGTH()          bfin_read16(CAN_MB30_LENGTH)
+#define bfin_write_CAN_MB30_LENGTH(val)      bfin_write16(CAN_MB30_LENGTH,val)
+#define bfin_read_CAN_MB30_DATA3()           bfin_read16(CAN_MB30_DATA3)
+#define bfin_write_CAN_MB30_DATA3(val)       bfin_write16(CAN_MB30_DATA3,val)
+#define bfin_read_CAN_MB30_DATA2()           bfin_read16(CAN_MB30_DATA2)
+#define bfin_write_CAN_MB30_DATA2(val)       bfin_write16(CAN_MB30_DATA2,val)
+#define bfin_read_CAN_MB30_DATA1()           bfin_read16(CAN_MB30_DATA1)
+#define bfin_write_CAN_MB30_DATA1(val)       bfin_write16(CAN_MB30_DATA1,val)
+#define bfin_read_CAN_MB30_DATA0()           bfin_read16(CAN_MB30_DATA0)
+#define bfin_write_CAN_MB30_DATA0(val)       bfin_write16(CAN_MB30_DATA0,val)
+
+#define bfin_read_CAN_MB31_ID1()             bfin_read16(CAN_MB31_ID1)
+#define bfin_write_CAN_MB31_ID1(val)         bfin_write16(CAN_MB31_ID1,val)
+#define bfin_read_CAN_MB31_ID0()             bfin_read16(CAN_MB31_ID0)
+#define bfin_write_CAN_MB31_ID0(val)         bfin_write16(CAN_MB31_ID0,val)
+#define bfin_read_CAN_MB31_TIMESTAMP()       bfin_read16(CAN_MB31_TIMESTAMP)
+#define bfin_write_CAN_MB31_TIMESTAMP(val)   bfin_write16(CAN_MB31_TIMESTAMP,val)
+#define bfin_read_CAN_MB31_LENGTH()          bfin_read16(CAN_MB31_LENGTH)
+#define bfin_write_CAN_MB31_LENGTH(val)      bfin_write16(CAN_MB31_LENGTH,val)
+#define bfin_read_CAN_MB31_DATA3()           bfin_read16(CAN_MB31_DATA3)
+#define bfin_write_CAN_MB31_DATA3(val)       bfin_write16(CAN_MB31_DATA3,val)
+#define bfin_read_CAN_MB31_DATA2()           bfin_read16(CAN_MB31_DATA2)
+#define bfin_write_CAN_MB31_DATA2(val)       bfin_write16(CAN_MB31_DATA2,val)
+#define bfin_read_CAN_MB31_DATA1()           bfin_read16(CAN_MB31_DATA1)
+#define bfin_write_CAN_MB31_DATA1(val)       bfin_write16(CAN_MB31_DATA1,val)
+#define bfin_read_CAN_MB31_DATA0()           bfin_read16(CAN_MB31_DATA0)
+#define bfin_write_CAN_MB31_DATA0(val)       bfin_write16(CAN_MB31_DATA0,val)
+
+/* CAN Mailbox Area Macros		*/
+#define bfin_read_CAN_MB_ID1(x)()            bfin_read16(CAN_MB_ID1(x))
+#define bfin_write_CAN_MB_ID1(x)(val)        bfin_write16(CAN_MB_ID1(x),val)
+#define bfin_read_CAN_MB_ID0(x)()            bfin_read16(CAN_MB_ID0(x))
+#define bfin_write_CAN_MB_ID0(x)(val)        bfin_write16(CAN_MB_ID0(x),val)
+#define bfin_read_CAN_MB_TIMESTAMP(x)()      bfin_read16(CAN_MB_TIMESTAMP(x))
+#define bfin_write_CAN_MB_TIMESTAMP(x)(val)  bfin_write16(CAN_MB_TIMESTAMP(x),val)
+#define bfin_read_CAN_MB_LENGTH(x)()         bfin_read16(CAN_MB_LENGTH(x))
+#define bfin_write_CAN_MB_LENGTH(x)(val)     bfin_write16(CAN_MB_LENGTH(x),val)
+#define bfin_read_CAN_MB_DATA3(x)()          bfin_read16(CAN_MB_DATA3(x))
+#define bfin_write_CAN_MB_DATA3(x)(val)      bfin_write16(CAN_MB_DATA3(x),val)
+#define bfin_read_CAN_MB_DATA2(x)()          bfin_read16(CAN_MB_DATA2(x))
+#define bfin_write_CAN_MB_DATA2(x)(val)      bfin_write16(CAN_MB_DATA2(x),val)
+#define bfin_read_CAN_MB_DATA1(x)()          bfin_read16(CAN_MB_DATA1(x))
+#define bfin_write_CAN_MB_DATA1(x)(val)      bfin_write16(CAN_MB_DATA1(x),val)
+#define bfin_read_CAN_MB_DATA0(x)()          bfin_read16(CAN_MB_DATA0(x))
+#define bfin_write_CAN_MB_DATA0(x)(val)      bfin_write16(CAN_MB_DATA0(x),val)
+
+/* Pin Control Registers	(0xFFC03200 - 0xFFC032FF)								*/
+#define bfin_read_PORTF_FER()                bfin_read16(PORTF_FER)
+#define bfin_write_PORTF_FER(val)            bfin_write16(PORTF_FER,val)
+#define bfin_read_PORTG_FER()                bfin_read16(PORTG_FER)
+#define bfin_write_PORTG_FER(val)            bfin_write16(PORTG_FER,val)
+#define bfin_read_PORTH_FER()                bfin_read16(PORTH_FER)
+#define bfin_write_PORTH_FER(val)            bfin_write16(PORTH_FER,val)
+#define bfin_read_PORT_MUX()                 bfin_read16(BFIN_PORT_MUX)
+#define bfin_write_PORT_MUX(val)             bfin_write16(BFIN_PORT_MUX,val)
+
+/* Handshake MDMA Registers	(0xFFC03300 - 0xFFC033FF)								*/
+#define bfin_read_HMDMA0_CONTROL()           bfin_read16(HMDMA0_CONTROL)
+#define bfin_write_HMDMA0_CONTROL(val)       bfin_write16(HMDMA0_CONTROL,val)
+#define bfin_read_HMDMA0_ECINIT()            bfin_read16(HMDMA0_ECINIT)
+#define bfin_write_HMDMA0_ECINIT(val)        bfin_write16(HMDMA0_ECINIT,val)
+#define bfin_read_HMDMA0_BCINIT()            bfin_read16(HMDMA0_BCINIT)
+#define bfin_write_HMDMA0_BCINIT(val)        bfin_write16(HMDMA0_BCINIT,val)
+#define bfin_read_HMDMA0_ECURGENT()          bfin_read16(HMDMA0_ECURGENT)
+#define bfin_write_HMDMA0_ECURGENT(val)      bfin_write16(HMDMA0_ECURGENT,val)
+#define bfin_read_HMDMA0_ECOVERFLOW()        bfin_read16(HMDMA0_ECOVERFLOW)
+#define bfin_write_HMDMA0_ECOVERFLOW(val)    bfin_write16(HMDMA0_ECOVERFLOW,val)
+#define bfin_read_HMDMA0_ECOUNT()            bfin_read16(HMDMA0_ECOUNT)
+#define bfin_write_HMDMA0_ECOUNT(val)        bfin_write16(HMDMA0_ECOUNT,val)
+#define bfin_read_HMDMA0_BCOUNT()            bfin_read16(HMDMA0_BCOUNT)
+#define bfin_write_HMDMA0_BCOUNT(val)        bfin_write16(HMDMA0_BCOUNT,val)
+
+#define bfin_read_HMDMA1_CONTROL()           bfin_read16(HMDMA1_CONTROL)
+#define bfin_write_HMDMA1_CONTROL(val)       bfin_write16(HMDMA1_CONTROL,val)
+#define bfin_read_HMDMA1_ECINIT()            bfin_read16(HMDMA1_ECINIT)
+#define bfin_write_HMDMA1_ECINIT(val)        bfin_write16(HMDMA1_ECINIT,val)
+#define bfin_read_HMDMA1_BCINIT()            bfin_read16(HMDMA1_BCINIT)
+#define bfin_write_HMDMA1_BCINIT(val)        bfin_write16(HMDMA1_BCINIT,val)
+#define bfin_read_HMDMA1_ECURGENT()          bfin_read16(HMDMA1_ECURGENT)
+#define bfin_write_HMDMA1_ECURGENT(val)      bfin_write16(HMDMA1_ECURGENT,val)
+#define bfin_read_HMDMA1_ECOVERFLOW()        bfin_read16(HMDMA1_ECOVERFLOW)
+#define bfin_write_HMDMA1_ECOVERFLOW(val)    bfin_write16(HMDMA1_ECOVERFLOW,val)
+#define bfin_read_HMDMA1_ECOUNT()            bfin_read16(HMDMA1_ECOUNT)
+#define bfin_write_HMDMA1_ECOUNT(val)        bfin_write16(HMDMA1_ECOUNT,val)
+#define bfin_read_HMDMA1_BCOUNT()            bfin_read16(HMDMA1_BCOUNT)
+#define bfin_write_HMDMA1_BCOUNT(val)        bfin_write16(HMDMA1_BCOUNT,val)
+
+#endif				/* _CDEF_BF534_H */
diff --git a/include/asm-blackfin/mach-bf537/cdefBF537.h b/include/asm-blackfin/mach-bf537/cdefBF537.h
new file mode 100644
index 0000000..932a1b6
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/cdefBF537.h
@@ -0,0 +1,209 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/cdefBF537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *	System MMR Register Map
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF537_H
+#define _CDEF_BF537_H
+
+/* Include MMRs Common to BF534 								*/
+#include "cdefBF534.h"
+
+/* Include all Core registers and bit definitions 									*/
+#include "defBF537.h"
+
+/* Include Macro "Defines" For EMAC (Unique to BF536/BF537		*/
+/* 10/100 Ethernet Controller	(0xFFC03000 - 0xFFC031FF) 						*/
+#define	pEMAC_OPMODE		((volatile unsigned long  *)EMAC_OPMODE)
+#define bfin_read_EMAC_OPMODE()              bfin_read32(EMAC_OPMODE)
+#define bfin_write_EMAC_OPMODE(val)          bfin_write32(EMAC_OPMODE,val)
+#define bfin_read_EMAC_ADDRLO()              bfin_read32(EMAC_ADDRLO)
+#define bfin_write_EMAC_ADDRLO(val)          bfin_write32(EMAC_ADDRLO,val)
+#define bfin_read_EMAC_ADDRHI()              bfin_read32(EMAC_ADDRHI)
+#define bfin_write_EMAC_ADDRHI(val)          bfin_write32(EMAC_ADDRHI,val)
+#define bfin_read_EMAC_HASHLO()              bfin_read32(EMAC_HASHLO)
+#define bfin_write_EMAC_HASHLO(val)          bfin_write32(EMAC_HASHLO,val)
+#define bfin_read_EMAC_HASHHI()              bfin_read32(EMAC_HASHHI)
+#define bfin_write_EMAC_HASHHI(val)          bfin_write32(EMAC_HASHHI,val)
+#define bfin_read_EMAC_STAADD()              bfin_read32(EMAC_STAADD)
+#define bfin_write_EMAC_STAADD(val)          bfin_write32(EMAC_STAADD,val)
+#define bfin_read_EMAC_STADAT()              bfin_read32(EMAC_STADAT)
+#define bfin_write_EMAC_STADAT(val)          bfin_write32(EMAC_STADAT,val)
+#define bfin_read_EMAC_FLC()                 bfin_read32(EMAC_FLC)
+#define bfin_write_EMAC_FLC(val)             bfin_write32(EMAC_FLC,val)
+#define bfin_read_EMAC_VLAN1()               bfin_read32(EMAC_VLAN1)
+#define bfin_write_EMAC_VLAN1(val)           bfin_write32(EMAC_VLAN1,val)
+#define bfin_read_EMAC_VLAN2()               bfin_read32(EMAC_VLAN2)
+#define bfin_write_EMAC_VLAN2(val)           bfin_write32(EMAC_VLAN2,val)
+#define bfin_read_EMAC_WKUP_CTL()            bfin_read32(EMAC_WKUP_CTL)
+#define bfin_write_EMAC_WKUP_CTL(val)        bfin_write32(EMAC_WKUP_CTL,val)
+#define bfin_read_EMAC_WKUP_FFMSK0()         bfin_read32(EMAC_WKUP_FFMSK0)
+#define bfin_write_EMAC_WKUP_FFMSK0(val)     bfin_write32(EMAC_WKUP_FFMSK0,val)
+#define bfin_read_EMAC_WKUP_FFMSK1()         bfin_read32(EMAC_WKUP_FFMSK1)
+#define bfin_write_EMAC_WKUP_FFMSK1(val)     bfin_write32(EMAC_WKUP_FFMSK1,val)
+#define bfin_read_EMAC_WKUP_FFMSK2()         bfin_read32(EMAC_WKUP_FFMSK2)
+#define bfin_write_EMAC_WKUP_FFMSK2(val)     bfin_write32(EMAC_WKUP_FFMSK2,val)
+#define bfin_read_EMAC_WKUP_FFMSK3()         bfin_read32(EMAC_WKUP_FFMSK3)
+#define bfin_write_EMAC_WKUP_FFMSK3(val)     bfin_write32(EMAC_WKUP_FFMSK3,val)
+#define bfin_read_EMAC_WKUP_FFCMD()          bfin_read32(EMAC_WKUP_FFCMD)
+#define bfin_write_EMAC_WKUP_FFCMD(val)      bfin_write32(EMAC_WKUP_FFCMD,val)
+#define bfin_read_EMAC_WKUP_FFOFF()          bfin_read32(EMAC_WKUP_FFOFF)
+#define bfin_write_EMAC_WKUP_FFOFF(val)      bfin_write32(EMAC_WKUP_FFOFF,val)
+#define bfin_read_EMAC_WKUP_FFCRC0()         bfin_read32(EMAC_WKUP_FFCRC0)
+#define bfin_write_EMAC_WKUP_FFCRC0(val)     bfin_write32(EMAC_WKUP_FFCRC0,val)
+#define bfin_read_EMAC_WKUP_FFCRC1()         bfin_read32(EMAC_WKUP_FFCRC1)
+#define bfin_write_EMAC_WKUP_FFCRC1(val)     bfin_write32(EMAC_WKUP_FFCRC1,val)
+
+#define	pEMAC_SYSCTL		((volatile unsigned long  *)EMAC_SYSCTL)
+#define bfin_read_EMAC_SYSCTL()              bfin_read32(EMAC_SYSCTL)
+#define bfin_write_EMAC_SYSCTL(val)          bfin_write32(EMAC_SYSCTL,val)
+#define bfin_read_EMAC_SYSTAT()              bfin_read32(EMAC_SYSTAT)
+#define bfin_write_EMAC_SYSTAT(val)          bfin_write32(EMAC_SYSTAT,val)
+#define bfin_read_EMAC_RX_STAT()             bfin_read32(EMAC_RX_STAT)
+#define bfin_write_EMAC_RX_STAT(val)         bfin_write32(EMAC_RX_STAT,val)
+#define bfin_read_EMAC_RX_STKY()             bfin_read32(EMAC_RX_STKY)
+#define bfin_write_EMAC_RX_STKY(val)         bfin_write32(EMAC_RX_STKY,val)
+#define bfin_read_EMAC_RX_IRQE()             bfin_read32(EMAC_RX_IRQE)
+#define bfin_write_EMAC_RX_IRQE(val)         bfin_write32(EMAC_RX_IRQE,val)
+#define bfin_read_EMAC_TX_STAT()             bfin_read32(EMAC_TX_STAT)
+#define bfin_write_EMAC_TX_STAT(val)         bfin_write32(EMAC_TX_STAT,val)
+#define bfin_read_EMAC_TX_STKY()             bfin_read32(EMAC_TX_STKY)
+#define bfin_write_EMAC_TX_STKY(val)         bfin_write32(EMAC_TX_STKY,val)
+#define bfin_read_EMAC_TX_IRQE()             bfin_read32(EMAC_TX_IRQE)
+#define bfin_write_EMAC_TX_IRQE(val)         bfin_write32(EMAC_TX_IRQE,val)
+
+#define bfin_read_EMAC_MMC_CTL()             bfin_read32(EMAC_MMC_CTL)
+#define bfin_write_EMAC_MMC_CTL(val)         bfin_write32(EMAC_MMC_CTL,val)
+#define bfin_read_EMAC_MMC_RIRQS()           bfin_read32(EMAC_MMC_RIRQS)
+#define bfin_write_EMAC_MMC_RIRQS(val)       bfin_write32(EMAC_MMC_RIRQS,val)
+#define bfin_read_EMAC_MMC_RIRQE()           bfin_read32(EMAC_MMC_RIRQE)
+#define bfin_write_EMAC_MMC_RIRQE(val)       bfin_write32(EMAC_MMC_RIRQE,val)
+#define bfin_read_EMAC_MMC_TIRQS()           bfin_read32(EMAC_MMC_TIRQS)
+#define bfin_write_EMAC_MMC_TIRQS(val)       bfin_write32(EMAC_MMC_TIRQS,val)
+#define bfin_read_EMAC_MMC_TIRQE()           bfin_read32(EMAC_MMC_TIRQE)
+#define bfin_write_EMAC_MMC_TIRQE(val)       bfin_write32(EMAC_MMC_TIRQE,val)
+
+#define bfin_read_EMAC_RXC_OK()              bfin_read32(EMAC_RXC_OK)
+#define bfin_write_EMAC_RXC_OK(val)          bfin_write32(EMAC_RXC_OK,val)
+#define bfin_read_EMAC_RXC_FCS()             bfin_read32(EMAC_RXC_FCS)
+#define bfin_write_EMAC_RXC_FCS(val)         bfin_write32(EMAC_RXC_FCS,val)
+#define bfin_read_EMAC_RXC_ALIGN()           bfin_read32(EMAC_RXC_ALIGN)
+#define bfin_write_EMAC_RXC_ALIGN(val)       bfin_write32(EMAC_RXC_ALIGN,val)
+#define bfin_read_EMAC_RXC_OCTET()           bfin_read32(EMAC_RXC_OCTET)
+#define bfin_write_EMAC_RXC_OCTET(val)       bfin_write32(EMAC_RXC_OCTET,val)
+#define bfin_read_EMAC_RXC_DMAOVF()          bfin_read32(EMAC_RXC_DMAOVF)
+#define bfin_write_EMAC_RXC_DMAOVF(val)      bfin_write32(EMAC_RXC_DMAOVF,val)
+#define bfin_read_EMAC_RXC_UNICST()          bfin_read32(EMAC_RXC_UNICST)
+#define bfin_write_EMAC_RXC_UNICST(val)      bfin_write32(EMAC_RXC_UNICST,val)
+#define bfin_read_EMAC_RXC_MULTI()           bfin_read32(EMAC_RXC_MULTI)
+#define bfin_write_EMAC_RXC_MULTI(val)       bfin_write32(EMAC_RXC_MULTI,val)
+#define bfin_read_EMAC_RXC_BROAD()           bfin_read32(EMAC_RXC_BROAD)
+#define bfin_write_EMAC_RXC_BROAD(val)       bfin_write32(EMAC_RXC_BROAD,val)
+#define bfin_read_EMAC_RXC_LNERRI()          bfin_read32(EMAC_RXC_LNERRI)
+#define bfin_write_EMAC_RXC_LNERRI(val)      bfin_write32(EMAC_RXC_LNERRI,val)
+#define bfin_read_EMAC_RXC_LNERRO()          bfin_read32(EMAC_RXC_LNERRO)
+#define bfin_write_EMAC_RXC_LNERRO(val)      bfin_write32(EMAC_RXC_LNERRO,val)
+#define bfin_read_EMAC_RXC_LONG()            bfin_read32(EMAC_RXC_LONG)
+#define bfin_write_EMAC_RXC_LONG(val)        bfin_write32(EMAC_RXC_LONG,val)
+#define bfin_read_EMAC_RXC_MACCTL()          bfin_read32(EMAC_RXC_MACCTL)
+#define bfin_write_EMAC_RXC_MACCTL(val)      bfin_write32(EMAC_RXC_MACCTL,val)
+#define bfin_read_EMAC_RXC_OPCODE()          bfin_read32(EMAC_RXC_OPCODE)
+#define bfin_write_EMAC_RXC_OPCODE(val)      bfin_write32(EMAC_RXC_OPCODE,val)
+#define bfin_read_EMAC_RXC_PAUSE()           bfin_read32(EMAC_RXC_PAUSE)
+#define bfin_write_EMAC_RXC_PAUSE(val)       bfin_write32(EMAC_RXC_PAUSE,val)
+#define bfin_read_EMAC_RXC_ALLFRM()          bfin_read32(EMAC_RXC_ALLFRM)
+#define bfin_write_EMAC_RXC_ALLFRM(val)      bfin_write32(EMAC_RXC_ALLFRM,val)
+#define bfin_read_EMAC_RXC_ALLOCT()          bfin_read32(EMAC_RXC_ALLOCT)
+#define bfin_write_EMAC_RXC_ALLOCT(val)      bfin_write32(EMAC_RXC_ALLOCT,val)
+#define bfin_read_EMAC_RXC_TYPED()           bfin_read32(EMAC_RXC_TYPED)
+#define bfin_write_EMAC_RXC_TYPED(val)       bfin_write32(EMAC_RXC_TYPED,val)
+#define bfin_read_EMAC_RXC_SHORT()           bfin_read32(EMAC_RXC_SHORT)
+#define bfin_write_EMAC_RXC_SHORT(val)       bfin_write32(EMAC_RXC_SHORT,val)
+#define bfin_read_EMAC_RXC_EQ64()            bfin_read32(EMAC_RXC_EQ64)
+#define bfin_write_EMAC_RXC_EQ64(val)        bfin_write32(EMAC_RXC_EQ64,val)
+#define	pEMAC_RXC_LT128		((volatile unsigned long  *)EMAC_RXC_LT128)
+#define bfin_read_EMAC_RXC_LT128()           bfin_read32(EMAC_RXC_LT128)
+#define bfin_write_EMAC_RXC_LT128(val)       bfin_write32(EMAC_RXC_LT128,val)
+#define bfin_read_EMAC_RXC_LT256()           bfin_read32(EMAC_RXC_LT256)
+#define bfin_write_EMAC_RXC_LT256(val)       bfin_write32(EMAC_RXC_LT256,val)
+#define bfin_read_EMAC_RXC_LT512()           bfin_read32(EMAC_RXC_LT512)
+#define bfin_write_EMAC_RXC_LT512(val)       bfin_write32(EMAC_RXC_LT512,val)
+#define bfin_read_EMAC_RXC_LT1024()          bfin_read32(EMAC_RXC_LT1024)
+#define bfin_write_EMAC_RXC_LT1024(val)      bfin_write32(EMAC_RXC_LT1024,val)
+#define bfin_read_EMAC_RXC_GE1024()          bfin_read32(EMAC_RXC_GE1024)
+#define bfin_write_EMAC_RXC_GE1024(val)      bfin_write32(EMAC_RXC_GE1024,val)
+
+#define bfin_read_EMAC_TXC_OK()              bfin_read32(EMAC_TXC_OK)
+#define bfin_write_EMAC_TXC_OK(val)          bfin_write32(EMAC_TXC_OK,val)
+#define bfin_read_EMAC_TXC_1COL()            bfin_read32(EMAC_TXC_1COL)
+#define bfin_write_EMAC_TXC_1COL(val)        bfin_write32(EMAC_TXC_1COL,val)
+#define bfin_read_EMAC_TXC_GT1COL()          bfin_read32(EMAC_TXC_GT1COL)
+#define bfin_write_EMAC_TXC_GT1COL(val)      bfin_write32(EMAC_TXC_GT1COL,val)
+#define bfin_read_EMAC_TXC_OCTET()           bfin_read32(EMAC_TXC_OCTET)
+#define bfin_write_EMAC_TXC_OCTET(val)       bfin_write32(EMAC_TXC_OCTET,val)
+#define bfin_read_EMAC_TXC_DEFER()           bfin_read32(EMAC_TXC_DEFER)
+#define bfin_write_EMAC_TXC_DEFER(val)       bfin_write32(EMAC_TXC_DEFER,val)
+#define bfin_read_EMAC_TXC_LATECL()          bfin_read32(EMAC_TXC_LATECL)
+#define bfin_write_EMAC_TXC_LATECL(val)      bfin_write32(EMAC_TXC_LATECL,val)
+#define bfin_read_EMAC_TXC_XS_COL()          bfin_read32(EMAC_TXC_XS_COL)
+#define bfin_write_EMAC_TXC_XS_COL(val)      bfin_write32(EMAC_TXC_XS_COL,val)
+#define bfin_read_EMAC_TXC_DMAUND()          bfin_read32(EMAC_TXC_DMAUND)
+#define bfin_write_EMAC_TXC_DMAUND(val)      bfin_write32(EMAC_TXC_DMAUND,val)
+#define bfin_read_EMAC_TXC_CRSERR()          bfin_read32(EMAC_TXC_CRSERR)
+#define bfin_write_EMAC_TXC_CRSERR(val)      bfin_write32(EMAC_TXC_CRSERR,val)
+#define bfin_read_EMAC_TXC_UNICST()          bfin_read32(EMAC_TXC_UNICST)
+#define bfin_write_EMAC_TXC_UNICST(val)      bfin_write32(EMAC_TXC_UNICST,val)
+#define bfin_read_EMAC_TXC_MULTI()           bfin_read32(EMAC_TXC_MULTI)
+#define bfin_write_EMAC_TXC_MULTI(val)       bfin_write32(EMAC_TXC_MULTI,val)
+#define bfin_read_EMAC_TXC_BROAD()           bfin_read32(EMAC_TXC_BROAD)
+#define bfin_write_EMAC_TXC_BROAD(val)       bfin_write32(EMAC_TXC_BROAD,val)
+#define bfin_read_EMAC_TXC_XS_DFR()          bfin_read32(EMAC_TXC_XS_DFR)
+#define bfin_write_EMAC_TXC_XS_DFR(val)      bfin_write32(EMAC_TXC_XS_DFR,val)
+#define bfin_read_EMAC_TXC_MACCTL()          bfin_read32(EMAC_TXC_MACCTL)
+#define bfin_write_EMAC_TXC_MACCTL(val)      bfin_write32(EMAC_TXC_MACCTL,val)
+#define bfin_read_EMAC_TXC_ALLFRM()          bfin_read32(EMAC_TXC_ALLFRM)
+#define bfin_write_EMAC_TXC_ALLFRM(val)      bfin_write32(EMAC_TXC_ALLFRM,val)
+#define bfin_read_EMAC_TXC_ALLOCT()          bfin_read32(EMAC_TXC_ALLOCT)
+#define bfin_write_EMAC_TXC_ALLOCT(val)      bfin_write32(EMAC_TXC_ALLOCT,val)
+#define bfin_read_EMAC_TXC_EQ64()            bfin_read32(EMAC_TXC_EQ64)
+#define bfin_write_EMAC_TXC_EQ64(val)        bfin_write32(EMAC_TXC_EQ64,val)
+#define bfin_read_EMAC_TXC_LT128()           bfin_read32(EMAC_TXC_LT128)
+#define bfin_write_EMAC_TXC_LT128(val)       bfin_write32(EMAC_TXC_LT128,val)
+#define bfin_read_EMAC_TXC_LT256()           bfin_read32(EMAC_TXC_LT256)
+#define bfin_write_EMAC_TXC_LT256(val)       bfin_write32(EMAC_TXC_LT256,val)
+#define bfin_read_EMAC_TXC_LT512()           bfin_read32(EMAC_TXC_LT512)
+#define bfin_write_EMAC_TXC_LT512(val)       bfin_write32(EMAC_TXC_LT512,val)
+#define bfin_read_EMAC_TXC_LT1024()          bfin_read32(EMAC_TXC_LT1024)
+#define bfin_write_EMAC_TXC_LT1024(val)      bfin_write32(EMAC_TXC_LT1024,val)
+#define bfin_read_EMAC_TXC_GE1024()          bfin_read32(EMAC_TXC_GE1024)
+#define bfin_write_EMAC_TXC_GE1024(val)      bfin_write32(EMAC_TXC_GE1024,val)
+#define bfin_read_EMAC_TXC_ABORT()           bfin_read32(EMAC_TXC_ABORT)
+#define bfin_write_EMAC_TXC_ABORT(val)       bfin_write32(EMAC_TXC_ABORT,val)
+
+#endif				/* _CDEF_BF537_H */
diff --git a/include/asm-blackfin/mach-bf537/defBF534.h b/include/asm-blackfin/mach-bf537/defBF534.h
new file mode 100644
index 0000000..e605e97
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/defBF534.h
@@ -0,0 +1,2501 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/cdefBF537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DEF_BF534_H
+#define _DEF_BF534_H
+
+/* Include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/************************************************************************************
+** System MMR Register Map
+*************************************************************************************/
+/* Clock and System Control	(0xFFC00000 - 0xFFC000FF)								*/
+#define PLL_CTL				0xFFC00000	/* PLL Control Register                                         */
+#define PLL_DIV				0xFFC00004	/* PLL Divide Register                                          */
+#define VR_CTL				0xFFC00008	/* Voltage Regulator Control Register           */
+#define PLL_STAT			0xFFC0000C	/* PLL Status Register                                          */
+#define PLL_LOCKCNT			0xFFC00010	/* PLL Lock Count Register                                      */
+#define CHIPID				0xFFC00014      /* Chip ID Register                                             */
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF)							*/
+#define SWRST				0xFFC00100	/* Software Reset Register                                      */
+#define SYSCR				0xFFC00104	/* System Configuration Register                        */
+#define SIC_RVECT			0xFFC00108	/* Interrupt Reset Vector Address Register      */
+#define SIC_IMASK			0xFFC0010C	/* Interrupt Mask Register                                      */
+#define SIC_IAR0			0xFFC00110	/* Interrupt Assignment Register 0                      */
+#define SIC_IAR1			0xFFC00114	/* Interrupt Assignment Register 1                      */
+#define SIC_IAR2			0xFFC00118	/* Interrupt Assignment Register 2                      */
+#define SIC_IAR3			0xFFC0011C	/* Interrupt Assignment Register 3                      */
+#define SIC_ISR				0xFFC00120	/* Interrupt Status Register                            */
+#define SIC_IWR				0xFFC00124	/* Interrupt Wakeup Register                            */
+
+/* Watchdog Timer			(0xFFC00200 - 0xFFC002FF)								*/
+#define WDOG_CTL			0xFFC00200	/* Watchdog Control Register                            */
+#define WDOG_CNT			0xFFC00204	/* Watchdog Count Register                                      */
+#define WDOG_STAT			0xFFC00208	/* Watchdog Status Register                                     */
+
+/* Real Time Clock		(0xFFC00300 - 0xFFC003FF)									*/
+#define RTC_STAT			0xFFC00300	/* RTC Status Register                                          */
+#define RTC_ICTL			0xFFC00304	/* RTC Interrupt Control Register                       */
+#define RTC_ISTAT			0xFFC00308	/* RTC Interrupt Status Register                        */
+#define RTC_SWCNT			0xFFC0030C	/* RTC Stopwatch Count Register                         */
+#define RTC_ALARM			0xFFC00310	/* RTC Alarm Time Register                                      */
+#define RTC_FAST			0xFFC00314	/* RTC Prescaler Enable Register                        */
+#define RTC_PREN			0xFFC00314	/* RTC Prescaler Enable Alternate Macro         */
+
+/* UART0 Controller		(0xFFC00400 - 0xFFC004FF)									*/
+#define UART0_THR			0xFFC00400	/* Transmit Holding register                            */
+#define UART0_RBR			0xFFC00400	/* Receive Buffer register                                      */
+#define UART0_DLL			0xFFC00400	/* Divisor Latch (Low-Byte)                                     */
+#define UART0_IER			0xFFC00404	/* Interrupt Enable Register                            */
+#define UART0_DLH			0xFFC00404	/* Divisor Latch (High-Byte)                            */
+#define UART0_IIR			0xFFC00408	/* Interrupt Identification Register            */
+#define UART0_LCR			0xFFC0040C	/* Line Control Register                                        */
+#define UART0_MCR			0xFFC00410	/* Modem Control Register                                       */
+#define UART0_LSR			0xFFC00414	/* Line Status Register                                         */
+#define UART0_MSR			0xFFC00418	/* Modem Status Register                                        */
+#define UART0_SCR			0xFFC0041C	/* SCR Scratch Register                                         */
+#define UART0_GCTL			0xFFC00424	/* Global Control Register                                      */
+
+/* SPI Controller			(0xFFC00500 - 0xFFC005FF)								*/
+#define SPI_CTL				0xFFC00500	/* SPI Control Register                                         */
+#define SPI_FLG				0xFFC00504	/* SPI Flag register                                            */
+#define SPI_STAT			0xFFC00508	/* SPI Status register                                          */
+#define SPI_TDBR			0xFFC0050C	/* SPI Transmit Data Buffer Register            */
+#define SPI_RDBR			0xFFC00510	/* SPI Receive Data Buffer Register                     */
+#define SPI_BAUD			0xFFC00514	/* SPI Baud rate Register                                       */
+#define SPI_SHADOW			0xFFC00518	/* SPI_RDBR Shadow Register                                     */
+
+/* TIMER0-7 Registers		(0xFFC00600 - 0xFFC006FF)								*/
+#define TIMER0_CONFIG		0xFFC00600	/* Timer 0 Configuration Register                       */
+#define TIMER0_COUNTER		0xFFC00604	/* Timer 0 Counter Register                                     */
+#define TIMER0_PERIOD		0xFFC00608	/* Timer 0 Period Register                                      */
+#define TIMER0_WIDTH		0xFFC0060C	/* Timer 0 Width Register                                       */
+
+#define TIMER1_CONFIG		0xFFC00610	/* Timer 1 Configuration Register                       */
+#define TIMER1_COUNTER		0xFFC00614	/* Timer 1 Counter Register                             */
+#define TIMER1_PERIOD		0xFFC00618	/* Timer 1 Period Register                              */
+#define TIMER1_WIDTH		0xFFC0061C	/* Timer 1 Width Register                               */
+
+#define TIMER2_CONFIG		0xFFC00620	/* Timer 2 Configuration Register                       */
+#define TIMER2_COUNTER		0xFFC00624	/* Timer 2 Counter Register                             */
+#define TIMER2_PERIOD		0xFFC00628	/* Timer 2 Period Register                              */
+#define TIMER2_WIDTH		0xFFC0062C	/* Timer 2 Width Register                               */
+
+#define TIMER3_CONFIG		0xFFC00630	/* Timer 3 Configuration Register                       */
+#define TIMER3_COUNTER		0xFFC00634	/* Timer 3 Counter Register                                     */
+#define TIMER3_PERIOD		0xFFC00638	/* Timer 3 Period Register                                      */
+#define TIMER3_WIDTH		0xFFC0063C	/* Timer 3 Width Register                                       */
+
+#define TIMER4_CONFIG		0xFFC00640	/* Timer 4 Configuration Register                       */
+#define TIMER4_COUNTER		0xFFC00644	/* Timer 4 Counter Register                             */
+#define TIMER4_PERIOD		0xFFC00648	/* Timer 4 Period Register                              */
+#define TIMER4_WIDTH		0xFFC0064C	/* Timer 4 Width Register                               */
+
+#define TIMER5_CONFIG		0xFFC00650	/* Timer 5 Configuration Register                       */
+#define TIMER5_COUNTER		0xFFC00654	/* Timer 5 Counter Register                             */
+#define TIMER5_PERIOD		0xFFC00658	/* Timer 5 Period Register                              */
+#define TIMER5_WIDTH		0xFFC0065C	/* Timer 5 Width Register                               */
+
+#define TIMER6_CONFIG		0xFFC00660	/* Timer 6 Configuration Register                       */
+#define TIMER6_COUNTER		0xFFC00664	/* Timer 6 Counter Register                             */
+#define TIMER6_PERIOD		0xFFC00668	/* Timer 6 Period Register                              */
+#define TIMER6_WIDTH		0xFFC0066C	/* Timer 6 Width Register                               */
+
+#define TIMER7_CONFIG		0xFFC00670	/* Timer 7 Configuration Register                       */
+#define TIMER7_COUNTER		0xFFC00674	/* Timer 7 Counter Register                             */
+#define TIMER7_PERIOD		0xFFC00678	/* Timer 7 Period Register                              */
+#define TIMER7_WIDTH		0xFFC0067C	/* Timer 7 Width Register                               */
+
+#define TIMER_ENABLE		0xFFC00680	/* Timer Enable Register                                        */
+#define TIMER_DISABLE		0xFFC00684	/* Timer Disable Register                                       */
+#define TIMER_STATUS		0xFFC00688	/* Timer Status Register                                        */
+
+/* General Purpose I/O Port F (0xFFC00700 - 0xFFC007FF)												*/
+#define PORTFIO					0xFFC00700	/* Port F I/O Pin State Specify Register                                */
+#define PORTFIO_CLEAR			0xFFC00704	/* Port F I/O Peripheral Interrupt Clear Register               */
+#define PORTFIO_SET				0xFFC00708	/* Port F I/O Peripheral Interrupt Set Register                 */
+#define PORTFIO_TOGGLE			0xFFC0070C	/* Port F I/O Pin State Toggle Register                                 */
+#define PORTFIO_MASKA			0xFFC00710	/* Port F I/O Mask State Specify Interrupt A Register   */
+#define PORTFIO_MASKA_CLEAR		0xFFC00714	/* Port F I/O Mask Disable Interrupt A Register                 */
+#define PORTFIO_MASKA_SET		0xFFC00718	/* Port F I/O Mask Enable Interrupt A Register                  */
+#define PORTFIO_MASKA_TOGGLE	0xFFC0071C	/* Port F I/O Mask Toggle Enable Interrupt A Register   */
+#define PORTFIO_MASKB			0xFFC00720	/* Port F I/O Mask State Specify Interrupt B Register   */
+#define PORTFIO_MASKB_CLEAR		0xFFC00724	/* Port F I/O Mask Disable Interrupt B Register                 */
+#define PORTFIO_MASKB_SET		0xFFC00728	/* Port F I/O Mask Enable Interrupt B Register                  */
+#define PORTFIO_MASKB_TOGGLE	0xFFC0072C	/* Port F I/O Mask Toggle Enable Interrupt B Register   */
+#define PORTFIO_DIR				0xFFC00730	/* Port F I/O Direction Register                                                */
+#define PORTFIO_POLAR			0xFFC00734	/* Port F I/O Source Polarity Register                                  */
+#define PORTFIO_EDGE			0xFFC00738	/* Port F I/O Source Sensitivity Register                               */
+#define PORTFIO_BOTH			0xFFC0073C	/* Port F I/O Set on BOTH Edges Register                                */
+#define PORTFIO_INEN			0xFFC00740	/* Port F I/O Input Enable Register                                     */
+
+/* SPORT0 Controller		(0xFFC00800 - 0xFFC008FF)										*/
+#define SPORT0_TCR1			0xFFC00800	/* SPORT0 Transmit Configuration 1 Register                     */
+#define SPORT0_TCR2			0xFFC00804	/* SPORT0 Transmit Configuration 2 Register                     */
+#define SPORT0_TCLKDIV		0xFFC00808	/* SPORT0 Transmit Clock Divider                                        */
+#define SPORT0_TFSDIV		0xFFC0080C	/* SPORT0 Transmit Frame Sync Divider                           */
+#define SPORT0_TX			0xFFC00810	/* SPORT0 TX Data Register                                                      */
+#define SPORT0_RX			0xFFC00818	/* SPORT0 RX Data Register                                                      */
+#define SPORT0_RCR1			0xFFC00820	/* SPORT0 Transmit Configuration 1 Register                     */
+#define SPORT0_RCR2			0xFFC00824	/* SPORT0 Transmit Configuration 2 Register                     */
+#define SPORT0_RCLKDIV		0xFFC00828	/* SPORT0 Receive Clock Divider                                         */
+#define SPORT0_RFSDIV		0xFFC0082C	/* SPORT0 Receive Frame Sync Divider                            */
+#define SPORT0_STAT			0xFFC00830	/* SPORT0 Status Register                                                       */
+#define SPORT0_CHNL			0xFFC00834	/* SPORT0 Current Channel Register                                      */
+#define SPORT0_MCMC1		0xFFC00838	/* SPORT0 Multi-Channel Configuration Register 1        */
+#define SPORT0_MCMC2		0xFFC0083C	/* SPORT0 Multi-Channel Configuration Register 2        */
+#define SPORT0_MTCS0		0xFFC00840	/* SPORT0 Multi-Channel Transmit Select Register 0      */
+#define SPORT0_MTCS1		0xFFC00844	/* SPORT0 Multi-Channel Transmit Select Register 1      */
+#define SPORT0_MTCS2		0xFFC00848	/* SPORT0 Multi-Channel Transmit Select Register 2      */
+#define SPORT0_MTCS3		0xFFC0084C	/* SPORT0 Multi-Channel Transmit Select Register 3      */
+#define SPORT0_MRCS0		0xFFC00850	/* SPORT0 Multi-Channel Receive Select Register 0       */
+#define SPORT0_MRCS1		0xFFC00854	/* SPORT0 Multi-Channel Receive Select Register 1       */
+#define SPORT0_MRCS2		0xFFC00858	/* SPORT0 Multi-Channel Receive Select Register 2       */
+#define SPORT0_MRCS3		0xFFC0085C	/* SPORT0 Multi-Channel Receive Select Register 3       */
+
+/* SPORT1 Controller		(0xFFC00900 - 0xFFC009FF)										*/
+#define SPORT1_TCR1			0xFFC00900	/* SPORT1 Transmit Configuration 1 Register                     */
+#define SPORT1_TCR2			0xFFC00904	/* SPORT1 Transmit Configuration 2 Register                     */
+#define SPORT1_TCLKDIV		0xFFC00908	/* SPORT1 Transmit Clock Divider                                        */
+#define SPORT1_TFSDIV		0xFFC0090C	/* SPORT1 Transmit Frame Sync Divider                           */
+#define SPORT1_TX			0xFFC00910	/* SPORT1 TX Data Register                                                      */
+#define SPORT1_RX			0xFFC00918	/* SPORT1 RX Data Register                                                      */
+#define SPORT1_RCR1			0xFFC00920	/* SPORT1 Transmit Configuration 1 Register                     */
+#define SPORT1_RCR2			0xFFC00924	/* SPORT1 Transmit Configuration 2 Register                     */
+#define SPORT1_RCLKDIV		0xFFC00928	/* SPORT1 Receive Clock Divider                                         */
+#define SPORT1_RFSDIV		0xFFC0092C	/* SPORT1 Receive Frame Sync Divider                            */
+#define SPORT1_STAT			0xFFC00930	/* SPORT1 Status Register                                                       */
+#define SPORT1_CHNL			0xFFC00934	/* SPORT1 Current Channel Register                                      */
+#define SPORT1_MCMC1		0xFFC00938	/* SPORT1 Multi-Channel Configuration Register 1        */
+#define SPORT1_MCMC2		0xFFC0093C	/* SPORT1 Multi-Channel Configuration Register 2        */
+#define SPORT1_MTCS0		0xFFC00940	/* SPORT1 Multi-Channel Transmit Select Register 0      */
+#define SPORT1_MTCS1		0xFFC00944	/* SPORT1 Multi-Channel Transmit Select Register 1      */
+#define SPORT1_MTCS2		0xFFC00948	/* SPORT1 Multi-Channel Transmit Select Register 2      */
+#define SPORT1_MTCS3		0xFFC0094C	/* SPORT1 Multi-Channel Transmit Select Register 3      */
+#define SPORT1_MRCS0		0xFFC00950	/* SPORT1 Multi-Channel Receive Select Register 0       */
+#define SPORT1_MRCS1		0xFFC00954	/* SPORT1 Multi-Channel Receive Select Register 1       */
+#define SPORT1_MRCS2		0xFFC00958	/* SPORT1 Multi-Channel Receive Select Register 2       */
+#define SPORT1_MRCS3		0xFFC0095C	/* SPORT1 Multi-Channel Receive Select Register 3       */
+
+/* External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF)								*/
+#define EBIU_AMGCTL			0xFFC00A00	/* Asynchronous Memory Global Control Register  */
+#define EBIU_AMBCTL0		0xFFC00A04	/* Asynchronous Memory Bank Control Register 0  */
+#define EBIU_AMBCTL1		0xFFC00A08	/* Asynchronous Memory Bank Control Register 1  */
+#define EBIU_SDGCTL			0xFFC00A10	/* SDRAM Global Control Register                                */
+#define EBIU_SDBCTL			0xFFC00A14	/* SDRAM Bank Control Register                                  */
+#define EBIU_SDRRC			0xFFC00A18	/* SDRAM Refresh Rate Control Register                  */
+#define EBIU_SDSTAT			0xFFC00A1C	/* SDRAM Status Register                                                */
+
+/* DMA Traffic Control Registers													*/
+#define DMA_TCPER			0xFFC00B0C	/* Traffic Control Periods Register                     */
+#define DMA_TCCNT			0xFFC00B10	/* Traffic Control Current Counts Register      */
+
+/* DMA Controller (0xFFC00C00 - 0xFFC00FFF)															*/
+#define DMA0_NEXT_DESC_PTR		0xFFC00C00	/* DMA Channel 0 Next Descriptor Pointer Register               */
+#define DMA0_START_ADDR			0xFFC00C04	/* DMA Channel 0 Start Address Register                                 */
+#define DMA0_CONFIG				0xFFC00C08	/* DMA Channel 0 Configuration Register                                 */
+#define DMA0_X_COUNT			0xFFC00C10	/* DMA Channel 0 X Count Register                                               */
+#define DMA0_X_MODIFY			0xFFC00C14	/* DMA Channel 0 X Modify Register                                              */
+#define DMA0_Y_COUNT			0xFFC00C18	/* DMA Channel 0 Y Count Register                                               */
+#define DMA0_Y_MODIFY			0xFFC00C1C	/* DMA Channel 0 Y Modify Register                                              */
+#define DMA0_CURR_DESC_PTR		0xFFC00C20	/* DMA Channel 0 Current Descriptor Pointer Register    */
+#define DMA0_CURR_ADDR			0xFFC00C24	/* DMA Channel 0 Current Address Register                               */
+#define DMA0_IRQ_STATUS			0xFFC00C28	/* DMA Channel 0 Interrupt/Status Register                              */
+#define DMA0_PERIPHERAL_MAP		0xFFC00C2C	/* DMA Channel 0 Peripheral Map Register                                */
+#define DMA0_CURR_X_COUNT		0xFFC00C30	/* DMA Channel 0 Current X Count Register                               */
+#define DMA0_CURR_Y_COUNT		0xFFC00C38	/* DMA Channel 0 Current Y Count Register                               */
+
+#define DMA1_NEXT_DESC_PTR		0xFFC00C40	/* DMA Channel 1 Next Descriptor Pointer Register               */
+#define DMA1_START_ADDR			0xFFC00C44	/* DMA Channel 1 Start Address Register                                 */
+#define DMA1_CONFIG				0xFFC00C48	/* DMA Channel 1 Configuration Register                                 */
+#define DMA1_X_COUNT			0xFFC00C50	/* DMA Channel 1 X Count Register                                               */
+#define DMA1_X_MODIFY			0xFFC00C54	/* DMA Channel 1 X Modify Register                                              */
+#define DMA1_Y_COUNT			0xFFC00C58	/* DMA Channel 1 Y Count Register                                               */
+#define DMA1_Y_MODIFY			0xFFC00C5C	/* DMA Channel 1 Y Modify Register                                              */
+#define DMA1_CURR_DESC_PTR		0xFFC00C60	/* DMA Channel 1 Current Descriptor Pointer Register    */
+#define DMA1_CURR_ADDR			0xFFC00C64	/* DMA Channel 1 Current Address Register                               */
+#define DMA1_IRQ_STATUS			0xFFC00C68	/* DMA Channel 1 Interrupt/Status Register                              */
+#define DMA1_PERIPHERAL_MAP		0xFFC00C6C	/* DMA Channel 1 Peripheral Map Register                                */
+#define DMA1_CURR_X_COUNT		0xFFC00C70	/* DMA Channel 1 Current X Count Register                               */
+#define DMA1_CURR_Y_COUNT		0xFFC00C78	/* DMA Channel 1 Current Y Count Register                               */
+
+#define DMA2_NEXT_DESC_PTR		0xFFC00C80	/* DMA Channel 2 Next Descriptor Pointer Register               */
+#define DMA2_START_ADDR			0xFFC00C84	/* DMA Channel 2 Start Address Register                                 */
+#define DMA2_CONFIG				0xFFC00C88	/* DMA Channel 2 Configuration Register                                 */
+#define DMA2_X_COUNT			0xFFC00C90	/* DMA Channel 2 X Count Register                                               */
+#define DMA2_X_MODIFY			0xFFC00C94	/* DMA Channel 2 X Modify Register                                              */
+#define DMA2_Y_COUNT			0xFFC00C98	/* DMA Channel 2 Y Count Register                                               */
+#define DMA2_Y_MODIFY			0xFFC00C9C	/* DMA Channel 2 Y Modify Register                                              */
+#define DMA2_CURR_DESC_PTR		0xFFC00CA0	/* DMA Channel 2 Current Descriptor Pointer Register    */
+#define DMA2_CURR_ADDR			0xFFC00CA4	/* DMA Channel 2 Current Address Register                               */
+#define DMA2_IRQ_STATUS			0xFFC00CA8	/* DMA Channel 2 Interrupt/Status Register                              */
+#define DMA2_PERIPHERAL_MAP		0xFFC00CAC	/* DMA Channel 2 Peripheral Map Register                                */
+#define DMA2_CURR_X_COUNT		0xFFC00CB0	/* DMA Channel 2 Current X Count Register                               */
+#define DMA2_CURR_Y_COUNT		0xFFC00CB8	/* DMA Channel 2 Current Y Count Register                               */
+
+#define DMA3_NEXT_DESC_PTR		0xFFC00CC0	/* DMA Channel 3 Next Descriptor Pointer Register               */
+#define DMA3_START_ADDR			0xFFC00CC4	/* DMA Channel 3 Start Address Register                                 */
+#define DMA3_CONFIG				0xFFC00CC8	/* DMA Channel 3 Configuration Register                                 */
+#define DMA3_X_COUNT			0xFFC00CD0	/* DMA Channel 3 X Count Register                                               */
+#define DMA3_X_MODIFY			0xFFC00CD4	/* DMA Channel 3 X Modify Register                                              */
+#define DMA3_Y_COUNT			0xFFC00CD8	/* DMA Channel 3 Y Count Register                                               */
+#define DMA3_Y_MODIFY			0xFFC00CDC	/* DMA Channel 3 Y Modify Register                                              */
+#define DMA3_CURR_DESC_PTR		0xFFC00CE0	/* DMA Channel 3 Current Descriptor Pointer Register    */
+#define DMA3_CURR_ADDR			0xFFC00CE4	/* DMA Channel 3 Current Address Register                               */
+#define DMA3_IRQ_STATUS			0xFFC00CE8	/* DMA Channel 3 Interrupt/Status Register                              */
+#define DMA3_PERIPHERAL_MAP		0xFFC00CEC	/* DMA Channel 3 Peripheral Map Register                                */
+#define DMA3_CURR_X_COUNT		0xFFC00CF0	/* DMA Channel 3 Current X Count Register                               */
+#define DMA3_CURR_Y_COUNT		0xFFC00CF8	/* DMA Channel 3 Current Y Count Register                               */
+
+#define DMA4_NEXT_DESC_PTR		0xFFC00D00	/* DMA Channel 4 Next Descriptor Pointer Register               */
+#define DMA4_START_ADDR			0xFFC00D04	/* DMA Channel 4 Start Address Register                                 */
+#define DMA4_CONFIG				0xFFC00D08	/* DMA Channel 4 Configuration Register                                 */
+#define DMA4_X_COUNT			0xFFC00D10	/* DMA Channel 4 X Count Register                                               */
+#define DMA4_X_MODIFY			0xFFC00D14	/* DMA Channel 4 X Modify Register                                              */
+#define DMA4_Y_COUNT			0xFFC00D18	/* DMA Channel 4 Y Count Register                                               */
+#define DMA4_Y_MODIFY			0xFFC00D1C	/* DMA Channel 4 Y Modify Register                                              */
+#define DMA4_CURR_DESC_PTR		0xFFC00D20	/* DMA Channel 4 Current Descriptor Pointer Register    */
+#define DMA4_CURR_ADDR			0xFFC00D24	/* DMA Channel 4 Current Address Register                               */
+#define DMA4_IRQ_STATUS			0xFFC00D28	/* DMA Channel 4 Interrupt/Status Register                              */
+#define DMA4_PERIPHERAL_MAP		0xFFC00D2C	/* DMA Channel 4 Peripheral Map Register                                */
+#define DMA4_CURR_X_COUNT		0xFFC00D30	/* DMA Channel 4 Current X Count Register                               */
+#define DMA4_CURR_Y_COUNT		0xFFC00D38	/* DMA Channel 4 Current Y Count Register                               */
+
+#define DMA5_NEXT_DESC_PTR		0xFFC00D40	/* DMA Channel 5 Next Descriptor Pointer Register               */
+#define DMA5_START_ADDR			0xFFC00D44	/* DMA Channel 5 Start Address Register                                 */
+#define DMA5_CONFIG				0xFFC00D48	/* DMA Channel 5 Configuration Register                                 */
+#define DMA5_X_COUNT			0xFFC00D50	/* DMA Channel 5 X Count Register                                               */
+#define DMA5_X_MODIFY			0xFFC00D54	/* DMA Channel 5 X Modify Register                                              */
+#define DMA5_Y_COUNT			0xFFC00D58	/* DMA Channel 5 Y Count Register                                               */
+#define DMA5_Y_MODIFY			0xFFC00D5C	/* DMA Channel 5 Y Modify Register                                              */
+#define DMA5_CURR_DESC_PTR		0xFFC00D60	/* DMA Channel 5 Current Descriptor Pointer Register    */
+#define DMA5_CURR_ADDR			0xFFC00D64	/* DMA Channel 5 Current Address Register                               */
+#define DMA5_IRQ_STATUS			0xFFC00D68	/* DMA Channel 5 Interrupt/Status Register                              */
+#define DMA5_PERIPHERAL_MAP		0xFFC00D6C	/* DMA Channel 5 Peripheral Map Register                                */
+#define DMA5_CURR_X_COUNT		0xFFC00D70	/* DMA Channel 5 Current X Count Register                               */
+#define DMA5_CURR_Y_COUNT		0xFFC00D78	/* DMA Channel 5 Current Y Count Register                               */
+
+#define DMA6_NEXT_DESC_PTR		0xFFC00D80	/* DMA Channel 6 Next Descriptor Pointer Register               */
+#define DMA6_START_ADDR			0xFFC00D84	/* DMA Channel 6 Start Address Register                                 */
+#define DMA6_CONFIG				0xFFC00D88	/* DMA Channel 6 Configuration Register                                 */
+#define DMA6_X_COUNT			0xFFC00D90	/* DMA Channel 6 X Count Register                                               */
+#define DMA6_X_MODIFY			0xFFC00D94	/* DMA Channel 6 X Modify Register                                              */
+#define DMA6_Y_COUNT			0xFFC00D98	/* DMA Channel 6 Y Count Register                                               */
+#define DMA6_Y_MODIFY			0xFFC00D9C	/* DMA Channel 6 Y Modify Register                                              */
+#define DMA6_CURR_DESC_PTR		0xFFC00DA0	/* DMA Channel 6 Current Descriptor Pointer Register    */
+#define DMA6_CURR_ADDR			0xFFC00DA4	/* DMA Channel 6 Current Address Register                               */
+#define DMA6_IRQ_STATUS			0xFFC00DA8	/* DMA Channel 6 Interrupt/Status Register                              */
+#define DMA6_PERIPHERAL_MAP		0xFFC00DAC	/* DMA Channel 6 Peripheral Map Register                                */
+#define DMA6_CURR_X_COUNT		0xFFC00DB0	/* DMA Channel 6 Current X Count Register                               */
+#define DMA6_CURR_Y_COUNT		0xFFC00DB8	/* DMA Channel 6 Current Y Count Register                               */
+
+#define DMA7_NEXT_DESC_PTR		0xFFC00DC0	/* DMA Channel 7 Next Descriptor Pointer Register               */
+#define DMA7_START_ADDR			0xFFC00DC4	/* DMA Channel 7 Start Address Register                                 */
+#define DMA7_CONFIG				0xFFC00DC8	/* DMA Channel 7 Configuration Register                                 */
+#define DMA7_X_COUNT			0xFFC00DD0	/* DMA Channel 7 X Count Register                                               */
+#define DMA7_X_MODIFY			0xFFC00DD4	/* DMA Channel 7 X Modify Register                                              */
+#define DMA7_Y_COUNT			0xFFC00DD8	/* DMA Channel 7 Y Count Register                                               */
+#define DMA7_Y_MODIFY			0xFFC00DDC	/* DMA Channel 7 Y Modify Register                                              */
+#define DMA7_CURR_DESC_PTR		0xFFC00DE0	/* DMA Channel 7 Current Descriptor Pointer Register    */
+#define DMA7_CURR_ADDR			0xFFC00DE4	/* DMA Channel 7 Current Address Register                               */
+#define DMA7_IRQ_STATUS			0xFFC00DE8	/* DMA Channel 7 Interrupt/Status Register                              */
+#define DMA7_PERIPHERAL_MAP		0xFFC00DEC	/* DMA Channel 7 Peripheral Map Register                                */
+#define DMA7_CURR_X_COUNT		0xFFC00DF0	/* DMA Channel 7 Current X Count Register                               */
+#define DMA7_CURR_Y_COUNT		0xFFC00DF8	/* DMA Channel 7 Current Y Count Register                               */
+
+#define DMA8_NEXT_DESC_PTR		0xFFC00E00	/* DMA Channel 8 Next Descriptor Pointer Register               */
+#define DMA8_START_ADDR			0xFFC00E04	/* DMA Channel 8 Start Address Register                                 */
+#define DMA8_CONFIG				0xFFC00E08	/* DMA Channel 8 Configuration Register                                 */
+#define DMA8_X_COUNT			0xFFC00E10	/* DMA Channel 8 X Count Register                                               */
+#define DMA8_X_MODIFY			0xFFC00E14	/* DMA Channel 8 X Modify Register                                              */
+#define DMA8_Y_COUNT			0xFFC00E18	/* DMA Channel 8 Y Count Register                                               */
+#define DMA8_Y_MODIFY			0xFFC00E1C	/* DMA Channel 8 Y Modify Register                                              */
+#define DMA8_CURR_DESC_PTR		0xFFC00E20	/* DMA Channel 8 Current Descriptor Pointer Register    */
+#define DMA8_CURR_ADDR			0xFFC00E24	/* DMA Channel 8 Current Address Register                               */
+#define DMA8_IRQ_STATUS			0xFFC00E28	/* DMA Channel 8 Interrupt/Status Register                              */
+#define DMA8_PERIPHERAL_MAP		0xFFC00E2C	/* DMA Channel 8 Peripheral Map Register                                */
+#define DMA8_CURR_X_COUNT		0xFFC00E30	/* DMA Channel 8 Current X Count Register                               */
+#define DMA8_CURR_Y_COUNT		0xFFC00E38	/* DMA Channel 8 Current Y Count Register                               */
+
+#define DMA9_NEXT_DESC_PTR		0xFFC00E40	/* DMA Channel 9 Next Descriptor Pointer Register               */
+#define DMA9_START_ADDR			0xFFC00E44	/* DMA Channel 9 Start Address Register                                 */
+#define DMA9_CONFIG				0xFFC00E48	/* DMA Channel 9 Configuration Register                                 */
+#define DMA9_X_COUNT			0xFFC00E50	/* DMA Channel 9 X Count Register                                               */
+#define DMA9_X_MODIFY			0xFFC00E54	/* DMA Channel 9 X Modify Register                                              */
+#define DMA9_Y_COUNT			0xFFC00E58	/* DMA Channel 9 Y Count Register                                               */
+#define DMA9_Y_MODIFY			0xFFC00E5C	/* DMA Channel 9 Y Modify Register                                              */
+#define DMA9_CURR_DESC_PTR		0xFFC00E60	/* DMA Channel 9 Current Descriptor Pointer Register    */
+#define DMA9_CURR_ADDR			0xFFC00E64	/* DMA Channel 9 Current Address Register                               */
+#define DMA9_IRQ_STATUS			0xFFC00E68	/* DMA Channel 9 Interrupt/Status Register                              */
+#define DMA9_PERIPHERAL_MAP		0xFFC00E6C	/* DMA Channel 9 Peripheral Map Register                                */
+#define DMA9_CURR_X_COUNT		0xFFC00E70	/* DMA Channel 9 Current X Count Register                               */
+#define DMA9_CURR_Y_COUNT		0xFFC00E78	/* DMA Channel 9 Current Y Count Register                               */
+
+#define DMA10_NEXT_DESC_PTR		0xFFC00E80	/* DMA Channel 10 Next Descriptor Pointer Register              */
+#define DMA10_START_ADDR		0xFFC00E84	/* DMA Channel 10 Start Address Register                                */
+#define DMA10_CONFIG			0xFFC00E88	/* DMA Channel 10 Configuration Register                                */
+#define DMA10_X_COUNT			0xFFC00E90	/* DMA Channel 10 X Count Register                                              */
+#define DMA10_X_MODIFY			0xFFC00E94	/* DMA Channel 10 X Modify Register                                             */
+#define DMA10_Y_COUNT			0xFFC00E98	/* DMA Channel 10 Y Count Register                                              */
+#define DMA10_Y_MODIFY			0xFFC00E9C	/* DMA Channel 10 Y Modify Register                                             */
+#define DMA10_CURR_DESC_PTR		0xFFC00EA0	/* DMA Channel 10 Current Descriptor Pointer Register   */
+#define DMA10_CURR_ADDR			0xFFC00EA4	/* DMA Channel 10 Current Address Register                              */
+#define DMA10_IRQ_STATUS		0xFFC00EA8	/* DMA Channel 10 Interrupt/Status Register                             */
+#define DMA10_PERIPHERAL_MAP	0xFFC00EAC	/* DMA Channel 10 Peripheral Map Register                               */
+#define DMA10_CURR_X_COUNT		0xFFC00EB0	/* DMA Channel 10 Current X Count Register                              */
+#define DMA10_CURR_Y_COUNT		0xFFC00EB8	/* DMA Channel 10 Current Y Count Register                              */
+
+#define DMA11_NEXT_DESC_PTR		0xFFC00EC0	/* DMA Channel 11 Next Descriptor Pointer Register              */
+#define DMA11_START_ADDR		0xFFC00EC4	/* DMA Channel 11 Start Address Register                                */
+#define DMA11_CONFIG			0xFFC00EC8	/* DMA Channel 11 Configuration Register                                */
+#define DMA11_X_COUNT			0xFFC00ED0	/* DMA Channel 11 X Count Register                                              */
+#define DMA11_X_MODIFY			0xFFC00ED4	/* DMA Channel 11 X Modify Register                                             */
+#define DMA11_Y_COUNT			0xFFC00ED8	/* DMA Channel 11 Y Count Register                                              */
+#define DMA11_Y_MODIFY			0xFFC00EDC	/* DMA Channel 11 Y Modify Register                                             */
+#define DMA11_CURR_DESC_PTR		0xFFC00EE0	/* DMA Channel 11 Current Descriptor Pointer Register   */
+#define DMA11_CURR_ADDR			0xFFC00EE4	/* DMA Channel 11 Current Address Register                              */
+#define DMA11_IRQ_STATUS		0xFFC00EE8	/* DMA Channel 11 Interrupt/Status Register                             */
+#define DMA11_PERIPHERAL_MAP	0xFFC00EEC	/* DMA Channel 11 Peripheral Map Register                               */
+#define DMA11_CURR_X_COUNT		0xFFC00EF0	/* DMA Channel 11 Current X Count Register                              */
+#define DMA11_CURR_Y_COUNT		0xFFC00EF8	/* DMA Channel 11 Current Y Count Register                              */
+
+#define MDMA_D0_NEXT_DESC_PTR	0xFFC00F00	/* MemDMA Stream 0 Destination Next Descriptor Pointer Register         */
+#define MDMA_D0_START_ADDR		0xFFC00F04	/* MemDMA Stream 0 Destination Start Address Register                           */
+#define MDMA_D0_CONFIG			0xFFC00F08	/* MemDMA Stream 0 Destination Configuration Register                           */
+#define MDMA_D0_X_COUNT			0xFFC00F10	/* MemDMA Stream 0 Destination X Count Register                                         */
+#define MDMA_D0_X_MODIFY		0xFFC00F14	/* MemDMA Stream 0 Destination X Modify Register                                        */
+#define MDMA_D0_Y_COUNT			0xFFC00F18	/* MemDMA Stream 0 Destination Y Count Register                                         */
+#define MDMA_D0_Y_MODIFY		0xFFC00F1C	/* MemDMA Stream 0 Destination Y Modify Register                                        */
+#define MDMA_D0_CURR_DESC_PTR	0xFFC00F20	/* MemDMA Stream 0 Destination Current Descriptor Pointer Register      */
+#define MDMA_D0_CURR_ADDR		0xFFC00F24	/* MemDMA Stream 0 Destination Current Address Register                         */
+#define MDMA_D0_IRQ_STATUS		0xFFC00F28	/* MemDMA Stream 0 Destination Interrupt/Status Register                        */
+#define MDMA_D0_PERIPHERAL_MAP	0xFFC00F2C	/* MemDMA Stream 0 Destination Peripheral Map Register                          */
+#define MDMA_D0_CURR_X_COUNT	0xFFC00F30	/* MemDMA Stream 0 Destination Current X Count Register                         */
+#define MDMA_D0_CURR_Y_COUNT	0xFFC00F38	/* MemDMA Stream 0 Destination Current Y Count Register                         */
+
+#define MDMA_S0_NEXT_DESC_PTR	0xFFC00F40	/* MemDMA Stream 0 Source Next Descriptor Pointer Register                      */
+#define MDMA_S0_START_ADDR		0xFFC00F44	/* MemDMA Stream 0 Source Start Address Register                                        */
+#define MDMA_S0_CONFIG			0xFFC00F48	/* MemDMA Stream 0 Source Configuration Register                                        */
+#define MDMA_S0_X_COUNT			0xFFC00F50	/* MemDMA Stream 0 Source X Count Register                                                      */
+#define MDMA_S0_X_MODIFY		0xFFC00F54	/* MemDMA Stream 0 Source X Modify Register                                                     */
+#define MDMA_S0_Y_COUNT			0xFFC00F58	/* MemDMA Stream 0 Source Y Count Register                                                      */
+#define MDMA_S0_Y_MODIFY		0xFFC00F5C	/* MemDMA Stream 0 Source Y Modify Register                                                     */
+#define MDMA_S0_CURR_DESC_PTR	0xFFC00F60	/* MemDMA Stream 0 Source Current Descriptor Pointer Register           */
+#define MDMA_S0_CURR_ADDR		0xFFC00F64	/* MemDMA Stream 0 Source Current Address Register                                      */
+#define MDMA_S0_IRQ_STATUS		0xFFC00F68	/* MemDMA Stream 0 Source Interrupt/Status Register                                     */
+#define MDMA_S0_PERIPHERAL_MAP	0xFFC00F6C	/* MemDMA Stream 0 Source Peripheral Map Register                                       */
+#define MDMA_S0_CURR_X_COUNT	0xFFC00F70	/* MemDMA Stream 0 Source Current X Count Register                                      */
+#define MDMA_S0_CURR_Y_COUNT	0xFFC00F78	/* MemDMA Stream 0 Source Current Y Count Register                                      */
+
+#define MDMA_D1_NEXT_DESC_PTR	0xFFC00F80	/* MemDMA Stream 1 Destination Next Descriptor Pointer Register         */
+#define MDMA_D1_START_ADDR		0xFFC00F84	/* MemDMA Stream 1 Destination Start Address Register                           */
+#define MDMA_D1_CONFIG			0xFFC00F88	/* MemDMA Stream 1 Destination Configuration Register                           */
+#define MDMA_D1_X_COUNT			0xFFC00F90	/* MemDMA Stream 1 Destination X Count Register                                         */
+#define MDMA_D1_X_MODIFY		0xFFC00F94	/* MemDMA Stream 1 Destination X Modify Register                                        */
+#define MDMA_D1_Y_COUNT			0xFFC00F98	/* MemDMA Stream 1 Destination Y Count Register                                         */
+#define MDMA_D1_Y_MODIFY		0xFFC00F9C	/* MemDMA Stream 1 Destination Y Modify Register                                        */
+#define MDMA_D1_CURR_DESC_PTR	0xFFC00FA0	/* MemDMA Stream 1 Destination Current Descriptor Pointer Register      */
+#define MDMA_D1_CURR_ADDR		0xFFC00FA4	/* MemDMA Stream 1 Destination Current Address Register                         */
+#define MDMA_D1_IRQ_STATUS		0xFFC00FA8	/* MemDMA Stream 1 Destination Interrupt/Status Register                        */
+#define MDMA_D1_PERIPHERAL_MAP	0xFFC00FAC	/* MemDMA Stream 1 Destination Peripheral Map Register                          */
+#define MDMA_D1_CURR_X_COUNT	0xFFC00FB0	/* MemDMA Stream 1 Destination Current X Count Register                         */
+#define MDMA_D1_CURR_Y_COUNT	0xFFC00FB8	/* MemDMA Stream 1 Destination Current Y Count Register                         */
+
+#define MDMA_S1_NEXT_DESC_PTR	0xFFC00FC0	/* MemDMA Stream 1 Source Next Descriptor Pointer Register                      */
+#define MDMA_S1_START_ADDR		0xFFC00FC4	/* MemDMA Stream 1 Source Start Address Register                                        */
+#define MDMA_S1_CONFIG			0xFFC00FC8	/* MemDMA Stream 1 Source Configuration Register                                        */
+#define MDMA_S1_X_COUNT			0xFFC00FD0	/* MemDMA Stream 1 Source X Count Register                                                      */
+#define MDMA_S1_X_MODIFY		0xFFC00FD4	/* MemDMA Stream 1 Source X Modify Register                                                     */
+#define MDMA_S1_Y_COUNT			0xFFC00FD8	/* MemDMA Stream 1 Source Y Count Register                                                      */
+#define MDMA_S1_Y_MODIFY		0xFFC00FDC	/* MemDMA Stream 1 Source Y Modify Register                                                     */
+#define MDMA_S1_CURR_DESC_PTR	0xFFC00FE0	/* MemDMA Stream 1 Source Current Descriptor Pointer Register           */
+#define MDMA_S1_CURR_ADDR		0xFFC00FE4	/* MemDMA Stream 1 Source Current Address Register                                      */
+#define MDMA_S1_IRQ_STATUS		0xFFC00FE8	/* MemDMA Stream 1 Source Interrupt/Status Register                                     */
+#define MDMA_S1_PERIPHERAL_MAP	0xFFC00FEC	/* MemDMA Stream 1 Source Peripheral Map Register                                       */
+#define MDMA_S1_CURR_X_COUNT	0xFFC00FF0	/* MemDMA Stream 1 Source Current X Count Register                                      */
+#define MDMA_S1_CURR_Y_COUNT	0xFFC00FF8	/* MemDMA Stream 1 Source Current Y Count Register                                      */
+
+/* Parallel Peripheral Interface (0xFFC01000 - 0xFFC010FF)				*/
+#define PPI_CONTROL			0xFFC01000	/* PPI Control Register                 */
+#define PPI_STATUS			0xFFC01004	/* PPI Status Register                  */
+#define PPI_COUNT			0xFFC01008	/* PPI Transfer Count Register  */
+#define PPI_DELAY			0xFFC0100C	/* PPI Delay Count Register             */
+#define PPI_FRAME			0xFFC01010	/* PPI Frame Length Register    */
+
+/* Two-Wire Interface		(0xFFC01400 - 0xFFC014FF)								*/
+#define TWI_CLKDIV			0xFFC01400	/* Serial Clock Divider Register                        */
+#define TWI_CONTROL			0xFFC01404	/* TWI Control Register                                         */
+#define TWI_SLAVE_CTL		0xFFC01408	/* Slave Mode Control Register                          */
+#define TWI_SLAVE_STAT		0xFFC0140C	/* Slave Mode Status Register                           */
+#define TWI_SLAVE_ADDR		0xFFC01410	/* Slave Mode Address Register                          */
+#define TWI_MASTER_CTL		0xFFC01414	/* Master Mode Control Register                         */
+#define TWI_MASTER_STAT		0xFFC01418	/* Master Mode Status Register                          */
+#define TWI_MASTER_ADDR		0xFFC0141C	/* Master Mode Address Register                         */
+#define TWI_INT_STAT		0xFFC01420	/* TWI Interrupt Status Register                        */
+#define TWI_INT_MASK		0xFFC01424	/* TWI Master Interrupt Mask Register           */
+#define TWI_FIFO_CTL		0xFFC01428	/* FIFO Control Register                                        */
+#define TWI_FIFO_STAT		0xFFC0142C	/* FIFO Status Register                                         */
+#define TWI_XMT_DATA8		0xFFC01480	/* FIFO Transmit Data Single Byte Register      */
+#define TWI_XMT_DATA16		0xFFC01484	/* FIFO Transmit Data Double Byte Register      */
+#define TWI_RCV_DATA8		0xFFC01488	/* FIFO Receive Data Single Byte Register       */
+#define TWI_RCV_DATA16		0xFFC0148C	/* FIFO Receive Data Double Byte Register       */
+
+/* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF)												*/
+#define PORTGIO					0xFFC01500	/* Port G I/O Pin State Specify Register                                */
+#define PORTGIO_CLEAR			0xFFC01504	/* Port G I/O Peripheral Interrupt Clear Register               */
+#define PORTGIO_SET				0xFFC01508	/* Port G I/O Peripheral Interrupt Set Register                 */
+#define PORTGIO_TOGGLE			0xFFC0150C	/* Port G I/O Pin State Toggle Register                                 */
+#define PORTGIO_MASKA			0xFFC01510	/* Port G I/O Mask State Specify Interrupt A Register   */
+#define PORTGIO_MASKA_CLEAR		0xFFC01514	/* Port G I/O Mask Disable Interrupt A Register                 */
+#define PORTGIO_MASKA_SET		0xFFC01518	/* Port G I/O Mask Enable Interrupt A Register                  */
+#define PORTGIO_MASKA_TOGGLE	0xFFC0151C	/* Port G I/O Mask Toggle Enable Interrupt A Register   */
+#define PORTGIO_MASKB			0xFFC01520	/* Port G I/O Mask State Specify Interrupt B Register   */
+#define PORTGIO_MASKB_CLEAR		0xFFC01524	/* Port G I/O Mask Disable Interrupt B Register                 */
+#define PORTGIO_MASKB_SET		0xFFC01528	/* Port G I/O Mask Enable Interrupt B Register                  */
+#define PORTGIO_MASKB_TOGGLE	0xFFC0152C	/* Port G I/O Mask Toggle Enable Interrupt B Register   */
+#define PORTGIO_DIR				0xFFC01530	/* Port G I/O Direction Register                                                */
+#define PORTGIO_POLAR			0xFFC01534	/* Port G I/O Source Polarity Register                                  */
+#define PORTGIO_EDGE			0xFFC01538	/* Port G I/O Source Sensitivity Register                               */
+#define PORTGIO_BOTH			0xFFC0153C	/* Port G I/O Set on BOTH Edges Register                                */
+#define PORTGIO_INEN			0xFFC01540	/* Port G I/O Input Enable Register                                             */
+
+/* General Purpose I/O Port H (0xFFC01700 - 0xFFC017FF)												*/
+#define PORTHIO					0xFFC01700	/* Port H I/O Pin State Specify Register                                */
+#define PORTHIO_CLEAR			0xFFC01704	/* Port H I/O Peripheral Interrupt Clear Register               */
+#define PORTHIO_SET				0xFFC01708	/* Port H I/O Peripheral Interrupt Set Register                 */
+#define PORTHIO_TOGGLE			0xFFC0170C	/* Port H I/O Pin State Toggle Register                                 */
+#define PORTHIO_MASKA			0xFFC01710	/* Port H I/O Mask State Specify Interrupt A Register   */
+#define PORTHIO_MASKA_CLEAR		0xFFC01714	/* Port H I/O Mask Disable Interrupt A Register                 */
+#define PORTHIO_MASKA_SET		0xFFC01718	/* Port H I/O Mask Enable Interrupt A Register                  */
+#define PORTHIO_MASKA_TOGGLE	0xFFC0171C	/* Port H I/O Mask Toggle Enable Interrupt A Register   */
+#define PORTHIO_MASKB			0xFFC01720	/* Port H I/O Mask State Specify Interrupt B Register   */
+#define PORTHIO_MASKB_CLEAR		0xFFC01724	/* Port H I/O Mask Disable Interrupt B Register                 */
+#define PORTHIO_MASKB_SET		0xFFC01728	/* Port H I/O Mask Enable Interrupt B Register                  */
+#define PORTHIO_MASKB_TOGGLE	0xFFC0172C	/* Port H I/O Mask Toggle Enable Interrupt B Register   */
+#define PORTHIO_DIR				0xFFC01730	/* Port H I/O Direction Register                                                */
+#define PORTHIO_POLAR			0xFFC01734	/* Port H I/O Source Polarity Register                                  */
+#define PORTHIO_EDGE			0xFFC01738	/* Port H I/O Source Sensitivity Register                               */
+#define PORTHIO_BOTH			0xFFC0173C	/* Port H I/O Set on BOTH Edges Register                                */
+#define PORTHIO_INEN			0xFFC01740	/* Port H I/O Input Enable Register                                             */
+
+/* UART1 Controller		(0xFFC02000 - 0xFFC020FF)								*/
+#define UART1_THR			0xFFC02000	/* Transmit Holding register                    */
+#define UART1_RBR			0xFFC02000	/* Receive Buffer register                              */
+#define UART1_DLL			0xFFC02000	/* Divisor Latch (Low-Byte)                             */
+#define UART1_IER			0xFFC02004	/* Interrupt Enable Register                    */
+#define UART1_DLH			0xFFC02004	/* Divisor Latch (High-Byte)                    */
+#define UART1_IIR			0xFFC02008	/* Interrupt Identification Register    */
+#define UART1_LCR			0xFFC0200C	/* Line Control Register                                */
+#define UART1_MCR			0xFFC02010	/* Modem Control Register                               */
+#define UART1_LSR			0xFFC02014	/* Line Status Register                                 */
+#define UART1_MSR			0xFFC02018	/* Modem Status Register                                */
+#define UART1_SCR			0xFFC0201C	/* SCR Scratch Register                                 */
+#define UART1_GCTL			0xFFC02024	/* Global Control Register                              */
+
+/* CAN Controller		(0xFFC02A00 - 0xFFC02FFF)										*/
+/* For Mailboxes 0-15																	*/
+#define CAN_MC1				0xFFC02A00	/* Mailbox config reg 1                                                 */
+#define CAN_MD1				0xFFC02A04	/* Mailbox direction reg 1                                              */
+#define CAN_TRS1			0xFFC02A08	/* Transmit Request Set reg 1                                   */
+#define CAN_TRR1			0xFFC02A0C	/* Transmit Request Reset reg 1                                 */
+#define CAN_TA1				0xFFC02A10	/* Transmit Acknowledge reg 1                                   */
+#define CAN_AA1				0xFFC02A14	/* Transmit Abort Acknowledge reg 1                             */
+#define CAN_RMP1			0xFFC02A18	/* Receive Message Pending reg 1                                */
+#define CAN_RML1			0xFFC02A1C	/* Receive Message Lost reg 1                                   */
+#define CAN_MBTIF1			0xFFC02A20	/* Mailbox Transmit Interrupt Flag reg 1                */
+#define CAN_MBRIF1			0xFFC02A24	/* Mailbox Receive  Interrupt Flag reg 1                */
+#define CAN_MBIM1			0xFFC02A28	/* Mailbox Interrupt Mask reg 1                                 */
+#define CAN_RFH1			0xFFC02A2C	/* Remote Frame Handling reg 1                                  */
+#define CAN_OPSS1			0xFFC02A30	/* Overwrite Protection Single Shot Xmit reg 1  */
+
+/* For Mailboxes 16-31   																*/
+#define CAN_MC2				0xFFC02A40	/* Mailbox config reg 2                                                 */
+#define CAN_MD2				0xFFC02A44	/* Mailbox direction reg 2                                              */
+#define CAN_TRS2			0xFFC02A48	/* Transmit Request Set reg 2                                   */
+#define CAN_TRR2			0xFFC02A4C	/* Transmit Request Reset reg 2                                 */
+#define CAN_TA2				0xFFC02A50	/* Transmit Acknowledge reg 2                                   */
+#define CAN_AA2				0xFFC02A54	/* Transmit Abort Acknowledge reg 2                             */
+#define CAN_RMP2			0xFFC02A58	/* Receive Message Pending reg 2                                */
+#define CAN_RML2			0xFFC02A5C	/* Receive Message Lost reg 2                                   */
+#define CAN_MBTIF2			0xFFC02A60	/* Mailbox Transmit Interrupt Flag reg 2                */
+#define CAN_MBRIF2			0xFFC02A64	/* Mailbox Receive  Interrupt Flag reg 2                */
+#define CAN_MBIM2			0xFFC02A68	/* Mailbox Interrupt Mask reg 2                                 */
+#define CAN_RFH2			0xFFC02A6C	/* Remote Frame Handling reg 2                                  */
+#define CAN_OPSS2			0xFFC02A70	/* Overwrite Protection Single Shot Xmit reg 2  */
+
+/* CAN Configuration, Control, and Status Registers										*/
+#define CAN_CLOCK			0xFFC02A80	/* Bit Timing Configuration register 0                  */
+#define CAN_TIMING			0xFFC02A84	/* Bit Timing Configuration register 1                  */
+#define CAN_DEBUG			0xFFC02A88	/* Debug Register                                                               */
+#define CAN_STATUS			0xFFC02A8C	/* Global Status Register                                               */
+#define CAN_CEC				0xFFC02A90	/* Error Counter Register                                               */
+#define CAN_GIS				0xFFC02A94	/* Global Interrupt Status Register                             */
+#define CAN_GIM				0xFFC02A98	/* Global Interrupt Mask Register                               */
+#define CAN_GIF				0xFFC02A9C	/* Global Interrupt Flag Register                               */
+#define CAN_CONTROL			0xFFC02AA0	/* Master Control Register                                              */
+#define CAN_INTR			0xFFC02AA4	/* Interrupt Pending Register                                   */
+#define CAN_SFCMVER			0xFFC02AA8	/* Version Code Register                                                */
+#define CAN_MBTD			0xFFC02AAC	/* Mailbox Temporary Disable Feature                    */
+#define CAN_EWR				0xFFC02AB0	/* Programmable Warning Level                                   */
+#define CAN_ESR				0xFFC02AB4	/* Error Status Register                                                */
+#define CAN_UCREG			0xFFC02AC0	/* Universal Counter Register/Capture Register  */
+#define CAN_UCCNT			0xFFC02AC4	/* Universal Counter                                                    */
+#define CAN_UCRC			0xFFC02AC8	/* Universal Counter Force Reload Register              */
+#define CAN_UCCNF			0xFFC02ACC	/* Universal Counter Configuration Register             */
+
+/* Mailbox Acceptance Masks 												*/
+#define CAN_AM00L			0xFFC02B00	/* Mailbox 0 Low Acceptance Mask        */
+#define CAN_AM00H			0xFFC02B04	/* Mailbox 0 High Acceptance Mask       */
+#define CAN_AM01L			0xFFC02B08	/* Mailbox 1 Low Acceptance Mask        */
+#define CAN_AM01H			0xFFC02B0C	/* Mailbox 1 High Acceptance Mask       */
+#define CAN_AM02L			0xFFC02B10	/* Mailbox 2 Low Acceptance Mask        */
+#define CAN_AM02H			0xFFC02B14	/* Mailbox 2 High Acceptance Mask       */
+#define CAN_AM03L			0xFFC02B18	/* Mailbox 3 Low Acceptance Mask        */
+#define CAN_AM03H			0xFFC02B1C	/* Mailbox 3 High Acceptance Mask       */
+#define CAN_AM04L			0xFFC02B20	/* Mailbox 4 Low Acceptance Mask        */
+#define CAN_AM04H			0xFFC02B24	/* Mailbox 4 High Acceptance Mask       */
+#define CAN_AM05L			0xFFC02B28	/* Mailbox 5 Low Acceptance Mask        */
+#define CAN_AM05H			0xFFC02B2C	/* Mailbox 5 High Acceptance Mask       */
+#define CAN_AM06L			0xFFC02B30	/* Mailbox 6 Low Acceptance Mask        */
+#define CAN_AM06H			0xFFC02B34	/* Mailbox 6 High Acceptance Mask       */
+#define CAN_AM07L			0xFFC02B38	/* Mailbox 7 Low Acceptance Mask        */
+#define CAN_AM07H			0xFFC02B3C	/* Mailbox 7 High Acceptance Mask       */
+#define CAN_AM08L			0xFFC02B40	/* Mailbox 8 Low Acceptance Mask        */
+#define CAN_AM08H			0xFFC02B44	/* Mailbox 8 High Acceptance Mask       */
+#define CAN_AM09L			0xFFC02B48	/* Mailbox 9 Low Acceptance Mask        */
+#define CAN_AM09H			0xFFC02B4C	/* Mailbox 9 High Acceptance Mask       */
+#define CAN_AM10L			0xFFC02B50	/* Mailbox 10 Low Acceptance Mask       */
+#define CAN_AM10H			0xFFC02B54	/* Mailbox 10 High Acceptance Mask      */
+#define CAN_AM11L			0xFFC02B58	/* Mailbox 11 Low Acceptance Mask       */
+#define CAN_AM11H			0xFFC02B5C	/* Mailbox 11 High Acceptance Mask      */
+#define CAN_AM12L			0xFFC02B60	/* Mailbox 12 Low Acceptance Mask       */
+#define CAN_AM12H			0xFFC02B64	/* Mailbox 12 High Acceptance Mask      */
+#define CAN_AM13L			0xFFC02B68	/* Mailbox 13 Low Acceptance Mask       */
+#define CAN_AM13H			0xFFC02B6C	/* Mailbox 13 High Acceptance Mask      */
+#define CAN_AM14L			0xFFC02B70	/* Mailbox 14 Low Acceptance Mask       */
+#define CAN_AM14H			0xFFC02B74	/* Mailbox 14 High Acceptance Mask      */
+#define CAN_AM15L			0xFFC02B78	/* Mailbox 15 Low Acceptance Mask       */
+#define CAN_AM15H			0xFFC02B7C	/* Mailbox 15 High Acceptance Mask      */
+
+#define CAN_AM16L			0xFFC02B80	/* Mailbox 16 Low Acceptance Mask       */
+#define CAN_AM16H			0xFFC02B84	/* Mailbox 16 High Acceptance Mask      */
+#define CAN_AM17L			0xFFC02B88	/* Mailbox 17 Low Acceptance Mask       */
+#define CAN_AM17H			0xFFC02B8C	/* Mailbox 17 High Acceptance Mask      */
+#define CAN_AM18L			0xFFC02B90	/* Mailbox 18 Low Acceptance Mask       */
+#define CAN_AM18H			0xFFC02B94	/* Mailbox 18 High Acceptance Mask      */
+#define CAN_AM19L			0xFFC02B98	/* Mailbox 19 Low Acceptance Mask       */
+#define CAN_AM19H			0xFFC02B9C	/* Mailbox 19 High Acceptance Mask      */
+#define CAN_AM20L			0xFFC02BA0	/* Mailbox 20 Low Acceptance Mask       */
+#define CAN_AM20H			0xFFC02BA4	/* Mailbox 20 High Acceptance Mask      */
+#define CAN_AM21L			0xFFC02BA8	/* Mailbox 21 Low Acceptance Mask       */
+#define CAN_AM21H			0xFFC02BAC	/* Mailbox 21 High Acceptance Mask      */
+#define CAN_AM22L			0xFFC02BB0	/* Mailbox 22 Low Acceptance Mask       */
+#define CAN_AM22H			0xFFC02BB4	/* Mailbox 22 High Acceptance Mask      */
+#define CAN_AM23L			0xFFC02BB8	/* Mailbox 23 Low Acceptance Mask       */
+#define CAN_AM23H			0xFFC02BBC	/* Mailbox 23 High Acceptance Mask      */
+#define CAN_AM24L			0xFFC02BC0	/* Mailbox 24 Low Acceptance Mask       */
+#define CAN_AM24H			0xFFC02BC4	/* Mailbox 24 High Acceptance Mask      */
+#define CAN_AM25L			0xFFC02BC8	/* Mailbox 25 Low Acceptance Mask       */
+#define CAN_AM25H			0xFFC02BCC	/* Mailbox 25 High Acceptance Mask      */
+#define CAN_AM26L			0xFFC02BD0	/* Mailbox 26 Low Acceptance Mask       */
+#define CAN_AM26H			0xFFC02BD4	/* Mailbox 26 High Acceptance Mask      */
+#define CAN_AM27L			0xFFC02BD8	/* Mailbox 27 Low Acceptance Mask       */
+#define CAN_AM27H			0xFFC02BDC	/* Mailbox 27 High Acceptance Mask      */
+#define CAN_AM28L			0xFFC02BE0	/* Mailbox 28 Low Acceptance Mask       */
+#define CAN_AM28H			0xFFC02BE4	/* Mailbox 28 High Acceptance Mask      */
+#define CAN_AM29L			0xFFC02BE8	/* Mailbox 29 Low Acceptance Mask       */
+#define CAN_AM29H			0xFFC02BEC	/* Mailbox 29 High Acceptance Mask      */
+#define CAN_AM30L			0xFFC02BF0	/* Mailbox 30 Low Acceptance Mask       */
+#define CAN_AM30H			0xFFC02BF4	/* Mailbox 30 High Acceptance Mask      */
+#define CAN_AM31L			0xFFC02BF8	/* Mailbox 31 Low Acceptance Mask       */
+#define CAN_AM31H			0xFFC02BFC	/* Mailbox 31 High Acceptance Mask      */
+
+/* CAN Acceptance Mask Macros				*/
+#define CAN_AM_L(x)		(CAN_AM00L+((x)*0x8))
+#define CAN_AM_H(x)		(CAN_AM00H+((x)*0x8))
+
+/* Mailbox Registers																*/
+#define CAN_MB00_DATA0		0xFFC02C00	/* Mailbox 0 Data Word 0 [15:0] Register        */
+#define CAN_MB00_DATA1		0xFFC02C04	/* Mailbox 0 Data Word 1 [31:16] Register       */
+#define CAN_MB00_DATA2		0xFFC02C08	/* Mailbox 0 Data Word 2 [47:32] Register       */
+#define CAN_MB00_DATA3		0xFFC02C0C	/* Mailbox 0 Data Word 3 [63:48] Register       */
+#define CAN_MB00_LENGTH		0xFFC02C10	/* Mailbox 0 Data Length Code Register          */
+#define CAN_MB00_TIMESTAMP	0xFFC02C14	/* Mailbox 0 Time Stamp Value Register          */
+#define CAN_MB00_ID0		0xFFC02C18	/* Mailbox 0 Identifier Low Register            */
+#define CAN_MB00_ID1		0xFFC02C1C	/* Mailbox 0 Identifier High Register           */
+
+#define CAN_MB01_DATA0		0xFFC02C20	/* Mailbox 1 Data Word 0 [15:0] Register        */
+#define CAN_MB01_DATA1		0xFFC02C24	/* Mailbox 1 Data Word 1 [31:16] Register       */
+#define CAN_MB01_DATA2		0xFFC02C28	/* Mailbox 1 Data Word 2 [47:32] Register       */
+#define CAN_MB01_DATA3		0xFFC02C2C	/* Mailbox 1 Data Word 3 [63:48] Register       */
+#define CAN_MB01_LENGTH		0xFFC02C30	/* Mailbox 1 Data Length Code Register          */
+#define CAN_MB01_TIMESTAMP	0xFFC02C34	/* Mailbox 1 Time Stamp Value Register          */
+#define CAN_MB01_ID0		0xFFC02C38	/* Mailbox 1 Identifier Low Register            */
+#define CAN_MB01_ID1		0xFFC02C3C	/* Mailbox 1 Identifier High Register           */
+
+#define CAN_MB02_DATA0		0xFFC02C40	/* Mailbox 2 Data Word 0 [15:0] Register        */
+#define CAN_MB02_DATA1		0xFFC02C44	/* Mailbox 2 Data Word 1 [31:16] Register       */
+#define CAN_MB02_DATA2		0xFFC02C48	/* Mailbox 2 Data Word 2 [47:32] Register       */
+#define CAN_MB02_DATA3		0xFFC02C4C	/* Mailbox 2 Data Word 3 [63:48] Register       */
+#define CAN_MB02_LENGTH		0xFFC02C50	/* Mailbox 2 Data Length Code Register          */
+#define CAN_MB02_TIMESTAMP	0xFFC02C54	/* Mailbox 2 Time Stamp Value Register          */
+#define CAN_MB02_ID0		0xFFC02C58	/* Mailbox 2 Identifier Low Register            */
+#define CAN_MB02_ID1		0xFFC02C5C	/* Mailbox 2 Identifier High Register           */
+
+#define CAN_MB03_DATA0		0xFFC02C60	/* Mailbox 3 Data Word 0 [15:0] Register        */
+#define CAN_MB03_DATA1		0xFFC02C64	/* Mailbox 3 Data Word 1 [31:16] Register       */
+#define CAN_MB03_DATA2		0xFFC02C68	/* Mailbox 3 Data Word 2 [47:32] Register       */
+#define CAN_MB03_DATA3		0xFFC02C6C	/* Mailbox 3 Data Word 3 [63:48] Register       */
+#define CAN_MB03_LENGTH		0xFFC02C70	/* Mailbox 3 Data Length Code Register          */
+#define CAN_MB03_TIMESTAMP	0xFFC02C74	/* Mailbox 3 Time Stamp Value Register          */
+#define CAN_MB03_ID0		0xFFC02C78	/* Mailbox 3 Identifier Low Register            */
+#define CAN_MB03_ID1		0xFFC02C7C	/* Mailbox 3 Identifier High Register           */
+
+#define CAN_MB04_DATA0		0xFFC02C80	/* Mailbox 4 Data Word 0 [15:0] Register        */
+#define CAN_MB04_DATA1		0xFFC02C84	/* Mailbox 4 Data Word 1 [31:16] Register       */
+#define CAN_MB04_DATA2		0xFFC02C88	/* Mailbox 4 Data Word 2 [47:32] Register       */
+#define CAN_MB04_DATA3		0xFFC02C8C	/* Mailbox 4 Data Word 3 [63:48] Register       */
+#define CAN_MB04_LENGTH		0xFFC02C90	/* Mailbox 4 Data Length Code Register          */
+#define CAN_MB04_TIMESTAMP	0xFFC02C94	/* Mailbox 4 Time Stamp Value Register          */
+#define CAN_MB04_ID0		0xFFC02C98	/* Mailbox 4 Identifier Low Register            */
+#define CAN_MB04_ID1		0xFFC02C9C	/* Mailbox 4 Identifier High Register           */
+
+#define CAN_MB05_DATA0		0xFFC02CA0	/* Mailbox 5 Data Word 0 [15:0] Register        */
+#define CAN_MB05_DATA1		0xFFC02CA4	/* Mailbox 5 Data Word 1 [31:16] Register       */
+#define CAN_MB05_DATA2		0xFFC02CA8	/* Mailbox 5 Data Word 2 [47:32] Register       */
+#define CAN_MB05_DATA3		0xFFC02CAC	/* Mailbox 5 Data Word 3 [63:48] Register       */
+#define CAN_MB05_LENGTH		0xFFC02CB0	/* Mailbox 5 Data Length Code Register          */
+#define CAN_MB05_TIMESTAMP	0xFFC02CB4	/* Mailbox 5 Time Stamp Value Register          */
+#define CAN_MB05_ID0		0xFFC02CB8	/* Mailbox 5 Identifier Low Register            */
+#define CAN_MB05_ID1		0xFFC02CBC	/* Mailbox 5 Identifier High Register           */
+
+#define CAN_MB06_DATA0		0xFFC02CC0	/* Mailbox 6 Data Word 0 [15:0] Register        */
+#define CAN_MB06_DATA1		0xFFC02CC4	/* Mailbox 6 Data Word 1 [31:16] Register       */
+#define CAN_MB06_DATA2		0xFFC02CC8	/* Mailbox 6 Data Word 2 [47:32] Register       */
+#define CAN_MB06_DATA3		0xFFC02CCC	/* Mailbox 6 Data Word 3 [63:48] Register       */
+#define CAN_MB06_LENGTH		0xFFC02CD0	/* Mailbox 6 Data Length Code Register          */
+#define CAN_MB06_TIMESTAMP	0xFFC02CD4	/* Mailbox 6 Time Stamp Value Register          */
+#define CAN_MB06_ID0		0xFFC02CD8	/* Mailbox 6 Identifier Low Register            */
+#define CAN_MB06_ID1		0xFFC02CDC	/* Mailbox 6 Identifier High Register           */
+
+#define CAN_MB07_DATA0		0xFFC02CE0	/* Mailbox 7 Data Word 0 [15:0] Register        */
+#define CAN_MB07_DATA1		0xFFC02CE4	/* Mailbox 7 Data Word 1 [31:16] Register       */
+#define CAN_MB07_DATA2		0xFFC02CE8	/* Mailbox 7 Data Word 2 [47:32] Register       */
+#define CAN_MB07_DATA3		0xFFC02CEC	/* Mailbox 7 Data Word 3 [63:48] Register       */
+#define CAN_MB07_LENGTH		0xFFC02CF0	/* Mailbox 7 Data Length Code Register          */
+#define CAN_MB07_TIMESTAMP	0xFFC02CF4	/* Mailbox 7 Time Stamp Value Register          */
+#define CAN_MB07_ID0		0xFFC02CF8	/* Mailbox 7 Identifier Low Register            */
+#define CAN_MB07_ID1		0xFFC02CFC	/* Mailbox 7 Identifier High Register           */
+
+#define CAN_MB08_DATA0		0xFFC02D00	/* Mailbox 8 Data Word 0 [15:0] Register        */
+#define CAN_MB08_DATA1		0xFFC02D04	/* Mailbox 8 Data Word 1 [31:16] Register       */
+#define CAN_MB08_DATA2		0xFFC02D08	/* Mailbox 8 Data Word 2 [47:32] Register       */
+#define CAN_MB08_DATA3		0xFFC02D0C	/* Mailbox 8 Data Word 3 [63:48] Register       */
+#define CAN_MB08_LENGTH		0xFFC02D10	/* Mailbox 8 Data Length Code Register          */
+#define CAN_MB08_TIMESTAMP	0xFFC02D14	/* Mailbox 8 Time Stamp Value Register          */
+#define CAN_MB08_ID0		0xFFC02D18	/* Mailbox 8 Identifier Low Register            */
+#define CAN_MB08_ID1		0xFFC02D1C	/* Mailbox 8 Identifier High Register           */
+
+#define CAN_MB09_DATA0		0xFFC02D20	/* Mailbox 9 Data Word 0 [15:0] Register        */
+#define CAN_MB09_DATA1		0xFFC02D24	/* Mailbox 9 Data Word 1 [31:16] Register       */
+#define CAN_MB09_DATA2		0xFFC02D28	/* Mailbox 9 Data Word 2 [47:32] Register       */
+#define CAN_MB09_DATA3		0xFFC02D2C	/* Mailbox 9 Data Word 3 [63:48] Register       */
+#define CAN_MB09_LENGTH		0xFFC02D30	/* Mailbox 9 Data Length Code Register          */
+#define CAN_MB09_TIMESTAMP	0xFFC02D34	/* Mailbox 9 Time Stamp Value Register          */
+#define CAN_MB09_ID0		0xFFC02D38	/* Mailbox 9 Identifier Low Register            */
+#define CAN_MB09_ID1		0xFFC02D3C	/* Mailbox 9 Identifier High Register           */
+
+#define CAN_MB10_DATA0		0xFFC02D40	/* Mailbox 10 Data Word 0 [15:0] Register       */
+#define CAN_MB10_DATA1		0xFFC02D44	/* Mailbox 10 Data Word 1 [31:16] Register      */
+#define CAN_MB10_DATA2		0xFFC02D48	/* Mailbox 10 Data Word 2 [47:32] Register      */
+#define CAN_MB10_DATA3		0xFFC02D4C	/* Mailbox 10 Data Word 3 [63:48] Register      */
+#define CAN_MB10_LENGTH		0xFFC02D50	/* Mailbox 10 Data Length Code Register         */
+#define CAN_MB10_TIMESTAMP	0xFFC02D54	/* Mailbox 10 Time Stamp Value Register         */
+#define CAN_MB10_ID0		0xFFC02D58	/* Mailbox 10 Identifier Low Register           */
+#define CAN_MB10_ID1		0xFFC02D5C	/* Mailbox 10 Identifier High Register          */
+
+#define CAN_MB11_DATA0		0xFFC02D60	/* Mailbox 11 Data Word 0 [15:0] Register       */
+#define CAN_MB11_DATA1		0xFFC02D64	/* Mailbox 11 Data Word 1 [31:16] Register      */
+#define CAN_MB11_DATA2		0xFFC02D68	/* Mailbox 11 Data Word 2 [47:32] Register      */
+#define CAN_MB11_DATA3		0xFFC02D6C	/* Mailbox 11 Data Word 3 [63:48] Register      */
+#define CAN_MB11_LENGTH		0xFFC02D70	/* Mailbox 11 Data Length Code Register         */
+#define CAN_MB11_TIMESTAMP	0xFFC02D74	/* Mailbox 11 Time Stamp Value Register         */
+#define CAN_MB11_ID0		0xFFC02D78	/* Mailbox 11 Identifier Low Register           */
+#define CAN_MB11_ID1		0xFFC02D7C	/* Mailbox 11 Identifier High Register          */
+
+#define CAN_MB12_DATA0		0xFFC02D80	/* Mailbox 12 Data Word 0 [15:0] Register       */
+#define CAN_MB12_DATA1		0xFFC02D84	/* Mailbox 12 Data Word 1 [31:16] Register      */
+#define CAN_MB12_DATA2		0xFFC02D88	/* Mailbox 12 Data Word 2 [47:32] Register      */
+#define CAN_MB12_DATA3		0xFFC02D8C	/* Mailbox 12 Data Word 3 [63:48] Register      */
+#define CAN_MB12_LENGTH		0xFFC02D90	/* Mailbox 12 Data Length Code Register         */
+#define CAN_MB12_TIMESTAMP	0xFFC02D94	/* Mailbox 12 Time Stamp Value Register         */
+#define CAN_MB12_ID0		0xFFC02D98	/* Mailbox 12 Identifier Low Register           */
+#define CAN_MB12_ID1		0xFFC02D9C	/* Mailbox 12 Identifier High Register          */
+
+#define CAN_MB13_DATA0		0xFFC02DA0	/* Mailbox 13 Data Word 0 [15:0] Register       */
+#define CAN_MB13_DATA1		0xFFC02DA4	/* Mailbox 13 Data Word 1 [31:16] Register      */
+#define CAN_MB13_DATA2		0xFFC02DA8	/* Mailbox 13 Data Word 2 [47:32] Register      */
+#define CAN_MB13_DATA3		0xFFC02DAC	/* Mailbox 13 Data Word 3 [63:48] Register      */
+#define CAN_MB13_LENGTH		0xFFC02DB0	/* Mailbox 13 Data Length Code Register         */
+#define CAN_MB13_TIMESTAMP	0xFFC02DB4	/* Mailbox 13 Time Stamp Value Register         */
+#define CAN_MB13_ID0		0xFFC02DB8	/* Mailbox 13 Identifier Low Register           */
+#define CAN_MB13_ID1		0xFFC02DBC	/* Mailbox 13 Identifier High Register          */
+
+#define CAN_MB14_DATA0		0xFFC02DC0	/* Mailbox 14 Data Word 0 [15:0] Register       */
+#define CAN_MB14_DATA1		0xFFC02DC4	/* Mailbox 14 Data Word 1 [31:16] Register      */
+#define CAN_MB14_DATA2		0xFFC02DC8	/* Mailbox 14 Data Word 2 [47:32] Register      */
+#define CAN_MB14_DATA3		0xFFC02DCC	/* Mailbox 14 Data Word 3 [63:48] Register      */
+#define CAN_MB14_LENGTH		0xFFC02DD0	/* Mailbox 14 Data Length Code Register         */
+#define CAN_MB14_TIMESTAMP	0xFFC02DD4	/* Mailbox 14 Time Stamp Value Register         */
+#define CAN_MB14_ID0		0xFFC02DD8	/* Mailbox 14 Identifier Low Register           */
+#define CAN_MB14_ID1		0xFFC02DDC	/* Mailbox 14 Identifier High Register          */
+
+#define CAN_MB15_DATA0		0xFFC02DE0	/* Mailbox 15 Data Word 0 [15:0] Register       */
+#define CAN_MB15_DATA1		0xFFC02DE4	/* Mailbox 15 Data Word 1 [31:16] Register      */
+#define CAN_MB15_DATA2		0xFFC02DE8	/* Mailbox 15 Data Word 2 [47:32] Register      */
+#define CAN_MB15_DATA3		0xFFC02DEC	/* Mailbox 15 Data Word 3 [63:48] Register      */
+#define CAN_MB15_LENGTH		0xFFC02DF0	/* Mailbox 15 Data Length Code Register         */
+#define CAN_MB15_TIMESTAMP	0xFFC02DF4	/* Mailbox 15 Time Stamp Value Register         */
+#define CAN_MB15_ID0		0xFFC02DF8	/* Mailbox 15 Identifier Low Register           */
+#define CAN_MB15_ID1		0xFFC02DFC	/* Mailbox 15 Identifier High Register          */
+
+#define CAN_MB16_DATA0		0xFFC02E00	/* Mailbox 16 Data Word 0 [15:0] Register       */
+#define CAN_MB16_DATA1		0xFFC02E04	/* Mailbox 16 Data Word 1 [31:16] Register      */
+#define CAN_MB16_DATA2		0xFFC02E08	/* Mailbox 16 Data Word 2 [47:32] Register      */
+#define CAN_MB16_DATA3		0xFFC02E0C	/* Mailbox 16 Data Word 3 [63:48] Register      */
+#define CAN_MB16_LENGTH		0xFFC02E10	/* Mailbox 16 Data Length Code Register         */
+#define CAN_MB16_TIMESTAMP	0xFFC02E14	/* Mailbox 16 Time Stamp Value Register         */
+#define CAN_MB16_ID0		0xFFC02E18	/* Mailbox 16 Identifier Low Register           */
+#define CAN_MB16_ID1		0xFFC02E1C	/* Mailbox 16 Identifier High Register          */
+
+#define CAN_MB17_DATA0		0xFFC02E20	/* Mailbox 17 Data Word 0 [15:0] Register       */
+#define CAN_MB17_DATA1		0xFFC02E24	/* Mailbox 17 Data Word 1 [31:16] Register      */
+#define CAN_MB17_DATA2		0xFFC02E28	/* Mailbox 17 Data Word 2 [47:32] Register      */
+#define CAN_MB17_DATA3		0xFFC02E2C	/* Mailbox 17 Data Word 3 [63:48] Register      */
+#define CAN_MB17_LENGTH		0xFFC02E30	/* Mailbox 17 Data Length Code Register         */
+#define CAN_MB17_TIMESTAMP	0xFFC02E34	/* Mailbox 17 Time Stamp Value Register         */
+#define CAN_MB17_ID0		0xFFC02E38	/* Mailbox 17 Identifier Low Register           */
+#define CAN_MB17_ID1		0xFFC02E3C	/* Mailbox 17 Identifier High Register          */
+
+#define CAN_MB18_DATA0		0xFFC02E40	/* Mailbox 18 Data Word 0 [15:0] Register       */
+#define CAN_MB18_DATA1		0xFFC02E44	/* Mailbox 18 Data Word 1 [31:16] Register      */
+#define CAN_MB18_DATA2		0xFFC02E48	/* Mailbox 18 Data Word 2 [47:32] Register      */
+#define CAN_MB18_DATA3		0xFFC02E4C	/* Mailbox 18 Data Word 3 [63:48] Register      */
+#define CAN_MB18_LENGTH		0xFFC02E50	/* Mailbox 18 Data Length Code Register         */
+#define CAN_MB18_TIMESTAMP	0xFFC02E54	/* Mailbox 18 Time Stamp Value Register         */
+#define CAN_MB18_ID0		0xFFC02E58	/* Mailbox 18 Identifier Low Register           */
+#define CAN_MB18_ID1		0xFFC02E5C	/* Mailbox 18 Identifier High Register          */
+
+#define CAN_MB19_DATA0		0xFFC02E60	/* Mailbox 19 Data Word 0 [15:0] Register       */
+#define CAN_MB19_DATA1		0xFFC02E64	/* Mailbox 19 Data Word 1 [31:16] Register      */
+#define CAN_MB19_DATA2		0xFFC02E68	/* Mailbox 19 Data Word 2 [47:32] Register      */
+#define CAN_MB19_DATA3		0xFFC02E6C	/* Mailbox 19 Data Word 3 [63:48] Register      */
+#define CAN_MB19_LENGTH		0xFFC02E70	/* Mailbox 19 Data Length Code Register         */
+#define CAN_MB19_TIMESTAMP	0xFFC02E74	/* Mailbox 19 Time Stamp Value Register         */
+#define CAN_MB19_ID0		0xFFC02E78	/* Mailbox 19 Identifier Low Register           */
+#define CAN_MB19_ID1		0xFFC02E7C	/* Mailbox 19 Identifier High Register          */
+
+#define CAN_MB20_DATA0		0xFFC02E80	/* Mailbox 20 Data Word 0 [15:0] Register       */
+#define CAN_MB20_DATA1		0xFFC02E84	/* Mailbox 20 Data Word 1 [31:16] Register      */
+#define CAN_MB20_DATA2		0xFFC02E88	/* Mailbox 20 Data Word 2 [47:32] Register      */
+#define CAN_MB20_DATA3		0xFFC02E8C	/* Mailbox 20 Data Word 3 [63:48] Register      */
+#define CAN_MB20_LENGTH		0xFFC02E90	/* Mailbox 20 Data Length Code Register         */
+#define CAN_MB20_TIMESTAMP	0xFFC02E94	/* Mailbox 20 Time Stamp Value Register         */
+#define CAN_MB20_ID0		0xFFC02E98	/* Mailbox 20 Identifier Low Register           */
+#define CAN_MB20_ID1		0xFFC02E9C	/* Mailbox 20 Identifier High Register          */
+
+#define CAN_MB21_DATA0		0xFFC02EA0	/* Mailbox 21 Data Word 0 [15:0] Register       */
+#define CAN_MB21_DATA1		0xFFC02EA4	/* Mailbox 21 Data Word 1 [31:16] Register      */
+#define CAN_MB21_DATA2		0xFFC02EA8	/* Mailbox 21 Data Word 2 [47:32] Register      */
+#define CAN_MB21_DATA3		0xFFC02EAC	/* Mailbox 21 Data Word 3 [63:48] Register      */
+#define CAN_MB21_LENGTH		0xFFC02EB0	/* Mailbox 21 Data Length Code Register         */
+#define CAN_MB21_TIMESTAMP	0xFFC02EB4	/* Mailbox 21 Time Stamp Value Register         */
+#define CAN_MB21_ID0		0xFFC02EB8	/* Mailbox 21 Identifier Low Register           */
+#define CAN_MB21_ID1		0xFFC02EBC	/* Mailbox 21 Identifier High Register          */
+
+#define CAN_MB22_DATA0		0xFFC02EC0	/* Mailbox 22 Data Word 0 [15:0] Register       */
+#define CAN_MB22_DATA1		0xFFC02EC4	/* Mailbox 22 Data Word 1 [31:16] Register      */
+#define CAN_MB22_DATA2		0xFFC02EC8	/* Mailbox 22 Data Word 2 [47:32] Register      */
+#define CAN_MB22_DATA3		0xFFC02ECC	/* Mailbox 22 Data Word 3 [63:48] Register      */
+#define CAN_MB22_LENGTH		0xFFC02ED0	/* Mailbox 22 Data Length Code Register         */
+#define CAN_MB22_TIMESTAMP	0xFFC02ED4	/* Mailbox 22 Time Stamp Value Register         */
+#define CAN_MB22_ID0		0xFFC02ED8	/* Mailbox 22 Identifier Low Register           */
+#define CAN_MB22_ID1		0xFFC02EDC	/* Mailbox 22 Identifier High Register          */
+
+#define CAN_MB23_DATA0		0xFFC02EE0	/* Mailbox 23 Data Word 0 [15:0] Register       */
+#define CAN_MB23_DATA1		0xFFC02EE4	/* Mailbox 23 Data Word 1 [31:16] Register      */
+#define CAN_MB23_DATA2		0xFFC02EE8	/* Mailbox 23 Data Word 2 [47:32] Register      */
+#define CAN_MB23_DATA3		0xFFC02EEC	/* Mailbox 23 Data Word 3 [63:48] Register      */
+#define CAN_MB23_LENGTH		0xFFC02EF0	/* Mailbox 23 Data Length Code Register         */
+#define CAN_MB23_TIMESTAMP	0xFFC02EF4	/* Mailbox 23 Time Stamp Value Register         */
+#define CAN_MB23_ID0		0xFFC02EF8	/* Mailbox 23 Identifier Low Register           */
+#define CAN_MB23_ID1		0xFFC02EFC	/* Mailbox 23 Identifier High Register          */
+
+#define CAN_MB24_DATA0		0xFFC02F00	/* Mailbox 24 Data Word 0 [15:0] Register       */
+#define CAN_MB24_DATA1		0xFFC02F04	/* Mailbox 24 Data Word 1 [31:16] Register      */
+#define CAN_MB24_DATA2		0xFFC02F08	/* Mailbox 24 Data Word 2 [47:32] Register      */
+#define CAN_MB24_DATA3		0xFFC02F0C	/* Mailbox 24 Data Word 3 [63:48] Register      */
+#define CAN_MB24_LENGTH		0xFFC02F10	/* Mailbox 24 Data Length Code Register         */
+#define CAN_MB24_TIMESTAMP	0xFFC02F14	/* Mailbox 24 Time Stamp Value Register         */
+#define CAN_MB24_ID0		0xFFC02F18	/* Mailbox 24 Identifier Low Register           */
+#define CAN_MB24_ID1		0xFFC02F1C	/* Mailbox 24 Identifier High Register          */
+
+#define CAN_MB25_DATA0		0xFFC02F20	/* Mailbox 25 Data Word 0 [15:0] Register       */
+#define CAN_MB25_DATA1		0xFFC02F24	/* Mailbox 25 Data Word 1 [31:16] Register      */
+#define CAN_MB25_DATA2		0xFFC02F28	/* Mailbox 25 Data Word 2 [47:32] Register      */
+#define CAN_MB25_DATA3		0xFFC02F2C	/* Mailbox 25 Data Word 3 [63:48] Register      */
+#define CAN_MB25_LENGTH		0xFFC02F30	/* Mailbox 25 Data Length Code Register         */
+#define CAN_MB25_TIMESTAMP	0xFFC02F34	/* Mailbox 25 Time Stamp Value Register         */
+#define CAN_MB25_ID0		0xFFC02F38	/* Mailbox 25 Identifier Low Register           */
+#define CAN_MB25_ID1		0xFFC02F3C	/* Mailbox 25 Identifier High Register          */
+
+#define CAN_MB26_DATA0		0xFFC02F40	/* Mailbox 26 Data Word 0 [15:0] Register       */
+#define CAN_MB26_DATA1		0xFFC02F44	/* Mailbox 26 Data Word 1 [31:16] Register      */
+#define CAN_MB26_DATA2		0xFFC02F48	/* Mailbox 26 Data Word 2 [47:32] Register      */
+#define CAN_MB26_DATA3		0xFFC02F4C	/* Mailbox 26 Data Word 3 [63:48] Register      */
+#define CAN_MB26_LENGTH		0xFFC02F50	/* Mailbox 26 Data Length Code Register         */
+#define CAN_MB26_TIMESTAMP	0xFFC02F54	/* Mailbox 26 Time Stamp Value Register         */
+#define CAN_MB26_ID0		0xFFC02F58	/* Mailbox 26 Identifier Low Register           */
+#define CAN_MB26_ID1		0xFFC02F5C	/* Mailbox 26 Identifier High Register          */
+
+#define CAN_MB27_DATA0		0xFFC02F60	/* Mailbox 27 Data Word 0 [15:0] Register       */
+#define CAN_MB27_DATA1		0xFFC02F64	/* Mailbox 27 Data Word 1 [31:16] Register      */
+#define CAN_MB27_DATA2		0xFFC02F68	/* Mailbox 27 Data Word 2 [47:32] Register      */
+#define CAN_MB27_DATA3		0xFFC02F6C	/* Mailbox 27 Data Word 3 [63:48] Register      */
+#define CAN_MB27_LENGTH		0xFFC02F70	/* Mailbox 27 Data Length Code Register         */
+#define CAN_MB27_TIMESTAMP	0xFFC02F74	/* Mailbox 27 Time Stamp Value Register         */
+#define CAN_MB27_ID0		0xFFC02F78	/* Mailbox 27 Identifier Low Register           */
+#define CAN_MB27_ID1		0xFFC02F7C	/* Mailbox 27 Identifier High Register          */
+
+#define CAN_MB28_DATA0		0xFFC02F80	/* Mailbox 28 Data Word 0 [15:0] Register       */
+#define CAN_MB28_DATA1		0xFFC02F84	/* Mailbox 28 Data Word 1 [31:16] Register      */
+#define CAN_MB28_DATA2		0xFFC02F88	/* Mailbox 28 Data Word 2 [47:32] Register      */
+#define CAN_MB28_DATA3		0xFFC02F8C	/* Mailbox 28 Data Word 3 [63:48] Register      */
+#define CAN_MB28_LENGTH		0xFFC02F90	/* Mailbox 28 Data Length Code Register         */
+#define CAN_MB28_TIMESTAMP	0xFFC02F94	/* Mailbox 28 Time Stamp Value Register         */
+#define CAN_MB28_ID0		0xFFC02F98	/* Mailbox 28 Identifier Low Register           */
+#define CAN_MB28_ID1		0xFFC02F9C	/* Mailbox 28 Identifier High Register          */
+
+#define CAN_MB29_DATA0		0xFFC02FA0	/* Mailbox 29 Data Word 0 [15:0] Register       */
+#define CAN_MB29_DATA1		0xFFC02FA4	/* Mailbox 29 Data Word 1 [31:16] Register      */
+#define CAN_MB29_DATA2		0xFFC02FA8	/* Mailbox 29 Data Word 2 [47:32] Register      */
+#define CAN_MB29_DATA3		0xFFC02FAC	/* Mailbox 29 Data Word 3 [63:48] Register      */
+#define CAN_MB29_LENGTH		0xFFC02FB0	/* Mailbox 29 Data Length Code Register         */
+#define CAN_MB29_TIMESTAMP	0xFFC02FB4	/* Mailbox 29 Time Stamp Value Register         */
+#define CAN_MB29_ID0		0xFFC02FB8	/* Mailbox 29 Identifier Low Register           */
+#define CAN_MB29_ID1		0xFFC02FBC	/* Mailbox 29 Identifier High Register          */
+
+#define CAN_MB30_DATA0		0xFFC02FC0	/* Mailbox 30 Data Word 0 [15:0] Register       */
+#define CAN_MB30_DATA1		0xFFC02FC4	/* Mailbox 30 Data Word 1 [31:16] Register      */
+#define CAN_MB30_DATA2		0xFFC02FC8	/* Mailbox 30 Data Word 2 [47:32] Register      */
+#define CAN_MB30_DATA3		0xFFC02FCC	/* Mailbox 30 Data Word 3 [63:48] Register      */
+#define CAN_MB30_LENGTH		0xFFC02FD0	/* Mailbox 30 Data Length Code Register         */
+#define CAN_MB30_TIMESTAMP	0xFFC02FD4	/* Mailbox 30 Time Stamp Value Register         */
+#define CAN_MB30_ID0		0xFFC02FD8	/* Mailbox 30 Identifier Low Register           */
+#define CAN_MB30_ID1		0xFFC02FDC	/* Mailbox 30 Identifier High Register          */
+
+#define CAN_MB31_DATA0		0xFFC02FE0	/* Mailbox 31 Data Word 0 [15:0] Register       */
+#define CAN_MB31_DATA1		0xFFC02FE4	/* Mailbox 31 Data Word 1 [31:16] Register      */
+#define CAN_MB31_DATA2		0xFFC02FE8	/* Mailbox 31 Data Word 2 [47:32] Register      */
+#define CAN_MB31_DATA3		0xFFC02FEC	/* Mailbox 31 Data Word 3 [63:48] Register      */
+#define CAN_MB31_LENGTH		0xFFC02FF0	/* Mailbox 31 Data Length Code Register         */
+#define CAN_MB31_TIMESTAMP	0xFFC02FF4	/* Mailbox 31 Time Stamp Value Register         */
+#define CAN_MB31_ID0		0xFFC02FF8	/* Mailbox 31 Identifier Low Register           */
+#define CAN_MB31_ID1		0xFFC02FFC	/* Mailbox 31 Identifier High Register          */
+
+/* CAN Mailbox Area Macros				*/
+#define CAN_MB_ID1(x)		(CAN_MB00_ID1+((x)*0x20))
+#define CAN_MB_ID0(x)		(CAN_MB00_ID0+((x)*0x20))
+#define CAN_MB_TIMESTAMP(x)	(CAN_MB00_TIMESTAMP+((x)*0x20))
+#define CAN_MB_LENGTH(x)	(CAN_MB00_LENGTH+((x)*0x20))
+#define CAN_MB_DATA3(x)		(CAN_MB00_DATA3+((x)*0x20))
+#define CAN_MB_DATA2(x)		(CAN_MB00_DATA2+((x)*0x20))
+#define CAN_MB_DATA1(x)		(CAN_MB00_DATA1+((x)*0x20))
+#define CAN_MB_DATA0(x)		(CAN_MB00_DATA0+((x)*0x20))
+
+/* Pin Control Registers	(0xFFC03200 - 0xFFC032FF)											*/
+#define PORTF_FER			0xFFC03200	/* Port F Function Enable Register (Alternate/Flag*)    */
+#define PORTG_FER			0xFFC03204	/* Port G Function Enable Register (Alternate/Flag*)    */
+#define PORTH_FER			0xFFC03208	/* Port H Function Enable Register (Alternate/Flag*)    */
+#define BFIN_PORT_MUX			0xFFC0320C	/* Port Multiplexer Control Register                                    */
+
+/* Handshake MDMA Registers	(0xFFC03300 - 0xFFC033FF)										*/
+#define HMDMA0_CONTROL		0xFFC03300	/* Handshake MDMA0 Control Register                                     */
+#define HMDMA0_ECINIT		0xFFC03304	/* HMDMA0 Initial Edge Count Register                           */
+#define HMDMA0_BCINIT		0xFFC03308	/* HMDMA0 Initial Block Count Register                          */
+#define HMDMA0_ECURGENT		0xFFC0330C	/* HMDMA0 Urgent Edge Count Threshhold Register         */
+#define HMDMA0_ECOVERFLOW	0xFFC03310	/* HMDMA0 Edge Count Overflow Interrupt Register        */
+#define HMDMA0_ECOUNT		0xFFC03314	/* HMDMA0 Current Edge Count Register                           */
+#define HMDMA0_BCOUNT		0xFFC03318	/* HMDMA0 Current Block Count Register                          */
+
+#define HMDMA1_CONTROL		0xFFC03340	/* Handshake MDMA1 Control Register                                     */
+#define HMDMA1_ECINIT		0xFFC03344	/* HMDMA1 Initial Edge Count Register                           */
+#define HMDMA1_BCINIT		0xFFC03348	/* HMDMA1 Initial Block Count Register                          */
+#define HMDMA1_ECURGENT		0xFFC0334C	/* HMDMA1 Urgent Edge Count Threshhold Register         */
+#define HMDMA1_ECOVERFLOW	0xFFC03350	/* HMDMA1 Edge Count Overflow Interrupt Register        */
+#define HMDMA1_ECOUNT		0xFFC03354	/* HMDMA1 Current Edge Count Register                           */
+#define HMDMA1_BCOUNT		0xFFC03358	/* HMDMA1 Current Block Count Register                          */
+
+/***********************************************************************************
+** System MMR Register Bits And Macros
+**
+** Disclaimer:	All macros are intended to make C and Assembly code more readable.
+**				Use these macros carefully, as any that do left shifts for field
+**				depositing will result in the lower order bits being destroyed.  Any
+**				macro that shifts left to properly position the bit-field should be
+**				used as part of an OR to initialize a register and NOT as a dynamic
+**				modifier UNLESS the lower order bits are saved and ORed back in when
+**				the macro is used.
+*************************************************************************************/
+/*
+** ********************* PLL AND RESET MASKS ****************************************/
+/* PLL_CTL Masks																	*/
+#define DF				0x0001	/* 0: PLL = CLKIN, 1: PLL = CLKIN/2                                     */
+#define PLL_OFF			0x0002	/* PLL Not Powered                                                                      */
+#define STOPCK			0x0008	/* Core Clock Off                                                                       */
+#define PDWN			0x0020	/* Enter Deep Sleep Mode                                                        */
+#define	IN_DELAY		0x0040	/* Add 200ps Delay To EBIU Input Latches                        */
+#define	OUT_DELAY		0x0080	/* Add 200ps Delay To EBIU Output Signals                       */
+#define BYPASS			0x0100	/* Bypass the PLL                                                                       */
+#define	MSEL			0x7E00	/* Multiplier Select For CCLK/VCO Factors                       */
+/* PLL_CTL Macros (Only Use With Logic OR While Setting Lower Order Bits)			*/
+#define	SET_MSEL(x)		(((x)&0x3F) << 0x9)	/* Set MSEL = 0-63 --> VCO = CLKIN*MSEL         */
+
+/* PLL_DIV Masks														*/
+#define SSEL			0x000F	/* System Select                                                */
+#define	CSEL			0x0030	/* Core Select                                                  */
+#define CSEL_DIV1		0x0000	/*              CCLK = VCO / 1                                  */
+#define CSEL_DIV2		0x0010	/*              CCLK = VCO / 2                                  */
+#define	CSEL_DIV4		0x0020	/*              CCLK = VCO / 4                                  */
+#define	CSEL_DIV8		0x0030	/*              CCLK = VCO / 8                                  */
+/* PLL_DIV Macros														*/
+#define SET_SSEL(x)		((x)&0xF)	/* Set SSEL = 0-15 --> SCLK = VCO/SSEL  */
+
+/* VR_CTL Masks																	*/
+#define	FREQ			0x0003	/* Switching Oscillator Frequency For Regulator */
+#define	HIBERNATE		0x0000	/*              Powerdown/Bypass On-Board Regulation    */
+#define	FREQ_333		0x0001	/*              Switching Frequency Is 333 kHz                  */
+#define	FREQ_667		0x0002	/*              Switching Frequency Is 667 kHz                  */
+#define	FREQ_1000		0x0003	/*              Switching Frequency Is 1 MHz                    */
+
+#define GAIN			0x000C	/* Voltage Level Gain   */
+#define	GAIN_5			0x0000	/*              GAIN = 5                */
+#define	GAIN_10			0x0004	/*              GAIN = 10               */
+#define	GAIN_20			0x0008	/*              GAIN = 20               */
+#define	GAIN_50			0x000C	/*              GAIN = 50               */
+
+#define	VLEV			0x00F0	/* Internal Voltage Level                                       */
+#define	VLEV_085 		0x0060	/*              VLEV = 0.85 V (-5% - +10% Accuracy)     */
+#define	VLEV_090		0x0070	/*              VLEV = 0.90 V (-5% - +10% Accuracy)     */
+#define	VLEV_095		0x0080	/*              VLEV = 0.95 V (-5% - +10% Accuracy)     */
+#define	VLEV_100		0x0090	/*              VLEV = 1.00 V (-5% - +10% Accuracy)     */
+#define	VLEV_105		0x00A0	/*              VLEV = 1.05 V (-5% - +10% Accuracy)     */
+#define	VLEV_110		0x00B0	/*              VLEV = 1.10 V (-5% - +10% Accuracy)     */
+#define	VLEV_115		0x00C0	/*              VLEV = 1.15 V (-5% - +10% Accuracy)     */
+#define	VLEV_120		0x00D0	/*              VLEV = 1.20 V (-5% - +10% Accuracy)     */
+#define	VLEV_125		0x00E0	/*              VLEV = 1.25 V (-5% - +10% Accuracy)     */
+#define	VLEV_130		0x00F0	/*              VLEV = 1.30 V (-5% - +10% Accuracy)     */
+
+#define	WAKE			0x0100	/* Enable RTC/Reset Wakeup From Hibernate       */
+#define PHYWE			0x0200	/* Enable PHY Wakeup From Hibernate                     */
+#define	CANWE			0x0400	/* Enable CAN Wakeup From Hibernate                     */
+#define	PHYCLKOE		0x4000	/* PHY Clock Output Enable                                      */
+#define	CKELOW			0x8000	/* Enable Drive CKE Low During Reset            */
+
+/* PLL_STAT Masks																	*/
+#define ACTIVE_PLLENABLED	0x0001	/* Processor In Active Mode With PLL Enabled    */
+#define	FULL_ON				0x0002	/* Processor In Full On Mode                                    */
+#define ACTIVE_PLLDISABLED	0x0004	/* Processor In Active Mode With PLL Disabled   */
+#define	PLL_LOCKED			0x0020	/* PLL_LOCKCNT Has Been Reached                                 */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION         0xF0000000
+#define CHIPID_FAMILY          0x0FFFF000
+#define CHIPID_MANUFACTURE     0x00000FFE
+
+/* SWRST Masks																		*/
+#define SYSTEM_RESET		0x0007	/* Initiates A System Software Reset                    */
+#define	DOUBLE_FAULT		0x0008	/* Core Double Fault Causes Reset                               */
+#define RESET_DOUBLE		0x2000	/* SW Reset Generated By Core Double-Fault              */
+#define RESET_WDOG			0x4000	/* SW Reset Generated By Watchdog Timer                 */
+#define RESET_SOFTWARE		0x8000	/* SW Reset Occurred Since Last Read Of SWRST   */
+
+/* SYSCR Masks																				*/
+#define BMODE				0x0006	/* Boot Mode - Latched During HW Reset From Mode Pins   */
+#define	NOBOOT				0x0010	/* Execute From L1 or ASYNC Bank 0 When BMODE = 0               */
+
+/* *************  SYSTEM INTERRUPT CONTROLLER MASKS *************************************/
+
+/* SIC_IAR0 Macros															*/
+#define P0_IVG(x)		(((x)&0xF)-7)	/* Peripheral #0 assigned IVG #x        */
+#define P1_IVG(x)		(((x)&0xF)-7) << 0x4	/* Peripheral #1 assigned IVG #x        */
+#define P2_IVG(x)		(((x)&0xF)-7) << 0x8	/* Peripheral #2 assigned IVG #x        */
+#define P3_IVG(x)		(((x)&0xF)-7) << 0xC	/* Peripheral #3 assigned IVG #x        */
+#define P4_IVG(x)		(((x)&0xF)-7) << 0x10	/* Peripheral #4 assigned IVG #x        */
+#define P5_IVG(x)		(((x)&0xF)-7) << 0x14	/* Peripheral #5 assigned IVG #x        */
+#define P6_IVG(x)		(((x)&0xF)-7) << 0x18	/* Peripheral #6 assigned IVG #x        */
+#define P7_IVG(x)		(((x)&0xF)-7) << 0x1C	/* Peripheral #7 assigned IVG #x        */
+
+/* SIC_IAR1 Macros															*/
+#define P8_IVG(x)		(((x)&0xF)-7)	/* Peripheral #8 assigned IVG #x        */
+#define P9_IVG(x)		(((x)&0xF)-7) << 0x4	/* Peripheral #9 assigned IVG #x        */
+#define P10_IVG(x)		(((x)&0xF)-7) << 0x8	/* Peripheral #10 assigned IVG #x       */
+#define P11_IVG(x)		(((x)&0xF)-7) << 0xC	/* Peripheral #11 assigned IVG #x       */
+#define P12_IVG(x)		(((x)&0xF)-7) << 0x10	/* Peripheral #12 assigned IVG #x       */
+#define P13_IVG(x)		(((x)&0xF)-7) << 0x14	/* Peripheral #13 assigned IVG #x       */
+#define P14_IVG(x)		(((x)&0xF)-7) << 0x18	/* Peripheral #14 assigned IVG #x       */
+#define P15_IVG(x)		(((x)&0xF)-7) << 0x1C	/* Peripheral #15 assigned IVG #x       */
+
+/* SIC_IAR2 Macros															*/
+#define P16_IVG(x)		(((x)&0xF)-7)	/* Peripheral #16 assigned IVG #x       */
+#define P17_IVG(x)		(((x)&0xF)-7) << 0x4	/* Peripheral #17 assigned IVG #x       */
+#define P18_IVG(x)		(((x)&0xF)-7) << 0x8	/* Peripheral #18 assigned IVG #x       */
+#define P19_IVG(x)		(((x)&0xF)-7) << 0xC	/* Peripheral #19 assigned IVG #x       */
+#define P20_IVG(x)		(((x)&0xF)-7) << 0x10	/* Peripheral #20 assigned IVG #x       */
+#define P21_IVG(x)		(((x)&0xF)-7) << 0x14	/* Peripheral #21 assigned IVG #x       */
+#define P22_IVG(x)		(((x)&0xF)-7) << 0x18	/* Peripheral #22 assigned IVG #x       */
+#define P23_IVG(x)		(((x)&0xF)-7) << 0x1C	/* Peripheral #23 assigned IVG #x       */
+
+/* SIC_IAR3 Macros															*/
+#define P24_IVG(x)		(((x)&0xF)-7)	/* Peripheral #24 assigned IVG #x       */
+#define P25_IVG(x)		(((x)&0xF)-7) << 0x4	/* Peripheral #25 assigned IVG #x       */
+#define P26_IVG(x)		(((x)&0xF)-7) << 0x8	/* Peripheral #26 assigned IVG #x       */
+#define P27_IVG(x)		(((x)&0xF)-7) << 0xC	/* Peripheral #27 assigned IVG #x       */
+#define P28_IVG(x)		(((x)&0xF)-7) << 0x10	/* Peripheral #28 assigned IVG #x       */
+#define P29_IVG(x)		(((x)&0xF)-7) << 0x14	/* Peripheral #29 assigned IVG #x       */
+#define P30_IVG(x)		(((x)&0xF)-7) << 0x18	/* Peripheral #30 assigned IVG #x       */
+#define P31_IVG(x)		(((x)&0xF)-7) << 0x1C	/* Peripheral #31 assigned IVG #x       */
+
+/* SIC_IMASK Masks																		*/
+#define SIC_UNMASK_ALL	0x00000000	/* Unmask all peripheral interrupts     */
+#define SIC_MASK_ALL	0xFFFFFFFF	/* Mask all peripheral interrupts       */
+#define SIC_MASK(x)		(1 << ((x)&0x1F))	/* Mask Peripheral #x interrupt         */
+#define SIC_UNMASK(x)	(0xFFFFFFFF ^ (1 << ((x)&0x1F)))	/* Unmask Peripheral #x interrupt       */
+
+/* SIC_IWR Masks																		*/
+#define IWR_DISABLE_ALL	0x00000000	/* Wakeup Disable all peripherals       */
+#define IWR_ENABLE_ALL	0xFFFFFFFF	/* Wakeup Enable all peripherals        */
+#define IWR_ENABLE(x)	(1 << ((x)&0x1F))	/* Wakeup Enable Peripheral #x          */
+#define IWR_DISABLE(x)	(0xFFFFFFFF ^ (1 << ((x)&0x1F)))	/* Wakeup Disable Peripheral #x         */
+
+/* ***************  WATCHDOG TIMER MASKS  *******************************************/
+/* WDOG_CTL Masks																	*/
+#define WDOG_RESET		0x0000	/* Generate Reset Event                                                 */
+#define WDOG_NMI		0x0002	/* Generate Non-Maskable Interrupt (NMI) Event  */
+#define WDOG_GPI		0x0004	/* Generate General Purpose (GP) Interrupt              */
+#define WDOG_NONE		0x0006	/* Disable Watchdog Timer Interrupts                    */
+#define TMR_EN			0x0FF0	/* Watchdog Counter Enable                                              */
+#define	TMR_DIS			0x0AD0	/* Watchdog Counter Disable                                             */
+#define TRO			0x8000	/* Watchdog Expired                                                     */
+
+/* ************** UART CONTROLLER MASKS *************************/
+/* UARTx_LCR Masks												*/
+#define WLS(x)		((((x)&0x3)-5) & 0x03)	/* Word Length Select   */
+#define STB			0x04	/* Stop Bits                    */
+#define PEN			0x08	/* Parity Enable                */
+#define EPS			0x10	/* Even Parity Select   */
+#define STP			0x20	/* Stick Parity                 */
+#define SB			0x40	/* Set Break                    */
+#define DLAB		0x80	/* Divisor Latch Access */
+
+/* UARTx_MCR Mask										*/
+#define LOOP		0x10	/* Loopback Mode Enable         */
+
+/* UARTx_LSR Masks										*/
+#define DR			0x01	/* Data Ready                           */
+#define OE			0x02	/* Overrun Error                        */
+#define PE			0x04	/* Parity Error                         */
+#define FE			0x08	/* Framing Error                        */
+#define BI			0x10	/* Break Interrupt                      */
+#define THRE		0x20	/* THR Empty                            */
+#define TEMT		0x40	/* TSR and UART_THR Empty       */
+
+/* UARTx_IER Masks															*/
+#define ERBFI		0x01	/* Enable Receive Buffer Full Interrupt         */
+#define ETBEI		0x02	/* Enable Transmit Buffer Empty Interrupt       */
+#define ELSI		0x04	/* Enable RX Status Interrupt                           */
+
+/* UARTx_IIR Masks														*/
+#define NINT		0x01	/* Pending Interrupt                                    */
+#define IIR_TX_READY    0x02	/* UART_THR empty                               */
+#define IIR_RX_READY    0x04	/* Receive data ready                           */
+#define IIR_LINE_CHANGE 0x06	/* Receive line status                          */
+#define IIR_STATUS	0x06
+
+/* UARTx_GCTL Masks													*/
+#define UCEN		0x01	/* Enable UARTx Clocks                          */
+#define IREN		0x02	/* Enable IrDA Mode                                     */
+#define TPOLC		0x04	/* IrDA TX Polarity Change                      */
+#define RPOLC		0x08	/* IrDA RX Polarity Change                      */
+#define FPE			0x10	/* Force Parity Error On Transmit       */
+#define FFE			0x20	/* Force Framing Error On Transmit      */
+
+/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  ****************************/
+/* SPI_CTL Masks																	*/
+#define	TIMOD		0x0003	/* Transfer Initiate Mode                                                       */
+#define RDBR_CORE	0x0000	/*              RDBR Read Initiates, IRQ When RDBR Full         */
+#define	TDBR_CORE	0x0001	/*              TDBR Write Initiates, IRQ When TDBR Empty       */
+#define RDBR_DMA	0x0002	/*              DMA Read, DMA Until FIFO Empty                          */
+#define TDBR_DMA	0x0003	/*              DMA Write, DMA Until FIFO Full                          */
+#define SZ			0x0004	/* Send Zero (When TDBR Empty, Send Zero/Last*)         */
+#define GM			0x0008	/* Get More (When RDBR Full, Overwrite/Discard*)        */
+#define PSSE		0x0010	/* Slave-Select Input Enable                                            */
+#define EMISO		0x0020	/* Enable MISO As Output                                                        */
+#define SPI_SIZE	0x0100	/* Size of Words (16/8* Bits)                                           */
+#define LSBF		0x0200	/* LSB First                                                                            */
+#define CPHA		0x0400	/* Clock Phase                                                                          */
+#define CPOL		0x0800	/* Clock Polarity                                                                       */
+#define MSTR		0x1000	/* Master/Slave*                                                                        */
+#define WOM			0x2000	/* Write Open Drain Master                                                      */
+#define SPE			0x4000	/* SPI Enable                                                                           */
+
+/* SPI_FLG Masks																	*/
+#define FLS1		0x0002	/* Enables SPI_FLOUT1 as SPI Slave-Select Output        */
+#define FLS2		0x0004	/* Enables SPI_FLOUT2 as SPI Slave-Select Output        */
+#define FLS3		0x0008	/* Enables SPI_FLOUT3 as SPI Slave-Select Output        */
+#define FLS4		0x0010	/* Enables SPI_FLOUT4 as SPI Slave-Select Output        */
+#define FLS5		0x0020	/* Enables SPI_FLOUT5 as SPI Slave-Select Output        */
+#define FLS6		0x0040	/* Enables SPI_FLOUT6 as SPI Slave-Select Output        */
+#define FLS7		0x0080	/* Enables SPI_FLOUT7 as SPI Slave-Select Output        */
+#define FLG1		0xFDFF	/* Activates SPI_FLOUT1                                                         */
+#define FLG2		0xFBFF	/* Activates SPI_FLOUT2                                                         */
+#define FLG3		0xF7FF	/* Activates SPI_FLOUT3                                                         */
+#define FLG4		0xEFFF	/* Activates SPI_FLOUT4                                                         */
+#define FLG5		0xDFFF	/* Activates SPI_FLOUT5                                                         */
+#define FLG6		0xBFFF	/* Activates SPI_FLOUT6                                                         */
+#define FLG7		0x7FFF	/* Activates SPI_FLOUT7                                                         */
+
+/* SPI_STAT Masks																				*/
+#define SPIF		0x0001	/* SPI Finished (Single-Word Transfer Complete)                                 */
+#define MODF		0x0002	/* Mode Fault Error (Another Device Tried To Become Master)             */
+#define TXE			0x0004	/* Transmission Error (Data Sent With No New Data In TDBR)              */
+#define TXS			0x0008	/* SPI_TDBR Data Buffer Status (Full/Empty*)                                    */
+#define RBSY		0x0010	/* Receive Error (Data Received With RDBR Full)                                 */
+#define RXS			0x0020	/* SPI_RDBR Data Buffer Status (Full/Empty*)                                    */
+#define TXCOL		0x0040	/* Transmit Collision Error (Corrupt Data May Have Been Sent)   */
+
+/*  ****************  GENERAL PURPOSE TIMER MASKS  **********************/
+/* TIMER_ENABLE Masks													*/
+#define TIMEN0			0x0001	/* Enable Timer 0                                       */
+#define TIMEN1			0x0002	/* Enable Timer 1                                       */
+#define TIMEN2			0x0004	/* Enable Timer 2                                       */
+#define TIMEN3			0x0008	/* Enable Timer 3                                       */
+#define TIMEN4			0x0010	/* Enable Timer 4                                       */
+#define TIMEN5			0x0020	/* Enable Timer 5                                       */
+#define TIMEN6			0x0040	/* Enable Timer 6                                       */
+#define TIMEN7			0x0080	/* Enable Timer 7                                       */
+
+/* TIMER_DISABLE Masks													*/
+#define TIMDIS0			TIMEN0	/* Disable Timer 0                                      */
+#define TIMDIS1			TIMEN1	/* Disable Timer 1                                      */
+#define TIMDIS2			TIMEN2	/* Disable Timer 2                                      */
+#define TIMDIS3			TIMEN3	/* Disable Timer 3                                      */
+#define TIMDIS4			TIMEN4	/* Disable Timer 4                                      */
+#define TIMDIS5			TIMEN5	/* Disable Timer 5                                      */
+#define TIMDIS6			TIMEN6	/* Disable Timer 6                                      */
+#define TIMDIS7			TIMEN7	/* Disable Timer 7                                      */
+
+/* TIMER_STATUS Masks													*/
+#define TIMIL0			0x00000001	/* Timer 0 Interrupt                            */
+#define TIMIL1			0x00000002	/* Timer 1 Interrupt                            */
+#define TIMIL2			0x00000004	/* Timer 2 Interrupt                            */
+#define TIMIL3			0x00000008	/* Timer 3 Interrupt                            */
+#define TOVL_ERR0		0x00000010	/* Timer 0 Counter Overflow                     */
+#define TOVL_ERR1		0x00000020	/* Timer 1 Counter Overflow                     */
+#define TOVL_ERR2		0x00000040	/* Timer 2 Counter Overflow                     */
+#define TOVL_ERR3		0x00000080	/* Timer 3 Counter Overflow                     */
+#define TRUN0			0x00001000	/* Timer 0 Slave Enable Status          */
+#define TRUN1			0x00002000	/* Timer 1 Slave Enable Status          */
+#define TRUN2			0x00004000	/* Timer 2 Slave Enable Status          */
+#define TRUN3			0x00008000	/* Timer 3 Slave Enable Status          */
+#define TIMIL4			0x00010000	/* Timer 4 Interrupt                            */
+#define TIMIL5			0x00020000	/* Timer 5 Interrupt                            */
+#define TIMIL6			0x00040000	/* Timer 6 Interrupt                            */
+#define TIMIL7			0x00080000	/* Timer 7 Interrupt                            */
+#define TOVL_ERR4		0x00100000	/* Timer 4 Counter Overflow                     */
+#define TOVL_ERR5		0x00200000	/* Timer 5 Counter Overflow                     */
+#define TOVL_ERR6		0x00400000	/* Timer 6 Counter Overflow                     */
+#define TOVL_ERR7		0x00800000	/* Timer 7 Counter Overflow                     */
+#define TRUN4			0x10000000	/* Timer 4 Slave Enable Status          */
+#define TRUN5			0x20000000	/* Timer 5 Slave Enable Status          */
+#define TRUN6			0x40000000	/* Timer 6 Slave Enable Status          */
+#define TRUN7			0x80000000	/* Timer 7 Slave Enable Status          */
+
+/* TIMERx_CONFIG Masks													*/
+#define PWM_OUT			0x0001	/* Pulse-Width Modulation Output Mode   */
+#define WDTH_CAP		0x0002	/* Width Capture Input Mode                             */
+#define EXT_CLK			0x0003	/* External Clock Mode                                  */
+#define PULSE_HI		0x0004	/* Action Pulse (Positive/Negative*)    */
+#define PERIOD_CNT		0x0008	/* Period Count                                                 */
+#define IRQ_ENA			0x0010	/* Interrupt Request Enable                             */
+#define TIN_SEL			0x0020	/* Timer Input Select                                   */
+#define OUT_DIS			0x0040	/* Output Pad Disable                                   */
+#define CLK_SEL			0x0080	/* Timer Clock Select                                   */
+#define TOGGLE_HI		0x0100	/* PWM_OUT PULSE_HI Toggle Mode                 */
+#define EMU_RUN			0x0200	/* Emulation Behavior Select                    */
+#define ERR_TYP			0xC000	/* Error Type                                                   */
+
+/* ******************   GPIO PORTS F, G, H MASKS  ***********************/
+/*  General Purpose IO (0xFFC00700 - 0xFFC007FF)  Masks 				*/
+/* Port F Masks 														*/
+#define PF0		0x0001
+#define PF1		0x0002
+#define PF2		0x0004
+#define PF3		0x0008
+#define PF4		0x0010
+#define PF5		0x0020
+#define PF6		0x0040
+#define PF7		0x0080
+#define PF8		0x0100
+#define PF9		0x0200
+#define PF10	0x0400
+#define PF11	0x0800
+#define PF12	0x1000
+#define PF13	0x2000
+#define PF14	0x4000
+#define PF15	0x8000
+
+/* Port G Masks															*/
+#define PG0		0x0001
+#define PG1		0x0002
+#define PG2		0x0004
+#define PG3		0x0008
+#define PG4		0x0010
+#define PG5		0x0020
+#define PG6		0x0040
+#define PG7		0x0080
+#define PG8		0x0100
+#define PG9		0x0200
+#define PG10	0x0400
+#define PG11	0x0800
+#define PG12	0x1000
+#define PG13	0x2000
+#define PG14	0x4000
+#define PG15	0x8000
+
+/* Port H Masks															*/
+#define PH0		0x0001
+#define PH1		0x0002
+#define PH2		0x0004
+#define PH3		0x0008
+#define PH4		0x0010
+#define PH5		0x0020
+#define PH6		0x0040
+#define PH7		0x0080
+#define PH8		0x0100
+#define PH9		0x0200
+#define PH10	0x0400
+#define PH11	0x0800
+#define PH12	0x1000
+#define PH13	0x2000
+#define PH14	0x4000
+#define PH15	0x8000
+
+/* *******************  SERIAL PORT MASKS  **************************************/
+/* SPORTx_TCR1 Masks															*/
+#define TSPEN		0x0001	/* Transmit Enable                                                              */
+#define ITCLK		0x0002	/* Internal Transmit Clock Select                               */
+#define DTYPE_NORM	0x0004	/* Data Format Normal                                                   */
+#define DTYPE_ULAW	0x0008	/* Compand Using u-Law                                                  */
+#define DTYPE_ALAW	0x000C	/* Compand Using A-Law                                                  */
+#define TLSBIT		0x0010	/* Transmit Bit Order                                                   */
+#define ITFS		0x0200	/* Internal Transmit Frame Sync Select                  */
+#define TFSR		0x0400	/* Transmit Frame Sync Required Select                  */
+#define DITFS		0x0800	/* Data-Independent Transmit Frame Sync Select  */
+#define LTFS		0x1000	/* Low Transmit Frame Sync Select                               */
+#define LATFS		0x2000	/* Late Transmit Frame Sync Select                              */
+#define TCKFE		0x4000	/* Clock Falling Edge Select                                    */
+
+/* SPORTx_TCR2 Masks and Macro													*/
+#define SLEN(x)		((x)&0x1F)	/* SPORT TX Word Length (2 - 31)                                */
+#define TXSE		0x0100	/* TX Secondary Enable                                                  */
+#define TSFSE		0x0200	/* Transmit Stereo Frame Sync Enable                    */
+#define TRFST		0x0400	/* Left/Right Order (1 = Right Channel 1st)             */
+
+/* SPORTx_RCR1 Masks															*/
+#define RSPEN		0x0001	/* Receive Enable                                                               */
+#define IRCLK		0x0002	/* Internal Receive Clock Select                                */
+#define DTYPE_NORM	0x0004	/* Data Format Normal                                                   */
+#define DTYPE_ULAW	0x0008	/* Compand Using u-Law                                                  */
+#define DTYPE_ALAW	0x000C	/* Compand Using A-Law                                                  */
+#define RLSBIT		0x0010	/* Receive Bit Order                                                    */
+#define IRFS		0x0200	/* Internal Receive Frame Sync Select                   */
+#define RFSR		0x0400	/* Receive Frame Sync Required Select                   */
+#define LRFS		0x1000	/* Low Receive Frame Sync Select                                */
+#define LARFS		0x2000	/* Late Receive Frame Sync Select                               */
+#define RCKFE		0x4000	/* Clock Falling Edge Select                                    */
+
+/* SPORTx_RCR2 Masks															*/
+#define SLEN(x)		((x)&0x1F)	/* SPORT RX Word Length (2 - 31)                                */
+#define RXSE		0x0100	/* RX Secondary Enable                                                  */
+#define RSFSE		0x0200	/* RX Stereo Frame Sync Enable                                  */
+#define RRFST		0x0400	/* Right-First Data Order                                               */
+
+/* SPORTx_STAT Masks															*/
+#define RXNE		0x0001	/* Receive FIFO Not Empty Status                                */
+#define RUVF		0x0002	/* Sticky Receive Underflow Status                              */
+#define ROVF		0x0004	/* Sticky Receive Overflow Status                               */
+#define TXF			0x0008	/* Transmit FIFO Full Status                                    */
+#define TUVF		0x0010	/* Sticky Transmit Underflow Status                             */
+#define TOVF		0x0020	/* Sticky Transmit Overflow Status                              */
+#define TXHRE		0x0040	/* Transmit Hold Register Empty                                 */
+
+/* SPORTx_MCMC1 Macros															*/
+#define SP_WOFF(x)		((x) & 0x3FF)	/* Multichannel Window Offset Field                     */
+
+/* Only use WSIZE Macro With Logic OR While Setting Lower Order Bits						*/
+#define SP_WSIZE(x)	(((((x)>>0x3)-1)&0xF) << 0xC)	/* Multichannel Window Size = (x/8)-1   */
+
+/* SPORTx_MCMC2 Masks															*/
+#define REC_BYPASS	0x0000	/* Bypass Mode (No Clock Recovery)                              */
+#define REC_2FROM4	0x0002	/* Recover 2 MHz Clock from 4 MHz Clock                 */
+#define REC_8FROM16	0x0003	/* Recover 8 MHz Clock from 16 MHz Clock                */
+#define MCDTXPE		0x0004	/* Multichannel DMA Transmit Packing                    */
+#define MCDRXPE		0x0008	/* Multichannel DMA Receive Packing                             */
+#define MCMEN		0x0010	/* Multichannel Frame Mode Enable                               */
+#define FSDR		0x0080	/* Multichannel Frame Sync to Data Relationship */
+#define MFD_0		0x0000	/* Multichannel Frame Delay = 0                                 */
+#define MFD_1		0x1000	/* Multichannel Frame Delay = 1                                 */
+#define MFD_2		0x2000	/* Multichannel Frame Delay = 2                                 */
+#define MFD_3		0x3000	/* Multichannel Frame Delay = 3                                 */
+#define MFD_4		0x4000	/* Multichannel Frame Delay = 4                                 */
+#define MFD_5		0x5000	/* Multichannel Frame Delay = 5                                 */
+#define MFD_6		0x6000	/* Multichannel Frame Delay = 6                                 */
+#define MFD_7		0x7000	/* Multichannel Frame Delay = 7                                 */
+#define MFD_8		0x8000	/* Multichannel Frame Delay = 8                                 */
+#define MFD_9		0x9000	/* Multichannel Frame Delay = 9                                 */
+#define MFD_10		0xA000	/* Multichannel Frame Delay = 10                                */
+#define MFD_11		0xB000	/* Multichannel Frame Delay = 11                                */
+#define MFD_12		0xC000	/* Multichannel Frame Delay = 12                                */
+#define MFD_13		0xD000	/* Multichannel Frame Delay = 13                                */
+#define MFD_14		0xE000	/* Multichannel Frame Delay = 14                                */
+#define MFD_15		0xF000	/* Multichannel Frame Delay = 15                                */
+
+/* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS  *************************/
+/* EBIU_AMGCTL Masks																	*/
+#define AMCKEN			0x0001	/* Enable CLKOUT                                                                        */
+#define	AMBEN_NONE		0x0000	/* All Banks Disabled                                                           */
+#define AMBEN_B0		0x0002	/* Enable Async Memory Bank 0 only                                      */
+#define AMBEN_B0_B1		0x0004	/* Enable Async Memory Banks 0 & 1 only                         */
+#define AMBEN_B0_B1_B2	0x0006	/* Enable Async Memory Banks 0, 1, and 2                        */
+#define AMBEN_ALL		0x0008	/* Enable Async Memory Banks (all) 0, 1, 2, and 3       */
+
+/* EBIU_AMBCTL0 Masks																	*/
+#define B0RDYEN			0x00000001	/* Bank 0 (B0) RDY Enable                                                   */
+#define B0RDYPOL		0x00000002	/* B0 RDY Active High                                                               */
+#define B0TT_1			0x00000004	/* B0 Transition Time (Read to Write) = 1 cycle             */
+#define B0TT_2			0x00000008	/* B0 Transition Time (Read to Write) = 2 cycles    */
+#define B0TT_3			0x0000000C	/* B0 Transition Time (Read to Write) = 3 cycles    */
+#define B0TT_4			0x00000000	/* B0 Transition Time (Read to Write) = 4 cycles    */
+#define B0ST_1			0x00000010	/* B0 Setup Time (AOE to Read/Write) = 1 cycle              */
+#define B0ST_2			0x00000020	/* B0 Setup Time (AOE to Read/Write) = 2 cycles             */
+#define B0ST_3			0x00000030	/* B0 Setup Time (AOE to Read/Write) = 3 cycles             */
+#define B0ST_4			0x00000000	/* B0 Setup Time (AOE to Read/Write) = 4 cycles             */
+#define B0HT_1			0x00000040	/* B0 Hold Time (~Read/Write to ~AOE) = 1 cycle             */
+#define B0HT_2			0x00000080	/* B0 Hold Time (~Read/Write to ~AOE) = 2 cycles    */
+#define B0HT_3			0x000000C0	/* B0 Hold Time (~Read/Write to ~AOE) = 3 cycles    */
+#define B0HT_0			0x00000000	/* B0 Hold Time (~Read/Write to ~AOE) = 0 cycles    */
+#define B0RAT_1			0x00000100	/* B0 Read Access Time = 1 cycle                                    */
+#define B0RAT_2			0x00000200	/* B0 Read Access Time = 2 cycles                                   */
+#define B0RAT_3			0x00000300	/* B0 Read Access Time = 3 cycles                                   */
+#define B0RAT_4			0x00000400	/* B0 Read Access Time = 4 cycles                                   */
+#define B0RAT_5			0x00000500	/* B0 Read Access Time = 5 cycles                                   */
+#define B0RAT_6			0x00000600	/* B0 Read Access Time = 6 cycles                                   */
+#define B0RAT_7			0x00000700	/* B0 Read Access Time = 7 cycles                                   */
+#define B0RAT_8			0x00000800	/* B0 Read Access Time = 8 cycles                                   */
+#define B0RAT_9			0x00000900	/* B0 Read Access Time = 9 cycles                                   */
+#define B0RAT_10		0x00000A00	/* B0 Read Access Time = 10 cycles                                  */
+#define B0RAT_11		0x00000B00	/* B0 Read Access Time = 11 cycles                                  */
+#define B0RAT_12		0x00000C00	/* B0 Read Access Time = 12 cycles                                  */
+#define B0RAT_13		0x00000D00	/* B0 Read Access Time = 13 cycles                                  */
+#define B0RAT_14		0x00000E00	/* B0 Read Access Time = 14 cycles                                  */
+#define B0RAT_15		0x00000F00	/* B0 Read Access Time = 15 cycles                                  */
+#define B0WAT_1			0x00001000	/* B0 Write Access Time = 1 cycle                                   */
+#define B0WAT_2			0x00002000	/* B0 Write Access Time = 2 cycles                                  */
+#define B0WAT_3			0x00003000	/* B0 Write Access Time = 3 cycles                                  */
+#define B0WAT_4			0x00004000	/* B0 Write Access Time = 4 cycles                                  */
+#define B0WAT_5			0x00005000	/* B0 Write Access Time = 5 cycles                                  */
+#define B0WAT_6			0x00006000	/* B0 Write Access Time = 6 cycles                                  */
+#define B0WAT_7			0x00007000	/* B0 Write Access Time = 7 cycles                                  */
+#define B0WAT_8			0x00008000	/* B0 Write Access Time = 8 cycles                                  */
+#define B0WAT_9			0x00009000	/* B0 Write Access Time = 9 cycles                                  */
+#define B0WAT_10		0x0000A000	/* B0 Write Access Time = 10 cycles                                 */
+#define B0WAT_11		0x0000B000	/* B0 Write Access Time = 11 cycles                                 */
+#define B0WAT_12		0x0000C000	/* B0 Write Access Time = 12 cycles                                 */
+#define B0WAT_13		0x0000D000	/* B0 Write Access Time = 13 cycles                                 */
+#define B0WAT_14		0x0000E000	/* B0 Write Access Time = 14 cycles                                 */
+#define B0WAT_15		0x0000F000	/* B0 Write Access Time = 15 cycles                                 */
+
+#define B1RDYEN			0x00010000	/* Bank 1 (B1) RDY Enable                           */
+#define B1RDYPOL		0x00020000	/* B1 RDY Active High                               */
+#define B1TT_1			0x00040000	/* B1 Transition Time (Read to Write) = 1 cycle     */
+#define B1TT_2			0x00080000	/* B1 Transition Time (Read to Write) = 2 cycles    */
+#define B1TT_3			0x000C0000	/* B1 Transition Time (Read to Write) = 3 cycles    */
+#define B1TT_4			0x00000000	/* B1 Transition Time (Read to Write) = 4 cycles    */
+#define B1ST_1			0x00100000	/* B1 Setup Time (AOE to Read/Write) = 1 cycle      */
+#define B1ST_2			0x00200000	/* B1 Setup Time (AOE to Read/Write) = 2 cycles     */
+#define B1ST_3			0x00300000	/* B1 Setup Time (AOE to Read/Write) = 3 cycles     */
+#define B1ST_4			0x00000000	/* B1 Setup Time (AOE to Read/Write) = 4 cycles     */
+#define B1HT_1			0x00400000	/* B1 Hold Time (~Read/Write to ~AOE) = 1 cycle     */
+#define B1HT_2			0x00800000	/* B1 Hold Time (~Read/Write to ~AOE) = 2 cycles    */
+#define B1HT_3			0x00C00000	/* B1 Hold Time (~Read/Write to ~AOE) = 3 cycles    */
+#define B1HT_0			0x00000000	/* B1 Hold Time (~Read/Write to ~AOE) = 0 cycles    */
+#define B1RAT_1			0x01000000	/* B1 Read Access Time = 1 cycle                                    */
+#define B1RAT_2			0x02000000	/* B1 Read Access Time = 2 cycles                                   */
+#define B1RAT_3			0x03000000	/* B1 Read Access Time = 3 cycles                                   */
+#define B1RAT_4			0x04000000	/* B1 Read Access Time = 4 cycles                                   */
+#define B1RAT_5			0x05000000	/* B1 Read Access Time = 5 cycles                                   */
+#define B1RAT_6			0x06000000	/* B1 Read Access Time = 6 cycles                                   */
+#define B1RAT_7			0x07000000	/* B1 Read Access Time = 7 cycles                                   */
+#define B1RAT_8			0x08000000	/* B1 Read Access Time = 8 cycles                                   */
+#define B1RAT_9			0x09000000	/* B1 Read Access Time = 9 cycles                                   */
+#define B1RAT_10		0x0A000000	/* B1 Read Access Time = 10 cycles                                  */
+#define B1RAT_11		0x0B000000	/* B1 Read Access Time = 11 cycles                                  */
+#define B1RAT_12		0x0C000000	/* B1 Read Access Time = 12 cycles                                  */
+#define B1RAT_13		0x0D000000	/* B1 Read Access Time = 13 cycles                                  */
+#define B1RAT_14		0x0E000000	/* B1 Read Access Time = 14 cycles                                  */
+#define B1RAT_15		0x0F000000	/* B1 Read Access Time = 15 cycles                                  */
+#define B1WAT_1			0x10000000	/* B1 Write Access Time = 1 cycle                                   */
+#define B1WAT_2			0x20000000	/* B1 Write Access Time = 2 cycles                                  */
+#define B1WAT_3			0x30000000	/* B1 Write Access Time = 3 cycles                                  */
+#define B1WAT_4			0x40000000	/* B1 Write Access Time = 4 cycles                                  */
+#define B1WAT_5			0x50000000	/* B1 Write Access Time = 5 cycles                                  */
+#define B1WAT_6			0x60000000	/* B1 Write Access Time = 6 cycles                                  */
+#define B1WAT_7			0x70000000	/* B1 Write Access Time = 7 cycles                                  */
+#define B1WAT_8			0x80000000	/* B1 Write Access Time = 8 cycles                                  */
+#define B1WAT_9			0x90000000	/* B1 Write Access Time = 9 cycles                                  */
+#define B1WAT_10		0xA0000000	/* B1 Write Access Time = 10 cycles                                 */
+#define B1WAT_11		0xB0000000	/* B1 Write Access Time = 11 cycles                                 */
+#define B1WAT_12		0xC0000000	/* B1 Write Access Time = 12 cycles                                 */
+#define B1WAT_13		0xD0000000	/* B1 Write Access Time = 13 cycles                                 */
+#define B1WAT_14		0xE0000000	/* B1 Write Access Time = 14 cycles                                 */
+#define B1WAT_15		0xF0000000	/* B1 Write Access Time = 15 cycles                                 */
+
+/* EBIU_AMBCTL1 Masks																	*/
+#define B2RDYEN			0x00000001	/* Bank 2 (B2) RDY Enable                                                   */
+#define B2RDYPOL		0x00000002	/* B2 RDY Active High                                                               */
+#define B2TT_1			0x00000004	/* B2 Transition Time (Read to Write) = 1 cycle             */
+#define B2TT_2			0x00000008	/* B2 Transition Time (Read to Write) = 2 cycles    */
+#define B2TT_3			0x0000000C	/* B2 Transition Time (Read to Write) = 3 cycles    */
+#define B2TT_4			0x00000000	/* B2 Transition Time (Read to Write) = 4 cycles    */
+#define B2ST_1			0x00000010	/* B2 Setup Time (AOE to Read/Write) = 1 cycle              */
+#define B2ST_2			0x00000020	/* B2 Setup Time (AOE to Read/Write) = 2 cycles             */
+#define B2ST_3			0x00000030	/* B2 Setup Time (AOE to Read/Write) = 3 cycles             */
+#define B2ST_4			0x00000000	/* B2 Setup Time (AOE to Read/Write) = 4 cycles             */
+#define B2HT_1			0x00000040	/* B2 Hold Time (~Read/Write to ~AOE) = 1 cycle             */
+#define B2HT_2			0x00000080	/* B2 Hold Time (~Read/Write to ~AOE) = 2 cycles    */
+#define B2HT_3			0x000000C0	/* B2 Hold Time (~Read/Write to ~AOE) = 3 cycles    */
+#define B2HT_0			0x00000000	/* B2 Hold Time (~Read/Write to ~AOE) = 0 cycles    */
+#define B2RAT_1			0x00000100	/* B2 Read Access Time = 1 cycle                                    */
+#define B2RAT_2			0x00000200	/* B2 Read Access Time = 2 cycles                                   */
+#define B2RAT_3			0x00000300	/* B2 Read Access Time = 3 cycles                                   */
+#define B2RAT_4			0x00000400	/* B2 Read Access Time = 4 cycles                                   */
+#define B2RAT_5			0x00000500	/* B2 Read Access Time = 5 cycles                                   */
+#define B2RAT_6			0x00000600	/* B2 Read Access Time = 6 cycles                                   */
+#define B2RAT_7			0x00000700	/* B2 Read Access Time = 7 cycles                                   */
+#define B2RAT_8			0x00000800	/* B2 Read Access Time = 8 cycles                                   */
+#define B2RAT_9			0x00000900	/* B2 Read Access Time = 9 cycles                                   */
+#define B2RAT_10		0x00000A00	/* B2 Read Access Time = 10 cycles                                  */
+#define B2RAT_11		0x00000B00	/* B2 Read Access Time = 11 cycles                                  */
+#define B2RAT_12		0x00000C00	/* B2 Read Access Time = 12 cycles                                  */
+#define B2RAT_13		0x00000D00	/* B2 Read Access Time = 13 cycles                                  */
+#define B2RAT_14		0x00000E00	/* B2 Read Access Time = 14 cycles                                  */
+#define B2RAT_15		0x00000F00	/* B2 Read Access Time = 15 cycles                                  */
+#define B2WAT_1			0x00001000	/* B2 Write Access Time = 1 cycle                                   */
+#define B2WAT_2			0x00002000	/* B2 Write Access Time = 2 cycles                                  */
+#define B2WAT_3			0x00003000	/* B2 Write Access Time = 3 cycles                                  */
+#define B2WAT_4			0x00004000	/* B2 Write Access Time = 4 cycles                                  */
+#define B2WAT_5			0x00005000	/* B2 Write Access Time = 5 cycles                                  */
+#define B2WAT_6			0x00006000	/* B2 Write Access Time = 6 cycles                                  */
+#define B2WAT_7			0x00007000	/* B2 Write Access Time = 7 cycles                                  */
+#define B2WAT_8			0x00008000	/* B2 Write Access Time = 8 cycles                                  */
+#define B2WAT_9			0x00009000	/* B2 Write Access Time = 9 cycles                                  */
+#define B2WAT_10		0x0000A000	/* B2 Write Access Time = 10 cycles                                 */
+#define B2WAT_11		0x0000B000	/* B2 Write Access Time = 11 cycles                                 */
+#define B2WAT_12		0x0000C000	/* B2 Write Access Time = 12 cycles                                 */
+#define B2WAT_13		0x0000D000	/* B2 Write Access Time = 13 cycles                                 */
+#define B2WAT_14		0x0000E000	/* B2 Write Access Time = 14 cycles                                 */
+#define B2WAT_15		0x0000F000	/* B2 Write Access Time = 15 cycles                                 */
+
+#define B3RDYEN			0x00010000	/* Bank 3 (B3) RDY Enable                                                   */
+#define B3RDYPOL		0x00020000	/* B3 RDY Active High                                                               */
+#define B3TT_1			0x00040000	/* B3 Transition Time (Read to Write) = 1 cycle             */
+#define B3TT_2			0x00080000	/* B3 Transition Time (Read to Write) = 2 cycles    */
+#define B3TT_3			0x000C0000	/* B3 Transition Time (Read to Write) = 3 cycles    */
+#define B3TT_4			0x00000000	/* B3 Transition Time (Read to Write) = 4 cycles    */
+#define B3ST_1			0x00100000	/* B3 Setup Time (AOE to Read/Write) = 1 cycle              */
+#define B3ST_2			0x00200000	/* B3 Setup Time (AOE to Read/Write) = 2 cycles             */
+#define B3ST_3			0x00300000	/* B3 Setup Time (AOE to Read/Write) = 3 cycles             */
+#define B3ST_4			0x00000000	/* B3 Setup Time (AOE to Read/Write) = 4 cycles             */
+#define B3HT_1			0x00400000	/* B3 Hold Time (~Read/Write to ~AOE) = 1 cycle             */
+#define B3HT_2			0x00800000	/* B3 Hold Time (~Read/Write to ~AOE) = 2 cycles    */
+#define B3HT_3			0x00C00000	/* B3 Hold Time (~Read/Write to ~AOE) = 3 cycles    */
+#define B3HT_0			0x00000000	/* B3 Hold Time (~Read/Write to ~AOE) = 0 cycles    */
+#define B3RAT_1			0x01000000	/* B3 Read Access Time = 1 cycle                                    */
+#define B3RAT_2			0x02000000	/* B3 Read Access Time = 2 cycles                                   */
+#define B3RAT_3			0x03000000	/* B3 Read Access Time = 3 cycles                                   */
+#define B3RAT_4			0x04000000	/* B3 Read Access Time = 4 cycles                                   */
+#define B3RAT_5			0x05000000	/* B3 Read Access Time = 5 cycles                                   */
+#define B3RAT_6			0x06000000	/* B3 Read Access Time = 6 cycles                                   */
+#define B3RAT_7			0x07000000	/* B3 Read Access Time = 7 cycles                                   */
+#define B3RAT_8			0x08000000	/* B3 Read Access Time = 8 cycles                                   */
+#define B3RAT_9			0x09000000	/* B3 Read Access Time = 9 cycles                                   */
+#define B3RAT_10		0x0A000000	/* B3 Read Access Time = 10 cycles                                  */
+#define B3RAT_11		0x0B000000	/* B3 Read Access Time = 11 cycles                                  */
+#define B3RAT_12		0x0C000000	/* B3 Read Access Time = 12 cycles                                  */
+#define B3RAT_13		0x0D000000	/* B3 Read Access Time = 13 cycles                                  */
+#define B3RAT_14		0x0E000000	/* B3 Read Access Time = 14 cycles                                  */
+#define B3RAT_15		0x0F000000	/* B3 Read Access Time = 15 cycles                                  */
+#define B3WAT_1			0x10000000	/* B3 Write Access Time = 1 cycle                                   */
+#define B3WAT_2			0x20000000	/* B3 Write Access Time = 2 cycles                                  */
+#define B3WAT_3			0x30000000	/* B3 Write Access Time = 3 cycles                                  */
+#define B3WAT_4			0x40000000	/* B3 Write Access Time = 4 cycles                                  */
+#define B3WAT_5			0x50000000	/* B3 Write Access Time = 5 cycles                                  */
+#define B3WAT_6			0x60000000	/* B3 Write Access Time = 6 cycles                                  */
+#define B3WAT_7			0x70000000	/* B3 Write Access Time = 7 cycles                                  */
+#define B3WAT_8			0x80000000	/* B3 Write Access Time = 8 cycles                                  */
+#define B3WAT_9			0x90000000	/* B3 Write Access Time = 9 cycles                                  */
+#define B3WAT_10		0xA0000000	/* B3 Write Access Time = 10 cycles                                 */
+#define B3WAT_11		0xB0000000	/* B3 Write Access Time = 11 cycles                                 */
+#define B3WAT_12		0xC0000000	/* B3 Write Access Time = 12 cycles                                 */
+#define B3WAT_13		0xD0000000	/* B3 Write Access Time = 13 cycles                                 */
+#define B3WAT_14		0xE0000000	/* B3 Write Access Time = 14 cycles                                 */
+#define B3WAT_15		0xF0000000	/* B3 Write Access Time = 15 cycles                                 */
+
+/* **********************  SDRAM CONTROLLER MASKS  **********************************************/
+/* EBIU_SDGCTL Masks																			*/
+#define SCTLE			0x00000001	/* Enable SDRAM Signals                                                                         */
+#define CL_2			0x00000008	/* SDRAM CAS Latency = 2 cycles                                                         */
+#define CL_3			0x0000000C	/* SDRAM CAS Latency = 3 cycles                                                         */
+#define PASR_ALL		0x00000000	/* All 4 SDRAM Banks Refreshed In Self-Refresh                          */
+#define PASR_B0_B1		0x00000010	/* SDRAM Banks 0 and 1 Are Refreshed In Self-Refresh            */
+#define PASR_B0			0x00000020	/* Only SDRAM Bank 0 Is Refreshed In Self-Refresh                       */
+#define TRAS_1			0x00000040	/* SDRAM tRAS = 1 cycle                                                                         */
+#define TRAS_2			0x00000080	/* SDRAM tRAS = 2 cycles                                                                        */
+#define TRAS_3			0x000000C0	/* SDRAM tRAS = 3 cycles                                                                        */
+#define TRAS_4			0x00000100	/* SDRAM tRAS = 4 cycles                                                                        */
+#define TRAS_5			0x00000140	/* SDRAM tRAS = 5 cycles                                                                        */
+#define TRAS_6			0x00000180	/* SDRAM tRAS = 6 cycles                                                                        */
+#define TRAS_7			0x000001C0	/* SDRAM tRAS = 7 cycles                                                                        */
+#define TRAS_8			0x00000200	/* SDRAM tRAS = 8 cycles                                                                        */
+#define TRAS_9			0x00000240	/* SDRAM tRAS = 9 cycles                                                                        */
+#define TRAS_10			0x00000280	/* SDRAM tRAS = 10 cycles                                                                       */
+#define TRAS_11			0x000002C0	/* SDRAM tRAS = 11 cycles                                                                       */
+#define TRAS_12			0x00000300	/* SDRAM tRAS = 12 cycles                                                                       */
+#define TRAS_13			0x00000340	/* SDRAM tRAS = 13 cycles                                                                       */
+#define TRAS_14			0x00000380	/* SDRAM tRAS = 14 cycles                                                                       */
+#define TRAS_15			0x000003C0	/* SDRAM tRAS = 15 cycles                                                                       */
+#define TRP_1			0x00000800	/* SDRAM tRP = 1 cycle                                                                          */
+#define TRP_2			0x00001000	/* SDRAM tRP = 2 cycles                                                                         */
+#define TRP_3			0x00001800	/* SDRAM tRP = 3 cycles                                                                         */
+#define TRP_4			0x00002000	/* SDRAM tRP = 4 cycles                                                                         */
+#define TRP_5			0x00002800	/* SDRAM tRP = 5 cycles                                                                         */
+#define TRP_6			0x00003000	/* SDRAM tRP = 6 cycles                                                                         */
+#define TRP_7			0x00003800	/* SDRAM tRP = 7 cycles                                                                         */
+#define TRCD_1			0x00008000	/* SDRAM tRCD = 1 cycle                                                                         */
+#define TRCD_2			0x00010000	/* SDRAM tRCD = 2 cycles                                                                        */
+#define TRCD_3			0x00018000	/* SDRAM tRCD = 3 cycles                                                                        */
+#define TRCD_4			0x00020000	/* SDRAM tRCD = 4 cycles                                                                        */
+#define TRCD_5			0x00028000	/* SDRAM tRCD = 5 cycles                                                                        */
+#define TRCD_6			0x00030000	/* SDRAM tRCD = 6 cycles                                                                        */
+#define TRCD_7			0x00038000	/* SDRAM tRCD = 7 cycles                                                                        */
+#define TWR_1			0x00080000	/* SDRAM tWR = 1 cycle                                                                          */
+#define TWR_2			0x00100000	/* SDRAM tWR = 2 cycles                                                                         */
+#define TWR_3			0x00180000	/* SDRAM tWR = 3 cycles                                                                         */
+#define PUPSD			0x00200000	/* Power-Up Start Delay (15 SCLK Cycles Delay)                          */
+#define PSM				0x00400000	/* Power-Up Sequence (Mode Register Before/After* Refresh)      */
+#define PSS				0x00800000	/* Enable Power-Up Sequence on Next SDRAM Access                        */
+#define SRFS			0x01000000	/* Enable SDRAM Self-Refresh Mode                                                       */
+#define EBUFE			0x02000000	/* Enable External Buffering Timing                                                     */
+#define FBBRW			0x04000000	/* Enable Fast Back-To-Back Read To Write                                       */
+#define EMREN			0x10000000	/* Extended Mode Register Enable                                                        */
+#define TCSR			0x20000000	/* Temp-Compensated Self-Refresh Value (85/45* Deg C)           */
+#define CDDBG			0x40000000	/* Tristate SDRAM Controls During Bus Grant                                     */
+
+/* EBIU_SDBCTL Masks																		*/
+#define EBE				0x0001	/* Enable SDRAM External Bank                                                   */
+#define EBSZ_16			0x0000	/* SDRAM External Bank Size = 16MB                                              */
+#define EBSZ_32			0x0002	/* SDRAM External Bank Size = 32MB                                              */
+#define EBSZ_64			0x0004	/* SDRAM External Bank Size = 64MB                                              */
+#define EBSZ_128		0x0006	/* SDRAM External Bank Size = 128MB                                             */
+#define EBCAW_8			0x0000	/* SDRAM External Bank Column Address Width = 8 Bits    */
+#define EBCAW_9			0x0010	/* SDRAM External Bank Column Address Width = 9 Bits    */
+#define EBCAW_10		0x0020	/* SDRAM External Bank Column Address Width = 10 Bits   */
+#define EBCAW_11		0x0030	/* SDRAM External Bank Column Address Width = 11 Bits   */
+
+/* EBIU_SDSTAT Masks														*/
+#define SDCI			0x0001	/* SDRAM Controller Idle                                */
+#define SDSRA			0x0002	/* SDRAM Self-Refresh Active                    */
+#define SDPUA			0x0004	/* SDRAM Power-Up Active                                */
+#define SDRS			0x0008	/* SDRAM Will Power-Up On Next Access   */
+#define SDEASE			0x0010	/* SDRAM EAB Sticky Error Status                */
+#define BGSTAT			0x0020	/* Bus Grant Status                                             */
+
+/* **************************  DMA CONTROLLER MASKS  ********************************/
+/* DMAx_CONFIG, MDMA_yy_CONFIG Masks												*/
+#define DMAEN			0x0001	/* DMA Channel Enable                                                   */
+#define WNR				0x0002	/* Channel Direction (W/R*)                                             */
+#define WDSIZE_8		0x0000	/* Transfer Word Size = 8                                               */
+#define WDSIZE_16		0x0004	/* Transfer Word Size = 16                                              */
+#define WDSIZE_32		0x0008	/* Transfer Word Size = 32                                              */
+#define DMA2D			0x0010	/* DMA Mode (2D/1D*)                                                    */
+#define RESTART			0x0020	/* DMA Buffer Clear                                                             */
+#define DI_SEL			0x0040	/* Data Interrupt Timing Select                                 */
+#define DI_EN			0x0080	/* Data Interrupt Enable                                                */
+#define NDSIZE_0		0x0000	/* Next Descriptor Size = 0 (Stop/Autobuffer)   */
+#define NDSIZE_1		0x0100	/* Next Descriptor Size = 1                                             */
+#define NDSIZE_2		0x0200	/* Next Descriptor Size = 2                                             */
+#define NDSIZE_3		0x0300	/* Next Descriptor Size = 3                                             */
+#define NDSIZE_4		0x0400	/* Next Descriptor Size = 4                                             */
+#define NDSIZE_5		0x0500	/* Next Descriptor Size = 5                                             */
+#define NDSIZE_6		0x0600	/* Next Descriptor Size = 6                                             */
+#define NDSIZE_7		0x0700	/* Next Descriptor Size = 7                                             */
+#define NDSIZE_8		0x0800	/* Next Descriptor Size = 8                                             */
+#define NDSIZE_9		0x0900	/* Next Descriptor Size = 9                                             */
+#define NDSIZE	        	0x0900	/* Next Descriptor Size */
+
+#define DMAFLOW	        	0x7000	/* Flow Control */
+#define DMAFLOW_STOP		0x0000	/* Stop Mode */
+#define DMAFLOW_AUTO		0x1000	/* Autobuffer Mode */
+#define DMAFLOW_ARRAY		0x4000	/* Descriptor Array Mode */
+#define DMAFLOW_SMALL		0x6000	/* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE		0x7000	/* Large Model Descriptor List Mode */
+
+/* DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP Masks								*/
+#define CTYPE			0x0040	/* DMA Channel Type Indicator (Memory/Peripheral*)      */
+#define PMAP			0xF000	/* Peripheral Mapped To This Channel                            */
+#define PMAP_PPI		0x0000	/*              PPI Port DMA                                                            */
+#define	PMAP_EMACRX		0x1000	/*              Ethernet Receive DMA                                            */
+#define PMAP_EMACTX		0x2000	/*              Ethernet Transmit DMA                                           */
+#define PMAP_SPORT0RX	0x3000	/*              SPORT0 Receive DMA                                                      */
+#define PMAP_SPORT0TX	0x4000	/*              SPORT0 Transmit DMA                                                     */
+#define PMAP_SPORT1RX	0x5000	/*              SPORT1 Receive DMA                                                      */
+#define PMAP_SPORT1TX	0x6000	/*              SPORT1 Transmit DMA                                                     */
+#define PMAP_SPI		0x7000	/*              SPI Port DMA                                                            */
+#define PMAP_UART0RX	0x8000	/*              UART0 Port Receive DMA                                          */
+#define PMAP_UART0TX	0x9000	/*              UART0 Port Transmit DMA                                         */
+#define	PMAP_UART1RX	0xA000	/*              UART1 Port Receive DMA                                          */
+#define	PMAP_UART1TX	0xB000	/*              UART1 Port Transmit DMA                                         */
+
+/* DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS Masks						*/
+#define DMA_DONE		0x0001	/* DMA Completion Interrupt Status      */
+#define DMA_ERR			0x0002	/* DMA Error Interrupt Status           */
+#define DFETCH			0x0004	/* DMA Descriptor Fetch Indicator       */
+#define DMA_RUN			0x0008	/* DMA Channel Running Indicator        */
+
+/*  ************  PARALLEL PERIPHERAL INTERFACE (PPI) MASKS *************/
+/*  PPI_CONTROL Masks													*/
+#define PORT_EN			0x0001	/* PPI Port Enable                                      */
+#define PORT_DIR		0x0002	/* PPI Port Direction                           */
+#define XFR_TYPE		0x000C	/* PPI Transfer Type                            */
+#define PORT_CFG		0x0030	/* PPI Port Configuration                       */
+#define FLD_SEL			0x0040	/* PPI Active Field Select                      */
+#define PACK_EN			0x0080	/* PPI Packing Mode                                     */
+#define DMA32			0x0100	/* PPI 32-bit DMA Enable                        */
+#define SKIP_EN			0x0200	/* PPI Skip Element Enable                      */
+#define SKIP_EO			0x0400	/* PPI Skip Even/Odd Elements           */
+#define DLENGTH         0x3800	/* PPI Data Length  */
+#define DLEN_8			0x0000	/* Data Length = 8 Bits                         */
+#define DLEN_10			0x0800	/* Data Length = 10 Bits                        */
+#define DLEN_11			0x1000	/* Data Length = 11 Bits                        */
+#define DLEN_12			0x1800	/* Data Length = 12 Bits                        */
+#define DLEN_13			0x2000	/* Data Length = 13 Bits                        */
+#define DLEN_14			0x2800	/* Data Length = 14 Bits                        */
+#define DLEN_15			0x3000	/* Data Length = 15 Bits                        */
+#define DLEN_16			0x3800	/* Data Length = 16 Bits                        */
+#define POLC			0x4000	/* PPI Clock Polarity                           */
+#define POLS			0x8000	/* PPI Frame Sync Polarity                      */
+
+/* PPI_STATUS Masks														*/
+#define FLD				0x0400	/* Field Indicator                                      */
+#define FT_ERR			0x0800	/* Frame Track Error                            */
+#define OVR				0x1000	/* FIFO Overflow Error                          */
+#define UNDR			0x2000	/* FIFO Underrun Error                          */
+#define ERR_DET			0x4000	/* Error Detected Indicator                     */
+#define ERR_NCOR		0x8000	/* Error Not Corrected Indicator        */
+
+/*  ********************  TWO-WIRE INTERFACE (TWI) MASKS  ***********************/
+/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y);  )				*/
+#define	CLKLOW(x)	((x) & 0xFF)	/* Periods Clock Is Held Low                    */
+#define CLKHI(y)	(((y)&0xFF)<<0x8)	/* Periods Before New Clock Low                 */
+
+/* TWI_PRESCALE Masks															*/
+#define	PRESCALE	0x007F	/* SCLKs Per Internal Time Reference (10MHz)    */
+#define	TWI_ENA		0x0080	/* TWI Enable                                                                   */
+#define	SCCB		0x0200	/* SCCB Compatibility Enable                                    */
+
+/* TWI_SLAVE_CTRL Masks															*/
+#define	SEN			0x0001	/* Slave Enable                                                                 */
+#define	SADD_LEN	0x0002	/* Slave Address Length                                                 */
+#define	STDVAL		0x0004	/* Slave Transmit Data Valid                                    */
+#define	NAK			0x0008	/* NAK/ACK* Generated At Conclusion Of Transfer */
+#define	GEN			0x0010	/* General Call Adrress Matching Enabled                */
+
+/* TWI_SLAVE_STAT Masks															*/
+#define	SDIR		0x0001	/* Slave Transfer Direction (Transmit/Receive*) */
+#define GCALL		0x0002	/* General Call Indicator                                               */
+
+/* TWI_MASTER_CTRL Masks													*/
+#define	MEN			0x0001	/* Master Mode Enable                                           */
+#define	MADD_LEN	0x0002	/* Master Address Length                                        */
+#define	MDIR		0x0004	/* Master Transmit Direction (RX/TX*)           */
+#define	FAST		0x0008	/* Use Fast Mode Timing Specs                           */
+#define	STOP		0x0010	/* Issue Stop Condition                                         */
+#define	RSTART		0x0020	/* Repeat Start or Stop* At End Of Transfer     */
+#define	DCNT		0x3FC0	/* Data Bytes To Transfer                                       */
+#define	SDAOVR		0x4000	/* Serial Data Override                                         */
+#define	SCLOVR		0x8000	/* Serial Clock Override                                        */
+
+/* TWI_MASTER_STAT Masks														*/
+#define	MPROG		0x0001	/* Master Transfer In Progress                                  */
+#define	LOSTARB		0x0002	/* Lost Arbitration Indicator (Xfer Aborted)    */
+#define	ANAK		0x0004	/* Address Not Acknowledged                                             */
+#define	DNAK		0x0008	/* Data Not Acknowledged                                                */
+#define	BUFRDERR	0x0010	/* Buffer Read Error                                                    */
+#define	BUFWRERR	0x0020	/* Buffer Write Error                                                   */
+#define	SDASEN		0x0040	/* Serial Data Sense                                                    */
+#define	SCLSEN		0x0080	/* Serial Clock Sense                                                   */
+#define	BUSBUSY		0x0100	/* Bus Busy Indicator                                                   */
+
+/* TWI_INT_SRC and TWI_INT_ENABLE Masks						*/
+#define	SINIT		0x0001	/* Slave Transfer Initiated     */
+#define	SCOMP		0x0002	/* Slave Transfer Complete      */
+#define	SERR		0x0004	/* Slave Transfer Error         */
+#define	SOVF		0x0008	/* Slave Overflow                       */
+#define	MCOMP		0x0010	/* Master Transfer Complete     */
+#define	MERR		0x0020	/* Master Transfer Error        */
+#define	XMTSERV		0x0040	/* Transmit FIFO Service        */
+#define	RCVSERV		0x0080	/* Receive FIFO Service         */
+
+/* TWI_FIFO_CTRL Masks												*/
+#define	XMTFLUSH	0x0001	/* Transmit Buffer Flush                        */
+#define	RCVFLUSH	0x0002	/* Receive Buffer Flush                         */
+#define	XMTINTLEN	0x0004	/* Transmit Buffer Interrupt Length     */
+#define	RCVINTLEN	0x0008	/* Receive Buffer Interrupt Length      */
+
+/* TWI_FIFO_STAT Masks															*/
+#define	XMTSTAT		0x0003	/* Transmit FIFO Status                                                 */
+#define	XMT_EMPTY	0x0000	/*              Transmit FIFO Empty                                             */
+#define	XMT_HALF	0x0001	/*              Transmit FIFO Has 1 Byte To Write               */
+#define	XMT_FULL	0x0003	/*              Transmit FIFO Full (2 Bytes To Write)   */
+
+#define	RCVSTAT		0x000C	/* Receive FIFO Status                                                  */
+#define	RCV_EMPTY	0x0000	/*              Receive FIFO Empty                                              */
+#define	RCV_HALF	0x0004	/*              Receive FIFO Has 1 Byte To Read                 */
+#define	RCV_FULL	0x000C	/*              Receive FIFO Full (2 Bytes To Read)             */
+
+/* ************  CONTROLLER AREA NETWORK (CAN) MASKS  ***************/
+/* CAN_CONTROL Masks												*/
+#define	SRS			0x0001	/* Software Reset                                               */
+#define	DNM			0x0002	/* Device Net Mode                                              */
+#define	ABO			0x0004	/* Auto-Bus On Enable                                   */
+#define	TXPRIO		0x0008	/* TX Priority (Priority/Mailbox*)              */
+#define	WBA			0x0010	/* Wake-Up On CAN Bus Activity Enable   */
+#define	SMR			0x0020	/* Sleep Mode Request                                   */
+#define	CSR			0x0040	/* CAN Suspend Mode Request                             */
+#define	CCR			0x0080	/* CAN Configuration Mode Request               */
+
+/* CAN_STATUS Masks												*/
+#define	WT			0x0001	/* TX Warning Flag                                      */
+#define	WR			0x0002	/* RX Warning Flag                                      */
+#define	EP			0x0004	/* Error Passive Mode                           */
+#define	EBO			0x0008	/* Error Bus Off Mode                           */
+#define	SMA			0x0020	/* Sleep Mode Acknowledge                       */
+#define	CSA			0x0040	/* Suspend Mode Acknowledge                     */
+#define	CCA			0x0080	/* Configuration Mode Acknowledge       */
+#define	MBPTR		0x1F00	/* Mailbox Pointer                                      */
+#define	TRM			0x4000	/* Transmit Mode                                        */
+#define	REC			0x8000	/* Receive Mode                                         */
+
+/* CAN_CLOCK Masks									*/
+#define	BRP			0x03FF	/* Bit-Rate Pre-Scaler  */
+
+/* CAN_TIMING Masks											*/
+#define	TSEG1		0x000F	/* Time Segment 1                               */
+#define	TSEG2		0x0070	/* Time Segment 2                               */
+#define	SAM			0x0080	/* Sampling                                             */
+#define	SJW			0x0300	/* Synchronization Jump Width   */
+
+/* CAN_DEBUG Masks											*/
+#define	DEC			0x0001	/* Disable CAN Error Counters   */
+#define	DRI			0x0002	/* Disable CAN RX Input                 */
+#define	DTO			0x0004	/* Disable CAN TX Output                */
+#define	DIL			0x0008	/* Disable CAN Internal Loop    */
+#define	MAA			0x0010	/* Mode Auto-Acknowledge Enable */
+#define	MRB			0x0020	/* Mode Read Back Enable                */
+#define	CDE			0x8000	/* CAN Debug Enable                             */
+
+/* CAN_CEC Masks										*/
+#define	RXECNT		0x00FF	/* Receive Error Counter        */
+#define	TXECNT		0xFF00	/* Transmit Error Counter       */
+
+/* CAN_INTR Masks											*/
+#define	MBRIF		0x0001	/* Mailbox Receive Interrupt    */
+#define	MBTIF		0x0002	/* Mailbox Transmit Interrupt   */
+#define	GIRQ		0x0004	/* Global Interrupt                             */
+#define	SMACK		0x0008	/* Sleep Mode Acknowledge               */
+#define	CANTX		0x0040	/* CAN TX Bus Value                             */
+#define	CANRX		0x0080	/* CAN RX Bus Value                             */
+
+/* CAN_MBxx_ID1 and CAN_MBxx_ID0 Masks										*/
+#define DFC			0xFFFF	/* Data Filtering Code (If Enabled) (ID0)               */
+#define	EXTID_LO	0xFFFF	/* Lower 16 Bits of Extended Identifier (ID0)   */
+#define	EXTID_HI	0x0003	/* Upper 2 Bits of Extended Identifier (ID1)    */
+#define	BASEID		0x1FFC	/* Base Identifier                                                              */
+#define	IDE			0x2000	/* Identifier Extension                                                 */
+#define	RTR			0x4000	/* Remote Frame Transmission Request                    */
+#define	AME			0x8000	/* Acceptance Mask Enable                                               */
+
+/* CAN_MBxx_TIMESTAMP Masks					*/
+#define TSV			0xFFFF	/* Timestamp    */
+
+/* CAN_MBxx_LENGTH Masks						*/
+#define DLC			0x000F	/* Data Length Code     */
+
+/* CAN_AMxxH and CAN_AMxxL Masks												*/
+#define DFM			0xFFFF	/* Data Field Mask (If Enabled) (CAN_AMxxL)                     */
+#define	EXTID_LO	0xFFFF	/* Lower 16 Bits of Extended Identifier (CAN_AMxxL)     */
+#define	EXTID_HI	0x0003	/* Upper 2 Bits of Extended Identifier (CAN_AMxxH)      */
+#define	BASEID		0x1FFC	/* Base Identifier                                                                      */
+#define	AMIDE		0x2000	/* Acceptance Mask ID Extension Enable                          */
+#define	FMD			0x4000	/* Full Mask Data Field Enable                                          */
+#define	FDF			0x8000	/* Filter On Data Field Enable                                          */
+
+/* CAN_MC1 Masks									*/
+#define	MC0			0x0001	/* Enable Mailbox 0             */
+#define	MC1			0x0002	/* Enable Mailbox 1             */
+#define	MC2			0x0004	/* Enable Mailbox 2             */
+#define	MC3			0x0008	/* Enable Mailbox 3             */
+#define	MC4			0x0010	/* Enable Mailbox 4             */
+#define	MC5			0x0020	/* Enable Mailbox 5             */
+#define	MC6			0x0040	/* Enable Mailbox 6             */
+#define	MC7			0x0080	/* Enable Mailbox 7             */
+#define	MC8			0x0100	/* Enable Mailbox 8             */
+#define	MC9			0x0200	/* Enable Mailbox 9             */
+#define	MC10		0x0400	/* Enable Mailbox 10    */
+#define	MC11		0x0800	/* Enable Mailbox 11    */
+#define	MC12		0x1000	/* Enable Mailbox 12    */
+#define	MC13		0x2000	/* Enable Mailbox 13    */
+#define	MC14		0x4000	/* Enable Mailbox 14    */
+#define	MC15		0x8000	/* Enable Mailbox 15    */
+
+/* CAN_MC2 Masks									*/
+#define	MC16		0x0001	/* Enable Mailbox 16    */
+#define	MC17		0x0002	/* Enable Mailbox 17    */
+#define	MC18		0x0004	/* Enable Mailbox 18    */
+#define	MC19		0x0008	/* Enable Mailbox 19    */
+#define	MC20		0x0010	/* Enable Mailbox 20    */
+#define	MC21		0x0020	/* Enable Mailbox 21    */
+#define	MC22		0x0040	/* Enable Mailbox 22    */
+#define	MC23		0x0080	/* Enable Mailbox 23    */
+#define	MC24		0x0100	/* Enable Mailbox 24    */
+#define	MC25		0x0200	/* Enable Mailbox 25    */
+#define	MC26		0x0400	/* Enable Mailbox 26    */
+#define	MC27		0x0800	/* Enable Mailbox 27    */
+#define	MC28		0x1000	/* Enable Mailbox 28    */
+#define	MC29		0x2000	/* Enable Mailbox 29    */
+#define	MC30		0x4000	/* Enable Mailbox 30    */
+#define	MC31		0x8000	/* Enable Mailbox 31    */
+
+/* CAN_MD1 Masks												*/
+#define	MD0			0x0001	/* Enable Mailbox 0 For Receive         */
+#define	MD1			0x0002	/* Enable Mailbox 1 For Receive         */
+#define	MD2			0x0004	/* Enable Mailbox 2 For Receive         */
+#define	MD3			0x0008	/* Enable Mailbox 3 For Receive         */
+#define	MD4			0x0010	/* Enable Mailbox 4 For Receive         */
+#define	MD5			0x0020	/* Enable Mailbox 5 For Receive         */
+#define	MD6			0x0040	/* Enable Mailbox 6 For Receive         */
+#define	MD7			0x0080	/* Enable Mailbox 7 For Receive         */
+#define	MD8			0x0100	/* Enable Mailbox 8 For Receive         */
+#define	MD9			0x0200	/* Enable Mailbox 9 For Receive         */
+#define	MD10		0x0400	/* Enable Mailbox 10 For Receive        */
+#define	MD11		0x0800	/* Enable Mailbox 11 For Receive        */
+#define	MD12		0x1000	/* Enable Mailbox 12 For Receive        */
+#define	MD13		0x2000	/* Enable Mailbox 13 For Receive        */
+#define	MD14		0x4000	/* Enable Mailbox 14 For Receive        */
+#define	MD15		0x8000	/* Enable Mailbox 15 For Receive        */
+
+/* CAN_MD2 Masks												*/
+#define	MD16		0x0001	/* Enable Mailbox 16 For Receive        */
+#define	MD17		0x0002	/* Enable Mailbox 17 For Receive        */
+#define	MD18		0x0004	/* Enable Mailbox 18 For Receive        */
+#define	MD19		0x0008	/* Enable Mailbox 19 For Receive        */
+#define	MD20		0x0010	/* Enable Mailbox 20 For Receive        */
+#define	MD21		0x0020	/* Enable Mailbox 21 For Receive        */
+#define	MD22		0x0040	/* Enable Mailbox 22 For Receive        */
+#define	MD23		0x0080	/* Enable Mailbox 23 For Receive        */
+#define	MD24		0x0100	/* Enable Mailbox 24 For Receive        */
+#define	MD25		0x0200	/* Enable Mailbox 25 For Receive        */
+#define	MD26		0x0400	/* Enable Mailbox 26 For Receive        */
+#define	MD27		0x0800	/* Enable Mailbox 27 For Receive        */
+#define	MD28		0x1000	/* Enable Mailbox 28 For Receive        */
+#define	MD29		0x2000	/* Enable Mailbox 29 For Receive        */
+#define	MD30		0x4000	/* Enable Mailbox 30 For Receive        */
+#define	MD31		0x8000	/* Enable Mailbox 31 For Receive        */
+
+/* CAN_RMP1 Masks												*/
+#define	RMP0		0x0001	/* RX Message Pending In Mailbox 0      */
+#define	RMP1		0x0002	/* RX Message Pending In Mailbox 1      */
+#define	RMP2		0x0004	/* RX Message Pending In Mailbox 2      */
+#define	RMP3		0x0008	/* RX Message Pending In Mailbox 3      */
+#define	RMP4		0x0010	/* RX Message Pending In Mailbox 4      */
+#define	RMP5		0x0020	/* RX Message Pending In Mailbox 5      */
+#define	RMP6		0x0040	/* RX Message Pending In Mailbox 6      */
+#define	RMP7		0x0080	/* RX Message Pending In Mailbox 7      */
+#define	RMP8		0x0100	/* RX Message Pending In Mailbox 8      */
+#define	RMP9		0x0200	/* RX Message Pending In Mailbox 9      */
+#define	RMP10		0x0400	/* RX Message Pending In Mailbox 10     */
+#define	RMP11		0x0800	/* RX Message Pending In Mailbox 11     */
+#define	RMP12		0x1000	/* RX Message Pending In Mailbox 12     */
+#define	RMP13		0x2000	/* RX Message Pending In Mailbox 13     */
+#define	RMP14		0x4000	/* RX Message Pending In Mailbox 14     */
+#define	RMP15		0x8000	/* RX Message Pending In Mailbox 15     */
+
+/* CAN_RMP2 Masks												*/
+#define	RMP16		0x0001	/* RX Message Pending In Mailbox 16     */
+#define	RMP17		0x0002	/* RX Message Pending In Mailbox 17     */
+#define	RMP18		0x0004	/* RX Message Pending In Mailbox 18     */
+#define	RMP19		0x0008	/* RX Message Pending In Mailbox 19     */
+#define	RMP20		0x0010	/* RX Message Pending In Mailbox 20     */
+#define	RMP21		0x0020	/* RX Message Pending In Mailbox 21     */
+#define	RMP22		0x0040	/* RX Message Pending In Mailbox 22     */
+#define	RMP23		0x0080	/* RX Message Pending In Mailbox 23     */
+#define	RMP24		0x0100	/* RX Message Pending In Mailbox 24     */
+#define	RMP25		0x0200	/* RX Message Pending In Mailbox 25     */
+#define	RMP26		0x0400	/* RX Message Pending In Mailbox 26     */
+#define	RMP27		0x0800	/* RX Message Pending In Mailbox 27     */
+#define	RMP28		0x1000	/* RX Message Pending In Mailbox 28     */
+#define	RMP29		0x2000	/* RX Message Pending In Mailbox 29     */
+#define	RMP30		0x4000	/* RX Message Pending In Mailbox 30     */
+#define	RMP31		0x8000	/* RX Message Pending In Mailbox 31     */
+
+/* CAN_RML1 Masks												*/
+#define	RML0		0x0001	/* RX Message Lost In Mailbox 0         */
+#define	RML1		0x0002	/* RX Message Lost In Mailbox 1         */
+#define	RML2		0x0004	/* RX Message Lost In Mailbox 2         */
+#define	RML3		0x0008	/* RX Message Lost In Mailbox 3         */
+#define	RML4		0x0010	/* RX Message Lost In Mailbox 4         */
+#define	RML5		0x0020	/* RX Message Lost In Mailbox 5         */
+#define	RML6		0x0040	/* RX Message Lost In Mailbox 6         */
+#define	RML7		0x0080	/* RX Message Lost In Mailbox 7         */
+#define	RML8		0x0100	/* RX Message Lost In Mailbox 8         */
+#define	RML9		0x0200	/* RX Message Lost In Mailbox 9         */
+#define	RML10		0x0400	/* RX Message Lost In Mailbox 10        */
+#define	RML11		0x0800	/* RX Message Lost In Mailbox 11        */
+#define	RML12		0x1000	/* RX Message Lost In Mailbox 12        */
+#define	RML13		0x2000	/* RX Message Lost In Mailbox 13        */
+#define	RML14		0x4000	/* RX Message Lost In Mailbox 14        */
+#define	RML15		0x8000	/* RX Message Lost In Mailbox 15        */
+
+/* CAN_RML2 Masks												*/
+#define	RML16		0x0001	/* RX Message Lost In Mailbox 16        */
+#define	RML17		0x0002	/* RX Message Lost In Mailbox 17        */
+#define	RML18		0x0004	/* RX Message Lost In Mailbox 18        */
+#define	RML19		0x0008	/* RX Message Lost In Mailbox 19        */
+#define	RML20		0x0010	/* RX Message Lost In Mailbox 20        */
+#define	RML21		0x0020	/* RX Message Lost In Mailbox 21        */
+#define	RML22		0x0040	/* RX Message Lost In Mailbox 22        */
+#define	RML23		0x0080	/* RX Message Lost In Mailbox 23        */
+#define	RML24		0x0100	/* RX Message Lost In Mailbox 24        */
+#define	RML25		0x0200	/* RX Message Lost In Mailbox 25        */
+#define	RML26		0x0400	/* RX Message Lost In Mailbox 26        */
+#define	RML27		0x0800	/* RX Message Lost In Mailbox 27        */
+#define	RML28		0x1000	/* RX Message Lost In Mailbox 28        */
+#define	RML29		0x2000	/* RX Message Lost In Mailbox 29        */
+#define	RML30		0x4000	/* RX Message Lost In Mailbox 30        */
+#define	RML31		0x8000	/* RX Message Lost In Mailbox 31        */
+
+/* CAN_OPSS1 Masks																				*/
+#define	OPSS0		0x0001	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 0       */
+#define	OPSS1		0x0002	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 1       */
+#define	OPSS2		0x0004	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 2       */
+#define	OPSS3		0x0008	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 3       */
+#define	OPSS4		0x0010	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 4       */
+#define	OPSS5		0x0020	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 5       */
+#define	OPSS6		0x0040	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 6       */
+#define	OPSS7		0x0080	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 7       */
+#define	OPSS8		0x0100	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 8       */
+#define	OPSS9		0x0200	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 9       */
+#define	OPSS10		0x0400	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 10      */
+#define	OPSS11		0x0800	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 11      */
+#define	OPSS12		0x1000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 12      */
+#define	OPSS13		0x2000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 13      */
+#define	OPSS14		0x4000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 14      */
+#define	OPSS15		0x8000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 15      */
+
+/* CAN_OPSS2 Masks																				*/
+#define	OPSS16		0x0001	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 16      */
+#define	OPSS17		0x0002	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 17      */
+#define	OPSS18		0x0004	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 18      */
+#define	OPSS19		0x0008	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 19      */
+#define	OPSS20		0x0010	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 20      */
+#define	OPSS21		0x0020	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 21      */
+#define	OPSS22		0x0040	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 22      */
+#define	OPSS23		0x0080	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 23      */
+#define	OPSS24		0x0100	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 24      */
+#define	OPSS25		0x0200	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 25      */
+#define	OPSS26		0x0400	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 26      */
+#define	OPSS27		0x0800	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 27      */
+#define	OPSS28		0x1000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 28      */
+#define	OPSS29		0x2000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 29      */
+#define	OPSS30		0x4000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 30      */
+#define	OPSS31		0x8000	/* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 31      */
+
+/* CAN_TRR1 Masks														*/
+#define	TRR0		0x0001	/* Deny But Don't Lock Access To Mailbox 0      */
+#define	TRR1		0x0002	/* Deny But Don't Lock Access To Mailbox 1      */
+#define	TRR2		0x0004	/* Deny But Don't Lock Access To Mailbox 2      */
+#define	TRR3		0x0008	/* Deny But Don't Lock Access To Mailbox 3      */
+#define	TRR4		0x0010	/* Deny But Don't Lock Access To Mailbox 4      */
+#define	TRR5		0x0020	/* Deny But Don't Lock Access To Mailbox 5      */
+#define	TRR6		0x0040	/* Deny But Don't Lock Access To Mailbox 6      */
+#define	TRR7		0x0080	/* Deny But Don't Lock Access To Mailbox 7      */
+#define	TRR8		0x0100	/* Deny But Don't Lock Access To Mailbox 8      */
+#define	TRR9		0x0200	/* Deny But Don't Lock Access To Mailbox 9      */
+#define	TRR10		0x0400	/* Deny But Don't Lock Access To Mailbox 10     */
+#define	TRR11		0x0800	/* Deny But Don't Lock Access To Mailbox 11     */
+#define	TRR12		0x1000	/* Deny But Don't Lock Access To Mailbox 12     */
+#define	TRR13		0x2000	/* Deny But Don't Lock Access To Mailbox 13     */
+#define	TRR14		0x4000	/* Deny But Don't Lock Access To Mailbox 14     */
+#define	TRR15		0x8000	/* Deny But Don't Lock Access To Mailbox 15     */
+
+/* CAN_TRR2 Masks														*/
+#define	TRR16		0x0001	/* Deny But Don't Lock Access To Mailbox 16     */
+#define	TRR17		0x0002	/* Deny But Don't Lock Access To Mailbox 17     */
+#define	TRR18		0x0004	/* Deny But Don't Lock Access To Mailbox 18     */
+#define	TRR19		0x0008	/* Deny But Don't Lock Access To Mailbox 19     */
+#define	TRR20		0x0010	/* Deny But Don't Lock Access To Mailbox 20     */
+#define	TRR21		0x0020	/* Deny But Don't Lock Access To Mailbox 21     */
+#define	TRR22		0x0040	/* Deny But Don't Lock Access To Mailbox 22     */
+#define	TRR23		0x0080	/* Deny But Don't Lock Access To Mailbox 23     */
+#define	TRR24		0x0100	/* Deny But Don't Lock Access To Mailbox 24     */
+#define	TRR25		0x0200	/* Deny But Don't Lock Access To Mailbox 25     */
+#define	TRR26		0x0400	/* Deny But Don't Lock Access To Mailbox 26     */
+#define	TRR27		0x0800	/* Deny But Don't Lock Access To Mailbox 27     */
+#define	TRR28		0x1000	/* Deny But Don't Lock Access To Mailbox 28     */
+#define	TRR29		0x2000	/* Deny But Don't Lock Access To Mailbox 29     */
+#define	TRR30		0x4000	/* Deny But Don't Lock Access To Mailbox 30     */
+#define	TRR31		0x8000	/* Deny But Don't Lock Access To Mailbox 31     */
+
+/* CAN_TRS1 Masks													*/
+#define	TRS0		0x0001	/* Remote Frame Request For Mailbox 0   */
+#define	TRS1		0x0002	/* Remote Frame Request For Mailbox 1   */
+#define	TRS2		0x0004	/* Remote Frame Request For Mailbox 2   */
+#define	TRS3		0x0008	/* Remote Frame Request For Mailbox 3   */
+#define	TRS4		0x0010	/* Remote Frame Request For Mailbox 4   */
+#define	TRS5		0x0020	/* Remote Frame Request For Mailbox 5   */
+#define	TRS6		0x0040	/* Remote Frame Request For Mailbox 6   */
+#define	TRS7		0x0080	/* Remote Frame Request For Mailbox 7   */
+#define	TRS8		0x0100	/* Remote Frame Request For Mailbox 8   */
+#define	TRS9		0x0200	/* Remote Frame Request For Mailbox 9   */
+#define	TRS10		0x0400	/* Remote Frame Request For Mailbox 10  */
+#define	TRS11		0x0800	/* Remote Frame Request For Mailbox 11  */
+#define	TRS12		0x1000	/* Remote Frame Request For Mailbox 12  */
+#define	TRS13		0x2000	/* Remote Frame Request For Mailbox 13  */
+#define	TRS14		0x4000	/* Remote Frame Request For Mailbox 14  */
+#define	TRS15		0x8000	/* Remote Frame Request For Mailbox 15  */
+
+/* CAN_TRS2 Masks													*/
+#define	TRS16		0x0001	/* Remote Frame Request For Mailbox 16  */
+#define	TRS17		0x0002	/* Remote Frame Request For Mailbox 17  */
+#define	TRS18		0x0004	/* Remote Frame Request For Mailbox 18  */
+#define	TRS19		0x0008	/* Remote Frame Request For Mailbox 19  */
+#define	TRS20		0x0010	/* Remote Frame Request For Mailbox 20  */
+#define	TRS21		0x0020	/* Remote Frame Request For Mailbox 21  */
+#define	TRS22		0x0040	/* Remote Frame Request For Mailbox 22  */
+#define	TRS23		0x0080	/* Remote Frame Request For Mailbox 23  */
+#define	TRS24		0x0100	/* Remote Frame Request For Mailbox 24  */
+#define	TRS25		0x0200	/* Remote Frame Request For Mailbox 25  */
+#define	TRS26		0x0400	/* Remote Frame Request For Mailbox 26  */
+#define	TRS27		0x0800	/* Remote Frame Request For Mailbox 27  */
+#define	TRS28		0x1000	/* Remote Frame Request For Mailbox 28  */
+#define	TRS29		0x2000	/* Remote Frame Request For Mailbox 29  */
+#define	TRS30		0x4000	/* Remote Frame Request For Mailbox 30  */
+#define	TRS31		0x8000	/* Remote Frame Request For Mailbox 31  */
+
+/* CAN_AA1 Masks												*/
+#define	AA0			0x0001	/* Aborted Message In Mailbox 0         */
+#define	AA1			0x0002	/* Aborted Message In Mailbox 1         */
+#define	AA2			0x0004	/* Aborted Message In Mailbox 2         */
+#define	AA3			0x0008	/* Aborted Message In Mailbox 3         */
+#define	AA4			0x0010	/* Aborted Message In Mailbox 4         */
+#define	AA5			0x0020	/* Aborted Message In Mailbox 5         */
+#define	AA6			0x0040	/* Aborted Message In Mailbox 6         */
+#define	AA7			0x0080	/* Aborted Message In Mailbox 7         */
+#define	AA8			0x0100	/* Aborted Message In Mailbox 8         */
+#define	AA9			0x0200	/* Aborted Message In Mailbox 9         */
+#define	AA10		0x0400	/* Aborted Message In Mailbox 10        */
+#define	AA11		0x0800	/* Aborted Message In Mailbox 11        */
+#define	AA12		0x1000	/* Aborted Message In Mailbox 12        */
+#define	AA13		0x2000	/* Aborted Message In Mailbox 13        */
+#define	AA14		0x4000	/* Aborted Message In Mailbox 14        */
+#define	AA15		0x8000	/* Aborted Message In Mailbox 15        */
+
+/* CAN_AA2 Masks												*/
+#define	AA16		0x0001	/* Aborted Message In Mailbox 16        */
+#define	AA17		0x0002	/* Aborted Message In Mailbox 17        */
+#define	AA18		0x0004	/* Aborted Message In Mailbox 18        */
+#define	AA19		0x0008	/* Aborted Message In Mailbox 19        */
+#define	AA20		0x0010	/* Aborted Message In Mailbox 20        */
+#define	AA21		0x0020	/* Aborted Message In Mailbox 21        */
+#define	AA22		0x0040	/* Aborted Message In Mailbox 22        */
+#define	AA23		0x0080	/* Aborted Message In Mailbox 23        */
+#define	AA24		0x0100	/* Aborted Message In Mailbox 24        */
+#define	AA25		0x0200	/* Aborted Message In Mailbox 25        */
+#define	AA26		0x0400	/* Aborted Message In Mailbox 26        */
+#define	AA27		0x0800	/* Aborted Message In Mailbox 27        */
+#define	AA28		0x1000	/* Aborted Message In Mailbox 28        */
+#define	AA29		0x2000	/* Aborted Message In Mailbox 29        */
+#define	AA30		0x4000	/* Aborted Message In Mailbox 30        */
+#define	AA31		0x8000	/* Aborted Message In Mailbox 31        */
+
+/* CAN_TA1 Masks													*/
+#define	TA0			0x0001	/* Transmit Successful From Mailbox 0   */
+#define	TA1			0x0002	/* Transmit Successful From Mailbox 1   */
+#define	TA2			0x0004	/* Transmit Successful From Mailbox 2   */
+#define	TA3			0x0008	/* Transmit Successful From Mailbox 3   */
+#define	TA4			0x0010	/* Transmit Successful From Mailbox 4   */
+#define	TA5			0x0020	/* Transmit Successful From Mailbox 5   */
+#define	TA6			0x0040	/* Transmit Successful From Mailbox 6   */
+#define	TA7			0x0080	/* Transmit Successful From Mailbox 7   */
+#define	TA8			0x0100	/* Transmit Successful From Mailbox 8   */
+#define	TA9			0x0200	/* Transmit Successful From Mailbox 9   */
+#define	TA10		0x0400	/* Transmit Successful From Mailbox 10  */
+#define	TA11		0x0800	/* Transmit Successful From Mailbox 11  */
+#define	TA12		0x1000	/* Transmit Successful From Mailbox 12  */
+#define	TA13		0x2000	/* Transmit Successful From Mailbox 13  */
+#define	TA14		0x4000	/* Transmit Successful From Mailbox 14  */
+#define	TA15		0x8000	/* Transmit Successful From Mailbox 15  */
+
+/* CAN_TA2 Masks													*/
+#define	TA16		0x0001	/* Transmit Successful From Mailbox 16  */
+#define	TA17		0x0002	/* Transmit Successful From Mailbox 17  */
+#define	TA18		0x0004	/* Transmit Successful From Mailbox 18  */
+#define	TA19		0x0008	/* Transmit Successful From Mailbox 19  */
+#define	TA20		0x0010	/* Transmit Successful From Mailbox 20  */
+#define	TA21		0x0020	/* Transmit Successful From Mailbox 21  */
+#define	TA22		0x0040	/* Transmit Successful From Mailbox 22  */
+#define	TA23		0x0080	/* Transmit Successful From Mailbox 23  */
+#define	TA24		0x0100	/* Transmit Successful From Mailbox 24  */
+#define	TA25		0x0200	/* Transmit Successful From Mailbox 25  */
+#define	TA26		0x0400	/* Transmit Successful From Mailbox 26  */
+#define	TA27		0x0800	/* Transmit Successful From Mailbox 27  */
+#define	TA28		0x1000	/* Transmit Successful From Mailbox 28  */
+#define	TA29		0x2000	/* Transmit Successful From Mailbox 29  */
+#define	TA30		0x4000	/* Transmit Successful From Mailbox 30  */
+#define	TA31		0x8000	/* Transmit Successful From Mailbox 31  */
+
+/* CAN_MBTD Masks												*/
+#define TDPTR		0x001F	/* Mailbox To Temporarily Disable       */
+#define	TDA			0x0040	/* Temporary Disable Acknowledge        */
+#define	TDR			0x0080	/* Temporary Disable Request            */
+
+/* CAN_RFH1 Masks																		*/
+#define	RFH0		0x0001	/* Enable Automatic Remote Frame Handling For Mailbox 0         */
+#define	RFH1		0x0002	/* Enable Automatic Remote Frame Handling For Mailbox 1         */
+#define	RFH2		0x0004	/* Enable Automatic Remote Frame Handling For Mailbox 2         */
+#define	RFH3		0x0008	/* Enable Automatic Remote Frame Handling For Mailbox 3         */
+#define	RFH4		0x0010	/* Enable Automatic Remote Frame Handling For Mailbox 4         */
+#define	RFH5		0x0020	/* Enable Automatic Remote Frame Handling For Mailbox 5         */
+#define	RFH6		0x0040	/* Enable Automatic Remote Frame Handling For Mailbox 6         */
+#define	RFH7		0x0080	/* Enable Automatic Remote Frame Handling For Mailbox 7         */
+#define	RFH8		0x0100	/* Enable Automatic Remote Frame Handling For Mailbox 8         */
+#define	RFH9		0x0200	/* Enable Automatic Remote Frame Handling For Mailbox 9         */
+#define	RFH10		0x0400	/* Enable Automatic Remote Frame Handling For Mailbox 10        */
+#define	RFH11		0x0800	/* Enable Automatic Remote Frame Handling For Mailbox 11        */
+#define	RFH12		0x1000	/* Enable Automatic Remote Frame Handling For Mailbox 12        */
+#define	RFH13		0x2000	/* Enable Automatic Remote Frame Handling For Mailbox 13        */
+#define	RFH14		0x4000	/* Enable Automatic Remote Frame Handling For Mailbox 14        */
+#define	RFH15		0x8000	/* Enable Automatic Remote Frame Handling For Mailbox 15        */
+
+/* CAN_RFH2 Masks																		*/
+#define	RFH16		0x0001	/* Enable Automatic Remote Frame Handling For Mailbox 16        */
+#define	RFH17		0x0002	/* Enable Automatic Remote Frame Handling For Mailbox 17        */
+#define	RFH18		0x0004	/* Enable Automatic Remote Frame Handling For Mailbox 18        */
+#define	RFH19		0x0008	/* Enable Automatic Remote Frame Handling For Mailbox 19        */
+#define	RFH20		0x0010	/* Enable Automatic Remote Frame Handling For Mailbox 20        */
+#define	RFH21		0x0020	/* Enable Automatic Remote Frame Handling For Mailbox 21        */
+#define	RFH22		0x0040	/* Enable Automatic Remote Frame Handling For Mailbox 22        */
+#define	RFH23		0x0080	/* Enable Automatic Remote Frame Handling For Mailbox 23        */
+#define	RFH24		0x0100	/* Enable Automatic Remote Frame Handling For Mailbox 24        */
+#define	RFH25		0x0200	/* Enable Automatic Remote Frame Handling For Mailbox 25        */
+#define	RFH26		0x0400	/* Enable Automatic Remote Frame Handling For Mailbox 26        */
+#define	RFH27		0x0800	/* Enable Automatic Remote Frame Handling For Mailbox 27        */
+#define	RFH28		0x1000	/* Enable Automatic Remote Frame Handling For Mailbox 28        */
+#define	RFH29		0x2000	/* Enable Automatic Remote Frame Handling For Mailbox 29        */
+#define	RFH30		0x4000	/* Enable Automatic Remote Frame Handling For Mailbox 30        */
+#define	RFH31		0x8000	/* Enable Automatic Remote Frame Handling For Mailbox 31        */
+
+/* CAN_MBTIF1 Masks													*/
+#define	MBTIF0		0x0001	/* TX Interrupt Active In Mailbox 0             */
+#define	MBTIF1		0x0002	/* TX Interrupt Active In Mailbox 1             */
+#define	MBTIF2		0x0004	/* TX Interrupt Active In Mailbox 2             */
+#define	MBTIF3		0x0008	/* TX Interrupt Active In Mailbox 3             */
+#define	MBTIF4		0x0010	/* TX Interrupt Active In Mailbox 4             */
+#define	MBTIF5		0x0020	/* TX Interrupt Active In Mailbox 5             */
+#define	MBTIF6		0x0040	/* TX Interrupt Active In Mailbox 6             */
+#define	MBTIF7		0x0080	/* TX Interrupt Active In Mailbox 7             */
+#define	MBTIF8		0x0100	/* TX Interrupt Active In Mailbox 8             */
+#define	MBTIF9		0x0200	/* TX Interrupt Active In Mailbox 9             */
+#define	MBTIF10		0x0400	/* TX Interrupt Active In Mailbox 10    */
+#define	MBTIF11		0x0800	/* TX Interrupt Active In Mailbox 11    */
+#define	MBTIF12		0x1000	/* TX Interrupt Active In Mailbox 12    */
+#define	MBTIF13		0x2000	/* TX Interrupt Active In Mailbox 13    */
+#define	MBTIF14		0x4000	/* TX Interrupt Active In Mailbox 14    */
+#define	MBTIF15		0x8000	/* TX Interrupt Active In Mailbox 15    */
+
+/* CAN_MBTIF2 Masks													*/
+#define	MBTIF16		0x0001	/* TX Interrupt Active In Mailbox 16    */
+#define	MBTIF17		0x0002	/* TX Interrupt Active In Mailbox 17    */
+#define	MBTIF18		0x0004	/* TX Interrupt Active In Mailbox 18    */
+#define	MBTIF19		0x0008	/* TX Interrupt Active In Mailbox 19    */
+#define	MBTIF20		0x0010	/* TX Interrupt Active In Mailbox 20    */
+#define	MBTIF21		0x0020	/* TX Interrupt Active In Mailbox 21    */
+#define	MBTIF22		0x0040	/* TX Interrupt Active In Mailbox 22    */
+#define	MBTIF23		0x0080	/* TX Interrupt Active In Mailbox 23    */
+#define	MBTIF24		0x0100	/* TX Interrupt Active In Mailbox 24    */
+#define	MBTIF25		0x0200	/* TX Interrupt Active In Mailbox 25    */
+#define	MBTIF26		0x0400	/* TX Interrupt Active In Mailbox 26    */
+#define	MBTIF27		0x0800	/* TX Interrupt Active In Mailbox 27    */
+#define	MBTIF28		0x1000	/* TX Interrupt Active In Mailbox 28    */
+#define	MBTIF29		0x2000	/* TX Interrupt Active In Mailbox 29    */
+#define	MBTIF30		0x4000	/* TX Interrupt Active In Mailbox 30    */
+#define	MBTIF31		0x8000	/* TX Interrupt Active In Mailbox 31    */
+
+/* CAN_MBRIF1 Masks													*/
+#define	MBRIF0		0x0001	/* RX Interrupt Active In Mailbox 0             */
+#define	MBRIF1		0x0002	/* RX Interrupt Active In Mailbox 1             */
+#define	MBRIF2		0x0004	/* RX Interrupt Active In Mailbox 2             */
+#define	MBRIF3		0x0008	/* RX Interrupt Active In Mailbox 3             */
+#define	MBRIF4		0x0010	/* RX Interrupt Active In Mailbox 4             */
+#define	MBRIF5		0x0020	/* RX Interrupt Active In Mailbox 5             */
+#define	MBRIF6		0x0040	/* RX Interrupt Active In Mailbox 6             */
+#define	MBRIF7		0x0080	/* RX Interrupt Active In Mailbox 7             */
+#define	MBRIF8		0x0100	/* RX Interrupt Active In Mailbox 8             */
+#define	MBRIF9		0x0200	/* RX Interrupt Active In Mailbox 9             */
+#define	MBRIF10		0x0400	/* RX Interrupt Active In Mailbox 10    */
+#define	MBRIF11		0x0800	/* RX Interrupt Active In Mailbox 11    */
+#define	MBRIF12		0x1000	/* RX Interrupt Active In Mailbox 12    */
+#define	MBRIF13		0x2000	/* RX Interrupt Active In Mailbox 13    */
+#define	MBRIF14		0x4000	/* RX Interrupt Active In Mailbox 14    */
+#define	MBRIF15		0x8000	/* RX Interrupt Active In Mailbox 15    */
+
+/* CAN_MBRIF2 Masks													*/
+#define	MBRIF16		0x0001	/* RX Interrupt Active In Mailbox 16    */
+#define	MBRIF17		0x0002	/* RX Interrupt Active In Mailbox 17    */
+#define	MBRIF18		0x0004	/* RX Interrupt Active In Mailbox 18    */
+#define	MBRIF19		0x0008	/* RX Interrupt Active In Mailbox 19    */
+#define	MBRIF20		0x0010	/* RX Interrupt Active In Mailbox 20    */
+#define	MBRIF21		0x0020	/* RX Interrupt Active In Mailbox 21    */
+#define	MBRIF22		0x0040	/* RX Interrupt Active In Mailbox 22    */
+#define	MBRIF23		0x0080	/* RX Interrupt Active In Mailbox 23    */
+#define	MBRIF24		0x0100	/* RX Interrupt Active In Mailbox 24    */
+#define	MBRIF25		0x0200	/* RX Interrupt Active In Mailbox 25    */
+#define	MBRIF26		0x0400	/* RX Interrupt Active In Mailbox 26    */
+#define	MBRIF27		0x0800	/* RX Interrupt Active In Mailbox 27    */
+#define	MBRIF28		0x1000	/* RX Interrupt Active In Mailbox 28    */
+#define	MBRIF29		0x2000	/* RX Interrupt Active In Mailbox 29    */
+#define	MBRIF30		0x4000	/* RX Interrupt Active In Mailbox 30    */
+#define	MBRIF31		0x8000	/* RX Interrupt Active In Mailbox 31    */
+
+/* CAN_MBIM1 Masks												*/
+#define	MBIM0		0x0001	/* Enable Interrupt For Mailbox 0       */
+#define	MBIM1		0x0002	/* Enable Interrupt For Mailbox 1       */
+#define	MBIM2		0x0004	/* Enable Interrupt For Mailbox 2       */
+#define	MBIM3		0x0008	/* Enable Interrupt For Mailbox 3       */
+#define	MBIM4		0x0010	/* Enable Interrupt For Mailbox 4       */
+#define	MBIM5		0x0020	/* Enable Interrupt For Mailbox 5       */
+#define	MBIM6		0x0040	/* Enable Interrupt For Mailbox 6       */
+#define	MBIM7		0x0080	/* Enable Interrupt For Mailbox 7       */
+#define	MBIM8		0x0100	/* Enable Interrupt For Mailbox 8       */
+#define	MBIM9		0x0200	/* Enable Interrupt For Mailbox 9       */
+#define	MBIM10		0x0400	/* Enable Interrupt For Mailbox 10      */
+#define	MBIM11		0x0800	/* Enable Interrupt For Mailbox 11      */
+#define	MBIM12		0x1000	/* Enable Interrupt For Mailbox 12      */
+#define	MBIM13		0x2000	/* Enable Interrupt For Mailbox 13      */
+#define	MBIM14		0x4000	/* Enable Interrupt For Mailbox 14      */
+#define	MBIM15		0x8000	/* Enable Interrupt For Mailbox 15      */
+
+/* CAN_MBIM2 Masks												*/
+#define	MBIM16		0x0001	/* Enable Interrupt For Mailbox 16      */
+#define	MBIM17		0x0002	/* Enable Interrupt For Mailbox 17      */
+#define	MBIM18		0x0004	/* Enable Interrupt For Mailbox 18      */
+#define	MBIM19		0x0008	/* Enable Interrupt For Mailbox 19      */
+#define	MBIM20		0x0010	/* Enable Interrupt For Mailbox 20      */
+#define	MBIM21		0x0020	/* Enable Interrupt For Mailbox 21      */
+#define	MBIM22		0x0040	/* Enable Interrupt For Mailbox 22      */
+#define	MBIM23		0x0080	/* Enable Interrupt For Mailbox 23      */
+#define	MBIM24		0x0100	/* Enable Interrupt For Mailbox 24      */
+#define	MBIM25		0x0200	/* Enable Interrupt For Mailbox 25      */
+#define	MBIM26		0x0400	/* Enable Interrupt For Mailbox 26      */
+#define	MBIM27		0x0800	/* Enable Interrupt For Mailbox 27      */
+#define	MBIM28		0x1000	/* Enable Interrupt For Mailbox 28      */
+#define	MBIM29		0x2000	/* Enable Interrupt For Mailbox 29      */
+#define	MBIM30		0x4000	/* Enable Interrupt For Mailbox 30      */
+#define	MBIM31		0x8000	/* Enable Interrupt For Mailbox 31      */
+
+/* CAN_GIM Masks																*/
+#define	EWTIM		0x0001	/* Enable TX Error Count Interrupt                                      */
+#define	EWRIM		0x0002	/* Enable RX Error Count Interrupt                                      */
+#define	EPIM		0x0004	/* Enable Error-Passive Mode Interrupt                          */
+#define	BOIM		0x0008	/* Enable Bus Off Interrupt                                                     */
+#define	WUIM		0x0010	/* Enable Wake-Up Interrupt                                                     */
+#define	UIAIM		0x0020	/* Enable Access To Unimplemented Address Interrupt     */
+#define	AAIM		0x0040	/* Enable Abort Acknowledge Interrupt                           */
+#define	RMLIM		0x0080	/* Enable RX Message Lost Interrupt                                     */
+#define	UCEIM		0x0100	/* Enable Universal Counter Overflow Interrupt          */
+#define	EXTIM		0x0200	/* Enable External Trigger Output Interrupt                     */
+#define	ADIM		0x0400	/* Enable Access Denied Interrupt                                       */
+
+/* CAN_GIS Masks															*/
+#define	EWTIS		0x0001	/* TX Error Count IRQ Status                                    */
+#define	EWRIS		0x0002	/* RX Error Count IRQ Status                                    */
+#define	EPIS		0x0004	/* Error-Passive Mode IRQ Status                                */
+#define	BOIS		0x0008	/* Bus Off IRQ Status                                                   */
+#define	WUIS		0x0010	/* Wake-Up IRQ Status                                                   */
+#define	UIAIS		0x0020	/* Access To Unimplemented Address IRQ Status   */
+#define	AAIS		0x0040	/* Abort Acknowledge IRQ Status                                 */
+#define	RMLIS		0x0080	/* RX Message Lost IRQ Status                                   */
+#define	UCEIS		0x0100	/* Universal Counter Overflow IRQ Status                */
+#define	EXTIS		0x0200	/* External Trigger Output IRQ Status                   */
+#define	ADIS		0x0400	/* Access Denied IRQ Status                                             */
+
+/* CAN_GIF Masks															*/
+#define	EWTIF		0x0001	/* TX Error Count IRQ Flag                                              */
+#define	EWRIF		0x0002	/* RX Error Count IRQ Flag                                              */
+#define	EPIF		0x0004	/* Error-Passive Mode IRQ Flag                                  */
+#define	BOIF		0x0008	/* Bus Off IRQ Flag                                                             */
+#define	WUIF		0x0010	/* Wake-Up IRQ Flag                                                             */
+#define	UIAIF		0x0020	/* Access To Unimplemented Address IRQ Flag             */
+#define	AAIF		0x0040	/* Abort Acknowledge IRQ Flag                                   */
+#define	RMLIF		0x0080	/* RX Message Lost IRQ Flag                                             */
+#define	UCEIF		0x0100	/* Universal Counter Overflow IRQ Flag                  */
+#define	EXTIF		0x0200	/* External Trigger Output IRQ Flag                             */
+#define	ADIF		0x0400	/* Access Denied IRQ Flag                                               */
+
+/* CAN_UCCNF Masks															*/
+#define	UCCNF		0x000F	/* Universal Counter Mode                                               */
+#define UC_STAMP	0x0001	/*              Timestamp Mode                                                  */
+#define UC_WDOG		0x0002	/*              Watchdog Mode                                                   */
+#define UC_AUTOTX	0x0003	/*              Auto-Transmit Mode                                              */
+#define UC_ERROR	0x0006	/*              CAN Error Frame Count                                   */
+#define UC_OVER		0x0007	/*              CAN Overload Frame Count                                */
+#define UC_LOST		0x0008	/*              Arbitration Lost During TX Count                */
+#define UC_AA		0x0009	/*              TX Abort Count                                                  */
+#define UC_TA		0x000A	/*              TX Successful Count                                             */
+#define UC_REJECT	0x000B	/*              RX Message Rejected Count                               */
+#define UC_RML		0x000C	/*              RX Message Lost Count                                   */
+#define UC_RX		0x000D	/*              Total Successful RX Messages Count              */
+#define UC_RMP		0x000E	/*              Successful RX W/Matching ID Count               */
+#define UC_ALL		0x000F	/*              Correct Message On CAN Bus Line Count   */
+#define	UCRC		0x0020	/* Universal Counter Reload/Clear                               */
+#define	UCCT		0x0040	/* Universal Counter CAN Trigger                                */
+#define	UCE			0x0080	/* Universal Counter Enable                                             */
+
+/* CAN_ESR Masks										*/
+#define	ACKE		0x0004	/* Acknowledge Error            */
+#define	SER			0x0008	/* Stuff Error                          */
+#define	CRCE		0x0010	/* CRC Error                            */
+#define	SA0			0x0020	/* Stuck At Dominant Error      */
+#define	BEF			0x0040	/* Bit Error Flag                       */
+#define	FER			0x0080	/* Form Error Flag                      */
+
+/* CAN_EWR Masks												*/
+#define	EWLREC		0x00FF	/* RX Error Count Limit (For EWRIS)     */
+#define	EWLTEC		0xFF00	/* TX Error Count Limit (For EWTIS)     */
+
+/*  *******************  PIN CONTROL REGISTER MASKS  ************************/
+/* PORT_MUX Masks															*/
+#define	PJSE			0x0001	/* Port J SPI/SPORT Enable                      */
+#define	PJSE_SPORT		0x0000	/*              Enable TFS0/DT0PRI                      */
+#define	PJSE_SPI		0x0001	/*              Enable SPI_SSEL3:2                      */
+
+#define	PJCE(x)			(((x)&0x3)<<1)	/* Port J CAN/SPI/SPORT Enable          */
+#define	PJCE_SPORT		0x0000	/*              Enable DR0SEC/DT0SEC            */
+#define	PJCE_CAN		0x0002	/*              Enable CAN RX/TX                        */
+#define	PJCE_SPI		0x0004	/*              Enable SPI_SSEL7                        */
+
+#define	PFDE			0x0008	/* Port F DMA Request Enable            */
+#define	PGDE_UART		0x0000	/*              Enable UART0 RX/TX                      */
+#define	PGDE_DMA		0x0008	/*              Enable DMAR1:0                          */
+
+#define	PFTE			0x0010	/* Port F Timer Enable                          */
+#define	PFTE_UART		0x0000	/*              Enable UART1 RX/TX                      */
+#define	PFTE_TIMER		0x0010	/*              Enable TMR7:6                           */
+
+#define	PFS6E			0x0020	/* Port F SPI SSEL 6 Enable                     */
+#define	PFS6E_TIMER		0x0000	/*              Enable TMR5                                     */
+#define	PFS6E_SPI		0x0020	/*              Enable SPI_SSEL6                        */
+
+#define	PFS5E			0x0040	/* Port F SPI SSEL 5 Enable                     */
+#define	PFS5E_TIMER		0x0000	/*              Enable TMR4                                     */
+#define	PFS5E_SPI		0x0040	/*              Enable SPI_SSEL5                        */
+
+#define	PFS4E			0x0080	/* Port F SPI SSEL 4 Enable                     */
+#define	PFS4E_TIMER		0x0000	/*              Enable TMR3                                     */
+#define	PFS4E_SPI		0x0080	/*              Enable SPI_SSEL4                        */
+
+#define	PFFE			0x0100	/* Port F PPI Frame Sync Enable         */
+#define	PFFE_TIMER		0x0000	/*              Enable TMR2                                     */
+#define	PFFE_PPI		0x0100	/*              Enable PPI FS3                          */
+
+#define	PGSE			0x0200	/* Port G SPORT1 Secondary Enable       */
+#define	PGSE_PPI		0x0000	/*              Enable PPI D9:8                         */
+#define	PGSE_SPORT		0x0200	/*              Enable DR1SEC/DT1SEC            */
+
+#define	PGRE			0x0400	/* Port G SPORT1 Receive Enable         */
+#define	PGRE_PPI		0x0000	/*              Enable PPI D12:10                       */
+#define	PGRE_SPORT		0x0400	/*              Enable DR1PRI/RFS1/RSCLK1       */
+
+#define	PGTE			0x0800	/* Port G SPORT1 Transmit Enable        */
+#define	PGTE_PPI		0x0000	/*              Enable PPI D15:13                       */
+#define	PGTE_SPORT		0x0800	/*              Enable DT1PRI/TFS1/TSCLK1       */
+
+/*  ******************  HANDSHAKE DMA (HDMA) MASKS  *********************/
+/* HDMAx_CTL Masks														*/
+#define	HMDMAEN		0x0001	/* Enable Handshake DMA 0/1                                     */
+#define	REP			0x0002	/* HDMA Request Polarity                                        */
+#define	UTE			0x0004	/* Urgency Threshold Enable                                     */
+#define	OIE			0x0010	/* Overflow Interrupt Enable                            */
+#define	BDIE		0x0020	/* Block Done Interrupt Enable                          */
+#define	MBDI		0x0040	/* Mask Block Done IRQ If Pending ECNT          */
+#define	DRQ			0x0300	/* HDMA Request Type                                            */
+#define	DRQ_NONE	0x0000	/*              No Request                                                      */
+#define	DRQ_SINGLE	0x0100	/*              Channels Request Single                         */
+#define	DRQ_MULTI	0x0200	/*              Channels Request Multi (Default)        */
+#define	DRQ_URGENT	0x0300	/*              Channels Request Multi Urgent           */
+#define	RBC			0x1000	/* Reload BCNT With IBCNT                                       */
+#define	PS			0x2000	/* HDMA Pin Status                                                      */
+#define	OI			0x4000	/* Overflow Interrupt Generated                         */
+#define	BDI			0x8000	/* Block Done Interrupt Generated                       */
+
+#endif				/* _DEF_BF534_H */
diff --git a/include/asm-blackfin/mach-bf537/defBF537.h b/include/asm-blackfin/mach-bf537/defBF537.h
new file mode 100644
index 0000000..26f9c02
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/defBF537.h
@@ -0,0 +1,404 @@
+/*
+ * file:         include/asm-blackfin/mach-bf537/defbf537.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _DEF_BF537_H
+#define _DEF_BF537_H
+
+/*include all Core registers and bit definitions*/
+#include "defBF537.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+/************************************************************************************
+** Define EMAC Section Unique to BF536/BF537
+*************************************************************************************/
+
+/* 10/100 Ethernet Controller	(0xFFC03000 - 0xFFC031FF)										*/
+#define	EMAC_OPMODE			0xFFC03000	/* Operating Mode Register                                                              */
+#define EMAC_ADDRLO			0xFFC03004	/* Address Low (32 LSBs) Register                                               */
+#define EMAC_ADDRHI			0xFFC03008	/* Address High (16 MSBs) Register                                              */
+#define EMAC_HASHLO			0xFFC0300C	/* Multicast Hash Table Low (Bins 31-0) Register                */
+#define EMAC_HASHHI			0xFFC03010	/* Multicast Hash Table High (Bins 63-32) Register              */
+#define EMAC_STAADD			0xFFC03014	/* Station Management Address Register                                  */
+#define EMAC_STADAT			0xFFC03018	/* Station Management Data Register                                     */
+#define EMAC_FLC			0xFFC0301C	/* Flow Control Register                                                                */
+#define EMAC_VLAN1			0xFFC03020	/* VLAN1 Tag Register                                                                   */
+#define EMAC_VLAN2			0xFFC03024	/* VLAN2 Tag Register                                                                   */
+#define EMAC_WKUP_CTL		0xFFC0302C	/* Wake-Up Control/Status Register                                              */
+#define EMAC_WKUP_FFMSK0	0xFFC03030	/* Wake-Up Frame Filter 0 Byte Mask Register                    */
+#define EMAC_WKUP_FFMSK1	0xFFC03034	/* Wake-Up Frame Filter 1 Byte Mask Register                    */
+#define EMAC_WKUP_FFMSK2	0xFFC03038	/* Wake-Up Frame Filter 2 Byte Mask Register                    */
+#define EMAC_WKUP_FFMSK3	0xFFC0303C	/* Wake-Up Frame Filter 3 Byte Mask Register                    */
+#define EMAC_WKUP_FFCMD		0xFFC03040	/* Wake-Up Frame Filter Commands Register                               */
+#define EMAC_WKUP_FFOFF		0xFFC03044	/* Wake-Up Frame Filter Offsets Register                                */
+#define EMAC_WKUP_FFCRC0	0xFFC03048	/* Wake-Up Frame Filter 0,1 CRC-16 Register                             */
+#define EMAC_WKUP_FFCRC1	0xFFC0304C	/* Wake-Up Frame Filter 2,3 CRC-16 Register                             */
+
+#define	EMAC_SYSCTL			0xFFC03060	/* EMAC System Control Register                                                 */
+#define EMAC_SYSTAT			0xFFC03064	/* EMAC System Status Register                                                  */
+#define EMAC_RX_STAT		0xFFC03068	/* RX Current Frame Status Register                                             */
+#define EMAC_RX_STKY		0xFFC0306C	/* RX Sticky Frame Status Register                                              */
+#define EMAC_RX_IRQE		0xFFC03070	/* RX Frame Status Interrupt Enables Register                   */
+#define EMAC_TX_STAT		0xFFC03074	/* TX Current Frame Status Register                                             */
+#define EMAC_TX_STKY		0xFFC03078	/* TX Sticky Frame Status Register                                              */
+#define EMAC_TX_IRQE		0xFFC0307C	/* TX Frame Status Interrupt Enables Register                   */
+
+#define EMAC_MMC_CTL		0xFFC03080	/* MMC Counter Control Register                                                 */
+#define EMAC_MMC_RIRQS		0xFFC03084	/* MMC RX Interrupt Status Register                                             */
+#define EMAC_MMC_RIRQE		0xFFC03088	/* MMC RX Interrupt Enables Register                                    */
+#define EMAC_MMC_TIRQS		0xFFC0308C	/* MMC TX Interrupt Status Register                                             */
+#define EMAC_MMC_TIRQE		0xFFC03090	/* MMC TX Interrupt Enables Register                                    */
+
+#define EMAC_RXC_OK			0xFFC03100	/* RX Frame Successful Count                                                    */
+#define EMAC_RXC_FCS		0xFFC03104	/* RX Frame FCS Failure Count                                                   */
+#define EMAC_RXC_ALIGN		0xFFC03108	/* RX Alignment Error Count                                                             */
+#define EMAC_RXC_OCTET		0xFFC0310C	/* RX Octets Successfully Received Count                                */
+#define EMAC_RXC_DMAOVF		0xFFC03110	/* Internal MAC Sublayer Error RX Frame Count                   */
+#define EMAC_RXC_UNICST		0xFFC03114	/* Unicast RX Frame Count                                                               */
+#define EMAC_RXC_MULTI		0xFFC03118	/* Multicast RX Frame Count                                                             */
+#define EMAC_RXC_BROAD		0xFFC0311C	/* Broadcast RX Frame Count                                                             */
+#define EMAC_RXC_LNERRI		0xFFC03120	/* RX Frame In Range Error Count                                                */
+#define EMAC_RXC_LNERRO		0xFFC03124	/* RX Frame Out Of Range Error Count                                    */
+#define EMAC_RXC_LONG		0xFFC03128	/* RX Frame Too Long Count                                                              */
+#define EMAC_RXC_MACCTL		0xFFC0312C	/* MAC Control RX Frame Count                                                   */
+#define EMAC_RXC_OPCODE		0xFFC03130	/* Unsupported Op-Code RX Frame Count                                   */
+#define EMAC_RXC_PAUSE		0xFFC03134	/* MAC Control Pause RX Frame Count                                             */
+#define EMAC_RXC_ALLFRM		0xFFC03138	/* Overall RX Frame Count                                                               */
+#define EMAC_RXC_ALLOCT		0xFFC0313C	/* Overall RX Octet Count                                                               */
+#define EMAC_RXC_TYPED		0xFFC03140	/* Type/Length Consistent RX Frame Count                                */
+#define EMAC_RXC_SHORT		0xFFC03144	/* RX Frame Fragment Count - Byte Count x < 64                  */
+#define EMAC_RXC_EQ64		0xFFC03148	/* Good RX Frame Count - Byte Count x = 64                              */
+#define EMAC_RXC_LT128		0xFFC0314C	/* Good RX Frame Count - Byte Count  64 <= x < 128              */
+#define EMAC_RXC_LT256		0xFFC03150	/* Good RX Frame Count - Byte Count 128 <= x < 256              */
+#define EMAC_RXC_LT512		0xFFC03154	/* Good RX Frame Count - Byte Count 256 <= x < 512              */
+#define EMAC_RXC_LT1024		0xFFC03158	/* Good RX Frame Count - Byte Count 512 <= x < 1024             */
+#define EMAC_RXC_GE1024		0xFFC0315C	/* Good RX Frame Count - Byte Count x >= 1024                   */
+
+#define EMAC_TXC_OK			0xFFC03180	/* TX Frame Successful Count                                                    */
+#define EMAC_TXC_1COL		0xFFC03184	/* TX Frames Successful After Single Collision Count    */
+#define EMAC_TXC_GT1COL		0xFFC03188	/* TX Frames Successful After Multiple Collisions Count */
+#define EMAC_TXC_OCTET		0xFFC0318C	/* TX Octets Successfully Received Count                                */
+#define EMAC_TXC_DEFER		0xFFC03190	/* TX Frame Delayed Due To Busy Count                                   */
+#define EMAC_TXC_LATECL		0xFFC03194	/* Late TX Collisions Count                                                             */
+#define EMAC_TXC_XS_COL		0xFFC03198	/* TX Frame Failed Due To Excessive Collisions Count    */
+#define EMAC_TXC_DMAUND		0xFFC0319C	/* Internal MAC Sublayer Error TX Frame Count                   */
+#define EMAC_TXC_CRSERR		0xFFC031A0	/* Carrier Sense Deasserted During TX Frame Count               */
+#define EMAC_TXC_UNICST		0xFFC031A4	/* Unicast TX Frame Count                                                               */
+#define EMAC_TXC_MULTI		0xFFC031A8	/* Multicast TX Frame Count                                                             */
+#define EMAC_TXC_BROAD		0xFFC031AC	/* Broadcast TX Frame Count                                                             */
+#define EMAC_TXC_XS_DFR		0xFFC031B0	/* TX Frames With Excessive Deferral Count                              */
+#define EMAC_TXC_MACCTL		0xFFC031B4	/* MAC Control TX Frame Count                                                   */
+#define EMAC_TXC_ALLFRM		0xFFC031B8	/* Overall TX Frame Count                                                               */
+#define EMAC_TXC_ALLOCT		0xFFC031BC	/* Overall TX Octet Count                                                               */
+#define EMAC_TXC_EQ64		0xFFC031C0	/* Good TX Frame Count - Byte Count x = 64                              */
+#define EMAC_TXC_LT128		0xFFC031C4	/* Good TX Frame Count - Byte Count  64 <= x < 128              */
+#define EMAC_TXC_LT256		0xFFC031C8	/* Good TX Frame Count - Byte Count 128 <= x < 256              */
+#define EMAC_TXC_LT512		0xFFC031CC	/* Good TX Frame Count - Byte Count 256 <= x < 512              */
+#define EMAC_TXC_LT1024		0xFFC031D0	/* Good TX Frame Count - Byte Count 512 <= x < 1024             */
+#define EMAC_TXC_GE1024		0xFFC031D4	/* Good TX Frame Count - Byte Count x >= 1024                   */
+#define EMAC_TXC_ABORT		0xFFC031D8	/* Total TX Frames Aborted Count                                                */
+
+/* Listing for IEEE-Supported Count Registers																	*/
+#define FramesReceivedOK				EMAC_RXC_OK	/* RX Frame Successful Count                                                    */
+#define FrameCheckSequenceErrors		EMAC_RXC_FCS	/* RX Frame FCS Failure Count                                                   */
+#define AlignmentErrors					EMAC_RXC_ALIGN	/* RX Alignment Error Count                                                             */
+#define OctetsReceivedOK				EMAC_RXC_OCTET	/* RX Octets Successfully Received Count                                */
+#define FramesLostDueToIntMACRcvError	EMAC_RXC_DMAOVF	/* Internal MAC Sublayer Error RX Frame Count                   */
+#define UnicastFramesReceivedOK			EMAC_RXC_UNICST	/* Unicast RX Frame Count                                                               */
+#define MulticastFramesReceivedOK		EMAC_RXC_MULTI	/* Multicast RX Frame Count                                                             */
+#define BroadcastFramesReceivedOK		EMAC_RXC_BROAD	/* Broadcast RX Frame Count                                                             */
+#define InRangeLengthErrors				EMAC_RXC_LNERRI	/* RX Frame In Range Error Count                                                */
+#define OutOfRangeLengthField			EMAC_RXC_LNERRO	/* RX Frame Out Of Range Error Count                                    */
+#define FrameTooLongErrors				EMAC_RXC_LONG	/* RX Frame Too Long Count                                                              */
+#define MACControlFramesReceived		EMAC_RXC_MACCTL	/* MAC Control RX Frame Count                                                   */
+#define UnsupportedOpcodesReceived		EMAC_RXC_OPCODE	/* Unsupported Op-Code RX Frame Count                                   */
+#define PAUSEMACCtrlFramesReceived		EMAC_RXC_PAUSE	/* MAC Control Pause RX Frame Count                                             */
+#define FramesReceivedAll				EMAC_RXC_ALLFRM	/* Overall RX Frame Count                                                               */
+#define OctetsReceivedAll				EMAC_RXC_ALLOCT	/* Overall RX Octet Count                                                               */
+#define TypedFramesReceived				EMAC_RXC_TYPED	/* Type/Length Consistent RX Frame Count                                */
+#define FramesLenLt64Received			EMAC_RXC_SHORT	/* RX Frame Fragment Count - Byte Count x < 64                  */
+#define FramesLenEq64Received			EMAC_RXC_EQ64	/* Good RX Frame Count - Byte Count x = 64                              */
+#define FramesLen65_127Received			EMAC_RXC_LT128	/* Good RX Frame Count - Byte Count  64 <= x < 128              */
+#define FramesLen128_255Received		EMAC_RXC_LT256	/* Good RX Frame Count - Byte Count 128 <= x < 256              */
+#define FramesLen256_511Received		EMAC_RXC_LT512	/* Good RX Frame Count - Byte Count 256 <= x < 512              */
+#define FramesLen512_1023Received		EMAC_RXC_LT1024	/* Good RX Frame Count - Byte Count 512 <= x < 1024             */
+#define FramesLen1024_MaxReceived		EMAC_RXC_GE1024	/* Good RX Frame Count - Byte Count x >= 1024                   */
+
+#define FramesTransmittedOK				EMAC_TXC_OK	/* TX Frame Successful Count                                                    */
+#define SingleCollisionFrames			EMAC_TXC_1COL	/* TX Frames Successful After Single Collision Count    */
+#define MultipleCollisionFrames			EMAC_TXC_GT1COL	/* TX Frames Successful After Multiple Collisions Count */
+#define OctetsTransmittedOK				EMAC_TXC_OCTET	/* TX Octets Successfully Received Count                                */
+#define FramesWithDeferredXmissions		EMAC_TXC_DEFER	/* TX Frame Delayed Due To Busy Count                                   */
+#define LateCollisions					EMAC_TXC_LATECL	/* Late TX Collisions Count                                                             */
+#define FramesAbortedDueToXSColls		EMAC_TXC_XS_COL	/* TX Frame Failed Due To Excessive Collisions Count    */
+#define FramesLostDueToIntMacXmitError	EMAC_TXC_DMAUND	/* Internal MAC Sublayer Error TX Frame Count                   */
+#define CarrierSenseErrors				EMAC_TXC_CRSERR	/* Carrier Sense Deasserted During TX Frame Count               */
+#define UnicastFramesXmittedOK			EMAC_TXC_UNICST	/* Unicast TX Frame Count                                                               */
+#define MulticastFramesXmittedOK		EMAC_TXC_MULTI	/* Multicast TX Frame Count                                                             */
+#define BroadcastFramesXmittedOK		EMAC_TXC_BROAD	/* Broadcast TX Frame Count                                                             */
+#define FramesWithExcessiveDeferral		EMAC_TXC_XS_DFR	/* TX Frames With Excessive Deferral Count                              */
+#define MACControlFramesTransmitted		EMAC_TXC_MACCTL	/* MAC Control TX Frame Count                                                   */
+#define FramesTransmittedAll			EMAC_TXC_ALLFRM	/* Overall TX Frame Count                                                               */
+#define OctetsTransmittedAll			EMAC_TXC_ALLOCT	/* Overall TX Octet Count                                                               */
+#define FramesLenEq64Transmitted		EMAC_TXC_EQ64	/* Good TX Frame Count - Byte Count x = 64                              */
+#define FramesLen65_127Transmitted		EMAC_TXC_LT128	/* Good TX Frame Count - Byte Count  64 <= x < 128              */
+#define FramesLen128_255Transmitted		EMAC_TXC_LT256	/* Good TX Frame Count - Byte Count 128 <= x < 256              */
+#define FramesLen256_511Transmitted		EMAC_TXC_LT512	/* Good TX Frame Count - Byte Count 256 <= x < 512              */
+#define FramesLen512_1023Transmitted	EMAC_TXC_LT1024	/* Good TX Frame Count - Byte Count 512 <= x < 1024             */
+#define FramesLen1024_MaxTransmitted	EMAC_TXC_GE1024	/* Good TX Frame Count - Byte Count x >= 1024                   */
+#define TxAbortedFrames					EMAC_TXC_ABORT	/* Total TX Frames Aborted Count                                                */
+
+/***********************************************************************************
+** System MMR Register Bits And Macros
+**
+** Disclaimer:	All macros are intended to make C and Assembly code more readable.
+**				Use these macros carefully, as any that do left shifts for field
+**				depositing will result in the lower order bits being destroyed.  Any
+**				macro that shifts left to properly position the bit-field should be
+**				used as part of an OR to initialize a register and NOT as a dynamic
+**				modifier UNLESS the lower order bits are saved and ORed back in when
+**				the macro is used.
+*************************************************************************************/
+/************************  ETHERNET 10/100 CONTROLLER MASKS  ************************/
+/* EMAC_OPMODE Masks																*/
+#define	RE			0x00000001	/* Receiver Enable                                                                      */
+#define	ASTP		0x00000002	/* Enable Automatic Pad Stripping On RX Frames          */
+#define	HU			0x00000010	/* Hash Filter Unicast Address                                          */
+#define	HM			0x00000020	/* Hash Filter Multicast Address                                        */
+#define	PAM			0x00000040	/* Pass-All-Multicast Mode Enable                                       */
+#define	PR			0x00000080	/* Promiscuous Mode Enable                                                      */
+#define	IFE			0x00000100	/* Inverse Filtering Enable                                                     */
+#define	DBF			0x00000200	/* Disable Broadcast Frame Reception                            */
+#define	PBF			0x00000400	/* Pass Bad Frames Enable                                                       */
+#define	PSF			0x00000800	/* Pass Short Frames Enable                                                     */
+#define	RAF			0x00001000	/* Receive-All Mode                                                                     */
+#define	TE			0x00010000	/* Transmitter Enable                                                           */
+#define	DTXPAD		0x00020000	/* Disable Automatic TX Padding                                         */
+#define	DTXCRC		0x00040000	/* Disable Automatic TX CRC Generation                          */
+#define	DC			0x00080000	/* Deferral Check                                                                       */
+#define	BOLMT		0x00300000	/* Back-Off Limit                                                                       */
+#define	BOLMT_10	0x00000000	/*              10-bit range                                                            */
+#define	BOLMT_8		0x00100000	/*              8-bit range                                                                     */
+#define	BOLMT_4		0x00200000	/*              4-bit range                                                                     */
+#define	BOLMT_1		0x00300000	/*              1-bit range                                                                     */
+#define	DRTY		0x00400000	/* Disable TX Retry On Collision                                        */
+#define	LCTRE		0x00800000	/* Enable TX Retry On Late Collision                            */
+#define	RMII		0x01000000	/* RMII/MII* Mode                                                                       */
+#define	RMII_10		0x02000000	/* Speed Select for RMII Port (10MBit/100MBit*)         */
+#define	FDMODE		0x04000000	/* Duplex Mode Enable (Full/Half*)                                      */
+#define	LB			0x08000000	/* Internal Loopback Enable                                                     */
+#define	DRO			0x10000000	/* Disable Receive Own Frames (Half-Duplex Mode)        */
+
+/* EMAC_STAADD Masks																*/
+#define	STABUSY		0x00000001	/* Initiate Station Mgt Reg Access / STA Busy Stat      */
+#define	STAOP		0x00000002	/* Station Management Operation Code (Write/Read*)      */
+#define	STADISPRE	0x00000004	/* Disable Preamble Generation                                          */
+#define	STAIE		0x00000008	/* Station Mgt. Transfer Done Interrupt Enable          */
+#define	REGAD		0x000007C0	/* STA Register Address                                                         */
+#define	PHYAD		0x0000F800	/* PHY Device Address                                                           */
+
+#define	SET_REGAD(x)	(((x)&0x1F)<<  6 )	/* Set STA Register Address                             */
+#define	SET_PHYAD(x)	(((x)&0x1F)<< 11 )	/* Set PHY Device Address                               */
+
+/* EMAC_STADAT Mask											*/
+#define	STADATA		0x0000FFFF	/* Station Management Data      */
+
+/* EMAC_FLC Masks																	*/
+#define	FLCBUSY		0x00000001	/* Send Flow Ctrl Frame / Flow Ctrl Busy Status         */
+#define	FLCE		0x00000002	/* Flow Control Enable                                                          */
+#define	PCF			0x00000004	/* Pass Control Frames                                                          */
+#define	BKPRSEN		0x00000008	/* Enable Backpressure                                                          */
+#define	FLCPAUSE	0xFFFF0000	/* Pause Time                                                                           */
+
+#define	SET_FLCPAUSE(x)	(((x)&0xFFFF)<< 16)	/* Set Pause Time                                               */
+
+/* EMAC_WKUP_CTL Masks																*/
+#define	CAPWKFRM	0x00000001	/* Capture Wake-Up Frames                                                       */
+#define	MPKE		0x00000002	/* Magic Packet Enable                                                          */
+#define	RWKE		0x00000004	/* Remote Wake-Up Frame Enable                                          */
+#define	GUWKE		0x00000008	/* Global Unicast Wake Enable                                           */
+#define	MPKS		0x00000020	/* Magic Packet Received Status                                         */
+#define	RWKS		0x00000F00	/* Wake-Up Frame Received Status, Filters 3:0           */
+
+/* EMAC_WKUP_FFCMD Masks															*/
+#define	WF0_E		0x00000001	/* Enable Wake-Up Filter 0                                                      */
+#define	WF0_T		0x00000008	/* Wake-Up Filter 0 Addr Type (Multicast/Unicast*)      */
+#define	WF1_E		0x00000100	/* Enable Wake-Up Filter 1                                                      */
+#define	WF1_T		0x00000800	/* Wake-Up Filter 1 Addr Type (Multicast/Unicast*)      */
+#define	WF2_E		0x00010000	/* Enable Wake-Up Filter 2                                                      */
+#define	WF2_T		0x00080000	/* Wake-Up Filter 2 Addr Type (Multicast/Unicast*)      */
+#define	WF3_E		0x01000000	/* Enable Wake-Up Filter 3                                                      */
+#define	WF3_T		0x08000000	/* Wake-Up Filter 3 Addr Type (Multicast/Unicast*)      */
+
+/* EMAC_WKUP_FFOFF Masks															*/
+#define	WF0_OFF		0x000000FF	/* Wake-Up Filter 0 Pattern Offset                                      */
+#define	WF1_OFF		0x0000FF00	/* Wake-Up Filter 1 Pattern Offset                                      */
+#define	WF2_OFF		0x00FF0000	/* Wake-Up Filter 2 Pattern Offset                                      */
+#define	WF3_OFF		0xFF000000	/* Wake-Up Filter 3 Pattern Offset                                      */
+
+#define	SET_WF0_OFF(x) (((x)&0xFF)<<  0 )	/* Set Wake-Up Filter 0 Byte Offset           */
+#define	SET_WF1_OFF(x) (((x)&0xFF)<<  8 )	/* Set Wake-Up Filter 1 Byte Offset           */
+#define	SET_WF2_OFF(x) (((x)&0xFF)<< 16 )	/* Set Wake-Up Filter 2 Byte Offset           */
+#define	SET_WF3_OFF(x) (((x)&0xFF)<< 24 )	/* Set Wake-Up Filter 3 Byte Offset           */
+/* Set ALL Offsets																	*/
+#define	SET_WF_OFFS(x0,x1,x2,x3) 	(SET_WF0_OFF((x0))|SET_WF1_OFF((x1))|SET_WF2_OFF((x2))|SET_WF3_OFF((x3)))
+
+/* EMAC_WKUP_FFCRC0 Masks															*/
+#define	WF0_CRC		0x0000FFFF	/* Wake-Up Filter 0 Pattern CRC                                         */
+#define	WF1_CRC		0xFFFF0000	/* Wake-Up Filter 1 Pattern CRC                                         */
+
+#define	SET_WF0_CRC(x) (((x)&0xFFFF)<<   0 )	/* Set Wake-Up Filter 0 Target CRC         */
+#define	SET_WF1_CRC(x) (((x)&0xFFFF)<<  16 )	/* Set Wake-Up Filter 1 Target CRC         */
+
+/* EMAC_WKUP_FFCRC1 Masks															*/
+#define	WF2_CRC		0x0000FFFF	/* Wake-Up Filter 2 Pattern CRC                                         */
+#define	WF3_CRC		0xFFFF0000	/* Wake-Up Filter 3 Pattern CRC                                         */
+
+#define	SET_WF2_CRC(x) (((x)&0xFFFF)<<   0 )	/* Set Wake-Up Filter 2 Target CRC         */
+#define	SET_WF3_CRC(x) (((x)&0xFFFF)<<  16 )	/* Set Wake-Up Filter 3 Target CRC         */
+
+/* EMAC_SYSCTL Masks																*/
+#define	PHYIE		0x00000001	/* PHY_INT Interrupt Enable                                                     */
+#define	RXDWA		0x00000002	/* Receive Frame DMA Word Alignment (Odd/Even*)         */
+#define	RXCKS		0x00000004	/* Enable RX Frame TCP/UDP Checksum Computation         */
+#define	MDCDIV		0x00003F00	/* SCLK:MDC Clock Divisor [MDC=SCLK/(2*(N+1))]          */
+
+#define	SET_MDCDIV(x)	(((x)&0x3F)<< 8)	/* Set MDC Clock Divisor                                */
+
+/* EMAC_SYSTAT Masks															*/
+#define	PHYINT		0x00000001	/* PHY_INT Interrupt Status                                             */
+#define	MMCINT		0x00000002	/* MMC Counter Interrupt Status                                 */
+#define	RXFSINT		0x00000004	/* RX Frame-Status Interrupt Status                             */
+#define	TXFSINT		0x00000008	/* TX Frame-Status Interrupt Status                             */
+#define	WAKEDET		0x00000010	/* Wake-Up Detected Status                                              */
+#define	RXDMAERR	0x00000020	/* RX DMA Direction Error Status                                */
+#define	TXDMAERR	0x00000040	/* TX DMA Direction Error Status                                */
+#define	STMDONE		0x00000080	/* Station Mgt. Transfer Done Interrupt Status  */
+
+/* EMAC_RX_STAT, EMAC_RX_STKY, and EMAC_RX_IRQE Masks							*/
+#define	RX_FRLEN	0x000007FF	/* Frame Length In Bytes                                                */
+#define	RX_COMP		0x00001000	/* RX Frame Complete                                                    */
+#define	RX_OK		0x00002000	/* RX Frame Received With No Errors                             */
+#define	RX_LONG		0x00004000	/* RX Frame Too Long Error                                              */
+#define	RX_ALIGN	0x00008000	/* RX Frame Alignment Error                                             */
+#define	RX_CRC		0x00010000	/* RX Frame CRC Error                                                   */
+#define	RX_LEN		0x00020000	/* RX Frame Length Error                                                */
+#define	RX_FRAG		0x00040000	/* RX Frame Fragment Error                                              */
+#define	RX_ADDR		0x00080000	/* RX Frame Address Filter Failed Error                 */
+#define	RX_DMAO		0x00100000	/* RX Frame DMA Overrun Error                                   */
+#define	RX_PHY		0x00200000	/* RX Frame PHY Error                                                   */
+#define	RX_LATE		0x00400000	/* RX Frame Late Collision Error                                */
+#define	RX_RANGE	0x00800000	/* RX Frame Length Field Out of Range Error             */
+#define	RX_MULTI	0x01000000	/* RX Multicast Frame Indicator                                 */
+#define	RX_BROAD	0x02000000	/* RX Broadcast Frame Indicator                                 */
+#define	RX_CTL		0x04000000	/* RX Control Frame Indicator                                   */
+#define	RX_UCTL		0x08000000	/* Unsupported RX Control Frame Indicator               */
+#define	RX_TYPE		0x10000000	/* RX Typed Frame Indicator                                             */
+#define	RX_VLAN1	0x20000000	/* RX VLAN1 Frame Indicator                                             */
+#define	RX_VLAN2	0x40000000	/* RX VLAN2 Frame Indicator                                             */
+#define	RX_ACCEPT	0x80000000	/* RX Frame Accepted Indicator                                  */
+
+/*  EMAC_TX_STAT, EMAC_TX_STKY, and EMAC_TX_IRQE Masks							*/
+#define	TX_COMP		0x00000001	/* TX Frame Complete                                                    */
+#define	TX_OK		0x00000002	/* TX Frame Sent With No Errors                                 */
+#define	TX_ECOLL	0x00000004	/* TX Frame Excessive Collision Error                   */
+#define	TX_LATE		0x00000008	/* TX Frame Late Collision Error                                */
+#define	TX_DMAU		0x00000010	/* TX Frame DMA Underrun Error (STAT)                   */
+#define	TX_MACE		0x00000010	/* Internal MAC Error Detected (STKY and IRQE)  */
+#define	TX_EDEFER	0x00000020	/* TX Frame Excessive Deferral Error                    */
+#define	TX_BROAD	0x00000040	/* TX Broadcast Frame Indicator                                 */
+#define	TX_MULTI	0x00000080	/* TX Multicast Frame Indicator                                 */
+#define	TX_CCNT		0x00000F00	/* TX Frame Collision Count                                             */
+#define	TX_DEFER	0x00001000	/* TX Frame Deferred Indicator                                  */
+#define	TX_CRS		0x00002000	/* TX Frame Carrier Sense Not Asserted Error    */
+#define	TX_LOSS		0x00004000	/* TX Frame Carrier Lost During TX Error                */
+#define	TX_RETRY	0x00008000	/* TX Frame Successful After Retry                              */
+#define	TX_FRLEN	0x07FF0000	/* TX Frame Length (Bytes)                                              */
+
+/* EMAC_MMC_CTL Masks															*/
+#define	RSTC		0x00000001	/* Reset All Counters                                                   */
+#define	CROLL		0x00000002	/* Counter Roll-Over Enable                                             */
+#define	CCOR		0x00000004	/* Counter Clear-On-Read Mode Enable                    */
+#define	MMCE		0x00000008	/* Enable MMC Counter Operation                                 */
+
+/* EMAC_MMC_RIRQS and EMAC_MMC_RIRQE Masks											*/
+#define	RX_OK_CNT		0x00000001	/* RX Frames Received With No Errors                    */
+#define	RX_FCS_CNT		0x00000002	/* RX Frames W/Frame Check Sequence Errors              */
+#define	RX_ALIGN_CNT	0x00000004	/* RX Frames With Alignment Errors                              */
+#define	RX_OCTET_CNT	0x00000008	/* RX Octets Received OK                                                */
+#define	RX_LOST_CNT		0x00000010	/* RX Frames Lost Due To Internal MAC RX Error  */
+#define	RX_UNI_CNT		0x00000020	/* Unicast RX Frames Received OK                                */
+#define	RX_MULTI_CNT	0x00000040	/* Multicast RX Frames Received OK                              */
+#define	RX_BROAD_CNT	0x00000080	/* Broadcast RX Frames Received OK                              */
+#define	RX_IRL_CNT		0x00000100	/* RX Frames With In-Range Length Errors                */
+#define	RX_ORL_CNT		0x00000200	/* RX Frames With Out-Of-Range Length Errors    */
+#define	RX_LONG_CNT		0x00000400	/* RX Frames With Frame Too Long Errors                 */
+#define	RX_MACCTL_CNT	0x00000800	/* MAC Control RX Frames Received                               */
+#define	RX_OPCODE_CTL	0x00001000	/* Unsupported Op-Code RX Frames Received               */
+#define	RX_PAUSE_CNT	0x00002000	/* PAUSEMAC Control RX Frames Received                  */
+#define	RX_ALLF_CNT		0x00004000	/* All RX Frames Received                                               */
+#define	RX_ALLO_CNT		0x00008000	/* All RX Octets Received                                               */
+#define	RX_TYPED_CNT	0x00010000	/* Typed RX Frames Received                                             */
+#define	RX_SHORT_CNT	0x00020000	/* RX Frame Fragments (< 64 Bytes) Received             */
+#define	RX_EQ64_CNT		0x00040000	/* 64-Byte RX Frames Received                                   */
+#define	RX_LT128_CNT	0x00080000	/* 65-127-Byte RX Frames Received                               */
+#define	RX_LT256_CNT	0x00100000	/* 128-255-Byte RX Frames Received                              */
+#define	RX_LT512_CNT	0x00200000	/* 256-511-Byte RX Frames Received                              */
+#define	RX_LT1024_CNT	0x00400000	/* 512-1023-Byte RX Frames Received                             */
+#define	RX_GE1024_CNT	0x00800000	/* 1024-Max-Byte RX Frames Received                             */
+
+/* EMAC_MMC_TIRQS and EMAC_MMC_TIRQE Masks											*/
+#define	TX_OK_CNT		0x00000001	/* TX Frames Sent OK                                                    */
+#define	TX_SCOLL_CNT	0x00000002	/* TX Frames With Single Collisions                             */
+#define	TX_MCOLL_CNT	0x00000004	/* TX Frames With Multiple Collisions                   */
+#define	TX_OCTET_CNT	0x00000008	/* TX Octets Sent OK                                                    */
+#define	TX_DEFER_CNT	0x00000010	/* TX Frames With Deferred Transmission                 */
+#define	TX_LATE_CNT		0x00000020	/* TX Frames With Late Collisions                               */
+#define	TX_ABORTC_CNT	0x00000040	/* TX Frames Aborted Due To Excess Collisions   */
+#define	TX_LOST_CNT		0x00000080	/* TX Frames Lost Due To Internal MAC TX Error  */
+#define	TX_CRS_CNT		0x00000100	/* TX Frames With Carrier Sense Errors                  */
+#define	TX_UNI_CNT		0x00000200	/* Unicast TX Frames Sent                                               */
+#define	TX_MULTI_CNT	0x00000400	/* Multicast TX Frames Sent                                             */
+#define	TX_BROAD_CNT	0x00000800	/* Broadcast TX Frames Sent                                             */
+#define	TX_EXDEF_CTL	0x00001000	/* TX Frames With Excessive Deferral                    */
+#define	TX_MACCTL_CNT	0x00002000	/* MAC Control TX Frames Sent                                   */
+#define	TX_ALLF_CNT		0x00004000	/* All TX Frames Sent                                                   */
+#define	TX_ALLO_CNT		0x00008000	/* All TX Octets Sent                                                   */
+#define	TX_EQ64_CNT		0x00010000	/* 64-Byte TX Frames Sent                                               */
+#define	TX_LT128_CNT	0x00020000	/* 65-127-Byte TX Frames Sent                                   */
+#define	TX_LT256_CNT	0x00040000	/* 128-255-Byte TX Frames Sent                                  */
+#define	TX_LT512_CNT	0x00080000	/* 256-511-Byte TX Frames Sent                                  */
+#define	TX_LT1024_CNT	0x00100000	/* 512-1023-Byte TX Frames Sent                                 */
+#define	TX_GE1024_CNT	0x00200000	/* 1024-Max-Byte TX Frames Sent                                 */
+#define	TX_ABORT_CNT	0x00400000	/* TX Frames Aborted                                                    */
+
+#endif				/* _DEF_BF537_H */
diff --git a/include/asm-blackfin/mach-bf537/dma.h b/include/asm-blackfin/mach-bf537/dma.h
new file mode 100644
index 0000000..7a96404
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/dma.h
@@ -0,0 +1,55 @@
+/*
+ * file:         include/asm-blackfin/mach-bf537/dma.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 16
+
+#define CH_PPI 			    0
+#define CH_EMAC_RX 		    1
+#define CH_EMAC_TX 		    2
+#define CH_SPORT0_RX 		3
+#define CH_SPORT0_TX 		4
+#define CH_SPORT1_RX 		5
+#define CH_SPORT1_TX 		6
+#define CH_SPI 			    7
+#define CH_UART0_RX 		8
+#define CH_UART0_TX 		9
+#define CH_UART1_RX 		10
+#define CH_UART1_TX 		11
+
+#define CH_MEM_STREAM0_DEST	12	 /* TX */
+#define CH_MEM_STREAM0_SRC  	13	 /* RX */
+#define CH_MEM_STREAM1_DEST	14	 /* TX */
+#define CH_MEM_STREAM1_SRC 	15	 /* RX */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf537/irq.h b/include/asm-blackfin/mach-bf537/irq.h
new file mode 100644
index 0000000..8af2a83
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/irq.h
@@ -0,0 +1,219 @@
+/*
+ * file:         include/asm-blackfin/mach-bf537/irq.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _BF537_IRQ_H_
+#define _BF537_IRQ_H_
+
+/*
+ * Interrupt source definitions
+             Event Source    Core Event Name
+Core        Emulation               **
+ Events         (highest priority)  EMU         0
+            Reset                   RST         1
+            NMI                     NMI         2
+            Exception               EVX         3
+            Reserved                --          4
+            Hardware Error          IVHW        5
+            Core Timer              IVTMR       6 *
+
+.....
+
+            Software Interrupt 1    IVG14       31
+            Software Interrupt 2    --
+                 (lowest priority)  IVG15       32 *
+ */
+
+#define SYS_IRQS        41
+#define NR_PERI_INTS    32
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define IRQ_EMU             0	/*Emulation */
+#define IRQ_RST             1	/*reset */
+#define IRQ_NMI             2	/*Non Maskable */
+#define IRQ_EVX             3	/*Exception */
+#define IRQ_UNUSED          4	/*- unused interrupt*/
+#define IRQ_HWERR           5	/*Hardware Error */
+#define IRQ_CORETMR         6	/*Core timer */
+
+#define IRQ_PLL_WAKEUP      7	/*PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR       8	/*DMA Error (general) */
+#define IRQ_GENERIC_ERROR   9	/*GENERIC Error Interrupt */
+#define IRQ_RTC             10	/*RTC Interrupt */
+#define IRQ_PPI             11	/*DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX       12	/*DMA3 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX       13	/*DMA4 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX       14	/*DMA5 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX       15	/*DMA6 Interrupt (SPORT1 TX) */
+#define IRQ_TWI             16	/*TWI Interrupt */
+#define IRQ_SPI             17	/*DMA7 Interrupt (SPI) */
+#define IRQ_UART0_RX        18	/*DMA8 Interrupt (UART0 RX) */
+#define IRQ_UART0_TX        19	/*DMA9 Interrupt (UART0 TX) */
+#define IRQ_UART1_RX        20	/*DMA10 Interrupt (UART1 RX) */
+#define IRQ_UART1_TX        21	/*DMA11 Interrupt (UART1 TX) */
+#define IRQ_CAN_RX          22	/*CAN Receive Interrupt */
+#define IRQ_CAN_TX          23	/*CAN Transmit Interrupt */
+#define IRQ_MAC_RX          24	/*DMA1 (Ethernet RX) Interrupt */
+#define IRQ_MAC_TX          25	/*DMA2 (Ethernet TX) Interrupt */
+#define IRQ_TMR0            26	/*Timer 0 */
+#define IRQ_TMR1            27	/*Timer 1 */
+#define IRQ_TMR2            28	/*Timer 2 */
+#define IRQ_TMR3            29	/*Timer 3 */
+#define IRQ_TMR4            30	/*Timer 4 */
+#define IRQ_TMR5            31	/*Timer 5 */
+#define IRQ_TMR6            32	/*Timer 6 */
+#define IRQ_TMR7            33	/*Timer 7 */
+#define IRQ_PROG_INTA       34	/* PF Ports F&G (PF15:0) Interrupt A */
+#define IRQ_PORTG_INTB      35	/* PF Port G (PF15:0) Interrupt B */
+#define IRQ_MEM_DMA0        36	/*(Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1        37	/*(Memory DMA Stream 1) */
+#define IRQ_PROG_INTB	    38	/* PF Ports F (PF15:0) Interrupt B */
+#define IRQ_WATCH           38	/*Watch Dog Timer */
+#define IRQ_SW_INT1         40	/*Software Int 1 */
+#define IRQ_SW_INT2         41	/*Software Int 2 (reserved for SYSCALL) */
+
+#define IRQ_PPI_ERROR       42	/*PPI Error Interrupt */
+#define IRQ_CAN_ERROR       43	/*CAN Error Interrupt */
+#define IRQ_MAC_ERROR       44	/*PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR    45	/*SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR    46	/*SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR       47	/*SPI Error Interrupt */
+#define IRQ_UART0_ERROR     48	/*UART Error Interrupt */
+#define IRQ_UART1_ERROR     49	/*UART Error Interrupt */
+
+#define IRQ_PF0         50
+#define IRQ_PF1         51
+#define IRQ_PF2         52
+#define IRQ_PF3         53
+#define IRQ_PF4         54
+#define IRQ_PF5         55
+#define IRQ_PF6         56
+#define IRQ_PF7         57
+#define IRQ_PF8         58
+#define IRQ_PF9         59
+#define IRQ_PF10        60
+#define IRQ_PF11        61
+#define IRQ_PF12        62
+#define IRQ_PF13        63
+#define IRQ_PF14        64
+#define IRQ_PF15        65
+
+#define IRQ_PG0         66
+#define IRQ_PG1         67
+#define IRQ_PG2         68
+#define IRQ_PG3         69
+#define IRQ_PG4         70
+#define IRQ_PG5         71
+#define IRQ_PG6         72
+#define IRQ_PG7         73
+#define IRQ_PG8         74
+#define IRQ_PG9         75
+#define IRQ_PG10        76
+#define IRQ_PG11        77
+#define IRQ_PG12        78
+#define IRQ_PG13        79
+#define IRQ_PG14        80
+#define IRQ_PG15        81
+
+#define IRQ_PH0         82
+#define IRQ_PH1         83
+#define IRQ_PH2         84
+#define IRQ_PH3         85
+#define IRQ_PH4         86
+#define IRQ_PH5         87
+#define IRQ_PH6         88
+#define IRQ_PH7         89
+#define IRQ_PH8         90
+#define IRQ_PH9         91
+#define IRQ_PH10        92
+#define IRQ_PH11        93
+#define IRQ_PH12        94
+#define IRQ_PH13        95
+#define IRQ_PH14        96
+#define IRQ_PH15        97
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS     (IRQ_PH15+1)
+#else
+#define NR_IRQS     (IRQ_UART1_ERROR+1)
+#endif
+
+#define IVG7            7
+#define IVG8            8
+#define IVG9            9
+#define IVG10           10
+#define IVG11           11
+#define IVG12           12
+#define IVG13           13
+#define IVG14           14
+#define IVG15           15
+
+/* IAR0 BIT FIELDS*/
+#define IRQ_PLL_WAKEUP_POS  0
+#define IRQ_DMA_ERROR_POS   4
+#define IRQ_ERROR_POS       8
+#define IRQ_RTC_POS         12
+#define IRQ_PPI_POS         16
+#define IRQ_SPORT0_RX_POS   20
+#define IRQ_SPORT0_TX_POS   24
+#define IRQ_SPORT1_RX_POS   28
+
+/* IAR1 BIT FIELDS*/
+#define IRQ_SPORT1_TX_POS   0
+#define IRQ_TWI_POS         4
+#define IRQ_SPI_POS         8
+#define IRQ_UART0_RX_POS    12
+#define IRQ_UART0_TX_POS    16
+#define IRQ_UART1_RX_POS    20
+#define IRQ_UART1_TX_POS    24
+#define IRQ_CAN_RX_POS      28
+
+/* IAR2 BIT FIELDS*/
+#define IRQ_CAN_TX_POS      0
+#define IRQ_MAC_RX_POS      4
+#define IRQ_MAC_TX_POS      8
+#define IRQ_TMR0_POS        12
+#define IRQ_TMR1_POS        16
+#define IRQ_TMR2_POS        20
+#define IRQ_TMR3_POS        24
+#define IRQ_TMR4_POS        28
+
+/* IAR3 BIT FIELDS*/
+#define IRQ_TMR5_POS        0
+#define IRQ_TMR6_POS        4
+#define IRQ_TMR7_POS        8
+#define IRQ_PROG_INTA_POS   12
+#define IRQ_PORTG_INTB_POS   16
+#define IRQ_MEM_DMA0_POS    20
+#define IRQ_MEM_DMA1_POS    24
+#define IRQ_WATCH_POS       28
+
+#endif				/* _BF537_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf537/mem_init.h b/include/asm-blackfin/mach-bf537/mem_init.h
new file mode 100644
index 0000000..9ad979d
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/mem_init.h
@@ -0,0 +1,330 @@
+/*
+ * File:         include/asm-blackfin/mach-bf537/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_MT48LC16M8A2TG_75 || CONFIG_MEM_GENERIC_BOARD || CONFIG_MEM_MT48LC32M8A2_75)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_7
+#define SDRAM_tRAS_num  7
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_6
+#define SDRAM_tRAS_num  6
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_5
+#define SDRAM_tRAS_num  5
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  4
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_2
+#define SDRAM_tRAS_num  2
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_1
+#define SDRAM_tRAS_num  1
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC16M8A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   4096	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC32M8A2_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+  /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE      EBSZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE      EBSZ_64
+#endif
+#if (CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE      EBSZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE      EBSZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH     EBCAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH     EBCAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH     EBCAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH     EBCAW_8
+#endif
+
+#define mem_SDBCTL      (SDRAM_WIDTH | SDRAM_SIZE | EBE)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC       (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL        (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF       1
+#else
+#define CLKIN_HALF       0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS      1
+#else
+#define PLL_BYPASS       0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT  ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT  ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT   ((CONFIG_FLASH_SPEED_BHT  * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST   ((CONFIG_FLASH_SPEED_BST  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT   ((CONFIG_FLASH_SPEED_BTT  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0  \
+	(flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+	 flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf537/mem_map.h b/include/asm-blackfin/mach-bf537/mem_map.h
new file mode 100644
index 0000000..2a808c1
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/mem_map.h
@@ -0,0 +1,175 @@
+/*
+ * file:         include/asm-blackfin/mach-bf537/mem_map.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ *	Memory MAP Common header file for blackfin BF537/6/4 of processors.
+ * rev:
+ *
+ * modified:
+ *
+ * bugs:         enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * this program is distributed in the hope that it will be useful,
+ * but without any warranty; without even the implied warranty of
+ * merchantability or fitness for a particular purpose.  see 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,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MEM_MAP_537_H_
+#define _MEM_MAP_537_H_
+
+#define COREMMR_BASE           0xFFE00000	 /* Core MMRs */
+#define SYSMMR_BASE            0xFFC00000	 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE	0x20300000	 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK2_BASE	0x20200000	 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK1_BASE	0x20100000	 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE	0x00100000	/* 1M */
+#define ASYNC_BANK0_BASE	0x20000000	 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE	0x00100000	/* 1M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START		0xEF000000
+
+/* Level 1 Memory */
+
+/* Memory Map for ADSP-BF537 processors */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE	(16*1024)
+#else
+#define BLKFIN_ICACHESIZE	(0*1024)
+#endif
+
+
+#ifdef CONFIG_BF537
+#define L1_CODE_START       0xFFA00000
+#define L1_DATA_A_START     0xFF800000
+#define L1_DATA_B_START     0xFF900000
+
+#define L1_CODE_LENGTH      0xC000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x8000
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif /*CONFIG_BF537*/
+
+/* Memory Map for ADSP-BF536 processors */
+
+#ifdef CONFIG_BF536
+#define L1_CODE_START       0xFFA00000
+#define L1_DATA_A_START     0xFF804000
+#define L1_DATA_B_START     0xFF904000
+
+#define L1_CODE_LENGTH      0xC000
+
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x4000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x4000
+#define L1_DATA_B_LENGTH      0x4000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif
+
+/* Memory Map for ADSP-BF534 processors */
+
+#ifdef CONFIG_BF534
+#define L1_CODE_START       0xFFA00000
+#define L1_DATA_A_START     0xFF800000
+#define L1_DATA_B_START     0xFF900000
+
+#define L1_CODE_LENGTH      0xC000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x8000
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536) || defined(CONFIG_BF534)
+#define L1_SCRATCH_START	0xFFB00000
+#define L1_SCRATCH_LENGTH	0x1000
+#endif
+
+#endif				/* _MEM_MAP_537_H_ */
diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
new file mode 100644
index 0000000..f5b32d6
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/anomaly.h
@@ -0,0 +1,184 @@
+
+/*
+ * File:         include/asm-blackfin/mach-bf561/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ *  - Revision L, 10Aug2006; ADSP-BF561 Silicon Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 or 0.4 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2) || defined(CONFIG_BF_REV_0_4))
+#error Kernel will not work on BF561 Version 0.1, 0.2, or 0.4
+#endif
+
+/* Issues that are common to 0.5 and  0.3 silicon */
+#if  (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+                            slot1 and store of a P register in slot 2 is not
+                            supported */
+#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not
+                            updated at the same time. */
+#define ANOMALY_05000120 /* Testset instructions restricted to 32-bit aligned
+                            memory locations */
+#define ANOMALY_05000122 /* Rx.H cannot be used to access 16-bit System MMR
+                            registers */
+#define ANOMALY_05000127 /* Signbits instruction not functional under certain
+                            conditions */
+#define ANOMALY_05000149 /* IMDMA S1/D1 channel may stall */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+                            upper bits */
+#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+                            syncs */
+#define ANOMALY_05000182 /* IMDMA does not operate to full speed for 600MHz
+                            and higher devices */
+#define ANOMALY_05000187 /* IMDMA Corrupted Data after a Halt */
+#define ANOMALY_05000190 /* PPI not functional at core voltage < 1Volt */
+#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not
+                            functional */
+#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the
+                            shadow of a conditional branch */
+#define ANOMALY_05000257 /* Interrupt/Exception during short hardware loop
+                            may cause bad instruction fetches */
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+                            external SPORT TX and RX clocks */
+#define ANOMALY_05000267 /* IMDMA may corrupt data under certain conditions */
+#define ANOMALY_05000269 /* High I/O activity causes output voltage of internal
+                            voltage regulator (VDDint) to increase */
+#define ANOMALY_05000270 /* High I/O activity causes output voltage of internal
+                            voltage regulator (VDDint) to decrease */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+                            VDDint <=0.9V */
+#define ANOMALY_05000274 /* Data cache write back to external synchronous memory
+                            may be lost */
+#define ANOMALY_05000275 /* PPI Timing and sampling informaton updates */
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+			    registers are interrupted */
+
+#endif /*  (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) */
+
+#if  (defined(CONFIG_BF_REV_0_5))
+#define ANOMALY_05000254 /* Incorrect Timer Pulse Width in Single-Shot PWM_OUT
+                            mode with external clock */
+#define ANOMALY_05000266 /* IMDMA destination IRQ status must be read prior to
+                            using IMDMA */
+#endif
+
+#if  (defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000156 /* Timers in PWM-Out Mode with PPI GP Receive (Input)
+                            Mode with 0 Frame Syncs */
+#define ANOMALY_05000168 /* SDRAM auto-refresh and subsequent Power Ups */
+#define ANOMALY_05000169 /* DATA CPLB page miss can result in lost write-through
+                            cache data writes */
+#define ANOMALY_05000171 /* Boot-ROM code modifies SICA_IWRx wakeup registers */
+#define ANOMALY_05000174 /* Cache Fill Buffer Data lost */
+#define ANOMALY_05000175 /* Overlapping Sequencer and Memory Stalls */
+#define ANOMALY_05000176 /* Multiplication of (-1) by (-1) followed by an
+                            accumulator saturation */
+#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General
+                            Purpose TX or RX modes */
+#define ANOMALY_05000181 /* Disabling the PPI resets the PPI configuration
+                            registers */
+#define ANOMALY_05000184 /* Timer Pin limitations for PPI TX Modes with
+                            External Frame Syncs */
+#define ANOMALY_05000185 /* PPI TX Mode with 2 External Frame Syncs */
+#define ANOMALY_05000186 /* PPI packing with Data Length greater than 8 bits
+                            (not a meaningful mode) */
+#define ANOMALY_05000188 /* IMDMA Restrictions on Descriptor and Buffer
+                            Placement in Memory */
+#define ANOMALY_05000189 /* False Protection Exception */
+#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs
+                            when polarity setting is changed */
+#define ANOMALY_05000194 /* Restarting SPORT in specific modes may cause data
+                            corruption */
+#define ANOMALY_05000198 /* Failing MMR accesses when stalled by preceding
+                            memory read */
+#define ANOMALY_05000199 /* DMA current address shows wrong value during carry
+                            fix */
+#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during
+                            inactive channels in certain conditions */
+#define ANOMALY_05000202 /* Possible infinite stall with specific dual-DAG
+                            situation */
+#define ANOMALY_05000204 /* Incorrect data read with write-through cache and
+                            allocate cache lines on reads only mode */
+#define ANOMALY_05000205 /* Specific sequence that can cause DMA error or DMA
+                            stopping */
+#define ANOMALY_05000207 /* Recovery from "brown-out" condition */
+#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain
+                            instructions */
+#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */
+#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable
+                            state */
+#define ANOMALY_05000220 /* Data Corruption with Cached External Memory and
+                            Non-Cached On-Chip L2 Memory */
+#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */
+#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect
+                            data */
+#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate
+                            Differences in certain Conditions */
+#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */
+#define ANOMALY_05000232 /* SPORT data transmit lines are incorrectly driven in
+                            multichannel mode */
+#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to
+                            hardware reset */
+#define ANOMALY_05000244 /* If i-cache is on, CSYNC/SSYNC/IDLE around Change of
+                            Control causes failures */
+#define ANOMALY_05000248 /* TESTSET operation forces stall on the other core */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+                            (TDM) mode in certain conditions */
+#define ANOMALY_05000251 /* Exception not generated for MMR accesses in
+                            reserved region */
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bits 9 and 12
+                            of the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB
+                            exception */
+#define ANOMALY_05000264 /* CSYNC/SSYNC/IDLE causes infinite stall in second
+                            to last instruction in hardware loop */
+#define ANOMALY_05000276 /* Timing requirements change for External Frame
+                            Sync PPI Modes with non-zero PPI_DELAY */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+                            DMA system instability */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+                            not restored */
+#define ANOMALY_05000283 /* An MMR write is stalled indefinitely when killed
+                            in a particular stage */
+#define ANOMALY_05000287 /* A read will receive incorrect data under certain
+                            conditions */
+#define ANOMALY_05000288 /* SPORTs may receive bad data if FIFOs fill up */
+#endif
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf561/bf561.h b/include/asm-blackfin/mach-bf561/bf561.h
new file mode 100644
index 0000000..96a5d3a
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/bf561.h
@@ -0,0 +1,408 @@
+/*
+ * File:         include/asm-blackfin/mach-bf561/bf561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MACH_BF561_H__
+#define __MACH_BF561_H__
+
+#define SUPPORTED_REVID		0x3
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+#define L1_ISRAM		0xFFA00000
+#define L1_ISRAM_END		0xFFA04000
+#define DATA_BANKA_SRAM		0xFF800000
+#define DATA_BANKA_SRAM_END	0xFF804000
+#define DATA_BANKB_SRAM		0xFF900000
+#define DATA_BANKB_SRAM_END	0xFF904000
+#define L1_DSRAMA		0xFF800000
+#define L1_DSRAMA_END		0xFF804000
+#define L1_DSRAMB		0xFF900000
+#define L1_DSRAMB_END		0xFF904000
+#define L2_SRAM			0xFEB00000
+#define L2_SRAM_END		0xFEB20000
+#define AMB_FLASH		0x20000000
+#define AMB_FLASH_END		0x21000000
+#define AMB_FLASH_LENGTH	0x01000000
+#define L1_ISRAM_LENGTH		0x4000
+#define L1_DSRAMA_LENGTH	0x4000
+#define L1_DSRAMB_LENGTH	0x4000
+#define L2_SRAM_LENGTH		0x20000
+
+/*some misc defines*/
+#define IMASK_IVG15		0x8000
+#define IMASK_IVG14		0x4000
+#define IMASK_IVG13		0x2000
+#define IMASK_IVG12		0x1000
+
+#define IMASK_IVG11		0x0800
+#define IMASK_IVG10		0x0400
+#define IMASK_IVG9		0x0200
+#define IMASK_IVG8		0x0100
+
+#define IMASK_IVG7		0x0080
+#define IMASK_IVGTMR		0x0040
+#define IMASK_IVGHW		0x0020
+
+/***************************
+ * Blackfin Cache setup
+ */
+
+
+#define BLKFIN_ISUBBANKS	4
+#define BLKFIN_IWAYS		4
+#define BLKFIN_ILINES		32
+
+#define BLKFIN_DSUBBANKS	4
+#define BLKFIN_DWAYS		2
+#define BLKFIN_DLINES		64
+
+#define WAY0_L			0x1
+#define WAY1_L			0x2
+#define WAY01_L			0x3
+#define WAY2_L			0x4
+#define WAY02_L			0x5
+#define	WAY12_L			0x6
+#define	WAY012_L		0x7
+
+#define	WAY3_L			0x8
+#define	WAY03_L			0x9
+#define	WAY13_L			0xA
+#define	WAY013_L		0xB
+
+#define	WAY32_L			0xC
+#define	WAY320_L		0xD
+#define	WAY321_L		0xE
+#define	WAYALL_L		0xF
+
+#define DMC_ENABLE (2<<2)	/*yes, 2, not 1 */
+
+/* IAR0 BIT FIELDS */
+#define	PLL_WAKEUP_BIT		0xFFFFFFFF
+#define	DMA1_ERROR_BIT		0xFFFFFF0F
+#define	DMA2_ERROR_BIT		0xFFFFF0FF
+#define IMDMA_ERROR_BIT		0xFFFF0FFF
+#define	PPI1_ERROR_BIT		0xFFF0FFFF
+#define	PPI2_ERROR_BIT		0xFF0FFFFF
+#define	SPORT0_ERROR_BIT	0xF0FFFFFF
+#define	SPORT1_ERROR_BIT	0x0FFFFFFF
+/* IAR1 BIT FIELDS */
+#define	SPI_ERROR_BIT		0xFFFFFFFF
+#define	UART_ERROR_BIT		0xFFFFFF0F
+#define RESERVED_ERROR_BIT	0xFFFFF0FF
+#define	DMA1_0_BIT		0xFFFF0FFF
+#define	DMA1_1_BIT		0xFFF0FFFF
+#define	DMA1_2_BIT		0xFF0FFFFF
+#define	DMA1_3_BIT		0xF0FFFFFF
+#define	DMA1_4_BIT		0x0FFFFFFF
+/* IAR2 BIT FIELDS */
+#define	DMA1_5_BIT		0xFFFFFFFF
+#define	DMA1_6_BIT		0xFFFFFF0F
+#define	DMA1_7_BIT		0xFFFFF0FF
+#define	DMA1_8_BIT		0xFFFF0FFF
+#define	DMA1_9_BIT		0xFFF0FFFF
+#define	DMA1_10_BIT		0xFF0FFFFF
+#define	DMA1_11_BIT		0xF0FFFFFF
+#define	DMA2_0_BIT		0x0FFFFFFF
+/* IAR3 BIT FIELDS */
+#define	DMA2_1_BIT		0xFFFFFFFF
+#define	DMA2_2_BIT		0xFFFFFF0F
+#define	DMA2_3_BIT		0xFFFFF0FF
+#define	DMA2_4_BIT		0xFFFF0FFF
+#define	DMA2_5_BIT		0xFFF0FFFF
+#define	DMA2_6_BIT		0xFF0FFFFF
+#define	DMA2_7_BIT		0xF0FFFFFF
+#define	DMA2_8_BIT		0x0FFFFFFF
+/* IAR4 BIT FIELDS */
+#define	DMA2_9_BIT		0xFFFFFFFF
+#define	DMA2_10_BIT             0xFFFFFF0F
+#define	DMA2_11_BIT             0xFFFFF0FF
+#define TIMER0_BIT	        0xFFFF0FFF
+#define TIMER1_BIT              0xFFF0FFFF
+#define TIMER2_BIT              0xFF0FFFFF
+#define TIMER3_BIT              0xF0FFFFFF
+#define TIMER4_BIT              0x0FFFFFFF
+/* IAR5 BIT FIELDS */
+#define TIMER5_BIT		0xFFFFFFFF
+#define TIMER6_BIT              0xFFFFFF0F
+#define TIMER7_BIT              0xFFFFF0FF
+#define TIMER8_BIT              0xFFFF0FFF
+#define TIMER9_BIT              0xFFF0FFFF
+#define TIMER10_BIT             0xFF0FFFFF
+#define TIMER11_BIT             0xF0FFFFFF
+#define	PROG0_INTA_BIT	        0x0FFFFFFF
+/* IAR6 BIT FIELDS */
+#define	PROG0_INTB_BIT		0xFFFFFFFF
+#define	PROG1_INTA_BIT          0xFFFFFF0F
+#define	PROG1_INTB_BIT          0xFFFFF0FF
+#define	PROG2_INTA_BIT          0xFFFF0FFF
+#define	PROG2_INTB_BIT          0xFFF0FFFF
+#define DMA1_WRRD0_BIT          0xFF0FFFFF
+#define DMA1_WRRD1_BIT          0xF0FFFFFF
+#define DMA2_WRRD0_BIT          0x0FFFFFFF
+/* IAR7 BIT FIELDS */
+#define DMA2_WRRD1_BIT		0xFFFFFFFF
+#define IMDMA_WRRD0_BIT         0xFFFFFF0F
+#define IMDMA_WRRD1_BIT         0xFFFFF0FF
+#define	WATCH_BIT	        0xFFFF0FFF
+#define RESERVED_1_BIT	        0xFFF0FFFF
+#define RESERVED_2_BIT	        0xFF0FFFFF
+#define SUPPLE_0_BIT	        0xF0FFFFFF
+#define SUPPLE_1_BIT	        0x0FFFFFFF
+
+/* Miscellaneous Values */
+
+/****************************** EBIU Settings ********************************/
+#define AMBCTL0VAL	((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL	((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#if defined(CONFIG_C_AMBEN_ALL)
+#define V_AMBEN AMBEN_ALL
+#elif defined(CONFIG_C_AMBEN)
+#define V_AMBEN 0x0
+#elif defined(CONFIG_C_AMBEN_B0)
+#define V_AMBEN AMBEN_B0
+#elif defined(CONFIG_C_AMBEN_B0_B1)
+#define V_AMBEN AMBEN_B0_B1
+#elif defined(CONFIG_C_AMBEN_B0_B1_B2)
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+
+#ifdef CONFIG_C_B0PEN
+#define V_B0PEN 0x10
+#else
+#define V_B0PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B1PEN
+#define V_B1PEN 0x20
+#else
+#define V_B1PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B2PEN
+#define V_B2PEN 0x40
+#else
+#define V_B2PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B3PEN
+#define V_B3PEN 0x80
+#else
+#define V_B3PEN 0x00
+#endif
+
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL	(V_AMBEN | V_AMCKEN | V_CDPRIO | V_B0PEN | V_B1PEN | V_B2PEN | V_B3PEN | 0x0002)
+
+#define MAX_VC	600000000
+#define MIN_VC	50000000
+
+/******************************* PLL Settings ********************************/
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ	(CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ	((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ	(CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ	(CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ	CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ	CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV   CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV   CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif				/* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF561
+#define CPU "BF561"
+#define CPUID 0x027bb000
+#endif
+#ifndef CPU
+#define CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM memory size must be a multiple of 4MB!"
+#endif
+#define SDRAM_IGENERIC    (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL     (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY        (               CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL   (               CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND		0x200
+#ifdef CONFIG_BLKFIN_WB		/*Write Back Policy */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_DIRTY \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else				/*Write Through */
+#define SDRAM_DGENERIC   (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_DIRTY \
+			| CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#endif
+
+
+#define L1_DMEMORY       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+#define SDRAM_DNON_CHBL  (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_EBIU       (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_OOPS  	 (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+
+#define L2_MEMORY	(CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+
+#define SIZE_1K 0x00000400	/* 1K */
+#define SIZE_4K 0x00001000	/* 4K */
+#define SIZE_1M 0x00100000	/* 1M */
+#define SIZE_4M 0x00400000	/* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for L2 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 64 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1 + 64) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for L2 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1 + 1) * 2)
+
+#if 0				/* comment by mhfan */
+/* Event Vector Table Address */
+#define EVT_EMULATION_ADDR      0xffe02000
+#define EVT_RESET_ADDR          0xffe02004
+#define EVT_NMI_ADDR            0xffe02008
+#define EVT_EXCEPTION_ADDR      0xffe0200c
+#define EVT_GLOBAL_INT_ENB_ADDR 0xffe02010
+#define EVT_HARDWARE_ERROR_ADDR 0xffe02014
+#define EVT_TIMER_ADDR          0xffe02018
+#define EVT_IVG7_ADDR           0xffe0201c
+#define EVT_IVG8_ADDR           0xffe02020
+#define EVT_IVG9_ADDR           0xffe02024
+#define EVT_IVG10_ADDR          0xffe02028
+#define EVT_IVG11_ADDR          0xffe0202c
+#define EVT_IVG12_ADDR          0xffe02030
+#define EVT_IVG13_ADDR          0xffe02034
+#define EVT_IVG14_ADDR          0xffe02038
+#define EVT_IVG15_ADDR          0xffe0203c
+#define EVT_OVERRIDE_ADDR       0xffe02100
+#endif				/* comment by mhfan */
+
+#endif				/* __MACH_BF561_H__  */
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
new file mode 100644
index 0000000..23bf76a
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -0,0 +1,108 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS                1
+
+#define OFFSET_THR              0x00	/* Transmit Holding register            */
+#define OFFSET_RBR              0x00	/* Receive Buffer register              */
+#define OFFSET_DLL              0x00	/* Divisor Latch (Low-Byte)             */
+#define OFFSET_IER              0x04	/* Interrupt Enable Register            */
+#define OFFSET_DLH              0x04	/* Divisor Latch (High-Byte)            */
+#define OFFSET_IIR              0x08	/* Interrupt Identification Register    */
+#define OFFSET_LCR              0x0C	/* Line Control Register                */
+#define OFFSET_MCR              0x10	/* Modem Control Register               */
+#define OFFSET_LSR              0x14	/* Line Status Register                 */
+#define OFFSET_MSR              0x18	/* Modem Status Register                */
+#define OFFSET_SCR              0x1C	/* SCR Scratch Register                 */
+#define OFFSET_GCTL             0x24	/* Global Control Register              */
+
+#define UART_GET_CHAR(uart)     bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart)      bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart)	bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart)      bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart)      bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart)     bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v)    bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v)   bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+# define CONFIG_SERIAL_BFIN_CTSRTS
+# ifndef CONFIG_UART0_CTS_PIN
+#  define CONFIG_UART0_CTS_PIN -1
+# endif
+# ifndef CONFIG_UART0_RTS_PIN
+#  define CONFIG_UART0_RTS_PIN -1
+# endif
+#endif
+
+struct bfin_serial_port {
+        struct uart_port        port;
+        unsigned int            old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	int			tx_done;
+	int			tx_count;
+	struct circ_buf		rx_dma_buf;
+	struct timer_list       rx_dma_timer;
+	int			rx_dma_nrows;
+	unsigned int		tx_dma_channel;
+	unsigned int		rx_dma_channel;
+	struct work_struct	tx_dma_workqueue;
+#else
+	struct work_struct 	cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int			cts_pin;
+	int			rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+	unsigned long	uart_base_addr;
+	int		uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	unsigned int	uart_tx_dma_channel;
+	unsigned int	uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	int		uart_cts_pin;
+	int		uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+	0xFFC00400,
+	IRQ_UART_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+	CH_UART_TX,
+	CH_UART_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+	CONFIG_UART0_CTS_PIN,
+	CONFIG_UART0_RTS_PIN,
+#endif
+};
+
+
+int nr_ports = NR_PORTS;
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+	if (uart->cts_pin >= 0) {
+		gpio_request(uart->cts_pin, NULL);
+		gpio_direction_input(uart->cts_pin);
+	}
+	if (uart->rts_pin >= 0) {
+		gpio_request(uart->rts_pin, NULL);
+		gpio_direction_input(uart->rts_pin);
+	}
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf561/blackfin.h b/include/asm-blackfin/mach-bf561/blackfin.h
new file mode 100644
index 0000000..2537c84
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/blackfin.h
@@ -0,0 +1,52 @@
+/*
+ * File:         include/asm-blackfin/mach-bf561/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF561_FAMILY
+
+#include "bf561.h"
+#include "mem_map.h"
+#include "defBF561.h"
+#include "anomaly.h"
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF561.h"
+#endif
+
+#define bfin_read_FIO_FLAG_D() bfin_read_FIO0_FLAG_D()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_FIO0_FLAG_D(val)
+#define bfin_read_FIO_DIR() bfin_read_FIO0_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_FIO0_DIR(val)
+#define bfin_read_FIO_INEN() bfin_read_FIO0_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_FIO0_INEN(val)
+
+#endif				/* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h
new file mode 100644
index 0000000..5dc0ed8
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/cdefBF561.h
@@ -0,0 +1,1543 @@
+/*
+ * File:         include/asm-blackfin/mach-bf561/cdefBF561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:  C POINTERS TO SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF561_H
+#define _CDEF_BF561_H
+
+/*
+#if !defined(__ADSPBF561__)
+#warning cdefBF561.h should only be included for BF561 chip.
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include "defBF561.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+#define bfin_read_PLL_CTL()                  bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val)              bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_DIV()                  bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val)              bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL()                   bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	bfin_write16(VR_CTL, val);
+	__builtin_bfin_ssync();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SICA_IWR0);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+	local_irq_save(flags);
+	asm("IDLE;");
+	local_irq_restore(flags);
+	bfin_write32(SICA_IWR0, iwr);
+}
+#define bfin_read_PLL_STAT()                 bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val)             bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT()              bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val)          bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID()                   bfin_read32(CHIPID)
+
+/* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
+#define bfin_read_SICA_SWRST()               bfin_read16(SICA_SWRST)
+#define bfin_write_SICA_SWRST(val)           bfin_write16(SICA_SWRST,val)
+#define bfin_read_SICA_SYSCR()               bfin_read16(SICA_SYSCR)
+#define bfin_write_SICA_SYSCR(val)           bfin_write16(SICA_SYSCR,val)
+#define bfin_read_SICA_RVECT()               bfin_read16(SICA_RVECT)
+#define bfin_write_SICA_RVECT(val)           bfin_write16(SICA_RVECT,val)
+#define bfin_read_SICA_IMASK()               bfin_read32(SICA_IMASK)
+#define bfin_write_SICA_IMASK(val)           bfin_write32(SICA_IMASK,val)
+#define bfin_read_SICA_IMASK0()              bfin_read32(SICA_IMASK0)
+#define bfin_write_SICA_IMASK0(val)          bfin_write32(SICA_IMASK0,val)
+#define bfin_read_SICA_IMASK1()              bfin_read32(SICA_IMASK1)
+#define bfin_write_SICA_IMASK1(val)          bfin_write32(SICA_IMASK1,val)
+#define bfin_read_SICA_IAR0()                bfin_read32(SICA_IAR0)
+#define bfin_write_SICA_IAR0(val)            bfin_write32(SICA_IAR0,val)
+#define bfin_read_SICA_IAR1()                bfin_read32(SICA_IAR1)
+#define bfin_write_SICA_IAR1(val)            bfin_write32(SICA_IAR1,val)
+#define bfin_read_SICA_IAR2()                bfin_read32(SICA_IAR2)
+#define bfin_write_SICA_IAR2(val)            bfin_write32(SICA_IAR2,val)
+#define bfin_read_SICA_IAR3()                bfin_read32(SICA_IAR3)
+#define bfin_write_SICA_IAR3(val)            bfin_write32(SICA_IAR3,val)
+#define bfin_read_SICA_IAR4()                bfin_read32(SICA_IAR4)
+#define bfin_write_SICA_IAR4(val)            bfin_write32(SICA_IAR4,val)
+#define bfin_read_SICA_IAR5()                bfin_read32(SICA_IAR5)
+#define bfin_write_SICA_IAR5(val)            bfin_write32(SICA_IAR5,val)
+#define bfin_read_SICA_IAR6()                bfin_read32(SICA_IAR6)
+#define bfin_write_SICA_IAR6(val)            bfin_write32(SICA_IAR6,val)
+#define bfin_read_SICA_IAR7()                bfin_read32(SICA_IAR7)
+#define bfin_write_SICA_IAR7(val)            bfin_write32(SICA_IAR7,val)
+#define bfin_read_SICA_ISR0()                bfin_read32(SICA_ISR0)
+#define bfin_write_SICA_ISR0(val)            bfin_write32(SICA_ISR0,val)
+#define bfin_read_SICA_ISR1()                bfin_read32(SICA_ISR1)
+#define bfin_write_SICA_ISR1(val)            bfin_write32(SICA_ISR1,val)
+#define bfin_read_SICA_IWR0()                bfin_read32(SICA_IWR0)
+#define bfin_write_SICA_IWR0(val)            bfin_write32(SICA_IWR0,val)
+#define bfin_read_SICA_IWR1()                bfin_read32(SICA_IWR1)
+#define bfin_write_SICA_IWR1(val)            bfin_write32(SICA_IWR1,val)
+
+/* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
+#define bfin_read_SICB_SWRST()               bfin_read16(SICB_SWRST)
+#define bfin_write_SICB_SWRST(val)           bfin_write16(SICB_SWRST,val)
+#define bfin_read_SICB_SYSCR()               bfin_read16(SICB_SYSCR)
+#define bfin_write_SICB_SYSCR(val)           bfin_write16(SICB_SYSCR,val)
+#define bfin_read_SICB_RVECT()               bfin_read16(SICB_RVECT)
+#define bfin_write_SICB_RVECT(val)           bfin_write16(SICB_RVECT,val)
+#define bfin_read_SICB_IMASK0()              bfin_read32(SICB_IMASK0)
+#define bfin_write_SICB_IMASK0(val)          bfin_write32(SICB_IMASK0,val)
+#define bfin_read_SICB_IMASK1()              bfin_read32(SICB_IMASK1)
+#define bfin_write_SICB_IMASK1(val)          bfin_write32(SICB_IMASK1,val)
+#define bfin_read_SICB_IAR0()                bfin_read32(SICB_IAR0)
+#define bfin_write_SICB_IAR0(val)            bfin_write32(SICB_IAR0,val)
+#define bfin_read_SICB_IAR1()                bfin_read32(SICB_IAR1)
+#define bfin_write_SICB_IAR1(val)            bfin_write32(SICB_IAR1,val)
+#define bfin_read_SICB_IAR2()                bfin_read32(SICB_IAR2)
+#define bfin_write_SICB_IAR2(val)            bfin_write32(SICB_IAR2,val)
+#define bfin_read_SICB_IAR3()                bfin_read32(SICB_IAR3)
+#define bfin_write_SICB_IAR3(val)            bfin_write32(SICB_IAR3,val)
+#define bfin_read_SICB_IAR4()                bfin_read32(SICB_IAR4)
+#define bfin_write_SICB_IAR4(val)            bfin_write32(SICB_IAR4,val)
+#define bfin_read_SICB_IAR5()                bfin_read32(SICB_IAR5)
+#define bfin_write_SICB_IAR5(val)            bfin_write32(SICB_IAR5,val)
+#define bfin_read_SICB_IAR6()                bfin_read32(SICB_IAR6)
+#define bfin_write_SICB_IAR6(val)            bfin_write32(SICB_IAR6,val)
+#define bfin_read_SICB_IAR7()                bfin_read32(SICB_IAR7)
+#define bfin_write_SICB_IAR7(val)            bfin_write32(SICB_IAR7,val)
+#define bfin_read_SICB_ISR0()                bfin_read32(SICB_ISR0)
+#define bfin_write_SICB_ISR0(val)            bfin_write32(SICB_ISR0,val)
+#define bfin_read_SICB_ISR1()                bfin_read32(SICB_ISR1)
+#define bfin_write_SICB_ISR1(val)            bfin_write32(SICB_ISR1,val)
+#define bfin_read_SICB_IWR0()                bfin_read32(SICB_IWR0)
+#define bfin_write_SICB_IWR0(val)            bfin_write32(SICB_IWR0,val)
+#define bfin_read_SICB_IWR1()                bfin_read32(SICB_IWR1)
+#define bfin_write_SICB_IWR1(val)            bfin_write32(SICB_IWR1,val)
+/* Watchdog Timer registers for Core A (0xFFC0 0200-0xFFC0 02FF) */
+#define bfin_read_WDOGA_CTL()                bfin_read16(WDOGA_CTL)
+#define bfin_write_WDOGA_CTL(val)            bfin_write16(WDOGA_CTL,val)
+#define bfin_read_WDOGA_CNT()                bfin_read32(WDOGA_CNT)
+#define bfin_write_WDOGA_CNT(val)            bfin_write32(WDOGA_CNT,val)
+#define bfin_read_WDOGA_STAT()               bfin_read32(WDOGA_STAT)
+#define bfin_write_WDOGA_STAT(val)           bfin_write32(WDOGA_STAT,val)
+
+/* Watchdog Timer registers for Core B (0xFFC0 1200-0xFFC0 12FF) */
+#define bfin_read_WDOGB_CTL()                bfin_read16(WDOGB_CTL)
+#define bfin_write_WDOGB_CTL(val)            bfin_write16(WDOGB_CTL,val)
+#define bfin_read_WDOGB_CNT()                bfin_read32(WDOGB_CNT)
+#define bfin_write_WDOGB_CNT(val)            bfin_write32(WDOGB_CNT,val)
+#define bfin_read_WDOGB_STAT()               bfin_read32(WDOGB_STAT)
+#define bfin_write_WDOGB_STAT(val)           bfin_write32(WDOGB_STAT,val)
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define bfin_read_UART_THR()                 bfin_read16(UART_THR)
+#define bfin_write_UART_THR(val)             bfin_write16(UART_THR,val)
+#define bfin_read_UART_RBR()                 bfin_read16(UART_RBR)
+#define bfin_write_UART_RBR(val)             bfin_write16(UART_RBR,val)
+#define bfin_read_UART_DLL()                 bfin_read16(UART_DLL)
+#define bfin_write_UART_DLL(val)             bfin_write16(UART_DLL,val)
+#define bfin_read_UART_IER()                 bfin_read16(UART_IER)
+#define bfin_write_UART_IER(val)             bfin_write16(UART_IER,val)
+#define bfin_read_UART_DLH()                 bfin_read16(UART_DLH)
+#define bfin_write_UART_DLH(val)             bfin_write16(UART_DLH,val)
+#define bfin_read_UART_IIR()                 bfin_read16(UART_IIR)
+#define bfin_write_UART_IIR(val)             bfin_write16(UART_IIR,val)
+#define bfin_read_UART_LCR()                 bfin_read16(UART_LCR)
+#define bfin_write_UART_LCR(val)             bfin_write16(UART_LCR,val)
+#define bfin_read_UART_MCR()                 bfin_read16(UART_MCR)
+#define bfin_write_UART_MCR(val)             bfin_write16(UART_MCR,val)
+#define bfin_read_UART_LSR()                 bfin_read16(UART_LSR)
+#define bfin_write_UART_LSR(val)             bfin_write16(UART_LSR,val)
+#define bfin_read_UART_MSR()                 bfin_read16(UART_MSR)
+#define bfin_write_UART_MSR(val)             bfin_write16(UART_MSR,val)
+#define bfin_read_UART_SCR()                 bfin_read16(UART_SCR)
+#define bfin_write_UART_SCR(val)             bfin_write16(UART_SCR,val)
+#define bfin_read_UART_GCTL()                bfin_read16(UART_GCTL)
+#define bfin_write_UART_GCTL(val)            bfin_write16(UART_GCTL,val)
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define bfin_read_SPI_CTL()                  bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val)              bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG()                  bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val)              bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT()                 bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val)             bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR()                 bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val)             bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR()                 bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val)             bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD()                 bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val)             bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW()               bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val)           bfin_write16(SPI_SHADOW,val)
+
+/* Timer 0-7 registers (0xFFC0 0600-0xFFC0 06FF) */
+#define bfin_read_TIMER0_CONFIG()            bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val)        bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER()           bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val)       bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD()            bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val)        bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH()             bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val)         bfin_write32(TIMER0_WIDTH,val)
+#define bfin_read_TIMER1_CONFIG()            bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val)        bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER()           bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val)       bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD()            bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val)        bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH()             bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val)         bfin_write32(TIMER1_WIDTH,val)
+#define bfin_read_TIMER2_CONFIG()            bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val)        bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER()           bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val)       bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD()            bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val)        bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH()             bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val)         bfin_write32(TIMER2_WIDTH,val)
+#define bfin_read_TIMER3_CONFIG()            bfin_read16(TIMER3_CONFIG)
+#define bfin_write_TIMER3_CONFIG(val)        bfin_write16(TIMER3_CONFIG,val)
+#define bfin_read_TIMER3_COUNTER()           bfin_read32(TIMER3_COUNTER)
+#define bfin_write_TIMER3_COUNTER(val)       bfin_write32(TIMER3_COUNTER,val)
+#define bfin_read_TIMER3_PERIOD()            bfin_read32(TIMER3_PERIOD)
+#define bfin_write_TIMER3_PERIOD(val)        bfin_write32(TIMER3_PERIOD,val)
+#define bfin_read_TIMER3_WIDTH()             bfin_read32(TIMER3_WIDTH)
+#define bfin_write_TIMER3_WIDTH(val)         bfin_write32(TIMER3_WIDTH,val)
+#define bfin_read_TIMER4_CONFIG()            bfin_read16(TIMER4_CONFIG)
+#define bfin_write_TIMER4_CONFIG(val)        bfin_write16(TIMER4_CONFIG,val)
+#define bfin_read_TIMER4_COUNTER()           bfin_read32(TIMER4_COUNTER)
+#define bfin_write_TIMER4_COUNTER(val)       bfin_write32(TIMER4_COUNTER,val)
+#define bfin_read_TIMER4_PERIOD()            bfin_read32(TIMER4_PERIOD)
+#define bfin_write_TIMER4_PERIOD(val)        bfin_write32(TIMER4_PERIOD,val)
+#define bfin_read_TIMER4_WIDTH()             bfin_read32(TIMER4_WIDTH)
+#define bfin_write_TIMER4_WIDTH(val)         bfin_write32(TIMER4_WIDTH,val)
+#define bfin_read_TIMER5_CONFIG()            bfin_read16(TIMER5_CONFIG)
+#define bfin_write_TIMER5_CONFIG(val)        bfin_write16(TIMER5_CONFIG,val)
+#define bfin_read_TIMER5_COUNTER()           bfin_read32(TIMER5_COUNTER)
+#define bfin_write_TIMER5_COUNTER(val)       bfin_write32(TIMER5_COUNTER,val)
+#define bfin_read_TIMER5_PERIOD()            bfin_read32(TIMER5_PERIOD)
+#define bfin_write_TIMER5_PERIOD(val)        bfin_write32(TIMER5_PERIOD,val)
+#define bfin_read_TIMER5_WIDTH()             bfin_read32(TIMER5_WIDTH)
+#define bfin_write_TIMER5_WIDTH(val)         bfin_write32(TIMER5_WIDTH,val)
+#define bfin_read_TIMER6_CONFIG()            bfin_read16(TIMER6_CONFIG)
+#define bfin_write_TIMER6_CONFIG(val)        bfin_write16(TIMER6_CONFIG,val)
+#define bfin_read_TIMER6_COUNTER()           bfin_read32(TIMER6_COUNTER)
+#define bfin_write_TIMER6_COUNTER(val)       bfin_write32(TIMER6_COUNTER,val)
+#define bfin_read_TIMER6_PERIOD()            bfin_read32(TIMER6_PERIOD)
+#define bfin_write_TIMER6_PERIOD(val)        bfin_write32(TIMER6_PERIOD,val)
+#define bfin_read_TIMER6_WIDTH()             bfin_read32(TIMER6_WIDTH)
+#define bfin_write_TIMER6_WIDTH(val)         bfin_write32(TIMER6_WIDTH,val)
+#define bfin_read_TIMER7_CONFIG()            bfin_read16(TIMER7_CONFIG)
+#define bfin_write_TIMER7_CONFIG(val)        bfin_write16(TIMER7_CONFIG,val)
+#define bfin_read_TIMER7_COUNTER()           bfin_read32(TIMER7_COUNTER)
+#define bfin_write_TIMER7_COUNTER(val)       bfin_write32(TIMER7_COUNTER,val)
+#define bfin_read_TIMER7_PERIOD()            bfin_read32(TIMER7_PERIOD)
+#define bfin_write_TIMER7_PERIOD(val)        bfin_write32(TIMER7_PERIOD,val)
+#define bfin_read_TIMER7_WIDTH()             bfin_read32(TIMER7_WIDTH)
+#define bfin_write_TIMER7_WIDTH(val)         bfin_write32(TIMER7_WIDTH,val)
+
+/* Timer registers 8-11 (0xFFC0 1600-0xFFC0 16FF) */
+#define bfin_read_TMRS8_ENABLE()             bfin_read16(TMRS8_ENABLE)
+#define bfin_write_TMRS8_ENABLE(val)         bfin_write16(TMRS8_ENABLE,val)
+#define bfin_read_TMRS8_DISABLE()            bfin_read16(TMRS8_DISABLE)
+#define bfin_write_TMRS8_DISABLE(val)        bfin_write16(TMRS8_DISABLE,val)
+#define bfin_read_TMRS8_STATUS()             bfin_read32(TMRS8_STATUS)
+#define bfin_write_TMRS8_STATUS(val)         bfin_write32(TMRS8_STATUS,val)
+#define bfin_read_TIMER8_CONFIG()            bfin_read16(TIMER8_CONFIG)
+#define bfin_write_TIMER8_CONFIG(val)        bfin_write16(TIMER8_CONFIG,val)
+#define bfin_read_TIMER8_COUNTER()           bfin_read32(TIMER8_COUNTER)
+#define bfin_write_TIMER8_COUNTER(val)       bfin_write32(TIMER8_COUNTER,val)
+#define bfin_read_TIMER8_PERIOD()            bfin_read32(TIMER8_PERIOD)
+#define bfin_write_TIMER8_PERIOD(val)        bfin_write32(TIMER8_PERIOD,val)
+#define bfin_read_TIMER8_WIDTH()             bfin_read32(TIMER8_WIDTH)
+#define bfin_write_TIMER8_WIDTH(val)         bfin_write32(TIMER8_WIDTH,val)
+#define bfin_read_TIMER9_CONFIG()            bfin_read16(TIMER9_CONFIG)
+#define bfin_write_TIMER9_CONFIG(val)        bfin_write16(TIMER9_CONFIG,val)
+#define bfin_read_TIMER9_COUNTER()           bfin_read32(TIMER9_COUNTER)
+#define bfin_write_TIMER9_COUNTER(val)       bfin_write32(TIMER9_COUNTER,val)
+#define bfin_read_TIMER9_PERIOD()            bfin_read32(TIMER9_PERIOD)
+#define bfin_write_TIMER9_PERIOD(val)        bfin_write32(TIMER9_PERIOD,val)
+#define bfin_read_TIMER9_WIDTH()             bfin_read32(TIMER9_WIDTH)
+#define bfin_write_TIMER9_WIDTH(val)         bfin_write32(TIMER9_WIDTH,val)
+#define bfin_read_TIMER10_CONFIG()           bfin_read16(TIMER10_CONFIG)
+#define bfin_write_TIMER10_CONFIG(val)       bfin_write16(TIMER10_CONFIG,val)
+#define bfin_read_TIMER10_COUNTER()          bfin_read32(TIMER10_COUNTER)
+#define bfin_write_TIMER10_COUNTER(val)      bfin_write32(TIMER10_COUNTER,val)
+#define bfin_read_TIMER10_PERIOD()           bfin_read32(TIMER10_PERIOD)
+#define bfin_write_TIMER10_PERIOD(val)       bfin_write32(TIMER10_PERIOD,val)
+#define bfin_read_TIMER10_WIDTH()            bfin_read32(TIMER10_WIDTH)
+#define bfin_write_TIMER10_WIDTH(val)        bfin_write32(TIMER10_WIDTH,val)
+#define bfin_read_TIMER11_CONFIG()           bfin_read16(TIMER11_CONFIG)
+#define bfin_write_TIMER11_CONFIG(val)       bfin_write16(TIMER11_CONFIG,val)
+#define bfin_read_TIMER11_COUNTER()          bfin_read32(TIMER11_COUNTER)
+#define bfin_write_TIMER11_COUNTER(val)      bfin_write32(TIMER11_COUNTER,val)
+#define bfin_read_TIMER11_PERIOD()           bfin_read32(TIMER11_PERIOD)
+#define bfin_write_TIMER11_PERIOD(val)       bfin_write32(TIMER11_PERIOD,val)
+#define bfin_read_TIMER11_WIDTH()            bfin_read32(TIMER11_WIDTH)
+#define bfin_write_TIMER11_WIDTH(val)        bfin_write32(TIMER11_WIDTH,val)
+#define bfin_read_TMRS4_ENABLE()             bfin_read16(TMRS4_ENABLE)
+#define bfin_write_TMRS4_ENABLE(val)         bfin_write16(TMRS4_ENABLE,val)
+#define bfin_read_TMRS4_DISABLE()            bfin_read16(TMRS4_DISABLE)
+#define bfin_write_TMRS4_DISABLE(val)        bfin_write16(TMRS4_DISABLE,val)
+#define bfin_read_TMRS4_STATUS()             bfin_read32(TMRS4_STATUS)
+#define bfin_write_TMRS4_STATUS(val)         bfin_write32(TMRS4_STATUS,val)
+
+/* Programmable Flag 0 registers (0xFFC0 0700-0xFFC0 07FF) */
+#define bfin_read_FIO0_FLAG_D()              bfin_read16(FIO0_FLAG_D)
+#define bfin_write_FIO0_FLAG_D(val)          bfin_write16(FIO0_FLAG_D,val)
+#define bfin_read_FIO0_FLAG_C()              bfin_read16(FIO0_FLAG_C)
+#define bfin_write_FIO0_FLAG_C(val)          bfin_write16(FIO0_FLAG_C,val)
+#define bfin_read_FIO0_FLAG_S()              bfin_read16(FIO0_FLAG_S)
+#define bfin_write_FIO0_FLAG_S(val)          bfin_write16(FIO0_FLAG_S,val)
+#define bfin_read_FIO0_FLAG_T()              bfin_read16(FIO0_FLAG_T)
+#define bfin_write_FIO0_FLAG_T(val)          bfin_write16(FIO0_FLAG_T,val)
+#define bfin_read_FIO0_MASKA_D()             bfin_read16(FIO0_MASKA_D)
+#define bfin_write_FIO0_MASKA_D(val)         bfin_write16(FIO0_MASKA_D,val)
+#define bfin_read_FIO0_MASKA_C()             bfin_read16(FIO0_MASKA_C)
+#define bfin_write_FIO0_MASKA_C(val)         bfin_write16(FIO0_MASKA_C,val)
+#define bfin_read_FIO0_MASKA_S()             bfin_read16(FIO0_MASKA_S)
+#define bfin_write_FIO0_MASKA_S(val)         bfin_write16(FIO0_MASKA_S,val)
+#define bfin_read_FIO0_MASKA_T()             bfin_read16(FIO0_MASKA_T)
+#define bfin_write_FIO0_MASKA_T(val)         bfin_write16(FIO0_MASKA_T,val)
+#define bfin_read_FIO0_MASKB_D()             bfin_read16(FIO0_MASKB_D)
+#define bfin_write_FIO0_MASKB_D(val)         bfin_write16(FIO0_MASKB_D,val)
+#define bfin_read_FIO0_MASKB_C()             bfin_read16(FIO0_MASKB_C)
+#define bfin_write_FIO0_MASKB_C(val)         bfin_write16(FIO0_MASKB_C,val)
+#define bfin_read_FIO0_MASKB_S()             bfin_read16(FIO0_MASKB_S)
+#define bfin_write_FIO0_MASKB_S(val)         bfin_write16(FIO0_MASKB_S,val)
+#define bfin_read_FIO0_MASKB_T()             bfin_read16(FIO0_MASKB_T)
+#define bfin_write_FIO0_MASKB_T(val)         bfin_write16(FIO0_MASKB_T,val)
+#define bfin_read_FIO0_DIR()                 bfin_read16(FIO0_DIR)
+#define bfin_write_FIO0_DIR(val)             bfin_write16(FIO0_DIR,val)
+#define bfin_read_FIO0_POLAR()               bfin_read16(FIO0_POLAR)
+#define bfin_write_FIO0_POLAR(val)           bfin_write16(FIO0_POLAR,val)
+#define bfin_read_FIO0_EDGE()                bfin_read16(FIO0_EDGE)
+#define bfin_write_FIO0_EDGE(val)            bfin_write16(FIO0_EDGE,val)
+#define bfin_read_FIO0_BOTH()                bfin_read16(FIO0_BOTH)
+#define bfin_write_FIO0_BOTH(val)            bfin_write16(FIO0_BOTH,val)
+#define bfin_read_FIO0_INEN()                bfin_read16(FIO0_INEN)
+#define bfin_write_FIO0_INEN(val)            bfin_write16(FIO0_INEN,val)
+/* Programmable Flag 1 registers (0xFFC0 1500-0xFFC0 15FF) */
+#define bfin_read_FIO1_FLAG_D()              bfin_read16(FIO1_FLAG_D)
+#define bfin_write_FIO1_FLAG_D(val)          bfin_write16(FIO1_FLAG_D,val)
+#define bfin_read_FIO1_FLAG_C()              bfin_read16(FIO1_FLAG_C)
+#define bfin_write_FIO1_FLAG_C(val)          bfin_write16(FIO1_FLAG_C,val)
+#define bfin_read_FIO1_FLAG_S()              bfin_read16(FIO1_FLAG_S)
+#define bfin_write_FIO1_FLAG_S(val)          bfin_write16(FIO1_FLAG_S,val)
+#define bfin_read_FIO1_FLAG_T()              bfin_read16(FIO1_FLAG_T)
+#define bfin_write_FIO1_FLAG_T(val)          bfin_write16(FIO1_FLAG_T,val)
+#define bfin_read_FIO1_MASKA_D()             bfin_read16(FIO1_MASKA_D)
+#define bfin_write_FIO1_MASKA_D(val)         bfin_write16(FIO1_MASKA_D,val)
+#define bfin_read_FIO1_MASKA_C()             bfin_read16(FIO1_MASKA_C)
+#define bfin_write_FIO1_MASKA_C(val)         bfin_write16(FIO1_MASKA_C,val)
+#define bfin_read_FIO1_MASKA_S()             bfin_read16(FIO1_MASKA_S)
+#define bfin_write_FIO1_MASKA_S(val)         bfin_write16(FIO1_MASKA_S,val)
+#define bfin_read_FIO1_MASKA_T()             bfin_read16(FIO1_MASKA_T)
+#define bfin_write_FIO1_MASKA_T(val)         bfin_write16(FIO1_MASKA_T,val)
+#define bfin_read_FIO1_MASKB_D()             bfin_read16(FIO1_MASKB_D)
+#define bfin_write_FIO1_MASKB_D(val)         bfin_write16(FIO1_MASKB_D,val)
+#define bfin_read_FIO1_MASKB_C()             bfin_read16(FIO1_MASKB_C)
+#define bfin_write_FIO1_MASKB_C(val)         bfin_write16(FIO1_MASKB_C,val)
+#define bfin_read_FIO1_MASKB_S()             bfin_read16(FIO1_MASKB_S)
+#define bfin_write_FIO1_MASKB_S(val)         bfin_write16(FIO1_MASKB_S,val)
+#define bfin_read_FIO1_MASKB_T()             bfin_read16(FIO1_MASKB_T)
+#define bfin_write_FIO1_MASKB_T(val)         bfin_write16(FIO1_MASKB_T,val)
+#define bfin_read_FIO1_DIR()                 bfin_read16(FIO1_DIR)
+#define bfin_write_FIO1_DIR(val)             bfin_write16(FIO1_DIR,val)
+#define bfin_read_FIO1_POLAR()               bfin_read16(FIO1_POLAR)
+#define bfin_write_FIO1_POLAR(val)           bfin_write16(FIO1_POLAR,val)
+#define bfin_read_FIO1_EDGE()                bfin_read16(FIO1_EDGE)
+#define bfin_write_FIO1_EDGE(val)            bfin_write16(FIO1_EDGE,val)
+#define bfin_read_FIO1_BOTH()                bfin_read16(FIO1_BOTH)
+#define bfin_write_FIO1_BOTH(val)            bfin_write16(FIO1_BOTH,val)
+#define bfin_read_FIO1_INEN()                bfin_read16(FIO1_INEN)
+#define bfin_write_FIO1_INEN(val)            bfin_write16(FIO1_INEN,val)
+/* Programmable Flag registers (0xFFC0 1700-0xFFC0 17FF) */
+#define bfin_read_FIO2_FLAG_D()              bfin_read16(FIO2_FLAG_D)
+#define bfin_write_FIO2_FLAG_D(val)          bfin_write16(FIO2_FLAG_D,val)
+#define bfin_read_FIO2_FLAG_C()              bfin_read16(FIO2_FLAG_C)
+#define bfin_write_FIO2_FLAG_C(val)          bfin_write16(FIO2_FLAG_C,val)
+#define bfin_read_FIO2_FLAG_S()              bfin_read16(FIO2_FLAG_S)
+#define bfin_write_FIO2_FLAG_S(val)          bfin_write16(FIO2_FLAG_S,val)
+#define bfin_read_FIO2_FLAG_T()              bfin_read16(FIO2_FLAG_T)
+#define bfin_write_FIO2_FLAG_T(val)          bfin_write16(FIO2_FLAG_T,val)
+#define bfin_read_FIO2_MASKA_D()             bfin_read16(FIO2_MASKA_D)
+#define bfin_write_FIO2_MASKA_D(val)         bfin_write16(FIO2_MASKA_D,val)
+#define bfin_read_FIO2_MASKA_C()             bfin_read16(FIO2_MASKA_C)
+#define bfin_write_FIO2_MASKA_C(val)         bfin_write16(FIO2_MASKA_C,val)
+#define bfin_read_FIO2_MASKA_S()             bfin_read16(FIO2_MASKA_S)
+#define bfin_write_FIO2_MASKA_S(val)         bfin_write16(FIO2_MASKA_S,val)
+#define bfin_read_FIO2_MASKA_T()             bfin_read16(FIO2_MASKA_T)
+#define bfin_write_FIO2_MASKA_T(val)         bfin_write16(FIO2_MASKA_T,val)
+#define bfin_read_FIO2_MASKB_D()             bfin_read16(FIO2_MASKB_D)
+#define bfin_write_FIO2_MASKB_D(val)         bfin_write16(FIO2_MASKB_D,val)
+#define bfin_read_FIO2_MASKB_C()             bfin_read16(FIO2_MASKB_C)
+#define bfin_write_FIO2_MASKB_C(val)         bfin_write16(FIO2_MASKB_C,val)
+#define bfin_read_FIO2_MASKB_S()             bfin_read16(FIO2_MASKB_S)
+#define bfin_write_FIO2_MASKB_S(val)         bfin_write16(FIO2_MASKB_S,val)
+#define bfin_read_FIO2_MASKB_T()             bfin_read16(FIO2_MASKB_T)
+#define bfin_write_FIO2_MASKB_T(val)         bfin_write16(FIO2_MASKB_T,val)
+#define bfin_read_FIO2_DIR()                 bfin_read16(FIO2_DIR)
+#define bfin_write_FIO2_DIR(val)             bfin_write16(FIO2_DIR,val)
+#define bfin_read_FIO2_POLAR()               bfin_read16(FIO2_POLAR)
+#define bfin_write_FIO2_POLAR(val)           bfin_write16(FIO2_POLAR,val)
+#define bfin_read_FIO2_EDGE()                bfin_read16(FIO2_EDGE)
+#define bfin_write_FIO2_EDGE(val)            bfin_write16(FIO2_EDGE,val)
+#define bfin_read_FIO2_BOTH()                bfin_read16(FIO2_BOTH)
+#define bfin_write_FIO2_BOTH(val)            bfin_write16(FIO2_BOTH,val)
+#define bfin_read_FIO2_INEN()                bfin_read16(FIO2_INEN)
+#define bfin_write_FIO2_INEN(val)            bfin_write16(FIO2_INEN,val)
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define bfin_read_SPORT0_TCR1()              bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val)          bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2()              bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val)          bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV()           bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val)       bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV()            bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val)        bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX()                bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val)            bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX()                bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val)            bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32()              bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val)          bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32()              bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val)          bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16()              bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val)          bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16()              bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val)          bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1()              bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val)          bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2()              bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val)          bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV()           bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val)       bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV()            bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val)        bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT()              bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val)          bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL()              bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val)          bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1()             bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val)         bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2()             bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val)         bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0()             bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val)         bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1()             bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val)         bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2()             bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val)         bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3()             bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val)         bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0()             bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val)         bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1()             bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val)         bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2()             bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val)         bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3()             bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val)         bfin_write32(SPORT0_MRCS3,val)
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define bfin_read_SPORT1_TCR1()              bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val)          bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2()              bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val)          bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV()           bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val)       bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV()            bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val)        bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX()                bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val)            bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX()                bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val)            bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32()              bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val)          bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32()              bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val)          bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16()              bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val)          bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16()              bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val)          bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1()              bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val)          bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2()              bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val)          bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV()           bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val)       bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV()            bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val)        bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT()              bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val)          bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL()              bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val)          bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1()             bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val)         bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2()             bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val)         bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0()             bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val)         bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1()             bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val)         bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2()             bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val)         bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3()             bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val)         bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0()             bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val)         bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1()             bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val)         bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2()             bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val)         bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3()             bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val)         bfin_write32(SPORT1_MRCS3,val)
+/* Asynchronous Memory Controller - External Bus Interface Unit */
+#define bfin_read_EBIU_AMGCTL()              bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val)          bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0()             bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val)         bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1()             bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val)         bfin_write32(EBIU_AMBCTL1,val)
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define bfin_read_EBIU_SDGCTL()              bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val)          bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDBCTL()              bfin_read32(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val)          bfin_write32(EBIU_SDBCTL,val)
+#define bfin_read_EBIU_SDRRC()               bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val)           bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT()              bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val)          bfin_write16(EBIU_SDSTAT,val)
+/* Parallel Peripheral Interface (PPI) 0 registers (0xFFC0 1000-0xFFC0 10FF) */
+#define bfin_read_PPI0_CONTROL()             bfin_read16(PPI0_CONTROL)
+#define bfin_write_PPI0_CONTROL(val)         bfin_write16(PPI0_CONTROL,val)
+#define bfin_read_PPI0_STATUS()              bfin_read16(PPI0_STATUS)
+#define bfin_write_PPI0_STATUS(val)          bfin_write16(PPI0_STATUS,val)
+#define bfin_read_PPI0_COUNT()               bfin_read16(PPI0_COUNT)
+#define bfin_write_PPI0_COUNT(val)           bfin_write16(PPI0_COUNT,val)
+#define bfin_read_PPI0_DELAY()               bfin_read16(PPI0_DELAY)
+#define bfin_write_PPI0_DELAY(val)           bfin_write16(PPI0_DELAY,val)
+#define bfin_read_PPI0_FRAME()               bfin_read16(PPI0_FRAME)
+#define bfin_write_PPI0_FRAME(val)           bfin_write16(PPI0_FRAME,val)
+/* Parallel Peripheral Interface (PPI) 1 registers (0xFFC0 1300-0xFFC0 13FF) */
+#define bfin_read_PPI1_CONTROL()             bfin_read16(PPI1_CONTROL)
+#define bfin_write_PPI1_CONTROL(val)         bfin_write16(PPI1_CONTROL,val)
+#define bfin_read_PPI1_STATUS()              bfin_read16(PPI1_STATUS)
+#define bfin_write_PPI1_STATUS(val)          bfin_write16(PPI1_STATUS,val)
+#define bfin_read_PPI1_COUNT()               bfin_read16(PPI1_COUNT)
+#define bfin_write_PPI1_COUNT(val)           bfin_write16(PPI1_COUNT,val)
+#define bfin_read_PPI1_DELAY()               bfin_read16(PPI1_DELAY)
+#define bfin_write_PPI1_DELAY(val)           bfin_write16(PPI1_DELAY,val)
+#define bfin_read_PPI1_FRAME()               bfin_read16(PPI1_FRAME)
+#define bfin_write_PPI1_FRAME(val)           bfin_write16(PPI1_FRAME,val)
+/*DMA traffic control registers */
+#define bfin_read_DMA1_TC_PER()              bfin_read16(DMA1_TC_PER)
+#define bfin_write_DMA1_TC_PER(val)          bfin_write16(DMA1_TC_PER,val)
+#define bfin_read_DMA1_TC_CNT()              bfin_read16(DMA1_TC_CNT)
+#define bfin_write_DMA1_TC_CNT(val)          bfin_write16(DMA1_TC_CNT,val)
+#define bfin_read_DMA2_TC_PER()              bfin_read16(DMA2_TC_PER)
+#define bfin_write_DMA2_TC_PER(val)          bfin_write16(DMA2_TC_PER,val)
+#define bfin_read_DMA2_TC_CNT()              bfin_read16(DMA2_TC_CNT)
+#define bfin_write_DMA2_TC_CNT(val)          bfin_write16(DMA2_TC_CNT,val)
+/* DMA1 Controller registers (0xFFC0 1C00-0xFFC0 1FFF) */
+#define bfin_read_DMA1_0_CONFIG()            bfin_read16(DMA1_0_CONFIG)
+#define bfin_write_DMA1_0_CONFIG(val)        bfin_write16(DMA1_0_CONFIG,val)
+#define bfin_read_DMA1_0_NEXT_DESC_PTR()     bfin_read32(DMA1_0_NEXT_DESC_PTR)
+#define bfin_write_DMA1_0_NEXT_DESC_PTR(val) bfin_write32(DMA1_0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_0_START_ADDR()        bfin_read32(DMA1_0_START_ADDR)
+#define bfin_write_DMA1_0_START_ADDR(val)    bfin_write32(DMA1_0_START_ADDR,val)
+#define bfin_read_DMA1_0_X_COUNT()           bfin_read16(DMA1_0_X_COUNT)
+#define bfin_write_DMA1_0_X_COUNT(val)       bfin_write16(DMA1_0_X_COUNT,val)
+#define bfin_read_DMA1_0_Y_COUNT()           bfin_read16(DMA1_0_Y_COUNT)
+#define bfin_write_DMA1_0_Y_COUNT(val)       bfin_write16(DMA1_0_Y_COUNT,val)
+#define bfin_read_DMA1_0_X_MODIFY()          bfin_read16(DMA1_0_X_MODIFY)
+#define bfin_write_DMA1_0_X_MODIFY(val)      bfin_write16(DMA1_0_X_MODIFY,val)
+#define bfin_read_DMA1_0_Y_MODIFY()          bfin_read16(DMA1_0_Y_MODIFY)
+#define bfin_write_DMA1_0_Y_MODIFY(val)      bfin_write16(DMA1_0_Y_MODIFY,val)
+#define bfin_read_DMA1_0_CURR_DESC_PTR()     bfin_read32(DMA1_0_CURR_DESC_PTR)
+#define bfin_write_DMA1_0_CURR_DESC_PTR(val) bfin_write32(DMA1_0_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_0_CURR_ADDR()         bfin_read32(DMA1_0_CURR_ADDR)
+#define bfin_write_DMA1_0_CURR_ADDR(val)     bfin_write32(DMA1_0_CURR_ADDR,val)
+#define bfin_read_DMA1_0_CURR_X_COUNT()      bfin_read16(DMA1_0_CURR_X_COUNT)
+#define bfin_write_DMA1_0_CURR_X_COUNT(val)  bfin_write16(DMA1_0_CURR_X_COUNT,val)
+#define bfin_read_DMA1_0_CURR_Y_COUNT()      bfin_read16(DMA1_0_CURR_Y_COUNT)
+#define bfin_write_DMA1_0_CURR_Y_COUNT(val)  bfin_write16(DMA1_0_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_0_IRQ_STATUS()        bfin_read16(DMA1_0_IRQ_STATUS)
+#define bfin_write_DMA1_0_IRQ_STATUS(val)    bfin_write16(DMA1_0_IRQ_STATUS,val)
+#define bfin_read_DMA1_0_PERIPHERAL_MAP()    bfin_read16(DMA1_0_PERIPHERAL_MAP)
+#define bfin_write_DMA1_0_PERIPHERAL_MAP(val) bfin_write16(DMA1_0_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_1_CONFIG()            bfin_read16(DMA1_1_CONFIG)
+#define bfin_write_DMA1_1_CONFIG(val)        bfin_write16(DMA1_1_CONFIG,val)
+#define bfin_read_DMA1_1_NEXT_DESC_PTR()     bfin_read32(DMA1_1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_1_NEXT_DESC_PTR(val) bfin_write32(DMA1_1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_1_START_ADDR()        bfin_read32(DMA1_1_START_ADDR)
+#define bfin_write_DMA1_1_START_ADDR(val)    bfin_write32(DMA1_1_START_ADDR,val)
+#define bfin_read_DMA1_1_X_COUNT()           bfin_read16(DMA1_1_X_COUNT)
+#define bfin_write_DMA1_1_X_COUNT(val)       bfin_write16(DMA1_1_X_COUNT,val)
+#define bfin_read_DMA1_1_Y_COUNT()           bfin_read16(DMA1_1_Y_COUNT)
+#define bfin_write_DMA1_1_Y_COUNT(val)       bfin_write16(DMA1_1_Y_COUNT,val)
+#define bfin_read_DMA1_1_X_MODIFY()          bfin_read16(DMA1_1_X_MODIFY)
+#define bfin_write_DMA1_1_X_MODIFY(val)      bfin_write16(DMA1_1_X_MODIFY,val)
+#define bfin_read_DMA1_1_Y_MODIFY()          bfin_read16(DMA1_1_Y_MODIFY)
+#define bfin_write_DMA1_1_Y_MODIFY(val)      bfin_write16(DMA1_1_Y_MODIFY,val)
+#define bfin_read_DMA1_1_CURR_DESC_PTR()     bfin_read32(DMA1_1_CURR_DESC_PTR)
+#define bfin_write_DMA1_1_CURR_DESC_PTR(val) bfin_write32(DMA1_1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_1_CURR_ADDR()         bfin_read32(DMA1_1_CURR_ADDR)
+#define bfin_write_DMA1_1_CURR_ADDR(val)     bfin_write32(DMA1_1_CURR_ADDR,val)
+#define bfin_read_DMA1_1_CURR_X_COUNT()      bfin_read16(DMA1_1_CURR_X_COUNT)
+#define bfin_write_DMA1_1_CURR_X_COUNT(val)  bfin_write16(DMA1_1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_1_CURR_Y_COUNT()      bfin_read16(DMA1_1_CURR_Y_COUNT)
+#define bfin_write_DMA1_1_CURR_Y_COUNT(val)  bfin_write16(DMA1_1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_1_IRQ_STATUS()        bfin_read16(DMA1_1_IRQ_STATUS)
+#define bfin_write_DMA1_1_IRQ_STATUS(val)    bfin_write16(DMA1_1_IRQ_STATUS,val)
+#define bfin_read_DMA1_1_PERIPHERAL_MAP()    bfin_read16(DMA1_1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_1_PERIPHERAL_MAP(val) bfin_write16(DMA1_1_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_2_CONFIG()            bfin_read16(DMA1_2_CONFIG)
+#define bfin_write_DMA1_2_CONFIG(val)        bfin_write16(DMA1_2_CONFIG,val)
+#define bfin_read_DMA1_2_NEXT_DESC_PTR()     bfin_read32(DMA1_2_NEXT_DESC_PTR)
+#define bfin_write_DMA1_2_NEXT_DESC_PTR(val) bfin_write32(DMA1_2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_2_START_ADDR()        bfin_read32(DMA1_2_START_ADDR)
+#define bfin_write_DMA1_2_START_ADDR(val)    bfin_write32(DMA1_2_START_ADDR,val)
+#define bfin_read_DMA1_2_X_COUNT()           bfin_read16(DMA1_2_X_COUNT)
+#define bfin_write_DMA1_2_X_COUNT(val)       bfin_write16(DMA1_2_X_COUNT,val)
+#define bfin_read_DMA1_2_Y_COUNT()           bfin_read16(DMA1_2_Y_COUNT)
+#define bfin_write_DMA1_2_Y_COUNT(val)       bfin_write16(DMA1_2_Y_COUNT,val)
+#define bfin_read_DMA1_2_X_MODIFY()          bfin_read16(DMA1_2_X_MODIFY)
+#define bfin_write_DMA1_2_X_MODIFY(val)      bfin_write16(DMA1_2_X_MODIFY,val)
+#define bfin_read_DMA1_2_Y_MODIFY()          bfin_read16(DMA1_2_Y_MODIFY)
+#define bfin_write_DMA1_2_Y_MODIFY(val)      bfin_write16(DMA1_2_Y_MODIFY,val)
+#define bfin_read_DMA1_2_CURR_DESC_PTR()     bfin_read32(DMA1_2_CURR_DESC_PTR)
+#define bfin_write_DMA1_2_CURR_DESC_PTR(val) bfin_write32(DMA1_2_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_2_CURR_ADDR()         bfin_read32(DMA1_2_CURR_ADDR)
+#define bfin_write_DMA1_2_CURR_ADDR(val)     bfin_write32(DMA1_2_CURR_ADDR,val)
+#define bfin_read_DMA1_2_CURR_X_COUNT()      bfin_read16(DMA1_2_CURR_X_COUNT)
+#define bfin_write_DMA1_2_CURR_X_COUNT(val)  bfin_write16(DMA1_2_CURR_X_COUNT,val)
+#define bfin_read_DMA1_2_CURR_Y_COUNT()      bfin_read16(DMA1_2_CURR_Y_COUNT)
+#define bfin_write_DMA1_2_CURR_Y_COUNT(val)  bfin_write16(DMA1_2_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_2_IRQ_STATUS()        bfin_read16(DMA1_2_IRQ_STATUS)
+#define bfin_write_DMA1_2_IRQ_STATUS(val)    bfin_write16(DMA1_2_IRQ_STATUS,val)
+#define bfin_read_DMA1_2_PERIPHERAL_MAP()    bfin_read16(DMA1_2_PERIPHERAL_MAP)
+#define bfin_write_DMA1_2_PERIPHERAL_MAP(val) bfin_write16(DMA1_2_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_3_CONFIG()            bfin_read16(DMA1_3_CONFIG)
+#define bfin_write_DMA1_3_CONFIG(val)        bfin_write16(DMA1_3_CONFIG,val)
+#define bfin_read_DMA1_3_NEXT_DESC_PTR()     bfin_read32(DMA1_3_NEXT_DESC_PTR)
+#define bfin_write_DMA1_3_NEXT_DESC_PTR(val) bfin_write32(DMA1_3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_3_START_ADDR()        bfin_read32(DMA1_3_START_ADDR)
+#define bfin_write_DMA1_3_START_ADDR(val)    bfin_write32(DMA1_3_START_ADDR,val)
+#define bfin_read_DMA1_3_X_COUNT()           bfin_read16(DMA1_3_X_COUNT)
+#define bfin_write_DMA1_3_X_COUNT(val)       bfin_write16(DMA1_3_X_COUNT,val)
+#define bfin_read_DMA1_3_Y_COUNT()           bfin_read16(DMA1_3_Y_COUNT)
+#define bfin_write_DMA1_3_Y_COUNT(val)       bfin_write16(DMA1_3_Y_COUNT,val)
+#define bfin_read_DMA1_3_X_MODIFY()          bfin_read16(DMA1_3_X_MODIFY)
+#define bfin_write_DMA1_3_X_MODIFY(val)      bfin_write16(DMA1_3_X_MODIFY,val)
+#define bfin_read_DMA1_3_Y_MODIFY()          bfin_read16(DMA1_3_Y_MODIFY)
+#define bfin_write_DMA1_3_Y_MODIFY(val)      bfin_write16(DMA1_3_Y_MODIFY,val)
+#define bfin_read_DMA1_3_CURR_DESC_PTR()     bfin_read32(DMA1_3_CURR_DESC_PTR)
+#define bfin_write_DMA1_3_CURR_DESC_PTR(val) bfin_write32(DMA1_3_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_3_CURR_ADDR()         bfin_read32(DMA1_3_CURR_ADDR)
+#define bfin_write_DMA1_3_CURR_ADDR(val)     bfin_write32(DMA1_3_CURR_ADDR,val)
+#define bfin_read_DMA1_3_CURR_X_COUNT()      bfin_read16(DMA1_3_CURR_X_COUNT)
+#define bfin_write_DMA1_3_CURR_X_COUNT(val)  bfin_write16(DMA1_3_CURR_X_COUNT,val)
+#define bfin_read_DMA1_3_CURR_Y_COUNT()      bfin_read16(DMA1_3_CURR_Y_COUNT)
+#define bfin_write_DMA1_3_CURR_Y_COUNT(val)  bfin_write16(DMA1_3_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_3_IRQ_STATUS()        bfin_read16(DMA1_3_IRQ_STATUS)
+#define bfin_write_DMA1_3_IRQ_STATUS(val)    bfin_write16(DMA1_3_IRQ_STATUS,val)
+#define bfin_read_DMA1_3_PERIPHERAL_MAP()    bfin_read16(DMA1_3_PERIPHERAL_MAP)
+#define bfin_write_DMA1_3_PERIPHERAL_MAP(val) bfin_write16(DMA1_3_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_4_CONFIG()            bfin_read16(DMA1_4_CONFIG)
+#define bfin_write_DMA1_4_CONFIG(val)        bfin_write16(DMA1_4_CONFIG,val)
+#define bfin_read_DMA1_4_NEXT_DESC_PTR()     bfin_read32(DMA1_4_NEXT_DESC_PTR)
+#define bfin_write_DMA1_4_NEXT_DESC_PTR(val) bfin_write32(DMA1_4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_4_START_ADDR()        bfin_read32(DMA1_4_START_ADDR)
+#define bfin_write_DMA1_4_START_ADDR(val)    bfin_write32(DMA1_4_START_ADDR,val)
+#define bfin_read_DMA1_4_X_COUNT()           bfin_read16(DMA1_4_X_COUNT)
+#define bfin_write_DMA1_4_X_COUNT(val)       bfin_write16(DMA1_4_X_COUNT,val)
+#define bfin_read_DMA1_4_Y_COUNT()           bfin_read16(DMA1_4_Y_COUNT)
+#define bfin_write_DMA1_4_Y_COUNT(val)       bfin_write16(DMA1_4_Y_COUNT,val)
+#define bfin_read_DMA1_4_X_MODIFY()          bfin_read16(DMA1_4_X_MODIFY)
+#define bfin_write_DMA1_4_X_MODIFY(val)      bfin_write16(DMA1_4_X_MODIFY,val)
+#define bfin_read_DMA1_4_Y_MODIFY()          bfin_read16(DMA1_4_Y_MODIFY)
+#define bfin_write_DMA1_4_Y_MODIFY(val)      bfin_write16(DMA1_4_Y_MODIFY,val)
+#define bfin_read_DMA1_4_CURR_DESC_PTR()     bfin_read32(DMA1_4_CURR_DESC_PTR)
+#define bfin_write_DMA1_4_CURR_DESC_PTR(val) bfin_write32(DMA1_4_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_4_CURR_ADDR()         bfin_read32(DMA1_4_CURR_ADDR)
+#define bfin_write_DMA1_4_CURR_ADDR(val)     bfin_write32(DMA1_4_CURR_ADDR,val)
+#define bfin_read_DMA1_4_CURR_X_COUNT()      bfin_read16(DMA1_4_CURR_X_COUNT)
+#define bfin_write_DMA1_4_CURR_X_COUNT(val)  bfin_write16(DMA1_4_CURR_X_COUNT,val)
+#define bfin_read_DMA1_4_CURR_Y_COUNT()      bfin_read16(DMA1_4_CURR_Y_COUNT)
+#define bfin_write_DMA1_4_CURR_Y_COUNT(val)  bfin_write16(DMA1_4_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_4_IRQ_STATUS()        bfin_read16(DMA1_4_IRQ_STATUS)
+#define bfin_write_DMA1_4_IRQ_STATUS(val)    bfin_write16(DMA1_4_IRQ_STATUS,val)
+#define bfin_read_DMA1_4_PERIPHERAL_MAP()    bfin_read16(DMA1_4_PERIPHERAL_MAP)
+#define bfin_write_DMA1_4_PERIPHERAL_MAP(val) bfin_write16(DMA1_4_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_5_CONFIG()            bfin_read16(DMA1_5_CONFIG)
+#define bfin_write_DMA1_5_CONFIG(val)        bfin_write16(DMA1_5_CONFIG,val)
+#define bfin_read_DMA1_5_NEXT_DESC_PTR()     bfin_read32(DMA1_5_NEXT_DESC_PTR)
+#define bfin_write_DMA1_5_NEXT_DESC_PTR(val) bfin_write32(DMA1_5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_5_START_ADDR()        bfin_read32(DMA1_5_START_ADDR)
+#define bfin_write_DMA1_5_START_ADDR(val)    bfin_write32(DMA1_5_START_ADDR,val)
+#define bfin_read_DMA1_5_X_COUNT()           bfin_read16(DMA1_5_X_COUNT)
+#define bfin_write_DMA1_5_X_COUNT(val)       bfin_write16(DMA1_5_X_COUNT,val)
+#define bfin_read_DMA1_5_Y_COUNT()           bfin_read16(DMA1_5_Y_COUNT)
+#define bfin_write_DMA1_5_Y_COUNT(val)       bfin_write16(DMA1_5_Y_COUNT,val)
+#define bfin_read_DMA1_5_X_MODIFY()          bfin_read16(DMA1_5_X_MODIFY)
+#define bfin_write_DMA1_5_X_MODIFY(val)      bfin_write16(DMA1_5_X_MODIFY,val)
+#define bfin_read_DMA1_5_Y_MODIFY()          bfin_read16(DMA1_5_Y_MODIFY)
+#define bfin_write_DMA1_5_Y_MODIFY(val)      bfin_write16(DMA1_5_Y_MODIFY,val)
+#define bfin_read_DMA1_5_CURR_DESC_PTR()     bfin_read32(DMA1_5_CURR_DESC_PTR)
+#define bfin_write_DMA1_5_CURR_DESC_PTR(val) bfin_write32(DMA1_5_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_5_CURR_ADDR()         bfin_read32(DMA1_5_CURR_ADDR)
+#define bfin_write_DMA1_5_CURR_ADDR(val)     bfin_write32(DMA1_5_CURR_ADDR,val)
+#define bfin_read_DMA1_5_CURR_X_COUNT()      bfin_read16(DMA1_5_CURR_X_COUNT)
+#define bfin_write_DMA1_5_CURR_X_COUNT(val)  bfin_write16(DMA1_5_CURR_X_COUNT,val)
+#define bfin_read_DMA1_5_CURR_Y_COUNT()      bfin_read16(DMA1_5_CURR_Y_COUNT)
+#define bfin_write_DMA1_5_CURR_Y_COUNT(val)  bfin_write16(DMA1_5_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_5_IRQ_STATUS()        bfin_read16(DMA1_5_IRQ_STATUS)
+#define bfin_write_DMA1_5_IRQ_STATUS(val)    bfin_write16(DMA1_5_IRQ_STATUS,val)
+#define bfin_read_DMA1_5_PERIPHERAL_MAP()    bfin_read16(DMA1_5_PERIPHERAL_MAP)
+#define bfin_write_DMA1_5_PERIPHERAL_MAP(val) bfin_write16(DMA1_5_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_6_CONFIG()            bfin_read16(DMA1_6_CONFIG)
+#define bfin_write_DMA1_6_CONFIG(val)        bfin_write16(DMA1_6_CONFIG,val)
+#define bfin_read_DMA1_6_NEXT_DESC_PTR()     bfin_read32(DMA1_6_NEXT_DESC_PTR)
+#define bfin_write_DMA1_6_NEXT_DESC_PTR(val) bfin_write32(DMA1_6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_6_START_ADDR()        bfin_read32(DMA1_6_START_ADDR)
+#define bfin_write_DMA1_6_START_ADDR(val)    bfin_write32(DMA1_6_START_ADDR,val)
+#define bfin_read_DMA1_6_X_COUNT()           bfin_read16(DMA1_6_X_COUNT)
+#define bfin_write_DMA1_6_X_COUNT(val)       bfin_write16(DMA1_6_X_COUNT,val)
+#define bfin_read_DMA1_6_Y_COUNT()           bfin_read16(DMA1_6_Y_COUNT)
+#define bfin_write_DMA1_6_Y_COUNT(val)       bfin_write16(DMA1_6_Y_COUNT,val)
+#define bfin_read_DMA1_6_X_MODIFY()          bfin_read16(DMA1_6_X_MODIFY)
+#define bfin_write_DMA1_6_X_MODIFY(val)      bfin_write16(DMA1_6_X_MODIFY,val)
+#define bfin_read_DMA1_6_Y_MODIFY()          bfin_read16(DMA1_6_Y_MODIFY)
+#define bfin_write_DMA1_6_Y_MODIFY(val)      bfin_write16(DMA1_6_Y_MODIFY,val)
+#define bfin_read_DMA1_6_CURR_DESC_PTR()     bfin_read32(DMA1_6_CURR_DESC_PTR)
+#define bfin_write_DMA1_6_CURR_DESC_PTR(val) bfin_write32(DMA1_6_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_6_CURR_ADDR()         bfin_read32(DMA1_6_CURR_ADDR)
+#define bfin_write_DMA1_6_CURR_ADDR(val)     bfin_write32(DMA1_6_CURR_ADDR,val)
+#define bfin_read_DMA1_6_CURR_X_COUNT()      bfin_read16(DMA1_6_CURR_X_COUNT)
+#define bfin_write_DMA1_6_CURR_X_COUNT(val)  bfin_write16(DMA1_6_CURR_X_COUNT,val)
+#define bfin_read_DMA1_6_CURR_Y_COUNT()      bfin_read16(DMA1_6_CURR_Y_COUNT)
+#define bfin_write_DMA1_6_CURR_Y_COUNT(val)  bfin_write16(DMA1_6_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_6_IRQ_STATUS()        bfin_read16(DMA1_6_IRQ_STATUS)
+#define bfin_write_DMA1_6_IRQ_STATUS(val)    bfin_write16(DMA1_6_IRQ_STATUS,val)
+#define bfin_read_DMA1_6_PERIPHERAL_MAP()    bfin_read16(DMA1_6_PERIPHERAL_MAP)
+#define bfin_write_DMA1_6_PERIPHERAL_MAP(val) bfin_write16(DMA1_6_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_7_CONFIG()            bfin_read16(DMA1_7_CONFIG)
+#define bfin_write_DMA1_7_CONFIG(val)        bfin_write16(DMA1_7_CONFIG,val)
+#define bfin_read_DMA1_7_NEXT_DESC_PTR()     bfin_read32(DMA1_7_NEXT_DESC_PTR)
+#define bfin_write_DMA1_7_NEXT_DESC_PTR(val) bfin_write32(DMA1_7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_7_START_ADDR()        bfin_read32(DMA1_7_START_ADDR)
+#define bfin_write_DMA1_7_START_ADDR(val)    bfin_write32(DMA1_7_START_ADDR,val)
+#define bfin_read_DMA1_7_X_COUNT()           bfin_read16(DMA1_7_X_COUNT)
+#define bfin_write_DMA1_7_X_COUNT(val)       bfin_write16(DMA1_7_X_COUNT,val)
+#define bfin_read_DMA1_7_Y_COUNT()           bfin_read16(DMA1_7_Y_COUNT)
+#define bfin_write_DMA1_7_Y_COUNT(val)       bfin_write16(DMA1_7_Y_COUNT,val)
+#define bfin_read_DMA1_7_X_MODIFY()          bfin_read16(DMA1_7_X_MODIFY)
+#define bfin_write_DMA1_7_X_MODIFY(val)      bfin_write16(DMA1_7_X_MODIFY,val)
+#define bfin_read_DMA1_7_Y_MODIFY()          bfin_read16(DMA1_7_Y_MODIFY)
+#define bfin_write_DMA1_7_Y_MODIFY(val)      bfin_write16(DMA1_7_Y_MODIFY,val)
+#define bfin_read_DMA1_7_CURR_DESC_PTR()     bfin_read32(DMA1_7_CURR_DESC_PTR)
+#define bfin_write_DMA1_7_CURR_DESC_PTR(val) bfin_write32(DMA1_7_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_7_CURR_ADDR()         bfin_read32(DMA1_7_CURR_ADDR)
+#define bfin_write_DMA1_7_CURR_ADDR(val)     bfin_write32(DMA1_7_CURR_ADDR,val)
+#define bfin_read_DMA1_7_CURR_X_COUNT()      bfin_read16(DMA1_7_CURR_X_COUNT)
+#define bfin_write_DMA1_7_CURR_X_COUNT(val)  bfin_write16(DMA1_7_CURR_X_COUNT,val)
+#define bfin_read_DMA1_7_CURR_Y_COUNT()      bfin_read16(DMA1_7_CURR_Y_COUNT)
+#define bfin_write_DMA1_7_CURR_Y_COUNT(val)  bfin_write16(DMA1_7_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_7_IRQ_STATUS()        bfin_read16(DMA1_7_IRQ_STATUS)
+#define bfin_write_DMA1_7_IRQ_STATUS(val)    bfin_write16(DMA1_7_IRQ_STATUS,val)
+#define bfin_read_DMA1_7_PERIPHERAL_MAP()    bfin_read16(DMA1_7_PERIPHERAL_MAP)
+#define bfin_write_DMA1_7_PERIPHERAL_MAP(val) bfin_write16(DMA1_7_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_8_CONFIG()            bfin_read16(DMA1_8_CONFIG)
+#define bfin_write_DMA1_8_CONFIG(val)        bfin_write16(DMA1_8_CONFIG,val)
+#define bfin_read_DMA1_8_NEXT_DESC_PTR()     bfin_read32(DMA1_8_NEXT_DESC_PTR)
+#define bfin_write_DMA1_8_NEXT_DESC_PTR(val) bfin_write32(DMA1_8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_8_START_ADDR()        bfin_read32(DMA1_8_START_ADDR)
+#define bfin_write_DMA1_8_START_ADDR(val)    bfin_write32(DMA1_8_START_ADDR,val)
+#define bfin_read_DMA1_8_X_COUNT()           bfin_read16(DMA1_8_X_COUNT)
+#define bfin_write_DMA1_8_X_COUNT(val)       bfin_write16(DMA1_8_X_COUNT,val)
+#define bfin_read_DMA1_8_Y_COUNT()           bfin_read16(DMA1_8_Y_COUNT)
+#define bfin_write_DMA1_8_Y_COUNT(val)       bfin_write16(DMA1_8_Y_COUNT,val)
+#define bfin_read_DMA1_8_X_MODIFY()          bfin_read16(DMA1_8_X_MODIFY)
+#define bfin_write_DMA1_8_X_MODIFY(val)      bfin_write16(DMA1_8_X_MODIFY,val)
+#define bfin_read_DMA1_8_Y_MODIFY()          bfin_read16(DMA1_8_Y_MODIFY)
+#define bfin_write_DMA1_8_Y_MODIFY(val)      bfin_write16(DMA1_8_Y_MODIFY,val)
+#define bfin_read_DMA1_8_CURR_DESC_PTR()     bfin_read32(DMA1_8_CURR_DESC_PTR)
+#define bfin_write_DMA1_8_CURR_DESC_PTR(val) bfin_write32(DMA1_8_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_8_CURR_ADDR()         bfin_read32(DMA1_8_CURR_ADDR)
+#define bfin_write_DMA1_8_CURR_ADDR(val)     bfin_write32(DMA1_8_CURR_ADDR,val)
+#define bfin_read_DMA1_8_CURR_X_COUNT()      bfin_read16(DMA1_8_CURR_X_COUNT)
+#define bfin_write_DMA1_8_CURR_X_COUNT(val)  bfin_write16(DMA1_8_CURR_X_COUNT,val)
+#define bfin_read_DMA1_8_CURR_Y_COUNT()      bfin_read16(DMA1_8_CURR_Y_COUNT)
+#define bfin_write_DMA1_8_CURR_Y_COUNT(val)  bfin_write16(DMA1_8_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_8_IRQ_STATUS()        bfin_read16(DMA1_8_IRQ_STATUS)
+#define bfin_write_DMA1_8_IRQ_STATUS(val)    bfin_write16(DMA1_8_IRQ_STATUS,val)
+#define bfin_read_DMA1_8_PERIPHERAL_MAP()    bfin_read16(DMA1_8_PERIPHERAL_MAP)
+#define bfin_write_DMA1_8_PERIPHERAL_MAP(val) bfin_write16(DMA1_8_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_9_CONFIG()            bfin_read16(DMA1_9_CONFIG)
+#define bfin_write_DMA1_9_CONFIG(val)        bfin_write16(DMA1_9_CONFIG,val)
+#define bfin_read_DMA1_9_NEXT_DESC_PTR()     bfin_read32(DMA1_9_NEXT_DESC_PTR)
+#define bfin_write_DMA1_9_NEXT_DESC_PTR(val) bfin_write32(DMA1_9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_9_START_ADDR()        bfin_read32(DMA1_9_START_ADDR)
+#define bfin_write_DMA1_9_START_ADDR(val)    bfin_write32(DMA1_9_START_ADDR,val)
+#define bfin_read_DMA1_9_X_COUNT()           bfin_read16(DMA1_9_X_COUNT)
+#define bfin_write_DMA1_9_X_COUNT(val)       bfin_write16(DMA1_9_X_COUNT,val)
+#define bfin_read_DMA1_9_Y_COUNT()           bfin_read16(DMA1_9_Y_COUNT)
+#define bfin_write_DMA1_9_Y_COUNT(val)       bfin_write16(DMA1_9_Y_COUNT,val)
+#define bfin_read_DMA1_9_X_MODIFY()          bfin_read16(DMA1_9_X_MODIFY)
+#define bfin_write_DMA1_9_X_MODIFY(val)      bfin_write16(DMA1_9_X_MODIFY,val)
+#define bfin_read_DMA1_9_Y_MODIFY()          bfin_read16(DMA1_9_Y_MODIFY)
+#define bfin_write_DMA1_9_Y_MODIFY(val)      bfin_write16(DMA1_9_Y_MODIFY,val)
+#define bfin_read_DMA1_9_CURR_DESC_PTR()     bfin_read32(DMA1_9_CURR_DESC_PTR)
+#define bfin_write_DMA1_9_CURR_DESC_PTR(val) bfin_write32(DMA1_9_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_9_CURR_ADDR()         bfin_read32(DMA1_9_CURR_ADDR)
+#define bfin_write_DMA1_9_CURR_ADDR(val)     bfin_write32(DMA1_9_CURR_ADDR,val)
+#define bfin_read_DMA1_9_CURR_X_COUNT()      bfin_read16(DMA1_9_CURR_X_COUNT)
+#define bfin_write_DMA1_9_CURR_X_COUNT(val)  bfin_write16(DMA1_9_CURR_X_COUNT,val)
+#define bfin_read_DMA1_9_CURR_Y_COUNT()      bfin_read16(DMA1_9_CURR_Y_COUNT)
+#define bfin_write_DMA1_9_CURR_Y_COUNT(val)  bfin_write16(DMA1_9_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_9_IRQ_STATUS()        bfin_read16(DMA1_9_IRQ_STATUS)
+#define bfin_write_DMA1_9_IRQ_STATUS(val)    bfin_write16(DMA1_9_IRQ_STATUS,val)
+#define bfin_read_DMA1_9_PERIPHERAL_MAP()    bfin_read16(DMA1_9_PERIPHERAL_MAP)
+#define bfin_write_DMA1_9_PERIPHERAL_MAP(val) bfin_write16(DMA1_9_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_10_CONFIG()           bfin_read16(DMA1_10_CONFIG)
+#define bfin_write_DMA1_10_CONFIG(val)       bfin_write16(DMA1_10_CONFIG,val)
+#define bfin_read_DMA1_10_NEXT_DESC_PTR()    bfin_read32(DMA1_10_NEXT_DESC_PTR)
+#define bfin_write_DMA1_10_NEXT_DESC_PTR(val) bfin_write32(DMA1_10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_10_START_ADDR()       bfin_read32(DMA1_10_START_ADDR)
+#define bfin_write_DMA1_10_START_ADDR(val)   bfin_write32(DMA1_10_START_ADDR,val)
+#define bfin_read_DMA1_10_X_COUNT()          bfin_read16(DMA1_10_X_COUNT)
+#define bfin_write_DMA1_10_X_COUNT(val)      bfin_write16(DMA1_10_X_COUNT,val)
+#define bfin_read_DMA1_10_Y_COUNT()          bfin_read16(DMA1_10_Y_COUNT)
+#define bfin_write_DMA1_10_Y_COUNT(val)      bfin_write16(DMA1_10_Y_COUNT,val)
+#define bfin_read_DMA1_10_X_MODIFY()         bfin_read16(DMA1_10_X_MODIFY)
+#define bfin_write_DMA1_10_X_MODIFY(val)     bfin_write16(DMA1_10_X_MODIFY,val)
+#define bfin_read_DMA1_10_Y_MODIFY()         bfin_read16(DMA1_10_Y_MODIFY)
+#define bfin_write_DMA1_10_Y_MODIFY(val)     bfin_write16(DMA1_10_Y_MODIFY,val)
+#define bfin_read_DMA1_10_CURR_DESC_PTR()    bfin_read32(DMA1_10_CURR_DESC_PTR)
+#define bfin_write_DMA1_10_CURR_DESC_PTR(val) bfin_write32(DMA1_10_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_10_CURR_ADDR()        bfin_read32(DMA1_10_CURR_ADDR)
+#define bfin_write_DMA1_10_CURR_ADDR(val)    bfin_write32(DMA1_10_CURR_ADDR,val)
+#define bfin_read_DMA1_10_CURR_X_COUNT()     bfin_read16(DMA1_10_CURR_X_COUNT)
+#define bfin_write_DMA1_10_CURR_X_COUNT(val) bfin_write16(DMA1_10_CURR_X_COUNT,val)
+#define bfin_read_DMA1_10_CURR_Y_COUNT()     bfin_read16(DMA1_10_CURR_Y_COUNT)
+#define bfin_write_DMA1_10_CURR_Y_COUNT(val) bfin_write16(DMA1_10_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_10_IRQ_STATUS()       bfin_read16(DMA1_10_IRQ_STATUS)
+#define bfin_write_DMA1_10_IRQ_STATUS(val)   bfin_write16(DMA1_10_IRQ_STATUS,val)
+#define bfin_read_DMA1_10_PERIPHERAL_MAP()   bfin_read16(DMA1_10_PERIPHERAL_MAP)
+#define bfin_write_DMA1_10_PERIPHERAL_MAP(val) bfin_write16(DMA1_10_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_11_CONFIG()           bfin_read16(DMA1_11_CONFIG)
+#define bfin_write_DMA1_11_CONFIG(val)       bfin_write16(DMA1_11_CONFIG,val)
+#define bfin_read_DMA1_11_NEXT_DESC_PTR()    bfin_read32(DMA1_11_NEXT_DESC_PTR)
+#define bfin_write_DMA1_11_NEXT_DESC_PTR(val) bfin_write32(DMA1_11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_11_START_ADDR()       bfin_read32(DMA1_11_START_ADDR)
+#define bfin_write_DMA1_11_START_ADDR(val)   bfin_write32(DMA1_11_START_ADDR,val)
+#define bfin_read_DMA1_11_X_COUNT()          bfin_read16(DMA1_11_X_COUNT)
+#define bfin_write_DMA1_11_X_COUNT(val)      bfin_write16(DMA1_11_X_COUNT,val)
+#define bfin_read_DMA1_11_Y_COUNT()          bfin_read16(DMA1_11_Y_COUNT)
+#define bfin_write_DMA1_11_Y_COUNT(val)      bfin_write16(DMA1_11_Y_COUNT,val)
+#define bfin_read_DMA1_11_X_MODIFY()         bfin_read16(DMA1_11_X_MODIFY)
+#define bfin_write_DMA1_11_X_MODIFY(val)     bfin_write16(DMA1_11_X_MODIFY,val)
+#define bfin_read_DMA1_11_Y_MODIFY()         bfin_read16(DMA1_11_Y_MODIFY)
+#define bfin_write_DMA1_11_Y_MODIFY(val)     bfin_write16(DMA1_11_Y_MODIFY,val)
+#define bfin_read_DMA1_11_CURR_DESC_PTR()    bfin_read32(DMA1_11_CURR_DESC_PTR)
+#define bfin_write_DMA1_11_CURR_DESC_PTR(val) bfin_write32(DMA1_11_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_11_CURR_ADDR()        bfin_read32(DMA1_11_CURR_ADDR)
+#define bfin_write_DMA1_11_CURR_ADDR(val)    bfin_write32(DMA1_11_CURR_ADDR,val)
+#define bfin_read_DMA1_11_CURR_X_COUNT()     bfin_read16(DMA1_11_CURR_X_COUNT)
+#define bfin_write_DMA1_11_CURR_X_COUNT(val) bfin_write16(DMA1_11_CURR_X_COUNT,val)
+#define bfin_read_DMA1_11_CURR_Y_COUNT()     bfin_read16(DMA1_11_CURR_Y_COUNT)
+#define bfin_write_DMA1_11_CURR_Y_COUNT(val) bfin_write16(DMA1_11_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_11_IRQ_STATUS()       bfin_read16(DMA1_11_IRQ_STATUS)
+#define bfin_write_DMA1_11_IRQ_STATUS(val)   bfin_write16(DMA1_11_IRQ_STATUS,val)
+#define bfin_read_DMA1_11_PERIPHERAL_MAP()   bfin_read16(DMA1_11_PERIPHERAL_MAP)
+#define bfin_write_DMA1_11_PERIPHERAL_MAP(val) bfin_write16(DMA1_11_PERIPHERAL_MAP,val)
+/* Memory DMA1 Controller registers (0xFFC0 1E80-0xFFC0 1FFF) */
+#define bfin_read_MDMA1_D0_CONFIG()          bfin_read16(MDMA1_D0_CONFIG)
+#define bfin_write_MDMA1_D0_CONFIG(val)      bfin_write16(MDMA1_D0_CONFIG,val)
+#define bfin_read_MDMA1_D0_NEXT_DESC_PTR()   bfin_read32(MDMA1_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA1_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_D0_START_ADDR()      bfin_read32(MDMA1_D0_START_ADDR)
+#define bfin_write_MDMA1_D0_START_ADDR(val)  bfin_write32(MDMA1_D0_START_ADDR,val)
+#define bfin_read_MDMA1_D0_X_COUNT()         bfin_read16(MDMA1_D0_X_COUNT)
+#define bfin_write_MDMA1_D0_X_COUNT(val)     bfin_write16(MDMA1_D0_X_COUNT,val)
+#define bfin_read_MDMA1_D0_Y_COUNT()         bfin_read16(MDMA1_D0_Y_COUNT)
+#define bfin_write_MDMA1_D0_Y_COUNT(val)     bfin_write16(MDMA1_D0_Y_COUNT,val)
+#define bfin_read_MDMA1_D0_X_MODIFY()        bfin_read16(MDMA1_D0_X_MODIFY)
+#define bfin_write_MDMA1_D0_X_MODIFY(val)    bfin_write16(MDMA1_D0_X_MODIFY,val)
+#define bfin_read_MDMA1_D0_Y_MODIFY()        bfin_read16(MDMA1_D0_Y_MODIFY)
+#define bfin_write_MDMA1_D0_Y_MODIFY(val)    bfin_write16(MDMA1_D0_Y_MODIFY,val)
+#define bfin_read_MDMA1_D0_CURR_DESC_PTR()   bfin_read32(MDMA1_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA1_D0_CURR_DESC_PTR(val) bfin_write32(MDMA1_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_D0_CURR_ADDR()       bfin_read32(MDMA1_D0_CURR_ADDR)
+#define bfin_write_MDMA1_D0_CURR_ADDR(val)   bfin_write32(MDMA1_D0_CURR_ADDR,val)
+#define bfin_read_MDMA1_D0_CURR_X_COUNT()    bfin_read16(MDMA1_D0_CURR_X_COUNT)
+#define bfin_write_MDMA1_D0_CURR_X_COUNT(val) bfin_write16(MDMA1_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_D0_CURR_Y_COUNT()    bfin_read16(MDMA1_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA1_D0_CURR_Y_COUNT(val) bfin_write16(MDMA1_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_D0_IRQ_STATUS()      bfin_read16(MDMA1_D0_IRQ_STATUS)
+#define bfin_write_MDMA1_D0_IRQ_STATUS(val)  bfin_write16(MDMA1_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA1_D0_PERIPHERAL_MAP()  bfin_read16(MDMA1_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA1_D0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_S0_CONFIG()          bfin_read16(MDMA1_S0_CONFIG)
+#define bfin_write_MDMA1_S0_CONFIG(val)      bfin_write16(MDMA1_S0_CONFIG,val)
+#define bfin_read_MDMA1_S0_NEXT_DESC_PTR()   bfin_read32(MDMA1_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA1_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_S0_START_ADDR()      bfin_read32(MDMA1_S0_START_ADDR)
+#define bfin_write_MDMA1_S0_START_ADDR(val)  bfin_write32(MDMA1_S0_START_ADDR,val)
+#define bfin_read_MDMA1_S0_X_COUNT()         bfin_read16(MDMA1_S0_X_COUNT)
+#define bfin_write_MDMA1_S0_X_COUNT(val)     bfin_write16(MDMA1_S0_X_COUNT,val)
+#define bfin_read_MDMA1_S0_Y_COUNT()         bfin_read16(MDMA1_S0_Y_COUNT)
+#define bfin_write_MDMA1_S0_Y_COUNT(val)     bfin_write16(MDMA1_S0_Y_COUNT,val)
+#define bfin_read_MDMA1_S0_X_MODIFY()        bfin_read16(MDMA1_S0_X_MODIFY)
+#define bfin_write_MDMA1_S0_X_MODIFY(val)    bfin_write16(MDMA1_S0_X_MODIFY,val)
+#define bfin_read_MDMA1_S0_Y_MODIFY()        bfin_read16(MDMA1_S0_Y_MODIFY)
+#define bfin_write_MDMA1_S0_Y_MODIFY(val)    bfin_write16(MDMA1_S0_Y_MODIFY,val)
+#define bfin_read_MDMA1_S0_CURR_DESC_PTR()   bfin_read32(MDMA1_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA1_S0_CURR_DESC_PTR(val) bfin_write32(MDMA1_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_S0_CURR_ADDR()       bfin_read32(MDMA1_S0_CURR_ADDR)
+#define bfin_write_MDMA1_S0_CURR_ADDR(val)   bfin_write32(MDMA1_S0_CURR_ADDR,val)
+#define bfin_read_MDMA1_S0_CURR_X_COUNT()    bfin_read16(MDMA1_S0_CURR_X_COUNT)
+#define bfin_write_MDMA1_S0_CURR_X_COUNT(val) bfin_write16(MDMA1_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_S0_CURR_Y_COUNT()    bfin_read16(MDMA1_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA1_S0_CURR_Y_COUNT(val) bfin_write16(MDMA1_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_S0_IRQ_STATUS()      bfin_read16(MDMA1_S0_IRQ_STATUS)
+#define bfin_write_MDMA1_S0_IRQ_STATUS(val)  bfin_write16(MDMA1_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA1_S0_PERIPHERAL_MAP()  bfin_read16(MDMA1_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA1_S0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_D1_CONFIG()          bfin_read16(MDMA1_D1_CONFIG)
+#define bfin_write_MDMA1_D1_CONFIG(val)      bfin_write16(MDMA1_D1_CONFIG,val)
+#define bfin_read_MDMA1_D1_NEXT_DESC_PTR()   bfin_read32(MDMA1_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA1_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_D1_START_ADDR()      bfin_read32(MDMA1_D1_START_ADDR)
+#define bfin_write_MDMA1_D1_START_ADDR(val)  bfin_write32(MDMA1_D1_START_ADDR,val)
+#define bfin_read_MDMA1_D1_X_COUNT()         bfin_read16(MDMA1_D1_X_COUNT)
+#define bfin_write_MDMA1_D1_X_COUNT(val)     bfin_write16(MDMA1_D1_X_COUNT,val)
+#define bfin_read_MDMA1_D1_Y_COUNT()         bfin_read16(MDMA1_D1_Y_COUNT)
+#define bfin_write_MDMA1_D1_Y_COUNT(val)     bfin_write16(MDMA1_D1_Y_COUNT,val)
+#define bfin_read_MDMA1_D1_X_MODIFY()        bfin_read16(MDMA1_D1_X_MODIFY)
+#define bfin_write_MDMA1_D1_X_MODIFY(val)    bfin_write16(MDMA1_D1_X_MODIFY,val)
+#define bfin_read_MDMA1_D1_Y_MODIFY()        bfin_read16(MDMA1_D1_Y_MODIFY)
+#define bfin_write_MDMA1_D1_Y_MODIFY(val)    bfin_write16(MDMA1_D1_Y_MODIFY,val)
+#define bfin_read_MDMA1_D1_CURR_DESC_PTR()   bfin_read32(MDMA1_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA1_D1_CURR_DESC_PTR(val) bfin_write32(MDMA1_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_D1_CURR_ADDR()       bfin_read32(MDMA1_D1_CURR_ADDR)
+#define bfin_write_MDMA1_D1_CURR_ADDR(val)   bfin_write32(MDMA1_D1_CURR_ADDR,val)
+#define bfin_read_MDMA1_D1_CURR_X_COUNT()    bfin_read16(MDMA1_D1_CURR_X_COUNT)
+#define bfin_write_MDMA1_D1_CURR_X_COUNT(val) bfin_write16(MDMA1_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_D1_CURR_Y_COUNT()    bfin_read16(MDMA1_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA1_D1_CURR_Y_COUNT(val) bfin_write16(MDMA1_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_D1_IRQ_STATUS()      bfin_read16(MDMA1_D1_IRQ_STATUS)
+#define bfin_write_MDMA1_D1_IRQ_STATUS(val)  bfin_write16(MDMA1_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA1_D1_PERIPHERAL_MAP()  bfin_read16(MDMA1_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA1_D1_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_S1_CONFIG()          bfin_read16(MDMA1_S1_CONFIG)
+#define bfin_write_MDMA1_S1_CONFIG(val)      bfin_write16(MDMA1_S1_CONFIG,val)
+#define bfin_read_MDMA1_S1_NEXT_DESC_PTR()   bfin_read32(MDMA1_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA1_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_S1_START_ADDR()      bfin_read32(MDMA1_S1_START_ADDR)
+#define bfin_write_MDMA1_S1_START_ADDR(val)  bfin_write32(MDMA1_S1_START_ADDR,val)
+#define bfin_read_MDMA1_S1_X_COUNT()         bfin_read16(MDMA1_S1_X_COUNT)
+#define bfin_write_MDMA1_S1_X_COUNT(val)     bfin_write16(MDMA1_S1_X_COUNT,val)
+#define bfin_read_MDMA1_S1_Y_COUNT()         bfin_read16(MDMA1_S1_Y_COUNT)
+#define bfin_write_MDMA1_S1_Y_COUNT(val)     bfin_write16(MDMA1_S1_Y_COUNT,val)
+#define bfin_read_MDMA1_S1_X_MODIFY()        bfin_read16(MDMA1_S1_X_MODIFY)
+#define bfin_write_MDMA1_S1_X_MODIFY(val)    bfin_write16(MDMA1_S1_X_MODIFY,val)
+#define bfin_read_MDMA1_S1_Y_MODIFY()        bfin_read16(MDMA1_S1_Y_MODIFY)
+#define bfin_write_MDMA1_S1_Y_MODIFY(val)    bfin_write16(MDMA1_S1_Y_MODIFY,val)
+#define bfin_read_MDMA1_S1_CURR_DESC_PTR()   bfin_read32(MDMA1_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA1_S1_CURR_DESC_PTR(val) bfin_write32(MDMA1_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_S1_CURR_ADDR()       bfin_read32(MDMA1_S1_CURR_ADDR)
+#define bfin_write_MDMA1_S1_CURR_ADDR(val)   bfin_write32(MDMA1_S1_CURR_ADDR,val)
+#define bfin_read_MDMA1_S1_CURR_X_COUNT()    bfin_read16(MDMA1_S1_CURR_X_COUNT)
+#define bfin_write_MDMA1_S1_CURR_X_COUNT(val) bfin_write16(MDMA1_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_S1_CURR_Y_COUNT()    bfin_read16(MDMA1_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA1_S1_CURR_Y_COUNT(val) bfin_write16(MDMA1_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_S1_IRQ_STATUS()      bfin_read16(MDMA1_S1_IRQ_STATUS)
+#define bfin_write_MDMA1_S1_IRQ_STATUS(val)  bfin_write16(MDMA1_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA1_S1_PERIPHERAL_MAP()  bfin_read16(MDMA1_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA1_S1_PERIPHERAL_MAP,val)
+/* DMA2 Controller registers (0xFFC0 0C00-0xFFC0 0DFF) */
+#define bfin_read_DMA2_0_CONFIG()            bfin_read16(DMA2_0_CONFIG)
+#define bfin_write_DMA2_0_CONFIG(val)        bfin_write16(DMA2_0_CONFIG,val)
+#define bfin_read_DMA2_0_NEXT_DESC_PTR()     bfin_read32(DMA2_0_NEXT_DESC_PTR)
+#define bfin_write_DMA2_0_NEXT_DESC_PTR(val) bfin_write32(DMA2_0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_0_START_ADDR()        bfin_read32(DMA2_0_START_ADDR)
+#define bfin_write_DMA2_0_START_ADDR(val)    bfin_write32(DMA2_0_START_ADDR,val)
+#define bfin_read_DMA2_0_X_COUNT()           bfin_read16(DMA2_0_X_COUNT)
+#define bfin_write_DMA2_0_X_COUNT(val)       bfin_write16(DMA2_0_X_COUNT,val)
+#define bfin_read_DMA2_0_Y_COUNT()           bfin_read16(DMA2_0_Y_COUNT)
+#define bfin_write_DMA2_0_Y_COUNT(val)       bfin_write16(DMA2_0_Y_COUNT,val)
+#define bfin_read_DMA2_0_X_MODIFY()          bfin_read16(DMA2_0_X_MODIFY)
+#define bfin_write_DMA2_0_X_MODIFY(val)      bfin_write16(DMA2_0_X_MODIFY,val)
+#define bfin_read_DMA2_0_Y_MODIFY()          bfin_read16(DMA2_0_Y_MODIFY)
+#define bfin_write_DMA2_0_Y_MODIFY(val)      bfin_write16(DMA2_0_Y_MODIFY,val)
+#define bfin_read_DMA2_0_CURR_DESC_PTR()     bfin_read32(DMA2_0_CURR_DESC_PTR)
+#define bfin_write_DMA2_0_CURR_DESC_PTR(val) bfin_write32(DMA2_0_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_0_CURR_ADDR()         bfin_read32(DMA2_0_CURR_ADDR)
+#define bfin_write_DMA2_0_CURR_ADDR(val)     bfin_write32(DMA2_0_CURR_ADDR,val)
+#define bfin_read_DMA2_0_CURR_X_COUNT()      bfin_read16(DMA2_0_CURR_X_COUNT)
+#define bfin_write_DMA2_0_CURR_X_COUNT(val)  bfin_write16(DMA2_0_CURR_X_COUNT,val)
+#define bfin_read_DMA2_0_CURR_Y_COUNT()      bfin_read16(DMA2_0_CURR_Y_COUNT)
+#define bfin_write_DMA2_0_CURR_Y_COUNT(val)  bfin_write16(DMA2_0_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_0_IRQ_STATUS()        bfin_read16(DMA2_0_IRQ_STATUS)
+#define bfin_write_DMA2_0_IRQ_STATUS(val)    bfin_write16(DMA2_0_IRQ_STATUS,val)
+#define bfin_read_DMA2_0_PERIPHERAL_MAP()    bfin_read16(DMA2_0_PERIPHERAL_MAP)
+#define bfin_write_DMA2_0_PERIPHERAL_MAP(val) bfin_write16(DMA2_0_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_1_CONFIG()            bfin_read16(DMA2_1_CONFIG)
+#define bfin_write_DMA2_1_CONFIG(val)        bfin_write16(DMA2_1_CONFIG,val)
+#define bfin_read_DMA2_1_NEXT_DESC_PTR()     bfin_read32(DMA2_1_NEXT_DESC_PTR)
+#define bfin_write_DMA2_1_NEXT_DESC_PTR(val) bfin_write32(DMA2_1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_1_START_ADDR()        bfin_read32(DMA2_1_START_ADDR)
+#define bfin_write_DMA2_1_START_ADDR(val)    bfin_write32(DMA2_1_START_ADDR,val)
+#define bfin_read_DMA2_1_X_COUNT()           bfin_read16(DMA2_1_X_COUNT)
+#define bfin_write_DMA2_1_X_COUNT(val)       bfin_write16(DMA2_1_X_COUNT,val)
+#define bfin_read_DMA2_1_Y_COUNT()           bfin_read16(DMA2_1_Y_COUNT)
+#define bfin_write_DMA2_1_Y_COUNT(val)       bfin_write16(DMA2_1_Y_COUNT,val)
+#define bfin_read_DMA2_1_X_MODIFY()          bfin_read16(DMA2_1_X_MODIFY)
+#define bfin_write_DMA2_1_X_MODIFY(val)      bfin_write16(DMA2_1_X_MODIFY,val)
+#define bfin_read_DMA2_1_Y_MODIFY()          bfin_read16(DMA2_1_Y_MODIFY)
+#define bfin_write_DMA2_1_Y_MODIFY(val)      bfin_write16(DMA2_1_Y_MODIFY,val)
+#define bfin_read_DMA2_1_CURR_DESC_PTR()     bfin_read32(DMA2_1_CURR_DESC_PTR)
+#define bfin_write_DMA2_1_CURR_DESC_PTR(val) bfin_write32(DMA2_1_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_1_CURR_ADDR()         bfin_read32(DMA2_1_CURR_ADDR)
+#define bfin_write_DMA2_1_CURR_ADDR(val)     bfin_write32(DMA2_1_CURR_ADDR,val)
+#define bfin_read_DMA2_1_CURR_X_COUNT()      bfin_read16(DMA2_1_CURR_X_COUNT)
+#define bfin_write_DMA2_1_CURR_X_COUNT(val)  bfin_write16(DMA2_1_CURR_X_COUNT,val)
+#define bfin_read_DMA2_1_CURR_Y_COUNT()      bfin_read16(DMA2_1_CURR_Y_COUNT)
+#define bfin_write_DMA2_1_CURR_Y_COUNT(val)  bfin_write16(DMA2_1_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_1_IRQ_STATUS()        bfin_read16(DMA2_1_IRQ_STATUS)
+#define bfin_write_DMA2_1_IRQ_STATUS(val)    bfin_write16(DMA2_1_IRQ_STATUS,val)
+#define bfin_read_DMA2_1_PERIPHERAL_MAP()    bfin_read16(DMA2_1_PERIPHERAL_MAP)
+#define bfin_write_DMA2_1_PERIPHERAL_MAP(val) bfin_write16(DMA2_1_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_2_CONFIG()            bfin_read16(DMA2_2_CONFIG)
+#define bfin_write_DMA2_2_CONFIG(val)        bfin_write16(DMA2_2_CONFIG,val)
+#define bfin_read_DMA2_2_NEXT_DESC_PTR()     bfin_read32(DMA2_2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_2_NEXT_DESC_PTR(val) bfin_write32(DMA2_2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_2_START_ADDR()        bfin_read32(DMA2_2_START_ADDR)
+#define bfin_write_DMA2_2_START_ADDR(val)    bfin_write32(DMA2_2_START_ADDR,val)
+#define bfin_read_DMA2_2_X_COUNT()           bfin_read16(DMA2_2_X_COUNT)
+#define bfin_write_DMA2_2_X_COUNT(val)       bfin_write16(DMA2_2_X_COUNT,val)
+#define bfin_read_DMA2_2_Y_COUNT()           bfin_read16(DMA2_2_Y_COUNT)
+#define bfin_write_DMA2_2_Y_COUNT(val)       bfin_write16(DMA2_2_Y_COUNT,val)
+#define bfin_read_DMA2_2_X_MODIFY()          bfin_read16(DMA2_2_X_MODIFY)
+#define bfin_write_DMA2_2_X_MODIFY(val)      bfin_write16(DMA2_2_X_MODIFY,val)
+#define bfin_read_DMA2_2_Y_MODIFY()          bfin_read16(DMA2_2_Y_MODIFY)
+#define bfin_write_DMA2_2_Y_MODIFY(val)      bfin_write16(DMA2_2_Y_MODIFY,val)
+#define bfin_read_DMA2_2_CURR_DESC_PTR()     bfin_read32(DMA2_2_CURR_DESC_PTR)
+#define bfin_write_DMA2_2_CURR_DESC_PTR(val) bfin_write32(DMA2_2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_2_CURR_ADDR()         bfin_read32(DMA2_2_CURR_ADDR)
+#define bfin_write_DMA2_2_CURR_ADDR(val)     bfin_write32(DMA2_2_CURR_ADDR,val)
+#define bfin_read_DMA2_2_CURR_X_COUNT()      bfin_read16(DMA2_2_CURR_X_COUNT)
+#define bfin_write_DMA2_2_CURR_X_COUNT(val)  bfin_write16(DMA2_2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_2_CURR_Y_COUNT()      bfin_read16(DMA2_2_CURR_Y_COUNT)
+#define bfin_write_DMA2_2_CURR_Y_COUNT(val)  bfin_write16(DMA2_2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_2_IRQ_STATUS()        bfin_read16(DMA2_2_IRQ_STATUS)
+#define bfin_write_DMA2_2_IRQ_STATUS(val)    bfin_write16(DMA2_2_IRQ_STATUS,val)
+#define bfin_read_DMA2_2_PERIPHERAL_MAP()    bfin_read16(DMA2_2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_2_PERIPHERAL_MAP(val) bfin_write16(DMA2_2_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_3_CONFIG()            bfin_read16(DMA2_3_CONFIG)
+#define bfin_write_DMA2_3_CONFIG(val)        bfin_write16(DMA2_3_CONFIG,val)
+#define bfin_read_DMA2_3_NEXT_DESC_PTR()     bfin_read32(DMA2_3_NEXT_DESC_PTR)
+#define bfin_write_DMA2_3_NEXT_DESC_PTR(val) bfin_write32(DMA2_3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_3_START_ADDR()        bfin_read32(DMA2_3_START_ADDR)
+#define bfin_write_DMA2_3_START_ADDR(val)    bfin_write32(DMA2_3_START_ADDR,val)
+#define bfin_read_DMA2_3_X_COUNT()           bfin_read16(DMA2_3_X_COUNT)
+#define bfin_write_DMA2_3_X_COUNT(val)       bfin_write16(DMA2_3_X_COUNT,val)
+#define bfin_read_DMA2_3_Y_COUNT()           bfin_read16(DMA2_3_Y_COUNT)
+#define bfin_write_DMA2_3_Y_COUNT(val)       bfin_write16(DMA2_3_Y_COUNT,val)
+#define bfin_read_DMA2_3_X_MODIFY()          bfin_read16(DMA2_3_X_MODIFY)
+#define bfin_write_DMA2_3_X_MODIFY(val)      bfin_write16(DMA2_3_X_MODIFY,val)
+#define bfin_read_DMA2_3_Y_MODIFY()          bfin_read16(DMA2_3_Y_MODIFY)
+#define bfin_write_DMA2_3_Y_MODIFY(val)      bfin_write16(DMA2_3_Y_MODIFY,val)
+#define bfin_read_DMA2_3_CURR_DESC_PTR()     bfin_read32(DMA2_3_CURR_DESC_PTR)
+#define bfin_write_DMA2_3_CURR_DESC_PTR(val) bfin_write32(DMA2_3_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_3_CURR_ADDR()         bfin_read32(DMA2_3_CURR_ADDR)
+#define bfin_write_DMA2_3_CURR_ADDR(val)     bfin_write32(DMA2_3_CURR_ADDR,val)
+#define bfin_read_DMA2_3_CURR_X_COUNT()      bfin_read16(DMA2_3_CURR_X_COUNT)
+#define bfin_write_DMA2_3_CURR_X_COUNT(val)  bfin_write16(DMA2_3_CURR_X_COUNT,val)
+#define bfin_read_DMA2_3_CURR_Y_COUNT()      bfin_read16(DMA2_3_CURR_Y_COUNT)
+#define bfin_write_DMA2_3_CURR_Y_COUNT(val)  bfin_write16(DMA2_3_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_3_IRQ_STATUS()        bfin_read16(DMA2_3_IRQ_STATUS)
+#define bfin_write_DMA2_3_IRQ_STATUS(val)    bfin_write16(DMA2_3_IRQ_STATUS,val)
+#define bfin_read_DMA2_3_PERIPHERAL_MAP()    bfin_read16(DMA2_3_PERIPHERAL_MAP)
+#define bfin_write_DMA2_3_PERIPHERAL_MAP(val) bfin_write16(DMA2_3_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_4_CONFIG()            bfin_read16(DMA2_4_CONFIG)
+#define bfin_write_DMA2_4_CONFIG(val)        bfin_write16(DMA2_4_CONFIG,val)
+#define bfin_read_DMA2_4_NEXT_DESC_PTR()     bfin_read32(DMA2_4_NEXT_DESC_PTR)
+#define bfin_write_DMA2_4_NEXT_DESC_PTR(val) bfin_write32(DMA2_4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_4_START_ADDR()        bfin_read32(DMA2_4_START_ADDR)
+#define bfin_write_DMA2_4_START_ADDR(val)    bfin_write32(DMA2_4_START_ADDR,val)
+#define bfin_read_DMA2_4_X_COUNT()           bfin_read16(DMA2_4_X_COUNT)
+#define bfin_write_DMA2_4_X_COUNT(val)       bfin_write16(DMA2_4_X_COUNT,val)
+#define bfin_read_DMA2_4_Y_COUNT()           bfin_read16(DMA2_4_Y_COUNT)
+#define bfin_write_DMA2_4_Y_COUNT(val)       bfin_write16(DMA2_4_Y_COUNT,val)
+#define bfin_read_DMA2_4_X_MODIFY()          bfin_read16(DMA2_4_X_MODIFY)
+#define bfin_write_DMA2_4_X_MODIFY(val)      bfin_write16(DMA2_4_X_MODIFY,val)
+#define bfin_read_DMA2_4_Y_MODIFY()          bfin_read16(DMA2_4_Y_MODIFY)
+#define bfin_write_DMA2_4_Y_MODIFY(val)      bfin_write16(DMA2_4_Y_MODIFY,val)
+#define bfin_read_DMA2_4_CURR_DESC_PTR()     bfin_read32(DMA2_4_CURR_DESC_PTR)
+#define bfin_write_DMA2_4_CURR_DESC_PTR(val) bfin_write32(DMA2_4_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_4_CURR_ADDR()         bfin_read32(DMA2_4_CURR_ADDR)
+#define bfin_write_DMA2_4_CURR_ADDR(val)     bfin_write32(DMA2_4_CURR_ADDR,val)
+#define bfin_read_DMA2_4_CURR_X_COUNT()      bfin_read16(DMA2_4_CURR_X_COUNT)
+#define bfin_write_DMA2_4_CURR_X_COUNT(val)  bfin_write16(DMA2_4_CURR_X_COUNT,val)
+#define bfin_read_DMA2_4_CURR_Y_COUNT()      bfin_read16(DMA2_4_CURR_Y_COUNT)
+#define bfin_write_DMA2_4_CURR_Y_COUNT(val)  bfin_write16(DMA2_4_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_4_IRQ_STATUS()        bfin_read16(DMA2_4_IRQ_STATUS)
+#define bfin_write_DMA2_4_IRQ_STATUS(val)    bfin_write16(DMA2_4_IRQ_STATUS,val)
+#define bfin_read_DMA2_4_PERIPHERAL_MAP()    bfin_read16(DMA2_4_PERIPHERAL_MAP)
+#define bfin_write_DMA2_4_PERIPHERAL_MAP(val) bfin_write16(DMA2_4_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_5_CONFIG()            bfin_read16(DMA2_5_CONFIG)
+#define bfin_write_DMA2_5_CONFIG(val)        bfin_write16(DMA2_5_CONFIG,val)
+#define bfin_read_DMA2_5_NEXT_DESC_PTR()     bfin_read32(DMA2_5_NEXT_DESC_PTR)
+#define bfin_write_DMA2_5_NEXT_DESC_PTR(val) bfin_write32(DMA2_5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_5_START_ADDR()        bfin_read32(DMA2_5_START_ADDR)
+#define bfin_write_DMA2_5_START_ADDR(val)    bfin_write32(DMA2_5_START_ADDR,val)
+#define bfin_read_DMA2_5_X_COUNT()           bfin_read16(DMA2_5_X_COUNT)
+#define bfin_write_DMA2_5_X_COUNT(val)       bfin_write16(DMA2_5_X_COUNT,val)
+#define bfin_read_DMA2_5_Y_COUNT()           bfin_read16(DMA2_5_Y_COUNT)
+#define bfin_write_DMA2_5_Y_COUNT(val)       bfin_write16(DMA2_5_Y_COUNT,val)
+#define bfin_read_DMA2_5_X_MODIFY()          bfin_read16(DMA2_5_X_MODIFY)
+#define bfin_write_DMA2_5_X_MODIFY(val)      bfin_write16(DMA2_5_X_MODIFY,val)
+#define bfin_read_DMA2_5_Y_MODIFY()          bfin_read16(DMA2_5_Y_MODIFY)
+#define bfin_write_DMA2_5_Y_MODIFY(val)      bfin_write16(DMA2_5_Y_MODIFY,val)
+#define bfin_read_DMA2_5_CURR_DESC_PTR()     bfin_read32(DMA2_5_CURR_DESC_PTR)
+#define bfin_write_DMA2_5_CURR_DESC_PTR(val) bfin_write32(DMA2_5_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_5_CURR_ADDR()         bfin_read32(DMA2_5_CURR_ADDR)
+#define bfin_write_DMA2_5_CURR_ADDR(val)     bfin_write32(DMA2_5_CURR_ADDR,val)
+#define bfin_read_DMA2_5_CURR_X_COUNT()      bfin_read16(DMA2_5_CURR_X_COUNT)
+#define bfin_write_DMA2_5_CURR_X_COUNT(val)  bfin_write16(DMA2_5_CURR_X_COUNT,val)
+#define bfin_read_DMA2_5_CURR_Y_COUNT()      bfin_read16(DMA2_5_CURR_Y_COUNT)
+#define bfin_write_DMA2_5_CURR_Y_COUNT(val)  bfin_write16(DMA2_5_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_5_IRQ_STATUS()        bfin_read16(DMA2_5_IRQ_STATUS)
+#define bfin_write_DMA2_5_IRQ_STATUS(val)    bfin_write16(DMA2_5_IRQ_STATUS,val)
+#define bfin_read_DMA2_5_PERIPHERAL_MAP()    bfin_read16(DMA2_5_PERIPHERAL_MAP)
+#define bfin_write_DMA2_5_PERIPHERAL_MAP(val) bfin_write16(DMA2_5_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_6_CONFIG()            bfin_read16(DMA2_6_CONFIG)
+#define bfin_write_DMA2_6_CONFIG(val)        bfin_write16(DMA2_6_CONFIG,val)
+#define bfin_read_DMA2_6_NEXT_DESC_PTR()     bfin_read32(DMA2_6_NEXT_DESC_PTR)
+#define bfin_write_DMA2_6_NEXT_DESC_PTR(val) bfin_write32(DMA2_6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_6_START_ADDR()        bfin_read32(DMA2_6_START_ADDR)
+#define bfin_write_DMA2_6_START_ADDR(val)    bfin_write32(DMA2_6_START_ADDR,val)
+#define bfin_read_DMA2_6_X_COUNT()           bfin_read16(DMA2_6_X_COUNT)
+#define bfin_write_DMA2_6_X_COUNT(val)       bfin_write16(DMA2_6_X_COUNT,val)
+#define bfin_read_DMA2_6_Y_COUNT()           bfin_read16(DMA2_6_Y_COUNT)
+#define bfin_write_DMA2_6_Y_COUNT(val)       bfin_write16(DMA2_6_Y_COUNT,val)
+#define bfin_read_DMA2_6_X_MODIFY()          bfin_read16(DMA2_6_X_MODIFY)
+#define bfin_write_DMA2_6_X_MODIFY(val)      bfin_write16(DMA2_6_X_MODIFY,val)
+#define bfin_read_DMA2_6_Y_MODIFY()          bfin_read16(DMA2_6_Y_MODIFY)
+#define bfin_write_DMA2_6_Y_MODIFY(val)      bfin_write16(DMA2_6_Y_MODIFY,val)
+#define bfin_read_DMA2_6_CURR_DESC_PTR()     bfin_read32(DMA2_6_CURR_DESC_PTR)
+#define bfin_write_DMA2_6_CURR_DESC_PTR(val) bfin_write32(DMA2_6_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_6_CURR_ADDR()         bfin_read32(DMA2_6_CURR_ADDR)
+#define bfin_write_DMA2_6_CURR_ADDR(val)     bfin_write32(DMA2_6_CURR_ADDR,val)
+#define bfin_read_DMA2_6_CURR_X_COUNT()      bfin_read16(DMA2_6_CURR_X_COUNT)
+#define bfin_write_DMA2_6_CURR_X_COUNT(val)  bfin_write16(DMA2_6_CURR_X_COUNT,val)
+#define bfin_read_DMA2_6_CURR_Y_COUNT()      bfin_read16(DMA2_6_CURR_Y_COUNT)
+#define bfin_write_DMA2_6_CURR_Y_COUNT(val)  bfin_write16(DMA2_6_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_6_IRQ_STATUS()        bfin_read16(DMA2_6_IRQ_STATUS)
+#define bfin_write_DMA2_6_IRQ_STATUS(val)    bfin_write16(DMA2_6_IRQ_STATUS,val)
+#define bfin_read_DMA2_6_PERIPHERAL_MAP()    bfin_read16(DMA2_6_PERIPHERAL_MAP)
+#define bfin_write_DMA2_6_PERIPHERAL_MAP(val) bfin_write16(DMA2_6_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_7_CONFIG()            bfin_read16(DMA2_7_CONFIG)
+#define bfin_write_DMA2_7_CONFIG(val)        bfin_write16(DMA2_7_CONFIG,val)
+#define bfin_read_DMA2_7_NEXT_DESC_PTR()     bfin_read32(DMA2_7_NEXT_DESC_PTR)
+#define bfin_write_DMA2_7_NEXT_DESC_PTR(val) bfin_write32(DMA2_7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_7_START_ADDR()        bfin_read32(DMA2_7_START_ADDR)
+#define bfin_write_DMA2_7_START_ADDR(val)    bfin_write32(DMA2_7_START_ADDR,val)
+#define bfin_read_DMA2_7_X_COUNT()           bfin_read16(DMA2_7_X_COUNT)
+#define bfin_write_DMA2_7_X_COUNT(val)       bfin_write16(DMA2_7_X_COUNT,val)
+#define bfin_read_DMA2_7_Y_COUNT()           bfin_read16(DMA2_7_Y_COUNT)
+#define bfin_write_DMA2_7_Y_COUNT(val)       bfin_write16(DMA2_7_Y_COUNT,val)
+#define bfin_read_DMA2_7_X_MODIFY()          bfin_read16(DMA2_7_X_MODIFY)
+#define bfin_write_DMA2_7_X_MODIFY(val)      bfin_write16(DMA2_7_X_MODIFY,val)
+#define bfin_read_DMA2_7_Y_MODIFY()          bfin_read16(DMA2_7_Y_MODIFY)
+#define bfin_write_DMA2_7_Y_MODIFY(val)      bfin_write16(DMA2_7_Y_MODIFY,val)
+#define bfin_read_DMA2_7_CURR_DESC_PTR()     bfin_read32(DMA2_7_CURR_DESC_PTR)
+#define bfin_write_DMA2_7_CURR_DESC_PTR(val) bfin_write32(DMA2_7_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_7_CURR_ADDR()         bfin_read32(DMA2_7_CURR_ADDR)
+#define bfin_write_DMA2_7_CURR_ADDR(val)     bfin_write32(DMA2_7_CURR_ADDR,val)
+#define bfin_read_DMA2_7_CURR_X_COUNT()      bfin_read16(DMA2_7_CURR_X_COUNT)
+#define bfin_write_DMA2_7_CURR_X_COUNT(val)  bfin_write16(DMA2_7_CURR_X_COUNT,val)
+#define bfin_read_DMA2_7_CURR_Y_COUNT()      bfin_read16(DMA2_7_CURR_Y_COUNT)
+#define bfin_write_DMA2_7_CURR_Y_COUNT(val)  bfin_write16(DMA2_7_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_7_IRQ_STATUS()        bfin_read16(DMA2_7_IRQ_STATUS)
+#define bfin_write_DMA2_7_IRQ_STATUS(val)    bfin_write16(DMA2_7_IRQ_STATUS,val)
+#define bfin_read_DMA2_7_PERIPHERAL_MAP()    bfin_read16(DMA2_7_PERIPHERAL_MAP)
+#define bfin_write_DMA2_7_PERIPHERAL_MAP(val) bfin_write16(DMA2_7_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_8_CONFIG()            bfin_read16(DMA2_8_CONFIG)
+#define bfin_write_DMA2_8_CONFIG(val)        bfin_write16(DMA2_8_CONFIG,val)
+#define bfin_read_DMA2_8_NEXT_DESC_PTR()     bfin_read32(DMA2_8_NEXT_DESC_PTR)
+#define bfin_write_DMA2_8_NEXT_DESC_PTR(val) bfin_write32(DMA2_8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_8_START_ADDR()        bfin_read32(DMA2_8_START_ADDR)
+#define bfin_write_DMA2_8_START_ADDR(val)    bfin_write32(DMA2_8_START_ADDR,val)
+#define bfin_read_DMA2_8_X_COUNT()           bfin_read16(DMA2_8_X_COUNT)
+#define bfin_write_DMA2_8_X_COUNT(val)       bfin_write16(DMA2_8_X_COUNT,val)
+#define bfin_read_DMA2_8_Y_COUNT()           bfin_read16(DMA2_8_Y_COUNT)
+#define bfin_write_DMA2_8_Y_COUNT(val)       bfin_write16(DMA2_8_Y_COUNT,val)
+#define bfin_read_DMA2_8_X_MODIFY()          bfin_read16(DMA2_8_X_MODIFY)
+#define bfin_write_DMA2_8_X_MODIFY(val)      bfin_write16(DMA2_8_X_MODIFY,val)
+#define bfin_read_DMA2_8_Y_MODIFY()          bfin_read16(DMA2_8_Y_MODIFY)
+#define bfin_write_DMA2_8_Y_MODIFY(val)      bfin_write16(DMA2_8_Y_MODIFY,val)
+#define bfin_read_DMA2_8_CURR_DESC_PTR()     bfin_read32(DMA2_8_CURR_DESC_PTR)
+#define bfin_write_DMA2_8_CURR_DESC_PTR(val) bfin_write32(DMA2_8_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_8_CURR_ADDR()         bfin_read32(DMA2_8_CURR_ADDR)
+#define bfin_write_DMA2_8_CURR_ADDR(val)     bfin_write32(DMA2_8_CURR_ADDR,val)
+#define bfin_read_DMA2_8_CURR_X_COUNT()      bfin_read16(DMA2_8_CURR_X_COUNT)
+#define bfin_write_DMA2_8_CURR_X_COUNT(val)  bfin_write16(DMA2_8_CURR_X_COUNT,val)
+#define bfin_read_DMA2_8_CURR_Y_COUNT()      bfin_read16(DMA2_8_CURR_Y_COUNT)
+#define bfin_write_DMA2_8_CURR_Y_COUNT(val)  bfin_write16(DMA2_8_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_8_IRQ_STATUS()        bfin_read16(DMA2_8_IRQ_STATUS)
+#define bfin_write_DMA2_8_IRQ_STATUS(val)    bfin_write16(DMA2_8_IRQ_STATUS,val)
+#define bfin_read_DMA2_8_PERIPHERAL_MAP()    bfin_read16(DMA2_8_PERIPHERAL_MAP)
+#define bfin_write_DMA2_8_PERIPHERAL_MAP(val) bfin_write16(DMA2_8_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_9_CONFIG()            bfin_read16(DMA2_9_CONFIG)
+#define bfin_write_DMA2_9_CONFIG(val)        bfin_write16(DMA2_9_CONFIG,val)
+#define bfin_read_DMA2_9_NEXT_DESC_PTR()     bfin_read32(DMA2_9_NEXT_DESC_PTR)
+#define bfin_write_DMA2_9_NEXT_DESC_PTR(val) bfin_write32(DMA2_9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_9_START_ADDR()        bfin_read32(DMA2_9_START_ADDR)
+#define bfin_write_DMA2_9_START_ADDR(val)    bfin_write32(DMA2_9_START_ADDR,val)
+#define bfin_read_DMA2_9_X_COUNT()           bfin_read16(DMA2_9_X_COUNT)
+#define bfin_write_DMA2_9_X_COUNT(val)       bfin_write16(DMA2_9_X_COUNT,val)
+#define bfin_read_DMA2_9_Y_COUNT()           bfin_read16(DMA2_9_Y_COUNT)
+#define bfin_write_DMA2_9_Y_COUNT(val)       bfin_write16(DMA2_9_Y_COUNT,val)
+#define bfin_read_DMA2_9_X_MODIFY()          bfin_read16(DMA2_9_X_MODIFY)
+#define bfin_write_DMA2_9_X_MODIFY(val)      bfin_write16(DMA2_9_X_MODIFY,val)
+#define bfin_read_DMA2_9_Y_MODIFY()          bfin_read16(DMA2_9_Y_MODIFY)
+#define bfin_write_DMA2_9_Y_MODIFY(val)      bfin_write16(DMA2_9_Y_MODIFY,val)
+#define bfin_read_DMA2_9_CURR_DESC_PTR()     bfin_read32(DMA2_9_CURR_DESC_PTR)
+#define bfin_write_DMA2_9_CURR_DESC_PTR(val) bfin_write32(DMA2_9_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_9_CURR_ADDR()         bfin_read32(DMA2_9_CURR_ADDR)
+#define bfin_write_DMA2_9_CURR_ADDR(val)     bfin_write32(DMA2_9_CURR_ADDR,val)
+#define bfin_read_DMA2_9_CURR_X_COUNT()      bfin_read16(DMA2_9_CURR_X_COUNT)
+#define bfin_write_DMA2_9_CURR_X_COUNT(val)  bfin_write16(DMA2_9_CURR_X_COUNT,val)
+#define bfin_read_DMA2_9_CURR_Y_COUNT()      bfin_read16(DMA2_9_CURR_Y_COUNT)
+#define bfin_write_DMA2_9_CURR_Y_COUNT(val)  bfin_write16(DMA2_9_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_9_IRQ_STATUS()        bfin_read16(DMA2_9_IRQ_STATUS)
+#define bfin_write_DMA2_9_IRQ_STATUS(val)    bfin_write16(DMA2_9_IRQ_STATUS,val)
+#define bfin_read_DMA2_9_PERIPHERAL_MAP()    bfin_read16(DMA2_9_PERIPHERAL_MAP)
+#define bfin_write_DMA2_9_PERIPHERAL_MAP(val) bfin_write16(DMA2_9_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_10_CONFIG()           bfin_read16(DMA2_10_CONFIG)
+#define bfin_write_DMA2_10_CONFIG(val)       bfin_write16(DMA2_10_CONFIG,val)
+#define bfin_read_DMA2_10_NEXT_DESC_PTR()    bfin_read32(DMA2_10_NEXT_DESC_PTR)
+#define bfin_write_DMA2_10_NEXT_DESC_PTR(val) bfin_write32(DMA2_10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_10_START_ADDR()       bfin_read32(DMA2_10_START_ADDR)
+#define bfin_write_DMA2_10_START_ADDR(val)   bfin_write32(DMA2_10_START_ADDR,val)
+#define bfin_read_DMA2_10_X_COUNT()          bfin_read16(DMA2_10_X_COUNT)
+#define bfin_write_DMA2_10_X_COUNT(val)      bfin_write16(DMA2_10_X_COUNT,val)
+#define bfin_read_DMA2_10_Y_COUNT()          bfin_read16(DMA2_10_Y_COUNT)
+#define bfin_write_DMA2_10_Y_COUNT(val)      bfin_write16(DMA2_10_Y_COUNT,val)
+#define bfin_read_DMA2_10_X_MODIFY()         bfin_read16(DMA2_10_X_MODIFY)
+#define bfin_write_DMA2_10_X_MODIFY(val)     bfin_write16(DMA2_10_X_MODIFY,val)
+#define bfin_read_DMA2_10_Y_MODIFY()         bfin_read16(DMA2_10_Y_MODIFY)
+#define bfin_write_DMA2_10_Y_MODIFY(val)     bfin_write16(DMA2_10_Y_MODIFY,val)
+#define bfin_read_DMA2_10_CURR_DESC_PTR()    bfin_read32(DMA2_10_CURR_DESC_PTR)
+#define bfin_write_DMA2_10_CURR_DESC_PTR(val) bfin_write32(DMA2_10_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_10_CURR_ADDR()        bfin_read32(DMA2_10_CURR_ADDR)
+#define bfin_write_DMA2_10_CURR_ADDR(val)    bfin_write32(DMA2_10_CURR_ADDR,val)
+#define bfin_read_DMA2_10_CURR_X_COUNT()     bfin_read16(DMA2_10_CURR_X_COUNT)
+#define bfin_write_DMA2_10_CURR_X_COUNT(val) bfin_write16(DMA2_10_CURR_X_COUNT,val)
+#define bfin_read_DMA2_10_CURR_Y_COUNT()     bfin_read16(DMA2_10_CURR_Y_COUNT)
+#define bfin_write_DMA2_10_CURR_Y_COUNT(val) bfin_write16(DMA2_10_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_10_IRQ_STATUS()       bfin_read16(DMA2_10_IRQ_STATUS)
+#define bfin_write_DMA2_10_IRQ_STATUS(val)   bfin_write16(DMA2_10_IRQ_STATUS,val)
+#define bfin_read_DMA2_10_PERIPHERAL_MAP()   bfin_read16(DMA2_10_PERIPHERAL_MAP)
+#define bfin_write_DMA2_10_PERIPHERAL_MAP(val) bfin_write16(DMA2_10_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_11_CONFIG()           bfin_read16(DMA2_11_CONFIG)
+#define bfin_write_DMA2_11_CONFIG(val)       bfin_write16(DMA2_11_CONFIG,val)
+#define bfin_read_DMA2_11_NEXT_DESC_PTR()    bfin_read32(DMA2_11_NEXT_DESC_PTR)
+#define bfin_write_DMA2_11_NEXT_DESC_PTR(val) bfin_write32(DMA2_11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_11_START_ADDR()       bfin_read32(DMA2_11_START_ADDR)
+#define bfin_write_DMA2_11_START_ADDR(val)   bfin_write32(DMA2_11_START_ADDR,val)
+#define bfin_read_DMA2_11_X_COUNT()          bfin_read16(DMA2_11_X_COUNT)
+#define bfin_write_DMA2_11_X_COUNT(val)      bfin_write16(DMA2_11_X_COUNT,val)
+#define bfin_read_DMA2_11_Y_COUNT()          bfin_read16(DMA2_11_Y_COUNT)
+#define bfin_write_DMA2_11_Y_COUNT(val)      bfin_write16(DMA2_11_Y_COUNT,val)
+#define bfin_read_DMA2_11_X_MODIFY()         bfin_read16(DMA2_11_X_MODIFY)
+#define bfin_write_DMA2_11_X_MODIFY(val)     bfin_write16(DMA2_11_X_MODIFY,val)
+#define bfin_read_DMA2_11_Y_MODIFY()         bfin_read16(DMA2_11_Y_MODIFY)
+#define bfin_write_DMA2_11_Y_MODIFY(val)     bfin_write16(DMA2_11_Y_MODIFY,val)
+#define bfin_read_DMA2_11_CURR_DESC_PTR()    bfin_read32(DMA2_11_CURR_DESC_PTR)
+#define bfin_write_DMA2_11_CURR_DESC_PTR(val) bfin_write32(DMA2_11_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_11_CURR_ADDR()        bfin_read32(DMA2_11_CURR_ADDR)
+#define bfin_write_DMA2_11_CURR_ADDR(val)    bfin_write32(DMA2_11_CURR_ADDR,val)
+#define bfin_read_DMA2_11_CURR_X_COUNT()     bfin_read16(DMA2_11_CURR_X_COUNT)
+#define bfin_write_DMA2_11_CURR_X_COUNT(val) bfin_write16(DMA2_11_CURR_X_COUNT,val)
+#define bfin_read_DMA2_11_CURR_Y_COUNT()     bfin_read16(DMA2_11_CURR_Y_COUNT)
+#define bfin_write_DMA2_11_CURR_Y_COUNT(val) bfin_write16(DMA2_11_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_11_IRQ_STATUS()       bfin_read16(DMA2_11_IRQ_STATUS)
+#define bfin_write_DMA2_11_IRQ_STATUS(val)   bfin_write16(DMA2_11_IRQ_STATUS,val)
+#define bfin_read_DMA2_11_PERIPHERAL_MAP()   bfin_read16(DMA2_11_PERIPHERAL_MAP)
+#define bfin_write_DMA2_11_PERIPHERAL_MAP(val) bfin_write16(DMA2_11_PERIPHERAL_MAP,val)
+/* Memory DMA2 Controller registers (0xFFC0 0E80-0xFFC0 0FFF) */
+#define bfin_read_MDMA2_D0_CONFIG()          bfin_read16(MDMA2_D0_CONFIG)
+#define bfin_write_MDMA2_D0_CONFIG(val)      bfin_write16(MDMA2_D0_CONFIG,val)
+#define bfin_read_MDMA2_D0_NEXT_DESC_PTR()   bfin_read32(MDMA2_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA2_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_D0_START_ADDR()      bfin_read32(MDMA2_D0_START_ADDR)
+#define bfin_write_MDMA2_D0_START_ADDR(val)  bfin_write32(MDMA2_D0_START_ADDR,val)
+#define bfin_read_MDMA2_D0_X_COUNT()         bfin_read16(MDMA2_D0_X_COUNT)
+#define bfin_write_MDMA2_D0_X_COUNT(val)     bfin_write16(MDMA2_D0_X_COUNT,val)
+#define bfin_read_MDMA2_D0_Y_COUNT()         bfin_read16(MDMA2_D0_Y_COUNT)
+#define bfin_write_MDMA2_D0_Y_COUNT(val)     bfin_write16(MDMA2_D0_Y_COUNT,val)
+#define bfin_read_MDMA2_D0_X_MODIFY()        bfin_read16(MDMA2_D0_X_MODIFY)
+#define bfin_write_MDMA2_D0_X_MODIFY(val)    bfin_write16(MDMA2_D0_X_MODIFY,val)
+#define bfin_read_MDMA2_D0_Y_MODIFY()        bfin_read16(MDMA2_D0_Y_MODIFY)
+#define bfin_write_MDMA2_D0_Y_MODIFY(val)    bfin_write16(MDMA2_D0_Y_MODIFY,val)
+#define bfin_read_MDMA2_D0_CURR_DESC_PTR()   bfin_read32(MDMA2_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA2_D0_CURR_DESC_PTR(val) bfin_write32(MDMA2_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_D0_CURR_ADDR()       bfin_read32(MDMA2_D0_CURR_ADDR)
+#define bfin_write_MDMA2_D0_CURR_ADDR(val)   bfin_write32(MDMA2_D0_CURR_ADDR,val)
+#define bfin_read_MDMA2_D0_CURR_X_COUNT()    bfin_read16(MDMA2_D0_CURR_X_COUNT)
+#define bfin_write_MDMA2_D0_CURR_X_COUNT(val) bfin_write16(MDMA2_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_D0_CURR_Y_COUNT()    bfin_read16(MDMA2_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA2_D0_CURR_Y_COUNT(val) bfin_write16(MDMA2_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_D0_IRQ_STATUS()      bfin_read16(MDMA2_D0_IRQ_STATUS)
+#define bfin_write_MDMA2_D0_IRQ_STATUS(val)  bfin_write16(MDMA2_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA2_D0_PERIPHERAL_MAP()  bfin_read16(MDMA2_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA2_D0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_S0_CONFIG()          bfin_read16(MDMA2_S0_CONFIG)
+#define bfin_write_MDMA2_S0_CONFIG(val)      bfin_write16(MDMA2_S0_CONFIG,val)
+#define bfin_read_MDMA2_S0_NEXT_DESC_PTR()   bfin_read32(MDMA2_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA2_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_S0_START_ADDR()      bfin_read32(MDMA2_S0_START_ADDR)
+#define bfin_write_MDMA2_S0_START_ADDR(val)  bfin_write32(MDMA2_S0_START_ADDR,val)
+#define bfin_read_MDMA2_S0_X_COUNT()         bfin_read16(MDMA2_S0_X_COUNT)
+#define bfin_write_MDMA2_S0_X_COUNT(val)     bfin_write16(MDMA2_S0_X_COUNT,val)
+#define bfin_read_MDMA2_S0_Y_COUNT()         bfin_read16(MDMA2_S0_Y_COUNT)
+#define bfin_write_MDMA2_S0_Y_COUNT(val)     bfin_write16(MDMA2_S0_Y_COUNT,val)
+#define bfin_read_MDMA2_S0_X_MODIFY()        bfin_read16(MDMA2_S0_X_MODIFY)
+#define bfin_write_MDMA2_S0_X_MODIFY(val)    bfin_write16(MDMA2_S0_X_MODIFY,val)
+#define bfin_read_MDMA2_S0_Y_MODIFY()        bfin_read16(MDMA2_S0_Y_MODIFY)
+#define bfin_write_MDMA2_S0_Y_MODIFY(val)    bfin_write16(MDMA2_S0_Y_MODIFY,val)
+#define bfin_read_MDMA2_S0_CURR_DESC_PTR()   bfin_read32(MDMA2_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA2_S0_CURR_DESC_PTR(val) bfin_write32(MDMA2_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_S0_CURR_ADDR()       bfin_read32(MDMA2_S0_CURR_ADDR)
+#define bfin_write_MDMA2_S0_CURR_ADDR(val)   bfin_write32(MDMA2_S0_CURR_ADDR,val)
+#define bfin_read_MDMA2_S0_CURR_X_COUNT()    bfin_read16(MDMA2_S0_CURR_X_COUNT)
+#define bfin_write_MDMA2_S0_CURR_X_COUNT(val) bfin_write16(MDMA2_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_S0_CURR_Y_COUNT()    bfin_read16(MDMA2_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA2_S0_CURR_Y_COUNT(val) bfin_write16(MDMA2_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_S0_IRQ_STATUS()      bfin_read16(MDMA2_S0_IRQ_STATUS)
+#define bfin_write_MDMA2_S0_IRQ_STATUS(val)  bfin_write16(MDMA2_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA2_S0_PERIPHERAL_MAP()  bfin_read16(MDMA2_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA2_S0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_D1_CONFIG()          bfin_read16(MDMA2_D1_CONFIG)
+#define bfin_write_MDMA2_D1_CONFIG(val)      bfin_write16(MDMA2_D1_CONFIG,val)
+#define bfin_read_MDMA2_D1_NEXT_DESC_PTR()   bfin_read32(MDMA2_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA2_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_D1_START_ADDR()      bfin_read32(MDMA2_D1_START_ADDR)
+#define bfin_write_MDMA2_D1_START_ADDR(val)  bfin_write32(MDMA2_D1_START_ADDR,val)
+#define bfin_read_MDMA2_D1_X_COUNT()         bfin_read16(MDMA2_D1_X_COUNT)
+#define bfin_write_MDMA2_D1_X_COUNT(val)     bfin_write16(MDMA2_D1_X_COUNT,val)
+#define bfin_read_MDMA2_D1_Y_COUNT()         bfin_read16(MDMA2_D1_Y_COUNT)
+#define bfin_write_MDMA2_D1_Y_COUNT(val)     bfin_write16(MDMA2_D1_Y_COUNT,val)
+#define bfin_read_MDMA2_D1_X_MODIFY()        bfin_read16(MDMA2_D1_X_MODIFY)
+#define bfin_write_MDMA2_D1_X_MODIFY(val)    bfin_write16(MDMA2_D1_X_MODIFY,val)
+#define bfin_read_MDMA2_D1_Y_MODIFY()        bfin_read16(MDMA2_D1_Y_MODIFY)
+#define bfin_write_MDMA2_D1_Y_MODIFY(val)    bfin_write16(MDMA2_D1_Y_MODIFY,val)
+#define bfin_read_MDMA2_D1_CURR_DESC_PTR()   bfin_read32(MDMA2_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA2_D1_CURR_DESC_PTR(val) bfin_write32(MDMA2_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_D1_CURR_ADDR()       bfin_read32(MDMA2_D1_CURR_ADDR)
+#define bfin_write_MDMA2_D1_CURR_ADDR(val)   bfin_write32(MDMA2_D1_CURR_ADDR,val)
+#define bfin_read_MDMA2_D1_CURR_X_COUNT()    bfin_read16(MDMA2_D1_CURR_X_COUNT)
+#define bfin_write_MDMA2_D1_CURR_X_COUNT(val) bfin_write16(MDMA2_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_D1_CURR_Y_COUNT()    bfin_read16(MDMA2_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA2_D1_CURR_Y_COUNT(val) bfin_write16(MDMA2_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_D1_IRQ_STATUS()      bfin_read16(MDMA2_D1_IRQ_STATUS)
+#define bfin_write_MDMA2_D1_IRQ_STATUS(val)  bfin_write16(MDMA2_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA2_D1_PERIPHERAL_MAP()  bfin_read16(MDMA2_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA2_D1_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_S1_CONFIG()          bfin_read16(MDMA2_S1_CONFIG)
+#define bfin_write_MDMA2_S1_CONFIG(val)      bfin_write16(MDMA2_S1_CONFIG,val)
+#define bfin_read_MDMA2_S1_NEXT_DESC_PTR()   bfin_read32(MDMA2_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA2_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_S1_START_ADDR()      bfin_read32(MDMA2_S1_START_ADDR)
+#define bfin_write_MDMA2_S1_START_ADDR(val)  bfin_write32(MDMA2_S1_START_ADDR,val)
+#define bfin_read_MDMA2_S1_X_COUNT()         bfin_read16(MDMA2_S1_X_COUNT)
+#define bfin_write_MDMA2_S1_X_COUNT(val)     bfin_write16(MDMA2_S1_X_COUNT,val)
+#define bfin_read_MDMA2_S1_Y_COUNT()         bfin_read16(MDMA2_S1_Y_COUNT)
+#define bfin_write_MDMA2_S1_Y_COUNT(val)     bfin_write16(MDMA2_S1_Y_COUNT,val)
+#define bfin_read_MDMA2_S1_X_MODIFY()        bfin_read16(MDMA2_S1_X_MODIFY)
+#define bfin_write_MDMA2_S1_X_MODIFY(val)    bfin_write16(MDMA2_S1_X_MODIFY,val)
+#define bfin_read_MDMA2_S1_Y_MODIFY()        bfin_read16(MDMA2_S1_Y_MODIFY)
+#define bfin_write_MDMA2_S1_Y_MODIFY(val)    bfin_write16(MDMA2_S1_Y_MODIFY,val)
+#define bfin_read_MDMA2_S1_CURR_DESC_PTR()   bfin_read32(MDMA2_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA2_S1_CURR_DESC_PTR(val) bfin_write32(MDMA2_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_S1_CURR_ADDR()       bfin_read32(MDMA2_S1_CURR_ADDR)
+#define bfin_write_MDMA2_S1_CURR_ADDR(val)   bfin_write32(MDMA2_S1_CURR_ADDR,val)
+#define bfin_read_MDMA2_S1_CURR_X_COUNT()    bfin_read16(MDMA2_S1_CURR_X_COUNT)
+#define bfin_write_MDMA2_S1_CURR_X_COUNT(val) bfin_write16(MDMA2_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_S1_CURR_Y_COUNT()    bfin_read16(MDMA2_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA2_S1_CURR_Y_COUNT(val) bfin_write16(MDMA2_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_S1_IRQ_STATUS()      bfin_read16(MDMA2_S1_IRQ_STATUS)
+#define bfin_write_MDMA2_S1_IRQ_STATUS(val)  bfin_write16(MDMA2_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA2_S1_PERIPHERAL_MAP()  bfin_read16(MDMA2_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA2_S1_PERIPHERAL_MAP,val)
+/* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
+#define bfin_read_IMDMA_D0_CONFIG()          bfin_read16(IMDMA_D0_CONFIG)
+#define bfin_write_IMDMA_D0_CONFIG(val)      bfin_write16(IMDMA_D0_CONFIG,val)
+#define bfin_read_IMDMA_D0_NEXT_DESC_PTR()   bfin_read32(IMDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_D0_NEXT_DESC_PTR(val) bfin_write32(IMDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_D0_START_ADDR()      bfin_read32(IMDMA_D0_START_ADDR)
+#define bfin_write_IMDMA_D0_START_ADDR(val)  bfin_write32(IMDMA_D0_START_ADDR,val)
+#define bfin_read_IMDMA_D0_X_COUNT()         bfin_read16(IMDMA_D0_X_COUNT)
+#define bfin_write_IMDMA_D0_X_COUNT(val)     bfin_write16(IMDMA_D0_X_COUNT,val)
+#define bfin_read_IMDMA_D0_Y_COUNT()         bfin_read16(IMDMA_D0_Y_COUNT)
+#define bfin_write_IMDMA_D0_Y_COUNT(val)     bfin_write16(IMDMA_D0_Y_COUNT,val)
+#define bfin_read_IMDMA_D0_X_MODIFY()        bfin_read16(IMDMA_D0_X_MODIFY)
+#define bfin_write_IMDMA_D0_X_MODIFY(val)    bfin_write16(IMDMA_D0_X_MODIFY,val)
+#define bfin_read_IMDMA_D0_Y_MODIFY()        bfin_read16(IMDMA_D0_Y_MODIFY)
+#define bfin_write_IMDMA_D0_Y_MODIFY(val)    bfin_write16(IMDMA_D0_Y_MODIFY,val)
+#define bfin_read_IMDMA_D0_CURR_DESC_PTR()   bfin_read32(IMDMA_D0_CURR_DESC_PTR)
+#define bfin_write_IMDMA_D0_CURR_DESC_PTR(val) bfin_write32(IMDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_D0_CURR_ADDR()       bfin_read32(IMDMA_D0_CURR_ADDR)
+#define bfin_write_IMDMA_D0_CURR_ADDR(val)   bfin_write32(IMDMA_D0_CURR_ADDR,val)
+#define bfin_read_IMDMA_D0_CURR_X_COUNT()    bfin_read16(IMDMA_D0_CURR_X_COUNT)
+#define bfin_write_IMDMA_D0_CURR_X_COUNT(val) bfin_write16(IMDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_D0_CURR_Y_COUNT()    bfin_read16(IMDMA_D0_CURR_Y_COUNT)
+#define bfin_write_IMDMA_D0_CURR_Y_COUNT(val) bfin_write16(IMDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_D0_IRQ_STATUS()      bfin_read16(IMDMA_D0_IRQ_STATUS)
+#define bfin_write_IMDMA_D0_IRQ_STATUS(val)  bfin_write16(IMDMA_D0_IRQ_STATUS,val)
+#define bfin_read_IMDMA_S0_CONFIG()          bfin_read16(IMDMA_S0_CONFIG)
+#define bfin_write_IMDMA_S0_CONFIG(val)      bfin_write16(IMDMA_S0_CONFIG,val)
+#define bfin_read_IMDMA_S0_NEXT_DESC_PTR()   bfin_read32(IMDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_S0_NEXT_DESC_PTR(val) bfin_write32(IMDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_S0_START_ADDR()      bfin_read32(IMDMA_S0_START_ADDR)
+#define bfin_write_IMDMA_S0_START_ADDR(val)  bfin_write32(IMDMA_S0_START_ADDR,val)
+#define bfin_read_IMDMA_S0_X_COUNT()         bfin_read16(IMDMA_S0_X_COUNT)
+#define bfin_write_IMDMA_S0_X_COUNT(val)     bfin_write16(IMDMA_S0_X_COUNT,val)
+#define bfin_read_IMDMA_S0_Y_COUNT()         bfin_read16(IMDMA_S0_Y_COUNT)
+#define bfin_write_IMDMA_S0_Y_COUNT(val)     bfin_write16(IMDMA_S0_Y_COUNT,val)
+#define bfin_read_IMDMA_S0_X_MODIFY()        bfin_read16(IMDMA_S0_X_MODIFY)
+#define bfin_write_IMDMA_S0_X_MODIFY(val)    bfin_write16(IMDMA_S0_X_MODIFY,val)
+#define bfin_read_IMDMA_S0_Y_MODIFY()        bfin_read16(IMDMA_S0_Y_MODIFY)
+#define bfin_write_IMDMA_S0_Y_MODIFY(val)    bfin_write16(IMDMA_S0_Y_MODIFY,val)
+#define bfin_read_IMDMA_S0_CURR_DESC_PTR()   bfin_read32(IMDMA_S0_CURR_DESC_PTR)
+#define bfin_write_IMDMA_S0_CURR_DESC_PTR(val) bfin_write32(IMDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_S0_CURR_ADDR()       bfin_read32(IMDMA_S0_CURR_ADDR)
+#define bfin_write_IMDMA_S0_CURR_ADDR(val)   bfin_write32(IMDMA_S0_CURR_ADDR,val)
+#define bfin_read_IMDMA_S0_CURR_X_COUNT()    bfin_read16(IMDMA_S0_CURR_X_COUNT)
+#define bfin_write_IMDMA_S0_CURR_X_COUNT(val) bfin_write16(IMDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_S0_CURR_Y_COUNT()    bfin_read16(IMDMA_S0_CURR_Y_COUNT)
+#define bfin_write_IMDMA_S0_CURR_Y_COUNT(val) bfin_write16(IMDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_S0_IRQ_STATUS()      bfin_read16(IMDMA_S0_IRQ_STATUS)
+#define bfin_write_IMDMA_S0_IRQ_STATUS(val)  bfin_write16(IMDMA_S0_IRQ_STATUS,val)
+#define bfin_read_IMDMA_D1_CONFIG()          bfin_read16(IMDMA_D1_CONFIG)
+#define bfin_write_IMDMA_D1_CONFIG(val)      bfin_write16(IMDMA_D1_CONFIG,val)
+#define bfin_read_IMDMA_D1_NEXT_DESC_PTR()   bfin_read32(IMDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_D1_NEXT_DESC_PTR(val) bfin_write32(IMDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_D1_START_ADDR()      bfin_read32(IMDMA_D1_START_ADDR)
+#define bfin_write_IMDMA_D1_START_ADDR(val)  bfin_write32(IMDMA_D1_START_ADDR,val)
+#define bfin_read_IMDMA_D1_X_COUNT()         bfin_read16(IMDMA_D1_X_COUNT)
+#define bfin_write_IMDMA_D1_X_COUNT(val)     bfin_write16(IMDMA_D1_X_COUNT,val)
+#define bfin_read_IMDMA_D1_Y_COUNT()         bfin_read16(IMDMA_D1_Y_COUNT)
+#define bfin_write_IMDMA_D1_Y_COUNT(val)     bfin_write16(IMDMA_D1_Y_COUNT,val)
+#define bfin_read_IMDMA_D1_X_MODIFY()        bfin_read16(IMDMA_D1_X_MODIFY)
+#define bfin_write_IMDMA_D1_X_MODIFY(val)    bfin_write16(IMDMA_D1_X_MODIFY,val)
+#define bfin_read_IMDMA_D1_Y_MODIFY()        bfin_read16(IMDMA_D1_Y_MODIFY)
+#define bfin_write_IMDMA_D1_Y_MODIFY(val)    bfin_write16(IMDMA_D1_Y_MODIFY,val)
+#define bfin_read_IMDMA_D1_CURR_DESC_PTR()   bfin_read32(IMDMA_D1_CURR_DESC_PTR)
+#define bfin_write_IMDMA_D1_CURR_DESC_PTR(val) bfin_write32(IMDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_D1_CURR_ADDR()       bfin_read32(IMDMA_D1_CURR_ADDR)
+#define bfin_write_IMDMA_D1_CURR_ADDR(val)   bfin_write32(IMDMA_D1_CURR_ADDR,val)
+#define bfin_read_IMDMA_D1_CURR_X_COUNT()    bfin_read16(IMDMA_D1_CURR_X_COUNT)
+#define bfin_write_IMDMA_D1_CURR_X_COUNT(val) bfin_write16(IMDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_D1_CURR_Y_COUNT()    bfin_read16(IMDMA_D1_CURR_Y_COUNT)
+#define bfin_write_IMDMA_D1_CURR_Y_COUNT(val) bfin_write16(IMDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_D1_IRQ_STATUS()      bfin_read16(IMDMA_D1_IRQ_STATUS)
+#define bfin_write_IMDMA_D1_IRQ_STATUS(val)  bfin_write16(IMDMA_D1_IRQ_STATUS,val)
+#define bfin_read_IMDMA_S1_CONFIG()          bfin_read16(IMDMA_S1_CONFIG)
+#define bfin_write_IMDMA_S1_CONFIG(val)      bfin_write16(IMDMA_S1_CONFIG,val)
+#define bfin_read_IMDMA_S1_NEXT_DESC_PTR()   bfin_read32(IMDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_S1_NEXT_DESC_PTR(val) bfin_write32(IMDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_S1_START_ADDR()      bfin_read32(IMDMA_S1_START_ADDR)
+#define bfin_write_IMDMA_S1_START_ADDR(val)  bfin_write32(IMDMA_S1_START_ADDR,val)
+#define bfin_read_IMDMA_S1_X_COUNT()         bfin_read16(IMDMA_S1_X_COUNT)
+#define bfin_write_IMDMA_S1_X_COUNT(val)     bfin_write16(IMDMA_S1_X_COUNT,val)
+#define bfin_read_IMDMA_S1_Y_COUNT()         bfin_read16(IMDMA_S1_Y_COUNT)
+#define bfin_write_IMDMA_S1_Y_COUNT(val)     bfin_write16(IMDMA_S1_Y_COUNT,val)
+#define bfin_read_IMDMA_S1_X_MODIFY()        bfin_read16(IMDMA_S1_X_MODIFY)
+#define bfin_write_IMDMA_S1_X_MODIFY(val)    bfin_write16(IMDMA_S1_X_MODIFY,val)
+#define bfin_read_IMDMA_S1_Y_MODIFY()        bfin_read16(IMDMA_S1_Y_MODIFY)
+#define bfin_write_IMDMA_S1_Y_MODIFY(val)    bfin_write16(IMDMA_S1_Y_MODIFY,val)
+#define bfin_read_IMDMA_S1_CURR_DESC_PTR()   bfin_read32(IMDMA_S1_CURR_DESC_PTR)
+#define bfin_write_IMDMA_S1_CURR_DESC_PTR(val) bfin_write32(IMDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_S1_CURR_ADDR()       bfin_read32(IMDMA_S1_CURR_ADDR)
+#define bfin_write_IMDMA_S1_CURR_ADDR(val)   bfin_write32(IMDMA_S1_CURR_ADDR,val)
+#define bfin_read_IMDMA_S1_CURR_X_COUNT()    bfin_read16(IMDMA_S1_CURR_X_COUNT)
+#define bfin_write_IMDMA_S1_CURR_X_COUNT(val) bfin_write16(IMDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_S1_CURR_Y_COUNT()    bfin_read16(IMDMA_S1_CURR_Y_COUNT)
+#define bfin_write_IMDMA_S1_CURR_Y_COUNT(val) bfin_write16(IMDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_S1_IRQ_STATUS()      bfin_read16(IMDMA_S1_IRQ_STATUS)
+#define bfin_write_IMDMA_S1_IRQ_STATUS(val)  bfin_write16(IMDMA_S1_IRQ_STATUS,val)
+
+#define bfin_read_MDMA_S0_CONFIG()  bfin_read_MDMA1_S0_CONFIG()
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write_MDMA1_S0_CONFIG(val)
+#define bfin_read_MDMA_S0_IRQ_STATUS()  bfin_read_MDMA1_S0_IRQ_STATUS()
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write_MDMA1_S0_IRQ_STATUS(val)
+#define bfin_read_MDMA_S0_X_MODIFY()  bfin_read_MDMA1_S0_X_MODIFY()
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write_MDMA1_S0_X_MODIFY(val)
+#define bfin_read_MDMA_S0_Y_MODIFY()  bfin_read_MDMA1_S0_Y_MODIFY()
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write_MDMA1_S0_Y_MODIFY(val)
+#define bfin_read_MDMA_S0_X_COUNT()  bfin_read_MDMA1_S0_X_COUNT()
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write_MDMA1_S0_X_COUNT(val)
+#define bfin_read_MDMA_S0_Y_COUNT()  bfin_read_MDMA1_S0_Y_COUNT()
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write_MDMA1_S0_Y_COUNT(val)
+#define bfin_read_MDMA_S0_START_ADDR()  bfin_read_MDMA1_S0_START_ADDR()
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write_MDMA1_S0_START_ADDR(val)
+#define bfin_read_MDMA_D0_CONFIG()  bfin_read_MDMA1_D0_CONFIG()
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write_MDMA1_D0_CONFIG(val)
+#define bfin_read_MDMA_D0_IRQ_STATUS()  bfin_read_MDMA1_D0_IRQ_STATUS()
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write_MDMA1_D0_IRQ_STATUS(val)
+#define bfin_read_MDMA_D0_X_MODIFY()  bfin_read_MDMA1_D0_X_MODIFY()
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write_MDMA1_D0_X_MODIFY(val)
+#define bfin_read_MDMA_D0_Y_MODIFY()  bfin_read_MDMA1_D0_Y_MODIFY()
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write_MDMA1_D0_Y_MODIFY(val)
+#define bfin_read_MDMA_D0_X_COUNT()  bfin_read_MDMA1_D0_X_COUNT()
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write_MDMA1_D0_X_COUNT(val)
+#define bfin_read_MDMA_D0_Y_COUNT()  bfin_read_MDMA1_D0_Y_COUNT()
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write_MDMA1_D0_Y_COUNT(val)
+#define bfin_read_MDMA_D0_START_ADDR()  bfin_read_MDMA1_D0_START_ADDR()
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA1_D0_START_ADDR(val)
+
+#endif				/* _CDEF_BF561_H */
diff --git a/include/asm-blackfin/mach-bf561/defBF561.h b/include/asm-blackfin/mach-bf561/defBF561.h
new file mode 100644
index 0000000..a6de4c6
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/defBF561.h
@@ -0,0 +1,1717 @@
+
+/*
+ * File:         include/asm-blackfin/mach-bf561/defBF561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DEF_BF561_H
+#define _DEF_BF561_H
+/*
+#if !defined(__ADSPBF561__)
+#warning defBF561.h should only be included for BF561 chip.
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+
+#define PLL_CTL                0xFFC00000	/* PLL Control register (16-bit) */
+#define PLL_DIV			        0xFFC00004	/* PLL Divide Register (16-bit) */
+#define VR_CTL			        0xFFC00008	/* Voltage Regulator Control Register (16-bit) */
+#define PLL_STAT               0xFFC0000C	/* PLL Status register (16-bit) */
+#define PLL_LOCKCNT            0xFFC00010	/* PLL Lock Count register (16-bit) */
+#define CHIPID                 0xFFC00014       /* Chip ID Register */
+
+/* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
+#define SICA_SWRST              0xFFC00100	/* Software Reset register */
+#define SICA_SYSCR              0xFFC00104	/* System Reset Configuration register */
+#define SICA_RVECT              0xFFC00108	/* SIC Reset Vector Address Register */
+#define SICA_IMASK              0xFFC0010C	/* SIC Interrupt Mask register 0 - hack to fix old tests */
+#define SICA_IMASK0             0xFFC0010C	/* SIC Interrupt Mask register 0 */
+#define SICA_IMASK1             0xFFC00110	/* SIC Interrupt Mask register 1 */
+#define SICA_IAR0               0xFFC00124	/* SIC Interrupt Assignment Register 0 */
+#define SICA_IAR1               0xFFC00128	/* SIC Interrupt Assignment Register 1 */
+#define SICA_IAR2               0xFFC0012C	/* SIC Interrupt Assignment Register 2 */
+#define SICA_IAR3               0xFFC00130	/* SIC Interrupt Assignment Register 3 */
+#define SICA_IAR4               0xFFC00134	/* SIC Interrupt Assignment Register 4 */
+#define SICA_IAR5               0xFFC00138	/* SIC Interrupt Assignment Register 5 */
+#define SICA_IAR6               0xFFC0013C	/* SIC Interrupt Assignment Register 6 */
+#define SICA_IAR7               0xFFC00140	/* SIC Interrupt Assignment Register 7 */
+#define SICA_ISR0               0xFFC00114	/* SIC Interrupt Status register 0 */
+#define SICA_ISR1               0xFFC00118	/* SIC Interrupt Status register 1 */
+#define SICA_IWR0               0xFFC0011C	/* SIC Interrupt Wakeup-Enable register 0 */
+#define SICA_IWR1               0xFFC00120	/* SIC Interrupt Wakeup-Enable register 1 */
+
+/* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
+#define SICB_SWRST              0xFFC01100	/* reserved */
+#define SICB_SYSCR              0xFFC01104	/* reserved */
+#define SICB_RVECT              0xFFC01108	/* SIC Reset Vector Address Register */
+#define SICB_IMASK0             0xFFC0110C	/* SIC Interrupt Mask register 0 */
+#define SICB_IMASK1             0xFFC01110	/* SIC Interrupt Mask register 1 */
+#define SICB_IAR0               0xFFC01124	/* SIC Interrupt Assignment Register 0 */
+#define SICB_IAR1               0xFFC01128	/* SIC Interrupt Assignment Register 1 */
+#define SICB_IAR2               0xFFC0112C	/* SIC Interrupt Assignment Register 2 */
+#define SICB_IAR3               0xFFC01130	/* SIC Interrupt Assignment Register 3 */
+#define SICB_IAR4               0xFFC01134	/* SIC Interrupt Assignment Register 4 */
+#define SICB_IAR5               0xFFC01138	/* SIC Interrupt Assignment Register 5 */
+#define SICB_IAR6               0xFFC0113C	/* SIC Interrupt Assignment Register 6 */
+#define SICB_IAR7               0xFFC01140	/* SIC Interrupt Assignment Register 7 */
+#define SICB_ISR0               0xFFC01114	/* SIC Interrupt Status register 0 */
+#define SICB_ISR1               0xFFC01118	/* SIC Interrupt Status register 1 */
+#define SICB_IWR0               0xFFC0111C	/* SIC Interrupt Wakeup-Enable register 0 */
+#define SICB_IWR1               0xFFC01120	/* SIC Interrupt Wakeup-Enable register 1 */
+
+/* Watchdog Timer registers for Core A (0xFFC0 0200-0xFFC0 02FF) */
+#define WDOGA_CTL 				0xFFC00200	/* Watchdog Control register */
+#define WDOGA_CNT 				0xFFC00204	/* Watchdog Count register */
+#define WDOGA_STAT 				0xFFC00208	/* Watchdog Status register */
+
+/* Watchdog Timer registers for Core B (0xFFC0 1200-0xFFC0 12FF) */
+#define WDOGB_CTL 				0xFFC01200	/* Watchdog Control register */
+#define WDOGB_CNT 				0xFFC01204	/* Watchdog Count register */
+#define WDOGB_STAT 				0xFFC01208	/* Watchdog Status register */
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define UART_THR             	0xFFC00400	/* Transmit Holding register */
+#define UART_RBR             	0xFFC00400	/* Receive Buffer register */
+#define UART_DLL              	0xFFC00400	/* Divisor Latch (Low-Byte) */
+#define UART_IER              	0xFFC00404	/* Interrupt Enable Register */
+#define UART_DLH              	0xFFC00404	/* Divisor Latch (High-Byte) */
+#define UART_IIR              	0xFFC00408	/* Interrupt Identification Register */
+#define UART_LCR              	0xFFC0040C	/* Line Control Register */
+#define UART_MCR			 	0xFFC00410	/* Modem Control Register */
+#define UART_LSR              	0xFFC00414	/* Line Status Register */
+#define UART_MSR            	0xFFC00418	/* Modem Status Register */
+#define UART_SCR              	0xFFC0041C	/* SCR Scratch Register */
+#define UART_GCTL      	      	0xFFC00424	/* Global Control Register */
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define SPI_CTL               		0xFFC00500	/* SPI Control Register */
+#define SPI_FLG               		0xFFC00504	/* SPI Flag register */
+#define SPI_STAT              		0xFFC00508	/* SPI Status register */
+#define SPI_TDBR              		0xFFC0050C	/* SPI Transmit Data Buffer Register */
+#define SPI_RDBR              		0xFFC00510	/* SPI Receive Data Buffer Register */
+#define SPI_BAUD              		0xFFC00514	/* SPI Baud rate Register */
+#define SPI_SHADOW            		0xFFC00518	/* SPI_RDBR Shadow Register */
+
+/* Timer 0-7 registers (0xFFC0 0600-0xFFC0 06FF) */
+#define TIMER0_CONFIG 				0xFFC00600	/* Timer0 Configuration register */
+#define TIMER0_COUNTER 				0xFFC00604	/* Timer0 Counter register */
+#define TIMER0_PERIOD 				0xFFC00608	/* Timer0 Period register */
+#define TIMER0_WIDTH 				0xFFC0060C	/* Timer0 Width register */
+
+#define TIMER1_CONFIG 				0xFFC00610	/* Timer1 Configuration register */
+#define TIMER1_COUNTER 				0xFFC00614	/* Timer1 Counter register */
+#define TIMER1_PERIOD 				0xFFC00618	/* Timer1 Period register */
+#define TIMER1_WIDTH 				0xFFC0061C	/* Timer1 Width register */
+
+#define TIMER2_CONFIG 				0xFFC00620	/* Timer2 Configuration register */
+#define TIMER2_COUNTER 				0xFFC00624	/* Timer2 Counter register */
+#define TIMER2_PERIOD 				0xFFC00628	/* Timer2 Period register */
+#define TIMER2_WIDTH 				0xFFC0062C	/* Timer2 Width register */
+
+#define TIMER3_CONFIG 				0xFFC00630	/* Timer3 Configuration register */
+#define TIMER3_COUNTER 				0xFFC00634	/* Timer3 Counter register */
+#define TIMER3_PERIOD 				0xFFC00638	/* Timer3 Period register */
+#define TIMER3_WIDTH 				0xFFC0063C	/* Timer3 Width register */
+
+#define TIMER4_CONFIG 				0xFFC00640	/* Timer4 Configuration register */
+#define TIMER4_COUNTER 				0xFFC00644	/* Timer4 Counter register */
+#define TIMER4_PERIOD 				0xFFC00648	/* Timer4 Period register */
+#define TIMER4_WIDTH 				0xFFC0064C	/* Timer4 Width register */
+
+#define TIMER5_CONFIG 				0xFFC00650	/* Timer5 Configuration register */
+#define TIMER5_COUNTER 				0xFFC00654	/* Timer5 Counter register */
+#define TIMER5_PERIOD 				0xFFC00658	/* Timer5 Period register */
+#define TIMER5_WIDTH 				0xFFC0065C	/* Timer5 Width register */
+
+#define TIMER6_CONFIG 				0xFFC00660	/* Timer6 Configuration register */
+#define TIMER6_COUNTER 				0xFFC00664	/* Timer6 Counter register */
+#define TIMER6_PERIOD 				0xFFC00668	/* Timer6 Period register */
+#define TIMER6_WIDTH 				0xFFC0066C	/* Timer6 Width register */
+
+#define TIMER7_CONFIG 				0xFFC00670	/* Timer7 Configuration register */
+#define TIMER7_COUNTER 				0xFFC00674	/* Timer7 Counter register */
+#define TIMER7_PERIOD 				0xFFC00678	/* Timer7 Period register */
+#define TIMER7_WIDTH 				0xFFC0067C	/* Timer7 Width register */
+
+#define TMRS8_ENABLE 				0xFFC00680	/* Timer Enable Register */
+#define TMRS8_DISABLE 				0xFFC00684	/* Timer Disable register */
+#define TMRS8_STATUS 				0xFFC00688	/* Timer Status register */
+
+/* Timer registers 8-11 (0xFFC0 1600-0xFFC0 16FF) */
+#define TIMER8_CONFIG 				0xFFC01600	/* Timer8 Configuration register */
+#define TIMER8_COUNTER 				0xFFC01604	/* Timer8 Counter register */
+#define TIMER8_PERIOD 				0xFFC01608	/* Timer8 Period register */
+#define TIMER8_WIDTH 				0xFFC0160C	/* Timer8 Width register */
+
+#define TIMER9_CONFIG 				0xFFC01610	/* Timer9 Configuration register */
+#define TIMER9_COUNTER 				0xFFC01614	/* Timer9 Counter register */
+#define TIMER9_PERIOD 				0xFFC01618	/* Timer9 Period register */
+#define TIMER9_WIDTH 				0xFFC0161C	/* Timer9 Width register */
+
+#define TIMER10_CONFIG 				0xFFC01620	/* Timer10 Configuration register */
+#define TIMER10_COUNTER 			0xFFC01624	/* Timer10 Counter register */
+#define TIMER10_PERIOD 				0xFFC01628	/* Timer10 Period register */
+#define TIMER10_WIDTH 				0xFFC0162C	/* Timer10 Width register */
+
+#define TIMER11_CONFIG 				0xFFC01630	/* Timer11 Configuration register */
+#define TIMER11_COUNTER 			0xFFC01634	/* Timer11 Counter register */
+#define TIMER11_PERIOD 				0xFFC01638	/* Timer11 Period register */
+#define TIMER11_WIDTH 				0xFFC0163C	/* Timer11 Width register */
+
+#define TMRS4_ENABLE 				0xFFC01640	/* Timer Enable Register */
+#define TMRS4_DISABLE 				0xFFC01644	/* Timer Disable register */
+#define TMRS4_STATUS 				0xFFC01648	/* Timer Status register */
+
+/* Programmable Flag 0 registers (0xFFC0 0700-0xFFC0 07FF) */
+#define FIO0_FLAG_D 				0xFFC00700	/* Flag Data register */
+#define FIO0_FLAG_C 				0xFFC00704	/* Flag Clear register */
+#define FIO0_FLAG_S 				0xFFC00708	/* Flag Set register */
+#define FIO0_FLAG_T 				0xFFC0070C	/* Flag Toggle register */
+#define FIO0_MASKA_D 				0xFFC00710	/* Flag Mask Interrupt A Data register */
+#define FIO0_MASKA_C 				0xFFC00714	/* Flag Mask Interrupt A Clear register */
+#define FIO0_MASKA_S 				0xFFC00718	/* Flag Mask Interrupt A Set register */
+#define FIO0_MASKA_T 				0xFFC0071C	/* Flag Mask Interrupt A Toggle register */
+#define FIO0_MASKB_D 				0xFFC00720	/* Flag Mask Interrupt B Data register */
+#define FIO0_MASKB_C 				0xFFC00724	/* Flag Mask Interrupt B Clear register */
+#define FIO0_MASKB_S 				0xFFC00728	/* Flag Mask Interrupt B Set register */
+#define FIO0_MASKB_T 				0xFFC0072C	/* Flag Mask Interrupt B Toggle register */
+#define FIO0_DIR 					0xFFC00730	/* Flag Direction register */
+#define FIO0_POLAR 					0xFFC00734	/* Flag Polarity register */
+#define FIO0_EDGE 					0xFFC00738	/* Flag Interrupt Sensitivity register */
+#define FIO0_BOTH 					0xFFC0073C	/* Flag Set on Both Edges register */
+#define FIO0_INEN 					0xFFC00740	/* Flag Input Enable register */
+
+/* Programmable Flag 1 registers (0xFFC0 1500-0xFFC0 15FF) */
+#define FIO1_FLAG_D 				0xFFC01500	/* Flag Data register (mask used to directly */
+#define FIO1_FLAG_C 				0xFFC01504	/* Flag Clear register */
+#define FIO1_FLAG_S 				0xFFC01508	/* Flag Set register */
+#define FIO1_FLAG_T 				0xFFC0150C	/* Flag Toggle register (mask used to */
+#define FIO1_MASKA_D 				0xFFC01510	/* Flag Mask Interrupt A Data register */
+#define FIO1_MASKA_C 				0xFFC01514	/* Flag Mask Interrupt A Clear register */
+#define FIO1_MASKA_S 				0xFFC01518	/* Flag Mask Interrupt A Set register */
+#define FIO1_MASKA_T 				0xFFC0151C	/* Flag Mask Interrupt A Toggle register */
+#define FIO1_MASKB_D 				0xFFC01520	/* Flag Mask Interrupt B Data register */
+#define FIO1_MASKB_C 				0xFFC01524	/* Flag Mask Interrupt B Clear register */
+#define FIO1_MASKB_S 				0xFFC01528	/* Flag Mask Interrupt B Set register */
+#define FIO1_MASKB_T 				0xFFC0152C	/* Flag Mask Interrupt B Toggle register */
+#define FIO1_DIR 					0xFFC01530	/* Flag Direction register */
+#define FIO1_POLAR 					0xFFC01534	/* Flag Polarity register */
+#define FIO1_EDGE 					0xFFC01538	/* Flag Interrupt Sensitivity register */
+#define FIO1_BOTH 					0xFFC0153C	/* Flag Set on Both Edges register */
+#define FIO1_INEN 					0xFFC01540	/* Flag Input Enable register */
+
+/* Programmable Flag registers (0xFFC0 1700-0xFFC0 17FF) */
+#define FIO2_FLAG_D 				0xFFC01700	/* Flag Data register (mask used to directly */
+#define FIO2_FLAG_C 				0xFFC01704	/* Flag Clear register */
+#define FIO2_FLAG_S 				0xFFC01708	/* Flag Set register */
+#define FIO2_FLAG_T 				0xFFC0170C	/* Flag Toggle register (mask used to */
+#define FIO2_MASKA_D 				0xFFC01710	/* Flag Mask Interrupt A Data register */
+#define FIO2_MASKA_C 				0xFFC01714	/* Flag Mask Interrupt A Clear register */
+#define FIO2_MASKA_S 				0xFFC01718	/* Flag Mask Interrupt A Set register */
+#define FIO2_MASKA_T 				0xFFC0171C	/* Flag Mask Interrupt A Toggle register */
+#define FIO2_MASKB_D 				0xFFC01720	/* Flag Mask Interrupt B Data register */
+#define FIO2_MASKB_C 				0xFFC01724	/* Flag Mask Interrupt B Clear register */
+#define FIO2_MASKB_S 				0xFFC01728	/* Flag Mask Interrupt B Set register */
+#define FIO2_MASKB_T 				0xFFC0172C	/* Flag Mask Interrupt B Toggle register */
+#define FIO2_DIR 					0xFFC01730	/* Flag Direction register */
+#define FIO2_POLAR 					0xFFC01734	/* Flag Polarity register */
+#define FIO2_EDGE 					0xFFC01738	/* Flag Interrupt Sensitivity register */
+#define FIO2_BOTH 					0xFFC0173C	/* Flag Set on Both Edges register */
+#define FIO2_INEN 					0xFFC01740	/* Flag Input Enable register */
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define SPORT0_TCR1     	 	0xFFC00800	/* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_TCR2      	 	0xFFC00804	/* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_TCLKDIV        		0xFFC00808	/* SPORT0 Transmit Clock Divider */
+#define SPORT0_TFSDIV          		0xFFC0080C	/* SPORT0 Transmit Frame Sync Divider */
+#define SPORT0_TX	             	0xFFC00810	/* SPORT0 TX Data Register */
+#define SPORT0_RX	            	0xFFC00818	/* SPORT0 RX Data Register */
+#define SPORT0_RCR1      	 		0xFFC00820	/* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_RCR2      	 		0xFFC00824	/* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_RCLKDIV        		0xFFC00828	/* SPORT0 Receive Clock Divider */
+#define SPORT0_RFSDIV          		0xFFC0082C	/* SPORT0 Receive Frame Sync Divider */
+#define SPORT0_STAT            		0xFFC00830	/* SPORT0 Status Register */
+#define SPORT0_CHNL            		0xFFC00834	/* SPORT0 Current Channel Register */
+#define SPORT0_MCMC1           		0xFFC00838	/* SPORT0 Multi-Channel Configuration Register 1 */
+#define SPORT0_MCMC2           		0xFFC0083C	/* SPORT0 Multi-Channel Configuration Register 2 */
+#define SPORT0_MTCS0           		0xFFC00840	/* SPORT0 Multi-Channel Transmit Select Register 0 */
+#define SPORT0_MTCS1           		0xFFC00844	/* SPORT0 Multi-Channel Transmit Select Register 1 */
+#define SPORT0_MTCS2           		0xFFC00848	/* SPORT0 Multi-Channel Transmit Select Register 2 */
+#define SPORT0_MTCS3           		0xFFC0084C	/* SPORT0 Multi-Channel Transmit Select Register 3 */
+#define SPORT0_MRCS0           		0xFFC00850	/* SPORT0 Multi-Channel Receive Select Register 0 */
+#define SPORT0_MRCS1           		0xFFC00854	/* SPORT0 Multi-Channel Receive Select Register 1 */
+#define SPORT0_MRCS2           		0xFFC00858	/* SPORT0 Multi-Channel Receive Select Register 2 */
+#define SPORT0_MRCS3           		0xFFC0085C	/* SPORT0 Multi-Channel Receive Select Register 3 */
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define SPORT1_TCR1     	 		0xFFC00900	/* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_TCR2      	 		0xFFC00904	/* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_TCLKDIV        		0xFFC00908	/* SPORT1 Transmit Clock Divider */
+#define SPORT1_TFSDIV          		0xFFC0090C	/* SPORT1 Transmit Frame Sync Divider */
+#define SPORT1_TX	             	0xFFC00910	/* SPORT1 TX Data Register */
+#define SPORT1_RX	            	0xFFC00918	/* SPORT1 RX Data Register */
+#define SPORT1_RCR1      	 		0xFFC00920	/* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_RCR2      	 		0xFFC00924	/* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_RCLKDIV        		0xFFC00928	/* SPORT1 Receive Clock Divider */
+#define SPORT1_RFSDIV          		0xFFC0092C	/* SPORT1 Receive Frame Sync Divider */
+#define SPORT1_STAT            		0xFFC00930	/* SPORT1 Status Register */
+#define SPORT1_CHNL            		0xFFC00934	/* SPORT1 Current Channel Register */
+#define SPORT1_MCMC1           		0xFFC00938	/* SPORT1 Multi-Channel Configuration Register 1 */
+#define SPORT1_MCMC2           		0xFFC0093C	/* SPORT1 Multi-Channel Configuration Register 2 */
+#define SPORT1_MTCS0           		0xFFC00940	/* SPORT1 Multi-Channel Transmit Select Register 0 */
+#define SPORT1_MTCS1           		0xFFC00944	/* SPORT1 Multi-Channel Transmit Select Register 1 */
+#define SPORT1_MTCS2           		0xFFC00948	/* SPORT1 Multi-Channel Transmit Select Register 2 */
+#define SPORT1_MTCS3           		0xFFC0094C	/* SPORT1 Multi-Channel Transmit Select Register 3 */
+#define SPORT1_MRCS0           		0xFFC00950	/* SPORT1 Multi-Channel Receive Select Register 0 */
+#define SPORT1_MRCS1           		0xFFC00954	/* SPORT1 Multi-Channel Receive Select Register 1 */
+#define SPORT1_MRCS2           		0xFFC00958	/* SPORT1 Multi-Channel Receive Select Register 2 */
+#define SPORT1_MRCS3           		0xFFC0095C	/* SPORT1 Multi-Channel Receive Select Register 3 */
+
+/* Asynchronous Memory Controller - External Bus Interface Unit  */
+#define EBIU_AMGCTL					0xFFC00A00	/* Asynchronous Memory Global Control Register */
+#define EBIU_AMBCTL0				0xFFC00A04	/* Asynchronous Memory Bank Control Register 0 */
+#define EBIU_AMBCTL1				0xFFC00A08	/* Asynchronous Memory Bank Control Register 1 */
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define EBIU_SDGCTL					0xFFC00A10	/* SDRAM Global Control Register */
+#define EBIU_SDBCTL					0xFFC00A14	/* SDRAM Bank Control Register */
+#define EBIU_SDRRC 					0xFFC00A18	/* SDRAM Refresh Rate Control Register */
+#define EBIU_SDSTAT					0xFFC00A1C	/* SDRAM Status Register */
+
+/* Parallel Peripheral Interface (PPI) 0 registers (0xFFC0 1000-0xFFC0 10FF) */
+#define PPI0_CONTROL 				0xFFC01000	/* PPI0 Control register */
+#define PPI0_STATUS 				0xFFC01004	/* PPI0 Status register */
+#define PPI0_COUNT 					0xFFC01008	/* PPI0 Transfer Count register */
+#define PPI0_DELAY 					0xFFC0100C	/* PPI0 Delay Count register */
+#define PPI0_FRAME 					0xFFC01010	/* PPI0 Frame Length register */
+
+/*Parallel Peripheral Interface (PPI) 1 registers (0xFFC0 1300-0xFFC0 13FF) */
+#define PPI1_CONTROL 				0xFFC01300	/* PPI1 Control register */
+#define PPI1_STATUS 				0xFFC01304	/* PPI1 Status register */
+#define PPI1_COUNT 					0xFFC01308	/* PPI1 Transfer Count register */
+#define PPI1_DELAY 					0xFFC0130C	/* PPI1 Delay Count register */
+#define PPI1_FRAME 					0xFFC01310	/* PPI1 Frame Length register */
+
+/*DMA traffic control registers */
+#define	DMA1_TC_PER  0xFFC01B0C	/* Traffic control periods */
+#define	DMA1_TC_CNT  0xFFC01B10	/* Traffic control current counts */
+#define	DMA2_TC_PER  0xFFC00B0C	/* Traffic control periods */
+#define	DMA2_TC_CNT  0xFFC00B10	/* Traffic control current counts        */
+
+/* DMA1 Controller registers (0xFFC0 1C00-0xFFC0 1FFF) */
+#define DMA1_0_CONFIG 0xFFC01C08	/* DMA1 Channel 0 Configuration register */
+#define DMA1_0_NEXT_DESC_PTR 0xFFC01C00	/* DMA1 Channel 0 Next Descripter Ptr Reg */
+#define DMA1_0_START_ADDR 0xFFC01C04	/* DMA1 Channel 0 Start Address */
+#define DMA1_0_X_COUNT 0xFFC01C10	/* DMA1 Channel 0 Inner Loop Count */
+#define DMA1_0_Y_COUNT 0xFFC01C18	/* DMA1 Channel 0 Outer Loop Count */
+#define DMA1_0_X_MODIFY 0xFFC01C14	/* DMA1 Channel 0 Inner Loop Addr Increment */
+#define DMA1_0_Y_MODIFY 0xFFC01C1C	/* DMA1 Channel 0 Outer Loop Addr Increment */
+#define DMA1_0_CURR_DESC_PTR 0xFFC01C20	/* DMA1 Channel 0 Current Descriptor Pointer */
+#define DMA1_0_CURR_ADDR 0xFFC01C24	/* DMA1 Channel 0 Current Address Pointer */
+#define DMA1_0_CURR_X_COUNT 0xFFC01C30	/* DMA1 Channel 0 Current Inner Loop Count */
+#define DMA1_0_CURR_Y_COUNT 0xFFC01C38	/* DMA1 Channel 0 Current Outer Loop Count */
+#define DMA1_0_IRQ_STATUS 0xFFC01C28	/* DMA1 Channel 0 Interrupt/Status Register */
+#define DMA1_0_PERIPHERAL_MAP 0xFFC01C2C	/* DMA1 Channel 0 Peripheral Map Register */
+
+#define DMA1_1_CONFIG 0xFFC01C48	/* DMA1 Channel 1 Configuration register */
+#define DMA1_1_NEXT_DESC_PTR 0xFFC01C40	/* DMA1 Channel 1 Next Descripter Ptr Reg */
+#define DMA1_1_START_ADDR 0xFFC01C44	/* DMA1 Channel 1 Start Address */
+#define DMA1_1_X_COUNT 0xFFC01C50	/* DMA1 Channel 1 Inner Loop Count */
+#define DMA1_1_Y_COUNT 0xFFC01C58	/* DMA1 Channel 1 Outer Loop Count */
+#define DMA1_1_X_MODIFY 0xFFC01C54	/* DMA1 Channel 1 Inner Loop Addr Increment */
+#define DMA1_1_Y_MODIFY 0xFFC01C5C	/* DMA1 Channel 1 Outer Loop Addr Increment */
+#define DMA1_1_CURR_DESC_PTR 0xFFC01C60	/* DMA1 Channel 1 Current Descriptor Pointer */
+#define DMA1_1_CURR_ADDR 0xFFC01C64	/* DMA1 Channel 1 Current Address Pointer */
+#define DMA1_1_CURR_X_COUNT 0xFFC01C70	/* DMA1 Channel 1 Current Inner Loop Count */
+#define DMA1_1_CURR_Y_COUNT 0xFFC01C78	/* DMA1 Channel 1 Current Outer Loop Count */
+#define DMA1_1_IRQ_STATUS 0xFFC01C68	/* DMA1 Channel 1 Interrupt/Status Register */
+#define DMA1_1_PERIPHERAL_MAP 0xFFC01C6C	/* DMA1 Channel 1 Peripheral Map Register */
+
+#define DMA1_2_CONFIG 0xFFC01C88	/* DMA1 Channel 2 Configuration register */
+#define DMA1_2_NEXT_DESC_PTR 0xFFC01C80	/* DMA1 Channel 2 Next Descripter Ptr Reg */
+#define DMA1_2_START_ADDR 0xFFC01C84	/* DMA1 Channel 2 Start Address */
+#define DMA1_2_X_COUNT 0xFFC01C90	/* DMA1 Channel 2 Inner Loop Count */
+#define DMA1_2_Y_COUNT 0xFFC01C98	/* DMA1 Channel 2 Outer Loop Count */
+#define DMA1_2_X_MODIFY 0xFFC01C94	/* DMA1 Channel 2 Inner Loop Addr Increment */
+#define DMA1_2_Y_MODIFY 0xFFC01C9C	/* DMA1 Channel 2 Outer Loop Addr Increment */
+#define DMA1_2_CURR_DESC_PTR 0xFFC01CA0	/* DMA1 Channel 2 Current Descriptor Pointer */
+#define DMA1_2_CURR_ADDR 0xFFC01CA4	/* DMA1 Channel 2 Current Address Pointer */
+#define DMA1_2_CURR_X_COUNT 0xFFC01CB0	/* DMA1 Channel 2 Current Inner Loop Count */
+#define DMA1_2_CURR_Y_COUNT 0xFFC01CB8	/* DMA1 Channel 2 Current Outer Loop Count */
+#define DMA1_2_IRQ_STATUS 0xFFC01CA8	/* DMA1 Channel 2 Interrupt/Status Register */
+#define DMA1_2_PERIPHERAL_MAP 0xFFC01CAC	/* DMA1 Channel 2 Peripheral Map Register */
+
+#define DMA1_3_CONFIG 0xFFC01CC8	/* DMA1 Channel 3 Configuration register */
+#define DMA1_3_NEXT_DESC_PTR 0xFFC01CC0	/* DMA1 Channel 3 Next Descripter Ptr Reg */
+#define DMA1_3_START_ADDR 0xFFC01CC4	/* DMA1 Channel 3 Start Address */
+#define DMA1_3_X_COUNT 0xFFC01CD0	/* DMA1 Channel 3 Inner Loop Count */
+#define DMA1_3_Y_COUNT 0xFFC01CD8	/* DMA1 Channel 3 Outer Loop Count */
+#define DMA1_3_X_MODIFY 0xFFC01CD4	/* DMA1 Channel 3 Inner Loop Addr Increment */
+#define DMA1_3_Y_MODIFY 0xFFC01CDC	/* DMA1 Channel 3 Outer Loop Addr Increment */
+#define DMA1_3_CURR_DESC_PTR 0xFFC01CE0	/* DMA1 Channel 3 Current Descriptor Pointer */
+#define DMA1_3_CURR_ADDR 0xFFC01CE4	/* DMA1 Channel 3 Current Address Pointer */
+#define DMA1_3_CURR_X_COUNT 0xFFC01CF0	/* DMA1 Channel 3 Current Inner Loop Count */
+#define DMA1_3_CURR_Y_COUNT 0xFFC01CF8	/* DMA1 Channel 3 Current Outer Loop Count */
+#define DMA1_3_IRQ_STATUS 0xFFC01CE8	/* DMA1 Channel 3 Interrupt/Status Register */
+#define DMA1_3_PERIPHERAL_MAP 0xFFC01CEC	/* DMA1 Channel 3 Peripheral Map Register */
+
+#define DMA1_4_CONFIG 0xFFC01D08	/* DMA1 Channel 4 Configuration register */
+#define DMA1_4_NEXT_DESC_PTR 0xFFC01D00	/* DMA1 Channel 4 Next Descripter Ptr Reg */
+#define DMA1_4_START_ADDR 0xFFC01D04	/* DMA1 Channel 4 Start Address */
+#define DMA1_4_X_COUNT 0xFFC01D10	/* DMA1 Channel 4 Inner Loop Count */
+#define DMA1_4_Y_COUNT 0xFFC01D18	/* DMA1 Channel 4 Outer Loop Count */
+#define DMA1_4_X_MODIFY 0xFFC01D14	/* DMA1 Channel 4 Inner Loop Addr Increment */
+#define DMA1_4_Y_MODIFY 0xFFC01D1C	/* DMA1 Channel 4 Outer Loop Addr Increment */
+#define DMA1_4_CURR_DESC_PTR 0xFFC01D20	/* DMA1 Channel 4 Current Descriptor Pointer */
+#define DMA1_4_CURR_ADDR 0xFFC01D24	/* DMA1 Channel 4 Current Address Pointer */
+#define DMA1_4_CURR_X_COUNT 0xFFC01D30	/* DMA1 Channel 4 Current Inner Loop Count */
+#define DMA1_4_CURR_Y_COUNT 0xFFC01D38	/* DMA1 Channel 4 Current Outer Loop Count */
+#define DMA1_4_IRQ_STATUS 0xFFC01D28	/* DMA1 Channel 4 Interrupt/Status Register */
+#define DMA1_4_PERIPHERAL_MAP 0xFFC01D2C	/* DMA1 Channel 4 Peripheral Map Register */
+
+#define DMA1_5_CONFIG 0xFFC01D48	/* DMA1 Channel 5 Configuration register */
+#define DMA1_5_NEXT_DESC_PTR 0xFFC01D40	/* DMA1 Channel 5 Next Descripter Ptr Reg */
+#define DMA1_5_START_ADDR 0xFFC01D44	/* DMA1 Channel 5 Start Address */
+#define DMA1_5_X_COUNT 0xFFC01D50	/* DMA1 Channel 5 Inner Loop Count */
+#define DMA1_5_Y_COUNT 0xFFC01D58	/* DMA1 Channel 5 Outer Loop Count */
+#define DMA1_5_X_MODIFY 0xFFC01D54	/* DMA1 Channel 5 Inner Loop Addr Increment */
+#define DMA1_5_Y_MODIFY 0xFFC01D5C	/* DMA1 Channel 5 Outer Loop Addr Increment */
+#define DMA1_5_CURR_DESC_PTR 0xFFC01D60	/* DMA1 Channel 5 Current Descriptor Pointer */
+#define DMA1_5_CURR_ADDR 0xFFC01D64	/* DMA1 Channel 5 Current Address Pointer */
+#define DMA1_5_CURR_X_COUNT 0xFFC01D70	/* DMA1 Channel 5 Current Inner Loop Count */
+#define DMA1_5_CURR_Y_COUNT 0xFFC01D78	/* DMA1 Channel 5 Current Outer Loop Count */
+#define DMA1_5_IRQ_STATUS 0xFFC01D68	/* DMA1 Channel 5 Interrupt/Status Register */
+#define DMA1_5_PERIPHERAL_MAP 0xFFC01D6C	/* DMA1 Channel 5 Peripheral Map Register */
+
+#define DMA1_6_CONFIG 0xFFC01D88	/* DMA1 Channel 6 Configuration register */
+#define DMA1_6_NEXT_DESC_PTR 0xFFC01D80	/* DMA1 Channel 6 Next Descripter Ptr Reg */
+#define DMA1_6_START_ADDR 0xFFC01D84	/* DMA1 Channel 6 Start Address */
+#define DMA1_6_X_COUNT 0xFFC01D90	/* DMA1 Channel 6 Inner Loop Count */
+#define DMA1_6_Y_COUNT 0xFFC01D98	/* DMA1 Channel 6 Outer Loop Count */
+#define DMA1_6_X_MODIFY 0xFFC01D94	/* DMA1 Channel 6 Inner Loop Addr Increment */
+#define DMA1_6_Y_MODIFY 0xFFC01D9C	/* DMA1 Channel 6 Outer Loop Addr Increment */
+#define DMA1_6_CURR_DESC_PTR 0xFFC01DA0	/* DMA1 Channel 6 Current Descriptor Pointer */
+#define DMA1_6_CURR_ADDR 0xFFC01DA4	/* DMA1 Channel 6 Current Address Pointer */
+#define DMA1_6_CURR_X_COUNT 0xFFC01DB0	/* DMA1 Channel 6 Current Inner Loop Count */
+#define DMA1_6_CURR_Y_COUNT 0xFFC01DB8	/* DMA1 Channel 6 Current Outer Loop Count */
+#define DMA1_6_IRQ_STATUS 0xFFC01DA8	/* DMA1 Channel 6 Interrupt/Status Register */
+#define DMA1_6_PERIPHERAL_MAP 0xFFC01DAC	/* DMA1 Channel 6 Peripheral Map Register */
+
+#define DMA1_7_CONFIG 0xFFC01DC8	/* DMA1 Channel 7 Configuration register */
+#define DMA1_7_NEXT_DESC_PTR 0xFFC01DC0	/* DMA1 Channel 7 Next Descripter Ptr Reg */
+#define DMA1_7_START_ADDR 0xFFC01DC4	/* DMA1 Channel 7 Start Address */
+#define DMA1_7_X_COUNT 0xFFC01DD0	/* DMA1 Channel 7 Inner Loop Count */
+#define DMA1_7_Y_COUNT 0xFFC01DD8	/* DMA1 Channel 7 Outer Loop Count */
+#define DMA1_7_X_MODIFY 0xFFC01DD4	/* DMA1 Channel 7 Inner Loop Addr Increment */
+#define DMA1_7_Y_MODIFY 0xFFC01DDC	/* DMA1 Channel 7 Outer Loop Addr Increment */
+#define DMA1_7_CURR_DESC_PTR 0xFFC01DE0	/* DMA1 Channel 7 Current Descriptor Pointer */
+#define DMA1_7_CURR_ADDR 0xFFC01DE4	/* DMA1 Channel 7 Current Address Pointer */
+#define DMA1_7_CURR_X_COUNT 0xFFC01DF0	/* DMA1 Channel 7 Current Inner Loop Count */
+#define DMA1_7_CURR_Y_COUNT 0xFFC01DF8	/* DMA1 Channel 7 Current Outer Loop Count */
+#define DMA1_7_IRQ_STATUS 0xFFC01DE8	/* DMA1 Channel 7 Interrupt/Status Register */
+#define DMA1_7_PERIPHERAL_MAP 0xFFC01DEC	/* DMA1 Channel 7 Peripheral Map Register */
+
+#define DMA1_8_CONFIG 0xFFC01E08	/* DMA1 Channel 8 Configuration register */
+#define DMA1_8_NEXT_DESC_PTR 0xFFC01E00	/* DMA1 Channel 8 Next Descripter Ptr Reg */
+#define DMA1_8_START_ADDR 0xFFC01E04	/* DMA1 Channel 8 Start Address */
+#define DMA1_8_X_COUNT 0xFFC01E10	/* DMA1 Channel 8 Inner Loop Count */
+#define DMA1_8_Y_COUNT 0xFFC01E18	/* DMA1 Channel 8 Outer Loop Count */
+#define DMA1_8_X_MODIFY 0xFFC01E14	/* DMA1 Channel 8 Inner Loop Addr Increment */
+#define DMA1_8_Y_MODIFY 0xFFC01E1C	/* DMA1 Channel 8 Outer Loop Addr Increment */
+#define DMA1_8_CURR_DESC_PTR 0xFFC01E20	/* DMA1 Channel 8 Current Descriptor Pointer */
+#define DMA1_8_CURR_ADDR 0xFFC01E24	/* DMA1 Channel 8 Current Address Pointer */
+#define DMA1_8_CURR_X_COUNT 0xFFC01E30	/* DMA1 Channel 8 Current Inner Loop Count */
+#define DMA1_8_CURR_Y_COUNT 0xFFC01E38	/* DMA1 Channel 8 Current Outer Loop Count */
+#define DMA1_8_IRQ_STATUS 0xFFC01E28	/* DMA1 Channel 8 Interrupt/Status Register */
+#define DMA1_8_PERIPHERAL_MAP 0xFFC01E2C	/* DMA1 Channel 8 Peripheral Map Register */
+
+#define DMA1_9_CONFIG 0xFFC01E48	/* DMA1 Channel 9 Configuration register */
+#define DMA1_9_NEXT_DESC_PTR 0xFFC01E40	/* DMA1 Channel 9 Next Descripter Ptr Reg */
+#define DMA1_9_START_ADDR 0xFFC01E44	/* DMA1 Channel 9 Start Address */
+#define DMA1_9_X_COUNT 0xFFC01E50	/* DMA1 Channel 9 Inner Loop Count */
+#define DMA1_9_Y_COUNT 0xFFC01E58	/* DMA1 Channel 9 Outer Loop Count */
+#define DMA1_9_X_MODIFY 0xFFC01E54	/* DMA1 Channel 9 Inner Loop Addr Increment */
+#define DMA1_9_Y_MODIFY 0xFFC01E5C	/* DMA1 Channel 9 Outer Loop Addr Increment */
+#define DMA1_9_CURR_DESC_PTR 0xFFC01E60	/* DMA1 Channel 9 Current Descriptor Pointer */
+#define DMA1_9_CURR_ADDR 0xFFC01E64	/* DMA1 Channel 9 Current Address Pointer */
+#define DMA1_9_CURR_X_COUNT 0xFFC01E70	/* DMA1 Channel 9 Current Inner Loop Count */
+#define DMA1_9_CURR_Y_COUNT 0xFFC01E78	/* DMA1 Channel 9 Current Outer Loop Count */
+#define DMA1_9_IRQ_STATUS 0xFFC01E68	/* DMA1 Channel 9 Interrupt/Status Register */
+#define DMA1_9_PERIPHERAL_MAP 0xFFC01E6C	/* DMA1 Channel 9 Peripheral Map Register */
+
+#define DMA1_10_CONFIG 0xFFC01E88	/* DMA1 Channel 10 Configuration register */
+#define DMA1_10_NEXT_DESC_PTR 0xFFC01E80	/* DMA1 Channel 10 Next Descripter Ptr Reg */
+#define DMA1_10_START_ADDR 0xFFC01E84	/* DMA1 Channel 10 Start Address */
+#define DMA1_10_X_COUNT 0xFFC01E90	/* DMA1 Channel 10 Inner Loop Count */
+#define DMA1_10_Y_COUNT 0xFFC01E98	/* DMA1 Channel 10 Outer Loop Count */
+#define DMA1_10_X_MODIFY 0xFFC01E94	/* DMA1 Channel 10 Inner Loop Addr Increment */
+#define DMA1_10_Y_MODIFY 0xFFC01E9C	/* DMA1 Channel 10 Outer Loop Addr Increment */
+#define DMA1_10_CURR_DESC_PTR 0xFFC01EA0	/* DMA1 Channel 10 Current Descriptor Pointer */
+#define DMA1_10_CURR_ADDR 0xFFC01EA4	/* DMA1 Channel 10 Current Address Pointer */
+#define DMA1_10_CURR_X_COUNT 0xFFC01EB0	/* DMA1 Channel 10 Current Inner Loop Count */
+#define DMA1_10_CURR_Y_COUNT 0xFFC01EB8	/* DMA1 Channel 10 Current Outer Loop Count */
+#define DMA1_10_IRQ_STATUS 0xFFC01EA8	/* DMA1 Channel 10 Interrupt/Status Register */
+#define DMA1_10_PERIPHERAL_MAP 0xFFC01EAC	/* DMA1 Channel 10 Peripheral Map Register */
+
+#define DMA1_11_CONFIG 0xFFC01EC8	/* DMA1 Channel 11 Configuration register */
+#define DMA1_11_NEXT_DESC_PTR 0xFFC01EC0	/* DMA1 Channel 11 Next Descripter Ptr Reg */
+#define DMA1_11_START_ADDR 0xFFC01EC4	/* DMA1 Channel 11 Start Address */
+#define DMA1_11_X_COUNT 0xFFC01ED0	/* DMA1 Channel 11 Inner Loop Count */
+#define DMA1_11_Y_COUNT 0xFFC01ED8	/* DMA1 Channel 11 Outer Loop Count */
+#define DMA1_11_X_MODIFY 0xFFC01ED4	/* DMA1 Channel 11 Inner Loop Addr Increment */
+#define DMA1_11_Y_MODIFY 0xFFC01EDC	/* DMA1 Channel 11 Outer Loop Addr Increment */
+#define DMA1_11_CURR_DESC_PTR 0xFFC01EE0	/* DMA1 Channel 11 Current Descriptor Pointer */
+#define DMA1_11_CURR_ADDR 0xFFC01EE4	/* DMA1 Channel 11 Current Address Pointer */
+#define DMA1_11_CURR_X_COUNT 0xFFC01EF0	/* DMA1 Channel 11 Current Inner Loop Count */
+#define DMA1_11_CURR_Y_COUNT 0xFFC01EF8	/* DMA1 Channel 11 Current Outer Loop Count */
+#define DMA1_11_IRQ_STATUS 0xFFC01EE8	/* DMA1 Channel 11 Interrupt/Status Register */
+#define DMA1_11_PERIPHERAL_MAP 0xFFC01EEC	/* DMA1 Channel 11 Peripheral Map Register */
+
+/* Memory DMA1 Controller registers (0xFFC0 1E80-0xFFC0 1FFF) */
+#define MDMA1_D0_CONFIG 0xFFC01F08	/*MemDMA1 Stream 0 Destination Configuration */
+#define MDMA1_D0_NEXT_DESC_PTR 0xFFC01F00	/*MemDMA1 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA1_D0_START_ADDR 0xFFC01F04	/*MemDMA1 Stream 0 Destination Start Address */
+#define MDMA1_D0_X_COUNT 0xFFC01F10	/*MemDMA1 Stream 0 Destination Inner-Loop Count */
+#define MDMA1_D0_Y_COUNT 0xFFC01F18	/*MemDMA1 Stream 0 Destination Outer-Loop Count */
+#define MDMA1_D0_X_MODIFY 0xFFC01F14	/*MemDMA1 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA1_D0_Y_MODIFY 0xFFC01F1C	/*MemDMA1 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA1_D0_CURR_DESC_PTR 0xFFC01F20	/*MemDMA1 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA1_D0_CURR_ADDR 0xFFC01F24	/*MemDMA1 Stream 0 Destination Current Address */
+#define MDMA1_D0_CURR_X_COUNT 0xFFC01F30	/*MemDMA1 Stream 0 Dest Current Inner-Loop Count */
+#define MDMA1_D0_CURR_Y_COUNT 0xFFC01F38	/*MemDMA1 Stream 0 Dest Current Outer-Loop Count */
+#define MDMA1_D0_IRQ_STATUS 0xFFC01F28	/*MemDMA1 Stream 0 Destination Interrupt/Status */
+#define MDMA1_D0_PERIPHERAL_MAP 0xFFC01F2C	/*MemDMA1 Stream 0 Destination Peripheral Map */
+
+#define MDMA1_S0_CONFIG 0xFFC01F48	/*MemDMA1 Stream 0 Source Configuration */
+#define MDMA1_S0_NEXT_DESC_PTR 0xFFC01F40	/*MemDMA1 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA1_S0_START_ADDR 0xFFC01F44	/*MemDMA1 Stream 0 Source Start Address */
+#define MDMA1_S0_X_COUNT 0xFFC01F50	/*MemDMA1 Stream 0 Source Inner-Loop Count */
+#define MDMA1_S0_Y_COUNT 0xFFC01F58	/*MemDMA1 Stream 0 Source Outer-Loop Count */
+#define MDMA1_S0_X_MODIFY 0xFFC01F54	/*MemDMA1 Stream 0 Source Inner-Loop Address-Increment */
+#define MDMA1_S0_Y_MODIFY 0xFFC01F5C	/*MemDMA1 Stream 0 Source Outer-Loop Address-Increment */
+#define MDMA1_S0_CURR_DESC_PTR 0xFFC01F60	/*MemDMA1 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA1_S0_CURR_ADDR 0xFFC01F64	/*MemDMA1 Stream 0 Source Current Address */
+#define MDMA1_S0_CURR_X_COUNT 0xFFC01F70	/*MemDMA1 Stream 0 Source Current Inner-Loop Count */
+#define MDMA1_S0_CURR_Y_COUNT 0xFFC01F78	/*MemDMA1 Stream 0 Source Current Outer-Loop Count */
+#define MDMA1_S0_IRQ_STATUS 0xFFC01F68	/*MemDMA1 Stream 0 Source Interrupt/Status */
+#define MDMA1_S0_PERIPHERAL_MAP 0xFFC01F6C	/*MemDMA1 Stream 0 Source Peripheral Map */
+
+#define MDMA1_D1_CONFIG 0xFFC01F88	/*MemDMA1 Stream 1 Destination Configuration */
+#define MDMA1_D1_NEXT_DESC_PTR 0xFFC01F80	/*MemDMA1 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA1_D1_START_ADDR 0xFFC01F84	/*MemDMA1 Stream 1 Destination Start Address */
+#define MDMA1_D1_X_COUNT 0xFFC01F90	/*MemDMA1 Stream 1 Destination Inner-Loop Count */
+#define MDMA1_D1_Y_COUNT 0xFFC01F98	/*MemDMA1 Stream 1 Destination Outer-Loop Count */
+#define MDMA1_D1_X_MODIFY 0xFFC01F94	/*MemDMA1 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA1_D1_Y_MODIFY 0xFFC01F9C	/*MemDMA1 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA1_D1_CURR_DESC_PTR 0xFFC01FA0	/*MemDMA1 Stream 1 Dest Current Descriptor Ptr reg */
+#define MDMA1_D1_CURR_ADDR 0xFFC01FA4	/*MemDMA1 Stream 1 Dest Current Address */
+#define MDMA1_D1_CURR_X_COUNT 0xFFC01FB0	/*MemDMA1 Stream 1 Dest Current Inner-Loop Count */
+#define MDMA1_D1_CURR_Y_COUNT 0xFFC01FB8	/*MemDMA1 Stream 1 Dest Current Outer-Loop Count */
+#define MDMA1_D1_IRQ_STATUS 0xFFC01FA8	/*MemDMA1 Stream 1 Dest Interrupt/Status */
+#define MDMA1_D1_PERIPHERAL_MAP 0xFFC01FAC	/*MemDMA1 Stream 1 Dest Peripheral Map */
+
+#define MDMA1_S1_CONFIG 0xFFC01FC8	/*MemDMA1 Stream 1 Source Configuration */
+#define MDMA1_S1_NEXT_DESC_PTR 0xFFC01FC0	/*MemDMA1 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA1_S1_START_ADDR 0xFFC01FC4	/*MemDMA1 Stream 1 Source Start Address */
+#define MDMA1_S1_X_COUNT 0xFFC01FD0	/*MemDMA1 Stream 1 Source Inner-Loop Count */
+#define MDMA1_S1_Y_COUNT 0xFFC01FD8	/*MemDMA1 Stream 1 Source Outer-Loop Count */
+#define MDMA1_S1_X_MODIFY 0xFFC01FD4	/*MemDMA1 Stream 1 Source Inner-Loop Address-Increment */
+#define MDMA1_S1_Y_MODIFY 0xFFC01FDC	/*MemDMA1 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA1_S1_CURR_DESC_PTR 0xFFC01FE0	/*MemDMA1 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA1_S1_CURR_ADDR 0xFFC01FE4	/*MemDMA1 Stream 1 Source Current Address */
+#define MDMA1_S1_CURR_X_COUNT 0xFFC01FF0	/*MemDMA1 Stream 1 Source Current Inner-Loop Count */
+#define MDMA1_S1_CURR_Y_COUNT 0xFFC01FF8	/*MemDMA1 Stream 1 Source Current Outer-Loop Count */
+#define MDMA1_S1_IRQ_STATUS 0xFFC01FE8	/*MemDMA1 Stream 1 Source Interrupt/Status */
+#define MDMA1_S1_PERIPHERAL_MAP 0xFFC01FEC	/*MemDMA1 Stream 1 Source Peripheral Map */
+
+/* DMA2 Controller registers (0xFFC0 0C00-0xFFC0 0DFF) */
+#define DMA2_0_CONFIG 0xFFC00C08	/* DMA2 Channel 0 Configuration register */
+#define DMA2_0_NEXT_DESC_PTR 0xFFC00C00	/* DMA2 Channel 0 Next Descripter Ptr Reg */
+#define DMA2_0_START_ADDR 0xFFC00C04	/* DMA2 Channel 0 Start Address */
+#define DMA2_0_X_COUNT 0xFFC00C10	/* DMA2 Channel 0 Inner Loop Count */
+#define DMA2_0_Y_COUNT 0xFFC00C18	/* DMA2 Channel 0 Outer Loop Count */
+#define DMA2_0_X_MODIFY 0xFFC00C14	/* DMA2 Channel 0 Inner Loop Addr Increment */
+#define DMA2_0_Y_MODIFY 0xFFC00C1C	/* DMA2 Channel 0 Outer Loop Addr Increment */
+#define DMA2_0_CURR_DESC_PTR 0xFFC00C20	/* DMA2 Channel 0 Current Descriptor Pointer */
+#define DMA2_0_CURR_ADDR 0xFFC00C24	/* DMA2 Channel 0 Current Address Pointer */
+#define DMA2_0_CURR_X_COUNT 0xFFC00C30	/* DMA2 Channel 0 Current Inner Loop Count */
+#define DMA2_0_CURR_Y_COUNT 0xFFC00C38	/* DMA2 Channel 0 Current Outer Loop Count */
+#define DMA2_0_IRQ_STATUS 0xFFC00C28	/* DMA2 Channel 0 Interrupt/Status Register */
+#define DMA2_0_PERIPHERAL_MAP 0xFFC00C2C	/* DMA2 Channel 0 Peripheral Map Register */
+
+#define DMA2_1_CONFIG 0xFFC00C48	/* DMA2 Channel 1 Configuration register */
+#define DMA2_1_NEXT_DESC_PTR 0xFFC00C40	/* DMA2 Channel 1 Next Descripter Ptr Reg */
+#define DMA2_1_START_ADDR 0xFFC00C44	/* DMA2 Channel 1 Start Address */
+#define DMA2_1_X_COUNT 0xFFC00C50	/* DMA2 Channel 1 Inner Loop Count */
+#define DMA2_1_Y_COUNT 0xFFC00C58	/* DMA2 Channel 1 Outer Loop Count */
+#define DMA2_1_X_MODIFY 0xFFC00C54	/* DMA2 Channel 1 Inner Loop Addr Increment */
+#define DMA2_1_Y_MODIFY 0xFFC00C5C	/* DMA2 Channel 1 Outer Loop Addr Increment */
+#define DMA2_1_CURR_DESC_PTR 0xFFC00C60	/* DMA2 Channel 1 Current Descriptor Pointer */
+#define DMA2_1_CURR_ADDR 0xFFC00C64	/* DMA2 Channel 1 Current Address Pointer */
+#define DMA2_1_CURR_X_COUNT 0xFFC00C70	/* DMA2 Channel 1 Current Inner Loop Count */
+#define DMA2_1_CURR_Y_COUNT 0xFFC00C78	/* DMA2 Channel 1 Current Outer Loop Count */
+#define DMA2_1_IRQ_STATUS 0xFFC00C68	/* DMA2 Channel 1 Interrupt/Status Register */
+#define DMA2_1_PERIPHERAL_MAP 0xFFC00C6C	/* DMA2 Channel 1 Peripheral Map Register */
+
+#define DMA2_2_CONFIG 0xFFC00C88	/* DMA2 Channel 2 Configuration register */
+#define DMA2_2_NEXT_DESC_PTR 0xFFC00C80	/* DMA2 Channel 2 Next Descripter Ptr Reg */
+#define DMA2_2_START_ADDR 0xFFC00C84	/* DMA2 Channel 2 Start Address */
+#define DMA2_2_X_COUNT 0xFFC00C90	/* DMA2 Channel 2 Inner Loop Count */
+#define DMA2_2_Y_COUNT 0xFFC00C98	/* DMA2 Channel 2 Outer Loop Count */
+#define DMA2_2_X_MODIFY 0xFFC00C94	/* DMA2 Channel 2 Inner Loop Addr Increment */
+#define DMA2_2_Y_MODIFY 0xFFC00C9C	/* DMA2 Channel 2 Outer Loop Addr Increment */
+#define DMA2_2_CURR_DESC_PTR 0xFFC00CA0	/* DMA2 Channel 2 Current Descriptor Pointer */
+#define DMA2_2_CURR_ADDR 0xFFC00CA4	/* DMA2 Channel 2 Current Address Pointer */
+#define DMA2_2_CURR_X_COUNT 0xFFC00CB0	/* DMA2 Channel 2 Current Inner Loop Count */
+#define DMA2_2_CURR_Y_COUNT 0xFFC00CB8	/* DMA2 Channel 2 Current Outer Loop Count */
+#define DMA2_2_IRQ_STATUS 0xFFC00CA8	/* DMA2 Channel 2 Interrupt/Status Register */
+#define DMA2_2_PERIPHERAL_MAP 0xFFC00CAC	/* DMA2 Channel 2 Peripheral Map Register */
+
+#define DMA2_3_CONFIG 0xFFC00CC8	/* DMA2 Channel 3 Configuration register */
+#define DMA2_3_NEXT_DESC_PTR 0xFFC00CC0	/* DMA2 Channel 3 Next Descripter Ptr Reg */
+#define DMA2_3_START_ADDR 0xFFC00CC4	/* DMA2 Channel 3 Start Address */
+#define DMA2_3_X_COUNT 0xFFC00CD0	/* DMA2 Channel 3 Inner Loop Count */
+#define DMA2_3_Y_COUNT 0xFFC00CD8	/* DMA2 Channel 3 Outer Loop Count */
+#define DMA2_3_X_MODIFY 0xFFC00CD4	/* DMA2 Channel 3 Inner Loop Addr Increment */
+#define DMA2_3_Y_MODIFY 0xFFC00CDC	/* DMA2 Channel 3 Outer Loop Addr Increment */
+#define DMA2_3_CURR_DESC_PTR 0xFFC00CE0	/* DMA2 Channel 3 Current Descriptor Pointer */
+#define DMA2_3_CURR_ADDR 0xFFC00CE4	/* DMA2 Channel 3 Current Address Pointer */
+#define DMA2_3_CURR_X_COUNT 0xFFC00CF0	/* DMA2 Channel 3 Current Inner Loop Count */
+#define DMA2_3_CURR_Y_COUNT 0xFFC00CF8	/* DMA2 Channel 3 Current Outer Loop Count */
+#define DMA2_3_IRQ_STATUS 0xFFC00CE8	/* DMA2 Channel 3 Interrupt/Status Register */
+#define DMA2_3_PERIPHERAL_MAP 0xFFC00CEC	/* DMA2 Channel 3 Peripheral Map Register */
+
+#define DMA2_4_CONFIG 0xFFC00D08	/* DMA2 Channel 4 Configuration register */
+#define DMA2_4_NEXT_DESC_PTR 0xFFC00D00	/* DMA2 Channel 4 Next Descripter Ptr Reg */
+#define DMA2_4_START_ADDR 0xFFC00D04	/* DMA2 Channel 4 Start Address */
+#define DMA2_4_X_COUNT 0xFFC00D10	/* DMA2 Channel 4 Inner Loop Count */
+#define DMA2_4_Y_COUNT 0xFFC00D18	/* DMA2 Channel 4 Outer Loop Count */
+#define DMA2_4_X_MODIFY 0xFFC00D14	/* DMA2 Channel 4 Inner Loop Addr Increment */
+#define DMA2_4_Y_MODIFY 0xFFC00D1C	/* DMA2 Channel 4 Outer Loop Addr Increment */
+#define DMA2_4_CURR_DESC_PTR 0xFFC00D20	/* DMA2 Channel 4 Current Descriptor Pointer */
+#define DMA2_4_CURR_ADDR 0xFFC00D24	/* DMA2 Channel 4 Current Address Pointer */
+#define DMA2_4_CURR_X_COUNT 0xFFC00D30	/* DMA2 Channel 4 Current Inner Loop Count */
+#define DMA2_4_CURR_Y_COUNT 0xFFC00D38	/* DMA2 Channel 4 Current Outer Loop Count */
+#define DMA2_4_IRQ_STATUS 0xFFC00D28	/* DMA2 Channel 4 Interrupt/Status Register */
+#define DMA2_4_PERIPHERAL_MAP 0xFFC00D2C	/* DMA2 Channel 4 Peripheral Map Register */
+
+#define DMA2_5_CONFIG 0xFFC00D48	/* DMA2 Channel 5 Configuration register */
+#define DMA2_5_NEXT_DESC_PTR 0xFFC00D40	/* DMA2 Channel 5 Next Descripter Ptr Reg */
+#define DMA2_5_START_ADDR 0xFFC00D44	/* DMA2 Channel 5 Start Address */
+#define DMA2_5_X_COUNT 0xFFC00D50	/* DMA2 Channel 5 Inner Loop Count */
+#define DMA2_5_Y_COUNT 0xFFC00D58	/* DMA2 Channel 5 Outer Loop Count */
+#define DMA2_5_X_MODIFY 0xFFC00D54	/* DMA2 Channel 5 Inner Loop Addr Increment */
+#define DMA2_5_Y_MODIFY 0xFFC00D5C	/* DMA2 Channel 5 Outer Loop Addr Increment */
+#define DMA2_5_CURR_DESC_PTR 0xFFC00D60	/* DMA2 Channel 5 Current Descriptor Pointer */
+#define DMA2_5_CURR_ADDR 0xFFC00D64	/* DMA2 Channel 5 Current Address Pointer */
+#define DMA2_5_CURR_X_COUNT 0xFFC00D70	/* DMA2 Channel 5 Current Inner Loop Count */
+#define DMA2_5_CURR_Y_COUNT 0xFFC00D78	/* DMA2 Channel 5 Current Outer Loop Count */
+#define DMA2_5_IRQ_STATUS 0xFFC00D68	/* DMA2 Channel 5 Interrupt/Status Register */
+#define DMA2_5_PERIPHERAL_MAP 0xFFC00D6C	/* DMA2 Channel 5 Peripheral Map Register */
+
+#define DMA2_6_CONFIG 0xFFC00D88	/* DMA2 Channel 6 Configuration register */
+#define DMA2_6_NEXT_DESC_PTR 0xFFC00D80	/* DMA2 Channel 6 Next Descripter Ptr Reg */
+#define DMA2_6_START_ADDR 0xFFC00D84	/* DMA2 Channel 6 Start Address */
+#define DMA2_6_X_COUNT 0xFFC00D90	/* DMA2 Channel 6 Inner Loop Count */
+#define DMA2_6_Y_COUNT 0xFFC00D98	/* DMA2 Channel 6 Outer Loop Count */
+#define DMA2_6_X_MODIFY 0xFFC00D94	/* DMA2 Channel 6 Inner Loop Addr Increment */
+#define DMA2_6_Y_MODIFY 0xFFC00D9C	/* DMA2 Channel 6 Outer Loop Addr Increment */
+#define DMA2_6_CURR_DESC_PTR 0xFFC00DA0	/* DMA2 Channel 6 Current Descriptor Pointer */
+#define DMA2_6_CURR_ADDR 0xFFC00DA4	/* DMA2 Channel 6 Current Address Pointer */
+#define DMA2_6_CURR_X_COUNT 0xFFC00DB0	/* DMA2 Channel 6 Current Inner Loop Count */
+#define DMA2_6_CURR_Y_COUNT 0xFFC00DB8	/* DMA2 Channel 6 Current Outer Loop Count */
+#define DMA2_6_IRQ_STATUS 0xFFC00DA8	/* DMA2 Channel 6 Interrupt/Status Register */
+#define DMA2_6_PERIPHERAL_MAP 0xFFC00DAC	/* DMA2 Channel 6 Peripheral Map Register */
+
+#define DMA2_7_CONFIG 0xFFC00DC8	/* DMA2 Channel 7 Configuration register */
+#define DMA2_7_NEXT_DESC_PTR 0xFFC00DC0	/* DMA2 Channel 7 Next Descripter Ptr Reg */
+#define DMA2_7_START_ADDR 0xFFC00DC4	/* DMA2 Channel 7 Start Address */
+#define DMA2_7_X_COUNT 0xFFC00DD0	/* DMA2 Channel 7 Inner Loop Count */
+#define DMA2_7_Y_COUNT 0xFFC00DD8	/* DMA2 Channel 7 Outer Loop Count */
+#define DMA2_7_X_MODIFY 0xFFC00DD4	/* DMA2 Channel 7 Inner Loop Addr Increment */
+#define DMA2_7_Y_MODIFY 0xFFC00DDC	/* DMA2 Channel 7 Outer Loop Addr Increment */
+#define DMA2_7_CURR_DESC_PTR 0xFFC00DE0	/* DMA2 Channel 7 Current Descriptor Pointer */
+#define DMA2_7_CURR_ADDR 0xFFC00DE4	/* DMA2 Channel 7 Current Address Pointer */
+#define DMA2_7_CURR_X_COUNT 0xFFC00DF0	/* DMA2 Channel 7 Current Inner Loop Count */
+#define DMA2_7_CURR_Y_COUNT 0xFFC00DF8	/* DMA2 Channel 7 Current Outer Loop Count */
+#define DMA2_7_IRQ_STATUS 0xFFC00DE8	/* DMA2 Channel 7 Interrupt/Status Register */
+#define DMA2_7_PERIPHERAL_MAP 0xFFC00DEC	/* DMA2 Channel 7 Peripheral Map Register */
+
+#define DMA2_8_CONFIG 0xFFC00E08	/* DMA2 Channel 8 Configuration register */
+#define DMA2_8_NEXT_DESC_PTR 0xFFC00E00	/* DMA2 Channel 8 Next Descripter Ptr Reg */
+#define DMA2_8_START_ADDR 0xFFC00E04	/* DMA2 Channel 8 Start Address */
+#define DMA2_8_X_COUNT 0xFFC00E10	/* DMA2 Channel 8 Inner Loop Count */
+#define DMA2_8_Y_COUNT 0xFFC00E18	/* DMA2 Channel 8 Outer Loop Count */
+#define DMA2_8_X_MODIFY 0xFFC00E14	/* DMA2 Channel 8 Inner Loop Addr Increment */
+#define DMA2_8_Y_MODIFY 0xFFC00E1C	/* DMA2 Channel 8 Outer Loop Addr Increment */
+#define DMA2_8_CURR_DESC_PTR 0xFFC00E20	/* DMA2 Channel 8 Current Descriptor Pointer */
+#define DMA2_8_CURR_ADDR 0xFFC00E24	/* DMA2 Channel 8 Current Address Pointer */
+#define DMA2_8_CURR_X_COUNT 0xFFC00E30	/* DMA2 Channel 8 Current Inner Loop Count */
+#define DMA2_8_CURR_Y_COUNT 0xFFC00E38	/* DMA2 Channel 8 Current Outer Loop Count */
+#define DMA2_8_IRQ_STATUS 0xFFC00E28	/* DMA2 Channel 8 Interrupt/Status Register */
+#define DMA2_8_PERIPHERAL_MAP 0xFFC00E2C	/* DMA2 Channel 8 Peripheral Map Register */
+
+#define DMA2_9_CONFIG 0xFFC00E48	/* DMA2 Channel 9 Configuration register */
+#define DMA2_9_NEXT_DESC_PTR 0xFFC00E40	/* DMA2 Channel 9 Next Descripter Ptr Reg */
+#define DMA2_9_START_ADDR 0xFFC00E44	/* DMA2 Channel 9 Start Address */
+#define DMA2_9_X_COUNT 0xFFC00E50	/* DMA2 Channel 9 Inner Loop Count */
+#define DMA2_9_Y_COUNT 0xFFC00E58	/* DMA2 Channel 9 Outer Loop Count */
+#define DMA2_9_X_MODIFY 0xFFC00E54	/* DMA2 Channel 9 Inner Loop Addr Increment */
+#define DMA2_9_Y_MODIFY 0xFFC00E5C	/* DMA2 Channel 9 Outer Loop Addr Increment */
+#define DMA2_9_CURR_DESC_PTR 0xFFC00E60	/* DMA2 Channel 9 Current Descriptor Pointer */
+#define DMA2_9_CURR_ADDR 0xFFC00E64	/* DMA2 Channel 9 Current Address Pointer */
+#define DMA2_9_CURR_X_COUNT 0xFFC00E70	/* DMA2 Channel 9 Current Inner Loop Count */
+#define DMA2_9_CURR_Y_COUNT 0xFFC00E78	/* DMA2 Channel 9 Current Outer Loop Count */
+#define DMA2_9_IRQ_STATUS 0xFFC00E68	/* DMA2 Channel 9 Interrupt/Status Register */
+#define DMA2_9_PERIPHERAL_MAP 0xFFC00E6C	/* DMA2 Channel 9 Peripheral Map Register */
+
+#define DMA2_10_CONFIG 0xFFC00E88	/* DMA2 Channel 10 Configuration register */
+#define DMA2_10_NEXT_DESC_PTR 0xFFC00E80	/* DMA2 Channel 10 Next Descripter Ptr Reg */
+#define DMA2_10_START_ADDR 0xFFC00E84	/* DMA2 Channel 10 Start Address */
+#define DMA2_10_X_COUNT 0xFFC00E90	/* DMA2 Channel 10 Inner Loop Count */
+#define DMA2_10_Y_COUNT 0xFFC00E98	/* DMA2 Channel 10 Outer Loop Count */
+#define DMA2_10_X_MODIFY 0xFFC00E94	/* DMA2 Channel 10 Inner Loop Addr Increment */
+#define DMA2_10_Y_MODIFY 0xFFC00E9C	/* DMA2 Channel 10 Outer Loop Addr Increment */
+#define DMA2_10_CURR_DESC_PTR 0xFFC00EA0	/* DMA2 Channel 10 Current Descriptor Pointer */
+#define DMA2_10_CURR_ADDR 0xFFC00EA4	/* DMA2 Channel 10 Current Address Pointer */
+#define DMA2_10_CURR_X_COUNT 0xFFC00EB0	/* DMA2 Channel 10 Current Inner Loop Count */
+#define DMA2_10_CURR_Y_COUNT 0xFFC00EB8	/* DMA2 Channel 10 Current Outer Loop Count */
+#define DMA2_10_IRQ_STATUS 0xFFC00EA8	/* DMA2 Channel 10 Interrupt/Status Register */
+#define DMA2_10_PERIPHERAL_MAP 0xFFC00EAC	/* DMA2 Channel 10 Peripheral Map Register */
+
+#define DMA2_11_CONFIG 0xFFC00EC8	/* DMA2 Channel 11 Configuration register */
+#define DMA2_11_NEXT_DESC_PTR 0xFFC00EC0	/* DMA2 Channel 11 Next Descripter Ptr Reg */
+#define DMA2_11_START_ADDR 0xFFC00EC4	/* DMA2 Channel 11 Start Address */
+#define DMA2_11_X_COUNT 0xFFC00ED0	/* DMA2 Channel 11 Inner Loop Count */
+#define DMA2_11_Y_COUNT 0xFFC00ED8	/* DMA2 Channel 11 Outer Loop Count */
+#define DMA2_11_X_MODIFY 0xFFC00ED4	/* DMA2 Channel 11 Inner Loop Addr Increment */
+#define DMA2_11_Y_MODIFY 0xFFC00EDC	/* DMA2 Channel 11 Outer Loop Addr Increment */
+#define DMA2_11_CURR_DESC_PTR 0xFFC00EE0	/* DMA2 Channel 11 Current Descriptor Pointer */
+#define DMA2_11_CURR_ADDR 0xFFC00EE4	/* DMA2 Channel 11 Current Address Pointer */
+#define DMA2_11_CURR_X_COUNT 0xFFC00EF0	/* DMA2 Channel 11 Current Inner Loop Count */
+#define DMA2_11_CURR_Y_COUNT 0xFFC00EF8	/* DMA2 Channel 11 Current Outer Loop Count */
+#define DMA2_11_IRQ_STATUS 0xFFC00EE8	/* DMA2 Channel 11 Interrupt/Status Register */
+#define DMA2_11_PERIPHERAL_MAP 0xFFC00EEC	/* DMA2 Channel 11 Peripheral Map Register */
+
+/* Memory DMA2 Controller registers (0xFFC0 0E80-0xFFC0 0FFF) */
+#define MDMA2_D0_CONFIG 0xFFC00F08	/*MemDMA2 Stream 0 Destination Configuration register */
+#define MDMA2_D0_NEXT_DESC_PTR 0xFFC00F00	/*MemDMA2 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA2_D0_START_ADDR 0xFFC00F04	/*MemDMA2 Stream 0 Destination Start Address */
+#define MDMA2_D0_X_COUNT 0xFFC00F10	/*MemDMA2 Stream 0 Dest Inner-Loop Count register */
+#define MDMA2_D0_Y_COUNT 0xFFC00F18	/*MemDMA2 Stream 0 Dest Outer-Loop Count register */
+#define MDMA2_D0_X_MODIFY 0xFFC00F14	/*MemDMA2 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA2_D0_Y_MODIFY 0xFFC00F1C	/*MemDMA2 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA2_D0_CURR_DESC_PTR 0xFFC00F20	/*MemDMA2 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA2_D0_CURR_ADDR 0xFFC00F24	/*MemDMA2 Stream 0 Destination Current Address */
+#define MDMA2_D0_CURR_X_COUNT 0xFFC00F30	/*MemDMA2 Stream 0 Dest Current Inner-Loop Count reg */
+#define MDMA2_D0_CURR_Y_COUNT 0xFFC00F38	/*MemDMA2 Stream 0 Dest Current Outer-Loop Count reg */
+#define MDMA2_D0_IRQ_STATUS 0xFFC00F28	/*MemDMA2 Stream 0 Dest Interrupt/Status Register */
+#define MDMA2_D0_PERIPHERAL_MAP 0xFFC00F2C	/*MemDMA2 Stream 0 Destination Peripheral Map register */
+
+#define MDMA2_S0_CONFIG 0xFFC00F48	/*MemDMA2 Stream 0 Source Configuration register */
+#define MDMA2_S0_NEXT_DESC_PTR 0xFFC00F40	/*MemDMA2 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA2_S0_START_ADDR 0xFFC00F44	/*MemDMA2 Stream 0 Source Start Address */
+#define MDMA2_S0_X_COUNT 0xFFC00F50	/*MemDMA2 Stream 0 Source Inner-Loop Count register */
+#define MDMA2_S0_Y_COUNT 0xFFC00F58	/*MemDMA2 Stream 0 Source Outer-Loop Count register */
+#define MDMA2_S0_X_MODIFY 0xFFC00F54	/*MemDMA2 Stream 0 Src Inner-Loop Addr-Increment reg */
+#define MDMA2_S0_Y_MODIFY 0xFFC00F5C	/*MemDMA2 Stream 0 Src Outer-Loop Addr-Increment reg */
+#define MDMA2_S0_CURR_DESC_PTR 0xFFC00F60	/*MemDMA2 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA2_S0_CURR_ADDR 0xFFC00F64	/*MemDMA2 Stream 0 Source Current Address */
+#define MDMA2_S0_CURR_X_COUNT 0xFFC00F70	/*MemDMA2 Stream 0 Src Current Inner-Loop Count reg */
+#define MDMA2_S0_CURR_Y_COUNT 0xFFC00F78	/*MemDMA2 Stream 0 Src Current Outer-Loop Count reg */
+#define MDMA2_S0_IRQ_STATUS 0xFFC00F68	/*MemDMA2 Stream 0 Source Interrupt/Status Register */
+#define MDMA2_S0_PERIPHERAL_MAP 0xFFC00F6C	/*MemDMA2 Stream 0 Source Peripheral Map register */
+
+#define MDMA2_D1_CONFIG 0xFFC00F88	/*MemDMA2 Stream 1 Destination Configuration register */
+#define MDMA2_D1_NEXT_DESC_PTR 0xFFC00F80	/*MemDMA2 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA2_D1_START_ADDR 0xFFC00F84	/*MemDMA2 Stream 1 Destination Start Address */
+#define MDMA2_D1_X_COUNT 0xFFC00F90	/*MemDMA2 Stream 1 Dest Inner-Loop Count register */
+#define MDMA2_D1_Y_COUNT 0xFFC00F98	/*MemDMA2 Stream 1 Dest Outer-Loop Count register */
+#define MDMA2_D1_X_MODIFY 0xFFC00F94	/*MemDMA2 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA2_D1_Y_MODIFY 0xFFC00F9C	/*MemDMA2 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA2_D1_CURR_DESC_PTR 0xFFC00FA0	/*MemDMA2 Stream 1 Destination Current Descriptor Ptr */
+#define MDMA2_D1_CURR_ADDR 0xFFC00FA4	/*MemDMA2 Stream 1 Destination Current Address reg */
+#define MDMA2_D1_CURR_X_COUNT 0xFFC00FB0	/*MemDMA2 Stream 1 Dest Current Inner-Loop Count reg */
+#define MDMA2_D1_CURR_Y_COUNT 0xFFC00FB8	/*MemDMA2 Stream 1 Dest Current Outer-Loop Count reg */
+#define MDMA2_D1_IRQ_STATUS 0xFFC00FA8	/*MemDMA2 Stream 1 Destination Interrupt/Status Reg */
+#define MDMA2_D1_PERIPHERAL_MAP 0xFFC00FAC	/*MemDMA2 Stream 1 Destination Peripheral Map register */
+
+#define MDMA2_S1_CONFIG 0xFFC00FC8	/*MemDMA2 Stream 1 Source Configuration register */
+#define MDMA2_S1_NEXT_DESC_PTR 0xFFC00FC0	/*MemDMA2 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA2_S1_START_ADDR 0xFFC00FC4	/*MemDMA2 Stream 1 Source Start Address */
+#define MDMA2_S1_X_COUNT 0xFFC00FD0	/*MemDMA2 Stream 1 Source Inner-Loop Count register */
+#define MDMA2_S1_Y_COUNT 0xFFC00FD8	/*MemDMA2 Stream 1 Source Outer-Loop Count register */
+#define MDMA2_S1_X_MODIFY 0xFFC00FD4	/*MemDMA2 Stream 1 Src Inner-Loop Address-Increment */
+#define MDMA2_S1_Y_MODIFY 0xFFC00FDC	/*MemDMA2 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA2_S1_CURR_DESC_PTR 0xFFC00FE0	/*MemDMA2 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA2_S1_CURR_ADDR 0xFFC00FE4	/*MemDMA2 Stream 1 Source Current Address */
+#define MDMA2_S1_CURR_X_COUNT 0xFFC00FF0	/*MemDMA2 Stream 1 Source Current Inner-Loop Count */
+#define MDMA2_S1_CURR_Y_COUNT 0xFFC00FF8	/*MemDMA2 Stream 1 Source Current Outer-Loop Count */
+#define MDMA2_S1_IRQ_STATUS 0xFFC00FE8	/*MemDMA2 Stream 1 Source Interrupt/Status Register */
+#define MDMA2_S1_PERIPHERAL_MAP 0xFFC00FEC	/*MemDMA2 Stream 1 Source Peripheral Map register */
+
+/* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
+#define IMDMA_D0_CONFIG 0xFFC01808	/*IMDMA Stream 0 Destination Configuration */
+#define IMDMA_D0_NEXT_DESC_PTR 0xFFC01800	/*IMDMA Stream 0 Destination Next Descriptor Ptr Reg */
+#define IMDMA_D0_START_ADDR 0xFFC01804	/*IMDMA Stream 0 Destination Start Address */
+#define IMDMA_D0_X_COUNT 0xFFC01810	/*IMDMA Stream 0 Destination Inner-Loop Count */
+#define IMDMA_D0_Y_COUNT 0xFFC01818	/*IMDMA Stream 0 Destination Outer-Loop Count */
+#define IMDMA_D0_X_MODIFY 0xFFC01814	/*IMDMA Stream 0 Dest Inner-Loop Address-Increment */
+#define IMDMA_D0_Y_MODIFY 0xFFC0181C	/*IMDMA Stream 0 Dest Outer-Loop Address-Increment */
+#define IMDMA_D0_CURR_DESC_PTR 0xFFC01820	/*IMDMA Stream 0 Destination Current Descriptor Ptr */
+#define IMDMA_D0_CURR_ADDR 0xFFC01824	/*IMDMA Stream 0 Destination Current Address */
+#define IMDMA_D0_CURR_X_COUNT 0xFFC01830	/*IMDMA Stream 0 Destination Current Inner-Loop Count */
+#define IMDMA_D0_CURR_Y_COUNT 0xFFC01838	/*IMDMA Stream 0 Destination Current Outer-Loop Count */
+#define IMDMA_D0_IRQ_STATUS 0xFFC01828	/*IMDMA Stream 0 Destination Interrupt/Status */
+
+#define IMDMA_S0_CONFIG 0xFFC01848	/*IMDMA Stream 0 Source Configuration */
+#define IMDMA_S0_NEXT_DESC_PTR 0xFFC01840	/*IMDMA Stream 0 Source Next Descriptor Ptr Reg */
+#define IMDMA_S0_START_ADDR 0xFFC01844	/*IMDMA Stream 0 Source Start Address */
+#define IMDMA_S0_X_COUNT 0xFFC01850	/*IMDMA Stream 0 Source Inner-Loop Count */
+#define IMDMA_S0_Y_COUNT 0xFFC01858	/*IMDMA Stream 0 Source Outer-Loop Count */
+#define IMDMA_S0_X_MODIFY 0xFFC01854	/*IMDMA Stream 0 Source Inner-Loop Address-Increment */
+#define IMDMA_S0_Y_MODIFY 0xFFC0185C	/*IMDMA Stream 0 Source Outer-Loop Address-Increment */
+#define IMDMA_S0_CURR_DESC_PTR 0xFFC01860	/*IMDMA Stream 0 Source Current Descriptor Ptr reg */
+#define IMDMA_S0_CURR_ADDR 0xFFC01864	/*IMDMA Stream 0 Source Current Address */
+#define IMDMA_S0_CURR_X_COUNT 0xFFC01870	/*IMDMA Stream 0 Source Current Inner-Loop Count */
+#define IMDMA_S0_CURR_Y_COUNT 0xFFC01878	/*IMDMA Stream 0 Source Current Outer-Loop Count */
+#define IMDMA_S0_IRQ_STATUS 0xFFC01868	/*IMDMA Stream 0 Source Interrupt/Status */
+
+#define IMDMA_D1_CONFIG 0xFFC01888	/*IMDMA Stream 1 Destination Configuration */
+#define IMDMA_D1_NEXT_DESC_PTR 0xFFC01880	/*IMDMA Stream 1 Destination Next Descriptor Ptr Reg */
+#define IMDMA_D1_START_ADDR 0xFFC01884	/*IMDMA Stream 1 Destination Start Address */
+#define IMDMA_D1_X_COUNT 0xFFC01890	/*IMDMA Stream 1 Destination Inner-Loop Count */
+#define IMDMA_D1_Y_COUNT 0xFFC01898	/*IMDMA Stream 1 Destination Outer-Loop Count */
+#define IMDMA_D1_X_MODIFY 0xFFC01894	/*IMDMA Stream 1 Dest Inner-Loop Address-Increment */
+#define IMDMA_D1_Y_MODIFY 0xFFC0189C	/*IMDMA Stream 1 Dest Outer-Loop Address-Increment */
+#define IMDMA_D1_CURR_DESC_PTR 0xFFC018A0	/*IMDMA Stream 1 Destination Current Descriptor Ptr */
+#define IMDMA_D1_CURR_ADDR 0xFFC018A4	/*IMDMA Stream 1 Destination Current Address */
+#define IMDMA_D1_CURR_X_COUNT 0xFFC018B0	/*IMDMA Stream 1 Destination Current Inner-Loop Count */
+#define IMDMA_D1_CURR_Y_COUNT 0xFFC018B8	/*IMDMA Stream 1 Destination Current Outer-Loop Count */
+#define IMDMA_D1_IRQ_STATUS 0xFFC018A8	/*IMDMA Stream 1 Destination Interrupt/Status */
+
+#define IMDMA_S1_CONFIG 0xFFC018C8	/*IMDMA Stream 1 Source Configuration */
+#define IMDMA_S1_NEXT_DESC_PTR 0xFFC018C0	/*IMDMA Stream 1 Source Next Descriptor Ptr Reg */
+#define IMDMA_S1_START_ADDR 0xFFC018C4	/*IMDMA Stream 1 Source Start Address */
+#define IMDMA_S1_X_COUNT 0xFFC018D0	/*IMDMA Stream 1 Source Inner-Loop Count */
+#define IMDMA_S1_Y_COUNT 0xFFC018D8	/*IMDMA Stream 1 Source Outer-Loop Count */
+#define IMDMA_S1_X_MODIFY 0xFFC018D4	/*IMDMA Stream 1 Source Inner-Loop Address-Increment */
+#define IMDMA_S1_Y_MODIFY 0xFFC018DC	/*IMDMA Stream 1 Source Outer-Loop Address-Increment */
+#define IMDMA_S1_CURR_DESC_PTR 0xFFC018E0	/*IMDMA Stream 1 Source Current Descriptor Ptr reg */
+#define IMDMA_S1_CURR_ADDR 0xFFC018E4	/*IMDMA Stream 1 Source Current Address */
+#define IMDMA_S1_CURR_X_COUNT 0xFFC018F0	/*IMDMA Stream 1 Source Current Inner-Loop Count */
+#define IMDMA_S1_CURR_Y_COUNT 0xFFC018F8	/*IMDMA Stream 1 Source Current Outer-Loop Count */
+#define IMDMA_S1_IRQ_STATUS 0xFFC018E8	/*IMDMA Stream 1 Source Interrupt/Status */
+
+/*********************************************************************************** */
+/* System MMR Register Bits */
+/******************************************************************************* */
+
+/* ********************* PLL AND RESET MASKS ************************ */
+
+/* PLL_CTL Masks */
+#define PLL_CLKIN              0x00000000	/* Pass CLKIN to PLL */
+#define PLL_CLKIN_DIV2         0x00000001	/* Pass CLKIN/2 to PLL */
+#define PLL_OFF                0x00000002	/* Shut off PLL clocks */
+#define STOPCK_OFF             0x00000008	/* Core clock off */
+#define PDWN                   0x00000020	/* Put the PLL in a Deep Sleep state */
+#define BYPASS                 0x00000100	/* Bypass the PLL */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION         0xF0000000
+#define CHIPID_FAMILY          0x0FFFF000
+#define CHIPID_MANUFACTURE     0x00000FFE
+
+/* PLL_DIV Masks */
+#define SCLK_DIV(x)  (x)	/* SCLK = VCO / x */
+
+#define CCLK_DIV1              0x00000000	/* CCLK = VCO / 1 */
+#define CCLK_DIV2              0x00000010	/* CCLK = VCO / 2 */
+#define CCLK_DIV4              0x00000020	/* CCLK = VCO / 4 */
+#define CCLK_DIV8              0x00000030	/* CCLK = VCO / 8 */
+
+/* PLL_STAT Masks																	*/
+#define ACTIVE_PLLENABLED	0x0001	/* Processor In Active Mode With PLL Enabled    */
+#define	FULL_ON				0x0002	/* Processor In Full On Mode                                    */
+#define ACTIVE_PLLDISABLED	0x0004	/* Processor In Active Mode With PLL Disabled   */
+#define	PLL_LOCKED			0x0020	/* PLL_LOCKCNT Has Been Reached                                 */
+
+/* SWRST Mask */
+#define SYSTEM_RESET           0x00000007	/* Initiates a system software reset */
+#define SWRST_DBL_FAULT_B      0x00000800	/* SWRST Core B Double Fault */
+#define SWRST_DBL_FAULT_A      0x00001000	/* SWRST Core A Double Fault */
+#define SWRST_WDT_B		       0x00002000	/* SWRST Watchdog B */
+#define SWRST_WDT_A		       0x00004000	/* SWRST Watchdog A */
+#define SWRST_OCCURRED         0x00008000	/* SWRST Status */
+
+/* *************  SYSTEM INTERRUPT CONTROLLER MASKS ***************** */
+
+/* SICu_IARv Masks	 */
+/* u = A or B */
+/* v = 0 to 7 */
+/* w = 0 or 1 */
+
+/* Per_number = 0 to 63 */
+/* IVG_number = 7 to 15   */
+#define Peripheral_IVG(Per_number, IVG_number)    \
+    ((IVG_number) - 7) << (((Per_number) % 8) * 4)	/* Peripheral #Per_number assigned IVG #IVG_number  */
+    /* Usage: r0.l = lo(Peripheral_IVG(62, 10)); */
+    /*        r0.h = hi(Peripheral_IVG(62, 10)); */
+
+/* SICx_IMASKw Masks */
+/* masks are 32 bit wide, so two writes reguired for "64 bit" wide registers  */
+#define SIC_UNMASK_ALL         0x00000000	/* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL           0xFFFFFFFF	/* Mask all peripheral interrupts */
+#define SIC_MASK(x)	       (1 << (x))	/* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << (x)))	/* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL        0x00000000	/* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL         0xFFFFFFFF	/* Wakeup Enable all peripherals */
+/* x = pos 0 to 31, for 32-63 use value-32 */
+#define IWR_ENABLE(x)	       (1 << (x))	/* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << (x)))	/* Wakeup Disable Peripheral #x */
+
+/* *********  WATCHDOG TIMER MASKS  ********************8 */
+
+/* Watchdog Timer WDOG_CTL Register */
+#define ICTL(x) ((x<<1) & 0x0006)
+#define ENABLE_RESET     0x00000000	/* Set Watchdog Timer to generate reset */
+#define ENABLE_NMI       0x00000002	/* Set Watchdog Timer to generate non-maskable interrupt */
+#define ENABLE_GPI       0x00000004	/* Set Watchdog Timer to generate general-purpose interrupt */
+#define DISABLE_EVT      0x00000006	/* Disable Watchdog Timer interrupts */
+
+#define TMR_EN		0x0000
+#define TMR_DIS		0x0AD0
+#define TRO		0x8000
+
+#define ICTL_P0		0x01
+#define ICTL_P1		0x02
+#define TRO_P		0x0F
+
+/* ***************************** UART CONTROLLER MASKS ********************** */
+
+/* UART_LCR Register */
+
+#define DLAB	0x80
+#define SB      0x40
+#define STP      0x20
+#define EPS     0x10
+#define PEN	0x08
+#define STB	0x04
+#define WLS(x)	((x-5) & 0x03)
+
+#define DLAB_P	0x07
+#define SB_P	0x06
+#define STP_P	0x05
+#define EPS_P	0x04
+#define PEN_P	0x03
+#define STB_P	0x02
+#define WLS_P1	0x01
+#define WLS_P0	0x00
+
+/* UART_MCR Register */
+#define LOOP_ENA	0x10
+#define LOOP_ENA_P	0x04
+
+/* UART_LSR Register */
+#define TEMT	0x40
+#define THRE	0x20
+#define BI	0x10
+#define FE	0x08
+#define PE	0x04
+#define OE	0x02
+#define DR	0x01
+
+#define TEMP_P	0x06
+#define THRE_P	0x05
+#define BI_P	0x04
+#define FE_P	0x03
+#define PE_P	0x02
+#define OE_P	0x01
+#define DR_P	0x00
+
+/* UART_IER Register */
+#define ELSI	0x04
+#define ETBEI	0x02
+#define ERBFI	0x01
+
+#define ELSI_P	0x02
+#define ETBEI_P	0x01
+#define ERBFI_P	0x00
+
+/* UART_IIR Register */
+#define STATUS(x)	((x << 1) & 0x06)
+#define NINT		0x01
+#define STATUS_P1	0x02
+#define STATUS_P0	0x01
+#define NINT_P		0x00
+#define IIR_TX_READY    0x02	/* UART_THR empty                               */
+#define IIR_RX_READY    0x04	/* Receive data ready                           */
+#define IIR_LINE_CHANGE 0x06	/* Receive line status                          */
+#define IIR_STATUS	0x06
+
+/* UART_GCTL Register */
+#define FFE	0x20
+#define FPE	0x10
+#define RPOLC	0x08
+#define TPOLC	0x04
+#define IREN	0x02
+#define UCEN	0x01
+
+#define FFE_P	0x05
+#define FPE_P	0x04
+#define RPOLC_P	0x03
+#define TPOLC_P	0x02
+#define IREN_P	0x01
+#define UCEN_P	0x00
+
+/* **********  SERIAL PORT MASKS  ********************** */
+
+/* SPORTx_TCR1 Masks */
+#define TSPEN    0x0001		/* TX enable  */
+#define ITCLK    0x0002		/* Internal TX Clock Select  */
+#define TDTYPE   0x000C		/* TX Data Formatting Select */
+#define TLSBIT   0x0010		/* TX Bit Order */
+#define ITFS     0x0200		/* Internal TX Frame Sync Select  */
+#define TFSR     0x0400		/* TX Frame Sync Required Select  */
+#define DITFS    0x0800		/* Data Independent TX Frame Sync Select  */
+#define LTFS     0x1000		/* Low TX Frame Sync Select  */
+#define LATFS    0x2000		/* Late TX Frame Sync Select  */
+#define TCKFE    0x4000		/* TX Clock Falling Edge Select  */
+
+/* SPORTx_TCR2 Masks */
+#define SLEN	    0x001F	/*TX Word Length  */
+#define TXSE        0x0100	/*TX Secondary Enable */
+#define TSFSE       0x0200	/*TX Stereo Frame Sync Enable */
+#define TRFST       0x0400	/*TX Right-First Data Order  */
+
+/* SPORTx_RCR1 Masks */
+#define RSPEN    0x0001		/* RX enable  */
+#define IRCLK    0x0002		/* Internal RX Clock Select  */
+#define RDTYPE   0x000C		/* RX Data Formatting Select */
+#define RULAW    0x0008		/* u-Law enable  */
+#define RALAW    0x000C		/* A-Law enable  */
+#define RLSBIT   0x0010		/* RX Bit Order */
+#define IRFS     0x0200		/* Internal RX Frame Sync Select  */
+#define RFSR     0x0400		/* RX Frame Sync Required Select  */
+#define LRFS     0x1000		/* Low RX Frame Sync Select  */
+#define LARFS    0x2000		/* Late RX Frame Sync Select  */
+#define RCKFE    0x4000		/* RX Clock Falling Edge Select  */
+
+/* SPORTx_RCR2 Masks */
+#define SLEN	    0x001F	/*RX Word Length  */
+#define RXSE        0x0100	/*RX Secondary Enable */
+#define RSFSE       0x0200	/*RX Stereo Frame Sync Enable */
+#define RRFST       0x0400	/*Right-First Data Order  */
+
+/*SPORTx_STAT Masks */
+#define RXNE		0x0001	/*RX FIFO Not Empty Status */
+#define RUVF	    	0x0002	/*RX Underflow Status */
+#define ROVF		0x0004	/*RX Overflow Status */
+#define TXF		0x0008	/*TX FIFO Full Status */
+#define TUVF         	0x0010	/*TX Underflow Status */
+#define TOVF         	0x0020	/*TX Overflow Status */
+#define TXHRE        	0x0040	/*TX Hold Register Empty */
+
+/*SPORTx_MCMC1 Masks */
+#define SP_WSIZE		0x0000F000	/*Multichannel Window Size Field */
+#define SP_WOFF		0x000003FF	/*Multichannel Window Offset Field */
+
+/*SPORTx_MCMC2 Masks */
+#define MCCRM		0x00000003	/*Multichannel Clock Recovery Mode */
+#define MCDTXPE		0x00000004	/*Multichannel DMA Transmit Packing */
+#define MCDRXPE		0x00000008	/*Multichannel DMA Receive Packing */
+#define MCMEN		0x00000010	/*Multichannel Frame Mode Enable */
+#define FSDR		0x00000080	/*Multichannel Frame Sync to Data Relationship */
+#define MFD		0x0000F000	/*Multichannel Frame Delay    */
+
+/*  *********  PARALLEL PERIPHERAL INTERFACE (PPI) MASKS ****************   */
+
+/*  PPI_CONTROL Masks         */
+#define PORT_EN              0x00000001	/* PPI Port Enable  */
+#define PORT_DIR             0x00000002	/* PPI Port Direction       */
+#define XFR_TYPE             0x0000000C	/* PPI Transfer Type  */
+#define PORT_CFG             0x00000030	/* PPI Port Configuration */
+#define FLD_SEL              0x00000040	/* PPI Active Field Select */
+#define PACK_EN              0x00000080	/* PPI Packing Mode */
+#define DMA32                0x00000100	/* PPI 32-bit DMA Enable */
+#define SKIP_EN              0x00000200	/* PPI Skip Element Enable */
+#define SKIP_EO              0x00000400	/* PPI Skip Even/Odd Elements */
+#define DLENGTH              0x00003800	/* PPI Data Length  */
+#define DLEN_8		     0x0	/* PPI Data Length mask for DLEN=8 */
+#define DLEN(x)	(((x-9) & 0x07) << 11)	/* PPI Data Length (only works for x=10-->x=16) */
+#define POL                  0x0000C000	/* PPI Signal Polarities       */
+
+/* PPI_STATUS Masks */
+#define FLD	             0x00000400	/* Field Indicator   */
+#define FT_ERR	             0x00000800	/* Frame Track Error */
+#define OVR	             0x00001000	/* FIFO Overflow Error */
+#define UNDR	             0x00002000	/* FIFO Underrun Error */
+#define ERR_DET	      	     0x00004000	/* Error Detected Indicator */
+#define ERR_NCOR	     0x00008000	/* Error Not Corrected Indicator */
+
+/* **********  DMA CONTROLLER MASKS  *********************8 */
+
+/* DMAx_CONFIG, MDMA_yy_CONFIG, IMDMA_yy_CONFIG Masks */
+#define DMAEN	        0x00000001	/* Channel Enable */
+#define WNR	   	0x00000002	/* Channel Direction (W/R*) */
+#define WDSIZE_8	0x00000000	/* Word Size 8 bits */
+#define WDSIZE_16	0x00000004	/* Word Size 16 bits */
+#define WDSIZE_32	0x00000008	/* Word Size 32 bits */
+#define DMA2D	        0x00000010	/* 2D/1D* Mode */
+#define RESTART         0x00000020	/* Restart */
+#define DI_SEL	        0x00000040	/* Data Interrupt Select */
+#define DI_EN	        0x00000080	/* Data Interrupt Enable */
+#define NDSIZE_0		0x0000	/* Next Descriptor Size = 0 (Stop/Autobuffer)   */
+#define NDSIZE_1		0x0100	/* Next Descriptor Size = 1                                             */
+#define NDSIZE_2		0x0200	/* Next Descriptor Size = 2                                             */
+#define NDSIZE_3		0x0300	/* Next Descriptor Size = 3                                             */
+#define NDSIZE_4		0x0400	/* Next Descriptor Size = 4                                             */
+#define NDSIZE_5		0x0500	/* Next Descriptor Size = 5                                             */
+#define NDSIZE_6		0x0600	/* Next Descriptor Size = 6                                             */
+#define NDSIZE_7		0x0700	/* Next Descriptor Size = 7                                             */
+#define NDSIZE_8		0x0800	/* Next Descriptor Size = 8                                             */
+#define NDSIZE_9		0x0900	/* Next Descriptor Size = 9                                             */
+#define NDSIZE	        0x00000900	/* Next Descriptor Size */
+#define DMAFLOW	        0x00007000	/* Flow Control */
+#define DMAFLOW_STOP		0x0000	/* Stop Mode */
+#define DMAFLOW_AUTO		0x1000	/* Autobuffer Mode */
+#define DMAFLOW_ARRAY		0x4000	/* Descriptor Array Mode */
+#define DMAFLOW_SMALL		0x6000	/* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE		0x7000	/* Large Model Descriptor List Mode */
+
+#define DMAEN_P	            	0	/* Channel Enable */
+#define WNR_P	            	1	/* Channel Direction (W/R*) */
+#define DMA2D_P	        	4	/* 2D/1D* Mode */
+#define RESTART_P	      	5	/* Restart */
+#define DI_SEL_P	     	6	/* Data Interrupt Select */
+#define DI_EN_P	            	7	/* Data Interrupt Enable */
+
+/* DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS, IMDMA_yy_IRQ_STATUS Masks */
+
+#define DMA_DONE		0x00000001	/* DMA Done Indicator */
+#define DMA_ERR	        	0x00000002	/* DMA Error Indicator */
+#define DFETCH	            	0x00000004	/* Descriptor Fetch Indicator */
+#define DMA_RUN	            	0x00000008	/* DMA Running Indicator */
+
+#define DMA_DONE_P	    	0	/* DMA Done Indicator */
+#define DMA_ERR_P     		1	/* DMA Error Indicator */
+#define DFETCH_P     		2	/* Descriptor Fetch Indicator */
+#define DMA_RUN_P     		3	/* DMA Running Indicator */
+
+/* DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP, IMDMA_yy_PERIPHERAL_MAP Masks */
+
+#define CTYPE	            0x00000040	/* DMA Channel Type Indicator */
+#define CTYPE_P             6	/* DMA Channel Type Indicator BIT POSITION */
+#define PCAP8	            0x00000080	/* DMA 8-bit Operation Indicator   */
+#define PCAP16	            0x00000100	/* DMA 16-bit Operation Indicator */
+#define PCAP32	            0x00000200	/* DMA 32-bit Operation Indicator */
+#define PCAPWR	            0x00000400	/* DMA Write Operation Indicator */
+#define PCAPRD	            0x00000800	/* DMA Read Operation Indicator */
+#define PMAP	            0x00007000	/* DMA Peripheral Map Field */
+
+/*  *************  GENERAL PURPOSE TIMER MASKS  ******************** */
+
+/* PWM Timer bit definitions */
+
+/* TIMER_ENABLE Register */
+#define TIMEN0	0x0001
+#define TIMEN1	0x0002
+#define TIMEN2	0x0004
+#define TIMEN3	0x0008
+#define TIMEN4	0x0010
+#define TIMEN5	0x0020
+#define TIMEN6	0x0040
+#define TIMEN7	0x0080
+#define TIMEN8	0x0001
+#define TIMEN9	0x0002
+#define TIMEN10	0x0004
+#define TIMEN11	0x0008
+
+#define TIMEN0_P	0x00
+#define TIMEN1_P	0x01
+#define TIMEN2_P	0x02
+#define TIMEN3_P	0x03
+#define TIMEN4_P	0x04
+#define TIMEN5_P	0x05
+#define TIMEN6_P	0x06
+#define TIMEN7_P	0x07
+#define TIMEN8_P	0x00
+#define TIMEN9_P	0x01
+#define TIMEN10_P	0x02
+#define TIMEN11_P	0x03
+
+/* TIMER_DISABLE Register */
+#define TIMDIS0		0x0001
+#define TIMDIS1		0x0002
+#define TIMDIS2		0x0004
+#define TIMDIS3		0x0008
+#define TIMDIS4		0x0010
+#define TIMDIS5		0x0020
+#define TIMDIS6		0x0040
+#define TIMDIS7		0x0080
+#define TIMDIS8		0x0001
+#define TIMDIS9		0x0002
+#define TIMDIS10	0x0004
+#define TIMDIS11	0x0008
+
+#define TIMDIS0_P	0x00
+#define TIMDIS1_P	0x01
+#define TIMDIS2_P	0x02
+#define TIMDIS3_P	0x03
+#define TIMDIS4_P	0x04
+#define TIMDIS5_P	0x05
+#define TIMDIS6_P	0x06
+#define TIMDIS7_P	0x07
+#define TIMDIS8_P	0x00
+#define TIMDIS9_P	0x01
+#define TIMDIS10_P	0x02
+#define TIMDIS11_P	0x03
+
+/* TIMER_STATUS Register */
+#define TIMIL0		0x00000001
+#define TIMIL1		0x00000002
+#define TIMIL2		0x00000004
+#define TIMIL3		0x00000008
+#define TIMIL4		0x00010000
+#define TIMIL5		0x00020000
+#define TIMIL6		0x00040000
+#define TIMIL7		0x00080000
+#define TIMIL8		0x0001
+#define TIMIL9		0x0002
+#define TIMIL10		0x0004
+#define TIMIL11		0x0008
+#define TOVL_ERR0	0x00000010
+#define TOVL_ERR1	0x00000020
+#define TOVL_ERR2	0x00000040
+#define TOVL_ERR3	0x00000080
+#define TOVL_ERR4	0x00100000
+#define TOVL_ERR5	0x00200000
+#define TOVL_ERR6	0x00400000
+#define TOVL_ERR7	0x00800000
+#define TOVL_ERR8	0x0010
+#define TOVL_ERR9	0x0020
+#define TOVL_ERR10	0x0040
+#define TOVL_ERR11	0x0080
+#define TRUN0		0x00001000
+#define TRUN1		0x00002000
+#define TRUN2		0x00004000
+#define TRUN3		0x00008000
+#define TRUN4		0x10000000
+#define TRUN5		0x20000000
+#define TRUN6		0x40000000
+#define TRUN7		0x80000000
+#define TRUN8		0x1000
+#define TRUN9		0x2000
+#define TRUN10		0x4000
+#define TRUN11		0x8000
+
+#define TIMIL0_P	0x00
+#define TIMIL1_P	0x01
+#define TIMIL2_P	0x02
+#define TIMIL3_P	0x03
+#define TIMIL4_P	0x10
+#define TIMIL5_P	0x11
+#define TIMIL6_P	0x12
+#define TIMIL7_P	0x13
+#define TIMIL8_P	0x00
+#define TIMIL9_P	0x01
+#define TIMIL10_P	0x02
+#define TIMIL11_P	0x03
+#define TOVL_ERR0_P	0x04
+#define TOVL_ERR1_P	0x05
+#define TOVL_ERR2_P	0x06
+#define TOVL_ERR3_P	0x07
+#define TOVL_ERR4_P	0x14
+#define TOVL_ERR5_P	0x15
+#define TOVL_ERR6_P	0x16
+#define TOVL_ERR7_P	0x17
+#define TOVL_ERR8_P	0x04
+#define TOVL_ERR9_P	0x05
+#define TOVL_ERR10_P	0x06
+#define TOVL_ERR11_P	0x07
+#define TRUN0_P		0x0C
+#define TRUN1_P		0x0D
+#define TRUN2_P		0x0E
+#define TRUN3_P		0x0F
+#define TRUN4_P		0x1C
+#define TRUN5_P		0x1D
+#define TRUN6_P		0x1E
+#define TRUN7_P		0x1F
+#define TRUN8_P		0x0C
+#define TRUN9_P		0x0D
+#define TRUN10_P	0x0E
+#define TRUN11_P	0x0F
+
+/* TIMERx_CONFIG Registers */
+#define PWM_OUT		0x0001
+#define WDTH_CAP	0x0002
+#define EXT_CLK		0x0003
+#define PULSE_HI	0x0004
+#define PERIOD_CNT	0x0008
+#define IRQ_ENA		0x0010
+#define TIN_SEL		0x0020
+#define OUT_DIS		0x0040
+#define CLK_SEL		0x0080
+#define TOGGLE_HI	0x0100
+#define EMU_RUN		0x0200
+#define ERR_TYP(x)	((x & 0x03) << 14)
+
+#define TMODE_P0		0x00
+#define TMODE_P1		0x01
+#define PULSE_HI_P		0x02
+#define PERIOD_CNT_P		0x03
+#define IRQ_ENA_P		0x04
+#define TIN_SEL_P		0x05
+#define OUT_DIS_P		0x06
+#define CLK_SEL_P		0x07
+#define TOGGLE_HI_P		0x08
+#define EMU_RUN_P		0x09
+#define ERR_TYP_P0		0x0E
+#define ERR_TYP_P1		0x0F
+
+/*/ ******************   PROGRAMMABLE FLAG MASKS  ********************* */
+
+/*  General Purpose IO (0xFFC00700 - 0xFFC007FF)  Masks */
+#define PF0         0x0001
+#define PF1         0x0002
+#define PF2         0x0004
+#define PF3         0x0008
+#define PF4         0x0010
+#define PF5         0x0020
+#define PF6         0x0040
+#define PF7         0x0080
+#define PF8         0x0100
+#define PF9         0x0200
+#define PF10        0x0400
+#define PF11        0x0800
+#define PF12        0x1000
+#define PF13        0x2000
+#define PF14        0x4000
+#define PF15        0x8000
+
+/*  General Purpose IO (0xFFC00700 - 0xFFC007FF)  BIT POSITIONS */
+#define PF0_P         0
+#define PF1_P         1
+#define PF2_P         2
+#define PF3_P         3
+#define PF4_P         4
+#define PF5_P         5
+#define PF6_P         6
+#define PF7_P         7
+#define PF8_P         8
+#define PF9_P         9
+#define PF10_P        10
+#define PF11_P        11
+#define PF12_P        12
+#define PF13_P        13
+#define PF14_P        14
+#define PF15_P        15
+
+/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  **************** */
+
+/* SPI_CTL Masks */
+#define TIMOD                  0x00000003	/* Transfer initiation mode and interrupt generation */
+#define SZ                     0x00000004	/* Send Zero (=0) or last (=1) word when TDBR empty. */
+#define GM                     0x00000008	/* When RDBR full, get more (=1) data or discard (=0) incoming Data */
+#define PSSE                   0x00000010	/* Enable (=1) Slave-Select input for Master. */
+#define EMISO                  0x00000020	/* Enable (=1) MISO pin as an output. */
+#define SIZE                   0x00000100	/* Word length (0 => 8 bits, 1 => 16 bits) */
+#define LSBF                   0x00000200	/* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
+#define CPHA                   0x00000400	/* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
+#define CPOL                   0x00000800	/* Clock polarity (0 => active-high, 1 => active-low) */
+#define MSTR                   0x00001000	/* Configures SPI as master (=1) or slave (=0) */
+#define WOM                    0x00002000	/* Open drain (=1) data output enable (for MOSI and MISO) */
+#define SPE                    0x00004000	/* SPI module enable (=1), disable (=0) */
+
+/* SPI_FLG Masks */
+#define FLS1                   0x00000002	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2                   0x00000004	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3                   0x00000008	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4                   0x00000010	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5                   0x00000020	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6                   0x00000040	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7                   0x00000080	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1                   0x00000200	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
+#define FLG2                   0x00000400	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3                   0x00000800	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
+#define FLG4                   0x00001000	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
+#define FLG5                   0x00002000	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
+#define FLG6                   0x00004000	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
+#define FLG7                   0x00008000	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_FLG Bit Positions */
+#define FLS1_P                 0x00000001	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2_P                 0x00000002	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3_P                 0x00000003	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4_P                 0x00000004	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5_P                 0x00000005	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6_P                 0x00000006	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7_P                 0x00000007	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1_P                 0x00000009	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
+#define FLG2_P                 0x0000000A	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3_P                 0x0000000B	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
+#define FLG4_P                 0x0000000C	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
+#define FLG5_P                 0x0000000D	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
+#define FLG6_P                 0x0000000E	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
+#define FLG7_P                 0x0000000F	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_STAT Masks */
+#define SPIF                   0x00000001	/* Set (=1) when SPI single-word transfer complete */
+#define MODF                   0x00000002	/* Set (=1) in a master device when some other device tries to become master */
+#define TXE                    0x00000004	/* Set (=1) when transmission occurs with no new data in SPI_TDBR */
+#define TXS                    0x00000008	/* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
+#define RBSY                   0x00000010	/* Set (=1) when data is received with RDBR full */
+#define RXS                    0x00000020	/* SPI_RDBR Data Buffer Status (0=Empty, 1=Full)  */
+#define TXCOL                  0x00000040	/* When set (=1), corrupt data may have been transmitted  */
+
+/* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS  ************* */
+
+/* AMGCTL Masks */
+#define AMCKEN			0x0001	/* Enable CLKOUT */
+#define AMBEN_B0		0x0002	/* Enable Asynchronous Memory Bank 0 only */
+#define AMBEN_B0_B1		0x0004	/* Enable Asynchronous Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2	0x0006	/* Enable Asynchronous Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL		0x0008	/* Enable Asynchronous Memory Banks (all) 0, 1, 2, and 3 */
+#define B0_PEN			0x0010	/* Enable 16-bit packing Bank 0  */
+#define B1_PEN			0x0020	/* Enable 16-bit packing Bank 1  */
+#define B2_PEN			0x0040	/* Enable 16-bit packing Bank 2  */
+#define B3_PEN			0x0080	/* Enable 16-bit packing Bank 3  */
+
+/* AMGCTL Bit Positions */
+#define AMCKEN_P		0x00000000	/* Enable CLKOUT */
+#define AMBEN_P0		0x00000001	/* Asynchronous Memory Enable, 000 - banks 0-3 disabled, 001 - Bank 0 enabled */
+#define AMBEN_P1		0x00000002	/* Asynchronous Memory Enable, 010 - banks 0&1 enabled,  011 - banks 0-3 enabled */
+#define AMBEN_P2		0x00000003	/* Asynchronous Memory Enable, 1xx - All banks (bank 0, 1, 2, and 3) enabled */
+#define B0_PEN_P			0x004	/* Enable 16-bit packing Bank 0  */
+#define B1_PEN_P			0x005	/* Enable 16-bit packing Bank 1  */
+#define B2_PEN_P			0x006	/* Enable 16-bit packing Bank 2  */
+#define B3_PEN_P			0x007	/* Enable 16-bit packing Bank 3  */
+
+/* AMBCTL0 Masks */
+#define B0RDYEN	0x00000001	/* Bank 0 RDY Enable, 0=disable, 1=enable */
+#define B0RDYPOL 0x00000002	/* Bank 0 RDY Active high, 0=active low, 1=active high */
+#define B0TT_1	0x00000004	/* Bank 0 Transition Time from Read to Write = 1 cycle */
+#define B0TT_2	0x00000008	/* Bank 0 Transition Time from Read to Write = 2 cycles */
+#define B0TT_3	0x0000000C	/* Bank 0 Transition Time from Read to Write = 3 cycles */
+#define B0TT_4	0x00000000	/* Bank 0 Transition Time from Read to Write = 4 cycles */
+#define B0ST_1	0x00000010	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=1 cycle */
+#define B0ST_2	0x00000020	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=2 cycles */
+#define B0ST_3	0x00000030	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=3 cycles */
+#define B0ST_4	0x00000000	/* Bank 0 Setup Time from AOE asserted to Read/Write asserted=4 cycles */
+#define B0HT_1	0x00000040	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 1 cycle */
+#define B0HT_2	0x00000080	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 2 cycles */
+#define B0HT_3	0x000000C0	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 3 cycles */
+#define B0HT_0	0x00000000	/* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 0 cycles */
+#define B0RAT_1			0x00000100	/* Bank 0 Read Access Time = 1 cycle */
+#define B0RAT_2			0x00000200	/* Bank 0 Read Access Time = 2 cycles */
+#define B0RAT_3			0x00000300	/* Bank 0 Read Access Time = 3 cycles */
+#define B0RAT_4			0x00000400	/* Bank 0 Read Access Time = 4 cycles */
+#define B0RAT_5			0x00000500	/* Bank 0 Read Access Time = 5 cycles */
+#define B0RAT_6			0x00000600	/* Bank 0 Read Access Time = 6 cycles */
+#define B0RAT_7			0x00000700	/* Bank 0 Read Access Time = 7 cycles */
+#define B0RAT_8			0x00000800	/* Bank 0 Read Access Time = 8 cycles */
+#define B0RAT_9			0x00000900	/* Bank 0 Read Access Time = 9 cycles */
+#define B0RAT_10		0x00000A00	/* Bank 0 Read Access Time = 10 cycles */
+#define B0RAT_11		0x00000B00	/* Bank 0 Read Access Time = 11 cycles */
+#define B0RAT_12		0x00000C00	/* Bank 0 Read Access Time = 12 cycles */
+#define B0RAT_13		0x00000D00	/* Bank 0 Read Access Time = 13 cycles */
+#define B0RAT_14		0x00000E00	/* Bank 0 Read Access Time = 14 cycles */
+#define B0RAT_15		0x00000F00	/* Bank 0 Read Access Time = 15 cycles */
+#define B0WAT_1			0x00001000	/* Bank 0 Write Access Time = 1 cycle */
+#define B0WAT_2			0x00002000	/* Bank 0 Write Access Time = 2 cycles */
+#define B0WAT_3			0x00003000	/* Bank 0 Write Access Time = 3 cycles */
+#define B0WAT_4			0x00004000	/* Bank 0 Write Access Time = 4 cycles */
+#define B0WAT_5			0x00005000	/* Bank 0 Write Access Time = 5 cycles */
+#define B0WAT_6			0x00006000	/* Bank 0 Write Access Time = 6 cycles */
+#define B0WAT_7			0x00007000	/* Bank 0 Write Access Time = 7 cycles */
+#define B0WAT_8			0x00008000	/* Bank 0 Write Access Time = 8 cycles */
+#define B0WAT_9			0x00009000	/* Bank 0 Write Access Time = 9 cycles */
+#define B0WAT_10		0x0000A000	/* Bank 0 Write Access Time = 10 cycles */
+#define B0WAT_11		0x0000B000	/* Bank 0 Write Access Time = 11 cycles */
+#define B0WAT_12		0x0000C000	/* Bank 0 Write Access Time = 12 cycles */
+#define B0WAT_13		0x0000D000	/* Bank 0 Write Access Time = 13 cycles */
+#define B0WAT_14		0x0000E000	/* Bank 0 Write Access Time = 14 cycles */
+#define B0WAT_15		0x0000F000	/* Bank 0 Write Access Time = 15 cycles */
+#define B1RDYEN			0x00010000	/* Bank 1 RDY enable, 0=disable, 1=enable */
+#define B1RDYPOL		0x00020000	/* Bank 1 RDY Active high, 0=active low, 1=active high */
+#define B1TT_1			0x00040000	/* Bank 1 Transition Time from Read to Write = 1 cycle */
+#define B1TT_2			0x00080000	/* Bank 1 Transition Time from Read to Write = 2 cycles */
+#define B1TT_3			0x000C0000	/* Bank 1 Transition Time from Read to Write = 3 cycles */
+#define B1TT_4			0x00000000	/* Bank 1 Transition Time from Read to Write = 4 cycles */
+#define B1ST_1			0x00100000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B1ST_2			0x00200000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B1ST_3			0x00300000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B1ST_4			0x00000000	/* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B1HT_1			0x00400000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B1HT_2			0x00800000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B1HT_3			0x00C00000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B1HT_0			0x00000000	/* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B1RAT_1			0x01000000	/* Bank 1 Read Access Time = 1 cycle */
+#define B1RAT_2			0x02000000	/* Bank 1 Read Access Time = 2 cycles */
+#define B1RAT_3			0x03000000	/* Bank 1 Read Access Time = 3 cycles */
+#define B1RAT_4			0x04000000	/* Bank 1 Read Access Time = 4 cycles */
+#define B1RAT_5			0x05000000	/* Bank 1 Read Access Time = 5 cycles */
+#define B1RAT_6			0x06000000	/* Bank 1 Read Access Time = 6 cycles */
+#define B1RAT_7			0x07000000	/* Bank 1 Read Access Time = 7 cycles */
+#define B1RAT_8			0x08000000	/* Bank 1 Read Access Time = 8 cycles */
+#define B1RAT_9			0x09000000	/* Bank 1 Read Access Time = 9 cycles */
+#define B1RAT_10		0x0A000000	/* Bank 1 Read Access Time = 10 cycles */
+#define B1RAT_11		0x0B000000	/* Bank 1 Read Access Time = 11 cycles */
+#define B1RAT_12		0x0C000000	/* Bank 1 Read Access Time = 12 cycles */
+#define B1RAT_13		0x0D000000	/* Bank 1 Read Access Time = 13 cycles */
+#define B1RAT_14		0x0E000000	/* Bank 1 Read Access Time = 14 cycles */
+#define B1RAT_15		0x0F000000	/* Bank 1 Read Access Time = 15 cycles */
+#define B1WAT_1			0x10000000	/* Bank 1 Write Access Time = 1 cycle */
+#define B1WAT_2			0x20000000	/* Bank 1 Write Access Time = 2 cycles */
+#define B1WAT_3			0x30000000	/* Bank 1 Write Access Time = 3 cycles */
+#define B1WAT_4			0x40000000	/* Bank 1 Write Access Time = 4 cycles */
+#define B1WAT_5			0x50000000	/* Bank 1 Write Access Time = 5 cycles */
+#define B1WAT_6			0x60000000	/* Bank 1 Write Access Time = 6 cycles */
+#define B1WAT_7			0x70000000	/* Bank 1 Write Access Time = 7 cycles */
+#define B1WAT_8			0x80000000	/* Bank 1 Write Access Time = 8 cycles */
+#define B1WAT_9			0x90000000	/* Bank 1 Write Access Time = 9 cycles */
+#define B1WAT_10		0xA0000000	/* Bank 1 Write Access Time = 10 cycles */
+#define B1WAT_11		0xB0000000	/* Bank 1 Write Access Time = 11 cycles */
+#define B1WAT_12		0xC0000000	/* Bank 1 Write Access Time = 12 cycles */
+#define B1WAT_13		0xD0000000	/* Bank 1 Write Access Time = 13 cycles */
+#define B1WAT_14		0xE0000000	/* Bank 1 Write Access Time = 14 cycles */
+#define B1WAT_15		0xF0000000	/* Bank 1 Write Access Time = 15 cycles */
+
+/* AMBCTL1 Masks */
+#define B2RDYEN			0x00000001	/* Bank 2 RDY Enable, 0=disable, 1=enable */
+#define B2RDYPOL		0x00000002	/* Bank 2 RDY Active high, 0=active low, 1=active high */
+#define B2TT_1			0x00000004	/* Bank 2 Transition Time from Read to Write = 1 cycle */
+#define B2TT_2			0x00000008	/* Bank 2 Transition Time from Read to Write = 2 cycles */
+#define B2TT_3			0x0000000C	/* Bank 2 Transition Time from Read to Write = 3 cycles */
+#define B2TT_4			0x00000000	/* Bank 2 Transition Time from Read to Write = 4 cycles */
+#define B2ST_1			0x00000010	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B2ST_2			0x00000020	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B2ST_3			0x00000030	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B2ST_4			0x00000000	/* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B2HT_1			0x00000040	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B2HT_2			0x00000080	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B2HT_3			0x000000C0	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B2HT_0			0x00000000	/* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B2RAT_1			0x00000100	/* Bank 2 Read Access Time = 1 cycle */
+#define B2RAT_2			0x00000200	/* Bank 2 Read Access Time = 2 cycles */
+#define B2RAT_3			0x00000300	/* Bank 2 Read Access Time = 3 cycles */
+#define B2RAT_4			0x00000400	/* Bank 2 Read Access Time = 4 cycles */
+#define B2RAT_5			0x00000500	/* Bank 2 Read Access Time = 5 cycles */
+#define B2RAT_6			0x00000600	/* Bank 2 Read Access Time = 6 cycles */
+#define B2RAT_7			0x00000700	/* Bank 2 Read Access Time = 7 cycles */
+#define B2RAT_8			0x00000800	/* Bank 2 Read Access Time = 8 cycles */
+#define B2RAT_9			0x00000900	/* Bank 2 Read Access Time = 9 cycles */
+#define B2RAT_10		0x00000A00	/* Bank 2 Read Access Time = 10 cycles */
+#define B2RAT_11		0x00000B00	/* Bank 2 Read Access Time = 11 cycles */
+#define B2RAT_12		0x00000C00	/* Bank 2 Read Access Time = 12 cycles */
+#define B2RAT_13		0x00000D00	/* Bank 2 Read Access Time = 13 cycles */
+#define B2RAT_14		0x00000E00	/* Bank 2 Read Access Time = 14 cycles */
+#define B2RAT_15		0x00000F00	/* Bank 2 Read Access Time = 15 cycles */
+#define B2WAT_1			0x00001000	/* Bank 2 Write Access Time = 1 cycle */
+#define B2WAT_2			0x00002000	/* Bank 2 Write Access Time = 2 cycles */
+#define B2WAT_3			0x00003000	/* Bank 2 Write Access Time = 3 cycles */
+#define B2WAT_4			0x00004000	/* Bank 2 Write Access Time = 4 cycles */
+#define B2WAT_5			0x00005000	/* Bank 2 Write Access Time = 5 cycles */
+#define B2WAT_6			0x00006000	/* Bank 2 Write Access Time = 6 cycles */
+#define B2WAT_7			0x00007000	/* Bank 2 Write Access Time = 7 cycles */
+#define B2WAT_8			0x00008000	/* Bank 2 Write Access Time = 8 cycles */
+#define B2WAT_9			0x00009000	/* Bank 2 Write Access Time = 9 cycles */
+#define B2WAT_10		0x0000A000	/* Bank 2 Write Access Time = 10 cycles */
+#define B2WAT_11		0x0000B000	/* Bank 2 Write Access Time = 11 cycles */
+#define B2WAT_12		0x0000C000	/* Bank 2 Write Access Time = 12 cycles */
+#define B2WAT_13		0x0000D000	/* Bank 2 Write Access Time = 13 cycles */
+#define B2WAT_14		0x0000E000	/* Bank 2 Write Access Time = 14 cycles */
+#define B2WAT_15		0x0000F000	/* Bank 2 Write Access Time = 15 cycles */
+#define B3RDYEN			0x00010000	/* Bank 3 RDY enable, 0=disable, 1=enable */
+#define B3RDYPOL		0x00020000	/* Bank 3 RDY Active high, 0=active low, 1=active high */
+#define B3TT_1			0x00040000	/* Bank 3 Transition Time from Read to Write = 1 cycle */
+#define B3TT_2			0x00080000	/* Bank 3 Transition Time from Read to Write = 2 cycles */
+#define B3TT_3			0x000C0000	/* Bank 3 Transition Time from Read to Write = 3 cycles */
+#define B3TT_4			0x00000000	/* Bank 3 Transition Time from Read to Write = 4 cycles */
+#define B3ST_1			0x00100000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B3ST_2			0x00200000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B3ST_3			0x00300000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B3ST_4			0x00000000	/* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B3HT_1			0x00400000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B3HT_2			0x00800000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B3HT_3			0x00C00000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B3HT_0			0x00000000	/* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B3RAT_1			0x01000000	/* Bank 3 Read Access Time = 1 cycle */
+#define B3RAT_2			0x02000000	/* Bank 3 Read Access Time = 2 cycles */
+#define B3RAT_3			0x03000000	/* Bank 3 Read Access Time = 3 cycles */
+#define B3RAT_4			0x04000000	/* Bank 3 Read Access Time = 4 cycles */
+#define B3RAT_5			0x05000000	/* Bank 3 Read Access Time = 5 cycles */
+#define B3RAT_6			0x06000000	/* Bank 3 Read Access Time = 6 cycles */
+#define B3RAT_7			0x07000000	/* Bank 3 Read Access Time = 7 cycles */
+#define B3RAT_8			0x08000000	/* Bank 3 Read Access Time = 8 cycles */
+#define B3RAT_9			0x09000000	/* Bank 3 Read Access Time = 9 cycles */
+#define B3RAT_10		0x0A000000	/* Bank 3 Read Access Time = 10 cycles */
+#define B3RAT_11		0x0B000000	/* Bank 3 Read Access Time = 11 cycles */
+#define B3RAT_12		0x0C000000	/* Bank 3 Read Access Time = 12 cycles */
+#define B3RAT_13		0x0D000000	/* Bank 3 Read Access Time = 13 cycles */
+#define B3RAT_14		0x0E000000	/* Bank 3 Read Access Time = 14 cycles */
+#define B3RAT_15		0x0F000000	/* Bank 3 Read Access Time = 15 cycles */
+#define B3WAT_1			0x10000000	/* Bank 3 Write Access Time = 1 cycle */
+#define B3WAT_2			0x20000000	/* Bank 3 Write Access Time = 2 cycles */
+#define B3WAT_3			0x30000000	/* Bank 3 Write Access Time = 3 cycles */
+#define B3WAT_4			0x40000000	/* Bank 3 Write Access Time = 4 cycles */
+#define B3WAT_5			0x50000000	/* Bank 3 Write Access Time = 5 cycles */
+#define B3WAT_6			0x60000000	/* Bank 3 Write Access Time = 6 cycles */
+#define B3WAT_7			0x70000000	/* Bank 3 Write Access Time = 7 cycles */
+#define B3WAT_8			0x80000000	/* Bank 3 Write Access Time = 8 cycles */
+#define B3WAT_9			0x90000000	/* Bank 3 Write Access Time = 9 cycles */
+#define B3WAT_10		0xA0000000	/* Bank 3 Write Access Time = 10 cycles */
+#define B3WAT_11		0xB0000000	/* Bank 3 Write Access Time = 11 cycles */
+#define B3WAT_12		0xC0000000	/* Bank 3 Write Access Time = 12 cycles */
+#define B3WAT_13		0xD0000000	/* Bank 3 Write Access Time = 13 cycles */
+#define B3WAT_14		0xE0000000	/* Bank 3 Write Access Time = 14 cycles */
+#define B3WAT_15		0xF0000000	/* Bank 3 Write Access Time = 15 cycles */
+
+/* **********************  SDRAM CONTROLLER MASKS  *************************** */
+
+/* EBIU_SDGCTL Masks */
+#define SCTLE			0x00000001	/* Enable SCLK[0], /SRAS, /SCAS, /SWE, SDQM[3:0] */
+#define CL_2			0x00000008	/* SDRAM CAS latency = 2 cycles */
+#define CL_3			0x0000000C	/* SDRAM CAS latency = 3 cycles */
+#define PFE			0x00000010	/* Enable SDRAM prefetch */
+#define PFP			0x00000020	/* Prefetch has priority over AMC requests */
+#define TRAS_1			0x00000040	/* SDRAM tRAS = 1 cycle */
+#define TRAS_2			0x00000080	/* SDRAM tRAS = 2 cycles */
+#define TRAS_3			0x000000C0	/* SDRAM tRAS = 3 cycles */
+#define TRAS_4			0x00000100	/* SDRAM tRAS = 4 cycles */
+#define TRAS_5			0x00000140	/* SDRAM tRAS = 5 cycles */
+#define TRAS_6			0x00000180	/* SDRAM tRAS = 6 cycles */
+#define TRAS_7			0x000001C0	/* SDRAM tRAS = 7 cycles */
+#define TRAS_8			0x00000200	/* SDRAM tRAS = 8 cycles */
+#define TRAS_9			0x00000240	/* SDRAM tRAS = 9 cycles */
+#define TRAS_10			0x00000280	/* SDRAM tRAS = 10 cycles */
+#define TRAS_11			0x000002C0	/* SDRAM tRAS = 11 cycles */
+#define TRAS_12			0x00000300	/* SDRAM tRAS = 12 cycles */
+#define TRAS_13			0x00000340	/* SDRAM tRAS = 13 cycles */
+#define TRAS_14			0x00000380	/* SDRAM tRAS = 14 cycles */
+#define TRAS_15			0x000003C0	/* SDRAM tRAS = 15 cycles */
+#define TRP_1			0x00000800	/* SDRAM tRP = 1 cycle */
+#define TRP_2			0x00001000	/* SDRAM tRP = 2 cycles */
+#define TRP_3			0x00001800	/* SDRAM tRP = 3 cycles */
+#define TRP_4			0x00002000	/* SDRAM tRP = 4 cycles */
+#define TRP_5			0x00002800	/* SDRAM tRP = 5 cycles */
+#define TRP_6			0x00003000	/* SDRAM tRP = 6 cycles */
+#define TRP_7			0x00003800	/* SDRAM tRP = 7 cycles */
+#define TRCD_1			0x00008000	/* SDRAM tRCD = 1 cycle */
+#define TRCD_2			0x00010000	/* SDRAM tRCD = 2 cycles */
+#define TRCD_3			0x00018000	/* SDRAM tRCD = 3 cycles */
+#define TRCD_4			0x00020000	/* SDRAM tRCD = 4 cycles */
+#define TRCD_5			0x00028000	/* SDRAM tRCD = 5 cycles */
+#define TRCD_6			0x00030000	/* SDRAM tRCD = 6 cycles */
+#define TRCD_7			0x00038000	/* SDRAM tRCD = 7 cycles */
+#define TWR_1			0x00080000	/* SDRAM tWR = 1 cycle */
+#define TWR_2			0x00100000	/* SDRAM tWR = 2 cycles */
+#define TWR_3			0x00180000	/* SDRAM tWR = 3 cycles */
+#define PUPSD			0x00200000	/*Power-up start delay */
+#define PSM			0x00400000	/* SDRAM power-up sequence = Precharge, mode register set, 8 CBR refresh cycles */
+#define PSS				0x00800000	/* enable SDRAM power-up sequence on next SDRAM access */
+#define SRFS			0x01000000	/* Start SDRAM self-refresh mode */
+#define EBUFE			0x02000000	/* Enable external buffering timing */
+#define FBBRW			0x04000000	/* Fast back-to-back read write enable */
+#define EMREN			0x10000000	/* Extended mode register enable */
+#define TCSR			0x20000000	/* Temp compensated self refresh value 85 deg C */
+#define CDDBG			0x40000000	/* Tristate SDRAM controls during bus grant */
+
+/* EBIU_SDBCTL Masks */
+#define EB0_E				0x00000001	/* Enable SDRAM external bank 0 */
+#define EB0_SZ_16			0x00000000	/* SDRAM external bank size = 16MB */
+#define EB0_SZ_32			0x00000002	/* SDRAM external bank size = 32MB */
+#define EB0_SZ_64			0x00000004	/* SDRAM external bank size = 64MB */
+#define EB0_SZ_128			0x00000006	/* SDRAM external bank size = 128MB */
+#define EB0_CAW_8			0x00000000	/* SDRAM external bank column address width = 8 bits */
+#define EB0_CAW_9			0x00000010	/* SDRAM external bank column address width = 9 bits */
+#define EB0_CAW_10			0x00000020	/* SDRAM external bank column address width = 9 bits */
+#define EB0_CAW_11			0x00000030	/* SDRAM external bank column address width = 9 bits */
+
+#define EB1_E				0x00000100	/* Enable SDRAM external bank 1 */
+#define EB1__SZ_16			0x00000000	/* SDRAM external bank size = 16MB */
+#define EB1__SZ_32			0x00000200	/* SDRAM external bank size = 32MB */
+#define EB1__SZ_64			0x00000400	/* SDRAM external bank size = 64MB */
+#define EB1__SZ_128			0x00000600	/* SDRAM external bank size = 128MB */
+#define EB1__CAW_8			0x00000000	/* SDRAM external bank column address width = 8 bits */
+#define EB1__CAW_9			0x00001000	/* SDRAM external bank column address width = 9 bits */
+#define EB1__CAW_10			0x00002000	/* SDRAM external bank column address width = 9 bits */
+#define EB1__CAW_11			0x00003000	/* SDRAM external bank column address width = 9 bits */
+
+#define EB2__E				0x00010000	/* Enable SDRAM external bank 2 */
+#define EB2__SZ_16			0x00000000	/* SDRAM external bank size = 16MB */
+#define EB2__SZ_32			0x00020000	/* SDRAM external bank size = 32MB */
+#define EB2__SZ_64			0x00040000	/* SDRAM external bank size = 64MB */
+#define EB2__SZ_128			0x00060000	/* SDRAM external bank size = 128MB */
+#define EB2__CAW_8			0x00000000	/* SDRAM external bank column address width = 8 bits */
+#define EB2__CAW_9			0x00100000	/* SDRAM external bank column address width = 9 bits */
+#define EB2__CAW_10			0x00200000	/* SDRAM external bank column address width = 9 bits */
+#define EB2__CAW_11			0x00300000	/* SDRAM external bank column address width = 9 bits */
+
+#define EB3__E				0x01000000	/* Enable SDRAM external bank 3 */
+#define EB3__SZ_16			0x00000000	/* SDRAM external bank size = 16MB */
+#define EB3__SZ_32			0x02000000	/* SDRAM external bank size = 32MB */
+#define EB3__SZ_64			0x04000000	/* SDRAM external bank size = 64MB */
+#define EB3__SZ_128			0x06000000	/* SDRAM external bank size = 128MB */
+#define EB3__CAW_8			0x00000000	/* SDRAM external bank column address width = 8 bits */
+#define EB3__CAW_9			0x10000000	/* SDRAM external bank column address width = 9 bits */
+#define EB3__CAW_10			0x20000000	/* SDRAM external bank column address width = 9 bits */
+#define EB3__CAW_11			0x30000000	/* SDRAM external bank column address width = 9 bits */
+
+/* EBIU_SDSTAT Masks */
+#define SDCI			0x00000001	/* SDRAM controller is idle  */
+#define SDSRA			0x00000002	/* SDRAM SDRAM self refresh is active */
+#define SDPUA			0x00000004	/* SDRAM power up active  */
+#define SDRS			0x00000008	/* SDRAM is in reset state */
+#define SDEASE		    0x00000010	/* SDRAM EAB sticky error status - W1C */
+#define BGSTAT			0x00000020	/* Bus granted */
+
+/*VR_CTL Masks*/
+#define WAKE                    0x100
+#define VLEV_6                  0x60
+#define VLEV_7                  0x70
+#define VLEV_8                  0x80
+#define VLEV_9                  0x90
+#define VLEV_10                 0xA0
+#define VLEV_11                 0xB0
+#define VLEV_12                 0xC0
+#define VLEV_13                 0xD0
+#define VLEV_14                 0xE0
+#define VLEV_15                 0xF0
+#define FREQ_3                  0x03
+
+#endif				/* _DEF_BF561_H */
diff --git a/include/asm-blackfin/mach-bf561/dma.h b/include/asm-blackfin/mach-bf561/dma.h
new file mode 100644
index 0000000..21d9820
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/dma.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+*
+*        BF-533/2/1 Specific Declarations
+*
+****************************************************************************/
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 36
+
+#define CH_PPI0			0
+#define CH_PPI			(CH_PPI0)
+#define CH_PPI1			1
+#define CH_SPORT0_RX		12
+#define CH_SPORT0_TX		13
+#define CH_SPORT1_RX		14
+#define CH_SPORT1_TX		15
+#define CH_SPI			16
+#define CH_UART_RX		17
+#define CH_UART_TX		18
+#define CH_MEM_STREAM0_DEST     24	 /* TX */
+#define CH_MEM_STREAM0_SRC      25	 /* RX */
+#define CH_MEM_STREAM1_DEST     26	 /* TX */
+#define CH_MEM_STREAM1_SRC      27	 /* RX */
+#define CH_MEM_STREAM2_DEST	28
+#define CH_MEM_STREAM2_SRC	29
+#define CH_MEM_STREAM3_SRC	30
+#define CH_MEM_STREAM3_DEST	31
+#define CH_IMEM_STREAM0_DEST	32
+#define CH_IMEM_STREAM0_SRC	33
+#define CH_IMEM_STREAM1_SRC	34
+#define CH_IMEM_STREAM1_DEST	35
+
+#endif
diff --git a/include/asm-blackfin/mach-bf561/irq.h b/include/asm-blackfin/mach-bf561/irq.h
new file mode 100644
index 0000000..a753ce7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/irq.h
@@ -0,0 +1,450 @@
+
+/*
+ * File:         include/asm-blackfin/mach-bf561/irq.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BF561_IRQ_H_
+#define _BF561_IRQ_H_
+
+/***********************************************************************
+ * Interrupt source definitions:
+             Event Source		Core Event Name	    IRQ No
+						(highest priority)
+	    Emulation Events			EMU         0
+            Reset				RST         1
+            NMI					NMI         2
+            Exception				EVX         3
+            Reserved				--          4
+            Hardware Error			IVHW        5
+            Core Timer				IVTMR       6 *
+
+	    PLL Wakeup Interrupt		IVG7	    7
+	    DMA1 Error (generic)		IVG7	    8
+	    DMA2 Error (generic)		IVG7	    9
+	    IMDMA Error (generic)		IVG7	    10
+	    PPI1 Error Interrupt		IVG7	    11
+	    PPI2 Error Interrupt		IVG7	    12
+	    SPORT0 Error Interrupt		IVG7	    13
+	    SPORT1 Error Interrupt		IVG7	    14
+	    SPI Error Interrupt			IVG7	    15
+	    UART Error Interrupt		IVG7	    16
+	    Reserved Interrupt			IVG7        17
+
+	    DMA1 0  Interrupt(PPI1)	        IVG8	    18
+	    DMA1 1  Interrupt(PPI2)             IVG8	    19
+	    DMA1 2  Interrupt	                IVG8	    20
+	    DMA1 3  Interrupt	                IVG8	    21
+	    DMA1 4  Interrupt	                IVG8	    22
+	    DMA1 5  Interrupt	                IVG8	    23
+	    DMA1 6  Interrupt	                IVG8	    24
+	    DMA1 7  Interrupt	                IVG8	    25
+	    DMA1 8  Interrupt	                IVG8	    26
+	    DMA1 9  Interrupt	                IVG8	    27
+	    DMA1 10 Interrupt	                IVG8	    28
+	    DMA1 11 Interrupt	                IVG8	    29
+
+	    DMA2 0  (SPORT0 RX)		        IVG9	    30
+	    DMA2 1  (SPORT0 TX)	                IVG9	    31
+	    DMA2 2  (SPORT1 RX)	                IVG9	    32
+	    DMA2 3  (SPORT2 TX)	                IVG9	    33
+	    DMA2 4  (SPI)	                IVG9	    34
+	    DMA2 5  (UART RX)	                IVG9	    35
+	    DMA2 6  (UART TX)	                IVG9	    36
+	    DMA2 7  Interrupt	                IVG9	    37
+	    DMA2 8  Interrupt	                IVG9	    38
+	    DMA2 9  Interrupt	                IVG9	    39
+	    DMA2 10 Interrupt	                IVG9	    40
+	    DMA2 11 Interrupt	                IVG9	    41
+
+	    TIMER 0  Interrupt		        IVG10	    42
+	    TIMER 1  Interrupt	                IVG10	    43
+	    TIMER 2  Interrupt	                IVG10	    44
+	    TIMER 3  Interrupt	                IVG10	    45
+	    TIMER 4  Interrupt	                IVG10	    46
+	    TIMER 5  Interrupt	                IVG10	    47
+	    TIMER 6  Interrupt	                IVG10	    48
+	    TIMER 7  Interrupt	                IVG10	    49
+	    TIMER 8  Interrupt	                IVG10	    50
+	    TIMER 9  Interrupt	                IVG10	    51
+	    TIMER 10 Interrupt	                IVG10	    52
+	    TIMER 11 Interrupt	                IVG10	    53
+
+	    Programmable Flags0 A (8)	        IVG11	    54
+	    Programmable Flags0 B (8)           IVG11	    55
+	    Programmable Flags1 A (8)           IVG11	    56
+	    Programmable Flags1 B (8)           IVG11	    57
+	    Programmable Flags2 A (8)           IVG11	    58
+	    Programmable Flags2 B (8)           IVG11	    59
+
+	    MDMA1 0 write/read INT		IVG8	    60
+	    MDMA1 1 write/read INT		IVG8	    61
+
+	    MDMA2 0 write/read INT		IVG9	    62
+	    MDMA2 1 write/read INT		IVG9	    63
+
+	    IMDMA 0 write/read INT		IVG12	    64
+	    IMDMA 1 write/read INT		IVG12	    65
+
+	    Watch Dog Timer			IVG13	    66
+
+	    Reserved interrupt			IVG7	    67
+	    Reserved interrupt			IVG7	    68
+	    Supplemental interrupt 0		IVG7	    69
+	    supplemental interrupt 1		IVG7	    70
+
+            Software Interrupt 1		IVG14       71
+            Software Interrupt 2		IVG15       72 *
+						(lowest priority)
+ **********************************************************************/
+
+#define SYS_IRQS		72
+#define NR_PERI_INTS		64
+
+/*
+ * The ABSTRACT IRQ definitions
+ *  the first seven of the following are fixed,
+ *  the rest you change if you need to.
+ */
+/* IVG 0-6*/
+#define	IRQ_EMU			0	/* Emulation                */
+#define	IRQ_RST			1	/* Reset                    */
+#define	IRQ_NMI			2	/* Non Maskable Interrupt   */
+#define	IRQ_EVX			3	/* Exception                */
+#define	IRQ_UNUSED		4	/* Reserved interrupt       */
+#define	IRQ_HWERR		5	/* Hardware Error           */
+#define	IRQ_CORETMR		6	/* Core timer               */
+
+#define IVG_BASE		7
+/* IVG 7  */
+#define	IRQ_PLL_WAKEUP		(IVG_BASE + 0)	/* PLL Wakeup Interrupt     */
+#define	IRQ_DMA1_ERROR		(IVG_BASE + 1)	/* DMA1   Error (general)   */
+#define	IRQ_DMA_ERROR		IRQ_DMA1_ERROR	/* DMA1   Error (general)   */
+#define	IRQ_DMA2_ERROR		(IVG_BASE + 2)	/* DMA2   Error (general)   */
+#define IRQ_IMDMA_ERROR		(IVG_BASE + 3)	/* IMDMA  Error Interrupt   */
+#define	IRQ_PPI1_ERROR		(IVG_BASE + 4)	/* PPI1   Error Interrupt   */
+#define	IRQ_PPI_ERROR		IRQ_PPI1_ERROR	/* PPI1   Error Interrupt   */
+#define	IRQ_PPI2_ERROR		(IVG_BASE + 5)	/* PPI2   Error Interrupt   */
+#define	IRQ_SPORT0_ERROR	(IVG_BASE + 6)	/* SPORT0 Error Interrupt   */
+#define	IRQ_SPORT1_ERROR	(IVG_BASE + 7)	/* SPORT1 Error Interrupt   */
+#define	IRQ_SPI_ERROR		(IVG_BASE + 8)	/* SPI    Error Interrupt   */
+#define	IRQ_UART_ERROR		(IVG_BASE + 9)	/* UART   Error Interrupt   */
+#define IRQ_RESERVED_ERROR	(IVG_BASE + 10)	/* Reversed     Interrupt   */
+/* IVG 8  */
+#define	IRQ_DMA1_0		(IVG_BASE + 11)	/* DMA1 0  Interrupt(PPI1)  */
+#define	IRQ_PPI			IRQ_DMA1_0	/* DMA1 0  Interrupt(PPI1)  */
+#define	IRQ_PPI0		IRQ_DMA1_0	/* DMA1 0  Interrupt(PPI1)  */
+#define	IRQ_DMA1_1		(IVG_BASE + 12)	/* DMA1 1  Interrupt(PPI2)  */
+#define	IRQ_PPI1		IRQ_DMA1_1	/* DMA1 1  Interrupt(PPI2)  */
+#define	IRQ_DMA1_2		(IVG_BASE + 13)	/* DMA1 2  Interrupt        */
+#define	IRQ_DMA1_3		(IVG_BASE + 14)	/* DMA1 3  Interrupt        */
+#define	IRQ_DMA1_4		(IVG_BASE + 15)	/* DMA1 4  Interrupt        */
+#define	IRQ_DMA1_5		(IVG_BASE + 16)	/* DMA1 5  Interrupt        */
+#define	IRQ_DMA1_6		(IVG_BASE + 17)	/* DMA1 6  Interrupt        */
+#define	IRQ_DMA1_7		(IVG_BASE + 18)	/* DMA1 7  Interrupt        */
+#define	IRQ_DMA1_8		(IVG_BASE + 19)	/* DMA1 8  Interrupt        */
+#define	IRQ_DMA1_9		(IVG_BASE + 20)	/* DMA1 9  Interrupt        */
+#define	IRQ_DMA1_10		(IVG_BASE + 21)	/* DMA1 10 Interrupt        */
+#define	IRQ_DMA1_11		(IVG_BASE + 22)	/* DMA1 11 Interrupt        */
+/* IVG 9  */
+#define	IRQ_DMA2_0		(IVG_BASE + 23)	/* DMA2 0  (SPORT0 RX)      */
+#define	IRQ_SPORT0_RX		IRQ_DMA2_0	/* DMA2 0  (SPORT0 RX)      */
+#define	IRQ_DMA2_1		(IVG_BASE + 24)	/* DMA2 1  (SPORT0 TX)      */
+#define	IRQ_SPORT0_TX		IRQ_DMA2_1	/* DMA2 1  (SPORT0 TX)      */
+#define	IRQ_DMA2_2		(IVG_BASE + 25)	/* DMA2 2  (SPORT1 RX)      */
+#define	IRQ_SPORT1_RX		IRQ_DMA2_2	/* DMA2 2  (SPORT1 RX)      */
+#define	IRQ_DMA2_3		(IVG_BASE + 26)	/* DMA2 3  (SPORT2 TX)      */
+#define	IRQ_SPORT1_TX		IRQ_DMA2_3	/* DMA2 3  (SPORT2 TX)      */
+#define	IRQ_DMA2_4		(IVG_BASE + 27)	/* DMA2 4  (SPI)            */
+#define	IRQ_SPI			IRQ_DMA2_4	/* DMA2 4  (SPI)            */
+#define	IRQ_DMA2_5		(IVG_BASE + 28)	/* DMA2 5  (UART RX)        */
+#define	IRQ_UART_RX		IRQ_DMA2_5	/* DMA2 5  (UART RX)        */
+#define	IRQ_DMA2_6		(IVG_BASE + 29)	/* DMA2 6  (UART TX)        */
+#define	IRQ_UART_TX		IRQ_DMA2_6	/* DMA2 6  (UART TX)        */
+#define	IRQ_DMA2_7		(IVG_BASE + 30)	/* DMA2 7  Interrupt        */
+#define	IRQ_DMA2_8		(IVG_BASE + 31)	/* DMA2 8  Interrupt        */
+#define	IRQ_DMA2_9		(IVG_BASE + 32)	/* DMA2 9  Interrupt        */
+#define	IRQ_DMA2_10		(IVG_BASE + 33)	/* DMA2 10 Interrupt        */
+#define	IRQ_DMA2_11		(IVG_BASE + 34)	/* DMA2 11 Interrupt        */
+/* IVG 10 */
+#define IRQ_TIMER0		(IVG_BASE + 35)	/* TIMER 0  Interrupt       */
+#define IRQ_TIMER1		(IVG_BASE + 36)	/* TIMER 1  Interrupt       */
+#define IRQ_TIMER2		(IVG_BASE + 37)	/* TIMER 2  Interrupt       */
+#define IRQ_TIMER3		(IVG_BASE + 38)	/* TIMER 3  Interrupt       */
+#define IRQ_TIMER4		(IVG_BASE + 39)	/* TIMER 4  Interrupt       */
+#define IRQ_TIMER5		(IVG_BASE + 40)	/* TIMER 5  Interrupt       */
+#define IRQ_TIMER6		(IVG_BASE + 41)	/* TIMER 6  Interrupt       */
+#define IRQ_TIMER7		(IVG_BASE + 42)	/* TIMER 7  Interrupt       */
+#define IRQ_TIMER8		(IVG_BASE + 43)	/* TIMER 8  Interrupt       */
+#define IRQ_TIMER9		(IVG_BASE + 44)	/* TIMER 9  Interrupt       */
+#define IRQ_TIMER10		(IVG_BASE + 45)	/* TIMER 10 Interrupt       */
+#define IRQ_TIMER11		(IVG_BASE + 46)	/* TIMER 11 Interrupt       */
+/* IVG 11 */
+#define	IRQ_PROG0_INTA		(IVG_BASE + 47)	/* Programmable Flags0 A (8) */
+#define	IRQ_PROG_INTA		IRQ_PROG0_INTA	/* Programmable Flags0 A (8) */
+#define	IRQ_PROG0_INTB		(IVG_BASE + 48)	/* Programmable Flags0 B (8) */
+#define	IRQ_PROG_INTB		IRQ_PROG0_INTB	/* Programmable Flags0 B (8) */
+#define	IRQ_PROG1_INTA		(IVG_BASE + 49)	/* Programmable Flags1 A (8) */
+#define	IRQ_PROG1_INTB		(IVG_BASE + 50)	/* Programmable Flags1 B (8) */
+#define	IRQ_PROG2_INTA		(IVG_BASE + 51)	/* Programmable Flags2 A (8) */
+#define	IRQ_PROG2_INTB		(IVG_BASE + 52)	/* Programmable Flags2 B (8) */
+/* IVG 8  */
+#define IRQ_DMA1_WRRD0		(IVG_BASE + 53)	/* MDMA1 0 write/read INT   */
+#define IRQ_DMA_WRRD0		IRQ_DMA1_WRRD0	/* MDMA1 0 write/read INT   */
+#define IRQ_MEM_DMA0		IRQ_DMA1_WRRD0
+#define IRQ_DMA1_WRRD1		(IVG_BASE + 54)	/* MDMA1 1 write/read INT   */
+#define IRQ_DMA_WRRD1		IRQ_DMA1_WRRD1	/* MDMA1 1 write/read INT   */
+#define IRQ_MEM_DMA1		IRQ_DMA1_WRRD1
+/* IVG 9  */
+#define IRQ_DMA2_WRRD0		(IVG_BASE + 55)	/* MDMA2 0 write/read INT   */
+#define IRQ_MEM_DMA2		IRQ_DMA2_WRRD0
+#define IRQ_DMA2_WRRD1		(IVG_BASE + 56)	/* MDMA2 1 write/read INT   */
+#define IRQ_MEM_DMA3		IRQ_DMA2_WRRD1
+/* IVG 12 */
+#define IRQ_IMDMA_WRRD0		(IVG_BASE + 57)	/* IMDMA 0 write/read INT   */
+#define IRQ_IMEM_DMA0		IRQ_IMDMA_WRRD0
+#define IRQ_IMDMA_WRRD1		(IVG_BASE + 58)	/* IMDMA 1 write/read INT   */
+#define IRQ_IMEM_DMA1		IRQ_IMDMA_WRRD1
+/* IVG 13 */
+#define	IRQ_WATCH	   	(IVG_BASE + 59)	/* Watch Dog Timer          */
+/* IVG 7  */
+#define IRQ_RESERVED_1		(IVG_BASE + 60)	/* Reserved interrupt       */
+#define IRQ_RESERVED_2		(IVG_BASE + 61)	/* Reserved interrupt       */
+#define IRQ_SUPPLE_0		(IVG_BASE + 62)	/* Supplemental interrupt 0 */
+#define IRQ_SUPPLE_1		(IVG_BASE + 63)	/* supplemental interrupt 1 */
+#define	IRQ_SW_INT1		71	/* Software Interrupt 1     */
+#define	IRQ_SW_INT2		72	/* Software Interrupt 2     */
+						/* reserved for SYSCALL */
+#define IRQ_PF0			73
+#define IRQ_PF1			74
+#define IRQ_PF2			75
+#define IRQ_PF3			76
+#define IRQ_PF4			77
+#define IRQ_PF5			78
+#define IRQ_PF6			79
+#define IRQ_PF7			80
+#define IRQ_PF8			81
+#define IRQ_PF9			82
+#define IRQ_PF10		83
+#define IRQ_PF11		84
+#define IRQ_PF12		85
+#define IRQ_PF13		86
+#define IRQ_PF14		87
+#define IRQ_PF15		88
+#define IRQ_PF16		89
+#define IRQ_PF17		90
+#define IRQ_PF18		91
+#define IRQ_PF19		92
+#define IRQ_PF20		93
+#define IRQ_PF21		94
+#define IRQ_PF22		95
+#define IRQ_PF23		96
+#define IRQ_PF24		97
+#define IRQ_PF25		98
+#define IRQ_PF26		99
+#define IRQ_PF27		100
+#define IRQ_PF28		101
+#define IRQ_PF29		102
+#define IRQ_PF30		103
+#define IRQ_PF31		104
+#define IRQ_PF32		105
+#define IRQ_PF33		106
+#define IRQ_PF34		107
+#define IRQ_PF35		108
+#define IRQ_PF36		109
+#define IRQ_PF37		110
+#define IRQ_PF38		111
+#define IRQ_PF39		112
+#define IRQ_PF40		113
+#define IRQ_PF41		114
+#define IRQ_PF42		115
+#define IRQ_PF43		116
+#define IRQ_PF44		117
+#define IRQ_PF45		118
+#define IRQ_PF46		119
+#define IRQ_PF47		120
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS			(IRQ_PF47 + 1)
+#else
+#define NR_IRQS			SYS_IRQS
+#endif
+
+#define IVG7			7
+#define IVG8			8
+#define IVG9			9
+#define IVG10			10
+#define IVG11			11
+#define IVG12			12
+#define IVG13			13
+#define IVG14			14
+#define IVG15			15
+
+/*
+ * DEFAULT PRIORITIES:
+ */
+
+#define	CONFIG_DEF_PLL_WAKEUP		7
+#define	CONFIG_DEF_DMA1_ERROR		7
+#define	CONFIG_DEF_DMA2_ERROR		7
+#define CONFIG_DEF_IMDMA_ERROR		7
+#define	CONFIG_DEF_PPI1_ERROR		7
+#define	CONFIG_DEF_PPI2_ERROR		7
+#define	CONFIG_DEF_SPORT0_ERROR		7
+#define	CONFIG_DEF_SPORT1_ERROR		7
+#define	CONFIG_DEF_SPI_ERROR		7
+#define	CONFIG_DEF_UART_ERROR		7
+#define CONFIG_DEF_RESERVED_ERROR	7
+#define	CONFIG_DEF_DMA1_0		8
+#define	CONFIG_DEF_DMA1_1		8
+#define	CONFIG_DEF_DMA1_2		8
+#define	CONFIG_DEF_DMA1_3		8
+#define	CONFIG_DEF_DMA1_4		8
+#define	CONFIG_DEF_DMA1_5		8
+#define	CONFIG_DEF_DMA1_6		8
+#define	CONFIG_DEF_DMA1_7		8
+#define	CONFIG_DEF_DMA1_8		8
+#define	CONFIG_DEF_DMA1_9		8
+#define	CONFIG_DEF_DMA1_10		8
+#define	CONFIG_DEF_DMA1_11		8
+#define	CONFIG_DEF_DMA2_0		9
+#define	CONFIG_DEF_DMA2_1		9
+#define	CONFIG_DEF_DMA2_2		9
+#define	CONFIG_DEF_DMA2_3		9
+#define	CONFIG_DEF_DMA2_4		9
+#define	CONFIG_DEF_DMA2_5		9
+#define	CONFIG_DEF_DMA2_6		9
+#define	CONFIG_DEF_DMA2_7		9
+#define	CONFIG_DEF_DMA2_8		9
+#define	CONFIG_DEF_DMA2_9		9
+#define	CONFIG_DEF_DMA2_10		9
+#define	CONFIG_DEF_DMA2_11		9
+#define CONFIG_DEF_TIMER0		10
+#define CONFIG_DEF_TIMER1		10
+#define CONFIG_DEF_TIMER2		10
+#define CONFIG_DEF_TIMER3		10
+#define CONFIG_DEF_TIMER4		10
+#define CONFIG_DEF_TIMER5		10
+#define CONFIG_DEF_TIMER6		10
+#define CONFIG_DEF_TIMER7		10
+#define CONFIG_DEF_TIMER8		10
+#define CONFIG_DEF_TIMER9		10
+#define CONFIG_DEF_TIMER10		10
+#define CONFIG_DEF_TIMER11		10
+#define	CONFIG_DEF_PROG0_INTA		11
+#define	CONFIG_DEF_PROG0_INTB		11
+#define	CONFIG_DEF_PROG1_INTA		11
+#define	CONFIG_DEF_PROG1_INTB		11
+#define	CONFIG_DEF_PROG2_INTA		11
+#define	CONFIG_DEF_PROG2_INTB		11
+#define CONFIG_DEF_DMA1_WRRD0		8
+#define CONFIG_DEF_DMA1_WRRD1		8
+#define CONFIG_DEF_DMA2_WRRD0		9
+#define CONFIG_DEF_DMA2_WRRD1		9
+#define CONFIG_DEF_IMDMA_WRRD0		12
+#define CONFIG_DEF_IMDMA_WRRD1		12
+#define	CONFIG_DEF_WATCH	   	13
+#define CONFIG_DEF_RESERVED_1		7
+#define CONFIG_DEF_RESERVED_2		7
+#define CONFIG_DEF_SUPPLE_0		7
+#define CONFIG_DEF_SUPPLE_1		7
+
+/* IAR0 BIT FIELDS */
+#define	IRQ_PLL_WAKEUP_POS			0
+#define	IRQ_DMA1_ERROR_POS			4
+#define	IRQ_DMA2_ERROR_POS			8
+#define IRQ_IMDMA_ERROR_POS			12
+#define	IRQ_PPI0_ERROR_POS			16
+#define	IRQ_PPI1_ERROR_POS			20
+#define	IRQ_SPORT0_ERROR_POS		24
+#define	IRQ_SPORT1_ERROR_POS		28
+/* IAR1 BIT FIELDS */
+#define	IRQ_SPI_ERROR_POS			0
+#define	IRQ_UART_ERROR_POS			4
+#define IRQ_RESERVED_ERROR_POS		8
+#define	IRQ_DMA1_0_POS			12
+#define	IRQ_DMA1_1_POS			16
+#define IRQ_DMA1_2_POS			20
+#define IRQ_DMA1_3_POS			24
+#define IRQ_DMA1_4_POS			28
+/* IAR2 BIT FIELDS */
+#define IRQ_DMA1_5_POS			0
+#define IRQ_DMA1_6_POS			4
+#define IRQ_DMA1_7_POS			8
+#define IRQ_DMA1_8_POS			12
+#define IRQ_DMA1_9_POS			16
+#define IRQ_DMA1_10_POS			20
+#define IRQ_DMA1_11_POS			24
+#define IRQ_DMA2_0_POS			28
+/* IAR3 BIT FIELDS */
+#define IRQ_DMA2_1_POS			0
+#define IRQ_DMA2_2_POS			4
+#define IRQ_DMA2_3_POS			8
+#define IRQ_DMA2_4_POS			12
+#define IRQ_DMA2_5_POS			16
+#define IRQ_DMA2_6_POS			20
+#define IRQ_DMA2_7_POS			24
+#define IRQ_DMA2_8_POS			28
+/* IAR4 BIT FIELDS */
+#define IRQ_DMA2_9_POS			0
+#define IRQ_DMA2_10_POS			4
+#define IRQ_DMA2_11_POS			8
+#define IRQ_TIMER0_POS			12
+#define IRQ_TIMER1_POS			16
+#define IRQ_TIMER2_POS			20
+#define IRQ_TIMER3_POS			24
+#define IRQ_TIMER4_POS			28
+/* IAR5 BIT FIELDS */
+#define IRQ_TIMER5_POS			0
+#define IRQ_TIMER6_POS			4
+#define IRQ_TIMER7_POS			8
+#define IRQ_TIMER8_POS			12
+#define IRQ_TIMER9_POS			16
+#define IRQ_TIMER10_POS			20
+#define IRQ_TIMER11_POS			24
+#define IRQ_PROG0_INTA_POS			28
+/* IAR6 BIT FIELDS */
+#define IRQ_PROG0_INTB_POS			0
+#define IRQ_PROG1_INTA_POS			4
+#define IRQ_PROG1_INTB_POS			8
+#define IRQ_PROG2_INTA_POS			12
+#define IRQ_PROG2_INTB_POS			16
+#define IRQ_DMA1_WRRD0_POS			20
+#define IRQ_DMA1_WRRD1_POS			24
+#define IRQ_DMA2_WRRD0_POS			28
+/* IAR7 BIT FIELDS */
+#define IRQ_DMA2_WRRD1_POS			0
+#define IRQ_IMDMA_WRRD0_POS			4
+#define IRQ_IMDMA_WRRD1_POS			8
+#define	IRQ_WDTIMER_POS			12
+#define IRQ_RESERVED_1_POS			16
+#define IRQ_RESERVED_2_POS			20
+#define IRQ_SUPPLE_0_POS			24
+#define IRQ_SUPPLE_1_POS			28
+
+#endif				/* _BF561_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf561/mem_init.h b/include/asm-blackfin/mach-bf561/mem_init.h
new file mode 100644
index 0000000..439a589
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/mem_init.h
@@ -0,0 +1,322 @@
+/*
+ * File:         include/asm-blackfin/mach-bf561/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_GENERIC_BOARD || CONFIG_MEM_MT48LC8M32B2B5_7)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_7
+#define SDRAM_tRAS_num  7
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_6
+#define SDRAM_tRAS_num  6
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_5
+#define SDRAM_tRAS_num  5
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  4
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP       TRP_2
+#define SDRAM_tRP_num   2
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_2
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_4
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_3
+#define SDRAM_tRAS_num  3
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_2
+#define SDRAM_tRAS_num  2
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP       TRP_1
+#define SDRAM_tRP_num   1
+#define SDRAM_tRAS      TRAS_1
+#define SDRAM_tRAS_num  1
+#define SDRAM_tRCD      TRCD_1
+#define SDRAM_tWR       TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC8M32B2B5_7)
+  /*SDRAM INFORMATION: */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   4096	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+  /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref  64		/* Refresh period in milliseconds   */
+#define SDRAM_NRA   8192	/* Number of row addresses in SDRAM */
+#define SDRAM_CL    CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE      EB0_SZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE      EB0_SZ_64
+#endif
+#if ( CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE      EB0_SZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE      EB0_SZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH     EB0_CAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH     EB0_CAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH     EB0_CAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH     EB0_CAW_8
+#endif
+
+#define mem_SDBCTL      (SDRAM_WIDTH | SDRAM_SIZE | EB0_E)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC       (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL        (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF       1
+#else
+#define CLKIN_HALF       0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS      1
+#else
+#define PLL_BYPASS       0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT  ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT  ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT   ((CONFIG_FLASH_SPEED_BHT  * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST   ((CONFIG_FLASH_SPEED_BST  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT   ((CONFIG_FLASH_SPEED_BTT  * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT   B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT   B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST   B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST   B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT   B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT   B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT  B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT  B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0  \
+	(flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+	 flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf561/mem_map.h b/include/asm-blackfin/mach-bf561/mem_map.h
new file mode 100644
index 0000000..ebac9a8
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/mem_map.h
@@ -0,0 +1,75 @@
+/*
+ * Memory MAP
+ * Common header file for blackfin BF561 of processors.
+ */
+
+#ifndef _MEM_MAP_561_H_
+#define _MEM_MAP_561_H_
+
+#define COREMMR_BASE           0xFFE00000	 /* Core MMRs */
+#define SYSMMR_BASE            0xFFC00000	 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE	0x2C000000	 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE	0x04000000	/* 64M */
+#define ASYNC_BANK2_BASE	0x28000000	 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE	0x04000000	/* 64M */
+#define ASYNC_BANK1_BASE	0x24000000	 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE	0x04000000	/* 64M */
+#define ASYNC_BANK0_BASE	0x20000000	 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE	0x04000000	/* 64M */
+
+/* Level 1 Memory */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE	(16*1024)
+#else
+#define BLKFIN_ICACHESIZE	(0*1024)
+#endif
+
+/* Memory Map for ADSP-BF561 processors */
+
+#ifdef CONFIG_BF561
+#define L1_CODE_START     0xFFA00000
+#define L1_DATA_A_START     0xFF800000
+#define L1_DATA_B_START     0xFF900000
+
+#define L1_CODE_LENGTH      0x4000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(16*1024)
+#define BLKFIN_DSUPBANKS	1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH      (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE	(32*1024)
+#define BLKFIN_DSUPBANKS	2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH      0x8000
+#define L1_DATA_B_LENGTH      0x8000
+#define BLKFIN_DCACHESIZE	(0*1024)
+#define BLKFIN_DSUPBANKS	0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Level 2 Memory */
+#define L2_START		0xFEB00000
+#define L2_LENGTH		0x20000
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF561)
+#define L1_SCRATCH_START	0xFFB00000
+#define L1_SCRATCH_LENGTH	0x1000
+#endif
+
+#endif				/* _MEM_MAP_533_H_ */
diff --git a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
new file mode 100644
index 0000000..22aa5e6
--- /dev/null
+++ b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
@@ -0,0 +1,471 @@
+ /*
+  * File:        include/asm-blackfin/mach-common/cdef_LPBlackfin.h
+  * Based on:
+  * Author:      unknown
+  *              COPYRIGHT 2005 Analog Devices
+  * Created:     ?
+  * Description:
+  *
+  * Modified:
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+  * any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+
+#ifndef _CDEF_LPBLACKFIN_H
+#define _CDEF_LPBLACKFIN_H
+
+/*#if !defined(__ADSPLPBLACKFIN__)
+#warning cdef_LPBlackfin.h should only be included for 532 compatible chips.
+#endif
+*/
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*Cache & SRAM Memory*/
+#define pSRAM_BASE_ADDRESS ((volatile void **)SRAM_BASE_ADDRESS)
+#define bfin_read_SRAM_BASE_ADDRESS()        bfin_read32(SRAM_BASE_ADDRESS)
+#define bfin_write_SRAM_BASE_ADDRESS(val)    bfin_write32(SRAM_BASE_ADDRESS,val)
+#define pDMEM_CONTROL ((volatile unsigned long *)DMEM_CONTROL)
+#define bfin_read_DMEM_CONTROL()             bfin_read32(DMEM_CONTROL)
+#define bfin_write_DMEM_CONTROL(val)         bfin_write32(DMEM_CONTROL,val)
+#define pDCPLB_STATUS ((volatile unsigned long *)DCPLB_STATUS)
+#define bfin_read_DCPLB_STATUS()             bfin_read32(DCPLB_STATUS)
+#define bfin_write_DCPLB_STATUS(val)         bfin_write32(DCPLB_STATUS,val)
+#define pDCPLB_FAULT_ADDR ((volatile void **)DCPLB_FAULT_ADDR)
+#define bfin_read_DCPLB_FAULT_ADDR()         bfin_read32(DCPLB_FAULT_ADDR)
+#define bfin_write_DCPLB_FAULT_ADDR(val)     bfin_write32(DCPLB_FAULT_ADDR,val)
+/*
+#define MMR_TIMEOUT            0xFFE00010
+*/
+#define pDCPLB_ADDR0 ((volatile void **)DCPLB_ADDR0)
+#define bfin_read_DCPLB_ADDR0()              bfin_read32(DCPLB_ADDR0)
+#define bfin_write_DCPLB_ADDR0(val)          bfin_write32(DCPLB_ADDR0,val)
+#define pDCPLB_ADDR1 ((volatile void **)DCPLB_ADDR1)
+#define bfin_read_DCPLB_ADDR1()              bfin_read32(DCPLB_ADDR1)
+#define bfin_write_DCPLB_ADDR1(val)          bfin_write32(DCPLB_ADDR1,val)
+#define pDCPLB_ADDR2 ((volatile void **)DCPLB_ADDR2)
+#define bfin_read_DCPLB_ADDR2()              bfin_read32(DCPLB_ADDR2)
+#define bfin_write_DCPLB_ADDR2(val)          bfin_write32(DCPLB_ADDR2,val)
+#define pDCPLB_ADDR3 ((volatile void **)DCPLB_ADDR3)
+#define bfin_read_DCPLB_ADDR3()              bfin_read32(DCPLB_ADDR3)
+#define bfin_write_DCPLB_ADDR3(val)          bfin_write32(DCPLB_ADDR3,val)
+#define pDCPLB_ADDR4 ((volatile void **)DCPLB_ADDR4)
+#define bfin_read_DCPLB_ADDR4()              bfin_read32(DCPLB_ADDR4)
+#define bfin_write_DCPLB_ADDR4(val)          bfin_write32(DCPLB_ADDR4,val)
+#define pDCPLB_ADDR5 ((volatile void **)DCPLB_ADDR5)
+#define bfin_read_DCPLB_ADDR5()              bfin_read32(DCPLB_ADDR5)
+#define bfin_write_DCPLB_ADDR5(val)          bfin_write32(DCPLB_ADDR5,val)
+#define pDCPLB_ADDR6 ((volatile void **)DCPLB_ADDR6)
+#define bfin_read_DCPLB_ADDR6()              bfin_read32(DCPLB_ADDR6)
+#define bfin_write_DCPLB_ADDR6(val)          bfin_write32(DCPLB_ADDR6,val)
+#define pDCPLB_ADDR7 ((volatile void **)DCPLB_ADDR7)
+#define bfin_read_DCPLB_ADDR7()              bfin_read32(DCPLB_ADDR7)
+#define bfin_write_DCPLB_ADDR7(val)          bfin_write32(DCPLB_ADDR7,val)
+#define pDCPLB_ADDR8 ((volatile void **)DCPLB_ADDR8)
+#define bfin_read_DCPLB_ADDR8()              bfin_read32(DCPLB_ADDR8)
+#define bfin_write_DCPLB_ADDR8(val)          bfin_write32(DCPLB_ADDR8,val)
+#define pDCPLB_ADDR9 ((volatile void **)DCPLB_ADDR9)
+#define bfin_read_DCPLB_ADDR9()              bfin_read32(DCPLB_ADDR9)
+#define bfin_write_DCPLB_ADDR9(val)          bfin_write32(DCPLB_ADDR9,val)
+#define pDCPLB_ADDR10 ((volatile void **)DCPLB_ADDR10)
+#define bfin_read_DCPLB_ADDR10()             bfin_read32(DCPLB_ADDR10)
+#define bfin_write_DCPLB_ADDR10(val)         bfin_write32(DCPLB_ADDR10,val)
+#define pDCPLB_ADDR11 ((volatile void **)DCPLB_ADDR11)
+#define bfin_read_DCPLB_ADDR11()             bfin_read32(DCPLB_ADDR11)
+#define bfin_write_DCPLB_ADDR11(val)         bfin_write32(DCPLB_ADDR11,val)
+#define pDCPLB_ADDR12 ((volatile void **)DCPLB_ADDR12)
+#define bfin_read_DCPLB_ADDR12()             bfin_read32(DCPLB_ADDR12)
+#define bfin_write_DCPLB_ADDR12(val)         bfin_write32(DCPLB_ADDR12,val)
+#define pDCPLB_ADDR13 ((volatile void **)DCPLB_ADDR13)
+#define bfin_read_DCPLB_ADDR13()             bfin_read32(DCPLB_ADDR13)
+#define bfin_write_DCPLB_ADDR13(val)         bfin_write32(DCPLB_ADDR13,val)
+#define pDCPLB_ADDR14 ((volatile void **)DCPLB_ADDR14)
+#define bfin_read_DCPLB_ADDR14()             bfin_read32(DCPLB_ADDR14)
+#define bfin_write_DCPLB_ADDR14(val)         bfin_write32(DCPLB_ADDR14,val)
+#define pDCPLB_ADDR15 ((volatile void **)DCPLB_ADDR15)
+#define bfin_read_DCPLB_ADDR15()             bfin_read32(DCPLB_ADDR15)
+#define bfin_write_DCPLB_ADDR15(val)         bfin_write32(DCPLB_ADDR15,val)
+#define pDCPLB_DATA0 ((volatile unsigned long *)DCPLB_DATA0)
+#define bfin_read_DCPLB_DATA0()              bfin_read32(DCPLB_DATA0)
+#define bfin_write_DCPLB_DATA0(val)          bfin_write32(DCPLB_DATA0,val)
+#define pDCPLB_DATA1 ((volatile unsigned long *)DCPLB_DATA1)
+#define bfin_read_DCPLB_DATA1()              bfin_read32(DCPLB_DATA1)
+#define bfin_write_DCPLB_DATA1(val)          bfin_write32(DCPLB_DATA1,val)
+#define pDCPLB_DATA2 ((volatile unsigned long *)DCPLB_DATA2)
+#define bfin_read_DCPLB_DATA2()              bfin_read32(DCPLB_DATA2)
+#define bfin_write_DCPLB_DATA2(val)          bfin_write32(DCPLB_DATA2,val)
+#define pDCPLB_DATA3 ((volatile unsigned long *)DCPLB_DATA3)
+#define bfin_read_DCPLB_DATA3()              bfin_read32(DCPLB_DATA3)
+#define bfin_write_DCPLB_DATA3(val)          bfin_write32(DCPLB_DATA3,val)
+#define pDCPLB_DATA4 ((volatile unsigned long *)DCPLB_DATA4)
+#define bfin_read_DCPLB_DATA4()              bfin_read32(DCPLB_DATA4)
+#define bfin_write_DCPLB_DATA4(val)          bfin_write32(DCPLB_DATA4,val)
+#define pDCPLB_DATA5 ((volatile unsigned long *)DCPLB_DATA5)
+#define bfin_read_DCPLB_DATA5()              bfin_read32(DCPLB_DATA5)
+#define bfin_write_DCPLB_DATA5(val)          bfin_write32(DCPLB_DATA5,val)
+#define pDCPLB_DATA6 ((volatile unsigned long *)DCPLB_DATA6)
+#define bfin_read_DCPLB_DATA6()              bfin_read32(DCPLB_DATA6)
+#define bfin_write_DCPLB_DATA6(val)          bfin_write32(DCPLB_DATA6,val)
+#define pDCPLB_DATA7 ((volatile unsigned long *)DCPLB_DATA7)
+#define bfin_read_DCPLB_DATA7()              bfin_read32(DCPLB_DATA7)
+#define bfin_write_DCPLB_DATA7(val)          bfin_write32(DCPLB_DATA7,val)
+#define pDCPLB_DATA8 ((volatile unsigned long *)DCPLB_DATA8)
+#define bfin_read_DCPLB_DATA8()              bfin_read32(DCPLB_DATA8)
+#define bfin_write_DCPLB_DATA8(val)          bfin_write32(DCPLB_DATA8,val)
+#define pDCPLB_DATA9 ((volatile unsigned long *)DCPLB_DATA9)
+#define bfin_read_DCPLB_DATA9()              bfin_read32(DCPLB_DATA9)
+#define bfin_write_DCPLB_DATA9(val)          bfin_write32(DCPLB_DATA9,val)
+#define pDCPLB_DATA10 ((volatile unsigned long *)DCPLB_DATA10)
+#define bfin_read_DCPLB_DATA10()             bfin_read32(DCPLB_DATA10)
+#define bfin_write_DCPLB_DATA10(val)         bfin_write32(DCPLB_DATA10,val)
+#define pDCPLB_DATA11 ((volatile unsigned long *)DCPLB_DATA11)
+#define bfin_read_DCPLB_DATA11()             bfin_read32(DCPLB_DATA11)
+#define bfin_write_DCPLB_DATA11(val)         bfin_write32(DCPLB_DATA11,val)
+#define pDCPLB_DATA12 ((volatile unsigned long *)DCPLB_DATA12)
+#define bfin_read_DCPLB_DATA12()             bfin_read32(DCPLB_DATA12)
+#define bfin_write_DCPLB_DATA12(val)         bfin_write32(DCPLB_DATA12,val)
+#define pDCPLB_DATA13 ((volatile unsigned long *)DCPLB_DATA13)
+#define bfin_read_DCPLB_DATA13()             bfin_read32(DCPLB_DATA13)
+#define bfin_write_DCPLB_DATA13(val)         bfin_write32(DCPLB_DATA13,val)
+#define pDCPLB_DATA14 ((volatile unsigned long *)DCPLB_DATA14)
+#define bfin_read_DCPLB_DATA14()             bfin_read32(DCPLB_DATA14)
+#define bfin_write_DCPLB_DATA14(val)         bfin_write32(DCPLB_DATA14,val)
+#define pDCPLB_DATA15 ((volatile unsigned long *)DCPLB_DATA15)
+#define bfin_read_DCPLB_DATA15()             bfin_read32(DCPLB_DATA15)
+#define bfin_write_DCPLB_DATA15(val)         bfin_write32(DCPLB_DATA15,val)
+#define pDTEST_COMMAND ((volatile unsigned long *)DTEST_COMMAND)
+#define bfin_read_DTEST_COMMAND()            bfin_read32(DTEST_COMMAND)
+#define bfin_write_DTEST_COMMAND(val)        bfin_write32(DTEST_COMMAND,val)
+/*
+#define DTEST_INDEX            0xFFE00304
+*/
+#define pDTEST_DATA0 ((volatile unsigned long *)DTEST_DATA0)
+#define bfin_read_DTEST_DATA0()              bfin_read32(DTEST_DATA0)
+#define bfin_write_DTEST_DATA0(val)          bfin_write32(DTEST_DATA0,val)
+#define pDTEST_DATA1 ((volatile unsigned long *)DTEST_DATA1)
+#define bfin_read_DTEST_DATA1()              bfin_read32(DTEST_DATA1)
+#define bfin_write_DTEST_DATA1(val)          bfin_write32(DTEST_DATA1,val)
+/*
+#define DTEST_DATA2            0xFFE00408
+#define DTEST_DATA3            0xFFE0040C
+*/
+#define pIMEM_CONTROL ((volatile unsigned long *)IMEM_CONTROL)
+#define bfin_read_IMEM_CONTROL()             bfin_read32(IMEM_CONTROL)
+#define bfin_write_IMEM_CONTROL(val)         bfin_write32(IMEM_CONTROL,val)
+#define pICPLB_STATUS ((volatile unsigned long *)ICPLB_STATUS)
+#define bfin_read_ICPLB_STATUS()             bfin_read32(ICPLB_STATUS)
+#define bfin_write_ICPLB_STATUS(val)         bfin_write32(ICPLB_STATUS,val)
+#define pICPLB_FAULT_ADDR ((volatile void **)ICPLB_FAULT_ADDR)
+#define bfin_read_ICPLB_FAULT_ADDR()         bfin_read32(ICPLB_FAULT_ADDR)
+#define bfin_write_ICPLB_FAULT_ADDR(val)     bfin_write32(ICPLB_FAULT_ADDR,val)
+#define pICPLB_ADDR0 ((volatile void **)ICPLB_ADDR0)
+#define bfin_read_ICPLB_ADDR0()              bfin_read32(ICPLB_ADDR0)
+#define bfin_write_ICPLB_ADDR0(val)          bfin_write32(ICPLB_ADDR0,val)
+#define pICPLB_ADDR1 ((volatile void **)ICPLB_ADDR1)
+#define bfin_read_ICPLB_ADDR1()              bfin_read32(ICPLB_ADDR1)
+#define bfin_write_ICPLB_ADDR1(val)          bfin_write32(ICPLB_ADDR1,val)
+#define pICPLB_ADDR2 ((volatile void **)ICPLB_ADDR2)
+#define bfin_read_ICPLB_ADDR2()              bfin_read32(ICPLB_ADDR2)
+#define bfin_write_ICPLB_ADDR2(val)          bfin_write32(ICPLB_ADDR2,val)
+#define pICPLB_ADDR3 ((volatile void **)ICPLB_ADDR3)
+#define bfin_read_ICPLB_ADDR3()              bfin_read32(ICPLB_ADDR3)
+#define bfin_write_ICPLB_ADDR3(val)          bfin_write32(ICPLB_ADDR3,val)
+#define pICPLB_ADDR4 ((volatile void **)ICPLB_ADDR4)
+#define bfin_read_ICPLB_ADDR4()              bfin_read32(ICPLB_ADDR4)
+#define bfin_write_ICPLB_ADDR4(val)          bfin_write32(ICPLB_ADDR4,val)
+#define pICPLB_ADDR5 ((volatile void **)ICPLB_ADDR5)
+#define bfin_read_ICPLB_ADDR5()              bfin_read32(ICPLB_ADDR5)
+#define bfin_write_ICPLB_ADDR5(val)          bfin_write32(ICPLB_ADDR5,val)
+#define pICPLB_ADDR6 ((volatile void **)ICPLB_ADDR6)
+#define bfin_read_ICPLB_ADDR6()              bfin_read32(ICPLB_ADDR6)
+#define bfin_write_ICPLB_ADDR6(val)          bfin_write32(ICPLB_ADDR6,val)
+#define pICPLB_ADDR7 ((volatile void **)ICPLB_ADDR7)
+#define bfin_read_ICPLB_ADDR7()              bfin_read32(ICPLB_ADDR7)
+#define bfin_write_ICPLB_ADDR7(val)          bfin_write32(ICPLB_ADDR7,val)
+#define pICPLB_ADDR8 ((volatile void **)ICPLB_ADDR8)
+#define bfin_read_ICPLB_ADDR8()              bfin_read32(ICPLB_ADDR8)
+#define bfin_write_ICPLB_ADDR8(val)          bfin_write32(ICPLB_ADDR8,val)
+#define pICPLB_ADDR9 ((volatile void **)ICPLB_ADDR9)
+#define bfin_read_ICPLB_ADDR9()              bfin_read32(ICPLB_ADDR9)
+#define bfin_write_ICPLB_ADDR9(val)          bfin_write32(ICPLB_ADDR9,val)
+#define pICPLB_ADDR10 ((volatile void **)ICPLB_ADDR10)
+#define bfin_read_ICPLB_ADDR10()             bfin_read32(ICPLB_ADDR10)
+#define bfin_write_ICPLB_ADDR10(val)         bfin_write32(ICPLB_ADDR10,val)
+#define pICPLB_ADDR11 ((volatile void **)ICPLB_ADDR11)
+#define bfin_read_ICPLB_ADDR11()             bfin_read32(ICPLB_ADDR11)
+#define bfin_write_ICPLB_ADDR11(val)         bfin_write32(ICPLB_ADDR11,val)
+#define pICPLB_ADDR12 ((volatile void **)ICPLB_ADDR12)
+#define bfin_read_ICPLB_ADDR12()             bfin_read32(ICPLB_ADDR12)
+#define bfin_write_ICPLB_ADDR12(val)         bfin_write32(ICPLB_ADDR12,val)
+#define pICPLB_ADDR13 ((volatile void **)ICPLB_ADDR13)
+#define bfin_read_ICPLB_ADDR13()             bfin_read32(ICPLB_ADDR13)
+#define bfin_write_ICPLB_ADDR13(val)         bfin_write32(ICPLB_ADDR13,val)
+#define pICPLB_ADDR14 ((volatile void **)ICPLB_ADDR14)
+#define bfin_read_ICPLB_ADDR14()             bfin_read32(ICPLB_ADDR14)
+#define bfin_write_ICPLB_ADDR14(val)         bfin_write32(ICPLB_ADDR14,val)
+#define pICPLB_ADDR15 ((volatile void **)ICPLB_ADDR15)
+#define bfin_read_ICPLB_ADDR15()             bfin_read32(ICPLB_ADDR15)
+#define bfin_write_ICPLB_ADDR15(val)         bfin_write32(ICPLB_ADDR15,val)
+#define pICPLB_DATA0 ((volatile unsigned long *)ICPLB_DATA0)
+#define bfin_read_ICPLB_DATA0()              bfin_read32(ICPLB_DATA0)
+#define bfin_write_ICPLB_DATA0(val)          bfin_write32(ICPLB_DATA0,val)
+#define pICPLB_DATA1 ((volatile unsigned long *)ICPLB_DATA1)
+#define bfin_read_ICPLB_DATA1()              bfin_read32(ICPLB_DATA1)
+#define bfin_write_ICPLB_DATA1(val)          bfin_write32(ICPLB_DATA1,val)
+#define pICPLB_DATA2 ((volatile unsigned long *)ICPLB_DATA2)
+#define bfin_read_ICPLB_DATA2()              bfin_read32(ICPLB_DATA2)
+#define bfin_write_ICPLB_DATA2(val)          bfin_write32(ICPLB_DATA2,val)
+#define pICPLB_DATA3 ((volatile unsigned long *)ICPLB_DATA3)
+#define bfin_read_ICPLB_DATA3()              bfin_read32(ICPLB_DATA3)
+#define bfin_write_ICPLB_DATA3(val)          bfin_write32(ICPLB_DATA3,val)
+#define pICPLB_DATA4 ((volatile unsigned long *)ICPLB_DATA4)
+#define bfin_read_ICPLB_DATA4()              bfin_read32(ICPLB_DATA4)
+#define bfin_write_ICPLB_DATA4(val)          bfin_write32(ICPLB_DATA4,val)
+#define pICPLB_DATA5 ((volatile unsigned long *)ICPLB_DATA5)
+#define bfin_read_ICPLB_DATA5()              bfin_read32(ICPLB_DATA5)
+#define bfin_write_ICPLB_DATA5(val)          bfin_write32(ICPLB_DATA5,val)
+#define pICPLB_DATA6 ((volatile unsigned long *)ICPLB_DATA6)
+#define bfin_read_ICPLB_DATA6()              bfin_read32(ICPLB_DATA6)
+#define bfin_write_ICPLB_DATA6(val)          bfin_write32(ICPLB_DATA6,val)
+#define pICPLB_DATA7 ((volatile unsigned long *)ICPLB_DATA7)
+#define bfin_read_ICPLB_DATA7()              bfin_read32(ICPLB_DATA7)
+#define bfin_write_ICPLB_DATA7(val)          bfin_write32(ICPLB_DATA7,val)
+#define pICPLB_DATA8 ((volatile unsigned long *)ICPLB_DATA8)
+#define bfin_read_ICPLB_DATA8()              bfin_read32(ICPLB_DATA8)
+#define bfin_write_ICPLB_DATA8(val)          bfin_write32(ICPLB_DATA8,val)
+#define pICPLB_DATA9 ((volatile unsigned long *)ICPLB_DATA9)
+#define bfin_read_ICPLB_DATA9()              bfin_read32(ICPLB_DATA9)
+#define bfin_write_ICPLB_DATA9(val)          bfin_write32(ICPLB_DATA9,val)
+#define pICPLB_DATA10 ((volatile unsigned long *)ICPLB_DATA10)
+#define bfin_read_ICPLB_DATA10()             bfin_read32(ICPLB_DATA10)
+#define bfin_write_ICPLB_DATA10(val)         bfin_write32(ICPLB_DATA10,val)
+#define pICPLB_DATA11 ((volatile unsigned long *)ICPLB_DATA11)
+#define bfin_read_ICPLB_DATA11()             bfin_read32(ICPLB_DATA11)
+#define bfin_write_ICPLB_DATA11(val)         bfin_write32(ICPLB_DATA11,val)
+#define pICPLB_DATA12 ((volatile unsigned long *)ICPLB_DATA12)
+#define bfin_read_ICPLB_DATA12()             bfin_read32(ICPLB_DATA12)
+#define bfin_write_ICPLB_DATA12(val)         bfin_write32(ICPLB_DATA12,val)
+#define pICPLB_DATA13 ((volatile unsigned long *)ICPLB_DATA13)
+#define bfin_read_ICPLB_DATA13()             bfin_read32(ICPLB_DATA13)
+#define bfin_write_ICPLB_DATA13(val)         bfin_write32(ICPLB_DATA13,val)
+#define pICPLB_DATA14 ((volatile unsigned long *)ICPLB_DATA14)
+#define bfin_read_ICPLB_DATA14()             bfin_read32(ICPLB_DATA14)
+#define bfin_write_ICPLB_DATA14(val)         bfin_write32(ICPLB_DATA14,val)
+#define pICPLB_DATA15 ((volatile unsigned long *)ICPLB_DATA15)
+#define bfin_read_ICPLB_DATA15()             bfin_read32(ICPLB_DATA15)
+#define bfin_write_ICPLB_DATA15(val)         bfin_write32(ICPLB_DATA15,val)
+#define pITEST_COMMAND ((volatile unsigned long *)ITEST_COMMAND)
+#define bfin_read_ITEST_COMMAND()            bfin_read32(ITEST_COMMAND)
+#define bfin_write_ITEST_COMMAND(val)        bfin_write32(ITEST_COMMAND,val)
+#if 0
+#define ITEST_INDEX            0xFFE01304   /* Instruction Test Index Register */
+#endif
+#define pITEST_DATA0 ((volatile unsigned long *)ITEST_DATA0)
+#define bfin_read_ITEST_DATA0()              bfin_read32(ITEST_DATA0)
+#define bfin_write_ITEST_DATA0(val)          bfin_write32(ITEST_DATA0,val)
+#define pITEST_DATA1 ((volatile unsigned long *)ITEST_DATA1)
+#define bfin_read_ITEST_DATA1()              bfin_read32(ITEST_DATA1)
+#define bfin_write_ITEST_DATA1(val)          bfin_write32(ITEST_DATA1,val)
+
+/* Event/Interrupt Registers*/
+
+#define pEVT0 ((volatile void **)EVT0)
+#define bfin_read_EVT0()                     bfin_read32(EVT0)
+#define bfin_write_EVT0(val)                 bfin_write32(EVT0,val)
+#define pEVT1 ((volatile void **)EVT1)
+#define bfin_read_EVT1()                     bfin_read32(EVT1)
+#define bfin_write_EVT1(val)                 bfin_write32(EVT1,val)
+#define pEVT2 ((volatile void **)EVT2)
+#define bfin_read_EVT2()                     bfin_read32(EVT2)
+#define bfin_write_EVT2(val)                 bfin_write32(EVT2,val)
+#define pEVT3 ((volatile void **)EVT3)
+#define bfin_read_EVT3()                     bfin_read32(EVT3)
+#define bfin_write_EVT3(val)                 bfin_write32(EVT3,val)
+#define pEVT4 ((volatile void **)EVT4)
+#define bfin_read_EVT4()                     bfin_read32(EVT4)
+#define bfin_write_EVT4(val)                 bfin_write32(EVT4,val)
+#define pEVT5 ((volatile void **)EVT5)
+#define bfin_read_EVT5()                     bfin_read32(EVT5)
+#define bfin_write_EVT5(val)                 bfin_write32(EVT5,val)
+#define pEVT6 ((volatile void **)EVT6)
+#define bfin_read_EVT6()                     bfin_read32(EVT6)
+#define bfin_write_EVT6(val)                 bfin_write32(EVT6,val)
+#define pEVT7 ((volatile void **)EVT7)
+#define bfin_read_EVT7()                     bfin_read32(EVT7)
+#define bfin_write_EVT7(val)                 bfin_write32(EVT7,val)
+#define pEVT8 ((volatile void **)EVT8)
+#define bfin_read_EVT8()                     bfin_read32(EVT8)
+#define bfin_write_EVT8(val)                 bfin_write32(EVT8,val)
+#define pEVT9 ((volatile void **)EVT9)
+#define bfin_read_EVT9()                     bfin_read32(EVT9)
+#define bfin_write_EVT9(val)                 bfin_write32(EVT9,val)
+#define pEVT10 ((volatile void **)EVT10)
+#define bfin_read_EVT10()                    bfin_read32(EVT10)
+#define bfin_write_EVT10(val)                bfin_write32(EVT10,val)
+#define pEVT11 ((volatile void **)EVT11)
+#define bfin_read_EVT11()                    bfin_read32(EVT11)
+#define bfin_write_EVT11(val)                bfin_write32(EVT11,val)
+#define pEVT12 ((volatile void **)EVT12)
+#define bfin_read_EVT12()                    bfin_read32(EVT12)
+#define bfin_write_EVT12(val)                bfin_write32(EVT12,val)
+#define pEVT13 ((volatile void **)EVT13)
+#define bfin_read_EVT13()                    bfin_read32(EVT13)
+#define bfin_write_EVT13(val)                bfin_write32(EVT13,val)
+#define pEVT14 ((volatile void **)EVT14)
+#define bfin_read_EVT14()                    bfin_read32(EVT14)
+#define bfin_write_EVT14(val)                bfin_write32(EVT14,val)
+#define pEVT15 ((volatile void **)EVT15)
+#define bfin_read_EVT15()                    bfin_read32(EVT15)
+#define bfin_write_EVT15(val)                bfin_write32(EVT15,val)
+#define pIMASK ((volatile unsigned long *)IMASK)
+#define bfin_read_IMASK()                    bfin_read32(IMASK)
+#define bfin_write_IMASK(val)                bfin_write32(IMASK,val)
+#define pIPEND ((volatile unsigned long *)IPEND)
+#define bfin_read_IPEND()                    bfin_read32(IPEND)
+#define bfin_write_IPEND(val)                bfin_write32(IPEND,val)
+#define pILAT ((volatile unsigned long *)ILAT)
+#define bfin_read_ILAT()                     bfin_read32(ILAT)
+#define bfin_write_ILAT(val)                 bfin_write32(ILAT,val)
+
+/*Core Timer Registers*/
+#define pTCNTL ((volatile unsigned long *)TCNTL)
+#define bfin_read_TCNTL()                    bfin_read32(TCNTL)
+#define bfin_write_TCNTL(val)                bfin_write32(TCNTL,val)
+#define pTPERIOD ((volatile unsigned long *)TPERIOD)
+#define bfin_read_TPERIOD()                  bfin_read32(TPERIOD)
+#define bfin_write_TPERIOD(val)              bfin_write32(TPERIOD,val)
+#define pTSCALE ((volatile unsigned long *)TSCALE)
+#define bfin_read_TSCALE()                   bfin_read32(TSCALE)
+#define bfin_write_TSCALE(val)               bfin_write32(TSCALE,val)
+#define pTCOUNT ((volatile unsigned long *)TCOUNT)
+#define bfin_read_TCOUNT()                   bfin_read32(TCOUNT)
+#define bfin_write_TCOUNT(val)               bfin_write32(TCOUNT,val)
+
+/*Debug/MP/Emulation Registers*/
+#define pDSPID ((volatile unsigned long *)DSPID)
+#define bfin_read_DSPID()                    bfin_read32(DSPID)
+#define bfin_write_DSPID(val)                bfin_write32(DSPID,val)
+#define pDBGCTL ((volatile unsigned long *)DBGCTL)
+#define bfin_read_DBGCTL()                   bfin_read32(DBGCTL)
+#define bfin_write_DBGCTL(val)               bfin_write32(DBGCTL,val)
+#define pDBGSTAT ((volatile unsigned long *)DBGSTAT)
+#define bfin_read_DBGSTAT()                  bfin_read32(DBGSTAT)
+#define bfin_write_DBGSTAT(val)              bfin_write32(DBGSTAT,val)
+#define pEMUDAT ((volatile unsigned long *)EMUDAT)
+#define bfin_read_EMUDAT()                   bfin_read32(EMUDAT)
+#define bfin_write_EMUDAT(val)               bfin_write32(EMUDAT,val)
+
+/*Trace Buffer Registers*/
+#define pTBUFCTL ((volatile unsigned long *)TBUFCTL)
+#define bfin_read_TBUFCTL()                  bfin_read32(TBUFCTL)
+#define bfin_write_TBUFCTL(val)              bfin_write32(TBUFCTL,val)
+#define pTBUFSTAT ((volatile unsigned long *)TBUFSTAT)
+#define bfin_read_TBUFSTAT()                 bfin_read32(TBUFSTAT)
+#define bfin_write_TBUFSTAT(val)             bfin_write32(TBUFSTAT,val)
+#define pTBUF ((volatile void **)TBUF)
+#define bfin_read_TBUF()                     bfin_read32(TBUF)
+#define bfin_write_TBUF(val)                 bfin_write32(TBUF,val)
+
+/*Watch Point Control Registers*/
+#define pWPIACTL ((volatile unsigned long *)WPIACTL)
+#define bfin_read_WPIACTL()                  bfin_read32(WPIACTL)
+#define bfin_write_WPIACTL(val)              bfin_write32(WPIACTL,val)
+#define pWPIA0 ((volatile void **)WPIA0)
+#define bfin_read_WPIA0()                    bfin_read32(WPIA0)
+#define bfin_write_WPIA0(val)                bfin_write32(WPIA0,val)
+#define pWPIA1 ((volatile void **)WPIA1)
+#define bfin_read_WPIA1()                    bfin_read32(WPIA1)
+#define bfin_write_WPIA1(val)                bfin_write32(WPIA1,val)
+#define pWPIA2 ((volatile void **)WPIA2)
+#define bfin_read_WPIA2()                    bfin_read32(WPIA2)
+#define bfin_write_WPIA2(val)                bfin_write32(WPIA2,val)
+#define pWPIA3 ((volatile void **)WPIA3)
+#define bfin_read_WPIA3()                    bfin_read32(WPIA3)
+#define bfin_write_WPIA3(val)                bfin_write32(WPIA3,val)
+#define pWPIA4 ((volatile void **)WPIA4)
+#define bfin_read_WPIA4()                    bfin_read32(WPIA4)
+#define bfin_write_WPIA4(val)                bfin_write32(WPIA4,val)
+#define pWPIA5 ((volatile void **)WPIA5)
+#define bfin_read_WPIA5()                    bfin_read32(WPIA5)
+#define bfin_write_WPIA5(val)                bfin_write32(WPIA5,val)
+#define pWPIACNT0 ((volatile unsigned long *)WPIACNT0)
+#define bfin_read_WPIACNT0()                 bfin_read32(WPIACNT0)
+#define bfin_write_WPIACNT0(val)             bfin_write32(WPIACNT0,val)
+#define pWPIACNT1 ((volatile unsigned long *)WPIACNT1)
+#define bfin_read_WPIACNT1()                 bfin_read32(WPIACNT1)
+#define bfin_write_WPIACNT1(val)             bfin_write32(WPIACNT1,val)
+#define pWPIACNT2 ((volatile unsigned long *)WPIACNT2)
+#define bfin_read_WPIACNT2()                 bfin_read32(WPIACNT2)
+#define bfin_write_WPIACNT2(val)             bfin_write32(WPIACNT2,val)
+#define pWPIACNT3 ((volatile unsigned long *)WPIACNT3)
+#define bfin_read_WPIACNT3()                 bfin_read32(WPIACNT3)
+#define bfin_write_WPIACNT3(val)             bfin_write32(WPIACNT3,val)
+#define pWPIACNT4 ((volatile unsigned long *)WPIACNT4)
+#define bfin_read_WPIACNT4()                 bfin_read32(WPIACNT4)
+#define bfin_write_WPIACNT4(val)             bfin_write32(WPIACNT4,val)
+#define pWPIACNT5 ((volatile unsigned long *)WPIACNT5)
+#define bfin_read_WPIACNT5()                 bfin_read32(WPIACNT5)
+#define bfin_write_WPIACNT5(val)             bfin_write32(WPIACNT5,val)
+#define pWPDACTL ((volatile unsigned long *)WPDACTL)
+#define bfin_read_WPDACTL()                  bfin_read32(WPDACTL)
+#define bfin_write_WPDACTL(val)              bfin_write32(WPDACTL,val)
+#define pWPDA0 ((volatile void **)WPDA0)
+#define bfin_read_WPDA0()                    bfin_read32(WPDA0)
+#define bfin_write_WPDA0(val)                bfin_write32(WPDA0,val)
+#define pWPDA1 ((volatile void **)WPDA1)
+#define bfin_read_WPDA1()                    bfin_read32(WPDA1)
+#define bfin_write_WPDA1(val)                bfin_write32(WPDA1,val)
+#define pWPDACNT0 ((volatile unsigned long *)WPDACNT0)
+#define bfin_read_WPDACNT0()                 bfin_read32(WPDACNT0)
+#define bfin_write_WPDACNT0(val)             bfin_write32(WPDACNT0,val)
+#define pWPDACNT1 ((volatile unsigned long *)WPDACNT1)
+#define bfin_read_WPDACNT1()                 bfin_read32(WPDACNT1)
+#define bfin_write_WPDACNT1(val)             bfin_write32(WPDACNT1,val)
+#define pWPSTAT ((volatile unsigned long *)WPSTAT)
+#define bfin_read_WPSTAT()                   bfin_read32(WPSTAT)
+#define bfin_write_WPSTAT(val)               bfin_write32(WPSTAT,val)
+
+/*Performance Monitor Registers*/
+#define pPFCTL ((volatile unsigned long *)PFCTL)
+#define bfin_read_PFCTL()                    bfin_read32(PFCTL)
+#define bfin_write_PFCTL(val)                bfin_write32(PFCTL,val)
+#define pPFCNTR0 ((volatile unsigned long *)PFCNTR0)
+#define bfin_read_PFCNTR0()                  bfin_read32(PFCNTR0)
+#define bfin_write_PFCNTR0(val)              bfin_write32(PFCNTR0,val)
+#define pPFCNTR1 ((volatile unsigned long *)PFCNTR1)
+#define bfin_read_PFCNTR1()                  bfin_read32(PFCNTR1)
+#define bfin_write_PFCNTR1(val)              bfin_write32(PFCNTR1,val)
+
+/*
+#define IPRIO                  0xFFE02110
+*/
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+#define pCONFIG_BFIN_ALIVE_LED_DPORT \
+	(volatile unsigned short *)CONFIG_BFIN_ALIVE_LED_DPORT
+#define pCONFIG_BFIN_ALIVE_LED_PORT \
+	(volatile unsigned short *)CONFIG_BFIN_ALIVE_LED_PORT
+#endif
+
+#if defined(CONFIG_BFIN_IDLE_LED)
+#define pCONFIG_BFIN_IDLE_LED_DPORT \
+	(volatile unsigned short *)CONFIG_BFIN_IDLE_LED_DPORT
+#define pCONFIG_BFIN_IDLE_LED_PORT \
+	(volatile unsigned short *)CONFIG_BFIN_IDLE_LED_PORT
+#endif
+
+#endif				/* _CDEF_LPBLACKFIN_H */
diff --git a/include/asm-blackfin/mach-common/context.S b/include/asm-blackfin/mach-common/context.S
new file mode 100644
index 0000000..fd0ebe1
--- /dev/null
+++ b/include/asm-blackfin/mach-common/context.S
@@ -0,0 +1,350 @@
+/*
+ * File:         arch/blackfin/kernel/context.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * Code to save processor context.
+ *  We even save the register which are preserved by a function call
+ *	 - r4, r5, r6, r7, p3, p4, p5
+ */
+.macro save_context_with_interrupts
+	[--sp] = SYSCFG;
+
+	[--sp] = P0;	/*orig_p0*/
+	[--sp] = R0;	/*orig_r0*/
+
+	[--sp] = ( R7:0, P5:0 );
+	[--sp] = fp;
+	[--sp] = usp;
+
+	[--sp] = i0;
+	[--sp] = i1;
+	[--sp] = i2;
+	[--sp] = i3;
+
+	[--sp] = m0;
+	[--sp] = m1;
+	[--sp] = m2;
+	[--sp] = m3;
+
+	[--sp] = l0;
+	[--sp] = l1;
+	[--sp] = l2;
+	[--sp] = l3;
+
+	[--sp] = b0;
+	[--sp] = b1;
+	[--sp] = b2;
+	[--sp] = b3;
+	[--sp] = a0.x;
+	[--sp] = a0.w;
+	[--sp] = a1.x;
+	[--sp] = a1.w;
+
+	[--sp] = LC0;
+	[--sp] = LC1;
+	[--sp] = LT0;
+	[--sp] = LT1;
+	[--sp] = LB0;
+	[--sp] = LB1;
+
+	[--sp] = ASTAT;
+
+	[--sp] = r0;	/* Skip reserved */
+	[--sp] = RETS;
+	r0 = RETI;
+	[--sp] = r0;
+	[--sp] = RETX;
+	[--sp] = RETN;
+	[--sp] = RETE;
+	[--sp] = SEQSTAT;
+	[--sp] = r0;	/* Skip IPEND as well. */
+	/* Switch to other method of keeping interrupts disabled.  */
+#ifdef CONFIG_DEBUG_HWERR
+	r0 = 0x3f;
+	sti r0;
+#else
+	cli r0;
+#endif
+	[--sp] = RETI;  /*orig_pc*/
+	/* Clear all L registers.  */
+	r0 = 0 (x);
+	l0 = r0;
+	l1 = r0;
+	l2 = r0;
+	l3 = r0;
+.endm
+
+.macro save_context_syscall
+	[--sp] = SYSCFG;
+
+	[--sp] = P0;	/*orig_p0*/
+	[--sp] = R0;	/*orig_r0*/
+	[--sp] = ( R7:0, P5:0 );
+	[--sp] = fp;
+	[--sp] = usp;
+
+	[--sp] = i0;
+	[--sp] = i1;
+	[--sp] = i2;
+	[--sp] = i3;
+
+	[--sp] = m0;
+	[--sp] = m1;
+	[--sp] = m2;
+	[--sp] = m3;
+
+	[--sp] = l0;
+	[--sp] = l1;
+	[--sp] = l2;
+	[--sp] = l3;
+
+	[--sp] = b0;
+	[--sp] = b1;
+	[--sp] = b2;
+	[--sp] = b3;
+	[--sp] = a0.x;
+	[--sp] = a0.w;
+	[--sp] = a1.x;
+	[--sp] = a1.w;
+
+	[--sp] = LC0;
+	[--sp] = LC1;
+	[--sp] = LT0;
+	[--sp] = LT1;
+	[--sp] = LB0;
+	[--sp] = LB1;
+
+	[--sp] = ASTAT;
+
+	[--sp] = r0;	/* Skip reserved */
+	[--sp] = RETS;
+	r0 = RETI;
+	[--sp] = r0;
+	[--sp] = RETX;
+	[--sp] = RETN;
+	[--sp] = RETE;
+	[--sp] = SEQSTAT;
+	[--sp] = r0;	/* Skip IPEND as well. */
+	[--sp] = RETI;  /*orig_pc*/
+	/* Clear all L registers.  */
+	r0 = 0 (x);
+	l0 = r0;
+	l1 = r0;
+	l2 = r0;
+	l3 = r0;
+.endm
+
+.macro save_context_no_interrupts
+	[--sp] = SYSCFG;
+	[--sp] = P0;	/* orig_p0 */
+	[--sp] = R0;	/* orig_r0 */
+	[--sp] = ( R7:0, P5:0 );
+	[--sp] = fp;
+	[--sp] = usp;
+
+	[--sp] = i0;
+	[--sp] = i1;
+	[--sp] = i2;
+	[--sp] = i3;
+
+	[--sp] = m0;
+	[--sp] = m1;
+	[--sp] = m2;
+	[--sp] = m3;
+
+	[--sp] = l0;
+	[--sp] = l1;
+	[--sp] = l2;
+	[--sp] = l3;
+
+	[--sp] = b0;
+	[--sp] = b1;
+	[--sp] = b2;
+	[--sp] = b3;
+	[--sp] = a0.x;
+	[--sp] = a0.w;
+	[--sp] = a1.x;
+	[--sp] = a1.w;
+
+	[--sp] = LC0;
+	[--sp] = LC1;
+	[--sp] = LT0;
+	[--sp] = LT1;
+	[--sp] = LB0;
+	[--sp] = LB1;
+
+	[--sp] = ASTAT;
+
+#ifdef CONFIG_KGDB
+	fp     = 0(Z);
+	r1     = sp;
+	r1    += 60;
+	r1    += 60;
+	r1    += 60;
+	[--sp] = r1;
+#else
+	[--sp] = r0;	/* Skip reserved */
+#endif
+	[--sp] = RETS;
+	r0 = RETI;
+	[--sp] = r0;
+	[--sp] = RETX;
+	[--sp] = RETN;
+	[--sp] = RETE;
+	[--sp] = SEQSTAT;
+#ifdef CONFIG_KGDB
+	r1.l = lo(IPEND);
+	r1.h = hi(IPEND);
+	[--sp] = r1;
+#else
+	[--sp] = r0;	/* Skip IPEND as well. */
+#endif
+	[--sp] = r0;  /*orig_pc*/
+	/* Clear all L registers.  */
+	r0 = 0 (x);
+	l0 = r0;
+	l1 = r0;
+	l2 = r0;
+	l3 = r0;
+.endm
+
+.macro restore_context_no_interrupts
+	sp += 4;	/* Skip orig_pc */
+	sp += 4;	/* Skip IPEND */
+	SEQSTAT = [sp++];
+	RETE = [sp++];
+	RETN = [sp++];
+	RETX = [sp++];
+	r0 = [sp++];
+	RETI = r0;	/* Restore RETI indirectly when in exception */
+	RETS = [sp++];
+
+	sp += 4;	/* Skip Reserved */
+
+	ASTAT = [sp++];
+
+	LB1 = [sp++];
+	LB0 = [sp++];
+	LT1 = [sp++];
+	LT0 = [sp++];
+	LC1 = [sp++];
+	LC0 = [sp++];
+
+	a1.w = [sp++];
+	a1.x = [sp++];
+	a0.w = [sp++];
+	a0.x = [sp++];
+	b3 = [sp++];
+	b2 = [sp++];
+	b1 = [sp++];
+	b0 = [sp++];
+
+	l3 = [sp++];
+	l2 = [sp++];
+	l1 = [sp++];
+	l0 = [sp++];
+
+	m3 = [sp++];
+	m2 = [sp++];
+	m1 = [sp++];
+	m0 = [sp++];
+
+	i3 = [sp++];
+	i2 = [sp++];
+	i1 = [sp++];
+	i0 = [sp++];
+
+	sp += 4;
+	fp = [sp++];
+
+	( R7 : 0, P5 : 0) = [ SP ++ ];
+	sp += 8;	/* Skip orig_r0/orig_p0 */
+	SYSCFG = [sp++];
+.endm
+
+.macro restore_context_with_interrupts
+	sp += 4;	/* Skip orig_pc */
+	sp += 4;	/* Skip IPEND */
+	SEQSTAT = [sp++];
+	RETE = [sp++];
+	RETN = [sp++];
+	RETX = [sp++];
+	RETI = [sp++];
+	RETS = [sp++];
+
+	p0.h = _irq_flags;
+	p0.l = _irq_flags;
+	r0 = [p0];
+	sti r0;
+
+	sp += 4;	/* Skip Reserved */
+
+	ASTAT = [sp++];
+
+	LB1 = [sp++];
+	LB0 = [sp++];
+	LT1 = [sp++];
+	LT0 = [sp++];
+	LC1 = [sp++];
+	LC0 = [sp++];
+
+	a1.w = [sp++];
+	a1.x = [sp++];
+	a0.w = [sp++];
+	a0.x = [sp++];
+	b3 = [sp++];
+	b2 = [sp++];
+	b1 = [sp++];
+	b0 = [sp++];
+
+	l3 = [sp++];
+	l2 = [sp++];
+	l1 = [sp++];
+	l0 = [sp++];
+
+	m3 = [sp++];
+	m2 = [sp++];
+	m1 = [sp++];
+	m0 = [sp++];
+
+	i3 = [sp++];
+	i2 = [sp++];
+	i1 = [sp++];
+	i0 = [sp++];
+
+	sp += 4;
+	fp = [sp++];
+
+	( R7 : 0, P5 : 0) = [ SP ++ ];
+	sp += 8;	/* Skip orig_r0/orig_p0 */
+	csync;
+	SYSCFG = [sp++];
+	csync;
+.endm
+
diff --git a/include/asm-blackfin/mach-common/def_LPBlackfin.h b/include/asm-blackfin/mach-common/def_LPBlackfin.h
new file mode 100644
index 0000000..7610352
--- /dev/null
+++ b/include/asm-blackfin/mach-common/def_LPBlackfin.h
@@ -0,0 +1,691 @@
+ /*
+  * File:        include/asm-blackfin/mach-common/def_LPBlackfin.h
+  * Based on:
+  * Author:      unknown
+  *              COPYRIGHT 2005 Analog Devices
+  * Created:     ?
+  * Description:
+  *
+  * Modified:
+  *
+  * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+  * any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  */
+
+/* LP Blackfin CORE REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532/33 */
+
+#ifndef _DEF_LPBLACKFIN_H
+#define _DEF_LPBLACKFIN_H
+
+#include <asm/mach/anomaly.h>
+
+/*#if !defined(__ADSPLPBLACKFIN__)
+#warning def_LPBlackfin.h should only be included for 532 compatible chips.
+#endif
+*/
+
+#define MK_BMSK_(x) (1<<x)
+
+#if defined(ANOMALY_05000198)
+
+#define bfin_read16(addr) ({ unsigned __v; \
+                       __asm__ __volatile__ ("NOP;\n\t"\
+	         			     			"%0 = w[%1] (z);\n\t"\
+  : "=d"(__v) : "a"(addr)); (unsigned short)__v; })
+
+#define bfin_read32(addr) ({ unsigned __v; \
+                      __asm__ __volatile__ ("NOP;\n\t"\
+                                            "%0 = [%1];\n\t"\
+  : "=d"(__v) : "a"(addr)); __v; })
+
+#define bfin_write16(addr,val) ({\
+                      __asm__ __volatile__ ("NOP;\n\t"\
+                                            "w[%0] = %1;\n\t"\
+  : : "a"(addr) , "d"(val) : "memory");})
+
+#define bfin_write32(addr,val) ({\
+                      __asm__ __volatile__ ("NOP;\n\t"\
+                                            "[%0] = %1;\n\t"\
+  : : "a"(addr) , "d"(val) : "memory");})
+
+#else
+
+#define bfin_read16(addr) ({ unsigned __v; \
+                       __asm__ __volatile__ (\
+	         			     			"%0 = w[%1] (z);\n\t"\
+  : "=d"(__v) : "a"(addr)); (unsigned short)__v; })
+
+#define bfin_read32(addr) ({ unsigned __v; \
+                      __asm__ __volatile__ (\
+                                            "%0 = [%1];\n\t"\
+  : "=d"(__v) : "a"(addr)); __v; })
+
+#define bfin_write16(addr,val) ({\
+                      __asm__ __volatile__ (\
+                                            "w[%0] = %1;\n\t"\
+  : : "a"(addr) , "d"(val) : "memory");})
+
+#define bfin_write32(addr,val) ({\
+                      __asm__ __volatile__ (\
+                                            "[%0] = %1;\n\t"\
+  : : "a"(addr) , "d"(val) : "memory");})
+
+#endif
+
+/**************************************************
+ * System Register Bits
+ **************************************************/
+
+/**************************************************
+ * ASTAT register
+ **************************************************/
+
+/* definitions of ASTAT bit positions*/
+
+/*Result of last ALU0 or shifter operation is zero*/
+#define ASTAT_AZ_P         0x00000000
+/*Result of last ALU0 or shifter operation is negative*/
+#define ASTAT_AN_P         0x00000001
+/*Condition Code, used for holding comparison results*/
+#define ASTAT_CC_P         0x00000005
+/*Quotient Bit*/
+#define ASTAT_AQ_P         0x00000006
+/*Rounding mode, set for biased, clear for unbiased*/
+#define ASTAT_RND_MOD_P    0x00000008
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_P        0x0000000C
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_COPY_P   0x00000002
+/*Result of last ALU1 operation generated a carry*/
+#define ASTAT_AC1_P        0x0000000D
+/*Result of last ALU0 or MAC0 operation overflowed, sticky for MAC*/
+#define ASTAT_AV0_P        0x00000010
+/*Sticky version of ASTAT_AV0 */
+#define ASTAT_AV0S_P       0x00000011
+/*Result of last MAC1 operation overflowed, sticky for MAC*/
+#define ASTAT_AV1_P        0x00000012
+/*Sticky version of ASTAT_AV1 */
+#define ASTAT_AV1S_P       0x00000013
+/*Result of last ALU0 or MAC0 operation overflowed*/
+#define ASTAT_V_P          0x00000018
+/*Result of last ALU0 or MAC0 operation overflowed*/
+#define ASTAT_V_COPY_P     0x00000003
+/*Sticky version of ASTAT_V*/
+#define ASTAT_VS_P         0x00000019
+
+/* Masks */
+
+/*Result of last ALU0 or shifter operation is zero*/
+#define ASTAT_AZ           MK_BMSK_(ASTAT_AZ_P)
+/*Result of last ALU0 or shifter operation is negative*/
+#define ASTAT_AN           MK_BMSK_(ASTAT_AN_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0          MK_BMSK_(ASTAT_AC0_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_COPY     MK_BMSK_(ASTAT_AC0_COPY_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC1          MK_BMSK_(ASTAT_AC1_P)
+/*Result of last ALU0 or MAC0 operation overflowed, sticky for MAC*/
+#define ASTAT_AV0          MK_BMSK_(ASTAT_AV0_P)
+/*Result of last MAC1 operation overflowed, sticky for MAC*/
+#define ASTAT_AV1          MK_BMSK_(ASTAT_AV1_P)
+/*Condition Code, used for holding comparison results*/
+#define ASTAT_CC           MK_BMSK_(ASTAT_CC_P)
+/*Quotient Bit*/
+#define ASTAT_AQ           MK_BMSK_(ASTAT_AQ_P)
+/*Rounding mode, set for biased, clear for unbiased*/
+#define ASTAT_RND_MOD      MK_BMSK_(ASTAT_RND_MOD_P)
+/*Overflow Bit*/
+#define ASTAT_V            MK_BMSK_(ASTAT_V_P)
+/*Overflow Bit*/
+#define ASTAT_V_COPY       MK_BMSK_(ASTAT_V_COPY_P)
+
+/**************************************************
+ *   SEQSTAT register
+ **************************************************/
+
+/* Bit Positions  */
+#define SEQSTAT_EXCAUSE0_P      0x00000000	/* Last exception cause bit 0 */
+#define SEQSTAT_EXCAUSE1_P      0x00000001	/* Last exception cause bit 1 */
+#define SEQSTAT_EXCAUSE2_P      0x00000002	/* Last exception cause bit 2 */
+#define SEQSTAT_EXCAUSE3_P      0x00000003	/* Last exception cause bit 3 */
+#define SEQSTAT_EXCAUSE4_P      0x00000004	/* Last exception cause bit 4 */
+#define SEQSTAT_EXCAUSE5_P      0x00000005	/* Last exception cause bit 5 */
+#define SEQSTAT_IDLE_REQ_P      0x0000000C	/* Pending idle mode request,
+						 * set by IDLE instruction.
+						 */
+#define SEQSTAT_SFTRESET_P      0x0000000D	/* Indicates whether the last
+						 * reset was a software reset
+						 * (=1)
+						 */
+#define SEQSTAT_HWERRCAUSE0_P   0x0000000E	/* Last hw error cause bit 0 */
+#define SEQSTAT_HWERRCAUSE1_P   0x0000000F	/* Last hw error cause bit 1 */
+#define SEQSTAT_HWERRCAUSE2_P   0x00000010	/* Last hw error cause bit 2 */
+#define SEQSTAT_HWERRCAUSE3_P   0x00000011	/* Last hw error cause bit 3 */
+#define SEQSTAT_HWERRCAUSE4_P   0x00000012	/* Last hw error cause bit 4 */
+/* Masks */
+/* Exception cause */
+#define SEQSTAT_EXCAUSE        (MK_BMSK_(SEQSTAT_EXCAUSE0_P) | \
+                                MK_BMSK_(SEQSTAT_EXCAUSE1_P) | \
+                                MK_BMSK_(SEQSTAT_EXCAUSE2_P) | \
+                                MK_BMSK_(SEQSTAT_EXCAUSE3_P) | \
+                                MK_BMSK_(SEQSTAT_EXCAUSE4_P) | \
+                                MK_BMSK_(SEQSTAT_EXCAUSE5_P) | \
+                                0)
+
+/* Indicates whether the last reset was a software reset (=1) */
+#define SEQSTAT_SFTRESET       (MK_BMSK_(SEQSTAT_SFTRESET_P))
+
+/* Last hw error cause */
+#define SEQSTAT_HWERRCAUSE     (MK_BMSK_(SEQSTAT_HWERRCAUSE0_P) | \
+                                MK_BMSK_(SEQSTAT_HWERRCAUSE1_P) | \
+                                MK_BMSK_(SEQSTAT_HWERRCAUSE2_P) | \
+                                MK_BMSK_(SEQSTAT_HWERRCAUSE3_P) | \
+                                MK_BMSK_(SEQSTAT_HWERRCAUSE4_P) | \
+                                0)
+
+/* Translate bits to something useful */
+
+/* Last hw error cause */
+#define SEQSTAT_HWERRCAUSE_SHIFT         (14)
+#define SEQSTAT_HWERRCAUSE_SYSTEM_MMR    (0x02 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_EXTERN_ADDR   (0x03 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_PERF_FLOW     (0x12 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_RAISE_5       (0x18 << SEQSTAT_HWERRCAUSE_SHIFT)
+
+/**************************************************
+ *   SYSCFG register
+ **************************************************/
+
+/* Bit Positions */
+#define SYSCFG_SSSTEP_P     0x00000000	/* Supervisor single step, when
+					 * set it forces an exception
+					 * for each instruction executed
+					 */
+#define SYSCFG_CCEN_P       0x00000001	/* Enable cycle counter (=1) */
+#define SYSCFG_SNEN_P       0x00000002	/* Self nesting Interrupt Enable */
+
+/* Masks */
+
+/* Supervisor single step, when set it forces an exception for each
+ *instruction executed
+ */
+#define SYSCFG_SSSTEP         MK_BMSK_(SYSCFG_SSSTEP_P )
+/* Enable cycle counter (=1) */
+#define SYSCFG_CCEN           MK_BMSK_(SYSCFG_CCEN_P )
+/* Self Nesting Interrupt Enable */
+#define SYSCFG_SNEN	       MK_BMSK_(SYSCFG_SNEN_P)
+/* Backward-compatibility for typos in prior releases */
+#define SYSCFG_SSSSTEP         SYSCFG_SSSTEP
+#define SYSCFG_CCCEN           SYSCFG_CCEN
+
+/****************************************************
+ * Core MMR Register Map
+ ****************************************************/
+
+/* Data Cache & SRAM Memory  (0xFFE00000 - 0xFFE00404) */
+
+#define SRAM_BASE_ADDRESS  0xFFE00000	/* SRAM Base Address Register */
+#define DMEM_CONTROL       0xFFE00004	/* Data memory control */
+#define DCPLB_STATUS       0xFFE00008	/* Data Cache Programmable Look-Aside
+					 * Buffer Status
+					 */
+#define DCPLB_FAULT_STATUS 0xFFE00008	/* "" (older define) */
+#define DCPLB_FAULT_ADDR   0xFFE0000C	/* Data Cache Programmable Look-Aside
+					 * Buffer Fault Address
+					 */
+#define DCPLB_ADDR0        0xFFE00100	/* Data Cache Protection Lookaside
+					 * Buffer 0
+					 */
+#define DCPLB_ADDR1        0xFFE00104	/* Data Cache Protection Lookaside
+					 * Buffer 1
+					 */
+#define DCPLB_ADDR2        0xFFE00108	/* Data Cache Protection Lookaside
+					 * Buffer 2
+					 */
+#define DCPLB_ADDR3        0xFFE0010C	/* Data Cacheability Protection
+					 * Lookaside Buffer 3
+					 */
+#define DCPLB_ADDR4        0xFFE00110	/* Data Cacheability Protection
+					 * Lookaside Buffer 4
+					 */
+#define DCPLB_ADDR5        0xFFE00114	/* Data Cacheability Protection
+					 * Lookaside Buffer 5
+					 */
+#define DCPLB_ADDR6        0xFFE00118	/* Data Cacheability Protection
+					 * Lookaside Buffer 6
+					 */
+#define DCPLB_ADDR7        0xFFE0011C	/* Data Cacheability Protection
+					 * Lookaside Buffer 7
+					 */
+#define DCPLB_ADDR8        0xFFE00120	/* Data Cacheability Protection
+					 * Lookaside Buffer 8
+					 */
+#define DCPLB_ADDR9        0xFFE00124	/* Data Cacheability Protection
+					 * Lookaside Buffer 9
+					 */
+#define DCPLB_ADDR10       0xFFE00128	/* Data Cacheability Protection
+					 * Lookaside Buffer 10
+					 */
+#define DCPLB_ADDR11       0xFFE0012C	/* Data Cacheability Protection
+					 * Lookaside Buffer 11
+					 */
+#define DCPLB_ADDR12       0xFFE00130	/* Data Cacheability Protection
+					 * Lookaside Buffer 12
+					 */
+#define DCPLB_ADDR13       0xFFE00134	/* Data Cacheability Protection
+					 * Lookaside Buffer 13
+					 */
+#define DCPLB_ADDR14       0xFFE00138	/* Data Cacheability Protection
+					 * Lookaside Buffer 14
+					 */
+#define DCPLB_ADDR15       0xFFE0013C	/* Data Cacheability Protection
+					 * Lookaside Buffer 15
+					 */
+#define DCPLB_DATA0        0xFFE00200	/* Data Cache 0 Status */
+#define DCPLB_DATA1        0xFFE00204	/* Data Cache 1 Status */
+#define DCPLB_DATA2        0xFFE00208	/* Data Cache 2 Status */
+#define DCPLB_DATA3        0xFFE0020C	/* Data Cache 3 Status */
+#define DCPLB_DATA4        0xFFE00210	/* Data Cache 4 Status */
+#define DCPLB_DATA5        0xFFE00214	/* Data Cache 5 Status */
+#define DCPLB_DATA6        0xFFE00218	/* Data Cache 6 Status */
+#define DCPLB_DATA7        0xFFE0021C	/* Data Cache 7 Status */
+#define DCPLB_DATA8        0xFFE00220	/* Data Cache 8 Status */
+#define DCPLB_DATA9        0xFFE00224	/* Data Cache 9 Status */
+#define DCPLB_DATA10       0xFFE00228	/* Data Cache 10 Status */
+#define DCPLB_DATA11       0xFFE0022C	/* Data Cache 11 Status */
+#define DCPLB_DATA12       0xFFE00230	/* Data Cache 12 Status */
+#define DCPLB_DATA13       0xFFE00234	/* Data Cache 13 Status */
+#define DCPLB_DATA14       0xFFE00238	/* Data Cache 14 Status */
+#define DCPLB_DATA15       0xFFE0023C	/* Data Cache 15 Status */
+#define DCPLB_DATA16       0xFFE00240	/* Extra Dummy entry */
+
+#define DTEST_COMMAND      0xFFE00300	/* Data Test Command Register */
+#define DTEST_DATA0        0xFFE00400	/* Data Test Data Register */
+#define DTEST_DATA1        0xFFE00404	/* Data Test Data Register */
+
+/* Instruction Cache & SRAM Memory  (0xFFE01004 - 0xFFE01404) */
+
+#define IMEM_CONTROL       0xFFE01004	/* Instruction Memory Control */
+#define ICPLB_STATUS       0xFFE01008	/* Instruction Cache miss status */
+#define CODE_FAULT_STATUS  0xFFE01008	/* "" (older define) */
+#define ICPLB_FAULT_ADDR   0xFFE0100C	/* Instruction Cache miss address */
+#define CODE_FAULT_ADDR    0xFFE0100C	/* "" (older define) */
+#define ICPLB_ADDR0        0xFFE01100	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 0
+					 */
+#define ICPLB_ADDR1        0xFFE01104	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 1
+					 */
+#define ICPLB_ADDR2        0xFFE01108	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 2
+					 */
+#define ICPLB_ADDR3        0xFFE0110C	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 3
+					 */
+#define ICPLB_ADDR4        0xFFE01110	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 4
+					 */
+#define ICPLB_ADDR5        0xFFE01114	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 5
+					 */
+#define ICPLB_ADDR6        0xFFE01118	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 6
+					 */
+#define ICPLB_ADDR7        0xFFE0111C	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 7
+					 */
+#define ICPLB_ADDR8        0xFFE01120	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 8
+					 */
+#define ICPLB_ADDR9        0xFFE01124	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 9
+					 */
+#define ICPLB_ADDR10       0xFFE01128	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 10
+					 */
+#define ICPLB_ADDR11       0xFFE0112C	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 11
+					 */
+#define ICPLB_ADDR12       0xFFE01130	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 12
+					 */
+#define ICPLB_ADDR13       0xFFE01134	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 13
+					 */
+#define ICPLB_ADDR14       0xFFE01138	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 14
+					 */
+#define ICPLB_ADDR15       0xFFE0113C	/* Instruction Cacheability
+					 * Protection Lookaside Buffer 15
+					 */
+#define ICPLB_DATA0        0xFFE01200	/* Instruction Cache 0 Status */
+#define ICPLB_DATA1        0xFFE01204	/* Instruction Cache 1 Status */
+#define ICPLB_DATA2        0xFFE01208	/* Instruction Cache 2 Status */
+#define ICPLB_DATA3        0xFFE0120C	/* Instruction Cache 3 Status */
+#define ICPLB_DATA4        0xFFE01210	/* Instruction Cache 4 Status */
+#define ICPLB_DATA5        0xFFE01214	/* Instruction Cache 5 Status */
+#define ICPLB_DATA6        0xFFE01218	/* Instruction Cache 6 Status */
+#define ICPLB_DATA7        0xFFE0121C	/* Instruction Cache 7 Status */
+#define ICPLB_DATA8        0xFFE01220	/* Instruction Cache 8 Status */
+#define ICPLB_DATA9        0xFFE01224	/* Instruction Cache 9 Status */
+#define ICPLB_DATA10       0xFFE01228	/* Instruction Cache 10 Status */
+#define ICPLB_DATA11       0xFFE0122C	/* Instruction Cache 11 Status */
+#define ICPLB_DATA12       0xFFE01230	/* Instruction Cache 12 Status */
+#define ICPLB_DATA13       0xFFE01234	/* Instruction Cache 13 Status */
+#define ICPLB_DATA14       0xFFE01238	/* Instruction Cache 14 Status */
+#define ICPLB_DATA15       0xFFE0123C	/* Instruction Cache 15 Status */
+#define ITEST_COMMAND      0xFFE01300	/* Instruction Test Command Register */
+#define ITEST_DATA0        0xFFE01400	/* Instruction Test Data Register */
+#define ITEST_DATA1        0xFFE01404	/* Instruction Test Data Register */
+
+/* Event/Interrupt Controller Registers   (0xFFE02000 - 0xFFE02110) */
+
+#define EVT0               0xFFE02000	/* Event Vector 0 ESR Address */
+#define EVT1               0xFFE02004	/* Event Vector 1 ESR Address */
+#define EVT2               0xFFE02008	/* Event Vector 2 ESR Address */
+#define EVT3               0xFFE0200C	/* Event Vector 3 ESR Address */
+#define EVT4               0xFFE02010	/* Event Vector 4 ESR Address */
+#define EVT5               0xFFE02014	/* Event Vector 5 ESR Address */
+#define EVT6               0xFFE02018	/* Event Vector 6 ESR Address */
+#define EVT7               0xFFE0201C	/* Event Vector 7 ESR Address */
+#define EVT8               0xFFE02020	/* Event Vector 8 ESR Address */
+#define EVT9               0xFFE02024	/* Event Vector 9 ESR Address */
+#define EVT10              0xFFE02028	/* Event Vector 10 ESR Address */
+#define EVT11              0xFFE0202C	/* Event Vector 11 ESR Address */
+#define EVT12              0xFFE02030	/* Event Vector 12 ESR Address */
+#define EVT13              0xFFE02034	/* Event Vector 13 ESR Address */
+#define EVT14              0xFFE02038	/* Event Vector 14 ESR Address */
+#define EVT15              0xFFE0203C	/* Event Vector 15 ESR Address */
+#define IMASK              0xFFE02104	/* Interrupt Mask Register */
+#define IPEND              0xFFE02108	/* Interrupt Pending Register */
+#define ILAT               0xFFE0210C	/* Interrupt Latch Register */
+#define IPRIO              0xFFE02110	/* Core Interrupt Priority Register */
+
+/* Core Timer Registers     (0xFFE03000 - 0xFFE0300C) */
+
+#define TCNTL              0xFFE03000	/* Core Timer Control Register */
+#define TPERIOD            0xFFE03004	/* Core Timer Period Register */
+#define TSCALE             0xFFE03008	/* Core Timer Scale Register */
+#define TCOUNT             0xFFE0300C	/* Core Timer Count Register */
+
+/* Debug/MP/Emulation Registers     (0xFFE05000 - 0xFFE05008) */
+#define DSPID              0xFFE05000	/* DSP Processor ID Register for
+					 * MP implementations
+					 */
+
+#define DBGSTAT            0xFFE05008	/* Debug Status Register */
+
+/* Trace Buffer Registers     (0xFFE06000 - 0xFFE06100) */
+
+#define TBUFCTL            0xFFE06000	/* Trace Buffer Control Register */
+#define TBUFSTAT           0xFFE06004	/* Trace Buffer Status Register */
+#define TBUF               0xFFE06100	/* Trace Buffer */
+
+/* Watchpoint Control Registers (0xFFE07000 - 0xFFE07200) */
+
+/* Watchpoint Instruction Address Control Register */
+#define WPIACTL            0xFFE07000
+/* Watchpoint Instruction Address Register 0 */
+#define WPIA0              0xFFE07040
+/* Watchpoint Instruction Address Register 1 */
+#define WPIA1              0xFFE07044
+/* Watchpoint Instruction Address Register 2 */
+#define WPIA2              0xFFE07048
+/* Watchpoint Instruction Address Register 3 */
+#define WPIA3              0xFFE0704C
+/* Watchpoint Instruction Address Register 4 */
+#define WPIA4              0xFFE07050
+/* Watchpoint Instruction Address Register 5 */
+#define WPIA5              0xFFE07054
+/* Watchpoint Instruction Address Count Register 0 */
+#define WPIACNT0           0xFFE07080
+/* Watchpoint Instruction Address Count Register 1 */
+#define WPIACNT1           0xFFE07084
+/* Watchpoint Instruction Address Count Register 2 */
+#define WPIACNT2           0xFFE07088
+/* Watchpoint Instruction Address Count Register 3 */
+#define WPIACNT3           0xFFE0708C
+/* Watchpoint Instruction Address Count Register 4 */
+#define WPIACNT4           0xFFE07090
+/* Watchpoint Instruction Address Count Register 5 */
+#define WPIACNT5           0xFFE07094
+/* Watchpoint Data Address Control Register */
+#define WPDACTL            0xFFE07100
+/* Watchpoint Data Address Register 0 */
+#define WPDA0              0xFFE07140
+/* Watchpoint Data Address Register 1 */
+#define WPDA1              0xFFE07144
+/* Watchpoint Data Address Count Value Register 0 */
+#define WPDACNT0           0xFFE07180
+/* Watchpoint Data Address Count Value Register 1 */
+#define WPDACNT1           0xFFE07184
+/* Watchpoint Status Register */
+#define WPSTAT             0xFFE07200
+
+/* Performance Monitor Registers    (0xFFE08000 - 0xFFE08104) */
+
+/* Performance Monitor Control Register */
+#define PFCTL              0xFFE08000
+/* Performance Monitor Counter Register 0 */
+#define PFCNTR0            0xFFE08100
+/* Performance Monitor Counter Register 1 */
+#define PFCNTR1            0xFFE08104
+
+/****************************************************
+ * Core MMR Register Bits
+ ****************************************************/
+
+/**************************************************
+ * EVT registers (ILAT, IMASK, and IPEND).
+ **************************************************/
+
+/* Bit Positions */
+#define EVT_EMU_P        0x00000000	/* Emulator interrupt bit position */
+#define EVT_RST_P        0x00000001	/* Reset interrupt bit position */
+#define EVT_NMI_P        0x00000002	/* Non Maskable interrupt bit position */
+#define EVT_EVX_P        0x00000003	/* Exception bit position */
+#define EVT_IRPTEN_P     0x00000004	/* Global interrupt enable bit position */
+#define EVT_IVHW_P       0x00000005	/* Hardware Error interrupt bit position */
+#define EVT_IVTMR_P      0x00000006	/* Timer interrupt bit position */
+#define EVT_IVG7_P       0x00000007	/* IVG7 interrupt bit position */
+#define EVT_IVG8_P       0x00000008	/* IVG8 interrupt bit position */
+#define EVT_IVG9_P       0x00000009	/* IVG9 interrupt bit position */
+#define EVT_IVG10_P      0x0000000a	/* IVG10 interrupt bit position */
+#define EVT_IVG11_P      0x0000000b	/* IVG11 interrupt bit position */
+#define EVT_IVG12_P      0x0000000c	/* IVG12 interrupt bit position */
+#define EVT_IVG13_P      0x0000000d	/* IVG13 interrupt bit position */
+#define EVT_IVG14_P      0x0000000e	/* IVG14 interrupt bit position */
+#define EVT_IVG15_P      0x0000000f	/* IVG15 interrupt bit position */
+
+/* Masks */
+#define EVT_EMU       MK_BMSK_(EVT_EMU_P   )	/* Emulator interrupt mask */
+#define EVT_RST       MK_BMSK_(EVT_RST_P   )	/* Reset interrupt mask */
+#define EVT_NMI       MK_BMSK_(EVT_NMI_P   )	/* Non Maskable interrupt mask */
+#define EVT_EVX       MK_BMSK_(EVT_EVX_P   )	/* Exception mask */
+#define EVT_IRPTEN    MK_BMSK_(EVT_IRPTEN_P)	/* Global interrupt enable mask */
+#define EVT_IVHW      MK_BMSK_(EVT_IVHW_P  )	/* Hardware Error interrupt mask */
+#define EVT_IVTMR     MK_BMSK_(EVT_IVTMR_P )	/* Timer interrupt mask */
+#define EVT_IVG7      MK_BMSK_(EVT_IVG7_P  )	/* IVG7 interrupt mask */
+#define EVT_IVG8      MK_BMSK_(EVT_IVG8_P  )	/* IVG8 interrupt mask */
+#define EVT_IVG9      MK_BMSK_(EVT_IVG9_P  )	/* IVG9 interrupt mask */
+#define EVT_IVG10     MK_BMSK_(EVT_IVG10_P )	/* IVG10 interrupt mask */
+#define EVT_IVG11     MK_BMSK_(EVT_IVG11_P )	/* IVG11 interrupt mask */
+#define EVT_IVG12     MK_BMSK_(EVT_IVG12_P )	/* IVG12 interrupt mask */
+#define EVT_IVG13     MK_BMSK_(EVT_IVG13_P )	/* IVG13 interrupt mask */
+#define EVT_IVG14     MK_BMSK_(EVT_IVG14_P )	/* IVG14 interrupt mask */
+#define EVT_IVG15     MK_BMSK_(EVT_IVG15_P )	/* IVG15 interrupt mask */
+
+/**************************************************
+ *  DMEM_CONTROL Register
+ **************************************************/
+/* Bit Positions */
+#define ENDM_P			0x00	/* (doesn't really exist) Enable
+					 *Data Memory L1
+					 */
+#define DMCTL_ENDM_P		ENDM_P	/* "" (older define) */
+
+#define ENDCPLB_P		0x01	/* Enable DCPLBS */
+#define DMCTL_ENDCPLB_P		ENDCPLB_P	/* "" (older define) */
+#define DMC0_P			0x02	/* L1 Data Memory Configure bit 0 */
+#define DMCTL_DMC0_P		DMC0_P	/* "" (older define) */
+#define DMC1_P			0x03	/* L1 Data Memory Configure bit 1 */
+#define DMCTL_DMC1_P		DMC1_P	/* "" (older define) */
+#define DCBS_P			0x04	/* L1 Data Cache Bank Select */
+#define PORT_PREF0_P		0x12	/* DAG0 Port Preference */
+#define PORT_PREF1_P		0x13	/* DAG1 Port Preference */
+
+/* Masks */
+#define ENDM               0x00000001	/* (doesn't really exist) Enable
+					 * Data Memory L1
+					 */
+#define ENDCPLB            0x00000002	/* Enable DCPLB */
+#define ASRAM_BSRAM        0x00000000
+#define ACACHE_BSRAM       0x00000008
+#define ACACHE_BCACHE      0x0000000C
+#define DCBS               0x00000010	/*  L1 Data Cache Bank Select */
+#define PORT_PREF0	   0x00001000	/* DAG0 Port Preference */
+#define PORT_PREF1	   0x00002000	/* DAG1 Port Preference */
+
+/* IMEM_CONTROL Register */
+/* Bit Positions */
+#define ENIM_P			0x00	/* Enable L1 Code Memory  */
+#define IMCTL_ENIM_P            0x00	/* "" (older define) */
+#define ENICPLB_P		0x01	/* Enable ICPLB */
+#define IMCTL_ENICPLB_P		0x01	/* "" (older define) */
+#define IMC_P			0x02	/* Enable  */
+#define IMCTL_IMC_P		0x02	/* Configure L1 code memory as
+					 * cache (0=SRAM)
+					 */
+#define ILOC0_P			0x03	/* Lock Way 0 */
+#define ILOC1_P			0x04	/* Lock Way 1 */
+#define ILOC2_P			0x05	/* Lock Way 2 */
+#define ILOC3_P			0x06	/* Lock Way 3 */
+#define LRUPRIORST_P		0x0D	/* Least Recently Used Replacement
+					 * Priority
+					 */
+/* Masks */
+#define ENIM               0x00000001	/* Enable L1 Code Memory */
+#define ENICPLB            0x00000002	/* Enable ICPLB */
+#define IMC                0x00000004	/* Configure L1 code memory as
+					 * cache (0=SRAM)
+					 */
+#define ILOC0		   0x00000008	/* Lock Way 0 */
+#define ILOC1		   0x00000010	/* Lock Way 1 */
+#define ILOC2		   0x00000020	/* Lock Way 2 */
+#define ILOC3		   0x00000040	/* Lock Way 3 */
+#define LRUPRIORST	   0x00002000	/* Least Recently Used Replacement
+					 * Priority
+					 */
+
+/* TCNTL Masks */
+#define TMPWR              0x00000001	/* Timer Low Power Control,
+					 * 0=low power mode, 1=active state
+					 */
+#define TMREN              0x00000002	/* Timer enable, 0=disable, 1=enable */
+#define TAUTORLD           0x00000004	/* Timer auto reload */
+#define TINT               0x00000008	/* Timer generated interrupt 0=no
+					 * interrupt has been generated,
+					 * 1=interrupt has been generated
+					 * (sticky)
+					 */
+
+/* DCPLB_DATA and ICPLB_DATA Registers */
+/* Bit Positions */
+#define CPLB_VALID_P       0x00000000	/* 0=invalid entry, 1=valid entry */
+#define CPLB_LOCK_P        0x00000001	/* 0=entry may be replaced, 1=entry
+					 * locked
+					 */
+#define CPLB_USER_RD_P     0x00000002	/* 0=no read access, 1=read access
+					 * allowed (user mode)
+					 */
+/* Masks */
+#define CPLB_VALID         0x00000001	/* 0=invalid entry, 1=valid entry */
+#define CPLB_LOCK          0x00000002	/* 0=entry may be replaced, 1=entry
+					 * locked
+					 */
+#define CPLB_USER_RD       0x00000004	/* 0=no read access, 1=read access
+					 * allowed (user mode)
+					 */
+#define PAGE_SIZE_1KB      0x00000000	/* 1 KB page size */
+#define PAGE_SIZE_4KB      0x00010000	/* 4 KB page size */
+#define PAGE_SIZE_1MB      0x00020000	/* 1 MB page size */
+#define PAGE_SIZE_4MB      0x00030000	/* 4 MB page size */
+#define CPLB_L1SRAM        0x00000020	/* 0=SRAM mapped in L1, 0=SRAM not
+					 * mapped to L1
+					 */
+#define CPLB_PORTPRIO	   0x00000200	/* 0=low priority port, 1= high
+					 * priority port
+					 */
+#define CPLB_L1_CHBL       0x00001000	/* 0=non-cacheable in L1, 1=cacheable
+					 * in L1
+					 */
+/* ICPLB_DATA only */
+#define CPLB_LRUPRIO	   0x00000100	/* 0=can be replaced by any line,
+					 * 1=priority for non-replacement
+					 */
+/* DCPLB_DATA only */
+#define CPLB_USER_WR       0x00000008	/* 0=no write access, 0=write
+					 * access allowed (user mode)
+					 */
+#define CPLB_SUPV_WR       0x00000010	/* 0=no write access, 0=write
+					 * access allowed (supervisor mode)
+					 */
+#define CPLB_DIRTY         0x00000080	/* 1=dirty, 0=clean */
+#define CPLB_L1_AOW	   0x00008000	/* 0=do not allocate cache lines on
+					 * write-through writes,
+					 * 1= allocate cache lines on
+					 * write-through writes.
+					 */
+#define CPLB_WT            0x00004000	/* 0=write-back, 1=write-through */
+
+/* TBUFCTL Masks */
+#define TBUFPWR            0x0001
+#define TBUFEN             0x0002
+#define TBUFOVF            0x0004
+#define TBUFCMPLP_SINGLE   0x0008
+#define TBUFCMPLP_DOUBLE   0x0010
+#define TBUFCMPLP          (TBUFCMPLP_SINGLE | TBUFCMPLP_DOUBLE)
+
+/* TBUFSTAT Masks */
+#define TBUFCNT            0x001F
+
+/* ITEST_COMMAND and DTEST_COMMAND Registers */
+/* Masks */
+#define TEST_READ	   0x00000000	/* Read Access */
+#define TEST_WRITE	   0x00000002	/* Write Access */
+#define TEST_TAG	   0x00000000	/* Access TAG */
+#define TEST_DATA	   0x00000004	/* Access DATA */
+#define TEST_DW0	   0x00000000	/* Select Double Word 0 */
+#define TEST_DW1	   0x00000008	/* Select Double Word 1 */
+#define TEST_DW2	   0x00000010	/* Select Double Word 2 */
+#define TEST_DW3	   0x00000018	/* Select Double Word 3 */
+#define TEST_MB0	   0x00000000	/* Select Mini-Bank 0 */
+#define TEST_MB1	   0x00010000	/* Select Mini-Bank 1 */
+#define TEST_MB2	   0x00020000	/* Select Mini-Bank 2 */
+#define TEST_MB3	   0x00030000	/* Select Mini-Bank 3 */
+#define TEST_SET(x)	   ((x << 5) & 0x03E0)	/* Set Index 0->31 */
+#define TEST_WAY0	   0x00000000	/* Access Way0 */
+#define TEST_WAY1	   0x04000000	/* Access Way1 */
+/* ITEST_COMMAND only */
+#define TEST_WAY2	   0x08000000	/* Access Way2 */
+#define TEST_WAY3	   0x0C000000	/* Access Way3 */
+/* DTEST_COMMAND only */
+#define TEST_BNKSELA	   0x00000000	/* Access SuperBank A */
+#define TEST_BNKSELB	   0x00800000	/* Access SuperBank B */
+
+#endif				/* _DEF_LPBLACKFIN_H */
diff --git a/include/asm-blackfin/macros.h b/include/asm-blackfin/macros.h
new file mode 100644
index 0000000..c0c04a2
--- /dev/null
+++ b/include/asm-blackfin/macros.h
@@ -0,0 +1,95 @@
+/************************************************************************
+ *
+ * macros.h
+ *
+ * (c) Copyright 2001-2003 Analog Devices, Inc.  All rights reserved.
+ *
+ ************************************************************************/
+
+/* Defines various assembly macros. */
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+#define LO(con32) ((con32) & 0xFFFF)
+#define lo(con32) ((con32) & 0xFFFF)
+#define HI(con32) (((con32) >> 16) & 0xFFFF)
+#define hi(con32) (((con32) >> 16) & 0xFFFF)
+
+/*
+ * Set the corresponding bits in a System Register (SR);
+ * All bits set in "mask" will be set in the system register
+ * specified by "sys_reg" bitset_SR(sys_reg, mask), where
+ * sys_reg is the system register and mask are the bits to be set.
+ */
+#define bitset_SR(sys_reg, mask)\
+		[--SP] = (R7:6);\
+		r7 = sys_reg;\
+		r6.l = (mask) & 0xffff;\
+		r6.h = (mask) >> 16;\
+		r7 = r7 | r6;\
+		sys_reg = r7;\
+		csync;\
+		(R7:6) = [SP++]
+
+/*
+ * Clear the corresponding bits in a System Register (SR);
+ * All bits set in "mask" will be cleared in the SR
+ * specified by "sys_reg" bitclr_SR(sys_reg, mask), where
+ * sys_reg is the SR and mask are the bits to be cleared.
+ */
+#define bitclr_SR(sys_reg, mask)\
+		[--SP] = (R7:6);\
+		r7 = sys_reg;\
+		r7 =~ r7;\
+		r6.l = (mask) & 0xffff;\
+		r6.h = (mask) >> 16;\
+		r7 = r7 | r6;\
+		r7 =~ r7;\
+		sys_reg = r7;\
+		csync;\
+		(R7:6) = [SP++]
+
+/*
+ * Set the corresponding bits in a Memory Mapped Register (MMR);
+ * All bits set in "mask" will be set in the MMR specified by "mmr_reg"
+ * bitset_MMR(mmr_reg, mask), where mmr_reg is the MMR and mask are
+ * the bits to be set.
+ */
+#define bitset_MMR(mmr_reg, mask)\
+		[--SP] = (R7:6);\
+		[--SP] = P5;\
+		p5.l = mmr_reg & 0xffff;\
+		p5.h = mmr_reg >> 16;\
+		r7 = [p5];\
+		r6.l = (mask) & 0xffff;\
+		r6.h = (mask) >> 16;\
+		r7 = r7 | r6;\
+		[p5] = r7;\
+		csync;\
+		p5 = [SP++];\
+		(R7:6) = [SP++]
+
+/*
+ * Clear the corresponding bits in a Memory Mapped Register (MMR);
+ * All bits set in "mask" will be cleared in the MMR specified by "mmr_reg"
+ * bitclr_MMRreg(mmr_reg, mask), where sys_reg is the MMR and mask are
+ * the bits to be cleared.
+ */
+#define bitclr_MMR(mmr_reg, mask)\
+		[--SP] = (R7:6);\
+		[--SP] = P5;\
+		p5.l = mmr_reg & 0xffff;\
+		p5.h = mmr_reg >> 16;\
+		r7 = [p5];\
+		r7 =~ r7;\
+		r6.l = (mask) & 0xffff;\
+		r6.h = (mask) >> 16;\
+		r7 = r7 | r6;\
+		r7 =~ r7;\
+		[p5] = r7;\
+		csync;\
+		p5 = [SP++];\
+		(R7:6) = [SP++]
+
+#endif				/* _MACROS_H */
diff --git a/include/asm-blackfin/mem_map.h b/include/asm-blackfin/mem_map.h
new file mode 100644
index 0000000..42d1f37
--- /dev/null
+++ b/include/asm-blackfin/mem_map.h
@@ -0,0 +1,12 @@
+/*
+ * mem_map.h
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _MEM_MAP_H_
+#define _MEM_MAP_H_
+
+#include <asm/mach/mem_map.h>
+
+#endif				/* _MEM_MAP_H_ */
diff --git a/include/asm-blackfin/mman.h b/include/asm-blackfin/mman.h
new file mode 100644
index 0000000..4d504f9
--- /dev/null
+++ b/include/asm-blackfin/mman.h
@@ -0,0 +1,45 @@
+#ifndef __BFIN_MMAN_H__
+#define __BFIN_MMAN_H__
+
+#define PROT_READ	0x1	/* page can be read */
+#define PROT_WRITE	0x2	/* page can be written */
+#define PROT_EXEC	0x4	/* page can be executed */
+#define PROT_SEM	0x8	/* page may be used for atomic ops */
+#define PROT_NONE	0x0	/* page can not be accessed */
+#define PROT_GROWSDOWN	0x01000000	/* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP	0x02000000	/* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED	0x01	/* Share changes */
+#define MAP_PRIVATE	0x02	/* Changes are private */
+#define MAP_TYPE	0x0f	/* Mask for type of mapping */
+#define MAP_FIXED	0x10	/* Interpret addr exactly */
+#define MAP_ANONYMOUS	0x20	/* don't use a file */
+
+#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) pagetables */
+#define MAP_NONBLOCK	0x10000	/* do not block on IO */
+#define MAP_UNINITIALIZE 0x4000000  /* For anonymous mmap, memory could
+                                    be uninitialized. */
+
+#define MS_ASYNC	1	/* sync memory asynchronously */
+#define MS_INVALIDATE	2	/* invalidate the caches */
+#define MS_SYNC		4	/* synchronous memory sync */
+
+#define MCL_CURRENT	1	/* lock all current mappings */
+#define MCL_FUTURE	2	/* lock all future mappings */
+
+#define MADV_NORMAL	0x0	/* default page-in behavior */
+#define MADV_RANDOM	0x1	/* page-in minimum required */
+#define MADV_SEQUENTIAL	0x2	/* read-ahead aggressively */
+#define MADV_WILLNEED	0x3	/* pre-fault pages */
+#define MADV_DONTNEED	0x4	/* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif				/* __BFIN_MMAN_H__ */
diff --git a/include/asm-blackfin/mmu.h b/include/asm-blackfin/mmu.h
new file mode 100644
index 0000000..11d52f1
--- /dev/null
+++ b/include/asm-blackfin/mmu.h
@@ -0,0 +1,30 @@
+#ifndef __MMU_H
+#define __MMU_H
+
+/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
+
+struct sram_list_struct {
+	struct sram_list_struct *next;
+	void *addr;
+	size_t length;
+};
+
+typedef struct {
+	struct vm_list_struct *vmlist;
+	unsigned long end_brk;
+	unsigned long stack_start;
+
+	/* Points to the location in SDRAM where the L1 stack is normally
+	   saved, or NULL if the stack is always in SDRAM.  */
+	void *l1_stack_save;
+
+	struct sram_list_struct *sram_list;
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+	unsigned long	exec_fdpic_loadmap;
+	unsigned long	interp_fdpic_loadmap;
+#endif
+
+} mm_context_t;
+
+#endif
diff --git a/include/asm-blackfin/mmu_context.h b/include/asm-blackfin/mmu_context.h
new file mode 100644
index 0000000..c5c71a6
--- /dev/null
+++ b/include/asm-blackfin/mmu_context.h
@@ -0,0 +1,129 @@
+/*
+ * File:         include/asm-blackfin/mmu_context.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *               Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __BLACKFIN_MMU_CONTEXT_H__
+#define __BLACKFIN_MMU_CONTEXT_H__
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+extern void *current_l1_stack_save;
+extern int nr_l1stack_tasks;
+extern void *l1_stack_base;
+extern unsigned long l1_stack_len;
+
+extern int l1sram_free(const void*);
+extern void *l1sram_alloc_max(void*);
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/* Called when creating a new context during fork() or execve().  */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	return 0;
+}
+
+static inline void free_l1stack(void)
+{
+	nr_l1stack_tasks--;
+	if (nr_l1stack_tasks == 0)
+		l1sram_free(l1_stack_base);
+}
+static inline void destroy_context(struct mm_struct *mm)
+{
+	struct sram_list_struct *tmp;
+
+	if (current_l1_stack_save == mm->context.l1_stack_save)
+		current_l1_stack_save = 0;
+	if (mm->context.l1_stack_save)
+		free_l1stack();
+
+	while ((tmp = mm->context.sram_list)) {
+		mm->context.sram_list = tmp->next;
+		sram_free(tmp->addr);
+		kfree(tmp);
+	}
+}
+
+static inline unsigned long
+alloc_l1stack(unsigned long length, unsigned long *stack_base)
+{
+	if (nr_l1stack_tasks == 0) {
+		l1_stack_base = l1sram_alloc_max(&l1_stack_len);
+		if (!l1_stack_base)
+			return 0;
+	}
+
+	if (l1_stack_len < length) {
+		if (nr_l1stack_tasks == 0)
+			l1sram_free(l1_stack_base);
+		return 0;
+	}
+	*stack_base = (unsigned long)l1_stack_base;
+	nr_l1stack_tasks++;
+	return l1_stack_len;
+}
+
+static inline int
+activate_l1stack(struct mm_struct *mm, unsigned long sp_base)
+{
+	if (current_l1_stack_save)
+		memcpy(current_l1_stack_save, l1_stack_base, l1_stack_len);
+	mm->context.l1_stack_save = current_l1_stack_save = (void*)sp_base;
+	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+	return 1;
+}
+
+#define deactivate_mm(tsk,mm)	do { } while (0)
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+			       struct mm_struct *next_mm)
+{
+	if (!next_mm->context.l1_stack_save)
+		return;
+	if (next_mm->context.l1_stack_save == current_l1_stack_save)
+		return;
+	if (current_l1_stack_save) {
+		memcpy(current_l1_stack_save, l1_stack_base, l1_stack_len);
+	}
+	current_l1_stack_save = next_mm->context.l1_stack_save;
+	memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+			     struct task_struct *tsk)
+{
+	activate_mm(prev, next);
+}
+
+#endif
diff --git a/include/asm-blackfin/module.h b/include/asm-blackfin/module.h
new file mode 100644
index 0000000..3c7ce16
--- /dev/null
+++ b/include/asm-blackfin/module.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_BFIN_MODULE_H
+#define _ASM_BFIN_MODULE_H
+
+#define MODULE_SYMBOL_PREFIX "_"
+
+#define Elf_Shdr        Elf32_Shdr
+#define Elf_Sym         Elf32_Sym
+#define Elf_Ehdr        Elf32_Ehdr
+#define FLG_CODE_IN_L1	0x10
+#define FLG_DATA_IN_L1	0x20
+
+struct mod_arch_specific {
+	Elf_Shdr	*text_l1;
+	Elf_Shdr	*data_a_l1;
+	Elf_Shdr	*bss_a_l1;
+	Elf_Shdr	*data_b_l1;
+	Elf_Shdr	*bss_b_l1;
+};
+#endif				/* _ASM_BFIN_MODULE_H */
diff --git a/include/asm-blackfin/msgbuf.h b/include/asm-blackfin/msgbuf.h
new file mode 100644
index 0000000..6fcbe8c
--- /dev/null
+++ b/include/asm-blackfin/msgbuf.h
@@ -0,0 +1,31 @@
+#ifndef _BFIN_MSGBUF_H
+#define _BFIN_MSGBUF_H
+
+/*
+ * The msqid64_ds structure for bfin 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				/* _BFIN_MSGBUF_H */
diff --git a/include/asm-blackfin/mutex.h b/include/asm-blackfin/mutex.h
new file mode 100644
index 0000000..458c1f7
--- /dev/null
+++ b/include/asm-blackfin/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-blackfin/namei.h b/include/asm-blackfin/namei.h
new file mode 100644
index 0000000..8b89a2d
--- /dev/null
+++ b/include/asm-blackfin/namei.h
@@ -0,0 +1,19 @@
+/*
+ * linux/include/asm/namei.h
+ *
+ * Included from linux/fs/namei.c
+ *
+ * Changes made by Lineo Inc.    May 2001
+ */
+
+#ifndef __BFIN_NAMEI_H
+#define __BFIN_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif
diff --git a/include/asm-blackfin/page.h b/include/asm-blackfin/page.h
new file mode 100644
index 0000000..ffad947
--- /dev/null
+++ b/include/asm-blackfin/page.h
@@ -0,0 +1,89 @@
+#ifndef _BLACKFIN_PAGE_H
+#define _BLACKFIN_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+
+#define PAGE_SHIFT	12
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+
+#include <asm/setup.h>
+
+#ifndef __ASSEMBLY__
+
+#define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)	free_page(addr)
+
+#define clear_page(page)	memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)	memcpy((to), (from), PAGE_SIZE)
+
+#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 pmd[16];
+} 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[0])
+#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) } )
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif				/* !__ASSEMBLY__ */
+
+#include <asm/page_offset.h>
+#include <asm/io.h>
+
+#define PAGE_OFFSET		(PAGE_OFFSET_RAW)
+
+#ifndef __ASSEMBLY__
+
+#define __pa(vaddr)		virt_to_phys((void *)(vaddr))
+#define __va(paddr)		phys_to_virt((unsigned long)(paddr))
+
+#define MAP_NR(addr)		(((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
+
+#define virt_to_pfn(kaddr)	(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn)	__va((pfn) << PAGE_SHIFT)
+#define virt_to_page(addr)	(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define page_to_virt(page)	((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+
+#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 pfn_valid(pfn)	        ((pfn) < max_mapnr)
+
+#define	virt_addr_valid(kaddr)	(((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+				((void *)(kaddr) < (void *)memory_end))
+
+#include <asm-generic/page.h>
+
+#endif				/* __ASSEMBLY__ */
+#endif				/* __KERNEL__ */
+
+#endif				/* _BLACKFIN_PAGE_H */
diff --git a/include/asm-blackfin/page_offset.h b/include/asm-blackfin/page_offset.h
new file mode 100644
index 0000000..3b671d5
--- /dev/null
+++ b/include/asm-blackfin/page_offset.h
@@ -0,0 +1,6 @@
+
+/* This handles the memory map.. */
+
+#ifdef CONFIG_BFIN
+#define PAGE_OFFSET_RAW		0x00000000
+#endif
diff --git a/include/asm-blackfin/param.h b/include/asm-blackfin/param.h
new file mode 100644
index 0000000..41564a6
--- /dev/null
+++ b/include/asm-blackfin/param.h
@@ -0,0 +1,22 @@
+#ifndef _BLACKFIN_PARAM_H
+#define _BLACKFIN_PARAM_H
+
+#ifdef __KERNEL__
+#define HZ 		CONFIG_HZ
+#define	USER_HZ		100
+#define	CLOCKS_PER_SEC	(USER_HZ)
+#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				/* _BLACKFIN_PARAM_H */
diff --git a/include/asm-blackfin/pci.h b/include/asm-blackfin/pci.h
new file mode 100644
index 0000000..6127735
--- /dev/null
+++ b/include/asm-blackfin/pci.h
@@ -0,0 +1,148 @@
+/* Changed from asm-m68k version, Lineo Inc. 	May 2001	*/
+
+#ifndef _ASM_BFIN_PCI_H
+#define _ASM_BFIN_PCI_H
+
+#include <asm/scatterlist.h>
+
+/*
+ *
+ * Written by Wout Klaren.
+ */
+
+/* Added by Chang Junxiao */
+#define PCIBIOS_MIN_IO 0x00001000
+#define PCIBIOS_MIN_MEM 0x10000000
+
+#define PCI_DMA_BUS_IS_PHYS       (1)
+struct pci_ops;
+
+/*
+ * Structure with hardware dependent information and functions of the
+ * PCI bus.
+ */
+struct pci_bus_info {
+
+	/*
+	 * Resources of the PCI bus.
+	 */
+	struct resource mem_space;
+	struct resource io_space;
+
+	/*
+	 * System dependent functions.
+	 */
+	struct pci_ops *bfin_pci_ops;
+	void (*fixup) (int pci_modify);
+	void (*conf_device) (unsigned char bus, unsigned char device_fn);
+};
+
+#define pcibios_assign_all_busses()	0
+static inline void pcibios_set_master(struct pci_dev *dev)
+{
+
+	/* No special bus mastering setup handling */
+}
+static inline void pcibios_penalize_isa_irq(int irq)
+{
+
+	/* We don't do dynamic PCI IRQ allocation */
+}
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	 /* return virt_to_bus(ptr); */
+	return (dma_addr_t) ptr;
+}
+
+/* Unmap a single streaming mode DMA translation.  The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+				    size_t size, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	/* Nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-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 pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			     int nents, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+	return nents;
+}
+
+/* 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 pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+				int nents, int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	/* Nothing to do */
+}
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so.  At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
+				       dma_addr_t dma_handle, size_t size,
+				       int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	/* Nothing to do */
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+				   struct scatterlist *sg, int nelems,
+				   int direction)
+{
+	if (direction == PCI_DMA_NONE)
+		BUG();
+
+	/* Nothing to do */
+}
+
+#endif				/* _ASM_BFIN_PCI_H */
diff --git a/include/asm-blackfin/percpu.h b/include/asm-blackfin/percpu.h
new file mode 100644
index 0000000..78dd61f
--- /dev/null
+++ b/include/asm-blackfin/percpu.h
@@ -0,0 +1,6 @@
+#ifndef __ARCH_BLACKFIN_PERCPU__
+#define __ARCH_BLACKFIN_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif				/* __ARCH_BLACKFIN_PERCPU__ */
diff --git a/include/asm-blackfin/pgalloc.h b/include/asm-blackfin/pgalloc.h
new file mode 100644
index 0000000..c686e05
--- /dev/null
+++ b/include/asm-blackfin/pgalloc.h
@@ -0,0 +1,8 @@
+#ifndef _BLACKFIN_PGALLOC_H
+#define _BLACKFIN_PGALLOC_H
+
+#include <asm/setup.h>
+
+#define check_pgt_cache()	do { } while (0)
+
+#endif				/* _BLACKFIN_PGALLOC_H */
diff --git a/include/asm-blackfin/pgtable.h b/include/asm-blackfin/pgtable.h
new file mode 100644
index 0000000..5a8f9e4
--- /dev/null
+++ b/include/asm-blackfin/pgtable.h
@@ -0,0 +1,96 @@
+#ifndef _BLACKFIN_PGTABLE_H
+#define _BLACKFIN_PGTABLE_H
+
+#include <asm-generic/4level-fixup.h>
+
+#include <asm/page.h>
+#include <asm/cplb.h>
+
+typedef pte_t *pte_addr_t;
+/*
+* Trivial page table functions.
+*/
+#define pgd_present(pgd)	(1)
+#define pgd_none(pgd)		(0)
+#define pgd_bad(pgd)		(0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr)	(1)
+
+#define pmd_offset(a, b)	((void *)0)
+#define pmd_none(x)		(!pmd_val(x))
+#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)
+
+#define kern_addr_valid(addr) (1)
+
+#define PAGE_NONE		__pgprot(0)	/* these mean nothing to NO_MM */
+#define PAGE_SHARED		__pgprot(0)	/* these mean nothing to NO_MM */
+#define PAGE_COPY		__pgprot(0)	/* these mean nothing to NO_MM */
+#define PAGE_READONLY		__pgprot(0)	/* these mean nothing to NO_MM */
+#define PAGE_KERNEL		__pgprot(0)	/* these mean nothing to NO_MM */
+
+extern void paging_init(void);
+
+#define __swp_type(x)		(0)
+#define __swp_offset(x)		(0)
+#define __swp_entry(typ,off)	((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)	((pte_t) { (x).val })
+
+static inline int pte_file(pte_t pte)
+{
+	return 0;
+}
+
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
+
+/*
+ * Page assess control based on Blackfin CPLB management
+ */
+#define _PAGE_RD	(CPLB_USER_RD)
+#define _PAGE_WR	(CPLB_USER_WR)
+#define _PAGE_USER	(CPLB_USER_RD | CPLB_USER_WR)
+#define _PAGE_ACCESSED	CPLB_ALL_ACCESS
+#define _PAGE_DIRTY	(CPLB_DIRTY)
+
+#define PTE_BIT_FUNC(fn, op) \
+	static inline pte_t pte_##fn(pte_t _pte) { _pte.pte op; return _pte; }
+
+PTE_BIT_FUNC(rdprotect, &= ~_PAGE_RD);
+PTE_BIT_FUNC(mkread, |= _PAGE_RD);
+PTE_BIT_FUNC(wrprotect, &= ~_PAGE_WR);
+PTE_BIT_FUNC(mkwrite, |= _PAGE_WR);
+PTE_BIT_FUNC(exprotect, &= ~_PAGE_USER);
+PTE_BIT_FUNC(mkexec, |= _PAGE_USER);
+PTE_BIT_FUNC(mkclean, &= ~_PAGE_DIRTY);
+PTE_BIT_FUNC(mkdirty, |= _PAGE_DIRTY);
+PTE_BIT_FUNC(mkold, &= ~_PAGE_ACCESSED);
+PTE_BIT_FUNC(mkyoung, |= _PAGE_ACCESSED);
+
+/*
+ * 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(0))
+
+extern unsigned int kobjsize(const void *objp);
+
+#define swapper_pg_dir ((pgd_t *) 0)
+/*
+ * No page table caches to initialise.
+ */
+#define pgtable_cache_init()	do { } while (0)
+#define io_remap_pfn_range      remap_pfn_range
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define	VMALLOC_START	0
+#define	VMALLOC_END	0xffffffff
+
+#include <asm-generic/pgtable.h>
+
+#endif				/* _BLACKFIN_PGTABLE_H */
diff --git a/include/asm-blackfin/poll.h b/include/asm-blackfin/poll.h
new file mode 100644
index 0000000..94cc263
--- /dev/null
+++ b/include/asm-blackfin/poll.h
@@ -0,0 +1,24 @@
+#ifndef __BFIN_POLL_H
+#define __BFIN_POLL_H
+
+#define POLLIN		  1
+#define POLLPRI		  2
+#define POLLOUT		  4
+#define POLLERR		  8
+#define POLLHUP		 16
+#define POLLNVAL	 32
+#define POLLRDNORM	 64
+#define POLLWRNORM	POLLOUT
+#define POLLRDBAND	128
+#define POLLWRBAND	256
+#define POLLMSG		0x0400
+#define POLLREMOVE	0x1000
+#define POLLRDHUP       0x2000
+
+struct pollfd {
+	int fd;
+	short events;
+	short revents;
+};
+
+#endif				/* __BFIN_POLL_H */
diff --git a/include/asm-blackfin/posix_types.h b/include/asm-blackfin/posix_types.h
new file mode 100644
index 0000000..c3fa50f
--- /dev/null
+++ b/include/asm-blackfin/posix_types.h
@@ -0,0 +1,65 @@
+#ifndef __ARCH_BFIN_POSIX_TYPES_H
+#define __ARCH_BFIN_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 int __kernel_ipc_pid_t;
+typedef unsigned int __kernel_uid_t;
+typedef unsigned int __kernel_gid_t;
+typedef unsigned long __kernel_size_t;
+typedef long __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__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef	__FD_SET
+#define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+
+#undef	__FD_CLR
+#define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+
+#undef	__FD_ISSET
+#define	__FD_ISSET(d, set)	((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+
+#undef	__FD_ZERO
+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif				/* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif
diff --git a/include/asm-blackfin/processor.h b/include/asm-blackfin/processor.h
new file mode 100644
index 0000000..997465c
--- /dev/null
+++ b/include/asm-blackfin/processor.h
@@ -0,0 +1,130 @@
+#ifndef __ASM_BFIN_PROCESSOR_H
+#define __ASM_BFIN_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#include <asm/blackfin.h>
+#include <asm/segment.h>
+#include <linux/compiler.h>
+
+static inline unsigned long rdusp(void)
+{
+	unsigned long usp;
+
+	__asm__ __volatile__("%0 = usp;\n\t":"=da"(usp));
+	return usp;
+}
+
+static inline void wrusp(unsigned long usp)
+{
+	__asm__ __volatile__("usp = %0;\n\t"::"da"(usp));
+}
+
+/*
+ * User space process size: 1st byte beyond user address space.
+ */
+extern unsigned long memory_end;
+#define TASK_SIZE	(memory_end)
+
+#define TASK_UNMAPPED_BASE	0
+
+struct thread_struct {
+	unsigned long ksp;	/* kernel stack pointer */
+	unsigned long usp;	/* user stack pointer */
+	unsigned short seqstat;	/* saved status register */
+	unsigned long esp0;	/* points to SR of stack frame pt_regs */
+	unsigned long pc;	/* instruction pointer */
+	void *        debuggerinfo;
+};
+
+#define INIT_THREAD  {						\
+	sizeof(init_stack) + (unsigned long) init_stack, 0,	\
+	PS_S, 0, 0						\
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ *
+ * pass the data segment into user programs if it exists,
+ * it can't hurt anything as far as I can tell
+ */
+#define start_thread(_regs, _pc, _usp)					\
+do {									\
+	set_fs(USER_DS);						\
+	(_regs)->pc = (_pc);						\
+	if (current->mm)						\
+		(_regs)->p5 = current->mm->start_data;			\
+	current->thread_info->l1_task_info.stack_start			\
+		= (void *)current->mm->context.stack_start;		\
+	current->thread_info->l1_task_info.lowest_sp = (void *)(_usp);	       	\
+	memcpy(L1_SCRATCH_TASK_INFO, &current->thread_info->l1_task_info,	\
+		sizeof(*L1_SCRATCH_TASK_INFO));				\
+	wrusp(_usp);							\
+} while(0)
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+#define prepare_to_copy(tsk)	do { } while (0)
+
+extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+#define thread_saved_pc(tsk)	(tsk->thread.pc)
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define	KSTK_EIP(tsk)							\
+    ({									\
+	unsigned long eip = 0;						\
+	if ((tsk)->thread.esp0 > PAGE_SIZE &&				\
+	    MAP_NR((tsk)->thread.esp0) < max_mapnr)			\
+	      eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc;	\
+	eip; })
+#define	KSTK_ESP(tsk)	((tsk) == current ? rdusp() : (tsk)->thread.usp)
+
+#define cpu_relax()    	barrier()
+
+/* Get the Silicon Revision of the chip */
+static inline uint32_t bfin_revid(void)
+{
+	/* stored in the upper 4 bits */
+	return bfin_read_CHIPID() >> 28;
+}
+
+static inline uint32_t bfin_compiled_revid(void)
+{
+#if defined(CONFIG_BF_REV_0_0)
+	return 0;
+#elif defined(CONFIG_BF_REV_0_1)
+	return 1;
+#elif defined(CONFIG_BF_REV_0_2)
+	return 2;
+#elif defined(CONFIG_BF_REV_0_3)
+	return 3;
+#elif defined(CONFIG_BF_REV_0_4)
+	return 4;
+#elif defined(CONFIG_BF_REV_0_5)
+	return 5;
+#endif
+}
+
+#endif
diff --git a/include/asm-blackfin/ptrace.h b/include/asm-blackfin/ptrace.h
new file mode 100644
index 0000000..b8346cd
--- /dev/null
+++ b/include/asm-blackfin/ptrace.h
@@ -0,0 +1,166 @@
+#ifndef _BFIN_PTRACE_H
+#define _BFIN_PTRACE_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ *       0 - 7 are data registers R0-R7
+ *       8 - 15 are address registers P0-P7
+ *      16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3
+ *      32 - 33 A registers A0 & A1
+ *      34 -    status register
+ * -----------------------------
+ *
+ * We follows above, except:
+ *      32-33 --- Low 32-bit of A0&1
+ *      34-35 --- High 8-bit of A0&1
+ */
+
+#ifndef __ASSEMBLY__
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct pt_regs {
+	long orig_pc;
+	long ipend;
+	long seqstat;
+	long rete;
+	long retn;
+	long retx;
+	long pc;		/* PC == RETI */
+	long rets;
+	long reserved;		/* Used as scratch during system calls */
+	long astat;
+	long lb1;
+	long lb0;
+	long lt1;
+	long lt0;
+	long lc1;
+	long lc0;
+	long a1w;
+	long a1x;
+	long a0w;
+	long a0x;
+	long b3;
+	long b2;
+	long b1;
+	long b0;
+	long l3;
+	long l2;
+	long l1;
+	long l0;
+	long m3;
+	long m2;
+	long m1;
+	long m0;
+	long i3;
+	long i2;
+	long i1;
+	long i0;
+	long usp;
+	long fp;
+	long p5;
+	long p4;
+	long p3;
+	long p2;
+	long p1;
+	long p0;
+	long r7;
+	long r6;
+	long r5;
+	long r4;
+	long r3;
+	long r2;
+	long r1;
+	long r0;
+	long orig_r0;
+	long orig_p0;
+	long syscfg;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13	/* ptrace signal  */
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+#define PTRACE_GETFDPIC           31
+#define PTRACE_GETFDPIC_EXEC      0
+#define PTRACE_GETFDPIC_INTERP    1
+#endif
+
+#define PS_S  (0x0002)
+
+/* user_mode returns true if only one bit is set in IPEND, other than the
+   master interrupt enable.  */
+#define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+extern void show_regs(struct pt_regs *);
+
+#endif				/* __ASSEMBLY__ */
+
+/*
+ * Offsets used by 'ptrace' system call interface.
+ */
+
+#define PT_R0 204
+#define PT_R1 200
+#define PT_R2 196
+#define PT_R3 192
+#define PT_R4 188
+#define PT_R5 184
+#define PT_R6 180
+#define PT_R7 176
+#define PT_P0 172
+#define PT_P1 168
+#define PT_P2 164
+#define PT_P3 160
+#define PT_P4 156
+#define PT_P5 152
+#define PT_FP 148
+#define PT_USP 144
+#define PT_I0 140
+#define PT_I1 136
+#define PT_I2 132
+#define PT_I3 128
+#define PT_M0 124
+#define PT_M1 120
+#define PT_M2 116
+#define PT_M3 112
+#define PT_L0 108
+#define PT_L1 104
+#define PT_L2 100
+#define PT_L3 96
+#define PT_B0 92
+#define PT_B1 88
+#define PT_B2 84
+#define PT_B3 80
+#define PT_A0X 76
+#define PT_A0W 72
+#define PT_A1X 68
+#define PT_A1W 64
+#define PT_LC0 60
+#define PT_LC1 56
+#define PT_LT0 52
+#define PT_LT1 48
+#define PT_LB0 44
+#define PT_LB1 40
+#define PT_ASTAT 36
+#define PT_RESERVED 32
+#define PT_RETS 28
+#define PT_PC 24
+#define PT_RETX 20
+#define PT_RETN 16
+#define PT_RETE 12
+#define PT_SEQSTAT 8
+#define PT_IPEND 4
+
+#define PT_SYSCFG 216
+#define PT_TEXT_ADDR 220
+#define PT_TEXT_END_ADDR 224
+#define PT_DATA_ADDR 228
+#define PT_FDPIC_EXEC 232
+#define PT_FDPIC_INTERP 236
+
+#endif				/* _BFIN_PTRACE_H */
diff --git a/include/asm-blackfin/resource.h b/include/asm-blackfin/resource.h
new file mode 100644
index 0000000..091355a
--- /dev/null
+++ b/include/asm-blackfin/resource.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_RESOURCE_H
+#define _BFIN_RESOURCE_H
+
+#include <asm-generic/resource.h>
+
+#endif				/* _BFIN_RESOURCE_H */
diff --git a/include/asm-blackfin/scatterlist.h b/include/asm-blackfin/scatterlist.h
new file mode 100644
index 0000000..60e07b9
--- /dev/null
+++ b/include/asm-blackfin/scatterlist.h
@@ -0,0 +1,26 @@
+#ifndef _BLACKFIN_SCATTERLIST_H
+#define _BLACKFIN_SCATTERLIST_H
+
+#include <linux/mm.h>
+
+struct scatterlist {
+	struct page *page;
+	unsigned int offset;
+	dma_addr_t dma_address;
+	unsigned int length;
+};
+
+/*
+ * These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_address(sg) (page_address((sg)->page) + (sg)->offset)
+#define sg_dma_address(sg)      ((sg)->dma_address)
+#define sg_dma_len(sg)          ((sg)->length)
+
+#define ISA_DMA_THRESHOLD	(0xffffffff)
+
+#endif				/* !(_BLACKFIN_SCATTERLIST_H) */
diff --git a/include/asm-blackfin/sections.h b/include/asm-blackfin/sections.h
new file mode 100644
index 0000000..1443c33
--- /dev/null
+++ b/include/asm-blackfin/sections.h
@@ -0,0 +1,7 @@
+#ifndef _BLACKFIN_SECTIONS_H
+#define _BLACKFIN_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/include/asm-blackfin/segment.h b/include/asm-blackfin/segment.h
new file mode 100644
index 0000000..02cfd09
--- /dev/null
+++ b/include/asm-blackfin/segment.h
@@ -0,0 +1,7 @@
+#ifndef _BFIN_SEGMENT_H
+#define _BFIN_SEGMENT_H
+
+#define KERNEL_DS   (0x5)
+#define USER_DS     (0x1)
+
+#endif				/* _BFIN_SEGMENT_H */
diff --git a/include/asm-blackfin/semaphore-helper.h b/include/asm-blackfin/semaphore-helper.h
new file mode 100644
index 0000000..9082b0d
--- /dev/null
+++ b/include/asm-blackfin/semaphore-helper.h
@@ -0,0 +1,82 @@
+/* Based on M68K version,	Lineo Inc.	May 2001 */
+
+#ifndef _BFIN_SEMAPHORE_HELPER_H
+#define _BFIN_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ */
+
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore *sem)
+{
+	atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	int ret;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	ret = 0;
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	int ret = 1;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 0;
+	} else
+		atomic_inc(&sem->count);
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+#endif				/* _BFIN_SEMAPHORE_HELPER_H */
diff --git a/include/asm-blackfin/semaphore.h b/include/asm-blackfin/semaphore.h
new file mode 100644
index 0000000..94c04d7
--- /dev/null
+++ b/include/asm-blackfin/semaphore.h
@@ -0,0 +1,106 @@
+#ifndef _BFIN_SEMAPHORE_H
+#define _BFIN_SEMAPHORE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <asm/atomic.h>
+
+/*
+ * Interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * BFIN version by akbar hussain Lineo Inc  April 2001
+ *
+ */
+
+struct semaphore {
+	atomic_t count;
+	int sleepers;
+	wait_queue_head_t wait;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n)				\
+{									\
+	.count		= ATOMIC_INIT(n),				\
+	.sleepers	= 0,						\
+	.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)
+{
+	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+static inline void init_MUTEX(struct semaphore *sem)
+{
+	sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED(struct semaphore *sem)
+{
+	sema_init(sem, 0);
+}
+
+asmlinkage void __down(struct semaphore *sem);
+asmlinkage int __down_interruptible(struct semaphore *sem);
+asmlinkage int __down_trylock(struct semaphore *sem);
+asmlinkage void __up(struct semaphore *sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+/*
+ * 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.
+ */
+static inline void down(struct semaphore *sem)
+{
+	might_sleep();
+	if (atomic_dec_return(&sem->count) < 0)
+		__down(sem);
+}
+
+static inline int down_interruptible(struct semaphore *sem)
+{
+	int ret = 0;
+
+	might_sleep();
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return (ret);
+}
+
+static inline int down_trylock(struct semaphore *sem)
+{
+	int ret = 0;
+
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_trylock(sem);
+	return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+static inline void up(struct semaphore *sem)
+{
+	if (atomic_inc_return(&sem->count) <= 0)
+		__up(sem);
+}
+
+#endif				/* __ASSEMBLY__ */
+#endif				/* _BFIN_SEMAPHORE_H */
diff --git a/include/asm-blackfin/sembuf.h b/include/asm-blackfin/sembuf.h
new file mode 100644
index 0000000..18deb5c
--- /dev/null
+++ b/include/asm-blackfin/sembuf.h
@@ -0,0 +1,25 @@
+#ifndef _BFIN_SEMBUF_H
+#define _BFIN_SEMBUF_H
+
+/*
+ * The semid64_ds structure for bfin 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				/* _BFIN_SEMBUF_H */
diff --git a/include/asm-blackfin/setup.h b/include/asm-blackfin/setup.h
new file mode 100644
index 0000000..01c8c6c
--- /dev/null
+++ b/include/asm-blackfin/setup.h
@@ -0,0 +1,17 @@
+/*
+** asm/setup.h -- Definition of the Linux/bfin setup information
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License.  See the file COPYING in the main directory of this archive
+** for more details.
+**
+** Copyright Lineo, Inc 2001          Tony Kou
+**
+*/
+
+#ifndef _BFIN_SETUP_H
+#define _BFIN_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif				/* _BFIN_SETUP_H */
diff --git a/include/asm-blackfin/shmbuf.h b/include/asm-blackfin/shmbuf.h
new file mode 100644
index 0000000..6124363
--- /dev/null
+++ b/include/asm-blackfin/shmbuf.h
@@ -0,0 +1,42 @@
+#ifndef _BFIN_SHMBUF_H
+#define _BFIN_SHMBUF_H
+
+/*
+ * The shmid64_ds structure for bfin 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				/* _BFIN_SHMBUF_H */
diff --git a/include/asm-blackfin/shmparam.h b/include/asm-blackfin/shmparam.h
new file mode 100644
index 0000000..3c03906
--- /dev/null
+++ b/include/asm-blackfin/shmparam.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_SHMPARAM_H
+#define _BFIN_SHMPARAM_H
+
+#define	SHMLBA PAGE_SIZE	/* attach addr a multiple of this */
+
+#endif				/* _BFIN_SHMPARAM_H */
diff --git a/include/asm-blackfin/sigcontext.h b/include/asm-blackfin/sigcontext.h
new file mode 100644
index 0000000..ce00b03
--- /dev/null
+++ b/include/asm-blackfin/sigcontext.h
@@ -0,0 +1,55 @@
+#ifndef _ASM_BLACKFIN_SIGCONTEXT_H
+#define _ASM_BLACKFIN_SIGCONTEXT_H
+
+/* Add new entries at the end of the structure only.  */
+struct sigcontext {
+	unsigned long sc_r0;
+	unsigned long sc_r1;
+	unsigned long sc_r2;
+	unsigned long sc_r3;
+	unsigned long sc_r4;
+	unsigned long sc_r5;
+	unsigned long sc_r6;
+	unsigned long sc_r7;
+	unsigned long sc_p0;
+	unsigned long sc_p1;
+	unsigned long sc_p2;
+	unsigned long sc_p3;
+	unsigned long sc_p4;
+	unsigned long sc_p5;
+	unsigned long sc_usp;
+	unsigned long sc_a0w;
+	unsigned long sc_a1w;
+	unsigned long sc_a0x;
+	unsigned long sc_a1x;
+	unsigned long sc_astat;
+	unsigned long sc_rets;
+	unsigned long sc_pc;
+	unsigned long sc_retx;
+	unsigned long sc_fp;
+	unsigned long sc_i0;
+	unsigned long sc_i1;
+	unsigned long sc_i2;
+	unsigned long sc_i3;
+	unsigned long sc_m0;
+	unsigned long sc_m1;
+	unsigned long sc_m2;
+	unsigned long sc_m3;
+	unsigned long sc_l0;
+	unsigned long sc_l1;
+	unsigned long sc_l2;
+	unsigned long sc_l3;
+	unsigned long sc_b0;
+	unsigned long sc_b1;
+	unsigned long sc_b2;
+	unsigned long sc_b3;
+	unsigned long sc_lc0;
+	unsigned long sc_lc1;
+	unsigned long sc_lt0;
+	unsigned long sc_lt1;
+	unsigned long sc_lb0;
+	unsigned long sc_lb1;
+	unsigned long sc_seqstat;
+};
+
+#endif
diff --git a/include/asm-blackfin/siginfo.h b/include/asm-blackfin/siginfo.h
new file mode 100644
index 0000000..eca4565
--- /dev/null
+++ b/include/asm-blackfin/siginfo.h
@@ -0,0 +1,35 @@
+#ifndef _BFIN_SIGINFO_H
+#define _BFIN_SIGINFO_H
+
+#include <linux/types.h>
+#include <asm-generic/siginfo.h>
+
+#define UID16_SIGINFO_COMPAT_NEEDED
+
+#define si_uid16	_sifields._kill._uid
+
+#define ILL_ILLPARAOP	(__SI_FAULT|2)	/* illegal opcode combine ********** */
+#define ILL_ILLEXCPT	(__SI_FAULT|4)	/* unrecoverable exception ********** */
+#define ILL_CPLB_VI	(__SI_FAULT|9)	/* D/I CPLB protect violation ******** */
+#define ILL_CPLB_MISS	(__SI_FAULT|10)	/* D/I CPLB miss ******** */
+#define ILL_CPLB_MULHIT	(__SI_FAULT|11)	/* D/I CPLB multiple hit ******** */
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_OPFETCH	(__SI_FAULT|4)	/* error from instruction fetch ******** */
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_STEP	(__SI_FAULT|1)	/* single-step breakpoint************* */
+#define TRAP_TRACEFLOW	(__SI_FAULT|2)	/* trace buffer overflow ************* */
+#define TRAP_WATCHPT	(__SI_FAULT|3)	/* watchpoint match      ************* */
+#define TRAP_ILLTRAP	(__SI_FAULT|4)	/* illegal trap          ************* */
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_STACKFLOW	(__SI_FAULT|3)	/* stack overflow */
+
+#endif
diff --git a/include/asm-blackfin/signal.h b/include/asm-blackfin/signal.h
new file mode 100644
index 0000000..0250429
--- /dev/null
+++ b/include/asm-blackfin/signal.h
@@ -0,0 +1,160 @@
+#ifndef _BLACKFIN_SIGNAL_H
+#define _BLACKFIN_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
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP	0x00000001
+#define SA_NOCLDWAIT	0x00000002	/* not supported yet */
+#define SA_SIGINFO	0x00000004
+#define SA_ONSTACK	0x08000000
+#define SA_RESTART	0x10000000
+#define SA_NODEFER	0x40000000
+#define SA_RESETHAND	0x80000000
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+
+/*
+ * 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;
+	void (*sa_restorer) (void);
+};
+
+struct sigaction {
+	__sighandler_t sa_handler;
+	unsigned long sa_flags;
+	void (*sa_restorer) (void);
+	sigset_t sa_mask;	/* mask last for extensibility */
+};
+
+struct k_sigaction {
+	struct sigaction sa;
+};
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+	union {
+		__sighandler_t _sa_handler;
+		void (*_sa_sigaction) (int, struct siginfo *, void *);
+	} _u;
+	sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer) (void);
+};
+
+#define sa_handler	_u._sa_handler
+#define sa_sigaction	_u._sa_sigaction
+
+#endif				/* __KERNEL__ */
+
+typedef struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+#include <asm/sigcontext.h>
+#undef __HAVE_ARCH_SIG_BITOPS
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _BLACKFIN_SIGNAL_H */
diff --git a/include/asm-blackfin/socket.h b/include/asm-blackfin/socket.h
new file mode 100644
index 0000000..5213c96
--- /dev/null
+++ b/include/asm-blackfin/socket.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET	1
+
+#define SO_DEBUG	1
+#define SO_REUSEADDR	2
+#define SO_TYPE		3
+#define SO_ERROR	4
+#define SO_DONTROUTE	5
+#define SO_BROADCAST	6
+#define SO_SNDBUF	7
+#define SO_RCVBUF	8
+#define SO_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
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
+#endif				/* _ASM_SOCKET_H */
diff --git a/include/asm-blackfin/sockios.h b/include/asm-blackfin/sockios.h
new file mode 100644
index 0000000..426b89b
--- /dev/null
+++ b/include/asm-blackfin/sockios.h
@@ -0,0 +1,13 @@
+#ifndef __ARCH_BFIN_SOCKIOS__
+#define __ARCH_BFIN_SOCKIOS__
+
+/* 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 (timeval) */
+#define SIOCGSTAMPNS	0x8907	/* Get stamp (timespec) */
+
+#endif				/* __ARCH_BFIN_SOCKIOS__ */
diff --git a/include/asm-blackfin/spinlock.h b/include/asm-blackfin/spinlock.h
new file mode 100644
index 0000000..64e908a
--- /dev/null
+++ b/include/asm-blackfin/spinlock.h
@@ -0,0 +1,6 @@
+#ifndef __BFIN_SPINLOCK_H
+#define __BFIN_SPINLOCK_H
+
+#error blackfin architecture does not support SMP spin lock yet
+
+#endif
diff --git a/include/asm-blackfin/stat.h b/include/asm-blackfin/stat.h
new file mode 100644
index 0000000..d2b6f11
--- /dev/null
+++ b/include/asm-blackfin/stat.h
@@ -0,0 +1,63 @@
+#ifndef _BFIN_STAT_H
+#define _BFIN_STAT_H
+
+struct stat {
+	unsigned short st_dev;
+	unsigned short __pad1;
+	unsigned long st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	unsigned short st_rdev;
+	unsigned short __pad2;
+	unsigned long st_size;
+	unsigned long st_blksize;
+	unsigned long st_blocks;
+	unsigned long st_atime;
+	unsigned long __unused1;
+	unsigned long st_mtime;
+	unsigned long __unused2;
+	unsigned long st_ctime;
+	unsigned long __unused3;
+	unsigned long __unused4;
+	unsigned long __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+	unsigned long long st_dev;
+	unsigned char __pad1[4];
+
+#define STAT64_HAS_BROKEN_ST_INO	1
+	unsigned long __st_ino;
+
+	unsigned int st_mode;
+	unsigned int st_nlink;
+
+	unsigned long st_uid;
+	unsigned long st_gid;
+
+	unsigned long long st_rdev;
+	unsigned char __pad2[4];
+
+	long long st_size;
+	unsigned long st_blksize;
+
+	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 long st_ino;
+};
+
+#endif				/* _BFIN_STAT_H */
diff --git a/include/asm-blackfin/statfs.h b/include/asm-blackfin/statfs.h
new file mode 100644
index 0000000..3506720
--- /dev/null
+++ b/include/asm-blackfin/statfs.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_STATFS_H
+#define _BFIN_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif				/* _BFIN_STATFS_H */
diff --git a/include/asm-blackfin/string.h b/include/asm-blackfin/string.h
new file mode 100644
index 0000000..6f1eb7d
--- /dev/null
+++ b/include/asm-blackfin/string.h
@@ -0,0 +1,104 @@
+#ifndef _BLACKFIN_STRING_H_
+#define _BLACKFIN_STRING_H_
+
+#ifdef __KERNEL__		/* only set these up for kernel code */
+
+#define __HAVE_ARCH_STRCPY
+extern inline char *strcpy(char *dest, const char *src)
+{
+	char *xdest = dest;
+	char temp = 0;
+
+	__asm__ __volatile__
+	    ("1:\t%2 = B [%1++] (Z);\n\t"
+	     "B [%0++] = %2;\n\t"
+	     "CC = %2;\n\t"
+        "if cc jump 1b (bp);\n"
+	: "+&a" (dest), "+&a" (src), "=&d" (temp)
+	     ::"memory", "CC");
+	return xdest;
+}
+
+#define __HAVE_ARCH_STRNCPY
+extern inline char *strncpy(char *dest, const char *src, size_t n)
+{
+	char *xdest = dest;
+	char temp = 0;
+
+	if (n == 0)
+		return xdest;
+
+	__asm__ __volatile__
+	    ("1:\t%3 = B [%1++] (Z);\n\t"
+	     "B [%0++] = %3;\n\t"
+	     "CC = %3;\n\t"
+	     "if ! cc jump 2f;\n\t"
+	     "%2 += -1;\n\t"
+	     "CC = %2 == 0;\n\t"
+	     "if ! cc jump 1b (bp);\n"
+        "2:\n"
+	: "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
+	     ::"memory", "CC");
+	return xdest;
+}
+
+#define __HAVE_ARCH_STRCMP
+extern inline int strcmp(const char *cs, const char *ct)
+{
+	char __res1, __res2;
+
+	__asm__
+       ("1:\t%2 = B[%0++] (Z);\n\t" /* get *cs */
+		"%3 = B[%1++] (Z);\n\t"	/* get *ct */
+		"CC = %2 == %3;\n\t"	/* compare a byte */
+		"if ! cc jump 2f;\n\t"	/* not equal, break out */
+		"CC = %2;\n\t"	/* at end of cs? */
+		"if cc jump 1b (bp);\n\t"	/* no, keep going */
+		"jump.s 3f;\n"	/* strings are equal */
+		"2:\t%2 = %2 - %3;\n"	/* *cs - *ct */
+        "3:\n"
+	: "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
+      : :	"CC");
+
+	return __res1;
+}
+
+#define __HAVE_ARCH_STRNCMP
+extern inline int strncmp(const char *cs, const char *ct, size_t count)
+{
+	char __res1, __res2;
+
+	if (!count)
+		return 0;
+	__asm__
+       ("1:\t%3 = B[%0++] (Z);\n\t"        /* get *cs */
+		"%4 = B[%1++] (Z);\n\t"	/* get *ct */
+		"CC = %3 == %4;\n\t"	/* compare a byte */
+		"if ! cc jump 3f;\n\t"	/* not equal, break out */
+		"CC = %3;\n\t"	/* at end of cs? */
+		"if ! cc jump 4f;\n\t"	/* yes, all done */
+		"%2 += -1;\n\t"	/* no, adjust count */
+	"CC = %2 == 0;\n\t"
+        "if ! cc jump 1b;\n"                 /* more to do, keep going */
+		"2:\t%3 = 0;\n\t"	/* strings are equal */
+        "jump.s    4f;\n"
+        "3:\t%3 = %3 - %4;\n"          /* *cs - *ct */
+        "4:"
+	: "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
+      : :	"CC");
+	return __res1;
+}
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *s, int c, size_t count);
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *d, const void *s, size_t count);
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, __kernel_size_t);
+#define	__HAVE_ARCH_MEMCHR
+extern void *memchr(const void *s, int c, size_t n);
+#define	__HAVE_ARCH_MEMMOVE
+extern void *memmove(void *dest, const void *src, size_t count);
+
+#endif /*__KERNEL__*/
+#endif				/* _BLACKFIN_STRING_H_ */
diff --git a/include/asm-blackfin/system.h b/include/asm-blackfin/system.h
new file mode 100644
index 0000000..b5bf6e7
--- /dev/null
+++ b/include/asm-blackfin/system.h
@@ -0,0 +1,249 @@
+/*
+ * File:        include/asm/system.h
+ * Based on:
+ * Author:      Tony Kou (tonyko@lineo.ca)
+ *              Copyright (c) 2002 Arcturus Networks Inc.
+ *                    (www.arcturusnetworks.com)
+ *              Copyright (c) 2003 Metrowerks (www.metrowerks.com)
+ *              Copyright (c) 2004 Analog Device Inc.
+ * Created:     25Jan2001 - Tony Kou
+ * Description: system.h include file
+ *
+ * Modified:     22Sep2006 - Robin Getz
+ *                - move include blackfin.h down, so I can get access to
+ *                   irq functions in other include files.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_SYSTEM_H
+#define _BLACKFIN_SYSTEM_H
+
+#include <linux/linkage.h>
+#include <linux/compiler.h>
+
+/*
+ * Interrupt configuring macros.
+ */
+
+extern unsigned long irq_flags;
+
+#define local_irq_enable() do {		\
+	__asm__ __volatile__ (		\
+		"sti %0;"		\
+		::"d"(irq_flags));	\
+} while (0)
+
+#define local_irq_disable() do {	\
+	int _tmp_dummy;			\
+	__asm__ __volatile__ (		\
+		"cli %0;"		\
+		:"=d" (_tmp_dummy):);	\
+} while (0)
+
+#if defined(ANOMALY_05000244) && defined (CONFIG_BLKFIN_CACHE)
+#define idle_with_irq_disabled() do {   \
+        __asm__ __volatile__ (          \
+                "nop; nop;\n"           \
+                ".align 8;\n"           \
+                "sti %0; idle;\n"       \
+                ::"d" (irq_flags));     \
+} while (0)
+#else
+#define idle_with_irq_disabled() do {   \
+	__asm__ __volatile__ (          \
+		".align 8;\n"           \
+		"sti %0; idle;\n"       \
+		::"d" (irq_flags));     \
+} while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_HWERR
+#define __save_and_cli(x) do {			\
+	__asm__ __volatile__ (		        \
+		"cli %0;\n\tsti %1;"		\
+		:"=&d"(x): "d" (0x3F));		\
+} while (0)
+#else
+#define __save_and_cli(x) do {		\
+	__asm__ __volatile__ (          \
+		"cli %0;"		\
+		:"=&d"(x):);		\
+} while (0)
+#endif
+
+#define local_save_flags(x) asm volatile ("cli %0;"     \
+					  "sti %0;"     \
+				    	  :"=d"(x):);
+
+#ifdef CONFIG_DEBUG_HWERR
+#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0)
+#else
+#define irqs_enabled_from_flags(x) ((x) != 0x1f)
+#endif
+
+#define local_irq_restore(x) do {			\
+	if (irqs_enabled_from_flags(x))			\
+		local_irq_enable ();			\
+} while (0)
+
+/* For spinlocks etc */
+#define local_irq_save(x) __save_and_cli(x)
+
+#define	irqs_disabled()				\
+({						\
+	unsigned long flags;			\
+	local_save_flags(flags);		\
+	!irqs_enabled_from_flags(flags);	\
+})
+
+/*
+ * Force strict CPU ordering.
+ */
+#define nop()  asm volatile ("nop;\n\t"::)
+#define mb()   asm volatile (""   : : :"memory")
+#define rmb()  asm volatile (""   : : :"memory")
+#define wmb()  asm volatile (""   : : :"memory")
+#define set_rmb(var, value)    do { (void) xchg(&var, value); } while (0)
+#define set_mb(var, value)     set_rmb(var, value)
+#define set_wmb(var, value)    do { var = value; wmb(); } while (0)
+
+#define read_barrier_depends() 		do { } while(0)
+
+#ifdef CONFIG_SMP
+#define smp_mb()	mb()
+#define smp_rmb()	rmb()
+#define smp_wmb()	wmb()
+#define smp_read_barrier_depends()	read_barrier_depends()
+#else
+#define smp_mb()	barrier()
+#define smp_rmb()	barrier()
+#define smp_wmb()	barrier()
+#define smp_read_barrier_depends()	do { } while(0)
+#endif
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy {
+	unsigned long a[100];
+};
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+				   int size)
+{
+	unsigned long tmp = 0;
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+
+	switch (size) {
+	case 1:
+		__asm__ __volatile__
+			("%0 = b%2 (z);\n\t"
+			 "b%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__
+			("%0 = w%2 (z);\n\t"
+			 "w%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__
+			("%0 = %2;\n\t"
+			 "%2 = %1;\n\t"
+			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+		break;
+	}
+	local_irq_restore(flags);
+	return tmp;
+}
+
+/*
+ * 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.
+ */
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long tmp = 0;
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+
+	switch (size) {
+	case 1:
+		__asm__ __volatile__
+			("%0 = b%3 (z);\n\t"
+			 "CC = %1 == %0;\n\t"
+			 "IF !CC JUMP 1f;\n\t"
+			 "b%3 = %2;\n\t"
+			 "1:\n\t"
+			 : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 2:
+		__asm__ __volatile__
+			("%0 = w%3 (z);\n\t"
+			 "CC = %1 == %0;\n\t"
+			 "IF !CC JUMP 1f;\n\t"
+			 "w%3 = %2;\n\t"
+			 "1:\n\t"
+			 : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+		break;
+	case 4:
+		__asm__ __volatile__
+			("%0 = %3;\n\t"
+			 "CC = %1 == %0;\n\t"
+			 "IF !CC JUMP 1f;\n\t"
+			 "%3 = %2;\n\t"
+			 "1:\n\t"
+			 : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+		break;
+	}
+	local_irq_restore(flags);
+	return tmp;
+}
+
+#define cmpxchg(ptr,o,n)\
+        ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+                                        (unsigned long)(n),sizeof(*(ptr))))
+
+#define prepare_to_switch()     do { } while(0)
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.
+ */
+
+#include <asm/blackfin.h>
+
+asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_struct *next);
+
+#define switch_to(prev,next,last) \
+do {    \
+	memcpy (&prev->thread_info->l1_task_info, L1_SCRATCH_TASK_INFO, \
+		sizeof *L1_SCRATCH_TASK_INFO); \
+	memcpy (L1_SCRATCH_TASK_INFO, &next->thread_info->l1_task_info, \
+		sizeof *L1_SCRATCH_TASK_INFO); \
+	(last) = resume (prev, next);   \
+} while (0)
+
+#endif				/* _BLACKFIN_SYSTEM_H */
diff --git a/include/asm-blackfin/termbits.h b/include/asm-blackfin/termbits.h
new file mode 100644
index 0000000..2fd9dab
--- /dev/null
+++ b/include/asm-blackfin/termbits.h
@@ -0,0 +1,184 @@
+#ifndef __ARCH_BFIN_TERMBITS_H__
+#define __ARCH_BFIN_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 */
+};
+
+struct ktermios {
+	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 */
+	speed_t c_ispeed;               /* input speed */
+	speed_t c_ospeed;               /* output speed */
+};
+
+/* 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				/* __ARCH_BFIN_TERMBITS_H__ */
diff --git a/include/asm-blackfin/termios.h b/include/asm-blackfin/termios.h
new file mode 100644
index 0000000..5c41478
--- /dev/null
+++ b/include/asm-blackfin/termios.h
@@ -0,0 +1,106 @@
+#ifndef __BFIN_TERMIOS_H__
+#define __BFIN_TERMIOS_H__
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+	unsigned short ws_row;
+	unsigned short ws_col;
+	unsigned short ws_xpixel;
+	unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+	unsigned short c_iflag;	/* input mode flags */
+	unsigned short c_oflag;	/* output mode flags */
+	unsigned short c_cflag;	/* control mode flags */
+	unsigned short c_lflag;	/* local mode flags */
+	unsigned char c_line;	/* line discipline */
+	unsigned char c_cc[NCC];	/* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE	0x001
+#define TIOCM_DTR	0x002
+#define TIOCM_RTS	0x004
+#define TIOCM_ST	0x008
+#define TIOCM_SR	0x010
+#define TIOCM_CTS	0x020
+#define TIOCM_CAR	0x040
+#define TIOCM_RNG	0x080
+#define TIOCM_DSR	0x100
+#define TIOCM_CD	TIOCM_CAR
+#define TIOCM_RI	TIOCM_RNG
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#define TIOCM_LOOP	0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY		0
+#define N_SLIP		1
+#define N_MOUSE		2
+#define N_PPP		3
+#define N_STRIP		4
+#define N_AX25		5
+#define N_X25		6	/* X.25 async */
+#define N_6PACK		7
+#define N_MASC		8	/* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964		9	/* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL	10	/* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC		13	/* synchronous HDLC */
+#define N_SYNC_PPP	14	/* 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"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+	unsigned short __tmp; \
+	get_user(__tmp,&(termio)->x); \
+	*(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+	SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+	copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+	put_user((termios)->c_iflag, &(termio)->c_iflag); \
+	put_user((termios)->c_oflag, &(termio)->c_oflag); \
+	put_user((termios)->c_cflag, &(termio)->c_cflag); \
+	put_user((termios)->c_lflag, &(termio)->c_lflag); \
+	put_user((termios)->c_line,  &(termio)->c_line); \
+	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif				/* __KERNEL__ */
+
+#endif				/* __BFIN_TERMIOS_H__ */
diff --git a/include/asm-blackfin/thread_info.h b/include/asm-blackfin/thread_info.h
new file mode 100644
index 0000000..fa8f08c
--- /dev/null
+++ b/include/asm-blackfin/thread_info.h
@@ -0,0 +1,143 @@
+/*
+ * File:         include/asm-blackfin/thread_info.h
+ * Based on:     include/asm-m68knommu/thread_info.h
+ * Author:       LG Soft India
+ *               Copyright (C) 2004-2005 Analog Devices Inc.
+ * Created:      Tue Sep 21 2004
+ * Description:  Blackfin low-level thread information
+ * Modified:
+ * Bugs:         Enter bugs at http://blackfin.uclinux.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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#include <asm/page.h>
+#include <asm/entry.h>
+#include <asm/l1layout.h>
+#include <linux/compiler.h>
+
+#ifdef __KERNEL__
+
+/* Thread Align Mask to reach to the top of the stack
+ * for any process
+ */
+#define ALIGN_PAGE_MASK         0xffffe000
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_segment_t;
+
+/*
+ * low level task data.
+ * If you change this, change the TI_* offsets below to match.
+ */
+
+struct thread_info {
+	struct task_struct *task;	/* main task structure */
+	struct exec_domain *exec_domain;	/* execution domain */
+	unsigned long flags;	/* low level flags */
+	int cpu;		/* cpu we're on */
+	int preempt_count;	/* 0 => preemptable, <0 => BUG */
+	mm_segment_t addr_limit;	/* address limit */
+	struct restart_block restart_block;
+	struct l1_scratch_task_info l1_task_info;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#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)
+
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#define THREAD_SIZE		8192	/* 2 pages */
+
+/* How to get the thread information struct from C */
+
+static inline struct thread_info *current_thread_info(void)
+    __attribute__ ((__const__));
+
+/* Given a task stack pointer, you can find it's task structure
+ * just by masking it to the 8K boundary.
+ */
+static inline struct thread_info *current_thread_info(void)
+{
+	struct thread_info *ti;
+      __asm__("%0 = sp;": "=&d"(ti):
+	);
+	return (struct thread_info *)((long)ti & ~8191UL);
+}
+
+/* thread information allocation */
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+				__get_free_pages(GFP_KERNEL, 1))
+#define free_thread_info(ti)	free_pages((unsigned long) (ti), 1)
+#endif				/* __ASSEMBLY__ */
+
+/*
+ * Offsets in thread_info structure, used in assembly code
+ */
+#define TI_TASK		0
+#define TI_EXECDOMAIN	4
+#define TI_FLAGS	8
+#define TI_CPU		12
+#define TI_PREEMPT	16
+
+#define	PREEMPT_ACTIVE	0x4000000
+
+/*
+ * thread information flag bit numbers
+ */
+#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_MEMDIE              5
+#define TIF_RESTORE_SIGMASK	6	/* restore signal mask in do_signal() */
+#define TIF_FREEZE              7       /* is freezing for suspend */
+
+/* as above, but as bit values */
+#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_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
+#define _TIF_FREEZE             (1<<TIF_FREEZE)
+
+#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _ASM_THREAD_INFO_H */
diff --git a/include/asm-blackfin/timex.h b/include/asm-blackfin/timex.h
new file mode 100644
index 0000000..8285901
--- /dev/null
+++ b/include/asm-blackfin/timex.h
@@ -0,0 +1,18 @@
+/* blackfin architecture timex specifications: Lineo Inc. 2001
+ *
+ * Based on: include/asm-m68knommu/timex.h
+ */
+
+#ifndef _ASMBLACKFIN_TIMEX_H
+#define _ASMBLACKFIN_TIMEX_H
+
+#define CLOCK_TICK_RATE	1000000	/* Underlying HZ */
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+	return 0;
+}
+
+#endif
diff --git a/include/asm-blackfin/tlb.h b/include/asm-blackfin/tlb.h
new file mode 100644
index 0000000..89a12ee
--- /dev/null
+++ b/include/asm-blackfin/tlb.h
@@ -0,0 +1,16 @@
+#ifndef _BLACKFIN_TLB_H
+#define _BLACKFIN_TLB_H
+
+#define tlb_start_vma(tlb, vma)	do { } while (0)
+#define tlb_end_vma(tlb, vma)	do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address)	do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb)		flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#endif				/* _BLACKFIN_TLB_H */
diff --git a/include/asm-blackfin/tlbflush.h b/include/asm-blackfin/tlbflush.h
new file mode 100644
index 0000000..10a07ba
--- /dev/null
+++ b/include/asm-blackfin/tlbflush.h
@@ -0,0 +1,62 @@
+#ifndef _BLACKFIN_TLBFLUSH_H
+#define _BLACKFIN_TLBFLUSH_H
+
+/*
+ * Copyright (C) 2000 Lineo, David McCullough <davidm@uclinux.org>
+ * Copyright (C) 2000-2002, Greg Ungerer <gerg@snapgear.com>
+ */
+
+#include <asm/setup.h>
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+	BUG();
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+	BUG();
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+	BUG();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	BUG();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	BUG();
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+				   unsigned long start, unsigned long end)
+{
+	BUG();
+}
+
+static inline void flush_tlb_kernel_page(unsigned long addr)
+{
+	BUG();
+}
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+	BUG();
+}
+
+#endif
diff --git a/include/asm-blackfin/topology.h b/include/asm-blackfin/topology.h
new file mode 100644
index 0000000..acee239
--- /dev/null
+++ b/include/asm-blackfin/topology.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_BLACKFIN_TOPOLOGY_H
+#define _ASM_BLACKFIN_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif				/* _ASM_BLACKFIN_TOPOLOGY_H */
diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
new file mode 100644
index 0000000..fe365b1
--- /dev/null
+++ b/include/asm-blackfin/traps.h
@@ -0,0 +1,75 @@
+/*
+ *  linux/include/asm/traps.h
+ *
+ *  Copyright (C) 1993        Hamish Macdonald
+ *
+ *  Lineo, Inc    Jul 2001    Tony Kou
+ *
+ * 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 _BFIN_TRAPS_H
+#define _BFIN_TRAPS_H
+
+#define VEC_SYS		(0)
+#define VEC_EXCPT01	(1)
+#define VEC_EXCPT02	(2)
+#define VEC_EXCPT03	(3)
+#define VEC_EXCPT04	(4)
+#define VEC_EXCPT05	(5)
+#define VEC_EXCPT06	(6)
+#define VEC_EXCPT07	(7)
+#define VEC_EXCPT08	(8)
+#define VEC_EXCPT09	(9)
+#define VEC_EXCPT10	(10)
+#define VEC_EXCPT11	(11)
+#define VEC_EXCPT12	(12)
+#define VEC_EXCPT13	(13)
+#define VEC_EXCPT14	(14)
+#define VEC_EXCPT15	(15)
+#define VEC_STEP	(16)
+#define VEC_OVFLOW	(17)
+#define VEC_UNDEF_I	(33)
+#define VEC_ILGAL_I	(34)
+#define VEC_CPLB_VL	(35)
+#define VEC_MISALI_D	(36)
+#define VEC_UNCOV	(37)
+#define VEC_CPLB_M	(38)
+#define VEC_CPLB_MHIT	(39)
+#define VEC_WATCH	(40)
+#define VEC_ISTRU_VL	(41)	/*ADSP-BF535 only (MH) */
+#define VEC_MISALI_I	(42)
+#define VEC_CPLB_I_VL	(43)
+#define VEC_CPLB_I_M	(44)
+#define VEC_CPLB_I_MHIT	(45)
+#define VEC_ILL_RES	(46)	/* including unvalid supervisor mode insn */
+
+#ifndef __ASSEMBLY__
+
+#define HWC_x2 "System MMR Error\nAn error occurred due to an invalid access to an System MMR location\nPossible reason: a 32-bit register is accessed with a 16-bit instruction,\nor a 16-bit register is accessed with a 32-bit instruction.\n"
+#define HWC_x3 "External Memory Addressing Error\n"
+#define HWC_x12 "Performance Monitor Overflow\n"
+#define HWC_x18 "RAISE 5 instruction\n Software issued a RAISE 5 instruction to invoke the Hardware\n"
+#define HWC_default "Reserved\n"
+
+#define EXC_0x03 "Application stack overflow\n - Please increase the stack size of the application using elf2flt -s option,\n and/or reduce the stack use of the application.\n"
+#define EXC_0x10 "Single step\n - When the processor is in single step mode, every instruction\n generates an exception. Primarily used for debugging.\n"
+#define EXC_0x11 "Exception caused by a trace buffer full condition\n - The processor takes this exception when the trace\n buffer overflows (only when enabled by the Trace Unit Control register).\n"
+#define EXC_0x21 "Undefined instruction\n - May be used to emulate instructions that are not defined for\n a particular processor implementation.\n"
+#define EXC_0x22 "Illegal instruction combination\n - See section for multi-issue rules in the ADSP-BF53x Blackfin\n Processor Instruction Set Reference.\n"
+#define EXC_0x23 "Data access CPLB protection violation\n - Attempted read or write to Supervisor resource,\n or illegal data memory access. \n"
+#define EXC_0x24 "Data access misaligned address violation\n - Attempted misaligned data memory or data cache access.\n"
+#define EXC_0x25 "Unrecoverable event\n - For example, an exception generated while processing a previous exception.\n"
+#define EXC_0x26 "Data access CPLB miss\n - Used by the MMU to signal a CPLB miss on a data access.\n"
+#define EXC_0x27 "Data access multiple CPLB hits\n - More than one CPLB entry matches data fetch address.\n"
+#define EXC_0x28 "Program Sequencer Exception caused by an emulation watchpoint match\n - There is a watchpoint match, and one of the EMUSW\n bits in the Watchpoint Instruction Address Control register (WPIACTL) is set.\n"
+#define EXC_0x2A "Instruction fetch misaligned address violation\n - Attempted misaligned instruction cache fetch. On a misaligned instruction fetch exception,\n the return address provided in RETX is the destination address which is misaligned, rather than the address of the offending instruction.\n"
+#define EXC_0x2B "CPLB protection violation\n - Illegal instruction fetch access (memory protection violation).\n"
+#define EXC_0x2C "Instruction fetch CPLB miss\n - CPLB miss on an instruction fetch.\n"
+#define EXC_0x2D "Instruction fetch multiple CPLB hits\n - More than one CPLB entry matches instruction fetch address.\n"
+#define EXC_0x2E "Illegal use of supervisor resource\n - Attempted to use a Supervisor register or instruction from User mode.\n Supervisor resources are registers and instructions that are reserved\n for Supervisor use: Supervisor only registers, all MMRs, and Supervisor\n only instructions.\n"
+
+#endif				/* __ASSEMBLY__ */
+#endif				/* _BFIN_TRAPS_H */
diff --git a/include/asm-blackfin/types.h b/include/asm-blackfin/types.h
new file mode 100644
index 0000000..36f8dc8
--- /dev/null
+++ b/include/asm-blackfin/types.h
@@ -0,0 +1,66 @@
+#ifndef _BFIN_TYPES_H
+#define _BFIN_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+#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;
+
+/* HK0617   -- Changes to unsigned long temporarily */
+#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;
+typedef u64 dma64_addr_t;
+
+#endif				/* __ASSEMBLY__ */
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _BFIN_TYPES_H */
diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
new file mode 100644
index 0000000..bfcb679
--- /dev/null
+++ b/include/asm-blackfin/uaccess.h
@@ -0,0 +1,271 @@
+/* Changes made by Lineo Inc.    May 2001
+ *
+ * Based on: include/asm-m68knommu/uaccess.h
+ */
+
+#ifndef __BLACKFIN_UACCESS_H
+#define __BLACKFIN_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+#ifndef CONFIG_NO_ACCESS_CHECK
+# include <asm/bfin-global.h>
+#endif
+
+#define get_ds()        (KERNEL_DS)
+#define get_fs()        (current_thread_info()->addr_limit)
+
+static inline void set_fs(mm_segment_t fs)
+{
+	current_thread_info()->addr_limit = fs;
+}
+
+#define segment_eq(a,b) ((a) == (b))
+
+#define VERIFY_READ	0
+#define VERIFY_WRITE	1
+
+#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
+
+static inline int is_in_rom(unsigned long addr)
+{
+	/*
+	 * What we are really trying to do is determine if addr is
+	 * in an allocated kernel memory region. If not then assume
+	 * we cannot free it or otherwise de-allocate it. Ideally
+	 * we could restrict this to really being in a ROM or flash,
+	 * but that would need to be done on a board by board basis,
+	 * not globally.
+	 */
+	if ((addr < _ramstart) || (addr >= _ramend))
+		return (1);
+
+	/* Default case, not in ROM */
+	return (0);
+}
+
+/*
+ * 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.
+ */
+
+#ifdef CONFIG_NO_ACCESS_CHECK
+static inline int _access_ok(unsigned long addr, unsigned long size) { return 1; }
+#else
+#ifdef CONFIG_ACCESS_OK_L1
+extern int _access_ok(unsigned long addr, unsigned long size)__attribute__((l1_text));
+#else
+extern int _access_ok(unsigned long addr, unsigned long size);
+#endif
+#endif
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+	unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise.  */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ */
+
+#define put_user(x,p)						\
+	({							\
+		int _err = 0;					\
+		typeof(*(p)) _x = (x);				\
+		typeof(*(p)) *_p = (p);				\
+		if (!access_ok(VERIFY_WRITE, _p, sizeof(*(_p)))) {\
+			_err = -EFAULT;				\
+		}						\
+		else {						\
+		switch (sizeof (*(_p))) {			\
+		case 1:						\
+			__put_user_asm(_x, _p, B);		\
+			break;					\
+		case 2:						\
+			__put_user_asm(_x, _p, W);		\
+			break;					\
+		case 4:						\
+			__put_user_asm(_x, _p,  );		\
+			break;					\
+		case 8: {					\
+			long _xl, _xh;				\
+			_xl = ((long *)&_x)[0];			\
+			_xh = ((long *)&_x)[1];			\
+			__put_user_asm(_xl, ((long *)_p)+0, );	\
+			__put_user_asm(_xh, ((long *)_p)+1, );	\
+		} break;					\
+		default:					\
+			_err = __put_user_bad();		\
+			break;					\
+		}						\
+		}						\
+		_err;						\
+	})
+
+#define __put_user(x,p) put_user(x,p)
+static inline int bad_user_access_length(void)
+{
+	panic("bad_user_access_length");
+	return -1;
+}
+
+#define __put_user_bad() (printk(KERN_INFO "put_user_bad %s:%d %s\n",\
+                           __FILE__, __LINE__, __FUNCTION__),\
+                           bad_user_access_length(), (-EFAULT))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+
+#define __ptr(x) ((unsigned long *)(x))
+
+#define __put_user_asm(x,p,bhw)				\
+	__asm__ (#bhw"[%1] = %0;\n\t"			\
+		 : /* no outputs */			\
+		 :"d" (x),"a" (__ptr(p)) : "memory")
+
+#define get_user(x,p)							\
+	({								\
+		int _err = 0;						\
+		typeof(*(p)) *_p = (p);					\
+		if (!access_ok(VERIFY_READ, _p, sizeof(*(_p)))) {	\
+			_err = -EFAULT;					\
+		}							\
+		else {							\
+		switch (sizeof(*(_p))) {				\
+		case 1:							\
+			__get_user_asm(x, _p, B,(Z));			\
+			break;						\
+		case 2:							\
+			__get_user_asm(x, _p, W,(Z));			\
+			break;						\
+		case 4:							\
+			__get_user_asm(x, _p,  , );			\
+			break;						\
+		case 8: {						\
+			unsigned long _xl, _xh;				\
+			__get_user_asm(_xl, ((unsigned long *)_p)+0,  , ); \
+			__get_user_asm(_xh, ((unsigned long *)_p)+1,  , ); \
+			((unsigned long *)&x)[0] = _xl;			\
+			((unsigned long *)&x)[1] = _xh;			\
+		} break;						\
+		default:						\
+			x = 0;						\
+			printk(KERN_INFO "get_user_bad: %s:%d %s\n",    \
+			       __FILE__, __LINE__, __FUNCTION__);	\
+			_err = __get_user_bad();			\
+			break;						\
+		}							\
+		}							\
+		_err;							\
+	})
+
+#define __get_user(x,p) get_user(x,p)
+
+#define __get_user_bad() (bad_user_access_length(), (-EFAULT))
+
+#define __get_user_asm(x,p,bhw,option)				\
+	{							\
+		unsigned long _tmp;				\
+		__asm__ ("%0 =" #bhw "[%1]"#option";\n\t"	\
+			 : "=d" (_tmp)				\
+			 : "a" (__ptr(p)));			\
+		(x) = (__typeof__(*(p))) _tmp;			\
+	}
+
+#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
+#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n))\
+				                 return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n))\
+                                                   return retval; })
+
+static inline long copy_from_user(void *to,
+				  const void __user * from, unsigned long n)
+{
+	if (access_ok(VERIFY_READ, from, n))
+		memcpy(to, from, n);
+	else
+		return n;
+	return 0;
+}
+
+static inline long copy_to_user(void *to,
+				const void __user * from, unsigned long n)
+{
+	if (access_ok(VERIFY_WRITE, to, n))
+		memcpy(to, from, n);
+	else
+		return n;
+	return 0;
+}
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+static inline long strncpy_from_user(char *dst,
+                                     const char *src, long count)
+{
+	char *tmp;
+	if (!access_ok(VERIFY_READ, src, 1))
+		return -EFAULT;
+	strncpy(dst, src, count);
+	for (tmp = dst; *tmp && count > 0; tmp++, count--) ;
+	return (tmp - dst);
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+static inline long strnlen_user(const char *src, long n)
+{
+	return (strlen(src) + 1);
+}
+
+#define strlen_user(str) strnlen_user(str, 32767)
+
+/*
+ * Zero Userspace
+ */
+
+static inline unsigned long __clear_user(void *to, unsigned long n)
+{
+	memset(to, 0, n);
+	return 0;
+}
+
+#define clear_user(to, n) __clear_user(to, n)
+
+#endif				/* _BLACKFIN_UACCESS_H */
diff --git a/include/asm-blackfin/ucontext.h b/include/asm-blackfin/ucontext.h
new file mode 100644
index 0000000..4a4e385
--- /dev/null
+++ b/include/asm-blackfin/ucontext.h
@@ -0,0 +1,17 @@
+/** Changes made by Tony Kou   Lineo Inc.    May 2001
+ *
+ *  Based on: include/m68knommu/ucontext.h
+ */
+
+#ifndef _BLACKFIN_UCONTEXT_H
+#define _BLACKFIN_UCONTEXT_H
+
+struct ucontext {
+	unsigned long uc_flags;	/* the others are necessary */
+	struct ucontext *uc_link;
+	stack_t uc_stack;
+	struct sigcontext uc_mcontext;
+	sigset_t uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif				/* _BLACKFIN_UCONTEXT_H */
diff --git a/include/asm-blackfin/unaligned.h b/include/asm-blackfin/unaligned.h
new file mode 100644
index 0000000..10081dc
--- /dev/null
+++ b/include/asm-blackfin/unaligned.h
@@ -0,0 +1,6 @@
+#ifndef __BFIN_UNALIGNED_H
+#define __BFIN_UNALIGNED_H
+
+#include <asm-generic/unaligned.h>
+
+#endif				/* __BFIN_UNALIGNED_H */
diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
new file mode 100644
index 0000000..4df8790
--- /dev/null
+++ b/include/asm-blackfin/unistd.h
@@ -0,0 +1,382 @@
+#ifndef __ASM_BFIN_UNISTD_H
+#define __ASM_BFIN_UNISTD_H
+/*
+ * This file contains the system call numbers.
+ */
+#define __NR_exit		  1
+#define __NR_fork		  2
+#define __NR_read		  3
+#define __NR_write		  4
+#define __NR_open		  5
+#define __NR_close		  6
+				/* 7 __NR_waitpid obsolete */
+#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
+				/* 17 __NR_break obsolete */
+				/* 18 __NR_oldstat obsolete */
+#define __NR_lseek		 19
+#define __NR_getpid		 20
+#define __NR_mount		 21
+				/* 22 __NR_umount obsolete */
+#define __NR_setuid		 23
+#define __NR_getuid		 24
+#define __NR_stime		 25
+#define __NR_ptrace		 26
+#define __NR_alarm		 27
+				/* 28 __NR_oldfstat obsolete */
+#define __NR_pause		 29
+				/* 30 __NR_utime obsolete */
+				/* 31 __NR_stty obsolete */
+				/* 32 __NR_gtty obsolete */
+#define __NR_access		 33
+#define __NR_nice		 34
+				/* 35 __NR_ftime obsolete */
+#define __NR_sync		 36
+#define __NR_kill		 37
+#define __NR_rename		 38
+#define __NR_mkdir		 39
+#define __NR_rmdir		 40
+#define __NR_dup		 41
+#define __NR_pipe		 42
+#define __NR_times		 43
+				/* 44 __NR_prof obsolete */
+#define __NR_brk		 45
+#define __NR_setgid		 46
+#define __NR_getgid		 47
+				/* 48 __NR_signal obsolete */
+#define __NR_geteuid		 49
+#define __NR_getegid		 50
+#define __NR_acct		 51
+#define __NR_umount2		 52
+				/* 53 __NR_lock obsolete */
+#define __NR_ioctl		 54
+#define __NR_fcntl		 55
+				/* 56 __NR_mpx obsolete */
+#define __NR_setpgid		 57
+				/* 58 __NR_ulimit obsolete */
+				/* 59 __NR_oldolduname obsolete */
+#define __NR_umask		 60
+#define __NR_chroot		 61
+#define __NR_ustat		 62
+#define __NR_dup2		 63
+#define __NR_getppid		 64
+#define __NR_getpgrp		 65
+#define __NR_setsid		 66
+				/* 67 __NR_sigaction obsolete */
+#define __NR_sgetmask		 68
+#define __NR_ssetmask		 69
+#define __NR_setreuid		 70
+#define __NR_setregid		 71
+				/* 72 __NR_sigsuspend obsolete */
+				/* 73 __NR_sigpending obsolete */
+#define __NR_sethostname	 74
+#define __NR_setrlimit		 75
+				/* 76 __NR_old_getrlimit obsolete */
+#define __NR_getrusage		 77
+#define __NR_gettimeofday	 78
+#define __NR_settimeofday	 79
+#define __NR_getgroups		 80
+#define __NR_setgroups		 81
+				/* 82 __NR_select obsolete */
+#define __NR_symlink		 83
+				/* 84 __NR_oldlstat obsolete */
+#define __NR_readlink		 85
+				/* 86 __NR_uselib obsolete */
+				/* 87 __NR_swapon obsolete */
+#define __NR_reboot		 88
+				/* 89 __NR_readdir obsolete */
+				/* 90 __NR_mmap obsolete */
+#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
+				/* 98 __NR_profil obsolete */
+#define __NR_statfs		 99
+#define __NR_fstatfs		100
+				/* 101 __NR_ioperm */
+				/* 102 __NR_socketcall obsolete */
+#define __NR_syslog		103
+#define __NR_setitimer		104
+#define __NR_getitimer		105
+#define __NR_stat		106
+#define __NR_lstat		107
+#define __NR_fstat		108
+				/* 109 __NR_olduname obsolete */
+				/* 110 __NR_iopl obsolete */
+#define __NR_vhangup		111
+				/* 112 __NR_idle obsolete */
+				/* 113 __NR_vm86old */
+#define __NR_wait4		114
+				/* 115 __NR_swapoff obsolete */
+#define __NR_sysinfo		116
+				/* 117 __NR_ipc oboslete */
+#define __NR_fsync		118
+				/* 119 __NR_sigreturn obsolete */
+#define __NR_clone		120
+#define __NR_setdomainname	121
+#define __NR_uname		122
+				/* 123 __NR_modify_ldt obsolete */
+#define __NR_adjtimex		124
+#define __NR_mprotect		125
+				/* 126 __NR_sigprocmask obsolete */
+				/* 127 __NR_create_module obsolete */
+#define __NR_init_module	128
+#define __NR_delete_module	129
+				/* 130 __NR_get_kernel_syms obsolete */
+#define __NR_quotactl		131
+#define __NR_getpgid		132
+#define __NR_fchdir		133
+#define __NR_bdflush		134
+				/* 135 was sysfs */
+#define __NR_personality	136
+				/* 137 __NR_afs_syscall */
+#define __NR_setfsuid		138
+#define __NR_setfsgid		139
+#define __NR__llseek		140
+#define __NR_getdents		141
+				/* 142 __NR__newselect obsolete */
+#define __NR_flock		143
+				/* 144 __NR_msync obsolete */
+#define __NR_readv		145
+#define __NR_writev		146
+#define __NR_getsid		147
+#define __NR_fdatasync		148
+#define __NR__sysctl		149
+				/* 150 __NR_mlock */
+				/* 151 __NR_munlock */
+				/* 152 __NR_mlockall */
+				/* 153 __NR_munlockall */
+#define __NR_sched_setparam		154
+#define __NR_sched_getparam		155
+#define __NR_sched_setscheduler		156
+#define __NR_sched_getscheduler		157
+#define __NR_sched_yield		158
+#define __NR_sched_get_priority_max	159
+#define __NR_sched_get_priority_min	160
+#define __NR_sched_rr_get_interval	161
+#define __NR_nanosleep		162
+				/* 163 __NR_mremap */
+#define __NR_setresuid		164
+#define __NR_getresuid		165
+				/* 166 __NR_vm86 */
+				/* 167 __NR_query_module */
+				/* 168 __NR_poll */
+				/* 169 __NR_nfsservctl */
+#define __NR_setresgid		170
+#define __NR_getresgid		171
+#define __NR_prctl		172
+#define __NR_rt_sigreturn	173
+#define __NR_rt_sigaction	174
+#define __NR_rt_sigprocmask	175
+#define __NR_rt_sigpending	176
+#define __NR_rt_sigtimedwait	177
+#define __NR_rt_sigqueueinfo	178
+#define __NR_rt_sigsuspend	179
+#define __NR_pread		180
+#define __NR_pwrite		181
+#define __NR_lchown		182
+#define __NR_getcwd		183
+#define __NR_capget		184
+#define __NR_capset		185
+#define __NR_sigaltstack	186
+#define __NR_sendfile		187
+				/* 188 __NR_getpmsg */
+				/* 189 __NR_putpmsg */
+#define __NR_vfork		190
+#define __NR_getrlimit		191
+#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_chown32		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_lchown32		212
+#define __NR_setuid32		213
+#define __NR_setgid32		214
+#define __NR_setfsuid32		215
+#define __NR_setfsgid32		216
+#define __NR_pivot_root		217
+				/* 218 __NR_mincore */
+				/* 219 __NR_madvise */
+#define __NR_getdents64		220
+#define __NR_fcntl64		221
+				/* 222 reserved for TUX */
+				/* 223 reserved for TUX */
+#define __NR_gettid		224
+				/* 225 __NR_readahead */
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
+#define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
+				/* 243 __NR_set_thread_area */
+				/* 244 __NR_get_thread_area */
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+				/* 250 __NR_alloc_hugepages */
+				/* 251 __NR_free_hugepages */
+#define __NR_exit_group		252
+#define __NR_lookup_dcookie     253
+#define __NR_bfin_spinlock      254
+
+#define __NR_epoll_create	255
+#define __NR_epoll_ctl		256
+#define __NR_epoll_wait		257
+				/* 258 __NR_remap_file_pages */
+#define __NR_set_tid_address	259
+#define __NR_timer_create	260
+#define __NR_timer_settime	(__NR_timer_create+1)
+#define __NR_timer_gettime	(__NR_timer_create+2)
+#define __NR_timer_getoverrun	(__NR_timer_create+3)
+#define __NR_timer_delete	(__NR_timer_create+4)
+#define __NR_clock_settime	(__NR_timer_create+5)
+#define __NR_clock_gettime	(__NR_timer_create+6)
+#define __NR_clock_getres	(__NR_timer_create+7)
+#define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_statfs64		269
+#define __NR_fstatfs64		270
+#define __NR_tgkill		271
+#define __NR_utimes		272
+#define __NR_fadvise64_64	273
+				/* 274 __NR_vserver */
+				/* 275 __NR_mbind */
+				/* 276 __NR_get_mempolicy */
+				/* 277 __NR_set_mempolicy */
+#define __NR_mq_open 		278
+#define __NR_mq_unlink		(__NR_mq_open+1)
+#define __NR_mq_timedsend	(__NR_mq_open+2)
+#define __NR_mq_timedreceive	(__NR_mq_open+3)
+#define __NR_mq_notify		(__NR_mq_open+4)
+#define __NR_mq_getsetattr	(__NR_mq_open+5)
+				/* 284 __NR_sys_kexec_load */
+#define __NR_waitid		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
+				/* 294 __NR_migrate_pages */
+#define __NR_openat		295
+#define __NR_mkdirat		296
+#define __NR_mknodat		297
+#define __NR_fchownat		298
+#define __NR_futimesat		299
+#define __NR_fstatat64		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
+
+/* Blackfin private syscalls */
+#define __NR_sram_alloc		311
+#define __NR_sram_free		312
+#define __NR_dma_memcpy		313
+
+/* socket syscalls */
+#define __NR_accept		314
+#define __NR_bind		315
+#define __NR_connect		316
+#define __NR_getpeername	317
+#define __NR_getsockname	318
+#define __NR_getsockopt		319
+#define __NR_listen		320
+#define __NR_recv		321
+#define __NR_recvfrom		322
+#define __NR_recvmsg		323
+#define __NR_send		324
+#define __NR_sendmsg		325
+#define __NR_sendto		326
+#define __NR_setsockopt		327
+#define __NR_shutdown		328
+#define __NR_socket		329
+#define __NR_socketpair		330
+
+/* sysv ipc syscalls */
+#define __NR_semctl		331
+#define __NR_semget		332
+#define __NR_semop		333
+#define __NR_msgctl		334
+#define __NR_msgget		335
+#define __NR_msgrcv		336
+#define __NR_msgsnd		337
+#define __NR_shmat		338
+#define __NR_shmctl		339
+#define __NR_shmdt		340
+#define __NR_shmget		341
+
+#define __NR_syscall		342
+#define NR_syscalls		__NR_syscall
+
+#ifdef __KERNEL__
+#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_SGETMASK
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t_" #x "\n\t.set\t_" #x ",_sys_ni_syscall");
+
+#endif				/* __ASM_BFIN_UNISTD_H */
diff --git a/include/asm-blackfin/user.h b/include/asm-blackfin/user.h
new file mode 100644
index 0000000..abc3462
--- /dev/null
+++ b/include/asm-blackfin/user.h
@@ -0,0 +1,89 @@
+#ifndef _BFIN_USER_H
+#define _BFIN_USER_H
+
+/* Changes by Tony Kou   Lineo, Inc.  July, 2001
+ *
+ * Based include/asm-m68knommu/user.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).  There are quite a number of
+   obstacles to being able to view the contents of the floating point
+   registers, and until these are solved you will not be able to view the
+   contents of them.  Actually, you can read in the core file and look at
+   the contents of the user struct to find out what the floating point
+   registers contain.
+   The actual 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 useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  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 (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.
+*/
+struct user_bfinfp_struct {
+};
+
+/* This is the old layout of "struct pt_regs" as of Linux 1.x, and
+   is still the layout used by user (the new pt_regs doesn't have
+   all registers). */
+struct user_regs_struct {
+	long r0, r1, r2, r3, r4, r5, r6, r7;
+	long p0, p1, p2, p3, p4, p5, usp, fp;
+	long i0, i1, i2, i3;
+	long l0, l1, l2, l3;
+	long b0, b1, b2, b3;
+	long m0, m1, m2, m3;
+	long a0w, a1w;
+	long a0x, a1x;
+	unsigned long rets;
+	unsigned long astat;
+	unsigned long pc;
+	unsigned long orig_p0;
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+
+struct user {
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+
+	struct user_regs_struct regs;	/* Where the registers are actually stored */
+
+/* The rest of this junk is to help gdb figure out what goes where */
+	unsigned long int u_tsize;	/* Text segment size (pages). */
+	unsigned long int u_dsize;	/* Data segment size (pages). */
+	unsigned long int u_ssize;	/* Stack segment size (pages). */
+	unsigned long start_code;	/* Starting virtual address of text. */
+	unsigned long start_stack;	/* Starting virtual address of stack area.
+					   This is actually the bottom of the stack,
+					   the top of the stack is always found in the
+					   esp register.  */
+	long int signal;	/* Signal that caused the core dump. */
+	int reserved;		/* No longer used */
+	struct user_regs_struct *u_ar0;
+	/* Used by gdb to help find the values for */
+	/* the registers. */
+	unsigned long magic;	/* To uniquely identify a core file */
+	char u_comm[32];	/* User command that was responsible */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif
diff --git a/include/asm-cris/kdebug.h b/include/asm-cris/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-cris/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-cris/mmu_context.h b/include/asm-cris/mmu_context.h
index e6e659d..72ba08d 100644
--- a/include/asm-cris/mmu_context.h
+++ b/include/asm-cris/mmu_context.h
@@ -1,6 +1,8 @@
 #ifndef __CRIS_MMU_CONTEXT_H
 #define __CRIS_MMU_CONTEXT_H
 
+#include <asm-generic/mm_hooks.h>
+
 extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
 extern void get_mmu_context(struct mm_struct *mm);
 extern void destroy_context(struct mm_struct *mm);
diff --git a/include/asm-cris/socket.h b/include/asm-cris/socket.h
index 01cfdf1..5b18dfd 100644
--- a/include/asm-cris/socket.h
+++ b/include/asm-cris/socket.h
@@ -51,6 +51,8 @@ #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
 
diff --git a/include/asm-cris/sockios.h b/include/asm-cris/sockios.h
index 6c4012f..cfe7bfe 100644
--- a/include/asm-cris/sockios.h
+++ b/include/asm-cris/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index 066386a..d425d8d 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -16,6 +16,7 @@ #define _ASM_ATOMIC_H
 
 #include <linux/types.h>
 #include <asm/spr-regs.h>
+#include <asm/system.h>
 
 #ifdef CONFIG_SMP
 #error not SMP safe
@@ -258,85 +259,23 @@ #endif
 
 #define tas(ptr) (xchg((ptr), 1))
 
-/*****************************************************************************/
-/*
- * compare and conditionally exchange value with memory
- * - if (*ptr == test) then orig = *ptr; *ptr = test;
- * - if (*ptr != test) then orig = *ptr;
- */
-#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
-
-#define cmpxchg(ptr, test, new)							\
-({										\
-	__typeof__(ptr) __xg_ptr = (ptr);					\
-	__typeof__(*(ptr)) __xg_orig, __xg_tmp;					\
-	__typeof__(*(ptr)) __xg_test = (test);					\
-	__typeof__(*(ptr)) __xg_new = (new);					\
-										\
-	switch (sizeof(__xg_orig)) {						\
-	case 4:									\
-		asm volatile(							\
-			"0:						\n"	\
-			"	orcc		gr0,gr0,gr0,icc3	\n"	\
-			"	ckeq		icc3,cc7		\n"	\
-			"	ld.p		%M0,%1			\n"	\
-			"	orcr		cc7,cc7,cc3		\n"	\
-			"	sub%I4cc	%1,%4,%2,icc0		\n"	\
-			"	bne		icc0,#0,1f		\n"	\
-			"	cst.p		%3,%M0		,cc3,#1	\n"	\
-			"	corcc		gr29,gr29,gr0	,cc3,#1	\n"	\
-			"	beq		icc3,#0,0b		\n"	\
-			"1:						\n"	\
-			: "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)	\
-			: "r"(__xg_new), "NPr"(__xg_test)			\
-			: "memory", "cc7", "cc3", "icc3", "icc0"		\
-			);							\
-		break;								\
-										\
-	default:								\
-		__xg_orig = 0;							\
-		asm volatile("break");						\
-		break;								\
-	}									\
-										\
-	__xg_orig;								\
-})
-
-#else
-
-extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
-
-#define cmpxchg(ptr, test, new)							\
-({										\
-	__typeof__(ptr) __xg_ptr = (ptr);					\
-	__typeof__(*(ptr)) __xg_orig;						\
-	__typeof__(*(ptr)) __xg_test = (test);					\
-	__typeof__(*(ptr)) __xg_new = (new);					\
-										\
-	switch (sizeof(__xg_orig)) {						\
-	case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break;	\
-	default:								\
-		__xg_orig = 0;							\
-		asm volatile("break");						\
-		break;								\
-	}									\
-										\
-	__xg_orig;								\
-})
-
-#endif
-
 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
 
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
diff --git a/include/asm-frv/kdebug.h b/include/asm-frv/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-frv/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-frv/mmu_context.h b/include/asm-frv/mmu_context.h
index 72edcaa..c7daa39 100644
--- a/include/asm-frv/mmu_context.h
+++ b/include/asm-frv/mmu_context.h
@@ -15,6 +15,7 @@ #define _ASM_MMU_CONTEXT_H
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 8a05aa1..2687c77 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -509,10 +509,6 @@ #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)
-
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-frv/scatterlist.h b/include/asm-frv/scatterlist.h
index fb38fd3..8e827fa 100644
--- a/include/asm-frv/scatterlist.h
+++ b/include/asm-frv/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
+#include <asm/types.h>
+
 /*
  * Drivers must set either ->address or (preferred) ->page and ->offset
  * to indicate where data must be transferred to/from.
diff --git a/include/asm-frv/semaphore.h b/include/asm-frv/semaphore.h
index 907c5c3..0958652 100644
--- a/include/asm-frv/semaphore.h
+++ b/include/asm-frv/semaphore.h
@@ -20,8 +20,6 @@ #include <linux/wait.h>
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 
-#define SEMAPHORE_DEBUG		0
-
 /*
  * the semaphore definition
  * - if counter is >0 then there are tokens available on the semaphore for down to collect
@@ -32,12 +30,12 @@ struct semaphore {
 	unsigned		counter;
 	spinlock_t		wait_lock;
 	struct list_head	wait_list;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 	unsigned		__magic;
 #endif
 };
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 # define __SEM_DEBUG_INIT(name) , (long)&(name).__magic
 #else
 # define __SEM_DEBUG_INIT(name)
@@ -76,7 +74,7 @@ static inline void down(struct semaphore
 {
 	unsigned long flags;
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 	CHECK_MAGIC(sem->__magic);
 #endif
 
@@ -95,7 +93,7 @@ static inline int down_interruptible(str
 	unsigned long flags;
 	int ret = 0;
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 	CHECK_MAGIC(sem->__magic);
 #endif
 
@@ -119,7 +117,7 @@ static inline int down_trylock(struct se
 	unsigned long flags;
 	int success = 0;
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 	CHECK_MAGIC(sem->__magic);
 #endif
 
@@ -136,7 +134,7 @@ static inline void up(struct semaphore *
 {
 	unsigned long flags;
 
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
 	CHECK_MAGIC(sem->__magic);
 #endif
 
diff --git a/include/asm-frv/socket.h b/include/asm-frv/socket.h
index 31db18f..a823bef 100644
--- a/include/asm-frv/socket.h
+++ b/include/asm-frv/socket.h
@@ -49,6 +49,8 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
 
diff --git a/include/asm-frv/sockios.h b/include/asm-frv/sockios.h
index 8a6e4b2..5dbdd13 100644
--- a/include/asm-frv/sockios.h
+++ b/include/asm-frv/sockios.h
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS__ */
 
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index 1166899..be303b3 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -13,7 +13,6 @@ #ifndef _ASM_SYSTEM_H
 #define _ASM_SYSTEM_H
 
 #include <linux/linkage.h>
-#include <asm/atomic.h>
 
 struct thread_struct;
 
@@ -197,4 +196,73 @@ extern void free_initmem(void);
 
 #define arch_align_stack(x) (x)
 
+/*****************************************************************************/
+/*
+ * compare and conditionally exchange value with memory
+ * - if (*ptr == test) then orig = *ptr; *ptr = test;
+ * - if (*ptr != test) then orig = *ptr;
+ */
+#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig, __xg_tmp;					\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4:									\
+		asm volatile(							\
+			"0:						\n"	\
+			"	orcc		gr0,gr0,gr0,icc3	\n"	\
+			"	ckeq		icc3,cc7		\n"	\
+			"	ld.p		%M0,%1			\n"	\
+			"	orcr		cc7,cc7,cc3		\n"	\
+			"	sub%I4cc	%1,%4,%2,icc0		\n"	\
+			"	bne		icc0,#0,1f		\n"	\
+			"	cst.p		%3,%M0		,cc3,#1	\n"	\
+			"	corcc		gr29,gr29,gr0	,cc3,#1	\n"	\
+			"	beq		icc3,#0,0b		\n"	\
+			"1:						\n"	\
+			: "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp)	\
+			: "r"(__xg_new), "NPr"(__xg_test)			\
+			: "memory", "cc7", "cc3", "icc3", "icc0"		\
+			);							\
+		break;								\
+										\
+	default:								\
+		__xg_orig = 0;							\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#else
+
+extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
+
+#define cmpxchg(ptr, test, new)							\
+({										\
+	__typeof__(ptr) __xg_ptr = (ptr);					\
+	__typeof__(*(ptr)) __xg_orig;						\
+	__typeof__(*(ptr)) __xg_test = (test);					\
+	__typeof__(*(ptr)) __xg_new = (new);					\
+										\
+	switch (sizeof(__xg_orig)) {						\
+	case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break;	\
+	default:								\
+		__xg_orig = 0;							\
+		asm volatile("break");						\
+		break;								\
+	}									\
+										\
+	__xg_orig;								\
+})
+
+#endif
+
+
 #endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index b7e4a04..85fd0aa 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -66,6 +66,76 @@ static inline void atomic_long_sub(long 
 	atomic64_sub(i, v);
 }
 
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return atomic64_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic64_t *v = (atomic64_t *)l;
+
+	return (long)atomic64_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic_cmpxchg((atomic64_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic_xchg((atomic64_t *)(l), (new)))
+
 #else  /*  BITS_PER_LONG == 64  */
 
 typedef atomic_t atomic_long_t;
@@ -113,6 +183,76 @@ static inline void atomic_long_sub(long 
 	atomic_sub(i, v);
 }
 
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return atomic_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+	atomic_t *v = (atomic_t *)l;
+
+	return (long)atomic_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+	(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+	(atomic_xchg((atomic_t *)(l), (new)))
+
 #endif  /*  BITS_PER_LONG == 64  */
 
 #endif  /*  _ASM_GENERIC_ATOMIC_H  */
diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h
index 8f4e319..a4a4937 100644
--- a/include/asm-generic/div64.h
+++ b/include/asm-generic/div64.h
@@ -30,6 +30,11 @@ # define do_div(n,base) ({					\
 	__rem;							\
  })
 
+static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+{
+	return dividend / divisor;
+}
+
 #elif BITS_PER_LONG == 32
 
 extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
@@ -49,6 +54,8 @@ # define do_div(n,base) ({				\
 	__rem;						\
  })
 
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
+
 #else /* BITS_PER_LONG == ?? */
 
 # error do_div() does not yet support the C64
diff --git a/include/asm-generic/kdebug.h b/include/asm-generic/kdebug.h
new file mode 100644
index 0000000..2b799c9
--- /dev/null
+++ b/include/asm-generic/kdebug.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_GENERIC_KDEBUG_H
+#define _ASM_GENERIC_KDEBUG_H
+
+enum die_val {
+	DIE_UNUSED,
+};
+
+#endif /* _ASM_GENERIC_KDEBUG_H */
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index ab46929..33d7d04 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -33,6 +33,19 @@ #define local_dec(l)	atomic_long_dec(&(l
 #define local_add(i,l)	atomic_long_add((i),(&(l)->a))
 #define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
 
+#define local_sub_and_test(i, l) atomic_long_sub_and_test((i), (&(l)->a))
+#define local_dec_and_test(l) atomic_long_dec_and_test(&(l)->a)
+#define local_inc_and_test(l) atomic_long_inc_and_test(&(l)->a)
+#define local_add_negative(i, l) atomic_long_add_negative((i), (&(l)->a))
+#define local_add_return(i, l) atomic_long_add_return((i), (&(l)->a))
+#define local_sub_return(i, l) atomic_long_sub_return((i), (&(l)->a))
+#define local_inc_return(l) atomic_long_inc_return(&(l)->a)
+
+#define local_cmpxchg(l, o, n) atomic_long_cmpxchg((&(l)->a), (o), (n))
+#define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n))
+#define local_add_unless(l, a, u) atomic_long_add_unless((&(l)->a), (a), (u))
+#define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a)
+
 /* Non-atomic variants, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well. */
 #define __local_inc(l)		local_set((l), local_read(l) + 1)
@@ -44,19 +57,19 @@ #define __local_sub(i,l)	local_set((l), 
  * much more efficient than these naive implementations.  Note they take
  * a variable (eg. mystruct.foo), not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l)	local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i)	local_set(&__get_cpu_var(l), (i))
+#define cpu_local_inc(l)	local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l)	local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l)	local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l)	local_sub((i), &__get_cpu_var(l))
 
 /* Non-atomic increments, ie. preemption disabled and won't be touched
  * in interrupt, etc.  Some archs can optimize this case well.
  */
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l)	__local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l)	__local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l)	__local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l)	__local_sub((i), &__get_cpu_var(l))
 
 #endif /* _ASM_GENERIC_LOCAL_H */
diff --git a/include/asm-generic/mm_hooks.h b/include/asm-generic/mm_hooks.h
new file mode 100644
index 0000000..67dea81
--- /dev/null
+++ b/include/asm-generic/mm_hooks.h
@@ -0,0 +1,18 @@
+/*
+ * Define generic no-op hooks for arch_dup_mmap and arch_exit_mmap, to
+ * be included in asm-FOO/mmu_context.h for any arch FOO which doesn't
+ * need to hook these.
+ */
+#ifndef _ASM_GENERIC_MM_HOOKS_H
+#define _ASM_GENERIC_MM_HOOKS_H
+
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+				 struct mm_struct *mm)
+{
+}
+
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+}
+
+#endif	/* _ASM_GENERIC_MM_HOOKS_H */
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 1963762..d984a90 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -1,6 +1,7 @@
 #ifndef _ASM_GENERIC_PERCPU_H_
 #define _ASM_GENERIC_PERCPU_H_
 #include <linux/compiler.h>
+#include <linux/threads.h>
 
 #define __GENERIC_PER_CPU
 #ifdef CONFIG_SMP
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 6d7e279..dc8f99e 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -139,8 +139,15 @@ #ifndef __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(pte_val(A) == pte_val(B))
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
-#define page_test_and_clear_dirty(page) (0)
+#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
+#define page_test_dirty(page)		(0)
+#endif
+
+#ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY
+#define page_clear_dirty(page)		do { } while (0)
+#endif
+
+#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
 #define pte_maybe_dirty(pte)		pte_dirty(pte)
 #else
 #define pte_maybe_dirty(pte)		(1)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 9fcc8d9..f3806a7 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -208,7 +208,7 @@ #define BUG_TABLE							\
 	}
 
 #define NOTES								\
-		.notes : { *(.note.*) } :note
+	.notes : { *(.note.*) } :note
 
 #define INITCALLS							\
   	*(.initcall0.init)						\
diff --git a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h
index 42a3ac4..41be646 100644
--- a/include/asm-h8300/irq.h
+++ b/include/asm-h8300/irq.h
@@ -61,6 +61,5 @@ static __inline__ int irq_canonicalize(i
 
 extern void enable_irq(unsigned int);
 extern void disable_irq(unsigned int);
-#define disable_irq_nosync(x)	disable_irq(x)
 
 #endif /* _H8300_IRQ_H_ */
diff --git a/include/asm-h8300/irq_regs.h b/include/asm-h8300/irq_regs.h
new file mode 100644
index 0000000..3dd9c0b
--- /dev/null
+++ b/include/asm-h8300/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-h8300/kdebug.h b/include/asm-h8300/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-h8300/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-h8300/mmu_context.h b/include/asm-h8300/mmu_context.h
index 5c165f7..f44b730 100644
--- a/include/asm-h8300/mmu_context.h
+++ b/include/asm-h8300/mmu_context.h
@@ -4,6 +4,7 @@ #define __H8300_MMU_CONTEXT_H
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h
index 8b7c685..a09230a 100644
--- a/include/asm-h8300/pgtable.h
+++ b/include/asm-h8300/pgtable.h
@@ -55,10 +55,6 @@ #define pgtable_cache_init()   do { } wh
 #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)
-
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
@@ -73,4 +69,5 @@ #define	VMALLOC_END	0xffffffff
 #define	VMALLOC_START	0
 #define	VMALLOC_END	0xffffffff
 
+#define arch_enter_lazy_cpu_mode()    do {} while (0)
 #endif /* _H8300_PGTABLE_H */
diff --git a/include/asm-h8300/scatterlist.h b/include/asm-h8300/scatterlist.h
index 7627f0c..985fdf5 100644
--- a/include/asm-h8300/scatterlist.h
+++ b/include/asm-h8300/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _H8300_SCATTERLIST_H
 #define _H8300_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page	*page;
 	unsigned int	offset;
diff --git a/include/asm-h8300/socket.h b/include/asm-h8300/socket.h
index ebc830f..39911d8 100644
--- a/include/asm-h8300/socket.h
+++ b/include/asm-h8300/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-h8300/sockios.h b/include/asm-h8300/sockios.h
index d005d95..e9c7ec8 100644
--- a/include/asm-h8300/sockios.h
+++ b/include/asm-h8300/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_H8300_SOCKIOS__ */
diff --git a/include/asm-h8300/system.h b/include/asm-h8300/system.h
index 5084a9d..7807018 100644
--- a/include/asm-h8300/system.h
+++ b/include/asm-h8300/system.h
@@ -98,7 +98,6 @@ #define smp_read_barrier_depends()	do { 
 #endif
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-i386/Kbuild b/include/asm-i386/Kbuild
index 5ae93af..cbf6e8f 100644
--- a/include/asm-i386/Kbuild
+++ b/include/asm-i386/Kbuild
@@ -3,8 +3,10 @@ include include/asm-generic/Kbuild.asm
 header-y += boot.h
 header-y += debugreg.h
 header-y += ldt.h
+header-y += msr-index.h
 header-y += ptrace-abi.h
 header-y += ucontext.h
 
+unifdef-y += msr.h
 unifdef-y += mtrr.h
 unifdef-y += vm86.h
diff --git a/include/asm-i386/agp.h b/include/asm-i386/agp.h
index 9075083..6af173d 100644
--- a/include/asm-i386/agp.h
+++ b/include/asm-i386/agp.h
@@ -12,8 +12,10 @@ #include <asm/cacheflush.h>
  * data corruption on some CPUs.
  */
 
-int map_page_into_agp(struct page *page);
-int unmap_page_from_agp(struct page *page);
+/* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
+#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)
+#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
 #define flush_agp_mappings() global_flush_tlb()
 
 /* Could use CLFLUSH here if the cpu supports it. But then it would
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index b8fa955..0f70b37 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -1,8 +1,6 @@
 #ifndef _I386_ALTERNATIVE_H
 #define _I386_ALTERNATIVE_H
 
-#ifdef __KERNEL__
-
 #include <asm/types.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -16,6 +14,7 @@ struct alt_instr {
 	u8  pad;
 };
 
+extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
 
 struct module;
@@ -31,9 +30,7 @@ static inline void alternatives_smp_modu
 					void *text, void *text_end) {}
 static inline void alternatives_smp_module_del(struct module *mod) {}
 static inline void alternatives_smp_switch(int smp) {}
-#endif
-
-#endif
+#endif	/* CONFIG_SMP */
 
 /*
  * Alternative instructions for different CPU types or capabilities.
@@ -85,6 +82,21 @@ #define alternative_input(oldinstr, newi
 		      "663:\n\t" newinstr "\n664:\n"   /* replacement */\
 		      ".previous" :: "i" (feature), ##input)
 
+/* Like alternative_input, but with a single output argument */
+#define alternative_io(oldinstr, newinstr, feature, output, input...) \
+	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
+		      ".section .altinstructions,\"a\"\n"		\
+		      "  .align 4\n"					\
+		      "  .long 661b\n"            /* label */		\
+		      "  .long 663f\n"		  /* new instruction */	\
+		      "  .byte %c[feat]\n"        /* feature bit */	\
+		      "  .byte 662b-661b\n"       /* sourcelen */	\
+		      "  .byte 664f-663f\n"       /* replacementlen */	\
+		      ".previous\n"					\
+		      ".section .altinstr_replacement,\"ax\"\n"		\
+		      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
+		      ".previous" : output : [feat] "i" (feature), ##input)
+
 /*
  * Alternative inline assembly for SMP.
  *
@@ -118,15 +130,17 @@ #else /* ! CONFIG_SMP */
 #define LOCK_PREFIX ""
 #endif
 
-struct paravirt_patch;
+struct paravirt_patch_site;
 #ifdef CONFIG_PARAVIRT
-void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end);
+void apply_paravirt(struct paravirt_patch_site *start,
+		    struct paravirt_patch_site *end);
 #else
 static inline void
-apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
+apply_paravirt(struct paravirt_patch_site *start,
+	       struct paravirt_patch_site *end)
 {}
-#define __start_parainstructions NULL
-#define __stop_parainstructions NULL
+#define __parainstructions	NULL
+#define __parainstructions_end	NULL
 #endif
 
 #endif /* _I386_ALTERNATIVE_H */
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index a19810a..1e8f6f2 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -2,6 +2,7 @@ #ifndef __ASM_APIC_H
 #define __ASM_APIC_H
 
 #include <linux/pm.h>
+#include <linux/delay.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <asm/processor.h>
@@ -64,12 +65,8 @@ static __inline fastcall unsigned long n
 	return *((volatile unsigned long *)(APIC_BASE+reg));
 }
 
-static __inline__ void apic_wait_icr_idle(void)
-{
-	while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY )
-		cpu_relax();
-}
-
+void apic_wait_icr_idle(void);
+unsigned long safe_apic_wait_icr_idle(void);
 int get_physical_broadcast(void);
 
 #ifdef CONFIG_X86_GOOD_APIC
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index 4dd2723..0baa2f8 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -3,6 +3,7 @@ #define __ARCH_I386_ATOMIC__
 
 #include <linux/compiler.h>
 #include <asm/processor.h>
+#include <asm/cmpxchg.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -51,7 +52,7 @@ static __inline__ void atomic_add(int i,
 }
 
 /**
- * atomic_sub - subtract the atomic variable
+ * atomic_sub - subtract integer from atomic variable
  * @i: integer value to subtract
  * @v: pointer of type atomic_t
  * 
@@ -170,7 +171,7 @@ static __inline__ int atomic_add_negativ
 }
 
 /**
- * atomic_add_return - add and return
+ * atomic_add_return - add integer and return
  * @v: pointer of type atomic_t
  * @i: integer value to add
  *
@@ -202,13 +203,20 @@ no_xadd: /* Legacy 386 processor */
 #endif
 }
 
+/**
+ * atomic_sub_return - subtract integer and return
+ * @v: pointer of type atomic_t
+ * @i: integer value to subtract
+ *
+ * Atomically subtracts @i from @v and returns @v - @i
+ */
 static __inline__ int atomic_sub_return(int i, atomic_t *v)
 {
 	return atomic_add_return(-i,v);
 }
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
 
 /**
  * atomic_add_unless - add unless the number is already a given value
@@ -219,20 +227,21 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as @v was not already @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_inc_return(v)  (atomic_add_return(1,v))
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index c90c7c4..d28979f 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -1,198 +1,12 @@
 /*
- *  include/asm-i386/bugs.h
- *
- *  Copyright (C) 1994  Linus Torvalds
- *
- *  Cyrix stuff, June 1998 by:
- *	- Rafael R. Reilova (moved everything from head.S),
- *        <rreilova@ececs.uc.edu>
- *	- Channing Corn (tests & fixes),
- *	- Andrew D. Balsa (code cleanup).
- */
-
-/*
  * This is included by init/main.c to check for architecture-dependent bugs.
  *
  * Needs:
  *	void check_bugs(void);
  */
+#ifndef _ASM_I386_BUG_H
+#define _ASM_I386_BUG_H
 
-#include <linux/init.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/paravirt.h>
-
-static int __init no_halt(char *s)
-{
-	boot_cpu_data.hlt_works_ok = 0;
-	return 1;
-}
-
-__setup("no-hlt", no_halt);
-
-static int __init mca_pentium(char *s)
-{
-	mca_pentium_flag = 1;
-	return 1;
-}
-
-__setup("mca-pentium", mca_pentium);
-
-static int __init no_387(char *s)
-{
-	boot_cpu_data.hard_math = 0;
-	write_cr0(0xE | read_cr0());
-	return 1;
-}
-
-__setup("no387", no_387);
-
-static double __initdata x = 4195835.0;
-static double __initdata y = 3145727.0;
-
-/*
- * This used to check for exceptions.. 
- * However, it turns out that to support that,
- * the XMM trap handlers basically had to
- * be buggy. So let's have a correct XMM trap
- * handler, and forget about printing out
- * some status at boot.
- *
- * We should really only care about bugs here
- * anyway. Not features.
- */
-static void __init check_fpu(void)
-{
-	if (!boot_cpu_data.hard_math) {
-#ifndef CONFIG_MATH_EMULATION
-		printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
-		printk(KERN_EMERG "Giving up.\n");
-		for (;;) ;
-#endif
-		return;
-	}
-
-/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
-	/* Test for the divl bug.. */
-	__asm__("fninit\n\t"
-		"fldl %1\n\t"
-		"fdivl %2\n\t"
-		"fmull %2\n\t"
-		"fldl %1\n\t"
-		"fsubp %%st,%%st(1)\n\t"
-		"fistpl %0\n\t"
-		"fwait\n\t"
-		"fninit"
-		: "=m" (*&boot_cpu_data.fdiv_bug)
-		: "m" (*&x), "m" (*&y));
-	if (boot_cpu_data.fdiv_bug)
-		printk("Hmm, FPU with FDIV bug.\n");
-}
-
-static void __init check_hlt(void)
-{
-	if (paravirt_enabled())
-		return;
-
-	printk(KERN_INFO "Checking 'hlt' instruction... ");
-	if (!boot_cpu_data.hlt_works_ok) {
-		printk("disabled\n");
-		return;
-	}
-	halt();
-	halt();
-	halt();
-	halt();
-	printk("OK.\n");
-}
-
-/*
- *	Most 386 processors have a bug where a POPAD can lock the 
- *	machine even from user space.
- */
- 
-static void __init check_popad(void)
-{
-#ifndef CONFIG_X86_POPAD_OK
-	int res, inp = (int) &res;
-
-	printk(KERN_INFO "Checking for popad bug... ");
-	__asm__ __volatile__( 
-	  "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
-	  : "=&a" (res)
-	  : "d" (inp)
-	  : "ecx", "edi" );
-	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
-	if (res != 12345678) printk( "Buggy.\n" );
-		        else printk( "OK.\n" );
-#endif
-}
-
-/*
- * Check whether we are able to run this kernel safely on SMP.
- *
- * - In order to run on a i386, we need to be compiled for i386
- *   (for due to lack of "invlpg" and working WP on a i386)
- * - In order to run on anything without a TSC, we need to be
- *   compiled for a i486.
- * - In order to support the local APIC on a buggy Pentium machine,
- *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
- *   which happens implicitly if compiled for a Pentium or lower
- *   (unless an advanced selection of CPU features is used) as an
- *   otherwise config implies a properly working local APIC without
- *   the need to do extra reads from the APIC.
-*/
-
-static void __init check_config(void)
-{
-/*
- * We'd better not be a i386 if we're configured to use some
- * i486+ only features! (WP works in supervisor mode and the
- * new "invlpg" and "bswap" instructions)
- */
-#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
-	if (boot_cpu_data.x86 == 3)
-		panic("Kernel requires i486+ for 'invlpg' and other features");
-#endif
-
-/*
- * If we configured ourselves for a TSC, we'd better have one!
- */
-#ifdef CONFIG_X86_TSC
-	if (!cpu_has_tsc && !tsc_disable)
-		panic("Kernel compiled for Pentium+, requires TSC feature!");
-#endif
-
-/*
- * If we were told we had a good local APIC, check for buggy Pentia,
- * i.e. all B steppings and the C2 stepping of P54C when using their
- * integrated APIC (see 11AP erratum in "Pentium Processor
- * Specification Update").
- */
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
-	    && cpu_has_apic
-	    && boot_cpu_data.x86 == 5
-	    && boot_cpu_data.x86_model == 2
-	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
-		panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
-#endif
-}
-
-extern void alternative_instructions(void);
+void check_bugs(void);
 
-static void __init check_bugs(void)
-{
-	identify_cpu(&boot_cpu_data);
-#ifndef CONFIG_SMP
-	printk("CPU: ");
-	print_cpu_info(&boot_cpu_data);
-#endif
-	check_config();
-	check_fpu();
-	check_hlt();
-	check_popad();
-	init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
-	alternative_instructions(); 
-}
+#endif	/* _ASM_I386_BUG_H */
diff --git a/include/asm-i386/cmpxchg.h b/include/asm-i386/cmpxchg.h
new file mode 100644
index 0000000..7adcef0
--- /dev/null
+++ b/include/asm-i386/cmpxchg.h
@@ -0,0 +1,293 @@
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <linux/bitops.h> /* for LOCK_PREFIX */
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+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))))
+#define sync_cmpxchg(ptr,o,n)\
+	((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg_local((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;
+}
+
+/*
+ * 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;
+}
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+			unsigned long old, unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__("cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__("cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__("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;								\
+})
+#define cmpxchg_local(ptr,o,n)						\
+({									\
+	__typeof__(*(ptr)) __ret;					\
+	if (likely(boot_cpu_data.x86 > 3))				\
+		__ret = __cmpxchg_local((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;
+}
+
+static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
+			unsigned long long old, unsigned long long new)
+{
+	unsigned long long prev;
+	__asm__ __volatile__("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)))
+#define cmpxchg64_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
+					(unsigned long long)(n)))
+#endif
+
+#endif
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index d1b8e4a..f514e90 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -7,7 +7,10 @@
 #ifndef __ASM_I386_CPUFEATURE_H
 #define __ASM_I386_CPUFEATURE_H
 
+#ifndef __ASSEMBLY__
 #include <linux/bitops.h>
+#endif
+#include <asm/required-features.h>
 
 #define NCAPINTS	7	/* N 32-bit words worth of info */
 
@@ -49,6 +52,7 @@ #define X86_FEATURE_SYSCALL	(1*32+11) /*
 #define X86_FEATURE_MP		(1*32+19) /* MP Capable. */
 #define X86_FEATURE_NX		(1*32+20) /* Execute Disable */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_RDTSCP	(1*32+27) /* RDTSCP */
 #define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
 #define X86_FEATURE_3DNOW	(1*32+31) /* 3DNow! */
@@ -76,6 +80,7 @@ #define X86_FEATURE_ARCH_PERFMON (3*32+1
 #define X86_FEATURE_PEBS	(3*32+12)  /* Precise-Event Based Sampling */
 #define X86_FEATURE_BTS		(3*32+13)  /* Branch Trace Store */
 #define X86_FEATURE_LAPIC_TIMER_BROKEN (3*32+ 14) /* lapic timer broken in C1 */
+#define X86_FEATURE_SYNC_RDTSC	(3*32+15)  /* RDTSC synchronizes the CPU */
 
 /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
 #define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
@@ -103,8 +108,12 @@ #define X86_FEATURE_PMM_EN	(5*32+ 13) /*
 #define X86_FEATURE_LAHF_LM	(6*32+ 0) /* LAHF/SAHF in long mode */
 #define X86_FEATURE_CMP_LEGACY	(6*32+ 1) /* If yes HyperThreading not valid */
 
-#define cpu_has(c, bit)		test_bit(bit, (c)->x86_capability)
-#define boot_cpu_has(bit)	test_bit(bit, boot_cpu_data.x86_capability)
+#define cpu_has(c, bit)					\
+	((__builtin_constant_p(bit) && (bit) < 32 && 	\
+		(1UL << (bit)) & REQUIRED_MASK1) ?	\
+		1 : 					\
+	test_bit(bit, (c)->x86_capability))
+#define boot_cpu_has(bit)	cpu_has(&boot_cpu_data, bit)
 
 #define cpu_has_fpu		boot_cpu_has(X86_FEATURE_FPU)
 #define cpu_has_vme		boot_cpu_has(X86_FEATURE_VME)
diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h
index 5252ee0..d352485 100644
--- a/include/asm-i386/current.h
+++ b/include/asm-i386/current.h
@@ -1,14 +1,15 @@
 #ifndef _I386_CURRENT_H
 #define _I386_CURRENT_H
 
-#include <asm/pda.h>
 #include <linux/compiler.h>
+#include <asm/percpu.h>
 
 struct task_struct;
 
+DECLARE_PER_CPU(struct task_struct *, current_task);
 static __always_inline struct task_struct *get_current(void)
 {
-	return read_pda(pcurrent);
+	return x86_read_percpu(current_task);
 }
  
 #define current get_current()
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
index 050831f..c547403 100644
--- a/include/asm-i386/desc.h
+++ b/include/asm-i386/desc.h
@@ -12,23 +12,24 @@ #include <linux/percpu.h>
 
 #include <asm/mmu.h>
 
-extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
-
 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);
-extern struct Xgt_desc_struct early_gdt_descr;
+struct gdt_page
+{
+	struct desc_struct gdt[GDT_ENTRIES];
+} __attribute__((aligned(PAGE_SIZE)));
+DECLARE_PER_CPU(struct gdt_page, gdt_page);
 
 static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
 {
-	return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address;
+	return per_cpu(gdt_page, cpu).gdt;
 }
 
+extern struct Xgt_desc_struct idt_descr;
 extern struct desc_struct idt_table[];
 extern void set_intr_gate(unsigned int irq, void * addr);
 
@@ -58,45 +59,33 @@ #define DESCTYPE_S	0x10	/* !system */
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
-
-#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
-#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
+#define load_TR_desc() native_load_tr_desc()
+#define load_gdt(dtr) native_load_gdt(dtr)
+#define load_idt(dtr) native_load_idt(dtr)
 #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":"=m" (tr))
+#define store_gdt(dtr) native_store_gdt(dtr)
+#define store_idt(dtr) native_store_idt(dtr)
+#define store_tr(tr) (tr = native_store_tr())
 #define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt))
 
-#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
-}
+#define load_TLS(t, cpu) native_load_tls(t, cpu)
+#define set_ldt native_set_ldt
 
 #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)
+#endif
 
-static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b)
+static inline void write_dt_entry(struct desc_struct *dt,
+				  int entry, u32 entry_low, u32 entry_high)
 {
-	__u32 *lp = (__u32 *)((char *)dt + entry*8);
-	*lp = entry_a;
-	*(lp+1) = entry_b;
+	dt[entry].a = entry_low;
+	dt[entry].b = entry_high;
 }
 
-#define set_ldt native_set_ldt
-#endif /* CONFIG_PARAVIRT */
-
-static inline fastcall void native_set_ldt(const void *addr,
-					   unsigned int entries)
+static inline void native_set_ldt(const void *addr, unsigned int entries)
 {
 	if (likely(entries == 0))
 		__asm__ __volatile__("lldt %w0"::"q" (0));
@@ -112,6 +101,48 @@ static inline fastcall void native_set_l
 	}
 }
 
+
+static inline void native_load_tr_desc(void)
+{
+	asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
+}
+
+static inline void native_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+	asm volatile("lgdt %0"::"m" (*dtr));
+}
+
+static inline void native_load_idt(const struct Xgt_desc_struct *dtr)
+{
+	asm volatile("lidt %0"::"m" (*dtr));
+}
+
+static inline void native_store_gdt(struct Xgt_desc_struct *dtr)
+{
+	asm ("sgdt %0":"=m" (*dtr));
+}
+
+static inline void native_store_idt(struct Xgt_desc_struct *dtr)
+{
+	asm ("sidt %0":"=m" (*dtr));
+}
+
+static inline unsigned long native_store_tr(void)
+{
+	unsigned long tr;
+	asm ("str %0":"=r" (tr));
+	return tr;
+}
+
+static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+	unsigned int i;
+	struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+
+	for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
+		gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
+}
+
 static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg)
 {
 	__u32 a, b;
diff --git a/include/asm-i386/div64.h b/include/asm-i386/div64.h
index 75c67c7..438e980 100644
--- a/include/asm-i386/div64.h
+++ b/include/asm-i386/div64.h
@@ -1,6 +1,8 @@
 #ifndef __I386_DIV64
 #define __I386_DIV64
 
+#include <linux/types.h>
+
 /*
  * do_div() is NOT a C function. It wants to return
  * two values (the quotient and the remainder), but
@@ -45,4 +47,6 @@ div_ll_X_l_rem(long long divs, long div,
 	return dum2;
 
 }
+
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
index c5b8fc6..096a2a8 100644
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -38,6 +38,7 @@ extern struct e820map e820;
 
 extern int e820_all_mapped(unsigned long start, unsigned long end,
 			   unsigned type);
+extern int e820_any_mapped(u64 start, u64 end, unsigned type);
 extern void find_max_pfn(void);
 extern void register_bootmem_low_pages(unsigned long max_low_pfn);
 extern void e820_register_memory(void);
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 952b3ee..b32df3a 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -9,8 +9,6 @@ #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <asm/auxvec.h>
 
-#include <linux/utsname.h>
-
 #define R_386_NONE	0
 #define R_386_32	1
 #define R_386_PC32	2
@@ -133,39 +131,31 @@ #define ELF_CORE_COPY_FPREGS(tsk, elf_fp
 #define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
 
 #define VDSO_HIGH_BASE		(__fix_to_virt(FIX_VDSO))
-#define VDSO_BASE		((unsigned long)current->mm->context.vdso)
-
-#ifdef CONFIG_COMPAT_VDSO
-# define VDSO_COMPAT_BASE	VDSO_HIGH_BASE
-# define VDSO_PRELINK		VDSO_HIGH_BASE
-#else
-# define VDSO_COMPAT_BASE	VDSO_BASE
-# define VDSO_PRELINK		0
-#endif
+#define VDSO_CURRENT_BASE	((unsigned long)current->mm->context.vdso)
+#define VDSO_PRELINK		0
 
 #define VDSO_SYM(x) \
-		(VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
+		(VDSO_CURRENT_BASE + (unsigned long)(x) - VDSO_PRELINK)
 
 #define VDSO_HIGH_EHDR		((const struct elfhdr *) VDSO_HIGH_BASE)
-#define VDSO_EHDR		((const struct elfhdr *) VDSO_COMPAT_BASE)
+#define VDSO_EHDR		((const struct elfhdr *) VDSO_CURRENT_BASE)
 
 extern void __kernel_vsyscall;
 
 #define VDSO_ENTRY		VDSO_SYM(&__kernel_vsyscall)
 
-#ifndef CONFIG_COMPAT_VDSO
-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
                                        int executable_stack);
-#endif
 
 extern unsigned int vdso_enabled;
 
-#define ARCH_DLINFO						\
-do if (vdso_enabled) {						\
-		NEW_AUX_ENT(AT_SYSINFO,	VDSO_ENTRY);		\
-		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE);	\
+#define ARCH_DLINFO							\
+do if (vdso_enabled) {							\
+		NEW_AUX_ENT(AT_SYSINFO,	VDSO_ENTRY);			\
+		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE);	\
 } while (0)
 
 #endif
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 3e9f610..80ea052 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -19,13 +19,9 @@ #define _ASM_FIXMAP_H
  * Leave one empty page between vmalloc'ed areas and
  * the start of the fixmap.
  */
-#ifndef CONFIG_COMPAT_VDSO
 extern unsigned long __FIXADDR_TOP;
-#else
-#define __FIXADDR_TOP  0xfffff000
-#define FIXADDR_USER_START	__fix_to_virt(FIX_VDSO)
-#define FIXADDR_USER_END	__fix_to_virt(FIX_VDSO - 1)
-#endif
+#define FIXADDR_USER_START     __fix_to_virt(FIX_VDSO)
+#define FIXADDR_USER_END       __fix_to_virt(FIX_VDSO - 1)
 
 #ifndef __ASSEMBLY__
 #include <linux/kernel.h>
@@ -88,6 +84,9 @@ #endif
 #ifdef CONFIG_PCI_MMCONFIG
 	FIX_PCIE_MCFG,
 #endif
+#ifdef CONFIG_PARAVIRT
+	FIX_PARAVIRT_BOOTMAP,
+#endif
 	__end_of_permanent_fixed_addresses,
 	/* temporary boot-time mappings, used before ioremap() is functional */
 #define NR_FIX_BTMAPS	16
diff --git a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h
index fd2be59..33e3ffe 100644
--- a/include/asm-i386/genapic.h
+++ b/include/asm-i386/genapic.h
@@ -36,7 +36,7 @@ struct genapic { 
 	void (*init_apic_ldr)(void);
 	physid_mask_t (*ioapic_phys_id_map)(physid_mask_t map);
 
-	void (*clustered_apic_check)(void);
+	void (*setup_apic_routing)(void);
 	int (*multi_timer_check)(int apic, int irq);
 	int (*apicid_to_node)(int logical_apicid); 
 	int (*cpu_to_logical_apicid)(int cpu);
@@ -99,7 +99,7 @@ #define APIC_INIT(aname, aprobe) { \
 	APICFUNC(check_apicid_present) \
 	APICFUNC(init_apic_ldr) \
 	APICFUNC(ioapic_phys_id_map) \
-	APICFUNC(clustered_apic_check) \
+	APICFUNC(setup_apic_routing) \
 	APICFUNC(multi_timer_check) \
 	APICFUNC(apicid_to_node) \
 	APICFUNC(cpu_to_logical_apicid) \
@@ -122,6 +122,6 @@ #define APIC_INIT(aname, aprobe) { \
 	APICFUNC(phys_pkg_id) \
 	}
 
-extern struct genapic *genapic, apic_default;
+extern struct genapic *genapic;
 
 #endif
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
index e9a34eb..13cdcd6 100644
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -24,6 +24,7 @@ #include <linux/interrupt.h>
 #include <linux/threads.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
+#include <asm/paravirt.h>
 
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
@@ -67,11 +68,16 @@ extern void FASTCALL(kunmap_high(struct 
 
 void *kmap(struct page *page);
 void kunmap(struct page *page);
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
 void *kmap_atomic(struct page *page, enum km_type type);
 void kunmap_atomic(void *kvaddr, enum km_type type);
 void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
 struct page *kmap_atomic_to_page(void *ptr);
 
+#ifndef CONFIG_PARAVIRT
+#define kmap_atomic_pte(page, type)	kmap_atomic(page, type)
+#endif
+
 #define flush_cache_kmaps()	do { } while (0)
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
index fc03cf9..dddeedf 100644
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -28,8 +28,6 @@ #include <asm/processor.h>
 
 #include <linux/timex.h>
 
-#include <asm/fixmap.h>
-
 /*
  * Documentation on HPET can be found at:
  *      http://www.intel.com/ial/home/sp/pcmmspec.htm
diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h
index 434936c..cdd1e24 100644
--- a/include/asm-i386/i387.h
+++ b/include/asm-i386/i387.h
@@ -74,17 +74,18 @@ static inline void __save_init_fpu( stru
 	task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
-#define __unlazy_fpu( tsk ) do { \
-	if (task_thread_info(tsk)->status & TS_USEDFPU) \
-		save_init_fpu( tsk ); 			\
-	else						\
-		tsk->fpu_counter = 0;			\
+#define __unlazy_fpu( tsk ) do {				\
+	if (task_thread_info(tsk)->status & TS_USEDFPU) {	\
+		__save_init_fpu(tsk);				\
+		stts();						\
+	} else							\
+		tsk->fpu_counter = 0;				\
 } while (0)
 
 #define __clear_fpu( tsk )					\
 do {								\
-	if (task_thread_info(tsk)->status & TS_USEDFPU) {		\
-		asm volatile("fnclex ; fwait");				\
+	if (task_thread_info(tsk)->status & TS_USEDFPU) {	\
+		asm volatile("fnclex ; fwait");			\
 		task_thread_info(tsk)->status &= ~TS_USEDFPU;	\
 		stts();						\
 	}							\
@@ -113,7 +114,7 @@ #define clear_fpu( tsk ) do {	\
 	__clear_fpu( tsk );	\
 	preempt_enable();	\
 } while (0)
-					\
+
 /*
  * FPU state interaction...
  */
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 59fe616..e797586 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -250,19 +250,22 @@ #endif
 
 #endif /* __KERNEL__ */
 
+static inline void native_io_delay(void)
+{
+	asm volatile("outb %%al,$0x80" : : : "memory");
+}
+
 #if defined(CONFIG_PARAVIRT)
 #include <asm/paravirt.h>
 #else
 
-#define __SLOW_DOWN_IO "outb %%al,$0x80;"
-
 static inline void slow_down_io(void) {
-	__asm__ __volatile__(
-		__SLOW_DOWN_IO
+	native_io_delay();
 #ifdef REALLY_SLOW_IO
-		__SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+	native_io_delay();
+	native_io_delay();
+	native_io_delay();
 #endif
-		: : );
 }
 
 #endif
diff --git a/include/asm-i386/ioctls.h b/include/asm-i386/ioctls.h
index f962fad..ef58787 100644
--- a/include/asm-i386/ioctls.h
+++ b/include/asm-i386/ioctls.h
@@ -47,6 +47,10 @@ #define TCSBRKP		0x5425	/* Needed for PO
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TCSETSF2	_IOW('T',0x2D, struct termios2)
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index 11761cd..9e15ce0 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -37,8 +37,6 @@ #ifdef CONFIG_IRQBALANCE
 extern int irqbalance_disable(char *str);
 #endif
 
-extern void quirk_intel_irqbalance(void);
-
 #ifdef CONFIG_HOTPLUG_CPU
 extern void fixup_irqs(cpumask_t map);
 #endif
diff --git a/include/asm-i386/irq_regs.h b/include/asm-i386/irq_regs.h
index a1b3f7f..3368b20 100644
--- a/include/asm-i386/irq_regs.h
+++ b/include/asm-i386/irq_regs.h
@@ -1,25 +1,27 @@
 /*
  * Per-cpu current frame pointer - the location of the last exception frame on
- * the stack, stored in the PDA.
+ * the stack, stored in the per-cpu area.
  *
  * Jeremy Fitzhardinge <jeremy@goop.org>
  */
 #ifndef _ASM_I386_IRQ_REGS_H
 #define _ASM_I386_IRQ_REGS_H
 
-#include <asm/pda.h>
+#include <asm/percpu.h>
+
+DECLARE_PER_CPU(struct pt_regs *, irq_regs);
 
 static inline struct pt_regs *get_irq_regs(void)
 {
-	return read_pda(irq_regs);
+	return x86_read_percpu(irq_regs);
 }
 
 static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
 {
 	struct pt_regs *old_regs;
 
-	old_regs = read_pda(irq_regs);
-	write_pda(irq_regs, new_regs);
+	old_regs = get_irq_regs();
+	x86_write_percpu(irq_regs, new_regs);
 
 	return old_regs;
 }
diff --git a/include/asm-i386/irqflags.h b/include/asm-i386/irqflags.h
index 17b18cf..eff8585 100644
--- a/include/asm-i386/irqflags.h
+++ b/include/asm-i386/irqflags.h
@@ -9,6 +9,43 @@
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
+#include <asm/processor-flags.h>
+
+#ifndef __ASSEMBLY__
+static inline unsigned long native_save_fl(void)
+{
+	unsigned long f;
+	asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);
+	return f;
+}
+
+static inline void native_restore_fl(unsigned long f)
+{
+	asm volatile("pushl %0 ; popfl": /* no output */
+			     :"g" (f)
+			     :"memory", "cc");
+}
+
+static inline void native_irq_disable(void)
+{
+	asm volatile("cli": : :"memory");
+}
+
+static inline void native_irq_enable(void)
+{
+	asm volatile("sti": : :"memory");
+}
+
+static inline void native_safe_halt(void)
+{
+	asm volatile("sti; hlt": : :"memory");
+}
+
+static inline void native_halt(void)
+{
+	asm volatile("hlt": : :"memory");
+}
+#endif	/* __ASSEMBLY__ */
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
@@ -17,35 +54,22 @@ #ifndef __ASSEMBLY__
 
 static inline unsigned long __raw_local_save_flags(void)
 {
-	unsigned long flags;
-
-	__asm__ __volatile__(
-		"pushfl ; popl %0"
-		: "=g" (flags)
-		: /* no input */
-	);
-
-	return flags;
+	return native_save_fl();
 }
 
 static inline void raw_local_irq_restore(unsigned long flags)
 {
-	__asm__ __volatile__(
-		"pushl %0 ; popfl"
-		: /* no output */
-		:"g" (flags)
-		:"memory", "cc"
-	);
+	native_restore_fl(flags);
 }
 
 static inline void raw_local_irq_disable(void)
 {
-	__asm__ __volatile__("cli" : : : "memory");
+	native_irq_disable();
 }
 
 static inline void raw_local_irq_enable(void)
 {
-	__asm__ __volatile__("sti" : : : "memory");
+	native_irq_enable();
 }
 
 /*
@@ -54,7 +78,7 @@ static inline void raw_local_irq_enable(
  */
 static inline void raw_safe_halt(void)
 {
-	__asm__ __volatile__("sti; hlt" : : : "memory");
+	native_safe_halt();
 }
 
 /*
@@ -63,7 +87,7 @@ static inline void raw_safe_halt(void)
  */
 static inline void halt(void)
 {
-	__asm__ __volatile__("hlt": : :"memory");
+	native_halt();
 }
 
 /*
@@ -96,7 +120,7 @@ #define raw_local_irq_save(flags) \
 
 static inline int raw_irqs_disabled_flags(unsigned long flags)
 {
-	return !(flags & (1 << 9));
+	return !(flags & X86_EFLAGS_IF);
 }
 
 static inline int raw_irqs_disabled(void)
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index d18cdb9..05c3117 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -9,19 +9,8 @@ #include <linux/notifier.h>
 
 struct pt_regs;
 
-struct die_args {
-	struct pt_regs *regs;
-	const char *str;
-	long err;
-	int trapnr;
-	int signr;
-};
-
-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 i386die_chain;
 
 
 /* Grossly misnamed. */
@@ -38,20 +27,8 @@ enum die_val {
 	DIE_GPF,
 	DIE_CALL,
 	DIE_NMI_IPI,
+	DIE_NMI_POST,
 	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(&i386die_chain, val, &args);
-}
-
 #endif
diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h
index 4dfc9f5..4b9dc9e 100644
--- a/include/asm-i386/kexec.h
+++ b/include/asm-i386/kexec.h
@@ -21,7 +21,6 @@ #endif
 
 #ifndef __ASSEMBLY__
 
-#include <asm/fixmap.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 
@@ -29,10 +28,6 @@ #include <asm/string.h>
  * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
  * I.e. Maximum page that is mapped directly into kernel memory,
  * and kmap is not required.
- *
- * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
- * calculation for the amount of memory directly mappable into the
- * kernel memory space.
  */
 
 /* Maximum physical address we can use pages from */
@@ -47,7 +42,8 @@ #define KEXEC_CONTROL_CODE_SIZE	4096
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_386
 
-#define MAX_NOTE_BYTES 1024
+/* We can also handle crash dumps from 64 bit kernel. */
+#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64)
 
 /* CPU does not save ss and esp on stack if execution is already
  * running in kernel mode at the time of NMI occurrence. This code
diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h
index 12060e2..e13d3e9 100644
--- a/include/asm-i386/local.h
+++ b/include/asm-i386/local.h
@@ -2,47 +2,198 @@ #ifndef _ARCH_I386_LOCAL_H
 #define _ARCH_I386_LOCAL_H
 
 #include <linux/percpu.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
 
 typedef struct
 {
-	volatile long counter;
+	atomic_long_t a;
 } local_t;
 
-#define LOCAL_INIT(i)	{ (i) }
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define local_read(v)	((v)->counter)
-#define local_set(v,i)	(((v)->counter) = (i))
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-static __inline__ void local_inc(local_t *v)
+static __inline__ void local_inc(local_t *l)
 {
 	__asm__ __volatile__(
 		"incl %0"
-		:"+m" (v->counter));
+		:"+m" (l->a.counter));
 }
 
-static __inline__ void local_dec(local_t *v)
+static __inline__ void local_dec(local_t *l)
 {
 	__asm__ __volatile__(
 		"decl %0"
-		:"+m" (v->counter));
+		:"+m" (l->a.counter));
 }
 
-static __inline__ void local_add(long i, local_t *v)
+static __inline__ void local_add(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"addl %1,%0"
-		:"+m" (v->counter)
+		:"+m" (l->a.counter)
 		:"ir" (i));
 }
 
-static __inline__ void local_sub(long i, local_t *v)
+static __inline__ void local_sub(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"subl %1,%0"
-		:"+m" (v->counter)
+		:"+m" (l->a.counter)
 		:"ir" (i));
 }
 
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"subl %2,%0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		:"ir" (i) : "memory");
+	return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int local_dec_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"decl %0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		: : "memory");
+	return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_inc_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"incl %0; sete %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		: : "memory");
+	return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"addl %2,%0; sets %1"
+		:"+m" (l->a.counter), "=qm" (c)
+		:"ir" (i) : "memory");
+	return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+	long __i;
+#ifdef CONFIG_M386
+	unsigned long flags;
+	if(unlikely(boot_cpu_data.x86==3))
+		goto no_xadd;
+#endif
+	/* Modern 486+ processor */
+	__i = i;
+	__asm__ __volatile__(
+		"xaddl %0, %1;"
+		:"+r" (i), "+m" (l->a.counter)
+		: : "memory");
+	return i + __i;
+
+#ifdef CONFIG_M386
+no_xadd: /* Legacy 386 processor */
+	local_irq_save(flags);
+	__i = local_read(l);
+	local_set(l, i + __i);
+	local_irq_restore(flags);
+	return i + __i;
+#endif
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+	return local_add_return(-i,l);
+}
+
+#define local_inc_return(l)  (local_add_return(1,l))
+#define local_dec_return(l)  (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
 /* On x86, these are no better than the atomic variants. */
 #define __local_inc(l)		local_inc(l)
 #define __local_dec(l)		local_dec(l)
@@ -56,27 +207,27 @@ #define __local_sub(i,l)	local_sub((i),(
 
 /* Need to disable preemption for the cpu local counters otherwise we could
    still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v)	 	\
+#define cpu_local_wrap_v(l)	 	\
 	({ local_t res__;		\
 	   preempt_disable(); 		\
-	   res__ = (v);			\
+	   res__ = (l);			\
 	   preempt_enable();		\
 	   res__; })
-#define cpu_local_wrap(v)		\
+#define cpu_local_wrap(l)		\
 	({ preempt_disable();		\
-	   v;				\
+	   l;				\
 	   preempt_enable(); })		\
 
-#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
-
-#define __cpu_local_inc(v)	cpu_local_inc(v)
-#define __cpu_local_dec(v)	cpu_local_dec(v)
-#define __cpu_local_add(i, v)	cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v)	cpu_local_sub((i), (v))
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
 #endif /* _ARCH_I386_LOCAL_H */
diff --git a/include/asm-i386/mach-bigsmp/mach_apic.h b/include/asm-i386/mach-bigsmp/mach_apic.h
index 18b19a7..ebd319f 100644
--- a/include/asm-i386/mach-bigsmp/mach_apic.h
+++ b/include/asm-i386/mach-bigsmp/mach_apic.h
@@ -71,7 +71,7 @@ static inline void init_apic_ldr(void)
 	apic_write_around(APIC_LDR, val);
 }
 
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
 		"Physflat", nr_ioapics);
diff --git a/include/asm-i386/mach-default/mach_apic.h b/include/asm-i386/mach-default/mach_apic.h
index 3ef6292..6db1c3b 100644
--- a/include/asm-i386/mach-default/mach_apic.h
+++ b/include/asm-i386/mach-default/mach_apic.h
@@ -54,7 +54,7 @@ static inline physid_mask_t ioapic_phys_
 	return phys_map;
 }
 
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
 					"Flat", nr_ioapics);
diff --git a/include/asm-i386/mach-es7000/mach_apic.h b/include/asm-i386/mach-es7000/mach_apic.h
index 2633368..2d97892 100644
--- a/include/asm-i386/mach-es7000/mach_apic.h
+++ b/include/asm-i386/mach-es7000/mach_apic.h
@@ -73,15 +73,8 @@ static inline void init_apic_ldr(void)
 	apic_write_around(APIC_LDR, val);
 }
 
-extern void es7000_sw_apic(void);
-static inline void enable_apic_mode(void)
-{
-	es7000_sw_apic();
-	return;
-}
-
 extern int apic_version [MAX_APICS];
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 	int apic = bios_cpu_apicid[smp_processor_id()];
 	printk("Enabling APIC mode:  %s.  Using %d I/O APICs, target cpus %lx\n",
diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h
index 24990e5..b9fb784 100644
--- a/include/asm-i386/mach-es7000/mach_mpparse.h
+++ b/include/asm-i386/mach-es7000/mach_mpparse.h
@@ -18,18 +18,6 @@ extern int parse_unisys_oem (char *oempt
 extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
 extern void setup_unisys(void);
 
-static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
-		char *productid)
-{
-	if (mpc->mpc_oemptr) {
-		struct mp_config_oemtable *oem_table =
-			(struct mp_config_oemtable *)mpc->mpc_oemptr;
-		if (!strncmp(oem, "UNISYS", 6))
-			return parse_unisys_oem((char *)oem_table);
-	}
-	return 0;
-}
-
 #ifdef CONFIG_ACPI
 
 static inline int es7000_check_dsdt(void)
@@ -41,26 +29,6 @@ static inline int es7000_check_dsdt(void
 		return 1;
 	return 0;
 }
-
-/* Hook from generic ACPI tables.c */
-static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-	unsigned long oem_addr;
-	if (!find_unisys_acpi_oem_table(&oem_addr)) {
-		if (es7000_check_dsdt())
-			return parse_unisys_oem((char *)oem_addr);
-		else {
-			setup_unisys();
-			return 1;
-		}
-	}
-	return 0;
-}
-#else
-static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-	return 0;
-}
 #endif
 
 #endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h
index d9dc039..a236e70 100644
--- a/include/asm-i386/mach-generic/mach_apic.h
+++ b/include/asm-i386/mach-generic/mach_apic.h
@@ -13,7 +13,7 @@ #define TARGET_CPUS	  (genapic->target_c
 #define apic_id_registered (genapic->apic_id_registered)
 #define init_apic_ldr (genapic->init_apic_ldr)
 #define ioapic_phys_id_map (genapic->ioapic_phys_id_map)
-#define clustered_apic_check (genapic->clustered_apic_check) 
+#define setup_apic_routing (genapic->setup_apic_routing)
 #define multi_timer_check (genapic->multi_timer_check)
 #define apicid_to_node (genapic->apicid_to_node)
 #define cpu_to_logical_apicid (genapic->cpu_to_logical_apicid) 
diff --git a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h
index 9d15809..5e5e7dd 100644
--- a/include/asm-i386/mach-numaq/mach_apic.h
+++ b/include/asm-i386/mach-numaq/mach_apic.h
@@ -34,7 +34,7 @@ static inline void init_apic_ldr(void)
 	/* Already done in NUMA-Q firmware */
 }
 
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
 		"NUMA-Q", nr_ioapics);
diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h
index 43e5bd8..732f776 100644
--- a/include/asm-i386/mach-summit/mach_apic.h
+++ b/include/asm-i386/mach-summit/mach_apic.h
@@ -80,7 +80,7 @@ static inline int apic_id_registered(voi
 	return 1;
 }
 
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 	printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
 						nr_ioapics);
diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
index 9426839..c252053 100644
--- a/include/asm-i386/mach-summit/mach_mpparse.h
+++ b/include/asm-i386/mach-summit/mach_mpparse.h
@@ -30,7 +30,7 @@ static inline int mps_oem_check(struct m
 			(!strncmp(productid, "VIGIL SMP", 9) 
 			 || !strncmp(productid, "EXA", 3)
 			 || !strncmp(productid, "RUTHLESS SMP", 12))){
-		mark_tsc_unstable();
+		mark_tsc_unstable("Summit based system");
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
 		return 1;
@@ -44,7 +44,7 @@ static inline int acpi_madt_oem_check(ch
 	if (!strncmp(oem_id, "IBM", 3) &&
 	    (!strncmp(oem_table_id, "SERVIGIL", 8)
 	     || !strncmp(oem_table_id, "EXA", 3))){
-		mark_tsc_unstable();
+		mark_tsc_unstable("Summit based system");
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
 		return 1;
diff --git a/include/asm-i386/mach-visws/mach_apic.h b/include/asm-i386/mach-visws/mach_apic.h
index 18afe6b..efac6f0 100644
--- a/include/asm-i386/mach-visws/mach_apic.h
+++ b/include/asm-i386/mach-visws/mach_apic.h
@@ -47,7 +47,7 @@ static inline void summit_check(char *oe
 {
 }
 
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
 {
 }
 
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index e6aa30f..8198d1c 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -5,6 +5,16 @@ #include <asm/desc.h>
 #include <asm/atomic.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/paravirt.h>
+#ifndef CONFIG_PARAVIRT
+#include <asm-generic/mm_hooks.h>
+
+static inline void paravirt_activate_mm(struct mm_struct *prev,
+					struct mm_struct *next)
+{
+}
+#endif	/* !CONFIG_PARAVIRT */
+
 
 /*
  * Used for LDT copy/destruction.
@@ -65,7 +75,10 @@ #endif
 #define deactivate_mm(tsk, mm)			\
 	asm("movl %0,%%gs": :"r" (0));
 
-#define activate_mm(prev, next) \
-	switch_mm((prev),(next),NULL)
+#define activate_mm(prev, next)				\
+	do {						\
+		paravirt_activate_mm(prev, next);	\
+		switch_mm((prev),(next),NULL);		\
+	} while(0);
 
 #endif
diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h
index 02f8f54..7e5fda6 100644
--- a/include/asm-i386/module.h
+++ b/include/asm-i386/module.h
@@ -54,6 +54,8 @@ #elif defined CONFIG_MCYRIXIII
 #define MODULE_PROC_FAMILY "CYRIXIII "
 #elif defined CONFIG_MVIAC3_2
 #define MODULE_PROC_FAMILY "VIAC3-2 "
+#elif defined CONFIG_MVIAC7
+#define MODULE_PROC_FAMILY "VIAC7 "
 #elif defined CONFIG_MGEODEGX1
 #define MODULE_PROC_FAMILY "GEODEGX1 "
 #elif defined CONFIG_MGEODE_LX
diff --git a/include/asm-i386/msr-index.h b/include/asm-i386/msr-index.h
new file mode 100644
index 0000000..a02eb29
--- /dev/null
+++ b/include/asm-i386/msr-index.h
@@ -0,0 +1,278 @@
+#ifndef __ASM_MSR_INDEX_H
+#define __ASM_MSR_INDEX_H
+
+/* CPU model specific register (MSR) numbers */
+
+/* x86-64 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 /* compat mode SYSCALL target */
+#define MSR_SYSCALL_MASK	0xc0000084 /* EFLAGS mask for syscall */
+#define MSR_FS_BASE		0xc0000100 /* 64bit FS base */
+#define MSR_GS_BASE		0xc0000101 /* 64bit GS base */
+#define MSR_KERNEL_GS_BASE	0xc0000102 /* SwapGS GS shadow */
+
+/* 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_PERFCTR0		0x000000c1
+#define MSR_IA32_PERFCTR1		0x000000c2
+#define MSR_FSB_FREQ			0x000000cd
+
+#define MSR_MTRRcap			0x000000fe
+#define MSR_IA32_BBL_CR_CTL		0x00000119
+
+#define MSR_IA32_SYSENTER_CS		0x00000174
+#define MSR_IA32_SYSENTER_ESP		0x00000175
+#define MSR_IA32_SYSENTER_EIP		0x00000176
+
+#define MSR_IA32_MCG_CAP		0x00000179
+#define MSR_IA32_MCG_STATUS		0x0000017a
+#define MSR_IA32_MCG_CTL		0x0000017b
+
+#define MSR_IA32_PEBS_ENABLE		0x000003f1
+#define MSR_IA32_DS_AREA		0x00000600
+#define MSR_IA32_PERF_CAPABILITIES	0x00000345
+
+#define MSR_MTRRfix64K_00000		0x00000250
+#define MSR_MTRRfix16K_80000		0x00000258
+#define MSR_MTRRfix16K_A0000		0x00000259
+#define MSR_MTRRfix4K_C0000		0x00000268
+#define MSR_MTRRfix4K_C8000		0x00000269
+#define MSR_MTRRfix4K_D0000		0x0000026a
+#define MSR_MTRRfix4K_D8000		0x0000026b
+#define MSR_MTRRfix4K_E0000		0x0000026c
+#define MSR_MTRRfix4K_E8000		0x0000026d
+#define MSR_MTRRfix4K_F0000		0x0000026e
+#define MSR_MTRRfix4K_F8000		0x0000026f
+#define MSR_MTRRdefType			0x000002ff
+
+#define MSR_IA32_DEBUGCTLMSR		0x000001d9
+#define MSR_IA32_LASTBRANCHFROMIP	0x000001db
+#define MSR_IA32_LASTBRANCHTOIP		0x000001dc
+#define MSR_IA32_LASTINTFROMIP		0x000001dd
+#define MSR_IA32_LASTINTTOIP		0x000001de
+
+#define MSR_IA32_MC0_CTL		0x00000400
+#define MSR_IA32_MC0_STATUS		0x00000401
+#define MSR_IA32_MC0_ADDR		0x00000402
+#define MSR_IA32_MC0_MISC		0x00000403
+
+#define MSR_P6_PERFCTR0			0x000000c1
+#define MSR_P6_PERFCTR1			0x000000c2
+#define MSR_P6_EVNTSEL0			0x00000186
+#define MSR_P6_EVNTSEL1			0x00000187
+
+/* 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_K7_CLK_CTL			0xc001001b
+#define MSR_K8_TOP_MEM2			0xc001001d
+#define MSR_K8_SYSCFG			0xc0010010
+
+#define K8_MTRRFIXRANGE_DRAM_ENABLE	0x00040000 /* MtrrFixDramEn bit    */
+#define K8_MTRRFIXRANGE_DRAM_MODIFY	0x00080000 /* MtrrFixDramModEn bit */
+#define K8_MTRR_RDMEM_WRMEM_MASK	0x18181818 /* Mask: RdMem|WrMem    */
+
+#define MSR_K7_HWCR			0xc0010015
+#define MSR_K8_HWCR			0xc0010015
+#define MSR_K7_FID_VID_CTL		0xc0010041
+#define MSR_K7_FID_VID_STATUS		0xc0010042
+#define MSR_K8_ENABLE_C1E		0xc0010055
+
+/* 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_EPMR			0xc0000086
+#define MSR_K6_PSOR			0xc0000087
+#define MSR_K6_PFIR			0xc0000088
+
+/* Centaur-Hauls/IDT defined MSRs. */
+#define MSR_IDT_FCR1			0x00000107
+#define MSR_IDT_FCR2			0x00000108
+#define MSR_IDT_FCR3			0x00000109
+#define MSR_IDT_FCR4			0x0000010a
+
+#define MSR_IDT_MCR0			0x00000110
+#define MSR_IDT_MCR1			0x00000111
+#define MSR_IDT_MCR2			0x00000112
+#define MSR_IDT_MCR3			0x00000113
+#define MSR_IDT_MCR4			0x00000114
+#define MSR_IDT_MCR5			0x00000115
+#define MSR_IDT_MCR6			0x00000116
+#define MSR_IDT_MCR7			0x00000117
+#define MSR_IDT_MCR_CTRL		0x00000120
+
+/* VIA Cyrix defined MSRs*/
+#define MSR_VIA_FCR			0x00001107
+#define MSR_VIA_LONGHAUL		0x0000110a
+#define MSR_VIA_RNG			0x0000110b
+#define MSR_VIA_BCR2			0x00001147
+
+/* Transmeta defined MSRs */
+#define MSR_TMTA_LONGRUN_CTRL		0x80868010
+#define MSR_TMTA_LONGRUN_FLAGS		0x80868011
+#define MSR_TMTA_LRTI_READOUT		0x80868018
+#define MSR_TMTA_LRTI_VOLT_MHZ		0x8086801a
+
+/* Intel defined MSRs. */
+#define MSR_IA32_P5_MC_ADDR		0x00000000
+#define MSR_IA32_P5_MC_TYPE		0x00000001
+#define MSR_IA32_TSC			0x00000010
+#define MSR_IA32_PLATFORM_ID		0x00000017
+#define MSR_IA32_EBL_CR_POWERON		0x0000002a
+
+#define MSR_IA32_APICBASE		0x0000001b
+#define MSR_IA32_APICBASE_BSP		(1<<8)
+#define MSR_IA32_APICBASE_ENABLE	(1<<11)
+#define MSR_IA32_APICBASE_BASE		(0xfffff<<12)
+
+#define MSR_IA32_UCODE_WRITE		0x00000079
+#define MSR_IA32_UCODE_REV		0x0000008b
+
+#define MSR_IA32_PERF_STATUS		0x00000198
+#define MSR_IA32_PERF_CTL		0x00000199
+
+#define MSR_IA32_MPERF			0x000000e7
+#define MSR_IA32_APERF			0x000000e8
+
+#define MSR_IA32_THERM_CONTROL		0x0000019a
+#define MSR_IA32_THERM_INTERRUPT	0x0000019b
+#define MSR_IA32_THERM_STATUS		0x0000019c
+#define MSR_IA32_MISC_ENABLE		0x000001a0
+
+/* Intel Model 6 */
+#define MSR_P6_EVNTSEL0			0x00000186
+#define MSR_P6_EVNTSEL1			0x00000187
+
+/* P4/Xeon+ specific */
+#define MSR_IA32_MCG_EAX		0x00000180
+#define MSR_IA32_MCG_EBX		0x00000181
+#define MSR_IA32_MCG_ECX		0x00000182
+#define MSR_IA32_MCG_EDX		0x00000183
+#define MSR_IA32_MCG_ESI		0x00000184
+#define MSR_IA32_MCG_EDI		0x00000185
+#define MSR_IA32_MCG_EBP		0x00000186
+#define MSR_IA32_MCG_ESP		0x00000187
+#define MSR_IA32_MCG_EFLAGS		0x00000188
+#define MSR_IA32_MCG_EIP		0x00000189
+#define MSR_IA32_MCG_RESERVED		0x0000018a
+
+/* Pentium IV performance counter MSRs */
+#define MSR_P4_BPU_PERFCTR0		0x00000300
+#define MSR_P4_BPU_PERFCTR1		0x00000301
+#define MSR_P4_BPU_PERFCTR2		0x00000302
+#define MSR_P4_BPU_PERFCTR3		0x00000303
+#define MSR_P4_MS_PERFCTR0		0x00000304
+#define MSR_P4_MS_PERFCTR1		0x00000305
+#define MSR_P4_MS_PERFCTR2		0x00000306
+#define MSR_P4_MS_PERFCTR3		0x00000307
+#define MSR_P4_FLAME_PERFCTR0		0x00000308
+#define MSR_P4_FLAME_PERFCTR1		0x00000309
+#define MSR_P4_FLAME_PERFCTR2		0x0000030a
+#define MSR_P4_FLAME_PERFCTR3		0x0000030b
+#define MSR_P4_IQ_PERFCTR0		0x0000030c
+#define MSR_P4_IQ_PERFCTR1		0x0000030d
+#define MSR_P4_IQ_PERFCTR2		0x0000030e
+#define MSR_P4_IQ_PERFCTR3		0x0000030f
+#define MSR_P4_IQ_PERFCTR4		0x00000310
+#define MSR_P4_IQ_PERFCTR5		0x00000311
+#define MSR_P4_BPU_CCCR0		0x00000360
+#define MSR_P4_BPU_CCCR1		0x00000361
+#define MSR_P4_BPU_CCCR2		0x00000362
+#define MSR_P4_BPU_CCCR3		0x00000363
+#define MSR_P4_MS_CCCR0			0x00000364
+#define MSR_P4_MS_CCCR1			0x00000365
+#define MSR_P4_MS_CCCR2			0x00000366
+#define MSR_P4_MS_CCCR3			0x00000367
+#define MSR_P4_FLAME_CCCR0		0x00000368
+#define MSR_P4_FLAME_CCCR1		0x00000369
+#define MSR_P4_FLAME_CCCR2		0x0000036a
+#define MSR_P4_FLAME_CCCR3		0x0000036b
+#define MSR_P4_IQ_CCCR0			0x0000036c
+#define MSR_P4_IQ_CCCR1			0x0000036d
+#define MSR_P4_IQ_CCCR2			0x0000036e
+#define MSR_P4_IQ_CCCR3			0x0000036f
+#define MSR_P4_IQ_CCCR4			0x00000370
+#define MSR_P4_IQ_CCCR5			0x00000371
+#define MSR_P4_ALF_ESCR0		0x000003ca
+#define MSR_P4_ALF_ESCR1		0x000003cb
+#define MSR_P4_BPU_ESCR0		0x000003b2
+#define MSR_P4_BPU_ESCR1		0x000003b3
+#define MSR_P4_BSU_ESCR0		0x000003a0
+#define MSR_P4_BSU_ESCR1		0x000003a1
+#define MSR_P4_CRU_ESCR0		0x000003b8
+#define MSR_P4_CRU_ESCR1		0x000003b9
+#define MSR_P4_CRU_ESCR2		0x000003cc
+#define MSR_P4_CRU_ESCR3		0x000003cd
+#define MSR_P4_CRU_ESCR4		0x000003e0
+#define MSR_P4_CRU_ESCR5		0x000003e1
+#define MSR_P4_DAC_ESCR0		0x000003a8
+#define MSR_P4_DAC_ESCR1		0x000003a9
+#define MSR_P4_FIRM_ESCR0		0x000003a4
+#define MSR_P4_FIRM_ESCR1		0x000003a5
+#define MSR_P4_FLAME_ESCR0		0x000003a6
+#define MSR_P4_FLAME_ESCR1		0x000003a7
+#define MSR_P4_FSB_ESCR0		0x000003a2
+#define MSR_P4_FSB_ESCR1		0x000003a3
+#define MSR_P4_IQ_ESCR0			0x000003ba
+#define MSR_P4_IQ_ESCR1			0x000003bb
+#define MSR_P4_IS_ESCR0			0x000003b4
+#define MSR_P4_IS_ESCR1			0x000003b5
+#define MSR_P4_ITLB_ESCR0		0x000003b6
+#define MSR_P4_ITLB_ESCR1		0x000003b7
+#define MSR_P4_IX_ESCR0			0x000003c8
+#define MSR_P4_IX_ESCR1			0x000003c9
+#define MSR_P4_MOB_ESCR0		0x000003aa
+#define MSR_P4_MOB_ESCR1		0x000003ab
+#define MSR_P4_MS_ESCR0			0x000003c0
+#define MSR_P4_MS_ESCR1			0x000003c1
+#define MSR_P4_PMH_ESCR0		0x000003ac
+#define MSR_P4_PMH_ESCR1		0x000003ad
+#define MSR_P4_RAT_ESCR0		0x000003bc
+#define MSR_P4_RAT_ESCR1		0x000003bd
+#define MSR_P4_SAAT_ESCR0		0x000003ae
+#define MSR_P4_SAAT_ESCR1		0x000003af
+#define MSR_P4_SSU_ESCR0		0x000003be
+#define MSR_P4_SSU_ESCR1		0x000003bf /* guess: not in manual */
+
+#define MSR_P4_TBPU_ESCR0		0x000003c2
+#define MSR_P4_TBPU_ESCR1		0x000003c3
+#define MSR_P4_TC_ESCR0			0x000003c4
+#define MSR_P4_TC_ESCR1			0x000003c5
+#define MSR_P4_U2L_ESCR0		0x000003b0
+#define MSR_P4_U2L_ESCR1		0x000003b1
+
+/* Intel Core-based CPU performance counters */
+#define MSR_CORE_PERF_FIXED_CTR0	0x00000309
+#define MSR_CORE_PERF_FIXED_CTR1	0x0000030a
+#define MSR_CORE_PERF_FIXED_CTR2	0x0000030b
+#define MSR_CORE_PERF_FIXED_CTR_CTRL	0x0000038d
+#define MSR_CORE_PERF_GLOBAL_STATUS	0x0000038e
+#define MSR_CORE_PERF_GLOBAL_CTRL	0x0000038f
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL	0x00000390
+
+/* Geode defined MSRs */
+#define MSR_GEODE_BUSCONT_CONF0		0x00001900
+
+#endif /* __ASM_MSR_INDEX_H */
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 2ad3f30..26861df 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -1,32 +1,103 @@
 #ifndef __ASM_MSR_H
 #define __ASM_MSR_H
 
+#include <asm/msr-index.h>
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <asm/errno.h>
+
+static inline unsigned long long native_read_msr(unsigned int msr)
+{
+	unsigned long long val;
+
+	asm volatile("rdmsr" : "=A" (val) : "c" (msr));
+	return val;
+}
+
+static inline unsigned long long native_read_msr_safe(unsigned int msr,
+						      int *err)
+{
+	unsigned long long val;
+
+	asm volatile("2: rdmsr ; xorl %0,%0\n"
+		     "1:\n\t"
+		     ".section .fixup,\"ax\"\n\t"
+		     "3:  movl %3,%0 ; jmp 1b\n\t"
+		     ".previous\n\t"
+ 		     ".section __ex_table,\"a\"\n"
+		     "   .align 4\n\t"
+		     "   .long 	2b,3b\n\t"
+		     ".previous"
+		     : "=r" (*err), "=A" (val)
+		     : "c" (msr), "i" (-EFAULT));
+
+	return val;
+}
+
+static inline void native_write_msr(unsigned int msr, unsigned long long val)
+{
+	asm volatile("wrmsr" : : "c" (msr), "A"(val));
+}
+
+static inline int native_write_msr_safe(unsigned int msr,
+					unsigned long long val)
+{
+	int err;
+	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 4\n\t"
+		     "   .long 	2b,3b\n\t"
+		     ".previous"
+		     : "=a" (err)
+		     : "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)),
+		       "i" (-EFAULT));
+	return err;
+}
+
+static inline unsigned long long native_read_tsc(void)
+{
+	unsigned long long val;
+	asm volatile("rdtsc" : "=A" (val));
+	return val;
+}
+
+static inline unsigned long long native_read_pmc(void)
+{
+	unsigned long long val;
+	asm volatile("rdpmc" : "=A" (val));
+	return val;
+}
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
-
+#include <linux/errno.h>
 /*
  * 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 rdmsr(msr,val1,val2)						\
+	do {								\
+		unsigned long long __val = native_read_msr(msr);	\
+		val1 = __val;						\
+		val2 = __val >> 32;					\
+	} while(0)
 
-#define wrmsr(msr,val1,val2) \
-	__asm__ __volatile__("wrmsr" \
-			  : /* no outputs */ \
-			  : "c" (msr), "a" (val1), "d" (val2))
+#define wrmsr(msr,val1,val2)						\
+	native_write_msr(msr, ((unsigned long long)val2 << 32) | val1)
 
-#define rdmsrl(msr,val) do { \
-	unsigned long l__,h__; \
-	rdmsr (msr, l__, h__);  \
-	val = l__;  \
-	val |= ((u64)h__<<32);  \
-} while(0)
+#define rdmsrl(msr,val)					\
+	do {						\
+		(val) = native_read_msr(msr);		\
+	} while(0)
 
 static inline void wrmsrl (unsigned long msr, unsigned long long val)
 {
@@ -37,55 +108,48 @@ static inline void wrmsrl (unsigned long
 }
 
 /* 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 4\n\t"							\
-		     "   .long 	2b,3b\n\t"						\
-		     ".previous"							\
-		     : "=a" (ret__)							\
-		     : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
-	ret__; })
+#define wrmsr_safe(msr,val1,val2)						\
+	(native_write_msr_safe(msr, ((unsigned long long)val2 << 32) | val1))
 
 /* rdmsr with exception handling */
-#define rdmsr_safe(msr,a,b) ({ int ret__;						\
-	asm volatile("2: rdmsr ; 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 4\n\t"							\
-		     "   .long 	2b,3b\n\t"						\
-		     ".previous"							\
-		     : "=r" (ret__), "=a" (*(a)), "=d" (*(b))				\
-		     : "c" (msr), "i" (-EFAULT));\
-	ret__; })
-
-#define rdtsc(low,high) \
-     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscl(low) \
-     __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
-
-#define rdtscll(val) \
-     __asm__ __volatile__("rdtsc" : "=A" (val))
+#define rdmsr_safe(msr,p1,p2)						\
+	({								\
+		int __err;						\
+		unsigned long long __val = native_read_msr_safe(msr, &__err);\
+		(*p1) = __val;						\
+		(*p2) = __val >> 32;					\
+		__err;							\
+	})
+
+#define rdtsc(low,high)						\
+	do {							\
+		u64 _l = native_read_tsc();			\
+		(low) = (u32)_l;				\
+		(high) = _l >> 32;				\
+	} while(0)
+
+#define rdtscl(low)						\
+	do {							\
+		(low) = native_read_tsc();			\
+	} while(0)
+
+#define rdtscll(val) ((val) = native_read_tsc())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
 
-#define rdpmc(counter,low,high) \
-     __asm__ __volatile__("rdpmc" \
-			  : "=a" (low), "=d" (high) \
-			  : "c" (counter))
+#define rdpmc(counter,low,high)					\
+	do {							\
+		u64 _l = native_read_pmc();			\
+		low = (u32)_l;					\
+		high = _l >> 32;				\
+	} while(0)
 #endif	/* !CONFIG_PARAVIRT */
 
 #ifdef CONFIG_SMP
 void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 #else  /*  CONFIG_SMP  */
 static inline void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
 {
@@ -95,235 +159,15 @@ static inline void wrmsr_on_cpu(unsigned
 {
 	wrmsr(msr_no, l, h);
 }
+static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+	return rdmsr_safe(msr_no, l, h);
+}
+static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	return wrmsr_safe(msr_no, l, h);
+}
 #endif  /*  CONFIG_SMP  */
-
-/* symbolic names for some interesting MSRs */
-/* 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)
-
-#define MSR_IA32_UCODE_WRITE		0x79
-#define MSR_IA32_UCODE_REV		0x8b
-
-#define MSR_P6_PERFCTR0		0xc1
-#define MSR_P6_PERFCTR1		0xc2
-#define MSR_FSB_FREQ		0xcd
-
-
-#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
-
-/* 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_MPERF			0xE7
-#define MSR_IA32_APERF			0xE8
-
-#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
-
-#define MSR_IA32_PEBS_ENABLE		0x3f1
-#define MSR_IA32_DS_AREA		0x600
-#define MSR_IA32_PERF_CAPABILITIES	0x345
-
-/* 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
-
-/* AMD Defined MSRs */
-#define MSR_K6_EFER			0xC0000080
-#define MSR_K6_STAR			0xC0000081
-#define MSR_K6_WHCR			0xC0000082
-#define MSR_K6_UWCCR			0xC0000085
-#define MSR_K6_EPMR			0xC0000086
-#define MSR_K6_PSOR			0xC0000087
-#define MSR_K6_PFIR			0xC0000088
-
-#define MSR_K7_EVNTSEL0			0xC0010000
-#define MSR_K7_EVNTSEL1			0xC0010001
-#define MSR_K7_EVNTSEL2			0xC0010002
-#define MSR_K7_EVNTSEL3			0xC0010003
-#define MSR_K7_PERFCTR0			0xC0010004
-#define MSR_K7_PERFCTR1			0xC0010005
-#define MSR_K7_PERFCTR2			0xC0010006
-#define MSR_K7_PERFCTR3			0xC0010007
-#define MSR_K7_HWCR			0xC0010015
-#define MSR_K7_CLK_CTL			0xC001001b
-#define MSR_K7_FID_VID_CTL		0xC0010041
-#define MSR_K7_FID_VID_STATUS		0xC0010042
-
-#define MSR_K8_ENABLE_C1E		0xC0010055
-
-/* extended feature register */
-#define MSR_EFER 			0xc0000080
-
-/* EFER bits: */
-
-/* Execute Disable enable */
-#define _EFER_NX			11
-#define EFER_NX				(1<<_EFER_NX)
-
-/* 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
-
-/* Transmeta defined MSRs */
-#define MSR_TMTA_LONGRUN_CTRL		0x80868010
-#define MSR_TMTA_LONGRUN_FLAGS		0x80868011
-#define MSR_TMTA_LRTI_READOUT		0x80868018
-#define MSR_TMTA_LRTI_VOLT_MHZ		0x8086801a
-
-/* Intel Core-based CPU performance counters */
-#define MSR_CORE_PERF_FIXED_CTR0	0x309
-#define MSR_CORE_PERF_FIXED_CTR1	0x30a
-#define MSR_CORE_PERF_FIXED_CTR2	0x30b
-#define MSR_CORE_PERF_FIXED_CTR_CTRL	0x38d
-#define MSR_CORE_PERF_GLOBAL_STATUS	0x38e
-#define MSR_CORE_PERF_GLOBAL_CTRL	0x38f
-#define MSR_CORE_PERF_GLOBAL_OVF_CTRL	0x390
-
-/* Geode defined MSRs */
-#define MSR_GEODE_BUSCONT_CONF0         0x1900
-
+#endif
+#endif
 #endif /* __ASM_MSR_H */
diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
index 07f063a..7e9c7cc 100644
--- a/include/asm-i386/mtrr.h
+++ b/include/asm-i386/mtrr.h
@@ -69,6 +69,8 @@ #ifdef __KERNEL__
 
 /*  The following functions are for use by other drivers  */
 # ifdef CONFIG_MTRR
+extern void mtrr_save_fixed_ranges(void *);
+extern void mtrr_save_state(void);
 extern int mtrr_add (unsigned long base, unsigned long size,
 		     unsigned int type, char increment);
 extern int mtrr_add_page (unsigned long base, unsigned long size,
@@ -79,6 +81,8 @@ extern void mtrr_centaur_report_mcr(int 
 extern void mtrr_ap_init(void);
 extern void mtrr_bp_init(void);
 #  else
+#define mtrr_save_fixed_ranges(arg) do {} while (0)
+#define mtrr_save_state() do {} while (0)
 static __inline__ int mtrr_add (unsigned long base, unsigned long size,
 				unsigned int type, char increment)
 {
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index b04333e..fb1e133 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -50,4 +50,12 @@ #define trigger_all_cpu_backtrace() __tr
 
 #endif
 
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+int lapic_watchdog_ok(void);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
+
 #endif /* ASM_NMI_H */
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 7b19f45..818ac8b 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -12,7 +12,6 @@ #define LARGE_PAGE_SIZE (1UL << PMD_SHIF
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
-
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
@@ -42,26 +41,81 @@ #define __HAVE_ARCH_ALLOC_ZEROED_USER_HI
  * 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 pmd_val(x)	((x).pmd)
-#define pte_val(x)	((x).pte_low | ((unsigned long long)(x).pte_high << 32))
-#define __pmd(x) ((pmd_t) { (x) } )
+
+static inline unsigned long long native_pgd_val(pgd_t pgd)
+{
+	return pgd.pgd;
+}
+
+static inline unsigned long long native_pmd_val(pmd_t pmd)
+{
+	return pmd.pmd;
+}
+
+static inline unsigned long long native_pte_val(pte_t pte)
+{
+	return pte.pte_low | ((unsigned long long)pte.pte_high << 32);
+}
+
+static inline pgd_t native_make_pgd(unsigned long long val)
+{
+	return (pgd_t) { val };
+}
+
+static inline pmd_t native_make_pmd(unsigned long long val)
+{
+	return (pmd_t) { val };
+}
+
+static inline pte_t native_make_pte(unsigned long long val)
+{
+	return (pte_t) { .pte_low = val, .pte_high = (val >> 32) } ;
+}
+
+#ifndef CONFIG_PARAVIRT
+#define pmd_val(x)	native_pmd_val(x)
+#define __pmd(x)	native_make_pmd(x)
+#endif
+
 #define HPAGE_SHIFT	21
 #include <asm-generic/pgtable-nopud.h>
-#else
+#else  /* !CONFIG_X86_PAE */
 typedef struct { unsigned long pte_low; } pte_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
 #define boot_pte_t pte_t /* or would you rather have a typedef */
-#define pte_val(x)	((x).pte_low)
+
+static inline unsigned long native_pgd_val(pgd_t pgd)
+{
+	return pgd.pgd;
+}
+
+static inline unsigned long native_pte_val(pte_t pte)
+{
+	return pte.pte_low;
+}
+
+static inline pgd_t native_make_pgd(unsigned long val)
+{
+	return (pgd_t) { val };
+}
+
+static inline pte_t native_make_pte(unsigned long val)
+{
+	return (pte_t) { .pte_low = val };
+}
+
 #define HPAGE_SHIFT	22
 #include <asm-generic/pgtable-nopmd.h>
-#endif
+#endif	/* CONFIG_X86_PAE */
+
 #define PTE_MASK	PAGE_MASK
 
 #ifdef CONFIG_HUGETLB_PAGE
@@ -71,13 +125,16 @@ #define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT 
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 #endif
 
-#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) } )
 
+#ifndef CONFIG_PARAVIRT
+#define pgd_val(x)	native_pgd_val(x)
+#define __pgd(x)	native_make_pgd(x)
+#define pte_val(x)	native_pte_val(x)
+#define __pte(x)	native_make_pte(x)
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -143,9 +200,7 @@ #define VM_DATA_DEFAULT_FLAGS \
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
-#ifndef CONFIG_COMPAT_VDSO
 #define __HAVE_ARCH_GATE_AREA 1
-#endif
 #endif /* __KERNEL__ */
 
 #endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index e63f1e4..e2e7f98 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -2,20 +2,9 @@ #ifndef __ASM_PARAVIRT_H
 #define __ASM_PARAVIRT_H
 /* Various instructions on x86 need to be replaced for
  * para-virtualization: those hooks are defined here. */
-#include <linux/linkage.h>
-#include <linux/stringify.h>
-#include <asm/page.h>
 
 #ifdef CONFIG_PARAVIRT
-/* These are the most performance critical ops, so we want to be able to patch
- * callers */
-#define PARAVIRT_IRQ_DISABLE 0
-#define PARAVIRT_IRQ_ENABLE 1
-#define PARAVIRT_RESTORE_FLAGS 2
-#define PARAVIRT_SAVE_FLAGS 3
-#define PARAVIRT_SAVE_FLAGS_IRQ_DISABLE 4
-#define PARAVIRT_INTERRUPT_RETURN 5
-#define PARAVIRT_STI_SYSEXIT 6
+#include <asm/page.h>
 
 /* Bitmask of what can be clobbered: usually at least eax. */
 #define CLBR_NONE 0x0
@@ -25,13 +14,29 @@ #define CLBR_EDX 0x4
 #define CLBR_ANY 0x7
 
 #ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/cpumask.h>
+#include <asm/kmap_types.h>
+
+struct page;
 struct thread_struct;
 struct Xgt_desc_struct;
 struct tss_struct;
 struct mm_struct;
+struct desc_struct;
+
+/* Lazy mode for batching updates / context switch */
+enum paravirt_lazy_mode {
+	PARAVIRT_LAZY_NONE = 0,
+	PARAVIRT_LAZY_MMU = 1,
+	PARAVIRT_LAZY_CPU = 2,
+	PARAVIRT_LAZY_FLUSH = 3,
+};
+
 struct paravirt_ops
 {
 	unsigned int kernel_rpl;
+	int shared_kernel_pmd;
  	int paravirt_enabled;
 	const char *name;
 
@@ -44,24 +49,33 @@ struct paravirt_ops
 	 */
 	unsigned (*patch)(u8 type, u16 clobber, void *firstinsn, unsigned len);
 
+	/* Basic arch-specific setup */
 	void (*arch_setup)(void);
 	char *(*memory_setup)(void);
 	void (*init_IRQ)(void);
+	void (*time_init)(void);
 
+	/*
+	 * Called before/after init_mm pagetable setup. setup_start
+	 * may reset %cr3, and may pre-install parts of the pagetable;
+	 * pagetable setup is expected to preserve any existing
+	 * mapping.
+	 */
+	void (*pagetable_setup_start)(pgd_t *pgd_base);
+	void (*pagetable_setup_done)(pgd_t *pgd_base);
+
+	/* Print a banner to identify the environment */
 	void (*banner)(void);
 
+	/* Set and set time of day */
 	unsigned long (*get_wallclock)(void);
 	int (*set_wallclock)(unsigned long);
-	void (*time_init)(void);
-
-	/* All the function pointers here are declared as "fastcall"
-	   so that we get a specific register-based calling
-	   convention.  This makes it easier to implement inline
-	   assembler replacements. */
 
+	/* cpuid emulation, mostly so that caps bits can be disabled */
 	void (*cpuid)(unsigned int *eax, unsigned int *ebx,
 		      unsigned int *ecx, unsigned int *edx);
 
+	/* hooks for various privileged instructions */
 	unsigned long (*get_debugreg)(int regno);
 	void (*set_debugreg)(int regno, unsigned long value);
 
@@ -80,15 +94,23 @@ struct paravirt_ops
 	unsigned long (*read_cr4)(void);
 	void (*write_cr4)(unsigned long);
 
+	/*
+	 * Get/set interrupt state.  save_fl and restore_fl are only
+	 * expected to use X86_EFLAGS_IF; all other bits
+	 * returned from save_fl are undefined, and may be ignored by
+	 * restore_fl.
+	 */
 	unsigned long (*save_fl)(void);
 	void (*restore_fl)(unsigned long);
 	void (*irq_disable)(void);
 	void (*irq_enable)(void);
 	void (*safe_halt)(void);
 	void (*halt)(void);
+
 	void (*wbinvd)(void);
 
-	/* err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
+	/* MSR, PMC and TSR operations.
+	   err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
 	u64 (*read_msr)(unsigned int msr, int *err);
 	int (*write_msr)(unsigned int msr, u64 val);
 
@@ -97,6 +119,7 @@ struct paravirt_ops
  	u64 (*get_scheduled_cycles)(void);
 	unsigned long (*get_cpu_khz)(void);
 
+	/* Segment descriptor handling */
 	void (*load_tr_desc)(void);
 	void (*load_gdt)(const struct Xgt_desc_struct *);
 	void (*load_idt)(const struct Xgt_desc_struct *);
@@ -105,59 +128,98 @@ struct paravirt_ops
 	void (*set_ldt)(const void *desc, unsigned entries);
 	unsigned long (*store_tr)(void);
 	void (*load_tls)(struct thread_struct *t, unsigned int cpu);
-	void (*write_ldt_entry)(void *dt, int entrynum,
-					 u32 low, u32 high);
-	void (*write_gdt_entry)(void *dt, int entrynum,
-					 u32 low, u32 high);
-	void (*write_idt_entry)(void *dt, int entrynum,
-					 u32 low, u32 high);
-	void (*load_esp0)(struct tss_struct *tss,
-				   struct thread_struct *thread);
+	void (*write_ldt_entry)(struct desc_struct *,
+				int entrynum, u32 low, u32 high);
+	void (*write_gdt_entry)(struct desc_struct *,
+				int entrynum, u32 low, u32 high);
+	void (*write_idt_entry)(struct desc_struct *,
+				int entrynum, u32 low, u32 high);
+	void (*load_esp0)(struct tss_struct *tss, struct thread_struct *t);
 
 	void (*set_iopl_mask)(unsigned mask);
-
 	void (*io_delay)(void);
 
+	/*
+	 * Hooks for intercepting the creation/use/destruction of an
+	 * mm_struct.
+	 */
+	void (*activate_mm)(struct mm_struct *prev,
+			    struct mm_struct *next);
+	void (*dup_mmap)(struct mm_struct *oldmm,
+			 struct mm_struct *mm);
+	void (*exit_mmap)(struct mm_struct *mm);
+
 #ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Direct APIC operations, principally for VMI.  Ideally
+	 * these shouldn't be in this interface.
+	 */
 	void (*apic_write)(unsigned long reg, unsigned long v);
 	void (*apic_write_atomic)(unsigned long reg, unsigned long v);
 	unsigned long (*apic_read)(unsigned long reg);
 	void (*setup_boot_clock)(void);
 	void (*setup_secondary_clock)(void);
+
+	void (*startup_ipi_hook)(int phys_apicid,
+				 unsigned long start_eip,
+				 unsigned long start_esp);
 #endif
 
+	/* TLB operations */
 	void (*flush_tlb_user)(void);
 	void (*flush_tlb_kernel)(void);
-	void (*flush_tlb_single)(u32 addr);
-
-	void (*map_pt_hook)(int type, pte_t *va, u32 pfn);
+	void (*flush_tlb_single)(unsigned long addr);
+	void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm,
+				 unsigned long va);
 
+	/* Hooks for allocating/releasing pagetable pages */
 	void (*alloc_pt)(u32 pfn);
 	void (*alloc_pd)(u32 pfn);
 	void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
 	void (*release_pt)(u32 pfn);
 	void (*release_pd)(u32 pfn);
 
+	/* Pagetable manipulation functions */
 	void (*set_pte)(pte_t *ptep, pte_t pteval);
-	void (*set_pte_at)(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval);
+	void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
+			   pte_t *ptep, pte_t pteval);
 	void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
-	void (*pte_update)(struct mm_struct *mm, u32 addr, pte_t *ptep);
-	void (*pte_update_defer)(struct mm_struct *mm, u32 addr, pte_t *ptep);
+	void (*pte_update)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+	void (*pte_update_defer)(struct mm_struct *mm,
+				 unsigned long addr, pte_t *ptep);
+
+#ifdef CONFIG_HIGHPTE
+	void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
+#endif
+
 #ifdef CONFIG_X86_PAE
 	void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
-	void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
+ 	void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
 	void (*set_pud)(pud_t *pudp, pud_t pudval);
-	void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+ 	void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
 	void (*pmd_clear)(pmd_t *pmdp);
+
+	unsigned long long (*pte_val)(pte_t);
+	unsigned long long (*pmd_val)(pmd_t);
+	unsigned long long (*pgd_val)(pgd_t);
+
+	pte_t (*make_pte)(unsigned long long pte);
+	pmd_t (*make_pmd)(unsigned long long pmd);
+	pgd_t (*make_pgd)(unsigned long long pgd);
+#else
+	unsigned long (*pte_val)(pte_t);
+	unsigned long (*pgd_val)(pgd_t);
+
+	pte_t (*make_pte)(unsigned long pte);
+	pgd_t (*make_pgd)(unsigned long pgd);
 #endif
 
-	void (*set_lazy_mode)(int mode);
+	/* Set deferred update mode, used for batching operations. */
+	void (*set_lazy_mode)(enum paravirt_lazy_mode mode);
 
 	/* These two are jmp to, not actually called. */
 	void (*irq_enable_sysexit)(void);
 	void (*iret)(void);
-
-	void (*startup_ipi_hook)(int phys_apicid, unsigned long start_eip, unsigned long start_esp);
 };
 
 /* Mark a paravirt probe function. */
@@ -167,23 +229,202 @@ #define paravirt_probe(fn)						\
 
 extern struct paravirt_ops paravirt_ops;
 
-#define paravirt_enabled() (paravirt_ops.paravirt_enabled)
+#define PARAVIRT_PATCH(x)					\
+	(offsetof(struct paravirt_ops, x) / sizeof(void *))
+
+#define paravirt_type(type)					\
+	[paravirt_typenum] "i" (PARAVIRT_PATCH(type))
+#define paravirt_clobber(clobber)		\
+	[paravirt_clobber] "i" (clobber)
+
+/*
+ * Generate some code, and mark it as patchable by the
+ * apply_paravirt() alternate instruction patcher.
+ */
+#define _paravirt_alt(insn_string, type, clobber)	\
+	"771:\n\t" insn_string "\n" "772:\n"		\
+	".pushsection .parainstructions,\"a\"\n"	\
+	"  .long 771b\n"				\
+	"  .byte " type "\n"				\
+	"  .byte 772b-771b\n"				\
+	"  .short " clobber "\n"			\
+	".popsection\n"
+
+/* Generate patchable code, with the default asm parameters. */
+#define paravirt_alt(insn_string)					\
+	_paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
+
+unsigned paravirt_patch_nop(void);
+unsigned paravirt_patch_ignore(unsigned len);
+unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
+			     void *site, u16 site_clobbers,
+			     unsigned len);
+unsigned paravirt_patch_jmp(void *target, void *site, unsigned len);
+unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len);
+
+unsigned paravirt_patch_insns(void *site, unsigned len,
+			      const char *start, const char *end);
+
+
+/*
+ * This generates an indirect call based on the operation type number.
+ * The type number, computed in PARAVIRT_PATCH, is derived from the
+ * offset into the paravirt_ops structure, and can therefore be freely
+ * converted back into a structure offset.
+ */
+#define PARAVIRT_CALL	"call *(paravirt_ops+%c[paravirt_typenum]*4);"
+
+/*
+ * These macros are intended to wrap calls into a paravirt_ops
+ * operation, so that they can be later identified and patched at
+ * runtime.
+ *
+ * Normally, a call to a pv_op function is a simple indirect call:
+ * (paravirt_ops.operations)(args...).
+ *
+ * Unfortunately, this is a relatively slow operation for modern CPUs,
+ * because it cannot necessarily determine what the destination
+ * address is.  In this case, the address is a runtime constant, so at
+ * the very least we can patch the call to e a simple direct call, or
+ * ideally, patch an inline implementation into the callsite.  (Direct
+ * calls are essentially free, because the call and return addresses
+ * are completely predictable.)
+ *
+ * These macros rely on the standard gcc "regparm(3)" calling
+ * convention, in which the first three arguments are placed in %eax,
+ * %edx, %ecx (in that order), and the remaining arguments are placed
+ * on the stack.  All caller-save registers (eax,edx,ecx) are expected
+ * to be modified (either clobbered or used for return values).
+ *
+ * The call instruction itself is marked by placing its start address
+ * and size into the .parainstructions section, so that
+ * apply_paravirt() in arch/i386/kernel/alternative.c can do the
+ * appropriate patching under the control of the backend paravirt_ops
+ * implementation.
+ *
+ * Unfortunately there's no way to get gcc to generate the args setup
+ * for the call, and then allow the call itself to be generated by an
+ * inline asm.  Because of this, we must do the complete arg setup and
+ * return value handling from within these macros.  This is fairly
+ * cumbersome.
+ *
+ * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments.
+ * It could be extended to more arguments, but there would be little
+ * to be gained from that.  For each number of arguments, there are
+ * the two VCALL and CALL variants for void and non-void functions.
+ *
+ * When there is a return value, the invoker of the macro must specify
+ * the return type.  The macro then uses sizeof() on that type to
+ * determine whether its a 32 or 64 bit value, and places the return
+ * in the right register(s) (just %eax for 32-bit, and %edx:%eax for
+ * 64-bit).
+ *
+ * 64-bit arguments are passed as a pair of adjacent 32-bit arguments
+ * in low,high order.
+ *
+ * Small structures are passed and returned in registers.  The macro
+ * calling convention can't directly deal with this, so the wrapper
+ * functions must do this.
+ *
+ * These PVOP_* macros are only defined within this header.  This
+ * means that all uses must be wrapped in inline functions.  This also
+ * makes sure the incoming and outgoing types are always correct.
+ */
+#define __PVOP_CALL(rettype, op, pre, post, ...)			\
+	({								\
+		rettype __ret;						\
+		unsigned long __eax, __edx, __ecx;			\
+		if (sizeof(rettype) > sizeof(unsigned long)) {		\
+			asm volatile(pre				\
+				     paravirt_alt(PARAVIRT_CALL)	\
+				     post				\
+				     : "=a" (__eax), "=d" (__edx),	\
+				       "=c" (__ecx)			\
+				     : paravirt_type(op),		\
+				       paravirt_clobber(CLBR_ANY),	\
+				       ##__VA_ARGS__			\
+				     : "memory", "cc");			\
+			__ret = (rettype)((((u64)__edx) << 32) | __eax); \
+		} else {						\
+			asm volatile(pre				\
+				     paravirt_alt(PARAVIRT_CALL)	\
+				     post				\
+				     : "=a" (__eax), "=d" (__edx),	\
+				       "=c" (__ecx)			\
+				     : paravirt_type(op),		\
+				       paravirt_clobber(CLBR_ANY),	\
+				       ##__VA_ARGS__			\
+				     : "memory", "cc");			\
+			__ret = (rettype)__eax;				\
+		}							\
+		__ret;							\
+	})
+#define __PVOP_VCALL(op, pre, post, ...)				\
+	({								\
+		unsigned long __eax, __edx, __ecx;			\
+		asm volatile(pre					\
+			     paravirt_alt(PARAVIRT_CALL)		\
+			     post					\
+			     : "=a" (__eax), "=d" (__edx), "=c" (__ecx) \
+			     : paravirt_type(op),			\
+			       paravirt_clobber(CLBR_ANY),		\
+			       ##__VA_ARGS__				\
+			     : "memory", "cc");				\
+	})
+
+#define PVOP_CALL0(rettype, op)						\
+	__PVOP_CALL(rettype, op, "", "")
+#define PVOP_VCALL0(op)							\
+	__PVOP_VCALL(op, "", "")
+
+#define PVOP_CALL1(rettype, op, arg1)					\
+	__PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)))
+#define PVOP_VCALL1(op, arg1)						\
+	__PVOP_VCALL(op, "", "", "0" ((u32)(arg1)))
+
+#define PVOP_CALL2(rettype, op, arg1, arg2)				\
+	__PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+#define PVOP_VCALL2(op, arg1, arg2)					\
+	__PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+
+#define PVOP_CALL3(rettype, op, arg1, arg2, arg3)			\
+	__PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)),		\
+		    "1"((u32)(arg2)), "2"((u32)(arg3)))
+#define PVOP_VCALL3(op, arg1, arg2, arg3)				\
+	__PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1"((u32)(arg2)),	\
+		     "2"((u32)(arg3)))
+
+#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4)			\
+	__PVOP_CALL(rettype, op,					\
+		    "push %[_arg4];", "lea 4(%%esp),%%esp;",		\
+		    "0" ((u32)(arg1)), "1" ((u32)(arg2)),		\
+		    "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4)				\
+	__PVOP_VCALL(op,						\
+		    "push %[_arg4];", "lea 4(%%esp),%%esp;",		\
+		    "0" ((u32)(arg1)), "1" ((u32)(arg2)),		\
+		    "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+
+static inline int paravirt_enabled(void)
+{
+	return paravirt_ops.paravirt_enabled;
+}
 
 static inline void load_esp0(struct tss_struct *tss,
 			     struct thread_struct *thread)
 {
-	paravirt_ops.load_esp0(tss, thread);
+	PVOP_VCALL2(load_esp0, tss, thread);
 }
 
 #define ARCH_SETUP			paravirt_ops.arch_setup();
 static inline unsigned long get_wallclock(void)
 {
-	return paravirt_ops.get_wallclock();
+	return PVOP_CALL0(unsigned long, get_wallclock);
 }
 
 static inline int set_wallclock(unsigned long nowtime)
 {
-	return paravirt_ops.set_wallclock(nowtime);
+	return PVOP_CALL1(int, set_wallclock, nowtime);
 }
 
 static inline void (*choose_time_init(void))(void)
@@ -195,113 +436,208 @@ static inline void (*choose_time_init(vo
 static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
 			   unsigned int *ecx, unsigned int *edx)
 {
-	paravirt_ops.cpuid(eax, ebx, ecx, edx);
+	PVOP_VCALL4(cpuid, eax, ebx, ecx, edx);
 }
 
 /*
  * These special macros can be used to get or set a debugging register
  */
-#define get_debugreg(var, reg) var = paravirt_ops.get_debugreg(reg)
-#define set_debugreg(val, reg) paravirt_ops.set_debugreg(reg, val)
+static inline unsigned long paravirt_get_debugreg(int reg)
+{
+	return PVOP_CALL1(unsigned long, get_debugreg, reg);
+}
+#define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
+static inline void set_debugreg(unsigned long val, int reg)
+{
+	PVOP_VCALL2(set_debugreg, reg, val);
+}
+
+static inline void clts(void)
+{
+	PVOP_VCALL0(clts);
+}
 
-#define clts() paravirt_ops.clts()
+static inline unsigned long read_cr0(void)
+{
+	return PVOP_CALL0(unsigned long, read_cr0);
+}
 
-#define read_cr0() paravirt_ops.read_cr0()
-#define write_cr0(x) paravirt_ops.write_cr0(x)
+static inline void write_cr0(unsigned long x)
+{
+	PVOP_VCALL1(write_cr0, x);
+}
 
-#define read_cr2() paravirt_ops.read_cr2()
-#define write_cr2(x) paravirt_ops.write_cr2(x)
+static inline unsigned long read_cr2(void)
+{
+	return PVOP_CALL0(unsigned long, read_cr2);
+}
 
-#define read_cr3() paravirt_ops.read_cr3()
-#define write_cr3(x) paravirt_ops.write_cr3(x)
+static inline void write_cr2(unsigned long x)
+{
+	PVOP_VCALL1(write_cr2, x);
+}
 
-#define read_cr4() paravirt_ops.read_cr4()
-#define read_cr4_safe(x) paravirt_ops.read_cr4_safe()
-#define write_cr4(x) paravirt_ops.write_cr4(x)
+static inline unsigned long read_cr3(void)
+{
+	return PVOP_CALL0(unsigned long, read_cr3);
+}
+
+static inline void write_cr3(unsigned long x)
+{
+	PVOP_VCALL1(write_cr3, x);
+}
+
+static inline unsigned long read_cr4(void)
+{
+	return PVOP_CALL0(unsigned long, read_cr4);
+}
+static inline unsigned long read_cr4_safe(void)
+{
+	return PVOP_CALL0(unsigned long, read_cr4_safe);
+}
+
+static inline void write_cr4(unsigned long x)
+{
+	PVOP_VCALL1(write_cr4, x);
+}
 
 static inline void raw_safe_halt(void)
 {
-	paravirt_ops.safe_halt();
+	PVOP_VCALL0(safe_halt);
 }
 
 static inline void halt(void)
 {
-	paravirt_ops.safe_halt();
+	PVOP_VCALL0(safe_halt);
+}
+
+static inline void wbinvd(void)
+{
+	PVOP_VCALL0(wbinvd);
 }
-#define wbinvd() paravirt_ops.wbinvd()
 
 #define get_kernel_rpl()  (paravirt_ops.kernel_rpl)
 
-#define rdmsr(msr,val1,val2) do {				\
-	int _err;						\
-	u64 _l = paravirt_ops.read_msr(msr,&_err);		\
-	val1 = (u32)_l;						\
-	val2 = _l >> 32;					\
+static inline u64 paravirt_read_msr(unsigned msr, int *err)
+{
+	return PVOP_CALL2(u64, read_msr, msr, err);
+}
+static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
+{
+	return PVOP_CALL3(int, write_msr, msr, low, high);
+}
+
+/* These should all do BUG_ON(_err), but our headers are too tangled. */
+#define rdmsr(msr,val1,val2) do {		\
+	int _err;				\
+	u64 _l = paravirt_read_msr(msr, &_err);	\
+	val1 = (u32)_l;				\
+	val2 = _l >> 32;			\
 } while(0)
 
-#define wrmsr(msr,val1,val2) do {				\
-	u64 _l = ((u64)(val2) << 32) | (val1);			\
-	paravirt_ops.write_msr((msr), _l);			\
+#define wrmsr(msr,val1,val2) do {		\
+	paravirt_write_msr(msr, val1, val2);	\
 } while(0)
 
-#define rdmsrl(msr,val) do {					\
-	int _err;						\
-	val = paravirt_ops.read_msr((msr),&_err);		\
+#define rdmsrl(msr,val) do {			\
+	int _err;				\
+	val = paravirt_read_msr(msr, &_err);	\
 } while(0)
 
-#define wrmsrl(msr,val) (paravirt_ops.write_msr((msr),(val)))
-#define wrmsr_safe(msr,a,b) ({					\
-	u64 _l = ((u64)(b) << 32) | (a);			\
-	paravirt_ops.write_msr((msr),_l);			\
-})
+#define wrmsrl(msr,val)		((void)paravirt_write_msr(msr, val, 0))
+#define wrmsr_safe(msr,a,b)	paravirt_write_msr(msr, a, b)
 
 /* rdmsr with exception handling */
-#define rdmsr_safe(msr,a,b) ({					\
-	int _err;						\
-	u64 _l = paravirt_ops.read_msr(msr,&_err);		\
-	(*a) = (u32)_l;						\
-	(*b) = _l >> 32;					\
+#define rdmsr_safe(msr,a,b) ({			\
+	int _err;				\
+	u64 _l = paravirt_read_msr(msr, &_err);	\
+	(*a) = (u32)_l;				\
+	(*b) = _l >> 32;			\
 	_err; })
 
-#define rdtsc(low,high) do {					\
-	u64 _l = paravirt_ops.read_tsc();			\
-	low = (u32)_l;						\
-	high = _l >> 32;					\
+
+static inline u64 paravirt_read_tsc(void)
+{
+	return PVOP_CALL0(u64, read_tsc);
+}
+#define rdtsc(low,high) do {			\
+	u64 _l = paravirt_read_tsc();		\
+	low = (u32)_l;				\
+	high = _l >> 32;			\
 } while(0)
 
-#define rdtscl(low) do {					\
-	u64 _l = paravirt_ops.read_tsc();			\
-	low = (int)_l;						\
+#define rdtscl(low) do {			\
+	u64 _l = paravirt_read_tsc();		\
+	low = (int)_l;				\
 } while(0)
 
-#define rdtscll(val) (val = paravirt_ops.read_tsc())
+#define rdtscll(val) (val = paravirt_read_tsc())
 
 #define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
 #define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
 
-#define rdpmc(counter,low,high) do {				\
-	u64 _l = paravirt_ops.read_pmc();			\
-	low = (u32)_l;						\
-	high = _l >> 32;					\
+static inline unsigned long long paravirt_read_pmc(int counter)
+{
+	return PVOP_CALL1(u64, read_pmc, counter);
+}
+
+#define rdpmc(counter,low,high) do {		\
+	u64 _l = paravirt_read_pmc(counter);	\
+	low = (u32)_l;				\
+	high = _l >> 32;			\
 } while(0)
 
-#define load_TR_desc() (paravirt_ops.load_tr_desc())
-#define load_gdt(dtr) (paravirt_ops.load_gdt(dtr))
-#define load_idt(dtr) (paravirt_ops.load_idt(dtr))
-#define set_ldt(addr, entries) (paravirt_ops.set_ldt((addr), (entries)))
-#define store_gdt(dtr) (paravirt_ops.store_gdt(dtr))
-#define store_idt(dtr) (paravirt_ops.store_idt(dtr))
-#define store_tr(tr) ((tr) = paravirt_ops.store_tr())
-#define load_TLS(t,cpu) (paravirt_ops.load_tls((t),(cpu)))
-#define write_ldt_entry(dt, entry, low, high)				\
-	(paravirt_ops.write_ldt_entry((dt), (entry), (low), (high)))
-#define write_gdt_entry(dt, entry, low, high)				\
-	(paravirt_ops.write_gdt_entry((dt), (entry), (low), (high)))
-#define write_idt_entry(dt, entry, low, high)				\
-	(paravirt_ops.write_idt_entry((dt), (entry), (low), (high)))
-#define set_iopl_mask(mask) (paravirt_ops.set_iopl_mask(mask))
+static inline void load_TR_desc(void)
+{
+	PVOP_VCALL0(load_tr_desc);
+}
+static inline void load_gdt(const struct Xgt_desc_struct *dtr)
+{
+	PVOP_VCALL1(load_gdt, dtr);
+}
+static inline void load_idt(const struct Xgt_desc_struct *dtr)
+{
+	PVOP_VCALL1(load_idt, dtr);
+}
+static inline void set_ldt(const void *addr, unsigned entries)
+{
+	PVOP_VCALL2(set_ldt, addr, entries);
+}
+static inline void store_gdt(struct Xgt_desc_struct *dtr)
+{
+	PVOP_VCALL1(store_gdt, dtr);
+}
+static inline void store_idt(struct Xgt_desc_struct *dtr)
+{
+	PVOP_VCALL1(store_idt, dtr);
+}
+static inline unsigned long paravirt_store_tr(void)
+{
+	return PVOP_CALL0(unsigned long, store_tr);
+}
+#define store_tr(tr)	((tr) = paravirt_store_tr())
+static inline void load_TLS(struct thread_struct *t, unsigned cpu)
+{
+	PVOP_VCALL2(load_tls, t, cpu);
+}
+static inline void write_ldt_entry(void *dt, int entry, u32 low, u32 high)
+{
+	PVOP_VCALL4(write_ldt_entry, dt, entry, low, high);
+}
+static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high)
+{
+	PVOP_VCALL4(write_gdt_entry, dt, entry, low, high);
+}
+static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high)
+{
+	PVOP_VCALL4(write_idt_entry, dt, entry, low, high);
+}
+static inline void set_iopl_mask(unsigned mask)
+{
+	PVOP_VCALL1(set_iopl_mask, mask);
+}
 
 /* The paravirtualized I/O functions */
 static inline void slow_down_io(void) {
@@ -319,215 +655,390 @@ #ifdef CONFIG_X86_LOCAL_APIC
  */
 static inline void apic_write(unsigned long reg, unsigned long v)
 {
-	paravirt_ops.apic_write(reg,v);
+	PVOP_VCALL2(apic_write, reg, v);
 }
 
 static inline void apic_write_atomic(unsigned long reg, unsigned long v)
 {
-	paravirt_ops.apic_write_atomic(reg,v);
+	PVOP_VCALL2(apic_write_atomic, reg, v);
 }
 
 static inline unsigned long apic_read(unsigned long reg)
 {
-	return paravirt_ops.apic_read(reg);
+	return PVOP_CALL1(unsigned long, apic_read, reg);
 }
 
 static inline void setup_boot_clock(void)
 {
-	paravirt_ops.setup_boot_clock();
+	PVOP_VCALL0(setup_boot_clock);
 }
 
 static inline void setup_secondary_clock(void)
 {
-	paravirt_ops.setup_secondary_clock();
+	PVOP_VCALL0(setup_secondary_clock);
 }
 #endif
 
+static inline void paravirt_pagetable_setup_start(pgd_t *base)
+{
+	if (paravirt_ops.pagetable_setup_start)
+		(*paravirt_ops.pagetable_setup_start)(base);
+}
+
+static inline void paravirt_pagetable_setup_done(pgd_t *base)
+{
+	if (paravirt_ops.pagetable_setup_done)
+		(*paravirt_ops.pagetable_setup_done)(base);
+}
+
 #ifdef CONFIG_SMP
 static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip,
 				    unsigned long start_esp)
 {
-	return paravirt_ops.startup_ipi_hook(phys_apicid, start_eip, start_esp);
+	PVOP_VCALL3(startup_ipi_hook, phys_apicid, start_eip, start_esp);
 }
 #endif
 
-#define __flush_tlb() paravirt_ops.flush_tlb_user()
-#define __flush_tlb_global() paravirt_ops.flush_tlb_kernel()
-#define __flush_tlb_single(addr) paravirt_ops.flush_tlb_single(addr)
+static inline void paravirt_activate_mm(struct mm_struct *prev,
+					struct mm_struct *next)
+{
+	PVOP_VCALL2(activate_mm, prev, next);
+}
 
-#define paravirt_map_pt_hook(type, va, pfn) paravirt_ops.map_pt_hook(type, va, pfn)
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+				 struct mm_struct *mm)
+{
+	PVOP_VCALL2(dup_mmap, oldmm, mm);
+}
 
-#define paravirt_alloc_pt(pfn) paravirt_ops.alloc_pt(pfn)
-#define paravirt_release_pt(pfn) paravirt_ops.release_pt(pfn)
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+	PVOP_VCALL1(exit_mmap, mm);
+}
 
-#define paravirt_alloc_pd(pfn) paravirt_ops.alloc_pd(pfn)
-#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) \
-	paravirt_ops.alloc_pd_clone(pfn, clonepfn, start, count)
-#define paravirt_release_pd(pfn) paravirt_ops.release_pd(pfn)
+static inline void __flush_tlb(void)
+{
+	PVOP_VCALL0(flush_tlb_user);
+}
+static inline void __flush_tlb_global(void)
+{
+	PVOP_VCALL0(flush_tlb_kernel);
+}
+static inline void __flush_tlb_single(unsigned long addr)
+{
+	PVOP_VCALL1(flush_tlb_single, addr);
+}
 
-static inline void set_pte(pte_t *ptep, pte_t pteval)
+static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+				    unsigned long va)
 {
-	paravirt_ops.set_pte(ptep, pteval);
+	PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
 }
 
-static inline void set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval)
+static inline void paravirt_alloc_pt(unsigned pfn)
 {
-	paravirt_ops.set_pte_at(mm, addr, ptep, pteval);
+	PVOP_VCALL1(alloc_pt, pfn);
+}
+static inline void paravirt_release_pt(unsigned pfn)
+{
+	PVOP_VCALL1(release_pt, pfn);
 }
 
-static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+static inline void paravirt_alloc_pd(unsigned pfn)
 {
-	paravirt_ops.set_pmd(pmdp, pmdval);
+	PVOP_VCALL1(alloc_pd, pfn);
 }
 
-static inline void pte_update(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static inline void paravirt_alloc_pd_clone(unsigned pfn, unsigned clonepfn,
+					   unsigned start, unsigned count)
 {
-	paravirt_ops.pte_update(mm, addr, ptep);
+	PVOP_VCALL4(alloc_pd_clone, pfn, clonepfn, start, count);
+}
+static inline void paravirt_release_pd(unsigned pfn)
+{
+	PVOP_VCALL1(release_pd, pfn);
 }
 
-static inline void pte_update_defer(struct mm_struct *mm, u32 addr, pte_t *ptep)
+#ifdef CONFIG_HIGHPTE
+static inline void *kmap_atomic_pte(struct page *page, enum km_type type)
 {
-	paravirt_ops.pte_update_defer(mm, addr, ptep);
+	unsigned long ret;
+	ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type);
+	return (void *)ret;
+}
+#endif
+
+static inline void pte_update(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep)
+{
+	PVOP_VCALL3(pte_update, mm, addr, ptep);
+}
+
+static inline void pte_update_defer(struct mm_struct *mm, unsigned long addr,
+				    pte_t *ptep)
+{
+	PVOP_VCALL3(pte_update_defer, mm, addr, ptep);
 }
 
 #ifdef CONFIG_X86_PAE
+static inline pte_t __pte(unsigned long long val)
+{
+	unsigned long long ret = PVOP_CALL2(unsigned long long, make_pte,
+					    val, val >> 32);
+	return (pte_t) { ret, ret >> 32 };
+}
+
+static inline pmd_t __pmd(unsigned long long val)
+{
+	return (pmd_t) { PVOP_CALL2(unsigned long long, make_pmd, val, val >> 32) };
+}
+
+static inline pgd_t __pgd(unsigned long long val)
+{
+	return (pgd_t) { PVOP_CALL2(unsigned long long, make_pgd, val, val >> 32) };
+}
+
+static inline unsigned long long pte_val(pte_t x)
+{
+	return PVOP_CALL2(unsigned long long, pte_val, x.pte_low, x.pte_high);
+}
+
+static inline unsigned long long pmd_val(pmd_t x)
+{
+	return PVOP_CALL2(unsigned long long, pmd_val, x.pmd, x.pmd >> 32);
+}
+
+static inline unsigned long long pgd_val(pgd_t x)
+{
+	return PVOP_CALL2(unsigned long long, pgd_val, x.pgd, x.pgd >> 32);
+}
+
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+	PVOP_VCALL3(set_pte, ptep, pteval.pte_low, pteval.pte_high);
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval)
+{
+	/* 5 arg words */
+	paravirt_ops.set_pte_at(mm, addr, ptep, pteval);
+}
+
 static inline void set_pte_atomic(pte_t *ptep, pte_t pteval)
 {
-	paravirt_ops.set_pte_atomic(ptep, pteval);
+	PVOP_VCALL3(set_pte_atomic, ptep, pteval.pte_low, pteval.pte_high);
 }
 
-static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void set_pte_present(struct mm_struct *mm, unsigned long addr,
+				   pte_t *ptep, pte_t pte)
 {
+	/* 5 arg words */
 	paravirt_ops.set_pte_present(mm, addr, ptep, pte);
 }
 
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+	PVOP_VCALL3(set_pmd, pmdp, pmdval.pmd, pmdval.pmd >> 32);
+}
+
 static inline void set_pud(pud_t *pudp, pud_t pudval)
 {
-	paravirt_ops.set_pud(pudp, pudval);
+	PVOP_VCALL3(set_pud, pudp, pudval.pgd.pgd, pudval.pgd.pgd >> 32);
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-	paravirt_ops.pte_clear(mm, addr, ptep);
+	PVOP_VCALL3(pte_clear, mm, addr, ptep);
 }
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
-	paravirt_ops.pmd_clear(pmdp);
+	PVOP_VCALL1(pmd_clear, pmdp);
 }
-#endif
 
-/* Lazy mode for batching updates / context switch */
-#define PARAVIRT_LAZY_NONE 0
-#define PARAVIRT_LAZY_MMU  1
-#define PARAVIRT_LAZY_CPU  2
-#define PARAVIRT_LAZY_FLUSH 3
+#else  /* !CONFIG_X86_PAE */
+
+static inline pte_t __pte(unsigned long val)
+{
+	return (pte_t) { PVOP_CALL1(unsigned long, make_pte, val) };
+}
+
+static inline pgd_t __pgd(unsigned long val)
+{
+	return (pgd_t) { PVOP_CALL1(unsigned long, make_pgd, val) };
+}
+
+static inline unsigned long pte_val(pte_t x)
+{
+	return PVOP_CALL1(unsigned long, pte_val, x.pte_low);
+}
+
+static inline unsigned long pgd_val(pgd_t x)
+{
+	return PVOP_CALL1(unsigned long, pgd_val, x.pgd);
+}
+
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+	PVOP_VCALL2(set_pte, ptep, pteval.pte_low);
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval)
+{
+	PVOP_VCALL4(set_pte_at, mm, addr, ptep, pteval.pte_low);
+}
+
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+	PVOP_VCALL2(set_pmd, pmdp, pmdval.pud.pgd.pgd);
+}
+#endif	/* CONFIG_X86_PAE */
 
 #define  __HAVE_ARCH_ENTER_LAZY_CPU_MODE
-#define arch_enter_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_CPU)
-#define arch_leave_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
-#define arch_flush_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_FLUSH)
+static inline void arch_enter_lazy_cpu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_CPU);
+}
+
+static inline void arch_leave_lazy_cpu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+}
+
+static inline void arch_flush_lazy_cpu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+}
+
 
 #define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
-#define arch_enter_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_MMU)
-#define arch_leave_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
-#define arch_flush_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_FLUSH)
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_MMU);
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+}
+
+static inline void arch_flush_lazy_mmu_mode(void)
+{
+	PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+}
+
+void _paravirt_nop(void);
+#define paravirt_nop	((void *)_paravirt_nop)
 
 /* These all sit in the .parainstructions section to tell us what to patch. */
-struct paravirt_patch {
+struct paravirt_patch_site {
 	u8 *instr; 		/* original instructions */
 	u8 instrtype;		/* type of this instruction */
 	u8 len;			/* length of original instruction */
 	u16 clobbers;		/* what registers you may clobber */
 };
 
-#define paravirt_alt(insn_string, typenum, clobber)	\
-	"771:\n\t" insn_string "\n" "772:\n"		\
-	".pushsection .parainstructions,\"a\"\n"	\
-	"  .long 771b\n"				\
-	"  .byte " __stringify(typenum) "\n"		\
-	"  .byte 772b-771b\n"				\
-	"  .short " __stringify(clobber) "\n"		\
-	".popsection"
+extern struct paravirt_patch_site __parainstructions[],
+	__parainstructions_end[];
 
 static inline unsigned long __raw_local_save_flags(void)
 {
 	unsigned long f;
 
-	__asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
-					   "call *%1;"
-					   "popl %%edx; popl %%ecx",
-					  PARAVIRT_SAVE_FLAGS, CLBR_NONE)
-			     : "=a"(f): "m"(paravirt_ops.save_fl)
-			     : "memory", "cc");
+	asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+				  PARAVIRT_CALL
+				  "popl %%edx; popl %%ecx")
+		     : "=a"(f)
+		     : paravirt_type(save_fl),
+		       paravirt_clobber(CLBR_EAX)
+		     : "memory", "cc");
 	return f;
 }
 
 static inline void raw_local_irq_restore(unsigned long f)
 {
-	__asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
-					   "call *%1;"
-					   "popl %%edx; popl %%ecx",
-					  PARAVIRT_RESTORE_FLAGS, CLBR_EAX)
-			     : "=a"(f) : "m" (paravirt_ops.restore_fl), "0"(f)
-			     : "memory", "cc");
+	asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+				  PARAVIRT_CALL
+				  "popl %%edx; popl %%ecx")
+		     : "=a"(f)
+		     : "0"(f),
+		       paravirt_type(restore_fl),
+		       paravirt_clobber(CLBR_EAX)
+		     : "memory", "cc");
 }
 
 static inline void raw_local_irq_disable(void)
 {
-	__asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
-					   "call *%0;"
-					   "popl %%edx; popl %%ecx",
-					  PARAVIRT_IRQ_DISABLE, CLBR_EAX)
-			     : : "m" (paravirt_ops.irq_disable)
-			     : "memory", "eax", "cc");
+	asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+				  PARAVIRT_CALL
+				  "popl %%edx; popl %%ecx")
+		     :
+		     : paravirt_type(irq_disable),
+		       paravirt_clobber(CLBR_EAX)
+		     : "memory", "eax", "cc");
 }
 
 static inline void raw_local_irq_enable(void)
 {
-	__asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
-					   "call *%0;"
-					   "popl %%edx; popl %%ecx",
-					  PARAVIRT_IRQ_ENABLE, CLBR_EAX)
-			     : : "m" (paravirt_ops.irq_enable)
-			     : "memory", "eax", "cc");
+	asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+				  PARAVIRT_CALL
+				  "popl %%edx; popl %%ecx")
+		     :
+		     : paravirt_type(irq_enable),
+		       paravirt_clobber(CLBR_EAX)
+		     : "memory", "eax", "cc");
 }
 
 static inline unsigned long __raw_local_irq_save(void)
 {
 	unsigned long f;
 
-	__asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
-					   "call *%1; pushl %%eax;"
-					   "call *%2; popl %%eax;"
-					   "popl %%edx; popl %%ecx",
-					  PARAVIRT_SAVE_FLAGS_IRQ_DISABLE,
-					  CLBR_NONE)
-			     : "=a"(f)
-			     : "m" (paravirt_ops.save_fl),
-			       "m" (paravirt_ops.irq_disable)
-			     : "memory", "cc");
+	f = __raw_local_save_flags();
+	raw_local_irq_disable();
 	return f;
 }
 
-#define CLI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;"		\
-		     "call *paravirt_ops+%c[irq_disable];"		\
-		     "popl %%edx; popl %%ecx",				\
-		     PARAVIRT_IRQ_DISABLE, CLBR_EAX)
+#define CLI_STRING							\
+	_paravirt_alt("pushl %%ecx; pushl %%edx;"			\
+		      "call *paravirt_ops+%c[paravirt_cli_type]*4;"	\
+		      "popl %%edx; popl %%ecx",				\
+		      "%c[paravirt_cli_type]", "%c[paravirt_clobber]")
+
+#define STI_STRING							\
+	_paravirt_alt("pushl %%ecx; pushl %%edx;"			\
+		      "call *paravirt_ops+%c[paravirt_sti_type]*4;"	\
+		      "popl %%edx; popl %%ecx",				\
+		      "%c[paravirt_sti_type]", "%c[paravirt_clobber]")
 
-#define STI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;"		\
-		     "call *paravirt_ops+%c[irq_enable];"		\
-		     "popl %%edx; popl %%ecx",				\
-		     PARAVIRT_IRQ_ENABLE, CLBR_EAX)
 #define CLI_STI_CLOBBERS , "%eax"
-#define CLI_STI_INPUT_ARGS \
+#define CLI_STI_INPUT_ARGS						\
 	,								\
-	[irq_disable] "i" (offsetof(struct paravirt_ops, irq_disable)),	\
-	[irq_enable] "i" (offsetof(struct paravirt_ops, irq_enable))
+	[paravirt_cli_type] "i" (PARAVIRT_PATCH(irq_disable)),		\
+	[paravirt_sti_type] "i" (PARAVIRT_PATCH(irq_enable)),		\
+	paravirt_clobber(CLBR_EAX)
+
+/* Make sure as little as possible of this mess escapes. */
+#undef PARAVIRT_CALL
+#undef __PVOP_CALL
+#undef __PVOP_VCALL
+#undef PVOP_VCALL0
+#undef PVOP_CALL0
+#undef PVOP_VCALL1
+#undef PVOP_CALL1
+#undef PVOP_VCALL2
+#undef PVOP_CALL2
+#undef PVOP_VCALL3
+#undef PVOP_CALL3
+#undef PVOP_VCALL4
+#undef PVOP_CALL4
 
 #else  /* __ASSEMBLY__ */
 
-#define PARA_PATCH(ptype, clobbers, ops)	\
+#define PARA_PATCH(off)	((off) / 4)
+
+#define PARA_SITE(ptype, clobbers, ops)		\
 771:;						\
 	ops;					\
 772:;						\
@@ -538,28 +1049,30 @@ #define PARA_PATCH(ptype, clobbers, ops)
 	 .short clobbers;			\
 	.popsection
 
-#define INTERRUPT_RETURN				\
-	PARA_PATCH(PARAVIRT_INTERRUPT_RETURN, CLBR_ANY,	\
-	jmp *%cs:paravirt_ops+PARAVIRT_iret)
+#define INTERRUPT_RETURN					\
+	PARA_SITE(PARA_PATCH(PARAVIRT_iret), CLBR_NONE,		\
+		  jmp *%cs:paravirt_ops+PARAVIRT_iret)
 
-#define DISABLE_INTERRUPTS(clobbers)			\
-	PARA_PATCH(PARAVIRT_IRQ_DISABLE, clobbers,	\
-	pushl %ecx; pushl %edx;				\
-	call *paravirt_ops+PARAVIRT_irq_disable;	\
-	popl %edx; popl %ecx)				\
+#define DISABLE_INTERRUPTS(clobbers)					\
+	PARA_SITE(PARA_PATCH(PARAVIRT_irq_disable), clobbers,		\
+		  pushl %eax; pushl %ecx; pushl %edx;			\
+		  call *%cs:paravirt_ops+PARAVIRT_irq_disable;		\
+		  popl %edx; popl %ecx; popl %eax)			\
 
-#define ENABLE_INTERRUPTS(clobbers)			\
-	PARA_PATCH(PARAVIRT_IRQ_ENABLE, clobbers,	\
-	pushl %ecx; pushl %edx;				\
-	call *%cs:paravirt_ops+PARAVIRT_irq_enable;	\
-	popl %edx; popl %ecx)
+#define ENABLE_INTERRUPTS(clobbers)					\
+	PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable), clobbers,		\
+		  pushl %eax; pushl %ecx; pushl %edx;			\
+		  call *%cs:paravirt_ops+PARAVIRT_irq_enable;		\
+		  popl %edx; popl %ecx; popl %eax)
 
-#define ENABLE_INTERRUPTS_SYSEXIT			\
-	PARA_PATCH(PARAVIRT_STI_SYSEXIT, CLBR_ANY,	\
-	jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
+#define ENABLE_INTERRUPTS_SYSEXIT					\
+	PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable_sysexit), CLBR_NONE,	\
+		  jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
 
 #define GET_CR0_INTO_EAX			\
-	call *paravirt_ops+PARAVIRT_read_cr0
+	push %ecx; push %edx;			\
+	call *paravirt_ops+PARAVIRT_read_cr0;	\
+	pop %edx; pop %ecx
 
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_PARAVIRT */
diff --git a/include/asm-i386/pda.h b/include/asm-i386/pda.h
deleted file mode 100644
index b12d59a..0000000
--- a/include/asm-i386/pda.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-   Per-processor Data Areas
-   Jeremy Fitzhardinge <jeremy@goop.org> 2006
-   Based on asm-x86_64/pda.h by Andi Kleen.
- */
-#ifndef _I386_PDA_H
-#define _I386_PDA_H
-
-#include <linux/stddef.h>
-#include <linux/types.h>
-
-struct i386_pda
-{
-	struct i386_pda *_pda;		/* pointer to self */
-
-	int cpu_number;
-	struct task_struct *pcurrent;	/* current process */
-	struct pt_regs *irq_regs;
-};
-
-extern struct i386_pda *_cpu_pda[];
-
-#define cpu_pda(i)	(_cpu_pda[i])
-
-#define pda_offset(field) offsetof(struct i386_pda, field)
-
-extern void __bad_pda_field(void);
-
-/* This variable is never instantiated.  It is only used as a stand-in
-   for the real per-cpu PDA memory, so that gcc can understand what
-   memory operations the inline asms() below are performing.  This
-   eliminates the need to make the asms volatile or have memory
-   clobbers, so gcc can readily analyse them. */
-extern struct i386_pda _proxy_pda;
-
-#define pda_to_op(op,field,val)						\
-	do {								\
-		typedef typeof(_proxy_pda.field) T__;			\
-		if (0) { T__ tmp__; tmp__ = (val); }			\
-		switch (sizeof(_proxy_pda.field)) {			\
-		case 1:							\
-			asm(op "b %1,%%fs:%c2"				\
-			    : "+m" (_proxy_pda.field)			\
-			    :"ri" ((T__)val),				\
-			     "i"(pda_offset(field)));			\
-			break;						\
-		case 2:							\
-			asm(op "w %1,%%fs:%c2"				\
-			    : "+m" (_proxy_pda.field)			\
-			    :"ri" ((T__)val),				\
-			     "i"(pda_offset(field)));			\
-			break;						\
-		case 4:							\
-			asm(op "l %1,%%fs:%c2"				\
-			    : "+m" (_proxy_pda.field)			\
-			    :"ri" ((T__)val),				\
-			     "i"(pda_offset(field)));			\
-			break;						\
-		default: __bad_pda_field();				\
-		}							\
-	} while (0)
-
-#define pda_from_op(op,field)						\
-	({								\
-		typeof(_proxy_pda.field) ret__;				\
-		switch (sizeof(_proxy_pda.field)) {			\
-		case 1:							\
-			asm(op "b %%fs:%c1,%0"				\
-			    : "=r" (ret__)				\
-			    : "i" (pda_offset(field)),			\
-			      "m" (_proxy_pda.field));			\
-			break;						\
-		case 2:							\
-			asm(op "w %%fs:%c1,%0"				\
-			    : "=r" (ret__)				\
-			    : "i" (pda_offset(field)),			\
-			      "m" (_proxy_pda.field));			\
-			break;						\
-		case 4:							\
-			asm(op "l %%fs:%c1,%0"				\
-			    : "=r" (ret__)				\
-			    : "i" (pda_offset(field)),			\
-			      "m" (_proxy_pda.field));			\
-			break;						\
-		default: __bad_pda_field();				\
-		}							\
-		ret__; })
-
-/* Return a pointer to a pda field */
-#define pda_addr(field)							\
-	((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
-				      pda_offset(field)))
-
-#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)
-#define sub_pda(field,val) pda_to_op("sub",field,val)
-#define or_pda(field,val) pda_to_op("or",field,val)
-
-#endif	/* _I386_PDA_H */
diff --git a/include/asm-i386/percpu.h b/include/asm-i386/percpu.h
index 510ae1d..f54830b 100644
--- a/include/asm-i386/percpu.h
+++ b/include/asm-i386/percpu.h
@@ -1,9 +1,32 @@
 #ifndef __ARCH_I386_PERCPU__
 #define __ARCH_I386_PERCPU__
 
-#ifndef __ASSEMBLY__
-#include <asm-generic/percpu.h>
-#else
+#ifdef __ASSEMBLY__
+
+/*
+ * PER_CPU finds an address of a per-cpu variable.
+ *
+ * Args:
+ *    var - variable name
+ *    reg - 32bit register
+ *
+ * The resulting address is stored in the "reg" argument.
+ *
+ * Example:
+ *    PER_CPU(cpu_gdt_descr, %ebx)
+ */
+#ifdef CONFIG_SMP
+#define PER_CPU(var, reg)				\
+	movl %fs:per_cpu__##this_cpu_off, reg;		\
+	lea per_cpu__##var(reg), reg
+#define PER_CPU_VAR(var)	%fs:per_cpu__##var
+#else /* ! SMP */
+#define PER_CPU(var, reg)			\
+	movl $per_cpu__##var, reg
+#define PER_CPU_VAR(var)	per_cpu__##var
+#endif	/* SMP */
+
+#else /* ...!ASSEMBLY */
 
 /*
  * PER_CPU finds an address of a per-cpu variable.
@@ -18,14 +41,109 @@ #else
  *    PER_CPU(cpu_gdt_descr, %ebx)
  */
 #ifdef CONFIG_SMP
-#define PER_CPU(var, cpu) \
-	movl __per_cpu_offset(,cpu,4), cpu;	\
-	addl $per_cpu__/**/var, cpu;
-#else /* ! SMP */
-#define PER_CPU(var, cpu) \
-	movl $per_cpu__/**/var, cpu;
+/* Same as generic implementation except for optimized local access. */
+#define __GENERIC_PER_CPU
+
+/* This is used for other cpus to find our section. */
+extern unsigned long __per_cpu_offset[];
+
+#define per_cpu_offset(x) (__per_cpu_offset[x])
+
+/* Separate out the type, so (int[3], foo) works. */
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+/* We can use this directly for local CPU (faster). */
+DECLARE_PER_CPU(unsigned long, this_cpu_off);
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) (*({				\
+	extern int simple_indentifier_##var(void);	\
+	RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
+
+#define __raw_get_cpu_var(var) (*({					\
+	extern int simple_indentifier_##var(void);			\
+	RELOC_HIDE(&per_cpu__##var, x86_read_percpu(this_cpu_off));	\
+}))
+
+#define __get_cpu_var(var) __raw_get_cpu_var(var)
+
+/* A macro to avoid #include hell... */
+#define percpu_modcopy(pcpudst, src, size)			\
+do {								\
+	unsigned int __i;					\
+	for_each_possible_cpu(__i)				\
+		memcpy((pcpudst)+__per_cpu_offset[__i],		\
+		       (src), (size));				\
+} while (0)
+
+#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
+#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
+
+/* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */
+#define __percpu_seg "%%fs:"
+#else  /* !SMP */
+#include <asm-generic/percpu.h>
+#define __percpu_seg ""
 #endif	/* SMP */
 
+/* For arch-specific code, we can use direct single-insn ops (they
+ * don't give an lvalue though). */
+extern void __bad_percpu_size(void);
+
+#define percpu_to_op(op,var,val)				\
+	do {							\
+		typedef typeof(var) T__;			\
+		if (0) { T__ tmp__; tmp__ = (val); }		\
+		switch (sizeof(var)) {				\
+		case 1:						\
+			asm(op "b %1,"__percpu_seg"%0"		\
+			    : "+m" (var)			\
+			    :"ri" ((T__)val));			\
+			break;					\
+		case 2:						\
+			asm(op "w %1,"__percpu_seg"%0"		\
+			    : "+m" (var)			\
+			    :"ri" ((T__)val));			\
+			break;					\
+		case 4:						\
+			asm(op "l %1,"__percpu_seg"%0"		\
+			    : "+m" (var)			\
+			    :"ri" ((T__)val));			\
+			break;					\
+		default: __bad_percpu_size();			\
+		}						\
+	} while (0)
+
+#define percpu_from_op(op,var)					\
+	({							\
+		typeof(var) ret__;				\
+		switch (sizeof(var)) {				\
+		case 1:						\
+			asm(op "b "__percpu_seg"%1,%0"		\
+			    : "=r" (ret__)			\
+			    : "m" (var));			\
+			break;					\
+		case 2:						\
+			asm(op "w "__percpu_seg"%1,%0"		\
+			    : "=r" (ret__)			\
+			    : "m" (var));			\
+			break;					\
+		case 4:						\
+			asm(op "l "__percpu_seg"%1,%0"		\
+			    : "=r" (ret__)			\
+			    : "m" (var));			\
+			break;					\
+		default: __bad_percpu_size();			\
+		}						\
+		ret__; })
+
+#define x86_read_percpu(var) percpu_from_op("mov", per_cpu__##var)
+#define x86_write_percpu(var,val) percpu_to_op("mov", per_cpu__##var, val)
+#define x86_add_percpu(var,val) percpu_to_op("add", per_cpu__##var, val)
+#define x86_sub_percpu(var,val) percpu_to_op("sub", per_cpu__##var, val)
+#define x86_or_percpu(var,val) percpu_to_op("or", per_cpu__##var, val)
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ARCH_I386_PERCPU__ */
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
index c8dc2d0..4743017 100644
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -1,7 +1,6 @@
 #ifndef _I386_PGALLOC_H
 #define _I386_PGALLOC_H
 
-#include <asm/fixmap.h>
 #include <linux/threads.h>
 #include <linux/mm.h>		/* for struct page */
 
diff --git a/include/asm-i386/pgtable-2level-defs.h b/include/asm-i386/pgtable-2level-defs.h
index 0251807..0f71c9f 100644
--- a/include/asm-i386/pgtable-2level-defs.h
+++ b/include/asm-i386/pgtable-2level-defs.h
@@ -1,6 +1,8 @@
 #ifndef _I386_PGTABLE_2LEVEL_DEFS_H
 #define _I386_PGTABLE_2LEVEL_DEFS_H
 
+#define SHARED_KERNEL_PMD	0
+
 /*
  * traditional i386 two-level paging structure:
  */
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
index 38c3fcc..a50fd17 100644
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -11,10 +11,23 @@ #define pgd_ERROR(e) \
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
  */
+static inline void native_set_pte(pte_t *ptep , pte_t pte)
+{
+	*ptep = pte;
+}
+static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
+				     pte_t *ptep , pte_t pte)
+{
+	native_set_pte(ptep, pte);
+}
+static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+	*pmdp = pmd;
+}
 #ifndef CONFIG_PARAVIRT
-#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#define set_pte(pteptr, pteval)		native_set_pte(pteptr, pteval)
+#define set_pte_at(mm,addr,ptep,pteval) native_set_pte_at(mm, addr, ptep, pteval)
+#define set_pmd(pmdptr, pmdval)		native_set_pmd(pmdptr, pmdval)
 #endif
 
 #define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
@@ -23,11 +36,23 @@ #define set_pte_present(mm,addr,ptep,pte
 #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 raw_ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte_low, 0))
+static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *xp)
+{
+	*xp = __pte(0);
+}
+
+#ifdef CONFIG_SMP
+static inline pte_t native_ptep_get_and_clear(pte_t *xp)
+{
+	return __pte(xchg(&xp->pte_low, 0));
+}
+#else
+#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
+#endif
 
 #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)))
+#define pte_pfn(x)		(pte_val(x) >> 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))
 
@@ -66,6 +91,4 @@ #define __swp_entry(type, offset)	((swp_
 #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 --git a/include/asm-i386/pgtable-3level-defs.h b/include/asm-i386/pgtable-3level-defs.h
index eb3a1ea..c0df89f 100644
--- a/include/asm-i386/pgtable-3level-defs.h
+++ b/include/asm-i386/pgtable-3level-defs.h
@@ -1,6 +1,12 @@
 #ifndef _I386_PGTABLE_3LEVEL_DEFS_H
 #define _I386_PGTABLE_3LEVEL_DEFS_H
 
+#ifdef CONFIG_PARAVIRT
+#define SHARED_KERNEL_PMD	(paravirt_ops.shared_kernel_pmd)
+#else
+#define SHARED_KERNEL_PMD	1
+#endif
+
 /*
  * PGDIR_SHIFT determines what a top-level page table entry can map
  */
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index 7a2318f..eb0f1d7 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -42,20 +42,23 @@ static inline int pte_exec_kernel(pte_t 
 	return pte_x(pte);
 }
 
-#ifndef CONFIG_PARAVIRT
 /* 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
  */
-static inline void set_pte(pte_t *ptep, pte_t pte)
+static inline void native_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_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
+				     pte_t *ptep , pte_t pte)
+{
+	native_set_pte(ptep, pte);
+}
 
 /*
  * Since this is only called on user PTEs, and the page fault handler
@@ -63,7 +66,8 @@ #define set_pte_at(mm,addr,ptep,pteval) 
  * 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)
+static inline void native_set_pte_present(struct mm_struct *mm, unsigned long addr,
+					  pte_t *ptep, pte_t pte)
 {
 	ptep->pte_low = 0;
 	smp_wmb();
@@ -72,32 +76,48 @@ static inline void set_pte_present(struc
 	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) \
-		set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
-#define set_pud(pudptr,pudval) \
-		(*(pudptr) = (pudval))
+static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+	set_64bit((unsigned long long *)(ptep),native_pte_val(pte));
+}
+static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+	set_64bit((unsigned long long *)(pmdp),native_pmd_val(pmd));
+}
+static inline void native_set_pud(pud_t *pudp, pud_t pud)
+{
+	*pudp = pud;
+}
 
 /*
  * 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)
+static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	ptep->pte_low = 0;
 	smp_wmb();
 	ptep->pte_high = 0;
 }
 
-static inline void pmd_clear(pmd_t *pmd)
+static inline void native_pmd_clear(pmd_t *pmd)
 {
 	u32 *tmp = (u32 *)pmd;
 	*tmp = 0;
 	smp_wmb();
 	*(tmp + 1) = 0;
 }
+
+#ifndef CONFIG_PARAVIRT
+#define set_pte(ptep, pte)			native_set_pte(ptep, pte)
+#define set_pte_at(mm, addr, ptep, pte)		native_set_pte_at(mm, addr, ptep, pte)
+#define set_pte_present(mm, addr, ptep, pte)	native_set_pte_present(mm, addr, ptep, pte)
+#define set_pte_atomic(ptep, pte)		native_set_pte_atomic(ptep, pte)
+#define set_pmd(pmdp, pmd)			native_set_pmd(pmdp, pmd)
+#define set_pud(pudp, pud)			native_set_pud(pudp, pud)
+#define pte_clear(mm, addr, ptep)		native_pte_clear(mm, addr, ptep)
+#define pmd_clear(pmd)				native_pmd_clear(pmd)
 #endif
 
 /*
@@ -119,7 +139,8 @@ ((unsigned long) __va(pud_val(pud) & PAG
 #define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
 			pmd_index(address))
 
-static inline pte_t raw_ptep_get_and_clear(pte_t *ptep)
+#ifdef CONFIG_SMP
+static inline pte_t native_ptep_get_and_clear(pte_t *ptep)
 {
 	pte_t res;
 
@@ -130,6 +151,9 @@ static inline pte_t raw_ptep_get_and_cle
 
 	return res;
 }
+#else
+#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
+#endif
 
 #define __HAVE_ARCH_PTE_SAME
 static inline int pte_same(pte_t a, pte_t b)
@@ -146,28 +170,21 @@ static inline int pte_none(pte_t pte)
 
 static inline unsigned long pte_pfn(pte_t pte)
 {
-	return (pte.pte_low >> PAGE_SHIFT) |
-		(pte.pte_high << (32 - PAGE_SHIFT));
+	return pte_val(pte) >> PAGE_SHIFT;
 }
 
 extern unsigned long long __supported_pte_mask;
 
 static inline pte_t pfn_pte(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;
+	return __pte((((unsigned long long)page_nr << PAGE_SHIFT) |
+		      pgprot_val(pgprot)) & __supported_pte_mask);
 }
 
 static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
 {
-	return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \
-			pgprot_val(pgprot)) & __supported_pte_mask);
+	return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) |
+		      pgprot_val(pgprot)) & __supported_pte_mask);
 }
 
 /*
@@ -187,6 +204,4 @@ #define __swp_entry_to_pte(x)		((pte_t){
 
 #define __pmd_free_tlb(tlb, x)		do { } while (0)
 
-#define vmalloc_sync_all() ((void)0)
-
 #endif /* _I386_PGTABLE_3LEVEL_H */
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index c3b58d4..edce9d5 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -159,6 +159,7 @@ #define _PAGE_KERNEL_EXEC \
 
 extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
 #define __PAGE_KERNEL_RO		(__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_RX		(__PAGE_KERNEL_EXEC & ~_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)
@@ -166,6 +167,7 @@ #define __PAGE_KERNEL_LARGE_EXEC	(__PAGE
 #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_RX		__pgprot(__PAGE_KERNEL_RX)
 #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)
@@ -263,9 +265,18 @@ #ifndef CONFIG_PARAVIRT
  */
 #define pte_update(mm, addr, ptep)		do { } while (0)
 #define pte_update_defer(mm, addr, ptep)	do { } while (0)
-#define paravirt_map_pt_hook(slot, va, pfn)	do { } while (0)
 #endif
 
+/* local pte updates need not use xchg for locking */
+static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
+{
+	pte_t res = *ptep;
+
+	/* Pure native function needs no input for mm, addr */
+	native_pte_clear(NULL, 0, ptep);
+	return res;
+}
+
 /*
  * We only update the dirty/accessed state if we set
  * the dirty bit by hand in the kernel, since the hardware
@@ -283,12 +294,25 @@ do {									\
 	}								\
 } 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 ptep_test_and_clear_dirty(vma, addr, ptep) ({			\
+	int ret = 0;							\
+	if (pte_dirty(*ptep))						\
+		ret = test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); \
+	if (ret)							\
+		pte_update_defer(vma->vm_mm, addr, ptep);		\
+	ret;								\
+})
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(vma, addr, ptep) ({			\
+	int ret = 0;							\
+	if (pte_young(*ptep))						\
+		ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); \
+	if (ret)							\
+		pte_update_defer(vma->vm_mm, addr, ptep);		\
+	ret;								\
+})
 
 /*
  * Rules for using ptep_establish: the pte MUST be a user pte, and
@@ -305,12 +329,9 @@ #define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLU
 #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, (address), (ptep));	\
+	__dirty = ptep_test_and_clear_dirty((vma), (address), (ptep));	\
+	if (__dirty)							\
 		flush_tlb_page(vma, address);				\
-	}								\
 	__dirty;							\
 })
 
@@ -318,19 +339,16 @@ #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLU
 #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, (address), (ptep));	\
+	__young = ptep_test_and_clear_young((vma), (address), (ptep));	\
+	if (__young)							\
 		flush_tlb_page(vma, address);				\
-	}								\
 	__young;							\
 })
 
 #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 pte = raw_ptep_get_and_clear(ptep);
+	pte_t pte = native_ptep_get_and_clear(ptep);
 	pte_update(mm, addr, ptep);
 	return pte;
 }
@@ -340,8 +358,11 @@ static inline pte_t ptep_get_and_clear_f
 {
 	pte_t pte;
 	if (full) {
-		pte = *ptep;
-		pte_clear(mm, addr, ptep);
+		/*
+		 * Full address destruction in progress; paravirt does not
+		 * care about updates and native needs no locking
+		 */
+		pte = native_local_ptep_get_and_clear(ptep);
 	} else {
 		pte = ptep_get_and_clear(mm, addr, ptep);
 	}
@@ -470,24 +491,10 @@ #else
 #endif
 
 #if defined(CONFIG_HIGHPTE)
-#define pte_offset_map(dir, address)				\
-({								\
-	pte_t *__ptep;						\
-	unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT;	   	\
-	__ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE0);\
-	paravirt_map_pt_hook(KM_PTE0,__ptep, pfn);		\
-	__ptep = __ptep + pte_index(address);			\
-	__ptep;							\
-})
-#define pte_offset_map_nested(dir, address)			\
-({								\
-	pte_t *__ptep;						\
-	unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT;	   	\
-	__ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE1);\
-	paravirt_map_pt_hook(KM_PTE1,__ptep, pfn);		\
-	__ptep = __ptep + pte_index(address);			\
-	__ptep;							\
-})
+#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
@@ -510,6 +517,22 @@ do {									\
  * tables contain all the necessary information.
  */
 #define update_mmu_cache(vma,address,pte) do { } while (0)
+
+void native_pagetable_setup_start(pgd_t *base);
+void native_pagetable_setup_done(pgd_t *base);
+
+#ifndef CONFIG_PARAVIRT
+static inline void paravirt_pagetable_setup_start(pgd_t *base)
+{
+	native_pagetable_setup_start(base);
+}
+
+static inline void paravirt_pagetable_setup_done(pgd_t *base)
+{
+	native_pagetable_setup_done(base);
+}
+#endif	/* !CONFIG_PARAVIRT */
+
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_FLATMEM
@@ -519,10 +542,6 @@ #endif /* CONFIG_FLATMEM */
 #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)
-
 #include <asm-generic/pgtable.h>
 
 #endif /* _I386_PGTABLE_H */
diff --git a/include/asm-i386/processor-flags.h b/include/asm-i386/processor-flags.h
new file mode 100644
index 0000000..5404e90
--- /dev/null
+++ b/include/asm-i386/processor-flags.h
@@ -0,0 +1,91 @@
+#ifndef __ASM_I386_PROCESSOR_FLAGS_H
+#define __ASM_I386_PROCESSOR_FLAGS_H
+/* Various flags defined: can be included from assembler. */
+
+/*
+ * 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 */
+
+/*
+ * Basic CPU control in CR0
+ */
+#define X86_CR0_PE	0x00000001 /* Protection Enable */
+#define X86_CR0_MP	0x00000002 /* Monitor Coprocessor */
+#define X86_CR0_EM	0x00000004 /* Emulation */
+#define X86_CR0_TS	0x00000008 /* Task Switched */
+#define X86_CR0_ET	0x00000010 /* Extension Type */
+#define X86_CR0_NE	0x00000020 /* Numeric Error */
+#define X86_CR0_WP	0x00010000 /* Write Protect */
+#define X86_CR0_AM	0x00040000 /* Alignment Mask */
+#define X86_CR0_NW	0x20000000 /* Not Write-through */
+#define X86_CR0_CD	0x40000000 /* Cache Disable */
+#define X86_CR0_PG	0x80000000 /* Paging */
+
+/*
+ * Paging options in CR3
+ */
+#define X86_CR3_PWT	0x00000008 /* Page Write Through */
+#define X86_CR3_PCD	0x00000010 /* Page Cache Disable */
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME	0x00000001 /* enable vm86 extensions */
+#define X86_CR4_PVI	0x00000002 /* virtual interrupts flag enable */
+#define X86_CR4_TSD	0x00000004 /* disable time stamp at ipl 3 */
+#define X86_CR4_DE	0x00000008 /* enable debugging extensions */
+#define X86_CR4_PSE	0x00000010 /* enable page size extensions */
+#define X86_CR4_PAE	0x00000020 /* enable physical address extensions */
+#define X86_CR4_MCE	0x00000040 /* Machine check enable */
+#define X86_CR4_PGE	0x00000080 /* enable global pages */
+#define X86_CR4_PCE	0x00000100 /* enable performance counters at ipl 3 */
+#define X86_CR4_OSFXSR	0x00000200 /* enable fast FPU save and restore */
+#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
+#define X86_CR4_VMXE	0x00002000 /* enable VMX virtualization */
+
+/*
+ * x86-64 Task Priority Register, CR8
+ */
+#define X86_CR8_TPR	0x00000007 /* task priority register */
+
+/*
+ * AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h>
+ */
+
+/*
+ *      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
+
+#endif	/* __ASM_I386_PROCESSOR_FLAGS_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 11bf899..70f3515 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -21,6 +21,7 @@ #include <linux/threads.h>
 #include <asm/percpu.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
+#include <asm/processor-flags.h>
 
 /* flag for disabling the tsc */
 extern int tsc_disable;
@@ -115,7 +116,8 @@ extern char ignore_fpu_irq;
 
 void __init cpu_detect(struct cpuinfo_x86 *c);
 
-extern void identify_cpu(struct cpuinfo_x86 *);
+extern void identify_boot_cpu(void);
+extern void identify_secondary_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;
@@ -126,28 +128,7 @@ #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 */
-
-static inline fastcall void native_cpuid(unsigned int *eax, unsigned int *ebx,
+static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
 					 unsigned int *ecx, unsigned int *edx)
 {
 	/* ecx is often an input as well as an output. */
@@ -162,21 +143,6 @@ static inline fastcall void native_cpuid
 #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
@@ -203,26 +169,6 @@ static inline void clear_in_cr4 (unsigne
 }
 
 /*
- *      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
  */
 
@@ -345,7 +291,8 @@ typedef struct {
 
 struct thread_struct;
 
-struct tss_struct {
+/* This is the TSS defined by the hardware. */
+struct i386_hw_tss {
 	unsigned short	back_link,__blh;
 	unsigned long	esp0;
 	unsigned short	ss0,__ss0h;
@@ -369,6 +316,11 @@ struct tss_struct {
 	unsigned short	gs, __gsh;
 	unsigned short	ldt, __ldth;
 	unsigned short	trace, io_bitmap_base;
+} __attribute__((packed));
+
+struct tss_struct {
+	struct i386_hw_tss x86_tss;
+
 	/*
 	 * The extra 1 is there because the CPU will access an
 	 * additional byte beyond the end of the IO permission
@@ -421,10 +373,11 @@ struct thread_struct {
 };
 
 #define INIT_THREAD  {							\
+	.esp0 = sizeof(init_stack) + (long)&init_stack,			\
 	.vm86_info = NULL,						\
 	.sysenter_cs = __KERNEL_CS,					\
 	.io_bitmap_ptr = NULL,						\
-	.fs = __KERNEL_PDA,						\
+	.fs = __KERNEL_PERCPU,						\
 }
 
 /*
@@ -434,10 +387,12 @@ #define INIT_THREAD  {							\
  * 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,			\
+	.x86_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 },		\
 }
 
@@ -544,40 +499,70 @@ static inline void rep_nop(void)
 
 #define cpu_relax()	rep_nop()
 
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define paravirt_enabled() 0
-#define __cpuid native_cpuid
-
-static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+static inline void native_load_esp0(struct tss_struct *tss, struct thread_struct *thread)
 {
-	tss->esp0 = thread->esp0;
+	tss->x86_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;
+	if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
+		tss->x86_tss.ss1 = thread->sysenter_cs;
 		wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
 	}
 }
 
-/*
- * These special macros can be used to get or set a debugging register
- */
-#define get_debugreg(var, register)				\
-		__asm__("movl %%db" #register ", %0"		\
-			:"=r" (var))
-#define set_debugreg(value, register)			\
-		__asm__("movl %0,%%db" #register		\
-			: /* no output */			\
-			:"r" (value))
 
-#define set_iopl_mask native_set_iopl_mask
-#endif /* CONFIG_PARAVIRT */
+static inline unsigned long native_get_debugreg(int regno)
+{
+	unsigned long val = 0; 	/* Damn you, gcc! */
+
+	switch (regno) {
+	case 0:
+		asm("movl %%db0, %0" :"=r" (val)); break;
+	case 1:
+		asm("movl %%db1, %0" :"=r" (val)); break;
+	case 2:
+		asm("movl %%db2, %0" :"=r" (val)); break;
+	case 3:
+		asm("movl %%db3, %0" :"=r" (val)); break;
+	case 6:
+		asm("movl %%db6, %0" :"=r" (val)); break;
+	case 7:
+		asm("movl %%db7, %0" :"=r" (val)); break;
+	default:
+		BUG();
+	}
+	return val;
+}
+
+static inline void native_set_debugreg(int regno, unsigned long value)
+{
+	switch (regno) {
+	case 0:
+		asm("movl %0,%%db0"	: /* no output */ :"r" (value));
+		break;
+	case 1:
+		asm("movl %0,%%db1"	: /* no output */ :"r" (value));
+		break;
+	case 2:
+		asm("movl %0,%%db2"	: /* no output */ :"r" (value));
+		break;
+	case 3:
+		asm("movl %0,%%db3"	: /* no output */ :"r" (value));
+		break;
+	case 6:
+		asm("movl %0,%%db6"	: /* no output */ :"r" (value));
+		break;
+	case 7:
+		asm("movl %0,%%db7"	: /* no output */ :"r" (value));
+		break;
+	default:
+		BUG();
+	}
+}
 
 /*
  * Set IOPL bits in EFLAGS from given mask
  */
-static fastcall inline void native_set_iopl_mask(unsigned mask)
+static inline void native_set_iopl_mask(unsigned mask)
 {
 	unsigned int reg;
 	__asm__ __volatile__ ("pushfl;"
@@ -590,6 +575,28 @@ static fastcall inline void native_set_i
 				: "i" (~X86_EFLAGS_IOPL), "r" (mask));
 }
 
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define paravirt_enabled() 0
+#define __cpuid native_cpuid
+
+static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+{
+	native_load_esp0(tss, thread);
+}
+
+/*
+ * These special macros can be used to get or set a debugging register
+ */
+#define get_debugreg(var, register)				\
+	(var) = native_get_debugreg(register)
+#define set_debugreg(value, register)				\
+	native_set_debugreg(register, value)
+
+#define set_iopl_mask native_set_iopl_mask
+#endif /* CONFIG_PARAVIRT */
+
 /*
  * Generic CPUID function
  * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
@@ -742,8 +749,10 @@ extern unsigned long boot_option_idle_ov
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
 
-extern int init_gdt(int cpu, struct task_struct *idle);
 extern void cpu_set_gdt(int);
-extern void secondary_cpu_init(void);
+extern void switch_to_new_gdt(void);
+extern void cpu_init(void);
+
+extern int force_mwait;
 
 #endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/reboot.h b/include/asm-i386/reboot.h
new file mode 100644
index 0000000..e9e3ffc
--- /dev/null
+++ b/include/asm-i386/reboot.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_REBOOT_H
+#define _ASM_REBOOT_H
+
+struct pt_regs;
+
+struct machine_ops
+{
+	void (*restart)(char *cmd);
+	void (*halt)(void);
+	void (*power_off)(void);
+	void (*shutdown)(void);
+	void (*crash_shutdown)(struct pt_regs *);
+	void (*emergency_restart)(void);
+};
+
+extern struct machine_ops machine_ops;
+
+void machine_real_restart(unsigned char *code, int length);
+
+#endif	/* _ASM_REBOOT_H */
diff --git a/include/asm-i386/reboot_fixups.h b/include/asm-i386/reboot_fixups.h
new file mode 100644
index 0000000..0cb7d87
--- /dev/null
+++ b/include/asm-i386/reboot_fixups.h
@@ -0,0 +1,6 @@
+#ifndef _LINUX_REBOOT_FIXUPS_H
+#define _LINUX_REBOOT_FIXUPS_H
+
+extern void mach_reboot_fixups(void);
+
+#endif /* _LINUX_REBOOT_FIXUPS_H */
diff --git a/include/asm-i386/required-features.h b/include/asm-i386/required-features.h
new file mode 100644
index 0000000..9db866c
--- /dev/null
+++ b/include/asm-i386/required-features.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_REQUIRED_FEATURES_H
+#define _ASM_REQUIRED_FEATURES_H 1
+
+/* Define minimum CPUID feature set for kernel These bits are checked
+   really early to actually display a visible error message before the
+   kernel dies.  Only add word 0 bits here
+
+   Some requirements that are not in CPUID yet are also in the
+   CONFIG_X86_MINIMUM_CPU mode which is checked too.
+
+   The real information is in arch/i386/Kconfig.cpu, this just converts
+   the CONFIGs into a bitmask */
+
+#ifdef CONFIG_X86_PAE
+#define NEED_PAE	(1<<X86_FEATURE_PAE)
+#else
+#define NEED_PAE	0
+#endif
+
+#ifdef CONFIG_X86_CMOV
+#define NEED_CMOV	(1<<X86_FEATURE_CMOV)
+#else
+#define NEED_CMOV	0
+#endif
+
+#ifdef CONFIG_X86_CMPXCHG64
+#define NEED_CMPXCHG64  (1<<X86_FEATURE_CX8)
+#else
+#define NEED_CMPXCHG64  0
+#endif
+
+#define REQUIRED_MASK1	(NEED_PAE|NEED_CMOV|NEED_CMPXCHG64)
+
+#endif
diff --git a/include/asm-i386/scatterlist.h b/include/asm-i386/scatterlist.h
index 55d6c95..d7e45a8 100644
--- a/include/asm-i386/scatterlist.h
+++ b/include/asm-i386/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _I386_SCATTERLIST_H
 #define _I386_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-i386/segment.h b/include/asm-i386/segment.h
index 065f10b..597a47c 100644
--- a/include/asm-i386/segment.h
+++ b/include/asm-i386/segment.h
@@ -39,7 +39,7 @@ #define _ASM_SEGMENT_H
  *  25 - APM BIOS support 
  *
  *  26 - ESPFIX small SS
- *  27 - PDA				[ per-cpu private data area ]
+ *  27 - per-cpu			[ offset to per-cpu data area ]
  *  28 - unused
  *  29 - unused
  *  30 - unused
@@ -74,8 +74,12 @@ #define GDT_ENTRY_APMBIOS_BASE		(GDT_ENT
 #define GDT_ENTRY_ESPFIX_SS		(GDT_ENTRY_KERNEL_BASE + 14)
 #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
 
-#define GDT_ENTRY_PDA			(GDT_ENTRY_KERNEL_BASE + 15)
-#define __KERNEL_PDA (GDT_ENTRY_PDA * 8)
+#define GDT_ENTRY_PERCPU			(GDT_ENTRY_KERNEL_BASE + 15)
+#ifdef CONFIG_SMP
+#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
+#else
+#define __KERNEL_PERCPU 0
+#endif
 
 #define GDT_ENTRY_DOUBLEFAULT_TSS	31
 
diff --git a/include/asm-i386/serial.h b/include/asm-i386/serial.h
index bd67480..57a4306 100644
--- a/include/asm-i386/serial.h
+++ b/include/asm-i386/serial.h
@@ -11,19 +11,3 @@
  * megabits/second; but this requires the faster clock.
  */
 #define BASE_BAUD ( 1843200 / 16 )
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#define SERIAL_PORT_DFNS			\
-	/* 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 */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 6bf0033..090abc1 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -8,19 +8,15 @@ #ifndef __ASSEMBLY__
 #include <linux/kernel.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
-#include <asm/pda.h>
 #endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
-#ifndef __ASSEMBLY__
-#include <asm/fixmap.h>
+#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__)
 #include <asm/bitops.h>
 #include <asm/mpspec.h>
+#include <asm/apic.h>
 #ifdef CONFIG_X86_IO_APIC
 #include <asm/io_apic.h>
 #endif
-#include <asm/apic.h>
-#endif
 #endif
 
 #define BAD_APICID 0xFFu
@@ -52,6 +48,59 @@ extern void cpu_exit_clear(void);
 extern void cpu_uninit(void);
 #endif
 
+struct smp_ops
+{
+	void (*smp_prepare_boot_cpu)(void);
+	void (*smp_prepare_cpus)(unsigned max_cpus);
+	int (*cpu_up)(unsigned cpu);
+	void (*smp_cpus_done)(unsigned max_cpus);
+
+	void (*smp_send_stop)(void);
+	void (*smp_send_reschedule)(int cpu);
+	int (*smp_call_function_mask)(cpumask_t mask,
+				      void (*func)(void *info), void *info,
+				      int wait);
+};
+
+extern struct smp_ops smp_ops;
+
+static inline void smp_prepare_boot_cpu(void)
+{
+	smp_ops.smp_prepare_boot_cpu();
+}
+static inline void smp_prepare_cpus(unsigned int max_cpus)
+{
+	smp_ops.smp_prepare_cpus(max_cpus);
+}
+static inline int __cpu_up(unsigned int cpu)
+{
+	return smp_ops.cpu_up(cpu);
+}
+static inline void smp_cpus_done(unsigned int max_cpus)
+{
+	smp_ops.smp_cpus_done(max_cpus);
+}
+
+static inline void smp_send_stop(void)
+{
+	smp_ops.smp_send_stop();
+}
+static inline void smp_send_reschedule(int cpu)
+{
+	smp_ops.smp_send_reschedule(cpu);
+}
+static inline int smp_call_function_mask(cpumask_t mask,
+					 void (*func) (void *info), void *info,
+					 int wait)
+{
+	return smp_ops.smp_call_function_mask(mask, func, info, wait);
+}
+
+void native_smp_prepare_boot_cpu(void);
+void native_smp_prepare_cpus(unsigned int max_cpus);
+int native_cpu_up(unsigned int cpunum);
+void native_smp_cpus_done(unsigned int max_cpus);
+
 #ifndef CONFIG_PARAVIRT
 #define startup_ipi_hook(phys_apicid, start_eip, start_esp) 		\
 do { } while (0)
@@ -62,7 +111,8 @@ #endif
  * 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() (read_pda(cpu_number))
+DECLARE_PER_CPU(int, cpu_number);
+#define raw_smp_processor_id() (x86_read_percpu(cpu_number))
 
 extern cpumask_t cpu_callout_map;
 extern cpumask_t cpu_callin_map;
diff --git a/include/asm-i386/socket.h b/include/asm-i386/socket.h
index 5755d57..99ca648 100644
--- a/include/asm-i386/socket.h
+++ b/include/asm-i386/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-i386/sockios.h b/include/asm-i386/sockios.h
index 6b747f8..ff528c7 100644
--- a/include/asm-i386/sockios.h
+++ b/include/asm-i386/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index a6d20d9..94ed368 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -4,7 +4,7 @@ #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/cmpxchg.h>
 
 #ifdef __KERNEL__
 
@@ -88,314 +88,113 @@ #define loadsegment(seg,value)			\
 #define savesegment(seg, value) \
 	asm volatile("mov %%" #seg ",%0":"=rm" (value))
 
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#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() ({ \
-	unsigned int __dummy; \
-	__asm__ __volatile__( \
-		"movl %%cr2,%0\n\t" \
-		:"=r" (__dummy)); \
-	__dummy; \
-})
-#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; \
-})
-#define write_cr3(x) \
-	__asm__ __volatile__("movl %0,%%cr3": :"r" (x))
-
-#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))
-
-#define wbinvd() \
-	__asm__ __volatile__ ("wbinvd": : :"memory")
-
-/* Clear the 'TS' bit */
-#define clts() __asm__ __volatile__ ("clts")
-#endif/* CONFIG_PARAVIRT */
-
-/* Set the 'TS' bit */
-#define stts() write_cr0(8 | read_cr0())
-
-#endif	/* __KERNEL__ */
 
-static inline unsigned long get_limit(unsigned long segment)
+static inline void native_clts(void)
 {
-	unsigned long __limit;
-	__asm__("lsll %1,%0"
-		:"=r" (__limit):"r" (segment));
-	return __limit+1;
+	asm volatile ("clts");
 }
 
-#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)
+static inline unsigned long native_read_cr0(void)
 {
-	__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");
+	unsigned long val;
+	asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
+	return val;
 }
 
-static inline void __set_64bit_constant (unsigned long long *ptr,
-						 unsigned long long value)
+static inline void native_write_cr0(unsigned long val)
 {
-	__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
+	asm volatile("movl %0,%%cr0": :"r" (val));
 }
-#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)
+static inline unsigned long native_read_cr2(void)
 {
-	__set_64bit(ptr,ll_low(value), ll_high(value));
+	unsigned long val;
+	asm volatile("movl %%cr2,%0\n\t" :"=r" (val));
+	return val;
 }
 
-#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)) )
+static inline void native_write_cr2(unsigned long val)
+{
+	asm volatile("movl %0,%%cr2": :"r" (val));
+}
 
-#endif
+static inline unsigned long native_read_cr3(void)
+{
+	unsigned long val;
+	asm volatile("movl %%cr3,%0\n\t" :"=r" (val));
+	return val;
+}
 
-/*
- * 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)
+static inline void native_write_cr3(unsigned long val)
 {
-	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;
+	asm volatile("movl %0,%%cr3": :"r" (val));
 }
 
-/*
- * 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.
- */
+static inline unsigned long native_read_cr4(void)
+{
+	unsigned long val;
+	asm volatile("movl %%cr4,%0\n\t" :"=r" (val));
+	return val;
+}
 
-#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))))
-#define sync_cmpxchg(ptr,o,n)\
-	((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
-					(unsigned long)(n),sizeof(*(ptr))))
-#endif
+static inline unsigned long native_read_cr4_safe(void)
+{
+	unsigned long val;
+	/* 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" (val): "0" (0));
+	return val;
+}
 
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-				      unsigned long new, int size)
+static inline void native_write_cr4(unsigned long val)
 {
-	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;
+	asm volatile("movl %0,%%cr4": :"r" (val));
 }
 
-/*
- * 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)
+static inline void native_wbinvd(void)
 {
-	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;
+	asm volatile("wbinvd": : :"memory");
 }
 
-#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);
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define read_cr0()	(native_read_cr0())
+#define write_cr0(x)	(native_write_cr0(x))
+#define read_cr2()	(native_read_cr2())
+#define write_cr2(x)	(native_write_cr2(x))
+#define read_cr3()	(native_read_cr3())
+#define write_cr3(x)	(native_write_cr3(x))
+#define read_cr4()	(native_read_cr4())
+#define read_cr4_safe()	(native_read_cr4_safe())
+#define write_cr4(x)	(native_write_cr4(x))
+#define wbinvd()	(native_wbinvd())
+
+/* Clear the 'TS' bit */
+#define clts()		(native_clts())
 
-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;
-}
+#endif/* CONFIG_PARAVIRT */
 
-#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
+/* Set the 'TS' bit */
+#define stts() write_cr0(8 | read_cr0())
 
-#ifdef CONFIG_X86_CMPXCHG64
+#endif	/* __KERNEL__ */
 
-static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
-				      unsigned long long new)
+static inline unsigned long get_limit(unsigned long segment)
 {
-	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;
+	unsigned long __limit;
+	__asm__("lsll %1,%0"
+		:"=r" (__limit):"r" (segment));
+	return __limit+1;
 }
 
-#define cmpxchg64(ptr,o,n)\
-	((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
-					(unsigned long long)(n)))
+#define nop() __asm__ __volatile__ ("nop")
 
-#endif
-    
 /*
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
diff --git a/include/asm-i386/termbits.h b/include/asm-i386/termbits.h
index 2e62376..a217003 100644
--- a/include/asm-i386/termbits.h
+++ b/include/asm-i386/termbits.h
@@ -17,6 +17,17 @@ struct termios {
 	cc_t c_cc[NCCS];		/* control characters */
 };
 
+struct termios2 {
+	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 */
+	speed_t c_ispeed;		/* input speed */
+	speed_t c_ospeed;		/* output speed */
+};
+
 struct ktermios {
 	tcflag_t c_iflag;		/* input mode flags */
 	tcflag_t c_oflag;		/* output mode flags */
@@ -129,6 +140,7 @@ #define PARODD	0001000
 #define HUPCL	0002000
 #define CLOCAL	0004000
 #define CBAUDEX 0010000
+#define   BOTHER  0010000
 #define    B57600 0010001
 #define   B115200 0010002
 #define   B230400 0010003
@@ -148,6 +160,8 @@ #define CIBAUD	  002003600000
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 
+#define IBSHIFT	  16		/* Shift from CBAUD to CIBAUD */
+
 /* c_lflag bits */
 #define ISIG	0000001
 #define ICANON	0000002
diff --git a/include/asm-i386/termios.h b/include/asm-i386/termios.h
index 7c99678..f520b7c 100644
--- a/include/asm-i386/termios.h
+++ b/include/asm-i386/termios.h
@@ -81,8 +81,10 @@ ({ \
 	copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
 })
 
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
 
 #endif	/* __KERNEL__ */
 
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 4b187bb..bf01d4b 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -95,12 +95,14 @@ static inline struct thread_info *curren
 
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) kzalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+	__get_free_pages(GFP_KERNEL| __GFP_ZERO, get_order(THREAD_SIZE)))
 #else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+	__get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)))
 #endif
 
-#define free_thread_info(info)	kfree(info)
+#define free_thread_info(info)	free_pages((unsigned long)(info), get_order(THREAD_SIZE))
 
 #else /* !__ASSEMBLY__ */
 
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index 12dd67b..153770e 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -9,8 +9,6 @@ void setup_pit_timer(void);
 unsigned long long native_sched_clock(void);
 unsigned long native_calculate_cpu_khz(void);
 
-/* Modifiers for buggy PIT handling */
-extern int pit_latch_buggy;
 extern int timer_ack;
 extern int no_timer_check;
 extern int no_sync_cmos_clock;
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index 4dd8284..db7f77e 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -79,11 +79,15 @@ #endif
  *  - 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
+ *  - flush_tlb_others(cpumask, mm, va) flushes a TLBs on other cpus
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
  * and page-granular flushes are available only on i486 and up.
  */
 
+#define TLB_FLUSH_ALL	0xffffffff
+
+
 #ifndef CONFIG_SMP
 
 #define flush_tlb() __flush_tlb()
@@ -110,7 +114,12 @@ static inline void flush_tlb_range(struc
 		__flush_tlb();
 }
 
-#else
+static inline void native_flush_tlb_others(const cpumask_t *cpumask,
+					   struct mm_struct *mm, unsigned long va)
+{
+}
+
+#else  /* SMP */
 
 #include <asm/smp.h>
 
@@ -129,6 +138,9 @@ static inline void flush_tlb_range(struc
 	flush_tlb_mm(vma->vm_mm);
 }
 
+void native_flush_tlb_others(const cpumask_t *cpumask, struct mm_struct *mm,
+			     unsigned long va);
+
 #define TLBSTATE_OK	1
 #define TLBSTATE_LAZY	2
 
@@ -139,8 +151,11 @@ struct tlb_state
 	char __cacheline_padding[L1_CACHE_BYTES-8];
 };
 DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+#endif	/* SMP */
 
-
+#ifndef CONFIG_PARAVIRT
+#define flush_tlb_others(mask, mm, va)		\
+	native_flush_tlb_others(&mask, mm, va)
 #endif
 
 #define flush_tlb_kernel_range(start, end) flush_tlb_all()
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
index 84016ff..3f3c1fa 100644
--- a/include/asm-i386/tsc.h
+++ b/include/asm-i386/tsc.h
@@ -35,25 +35,30 @@ #endif
 static __always_inline cycles_t get_cycles_sync(void)
 {
 	unsigned long long ret;
-#ifdef X86_FEATURE_SYNC_RDTSC
 	unsigned eax;
 
 	/*
+  	 * Use RDTSCP if possible; it is guaranteed to be synchronous
+ 	 * and doesn't cause a VMEXIT on Hypervisors
+	 */
+	alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP,
+			 	 "=A" (ret), "0" (0ULL) : "ecx", "memory");
+	if (ret)
+		return ret;
+
+	/*
 	 * Don't do an additional sync on CPUs where we know
 	 * RDTSC is already synchronous:
 	 */
 	alternative_io("cpuid", ASM_NOP2, X86_FEATURE_SYNC_RDTSC,
 			  "=a" (eax), "0" (1) : "ebx","ecx","edx","memory");
-#else
-	sync_core();
-#endif
 	rdtscll(ret);
 
 	return ret;
 }
 
 extern void tsc_init(void);
-extern void mark_tsc_unstable(void);
+extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
 extern void init_tsc_clocksource(void);
 
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 70829ae..e2aa5e0 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -397,7 +397,19 @@ unsigned long __must_check __copy_from_u
 unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
 				const void __user *from, unsigned long n);
 
-/*
+/**
+ * __copy_to_user_inatomic: - 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.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ * The caller should also make sure he pins the user space address
+ * so that the we don't result in page fault and sleep.
+ *
  * Here we special-case 1, 2 and 4-byte copy_*_user invocations.  On a fault
  * we return the initial request size (1, 2 or 4), as copy_*_user should do.
  * If a store crosses a page boundary and gets a fault, the x86 will not write
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 833fa17..bd21e79 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -325,10 +325,11 @@ #define __NR_vmsplice		316
 #define __NR_move_pages		317
 #define __NR_getcpu		318
 #define __NR_epoll_pwait	319
+#define __NR_utimensat		320
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 320
+#define NR_syscalls 321
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/vmi_time.h b/include/asm-i386/vmi_time.h
index c3a1fcf..213930b 100644
--- a/include/asm-i386/vmi_time.h
+++ b/include/asm-i386/vmi_time.h
@@ -53,22 +53,8 @@ extern unsigned long long vmi_get_sched_
 extern unsigned long vmi_cpu_khz(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
-extern void __init vmi_timer_setup_boot_alarm(void);
-extern void __devinit vmi_timer_setup_secondary_alarm(void);
-extern void apic_vmi_timer_interrupt(void);
-#endif
-
-#ifdef CONFIG_NO_IDLE_HZ
-extern int vmi_stop_hz_timer(void);
-extern void vmi_account_time_restart_hz_timer(void);
-#else
-static inline int vmi_stop_hz_timer(void)
-{
-	return 0;
-}
-static inline void vmi_account_time_restart_hz_timer(void)
-{
-}
+extern void __devinit vmi_time_bsp_init(void);
+extern void __devinit vmi_time_ap_init(void);
 #endif
 
 /*
diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h
index 5b27838..91a9932 100644
--- a/include/asm-i386/voyager.h
+++ b/include/asm-i386/voyager.h
@@ -487,15 +487,11 @@ extern struct voyager_qic_cpi *voyager_q
 extern struct voyager_SUS *voyager_SUS;
 
 /* variables exported always */
+extern struct task_struct *voyager_thread;
 extern int voyager_level;
-extern int kvoyagerd_running;
-extern struct semaphore kvoyagerd_sem;
 extern struct voyager_status voyager_status;
 
-
-
 /* functions exported by the voyager and voyager_smp modules */
-
 extern int voyager_cat_readb(__u8 module, __u8 asic, int reg);
 extern void voyager_cat_init(void);
 extern void voyager_detect(struct voyager_bios_info *);
diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h
index c22b465..c1642fd 100644
--- a/include/asm-ia64/asmmacro.h
+++ b/include/asm-ia64/asmmacro.h
@@ -104,6 +104,16 @@ # define FSYS_RETURN	br.ret.sptk.many b6
 #endif
 
 /*
+ * If physical stack register size is different from DEF_NUM_STACK_REG,
+ * dynamically patch the kernel for correct size.
+ */
+	.section ".data.patch.phys_stack_reg", "a"
+	.previous
+#define LOAD_PHYS_STACK_REG_SIZE(reg)			\
+[1:]	adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0;	\
+	.xdata4 ".data.patch.phys_stack_reg", 1b-.
+
+/*
  * Up until early 2004, use of .align within a function caused bad unwind info.
  * TEXT_ALIGN(n) expands into ".align n" if a fixed GAS is available or into nothing
  * otherwise.
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index 569ec75..1fc3b83 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -15,6 +15,7 @@ #define _ASM_IA64_ATOMIC_H
 #include <linux/types.h>
 
 #include <asm/intrinsics.h>
+#include <asm/system.h>
 
 /*
  * On IA-64, counter must always be volatile to ensure that that the
@@ -88,25 +89,47 @@ ia64_atomic64_sub (__s64 i, atomic64_t *
 	return new;
 }
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+#define atomic64_cmpxchg(v, old, new) \
+	(cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic_add_return(i,v)						\
 ({									\
 	int __ia64_aar_i = (i);						\
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 6311e16..eb17a86 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -421,11 +421,7 @@ # ifdef __KERNEL__
 
 extern void __iomem * ioremap(unsigned long offset, unsigned long size);
 extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
-
-static inline void
-iounmap (volatile void __iomem *addr)
-{
-}
+extern void iounmap (volatile void __iomem *addr);
 
 /* Use normal IO mappings for DMI */
 #define dmi_ioremap ioremap
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h
index aed7142..ba211e0 100644
--- a/include/asm-ia64/kdebug.h
+++ b/include/asm-ia64/kdebug.h
@@ -28,21 +28,8 @@ #define _IA64_KDEBUG_H 1
  */
 #include <linux/notifier.h>
 
-struct pt_regs;
-
-struct die_args {
-	struct pt_regs *regs;
-	const char *str;
-	long err;
-	int trapnr;
-	int signr;
-};
-
-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 ia64die_chain;
 
 enum die_val {
 	DIE_BREAK = 1,
@@ -74,18 +61,4 @@ enum die_val {
 	DIE_KDUMP_LEAVE,
 };
 
-static inline int notify_die(enum die_val val, 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(&ia64die_chain, val, &args);
-}
-
 #endif
diff --git a/include/asm-ia64/kexec.h b/include/asm-ia64/kexec.h
index 41299dd..541be83 100644
--- a/include/asm-ia64/kexec.h
+++ b/include/asm-ia64/kexec.h
@@ -14,8 +14,6 @@ #define KEXEC_CONTROL_CODE_SIZE (8192 + 
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_IA_64
 
-#define MAX_NOTE_BYTES 1024
-
 #define kexec_flush_icache_page(page) do { \
                 unsigned long page_addr = (unsigned long)page_address(page); \
                 flush_icache_range(page_addr, page_addr + PAGE_SIZE); \
diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
index 221b5cb..7e55a58 100644
--- a/include/asm-ia64/kregs.h
+++ b/include/asm-ia64/kregs.h
@@ -29,8 +29,7 @@ #define IA64_KR(n)		_IA64_KR_PREFIX(IA64
  */
 #define IA64_TR_KERNEL		0	/* itr0, dtr0: maps kernel image (code & data) */
 #define IA64_TR_PALCODE		1	/* itr1: maps PALcode as required by EFI */
-#define IA64_TR_PERCPU_DATA	1	/* dtr1: percpu data */
-#define IA64_TR_CURRENT_STACK	2	/* dtr2: maps kernel's memory- & register-stacks */
+#define IA64_TR_CURRENT_STACK	1	/* dtr1: maps kernel's memory- & register-stacks */
 
 /* Processor status register bits: */
 #define IA64_PSR_BE_BIT		1
diff --git a/include/asm-ia64/local.h b/include/asm-ia64/local.h
index dc51909..c11c530 100644
--- a/include/asm-ia64/local.h
+++ b/include/asm-ia64/local.h
@@ -1,50 +1 @@
-#ifndef _ASM_IA64_LOCAL_H
-#define _ASM_IA64_LOCAL_H
-
-/*
- * Copyright (C) 2003 Hewlett-Packard Co
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/percpu.h>
-
-typedef struct {
-	atomic64_t val;
-} local_t;
-
-#define LOCAL_INIT(i)	((local_t) { { (i) } })
-#define local_read(l)	atomic64_read(&(l)->val)
-#define local_set(l, i)	atomic64_set(&(l)->val, i)
-#define local_inc(l)	atomic64_inc(&(l)->val)
-#define local_dec(l)	atomic64_dec(&(l)->val)
-#define local_add(i, l)	atomic64_add((i), &(l)->val)
-#define local_sub(i, l)	atomic64_sub((i), &(l)->val)
-
-/* Non-atomic variants, i.e., preemption disabled and won't be touched in interrupt, etc.  */
-
-#define __local_inc(l)		(++(l)->val.counter)
-#define __local_dec(l)		(--(l)->val.counter)
-#define __local_add(i,l)	((l)->val.counter += (i))
-#define __local_sub(i,l)	((l)->val.counter -= (i))
-
-/*
- * Use these for per-cpu local_t variables.  Note they take a variable (eg. mystruct.foo),
- * not an address.
- */
-#define cpu_local_read(v)	local_read(&__ia64_per_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__ia64_per_cpu_var(v), (i))
-#define cpu_local_inc(v)	local_inc(&__ia64_per_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__ia64_per_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__ia64_per_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__ia64_per_cpu_var(v))
-
-/*
- * Non-atomic increments, i.e., preemption disabled and won't be touched in interrupt,
- * etc.
- */
-#define __cpu_local_inc(v)	__local_inc(&__ia64_per_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__ia64_per_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__ia64_per_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__ia64_per_cpu_var(v))
-
-#endif /* _ASM_IA64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index b5c6508..cef2400 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -29,6 +29,7 @@ #include <linux/sched.h>
 #include <linux/spinlock.h>
 
 #include <asm/processor.h>
+#include <asm-generic/mm_hooks.h>
 
 struct ia64_ctx {
 	spinlock_t lock;
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 67656ce..abfcb3a 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -89,6 +89,8 @@ #define PAL_GET_PSTATE_TYPE_AVGANDRESET	
 #define PAL_GET_PSTATE_TYPE_AVGNORESET	2
 #define PAL_GET_PSTATE_TYPE_INSTANT	3
 
+#define PAL_MC_ERROR_INJECT	276	/* Injects processor error or returns injection capabilities */
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -1235,6 +1237,37 @@ ia64_pal_mc_error_info (u64 info_index, 
 	return iprv.status;
 }
 
+/* Injects the requested processor error or returns info on
+ * supported injection capabilities for current processor implementation
+ */
+static inline s64
+ia64_pal_mc_error_inject_phys (u64 err_type_info, u64 err_struct_info,
+			u64 err_data_buffer, u64 *capabilities, u64 *resources)
+{
+	struct ia64_pal_retval iprv;
+	PAL_CALL_PHYS_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
+			  err_struct_info, err_data_buffer);
+	if (capabilities)
+		*capabilities= iprv.v0;
+	if (resources)
+		*resources= iprv.v1;
+	return iprv.status;
+}
+
+static inline s64
+ia64_pal_mc_error_inject_virt (u64 err_type_info, u64 err_struct_info,
+			u64 err_data_buffer, u64 *capabilities, u64 *resources)
+{
+	struct ia64_pal_retval iprv;
+	PAL_CALL_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
+			  err_struct_info, err_data_buffer);
+	if (capabilities)
+		*capabilities= iprv.v0;
+	if (resources)
+		*resources= iprv.v1;
+	return iprv.status;
+}
+
 /* Inform PALE_CHECK whether a machine check is expected so that PALE_CHECK willnot
  * attempt to correct any expected machine checks.
  */
diff --git a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h
index 4797f35..a715430 100644
--- a/include/asm-ia64/patch.h
+++ b/include/asm-ia64/patch.h
@@ -20,6 +20,7 @@ extern void ia64_patch_imm60 (u64 insn_a
 
 extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end);
 extern void ia64_patch_vtop (unsigned long start, unsigned long end);
+extern void ia64_patch_phys_stack_reg(unsigned long val);
 extern void ia64_patch_gate (void);
 
 #endif /* _ASM_IA64_PATCH_H */
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 5531827..670b706 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -485,10 +485,6 @@ #define pgoff_to_pte(off)		((pte_t) { ((
 #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)
-
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 4f4ee1c..db81ba4 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -19,6 +19,7 @@ #include <asm/kregs.h>
 #include <asm/ptrace.h>
 #include <asm/ustack.h>
 
+#define IA64_NUM_PHYS_STACK_REG	96
 #define IA64_NUM_DBG_REGS	8
 
 #define DEFAULT_MAP_BASE	__IA64_UL_CONST(0x2000000000000000)
diff --git a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h
index 9dbea88..a452ea2 100644
--- a/include/asm-ia64/scatterlist.h
+++ b/include/asm-ia64/scatterlist.h
@@ -6,6 +6,8 @@ #define _ASM_IA64_SCATTERLIST_H
  *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page *page;
 	unsigned int offset;
diff --git a/include/asm-ia64/sections.h b/include/asm-ia64/sections.h
index e9eb7f6..dc42a35 100644
--- a/include/asm-ia64/sections.h
+++ b/include/asm-ia64/sections.h
@@ -11,6 +11,7 @@ #include <asm-generic/sections.h>
 extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
 extern char __start___vtop_patchlist[], __end___vtop_patchlist[];
 extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[];
+extern char __start___phys_stack_reg_patchlist[], __end___phys_stack_reg_patchlist[];
 extern char __start_gate_section[];
 extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchlist[];
 extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[];
diff --git a/include/asm-ia64/socket.h b/include/asm-ia64/socket.h
index d638ef3..9e42ce4 100644
--- a/include/asm-ia64/socket.h
+++ b/include/asm-ia64/socket.h
@@ -58,5 +58,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_IA64_SOCKET_H */
diff --git a/include/asm-ia64/sockios.h b/include/asm-ia64/sockios.h
index cf94857..15c9246 100644
--- a/include/asm-ia64/sockios.h
+++ b/include/asm-ia64/sockios.h
@@ -14,6 +14,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_IA64_SOCKIOS_H */
diff --git a/include/asm-m32r/atomic.h b/include/asm-m32r/atomic.h
index f5a7d73..3a38ffe 100644
--- a/include/asm-m32r/atomic.h
+++ b/include/asm-m32r/atomic.h
@@ -253,14 +253,21 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
diff --git a/include/asm-m32r/kdebug.h b/include/asm-m32r/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-m32r/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m32r/mmu_context.h b/include/asm-m32r/mmu_context.h
index 1f40d4a..91909e5 100644
--- a/include/asm-m32r/mmu_context.h
+++ b/include/asm-m32r/mmu_context.h
@@ -15,6 +15,7 @@ #include <asm/atomic.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu.h>
 #include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * Cache of MMU context last used.
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 1c15ba7..8b2a2f1 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -381,10 +381,6 @@ #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)
-
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-m32r/scatterlist.h b/include/asm-m32r/scatterlist.h
index c2de96c..352415f 100644
--- a/include/asm-m32r/scatterlist.h
+++ b/include/asm-m32r/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_M32R_SCATTERLIST_H
 #define _ASM_M32R_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
                          * highmem page */
diff --git a/include/asm-m32r/socket.h b/include/asm-m32r/socket.h
index acdf748..793d5d3 100644
--- a/include/asm-m32r/socket.h
+++ b/include/asm-m32r/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_M32R_SOCKET_H */
diff --git a/include/asm-m32r/sockios.h b/include/asm-m32r/sockios.h
index f89962e..6c1fb9b 100644
--- a/include/asm-m32r/sockios.h
+++ b/include/asm-m32r/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif  /* _ASM_M32R_SOCKIOS_H */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 99ee098..06cdece 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -122,8 +122,6 @@ #define nop()	__asm__ __volatile__ ("nop
 #define xchg(ptr,x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
-#define tas(ptr)	(xchg((ptr),1))
-
 #ifdef CONFIG_SMP
 extern void  __xchg_called_with_bad_pointer(void);
 #endif
diff --git a/include/asm-m68k/adb.h b/include/asm-m68k/adb.h
deleted file mode 100644
index 9176b55..0000000
--- a/include/asm-m68k/adb.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Definitions for talking to ADB and CUDA.  The CUDA is a microcontroller
- * which controls the ADB, system power, RTC, and various other things on
- * later Macintoshes
- *
- * Copyright (C) 1996 Paul Mackerras.
- */
-
-/* First byte sent to or received from CUDA */
-#define ADB_PACKET	0
-#define CUDA_PACKET	1
-#define ERROR_PACKET	2
-#define TIMER_PACKET	3
-#define POWER_PACKET	4
-#define MACIIC_PACKET	5
-
-/* ADB commands (2nd byte) */
-#define ADB_BUSRESET		0
-#define ADB_FLUSH(id)		(1 + ((id) << 4))
-#define ADB_WRITEREG(id, reg)	(8 + (reg) + ((id) << 4))
-#define ADB_READREG(id, reg)	(0xc + (reg) + ((id) << 4))
-
-/* ADB default device IDs (upper 4 bits of 2nd byte) */
-#define ADB_DONGLE	1	/* "software execution control" devices */
-#define ADB_KEYBOARD	2
-#define ADB_MOUSE	3
-#define ADB_TABLET	4
-#define ADB_MODEM	5
-#define ADB_MISC	7	/* maybe a monitor */
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START		0
-#define CUDA_AUTOPOLL		1
-#define CUDA_GET_6805_ADDR	2
-#define CUDA_GET_TIME		3
-#define CUDA_GET_PRAM		7
-#define CUDA_SET_6805_ADDR	8
-#define CUDA_SET_TIME		9
-#define CUDA_POWERDOWN		0xa
-#define CUDA_POWERUP_TIME	0xb
-#define CUDA_SET_PRAM		0xc
-#define CUDA_MS_RESET		0xd
-#define CUDA_SEND_DFAC		0xe
-#define CUDA_RESET_SYSTEM	0x11
-#define CUDA_SET_IPL		0x12
-#define CUDA_SET_AUTO_RATE	0x14
-#define CUDA_GET_AUTO_RATE	0x16
-#define CUDA_SET_DEVICE_LIST	0x19
-#define CUDA_GET_DEVICE_LIST	0x1a
-#define CUDA_GET_SET_IIC	0x22
-
-#ifdef __KERNEL__
-
-struct adb_request {
-    unsigned char data[16];
-    int nbytes;
-    unsigned char reply[16];
-    int reply_len;
-    unsigned char reply_expected;
-    unsigned char sent;
-    unsigned char got_reply;
-    void (*done)(struct adb_request *);
-    void *arg;
-    struct adb_request *next;
-};
-
-void via_adb_init(void);
-int adb_request(struct adb_request *req,
-		 void (*done)(struct adb_request *), int nbytes, ...);
-int adb_send_request(struct adb_request *req);
-void adb_poll(void);
-int adb_register(int default_id,
-		 void (*handler)(unsigned char *, int, struct pt_regs *));
-
-#endif	/* __KERNEL */
diff --git a/include/asm-m68k/atarikb.h b/include/asm-m68k/atarikb.h
index 1892605..546e7da 100644
--- a/include/asm-m68k/atarikb.h
+++ b/include/asm-m68k/atarikb.h
@@ -36,5 +36,11 @@ void ikbd_joystick_disable(void);
 extern void (*atari_MIDI_interrupt_hook) (void);
 /* Hook for mouse driver */
 extern void (*atari_mouse_interrupt_hook) (char *);
+/* Hook for keyboard inputdev  driver */
+extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
+/* Hook for mouse inputdev  driver */
+extern void (*atari_input_mouse_interrupt_hook) (char *);
+
+int atari_keyb_init(void);
 
 #endif /* _LINUX_ATARIKB_H */
diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h
index d5eed64..4915294 100644
--- a/include/asm-m68k/atomic.h
+++ b/include/asm-m68k/atomic.h
@@ -2,7 +2,7 @@ #ifndef __ARCH_M68K_ATOMIC__
 #define __ARCH_M68K_ATOMIC__
 
 
-#include <asm/system.h>	/* local_irq_XXX() */
+#include <asm/system.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -170,20 +170,21 @@ static inline void atomic_set_mask(unsig
 	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
 }
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 /* Atomic operations are already serializing */
diff --git a/include/asm-m68k/div64.h b/include/asm-m68k/div64.h
index 9f65de1..33caad1 100644
--- a/include/asm-m68k/div64.h
+++ b/include/asm-m68k/div64.h
@@ -1,6 +1,8 @@
 #ifndef _M68K_DIV64_H
 #define _M68K_DIV64_H
 
+#include <linux/types.h>
+
 /* n = n / base; return rem; */
 
 #define do_div(n, base) ({					\
@@ -23,4 +25,5 @@ #define do_div(n, base) ({					\
 	__rem;							\
 })
 
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif /* _M68K_DIV64_H */
diff --git a/include/asm-m68k/kdebug.h b/include/asm-m68k/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-m68k/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m68k/mmu_context.h b/include/asm-m68k/mmu_context.h
index 231d11b..894dacb 100644
--- a/include/asm-m68k/mmu_context.h
+++ b/include/asm-m68k/mmu_context.h
@@ -1,6 +1,7 @@
 #ifndef __M68K_MMU_CONTEXT_H
 #define __M68K_MMU_CONTEXT_H
 
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index f3aa053..555b87a 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -143,10 +143,6 @@ #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)
-
 /* MMU-specific headers */
 
 #ifdef CONFIG_SUN3
diff --git a/include/asm-m68k/socket.h b/include/asm-m68k/socket.h
index a5966ec..6d21b90 100644
--- a/include/asm-m68k/socket.h
+++ b/include/asm-m68k/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-m68k/sockios.h b/include/asm-m68k/sockios.h
index 9b9ed97..c04a239 100644
--- a/include/asm-m68k/sockios.h
+++ b/include/asm-m68k/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __ARCH_M68K_SOCKIOS__ */
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index 243dd13..198878b 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -88,7 +88,6 @@ #define smp_read_barrier_depends()	((voi
 
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-m68knommu/atomic.h b/include/asm-m68knommu/atomic.h
index 6c4e4b6..d5632a3 100644
--- a/include/asm-m68knommu/atomic.h
+++ b/include/asm-m68knommu/atomic.h
@@ -1,7 +1,7 @@
 #ifndef __ARCH_M68KNOMMU_ATOMIC__
 #define __ARCH_M68KNOMMU_ATOMIC__
 
-#include <asm/system.h>	/* local_irq_XXX() */
+#include <asm/system.h>
 
 /*
  * Atomic operations that C can't guarantee us.  Useful for
@@ -131,14 +131,21 @@ static inline int atomic_sub_return(int 
 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
diff --git a/include/asm-m68knommu/kdebug.h b/include/asm-m68knommu/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-m68knommu/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m68knommu/mmu_context.h b/include/asm-m68knommu/mmu_context.h
index 6c077d3..9ccee42 100644
--- a/include/asm-m68knommu/mmu_context.h
+++ b/include/asm-m68knommu/mmu_context.h
@@ -4,6 +4,7 @@ #define __M68KNOMMU_MMU_CONTEXT_H
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
index 549ad23..9dfbbc2 100644
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -59,10 +59,6 @@ #define pgtable_cache_init()	do { } whil
 #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)
-
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h
index 2085d6f..4da79d3 100644
--- a/include/asm-m68knommu/scatterlist.h
+++ b/include/asm-m68knommu/scatterlist.h
@@ -2,6 +2,7 @@ #ifndef _M68KNOMMU_SCATTERLIST_H
 #define _M68KNOMMU_SCATTERLIST_H
 
 #include <linux/mm.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page	*page;
diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h
index 2a81449..5e5ed18 100644
--- a/include/asm-m68knommu/system.h
+++ b/include/asm-m68knommu/system.h
@@ -120,7 +120,6 @@ #define smp_read_barrier_depends()	do { 
 #endif
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 1ac50b6..62daa74 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -18,6 +18,7 @@ #include <linux/irqflags.h>
 #include <asm/barrier.h>
 #include <asm/cpu-features.h>
 #include <asm/war.h>
+#include <asm/system.h>
 
 typedef struct { volatile int counter; } atomic_t;
 
@@ -306,8 +307,8 @@ static __inline__ int atomic_sub_if_posi
 	return result;
 }
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
 
 /**
  * atomic_add_unless - add unless the number is a given value
@@ -318,14 +319,20 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
@@ -681,6 +688,36 @@ static __inline__ long atomic64_sub_if_p
 	return result;
 }
 
+#define atomic64_cmpxchg(v, o, n) \
+	(((__typeof__((v)->counter)))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #define atomic64_dec_return(v) atomic64_sub_return(1,(v))
 #define atomic64_inc_return(v) atomic64_add_return(1,(v))
 
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
index 28d907d..4933b49 100644
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -96,6 +96,6 @@ #define ClearPageDcacheDirty(page)	\
 unsigned long __init run_uncached(void *func);
 
 extern void *kmap_coherent(struct page *page, unsigned long addr);
-extern void kunmap_coherent(struct page *page);
+extern void kunmap_coherent(void);
 
 #endif /* _ASM_CACHEFLUSH_H */
diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h
index d107832..66189f5 100644
--- a/include/asm-mips/div64.h
+++ b/include/asm-mips/div64.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000, 2004  Maciej W. Rozycki
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -9,6 +9,8 @@
 #ifndef _ASM_DIV64_H
 #define _ASM_DIV64_H
 
+#include <linux/types.h>
+
 #if (_MIPS_SZLONG == 32)
 
 #include <asm/compiler.h>
@@ -78,6 +80,8 @@ #define do_div(n, base) ({ \
 	__quot = __quot << 32 | __low; \
 	(n) = __quot; \
 	__mod; })
+
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif /* (_MIPS_SZLONG == 32) */
 
 #if (_MIPS_SZLONG == 64)
@@ -101,6 +105,11 @@ #define do_div(n, base) ({ \
 	(n) = __quot; \
 	__mod; })
 
+static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+{
+	return dividend / divisor;
+}
+
 #endif /* (_MIPS_SZLONG == 64) */
 
 #endif /* _ASM_DIV64_H */
diff --git a/include/asm-mips/jmr3927/irq.h b/include/asm-mips/jmr3927/irq.h
deleted file mode 100644
index e3e7ed3..0000000
--- a/include/asm-mips/jmr3927/irq.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  linux/include/asm-mips/tx3927/irq.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Toshiba Corporation
- */
-#ifndef __ASM_TX3927_IRQ_H
-#define __ASM_TX3927_IRQ_H
-
-#ifndef __ASSEMBLY__
-
-#include <asm/irq.h>
-
-struct tb_irq_space {
-	struct tb_irq_space* next;
-	int start_irqno;
-	int nr_irqs;
-	void (*mask_func)(int irq_nr, int space_id);
-	void (*unmask_func)(int irq_no, int space_id);
-	const char *name;
-	int space_id;
-	int can_share;
-};
-extern struct tb_irq_space* tb_irq_spaces;
-
-static __inline__ void add_tb_irq_space(struct tb_irq_space* sp)
-{
-	sp->next = tb_irq_spaces;
-	tb_irq_spaces = sp;
-}
-
-
-struct pt_regs;
-extern void
-toshibaboards_spurious(struct pt_regs *regs, int irq);
-extern void
-toshibaboards_irqdispatch(struct pt_regs *regs, int irq);
-
-extern struct irqaction *
-toshibaboards_get_irq_action(int irq);
-extern int
-toshibaboards_setup_irq(int irq, struct irqaction * new);
-
-
-extern int (*toshibaboards_gen_iack)(void);
-
-#endif /* !__ASSEMBLY__ */
-
-#define NR_ISA_IRQS 16
-#define TB_IRQ_IS_ISA(irq)	\
-	(0 <= (irq) && (irq) < NR_ISA_IRQS)
-#define TB_IRQ_TO_ISA_IRQ(irq)	(irq)
-
-#endif /* __ASM_TX3927_IRQ_H */
diff --git a/include/asm-mips/jmr3927/jmr3927.h b/include/asm-mips/jmr3927/jmr3927.h
index c50e68f..958e297 100644
--- a/include/asm-mips/jmr3927/jmr3927.h
+++ b/include/asm-mips/jmr3927/jmr3927.h
@@ -1,5 +1,5 @@
 /*
- * Defines for the TJSYS JMR-TX3927/JMI-3927IO2/JMY-1394IF.
+ * Defines for the TJSYS JMR-TX3927
  *
  * 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
@@ -12,10 +12,7 @@ #define __ASM_TX3927_JMR3927_H
 
 #include <asm/jmr3927/tx3927.h>
 #include <asm/addrspace.h>
-#include <asm/jmr3927/irq.h>
-#ifndef __ASSEMBLY__
 #include <asm/system.h>
-#endif
 
 /* CS */
 #define JMR3927_ROMCE0	0x1fc00000	/* 4M */
@@ -35,28 +32,10 @@ #define JMR3927_PCIIO_SIZE	0x01000000	/*
 #define JMR3927_SDRAM_SIZE	0x02000000	/* 32M */
 #define JMR3927_PORT_BASE	KSEG1
 
-/* select indirect initiator access per errata */
-#define JMR3927_INIT_INDIRECT_PCI
-#define PCI_ISTAT_IDICC           0x1000
-#define PCI_IPCIBE_IBE_LONG       0
-#define PCI_IPCIBE_ICMD_IOREAD    2
-#define PCI_IPCIBE_ICMD_IOWRITE   3
-#define PCI_IPCIBE_ICMD_MEMREAD   6
-#define PCI_IPCIBE_ICMD_MEMWRITE  7
-#define PCI_IPCIBE_ICMD_SHIFT     4
-
 /* Address map (virtual address) */
 #define JMR3927_ROM0_BASE	(KSEG1 + JMR3927_ROMCE0)
 #define JMR3927_ROM1_BASE	(KSEG1 + JMR3927_ROMCE1)
 #define JMR3927_IOC_BASE	(KSEG1 + JMR3927_ROMCE2)
-#define JMR3927_IOB_BASE	(KSEG1 + JMR3927_ROMCE3)
-#define JMR3927_ISAMEM_BASE	(JMR3927_IOB_BASE)
-#define JMR3927_ISAIO_BASE	(JMR3927_IOB_BASE + 0x01000000)
-#define JMR3927_ISAC_BASE	(JMR3927_IOB_BASE + 0x02000000)
-#define JMR3927_LCDVGA_REG_BASE	(JMR3927_IOB_BASE + 0x03000000)
-#define JMR3927_LCDVGA_MEM_BASE	(JMR3927_IOB_BASE + 0x03800000)
-#define JMR3927_JMY1394_BASE	(KSEG1 + JMR3927_ROMCE5)
-#define JMR3927_PREMIER3_BASE	(JMR3927_JMY1394_BASE + 0x00100000)
 #define JMR3927_PCIMEM_BASE	(KSEG1 + JMR3927_PCIMEM)
 #define JMR3927_PCIIO_BASE	(KSEG1 + JMR3927_PCIIO)
 
@@ -72,25 +51,14 @@ #define JMR3927_IOC_INTM_ADDR	(JMR3927_I
 #define JMR3927_IOC_INTP_ADDR	(JMR3927_IOC_BASE + 0x000b0000)
 #define JMR3927_IOC_RESET_ADDR	(JMR3927_IOC_BASE + 0x000f0000)
 
-#define JMR3927_ISAC_REV_ADDR	(JMR3927_ISAC_BASE + 0x00000000)
-#define JMR3927_ISAC_EINTS_ADDR	(JMR3927_ISAC_BASE + 0x00200000)
-#define JMR3927_ISAC_EINTM_ADDR	(JMR3927_ISAC_BASE + 0x00300000)
-#define JMR3927_ISAC_NMI_ADDR	(JMR3927_ISAC_BASE + 0x00400000)
-#define JMR3927_ISAC_LED_ADDR	(JMR3927_ISAC_BASE + 0x00500000)
-#define JMR3927_ISAC_INTP_ADDR	(JMR3927_ISAC_BASE + 0x00800000)
-#define JMR3927_ISAC_INTS1_ADDR	(JMR3927_ISAC_BASE + 0x00900000)
-#define JMR3927_ISAC_INTS2_ADDR	(JMR3927_ISAC_BASE + 0x00a00000)
-#define JMR3927_ISAC_INTM_ADDR	(JMR3927_ISAC_BASE + 0x00b00000)
-
 /* Flash ROM */
 #define JMR3927_FLASH_BASE	(JMR3927_ROM0_BASE)
 #define JMR3927_FLASH_SIZE	0x00400000
 
-/* bits for IOC_REV/IOC_BREV/ISAC_REV (high byte) */
+/* bits for IOC_REV/IOC_BREV (high byte) */
 #define JMR3927_IDT_MASK	0xfc
 #define JMR3927_REV_MASK	0x03
 #define JMR3927_IOC_IDT		0xe0
-#define JMR3927_ISAC_IDT	0x20
 
 /* bits for IOC_INTS1/IOC_INTS2/IOC_INTM/IOC_INTP (high byte) */
 #define JMR3927_IOC_INTB_PCIA	0
@@ -114,40 +82,6 @@ #define JMR3927_IOC_INTF_SOFT	(1 << JMR3
 #define JMR3927_IOC_RESET_CPU	1
 #define JMR3927_IOC_RESET_PCI	2
 
-/* bits for ISAC_EINTS/ISAC_EINTM (high byte) */
-#define JMR3927_ISAC_EINTB_IOCHK	2
-#define JMR3927_ISAC_EINTB_BWTH	4
-#define JMR3927_ISAC_EINTF_IOCHK	(1 << JMR3927_ISAC_EINTB_IOCHK)
-#define JMR3927_ISAC_EINTF_BWTH	(1 << JMR3927_ISAC_EINTB_BWTH)
-
-/* bits for ISAC_LED (high byte) */
-#define JMR3927_ISAC_LED_ISALED	0x01
-#define JMR3927_ISAC_LED_USRLED	0x02
-
-/* bits for ISAC_INTS/ISAC_INTM/ISAC_INTP (high byte) */
-#define JMR3927_ISAC_INTB_IRQ5	0
-#define JMR3927_ISAC_INTB_IRQKB	1
-#define JMR3927_ISAC_INTB_IRQMOUSE	2
-#define JMR3927_ISAC_INTB_IRQ4	3
-#define JMR3927_ISAC_INTB_IRQ12	4
-#define JMR3927_ISAC_INTB_IRQ3	5
-#define JMR3927_ISAC_INTB_IRQ10	6
-#define JMR3927_ISAC_INTB_ISAER	7
-#define JMR3927_ISAC_INTF_IRQ5	(1 << JMR3927_ISAC_INTB_IRQ5)
-#define JMR3927_ISAC_INTF_IRQKB	(1 << JMR3927_ISAC_INTB_IRQKB)
-#define JMR3927_ISAC_INTF_IRQMOUSE	(1 << JMR3927_ISAC_INTB_IRQMOUSE)
-#define JMR3927_ISAC_INTF_IRQ4	(1 << JMR3927_ISAC_INTB_IRQ4)
-#define JMR3927_ISAC_INTF_IRQ12	(1 << JMR3927_ISAC_INTB_IRQ12)
-#define JMR3927_ISAC_INTF_IRQ3	(1 << JMR3927_ISAC_INTB_IRQ3)
-#define JMR3927_ISAC_INTF_IRQ10	(1 << JMR3927_ISAC_INTB_IRQ10)
-#define JMR3927_ISAC_INTF_ISAER	(1 << JMR3927_ISAC_INTB_ISAER)
-
-#ifndef __ASSEMBLY__
-
-#if 0
-#define jmr3927_ioc_reg_out(d, a)	((*(volatile unsigned short *)(a)) = (d) << 8)
-#define jmr3927_ioc_reg_in(a)		(((*(volatile unsigned short *)(a)) >> 8) & 0xff)
-#else
 #if defined(__BIG_ENDIAN)
 #define jmr3927_ioc_reg_out(d, a)	((*(volatile unsigned char *)(a)) = (d))
 #define jmr3927_ioc_reg_in(a)		(*(volatile unsigned char *)(a))
@@ -157,31 +91,9 @@ #define jmr3927_ioc_reg_in(a)		(*(volati
 #else
 #error "No Endian"
 #endif
-#endif
-#define jmr3927_isac_reg_out(d, a)	((*(volatile unsigned char *)(a)) = (d))
-#define jmr3927_isac_reg_in(a)		(*(volatile unsigned char *)(a))
-
-static inline int jmr3927_have_isac(void)
-{
-	unsigned char idt;
-	unsigned long flags;
-	unsigned long romcr3;
-
-	local_irq_save(flags);
-	romcr3 = tx3927_romcptr->cr[3];
-	tx3927_romcptr->cr[3] &= 0xffffefff;	/* do not wait infinitely */
-	idt = jmr3927_isac_reg_in(JMR3927_ISAC_REV_ADDR) & JMR3927_IDT_MASK;
-	tx3927_romcptr->cr[3] = romcr3;
-	local_irq_restore(flags);
-
-	return idt == JMR3927_ISAC_IDT;
-}
-#define jmr3927_have_nvram() \
-	((jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_IDT_MASK) == JMR3927_IOC_IDT)
 
 /* LED macro */
 #define jmr3927_led_set(n/*0-16*/)	jmr3927_ioc_reg_out(~(n), JMR3927_IOC_LED_ADDR)
-#define jmr3927_io_led_set(n/*0-3*/)	jmr3927_isac_reg_out((n), JMR3927_ISAC_LED_ADDR)
 
 #define jmr3927_led_and_set(n/*0-16*/)	jmr3927_ioc_reg_out((~(n)) & jmr3927_ioc_reg_in(JMR3927_IOC_LED_ADDR), JMR3927_IOC_LED_ADDR)
 
@@ -190,10 +102,6 @@ #define jmr3927_dipsw1()	((tx3927_pioptr
 #define jmr3927_dipsw2()	((tx3927_pioptr->din & (1 << 10)) == 0)
 #define jmr3927_dipsw3()	((jmr3927_ioc_reg_in(JMR3927_IOC_DIPSW_ADDR) & 2) == 0)
 #define jmr3927_dipsw4()	((jmr3927_ioc_reg_in(JMR3927_IOC_DIPSW_ADDR) & 1) == 0)
-#define jmr3927_io_dipsw()	(jmr3927_isac_reg_in(JMR3927_ISAC_LED_ADDR) >> 4)
-
-
-#endif /* !__ASSEMBLY__ */
 
 /*
  * IRQ mappings
@@ -206,16 +114,10 @@ #endif /* !__ASSEMBLY__ */
  */
 #define JMR3927_NR_IRQ_IRC	16	/* On-Chip IRC */
 #define JMR3927_NR_IRQ_IOC	8	/* PCI/MODEM/INT[6:7] */
-#define JMR3927_NR_IRQ_ISAC	8	/* ISA */
 
-
-#define JMR3927_IRQ_IRC	NR_ISA_IRQS
+#define JMR3927_IRQ_IRC	16
 #define JMR3927_IRQ_IOC	(JMR3927_IRQ_IRC + JMR3927_NR_IRQ_IRC)
-#define JMR3927_IRQ_ISAC	(JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC)
-#define JMR3927_IRQ_END	(JMR3927_IRQ_ISAC + JMR3927_NR_IRQ_ISAC)
-#define JMR3927_IRQ_IS_IRC(irq)	(JMR3927_IRQ_IRC <= (irq) && (irq) < JMR3927_IRQ_IOC)
-#define JMR3927_IRQ_IS_IOC(irq)		(JMR3927_IRQ_IOC <= (irq) && (irq) < JMR3927_IRQ_ISAC)
-#define JMR3927_IRQ_IS_ISAC(irq)	(JMR3927_IRQ_ISAC <= (irq) && (irq) < JMR3927_IRQ_END)
+#define JMR3927_IRQ_END	(JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC)
 
 #define JMR3927_IRQ_IRC_INT0	(JMR3927_IRQ_IRC + TX3927_IR_INT0)
 #define JMR3927_IRQ_IRC_INT1	(JMR3927_IRQ_IRC + TX3927_IR_INT1)
@@ -240,37 +142,13 @@ #define JMR3927_IRQ_IOC_MODEM	(JMR3927_I
 #define JMR3927_IRQ_IOC_INT6	(JMR3927_IRQ_IOC + JMR3927_IOC_INTB_INT6)
 #define JMR3927_IRQ_IOC_INT7	(JMR3927_IRQ_IOC + JMR3927_IOC_INTB_INT7)
 #define JMR3927_IRQ_IOC_SOFT	(JMR3927_IRQ_IOC + JMR3927_IOC_INTB_SOFT)
-#define JMR3927_IRQ_ISAC_IRQ5	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQ5)
-#define JMR3927_IRQ_ISAC_IRQKB	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQKB)
-#define JMR3927_IRQ_ISAC_IRQMOUSE	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQMOUSE)
-#define JMR3927_IRQ_ISAC_IRQ4	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQ4)
-#define JMR3927_IRQ_ISAC_IRQ12	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQ12)
-#define JMR3927_IRQ_ISAC_IRQ3	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQ3)
-#define JMR3927_IRQ_ISAC_IRQ10	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_IRQ10)
-#define JMR3927_IRQ_ISAC_ISAER	(JMR3927_IRQ_ISAC + JMR3927_ISAC_INTB_ISAER)
 
-#if 0	/* auto detect */
-/* RTL8019AS 10M Ether (JMI-3927IO2:JPW2:1-2 Short) */
-#define JMR3927_IRQ_ETHER1	JMR3927_IRQ_IRC_INT0
-#endif
 /* IOC (PCI, MODEM) */
 #define JMR3927_IRQ_IOCINT	JMR3927_IRQ_IRC_INT1
-/* ISAC (ISA, PCMCIA, KEYBOARD, MOUSE) */
-#define JMR3927_IRQ_ISACINT	JMR3927_IRQ_IRC_INT2
 /* TC35815 100M Ether (JMR-TX3912:JPW4:2-3 Short) */
 #define JMR3927_IRQ_ETHER0	JMR3927_IRQ_IRC_INT3
 /* Clock Tick (10ms) */
 #define JMR3927_IRQ_TICK	JMR3927_IRQ_IRC_TMR0
-#define JMR3927_IRQ_IDE		JMR3927_IRQ_ISAC_IRQ12
-
-/* IEEE1394 (Note that this may conflicts with RTL8019AS 10M Ether...) */
-#define JMR3927_IRQ_PREMIER3	JMR3927_IRQ_IRC_INT0
-
-/* I/O Ports */
-/* RTL8019AS 10M Ether */
-#define JMR3927_ETHER1_PORT	(JMR3927_ISAIO_BASE - JMR3927_PORT_BASE + 0x280)
-#define JMR3927_KBD_PORT	(JMR3927_ISAIO_BASE - JMR3927_PORT_BASE + 0x00800060)
-#define JMR3927_IDE_PORT	(JMR3927_ISAIO_BASE - JMR3927_PORT_BASE + 0x001001f0)
 
 /* Clocks */
 #define JMR3927_CORECLK	132710400	/* 132.7MHz */
diff --git a/include/asm-mips/jmr3927/tx3927.h b/include/asm-mips/jmr3927/tx3927.h
index b3d67c7..0b9073b 100644
--- a/include/asm-mips/jmr3927/tx3927.h
+++ b/include/asm-mips/jmr3927/tx3927.h
@@ -22,8 +22,6 @@ #define TX3927_NR_SIO	2
 #define TX3927_SIO_REG(ch)	(0xfffef300 + (ch) * 0x100)
 #define TX3927_PIO_REG		0xfffef500
 
-#ifndef __ASSEMBLY__
-
 struct tx3927_sdramc_reg {
 	volatile unsigned long cr[8];
 	volatile unsigned long tr[3];
@@ -164,8 +162,6 @@ struct tx3927_ccfg_reg {
 	volatile unsigned long pdcr;
 };
 
-#endif /* !__ASSEMBLY__ */
-
 /*
  * SDRAMC
  */
@@ -348,8 +344,6 @@ #define TX3927_PCFG_INTDMA(ch)	(0x000000
 #define TX3927_PCFG_SELDMA_ALL	0x0000000f
 #define TX3927_PCFG_SELDMA(ch)	(0x00000001<<(ch))
 
-#ifndef __ASSEMBLY__
-
 #define tx3927_sdramcptr	((struct tx3927_sdramc_reg *)TX3927_SDRAMC_REG)
 #define tx3927_romcptr		((struct tx3927_romc_reg *)TX3927_ROMC_REG)
 #define tx3927_dmaptr		((struct tx3927_dma_reg *)TX3927_DMA_REG)
@@ -360,6 +354,4 @@ #define tx3927_tmrptr(ch)	((struct txx92
 #define tx3927_sioptr(ch)	((struct txx927_sio_reg *)TX3927_SIO_REG(ch))
 #define tx3927_pioptr		((struct txx927_pio_reg *)TX3927_PIO_REG)
 
-#endif /* !__ASSEMBLY__ */
-
 #endif /* __ASM_TX3927_H */
diff --git a/include/asm-mips/jmr3927/txx927.h b/include/asm-mips/jmr3927/txx927.h
index 9d5792e..58a8ff6 100644
--- a/include/asm-mips/jmr3927/txx927.h
+++ b/include/asm-mips/jmr3927/txx927.h
@@ -10,8 +10,6 @@
 #ifndef __ASM_TXX927_H
 #define __ASM_TXX927_H
 
-#ifndef __ASSEMBLY__
-
 struct txx927_tmr_reg {
 	volatile unsigned long tcr;
 	volatile unsigned long tisr;
@@ -52,9 +50,6 @@ struct txx927_pio_reg {
 	volatile unsigned long maskext;
 };
 
-#endif /* !__ASSEMBLY__ */
-
-
 /*
  * TMR
  */
diff --git a/include/asm-mips/kdebug.h b/include/asm-mips/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-mips/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-mips/kexec.h b/include/asm-mips/kexec.h
index b25267e..cdbab43 100644
--- a/include/asm-mips/kexec.h
+++ b/include/asm-mips/kexec.h
@@ -21,8 +21,6 @@ #define KEXEC_CONTROL_CODE_SIZE 4096
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_MIPS
 
-#define MAX_NOTE_BYTES 1024
-
 static inline void crash_setup_regs(struct pt_regs *newregs,
 				    struct pt_regs *oldregs)
 {
diff --git a/include/asm-mips/local.h b/include/asm-mips/local.h
index 9e2d43b..ed882c8 100644
--- a/include/asm-mips/local.h
+++ b/include/asm-mips/local.h
@@ -1,60 +1,288 @@
-#ifndef _ASM_LOCAL_H
-#define _ASM_LOCAL_H
+#ifndef _ARCH_MIPS_LOCAL_H
+#define _ARCH_MIPS_LOCAL_H
 
 #include <linux/percpu.h>
+#include <linux/bitops.h>
 #include <asm/atomic.h>
+#include <asm/war.h>
 
-#ifdef CONFIG_32BIT
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
 
-typedef atomic_t local_t;
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define LOCAL_INIT(i)	ATOMIC_INIT(i)
-#define local_read(v)	atomic_read(v)
-#define local_set(v,i)	atomic_set(v,i)
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-#define local_inc(v)	atomic_inc(v)
-#define local_dec(v)	atomic_dec(v)
-#define local_add(i, v)	atomic_add(i, v)
-#define local_sub(i, v)	atomic_sub(i, v)
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
 
-#endif
+/*
+ * Same as above, but return the result value
+ */
+static __inline__ long local_add_return(long i, local_t * l)
+{
+	unsigned long result;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_add_return	\n"
+		"	addu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqzl	%0, 1b					\n"
+		"	addu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_add_return	\n"
+		"	addu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqz	%0, 1b					\n"
+		"	addu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
 
-#ifdef CONFIG_64BIT
+		local_irq_save(flags);
+		result = l->a.counter;
+		result += i;
+		l->a.counter = result;
+		local_irq_restore(flags);
+	}
 
-typedef atomic64_t local_t;
+	return result;
+}
 
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+	unsigned long result;
 
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
 
-#endif
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_return	\n"
+		"	subu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqzl	%0, 1b					\n"
+		"	subu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
 
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_return	\n"
+		"	subu	%0, %1, %3				\n"
+			__SC	"%0, %2					\n"
+		"	beqz	%0, 1b					\n"
+		"	subu	%0, %1, %3				\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		result = l->a.counter;
+		result -= i;
+		l->a.counter = result;
+		local_irq_restore(flags);
+	}
+
+	return result;
+}
 
 /*
- * Use these for per-cpu local_t variables: on some archs they are
+ * local_sub_if_positive - conditionally subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically test @l and subtract @i if @l is greater or equal than @i.
+ * The function returns the old value of @l minus @i.
+ */
+static __inline__ long local_sub_if_positive(long i, local_t * l)
+{
+	unsigned long result;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_if_positive\n"
+		"	dsubu	%0, %1, %3				\n"
+		"	bltz	%0, 1f					\n"
+			__SC	"%0, %2					\n"
+		"	.set	noreorder				\n"
+		"	beqzl	%0, 1b					\n"
+		"	 dsubu	%0, %1, %3				\n"
+		"	.set	reorder					\n"
+		"1:							\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		unsigned long temp;
+
+		__asm__ __volatile__(
+		"	.set	mips3					\n"
+		"1:"	__LL	"%1, %2		# local_sub_if_positive\n"
+		"	dsubu	%0, %1, %3				\n"
+		"	bltz	%0, 1f					\n"
+			__SC	"%0, %2					\n"
+		"	.set	noreorder				\n"
+		"	beqz	%0, 1b					\n"
+		"	 dsubu	%0, %1, %3				\n"
+		"	.set	reorder					\n"
+		"1:							\n"
+		"	.set	mips0					\n"
+		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+		: "Ir" (i), "m" (l->a.counter)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		result = l->a.counter;
+		result -= i;
+		if (result >= 0)
+			l->a.counter = result;
+		local_irq_restore(flags);
+	}
+
+	return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+	((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter),(n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+#define local_inc_return(l) local_add_return(1,(l))
+
+/*
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+/*
+ * local_dec_and_test - decrement by 1 and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/*
+ * local_dec_if_positive - decrement by 1 if old value positive
+ * @l: pointer of type local_t
+ */
+#define local_dec_if_positive(l)	local_sub_if_positive(1, l)
+
+/*
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define local_add_negative(i,l) (local_add_return(i, (l)) < 0)
+
+/* Use these for per-cpu local_t variables: on some archs they are
  * much more efficient than these naive implementations.  Note they take
  * a variable, not an address.
  */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
 
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (l);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(l)		\
+	({ preempt_disable();		\
+	   l;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
 
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
-#endif /* _ASM_LOCAL_H */
+#endif /* _ARCH_MIPS_LOCAL_H */
diff --git a/include/asm-mips/mach-au1x00/au1550_spi.h b/include/asm-mips/mach-au1x00/au1550_spi.h
new file mode 100644
index 0000000..c2f0466
--- /dev/null
+++ b/include/asm-mips/mach-au1x00/au1550_spi.h
@@ -0,0 +1,16 @@
+/*
+ * au1550_spi.h - au1550 psc spi controller driver - platform data struct
+ */
+
+#ifndef _AU1550_SPI_H_
+#define _AU1550_SPI_H_
+
+struct au1550_spi_info {
+	s16 bus_num;		/* defines which PSC and IRQ to use */
+	u32 mainclk_hz;		/* main input clock frequency of PSC */
+	u16 num_chipselect;	/* number of chipselects supported */
+	void (*activate_cs)(struct au1550_spi_info *spi, int cs, int polarity);
+	void (*deactivate_cs)(struct au1550_spi_info *spi, int cs, int polarity);
+};
+
+#endif
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index fe065d6..65024ff 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -20,6 +20,7 @@ #ifdef CONFIG_MIPS_MT_SMTC
 #include <asm/mipsmtregs.h>
 #include <asm/smtc.h>
 #endif /* SMTC */
+#include <asm-generic/mm_hooks.h>
 
 /*
  * For the fast tlb miss handlers, we keep a per cpu array of pointers
diff --git a/include/asm-mips/paccess.h b/include/asm-mips/paccess.h
index 147844e..8c08fa9 100644
--- a/include/asm-mips/paccess.h
+++ b/include/asm-mips/paccess.h
@@ -34,7 +34,7 @@ #define __mp(x) (*(struct __large_pstruc
 #define __get_dbe(x,ptr,size)						\
 ({									\
 	long __gu_err;							\
-	__typeof(*(ptr)) __gu_val;					\
+	__typeof__(*(ptr)) __gu_val;					\
 	unsigned long __gu_addr;					\
 	__asm__("":"=r" (__gu_val));					\
 	__gu_addr = (unsigned long) (ptr);				\
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 0d3295f..27d77d9 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -387,10 +387,6 @@ #define io_remap_pfn_range(vma, vaddr, p
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #include <asm-generic/pgtable.h>
 
 /*
diff --git a/include/asm-mips/scatterlist.h b/include/asm-mips/scatterlist.h
index 2263470..7af104c 100644
--- a/include/asm-mips/scatterlist.h
+++ b/include/asm-mips/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SCATTERLIST_H
 #define __ASM_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page *	page;
 	unsigned int	offset;
diff --git a/include/asm-mips/sgi/hpc3.h b/include/asm-mips/sgi/hpc3.h
index fcec52b..c4729f5 100644
--- a/include/asm-mips/sgi/hpc3.h
+++ b/include/asm-mips/sgi/hpc3.h
@@ -206,7 +206,7 @@ #define HPC3_ISTAT_SC1MASK	0x200	/* irq 
 #define HPC3_GIOMISC_ERTIME	0x1	/* Enable external timer real time. */
 #define HPC3_GIOMISC_DENDIAN	0x2	/* dma descriptor endian, 1=lit 0=big */
 
-	volatile u32 eeprom;		/* EEPROM data reg. */
+	u32 eeprom;			/* EEPROM data reg. */
 #define HPC3_EEPROM_EPROT	0x01	/* Protect register enable */
 #define HPC3_EEPROM_CSEL	0x02	/* Chip select */
 #define HPC3_EEPROM_ECLK	0x04	/* EEPROM clock */
diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h
index 6592f3b..f4981c4 100644
--- a/include/asm-mips/sgi/ip22.h
+++ b/include/asm-mips/sgi/ip22.h
@@ -72,7 +72,7 @@ #define SGI_SERIAL_IRQ	SGINT_LOCAL2 + 5	
 
 #define ip22_is_fullhouse()	(sgioc->sysid & SGIOC_SYSID_FULLHOUSE)
 
-extern unsigned short ip22_eeprom_read(volatile unsigned int *ctrl, int reg);
+extern unsigned short ip22_eeprom_read(unsigned int *ctrl, int reg);
 extern unsigned short ip22_nvram_read(int reg);
 
 #endif
diff --git a/include/asm-mips/sgi/mc.h b/include/asm-mips/sgi/mc.h
index c52f783..1576c23 100644
--- a/include/asm-mips/sgi/mc.h
+++ b/include/asm-mips/sgi/mc.h
@@ -57,7 +57,7 @@ #define SGIMC_SYSID_EPRESENT	0x00000010 
 	volatile u32 divider;	/* Divider reg for RPSS */
 
 	u32 _unused5;
-	volatile u32 eeprom;	/* EEPROM byte reg for r4k */
+	u32 eeprom;		/* EEPROM byte reg for r4k */
 #define SGIMC_EEPROM_PRE	0x00000001 /* eeprom chip PRE pin assertion */
 #define SGIMC_EEPROM_CSEL	0x00000002 /* Active high, eeprom chip select */
 #define SGIMC_EEPROM_SECLOCK	0x00000004 /* EEPROM serial clock */
diff --git a/include/asm-mips/sibyte/bcm1480_int.h b/include/asm-mips/sibyte/bcm1480_int.h
index 42d4cf0..c0d5206 100644
--- a/include/asm-mips/sibyte/bcm1480_int.h
+++ b/include/asm-mips/sibyte/bcm1480_int.h
@@ -157,6 +157,7 @@ #define K_BCM1480_INT_GPIO_15           
  * Mask values for each interrupt
  */
 
+#define _BCM1480_INT_MASK(w,n)              _SB_MAKEMASK(w,((n) & 0x3F))
 #define _BCM1480_INT_MASK1(n)               _SB_MAKEMASK1(((n) & 0x3F))
 #define _BCM1480_INT_OFFSET(n)              (((n) & 0x40) << 6)
 
@@ -195,6 +196,7 @@ #define M_BCM1480_INT_PMI_LOW           
 #define M_BCM1480_INT_PMI_HIGH              _BCM1480_INT_MASK1(K_BCM1480_INT_PMI_HIGH)
 #define M_BCM1480_INT_PMO_LOW               _BCM1480_INT_MASK1(K_BCM1480_INT_PMO_LOW)
 #define M_BCM1480_INT_PMO_HIGH              _BCM1480_INT_MASK1(K_BCM1480_INT_PMO_HIGH)
+#define M_BCM1480_INT_MBOX_ALL              _BCM1480_INT_MASK(8,K_BCM1480_INT_MBOX_0_0)
 #define M_BCM1480_INT_MBOX_0_0              _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_0)
 #define M_BCM1480_INT_MBOX_0_1              _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_1)
 #define M_BCM1480_INT_MBOX_0_2              _BCM1480_INT_MASK1(K_BCM1480_INT_MBOX_0_2)
diff --git a/include/asm-mips/sibyte/bcm1480_mc.h b/include/asm-mips/sibyte/bcm1480_mc.h
index 6bdc941..a6a4374 100644
--- a/include/asm-mips/sibyte/bcm1480_mc.h
+++ b/include/asm-mips/sibyte/bcm1480_mc.h
@@ -382,6 +382,10 @@ #define M_BCM1480_MC_CS5                
 #define M_BCM1480_MC_CS6                    _SB_MAKEMASK1(10)
 #define M_BCM1480_MC_CS7                    _SB_MAKEMASK1(11)
 
+#define M_BCM1480_MC_CS                  _SB_MAKEMASK(8,S_BCM1480_MC_CS0)
+#define V_BCM1480_MC_CS(x)               _SB_MAKEVALUE(x,S_BCM1480_MC_CS0)
+#define G_BCM1480_MC_CS(x)               _SB_GETVALUE(x,S_BCM1480_MC_CS0,M_BCM1480_MC_CS0)
+
 #define M_BCM1480_MC_CMD_ACTIVE             _SB_MAKEMASK1(16)
 
 /*
@@ -412,6 +416,8 @@ #if SIBYTE_HDR_FEATURE(1480, PASS2)
 #define K_BCM1480_MC_DRAM_TYPE_DDR2	    2
 #endif
 
+#define K_BCM1480_MC_DRAM_TYPE_DDR2_PASS1   0
+
 #define V_BCM1480_MC_DRAM_TYPE_JEDEC        V_BCM1480_MC_DRAM_TYPE(K_BCM1480_MC_DRAM_TYPE_JEDEC)
 #define V_BCM1480_MC_DRAM_TYPE_FCRAM        V_BCM1480_MC_DRAM_TYPE(K_BCM1480_MC_DRAM_TYPE_FCRAM)
 
@@ -511,6 +517,22 @@ #define M_BCM1480_MC_WR_ODT6_CS4	    _SB
 #define M_BCM1480_MC_WR_ODT6_CS6	    _SB_MAKEMASK1(31)
 
 #define M_BCM1480_MC_CS_ODD_ODT_EN	    _SB_MAKEMASK1(32)
+
+#define S_BCM1480_MC_ODT0	            0
+#define M_BCM1480_MC_ODT0		    _SB_MAKEMASK(8,S_BCM1480_MC_ODT0)
+#define V_BCM1480_MC_ODT0(x)		    _SB_MAKEVALUE(x,S_BCM1480_MC_ODT0)
+
+#define S_BCM1480_MC_ODT2	            8
+#define M_BCM1480_MC_ODT2		    _SB_MAKEMASK(8,S_BCM1480_MC_ODT2)
+#define V_BCM1480_MC_ODT2(x)		    _SB_MAKEVALUE(x,S_BCM1480_MC_ODT2)
+
+#define S_BCM1480_MC_ODT4	            16
+#define M_BCM1480_MC_ODT4		    _SB_MAKEMASK(8,S_BCM1480_MC_ODT4)
+#define V_BCM1480_MC_ODT4(x)		    _SB_MAKEVALUE(x,S_BCM1480_MC_ODT4)
+
+#define S_BCM1480_MC_ODT6	            24
+#define M_BCM1480_MC_ODT6		    _SB_MAKEMASK(8,S_BCM1480_MC_ODT6)
+#define V_BCM1480_MC_ODT6(x)		    _SB_MAKEVALUE(x,S_BCM1480_MC_ODT6)
 #endif
 
 /*
@@ -588,11 +610,11 @@ #define	M_BCM1480_MC_DLL_REGBYPASS      
 #define	M_BCM1480_MC_DQO_SHIFT            _SB_MAKEMASK1(47)
 #endif
 
-#define S_BCM1480_MC_DLL_DEFAULT            48
-#define M_BCM1480_MC_DLL_DEFAULT            _SB_MAKEMASK(6,S_BCM1480_MC_DLL_DEFAULT)
-#define V_BCM1480_MC_DLL_DEFAULT(x)         _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_DEFAULT)
-#define G_BCM1480_MC_DLL_DEFAULT(x)         _SB_GETVALUE(x,S_BCM1480_MC_DLL_DEFAULT,M_BCM1480_MC_DLL_DEFAULT)
-#define V_BCM1480_MC_DLL_DEFAULT_DEFAULT    V_BCM1480_MC_DLL_DEFAULT(0x10)
+#define S_BCM1480_MC_DLL_DEFAULT           48
+#define M_BCM1480_MC_DLL_DEFAULT           _SB_MAKEMASK(6,S_BCM1480_MC_DLL_DEFAULT)
+#define V_BCM1480_MC_DLL_DEFAULT(x)        _SB_MAKEVALUE(x,S_BCM1480_MC_DLL_DEFAULT)
+#define G_BCM1480_MC_DLL_DEFAULT(x)        _SB_GETVALUE(x,S_BCM1480_MC_DLL_DEFAULT,M_BCM1480_MC_DLL_DEFAULT)
+#define V_BCM1480_MC_DLL_DEFAULT_DEFAULT   V_BCM1480_MC_DLL_DEFAULT(0x10)
 
 #if SIBYTE_HDR_FEATURE(1480, PASS2)
 #define S_BCM1480_MC_DLL_REGCTRL	  54
diff --git a/include/asm-mips/sibyte/bcm1480_regs.h b/include/asm-mips/sibyte/bcm1480_regs.h
index c2dd2fe..bda391d 100644
--- a/include/asm-mips/sibyte/bcm1480_regs.h
+++ b/include/asm-mips/sibyte/bcm1480_regs.h
@@ -230,6 +230,7 @@ #define R_BCM1480_DUART_ISRREG(chan)	   
 
 #define A_BCM1480_DUART_IMRREG(chan)	    (A_BCM1480_DUART(chan) + R_BCM1480_DUART_IMRREG(chan))
 #define A_BCM1480_DUART_ISRREG(chan)	    (A_BCM1480_DUART(chan) + R_BCM1480_DUART_ISRREG(chan))
+#define A_BCM1480_DUART_IN_PORT(chan)       (A_BCM1480_DUART(chan) + R_DUART_INP_ORT)
 
 /*
  * These constants are the absolute addresses.
@@ -404,6 +405,21 @@ #define A_BCM1480_IMR_ALIAS_MAILBOX_REGI
 #define R_BCM1480_IMR_ALIAS_MAILBOX_0           0x0000		/* 0x0x0 */
 #define R_BCM1480_IMR_ALIAS_MAILBOX_0_SET       0x0008		/* 0x0x8 */
 
+/*
+ * these macros work together to build the address of a mailbox
+ * register, e.g., A_BCM1480_MAILBOX_REGISTER(0,R_BCM1480_IMR_MAILBOX_SET,2)
+ * for mbox_0_set_cpu2 returns 0x00100240C8
+ */
+#define R_BCM1480_IMR_MAILBOX_CPU         0x00
+#define R_BCM1480_IMR_MAILBOX_SET         0x08
+#define R_BCM1480_IMR_MAILBOX_CLR         0x10
+#define R_BCM1480_IMR_MAILBOX_NUM_SPACING 0x20
+#define A_BCM1480_MAILBOX_REGISTER(num,reg,cpu) \
+    (A_BCM1480_IMR_CPU0_BASE + \
+     (num * R_BCM1480_IMR_MAILBOX_NUM_SPACING) + \
+     (cpu * BCM1480_IMR_REGISTER_SPACING) + \
+     (R_BCM1480_IMR_MAILBOX_0_CPU + reg))
+
 /*  *********************************************************************
     * System Performance Counter Registers (Section 4.7)
     ********************************************************************* */
@@ -428,6 +444,10 @@ #define A_BCM1480_SCD_PERF_CNT_5        
 #define A_BCM1480_SCD_PERF_CNT_6            0x0010020500
 #define A_BCM1480_SCD_PERF_CNT_7            0x0010020508
 
+#define BCM1480_SCD_NUM_PERF_CNT 8
+#define BCM1480_SCD_PERF_CNT_SPACING 8
+#define A_BCM1480_SCD_PERF_CNT(n) (A_SCD_PERF_CNT_0+(n*BCM1480_SCD_PERF_CNT_SPACING))
+
 /*  *********************************************************************
     * System Bus Watcher Registers (Section 4.8)
     ********************************************************************* */
diff --git a/include/asm-mips/sibyte/bcm1480_scd.h b/include/asm-mips/sibyte/bcm1480_scd.h
index 648bed9..6111d6d 100644
--- a/include/asm-mips/sibyte/bcm1480_scd.h
+++ b/include/asm-mips/sibyte/bcm1480_scd.h
@@ -10,7 +10,7 @@
     *
     *********************************************************************
     *
-    *  Copyright 2000,2001,2002,2003
+    *  Copyright 2000,2001,2002,2003,2004,2005
     *  Broadcom Corporation. All rights reserved.
     *
     *  This program is free software; you can redistribute it and/or
@@ -78,6 +78,7 @@ #define K_SYS_PART_BCM1480          0x14
 #define K_SYS_PART_BCM1280          0x1206
 #define K_SYS_PART_BCM1455          0x1407
 #define K_SYS_PART_BCM1255          0x1257
+#define K_SYS_PART_BCM1158          0x1156
 
 /*
  * Manufacturing Information Register (Table 14)
@@ -237,58 +238,42 @@ #define M_BCM1480_SCD_WDOG_HAS_RESET    
  * System Performance Counter Configuration Register (Table 31)
  * Register: PERF_CNT_CFG_0
  *
- * Since the clear/enable bits are moved compared to the
- * 1250 and there are more fields, this register will be BCM1480 specific.
+ * SPC_CFG_SRC[0-3] is the same as the 1250.
+ * SPC_CFG_SRC[4-7] only exist on the 1480
+ * The clear/enable bits are in different locations on the 1250 and 1480.
  */
 
-#define S_BCM1480_SPC_CFG_SRC0              0
-#define M_BCM1480_SPC_CFG_SRC0              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC0)
-#define V_BCM1480_SPC_CFG_SRC0(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC0)
-#define G_BCM1480_SPC_CFG_SRC0(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC0,M_BCM1480_SPC_CFG_SRC0)
-
-#define S_BCM1480_SPC_CFG_SRC1              8
-#define M_BCM1480_SPC_CFG_SRC1              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC1)
-#define V_BCM1480_SPC_CFG_SRC1(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC1)
-#define G_BCM1480_SPC_CFG_SRC1(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC1,M_BCM1480_SPC_CFG_SRC1)
-
-#define S_BCM1480_SPC_CFG_SRC2              16
-#define M_BCM1480_SPC_CFG_SRC2              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC2)
-#define V_BCM1480_SPC_CFG_SRC2(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC2)
-#define G_BCM1480_SPC_CFG_SRC2(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC2,M_BCM1480_SPC_CFG_SRC2)
-
-#define S_BCM1480_SPC_CFG_SRC3              24
-#define M_BCM1480_SPC_CFG_SRC3              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC3)
-#define V_BCM1480_SPC_CFG_SRC3(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC3)
-#define G_BCM1480_SPC_CFG_SRC3(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC3,M_BCM1480_SPC_CFG_SRC3)
-
-#define S_BCM1480_SPC_CFG_SRC4              32
-#define M_BCM1480_SPC_CFG_SRC4              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC4)
-#define V_BCM1480_SPC_CFG_SRC4(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC4)
-#define G_BCM1480_SPC_CFG_SRC4(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC4,M_BCM1480_SPC_CFG_SRC4)
-
-#define S_BCM1480_SPC_CFG_SRC5              40
-#define M_BCM1480_SPC_CFG_SRC5              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC5)
-#define V_BCM1480_SPC_CFG_SRC5(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC5)
-#define G_BCM1480_SPC_CFG_SRC5(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC5,M_BCM1480_SPC_CFG_SRC5)
-
-#define S_BCM1480_SPC_CFG_SRC6              48
-#define M_BCM1480_SPC_CFG_SRC6              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC6)
-#define V_BCM1480_SPC_CFG_SRC6(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC6)
-#define G_BCM1480_SPC_CFG_SRC6(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC6,M_BCM1480_SPC_CFG_SRC6)
-
-#define S_BCM1480_SPC_CFG_SRC7              56
-#define M_BCM1480_SPC_CFG_SRC7              _SB_MAKEMASK(8,S_BCM1480_SPC_CFG_SRC7)
-#define V_BCM1480_SPC_CFG_SRC7(x)           _SB_MAKEVALUE(x,S_BCM1480_SPC_CFG_SRC7)
-#define G_BCM1480_SPC_CFG_SRC7(x)           _SB_GETVALUE(x,S_BCM1480_SPC_CFG_SRC7,M_BCM1480_SPC_CFG_SRC7)
+#define S_SPC_CFG_SRC4              32
+#define M_SPC_CFG_SRC4              _SB_MAKEMASK(8,S_SPC_CFG_SRC4)
+#define V_SPC_CFG_SRC4(x)           _SB_MAKEVALUE(x,S_SPC_CFG_SRC4)
+#define G_SPC_CFG_SRC4(x)           _SB_GETVALUE(x,S_SPC_CFG_SRC4,M_SPC_CFG_SRC4)
+
+#define S_SPC_CFG_SRC5              40
+#define M_SPC_CFG_SRC5              _SB_MAKEMASK(8,S_SPC_CFG_SRC5)
+#define V_SPC_CFG_SRC5(x)           _SB_MAKEVALUE(x,S_SPC_CFG_SRC5)
+#define G_SPC_CFG_SRC5(x)           _SB_GETVALUE(x,S_SPC_CFG_SRC5,M_SPC_CFG_SRC5)
+
+#define S_SPC_CFG_SRC6              48
+#define M_SPC_CFG_SRC6              _SB_MAKEMASK(8,S_SPC_CFG_SRC6)
+#define V_SPC_CFG_SRC6(x)           _SB_MAKEVALUE(x,S_SPC_CFG_SRC6)
+#define G_SPC_CFG_SRC6(x)           _SB_GETVALUE(x,S_SPC_CFG_SRC6,M_SPC_CFG_SRC6)
+
+#define S_SPC_CFG_SRC7              56
+#define M_SPC_CFG_SRC7              _SB_MAKEMASK(8,S_SPC_CFG_SRC7)
+#define V_SPC_CFG_SRC7(x)           _SB_MAKEVALUE(x,S_SPC_CFG_SRC7)
+#define G_SPC_CFG_SRC7(x)           _SB_GETVALUE(x,S_SPC_CFG_SRC7,M_SPC_CFG_SRC7)
 
 /*
  * System Performance Counter Control Register (Table 32)
  * Register: PERF_CNT_CFG_1
  * BCM1480 specific
  */
-
-#define M_BCM1480_SPC_CFG_CLEAR             _SB_MAKEMASK1(0)
-#define M_BCM1480_SPC_CFG_ENABLE            _SB_MAKEMASK1(1)
+#define M_BCM1480_SPC_CFG_CLEAR     _SB_MAKEMASK1(0)
+#define M_BCM1480_SPC_CFG_ENABLE    _SB_MAKEMASK1(1)
+#if SIBYTE_HDR_FEATURE_CHIP(1480)
+#define M_SPC_CFG_CLEAR			M_BCM1480_SPC_CFG_CLEAR
+#define M_SPC_CFG_ENABLE		M_BCM1480_SPC_CFG_ENABLE
+#endif
 
 /*
  * System Performance Counters (Table 33)
@@ -405,20 +390,10 @@ #define G_BCM1480_SCD_TRSEQ_SWFUNC(x)   
  * Trace Control Register (Table 49)
  * Register: TRACE_CFG
  *
- * Bits 0..8 are the same as the BCM1250, rest are different.
- * Entire register is redefined below.
+ * BCM1480 changes to this register (other than location of the CUR_ADDR field)
+ * are defined below.
  */
 
-#define M_BCM1480_SCD_TRACE_CFG_RESET       _SB_MAKEMASK1(0)
-#define M_BCM1480_SCD_TRACE_CFG_START_READ  _SB_MAKEMASK1(1)
-#define M_BCM1480_SCD_TRACE_CFG_START       _SB_MAKEMASK1(2)
-#define M_BCM1480_SCD_TRACE_CFG_STOP        _SB_MAKEMASK1(3)
-#define M_BCM1480_SCD_TRACE_CFG_FREEZE      _SB_MAKEMASK1(4)
-#define M_BCM1480_SCD_TRACE_CFG_FREEZE_FULL _SB_MAKEMASK1(5)
-#define M_BCM1480_SCD_TRACE_CFG_DEBUG_FULL  _SB_MAKEMASK1(6)
-#define M_BCM1480_SCD_TRACE_CFG_FULL        _SB_MAKEMASK1(7)
-#define M_BCM1480_SCD_TRACE_CFG_FORCE_CNT   _SB_MAKEMASK1(8)
-
 #define S_BCM1480_SCD_TRACE_CFG_MODE        16
 #define M_BCM1480_SCD_TRACE_CFG_MODE        _SB_MAKEMASK(2,S_BCM1480_SCD_TRACE_CFG_MODE)
 #define V_BCM1480_SCD_TRACE_CFG_MODE(x)     _SB_MAKEVALUE(x,S_BCM1480_SCD_TRACE_CFG_MODE)
@@ -428,9 +403,4 @@ #define K_BCM1480_SCD_TRACE_CFG_MODE_BLO
 #define K_BCM1480_SCD_TRACE_CFG_MODE_BYTEEN_INT	1
 #define K_BCM1480_SCD_TRACE_CFG_MODE_FLOW_ID	2
 
-#define S_BCM1480_SCD_TRACE_CFG_CUR_ADDR    24
-#define M_BCM1480_SCD_TRACE_CFG_CUR_ADDR    _SB_MAKEMASK(8,S_BCM1480_SCD_TRACE_CFG_CUR_ADDR)
-#define V_BCM1480_SCD_TRACE_CFG_CUR_ADDR(x) _SB_MAKEVALUE(x,S_BCM1480_SCD_TRACE_CFG_CUR_ADDR)
-#define G_BCM1480_SCD_TRACE_CFG_CUR_ADDR(x) _SB_GETVALUE(x,S_BCM1480_SCD_TRACE_CFG_CUR_ADDR,M_BCM1480_SCD_TRACE_CFG_CUR_ADDR)
-
 #endif /* _BCM1480_SCD_H */
diff --git a/include/asm-mips/sibyte/board.h b/include/asm-mips/sibyte/board.h
index 3dfe29e..73bce90 100644
--- a/include/asm-mips/sibyte/board.h
+++ b/include/asm-mips/sibyte/board.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2002, 2003 Broadcom Corporation
+ * 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
@@ -19,8 +19,8 @@
 #ifndef _SIBYTE_BOARD_H
 #define _SIBYTE_BOARD_H
 
-
 #if defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_PTSWARM) || \
+    defined(CONFIG_SIBYTE_PT1120) || defined(CONFIG_SIBYTE_PT1125) || \
     defined(CONFIG_SIBYTE_CRHONE) || defined(CONFIG_SIBYTE_CRHINE) || \
     defined(CONFIG_SIBYTE_LITTLESUR)
 #include <asm/sibyte/swarm.h>
@@ -55,6 +55,16 @@ #else
 #define setleds(t0,t1,c0,c1,c2,c3)
 #endif /* LEDS_PHYS */
 
+#else
+
+void swarm_setup(void);
+
+#ifdef LEDS_PHYS
+extern void setleds(char *str);
+#else
+#define setleds(s) do { } while (0)
+#endif /* LEDS_PHYS */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _SIBYTE_BOARD_H */
diff --git a/include/asm-mips/sibyte/carmel.h b/include/asm-mips/sibyte/carmel.h
index 57c53e6..11cad71 100644
--- a/include/asm-mips/sibyte/carmel.h
+++ b/include/asm-mips/sibyte/carmel.h
@@ -18,7 +18,6 @@
 #ifndef __ASM_SIBYTE_CARMEL_H
 #define __ASM_SIBYTE_CARMEL_H
 
-
 #include <asm/sibyte/sb1250.h>
 #include <asm/sibyte/sb1250_int.h>
 
diff --git a/include/asm-mips/sibyte/sb1250_int.h b/include/asm-mips/sibyte/sb1250_int.h
index 05c7b39..94e8299 100644
--- a/include/asm-mips/sibyte/sb1250_int.h
+++ b/include/asm-mips/sibyte/sb1250_int.h
@@ -45,8 +45,6 @@ #include "sb1250_defs.h"
  * First, the interrupt numbers.
  */
 
-#if SIBYTE_HDR_FEATURE_1250_112x
-
 #define K_INT_SOURCES               64
 
 #define K_INT_WATCHDOG_TIMER_0      0
@@ -152,6 +150,7 @@ #define M_INT_MBOX_0                _SB_
 #define M_INT_MBOX_1                _SB_MAKEMASK1(K_INT_MBOX_1)
 #define M_INT_MBOX_2                _SB_MAKEMASK1(K_INT_MBOX_2)
 #define M_INT_MBOX_3                _SB_MAKEMASK1(K_INT_MBOX_3)
+#define M_INT_MBOX_ALL              _SB_MAKEMASK(4,K_INT_MBOX_0)
 #if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
 #define M_INT_CYCLE_CP0_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP0_INT)
 #define M_INT_CYCLE_CP1_INT	    _SB_MAKEMASK1(K_INT_CYCLE_CP1_INT)
@@ -247,5 +246,3 @@ #define M_LDTVECT_RAISEMBOX             
 
 
 #endif	/* 1250/112x */
-
-#endif
diff --git a/include/asm-mips/sibyte/sb1250_mac.h b/include/asm-mips/sibyte/sb1250_mac.h
index adfc688..833c8b5 100644
--- a/include/asm-mips/sibyte/sb1250_mac.h
+++ b/include/asm-mips/sibyte/sb1250_mac.h
@@ -129,9 +129,9 @@ #define K_MAC_BYPASS_EOP            3
 #define M_MAC_BYPASS_16             _SB_MAKEMASK1(42)
 #define M_MAC_BYPASS_FCS_CHK	    _SB_MAKEMASK1(43)
 
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_RX_CH_SEL_MSB	    _SB_MAKEMASK1(44)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480*/
 
 #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_SPLIT_CH_SEL	    _SB_MAKEMASK1(45)
@@ -223,9 +223,9 @@ #if SIBYTE_HDR_FEATURE_UP_TO(1250, PASS1
 /* XXX: Can't enable, as it has the same name as a pass2+ define below.  */
 /* #define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(6,S_MAC_TX_WR_THRSH) */
 #endif /* up to 1250 PASS1 */
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_TX_WR_THRSH           _SB_MAKEMASK(7,S_MAC_TX_WR_THRSH)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 #define V_MAC_TX_WR_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_WR_THRSH)
 #define G_MAC_TX_WR_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_WR_THRSH,M_MAC_TX_WR_THRSH)
 
@@ -234,9 +234,9 @@ #if SIBYTE_HDR_FEATURE_UP_TO(1250, PASS1
 /* XXX: Can't enable, as it has the same name as a pass2+ define below.  */
 /* #define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(6,S_MAC_TX_RD_THRSH) */
 #endif /* up to 1250 PASS1 */
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_TX_RD_THRSH           _SB_MAKEMASK(7,S_MAC_TX_RD_THRSH)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 #define V_MAC_TX_RD_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_TX_RD_THRSH)
 #define G_MAC_TX_RD_THRSH(x)        _SB_GETVALUE(x,S_MAC_TX_RD_THRSH,M_MAC_TX_RD_THRSH)
 
@@ -260,12 +260,12 @@ #define M_MAC_RX_RL_THRSH           _SB_
 #define V_MAC_RX_RL_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_RX_RL_THRSH)
 #define G_MAC_RX_RL_THRSH(x)        _SB_GETVALUE(x,S_MAC_RX_RL_THRSH,M_MAC_RX_RL_THRSH)
 
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define S_MAC_ENC_FC_THRSH           _SB_MAKE64(56)
 #define M_MAC_ENC_FC_THRSH           _SB_MAKEMASK(6,S_MAC_ENC_FC_THRSH)
 #define V_MAC_ENC_FC_THRSH(x)        _SB_MAKEVALUE(x,S_MAC_ENC_FC_THRSH)
 #define G_MAC_ENC_FC_THRSH(x)        _SB_GETVALUE(x,S_MAC_ENC_FC_THRSH,M_MAC_ENC_FC_THRSH)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 
 /*
  * MAC Frame Configuration Registers (Table 9-15)
@@ -462,9 +462,9 @@ #define M_MAC_TX_OVRFL              _SB_
 #define M_MAC_LTCOL_ERR             _SB_MAKEMASK1(44)
 #define M_MAC_EXCOL_ERR             _SB_MAKEMASK1(45)
 #define M_MAC_CNTR_OVRFL_ERR        _SB_MAKEMASK1(46)
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_SPLIT_EN		    _SB_MAKEMASK1(47) 	/* interrupt mask only */
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 
 #define S_MAC_COUNTER_ADDR          _SB_MAKE64(47)
 #define M_MAC_COUNTER_ADDR          _SB_MAKEMASK(5,S_MAC_COUNTER_ADDR)
@@ -598,9 +598,9 @@ #define M_MAC_MCAST_EN          _SB_MAKE
 #define M_MAC_MCAST_INV         _SB_MAKEMASK1(4)
 #define M_MAC_BCAST_EN          _SB_MAKEMASK1(5)
 #define M_MAC_DIRECT_INV        _SB_MAKEMASK1(6)
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_MAC_ALLMCAST_EN	_SB_MAKEMASK1(7)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 
 #define S_MAC_IPHDR_OFFSET      _SB_MAKE64(8)
 #define M_MAC_IPHDR_OFFSET      _SB_MAKEMASK(8,S_MAC_IPHDR_OFFSET)
diff --git a/include/asm-mips/sibyte/sb1250_mc.h b/include/asm-mips/sibyte/sb1250_mc.h
index 26e4214..4fe848f 100644
--- a/include/asm-mips/sibyte/sb1250_mc.h
+++ b/include/asm-mips/sibyte/sb1250_mc.h
@@ -295,7 +295,7 @@ #define M_MC_EXTERNALDECODE	    _SB_MAKE
 
 #if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1)
 #define M_MC_PRE_ON_A8              _SB_MAKEMASK1(36)
-#define M_MC_RAM_WITH_A13           _SB_MAKEMASK1(38)
+#define M_MC_RAM_WITH_A13           _SB_MAKEMASK1(37)
 #endif /* 1250 PASS3 || 112x PASS1 */
 
 
diff --git a/include/asm-mips/sibyte/sb1250_regs.h b/include/asm-mips/sibyte/sb1250_regs.h
index bab3a45..da7c188 100644
--- a/include/asm-mips/sibyte/sb1250_regs.h
+++ b/include/asm-mips/sibyte/sb1250_regs.h
@@ -131,6 +131,7 @@ #define A_L2_EEC_ADDRESS            A_L2
 
 #endif
 
+
 /*  *********************************************************************
     * PCI Interface Registers
     ********************************************************************* */
@@ -239,14 +240,14 @@ #define R_MAC_THRSH_CFG                 
 #define R_MAC_VLANTAG                   0x00000110
 #define R_MAC_FRAMECFG                  0x00000118
 #define R_MAC_EOPCNT                    0x00000120
-#define R_MAC_FIFO_PTRS                 0x00000130
+#define R_MAC_FIFO_PTRS                 0x00000128
 #define R_MAC_ADFILTER_CFG              0x00000200
 #define R_MAC_ETHERNET_ADDR             0x00000208
 #define R_MAC_PKT_TYPE                  0x00000210
-#if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS3) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define R_MAC_ADMASK0			0x00000218
 #define R_MAC_ADMASK1			0x00000220
-#endif /* 1250 PASS3 || 112x PASS1 */
+#endif /* 1250 PASS3 || 112x PASS1 || 1480 */
 #define R_MAC_HASH_BASE                 0x00000240
 #define R_MAC_ADDR_BASE                 0x00000280
 #define R_MAC_CHLO0_BASE                0x00000300
@@ -256,9 +257,9 @@ #define R_MAC_STATUS                    
 #define R_MAC_INT_MASK                  0x00000410
 #define R_MAC_TXD_CTL                   0x00000420
 #define R_MAC_MDIO                      0x00000428
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define R_MAC_STATUS1		        0x00000430
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 #define R_MAC_DEBUG_STATUS              0x00000448
 
 #define MAC_HASH_COUNT			8
@@ -289,11 +290,11 @@ #define R_DUART_CMD                 0x15
 #define R_DUART_RX_HOLD             0x160
 #define R_DUART_TX_HOLD             0x170
 
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define R_DUART_FULL_CTL	    0x140
 #define R_DUART_OPCR_X		    0x180
 #define R_DUART_AUXCTL_X	    0x190
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480*/
 
 
 /*
@@ -308,6 +309,7 @@ #define R_DUART_ISR_B               0x34
 #define R_DUART_IMR_B               0x350
 #define R_DUART_OUT_PORT            0x360
 #define R_DUART_OPCR                0x370
+#define R_DUART_IN_PORT             0x380
 
 #define R_DUART_SET_OPR		    0x3B0
 #define R_DUART_CLEAR_OPR	    0x3C0
@@ -685,12 +687,17 @@ #if SIBYTE_HDR_FEATURE(1250, PASS2) || S
 #define A_ADDR_TRAP_REG_DEBUG	    0x0010020460
 #endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 
+#define ADDR_TRAP_SPACING 8
+#define NUM_ADDR_TRAP 4
+#define A_ADDR_TRAP_UP(n) (A_ADDR_TRAP_UP_0 + ((n) * ADDR_TRAP_SPACING))
+#define A_ADDR_TRAP_DOWN(n) (A_ADDR_TRAP_DOWN_0 + ((n) * ADDR_TRAP_SPACING))
+#define A_ADDR_TRAP_CFG(n) (A_ADDR_TRAP_CFG_0 + ((n) * ADDR_TRAP_SPACING))
+
 
 /*  *********************************************************************
     * System Interrupt Mapper Registers
     ********************************************************************* */
 
-#if SIBYTE_HDR_FEATURE_1250_112x
 #define A_IMR_CPU0_BASE                 0x0010020000
 #define A_IMR_CPU1_BASE                 0x0010022000
 #define IMR_REGISTER_SPACING            0x2000
@@ -700,6 +707,7 @@ #define A_IMR_MAPPER(cpu) (A_IMR_CPU0_BA
 #define A_IMR_REGISTER(cpu,reg) (A_IMR_MAPPER(cpu)+(reg))
 
 #define R_IMR_INTERRUPT_DIAG            0x0010
+#define R_IMR_INTERRUPT_LDT             0x0018
 #define R_IMR_INTERRUPT_MASK            0x0028
 #define R_IMR_INTERRUPT_TRACE           0x0038
 #define R_IMR_INTERRUPT_SOURCE_STATUS   0x0040
@@ -715,7 +723,14 @@ #define R_IMR_INTERRUPT_STATUS_BASE     
 #define R_IMR_INTERRUPT_STATUS_COUNT    7
 #define R_IMR_INTERRUPT_MAP_BASE        0x0200
 #define R_IMR_INTERRUPT_MAP_COUNT       64
-#endif	/* 1250/112x */
+
+/*
+ * these macros work together to build the address of a mailbox
+ * register, e.g., A_MAILBOX_REGISTER(R_IMR_MAILBOX_SET_CPU,1)
+ * for mbox_0_set_cpu2 returns 0x00100240C8
+ */
+#define A_MAILBOX_REGISTER(reg,cpu) \
+    (A_IMR_CPU0_BASE + (cpu * IMR_REGISTER_SPACING) + reg)
 
 /*  *********************************************************************
     * System Performance Counter Registers
@@ -727,6 +742,10 @@ #define A_SCD_PERF_CNT_1            0x00
 #define A_SCD_PERF_CNT_2            0x00100204E0
 #define A_SCD_PERF_CNT_3            0x00100204E8
 
+#define SCD_NUM_PERF_CNT 4
+#define SCD_PERF_CNT_SPACING 8
+#define A_SCD_PERF_CNT(n) (A_SCD_PERF_CNT_0+(n*SCD_PERF_CNT_SPACING))
+
 /*  *********************************************************************
     * System Bus Watcher Registers
     ********************************************************************* */
@@ -772,6 +791,15 @@ #define A_SCD_TRACE_SEQUENCE_5      0x00
 #define A_SCD_TRACE_SEQUENCE_6      0x0010020A90
 #define A_SCD_TRACE_SEQUENCE_7      0x0010020A98
 
+#define TRACE_REGISTER_SPACING 8
+#define TRACE_NUM_REGISTERS    8
+#define A_SCD_TRACE_EVENT(n) (((n) & 4) ? \
+   (A_SCD_TRACE_EVENT_4 + (((n) & 3) * TRACE_REGISTER_SPACING)) : \
+   (A_SCD_TRACE_EVENT_0 + ((n) * TRACE_REGISTER_SPACING)))
+#define A_SCD_TRACE_SEQUENCE(n) (((n) & 4) ? \
+   (A_SCD_TRACE_SEQUENCE_4 + (((n) & 3) * TRACE_REGISTER_SPACING)) : \
+   (A_SCD_TRACE_SEQUENCE_0 + ((n) * TRACE_REGISTER_SPACING)))
+
 /*  *********************************************************************
     * System Generic DMA Registers
     ********************************************************************* */
diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/include/asm-mips/sibyte/sb1250_scd.h
index b6a7d8f..9ea3da3 100644
--- a/include/asm-mips/sibyte/sb1250_scd.h
+++ b/include/asm-mips/sibyte/sb1250_scd.h
@@ -10,7 +10,7 @@
     *
     *********************************************************************
     *
-    *  Copyright 2000,2001,2002,2003
+    *  Copyright 2000,2001,2002,2003,2004,2005
     *  Broadcom Corporation. All rights reserved.
     *
     *  This program is free software; you can redistribute it and/or
@@ -150,7 +150,7 @@ #define K_SYS_SOC_TYPE_BCM1x55      0x7
  * (For the assembler version, sysrev and dest may be the same register.
  * Also, it clobbers AT.)
  */
-#ifdef __ASSEMBLY__
+#ifdef __ASSEMBLER__
 #define SYS_SOC_TYPE(dest, sysrev)					\
 	.set push ;							\
 	.set reorder ;							\
@@ -214,6 +214,7 @@ #define V_SYS_YPOS(x)             _SB_MA
 #define G_SYS_YPOS(x)             _SB_GETVALUE(x,S_SYS_YPOS,M_SYS_YPOS)
 #endif
 
+
 /*
  * System Config Register (Table 4-2)
  * Register: SCD_SYSTEM_CFG
@@ -360,13 +361,13 @@ #endif
  */
 
 #define V_SCD_TIMER_FREQ            1000000
-#define V_SCD_TIMER_WIDTH           23
 
 #define S_SCD_TIMER_INIT            0
-#define M_SCD_TIMER_INIT            _SB_MAKEMASK(V_SCD_TIMER_WIDTH,S_SCD_TIMER_INIT)
+#define M_SCD_TIMER_INIT            _SB_MAKEMASK(23,S_SCD_TIMER_INIT)
 #define V_SCD_TIMER_INIT(x)         _SB_MAKEVALUE(x,S_SCD_TIMER_INIT)
 #define G_SCD_TIMER_INIT(x)         _SB_GETVALUE(x,S_SCD_TIMER_INIT,M_SCD_TIMER_INIT)
 
+#define V_SCD_TIMER_WIDTH	    23
 #define S_SCD_TIMER_CNT             0
 #define M_SCD_TIMER_CNT             _SB_MAKEMASK(V_SCD_TIMER_WIDTH,S_SCD_TIMER_CNT)
 #define V_SCD_TIMER_CNT(x)         _SB_MAKEVALUE(x,S_SCD_TIMER_CNT)
@@ -380,7 +381,6 @@ #define M_SCD_TIMER_MODE_CONTINUOUS M_SC
  * System Performance Counters
  */
 
-#if SIBYTE_HDR_FEATURE_1250_112x
 #define S_SPC_CFG_SRC0            0
 #define M_SPC_CFG_SRC0            _SB_MAKEMASK(8,S_SPC_CFG_SRC0)
 #define V_SPC_CFG_SRC0(x)         _SB_MAKEVALUE(x,S_SPC_CFG_SRC0)
@@ -401,6 +401,7 @@ #define M_SPC_CFG_SRC3            _SB_MA
 #define V_SPC_CFG_SRC3(x)         _SB_MAKEVALUE(x,S_SPC_CFG_SRC3)
 #define G_SPC_CFG_SRC3(x)         _SB_GETVALUE(x,S_SPC_CFG_SRC3,M_SPC_CFG_SRC3)
 
+#if SIBYTE_HDR_FEATURE_1250_112x
 #define M_SPC_CFG_CLEAR		_SB_MAKEMASK1(32)
 #define M_SPC_CFG_ENABLE	_SB_MAKEMASK1(33)
 #endif
@@ -516,8 +517,6 @@ #endif	/* 1250/112x */
  * Trace Buffer Config register
  */
 
-#if SIBYTE_HDR_FEATURE_1250_112x
-
 #define M_SCD_TRACE_CFG_RESET           _SB_MAKEMASK1(0)
 #define M_SCD_TRACE_CFG_START_READ      _SB_MAKEMASK1(1)
 #define M_SCD_TRACE_CFG_START           _SB_MAKEMASK1(2)
@@ -526,17 +525,26 @@ #define M_SCD_TRACE_CFG_FREEZE          
 #define M_SCD_TRACE_CFG_FREEZE_FULL     _SB_MAKEMASK1(5)
 #define M_SCD_TRACE_CFG_DEBUG_FULL      _SB_MAKEMASK1(6)
 #define M_SCD_TRACE_CFG_FULL            _SB_MAKEMASK1(7)
-#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1)
+#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
 #define M_SCD_TRACE_CFG_FORCECNT        _SB_MAKEMASK1(8)
-#endif /* 1250 PASS2 || 112x PASS1 */
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
 
+/*
+ * This field is the same on the 1250/112x and 1480, just located in
+ * a slightly different place in the register.
+ */
+#if SIBYTE_HDR_FEATURE_1250_112x
 #define S_SCD_TRACE_CFG_CUR_ADDR        10
+#else
+#if SIBYTE_HDR_FEATURE_CHIP(1480)
+#define S_SCD_TRACE_CFG_CUR_ADDR        24
+#endif	/* 1480 */
+#endif  /* 1250/112x */
+
 #define M_SCD_TRACE_CFG_CUR_ADDR        _SB_MAKEMASK(8,S_SCD_TRACE_CFG_CUR_ADDR)
 #define V_SCD_TRACE_CFG_CUR_ADDR(x)     _SB_MAKEVALUE(x,S_SCD_TRACE_CFG_CUR_ADDR)
 #define G_SCD_TRACE_CFG_CUR_ADDR(x)     _SB_GETVALUE(x,S_SCD_TRACE_CFG_CUR_ADDR,M_SCD_TRACE_CFG_CUR_ADDR)
 
-#endif	/* 1250/112x */
-
 /*
  * Trace Event registers
  */
diff --git a/include/asm-mips/sibyte/swarm.h b/include/asm-mips/sibyte/swarm.h
index 86db37e..540865f 100644
--- a/include/asm-mips/sibyte/swarm.h
+++ b/include/asm-mips/sibyte/swarm.h
@@ -32,6 +32,18 @@ #define SIBYTE_HAVE_PCMCIA 1
 #define SIBYTE_HAVE_IDE    1
 #define SIBYTE_DEFAULT_CONSOLE "ttyS0,115200"
 #endif
+#ifdef CONFIG_SIBYTE_PT1120
+#define SIBYTE_BOARD_NAME "PT1120"
+#define SIBYTE_HAVE_PCMCIA 1
+#define SIBYTE_HAVE_IDE    1
+#define SIBYTE_DEFAULT_CONSOLE "ttyS0,115200"
+#endif
+#ifdef CONFIG_SIBYTE_PT1125
+#define SIBYTE_BOARD_NAME "PT1125"
+#define SIBYTE_HAVE_PCMCIA 1
+#define SIBYTE_HAVE_IDE    1
+#define SIBYTE_DEFAULT_CONSOLE "ttyS0,115200"
+#endif
 #ifdef CONFIG_SIBYTE_LITTLESUR
 #define SIBYTE_BOARD_NAME "BCM91250C2 (LittleSur)"
 #define SIBYTE_HAVE_PCMCIA 0
diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h
index 36ebe4e..9594568 100644
--- a/include/asm-mips/socket.h
+++ b/include/asm-mips/socket.h
@@ -70,6 +70,8 @@ #define SO_PEERSEC		30
 #define SO_SNDBUFFORCE		31
 #define SO_RCVBUFFORCE		33
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #ifdef __KERNEL__
 
diff --git a/include/asm-mips/sockios.h b/include/asm-mips/sockios.h
index 87a50bf..ed1a5f7 100644
--- a/include/asm-mips/sockios.h
+++ b/include/asm-mips/sockios.h
@@ -20,6 +20,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* _ASM_SOCKIOS_H */
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 2908870..30f23a2 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -201,7 +201,6 @@ static inline unsigned long __xchg(unsig
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 #define __HAVE_ARCH_CMPXCHG 1
 
@@ -262,6 +261,58 @@ static inline unsigned long __cmpxchg_u3
 	return retval;
 }
 
+static inline unsigned long __cmpxchg_u32_local(volatile int * m,
+	unsigned long old, unsigned long new)
+{
+	__u32 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	ll	%0, %2			# __cmpxchg_u32	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	.set	mips0					\n"
+		"	move	$1, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	$1, %1					\n"
+		"	beqzl	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	ll	%0, %2			# __cmpxchg_u32	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	.set	mips0					\n"
+		"	move	$1, %z4					\n"
+		"	.set	mips3					\n"
+		"	sc	$1, %1					\n"
+		"	beqz	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		retval = *m;
+		if (retval == old)
+			*m = new;
+		local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	return retval;
+}
+
 #ifdef CONFIG_64BIT
 static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
 	unsigned long new)
@@ -315,10 +366,62 @@ static inline unsigned long __cmpxchg_u6
 
 	return retval;
 }
+
+static inline unsigned long __cmpxchg_u64_local(volatile int * m,
+	unsigned long old, unsigned long new)
+{
+	__u64 retval;
+
+	if (cpu_has_llsc && R10000_LLSC_WAR) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	lld	%0, %2			# __cmpxchg_u64	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	move	$1, %z4					\n"
+		"	scd	$1, %1					\n"
+		"	beqzl	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else if (cpu_has_llsc) {
+		__asm__ __volatile__(
+		"	.set	push					\n"
+		"	.set	noat					\n"
+		"	.set	mips3					\n"
+		"1:	lld	%0, %2			# __cmpxchg_u64	\n"
+		"	bne	%0, %z3, 2f				\n"
+		"	move	$1, %z4					\n"
+		"	scd	$1, %1					\n"
+		"	beqz	$1, 1b					\n"
+		"2:							\n"
+		"	.set	pop					\n"
+		: "=&r" (retval), "=R" (*m)
+		: "R" (*m), "Jr" (old), "Jr" (new)
+		: "memory");
+	} else {
+		unsigned long flags;
+
+		local_irq_save(flags);
+		retval = *m;
+		if (retval == old)
+			*m = new;
+		local_irq_restore(flags);	/* implies memory barrier  */
+	}
+
+	return retval;
+}
+
 #else
 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
+extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels(
+	volatile int * m, unsigned long old, unsigned long new);
+#define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -338,7 +441,26 @@ static inline unsigned long __cmpxchg(vo
 	return old;
 }
 
-#define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+static inline unsigned long __cmpxchg_local(volatile void * ptr,
+	unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_local(ptr, old, new);
+	case 8:
+		return __cmpxchg_u64_local(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))))
+
+#define cmpxchg_local(ptr,old,new) \
+	((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
+		(unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
 
 extern void set_handler (unsigned long offset, void *addr, unsigned long len);
 extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len);
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 7d57d34..e894ee3 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -163,7 +163,7 @@ static __inline__ int atomic_read(const 
 }
 
 /* exported interface */
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -175,14 +175,21 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define atomic_add(i,v)	((void)(__atomic_add_return( ((int)i),(v))))
@@ -270,6 +277,37 @@ #define atomic64_inc_and_test(v) 	(atomi
 #define atomic64_dec_and_test(v)	(atomic64_dec_return(v) == 0)
 #define atomic64_sub_and_test(i,v)	(atomic64_sub_return((i),(v)) == 0)
 
+/* exported interface */
+#define atomic64_cmpxchg(v, o, n) \
+	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 #endif /* CONFIG_64BIT */
 
 #include <asm-generic/atomic.h>
diff --git a/include/asm-parisc/kdebug.h b/include/asm-parisc/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-parisc/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-parisc/local.h b/include/asm-parisc/local.h
index d0f5509..c11c530 100644
--- a/include/asm-parisc/local.h
+++ b/include/asm-parisc/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_PARISC_LOCAL_H
-#define _ARCH_PARISC_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic_long_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC_LONG_INIT(i)
-#define local_read(v)	atomic_long_read(v)
-#define local_set(v,i)	atomic_long_set(v,i)
-
-#define local_inc(v)	atomic_long_inc(v)
-#define local_dec(v)	atomic_long_dec(v)
-#define local_add(i, v)	atomic_long_add(i, v)
-#define local_sub(i, v)	atomic_long_sub(i, v)
-
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_PARISC_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-parisc/mmu_context.h b/include/asm-parisc/mmu_context.h
index 9c05836..bad6902 100644
--- a/include/asm-parisc/mmu_context.h
+++ b/include/asm-parisc/mmu_context.h
@@ -5,6 +5,7 @@ #include <linux/mm.h>
 #include <asm/atomic.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index d7e1b10..beb2adb 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -528,10 +528,6 @@ #define io_remap_pfn_range(vma, vaddr, p
 
 #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /* We provide our own get_unmapped_area to provide cache coherency */
 
 #define HAVE_ARCH_UNMAPPED_AREA
diff --git a/include/asm-parisc/scatterlist.h b/include/asm-parisc/scatterlist.h
index 236c1d0..e7211c7 100644
--- a/include/asm-parisc/scatterlist.h
+++ b/include/asm-parisc/scatterlist.h
@@ -2,6 +2,7 @@ #ifndef _ASM_PARISC_SCATTERLIST_H
 #define _ASM_PARISC_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page *page;
diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h
index ce2eae1..99e868f 100644
--- a/include/asm-parisc/socket.h
+++ b/include/asm-parisc/socket.h
@@ -33,6 +33,8 @@ #define SO_PASSCRED	0x4010
 #define SO_PEERCRED	0x4011
 #define SO_TIMESTAMP	0x4012
 #define SCM_TIMESTAMP	SO_TIMESTAMP
+#define SO_TIMESTAMPNS	0x4013
+#define SCM_TIMESTAMPNS	SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x4016
diff --git a/include/asm-parisc/sockios.h b/include/asm-parisc/sockios.h
index aace496..dabfbc7 100644
--- a/include/asm-parisc/sockios.h
+++ b/include/asm-parisc/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
index c89bd58..c19e736 100644
--- a/include/asm-powerpc/asm-compat.h
+++ b/include/asm-powerpc/asm-compat.h
@@ -78,6 +78,15 @@ #define PPC_LLARX	stringify_in_c(ldarx)
 #define PPC_STLCX	stringify_in_c(stdcx.)
 #define PPC_CNTLZL	stringify_in_c(cntlzd)
 
+/* Move to CR, single-entry optimized version. Only available
+ * on POWER4 and later.
+ */
+#ifdef CONFIG_POWER4_ONLY
+#define PPC_MTOCRF	stringify_in_c(mtocrf)
+#else
+#define PPC_MTOCRF	stringify_in_c(mtcrf)
+#endif
+
 #else /* 32-bit */
 
 /* operations for longs and pointers */
@@ -89,6 +98,7 @@ #define PPC_TLNEI	stringify_in_c(twnei)
 #define PPC_LLARX	stringify_in_c(lwarx)
 #define PPC_STLCX	stringify_in_c(stwcx.)
 #define PPC_CNTLZL	stringify_in_c(cntlzw)
+#define PPC_MTOCRF	stringify_in_c(mtcrf)
 
 #endif
 
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 2ce4b6b..c44810b 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -11,6 +11,7 @@ #ifdef __KERNEL__
 #include <linux/compiler.h>
 #include <asm/synch.h>
 #include <asm/asm-compat.h>
+#include <asm/system.h>
 
 #define ATOMIC_INIT(i)		{ (i) }
 
@@ -165,8 +166,7 @@ static __inline__ int atomic_dec_return(
 	return t;
 }
 
-#define atomic_cmpxchg(v, o, n) \
-	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -414,8 +414,7 @@ static __inline__ long atomic64_dec_if_p
 	return t;
 }
 
-#define atomic64_cmpxchg(v, o, n) \
-	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index 8f757f6..8144a27 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -39,7 +39,6 @@ #define _ASM_POWERPC_BITOPS_H
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-#include <asm/atomic.h>
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
 
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
index 08e93e7..ba667a3 100644
--- a/include/asm-powerpc/cacheflush.h
+++ b/include/asm-powerpc/cacheflush.h
@@ -64,6 +64,12 @@ #define copy_from_user_page(vma, page, v
 	memcpy(dst, src, len)
 
 
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+/* internal debugging function */
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_POWERPC_CACHEFLUSH_H */
diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h
index 35b9577..8066eed 100644
--- a/include/asm-powerpc/cell-pmu.h
+++ b/include/asm-powerpc/cell-pmu.h
@@ -97,11 +97,6 @@ extern void cbe_disable_pm_interrupts(u3
 extern u32  cbe_get_and_clear_pm_interrupts(u32 cpu);
 extern void cbe_sync_irq(int node);
 
-/* Utility functions, macros */
-extern u32 cbe_get_hw_thread_id(int cpu);
-
-#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
-
 #define CBE_COUNT_SUPERVISOR_MODE       0
 #define CBE_COUNT_HYPERVISOR_MODE       1
 #define CBE_COUNT_PROBLEM_MODE          2
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index e870b53..4345249 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -48,6 +48,7 @@ enum powerpc_oprofile_type {
 	PPC_OPROFILE_G4 = 3,
 	PPC_OPROFILE_BOOKE = 4,
 	PPC_OPROFILE_CELL = 5,
+	PPC_OPROFILE_PA6T = 6,
 };
 
 enum powerpc_pmc_type {
@@ -223,6 +224,10 @@ #define CPU_FTRS_750	(CPU_FTR_COMMON | C
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
 	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_PPC_LE)
+#define CPU_FTRS_750CL	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+	    CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
 #define CPU_FTRS_750FX1	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
 	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
@@ -235,9 +240,9 @@ #define CPU_FTRS_750FX	(CPU_FTR_COMMON |
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
 	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750GX	(CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
-	    CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
-	    CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+#define CPU_FTRS_750GX	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+	    CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
 	    CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
 #define CPU_FTRS_7400_NOTAU	(CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
 	    CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
index b8708ae..e2c7f06 100644
--- a/include/asm-powerpc/current.h
+++ b/include/asm-powerpc/current.h
@@ -12,6 +12,7 @@ #ifdef __KERNEL__
 struct task_struct;
 
 #ifdef __powerpc64__
+#include <linux/stddef.h>
 #include <asm/paca.h>
 
 static inline struct task_struct *get_current(void)
diff --git a/include/asm-powerpc/edac.h b/include/asm-powerpc/edac.h
new file mode 100644
index 0000000..6ead88b
--- /dev/null
+++ b/include/asm-powerpc/edac.h
@@ -0,0 +1,40 @@
+/*
+ * PPC EDAC common defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (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 ASM_EDAC_H
+#define ASM_EDAC_H
+/*
+ * ECC atomic, DMA, SMP and interrupt safe scrub function.
+ * Implements the per arch atomic_scrub() that EDAC use for software
+ * ECC scrubbing.  It reads memory and then writes back the original
+ * value, allowing the hardware to detect and correct memory errors.
+ */
+static __inline__ void atomic_scrub(void *va, u32 size)
+{
+	unsigned int *virt_addr = va;
+	unsigned int temp;
+	unsigned int i;
+
+	for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
+		/* Very carefully read and write to memory atomically
+		 * so we are interrupt, DMA and SMP safe.
+		 */
+		__asm__ __volatile__ ("\n\
+				1:	lwarx	%0,0,%1\n\
+					stwcx.	%0,0,%1\n\
+					bne-	1b\n\
+					isync"
+					: "=&r"(temp)
+					: "r"(virt_addr)
+					: "cr0", "memory");
+	}
+}
+
+#endif
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index dc6bf0f..cc3cb04 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -30,8 +30,6 @@ struct eeh_event {
 	struct list_head     list;
 	struct device_node 	*dn;   /* struct device node */
 	struct pci_dev       *dev;  /* affected device */
-	enum pci_channel_state state; /* PCI bus state for the affected device */
-	int time_unavail;    /* milliseconds until device might be available */
 };
 
 /**
@@ -46,9 +44,7 @@ struct eeh_event {
  * (from a workqueue).
  */
 int eeh_send_failure_event (struct device_node *dn,
-                            struct pci_dev *dev,
-                            enum pci_channel_state state,
-                            int time_unavail);
+                            struct pci_dev *dev);
 
 /* Main recovery function */
 struct pci_dn * handle_eeh_events (struct eeh_event *);
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
index 6611211..87d396e 100644
--- a/include/asm-powerpc/ibmebus.h
+++ b/include/asm-powerpc/ibmebus.h
@@ -2,36 +2,37 @@
  * IBM PowerPC eBus Infrastructure Support.
  *
  * Copyright (c) 2005 IBM Corporation
+ *  Joachim Fenkes <fenkes@de.ibm.com>
  *  Heiko J Schick <schickhj@de.ibm.com>
- *    
+ *
  * All rights reserved.
  *
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB 
- * BSD. 
+ * 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: 
+ * 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 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 
+ * 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. 
+ * 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 
+ * 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 
+ * 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.
  */
 
@@ -46,12 +47,11 @@ #include <asm/of_device.h>
 
 extern struct bus_type ibmebus_bus_type;
 
-struct ibmebus_dev {	
-	const char *name;
+struct ibmebus_dev {
 	struct of_device ofdev;
 };
 
-struct ibmebus_driver {	
+struct ibmebus_driver {
 	char *name;
 	struct of_device_id *id_table;
 	int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
@@ -63,7 +63,7 @@ int ibmebus_register_driver(struct ibmeb
 void ibmebus_unregister_driver(struct ibmebus_driver *drv);
 
 int ibmebus_request_irq(struct ibmebus_dev *dev,
-			u32 ist, 
+			u32 ist,
 			irq_handler_t handler,
 			unsigned long irq_flags, const char * devname,
 			void *dev_id);
diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h
index d905b66..59b9e07 100644
--- a/include/asm-powerpc/immap_86xx.h
+++ b/include/asm-powerpc/immap_86xx.h
@@ -85,81 +85,6 @@ typedef struct ccsr_pci {
 	char	res19[472];
 } ccsr_pci_t;
 
-/* PCI Express Registers */
-typedef struct ccsr_pex {
-	uint    pex_config_addr;        /* 0x.000 - PCI Express Configuration Address Register */
-	uint    pex_config_data;        /* 0x.004 - PCI Express Configuration Data Register */
-	char    res1[4];
-	uint    pex_otb_cpl_tor;        /* 0x.00c - PCI Express Outbound completion timeout register */
-	uint    pex_conf_tor;           /* 0x.010 - PCI Express configuration timeout register */
-	char    res2[12];
-	uint    pex_pme_mes_dr;         /* 0x.020 - PCI Express PME and message detect register */
-	uint    pex_pme_mes_disr;       /* 0x.024 - PCI Express PME and message disable register */
-	uint    pex_pme_mes_ier;        /* 0x.028 - PCI Express PME and message interrupt enable register */
-	uint    pex_pmcr;               /* 0x.02c - PCI Express power management command register */
-	char    res3[3024];
-	uint    pexotar0;               /* 0x.c00 - PCI Express outbound translation address register 0 */
-	uint    pexotear0;              /* 0x.c04 - PCI Express outbound translation extended address register 0*/
-	char    res4[8];
-	uint    pexowar0;               /* 0x.c10 - PCI Express outbound window attributes register 0*/
-	char    res5[12];
-	uint    pexotar1;               /* 0x.c20 - PCI Express outbound translation address register 1 */
-	uint    pexotear1;              /* 0x.c24 - PCI Express outbound translation extended address register 1*/
-	uint    pexowbar1;              /* 0x.c28 - PCI Express outbound window base address register 1*/
-	char    res6[4];
-	uint    pexowar1;               /* 0x.c30 - PCI Express outbound window attributes register 1*/
-	char    res7[12];
-	uint    pexotar2;               /* 0x.c40 - PCI Express outbound translation address register 2 */
-	uint    pexotear2;              /* 0x.c44 - PCI Express outbound translation extended address register 2*/
-	uint    pexowbar2;              /* 0x.c48 - PCI Express outbound window base address register 2*/
-	char    res8[4];
-	uint    pexowar2;               /* 0x.c50 - PCI Express outbound window attributes register 2*/
-	char    res9[12];
-	uint    pexotar3;               /* 0x.c60 - PCI Express outbound translation address register 3 */
-	uint    pexotear3;              /* 0x.c64 - PCI Express outbound translation extended address register 3*/
-	uint    pexowbar3;              /* 0x.c68 - PCI Express outbound window base address register 3*/
-	char    res10[4];
-	uint    pexowar3;               /* 0x.c70 - PCI Express outbound window attributes register 3*/
-	char    res11[12];
-	uint    pexotar4;               /* 0x.c80 - PCI Express outbound translation address register 4 */
-	uint    pexotear4;              /* 0x.c84 - PCI Express outbound translation extended address register 4*/
-	uint    pexowbar4;              /* 0x.c88 - PCI Express outbound window base address register 4*/
-	char    res12[4];
-	uint    pexowar4;               /* 0x.c90 - PCI Express outbound window attributes register 4*/
-	char    res13[12];
-	char    res14[256];
-	uint    pexitar3;               /* 0x.da0 - PCI Express inbound translation address register 3 */
-	char    res15[4];
-	uint    pexiwbar3;              /* 0x.da8 - PCI Express inbound window base address register 3 */
-	uint    pexiwbear3;             /* 0x.dac - PCI Express inbound window base extended address register 3 */
-	uint    pexiwar3;               /* 0x.db0 - PCI Express inbound window attributes register 3 */
-	char    res16[12];
-	uint    pexitar2;               /* 0x.dc0 - PCI Express inbound translation address register 2 */
-	char    res17[4];
-	uint    pexiwbar2;              /* 0x.dc8 - PCI Express inbound window base address register 2 */
-	uint    pexiwbear2;             /* 0x.dcc - PCI Express inbound window base extended address register 2 */
-	uint    pexiwar2;               /* 0x.dd0 - PCI Express inbound window attributes register 2 */
-	char    res18[12];
-	uint    pexitar1;               /* 0x.de0 - PCI Express inbound translation address register 2 */
-	char    res19[4];
-	uint    pexiwbar1;              /* 0x.de8 - PCI Express inbound window base address register 2 */
-	uint    pexiwbear1;             /* 0x.dec - PCI Express inbound window base extended address register 2 */
-	uint    pexiwar1;               /* 0x.df0 - PCI Express inbound window attributes register 2 */
-	char    res20[12];
-	uint    pex_err_dr;             /* 0x.e00 - PCI Express error detect register */
-	char    res21[4];
-	uint    pex_err_en;             /* 0x.e08 - PCI Express error interrupt enable register */
-	char    res22[4];
-	uint    pex_err_disr;           /* 0x.e10 - PCI Express error disable register */
-	char    res23[12];
-	uint    pex_err_cap_stat;       /* 0x.e20 - PCI Express error capture status register */
-	char    res24[4];
-	uint    pex_err_cap_r0;         /* 0x.e28 - PCI Express error capture register 0 */
-	uint    pex_err_cap_r1;         /* 0x.e2c - PCI Express error capture register 0 */
-	uint    pex_err_cap_r2;         /* 0x.e30 - PCI Express error capture register 0 */
-	uint    pex_err_cap_r3;         /* 0x.e34 - PCI Express error capture register 0 */
-} ccsr_pex_t;
-
 /* Global Utility Registers */
 typedef struct ccsr_guts {
 	uint	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 301c9bb..350c9bd 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -11,7 +11,12 @@ #ifdef __KERNEL__
 
 /* Check of existence of legacy devices */
 extern int check_legacy_ioport(unsigned long base_port);
-#define PNPBIOS_BASE	0xf000	/* only relevant for PReP */
+#define I8042_DATA_REG	0x60
+#define FDC_BASE	0x3f0
+/* only relevant for PReP */
+#define _PIDXR		0x279
+#define _PNPWRP		0xa79
+#define PNPBIOS_BASE	0xf000
 
 #include <linux/compiler.h>
 #include <asm/page.h>
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index b2e56b3..870967e 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -26,6 +26,7 @@ #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <asm/machdep.h>
 #include <asm/types.h>
 #include <asm/bitops.h>
 
@@ -109,6 +110,19 @@ static inline void pci_iommu_init(void) 
 #endif
 
 extern void alloc_dart_table(void);
+#if defined(CONFIG_PPC64) && defined(CONFIG_PM)
+static inline void iommu_save(void)
+{
+	if (ppc_md.iommu_save)
+		ppc_md.iommu_save();
+}
+
+static inline void iommu_restore(void)
+{
+	if (ppc_md.iommu_restore)
+		ppc_md.iommu_restore();
+}
+#endif
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_IOMMU_H */
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index 532bfee..295f016 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -6,20 +6,19 @@ #ifdef __KERNEL__
 
 #include <linux/notifier.h>
 
-struct pt_regs;
-
-struct die_args {
-	struct pt_regs *regs;
-	const char *str;
-	long err;
-	int trapnr;
-	int signr;
-};
-
-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 *);
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation.  Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
 extern struct atomic_notifier_head powerpc_die_chain;
 
 /* Grossly misnamed. */
@@ -29,14 +28,7 @@ enum die_val {
 	DIE_DABR_MATCH,
 	DIE_BPT,
 	DIE_SSTEP,
-	DIE_PAGE_FAULT,
 };
 
-static inline int notify_die(enum die_val val,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(&powerpc_die_chain, val, &args);
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KDEBUG_H */
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 11cbdf8..b6f817b 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -108,8 +108,6 @@ static inline void crash_setup_regs(stru
 					struct pt_regs *oldregs) { }
 #endif /* !__powerpc64 __ */
 
-#define MAX_NOTE_BYTES 1024
-
 extern void kexec_smp_wait(void);	/* get and clear naca physid, wait for
 					  master to copy new code to 0 */
 extern int crashing_cpu;
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 3a5dd49..b0e40ff 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -64,6 +64,12 @@ #define kprobe_lookup_name(name, addr)		
 				addr = *(kprobe_opcode_t **)addr;	\
 		} else if (name[0] != '.')				\
 			addr = *(kprobe_opcode_t **)addr;		\
+	} else {							\
+		char dot_name[KSYM_NAME_LEN+1];				\
+		dot_name[0] = '.';					\
+		dot_name[1] = '\0';					\
+		strncat(dot_name, name, KSYM_NAME_LEN);			\
+		addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \
 	}								\
 }
 
@@ -87,6 +93,11 @@ extern void arch_remove_kprobe(struct kp
 struct arch_specific_insn {
 	/* copy of original instruction */
 	kprobe_opcode_t *insn;
+	/*
+	 * Set in kprobes code, initially to 0. If the instruction can be
+	 * eumulated, this is set to 1, if not, to -1.
+	 */
+	int boostable;
 };
 
 struct prev_kprobe {
@@ -105,5 +116,6 @@ struct kprobe_ctlblk {
 
 extern int kprobe_exceptions_notify(struct notifier_block *self,
 					unsigned long val, void *data);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 #endif /* __KERNEL__ */
 #endif	/* _ASM_POWERPC_KPROBES_H */
diff --git a/include/asm-powerpc/local.h b/include/asm-powerpc/local.h
index c11c530..612d832 100644
--- a/include/asm-powerpc/local.h
+++ b/include/asm-powerpc/local.h
@@ -1 +1,200 @@
-#include <asm-generic/local.h>
+#ifndef _ARCH_POWERPC_LOCAL_H
+#define _ARCH_POWERPC_LOCAL_H
+
+#include <linux/percpu.h>
+#include <asm/atomic.h>
+
+typedef struct
+{
+	atomic_long_t a;
+} local_t;
+
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
+
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
+
+#define local_add(i,l)	atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l)	atomic_long_sub((i),(&(l)->a))
+#define local_inc(l)	atomic_long_inc(&(l)->a)
+#define local_dec(l)	atomic_long_dec(&(l)->a)
+
+static __inline__ long local_add_return(long a, local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%2		# local_add_return\n\
+	add	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%2 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (a), "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+#define local_add_negative(a, l)	(local_add_return((a), (l)) < 0)
+
+static __inline__ long local_sub_return(long a, local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%2		# local_sub_return\n\
+	subf	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%2 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (a), "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+static __inline__ long local_inc_return(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_inc_return\n\
+	addic	%0,%0,1\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1 \n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+static __inline__ long local_dec_return(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_dec_return\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1\n\
+	bne-	1b"
+	: "=&r" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+static __inline__ int local_add_unless(local_t *l, long a, long u)
+{
+	long t;
+
+	__asm__ __volatile__ (
+"1:"	PPC_LLARX	"%0,0,%1		# local_add_unless\n\
+	cmpw	0,%0,%3 \n\
+	beq-	2f \n\
+	add	%0,%2,%0 \n"
+	PPC405_ERR77(0,%2)
+	PPC_STLCX	"%0,0,%1 \n\
+	bne-	1b \n"
+"	subf	%0,%2,%0 \n\
+2:"
+	: "=&r" (t)
+	: "r" (&(l->a.counter)), "r" (a), "r" (u)
+	: "cc", "memory");
+
+	return t != u;
+}
+
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_sub_and_test(a, l)	(local_sub_return((a), (l)) == 0)
+#define local_dec_and_test(l)		(local_dec_return((l)) == 0)
+
+/*
+ * Atomically test *l and decrement if it is greater than 0.
+ * The function returns the old value of *l minus 1.
+ */
+static __inline__ long local_dec_if_positive(local_t *l)
+{
+	long t;
+
+	__asm__ __volatile__(
+"1:"	PPC_LLARX	"%0,0,%1		# local_dec_if_positive\n\
+	cmpwi	%0,1\n\
+	addi	%0,%0,-1\n\
+	blt-	2f\n"
+	PPC405_ERR77(0,%1)
+	PPC_STLCX	"%0,0,%1\n\
+	bne-	1b"
+	"\n\
+2:"	: "=&b" (t)
+	: "r" (&(l->a.counter))
+	: "cc", "memory");
+
+	return t;
+}
+
+/* Use these for per-cpu local_t variables: on some archs they are
+ * much more efficient than these naive implementations.  Note they take
+ * a variable, not an address.
+ */
+
+#define __local_inc(l)		((l)->a.counter++)
+#define __local_dec(l)		((l)->a.counter++)
+#define __local_add(i,l)	((l)->a.counter+=(i))
+#define __local_sub(i,l)	((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+   still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l)	 	\
+	({ local_t res__;		\
+	   preempt_disable(); 		\
+	   res__ = (l);			\
+	   preempt_enable();		\
+	   res__; })
+#define cpu_local_wrap(l)		\
+	({ preempt_disable();		\
+	   l;				\
+	   preempt_enable(); })		\
+
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
+
+#endif /* _ARCH_POWERPC_LOCAL_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 1b04e57..6cf1a83 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -91,6 +91,11 @@ #ifdef CONFIG_PPC64
 	void __iomem *	(*ioremap)(phys_addr_t addr, unsigned long size,
 				   unsigned long flags);
 	void		(*iounmap)(volatile void __iomem *token);
+
+#ifdef CONFIG_PM
+	void		(*iommu_save)(void);
+	void		(*iommu_restore)(void);
+#endif
 #endif /* CONFIG_PPC64 */
 
 	int		(*probe)(void);
@@ -115,6 +120,14 @@ #endif
 	/* To setup PHBs when using automatic OF platform driver for PCI */
 	int		(*pci_setup_phb)(struct pci_controller *host);
 
+#ifdef CONFIG_PCI_MSI
+	int		(*msi_check_device)(struct pci_dev* dev,
+					    int nvec, int type);
+	int		(*setup_msi_irqs)(struct pci_dev *dev,
+					  int nvec, int type);
+	void		(*teardown_msi_irqs)(struct pci_dev *dev);
+#endif
+
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
 	void		(*halt)(void);
@@ -153,9 +166,6 @@ #endif
 	 */
 	long	 	(*feature_call)(unsigned int feature, ...);
 
-	/* Check availability of legacy devices like i8042 */
-	int 		(*check_legacy_ioport)(unsigned int baseport);
-
 	/* Get legacy PCI/IDE interrupt mapping */ 
 	int		(*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
 	
@@ -243,14 +253,10 @@ #ifdef CONFIG_KEXEC
 	 */
 	void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_PCI_MSI
-	int (*enable_msi)(struct pci_dev *pdev);
-	void (*disable_msi)(struct pci_dev *pdev);
-#endif /* CONFIG_PCI_MSI */
 };
 
 extern void power4_idle(void);
+extern void power4_cpu_offline_powersave(void);
 extern void ppc6xx_idle(void);
 
 /*
diff --git a/include/asm-powerpc/mmu-44x.h b/include/asm-powerpc/mmu-44x.h
new file mode 100644
index 0000000..d5ce7a8
--- /dev/null
+++ b/include/asm-powerpc/mmu-44x.h
@@ -0,0 +1,78 @@
+#ifndef _ASM_POWERPC_MMU_44X_H_
+#define _ASM_POWERPC_MMU_44X_H_
+/*
+ * PPC440 support
+ */
+
+#define PPC44x_MMUCR_TID	0x000000ff
+#define PPC44x_MMUCR_STS	0x00010000
+
+#define	PPC44x_TLB_PAGEID	0
+#define	PPC44x_TLB_XLAT		1
+#define	PPC44x_TLB_ATTRIB	2
+
+/* Page identification fields */
+#define PPC44x_TLB_EPN_MASK	0xfffffc00      /* Effective Page Number */
+#define	PPC44x_TLB_VALID	0x00000200      /* Valid flag */
+#define PPC44x_TLB_TS		0x00000100	/* Translation address space */
+#define PPC44x_TLB_1K		0x00000000	/* Page sizes */
+#define PPC44x_TLB_4K		0x00000010
+#define PPC44x_TLB_16K		0x00000020
+#define PPC44x_TLB_64K		0x00000030
+#define PPC44x_TLB_256K		0x00000040
+#define PPC44x_TLB_1M		0x00000050
+#define PPC44x_TLB_16M		0x00000070
+#define	PPC44x_TLB_256M		0x00000090
+
+/* Translation fields */
+#define PPC44x_TLB_RPN_MASK	0xfffffc00      /* Real Page Number */
+#define	PPC44x_TLB_ERPN_MASK	0x0000000f
+
+/* Storage attribute and access control fields */
+#define PPC44x_TLB_ATTR_MASK	0x0000ff80
+#define PPC44x_TLB_U0		0x00008000      /* User 0 */
+#define PPC44x_TLB_U1		0x00004000      /* User 1 */
+#define PPC44x_TLB_U2		0x00002000      /* User 2 */
+#define PPC44x_TLB_U3		0x00001000      /* User 3 */
+#define PPC44x_TLB_W		0x00000800      /* Caching is write-through */
+#define PPC44x_TLB_I		0x00000400      /* Caching is inhibited */
+#define PPC44x_TLB_M		0x00000200      /* Memory is coherent */
+#define PPC44x_TLB_G		0x00000100      /* Memory is guarded */
+#define PPC44x_TLB_E		0x00000080      /* Memory is guarded */
+
+#define PPC44x_TLB_PERM_MASK	0x0000003f
+#define PPC44x_TLB_UX		0x00000020      /* User execution */
+#define PPC44x_TLB_UW		0x00000010      /* User write */
+#define PPC44x_TLB_UR		0x00000008      /* User read */
+#define PPC44x_TLB_SX		0x00000004      /* Super execution */
+#define PPC44x_TLB_SW		0x00000002      /* Super write */
+#define PPC44x_TLB_SR		0x00000001      /* Super read */
+
+/* Number of TLB entries */
+#define PPC44x_TLB_SIZE		64
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long long phys_addr_t;
+
+extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
+
+typedef struct {
+	unsigned long id;
+	unsigned long vdso_base;
+} mm_context_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#ifndef CONFIG_PPC_EARLY_DEBUG_44x
+#define PPC44x_EARLY_TLBS	1
+#else
+#define PPC44x_EARLY_TLBS	2
+#define PPC44x_EARLY_DEBUG_VIRTADDR	(ASM_CONST(0xf0000000) \
+	| (ASM_CONST(CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW) & 0xffff))
+#endif
+
+/* Size of the TLBs used for pinning in lowmem */
+#define PPC_PIN_SIZE	(1 << 28)	/* 256M */
+
+#endif /* _ASM_POWERPC_MMU_44X_H_ */
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
new file mode 100644
index 0000000..6739457
--- /dev/null
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -0,0 +1,400 @@
+#ifndef _ASM_POWERPC_MMU_HASH64_H_
+#define _ASM_POWERPC_MMU_HASH64_H_
+/*
+ * PowerPC64 memory management structures
+ *
+ * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
+ *   PPC64 rework.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/asm-compat.h>
+#include <asm/page.h>
+
+/*
+ * Segment table
+ */
+
+#define STE_ESID_V	0x80
+#define STE_ESID_KS	0x20
+#define STE_ESID_KP	0x10
+#define STE_ESID_N	0x08
+
+#define STE_VSID_SHIFT	12
+
+/* Location of cpu0's segment table */
+#define STAB0_PAGE	0x6
+#define STAB0_OFFSET	(STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR	(STAB0_OFFSET + PHYSICAL_START)
+
+#ifndef __ASSEMBLY__
+extern char initial_stab[];
+#endif /* ! __ASSEMBLY */
+
+/*
+ * SLB
+ */
+
+#define SLB_NUM_BOLTED		3
+#define SLB_CACHE_ENTRIES	8
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_V		ASM_CONST(0x0000000008000000) /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT		12
+#define SLB_VSID_B		ASM_CONST(0xc000000000000000)
+#define SLB_VSID_B_256M		ASM_CONST(0x0000000000000000)
+#define SLB_VSID_B_1T		ASM_CONST(0x4000000000000000)
+#define SLB_VSID_KS		ASM_CONST(0x0000000000000800)
+#define SLB_VSID_KP		ASM_CONST(0x0000000000000400)
+#define SLB_VSID_N		ASM_CONST(0x0000000000000200) /* no-execute */
+#define SLB_VSID_L		ASM_CONST(0x0000000000000100)
+#define SLB_VSID_C		ASM_CONST(0x0000000000000080) /* class */
+#define SLB_VSID_LP		ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LP_00		ASM_CONST(0x0000000000000000)
+#define SLB_VSID_LP_01		ASM_CONST(0x0000000000000010)
+#define SLB_VSID_LP_10		ASM_CONST(0x0000000000000020)
+#define SLB_VSID_LP_11		ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LLP		(SLB_VSID_L|SLB_VSID_LP)
+
+#define SLB_VSID_KERNEL		(SLB_VSID_KP)
+#define SLB_VSID_USER		(SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C			(0x08000000)
+
+/*
+ * Hash table
+ */
+
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_AVPN_SHIFT	7
+#define HPTE_V_AVPN		ASM_CONST(0xffffffffffffff80)
+#define HPTE_V_AVPN_VAL(x)	(((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x,y)	(!(((x) ^ (y)) & HPTE_V_AVPN))
+#define HPTE_V_BOLTED		ASM_CONST(0x0000000000000010)
+#define HPTE_V_LOCK		ASM_CONST(0x0000000000000008)
+#define HPTE_V_LARGE		ASM_CONST(0x0000000000000004)
+#define HPTE_V_SECONDARY	ASM_CONST(0x0000000000000002)
+#define HPTE_V_VALID		ASM_CONST(0x0000000000000001)
+
+#define HPTE_R_PP0		ASM_CONST(0x8000000000000000)
+#define HPTE_R_TS		ASM_CONST(0x4000000000000000)
+#define HPTE_R_RPN_SHIFT	12
+#define HPTE_R_RPN		ASM_CONST(0x3ffffffffffff000)
+#define HPTE_R_FLAGS		ASM_CONST(0x00000000000003ff)
+#define HPTE_R_PP		ASM_CONST(0x0000000000000003)
+#define HPTE_R_N		ASM_CONST(0x0000000000000004)
+#define HPTE_R_C		ASM_CONST(0x0000000000000080)
+#define HPTE_R_R		ASM_CONST(0x0000000000000100)
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+/* pp0 will always be 0 for linux     */
+#define PP_RWXX	0	/* Supervisor read/write, User none */
+#define PP_RWRX 1	/* Supervisor read/write, User read */
+#define PP_RWRW 2	/* Supervisor read/write, User read/write */
+#define PP_RXRX 3	/* Supervisor read,       User read */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+	unsigned long v;
+	unsigned long r;
+} hpte_t;
+
+extern hpte_t *htab_address;
+extern unsigned long htab_size_bytes;
+extern unsigned long htab_hash_mask;
+
+/*
+ * Page size definition
+ *
+ *    shift : is the "PAGE_SHIFT" value for that page size
+ *    sllp  : is a bit mask with the value of SLB L || LP to be or'ed
+ *            directly to a slbmte "vsid" value
+ *    penc  : is the HPTE encoding mask for the "LP" field:
+ *
+ */
+struct mmu_psize_def
+{
+	unsigned int	shift;	/* number of bits */
+	unsigned int	penc;	/* HPTE encoding */
+	unsigned int	tlbiel;	/* tlbiel supported for that page size */
+	unsigned long	avpnm;	/* bits to mask out in AVPN in the HPTE */
+	unsigned long	sllp;	/* SLB L||LP (exact mask to use in slbmte) */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ */
+
+#define MMU_PAGE_4K		0	/* 4K */
+#define MMU_PAGE_64K		1	/* 64K */
+#define MMU_PAGE_64K_AP		2	/* 64K Admixed (in a 4K segment) */
+#define MMU_PAGE_1M		3	/* 1M */
+#define MMU_PAGE_16M		4	/* 16M */
+#define MMU_PAGE_16G		5	/* 16G */
+#define MMU_PAGE_COUNT		6
+
+#ifndef __ASSEMBLY__
+
+/*
+ * The current system page sizes
+ */
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+extern int mmu_linear_psize;
+extern int mmu_virtual_psize;
+extern int mmu_vmalloc_psize;
+extern int mmu_io_psize;
+
+/*
+ * If the processor supports 64k normal pages but not 64k cache
+ * inhibited pages, we have to be prepared to switch processes
+ * to use 4k pages when they create cache-inhibited mappings.
+ * If this is the case, mmu_ci_restrictions will be set to 1.
+ */
+extern int mmu_ci_restrictions;
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The page size index of the huge pages for use by hugetlbfs
+ */
+extern int mmu_huge_psize;
+
+#endif /* CONFIG_HUGETLB_PAGE */
+
+/*
+ * This function sets the AVPN and L fields of the HPTE  appropriately
+ * for the page size
+ */
+static inline unsigned long hpte_encode_v(unsigned long va, int psize)
+{
+	unsigned long v =
+	v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
+	v <<= HPTE_V_AVPN_SHIFT;
+	if (psize != MMU_PAGE_4K)
+		v |= HPTE_V_LARGE;
+	return v;
+}
+
+/*
+ * This function sets the ARPN, and LP fields of the HPTE appropriately
+ * for the page size. We assume the pa is already "clean" that is properly
+ * aligned for the requested page size
+ */
+static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
+{
+	unsigned long r;
+
+	/* A 4K page needs no special encoding */
+	if (psize == MMU_PAGE_4K)
+		return pa & HPTE_R_RPN;
+	else {
+		unsigned int penc = mmu_psize_defs[psize].penc;
+		unsigned int shift = mmu_psize_defs[psize].shift;
+		return (pa & ~((1ul << shift) - 1)) | (penc << 12);
+	}
+	return r;
+}
+
+/*
+ * This hashes a virtual address for a 256Mb segment only for now
+ */
+
+static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
+{
+	return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
+}
+
+extern int __hash_page_4K(unsigned long ea, unsigned long access,
+			  unsigned long vsid, pte_t *ptep, unsigned long trap,
+			  unsigned int local);
+extern int __hash_page_64K(unsigned long ea, unsigned long access,
+			   unsigned long vsid, pte_t *ptep, unsigned long trap,
+			   unsigned int local);
+struct mm_struct;
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap);
+extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
+			  unsigned long ea, unsigned long vsid, int local,
+			  unsigned long trap);
+
+extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
+			     unsigned long pstart, unsigned long mode,
+			     int psize);
+
+extern void htab_initialize(void);
+extern void htab_initialize_secondary(void);
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
+extern void hpte_init_iSeries(void);
+extern void hpte_init_beat(void);
+
+extern void stabs_alloc(void);
+extern void slb_initialize(void);
+extern void slb_flush_and_rebolt(void);
+extern void stab_initialize(unsigned long stab);
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * VSID allocation
+ *
+ * We first generate a 36-bit "proto-VSID".  For kernel addresses this
+ * is equal to the ESID, for user addresses it is:
+ *	(context << 15) | (esid & 0x7fff)
+ *
+ * The two forms are distinguishable because the top bit is 0 for user
+ * addresses, whereas the top two bits are 1 for kernel addresses.
+ * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
+ * now.
+ *
+ * The proto-VSIDs are then scrambled into real VSIDs with the
+ * multiplicative hash:
+ *
+ *	VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
+ *	where	VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
+ *		VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
+ *
+ * This scramble is only well defined for proto-VSIDs below
+ * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
+ * reserved.  VSID_MULTIPLIER is prime, so in particular it is
+ * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
+ * Because the modulus is 2^n-1 we can compute it efficiently without
+ * a divide or extra multiply (see below).
+ *
+ * This scheme has several advantages over older methods:
+ *
+ * 	- We have VSIDs allocated for every kernel address
+ * (i.e. everything above 0xC000000000000000), except the very top
+ * segment, which simplifies several things.
+ *
+ * 	- We allow for 15 significant bits of ESID and 20 bits of
+ * context for user addresses.  i.e. 8T (43 bits) of address space for
+ * up to 1M contexts (although the page table structure and context
+ * allocation will need changes to take advantage of this).
+ *
+ * 	- The scramble function gives robust scattering in the hash
+ * table (at least based on some initial results).  The previous
+ * method was more susceptible to pathological cases giving excessive
+ * hash collisions.
+ */
+/*
+ * WARNING - If you change these you must make sure the asm
+ * implementations in slb_allocate (slb_low.S), do_stab_bolted
+ * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
+ *
+ * You'll also need to change the precomputed VSID values in head.S
+ * which are used by the iSeries firmware.
+ */
+
+#define VSID_MULTIPLIER	ASM_CONST(200730139)	/* 28-bit prime */
+#define VSID_BITS	36
+#define VSID_MODULUS	((1UL<<VSID_BITS)-1)
+
+#define CONTEXT_BITS	19
+#define USER_ESID_BITS	16
+
+#define USER_VSID_RANGE	(1UL << (USER_ESID_BITS + SID_SHIFT))
+
+/*
+ * This macro generates asm code to compute the VSID scramble
+ * function.  Used in slb_allocate() and do_stab_bolted.  The function
+ * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
+ *
+ *	rt = register continaing the proto-VSID and into which the
+ *		VSID will be stored
+ *	rx = scratch register (clobbered)
+ *
+ * 	- rt and rx must be different registers
+ * 	- The answer will end up in the low 36 bits of rt.  The higher
+ * 	  bits may contain other garbage, so you may need to mask the
+ * 	  result.
+ */
+#define ASM_VSID_SCRAMBLE(rt, rx)	\
+	lis	rx,VSID_MULTIPLIER@h;					\
+	ori	rx,rx,VSID_MULTIPLIER@l;				\
+	mulld	rt,rt,rx;		/* rt = rt * MULTIPLIER */	\
+									\
+	srdi	rx,rt,VSID_BITS;					\
+	clrldi	rt,rt,(64-VSID_BITS);					\
+	add	rt,rt,rx;		/* add high and low bits */	\
+	/* Now, r3 == VSID (mod 2^36-1), and lies between 0 and		\
+	 * 2^36-1+2^28-1.  That in particular means that if r3 >=	\
+	 * 2^36-1, then r3+1 has the 2^36 bit set.  So, if r3+1 has	\
+	 * the bit clear, r3 already has the answer we want, if it	\
+	 * doesn't, the answer is the low 36 bits of r3+1.  So in all	\
+	 * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
+	addi	rx,rt,1;						\
+	srdi	rx,rx,VSID_BITS;	/* extract 2^36 bit */		\
+	add	rt,rt,rx
+
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_context_id_t;
+
+typedef struct {
+	mm_context_id_t id;
+	u16 user_psize;			/* page size index */
+	u16 sllp;			/* SLB entry page size encoding */
+#ifdef CONFIG_HUGETLB_PAGE
+	u16 low_htlb_areas, high_htlb_areas;
+#endif
+	unsigned long vdso_base;
+} mm_context_t;
+
+
+static inline unsigned long vsid_scramble(unsigned long protovsid)
+{
+#if 0
+	/* The code below is equivalent to this function for arguments
+	 * < 2^VSID_BITS, which is all this should ever be called
+	 * with.  However gcc is not clever enough to compute the
+	 * modulus (2^n-1) without a second multiply. */
+	return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
+#else /* 1 */
+	unsigned long x;
+
+	x = protovsid * VSID_MULTIPLIER;
+	x = (x >> VSID_BITS) + (x & VSID_MODULUS);
+	return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
+#endif /* 1 */
+}
+
+/* This is only valid for addresses >= KERNELBASE */
+static inline unsigned long get_kernel_vsid(unsigned long ea)
+{
+	return vsid_scramble(ea >> SID_SHIFT);
+}
+
+/* This is only valid for user addresses (which are below 2^41) */
+static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
+{
+	return vsid_scramble((context << USER_ESID_BITS)
+			     | (ea >> SID_SHIFT));
+}
+
+#define VSID_SCRAMBLE(pvsid)	(((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
+#define KERNEL_VSID(ea)		VSID_SCRAMBLE(GET_ESID(ea))
+
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_HASH64_H_ */
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 200055a..fe510ff 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -2,407 +2,17 @@ #ifndef _ASM_POWERPC_MMU_H_
 #define _ASM_POWERPC_MMU_H_
 #ifdef __KERNEL__
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/mmu.h>
+#ifdef CONFIG_PPC64
+/* 64-bit classic hash table MMU */
+#  include <asm/mmu-hash64.h>
+#elif defined(CONFIG_44x)
+/* 44x-style software loaded TLB */
+#  include <asm/mmu-44x.h>
 #else
-
-/*
- * PowerPC memory management structures
- *
- * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
- *   PPC64 rework.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the 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/asm-compat.h>
-#include <asm/page.h>
-
-/*
- * Segment table
- */
-
-#define STE_ESID_V	0x80
-#define STE_ESID_KS	0x20
-#define STE_ESID_KP	0x10
-#define STE_ESID_N	0x08
-
-#define STE_VSID_SHIFT	12
-
-/* Location of cpu0's segment table */
-#define STAB0_PAGE	0x6
-#define STAB0_OFFSET	(STAB0_PAGE << 12)
-#define STAB0_PHYS_ADDR	(STAB0_OFFSET + PHYSICAL_START)
-
-#ifndef __ASSEMBLY__
-extern char initial_stab[];
-#endif /* ! __ASSEMBLY */
-
-/*
- * SLB
- */
-
-#define SLB_NUM_BOLTED		3
-#define SLB_CACHE_ENTRIES	8
-
-/* Bits in the SLB ESID word */
-#define SLB_ESID_V		ASM_CONST(0x0000000008000000) /* valid */
-
-/* Bits in the SLB VSID word */
-#define SLB_VSID_SHIFT		12
-#define SLB_VSID_B		ASM_CONST(0xc000000000000000)
-#define SLB_VSID_B_256M		ASM_CONST(0x0000000000000000)
-#define SLB_VSID_B_1T		ASM_CONST(0x4000000000000000)
-#define SLB_VSID_KS		ASM_CONST(0x0000000000000800)
-#define SLB_VSID_KP		ASM_CONST(0x0000000000000400)
-#define SLB_VSID_N		ASM_CONST(0x0000000000000200) /* no-execute */
-#define SLB_VSID_L		ASM_CONST(0x0000000000000100)
-#define SLB_VSID_C		ASM_CONST(0x0000000000000080) /* class */
-#define SLB_VSID_LP		ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LP_00		ASM_CONST(0x0000000000000000)
-#define SLB_VSID_LP_01		ASM_CONST(0x0000000000000010)
-#define SLB_VSID_LP_10		ASM_CONST(0x0000000000000020)
-#define SLB_VSID_LP_11		ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LLP		(SLB_VSID_L|SLB_VSID_LP)
-
-#define SLB_VSID_KERNEL		(SLB_VSID_KP)
-#define SLB_VSID_USER		(SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
-
-#define SLBIE_C			(0x08000000)
-
-/*
- * Hash table
- */
-
-#define HPTES_PER_GROUP 8
-
-#define HPTE_V_AVPN_SHIFT	7
-#define HPTE_V_AVPN		ASM_CONST(0xffffffffffffff80)
-#define HPTE_V_AVPN_VAL(x)	(((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
-#define HPTE_V_COMPARE(x,y)	(!(((x) ^ (y)) & HPTE_V_AVPN))
-#define HPTE_V_BOLTED		ASM_CONST(0x0000000000000010)
-#define HPTE_V_LOCK		ASM_CONST(0x0000000000000008)
-#define HPTE_V_LARGE		ASM_CONST(0x0000000000000004)
-#define HPTE_V_SECONDARY	ASM_CONST(0x0000000000000002)
-#define HPTE_V_VALID		ASM_CONST(0x0000000000000001)
-
-#define HPTE_R_PP0		ASM_CONST(0x8000000000000000)
-#define HPTE_R_TS		ASM_CONST(0x4000000000000000)
-#define HPTE_R_RPN_SHIFT	12
-#define HPTE_R_RPN		ASM_CONST(0x3ffffffffffff000)
-#define HPTE_R_FLAGS		ASM_CONST(0x00000000000003ff)
-#define HPTE_R_PP		ASM_CONST(0x0000000000000003)
-#define HPTE_R_N		ASM_CONST(0x0000000000000004)
-#define HPTE_R_C		ASM_CONST(0x0000000000000080)
-#define HPTE_R_R		ASM_CONST(0x0000000000000100)
-
-/* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux     */
-#define PP_RWXX	0	/* Supervisor read/write, User none */
-#define PP_RWRX 1	/* Supervisor read/write, User read */
-#define PP_RWRW 2	/* Supervisor read/write, User read/write */
-#define PP_RXRX 3	/* Supervisor read,       User read */
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
-	unsigned long v;
-	unsigned long r;
-} hpte_t;
-
-extern hpte_t *htab_address;
-extern unsigned long htab_size_bytes;
-extern unsigned long htab_hash_mask;
-
-/*
- * Page size definition
- *
- *    shift : is the "PAGE_SHIFT" value for that page size
- *    sllp  : is a bit mask with the value of SLB L || LP to be or'ed
- *            directly to a slbmte "vsid" value
- *    penc  : is the HPTE encoding mask for the "LP" field:
- *
- */
-struct mmu_psize_def
-{
-	unsigned int	shift;	/* number of bits */
-	unsigned int	penc;	/* HPTE encoding */
-	unsigned int	tlbiel;	/* tlbiel supported for that page size */
-	unsigned long	avpnm;	/* bits to mask out in AVPN in the HPTE */
-	unsigned long	sllp;	/* SLB L||LP (exact mask to use in slbmte) */
-};
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * The kernel use the constants below to index in the page sizes array.
- * The use of fixed constants for this purpose is better for performances
- * of the low level hash refill handlers.
- *
- * A non supported page size has a "shift" field set to 0
- *
- * Any new page size being implemented can get a new entry in here. Whether
- * the kernel will use it or not is a different matter though. The actual page
- * size used by hugetlbfs is not defined here and may be made variable
- */
-
-#define MMU_PAGE_4K		0	/* 4K */
-#define MMU_PAGE_64K		1	/* 64K */
-#define MMU_PAGE_64K_AP		2	/* 64K Admixed (in a 4K segment) */
-#define MMU_PAGE_1M		3	/* 1M */
-#define MMU_PAGE_16M		4	/* 16M */
-#define MMU_PAGE_16G		5	/* 16G */
-#define MMU_PAGE_COUNT		6
-
-#ifndef __ASSEMBLY__
-
-/*
- * The current system page sizes
- */
-extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
-extern int mmu_linear_psize;
-extern int mmu_virtual_psize;
-extern int mmu_vmalloc_psize;
-extern int mmu_io_psize;
-
-/*
- * If the processor supports 64k normal pages but not 64k cache
- * inhibited pages, we have to be prepared to switch processes
- * to use 4k pages when they create cache-inhibited mappings.
- * If this is the case, mmu_ci_restrictions will be set to 1.
- */
-extern int mmu_ci_restrictions;
-
-#ifdef CONFIG_HUGETLB_PAGE
-/*
- * The page size index of the huge pages for use by hugetlbfs
- */
-extern int mmu_huge_psize;
-
-#endif /* CONFIG_HUGETLB_PAGE */
-
-/*
- * This function sets the AVPN and L fields of the HPTE  appropriately
- * for the page size
- */
-static inline unsigned long hpte_encode_v(unsigned long va, int psize)
-{
-	unsigned long v =
-	v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
-	v <<= HPTE_V_AVPN_SHIFT;
-	if (psize != MMU_PAGE_4K)
-		v |= HPTE_V_LARGE;
-	return v;
-}
-
-/*
- * This function sets the ARPN, and LP fields of the HPTE appropriately
- * for the page size. We assume the pa is already "clean" that is properly
- * aligned for the requested page size
- */
-static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
-{
-	unsigned long r;
-
-	/* A 4K page needs no special encoding */
-	if (psize == MMU_PAGE_4K)
-		return pa & HPTE_R_RPN;
-	else {
-		unsigned int penc = mmu_psize_defs[psize].penc;
-		unsigned int shift = mmu_psize_defs[psize].shift;
-		return (pa & ~((1ul << shift) - 1)) | (penc << 12);
-	}
-	return r;
-}
-
-/*
- * This hashes a virtual address for a 256Mb segment only for now
- */
-
-static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
-{
-	return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
-}
-
-extern int __hash_page_4K(unsigned long ea, unsigned long access,
-			  unsigned long vsid, pte_t *ptep, unsigned long trap,
-			  unsigned int local);
-extern int __hash_page_64K(unsigned long ea, unsigned long access,
-			   unsigned long vsid, pte_t *ptep, unsigned long trap,
-			   unsigned int local);
-struct mm_struct;
-extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
-			  unsigned long ea, unsigned long vsid, int local,
-			  unsigned long trap);
-
-extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
-			     unsigned long pstart, unsigned long mode,
-			     int psize);
-
-extern void htab_initialize(void);
-extern void htab_initialize_secondary(void);
-extern void hpte_init_native(void);
-extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
-extern void hpte_init_beat(void);
-
-extern void stabs_alloc(void);
-extern void slb_initialize(void);
-extern void slb_flush_and_rebolt(void);
-extern void stab_initialize(unsigned long stab);
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * VSID allocation
- *
- * We first generate a 36-bit "proto-VSID".  For kernel addresses this
- * is equal to the ESID, for user addresses it is:
- *	(context << 15) | (esid & 0x7fff)
- *
- * The two forms are distinguishable because the top bit is 0 for user
- * addresses, whereas the top two bits are 1 for kernel addresses.
- * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
- * now.
- *
- * The proto-VSIDs are then scrambled into real VSIDs with the
- * multiplicative hash:
- *
- *	VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
- *	where	VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
- *		VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
- *
- * This scramble is only well defined for proto-VSIDs below
- * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
- * reserved.  VSID_MULTIPLIER is prime, so in particular it is
- * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
- * Because the modulus is 2^n-1 we can compute it efficiently without
- * a divide or extra multiply (see below).
- *
- * This scheme has several advantages over older methods:
- *
- * 	- We have VSIDs allocated for every kernel address
- * (i.e. everything above 0xC000000000000000), except the very top
- * segment, which simplifies several things.
- *
- * 	- We allow for 15 significant bits of ESID and 20 bits of
- * context for user addresses.  i.e. 8T (43 bits) of address space for
- * up to 1M contexts (although the page table structure and context
- * allocation will need changes to take advantage of this).
- *
- * 	- The scramble function gives robust scattering in the hash
- * table (at least based on some initial results).  The previous
- * method was more susceptible to pathological cases giving excessive
- * hash collisions.
- */
-/*
- * WARNING - If you change these you must make sure the asm
- * implementations in slb_allocate (slb_low.S), do_stab_bolted
- * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
- */
-
-#define VSID_MULTIPLIER	ASM_CONST(200730139)	/* 28-bit prime */
-#define VSID_BITS	36
-#define VSID_MODULUS	((1UL<<VSID_BITS)-1)
-
-#define CONTEXT_BITS	19
-#define USER_ESID_BITS	16
-
-#define USER_VSID_RANGE	(1UL << (USER_ESID_BITS + SID_SHIFT))
-
-/*
- * This macro generates asm code to compute the VSID scramble
- * function.  Used in slb_allocate() and do_stab_bolted.  The function
- * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
- *
- *	rt = register continaing the proto-VSID and into which the
- *		VSID will be stored
- *	rx = scratch register (clobbered)
- *
- * 	- rt and rx must be different registers
- * 	- The answer will end up in the low 36 bits of rt.  The higher
- * 	  bits may contain other garbage, so you may need to mask the
- * 	  result.
- */
-#define ASM_VSID_SCRAMBLE(rt, rx)	\
-	lis	rx,VSID_MULTIPLIER@h;					\
-	ori	rx,rx,VSID_MULTIPLIER@l;				\
-	mulld	rt,rt,rx;		/* rt = rt * MULTIPLIER */	\
-									\
-	srdi	rx,rt,VSID_BITS;					\
-	clrldi	rt,rt,(64-VSID_BITS);					\
-	add	rt,rt,rx;		/* add high and low bits */	\
-	/* Now, r3 == VSID (mod 2^36-1), and lies between 0 and		\
-	 * 2^36-1+2^28-1.  That in particular means that if r3 >=	\
-	 * 2^36-1, then r3+1 has the 2^36 bit set.  So, if r3+1 has	\
-	 * the bit clear, r3 already has the answer we want, if it	\
-	 * doesn't, the answer is the low 36 bits of r3+1.  So in all	\
-	 * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
-	addi	rx,rt,1;						\
-	srdi	rx,rx,VSID_BITS;	/* extract 2^36 bit */		\
-	add	rt,rt,rx
-
-
-#ifndef __ASSEMBLY__
-
-typedef unsigned long mm_context_id_t;
-
-typedef struct {
-	mm_context_id_t id;
-	u16 user_psize;			/* page size index */
-	u16 sllp;			/* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
-	u16 low_htlb_areas, high_htlb_areas;
+/* Other 32-bit.  FIXME: split up the other 32-bit MMU types, and
+ * revise for arch/powerpc */
+#  include <asm-ppc/mmu.h>
 #endif
-	unsigned long vdso_base;
-} mm_context_t;
-
-
-static inline unsigned long vsid_scramble(unsigned long protovsid)
-{
-#if 0
-	/* The code below is equivalent to this function for arguments
-	 * < 2^VSID_BITS, which is all this should ever be called
-	 * with.  However gcc is not clever enough to compute the
-	 * modulus (2^n-1) without a second multiply. */
-	return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
-#else /* 1 */
-	unsigned long x;
-
-	x = protovsid * VSID_MULTIPLIER;
-	x = (x >> VSID_BITS) + (x & VSID_MODULUS);
-	return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
-#endif /* 1 */
-}
-
-/* This is only valid for addresses >= KERNELBASE */
-static inline unsigned long get_kernel_vsid(unsigned long ea)
-{
-	return vsid_scramble(ea >> SID_SHIFT);
-}
-
-/* This is only valid for user addresses (which are below 2^41) */
-static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
-{
-	return vsid_scramble((context << USER_ESID_BITS)
-			     | (ea >> SID_SHIFT));
-}
-
-#define VSID_SCRAMBLE(pvsid)	(((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
-#define KERNEL_VSID(ea)		VSID_SCRAMBLE(GET_ESID(ea))
-
-/* Physical address used by some IO functions */
-typedef unsigned long phys_addr_t;
-
-
-#endif /* __ASSEMBLY */
 
-#endif /* CONFIG_PPC64 */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MMU_H_ */
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index 083ac91..c0d7795 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -10,6 +10,7 @@ #include <linux/kernel.h>	
 #include <linux/mm.h>	
 #include <asm/mmu.h>	
 #include <asm/cputable.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * Copyright (C) 2001 PPC 64 Team, IBM Corp
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
index 7afd5bf..c4631f6 100644
--- a/include/asm-powerpc/mpc52xx.h
+++ b/include/asm-powerpc/mpc52xx.h
@@ -253,5 +253,16 @@ extern int __init mpc52xx_add_bridge(str
 
 #endif /* __ASSEMBLY__ */
 
+#ifdef CONFIG_PM
+struct mpc52xx_suspend {
+	void (*board_suspend_prepare)(void __iomem *mbar);
+	void (*board_resume_finish)(void __iomem *mbar);
+};
+
+extern struct mpc52xx_suspend mpc52xx_suspend;
+extern int __init mpc52xx_pm_init(void);
+extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level);
+#endif /* CONFIG_PM */
+
 #endif /* __ASM_POWERPC_MPC52xx_H__ */
 
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index cb204a7..2ffb06a 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -3,6 +3,7 @@ #define _ASM_POWERPC_MPIC_H
 #ifdef __KERNEL__
 
 #include <linux/irq.h>
+#include <linux/sysdev.h>
 #include <asm/dcr.h>
 
 /*
@@ -199,7 +200,7 @@ enum {
 };
 
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 /* Fixup table entry */
 struct mpic_irq_fixup
 {
@@ -208,7 +209,7 @@ struct mpic_irq_fixup
 	u32		data;
 	unsigned int	index;
 };
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 
 enum mpic_reg_type {
@@ -228,6 +229,14 @@ #ifdef CONFIG_PPC_DCR
 #endif /* CONFIG_PPC_DCR */
 };
 
+struct mpic_irq_save {
+	u32		vecprio,
+			dest;
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+	u32		fixup_data;
+#endif
+};
+
 /* The instance data of a given MPIC */
 struct mpic
 {
@@ -239,7 +248,7 @@ struct mpic
 
 	/* The "linux" controller struct */
 	struct irq_chip		hc_irq;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 	struct irq_chip		hc_ht_irq;
 #endif
 #ifdef CONFIG_SMP
@@ -268,7 +277,7 @@ #endif
 	/* Spurious vector to program into unused sources */
 	unsigned int		spurious_vec;
 
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
 	/* The fixup table */
 	struct mpic_irq_fixup	*fixups;
 	spinlock_t		fixup_lock;
@@ -292,8 +301,19 @@ #ifdef CONFIG_MPIC_WEIRD
 	u32			*hw_set;
 #endif
 
+#ifdef CONFIG_PCI_MSI
+	spinlock_t		bitmap_lock;
+	unsigned long		*hwirq_bitmap;
+#endif
+
 	/* link */
 	struct mpic		*next;
+
+	struct sys_device	sysdev;
+
+#ifdef CONFIG_PM
+	struct mpic_irq_save	*save_data;
+#endif
 };
 
 /*
@@ -313,7 +333,7 @@ #define MPIC_PRIMARY			0x00000001
 /* Set this for a big-endian MPIC */
 #define MPIC_BIG_ENDIAN			0x00000002
 /* Broken U3 MPIC */
-#define MPIC_BROKEN_U3			0x00000004
+#define MPIC_U3_HT_IRQS			0x00000004
 /* Broken IPI registers (autodetected) */
 #define MPIC_BROKEN_IPI			0x00000008
 /* MPIC wants a reset */
@@ -352,7 +372,7 @@ #define	MPIC_REGSET_TSI108		MPIC_REGSET(
  * @senses_num: number of entries in the array
  *
  * Note about the sense array. If none is passed, all interrupts are
- * setup to be level negative unless MPIC_BROKEN_U3 is set in which
+ * setup to be level negative unless MPIC_U3_HT_IRQS is set in which
  * case they are edge positive (and the array is ignored anyway).
  * The values in the array start at the first source of the MPIC,
  * that is senses[0] correspond to linux irq "irq_offset".
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index a889b20..e9af49e 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -32,5 +32,10 @@ extern int of_device_register(struct of_
 extern void of_device_unregister(struct of_device *ofdev);
 extern void of_release_dev(struct device *dev);
 
+extern ssize_t of_device_get_modalias(struct of_device *ofdev,
+					char *str, ssize_t len);
+extern int of_device_uevent(struct device *dev,
+	char **envp, int num_envp, char *buffer, int buffer_size);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 94c0ad2..8d6b47f 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -57,6 +57,8 @@ extern struct op_powerpc_model op_model_
 extern struct op_powerpc_model op_model_power4;
 extern struct op_powerpc_model op_model_7450;
 extern struct op_powerpc_model op_model_cell;
+extern struct op_powerpc_model op_model_pa6t;
+
 
 /* All the classic PPC parts use these */
 static inline unsigned int classic_ctr_read(unsigned int i)
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 0d3adc0..cf95274 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -70,6 +70,7 @@ #endif /* CONFIG_PPC_ISERIES */
 	s16 hw_cpu_id;			/* Physical processor number */
 	u8 cpu_start;			/* At startup, processor spins until */
 					/* this becomes non-zero. */
+	struct slb_shadow *slb_shadow_ptr;
 
 	/*
 	 * Now, starting in cacheline 2, the exception save areas
@@ -93,6 +94,7 @@ #endif /* CONFIG_PPC_ISERIES */
 	u64 stab_rr;			/* stab/slb round-robin counter */
 	u64 saved_r1;			/* r1 save for RTAS calls */
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
+	u16 trap_save;			/* Used when bad stack is encountered */
 	u8 soft_enabled;		/* irq soft-enable flag */
 	u8 hard_enabled;		/* set if irqs are enabled in MSR */
 	u8 io_sync;			/* writel() needs spin_unlock sync */
@@ -101,8 +103,6 @@ #endif /* CONFIG_PPC_ISERIES */
 	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 b4d38b0..10c51f4 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -121,6 +121,7 @@ typedef struct { pte_t pte; } real_pte_t
 #endif
 
 /* PMD level */
+#ifdef CONFIG_PPC64
 typedef struct { unsigned long pmd; } pmd_t;
 #define pmd_val(x)	((x).pmd)
 #define __pmd(x)	((pmd_t) { (x) })
@@ -130,7 +131,8 @@ #ifndef CONFIG_PPC_64K_PAGES
 typedef struct { unsigned long pud; } pud_t;
 #define pud_val(x)	((x).pud)
 #define __pud(x)	((pud_t) { (x) })
-#endif
+#endif /* !CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC64 */
 
 /* PGD level */
 typedef struct { unsigned long pgd; } pgd_t;
@@ -159,15 +161,17 @@ typedef unsigned long real_pte_t;
 #endif
 
 
+#ifdef CONFIG_PPC64
 typedef unsigned long pmd_t;
 #define pmd_val(x)	(x)
 #define __pmd(x)	(x)
 
-#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_64K_PAGES)
+#ifndef CONFIG_PPC_64K_PAGES
 typedef unsigned long pud_t;
 #define pud_val(x)	(x)
 #define __pud(x)	(x)
-#endif
+#endif /* !CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC64 */
 
 typedef unsigned long pgd_t;
 #define pgd_val(x)	(x)
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 07f6d3c..374d0db 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -14,11 +14,9 @@ #ifndef __ASSEMBLY__
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
 #define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
-#define PTE_FMT		"%16Lx"
 #else
 typedef unsigned long pte_basic_t;
 #define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
-#define PTE_FMT		"%.8lx"
 #endif
 
 struct page;
diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h
index 3fca21d..414c50e 100644
--- a/include/asm-powerpc/parport.h
+++ b/include/asm-powerpc/parport.h
@@ -12,26 +12,21 @@ #ifdef __KERNEL__
 
 #include <asm/prom.h>
 
-extern struct parport *parport_pc_probe_port (unsigned long int base,
-                                              unsigned long int base_hi,
-                                              int irq, int dma,
-                                              struct pci_dev *dev);
-
 static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
 	struct device_node *np;
-	u32 *prop;
+	const u32 *prop;
 	u32 io1, io2;
 	int propsize;
 	int count = 0;
 	for (np = NULL; (np = of_find_compatible_node(np,
 						      "parallel",
 						      "pnpPNP,400")) != NULL;) {
-		prop = (u32 *)get_property(np, "reg", &propsize);
+		prop = of_get_property(np, "reg", &propsize);
 		if (!prop || propsize > 6*sizeof(u32))
 			continue;
 		io1 = prop[1]; io2 = prop[2];
-		prop = (u32 *)get_property(np, "interrupts", NULL);
+		prop = of_get_property(np, "interrupts", NULL);
 		if (!prop)
 			continue;
 		if (parport_pc_probe_port(io1, io2, prop[0], autodma, NULL) != NULL)
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index ac656ee..ce0f13e 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -70,19 +70,22 @@ #ifdef CONFIG_PPC64
  */
 #define PCI_DISABLE_MWI
 
-extern struct dma_mapping_ops *pci_dma_ops;
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
 
 /* For DAC DMA, we currently don't support it by default, but
  * we let 64-bit platforms override this.
  */
 static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
 {
-	if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
-		return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
+	struct dma_mapping_ops *d = get_pci_dma_ops();
+
+	if (d && d->dac_dma_supported)
+		return d->dac_dma_supported(&hwdev->dev, mask);
 	return 0;
 }
 
-#ifdef CONFIG_PCI
 static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 					enum pci_dma_burst_strategy *strat,
 					unsigned long *strategy_parameter)
@@ -99,6 +102,9 @@ static inline void pci_dma_burst_advice(
 	*strat = PCI_DMA_BURST_MULTIPLE;
 	*strategy_parameter = cacheline_size;
 }
+#else	/* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops()	NULL
 #endif
 
 extern int pci_domain_nr(struct pci_bus *bus);
diff --git a/include/asm-powerpc/pgalloc-32.h b/include/asm-powerpc/pgalloc-32.h
new file mode 100644
index 0000000..e130743
--- /dev/null
+++ b/include/asm-powerpc/pgalloc-32.h
@@ -0,0 +1,41 @@
+#ifndef _ASM_POWERPC_PGALLOC_32_H
+#define _ASM_POWERPC_PGALLOC_32_H
+
+#include <linux/threads.h>
+
+extern void __bad_pte(pmd_t *pmd);
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(pgd_t *pgd);
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+/* #define pmd_alloc_one(mm,address)       ({ 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() */
+
+#ifndef CONFIG_BOOKE
+#define pmd_populate_kernel(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = __pa(pte) | _PMD_PRESENT)
+#define pmd_populate(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT) | _PMD_PRESENT)
+#else
+#define pmd_populate_kernel(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = (unsigned long)pte | _PMD_PRESENT)
+#define pmd_populate(mm, pmd, pte)	\
+		(pmd_val(*(pmd)) = (unsigned long)lowmem_page_address(pte) | _PMD_PRESENT)
+#endif
+
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
+extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
+extern void pte_free_kernel(pte_t *pte);
+extern void pte_free(struct page *pte);
+
+#define __pte_free_tlb(tlb, pte)	pte_free((pte))
+
+#define check_pgt_cache()	do { } while (0)
+
+#endif /* _ASM_POWERPC_PGALLOC_32_H */
diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h
new file mode 100644
index 0000000..30b50cf
--- /dev/null
+++ b/include/asm-powerpc/pgalloc-64.h
@@ -0,0 +1,152 @@
+#ifndef _ASM_POWERPC_PGALLOC_64_H
+#define _ASM_POWERPC_PGALLOC_64_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 <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
+
+extern struct kmem_cache *pgtable_cache[];
+
+#ifdef CONFIG_PPC_64K_PAGES
+#define PTE_CACHE_NUM	0
+#define PMD_CACHE_NUM	1
+#define PGD_CACHE_NUM	2
+#define HUGEPTE_CACHE_NUM 3
+#else
+#define PTE_CACHE_NUM	0
+#define PMD_CACHE_NUM	1
+#define PUD_CACHE_NUM	1
+#define PGD_CACHE_NUM	0
+#define HUGEPTE_CACHE_NUM 2
+#endif
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
+}
+
+static inline void pgd_free(pgd_t *pgd)
+{
+	kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
+}
+
+#ifndef CONFIG_PPC_64K_PAGES
+
+#define pgd_populate(MM, PGD, PUD)	pgd_set(PGD, PUD)
+
+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
+				GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pud_free(pud_t *pud)
+{
+	kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
+}
+
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+	pud_set(pud, (unsigned long)pmd);
+}
+
+#define pmd_populate(mm, pmd, pte_page) \
+	pmd_populate_kernel(mm, pmd, page_address(pte_page))
+#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte))
+
+
+#else /* CONFIG_PPC_64K_PAGES */
+
+#define pud_populate(mm, pud, pmd)	pud_set(pud, (unsigned long)pmd)
+
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
+				       pte_t *pte)
+{
+	pmd_set(pmd, (unsigned long)pte);
+}
+
+#define pmd_populate(mm, pmd, pte_page) \
+	pmd_populate_kernel(mm, pmd, page_address(pte_page))
+
+#endif /* CONFIG_PPC_64K_PAGES */
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+	return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
+				GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pmd_free(pmd_t *pmd)
+{
+	kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
+}
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+					  unsigned long address)
+{
+	return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
+				GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+					 unsigned long address)
+{
+	return virt_to_page(pte_alloc_one_kernel(mm, address));
+}
+
+static inline void pte_free_kernel(pte_t *pte)
+{
+	kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
+}
+
+static inline void pte_free(struct page *ptepage)
+{
+	pte_free_kernel(page_address(ptepage));
+}
+
+#define PGF_CACHENUM_MASK	0x3
+
+typedef struct pgtable_free {
+	unsigned long val;
+} pgtable_free_t;
+
+static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
+						unsigned long mask)
+{
+	BUG_ON(cachenum > PGF_CACHENUM_MASK);
+
+	return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
+}
+
+static inline void pgtable_free(pgtable_free_t pgf)
+{
+	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
+	int cachenum = pgf.val & PGF_CACHENUM_MASK;
+
+	kmem_cache_free(pgtable_cache[cachenum], p);
+}
+
+extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+
+#define __pte_free_tlb(tlb, ptepage)	\
+	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
+		PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
+#define __pmd_free_tlb(tlb, pmd) 	\
+	pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
+		PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
+#ifndef CONFIG_PPC_64K_PAGES
+#define __pud_free_tlb(tlb, pud)	\
+	pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
+		PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#define check_pgt_cache()	do { } while (0)
+
+#endif /* _ASM_POWERPC_PGALLOC_64_H */
diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h
index b0830db..b4505ed 100644
--- a/include/asm-powerpc/pgalloc.h
+++ b/include/asm-powerpc/pgalloc.h
@@ -2,159 +2,11 @@ #ifndef _ASM_POWERPC_PGALLOC_H
 #define _ASM_POWERPC_PGALLOC_H
 #ifdef __KERNEL__
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/pgalloc.h>
+#ifdef CONFIG_PPC64
+#include <asm/pgalloc-64.h>
 #else
-
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/cpumask.h>
-#include <linux/percpu.h>
-
-extern struct kmem_cache *pgtable_cache[];
-
-#ifdef CONFIG_PPC_64K_PAGES
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PGD_CACHE_NUM	2
-#define HUGEPTE_CACHE_NUM 3
-#else
-#define PTE_CACHE_NUM	0
-#define PMD_CACHE_NUM	1
-#define PUD_CACHE_NUM	1
-#define PGD_CACHE_NUM	0
-#define HUGEPTE_CACHE_NUM 2
+#include <asm/pgalloc-32.h>
 #endif
 
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-	return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
-}
-
-static inline void pgd_free(pgd_t *pgd)
-{
-	kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
-}
-
-#ifndef CONFIG_PPC_64K_PAGES
-
-#define pgd_populate(MM, PGD, PUD)	pgd_set(PGD, PUD)
-
-static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
-	return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
-				GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pud_free(pud_t *pud)
-{
-	kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
-}
-
-static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
-{
-	pud_set(pud, (unsigned long)pmd);
-}
-
-#define pmd_populate(mm, pmd, pte_page) \
-	pmd_populate_kernel(mm, pmd, page_address(pte_page))
-#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte))
-
-
-#else /* CONFIG_PPC_64K_PAGES */
-
-#define pud_populate(mm, pud, pmd)	pud_set(pud, (unsigned long)pmd)
-
-static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
-				       pte_t *pte)
-{
-	pmd_set(pmd, (unsigned long)pte);
-}
-
-#define pmd_populate(mm, pmd, pte_page) \
-	pmd_populate_kernel(mm, pmd, page_address(pte_page))
-
-#endif /* CONFIG_PPC_64K_PAGES */
-
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
-	return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
-				GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pmd_free(pmd_t *pmd)
-{
-	kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
-}
-
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
-					  unsigned long address)
-{
-	return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
-				GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline struct page *pte_alloc_one(struct mm_struct *mm,
-					 unsigned long address)
-{
-	return virt_to_page(pte_alloc_one_kernel(mm, address));
-}
-		
-static inline void pte_free_kernel(pte_t *pte)
-{
-	kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
-}
-
-static inline void pte_free(struct page *ptepage)
-{
-	pte_free_kernel(page_address(ptepage));
-}
-
-#define PGF_CACHENUM_MASK	0x3
-
-typedef struct pgtable_free {
-	unsigned long val;
-} pgtable_free_t;
-
-static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
-						unsigned long mask)
-{
-	BUG_ON(cachenum > PGF_CACHENUM_MASK);
-
-	return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
-}
-
-static inline void pgtable_free(pgtable_free_t pgf)
-{
-	void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
-	int cachenum = pgf.val & PGF_CACHENUM_MASK;
-
-	kmem_cache_free(pgtable_cache[cachenum], p);
-}
-
-extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
-
-#define __pte_free_tlb(tlb, ptepage)	\
-	pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-		PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
-#define __pmd_free_tlb(tlb, pmd) 	\
-	pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
-		PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
-#ifndef CONFIG_PPC_64K_PAGES
-#define __pud_free_tlb(tlb, pud)	\
-	pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
-		PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
-#endif /* CONFIG_PPC_64K_PAGES */
-
-#define check_pgt_cache()	do { } while (0)
-
-#endif /* CONFIG_PPC64 */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
index 345d9b0..1744d6a 100644
--- a/include/asm-powerpc/pgtable-4k.h
+++ b/include/asm-powerpc/pgtable-4k.h
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_PGTABLE_4K_H
+#define _ASM_POWERPC_PGTABLE_4K_H
 /*
  * Entries per page directory level.  The PTE level must use a 64b record
  * for each page table entry.  The PMD and PGD level use a 32b record for
@@ -97,3 +99,7 @@ #define pud_offset(pgdp, addr)	\
 
 #define pud_ERROR(e) \
 	printk("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
+
+#define remap_4k_pfn(vma, addr, pfn, prot)	\
+	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
+#endif /* _ASM_POWERPC_PGTABLE_4K_H */
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 4b7126c..16ef497 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -1,6 +1,5 @@
 #ifndef _ASM_POWERPC_PGTABLE_64K_H
 #define _ASM_POWERPC_PGTABLE_64K_H
-#ifdef __KERNEL__
 
 #include <asm-generic/pgtable-nopud.h>
 
@@ -35,6 +34,7 @@ #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 #define _PAGE_HPTE_SUB	0x0ffff000 /* combo only: sub pages HPTE bits */
 #define _PAGE_HPTE_SUB0	0x08000000 /* combo only: first sub page */
 #define _PAGE_COMBO	0x10000000 /* this is a combo 4k page */
+#define _PAGE_4K_PFN	0x20000000 /* PFN is for a single 4k page */
 #define _PAGE_F_SECOND  0x00008000 /* full page: hidx bits */
 #define _PAGE_F_GIX     0x00007000 /* full page: hidx bits */
 
@@ -64,8 +64,6 @@ #define PMD_MASKED_BITS		0x1ff
 /* Bits to mask out from a PGD/PUD to get to the PMD page */
 #define PUD_MASKED_BITS		0x1ff
 
-#ifndef __ASSEMBLY__
-
 /* Manipulate "rpte" values */
 #define __real_pte(e,p) 	((real_pte_t) { \
 	(e), pte_val(*((p) + PTRS_PER_PTE)) })
@@ -93,6 +91,8 @@ #define pte_iterate_hashed_end() } while
 #define pte_pagesize_index(pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
-#endif /*  __ASSEMBLY__ */
-#endif /* __KERNEL__ */
+#define remap_4k_pfn(vma, addr, pfn, prot)				\
+	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+
 #endif /* _ASM_POWERPC_PGTABLE_64K_H */
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h
new file mode 100644
index 0000000..09662a2
--- /dev/null
+++ b/include/asm-powerpc/pgtable-ppc32.h
@@ -0,0 +1,813 @@
+#ifndef _ASM_POWERPC_PGTABLE_PPC32_H
+#define _ASM_POWERPC_PGTABLE_PPC32_H
+
+#include <asm-generic/pgtable-nopmd.h>
+
+#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h>		/* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/io.h>			/* For sub-arch specific PPC_PIN_SIZE */
+struct mm_struct;
+
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The PowerPC MMU uses a hash table containing PTEs, together with
+ * a set of 16 segment registers (on 32-bit implementations), to define
+ * the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much
+ * like that used by the i386, for the sake of the Linux memory
+ * management code.  Low-level assembler code in hashtable.S
+ * (procedure hash_page) is responsible for extracting ptes from the
+ * tree and putting them into the hash table when necessary, and
+ * updating the accessed and modified bits in the page table tree.
+ */
+
+/*
+ * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk.
+ * We also use the two level tables, but we can put the real bits in them
+ * needed for the TLB and tablewalk.  These definitions require Mx_CTR.PPM = 0,
+ * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1.  The level 2 descriptor has
+ * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit
+ * based upon user/super access.  The TLB does not have accessed nor write
+ * protect.  We assume that if the TLB get loaded with an entry it is
+ * accessed, and overload the changed bit for write protect.  We use
+ * two bits in the software pte that are supposed to be set to zero in
+ * the TLB entry (24 and 25) for these indicators.  Although the level 1
+ * descriptor contains the guarded and writethrough/copyback bits, we can
+ * set these at the page level since they get copied from the Mx_TWC
+ * register when the TLB entry is loaded.  We will use bit 27 for guard, since
+ * that is where it exists in the MD_TWC, and bit 26 for writethrough.
+ * These will get masked from the level 2 descriptor at TLB load time, and
+ * copied to the MD_TWC before it gets loaded.
+ * Large page sizes added.  We currently support two sizes, 4K and 8M.
+ * This also allows a TLB hander optimization because we can directly
+ * load the PMD into MD_TWC.  The 8M pages are only used for kernel
+ * mapping of well known areas.  The PMD (PGD) entries contain control
+ * flags in addition to the address, so care must be taken that the
+ * software no longer assumes these are only pointers.
+ */
+
+/*
+ * At present, all PowerPC 400-class processors share a similar TLB
+ * architecture. The instruction and data sides share a unified,
+ * 64-entry, fully-associative TLB which is maintained totally under
+ * software control. In addition, the instruction side has a
+ * hardware-managed, 4-entry, fully-associative TLB which serves as a
+ * first level to the shared TLB. These two TLBs are known as the UTLB
+ * and ITLB, respectively (see "mmu.h" for definitions).
+ */
+
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages.  -- paulus
+ *
+ * For any >32-bit physical address platform, we can use the following
+ * two level page table layout where the pgdir is 8KB and the MS 13 bits
+ * are an index to the second level table.  The combined pgdir/pmd first
+ * level has 2048 entries and the second level has 512 64-bit PTE entries.
+ * -Matt
+ */
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT	(PAGE_SHIFT + PTE_SHIFT)
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
+ */
+#define PTRS_PER_PTE	(1 << PTE_SHIFT)
+#define PTRS_PER_PMD	1
+#define PTRS_PER_PGD	(1 << (32 - PGDIR_SHIFT))
+
+#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 pte_ERROR(e) \
+	printk("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
+		(unsigned long long)pte_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 64MB value just means that there will be a 64MB "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. ;)
+ *
+ * We no longer map larger than phys RAM with the BATs so we don't have
+ * to worry about the VMALLOC_OFFSET causing problems.  We do have to worry
+ * about clashes between our early calls to ioremap() that start growing down
+ * from ioremap_base being run into the VM area allocations (growing upwards
+ * from VMALLOC_START).  For this reason we have ioremap_bot to check when
+ * we actually run into our mappings setup in the early boot with the VM
+ * system.  This really does become a problem for machines with good amounts
+ * of RAM.  -- Cort
+ */
+#define VMALLOC_OFFSET (0x1000000) /* 16M */
+#ifdef PPC_PIN_SIZE
+#define VMALLOC_START (((_ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#else
+#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#endif
+#define VMALLOC_END	ioremap_bot
+
+/*
+ * Bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+
+#if defined(CONFIG_40x)
+
+/* There are several potential gotchas here.  The 40x hardware TLBLO
+   field looks like this:
+
+   0  1  2  3  4  ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+   RPN.....................  0  0 EX WR ZSEL.......  W  I  M  G
+
+   Where possible we make the Linux PTE bits match up with this
+
+   - bits 20 and 21 must be cleared, because we use 4k pages (40x can
+     support down to 1k pages), this is done in the TLBMiss exception
+     handler.
+   - We use only zones 0 (for kernel pages) and 1 (for user pages)
+     of the 16 available.  Bit 24-26 of the TLB are cleared in the TLB
+     miss handler.  Bit 27 is PAGE_USER, thus selecting the correct
+     zone.
+   - PRESENT *must* be in the bottom two bits because swap cache
+     entries use the top 30 bits.  Because 40x doesn't support SMP
+     anyway, M is irrelevant so we borrow it for PAGE_PRESENT.  Bit 30
+     is cleared in the TLB miss handler before the TLB entry is loaded.
+   - All other bits of the PTE are loaded into TLBLO without
+     modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
+     software PTE bits.  We actually use use bits 21, 24, 25, and
+     30 respectively for the software bits: ACCESSED, DIRTY, RW, and
+     PRESENT.
+*/
+
+/* Definitions for 40x embedded chips. */
+#define	_PAGE_GUARDED	0x001	/* G: page is guarded from prefetch */
+#define _PAGE_FILE	0x001	/* when !present: nonlinear file mapping */
+#define _PAGE_PRESENT	0x002	/* software: PTE contains a translation */
+#define	_PAGE_NO_CACHE	0x004	/* I: caching is inhibited */
+#define	_PAGE_WRITETHRU	0x008	/* W: caching is write-through */
+#define	_PAGE_USER	0x010	/* matches one of the zone permission bits */
+#define	_PAGE_RW	0x040	/* software: Writes permitted */
+#define	_PAGE_DIRTY	0x080	/* software: dirty page */
+#define _PAGE_HWWRITE	0x100	/* hardware: Dirty & RW, set in exception */
+#define _PAGE_HWEXEC	0x200	/* hardware: EX permission */
+#define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
+
+#define _PMD_PRESENT	0x400	/* PMD points to page of PTEs */
+#define _PMD_BAD	0x802
+#define _PMD_SIZE	0x0e0	/* size field, != 0 for large-page PMD entry */
+#define _PMD_SIZE_4M	0x0c0
+#define _PMD_SIZE_16M	0x0e0
+#define PMD_PAGE_SIZE(pmdval)	(1024 << (((pmdval) & _PMD_SIZE) >> 4))
+
+#elif defined(CONFIG_44x)
+/*
+ * Definitions for PPC440
+ *
+ * Because of the 3 word TLB entries to support 36-bit addressing,
+ * the attribute are difficult to map in such a fashion that they
+ * are easily loaded during exception processing.  I decided to
+ * organize the entry so the ERPN is the only portion in the
+ * upper word of the PTE and the attribute bits below are packed
+ * in as sensibly as they can be in the area below a 4KB page size
+ * oriented RPN.  This at least makes it easy to load the RPN and
+ * ERPN fields in the TLB. -Matt
+ *
+ * Note that these bits preclude future use of a page size
+ * less than 4KB.
+ *
+ *
+ * PPC 440 core has following TLB attribute fields;
+ *
+ *   TLB1:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   RPN.................................  -  -  -  -  -  - ERPN.......
+ *
+ *   TLB2:
+ *   0  1  2  3  4  ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ *   -  -  -  -  -    - U0 U1 U2 U3 W  I  M  G  E   - UX UW UR SX SW SR
+ *
+ * There are some constrains and options, to decide mapping software bits
+ * into TLB entry.
+ *
+ *   - PRESENT *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - FILE *must* be in the bottom three bits because swap cache
+ *     entries use the top 29 bits for TLB2.
+ *
+ *   - CACHE COHERENT bit (M) has no effect on PPC440 core, because it
+ *     doesn't support SMP. So we can use this as software bit, like
+ *     DIRTY.
+ *
+ * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used
+ * for memory protection related functions (see PTE structure in
+ * include/asm-ppc/mmu.h).  The _PAGE_XXX definitions in this file map to the
+ * above bits.  Note that the bit values are CPU specific, not architecture
+ * specific.
+ *
+ * The kernel PTE entry holds an arch-dependent swp_entry structure under
+ * certain situations. In other words, in such situations some portion of
+ * the PTE bits are used as a swp_entry. In the PPC implementation, the
+ * 3-24th LSB are shared with swp_entry, however the 0-2nd three LSB still
+ * hold protection values. That means the three protection bits are
+ * reserved for both PTE and SWAP entry at the most significant three
+ * LSBs.
+ *
+ * There are three protection bits available for SWAP entry:
+ *	_PAGE_PRESENT
+ *	_PAGE_FILE
+ *	_PAGE_HASHPTE (if HW has)
+ *
+ * So those three bits have to be inside of 0-2nd LSB of PTE.
+ *
+ */
+
+#define _PAGE_PRESENT	0x00000001		/* S: PTE valid */
+#define	_PAGE_RW	0x00000002		/* S: Write permission */
+#define _PAGE_FILE	0x00000004		/* S: nonlinear file mapping */
+#define _PAGE_ACCESSED	0x00000008		/* S: Page referenced */
+#define _PAGE_HWWRITE	0x00000010		/* H: Dirty & RW */
+#define _PAGE_HWEXEC	0x00000020		/* H: Execute permission */
+#define	_PAGE_USER	0x00000040		/* S: User page */
+#define	_PAGE_ENDIAN	0x00000080		/* H: E bit */
+#define	_PAGE_GUARDED	0x00000100		/* H: G bit */
+#define	_PAGE_DIRTY	0x00000200		/* S: Page dirty */
+#define	_PAGE_NO_CACHE	0x00000400		/* H: I bit */
+#define	_PAGE_WRITETHRU	0x00000800		/* H: W bit */
+
+/* TODO: Add large page lowmem mapping support */
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK	0xffffffff00000000ULL
+
+#elif defined(CONFIG_FSL_BOOKE)
+/*
+   MMU Assist Register 3:
+
+   32 33 34 35 36  ... 50 51 52 53 54 55 56 57 58 59 60 61 62 63
+   RPN......................  0  0 U0 U1 U2 U3 UX SX UW SW UR SR
+
+   - PRESENT *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+
+   - FILE *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+*/
+
+/* Definitions for FSL Book-E Cores */
+#define _PAGE_PRESENT	0x00001	/* S: PTE contains a translation */
+#define _PAGE_USER	0x00002	/* S: User page (maps to UR) */
+#define _PAGE_FILE	0x00002	/* S: when !present: nonlinear file mapping */
+#define _PAGE_ACCESSED	0x00004	/* S: Page referenced */
+#define _PAGE_HWWRITE	0x00008	/* H: Dirty & RW, set in exception */
+#define _PAGE_RW	0x00010	/* S: Write permission */
+#define _PAGE_HWEXEC	0x00020	/* H: UX permission */
+
+#define _PAGE_ENDIAN	0x00040	/* H: E bit */
+#define _PAGE_GUARDED	0x00080	/* H: G bit */
+#define _PAGE_COHERENT	0x00100	/* H: M bit */
+#define _PAGE_NO_CACHE	0x00200	/* H: I bit */
+#define _PAGE_WRITETHRU	0x00400	/* H: W bit */
+
+#ifdef CONFIG_PTE_64BIT
+#define _PAGE_DIRTY	0x08000	/* S: Page dirty */
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK	0xffffffffffff0000ULL
+#else
+#define _PAGE_DIRTY	0x00800	/* S: Page dirty */
+#endif
+
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
+
+#elif defined(CONFIG_8xx)
+/* Definitions for 8xx embedded chips. */
+#define _PAGE_PRESENT	0x0001	/* Page is valid */
+#define _PAGE_FILE	0x0002	/* when !present: nonlinear file mapping */
+#define _PAGE_NO_CACHE	0x0002	/* I: cache inhibit */
+#define _PAGE_SHARED	0x0004	/* No ASID (context) compare */
+
+/* These five software bits must be masked out when the entry is loaded
+ * into the TLB.
+ */
+#define _PAGE_EXEC	0x0008	/* software: i-cache coherency required */
+#define _PAGE_GUARDED	0x0010	/* software: guarded access */
+#define _PAGE_DIRTY	0x0020	/* software: page changed */
+#define _PAGE_RW	0x0040	/* software: user write access allowed */
+#define _PAGE_ACCESSED	0x0080	/* software: page referenced */
+
+/* Setting any bits in the nibble with the follow two controls will
+ * require a TLB exception handler change.  It is assumed unused bits
+ * are always zero.
+ */
+#define _PAGE_HWWRITE	0x0100	/* h/w write enable: never set in Linux PTE */
+#define _PAGE_USER	0x0800	/* One of the PP bits, the other is USER&~RW */
+
+#define _PMD_PRESENT	0x0001
+#define _PMD_BAD	0x0ff0
+#define _PMD_PAGE_MASK	0x000c
+#define _PMD_PAGE_8M	0x000c
+
+/*
+ * The 8xx TLB miss handler allegedly sets _PAGE_ACCESSED in the PTE
+ * for an address even if _PAGE_PRESENT is not set, as a performance
+ * optimization.  This is a bug if you ever want to use swap unless
+ * _PAGE_ACCESSED is 2, which it isn't, or unless you have 8xx-specific
+ * definitions for __swp_entry etc. below, which would be gross.
+ *  -- paulus
+ */
+#define _PTE_NONE_MASK _PAGE_ACCESSED
+
+#else /* CONFIG_6xx */
+/* Definitions for 60x, 740/750, etc. */
+#define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
+#define _PAGE_HASHPTE	0x002	/* hash_page has made an HPTE for this pte */
+#define _PAGE_FILE	0x004	/* when !present: nonlinear file mapping */
+#define _PAGE_USER	0x004	/* usermode access allowed */
+#define _PAGE_GUARDED	0x008	/* G: prohibit speculative access */
+#define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE	0x020	/* I: cache inhibit */
+#define _PAGE_WRITETHRU	0x040	/* W: cache write-through */
+#define _PAGE_DIRTY	0x080	/* C: page changed */
+#define _PAGE_ACCESSED	0x100	/* R: page referenced */
+#define _PAGE_EXEC	0x200	/* software: i-cache coherency required */
+#define _PAGE_RW	0x400	/* software: user write access allowed */
+
+#define _PTE_NONE_MASK	_PAGE_HASHPTE
+
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
+#endif
+
+/*
+ * Some bits are only used on some cpu families...
+ */
+#ifndef _PAGE_HASHPTE
+#define _PAGE_HASHPTE	0
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK 0
+#endif
+#ifndef _PAGE_SHARED
+#define _PAGE_SHARED	0
+#endif
+#ifndef _PAGE_HWWRITE
+#define _PAGE_HWWRITE	0
+#endif
+#ifndef _PAGE_HWEXEC
+#define _PAGE_HWEXEC	0
+#endif
+#ifndef _PAGE_EXEC
+#define _PAGE_EXEC	0
+#endif
+#ifndef _PMD_PRESENT_MASK
+#define _PMD_PRESENT_MASK	_PMD_PRESENT
+#endif
+#ifndef _PMD_SIZE
+#define _PMD_SIZE	0
+#define PMD_PAGE_SIZE(pmd)	bad_call_to_PMD_PAGE_SIZE()
+#endif
+
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+/*
+ * Note: the _PAGE_COHERENT bit automatically gets set in the hardware
+ * PTE if CONFIG_SMP is defined (hash_page does this); there is no need
+ * to have it in the Linux PTE, and in fact the bit could be reused for
+ * another purpose.  -- paulus.
+ */
+
+#ifdef CONFIG_44x
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_GUARDED)
+#else
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED)
+#endif
+#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
+#define _PAGE_KERNEL	(_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE)
+
+#ifdef CONFIG_PPC_STD_MMU
+/* On standard PPC MMU, no user access implies kernel read/write access,
+ * so to write-protect kernel memory we must turn on user access */
+#define _PAGE_KERNEL_RO	(_PAGE_BASE | _PAGE_SHARED | _PAGE_USER)
+#else
+#define _PAGE_KERNEL_RO	(_PAGE_BASE | _PAGE_SHARED)
+#endif
+
+#define _PAGE_IO	(_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define _PAGE_RAM	(_PAGE_KERNEL | _PAGE_HWEXEC)
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH)
+/* We want the debuggers to be able to set breakpoints anywhere, so
+ * don't write protect the kernel text */
+#define _PAGE_RAM_TEXT	_PAGE_RAM
+#else
+#define _PAGE_RAM_TEXT	(_PAGE_KERNEL_RO | _PAGE_HWEXEC)
+#endif
+
+#define PAGE_NONE	__pgprot(_PAGE_BASE)
+#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
+#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define PAGE_KERNEL		__pgprot(_PAGE_RAM)
+#define PAGE_KERNEL_NOCACHE	__pgprot(_PAGE_IO)
+
+/*
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis.  So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY_X
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY_X
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY_X
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY_X
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY_X
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED_X
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY_X
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+/* Make sure we get a link error if PMD_PAGE_SIZE is ever called on a
+ * kernel without large page PMD support */
+extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
+
+/*
+ * Conversions between PTE values and page frame numbers.
+ */
+
+/* in some case we want to additionaly adjust where the pfn is in the pte to
+ * allow room for more flags */
+#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
+#define PFN_SHIFT_OFFSET	(PAGE_SHIFT + 8)
+#else
+#define PFN_SHIFT_OFFSET	(PAGE_SHIFT)
+#endif
+
+#define pte_pfn(x)		(pte_val(x) >> PFN_SHIFT_OFFSET)
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+
+#define pfn_pte(pfn, prot)	__pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) |\
+					pgprot_val(prot))
+#define mk_pte(page, prot)	pfn_pte(page_to_pfn(page), prot)
+
+/*
+ * 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];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* __ASSEMBLY__ */
+
+#define pte_none(pte)		((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
+#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+#define pte_clear(mm,addr,ptep)	do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define	pmd_bad(pmd)		(pmd_val(pmd) & _PMD_BAD)
+#define	pmd_present(pmd)	(pmd_val(pmd) & _PMD_PRESENT_MASK)
+#define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
+
+#ifndef __ASSEMBLY__
+/*
+ * 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_EXEC; }
+static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+
+static inline void pte_uncache(pte_t pte)       { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)         { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+static inline pte_t pte_rdprotect(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_exprotect(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_EXEC; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+static inline pte_t pte_mkread(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) {
+	pte_val(pte) |= _PAGE_RW; 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_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	return pte;
+}
+
+/*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry.  flush_hash_pages is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_pages(unsigned context, unsigned long va,
+			    unsigned long pmdval, int count);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va,
+			  unsigned long pmdval);
+
+/*
+ * Atomic PTE updates.
+ *
+ * pte_update clears and sets bit atomically, and returns
+ * the old pte value.  In the 64-bit PTE case we lock around the
+ * low PTE word since we expect ALL flag bits to be there
+ */
+#ifndef CONFIG_PTE_64BIT
+static inline unsigned long pte_update(pte_t *p, unsigned long clr,
+				       unsigned long set)
+{
+	unsigned long old, tmp;
+
+	__asm__ __volatile__("\
+1:	lwarx	%0,0,%3\n\
+	andc	%1,%0,%4\n\
+	or	%1,%1,%5\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%1,0,%3\n\
+	bne-	1b"
+	: "=&r" (old), "=&r" (tmp), "=m" (*p)
+	: "r" (p), "r" (clr), "r" (set), "m" (*p)
+	: "cc" );
+	return old;
+}
+#else
+static inline unsigned long long pte_update(pte_t *p, unsigned long clr,
+				       unsigned long set)
+{
+	unsigned long long old;
+	unsigned long tmp;
+
+	__asm__ __volatile__("\
+1:	lwarx	%L0,0,%4\n\
+	lwzx	%0,0,%3\n\
+	andc	%1,%L0,%5\n\
+	or	%1,%1,%6\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%1,0,%4\n\
+	bne-	1b"
+	: "=&r" (old), "=&r" (tmp), "=m" (*p)
+	: "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
+	: "cc" );
+	return old;
+}
+#endif
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ * On machines which use an MMU hash table we avoid changing the
+ * _PAGE_HASHPTE bit.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pte)
+{
+#if _PAGE_HASHPTE != 0
+	pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
+#else
+	*ptep = pte;
+#endif
+}
+
+/*
+ * 2.6 calles this without flushing the TLB entry, this is wrong
+ * for our hash-based implementation, we fix that up here
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep)
+{
+	unsigned long old;
+	old = pte_update(ptep, _PAGE_ACCESSED, 0);
+#if _PAGE_HASHPTE != 0
+	if (old & _PAGE_HASHPTE) {
+		unsigned long ptephys = __pa(ptep) & PAGE_MASK;
+		flush_hash_pages(context, addr, ptephys, 1);
+	}
+#endif
+	return (old & _PAGE_ACCESSED) != 0;
+}
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+	__ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
+					    unsigned long addr, pte_t *ptep)
+{
+	return (pte_update(ptep, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 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)
+{
+	return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+				      pte_t *ptep)
+{
+	pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
+}
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+	unsigned long bits = pte_val(entry) &
+		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
+	pte_update(ptep, 0, bits);
+}
+
+#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+	do {								   \
+		__ptep_set_access_flags(__ptep, __entry, __dirty);	   \
+		flush_tlb_page_nohash(__vma, __address);	       	   \
+	} while(0)
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+#define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
+
+/*
+ * Note that on Book E processors, the pmd contains the kernel virtual
+ * (lowmem) address of the pte page.  The physical address is less useful
+ * because everything runs with translation enabled (even the TLB miss
+ * handler).  On everything else the pmd contains the physical address
+ * of the pte page.  -- paulus
+ */
+#ifndef CONFIG_BOOKE
+#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_vaddr(pmd)	\
+	((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd)		\
+	(mem_map + (__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+#endif
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address)	 ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
+
+/* 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_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)	\
+	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+
+#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+extern void paging_init(void);
+
+/*
+ * Encode and decode a swap entry.
+ * Note that the bits we use in a PTE for representing a swap entry
+ * must not include the _PAGE_PRESENT bit, the _PAGE_FILE bit, or the
+ *_PAGE_HASHPTE bit (if used).  -- paulus
+ */
+#define __swp_type(entry)		((entry).val & 0x1f)
+#define __swp_offset(entry)		((entry).val >> 5)
+#define __swp_entry(type, offset)	((swp_entry_t) { (type) | ((offset) << 5) })
+#define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> 3 })
+#define __swp_entry_to_pte(x)		((pte_t) { (x).val << 3 })
+
+/* Encode and decode a nonlinear file mapping entry */
+#define PTE_FILE_MAX_BITS	29
+#define pte_to_pgoff(pte)	(pte_val(pte) >> 3)
+#define pgoff_to_pte(off)	((pte_t) { ((off) << 3) | _PAGE_FILE })
+
+/* CONFIG_APUS */
+/* For virtual address to physical address conversion */
+extern void cache_clear(__u32 addr, int length);
+extern void cache_push(__u32 addr, int length);
+extern int mm_end_of_chunk (unsigned long addr, int len);
+extern unsigned long iopa(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+
+/* Values for nocacheflag and cmode */
+/* These are not used by the APUS kernel_map, but prevents
+   compilation errors. */
+#define	KERNELMAP_FULL_CACHING		0
+#define	KERNELMAP_NOCACHE_SER		1
+#define	KERNELMAP_NOCACHE_NONSER	2
+#define	KERNELMAP_NO_COPYBACK		3
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
+				int nocacheflag, unsigned long *memavailp );
+
+/*
+ * Set cache mode of (kernel space) address range.
+ */
+extern void kernel_set_cachemode (unsigned long address, unsigned long size,
+                                 unsigned int cmode);
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define kern_addr_valid(addr)	(1)
+
+#ifdef CONFIG_PHYS_64BIT
+extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+			unsigned long paddr, unsigned long size, pgprot_t prot);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+					unsigned long vaddr,
+					unsigned long pfn,
+					unsigned long size,
+					pgprot_t prot)
+{
+	phys_addr_t paddr64 = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+	return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
+}
+#else
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+#endif
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
+
+extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
+		      pmd_t **pmdp);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC32_H */
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h
new file mode 100644
index 0000000..704c4e6
--- /dev/null
+++ b/include/asm-powerpc/pgtable-ppc64.h
@@ -0,0 +1,492 @@
+#ifndef _ASM_POWERPC_PGTABLE_PPC64_H_
+#define _ASM_POWERPC_PGTABLE_PPC64_H_
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the ppc64 hashed page table.
+ */
+
+#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <asm/processor.h>		/* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+struct mm_struct;
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_PPC_64K_PAGES
+#include <asm/pgtable-64k.h>
+#else
+#include <asm/pgtable-4k.h>
+#endif
+
+#define FIRST_USER_ADDRESS	0
+
+/*
+ * Size of EA range mapped by our pagetables.
+ */
+#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+                	    PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
+#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+
+#if TASK_SIZE_USER64 > PGTABLE_RANGE
+#error TASK_SIZE_USER64 exceeds pagetable range
+#endif
+
+#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
+#error TASK_SIZE_USER64 exceeds user VSID range
+#endif
+
+/*
+ * Define the address range of the vmalloc VM area.
+ */
+#define VMALLOC_START ASM_CONST(0xD000000000000000)
+#define VMALLOC_SIZE  ASM_CONST(0x80000000000)
+#define VMALLOC_END   (VMALLOC_START + VMALLOC_SIZE)
+
+/*
+ * Define the address range of the imalloc VM area.
+ */
+#define PHBS_IO_BASE	VMALLOC_END
+#define IMALLOC_BASE	(PHBS_IO_BASE + 0x80000000ul)	/* Reserve 2 gigs for PHBs */
+#define IMALLOC_END	(VMALLOC_START + PGTABLE_RANGE)
+
+/*
+ * Region IDs
+ */
+#define REGION_SHIFT		60UL
+#define REGION_MASK		(0xfUL << REGION_SHIFT)
+#define REGION_ID(ea)		(((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID	(REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID	(REGION_ID(PAGE_OFFSET))
+#define USER_REGION_ID		(0UL)
+
+/*
+ * Common bits in a linux-style PTE.  These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible. Additional
+ * bits may be defined in pgtable-*.h
+ */
+#define _PAGE_PRESENT	0x0001 /* software: pte contains a translation */
+#define _PAGE_USER	0x0002 /* matches one of the PP bits */
+#define _PAGE_FILE	0x0002 /* (!present only) software: pte holds file offset */
+#define _PAGE_EXEC	0x0004 /* No execute on POWER4 and newer (we invert) */
+#define _PAGE_GUARDED	0x0008
+#define _PAGE_COHERENT	0x0010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE	0x0020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU	0x0040 /* W: cache write-through */
+#define _PAGE_DIRTY	0x0080 /* C: page changed */
+#define _PAGE_ACCESSED	0x0100 /* R: page referenced */
+#define _PAGE_RW	0x0200 /* software: user write access allowed */
+#define _PAGE_HASHPTE	0x0400 /* software: pte has an associated HPTE */
+#define _PAGE_BUSY	0x0800 /* software: PTE & hash are busy */
+
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
+
+#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY)
+
+/* __pgprot defined in asm-powerpc/page.h */
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
+#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_WRENABLE)
+#define PAGE_KERNEL_CI	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+			       _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
+
+#define PAGE_AGP	__pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
+#define HAVE_PAGE_AGP
+
+/* PTEIDX nibble */
+#define _PTEIDX_SECONDARY	0x8
+#define _PTEIDX_GROUP_IX	0x7
+
+
+/*
+ * POWER4 and newer have per page execute protection, older chips can only
+ * do this on a segment (256MB) basis.
+ *
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ *
+ * Note due to the way vm flags are laid out, the bits are XWR
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY_X
+#define __P101	PAGE_READONLY_X
+#define __P110	PAGE_COPY_X
+#define __P111	PAGE_COPY_X
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY_X
+#define __S101	PAGE_READONLY_X
+#define __S110	PAGE_SHARED_X
+#define __S111	PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+
+/*
+ * 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))
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+
+#endif
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * mk_pte takes a (struct page *) as input
+ */
+#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
+
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+	pte_t pte;
+
+
+	pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
+	return pte;
+}
+
+#define pte_modify(_pte, newprot) \
+  (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
+
+#define pte_none(pte)		((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
+#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
+
+/* pte_clear moved to later in this file */
+
+#define pte_pfn(x)		((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
+#define pte_page(x)		pfn_to_page(pte_pfn(x))
+
+#define PMD_BAD_BITS		(PTE_TABLE_SIZE-1)
+#define PUD_BAD_BITS		(PMD_TABLE_SIZE-1)
+
+#define pmd_set(pmdp, pmdval) 	(pmd_val(*(pmdp)) = (pmdval))
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define	pmd_bad(pmd)		(!is_kernel_addr(pmd_val(pmd)) \
+				 || (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_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))
+#define	pud_bad(pud)		(!is_kernel_addr(pud_val(pud)) \
+				 || (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_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);})
+
+/*
+ * Find an entry in a page-table-directory.  We combine the address region
+ * (the high order N bits) and the pgd portion of the address.
+ */
+/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
+
+#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
+
+#define pmd_offset(pudp,addr) \
+  (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+
+#define pte_offset_kernel(dir,addr) \
+  (((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))
+#define pte_unmap(pte)			do { } while(0)
+#define pte_unmap_nested(pte)		do { } while(0)
+
+/* to find an entry in a kernel page-table-directory */
+/* This now only contains the vmalloc pages */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/*
+ * 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_EXEC;}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+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_EXEC; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_RW); return pte; }
+static inline pte_t pte_mkclean(pte_t pte) {
+	pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
+static inline pte_t pte_mkold(pte_t pte) {
+	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkread(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) {
+	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) {
+	pte_val(pte) |= _PAGE_RW; 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_mkhuge(pte_t pte) {
+	return pte; }
+
+/* Atomic PTE updates */
+static inline unsigned long pte_update(struct mm_struct *mm,
+				       unsigned long addr,
+				       pte_t *ptep, unsigned long clr,
+				       int huge)
+{
+	unsigned long old, tmp;
+
+	__asm__ __volatile__(
+	"1:	ldarx	%0,0,%3		# pte_update\n\
+	andi.	%1,%0,%6\n\
+	bne-	1b \n\
+	andc	%1,%0,%4 \n\
+	stdcx.	%1,0,%3 \n\
+	bne-	1b"
+	: "=&r" (old), "=&r" (tmp), "=m" (*ptep)
+	: "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
+	: "cc" );
+
+	if (old & _PAGE_HASHPTE)
+		hpte_need_flush(mm, addr, ptep, old, huge);
+	return old;
+}
+
+static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
+					      unsigned long addr, pte_t *ptep)
+{
+	unsigned long old;
+
+       	if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+		return 0;
+	old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
+	return (old & _PAGE_ACCESSED) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(__vma, __addr, __ptep)		   \
+({									   \
+	int __r;							   \
+	__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
+	__r;								   \
+})
+
+/*
+ * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
+ * moment we always flush but we need to fix hpte_update and test if the
+ * optimisation is worth it.
+ */
+static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
+					      unsigned long addr, pte_t *ptep)
+{
+	unsigned long old;
+
+       	if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
+		return 0;
+	old = pte_update(mm, addr, ptep, _PAGE_DIRTY, 0);
+	return (old & _PAGE_DIRTY) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define ptep_test_and_clear_dirty(__vma, __addr, __ptep)		   \
+({									   \
+	int __r;							   \
+	__r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
+	__r;								   \
+})
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+				      pte_t *ptep)
+{
+	unsigned long old;
+
+       	if ((pte_val(*ptep) & _PAGE_RW) == 0)
+       		return;
+	old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
+}
+
+/*
+ * We currently remove entries from the hashtable regardless of whether
+ * the entry was young or dirty. The generic routines only flush if the
+ * entry was young or dirty which is not good enough.
+ *
+ * We should be more intelligent about this but for the moment we override
+ * these functions and force a tlb flush unconditionally
+ */
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+#define ptep_clear_flush_young(__vma, __address, __ptep)		\
+({									\
+	int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
+						  __ptep);		\
+	__young;							\
+})
+
+#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
+#define ptep_clear_flush_dirty(__vma, __address, __ptep)		\
+({									\
+	int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
+						  __ptep); 		\
+	__dirty;							\
+})
+
+#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)
+{
+	unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
+	return __pte(old);
+}
+
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
+			     pte_t * ptep)
+{
+	pte_update(mm, addr, ptep, ~0UL, 0);
+}
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pte)
+{
+	if (pte_present(*ptep))
+		pte_clear(mm, addr, ptep);
+	pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+	*ptep = pte;
+}
+
+/* Set the dirty and/or accessed bits atomically in a linux PTE, this
+ * function doesn't need to flush the hash entry
+ */
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+	unsigned long bits = pte_val(entry) &
+		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
+	unsigned long old, tmp;
+
+	__asm__ __volatile__(
+	"1:	ldarx	%0,0,%4\n\
+		andi.	%1,%0,%6\n\
+		bne-	1b \n\
+		or	%0,%3,%0\n\
+		stdcx.	%0,0,%4\n\
+		bne-	1b"
+	:"=&r" (old), "=&r" (tmp), "=m" (*ptep)
+	:"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
+	:"cc");
+}
+#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+	do {								   \
+		__ptep_set_access_flags(__ptep, __entry, __dirty);	   \
+		flush_tlb_page_nohash(__vma, __address);	       	   \
+	} while(0)
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+#define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+				     unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
+
+#define pte_ERROR(e) \
+	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern pgd_t swapper_pg_dir[];
+
+extern void paging_init(void);
+
+/* Encode and de-code a swap entry */
+#define __swp_type(entry)	(((entry).val >> 1) & 0x3f)
+#define __swp_offset(entry)	((entry).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) >> PTE_RPN_SHIFT})
+#define __swp_entry_to_pte(x)	((pte_t) { (x).val << PTE_RPN_SHIFT })
+#define pte_to_pgoff(pte)	(pte_val(pte) >> PTE_RPN_SHIFT)
+#define pgoff_to_pte(off)	((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
+#define PTE_FILE_MAX_BITS	(BITS_PER_LONG - PTE_RPN_SHIFT)
+
+/*
+ * kern_addr_valid is intended to indicate whether an address is a valid
+ * kernel address.  Most 32-bit archs define it as always true (like this)
+ * but most 64-bit archs actually perform a test.  What should we do here?
+ * The only use is in fs/ncpfs/dir.c
+ */
+#define kern_addr_valid(addr)	(1)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
+		remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+void pgtable_cache_init(void);
+
+/*
+ * find_linux_pte returns the address of a linux pte for a given
+ * effective address and directory.  If not found, it returns zero.
+ */static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
+{
+	pgd_t *pg;
+	pud_t *pu;
+	pmd_t *pm;
+	pte_t *pt = NULL;
+
+	pg = pgdir + pgd_index(ea);
+	if (!pgd_none(*pg)) {
+		pu = pud_offset(pg, ea);
+		if (!pud_none(*pu)) {
+			pm = pmd_offset(pu, ea);
+			if (pmd_present(*pm))
+				pt = pte_offset_kernel(pm, ea);
+		}
+	}
+	return pt;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 10f5274..78bf4ae 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -2,530 +2,15 @@ #ifndef _ASM_POWERPC_PGTABLE_H
 #define _ASM_POWERPC_PGTABLE_H
 #ifdef __KERNEL__
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/pgtable.h>
+#if defined(CONFIG_PPC64)
+#  include <asm/pgtable-ppc64.h>
 #else
-
-/*
- * This file contains the functions and defines necessary to modify and use
- * the ppc64 hashed page table.
- */
-
-#ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <asm/processor.h>		/* For TASK_SIZE */
-#include <asm/mmu.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-struct mm_struct;
-#endif /* __ASSEMBLY__ */
-
-#ifdef CONFIG_PPC_64K_PAGES
-#include <asm/pgtable-64k.h>
-#else
-#include <asm/pgtable-4k.h>
-#endif
-
-#define FIRST_USER_ADDRESS	0
-
-/*
- * Size of EA range mapped by our pagetables.
- */
-#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
-                	    PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
-#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
-
-#if TASK_SIZE_USER64 > PGTABLE_RANGE
-#error TASK_SIZE_USER64 exceeds pagetable range
-#endif
-
-#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
-#error TASK_SIZE_USER64 exceeds user VSID range
-#endif
-
-/*
- * Define the address range of the vmalloc VM area.
- */
-#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE  ASM_CONST(0x80000000000)
-#define VMALLOC_END   (VMALLOC_START + VMALLOC_SIZE)
-
-/*
- * Define the address range of the imalloc VM area.
- */
-#define PHBS_IO_BASE	VMALLOC_END
-#define IMALLOC_BASE	(PHBS_IO_BASE + 0x80000000ul)	/* Reserve 2 gigs for PHBs */
-#define IMALLOC_END	(VMALLOC_START + PGTABLE_RANGE)
-
-/*
- * Region IDs
- */
-#define REGION_SHIFT		60UL
-#define REGION_MASK		(0xfUL << REGION_SHIFT)
-#define REGION_ID(ea)		(((unsigned long)(ea)) >> REGION_SHIFT)
-
-#define VMALLOC_REGION_ID	(REGION_ID(VMALLOC_START))
-#define KERNEL_REGION_ID	(REGION_ID(PAGE_OFFSET))
-#define USER_REGION_ID		(0UL)
-
-/*
- * Common bits in a linux-style PTE.  These match the bits in the
- * (hardware-defined) PowerPC PTE as closely as possible. Additional
- * bits may be defined in pgtable-*.h
- */
-#define _PAGE_PRESENT	0x0001 /* software: pte contains a translation */
-#define _PAGE_USER	0x0002 /* matches one of the PP bits */
-#define _PAGE_FILE	0x0002 /* (!present only) software: pte holds file offset */
-#define _PAGE_EXEC	0x0004 /* No execute on POWER4 and newer (we invert) */
-#define _PAGE_GUARDED	0x0008
-#define _PAGE_COHERENT	0x0010 /* M: enforce memory coherence (SMP systems) */
-#define _PAGE_NO_CACHE	0x0020 /* I: cache inhibit */
-#define _PAGE_WRITETHRU	0x0040 /* W: cache write-through */
-#define _PAGE_DIRTY	0x0080 /* C: page changed */
-#define _PAGE_ACCESSED	0x0100 /* R: page referenced */
-#define _PAGE_RW	0x0200 /* software: user write access allowed */
-#define _PAGE_HASHPTE	0x0400 /* software: pte has an associated HPTE */
-#define _PAGE_BUSY	0x0800 /* software: PTE & hash are busy */ 
-
-#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
-
-#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY)
-
-/* __pgprot defined in asm-powerpc/page.h */
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-
-#define PAGE_SHARED	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
-#define PAGE_SHARED_X	__pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY	__pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_KERNEL	__pgprot(_PAGE_BASE | _PAGE_WRENABLE)
-#define PAGE_KERNEL_CI	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
-			       _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
-#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
-
-#define PAGE_AGP	__pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
-#define HAVE_PAGE_AGP
-
-/* PTEIDX nibble */
-#define _PTEIDX_SECONDARY	0x8
-#define _PTEIDX_GROUP_IX	0x7
-
-
-/*
- * POWER4 and newer have per page execute protection, older chips can only
- * do this on a segment (256MB) basis.
- *
- * Also, write permissions imply read permissions.
- * This is the closest we can get..
- *
- * Note due to the way vm flags are laid out, the bits are XWR
- */
-#define __P000	PAGE_NONE
-#define __P001	PAGE_READONLY
-#define __P010	PAGE_COPY
-#define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY_X
-#define __P101	PAGE_READONLY_X
-#define __P110	PAGE_COPY_X
-#define __P111	PAGE_COPY_X
-
-#define __S000	PAGE_NONE
-#define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY_X
-#define __S101	PAGE_READONLY_X
-#define __S110	PAGE_SHARED_X
-#define __S111	PAGE_SHARED_X
-
-#ifndef __ASSEMBLY__
-
-/*
- * 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))
-#endif /* __ASSEMBLY__ */
-
-#ifdef CONFIG_HUGETLB_PAGE
-
-#define HAVE_ARCH_UNMAPPED_AREA
-#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
-
+#  include <asm/pgtable-ppc32.h>
 #endif
 
 #ifndef __ASSEMBLY__
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- *
- * mk_pte takes a (struct page *) as input
- */
-#define mk_pte(page, pgprot)	pfn_pte(page_to_pfn(page), (pgprot))
-
-static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
-{
-	pte_t pte;
-
-
-	pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
-	return pte;
-}
-
-#define pte_modify(_pte, newprot) \
-  (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
-
-#define pte_none(pte)		((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
-#define pte_present(pte)	(pte_val(pte) & _PAGE_PRESENT)
-
-/* pte_clear moved to later in this file */
-
-#define pte_pfn(x)		((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
-#define pte_page(x)		pfn_to_page(pte_pfn(x))
-
-#define PMD_BAD_BITS		(PTE_TABLE_SIZE-1)
-#define PUD_BAD_BITS		(PMD_TABLE_SIZE-1)
-
-#define pmd_set(pmdp, pmdval) 	(pmd_val(*(pmdp)) = (pmdval))
-#define pmd_none(pmd)		(!pmd_val(pmd))
-#define	pmd_bad(pmd)		(!is_kernel_addr(pmd_val(pmd)) \
-				 || (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_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))
-#define	pud_bad(pud)		(!is_kernel_addr(pud_val(pud)) \
-				 || (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_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);})
-
-/* 
- * Find an entry in a page-table-directory.  We combine the address region 
- * (the high order N bits) and the pgd portion of the address.
- */
-/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
-#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
-
-#define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
-
-#define pmd_offset(pudp,addr) \
-  (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
-
-#define pte_offset_kernel(dir,addr) \
-  (((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))
-#define pte_unmap(pte)			do { } while(0)
-#define pte_unmap_nested(pte)		do { } while(0)
-
-/* to find an entry in a kernel page-table-directory */
-/* This now only contains the vmalloc pages */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-/*
- * 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_EXEC;}
-static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
-static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
-
-static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
-static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
-
-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_EXEC; return pte; }
-static inline pte_t pte_wrprotect(pte_t pte) {
-	pte_val(pte) &= ~(_PAGE_RW); return pte; }
-static inline pte_t pte_mkclean(pte_t pte) {
-	pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-static inline pte_t pte_mkold(pte_t pte) {
-	pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkread(pte_t pte) {
-	pte_val(pte) |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) {
-	pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) {
-	pte_val(pte) |= _PAGE_RW; 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_mkhuge(pte_t pte) {
-	return pte; }
-
-/* Atomic PTE updates */
-static inline unsigned long pte_update(pte_t *p, unsigned long clr)
-{
-	unsigned long old, tmp;
-
-	__asm__ __volatile__(
-	"1:	ldarx	%0,0,%3		# pte_update\n\
-	andi.	%1,%0,%6\n\
-	bne-	1b \n\
-	andc	%1,%0,%4 \n\
-	stdcx.	%1,0,%3 \n\
-	bne-	1b"
-	: "=&r" (old), "=&r" (tmp), "=m" (*p)
-	: "r" (p), "r" (clr), "m" (*p), "i" (_PAGE_BUSY)
-	: "cc" );
-	return old;
-}
-
-/* PTE updating functions, this function puts the PTE in the
- * batch, doesn't actually triggers the hash flush immediately,
- * you need to call flush_tlb_pending() to do that.
- * Pass -1 for "normal" size (4K or 64K)
- */
-extern void hpte_update(struct mm_struct *mm, unsigned long addr,
-			pte_t *ptep, unsigned long pte, int huge);
-
-static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
-					      unsigned long addr, pte_t *ptep)
-{
-	unsigned long old;
-
-       	if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
-		return 0;
-	old = pte_update(ptep, _PAGE_ACCESSED);
-	if (old & _PAGE_HASHPTE) {
-		hpte_update(mm, addr, ptep, old, 0);
-		flush_tlb_pending();
-	}
-	return (old & _PAGE_ACCESSED) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define ptep_test_and_clear_young(__vma, __addr, __ptep)		   \
-({									   \
-	int __r;							   \
-	__r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
-	__r;								   \
-})
-
-/*
- * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
- * moment we always flush but we need to fix hpte_update and test if the
- * optimisation is worth it.
- */
-static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
-					      unsigned long addr, pte_t *ptep)
-{
-	unsigned long old;
-
-       	if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
-		return 0;
-	old = pte_update(ptep, _PAGE_DIRTY);
-	if (old & _PAGE_HASHPTE)
-		hpte_update(mm, addr, ptep, old, 0);
-	return (old & _PAGE_DIRTY) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define ptep_test_and_clear_dirty(__vma, __addr, __ptep)		   \
-({									   \
-	int __r;							   \
-	__r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
-	__r;								   \
-})
-
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
-				      pte_t *ptep)
-{
-	unsigned long old;
-
-       	if ((pte_val(*ptep) & _PAGE_RW) == 0)
-       		return;
-	old = pte_update(ptep, _PAGE_RW);
-	if (old & _PAGE_HASHPTE)
-		hpte_update(mm, addr, ptep, old, 0);
-}
-
-/*
- * We currently remove entries from the hashtable regardless of whether
- * the entry was young or dirty. The generic routines only flush if the
- * entry was young or dirty which is not good enough.
- *
- * We should be more intelligent about this but for the moment we override
- * these functions and force a tlb flush unconditionally
- */
-#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-#define ptep_clear_flush_young(__vma, __address, __ptep)		\
-({									\
-	int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
-						  __ptep);		\
-	__young;							\
-})
-
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(__vma, __address, __ptep)		\
-({									\
-	int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
-						  __ptep); 		\
-	flush_tlb_page(__vma, __address);				\
-	__dirty;							\
-})
-
-#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)
-{
-	unsigned long old = pte_update(ptep, ~0UL);
-
-	if (old & _PAGE_HASHPTE)
-		hpte_update(mm, addr, ptep, old, 0);
-	return __pte(old);
-}
-
-static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
-			     pte_t * ptep)
-{
-	unsigned long old = pte_update(ptep, ~0UL);
-
-	if (old & _PAGE_HASHPTE)
-		hpte_update(mm, addr, ptep, old, 0);
-}
-
-/*
- * set_pte stores a linux PTE into the linux page table.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-			      pte_t *ptep, pte_t pte)
-{
-	if (pte_present(*ptep)) {
-		pte_clear(mm, addr, ptep);
-		flush_tlb_pending();
-	}
-	pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
-	*ptep = pte;
-}
-
-/* Set the dirty and/or accessed bits atomically in a linux PTE, this
- * function doesn't need to flush the hash entry
- */
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
-{
-	unsigned long bits = pte_val(entry) &
-		(_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
-	unsigned long old, tmp;
-
-	__asm__ __volatile__(
-	"1:	ldarx	%0,0,%4\n\
-		andi.	%1,%0,%6\n\
-		bne-	1b \n\
-		or	%0,%3,%0\n\
-		stdcx.	%0,0,%4\n\
-		bne-	1b"
-	:"=&r" (old), "=&r" (tmp), "=m" (*ptep)
-	:"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
-	:"cc");
-}
-#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-	do {								   \
-		__ptep_set_access_flags(__ptep, __entry, __dirty);	   \
-		flush_tlb_page_nohash(__vma, __address);	       	   \
-	} while(0)
-
-/*
- * Macro to mark a page protection value as "uncacheable".
- */
-#define pgprot_noncached(prot)	(__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-				     unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
-#define __HAVE_ARCH_PTE_SAME
-#define pte_same(A,B)	(((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
-
-#define pte_ERROR(e) \
-	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#define pmd_ERROR(e) \
-	printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
-#define pgd_ERROR(e) \
-	printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
-
-extern pgd_t swapper_pg_dir[];
-
-extern void paging_init(void);
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to put a corresponding HPTE into the hash table
- * ahead of time, instead of waiting for the inevitable extra
- * hash-table miss exception.
- */
-struct vm_area_struct;
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-/* Encode and de-code a swap entry */
-#define __swp_type(entry)	(((entry).val >> 1) & 0x3f)
-#define __swp_offset(entry)	((entry).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) >> PTE_RPN_SHIFT})
-#define __swp_entry_to_pte(x)	((pte_t) { (x).val << PTE_RPN_SHIFT })
-#define pte_to_pgoff(pte)	(pte_val(pte) >> PTE_RPN_SHIFT)
-#define pgoff_to_pte(off)	((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
-#define PTE_FILE_MAX_BITS	(BITS_PER_LONG - PTE_RPN_SHIFT)
-
-/*
- * kern_addr_valid is intended to indicate whether an address is a valid
- * kernel address.  Most 32-bit archs define it as always true (like this)
- * but most 64-bit archs actually perform a test.  What should we do here?
- * The only use is in fs/ncpfs/dir.c
- */
-#define kern_addr_valid(addr)	(1)
-
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
-		remap_pfn_range(vma, vaddr, pfn, size, prot)
-
-void pgtable_cache_init(void);
-
-/*
- * find_linux_pte returns the address of a linux pte for a given 
- * effective address and directory.  If not found, it returns zero.
- */static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
-{
-	pgd_t *pg;
-	pud_t *pu;
-	pmd_t *pm;
-	pte_t *pt = NULL;
-
-	pg = pgdir + pgd_index(ea);
-	if (!pgd_none(*pg)) {
-		pu = pud_offset(pg, ea);
-		if (!pud_none(*pu)) {
-			pm = pmd_offset(pu, ea);
-			if (pmd_present(*pm))
-				pt = pte_offset_kernel(pm, ea);
-		}
-	}
-	return pt;
-}
-
 #include <asm-generic/pgtable.h>
-
 #endif /* __ASSEMBLY__ */
 
-#endif /* CONFIG_PPC64 */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index d3599cc..d43d91b 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -146,7 +146,7 @@ struct device_node;
 static inline long pmac_call_feature(int selector, struct device_node* node,
 					long param, long value)
 {
-	if (!ppc_md.feature_call)
+	if (!ppc_md.feature_call || !machine_is(powermac))
 		return -ENODEV;
 	return ppc_md.feature_call(selector, node, param, value);
 }
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 8588be6..d6a616a 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -30,6 +30,7 @@ void release_pmc_hardware(void);
 
 #ifdef CONFIG_PPC64
 void power4_enable_pmcs(void);
+void pasemi_enable_pmcs(void);
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index ab6eddb..d74b296 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -10,6 +10,8 @@ #ifndef _ASM_POWERPC_PPC_PCI_H
 #define _ASM_POWERPC_PPC_PCI_H
 #ifdef __KERNEL__
 
+#ifdef CONFIG_PCI
+
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 
@@ -22,7 +24,7 @@ extern void pci_setup_phb_io_dynamic(str
 extern struct list_head hose_list;
 extern int global_phb_number;
 
-extern unsigned long find_and_init_phbs(void);
+extern void find_and_init_phbs(void);
 
 extern struct pci_dev *ppc64_isabridge_dev;	/* may be NULL if no ISA bus */
 
@@ -68,7 +70,7 @@ 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
+ * rtas_pci_enable - enable IO transfers for this slot
  * @pdn:       pci device node
  * @function:  either EEH_THAW_MMIO or EEH_THAW_DMA 
  *
@@ -89,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, 
  * Returns a non-zero value if the reset failed.
  */
 int rtas_set_slot_reset (struct pci_dn *);
+int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
 
 /** 
  * eeh_restore_bars - Restore device configuration info.
@@ -126,5 +129,10 @@ struct device_node * find_device_pe(stru
 
 #endif
 
+#else /* CONFIG_PCI */
+static inline void find_and_init_phbs(void) { }
+static inline void init_pci_config_tokens(void) { }
+#endif /* !CONFIG_PCI */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_PPC_PCI_H */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index a26c32e..d947b16 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -133,7 +133,6 @@ #endif
 	mm_segment_t	fs;		/* for get_fs() validation */
 #ifdef CONFIG_PPC32
 	void		*pgdir;		/* root of page-table tree */
-	signed long	last_syscall;
 #endif
 #if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
 	unsigned long	dbcr0;		/* debug control register values */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 020ed01..6845af9 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -18,6 +18,7 @@ #ifdef __KERNEL__
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/platform_device.h>
+#include <asm/irq.h>
 #include <asm/atomic.h>
 
 /* Definitions used by the flattened device tree */
@@ -58,6 +59,8 @@ struct boot_param_header
 	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 */
+	/* version 17 fields below */
+	u32	dt_struct_size;		/* size of the DT structure block */
 };
 
 
@@ -68,7 +71,7 @@ typedef u32 ihandle;
 struct property {
 	char	*name;
 	int	length;
-	unsigned char *value;
+	void	*value;
 	struct property *next;
 };
 
@@ -108,14 +111,6 @@ static inline void set_node_proc_entry(s
 }
 
 
-/* OBSOLETE: Old style node lookup */
-extern struct device_node *find_devices(const char *name);
-extern struct device_node *find_type_devices(const char *type);
-extern struct device_node *find_path_device(const char *path);
-extern struct device_node *find_compatible_devices(const char *type,
-						   const char *compat);
-extern struct device_node *find_all_nodes(void);
-
 /* New style node lookup */
 extern struct device_node *of_find_node_by_name(struct device_node *from,
 	const char *name);
@@ -159,15 +154,17 @@ 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(const struct device_node *device,
+extern int of_device_is_compatible(const struct device_node *device,
 				const char *);
+#define device_is_compatible(d, c)	of_device_is_compatible((d), (c))
 extern int machine_is_compatible(const char *compat);
-extern const void *get_property(const struct device_node *node,
+extern const void *of_get_property(const struct device_node *node,
 				const char *name,
 				int *lenp);
+#define get_property(a, b, c)	of_get_property((a), (b), (c))
 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);
+extern int of_n_addr_cells(struct device_node* np);
+extern int of_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -336,20 +333,17 @@ extern int of_irq_map_one(struct device_
 struct pci_dev;
 extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
 
-static inline int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
-{
-	int irq = irq_of_parse_and_map(dev, index);
-
-	/* Only dereference the resource if both the
-	 * resource and the irq are valid. */
-	if (r && irq != NO_IRQ) {
-		r->start = r->end = irq;
-		r->flags = IORESOURCE_IRQ;
-	}
-
-	return irq;
-}
+extern int of_irq_to_resource(struct device_node *dev, int index,
+			struct resource *r);
 
+/**
+ * of_iomap - Maps the memory mapped IO for a given device_node
+ * @device:	the device whose io range will be mapped
+ * @index:	index of the io range
+ *
+ * Returns a pointer to the mapped memory
+ */
+extern void __iomem *of_iomap(struct device_node *device, int index);
 
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 821581a..13c372d 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -167,26 +167,31 @@ enum ps3_cpu_binding {
 	PS3_BINDING_CPU_1 = 1,
 };
 
-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
 	unsigned int *virq);
-int ps3_free_io_irq(unsigned int virq);
-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq);
-int ps3_free_event_irq(unsigned int virq);
+int ps3_virq_destroy(unsigned int virq);
+int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+	unsigned int *virq);
+int ps3_irq_plug_destroy(unsigned int virq);
+int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq);
+int ps3_event_receive_port_destroy(unsigned int virq);
 int ps3_send_event_locally(unsigned int virq);
-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
-	const struct ps3_device_id *did, unsigned int interrupt_id,
+
+int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
 	unsigned int *virq);
-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
-	unsigned int interrupt_id, unsigned int virq);
-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+int ps3_io_irq_destroy(unsigned int virq);
+int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
 	unsigned int *virq);
-int ps3_free_vuart_irq(unsigned int virq);
-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+int ps3_vuart_irq_destroy(unsigned int virq);
+int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
 	unsigned int class, unsigned int *virq);
-int ps3_free_spe_irq(unsigned int virq);
-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+int ps3_spe_irq_destroy(unsigned int virq);
+
+int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
+	const struct ps3_device_id *did, unsigned int interrupt_id,
 	unsigned int *virq);
-int ps3_free_irq(unsigned int virq);
+int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
+	unsigned int interrupt_id, unsigned int virq);
 
 /* lv1 result codes */
 
diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
index 43e90ea..9efc40f 100644
--- a/include/asm-powerpc/ps3av.h
+++ b/include/asm-powerpc/ps3av.h
@@ -18,8 +18,6 @@
 #ifndef _ASM_POWERPC_PS3AV_H_
 #define _ASM_POWERPC_PS3AV_H_
 
-#include <linux/mutex.h>
-
 /** command for ioctl() **/
 #define PS3AV_VERSION 0x205	/* version of ps3av command */
 
@@ -643,24 +641,6 @@ struct ps3av_pkt_avb_param {
 	u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE];
 };
 
-struct ps3av {
-	int available;
-	struct semaphore sem;
-	struct semaphore ping;
-	struct semaphore pong;
-	struct mutex mutex;
-	int open_count;
-	struct ps3_vuart_port_device *dev;
-
-	int region;
-	struct ps3av_pkt_av_get_hw_conf av_hw_conf;
-	u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
-	u32 opt_port[PS3AV_OPT_PORT_MAX];
-	u32 head[PS3AV_HEAD_MAX];
-	u32 audio_port;
-	int ps3av_mode;
-	int ps3av_mode_old;
-};
 
 /** command status **/
 #define PS3AV_STATUS_SUCCESS			0x0000	/* success */
@@ -718,6 +698,7 @@ #endif
 extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *,
 					    u32);
 
+struct ps3_vuart_port_device;
 extern int ps3av_vuart_write(struct ps3_vuart_port_device *dev,
 			     const void *buf, unsigned long size);
 extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
@@ -725,6 +706,7 @@ extern int ps3av_vuart_read(struct ps3_v
 
 extern int ps3av_set_video_mode(u32, int);
 extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
+extern int ps3av_get_auto_mode(int);
 extern int ps3av_set_mode(u32, int);
 extern int ps3av_get_mode(void);
 extern int ps3av_get_scanmode(int);
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 0d7f016..749c7f9 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -469,12 +469,68 @@ #define SPRN_PMC8	794
 #define SPRN_SIAR	780
 #define SPRN_SDAR	781
 
-#define PA6T_SPRN_PMC0	787
-#define PA6T_SPRN_PMC1	788
-#define PA6T_SPRN_PMC2	789
-#define PA6T_SPRN_PMC3	790
-#define PA6T_SPRN_PMC4	791
-#define PA6T_SPRN_PMC5	792
+#define SPRN_PA6T_MMCR0 795
+#define   PA6T_MMCR0_EN0	0x0000000000000001UL
+#define   PA6T_MMCR0_EN1	0x0000000000000002UL
+#define   PA6T_MMCR0_EN2	0x0000000000000004UL
+#define   PA6T_MMCR0_EN3	0x0000000000000008UL
+#define   PA6T_MMCR0_EN4	0x0000000000000010UL
+#define   PA6T_MMCR0_EN5	0x0000000000000020UL
+#define   PA6T_MMCR0_SUPEN	0x0000000000000040UL
+#define   PA6T_MMCR0_PREN	0x0000000000000080UL
+#define   PA6T_MMCR0_HYPEN	0x0000000000000100UL
+#define   PA6T_MMCR0_FCM0	0x0000000000000200UL
+#define   PA6T_MMCR0_FCM1	0x0000000000000400UL
+#define   PA6T_MMCR0_INTGEN	0x0000000000000800UL
+#define   PA6T_MMCR0_INTEN0	0x0000000000001000UL
+#define   PA6T_MMCR0_INTEN1	0x0000000000002000UL
+#define   PA6T_MMCR0_INTEN2	0x0000000000004000UL
+#define   PA6T_MMCR0_INTEN3	0x0000000000008000UL
+#define   PA6T_MMCR0_INTEN4	0x0000000000010000UL
+#define   PA6T_MMCR0_INTEN5	0x0000000000020000UL
+#define   PA6T_MMCR0_DISCNT	0x0000000000040000UL
+#define   PA6T_MMCR0_UOP	0x0000000000080000UL
+#define   PA6T_MMCR0_TRG	0x0000000000100000UL
+#define   PA6T_MMCR0_TRGEN	0x0000000000200000UL
+#define   PA6T_MMCR0_TRGREG	0x0000000001600000UL
+#define   PA6T_MMCR0_SIARLOG	0x0000000002000000UL
+#define   PA6T_MMCR0_SDARLOG	0x0000000004000000UL
+#define   PA6T_MMCR0_PROEN	0x0000000008000000UL
+#define   PA6T_MMCR0_PROLOG	0x0000000010000000UL
+#define   PA6T_MMCR0_DAMEN2	0x0000000020000000UL
+#define   PA6T_MMCR0_DAMEN3	0x0000000040000000UL
+#define   PA6T_MMCR0_DAMEN4	0x0000000080000000UL
+#define   PA6T_MMCR0_DAMEN5	0x0000000100000000UL
+#define   PA6T_MMCR0_DAMSEL2	0x0000000200000000UL
+#define   PA6T_MMCR0_DAMSEL3	0x0000000400000000UL
+#define   PA6T_MMCR0_DAMSEL4	0x0000000800000000UL
+#define   PA6T_MMCR0_DAMSEL5	0x0000001000000000UL
+#define   PA6T_MMCR0_HANDDIS	0x0000002000000000UL
+#define   PA6T_MMCR0_PCTEN	0x0000004000000000UL
+#define   PA6T_MMCR0_SOCEN	0x0000008000000000UL
+#define   PA6T_MMCR0_SOCMOD	0x0000010000000000UL
+
+#define SPRN_PA6T_MMCR1 798
+#define   PA6T_MMCR1_ES2	0x00000000000000ffUL
+#define   PA6T_MMCR1_ES3	0x000000000000ff00UL
+#define   PA6T_MMCR1_ES4	0x0000000000ff0000UL
+#define   PA6T_MMCR1_ES5	0x00000000ff000000UL
+
+#define SPRN_PA6T_SIAR  780
+#define SPRN_PA6T_UPMC0 771
+#define SPRN_PA6T_UPMC1 772
+#define SPRN_PA6T_UPMC2 773
+#define SPRN_PA6T_UPMC3 774
+#define SPRN_PA6T_UPMC4 775
+#define SPRN_PA6T_UPMC5 776
+#define SPRN_PA6T_UMMCR0 779
+#define SPRN_PA6T_UMMCR1 782
+#define SPRN_PA6T_PMC0  787
+#define SPRN_PA6T_PMC1  788
+#define SPRN_PA6T_PMC2  789
+#define SPRN_PA6T_PMC3  790
+#define SPRN_PA6T_PMC4  791
+#define SPRN_PA6T_PMC5  792
 
 #else /* 32-bit */
 #define SPRN_MMCR0	952	/* Monitor Mode Control Register 0 */
diff --git a/include/asm-powerpc/socket.h b/include/asm-powerpc/socket.h
index c8b1da5..403e9fd 100644
--- a/include/asm-powerpc/socket.h
+++ b/include/asm-powerpc/socket.h
@@ -56,5 +56,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _ASM_POWERPC_SOCKET_H */
diff --git a/include/asm-powerpc/sockios.h b/include/asm-powerpc/sockios.h
index 590078d..55cef76 100644
--- a/include/asm-powerpc/sockios.h
+++ b/include/asm-powerpc/sockios.h
@@ -14,6 +14,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _ASM_POWERPC_SOCKIOS_H */
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index 8aad061..02e56a6 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -242,6 +242,7 @@ struct spu_state {
 	u64 spu_chnldata_RW[32];
 	u32 spu_mailbox_data[4];
 	u32 pu_mailbox_data[1];
+	u64 dar, dsisr;
 	unsigned long suspend_time;
 	spinlock_t register_lock;
 };
diff --git a/include/asm-powerpc/string.h b/include/asm-powerpc/string.h
index faa407f..aa40f92 100644
--- a/include/asm-powerpc/string.h
+++ b/include/asm-powerpc/string.h
@@ -14,8 +14,6 @@ #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMCMP
 #define __HAVE_ARCH_MEMCHR
 
-extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, __kernel_size_t);
 extern char * strcpy(char *,const char *);
 extern char * strncpy(char *,const char *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
diff --git a/include/asm-powerpc/suspend.h b/include/asm-powerpc/suspend.h
new file mode 100644
index 0000000..cbf2c94
--- /dev/null
+++ b/include/asm-powerpc/suspend.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_POWERPC_SUSPEND_H
+#define __ASM_POWERPC_SUSPEND_H
+
+static inline int arch_prepare_suspend(void) { return 0; }
+
+void save_processor_state(void);
+void restore_processor_state(void);
+
+#endif /* __ASM_POWERPC_SUSPEND_H */
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index f7b1227..09621f6 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -7,7 +7,6 @@ #define _ASM_POWERPC_SYSTEM_H
 #include <linux/kernel.h>
 
 #include <asm/hw_irq.h>
-#include <asm/atomic.h>
 
 /*
  * Memory barrier.
@@ -131,6 +130,7 @@ extern void enable_kernel_altivec(void);
 extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
+extern void enable_kernel_spe(void);
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 extern int fix_alignment(struct pt_regs *);
@@ -226,6 +226,29 @@ __xchg_u32(volatile void *p, unsigned lo
 	return prev;
 }
 
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+static __inline__ unsigned long
+__xchg_u32_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
+
 #ifdef CONFIG_PPC64
 static __inline__ unsigned long
 __xchg_u64(volatile void *p, unsigned long val)
@@ -245,6 +268,23 @@ __xchg_u64(volatile void *p, unsigned lo
 
 	return prev;
 }
+
+static __inline__ unsigned long
+__xchg_u64_local(volatile void *p, unsigned long val)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__(
+"1:	ldarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stdcx.	%3,0,%2 \n\
+	bne-	1b"
+	: "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+	: "r" (p), "r" (val)
+	: "cc", "memory");
+
+	return prev;
+}
 #endif
 
 /*
@@ -268,13 +308,32 @@ #endif
 	return x;
 }
 
+static __inline__ unsigned long
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __xchg_u32_local(ptr, x);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __xchg_u64_local(ptr, x);
+#endif
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
+}
 #define xchg(ptr,x)							     \
   ({									     \
      __typeof__(*(ptr)) _x_ = (x);					     \
      (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
   })
 
-#define tas(ptr) (xchg((ptr),1))
+#define xchg_local(ptr,x)						     \
+  ({									     \
+     __typeof__(*(ptr)) _x_ = (x);					     \
+     (__typeof__(*(ptr))) __xchg_local((ptr),				     \
+     		(unsigned long)_x_, sizeof(*(ptr))); 			     \
+  })
 
 /*
  * Compare and exchange - if *p == old, set it to new,
@@ -305,6 +364,28 @@ __cmpxchg_u32(volatile unsigned int *p, 
 	return prev;
 }
 
+static __inline__ unsigned long
+__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned int prev;
+
+	__asm__ __volatile__ (
+"1:	lwarx	%0,0,%2		# __cmpxchg_u32\n\
+	cmpw	0,%0,%3\n\
+	bne-	2f\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
+
 #ifdef CONFIG_PPC64
 static __inline__ unsigned long
 __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
@@ -327,6 +408,27 @@ __cmpxchg_u64(volatile unsigned long *p,
 
 	return prev;
 }
+
+static __inline__ unsigned long
+__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
+			unsigned long new)
+{
+	unsigned long prev;
+
+	__asm__ __volatile__ (
+"1:	ldarx	%0,0,%2		# __cmpxchg_u64\n\
+	cmpd	0,%0,%3\n\
+	bne-	2f\n\
+	stdcx.	%4,0,%2\n\
+	bne-	1b"
+	"\n\
+2:"
+	: "=&r" (prev), "+m" (*p)
+	: "r" (p), "r" (old), "r" (new)
+	: "cc", "memory");
+
+	return prev;
+}
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -349,6 +451,22 @@ #endif
 	return old;
 }
 
+static __inline__ unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+	  unsigned int size)
+{
+	switch (size) {
+	case 4:
+		return __cmpxchg_u32_local(ptr, old, new);
+#ifdef CONFIG_PPC64
+	case 8:
+		return __cmpxchg_u64_local(ptr, old, new);
+#endif
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
 #define cmpxchg(ptr,o,n)						 \
   ({									 \
      __typeof__(*(ptr)) _o_ = (o);					 \
@@ -357,6 +475,15 @@ #define cmpxchg(ptr,o,n)						 \
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+
+#define cmpxchg_local(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,	 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
+
 #ifdef CONFIG_PPC64
 /*
  * We handle most unaligned accesses in hardware. On the other hand 
diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h
index 4e2a834..0a17682 100644
--- a/include/asm-powerpc/tlb.h
+++ b/include/asm-powerpc/tlb.h
@@ -38,7 +38,6 @@ extern void pte_free_finish(void);
 
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
-	flush_tlb_pending();
 	pte_free_finish();
 }
 
diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h
index 93c7d0c..86e6266 100644
--- a/include/asm-powerpc/tlbflush.h
+++ b/include/asm-powerpc/tlbflush.h
@@ -17,10 +17,73 @@ #define _ASM_POWERPC_TLBFLUSH_H
  */
 #ifdef __KERNEL__
 
-
 struct mm_struct;
+struct vm_area_struct;
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+/*
+ * TLB flushing for software loaded TLB chips
+ *
+ * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
+ * flush_tlb_kernel_range are best implemented as tlbia vs
+ * specific tlbie's
+ */
+
+extern void _tlbie(unsigned long address);
+
+#if defined(CONFIG_40x) || defined(CONFIG_8xx)
+#define _tlbia()	asm volatile ("tlbia; sync" : : : "memory")
+#else /* CONFIG_44x || CONFIG_FSL_BOOKE */
+extern void _tlbia(void);
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	_tlbia();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long vmaddr)
+{
+	_tlbie(vmaddr);
+}
+
+static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
+					 unsigned long vmaddr)
+{
+	_tlbie(vmaddr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	_tlbia();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+					  unsigned long end)
+{
+	_tlbia();
+}
 
-#ifdef CONFIG_PPC64
+#elif defined(CONFIG_PPC32)
+/*
+ * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx
+ */
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+			    unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+#else
+/*
+ * TLB flushing for 64-bit has-MMU CPUs
+ */
 
 #include <linux/percpu.h>
 #include <asm/page.h>
@@ -28,117 +91,90 @@ #include <asm/page.h>
 #define PPC64_TLB_BATCH_NR 192
 
 struct ppc64_tlb_batch {
-	unsigned long index;
-	struct mm_struct *mm;
-	real_pte_t pte[PPC64_TLB_BATCH_NR];
-	unsigned long vaddr[PPC64_TLB_BATCH_NR];
-	unsigned int psize;
+	int			active;
+	unsigned long		index;
+	struct mm_struct	*mm;
+	real_pte_t		pte[PPC64_TLB_BATCH_NR];
+	unsigned long		vaddr[PPC64_TLB_BATCH_NR];
+	unsigned int		psize;
 };
 DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
 
 extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
 
-static inline void flush_tlb_pending(void)
+extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+			    pte_t *ptep, unsigned long pte, int huge);
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+
+	batch->active = 1;
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
 {
-	struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
+	struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
 
 	if (batch->index)
 		__flush_tlb_pending(batch);
-	put_cpu_var(ppc64_tlb_batch);
+	batch->active = 0;
 }
 
+#define arch_flush_lazy_mmu_mode()      do {} while (0)
+
+
 extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize,
 			    int local);
 extern void flush_hash_range(unsigned long number, int local);
 
-#else /* CONFIG_PPC64 */
-
-#include <linux/mm.h>
-
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
-/*
- * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
- * flush_tlb_kernel_range are best implemented as tlbia vs
- * specific tlbie's
- */
-
-#if (defined(CONFIG_4xx) && !defined(CONFIG_44x)) || defined(CONFIG_8xx)
-#define flush_tlb_pending()	asm volatile ("tlbia; sync" : : : "memory")
-#elif defined(CONFIG_4xx) || defined(CONFIG_FSL_BOOKE)
-#define flush_tlb_pending()	_tlbia()
-#endif
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- * On machines which use an MMU hash table, we use this to put a
- * corresponding HPTE into the hash table ahead of time, instead of
- * waiting for the inevitable extra hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-#endif /* CONFIG_PPC64 */
-
-#if defined(CONFIG_PPC64) || defined(CONFIG_4xx) || \
-	defined(CONFIG_FSL_BOOKE) || defined(CONFIG_8xx)
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-	flush_tlb_pending();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
-				unsigned long vmaddr)
+				  unsigned long vmaddr)
 {
-#ifdef CONFIG_PPC64
-	flush_tlb_pending();
-#else
-	_tlbie(vmaddr);
-#endif
 }
 
 static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
 					 unsigned long vmaddr)
 {
-#ifndef CONFIG_PPC64
-	_tlbie(vmaddr);
-#endif
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
-		unsigned long start, unsigned long end)
+				   unsigned long start, unsigned long end)
 {
-	flush_tlb_pending();
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start,
-		unsigned long end)
+					  unsigned long end)
 {
-	flush_tlb_pending();
 }
 
-#else	/* 6xx, 7xx, 7xxx cpus */
-
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
-			    unsigned long end);
-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
-
 #endif
 
 /*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+/*
  * This is called in munmap when we have freed up some page-table
  * pages.  We don't need to do anything here, there's nothing special
  * about our page-table pages.  -- paulus
  */
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
-		unsigned long start, unsigned long end)
+				      unsigned long start, unsigned long end)
 {
 }
 
diff --git a/include/asm-powerpc/tsi108.h b/include/asm-powerpc/tsi108.h
index 4e95d15..f8b6079 100644
--- a/include/asm-powerpc/tsi108.h
+++ b/include/asm-powerpc/tsi108.h
@@ -68,8 +68,17 @@ #define TSI108_PB_AERR		(0x408)
 #define TSI108_PB_ERRCS_ES		(1 << 1)
 #define TSI108_PB_ISR_PBS_RD_ERR	(1 << 8)
 
-#define TSI108_PCI_CFG_BASE_PHYS	(0xfb000000)
 #define TSI108_PCI_CFG_SIZE		(0x01000000)
+
+/*
+ * PHY Configuration Options
+ *
+ * Specify "bcm54xx" in the compatible property of your device tree phy
+ * nodes if your board uses the Broadcom PHYs
+ */
+#define TSI108_PHY_MV88E	0	/* Marvel 88Exxxx PHY */
+#define TSI108_PHY_BCM54XX	1	/* Broardcom BCM54xx PHY */
+
 /* Global variables */
 
 extern u32 tsi108_pci_cfg_base;
@@ -93,6 +102,7 @@ typedef struct {
 	u16 phy;		/* phy address */
 	u16 irq_num;		/* irq number */
 	u8 mac_addr[6];		/* phy mac address */
+	u16 phy_type;	/* type of phy on board */
 } hw_info;
 
 extern u32 get_vir_csrbase(void);
diff --git a/include/asm-powerpc/tsi108_pci.h b/include/asm-powerpc/tsi108_pci.h
new file mode 100644
index 0000000..a9f92f7
--- /dev/null
+++ b/include/asm-powerpc/tsi108_pci.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You 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_PPC_TSI108_PCI_H
+#define _ASM_PPC_TSI108_PCI_H
+
+#include <asm/tsi108.h>
+
+/* Register definitions */
+#define TSI108_PCI_P2O_BAR0 (TSI108_PCI_OFFSET + 0x10)
+#define TSI108_PCI_P2O_BAR0_UPPER (TSI108_PCI_OFFSET + 0x14)
+#define TSI108_PCI_P2O_BAR2 (TSI108_PCI_OFFSET + 0x18)
+#define TSI108_PCI_P2O_BAR2_UPPER (TSI108_PCI_OFFSET + 0x1c)
+#define TSI108_PCI_P2O_PAGE_SIZES (TSI108_PCI_OFFSET + 0x4c)
+#define TSI108_PCI_PFAB_BAR0 (TSI108_PCI_OFFSET + 0x204)
+#define TSI108_PCI_PFAB_BAR0_UPPER (TSI108_PCI_OFFSET + 0x208)
+#define TSI108_PCI_PFAB_IO (TSI108_PCI_OFFSET + 0x20c)
+#define TSI108_PCI_PFAB_IO_UPPER (TSI108_PCI_OFFSET + 0x210)
+#define TSI108_PCI_PFAB_MEM32 (TSI108_PCI_OFFSET + 0x214)
+#define TSI108_PCI_PFAB_PFM3 (TSI108_PCI_OFFSET + 0x220)
+#define TSI108_PCI_PFAB_PFM4 (TSI108_PCI_OFFSET + 0x230)
+
+extern int tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary);
+extern void tsi108_pci_int_init(struct device_node *node);
+extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
+extern void tsi108_clear_pci_cfg_error(void);
+
+#endif				/*  _ASM_PPC_TSI108_PCI_H */
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h
index adbf16b..8e798e3 100644
--- a/include/asm-powerpc/uaccess.h
+++ b/include/asm-powerpc/uaccess.h
@@ -110,12 +110,18 @@ #define __get_user(x, ptr) \
 	__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
 #define __put_user(x, ptr) \
 	__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
 #ifndef __powerpc64__
 #define __get_user64(x, ptr) \
 	__get_user64_nocheck((x), (ptr), sizeof(*(ptr)))
 #define __put_user64(x, ptr) __put_user(x, ptr)
 #endif
 
+#define __get_user_inatomic(x, ptr) \
+	__get_user_nosleep((x), (ptr), sizeof(*(ptr)))
+#define __put_user_inatomic(x, ptr) \
+	__put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
 #define __get_user_unaligned __get_user
 #define __put_user_unaligned __put_user
 
@@ -198,6 +204,16 @@ ({									\
 	__pu_err;							\
 })
 
+#define __put_user_nosleep(x, ptr, size)			\
+({								\
+	long __pu_err;						\
+	__typeof__(*(ptr)) __user *__pu_addr = (ptr);		\
+	__chk_user_ptr(ptr);					\
+	__put_user_size((x), __pu_addr, (size), __pu_err);	\
+	__pu_err;						\
+})
+
+
 extern long __get_user_bad(void);
 
 #define __get_user_asm(x, addr, err, op)		\
@@ -297,6 +313,18 @@ ({									\
 	__gu_err;							\
 })
 
+#define __get_user_nosleep(x, ptr, size)			\
+({								\
+	long __gu_err;						\
+	unsigned long __gu_val;					\
+	const __typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
+	__chk_user_ptr(ptr);					\
+	__get_user_size(__gu_val, __gu_addr, (size), __gu_err);	\
+	(x) = (__typeof__(*(ptr)))__gu_val;			\
+	__gu_err;						\
+})
+
+
 /* more complex routines */
 
 extern unsigned long __copy_tofrom_user(void __user *to,
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
index 39d1c90..f529f70 100644
--- a/include/asm-powerpc/ucc_fast.h
+++ b/include/asm-powerpc/ucc_fast.h
@@ -159,6 +159,9 @@ struct ucc_fast_private {
 	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. */
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+	u16 *p_utodr;		/* pointer to the transmit on demand register */
+#endif
 	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
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index d03d855..ce9d82f 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -47,6 +47,7 @@ extern void __init udbg_init_rtas_panel(
 extern void __init udbg_init_rtas_console(void);
 extern void __init udbg_init_debug_beat(void);
 extern void __init udbg_init_btext(void);
+extern void __init udbg_init_44x_as1(void);
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-powerpc/uic.h b/include/asm-powerpc/uic.h
new file mode 100644
index 0000000..970eb7e
--- /dev/null
+++ b/include/asm-powerpc/uic.h
@@ -0,0 +1,23 @@
+/*
+ * include/asm-powerpc/uic.h
+ *
+ * IBM PPC4xx UIC external definitions and structure.
+ *
+ * Maintainer: David Gibson <dwg@au1.ibm.com>
+ * Copyright 2007 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.
+ */
+#ifndef _ASM_POWERPC_UIC_H
+#define _ASM_POWERPC_UIC_H
+
+#ifdef __KERNEL__
+
+extern void __init uic_init_tree(void);
+extern unsigned int uic_get_irq(void);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_UIC_H */
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index 92fd02d..ed6891a 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -47,12 +47,8 @@ #if defined(CONFIG_WALNUT)
 #include <platforms/4xx/walnut.h>
 #endif
 
-#if defined(CONFIG_XILINX_ML300)
-#include <platforms/4xx/xilinx_ml300.h>
-#endif
-
-#if defined(CONFIG_XILINX_ML403)
-#include <platforms/4xx/xilinx_ml403.h>
+#if defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/virtex.h>
 #endif
 
 #ifndef __ASSEMBLY__
diff --git a/include/asm-ppc/kdebug.h b/include/asm-ppc/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-ppc/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 2bc8589..a6441a0 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -6,6 +6,7 @@ #include <asm/atomic.h>
 #include <asm/bitops.h>
 #include <asm/mmu.h>
 #include <asm/cputable.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index b1fdbf4..bed452d 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -827,10 +827,6 @@ #define io_remap_pfn_range(vma, vaddr, p
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /*
  * No page table caches to initialise
  */
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index 40f197a..de99e92 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -33,8 +33,6 @@ #elif defined(CONFIG_PPC_MPC52xx)
 #include <asm/mpc52xx.h>
 #elif defined(CONFIG_MPC10X_BRIDGE)
 #include <asm/mpc10x.h>
-#elif defined(CONFIG_XILINX_VIRTEX)
-#include <platforms/4xx/virtex.h>
 #else
 #error "need definition of ppc_sys_devices"
 #endif
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index adc5ae7..901f7fa 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -34,7 +34,8 @@ #define PTRUNRELOC(x)	((typeof(x))sub_re
  */
 #define machine_is_compatible(x)		0
 #define of_find_compatible_node(f, t, c)	NULL
-#define get_property(p, n, l)			NULL
+#define of_get_property(p, n, l)		NULL
+#define get_property(a, b, c)			of_get_property((a), (b), (c))
 
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 7389435..d84a3cf 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -6,7 +6,6 @@ #define __PPC_SYSTEM_H
 
 #include <linux/kernel.h>
 
-#include <asm/atomic.h>
 #include <asm/hw_irq.h>
 
 /*
@@ -170,7 +169,6 @@ xchg_u32(volatile void *p, unsigned long
 extern void __xchg_called_with_bad_pointer(void);
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
diff --git a/include/asm-s390/bug.h b/include/asm-s390/bug.h
index 8768983..838684d 100644
--- a/include/asm-s390/bug.h
+++ b/include/asm-s390/bug.h
@@ -1,27 +1,70 @@
-#ifndef _S390_BUG_H
-#define _S390_BUG_H
+#ifndef _ASM_S390_BUG_H
+#define _ASM_S390_BUG_H
 
 #include <linux/kernel.h>
 
 #ifdef CONFIG_BUG
 
-static inline __attribute__((noreturn)) void __do_illegal_op(void)
-{
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
-	__builtin_trap();
+#ifdef CONFIG_64BIT
+#define S390_LONG ".quad"
 #else
-	asm volatile(".long 0");
+#define S390_LONG ".long"
 #endif
-}
 
-#define BUG() do { \
-	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-	__do_illegal_op(); \
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define __EMIT_BUG(x) do {					\
+	asm volatile(						\
+		"0:	j	0b+2\n"				\
+		"1:\n"						\
+		".section .rodata.str,\"aMS\",@progbits,1\n"	\
+		"2:	.asciz	\""__FILE__"\"\n"		\
+		".previous\n"					\
+		".section __bug_table,\"a\"\n"			\
+		"3:\t"	S390_LONG "\t1b,2b\n"			\
+		"	.short	%0,%1\n"			\
+		"	.org	3b+%2\n"			\
+		".previous\n"					\
+		: : "i" (__LINE__),				\
+		    "i" (x),					\
+		    "i" (sizeof(struct bug_entry)));		\
 } while (0)
 
+#else /* CONFIG_DEBUG_BUGVERBOSE */
+
+#define __EMIT_BUG(x) do {				\
+	asm volatile(					\
+		"0:	j	0b+2\n"			\
+		"1:\n"					\
+		".section __bug_table,\"a\"\n"		\
+		"2:\t"	S390_LONG "\t1b\n"		\
+		"	.short	%0\n"			\
+		"	.org	2b+%1\n"		\
+		".previous\n"				\
+		: : "i" (x),				\
+		    "i" (sizeof(struct bug_entry)));	\
+} while (0)
+
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
+#define BUG()	__EMIT_BUG(0)
+
+#define WARN_ON(x) ({					\
+	typeof(x) __ret_warn_on = (x);			\
+	if (__builtin_constant_p(__ret_warn_on)) {	\
+		if (__ret_warn_on)			\
+			__EMIT_BUG(BUGFLAG_WARNING);	\
+	} else {					\
+		if (unlikely(__ret_warn_on))		\
+			__EMIT_BUG(BUGFLAG_WARNING);	\
+	}						\
+	unlikely(__ret_warn_on);			\
+})
+
 #define HAVE_ARCH_BUG
-#endif
+#define HAVE_ARCH_WARN_ON
+#endif /* CONFIG_BUG */
 
 #include <asm-generic/bug.h>
 
-#endif
+#endif /* _ASM_S390_BUG_H */
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index cfc8153..6795ece 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -164,9 +164,9 @@ extern int ccw_device_resume(struct ccw_
 extern int ccw_device_halt(struct ccw_device *, unsigned long);
 extern int ccw_device_clear(struct ccw_device *, unsigned long);
 
-extern int read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
-extern int read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
-extern int read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
+extern int __deprecated read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
+extern int __deprecated read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
+extern int __deprecated read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
 			      int *length, __u8 lpm);
 
 extern int ccw_device_set_online(struct ccw_device *cdev);
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index d2f9c0d..925b3dd 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -11,6 +11,7 @@ struct ccwgroup_device {
 		CCWGROUP_ONLINE,
 	} state;
 	atomic_t onoff;
+	struct mutex reg_mutex;
 	unsigned int count;		/* number of attached slave devices */
 	struct device	dev;		/* master device		    */
 	struct ccw_device *cdev[0];	/* variable number, allocate as needed */
diff --git a/include/asm-s390/chpid.h b/include/asm-s390/chpid.h
new file mode 100644
index 0000000..b203336
--- /dev/null
+++ b/include/asm-s390/chpid.h
@@ -0,0 +1,53 @@
+/*
+ *  drivers/s390/cio/chpid.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_CHPID_H
+#define _ASM_S390_CHPID_H _ASM_S390_CHPID_H
+
+#include <linux/string.h>
+#include <asm/types.h>
+#include <asm/cio.h>
+
+#define __MAX_CHPID 255
+
+struct chp_id {
+	u8 reserved1;
+	u8 cssid;
+	u8 reserved2;
+	u8 id;
+} __attribute__((packed));
+
+static inline void chp_id_init(struct chp_id *chpid)
+{
+	memset(chpid, 0, sizeof(struct chp_id));
+}
+
+static inline int chp_id_is_equal(struct chp_id *a, struct chp_id *b)
+{
+	return (a->id == b->id) && (a->cssid == b->cssid);
+}
+
+static inline void chp_id_next(struct chp_id *chpid)
+{
+	if (chpid->id < __MAX_CHPID)
+		chpid->id++;
+	else {
+		chpid->id = 0;
+		chpid->cssid++;
+	}
+}
+
+static inline int chp_id_is_valid(struct chp_id *chpid)
+{
+	return (chpid->cssid <= __MAX_CSSID);
+}
+
+
+#define chp_id_for_each(c) \
+	for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c))
+
+#endif /* _ASM_S390_CHPID_H */
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index d927850..f738d28 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -13,6 +13,7 @@ #include <asm/types.h>
 #ifdef __KERNEL__
 
 #define LPM_ANYPATH 0xff
+#define __MAX_CSSID 0
 
 /*
  * subchannel status word
@@ -292,6 +293,13 @@ extern void css_schedule_reprobe(void);
 
 extern void reipl_ccw_dev(struct ccw_dev_id *id);
 
+struct cio_iplinfo {
+	u16 devno;
+	int is_qdio;
+};
+
+extern int cio_get_iplinfo(struct cio_iplinfo *iplinfo);
+
 #endif
 
 #endif
diff --git a/include/asm-s390/dma-mapping.h b/include/asm-s390/dma-mapping.h
index 09bb7b0..3f8c12f 100644
--- a/include/asm-s390/dma-mapping.h
+++ b/include/asm-s390/dma-mapping.h
@@ -9,6 +9,4 @@
 #ifndef _ASM_DMA_MAPPING_H
 #define _ASM_DMA_MAPPING_H
 
-#include <asm-generic/dma-mapping-broken.h>
-
 #endif /* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h
index c0d629d..91d0632 100644
--- a/include/asm-s390/elf.h
+++ b/include/asm-s390/elf.h
@@ -188,7 +188,8 @@ #define ELF_CORE_COPY_FPREGS(tsk, fpregs
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports. */
 
-#define ELF_HWCAP (0)
+extern unsigned long elf_hwcap;
+#define ELF_HWCAP (elf_hwcap)
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
@@ -197,7 +198,9 @@ #define ELF_HWCAP (0)
    For the moment, we have only optimizations for the Intel generations,
    but that could change... */
 
-#define ELF_PLATFORM (NULL)
+#define ELF_PLATFORM_SIZE 8
+extern char elf_platform[];
+#define ELF_PLATFORM (elf_platform)
 
 #ifndef __s390x__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
index 0eb6408..bdcd448 100644
--- a/include/asm-s390/ipl.h
+++ b/include/asm-s390/ipl.h
@@ -8,6 +8,8 @@ #ifndef _ASM_S390_IPL_H
 #define _ASM_S390_IPL_H
 
 #include <asm/types.h>
+#include <asm/cio.h>
+#include <asm/setup.h>
 
 #define IPL_PARMBLOCK_ORIGIN	0x2000
 
@@ -74,12 +76,12 @@ struct ipl_parameter_block {
 } __attribute__((packed));
 
 /*
- * IPL validity flags and parameters as detected in head.S
+ * IPL validity flags
  */
 extern u32 ipl_flags;
-extern u16 ipl_devno;
 
 extern u32 dump_prefix_page;
+
 extern void do_reipl(void);
 extern void ipl_save_parameters(void);
 
@@ -89,6 +91,35 @@ enum {
 	IPL_NSS_VALID		= 4,
 };
 
+enum ipl_type {
+	IPL_TYPE_UNKNOWN	= 1,
+	IPL_TYPE_CCW		= 2,
+	IPL_TYPE_FCP		= 4,
+	IPL_TYPE_FCP_DUMP	= 8,
+	IPL_TYPE_NSS		= 16,
+};
+
+struct ipl_info
+{
+	enum ipl_type type;
+	union {
+		struct {
+			struct ccw_dev_id dev_id;
+		} ccw;
+		struct {
+			struct ccw_dev_id dev_id;
+			u64 wwpn;
+			u64 lun;
+		} fcp;
+		struct {
+			char name[NSS_NAME_SIZE + 1];
+		} nss;
+	} data;
+};
+
+extern struct ipl_info ipl_info;
+extern void setup_ipl_info(void);
+
 /*
  * DIAG 308 support
  */
diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h
index 1b50f89..04418af 100644
--- a/include/asm-s390/kdebug.h
+++ b/include/asm-s390/kdebug.h
@@ -8,23 +8,19 @@ #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.
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation. Will hopefully go away soon once all
+ * architectures are updated.
  */
-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;
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
 
 enum die_val {
 	DIE_OOPS = 1,
@@ -39,22 +35,8 @@ enum die_val {
 	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);
-}
-
 extern void die(const char *, struct pt_regs *, long);
 
 #endif
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h
index 9c35c8a..7592af7 100644
--- a/include/asm-s390/kexec.h
+++ b/include/asm-s390/kexec.h
@@ -34,8 +34,6 @@ #define KEXEC_CONTROL_CODE_SIZE 4096
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_S390
 
-#define MAX_NOTE_BYTES 1024
-
 /* Provide a dummy definition to avoid build failures. */
 static inline void crash_setup_regs(struct pt_regs *newregs,
 					struct pt_regs *oldregs) { }
diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h
index b847ff0..830fe4c 100644
--- a/include/asm-s390/kprobes.h
+++ b/include/asm-s390/kprobes.h
@@ -97,18 +97,10 @@ void kretprobe_trampoline(void);
 int  is_prohibited_opcode(kprobe_opcode_t *instruction);
 void get_instruction_type(struct arch_specific_insn *ainsn);
 
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
+int kprobe_exceptions_notify(struct notifier_block *self,
+	unsigned long val, void *data);
+
 #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 4a31d0a..801a6fd 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -147,6 +147,52 @@ void pgm_check_handler(void);
 void mcck_int_handler(void);
 void io_int_handler(void);
 
+struct save_area_s390 {
+	u32	ext_save;
+	u64	timer;
+	u64	clk_cmp;
+	u8	pad1[24];
+	u8	psw[8];
+	u32	pref_reg;
+	u8	pad2[20];
+	u32	acc_regs[16];
+	u64	fp_regs[4];
+	u32	gp_regs[16];
+	u32	ctrl_regs[16];
+}  __attribute__((packed));
+
+struct save_area_s390x {
+	u64	fp_regs[16];
+	u64	gp_regs[16];
+	u8	psw[16];
+	u8	pad1[8];
+	u32	pref_reg;
+	u32	fp_ctrl_reg;
+	u8	pad2[4];
+	u32	tod_reg;
+	u64	timer;
+	u64	clk_cmp;
+	u8	pad3[8];
+	u32	acc_regs[16];
+	u64	ctrl_regs[16];
+}  __attribute__((packed));
+
+union save_area {
+	struct save_area_s390	s390;
+	struct save_area_s390x	s390x;
+};
+
+#define SAVE_AREA_BASE_S390	0xd4
+#define SAVE_AREA_BASE_S390X	0x1200
+
+#ifndef __s390x__
+#define SAVE_AREA_SIZE sizeof(struct save_area_s390)
+#define SAVE_AREA_BASE SAVE_AREA_BASE_S390
+#else
+#define SAVE_AREA_SIZE sizeof(struct save_area_s390x)
+#define SAVE_AREA_BASE SAVE_AREA_BASE_S390X
+#endif
+
 struct _lowcore
 {
 #ifndef __s390x__
@@ -183,17 +229,19 @@ #ifndef __s390x__
 	__u16        subchannel_nr;            /* 0x0ba */
 	__u32        io_int_parm;              /* 0x0bc */
 	__u32        io_int_word;              /* 0x0c0 */
-        __u8         pad3[0xD4-0xC4];          /* 0x0c4 */
+	__u8	     pad3[0xc8-0xc4];	       /* 0x0c4 */
+	__u32	     stfl_fac_list;	       /* 0x0c8 */
+	__u8	     pad4[0xd4-0xcc];	       /* 0x0cc */
 	__u32        extended_save_area_addr;  /* 0x0d4 */
 	__u32        cpu_timer_save_area[2];   /* 0x0d8 */
 	__u32        clock_comp_save_area[2];  /* 0x0e0 */
 	__u32        mcck_interruption_code[2]; /* 0x0e8 */
-	__u8         pad4[0xf4-0xf0];          /* 0x0f0 */
+	__u8	     pad5[0xf4-0xf0];	       /* 0x0f0 */
 	__u32        external_damage_code;     /* 0x0f4 */
 	__u32        failing_storage_address;  /* 0x0f8 */
-	__u8         pad5[0x100-0xfc];         /* 0x0fc */
+	__u8	     pad6[0x100-0xfc];	       /* 0x0fc */
 	__u32        st_status_fixed_logout[4];/* 0x100 */
-	__u8         pad6[0x120-0x110];        /* 0x110 */
+	__u8	     pad7[0x120-0x110];        /* 0x110 */
 	__u32        access_regs_save_area[16];/* 0x120 */
 	__u32        floating_pt_save_area[8]; /* 0x160 */
 	__u32        gpregs_save_area[16];     /* 0x180 */
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index 1d21da2..501cb9b 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -10,6 +10,8 @@ #ifndef __S390_MMU_CONTEXT_H
 #define __S390_MMU_CONTEXT_H
 
 #include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
+
 /*
  * get a new mmu context.. S390 don't know about contexts.
  */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 13c1654..8fe8d42 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -753,14 +753,14 @@ #define ptep_set_access_flags(__vma, __a
  * should therefore only be called if it is not mapped in any
  * address space.
  */
-static inline int page_test_and_clear_dirty(struct page *page)
+static inline int page_test_dirty(struct page *page)
 {
-	unsigned long physpage = page_to_phys(page);
-	int skey = page_get_storage_key(physpage);
+	return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0;
+}
 
-	if (skey & _PAGE_CHANGED)
-		page_set_storage_key(physpage, skey & ~_PAGE_CHANGED);
-	return skey & _PAGE_CHANGED;
+static inline void page_clear_dirty(struct page *page)
+{
+	page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY);
 }
 
 /*
@@ -953,7 +953,8 @@ #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 #define __HAVE_ARCH_PTE_SAME
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+#define __HAVE_ARCH_PAGE_TEST_DIRTY
+#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
 #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
 #include <asm-generic/pgtable.h>
 
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index 33b80ce..e0fcea8 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -57,6 +57,7 @@ #endif /* __s390x__ */
 
 extern void s390_adjust_jiffies(void);
 extern void print_cpu_info(struct cpuinfo_S390 *);
+extern int get_cpu_capability(unsigned int *);
 
 /* Lazy FPU handling on uni-processor */
 extern struct task_struct *last_task_used_math;
@@ -196,6 +197,7 @@ extern unsigned long thread_saved_pc(str
 extern char *task_show_regs(struct task_struct *task, char *buffer);
 
 extern void show_registers(struct pt_regs *regs);
+extern void show_code(struct pt_regs *regs);
 extern void show_trace(struct task_struct *task, unsigned long *sp);
 
 unsigned long get_wchan(struct task_struct *p);
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index 127f72e..74db1dc 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -120,6 +120,7 @@ #define QDIO_FLAG_UNDER_INTERRUPT 0x04
 #define QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT 0x08 /* no effect on
 						     adapter interrupts */
 #define QDIO_FLAG_DONT_SIGA 0x10
+#define QDIO_FLAG_PCI_OUT   0x20
 
 extern int do_QDIO(struct ccw_device*, unsigned int flags, 
 		   unsigned int queue_number,
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
index 468b970..21ed647 100644
--- a/include/asm-s390/sclp.h
+++ b/include/asm-s390/sclp.h
@@ -9,6 +9,7 @@ #ifndef _ASM_S390_SCLP_H
 #define _ASM_S390_SCLP_H
 
 #include <linux/types.h>
+#include <asm/chpid.h>
 
 struct sccb_header {
 	u16	length;
@@ -33,7 +34,20 @@ struct sclp_readinfo_sccb {
 	u8	_reserved3[4096 - 112];	/* 112-4095 */
 } __attribute__((packed, aligned(4096)));
 
+#define SCLP_CHP_INFO_MASK_SIZE		32
+
+struct sclp_chp_info {
+	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+};
+
 extern struct sclp_readinfo_sccb s390_readinfo_sccb;
 extern void sclp_readinfo_early(void);
+extern int sclp_sdias_blk_count(void);
+extern int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
+extern int sclp_chp_configure(struct chp_id chpid);
+extern int sclp_chp_deconfigure(struct chp_id chpid);
+extern int sclp_chp_read_info(struct sclp_chp_info *info);
 
 #endif /* _ASM_S390_SCLP_H */
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index 44c7aee..a76a6b8 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -40,6 +40,7 @@ struct mem_chunk {
 };
 
 extern struct mem_chunk memory_chunk[];
+extern unsigned long real_memory_size;
 
 #ifdef CONFIG_S390_SWITCH_AMODE
 extern unsigned int switch_amode;
@@ -77,6 +78,7 @@ #define MACHINE_HAS_MVCOS	(machine_flags
 #endif /* __s390x__ */
 
 #define MACHINE_HAS_SCLP	(!MACHINE_IS_P390)
+#define ZFCPDUMP_HSA_SIZE	(32UL<<20)
 
 /*
  * Console mode. Override with conmode=
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index b957e4c..0a28e6d 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -54,9 +54,6 @@ #define PROC_CHANGE_PENALTY	20		/* Sched
 
 #define raw_smp_processor_id()	(S390_lowcore.cpu_data.cpu_nr)
 
-extern int smp_get_cpu(cpumask_t cpu_map);
-extern void smp_put_cpu(int cpu);
-
 static inline __u16 hard_smp_processor_id(void)
 {
         __u16 cpu_address;
@@ -114,9 +111,8 @@ static inline void smp_send_stop(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()	do { } while (0)
 #endif
 
+extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
 #endif
diff --git a/include/asm-s390/socket.h b/include/asm-s390/socket.h
index 1778a49..1161ebe 100644
--- a/include/asm-s390/socket.h
+++ b/include/asm-s390/socket.h
@@ -57,5 +57,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-s390/sockios.h b/include/asm-s390/sockios.h
index 412aeb4..f4fc16c 100644
--- a/include/asm-s390/sockios.h
+++ b/include/asm-s390/sockios.h
@@ -15,6 +15,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
index 2f89dd0..794c36d 100644
--- a/include/asm-sh/bug.h
+++ b/include/asm-sh/bug.h
@@ -2,50 +2,80 @@ #ifndef __ASM_SH_BUG_H
 #define __ASM_SH_BUG_H
 
 #ifdef CONFIG_BUG
-
-struct bug_frame {
-	unsigned short	opcode;
-	unsigned short	line;
-	const char	*file;
-	const char	*func;
-};
-
-struct pt_regs;
-
-extern void handle_BUG(struct pt_regs *);
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
 
 #define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
 
+/**
+ * _EMIT_BUG_ENTRY
+ * %1 - __FILE__
+ * %2 - __LINE__
+ * %3 - trap type
+ * %4 - sizeof(struct bug_entry)
+ *
+ * The trapa opcode itself sits in %0.
+ * The %O notation is used to avoid # generation.
+ *
+ * The offending file and line are encoded in the __bug_table section.
+ */
 #ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY				\
+	"\t.pushsection __bug_table,\"a\"\n"	\
+	"2:\t.long 1b, %O1\n"			\
+	"\t.short %O2, %O3\n"			\
+	"\t.org 2b+%O4\n"			\
+	"\t.popsection\n"
+#else
+#define _EMIT_BUG_ENTRY				\
+	"\t.pushsection __bug_table,\"a\"\n"	\
+	"2:\t.long 1b\n"			\
+	"\t.short %O3\n"			\
+	"\t.org 2b+%O4\n"			\
+	"\t.popsection\n"
+#endif
 
 #define BUG()						\
 do {							\
 	__asm__ __volatile__ (				\
-		".align	2\n\t"				\
-		".short	%O0\n\t"			\
-		".short	%O1\n\t"			\
-		".long	%O2\n\t"			\
-		".long	%O3\n\t"			\
-		:					\
-		: "n" (TRAPA_BUG_OPCODE),		\
-		  "i" (__LINE__), "X" (__FILE__),	\
-		  "X" (__FUNCTION__));			\
+		"1:\t.short %O0\n"			\
+		_EMIT_BUG_ENTRY				\
+		 :					\
+		 : "n" (TRAPA_BUG_OPCODE),		\
+		   "i" (__FILE__),			\
+		   "i" (__LINE__), "i" (0),		\
+		   "i" (sizeof(struct bug_entry)));	\
 } while (0)
 
-#else
-
-#define BUG()					\
-do {						\
-	__asm__ __volatile__ (			\
-		".align	2\n\t"			\
-		".short	%O0\n\t"		\
-		:				\
-		: "n" (TRAPA_BUG_OPCODE));	\
+#define __WARN()					\
+do {							\
+	__asm__ __volatile__ (				\
+		"1:\t.short %O0\n"			\
+		 _EMIT_BUG_ENTRY			\
+		 :					\
+		 : "n" (TRAPA_BUG_OPCODE),		\
+		   "i" (__FILE__),			\
+		   "i" (__LINE__),			\
+		   "i" (BUGFLAG_WARNING),		\
+		   "i" (sizeof(struct bug_entry)));	\
 } while (0)
 
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#define WARN_ON(x) ({						\
+	typeof(x) __ret_warn_on = (x);				\
+	if (__builtin_constant_p(__ret_warn_on)) {		\
+		if (__ret_warn_on)				\
+			__WARN();				\
+	} else {						\
+		if (unlikely(__ret_warn_on))			\
+			__WARN();				\
+	}							\
+	unlikely(__ret_warn_on);				\
+})
 
-#define HAVE_ARCH_BUG
+struct pt_regs;
+
+/* arch/sh/kernel/traps.c */
+void handle_BUG(struct pt_regs *);
 
 #endif /* CONFIG_BUG */
 
diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h
index 1df9280..386d797 100644
--- a/include/asm-sh/clock.h
+++ b/include/asm-sh/clock.h
@@ -13,7 +13,7 @@ struct clk_ops {
 	void (*enable)(struct clk *clk);
 	void (*disable)(struct clk *clk);
 	void (*recalc)(struct clk *clk);
-	int (*set_rate)(struct clk *clk, unsigned long rate);
+	int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
 };
 
 struct clk {
@@ -48,6 +48,34 @@ void clk_recalc_rate(struct clk *);
 int clk_register(struct clk *);
 void clk_unregister(struct clk *);
 
-int show_clocks(struct seq_file *m);
+/* the exported API, in addition to clk_set_rate */
+/**
+ * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ * @algo_id: algorithm id to be passed down to ops->set_rate
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);
 
+enum clk_sh_algo_id {
+	NO_CHANGE = 0,
+
+	IUS_N1_N1,
+	IUS_322,
+	IUS_522,
+	IUS_N11,
+
+	SB_N1,
+
+	SB3_N1,
+	SB3_32,
+	SB3_43,
+	SB3_54,
+
+	BP_N1,
+
+	IP_N1,
+};
 #endif /* __ASM_SH_CLOCK_H */
diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
index bccb7dd..4704e86 100644
--- a/include/asm-sh/cpu-sh3/mmu_context.h
+++ b/include/asm-sh/cpu-sh3/mmu_context.h
@@ -32,6 +32,7 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7707) |
     defined(CONFIG_CPU_SUBTYPE_SH7706) || \
     defined(CONFIG_CPU_SUBTYPE_SH7300) || \
     defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7712) || \
     defined(CONFIG_CPU_SUBTYPE_SH7710)
 #define INTEVT	0xa4000000	/* INTEVTE2(0xa4000000) */
 #else
diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h
index 602d061..86564e7 100644
--- a/include/asm-sh/cpu-sh4/freq.h
+++ b/include/asm-sh/cpu-sh4/freq.h
@@ -12,8 +12,16 @@ #define __ASM_CPU_SH4_FREQ_H
 
 #if defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7722)
 #define FRQCR		        0xa4150000
+#define VCLKCR			0xa4150004
+#define SCLKACR			0xa4150008
+#define SCLKBCR			0xa415000c
+#define IrDACLKCR		0xa4150010
 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
 #define	FRQCR			0xffc80000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define FRQCR0			0xffc80000
+#define FRQCR1			0xffc80004
+#define FRQMR1			0xffc80014
 #else
 #define FRQCR			0xffc00000
 #endif
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index afe188f..e81bf21 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -2,94 +2,13 @@ #ifndef __ASM_SH_IRQ_H
 #define __ASM_SH_IRQ_H
 
 #include <asm/machvec.h>
-#include <asm/ptrace.h>		/* for pt_regs */
 
-/* NR_IRQS is made from three components:
- *   1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules
- *   2. PINT_NR_IRQS   - number of PINT interrupts
- *   3. OFFCHIP_NR_IRQS - numbe of IRQs from off-chip peripherial modules
+/*
+ * A sane default based on a reasonable vector table size, platforms are
+ * advised to cap this at the hard limit that they're interested in
+ * through the machvec.
  */
-
-/* 1. ONCHIP_NR_IRQS */
-#if defined(CONFIG_CPU_SUBTYPE_SH7604)
-# define ONCHIP_NR_IRQS 24	// Actually 21
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707)
-# define ONCHIP_NR_IRQS 64
-# define PINT_NR_IRQS   16
-#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)
-# define ONCHIP_NR_IRQS 72
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define ONCHIP_NR_IRQS 112	/* XXX */
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define ONCHIP_NR_IRQS 72
-#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_SH7343) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define ONCHIP_NR_IRQS 109
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define ONCHIP_NR_IRQS 111
-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
-# define ONCHIP_NR_IRQS 256
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define ONCHIP_NR_IRQS 128
-#elif defined(CONFIG_SH_UNKNOWN)	/* Most be last */
-# define ONCHIP_NR_IRQS 144
-#endif
-
-/* 2. PINT_NR_IRQS */
-#ifdef CONFIG_SH_UNKNOWN
-# define PINT_NR_IRQS 16
-#else
-# ifndef PINT_NR_IRQS
-#  define PINT_NR_IRQS 0
-# endif
-#endif
-
-#if PINT_NR_IRQS > 0
-# define PINT_IRQ_BASE  ONCHIP_NR_IRQS
-#endif
-
-/* 3. OFFCHIP_NR_IRQS */
-#if defined(CONFIG_HD64461)
-# define OFFCHIP_NR_IRQS 18
-#elif defined(CONFIG_HD64465)
-# define OFFCHIP_NR_IRQS 16
-#elif defined (CONFIG_SH_DREAMCAST)
-# define OFFCHIP_NR_IRQS 96
-#elif defined (CONFIG_SH_TITAN)
-# 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_7722_SOLUTION_ENGINE)
-# define OFFCHIP_NR_IRQS 14
-#elif defined(CONFIG_SH_UNKNOWN)
-# define OFFCHIP_NR_IRQS 16	/* Must also be last */
-#else
-# define OFFCHIP_NR_IRQS 0
-#endif
-
-#if OFFCHIP_NR_IRQS > 0
-# define OFFCHIP_IRQ_BASE (ONCHIP_NR_IRQS + PINT_NR_IRQS)
-#endif
-
-/* NR_IRQS. 1+2+3 */
-#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS)
+#define NR_IRQS 256
 
 /*
  * Convert back and forth between INTEVT and IRQ values.
diff --git a/include/asm-sh/kdebug.h b/include/asm-sh/kdebug.h
new file mode 100644
index 0000000..493c206
--- /dev/null
+++ b/include/asm-sh/kdebug.h
@@ -0,0 +1,36 @@
+#ifndef __ASM_SH_KDEBUG_H
+#define __ASM_SH_KDEBUG_H
+
+#include <linux/notifier.h>
+#include <asm-generic/kdebug.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 shdie_chain;
+
+/* Grossly misnamed. */
+enum die_val {
+	DIE_TRAP,
+	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(&shdie_chain, val, &args);
+}
+#endif /* __ASM_SH_KDEBUG_H */
diff --git a/include/asm-sh/kexec.h b/include/asm-sh/kexec.h
index 9d235af..00f4260 100644
--- a/include/asm-sh/kexec.h
+++ b/include/asm-sh/kexec.h
@@ -1,5 +1,8 @@
-#ifndef _SH_KEXEC_H
-#define _SH_KEXEC_H
+#ifndef __ASM_SH_KEXEC_H
+#define __ASM_SH_KEXEC_H
+
+#include <asm/ptrace.h>
+#include <asm/string.h>
 
 /*
  * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
@@ -23,10 +26,37 @@ #define KEXEC_CONTROL_CODE_SIZE	4096
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_SH
 
-#define MAX_NOTE_BYTES 1024
-
-/* Provide a dummy definition to avoid build failures. */
 static inline void crash_setup_regs(struct pt_regs *newregs,
-					struct pt_regs *oldregs) { }
+				    struct pt_regs *oldregs)
+{
+	if (oldregs)
+		memcpy(newregs, oldregs, sizeof(*newregs));
+	else {
+		__asm__ __volatile__ ("mov r0, %0" : "=r" (newregs->regs[0]));
+		__asm__ __volatile__ ("mov r1, %0" : "=r" (newregs->regs[1]));
+		__asm__ __volatile__ ("mov r2, %0" : "=r" (newregs->regs[2]));
+		__asm__ __volatile__ ("mov r3, %0" : "=r" (newregs->regs[3]));
+		__asm__ __volatile__ ("mov r4, %0" : "=r" (newregs->regs[4]));
+		__asm__ __volatile__ ("mov r5, %0" : "=r" (newregs->regs[5]));
+		__asm__ __volatile__ ("mov r6, %0" : "=r" (newregs->regs[6]));
+		__asm__ __volatile__ ("mov r7, %0" : "=r" (newregs->regs[7]));
+		__asm__ __volatile__ ("mov r8, %0" : "=r" (newregs->regs[8]));
+		__asm__ __volatile__ ("mov r9, %0" : "=r" (newregs->regs[9]));
+		__asm__ __volatile__ ("mov r10, %0" : "=r" (newregs->regs[10]));
+		__asm__ __volatile__ ("mov r11, %0" : "=r" (newregs->regs[11]));
+		__asm__ __volatile__ ("mov r12, %0" : "=r" (newregs->regs[12]));
+		__asm__ __volatile__ ("mov r13, %0" : "=r" (newregs->regs[13]));
+		__asm__ __volatile__ ("mov r14, %0" : "=r" (newregs->regs[14]));
+		__asm__ __volatile__ ("mov r15, %0" : "=r" (newregs->regs[15]));
+
+		__asm__ __volatile__ ("sts pr, %0" : "=r" (newregs->pr));
+		__asm__ __volatile__ ("sts macl, %0" : "=r" (newregs->macl));
+		__asm__ __volatile__ ("sts mach, %0" : "=r" (newregs->mach));
+
+		__asm__ __volatile__ ("stc gbr, %0" : "=r" (newregs->gbr));
+		__asm__ __volatile__ ("stc sr, %0" : "=r" (newregs->sr));
 
-#endif /* _SH_KEXEC_H */
+		newregs->pc = (unsigned long)current_text_addr();
+	}
+}
+#endif /* __ASM_SH_KEXEC_H */
diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
index 0095c66..74bd095 100644
--- a/include/asm-sh/kgdb.h
+++ b/include/asm-sh/kgdb.h
@@ -17,6 +17,7 @@ #ifndef __KGDB_H
 #define __KGDB_H
 
 #include <asm/ptrace.h>
+#include <asm/cacheflush.h>
 
 struct console;
 
@@ -45,35 +46,21 @@ extern int kgdb_portnum;
 extern int kgdb_baud;
 extern char kgdb_parity;
 extern char kgdb_bits;
-extern int kgdb_console_setup(struct console *, char *);
 
 /* Init and interface stuff */
 extern int kgdb_init(void);
-extern int (*kgdb_serial_setup)(void);
 extern int (*kgdb_getchar)(void);
 extern void (*kgdb_putchar)(int);
 
-struct kgdb_sermap {
-	char *name;
-	int namelen;
-	int (*setup_fn)(struct console *, char *);
-	struct kgdb_sermap *next;
-};
-extern void kgdb_register_sermap(struct kgdb_sermap *map);
-extern struct kgdb_sermap *kgdb_porttype;
-
 /* Trap functions */
-typedef void (kgdb_debug_hook_t)(struct pt_regs *regs); 
+typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
 typedef void (kgdb_bus_error_hook_t)(void);
 extern kgdb_debug_hook_t  *kgdb_debug_hook;
 extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
 
-extern void breakpoint(void);
-
 /* Console */
-struct console;
 void kgdb_console_write(struct console *co, const char *s, unsigned count);
-void kgdb_console_init(void);
+extern int kgdb_console_setup(struct console *, char *);
 
 /* Prototypes for jmp fns */
 #define _JBLEN 9
@@ -81,11 +68,8 @@ typedef        int jmp_buf[_JBLEN];
 extern void    longjmp(jmp_buf __jmpb, int __retval);
 extern int     setjmp(jmp_buf __jmpb);
 
-/* Variadic macro to print our own message to the console */
-#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
-
 /* Forced breakpoint */
-#define BREAKPOINT()					\
+#define breakpoint()					\
 do {							\
 	if (kgdb_enabled)				\
 		__asm__ __volatile__("trapa   #0x3c");	\
@@ -95,7 +79,6 @@ do {							\
 #if defined(CONFIG_CPU_SH4)
 #define kgdb_flush_icache_range(start, end) \
 {									\
-	extern void __flush_purge_region(void *, int);			\
 	__flush_purge_region((void*)(start), (int)(end) - (int)(start));\
 	flush_icache_range((start), (end));				\
 }
@@ -103,31 +86,6 @@ #else
 #define kgdb_flush_icache_range(start, end)	do { } while (0)
 #endif
 
-/* Kernel assert macros */
-#ifdef CONFIG_KGDB_KERNEL_ASSERTS
-
-/* Predefined conditions */
-#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
-#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
-#define KA_VALID_KPTR(ptr)  (!(ptr) || \
-              ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
-               (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
-#define KA_VALID_PTRORERR(errptr) \
-               (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
-#define KA_HELD_GKL()  (current->lock_depth >= 0)
-
-/* The actual assert */
-#define KGDB_ASSERT(condition, message) do {                   \
-       if (!(condition) && (kgdb_enabled)) {                   \
-               KGDB_PRINTK("Assertion failed at %s:%d: %s\n",  \
-                                  __FILE__, __LINE__, message);\
-               BREAKPOINT();                                   \
-       }                                                       \
-} while (0)
-#else
-#define KGDB_ASSERT(condition, message)
-#endif
-
 /* Taken from sh-stub.c of GDB 4.18 */
 static const char hexchars[] = "0123456789abcdef";
 
@@ -142,5 +100,4 @@ static inline char lowhex(const int x)
 {
 	return hexchars[x & 0xf];
 }
-
 #endif
diff --git a/include/asm-sh/lboxre2.h b/include/asm-sh/lboxre2.h
new file mode 100644
index 0000000..e6d1605
--- /dev/null
+++ b/include/asm-sh/lboxre2.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_SH_LBOXRE2_H
+#define __ASM_SH_LBOXRE2_H
+
+/*
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 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.
+ *
+ */
+
+#define IRQ_CF1		9	/* CF1 */
+#define IRQ_CF0		10	/* CF0 */
+#define IRQ_INTD	11	/* INTD */
+#define IRQ_ETH1	12	/* Ether1 */
+#define IRQ_ETH0	13	/* Ether0 */
+#define IRQ_INTA	14	/* INTA */
+
+void init_lboxre2_IRQ(void);
+
+#define __IO_PREFIX	lboxre2
+#include <asm/io_generic.h>
+
+#endif  /* __ASM_SH_LBOXRE2_H */
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
index 3420244..199662b 100644
--- a/include/asm-sh/mmu_context.h
+++ b/include/asm-sh/mmu_context.h
@@ -12,6 +12,7 @@ #include <asm/cpu/mmu_context.h>
 #include <asm/tlbflush.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * The MMU "context" consists of two things:
@@ -168,6 +169,8 @@ #define init_new_context(tsk,mm)	(0)
 #define destroy_context(mm)		do { } while (0)
 #define set_asid(asid)			do { } while (0)
 #define get_asid()			(0)
+#define set_TTB(pgd)			do { } while (0)
+#define get_TTB()			(0)
 #define activate_context(mm,cpu)	do { } while (0)
 #define switch_mm(prev,next,tsk)	do { } while (0)
 #define deactivate_mm(tsk,mm)		do { } while (0)
@@ -210,8 +213,8 @@ #else
  * MMU control handlers for processors lacking memory
  * management hardware.
  */
-#define enable_mmu()	do { BUG(); } while (0)
-#define disable_mmu()	do { BUG(); } while (0)
+#define enable_mmu()	do { } while (0)
+#define disable_mmu()	do { } while (0)
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index ac4b467..7464de4 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -59,6 +59,7 @@ extern void (*clear_page)(void *to);
 extern void (*copy_page)(void *to, void *from);
 
 extern unsigned long shm_align_mask;
+extern unsigned long max_low_pfn, min_low_pfn;
 
 #ifdef CONFIG_MMU
 extern void clear_page_slow(void *to);
@@ -124,17 +125,16 @@ #define __MEMORY_SIZE		CONFIG_MEMORY_SIZ
 #define PAGE_OFFSET		CONFIG_PAGE_OFFSET
 #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)
 
-#define MAP_NR(addr)		(((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
-
-#define phys_to_page(phys)	(mem_map + (((phys)-__MEMORY_START) >> PAGE_SHIFT))
-#define page_to_phys(page)	(((page - mem_map) << PAGE_SHIFT) + __MEMORY_START)
+#define phys_to_page(phys)	(pfn_to_page(phys >> PAGE_SHIFT))
+#define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 
 /* PFN start number, because of __MEMORY_START */
 #define PFN_START		(__MEMORY_START >> PAGE_SHIFT)
 #define ARCH_PFN_OFFSET		(PFN_START)
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define pfn_valid(pfn)		(((pfn) - PFN_START) < max_mapnr)
+#define pfn_valid(pfn)		((pfn) >= min_low_pfn && (pfn) < max_low_pfn)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
diff --git a/include/asm-sh/param.h b/include/asm-sh/param.h
index ce13064..1012296 100644
--- a/include/asm-sh/param.h
+++ b/include/asm-sh/param.h
@@ -5,7 +5,7 @@ #ifdef __KERNEL__
 # ifdef CONFIG_SH_WDT
 #  define HZ		1000		/* Needed for high-res WOVF */
 # else
-#  define HZ		100
+#  define HZ		CONFIG_HZ
 # endif
 # define USER_HZ	100		/* User interfaces are in "ticks" */
 # define CLOCKS_PER_SEC	(USER_HZ)	/* frequency at which times() counts */
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 6ccc948..b1f9a9e 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -35,7 +35,7 @@ #define PCIBIOS_MIN_MEM		board_pci_chann
 /*
  * I/O routine helpers
  */
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define PCI_IO_AREA		0xFE400000
 #define PCI_IO_SIZE		0x00400000
 #else
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 184d7fc..5b523c7 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -568,10 +568,6 @@ #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)
-
 struct mm_struct;
 
 /*
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index 3e46a7a..d42f68e 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -44,7 +44,7 @@ enum cpu_type {
 	/* SH-3 types */
 	CPU_SH7705, CPU_SH7706, CPU_SH7707,
 	CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
-	CPU_SH7709, CPU_SH7709A, CPU_SH7710,
+	CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712,
 	CPU_SH7729, CPU_SH7300,
 
 	/* SH-4 types */
diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h
index c18f648..4083b59 100644
--- a/include/asm-sh/r7780rp.h
+++ b/include/asm-sh/r7780rp.h
@@ -1,17 +1,11 @@
 #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_SDPOW	(-1)
+
 #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 */
@@ -70,18 +64,12 @@ #define PA_VERREG       (PA_BCR+0x0700) 
 #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 */
@@ -95,7 +83,10 @@ #define IRQ_EXTENTION1  11              
 #define IRQ_ONETH       13              /* On board Ethernet IRQ */
 #define IRQ_PSW         14              /* Push Switch IRQ */
 
-#else /* R7780RP */
+#define IVDR_CK_ON	8		/* iVDR Clock ON */
+
+#elif defined(CONFIG_SH_R7780RP)
+#define PA_POFF		(-1)
 
 #define PA_BCR		0xa5000000	/* FPGA */
 #define	PA_IRLMSK	(PA_BCR+0x0000)	/* Interrupt Mask control */
@@ -163,7 +154,60 @@ #define IRQ_ONETH	12		/* On board Ethern
 #define IRQ_PSW		13		/* Push Switch IRQ */
 #define IRQ_ZIGBEE	14		/* Ziggbee IO IRQ */
 
-#endif  /* CONFIG_SH_R7780MP */
+#define IVDR_CK_ON	8		/* iVDR Clock ON */
+
+#elif defined(CONFIG_SH_R7785RP)
+#define PA_BCR		0xa4000000	/* FPGA */
+#define PA_SDPOW	(-1)
+
+#define	PA_PCISCR	(PA_BCR+0x0000)
+#define PA_IRLPRA	(PA_BCR+0x0002)
+#define	PA_IRLPRB	(PA_BCR+0x0004)
+#define	PA_IRLPRC	(PA_BCR+0x0006)
+#define	PA_IRLPRD	(PA_BCR+0x0008)
+#define IRLCNTR1	(PA_BCR+0x0010)
+#define	PA_IRLPRE	(PA_BCR+0x000a)
+#define	PA_IRLPRF	(PA_BCR+0x000c)
+#define	PA_EXIRLCR	(PA_BCR+0x000e)
+#define	PA_IRLMCR1	(PA_BCR+0x0010)
+#define	PA_IRLMCR2	(PA_BCR+0x0012)
+#define	PA_IRLSSR1	(PA_BCR+0x0014)
+#define	PA_IRLSSR2	(PA_BCR+0x0016)
+#define PA_CFTCR	(PA_BCR+0x0100)
+#define PA_CFPCR	(PA_BCR+0x0102)
+#define PA_PCICR	(PA_BCR+0x0110)
+#define PA_IVDRCTL	(PA_BCR+0x0112)
+#define PA_IVDRSR	(PA_BCR+0x0114)
+#define PA_PDRSTCR	(PA_BCR+0x0116)
+#define PA_POFF		(PA_BCR+0x0120)
+#define PA_LCDCR	(PA_BCR+0x0130)
+#define PA_TPCR		(PA_BCR+0x0140)
+#define PA_TPCKCR	(PA_BCR+0x0142)
+#define PA_TPRSTR	(PA_BCR+0x0144)
+#define PA_TPXPDR	(PA_BCR+0x0146)
+#define PA_TPYPDR	(PA_BCR+0x0148)
+#define PA_GPIOPFR	(PA_BCR+0x0150)
+#define PA_GPIODR	(PA_BCR+0x0152)
+#define PA_OBLED	(PA_BCR+0x0154)
+#define PA_SWSR		(PA_BCR+0x0156)
+#define PA_VERREG	(PA_BCR+0x0158)
+#define PA_SMCR		(PA_BCR+0x0200)
+#define PA_SMSMADR	(PA_BCR+0x0202)
+#define PA_SMMR		(PA_BCR+0x0204)
+#define PA_SMSADR1	(PA_BCR+0x0206)
+#define PA_SMSADR32	(PA_BCR+0x0244)
+#define PA_SMTRDR1	(PA_BCR+0x0246)
+#define PA_SMTRDR16	(PA_BCR+0x0264)
+#define PA_CU3MDR	(PA_BCR+0x0300)
+#define PA_CU5MDR	(PA_BCR+0x0302)
+#define PA_MMSR		(PA_BCR+0x0400)
+
+#define IVDR_CK_ON	4		/* iVDR Clock ON */
+
+#endif
+
+void make_r7780rp_irq(unsigned int irq);
+void highlander_init_irq(void);
 
 #define __IO_PREFIX	r7780rp
 #include <asm/io_generic.h>
diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
index d19e7cd..b9ae53c 100644
--- a/include/asm-sh/scatterlist.h
+++ b/include/asm-sh/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_SCATTERLIST_H
 #define __ASM_SH_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page * page; /* Location for highmem page, if any */
     unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sh/se.h b/include/asm-sh/se.h
index a183215..bd2596c 100644
--- a/include/asm-sh/se.h
+++ b/include/asm-sh/se.h
@@ -69,9 +69,11 @@ #define BCR_ILCRF	(PA_BCR + 10)
 #define BCR_ILCRG	(PA_BCR + 12)
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define IRQ_STNIC   12
+#define IRQ_STNIC	12
+#define IRQ_CFCARD	14
 #else
 #define IRQ_STNIC	10
+#define IRQ_CFCARD	7
 #endif
 
 #define __IO_PREFIX	se
diff --git a/include/asm-sh/se7722.h b/include/asm-sh/se7722.h
new file mode 100644
index 0000000..b3b31e4
--- /dev/null
+++ b/include/asm-sh/se7722.h
@@ -0,0 +1,118 @@
+#ifndef __ASM_SH_SE7722_H
+#define __ASM_SH_SE7722_H
+
+/*
+ * linux/include/asm-sh/se7722.h
+ *
+ * Copyright (C) 2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 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 <asm/addrspace.h>
+
+/* Box specific addresses.  */
+#define SE_AREA0_WIDTH	4		/* Area0: 32bit */
+#define PA_ROM		0xa0000000	/* EPROM */
+#define PA_ROM_SIZE	0x00200000	/* EPROM size 2M byte */
+#define PA_FROM		0xa1000000	/* Flash-ROM */
+#define PA_FROM_SIZE	0x01000000	/* Flash-ROM size 16M byte */
+#define PA_EXT1		0xa4000000
+#define PA_EXT1_SIZE	0x04000000
+#define PA_SDRAM	0xaC000000	/* DDR-SDRAM(Area3) 64MB */
+#define PA_SDRAM_SIZE	0x04000000
+
+#define PA_EXT4		0xb0000000
+#define PA_EXT4_SIZE	0x04000000
+
+#define PA_PERIPHERAL	0xB0000000
+
+#define PA_PCIC         PA_PERIPHERAL   		/* MR-SHPC-01 PCMCIA */
+#define PA_MRSHPC       (PA_PERIPHERAL + 0x003fffe0)    /* MR-SHPC-01 PCMCIA controller */
+#define PA_MRSHPC_MW1   (PA_PERIPHERAL + 0x00400000)    /* MR-SHPC-01 memory window base */
+#define PA_MRSHPC_MW2   (PA_PERIPHERAL + 0x00500000)    /* MR-SHPC-01 attribute window base */
+#define PA_MRSHPC_IO    (PA_PERIPHERAL + 0x00600000)    /* 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		(PA_PERIPHERAL + 0x00800000)	/* 8bit LED */
+#define PA_FPGA		(PA_PERIPHERAL + 0x01800000) 	/* FPGA base address */
+
+#define PA_LAN		(PA_AREA6_IO + 0)		/* SMC LAN91C111 */
+/* GPIO */
+#define MSTPCR0         0xA4150030UL
+#define MSTPCR1         0xA4150034UL
+#define MSTPCR2         0xA4150038UL
+
+#define FPGA_IN         0xb1840000UL
+#define FPGA_OUT        0xb1840004UL
+
+#define PORT_PECR       0xA4050108UL
+#define PORT_PJCR       0xA4050110UL
+#define PORT_PSELD      0xA4050154UL
+#define PORT_PSELB      0xA4050150UL
+
+#define PORT_PSELC      0xA4050152UL
+#define PORT_PKCR       0xA4050112UL
+#define PORT_PHCR       0xA405010EUL
+#define PORT_PLCR       0xA4050114UL
+#define PORT_PMCR       0xA4050116UL
+#define PORT_PRCR       0xA405011CUL
+#define PORT_PXCR       0xA4050148UL
+#define PORT_PSELA      0xA405014EUL
+#define PORT_PYCR       0xA405014AUL
+#define PORT_PZCR       0xA405014CUL
+
+/* IRQ */
+#define IRQ0_IRQ        32
+#define IRQ1_IRQ        33
+#define INTC_ICR0       0xA4140000UL
+#define INTC_ICR1       0xA414001CUL
+
+#define INTMSK0         0xa4140044
+#define INTMSKCLR0      0xa4140064
+#define INTC_INTPRI0    0xa4140010
+
+#define IRQ01_MODE      0xb1800000
+#define IRQ01_STS       0xb1800004
+#define IRQ01_MASK      0xb1800008
+#define EXT_BIT		(0x3fc0)        /* SH IRQ1 */
+#define MRSHPC_BIT0	(0x0004)        /* SH IRQ1 */
+#define MRSHPC_BIT1	(0x0008)        /* SH IRQ1 */
+#define MRSHPC_BIT2	(0x0010)        /* SH IRQ1 */
+#define MRSHPC_BIT3	(0x0020)        /* SH IRQ1 */
+#define SMC_BIT		(0x0002)        /* SH IRQ0 */
+#define USB_BIT		(0x0001)        /* SH IRQ0 */
+
+#define MRSHPC_IRQ3    	11
+#define MRSHPC_IRQ2    	12
+#define MRSHPC_IRQ1    	13
+#define MRSHPC_IRQ0    	14
+#define SMC_IRQ		10
+#define EXT_IRQ		5
+#define USB_IRQ		6
+
+
+/* arch/sh/boards/se/7722/irq.c */
+void init_se7722_IRQ(void);
+int se7722_irq_demux(int);
+
+#define __IO_PREFIX		se7722
+#include <asm/io_generic.h>
+
+#endif  /* __ASM_SH_SE7722_H */
diff --git a/include/asm-sh/se7751.h b/include/asm-sh/se7751.h
index 88cd379..02ca934 100644
--- a/include/asm-sh/se7751.h
+++ b/include/asm-sh/se7751.h
@@ -65,6 +65,8 @@ #define BCR_ILCRG	(PA_BCR + 12)
 
 #define IRQ_79C973	13
 
+void init_7751se_IRQ(void);
+
 #define __IO_PREFIX	sh7751se
 #include <asm/io_generic.h>
 
diff --git a/include/asm-sh/se7780.h b/include/asm-sh/se7780.h
new file mode 100644
index 0000000..40e9b41
--- /dev/null
+++ b/include/asm-sh/se7780.h
@@ -0,0 +1,108 @@
+#ifndef __ASM_SH_SE7780_H
+#define __ASM_SH_SE7780_H
+
+/*
+ * linux/include/asm-sh/se7780.h
+ *
+ * Copyright (C) 2006,2007  Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 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 <asm/addrspace.h>
+
+/* Box specific addresses.  */
+#define SE_AREA0_WIDTH	4		/* Area0: 32bit */
+#define PA_ROM		0xa0000000	/* EPROM */
+#define PA_ROM_SIZE	0x00400000	/* EPROM size 4M byte */
+#define PA_FROM		0xa1000000	/* Flash-ROM */
+#define PA_FROM_SIZE	0x01000000	/* Flash-ROM size 16M byte */
+#define PA_EXT1		0xa4000000
+#define PA_EXT1_SIZE	0x04000000
+#define PA_SM501	PA_EXT1		/* Graphic IC (SM501) */
+#define PA_SM501_SIZE	PA_EXT1_SIZE	/* Graphic IC (SM501) */
+#define PA_SDRAM	0xa8000000	/* DDR-SDRAM(Area2/3) 128MB */
+#define PA_SDRAM_SIZE	0x08000000
+
+#define PA_EXT4		0xb0000000
+#define PA_EXT4_SIZE	0x04000000
+#define PA_EXT_FLASH	PA_EXT4		/* Expansion Flash-ROM */
+
+#define PA_PERIPHERAL	PA_AREA6_IO	/* SW6-6=ON */
+
+#define PA_LAN		(PA_PERIPHERAL + 0)		/* SMC LAN91C111 */
+#define PA_LED_DISP	(PA_PERIPHERAL + 0x02000000)	/* 8words LED Display */
+#define DISP_CHAR_RAM	(7 << 3)
+#define DISP_SEL0_ADDR	(DISP_CHAR_RAM + 0)
+#define DISP_SEL1_ADDR	(DISP_CHAR_RAM + 1)
+#define DISP_SEL2_ADDR	(DISP_CHAR_RAM + 2)
+#define DISP_SEL3_ADDR	(DISP_CHAR_RAM + 3)
+#define DISP_SEL4_ADDR	(DISP_CHAR_RAM + 4)
+#define DISP_SEL5_ADDR	(DISP_CHAR_RAM + 5)
+#define DISP_SEL6_ADDR	(DISP_CHAR_RAM + 6)
+#define DISP_SEL7_ADDR	(DISP_CHAR_RAM + 7)
+
+#define DISP_UDC_RAM	(5 << 3)
+#define PA_FPGA		(PA_PERIPHERAL + 0x03000000) /* FPGA base address */
+
+/* FPGA register address and bit */
+#define FPGA_SFTRST		(PA_FPGA + 0)	/* Soft reset register */
+#define FPGA_INTMSK1		(PA_FPGA + 2)	/* Interrupt Mask register 1 */
+#define FPGA_INTMSK2		(PA_FPGA + 4)	/* Interrupt Mask register 2 */
+#define FPGA_INTSEL1		(PA_FPGA + 6)	/* Interrupt select register 1 */
+#define FPGA_INTSEL2		(PA_FPGA + 8)	/* Interrupt select register 2 */
+#define FPGA_INTSEL3		(PA_FPGA + 10)	/* Interrupt select register 3 */
+#define FPGA_PCI_INTSEL1	(PA_FPGA + 12)	/* PCI Interrupt select register 1 */
+#define FPGA_PCI_INTSEL2	(PA_FPGA + 14)	/* PCI Interrupt select register 2 */
+#define FPGA_INTSET		(PA_FPGA + 16)	/* IRQ/IRL select register */
+#define FPGA_INTSTS1		(PA_FPGA + 18)	/* Interrupt status register 1 */
+#define FPGA_INTSTS2		(PA_FPGA + 20)	/* Interrupt status register 2 */
+#define FPGA_REQSEL		(PA_FPGA + 22)	/* REQ/GNT select register */
+#define FPGA_DBG_LED		(PA_FPGA + 32)	/* Debug LED(D-LED[8:1] */
+#define PA_LED			FPGA_DBG_LED
+#define FPGA_IVDRID		(PA_FPGA + 36)	/* iVDR ID Register */
+#define FPGA_IVDRPW		(PA_FPGA + 38)	/* iVDR Power ON Register */
+#define FPGA_MMCID		(PA_FPGA + 40)	/* MMC ID Register */
+
+/* FPGA INTSEL position */
+/* INTSEL1 */
+#define IRQPOS_SMC91CX          (0 * 4)
+#define IRQPOS_SM501            (1 * 4)
+/* INTSEL2 */
+#define IRQPOS_EXTINT1          (0 * 4)
+#define IRQPOS_EXTINT2          (1 * 4)
+#define IRQPOS_EXTINT3          (2 * 4)
+#define IRQPOS_EXTINT4          (3 * 4)
+/* INTSEL3 */
+#define IRQPOS_PCCPW            (0 * 4)
+
+/* IDE interrupt */
+#define IRQ_IDE0                67 /* iVDR */
+
+/* SMC interrupt */
+#define SMC_IRQ                 8
+
+/* SM501 interrupt */
+#define SM501_IRQ               0
+
+/* interrupt pin */
+#define IRQPIN_EXTINT1          0 /* IRQ0 pin */
+#define IRQPIN_EXTINT2          1 /* IRQ1 pin */
+#define IRQPIN_EXTINT3          2 /* IRQ2 pin */
+#define IRQPIN_SMC91CX          3 /* IRQ3 pin */
+#define IRQPIN_EXTINT4          4 /* IRQ4 pin */
+#define IRQPIN_PCC0             5 /* IRQ5 pin */
+#define IRQPIN_PCC2             6 /* IRQ6 pin */
+#define IRQPIN_SM501            7 /* IRQ7 pin */
+#define IRQPIN_PCCPW            7 /* IRQ7 pin */
+
+/* arch/sh/boards/se/7780/irq.c */
+void init_se7780_IRQ(void);
+
+#define __IO_PREFIX		se7780
+#include <asm/io_generic.h>
+
+#endif  /* __ASM_SH_SE7780_H */
diff --git a/include/asm-sh/socket.h b/include/asm-sh/socket.h
index ca70362..c48d6fc 100644
--- a/include/asm-sh/socket.h
+++ b/include/asm-sh/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __ASM_SH_SOCKET_H */
diff --git a/include/asm-sh/sockios.h b/include/asm-sh/sockios.h
index 08a71df..cf8b96b 100644
--- a/include/asm-sh/sockios.h
+++ b/include/asm-sh/sockios.h
@@ -9,5 +9,6 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp (timespec) */
 #endif /* __ASM_SH_SOCKIOS_H */
diff --git a/include/asm-sh/stat.h b/include/asm-sh/stat.h
index 6c41a60..6d6ad26 100644
--- a/include/asm-sh/stat.h
+++ b/include/asm-sh/stat.h
@@ -16,15 +16,13 @@ struct __old_kernel_stat {
 };
 
 struct stat {
-	unsigned short st_dev;
-	unsigned short __pad1;
-	unsigned long st_ino;
+	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 short st_rdev;
-	unsigned short __pad2;
+	unsigned long  st_rdev;
 	unsigned long  st_size;
 	unsigned long  st_blksize;
 	unsigned long  st_blocks;
@@ -38,8 +36,6 @@ struct stat {
 	unsigned long  __unused5;
 };
 
-#define STAT_HAVE_NSEC 1
-
 /* This matches struct stat64 in glibc2.1, hence the absolutely
  * insane amounts of padding around dev_t's.
  */
@@ -47,7 +43,9 @@ struct stat64 {
 	unsigned long long	st_dev;
 	unsigned char	__pad0[4];
 
-	unsigned long	st_ino;
+#define STAT64_HAS_BROKEN_ST_INO	1
+	unsigned long	__st_ino;
+
 	unsigned int	st_mode;
 	unsigned int	st_nlink;
 
@@ -71,8 +69,9 @@ struct stat64 {
 	unsigned long	st_ctime;
 	unsigned long	st_ctime_nsec; 
 
-	unsigned long	__unused1;
-	unsigned long	__unused2;
+	unsigned long long	st_ino;
 };
 
+#define STAT_HAVE_NSEC 1
+
 #endif /* __ASM_SH_STAT_H */
diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
index 95bc7db..55f8db6 100644
--- a/include/asm-sh/string.h
+++ b/include/asm-sh/string.h
@@ -126,9 +126,6 @@ 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 4a6a19f..e7e96ee 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -9,6 +9,7 @@ #define __ASM_SH_SYSTEM_H
 #include <linux/irqflags.h>
 #include <linux/compiler.h>
 #include <asm/types.h>
+#include <asm/ptrace.h>
 
 /*
  *	switch_to() should switch tasks to task nr n, first
@@ -81,16 +82,6 @@ #define __icbi()			\
 }
 #endif
 
-static inline unsigned long tas(volatile int *m)
-{
-	unsigned long retval;
-
-	__asm__ __volatile__ ("tas.b	@%1\n\t"
-			      "movt	%0"
-			      : "=r" (retval): "r" (m): "t", "memory");
-	return retval;
-}
-
 /*
  * A brief note on ctrl_barrier(), the control register write barrier.
  *
@@ -255,6 +246,8 @@ #define cmpxchg(ptr,o,n)						 \
 				    (unsigned long)_n_, sizeof(*(ptr))); \
   })
 
+extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
+
 extern void *set_exception_table_vec(unsigned int vec, void *handler);
 
 static inline void *set_exception_table_evt(unsigned int evt, void *handler)
diff --git a/include/asm-sh64/kdebug.h b/include/asm-sh64/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-sh64/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-sh64/mmu_context.h b/include/asm-sh64/mmu_context.h
index 8c860da..507bf72 100644
--- a/include/asm-sh64/mmu_context.h
+++ b/include/asm-sh64/mmu_context.h
@@ -27,7 +27,7 @@ #ifndef __ASSEMBLY__
 extern unsigned long mmu_context_cache;
 
 #include <asm/page.h>
-
+#include <asm-generic/mm_hooks.h>
 
 /* Current mm's pgd */
 extern pgd_t *mmu_pdtp_cache;
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
index 6b97c4c..b875482 100644
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -485,10 +485,6 @@ #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)
-
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/include/asm-sh64/scatterlist.h b/include/asm-sh64/scatterlist.h
index 5d8fa32..1c723f2 100644
--- a/include/asm-sh64/scatterlist.h
+++ b/include/asm-sh64/scatterlist.h
@@ -11,6 +11,8 @@
 #ifndef __ASM_SH64_SCATTERLIST_H
 #define __ASM_SH64_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page * page; /* Location for highmem page, if any */
     unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sh64/sockios.h b/include/asm-sh64/sockios.h
index 1ae23ae..419e76f 100644
--- a/include/asm-sh64/sockios.h
+++ b/include/asm-sh64/sockios.h
@@ -20,5 +20,6 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp - linux-specific */
+#define SIOCGSTAMP	_IOR('s', 100, struct timeval) /* Get stamp (timeval) */
+#define SIOCGSTAMPNS	_IOR('s', 101, struct timespec) /* Get stamp (timespec) */
 #endif /* __ASM_SH64_SOCKIOS_H */
diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h
index b1598c2..5ff9464 100644
--- a/include/asm-sh64/system.h
+++ b/include/asm-sh64/system.h
@@ -43,8 +43,6 @@ #define nop() __asm__ __volatile__ ("nop
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
-#define tas(ptr) (xchg((ptr), 1))
-
 extern void __xchg_called_with_bad_pointer(void);
 
 #define mb()	__asm__ __volatile__ ("synco": : :"memory")
diff --git a/include/asm-sparc/kdebug.h b/include/asm-sparc/kdebug.h
index fba9248..404d807 100644
--- a/include/asm-sparc/kdebug.h
+++ b/include/asm-sparc/kdebug.h
@@ -66,4 +66,8 @@ #define KDEBUG_DUNNO_OFF    0x4
 #define KDEBUG_DUNNO2_OFF   0x8
 #define KDEBUG_TEACH_OFF    0xc
 
+enum die_val {
+	DIE_UNUSED,
+};
+
 #endif /* !(_SPARC_KDEBUG_H) */
diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h
index ed1e01d..671a997 100644
--- a/include/asm-sparc/mmu_context.h
+++ b/include/asm-sparc/mmu_context.h
@@ -5,6 +5,8 @@ #include <asm/btfixup.h>
 
 #ifndef __ASSEMBLY__
 
+#include <asm-generic/mm_hooks.h>
+
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 }
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index 274868d..9ea105e 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -35,8 +35,8 @@ struct property {
 };
 
 struct device_node {
-	char	*name;
-	char	*type;
+	const char	*name;
+	const char	*type;
 	phandle	node;
 	char	*path_component_name;
 	char	*full_name;
@@ -85,12 +85,14 @@ extern struct device_node *of_find_node_
 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 int of_device_is_compatible(struct device_node *device, const char *);
-extern void *of_get_property(struct device_node *node, const char *name,
-			     int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+				   const char *);
+extern const void *of_get_property(const struct device_node *node,
+				   const char *name,
+				   int *lenp);
 #define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
diff --git a/include/asm-sparc/socket.h b/include/asm-sparc/socket.h
index f6c4e5b..7c14239 100644
--- a/include/asm-sparc/socket.h
+++ b/include/asm-sparc/socket.h
@@ -49,6 +49,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0021
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
diff --git a/include/asm-sparc/sockios.h b/include/asm-sparc/sockios.h
index 0c01b59..990ea74 100644
--- a/include/asm-sparc/sockios.h
+++ b/include/asm-sparc/sockios.h
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC_SOCKIOS_H) */
 
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 100c3ea..8b6d9c9 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -241,7 +241,6 @@ #endif
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 extern void __xchg_called_with_bad_pointer(void);
 
diff --git a/include/asm-sparc64/Kbuild b/include/asm-sparc64/Kbuild
index a7f4440..854fd3a 100644
--- a/include/asm-sparc64/Kbuild
+++ b/include/asm-sparc64/Kbuild
@@ -8,7 +8,6 @@ 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
diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h
index 2f0bec2..3fb4e1f 100644
--- a/include/asm-sparc64/atomic.h
+++ b/include/asm-sparc64/atomic.h
@@ -9,6 +9,7 @@ #ifndef __ARCH_SPARC64_ATOMIC__
 #define __ARCH_SPARC64_ATOMIC__
 
 #include <linux/types.h>
+#include <asm/system.h>
 
 typedef struct { volatile int counter; } atomic_t;
 typedef struct { volatile __s64 counter; } atomic64_t;
@@ -70,25 +71,47 @@ #define atomic64_dec(v) atomic64_sub(1, 
 #define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
 #define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
 
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	likely(c != (u));					\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+#define atomic64_cmpxchg(v, o, n) \
+	((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 /* Atomic operations are already serializing */
 #ifdef CONFIG_SMP
 #define smp_mb__before_atomic_dec()	membar_storeload_loadload();
diff --git a/include/asm-sparc64/const.h b/include/asm-sparc64/const.h
deleted file mode 100644
index 8ad902b..0000000
--- a/include/asm-sparc64/const.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* const.h: Macros for dealing with constants.  */
-
-#ifndef _SPARC64_CONST_H
-#define _SPARC64_CONST_H
-
-/* Some constant macros are used in both assembler and
- * C code.  Therefore we cannot annotate them always with
- * 'UL' and other type specificers unilaterally.  We
- * use the following macros to deal with this.
- */
-
-#ifdef __ASSEMBLY__
-#define _AC(X,Y)	X
-#else
-#define _AC(X,Y)	(X##Y)
-#endif
-
-
-#endif /* !(_SPARC64_CONST_H) */
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index f2cc941..e89922d 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -17,8 +17,8 @@ #include <linux/threads.h>
 typedef struct {
 	/* Dcache line 1 */
 	unsigned int	__softirq_pending; /* must be 1st, see rtrap.S */
-	unsigned int	multiplier;
-	unsigned int	counter;
+	unsigned int	__pad0_1;
+	unsigned int	__pad0_2;
 	unsigned int	__pad1;
 	unsigned long	clock_tick;	/* %tick's per second */
 	unsigned long	udelay_val;
diff --git a/include/asm-sparc64/device.h b/include/asm-sparc64/device.h
index d8f9872..d5a4559 100644
--- a/include/asm-sparc64/device.h
+++ b/include/asm-sparc64/device.h
@@ -3,5 +3,21 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC64_DEVICE_H
+#define _ASM_SPARC64_DEVICE_H
 
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+	void			*iommu;
+	void			*stc;
+	void			*host_controller;
+
+	struct device_node	*prom_node;
+	struct of_device	*op;
+
+	unsigned int		msi_num;
+};
+
+#endif /* _ASM_SPARC64_DEVICE_H */
diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h
index a4afe9d..9c1c6db 100644
--- a/include/asm-sparc64/ebus.h
+++ b/include/asm-sparc64/ebus.h
@@ -8,7 +8,6 @@
 #ifndef __SPARC64_EBUS_H
 #define __SPARC64_EBUS_H
 
-#include <asm/pbm.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
@@ -41,7 +40,6 @@ struct linux_ebus {
 	struct of_device		ofdev;
 	struct linux_ebus		*next;
 	struct linux_ebus_device	*devices;
-	struct pci_pbm_info		*parent;
 	struct pci_dev			*self;
 	int				 index;
 	int				 is_rio;
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index 331013a..4aa0925 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -549,7 +549,7 @@ static int __init ebus_fdthree_p(struct 
 	if (!strcmp(edev->prom_node->name, "fdthree"))
 		return 1;
 	if (!strcmp(edev->prom_node->name, "floppy")) {
-		char *compat;
+		const char *compat;
 
 		compat = of_get_property(edev->prom_node,
 					 "compatible", NULL);
@@ -661,7 +661,7 @@ #ifdef CONFIG_PCI
 		struct linux_ebus_device *edev = NULL;
 		unsigned long config = 0;
 		void __iomem *auxio_reg;
-		char *state_prop;
+		const char *state_prop;
 
 		for_each_ebus(ebus) {
 			for_each_ebusdev(edev, ebus) {
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index 30b912d..ad595b6 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -24,14 +24,6 @@ extern unsigned long kern_base, kern_siz
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 #define BIO_VMERGE_BOUNDARY	8192
 
-/* Different PCI controllers we support have their PCI MEM space
- * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area,
- * so need to chop off the top 33 or 32 bits.
- */
-extern unsigned long pci_memspace_mask;
-
-#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask)
-
 static __inline__ u8 _inb(unsigned long addr)
 {
 	u8 ret;
diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h
index 0de7a3d..0b1813f 100644
--- a/include/asm-sparc64/iommu.h
+++ b/include/asm-sparc64/iommu.h
@@ -7,15 +7,51 @@ #ifndef _SPARC64_IOMMU_H
 #define _SPARC64_IOMMU_H
 
 /* The format of an iopte in the page tables. */
-#define IOPTE_VALID   0x8000000000000000UL /* IOPTE is valid                  */
-#define IOPTE_64K     0x2000000000000000UL /* IOPTE is for 64k page           */
-#define IOPTE_STBUF   0x1000000000000000UL /* DVMA can use streaming buffer   */
-#define IOPTE_INTRA   0x0800000000000000UL /* SBUS slot-->slot direct transfer*/
-#define IOPTE_CONTEXT 0x07ff800000000000UL /* Context number		      */
-#define IOPTE_PAGE    0x00007fffffffe000UL /* Physical page number (PA[42:13])*/
-#define IOPTE_CACHE   0x0000000000000010UL /* Cached (in UPA E-cache)         */
-#define IOPTE_WRITE   0x0000000000000002UL /* Writeable                       */
+#define IOPTE_VALID   0x8000000000000000UL
+#define IOPTE_64K     0x2000000000000000UL
+#define IOPTE_STBUF   0x1000000000000000UL
+#define IOPTE_INTRA   0x0800000000000000UL
+#define IOPTE_CONTEXT 0x07ff800000000000UL
+#define IOPTE_PAGE    0x00007fffffffe000UL
+#define IOPTE_CACHE   0x0000000000000010UL
+#define IOPTE_WRITE   0x0000000000000002UL
 
 #define IOMMU_NUM_CTXS	4096
 
+struct iommu_arena {
+	unsigned long	*map;
+	unsigned int	hint;
+	unsigned int	limit;
+};
+
+struct iommu {
+	spinlock_t		lock;
+	struct iommu_arena	arena;
+	iopte_t			*page_table;
+	u32			page_table_map_base;
+	unsigned long		iommu_control;
+	unsigned long		iommu_tsbbase;
+	unsigned long		iommu_flush;
+	unsigned long		iommu_flushinv;
+	unsigned long		iommu_ctxflush;
+	unsigned long		write_complete_reg;
+	unsigned long		dummy_page;
+	unsigned long		dummy_page_pa;
+	unsigned long		ctx_lowest_free;
+	DECLARE_BITMAP(ctx_bitmap, IOMMU_NUM_CTXS);
+	u32			dma_addr_mask;
+};
+
+struct strbuf {
+	int			strbuf_enabled;
+	unsigned long		strbuf_control;
+	unsigned long		strbuf_pflush;
+	unsigned long		strbuf_fsync;
+	unsigned long		strbuf_ctxflush;
+	unsigned long		strbuf_ctxmatch_base;
+	unsigned long		strbuf_flushflag_pa;
+	volatile unsigned long *strbuf_flushflag;
+	volatile unsigned long	__flushflag_buf[(64+(64-1)) / sizeof(long)];
+};
+
 #endif /* !(_SPARC_IOMMU_H) */
diff --git a/include/asm-sparc64/isa.h b/include/asm-sparc64/isa.h
index d9728b9..ecd9290 100644
--- a/include/asm-sparc64/isa.h
+++ b/include/asm-sparc64/isa.h
@@ -7,7 +7,6 @@
 #ifndef __SPARC64_ISA_H
 #define __SPARC64_ISA_H
 
-#include <asm/pbm.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
@@ -29,7 +28,6 @@ struct sparc_isa_bridge {
 	struct of_device	ofdev;
 	struct sparc_isa_bridge	*next;
 	struct sparc_isa_device	*devices;
-	struct pci_pbm_info	*parent;
 	struct pci_dev		*self;
 	int			index;
 	struct device_node	*prom_node;
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index 11251bd..f8032e7 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -7,19 +7,8 @@ #include <linux/notifier.h>
 
 struct pt_regs;
 
-struct die_args {
-	struct pt_regs *regs;
-	const char *str;
-	long err;
-	int trapnr;
-	int signr;
-};
-
-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 sparc64die_chain;
 
 extern void bad_trap(struct pt_regs *, long);
 
@@ -36,16 +25,4 @@ enum die_val {
 	DIE_PAGE_FAULT,
 };
 
-static inline int notify_die(enum die_val val,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(&sparc64die_chain, val, &args);
-}
-
 #endif
diff --git a/include/asm-sparc64/local.h b/include/asm-sparc64/local.h
index dfde115..c11c530 100644
--- a/include/asm-sparc64/local.h
+++ b/include/asm-sparc64/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_SPARC64_LOCAL_H
-#define _ARCH_SPARC64_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic64_t local_t;
-
-#define LOCAL_INIT(i)	ATOMIC64_INIT(i)
-#define local_read(v)	atomic64_read(v)
-#define local_set(v,i)	atomic64_set(v,i)
-
-#define local_inc(v)	atomic64_inc(v)
-#define local_dec(v)	atomic64_dec(v)
-#define local_add(i, v)	atomic64_add(i, v)
-#define local_sub(i, v)	atomic64_sub(i, v)
-
-#define __local_inc(v)		((v)->counter++)
-#define __local_dec(v)		((v)->counter--)
-#define __local_add(i,v)	((v)->counter+=(i))
-#define __local_sub(i,v)	((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations.  Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v)	local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i)	local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v)	local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v)	local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v)	local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v)	local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v)	__local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v)	__local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v)	__local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v)	__local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_SPARC64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-sparc64/lsu.h b/include/asm-sparc64/lsu.h
index e5329c7..79f1098 100644
--- a/include/asm-sparc64/lsu.h
+++ b/include/asm-sparc64/lsu.h
@@ -2,7 +2,7 @@
 #ifndef _SPARC64_LSU_H
 #define _SPARC64_LSU_H
 
-#include <asm/const.h>
+#include <linux/const.h>
 
 /* LSU Control Register */
 #define LSU_CONTROL_PM _AC(0x000001fe00000000,UL) /* Phys-watchpoint byte mask*/
diff --git a/include/asm-sparc64/mmu.h b/include/asm-sparc64/mmu.h
index 70af4b6..8abc58f 100644
--- a/include/asm-sparc64/mmu.h
+++ b/include/asm-sparc64/mmu.h
@@ -1,8 +1,8 @@
 #ifndef __MMU_H
 #define __MMU_H
 
+#include <linux/const.h>
 #include <asm/page.h>
-#include <asm/const.h>
 #include <asm/hypervisor.h>
 
 #define CTX_NR_BITS		13
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index 2337eb4..8d12903 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -9,6 +9,7 @@ #ifndef __ASSEMBLY__
 #include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
+#include <asm-generic/mm_hooks.h>
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index ff736ea..7af1077 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -5,7 +5,7 @@ #define _SPARC64_PAGE_H
 
 #ifdef __KERNEL__
 
-#include <asm/const.h>
+#include <linux/const.h>
 
 #if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
 #define PAGE_SHIFT   13
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 284dfd0..6340a52 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -103,7 +103,7 @@ static int ebus_ecpp_p(struct linux_ebus
 	if (!strcmp(edev->prom_node->name, "ecpp"))
 		return 1;
 	if (!strcmp(edev->prom_node->name, "parallel")) {
-		char *compat;
+		const char *compat;
 
 		compat = of_get_property(edev->prom_node,
 					 "compatible", NULL);
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index 7a246d8..c008cec 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -1,7 +1,6 @@
-/* $Id: pbm.h,v 1.27 2001/08/12 13:18:23 davem Exp $
- * pbm.h: UltraSparc PCI controller software state.
+/* pbm.h: UltraSparc PCI controller software state.
  *
- * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
  */
 
 #ifndef __SPARC64_PBM_H
@@ -30,90 +29,7 @@ #include <asm/iommu.h>
  * PCI bus.
  */
 
-struct pci_controller_info;
-
-/* This contains the software state necessary to drive a PCI
- * controller's IOMMU.
- */
-struct pci_iommu_arena {
-	unsigned long	*map;
-	unsigned int	hint;
-	unsigned int	limit;
-};
-
-struct pci_iommu {
-	/* This protects the controller's IOMMU and all
-	 * streaming buffers underneath.
-	 */
-	spinlock_t	lock;
-
-	struct pci_iommu_arena arena;
-
-	/* IOMMU page table, a linear array of ioptes. */
-	iopte_t		*page_table;		/* The page table itself. */
-
-	/* Base PCI memory space address where IOMMU mappings
-	 * begin.
-	 */
-	u32		page_table_map_base;
-
-	/* IOMMU Controller Registers */
-	unsigned long	iommu_control;		/* IOMMU control register */
-	unsigned long	iommu_tsbbase;		/* IOMMU page table base register */
-	unsigned long	iommu_flush;		/* IOMMU page flush register */
-	unsigned long	iommu_ctxflush;		/* IOMMU context flush register */
-
-	/* This is a register in the PCI controller, which if
-	 * read will have no side-effects but will guarantee
-	 * completion of all previous writes into IOMMU/STC.
-	 */
-	unsigned long	write_complete_reg;
-
-	/* In order to deal with some buggy third-party PCI bridges that
-	 * do wrong prefetching, we never mark valid mappings as invalid.
-	 * Instead we point them at this dummy page.
-	 */
-	unsigned long	dummy_page;
-	unsigned long	dummy_page_pa;
-
-	/* CTX allocation. */
-	unsigned long ctx_lowest_free;
-	unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)];
-
-	/* Here a PCI controller driver describes the areas of
-	 * PCI memory space where DMA to/from physical memory
-	 * are addressed.  Drivers interrogate the PCI layer
-	 * if their device has addressing limitations.  They
-	 * do so via pci_dma_supported, and pass in a mask of
-	 * DMA address bits their device can actually drive.
-	 *
-	 * The test for being usable is:
-	 * 	(device_mask & dma_addr_mask) == dma_addr_mask
-	 */
-	u32 dma_addr_mask;
-};
-
-extern void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
-
-/* This describes a PCI bus module's streaming buffer. */
-struct pci_strbuf {
-	int		strbuf_enabled;		/* Present and using it? */
-
-	/* Streaming Buffer Control Registers */
-	unsigned long	strbuf_control;		/* STC control register */
-	unsigned long	strbuf_pflush;		/* STC page flush register */
-	unsigned long	strbuf_fsync;		/* STC flush synchronization reg */
-	unsigned long	strbuf_ctxflush;	/* STC context flush register */
-	unsigned long	strbuf_ctxmatch_base;	/* STC context flush match reg */
-	unsigned long	strbuf_flushflag_pa;	/* Physical address of flush flag */
-	volatile unsigned long *strbuf_flushflag; /* The flush flag itself */
-
-	/* And this is the actual flush flag area.
-	 * We allocate extra because the chips require
-	 * a 64-byte aligned area.
-	 */
-	volatile unsigned long	__flushflag_buf[(64 + (64 - 1)) / sizeof(long)];
-};
+extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
 
 #define PCI_STC_FLUSHFLAG_INIT(STC) \
 	(*((STC)->strbuf_flushflag) = 0UL)
@@ -126,6 +42,8 @@ #define PCI_STC_FLUSHFLAG_SET(STC) \
 #define PROM_PCIRNG_MAX		64
 #define PROM_PCIIMAP_MAX	64
 
+struct pci_controller_info;
+
 struct pci_pbm_info {
 	/* PCI controller we sit under. */
 	struct pci_controller_info	*parent;
@@ -160,11 +78,6 @@ #define PBM_CHIP_TYPE_TOMATILLO		5
 
 	/* OBP specific information. */
 	struct device_node		*prom_node;
-	struct linux_prom_pci_ranges	*pbm_ranges;
-	int				num_pbm_ranges;
-	struct linux_prom_pci_intmap	*pbm_intmap;
-	int				num_pbm_intmap;
-	struct linux_prom_pci_intmask	*pbm_intmask;
 	u64				ino_bitmap;
 
 	/* PBM I/O and Memory space resources. */
@@ -197,13 +110,10 @@ #ifdef CONFIG_PCI_MSI
 #endif /* !(CONFIG_PCI_MSI) */
 
 	/* This PBM's streaming buffer. */
-	struct pci_strbuf		stc;
+	struct strbuf			stc;
 
 	/* IOMMU state, potentially shared by both PBM segments. */
-	struct pci_iommu		*iommu;
-
-	/* PCI slot mapping. */
-	unsigned int			pci_first_slot;
+	struct iommu			*iommu;
 
 	/* Now things for the actual PCI bus probes. */
 	unsigned int			pci_first_busno;
@@ -220,17 +130,12 @@ struct pci_controller_info {
 	 */
 	int				index;
 
-	/* Do the PBMs both exist in the same PCI domain? */
-	int				pbms_same_domain;
-
 	/* The PCI bus modules controlled by us. */
 	struct pci_pbm_info		pbm_A;
 	struct pci_pbm_info		pbm_B;
 
 	/* Operations which are controller specific. */
 	void (*scan_bus)(struct pci_controller_info *);
-	void (*base_address_update)(struct pci_dev *, int);
-	void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *);
 
 #ifdef CONFIG_PCI_MSI
 	int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
@@ -244,27 +149,4 @@ #endif
 	unsigned int			pci_last_busno;
 };
 
-/* PCI devices which are not bridges have this placed in their pci_dev
- * sysdata member.  This makes OBP aware PCI device drivers easier to
- * code.
- */
-struct pcidev_cookie {
-	struct pci_pbm_info		*pbm;
-	struct device_node		*prom_node;
-	struct of_device		*op;
-	struct linux_prom_pci_registers	prom_regs[PROMREG_MAX];
-	int num_prom_regs;
-	struct linux_prom_pci_registers prom_assignments[PROMREG_MAX];
-	int num_prom_assignments;
-#ifdef CONFIG_PCI_MSI
-	unsigned int			msi_num;
-#endif
-};
-
-/* Currently these are the same across all PCI controllers
- * we support.  Someday they may not be...
- */
-#define PCI_IRQ_IGN	0x000007c0	/* Interrupt Group Number */
-#define PCI_IRQ_INO	0x0000003f	/* Interrupt Number */
-
 #endif /* !(__SPARC64_PBM_H) */
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index b14a725..47cea16 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -54,7 +54,7 @@ struct pci_iommu_ops {
 	void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int);
 };
 
-extern struct pci_iommu_ops *pci_iommu_ops;
+extern const struct pci_iommu_ops *pci_iommu_ops;
 
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices.
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index 0d3df76..ced8cbd 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -5,16 +5,6 @@ #include <linux/compiler.h>
 
 #ifdef CONFIG_SMP
 
-#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)
-
 extern void setup_per_cpu_areas(void);
 
 extern unsigned long __per_cpu_base;
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index 5891ff7..5d66b85 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -6,6 +6,7 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/quicklist.h>
 
 #include <asm/spitfire.h>
 #include <asm/cpudata.h>
@@ -13,52 +14,50 @@ #include <asm/cacheflush.h>
 #include <asm/page.h>
 
 /* Page table allocation/freeing. */
-extern struct kmem_cache *pgtable_cache;
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
+	return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
 static inline void pgd_free(pgd_t *pgd)
 {
-	kmem_cache_free(pgtable_cache, pgd);
+	quicklist_free(0, NULL, pgd);
 }
 
 #define pud_populate(MM, PUD, PMD)	pud_set(PUD, PMD)
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	return kmem_cache_alloc(pgtable_cache,
-				GFP_KERNEL|__GFP_REPEAT);
+	return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
 static inline void pmd_free(pmd_t *pmd)
 {
-	kmem_cache_free(pgtable_cache, pmd);
+	quicklist_free(0, NULL, pmd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 					  unsigned long address)
 {
-	return kmem_cache_alloc(pgtable_cache,
-				GFP_KERNEL|__GFP_REPEAT);
+	return quicklist_alloc(0, GFP_KERNEL, NULL);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
 					 unsigned long address)
 {
-	return virt_to_page(pte_alloc_one_kernel(mm, address));
+	void *pg = quicklist_alloc(0, GFP_KERNEL, NULL);
+	return pg ? virt_to_page(pg) : NULL;
 }
 		
 static inline void pte_free_kernel(pte_t *pte)
 {
-	kmem_cache_free(pgtable_cache, pte);
+	quicklist_free(0, NULL, pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-	pte_free_kernel(page_address(ptepage));
+	quicklist_free_page(0, NULL, ptepage);
 }
 
 
@@ -66,6 +65,9 @@ #define pmd_populate_kernel(MM, PMD, PTE
 #define pmd_populate(MM,PMD,PTE_PAGE)		\
 	pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
 
-#define check_pgt_cache()	do { } while (0)
+static inline void check_pgt_cache(void)
+{
+	quicklist_trim(0, NULL, 25, 16);
+}
 
 #endif /* _SPARC64_PGALLOC_H */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index b12be7a..9e80ad4 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -15,13 +15,13 @@ #define _SPARC64_PGTABLE_H
 #include <asm-generic/pgtable-nopud.h>
 
 #include <linux/compiler.h>
+#include <linux/const.h>
 #include <asm/types.h>
 #include <asm/spitfire.h>
 #include <asm/asi.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/processor.h>
-#include <asm/const.h>
 
 /* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB).
  * The page copy blockops can use 0x2000000 to 0x4000000.
@@ -737,20 +737,6 @@ #define pte_to_pgoff(pte)	(pte_val(pte) 
 extern pte_t pgoff_to_pte(unsigned long);
 #define PTE_FILE_MAX_BITS	(64UL - PAGE_SHIFT - 1UL)
 
-extern unsigned long prom_virt_to_phys(unsigned long, int *);
-
-extern unsigned long sun4u_get_pte(unsigned long);
-
-static inline unsigned long __get_phys(unsigned long addr)
-{
-	return sun4u_get_pte(addr);
-}
-
-static inline int __get_iospace(unsigned long addr)
-{
-	return ((sun4u_get_pte(addr) & 0xf0000000) >> 28);
-}
-
 extern unsigned long *sparc64_valid_addr_bitmap;
 
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
@@ -791,6 +777,8 @@ extern void pgtable_cache_init(void);
 extern void sun4v_register_fault_status(void);
 extern void sun4v_ktsb_register(void);
 
+extern unsigned long cmdline_memory_size;
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index 0eca2d9..ddad5f9 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -36,8 +36,8 @@ struct property {
 
 struct of_irq_controller;
 struct device_node {
-	char	*name;
-	char	*type;
+	const char	*name;
+	const char	*type;
 	phandle	node;
 	char	*path_component_name;
 	char	*full_name;
@@ -93,11 +93,13 @@ extern struct device_node *of_find_node_
 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 int of_device_is_compatible(struct device_node *device, const char *);
-extern void *of_get_property(struct device_node *node, const char *name,
+extern int of_device_is_compatible(const struct device_node *device,
+				   const char *);
+extern const void *of_get_property(const struct device_node *node,
+			     const char *name,
 			     int *lenp);
 #define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
diff --git a/include/asm-sparc64/pstate.h b/include/asm-sparc64/pstate.h
index 49a7924..f3c4548 100644
--- a/include/asm-sparc64/pstate.h
+++ b/include/asm-sparc64/pstate.h
@@ -2,7 +2,7 @@
 #ifndef _SPARC64_PSTATE_H
 #define _SPARC64_PSTATE_H
 
-#include <asm/const.h>
+#include <linux/const.h>
 
 /* The V9 PSTATE Register (with SpitFire extensions).
  *
diff --git a/include/asm-sparc64/scatterlist.h b/include/asm-sparc64/scatterlist.h
index ec4f3c6..048fdb4 100644
--- a/include/asm-sparc64/scatterlist.h
+++ b/include/asm-sparc64/scatterlist.h
@@ -3,6 +3,7 @@ #ifndef _SPARC64_SCATTERLIST_H
 #define _SPARC64_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page	*page;
diff --git a/include/asm-sparc64/sfafsr.h b/include/asm-sparc64/sfafsr.h
index 2f792c2..e96137b 100644
--- a/include/asm-sparc64/sfafsr.h
+++ b/include/asm-sparc64/sfafsr.h
@@ -1,7 +1,7 @@
 #ifndef _SPARC64_SFAFSR_H
 #define _SPARC64_SFAFSR_H
 
-#include <asm/const.h>
+#include <linux/const.h>
 
 /* Spitfire Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */
 
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index 388249b..cca5480 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -42,15 +42,15 @@ extern int hard_smp_processor_id(void);
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 extern void smp_setup_cpu_possible_map(void);
+extern unsigned char boot_cpu_id;
 
 #endif /* !(__ASSEMBLY__) */
 
 #else
 
 #define smp_setup_cpu_possible_map() do { } while (0)
+#define boot_cpu_id	(0)
 
 #endif /* !(CONFIG_SMP) */
 
-#define NO_PROC_ID		0xFF
-
 #endif /* !(_SPARC64_SMP_H) */
diff --git a/include/asm-sparc64/socket.h b/include/asm-sparc64/socket.h
index 754d46a..986441d 100644
--- a/include/asm-sparc64/socket.h
+++ b/include/asm-sparc64/socket.h
@@ -49,6 +49,8 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 
 #define SO_PEERSEC		0x001e
 #define SO_PASSSEC		0x001f
+#define SO_TIMESTAMPNS		0x0021
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
diff --git a/include/asm-sparc64/sockios.h b/include/asm-sparc64/sockios.h
index 6735bab..c7d9900 100644
--- a/include/asm-sparc64/sockios.h
+++ b/include/asm-sparc64/sockios.h
@@ -7,7 +7,8 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* !(_ASM_SPARC64_SOCKIOS_H) */
 
diff --git a/include/asm-sparc64/sparsemem.h b/include/asm-sparc64/sparsemem.h
index ed5c9d8..77bcd2b 100644
--- a/include/asm-sparc64/sparsemem.h
+++ b/include/asm-sparc64/sparsemem.h
@@ -3,7 +3,7 @@ #define _SPARC64_SPARSEMEM_H
 
 #ifdef __KERNEL__
 
-#define SECTION_SIZE_BITS       26
+#define SECTION_SIZE_BITS       31
 #define MAX_PHYSADDR_BITS       42
 #define MAX_PHYSMEM_BITS        42
 
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 32281ac..8ba380e 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -253,7 +253,6 @@ static inline unsigned long xchg64(__vol
 }
 
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
 
 extern void __xchg_called_with_bad_pointer(void);
 
diff --git a/include/asm-sparc64/timer.h b/include/asm-sparc64/timer.h
index d435594..ccbd694 100644
--- a/include/asm-sparc64/timer.h
+++ b/include/asm-sparc64/timer.h
@@ -11,22 +11,19 @@ #include <linux/types.h>
 
 
 struct sparc64_tick_ops {
-	void (*init_tick)(unsigned long);
 	unsigned long (*get_tick)(void);
-	unsigned long (*get_compare)(void);
-	unsigned long (*add_tick)(unsigned long, unsigned long);
-	unsigned long (*add_compare)(unsigned long);
+	int (*add_compare)(unsigned long);
 	unsigned long softint_mask;
+	void (*disable_irq)(void);
+
+	void (*init_tick)(void);
+	unsigned long (*add_tick)(unsigned long);
+
+	char *name;
 };
 
 extern struct sparc64_tick_ops *tick_ops;
 
-#ifdef CONFIG_SMP
-extern unsigned long timer_tick_offset;
-struct pt_regs;
-extern void timer_tick_interrupt(struct pt_regs *);
-#endif
-
 extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
 
 #endif /* _SPARC64_TIMER_H */
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index c2a16e1..bbb9c8f 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -157,23 +157,6 @@ #define TRAP_IRQ(routine, level)			\
 	ba,a,pt	%xcc, rtrap_irq;			\
 	.previous;
 
-#define TICK_SMP_IRQ					\
-	rdpr	%pil, %g2;				\
-	wrpr	%g0, 15, %pil;				\
-	sethi	%hi(1f-4), %g7;				\
-	ba,pt	%xcc, etrap_irq;			\
-	 or	%g7, %lo(1f-4), %g7;			\
-	nop;						\
-	nop;						\
-	nop;						\
-	.subsection	2;				\
-1:	call	trace_hardirqs_off;			\
-	 nop;						\
-	call	smp_percpu_timer_interrupt;		\
-	 add	%sp, PTREGS_OFF, %o0;			\
-	ba,a,pt	%xcc, rtrap_irq;			\
-	.previous;
-
 #else
 
 #define TRAP_IRQ(routine, level)			\
@@ -186,16 +169,6 @@ #define TRAP_IRQ(routine, level)			\
 	 add	%sp, PTREGS_OFF, %o1;			\
 	ba,a,pt	%xcc, rtrap_irq;
 	
-#define TICK_SMP_IRQ					\
-	rdpr	%pil, %g2;				\
-	wrpr	%g0, 15, %pil;				\
-	sethi	%hi(109f), %g7;				\
-	ba,pt	%xcc, etrap_irq;			\
-109:	 or	%g7, %lo(109b), %g7;			\
-	call	smp_percpu_timer_interrupt;		\
-	 add	%sp, PTREGS_OFF, %o0;			\
-	ba,a,pt	%xcc, rtrap_irq;
-
 #endif
 
 #define TRAP_IVEC TRAP_NOSAVE(do_ivec)
diff --git a/include/asm-um/cmpxchg.h b/include/asm-um/cmpxchg.h
new file mode 100644
index 0000000..529376a
--- /dev/null
+++ b/include/asm-um/cmpxchg.h
@@ -0,0 +1,6 @@
+#ifndef __UM_CMPXCHG_H
+#define __UM_CMPXCHG_H
+
+#include "asm/arch/cmpxchg.h"
+
+#endif
diff --git a/include/asm-um/div64.h b/include/asm-um/div64.h
index 1e17f74..7b73b2c 100644
--- a/include/asm-um/div64.h
+++ b/include/asm-um/div64.h
@@ -3,4 +3,5 @@ #define _UM_DIV64_H
 
 #include "asm/arch/div64.h"
 
+extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
 #endif
diff --git a/include/asm-um/kdebug.h b/include/asm-um/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-um/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index f709c78..9aa4b44 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -6,6 +6,8 @@
 #ifndef __UM_MMU_CONTEXT_H
 #define __UM_MMU_CONTEXT_H
 
+#include <asm-generic/mm_hooks.h>
+
 #include "linux/sched.h"
 #include "choose-mode.h"
 #include "um_mmu.h"
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 4296d31..8e310d8 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -114,9 +114,6 @@ #define virt_addr_valid(v) pfn_valid(phy
 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);
-#define HAVE_ARCH_FREE_PAGE
-
 #include <asm-generic/memory_model.h>
 #include <asm-generic/page.h>
 
diff --git a/include/asm-um/tlbflush.h b/include/asm-um/tlbflush.h
index 522aa30..e78c28c 100644
--- a/include/asm-um/tlbflush.h
+++ b/include/asm-um/tlbflush.h
@@ -7,6 +7,7 @@ #ifndef __UM_TLBFLUSH_H
 #define __UM_TLBFLUSH_H
 
 #include <linux/mm.h>
+#include "choose-mode.h"
 
 /*
  * TLB flushing:
@@ -24,6 +25,18 @@ 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_skas(struct vm_area_struct *vma,
+				unsigned long address);
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long address)
+{
+	address &= PAGE_MASK;
+
+	CHOOSE_MODE(flush_tlb_range(vma, address, address + PAGE_SIZE),
+		    flush_tlb_page_skas(vma, address));
+}
+
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void flush_tlb_kernel_vm(void);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
@@ -35,14 +48,3 @@ static inline void flush_tlb_pgtables(st
 }
 
 #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/include/asm-v850/kdebug.h b/include/asm-v850/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-v850/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-v850/mmu_context.h b/include/asm-v850/mmu_context.h
index f521c80..01daacd 100644
--- a/include/asm-v850/mmu_context.h
+++ b/include/asm-v850/mmu_context.h
@@ -1,6 +1,8 @@
 #ifndef __V850_MMU_CONTEXT_H__
 #define __V850_MMU_CONTEXT_H__
 
+#include <asm-generic/mm_hooks.h>
+
 #define destroy_context(mm)		((void)0)
 #define init_new_context(tsk,mm)	0
 #define switch_mm(prev,next,tsk)	((void)0)
diff --git a/include/asm-v850/scatterlist.h b/include/asm-v850/scatterlist.h
index af1cba6..56f4029 100644
--- a/include/asm-v850/scatterlist.h
+++ b/include/asm-v850/scatterlist.h
@@ -14,6 +14,8 @@
 #ifndef __V850_SCATTERLIST_H__
 #define __V850_SCATTERLIST_H__
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page	*page;
 	unsigned	offset;
diff --git a/include/asm-v850/socket.h b/include/asm-v850/socket.h
index 0dfe55a..a4c2493 100644
--- a/include/asm-v850/socket.h
+++ b/include/asm-v850/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* __V850_SOCKET_H__ */
diff --git a/include/asm-v850/sockios.h b/include/asm-v850/sockios.h
index cf4874c..823e106 100644
--- a/include/asm-v850/sockios.h
+++ b/include/asm-v850/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif /* __V850_SOCKIOS_H__ */
diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h
index da39916..0de2481 100644
--- a/include/asm-v850/system.h
+++ b/include/asm-v850/system.h
@@ -76,7 +76,6 @@ #define smp_read_barrier_depends()	read_
 
 #define xchg(ptr, with) \
   ((__typeof__ (*(ptr)))__xchg ((unsigned long)(with), (ptr), sizeof (*(ptr))))
-#define tas(ptr) (xchg ((ptr), 1))
 
 static inline unsigned long __xchg (unsigned long with,
 				    __volatile__ void *ptr, int size)
diff --git a/include/asm-x86_64/Kbuild b/include/asm-x86_64/Kbuild
index ebd7117..75a2def 100644
--- a/include/asm-x86_64/Kbuild
+++ b/include/asm-x86_64/Kbuild
@@ -8,7 +8,7 @@ header-y += boot.h
 header-y += bootsetup.h
 header-y += debugreg.h
 header-y += ldt.h
-header-y += msr.h
+header-y += msr-index.h
 header-y += prctl.h
 header-y += ptrace-abi.h
 header-y += sigcontext32.h
@@ -16,5 +16,6 @@ header-y += ucontext.h
 header-y += vsyscall32.h
 
 unifdef-y += mce.h
+unifdef-y += msr.h
 unifdef-y += mtrr.h
 unifdef-y += vsyscall.h
diff --git a/include/asm-x86_64/agp.h b/include/asm-x86_64/agp.h
index 06c52ee..de33866 100644
--- a/include/asm-x86_64/agp.h
+++ b/include/asm-x86_64/agp.h
@@ -10,8 +10,10 @@ #include <asm/cacheflush.h>
  * with different cachability attributes for the same page.
  */
 
-int map_page_into_agp(struct page *page);
-int unmap_page_from_agp(struct page *page);
+/* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
+#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)
+#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
 #define flush_agp_mappings() global_flush_tlb()
 
 /* Could use CLFLUSH here if the cpu supports it. But then it would
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index a6657b4..a09fe85 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -16,6 +16,7 @@ struct alt_instr {
 	u8  pad[5];
 };
 
+extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
 
 struct module;
@@ -141,8 +142,8 @@ #else
 static inline void
 apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
 {}
-#define __start_parainstructions NULL
-#define __stop_parainstructions NULL
+#define __parainstructions NULL
+#define __parainstructions_end NULL
 #endif
 
 #endif /* _X86_64_ALTERNATIVE_H */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 7cfb39c..45e9fca 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -2,6 +2,7 @@ #ifndef __ASM_APIC_H
 #define __ASM_APIC_H
 
 #include <linux/pm.h>
+#include <linux/delay.h>
 #include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <asm/system.h>
@@ -47,11 +48,8 @@ static __inline unsigned int apic_read(u
 	return *((volatile unsigned int *)(APIC_BASE+reg));
 }
 
-static __inline__ void apic_wait_icr_idle(void)
-{
-	while (apic_read( APIC_ICR ) & APIC_ICR_BUSY)
-		cpu_relax();
-}
+extern void apic_wait_icr_idle(void);
+extern unsigned int safe_apic_wait_icr_idle(void);
 
 static inline void ack_APIC_irq(void)
 {
@@ -83,7 +81,7 @@ extern void setup_secondary_APIC_clock (
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
-extern void clustered_apic_check(void);
+extern void setup_apic_routing(void);
 
 extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
 				   unsigned char msg_type, unsigned char mask);
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index 706ca4b..f2e6463 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -2,6 +2,7 @@ #ifndef __ARCH_X86_64_ATOMIC__
 #define __ARCH_X86_64_ATOMIC__
 
 #include <asm/alternative.h>
+#include <asm/cmpxchg.h>
 
 /* atomic_t should be 32 bit signed type */
 
@@ -375,8 +376,8 @@ static __inline__ long atomic64_add_retu
 	long __i = i;
 	__asm__ __volatile__(
 		LOCK_PREFIX "xaddq %0, %1;"
-		:"=r"(i)
-		:"m"(v->counter), "0"(i));
+		:"+r" (i), "+m" (v->counter)
+		: : "memory");
 	return i + __i;
 }
 
@@ -388,7 +389,10 @@ static __inline__ long atomic64_sub_retu
 #define atomic64_inc_return(v)  (atomic64_add_return(1,v))
 #define atomic64_dec_return(v)  (atomic64_sub_return(1,v))
 
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 
 /**
@@ -400,22 +404,49 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	for (;;) {						\
-		if (unlikely(c == (u)))				\
-			break;					\
-		old = atomic_cmpxchg((v), c, c + (a));		\
-		if (likely(old == c))				\
-			break;					\
-		c = old;					\
-	}							\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+	long c, old;
+	c = atomic64_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic64_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
 /* These are x86-specific, used by some header files */
 #define atomic_clear_mask(mask, addr) \
 __asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \
diff --git a/include/asm-x86_64/bugs.h b/include/asm-x86_64/bugs.h
index d86c5dd..b33dc04 100644
--- a/include/asm-x86_64/bugs.h
+++ b/include/asm-x86_64/bugs.h
@@ -1,28 +1,6 @@
-/*
- *  include/asm-x86_64/bugs.h
- *
- *  Copyright (C) 1994  Linus Torvalds
- *  Copyright (C) 2000  SuSE
- *
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- *	void check_bugs(void);
- */
+#ifndef _ASM_X86_64_BUGS_H
+#define _ASM_X86_64_BUGS_H
 
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/pda.h>
+void check_bugs(void);
 
-extern void alternative_instructions(void);
-
-static void __init check_bugs(void)
-{
-	identify_cpu(&boot_cpu_data);
-#if !defined(CONFIG_SMP)
-	printk("CPU: ");
-	print_cpu_info(&boot_cpu_data);
-#endif
-	alternative_instructions(); 
-}
+#endif	/* _ASM_X86_64_BUGS_H */
diff --git a/include/asm-x86_64/cmpxchg.h b/include/asm-x86_64/cmpxchg.h
new file mode 100644
index 0000000..09a6b6b
--- /dev/null
+++ b/include/asm-x86_64/cmpxchg.h
@@ -0,0 +1,134 @@
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <asm/alternative.h> /* Provides LOCK_PREFIX */
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+#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;
+}
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+			unsigned long old, unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__("cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__("cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__("cmpxchgl %k1,%2"
+				     : "=a"(prev)
+				     : "r"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 8:
+		__asm__ __volatile__("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))))
+#define cmpxchg_local(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
+
+#endif
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 913d6ac..ac991b5 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -107,16 +107,6 @@ static inline void set_ldt_desc(unsigned
 			      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 
@@ -145,16 +135,13 @@ #define LDT_empty(info) (\
 	(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)
 {
+	unsigned int i;
 	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];
+
+	for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
+		gdt[i] = t->tls_array[i];
 } 
 
 /*
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index d2af227..6897e2a 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -52,7 +52,7 @@ struct dma_mapping_ops {
 };
 
 extern dma_addr_t bad_dma_address;
-extern struct dma_mapping_ops* dma_ops;
+extern const struct dma_mapping_ops* dma_ops;
 extern int iommu_merge;
 
 static inline int dma_mapping_error(dma_addr_t dma_addr)
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index 1b620db..e90e167 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -15,7 +15,6 @@ #include <linux/kernel.h>
 #include <asm/apicdef.h>
 #include <asm/page.h>
 #include <asm/vsyscall.h>
-#include <asm/vsyscall32.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h
index b80f4bb..d7e516c 100644
--- a/include/asm-x86_64/genapic.h
+++ b/include/asm-x86_64/genapic.h
@@ -29,7 +29,9 @@ struct genapic {
 	unsigned int (*phys_pkg_id)(int index_msb);
 };
 
+extern struct genapic *genapic;
 
-extern struct genapic *genapic, *genapic_force, apic_flat;
+extern struct genapic apic_flat;
+extern struct genapic apic_physflat;
 
 #endif
diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h
index 2a5c162..a7c75ea 100644
--- a/include/asm-x86_64/ipi.h
+++ b/include/asm-x86_64/ipi.h
@@ -18,10 +18,8 @@ #define __ASM_IPI_H
  * Subject to the GNU Public License, v.2
  */
 
-#include <asm/fixmap.h>
 #include <asm/hw_irq.h>
-#include <asm/apicdef.h>
-#include <asm/genapic.h>
+#include <asm/apic.h>
 
 /*
  * the following functions deal with sending IPIs between CPUs.
@@ -76,10 +74,42 @@ static inline void __send_IPI_shortcut(u
 	apic_write(APIC_ICR, cfg);
 }
 
+/*
+ * This is used to send an IPI with no shorthand notation (the destination is
+ * specified in bits 56 to 63 of the ICR).
+ */
+static inline void __send_IPI_dest_field(unsigned int mask, int vector, unsigned int dest)
+{
+	unsigned long cfg;
+
+	/*
+	 * Wait for idle.
+	 */
+	if (unlikely(vector == NMI_VECTOR))
+		safe_apic_wait_icr_idle();
+	else
+		apic_wait_icr_idle();
+
+	/*
+	 * prepare target chip field
+	 */
+	cfg = __prepare_ICR2(mask);
+	apic_write(APIC_ICR2, cfg);
+
+	/*
+	 * program the ICR
+	 */
+	cfg = __prepare_ICR(0, vector, dest);
+
+	/*
+	 * Send the IPI. The write to APIC_ICR fires this off.
+	 */
+	apic_write(APIC_ICR, cfg);
+}
 
 static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
 {
-	unsigned long cfg, flags;
+	unsigned long flags;
 	unsigned long query_cpu;
 
 	/*
@@ -88,28 +118,9 @@ static inline void send_IPI_mask_sequenc
 	 * - mbligh
 	 */
 	local_irq_save(flags);
-
 	for_each_cpu_mask(query_cpu, mask) {
-		/*
-		 * Wait for idle.
-		 */
-		apic_wait_icr_idle();
-
-		/*
-		 * prepare target chip field
-		 */
-		cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
-		apic_write(APIC_ICR2, cfg);
-
-		/*
-		 * program the ICR
-		 */
-		cfg = __prepare_ICR(0, vector, APIC_DEST_PHYSICAL);
-
-		/*
-		 * Send the IPI. The write to APIC_ICR fires this off.
-		 */
-		apic_write(APIC_ICR, cfg);
+		__send_IPI_dest_field(x86_cpu_to_apicid[query_cpu],
+				      vector, APIC_DEST_PHYSICAL);
 	}
 	local_irq_restore(flags);
 }
diff --git a/include/asm-x86_64/irqflags.h b/include/asm-x86_64/irqflags.h
index cce6937..86e70fe 100644
--- a/include/asm-x86_64/irqflags.h
+++ b/include/asm-x86_64/irqflags.h
@@ -9,6 +9,7 @@
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
+#include <asm/processor-flags.h>
 
 #ifndef __ASSEMBLY__
 /*
@@ -53,19 +54,19 @@ static inline void raw_local_irq_disable
 {
 	unsigned long flags = __raw_local_save_flags();
 
-	raw_local_irq_restore((flags & ~(1 << 9)) | (1 << 18));
+	raw_local_irq_restore((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC);
 }
 
 static inline void raw_local_irq_enable(void)
 {
 	unsigned long flags = __raw_local_save_flags();
 
-	raw_local_irq_restore((flags | (1 << 9)) & ~(1 << 18));
+	raw_local_irq_restore((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC));
 }
 
 static inline int raw_irqs_disabled_flags(unsigned long flags)
 {
-	return !(flags & (1<<9)) || (flags & (1 << 18));
+	return !(flags & X86_EFLAGS_IF) || (flags & X86_EFLAGS_AC);
 }
 
 #else /* CONFIG_X86_VSMP */
@@ -82,7 +83,7 @@ static inline void raw_local_irq_enable(
 
 static inline int raw_irqs_disabled_flags(unsigned long flags)
 {
-	return !(flags & (1 << 9));
+	return !(flags & X86_EFLAGS_IF);
 }
 
 #endif
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index 2b0c088..74feae9 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -5,19 +5,8 @@ #include <linux/notifier.h>
 
 struct pt_regs;
 
-struct die_args {
-	struct pt_regs *regs;
-	const char *str;
-	long err;
-	int trapnr;
-	int signr;
-};
-
-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 die_chain;
 
 /* Grossly misnamed. */
 enum die_val {
@@ -33,22 +22,10 @@ enum die_val {
 	DIE_GPF,
 	DIE_CALL,
 	DIE_NMI_IPI,
+	DIE_NMI_POST,
 	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(&die_chain, val, &args);
-} 
-
 extern void printk_address(unsigned long address);
 extern void die(const char *,struct pt_regs *,long);
 extern void __die(const char *,struct pt_regs *,long);
diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
index 5fab957..738e581 100644
--- a/include/asm-x86_64/kexec.h
+++ b/include/asm-x86_64/kexec.h
@@ -48,8 +48,6 @@ #define KEXEC_CONTROL_CODE_SIZE  (4096UL
 /* The native architecture */
 #define KEXEC_ARCH KEXEC_ARCH_X86_64
 
-#define MAX_NOTE_BYTES 1024
-
 /*
  * Saving the registers of the cpu on which panic occured in
  * crash_kexec to save a valid sp. The registers of other cpus
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
index e769e62..e87492b 100644
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -2,49 +2,183 @@ #ifndef _ARCH_X8664_LOCAL_H
 #define _ARCH_X8664_LOCAL_H
 
 #include <linux/percpu.h>
+#include <asm/atomic.h>
 
 typedef struct
 {
-	volatile long counter;
+	atomic_long_t a;
 } local_t;
 
-#define LOCAL_INIT(i)	{ (i) }
+#define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
 
-#define local_read(v)	((v)->counter)
-#define local_set(v,i)	(((v)->counter) = (i))
+#define local_read(l)	atomic_long_read(&(l)->a)
+#define local_set(l,i)	atomic_long_set(&(l)->a, (i))
 
-static inline void local_inc(local_t *v)
+static inline void local_inc(local_t *l)
 {
 	__asm__ __volatile__(
 		"incq %0"
-		:"=m" (v->counter)
-		:"m" (v->counter));
+		:"=m" (l->a.counter)
+		:"m" (l->a.counter));
 }
 
-static inline void local_dec(local_t *v)
+static inline void local_dec(local_t *l)
 {
 	__asm__ __volatile__(
 		"decq %0"
-		:"=m" (v->counter)
-		:"m" (v->counter));
+		:"=m" (l->a.counter)
+		:"m" (l->a.counter));
 }
 
-static inline void local_add(long i, local_t *v)
+static inline void local_add(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"addq %1,%0"
-		:"=m" (v->counter)
-		:"ir" (i), "m" (v->counter));
+		:"=m" (l->a.counter)
+		:"ir" (i), "m" (l->a.counter));
 }
 
-static inline void local_sub(long i, local_t *v)
+static inline void local_sub(long i, local_t *l)
 {
 	__asm__ __volatile__(
 		"subq %1,%0"
-		:"=m" (v->counter)
-		:"ir" (i), "m" (v->counter));
+		:"=m" (l->a.counter)
+		:"ir" (i), "m" (l->a.counter));
 }
 
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer to type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"subq %2,%0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"ir" (i), "m" (l->a.counter) : "memory");
+	return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer to type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int local_dec_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"decq %0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"m" (l->a.counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer to type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_inc_and_test(local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"incq %0; sete %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"m" (l->a.counter) : "memory");
+	return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+	unsigned char c;
+
+	__asm__ __volatile__(
+		"addq %2,%0; sets %1"
+		:"=m" (l->a.counter), "=qm" (c)
+		:"ir" (i), "m" (l->a.counter) : "memory");
+	return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+	long __i = i;
+	__asm__ __volatile__(
+		"xaddq %0, %1;"
+		:"+r" (i), "+m" (l->a.counter)
+		: : "memory");
+	return i + __i;
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+	return local_add_return(-i,l);
+}
+
+#define local_inc_return(l)  (local_add_return(1,l))
+#define local_dec_return(l)  (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+	(cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * atomic_up_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u)				\
+({								\
+	long c, old;						\
+	c = local_read(l);					\
+	for (;;) {						\
+		if (unlikely(c == (u)))				\
+			break;					\
+		old = local_cmpxchg((l), c, c + (a));	\
+		if (likely(old == c))				\
+			break;					\
+		c = old;					\
+	}							\
+	c != (u);						\
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
 /* On x86-64 these are better than the atomic variants on SMP kernels
    because they dont use a lock prefix. */
 #define __local_inc(l)		local_inc(l)
@@ -62,27 +196,27 @@ #define __local_sub(i,l)	local_sub((i),(
 
 /* Need to disable preemption for the cpu local counters otherwise we could
    still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v)	 	\
+#define cpu_local_wrap_v(l)	 	\
 	({ local_t res__;		\
 	   preempt_disable(); 		\
-	   res__ = (v);			\
+	   res__ = (l);			\
 	   preempt_enable();		\
 	   res__; })
-#define cpu_local_wrap(v)		\
+#define cpu_local_wrap(l)		\
 	({ preempt_disable();		\
-	   v;				\
+	   l;				\
 	   preempt_enable(); })		\
 
-#define cpu_local_read(v)    cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i)  cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v)     cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v)     cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v)  cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v)  cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
+#define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
 
-#define __cpu_local_inc(v)	cpu_local_inc(v)
-#define __cpu_local_dec(v)	cpu_local_dec(v)
-#define __cpu_local_add(i, v)	cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v)	cpu_local_sub((i), (v))
+#define __cpu_local_inc(l)	cpu_local_inc(l)
+#define __cpu_local_dec(l)	cpu_local_dec(l)
+#define __cpu_local_add(i, l)	cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
 
-#endif /* _ARCH_I386_LOCAL_H */
+#endif /* _ARCH_X8664_LOCAL_H */
diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
index af03b9f..0cce83a 100644
--- a/include/asm-x86_64/mmu_context.h
+++ b/include/asm-x86_64/mmu_context.h
@@ -7,6 +7,7 @@ #include <asm/pgalloc.h>
 #include <asm/pda.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
 
 /*
  * possibly do the LDT unload here?
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h
index fb558fb..19a8937 100644
--- a/include/asm-x86_64/mmzone.h
+++ b/include/asm-x86_64/mmzone.h
@@ -49,7 +49,7 @@ #endif
 
 #ifdef CONFIG_NUMA_EMU
 #define FAKE_NODE_MIN_SIZE	(64*1024*1024)
-#define FAKE_NODE_MIN_HASH_MASK	(~(FAKE_NODE_MIN_SIZE - 1ul))
+#define FAKE_NODE_MIN_HASH_MASK	(~(FAKE_NODE_MIN_SIZE - 1uL))
 #endif
 
 #endif
diff --git a/include/asm-x86_64/msr-index.h b/include/asm-x86_64/msr-index.h
new file mode 100644
index 0000000..d77a63f
--- /dev/null
+++ b/include/asm-x86_64/msr-index.h
@@ -0,0 +1 @@
+#include <asm-i386/msr-index.h>
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 902f9a5..d5c55b8 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -1,7 +1,10 @@
 #ifndef X86_64_MSR_H
 #define X86_64_MSR_H 1
 
+#include <asm/msr-index.h>
+
 #ifndef __ASSEMBLY__
+#include <linux/errno.h>
 /*
  * Access to machine-specific registers (available on 586 and better only)
  * Note: the rd* operations modify the parameters directly (without using
@@ -157,12 +160,11 @@ static inline unsigned int cpuid_edx(uns
 	return edx;
 }
 
-#define MSR_IA32_UCODE_WRITE		0x79
-#define MSR_IA32_UCODE_REV		0x8b
-
 #ifdef CONFIG_SMP
 void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 #else  /*  CONFIG_SMP  */
 static inline void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
 {
@@ -172,269 +174,14 @@ static inline void wrmsr_on_cpu(unsigned
 {
 	wrmsr(msr_no, l, h);
 }
-#endif  /*  CONFIG_SMP  */
-
-#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 FS base */
-#define MSR_GS_BASE 0xc0000101		/* 64bit GS 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_FSB_FREQ		0xcd
-
-#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_IA32_PEBS_ENABLE		0x3f1
-#define MSR_IA32_DS_AREA		0x600
-#define MSR_IA32_PERF_CAPABILITIES	0x345
-
-#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_MPERF			0xE7
-#define MSR_IA32_APERF			0xE8
-
-#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
-
-/* Intel Core-based CPU performance counters */
-#define MSR_CORE_PERF_FIXED_CTR0	0x309
-#define MSR_CORE_PERF_FIXED_CTR1	0x30a
-#define MSR_CORE_PERF_FIXED_CTR2	0x30b
-#define MSR_CORE_PERF_FIXED_CTR_CTRL	0x38d
-#define MSR_CORE_PERF_GLOBAL_STATUS	0x38e
-#define MSR_CORE_PERF_GLOBAL_CTRL	0x38f
-#define MSR_CORE_PERF_GLOBAL_OVF_CTRL	0x390
-
-#endif
+static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+	return rdmsr_safe(msr_no, l, h);
+}
+static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+	return wrmsr_safe(msr_no, l, h);
+}
+#endif  /* CONFIG_SMP */
+#endif /* __ASSEMBLY__ */
+#endif	/* X86_64_MSR_H */
diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86_64/mtrr.h
index d6135b2..b557c48 100644
--- a/include/asm-x86_64/mtrr.h
+++ b/include/asm-x86_64/mtrr.h
@@ -135,6 +135,18 @@ #define MTRRIOC32_KILL_PAGE_ENTRY  _IOW(
 
 #endif /* CONFIG_COMPAT */
 
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+extern void mtrr_save_fixed_ranges(void *);
+extern void mtrr_save_state(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#define mtrr_save_fixed_ranges(arg) do {} while (0)
+#define mtrr_save_state() do {} while (0)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif  /*  _LINUX_MTRR_H  */
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index 72375e7..d0a7f53 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -80,4 +80,13 @@ extern int unknown_nmi_panic;
 void __trigger_all_cpu_backtrace(void);
 #define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
 
+
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+int lapic_watchdog_ok(void);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
+
 #endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 10f3461..dee632f 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -1,14 +1,11 @@
 #ifndef _X86_64_PAGE_H
 #define _X86_64_PAGE_H
 
+#include <linux/const.h>
 
 /* 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_SIZE	(_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PHYSICAL_PAGE_MASK	(~(PAGE_SIZE-1) & __PHYSICAL_MASK)
 
@@ -33,10 +30,10 @@ #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 LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)
 
 #define HPAGE_SHIFT PMD_SHIFT
-#define HPAGE_SIZE	((1UL) << HPAGE_SHIFT)
+#define HPAGE_SIZE	(_AC(1,UL) << HPAGE_SHIFT)
 #define HPAGE_MASK	(~(HPAGE_SIZE - 1))
 #define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
 
@@ -64,6 +61,8 @@ #define PTE_MASK	PHYSICAL_PAGE_MASK
 
 typedef struct { unsigned long pgprot; } pgprot_t;
 
+extern unsigned long phys_base;
+
 #define pte_val(x)	((x).pte)
 #define pmd_val(x)	((x).pmd)
 #define pud_val(x)	((x).pud)
@@ -76,47 +75,38 @@ #define __pud(x) ((pud_t) { (x) } )
 #define __pgd(x) ((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           0xffff810000000000UL
+#endif /* !__ASSEMBLY__ */
 
-#else
 #define __PHYSICAL_START	CONFIG_PHYSICAL_START
+#define __KERNEL_ALIGN		0x200000
+
 #define __START_KERNEL		(__START_KERNEL_map + __PHYSICAL_START)
-#define __START_KERNEL_map	0xffffffff80000000
-#define __PAGE_OFFSET           0xffff810000000000
-#endif /* !__ASSEMBLY__ */
+#define __START_KERNEL_map	_AC(0xffffffff80000000, UL)
+#define __PAGE_OFFSET           _AC(0xffff810000000000, UL)
 
 /* 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 __PHYSICAL_MASK		((_AC(1,UL) << __PHYSICAL_MASK_SHIFT) - 1)
 #define __VIRTUAL_MASK_SHIFT	48
-#define __VIRTUAL_MASK		((1UL << __VIRTUAL_MASK_SHIFT) - 1)
+#define __VIRTUAL_MASK		((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1)
 
-#define KERNEL_TEXT_SIZE  (40UL*1024*1024)
-#define KERNEL_TEXT_START 0xffffffff80000000UL 
+#define KERNEL_TEXT_SIZE  (40*1024*1024)
+#define KERNEL_TEXT_START _AC(0xffffffff80000000, UL)
+#define PAGE_OFFSET		__PAGE_OFFSET
 
 #ifndef __ASSEMBLY__
 
 #include <asm/bug.h>
 
+extern unsigned long __phys_addr(unsigned long);
+
 #endif /* __ASSEMBLY__ */
 
-#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 __pa(x)		__phys_addr((unsigned long)(x))
+#define __pa_symbol(x)	__phys_addr((unsigned long)(x))
 
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define __boot_va(x)		__va(x)
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index 5ed0ef3..c6fbb67 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -11,16 +11,6 @@ #ifdef CONFIG_SMP
 
 #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)
 
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
index 4e28b60..8bb5646 100644
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -1,7 +1,6 @@
 #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>
@@ -45,24 +44,16 @@ static inline void pgd_list_add(pgd_t *p
 	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;
+	list_add(&page->lru, &pgd_list);
 	spin_unlock(&pgd_lock);
 }
 
 static inline void pgd_list_del(pgd_t *pgd)
 {
-	struct page *next, **pprev, *page = virt_to_page(pgd);
+	struct page *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;
+	list_del(&page->lru);
 	spin_unlock(&pgd_lock);
 }
 
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 730bd60..08b9831 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -1,22 +1,22 @@
 #ifndef _X86_64_PGTABLE_H
 #define _X86_64_PGTABLE_H
 
+#include <linux/const.h>
+#ifndef __ASSEMBLY__
+
 /*
  * 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 <asm/pda.h>
 
 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
@@ -31,6 +31,8 @@ extern void clear_kernel_mapping(unsigne
 extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
+#endif /* !__ASSEMBLY__ */
+
 /*
  * PGDIR_SHIFT determines what a top-level page table entry can map
  */
@@ -55,6 +57,8 @@ #define PTRS_PER_PMD	512
  */
 #define PTRS_PER_PTE	512
 
+#ifndef __ASSEMBLY__
+
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
 #define pmd_ERROR(e) \
@@ -118,22 +122,23 @@ #define pte_same(a, b)		((a).pte == (b).
 
 #define pte_pgprot(a)	(__pgprot((a).pte & ~PHYSICAL_PAGE_MASK))
 
-#define PMD_SIZE	(1UL << PMD_SHIFT)
+#endif /* !__ASSEMBLY__ */
+
+#define PMD_SIZE	(_AC(1,UL) << PMD_SHIFT)
 #define PMD_MASK	(~(PMD_SIZE-1))
-#define PUD_SIZE	(1UL << PUD_SHIFT)
+#define PUD_SIZE	(_AC(1,UL) << PUD_SHIFT)
 #define PUD_MASK	(~(PUD_SIZE-1))
-#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_SIZE	(_AC(1,UL) << 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 MAXMEM		 _AC(0x3fffffffffff, UL)
+#define VMALLOC_START    _AC(0xffffc20000000000, UL)
+#define VMALLOC_END      _AC(0xffffe1ffffffffff, UL)
+#define MODULES_VADDR    _AC(0xffffffff88000000, UL)
+#define MODULES_END      _AC(0xfffffffffff00000, UL)
 #define MODULES_LEN   (MODULES_END - MODULES_VADDR)
 
 #define _PAGE_BIT_PRESENT	0
@@ -159,7 +164,7 @@ #define _PAGE_FILE	0x040	/* nonlinear fi
 #define _PAGE_GLOBAL	0x100	/* Global TLB entry */
 
 #define _PAGE_PROTNONE	0x080	/* If not present */
-#define _PAGE_NX        (1UL<<_PAGE_BIT_NX)
+#define _PAGE_NX        (_AC(1,UL)<<_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)
@@ -221,6 +226,8 @@ #define __S101	PAGE_READONLY_EXEC
 #define __S110	PAGE_SHARED_EXEC
 #define __S111	PAGE_SHARED_EXEC
 
+#ifndef __ASSEMBLY__
+
 static inline unsigned long pgd_bad(pgd_t pgd)
 {
 	return pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
@@ -403,20 +410,13 @@ #define __pte_to_swp_entry(pte)		((swp_e
 #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 struct list_head pgd_list;
 
 extern int kern_addr_valid(unsigned long addr); 
 
 #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)
-
 #define HAVE_ARCH_UNMAPPED_AREA
 
 #define pgtable_cache_init()   do { } while (0)
@@ -437,5 +437,6 @@ #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_F
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
 #define __HAVE_ARCH_PTE_SAME
 #include <asm-generic/pgtable.h>
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _X86_64_PGTABLE_H */
diff --git a/include/asm-x86_64/processor-flags.h b/include/asm-x86_64/processor-flags.h
new file mode 100644
index 0000000..ec99a57
--- /dev/null
+++ b/include/asm-x86_64/processor-flags.h
@@ -0,0 +1 @@
+#include <asm-i386/processor-flags.h>
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 76552d7..461ffe4 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -20,6 +20,7 @@ #include <asm/mmsegment.h>
 #include <asm/percpu.h>
 #include <linux/personality.h>
 #include <linux/cpumask.h>
+#include <asm/processor-flags.h>
 
 #define TF_MASK		0x00000100
 #define IF_MASK		0x00000200
@@ -103,42 +104,6 @@ extern unsigned int init_intel_cacheinfo
 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
@@ -201,7 +166,7 @@ struct i387_fxsave_struct {
 	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	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 256 bytes */
 	u32	padding[24];
 } __attribute__ ((aligned (16)));
 
@@ -427,22 +392,6 @@ #define spin_lock_prefetch(x)  prefetchw
 #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
  */
 
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index b6e65a6..85255db 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -11,18 +11,9 @@ struct pt_regs;
 extern void start_kernel(void);
 extern void pda_init(int); 
 
-extern void zap_low_mappings(int cpu);
-
 extern void early_idt_handler(void);
 
 extern void mcheck_init(struct cpuinfo_x86 *c);
-#ifdef CONFIG_MTRR
-extern void mtrr_ap_init(void);
-extern void mtrr_bp_init(void);
-#else
-#define mtrr_ap_init() do {} while (0)
-#define mtrr_bp_init() do {} while (0)
-#endif
 extern void init_memory_mapping(unsigned long start, unsigned long end);
 
 extern void system_call(void); 
@@ -82,7 +73,6 @@ extern void syscall32_cpu_init(void);
 extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
 
 extern void early_quirks(void);
-extern void quirk_intel_irqbalance(void);
 extern void check_efer(void);
 
 extern int unhandled_signal(struct task_struct *tsk, int sig);
@@ -93,6 +83,7 @@ extern unsigned long table_start, table_
 
 extern int exception_trace;
 extern unsigned cpu_khz;
+extern unsigned tsc_khz;
 
 extern void no_iommu_init(void);
 extern int force_iommu, no_iommu;
@@ -121,8 +112,12 @@ extern int gsi_irq_sharing(int gsi);
 
 extern void smp_local_timer_interrupt(void);
 
+extern int force_mwait;
+
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
+void i8254_timer_resume(void);
+
 #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
 #define round_down(x,y) ((x) & ~((y)-1))
 
diff --git a/include/asm-x86_64/scatterlist.h b/include/asm-x86_64/scatterlist.h
index 49d89f8..eaf7ada 100644
--- a/include/asm-x86_64/scatterlist.h
+++ b/include/asm-x86_64/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _X8664_SCATTERLIST_H
 #define _X8664_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
index 334ddcd..adf2bf1 100644
--- a/include/asm-x86_64/segment.h
+++ b/include/asm-x86_64/segment.h
@@ -6,7 +6,7 @@ #include <asm/cache.h>
 #define __KERNEL_CS	0x10
 #define __KERNEL_DS	0x18
 
-#define __KERNEL32_CS   0x38
+#define __KERNEL32_CS   0x08
 
 /* 
  * we cannot use the same code segment descriptor for user and kernel
diff --git a/include/asm-x86_64/serial.h b/include/asm-x86_64/serial.h
index b0496e0..8ebd765 100644
--- a/include/asm-x86_64/serial.h
+++ b/include/asm-x86_64/serial.h
@@ -11,19 +11,3 @@
  * megabits/second; but this requires the faster clock.
  */
 #define BASE_BAUD ( 1843200 / 16 )
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#define SERIAL_PORT_DFNS			\
-	/* 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 */
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index de592a4..d570442 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -10,10 +10,9 @@ #include <linux/bitops.h>
 #include <linux/init.h>
 extern int disable_apic;
 
-#include <asm/fixmap.h>
 #include <asm/mpspec.h>
-#include <asm/io_apic.h>
 #include <asm/apic.h>
+#include <asm/io_apic.h>
 #include <asm/thread_info.h>
 
 #ifdef CONFIG_SMP
@@ -38,7 +37,6 @@ 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 cpumask_t cpu_sibling_map[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
diff --git a/include/asm-x86_64/socket.h b/include/asm-x86_64/socket.h
index b467026..90af60c 100644
--- a/include/asm-x86_64/socket.h
+++ b/include/asm-x86_64/socket.h
@@ -49,5 +49,7 @@ #define SO_ACCEPTCONN		30
 
 #define SO_PEERSEC             31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-x86_64/sockios.h b/include/asm-x86_64/sockios.h
index 2eefd10..d726ba2 100644
--- a/include/asm-x86_64/sockios.h
+++ b/include/asm-x86_64/sockios.h
@@ -7,6 +7,7 @@ #define SIOCSPGRP	0x8902
 #define FIOGETOWN	0x8903
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
index bc7f817..9c3f8de 100644
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -17,6 +17,7 @@ struct saved_context {
   	u16 ds, es, fs, gs, ss;
 	unsigned long gs_base, gs_kernel_base, fs_base;
 	unsigned long cr0, cr2, cr3, cr4, cr8;
+	unsigned long efer;
 	u16 gdt_pad;
 	u16 gdt_limit;
 	unsigned long gdt_base;
@@ -44,12 +45,12 @@ #define loaddebug(thread,register) \
 extern void fix_processor_context(void);
 
 #ifdef CONFIG_ACPI_SLEEP
-extern unsigned long saved_eip;
-extern unsigned long saved_esp;
-extern unsigned long saved_ebp;
-extern unsigned long saved_ebx;
-extern unsigned long saved_esi;
-extern unsigned long saved_edi;
+extern unsigned long saved_rip;
+extern unsigned long saved_rsp;
+extern unsigned long saved_rbp;
+extern unsigned long saved_rbx;
+extern unsigned long saved_rsi;
+extern unsigned long saved_rdi;
 
 /* routines for saving/restoring kernel state */
 extern int acpi_save_state_mem(void);
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index bd376bc..b7b8021 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -3,7 +3,7 @@ #define __ASM_SYSTEM_H
 
 #include <linux/kernel.h>
 #include <asm/segment.h>
-#include <asm/alternative.h>
+#include <asm/cmpxchg.h>
 
 #ifdef __KERNEL__
 
@@ -89,6 +89,11 @@ static inline unsigned long read_cr3(voi
 	return cr3;
 } 
 
+static inline void write_cr3(unsigned long val)
+{
+	asm volatile("movq %0,%%cr3" :: "r" (val) : "memory");
+}
+
 static inline unsigned long read_cr4(void)
 { 
 	unsigned long cr4;
@@ -98,7 +103,7 @@ static inline unsigned long read_cr4(voi
 
 static inline void write_cr4(unsigned long val)
 { 
-	asm volatile("movq %0,%%cr4" :: "r" (val));
+	asm volatile("movq %0,%%cr4" :: "r" (val) : "memory");
 } 
 
 #define stts() write_cr0(8 | read_cr0())
@@ -119,100 +124,6 @@ #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()
diff --git a/include/asm-x86_64/termbits.h b/include/asm-x86_64/termbits.h
index 6cfc3bb..7405756 100644
--- a/include/asm-x86_64/termbits.h
+++ b/include/asm-x86_64/termbits.h
@@ -160,7 +160,7 @@ #define CIBAUD	  002003600000	/* input b
 #define CMSPAR	  010000000000		/* mark or space (stick) parity */
 #define CRTSCTS	  020000000000		/* flow control */
 
-#define IBSHIFT	  8		/* Shift from CBAUD to CIBAUD */
+#define IBSHIFT	  16		/* Shift from CBAUD to CIBAUD */
 
 /* c_lflag bits */
 #define ISIG	0000001
diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
index 8c6808a..f6527e1 100644
--- a/include/asm-x86_64/timex.h
+++ b/include/asm-x86_64/timex.h
@@ -27,6 +27,6 @@ #define FSEC_PER_TICK (FSEC_PER_SEC / HZ
 #define NS_SCALE        10 /* 2^10, carefully chosen */
 #define US_SCALE        32 /* 2^32, arbitralrily chosen */
 
-extern void mark_tsc_unstable(void);
+extern void mark_tsc_unstable(char *msg);
 extern void set_cyc2ns_scale(unsigned long khz);
 #endif
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 983bd29..512401b 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -3,41 +3,18 @@ #define _X8664_TLBFLUSH_H
 
 #include <linux/mm.h>
 #include <asm/processor.h>
-
-static inline unsigned long get_cr3(void)
-{
-	unsigned long cr3;
-	asm volatile("mov %%cr3,%0" : "=r" (cr3));
-	return cr3;
-}
-
-static inline void set_cr3(unsigned long cr3)
-{
-	asm volatile("mov %0,%%cr3" :: "r" (cr3) : "memory");
-}
+#include <asm/system.h>
 
 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");
+	write_cr3(read_cr3());
 }
 
 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 */
+	unsigned long cr4 = read_cr4();
+	write_cr4(cr4 & ~X86_CR4_PGE);	/* clear PGE */
+	write_cr4(cr4);			/* write old PGE again and flush TLBs */
 }
 
 #define __flush_tlb_one(addr) \
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index c5f596e..5957039 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -619,8 +619,8 @@ #define __NR_vmsplice		278
 __SYSCALL(__NR_vmsplice, sys_vmsplice)
 #define __NR_move_pages		279
 __SYSCALL(__NR_move_pages, sys_move_pages)
-
-#define __NR_syscall_max __NR_move_pages
+#define __NR_utimensat		280
+__SYSCALL(__NR_utimensat, sys_utimensat)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
@@ -655,7 +655,6 @@ #include <linux/types.h>
 #include <asm/ptrace.h>
 
 asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
index 5c26720..b3b2354 100644
--- a/include/asm-xtensa/atomic.h
+++ b/include/asm-xtensa/atomic.h
@@ -234,14 +234,21 @@ #define atomic_xchg(v, new) (xchg(&((v)-
  * Atomically adds @a to @v, so long as it was not @u.
  * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_add_unless(v, a, u)				\
-({								\
-	int c, old;						\
-	c = atomic_read(v);					\
-	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
-		c = old;					\
-	c != (u);						\
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
diff --git a/include/asm-xtensa/div64.h b/include/asm-xtensa/div64.h
index c4a1057..20965e3 100644
--- a/include/asm-xtensa/div64.h
+++ b/include/asm-xtensa/div64.h
@@ -11,9 +11,15 @@
 #ifndef _XTENSA_DIV64_H
 #define _XTENSA_DIV64_H
 
+#include <linux/types.h>
+
 #define do_div(n,base) ({ \
 	int __res = n % ((unsigned int) base); \
 	n /= (unsigned int) base; \
 	__res; })
 
+static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+{
+	return dividend / divisor;
+}
 #endif
diff --git a/include/asm-xtensa/kdebug.h b/include/asm-xtensa/kdebug.h
new file mode 100644
index 0000000..6ece1b0
--- /dev/null
+++ b/include/asm-xtensa/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
index f14851f..92f9483 100644
--- a/include/asm-xtensa/mmu_context.h
+++ b/include/asm-xtensa/mmu_context.h
@@ -18,6 +18,7 @@ #include <linux/stringify.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
 
 #define XCHAL_MMU_ASID_BITS	8
 
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h
index 38a2b9a..ca337a2 100644
--- a/include/asm-xtensa/scatterlist.h
+++ b/include/asm-xtensa/scatterlist.h
@@ -11,6 +11,8 @@
 #ifndef _XTENSA_SCATTERLIST_H
 #define _XTENSA_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page 	*page;
 	unsigned int	offset;
diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h
index 971d231..1f5aeac 100644
--- a/include/asm-xtensa/socket.h
+++ b/include/asm-xtensa/socket.h
@@ -60,5 +60,7 @@ #define SCM_TIMESTAMP		SO_TIMESTAMP
 #define SO_ACCEPTCONN		30
 #define SO_PEERSEC		31
 #define SO_PASSSEC		34
+#define SO_TIMESTAMPNS		35
+#define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #endif	/* _XTENSA_SOCKET_H */
diff --git a/include/asm-xtensa/sockios.h b/include/asm-xtensa/sockios.h
index 20d2ba1..efe0af3 100644
--- a/include/asm-xtensa/sockios.h
+++ b/include/asm-xtensa/sockios.h
@@ -25,6 +25,7 @@ #define SIOCATMARK	_IOR('s', 7, int)
 #define SIOCSPGRP	_IOW('s', 8, pid_t)
 #define SIOCGPGRP	_IOR('s', 9, pid_t)
 
-#define SIOCGSTAMP	0x8906		/* Get stamp - linux-specific */
+#define SIOCGSTAMP	0x8906		/* Get stamp (timeval) */
+#define SIOCGSTAMPNS	0x8907		/* Get stamp (timespec) */
 
 #endif	/* _XTENSA_SOCKIOS_H */
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index 4aaed7f..ddc9708 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -183,8 +183,6 @@ static inline unsigned long xchg_u32(vol
   return tmp;
 }
 
-#define tas(ptr) (xchg((ptr),1))
-
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 /*
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 4e05e93..b2b1e6e 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -13,8 +13,11 @@ #ifndef _CRYPTO_ALGAPI_H
 #define _CRYPTO_ALGAPI_H
 
 #include <linux/crypto.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
 
 struct module;
+struct rtattr;
 struct seq_file;
 
 struct crypto_type {
@@ -38,7 +41,7 @@ struct crypto_template {
 	struct hlist_head instances;
 	struct module *module;
 
-	struct crypto_instance *(*alloc)(void *param, unsigned int len);
+	struct crypto_instance *(*alloc)(struct rtattr **tb);
 	void (*free)(struct crypto_instance *inst);
 
 	char name[CRYPTO_MAX_ALG_NAME];
@@ -48,6 +51,15 @@ struct crypto_spawn {
 	struct list_head list;
 	struct crypto_alg *alg;
 	struct crypto_instance *inst;
+	u32 mask;
+};
+
+struct crypto_queue {
+	struct list_head list;
+	struct list_head *backlog;
+
+	unsigned int qlen;
+	unsigned int max_qlen;
 };
 
 struct scatter_walk {
@@ -81,6 +93,7 @@ struct blkcipher_walk {
 	int flags;
 };
 
+extern const struct crypto_type crypto_ablkcipher_type;
 extern const struct crypto_type crypto_blkcipher_type;
 extern const struct crypto_type crypto_hash_type;
 
@@ -91,16 +104,23 @@ void crypto_unregister_template(struct c
 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);
+		      struct crypto_instance *inst, u32 mask);
 void crypto_drop_spawn(struct crypto_spawn *spawn);
 struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
 				    u32 mask);
 
-struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
-				       u32 type, u32 mask);
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
+int crypto_check_attr_type(struct rtattr **tb, u32 type);
+struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask);
 struct crypto_instance *crypto_alloc_instance(const char *name,
 					      struct crypto_alg *alg);
 
+void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen);
+int crypto_enqueue_request(struct crypto_queue *queue,
+			   struct crypto_async_request *request);
+struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
+int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
+
 int blkcipher_walk_done(struct blkcipher_desc *desc,
 			struct blkcipher_walk *walk, int err);
 int blkcipher_walk_virt(struct blkcipher_desc *desc,
@@ -118,11 +138,37 @@ static inline void *crypto_tfm_ctx_align
 	return (void *)ALIGN(addr, align);
 }
 
+static inline struct crypto_instance *crypto_tfm_alg_instance(
+	struct crypto_tfm *tfm)
+{
+	return container_of(tfm->__crt_alg, struct crypto_instance, alg);
+}
+
 static inline void *crypto_instance_ctx(struct crypto_instance *inst)
 {
 	return inst->__ctx;
 }
 
+static inline struct ablkcipher_alg *crypto_ablkcipher_alg(
+	struct crypto_ablkcipher *tfm)
+{
+	return &crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_ablkcipher;
+}
+
+static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm)
+{
+	return crypto_tfm_ctx(&tfm->base);
+}
+
+static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
+	struct crypto_spawn *spawn)
+{
+	u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
+	u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+
+	return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
 static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm)
 {
 	return crypto_tfm_ctx(&tfm->base);
@@ -170,5 +216,35 @@ static inline void blkcipher_walk_init(s
 	walk->total = nbytes;
 }
 
+static inline struct crypto_async_request *crypto_get_backlog(
+	struct crypto_queue *queue)
+{
+	return queue->backlog == &queue->list ? NULL :
+	       container_of(queue->backlog, struct crypto_async_request, list);
+}
+
+static inline int ablkcipher_enqueue_request(struct ablkcipher_alg *alg,
+					     struct ablkcipher_request *request)
+{
+	return crypto_enqueue_request(alg->queue, &request->base);
+}
+
+static inline struct ablkcipher_request *ablkcipher_dequeue_request(
+	struct ablkcipher_alg *alg)
+{
+	return ablkcipher_request_cast(crypto_dequeue_request(alg->queue));
+}
+
+static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req)
+{
+	return req->__ctx;
+}
+
+static inline int ablkcipher_tfm_in_queue(struct crypto_ablkcipher *tfm)
+{
+	return crypto_tfm_in_queue(crypto_ablkcipher_alg(tfm)->queue,
+				   crypto_ablkcipher_tfm(tfm));
+}
+
 #endif	/* _CRYPTO_ALGAPI_H */
 
diff --git a/include/keys/rxrpc-type.h b/include/keys/rxrpc-type.h
new file mode 100644
index 0000000..e2ee73a
--- /dev/null
+++ b/include/keys/rxrpc-type.h
@@ -0,0 +1,22 @@
+/* RxRPC key type
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _KEYS_RXRPC_TYPE_H
+#define _KEYS_RXRPC_TYPE_H
+
+#include <linux/key.h>
+
+/*
+ * key type for AF_RXRPC keys
+ */
+extern struct key_type key_type_rxrpc;
+
+#endif /* _KEYS_USER_TYPE_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index e81e301..94cc04a 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -4,6 +4,7 @@ header-y += hdlc/
 header-y += isdn/
 header-y += nfsd/
 header-y += raid/
+header-y += spi/
 header-y += sunrpc/
 header-y += tc_act/
 header-y += netfilter/
@@ -33,7 +34,6 @@ 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
@@ -46,6 +46,7 @@ header-y += coda_psdev.h
 header-y += coff.h
 header-y += comstats.h
 header-y += consolemap.h
+header-y += const.h
 header-y += cycx_cfm.h
 header-y += dlm_device.h
 header-y += dm-ioctl.h
@@ -69,9 +70,7 @@ 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_arcnet.h
-header-y += if_arp.h
 header-y += if_bonding.h
 header-y += if_cablemodem.h
 header-y += if_fc.h
@@ -88,17 +87,16 @@ 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 += kvm.h
 header-y += limits.h
 header-y += lock_dlm_plock.h
 header-y += magic.h
@@ -116,12 +114,14 @@ header-y += netrom.h
 header-y += nfs2.h
 header-y += nfs4_mount.h
 header-y += nfs_mount.h
+header-y += nl80211.h
 header-y += oom.h
 header-y += param.h
 header-y += pci_regs.h
 header-y += personality.h
 header-y += pfkeyv2.h
 header-y += pg.h
+header-y += phantom.h
 header-y += pkt_cls.h
 header-y += pkt_sched.h
 header-y += posix_types.h
@@ -141,6 +141,7 @@ header-y += sockios.h
 header-y += som.h
 header-y += sound.h
 header-y += synclink.h
+header-y += taskstats.h
 header-y += telephony.h
 header-y += termios.h
 header-y += ticable.h
@@ -210,8 +211,10 @@ unifdef-y += hiddev.h
 unifdef-y += hpet.h
 unifdef-y += i2c.h
 unifdef-y += i2o-dev.h
+unifdef-y += icmp.h
 unifdef-y += icmpv6.h
 unifdef-y += if_addr.h
+unifdef-y += if_arp.h
 unifdef-y += if_bridge.h
 unifdef-y += if_ec.h
 unifdef-y += if_eql.h
@@ -231,12 +234,14 @@ unifdef-y += inet_diag.h
 unifdef-y += in.h
 unifdef-y += inotify.h
 unifdef-y += input.h
+unifdef-y += ip.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_divertif.h
 unifdef-y += isdn_ppp.h
 unifdef-y += isicom.h
 unifdef-y += jbd.h
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 6caeb98..edb31bf 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -159,11 +159,19 @@ enum {
 	ATA_CMD_INIT_DEV_PARAMS	= 0x91,
 	ATA_CMD_READ_NATIVE_MAX	= 0xF8,
 	ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+	ATA_CMD_SET_MAX		= 0xF9,
+	ATA_CMD_SET_MAX_EXT	= 0x37,
 	ATA_CMD_READ_LOG_EXT	= 0x2f,
 
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
 
+	/* READ/WRITE LONG (obsolete) */
+	ATA_CMD_READ_LONG	= 0x22,
+	ATA_CMD_READ_LONG_ONCE	= 0x23,
+	ATA_CMD_WRITE_LONG	= 0x32,
+	ATA_CMD_WRITE_LONG_ONCE	= 0x33,
+
 	/* SETFEATURES stuff */
 	SETFEATURES_XFER	= 0x03,
 	XFER_UDMA_7		= 0x47,
@@ -194,6 +202,8 @@ enum {
 	SETFEATURES_WC_ON	= 0x02, /* Enable write cache */
 	SETFEATURES_WC_OFF	= 0x82, /* Disable write cache */
 
+	SETFEATURES_SPINUP	= 0x07, /* Spin-up drive */
+
 	/* ATAPI stuff */
 	ATAPI_PKT_DMA		= (1 << 0),
 	ATAPI_DMADIR		= (1 << 2),	/* ATAPI data dir:
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index d12984d..ced8a1e 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -101,7 +101,7 @@ struct ddpehdr {
 
 static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb)
 {
-	return (struct ddpehdr *)skb->h.raw;
+	return (struct ddpehdr *)skb_transport_header(skb);
 }
 
 /* AppleTalk AARP headers */
@@ -129,7 +129,7 @@ #define AARP_PROBE			3
 
 static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb)
 {
-	return (struct elapaarp *)skb->h.raw;
+	return (struct elapaarp *)skb_transport_header(skb);
 }
 
 /* Not specified - how long till we drop a resolved entry */
diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
deleted file mode 100644
index bf33f17..0000000
--- a/include/linux/awe_voice.h
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * include/linux/awe_voice.h
- *
- * Voice information definitions for 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.
- */
-
-#ifndef AWE_VOICE_H
-#define AWE_VOICE_H
-
-#ifndef SAMPLE_TYPE_AWE32
-#define SAMPLE_TYPE_AWE32	0x20
-#endif
-
-#define _LINUX_PATCHKEY_H_INDIRECT
-#include <linux/patchkey.h>
-#undef _LINUX_PATCHKEY_H_INDIRECT
-
-/*----------------------------------------------------------------
- * patch information record
- *----------------------------------------------------------------*/
-
-/* patch interface header: 16 bytes */
-typedef struct awe_patch_info {
-	short key;			/* use AWE_PATCH here */
-#define AWE_PATCH	_PATCHKEY(0x07)
-
-	short device_no;		/* synthesizer number */
-	unsigned short sf_id;		/* file id (should be zero) */
-	short optarg;			/* optional argument */
-	int len;			/* data length (without this header) */
-
-	short type;			/* patch operation type */
-#define AWE_LOAD_INFO		0	/* awe_voice_rec */
-#define AWE_LOAD_DATA		1	/* awe_sample_info */
-#define AWE_OPEN_PATCH		2	/* awe_open_parm */
-#define AWE_CLOSE_PATCH		3	/* none */
-#define AWE_UNLOAD_PATCH	4	/* none */
-#define AWE_REPLACE_DATA	5	/* awe_sample_info (optarg=#channels)*/
-#define AWE_MAP_PRESET		6	/* awe_voice_map */
-/*#define AWE_PROBE_INFO	7*/	/* awe_voice_map (pat only) */
-#define AWE_PROBE_DATA		8	/* optarg=sample */
-#define AWE_REMOVE_INFO		9	/* optarg=(bank<<8)|instr */
-#define AWE_LOAD_CHORUS_FX	0x10	/* awe_chorus_fx_rec (optarg=mode) */
-#define AWE_LOAD_REVERB_FX	0x11	/* awe_reverb_fx_rec (optarg=mode) */
-
-	short reserved;			/* word alignment data */
-
-	/* the actual patch data begins after this */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
-	char data[0];
-#endif
-} awe_patch_info;
-
-/*#define AWE_PATCH_INFO_SIZE	16*/
-#define AWE_PATCH_INFO_SIZE	sizeof(awe_patch_info)
-
-
-/*----------------------------------------------------------------
- * open patch
- *----------------------------------------------------------------*/
-
-#define AWE_PATCH_NAME_LEN	32
-
-typedef struct _awe_open_parm {
-	unsigned short type;		/* sample type */
-#define AWE_PAT_TYPE_MISC	0
-#define AWE_PAT_TYPE_GM		1
-#define AWE_PAT_TYPE_GS		2
-#define AWE_PAT_TYPE_MT32	3
-#define AWE_PAT_TYPE_XG		4
-#define AWE_PAT_TYPE_SFX	5
-#define AWE_PAT_TYPE_GUS	6
-#define AWE_PAT_TYPE_MAP	7
-
-#define AWE_PAT_LOCKED		0x100	/* lock the samples */
-#define AWE_PAT_SHARED		0x200	/* sample is shared */
-
-	short reserved;
-	char name[AWE_PATCH_NAME_LEN];
-} awe_open_parm;
-
-/*#define AWE_OPEN_PARM_SIZE	28*/
-#define AWE_OPEN_PARM_SIZE	sizeof(awe_open_parm)
-
-
-/*----------------------------------------------------------------
- * raw voice information record
- *----------------------------------------------------------------*/
-
-/* wave table envelope & effect parameters to control EMU8000 */
-typedef struct _awe_voice_parm {
-	unsigned short moddelay;	/* modulation delay (0x8000) */
-	unsigned short modatkhld;	/* modulation attack & hold time (0x7f7f) */
-	unsigned short moddcysus;	/* modulation decay & sustain (0x7f7f) */
-	unsigned short modrelease;	/* modulation release time (0x807f) */
-	short modkeyhold, modkeydecay;	/* envelope change per key (not used) */
-	unsigned short voldelay;	/* volume delay (0x8000) */
-	unsigned short volatkhld;	/* volume attack & hold time (0x7f7f) */
-	unsigned short voldcysus;	/* volume decay & sustain (0x7f7f) */
-	unsigned short volrelease;	/* volume release time (0x807f) */
-	short volkeyhold, volkeydecay;	/* envelope change per key (not used) */
-	unsigned short lfo1delay;	/* LFO1 delay (0x8000) */
-	unsigned short lfo2delay;	/* LFO2 delay (0x8000) */
-	unsigned short pefe;		/* modulation pitch & cutoff (0x0000) */
-	unsigned short fmmod;		/* LFO1 pitch & cutoff (0x0000) */
-	unsigned short tremfrq;		/* LFO1 volume & freq (0x0000) */
-	unsigned short fm2frq2;		/* LFO2 pitch & freq (0x0000) */
-	unsigned char cutoff;		/* initial cutoff (0xff) */
-	unsigned char filterQ;		/* initial filter Q [0-15] (0x0) */
-	unsigned char chorus;		/* chorus send (0x00) */
-	unsigned char reverb;		/* reverb send (0x00) */
-	unsigned short reserved[4];	/* not used */
-} awe_voice_parm;
-
-typedef struct _awe_voice_parm_block {
-	unsigned short moddelay;	/* modulation delay (0x8000) */
-	unsigned char modatk, modhld;
-	unsigned char moddcy, modsus;
-	unsigned char modrel, moddummy;
-	short modkeyhold, modkeydecay;	/* envelope change per key (not used) */
-	unsigned short voldelay;	/* volume delay (0x8000) */
-	unsigned char volatk, volhld;
-	unsigned char voldcy, volsus;
-	unsigned char volrel, voldummy;
-	short volkeyhold, volkeydecay;	/* envelope change per key (not used) */
-	unsigned short lfo1delay;	/* LFO1 delay (0x8000) */
-	unsigned short lfo2delay;	/* LFO2 delay (0x8000) */
-	unsigned char env1fc, env1pit;
-	unsigned char lfo1fc, lfo1pit;
-	unsigned char lfo1freq, lfo1vol;
-	unsigned char lfo2freq, lfo2pit;
-	unsigned char cutoff;		/* initial cutoff (0xff) */
-	unsigned char filterQ;		/* initial filter Q [0-15] (0x0) */
-	unsigned char chorus;		/* chorus send (0x00) */
-	unsigned char reverb;		/* reverb send (0x00) */
-	unsigned short reserved[4];	/* not used */
-} awe_voice_parm_block;
-
-#define AWE_VOICE_PARM_SIZE	48
-
-
-/* wave table parameters: 92 bytes */
-typedef struct _awe_voice_info {
-	unsigned short sf_id;		/* file id (should be zero) */
-	unsigned short sample;		/* sample id */
-	int start, end;			/* sample offset correction */
-	int loopstart, loopend;		/* loop offset correction */
-	short rate_offset;		/* sample rate pitch offset */
-	unsigned short mode;		/* sample mode */
-#define AWE_MODE_ROMSOUND		0x8000
-#define AWE_MODE_STEREO			1
-#define AWE_MODE_LOOPING		2
-#define AWE_MODE_NORELEASE		4	/* obsolete */
-#define AWE_MODE_INIT_PARM		8
-
-	short root;			/* midi root key */
-	short tune;			/* pitch tuning (in cents) */
-	signed char low, high;		/* key note range */
-	signed char vellow, velhigh;	/* velocity range */
-	signed char fixkey, fixvel;	/* fixed key, velocity */
-	signed char pan, fixpan;	/* panning, fixed panning */
-	short exclusiveClass;		/* exclusive class (0 = none) */
-	unsigned char amplitude;	/* sample volume (127 max) */
-	unsigned char attenuation;	/* attenuation (0.375dB) */
-	short scaleTuning;		/* pitch scale tuning(%), normally 100 */
-	awe_voice_parm parm;		/* voice envelope parameters */
-	short index;			/* internal index (set by driver) */
-} awe_voice_info;
-
-/*#define AWE_VOICE_INFO_SIZE	92*/
-#define AWE_VOICE_INFO_SIZE	sizeof(awe_voice_info)
-
-/*----------------------------------------------------------------*/
-
-/* The info entry of awe_voice_rec is changed from 0 to 1
- * for some compilers refusing zero size array.
- * Due to this change, sizeof(awe_voice_rec) becomes different
- * from older versions.
- * Use AWE_VOICE_REC_SIZE instead.
- */
-
-/* instrument info header: 4 bytes */
-typedef struct _awe_voice_rec_hdr {
-	unsigned char bank;		/* midi bank number */
-	unsigned char instr;		/* midi preset number */
-	char nvoices;			/* number of voices */
-	char write_mode;		/* write mode; normally 0 */
-#define AWE_WR_APPEND		0	/* append anyway */
-#define AWE_WR_EXCLUSIVE	1	/* skip if already exists */
-#define AWE_WR_REPLACE		2	/* replace if already exists */
-} awe_voice_rec_hdr;
-
-/*#define AWE_VOICE_REC_SIZE	4*/
-#define AWE_VOICE_REC_SIZE	sizeof(awe_voice_rec_hdr)
-
-/* the standard patch structure for one sample */
-typedef struct _awe_voice_rec_patch {
-	awe_patch_info		patch;
-	awe_voice_rec_hdr	hdr;
-	awe_voice_info		info;
-} awe_voice_rec_patch;
-
-
-/* obsolete data type */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
-#define AWE_INFOARRAY_SIZE	0
-#else
-#define AWE_INFOARRAY_SIZE	1
-#endif
-
-typedef struct _awe_voice_rec {
-	unsigned char bank;		/* midi bank number */
-	unsigned char instr;		/* midi preset number */
-	short nvoices;			/* number of voices */
-	/* voice information follows here */
-	awe_voice_info info[AWE_INFOARRAY_SIZE];
-} awe_voice_rec;
-
-
-/*----------------------------------------------------------------
- * sample wave information
- *----------------------------------------------------------------*/
-
-/* wave table sample header: 32 bytes */
-typedef struct awe_sample_info {
-	unsigned short sf_id;		/* file id (should be zero) */
-	unsigned short sample;		/* sample id */
-	int start, end;			/* start & end offset */
-	int loopstart, loopend;		/* loop start & end offset */
-	int size;			/* size (0 = ROM) */
-	short checksum_flag;		/* use check sum = 1 */
-	unsigned short mode_flags;	/* mode flags */
-#define AWE_SAMPLE_8BITS	1	/* wave data is 8bits */
-#define AWE_SAMPLE_UNSIGNED	2	/* wave data is unsigned */
-#define AWE_SAMPLE_NO_BLANK	4	/* no blank loop is attached */
-#define AWE_SAMPLE_SINGLESHOT	8	/* single-shot w/o loop */
-#define AWE_SAMPLE_BIDIR_LOOP	16	/* bidirectional looping */
-#define AWE_SAMPLE_STEREO_LEFT	32	/* stereo left sound */
-#define AWE_SAMPLE_STEREO_RIGHT	64	/* stereo right sound */
-#define AWE_SAMPLE_REVERSE_LOOP 128	/* reverse looping */
-	unsigned int checksum;		/* check sum */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
-	unsigned short data[0];		/* sample data follows here */
-#endif
-} awe_sample_info;
-
-/*#define AWE_SAMPLE_INFO_SIZE	32*/
-#define AWE_SAMPLE_INFO_SIZE	sizeof(awe_sample_info)
-
-
-/*----------------------------------------------------------------
- * voice preset mapping
- *----------------------------------------------------------------*/
-
-typedef struct awe_voice_map {
-	int map_bank, map_instr, map_key;	/* key = -1 means all keys */
-	int src_bank, src_instr, src_key;
-} awe_voice_map;
-
-#define AWE_VOICE_MAP_SIZE	sizeof(awe_voice_map)
-
-
-/*----------------------------------------------------------------
- * awe hardware controls
- *----------------------------------------------------------------*/
-
-#define _AWE_DEBUG_MODE			0x00
-#define _AWE_REVERB_MODE		0x01
-#define _AWE_CHORUS_MODE		0x02
-#define _AWE_REMOVE_LAST_SAMPLES	0x03
-#define _AWE_INITIALIZE_CHIP		0x04
-#define _AWE_SEND_EFFECT		0x05
-#define _AWE_TERMINATE_CHANNEL		0x06
-#define _AWE_TERMINATE_ALL		0x07
-#define _AWE_INITIAL_VOLUME		0x08
-#define _AWE_INITIAL_ATTEN	_AWE_INITIAL_VOLUME
-#define _AWE_RESET_CHANNEL		0x09
-#define _AWE_CHANNEL_MODE		0x0a
-#define _AWE_DRUM_CHANNELS		0x0b
-#define _AWE_MISC_MODE			0x0c
-#define _AWE_RELEASE_ALL		0x0d
-#define _AWE_NOTEOFF_ALL		0x0e
-#define _AWE_CHN_PRESSURE		0x0f
-/*#define _AWE_GET_CURRENT_MODE		0x10*/
-#define _AWE_EQUALIZER			0x11
-/*#define _AWE_GET_MISC_MODE		0x12*/
-/*#define _AWE_GET_FONTINFO		0x13*/
-
-#define _AWE_MODE_FLAG			0x80
-#define _AWE_COOKED_FLAG		0x40	/* not supported */
-#define _AWE_MODE_VALUE_MASK		0x3F
-
-/*----------------------------------------------------------------*/
-
-#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \
-{((char*)(p))[0] = SEQ_PRIVATE;\
- ((char*)(p))[1] = dev;\
- ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\
- ((char*)(p))[3] = voice;\
- ((unsigned short*)(p))[2] = p1;\
- ((unsigned short*)(p))[3] = p2;}
-
-/* buffered access */
-#define _AWE_CMD(dev, voice, cmd, p1, p2) \
-{_SEQ_NEEDBUF(8);\
- _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\
- _SEQ_ADVBUF(8);}
-
-/* direct access */
-#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \
-{struct seq_event_rec tmp;\
- _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\
- ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);}
-
-/*----------------------------------------------------------------*/
-
-/* set debugging mode */
-#define AWE_DEBUG_MODE(dev,p1)	_AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0)
-/* set reverb mode; from 0 to 7 */
-#define AWE_REVERB_MODE(dev,p1)	_AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0)
-/* set chorus mode; from 0 to 7 */
-#define AWE_CHORUS_MODE(dev,p1)	_AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0)
-
-/* reset channel */
-#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0)
-#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0)
-
-/* send an effect to all layers */
-#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value)
-#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value)
-#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0)
-/* send an effect to a layer */
-#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value)
-#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value)
-#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0)
-
-/* terminate sound on the channel/voice */
-#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0)
-/* terminate all sounds */
-#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0)
-/* release all sounds (w/o sustain effect) */
-#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0)
-/* note off all sounds (w sustain effect) */
-#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0)
-
-/* set initial attenuation */
-#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0)
-#define AWE_INITIAL_ATTEN  AWE_INITIAL_VOLUME
-/* relative attenuation */
-#define AWE_SET_ATTEN(dev,atten)  _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1)
-
-/* set channel playing mode; mode=0/1/2 */
-#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0)
-#define AWE_PLAY_INDIRECT	0	/* indirect voice mode (default) */
-#define AWE_PLAY_MULTI		1	/* multi note voice mode */
-#define AWE_PLAY_DIRECT		2	/* direct single voice mode */
-#define AWE_PLAY_MULTI2		3	/* sequencer2 mode; used internally */
-
-/* set drum channel mask; channels is 32bit long value */
-#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16))
-
-/* set bass and treble control; values are from 0 to 11 */
-#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble)
-
-/* remove last loaded samples */
-#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0)
-/* initialize emu8000 chip */
-#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0)
-
-/* set miscellaneous modes; meta command */
-#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value)
-/* exclusive sound off; 1=off */
-#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode)
-/* default GUS bank number */
-#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank)
-/* change panning position in realtime; 0=don't 1=do */
-#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode)
-
-/* extended pressure controls; not portable with other sound drivers */
-#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel)
-#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0)
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode parameters */
-#define	AWE_REVERB_ROOM1	0
-#define AWE_REVERB_ROOM2	1
-#define	AWE_REVERB_ROOM3	2
-#define	AWE_REVERB_HALL1	3
-#define	AWE_REVERB_HALL2	4
-#define	AWE_REVERB_PLATE	5
-#define	AWE_REVERB_DELAY	6
-#define	AWE_REVERB_PANNINGDELAY 7
-#define AWE_REVERB_PREDEFINED	8
-/* user can define reverb modes up to 32 */
-#define AWE_REVERB_NUMBERS	32
-
-typedef struct awe_reverb_fx_rec {
-	unsigned short parms[28];
-} awe_reverb_fx_rec;
-
-/*----------------------------------------------------------------*/
-
-/* chorus mode parameters */
-#define AWE_CHORUS_1		0
-#define	AWE_CHORUS_2		1
-#define	AWE_CHORUS_3		2
-#define	AWE_CHORUS_4		3
-#define	AWE_CHORUS_FEEDBACK	4
-#define	AWE_CHORUS_FLANGER	5
-#define	AWE_CHORUS_SHORTDELAY	6
-#define	AWE_CHORUS_SHORTDELAY2	7
-#define AWE_CHORUS_PREDEFINED	8
-/* user can define chorus modes up to 32 */
-#define AWE_CHORUS_NUMBERS	32
-
-typedef struct awe_chorus_fx_rec {
-	unsigned short feedback;	/* feedback level (0xE600-0xE6FF) */
-	unsigned short delay_offset;	/* delay (0-0x0DA3) [1/44100 sec] */
-	unsigned short lfo_depth;	/* LFO depth (0xBC00-0xBCFF) */
-	unsigned int delay;	/* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
-	unsigned int lfo_freq;		/* LFO freq LFO freq (0-0xFFFFFFFF) */
-} awe_chorus_fx_rec;
-
-/*----------------------------------------------------------------*/
-
-/* misc mode types */
-enum {
-/* 0*/	AWE_MD_EXCLUSIVE_OFF,	/* obsolete */
-/* 1*/	AWE_MD_EXCLUSIVE_ON,	/* obsolete */
-/* 2*/	AWE_MD_VERSION,		/* read only */
-/* 3*/	AWE_MD_EXCLUSIVE_SOUND,	/* 0/1: exclusive note on (default=1) */
-/* 4*/	AWE_MD_REALTIME_PAN,	/* 0/1: do realtime pan change (default=1) */
-/* 5*/	AWE_MD_GUS_BANK,	/* bank number for GUS patches (default=0) */
-/* 6*/	AWE_MD_KEEP_EFFECT,	/* 0/1: keep effect values, (default=0) */
-/* 7*/	AWE_MD_ZERO_ATTEN,	/* attenuation of max volume (default=32) */
-/* 8*/	AWE_MD_CHN_PRIOR,	/* 0/1: set MIDI channel priority mode (default=1) */
-/* 9*/	AWE_MD_MOD_SENSE,	/* integer: modwheel sensitivity (def=18) */
-/*10*/	AWE_MD_DEF_PRESET,	/* integer: default preset number (def=0) */
-/*11*/	AWE_MD_DEF_BANK,	/* integer: default bank number (def=0) */
-/*12*/	AWE_MD_DEF_DRUM,	/* integer: default drumset number (def=0) */
-/*13*/	AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */
-/*14*/	AWE_MD_NEW_VOLUME_CALC,	/* 0/1: volume calculation mode (def=1) */
-/*15*/	AWE_MD_CHORUS_MODE,	/* integer: chorus mode (def=2) */
-/*16*/	AWE_MD_REVERB_MODE,	/* integer: chorus mode (def=4) */
-/*17*/	AWE_MD_BASS_LEVEL,	/* integer: bass level (def=5) */
-/*18*/	AWE_MD_TREBLE_LEVEL,	/* integer: treble level (def=9) */
-/*19*/	AWE_MD_DEBUG_MODE,	/* integer: debug level (def=0) */
-/*20*/	AWE_MD_PAN_EXCHANGE,	/* 0/1: exchange panning direction (def=0) */
-	AWE_MD_END,
-};
-
-/*----------------------------------------------------------------*/
-
-/* effect parameters */
-enum {
-
-/* modulation envelope parameters */
-/* 0*/	AWE_FX_ENV1_DELAY,	/* WORD: ENVVAL */
-/* 1*/	AWE_FX_ENV1_ATTACK,	/* BYTE: up ATKHLD */
-/* 2*/	AWE_FX_ENV1_HOLD,	/* BYTE: lw ATKHLD */
-/* 3*/	AWE_FX_ENV1_DECAY,	/* BYTE: lw DCYSUS */
-/* 4*/	AWE_FX_ENV1_RELEASE,	/* BYTE: lw DCYSUS */
-/* 5*/	AWE_FX_ENV1_SUSTAIN,	/* BYTE: up DCYSUS */
-/* 6*/	AWE_FX_ENV1_PITCH,	/* BYTE: up PEFE */
-/* 7*/	AWE_FX_ENV1_CUTOFF,	/* BYTE: lw PEFE */
-
-/* volume envelope parameters */
-/* 8*/	AWE_FX_ENV2_DELAY,	/* WORD: ENVVOL */
-/* 9*/	AWE_FX_ENV2_ATTACK,	/* BYTE: up ATKHLDV */
-/*10*/	AWE_FX_ENV2_HOLD,	/* BYTE: lw ATKHLDV */
-/*11*/	AWE_FX_ENV2_DECAY,	/* BYTE: lw DCYSUSV */
-/*12*/	AWE_FX_ENV2_RELEASE,	/* BYTE: lw DCYSUSV */
-/*13*/	AWE_FX_ENV2_SUSTAIN,	/* BYTE: up DCYSUSV */
-	
-/* LFO1 (tremolo & vibrato) parameters */
-/*14*/	AWE_FX_LFO1_DELAY,	/* WORD: LFO1VAL */
-/*15*/	AWE_FX_LFO1_FREQ,	/* BYTE: lo TREMFRQ */
-/*16*/	AWE_FX_LFO1_VOLUME,	/* BYTE: up TREMFRQ */
-/*17*/	AWE_FX_LFO1_PITCH,	/* BYTE: up FMMOD */
-/*18*/	AWE_FX_LFO1_CUTOFF,	/* BYTE: lo FMMOD */
-
-/* LFO2 (vibrato) parameters */
-/*19*/	AWE_FX_LFO2_DELAY,	/* WORD: LFO2VAL */
-/*20*/	AWE_FX_LFO2_FREQ,	/* BYTE: lo FM2FRQ2 */
-/*21*/	AWE_FX_LFO2_PITCH,	/* BYTE: up FM2FRQ2 */
-
-/* Other overall effect parameters */
-/*22*/	AWE_FX_INIT_PITCH,	/* SHORT: pitch offset */
-/*23*/	AWE_FX_CHORUS,		/* BYTE: chorus effects send (0-255) */
-/*24*/	AWE_FX_REVERB,		/* BYTE: reverb effects send (0-255) */
-/*25*/	AWE_FX_CUTOFF,		/* BYTE: up IFATN */
-/*26*/	AWE_FX_FILTERQ,		/* BYTE: up CCCA */
-
-/* Sample / loop offset changes */
-/*27*/	AWE_FX_SAMPLE_START,	/* SHORT: offset */
-/*28*/	AWE_FX_LOOP_START,	/* SHORT: offset */
-/*29*/	AWE_FX_LOOP_END,	/* SHORT: offset */
-/*30*/	AWE_FX_COARSE_SAMPLE_START,	/* SHORT: upper word offset */
-/*31*/	AWE_FX_COARSE_LOOP_START,	/* SHORT: upper word offset */
-/*32*/	AWE_FX_COARSE_LOOP_END,		/* SHORT: upper word offset */
-/*33*/	AWE_FX_ATTEN,		/* BYTE: lo IFATN */
-
-	AWE_FX_END,
-};
-
-#endif /* AWE_VOICE_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 08daf32..4d85262 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -276,7 +276,7 @@ extern struct bio_pair *bio_split(struct
 extern mempool_t *bio_split_pool;
 extern void bio_pair_release(struct bio_pair *dbio);
 
-extern struct bio_set *bioset_create(int, int, int);
+extern struct bio_set *bioset_create(int, int);
 extern void bioset_free(struct bio_set *);
 
 extern struct bio *bio_alloc(gfp_t, int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 83dcd8c..a686eab 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -116,6 +116,7 @@ struct io_context {
 
 	struct as_io_context *aic;
 	struct rb_root cic_root;
+	void *ioc_data;
 };
 
 void put_io_context(struct io_context *ioc);
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 81c07cd..0365ec9 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -122,9 +122,9 @@ extern void *alloc_large_system_hash(con
 #define HASH_EARLY	0x00000001	/* Allocating during early boot? */
 
 /* Only NUMA needs hash distribution.
- * IA64 is known to have sufficient vmalloc space.
+ * IA64 and x86_64 have sufficient vmalloc space.
  */
-#if defined(CONFIG_NUMA) && defined(CONFIG_IA64)
+#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64))
 #define HASHDIST_DEFAULT 1
 #else
 #define HASHDIST_DEFAULT 0
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index dd27b1c..5c6e128 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -165,7 +165,7 @@ int sync_mapping_buffers(struct address_
 void unmap_underlying_metadata(struct block_device *bdev, sector_t block);
 
 void mark_buffer_async_write(struct buffer_head *bh);
-void invalidate_bdev(struct block_device *, int);
+void invalidate_bdev(struct block_device *);
 int sync_blockdev(struct block_device *bdev);
 void __wait_on_buffer(struct buffer_head *);
 wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
@@ -182,6 +182,7 @@ void __brelse(struct buffer_head *);
 void __bforget(struct buffer_head *);
 void __breadahead(struct block_device *, sector_t block, unsigned int size);
 struct buffer_head *__bread(struct block_device *, sector_t block, unsigned size);
+void invalidate_bh_lrus(void);
 struct buffer_head *alloc_buffer_head(gfp_t gfp_flags);
 void free_buffer_head(struct buffer_head * bh);
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
@@ -319,7 +320,7 @@ static inline int inode_has_buffers(stru
 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) {}
+static inline void invalidate_bdev(struct block_device *bdev) {}
 
 
 #endif /* CONFIG_BLOCK */
diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
index e86e4a9..3dc715b 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -124,19 +124,8 @@ #define cpu_to_be32s __cpu_to_be32s
 #define be32_to_cpus __be32_to_cpus
 #define cpu_to_be16s __cpu_to_be16s
 #define be16_to_cpus __be16_to_cpus
-#endif
 
-
-#if defined(__KERNEL__)
 /*
- * Handle ntohl and suches. These have various compatibility
- * issues - like we want to give the prototype even though we
- * also have a macro for them in case some strange program
- * wants to take the address of the thing or something..
- *
- * Note that these used to return a "long" in libc5, even though
- * long is often 64-bit these days.. Thus the casts.
- *
  * They have to be macros in order to do the constant folding
  * correctly - if the argument passed into a inline function
  * it is no longer constant according to gcc..
@@ -147,17 +136,6 @@ #undef ntohs
 #undef htonl
 #undef htons
 
-/*
- * Do the prototypes. Somebody might want to take the
- * address or some such sick thing..
- */
-extern __u32			ntohl(__be32);
-extern __be32			htonl(__u32);
-extern __u16			ntohs(__be16);
-extern __be16			htons(__u16);
-
-#if defined(__GNUC__) && defined(__OPTIMIZE__)
-
 #define ___htonl(x) __cpu_to_be32(x)
 #define ___htons(x) __cpu_to_be16(x)
 #define ___ntohl(x) __be32_to_cpu(x)
@@ -168,9 +146,6 @@ #define ntohl(x) ___ntohl(x)
 #define htons(x) ___htons(x)
 #define ntohs(x) ___ntohs(x)
 
-#endif /* OPTIMIZE */
-
 #endif /* KERNEL */
 
-
 #endif /* _LINUX_BYTEORDER_GENERIC_H */
diff --git a/include/linux/byteorder/swab.h b/include/linux/byteorder/swab.h
index 25f7f32..142134f 100644
--- a/include/linux/byteorder/swab.h
+++ b/include/linux/byteorder/swab.h
@@ -10,6 +10,10 @@ #define _LINUX_BYTEORDER_SWAB_H
  *    separated swab functions from cpu_to_XX,
  *    to clean up support for bizarre-endian architectures.
  *
+ * Trent Piepho <xyzzy@speakeasy.org> 2007114
+ *    make constant-folding work, provide C versions that
+ *    gcc can optimize better, explain different versions
+ *
  * See asm-i386/byteorder.h and suches for examples of how to provide
  * architecture-dependent optimized versions
  *
@@ -17,40 +21,66 @@ #define _LINUX_BYTEORDER_SWAB_H
 
 #include <linux/compiler.h>
 
+/* Functions/macros defined, there are a lot:
+ *
+ * ___swabXX
+ *    Generic C versions of the swab functions.
+ *
+ * ___constant_swabXX
+ *    C versions that gcc can fold into a compile-time constant when
+ *    the argument is a compile-time constant.
+ *
+ * __arch__swabXX[sp]?
+ *    Architecture optimized versions of all the swab functions
+ *    (including the s and p versions).  These can be defined in
+ *    asm-arch/byteorder.h.  Any which are not, are defined here.
+ *    __arch__swabXXs() is defined in terms of __arch__swabXXp(), which
+ *    is defined in terms of __arch__swabXX(), which is in turn defined
+ *    in terms of ___swabXX(x).
+ *    These must be macros.  They may be unsafe for arguments with
+ *    side-effects.
+ *
+ * __fswabXX
+ *    Inline function versions of the __arch__ macros.  These _are_ safe
+ *    if the arguments have side-effects.  Note there are no s and p
+ *    versions of these.
+ *
+ * __swabXX[sb]
+ *    There are the ones you should actually use.  The __swabXX versions
+ *    will be a constant given a constant argument and use the arch
+ *    specific code (if any) for non-constant arguments.  The s and p
+ *    versions always use the arch specific code (constant folding
+ *    doesn't apply).  They are safe to use with arguments with
+ *    side-effects.
+ *
+ * swabXX[sb]
+ *    Nicknames for __swabXX[sb] to use in the kernel.
+ */
+
 /* casts are necessary for constants, because we never know how for sure
  * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
  */
-#define ___swab16(x) \
-({ \
-	__u16 __x = (x); \
-	((__u16)( \
-		(((__u16)(__x) & (__u16)0x00ffU) << 8) | \
-		(((__u16)(__x) & (__u16)0xff00U) >> 8) )); \
-})
 
-#define ___swab32(x) \
-({ \
-	__u32 __x = (x); \
-	((__u32)( \
-		(((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \
-		(((__u32)(__x) & (__u32)0x0000ff00UL) <<  8) | \
-		(((__u32)(__x) & (__u32)0x00ff0000UL) >>  8) | \
-		(((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \
-})
-
-#define ___swab64(x) \
-({ \
-	__u64 __x = (x); \
-	((__u64)( \
-		(__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
-		(__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
-		(__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
-		(__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) <<  8) | \
-	        (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >>  8) | \
-		(__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
-		(__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
-		(__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \
-})
+static __inline__ __attribute_const__ __u16 ___swab16(__u16 x)
+{
+	return x<<8 | x>>8;
+}
+static __inline__ __attribute_const__ __u32 ___swab32(__u32 x)
+{
+	return x<<24 | x>>24 |
+		(x & (__u32)0x0000ff00UL)<<8 |
+		(x & (__u32)0x00ff0000UL)>>8;
+}
+static __inline__ __attribute_const__ __u64 ___swab64(__u64 x)
+{
+	return x<<56 | x>>56 |
+		(x & (__u64)0x000000000000ff00ULL)<<40 |
+		(x & (__u64)0x0000000000ff0000ULL)<<24 |
+		(x & (__u64)0x00000000ff000000ULL)<< 8 |
+	        (x & (__u64)0x000000ff00000000ULL)>> 8 |
+		(x & (__u64)0x0000ff0000000000ULL)>>24 |
+		(x & (__u64)0x00ff000000000000ULL)>>40;
+}
 
 #define ___constant_swab16(x) \
 	((__u16)( \
@@ -77,13 +107,13 @@ #define ___constant_swab64(x) \
  * provide defaults when no architecture-specific optimization is detected
  */
 #ifndef __arch__swab16
-#  define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); })
+#  define __arch__swab16(x) ___swab16(x)
 #endif
 #ifndef __arch__swab32
-#  define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); })
+#  define __arch__swab32(x) ___swab32(x)
 #endif
 #ifndef __arch__swab64
-#  define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); })
+#  define __arch__swab64(x) ___swab64(x)
 #endif
 
 #ifndef __arch__swab16p
@@ -97,13 +127,13 @@ #  define __arch__swab64p(x) __arch__swa
 #endif
 
 #ifndef __arch__swab16s
-#  define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0)
+#  define __arch__swab16s(x) ((void)(*(x) = __arch__swab16p(x)))
 #endif
 #ifndef __arch__swab32s
-#  define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0)
+#  define __arch__swab32s(x) ((void)(*(x) = __arch__swab32p(x)))
 #endif
 #ifndef __arch__swab64s
-#  define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0)
+#  define __arch__swab64s(x) ((void)(*(x) = __arch__swab64p(x)))
 #endif
 
 
@@ -113,15 +143,15 @@ #endif
 #if defined(__GNUC__) && defined(__OPTIMIZE__)
 #  define __swab16(x) \
 (__builtin_constant_p((__u16)(x)) ? \
- ___swab16((x)) : \
+ ___constant_swab16((x)) : \
  __fswab16((x)))
 #  define __swab32(x) \
 (__builtin_constant_p((__u32)(x)) ? \
- ___swab32((x)) : \
+ ___constant_swab32((x)) : \
  __fswab32((x)))
 #  define __swab64(x) \
 (__builtin_constant_p((__u64)(x)) ? \
- ___swab64((x)) : \
+ ___constant_swab64((x)) : \
  __fswab64((x)))
 #else
 #  define __swab16(x) __fswab16(x)
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 4ea7e7b..8486e78 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -54,17 +54,17 @@ #define CLOCK_EVT_FEAT_DUMMY		0x000008
 /**
  * struct clock_event_device - clock event device descriptor
  * @name:		ptr to clock event name
- * @hints:		usage hints
+ * @features:		features
  * @max_delta_ns:	maximum delta value in ns
  * @min_delta_ns:	minimum delta value in ns
  * @mult:		nanosecond to cycles multiplier
  * @shift:		nanoseconds to cycles divisor (power of two)
  * @rating:		variable to rate clock event devices
- * @irq:		irq number (only for non cpu local devices)
- * @cpumask:		cpumask to indicate for which cpus this device works
- * @set_next_event:	set next event
+ * @irq:		IRQ number (only for non CPU local devices)
+ * @cpumask:		cpumask to indicate for which CPUs this device works
+ * @set_next_event:	set next event function
  * @set_mode:		set mode function
- * @evthandler:		Assigned by the framework to be called by the low
+ * @event_handler:	Assigned by the framework to be called by the low
  *			level handler of the event source
  * @broadcast:		function to broadcast events
  * @list:		list head for the management code
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index daa4940..2665ca0 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -12,6 +12,7 @@ #include <linux/types.h>
 #include <linux/timex.h>
 #include <linux/time.h>
 #include <linux/list.h>
+#include <linux/cache.h>
 #include <linux/timer.h>
 #include <asm/div64.h>
 #include <asm/io.h>
@@ -52,6 +53,9 @@ struct clocksource;
  * @xtime_interval:	Used internally by timekeeping core, please ignore.
  */
 struct clocksource {
+	/*
+	 * First part of structure is read mostly
+	 */
 	char *name;
 	struct list_head list;
 	int rating;
@@ -63,8 +67,15 @@ struct clocksource {
 	cycle_t (*vread)(void);
 
 	/* timekeeping specific data, ignore */
-	cycle_t cycle_last, cycle_interval;
-	u64 xtime_nsec, xtime_interval;
+	cycle_t cycle_interval;
+	u64	xtime_interval;
+	/*
+	 * Second part is written at each timer interrupt
+	 * Keep it in a different cache line to dirty no
+	 * more than one cache line.
+	 */
+	cycle_t cycle_last ____cacheline_aligned_in_smp;
+	u64 xtime_nsec;
 	s64 error;
 
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
deleted file mode 100644
index c26c3ad..0000000
--- a/include/linux/compat_ioctl.h
+++ /dev/null
@@ -1,830 +0,0 @@
-/* List here explicitly which ioctl's are known to have
- * compatible types passed or none at all... Please include
- * only stuff that is compatible on *all architectures*.
- */
-
-COMPATIBLE_IOCTL(0x4B50)   /* KDGHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(0x4B51)   /* KDSHWCLK - not in the kernel, but don't complain */
-
-/* Big T */
-COMPATIBLE_IOCTL(TCGETA)
-COMPATIBLE_IOCTL(TCSETA)
-COMPATIBLE_IOCTL(TCSETAW)
-COMPATIBLE_IOCTL(TCSETAF)
-COMPATIBLE_IOCTL(TCSBRK)
-ULONG_IOCTL(TCSBRKP)
-COMPATIBLE_IOCTL(TCXONC)
-COMPATIBLE_IOCTL(TCFLSH)
-COMPATIBLE_IOCTL(TCGETS)
-COMPATIBLE_IOCTL(TCSETS)
-COMPATIBLE_IOCTL(TCSETSW)
-COMPATIBLE_IOCTL(TCSETSF)
-COMPATIBLE_IOCTL(TIOCLINUX)
-COMPATIBLE_IOCTL(TIOCSBRK)
-COMPATIBLE_IOCTL(TIOCCBRK)
-ULONG_IOCTL(TIOCMIWAIT)
-COMPATIBLE_IOCTL(TIOCGICOUNT)
-/* Little t */
-COMPATIBLE_IOCTL(TIOCGETD)
-COMPATIBLE_IOCTL(TIOCSETD)
-COMPATIBLE_IOCTL(TIOCEXCL)
-COMPATIBLE_IOCTL(TIOCNXCL)
-COMPATIBLE_IOCTL(TIOCCONS)
-COMPATIBLE_IOCTL(TIOCGSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSWINSZ)
-COMPATIBLE_IOCTL(TIOCGWINSZ)
-COMPATIBLE_IOCTL(TIOCMGET)
-COMPATIBLE_IOCTL(TIOCMBIC)
-COMPATIBLE_IOCTL(TIOCMBIS)
-COMPATIBLE_IOCTL(TIOCMSET)
-COMPATIBLE_IOCTL(TIOCPKT)
-COMPATIBLE_IOCTL(TIOCNOTTY)
-COMPATIBLE_IOCTL(TIOCSTI)
-COMPATIBLE_IOCTL(TIOCOUTQ)
-COMPATIBLE_IOCTL(TIOCSPGRP)
-COMPATIBLE_IOCTL(TIOCGPGRP)
-ULONG_IOCTL(TIOCSCTTY)
-COMPATIBLE_IOCTL(TIOCGPTN)
-COMPATIBLE_IOCTL(TIOCSPTLCK)
-COMPATIBLE_IOCTL(TIOCSERGETLSR)
-/* Little f */
-COMPATIBLE_IOCTL(FIOCLEX)
-COMPATIBLE_IOCTL(FIONCLEX)
-COMPATIBLE_IOCTL(FIOASYNC)
-COMPATIBLE_IOCTL(FIONBIO)
-COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
-/* 0x00 */
-COMPATIBLE_IOCTL(FIBMAP)
-COMPATIBLE_IOCTL(FIGETBSZ)
-/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
- *         Some need translations, these do not.
- */
-COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
-COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
-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)
-COMPATIBLE_IOCTL(FDSETEMSGTRESH)
-COMPATIBLE_IOCTL(FDFLUSH)
-COMPATIBLE_IOCTL(FDWERRORCLR)
-COMPATIBLE_IOCTL(FDSETMAXERRS)
-COMPATIBLE_IOCTL(FDGETMAXERRS)
-COMPATIBLE_IOCTL(FDGETDRVTYP)
-COMPATIBLE_IOCTL(FDEJECT)
-COMPATIBLE_IOCTL(FDCLRPRM)
-COMPATIBLE_IOCTL(FDFMTBEG)
-COMPATIBLE_IOCTL(FDFMTEND)
-COMPATIBLE_IOCTL(FDRESET)
-COMPATIBLE_IOCTL(FDTWADDLE)
-COMPATIBLE_IOCTL(FDFMTTRK)
-COMPATIBLE_IOCTL(FDRAWCMD)
-/* 0x12 */
-#ifdef CONFIG_BLOCK
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(BLKROSET)
-COMPATIBLE_IOCTL(BLKROGET)
-COMPATIBLE_IOCTL(BLKRRPART)
-COMPATIBLE_IOCTL(BLKFLSBUF)
-COMPATIBLE_IOCTL(BLKSECTSET)
-COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKTRACESTART)
-COMPATIBLE_IOCTL(BLKTRACESTOP)
-COMPATIBLE_IOCTL(BLKTRACESETUP)
-COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
-ULONG_IOCTL(BLKRASET)
-ULONG_IOCTL(BLKFRASET)
-#endif
-/* RAID */
-COMPATIBLE_IOCTL(RAID_VERSION)
-COMPATIBLE_IOCTL(GET_ARRAY_INFO)
-COMPATIBLE_IOCTL(GET_DISK_INFO)
-COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
-COMPATIBLE_IOCTL(RAID_AUTORUN)
-COMPATIBLE_IOCTL(CLEAR_ARRAY)
-COMPATIBLE_IOCTL(ADD_NEW_DISK)
-ULONG_IOCTL(HOT_REMOVE_DISK)
-COMPATIBLE_IOCTL(SET_ARRAY_INFO)
-COMPATIBLE_IOCTL(SET_DISK_INFO)
-COMPATIBLE_IOCTL(WRITE_RAID_INFO)
-COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
-COMPATIBLE_IOCTL(PROTECT_ARRAY)
-ULONG_IOCTL(HOT_ADD_DISK)
-ULONG_IOCTL(SET_DISK_FAULTY)
-COMPATIBLE_IOCTL(RUN_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)
-COMPATIBLE_IOCTL(DM_LIST_DEVICES_32)
-COMPATIBLE_IOCTL(DM_DEV_CREATE_32)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE_32)
-COMPATIBLE_IOCTL(DM_DEV_RENAME_32)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND_32)
-COMPATIBLE_IOCTL(DM_DEV_STATUS_32)
-COMPATIBLE_IOCTL(DM_DEV_WAIT_32)
-COMPATIBLE_IOCTL(DM_TABLE_LOAD_32)
-COMPATIBLE_IOCTL(DM_TABLE_CLEAR_32)
-COMPATIBLE_IOCTL(DM_TABLE_DEPS_32)
-COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
-COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
-COMPATIBLE_IOCTL(DM_TARGET_MSG_32)
-COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32)
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_LIST_DEVICES)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_DEV_WAIT)
-COMPATIBLE_IOCTL(DM_TABLE_LOAD)
-COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
-COMPATIBLE_IOCTL(DM_TABLE_DEPS)
-COMPATIBLE_IOCTL(DM_TABLE_STATUS)
-COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
-COMPATIBLE_IOCTL(DM_TARGET_MSG)
-COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY)
-/* Big K */
-COMPATIBLE_IOCTL(PIO_FONT)
-COMPATIBLE_IOCTL(GIO_FONT)
-ULONG_IOCTL(KDSIGACCEPT)
-COMPATIBLE_IOCTL(KDGETKEYCODE)
-COMPATIBLE_IOCTL(KDSETKEYCODE)
-ULONG_IOCTL(KIOCSOUND)
-ULONG_IOCTL(KDMKTONE)
-COMPATIBLE_IOCTL(KDGKBTYPE)
-ULONG_IOCTL(KDSETMODE)
-COMPATIBLE_IOCTL(KDGETMODE)
-ULONG_IOCTL(KDSKBMODE)
-COMPATIBLE_IOCTL(KDGKBMODE)
-ULONG_IOCTL(KDSKBMETA)
-COMPATIBLE_IOCTL(KDGKBMETA)
-COMPATIBLE_IOCTL(KDGKBENT)
-COMPATIBLE_IOCTL(KDSKBENT)
-COMPATIBLE_IOCTL(KDGKBSENT)
-COMPATIBLE_IOCTL(KDSKBSENT)
-COMPATIBLE_IOCTL(KDGKBDIACR)
-COMPATIBLE_IOCTL(KDSKBDIACR)
-COMPATIBLE_IOCTL(KDKBDREP)
-COMPATIBLE_IOCTL(KDGKBLED)
-ULONG_IOCTL(KDSKBLED)
-COMPATIBLE_IOCTL(KDGETLED)
-ULONG_IOCTL(KDSETLED)
-COMPATIBLE_IOCTL(GIO_SCRNMAP)
-COMPATIBLE_IOCTL(PIO_SCRNMAP)
-COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_FONTRESET)
-COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
-/* Big S */
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
-COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
-COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
-/* Big T */
-COMPATIBLE_IOCTL(TUNSETNOCSUM)
-COMPATIBLE_IOCTL(TUNSETDEBUG)
-COMPATIBLE_IOCTL(TUNSETPERSIST)
-COMPATIBLE_IOCTL(TUNSETOWNER)
-/* Big V */
-COMPATIBLE_IOCTL(VT_SETMODE)
-COMPATIBLE_IOCTL(VT_GETMODE)
-COMPATIBLE_IOCTL(VT_GETSTATE)
-COMPATIBLE_IOCTL(VT_OPENQRY)
-ULONG_IOCTL(VT_ACTIVATE)
-ULONG_IOCTL(VT_WAITACTIVE)
-ULONG_IOCTL(VT_RELDISP)
-ULONG_IOCTL(VT_DISALLOCATE)
-COMPATIBLE_IOCTL(VT_RESIZE)
-COMPATIBLE_IOCTL(VT_RESIZEX)
-COMPATIBLE_IOCTL(VT_LOCKSWITCH)
-COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-COMPATIBLE_IOCTL(VT_GETHIFONTMASK)
-/* Little p (/dev/rtc, /dev/envctrl, etc.) */
-COMPATIBLE_IOCTL(RTC_AIE_ON)
-COMPATIBLE_IOCTL(RTC_AIE_OFF)
-COMPATIBLE_IOCTL(RTC_UIE_ON)
-COMPATIBLE_IOCTL(RTC_UIE_OFF)
-COMPATIBLE_IOCTL(RTC_PIE_ON)
-COMPATIBLE_IOCTL(RTC_PIE_OFF)
-COMPATIBLE_IOCTL(RTC_WIE_ON)
-COMPATIBLE_IOCTL(RTC_WIE_OFF)
-COMPATIBLE_IOCTL(RTC_ALM_SET)
-COMPATIBLE_IOCTL(RTC_ALM_READ)
-COMPATIBLE_IOCTL(RTC_RD_TIME)
-COMPATIBLE_IOCTL(RTC_SET_TIME)
-COMPATIBLE_IOCTL(RTC_WKALM_SET)
-COMPATIBLE_IOCTL(RTC_WKALM_RD)
-/*
- * These two are only for the sbus rtc driver, but
- * hwclock tries them on every rtc device first when
- * running on sparc.  On other architectures the entries
- * are useless but harmless.
- */
-COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
-COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
-/* Little m */
-COMPATIBLE_IOCTL(MTIOCTOP)
-/* Socket level stuff */
-COMPATIBLE_IOCTL(FIOQSIZE)
-COMPATIBLE_IOCTL(FIOSETOWN)
-COMPATIBLE_IOCTL(SIOCSPGRP)
-COMPATIBLE_IOCTL(FIOGETOWN)
-COMPATIBLE_IOCTL(SIOCGPGRP)
-COMPATIBLE_IOCTL(SIOCATMARK)
-COMPATIBLE_IOCTL(SIOCSIFLINK)
-COMPATIBLE_IOCTL(SIOCSIFENCAP)
-COMPATIBLE_IOCTL(SIOCGIFENCAP)
-COMPATIBLE_IOCTL(SIOCSIFNAME)
-COMPATIBLE_IOCTL(SIOCSARP)
-COMPATIBLE_IOCTL(SIOCGARP)
-COMPATIBLE_IOCTL(SIOCDARP)
-COMPATIBLE_IOCTL(SIOCSRARP)
-COMPATIBLE_IOCTL(SIOCGRARP)
-COMPATIBLE_IOCTL(SIOCDRARP)
-COMPATIBLE_IOCTL(SIOCADDDLCI)
-COMPATIBLE_IOCTL(SIOCDELDLCI)
-COMPATIBLE_IOCTL(SIOCGMIIPHY)
-COMPATIBLE_IOCTL(SIOCGMIIREG)
-COMPATIBLE_IOCTL(SIOCSMIIREG)
-COMPATIBLE_IOCTL(SIOCGIFVLAN)
-COMPATIBLE_IOCTL(SIOCSIFVLAN)
-COMPATIBLE_IOCTL(SIOCBRADDBR)
-COMPATIBLE_IOCTL(SIOCBRDELBR)
-/* SG stuff */
-COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_EMULATED_HOST)
-ULONG_IOCTL(SG_SET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
-COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
-COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
-COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
-COMPATIBLE_IOCTL(SG_SET_DEBUG)
-COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
-COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
-COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
-COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
-COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
-/* PPP stuff */
-COMPATIBLE_IOCTL(PPPIOCGFLAGS)
-COMPATIBLE_IOCTL(PPPIOCSFLAGS)
-COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGUNIT)
-COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGMRU)
-COMPATIBLE_IOCTL(PPPIOCSMRU)
-COMPATIBLE_IOCTL(PPPIOCSMAXCID)
-COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
-/* PPPIOCSCOMPRESS is translated */
-COMPATIBLE_IOCTL(PPPIOCGNPMODE)
-COMPATIBLE_IOCTL(PPPIOCSNPMODE)
-COMPATIBLE_IOCTL(PPPIOCGDEBUG)
-COMPATIBLE_IOCTL(PPPIOCSDEBUG)
-/* PPPIOCSPASS is translated */
-/* PPPIOCSACTIVE is translated */
-/* PPPIOCGIDLE is translated */
-COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
-COMPATIBLE_IOCTL(PPPIOCATTACH)
-COMPATIBLE_IOCTL(PPPIOCDETACH)
-COMPATIBLE_IOCTL(PPPIOCSMRRU)
-COMPATIBLE_IOCTL(PPPIOCCONNECT)
-COMPATIBLE_IOCTL(PPPIOCDISCONN)
-COMPATIBLE_IOCTL(PPPIOCATTCHAN)
-COMPATIBLE_IOCTL(PPPIOCGCHAN)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
-/* LP */
-COMPATIBLE_IOCTL(LPGETSTATUS)
-/* ppdev */
-COMPATIBLE_IOCTL(PPSETMODE)
-COMPATIBLE_IOCTL(PPRSTATUS)
-COMPATIBLE_IOCTL(PPRCONTROL)
-COMPATIBLE_IOCTL(PPWCONTROL)
-COMPATIBLE_IOCTL(PPFCONTROL)
-COMPATIBLE_IOCTL(PPRDATA)
-COMPATIBLE_IOCTL(PPWDATA)
-COMPATIBLE_IOCTL(PPCLAIM)
-COMPATIBLE_IOCTL(PPRELEASE)
-COMPATIBLE_IOCTL(PPYIELD)
-COMPATIBLE_IOCTL(PPEXCL)
-COMPATIBLE_IOCTL(PPDATADIR)
-COMPATIBLE_IOCTL(PPNEGOT)
-COMPATIBLE_IOCTL(PPWCTLONIRQ)
-COMPATIBLE_IOCTL(PPCLRIRQ)
-COMPATIBLE_IOCTL(PPSETPHASE)
-COMPATIBLE_IOCTL(PPGETMODES)
-COMPATIBLE_IOCTL(PPGETMODE)
-COMPATIBLE_IOCTL(PPGETPHASE)
-COMPATIBLE_IOCTL(PPGETFLAGS)
-COMPATIBLE_IOCTL(PPSETFLAGS)
-/* CDROM stuff */
-COMPATIBLE_IOCTL(CDROMPAUSE)
-COMPATIBLE_IOCTL(CDROMRESUME)
-COMPATIBLE_IOCTL(CDROMPLAYMSF)
-COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
-COMPATIBLE_IOCTL(CDROMREADTOCHDR)
-COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
-COMPATIBLE_IOCTL(CDROMSTOP)
-COMPATIBLE_IOCTL(CDROMSTART)
-COMPATIBLE_IOCTL(CDROMEJECT)
-COMPATIBLE_IOCTL(CDROMVOLCTRL)
-COMPATIBLE_IOCTL(CDROMSUBCHNL)
-ULONG_IOCTL(CDROMEJECT_SW)
-COMPATIBLE_IOCTL(CDROMMULTISESSION)
-COMPATIBLE_IOCTL(CDROM_GET_MCN)
-COMPATIBLE_IOCTL(CDROMRESET)
-COMPATIBLE_IOCTL(CDROMVOLREAD)
-COMPATIBLE_IOCTL(CDROMSEEK)
-COMPATIBLE_IOCTL(CDROMPLAYBLK)
-COMPATIBLE_IOCTL(CDROMCLOSETRAY)
-ULONG_IOCTL(CDROM_SET_OPTIONS)
-ULONG_IOCTL(CDROM_CLEAR_OPTIONS)
-ULONG_IOCTL(CDROM_SELECT_SPEED)
-ULONG_IOCTL(CDROM_SELECT_DISC)
-ULONG_IOCTL(CDROM_MEDIA_CHANGED)
-ULONG_IOCTL(CDROM_DRIVE_STATUS)
-COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
-COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
-ULONG_IOCTL(CDROM_LOCKDOOR)
-ULONG_IOCTL(CDROM_DEBUG)
-COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
-/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
- * not take a struct cdrom_read, instead they take a struct cdrom_msf
- * which is compatible.
- */
-COMPATIBLE_IOCTL(CDROMREADMODE2)
-COMPATIBLE_IOCTL(CDROMREADMODE1)
-COMPATIBLE_IOCTL(CDROMREADRAW)
-COMPATIBLE_IOCTL(CDROMREADCOOKED)
-COMPATIBLE_IOCTL(CDROMREADALL)
-/* DVD ioctls */
-COMPATIBLE_IOCTL(DVD_READ_STRUCT)
-COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
-COMPATIBLE_IOCTL(DVD_AUTH)
-/* pktcdvd */
-COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
-/* Big A */
-/* sparc only */
-/* Big Q for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
-COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
-COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
-/* Big T for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_START)
-COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
-COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
-/* Little m for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
-/* Big P for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
-COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
-/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
-/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
-COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
-/* Big C for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
-COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
-COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
-COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
-/* Big M for sound/OSS */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
-/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
-/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
-/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
-/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
-COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
-COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
-COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
-COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
-COMPATIBLE_IOCTL(OSS_GETVERSION)
-/* AUTOFS */
-ULONG_IOCTL(AUTOFS_IOC_READY)
-ULONG_IOCTL(AUTOFS_IOC_FAIL)
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
-COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
-/* Raw devices */
-COMPATIBLE_IOCTL(RAW_SETBIND)
-COMPATIBLE_IOCTL(RAW_GETBIND)
-/* SMB ioctls which do not need any translations */
-COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
-/* Little a */
-COMPATIBLE_IOCTL(ATMSIGD_CTRL)
-COMPATIBLE_IOCTL(ATMARPD_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_MCAST)
-COMPATIBLE_IOCTL(ATMLEC_DATA)
-COMPATIBLE_IOCTL(ATM_SETSC)
-COMPATIBLE_IOCTL(SIOCSIFATMTCP)
-COMPATIBLE_IOCTL(SIOCMKCLIP)
-COMPATIBLE_IOCTL(ATMARP_MKIP)
-COMPATIBLE_IOCTL(ATMARP_SETENTRY)
-COMPATIBLE_IOCTL(ATMARP_ENCAP)
-COMPATIBLE_IOCTL(ATMTCP_CREATE)
-COMPATIBLE_IOCTL(ATMTCP_REMOVE)
-COMPATIBLE_IOCTL(ATMMPC_CTRL)
-COMPATIBLE_IOCTL(ATMMPC_DATA)
-/* Watchdog */
-COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
-COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETTEMP)
-COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
-COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
-COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
-COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
-/* Big R */
-COMPATIBLE_IOCTL(RNDGETENTCNT)
-COMPATIBLE_IOCTL(RNDADDTOENTCNT)
-COMPATIBLE_IOCTL(RNDGETPOOL)
-COMPATIBLE_IOCTL(RNDADDENTROPY)
-COMPATIBLE_IOCTL(RNDZAPENTCNT)
-COMPATIBLE_IOCTL(RNDCLEARPOOL)
-/* Bluetooth */
-COMPATIBLE_IOCTL(HCIDEVUP)
-COMPATIBLE_IOCTL(HCIDEVDOWN)
-COMPATIBLE_IOCTL(HCIDEVRESET)
-COMPATIBLE_IOCTL(HCIDEVRESTAT)
-COMPATIBLE_IOCTL(HCIGETDEVLIST)
-COMPATIBLE_IOCTL(HCIGETDEVINFO)
-COMPATIBLE_IOCTL(HCIGETCONNLIST)
-COMPATIBLE_IOCTL(HCIGETCONNINFO)
-COMPATIBLE_IOCTL(HCISETRAW)
-COMPATIBLE_IOCTL(HCISETSCAN)
-COMPATIBLE_IOCTL(HCISETAUTH)
-COMPATIBLE_IOCTL(HCISETENCRYPT)
-COMPATIBLE_IOCTL(HCISETPTYPE)
-COMPATIBLE_IOCTL(HCISETLINKPOL)
-COMPATIBLE_IOCTL(HCISETLINKMODE)
-COMPATIBLE_IOCTL(HCISETACLMTU)
-COMPATIBLE_IOCTL(HCISETSCOMTU)
-COMPATIBLE_IOCTL(HCIINQUIRY)
-COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-COMPATIBLE_IOCTL(BNEPCONNADD)
-COMPATIBLE_IOCTL(BNEPCONNDEL)
-COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-COMPATIBLE_IOCTL(CMTPCONNADD)
-COMPATIBLE_IOCTL(CMTPCONNDEL)
-COMPATIBLE_IOCTL(CMTPGETCONNLIST)
-COMPATIBLE_IOCTL(CMTPGETCONNINFO)
-COMPATIBLE_IOCTL(HIDPCONNADD)
-COMPATIBLE_IOCTL(HIDPCONNDEL)
-COMPATIBLE_IOCTL(HIDPGETCONNLIST)
-COMPATIBLE_IOCTL(HIDPGETCONNINFO)
-/* CAPI */
-COMPATIBLE_IOCTL(CAPI_REGISTER)
-COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
-COMPATIBLE_IOCTL(CAPI_GET_VERSION)
-COMPATIBLE_IOCTL(CAPI_GET_SERIAL)
-COMPATIBLE_IOCTL(CAPI_GET_PROFILE)
-COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD)
-COMPATIBLE_IOCTL(CAPI_GET_ERRCODE)
-COMPATIBLE_IOCTL(CAPI_INSTALLED)
-COMPATIBLE_IOCTL(CAPI_GET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_SET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
-COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
-COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
-/* Siemens Gigaset */
-COMPATIBLE_IOCTL(GIGASET_REDIR)
-COMPATIBLE_IOCTL(GIGASET_CONFIG)
-COMPATIBLE_IOCTL(GIGASET_BRKCHARS)
-COMPATIBLE_IOCTL(GIGASET_VERSION)
-/* Misc. */
-COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
-COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
-COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
-COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* USB */
-COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
-COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
-COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
-COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
-COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_RESET)
-COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
-COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
-/* MTD */
-COMPATIBLE_IOCTL(MEMGETINFO)
-COMPATIBLE_IOCTL(MEMERASE)
-COMPATIBLE_IOCTL(MEMLOCK)
-COMPATIBLE_IOCTL(MEMUNLOCK)
-COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
-COMPATIBLE_IOCTL(MEMGETREGIONINFO)
-COMPATIBLE_IOCTL(MEMGETBADBLOCK)
-COMPATIBLE_IOCTL(MEMSETBADBLOCK)
-/* NBD */
-ULONG_IOCTL(NBD_SET_SOCK)
-ULONG_IOCTL(NBD_SET_BLKSIZE)
-ULONG_IOCTL(NBD_SET_SIZE)
-COMPATIBLE_IOCTL(NBD_DO_IT)
-COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
-COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
-COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
-ULONG_IOCTL(NBD_SET_SIZE_BLOCKS)
-COMPATIBLE_IOCTL(NBD_DISCONNECT)
-/* i2c */
-COMPATIBLE_IOCTL(I2C_SLAVE)
-COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
-COMPATIBLE_IOCTL(I2C_TENBIT)
-COMPATIBLE_IOCTL(I2C_PEC)
-COMPATIBLE_IOCTL(I2C_RETRIES)
-COMPATIBLE_IOCTL(I2C_TIMEOUT)
-/* wireless */
-COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
-COMPATIBLE_IOCTL(SIOCGIWNAME)
-COMPATIBLE_IOCTL(SIOCSIWNWID)
-COMPATIBLE_IOCTL(SIOCGIWNWID)
-COMPATIBLE_IOCTL(SIOCSIWFREQ)
-COMPATIBLE_IOCTL(SIOCGIWFREQ)
-COMPATIBLE_IOCTL(SIOCSIWMODE)
-COMPATIBLE_IOCTL(SIOCGIWMODE)
-COMPATIBLE_IOCTL(SIOCSIWSENS)
-COMPATIBLE_IOCTL(SIOCGIWSENS)
-COMPATIBLE_IOCTL(SIOCSIWRANGE)
-COMPATIBLE_IOCTL(SIOCSIWPRIV)
-COMPATIBLE_IOCTL(SIOCGIWPRIV)
-COMPATIBLE_IOCTL(SIOCSIWSTATS)
-COMPATIBLE_IOCTL(SIOCGIWSTATS)
-COMPATIBLE_IOCTL(SIOCSIWAP)
-COMPATIBLE_IOCTL(SIOCGIWAP)
-COMPATIBLE_IOCTL(SIOCSIWSCAN)
-COMPATIBLE_IOCTL(SIOCSIWRATE)
-COMPATIBLE_IOCTL(SIOCGIWRATE)
-COMPATIBLE_IOCTL(SIOCSIWRTS)
-COMPATIBLE_IOCTL(SIOCGIWRTS)
-COMPATIBLE_IOCTL(SIOCSIWFRAG)
-COMPATIBLE_IOCTL(SIOCGIWFRAG)
-COMPATIBLE_IOCTL(SIOCSIWTXPOW)
-COMPATIBLE_IOCTL(SIOCGIWTXPOW)
-COMPATIBLE_IOCTL(SIOCSIWRETRY)
-COMPATIBLE_IOCTL(SIOCGIWRETRY)
-COMPATIBLE_IOCTL(SIOCSIWPOWER)
-COMPATIBLE_IOCTL(SIOCGIWPOWER)
-/* hiddev */
-COMPATIBLE_IOCTL(HIDIOCGVERSION)
-COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
-COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
-COMPATIBLE_IOCTL(HIDIOCGSTRING)
-COMPATIBLE_IOCTL(HIDIOCINITREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORT)
-COMPATIBLE_IOCTL(HIDIOCSREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
-COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
-COMPATIBLE_IOCTL(HIDIOCGUSAGE)
-COMPATIBLE_IOCTL(HIDIOCSUSAGE)
-COMPATIBLE_IOCTL(HIDIOCGUCODE)
-COMPATIBLE_IOCTL(HIDIOCGFLAG)
-COMPATIBLE_IOCTL(HIDIOCSFLAG)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
-/* dvb */
-COMPATIBLE_IOCTL(AUDIO_STOP)
-COMPATIBLE_IOCTL(AUDIO_PLAY)
-COMPATIBLE_IOCTL(AUDIO_PAUSE)
-COMPATIBLE_IOCTL(AUDIO_CONTINUE)
-COMPATIBLE_IOCTL(AUDIO_SELECT_SOURCE)
-COMPATIBLE_IOCTL(AUDIO_SET_MUTE)
-COMPATIBLE_IOCTL(AUDIO_SET_AV_SYNC)
-COMPATIBLE_IOCTL(AUDIO_SET_BYPASS_MODE)
-COMPATIBLE_IOCTL(AUDIO_CHANNEL_SELECT)
-COMPATIBLE_IOCTL(AUDIO_GET_STATUS)
-COMPATIBLE_IOCTL(AUDIO_GET_CAPABILITIES)
-COMPATIBLE_IOCTL(AUDIO_CLEAR_BUFFER)
-COMPATIBLE_IOCTL(AUDIO_SET_ID)
-COMPATIBLE_IOCTL(AUDIO_SET_MIXER)
-COMPATIBLE_IOCTL(AUDIO_SET_STREAMTYPE)
-COMPATIBLE_IOCTL(AUDIO_SET_EXT_ID)
-COMPATIBLE_IOCTL(AUDIO_SET_ATTRIBUTES)
-COMPATIBLE_IOCTL(AUDIO_SET_KARAOKE)
-COMPATIBLE_IOCTL(DMX_START)
-COMPATIBLE_IOCTL(DMX_STOP)
-COMPATIBLE_IOCTL(DMX_SET_FILTER)
-COMPATIBLE_IOCTL(DMX_SET_PES_FILTER)
-COMPATIBLE_IOCTL(DMX_SET_BUFFER_SIZE)
-COMPATIBLE_IOCTL(DMX_GET_PES_PIDS)
-COMPATIBLE_IOCTL(DMX_GET_CAPS)
-COMPATIBLE_IOCTL(DMX_SET_SOURCE)
-COMPATIBLE_IOCTL(DMX_GET_STC)
-COMPATIBLE_IOCTL(FE_GET_INFO)
-COMPATIBLE_IOCTL(FE_DISEQC_RESET_OVERLOAD)
-COMPATIBLE_IOCTL(FE_DISEQC_SEND_MASTER_CMD)
-COMPATIBLE_IOCTL(FE_DISEQC_RECV_SLAVE_REPLY)
-COMPATIBLE_IOCTL(FE_DISEQC_SEND_BURST)
-COMPATIBLE_IOCTL(FE_SET_TONE)
-COMPATIBLE_IOCTL(FE_SET_VOLTAGE)
-COMPATIBLE_IOCTL(FE_ENABLE_HIGH_LNB_VOLTAGE)
-COMPATIBLE_IOCTL(FE_READ_STATUS)
-COMPATIBLE_IOCTL(FE_READ_BER)
-COMPATIBLE_IOCTL(FE_READ_SIGNAL_STRENGTH)
-COMPATIBLE_IOCTL(FE_READ_SNR)
-COMPATIBLE_IOCTL(FE_READ_UNCORRECTED_BLOCKS)
-COMPATIBLE_IOCTL(FE_SET_FRONTEND)
-COMPATIBLE_IOCTL(FE_GET_FRONTEND)
-COMPATIBLE_IOCTL(FE_GET_EVENT)
-COMPATIBLE_IOCTL(FE_DISHNETWORK_SEND_LEGACY_CMD)
-COMPATIBLE_IOCTL(VIDEO_STOP)
-COMPATIBLE_IOCTL(VIDEO_PLAY)
-COMPATIBLE_IOCTL(VIDEO_FREEZE)
-COMPATIBLE_IOCTL(VIDEO_CONTINUE)
-COMPATIBLE_IOCTL(VIDEO_SELECT_SOURCE)
-COMPATIBLE_IOCTL(VIDEO_SET_BLANK)
-COMPATIBLE_IOCTL(VIDEO_GET_STATUS)
-COMPATIBLE_IOCTL(VIDEO_SET_DISPLAY_FORMAT)
-COMPATIBLE_IOCTL(VIDEO_FAST_FORWARD)
-COMPATIBLE_IOCTL(VIDEO_SLOWMOTION)
-COMPATIBLE_IOCTL(VIDEO_GET_CAPABILITIES)
-COMPATIBLE_IOCTL(VIDEO_CLEAR_BUFFER)
-COMPATIBLE_IOCTL(VIDEO_SET_ID)
-COMPATIBLE_IOCTL(VIDEO_SET_STREAMTYPE)
-COMPATIBLE_IOCTL(VIDEO_SET_FORMAT)
-COMPATIBLE_IOCTL(VIDEO_SET_SYSTEM)
-COMPATIBLE_IOCTL(VIDEO_SET_HIGHLIGHT)
-COMPATIBLE_IOCTL(VIDEO_SET_SPU)
-COMPATIBLE_IOCTL(VIDEO_GET_NAVI)
-COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES)
-COMPATIBLE_IOCTL(VIDEO_GET_SIZE)
-COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE)
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 9008eab..a9f7947 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -22,6 +22,9 @@ #define RELOC_HIDE(ptr, off)					\
     __asm__ ("" : "=r"(__ptr) : "0"(ptr));		\
     (typeof(ptr)) (__ptr + (off)); })
 
+/* &a[0] degrades to a pointer: a different type from an array */
+#define __must_be_array(a) \
+  BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
 
 #define inline		inline		__attribute__((always_inline))
 #define __inline__	__inline__	__attribute__((always_inline))
diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
index 1698b84..ecd621f 100644
--- a/include/linux/compiler-gcc3.h
+++ b/include/linux/compiler-gcc3.h
@@ -13,4 +13,10 @@ #if __GNUC_MINOR__ >= 4
 #define __must_check		__attribute__((warn_unused_result))
 #endif
 
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
+
 #define __always_inline		inline __attribute__((always_inline))
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 6f5cc6f..fd0cc7c 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -16,3 +16,9 @@ #define __attribute_used__	__attribute__
 #define __must_check 		__attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
 #define __always_inline		inline __attribute__((always_inline))
+
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h
index 1d1c3ce..b769961 100644
--- a/include/linux/compiler-intel.h
+++ b/include/linux/compiler-intel.h
@@ -21,4 +21,9 @@ #define RELOC_HIDE(ptr, off)					\
      __ptr = (unsigned long) (ptr);				\
     (typeof(ptr)) (__ptr + (off)); })
 
+/* Intel ECC compiler doesn't support __builtin_types_compatible_p() */
+#define __must_be_array(a) 0
+
 #endif
+
+#define uninitialized_var(x) x
diff --git a/include/linux/console.h b/include/linux/console.h
index de25ee3..62ef6e1 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -51,7 +51,7 @@ struct consw {
 	int	(*con_scrolldelta)(struct vc_data *, int);
 	int	(*con_set_origin)(struct vc_data *);
 	void	(*con_save_screen)(struct vc_data *);
-	u8	(*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8);
+	u8	(*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);
 	void	(*con_invert_region)(struct vc_data *, u16 *, int);
 	u16    *(*con_screen_pos)(struct vc_data *, int);
 	unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
@@ -92,9 +92,8 @@ #define CON_ENABLED	(4)
 #define CON_BOOT	(8)
 #define CON_ANYTIME	(16) /* Safe to call when cpu is offline */
 
-struct console
-{
-	char	name[8];
+struct console {
+	char	name[16];
 	void	(*write)(struct console *, const char *, unsigned);
 	int	(*read)(struct console *, char *, unsigned);
 	struct tty_driver *(*device)(struct console *, int *);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index a86162b..a461f76 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -37,6 +37,7 @@ struct vc_data {
 	unsigned char	vc_color;		/* Foreground & background */
 	unsigned char	vc_s_color;		/* Saved foreground & background */
 	unsigned char	vc_ulcolor;		/* Color for underline mode */
+	unsigned char   vc_itcolor;
 	unsigned char	vc_halfcolor;		/* Color for half intensity mode */
 	/* cursor */
 	unsigned int	vc_cursor_type;
@@ -71,10 +72,12 @@ struct vc_data {
 	unsigned int	vc_deccolm	: 1;	/* 80/132 Column Mode */
 	/* attribute flags */
 	unsigned int	vc_intensity	: 2;	/* 0=half-bright, 1=normal, 2=bold */
+	unsigned int    vc_italic:1;
 	unsigned int	vc_underline	: 1;
 	unsigned int	vc_blink	: 1;
 	unsigned int	vc_reverse	: 1;
 	unsigned int	vc_s_intensity	: 2;	/* saved rendition */
+	unsigned int    vc_s_italic:1;
 	unsigned int	vc_s_underline	: 1;
 	unsigned int	vc_s_blink	: 1;
 	unsigned int	vc_s_reverse	: 1;
diff --git a/include/linux/const.h b/include/linux/const.h
new file mode 100644
index 0000000..07b300b
--- /dev/null
+++ b/include/linux/const.h
@@ -0,0 +1,19 @@
+/* const.h: Macros for dealing with constants.  */
+
+#ifndef _LINUX_CONST_H
+#define _LINUX_CONST_H
+
+/* Some constant macros are used in both assembler and
+ * C code.  Therefore we cannot annotate them always with
+ * 'UL' and other type specifiers unilaterally.  We
+ * use the following macros to deal with this.
+ */
+
+#ifdef __ASSEMBLY__
+#define _AC(X,Y)	X
+#else
+#define __AC(X,Y)	(X##Y)
+#define _AC(X,Y)	__AC(X,Y)
+#endif
+
+#endif /* !(_LINUX_CONST_H) */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index c22b0df..3b2df25 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -41,6 +41,9 @@ extern void cpu_remove_sysdev_attr(struc
 extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs);
 extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs);
 
+extern struct sysdev_attribute attr_sched_mc_power_savings;
+extern struct sysdev_attribute attr_sched_smt_power_savings;
+extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
 
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 0899e2c..963051a 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -32,7 +32,15 @@ #define CPUFREQ_NAME_LEN 16
  *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
 
+#ifdef CONFIG_CPU_FREQ
 int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+#else
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+						unsigned int list)
+{
+	return 0;
+}
+#endif
 int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
 
 #define CPUFREQ_TRANSITION_NOTIFIER	(0)
@@ -257,21 +265,25 @@ struct freq_attr {
 /*********************************************************************
  *                        CPUFREQ 2.6. INTERFACE                     *
  *********************************************************************/
-int cpufreq_set_policy(struct cpufreq_policy *policy);
 int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
 int cpufreq_update_policy(unsigned int cpu);
 
-/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
-unsigned int cpufreq_get(unsigned int cpu);
 
-/* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */
+/*
+ * query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it
+ */
 #ifdef CONFIG_CPU_FREQ
 unsigned int cpufreq_quick_get(unsigned int cpu);
+unsigned int cpufreq_get(unsigned int cpu);
 #else
 static inline unsigned int cpufreq_quick_get(unsigned int cpu)
 {
 	return 0;
 }
+static inline unsigned int cpufreq_get(unsigned int cpu)
+{
+	return 0;
+}
 #endif
 
 
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 3250365..22c7ac5 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -14,5 +14,13 @@ extern ssize_t copy_oldmem_page(unsigned
 extern const struct file_operations proc_vmcore_operations;
 extern struct proc_dir_entry *proc_vmcore;
 
+/* Architecture code defines this if there are other possible ELF
+ * machine types, e.g. on bi-arch capable hardware. */
+#ifndef vmcore_elf_check_arch_cross
+#define vmcore_elf_check_arch_cross(x) 0
+#endif
+
+#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x))
+
 #endif /* CONFIG_CRASH_DUMP */
 #endif /* LINUX_CRASHDUMP_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 779aa78..0de7e2a 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -56,6 +56,7 @@ #define CRYPTO_TFM_RES_MASK		0xfff00000
 
 #define CRYPTO_TFM_REQ_WEAK_KEY		0x00000100
 #define CRYPTO_TFM_REQ_MAY_SLEEP	0x00000200
+#define CRYPTO_TFM_REQ_MAY_BACKLOG	0x00000400
 #define CRYPTO_TFM_RES_WEAK_KEY		0x00100000
 #define CRYPTO_TFM_RES_BAD_KEY_LEN   	0x00200000
 #define CRYPTO_TFM_RES_BAD_KEY_SCHED 	0x00400000
@@ -88,11 +89,38 @@ #define CRYPTO_MINALIGN_ATTR
 #endif
 
 struct scatterlist;
+struct crypto_ablkcipher;
+struct crypto_async_request;
 struct crypto_blkcipher;
 struct crypto_hash;
+struct crypto_queue;
 struct crypto_tfm;
 struct crypto_type;
 
+typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err);
+
+struct crypto_async_request {
+	struct list_head list;
+	crypto_completion_t complete;
+	void *data;
+	struct crypto_tfm *tfm;
+
+	u32 flags;
+};
+
+struct ablkcipher_request {
+	struct crypto_async_request base;
+
+	unsigned int nbytes;
+
+	void *info;
+
+	struct scatterlist *src;
+	struct scatterlist *dst;
+
+	void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
 struct blkcipher_desc {
 	struct crypto_blkcipher *tfm;
 	void *info;
@@ -116,6 +144,19 @@ struct hash_desc {
  * Algorithms: modular crypto algorithm implementations, managed
  * via crypto_register_alg() and crypto_unregister_alg().
  */
+struct ablkcipher_alg {
+	int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+	              unsigned int keylen);
+	int (*encrypt)(struct ablkcipher_request *req);
+	int (*decrypt)(struct ablkcipher_request *req);
+
+	struct crypto_queue *queue;
+
+	unsigned int min_keysize;
+	unsigned int max_keysize;
+	unsigned int ivsize;
+};
+
 struct blkcipher_alg {
 	int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
 	              unsigned int keylen);
@@ -170,6 +211,7 @@ struct compress_alg {
 			      unsigned int slen, u8 *dst, unsigned int *dlen);
 };
 
+#define cra_ablkcipher	cra_u.ablkcipher
 #define cra_blkcipher	cra_u.blkcipher
 #define cra_cipher	cra_u.cipher
 #define cra_digest	cra_u.digest
@@ -194,6 +236,7 @@ struct crypto_alg {
 	const struct crypto_type *cra_type;
 
 	union {
+		struct ablkcipher_alg ablkcipher;
 		struct blkcipher_alg blkcipher;
 		struct cipher_alg cipher;
 		struct digest_alg digest;
@@ -232,6 +275,15 @@ #endif
  * crypto_free_*(), as well as the various helpers below.
  */
 
+struct ablkcipher_tfm {
+	int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+	              unsigned int keylen);
+	int (*encrypt)(struct ablkcipher_request *req);
+	int (*decrypt)(struct ablkcipher_request *req);
+	unsigned int ivsize;
+	unsigned int reqsize;
+};
+
 struct blkcipher_tfm {
 	void *iv;
 	int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
@@ -290,6 +342,7 @@ struct compress_tfm {
 	                      u8 *dst, unsigned int *dlen);
 };
 
+#define crt_ablkcipher	crt_u.ablkcipher
 #define crt_blkcipher	crt_u.blkcipher
 #define crt_cipher	crt_u.cipher
 #define crt_hash	crt_u.hash
@@ -300,6 +353,7 @@ struct crypto_tfm {
 	u32 crt_flags;
 	
 	union {
+		struct ablkcipher_tfm ablkcipher;
 		struct blkcipher_tfm blkcipher;
 		struct cipher_tfm cipher;
 		struct hash_tfm hash;
@@ -311,6 +365,10 @@ struct crypto_tfm {
 	void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
+struct crypto_ablkcipher {
+	struct crypto_tfm base;
+};
+
 struct crypto_blkcipher {
 	struct crypto_tfm base;
 };
@@ -330,12 +388,21 @@ struct crypto_hash {
 enum {
 	CRYPTOA_UNSPEC,
 	CRYPTOA_ALG,
+	CRYPTOA_TYPE,
+	__CRYPTOA_MAX,
 };
 
+#define CRYPTOA_MAX (__CRYPTOA_MAX - 1)
+
 struct crypto_attr_alg {
 	char name[CRYPTO_MAX_ALG_NAME];
 };
 
+struct crypto_attr_type {
+	u32 type;
+	u32 mask;
+};
+
 /* 
  * Transform user interface.
  */
@@ -411,6 +478,167 @@ static inline unsigned int crypto_tfm_ct
 /*
  * API wrappers.
  */
+static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast(
+	struct crypto_tfm *tfm)
+{
+	return (struct crypto_ablkcipher *)tfm;
+}
+
+static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher(
+	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_ablkcipher_cast(
+		crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_ablkcipher_tfm(
+	struct crypto_ablkcipher *tfm)
+{
+	return &tfm->base;
+}
+
+static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm)
+{
+	crypto_free_tfm(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline int crypto_has_ablkcipher(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 struct ablkcipher_tfm *crypto_ablkcipher_crt(
+	struct crypto_ablkcipher *tfm)
+{
+	return &crypto_ablkcipher_tfm(tfm)->crt_ablkcipher;
+}
+
+static inline unsigned int crypto_ablkcipher_ivsize(
+	struct crypto_ablkcipher *tfm)
+{
+	return crypto_ablkcipher_crt(tfm)->ivsize;
+}
+
+static inline unsigned int crypto_ablkcipher_blocksize(
+	struct crypto_ablkcipher *tfm)
+{
+	return crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline unsigned int crypto_ablkcipher_alignmask(
+	struct crypto_ablkcipher *tfm)
+{
+	return crypto_tfm_alg_alignmask(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline u32 crypto_ablkcipher_get_flags(struct crypto_ablkcipher *tfm)
+{
+	return crypto_tfm_get_flags(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline void crypto_ablkcipher_set_flags(struct crypto_ablkcipher *tfm,
+					       u32 flags)
+{
+	crypto_tfm_set_flags(crypto_ablkcipher_tfm(tfm), flags);
+}
+
+static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm,
+						 u32 flags)
+{
+	crypto_tfm_clear_flags(crypto_ablkcipher_tfm(tfm), flags);
+}
+
+static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+					   const u8 *key, unsigned int keylen)
+{
+	return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen);
+}
+
+static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
+	struct ablkcipher_request *req)
+{
+	return __crypto_ablkcipher_cast(req->base.tfm);
+}
+
+static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+	return crt->encrypt(req);
+}
+
+static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+	struct ablkcipher_tfm *crt =
+		crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+	return crt->decrypt(req);
+}
+
+static inline int crypto_ablkcipher_reqsize(struct crypto_ablkcipher *tfm)
+{
+	return crypto_ablkcipher_crt(tfm)->reqsize;
+}
+
+static inline void ablkcipher_request_set_tfm(
+	struct ablkcipher_request *req, struct crypto_ablkcipher *tfm)
+{
+	req->base.tfm = crypto_ablkcipher_tfm(tfm);
+}
+
+static inline struct ablkcipher_request *ablkcipher_request_cast(
+	struct crypto_async_request *req)
+{
+	return container_of(req, struct ablkcipher_request, base);
+}
+
+static inline struct ablkcipher_request *ablkcipher_request_alloc(
+	struct crypto_ablkcipher *tfm, gfp_t gfp)
+{
+	struct ablkcipher_request *req;
+
+	req = kmalloc(sizeof(struct ablkcipher_request) +
+		      crypto_ablkcipher_reqsize(tfm), gfp);
+
+	if (likely(req))
+		ablkcipher_request_set_tfm(req, tfm);
+
+	return req;
+}
+
+static inline void ablkcipher_request_free(struct ablkcipher_request *req)
+{
+	kfree(req);
+}
+
+static inline void ablkcipher_request_set_callback(
+	struct ablkcipher_request *req,
+	u32 flags, crypto_completion_t complete, void *data)
+{
+	req->base.complete = complete;
+	req->base.data = data;
+	req->base.flags = flags;
+}
+
+static inline void ablkcipher_request_set_crypt(
+	struct ablkcipher_request *req,
+	struct scatterlist *src, struct scatterlist *dst,
+	unsigned int nbytes, void *iv)
+{
+	req->src = src;
+	req->dst = dst;
+	req->nbytes = nbytes;
+	req->info = iv;
+}
+
 static inline struct crypto_blkcipher *__crypto_blkcipher_cast(
 	struct crypto_tfm *tfm)
 {
@@ -427,9 +655,9 @@ static inline struct crypto_blkcipher *c
 static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
 	const char *alg_name, u32 type, u32 mask)
 {
-	type &= ~CRYPTO_ALG_TYPE_MASK;
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK;
+	mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
 
 	return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
 }
@@ -447,9 +675,9 @@ static inline void crypto_free_blkcipher
 
 static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
 {
-	type &= ~CRYPTO_ALG_TYPE_MASK;
+	type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
 	type |= CRYPTO_ALG_TYPE_BLKCIPHER;
-	mask |= CRYPTO_ALG_TYPE_MASK;
+	mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
 
 	return crypto_has_alg(alg_name, type, mask);
 }
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index 46d8254..72aa00c 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -67,6 +67,8 @@
 #ifndef _LINUX_CYCLADES_H
 #define _LINUX_CYCLADES_H
 
+#include <linux/types.h>
+
 struct cyclades_monitor {
         unsigned long           int_count;
         unsigned long           char_count;
@@ -108,7 +110,6 @@ #define CYGETRTSDTR_INV		0x43590d
 #define CYZSETPOLLCYCLE		0x43590e
 #define CYZGETPOLLCYCLE		0x43590f
 #define CYGETCD1400VER		0x435910
-#define CYGETCARDINFO		0x435911
 #define	CYSETWAIT		0x435912
 #define	CYGETWAIT		0x435913
 
@@ -149,14 +150,12 @@ #ifndef DP_WINDOW_SIZE
  *	architectures and compilers.
  */
 
-#if defined(__alpha__)
-typedef unsigned long	ucdouble;	/* 64 bits, unsigned */
-typedef unsigned int	uclong;		/* 32 bits, unsigned */
-#else
-typedef unsigned long	uclong;		/* 32 bits, unsigned */
-#endif
-typedef unsigned short	ucshort;	/* 16 bits, unsigned */
-typedef unsigned char	ucchar;		/* 8 bits, unsigned */
+#include <asm/types.h>
+
+typedef __u64  ucdouble;		/* 64 bits, unsigned */
+typedef __u32  uclong;			/* 32 bits, unsigned */
+typedef __u16  ucshort;		/* 16 bits, unsigned */
+typedef __u8   ucchar;			/* 8 bits, unsigned */
 
 /*
  *	Memory Window Sizes
@@ -174,24 +173,24 @@ #define	CTRL_WINDOW_SIZE	(0x00000080)	/*
  */
 
 struct	CUSTOM_REG {
-	uclong	fpga_id;		/* FPGA Identification Register */
-	uclong	fpga_version;		/* FPGA Version Number Register */
-	uclong	cpu_start;		/* CPU start Register (write) */
-	uclong	cpu_stop;		/* CPU stop Register (write) */
-	uclong	misc_reg;		/* Miscelaneous Register */
-	uclong	idt_mode;		/* IDT mode Register */
-	uclong	uart_irq_status;	/* UART IRQ status Register */
-	uclong	clear_timer0_irq;	/* Clear timer interrupt Register */
-	uclong	clear_timer1_irq;	/* Clear timer interrupt Register */
-	uclong	clear_timer2_irq;	/* Clear timer interrupt Register */
-	uclong	test_register;		/* Test Register */
-	uclong	test_count;		/* Test Count Register */
-	uclong	timer_select;		/* Timer select register */
-	uclong	pr_uart_irq_status;	/* Prioritized UART IRQ stat Reg */
-	uclong	ram_wait_state;		/* RAM wait-state Register */
-	uclong	uart_wait_state;	/* UART wait-state Register */
-	uclong	timer_wait_state;	/* timer wait-state Register */
-	uclong	ack_wait_state;		/* ACK wait State Register */
+	__u32	fpga_id;		/* FPGA Identification Register */
+	__u32	fpga_version;		/* FPGA Version Number Register */
+	__u32	cpu_start;		/* CPU start Register (write) */
+	__u32	cpu_stop;		/* CPU stop Register (write) */
+	__u32	misc_reg;		/* Miscelaneous Register */
+	__u32	idt_mode;		/* IDT mode Register */
+	__u32	uart_irq_status;	/* UART IRQ status Register */
+	__u32	clear_timer0_irq;	/* Clear timer interrupt Register */
+	__u32	clear_timer1_irq;	/* Clear timer interrupt Register */
+	__u32	clear_timer2_irq;	/* Clear timer interrupt Register */
+	__u32	test_register;		/* Test Register */
+	__u32	test_count;		/* Test Count Register */
+	__u32	timer_select;		/* Timer select register */
+	__u32	pr_uart_irq_status;	/* Prioritized UART IRQ stat Reg */
+	__u32	ram_wait_state;		/* RAM wait-state Register */
+	__u32	uart_wait_state;	/* UART wait-state Register */
+	__u32	timer_wait_state;	/* timer wait-state Register */
+	__u32	ack_wait_state;		/* ACK wait State Register */
 };
 
 /*
@@ -201,34 +200,34 @@ struct	CUSTOM_REG {
  */
 
 struct RUNTIME_9060 {
-	uclong	loc_addr_range;	/* 00h - Local Address Range */
-	uclong	loc_addr_base;	/* 04h - Local Address Base */
-	uclong	loc_arbitr;	/* 08h - Local Arbitration */
-	uclong	endian_descr;	/* 0Ch - Big/Little Endian Descriptor */
-	uclong	loc_rom_range;	/* 10h - Local ROM Range */
-	uclong	loc_rom_base;	/* 14h - Local ROM Base */
-	uclong	loc_bus_descr;	/* 18h - Local Bus descriptor */
-	uclong	loc_range_mst;	/* 1Ch - Local Range for Master to PCI */
-	uclong	loc_base_mst;	/* 20h - Local Base for Master PCI */
-	uclong	loc_range_io;	/* 24h - Local Range for Master IO */
-	uclong	pci_base_mst;	/* 28h - PCI Base for Master PCI */
-	uclong	pci_conf_io;	/* 2Ch - PCI configuration for Master IO */
-	uclong	filler1;	/* 30h */
-	uclong	filler2;	/* 34h */
-	uclong	filler3;	/* 38h */
-	uclong	filler4;	/* 3Ch */
-	uclong	mail_box_0;	/* 40h - Mail Box 0 */
-	uclong	mail_box_1;	/* 44h - Mail Box 1 */
-	uclong	mail_box_2;	/* 48h - Mail Box 2 */
-	uclong	mail_box_3;	/* 4Ch - Mail Box 3 */
-	uclong	filler5;	/* 50h */
-	uclong	filler6;	/* 54h */
-	uclong	filler7;	/* 58h */
-	uclong	filler8;	/* 5Ch */
-	uclong	pci_doorbell;	/* 60h - PCI to Local Doorbell */
-	uclong	loc_doorbell;	/* 64h - Local to PCI Doorbell */
-	uclong	intr_ctrl_stat;	/* 68h - Interrupt Control/Status */
-	uclong	init_ctrl;	/* 6Ch - EEPROM control, Init Control, etc */
+	__u32	loc_addr_range;	/* 00h - Local Address Range */
+	__u32	loc_addr_base;	/* 04h - Local Address Base */
+	__u32	loc_arbitr;	/* 08h - Local Arbitration */
+	__u32	endian_descr;	/* 0Ch - Big/Little Endian Descriptor */
+	__u32	loc_rom_range;	/* 10h - Local ROM Range */
+	__u32	loc_rom_base;	/* 14h - Local ROM Base */
+	__u32	loc_bus_descr;	/* 18h - Local Bus descriptor */
+	__u32	loc_range_mst;	/* 1Ch - Local Range for Master to PCI */
+	__u32	loc_base_mst;	/* 20h - Local Base for Master PCI */
+	__u32	loc_range_io;	/* 24h - Local Range for Master IO */
+	__u32	pci_base_mst;	/* 28h - PCI Base for Master PCI */
+	__u32	pci_conf_io;	/* 2Ch - PCI configuration for Master IO */
+	__u32	filler1;	/* 30h */
+	__u32	filler2;	/* 34h */
+	__u32	filler3;	/* 38h */
+	__u32	filler4;	/* 3Ch */
+	__u32	mail_box_0;	/* 40h - Mail Box 0 */
+	__u32	mail_box_1;	/* 44h - Mail Box 1 */
+	__u32	mail_box_2;	/* 48h - Mail Box 2 */
+	__u32	mail_box_3;	/* 4Ch - Mail Box 3 */
+	__u32	filler5;	/* 50h */
+	__u32	filler6;	/* 54h */
+	__u32	filler7;	/* 58h */
+	__u32	filler8;	/* 5Ch */
+	__u32	pci_doorbell;	/* 60h - PCI to Local Doorbell */
+	__u32	loc_doorbell;	/* 64h - Local to PCI Doorbell */
+	__u32	intr_ctrl_stat;	/* 68h - Interrupt Control/Status */
+	__u32	init_ctrl;	/* 6Ch - EEPROM control, Init Control, etc */
 };
 
 /* Values for the Local Base Address re-map register */
@@ -270,8 +269,8 @@ #define	ZF_TINACT_DEF	1000		/* default i
 #define	ZF_TINACT	ZF_TINACT_DEF
 
 struct	FIRM_ID {
-	uclong	signature;		/* ZFIRM/U signature */
-	uclong	zfwctrl_addr;		/* pointer to ZFW_CTRL structure */
+	__u32	signature;		/* ZFIRM/U signature */
+	__u32	zfwctrl_addr;		/* pointer to ZFW_CTRL structure */
 };
 
 /* Op. System id */
@@ -408,24 +407,24 @@ #define	C_CM_HW_RESET	0x92		/* reset boa
  */
 
 struct CH_CTRL {
-	uclong	op_mode;	/* operation mode */
-	uclong	intr_enable;	/* interrupt masking */
-	uclong	sw_flow;	/* SW flow control */
-	uclong	flow_status;	/* output flow status */
-	uclong	comm_baud;	/* baud rate  - numerically specified */
-	uclong	comm_parity;	/* parity */
-	uclong	comm_data_l;	/* data length/stop */
-	uclong	comm_flags;	/* other flags */
-	uclong	hw_flow;	/* HW flow control */
-	uclong	rs_control;	/* RS-232 outputs */
-	uclong	rs_status;	/* RS-232 inputs */
-	uclong	flow_xon;	/* xon char */
-	uclong	flow_xoff;	/* xoff char */
-	uclong	hw_overflow;	/* hw overflow counter */
-	uclong	sw_overflow;	/* sw overflow counter */
-	uclong	comm_error;	/* frame/parity error counter */
-	uclong ichar;
-	uclong filler[7];
+	__u32	op_mode;	/* operation mode */
+	__u32	intr_enable;	/* interrupt masking */
+	__u32	sw_flow;	/* SW flow control */
+	__u32	flow_status;	/* output flow status */
+	__u32	comm_baud;	/* baud rate  - numerically specified */
+	__u32	comm_parity;	/* parity */
+	__u32	comm_data_l;	/* data length/stop */
+	__u32	comm_flags;	/* other flags */
+	__u32	hw_flow;	/* HW flow control */
+	__u32	rs_control;	/* RS-232 outputs */
+	__u32	rs_status;	/* RS-232 inputs */
+	__u32	flow_xon;	/* xon char */
+	__u32	flow_xoff;	/* xoff char */
+	__u32	hw_overflow;	/* hw overflow counter */
+	__u32	sw_overflow;	/* sw overflow counter */
+	__u32	comm_error;	/* frame/parity error counter */
+	__u32 ichar;
+	__u32 filler[7];
 };
 
 
@@ -435,18 +434,18 @@ struct CH_CTRL {
  */
 
 struct	BUF_CTRL	{
-	uclong	flag_dma;	/* buffers are in Host memory */
-	uclong	tx_bufaddr;	/* address of the tx buffer */
-	uclong	tx_bufsize;	/* tx buffer size */
-	uclong	tx_threshold;	/* tx low water mark */
-	uclong	tx_get;		/* tail index tx buf */
-	uclong	tx_put;		/* head index tx buf */
-	uclong	rx_bufaddr;	/* address of the rx buffer */
-	uclong	rx_bufsize;	/* rx buffer size */
-	uclong	rx_threshold;	/* rx high water mark */
-	uclong	rx_get;		/* tail index rx buf */
-	uclong	rx_put;		/* head index rx buf */
-	uclong	filler[5];	/* filler to align structures */
+	__u32	flag_dma;	/* buffers are in Host memory */
+	__u32	tx_bufaddr;	/* address of the tx buffer */
+	__u32	tx_bufsize;	/* tx buffer size */
+	__u32	tx_threshold;	/* tx low water mark */
+	__u32	tx_get;		/* tail index tx buf */
+	__u32	tx_put;		/* head index tx buf */
+	__u32	rx_bufaddr;	/* address of the rx buffer */
+	__u32	rx_bufsize;	/* rx buffer size */
+	__u32	rx_threshold;	/* rx high water mark */
+	__u32	rx_get;		/* tail index rx buf */
+	__u32	rx_put;		/* head index rx buf */
+	__u32	filler[5];	/* filler to align structures */
 };
 
 /*
@@ -457,27 +456,27 @@ struct	BUF_CTRL	{
 struct BOARD_CTRL {
 
 	/* static info provided by the on-board CPU */
-	uclong	n_channel;	/* number of channels */
-	uclong	fw_version;	/* firmware version */
+	__u32	n_channel;	/* number of channels */
+	__u32	fw_version;	/* firmware version */
 
 	/* static info provided by the driver */
-	uclong	op_system;	/* op_system id */
-	uclong	dr_version;	/* driver version */
+	__u32	op_system;	/* op_system id */
+	__u32	dr_version;	/* driver version */
 
 	/* board control area */
-	uclong	inactivity;	/* inactivity control */
+	__u32	inactivity;	/* inactivity control */
 
 	/* host to FW commands */
-	uclong	hcmd_channel;	/* channel number */
-	uclong	hcmd_param;	/* pointer to parameters */
+	__u32	hcmd_channel;	/* channel number */
+	__u32	hcmd_param;	/* pointer to parameters */
 
 	/* FW to Host commands */
-	uclong	fwcmd_channel;	/* channel number */
-	uclong	fwcmd_param;	/* pointer to parameters */
-	uclong	zf_int_queue_addr; /* offset for INT_QUEUE structure */
+	__u32	fwcmd_channel;	/* channel number */
+	__u32	fwcmd_param;	/* pointer to parameters */
+	__u32	zf_int_queue_addr; /* offset for INT_QUEUE structure */
 
 	/* filler so the structures are aligned */
-	uclong	filler[6];
+	__u32	filler[6];
 };
 
 /* Host Interrupt Queue */
@@ -506,11 +505,10 @@ struct ZFW_CTRL {
 /****************** ****************** *******************/
 #endif
 
+#ifdef __KERNEL__
+
 /* Per card data structure */
-struct resource;
 struct cyclades_card {
-    unsigned long base_phys;
-    unsigned long ctl_phys;
     void __iomem *base_addr;
     void __iomem *ctl_addr;
     int irq;
@@ -519,33 +517,18 @@ struct cyclades_card {
     int nports;		/* Number of ports in the card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
     int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
-    struct pci_dev *pdev;
-#ifdef __KERNEL__
     spinlock_t card_lock;
-#else
-    unsigned long filler;
-#endif
+    struct cyclades_port *ports;
 };
 
-struct cyclades_chip {
-  int filler;
-};
-
-
-#ifdef __KERNEL__
-
 /***************************************
  * Memory access functions/macros      *
  * (required to support Alpha systems) *
  ***************************************/
 
-#define cy_writeb(port,val)     {writeb((val),(port)); mb();}
-#define cy_writew(port,val)     {writew((val),(port)); mb();}
-#define cy_writel(port,val)     {writel((val),(port)); mb();}
-
-#define cy_readb(port)  readb(port)
-#define cy_readw(port)  readw(port)
-#define cy_readl(port)  readl(port)
+#define cy_writeb(port,val)     do { writeb((val), (port)); mb(); } while (0)
+#define cy_writew(port,val)     do { writew((val), (port)); mb(); } while (0)
+#define cy_writel(port,val)     do { writel((val), (port)); mb(); } while (0)
 
 /*
  * Statistics counters
@@ -567,7 +550,7 @@ struct cyclades_icount {
 
 struct cyclades_port {
 	int                     magic;
-	int			card;
+	struct cyclades_card	*card;
 	int			line;
 	int			flags; 		/* defined in tty.h */
 	int                     type;		/* UART type */
@@ -587,7 +570,6 @@ struct cyclades_port {
 	int			close_delay;
 	unsigned short		closing_wait;
 	unsigned long		event;
-	unsigned long		last_active;
 	int			count;	/* # of fd on device */
 	int                     breakon;
 	int                     breakoff;
@@ -598,7 +580,6 @@ struct cyclades_port {
 	int			xmit_cnt;
         int                     default_threshold;
         int                     default_timeout;
-	unsigned long		jiffies[3];
 	unsigned long		rflush_count;
 	struct cyclades_monitor	mon;
 	struct cyclades_idle_stats	idle_stats;
@@ -606,7 +587,7 @@ struct cyclades_port {
 	struct work_struct	tqueue;
 	wait_queue_head_t       open_wait;
 	wait_queue_head_t       close_wait;
-	wait_queue_head_t       shutdown_wait;
+	struct completion       shutdown_wait;
 	wait_queue_head_t       delta_msr_wait;
 	int throttle;
 };
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 63f64a9..aab53df 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -133,6 +133,7 @@ struct dentry_operations {
 	int (*d_delete)(struct dentry *);
 	void (*d_release)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
+	char *(*d_dname)(struct dentry *, char *, int);
 };
 
 /* the dentry parameter passed to d_hash and d_compare is the parent
@@ -293,6 +294,11 @@ extern struct dentry * d_hash_and_lookup
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
 
+/*
+ * helper function for dentry_operations.d_dname() members
+ */
+extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+
 extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
   
 /* Allocation counts.. */
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 1cb054b..fda2148 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -260,19 +260,20 @@ enum {
 
 static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb)
 {
-	return (struct dccp_hdr *)skb->h.raw;
+	return (struct dccp_hdr *)skb_transport_header(skb);
 }
 
 static inline struct dccp_hdr *dccp_zeroed_hdr(struct sk_buff *skb, int headlen)
 {
-	skb->h.raw = skb_push(skb, headlen);
-	memset(skb->h.raw, 0, headlen);
-	return dccp_hdr(skb);
+	skb_push(skb, headlen);
+	skb_reset_transport_header(skb);
+	return memset(skb_transport_header(skb), 0, headlen);
 }
 
 static inline struct dccp_hdr_ext *dccp_hdrx(const struct sk_buff *skb)
 {
-	return (struct dccp_hdr_ext *)(skb->h.raw + sizeof(struct dccp_hdr));
+	return (struct dccp_hdr_ext *)(skb_transport_header(skb) +
+				       sizeof(struct dccp_hdr));
 }
 
 static inline unsigned int __dccp_basic_hdr_len(const struct dccp_hdr *dh)
@@ -301,12 +302,14 @@ static inline __u64 dccp_hdr_seq(const s
 
 static inline struct dccp_hdr_request *dccp_hdr_request(struct sk_buff *skb)
 {
-	return (struct dccp_hdr_request *)(skb->h.raw + dccp_basic_hdr_len(skb));
+	return (struct dccp_hdr_request *)(skb_transport_header(skb) +
+					   dccp_basic_hdr_len(skb));
 }
 
 static inline struct dccp_hdr_ack_bits *dccp_hdr_ack_bits(const struct sk_buff *skb)
 {
-	return (struct dccp_hdr_ack_bits *)(skb->h.raw + dccp_basic_hdr_len(skb));
+	return (struct dccp_hdr_ack_bits *)(skb_transport_header(skb) +
+					    dccp_basic_hdr_len(skb));
 }
 
 static inline u64 dccp_hdr_ack_seq(const struct sk_buff *skb)
@@ -317,12 +320,14 @@ static inline u64 dccp_hdr_ack_seq(const
 
 static inline struct dccp_hdr_response *dccp_hdr_response(struct sk_buff *skb)
 {
-	return (struct dccp_hdr_response *)(skb->h.raw + dccp_basic_hdr_len(skb));
+	return (struct dccp_hdr_response *)(skb_transport_header(skb) +
+					    dccp_basic_hdr_len(skb));
 }
 
 static inline struct dccp_hdr_reset *dccp_hdr_reset(struct sk_buff *skb)
 {
-	return (struct dccp_hdr_reset *)(skb->h.raw + dccp_basic_hdr_len(skb));
+	return (struct dccp_hdr_reset *)(skb_transport_header(skb) +
+					 dccp_basic_hdr_len(skb));
 }
 
 static inline unsigned int __dccp_hdr_len(const struct dccp_hdr *dh)
@@ -460,26 +465,27 @@ struct dccp_ackvec;
  * @dccps_service_list - second .. last service code on passive socket
  * @dccps_timestamp_time - time of latest TIMESTAMP option
  * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option
- * @dccps_l_ack_ratio -
- * @dccps_r_ack_ratio -
+ * @dccps_l_ack_ratio - feature-local Ack Ratio
+ * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
- * @dccps_mss_cache -
- * @dccps_minisock -
+ * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
+ * @dccps_minisock - associated minisock (accessed via dccp_msk)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
- * @dccps_hc_rx_ccid -
- * @dccps_hc_tx_ccid -
- * @dccps_options_received -
- * @dccps_epoch -
- * @dccps_role - Role of this sock, one of %dccp_role
- * @dccps_hc_rx_insert_options -
- * @dccps_hc_tx_insert_options -
+ * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
+ * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
+ * @dccps_options_received - parsed set of retrieved options
+ * @dccps_role - role of this sock, one of %dccp_role
+ * @dccps_hc_rx_insert_options - receiver wants to add options when acking
+ * @dccps_hc_tx_insert_options - sender wants to add options when sending
  * @dccps_xmit_timer - timer for when CCID is not ready to send
+ * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs)
  */
 struct dccp_sock {
 	/* inet_connection_sock has to be the first member of dccp_sock */
 	struct inet_connection_sock	dccps_inet_connection;
+#define dccps_syn_rtt			dccps_inet_connection.icsk_ack.lrcvtime
 	__u64				dccps_swl;
 	__u64				dccps_swh;
 	__u64				dccps_awl;
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 9fa0983..5a9c495 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -44,6 +44,8 @@ struct dentry *debugfs_create_u16(const 
 				  struct dentry *parent, u16 *value);
 struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+				  struct dentry *parent, u64 *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
 
@@ -104,6 +106,13 @@ static inline struct dentry *debugfs_cre
 	return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+						struct dentry *parent,
+						u64 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 						 struct dentry *parent,
 						 u32 *value)
diff --git a/include/linux/device.h b/include/linux/device.h
index 5cf30e9..2e1a298 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -34,11 +34,26 @@ struct device;
 struct device_driver;
 struct class;
 struct class_device;
+struct bus_type;
+
+struct bus_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct bus_type *, char * buf);
+	ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
+};
+
+#define BUS_ATTR(_name,_mode,_show,_store)	\
+struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+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 bus_type {
 	const char		* name;
+	struct module		* owner;
 
-	struct subsystem	subsys;
+	struct kset		subsys;
 	struct kset		drivers;
 	struct kset		devices;
 	struct klist		klist_devices;
@@ -49,6 +64,8 @@ struct bus_type {
 	struct bus_attribute	* bus_attrs;
 	struct device_attribute	* dev_attrs;
 	struct driver_attribute	* drv_attrs;
+	struct bus_attribute drivers_autoprobe_attr;
+	struct bus_attribute drivers_probe_attr;
 
 	int		(*match)(struct device * dev, struct device_driver * drv);
 	int		(*uevent)(struct device *dev, char **envp,
@@ -61,6 +78,8 @@ struct bus_type {
 	int (*suspend_late)(struct device * dev, pm_message_t state);
 	int (*resume_early)(struct device * dev);
 	int (*resume)(struct device * dev);
+
+	unsigned int drivers_autoprobe:1;
 };
 
 extern int __must_check bus_register(struct bus_type * bus);
@@ -102,26 +121,10 @@ #define BUS_NOTIFY_BOUND_DRIVER		0x00000
 #define BUS_NOTIFY_UNBIND_DRIVER	0x00000004 /* driver about to be
 						      unbound */
 
-/* sysfs interface for exporting bus attributes */
-
-struct bus_attribute {
-	struct attribute	attr;
-	ssize_t (*show)(struct bus_type *, char * buf);
-	ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
-};
-
-#define BUS_ATTR(_name,_mode,_show,_store)	\
-struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
-
-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 {
 	const char		* name;
 	struct bus_type		* bus;
 
-	struct completion	unloaded;
 	struct kobject		kobj;
 	struct klist		klist_devices;
 	struct klist_node	knode_bus;
@@ -135,8 +138,6 @@ 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;
 };
 
 
@@ -177,14 +178,13 @@ struct class {
 	const char		* name;
 	struct module		* owner;
 
-	struct subsystem	subsys;
+	struct kset		subsys;
 	struct list_head	children;
 	struct list_head	devices;
 	struct list_head	interfaces;
+	struct kset		class_dirs;
 	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;
@@ -328,11 +328,23 @@ extern struct class_device *class_device
 					__attribute__((format(printf,5,6)));
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
+/*
+ * The type of device, "struct device" is embedded in. A class
+ * or bus can contain devices of different types
+ * like "partitions" and "disks", "mouse" and "event".
+ * This identifies the device type and carries type-specific
+ * information, equivalent to the kobj_type of a kobject.
+ * If "name" is specified, the uevent will contain it in
+ * the DEVTYPE variable.
+ */
 struct device_type {
-	struct device_attribute *attrs;
+	const char *name;
+	struct attribute_group **groups;
 	int (*uevent)(struct device *dev, char **envp, int num_envp,
 		      char *buffer, int buffer_size);
 	void (*release)(struct device *dev);
+	int (*suspend)(struct device * dev, pm_message_t state);
+	int (*resume)(struct device * dev);
 };
 
 /* interface for exporting device attributes */
@@ -354,8 +366,12 @@ extern int __must_check device_create_bi
 					       struct bin_attribute *attr);
 extern void device_remove_bin_file(struct device *dev,
 				   struct bin_attribute *attr);
-extern int device_schedule_callback(struct device *dev,
-		void (*func)(struct device *));
+extern int device_schedule_callback_owner(struct device *dev,
+		void (*func)(struct device *), struct module *owner);
+
+/* This is a macro to avoid include problems with THIS_MODULE */
+#define device_schedule_callback(dev, func)			\
+	device_schedule_callback_owner(dev, func, THIS_MODULE)
 
 /* device resource management */
 typedef void (*dr_release_t)(struct device *dev, void *res);
@@ -396,12 +412,13 @@ struct device {
 	struct klist_node	knode_parent;		/* node in sibling list */
 	struct klist_node	knode_driver;
 	struct klist_node	knode_bus;
-	struct device 	* parent;
+	struct device		*parent;
 
 	struct kobject kobj;
 	char	bus_id[BUS_ID_SIZE];	/* position on parent bus */
 	struct device_type	*type;
 	unsigned		is_registered:1;
+	unsigned		uevent_suppress:1;
 	struct device_attribute uevent_attr;
 	struct device_attribute *devt_attr;
 
@@ -442,7 +459,6 @@ #endif
 	struct class		*class;
 	dev_t			devt;		/* dev_t, creates the sysfs "dev" */
 	struct attribute_group	**groups;	/* optional groups */
-	int			uevent_suppress;
 
 	void	(*release)(struct device * dev);
 };
@@ -542,8 +558,8 @@ extern void device_shutdown(void);
 
 
 /* drivers/base/firmware.c */
-extern int __must_check firmware_register(struct subsystem *);
-extern void firmware_unregister(struct subsystem *);
+extern int __must_check firmware_register(struct kset *);
+extern void firmware_unregister(struct kset *);
 
 /* debugging and troubleshooting/diagnostic helpers. */
 extern const char *dev_driver_string(struct device *dev);
@@ -554,7 +570,11 @@ #ifdef DEBUG
 #define dev_dbg(dev, format, arg...)		\
 	dev_printk(KERN_DEBUG , dev , format , ## arg)
 #else
-#define dev_dbg(dev, format, arg...) do { (void)(dev); } while (0)
+static inline int __attribute__ ((format (printf, 2, 3)))
+dev_dbg(struct device * dev, const char * fmt, ...)
+{
+	return 0;
+}
 #endif
 
 #define dev_err(dev, format, arg...)		\
diff --git a/include/linux/display.h b/include/linux/display.h
new file mode 100644
index 0000000..3bf70d6
--- /dev/null
+++ b/include/linux/display.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (C) 2006 James Simmons <jsimmons@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.
+ *
+ *  You 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_DISPLAY_H
+#define _LINUX_DISPLAY_H
+
+#include <linux/device.h>
+
+struct display_device;
+
+/* This structure defines all the properties of a Display. */
+struct display_driver {
+	int  (*set_contrast)(struct display_device *, unsigned int);
+	int  (*get_contrast)(struct display_device *);
+	void (*suspend)(struct display_device *, pm_message_t state);
+	void (*resume)(struct display_device *);
+	int  (*probe)(struct display_device *, void *);
+	int  (*remove)(struct display_device *);
+	int  max_contrast;
+};
+
+struct display_device {
+	struct module *owner;			/* Owner module */
+	struct display_driver *driver;
+	struct device *parent;			/* This is the parent */
+	struct device *dev;			/* This is this display device */
+	struct mutex lock;
+	void *priv_data;
+	char type[16];
+	char *name;
+	int idx;
+};
+
+extern struct display_device *display_device_register(struct display_driver *driver,
+					struct device *dev, void *devdata);
+extern void display_device_unregister(struct display_device *dev);
+
+extern int probe_edid(struct display_device *dev, void *devdata);
+
+#define to_display_device(obj) container_of(obj, struct display_device, class_dev)
+
+#endif
diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
index 2a2dd18..c2735ca 100644
--- a/include/linux/dlm_device.h
+++ b/include/linux/dlm_device.h
@@ -19,7 +19,7 @@ #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_MINOR 1
 #define DLM_DEVICE_VERSION_PATCH 0
 
 /* struct passed to the lock write */
@@ -44,6 +44,11 @@ struct dlm_lspace_params {
 	char name[0];
 };
 
+struct dlm_purge_params {
+	__u32 nodeid;
+	__u32 pid;
+};
+
 struct dlm_write_request {
 	__u32 version[3];
 	__u8 cmd;
@@ -53,6 +58,7 @@ struct dlm_write_request {
 	union  {
 		struct dlm_lock_params   lock;
 		struct dlm_lspace_params lspace;
+		struct dlm_purge_params  purge;
 	} i;
 };
 
@@ -76,6 +82,7 @@ #define DLM_USER_UNLOCK       2
 #define DLM_USER_QUERY        3
 #define DLM_USER_CREATE_LOCKSPACE  4
 #define DLM_USER_REMOVE_LOCKSPACE  5
+#define DLM_USER_PURGE        6
 
 /* Arbitrary length restriction */
 #define MAX_LS_NAME_LEN 64
diff --git a/include/linux/ds1wm.h b/include/linux/ds1wm.h
new file mode 100644
index 0000000..31f6e3c
--- /dev/null
+++ b/include/linux/ds1wm.h
@@ -0,0 +1,11 @@
+/* platform data for the DS1WM driver */
+
+struct ds1wm_platform_data {
+	int bus_shift;	    /* number of shifts needed to calculate the
+			     * offset between DS1WM registers;
+			     * e.g. on h5xxx and h2200 this is 2
+			     * (registers aligned to 4-byte boundaries),
+			     * while on hx4700 this is 1 */
+	void (*enable)(struct platform_device *pdev);
+	void (*disable)(struct platform_device *pdev);
+};
diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
index 0874a67..89412e1 100644
--- a/include/linux/dvb/audio.h
+++ b/include/linux/dvb/audio.h
@@ -47,7 +47,9 @@ typedef enum {
 typedef enum {
 	AUDIO_STEREO,
 	AUDIO_MONO_LEFT,
-	AUDIO_MONO_RIGHT
+	AUDIO_MONO_RIGHT,
+	AUDIO_MONO,
+	AUDIO_STEREO_SWAPPED
 } audio_channel_select_t;
 
 
@@ -133,5 +135,6 @@ #define AUDIO_SET_KARAOKE          _IOW(
  * extracted by the PES parser.
  */
 #define AUDIO_GET_PTS              _IOR('o', 19, __u64)
+#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20)
 
 #endif /* _DVBAUDIO_H_ */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 6183c9c..126e0c2 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@ #ifndef _DVBVERSION_H_
 #define _DVBVERSION_H_
 
 #define DVB_API_VERSION 3
-#define DVB_API_VERSION_MINOR 1
+#define DVB_API_VERSION_MINOR 2
 
 #endif /*_DVBVERSION_H_*/
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
index faebfda..93e4c3a 100644
--- a/include/linux/dvb/video.h
+++ b/include/linux/dvb/video.h
@@ -80,14 +80,70 @@ typedef enum {
 } video_play_state_t;
 
 
+/* Decoder commands */
+#define VIDEO_CMD_PLAY        (0)
+#define VIDEO_CMD_STOP        (1)
+#define VIDEO_CMD_FREEZE      (2)
+#define VIDEO_CMD_CONTINUE    (3)
+
+/* Flags for VIDEO_CMD_FREEZE */
+#define VIDEO_CMD_FREEZE_TO_BLACK     	(1 << 0)
+
+/* Flags for VIDEO_CMD_STOP */
+#define VIDEO_CMD_STOP_TO_BLACK      	(1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY     	(1 << 1)
+
+/* Play input formats: */
+/* The decoder has no special format requirements */
+#define VIDEO_PLAY_FMT_NONE         (0)
+/* The decoder requires full GOPs */
+#define VIDEO_PLAY_FMT_GOP          (1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct video_command {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} play;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
+
+/* FIELD_UNKNOWN can be used if the hardware does not know whether
+   the Vsync is for an odd, even or progressive (i.e. non-interlaced)
+   field. */
+#define VIDEO_VSYNC_FIELD_UNKNOWN  	(0)
+#define VIDEO_VSYNC_FIELD_ODD 		(1)
+#define VIDEO_VSYNC_FIELD_EVEN		(2)
+#define VIDEO_VSYNC_FIELD_PROGRESSIVE	(3)
+
 struct video_event {
 	int32_t type;
 #define VIDEO_EVENT_SIZE_CHANGED	1
 #define VIDEO_EVENT_FRAME_RATE_CHANGED	2
+#define VIDEO_EVENT_DECODER_STOPPED 	3
+#define VIDEO_EVENT_VSYNC 		4
 	time_t timestamp;
 	union {
 		video_size_t size;
 		unsigned int frame_rate;	/* in frames per 1000sec */
+		unsigned char vsync_field;	/* unknown/odd/even/progressive */
 	} u;
 };
 
@@ -213,4 +269,10 @@ #define VIDEO_GET_FRAME_RATE       _IOR(
  */
 #define VIDEO_GET_PTS              _IOR('o', 57, __u64)
 
+/* Read the number of displayed frames since the decoder was started */
+#define VIDEO_GET_FRAME_COUNT  	   _IOR('o', 58, __u64)
+
+#define VIDEO_COMMAND     	   _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND 	   _IOWR('o', 60, struct video_command)
+
 #endif /*_DVBVIDEO_H_*/
diff --git a/include/linux/efi.h b/include/linux/efi.h
index f8ebd7c..0b9579a 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -213,7 +213,6 @@ typedef struct {
 } efi_config_table_t;
 
 #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
-#define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
 
 typedef struct {
 	efi_table_hdr_t hdr;
diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
index 666e0a5..0311bad 100644
--- a/include/linux/elf-em.h
+++ b/include/linux/elf-em.h
@@ -30,6 +30,7 @@ #define EM_CRIS		76	/* Axis Communicatio
 #define EM_V850		87	/* NEC v850 */
 #define EM_M32R		88	/* Renesas M32R */
 #define EM_H8_300	46	/* Renesas H8/300,300H,H8S */
+#define EM_BLACKFIN     106     /* ADI Blackfin Processor */
 #define EM_FRV		0x5441	/* Fujitsu FR-V */
 #define EM_AVR32	0x18ad	/* Atmel AVR32 */
 
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 60713e6..8b17ffe 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -83,6 +83,23 @@ #define DT_PLTREL	20
 #define DT_DEBUG	21
 #define DT_TEXTREL	22
 #define DT_JMPREL	23
+#define DT_ENCODING	32
+#define OLD_DT_LOOS	0x60000000
+#define DT_LOOS		0x6000000d
+#define DT_HIOS		0x6ffff000
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_VALRNGHI	0x6ffffdff
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_ADDRRNGHI	0x6ffffeff
+#define DT_VERSYM	0x6ffffff0
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+#define DT_FLAGS_1	0x6ffffffb
+#define DT_VERDEF	0x6ffffffc
+#define	DT_VERDEFNUM	0x6ffffffd
+#define DT_VERNEED	0x6ffffffe
+#define	DT_VERNEEDNUM	0x6fffffff
+#define OLD_DT_HIOS     0x6fffffff
 #define DT_LOPROC	0x70000000
 #define DT_HIPROC	0x7fffffff
 
diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h
index 67396db..9a1e067 100644
--- a/include/linux/elfnote.h
+++ b/include/linux/elfnote.h
@@ -39,12 +39,12 @@ #ifdef __ASSEMBLER__
  *      ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
  */
 #define ELFNOTE(name, type, desctype, descdata)	\
-.pushsection .note.name			;	\
+.pushsection .note.name, "",@note	;	\
   .align 4				;	\
   .long 2f - 1f		/* namesz */	;	\
   .long 4f - 3f		/* descsz */	;	\
   .long type				;	\
-1:.asciz "name"				;	\
+1:.asciz #name				;	\
 2:.align 4				;	\
 3:desctype descdata			;	\
 4:.align 4				;	\
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 745c988..071c67a 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -71,6 +71,18 @@ static inline int is_multicast_ether_add
 }
 
 /**
+ * is_local_ether_addr - Determine if the Ethernet address is locally-assigned
+ * one (IEEE 802).
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return true if the address is a local address.
+ */
+static inline int is_local_ether_addr(const u8 *addr)
+{
+	return (0x02 & addr[0]);
+}
+
+/**
  * is_broadcast_ether_addr - Determine if the Ethernet address is broadcast
  * @addr: Pointer to a six-byte array containing the Ethernet address
  *
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index c6310ae..f2d248f 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -434,6 +434,7 @@ #define SUPPORTED_BNC			(1 << 11)
 #define SUPPORTED_10000baseT_Full	(1 << 12)
 #define SUPPORTED_Pause			(1 << 13)
 #define SUPPORTED_Asym_Pause		(1 << 14)
+#define SUPPORTED_2500baseX_Full	(1 << 15)
 
 /* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half		(1 << 0)
@@ -451,6 +452,7 @@ #define ADVERTISED_BNC			(1 << 11)
 #define ADVERTISED_10000baseT_Full	(1 << 12)
 #define ADVERTISED_Pause		(1 << 13)
 #define ADVERTISED_Asym_Pause		(1 << 14)
+#define ADVERTISED_2500baseX_Full	(1 << 15)
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 4eb18ac..ece49a8 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -824,6 +824,7 @@ extern int ext3_change_inode_journal_fla
 extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
 extern void ext3_truncate (struct inode *);
 extern void ext3_set_inode_flags(struct inode *);
+extern void ext3_get_inode_flags(struct ext3_inode_info *);
 extern void ext3_set_aops(struct inode *inode);
 
 /* ioctl.c */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index be913ec..dff7a72 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -4,6 +4,8 @@ #define _LINUX_FB_H
 #include <asm/types.h>
 #include <linux/i2c.h>
 
+struct dentry;
+
 /* Definitions of frame buffers						*/
 
 #define FB_MAJOR		29
@@ -525,12 +527,20 @@ #define FB_EVENT_NEW_MODELIST           
 #define FB_EVENT_MODE_CHANGE_ALL	0x0B
 /*	A software display blank change occured */
 #define FB_EVENT_CONBLANK               0x0C
+/*      Get drawing requirements        */
+#define FB_EVENT_GET_REQ                0x0D
 
 struct fb_event {
 	struct fb_info *info;
 	void *data;
 };
 
+struct fb_blit_caps {
+	u32 x;
+	u32 y;
+	u32 len;
+	u32 flags;
+};
 
 extern int fb_register_client(struct notifier_block *nb);
 extern int fb_unregister_client(struct notifier_block *nb);
@@ -556,11 +566,25 @@ struct fb_pixmap {
 	u32 scan_align;		/* alignment per scanline		*/
 	u32 access_align;	/* alignment per read/write (bits)	*/
 	u32 flags;		/* see FB_PIXMAP_*			*/
+	u32 blit_x;             /* supported bit block dimensions (1-32)*/
+	u32 blit_y;             /* Format: blit_x = 1 << (width - 1)    */
+	                        /*         blit_y = 1 << (height - 1)   */
+	                        /* if 0, will be set to 0xffffffff (all)*/
 	/* access methods */
 	void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size);
 	void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
 };
 
+#ifdef CONFIG_FB_DEFERRED_IO
+struct fb_deferred_io {
+	/* delay between mkwrite and deferred handler */
+	unsigned long delay;
+	struct mutex lock; /* mutex that protects the page list */
+	struct list_head pagelist; /* list of touched pages */
+	/* callback */
+	void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
+};
+#endif
 
 /*
  * Frame buffer operations
@@ -579,8 +603,10 @@ struct fb_ops {
 	/* For framebuffers with strange non linear layouts or that do not
 	 * work with normal memory mapped access
 	 */
-	ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
-	ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+	ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
+			   size_t count, loff_t *ppos);
+	ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
+			    size_t count, loff_t *ppos);
 
 	/* checks var and eventually tweaks it to something supported,
 	 * DO NOT MODIFY PAR */
@@ -634,10 +660,13 @@ struct fb_ops {
 
 	/* restore saved state */
 	void (*fb_restore_state)(struct fb_info *info);
+
+	/* get capability given var */
+	void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
+			    struct fb_var_screeninfo *var);
 };
 
 #ifdef CONFIG_FB_TILEBLITTING
-
 #define FB_TILE_CURSOR_NONE        0
 #define FB_TILE_CURSOR_UNDERLINE   1
 #define FB_TILE_CURSOR_LOWER_THIRD 2
@@ -709,6 +738,8 @@ struct fb_tile_ops {
 	/* cursor */
 	void (*fb_tilecursor)(struct fb_info *info,
 			      struct fb_tilecursor *cursor);
+	/* get maximum length of the tile map */
+	int (*fb_get_tilemax)(struct fb_info *info);
 };
 #endif /* CONFIG_FB_TILEBLITTING */
 
@@ -778,6 +809,10 @@ #ifdef CONFIG_FB_BACKLIGHT
 	struct mutex bl_curve_mutex;	
 	u8 bl_curve[FB_BACKLIGHT_LEVELS];
 #endif
+#ifdef CONFIG_FB_DEFERRED_IO
+	struct delayed_work deferred_work;
+	struct fb_deferred_io *fbdefio;
+#endif
 
 	struct fb_ops *fbops;
 	struct device *device;		/* This is the parent */
@@ -879,6 +914,16 @@ extern int fb_blank(struct fb_info *info
 extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 
 extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); 
 extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
+/*
+ * Drawing operations where framebuffer is in system RAM
+ */
+extern void sys_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+extern void sys_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+extern void sys_imageblit(struct fb_info *info, const struct fb_image *image);
+extern ssize_t fb_sys_read(struct fb_info *info, char __user *buf,
+			   size_t count, loff_t *ppos);
+extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
+			    size_t count, loff_t *ppos);
 
 /* drivers/video/fbmem.c */
 extern int register_framebuffer(struct fb_info *fb_info);
@@ -913,6 +958,12 @@ static inline void __fb_pad_aligned_buff
 	}
 }
 
+/* drivers/video/fb_defio.c */
+extern void fb_deferred_io_init(struct fb_info *info);
+extern void fb_deferred_io_cleanup(struct fb_info *info);
+extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
+				int datasync);
+
 /* drivers/video/fbsysfs.c */
 extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
 extern void framebuffer_release(struct fb_info *info);
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 996f561..40b9326 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -3,6 +3,10 @@ #define _LINUX_FCNTL_H
 
 #include <asm/fcntl.h>
 
+/* Cancel a blocking posix lock; internal use only until we expose an
+ * asynchronous lock api to userspace: */
+#define F_CANCELLK	(F_LINUX_SPECIFIC_BASE+5)
+
 #define F_SETLEASE	(F_LINUX_SPECIFIC_BASE+0)
 #define F_GETLEASE	(F_LINUX_SPECIFIC_BASE+1)
 
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index 8270aac..87b606b 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -5,8 +5,13 @@ #include <linux/types.h>
 #include <linux/rtnetlink.h>
 
 /* rule is permanent, and cannot be deleted */
-#define FIB_RULE_PERMANENT	1
-#define FIB_RULE_INVERT		2
+#define FIB_RULE_PERMANENT	0x00000001
+#define FIB_RULE_INVERT		0x00000002
+#define FIB_RULE_UNRESOLVED	0x00000004
+#define FIB_RULE_DEV_DETACHED	0x00000008
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR	0x00010000
 
 struct fib_rule_hdr
 {
@@ -29,7 +34,7 @@ enum
 	FRA_DST,	/* destination address */
 	FRA_SRC,	/* source address */
 	FRA_IFNAME,	/* interface name */
-	FRA_UNUSED1,
+	FRA_GOTO,	/* target to jump to (FR_ACT_GOTO) */
 	FRA_UNUSED2,
 	FRA_PRIORITY,	/* priority/preference */
 	FRA_UNUSED3,
@@ -51,8 +56,8 @@ enum
 {
 	FR_ACT_UNSPEC,
 	FR_ACT_TO_TBL,		/* Pass to fixed table */
-	FR_ACT_RES1,
-	FR_ACT_RES2,
+	FR_ACT_GOTO,		/* Jump to another rule */
+	FR_ACT_NOP,		/* No operation */
 	FR_ACT_RES3,
 	FR_ACT_RES4,
 	FR_ACT_BLACKHOLE,	/* Drop without notification */
diff --git a/include/linux/font.h b/include/linux/font.h
index 53b129f..40a24ab 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -49,7 +49,8 @@ extern const struct font_desc *find_font
 
 /* Get the default font for a specific screen size */
 
-extern const struct font_desc *get_default_font(int xres, int yres);
+extern const struct font_desc *get_default_font(int xres, int yres,
+						u32 font_w, u32 font_h);
 
 /* Max. length for the name of a predefined font */
 #define MAX_FONT_NAME	32
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 86ec3f4..7cf0c54 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -30,6 +30,7 @@ #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
 #define SEEK_SET	0	/* seek relative to beginning of file */
 #define SEEK_CUR	1	/* seek relative to current file position */
 #define SEEK_END	2	/* seek relative to end of file */
+#define SEEK_MAX	SEEK_END
 
 /* And dynamically-tunable limits and defaults: */
 struct files_stat_struct {
@@ -91,6 +92,7 @@ #define SEL_EX		4
 /* public flags for file_system_type */
 #define FS_REQUIRES_DEV 1 
 #define FS_BINARY_MOUNTDATA 2
+#define FS_HAS_SUBTYPE 4
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move()
 					 * during rename() internally.
@@ -696,12 +698,13 @@ struct file_ra_state {
 	unsigned long size;
 	unsigned long flags;		/* ra flags RA_FLAG_xxx*/
 	unsigned long cache_hit;	/* cache hit count*/
-	unsigned long prev_page;	/* Cache last read() position */
+	unsigned long prev_index;	/* Cache last read() position */
 	unsigned long ahead_start;	/* Ahead window */
 	unsigned long ahead_size;
 	unsigned long ra_pages;		/* Maximum readahead window */
 	unsigned long mmap_hit;		/* Cache hit stat for mmap accesses */
 	unsigned long mmap_miss;	/* Cache miss stat for mmap accesses */
+	unsigned int prev_offset;	/* Offset where last read() ended in a page */
 };
 #define RA_FLAG_MISS 0x01	/* a cache miss occured against this file */
 #define RA_FLAG_INCACHE 0x02	/* file is already in cache */
@@ -785,6 +788,7 @@ struct file_lock_operations {
 struct lock_manager_operations {
 	int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
 	void (*fl_notify)(struct file_lock *);	/* unblock callback */
+	int (*fl_grant)(struct file_lock *, struct file_lock *, int);
 	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
 	void (*fl_release_private)(struct file_lock *);
 	void (*fl_break)(struct file_lock *);
@@ -843,19 +847,21 @@ extern int fcntl_setlease(unsigned int f
 extern int fcntl_getlease(struct file *filp);
 
 /* fs/sync.c */
-extern int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte,
-			unsigned int flags);
+extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
+			loff_t endbyte, unsigned int flags);
 
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
-extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_test_lock(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
 extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern int posix_unblock_lock(struct file *, struct file_lock *);
+extern int vfs_test_lock(struct file *, struct file_lock *);
+extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
+extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
@@ -951,6 +957,12 @@ #endif
 	/* Granularity of c/m/atime in ns.
 	   Cannot be worse than a second */
 	u32		   s_time_gran;
+
+	/*
+	 * Filesystem subtype.  If non-empty the filesystem type field
+	 * in /proc/mounts will be "type.subtype"
+	 */
+	char *s_subtype;
 };
 
 extern struct timespec current_fs_time(struct super_block *sb);
@@ -1411,7 +1423,7 @@ extern void mnt_set_mountpoint(struct vf
 extern int vfs_statfs(struct dentry *, struct kstatfs *);
 
 /* /sys/fs */
-extern struct subsystem fs_subsys;
+extern struct kset fs_subsys;
 
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
@@ -1726,6 +1738,8 @@ extern ssize_t generic_file_sendfile(str
 extern void do_generic_mapping_read(struct address_space *mapping,
 				    struct file_ra_state *, struct file *,
 				    loff_t *, read_descriptor_t *, read_actor_t);
+extern int generic_segment_checks(const struct iovec *iov,
+		unsigned long *nr_segs, size_t *count, int access_flags);
 
 /* fs/splice.c */
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index abb64c4..73710d6 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -120,44 +120,5 @@ struct fsl_spi_platform_data {
 	u32	sysclk;
 };
 
-/* 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/futex.h b/include/linux/futex.h
index 3f153b4..820125c 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -100,6 +100,35 @@ long do_futex(u32 __user *uaddr, int op,
 extern int
 handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
 
+/*
+ * Futexes are matched on equal values of this key.
+ * The key type depends on whether it's a shared or private mapping.
+ * Don't rearrange members without looking at hash_futex().
+ *
+ * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
+ * We set bit 0 to indicate if it's an inode-based key.
+ */
+union futex_key {
+	struct {
+		unsigned long pgoff;
+		struct inode *inode;
+		int offset;
+	} shared;
+	struct {
+		unsigned long address;
+		struct mm_struct *mm;
+		int offset;
+	} private;
+	struct {
+		unsigned long word;
+		void *ptr;
+		int offset;
+	} both;
+};
+int get_futex_key(u32 __user *uaddr, union futex_key *key);
+void get_futex_key_refs(union futex_key *key);
+void drop_futex_key_refs(union futex_key *key);
+
 #ifdef CONFIG_FUTEX
 extern void exit_robust_list(struct task_struct *curr);
 extern void exit_pi_state_list(struct task_struct *curr);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 2a7d15b..97a36c3 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -40,7 +40,6 @@ #define __GFP_NOWARN	((__force gfp_t)0x2
 #define __GFP_REPEAT	((__force gfp_t)0x400u)	/* Retry the allocation.  Might fail */
 #define __GFP_NOFAIL	((__force gfp_t)0x800u)	/* Retry for ever.  Cannot fail */
 #define __GFP_NORETRY	((__force gfp_t)0x1000u)/* Do not retry.  Might fail */
-#define __GFP_NO_GROW	((__force gfp_t)0x2000u)/* Slab internal usage */
 #define __GFP_COMP	((__force gfp_t)0x4000u)/* Add compound page metadata */
 #define __GFP_ZERO	((__force gfp_t)0x8000u)/* Return zeroed page on success */
 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
@@ -53,7 +52,7 @@ #define __GFP_BITS_MASK ((__force gfp_t)
 /* if you forget to add the bitmask here kernel will crash, period */
 #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_NOFAIL|__GFP_NORETRY|__GFP_COMP| \
 			__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)
 
 /* This equals 0, but use constants in case they ever change */
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 2b217c7..265d178 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -3,10 +3,11 @@ #define _GPIO_KEYS_H
 
 struct gpio_keys_button {
 	/* Configuration parameters */
-	int keycode;
+	int code;		/* input event code (KEY_*, SW_*) */
 	int gpio;
 	int active_low;
 	char *desc;
+	int type;		/* input event type (EV_KEY, EV_SW) */
 };
 
 struct gpio_keys_platform_data {
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index d4b3339..db390c5 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -43,8 +43,7 @@ struct hdlc_proto {
 	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);
+	__be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
 	struct module *module;
 	struct hdlc_proto *next; /* next protocol in the list */
 };
@@ -132,8 +131,8 @@ static __inline__ __be16 hdlc_type_trans
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 
-	skb->mac.raw  = skb->data;
-	skb->dev      = dev;
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
 
 	if (hdlc->proto->type_trans)
 		return hdlc->proto->type_trans(skb, dev);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8c97d4d..37076b1 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -247,6 +247,11 @@ #define HID_FEATURE_REPORT	2
  * HID device quirks.
  */
 
+/* 
+ * Increase this if you need to configure more HID quirks at module load time
+ */
+#define MAX_USBHID_BOOT_QUIRKS 4
+
 #define HID_QUIRK_INVERT			0x00000001
 #define HID_QUIRK_NOTOUCH			0x00000002
 #define HID_QUIRK_IGNORE			0x00000004
@@ -267,8 +272,9 @@ #define HID_QUIRK_BAD_RELATIVE_KEYS		0x0
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00020000
 #define HID_QUIRK_IGNORE_MOUSE			0x00040000
 #define HID_QUIRK_SONY_PS3_CONTROLLER		0x00080000
-#define HID_QUIRK_LOGITECH_S510_DESCRIPTOR	0x00100000
+#define HID_QUIRK_LOGITECH_DESCRIPTOR		0x00100000
 #define HID_QUIRK_DUPLICATE_USAGES		0x00200000
+#define HID_QUIRK_RESET_LEDS			0x00400000
 
 /*
  * This is the global environment of the parser. This information is
@@ -494,6 +500,12 @@ void hid_output_report(struct hid_report
 void hid_free_device(struct hid_device *device);
 struct hid_device *hid_parse_report(__u8 *start, unsigned size);
 
+/* HID quirks API */
+u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
+int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
+int usbhid_quirks_init(char **quirks_param);
+void usbhid_quirks_exit(void);
+
 #ifdef CONFIG_HID_FF
 int hid_ff_init(struct hid_device *hid);
 
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 645d440..a515eb0 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -27,6 +27,8 @@ #include <asm/highmem.h>
 unsigned int nr_free_highpages(void);
 extern unsigned long totalhigh_pages;
 
+void kmap_flush_unused(void);
+
 #else /* CONFIG_HIGHMEM */
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -42,11 +44,20 @@ static inline void *kmap(struct page *pa
 
 #define kunmap(page) do { (void) (page); } while (0)
 
-#define kmap_atomic(page, idx) \
-	({ pagefault_disable(); page_address(page); })
+#include <asm/kmap_types.h>
+
+static inline void *kmap_atomic(struct page *page, enum km_type idx)
+{
+	pagefault_disable();
+	return page_address(page);
+}
+#define kmap_atomic_prot(page, idx, prot)	kmap_atomic(page, idx)
+
 #define kunmap_atomic(addr, idx)	do { pagefault_enable(); } while (0)
 #define kmap_atomic_pfn(pfn, idx)	kmap_atomic(pfn_to_page(pfn), (idx))
 #define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
+
+#define kmap_flush_unused()	do {} while(0)
 #endif
 
 #endif /* CONFIG_HIGHMEM */
diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h
index debd715..9db3d45 100644
--- a/include/linux/hp_sdc.h
+++ b/include/linux/hp_sdc.h
@@ -71,6 +71,7 @@ typedef struct {
 	  struct semaphore *semaphore;	/* Semaphore to sleep on. */
 	} act;
 } hp_sdc_transaction;
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
 int hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
 int hp_sdc_dequeue_transaction(hp_sdc_transaction *this);
 
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 3f3e7a6..b4570b6 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -189,4 +189,10 @@ #define hugetlb_zero_setup(size)	ERR_PTR
 
 #endif /* !CONFIG_HUGETLBFS */
 
+#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+					unsigned long len, unsigned long pgoff,
+					unsigned long flags);
+#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */
+
 #endif /* _LINUX_HUGETLB_H */
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index 937da70..9ee0f80 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -38,11 +38,14 @@ struct i2c_algo_bit_data {
 	int  (*getscl) (void *data);
 
 	/* local settings */
-	int udelay;		/* half-clock-cycle time in microsecs */
-				/* i.e. clock is (500 / udelay) KHz */
+	int udelay;		/* half clock cycle time in us,
+				   minimum 2 us for fast-mode I2C,
+				   minimum 5 us for standard-mode I2C and SMBus,
+				   maximum 50 us for SMBus */
 	int timeout;		/* in jiffies */
 };
 
 int i2c_bit_add_bus(struct i2c_adapter *);
+int i2c_bit_add_numbered_bus(struct i2c_adapter *);
 
 #endif /* _LINUX_I2C_ALGO_BIT_H */
diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h
new file mode 100644
index 0000000..c1bcb1f
--- /dev/null
+++ b/include/linux/i2c-gpio.h
@@ -0,0 +1,38 @@
+/*
+ * i2c-gpio interface to platform code
+ *
+ * Copyright (C) 2007 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 _LINUX_I2C_GPIO_H
+#define _LINUX_I2C_GPIO_H
+
+/**
+ * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
+ * @sda_pin: GPIO pin ID to use for SDA
+ * @scl_pin: GPIO pin ID to use for SCL
+ * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
+ * @timeout: clock stretching timeout in jiffies. If the slave keeps
+ *	SCL low for longer than this, the transfer will time out.
+ * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
+ *	isn't actively driven high when setting the output value high.
+ *	gpio_get_value() must return the actual pin state even if the
+ *	pin is configured as an output.
+ * @scl_is_open_drain: SCL is set up as open drain. Same requirements
+ *	as for sda_is_open_drain apply.
+ * @scl_is_output_only: SCL output drivers cannot be turned off.
+ */
+struct i2c_gpio_platform_data {
+	unsigned int	sda_pin;
+	unsigned int	scl_pin;
+	int		udelay;
+	int		timeout;
+	unsigned int	sda_is_open_drain:1;
+	unsigned int	scl_is_open_drain:1;
+	unsigned int	scl_is_output_only:1;
+};
+
+#endif /* _LINUX_I2C_GPIO_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 9c21dc7..0e8da68 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -258,8 +258,9 @@ #define I2C_HW_IPMB		0x0c0000
 /* --- MCP107 adapter */
 #define I2C_HW_MPC107		0x0d0000
 
-/* --- Marvell mv64xxx i2c adapter */
+/* --- Embedded adapters */
 #define I2C_HW_MV64XXX		0x190000
+#define I2C_HW_BLACKFIN		0x190001 /* ADI Blackfin I2C TWI driver */
 
 /* --- Miscellaneous adapters */
 #define I2C_HW_SAA7146		0x060000 /* SAA7146 video decoder bus */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 9428092..cae7d61 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -35,11 +35,6 @@ #include <linux/device.h>	/* for struct 
 #include <linux/sched.h>	/* for completion */
 #include <linux/mutex.h>
 
-/* --- For i2c-isa ---------------------------------------------------- */
-
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct device_driver i2c_adapter_driver;
-extern struct class i2c_adapter_class;
 extern struct bus_type i2c_bus_type;
 
 /* --- General options ------------------------------------------------	*/
@@ -87,6 +82,9 @@ extern s32 i2c_smbus_write_byte_data(str
 extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
 extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
                                      u8 command, u16 value);
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_read_block_data(struct i2c_client *client,
+				     u8 command, u8 *values);
 extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
 				      u8 command, u8 length,
 				      const u8 *values);
@@ -114,7 +112,7 @@ struct i2c_driver {
 	 * can be used by the driver to test if the bus meets its conditions
 	 * & seek for the presence of the chip(s) it supports. If found, it
 	 * registers the client(s) that are on the bus to the i2c admin. via
-	 * i2c_attach_client.
+	 * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)
 	 */
 	int (*attach_adapter)(struct i2c_adapter *);
 	int (*detach_adapter)(struct i2c_adapter *);
@@ -122,10 +120,17 @@ struct i2c_driver {
 	/* tells the driver that a client is about to be deleted & gives it
 	 * the chance to remove its private data. Also, if the client struct
 	 * has been dynamically allocated by the driver in the function above,
-	 * it must be freed here.
+	 * it must be freed here.  (LEGACY I2C DRIVERS ONLY)
 	 */
 	int (*detach_client)(struct i2c_client *);
 
+	/* Standard driver model interfaces, for "new style" i2c drivers.
+	 * With the driver model, device enumeration is NEVER done by drivers;
+	 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
+	 */
+	int (*probe)(struct i2c_client *);
+	int (*remove)(struct i2c_client *);
+
 	/* driver model interfaces that don't relate to enumeration  */
 	void (*shutdown)(struct i2c_client *);
 	int (*suspend)(struct i2c_client *, pm_message_t mesg);
@@ -141,25 +146,34 @@ struct i2c_driver {
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
-#define I2C_NAME_SIZE	50
+#define I2C_NAME_SIZE	20
 
-/*
- * i2c_client identifies a single device (i.e. chip) that is connected to an
- * i2c bus. The behaviour is defined by the routines of the driver. This
- * function is mainly used for lookup & other admin. functions.
+/**
+ * struct i2c_client - represent an I2C slave device
+ * @addr: Address used on the I2C bus connected to the parent adapter.
+ * @name: Indicates the type of the device, usually a chip name that's
+ *	generic enough to hide second-sourcing and compatible revisions.
+ * @dev: Driver model device node for the slave.
+ * @driver_name: Identifies new-style driver used with this device; also
+ *	used as the module name for hotplug/coldplug modprobe support.
+ *
+ * An i2c_client identifies a single device (i.e. chip) connected to an
+ * i2c bus. The behaviour is defined by the routines of the driver.
  */
 struct i2c_client {
-	unsigned int flags;		/* div., see below		*/
+	unsigned short flags;		/* div., see below		*/
 	unsigned short addr;		/* chip address - NOTE: 7bit	*/
 					/* addresses are stored in the	*/
 					/* _LOWER_ 7 bits		*/
+	char name[I2C_NAME_SIZE];
 	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
 	struct i2c_driver *driver;	/* and our access routines	*/
 	int usage_count;		/* How many accesses currently  */
 					/* to the client		*/
 	struct device dev;		/* the device structure		*/
+	int irq;			/* irq issued by device (or -1) */
+	char driver_name[KOBJ_NAME_LEN];
 	struct list_head list;
-	char name[I2C_NAME_SIZE];
 	struct completion released;
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
@@ -179,6 +193,76 @@ static inline void i2c_set_clientdata (s
 	dev_set_drvdata (&dev->dev, data);
 }
 
+/**
+ * struct i2c_board_info - template for device creation
+ * @driver_name: identifies the driver to be bound to the device
+ * @type: optional chip type information, to initialize i2c_client.name
+ * @flags: to initialize i2c_client.flags
+ * @addr: stored in i2c_client.addr
+ * @platform_data: stored in i2c_client.dev.platform_data
+ * @irq: stored in i2c_client.irq
+
+ * I2C doesn't actually support hardware probing, although controllers and
+ * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
+ * a device at a given address.  Drivers commonly need more information than
+ * that, such as chip type, configuration, associated IRQ, and so on.
+ *
+ * i2c_board_info is used to build tables of information listing I2C devices
+ * that are present.  This information is used to grow the driver model tree
+ * for "new style" I2C drivers.  For mainboards this is done statically using
+ * i2c_register_board_info(), where @bus_num represents an adapter that isn't
+ * yet available.  For add-on boards, i2c_new_device() does this dynamically
+ * with the adapter already known.
+ */
+struct i2c_board_info {
+	char		driver_name[KOBJ_NAME_LEN];
+	char		type[I2C_NAME_SIZE];
+	unsigned short	flags;
+	unsigned short	addr;
+	void		*platform_data;
+	int		irq;
+};
+
+/**
+ * I2C_BOARD_INFO - macro used to list an i2c device and its driver
+ * @driver: identifies the driver to use with the device
+ * @dev_addr: the device's address on the bus.
+ *
+ * This macro initializes essential fields of a struct i2c_board_info,
+ * declaring what has been provided on a particular board.  Optional
+ * fields (such as the chip type, its associated irq, or device-specific
+ * platform_data) are provided using conventional syntax.
+ */
+#define I2C_BOARD_INFO(driver,dev_addr) \
+	.driver_name = (driver), .addr = (dev_addr)
+
+
+/* Add-on boards should register/unregister their devices; e.g. a board
+ * with integrated I2C, a config eeprom, sensors, and a codec that's
+ * used in conjunction with the primary hardware.
+ */
+extern struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+
+/* If you don't know the exact address of an I2C device, use this variant
+ * instead, which can probe for device presence in a list of possible
+ * addresses.
+ */
+extern struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+		      struct i2c_board_info *info,
+		      unsigned short const *addr_list);
+
+extern void i2c_unregister_device(struct i2c_client *);
+
+/* Mainboard arch_initcall() code should register all its I2C devices.
+ * This is done at arch_initcall time, before declaring any i2c adapters.
+ * Modules for add-on boards must use other calls.
+ */
+extern int
+i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
+
+
 /*
  * The following structs are for those who like to implement new bus drivers:
  * i2c_algorithm is the interface to a class of hardware solutions which can
@@ -228,17 +312,14 @@ struct i2c_adapter {
 	int timeout;
 	int retries;
 	struct device dev;		/* the adapter device */
-	struct class_device class_dev;	/* the class device */
 
 	int nr;
 	struct list_head clients;
 	struct list_head list;
-	char name[I2C_NAME_SIZE];
+	char name[48];
 	struct completion dev_released;
-	struct completion class_dev_released;
 };
-#define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
-#define class_dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, class_dev)
+#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
 static inline void *i2c_get_adapdata (struct i2c_adapter *dev)
 {
@@ -290,9 +371,10 @@ #define ANY_I2C_ISA_BUS		9191
  */
 extern int i2c_add_adapter(struct i2c_adapter *);
 extern int i2c_del_adapter(struct i2c_adapter *);
+extern int i2c_add_numbered_adapter(struct i2c_adapter *);
 
 extern int i2c_register_driver(struct module *, struct i2c_driver *);
-extern int i2c_del_driver(struct i2c_driver *);
+extern void i2c_del_driver(struct i2c_driver *);
 
 static inline int i2c_add_driver(struct i2c_driver *driver)
 {
@@ -365,6 +447,7 @@ #define I2C_M_NOSTART	0x4000
 #define I2C_M_REV_DIR_ADDR	0x2000
 #define I2C_M_IGNORE_NAK	0x1000
 #define I2C_M_NO_RD_ACK		0x0800
+#define I2C_M_RECV_LEN		0x0400 /* length will be first received byte */
 	__u16 len;		/* msg length				*/
 	__u8 *buf;		/* pointer to msg data			*/
 };
diff --git a/include/linux/icmp.h b/include/linux/icmp.h
index 24da4fb..474f2a5 100644
--- a/include/linux/icmp.h
+++ b/include/linux/icmp.h
@@ -82,6 +82,15 @@ struct icmphdr {
   } un;
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb)
+{
+	return (struct icmphdr *)skb_transport_header(skb);
+}
+#endif
+
 /*
  *	constants for (set|get)sockopt
  */
diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h
index 68d3526..7c5e981 100644
--- a/include/linux/icmpv6.h
+++ b/include/linux/icmpv6.h
@@ -75,6 +75,15 @@ #define icmp6_rt_lifetime	icmp6_dataun.u
 #define icmp6_router_pref	icmp6_dataun.u_nd_ra.router_pref
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct icmp6hdr *icmp6_hdr(const struct sk_buff *skb)
+{
+	return (struct icmp6hdr *)skb_transport_header(skb);
+}
+#endif
+
 #define ICMPV6_ROUTER_PREF_LOW		0x3
 #define ICMPV6_ROUTER_PREF_MEDIUM	0x0
 #define ICMPV6_ROUTER_PREF_HIGH		0x1
diff --git a/include/linux/ide.h b/include/linux/ide.h
index d3bbc71..418dfb5 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -613,7 +613,6 @@ typedef struct ide_drive_s {
 
         u8	quirk_list;	/* considered quirky, set for a specific host */
         u8	init_speed;	/* transfer rate set at boot */
-        u8	pio_speed;      /* unused by core, used by some drivers for fallback from DMA */
         u8	current_speed;	/* current transfer rate set */
 	u8	desired_speed;	/* desired transfer rate set */
         u8	dn;		/* now wide spread use */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
new file mode 100644
index 0000000..ecd61e8
--- /dev/null
+++ b/include/linux/ieee80211.h
@@ -0,0 +1,342 @@
+/*
+ * IEEE 802.11 defines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.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.
+ */
+
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/types.h>
+
+#define FCS_LEN 4
+
+#define IEEE80211_FCTL_VERS		0x0003
+#define IEEE80211_FCTL_FTYPE		0x000c
+#define IEEE80211_FCTL_STYPE		0x00f0
+#define IEEE80211_FCTL_TODS		0x0100
+#define IEEE80211_FCTL_FROMDS		0x0200
+#define IEEE80211_FCTL_MOREFRAGS	0x0400
+#define IEEE80211_FCTL_RETRY		0x0800
+#define IEEE80211_FCTL_PM		0x1000
+#define IEEE80211_FCTL_MOREDATA		0x2000
+#define IEEE80211_FCTL_PROTECTED	0x4000
+#define IEEE80211_FCTL_ORDER		0x8000
+
+#define IEEE80211_SCTL_FRAG		0x000F
+#define IEEE80211_SCTL_SEQ		0xFFF0
+
+#define IEEE80211_FTYPE_MGMT		0x0000
+#define IEEE80211_FTYPE_CTL		0x0004
+#define IEEE80211_FTYPE_DATA		0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ	0x0000
+#define IEEE80211_STYPE_ASSOC_RESP	0x0010
+#define IEEE80211_STYPE_REASSOC_REQ	0x0020
+#define IEEE80211_STYPE_REASSOC_RESP	0x0030
+#define IEEE80211_STYPE_PROBE_REQ	0x0040
+#define IEEE80211_STYPE_PROBE_RESP	0x0050
+#define IEEE80211_STYPE_BEACON		0x0080
+#define IEEE80211_STYPE_ATIM		0x0090
+#define IEEE80211_STYPE_DISASSOC	0x00A0
+#define IEEE80211_STYPE_AUTH		0x00B0
+#define IEEE80211_STYPE_DEAUTH		0x00C0
+#define IEEE80211_STYPE_ACTION		0x00D0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL		0x00A0
+#define IEEE80211_STYPE_RTS		0x00B0
+#define IEEE80211_STYPE_CTS		0x00C0
+#define IEEE80211_STYPE_ACK		0x00D0
+#define IEEE80211_STYPE_CFEND		0x00E0
+#define IEEE80211_STYPE_CFENDACK	0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA			0x0000
+#define IEEE80211_STYPE_DATA_CFACK		0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL		0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL		0x0030
+#define IEEE80211_STYPE_NULLFUNC		0x0040
+#define IEEE80211_STYPE_CFACK			0x0050
+#define IEEE80211_STYPE_CFPOLL			0x0060
+#define IEEE80211_STYPE_CFACKPOLL		0x0070
+#define IEEE80211_STYPE_QOS_DATA		0x0080
+#define IEEE80211_STYPE_QOS_DATA_CFACK		0x0090
+#define IEEE80211_STYPE_QOS_DATA_CFPOLL		0x00A0
+#define IEEE80211_STYPE_QOS_DATA_CFACKPOLL	0x00B0
+#define IEEE80211_STYPE_QOS_NULLFUNC		0x00C0
+#define IEEE80211_STYPE_QOS_CFACK		0x00D0
+#define IEEE80211_STYPE_QOS_CFPOLL		0x00E0
+#define IEEE80211_STYPE_QOS_CFACKPOLL		0x00F0
+
+
+/* miscellaneous IEEE 802.11 constants */
+#define IEEE80211_MAX_FRAG_THRESHOLD	2346
+#define IEEE80211_MAX_RTS_THRESHOLD	2347
+#define IEEE80211_MAX_AID		2007
+#define IEEE80211_MAX_TIM_LEN		251
+#define IEEE80211_MAX_DATA_LEN		2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+#define IEEE80211_MAX_SSID_LEN		32
+
+struct ieee80211_hdr {
+	__le16 frame_control;
+	__le16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	__le16 seq_ctrl;
+	u8 addr4[6];
+} __attribute__ ((packed));
+
+
+struct ieee80211_mgmt {
+	__le16 frame_control;
+	__le16 duration;
+	u8 da[6];
+	u8 sa[6];
+	u8 bssid[6];
+	__le16 seq_ctrl;
+	union {
+		struct {
+			__le16 auth_alg;
+			__le16 auth_transaction;
+			__le16 status_code;
+			/* possibly followed by Challenge text */
+			u8 variable[0];
+		} __attribute__ ((packed)) auth;
+		struct {
+			__le16 reason_code;
+		} __attribute__ ((packed)) deauth;
+		struct {
+			__le16 capab_info;
+			__le16 listen_interval;
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} __attribute__ ((packed)) assoc_req;
+		struct {
+			__le16 capab_info;
+			__le16 status_code;
+			__le16 aid;
+			/* followed by Supported rates */
+			u8 variable[0];
+		} __attribute__ ((packed)) assoc_resp, reassoc_resp;
+		struct {
+			__le16 capab_info;
+			__le16 listen_interval;
+			u8 current_ap[6];
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} __attribute__ ((packed)) reassoc_req;
+		struct {
+			__le16 reason_code;
+		} __attribute__ ((packed)) disassoc;
+		struct {
+			__le64 timestamp;
+			__le16 beacon_int;
+			__le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			u8 variable[0];
+		} __attribute__ ((packed)) beacon;
+		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} __attribute__ ((packed)) probe_req;
+		struct {
+			__le64 timestamp;
+			__le16 beacon_int;
+			__le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		} __attribute__ ((packed)) probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				} __attribute__ ((packed)) wme_action;
+				struct{
+					u8 action_code;
+					u8 element_id;
+					u8 length;
+					u8 switch_mode;
+					u8 new_chan;
+					u8 switch_count;
+				} __attribute__((packed)) chan_switch;
+			} u;
+		} __attribute__ ((packed)) action;
+	} u;
+} __attribute__ ((packed));
+
+
+/* Control frames */
+struct ieee80211_rts {
+	__le16 frame_control;
+	__le16 duration;
+	u8 ra[6];
+	u8 ta[6];
+} __attribute__ ((packed));
+
+struct ieee80211_cts {
+	__le16 frame_control;
+	__le16 duration;
+	u8 ra[6];
+} __attribute__ ((packed));
+
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+#define WLAN_AUTH_FAST_BSS_TRANSITION 2
+#define WLAN_AUTH_LEAP 128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS		(1<<0)
+#define WLAN_CAPABILITY_IBSS		(1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE	(1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST	(1<<3)
+#define WLAN_CAPABILITY_PRIVACY		(1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE	(1<<5)
+#define WLAN_CAPABILITY_PBCC		(1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY	(1<<7)
+/* 802.11h */
+#define WLAN_CAPABILITY_SPECTRUM_MGMT	(1<<8)
+#define WLAN_CAPABILITY_QOS		(1<<9)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME	(1<<10)
+#define WLAN_CAPABILITY_DSSS_OFDM	(1<<13)
+
+/* Status codes */
+enum ieee80211_statuscode {
+	WLAN_STATUS_SUCCESS = 0,
+	WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
+	WLAN_STATUS_CAPS_UNSUPPORTED = 10,
+	WLAN_STATUS_REASSOC_NO_ASSOC = 11,
+	WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
+	WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
+	WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
+	WLAN_STATUS_CHALLENGE_FAIL = 15,
+	WLAN_STATUS_AUTH_TIMEOUT = 16,
+	WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+	WLAN_STATUS_ASSOC_DENIED_RATES = 18,
+	/* 802.11b */
+	WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
+	WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
+	WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
+	/* 802.11h */
+	WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
+	WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
+	WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
+	/* 802.11g */
+	WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
+	WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+	/* 802.11i */
+	WLAN_STATUS_INVALID_IE = 40,
+	WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
+	WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
+	WLAN_STATUS_INVALID_AKMP = 43,
+	WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
+	WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
+	WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+};
+
+
+/* Reason codes */
+enum ieee80211_reasoncode {
+	WLAN_REASON_UNSPECIFIED = 1,
+	WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+	WLAN_REASON_DEAUTH_LEAVING = 3,
+	WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
+	WLAN_REASON_DISASSOC_AP_BUSY = 5,
+	WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+	WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+	WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
+	WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+	/* 802.11h */
+	WLAN_REASON_DISASSOC_BAD_POWER = 10,
+	WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
+	/* 802.11i */
+	WLAN_REASON_INVALID_IE = 13,
+	WLAN_REASON_MIC_FAILURE = 14,
+	WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+	WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
+	WLAN_REASON_IE_DIFFERENT = 17,
+	WLAN_REASON_INVALID_GROUP_CIPHER = 18,
+	WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
+	WLAN_REASON_INVALID_AKMP = 20,
+	WLAN_REASON_UNSUPP_RSN_VERSION = 21,
+	WLAN_REASON_INVALID_RSN_IE_CAP = 22,
+	WLAN_REASON_IEEE8021X_FAILED = 23,
+	WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+};
+
+
+/* Information Element IDs */
+enum ieee80211_eid {
+	WLAN_EID_SSID = 0,
+	WLAN_EID_SUPP_RATES = 1,
+	WLAN_EID_FH_PARAMS = 2,
+	WLAN_EID_DS_PARAMS = 3,
+	WLAN_EID_CF_PARAMS = 4,
+	WLAN_EID_TIM = 5,
+	WLAN_EID_IBSS_PARAMS = 6,
+	WLAN_EID_CHALLENGE = 16,
+	/* 802.11d */
+	WLAN_EID_COUNTRY = 7,
+	WLAN_EID_HP_PARAMS = 8,
+	WLAN_EID_HP_TABLE = 9,
+	WLAN_EID_REQUEST = 10,
+	/* 802.11h */
+	WLAN_EID_PWR_CONSTRAINT = 32,
+	WLAN_EID_PWR_CAPABILITY = 33,
+	WLAN_EID_TPC_REQUEST = 34,
+	WLAN_EID_TPC_REPORT = 35,
+	WLAN_EID_SUPPORTED_CHANNELS = 36,
+	WLAN_EID_CHANNEL_SWITCH = 37,
+	WLAN_EID_MEASURE_REQUEST = 38,
+	WLAN_EID_MEASURE_REPORT = 39,
+	WLAN_EID_QUIET = 40,
+	WLAN_EID_IBSS_DFS = 41,
+	/* 802.11g */
+	WLAN_EID_ERP_INFO = 42,
+	WLAN_EID_EXT_SUPP_RATES = 50,
+	/* 802.11i */
+	WLAN_EID_RSN = 48,
+	WLAN_EID_WPA = 221,
+	WLAN_EID_GENERIC = 221,
+	WLAN_EID_VENDOR_SPECIFIC = 221,
+	WLAN_EID_QOS_PARAMETER = 222
+};
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
+/* reserved: 				0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
+
+#define WLAN_MAX_KEY_LEN		32
+
+#endif /* IEEE80211_H */
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index d557e4c..43f3bed 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -39,6 +39,7 @@ #define IFA_F_SECONDARY		0x01
 #define IFA_F_TEMPORARY		IFA_F_SECONDARY
 
 #define	IFA_F_NODAD		0x02
+#define IFA_F_OPTIMISTIC	0x04
 #define	IFA_F_HOMEADDRESS	0x10
 #define IFA_F_DEPRECATED	0x20
 #define IFA_F_TENTATIVE		0x40
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 7f57142..ed7b93c 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -148,4 +148,13 @@ #endif
 
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
+{
+	return (struct arphdr *)skb_network_header(skb);
+}
+#endif
+
 #endif	/* _LINUX_IF_ARP_H */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index fd1b6eb..4ff211d 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -105,7 +105,8 @@ #ifdef __KERNEL__
 #include <linux/netdevice.h>
 
 extern void brioctl_set(int (*ioctl_hook)(unsigned int, void __user *));
-extern int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
+extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
+					       struct sk_buff *skb);
 extern int (*br_should_route_hook)(struct sk_buff **pskb);
 
 #endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index ab08f35..1db774c 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -61,6 +61,7 @@ #define ETH_P_AARP	0x80F3		/* Appletalk 
 #define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
 #define ETH_P_IPX	0x8137		/* IPX over DIX			*/
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+#define ETH_P_PAUSE	0x8808		/* IEEE Pause frames. See 802.3 31B */
 #define ETH_P_SLOW	0x8809		/* Slow Protocol. See 802.3ad 43B */
 #define ETH_P_WCCP	0x883E		/* Web-cache coordination protocol
 					 * defined in draft-wilson-wrec-wccp-v2-00.txt */
@@ -112,7 +113,7 @@ #include <linux/skbuff.h>
 
 static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
 {
-	return (struct ethhdr *)skb->mac.raw;
+	return (struct ethhdr *)skb_mac_header(skb);
 }
 
 #ifdef CONFIG_SYSCTL
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 35ed3b5..604c243 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -126,6 +126,7 @@ enum
 	IFLA_INET6_STATS,	/* statistics			*/
 	IFLA_INET6_MCAST,	/* MC things. What of them?	*/
 	IFLA_INET6_CACHEINFO,	/* time values and max reasm size */
+	IFLA_INET6_ICMP6STATS,	/* statistics (icmpv6)		*/
 	__IFLA_INET6_MAX
 };
 
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index f3de05c..ad09609 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -42,6 +42,7 @@ #define PACKET_RX_RING			5
 #define PACKET_STATISTICS		6
 #define PACKET_COPY_THRESH		7
 #define PACKET_AUXDATA			8
+#define PACKET_ORIGDEV			9
 
 struct tpacket_stats
 {
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index e33ee76..6f987be 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -111,7 +111,17 @@ #endif
 	struct pppoe_tag tag[0];
 } __attribute__ ((packed));
 
+/* Length of entire PPPoE + PPP header */
+#define PPPOE_SES_HLEN	8
+
 #ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
+{
+	return (struct pppoe_hdr *)skb_network_header(skb);
+}
+
 struct pppoe_opt {
 	struct net_device      *dev;	  /* device associated with socket*/
 	int			ifindex;  /* ifindex of device associated with socket */
diff --git a/include/linux/if_tr.h b/include/linux/if_tr.h
index 2f94cf2..046e9d9 100644
--- a/include/linux/if_tr.h
+++ b/include/linux/if_tr.h
@@ -47,7 +47,7 @@ #include <linux/skbuff.h>
 
 static inline struct trh_hdr *tr_hdr(const struct sk_buff *skb)
 {
-	return (struct trh_hdr *)skb->mac.raw;
+	return (struct trh_hdr *)skb_mac_header(skb);
 }
 #ifdef CONFIG_SYSCTL
 extern struct ctl_table tr_table[];
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index d103580..81e9bc9 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -51,7 +51,7 @@ #include <linux/skbuff.h>
 
 static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
 {
-	return (struct vlan_ethhdr *)skb->mac.raw;
+	return (struct vlan_ethhdr *)skb_mac_header(skb);
 }
 
 struct vlan_hdr {
@@ -275,8 +275,8 @@ static inline struct sk_buff *__vlan_put
 	veth->h_vlan_TCI = htons(tag);
 
 	skb->protocol = __constant_htons(ETH_P_8021Q);
-	skb->mac.raw -= VLAN_HLEN;
-	skb->nh.raw -= VLAN_HLEN;
+	skb->mac_header -= VLAN_HLEN;
+	skb->network_header -= VLAN_HLEN;
 
 	return skb;
 }
diff --git a/include/linux/if_wanpipe_common.h b/include/linux/if_wanpipe_common.h
deleted file mode 100644
index 6e5461d..0000000
--- a/include/linux/if_wanpipe_common.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*****************************************************************************
-* if_wanipe_common.h   Sangoma Driver/Socket common area definitions.
-*
-* Author:       Nenad Corbic <ncorbic@sangoma.com>
-*
-* Copyright:    (c) 2000 Sangoma Technologies 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.
-* ============================================================================
-* Jan 13, 2000  Nenad Corbic      Initial version
-*****************************************************************************/
-
-
-#ifndef _WANPIPE_SOCK_DRIVER_COMMON_H
-#define _WANPIPE_SOCK_DRIVER_COMMON_H
-
-typedef struct {
-	struct net_device *slave;
-	atomic_t packet_sent;
-	atomic_t receive_block;
-	atomic_t command;
-	atomic_t disconnect;
-	atomic_t driver_busy;
-	long common_critical;
-	struct timer_list *tx_timer;
-	struct sock *sk;		/* Wanpipe Sock bind's here */ 
-	int (*func)(struct sk_buff *skb, struct net_device *dev, 
-		    struct sock *sk);
-
-	struct work_struct wanpipe_work;    /* deferred keventd work */
-	unsigned char rw_bind;			  /* Sock bind state */
-	unsigned char usedby;
-	unsigned char state;
-	unsigned char svc;
-	unsigned short lcn;
-	void *mbox;
-} wanpipe_common_t;
-
-
-enum {
-	WANSOCK_UNCONFIGURED,	/* link/channel is not configured */
-	WANSOCK_DISCONNECTED,	/* link/channel is disconnected */
-	WANSOCK_CONNECTING,		/* connection is in progress */
-	WANSOCK_CONNECTED,		/* link/channel is operational */
-	WANSOCK_LIMIT,		/* for verification only */
-	WANSOCK_DUALPORT,		/* for Dual Port cards */
-	WANSOCK_DISCONNECTING,
-	WANSOCK_BINDED,
-	WANSOCK_BIND_LISTEN,
-	WANSOCK_LISTEN
-};
-
-#endif
-
-
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index a113fe6..f510e7e 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -80,6 +80,27 @@ #endif
 	__be32 srcs[0];
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb)
+{
+	return (struct igmphdr *)skb_transport_header(skb);
+}
+
+static inline struct igmpv3_report *
+			igmpv3_report_hdr(const struct sk_buff *skb)
+{
+	return (struct igmpv3_report *)skb_transport_header(skb);
+}
+
+static inline struct igmpv3_query *
+			igmpv3_query_hdr(const struct sk_buff *skb)
+{
+	return (struct igmpv3_query *)skb_transport_header(skb);
+}
+#endif
+
 #define IGMP_HOST_MEMBERSHIP_QUERY	0x11	/* From RFC1112 */
 #define IGMP_HOST_MEMBERSHIP_REPORT	0x12	/* Ditto */
 #define IGMP_DVMRP			0x13	/* DVMRP routing */
diff --git a/include/linux/in.h b/include/linux/in.h
index 1912e7c..3975cbf 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -83,6 +83,7 @@ #define IP_RECVRETOPTS	IP_RETOPTS
 #define IP_PMTUDISC_DONT		0	/* Never send DF frames */
 #define IP_PMTUDISC_WANT		1	/* Use per route hints	*/
 #define IP_PMTUDISC_DO			2	/* Always DF		*/
+#define IP_PMTUDISC_PROBE		3       /* Ignore dst pmtu      */
 
 #define IP_MULTICAST_IF			32
 #define IP_MULTICAST_TTL 		33
diff --git a/include/linux/in6.h b/include/linux/in6.h
index 4e8350a..2a61c82 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -44,10 +44,8 @@ #define s6_addr32		in6_u.u6_addr32
  * NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined
  * in network byte order, not in host byte order as are the IPv4 equivalents
  */
-#if 0
 extern const struct in6_addr in6addr_any;
 #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
-#endif
 extern const struct in6_addr in6addr_loopback;
 #define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
 
@@ -179,6 +177,7 @@ #define IPV6_LEAVE_ANYCAST	28
 #define IPV6_PMTUDISC_DONT		0
 #define IPV6_PMTUDISC_WANT		1
 #define IPV6_PMTUDISC_DO		2
+#define IPV6_PMTUDISC_PROBE		3
 
 /* Flowlabel */
 #define IPV6_FLOWLABEL_MGR	32
diff --git a/include/linux/init.h b/include/linux/init.h
index e290a01..8bc32bb 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -52,9 +52,14 @@ #define __exit		__attribute_used__ __att
 #endif
 
 /* For assembly routines */
+#ifdef CONFIG_HOTPLUG_CPU
+#define __INIT		.section	".text","ax"
+#define __INITDATA	.section	".data","aw"
+#else
 #define __INIT		.section	".init.text","ax"
-#define __FINIT		.previous
 #define __INITDATA	.section	".init.data","aw"
+#endif
+#define __FINIT		.previous
 
 #ifndef __ASSEMBLY__
 /*
@@ -72,7 +77,8 @@ extern char *saved_command_line;
 extern unsigned int reset_devices;
 
 /* used by init/main.c */
-extern void setup_arch(char **);
+void setup_arch(char **);
+void prepare_namespace(void);
 
 #endif
   
@@ -228,7 +234,7 @@ #define __setup(str, func) 			/* nothing
 #define __obsolete_setup(str) 			/* nothing */
 #endif
 
-/* Data marked not to be saved by software_suspend() */
+/* Data marked not to be saved by software suspend */
 #define __nosavedata __attribute__ ((__section__ (".data.nosave")))
 
 /* This means "can be init if no module support, otherwise module load
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index a2d95ff..7951023 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -138,7 +138,7 @@ #define INIT_TASK(tsk)	\
 	.journal_info	= NULL,						\
 	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
 	.fs_excl	= ATOMIC_INIT(0),				\
-	.pi_lock	= SPIN_LOCK_UNLOCKED,				\
+	.pi_lock	= __SPIN_LOCK_UNLOCKED(tsk.pi_lock),		\
 	INIT_TRACE_IRQFLAGS						\
 	INIT_LOCKDEP							\
 }
diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h
new file mode 100644
index 0000000..597a007
--- /dev/null
+++ b/include/linux/input-polldev.h
@@ -0,0 +1,46 @@
+#ifndef _INPUT_POLLDEV_H
+#define _INPUT_POLLDEV_H
+
+/*
+ * Copyright (c) 2007 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/workqueue.h>
+
+/**
+ * struct input_polled_dev - simple polled input device
+ * @private: private driver data
+ * @flush: driver-supplied method that flushes device's state upon
+ *	opening (optional)
+ * @poll: driver-supplied method that polls the device and posts
+ *	input events (mandatory).
+ * @poll_interval: specifies how often the poll() method shoudl be called.
+ * @input: input device structire associated with the polled device.
+ *	Must be properly initialized by the driver (id, name, phys, bits).
+ *
+ * Polled input device provides a skeleton for supporting simple input
+ * devices that do not raise interrupts but have to be periodically
+ * scanned or polled to detect changes in their state.
+ */
+struct input_polled_dev {
+	void *private;
+
+	void (*flush)(struct input_polled_dev *dev);
+	void (*poll)(struct input_polled_dev *dev);
+	unsigned int poll_interval; /* msec */
+
+	struct input_dev *input;
+	struct delayed_work work;
+};
+
+struct input_polled_dev *input_allocate_polled_device(void);
+void input_free_polled_device(struct input_polled_dev *dev);
+int input_register_polled_device(struct input_polled_dev *dev);
+void input_unregister_polled_device(struct input_polled_dev *dev);
+
+#endif
diff --git a/include/linux/input.h b/include/linux/input.h
index bde65c8..be2bf3a 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -506,6 +506,7 @@ #define KEY_NEWS		0x1ab
 #define KEY_VOICEMAIL		0x1ac
 #define KEY_ADDRESSBOOK		0x1ad
 #define KEY_MESSENGER		0x1ae
+#define KEY_DISPLAYTOGGLE	0x1af	/* Turn display (LCD) on and off */
 
 #define KEY_DEL_EOL		0x1c0
 #define KEY_DEL_EOS		0x1c1
@@ -676,6 +677,7 @@ #define BUS_ADB			0x17
 #define BUS_I2C			0x18
 #define BUS_HOST		0x19
 #define BUS_GSC			0x1A
+#define BUS_ATARI		0x1B
 
 /*
  * Values describing the status of a force-feedback effect
@@ -913,33 +915,6 @@ #define NBITS(x) (((x)/BITS_PER_LONG)+1)
 #define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
 #define LONG(x) ((x)/BITS_PER_LONG)
 
-#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
-	((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
-
-#define SET_INPUT_KEYCODE(dev, scancode, val)			\
-		({	unsigned __old;				\
-		switch (dev->keycodesize) {			\
-			case 1: {				\
-				u8 *k = (u8 *)dev->keycode;	\
-				__old = k[scancode];		\
-				k[scancode] = val;		\
-				break;				\
-			}					\
-			case 2: {				\
-				u16 *k = (u16 *)dev->keycode;	\
-				__old = k[scancode];		\
-				k[scancode] = val;		\
-				break;				\
-			}					\
-			default: {				\
-				u32 *k = (u32 *)dev->keycode;	\
-				__old = k[scancode];		\
-				k[scancode] = val;		\
-				break;				\
-			}					\
-		}						\
-		__old; })
-
 struct input_dev {
 
 	void *private;
@@ -962,6 +937,8 @@ struct input_dev {
 	unsigned int keycodemax;
 	unsigned int keycodesize;
 	void *keycode;
+	int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
+	int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
 
 	struct ff_device *ff;
 
@@ -996,6 +973,9 @@ struct input_dev {
 	unsigned int users;
 
 	struct class_device cdev;
+	union {			/* temporarily so while we switching to struct device */
+		struct device *parent;
+	} dev;
 
 	struct list_head	h_list;
 	struct list_head	node;
@@ -1010,6 +990,10 @@ #if EV_MAX != INPUT_DEVICE_ID_EV_MAX
 #error "EV_MAX and INPUT_DEVICE_ID_EV_MAX do not match"
 #endif
 
+#if KEY_MIN_INTERESTING != INPUT_DEVICE_ID_KEY_MIN_INTERESTING
+#error "KEY_MIN_INTERESTING and INPUT_DEVICE_ID_KEY_MIN_INTERESTING do not match"
+#endif
+
 #if KEY_MAX != INPUT_DEVICE_ID_KEY_MAX
 #error "KEY_MAX and INPUT_DEVICE_ID_KEY_MAX do not match"
 #endif
@@ -1074,7 +1058,7 @@ 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, const struct input_device_id *id);
+	int (*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);
 
@@ -1104,7 +1088,7 @@ struct input_handle {
 };
 
 #define to_dev(n) container_of(n,struct input_dev,node)
-#define to_handler(n) container_of(n,struct input_handler,node);
+#define to_handler(n) container_of(n,struct input_handler,node)
 #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)
 
@@ -1121,12 +1105,25 @@ static inline void input_put_device(stru
 	class_device_put(&dev->cdev);
 }
 
+static inline void *input_get_drvdata(struct input_dev *dev)
+{
+	return dev->private;
+}
+
+static inline void input_set_drvdata(struct input_dev *dev, void *data)
+{
+	dev->private = data;
+}
+
 int input_register_device(struct input_dev *);
 void input_unregister_device(struct input_dev *);
 
 int input_register_handler(struct input_handler *);
 void input_unregister_handler(struct input_handler *);
 
+int input_register_handle(struct input_handle *);
+void input_unregister_handle(struct input_handle *);
+
 int input_grab_device(struct input_handle *);
 void input_release_device(struct input_handle *);
 
@@ -1168,6 +1165,8 @@ static inline void input_sync(struct inp
 	input_event(dev, EV_SYN, SYN_REPORT, 0);
 }
 
+void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
+
 static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
 {
 	dev->absmin[axis] = min;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 838cf5a..f7b01b9 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -44,6 +44,9 @@ #define IRQF_TRIGGER_PROBE	0x00000010
  * IRQF_TIMER - Flag to mark this interrupt as timer interrupt
  * IRQF_PERCPU - Interrupt is per cpu
  * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
+ * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
+ *                registered first in an shared interrupt is considered for
+ *                performance reasons)
  */
 #define IRQF_DISABLED		0x00000020
 #define IRQF_SAMPLE_RANDOM	0x00000040
@@ -52,22 +55,29 @@ #define IRQF_PROBE_SHARED	0x00000100
 #define IRQF_TIMER		0x00000200
 #define IRQF_PERCPU		0x00000400
 #define IRQF_NOBALANCING	0x00000800
+#define IRQF_IRQPOLL		0x00001000
 
 /*
- * Migration helpers. Scheduled for removal in 1/2007
+ * Migration helpers. Scheduled for removal in 9/2007
  * Do not use for new code !
  */
-#define SA_INTERRUPT		IRQF_DISABLED
-#define SA_SAMPLE_RANDOM	IRQF_SAMPLE_RANDOM
-#define SA_SHIRQ		IRQF_SHARED
-#define SA_PROBEIRQ		IRQF_PROBE_SHARED
-#define SA_PERCPU		IRQF_PERCPU
-
-#define SA_TRIGGER_LOW		IRQF_TRIGGER_LOW
-#define SA_TRIGGER_HIGH		IRQF_TRIGGER_HIGH
-#define SA_TRIGGER_FALLING	IRQF_TRIGGER_FALLING
-#define SA_TRIGGER_RISING	IRQF_TRIGGER_RISING
-#define SA_TRIGGER_MASK		IRQF_TRIGGER_MASK
+static inline
+unsigned long __deprecated deprecated_irq_flag(unsigned long flag)
+{
+	return flag;
+}
+
+#define SA_INTERRUPT		deprecated_irq_flag(IRQF_DISABLED)
+#define SA_SAMPLE_RANDOM	deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
+#define SA_SHIRQ		deprecated_irq_flag(IRQF_SHARED)
+#define SA_PROBEIRQ		deprecated_irq_flag(IRQF_PROBE_SHARED)
+#define SA_PERCPU		deprecated_irq_flag(IRQF_PERCPU)
+
+#define SA_TRIGGER_LOW		deprecated_irq_flag(IRQF_TRIGGER_LOW)
+#define SA_TRIGGER_HIGH		deprecated_irq_flag(IRQF_TRIGGER_HIGH)
+#define SA_TRIGGER_FALLING	deprecated_irq_flag(IRQF_TRIGGER_FALLING)
+#define SA_TRIGGER_RISING	deprecated_irq_flag(IRQF_TRIGGER_RISING)
+#define SA_TRIGGER_MASK		deprecated_irq_flag(IRQF_TRIGGER_MASK)
 
 typedef irqreturn_t (*irq_handler_t)(int, void *);
 
@@ -83,11 +93,11 @@ struct irqaction {
 };
 
 extern irqreturn_t no_action(int cpl, void *dev_id);
-extern int request_irq(unsigned int, irq_handler_t handler,
+extern int __must_check request_irq(unsigned int, irq_handler_t handler,
 		       unsigned long, const char *, void *);
 extern void free_irq(unsigned int, void *);
 
-extern int devm_request_irq(struct device *dev, unsigned int irq,
+extern int __must_check devm_request_irq(struct device *dev, unsigned int irq,
 			    irq_handler_t handler, unsigned long irqflags,
 			    const char *devname, void *dev_id);
 extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
@@ -185,10 +195,14 @@ #else /* !CONFIG_GENERIC_HARDIRQS */
  * validator need to define the methods below in their asm/irq.h
  * files, under an #ifdef CONFIG_LOCKDEP section.
  */
-# ifndef CONFIG_LOCKDEP
+#ifndef CONFIG_LOCKDEP
 #  define disable_irq_nosync_lockdep(irq)	disable_irq_nosync(irq)
+#  define disable_irq_nosync_lockdep_irqsave(irq, flags) \
+						disable_irq_nosync(irq)
 #  define disable_irq_lockdep(irq)		disable_irq(irq)
 #  define enable_irq_lockdep(irq)		enable_irq(irq)
+#  define enable_irq_lockdep_irqrestore(irq, flags) \
+						enable_irq(irq)
 # endif
 
 #endif /* CONFIG_GENERIC_HARDIRQS */
diff --git a/include/linux/ioctl32.h b/include/linux/ioctl32.h
deleted file mode 100644
index 948809d..0000000
--- a/include/linux/ioctl32.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef IOCTL32_H
-#define IOCTL32_H 1
-
-#include <linux/compiler.h>	/* for __deprecated */
-
-struct file;
-
-typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
-					unsigned long, struct file *);
-
-struct ioctl_trans {
-	unsigned long cmd;
-	ioctl_trans_handler_t handler;
-	struct ioctl_trans *next;
-};
-
-#endif
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 6859a3b..71ea923 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -99,7 +99,6 @@ extern struct resource ioport_resource;
 extern struct resource iomem_resource;
 
 extern int request_resource(struct resource *root, struct resource *new);
-extern struct resource * ____request_resource(struct resource *root, struct resource *new);
 extern int release_resource(struct resource *new);
 extern int insert_resource(struct resource *parent, struct resource *new);
 extern int allocate_resource(struct resource *root, struct resource *new,
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 1d36b97..bd0a2a8 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -104,6 +104,20 @@ #endif
 	/*The options start here. */
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
+{
+	return (struct iphdr *)skb_network_header(skb);
+}
+
+static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
+{
+	return (struct iphdr *)skb_transport_header(skb);
+}
+#endif
+
 struct ip_auth_hdr {
 	__u8  nexthdr;
 	__u8  hdrlen;		/* This one is measured in 32 bit units! */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 6da6772..1980867 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -92,16 +92,19 @@ extern struct ipc_namespace init_ipc_ns;
 
 #ifdef CONFIG_SYSVIPC
 #define INIT_IPC_NS(ns)		.ns		= &init_ipc_ns,
-extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
+extern struct ipc_namespace *copy_ipcs(unsigned long flags,
+						struct ipc_namespace *ns);
 #else
 #define INIT_IPC_NS(ns)
-static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
-{ return 0; }
+static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
+						struct ipc_namespace *ns)
+{
+	return ns;
+}
 #endif
 
 #ifdef CONFIG_IPC_NS
 extern void free_ipc_ns(struct kref *kref);
-extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
 #endif
 
 static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 713eb5e..09ea01a 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -178,6 +178,9 @@ #endif
 #endif
 	__s32		proxy_ndp;
 	__s32		accept_source_route;
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+	__s32		optimistic_dad;
+#endif
 	void		*sysctl;
 };
 
@@ -208,6 +211,7 @@ enum {
 	DEVCONF_PROXY_NDP,
 	__DEVCONF_OPTIMISTIC_DAD,
 	DEVCONF_ACCEPT_SOURCE_ROUTE,
+	DEVCONF_OPTIMISTIC_DAD,
 	DEVCONF_MAX
 };
 
@@ -219,6 +223,16 @@ #include <linux/udp.h>
 #include <net/if_inet6.h>       /* struct ipv6_mc_socklist */
 #include <net/inet_sock.h>
 
+static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
+{
+	return (struct ipv6hdr *)skb_network_header(skb);
+}
+
+static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb)
+{
+	return (struct ipv6hdr *)skb_transport_header(skb);
+}
+
 /* 
    This structure contains results of exthdrs parsing
    as offsets from skb->nh.
diff --git a/include/linux/irq.h b/include/linux/irq.h
index a689940..1695054 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -147,8 +147,6 @@ #endif
  * @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 {
 	irq_flow_handler_t	handle_irq;
@@ -175,7 +173,7 @@ #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry	*dir;
 #endif
 	const char		*name;
-} ____cacheline_aligned;
+} ____cacheline_internodealigned_in_smp;
 
 extern struct irq_desc irq_desc[NR_IRQS];
 
diff --git a/include/linux/isdn/capiutil.h b/include/linux/isdn/capiutil.h
index 63bd9cf..5a52f2c 100644
--- a/include/linux/isdn/capiutil.h
+++ b/include/linux/isdn/capiutil.h
@@ -187,7 +187,6 @@ typedef struct {
 #define	CDEBUG_SIZE	1024
 #define	CDEBUG_GSIZE	4096
 
-_cdebbuf *cdebbuf_alloc(void);
 void cdebbuf_free(_cdebbuf *cdb);
 int cdebug_init(void);
 void cdebug_exit(void);
diff --git a/include/linux/isdn_divertif.h b/include/linux/isdn_divertif.h
index 0e7e44c..07821ca 100644
--- a/include/linux/isdn_divertif.h
+++ b/include/linux/isdn_divertif.h
@@ -24,6 +24,10 @@ #define DIVERT_REG_ERR  0x03  /* module 
 #define DIVERT_REL_ERR  0x04  /* module not registered */
 #define DIVERT_REG_NAME isdn_register_divert
 
+#ifdef __KERNEL__
+#include <linux/isdnif.h>
+#include <linux/types.h>
+
 /***************************************************************/
 /* structure exchanging data between isdn hl and divert module */
 /***************************************************************/ 
@@ -40,3 +44,4 @@ typedef struct
 /* function register */
 /*********************/
 extern int DIVERT_REG_NAME(isdn_divert_if *);
+#endif
diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index 82c7ae4..2a2f99f 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -84,7 +84,7 @@ static inline u32 jhash(const void *key,
 /* A special optimized version that handles 1 or more of u32s.
  * The length parameter here is the number of u32s in the key.
  */
-static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
 	u32 a, b, c, len;
 
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 1cebcbc..12178d2 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -7,6 +7,8 @@ #define _LINUX_KALLSYMS_H
 
 
 #define KSYM_NAME_LEN 127
+#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +	\
+			 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1)
 
 #ifdef CONFIG_KALLSYMS
 /* Lookup the address for a symbol. Returns 0 if not found. */
@@ -22,9 +24,15 @@ const char *kallsyms_lookup(unsigned lon
 			    unsigned long *offset,
 			    char **modname, char *namebuf);
 
-/* Replace "%s" in format with address, if found */
+/* Look up a kernel symbol and return it in a text buffer. */
+extern int sprint_symbol(char *buffer, unsigned long address);
+
+/* Look up a kernel symbol and print it to the kernel messages. */
 extern void __print_symbol(const char *fmt, unsigned long address);
 
+int lookup_symbol_name(unsigned long addr, char *symname);
+int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
+
 #else /* !CONFIG_KALLSYMS */
 
 static inline unsigned long kallsyms_lookup_name(const char *name)
@@ -47,6 +55,22 @@ static inline const char *kallsyms_looku
 	return NULL;
 }
 
+static inline int sprint_symbol(char *buffer, unsigned long addr)
+{
+	*buffer = '\0';
+	return 0;
+}
+
+static inline int lookup_symbol_name(unsigned long addr, char *symname)
+{
+	return -ERANGE;
+}
+
+static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name)
+{
+	return -ERANGE;
+}
+
 /* Stupid that this does nothing, but I didn't create this mess. */
 #define __print_symbol(fmt, addr)
 #endif /*CONFIG_KALLSYMS*/
diff --git a/include/linux/kdebug.h b/include/linux/kdebug.h
new file mode 100644
index 0000000..5db38d6
--- /dev/null
+++ b/include/linux/kdebug.h
@@ -0,0 +1,20 @@
+#ifndef _LINUX_KDEBUG_H
+#define _LINUX_KDEBUG_H
+
+#include <asm/kdebug.h>
+
+struct die_args {
+	struct pt_regs *regs;
+	const char *str;
+	long err;
+	int trapnr;
+	int signr;
+};
+
+int register_die_notifier(struct notifier_block *nb);
+int unregister_die_notifier(struct notifier_block *nb);
+
+int notify_die(enum die_val val, const char *str,
+	       struct pt_regs *regs, long err, int trap, int sig);
+
+#endif /* _LINUX_KDEBUG_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 9ddf25c..144b615 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -35,7 +35,8 @@ #define STACK_MAGIC	0xdeadbeef
 #define ALIGN(x,a)		__ALIGN_MASK(x,(typeof(x))(a)-1)
 #define __ALIGN_MASK(x,mask)	(((x)+(mask))&~(mask))
 
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+
 #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))
@@ -121,6 +122,7 @@ extern int vscnprintf(char *buf, size_t 
 	__attribute__ ((format (printf, 3, 0)));
 extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
+extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
 
 extern int sscanf(const char *, const char *, ...)
 	__attribute__ ((format (scanf, 2, 3)));
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 696e5ec..8c2c7fc 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -7,6 +7,8 @@ #include <linux/list.h>
 #include <linux/linkage.h>
 #include <linux/compat.h>
 #include <linux/ioport.h>
+#include <linux/elfcore.h>
+#include <linux/elf.h>
 #include <asm/kexec.h>
 
 /* Verify architecture specific macros are defined */
@@ -31,6 +33,19 @@ #ifndef KEXEC_ARCH
 #error KEXEC_ARCH not defined
 #endif
 
+#define KEXEC_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)
+#define KEXEC_CORE_NOTE_NAME "CORE"
+#define KEXEC_CORE_NOTE_NAME_BYTES ALIGN(sizeof(KEXEC_CORE_NOTE_NAME), 4)
+#define KEXEC_CORE_NOTE_DESC_BYTES ALIGN(sizeof(struct elf_prstatus), 4)
+/*
+ * The per-cpu notes area is a list of notes terminated by a "NULL"
+ * note header.  For kdump, the code in vmcore.c runs in the context
+ * of the second kernel to combine them into one note.
+ */
+#define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) +		\
+			    KEXEC_CORE_NOTE_NAME_BYTES +		\
+			    KEXEC_CORE_NOTE_DESC_BYTES )
+
 /*
  * This structure is used to hold the arguments that are used when loading
  * kernel binaries.
@@ -136,7 +151,7 @@ #define KEXEC_FLAGS    (KEXEC_ON_CRASH) 
 /* Location of a reserved region to hold the crash kernel.
  */
 extern struct resource crashk_res;
-typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4];
 extern note_buf_t *crash_notes;
 
 
diff --git a/include/linux/key.h b/include/linux/key.h
index 169f05e..a9220e7 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -160,6 +160,8 @@ #define KEY_FLAG_NEGATIVE	5	/* set if ke
 	 */
 	union {
 		struct list_head	link;
+		unsigned long		x[2];
+		void			*p[2];
 	} type_data;
 
 	/* key data
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index b850e03..c288e41 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -22,7 +22,6 @@ #include <linux/list.h>
 #include <linux/sysfs.h>
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
-#include <linux/rwsem.h>
 #include <linux/kref.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
@@ -43,11 +42,9 @@ enum kobject_action {
 	KOBJ_ADD	= (__force kobject_action_t) 0x01,	/* exclusive to core */
 	KOBJ_REMOVE	= (__force kobject_action_t) 0x02,	/* exclusive to core */
 	KOBJ_CHANGE	= (__force kobject_action_t) 0x03,	/* device state change */
-	KOBJ_MOUNT	= (__force kobject_action_t) 0x04,	/* mount event for block devices (broken) */
-	KOBJ_UMOUNT	= (__force kobject_action_t) 0x05,	/* umount event for block devices (broken) */
-	KOBJ_OFFLINE	= (__force kobject_action_t) 0x06,	/* device offline */
-	KOBJ_ONLINE	= (__force kobject_action_t) 0x07,	/* device online */
-	KOBJ_MOVE	= (__force kobject_action_t) 0x08,	/* device move */
+	KOBJ_OFFLINE	= (__force kobject_action_t) 0x04,	/* device offline */
+	KOBJ_ONLINE	= (__force kobject_action_t) 0x05,	/* device online */
+	KOBJ_MOVE	= (__force kobject_action_t) 0x06,	/* device move */
 };
 
 struct kobject {
@@ -89,6 +86,8 @@ extern void kobject_unregister(struct ko
 extern struct kobject * kobject_get(struct kobject *);
 extern void kobject_put(struct kobject *);
 
+extern struct kobject *kobject_kset_add_dir(struct kset *kset,
+					    struct kobject *, const char *);
 extern struct kobject *kobject_add_dir(struct kobject *, const char *);
 
 extern char * kobject_get_path(struct kobject *, gfp_t);
@@ -125,7 +124,6 @@ struct kset_uevent_ops {
 };
 
 struct kset {
-	struct subsystem	* subsys;
 	struct kobj_type	* ktype;
 	struct list_head	list;
 	spinlock_t		list_lock;
@@ -172,33 +170,23 @@ extern struct kobject * kset_find_obj(st
 #define set_kset_name(str)	.kset = { .kobj = { .name = str } }
 
 
-
-struct subsystem {
-	struct kset		kset;
-	struct rw_semaphore	rwsem;
-};
-
 #define decl_subsys(_name,_type,_uevent_ops) \
-struct subsystem _name##_subsys = { \
-	.kset = { \
-		.kobj = { .name = __stringify(_name) }, \
-		.ktype = _type, \
-		.uevent_ops =_uevent_ops, \
-	} \
+struct kset _name##_subsys = { \
+	.kobj = { .name = __stringify(_name) }, \
+	.ktype = _type, \
+	.uevent_ops =_uevent_ops, \
 }
 #define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
-struct subsystem _varname##_subsys = { \
-	.kset = { \
-		.kobj = { .name = __stringify(_name) }, \
-		.ktype = _type, \
-		.uevent_ops =_uevent_ops, \
-	} \
+struct kset _varname##_subsys = { \
+	.kobj = { .name = __stringify(_name) }, \
+	.ktype = _type, \
+	.uevent_ops =_uevent_ops, \
 }
 
 /* The global /sys/kernel/ subsystem for people to chain off of */
-extern struct subsystem kernel_subsys;
+extern struct kset kernel_subsys;
 /* The global /sys/hypervisor/ subsystem  */
-extern struct subsystem hypervisor_subsys;
+extern struct kset hypervisor_subsys;
 
 /**
  * Helpers for setting the kset of registered objects.
@@ -216,7 +204,7 @@ extern struct subsystem hypervisor_subsy
  */
 
 #define kobj_set_kset_s(obj,subsys) \
-	(obj)->kobj.kset = &(subsys).kset
+	(obj)->kobj.kset = &(subsys)
 
 /**
  *	kset_set_kset_s(obj,subsys) - set kset for embedded kset.
@@ -230,7 +218,7 @@ #define kobj_set_kset_s(obj,subsys) \
  */
 
 #define kset_set_kset_s(obj,subsys) \
-	(obj)->kset.kobj.kset = &(subsys).kset
+	(obj)->kset.kobj.kset = &(subsys)
 
 /**
  *	subsys_set_kset(obj,subsys) - set kset for subsystem
@@ -243,29 +231,31 @@ #define kset_set_kset_s(obj,subsys) \
  */
 
 #define subsys_set_kset(obj,_subsys) \
-	(obj)->subsys.kset.kobj.kset = &(_subsys).kset
+	(obj)->subsys.kobj.kset = &(_subsys)
 
-extern void subsystem_init(struct subsystem *);
-extern int __must_check subsystem_register(struct subsystem *);
-extern void subsystem_unregister(struct subsystem *);
+extern void subsystem_init(struct kset *);
+extern int __must_check subsystem_register(struct kset *);
+extern void subsystem_unregister(struct kset *);
 
-static inline struct subsystem * subsys_get(struct subsystem * s)
+static inline struct kset *subsys_get(struct kset *s)
 {
-	return s ? container_of(kset_get(&s->kset),struct subsystem,kset) : NULL;
+	if (s)
+		return kset_get(s);
+	return NULL;
 }
 
-static inline void subsys_put(struct subsystem * s)
+static inline void subsys_put(struct kset *s)
 {
-	kset_put(&s->kset);
+	kset_put(s);
 }
 
 struct subsys_attribute {
 	struct attribute attr;
-	ssize_t (*show)(struct subsystem *, char *);
-	ssize_t (*store)(struct subsystem *, const char *, size_t); 
+	ssize_t (*show)(struct kset *, char *);
+	ssize_t (*store)(struct kset *, const char *, size_t);
 };
 
-extern int __must_check subsys_create_file(struct subsystem * ,
+extern int __must_check subsys_create_file(struct kset *,
 					struct subsys_attribute *);
 
 #if defined(CONFIG_HOTPLUG)
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 769be39..23adf60 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -78,7 +78,7 @@ struct kprobe {
 	kprobe_opcode_t *addr;
 
 	/* Allow user to indicate symbol name of the probe point */
-	char *symbol_name;
+	const char *symbol_name;
 
 	/* Offset into the symbol */
 	unsigned int offset;
@@ -123,12 +123,18 @@ DECLARE_PER_CPU(struct kprobe *, current
 DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
 #ifdef ARCH_SUPPORTS_KRETPROBES
-extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
+extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
+				   struct pt_regs *regs);
+extern int arch_trampoline_kprobe(struct kprobe *p);
 #else /* ARCH_SUPPORTS_KRETPROBES */
 static inline void arch_prepare_kretprobe(struct kretprobe *rp,
 					struct pt_regs *regs)
 {
 }
+static inline int arch_trampoline_kprobe(struct kprobe *p)
+{
+	return 0;
+}
 #endif /* ARCH_SUPPORTS_KRETPROBES */
 /*
  * Function-return probe -
@@ -157,6 +163,16 @@ struct kretprobe_instance {
 	struct task_struct *task;
 };
 
+static inline void kretprobe_assert(struct kretprobe_instance *ri,
+	unsigned long orig_ret_address, unsigned long trampoline_address)
+{
+	if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
+		printk("kretprobe BUG!: Processing kretprobe %p @ %p\n",
+				ri->rp, ri->rp->kp.addr);
+		BUG();
+	}
+}
+
 extern spinlock_t kretprobe_lock;
 extern struct mutex kprobe_mutex;
 extern int arch_prepare_kprobe(struct kprobe *p);
@@ -199,8 +215,6 @@ void jprobe_return(void);
 int register_kretprobe(struct kretprobe *rp);
 void unregister_kretprobe(struct kretprobe *rp);
 
-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, struct hlist_head *head);
 #else /* CONFIG_KPROBES */
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 248305b..81bb9c7 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -259,6 +259,12 @@ static inline s64 ktime_to_ns(const ktim
 
 #endif
 
+static inline s64 ktime_to_us(const ktime_t kt)
+{
+	struct timeval tv = ktime_to_timeval(kt);
+	return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
+}
+
 /*
  * The resolution of the clocks. The resolution value is returned in
  * the clock_getres() system call to give application programmers an
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 275354f..e6edca8 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -11,7 +11,7 @@ #define __LINUX_KVM_H
 #include <asm/types.h>
 #include <linux/ioctl.h>
 
-#define KVM_API_VERSION 4
+#define KVM_API_VERSION 12
 
 /*
  * Architectural interrupt line count, and the size of the bitmap needed
@@ -33,37 +33,39 @@ struct kvm_memory_region {
 /* for kvm_memory_region::flags */
 #define KVM_MEM_LOG_DIRTY_PAGES  1UL
 
-
-#define KVM_EXIT_TYPE_FAIL_ENTRY 1
-#define KVM_EXIT_TYPE_VM_EXIT    2
+struct kvm_memory_alias {
+	__u32 slot;  /* this has a different namespace than memory slots */
+	__u32 flags;
+	__u64 guest_phys_addr;
+	__u64 memory_size;
+	__u64 target_phys_addr;
+};
 
 enum kvm_exit_reason {
 	KVM_EXIT_UNKNOWN          = 0,
 	KVM_EXIT_EXCEPTION        = 1,
 	KVM_EXIT_IO               = 2,
-	KVM_EXIT_CPUID            = 3,
+	KVM_EXIT_HYPERCALL        = 3,
 	KVM_EXIT_DEBUG            = 4,
 	KVM_EXIT_HLT              = 5,
 	KVM_EXIT_MMIO             = 6,
 	KVM_EXIT_IRQ_WINDOW_OPEN  = 7,
 	KVM_EXIT_SHUTDOWN         = 8,
+	KVM_EXIT_FAIL_ENTRY       = 9,
+	KVM_EXIT_INTR             = 10,
 };
 
-/* for KVM_RUN */
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
 struct kvm_run {
 	/* in */
-	__u32 emulated;  /* skip current instruction */
-	__u32 mmio_completed; /* mmio request completed */
 	__u8 request_interrupt_window;
 	__u8 padding1[7];
 
 	/* out */
-	__u32 exit_type;
 	__u32 exit_reason;
-	__u32 instruction_length;
 	__u8 ready_for_interrupt_injection;
 	__u8 if_flag;
-	__u16 padding2;
+	__u8 padding2[2];
 
 	/* in (pre_kvm_run), out (post_kvm_run) */
 	__u64 cr8;
@@ -72,29 +74,26 @@ struct kvm_run {
 	union {
 		/* KVM_EXIT_UNKNOWN */
 		struct {
-			__u32 hardware_exit_reason;
+			__u64 hardware_exit_reason;
 		} hw;
+		/* KVM_EXIT_FAIL_ENTRY */
+		struct {
+			__u64 hardware_entry_failure_reason;
+		} fail_entry;
 		/* KVM_EXIT_EXCEPTION */
 		struct {
 			__u32 exception;
 			__u32 error_code;
 		} ex;
 		/* KVM_EXIT_IO */
-		struct {
+		struct kvm_io {
 #define KVM_EXIT_IO_IN  0
 #define KVM_EXIT_IO_OUT 1
 			__u8 direction;
 			__u8 size; /* bytes */
-			__u8 string;
-			__u8 string_down;
-			__u8 rep;
-			__u8 pad;
 			__u16 port;
-			__u64 count;
-			union {
-				__u64 address;
-				__u32 value;
-			};
+			__u32 count;
+			__u64 data_offset; /* relative to kvm_run start */
 		} io;
 		struct {
 		} debug;
@@ -105,6 +104,13 @@ #define KVM_EXIT_IO_OUT 1
 			__u32 len;
 			__u8  is_write;
 		} mmio;
+		/* KVM_EXIT_HYPERCALL */
+		struct {
+			__u64 args[6];
+			__u64 ret;
+			__u32 longmode;
+			__u32 pad;
+		} hypercall;
 	};
 };
 
@@ -118,6 +124,21 @@ struct kvm_regs {
 	__u64 rip, rflags;
 };
 
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+	__u8  fpr[8][16];
+	__u16 fcw;
+	__u16 fsw;
+	__u8  ftwx;  /* in fxsave format */
+	__u8  pad1;
+	__u16 last_opcode;
+	__u64 last_ip;
+	__u64 last_dp;
+	__u8  xmm[16][16];
+	__u32 mxcsr;
+	__u32 pad2;
+};
+
 struct kvm_segment {
 	__u64 base;
 	__u32 limit;
@@ -210,38 +231,74 @@ struct kvm_dirty_log {
 	};
 };
 
+struct kvm_cpuid_entry {
+	__u32 function;
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+	__u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+	__u32 nent;
+	__u32 padding;
+	struct kvm_cpuid_entry entries[0];
+};
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+	__u32 len;
+	__u8  sigset[0];
+};
+
 #define KVMIO 0xAE
 
 /*
  * ioctls for /dev/kvm fds:
  */
-#define KVM_GET_API_VERSION       _IO(KVMIO, 1)
-#define KVM_CREATE_VM             _IO(KVMIO, 2) /* returns a VM fd */
-#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 15, struct kvm_msr_list)
+#define KVM_GET_API_VERSION       _IO(KVMIO,   0x00)
+#define KVM_CREATE_VM             _IO(KVMIO,   0x01) /* returns a VM fd */
+#define KVM_GET_MSR_INDEX_LIST    _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+/*
+ * Check if a kvm extension is available.  Argument is extension number,
+ * return is 1 (yes) or 0 (no, sorry).
+ */
+#define KVM_CHECK_EXTENSION       _IO(KVMIO,   0x03)
+/*
+ * Get size for mmap(vcpu_fd)
+ */
+#define KVM_GET_VCPU_MMAP_SIZE    _IO(KVMIO,   0x04) /* in bytes */
 
 /*
  * ioctls for VM fds
  */
-#define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 10, struct kvm_memory_region)
+#define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 0x40, struct kvm_memory_region)
 /*
  * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
  * a vcpu fd.
  */
-#define KVM_CREATE_VCPU           _IOW(KVMIO, 11, int)
-#define KVM_GET_DIRTY_LOG         _IOW(KVMIO, 12, struct kvm_dirty_log)
+#define KVM_CREATE_VCPU           _IO(KVMIO,  0x41)
+#define KVM_GET_DIRTY_LOG         _IOW(KVMIO, 0x42, struct kvm_dirty_log)
+#define KVM_SET_MEMORY_ALIAS      _IOW(KVMIO, 0x43, struct kvm_memory_alias)
 
 /*
  * ioctls for vcpu fds
  */
-#define KVM_RUN                   _IOWR(KVMIO, 2, struct kvm_run)
-#define KVM_GET_REGS              _IOR(KVMIO, 3, struct kvm_regs)
-#define KVM_SET_REGS              _IOW(KVMIO, 4, struct kvm_regs)
-#define KVM_GET_SREGS             _IOR(KVMIO, 5, struct kvm_sregs)
-#define KVM_SET_SREGS             _IOW(KVMIO, 6, struct kvm_sregs)
-#define KVM_TRANSLATE             _IOWR(KVMIO, 7, struct kvm_translation)
-#define KVM_INTERRUPT             _IOW(KVMIO, 8, struct kvm_interrupt)
-#define KVM_DEBUG_GUEST           _IOW(KVMIO, 9, struct kvm_debug_guest)
-#define KVM_GET_MSRS              _IOWR(KVMIO, 13, struct kvm_msrs)
-#define KVM_SET_MSRS              _IOW(KVMIO, 14, struct kvm_msrs)
+#define KVM_RUN                   _IO(KVMIO,   0x80)
+#define KVM_GET_REGS              _IOR(KVMIO,  0x81, struct kvm_regs)
+#define KVM_SET_REGS              _IOW(KVMIO,  0x82, struct kvm_regs)
+#define KVM_GET_SREGS             _IOR(KVMIO,  0x83, struct kvm_sregs)
+#define KVM_SET_SREGS             _IOW(KVMIO,  0x84, struct kvm_sregs)
+#define KVM_TRANSLATE             _IOWR(KVMIO, 0x85, struct kvm_translation)
+#define KVM_INTERRUPT             _IOW(KVMIO,  0x86, struct kvm_interrupt)
+#define KVM_DEBUG_GUEST           _IOW(KVMIO,  0x87, struct kvm_debug_guest)
+#define KVM_GET_MSRS              _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS              _IOW(KVMIO,  0x89, struct kvm_msrs)
+#define KVM_SET_CPUID             _IOW(KVMIO,  0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK       _IOW(KVMIO,  0x8b, struct kvm_signal_mask)
+#define KVM_GET_FPU               _IOR(KVMIO,  0x8c, struct kvm_fpu)
+#define KVM_SET_FPU               _IOW(KVMIO,  0x8d, struct kvm_fpu)
 
 #endif
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 0cfbcb6..7906d75 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -210,6 +210,7 @@ enum {
 
 	/* host set flags */
 	ATA_HOST_SIMPLEX	= (1 << 0),	/* Host is simplex, one DMA channel per host only */
+	ATA_HOST_STARTED	= (1 << 1),	/* Host started */
 
 	/* various lengths of time */
 	ATA_TMOUT_BOOT		= 30 * HZ,	/* heuristic */
@@ -281,11 +282,13 @@ enum {
 	ATA_EHI_NO_AUTOPSY	= (1 << 2),  /* no autopsy */
 	ATA_EHI_QUIET		= (1 << 3),  /* be quiet */
 
-	ATA_EHI_DID_RESET	= (1 << 16), /* already reset this port */
-	ATA_EHI_PRINTINFO	= (1 << 17), /* print configuration info */
-	ATA_EHI_SETMODE		= (1 << 18), /* configure transfer mode */
-	ATA_EHI_POST_SETMODE	= (1 << 19), /* revaildating after setmode */
+	ATA_EHI_DID_SOFTRESET	= (1 << 16), /* already soft-reset this port */
+	ATA_EHI_DID_HARDRESET	= (1 << 17), /* already soft-reset this port */
+	ATA_EHI_PRINTINFO	= (1 << 18), /* print configuration info */
+	ATA_EHI_SETMODE		= (1 << 19), /* configure transfer mode */
+	ATA_EHI_POST_SETMODE	= (1 << 20), /* revaildating after setmode */
 
+	ATA_EHI_DID_RESET	= ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
 	ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
 
 	/* max repeat if error condition is still set after ->error_handler */
@@ -293,18 +296,8 @@ enum {
 
 	/* how hard are we gonna try to probe/recover devices */
 	ATA_PROBE_MAX_TRIES	= 3,
-	ATA_EH_RESET_TRIES	= 3,
 	ATA_EH_DEV_TRIES	= 3,
 
-	/* Drive spinup time (time from power-on to the first D2H FIS)
-	 * in msecs - 8s currently.  Failing to get ready in this time
-	 * isn't critical.  It will result in reset failure for
-	 * controllers which can't wait for the first D2H FIS.  libata
-	 * will retry, so it just has to be long enough to spin up
-	 * 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 */
 
@@ -345,8 +338,9 @@ struct ata_queued_cmd;
 
 /* typedefs */
 typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
-typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline);
+typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes,
+			      unsigned long deadline);
 typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
 
 struct ata_ioports {
@@ -367,34 +361,6 @@ struct ata_ioports {
 	void __iomem		*scr_addr;
 };
 
-struct ata_probe_ent {
-	struct list_head	node;
-	struct device 		*dev;
-	const struct ata_port_operations *port_ops;
-	struct scsi_host_template *sht;
-	struct ata_ioports	port[ATA_MAX_PORTS];
-	unsigned int		n_ports;
-	unsigned int		dummy_port_mask;
-	unsigned int		pio_mask;
-	unsigned int		mwdma_mask;
-	unsigned int		udma_mask;
-	unsigned long		irq;
-	unsigned long		irq2;
-	unsigned int		irq_flags;
-	unsigned long		port_flags;
-	unsigned long		_host_flags;
-	void __iomem * const	*iomap;
-	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 {
 	spinlock_t		lock;
 	struct device 		*dev;
@@ -427,6 +393,7 @@ struct ata_queued_cmd {
 	int			dma_dir;
 
 	unsigned int		pad_len;
+	unsigned int		sect_size;
 
 	unsigned int		nbytes;
 	unsigned int		curbytes;
@@ -472,6 +439,7 @@ struct ata_device {
 	struct scsi_device	*sdev;		/* attached SCSI device */
 	/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
 	u64			n_sectors;	/* size of device, if ATA */
+	u64			n_sectors_boot;	/* size of ATA device at startup */
 	unsigned int		class;		/* ATA_DEV_xxx */
 	u16			id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
 	u8			pio_mode;
@@ -517,7 +485,6 @@ struct ata_eh_info {
 	unsigned int		dev_action[ATA_MAX_DEVICES]; /* dev EH action */
 	unsigned int		flags;		/* ATA_EHI_* flags */
 
-	unsigned long		hotplug_timestamp;
 	unsigned int		probe_mask;
 
 	char			desc[ATA_EH_DESC_LEN];
@@ -597,11 +564,11 @@ struct ata_port {
 struct ata_port_operations {
 	void (*port_disable) (struct ata_port *);
 
-	void (*dev_config) (struct ata_port *, struct ata_device *);
+	void (*dev_config) (struct ata_device *);
 
 	void (*set_piomode) (struct ata_port *, struct ata_device *);
 	void (*set_dmamode) (struct ata_port *, struct ata_device *);
-	unsigned long (*mode_filter) (const struct ata_port *, struct ata_device *, unsigned long);
+	unsigned long (*mode_filter) (struct ata_device *, unsigned long);
 
 	void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf);
 	void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -616,6 +583,8 @@ struct ata_port_operations {
 
 	void (*post_set_mode) (struct ata_port *ap);
 
+	int (*cable_detect) (struct ata_port *ap);
+
 	int  (*check_atapi_dma) (struct ata_queued_cmd *qc);
 
 	void (*bmdma_setup) (struct ata_queued_cmd *qc);
@@ -664,6 +633,7 @@ struct ata_port_info {
 	unsigned long		mwdma_mask;
 	unsigned long		udma_mask;
 	const struct ata_port_operations *port_ops;
+	irq_handler_t		irq_handler;
 	void 			*private_data;
 };
 
@@ -686,6 +656,7 @@ extern const unsigned long sata_deb_timi
 extern const unsigned long sata_deb_timing_long[];
 
 extern const struct ata_port_operations ata_dummy_port_ops;
+extern const struct ata_port_info ata_dummy_port_info;
 
 static inline const unsigned long *
 sata_ehc_deb_timing(struct ata_eh_context *ehc)
@@ -701,18 +672,23 @@ static inline int ata_port_is_dummy(stru
 	return ap->ops == &ata_dummy_port_ops;
 }
 
+extern void sata_print_link_status(struct ata_port *ap);
 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);
 extern void ata_bus_reset(struct ata_port *ap);
 extern int sata_set_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
-extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
-extern int ata_std_prereset(struct ata_port *ap);
-extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
-extern int sata_port_hardreset(struct ata_port *ap,
-			       const unsigned long *timing);
-extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
+extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param,
+			     unsigned long deadline);
+extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param,
+			   unsigned long deadline);
+extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline);
+extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+			     unsigned long deadline);
+extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+			       unsigned long deadline);
+extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+			      unsigned long deadline);
 extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
 extern void ata_port_disable(struct ata_port *);
 extern void ata_std_ports(struct ata_ioports *ioaddr);
@@ -728,7 +704,15 @@ extern int ata_pci_device_resume(struct 
 #endif
 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 struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
+extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+			const struct ata_port_info * const * ppi, int n_ports);
+extern int ata_host_start(struct ata_host *host);
+extern int ata_host_register(struct ata_host *host,
+			     struct scsi_host_template *sht);
+extern int ata_host_activate(struct ata_host *host, int irq,
+			     irq_handler_t irq_handler, unsigned long irq_flags,
+			     struct scsi_host_template *sht);
 extern void ata_host_detach(struct ata_host *host);
 extern void ata_host_init(struct ata_host *, struct device *,
 			  unsigned long, const struct ata_port_operations *);
@@ -760,6 +744,7 @@ #endif
 extern int ata_ratelimit(void);
 extern int ata_busy_sleep(struct ata_port *ap,
 			  unsigned long timeout_pat, unsigned long timeout);
+extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline);
 extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn,
 				void *data, unsigned long delay);
 extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
@@ -828,11 +813,17 @@ extern void ata_scsi_slave_destroy(struc
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
 				       int queue_depth);
 extern struct ata_device *ata_dev_pair(struct ata_device *adev);
+extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
 extern u8 ata_irq_on(struct ata_port *ap);
 extern u8 ata_dummy_irq_on(struct ata_port *ap);
 extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq);
 extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq);
 
+extern int ata_cable_40wire(struct ata_port *ap);
+extern int ata_cable_80wire(struct ata_port *ap);
+extern int ata_cable_sata(struct ata_port *ap);
+extern int ata_cable_unknown(struct ata_port *ap);
+
 /*
  * Timing helpers
  */
@@ -870,10 +861,13 @@ struct pci_bits {
 	unsigned long		val;
 };
 
-extern struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
+extern int ata_pci_init_native_host(struct ata_host *host,
+				    unsigned int port_mask);
+extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
+				const struct ata_port_info * const * ppi,
+				int n_ports, struct ata_host **r_host);
 extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
-extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_device *, unsigned long);
+extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
 #endif /* CONFIG_PCI */
 
 /*
@@ -920,12 +914,7 @@ #define ata_ehi_clear_desc(ehi) do { \
 
 static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
-	if (ehi->flags & ATA_EHI_HOTPLUGGED)
-		return;
-
 	ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
-	ehi->hotplug_timestamp = jiffies;
-
 	ehi->action |= ATA_EH_SOFTRESET;
 	ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
@@ -1173,6 +1162,7 @@ static inline void ata_qc_reinit(struct 
 	qc->n_elem = 0;
 	qc->err_mask = 0;
 	qc->pad_len = 0;
+	qc->sect_size = ATA_SECT_SIZE;
 
 	ata_tf_init(qc->dev, &qc->tf);
 
@@ -1220,7 +1210,7 @@ static inline void ata_pad_free(struct a
 
 static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
 {
-	return (struct ata_port *) &host->hostdata[0];
+	return *(struct ata_port **)&host->hostdata[0];
 }
 
 #endif /* __LINUX_LIBATA_H__ */
diff --git a/include/linux/list.h b/include/linux/list.h
index f9d71ea..9202703 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -426,6 +426,17 @@ #define list_entry(ptr, type, member) \
 	container_of(ptr, type, member)
 
 /**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
  * list_for_each	-	iterate over a list
  * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index ac25b56..05707e2 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -88,7 +88,7 @@ struct nlm_wait;
 /*
  * Memory chunk for NLM client RPC request.
  */
-#define NLMCLNT_OHSIZE		(sizeof(utsname()->nodename)+10)
+#define NLMCLNT_OHSIZE		((__NEW_UTS_LEN) + 10u)
 struct nlm_rqst {
 	unsigned int		a_flags;	/* initial RPC task flags */
 	struct nlm_host *	a_host;		/* host handle */
@@ -119,6 +119,9 @@ struct nlm_file {
  * couldn't be granted because of a conflicting lock).
  */
 #define NLM_NEVER		(~(unsigned long) 0)
+/* timeout on non-blocking call: */
+#define NLM_TIMEOUT		(7 * HZ)
+
 struct nlm_block {
 	struct kref		b_count;	/* Reference count */
 	struct list_head	b_list;		/* linked list of all blocks */
@@ -130,6 +133,13 @@ struct nlm_block {
 	unsigned int		b_id;		/* block id */
 	unsigned char		b_granted;	/* VFS granted lock */
 	struct nlm_file *	b_file;		/* file in question */
+	struct cache_req *	b_cache_req;	/* deferred request handling */
+	struct file_lock *	b_fl;		/* set for GETLK */
+	struct cache_deferred_req * b_deferred_req;
+	unsigned int		b_flags;	/* block flags */
+#define B_QUEUED		1	/* lock queued */
+#define B_GOT_CALLBACK		2	/* got lock or conflicting lock */
+#define B_TIMED_OUT		4	/* filesystem too slow to respond */
 };
 
 /*
@@ -185,8 +195,8 @@ typedef int	  (*nlm_host_match_fn_t)(str
 __be32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 					struct nlm_lock *, int, struct nlm_cookie *);
 __be32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-__be32		  nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
-					struct nlm_lock *);
+__be32		  nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
+			struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *);
 __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 *,
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 191a595..0b99b31 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -64,6 +64,8 @@ struct loop_device {
 	wait_queue_head_t	lo_event;
 
 	request_queue_t		*lo_queue;
+	struct gendisk		*lo_disk;
+	struct list_head	lo_list;
 };
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h
index bdc0112..580b3f4 100644
--- a/include/linux/mc146818rtc.h
+++ b/include/linux/mc146818rtc.h
@@ -22,8 +22,15 @@ extern spinlock_t rtc_lock;		/* serializ
 /* Some RTCs extend the mc146818 register set to support alarms of more
  * than 24 hours in the future; or dates that include a century code.
  * This platform_data structure can pass this information to the driver.
+ *
+ * Also, some platforms need suspend()/resume() hooks to kick in special
+ * handling of wake alarms, e.g. activating ACPI BIOS hooks or setting up
+ * a separate wakeup alarm used by some almost-clone chips.
  */
 struct cmos_rtc_board_info {
+	void	(*wake_on)(struct device *dev);
+	void	(*wake_off)(struct device *dev);
+
 	u8	rtc_day_alarm;		/* zero, or register index */
 	u8	rtc_mon_alarm;		/* zero, or register index */
 	u8	rtc_century;		/* zero, or register index */
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 75e55dc..e10a90a 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -2,18 +2,29 @@ #ifndef _LINUX_MIGRATE_H
 #define _LINUX_MIGRATE_H
 
 #include <linux/mm.h>
+#include <linux/mempolicy.h>
+#include <linux/pagemap.h>
 
 typedef struct page *new_page_t(struct page *, unsigned long private, int **);
 
+#ifdef CONFIG_MIGRATION
 /* Check if a vma is migratable */
 static inline int vma_migratable(struct vm_area_struct *vma)
 {
 	if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
 		return 0;
+	/*
+	 * Migration allocates pages in the highest zone. If we cannot
+	 * do so then migration (at least from node to node) is not
+	 * possible.
+	 */
+	if (vma->vm_file &&
+		gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
+								< policy_zone)
+			return 0;
 	return 1;
 }
 
-#ifdef CONFIG_MIGRATION
 extern int isolate_lru_page(struct page *p, struct list_head *pagelist);
 extern int putback_lru_pages(struct list_head *l);
 extern int migrate_page(struct address_space *,
@@ -28,6 +39,8 @@ extern int migrate_vmas(struct mm_struct
 		const nodemask_t *from, const nodemask_t *to,
 		unsigned long flags);
 #else
+static inline int vma_migratable(struct vm_area_struct *vma)
+					{ return 0; }
 
 static inline int isolate_lru_page(struct page *p, struct list_head *list)
 					{ return -ENOSYS; }
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 326da7d..dff9ea3 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -29,6 +29,7 @@ #define MISC_DYNAMIC_MINOR 255
 
 #define TUN_MINOR	     200
 #define	HPET_MINOR	     228
+#define KVM_MINOR            232
 
 struct device;
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 60e0e4a..4670ebd 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -267,21 +267,31 @@ static inline int get_page_unless_zero(s
 	return atomic_inc_not_zero(&page->_count);
 }
 
+static inline struct page *compound_head(struct page *page)
+{
+	if (unlikely(PageTail(page)))
+		return page->first_page;
+	return page;
+}
+
 static inline int page_count(struct page *page)
 {
-	if (unlikely(PageCompound(page)))
-		page = (struct page *)page_private(page);
-	return atomic_read(&page->_count);
+	return atomic_read(&compound_head(page)->_count);
 }
 
 static inline void get_page(struct page *page)
 {
-	if (unlikely(PageCompound(page)))
-		page = (struct page *)page_private(page);
+	page = compound_head(page);
 	VM_BUG_ON(atomic_read(&page->_count) == 0);
 	atomic_inc(&page->_count);
 }
 
+static inline struct page *virt_to_head_page(const void *x)
+{
+	struct page *page = virt_to_page(x);
+	return compound_head(page);
+}
+
 /*
  * Setup the page count before being freed into the page allocator for
  * the first time (boot or memory hotplug)
@@ -314,6 +324,18 @@ static inline compound_page_dtor *get_co
 	return (compound_page_dtor *)page[1].lru.next;
 }
 
+static inline int compound_order(struct page *page)
+{
+	if (!PageHead(page))
+		return 0;
+	return (unsigned long)page[1].lru.prev;
+}
+
+static inline void set_compound_order(struct page *page, unsigned long order)
+{
+	page[1].lru.prev = (void *)order;
+}
+
 /*
  * Multiple processes may "see" the same page. E.g. for untouched
  * mappings of /dev/null, all processes see the same page full of
@@ -850,8 +872,26 @@ static inline int vma_wants_writenotify(
 
 extern pte_t *FASTCALL(get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl));
 
+#ifdef __PAGETABLE_PUD_FOLDED
+static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd,
+						unsigned long address)
+{
+	return 0;
+}
+#else
 int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address);
+#endif
+
+#ifdef __PAGETABLE_PMD_FOLDED
+static inline int __pmd_alloc(struct mm_struct *mm, pud_t *pud,
+						unsigned long address)
+{
+	return 0;
+}
+#else
 int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address);
+#endif
+
 int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address);
 int __pte_alloc_kernel(pmd_t *pmd, unsigned long address);
 
@@ -1130,6 +1170,11 @@ #define FOLL_TOUCH	0x02	/* mark page acc
 #define FOLL_GET	0x04	/* do get_page on page */
 #define FOLL_ANON	0x08	/* give ZERO_PAGE if no pgtable */
 
+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);
+
 #ifdef CONFIG_PROC_FS
 void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
 #else
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index c3852fd..e30687b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -19,10 +19,16 @@ 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,
+	union {
+		atomic_t _mapcount;	/* Count of ptes mapped in mms,
 					 * to show when page is mapped
 					 * & limit reverse map searches.
 					 */
+		struct {	/* SLUB uses */
+			short unsigned int inuse;
+			short unsigned int offset;
+		};
+	};
 	union {
 	    struct {
 		unsigned long private;		/* Mapping-private opaque data:
@@ -43,8 +49,15 @@ struct page {
 #if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
 	    spinlock_t ptl;
 #endif
+	    struct {			/* SLUB uses */
+		struct page *first_page;	/* Compound pages */
+		struct kmem_cache *slab;	/* Pointer to slab */
+	    };
+	};
+	union {
+		pgoff_t index;		/* Our offset within mapping. */
+		void *freelist;		/* SLUB: pointer to free object */
 	};
-	pgoff_t index;			/* Our offset within mapping. */
 	struct list_head lru;		/* Pageout list, eg. active_list
 					 * protected by zone->lru_lock !
 					 */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e45712a..badf702 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -10,7 +10,7 @@
 #ifndef LINUX_MMC_CARD_H
 #define LINUX_MMC_CARD_H
 
-#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
 
 struct mmc_cid {
 	unsigned int		manfid;
@@ -41,6 +41,7 @@ struct mmc_csd {
 
 struct mmc_ext_csd {
 	unsigned int		hs_max_dtr;
+	unsigned int		sectors;
 };
 
 struct sd_scr {
@@ -60,18 +61,17 @@ struct mmc_host;
  * MMC device
  */
 struct mmc_card {
-	struct list_head	node;		/* node in hosts devices list */
 	struct mmc_host		*host;		/* the host this device belongs to */
 	struct device		dev;		/* the device */
 	unsigned int		rca;		/* relative card address of device */
+	unsigned int		type;		/* card type */
+#define MMC_TYPE_MMC		0		/* MMC card */
+#define MMC_TYPE_SD		1		/* SD card */
 	unsigned int		state;		/* (our) card state */
 #define MMC_STATE_PRESENT	(1<<0)		/* present in sysfs */
-#define MMC_STATE_DEAD		(1<<1)		/* device no longer in stack */
-#define MMC_STATE_BAD		(1<<2)		/* unrecognised device */
-#define MMC_STATE_SDCARD	(1<<3)		/* is an SD card */
-#define MMC_STATE_READONLY	(1<<4)		/* card is read-only */
-#define MMC_STATE_HIGHSPEED	(1<<5)		/* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR	(1<<6)		/* card uses block-addressing */
+#define MMC_STATE_READONLY	(1<<1)		/* card is read-only */
+#define MMC_STATE_HIGHSPEED	(1<<2)		/* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR	(1<<3)		/* card uses block-addressing */
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	u32			raw_scr[2];	/* raw card SCR */
@@ -82,18 +82,15 @@ #define MMC_STATE_BLOCKADDR	(1<<6)		/* c
 	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
 };
 
+#define mmc_card_mmc(c)		((c)->type == MMC_TYPE_MMC)
+#define mmc_card_sd(c)		((c)->type == MMC_TYPE_SD)
+
 #define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
-#define mmc_card_dead(c)	((c)->state & MMC_STATE_DEAD)
-#define mmc_card_bad(c)		((c)->state & MMC_STATE_BAD)
-#define mmc_card_sd(c)		((c)->state & MMC_STATE_SDCARD)
 #define mmc_card_readonly(c)	((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)	((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)	((c)->state & MMC_STATE_BLOCKADDR)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
-#define mmc_card_set_dead(c)	((c)->state |= MMC_STATE_DEAD)
-#define mmc_card_set_bad(c)	((c)->state |= MMC_STATE_BAD)
-#define mmc_card_set_sd(c)	((c)->state |= MMC_STATE_SDCARD)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
@@ -119,11 +116,4 @@ struct mmc_driver {
 extern int mmc_register_driver(struct mmc_driver *);
 extern void mmc_unregister_driver(struct mmc_driver *);
 
-static inline int mmc_card_claim_host(struct mmc_card *card)
-{
-	return __mmc_claim_host(card->host, card);
-}
-
-#define mmc_card_release_host(c)	mmc_release_host((c)->host)
-
 #endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
new file mode 100644
index 0000000..04bbe12
--- /dev/null
+++ b/include/linux/mmc/core.h
@@ -0,0 +1,112 @@
+/*
+ *  linux/include/linux/mmc/core.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.
+ */
+#ifndef LINUX_MMC_CORE_H
+#define LINUX_MMC_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+struct request;
+struct mmc_data;
+struct mmc_request;
+
+struct mmc_command {
+	u32			opcode;
+	u32			arg;
+	u32			resp[4];
+	unsigned int		flags;		/* expected response type */
+#define MMC_RSP_PRESENT	(1 << 0)
+#define MMC_RSP_136	(1 << 1)		/* 136 bit response */
+#define MMC_RSP_CRC	(1 << 2)		/* expect valid crc */
+#define MMC_RSP_BUSY	(1 << 3)		/* card may send busy */
+#define MMC_RSP_OPCODE	(1 << 4)		/* response contains opcode */
+#define MMC_CMD_MASK	(3 << 5)		/* command type */
+#define MMC_CMD_AC	(0 << 5)
+#define MMC_CMD_ADTC	(1 << 5)
+#define MMC_CMD_BC	(2 << 5)
+#define MMC_CMD_BCR	(3 << 5)
+
+/*
+ * These are the response types, and correspond to valid bit
+ * patterns of the above flags.  One additional valid pattern
+ * is all zeros, which means we don't expect a response.
+ */
+#define MMC_RSP_NONE	(0)
+#define MMC_RSP_R1	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+#define MMC_RSP_R2	(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3	(MMC_RSP_PRESENT)
+#define MMC_RSP_R6	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+
+#define mmc_resp_type(cmd)	((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+/*
+ * These are the command types.
+ */
+#define mmc_cmd_type(cmd)	((cmd)->flags & MMC_CMD_MASK)
+
+	unsigned int		retries;	/* max number of retries */
+	unsigned int		error;		/* command error */
+
+#define MMC_ERR_NONE	0
+#define MMC_ERR_TIMEOUT	1
+#define MMC_ERR_BADCRC	2
+#define MMC_ERR_FIFO	3
+#define MMC_ERR_FAILED	4
+#define MMC_ERR_INVALID	5
+
+	struct mmc_data		*data;		/* data segment associated with cmd */
+	struct mmc_request	*mrq;		/* associated request */
+};
+
+struct mmc_data {
+	unsigned int		timeout_ns;	/* data timeout (in ns, max 80ms) */
+	unsigned int		timeout_clks;	/* data timeout (in clocks) */
+	unsigned int		blksz;		/* data block size */
+	unsigned int		blocks;		/* number of blocks */
+	unsigned int		error;		/* data error */
+	unsigned int		flags;
+
+#define MMC_DATA_WRITE	(1 << 8)
+#define MMC_DATA_READ	(1 << 9)
+#define MMC_DATA_STREAM	(1 << 10)
+#define MMC_DATA_MULTI	(1 << 11)
+
+	unsigned int		bytes_xfered;
+
+	struct mmc_command	*stop;		/* stop command */
+	struct mmc_request	*mrq;		/* associated request */
+
+	unsigned int		sg_len;		/* size of scatter list */
+	struct scatterlist	*sg;		/* I/O scatter list */
+};
+
+struct mmc_request {
+	struct mmc_command	*cmd;
+	struct mmc_data		*data;
+	struct mmc_command	*stop;
+
+	void			*done_data;	/* completion data */
+	void			(*done)(struct mmc_request *);/* completion function */
+};
+
+struct mmc_host;
+struct mmc_card;
+
+extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
+	struct mmc_command *, int);
+
+extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int);
+
+extern void mmc_claim_host(struct mmc_host *host);
+extern void mmc_release_host(struct mmc_host *host);
+
+#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index bfcef8a..b1350df 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -10,36 +10,13 @@
 #ifndef LINUX_MMC_HOST_H
 #define LINUX_MMC_HOST_H
 
-#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
 
 struct mmc_ios {
 	unsigned int	clock;			/* clock rate */
 	unsigned short	vdd;
 
-#define	MMC_VDD_150	0
-#define	MMC_VDD_155	1
-#define	MMC_VDD_160	2
-#define	MMC_VDD_165	3
-#define	MMC_VDD_170	4
-#define	MMC_VDD_180	5
-#define	MMC_VDD_190	6
-#define	MMC_VDD_200	7
-#define	MMC_VDD_210	8
-#define	MMC_VDD_220	9
-#define	MMC_VDD_230	10
-#define	MMC_VDD_240	11
-#define	MMC_VDD_250	12
-#define	MMC_VDD_260	13
-#define	MMC_VDD_270	14
-#define	MMC_VDD_280	15
-#define	MMC_VDD_290	16
-#define	MMC_VDD_300	17
-#define	MMC_VDD_310	18
-#define	MMC_VDD_320	19
-#define	MMC_VDD_330	20
-#define	MMC_VDD_340	21
-#define	MMC_VDD_350	22
-#define	MMC_VDD_360	23
+/* vdd stores the bit number of the selected voltage range from below. */
 
 	unsigned char	bus_mode;		/* command output mode */
 
@@ -88,6 +65,24 @@ struct mmc_host {
 	unsigned int		f_max;
 	u32			ocr_avail;
 
+#define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
+#define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22		0x00000200	/* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23		0x00000400	/* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24		0x00000800	/* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25		0x00001000	/* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26		0x00002000	/* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27		0x00004000	/* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28		0x00008000	/* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29		0x00010000	/* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30		0x00020000	/* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31		0x00040000	/* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32		0x00080000	/* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33		0x00100000	/* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34		0x00200000	/* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */
+
 	unsigned long		caps;		/* Host capabilities */
 
 #define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
@@ -106,6 +101,8 @@ #define MMC_CAP_SD_HIGHSPEED	(1 << 4)	/*
 	unsigned int		max_blk_count;	/* maximum number of blocks in one req */
 
 	/* private data */
+	spinlock_t		lock;		/* lock for claim and bus ops */
+
 	struct mmc_ios		ios;		/* current io bus settings */
 	u32			ocr;		/* the current OCR setting */
 
@@ -113,15 +110,19 @@ #define MMC_CAP_SD_HIGHSPEED	(1 << 4)	/*
 #define MMC_MODE_MMC		0
 #define MMC_MODE_SD		1
 
-	struct list_head	cards;		/* devices attached to this host */
+	struct mmc_card		*card;		/* device attached to this host */
 
 	wait_queue_head_t	wq;
-	spinlock_t		lock;		/* claimed lock */
 	unsigned int		claimed:1;	/* host exclusively claimed */
 
-	struct mmc_card		*card_selected;	/* the selected MMC card */
-
 	struct delayed_work	detect;
+#ifdef CONFIG_MMC_DEBUG
+	unsigned int		removed:1;	/* host is being removed */
+#endif
+
+	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
+	unsigned int		bus_refs;	/* reference counter */
+	unsigned int		bus_dead:1;	/* bus has been released */
 
 	unsigned long		private[0] ____cacheline_aligned;
 };
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index cdc54be..e3ed9b9 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -1,119 +1,257 @@
 /*
- *  linux/include/linux/mmc/mmc.h
+ * Header for MultiMediaCard (MMC)
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2002/06/18 12:37:30 $
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
  */
-#ifndef MMC_H
-#define MMC_H
-
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-
-struct request;
-struct mmc_data;
-struct mmc_request;
-
-struct mmc_command {
-	u32			opcode;
-	u32			arg;
-	u32			resp[4];
-	unsigned int		flags;		/* expected response type */
-#define MMC_RSP_PRESENT	(1 << 0)
-#define MMC_RSP_136	(1 << 1)		/* 136 bit response */
-#define MMC_RSP_CRC	(1 << 2)		/* expect valid crc */
-#define MMC_RSP_BUSY	(1 << 3)		/* card may send busy */
-#define MMC_RSP_OPCODE	(1 << 4)		/* response contains opcode */
-#define MMC_CMD_MASK	(3 << 5)		/* command type */
-#define MMC_CMD_AC	(0 << 5)
-#define MMC_CMD_ADTC	(1 << 5)
-#define MMC_CMD_BC	(2 << 5)
-#define MMC_CMD_BCR	(3 << 5)
+
+#ifndef MMC_MMC_H
+#define MMC_MMC_H
+
+/* Standard MMC commands (4.1)           type  argument     response */
+   /* class 1 */
+#define	MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
+#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
+#define MMC_SWITCH                6   /* ac   [31:0] See below   R1b */
+#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_EXT_CSD          8   /* adtc                    R1  */
+#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
+#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
+#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
+#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+
+  /* class 2 */
+#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
+#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+
+  /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+
+  /* class 4 */
+#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
+
+  /* class 6 */
+#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
+#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
+#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
+
+  /* class 5 */
+#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE                38   /* ac                      R1b */
+
+  /* class 9 */
+#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
+
+  /* class 7 */
+#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
+
+  /* class 8 */
+#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
 
 /*
- * These are the response types, and correspond to valid bit
- * patterns of the above flags.  One additional valid pattern
- * is all zeros, which means we don't expect a response.
+ * MMC_SWITCH argument format:
+ *
+ *	[31:26] Always 0
+ *	[25:24] Access Mode
+ *	[23:16] Location of target Byte in EXT_CSD
+ *	[15:08] Value Byte
+ *	[07:03] Always 0
+ *	[02:00] Command Set
  */
-#define MMC_RSP_NONE	(0)
-#define MMC_RSP_R1	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R1B	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
-#define MMC_RSP_R2	(MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
-#define MMC_RSP_R3	(MMC_RSP_PRESENT)
-#define MMC_RSP_R6	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R7	(MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-
-#define mmc_resp_type(cmd)	((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
 
 /*
- * These are the command types.
+  MMC status in R1
+  Type
+  	e : error bit
+	s : status bit
+	r : detected and set for the actual command response
+	x : detected and set during command execution. the host must poll
+            the card by sending status command in order to read these bits.
+  Clear condition
+  	a : according to the card state
+	b : always related to the previous command. Reception of
+            a valid command will clear it (with a delay of one command)
+	c : clear by read
  */
-#define mmc_cmd_type(cmd)	((cmd)->flags & MMC_CMD_MASK)
 
-	unsigned int		retries;	/* max number of retries */
-	unsigned int		error;		/* command error */
+#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
+#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
+#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
+#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
+#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
+#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
+#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
+#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
+#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
+#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
+#define R1_CC_ERROR		(1 << 20)	/* erx, c */
+#define R1_ERROR		(1 << 19)	/* erx, c */
+#define R1_UNDERRUN		(1 << 18)	/* ex, c */
+#define R1_OVERRUN		(1 << 17)	/* ex, c */
+#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
+#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
+#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
+#define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
+#define R1_APP_CMD		(1 << 5)	/* sr, c */
 
-#define MMC_ERR_NONE	0
-#define MMC_ERR_TIMEOUT	1
-#define MMC_ERR_BADCRC	2
-#define MMC_ERR_FIFO	3
-#define MMC_ERR_FAILED	4
-#define MMC_ERR_INVALID	5
+/* These are unpacked versions of the actual responses */
 
-	struct mmc_data		*data;		/* data segment associated with cmd */
-	struct mmc_request	*mrq;		/* associated request */
+struct _mmc_csd {
+	u8  csd_structure;
+	u8  spec_vers;
+	u8  taac;
+	u8  nsac;
+	u8  tran_speed;
+	u16 ccc;
+	u8  read_bl_len;
+	u8  read_bl_partial;
+	u8  write_blk_misalign;
+	u8  read_blk_misalign;
+	u8  dsr_imp;
+	u16 c_size;
+	u8  vdd_r_curr_min;
+	u8  vdd_r_curr_max;
+	u8  vdd_w_curr_min;
+	u8  vdd_w_curr_max;
+	u8  c_size_mult;
+	union {
+		struct { /* MMC system specification version 3.1 */
+			u8  erase_grp_size;
+			u8  erase_grp_mult;
+		} v31;
+		struct { /* MMC system specification version 2.2 */
+			u8  sector_size;
+			u8  erase_grp_size;
+		} v22;
+	} erase;
+	u8  wp_grp_size;
+	u8  wp_grp_enable;
+	u8  default_ecc;
+	u8  r2w_factor;
+	u8  write_bl_len;
+	u8  write_bl_partial;
+	u8  file_format_grp;
+	u8  copy;
+	u8  perm_write_protect;
+	u8  tmp_write_protect;
+	u8  file_format;
+	u8  ecc;
 };
 
-struct mmc_data {
-	unsigned int		timeout_ns;	/* data timeout (in ns, max 80ms) */
-	unsigned int		timeout_clks;	/* data timeout (in clocks) */
-	unsigned int		blksz;		/* data block size */
-	unsigned int		blocks;		/* number of blocks */
-	unsigned int		error;		/* data error */
-	unsigned int		flags;
+/*
+ * OCR bits are mostly in host.h
+ */
+#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
 
-#define MMC_DATA_WRITE	(1 << 8)
-#define MMC_DATA_READ	(1 << 9)
-#define MMC_DATA_STREAM	(1 << 10)
-#define MMC_DATA_MULTI	(1 << 11)
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC		(1<<0)	/* (0) Basic protocol functions */
+					/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ		(1<<1)	/* (1) Stream read commands */
+					/* (CMD11) */
+#define CCC_BLOCK_READ		(1<<2)	/* (2) Block read commands */
+					/* (CMD16,17,18) */
+#define CCC_STREAM_WRITE	(1<<3)	/* (3) Stream write commands */
+					/* (CMD20) */
+#define CCC_BLOCK_WRITE		(1<<4)	/* (4) Block write commands */
+					/* (CMD16,24,25,26,27) */
+#define CCC_ERASE		(1<<5)	/* (5) Ability to erase blocks */
+					/* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT		(1<<6)	/* (6) Able to write protect blocks */
+					/* (CMD28,29,30) */
+#define CCC_LOCK_CARD		(1<<7)	/* (7) Able to lock down card */
+					/* (CMD16,CMD42) */
+#define CCC_APP_SPEC		(1<<8)	/* (8) Application specific */
+					/* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE		(1<<9)	/* (9) I/O mode */
+					/* (CMD5,39,40,52,53) */
+#define CCC_SWITCH		(1<<10)	/* (10) High speed switch */
+					/* (CMD6,34,35,36,37,50) */
+					/* (11) Reserved */
+					/* (CMD?) */
 
-	unsigned int		bytes_xfered;
+/*
+ * CSD field definitions
+ */
 
-	struct mmc_command	*stop;		/* stop command */
-	struct mmc_request	*mrq;		/* associated request */
+#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD  3           /* Version is coded in CSD_STRUCTURE in EXT_CSD */
 
-	unsigned int		sg_len;		/* size of scatter list */
-	struct scatterlist	*sg;		/* I/O scatter list */
-};
+#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4      4           /* Implements system specification 4.0 - 4.1 */
 
-struct mmc_request {
-	struct mmc_command	*cmd;
-	struct mmc_data		*data;
-	struct mmc_command	*stop;
+/*
+ * EXT_CSD fields
+ */
 
-	void			*done_data;	/* completion data */
-	void			(*done)(struct mmc_request *);/* completion function */
-};
+#define EXT_CSD_BUS_WIDTH	183	/* R/W */
+#define EXT_CSD_HS_TIMING	185	/* R/W */
+#define EXT_CSD_CARD_TYPE	196	/* RO */
+#define EXT_CSD_SEC_CNT		212	/* RO, 4 bytes */
+
+/*
+ * EXT_CSD field definitions
+ */
 
-struct mmc_host;
-struct mmc_card;
+#define EXT_CSD_CMD_SET_NORMAL		(1<<0)
+#define EXT_CSD_CMD_SET_SECURE		(1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
 
-extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
-extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
-extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
-	struct mmc_command *, int);
+#define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
 
-extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int);
+#define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 
-extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
+/*
+ * MMC_SWITCH access modes
+ */
 
-static inline void mmc_claim_host(struct mmc_host *host)
-{
-	__mmc_claim_host(host, (struct mmc_card *)-1);
-}
+#define MMC_SWITCH_MODE_CMD_SET		0x00	/* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS	0x01	/* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS	0x02	/* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE	0x03	/* Set target to value */
 
-extern void mmc_release_host(struct mmc_host *host);
+#endif  /* MMC_MMC_PROTOCOL_H */
 
-#endif
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
deleted file mode 100644
index c90b676..0000000
--- a/include/linux/mmc/protocol.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Header for MultiMediaCard (MMC)
- *
- * Copyright 2002 Hewlett-Packard Company
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Many thanks to Alessandro Rubini and Jonathan Corbet!
- *
- * Based strongly on code by:
- *
- * Author: Yong-iL Joh <tolkien@mizi.com>
- * Date  : $Date: 2002/06/18 12:37:30 $
- *
- * Author:  Andrew Christian
- *          15 May 2002
- */
-
-#ifndef MMC_MMC_PROTOCOL_H
-#define MMC_MMC_PROTOCOL_H
-
-/* Standard MMC commands (4.1)           type  argument     response */
-   /* class 1 */
-#define	MMC_GO_IDLE_STATE         0   /* bc                          */
-#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
-#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
-#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
-#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
-#define MMC_SWITCH                6   /* ac   [31:0] See below   R1b */
-#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
-#define MMC_SEND_EXT_CSD          8   /* adtc                    R1  */
-#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
-#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
-#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
-#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
-#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
-#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
-
-  /* class 2 */
-#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
-#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
-#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
-
-  /* class 3 */
-#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
-
-  /* class 4 */
-#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
-#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
-#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
-#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
-#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
-
-  /* class 6 */
-#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
-#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
-#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
-
-  /* class 5 */
-#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
-#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
-#define MMC_ERASE                38   /* ac                      R1b */
-
-  /* class 9 */
-#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
-#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
-
-  /* class 7 */
-#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
-
-  /* class 8 */
-#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
-#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
-
-/* SD commands                           type  argument     response */
-  /* class 0 */
-/* This is basically the same command as for MMC with some quirks. */
-#define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
-#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
-
-  /* class 10 */
-#define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
-
-  /* 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  */
-
-/*
- * MMC_SWITCH argument format:
- *
- *	[31:26] Always 0
- *	[25:24] Access Mode
- *	[23:16] Location of target Byte in EXT_CSD
- *	[15:08] Value Byte
- *	[07:03] Always 0
- *	[02:00] Command Set
- */
-
-/*
- * SD_SWITCH argument format:
- *
- *      [31] Check (0) or switch (1)
- *      [30:24] Reserved (0)
- *      [23:20] Function group 6
- *      [19:16] Function group 5
- *      [15:12] Function group 4
- *      [11:8] Function group 3
- *      [7:4] Function group 2
- *      [3:0] Function group 1
- */
-
-/*
- * SD_SEND_IF_COND argument format:
- *
- *	[31:12] Reserved (0)
- *	[11:8] Host Voltage Supply Flags
- *	[7:0] Check Pattern (0xAA)
- */
-
-/*
-  MMC status in R1
-  Type
-  	e : error bit
-	s : status bit
-	r : detected and set for the actual command response
-	x : detected and set during command execution. the host must poll
-            the card by sending status command in order to read these bits.
-  Clear condition
-  	a : according to the card state
-	b : always related to the previous command. Reception of
-            a valid command will clear it (with a delay of one command)
-	c : clear by read
- */
-
-#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
-#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
-#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
-#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
-#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
-#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
-#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
-#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
-#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
-#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
-#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
-#define R1_CC_ERROR		(1 << 20)	/* erx, c */
-#define R1_ERROR		(1 << 19)	/* erx, c */
-#define R1_UNDERRUN		(1 << 18)	/* ex, c */
-#define R1_OVERRUN		(1 << 17)	/* ex, c */
-#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
-#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
-#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
-#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
-#define R1_STATUS(x)            (x & 0xFFFFE000)
-#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
-#define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
-#define R1_APP_CMD		(1 << 5)	/* sr, c */
-
-/* These are unpacked versions of the actual responses */
-
-struct _mmc_csd {
-	u8  csd_structure;
-	u8  spec_vers;
-	u8  taac;
-	u8  nsac;
-	u8  tran_speed;
-	u16 ccc;
-	u8  read_bl_len;
-	u8  read_bl_partial;
-	u8  write_blk_misalign;
-	u8  read_blk_misalign;
-	u8  dsr_imp;
-	u16 c_size;
-	u8  vdd_r_curr_min;
-	u8  vdd_r_curr_max;
-	u8  vdd_w_curr_min;
-	u8  vdd_w_curr_max;
-	u8  c_size_mult;
-	union {
-		struct { /* MMC system specification version 3.1 */
-			u8  erase_grp_size;
-			u8  erase_grp_mult;
-		} v31;
-		struct { /* MMC system specification version 2.2 */
-			u8  sector_size;
-			u8  erase_grp_size;
-		} v22;
-	} erase;
-	u8  wp_grp_size;
-	u8  wp_grp_enable;
-	u8  default_ecc;
-	u8  r2w_factor;
-	u8  write_bl_len;
-	u8  write_bl_partial;
-	u8  file_format_grp;
-	u8  copy;
-	u8  perm_write_protect;
-	u8  tmp_write_protect;
-	u8  file_format;
-	u8  ecc;
-};
-
-#define MMC_VDD_145_150	0x00000001	/* VDD voltage 1.45 - 1.50 */
-#define MMC_VDD_150_155	0x00000002	/* VDD voltage 1.50 - 1.55 */
-#define MMC_VDD_155_160	0x00000004	/* VDD voltage 1.55 - 1.60 */
-#define MMC_VDD_160_165	0x00000008	/* VDD voltage 1.60 - 1.65 */
-#define MMC_VDD_165_170	0x00000010	/* VDD voltage 1.65 - 1.70 */
-#define MMC_VDD_17_18	0x00000020	/* VDD voltage 1.7 - 1.8 */
-#define MMC_VDD_18_19	0x00000040	/* VDD voltage 1.8 - 1.9 */
-#define MMC_VDD_19_20	0x00000080	/* VDD voltage 1.9 - 2.0 */
-#define MMC_VDD_20_21	0x00000100	/* VDD voltage 2.0 ~ 2.1 */
-#define MMC_VDD_21_22	0x00000200	/* VDD voltage 2.1 ~ 2.2 */
-#define MMC_VDD_22_23	0x00000400	/* VDD voltage 2.2 ~ 2.3 */
-#define MMC_VDD_23_24	0x00000800	/* VDD voltage 2.3 ~ 2.4 */
-#define MMC_VDD_24_25	0x00001000	/* VDD voltage 2.4 ~ 2.5 */
-#define MMC_VDD_25_26	0x00002000	/* VDD voltage 2.5 ~ 2.6 */
-#define MMC_VDD_26_27	0x00004000	/* VDD voltage 2.6 ~ 2.7 */
-#define MMC_VDD_27_28	0x00008000	/* VDD voltage 2.7 ~ 2.8 */
-#define MMC_VDD_28_29	0x00010000	/* VDD voltage 2.8 ~ 2.9 */
-#define MMC_VDD_29_30	0x00020000	/* VDD voltage 2.9 ~ 3.0 */
-#define MMC_VDD_30_31	0x00040000	/* VDD voltage 3.0 ~ 3.1 */
-#define MMC_VDD_31_32	0x00080000	/* VDD voltage 3.1 ~ 3.2 */
-#define MMC_VDD_32_33	0x00100000	/* VDD voltage 3.2 ~ 3.3 */
-#define MMC_VDD_33_34	0x00200000	/* VDD voltage 3.3 ~ 3.4 */
-#define MMC_VDD_34_35	0x00400000	/* VDD voltage 3.4 ~ 3.5 */
-#define MMC_VDD_35_36	0x00800000	/* VDD voltage 3.5 ~ 3.6 */
-#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
-
-/*
- * Card Command Classes (CCC)
- */
-#define CCC_BASIC		(1<<0)	/* (0) Basic protocol functions */
-					/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
-#define CCC_STREAM_READ		(1<<1)	/* (1) Stream read commands */
-					/* (CMD11) */
-#define CCC_BLOCK_READ		(1<<2)	/* (2) Block read commands */
-					/* (CMD16,17,18) */
-#define CCC_STREAM_WRITE	(1<<3)	/* (3) Stream write commands */
-					/* (CMD20) */
-#define CCC_BLOCK_WRITE		(1<<4)	/* (4) Block write commands */
-					/* (CMD16,24,25,26,27) */
-#define CCC_ERASE		(1<<5)	/* (5) Ability to erase blocks */
-					/* (CMD32,33,34,35,36,37,38,39) */
-#define CCC_WRITE_PROT		(1<<6)	/* (6) Able to write protect blocks */
-					/* (CMD28,29,30) */
-#define CCC_LOCK_CARD		(1<<7)	/* (7) Able to lock down card */
-					/* (CMD16,CMD42) */
-#define CCC_APP_SPEC		(1<<8)	/* (8) Application specific */
-					/* (CMD55,56,57,ACMD*) */
-#define CCC_IO_MODE		(1<<9)	/* (9) I/O mode */
-					/* (CMD5,39,40,52,53) */
-#define CCC_SWITCH		(1<<10)	/* (10) High speed switch */
-					/* (CMD6,34,35,36,37,50) */
-					/* (11) Reserved */
-					/* (CMD?) */
-
-/*
- * CSD field definitions
- */
-
-#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
-#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
-#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
-#define CSD_STRUCT_EXT_CSD  3           /* Version is coded in CSD_STRUCTURE in EXT_CSD */
-
-#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
-#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
-#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
-#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 - 3.2 - 3.31 */
-#define CSD_SPEC_VER_4      4           /* Implements system specification 4.0 - 4.1 */
-
-/*
- * EXT_CSD fields
- */
-
-#define EXT_CSD_BUS_WIDTH	183	/* R/W */
-#define EXT_CSD_HS_TIMING	185	/* R/W */
-#define EXT_CSD_CARD_TYPE	196	/* RO */
-
-/*
- * EXT_CSD field definitions
- */
-
-#define EXT_CSD_CMD_SET_NORMAL		(1<<0)
-#define EXT_CSD_CMD_SET_SECURE		(1<<1)
-#define EXT_CSD_CMD_SET_CPSECURE	(1<<2)
-
-#define EXT_CSD_CARD_TYPE_26	(1<<0)	/* Card can run at 26MHz */
-#define EXT_CSD_CARD_TYPE_52	(1<<1)	/* Card can run at 52MHz */
-
-#define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
-#define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
-#define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
-
-/*
- * MMC_SWITCH access modes
- */
-
-#define MMC_SWITCH_MODE_CMD_SET		0x00	/* Change the command set */
-#define MMC_SWITCH_MODE_SET_BITS	0x01	/* Set bits which are 1 in value */
-#define MMC_SWITCH_MODE_CLEAR_BITS	0x02	/* Clear bits which are 1 in value */
-#define MMC_SWITCH_MODE_WRITE_BYTE	0x03	/* Set target to value */
-
-/*
- * SCR field definitions
- */
-
-#define SCR_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.01 */
-#define SCR_SPEC_VER_1      1           /* Implements system specification 1.10 */
-#define SCR_SPEC_VER_2      2           /* Implements system specification 2.00 */
-
-/*
- * SD bus widths
- */
-#define SD_BUS_WIDTH_1      0
-#define SD_BUS_WIDTH_4      2
-
-#endif  /* MMC_MMC_PROTOCOL_H */
-
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
new file mode 100644
index 0000000..f310062
--- /dev/null
+++ b/include/linux/mmc/sd.h
@@ -0,0 +1,83 @@
+/*
+ *  include/linux/mmc/sd.h
+ *
+ *  Copyright (C) 2005-2007 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef MMC_SD_H
+#define MMC_SD_H
+
+/* SD commands                           type  argument     response */
+  /* class 0 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
+#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+
+  /* class 10 */
+#define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
+
+  /* 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  */
+
+/*
+ * SD_SWITCH argument format:
+ *
+ *      [31] Check (0) or switch (1)
+ *      [30:24] Reserved (0)
+ *      [23:20] Function group 6
+ *      [19:16] Function group 5
+ *      [15:12] Function group 4
+ *      [11:8] Function group 3
+ *      [7:4] Function group 2
+ *      [3:0] Function group 1
+ */
+
+/*
+ * SD_SEND_IF_COND argument format:
+ *
+ *	[31:12] Reserved (0)
+ *	[11:8] Host Voltage Supply Flags
+ *	[7:0] Check Pattern (0xAA)
+ */
+
+/*
+ * SCR field definitions
+ */
+
+#define SCR_SPEC_VER_0		0	/* Implements system specification 1.0 - 1.01 */
+#define SCR_SPEC_VER_1		1	/* Implements system specification 1.10 */
+#define SCR_SPEC_VER_2		2	/* Implements system specification 2.00 */
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1		0
+#define SD_BUS_WIDTH_4		2
+
+/*
+ * SD_SWITCH mode
+ */
+#define SD_SWITCH_CHECK		0
+#define SD_SWITCH_SET		1
+
+/*
+ * SD_SWITCH function groups
+ */
+#define SD_SWITCH_GRP_ACCESS	0
+
+/*
+ * SD_SWITCH access modes
+ */
+#define SD_SWITCH_ACCESS_DEF	0
+#define SD_SWITCH_ACCESS_HS	1
+
+#endif
+
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ee9e314..2f1544e 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -784,6 +784,18 @@ #endif
 void memory_present(int nid, unsigned long start, unsigned long end);
 unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
 
+/*
+ * If it is possible to have holes within a MAX_ORDER_NR_PAGES, then we
+ * need to check pfn validility within that MAX_ORDER_NR_PAGES block.
+ * pfn_valid_within() should be used in this case; we optimise this away
+ * when we have no holes within a MAX_ORDER_NR_PAGES block.
+ */
+#ifdef CONFIG_HOLES_IN_ZONE
+#define pfn_valid_within(pfn) pfn_valid(pfn)
+#else
+#define pfn_valid_within(pfn) (1)
+#endif
+
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MMZONE_H */
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 4af0b1f..1fa4d98 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -14,10 +14,9 @@ struct mnt_namespace {
 	int event;
 };
 
-extern int copy_mnt_ns(int, struct task_struct *);
-extern void __put_mnt_ns(struct mnt_namespace *ns);
-extern struct mnt_namespace *dup_mnt_ns(struct task_struct *,
+extern struct mnt_namespace *copy_mnt_ns(int, struct mnt_namespace *,
 		struct fs_struct *);
+extern void __put_mnt_ns(struct mnt_namespace *ns);
 
 static inline void put_mnt_ns(struct mnt_namespace *ns)
 {
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index e96b2de..af04a55 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -262,6 +262,7 @@ struct i2c_device_id {
 
 /* Input */
 #define INPUT_DEVICE_ID_EV_MAX		0x1f
+#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING	0x71
 #define INPUT_DEVICE_ID_KEY_MAX		0x1ff
 #define INPUT_DEVICE_ID_REL_MAX		0x0f
 #define INPUT_DEVICE_ID_ABS_MAX		0x3f
diff --git a/include/linux/module.h b/include/linux/module.h
index 95679eb..6d3dc9c 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -370,16 +370,14 @@ struct module *module_text_address(unsig
 struct module *__module_text_address(unsigned long addr);
 int is_module_address(unsigned long addr);
 
-/* Returns module and fills in value, defined and namebuf, or NULL if
+/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
    symnum out of range. */
-struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
-				char *type, char *name, size_t namelen);
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+			char *name, char *module_name, int *exported);
 
 /* Look for this name: can be of form module:name. */
 unsigned long module_kallsyms_lookup_name(const char *name);
 
-int is_exported(const char *name, const struct module *mod);
-
 extern void __module_put_and_exit(struct module *mod, long code)
 	__attribute__((noreturn));
 #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code);
@@ -456,6 +454,8 @@ const char *module_address_lookup(unsign
 				  unsigned long *symbolsize,
 				  unsigned long *offset,
 				  char **modname);
+int lookup_module_symbol_name(unsigned long addr, char *symname);
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
 
 /* For extable.c to search modules' exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr);
@@ -527,20 +527,24 @@ static inline const char *module_address
 	return NULL;
 }
 
-static inline struct module *module_get_kallsym(unsigned int symnum,
-						unsigned long *value,
-						char *type, char *name,
-						size_t namelen)
+static inline int lookup_module_symbol_name(unsigned long addr, char *symname)
 {
-	return NULL;
+	return -ERANGE;
 }
 
-static inline unsigned long module_kallsyms_lookup_name(const char *name)
+static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name)
 {
-	return 0;
+	return -ERANGE;
 }
 
-static inline int is_exported(const char *name, const struct module *mod)
+static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
+					char *type, char *name,
+					char *module_name, int *exported)
+{
+	return -ERANGE;
+}
+
+static inline unsigned long module_kallsyms_lookup_name(const char *name)
 {
 	return 0;
 }
@@ -568,7 +572,7 @@ struct device_driver;
 #ifdef CONFIG_SYSFS
 struct module;
 
-extern struct subsystem module_subsys;
+extern struct kset module_subsys;
 
 int mod_sysfs_init(struct module *mod);
 int mod_sysfs_setup(struct module *mod,
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index fa253fa..0e09c00 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -205,7 +205,8 @@ struct fat_mount_options {
 		 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*/
+		 nocase:1,	  /* Does this need case conversion? 0=need case conversion*/
+		 usefree:1;	  /* Use free_clusters for FAT32 */
 };
 
 #define FAT_HASH_BITS	8
diff --git a/include/linux/msi.h b/include/linux/msi.h
index e38fe68..94bb46d 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -1,6 +1,8 @@
 #ifndef LINUX_MSI_H
 #define LINUX_MSI_H
 
+#include <linux/list.h>
+
 struct msi_msg {
 	u32	address_lo;	/* low 32 bits of msi message address */
 	u32	address_hi;	/* high 32 bits of msi message address */
@@ -24,10 +26,8 @@ struct msi_desc {
 		unsigned default_irq;	/* default pre-assigned irq	  */
 	}msi_attrib;
 
-	struct {
-		__u16	head;
-		__u16	tail;
-	}link;
+	unsigned int irq;
+	struct list_head list;
 
 	void __iomem *mask_base;
 	struct pci_dev *dev;
@@ -41,6 +41,9 @@ struct msi_desc {
  */
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);
+extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+extern void arch_teardown_msi_irqs(struct pci_dev *dev);
+extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
 
 
 #endif /* LINUX_MSI_H */
diff --git a/include/linux/mtd/iflash.h b/include/linux/mtd/iflash.h
deleted file mode 100644
index 9aa5b4f..0000000
--- a/include/linux/mtd/iflash.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* $Id: iflash.h,v 1.2 2000/11/13 18:01:54 dwmw2 Exp $ */
-
-#ifndef __MTD_IFLASH_H__
-#define __MTD_IFLASH_H__
-
-/* Extended CIS registers for Series 2 and 2+ cards */
-/* The registers are all offsets from 0x4000 */
-#define CISREG_CSR		0x0100
-#define CISREG_WP		0x0104
-#define CISREG_RDYBSY		0x0140
-
-/* Extended CIS registers for Series 2 cards */
-#define CISREG_SLEEP		0x0118
-#define CISREG_RDY_MASK		0x0120
-#define CISREG_RDY_STATUS	0x0130
-
-/* Extended CIS registers for Series 2+ cards */
-#define CISREG_VCR		0x010c
-
-/* Card Status Register */
-#define CSR_SRESET		0x20	/* Soft reset */
-#define CSR_CMWP		0x10	/* Common memory write protect */
-#define CSR_PWRDOWN		0x08	/* Power down status */
-#define CSR_CISWP		0x04	/* Common memory CIS WP */
-#define CSR_WP			0x02	/* Mechanical write protect */
-#define CSR_READY		0x01	/* Ready/busy status */
-
-/* Write Protection Register */
-#define WP_BLKEN		0x04	/* Enable block locking */
-#define WP_CMWP			0x02	/* Common memory write protect */
-#define WP_CISWP		0x01	/* Common memory CIS WP */
-
-/* Voltage Control Register */
-#define VCR_VCC_LEVEL		0x80	/* 0 = 5V, 1 = 3.3V */
-#define VCR_VPP_VALID		0x02	/* Vpp Valid */
-#define VCR_VPP_GEN		0x01	/* Integrated Vpp generator */
-
-/* Ready/Busy Mode Register */
-#define RDYBSY_RACK		0x02	/* Ready acknowledge */
-#define RDYBSY_MODE		0x01	/* 1 = high performance */
-
-#define LOW(x) ((x) & 0xff)
-
-/* 28F008SA-Compatible Command Set */
-#define IF_READ_ARRAY		0xffff
-#define IF_INTEL_ID		0x9090
-#define IF_READ_CSR		0x7070
-#define IF_CLEAR_CSR		0x5050
-#define IF_WRITE		0x4040
-#define IF_BLOCK_ERASE		0x2020
-#define IF_ERASE_SUSPEND	0xb0b0
-#define IF_CONFIRM		0xd0d0
-
-/* 28F016SA Performance Enhancement Commands */
-#define IF_READ_PAGE		0x7575
-#define IF_PAGE_SWAP		0x7272
-#define IF_SINGLE_LOAD		0x7474
-#define IF_SEQ_LOAD		0xe0e0
-#define IF_PAGE_WRITE		0x0c0c
-#define IF_RDY_MODE		0x9696
-#define IF_RDY_LEVEL		0x0101
-#define IF_RDY_PULSE_WRITE	0x0202
-#define IF_RDY_PULSE_ERASE	0x0303
-#define IF_RDY_DISABLE		0x0404
-#define IF_LOCK_BLOCK		0x7777
-#define IF_UPLOAD_STATUS	0x9797
-#define IF_READ_ESR		0x7171
-#define IF_ERASE_UNLOCKED	0xa7a7
-#define IF_SLEEP		0xf0f0
-#define IF_ABORT		0x8080
-#define IF_UPLOAD_DEVINFO	0x9999
-
-/* Definitions for Compatible Status Register */
-#define CSR_WR_READY		0x8080	/* Write state machine status */
-#define CSR_ERA_SUSPEND		0x4040	/* Erase suspend status */
-#define CSR_ERA_ERR		0x2020	/* Erase status */
-#define CSR_WR_ERR		0x1010	/* Data write status */
-#define CSR_VPP_LOW		0x0808	/* Vpp status */
-
-/* Definitions for Global Status Register */
-#define GSR_WR_READY		0x8080	/* Write state machine status */
-#define GSR_OP_SUSPEND		0x4040	/* Operation suspend status */
-#define GSR_OP_ERR		0x2020	/* Device operation status */
-#define GSR_SLEEP		0x1010	/* Device sleep status */
-#define GSR_QUEUE_FULL		0x0808	/* Queue status */
-#define GSR_PAGE_AVAIL		0x0404	/* Page buffer available status */
-#define GSR_PAGE_READY		0x0202	/* Page buffer status */
-#define GSR_PAGE_SELECT		0x0101	/* Page buffer select status */
-
-/* Definitions for Block Status Register */
-#define BSR_READY		0x8080	/* Block status */
-#define BSR_UNLOCK		0x4040	/* Block lock status */
-#define BSR_FAILED		0x2020	/* Block operation status */
-#define BSR_ABORTED		0x1010	/* Operation abort status */
-#define BSR_QUEUE_FULL		0x0808	/* Queue status */
-#define BSR_VPP_LOW		0x0404	/* Vpp status */
-
-#endif /* __MTD_IFLASH_H__ */
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 3d956c3..45d482c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -53,6 +53,7 @@ struct mtd_erase_region_info {
 	u_int32_t offset;			/* At which this region starts, from the beginning of the MTD */
 	u_int32_t erasesize;		/* For this region */
 	u_int32_t numblocks;		/* Number of blocks of erasesize in this region */
+	unsigned long *lockmap;		/* If keeping bitmap of locks */
 };
 
 /*
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 9752388..cf197ad 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -431,6 +431,7 @@ #define NAND_MFR_NATIONAL	0x8f
 #define NAND_MFR_RENESAS	0x07
 #define NAND_MFR_STMICRO	0x20
 #define NAND_MFR_HYNIX		0xad
+#define NAND_MFR_MICRON		0x2c
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
new file mode 100644
index 0000000..3d967b6
--- /dev/null
+++ b/include/linux/mtd/ubi.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+#ifndef __LINUX_UBI_H__
+#define __LINUX_UBI_H__
+
+#include <asm/ioctl.h>
+#include <linux/types.h>
+#include <mtd/ubi-user.h>
+
+/*
+ * UBI data type hint constants.
+ *
+ * UBI_LONGTERM: long-term data
+ * UBI_SHORTTERM: short-term data
+ * UBI_UNKNOWN: data persistence is unknown
+ *
+ * These constants are used when data is written to UBI volumes in order to
+ * help the UBI wear-leveling unit to find more appropriate physical
+ * eraseblocks.
+ */
+enum {
+	UBI_LONGTERM = 1,
+	UBI_SHORTTERM,
+	UBI_UNKNOWN
+};
+
+/*
+ * enum ubi_open_mode - UBI volume open mode constants.
+ *
+ * UBI_READONLY: read-only mode
+ * UBI_READWRITE: read-write mode
+ * UBI_EXCLUSIVE: exclusive mode
+ */
+enum {
+	UBI_READONLY = 1,
+	UBI_READWRITE,
+	UBI_EXCLUSIVE
+};
+
+/**
+ * struct ubi_volume_info - UBI volume description data structure.
+ * @vol_id: volume ID
+ * @ubi_num: UBI device number this volume belongs to
+ * @size: how many physical eraseblocks are reserved for this volume
+ * @used_bytes: how many bytes of data this volume contains
+ * @used_ebs: how many physical eraseblocks of this volume actually contain any
+ * data
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @corrupted: non-zero if the volume is corrupted (static volumes only)
+ * @upd_marker: non-zero if the volume has update marker set
+ * @alignment: volume alignment
+ * @usable_leb_size: how many bytes are available in logical eraseblocks of
+ * this volume
+ * @name_len: volume name length
+ * @name: volume name
+ * @cdev: UBI volume character device major and minor numbers
+ *
+ * The @corrupted flag is only relevant to static volumes and is always zero
+ * for dynamic ones. This is because UBI does not care about dynamic volume
+ * data protection and only cares about protecting static volume data.
+ *
+ * The @upd_marker flag is set if the volume update operation was interrupted.
+ * Before touching the volume data during the update operation, UBI first sets
+ * the update marker flag for this volume. If the volume update operation was
+ * further interrupted, the update marker indicates this. If the update marker
+ * is set, the contents of the volume is certainly damaged and a new volume
+ * update operation has to be started.
+ *
+ * To put it differently, @corrupted and @upd_marker fields have different
+ * semantics:
+ *     o the @corrupted flag means that this static volume is corrupted for some
+ *       reasons, but not because an interrupted volume update
+ *     o the @upd_marker field means that the volume is damaged because of an
+ *       interrupted update operation.
+ *
+ * I.e., the @corrupted flag is never set if the @upd_marker flag is set.
+ *
+ * The @used_bytes and @used_ebs fields are only really needed for static
+ * volumes and contain the number of bytes stored in this static volume and how
+ * many eraseblock this data occupies. In case of dynamic volumes, the
+ * @used_bytes field is equivalent to @size*@usable_leb_size, and the @used_ebs
+ * field is equivalent to @size.
+ *
+ * In general, logical eraseblock size is a property of the UBI device, not
+ * of the UBI volume. Indeed, the logical eraseblock size depends on the
+ * physical eraseblock size and on how much bytes UBI headers consume. But
+ * because of the volume alignment (@alignment), the usable size of logical
+ * eraseblocks if a volume may be less. The following equation is true:
+ * 	@usable_leb_size = LEB size - (LEB size mod @alignment),
+ * where LEB size is the logical eraseblock size defined by the UBI device.
+ *
+ * The alignment is multiple to the minimal flash input/output unit size or %1
+ * if all the available space is used.
+ *
+ * To put this differently, alignment may be considered is a way to change
+ * volume logical eraseblock sizes.
+ */
+struct ubi_volume_info {
+	int ubi_num;
+	int vol_id;
+	int size;
+	long long used_bytes;
+	int used_ebs;
+	int vol_type;
+	int corrupted;
+	int upd_marker;
+	int alignment;
+	int usable_leb_size;
+	int name_len;
+	const char *name;
+	dev_t cdev;
+};
+
+/**
+ * struct ubi_device_info - UBI device description data structure.
+ * @ubi_num: ubi device number
+ * @leb_size: logical eraseblock size on this UBI device
+ * @min_io_size: minimal I/O unit size
+ * @ro_mode: if this device is in read-only mode
+ * @cdev: UBI character device major and minor numbers
+ *
+ * Note, @leb_size is the logical eraseblock size offered by the UBI device.
+ * Volumes of this UBI device may have smaller logical eraseblock size if their
+ * alignment is not equivalent to %1.
+ */
+struct ubi_device_info {
+	int ubi_num;
+	int leb_size;
+	int min_io_size;
+	int ro_mode;
+	dev_t cdev;
+};
+
+/* UBI descriptor given to users when they open UBI volumes */
+struct ubi_volume_desc;
+
+int ubi_get_device_info(int ubi_num, struct ubi_device_info *di);
+void ubi_get_volume_info(struct ubi_volume_desc *desc,
+			 struct ubi_volume_info *vi);
+struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode);
+struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
+					   int mode);
+void ubi_close_volume(struct ubi_volume_desc *desc);
+int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+		 int len, int check);
+int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+		  int offset, int len, int dtype);
+int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+		   int len, int dtype);
+int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
+int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
+int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
+
+/*
+ * This function is the same as the 'ubi_leb_read()' function, but it does not
+ * provide the checking capability.
+ */
+static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf,
+			   int offset, int len)
+{
+	return ubi_leb_read(desc, lnum, buf, offset, len, 0);
+}
+
+/*
+ * This function is the same as the 'ubi_leb_write()' functions, but it does
+ * not have the data type argument.
+ */
+static inline int ubi_write(struct ubi_volume_desc *desc, int lnum,
+			    const void *buf, int offset, int len)
+{
+	return ubi_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
+}
+
+/*
+ * This function is the same as the 'ubi_leb_change()' functions, but it does
+ * not have the data type argument.
+ */
+static inline int ubi_change(struct ubi_volume_desc *desc, int lnum,
+				    const void *buf, int len)
+{
+	return ubi_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
+}
+
+#endif /* !__LINUX_UBI_H__ */
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d39a5a6..b7dd249 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(st
 extern void release_open_intent(struct nameidata *);
 
 extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry *lookup_one_len_kern(const char *, struct dentry *, int);
 
 extern int follow_down(struct vfsmount **, struct dentry **);
 extern int follow_up(struct vfsmount **, struct dentry **);
diff --git a/include/linux/net.h b/include/linux/net.h
index 4db21e6..efc4517 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -24,7 +24,7 @@ #include <asm/socket.h>
 struct poll_table_struct;
 struct inode;
 
-#define NPROTO		33		/* should be enough for now..	*/
+#define NPROTO		34		/* should be enough for now..	*/
 
 #define SYS_SOCKET	1		/* sys_socket(2)		*/
 #define SYS_BIND	2		/* sys_bind(2)			*/
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1a52854..3044622 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -42,6 +42,8 @@ #include <linux/dmaengine.h>
 struct vlan_group;
 struct ethtool_ops;
 struct netpoll_info;
+/* 802.11 specific */
+struct wireless_dev;
 					/* source back-compat hooks */
 #define SET_ETHTOOL_OPS(netdev,ops) \
 	( (netdev)->ethtool_ops = (ops) )
@@ -302,7 +304,7 @@ struct net_device
 
 	unsigned long		state;
 
-	struct net_device	*next;
+	struct list_head	dev_list;
 	
 	/* The device initialization function. Called only once. */
 	int			(*init)(struct net_device *dev);
@@ -347,13 +349,15 @@ #define NETIF_F_ALL_CSUM	(NETIF_F_IP_CSU
 
 
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
+	struct net_device_stats	stats;
 
+#ifdef CONFIG_WIRELESS_EXT
 	/* List of functions to handle Wireless Extensions (instead of ioctl).
 	 * See <net/iw_handler.h> for details. Jean II */
 	const struct iw_handler_def *	wireless_handlers;
 	/* Instance data managed by the core of Wireless Extensions. */
 	struct iw_public_data *	wireless_data;
-
+#endif
 	const struct ethtool_ops *ethtool_ops;
 
 	/*
@@ -398,6 +402,8 @@ #define NETIF_F_ALL_CSUM	(NETIF_F_IP_CSU
 	void                    *ip6_ptr;       /* IPv6 specific data */
 	void			*ec_ptr;	/* Econet specific data	*/
 	void			*ax25_ptr;	/* AX.25 specific data */
+	struct wireless_dev	*ieee80211_ptr;	/* IEEE 802.11 specific data,
+						   assign before registering */
 
 /*
  * Cache line mostly used on receive path (including eth_type_trans())
@@ -569,13 +575,36 @@ #include <linux/interrupt.h>
 #include <linux/notifier.h>
 
 extern struct net_device		loopback_dev;		/* The loopback */
-extern struct net_device		*dev_base;		/* All devices */
+extern struct list_head			dev_base_head;		/* All devices */
 extern rwlock_t				dev_base_lock;		/* Device list lock */
 
+#define for_each_netdev(d)		\
+		list_for_each_entry(d, &dev_base_head, dev_list)
+#define for_each_netdev_safe(d, n)	\
+		list_for_each_entry_safe(d, n, &dev_base_head, dev_list)
+#define for_each_netdev_continue(d)		\
+		list_for_each_entry_continue(d, &dev_base_head, dev_list)
+#define net_device_entry(lh)	list_entry(lh, struct net_device, dev_list)
+
+static inline struct net_device *next_net_device(struct net_device *dev)
+{
+	struct list_head *lh;
+
+	lh = dev->dev_list.next;
+	return lh == &dev_base_head ? NULL : net_device_entry(lh);
+}
+
+static inline struct net_device *first_net_device(void)
+{
+	return list_empty(&dev_base_head) ? NULL :
+		net_device_entry(dev_base_head.next);
+}
+
 extern int 			netdev_boot_setup_check(struct net_device *dev);
 extern unsigned long		netdev_boot_base(const char *prefix, int unit);
 extern struct net_device    *dev_getbyhwaddr(unsigned short type, char *hwaddr);
 extern struct net_device *dev_getfirstbyhwtype(unsigned short type);
+extern struct net_device *__dev_getfirstbyhwtype(unsigned short type);
 extern void		dev_add_pack(struct packet_type *pt);
 extern void		dev_remove_pack(struct packet_type *pt);
 extern void		__dev_remove_pack(struct packet_type *pt);
@@ -647,8 +676,10 @@ static inline void netif_start_queue(str
 static inline void netif_wake_queue(struct net_device *dev)
 {
 #ifdef CONFIG_NETPOLL_TRAP
-	if (netpoll_trap())
+	if (netpoll_trap()) {
+		clear_bit(__LINK_STATE_XOFF, &dev->state);
 		return;
+	}
 #endif
 	if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
 		__netif_schedule(dev);
@@ -656,10 +687,6 @@ #endif
 
 static inline void netif_stop_queue(struct net_device *dev)
 {
-#ifdef CONFIG_NETPOLL_TRAP
-	if (netpoll_trap())
-		return;
-#endif
 	set_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 70d3b4f..10b5c62 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -281,9 +281,6 @@ extern void nf_reinject(struct sk_buff *
 			struct nf_info *info,
 			unsigned int verdict);
 
-extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
-extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
-
 /* FIXME: Before cache is ever used, this must be implemented for real. */
 extern void nf_invalidate_cache(int pf);
 
@@ -388,11 +385,18 @@ static inline int nf_hook(int pf, unsign
 {
 	return 1;
 }
-static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 struct flowi;
 static inline void
 nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) {}
 #endif /*CONFIG_NETFILTER*/
 
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
+extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
+extern void (*nf_ct_destroy)(struct nf_conntrack *);
+#else
+static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
+#endif
+
 #endif /*__KERNEL__*/
 #endif /*__LINUX_NETFILTER_H*/
diff --git a/include/linux/netfilter/nf_conntrack_proto_gre.h b/include/linux/netfilter/nf_conntrack_proto_gre.h
index 4e6bbce..535e421 100644
--- a/include/linux/netfilter/nf_conntrack_proto_gre.h
+++ b/include/linux/netfilter/nf_conntrack_proto_gre.h
@@ -87,24 +87,6 @@ int nf_ct_gre_keymap_add(struct nf_conn 
 /* delete keymap entries */
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct);
 
-/* get pointer to gre key, if present */
-static inline __be32 *gre_key(struct gre_hdr *greh)
-{
-	if (!greh->key)
-		return NULL;
-	if (greh->csum || greh->routing)
-		return (__be32 *)(greh+sizeof(*greh)+4);
-	return (__be32 *)(greh+sizeof(*greh));
-}
-
-/* get pointer ot gre csum, if present */
-static inline __sum16 *gre_csum(struct gre_hdr *greh)
-{
-	if (!greh->csum)
-		return NULL;
-	return (__sum16 *)(greh+sizeof(*greh));
-}
-
 extern void nf_ct_gre_keymap_flush(void);
 extern void nf_nat_need_gre(void);
 
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h
index 007af4c..22ce299 100644
--- a/include/linux/netfilter/nf_conntrack_tcp.h
+++ b/include/linux/netfilter/nf_conntrack_tcp.h
@@ -30,6 +30,11 @@ #define IP_CT_TCP_FLAG_CLOSE_INIT		0x04
 /* Be liberal in window checking */
 #define IP_CT_TCP_FLAG_BE_LIBERAL		0x08
 
+struct nf_ct_tcp_flags {
+	u_int8_t flags;
+	u_int8_t mask;
+};
+
 #ifdef __KERNEL__
 
 struct ip_ct_tcp_state {
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 1e9c821..0f9311d 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -62,11 +62,11 @@ #define NFA_SPACE(len)	NFA_ALIGN(NFA_LEN
 #define NFA_DATA(nfa)   ((void *)(((char *)(nfa)) + NFA_LENGTH(0)))
 #define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
 #define NFA_NEST(skb, type) \
-({	struct nfattr *__start = (struct nfattr *) (skb)->tail; \
+({	struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \
 	NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \
 	__start;  })
 #define NFA_NEST_END(skb, start) \
-({      (start)->nfa_len = ((skb)->tail - (unsigned char *) (start)); \
+({      (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \
         (skb)->len; })
 #define NFA_NEST_CANCEL(skb, start) \
 ({      if (start) \
@@ -111,7 +111,7 @@ #include <linux/capability.h>
 struct nfnl_callback
 {
 	int (*call)(struct sock *nl, struct sk_buff *skb, 
-		struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
+		struct nlmsghdr *nlh, struct nfattr *cda[]);
 	u_int16_t attr_count;	/* number of nfattr's */
 };
 
@@ -129,19 +129,6 @@ #define NFA_PUT(skb, attrtype, attrlen, 
 ({ if (skb_tailroom(skb) < (int)NFA_SPACE(attrlen)) goto nfattr_failure; \
    __nfa_fill(skb, attrtype, attrlen, data); })
 
-extern struct semaphore nfnl_sem;
-
-#define nfnl_shlock()		down(&nfnl_sem)
-#define nfnl_shlock_nowait()	down_trylock(&nfnl_sem)
-
-#define nfnl_shunlock()		do { up(&nfnl_sem); \
-				     if(nfnl && nfnl->sk_receive_queue.qlen) \
-					    nfnl->sk_data_ready(nfnl, 0); \
-                        	} while(0)
-
-extern void nfnl_lock(void);
-extern void nfnl_unlock(void);
-
 extern int nfnetlink_subsys_register(struct nfnetlink_subsystem *n);
 extern int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n);
 
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index b5883cc..d7c3503 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -83,6 +83,10 @@ #define CTA_PROTOINFO_MAX (__CTA_PROTOIN
 enum ctattr_protoinfo_tcp {
 	CTA_PROTOINFO_TCP_UNSPEC,
 	CTA_PROTOINFO_TCP_STATE,
+	CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+	CTA_PROTOINFO_TCP_WSCALE_REPLY,
+	CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+	CTA_PROTOINFO_TCP_FLAGS_REPLY,
 	__CTA_PROTOINFO_TCP_MAX
 };
 #define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1)
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index 55689f3..533ee35 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -7,6 +7,7 @@ #define __LINUX_BRIDGE_NETFILTER_H
 #include <linux/netfilter.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
 
 /* Bridge Hooks */
 /* After promisc drops, checksum checks. */
@@ -54,12 +55,25 @@ static inline int nf_bridge_maybe_copy_h
   	return 0;
 }
 
+static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
+{
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_8021Q):
+		return VLAN_HLEN;
+	case __constant_htons(ETH_P_PPP_SES):
+		return PPPOE_SES_HLEN;
+	default:
+		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(const struct sk_buff *skb)
+static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
 {
- 	return (skb->nf_bridge && skb->protocol == htons(ETH_P_8021Q))
-		? VLAN_HLEN : 0;
+	if (skb->nf_bridge)
+		return nf_bridge_encap_header_len(skb);
+	return 0;
 }
 
 struct bridge_skb_cb {
diff --git a/include/linux/netfilter_bridge/ebt_802_3.h b/include/linux/netfilter_bridge/ebt_802_3.h
index 07f044f..a11b0c2 100644
--- a/include/linux/netfilter_bridge/ebt_802_3.h
+++ b/include/linux/netfilter_bridge/ebt_802_3.h
@@ -54,7 +54,7 @@ #include <linux/skbuff.h>
 
 static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb)
 {
-	return (struct ebt_802_3_hdr *)skb->mac.raw;
+	return (struct ebt_802_3_hdr *)skb_mac_header(skb);
 }
 #endif
 
diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/linux/netfilter_bridge/ebt_arp.h
index 97e4dbd..cbf4843 100644
--- a/include/linux/netfilter_bridge/ebt_arp.h
+++ b/include/linux/netfilter_bridge/ebt_arp.h
@@ -8,8 +8,10 @@ #define EBT_ARP_SRC_IP 0x08
 #define EBT_ARP_DST_IP 0x10
 #define EBT_ARP_SRC_MAC 0x20
 #define EBT_ARP_DST_MAC 0x40
+#define EBT_ARP_GRAT 0x80
 #define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \
-   EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)
+   EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC | \
+   EBT_ARP_GRAT)
 #define EBT_ARP_MATCH "arp"
 
 struct ebt_arp_info
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild
index 1803378..7185792 100644
--- a/include/linux/netfilter_ipv4/Kbuild
+++ b/include/linux/netfilter_ipv4/Kbuild
@@ -1,9 +1,3 @@
-header-y += ip_conntrack_helper.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
@@ -49,13 +43,5 @@ header-y += ipt_ttl.h
 header-y += ipt_TTL.h
 header-y += ipt_ULOG.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
deleted file mode 100644
index da9274e..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ /dev/null
@@ -1,402 +0,0 @@
-#ifndef _IP_CONNTRACK_H
-#define _IP_CONNTRACK_H
-
-#include <linux/netfilter/nf_conntrack_common.h>
-
-#ifdef __KERNEL__
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <asm/atomic.h>
-
-#include <linux/timer.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>
-
-/* per conntrack: protocol private data */
-union ip_conntrack_proto {
-	/* insert conntrack proto private data here */
-	struct ip_ct_gre gre;
-	struct ip_ct_sctp sctp;
-	struct ip_ct_tcp tcp;
-	struct ip_ct_icmp icmp;
-};
-
-union ip_conntrack_expect_proto {
-	/* insert expect proto private data here */
-};
-
-/* Add protocol helper include file here */
-#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
-
-/* per conntrack: application helper private data */
-union ip_conntrack_help {
-	/* insert conntrack helper private data (master) here */
-	struct ip_ct_h323_master ct_h323_info;
-	struct ip_ct_pptp_master ct_pptp_info;
-	struct ip_ct_ftp_master ct_ftp_info;
-	struct ip_ct_irc_master ct_irc_info;
-};
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_pptp.h>
-
-/* per conntrack: nat application helper private data */
-union ip_conntrack_nat_help {
-	/* insert nat helper private data here */
-	struct ip_nat_pptp nat_pptp_info;
-};
-#endif
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-
-#ifdef CONFIG_NETFILTER_DEBUG
-#define IP_NF_ASSERT(x)							\
-do {									\
-	if (!(x))							\
-		/* Wooah!  I'm tripping my conntrack in a frenzy of	\
-		   netplay... */					\
-		printk("NF_IP_ASSERT: %s:%i(%s)\n",			\
-		       __FILE__, __LINE__, __FUNCTION__);		\
-} while(0)
-#else
-#define IP_NF_ASSERT(x)
-#endif
-
-struct ip_conntrack_helper;
-
-struct ip_conntrack
-{
-	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
-           plus 1 for any connection(s) we are `master' for */
-	struct nf_conntrack ct_general;
-
-	/* Have we seen traffic both ways yet? (bitset) */
-	unsigned long status;
-
-	/* Timer function; drops refcnt when it goes off. */
-	struct timer_list timeout;
-
-#ifdef CONFIG_IP_NF_CT_ACCT
-	/* Accounting Information (same cache line as other written members) */
-	struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
-#endif
-	/* If we were expected by an expectation, this will be it */
-	struct ip_conntrack *master;
-
-	/* Current number of expected connections */
-	unsigned int expecting;
-
-	/* Unique ID that identifies this conntrack*/
-	unsigned int id;
-
-	/* Helper, if any. */
-	struct ip_conntrack_helper *helper;
-
-	/* Storage reserved for other modules: */
-	union ip_conntrack_proto proto;
-
-	union ip_conntrack_help help;
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-	struct {
-		struct ip_nat_info info;
-		union ip_conntrack_nat_help help;
-#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
-	defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
-		int masq_index;
-#endif
-	} nat;
-#endif /* CONFIG_IP_NF_NAT_NEEDED */
-
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-	u_int32_t mark;
-#endif
-
-#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
-	u_int32_t secmark;
-#endif
-
-	/* Traversed often, so hopefully in different cacheline to top */
-	/* These are my tuples; original and reply */
-	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
-};
-
-struct ip_conntrack_expect
-{
-	/* Internal linked list (global expectation list) */
-	struct list_head list;
-
-	/* We expect this tuple, with the following mask */
-	struct ip_conntrack_tuple tuple, mask;
- 
-	/* Function to call after setup and insertion */
-	void (*expectfn)(struct ip_conntrack *new,
-			 struct ip_conntrack_expect *this);
-
-	/* The conntrack of the master connection */
-	struct ip_conntrack *master;
-
-	/* Timer function; deletes the expectation. */
-	struct timer_list timeout;
-
-	/* Usage count. */
-	atomic_t use;
-
-	/* Unique ID */
-	unsigned int id;
-
-	/* Flags */
-	unsigned int flags;
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-	__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;
-	/* Direction relative to the master connection. */
-	enum ip_conntrack_dir dir;
-#endif
-};
-
-#define IP_CT_EXPECT_PERMANENT	0x1
-
-static inline struct ip_conntrack *
-tuplehash_to_ctrack(const struct ip_conntrack_tuple_hash *hash)
-{
-	return container_of(hash, struct ip_conntrack,
-			    tuplehash[hash->tuple.dst.dir]);
-}
-
-/* get master conntrack via master expectation */
-#define master_ct(conntr) (conntr->master)
-
-/* Alter reply tuple (maybe alter helper). */
-extern void
-ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
-			 const struct ip_conntrack_tuple *newreply);
-
-/* Is this tuple taken? (ignoring any belonging to the given
-   conntrack). */
-extern int
-ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
-			 const struct ip_conntrack *ignored_conntrack);
-
-/* Return conntrack_info and tuple hash for given skb. */
-static inline struct ip_conntrack *
-ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
-{
-	*ctinfo = skb->nfctinfo;
-	return (struct ip_conntrack *)skb->nfct;
-}
-
-/* decrement reference count on a conntrack */
-static inline void
-ip_conntrack_put(struct ip_conntrack *ct)
-{
-	IP_NF_ASSERT(ct);
-	nf_conntrack_put(&ct->ct_general);
-}
-
-extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
-			  const struct ip_conntrack_tuple *orig);
-
-extern void __ip_ct_refresh_acct(struct ip_conntrack *ct,
-			         enum ip_conntrack_info ctinfo,
-			         const struct sk_buff *skb,
-			         unsigned long extra_jiffies,
-				 int do_acct);
-
-/* Refresh conntrack for this many jiffies and do accounting */
-static inline void ip_ct_refresh_acct(struct ip_conntrack *ct, 
-				      enum ip_conntrack_info ctinfo,
-				      const struct sk_buff *skb,
-				      unsigned long extra_jiffies)
-{
-	__ip_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1);
-}
-
-/* Refresh conntrack for this many jiffies */
-static inline void ip_ct_refresh(struct ip_conntrack *ct,
-				 const struct sk_buff *skb,
-				 unsigned long extra_jiffies)
-{
-	__ip_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
-}
-
-/* These are for NAT.  Icky. */
-/* Update TCP window tracking data when NAT mangles the packet */
-extern void ip_conntrack_tcp_update(struct sk_buff *skb,
-				    struct ip_conntrack *conntrack,
-				    enum ip_conntrack_dir dir);
-
-/* Call me when a conntrack is destroyed. */
-extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
-
-/* Fake conntrack entry for untracked connections */
-extern struct ip_conntrack ip_conntrack_untracked;
-
-/* Returns new sk_buff, or NULL */
-struct sk_buff *
-ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user);
-
-/* Iterate over all conntracks: if iter returns true, it's deleted. */
-extern void
-ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data),
-		      void *data);
-
-extern struct ip_conntrack_helper *
-__ip_conntrack_helper_find_byname(const char *);
-extern struct ip_conntrack_helper *
-ip_conntrack_helper_find_get(const struct ip_conntrack_tuple *tuple);
-extern void ip_conntrack_helper_put(struct ip_conntrack_helper *helper);
-
-extern struct ip_conntrack_protocol *
-__ip_conntrack_proto_find(u_int8_t protocol);
-extern struct ip_conntrack_protocol *
-ip_conntrack_proto_find_get(u_int8_t protocol);
-extern void ip_conntrack_proto_put(struct ip_conntrack_protocol *proto);
-
-extern void ip_ct_remove_expectations(struct ip_conntrack *ct);
-
-extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *,
-					       struct ip_conntrack_tuple *);
-
-extern void ip_conntrack_free(struct ip_conntrack *ct);
-
-extern void ip_conntrack_hash_insert(struct ip_conntrack *ct);
-
-extern struct ip_conntrack_expect *
-__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);
-
-extern struct ip_conntrack_expect *
-ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
-
-extern struct ip_conntrack_tuple_hash *
-__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
-                    const struct ip_conntrack *ignored_conntrack);
-
-extern void ip_conntrack_flush(void);
-
-/* It's confirmed if it is, or has been in the hash table. */
-static inline int is_confirmed(struct ip_conntrack *ct)
-{
-	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
-}
-
-static inline int is_dying(struct ip_conntrack *ct)
-{
-	return test_bit(IPS_DYING_BIT, &ct->status);
-}
-
-extern unsigned int ip_conntrack_htable_size;
-extern int ip_conntrack_checksum;
- 
-#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
-#define CONNTRACK_STAT_INC_ATOMIC(count)		\
-do {							\
-	local_bh_disable();				\
-	__get_cpu_var(ip_conntrack_stat).count++;	\
-	local_bh_enable();				\
-} while (0)
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-
-struct ip_conntrack_ecache {
-	struct ip_conntrack *ct;
-	unsigned int events;
-};
-DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
-
-#define CONNTRACK_ECACHE(x)	(__get_cpu_var(ip_conntrack_ecache).x)
- 
-extern struct atomic_notifier_head ip_conntrack_chain;
-extern struct atomic_notifier_head ip_conntrack_expect_chain;
-
-static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&ip_conntrack_chain, nb);
-}
-
-static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb);
-}
-
-static inline int 
-ip_conntrack_expect_register_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb);
-}
-
-static inline int
-ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain,
-			nb);
-}
-
-extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
-extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
-
-static inline void 
-ip_conntrack_event_cache(enum ip_conntrack_events event,
-			 const struct sk_buff *skb)
-{
-	struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
-	struct ip_conntrack_ecache *ecache;
-	
-	local_bh_disable();
-	ecache = &__get_cpu_var(ip_conntrack_ecache);
-	if (ct != ecache->ct)
-		__ip_ct_event_cache_init(ct);
-	ecache->events |= event;
-	local_bh_enable();
-}
-
-static inline void ip_conntrack_event(enum ip_conntrack_events event,
-				      struct ip_conntrack *ct)
-{
-	if (is_confirmed(ct) && !is_dying(ct))
-		atomic_notifier_call_chain(&ip_conntrack_chain, event, ct);
-}
-
-static inline void 
-ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
-			  struct ip_conntrack_expect *exp)
-{
-	atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
-}
-#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, 
-					    const struct sk_buff *skb) {}
-static inline void ip_conntrack_event(enum ip_conntrack_events event, 
-				      struct ip_conntrack *ct) {}
-static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
-static inline void 
-ip_conntrack_expect_event(enum ip_conntrack_expect_events event, 
-			  struct ip_conntrack_expect *exp) {}
-#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
-				     enum ip_nat_manip_type manip)
-{
-	if (manip == IP_NAT_MANIP_SRC)
-		return test_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
-	return test_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
-}
-#endif /* CONFIG_IP_NF_NAT_NEEDED */
-
-#endif /* __KERNEL__ */
-#endif /* _IP_CONNTRACK_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
deleted file mode 100644
index de3e41f..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _IP_CONNTRACK_AMANDA_H
-#define _IP_CONNTRACK_AMANDA_H
-/* AMANDA tracking. */
-
-struct ip_conntrack_expect;
-extern unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
-					  enum ip_conntrack_info ctinfo,
-					  unsigned int matchoff,
-					  unsigned int matchlen,
-					  struct ip_conntrack_expect *exp);
-#endif /* _IP_CONNTRACK_AMANDA_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
deleted file mode 100644
index e3a6df0..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _IP_CONNTRACK_CORE_H
-#define _IP_CONNTRACK_CORE_H
-#include <linux/netfilter.h>
-
-#define MAX_IP_CT_PROTO 256
-extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
-
-/* This header is used to share core functionality between the
-   standalone connection tracking module, and the compatibility layer's use
-   of connection tracking. */
-extern unsigned int ip_conntrack_in(unsigned int hooknum,
-				    struct sk_buff **pskb,
-				    const struct net_device *in,
-				    const struct net_device *out,
-				    int (*okfn)(struct sk_buff *));
-
-extern int ip_conntrack_init(void);
-extern void ip_conntrack_cleanup(void);
-
-struct ip_conntrack_protocol;
-
-extern int
-ip_ct_get_tuple(const struct iphdr *iph,
-		const struct sk_buff *skb,
-		unsigned int dataoff,
-		struct ip_conntrack_tuple *tuple,
-		const struct ip_conntrack_protocol *protocol);
-
-extern int
-ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
-		   const struct ip_conntrack_tuple *orig,
-		   const struct ip_conntrack_protocol *protocol);
-
-/* Find a connection corresponding to a tuple. */
-struct ip_conntrack_tuple_hash *
-ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-		      const struct ip_conntrack *ignored_conntrack);
-
-extern int __ip_conntrack_confirm(struct sk_buff **pskb);
-
-/* Confirm a connection: returns NF_DROP if packet must be dropped. */
-static inline int ip_conntrack_confirm(struct sk_buff **pskb)
-{
-	struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
-	int ret = NF_ACCEPT;
-
-	if (ct) {
-		if (!is_confirmed(ct) && !is_dying(ct))
-			ret = __ip_conntrack_confirm(pskb);
-		ip_ct_deliver_cached_events(ct);
-	}
-	return ret;
-}
-
-extern void ip_ct_unlink_expect(struct ip_conntrack_expect *exp);
-
-extern struct list_head *ip_conntrack_hash;
-extern struct list_head ip_conntrack_expect_list;
-extern rwlock_t ip_conntrack_lock;
-#endif /* _IP_CONNTRACK_CORE_H */
-
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
deleted file mode 100644
index 2129fc3..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _IP_CONNTRACK_FTP_H
-#define _IP_CONNTRACK_FTP_H
-/* FTP tracking. */
-
-/* This enum is exposed to userspace */
-enum ip_ct_ftp_type
-{
-	/* PORT command from client */
-	IP_CT_FTP_PORT,
-	/* PASV response from server */
-	IP_CT_FTP_PASV,
-	/* EPRT command from client */
-	IP_CT_FTP_EPRT,
-	/* EPSV response from server */
-	IP_CT_FTP_EPSV,
-};
-
-#ifdef __KERNEL__
-
-#define FTP_PORT	21
-
-#define NUM_SEQ_TO_REMEMBER 2
-/* This structure exists only once per master */
-struct ip_ct_ftp_master {
-	/* Valid seq positions for cmd matching after newline */
-	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
-	/* 0 means seq_match_aft_nl not set */
-	int seq_aft_nl_num[IP_CT_DIR_MAX];
-};
-
-struct ip_conntrack_expect;
-
-/* For NAT to hook in when we find a packet which describes what other
- * connection we should expect. */
-extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
-				       enum ip_conntrack_info ctinfo,
-				       enum ip_ct_ftp_type type,
-				       unsigned int matchoff,
-				       unsigned int matchlen,
-				       struct ip_conntrack_expect *exp,
-				       u32 *seq);
-#endif /* __KERNEL__ */
-
-#endif /* _IP_CONNTRACK_FTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
deleted file mode 100644
index 18f7698..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _IP_CONNTRACK_H323_H
-#define _IP_CONNTRACK_H323_H
-
-#ifdef __KERNEL__
-
-#include <linux/netfilter/nf_conntrack_h323_asn1.h>
-
-#define RAS_PORT 1719
-#define Q931_PORT 1720
-#define H323_RTP_CHANNEL_MAX 4	/* Audio, video, FAX and other */
-
-/* This structure exists only once per master */
-struct ip_ct_h323_master {
-
-	/* Original and NATed Q.931 or H.245 signal ports */
-	u_int16_t sig_port[IP_CT_DIR_MAX];
-
-	/* Original and NATed RTP ports */
-	u_int16_t rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX];
-
-	union {
-		/* RAS connection timeout */
-		u_int32_t timeout;
-
-		/* Next TPKT length (for separate TPKT header and data) */
-		u_int16_t tpkt_len[IP_CT_DIR_MAX];
-	};
-};
-
-struct ip_conntrack_expect;
-
-extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
-			 __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,
-				     struct ip_conntrack_expect *this);
-extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
-				  unsigned char **data, int dataoff,
-				  H245_TransportAddress * addr,
-				  __be32 ip, u_int16_t port);
-extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
-				  unsigned char **data, int dataoff,
-				  TransportAddress * addr,
-				  __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,
-				 unsigned char **data,
-				 TransportAddress * addr, int count);
-extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
-				 struct ip_conntrack * ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data,
-				 TransportAddress * addr, int count);
-extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
-				 struct ip_conntrack * ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data, int dataoff,
-				 H245_TransportAddress * addr,
-				 u_int16_t port, u_int16_t rtp_port,
-				 struct ip_conntrack_expect * rtp_exp,
-				 struct ip_conntrack_expect * rtcp_exp);
-extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, int dataoff,
-			     H245_TransportAddress * addr, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, int dataoff,
-			     TransportAddress * addr, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
-				       struct ip_conntrack * ct,
-				       enum ip_conntrack_info ctinfo,
-				       unsigned char **data, int dataoff,
-				       TransportAddress * addr,
-				       u_int16_t port,
-				       struct ip_conntrack_expect * exp);
-extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, TransportAddress * addr,
-			     int idx, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-
-#endif
-
-#endif
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
deleted file mode 100644
index 77fe868..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* IP connection tracking helpers. */
-#ifndef _IP_CONNTRACK_HELPER_H
-#define _IP_CONNTRACK_HELPER_H
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-
-struct module;
-
-struct ip_conntrack_helper
-{	
-	struct list_head list; 		/* Internal use. */
-
-	const char *name;		/* name of the module */
-	struct module *me;		/* pointer to self */
-	unsigned int max_expected;	/* Maximum number of concurrent 
-					 * expected connections */
-	unsigned int timeout;		/* timeout for expecteds */
-
-	/* Mask of things we will help (compared against server response) */
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack_tuple mask;
-	
-	/* Function to call when data passes; return verdict, or -1 to
-           invalidate. */
-	int (*help)(struct sk_buff **pskb,
-		    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);
-};
-
-extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
-extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
-
-/* Allocate space for an expectation: this is mandatory before calling 
-   ip_conntrack_expect_related.  You will have to call put afterwards. */
-extern struct ip_conntrack_expect *
-ip_conntrack_expect_alloc(struct ip_conntrack *master);
-extern void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
-
-/* Add an expected connection: can have more than one per connection */
-extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp);
-extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
-
-#endif /*_IP_CONNTRACK_HELPER_H*/
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h
deleted file mode 100644
index eed5ee3..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _IP_CONNTRACK_ICMP_H
-#define _IP_CONNTRACK_ICMP_H
-
-#include <net/netfilter/ipv4/nf_conntrack_icmp.h>
-
-#endif /* _IP_CONNTRACK_ICMP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h
deleted file mode 100644
index 16601e0..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* IRC extension for IP connection tracking.
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
- * based on RR's ip_conntrack_ftp.h
- *
- * ip_conntrack_irc.h,v 1.6 2000/11/07 18:26:42 laforge Exp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- *
- */
-#ifndef _IP_CONNTRACK_IRC_H
-#define _IP_CONNTRACK_IRC_H
-
-/* This structure exists only once per master */
-struct ip_ct_irc_master {
-};
-
-#ifdef __KERNEL__
-extern unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
-				       enum ip_conntrack_info ctinfo,
-				       unsigned int matchoff,
-				       unsigned int matchlen,
-				       struct ip_conntrack_expect *exp);
-
-#define IRC_PORT	6667
-
-#endif /* __KERNEL__ */
-
-#endif /* _IP_CONNTRACK_IRC_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
deleted file mode 100644
index 2644b1f..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/* PPTP constants and structs */
-#ifndef _CONNTRACK_PPTP_H
-#define _CONNTRACK_PPTP_H
-
-/* state of the control session */
-enum pptp_ctrlsess_state {
-	PPTP_SESSION_NONE,			/* no session present */
-	PPTP_SESSION_ERROR,			/* some session error */
-	PPTP_SESSION_STOPREQ,			/* stop_sess request seen */
-	PPTP_SESSION_REQUESTED,			/* start_sess request seen */
-	PPTP_SESSION_CONFIRMED,			/* session established */
-};
-
-/* state of the call inside the control session */
-enum pptp_ctrlcall_state {
-	PPTP_CALL_NONE,
-	PPTP_CALL_ERROR,
-	PPTP_CALL_OUT_REQ,
-	PPTP_CALL_OUT_CONF,
-	PPTP_CALL_IN_REQ,
-	PPTP_CALL_IN_REP,
-	PPTP_CALL_IN_CONF,
-	PPTP_CALL_CLEAR_REQ,
-};
-
-
-/* conntrack private data */
-struct ip_ct_pptp_master {
-	enum pptp_ctrlsess_state sstate;	/* session state */
-
-	/* 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 */
-	__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 */
-	struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
-};
-
-/* conntrack_expect private member */
-struct ip_ct_pptp_expect {
-	enum pptp_ctrlcall_state cstate; 	/* call state */
-	__be16 pac_call_id;			/* call id of PAC */
-	__be16 pns_call_id;			/* call id of PNS */
-};
-
-
-#ifdef __KERNEL__
-
-#define IP_CONNTR_PPTP		PPTP_CONTROL_PORT
-
-#define PPTP_CONTROL_PORT	1723
-
-#define PPTP_PACKET_CONTROL	1
-#define PPTP_PACKET_MGMT	2
-
-#define PPTP_MAGIC_COOKIE	0x1a2b3c4d
-
-struct pptp_pkt_hdr {
-	__u16	packetLength;
-	__be16	packetType;
-	__be32	magicCookie;
-};
-
-/* PptpControlMessageType values */
-#define PPTP_START_SESSION_REQUEST	1
-#define PPTP_START_SESSION_REPLY	2
-#define PPTP_STOP_SESSION_REQUEST	3
-#define PPTP_STOP_SESSION_REPLY		4
-#define PPTP_ECHO_REQUEST		5
-#define PPTP_ECHO_REPLY			6
-#define PPTP_OUT_CALL_REQUEST		7
-#define PPTP_OUT_CALL_REPLY		8
-#define PPTP_IN_CALL_REQUEST		9
-#define PPTP_IN_CALL_REPLY		10
-#define PPTP_IN_CALL_CONNECT		11
-#define PPTP_CALL_CLEAR_REQUEST		12
-#define PPTP_CALL_DISCONNECT_NOTIFY	13
-#define PPTP_WAN_ERROR_NOTIFY		14
-#define PPTP_SET_LINK_INFO		15
-
-#define PPTP_MSG_MAX			15
-
-/* PptpGeneralError values */
-#define PPTP_ERROR_CODE_NONE		0
-#define PPTP_NOT_CONNECTED		1
-#define PPTP_BAD_FORMAT			2
-#define PPTP_BAD_VALUE			3
-#define PPTP_NO_RESOURCE		4
-#define PPTP_BAD_CALLID			5
-#define PPTP_REMOVE_DEVICE_ERROR	6
-
-struct PptpControlHeader {
-	__be16	messageType;
-	__u16	reserved;
-};
-
-/* FramingCapability Bitmap Values */
-#define PPTP_FRAME_CAP_ASYNC		0x1
-#define PPTP_FRAME_CAP_SYNC		0x2
-
-/* BearerCapability Bitmap Values */
-#define PPTP_BEARER_CAP_ANALOG		0x1
-#define PPTP_BEARER_CAP_DIGITAL		0x2
-
-struct PptpStartSessionRequest {
-	__be16	protocolVersion;
-	__u16	reserved1;
-	__be32	framingCapability;
-	__be32	bearerCapability;
-	__be16	maxChannels;
-	__be16	firmwareRevision;
-	__u8	hostName[64];
-	__u8	vendorString[64];
-};
-
-/* PptpStartSessionResultCode Values */
-#define PPTP_START_OK			1
-#define PPTP_START_GENERAL_ERROR	2
-#define PPTP_START_ALREADY_CONNECTED	3
-#define PPTP_START_NOT_AUTHORIZED	4
-#define PPTP_START_UNKNOWN_PROTOCOL	5
-
-struct PptpStartSessionReply {
-	__be16	protocolVersion;
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__be32	framingCapability;
-	__be32	bearerCapability;
-	__be16	maxChannels;
-	__be16	firmwareRevision;
-	__u8	hostName[64];
-	__u8	vendorString[64];
-};
-
-/* PptpStopReasons */
-#define PPTP_STOP_NONE			1
-#define PPTP_STOP_PROTOCOL		2
-#define PPTP_STOP_LOCAL_SHUTDOWN	3
-
-struct PptpStopSessionRequest {
-	__u8	reason;
-	__u8	reserved1;
-	__u16	reserved2;
-};
-
-/* PptpStopSessionResultCode */
-#define PPTP_STOP_OK			1
-#define PPTP_STOP_GENERAL_ERROR		2
-
-struct PptpStopSessionReply {
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__u16	reserved1;
-};
-
-struct PptpEchoRequest {
-	__be32 identNumber;
-};
-
-/* PptpEchoReplyResultCode */
-#define PPTP_ECHO_OK			1
-#define PPTP_ECHO_GENERAL_ERROR		2
-
-struct PptpEchoReply {
-	__be32	identNumber;
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__u16	reserved;
-};
-
-/* PptpFramingType */
-#define PPTP_ASYNC_FRAMING		1
-#define PPTP_SYNC_FRAMING		2
-#define PPTP_DONT_CARE_FRAMING		3
-
-/* PptpCallBearerType */
-#define PPTP_ANALOG_TYPE		1
-#define PPTP_DIGITAL_TYPE		2
-#define PPTP_DONT_CARE_BEARER_TYPE	3
-
-struct PptpOutCallRequest {
-	__be16	callID;
-	__be16	callSerialNumber;
-	__be32	minBPS;
-	__be32	maxBPS;
-	__be32	bearerType;
-	__be32	framingType;
-	__be16	packetWindow;
-	__be16	packetProcDelay;
-	__be16	phoneNumberLength;
-	__u16	reserved1;
-	__u8	phoneNumber[64];
-	__u8	subAddress[64];
-};
-
-/* PptpCallResultCode */
-#define PPTP_OUTCALL_CONNECT		1
-#define PPTP_OUTCALL_GENERAL_ERROR	2
-#define PPTP_OUTCALL_NO_CARRIER		3
-#define PPTP_OUTCALL_BUSY		4
-#define PPTP_OUTCALL_NO_DIAL_TONE	5
-#define PPTP_OUTCALL_TIMEOUT		6
-#define PPTP_OUTCALL_DONT_ACCEPT	7
-
-struct PptpOutCallReply {
-	__be16	callID;
-	__be16	peersCallID;
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__be16	causeCode;
-	__be32	connectSpeed;
-	__be16	packetWindow;
-	__be16	packetProcDelay;
-	__be32	physChannelID;
-};
-
-struct PptpInCallRequest {
-	__be16	callID;
-	__be16	callSerialNumber;
-	__be32	callBearerType;
-	__be32	physChannelID;
-	__be16	dialedNumberLength;
-	__be16	dialingNumberLength;
-	__u8	dialedNumber[64];
-	__u8	dialingNumber[64];
-	__u8	subAddress[64];
-};
-
-/* PptpInCallResultCode */
-#define PPTP_INCALL_ACCEPT		1
-#define PPTP_INCALL_GENERAL_ERROR	2
-#define PPTP_INCALL_DONT_ACCEPT		3
-
-struct PptpInCallReply {
-	__be16	callID;
-	__be16	peersCallID;
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__be16	packetWindow;
-	__be16	packetProcDelay;
-	__u16	reserved;
-};
-
-struct PptpInCallConnected {
-	__be16	peersCallID;
-	__u16	reserved;
-	__be32	connectSpeed;
-	__be16	packetWindow;
-	__be16	packetProcDelay;
-	__be32	callFramingType;
-};
-
-struct PptpClearCallRequest {
-	__be16	callID;
-	__u16	reserved;
-};
-
-struct PptpCallDisconnectNotify {
-	__be16	callID;
-	__u8	resultCode;
-	__u8	generalErrorCode;
-	__be16	causeCode;
-	__u16	reserved;
-	__u8	callStatistics[128];
-};
-
-struct PptpWanErrorNotify {
-	__be16	peersCallID;
-	__u16	reserved;
-	__be32	crcErrors;
-	__be32	framingErrors;
-	__be32	hardwareOverRuns;
-	__be32	bufferOverRuns;
-	__be32	timeoutErrors;
-	__be32	alignmentErrors;
-};
-
-struct PptpSetLinkInfo {
-	__be16	peersCallID;
-	__u16	reserved;
-	__be32	sendAccm;
-	__be32	recvAccm;
-};
-
-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;
-};
-
-extern int
-(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
-			  struct ip_conntrack *ct,
-			  enum ip_conntrack_info ctinfo,
-			  struct PptpControlHeader *ctlh,
-			  union pptp_ctrl_union *pptpReq);
-
-extern int
-(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
-			  struct ip_conntrack *ct,
-			  enum ip_conntrack_info ctinfo,
-			  struct PptpControlHeader *ctlh,
-			  union pptp_ctrl_union *pptpReq);
-
-extern void
-(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig,
-			    struct ip_conntrack_expect *exp_reply);
-
-extern void
-(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
-			     struct ip_conntrack_expect *exp);
-#endif /* __KERNEL__ */
-#endif /* _CONNTRACK_PPTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
deleted file mode 100644
index e371e0f..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _CONNTRACK_PROTO_GRE_H
-#define _CONNTRACK_PROTO_GRE_H
-#include <asm/byteorder.h>
-
-/* GRE PROTOCOL HEADER */
-
-/* GRE Version field */
-#define GRE_VERSION_1701	0x0
-#define GRE_VERSION_PPTP	0x1
-
-/* GRE Protocol field */
-#define GRE_PROTOCOL_PPTP	0x880B
-
-/* GRE Flags */
-#define GRE_FLAG_C		0x80
-#define GRE_FLAG_R		0x40
-#define GRE_FLAG_K		0x20
-#define GRE_FLAG_S		0x10
-#define GRE_FLAG_A		0x80
-
-#define GRE_IS_C(f)	((f)&GRE_FLAG_C)
-#define GRE_IS_R(f)	((f)&GRE_FLAG_R)
-#define GRE_IS_K(f)	((f)&GRE_FLAG_K)
-#define GRE_IS_S(f)	((f)&GRE_FLAG_S)
-#define GRE_IS_A(f)	((f)&GRE_FLAG_A)
-
-/* GRE is a mess: Four different standards */
-struct gre_hdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u16	rec:3,
-		srr:1,
-		seq:1,
-		key:1,
-		routing:1,
-		csum:1,
-		version:3,
-		reserved:4,
-		ack:1;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u16	csum:1,
-		routing:1,
-		key:1,
-		seq:1,
-		srr:1,
-		rec:3,
-		ack:1,
-		reserved:4,
-		version:3;
-#else
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
-	__be16	protocol;
-};
-
-/* modified GRE header for PPTP */
-struct gre_hdr_pptp {
-	__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 */
-};
-
-
-/* this is part of ip_conntrack */
-struct ip_ct_gre {
-	unsigned int stream_timeout;
-	unsigned int timeout;
-};
-
-#ifdef __KERNEL__
-struct ip_conntrack_expect;
-struct ip_conntrack;
-
-/* structure for original <-> reply keymap */
-struct ip_ct_gre_keymap {
-	struct list_head list;
-
-	struct ip_conntrack_tuple tuple;
-};
-
-/* add new tuple->key_reply pair to keymap */
-int ip_ct_gre_keymap_add(struct ip_conntrack *ct,
-			 struct ip_conntrack_tuple *t,
-			 int reply);
-
-/* delete keymap entries */
-void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct);
-
-
-/* get pointer to gre key, if present */
-static inline __be32 *gre_key(struct gre_hdr *greh)
-{
-	if (!greh->key)
-		return NULL;
-	if (greh->csum || greh->routing)
-		return (__be32 *) (greh+sizeof(*greh)+4);
-	return (__be32 *) (greh+sizeof(*greh));
-}
-
-/* get pointer ot gre csum, if present */
-static inline __sum16 *gre_csum(struct gre_hdr *greh)
-{
-	if (!greh->csum)
-		return NULL;
-	return (__sum16 *) (greh+sizeof(*greh));
-}
-
-#endif /* __KERNEL__ */
-
-#endif /* _CONNTRACK_PROTO_GRE_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
deleted file mode 100644
index 2c76b87..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Header for use in defining a given protocol for connection tracking. */
-#ifndef _IP_CONNTRACK_PROTOCOL_H
-#define _IP_CONNTRACK_PROTOCOL_H
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter/nfnetlink_conntrack.h>
-
-struct seq_file;
-
-struct ip_conntrack_protocol
-{
-	/* Protocol number. */
-	u_int8_t proto;
-
-	/* Protocol name */
-	const char *name;
-
-	/* Try to fill in the third arg: dataoff is offset past IP
-           hdr.  Return true if possible. */
-	int (*pkt_to_tuple)(const struct sk_buff *skb,
-			   unsigned int dataoff,
-			   struct ip_conntrack_tuple *tuple);
-
-	/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
-	 * Some packets can't be inverted: return 0 in that case.
-	 */
-	int (*invert_tuple)(struct ip_conntrack_tuple *inverse,
-			    const struct ip_conntrack_tuple *orig);
-
-	/* Print out the per-protocol part of the tuple. Return like seq_* */
-	int (*print_tuple)(struct seq_file *,
-			   const struct ip_conntrack_tuple *);
-
-	/* Print out the private part of the conntrack. */
-	int (*print_conntrack)(struct seq_file *, const struct ip_conntrack *);
-
-	/* Returns verdict for packet, or -1 for invalid. */
-	int (*packet)(struct ip_conntrack *conntrack,
-		      const struct sk_buff *skb,
-		      enum ip_conntrack_info ctinfo);
-
-	/* Called when a new connection for this protocol found;
-	 * returns TRUE if it's OK.  If so, packet() called next. */
-	int (*new)(struct ip_conntrack *conntrack, const struct sk_buff *skb);
-
-	/* Called when a conntrack entry is destroyed */
-	void (*destroy)(struct ip_conntrack *conntrack);
-
-	int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
-		     unsigned int hooknum);
-
-	/* convert protoinfo to nfnetink attributes */
-	int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa,
-			 const struct ip_conntrack *ct);
-
-	/* convert nfnetlink attributes to protoinfo */
-	int (*from_nfattr)(struct nfattr *tb[], struct ip_conntrack *ct);
-
-	int (*tuple_to_nfattr)(struct sk_buff *skb,
-			       const struct ip_conntrack_tuple *t);
-	int (*nfattr_to_tuple)(struct nfattr *tb[],
-			       struct ip_conntrack_tuple *t);
-
-	/* Module (if any) which this is connected to. */
-	struct module *me;
-};
-
-/* Protocol registration. */
-extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto);
-extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto);
-/* Existing built-in protocols */
-extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp;
-extern struct ip_conntrack_protocol ip_conntrack_protocol_udp;
-extern struct ip_conntrack_protocol ip_conntrack_protocol_icmp;
-extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
-extern int ip_conntrack_protocol_tcp_init(void);
-
-/* Log invalid packets */
-extern unsigned int ip_ct_log_invalid;
-
-extern int ip_ct_port_tuple_to_nfattr(struct sk_buff *,
-				      const struct ip_conntrack_tuple *);
-extern int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
-				      struct ip_conntrack_tuple *);
-
-#ifdef CONFIG_SYSCTL
-#ifdef DEBUG_INVALID_PACKETS
-#define LOG_INVALID(proto) \
-	(ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW)
-#else
-#define LOG_INVALID(proto) \
-	((ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW) \
-	 && net_ratelimit())
-#endif
-#else
-#define LOG_INVALID(proto) 0
-#endif /* CONFIG_SYSCTL */
-
-#endif /*_IP_CONNTRACK_PROTOCOL_H*/
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
deleted file mode 100644
index 4099a04..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _IP_CONNTRACK_SCTP_H
-#define _IP_CONNTRACK_SCTP_H
-
-#include <linux/netfilter/nf_conntrack_sctp.h>
-
-#endif /* _IP_CONNTRACK_SCTP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h
deleted file mode 100644
index bef6c64..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __IP_CONNTRACK_SIP_H__
-#define __IP_CONNTRACK_SIP_H__
-#ifdef __KERNEL__
-
-#define SIP_PORT	5060
-#define SIP_TIMEOUT	3600
-
-enum sip_header_pos {
-	POS_REG_REQ_URI,
-	POS_REQ_URI,
-	POS_FROM,
-	POS_TO,
-	POS_VIA,
-	POS_CONTACT,
-	POS_CONTENT,
-	POS_MEDIA,
-	POS_OWNER,
-	POS_CONNECTION,
-	POS_SDP_HEADER,
-};
-
-extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
-				       enum ip_conntrack_info ctinfo,
-				       struct ip_conntrack *ct,
-				       const char **dptr);
-extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
-				       enum ip_conntrack_info ctinfo,
-				       struct ip_conntrack_expect *exp,
-				       const char *dptr);
-
-extern int ct_sip_get_info(const char *dptr, size_t dlen,
-			   unsigned int *matchoff,
-			   unsigned int *matchlen,
-			   enum sip_header_pos pos);
-extern int ct_sip_lnlen(const char *line, const char *limit);
-extern const char *ct_sip_search(const char *needle, const char *haystack,
-				 size_t needle_len, size_t haystack_len,
-				 int case_sensitive);
-#endif /* __KERNEL__ */
-#endif /* __IP_CONNTRACK_SIP_H__ */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
deleted file mode 100644
index 876b8fb..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _IP_CONNTRACK_TCP_H
-#define _IP_CONNTRACK_TCP_H
-
-#include <linux/netfilter/nf_conntrack_tcp.h>
-
-#endif /* _IP_CONNTRACK_TCP_H */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h
deleted file mode 100644
index a404fc0..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _IP_CT_TFTP
-#define _IP_CT_TFTP
-
-#define TFTP_PORT 69
-
-struct tftphdr {
-	__be16 opcode;
-};
-
-#define TFTP_OPCODE_READ	1
-#define TFTP_OPCODE_WRITE	2
-#define TFTP_OPCODE_DATA	3
-#define TFTP_OPCODE_ACK		4
-#define TFTP_OPCODE_ERROR	5
-
-extern unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb,
-				 enum ip_conntrack_info ctinfo,
-				 struct ip_conntrack_expect *exp);
-
-#endif /* _IP_CT_TFTP */
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
deleted file mode 100644
index c228bde..0000000
--- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef _IP_CONNTRACK_TUPLE_H
-#define _IP_CONNTRACK_TUPLE_H
-
-#include <linux/types.h>
-#include <linux/netfilter/nf_conntrack_tuple_common.h>
-
-/* A `tuple' is a structure containing the information to uniquely
-  identify a connection.  ie. if two packets have the same tuple, they
-  are in the same connection; if not, they are not.
-
-  We divide the structure along "manipulatable" and
-  "non-manipulatable" lines, for the benefit of the NAT code.
-*/
-
-/* The protocol-specific manipulable parts of the tuple: always in
-   network order! */
-union ip_conntrack_manip_proto
-{
-	/* Add other protocols here. */
-	u_int16_t all;
-
-	struct {
-		__be16 port;
-	} tcp;
-	struct {
-		__be16 port;
-	} udp;
-	struct {
-		__be16 id;
-	} icmp;
-	struct {
-		__be16 port;
-	} sctp;
-	struct {
-		__be16 key;	/* key is 32bit, pptp only uses 16 */
-	} gre;
-};
-
-/* The manipulable part of the tuple. */
-struct ip_conntrack_manip
-{
-	__be32 ip;
-	union ip_conntrack_manip_proto u;
-};
-
-/* This contains the information to distinguish a connection. */
-struct ip_conntrack_tuple
-{
-	struct ip_conntrack_manip src;
-
-	/* These are the parts of the tuple which are fixed. */
-	struct {
-		__be32 ip;
-		union {
-			/* Add other protocols here. */
-			u_int16_t all;
-
-			struct {
-				__be16 port;
-			} tcp;
-			struct {
-				__be16 port;
-			} udp;
-			struct {
-				u_int8_t type, code;
-			} icmp;
-			struct {
-				__be16 port;
-			} sctp;
-			struct {
-				__be16 key;	/* key is 32bit, 
-						 * pptp only uses 16 */
-			} gre;
-		} u;
-
-		/* The protocol. */
-		u_int8_t protonum;
-
-		/* The direction (for tuplehash) */
-		u_int8_t dir;
-	} dst;
-};
-
-/* This is optimized opposed to a memset of the whole structure.  Everything we
- * really care about is the  source/destination unions */
-#define IP_CT_TUPLE_U_BLANK(tuple) 				\
-	do {							\
-		(tuple)->src.u.all = 0;				\
-		(tuple)->dst.u.all = 0;				\
-	} while (0)
-
-#ifdef __KERNEL__
-
-#define DUMP_TUPLE(tp)						\
-DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",	\
-       (tp), (tp)->dst.protonum,				\
-       NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all),		\
-       NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
-
-/* If we're the first tuple, it's the original dir. */
-#define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir)
-
-/* Connections have two entries in the hash table: one for each way */
-struct ip_conntrack_tuple_hash
-{
-	struct list_head list;
-
-	struct ip_conntrack_tuple tuple;
-};
-
-#endif /* __KERNEL__ */
-
-static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
-				        const struct ip_conntrack_tuple *t2)
-{
-	return t1->src.ip == t2->src.ip
-		&& t1->src.u.all == t2->src.u.all;
-}
-
-static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
-				        const struct ip_conntrack_tuple *t2)
-{
-	return t1->dst.ip == t2->dst.ip
-		&& t1->dst.u.all == t2->dst.u.all
-		&& t1->dst.protonum == t2->dst.protonum;
-}
-
-static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
-				    const struct ip_conntrack_tuple *t2)
-{
-	return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
-}
-
-static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
-				       const struct ip_conntrack_tuple *tuple,
-				       const struct ip_conntrack_tuple *mask)
-{
-	return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip)
-		 || ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip)
-		 || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all)
-		 || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all)
-		 || ((t->dst.protonum ^ tuple->dst.protonum)
-		     & mask->dst.protonum));
-}
-
-#endif /* _IP_CONNTRACK_TUPLE_H */
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
deleted file mode 100644
index bbca89a..0000000
--- a/include/linux/netfilter_ipv4/ip_nat.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _IP_NAT_H
-#define _IP_NAT_H
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-
-#define IP_NAT_MAPPING_TYPE_MAX_NAMELEN 16
-
-enum ip_nat_manip_type
-{
-	IP_NAT_MANIP_SRC,
-	IP_NAT_MANIP_DST
-};
-
-/* SRC manip occurs POST_ROUTING or LOCAL_IN */
-#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
-
-#define IP_NAT_RANGE_MAP_IPS 1
-#define IP_NAT_RANGE_PROTO_SPECIFIED 2
-#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
-
-/* NAT sequence number modifications */
-struct ip_nat_seq {
-	/* position of the last TCP sequence number 
-	 * modification (if any) */
-	u_int32_t correction_pos;
-	/* sequence number offset before and after last modification */
-	int16_t offset_before, offset_after;
-};
-
-/* Single range specification. */
-struct ip_nat_range
-{
-	/* Set to OR of flags above. */
-	unsigned int flags;
-
-	/* Inclusive: network order. */
-	__be32 min_ip, max_ip;
-
-	/* Inclusive: network order */
-	union ip_conntrack_manip_proto min, max;
-};
-
-/* For backwards compat: don't use in modern code. */
-struct ip_nat_multi_range_compat
-{
-	unsigned int rangesize; /* Must be 1. */
-
-	/* hangs off end. */
-	struct ip_nat_range range[1];
-};
-
-#ifdef __KERNEL__
-#include <linux/list.h>
-
-/* Protects NAT hash tables, and NAT-private part of conntracks. */
-extern rwlock_t ip_nat_lock;
-
-/* The structure embedded in the conntrack structure. */
-struct ip_nat_info
-{
-	struct list_head bysource;
-	struct ip_nat_seq seq[IP_CT_DIR_MAX];
-};
-
-struct ip_conntrack;
-
-/* Set up the info structure to map into this range. */
-extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
-				      const struct ip_nat_range *range,
-				      unsigned int hooknum);
-
-/* Is this tuple already taken? (not by us)*/
-extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
-			     const struct ip_conntrack *ignored_conntrack);
-
-#else  /* !__KERNEL__: iptables wants this to compile. */
-#define ip_nat_multi_range ip_nat_multi_range_compat
-#endif /*__KERNEL__*/
-#endif
diff --git a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h
deleted file mode 100644
index 60566f9..0000000
--- a/include/linux/netfilter_ipv4/ip_nat_core.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _IP_NAT_CORE_H
-#define _IP_NAT_CORE_H
-#include <linux/list.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-
-/* This header used to share core functionality between the standalone
-   NAT module, and the compatibility layer's use of NAT for masquerading. */
-
-extern unsigned int ip_nat_packet(struct ip_conntrack *ct,
-			       enum ip_conntrack_info conntrackinfo,
-			       unsigned int hooknum,
-			       struct sk_buff **pskb);
-
-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_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h
deleted file mode 100644
index bf9cb10..0000000
--- a/include/linux/netfilter_ipv4/ip_nat_helper.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _IP_NAT_HELPER_H
-#define _IP_NAT_HELPER_H
-/* NAT protocol helper routines. */
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/module.h>
-
-struct sk_buff;
-
-/* These return true or false. */
-extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
-				struct ip_conntrack *ct,
-				enum ip_conntrack_info ctinfo,
-				unsigned int match_offset,
-				unsigned int match_len,
-				const char *rep_buffer,
-				unsigned int rep_len);
-extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
-				struct ip_conntrack *ct,
-				enum ip_conntrack_info ctinfo,
-				unsigned int match_offset,
-				unsigned int match_len,
-				const char *rep_buffer,
-				unsigned int rep_len);
-extern int ip_nat_seq_adjust(struct sk_buff **pskb, 
-			     struct ip_conntrack *ct, 
-			     enum ip_conntrack_info ctinfo);
-
-/* Setup NAT on this expected conntrack so it follows master, but goes
- * to port ct->master->saved_proto. */
-extern void ip_nat_follow_master(struct ip_conntrack *ct,
-				 struct ip_conntrack_expect *this);
-#endif
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h
deleted file mode 100644
index 36668bf..0000000
--- a/include/linux/netfilter_ipv4/ip_nat_pptp.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* PPTP constants and structs */
-#ifndef _NAT_PPTP_H
-#define _NAT_PPTP_H
-
-/* conntrack private data */
-struct ip_nat_pptp {
-	__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_nat_protocol.h b/include/linux/netfilter_ipv4/ip_nat_protocol.h
deleted file mode 100644
index 612a436..0000000
--- a/include/linux/netfilter_ipv4/ip_nat_protocol.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Header for use in defining a given protocol. */
-#ifndef _IP_NAT_PROTOCOL_H
-#define _IP_NAT_PROTOCOL_H
-#include <linux/init.h>
-#include <linux/list.h>
-
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter/nfnetlink_conntrack.h>
-
-struct iphdr;
-struct ip_nat_range;
-
-struct ip_nat_protocol
-{
-	/* Protocol name */
-	const char *name;
-
-	/* Protocol number. */
-	unsigned int protonum;
-
-	struct module *me;
-
-	/* Translate a packet to the target according to manip type.
-	   Return true if succeeded. */
-	int (*manip_pkt)(struct sk_buff **pskb,
-			 unsigned int iphdroff,
-			 const struct ip_conntrack_tuple *tuple,
-			 enum ip_nat_manip_type maniptype);
-
-	/* Is the manipable part of the tuple between min and max incl? */
-	int (*in_range)(const struct ip_conntrack_tuple *tuple,
-			enum ip_nat_manip_type maniptype,
-			const union ip_conntrack_manip_proto *min,
-			const union ip_conntrack_manip_proto *max);
-
-	/* Alter the per-proto part of the tuple (depending on
-	   maniptype), to give a unique tuple in the given range if
-	   possible; return false if not.  Per-protocol part of tuple
-	   is initialized to the incoming packet. */
-	int (*unique_tuple)(struct ip_conntrack_tuple *tuple,
-			    const struct ip_nat_range *range,
-			    enum ip_nat_manip_type maniptype,
-			    const struct ip_conntrack *conntrack);
-
-	int (*range_to_nfattr)(struct sk_buff *skb,
-			       const struct ip_nat_range *range);
-
-	int (*nfattr_to_range)(struct nfattr *tb[],
-			       struct ip_nat_range *range);
-};
-
-/* Protocol registration. */
-extern int ip_nat_protocol_register(struct ip_nat_protocol *proto);
-extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto);
-
-extern struct ip_nat_protocol *ip_nat_proto_find_get(u_int8_t protocol);
-extern void ip_nat_proto_put(struct ip_nat_protocol *proto);
-
-/* Built-in protocols. */
-extern struct ip_nat_protocol ip_nat_protocol_tcp;
-extern struct ip_nat_protocol ip_nat_protocol_udp;
-extern struct ip_nat_protocol ip_nat_protocol_icmp;
-extern struct ip_nat_protocol ip_nat_unknown_protocol;
-
-extern int init_protocols(void) __init;
-extern void cleanup_protocols(void);
-extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum);
-
-extern int ip_nat_port_range_to_nfattr(struct sk_buff *skb,
-				       const struct ip_nat_range *range);
-extern int ip_nat_port_nfattr_to_range(struct nfattr *tb[],
-				       struct ip_nat_range *range);
-
-#endif /*_IP_NAT_PROTO_H*/
diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h
deleted file mode 100644
index 73b9552..0000000
--- a/include/linux/netfilter_ipv4/ip_nat_rule.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _IP_NAT_RULE_H
-#define _IP_NAT_RULE_H
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-
-#ifdef __KERNEL__
-
-extern int ip_nat_rule_init(void) __init;
-extern void ip_nat_rule_cleanup(void);
-extern int ip_nat_rule_find(struct sk_buff **pskb,
-			    unsigned int hooknum,
-			    const struct net_device *in,
-			    const struct net_device *out,
-			    struct ip_conntrack *ct,
-			    struct ip_nat_info *info);
-
-extern unsigned int
-alloc_null_binding(struct ip_conntrack *conntrack,
-		   struct ip_nat_info *info,
-		   unsigned int hooknum);
-
-extern unsigned int
-alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
-			     struct ip_nat_info *info,
-			     unsigned int hooknum);
-#endif
-#endif /* _IP_NAT_RULE_H */
diff --git a/include/linux/netfilter_ipv4/ipt_SAME.h b/include/linux/netfilter_ipv4/ipt_SAME.h
index cc4c0b2..be6e682 100644
--- a/include/linux/netfilter_ipv4/ipt_SAME.h
+++ b/include/linux/netfilter_ipv4/ipt_SAME.h
@@ -13,7 +13,7 @@ struct ipt_same_info
 	u_int32_t *iparray;
 
 	/* hangs off end. */
-	struct ip_nat_range range[IPT_SAME_MAX_RANGE];
+	struct nf_nat_range range[IPT_SAME_MAX_RANGE];
 };
 
 #endif /*_IPT_SAME_H*/
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 2a20f48..2e23353 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -31,7 +31,7 @@ struct sockaddr_nl
 {
 	sa_family_t	nl_family;	/* AF_NETLINK	*/
 	unsigned short	nl_pad;		/* zero		*/
-	__u32		nl_pid;		/* process pid	*/
+	__u32		nl_pid;		/* port ID	*/
        	__u32		nl_groups;	/* multicast groups mask */
 };
 
@@ -41,7 +41,7 @@ struct nlmsghdr
 	__u16		nlmsg_type;	/* Message content */
 	__u16		nlmsg_flags;	/* Additional flags */
 	__u32		nlmsg_seq;	/* Sequence number */
-	__u32		nlmsg_pid;	/* Sending process PID */
+	__u32		nlmsg_pid;	/* Sending process port ID */
 };
 
 /* Flags values */
@@ -138,6 +138,11 @@ #ifdef __KERNEL__
 #include <linux/capability.h>
 #include <linux/skbuff.h>
 
+static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
+{
+	return (struct nlmsghdr *)skb->data;
+}
+
 struct netlink_skb_parms
 {
 	struct ucred		creds;		/* Skb credentials	*/
@@ -152,7 +157,10 @@ #define NETLINK_CB(skb)		(*(struct netli
 #define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
 
 
-extern struct sock *netlink_kernel_create(int unit, unsigned int groups, void (*input)(struct sock *sk, int len), struct module *module);
+extern struct sock *netlink_kernel_create(int unit, unsigned int groups,
+					  void (*input)(struct sock *sk, int len),
+					  struct mutex *cb_mutex,
+					  struct module *module);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
@@ -171,9 +179,16 @@ int netlink_sendskb(struct sock *sk, str
 
 /*
  *	skb should fit one page. This choice is good for headerless malloc.
+ *	But we should limit to 8K so that userspace does not have to
+ *	use enormous buffer sizes on recvmsg() calls just to avoid
+ *	MSG_TRUNC when PAGE_SIZE is very large.
  */
-#define NLMSG_GOODORDER 0
-#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
+#if PAGE_SIZE < 8192UL
+#define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(PAGE_SIZE)
+#else
+#define NLMSG_GOODSIZE	SKB_WITH_OVERHEAD(8192UL)
+#endif
+
 #define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN)
 
 
@@ -217,18 +232,6 @@ ({	if (skb_tailroom(skb) < (int)NLMSG_SP
 #define NLMSG_PUT(skb, pid, seq, type, len) \
 	NLMSG_NEW(skb, pid, seq, type, len, 0)
 
-#define NLMSG_NEW_ANSWER(skb, cb, type, len, flags) \
-	NLMSG_NEW(skb, NETLINK_CB((cb)->skb).pid, \
-		  (cb)->nlh->nlmsg_seq, type, len, flags)
-
-#define NLMSG_END(skb, nlh) \
-({	(nlh)->nlmsg_len = (skb)->tail - (unsigned char *) (nlh); \
-	(skb)->len; })
-
-#define NLMSG_CANCEL(skb, nlh) \
-({	skb_trim(skb, (unsigned char *) (nlh) - (skb)->data); \
-	-1; })
-
 extern int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
 			      struct nlmsghdr *nlh,
 			      int (*dump)(struct sk_buff *skb, struct netlink_callback*),
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e9ae0c6..0543439 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -455,7 +455,7 @@ nfs_have_writebacks(struct inode *inode)
 /*
  * Allocate nfs_write_data structures
  */
-extern struct nfs_write_data *nfs_writedata_alloc(size_t len);
+extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs/read.c
@@ -469,7 +469,7 @@ extern void nfs_readdata_release(void *d
 /*
  * Allocate nfs_read_data structures
  */
-extern struct nfs_read_data *nfs_readdata_alloc(size_t len);
+extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages);
 
 /*
  * linux/fs/nfs3proc.c
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c95d5e6..52b4378 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -82,7 +82,7 @@ struct nfs_server {
 	struct rpc_clnt *	client_acl;	/* ACL RPC client handle */
 	struct nfs_iostats *	io_stats;	/* I/O statistics */
 	struct backing_dev_info	backing_dev_info;
-	atomic_t		writeback;	/* number of writeback pages */
+	atomic_long_t		writeback;	/* number of writeback pages */
 	int			flags;		/* various flags */
 	unsigned int		caps;		/* server capabilities */
 	unsigned int		rsize;		/* read size */
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 659c754..cc8b9c5 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -61,6 +61,7 @@ #define NFS_MOUNT_BROKEN_SUID	0x0400	/* 
 #define NFS_MOUNT_NOACL		0x0800	/* 4 */
 #define NFS_MOUNT_STRICTLOCK	0x1000	/* reserved for NFSv4 */
 #define NFS_MOUNT_SECFLAVOUR	0x2000	/* 5 */
+#define NFS_MOUNT_NORDIRPLUS	0x4000	/* 5 */
 #define NFS_MOUNT_FLAGMASK	0xFFFF
 
 #endif
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 16b0266..41afab6 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -21,8 +21,7 @@ #include <asm/atomic.h>
 /*
  * Valid flags for the radix tree
  */
-#define NFS_PAGE_TAG_DIRTY	0
-#define NFS_PAGE_TAG_WRITEBACK	1
+#define NFS_PAGE_TAG_WRITEBACK	0
 
 /*
  * Valid flags for a dirty buffer
@@ -39,7 +38,7 @@ struct nfs_page {
 	struct page		*wb_page;	/* page to read in/write out */
 	struct nfs_open_context	*wb_context;	/* File state context info */
 	atomic_t		wb_complete;	/* i/os we're waiting for */
-	unsigned long		wb_index;	/* Offset >> PAGE_CACHE_SHIFT */
+	pgoff_t			wb_index;	/* Offset >> PAGE_CACHE_SHIFT */
 	unsigned int		wb_offset,	/* Offset & ~PAGE_CACHE_MASK */
 				wb_pgbase,	/* Start of page data */
 				wb_bytes;	/* Length of request */
@@ -48,6 +47,19 @@ struct nfs_page {
 	struct nfs_writeverf	wb_verf;	/* Commit cookie */
 };
 
+struct nfs_pageio_descriptor {
+	struct list_head	pg_list;
+	unsigned long		pg_bytes_written;
+	size_t			pg_count;
+	size_t			pg_bsize;
+	unsigned int		pg_base;
+
+	struct inode		*pg_inode;
+	int			(*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
+	int 			pg_ioflags;
+	int			pg_error;
+};
+
 #define NFS_WBACK_BUSY(req)	(test_bit(PG_BUSY,&(req)->wb_flags))
 
 extern	struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
@@ -59,13 +71,16 @@ extern	void nfs_clear_request(struct nfs
 extern	void nfs_release_request(struct nfs_page *req);
 
 
-extern	long nfs_scan_dirty(struct address_space *mapping,
-				struct writeback_control *wbc,
-				struct list_head *dst);
 extern	int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
-			  unsigned long idx_start, unsigned int npages);
-extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
-				  unsigned int);
+			  pgoff_t idx_start, unsigned int npages);
+extern	void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+			     struct inode *inode,
+			     int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+			     size_t bsize,
+			     int how);
+extern	int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
+				   struct nfs_page *);
+extern	void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
 extern  int nfs_wait_on_request(struct nfs_page *);
 extern	void nfs_unlock_request(struct nfs_page *req);
 extern  int nfs_set_page_writeback_locked(struct nfs_page *req);
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
new file mode 100644
index 0000000..9a30ba2
--- /dev/null
+++ b/include/linux/nl80211.h
@@ -0,0 +1,38 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+	NL80211_IFTYPE_UNSPECIFIED,
+	NL80211_IFTYPE_ADHOC,
+	NL80211_IFTYPE_STATION,
+	NL80211_IFTYPE_AP,
+	NL80211_IFTYPE_AP_VLAN,
+	NL80211_IFTYPE_WDS,
+	NL80211_IFTYPE_MONITOR,
+
+	/* keep last */
+	__NL80211_IFTYPE_AFTER_LAST
+};
+#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1)
+
+#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 0b9f0dc..189e0dc 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -31,10 +31,11 @@ struct nsproxy {
 };
 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);
+int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
+	struct fs_struct *);
 
 static inline void put_nsproxy(struct nsproxy *ns)
 {
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index 870e66a..cdb3e9b 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -28,18 +28,18 @@ enum nubus_category {
 };
 
 enum nubus_type_network {
-	NUBUS_TYPE_ETHERNET 	 = 0x0001,
-	NUBUS_TYPE_RS232    	 = 0x0002
+	NUBUS_TYPE_ETHERNET      = 0x0001,
+	NUBUS_TYPE_RS232         = 0x0002
 };
 
 enum nubus_type_display {
-	NUBUS_TYPE_VIDEO 	 = 0x0001
+	NUBUS_TYPE_VIDEO         = 0x0001
 };
 
 enum nubus_type_cpu {
-	NUBUS_TYPE_68020 	 = 0x0003,
-	NUBUS_TYPE_68030 	 = 0x0004,
-	NUBUS_TYPE_68040 	 = 0x0005
+	NUBUS_TYPE_68020         = 0x0003,
+	NUBUS_TYPE_68030         = 0x0004,
+	NUBUS_TYPE_68040         = 0x0005
 };
 
 /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
@@ -56,6 +56,7 @@ enum nubus_type_cpu {
  *
  *  SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272>
  *  SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271>
+ *  Apple SONIC LC-PDS Ethernet ("Apple Ethernet LC Twisted-Pair Card"): <4,1,0,281>
  *  Sonic Systems Ethernet A-Series Card: <4,1,268,256>
  *  Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision)
  *   ROM on the above card: <2,1,0,0>
@@ -80,24 +81,26 @@ enum nubus_type_cpu {
 /* Add known DrSW values here */
 enum nubus_drsw {
 	/* NUBUS_CAT_DISPLAY */
-	NUBUS_DRSW_APPLE       	= 0x0001,
-	NUBUS_DRSW_APPLE_HIRES 	= 0x0013, /* MacII HiRes card driver */
+	NUBUS_DRSW_APPLE        = 0x0001,
+	NUBUS_DRSW_APPLE_HIRES  = 0x0013, /* MacII HiRes card driver */
 	
 	/* NUBUS_CAT_NETWORK */
-	NUBUS_DRSW_CABLETRON   	= 0x0001,
-	NUBUS_DRSW_SONIC_LC    	= 0x0001,
-	NUBUS_DRSW_KINETICS    	= 0x0103,
-	NUBUS_DRSW_ASANTE      	= 0x0104,
-	NUBUS_DRSW_DAYNA       	= 0x010b,
-	NUBUS_DRSW_FARALLON    	= 0x010c,
-	NUBUS_DRSW_APPLE_SN    	= 0x010f,
-	NUBUS_DRSW_DAYNA2	= 0x0115,
+	NUBUS_DRSW_3COM         = 0x0000,
+	NUBUS_DRSW_CABLETRON    = 0x0001,
+	NUBUS_DRSW_SONIC_LC     = 0x0001,
+	NUBUS_DRSW_KINETICS     = 0x0103,
+	NUBUS_DRSW_ASANTE       = 0x0104,
+	NUBUS_DRSW_TECHWORKS    = 0x0109,
+	NUBUS_DRSW_DAYNA        = 0x010b,
+	NUBUS_DRSW_FARALLON     = 0x010c,
+	NUBUS_DRSW_APPLE_SN     = 0x010f,
+	NUBUS_DRSW_DAYNA2       = 0x0115,
 	NUBUS_DRSW_FOCUS        = 0x011a,
 	NUBUS_DRSW_ASANTE_CS    = 0x011d, /* use asante SMC9194 driver */
-	NUBUS_DRSW_DAYNA_LC	= 0x011e,
+	NUBUS_DRSW_DAYNA_LC     = 0x011e,
 
 	/* NUBUS_CAT_CPU */
-	NUBUS_DRSW_NONE        	= 0x0000,
+	NUBUS_DRSW_NONE         = 0x0000,
 };
 
 /* DrHW: Uniquely identifies the hardware interface to a board (or at
@@ -107,27 +110,48 @@ enum nubus_drsw {
 /* Add known DrHW values here */
 enum nubus_drhw {
 	/* NUBUS_CAT_DISPLAY */
-	NUBUS_DRHW_APPLE_TFB	= 0x0001, /* Toby frame buffer card */
-	NUBUS_DRHW_APPLE_HRVC	= 0x0013, /* Mac II High Res Video card */
-	NUBUS_DRHW_APPLE_RBV1   = 0x0018, /* IIci RBV video */
-	NUBUS_DRHW_APPLE_MDC    = 0x0019, /* Macintosh Display Card */
-	NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
-	NUBUS_DRHW_APPLE_JET 	= 0x0029, /* Jet framebuffer (DuoDock) */
+	NUBUS_DRHW_APPLE_TFB      = 0x0001, /* Toby frame buffer card */
+	NUBUS_DRHW_APPLE_WVC      = 0x0006, /* Apple Workstation Video Card */
+	NUBUS_DRHW_SIGMA_CLRMAX   = 0x0007, /* Sigma Design ColorMax */
+	NUBUS_DRHW_APPLE_SE30     = 0x0009, /* Apple SE/30 video */
+	NUBUS_DRHW_APPLE_HRVC     = 0x0013, /* Mac II High-Res Video Card */
+	NUBUS_DRHW_APPLE_PVC      = 0x0017, /* Mac II Portrait Video Card */
+	NUBUS_DRHW_APPLE_RBV1     = 0x0018, /* IIci RBV video */
+	NUBUS_DRHW_APPLE_MDC      = 0x0019, /* Macintosh Display Card */
+	NUBUS_DRHW_APPLE_SONORA   = 0x0022, /* Sonora built-in video */
+	NUBUS_DRHW_APPLE_24AC     = 0x002b, /* Mac 24AC Video Card */
 	NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
-	NUBUS_DRHW_THUNDER24	= 0x02cb, /* SuperMac Thunder/24 */
+	NUBUS_DRHW_APPLE_JET      = 0x0029, /* Jet framebuffer (DuoDock) */
+	NUBUS_DRHW_SMAC_GFX       = 0x0105, /* SuperMac GFX */
+	NUBUS_DRHW_RASTER_CB264   = 0x013B, /* RasterOps ColorBoard 264 */
+	NUBUS_DRHW_MICRON_XCEED   = 0x0146, /* Micron Exceed color */
+	NUBUS_DRHW_RDIUS_GSC      = 0x0153, /* Radius GS/C */
+	NUBUS_DRHW_SMAC_SPEC8     = 0x017B, /* SuperMac Spectrum/8 */
+	NUBUS_DRHW_SMAC_SPEC24    = 0x017C, /* SuperMac Spectrum/24 */
+	NUBUS_DRHW_RASTER_CB364   = 0x026F, /* RasterOps ColorBoard 364 */
+	NUBUS_DRHW_RDIUS_DCGX     = 0x027C, /* Radius DirectColor/GX */
+	NUBUS_DRHW_RDIUS_PC8      = 0x0291, /* Radius PrecisionColor 8 */
+	NUBUS_DRHW_LAPIS_PCS8     = 0x0292, /* Lapis ProColorServer 8 */
+	NUBUS_DRHW_RASTER_24LXI   = 0x02A0, /* RasterOps 8/24 XLi */
+	NUBUS_DRHW_RASTER_PBPGT   = 0x02A5, /* RasterOps PaintBoard Prism GT */
+	NUBUS_DRHW_EMACH_FSX      = 0x02AE, /* E-Machines Futura SX */
+	NUBUS_DRHW_SMAC_THUND24   = 0x02CB, /* SuperMac Thunder/24 */
+	NUBUS_DRHW_RDIUS_PC24XP   = 0x0406, /* Radius PrecisionColor 24Xp */
+	NUBUS_DRHW_RDIUS_PC24X    = 0x040A, /* Radius PrecisionColor 24X */
+	NUBUS_DRHW_RDIUS_PC8XJ    = 0x040B, /* Radius PrecisionColor 8XJ */
 	
 	/* NUBUS_CAT_NETWORK */
-	NUBUS_DRHW_INTERLAN     = 0x0100,
-	NUBUS_DRHW_SMC9194      = 0x0101,
-	NUBUS_DRHW_KINETICS     = 0x0106,
-	NUBUS_DRHW_CABLETRON    = 0x0109,
-	NUBUS_DRHW_ASANTE_LC    = 0x010f,
-	NUBUS_DRHW_SONIC        = 0x0110,
-	NUBUS_DRHW_SONIC_NB	= 0x0118,
-	NUBUS_DRHW_SONIC_LC	= 0x0119,
-	
-	/* NUBUS_CAT_COMMUNICATIONS */
-	NUBUS_DRHW_DOVEFAX	= 0x0100,
+	NUBUS_DRHW_INTERLAN       = 0x0100,
+	NUBUS_DRHW_SMC9194        = 0x0101,
+	NUBUS_DRHW_KINETICS       = 0x0106,
+	NUBUS_DRHW_CABLETRON      = 0x0109,
+	NUBUS_DRHW_ASANTE_LC      = 0x010f,
+	NUBUS_DRHW_SONIC          = 0x0110,
+	NUBUS_DRHW_TECHWORKS      = 0x0112,
+	NUBUS_DRHW_APPLE_SONIC_NB = 0x0118,
+	NUBUS_DRHW_APPLE_SONIC_LC = 0x0119,
+	NUBUS_DRHW_FOCUS          = 0x011c,
+	NUBUS_DRHW_SONNET         = 0x011d,
 };
 
 /* Resource IDs: These are the identifiers for the various weird and
@@ -153,17 +177,17 @@ enum nubus_res_id {
 
 /* Category-specific resources. */
 enum nubus_board_res_id {
-	NUBUS_RESID_BOARDID	 = 0x0020,
+	NUBUS_RESID_BOARDID      = 0x0020,
 	NUBUS_RESID_PRAMINITDATA = 0x0021,
-	NUBUS_RESID_PRIMARYINIT	 = 0x0022,
+	NUBUS_RESID_PRIMARYINIT  = 0x0022,
 	NUBUS_RESID_TIMEOUTCONST = 0x0023,
-	NUBUS_RESID_VENDORINFO	 = 0x0024,
-	NUBUS_RESID_BOARDFLAGS	 = 0x0025,
-	NUBUS_RESID_SECONDINIT	 = 0x0026,
+	NUBUS_RESID_VENDORINFO   = 0x0024,
+	NUBUS_RESID_BOARDFLAGS   = 0x0025,
+	NUBUS_RESID_SECONDINIT   = 0x0026,
 
 	/* Not sure why Apple put these next two in here */
-	NUBUS_RESID_VIDNAMES 	 = 0x0041,
-	NUBUS_RESID_VIDMODES 	 = 0x007e
+	NUBUS_RESID_VIDNAMES     = 0x0041,
+	NUBUS_RESID_VIDMODES     = 0x007e
 };
 
 /* Fields within the vendor info directory */
@@ -185,13 +209,13 @@ enum nubus_cpu_res_id {
 };
 
 enum nubus_display_res_id {
-	NUBUS_RESID_GAMMADIR	= 0x0040,
-	NUBUS_RESID_FIRSTMODE	= 0x0080,
-	NUBUS_RESID_SECONDMODE	= 0x0081,
-	NUBUS_RESID_THIRDMODE	= 0x0082,
-	NUBUS_RESID_FOURTHMODE	= 0x0083,
-	NUBUS_RESID_FIFTHMODE	= 0x0084,
-	NUBUS_RESID_SIXTHMODE	= 0x0085
+	NUBUS_RESID_GAMMADIR    = 0x0040,
+	NUBUS_RESID_FIRSTMODE   = 0x0080,
+	NUBUS_RESID_SECONDMODE  = 0x0081,
+	NUBUS_RESID_THIRDMODE   = 0x0082,
+	NUBUS_RESID_FOURTHMODE  = 0x0083,
+	NUBUS_RESID_FIFTHMODE   = 0x0084,
+	NUBUS_RESID_SIXTHMODE   = 0x0085
 };
 
 struct nubus_dir
@@ -214,7 +238,7 @@ struct nubus_board {
 	struct nubus_board* next;
 	struct nubus_dev* first_dev;
 	
-        /* Only 9-E actually exist, though 0-8 are also theoretically
+	/* Only 9-E actually exist, though 0-8 are also theoretically
 	   possible, and 0 is a special case which represents the
 	   motherboard and onboard peripherals (Ethernet, video) */
 	int slot;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 9cd0d0e..ae2d79f 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -6,6 +6,7 @@ #ifndef PAGE_FLAGS_H
 #define PAGE_FLAGS_H
 
 #include <linux/types.h>
+#include <linux/mm_types.h>
 
 /*
  * Various page->flags bits:
@@ -82,13 +83,11 @@ #define PG_reserved		10
 #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 */
 #define PG_compound		14	/* Part of a compound page */
 #define PG_swapcache		15	/* Swap page: swp_entry_t in private */
 
 #define PG_mappedtodisk		16	/* Has blocks allocated on-disk */
 #define PG_reclaim		17	/* To be reclaimed asap */
-#define PG_nosave_free		18	/* Used for system suspend/resume */
 #define PG_buddy		19	/* Page is free, on buddy lists */
 
 /* PG_owner_priv_1 users should have descriptive aliases */
@@ -133,7 +132,7 @@ #ifdef CONFIG_S390
 static inline void SetPageUptodate(struct page *page)
 {
 	if (!test_and_set_bit(PG_uptodate, &page->flags))
-		page_test_and_clear_dirty(page);
+		page_clear_dirty(page);
 }
 #else
 #define SetPageUptodate(page)	set_bit(PG_uptodate, &(page)->flags)
@@ -214,16 +213,6 @@ #define TestClearPageWriteback(page)				
 		ret;							\
 	})
 
-#define PageNosave(page)	test_bit(PG_nosave, &(page)->flags)
-#define SetPageNosave(page)	set_bit(PG_nosave, &(page)->flags)
-#define TestSetPageNosave(page)	test_and_set_bit(PG_nosave, &(page)->flags)
-#define ClearPageNosave(page)		clear_bit(PG_nosave, &(page)->flags)
-#define TestClearPageNosave(page)	test_and_clear_bit(PG_nosave, &(page)->flags)
-
-#define PageNosaveFree(page)	test_bit(PG_nosave_free, &(page)->flags)
-#define SetPageNosaveFree(page)	set_bit(PG_nosave_free, &(page)->flags)
-#define ClearPageNosaveFree(page)		clear_bit(PG_nosave_free, &(page)->flags)
-
 #define PageBuddy(page)		test_bit(PG_buddy, &(page)->flags)
 #define __SetPageBuddy(page)	__set_bit(PG_buddy, &(page)->flags)
 #define __ClearPageBuddy(page)	__clear_bit(PG_buddy, &(page)->flags)
@@ -241,6 +230,34 @@ #define PageCompound(page)	test_bit(PG_c
 #define __SetPageCompound(page)	__set_bit(PG_compound, &(page)->flags)
 #define __ClearPageCompound(page) __clear_bit(PG_compound, &(page)->flags)
 
+/*
+ * PG_reclaim is used in combination with PG_compound to mark the
+ * head and tail of a compound page
+ *
+ * PG_compound & PG_reclaim	=> Tail page
+ * PG_compound & ~PG_reclaim	=> Head page
+ */
+
+#define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim))
+
+#define PageTail(page)	((page->flags & PG_head_tail_mask) \
+				== PG_head_tail_mask)
+
+static inline void __SetPageTail(struct page *page)
+{
+	page->flags |= PG_head_tail_mask;
+}
+
+static inline void __ClearPageTail(struct page *page)
+{
+	page->flags &= ~PG_head_tail_mask;
+}
+
+#define PageHead(page)	((page->flags & PG_head_tail_mask) \
+				== (1L << PG_compound))
+#define __SetPageHead(page)	__SetPageCompound(page)
+#define __ClearPageHead(page)	__ClearPageCompound(page)
+
 #ifdef CONFIG_SWAP
 #define PageSwapCache(page)	test_bit(PG_swapcache, &(page)->flags)
 #define SetPageSwapCache(page)	set_bit(PG_swapcache, &(page)->flags)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 7a8dcb8..8a83537 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -11,6 +11,7 @@ #include <linux/highmem.h>
 #include <linux/compiler.h>
 #include <asm/uaccess.h>
 #include <linux/gfp.h>
+#include <linux/bitops.h>
 
 /*
  * Bits in mapping->flags.  The lower __GFP_BITS_SHIFT bits are the page
@@ -19,6 +20,16 @@ #include <linux/gfp.h>
 #define	AS_EIO		(__GFP_BITS_SHIFT + 0)	/* IO error on async write */
 #define AS_ENOSPC	(__GFP_BITS_SHIFT + 1)	/* ENOSPC on async write */
 
+static inline void mapping_set_error(struct address_space *mapping, int error)
+{
+	if (error) {
+		if (error == -ENOSPC)
+			set_bit(AS_ENOSPC, &mapping->flags);
+		else
+			set_bit(AS_EIO, &mapping->flags);
+	}
+}
+
 static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 {
 	return (__force gfp_t)mapping->flags & __GFP_BITS_MASK;
@@ -95,12 +106,23 @@ static inline struct page *grab_cache_pa
 
 extern struct page * grab_cache_page_nowait(struct address_space *mapping,
 				unsigned long index);
+extern struct page * read_cache_page_async(struct address_space *mapping,
+				unsigned long index, filler_t *filler,
+				void *data);
 extern struct page * read_cache_page(struct address_space *mapping,
 				unsigned long index, filler_t *filler,
 				void *data);
 extern int read_cache_pages(struct address_space *mapping,
 		struct list_head *pages, filler_t *filler, void *data);
 
+static inline struct page *read_mapping_page_async(
+						struct address_space *mapping,
+					     unsigned long index, void *data)
+{
+	filler_t *filler = (filler_t *)mapping->a_ops->readpage;
+	return read_cache_page_async(mapping, index, filler, data);
+}
+
 static inline struct page *read_mapping_page(struct address_space *mapping,
 					     unsigned long index, void *data)
 {
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 80682aa..9cdd694 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -279,6 +279,10 @@ struct parport {
 	int dma;
 	int muxport;		/* which muxport (if any) this is */
 	int portnum;		/* which physical parallel port (not mux) */
+	struct device *dev;	/* Physical device associated with IO/DMA.
+				 * This may unfortulately be null if the
+				 * port has a legacy driver.
+				 */
 
 	struct parport *physport;
 				/* If this is a non-default mux
@@ -289,7 +293,7 @@ struct parport {
 				   following structure members are
 				   meaningless: devices, cad, muxsel,
 				   waithead, waittail, flags, pdir,
-				   ieee1284, *_lock.
+				   dev, ieee1284, *_lock.
 
 				   It this is a default mux parport, or
 				   there is no mux involved, this points to
@@ -302,7 +306,7 @@ struct parport {
 
 	struct pardevice *waithead;
 	struct pardevice *waittail;
-	
+
 	struct list_head list;
 	unsigned int flags;
 
diff --git a/include/linux/parport_pc.h b/include/linux/parport_pc.h
index 1cc0f6b..ea8c6d8 100644
--- a/include/linux/parport_pc.h
+++ b/include/linux/parport_pc.h
@@ -38,7 +38,6 @@ struct parport_pc_private {
 	/* buffer suitable for DMA, if DMA enabled */
 	char *dma_buf;
 	dma_addr_t dma_handle;
-	struct pci_dev *dev;
 	struct list_head list;
 	struct parport *port;
 };
@@ -232,7 +231,7 @@ extern int parport_pc_claim_resources(st
 extern struct parport *parport_pc_probe_port (unsigned long base,
 					      unsigned long base_hi,
 					      int irq, int dma,
-					      struct pci_dev *dev);
+					      struct device *dev);
 extern void parport_pc_unregister_port (struct parport *p);
 
 #endif
diff --git a/include/linux/parser.h b/include/linux/parser.h
index fa33328..26b2bdf 100644
--- a/include/linux/parser.h
+++ b/include/linux/parser.h
@@ -11,7 +11,7 @@
 /* associates an integer enumerator with a pattern string. */
 struct match_token {
 	int token;
-	char *pattern;
+	const char *pattern;
 };
 
 typedef struct match_token match_table_t[];
@@ -29,5 +29,5 @@ int match_token(char *, match_table_t ta
 int match_int(substring_t *, int *result);
 int match_octal(substring_t *, int *result);
 int match_hex(substring_t *, int *result);
-void match_strcpy(char *, substring_t *);
-char *match_strdup(substring_t *);
+void match_strcpy(char *, const substring_t *);
+char *match_strdup(const substring_t *);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 481ea06..fbf3766 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -96,6 +96,19 @@ enum pci_channel_state {
 	pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
 };
 
+typedef unsigned int __bitwise pcie_reset_state_t;
+
+enum pcie_reset_state {
+	/* Reset is NOT asserted (Use to deassert reset) */
+	pcie_deassert_reset = (__force pcie_reset_state_t) 1,
+
+	/* Use #PERST to reset PCI-E device */
+	pcie_warm_reset = (__force pcie_reset_state_t) 2,
+
+	/* Use PCI-E Hot Reset to reset device */
+	pcie_hot_reset = (__force pcie_reset_state_t) 3
+};
+
 typedef unsigned short __bitwise pci_bus_flags_t;
 enum pci_bus_flags {
 	PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
@@ -176,10 +189,12 @@ struct pci_dev {
 	int rom_attr_enabled;		/* has display of the rom attribute been enabled? */
 	struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
 #ifdef CONFIG_PCI_MSI
-	unsigned int first_msi_irq;
+	struct list_head msi_list;
 #endif
 };
 
+extern struct pci_dev *alloc_pci_dev(void);
+
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
 #define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
 #define	to_pci_dev(n) container_of(n, struct pci_dev, dev)
@@ -361,8 +376,6 @@ 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)
@@ -394,12 +407,6 @@ #define PCI_DEVICE_CLASS(dev_class,dev_c
 	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
 	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
 
-/*
- * pci_module_init is obsolete, this stays here till we fix up all usages of it
- * in the tree.
- */
-#define pci_module_init	pci_register_driver
-
 /**
  * PCI_VDEVICE - macro used to describe a specific pci device in short form
  * @vend: the vendor name
@@ -534,6 +541,7 @@ static inline int pci_is_managed(struct 
 
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
+int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
 #define HAVE_PCI_SET_MWI
 int __must_check pci_set_mwi(struct pci_dev *dev);
 void pci_clear_mwi(struct pci_dev *dev);
@@ -732,6 +740,9 @@ static inline int pci_set_power_state(st
 static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
 
+static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; }
+static inline void pci_release_regions(struct pci_dev *dev) { }
+
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
 static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
@@ -840,6 +851,7 @@ void __iomem * pcim_iomap(struct pci_dev
 void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
 void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
 int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
 
 extern int pci_pci_problems;
 #define PCIPCI_FAIL		1	/* No PCI PCI DMA */
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index a675a05..ab4cb6e 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -174,7 +174,7 @@ extern int pci_hp_register		(struct hotp
 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;
+extern struct kset pci_hotplug_slots_subsys;
 
 /* PCI Setting Record (Type 0) */
 struct hpp_type0 {
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 600308f..ae849f0 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -368,7 +368,6 @@ #define PCI_DEVICE_ID_ATI_IXP400_IDE	0x4
 #define PCI_DEVICE_ID_ATI_IXP400_SATA   0x4379
 #define PCI_DEVICE_ID_ATI_IXP400_SATA2	0x437a
 #define PCI_DEVICE_ID_ATI_IXP600_SATA	0x4380
-#define PCI_DEVICE_ID_ATI_IXP600_SRAID	0x4381
 #define PCI_DEVICE_ID_ATI_IXP600_SMBUS	0x4385
 #define PCI_DEVICE_ID_ATI_IXP600_IDE	0x438c
 
@@ -1214,11 +1213,13 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_15  
 #define PCI_DEVICE_ID_NVIDIA_NVENET_16              0x03E5
 #define PCI_DEVICE_ID_NVIDIA_NVENET_17              0x03E6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA      0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS	    0x03EB
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE       0x03EC
 #define PCI_DEVICE_ID_NVIDIA_NVENET_18              0x03EE
 #define PCI_DEVICE_ID_NVIDIA_NVENET_19              0x03EF
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2     0x03F6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3     0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS	    0x0446
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE	    0x0448
 #define PCI_DEVICE_ID_NVIDIA_NVENET_20              0x0450
 #define PCI_DEVICE_ID_NVIDIA_NVENET_21              0x0451
@@ -1459,6 +1460,8 @@ #define PCI_DEVICE_ID_TOSHIBA_TOPIC100	0
 
 #define PCI_VENDOR_ID_TOSHIBA_2		0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU	0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939	0x0032
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE	0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC	0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
@@ -1923,6 +1926,7 @@ #define PCI_VENDOR_ID_BROADCOM		0x14e4
 #define PCI_DEVICE_ID_TIGON3_5752	0x1600
 #define PCI_DEVICE_ID_TIGON3_5752M	0x1601
 #define PCI_DEVICE_ID_NX2_5709		0x1639
+#define PCI_DEVICE_ID_NX2_5709S		0x163a
 #define PCI_DEVICE_ID_TIGON3_5700	0x1644
 #define PCI_DEVICE_ID_TIGON3_5701	0x1645
 #define PCI_DEVICE_ID_TIGON3_5702	0x1646
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 600e3d3..b72be2f 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -11,9 +11,16 @@ #include <asm/percpu.h>
 
 /* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */
 #ifndef PERCPU_ENOUGH_ROOM
-#define PERCPU_ENOUGH_ROOM 32768
+#ifdef CONFIG_MODULES
+#define PERCPU_MODULE_RESERVE	8192
+#else
+#define PERCPU_MODULE_RESERVE	0
 #endif
 
+#define PERCPU_ENOUGH_ROOM						\
+	(__per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE)
+#endif	/* PERCPU_ENOUGH_ROOM */
+
 /*
  * Must be an lvalue. Since @var must be a simple identifier,
  * we force a syntax error here if it isn't.
diff --git a/include/linux/phantom.h b/include/linux/phantom.h
new file mode 100644
index 0000000..d3ebbfa
--- /dev/null
+++ b/include/linux/phantom.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (C) 2005-2007 Jiri Slaby <jirislaby@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.
+ */
+
+#ifndef __PHANTOM_H
+#define __PHANTOM_H
+
+#include <asm/types.h>
+
+/* PHN_(G/S)ET_REG param */
+struct phm_reg {
+	__u32 reg;
+	__u32 value;
+};
+
+/* PHN_(G/S)ET_REGS param */
+struct phm_regs {
+	__u32 count;
+	__u32 mask;
+	__u32 values[8];
+};
+
+#define PH_IOC_MAGIC		'p'
+#define PHN_GET_REG		_IOWR(PH_IOC_MAGIC, 0, struct phm_reg *)
+#define PHN_SET_REG		_IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
+#define PHN_GET_REGS		_IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
+#define PHN_SET_REGS		_IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
+#define PH_IOC_MAXNR		3
+
+#define PHN_CONTROL		0x6     /* control byte in iaddr space */
+#define PHN_CTL_AMP		0x1     /*   switch after torques change */
+#define PHN_CTL_BUT		0x2     /*   is button switched */
+#define PHN_CTL_IRQ		0x10    /*   is irq enabled */
+
+#define PHN_ZERO_FORCE		2048	/* zero torque on motor */
+
+#endif
diff --git a/include/linux/phy.h b/include/linux/phy.h
index edd4c88..2a65978 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -55,6 +55,7 @@ typedef enum {
 	PHY_INTERFACE_MODE_TBI,
 	PHY_INTERFACE_MODE_RMII,
 	PHY_INTERFACE_MODE_RGMII,
+	PHY_INTERFACE_MODE_RGMII_ID,
 	PHY_INTERFACE_MODE_RTBI
 } phy_interface_t;
 
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 2833806..169c6c2 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -29,7 +29,7 @@ static inline void get_pid_ns(struct pid
 	kref_get(&ns->kref);
 }
 
-extern int copy_pid_ns(int flags, struct task_struct *tsk);
+extern struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *ns);
 extern void free_pid_ns(struct kref *kref);
 
 static inline void put_pid_ns(struct pid_namespace *ns)
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 21db05a..6e8fa30 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -112,21 +112,25 @@ #define PM_SUSPEND_MAX		((__force suspen
 
 typedef int __bitwise suspend_disk_method_t;
 
-#define	PM_DISK_FIRMWARE	((__force suspend_disk_method_t) 1)
-#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_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)
+/* invalid must be 0 so struct pm_ops initialisers can leave it out */
+#define PM_DISK_INVALID		((__force suspend_disk_method_t) 0)
+#define	PM_DISK_PLATFORM	((__force suspend_disk_method_t) 1)
+#define	PM_DISK_SHUTDOWN	((__force suspend_disk_method_t) 2)
+#define	PM_DISK_REBOOT		((__force suspend_disk_method_t) 3)
+#define	PM_DISK_TEST		((__force suspend_disk_method_t) 4)
+#define	PM_DISK_TESTPROC	((__force suspend_disk_method_t) 5)
+#define	PM_DISK_MAX		((__force suspend_disk_method_t) 6)
 
 /**
  * struct pm_ops - Callbacks for managing platform dependent suspend states.
  * @valid: Callback to determine whether the given state can be entered.
  * 	If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
- *	always valid and never passed to this call.
- *	If not assigned, all suspend states are advertised as valid
- *	in /sys/power/state (but can still be rejected by prepare or enter.)
+ *	always valid and never passed to this call. If not assigned,
+ *	no suspend states are valid.
+ *	Valid states are advertised in /sys/power/state but can still
+ *	be rejected by prepare or enter if the conditions aren't right.
+ *	There is a %pm_valid_only_mem function available that can be assigned
+ *	to this if you only implement mem sleep.
  *
  * @prepare: Prepare the platform for the given suspend state. Can return a
  *	negative error code if necessary.
@@ -137,17 +141,16 @@ #define	PM_DISK_MAX		((__force suspend_d
  * @finish: Called when the system has left the given state and all devices
  *	are resumed. The return value is ignored.
  *
- * @pm_disk_mode: Set to the disk method that the user should be able to
- *	configure for suspend-to-disk. Since %PM_DISK_SHUTDOWN,
- *	%PM_DISK_REBOOT, %PM_DISK_TEST and %PM_DISK_TESTPROC
- *	are always allowed, currently only %PM_DISK_PLATFORM
- *	makes sense. If the user then choses %PM_DISK_PLATFORM,
- *	the @prepare call will be called before suspending to disk
- *	(if present), the @enter call should be present and will
- *	be called after all state has been saved and the machine
- *	is ready to be shut down/suspended/..., and the @finish
- *	callback is called after state has been restored. All
- *	these calls are called with %PM_SUSPEND_DISK as the state.
+ * @pm_disk_mode: The generic code always allows one of the shutdown methods
+ *	%PM_DISK_SHUTDOWN, %PM_DISK_REBOOT, %PM_DISK_TEST and
+ *	%PM_DISK_TESTPROC. If this variable is set, the mode it is set
+ *	to is allowed in addition to those modes and is also made default.
+ *	When this mode is sent selected, the @prepare call will be called
+ *	before suspending to disk (if present), the @enter call should be
+ *	present and will be called after all state has been saved and the
+ *	machine is ready to be powered off; the @finish callback is called
+ *	after state has been restored. All these calls are called with
+ *	%PM_SUSPEND_DISK as the state.
  */
 struct pm_ops {
 	int (*valid)(suspend_state_t state);
@@ -165,6 +168,25 @@ extern void pm_set_ops(struct pm_ops *pm
 extern struct pm_ops *pm_ops;
 extern int pm_suspend(suspend_state_t state);
 
+extern int pm_valid_only_mem(suspend_state_t state);
+
+/**
+ * arch_suspend_disable_irqs - disable IRQs for suspend
+ *
+ * Disables IRQs (in the default case). This is a weak symbol in the common
+ * code and thus allows architectures to override it if more needs to be
+ * done. Not called for suspend to disk.
+ */
+extern void arch_suspend_disable_irqs(void);
+
+/**
+ * arch_suspend_enable_irqs - enable IRQs after suspend
+ *
+ * Enables IRQs (in the default case). This is a weak symbol in the common
+ * code and thus allows architectures to override it if more needs to be
+ * done. Not called for suspend to disk.
+ */
+extern void arch_suspend_enable_irqs(void);
 
 /*
  * Device power management
@@ -273,6 +295,20 @@ #define suspend_report_result(fn, ret)		
 		__suspend_report_result(__FUNCTION__, fn, ret);		\
 	} while (0)
 
+/*
+ * Platform hook to activate device wakeup capability, if that's not already
+ * handled by enable_irq_wake() etc.
+ * Returns zero on success, else negative errno
+ */
+extern int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
+static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
+{
+	if (platform_enable_wakeup)
+		return (*platform_enable_wakeup)(dev, is_on);
+	return 0;
+}
+
 #else /* !CONFIG_PM */
 
 static inline int device_suspend(pm_message_t state)
@@ -294,6 +330,11 @@ static inline void dpm_runtime_resume(st
 
 #define suspend_report_result(fn, ret) do { } while (0)
 
+static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
+{
+	return 0;
+}
+
 #endif
 
 /* changes to device_may_wakeup take effect on the next pm state change.
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 7831773..37ca573 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -168,24 +168,16 @@ #include <linux/list.h>
 
 struct pmu_sleep_notifier
 {
-	int (*notifier_call)(struct pmu_sleep_notifier *self, int when);
+	void (*notifier_call)(struct pmu_sleep_notifier *self, int when);
 	int priority;
 	struct list_head list;
 };
 
 /* Code values for calling sleep/wakeup handlers
- *
- * Note: If a sleep request got cancelled, all drivers will get
- * the PBOOK_SLEEP_REJECT, even those who didn't get the PBOOK_SLEEP_REQUEST.
  */
 #define PBOOK_SLEEP_REQUEST	1
 #define PBOOK_SLEEP_NOW		2
-#define PBOOK_SLEEP_REJECT	3
-#define PBOOK_WAKE		4
-
-/* Result codes returned by the notifiers */
-#define PBOOK_SLEEP_OK		0
-#define PBOOK_SLEEP_REFUSE	-1
+#define PBOOK_WAKE		3
 
 /* priority levels in notifiers */
 #define SLEEP_LEVEL_VIDEO	100	/* Video driver (first wake) */
@@ -233,4 +225,12 @@ extern unsigned int pmu_power_flags;
 /* Backlight */
 extern void pmu_backlight_init(void);
 
+/* some code needs to know if the PMU was suspended for hibernation */
+#ifdef CONFIG_PM
+extern int pmu_sys_suspended;
+#else
+/* if power management is not configured it can't be suspended */
+#define pmu_sys_suspended	0
+#endif
+
 #endif	/* __KERNEL__ */
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 9a5226f..2a1897e 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -177,6 +177,7 @@ static inline void pnp_set_card_drvdata 
 
 struct pnp_dev {
 	struct device dev;		/* Driver Model device interface */
+	u64 dma_mask;
 	unsigned char number;		/* used as an index, must be unique */
 	int status;
 
@@ -363,6 +364,7 @@ int pnp_add_device(struct pnp_dev *dev);
 int pnp_device_attach(struct pnp_dev *pnp_dev);
 void pnp_device_detach(struct pnp_dev *pnp_dev);
 extern struct list_head pnp_global;
+extern int pnp_platform_devices;
 
 /* multidevice card support */
 int pnp_add_card(struct pnp_card *card);
@@ -410,6 +412,7 @@ static inline int pnp_init_device(struct
 static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; }
 static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
 static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; }
+#define pnp_platform_devices 0
 
 /* multidevice card support */
 static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; }
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 3e628f9..d93c300 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -15,8 +15,11 @@ #define LIST_POISON2  ((void *) 0x002002
  * Magic nums for obj red zoning.
  * Placed in the first word before and the first word after an obj.
  */
-#define	RED_INACTIVE	0x5A2CF071UL	/* when obj is inactive */
-#define	RED_ACTIVE	0x170FC2A5UL	/* when obj is active */
+#define	RED_INACTIVE	0x09F911029D74E35BULL	/* when obj is inactive */
+#define	RED_ACTIVE	0xD84156C5635688C0ULL	/* when obj is active */
+
+#define SLUB_RED_INACTIVE	0xbb
+#define SLUB_RED_ACTIVE		0xcc
 
 /* ...and for poisoning */
 #define	POISON_INUSE	0x5a	/* for use-uninitialised poisoning */
@@ -26,9 +29,6 @@ #define	POISON_END	0xa5	/* end-byte of p
 /********** arch/$ARCH/mm/init.c **********/
 #define POISON_FREE_INITMEM	0xcc
 
-/********** arch/x86_64/mm/init.c **********/
-#define	POISON_FREE_INITDATA	0xba
-
 /********** arch/ia64/hp/common/sba_iommu.c **********/
 /*
  * arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index be4652a..3469f96 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -104,6 +104,10 @@ int proc_pid_readdir(struct file * filp,
 unsigned long task_vsize(struct mm_struct *);
 int task_statm(struct mm_struct *, int *, int *, int *, int *);
 char *task_mem(struct mm_struct *, char *);
+void clear_refs_smap(struct mm_struct *mm);
+
+struct proc_dir_entry *de_get(struct proc_dir_entry *de);
+void de_put(struct proc_dir_entry *de);
 
 extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
 						struct proc_dir_entry *parent);
diff --git a/include/linux/quicklist.h b/include/linux/quicklist.h
new file mode 100644
index 0000000..9371c61
--- /dev/null
+++ b/include/linux/quicklist.h
@@ -0,0 +1,94 @@
+#ifndef LINUX_QUICKLIST_H
+#define LINUX_QUICKLIST_H
+/*
+ * Fast allocations and disposal of pages. Pages must be in the condition
+ * as needed after allocation when they are freed. Per cpu lists of pages
+ * are kept that only contain node local pages.
+ *
+ * (C) 2007, SGI. Christoph Lameter <clameter@sgi.com>
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/percpu.h>
+
+#ifdef CONFIG_QUICKLIST
+
+struct quicklist {
+	void *page;
+	int nr_pages;
+};
+
+DECLARE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+
+/*
+ * The two key functions quicklist_alloc and quicklist_free are inline so
+ * that they may be custom compiled for the platform.
+ * Specifying a NULL ctor can remove constructor support. Specifying
+ * a constant quicklist allows the determination of the exact address
+ * in the per cpu area.
+ *
+ * The fast patch in quicklist_alloc touched only a per cpu cacheline and
+ * the first cacheline of the page itself. There is minmal overhead involved.
+ */
+static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *))
+{
+	struct quicklist *q;
+	void **p = NULL;
+
+	q =&get_cpu_var(quicklist)[nr];
+	p = q->page;
+	if (likely(p)) {
+		q->page = p[0];
+		p[0] = NULL;
+		q->nr_pages--;
+	}
+	put_cpu_var(quicklist);
+	if (likely(p))
+		return p;
+
+	p = (void *)__get_free_page(flags | __GFP_ZERO);
+	if (ctor && p)
+		ctor(p);
+	return p;
+}
+
+static inline void __quicklist_free(int nr, void (*dtor)(void *), void *p,
+	struct page *page)
+{
+	struct quicklist *q;
+	int nid = page_to_nid(page);
+
+	if (unlikely(nid != numa_node_id())) {
+		if (dtor)
+			dtor(p);
+		__free_page(page);
+		return;
+	}
+
+	q = &get_cpu_var(quicklist)[nr];
+	*(void **)p = q->page;
+	q->page = p;
+	q->nr_pages++;
+	put_cpu_var(quicklist);
+}
+
+static inline void quicklist_free(int nr, void (*dtor)(void *), void *pp)
+{
+	__quicklist_free(nr, dtor, pp, virt_to_page(pp));
+}
+
+static inline void quicklist_free_page(int nr, void (*dtor)(void *),
+							struct page *page)
+{
+	__quicklist_free(nr, dtor, page_address(page), page);
+}
+
+void quicklist_trim(int nr, void (*dtor)(void *),
+	unsigned long min_pages, unsigned long max_free);
+
+unsigned long quicklist_total_size(void);
+
+#endif
+
+#endif /* LINUX_QUICKLIST_H */
+
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 77db80a..6243982 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -44,8 +44,6 @@ #define __DQUOT_NUM_VERSION__	6*10000+5*
 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
 typedef __u64 qsize_t;          /* Type in which we store sizes */
 
-extern spinlock_t dq_data_lock;
-
 /* Size of blocks in which are counted size limits */
 #define QUOTABLOCK_BITS 10
 #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
@@ -139,6 +137,8 @@ #include <linux/dqblk_xfs.h>
 #include <linux/dqblk_v1.h>
 #include <linux/dqblk_v2.h>
 
+extern spinlock_t dq_data_lock;
+
 /* Maximal numbers of writes for quota operation (insert/delete/update)
  * (over VFS all formats) */
 #define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC)
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 90c23f6..5110201 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -37,9 +37,6 @@ extern int dquot_release(struct dquot *d
 extern int dquot_commit_info(struct super_block *sb, int type);
 extern int dquot_mark_dquot_dirty(struct dquot *dquot);
 
-int remove_inode_dquot_ref(struct inode *inode, int type,
-			   struct list_head *tofree_head);
-
 extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path);
 extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
 		int format_id, int type);
diff --git a/include/linux/reboot_fixups.h b/include/linux/reboot_fixups.h
deleted file mode 100644
index 480ea2d..0000000
--- a/include/linux/reboot_fixups.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _LINUX_REBOOT_FIXUPS_H
-#define _LINUX_REBOOT_FIXUPS_H
-
-#ifdef CONFIG_X86_REBOOTFIXUPS
-extern void mach_reboot_fixups(void);
-#else
-#define mach_reboot_fixups() ((void)(0))
-#endif
-
-#endif /* _LINUX_REBOOT_FIXUPS_H */
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 3a28742..1e5488e 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -401,9 +401,10 @@ struct reiserfs_sb_info {
 	int reserved_blocks;	/* amount of blocks reserved for further allocations */
 	spinlock_t bitmap_lock;	/* this lock on now only used to protect reserved_blocks variable */
 	struct dentry *priv_root;	/* root of /.reiserfs_priv */
+#ifdef CONFIG_REISERFS_FS_XATTR
 	struct dentry *xattr_root;	/* root of /.reiserfs_priv/.xa */
 	struct rw_semaphore xattr_dir_sem;
-
+#endif
 	int j_errno;
 #ifdef CONFIG_QUOTA
 	char *s_qf_names[MAXQUOTAS];
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
new file mode 100644
index 0000000..7c1ffba
--- /dev/null
+++ b/include/linux/rfkill.h
@@ -0,0 +1,89 @@
+#ifndef __RFKILL_H
+#define __RFKILL_H
+
+/*
+ * Copyright (C) 2006 Ivo van Doorn
+ * Copyright (C) 2007 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+/**
+ * enum rfkill_type - type of rfkill switch.
+ * RFKILL_TYPE_WLAN: switch is no a Wireless network devices.
+ * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device.
+ * RFKILL_TYPE_IRDA: switch is on an infrared devices.
+ */
+enum rfkill_type {
+	RFKILL_TYPE_WLAN = 0,
+	RFKILL_TYPE_BLUETOOTH = 1,
+	RFKILL_TYPE_IRDA = 2,
+	RFKILL_TYPE_MAX = 3,
+};
+
+enum rfkill_state {
+	RFKILL_STATE_OFF	= 0,
+	RFKILL_STATE_ON		= 1,
+};
+
+/**
+ * struct rfkill - rfkill control structure.
+ * @name: Name of the switch.
+ * @type: Radio type which the button controls, the value stored
+ *	here should be a value from enum rfkill_type.
+ * @state: State of the switch (on/off).
+ * @user_claim: Set when the switch is controlled exlusively by userspace.
+ * @mutex: Guards switch state transitions
+ * @data: Pointer to the RF button drivers private data which will be
+ *	passed along when toggling radio state.
+ * @toggle_radio(): Mandatory handler to control state of the radio.
+ * @dev: Device structure integrating the switch into device tree.
+ * @node: Used to place switch into list of all switches known to the
+ *	the system.
+ *
+ * This structure represents a RF switch located on a network device.
+ */
+struct rfkill {
+	char *name;
+	enum rfkill_type type;
+
+	enum rfkill_state state;
+	bool user_claim;
+
+	struct mutex mutex;
+
+	void *data;
+	int (*toggle_radio)(void *data, enum rfkill_state state);
+
+	struct device dev;
+	struct list_head node;
+};
+#define to_rfkill(d)	container_of(d, struct rfkill, dev)
+
+struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type);
+void rfkill_free(struct rfkill *rfkill);
+int rfkill_register(struct rfkill *rfkill);
+void rfkill_unregister(struct rfkill *rfkill);
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+
+#endif /* RFKILL_H */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 5e22d45..6d5e4a4 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -4,7 +4,7 @@
  * service. It is used with both the legacy mc146818 and also  EFI
  * Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out
  * from <linux/mc146818rtc.h> to this file for 2.4 kernels.
- * 
+ *
  * Copyright (C) 1999 Hewlett-Packard Co.
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  */
@@ -13,7 +13,7 @@ #define _LINUX_RTC_H_
 
 /*
  * The struct used to pass data via the following ioctl. Similar to the
- * struct tm in <time.h>, but it needs to be here so that the kernel 
+ * struct tm in <time.h>, but it needs to be here so that the kernel
  * source is self contained, allowing cross-compiles, etc. etc.
  */
 
@@ -50,7 +50,7 @@ struct rtc_wkalrm {
  *   pll_value*pll_posmult/pll_clock
  * -ve pll_value means clock will run slower by
  *   pll_value*pll_negmult/pll_clock
- */ 
+ */
 
 struct rtc_pll_info {
 	int pll_ctrl;       /* placeholder for fancier control */
@@ -106,7 +106,6 @@ extern int rtc_year_days(unsigned int da
 extern int rtc_valid_tm(struct rtc_time *tm);
 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
-extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm);
 
 #include <linux/device.h>
 #include <linux/seq_file.h>
@@ -136,7 +135,7 @@ struct rtc_task;
 
 struct rtc_device
 {
-	struct class_device class_dev;
+	struct device dev;
 	struct module *owner;
 
 	int id;
@@ -145,7 +144,6 @@ struct rtc_device
 	const struct rtc_class_ops *ops;
 	struct mutex ops_lock;
 
-	struct class_device *rtc_dev;
 	struct cdev char_dev;
 	struct mutex char_lock;
 
@@ -169,35 +167,34 @@ #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 	unsigned int uie_timer_active:1;
 #endif
 };
-#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
+#define to_rtc_device(d) container_of(d, struct rtc_device, dev)
 
 extern struct rtc_device *rtc_device_register(const char *name,
 					struct device *dev,
 					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);
+extern void rtc_device_unregister(struct rtc_device *rtc);
 
-extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
-extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
-extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
-extern int rtc_read_alarm(struct class_device *class_dev,
+extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
+extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
+extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
+extern int rtc_read_alarm(struct rtc_device *rtc,
 			struct rtc_wkalrm *alrm);
-extern int rtc_set_alarm(struct class_device *class_dev,
+extern int rtc_set_alarm(struct rtc_device *rtc,
 				struct rtc_wkalrm *alrm);
-extern void rtc_update_irq(struct class_device *class_dev,
+extern void rtc_update_irq(struct rtc_device *rtc,
 			unsigned long num, unsigned long events);
 
-extern struct class_device *rtc_class_open(char *name);
-extern void rtc_class_close(struct class_device *class_dev);
+extern struct rtc_device *rtc_class_open(char *name);
+extern void rtc_class_close(struct rtc_device *rtc);
 
-extern int rtc_irq_register(struct class_device *class_dev,
+extern int rtc_irq_register(struct rtc_device *rtc,
 				struct rtc_task *task);
-extern void rtc_irq_unregister(struct class_device *class_dev,
+extern void rtc_irq_unregister(struct rtc_device *rtc,
 				struct rtc_task *task);
-extern int rtc_irq_set_state(struct class_device *class_dev,
+extern int rtc_irq_set_state(struct rtc_device *rtc,
 				struct rtc_task *task, int enabled);
-extern int rtc_irq_set_freq(struct class_device *class_dev,
+extern int rtc_irq_set_freq(struct rtc_device *rtc,
 				struct rtc_task *task, int freq);
 
 typedef struct rtc_task {
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 4a629ea..1fae30a 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -574,13 +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)))
 
-struct rtnetlink_link
-{
-	int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);
-	int (*dumpit)(struct sk_buff *, struct netlink_callback *cb);
-};
-
-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,
@@ -605,7 +598,7 @@ ({	if (unlikely(skb_tailroom(skb) < (int
 
 #define RTA_PUT_NOHDR(skb, attrlen, data) \
 ({	RTA_APPEND(skb, RTA_ALIGN(attrlen), data); \
-	memset(skb->tail - (RTA_ALIGN(attrlen) - attrlen), 0, \
+	memset(skb_tail_pointer(skb) - (RTA_ALIGN(attrlen) - attrlen), 0, \
 	       RTA_ALIGN(attrlen) - attrlen); })
 
 #define RTA_PUT_U8(skb, attrtype, value) \
@@ -637,12 +630,12 @@ #define RTA_PUT_FLAG(skb, attrtype) \
 	RTA_PUT(skb, attrtype, 0, NULL);
 
 #define RTA_NEST(skb, type) \
-({	struct rtattr *__start = (struct rtattr *) (skb)->tail; \
+({	struct rtattr *__start = (struct rtattr *)skb_tail_pointer(skb); \
 	RTA_PUT(skb, type, 0, NULL); \
 	__start;  })
 
 #define RTA_NEST_END(skb, start) \
-({	(start)->rta_len = ((skb)->tail - (unsigned char *) (start)); \
+({	(start)->rta_len = skb_tail_pointer(skb) - (unsigned char *)(start); \
 	(skb)->len; })
 
 #define RTA_NEST_CANCEL(skb, start) \
diff --git a/include/linux/rxrpc.h b/include/linux/rxrpc.h
new file mode 100644
index 0000000..f7b826b
--- /dev/null
+++ b/include/linux/rxrpc.h
@@ -0,0 +1,62 @@
+/* AF_RXRPC parameters
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_H
+#define _LINUX_RXRPC_H
+
+#include <linux/in.h>
+#include <linux/in6.h>
+
+/*
+ * RxRPC socket address
+ */
+struct sockaddr_rxrpc {
+	sa_family_t	srx_family;	/* address family */
+	u16		srx_service;	/* service desired */
+	u16		transport_type;	/* type of transport socket (SOCK_DGRAM) */
+	u16		transport_len;	/* length of transport address */
+	union {
+		sa_family_t family;		/* transport address family */
+		struct sockaddr_in sin;		/* IPv4 transport address */
+		struct sockaddr_in6 sin6;	/* IPv6 transport address */
+	} transport;
+};
+
+/*
+ * RxRPC socket options
+ */
+#define RXRPC_SECURITY_KEY		1	/* [clnt] set client security key */
+#define RXRPC_SECURITY_KEYRING		2	/* [srvr] set ring of server security keys */
+#define RXRPC_EXCLUSIVE_CONNECTION	3	/* [clnt] use exclusive RxRPC connection */
+#define RXRPC_MIN_SECURITY_LEVEL	4	/* minimum security level */
+
+/*
+ * RxRPC control messages
+ * - terminal messages mean that a user call ID tag can be recycled
+ */
+#define RXRPC_USER_CALL_ID	1	/* user call ID specifier */
+#define RXRPC_ABORT		2	/* abort request / notification [terminal] */
+#define RXRPC_ACK		3	/* [Server] RPC op final ACK received [terminal] */
+#define RXRPC_NET_ERROR		5	/* network error received [terminal] */
+#define RXRPC_BUSY		6	/* server busy received [terminal] */
+#define RXRPC_LOCAL_ERROR	7	/* local error generated [terminal] */
+#define RXRPC_NEW_CALL		8	/* [Server] new incoming call notification */
+#define RXRPC_ACCEPT		9	/* [Server] accept request */
+
+/*
+ * RxRPC security levels
+ */
+#define RXRPC_SECURITY_PLAIN	0	/* plain secure-checksummed packets only */
+#define RXRPC_SECURITY_AUTH	1	/* authenticated packets */
+#define RXRPC_SECURITY_ENCRYPT	2	/* encrypted packets */
+
+
+#endif /* _LINUX_RXRPC_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 49fe299..3d95c48 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -194,15 +194,23 @@ extern void sched_init_smp(void);
 extern void init_idle(struct task_struct *idle, int cpu);
 
 extern cpumask_t nohz_cpu_mask;
+#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
+extern int select_nohz_load_balancer(int cpu);
+#else
+static inline int select_nohz_load_balancer(int cpu)
+{
+	return 0;
+}
+#endif
 
 /*
- * Only dump TASK_* tasks. (-1 for all tasks)
+ * Only dump TASK_* tasks. (0 for all tasks)
  */
 extern void show_state_filter(unsigned long state_filter);
 
 static inline void show_state(void)
 {
-	show_state_filter(-1);
+	show_state_filter(0);
 }
 
 extern void show_regs(struct pt_regs *);
@@ -226,6 +234,7 @@ #ifdef CONFIG_DETECT_SOFTLOCKUP
 extern void softlockup_tick(void);
 extern void spawn_softlockup_task(void);
 extern void touch_softlockup_watchdog(void);
+extern void touch_all_softlockup_watchdogs(void);
 #else
 static inline void softlockup_tick(void)
 {
@@ -236,6 +245,9 @@ static inline void spawn_softlockup_task
 static inline void touch_softlockup_watchdog(void)
 {
 }
+static inline void touch_all_softlockup_watchdogs(void)
+{
+}
 #endif
 
 
@@ -668,8 +680,14 @@ struct sched_group {
 	/*
 	 * CPU power of this group, SCHED_LOAD_SCALE being max power for a
 	 * single CPU. This is read only (except for setup, hotplug CPU).
+	 * Note : Never change cpu_power without recompute its reciprocal
+	 */
+	unsigned int __cpu_power;
+	/*
+	 * reciprocal value of cpu_power to avoid expensive divides
+	 * (see include/linux/reciprocal_div.h)
 	 */
-	unsigned long cpu_power;
+	u32 reciprocal_cpu_power;
 };
 
 struct sched_domain {
@@ -801,8 +819,8 @@ struct task_struct {
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	struct thread_info *thread_info;
 	atomic_t usage;
-	unsigned long flags;	/* per process flags, defined below */
-	unsigned long ptrace;
+	unsigned int flags;	/* per process flags, defined below */
+	unsigned int ptrace;
 
 	int lock_depth;		/* BKL lock depth */
 
@@ -825,7 +843,7 @@ #endif
 	unsigned long long sched_time; /* sched_clock time spent running */
 	enum sleep_type sleep_type;
 
-	unsigned long policy;
+	unsigned int policy;
 	cpumask_t cpus_allowed;
 	unsigned int time_slice, first_time_slice;
 
@@ -845,11 +863,11 @@ #endif
 
 /* task state */
 	struct linux_binfmt *binfmt;
-	long exit_state;
+	int exit_state;
 	int exit_code, exit_signal;
 	int pdeath_signal;  /*  The signal sent when the parent dies  */
 	/* ??? */
-	unsigned long personality;
+	unsigned int personality;
 	unsigned did_exec:1;
 	pid_t pid;
 	pid_t tgid;
@@ -881,7 +899,7 @@ #endif
 	int __user *set_child_tid;		/* CLONE_CHILD_SETTID */
 	int __user *clear_child_tid;		/* CLONE_CHILD_CLEARTID */
 
-	unsigned long rt_priority;
+	unsigned int rt_priority;
 	cputime_t utime, stime;
 	unsigned long nvcsw, nivcsw; /* context switch counts */
 	struct timespec start_time;
@@ -1641,10 +1659,7 @@ #endif
 extern long sched_setaffinity(pid_t pid, cpumask_t new_mask);
 extern long sched_getaffinity(pid_t pid, cpumask_t *mask);
 
-#include <linux/sysdev.h>
 extern int sched_mc_power_savings, sched_smt_power_savings;
-extern struct sysdev_attribute attr_sched_mc_power_savings, attr_sched_smt_power_savings;
-extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
 
 extern void normalize_rt_tasks(void);
 
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index d4f8656..d70df61 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -63,6 +63,15 @@ typedef struct sctphdr {
 	__be32 checksum;
 } __attribute__((packed)) sctp_sctphdr_t;
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct sctphdr *sctp_hdr(const struct sk_buff *skb)
+{
+	return (struct sctphdr *)skb_transport_header(skb);
+}
+#endif
+
 /* Section 3.2.  Chunk Field Descriptions. */
 typedef struct sctp_chunkhdr {
 	__u8 type;
diff --git a/include/linux/sdla_fr.h b/include/linux/sdla_fr.h
deleted file mode 100644
index cdfa77f..0000000
--- a/include/linux/sdla_fr.h
+++ /dev/null
@@ -1,638 +0,0 @@
-/*****************************************************************************
-* sdla_fr.h	Sangoma frame relay firmware API definitions.
-*
-* Author:       Gideon Hack  	
-*		Nenad Corbic <ncorbic@sangoma.com> 	
-*
-* Copyright:	(c) 1995-2000 Sangoma Technologies 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.
-* ============================================================================
-* Oct 04, 1999  Gideon Hack     Updated API structures
-* Jun 02, 1999  Gideon Hack 	Modifications for S514 support
-* Oct 12, 1997	Jaspreet Singh	Added FR_READ_DLCI_IB_MAPPING
-* Jul 21, 1997 	Jaspreet Singh	Changed FRRES_TOO_LONG and FRRES_TOO_MANY to 
-*				0x05 and 0x06 respectively.
-* Dec 23, 1996	Gene Kozin	v2.0
-* Apr 29, 1996	Gene Kozin	v1.0 (merged version S502 & S508 definitions).
-* Sep 26, 1995	Gene Kozin	Initial version.
-*****************************************************************************/
-#ifndef	_SDLA_FR_H
-#define	_SDLA_FR_H
-
-/*----------------------------------------------------------------------------
- * Notes:
- * ------
- * 1. All structures defined in this file are byte-alined.  
- *
- *	Compiler	Platform
- *	--------	--------
- *	GNU C		Linux
- */
-
-#ifndef	PACKED
-#    define	PACKED	__attribute__((packed))
-#endif	/* PACKED */
-
-/* Adapter memory layout */
-#define	FR_MB_VECTOR	0xE000	/* mailbox window vector */
-#define	FR502_RX_VECTOR	0xA000	/* S502 direct receive window vector */
-#define	FR502_MBOX_OFFS	0xF60	/* S502 mailbox offset */
-#define	FR508_MBOX_OFFS	0	/* S508 mailbox offset */
-#define	FR502_FLAG_OFFS	0x1FF0	/* S502 status flags offset */
-#define	FR508_FLAG_OFFS	0x1000	/* S508 status flags offset */
-#define	FR502_RXMB_OFFS	0x900	/* S502 direct receive mailbox offset */
-#define	FR508_TXBC_OFFS	0x1100	/* S508 Tx buffer info offset */
-#define	FR508_RXBC_OFFS	0x1120	/* S508 Rx buffer info offset */
-
-/* Important constants */
-#define FR502_MAX_DATA	4096	/* maximum data buffer length */
-#define FR508_MAX_DATA	4080	/* maximum data buffer length */
-#define MIN_LGTH_FR_DATA_CFG         300     /* min Information frame length
-(for configuration purposes) */
-#define FR_MAX_NO_DATA_BYTES_IN_FRAME  15354 	/* max Information frame length */
- 
-#define HIGHEST_VALID_DLCI	991
-
-/****** Data Structures *****************************************************/
-
-/*----------------------------------------------------------------------------
- * Frame relay command block.
- */
-typedef struct fr_cmd
-{
-	unsigned char  command	PACKED;	/* command code */
-	unsigned short length	PACKED;	/* length of data buffer */
-	unsigned char  result	PACKED;	/* return code */
-	unsigned short dlci	PACKED;	/* DLCI number */
-	unsigned char  attr	PACKED;	/* FECN, BECN, DE and C/R bits */
-	unsigned short rxlost1	PACKED;	/* frames discarded at int. level */
-	unsigned long  rxlost2	PACKED;	/* frames discarded at app. level */
-	unsigned char  rsrv[2]	PACKED;	/* reserved for future use */
-} fr_cmd_t;
-
-/* 'command' field defines */
-#define	FR_WRITE		0x01
-#define	FR_READ			0x02
-#define	FR_ISSUE_IS_FRAME	0x03
-#define FR_SET_CONFIG		0x10
-#define FR_READ_CONFIG		0x11
-#define FR_COMM_DISABLE		0x12
-#define FR_COMM_ENABLE		0x13
-#define FR_READ_STATUS		0x14
-#define FR_READ_STATISTICS	0x15
-#define FR_FLUSH_STATISTICS	0x16
-#define	FR_LIST_ACTIVE_DLCI	0x17
-#define FR_FLUSH_DATA_BUFFERS	0x18
-#define FR_READ_ADD_DLC_STATS	0x19
-#define	FR_ADD_DLCI		0x20
-#define	FR_DELETE_DLCI		0x21
-#define	FR_ACTIVATE_DLCI	0x22
-#define	FR_DEACTIVATE_DLCI	0x22
-#define FR_READ_MODEM_STATUS	0x30
-#define FR_SET_MODEM_STATUS	0x31
-#define FR_READ_ERROR_STATS	0x32
-#define FR_FLUSH_ERROR_STATS	0x33
-#define FR_READ_DLCI_IB_MAPPING 0x34
-#define FR_READ_CODE_VERSION	0x40
-#define	FR_SET_INTR_MODE	0x50
-#define	FR_READ_INTR_MODE	0x51
-#define FR_SET_TRACE_CONFIG	0x60
-#define FR_FT1_STATUS_CTRL 	0x80
-#define FR_SET_FT1_MODE		0x81
-
-/* Special UDP drivers management commands */
-#define FPIPE_ENABLE_TRACING          	0x41
-#define FPIPE_DISABLE_TRACING		0x42
-#define FPIPE_GET_TRACE_INFO            0x43
-#define FPIPE_FT1_READ_STATUS           0x44
-#define FPIPE_DRIVER_STAT_IFSEND        0x45
-#define FPIPE_DRIVER_STAT_INTR          0x46
-#define FPIPE_DRIVER_STAT_GEN           0x47
-#define FPIPE_FLUSH_DRIVER_STATS        0x48
-#define FPIPE_ROUTER_UP_TIME            0x49
-
-/* 'result' field defines */
-#define FRRES_OK		0x00	/* command executed successfully */
-#define	FRRES_DISABLED		0x01	/* communications not enabled */
-#define	FRRES_INOPERATIVE	0x02	/* channel inoperative */
-#define	FRRES_DLCI_INACTIVE	0x03	/* DLCI is inactive */
-#define	FRRES_DLCI_INVALID	0x04	/* DLCI is not configured */
-#define	FRRES_TOO_LONG		0x05
-#define	FRRES_TOO_MANY		0x06
-#define	FRRES_CIR_OVERFLOW	0x07	/* Tx throughput has exceeded CIR */
-#define	FRRES_BUFFER_OVERFLOW	0x08
-#define	FRRES_MODEM_FAILURE	0x10	/* DCD and/or CTS dropped */
-#define	FRRES_CHANNEL_DOWN	0x11	/* channel became inoperative */
-#define	FRRES_CHANNEL_UP	0x12	/* channel became operative */
-#define	FRRES_DLCI_CHANGE	0x13	/* DLCI status (or number) changed */
-#define	FRRES_DLCI_MISMATCH	0x14
-#define	FRRES_INVALID_CMD	0x1F	/* invalid command */
-
-/* 'attr' field defines */
-#define	FRATTR_
-
-/*----------------------------------------------------------------------------
- * Frame relay mailbox.
- *	This structure is located at offset FR50?_MBOX_OFFS into FR_MB_VECTOR.
- *	For S502 it is also located at offset FR502_RXMB_OFFS into
- *	FR502_RX_VECTOR.
- */
-typedef struct fr_mbox
-{
-	unsigned char opflag	PACKED;	/* 00h: execution flag */
-	fr_cmd_t cmd		PACKED;	/* 01h: command block */
-	unsigned char data[1]	PACKED;	/* 10h: variable length data buffer */
-} fr_mbox_t;
-
-/*----------------------------------------------------------------------------
- * S502 frame relay status flags.
- *	This structure is located at offset FR502_FLAG_OFFS into FR_MB_VECTOR.
- */
-typedef struct	fr502_flags
-{	
-	unsigned char rsrv1[1]	PACKED;	/* 00h: */
-	unsigned char tx_ready	PACKED;	/* 01h: Tx buffer available */
-	unsigned char rx_ready	PACKED;	/* 02h: Rx frame available */
-	unsigned char event	PACKED;	/* 03h: asynchronous event */
-	unsigned char mstatus	PACKED;	/* 04h: modem status */
-	unsigned char rsrv2[8]	PACKED;	/* 05h: */
-	unsigned char iflag	PACKED;	/* 0Dh: interrupt flag */
-	unsigned char imask	PACKED;	/* 0Eh: interrupt mask */
-} fr502_flags_t;
-
-/*----------------------------------------------------------------------------
- * S508 frame relay status flags.
- *	This structure is located at offset FR508_FLAG_OFFS into FR_MB_VECTOR.
- */
-typedef struct	fr508_flags
-{
-	unsigned char rsrv1[3]	PACKED;	/* 00h: reserved */
-	unsigned char event	PACKED;	/* 03h: asynchronous event */
-	unsigned char mstatus	PACKED;	/* 04h: modem status */
-	unsigned char rsrv2[11]	PACKED;	/* 05h: reserved */
-	unsigned char iflag	PACKED;	/* 10h: interrupt flag */
-	unsigned char imask	PACKED;	/* 11h: interrupt mask */
-	unsigned long tse_offs	PACKED;	/* 12h: Tx status element */
-	unsigned short dlci	PACKED; /* 16h: DLCI NUMBER */
-} fr508_flags_t;
-
-/* 'event' field defines */
-#define	FR_EVENT_STATUS		0x01	/* channel status change */
-#define	FR_EVENT_DLC_STATUS	0x02	/* DLC status change */
-#define	FR_EVENT_BAD_DLCI	0x04	/* FSR included wrong DLCI */
-#define	FR_EVENT_LINK_DOWN	0x40	/* DCD or CTS low */
-
-/* 'mstatus' field defines */
-#define	FR_MDM_DCD		0x08	/* mdm_status: DCD */
-#define	FR_MDM_CTS		0x20	/* mdm_status: CTS */
-
-/* 'iflag' & 'imask' fields defines */
-#define	FR_INTR_RXRDY		0x01	/* Rx ready */
-#define	FR_INTR_TXRDY		0x02	/* Tx ready */
-#define	FR_INTR_MODEM		0x04	/* modem status change (DCD, CTS) */
-#define	FR_INTR_READY		0x08	/* interface command completed */
-#define	FR_INTR_DLC		0x10	/* DLC status change */
-#define	FR_INTR_TIMER		0x20	/* millisecond timer */
-#define FR_INTR_TX_MULT_DLCIs	0x80	/* Tx interrupt on multiple DLCIs */
-
-
-/*----------------------------------------------------------------------------
- * Receive Buffer Configuration Info. S508 only!
- *	This structure is located at offset FR508_RXBC_OFFS into FR_MB_VECTOR.
- */
-typedef struct	fr_buf_info
-{
-	unsigned short rse_num	PACKED;	/* 00h: number of status elements */
-	unsigned long rse_base	PACKED;	/* 02h: receive status array base */
-	unsigned long rse_next	PACKED;	/* 06h: next status element */
-	unsigned long buf_base	PACKED;	/* 0Ah: rotational buffer base */
-	unsigned short reserved	PACKED;	/* 0Eh:  */
-	unsigned long buf_top	PACKED;	/* 10h: rotational buffer top */
-} fr_buf_info_t;
-
-/*----------------------------------------------------------------------------
- * Buffer Status Element. S508 only!
- *	Array of structures of this type is located at offset defined by the
- *	'rse_base' field of the frBufInfo_t structure into absolute adapter
- *	memory address space.
- */
-typedef struct	fr_rx_buf_ctl
-{
-	unsigned char flag	PACKED;	/* 00h: ready flag */
-	unsigned short length	PACKED;	/* 01h: frame length */
-	unsigned short dlci	PACKED;	/* 03h: DLCI */
-	unsigned char attr	PACKED;	/* 05h: FECN/BECN/DE/CR */
-	unsigned short tmstamp	PACKED;	/* 06h: time stamp */
-	unsigned short rsrv[2]	PACKED; /* 08h:  */
-	unsigned long offset	PACKED;	/* 0Ch: buffer absolute address */
-} fr_rx_buf_ctl_t;
-
-typedef struct  fr_tx_buf_ctl
-{
-        unsigned char flag      PACKED; /* 00h: ready flag */
-	unsigned short rsrv0[2]	PACKED;	/* 01h: */
-        unsigned short length   PACKED; /* 05h: frame length */
-        unsigned short dlci     PACKED; /* 07h: DLCI */
-        unsigned char attr      PACKED; /* 09h: FECN/BECN/DE/CR */
-        unsigned short rsrv1 	PACKED; /* 0Ah:  */
-        unsigned long offset    PACKED; /* 0Ch: buffer absolute address */
-} fr_tx_buf_ctl_t;
-
-/*----------------------------------------------------------------------------
- * Global Configuration Block. Passed to FR_SET_CONFIG command when dlci == 0.
- */
-typedef struct	fr_conf
-{
-	unsigned short station	PACKED;	/* 00h: CPE/Node */
-	unsigned short options	PACKED;	/* 02h: configuration options */
-	unsigned short kbps	PACKED;	/* 04h: baud rate in kbps */
-	unsigned short port	PACKED;	/* 06h: RS-232/V.35 */
-	unsigned short mtu	PACKED;	/* 08h: max. transmit length */
-	unsigned short t391	PACKED;	/* 0Ah:  */
-	unsigned short t392	PACKED;	/* 0Ch:  */
-	unsigned short n391	PACKED;	/* 0Eh:  */
-	unsigned short n392	PACKED;	/* 10h:  */
-	unsigned short n393	PACKED;	/* 12h:  */
-	unsigned short cir_fwd	PACKED;	/* 14h:  */
-	unsigned short bc_fwd	PACKED;	/* 16h:  */
-	unsigned short be_fwd	PACKED;	/* 18h:  */
-	unsigned short cir_bwd	PACKED;	/* 1Ah:  */
-	unsigned short bc_bwd	PACKED;	/* 1Ch:  */
-	unsigned short be_bwd	PACKED;	/* 1Eh:  */
-	unsigned short dlci[0]	PACKED;	/* 20h:  */
-} fr_conf_t;
-
-/* 'station_type' defines */
-#define	FRCFG_STATION_CPE	0
-#define	FRCFG_STATION_NODE	1
-
-/* 'conf_flags' defines */
-#define	FRCFG_IGNORE_TX_CIR	0x0001
-#define	FRCFG_IGNORE_RX_CIR	0x0002
-#define	FRCFG_DONT_RETRANSMIT	0x0004
-#define	FRCFG_IGNORE_CBS	0x0008
-#define	FRCFG_THROUGHPUT	0x0010	/* enable throughput calculation */
-#define	FRCFG_DIRECT_RX		0x0080	/* enable direct receive buffer */
-#define	FRCFG_AUTO_CONFIG	0x8000	/* enable  auto DLCI configuration */
-
-/* 'baud_rate' defines */
-#define	FRCFG_BAUD_1200		12
-#define	FRCFG_BAUD_2400		24
-#define	FRCFG_BAUD_4800		48
-#define	FRCFG_BAUD_9600		96
-#define	FRCFG_BAUD_19200	19
-#define	FRCFG_BAUD_38400	38
-#define	FRCFG_BAUD_56000	56
-#define	FRCFG_BAUD_64000	64
-#define	FRCFG_BAUD_128000	128
-
-/* 'port_mode' defines */
-#define	FRCFG_MODE_EXT_CLK	0x0000
-#define	FRCFG_MODE_INT_CLK	0x0001
-#define	FRCFG_MODE_V35		0x0000	/* S508 only */
-#define	FRCFG_MODE_RS232	0x0002	/* S508 only */
-
-/* defines for line tracing */
-
-/* the line trace status element presented by the frame relay code */
-typedef struct {
-        unsigned char flag      PACKED; /* ready flag */
-        unsigned short length   PACKED; /* trace length */
-        unsigned char rsrv0[2]  PACKED; /* reserved */
-        unsigned char attr      PACKED; /* trace attributes */
-        unsigned short tmstamp  PACKED; /* time stamp */
-        unsigned char rsrv1[4]  PACKED; /* reserved */
-        unsigned long offset    PACKED; /* buffer absolute address */
-} fr_trc_el_t;
-
-typedef struct {
-        unsigned char status    	PACKED; /* status flag */
-	unsigned char data_passed	PACKED;	/* 0 if no data passed, 1 if */
-						/* data passed */
-        unsigned short length   	PACKED; /* frame length */
-        unsigned short tmstamp  	PACKED; /* time stamp */
-} fpipemon_trc_hdr_t;
-
-typedef struct {
-	fpipemon_trc_hdr_t fpipemon_trc_hdr			PACKED;
-        unsigned char data[FR_MAX_NO_DATA_BYTES_IN_FRAME]	PACKED;
-} fpipemon_trc_t;
-
-/* bit settings for the 'status' byte  - note that bits 1, 2 and 3 are used */
-/* for returning the number of frames being passed to fpipemon */
-#define TRC_OUTGOING_FRM	0x01
-#define TRC_ABORT_ERROR         0x10
-#define TRC_CRC_ERROR           0x20
-#define TRC_OVERRUN_ERROR       0x40
-#define MORE_TRC_DATA		0x80
-
-#define MAX_FRMS_TRACED		0x07
-
-#define NO_TRC_ELEMENTS_OFF		0x9000
-#define BASE_TRC_ELEMENTS_OFF		0x9002
-#define TRC_ACTIVE			0x01
-#define FLUSH_TRC_BUFFERS 		0x02
-#define FLUSH_TRC_STATISTICS		0x04
-#define TRC_SIGNALLING_FRMS		0x10
-#define TRC_INFO_FRMS			0x20
-#define ACTIVATE_TRC	(TRC_ACTIVE | TRC_SIGNALLING_FRMS | TRC_INFO_FRMS)
-#define RESET_TRC	(FLUSH_TRC_BUFFERS | FLUSH_TRC_STATISTICS)
-
-/*----------------------------------------------------------------------------
- * Channel configuration.
- *	This structure is passed to the FR_SET_CONFIG command when dlci != 0.
- */
-typedef struct	fr_dlc_conf
-{
-	unsigned short conf_flags	PACKED;	/* 00h: configuration bits */
-	unsigned short cir_fwd		PACKED;	/* 02h:  */
-	unsigned short bc_fwd		PACKED;	/* 04h:  */
-	unsigned short be_fwd		PACKED;	/* 06h:  */
-	unsigned short cir_bwd		PACKED;	/* 08h:  */
-	unsigned short bc_bwd		PACKED;	/* 0Ah:  */
-	unsigned short be_bwd		PACKED;	/* 0Ch:  */
-} fr_dlc_conf_t;
-
-/*----------------------------------------------------------------------------
- * S502 interrupt mode control block.
- *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
- *	FR_READ_INTR_FLAGS commands.
- */
-typedef struct fr502_intr_ctl
-{
-	unsigned char mode	PACKED;	/* 00h: interrupt enable flags */
-	unsigned short tx_len	PACKED;	/* 01h: required Tx buffer size */
-} fr502_intr_ctl_t;
-
-/*----------------------------------------------------------------------------
- * S508 interrupt mode control block.
- *	This structure is passed to the FR_SET_INTR_FLAGS and returned by the
- *	FR_READ_INTR_FLAGS commands.
- */
-typedef struct fr508_intr_ctl
-{
-	unsigned char mode	PACKED;	/* 00h: interrupt enable flags */
-	unsigned short tx_len	PACKED;	/* 01h: required Tx buffer size */
-	unsigned char irq	PACKED;	/* 03h: IRQ level to activate */
-	unsigned char flags	PACKED;	/* 04h: ?? */
-	unsigned short timeout	PACKED;	/* 05h: ms, for timer interrupt */
-} fr508_intr_ctl_t;
-
-/*----------------------------------------------------------------------------
- * Channel status.
- *	This structure is returned by the FR_READ_STATUS command.
- */
-typedef struct	fr_dlc_Status
-{
-	unsigned char status		PACKED;	/* 00h: link/DLCI status */
-	struct
-	{
-		unsigned short dlci	PACKED;	/* 01h: DLCI number */
-		unsigned char status	PACKED;	/* 03h: DLCI status */
-	} circuit[1]			PACKED;
-} fr_dlc_status_t;
-
-/* 'status' defines */
-#define	FR_LINK_INOPER	0x00		/* for global status (DLCI == 0) */
-#define	FR_LINK_OPER	0x01
-#define	FR_DLCI_DELETED	0x01		/* for circuit status (DLCI != 0) */
-#define	FR_DLCI_ACTIVE	0x02
-#define	FR_DLCI_WAITING	0x04
-#define	FR_DLCI_NEW	0x08
-#define	FR_DLCI_REPORT	0x40
-
-/*----------------------------------------------------------------------------
- * Global Statistics Block.
- *	This structure is returned by the FR_READ_STATISTICS command when
- *	dcli == 0.
- */
-typedef struct	fr_link_stat
-{
-	unsigned short rx_too_long	PACKED;	/* 00h:  */
-	unsigned short rx_dropped	PACKED;	/* 02h:  */
-	unsigned short rx_dropped2	PACKED;	/* 04h:  */
-	unsigned short rx_bad_dlci	PACKED;	/* 06h:  */
-	unsigned short rx_bad_format	PACKED;	/* 08h:  */
-	unsigned short retransmitted	PACKED;	/* 0Ah:  */
-	unsigned short cpe_tx_FSE	PACKED;	/* 0Ch:  */
-	unsigned short cpe_tx_LIV	PACKED;	/* 0Eh:  */
-	unsigned short cpe_rx_FSR	PACKED;	/* 10h:  */
-	unsigned short cpe_rx_LIV	PACKED;	/* 12h:  */
-	unsigned short node_rx_FSE	PACKED;	/* 14h:  */
-	unsigned short node_rx_LIV	PACKED;	/* 16h:  */
-	unsigned short node_tx_FSR	PACKED;	/* 18h:  */
-	unsigned short node_tx_LIV	PACKED;	/* 1Ah:  */
-	unsigned short rx_ISF_err	PACKED;	/* 1Ch:  */
-	unsigned short rx_unsolicited	PACKED;	/* 1Eh:  */
-	unsigned short rx_SSN_err	PACKED;	/* 20h:  */
-	unsigned short rx_RSN_err	PACKED;	/* 22h:  */
-	unsigned short T391_timeouts	PACKED;	/* 24h:  */
-	unsigned short T392_timeouts	PACKED;	/* 26h:  */
-	unsigned short N392_reached	PACKED;	/* 28h:  */
-	unsigned short cpe_SSN_RSN	PACKED;	/* 2Ah:  */
-	unsigned short current_SSN	PACKED;	/* 2Ch:  */
-	unsigned short current_RSN	PACKED;	/* 2Eh:  */
-	unsigned short curreny_T391	PACKED;	/* 30h:  */
-	unsigned short current_T392	PACKED;	/* 32h:  */
-	unsigned short current_N392	PACKED;	/* 34h:  */
-	unsigned short current_N393	PACKED;	/* 36h:  */
-} fr_link_stat_t;
-
-/*----------------------------------------------------------------------------
- * DLCI statistics.
- *	This structure is returned by the FR_READ_STATISTICS command when
- *	dlci != 0.
- */
-typedef struct	fr_dlci_stat
-{
-	unsigned long tx_frames		PACKED;	/* 00h:  */
-	unsigned long tx_bytes		PACKED;	/* 04h:  */
-	unsigned long rx_frames		PACKED;	/* 08h:  */
-	unsigned long rx_bytes		PACKED;	/* 0Ch:  */
-	unsigned long rx_dropped	PACKED;	/* 10h:  */
-	unsigned long rx_inactive	PACKED;	/* 14h:  */
-	unsigned long rx_exceed_CIR	PACKED;	/* 18h:  */
-	unsigned long rx_DE_set		PACKED;	/* 1Ch:  */
-	unsigned long tx_throughput	PACKED;	/* 20h:  */
-	unsigned long tx_calc_timer	PACKED;	/* 24h:  */
-	unsigned long rx_throughput	PACKED;	/* 28h:  */
-	unsigned long rx_calc_timer	PACKED;	/* 2Ch:  */
-} fr_dlci_stat_t;
-
-/*----------------------------------------------------------------------------
- * Communications error statistics.
- *	This structure is returned by the FR_READ_ERROR_STATS command.
- */
-typedef struct	fr_comm_stat
-{
-	unsigned char rx_overruns	PACKED;	/* 00h:  */
-	unsigned char rx_bad_crc	PACKED;	/* 01h:  */
-	unsigned char rx_aborts		PACKED;	/* 02h:  */
-	unsigned char rx_too_long	PACKED;	/* 03h:  */
-	unsigned char tx_aborts		PACKED;	/* 04h:  */
-	unsigned char tx_underruns	PACKED;	/* 05h:  */
-	unsigned char tx_missed_undr	PACKED;	/* 06h:  */
-	unsigned char dcd_dropped	PACKED;	/* 07h:  */
-	unsigned char cts_dropped	PACKED;	/* 08h:  */
-} fr_comm_stat_t;
-
-/*----------------------------------------------------------------------------
- * Defines for the FR_ISSUE_IS_FRAME command.
- */
-#define	FR_ISF_LVE	2		/* issue Link Verification Enquiry */
-#define	FR_ISF_FSE	3		/* issue Full Status Enquiry */
-
-/*----------------------------------------------------------------------------
- * Frame Relay ARP Header -- Used for Dynamic route creation with InvARP 
- */
-
-typedef struct arphdr_fr
-	{
-	unsigned short ar_hrd PACKED;		/* format of hardware addr */
-	unsigned short ar_pro PACKED;		/* format of protocol addr */
-	unsigned char  ar_hln PACKED;		/* length of hardware addr */	
-	unsigned char  ar_pln PACKED;		/* length of protocol addr */
-	unsigned short ar_op  PACKED;		/* ARP opcode		   */
-	unsigned short ar_sha PACKED;		/* Sender DLCI addr 2 bytes */
-	unsigned long  ar_sip PACKED;		/* Sender IP   addr 4 bytes */
-	unsigned short ar_tha PACKED;		/* Target DLCI addr 2 bytes */
-	unsigned long  ar_tip PACKED;		/* Target IP   addr 4 bytes */
-	} arphdr_fr_t;
-
-/*----------------------------------------------------------------------------
- * Frame Relay RFC 1490 SNAP Header -- Used to check for ARP packets
- */
-typedef struct arphdr_1490
-	{
-	unsigned char control PACKED;		/* UI, etc...  */
-	unsigned char pad     PACKED;		/* Pad */
-	unsigned char NLPID   PACKED;		/* SNAP */
-	unsigned char OUI[3]  PACKED;		/* Ethertype, etc... */
-	unsigned short PID    PACKED;		/* ARP, IP, etc... */
-	}  arphdr_1490_t;
-
-/* UDP/IP packet (for UDP management) layout */
-
-/* The embedded control block for UDP mgmt
-   This is essentially a mailbox structure, without the large data field */
-
-typedef struct {
-        unsigned char  opp_flag PACKED; /* the opp flag */
-        unsigned char  command  PACKED; /* command code */
-        unsigned short length   PACKED; /* length of data buffer */
-        unsigned char  result   PACKED; /* return code */
-        unsigned short dlci     PACKED; /* DLCI number */
-        unsigned char  attr     PACKED; /* FECN, BECN, DE and C/R bits */
-        unsigned short rxlost1  PACKED; /* frames discarded at int. level */
-        unsigned long  rxlost2  PACKED; /* frames discarded at app. level */
-        unsigned char  rsrv[2]  PACKED; /* reserved for future use */
-} cblock_t;
-
-
-/* UDP management packet layout (data area of ip packet) */
-
-typedef struct {
-        unsigned char   control                 PACKED;
-        unsigned char   NLPID                   PACKED;
-} fr_encap_hdr_t;
-
-typedef struct {
-//	fr_encap_hdr_t 		fr_encap_hdr	PACKED;
-	ip_pkt_t 		ip_pkt		PACKED;
-	udp_pkt_t		udp_pkt		PACKED;
-	wp_mgmt_t 		wp_mgmt       	PACKED;
-        cblock_t                cblock          PACKED;
-        unsigned char           data[4080]      PACKED;
-} fr_udp_pkt_t;
-
-
-/* valid ip_protocol for UDP management */
-#define UDPMGMT_UDP_PROTOCOL 0x11
-
-#define UDPMGMT_FPIPE_SIGNATURE         "FPIPE8ND"
-#define UDPMGMT_DRVRSTATS_SIGNATURE     "DRVSTATS"
-
-/* values for request/reply byte */
-#define UDPMGMT_REQUEST	0x01
-#define UDPMGMT_REPLY	0x02
-#define UDP_OFFSET	12
-
-typedef struct {
-        unsigned long if_send_entry;
-        unsigned long if_send_skb_null;
-        unsigned long if_send_broadcast;
-        unsigned long if_send_multicast;
-        unsigned long if_send_critical_ISR;
-        unsigned long if_send_critical_non_ISR;
-        unsigned long if_send_busy;
-        unsigned long if_send_busy_timeout;
-	unsigned long if_send_DRVSTATS_request;
-        unsigned long if_send_FPIPE_request;
-        unsigned long if_send_wan_disconnected;
-        unsigned long if_send_dlci_disconnected;
-        unsigned long if_send_no_bfrs;
-        unsigned long if_send_adptr_bfrs_full;
-        unsigned long if_send_bfrs_passed_to_adptr;
-	unsigned long if_send_consec_send_fail;
-} drvstats_if_send_t; 
-
-typedef struct {
-        unsigned long rx_intr_no_socket;
-        unsigned long rx_intr_dev_not_started;
-        unsigned long rx_intr_DRVSTATS_request;
-        unsigned long rx_intr_FPIPE_request;
-        unsigned long rx_intr_bfr_not_passed_to_stack;
-        unsigned long rx_intr_bfr_passed_to_stack;
- } drvstats_rx_intr_t;
-
-typedef struct {
-        unsigned long UDP_FPIPE_mgmt_kmalloc_err;
-        unsigned long UDP_FPIPE_mgmt_direction_err;
-        unsigned long UDP_FPIPE_mgmt_adptr_type_err;
-        unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK;
-        unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout;
-        unsigned long UDP_FPIPE_mgmt_adptr_send_passed;
-        unsigned long UDP_FPIPE_mgmt_adptr_send_failed;
-        unsigned long UDP_FPIPE_mgmt_not_passed_to_stack;
-        unsigned long UDP_FPIPE_mgmt_passed_to_stack;
-        unsigned long UDP_FPIPE_mgmt_no_socket;
-        unsigned long UDP_DRVSTATS_mgmt_kmalloc_err;
-        unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK;
-        unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout;
-        unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed;
-        unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed;
-        unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack;
-        unsigned long UDP_DRVSTATS_mgmt_passed_to_stack;
-        unsigned long UDP_DRVSTATS_mgmt_no_socket;
-} drvstats_gen_t;
-
-typedef struct {
-        unsigned char   attr      	PACKED;
-        unsigned short  time_stamp      PACKED;
-        unsigned char   reserved[13]    PACKED;
-} api_rx_hdr_t;
-
-typedef struct {
-        api_rx_hdr_t    api_rx_hdr      PACKED;
-        void *          data            PACKED;
-} api_rx_element_t;
-
-typedef struct {
-        unsigned char   attr            PACKED;
-        unsigned char   reserved[15]    PACKED;
-} api_tx_hdr_t;
-
-typedef struct {
-        api_tx_hdr_t    api_tx_hdr      PACKED;
-        void *          data            PACKED;
-} api_tx_element_t;
-
-#ifdef		_MSC_
-#  pragma	pack()
-#endif
-#endif	/* _SDLA_FR_H */
-
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 52c9eb9..26e4925 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -61,10 +61,10 @@ static inline void write_seqlock(seqlock
 {
 	spin_lock(&sl->lock);
 	++sl->sequence;
-	smp_wmb();			
-}	
+	smp_wmb();
+}
 
-static inline void write_sequnlock(seqlock_t *sl) 
+static inline void write_sequnlock(seqlock_t *sl)
 {
 	smp_wmb();
 	sl->sequence++;
@@ -77,7 +77,7 @@ static inline int write_tryseqlock(seqlo
 
 	if (ret) {
 		++sl->sequence;
-		smp_wmb();			
+		smp_wmb();
 	}
 	return ret;
 }
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 586aaba..aa2653a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -39,7 +39,8 @@ #define PORT_16850	12
 #define PORT_RSA	13
 #define PORT_NS16550A	14
 #define PORT_XSCALE	15
-#define PORT_MAX_8250	15	/* max port ID */
+#define PORT_RM9000	16	/* PMC-Sierra RM9xxx internal UART */
+#define PORT_MAX_8250	16	/* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
@@ -135,6 +136,9 @@ #define PORT_S3C2412	73
 /* Xilinx uartlite */
 #define PORT_UARTLITE	74
 
+/* Blackfin bf5xx */
+#define PORT_BFIN	75
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
@@ -230,6 +234,8 @@ #define UPIO_MEM		(2)
 #define UPIO_MEM32		(3)
 #define UPIO_AU			(4)			/* Au1x00 type IO */
 #define UPIO_TSI		(5)			/* Tsi108/109 type IO */
+#define UPIO_DWAPB		(6)			/* DesignWare APB UART */
+#define UPIO_RM9000		(7)			/* RM9000 type IO */
 
 	unsigned int		read_status_mask;	/* driver specific */
 	unsigned int		ignore_status_mask;	/* driver specific */
@@ -260,6 +266,7 @@ #define UPF_MAGIC_MULTIPLIER	((__force u
 #define UPF_CONS_FLOW		((__force upf_t) (1 << 23))
 #define UPF_SHARE_IRQ		((__force upf_t) (1 << 24))
 #define UPF_BOOT_AUTOCONF	((__force upf_t) (1 << 28))
+#define UPF_FIXED_PORT		((__force upf_t) (1 << 29))
 #define UPF_DEAD		((__force upf_t) (1 << 30))
 #define UPF_IOREMAP		((__force upf_t) (1 << 31))
 
@@ -276,6 +283,7 @@ #define UPF_USR_MASK		((__force upf_t) (
 	struct device		*dev;			/* parent device */
 	unsigned char		hub6;			/* this should be in the 8250 driver */
 	unsigned char		unused[3];
+	void			*private_data;		/* generic platform data pointer */
 };
 
 /*
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 3c8a6aa..1c5ed7d 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -38,6 +38,8 @@ #define UART_IIR_THRI		0x02 /* Transmitt
 #define UART_IIR_RDI		0x04 /* Receiver data interrupt */
 #define UART_IIR_RLSI		0x06 /* Receiver line status interrupt */
 
+#define UART_IIR_BUSY		0x07 /* DesignWare APB Busy Detect */
+
 #define UART_FCR	2	/* Out: FIFO Control Register */
 #define UART_FCR_ENABLE_FIFO	0x01 /* Enable the FIFO */
 #define UART_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 5992f65..e7367c7 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -27,20 +27,24 @@ #include <linux/textsearch.h>
 #include <net/checksum.h>
 #include <linux/rcupdate.h>
 #include <linux/dmaengine.h>
+#include <linux/hrtimer.h>
 
 #define HAVE_ALLOC_SKB		/* For the drivers to know */
 #define HAVE_ALIGNABLE_SKB	/* Ditto 8)		   */
 
+/* Don't change this without changing skb_csum_unnecessary! */
 #define CHECKSUM_NONE 0
-#define CHECKSUM_PARTIAL 1
-#define CHECKSUM_UNNECESSARY 2
-#define CHECKSUM_COMPLETE 3
+#define CHECKSUM_UNNECESSARY 1
+#define CHECKSUM_COMPLETE 2
+#define CHECKSUM_PARTIAL 3
 
 #define SKB_DATA_ALIGN(X)	(((X) + (SMP_CACHE_BYTES - 1)) & \
 				 ~(SMP_CACHE_BYTES - 1))
-#define SKB_MAX_ORDER(X, ORDER)	(((PAGE_SIZE << (ORDER)) - (X) - \
-				  sizeof(struct skb_shared_info)) & \
-				  ~(SMP_CACHE_BYTES - 1))
+#define SKB_WITH_OVERHEAD(X)	\
+	(((X) - sizeof(struct skb_shared_info)) & \
+	 ~(SMP_CACHE_BYTES - 1))
+#define SKB_MAX_ORDER(X, ORDER) \
+	SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
 #define SKB_MAX_HEAD(X)		(SKB_MAX_ORDER((X), 0))
 #define SKB_MAX_ALLOC		(SKB_MAX_ORDER(0, 2))
 
@@ -66,8 +70,8 @@ #define SKB_MAX_ALLOC		(SKB_MAX_ORDER(0,
  *	NONE: skb is checksummed by protocol or csum is not required.
  *
  *	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.
+ *	from skb->transport_header to the end and to record the checksum
+ *	at skb->transport_header + skb->csum.
  *
  *	Device must show its capabilities in dev->features, set
  *	at device setup time.
@@ -83,12 +87,13 @@ #define SKB_MAX_ALLOC		(SKB_MAX_ORDER(0,
  */
 
 struct net_device;
+struct scatterlist;
 
-#ifdef CONFIG_NETFILTER
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 struct nf_conntrack {
 	atomic_t use;
-	void (*destroy)(struct nf_conntrack *);
 };
+#endif
 
 #ifdef CONFIG_BRIDGE_NETFILTER
 struct nf_bridge_info {
@@ -103,8 +108,6 @@ #endif
 };
 #endif
 
-#endif
-
 struct sk_buff_head {
 	/* These two members must be first. */
 	struct sk_buff	*next;
@@ -156,11 +159,6 @@ struct skb_shared_info {
 #define SKB_DATAREF_SHIFT 16
 #define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
 
-struct skb_timeval {
-	u32	off_sec;
-	u32	off_usec;
-};
-
 
 enum {
 	SKB_FCLONE_UNAVAILABLE,
@@ -181,6 +179,16 @@ enum {
 	SKB_GSO_TCPV6 = 1 << 4,
 };
 
+#if BITS_PER_LONG > 32
+#define NET_SKBUFF_DATA_USES_OFFSET 1
+#endif
+
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+typedef unsigned int sk_buff_data_t;
+#else
+typedef unsigned char *sk_buff_data_t;
+#endif
+
 /** 
  *	struct sk_buff - socket buffer
  *	@next: Next buffer in list
@@ -189,16 +197,18 @@ enum {
  *	@tstamp: Time we arrived
  *	@dev: Device we arrived on/are leaving by
  *	@iif: ifindex of device we arrived on
- *	@h: Transport layer header
- *	@nh: Network layer header
- *	@mac: Link layer header
+ *	@transport_header: Transport layer header
+ *	@network_header: Network layer header
+ *	@mac_header: Link layer header
  *	@dst: destination entry
  *	@sp: the security path, used for xfrm
  *	@cb: Control buffer. Free for use by every layer. Put private vars here
  *	@len: Length of actual data
  *	@data_len: Data length
  *	@mac_len: Length of link layer header
- *	@csum: Checksum
+ *	@csum: Checksum (must include start/offset pair)
+ *	@csum_start: Offset from skb->head where checksumming should start
+ *	@csum_offset: Offset from csum_start where checksum should be stored
  *	@local_df: allow local fragmentation
  *	@cloned: Head may be cloned (check refcnt to be sure)
  *	@nohdr: Payload reference only, must not modify header
@@ -233,32 +243,11 @@ struct sk_buff {
 	struct sk_buff		*prev;
 
 	struct sock		*sk;
-	struct skb_timeval	tstamp;
+	ktime_t			tstamp;
 	struct net_device	*dev;
 	int			iif;
 	/* 4 byte hole on 64 bit*/
 
-	union {
-		struct tcphdr	*th;
-		struct udphdr	*uh;
-		struct icmphdr	*icmph;
-		struct igmphdr	*igmph;
-		struct iphdr	*ipiph;
-		struct ipv6hdr	*ipv6h;
-		unsigned char	*raw;
-	} h;
-
-	union {
-		struct iphdr	*iph;
-		struct ipv6hdr	*ipv6h;
-		struct arphdr	*arph;
-		unsigned char	*raw;
-	} nh;
-
-	union {
-	  	unsigned char 	*raw;
-	} mac;
-
 	struct  dst_entry	*dst;
 	struct	sec_path	*sp;
 
@@ -275,7 +264,10 @@ struct sk_buff {
 				mac_len;
 	union {
 		__wsum		csum;
-		__u32		csum_offset;
+		struct {
+			__u16	csum_start;
+			__u16	csum_offset;
+		};
 	};
 	__u32			priority;
 	__u8			local_df:1,
@@ -289,15 +281,13 @@ struct sk_buff {
 	__be16			protocol;
 
 	void			(*destructor)(struct sk_buff *skb);
-#ifdef CONFIG_NETFILTER
-	struct nf_conntrack	*nfct;
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	struct nf_conntrack	*nfct;
 	struct sk_buff		*nfct_reasm;
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	struct nf_bridge_info	*nf_bridge;
 #endif
-#endif /* CONFIG_NETFILTER */
 #ifdef CONFIG_NET_SCHED
 	__u16			tc_index;	/* traffic control index */
 #ifdef CONFIG_NET_CLS_ACT
@@ -313,13 +303,16 @@ #endif
 
 	__u32			mark;
 
+	sk_buff_data_t		transport_header;
+	sk_buff_data_t		network_header;
+	sk_buff_data_t		mac_header;
 	/* These elements must be at the end, see alloc_skb() for details.  */
+	sk_buff_data_t		tail;
+	sk_buff_data_t		end;
+	unsigned char		*head,
+				*data;
 	unsigned int		truesize;
 	atomic_t		users;
-	unsigned char		*head,
-				*data,
-				*tail,
-				*end;
 };
 
 #ifdef __KERNEL__
@@ -361,6 +354,11 @@ extern struct sk_buff *skb_realloc_headr
 extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 				       int newheadroom, int newtailroom,
 				       gfp_t priority);
+extern int	       skb_to_sgvec(struct sk_buff *skb,
+				    struct scatterlist *sg, int offset,
+				    int len);
+extern int	       skb_cow_data(struct sk_buff *skb, int tailbits,
+				    struct sk_buff **trailer);
 extern int	       skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)	kfree_skb(a)
 extern void	      skb_over_panic(struct sk_buff *skb, int len,
@@ -402,8 +400,20 @@ extern unsigned int   skb_find_text(stru
 				    unsigned int to, struct ts_config *config,
 				    struct ts_state *state);
 
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
+{
+	return skb->head + skb->end;
+}
+#else
+static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
+{
+	return skb->end;
+}
+#endif
+
 /* Internal */
-#define skb_shinfo(SKB)		((struct skb_shared_info *)((SKB)->end))
+#define skb_shinfo(SKB)	((struct skb_shared_info *)(skb_end_pointer(SKB)))
 
 /**
  *	skb_queue_empty - check if a queue is empty
@@ -822,12 +832,46 @@ #define SKB_PAGE_ASSERT(skb) 	BUG_ON(skb
 #define SKB_FRAG_ASSERT(skb) 	BUG_ON(skb_shinfo(skb)->frag_list)
 #define SKB_LINEAR_ASSERT(skb)  BUG_ON(skb_is_nonlinear(skb))
 
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
+{
+	return skb->head + skb->tail;
+}
+
+static inline void skb_reset_tail_pointer(struct sk_buff *skb)
+{
+	skb->tail = skb->data - skb->head;
+}
+
+static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
+{
+	skb_reset_tail_pointer(skb);
+	skb->tail += offset;
+}
+#else /* NET_SKBUFF_DATA_USES_OFFSET */
+static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
+{
+	return skb->tail;
+}
+
+static inline void skb_reset_tail_pointer(struct sk_buff *skb)
+{
+	skb->tail = skb->data;
+}
+
+static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
+{
+	skb->tail = skb->data + offset;
+}
+
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+
 /*
  *	Add data to an sk_buff
  */
 static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
 {
-	unsigned char *tmp = skb->tail;
+	unsigned char *tmp = skb_tail_pointer(skb);
 	SKB_LINEAR_ASSERT(skb);
 	skb->tail += len;
 	skb->len  += len;
@@ -845,11 +889,11 @@ static inline unsigned char *__skb_put(s
  */
 static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
 {
-	unsigned char *tmp = skb->tail;
+	unsigned char *tmp = skb_tail_pointer(skb);
 	SKB_LINEAR_ASSERT(skb);
 	skb->tail += len;
 	skb->len  += len;
-	if (unlikely(skb->tail>skb->end))
+	if (unlikely(skb->tail > skb->end))
 		skb_over_panic(skb, len, current_text_addr());
 	return tmp;
 }
@@ -962,6 +1006,130 @@ static inline void skb_reserve(struct sk
 	skb->tail += len;
 }
 
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
+{
+	return skb->head + skb->transport_header;
+}
+
+static inline void skb_reset_transport_header(struct sk_buff *skb)
+{
+	skb->transport_header = skb->data - skb->head;
+}
+
+static inline void skb_set_transport_header(struct sk_buff *skb,
+					    const int offset)
+{
+	skb_reset_transport_header(skb);
+	skb->transport_header += offset;
+}
+
+static inline unsigned char *skb_network_header(const struct sk_buff *skb)
+{
+	return skb->head + skb->network_header;
+}
+
+static inline void skb_reset_network_header(struct sk_buff *skb)
+{
+	skb->network_header = skb->data - skb->head;
+}
+
+static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
+{
+	skb_reset_network_header(skb);
+	skb->network_header += offset;
+}
+
+static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
+{
+	return skb->head + skb->mac_header;
+}
+
+static inline int skb_mac_header_was_set(const struct sk_buff *skb)
+{
+	return skb->mac_header != ~0U;
+}
+
+static inline void skb_reset_mac_header(struct sk_buff *skb)
+{
+	skb->mac_header = skb->data - skb->head;
+}
+
+static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
+{
+	skb_reset_mac_header(skb);
+	skb->mac_header += offset;
+}
+
+#else /* NET_SKBUFF_DATA_USES_OFFSET */
+
+static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
+{
+	return skb->transport_header;
+}
+
+static inline void skb_reset_transport_header(struct sk_buff *skb)
+{
+	skb->transport_header = skb->data;
+}
+
+static inline void skb_set_transport_header(struct sk_buff *skb,
+					    const int offset)
+{
+	skb->transport_header = skb->data + offset;
+}
+
+static inline unsigned char *skb_network_header(const struct sk_buff *skb)
+{
+	return skb->network_header;
+}
+
+static inline void skb_reset_network_header(struct sk_buff *skb)
+{
+	skb->network_header = skb->data;
+}
+
+static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
+{
+	skb->network_header = skb->data + offset;
+}
+
+static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
+{
+	return skb->mac_header;
+}
+
+static inline int skb_mac_header_was_set(const struct sk_buff *skb)
+{
+	return skb->mac_header != NULL;
+}
+
+static inline void skb_reset_mac_header(struct sk_buff *skb)
+{
+	skb->mac_header = skb->data;
+}
+
+static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
+{
+	skb->mac_header = skb->data + offset;
+}
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+
+static inline int skb_transport_offset(const struct sk_buff *skb)
+{
+	return skb_transport_header(skb) - skb->data;
+}
+
+static inline u32 skb_network_header_len(const struct sk_buff *skb)
+{
+	return skb->transport_header - skb->network_header;
+}
+
+static inline int skb_network_offset(const struct sk_buff *skb)
+{
+	return skb_network_header(skb) - skb->data;
+}
+
 /*
  * CPUs often take a performance hit when accessing unaligned memory
  * locations. The actual performance hit varies, it can be small if the
@@ -1013,8 +1181,8 @@ static inline void __skb_trim(struct sk_
 		WARN_ON(1);
 		return;
 	}
-	skb->len  = len;
-	skb->tail = skb->data + len;
+	skb->len = len;
+	skb_set_tail_pointer(skb, len);
 }
 
 /**
@@ -1303,6 +1471,11 @@ #define skb_queue_walk(queue, skb) \
 		     prefetch(skb->next), (skb != (struct sk_buff *)(queue));	\
 		     skb = skb->next)
 
+#define skb_queue_walk_safe(queue, skb, tmp)					\
+		for (skb = (queue)->next, tmp = skb->next;			\
+		     skb != (struct sk_buff *)(queue);				\
+		     skb = tmp, tmp = skb->next)
+
 #define skb_queue_reverse_walk(queue, skb) \
 		for (skb = (queue)->prev;					\
 		     prefetch(skb->prev), (skb != (struct sk_buff *)(queue));	\
@@ -1326,8 +1499,8 @@ extern __wsum	       skb_checksum(const 
 				    int len, __wsum csum);
 extern int	       skb_copy_bits(const struct sk_buff *skb, int offset,
 				     void *to, int len);
-extern int	       skb_store_bits(const struct sk_buff *skb, int offset,
-				      void *from, int len);
+extern int	       skb_store_bits(struct sk_buff *skb, int offset,
+				      const void *from, int len);
 extern __wsum	       skb_copy_and_csum_bits(const struct sk_buff *skb,
 					      int offset, u8 *to, int len,
 					      __wsum csum);
@@ -1351,8 +1524,36 @@ static inline void *skb_header_pointer(c
 	return buffer;
 }
 
+static inline void skb_copy_from_linear_data(const struct sk_buff *skb,
+					     void *to,
+					     const unsigned int len)
+{
+	memcpy(to, skb->data, len);
+}
+
+static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb,
+						    const int offset, void *to,
+						    const unsigned int len)
+{
+	memcpy(to, skb->data + offset, len);
+}
+
+static inline void skb_copy_to_linear_data(struct sk_buff *skb,
+					   const void *from,
+					   const unsigned int len)
+{
+	memcpy(skb->data, from, len);
+}
+
+static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
+						  const int offset,
+						  const void *from,
+						  const unsigned int len)
+{
+	memcpy(skb->data + offset, from, len);
+}
+
 extern void skb_init(void);
-extern void skb_add_mtu(int mtu);
 
 /**
  *	skb_get_timestamp - get timestamp from a skb
@@ -1365,29 +1566,28 @@ extern void skb_add_mtu(int mtu);
  */
 static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
 {
-	stamp->tv_sec  = skb->tstamp.off_sec;
-	stamp->tv_usec = skb->tstamp.off_usec;
+	*stamp = ktime_to_timeval(skb->tstamp);
 }
 
-/**
- * 	skb_set_timestamp - set timestamp of a skb
- *	@skb: skb to set stamp of
- *	@stamp: pointer to struct timeval to get stamp from
- *
- *	Timestamps are stored in the skb as offsets to a base timestamp.
- *	This function converts a struct timeval to an offset and stores
- *	it in the skb.
- */
-static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
+static inline void __net_timestamp(struct sk_buff *skb)
+{
+	skb->tstamp = ktime_get_real();
+}
+
+static inline ktime_t net_timedelta(ktime_t t)
 {
-	skb->tstamp.off_sec  = stamp->tv_sec;
-	skb->tstamp.off_usec = stamp->tv_usec;
+	return ktime_sub(ktime_get_real(), t);
 }
 
-extern void __net_timestamp(struct sk_buff *skb);
 
+extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
+static inline int skb_csum_unnecessary(const struct sk_buff *skb)
+{
+	return skb->ip_summed & CHECKSUM_UNNECESSARY;
+}
+
 /**
  *	skb_checksum_complete - Calculate checksum of an entire packet
  *	@skb: packet to process
@@ -1406,22 +1606,22 @@ extern __sum16 __skb_checksum_complete(s
  */
 static inline unsigned int skb_checksum_complete(struct sk_buff *skb)
 {
-	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
-		__skb_checksum_complete(skb);
+	return skb_csum_unnecessary(skb) ?
+	       0 : __skb_checksum_complete(skb);
 }
 
-#ifdef CONFIG_NETFILTER
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+extern void nf_conntrack_destroy(struct nf_conntrack *nfct);
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
 {
 	if (nfct && atomic_dec_and_test(&nfct->use))
-		nfct->destroy(nfct);
+		nf_conntrack_destroy(nfct);
 }
 static inline void nf_conntrack_get(struct nf_conntrack *nfct)
 {
 	if (nfct)
 		atomic_inc(&nfct->use);
 }
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
 {
 	if (skb)
@@ -1447,9 +1647,9 @@ static inline void nf_bridge_get(struct 
 #endif /* CONFIG_BRIDGE_NETFILTER */
 static inline void nf_reset(struct sk_buff *skb)
 {
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	nf_conntrack_put(skb->nfct);
 	skb->nfct = NULL;
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	nf_conntrack_put_reasm(skb->nfct_reasm);
 	skb->nfct_reasm = NULL;
 #endif
@@ -1459,9 +1659,33 @@ #ifdef CONFIG_BRIDGE_NETFILTER
 #endif
 }
 
-#else /* CONFIG_NETFILTER */
-static inline void nf_reset(struct sk_buff *skb) {}
-#endif /* CONFIG_NETFILTER */
+/* Note: This doesn't put any conntrack and bridge info in dst. */
+static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
+{
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	dst->nfct = src->nfct;
+	nf_conntrack_get(src->nfct);
+	dst->nfctinfo = src->nfctinfo;
+	dst->nfct_reasm = src->nfct_reasm;
+	nf_conntrack_get_reasm(src->nfct_reasm);
+#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+	dst->nf_bridge  = src->nf_bridge;
+	nf_bridge_get(src->nf_bridge);
+#endif
+}
+
+static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
+{
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	nf_conntrack_put(dst->nfct);
+	nf_conntrack_put_reasm(dst->nfct_reasm);
+#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+	nf_bridge_put(dst->nf_bridge);
+#endif
+	__nf_copy(dst, src);
+}
 
 #ifdef CONFIG_NETWORK_SECMARK
 static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from)
@@ -1486,5 +1710,12 @@ static inline int skb_is_gso(const struc
 	return skb_shinfo(skb)->gso_size;
 }
 
+static inline void skb_forward_csum(struct sk_buff *skb)
+{
+	/* Unfortunately we don't support this one.  Any brave souls? */
+	if (skb->ip_summed == CHECKSUM_COMPLETE)
+		skb->ip_summed = CHECKSUM_NONE;
+}
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SKBUFF_H */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 1ef822e..71829ef 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -21,28 +21,25 @@ typedef struct kmem_cache kmem_cache_t _
  * The ones marked DEBUG are only valid if CONFIG_SLAB_DEBUG is set.
  */
 #define SLAB_DEBUG_FREE		0x00000100UL	/* DEBUG: Perform (expensive) checks on free */
-#define SLAB_DEBUG_INITIAL	0x00000200UL	/* DEBUG: Call constructor (as verifier) */
 #define SLAB_RED_ZONE		0x00000400UL	/* DEBUG: Red zone objs in a cache */
 #define SLAB_POISON		0x00000800UL	/* DEBUG: Poison objects */
 #define SLAB_HWCACHE_ALIGN	0x00002000UL	/* Align objs on cache lines */
 #define SLAB_CACHE_DMA		0x00004000UL	/* Use GFP_DMA memory */
-#define SLAB_MUST_HWCACHE_ALIGN	0x00008000UL	/* Force alignment even if debuggin is active */
 #define SLAB_STORE_USER		0x00010000UL	/* DEBUG: Store the last owner for bug hunting */
 #define SLAB_RECLAIM_ACCOUNT	0x00020000UL	/* Objects are reclaimable */
 #define SLAB_PANIC		0x00040000UL	/* Panic if kmem_cache_create() fails */
 #define SLAB_DESTROY_BY_RCU	0x00080000UL	/* Defer freeing slabs to RCU */
 #define SLAB_MEM_SPREAD		0x00100000UL	/* Spread some memory over cpuset */
+#define SLAB_TRACE		0x00200000UL	/* Trace allocations and frees */
 
 /* Flags passed to a constructor functions */
 #define SLAB_CTOR_CONSTRUCTOR	0x001UL		/* If not set, then deconstructor */
-#define SLAB_CTOR_ATOMIC	0x002UL		/* Tell constructor it can't sleep */
-#define SLAB_CTOR_VERIFY	0x004UL		/* Tell constructor it's a verify call */
 
 /*
  * struct kmem_cache related prototypes
  */
 void __init kmem_cache_init(void);
-extern int slab_is_available(void);
+int slab_is_available(void);
 
 struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
 			unsigned long,
@@ -57,6 +54,18 @@ unsigned int kmem_cache_size(struct kmem
 const char *kmem_cache_name(struct kmem_cache *);
 int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
 
+/*
+ * Please use this macro to create slab caches. Simply specify the
+ * name of the structure and maybe some flags that are listed above.
+ *
+ * The alignment of the struct determines object alignment. If you
+ * f.e. add ____cacheline_aligned_in_smp to the struct declaration
+ * then the objects will be properly aligned in SMP configurations.
+ */
+#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
+		sizeof(struct __struct), __alignof__(struct __struct),\
+		(__flags), NULL, NULL)
+
 #ifdef CONFIG_NUMA
 extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
 #else
@@ -72,8 +81,9 @@ #endif
  */
 void *__kmalloc(size_t, gfp_t);
 void *__kzalloc(size_t, gfp_t);
+void * __must_check krealloc(const void *, size_t, gfp_t);
 void kfree(const void *);
-unsigned int ksize(const void *);
+size_t ksize(const void *);
 
 /**
  * kcalloc - allocate memory for an array. The memory is set to zero.
@@ -94,9 +104,14 @@ static inline void *kcalloc(size_t n, si
  * the appropriate general cache at compile time.
  */
 
-#ifdef CONFIG_SLAB
+#if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
+#ifdef CONFIG_SLUB
+#include <linux/slub_def.h>
+#else
 #include <linux/slab_def.h>
+#endif /* !CONFIG_SLUB */
 #else
+
 /*
  * Fallback definitions for an allocator not wanting to provide
  * its own optimized kmalloc definitions (like SLOB).
@@ -183,7 +198,7 @@ #endif /* !CONFIG_NUMA */
  * allocator where we care about the real place the memory allocation
  * request comes from.
  */
-#ifdef CONFIG_DEBUG_SLAB
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
 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))
@@ -201,7 +216,7 @@ #ifdef CONFIG_NUMA
  * standard allocator where we care about the real place the memory
  * allocation request comes from.
  */
-#ifdef CONFIG_DEBUG_SLAB
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
 extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
 #define kmalloc_node_track_caller(size, flags, node) \
 	__kmalloc_node_track_caller(size, flags, node, \
@@ -218,6 +233,9 @@ #define kmalloc_node_track_caller(size, 
 
 #endif /* DEBUG_SLAB */
 
+extern const struct seq_operations slabinfo_op;
+ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SLAB_H */
 
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
new file mode 100644
index 0000000..ea27065
--- /dev/null
+++ b/include/linux/slub_def.h
@@ -0,0 +1,206 @@
+#ifndef _LINUX_SLUB_DEF_H
+#define _LINUX_SLUB_DEF_H
+
+/*
+ * SLUB : A Slab allocator without object queues.
+ *
+ * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+
+struct kmem_cache_node {
+	spinlock_t list_lock;	/* Protect partial list and nr_partial */
+	unsigned long nr_partial;
+	atomic_long_t nr_slabs;
+	struct list_head partial;
+	struct list_head full;
+};
+
+/*
+ * Slab cache management.
+ */
+struct kmem_cache {
+	/* Used for retriving partial slabs etc */
+	unsigned long flags;
+	int size;		/* The size of an object including meta data */
+	int objsize;		/* The size of an object without meta data */
+	int offset;		/* Free pointer offset. */
+	unsigned int order;
+
+	/*
+	 * Avoid an extra cache line for UP, SMP and for the node local to
+	 * struct kmem_cache.
+	 */
+	struct kmem_cache_node local_node;
+
+	/* Allocation and freeing of slabs */
+	int objects;		/* Number of objects in slab */
+	int refcount;		/* Refcount for slab cache destroy */
+	void (*ctor)(void *, struct kmem_cache *, unsigned long);
+	void (*dtor)(void *, struct kmem_cache *, unsigned long);
+	int inuse;		/* Offset to metadata */
+	int align;		/* Alignment */
+	const char *name;	/* Name (only for display!) */
+	struct list_head list;	/* List of slab caches */
+	struct kobject kobj;	/* For sysfs */
+
+#ifdef CONFIG_NUMA
+	int defrag_ratio;
+	struct kmem_cache_node *node[MAX_NUMNODES];
+#endif
+	struct page *cpu_slab[NR_CPUS];
+};
+
+/*
+ * Kmalloc subsystem.
+ */
+#define KMALLOC_SHIFT_LOW 3
+
+#ifdef CONFIG_LARGE_ALLOCS
+#define KMALLOC_SHIFT_HIGH 25
+#else
+#if !defined(CONFIG_MMU) || NR_CPUS > 512 || MAX_NUMNODES > 256
+#define KMALLOC_SHIFT_HIGH 20
+#else
+#define KMALLOC_SHIFT_HIGH 18
+#endif
+#endif
+
+/*
+ * We keep the general caches in an array of slab caches that are used for
+ * 2^x bytes of allocations.
+ */
+extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
+
+/*
+ * Sorry that the following has to be that ugly but some versions of GCC
+ * have trouble with constant propagation and loops.
+ */
+static inline int kmalloc_index(int size)
+{
+	/*
+	 * We should return 0 if size == 0 but we use the smallest object
+	 * here for SLAB legacy reasons.
+	 */
+	WARN_ON_ONCE(size == 0);
+
+	if (size > 64 && size <= 96)
+		return 1;
+	if (size > 128 && size <= 192)
+		return 2;
+	if (size <=          8) return 3;
+	if (size <=         16) return 4;
+	if (size <=         32) return 5;
+	if (size <=         64) return 6;
+	if (size <=        128) return 7;
+	if (size <=        256) return 8;
+	if (size <=        512) return 9;
+	if (size <=       1024) return 10;
+	if (size <=   2 * 1024) return 11;
+	if (size <=   4 * 1024) return 12;
+	if (size <=   8 * 1024) return 13;
+	if (size <=  16 * 1024) return 14;
+	if (size <=  32 * 1024) return 15;
+	if (size <=  64 * 1024) return 16;
+	if (size <= 128 * 1024) return 17;
+	if (size <= 256 * 1024) return 18;
+#if KMALLOC_SHIFT_HIGH > 18
+	if (size <=  512 * 1024) return 19;
+	if (size <= 1024 * 1024) return 20;
+#endif
+#if KMALLOC_SHIFT_HIGH > 20
+	if (size <=  2 * 1024 * 1024) return 21;
+	if (size <=  4 * 1024 * 1024) return 22;
+	if (size <=  8 * 1024 * 1024) return 23;
+	if (size <= 16 * 1024 * 1024) return 24;
+	if (size <= 32 * 1024 * 1024) return 25;
+#endif
+	return -1;
+
+/*
+ * What we really wanted to do and cannot do because of compiler issues is:
+ *	int i;
+ *	for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+ *		if (size <= (1 << i))
+ *			return i;
+ */
+}
+
+/*
+ * Find the slab cache for a given combination of allocation flags and size.
+ *
+ * This ought to end up with a global pointer to the right cache
+ * in kmalloc_caches.
+ */
+static inline struct kmem_cache *kmalloc_slab(size_t size)
+{
+	int index = kmalloc_index(size);
+
+	if (index == 0)
+		return NULL;
+
+	if (index < 0) {
+		/*
+		 * Generate a link failure. Would be great if we could
+		 * do something to stop the compile here.
+		 */
+		extern void __kmalloc_size_too_large(void);
+		__kmalloc_size_too_large();
+	}
+	return &kmalloc_caches[index];
+}
+
+#ifdef CONFIG_ZONE_DMA
+#define SLUB_DMA __GFP_DMA
+#else
+/* Disable DMA functionality */
+#define SLUB_DMA 0
+#endif
+
+static inline void *kmalloc(size_t size, gfp_t flags)
+{
+	if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
+		struct kmem_cache *s = kmalloc_slab(size);
+
+		if (!s)
+			return NULL;
+
+		return kmem_cache_alloc(s, flags);
+	} else
+		return __kmalloc(size, flags);
+}
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+	if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
+		struct kmem_cache *s = kmalloc_slab(size);
+
+		if (!s)
+			return NULL;
+
+		return kmem_cache_zalloc(s, flags);
+	} else
+		return __kzalloc(size, flags);
+}
+
+#ifdef CONFIG_NUMA
+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) && !(flags & SLUB_DMA)) {
+		struct kmem_cache *s = kmalloc_slab(size);
+
+		if (!s)
+			return NULL;
+
+		return kmem_cache_alloc_node(s, flags, node);
+	} else
+		return __kmalloc_node(size, flags, node);
+}
+#endif
+
+#endif /* _LINUX_SLUB_DEF_H */
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 854aa6b..802b3a3 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -40,6 +40,8 @@ enum
 	IPSTATS_MIB_FRAGCREATES,		/* FragCreates */
 	IPSTATS_MIB_INMCASTPKTS,		/* InMcastPkts */
 	IPSTATS_MIB_OUTMCASTPKTS,		/* OutMcastPkts */
+	IPSTATS_MIB_INBCASTPKTS,		/* InBcastPkts */
+	IPSTATS_MIB_OUTBCASTPKTS,		/* OutBcastPkts */
 	__IPSTATS_MIB_MAX
 };
 
diff --git a/include/linux/socket.h b/include/linux/socket.h
index fcd35a2..6e7c948 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -188,7 +188,8 @@ #define AF_LLC		26	/* Linux LLC			*/
 #define AF_TIPC		30	/* TIPC sockets			*/
 #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
 #define AF_IUCV		32	/* IUCV sockets			*/
-#define AF_MAX		33	/* For now.. */
+#define AF_RXRPC	33	/* RxRPC sockets 		*/
+#define AF_MAX		34	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -222,6 +223,7 @@ #define PF_LLC		AF_LLC
 #define PF_TIPC		AF_TIPC
 #define PF_BLUETOOTH	AF_BLUETOOTH
 #define PF_IUCV		AF_IUCV
+#define PF_RXRPC	AF_RXRPC
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -284,6 +286,7 @@ #define SOL_LLC		268
 #define SOL_DCCP	269
 #define SOL_NETLINK	270
 #define SOL_TIPC	271
+#define SOL_RXRPC	272
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/include/linux/sony-laptop.h b/include/linux/sony-laptop.h
new file mode 100644
index 0000000..e2e036d
--- /dev/null
+++ b/include/linux/sony-laptop.h
@@ -0,0 +1,34 @@
+#ifndef _SONYLAPTOP_H_
+#define _SONYLAPTOP_H_
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+/* used only for communication between v4l and sony-laptop */
+
+#define SONY_PIC_COMMAND_GETCAMERA		 1	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERA		 2
+#define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS	 3	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS	 4
+#define SONY_PIC_COMMAND_GETCAMERACONTRAST	 5	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST	 6
+#define SONY_PIC_COMMAND_GETCAMERAHUE		 7	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAHUE		 8
+#define SONY_PIC_COMMAND_GETCAMERACOLOR		 9	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACOLOR		10
+#define SONY_PIC_COMMAND_GETCAMERASHARPNESS	11	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS	12
+#define SONY_PIC_COMMAND_GETCAMERAPICTURE	13	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE	14
+#define SONY_PIC_COMMAND_GETCAMERAAGC		15	/* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAAGC		16
+#define SONY_PIC_COMMAND_GETCAMERADIRECTION	17	/* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAROMVERSION	18	/* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAREVISION	19	/* obsolete */
+
+int sony_pic_camera_command(int command, u8 value);
+
+#endif	/* __KERNEL__ */
+
+#endif /* _SONYLAPTOP_H_ */
diff --git a/include/linux/spi/Kbuild b/include/linux/spi/Kbuild
new file mode 100644
index 0000000..d375a08
--- /dev/null
+++ b/include/linux/spi/Kbuild
@@ -0,0 +1 @@
+header-y += spidev.h
diff --git a/include/linux/spi/ad7877.h b/include/linux/spi/ad7877.h
new file mode 100644
index 0000000..cdbed81
--- /dev/null
+++ b/include/linux/spi/ad7877.h
@@ -0,0 +1,24 @@
+/* linux/spi/ad7877.h */
+
+/* Touchscreen characteristics vary between boards and models.  The
+ * platform_data for the device's "struct device" holds this information.
+ *
+ * It's OK if the min/max values are zero.
+ */
+struct ad7877_platform_data {
+	u16	model;			/* 7877 */
+	u16	vref_delay_usecs;	/* 0 for external vref; etc */
+	u16	x_plate_ohms;
+	u16	y_plate_ohms;
+
+	u16	x_min, x_max;
+	u16	y_min, y_max;
+	u16	pressure_min, pressure_max;
+
+	u8	stopacq_polarity;	/* 1 = Active HIGH, 0 = Active LOW */
+	u8	first_conversion_delay;	/* 0 = 0.5us, 1 = 128us, 2 = 1ms, 3 = 8ms */
+	u8	acquisition_time;	/* 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */
+	u8	averaging;		/* 0 = 1, 1 = 4, 2 = 8, 3 = 16 */
+	u8	pen_down_acc_interval;	/* 0 = covert once, 1 = every 0.5 ms,
+					   2 = ever 1 ms,   3 = every 8 ms,*/
+};
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4f0f8c2..b6bedc3 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -32,11 +32,12 @@ extern struct bus_type spi_bus_type;
  * @max_speed_hz: Maximum clock rate to be used with this chip
  *	(on this board); may be changed by the device's driver.
  *	The spi_transfer.speed_hz can override this for each transfer.
- * @chip-select: Chipselect, distinguishing chips handled by "master".
+ * @chip_select: Chipselect, distinguishing chips handled by @master.
  * @mode: The spi mode defines how data is clocked out and in.
  *	This may be changed by the device's driver.
- *	The "active low" default for chipselect mode can be overridden,
- *	as can the "MSB first" default for each word in a transfer.
+ *	The "active low" default for chipselect mode can be overridden
+ *	(by specifying SPI_CS_HIGH) as can the "MSB first" default for
+ *	each word in a transfer (by specifying SPI_LSB_FIRST).
  * @bits_per_word: Data transfers involve one or more words; word sizes
  *	like eight or 12 bits are common.  In-memory wordsizes are
  *	powers of two bytes (e.g. 20 bit samples use 32 bits).
@@ -48,14 +49,18 @@ extern struct bus_type spi_bus_type;
  * @controller_state: Controller's runtime state
  * @controller_data: Board-specific definitions for controller, such as
  *	FIFO initialization parameters; from board_info.controller_data
+ * @modalias: Name of the driver to use with this device, or an alias
+ *	for that name.  This appears in the sysfs "modalias" attribute
+ *	for driver coldplugging, and in uevents used for hotplugging
  *
- * An spi_device is used to interchange data between an SPI slave
+ * A @spi_device is used to interchange data between an SPI slave
  * (usually a discrete chip) and CPU memory.
  *
- * In "dev", the platform_data is used to hold information about this
+ * In @dev, the platform_data is used to hold information about this
  * device that's meaningful to the device's protocol driver, but not
  * to its controller.  One example might be an identifier for a chip
- * variant with slightly different functionality.
+ * variant with slightly different functionality; another might be
+ * information about how this particular board wires the chip's pins.
  */
 struct spi_device {
 	struct device		dev;
@@ -77,13 +82,15 @@ #define	SPI_LSB_FIRST	0x08			/* per-word
 	void			*controller_data;
 	const char		*modalias;
 
-	// likely need more hooks for more protocol options affecting how
-	// the controller talks to each chip, like:
-	//  - memory packing (12 bit samples into low bits, others zeroed)
-	//  - priority
-	//  - drop chipselect after each word
-	//  - chipselect delays
-	//  - ...
+	/*
+	 * likely need more hooks for more protocol options affecting how
+	 * the controller talks to each chip, like:
+	 *  - memory packing (12 bit samples into low bits, others zeroed)
+	 *  - priority
+	 *  - drop chipselect after each word
+	 *  - chipselect delays
+	 *  - ...
+	 */
 };
 
 static inline struct spi_device *to_spi_device(struct device *dev)
@@ -146,6 +153,11 @@ static inline struct spi_driver *to_spi_
 
 extern int spi_register_driver(struct spi_driver *sdrv);
 
+/**
+ * spi_unregister_driver - reverse effect of spi_register_driver
+ * @sdrv: the driver to unregister
+ * Context: can sleep
+ */
 static inline void spi_unregister_driver(struct spi_driver *sdrv)
 {
 	if (sdrv)
@@ -165,18 +177,20 @@ static inline void spi_unregister_driver
  * @setup: updates the device mode and clocking records used by a
  *	device's SPI controller; protocol code may call this.  This
  *	must fail if an unrecognized or unsupported mode is requested.
+ *	It's always safe to call this unless transfers are pending on
+ *	the device whose settings are being modified.
  * @transfer: adds a message to the controller's transfer queue.
  * @cleanup: frees controller-specific state
  *
- * Each SPI master controller can communicate with one or more spi_device
+ * Each SPI master controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
  * but not chip select signals.  Each device may be configured to use a
  * different clock rate, since those shared signals are ignored unless
  * the chip is selected.
  *
  * The driver for an SPI controller manages access to those devices through
- * a queue of spi_message transactions, copyin data between CPU memory and
- * an SPI slave device).  For each such message it queues, it calls the
+ * a queue of spi_message transactions, copying data between CPU memory and
+ * an SPI slave device.  For each such message it queues, it calls the
  * message's completion function when the transaction completes.
  */
 struct spi_master {
@@ -280,27 +294,27 @@ extern struct spi_master *spi_busnum_to_
  * struct spi_transfer - a read/write buffer pair
  * @tx_buf: data to be written (dma-safe memory), or NULL
  * @rx_buf: data to be read (dma-safe memory), or NULL
- * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped
- * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
+ * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
+ * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
  * @len: size of rx and tx buffers (in bytes)
  * @speed_hz: Select a speed other then the device default for this
- *      transfer. If 0 the default (from spi_device) is used.
+ *      transfer. If 0 the default (from @spi_device) is used.
  * @bits_per_word: select a bits_per_word other then the device default
- *      for this transfer. If 0 the default (from spi_device) is used.
+ *      for this transfer. If 0 the default (from @spi_device) is used.
  * @cs_change: affects chipselect after this transfer completes
  * @delay_usecs: microseconds to delay after this transfer before
  *	(optionally) changing the chipselect status, then starting
- *	the next transfer or completing this spi_message.
- * @transfer_list: transfers are sequenced through spi_message.transfers
+ *	the next transfer or completing this @spi_message.
+ * @transfer_list: transfers are sequenced through @spi_message.transfers
  *
  * SPI transfers always write the same number of bytes as they read.
- * Protocol drivers should always provide rx_buf and/or tx_buf.
+ * Protocol drivers should always provide @rx_buf and/or @tx_buf.
  * In some cases, they may also want to provide DMA addresses for
  * the data being transferred; that may reduce overhead, when the
  * underlying driver uses dma.
  *
  * If the transmit buffer is null, zeroes will be shifted out
- * while filling rx_buf.  If the receive buffer is null, the data
+ * while filling @rx_buf.  If the receive buffer is null, the data
  * shifted in will be discarded.  Only "len" bytes shift out (or in).
  * It's an error to try to shift out a partial word.  (For example, by
  * shifting out three bytes with word size of sixteen or twenty bits;
@@ -309,7 +323,7 @@ extern struct spi_master *spi_busnum_to_
  * In-memory data values are always in native CPU byte order, translated
  * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
  * for example when bits_per_word is sixteen, buffers are 2N bytes long
- * and hold N sixteen bit words in CPU byte order.
+ * (@len = 2N) and hold N sixteen bit words in CPU byte order.
  *
  * When the word size of the SPI transfer is not a power-of-two multiple
  * of eight bits, those in-memory words include extra bits.  In-memory
@@ -318,7 +332,7 @@ extern struct spi_master *spi_busnum_to_
  *
  * All SPI transfers start with the relevant chipselect active.  Normally
  * it stays selected until after the last transfer in a message.  Drivers
- * can affect the chipselect signal using cs_change:
+ * can affect the chipselect signal using cs_change.
  *
  * (i) If the transfer isn't the last one in the message, this flag is
  * used to make the chipselect briefly go inactive in the middle of the
@@ -372,7 +386,7 @@ struct spi_transfer {
  * @queue: for use by whichever driver currently owns the message
  * @state: for use by whichever driver currently owns the message
  *
- * An spi_message is used to execute an atomic sequence of data transfers,
+ * A @spi_message is used to execute an atomic sequence of data transfers,
  * each represented by a struct spi_transfer.  The sequence is "atomic"
  * in the sense that no other spi_message may use that SPI bus until that
  * sequence completes.  On some systems, many such sequences can execute as
@@ -464,8 +478,9 @@ static inline void spi_message_free(stru
 }
 
 /**
- * spi_setup -- setup SPI mode and clock rate
+ * spi_setup - setup SPI mode and clock rate
  * @spi: the device whose settings are being modified
+ * Context: can sleep
  *
  * SPI protocol drivers may need to update the transfer mode if the
  * device doesn't work with the mode 0 default.  They may likewise need
@@ -474,7 +489,7 @@ static inline void spi_message_free(stru
  * The changes take effect the next time the device is selected and data
  * is transferred to or from it.
  *
- * Note that this call wil fail if the protocol driver specifies an option
+ * Note that this call will fail if the protocol driver specifies an option
  * that the underlying controller or its driver does not support.  For
  * example, not all hardware supports wire transfers using nine bit words,
  * LSB-first wire encoding, or active-high chipselects.
@@ -487,9 +502,10 @@ spi_setup(struct spi_device *spi)
 
 
 /**
- * spi_async -- asynchronous SPI transfer
+ * spi_async - asynchronous SPI transfer
  * @spi: device with which data will be exchanged
  * @message: describes the data transfers, including completion callback
+ * Context: any (irqs may be blocked, etc)
  *
  * This call may be used in_irq and other contexts which can't sleep,
  * as well as from task contexts which can sleep.
@@ -535,6 +551,7 @@ extern int spi_sync(struct spi_device *s
  * @spi: device to which data will be written
  * @buf: data buffer
  * @len: data buffer size
+ * Context: can sleep
  *
  * This writes the buffer and returns zero or a negative error code.
  * Callable only from contexts that can sleep.
@@ -558,8 +575,9 @@ spi_write(struct spi_device *spi, const 
  * @spi: device from which data will be read
  * @buf: data buffer
  * @len: data buffer size
+ * Context: can sleep
  *
- * This writes the buffer and returns zero or a negative error code.
+ * This reads the buffer and returns zero or a negative error code.
  * Callable only from contexts that can sleep.
  */
 static inline int
@@ -585,6 +603,7 @@ extern int spi_write_then_read(struct sp
  * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
  * @spi: device with which data will be exchanged
  * @cmd: command to be written before data is read back
+ * Context: can sleep
  *
  * This returns the (unsigned) eight bit number returned by the
  * device, or else a negative error code.  Callable only from
@@ -605,6 +624,7 @@ static inline ssize_t spi_w8r8(struct sp
  * spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read
  * @spi: device with which data will be exchanged
  * @cmd: command to be written before data is read back
+ * Context: can sleep
  *
  * This returns the (unsigned) sixteen bit number returned by the
  * device, or else a negative error code.  Callable only from
diff --git a/include/linux/spi/spidev.h b/include/linux/spi/spidev.h
new file mode 100644
index 0000000..7d700be
--- /dev/null
+++ b/include/linux/spi/spidev.h
@@ -0,0 +1,124 @@
+/*
+ * include/linux/spi/spidev.h
+ *
+ * Copyright (C) 2006 SWAPP
+ *	Andrea Paterniani <a.paterniani@swapp-eng.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+
+#ifndef SPIDEV_H
+#define SPIDEV_H
+
+
+/* User space versions of kernel symbols for SPI clocking modes,
+ * matching <linux/spi/spi.h>
+ */
+
+#define SPI_CPHA		0x01
+#define SPI_CPOL		0x02
+
+#define SPI_MODE_0		(0|0)
+#define SPI_MODE_1		(0|SPI_CPHA)
+#define SPI_MODE_2		(SPI_CPOL|0)
+#define SPI_MODE_3		(SPI_CPOL|SPI_CPHA)
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL commands */
+
+#define SPI_IOC_MAGIC			'k'
+
+/**
+ * struct spi_ioc_transfer - describes a single SPI transfer
+ * @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
+ *	If no data is provided, zeroes are shifted out.
+ * @rx_buf: Holds pointer to userspace buffer for receive data, or null.
+ * @len: Length of tx and rx buffers, in bytes.
+ * @speed_hz: Temporary override of the device's bitrate.
+ * @bits_per_word: Temporary override of the device's wordsize.
+ * @delay_usecs: If nonzero, how long to delay after the last bit transfer
+ *	before optionally deselecting the device before the next transfer.
+ * @cs_change: True to deselect device before starting the next transfer.
+ *
+ * This structure is mapped directly to the kernel spi_transfer structure;
+ * the fields have the same meanings, except of course that the pointers
+ * are in a different address space (and may be of different sizes in some
+ * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
+ * Zero-initialize the structure, including currently unused fields, to
+ * accomodate potential future updates.
+ *
+ * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
+ * Pass it an array of related transfers, they'll execute together.
+ * Each transfer may be half duplex (either direction) or full duplex.
+ *
+ *	struct spi_ioc_transfer mesg[4];
+ *	...
+ *	status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
+ *
+ * So for example one transfer might send a nine bit command (right aligned
+ * in a 16-bit word), the next could read a block of 8-bit data before
+ * terminating that command by temporarily deselecting the chip; the next
+ * could send a different nine bit command (re-selecting the chip), and the
+ * last transfer might write some register values.
+ */
+struct spi_ioc_transfer {
+	__u64		tx_buf;
+	__u64		rx_buf;
+
+	__u32		len;
+	__u32		speed_hz;
+
+	__u16		delay_usecs;
+	__u8		bits_per_word;
+	__u8		cs_change;
+	__u32		pad;
+
+	/* If the contents of 'struct spi_ioc_transfer' ever change
+	 * incompatibly, then the ioctl number (currently 0) must change;
+	 * ioctls with constant size fields get a bit more in the way of
+	 * error checking than ones (like this) where that field varies.
+	 *
+	 * NOTE: struct layout is the same in 64bit and 32bit userspace.
+	 */
+};
+
+/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+#define SPI_MSGSIZE(N) \
+	((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+		? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+
+
+/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
+#define SPI_IOC_RD_MODE			_IOR(SPI_IOC_MAGIC, 1, __u8)
+#define SPI_IOC_WR_MODE			_IOW(SPI_IOC_MAGIC, 1, __u8)
+
+/* Read / Write SPI bit justification */
+#define SPI_IOC_RD_LSB_FIRST		_IOR(SPI_IOC_MAGIC, 2, __u8)
+#define SPI_IOC_WR_LSB_FIRST		_IOW(SPI_IOC_MAGIC, 2, __u8)
+
+/* Read / Write SPI device word length (1..N) */
+#define SPI_IOC_RD_BITS_PER_WORD	_IOR(SPI_IOC_MAGIC, 3, __u8)
+#define SPI_IOC_WR_BITS_PER_WORD	_IOW(SPI_IOC_MAGIC, 3, __u8)
+
+/* Read / Write SPI device default max speed hz */
+#define SPI_IOC_RD_MAX_SPEED_HZ		_IOR(SPI_IOC_MAGIC, 4, __u32)
+#define SPI_IOC_WR_MAX_SPEED_HZ		_IOW(SPI_IOC_MAGIC, 4, __u32)
+
+
+
+#endif /* SPIDEV_H */
diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h
index dc5fb69..210549b 100644
--- a/include/linux/spinlock_types.h
+++ b/include/linux/spinlock_types.h
@@ -85,6 +85,12 @@ #define __RW_LOCK_UNLOCKED(lockname) \
 				RW_DEP_MAP_INIT(lockname) }
 #endif
 
+/*
+ * SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and
+ * are hence deprecated.
+ * Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
+ * __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate.
+ */
 #define SPIN_LOCK_UNLOCKED	__SPIN_LOCK_UNLOCKED(old_style_spin_init)
 #define RW_LOCK_UNLOCKED	__RW_LOCK_UNLOCKED(old_style_rw_init)
 
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 50e2b01..1d2b084 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -6,15 +6,13 @@ 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);
+extern void save_stack_trace(struct stack_trace *trace);
 
 extern void print_stack_trace(struct stack_trace *trace, int spaces);
 #else
-# define save_stack_trace(trace, task)			do { } while (0)
+# define save_stack_trace(trace)			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 679ef0d..611c398 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -53,6 +53,9 @@ #define S_IRUGO		(S_IRUSR|S_IRGRP|S_IROT
 #define S_IWUGO		(S_IWUSR|S_IWGRP|S_IWOTH)
 #define S_IXUGO		(S_IXUSR|S_IXGRP|S_IXOTH)
 
+#define UTIME_NOW	((1l << 30) - 1l)
+#define UTIME_OMIT	((1l << 30) - 2l)
+
 #include <linux/types.h>
 #include <linux/time.h>
 
diff --git a/include/linux/string.h b/include/linux/string.h
index 4f69ef9..7f2eb6a 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -47,6 +47,12 @@ #endif
 #ifndef __HAVE_ARCH_STRNICMP
 extern int strnicmp(const char *, const char *, __kernel_size_t);
 #endif
+#ifndef __HAVE_ARCH_STRCASECMP
+extern int strcasecmp(const char *s1, const char *s2);
+#endif
+#ifndef __HAVE_ARCH_STRNCASECMP
+extern int strncasecmp(const char *s1, const char *s2, size_t n);
+#endif
 #ifndef __HAVE_ARCH_STRCHR
 extern char * strchr(const char *,int);
 #endif
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index c7a78ee..6661142 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -84,7 +84,8 @@ struct rpc_procinfo {
 	u32			p_proc;		/* RPC procedure number */
 	kxdrproc_t		p_encode;	/* XDR encode function */
 	kxdrproc_t		p_decode;	/* XDR decode function */
-	unsigned int		p_bufsiz;	/* req. buffer size */
+	unsigned int		p_arglen;	/* argument hdr length (u32) */
+	unsigned int		p_replen;	/* reply hdr length (u32) */
 	unsigned int		p_count;	/* call count */
 	unsigned int		p_timer;	/* Which RTT timer to use */
 	u32			p_statidx;	/* Which procedure to account */
@@ -121,8 +122,8 @@ struct rpc_clnt *rpc_clone_client(struct
 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 *);
-int		rpc_register(u32, u32, int, unsigned short, int *);
+int		rpcb_register(u32, u32, int, unsigned short, int *);
+void		rpcb_getport(struct rpc_task *);
 
 void		rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
 
@@ -144,7 +145,7 @@ char *		rpc_peeraddr2str(struct rpc_clnt
 /*
  * Helper function for NFSroot support
  */
-int		rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+int		rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index b7c7307..3912cf1 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -17,7 +17,7 @@ #define RPCDBG_CALL		0x0002
 #define RPCDBG_DEBUG		0x0004
 #define RPCDBG_NFS		0x0008
 #define RPCDBG_AUTH		0x0010
-#define RPCDBG_PMAP		0x0020
+#define RPCDBG_BIND		0x0020
 #define RPCDBG_SCHED		0x0040
 #define RPCDBG_TRANS		0x0080
 #define RPCDBG_SVCSOCK		0x0100
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 606cb21..784d4c3 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -78,10 +78,6 @@ enum rpc_auth_stat {
 	RPCSEC_GSS_CTXPROBLEM = 14
 };
 
-#define RPC_PMAP_PROGRAM	100000
-#define RPC_PMAP_VERSION	2
-#define RPC_PMAP_PORT		111
-
 #define RPC_MAXNETNAMELEN	256
 
 /*
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 3069ecc..2047fb2 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -264,7 +264,7 @@ struct rpc_task *rpc_wake_up_next(struct
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
 void		rpc_delay(struct rpc_task *, unsigned long);
 void *		rpc_malloc(struct rpc_task *, size_t);
-void		rpc_free(struct rpc_task *);
+void		rpc_free(void *);
 int		rpciod_up(void);
 void		rpciod_down(void);
 int		__rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index f780e72..fa89ce6 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -84,7 +84,9 @@ struct rpc_rqst {
 	struct list_head	rq_list;
 
 	__u32 *			rq_buffer;	/* XDR encode buffer */
-	size_t			rq_bufsize;
+	size_t			rq_bufsize,
+				rq_callsize,
+				rq_rcvsize;
 
 	struct xdr_buf		rq_private_buf;		/* The receive buffer
 							 * used in the softirq.
@@ -112,7 +114,7 @@ struct rpc_xprt_ops {
 	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);
-	void		(*buf_free)(struct rpc_task *task);
+	void		(*buf_free)(void *buffer);
 	int		(*send_request)(struct rpc_task *task);
 	void		(*set_retrans_timeout)(struct rpc_task *task);
 	void		(*timer)(struct rpc_task *task);
@@ -150,6 +152,7 @@ struct rpc_xprt {
 	unsigned long		state;		/* transport state */
 	unsigned char		shutdown   : 1,	/* being shut down */
 				resvport   : 1; /* use a reserved port */
+	unsigned int		bind_index;	/* bind function index */
 
 	/*
 	 * Connection of transports
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index bf99bd4..9d2aa1a 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -1,13 +1,14 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
+#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
 #include <asm/suspend.h>
 #endif
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/mm.h>
 
 /* struct pbe is used for creating lists of pages that should be restored
  * atomically during the resume from disk, because the page frames they have
@@ -23,36 +24,32 @@ struct pbe {
 extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
-#ifdef CONFIG_PM
-/* kernel/power/swsusp.c */
-extern int software_suspend(void);
-
-#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+#if defined(CONFIG_PM) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
 extern int pm_prepare_console(void);
 extern void pm_restore_console(void);
 #else
 static inline int pm_prepare_console(void) { return 0; }
 static inline void pm_restore_console(void) {}
-#endif /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */
+#endif
+
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+/* kernel/power/snapshot.c */
+extern void __init register_nosave_region(unsigned long, unsigned long);
+extern int swsusp_page_is_forbidden(struct page *);
+extern void swsusp_set_page_free(struct page *);
+extern void swsusp_unset_page_free(struct page *);
+extern unsigned long get_safe_page(gfp_t gfp_mask);
 #else
-static inline int software_suspend(void)
-{
-	printk("Warning: fake suspend called\n");
-	return -ENOSYS;
-}
-#endif /* CONFIG_PM */
+static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
+static inline void swsusp_set_page_free(struct page *p) {}
+static inline void swsusp_unset_page_free(struct page *p) {}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
 
 void save_processor_state(void);
 void restore_processor_state(void);
 struct saved_context;
 void __save_processor_state(struct saved_context *ctxt);
 void __restore_processor_state(struct saved_context *ctxt);
-unsigned long get_safe_page(gfp_t gfp_mask);
-
-/*
- * XXX: We try to keep some more pages free so that I/O operations succeed
- * without paging. Might this be more?
- */
-#define PAGES_FOR_IO	1024
 
 #endif /* _LINUX_SWSUSP_H */
diff --git a/include/linux/svga.h b/include/linux/svga.h
index eadb981..e1cc552 100644
--- a/include/linux/svga.h
+++ b/include/linux/svga.h
@@ -112,6 +112,7 @@ void svga_tilecopy(struct fb_info *info,
 void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect);
 void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit);
 void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor);
+int svga_get_tilemax(struct fb_info *info);
 
 int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node);
 int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 9a8970b..47f1c53 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -290,6 +290,7 @@ enum
 	NET_CORE_BUDGET=19,
 	NET_CORE_AEVENT_ETIME=20,
 	NET_CORE_AEVENT_RSEQTH=21,
+	NET_CORE_WARNINGS=22,
 };
 
 /* /proc/sys/net/ethernet */
@@ -438,6 +439,8 @@ enum
 	NET_CIPSOV4_RBM_STRICTVALID=121,
 	NET_TCP_AVAIL_CONG_CONTROL=122,
 	NET_TCP_ALLOWED_CONG_CONTROL=123,
+	NET_TCP_MAX_SSTHRESH=124,
+	NET_TCP_FRTO_RESPONSE=125,
 };
 
 enum {
@@ -789,6 +792,7 @@ enum {
 	NET_BRIDGE_NF_CALL_IPTABLES = 2,
 	NET_BRIDGE_NF_CALL_IP6TABLES = 3,
 	NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
+	NET_BRIDGE_NF_FILTER_PPPOE_TAGGED = 5,
 };
 
 /* CTL_FS names: */
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
index 389ccf8..e699ab2 100644
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -22,6 +22,7 @@ #ifndef _SYSDEV_H_
 #define _SYSDEV_H_
 
 #include <linux/kobject.h>
+#include <linux/module.h>
 #include <linux/pm.h>
 
 
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fea9a6b..7d5d1ec 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -80,7 +80,7 @@ #define SYSFS_NOT_PINNED	(SYSFS_KOBJ_ATT
 #ifdef CONFIG_SYSFS
 
 extern int sysfs_schedule_callback(struct kobject *kobj,
-		void (*func)(void *), void *data);
+		void (*func)(void *), void *data, struct module *owner);
 
 extern int __must_check
 sysfs_create_dir(struct kobject *, struct dentry *);
@@ -137,7 +137,7 @@ extern int __must_check sysfs_init(void)
 #else /* CONFIG_SYSFS */
 
 static inline int sysfs_schedule_callback(struct kobject *kobj,
-		void (*func)(void *), void *data)
+		void (*func)(void *), void *data, struct module *owner)
 {
 	return -ENOSYS;
 }
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 29d3089..c6b9f92 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -178,6 +178,21 @@ #include <net/sock.h>
 #include <net/inet_connection_sock.h>
 #include <net/inet_timewait_sock.h>
 
+static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
+{
+	return (struct tcphdr *)skb_transport_header(skb);
+}
+
+static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
+{
+	return tcp_hdr(skb)->doff * 4;
+}
+
+static inline unsigned int tcp_optlen(const struct sk_buff *skb)
+{
+	return (tcp_hdr(skb)->doff - 5) * 4;
+}
+
 /* This defines a selective acknowledgement block. */
 struct tcp_sack_block_wire {
 	__be32	start_seq;
@@ -242,6 +257,8 @@ struct tcp_sock {
  *	See RFC793 and RFC1122. The RFC writes these in capitals.
  */
  	u32	rcv_nxt;	/* What we want to receive next 	*/
+	u32	copied_seq;	/* Head of yet unread data		*/
+	u32	rcv_wup;	/* rcv_nxt on last window update sent	*/
  	u32	snd_nxt;	/* Next sequence we send		*/
 
  	u32	snd_una;	/* First byte we want an ack for	*/
@@ -300,17 +317,15 @@ #endif
  	u32	snd_ssthresh;	/* Slow start size threshold		*/
  	u32	snd_cwnd;	/* Sending congestion window		*/
  	u16	snd_cwnd_cnt;	/* Linear increase counter		*/
-	u16	snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */
+	u32	snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */
 	u32	snd_cwnd_used;
 	u32	snd_cwnd_stamp;
 
 	struct sk_buff_head	out_of_order_queue; /* Out of order segments go here */
 
  	u32	rcv_wnd;	/* Current receiver window		*/
-	u32	rcv_wup;	/* rcv_nxt on last window update sent	*/
 	u32	write_seq;	/* Tail(+1) of data held in tcp send buffer */
 	u32	pushed_seq;	/* Last pushed seq, required to talk to windows */
-	u32	copied_seq;	/* Head of yet unread data		*/
 
 /*	SACKs data	*/
 	struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index 3deb0a6..2a19698 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -14,16 +14,16 @@ #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/kthread.h>
+#include <linux/workqueue.h>
 
 /* Host registers (relative to pci base address): */
 enum {
 	FM_SET_INTERRUPT_ENABLE   = 0x008,
 	FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
-	FM_INTERRUPT_STATUS       = 0x014 };
+	FM_INTERRUPT_STATUS       = 0x014
+};
 
 /* Socket registers (relative to socket base address): */
 enum {
@@ -58,14 +58,8 @@ enum {
 	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(x)      (x)
-#define TIFM_IRQ_CARDMASK(x)      ((x) << 8)
-#define TIFM_IRQ_FIFOMASK(x)      ((x) << 16)
-#define TIFM_IRQ_SETALL           0xffffffff
+	SOCK_FIFO_ACCESS               = 0x200
+};
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
@@ -73,63 +67,76 @@ #define TIFM_CTRL_FAST_CLK        0x0000
 #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_ENABLE          0x00000001
+#define TIFM_FIFO_READY           0x00000001
 #define TIFM_FIFO_INT_SETALL      0x0000ffff
-#define TIFM_FIFO_INTMASK         0x00000005 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_INTMASK         0x00000005
+
+#define TIFM_DMA_RESET            0x00000002
+#define TIFM_DMA_TX               0x00008000
+#define TIFM_DMA_EN               0x00000001
+#define TIFM_DMA_TSIZE            0x0000007f
 
-#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 */
+#define TIFM_TYPE_XD 1
+#define TIFM_TYPE_MS 2
+#define TIFM_TYPE_SD 3
 
-typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
+struct tifm_device_id {
+	unsigned char type;
+};
 
 struct tifm_driver;
 struct tifm_dev {
-	char __iomem            *addr;
-	spinlock_t              lock;
-	tifm_media_id           media_id;
-	unsigned int            socket_id;
+	char __iomem  *addr;
+	spinlock_t    lock;
+	unsigned char type;
+	unsigned int  socket_id;
 
-	void                    (*signal_irq)(struct tifm_dev *sock,
-					      unsigned int sock_irq_status);
+	void          (*card_event)(struct tifm_dev *sock);
+	void          (*data_event)(struct tifm_dev *sock);
 
-	struct tifm_driver      *drv;
-	struct device           dev;
+	struct device dev;
 };
 
 struct tifm_driver {
-	tifm_media_id        *id_table;
-	int                  (*probe)(struct tifm_dev *dev);
-	void                 (*remove)(struct tifm_dev *dev);
-	int                  (*suspend)(struct tifm_dev *dev,
-                                        pm_message_t state);
-	int                  (*resume)(struct tifm_dev *dev);
-
-	struct device_driver driver;
+	struct tifm_device_id *id_table;
+	int                   (*probe)(struct tifm_dev *dev);
+	void                  (*remove)(struct tifm_dev *dev);
+	int                   (*suspend)(struct tifm_dev *dev,
+					 pm_message_t state);
+	int                   (*resume)(struct tifm_dev *dev);
+
+	struct device_driver  driver;
 };
 
 struct tifm_adapter {
-	char __iomem            *addr;
-	spinlock_t              lock;
-	unsigned int            irq_status;
-	unsigned int            socket_change_set;
-	wait_queue_head_t       change_set_notify;
-	unsigned int            id;
-	unsigned int            num_sockets;
-	struct tifm_dev         **sockets;
-	struct task_struct      *media_switcher;
-	struct class_device     cdev;
-	struct device           *dev;
-
-	void                    (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
+	char __iomem        *addr;
+	spinlock_t          lock;
+	unsigned int        irq_status;
+	unsigned int        socket_change_set;
+	unsigned int        id;
+	unsigned int        num_sockets;
+	struct completion   *finish_me;
+
+	struct work_struct  media_switcher;
+	struct class_device cdev;
+
+	void                (*eject)(struct tifm_adapter *fm,
+				     struct tifm_dev *sock);
+
+	struct tifm_dev     *sockets[0];
 };
 
-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, int (*mediathreadfn)(void *data));
+struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+					struct device *dev);
+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);
+void tifm_free_adapter(struct tifm_adapter *fm);
+
+void tifm_free_device(struct device *dev);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
+				   unsigned char type);
+
 int tifm_register_driver(struct tifm_driver *drv);
 void tifm_unregister_driver(struct tifm_driver *drv);
 void tifm_eject(struct tifm_dev *sock);
@@ -137,11 +144,11 @@ int tifm_map_sg(struct tifm_dev *sock, s
 		int direction);
 void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
 		   int direction);
-
+void tifm_queue_work(struct work_struct *work);
 
 static inline void *tifm_get_drvdata(struct tifm_dev *dev)
 {
-        return dev_get_drvdata(&dev->dev);
+	return dev_get_drvdata(&dev->dev);
 }
 
 static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
@@ -149,8 +156,4 @@ static inline void tifm_set_drvdata(stru
 	dev_set_drvdata(&dev->dev, data);
 }
 
-struct tifm_device_id {
-	tifm_media_id media_id;
-};
-
 #endif
diff --git a/include/linux/time.h b/include/linux/time.h
index 8ea8dea..dda9be6 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -109,7 +109,7 @@ extern void do_gettimeofday(struct timev
 extern int do_settimeofday(struct timespec *tv);
 extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
 #define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
-extern long do_utimes(int dfd, char __user *filename, struct timeval *times);
+extern long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags);
 struct itimerval;
 extern int do_setitimer(int which, struct itimerval *value,
 			struct itimerval *ovalue);
@@ -119,6 +119,7 @@ extern void getnstimeofday(struct timesp
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 extern int timekeeping_is_continuous(void);
+extern void update_wall_time(void);
 
 /**
  * timespec_to_ns - Convert timespec to nanoseconds
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 719113b..e0c5c16 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -37,6 +37,7 @@ #define DEFINE_TIMER(_name, _function, _
 		TIMER_INITIALIZER(_function, _expires, _data)
 
 void fastcall init_timer(struct timer_list * timer);
+void fastcall init_timer_deferrable(struct timer_list *timer);
 
 static inline void setup_timer(struct timer_list * timer,
 				void (*function)(unsigned long),
diff --git a/include/linux/tty.h b/include/linux/tty.h
index dee72b9..bb45760 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -313,6 +313,7 @@ extern int tty_hung_up_p(struct file * f
 extern void do_SAK(struct tty_struct *tty);
 extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
+extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
@@ -333,7 +334,6 @@ extern int tty_ioctl(struct inode *inode
 
 extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
-extern void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
 extern struct tty_struct *get_current_tty(void);
 
 extern struct mutex tty_mutex;
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 7e08c07..6de445c 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -26,6 +26,15 @@ struct udphdr {
 	__sum16	check;
 };
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
+{
+	return (struct udphdr *)skb_transport_header(skb);
+}
+#endif
+
 /* UDP socket options */
 #define UDP_CORK	1	/* Never send partially complete segments */
 #define UDP_ENCAP	100	/* Set the socket to accept encapsulated packets */
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 1fd61ee..a6c1e8e 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -32,6 +32,8 @@ #define __UINPUT_H_
  *		- first public version
  */
 
+#include <linux/input.h>
+
 #define UINPUT_VERSION		3
 
 #ifdef __KERNEL__
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 87dc75a..cfbd2bb 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -299,8 +299,9 @@ struct usb_bus {
 	int bandwidth_int_reqs;		/* number of Interrupt requests */
 	int bandwidth_isoc_reqs;	/* number of Isoc. requests */
 
+#ifdef CONFIG_USB_DEVICEFS
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
-
+#endif
 	struct class_device *class_dev;	/* class device for this bus */
 
 #if defined(CONFIG_USB_MON)
@@ -373,9 +374,12 @@ struct usb_device {
 	char *serial;			/* iSerialNumber string, if present */
 
 	struct list_head filelist;
-	struct device *usbfs_dev;
+#ifdef CONFIG_USB_DEVICE_CLASS
+	struct device *usb_classdev;
+#endif
+#ifdef CONFIG_USB_DEVICEFS
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
-
+#endif
 	/*
 	 * Child devices - these can be either new devices
 	 * (if this is a hub device), or different instances
@@ -394,10 +398,13 @@ #ifdef CONFIG_PM
 	struct delayed_work autosuspend; /* for delayed autosuspends */
 	struct mutex pm_mutex;		/* protects PM operations */
 
-	unsigned autosuspend_delay;	/* in jiffies */
+	unsigned long last_busy;	/* time of last use */
+	int autosuspend_delay;		/* in jiffies */
 
 	unsigned auto_pm:1;		/* autosuspend/resume in progress */
 	unsigned do_remote_wakeup:1;	/* remote wakeup should be enabled */
+	unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
+	unsigned autoresume_disabled:1;  /*  disabled by the user */
 #endif
 };
 #define	to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -437,6 +444,11 @@ static inline void usb_autopm_disable(st
 	usb_autopm_set_interface(intf);
 }
 
+static inline void usb_mark_last_busy(struct usb_device *udev)
+{
+	udev->last_busy = jiffies;
+}
+
 #else
 
 static inline int usb_autopm_set_interface(struct usb_interface *intf)
@@ -451,6 +463,8 @@ static inline void usb_autopm_enable(str
 { }
 static inline void usb_autopm_disable(struct usb_interface *intf)
 { }
+static inline void usb_mark_last_busy(struct usb_device *udev)
+{ }
 #endif
 
 /*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 956edf3..2204ae2 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -91,6 +91,17 @@ struct usb_cdc_union_desc {
 	/* ... and there could be other slave interfaces */
 } __attribute__ ((packed));
 
+/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
+struct usb_cdc_country_functional_desc {
+	__u8	bLength;
+	__u8	bDescriptorType;
+	__u8	bDescriptorSubType;
+
+	__u8	iCountryCodeRelDate;
+	__le16	wCountyCode0;
+	/* ... and there can be a lot of country codes */
+} __attribute__ ((packed));
+
 /* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
 struct usb_cdc_network_terminal_desc {
 	__u8	bLength;
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 1122a6c..6169438 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -181,12 +181,15 @@ #define USB_DT_WIRELESS_ENDPOINT_COMP	0x
 #define USB_DT_WIRE_ADAPTER		0x21
 #define USB_DT_RPIPE			0x22
 
-/* conventional codes for class-specific descriptors */
-#define USB_DT_CS_DEVICE		0x21
-#define USB_DT_CS_CONFIG		0x22
-#define USB_DT_CS_STRING		0x23
-#define USB_DT_CS_INTERFACE		0x24
-#define USB_DT_CS_ENDPOINT		0x25
+/* Conventional codes for class-specific descriptors.  The convention is
+ * defined in the USB "Common Class" Spec (3.11).  Individual class specs
+ * are authoritative for their usage, not the "common class" writeup.
+ */
+#define USB_DT_CS_DEVICE		(USB_TYPE_CLASS | USB_DT_DEVICE)
+#define USB_DT_CS_CONFIG		(USB_TYPE_CLASS | USB_DT_CONFIG)
+#define USB_DT_CS_STRING		(USB_TYPE_CLASS | USB_DT_STRING)
+#define USB_DT_CS_INTERFACE		(USB_TYPE_CLASS | USB_DT_INTERFACE)
+#define USB_DT_CS_ENDPOINT		(USB_TYPE_CLASS | USB_DT_ENDPOINT)
 
 /* All standard descriptors have these 2 fields at the beginning */
 struct usb_descriptor_header {
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
new file mode 100644
index 0000000..4f2d012
--- /dev/null
+++ b/include/linux/usb_sl811.h
@@ -0,0 +1,26 @@
+
+/*
+ * board initialization should put one of these into dev->platform_data
+ * and place the sl811hs onto platform_bus named "sl811-hcd".
+ */
+
+struct sl811_platform_data {
+	unsigned	can_wakeup:1;
+
+	/* given port_power, msec/2 after power on till power good */
+	u8		potpg;
+
+	/* mA/2 power supplied on this port (max = default = 250) */
+	u8		power;
+
+	/* sl811 relies on an external source of VBUS current */
+	void 		(*port_power)(struct device *dev, int is_on);
+
+	/* pulse sl811 nRST (probably with a GPIO) */
+	void 		(*reset)(struct device *dev);
+
+	// some boards need something like these:
+ 	// int 		(*check_overcurrent)(struct device *dev);
+ 	// void 	(*clock_enable)(struct device *dev, int is_on);
+};
+
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index e10267d..f8d3b32 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -49,9 +49,7 @@ static inline void get_uts_ns(struct uts
 }
 
 #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 struct uts_namespace *copy_utsname(int flags, struct uts_namespace *ns);
 extern void free_uts_ns(struct kref *kref);
 
 static inline void put_uts_ns(struct uts_namespace *ns)
@@ -59,21 +57,12 @@ static inline void put_uts_ns(struct uts
 	kref_put(&ns->kref, free_uts_ns);
 }
 #else
-static inline int unshare_utsname(unsigned long unshare_flags,
-			struct uts_namespace **new_uts)
+static inline struct uts_namespace *copy_utsname(int flags,
+						struct uts_namespace *ns)
 {
-	if (unshare_flags & CLONE_NEWUTS)
-		return -EINVAL;
-
-	return 0;
+	return ns;
 }
 
-static inline int copy_utsname(int flags, struct task_struct *tsk)
-{
-	if (flags & CLONE_NEWUTS)
-		return -EINVAL;
-	return 0;
-}
 static inline void put_uts_ns(struct uts_namespace *ns)
 {
 }
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 441b877..a25c2af 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -96,44 +96,60 @@ #define v4l2_fourcc(a,b,c,d)\
  *	E N U M S
  */
 enum v4l2_field {
-	V4L2_FIELD_ANY        = 0, /* driver can choose from none,
-				      top, bottom, interlaced
-				      depending on whatever it thinks
-				      is approximate ... */
-	V4L2_FIELD_NONE       = 1, /* this device has no fields ... */
-	V4L2_FIELD_TOP        = 2, /* top field only */
-	V4L2_FIELD_BOTTOM     = 3, /* bottom field only */
-	V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */
-	V4L2_FIELD_SEQ_TB     = 5, /* both fields sequential into one
-				      buffer, top-bottom order */
-	V4L2_FIELD_SEQ_BT     = 6, /* same as above + bottom-top order */
-	V4L2_FIELD_ALTERNATE  = 7, /* both fields alternating into
-				      separate buffers */
+	V4L2_FIELD_ANY           = 0, /* driver can choose from none,
+					 top, bottom, interlaced
+					 depending on whatever it thinks
+					 is approximate ... */
+	V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
+	V4L2_FIELD_TOP           = 2, /* top field only */
+	V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
+	V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
+	V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
+					 buffer, top-bottom order */
+	V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
+	V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
+					 separate buffers */
+	V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
+					 first and the top field is
+					 transmitted first */
+	V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
+					 first and the bottom field is
+					 transmitted first */
 };
 #define V4L2_FIELD_HAS_TOP(field)	\
 	((field) == V4L2_FIELD_TOP 	||\
 	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
 	 (field) == V4L2_FIELD_SEQ_TB	||\
 	 (field) == V4L2_FIELD_SEQ_BT)
 #define V4L2_FIELD_HAS_BOTTOM(field)	\
 	((field) == V4L2_FIELD_BOTTOM 	||\
 	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
 	 (field) == V4L2_FIELD_SEQ_TB	||\
 	 (field) == V4L2_FIELD_SEQ_BT)
 #define V4L2_FIELD_HAS_BOTH(field)	\
 	((field) == V4L2_FIELD_INTERLACED ||\
-	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB ||\
 	 (field) == V4L2_FIELD_SEQ_BT)
 
 enum v4l2_buf_type {
-	V4L2_BUF_TYPE_VIDEO_CAPTURE      = 1,
-	V4L2_BUF_TYPE_VIDEO_OUTPUT       = 2,
-	V4L2_BUF_TYPE_VIDEO_OVERLAY      = 3,
-	V4L2_BUF_TYPE_VBI_CAPTURE        = 4,
-	V4L2_BUF_TYPE_VBI_OUTPUT         = 5,
-	V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
-	V4L2_BUF_TYPE_SLICED_VBI_OUTPUT  = 7,
-	V4L2_BUF_TYPE_PRIVATE            = 0x80,
+	V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
+	V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
+	V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
+	V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
+	V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
+	V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
+#if 1
+	/* Experimental */
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
+#endif
+	V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
 enum v4l2_ctrl_type {
@@ -227,6 +243,8 @@ #define V4L2_CAP_VBI_OUTPUT		0x00000020 
 #define V4L2_CAP_SLICED_VBI_CAPTURE	0x00000040  /* Is a sliced VBI capture device */
 #define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
 #define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
+#define V4L2_CAP_VIDEO_OUTPUT_POS       0x00000200  /* Video output can have x,y coords */
+#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY	0x00000400  /* Can do video output overlay */
 
 #define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
 #define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
@@ -249,6 +267,8 @@ struct v4l2_pix_format
 	__u32          		sizeimage;
 	enum v4l2_colorspace	colorspace;
 	__u32			priv;		/* private data, depends on pixelformat */
+	__u32 			left;	/* only valid if V4L2_CAP_VIDEO_OUTPUT_POS is set */
+	__u32 			top;	/* only valid if V4L2_CAP_VIDEO_OUTPUT_POS is set */
 };
 
 /*      Pixel format         FOURCC                        depth  Description  */
@@ -596,10 +616,14 @@ #define V4L2_FBUF_CAP_EXTERNOVERLAY	0x00
 #define V4L2_FBUF_CAP_CHROMAKEY		0x0002
 #define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
 #define V4L2_FBUF_CAP_BITMAP_CLIPPING	0x0008
+#define V4L2_FBUF_CAP_LOCAL_ALPHA	0x0010
+#define V4L2_FBUF_CAP_GLOBAL_ALPHA	0x0020
 /*  Flags for the 'flags' field. */
 #define V4L2_FBUF_FLAG_PRIMARY		0x0001
 #define V4L2_FBUF_FLAG_OVERLAY		0x0002
 #define V4L2_FBUF_FLAG_CHROMAKEY	0x0004
+#define V4L2_FBUF_FLAG_LOCAL_ALPHA	0x0008
+#define V4L2_FBUF_FLAG_GLOBAL_ALPHA	0x0010
 
 struct v4l2_clip
 {
@@ -615,6 +639,7 @@ struct v4l2_window
 	struct v4l2_clip	__user *clips;
 	__u32			clipcount;
 	void			__user *bitmap;
+	__u8                    global_alpha;
 };
 
 /*
@@ -1037,6 +1062,7 @@ enum v4l2_mpeg_audio_crc {
 	V4L2_MPEG_AUDIO_CRC_NONE  = 0,
 	V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
 };
+#define V4L2_CID_MPEG_AUDIO_MUTE 		(V4L2_CID_MPEG_BASE+109)
 
 /*  MPEG video */
 #define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
@@ -1063,6 +1089,8 @@ enum v4l2_mpeg_video_bitrate_mode {
 #define V4L2_CID_MPEG_VIDEO_BITRATE 		(V4L2_CID_MPEG_BASE+207)
 #define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK 	(V4L2_CID_MPEG_BASE+208)
 #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+#define V4L2_CID_MPEG_VIDEO_MUTE 		(V4L2_CID_MPEG_BASE+210)
+#define V4L2_CID_MPEG_VIDEO_MUTE_YUV 		(V4L2_CID_MPEG_BASE+211)
 
 /*  MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE 				(V4L2_CTRL_CLASS_MPEG | 0x1000)
@@ -1103,6 +1131,7 @@ #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA
 #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+8)
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM	(V4L2_CID_MPEG_CX2341X_BASE+9)
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
+#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS 	(V4L2_CID_MPEG_CX2341X_BASE+11)
 
 /*
  *	T U N I N G
@@ -1369,6 +1398,14 @@ struct v4l2_register {
 	__u64 val;
 };
 
+/* VIDIOC_G_CHIP_IDENT */
+struct v4l2_chip_ident {
+	__u32 match_type;  /* Match type */
+	__u32 match_chip;  /* Match this chip, meaning determined by match_type */
+	__u32 ident;       /* chip identifier as specified in <media/v4l2-chip-ident.h> */
+	__u32 revision;    /* chip revision, chip specific */
+};
+
 /*
  *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -1442,6 +1479,8 @@ #define VIDIOC_TRY_ENCODER_CMD  _IOWR ('
 /* Experimental, only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
 #define	VIDIOC_DBG_S_REGISTER 	_IOW  ('V', 79, struct v4l2_register)
 #define	VIDIOC_DBG_G_REGISTER 	_IOWR ('V', 80, struct v4l2_register)
+
+#define VIDIOC_G_CHIP_IDENT     _IOWR ('V', 81, struct v4l2_chip_ident)
 #endif
 
 #ifdef __OLD_VIDIOC_
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 924e502..4b7ee83 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -53,6 +53,7 @@ extern void vunmap(void *addr);
 
 extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
 							unsigned long pgoff);
+void vmalloc_sync_all(void);
  
 /*
  *	Lowlevel-APIs (not for driver use!)
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index e0db669..d961635 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -9,6 +9,7 @@ #define _VT_KERN_H
 #include <linux/vt.h>
 #include <linux/kd.h>
 #include <linux/tty.h>
+#include <linux/mutex.h>
 #include <linux/console_struct.h>
 #include <linux/mm.h>
 
@@ -82,7 +83,7 @@ void reset_vc(struct vc_data *vc);
 
 #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
 extern char con_buf[CON_BUF_SIZE];
-extern struct semaphore con_buf_sem;
+extern struct mutex con_buf_mtx;
 extern char vt_dont_switch;
 
 struct vt_spawn_console {
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 48759b2..0987aa7 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -186,7 +186,7 @@ #define WIRELESS_EXT	22
  *	- Wireless Event capability in struct iw_range
  *	- Add support for relative TxPower (yick !)
  *
- * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
  * ----------
  *	- Add support for WPA/WPA2
  *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 2a7b38d..f16ba1e 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -121,6 +121,12 @@ #define INIT_DELAYED_WORK_NAR(_work, _fu
 		init_timer(&(_work)->timer);			\
 	} while (0)
 
+#define INIT_DELAYED_WORK_DEFERRABLE(_work, _func)			\
+	do {							\
+		INIT_WORK(&(_work)->work, (_func));		\
+		init_timer_deferrable(&(_work)->timer);		\
+	} while (0)
+
 /**
  * work_pending - Find out whether a work item is currently pending
  * @work: The work item in question
@@ -191,14 +197,15 @@ int execute_in_process_context(work_func
 
 /*
  * Kill off a pending schedule_delayed_work().  Note that the work callback
- * function may still be running on return from cancel_delayed_work().  Run
- * flush_scheduled_work() to wait on it.
+ * function may still be running on return from cancel_delayed_work(), unless
+ * it returns 1 and the work doesn't re-arm itself. Run flush_workqueue() or
+ * cancel_work_sync() to wait on it.
  */
 static inline int cancel_delayed_work(struct delayed_work *work)
 {
 	int ret;
 
-	ret = del_timer_sync(&work->timer);
+	ret = del_timer(&work->timer);
 	if (ret)
 		work_release(&work->work);
 	return ret;
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 0c78f7f..daa6c12 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -59,6 +59,8 @@ struct writeback_control {
 	unsigned for_reclaim:1;		/* Invoked from the page allocator */
 	unsigned for_writepages:1;	/* This is a writepages() call */
 	unsigned range_cyclic:1;	/* range_start is cyclic */
+
+	void *fs_private;		/* For use by ->writepages() */
 };
 
 /*
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 15ca89e..b58adc5 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -181,6 +181,15 @@ #define XFRM_MSG_REPORT XFRM_MSG_REPORT
 	XFRM_MSG_MIGRATE,
 #define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE
 
+	XFRM_MSG_NEWSADINFO,
+#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO
+	XFRM_MSG_GETSADINFO,
+#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO
+
+	XFRM_MSG_NEWSPDINFO,
+#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
+	XFRM_MSG_GETSPDINFO,
+#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
 	__XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -265,6 +274,43 @@ enum xfrm_attr_type_t {
 #define XFRMA_MAX (__XFRMA_MAX - 1)
 };
 
+enum xfrm_sadattr_type_t {
+	XFRMA_SAD_UNSPEC,
+	XFRMA_SAD_CNT,
+	XFRMA_SAD_HINFO,
+	__XFRMA_SAD_MAX
+
+#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1)
+};
+
+struct xfrmu_sadhinfo {
+	__u32 sadhcnt; /* current hash bkts */
+	__u32 sadhmcnt; /* max allowed hash bkts */
+};
+
+enum xfrm_spdattr_type_t {
+	XFRMA_SPD_UNSPEC,
+	XFRMA_SPD_INFO,
+	XFRMA_SPD_HINFO,
+	__XFRMA_SPD_MAX
+
+#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
+};
+
+struct xfrmu_spdinfo {
+	__u32 incnt;
+	__u32 outcnt;
+	__u32 fwdcnt;
+	__u32 inscnt;
+	__u32 outscnt;
+	__u32 fwdscnt;
+};
+
+struct xfrmu_spdhinfo {
+	__u32 spdhcnt;
+	__u32 spdhmcnt;
+};
+
 struct xfrm_usersa_info {
 	struct xfrm_selector		sel;
 	struct xfrm_id			id;
diff --git a/include/math-emu/extended.h b/include/math-emu/extended.h
deleted file mode 100644
index 84770fc..0000000
--- a/include/math-emu/extended.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* Software floating-point emulation.
-   Definitions for IEEE Extended Precision.
-   Copyright (C) 1999 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Jakub Jelinek (jj@ultra.linux.cz).
-
-   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    __MATH_EMU_EXTENDED_H__
-#define    __MATH_EMU_EXTENDED_H__
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel, kid. Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-#define _FP_FRACTBITS_E         (4*_FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_E		(2*_FP_W_TYPE_SIZE)
-#endif
-
-#define _FP_FRACBITS_E		64
-#define _FP_FRACXBITS_E		(_FP_FRACTBITS_E - _FP_FRACBITS_E)
-#define _FP_WFRACBITS_E		(_FP_WORKBITS + _FP_FRACBITS_E)
-#define _FP_WFRACXBITS_E	(_FP_FRACTBITS_E - _FP_WFRACBITS_E)
-#define _FP_EXPBITS_E		15
-#define _FP_EXPBIAS_E		16383
-#define _FP_EXPMAX_E		32767
-
-#define _FP_QNANBIT_E		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE)
-#define _FP_IMPLBIT_E		\
-	((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE)
-#define _FP_OVERFLOW_E		\
-	((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE))
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_E
-{
-   long double flt;
-   struct 
-   {
-#if __BYTE_ORDER == __BIG_ENDIAN
-      unsigned long pad1 : _FP_W_TYPE_SIZE;
-      unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
-      unsigned long sign : 1;
-      unsigned long exp : _FP_EXPBITS_E;
-      unsigned long frac1 : _FP_W_TYPE_SIZE;
-      unsigned long frac0 : _FP_W_TYPE_SIZE;
-#else
-      unsigned long frac0 : _FP_W_TYPE_SIZE;
-      unsigned long frac1 : _FP_W_TYPE_SIZE;
-      unsigned exp : _FP_EXPBITS_E;
-      unsigned sign : 1;
-#endif /* not bigendian */
-   } bits __attribute__((packed));
-};
-
-
-#define FP_DECL_E(X)		_FP_DECL(4,X)
-
-#define FP_UNPACK_RAW_E(X, val)				\
-  do {							\
-    union _FP_UNION_E _flo; _flo.flt = (val);		\
-							\
-    X##_f[2] = 0; X##_f[3] = 0;				\
-    X##_f[0] = _flo.bits.frac0;				\
-    X##_f[1] = _flo.bits.frac1;				\
-    X##_e  = _flo.bits.exp;				\
-    X##_s  = _flo.bits.sign;				\
-    if (!X##_e && (X##_f[1] || X##_f[0])		\
-        && !(X##_f[1] & _FP_IMPLBIT_E))			\
-      {							\
-        X##_e++;					\
-        FP_SET_EXCEPTION(FP_EX_DENORM);			\
-      }							\
-  } while (0)
-
-#define FP_UNPACK_RAW_EP(X, val)			\
-  do {							\
-    union _FP_UNION_E *_flo =				\
-    (union _FP_UNION_E *)(val);				\
-							\
-    X##_f[2] = 0; X##_f[3] = 0;				\
-    X##_f[0] = _flo->bits.frac0;			\
-    X##_f[1] = _flo->bits.frac1;			\
-    X##_e  = _flo->bits.exp;				\
-    X##_s  = _flo->bits.sign;				\
-    if (!X##_e && (X##_f[1] || X##_f[0])		\
-        && !(X##_f[1] & _FP_IMPLBIT_E))			\
-      {							\
-        X##_e++;					\
-        FP_SET_EXCEPTION(FP_EX_DENORM);			\
-      }							\
-  } while (0)
-
-#define FP_PACK_RAW_E(val, X)				\
-  do {							\
-    union _FP_UNION_E _flo;				\
-							\
-    if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;		\
-    else X##_f[1] &= ~(_FP_IMPLBIT_E);			\
-    _flo.bits.frac0 = X##_f[0];				\
-    _flo.bits.frac1 = X##_f[1];				\
-    _flo.bits.exp   = X##_e;				\
-    _flo.bits.sign  = X##_s;				\
-							\
-    (val) = _flo.flt;					\
-  } while (0)
-
-#define FP_PACK_RAW_EP(val, X)				\
-  do {							\
-    if (!FP_INHIBIT_RESULTS)				\
-      {							\
-	union _FP_UNION_E *_flo =			\
-	  (union _FP_UNION_E *)(val);			\
-							\
-	if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;		\
-	else X##_f[1] &= ~(_FP_IMPLBIT_E);		\
-	_flo->bits.frac0 = X##_f[0];			\
-	_flo->bits.frac1 = X##_f[1];			\
-	_flo->bits.exp   = X##_e;			\
-	_flo->bits.sign  = X##_s;			\
-      }							\
-  } while (0)
-
-#define FP_UNPACK_E(X,val)		\
-  do {					\
-    FP_UNPACK_RAW_E(X,val);		\
-    _FP_UNPACK_CANONICAL(E,4,X);	\
-  } while (0)
-
-#define FP_UNPACK_EP(X,val)		\
-  do {					\
-    FP_UNPACK_RAW_2_P(X,val);		\
-    _FP_UNPACK_CANONICAL(E,4,X);	\
-  } while (0)
-
-#define FP_PACK_E(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(E,4,X);		\
-    FP_PACK_RAW_E(val,X);		\
-  } while (0)
-
-#define FP_PACK_EP(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(E,4,X);		\
-    FP_PACK_RAW_EP(val,X);		\
-  } while (0)
-
-#define FP_ISSIGNAN_E(X)	_FP_ISSIGNAN(E,4,X)
-#define FP_NEG_E(R,X)		_FP_NEG(E,4,R,X)
-#define FP_ADD_E(R,X,Y)		_FP_ADD(E,4,R,X,Y)
-#define FP_SUB_E(R,X,Y)		_FP_SUB(E,4,R,X,Y)
-#define FP_MUL_E(R,X,Y)		_FP_MUL(E,4,R,X,Y)
-#define FP_DIV_E(R,X,Y)		_FP_DIV(E,4,R,X,Y)
-#define FP_SQRT_E(R,X)		_FP_SQRT(E,4,R,X)
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- * This has special _E version because standard _4 square
- * root would not work (it has to start normally with the
- * second word and not the first), but as we have to do it
- * anyway, we optimize it by doing most of the calculations
- * in two UWtype registers instead of four.
- */
- 
-#define _FP_SQRT_MEAT_E(R, S, T, X, q)			\
-  do {							\
-    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
-    _FP_FRAC_SRL_4(X, (_FP_WORKBITS));			\
-    while (q)						\
-      {							\
-	T##_f[1] = S##_f[1] + q;			\
-	if (T##_f[1] <= X##_f[1])			\
-	  {						\
-	    S##_f[1] = T##_f[1] + q;			\
-	    X##_f[1] -= T##_f[1];			\
-	    R##_f[1] += q;				\
-	  }						\
-	_FP_FRAC_SLL_2(X, 1);				\
-	q >>= 1;					\
-      }							\
-    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
-    while (q)						\
-      {							\
-	T##_f[0] = S##_f[0] + q;			\
-	T##_f[1] = S##_f[1];				\
-	if (T##_f[1] < X##_f[1] || 			\
-	    (T##_f[1] == X##_f[1] &&			\
-	     T##_f[0] <= X##_f[0]))			\
-	  {						\
-	    S##_f[0] = T##_f[0] + q;			\
-	    S##_f[1] += (T##_f[0] > S##_f[0]);		\
-	    _FP_FRAC_DEC_2(X, T);			\
-	    R##_f[0] += q;				\
-	  }						\
-	_FP_FRAC_SLL_2(X, 1);				\
-	q >>= 1;					\
-      }							\
-    _FP_FRAC_SLL_4(R, (_FP_WORKBITS));			\
-    if (X##_f[0] | X##_f[1])				\
-      {							\
-	if (S##_f[1] < X##_f[1] || 			\
-	    (S##_f[1] == X##_f[1] &&			\
-	     S##_f[0] < X##_f[0]))			\
-	  R##_f[0] |= _FP_WORK_ROUND;			\
-	R##_f[0] |= _FP_WORK_STICKY;			\
-      }							\
-  } while (0)
-
-#define FP_CMP_E(r,X,Y,un)	_FP_CMP(E,4,r,X,Y,un)
-#define FP_CMP_EQ_E(r,X,Y)	_FP_CMP_EQ(E,4,r,X,Y)
-
-#define FP_TO_INT_E(r,X,rsz,rsg)	_FP_TO_INT(E,4,r,X,rsz,rsg)
-#define FP_TO_INT_ROUND_E(r,X,rsz,rsg)	_FP_TO_INT_ROUND(E,4,r,X,rsz,rsg)
-#define FP_FROM_INT_E(X,r,rs,rt)	_FP_FROM_INT(E,4,X,r,rs,rt)
-
-#define _FP_FRAC_HIGH_E(X)	(X##_f[2])
-#define _FP_FRAC_HIGH_RAW_E(X)	(X##_f[1])
-
-#else   /* not _FP_W_TYPE_SIZE < 64 */
-union _FP_UNION_E
-{
-  long double flt /* __attribute__((mode(TF))) */ ;
-  struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
-    unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
-    unsigned sign  : 1;
-    unsigned exp   : _FP_EXPBITS_E;
-    unsigned long frac : _FP_W_TYPE_SIZE;
-#else
-    unsigned long frac : _FP_W_TYPE_SIZE;
-    unsigned exp   : _FP_EXPBITS_E;
-    unsigned sign  : 1;
-#endif
-  } bits;
-};
-
-#define FP_DECL_E(X)		_FP_DECL(2,X)
-
-#define FP_UNPACK_RAW_E(X, val)					\
-  do {								\
-    union _FP_UNION_E _flo; _flo.flt = (val);			\
-								\
-    X##_f0 = _flo.bits.frac;					\
-    X##_f1 = 0;							\
-    X##_e = _flo.bits.exp;					\
-    X##_s = _flo.bits.sign;					\
-    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))		\
-      {								\
-        X##_e++;						\
-        FP_SET_EXCEPTION(FP_EX_DENORM);				\
-      }								\
-  } while (0)
-
-#define FP_UNPACK_RAW_EP(X, val)				\
-  do {								\
-    union _FP_UNION_E *_flo =					\
-      (union _FP_UNION_E *)(val);				\
-								\
-    X##_f0 = _flo->bits.frac;					\
-    X##_f1 = 0;							\
-    X##_e = _flo->bits.exp;					\
-    X##_s = _flo->bits.sign;					\
-    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))		\
-      {								\
-        X##_e++;						\
-        FP_SET_EXCEPTION(FP_EX_DENORM);				\
-      }								\
-  } while (0)
-
-#define FP_PACK_RAW_E(val, X)					\
-  do {								\
-    union _FP_UNION_E _flo;					\
-								\
-    if (X##_e) X##_f0 |= _FP_IMPLBIT_E;				\
-    else X##_f0 &= ~(_FP_IMPLBIT_E);				\
-    _flo.bits.frac = X##_f0;					\
-    _flo.bits.exp  = X##_e;					\
-    _flo.bits.sign = X##_s;					\
-								\
-    (val) = _flo.flt;						\
-  } while (0)
-
-#define FP_PACK_RAW_EP(fs, val, X)				\
-  do {								\
-    if (!FP_INHIBIT_RESULTS)					\
-      {								\
-	union _FP_UNION_E *_flo =				\
-	  (union _FP_UNION_E *)(val);				\
-								\
-	if (X##_e) X##_f0 |= _FP_IMPLBIT_E;			\
-	else X##_f0 &= ~(_FP_IMPLBIT_E);			\
-	_flo->bits.frac = X##_f0;				\
-	_flo->bits.exp  = X##_e;				\
-	_flo->bits.sign = X##_s;				\
-      }								\
-  } while (0)
-
-
-#define FP_UNPACK_E(X,val)		\
-  do {					\
-    FP_UNPACK_RAW_E(X,val);		\
-    _FP_UNPACK_CANONICAL(E,2,X);	\
-  } while (0)
-
-#define FP_UNPACK_EP(X,val)		\
-  do {					\
-    FP_UNPACK_RAW_EP(X,val);		\
-    _FP_UNPACK_CANONICAL(E,2,X);	\
-  } while (0)
-
-#define FP_PACK_E(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(E,2,X);		\
-    FP_PACK_RAW_E(val,X);		\
-  } while (0)
-
-#define FP_PACK_EP(val,X)		\
-  do {					\
-    _FP_PACK_CANONICAL(E,2,X);		\
-    FP_PACK_RAW_EP(val,X);		\
-  } while (0)
-
-#define FP_ISSIGNAN_E(X)	_FP_ISSIGNAN(E,2,X)
-#define FP_NEG_E(R,X)		_FP_NEG(E,2,R,X)
-#define FP_ADD_E(R,X,Y)		_FP_ADD(E,2,R,X,Y)
-#define FP_SUB_E(R,X,Y)		_FP_SUB(E,2,R,X,Y)
-#define FP_MUL_E(R,X,Y)		_FP_MUL(E,2,R,X,Y)
-#define FP_DIV_E(R,X,Y)		_FP_DIV(E,2,R,X,Y)
-#define FP_SQRT_E(R,X)		_FP_SQRT(E,2,R,X)
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- * We optimize it by doing most of the calculations
- * in one UWtype registers instead of two, although we don't
- * have to.
- */
-#define _FP_SQRT_MEAT_E(R, S, T, X, q)			\
-  do {							\
-    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);		\
-    _FP_FRAC_SRL_2(X, (_FP_WORKBITS));			\
-    while (q)						\
-      {							\
-        T##_f0 = S##_f0 + q;				\
-        if (T##_f0 <= X##_f0)				\
-          {						\
-            S##_f0 = T##_f0 + q;			\
-            X##_f0 -= T##_f0;				\
-            R##_f0 += q;				\
-          }						\
-        _FP_FRAC_SLL_1(X, 1);				\
-        q >>= 1;					\
-      }							\
-    _FP_FRAC_SLL_2(R, (_FP_WORKBITS));			\
-    if (X##_f0)						\
-      {							\
-	if (S##_f0 < X##_f0)				\
-	  R##_f0 |= _FP_WORK_ROUND;			\
-	R##_f0 |= _FP_WORK_STICKY;			\
-      }							\
-  } while (0)
- 
-#define FP_CMP_E(r,X,Y,un)	_FP_CMP(E,2,r,X,Y,un)
-#define FP_CMP_EQ_E(r,X,Y)	_FP_CMP_EQ(E,2,r,X,Y)
-
-#define FP_TO_INT_E(r,X,rsz,rsg)	_FP_TO_INT(E,2,r,X,rsz,rsg)
-#define FP_TO_INT_ROUND_E(r,X,rsz,rsg)	_FP_TO_INT_ROUND(E,2,r,X,rsz,rsg)
-#define FP_FROM_INT_E(X,r,rs,rt)	_FP_FROM_INT(E,2,X,r,rs,rt)
-
-#define _FP_FRAC_HIGH_E(X)	(X##_f1)
-#define _FP_FRAC_HIGH_RAW_E(X)	(X##_f0)
-
-#endif /* not _FP_W_TYPE_SIZE < 64 */
-
-#endif /* __MATH_EMU_EXTENDED_H__ */
diff --git a/include/media/cx2341x.h b/include/media/cx2341x.h
index d758a52..38c12fe 100644
--- a/include/media/cx2341x.h
+++ b/include/media/cx2341x.h
@@ -40,6 +40,7 @@ struct cx2341x_mpeg_params {
 	/* stream */
 	enum v4l2_mpeg_stream_type stream_type;
 	enum v4l2_mpeg_stream_vbi_fmt stream_vbi_fmt;
+	u16 stream_insert_nav_packets;
 
 	/* audio */
 	enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
@@ -50,6 +51,7 @@ struct cx2341x_mpeg_params {
 	enum v4l2_mpeg_audio_emphasis audio_emphasis;
 	enum v4l2_mpeg_audio_crc audio_crc;
 	u16 audio_properties;
+	u16 audio_mute;
 
 	/* video */
 	enum v4l2_mpeg_video_encoding video_encoding;
@@ -61,6 +63,8 @@ struct cx2341x_mpeg_params {
 	u32 video_bitrate;
 	u32 video_bitrate_peak;
 	u16 video_temporal_decimation;
+	u16 video_mute;
+	u32 video_mute_yuv;
 
 	/* encoding filters */
 	enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
@@ -162,7 +166,7 @@ #define CX2341X_ENC_SET_NUM_VSYNC_LINES 
 #define CX2341X_ENC_SET_PLACEHOLDER 		0xd7
 #define CX2341X_ENC_MUTE_VIDEO 			0xd9
 #define CX2341X_ENC_MUTE_AUDIO 			0xda
-#define CX2341X_ENC_UNKNOWN			0xdb
+#define CX2341X_ENC_SET_VERT_CROP_LINE		0xdb
 #define CX2341X_ENC_MISC 			0xdc
 
 /* OSD API, specific to the cx23415 */
diff --git a/include/media/ivtv.h b/include/media/ivtv.h
new file mode 100644
index 0000000..412b48e
--- /dev/null
+++ b/include/media/ivtv.h
@@ -0,0 +1,65 @@
+/*
+    Public ivtv API header
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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_IVTV_H
+#define _LINUX_IVTV_H
+
+/* ivtv knows several distinct output modes: MPEG streaming,
+   YUV streaming, YUV updates through user DMA and the passthrough
+   mode.
+
+   In order to clearly tell the driver that we are in user DMA
+   YUV mode you need to call IVTV_IOC_DMA_FRAME with y_source == NULL
+   first (althrough if you don't then the first time
+   DMA_FRAME is called the mode switch is done automatically).
+
+   When you close the file handle the user DMA mode is exited again.
+
+   While in one mode, you cannot use another mode (EBUSY is returned).
+
+   All this means that if you want to change the YUV interlacing
+   for the user DMA YUV mode you first need to do call IVTV_IOC_DMA_FRAME
+   with y_source == NULL before you can set the correct format using
+   VIDIOC_S_FMT.
+
+   Eventually all this should be replaced with a proper V4L2 API,
+   but for now we have to do it this way. */
+
+struct ivtv_dma_frame {
+	enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_OUTPUT */
+	__u32 pixelformat;	 /* 0 == same as destination */
+	void __user *y_source;   /* if NULL and type == V4L2_BUF_TYPE_VIDEO_OUTPUT,
+				    then just switch to user DMA YUV output mode */
+	void __user *uv_source;  /* Unused for RGB pixelformats */
+	struct v4l2_rect src;
+	struct v4l2_rect dst;
+	__u32 src_width;
+	__u32 src_height;
+};
+
+#define IVTV_IOC_DMA_FRAME  _IOW ('V', BASE_VIDIOC_PRIVATE+0, struct ivtv_dma_frame)
+
+/* These are the VBI types as they appear in the embedded VBI private packets. */
+#define IVTV_SLICED_TYPE_TELETEXT_B     (1)
+#define IVTV_SLICED_TYPE_CAPTION_525    (4)
+#define IVTV_SLICED_TYPE_WSS_625        (5)
+#define IVTV_SLICED_TYPE_VPS            (7)
+
+#endif /* _LINUX_IVTV_H */
diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h
index 0f43451..05b9569 100644
--- a/include/media/ovcamchip.h
+++ b/include/media/ovcamchip.h
@@ -16,7 +16,6 @@ #define __LINUX_OVCAMCHIP_H
 
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
-#include <linux/i2c.h>
 
 /* --------------------------------- */
 /*           ENUMERATIONS            */
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 99acf84..6dcf3c4 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -23,6 +23,7 @@ #ifndef _TUNER_H
 #define _TUNER_H
 
 #include <linux/videodev2.h>
+#include <linux/i2c.h>
 #include <media/tuner-types.h>
 
 extern int tuner_debug;
@@ -177,6 +178,8 @@ struct tuner_setup {
 	unsigned short	addr; 	/* I2C address */
 	unsigned int	type;   /* Tuner type */
 	unsigned int	mode_mask;  /* Allowed tuner modes */
+	unsigned int	config; /* configuraion for more complex tuners */
+	int (*tuner_callback) (void *dev, int command,int arg);
 };
 
 struct tuner {
@@ -211,6 +214,9 @@ struct tuner {
 	unsigned char tda827x_ver;
 	unsigned int sgIF;
 
+	unsigned int config;
+	int (*tuner_callback) (void *dev, int command,int arg);
+
 	/* function ptrs */
 	void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
 	void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
new file mode 100644
index 0000000..09d16c4
--- /dev/null
+++ b/include/media/v4l2-chip-ident.h
@@ -0,0 +1,149 @@
+/*
+    v4l2 chip identifiers header
+
+    This header provides a list of chip identifiers that can be returned
+    through the VIDIOC_G_CHIP_IDENT ioctl.
+
+    Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU 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 V4L2_CHIP_IDENT_H_
+#define V4L2_CHIP_IDENT_H_
+
+/* VIDIOC_G_CHIP_IDENT: identifies the actual chip installed on the board */
+enum {
+	/* general idents: reserved range 0-49 */
+	V4L2_IDENT_NONE      = 0,       /* No chip matched */
+	V4L2_IDENT_AMBIGUOUS = 1,       /* Match too general, multiple chips matched */
+	V4L2_IDENT_UNKNOWN   = 2,       /* Chip found, but cannot identify */
+
+	/* module tvaudio: reserved range 50-99 */
+	V4L2_IDENT_TVAUDIO = 50,	/* A tvaudio chip, unknown which it is exactly */
+
+	/* 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,
+	V4L2_IDENT_SAA7129 = 159,
+
+	/* module cx25840: reserved range 200-249 */
+	V4L2_IDENT_CX25836 = 236,
+	V4L2_IDENT_CX25837 = 237,
+	V4L2_IDENT_CX25840 = 240,
+	V4L2_IDENT_CX25841 = 241,
+	V4L2_IDENT_CX25842 = 242,
+	V4L2_IDENT_CX25843 = 243,
+
+	/* OmniVision sensors: reserved range 250-299 */
+	V4L2_IDENT_OV7670 = 250,
+
+	/* Conexant MPEG encoder/decoders: reserved range 410-420 */
+	V4L2_IDENT_CX23415 = 415,
+	V4L2_IDENT_CX23416 = 416,
+
+	/* module wm8739: just ident 8739 */
+	V4L2_IDENT_WM8739 = 8739,
+
+	/* module wm8775: just ident 8775 */
+	V4L2_IDENT_WM8775 = 8775,
+
+	/* module cs53132a: just ident 53132 */
+	V4L2_IDENT_CS53l32A = 53132,
+
+	/* module upd64031a: just ident 64031 */
+	V4L2_IDENT_UPD64031A = 64031,
+
+	/* module upd64083: just ident 64083 */
+	V4L2_IDENT_UPD64083 = 64083,
+
+	/* module msp34xx: reserved range 34000-34999 */
+	V4L2_IDENT_MSP3400B = 34002,
+	V4L2_IDENT_MSP3410B = 34102,
+
+	V4L2_IDENT_MSP3400C = 34003,
+	V4L2_IDENT_MSP3410C = 34103,
+
+	V4L2_IDENT_MSP3400D = 34004,
+	V4L2_IDENT_MSP3410D = 34104,
+	V4L2_IDENT_MSP3405D = 34054,
+	V4L2_IDENT_MSP3415D = 34154,
+	V4L2_IDENT_MSP3407D = 34074,
+	V4L2_IDENT_MSP3417D = 34174,
+
+	V4L2_IDENT_MSP3400G = 34007,
+	V4L2_IDENT_MSP3410G = 34107,
+	V4L2_IDENT_MSP3420G = 34207,
+	V4L2_IDENT_MSP3430G = 34307,
+	V4L2_IDENT_MSP3440G = 34407,
+	V4L2_IDENT_MSP3450G = 34507,
+	V4L2_IDENT_MSP3460G = 34607,
+
+	V4L2_IDENT_MSP3401G = 34017,
+	V4L2_IDENT_MSP3411G = 34117,
+	V4L2_IDENT_MSP3421G = 34217,
+	V4L2_IDENT_MSP3431G = 34317,
+	V4L2_IDENT_MSP3441G = 34417,
+	V4L2_IDENT_MSP3451G = 34517,
+	V4L2_IDENT_MSP3461G = 34617,
+
+	V4L2_IDENT_MSP3402G = 34027,
+	V4L2_IDENT_MSP3412G = 34127,
+	V4L2_IDENT_MSP3422G = 34227,
+	V4L2_IDENT_MSP3442G = 34427,
+	V4L2_IDENT_MSP3452G = 34527,
+
+	V4L2_IDENT_MSP3405G = 34057,
+	V4L2_IDENT_MSP3415G = 34157,
+	V4L2_IDENT_MSP3425G = 34257,
+	V4L2_IDENT_MSP3435G = 34357,
+	V4L2_IDENT_MSP3445G = 34457,
+	V4L2_IDENT_MSP3455G = 34557,
+	V4L2_IDENT_MSP3465G = 34657,
+
+	V4L2_IDENT_MSP3407G = 34077,
+	V4L2_IDENT_MSP3417G = 34177,
+	V4L2_IDENT_MSP3427G = 34277,
+	V4L2_IDENT_MSP3437G = 34377,
+	V4L2_IDENT_MSP3447G = 34477,
+	V4L2_IDENT_MSP3457G = 34577,
+	V4L2_IDENT_MSP3467G = 34677,
+
+	/* module msp44xx: reserved range 44000-44999 */
+	V4L2_IDENT_MSP4400G = 44007,
+	V4L2_IDENT_MSP4410G = 44107,
+	V4L2_IDENT_MSP4420G = 44207,
+	V4L2_IDENT_MSP4440G = 44407,
+	V4L2_IDENT_MSP4450G = 44507,
+
+	V4L2_IDENT_MSP4408G = 44087,
+	V4L2_IDENT_MSP4418G = 44187,
+	V4L2_IDENT_MSP4428G = 44287,
+	V4L2_IDENT_MSP4448G = 44487,
+	V4L2_IDENT_MSP4458G = 44587,
+};
+
+#endif
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 6eaeec9..181a40c 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -98,6 +98,8 @@ u32 v4l2_ctrl_next(const u32 * const *ct
 
 struct i2c_client; /* forward reference */
 int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 id_type, u32 chip_id);
+int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip,
+		u32 ident, u32 revision);
 int v4l2_chip_match_host(u32 id_type, u32 chip_id);
 
 /* ------------------------------------------------------------------------- */
@@ -114,39 +116,6 @@ struct v4l2_decode_vbi_line {
 	u32 type;		/* VBI service type (V4L2_SLICED_*). 0 if no service found */
 };
 
-/* VIDIOC_INT_G_CHIP_IDENT: identifies the actual chip installed on the board */
-enum v4l2_chip_ident {
-	/* general idents: reserved range 0-49 */
-	V4L2_IDENT_UNKNOWN = 0,
-
-	/* 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,
-	V4L2_IDENT_SAA7129 = 159,
-
-	/* module cx25840: reserved range 200-249 */
-	V4L2_IDENT_CX25836 = 236,
-	V4L2_IDENT_CX25837 = 237,
-	V4L2_IDENT_CX25840 = 240,
-	V4L2_IDENT_CX25841 = 241,
-	V4L2_IDENT_CX25842 = 242,
-	V4L2_IDENT_CX25843 = 243,
-
-	/* OmniVision sensors - range 250-299 */
-	V4L2_IDENT_OV7670 = 250,
-};
-
 /* audio ioctls */
 
 /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
@@ -208,10 +177,6 @@ #define VIDIOC_INT_S_VBI_DATA 		_IOW ('d
    whether CC data from the first or second field should be obtained). */
 #define VIDIOC_INT_G_VBI_DATA 		_IOWR('d', 106, struct v4l2_sliced_vbi_data)
 
-/* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
-   be made. */
-#define VIDIOC_INT_G_CHIP_IDENT		_IOR ('d', 107, enum v4l2_chip_ident)
-
 /* Sets I2S speed in bps. This is used to provide a standard way to select I2S
    clock used by driving digital audio streams at some board designs.
    Usual values for the frequency are 1024000 and 2048000.
@@ -254,4 +219,12 @@ #define VIDIOC_INT_S_CRYSTAL_FREQ 	_IOW 
    default values. */
 #define VIDIOC_INT_INIT			_IOW ('d', 114, u32)
 
+/* Set v4l2_std_id for video OUTPUT devices. This is ignored by
+   video input devices. */
+#define VIDIOC_INT_S_STD_OUTPUT		_IOW  ('d', 115, v4l2_std_id)
+
+/* Get v4l2_std_id for video OUTPUT devices. This is ignored by
+   video input devices. */
+#define VIDIOC_INT_G_STD_OUTPUT		_IOW  ('d', 116, v4l2_std_id)
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 1dd3d32..d62847f 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -127,6 +127,8 @@ struct video_device
 					    struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_output_overlay) (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_vbi_output)  (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
@@ -145,6 +147,8 @@ struct video_device
 					struct v4l2_format *f);
 	int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_g_fmt_output_overlay) (struct file *file, void *fh,
+					struct v4l2_format *f);
 	int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
@@ -162,6 +166,8 @@ struct video_device
 					struct v4l2_format *f);
 	int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_s_fmt_output_overlay) (struct file *file, void *fh,
+					struct v4l2_format *f);
 	int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
 					struct v4l2_format *f);
 
@@ -178,6 +184,8 @@ struct video_device
 					  struct v4l2_format *f);
 	int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
 					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_output_overlay)(struct file *file, void *fh,
+					  struct v4l2_format *f);
 	int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
 					  struct v4l2_format *f);
 
@@ -309,6 +317,8 @@ #ifdef CONFIG_VIDEO_ADV_DEBUG
 	int (*vidioc_s_register)       (struct file *file, void *fh,
 					struct v4l2_register *reg);
 #endif
+	int (*vidioc_g_chip_ident)     (struct file *file, void *fh,
+					struct v4l2_chip_ident *chip);
 
 
 #ifdef OBSOLETE_OWNER /* to be removed soon */
diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild
index e0fe92b..4d46b3b 100644
--- a/include/mtd/Kbuild
+++ b/include/mtd/Kbuild
@@ -3,3 +3,5 @@ header-y += jffs2-user.h
 header-y += mtd-abi.h
 header-y += mtd-user.h
 header-y += nftl-user.h
+header-y += ubi-header.h
+header-y += ubi-user.h
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 8e501a7..f71dac4 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -24,6 +24,7 @@ #define MTD_ROM			2
 #define MTD_NORFLASH		3
 #define MTD_NANDFLASH		4
 #define MTD_DATAFLASH		6
+#define MTD_UBIVOLUME		7
 
 #define MTD_WRITEABLE		0x400	/* Device is writeable */
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h
new file mode 100644
index 0000000..fa479c7
--- /dev/null
+++ b/include/mtd/ubi-header.h
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Authors: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ *          Thomas Gleixner
+ *          Frank Haverkamp
+ *          Oliver Lohmann
+ *          Andreas Arnez
+ */
+
+/*
+ * This file defines the layout of UBI headers and all the other UBI on-flash
+ * data structures. May be included by user-space.
+ */
+
+#ifndef __UBI_HEADER_H__
+#define __UBI_HEADER_H__
+
+#include <asm/byteorder.h>
+
+/* The version of UBI images supported by this implementation */
+#define UBI_VERSION 1
+
+/* The highest erase counter value supported by this implementation */
+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
+
+/* The initial CRC32 value used when calculating CRC checksums */
+#define UBI_CRC32_INIT 0xFFFFFFFFU
+
+/* Erase counter header magic number (ASCII "UBI#") */
+#define UBI_EC_HDR_MAGIC  0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
+
+/*
+ * Volume type constants used in the volume identifier header.
+ *
+ * @UBI_VID_DYNAMIC: dynamic volume
+ * @UBI_VID_STATIC: static volume
+ */
+enum {
+	UBI_VID_DYNAMIC = 1,
+	UBI_VID_STATIC  = 2
+};
+
+/*
+ * Compatibility constants used by internal volumes.
+ *
+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written
+ * to the flash
+ * @UBI_COMPAT_RO: attach this device in read-only mode
+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
+ * physical eraseblocks, don't allow the wear-leveling unit to move them
+ * @UBI_COMPAT_REJECT: reject this UBI image
+ */
+enum {
+	UBI_COMPAT_DELETE   = 1,
+	UBI_COMPAT_RO       = 2,
+	UBI_COMPAT_PRESERVE = 4,
+	UBI_COMPAT_REJECT   = 5
+};
+
+/*
+ * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
+ * data structures.
+ */
+typedef struct {
+	uint16_t int16;
+} __attribute__ ((packed)) ubi16_t;
+
+typedef struct {
+	uint32_t int32;
+} __attribute__ ((packed)) ubi32_t;
+
+typedef struct {
+	uint64_t int64;
+} __attribute__ ((packed)) ubi64_t;
+
+/*
+ * In this implementation of UBI uses the big-endian format for on-flash
+ * integers. The below are the corresponding conversion macros.
+ */
+#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
+#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
+
+#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
+#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
+
+#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
+#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
+
+/* Sizes of UBI headers */
+#define UBI_EC_HDR_SIZE  sizeof(struct ubi_ec_hdr)
+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
+
+/* Sizes of UBI headers without the ending CRC */
+#define UBI_EC_HDR_SIZE_CRC  (UBI_EC_HDR_SIZE  - sizeof(ubi32_t))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
+
+/**
+ * struct ubi_ec_hdr - UBI erase counter header.
+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
+ * @version: version of UBI implementation which is supposed to accept this
+ * UBI image
+ * @padding1: reserved for future, zeroes
+ * @ec: the erase counter
+ * @vid_hdr_offset: where the VID header starts
+ * @data_offset: where the user data start
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: erase counter header CRC checksum
+ *
+ * The erase counter header takes 64 bytes and has a plenty of unused space for
+ * future usage. The unused fields are zeroed. The @version field is used to
+ * indicate the version of UBI implementation which is supposed to be able to
+ * work with this UBI image. If @version is greater then the current UBI
+ * version, the image is rejected. This may be useful in future if something
+ * is changed radically. This field is duplicated in the volume identifier
+ * header.
+ *
+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the
+ * volume identifier header and user data, relative to the beginning of the
+ * physical eraseblock. These values have to be the same for all physical
+ * eraseblocks.
+ */
+struct ubi_ec_hdr {
+	ubi32_t magic;
+	uint8_t version;
+	uint8_t padding1[3];
+	ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
+	ubi32_t vid_hdr_offset;
+	ubi32_t data_offset;
+	uint8_t padding2[36];
+	ubi32_t hdr_crc;
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
+ * @version: UBI implementation version which is supposed to accept this UBI
+ * image (%UBI_VERSION)
+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
+ * @copy_flag: if this logical eraseblock was copied from another physical
+ * eraseblock (for wear-leveling reasons)
+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
+ * @vol_id: ID of this volume
+ * @lnum: logical eraseblock number
+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be
+ * removed, kept only for not breaking older UBI users)
+ * @data_size: how many bytes of data this logical eraseblock contains
+ * @used_ebs: total number of used logical eraseblocks in this volume
+ * @data_pad: how many bytes at the end of this physical eraseblock are not
+ * used
+ * @data_crc: CRC checksum of the data stored in this logical eraseblock
+ * @padding1: reserved for future, zeroes
+ * @sqnum: sequence number
+ * @padding2: reserved for future, zeroes
+ * @hdr_crc: volume identifier header CRC checksum
+ *
+ * The @sqnum is the value of the global sequence counter at the time when this
+ * VID header was created. The global sequence counter is incremented each time
+ * UBI writes a new VID header to the flash, i.e. when it maps a logical
+ * eraseblock to a new physical eraseblock. The global sequence counter is an
+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum
+ * (sequence number) is used to distinguish between older and newer versions of
+ * logical eraseblocks.
+ *
+ * There are 2 situations when there may be more then one physical eraseblock
+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id
+ * and @lnum values in the volume identifier header. Suppose we have a logical
+ * eraseblock L and it is mapped to the physical eraseblock P.
+ *
+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following
+ * situation is possible: L is asynchronously erased, so P is scheduled for
+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
+ * so P1 is written to, then an unclean reboot happens. Result - there are 2
+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock
+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
+ * flash.
+ *
+ * 2. From time to time UBI moves logical eraseblocks to other physical
+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
+ * to P1, and an unclean reboot happens before P is physically erased, there
+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to
+ * select one of them when the flash is attached. The @sqnum field says which
+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But
+ * it is not enough to select the physical eraseblock with the higher sequence
+ * number, because the unclean reboot could have happen in the middle of the
+ * copying process, so the data in P is corrupted. It is also not enough to
+ * just select the physical eraseblock with lower sequence number, because the
+ * data there may be old (consider a case if more data was added to P1 after
+ * the copying). Moreover, the unclean reboot may happen when the erasure of P
+ * was just started, so it result in unstable P, which is "mostly" OK, but
+ * still has unstable bits.
+ *
+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a
+ * copy. UBI also calculates data CRC when the data is moved and stores it at
+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical
+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
+ * examined. If it is cleared, the situation* is simple and the newer one is
+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise
+ * the older one (P) is selected.
+ *
+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum
+ * in the past. But it is not used anymore and we keep it in order to be able
+ * to deal with old UBI images. It will be removed at some point.
+ *
+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes.
+ * Internal volumes are not seen from outside and are used for various internal
+ * UBI purposes. In this implementation there is only one internal volume - the
+ * layout volume. Internal volumes are the main mechanism of UBI extensions.
+ * For example, in future one may introduce a journal internal volume. Internal
+ * volumes have their own reserved range of IDs.
+ *
+ * The @compat field is only used for internal volumes and contains the "degree
+ * of their compatibility". It is always zero for user volumes. This field
+ * provides a mechanism to introduce UBI extensions and to be still compatible
+ * with older UBI binaries. For example, if someone introduced a journal in
+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the
+ * journal volume.  And in this case, older UBI binaries, which know nothing
+ * about the journal volume, would just delete this volume and work perfectly
+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
+ * - it just ignores the Ext3fs journal.
+ *
+ * The @data_crc field contains the CRC checksum of the contents of the logical
+ * eraseblock if this is a static volume. In case of dynamic volumes, it does
+ * not contain the CRC checksum as a rule. The only exception is when the
+ * data of the physical eraseblock was moved by the wear-leveling unit, then
+ * the wear-leveling unit calculates the data CRC and stores it in the
+ * @data_crc field. And of course, the @copy_flag is %in this case.
+ *
+ * The @data_size field is used only for static volumes because UBI has to know
+ * how many bytes of data are stored in this eraseblock. For dynamic volumes,
+ * this field usually contains zero. The only exception is when the data of the
+ * physical eraseblock was moved to another physical eraseblock for
+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the
+ * contents and uses both @data_crc and @data_size fields. In this case, the
+ * @data_size field contains data size.
+ *
+ * The @used_ebs field is used only for static volumes and indicates how many
+ * eraseblocks the data of the volume takes. For dynamic volumes this field is
+ * not used and always contains zero.
+ *
+ * The @data_pad is calculated when volumes are created using the alignment
+ * parameter. So, effectively, the @data_pad field reduces the size of logical
+ * eraseblocks of this volume. This is very handy when one uses block-oriented
+ * software (say, cramfs) on top of the UBI volume.
+ */
+struct ubi_vid_hdr {
+	ubi32_t magic;
+	uint8_t version;
+	uint8_t vol_type;
+	uint8_t copy_flag;
+	uint8_t compat;
+	ubi32_t vol_id;
+	ubi32_t lnum;
+	ubi32_t leb_ver; /* obsolete, to be removed, don't use */
+	ubi32_t data_size;
+	ubi32_t used_ebs;
+	ubi32_t data_pad;
+	ubi32_t data_crc;
+	uint8_t padding1[4];
+	ubi64_t sqnum;
+	uint8_t padding2[12];
+	ubi32_t hdr_crc;
+} __attribute__ ((packed));
+
+/* Internal UBI volumes count */
+#define UBI_INT_VOL_COUNT 1
+
+/*
+ * Starting ID of internal volumes. There is reserved room for 4096 internal
+ * volumes.
+ */
+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
+
+/* The layout volume contains the volume table */
+
+#define UBI_LAYOUT_VOL_ID        UBI_INTERNAL_VOL_START
+#define UBI_LAYOUT_VOLUME_EBS    2
+#define UBI_LAYOUT_VOLUME_NAME   "layout volume"
+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
+
+/* The maximum number of volumes per one UBI device */
+#define UBI_MAX_VOLUMES 128
+
+/* The maximum volume name length */
+#define UBI_VOL_NAME_MAX 127
+
+/* Size of the volume table record */
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+
+/* Size of the volume table record without the ending CRC */
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
+
+/**
+ * struct ubi_vtbl_record - a record in the volume table.
+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume
+ * @alignment: volume alignment
+ * @data_pad: how many bytes are unused at the end of the each physical
+ * eraseblock to satisfy the requested alignment
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @upd_marker: if volume update was started but not finished
+ * @name_len: volume name length
+ * @name: the volume name
+ * @padding2: reserved, zeroes
+ * @crc: a CRC32 checksum of the record
+ *
+ * The volume table records are stored in the volume table, which is stored in
+ * the layout volume. The layout volume consists of 2 logical eraseblock, each
+ * of which contains a copy of the volume table (i.e., the volume table is
+ * duplicated). The volume table is an array of &struct ubi_vtbl_record
+ * objects indexed by the volume ID.
+ *
+ * If the size of the logical eraseblock is large enough to fit
+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
+ * records. Otherwise, it contains as many records as it can fit (i.e., size of
+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
+ *
+ * The @upd_marker flag is used to implement volume update. It is set to %1
+ * before update and set to %0 after the update. So if the update operation was
+ * interrupted, UBI knows that the volume is corrupted.
+ *
+ * The @alignment field is specified when the volume is created and cannot be
+ * later changed. It may be useful, for example, when a block-oriented file
+ * system works on top of UBI. The @data_pad field is calculated using the
+ * logical eraseblock size and @alignment. The alignment must be multiple to the
+ * minimal flash I/O unit. If @alignment is 1, all the available space of
+ * the physical eraseblocks is used.
+ *
+ * Empty records contain all zeroes and the CRC checksum of those zeroes.
+ */
+struct ubi_vtbl_record {
+	ubi32_t reserved_pebs;
+	ubi32_t alignment;
+	ubi32_t data_pad;
+	uint8_t vol_type;
+	uint8_t upd_marker;
+	ubi16_t name_len;
+	uint8_t name[UBI_VOL_NAME_MAX+1];
+	uint8_t padding2[24];
+	ubi32_t crc;
+} __attribute__ ((packed));
+
+#endif /* !__UBI_HEADER_H__ */
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h
new file mode 100644
index 0000000..fe06ded
--- /dev/null
+++ b/include/mtd/ubi-user.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) International Business Machines Corp., 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
+ *
+ * Author: Artem Bityutskiy (Ð‘Ð¸Ñ‚ÑŽÑ†ÐºÐ¸Ð¹ ÐÑ€Ñ‚Ñ‘Ð¼)
+ */
+
+#ifndef __UBI_USER_H__
+#define __UBI_USER_H__
+
+/*
+ * UBI volume creation
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character
+ * device. A &struct ubi_mkvol_req object has to be properly filled and a
+ * pointer to it has to be passed to the IOCTL.
+ *
+ * UBI volume deletion
+ * ~~~~~~~~~~~~~~~~~~~
+ *
+ * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character
+ * device should be used. A pointer to the 32-bit volume ID hast to be passed
+ * to the IOCTL.
+ *
+ * UBI volume re-size
+ * ~~~~~~~~~~~~~~~~~~
+ *
+ * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character
+ * device should be used. A &struct ubi_rsvol_req object has to be properly
+ * filled and a pointer to it has to be passed to the IOCTL.
+ *
+ * UBI volume update
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the
+ * corresponding UBI volume character device. A pointer to a 64-bit update
+ * size should be passed to the IOCTL. After then, UBI expects user to write
+ * this number of bytes to the volume character device. The update is finished
+ * when the claimed number of bytes is passed. So, the volume update sequence
+ * is something like:
+ *
+ * fd = open("/dev/my_volume");
+ * ioctl(fd, UBI_IOCVOLUP, &image_size);
+ * write(fd, buf, image_size);
+ * close(fd);
+ */
+
+/*
+ * When a new volume is created, users may either specify the volume number they
+ * want to create or to let UBI automatically assign a volume number using this
+ * constant.
+ */
+#define UBI_VOL_NUM_AUTO (-1)
+
+/* Maximum volume name length */
+#define UBI_MAX_VOLUME_NAME 127
+
+/* IOCTL commands of UBI character devices */
+
+#define UBI_IOC_MAGIC 'o'
+
+/* Create an UBI volume */
+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
+/* Remove an UBI volume */
+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
+/* Re-size an UBI volume */
+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
+
+/* IOCTL commands of UBI volume character devices */
+
+#define UBI_VOL_IOC_MAGIC 'O'
+
+/* Start UBI volume update */
+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
+/* An eraseblock erasure command, used for debugging, disabled by default */
+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
+
+/*
+ * UBI volume type constants.
+ *
+ * @UBI_DYNAMIC_VOLUME: dynamic volume
+ * @UBI_STATIC_VOLUME:  static volume
+ */
+enum {
+	UBI_DYNAMIC_VOLUME = 3,
+	UBI_STATIC_VOLUME = 4
+};
+
+/**
+ * struct ubi_mkvol_req - volume description data structure used in
+ * volume creation requests.
+ * @vol_id: volume number
+ * @alignment: volume alignment
+ * @bytes: volume size in bytes
+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
+ * @padding1: reserved for future, not used
+ * @name_len: volume name length
+ * @padding2: reserved for future, not used
+ * @name: volume name
+ *
+ * This structure is used by userspace programs when creating new volumes. The
+ * @used_bytes field is only necessary when creating static volumes.
+ *
+ * The @alignment field specifies the required alignment of the volume logical
+ * eraseblock. This means, that the size of logical eraseblocks will be aligned
+ * to this number, i.e.,
+ *	(UBI device logical eraseblock size) mod (@alignment) = 0.
+ *
+ * To put it differently, the logical eraseblock of this volume may be slightly
+ * shortened in order to make it properly aligned. The alignment has to be
+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire
+ * available space of logical eraseblocks.
+ *
+ * The @alignment field may be useful, for example, when one wants to maintain
+ * a block device on top of an UBI volume. In this case, it is desirable to fit
+ * an integer number of blocks in logical eraseblocks of this UBI volume. With
+ * alignment it is possible to update this volume using plane UBI volume image
+ * BLOBs, without caring about how to properly align them.
+ */
+struct ubi_mkvol_req {
+	int32_t vol_id;
+	int32_t alignment;
+	int64_t bytes;
+	int8_t vol_type;
+	int8_t padding1;
+	int16_t name_len;
+	int8_t padding2[4];
+	char name[UBI_MAX_VOLUME_NAME+1];
+} __attribute__ ((packed));
+
+/**
+ * struct ubi_rsvol_req - a data structure used in volume re-size requests.
+ * @vol_id: ID of the volume to re-size
+ * @bytes: new size of the volume in bytes
+ *
+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic
+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be
+ * smaller then the number of bytes they bear. To arbitrarily shrink a static
+ * volume, it must be wiped out first (by means of volume update operation with
+ * zero number of bytes).
+ */
+struct ubi_rsvol_req {
+	int64_t bytes;
+	int32_t vol_id;
+} __attribute__ ((packed));
+
+#endif /* __UBI_USER_H__ */
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 88df8fc..f3531d0 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -73,7 +73,9 @@ extern int			ipv6_get_saddr(struct dst_e
 extern int			ipv6_dev_get_saddr(struct net_device *dev, 
 					       struct in6_addr *daddr,
 					       struct in6_addr *saddr);
-extern int			ipv6_get_lladdr(struct net_device *dev, struct in6_addr *);
+extern int			ipv6_get_lladdr(struct net_device *dev,
+						struct in6_addr *addr,
+						unsigned char banned_flags);
 extern int			ipv6_rcv_saddr_equal(const struct sock *sk, 
 						      const struct sock *sk2);
 extern void			addrconf_join_solict(struct net_device *dev,
diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
new file mode 100644
index 0000000..00c2eaa
--- /dev/null
+++ b/include/net/af_rxrpc.h
@@ -0,0 +1,57 @@
+/* RxRPC kernel service interface definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_RXRPC_H
+#define _NET_RXRPC_H
+
+#ifdef __KERNEL__
+
+#include <linux/rxrpc.h>
+
+struct rxrpc_call;
+
+/*
+ * the mark applied to socket buffers that may be intercepted
+ */
+enum {
+	RXRPC_SKB_MARK_DATA,		/* data message */
+	RXRPC_SKB_MARK_FINAL_ACK,	/* final ACK received message */
+	RXRPC_SKB_MARK_BUSY,		/* server busy message */
+	RXRPC_SKB_MARK_REMOTE_ABORT,	/* remote abort message */
+	RXRPC_SKB_MARK_NET_ERROR,	/* network error message */
+	RXRPC_SKB_MARK_LOCAL_ERROR,	/* local error message */
+	RXRPC_SKB_MARK_NEW_CALL,	/* local error message */
+};
+
+typedef void (*rxrpc_interceptor_t)(struct sock *, unsigned long,
+				    struct sk_buff *);
+extern void rxrpc_kernel_intercept_rx_messages(struct socket *,
+					       rxrpc_interceptor_t);
+extern struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
+						  struct sockaddr_rxrpc *,
+						  struct key *,
+						  unsigned long,
+						  gfp_t);
+extern int rxrpc_kernel_send_data(struct rxrpc_call *, struct msghdr *,
+				  size_t);
+extern void rxrpc_kernel_abort_call(struct rxrpc_call *, u32);
+extern void rxrpc_kernel_end_call(struct rxrpc_call *);
+extern bool rxrpc_kernel_is_data_last(struct sk_buff *);
+extern u32 rxrpc_kernel_get_abort_code(struct sk_buff *);
+extern int rxrpc_kernel_get_error_number(struct sk_buff *);
+extern void rxrpc_kernel_data_delivered(struct sk_buff *);
+extern void rxrpc_kernel_free_skb(struct sk_buff *);
+extern struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *,
+						   unsigned long);
+extern int rxrpc_kernel_reject_call(struct socket *);
+
+#endif /* __KERNEL__ */
+#endif /* _NET_RXRPC_H */
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 47ff2f4..99a4e36 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -263,8 +263,8 @@ static __inline__ void ax25_cb_put(ax25_
 static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	skb->dev      = dev;
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_HOST;
-	skb->mac.raw  = skb->data;
 	return htons(ETH_P_AX25);
 }
 
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 41456c1..93ce272 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -709,6 +709,24 @@ struct hci_sco_hdr {
 	__u8 	dlen;
 } __attribute__ ((packed));
 
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
+{
+	return (struct hci_event_hdr *)skb->data;
+}
+
+static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
+{
+	return (struct hci_acl_hdr *)skb->data;
+}
+
+static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
+{
+	return (struct hci_sco_hdr *)skb->data;
+}
+#endif
+
 /* Command opcode pack/unpack */
 #define hci_opcode_pack(ogf, ocf)	(__u16) ((ocf & 0x03ff)|(ogf << 10))
 #define hci_opcode_ogf(op)		(op >> 10)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
new file mode 100644
index 0000000..88171f8
--- /dev/null
+++ b/include/net/cfg80211.h
@@ -0,0 +1,40 @@
+#ifndef __NET_CFG80211_H
+#define __NET_CFG80211_H
+
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <net/genetlink.h>
+
+/*
+ * 802.11 configuration in-kernel interface
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/* from net/wireless.h */
+struct wiphy;
+
+/**
+ * struct cfg80211_ops - backend description for wireless configuration
+ *
+ * This struct is registered by fullmac card drivers and/or wireless stacks
+ * in order to handle configuration requests on their interfaces.
+ *
+ * All callbacks except where otherwise noted should return 0
+ * on success or a negative error code.
+ *
+ * All operations are currently invoked under rtnl for consistency with the
+ * wireless extensions but this is subject to reevaluation as soon as this
+ * code is used more widely and we have a first user without wext.
+ *
+ * @add_virtual_intf: create a new virtual interface with the given name
+ *
+ * @del_virtual_intf: remove the virtual interface determined by ifindex.
+ */
+struct cfg80211_ops {
+	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
+				    unsigned int type);
+	int	(*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
+};
+
+#endif /* __NET_CFG80211_H */
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index 4c9522c..4f90f55 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -120,7 +120,7 @@ #endif
  */
 
 #define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
-#define CIPSO_V4_OPTPTR(x) ((x)->nh.raw + IPCB(x)->opt.cipso)
+#define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso)
 
 /*
  * DOI List Functions
diff --git a/include/net/compat.h b/include/net/compat.h
index 9859b60..406db24 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -25,6 +25,7 @@ struct compat_cmsghdr {
 };
 
 extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int compat_sock_get_timestampns(struct sock *, struct timespec __user *);
 
 #else /* defined(CONFIG_COMPAT) */
 #define compat_msghdr	msghdr		/* to avoid compiler warnings */
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h
index f01626c..3012511 100644
--- a/include/net/dn_fib.h
+++ b/include/net/dn_fib.h
@@ -148,17 +148,8 @@ extern void dn_fib_rules_cleanup(void);
 extern unsigned dnet_addr_type(__le16 addr);
 extern int dn_fib_lookup(struct flowi *fl, struct dn_fib_res *res);
 
-/*
- * rtnetlink interface
- */
-extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb);
 
-extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
-
 extern void dn_fib_free_info(struct dn_fib_info *fi);
 
 static inline void dn_fib_info_put(struct dn_fib_info *fi)
diff --git a/include/net/dn_route.h b/include/net/dn_route.h
index a566944..c10e8e7 100644
--- a/include/net/dn_route.h
+++ b/include/net/dn_route.h
@@ -18,7 +18,6 @@ #define _NET_DN_ROUTE_H
 extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, gfp_t pri);
 extern int dn_route_output_sock(struct dst_entry **pprt, struct flowi *, struct sock *sk, int flags);
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-extern int dn_cache_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern void dn_rt_cache_flush(int delay);
 
 /* Masks for flags field */
diff --git a/include/net/esp.h b/include/net/esp.h
index 713d039..d05d8d2 100644
--- a/include/net/esp.h
+++ b/include/net/esp.h
@@ -40,8 +40,6 @@ struct esp_data
 	} auth;
 };
 
-extern int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len);
-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 int esp_mac_digest(struct esp_data *esp, struct sk_buff *skb,
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index d585ea9..ed3a887 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -5,7 +5,7 @@ #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/fib_rules.h>
 #include <net/flow.h>
-#include <net/netlink.h>
+#include <net/rtnetlink.h>
 
 struct fib_rule
 {
@@ -19,6 +19,8 @@ struct fib_rule
 	u32			flags;
 	u32			table;
 	u8			action;
+	u32			target;
+	struct fib_rule *	ctarget;
 	struct rcu_head		rcu;
 };
 
@@ -35,6 +37,8 @@ struct fib_rules_ops
 	struct list_head	list;
 	int			rule_size;
 	int			addr_size;
+	int			unresolved_rules;
+	int			nr_goto_rules;
 
 	int			(*action)(struct fib_rule *,
 					  struct flowi *, int,
@@ -55,6 +59,10 @@ struct fib_rules_ops
 	u32			(*default_pref)(void);
 	size_t			(*nlmsg_payload)(struct fib_rule *);
 
+	/* Called after modifications to the rules set, must flush
+	 * the route cache if one exists. */
+	void			(*flush_cache)(void);
+
 	int			nlgroup;
 	struct nla_policy	*policy;
 	struct list_head	*rules_list;
@@ -66,7 +74,8 @@ #define FRA_GENERIC_POLICY \
 	[FRA_PRIORITY]	= { .type = NLA_U32 }, \
 	[FRA_FWMARK]	= { .type = NLA_U32 }, \
 	[FRA_FWMASK]	= { .type = NLA_U32 }, \
-	[FRA_TABLE]     = { .type = NLA_U32 }
+	[FRA_TABLE]     = { .type = NLA_U32 }, \
+	[FRA_GOTO]	= { .type = NLA_U32 }
 
 static inline void fib_rule_get(struct fib_rule *rule)
 {
@@ -98,11 +107,4 @@ extern int			fib_rules_unregister(struct
 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 ce4b10d..f3cc1f8 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct fl
 extern void flow_cache_flush(void);
 extern atomic_t flow_cache_genid;
 
+static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2)
+{
+	return (fl1->proto == fl2->proto &&
+		!memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u)));
+}
+
 #endif
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index e02d85f..d56b292 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -6,8 +6,8 @@
  * LAN access point) driver for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index eb47641..b3d65e0 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 429b738..a0c2b41 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -66,7 +66,9 @@ #define PKTHDR_RADIOTAP_VERSION		0
  */
 #define IEEE80211_RADIOTAP_HDRLEN	64
 
-/* The radio capture header precedes the 802.11 header. */
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
 struct ieee80211_radiotap_header {
 	u8 it_version;		/* Version 0. Only increases
 				 * for drastic changes,
@@ -74,12 +76,12 @@ struct ieee80211_radiotap_header {
 				 * new fields does not count.
 				 */
 	u8 it_pad;
-	u16 it_len;		/* length of the whole
+	__le16 it_len;		/* length of the whole
 				 * header in bytes, including
 				 * it_version, it_pad,
 				 * it_len, and data fields.
 				 */
-	u32 it_present;		/* A bitmap telling which
+	__le32 it_present;	/* A bitmap telling which
 				 * fields are present. Set bit 31
 				 * (0x80000000) to extend the
 				 * bitmap by another 32 bits.
@@ -88,89 +90,102 @@ struct ieee80211_radiotap_header {
 				 */
 };
 
-/* Name                                 Data type       Units
- * ----                                 ---------       -----
+/* Name                                 Data type    Units
+ * ----                                 ---------    -----
  *
- * IEEE80211_RADIOTAP_TSFT              u64       microseconds
+ * IEEE80211_RADIOTAP_TSFT              __le64       microseconds
  *
  *      Value in microseconds of the MAC's 64-bit 802.11 Time
  *      Synchronization Function timer when the first bit of the
  *      MPDU arrived at the MAC. For received frames, only.
  *
- * IEEE80211_RADIOTAP_CHANNEL           2 x u16   MHz, bitmap
+ * IEEE80211_RADIOTAP_CHANNEL           2 x __le16   MHz, bitmap
  *
  *      Tx/Rx frequency in MHz, followed by flags (see below).
  *
- * IEEE80211_RADIOTAP_FHSS              u16       see below
+ * IEEE80211_RADIOTAP_FHSS              __le16       see below
  *
  *      For frequency-hopping radios, the hop set (first byte)
  *      and pattern (second byte).
  *
- * IEEE80211_RADIOTAP_RATE              u8        500kb/s
+ * IEEE80211_RADIOTAP_RATE              u8           500kb/s
  *
  *      Tx/Rx data rate
  *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL     s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      RF signal power at the antenna, decibel difference from
  *      one milliwatt.
  *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE      int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE      s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      RF noise power at the antenna, decibel difference from one
  *      milliwatt.
  *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8        decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL      u8           decibel (dB)
  *
  *      RF signal power at the antenna, decibel difference from an
  *      arbitrary, fixed reference.
  *
- * IEEE80211_RADIOTAP_DB_ANTNOISE       u8        decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTNOISE       u8           decibel (dB)
  *
  *      RF noise power at the antenna, decibel difference from an
  *      arbitrary, fixed reference point.
  *
- * IEEE80211_RADIOTAP_LOCK_QUALITY      u16       unitless
+ * IEEE80211_RADIOTAP_LOCK_QUALITY      __le16       unitless
  *
  *      Quality of Barker code lock. Unitless. Monotonically
  *      nondecreasing with "better" lock strength. Called "Signal
  *      Quality" in datasheets.  (Is there a standard way to measure
  *      this?)
  *
- * IEEE80211_RADIOTAP_TX_ATTENUATION    u16       unitless
+ * IEEE80211_RADIOTAP_TX_ATTENUATION    __le16       unitless
  *
  *      Transmit power expressed as unitless distance from max
  *      power set at factory calibration.  0 is max power.
  *      Monotonically nondecreasing with lower power levels.
  *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u16       decibels (dB)
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16       decibels (dB)
  *
  *      Transmit power expressed as decibel distance from max power
  *      set at factory calibration.  0 is max power.  Monotonically
  *      nondecreasing with lower power levels.
  *
- * IEEE80211_RADIOTAP_DBM_TX_POWER      int8_t          decibels from
- *                                                      one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_TX_POWER      s8           decibels from
+ *                                                   one milliwatt (dBm)
  *
  *      Transmit power expressed as dBm (decibels from a 1 milliwatt
  *      reference). This is the absolute power level measured at
  *      the antenna port.
  *
- * IEEE80211_RADIOTAP_FLAGS             u8        bitmap
+ * IEEE80211_RADIOTAP_FLAGS             u8           bitmap
  *
  *      Properties of transmitted and received frames. See flags
  *      defined below.
  *
- * IEEE80211_RADIOTAP_ANTENNA           u8        antenna index
+ * IEEE80211_RADIOTAP_ANTENNA           u8           antenna index
  *
  *      Unitless indication of the Rx/Tx antenna for this packet.
  *      The first antenna is antenna 0.
  *
- * IEEE80211_RADIOTAP_FCS           	u32       data
+ * IEEE80211_RADIOTAP_RX_FLAGS          __le16       bitmap
+ *
+ *     Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS          __le16       bitmap
+ *
+ *     Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES       u8           data
+ *
+ *     Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES      u8           data
+ *
+ *     Number of unicast retries a transmitted frame used.
  *
- *	FCS from frame in network byte order.
  */
 enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_TSFT = 0,
@@ -187,7 +202,11 @@ enum ieee80211_radiotap_type {
 	IEEE80211_RADIOTAP_ANTENNA = 11,
 	IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
 	IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
-	IEEE80211_RADIOTAP_EXT = 31,
+	IEEE80211_RADIOTAP_RX_FLAGS = 14,
+	IEEE80211_RADIOTAP_TX_FLAGS = 15,
+	IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+	IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+	IEEE80211_RADIOTAP_EXT = 31
 };
 
 /* Channel flags. */
@@ -219,6 +238,14 @@ #define	IEEE80211_RADIOTAP_F_DATAPAD	0x2
 						 * 802.11 header and payload
 						 * (to 32-bit boundary)
 						 */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS	0x0001	/* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL	0x0001	/* failed due to excessive
+						 * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
 
 /* Ugly macro to convert literal channel numbers into their mhz equivalents
  * There are certianly some conditions that will break this (like feeding it '30')
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index c28e424..668056b 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -19,6 +19,9 @@ #if defined(CONFIG_IPV6) || defined (CON
 #include <linux/in6.h>
 #include <linux/ipv6.h>
 #include <linux/types.h>
+#include <linux/jhash.h>
+
+#include <net/inet_sock.h>
 
 #include <net/ipv6.h>
 
@@ -28,12 +31,11 @@ struct inet_hashinfo;
 static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
 				const struct in6_addr *faddr, const __be16 fport)
 {
-	unsigned int hashent = (lport ^ (__force u16)fport);
+	u32 ports = (lport ^ (__force u16)fport);
 
-	hashent ^= (__force u32)(laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-	hashent ^= hashent >> 16;
-	hashent ^= hashent >> 8;
-	return hashent;
+	return jhash_3words((__force u32)laddr->s6_addr32[3],
+			    (__force u32)faddr->s6_addr32[3],
+			    ports, inet_ehash_secret);
 }
 
 static inline int inet6_sk_ehashfn(const struct sock *sk)
diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h
index 10117c8..de8399a 100644
--- a/include/net/inet_ecn.h
+++ b/include/net/inet_ecn.h
@@ -114,13 +114,13 @@ static inline int INET_ECN_set_ce(struct
 {
 	switch (skb->protocol) {
 	case __constant_htons(ETH_P_IP):
-		if (skb->nh.raw + sizeof(struct iphdr) <= skb->tail)
-			return IP_ECN_set_ce(skb->nh.iph);
+		if (skb->network_header + sizeof(struct iphdr) <= skb->tail)
+			return IP_ECN_set_ce(ip_hdr(skb));
 		break;
 
 	case __constant_htons(ETH_P_IPV6):
-		if (skb->nh.raw + sizeof(struct ipv6hdr) <= skb->tail)
-			return IP6_ECN_set_ce(skb->nh.ipv6h);
+		if (skb->network_header + sizeof(struct ipv6hdr) <= skb->tail)
+			return IP6_ECN_set_ce(ipv6_hdr(skb));
 		break;
 	}
 
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index ce6da97..62daf21 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -19,6 +19,7 @@ #define _INET_SOCK_H
 
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/jhash.h>
 
 #include <net/flow.h>
 #include <net/sock.h>
@@ -167,13 +168,15 @@ #endif
 
 extern int inet_sk_rebuild_header(struct sock *sk);
 
+extern u32 inet_ehash_secret;
+extern void build_ehash_secret(void);
+
 static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
 					const __be32 faddr, const __be16 fport)
 {
-	unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport);
-	h ^= h >> 16;
-	h ^= h >> 8;
-	return h;
+	return jhash_2words((__force __u32) laddr ^ (__force __u32) faddr,
+			    ((__u32) lport) << 16 | (__force __u32)fport,
+			    inet_ehash_secret);
 }
 
 static inline int inet_sk_ehashfn(const struct sock *sk)
diff --git a/include/net/ip.h b/include/net/ip.h
index e79c3e3..bb207db 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -25,6 +25,7 @@ #define _IP_H
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/in.h>
+#include <linux/skbuff.h>
 
 #include <net/inet_sock.h>
 #include <net/snmp.h>
@@ -43,6 +44,11 @@ #define IPSKB_FRAG_COMPLETE	8
 #define IPSKB_REROUTED		16
 };
 
+static inline unsigned int ip_hdrlen(const struct sk_buff *skb)
+{
+	return ip_hdr(skb)->ihl * 4;
+}
+
 struct ipcm_cookie
 {
 	__be32			addr;
@@ -74,7 +80,6 @@ struct msghdr;
 struct net_device;
 struct packet_type;
 struct rtable;
-struct sk_buff;
 struct sockaddr;
 
 extern void		ip_mc_dropsocket(struct sock *);
@@ -161,6 +166,10 @@ #define NET_INC_STATS_USER(field) 	SNMP_
 #define NET_ADD_STATS_BH(field, adnd)	SNMP_ADD_STATS_BH(net_statistics, field, adnd)
 #define NET_ADD_STATS_USER(field, adnd)	SNMP_ADD_STATS_USER(net_statistics, field, adnd)
 
+extern unsigned long snmp_fold_field(void *mib[], int offt);
+extern int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
+extern void snmp_mib_free(void *ptr[2]);
+
 extern int sysctl_local_port_range[2];
 extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index cf355a3..c48ea87 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -219,8 +219,6 @@ 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 4e927eb..5456fdd 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -116,12 +116,7 @@ extern void			rt6_pmtu_discovery(struct 
 						   struct net_device *dev,
 						   u32 pmtu);
 
-struct nlmsghdr;
 struct netlink_callback;
-extern int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
-extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
-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
 {
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 36c635c..5a4a036 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -215,10 +215,6 @@ #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(__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);
@@ -235,8 +231,6 @@ extern __be32  __fib_res_prefsrc(struct 
 extern struct fib_table *fib_hash_init(u32 id);
 
 #ifdef CONFIG_IP_MULTIPLE_TABLES
-extern int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb);
-
 extern void __init fib4_rules_init(void);
 
 #ifdef CONFIG_NET_CLS_ROUTE
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 00328b7..4fa5dfe 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -166,13 +166,6 @@ #define UDP6_INC_STATS_USER(field, is_ud
 	if (is_udplite) SNMP_INC_STATS_USER(udplite_stats_in6, field);         \
 	else		SNMP_INC_STATS_USER(udp_stats_in6, field);    } while(0)
 
-int snmp6_register_dev(struct inet6_dev *idev);
-int snmp6_unregister_dev(struct inet6_dev *idev);
-int snmp6_alloc_dev(struct inet6_dev *idev);
-int snmp6_free_dev(struct inet6_dev *idev);
-int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
-void snmp6_mib_free(void *ptr[2]);
-
 struct ip6_ra_chain
 {
 	struct ip6_ra_chain	*next;
@@ -211,9 +204,9 @@ struct ip6_flowlabel
 {
 	struct ip6_flowlabel	*next;
 	__be32			label;
+	atomic_t		users;
 	struct in6_addr		dst;
 	struct ipv6_txoptions	*opt;
-	atomic_t		users;
 	unsigned long		linger;
 	u8			share;
 	u32			owner;
@@ -298,7 +291,7 @@ static inline int ipv6_addr_src_scope(co
 
 static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
 {
-	return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
+	return memcmp(a1, a2, sizeof(struct in6_addr));
 }
 
 static inline int
@@ -315,7 +308,7 @@ ipv6_masked_addr_cmp(const struct in6_ad
 
 static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
 {
-	memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
+	memcpy(a1, a2, sizeof(struct in6_addr));
 }
 
 static inline void ipv6_addr_prefix(struct in6_addr *pfx, 
@@ -326,16 +319,12 @@ static inline void ipv6_addr_prefix(stru
 	int o = plen >> 3,
 	    b = plen & 0x7;
 
+	memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr));
 	memcpy(pfx->s6_addr, addr, o);
-	if (b != 0) {
+	if (b != 0)
 		pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
-		o++;
-	}
-	if (o < 16)
-		memset(pfx->s6_addr + o, 0, 16 - o);
 }
 
-#ifndef __HAVE_ARCH_ADDR_SET
 static inline void ipv6_addr_set(struct in6_addr *addr, 
 				     __be32 w1, __be32 w2,
 				     __be32 w3, __be32 w4)
@@ -345,7 +334,6 @@ static inline void ipv6_addr_set(struct 
 	addr->s6_addr32[2] = w3;
 	addr->s6_addr32[3] = w4;
 }
-#endif
 
 static inline int ipv6_addr_equal(const struct in6_addr *a1,
 				  const struct in6_addr *a2)
@@ -605,8 +593,20 @@ extern int  udplite6_proc_init(void);
 extern void udplite6_proc_exit(void);
 extern int  ipv6_misc_proc_init(void);
 extern void ipv6_misc_proc_exit(void);
+extern int snmp6_register_dev(struct inet6_dev *idev);
+extern int snmp6_unregister_dev(struct inet6_dev *idev);
 
 extern struct rt6_statistics rt6_stats;
+#else
+static inline int snmp6_register_dev(struct inet6_dev *idev)
+{
+	return 0;
+}
+
+static inline int snmp6_unregister_dev(struct inet6_dev *idev)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_SYSCTL
diff --git a/include/net/ipx.h b/include/net/ipx.h
index c6b2ee6..4cc0b4e 100644
--- a/include/net/ipx.h
+++ b/include/net/ipx.h
@@ -43,7 +43,7 @@ #define IPX_TYPE_PPROP		0x14	/* complica
 
 static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
 {
-	return (struct ipxhdr *)skb->h.raw;
+	return (struct ipxhdr *)skb_transport_header(skb);
 }
 
 struct ipx_interface {
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index 04d1abb..f9bd11b 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -28,6 +28,7 @@ enum {
 	IUCV_LISTEN,
 	IUCV_SEVERED,
 	IUCV_DISCONN,
+	IUCV_CLOSING,
 	IUCV_CLOSED
 };
 
@@ -62,6 +63,7 @@ struct iucv_sock {
 	struct sock		*parent;
 	struct iucv_path	*path;
 	struct sk_buff_head	send_skb_q;
+	struct sk_buff_head	backlog_skb_q;
 	unsigned int		send_tag;
 };
 
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
index 746e741..fd70adb 100644
--- a/include/net/iucv/iucv.h
+++ b/include/net/iucv/iucv.h
@@ -16,7 +16,7 @@
  * completed a register, it can exploit the other functions.
  * For furthur reference on all IUCV functionality, refer to the
  * CP Programming Services book, also available on the web thru
- * www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ * www.vm.ibm.com/pubs, manual # SC24-6084
  *
  * Definition of Return Codes
  * - All positive return codes including zero are reflected back
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h
index 8a83018..f23d07c 100644
--- a/include/net/iw_handler.h
+++ b/include/net/iw_handler.h
@@ -431,26 +431,7 @@ struct iw_public_data {
  * Those may be called only within the kernel.
  */
 
-/* First : function strictly used inside the kernel */
-
-/* Handle /proc/net/wireless, called in net/code/dev.c */
-extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-				 int length);
-
-/* Handle IOCTLs, called in net/core/dev.c */
-extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
-
-/* Handle RtNetlink requests, called in net/core/rtnetlink.c */
-extern int wireless_rtnetlink_set(struct net_device *	dev,
-				  char *		data,
-				  int			len);
-extern int wireless_rtnetlink_get(struct net_device *	dev,
-				  char *		data,
-				  int			len,
-				  char **		p_buf,
-				  int *			p_len);
-
-/* Second : functions that may be called by driver modules */
+/* functions that may be called by driver modules */
 
 /* Send a single event to user space */
 extern void wireless_send_event(struct net_device *	dev,
diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h
index aa33a47..4a8f58b 100644
--- a/include/net/llc_pdu.h
+++ b/include/net/llc_pdu.h
@@ -203,7 +203,7 @@ struct llc_pdu_sn {
 
 static inline struct llc_pdu_sn *llc_pdu_sn_hdr(struct sk_buff *skb)
 {
-	return (struct llc_pdu_sn *)skb->nh.raw;
+	return (struct llc_pdu_sn *)skb_network_header(skb);
 }
 
 /* Un-numbered PDU format (3 bytes in length) */
@@ -215,12 +215,7 @@ struct llc_pdu_un {
 
 static inline struct llc_pdu_un *llc_pdu_un_hdr(struct sk_buff *skb)
 {
-	return (struct llc_pdu_un *)skb->nh.raw;
-}
-
-static inline void *llc_set_pdu_hdr(struct sk_buff *skb, void *ptr)
-{
-	return skb->nh.raw = ptr;
+	return (struct llc_pdu_un *)skb_network_header(skb);
 }
 
 /**
@@ -237,7 +232,11 @@ static inline void llc_pdu_header_init(s
 				       u8 ssap, u8 dsap, u8 cr)
 {
 	const int hlen = type == LLC_PDU_TYPE_U ? 3 : 4;
-	struct llc_pdu_un *pdu = llc_set_pdu_hdr(skb, skb_push(skb, hlen));
+	struct llc_pdu_un *pdu;
+
+	skb_push(skb, hlen);
+	skb_reset_network_header(skb);
+	pdu = llc_pdu_un_hdr(skb);
 	pdu->dsap = dsap;
 	pdu->ssap = ssap;
 	pdu->ssap |= cr;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
new file mode 100644
index 0000000..a7f122b
--- /dev/null
+++ b/include/net/mac80211.h
@@ -0,0 +1,1045 @@
+/*
+ * Low-level hardware driver -- IEEE 802.11 driver (80211.o) interface
+ * Copyright 2002-2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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 MAC80211_H
+#define MAC80211_H
+
+#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <linux/device.h>
+#include <linux/ieee80211.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+
+/* Note! Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be
+ * called in hardware interrupt context. The low-level driver must not call any
+ * other functions in hardware interrupt context. If there is a need for such
+ * call, the low-level driver should first ACK the interrupt and perform the
+ * IEEE 802.11 code call after this, e.g., from a scheduled tasklet (in
+ * software interrupt context).
+ */
+
+/*
+ * Frame format used when passing frame between low-level hardware drivers
+ * and IEEE 802.11 driver the same as used in the wireless media, i.e.,
+ * buffers start with IEEE 802.11 header and include the same octets that
+ * are sent over air.
+ *
+ * If hardware uses IEEE 802.3 headers (and perform 802.3 <-> 802.11
+ * conversion in firmware), upper layer 802.11 code needs to be changed to
+ * support this.
+ *
+ * If the receive frame format is not the same as the real frame sent
+ * on the wireless media (e.g., due to padding etc.), upper layer 802.11 code
+ * could be updated to provide support for such format assuming this would
+ * optimize the performance, e.g., by removing need to re-allocation and
+ * copying of the data.
+ */
+
+#define IEEE80211_CHAN_W_SCAN 0x00000001
+#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002
+#define IEEE80211_CHAN_W_IBSS 0x00000004
+
+/* Channel information structure. Low-level driver is expected to fill in chan,
+ * freq, and val fields. Other fields will be filled in by 80211.o based on
+ * hostapd information and low-level driver does not need to use them. The
+ * limits for each channel will be provided in 'struct ieee80211_conf' when
+ * configuring the low-level driver with hw->config callback. If a device has
+ * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED
+ * can be set to let the driver configure all fields */
+struct ieee80211_channel {
+	short chan; /* channel number (IEEE 802.11) */
+	short freq; /* frequency in MHz */
+	int val; /* hw specific value for the channel */
+	int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+	unsigned char power_level;
+	unsigned char antenna_max;
+};
+
+#define IEEE80211_RATE_ERP 0x00000001
+#define IEEE80211_RATE_BASIC 0x00000002
+#define IEEE80211_RATE_PREAMBLE2 0x00000004
+#define IEEE80211_RATE_SUPPORTED 0x00000010
+#define IEEE80211_RATE_OFDM 0x00000020
+#define IEEE80211_RATE_CCK 0x00000040
+#define IEEE80211_RATE_TURBO 0x00000080
+#define IEEE80211_RATE_MANDATORY 0x00000100
+
+#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2)
+#define IEEE80211_RATE_MODULATION(f) \
+	(f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM))
+
+/* Low-level driver should set PREAMBLE2, OFDM, CCK, and TURBO flags.
+ * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the
+ * configuration. */
+struct ieee80211_rate {
+	int rate; /* rate in 100 kbps */
+	int val; /* hw specific value for the rate */
+	int flags; /* IEEE80211_RATE_ flags */
+	int val2; /* hw specific value for the rate when using short preamble
+		   * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for
+		   * 2, 5.5, and 11 Mbps) */
+	signed char min_rssi_ack;
+	unsigned char min_rssi_ack_delta;
+
+	/* following fields are set by 80211.o and need not be filled by the
+	 * low-level driver */
+	int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for
+		       * optimizing channel utilization estimates */
+};
+
+/* 802.11g is backwards-compatible with 802.11b, so a wlan card can
+ * actually be both in 11b and 11g modes at the same time. */
+enum {
+	MODE_IEEE80211A, /* IEEE 802.11a */
+	MODE_IEEE80211B, /* IEEE 802.11b only */
+	MODE_ATHEROS_TURBO, /* Atheros Turbo mode (2x.11a at 5 GHz) */
+	MODE_IEEE80211G, /* IEEE 802.11g (and 802.11b compatibility) */
+	MODE_ATHEROS_TURBOG, /* Atheros Turbo mode (2x.11g at 2.4 GHz) */
+
+	/* keep last */
+	NUM_IEEE80211_MODES
+};
+
+struct ieee80211_hw_mode {
+	int mode; /* MODE_IEEE80211... */
+	int num_channels; /* Number of channels (below) */
+	struct ieee80211_channel *channels; /* Array of supported channels */
+	int num_rates; /* Number of rates (below) */
+	struct ieee80211_rate *rates; /* Array of supported rates */
+
+	struct list_head list; /* Internal, don't touch */
+};
+
+struct ieee80211_tx_queue_params {
+	int aifs; /* 0 .. 255; -1 = use default */
+	int cw_min; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */
+	int cw_max; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */
+	int burst_time; /* maximum burst time in 0.1 ms (i.e., 10 = 1 ms);
+			 * 0 = disabled */
+};
+
+struct ieee80211_tx_queue_stats_data {
+	unsigned int len; /* num packets in queue */
+	unsigned int limit; /* queue len (soft) limit */
+	unsigned int count; /* total num frames sent */
+};
+
+enum {
+	IEEE80211_TX_QUEUE_DATA0,
+	IEEE80211_TX_QUEUE_DATA1,
+	IEEE80211_TX_QUEUE_DATA2,
+	IEEE80211_TX_QUEUE_DATA3,
+	IEEE80211_TX_QUEUE_DATA4,
+	IEEE80211_TX_QUEUE_SVP,
+
+	NUM_TX_DATA_QUEUES,
+
+/* due to stupidity in the sub-ioctl userspace interface, the items in
+ * this struct need to have fixed values. As soon as it is removed, we can
+ * fix these entries. */
+	IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+	IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+struct ieee80211_tx_queue_stats {
+	struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+};
+
+struct ieee80211_low_level_stats {
+	unsigned int dot11ACKFailureCount;
+	unsigned int dot11RTSFailureCount;
+	unsigned int dot11FCSErrorCount;
+	unsigned int dot11RTSSuccessCount;
+};
+
+/* Transmit control fields. This data structure is passed to low-level driver
+ * with each TX frame. The low-level driver is responsible for configuring
+ * the hardware to use given values (depending on what is supported). */
+#define HW_KEY_IDX_INVALID -1
+
+struct ieee80211_tx_control {
+	int tx_rate; /* Transmit rate, given as the hw specific value for the
+		      * rate (from struct ieee80211_rate) */
+	int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
+			   * specific value for the rate (from
+			   * struct ieee80211_rate) */
+
+#define IEEE80211_TXCTL_REQ_TX_STATUS	(1<<0)/* request TX status callback for
+						* this frame */
+#define IEEE80211_TXCTL_DO_NOT_ENCRYPT	(1<<1) /* send this frame without
+						* encryption; e.g., for EAPOL
+						* frames */
+#define IEEE80211_TXCTL_USE_RTS_CTS	(1<<2) /* use RTS-CTS before sending
+						* frame */
+#define IEEE80211_TXCTL_USE_CTS_PROTECT	(1<<3) /* use CTS protection for the
+						* frame (e.g., for combined
+						* 802.11g / 802.11b networks) */
+#define IEEE80211_TXCTL_NO_ACK		(1<<4) /* tell the low level not to
+						* wait for an ack */
+#define IEEE80211_TXCTL_RATE_CTRL_PROBE	(1<<5)
+#define IEEE80211_TXCTL_CLEAR_DST_MASK	(1<<6)
+#define IEEE80211_TXCTL_REQUEUE		(1<<7)
+#define IEEE80211_TXCTL_FIRST_FRAGMENT	(1<<8) /* this is a first fragment of
+						* the frame */
+#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
+	u32 flags;			       /* tx control flags defined
+						* above */
+	u8 retry_limit;		/* 1 = only first attempt, 2 = one retry, .. */
+	u8 power_level;		/* per-packet transmit power level, in dBm */
+	u8 antenna_sel_tx; 	/* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+	s8 key_idx;		/* -1 = do not encrypt, >= 0 keyidx from
+				 * hw->set_key() */
+	u8 icv_len;		/* length of the ICV/MIC field in octets */
+	u8 iv_len;		/* length of the IV field in octets */
+	u8 tkip_key[16];	/* generated phase2/phase1 key for hw TKIP */
+	u8 queue;		/* hardware queue to use for this frame;
+				 * 0 = highest, hw->queues-1 = lowest */
+	u8 sw_retry_attempt;	/* number of times hw has tried to
+				 * transmit frame (not incl. hw retries) */
+
+	struct ieee80211_rate *rate;		/* internal 80211.o rate */
+	struct ieee80211_rate *rts_rate;	/* internal 80211.o rate
+						 * for RTS/CTS */
+	int alt_retry_rate; /* retry rate for the last retries, given as the
+			     * hw specific value for the rate (from
+			     * struct ieee80211_rate). To be used to limit
+			     * packet dropping when probing higher rates, if hw
+			     * supports multiple retry rates. -1 = not used */
+	int type;	/* internal */
+	int ifindex;	/* internal */
+};
+
+/* Receive status. The low-level driver should provide this information
+ * (the subset supported by hardware) to the 802.11 code with each received
+ * frame. */
+struct ieee80211_rx_status {
+	u64 mactime;
+	int freq; /* receive frequency in Mhz */
+	int channel;
+	int phymode;
+	int ssi;
+	int signal; /* used as qual in statistics reporting */
+	int noise;
+	int antenna;
+	int rate;
+#define RX_FLAG_MMIC_ERROR	(1<<0)
+#define RX_FLAG_DECRYPTED	(1<<1)
+#define RX_FLAG_RADIOTAP	(1<<2)
+	int flag;
+};
+
+/* Transmit status. The low-level driver should provide this information
+ * (the subset supported by hardware) to the 802.11 code for each transmit
+ * frame. */
+struct ieee80211_tx_status {
+	/* copied ieee80211_tx_control structure */
+	struct ieee80211_tx_control control;
+
+#define IEEE80211_TX_STATUS_TX_FILTERED	(1<<0)
+#define IEEE80211_TX_STATUS_ACK		(1<<1) /* whether the TX frame was ACKed */
+	u32 flags;		/* tx staus flags defined above */
+
+	int ack_signal; /* measured signal strength of the ACK frame */
+	int excessive_retries;
+	int retry_count;
+
+	int queue_length;      /* information about TX queue */
+	int queue_number;
+};
+
+
+/**
+ * struct ieee80211_conf - configuration of the device
+ *
+ * This struct indicates how the driver shall configure the hardware.
+ *
+ * @radio_enabled: when zero, driver is required to switch off the radio.
+ */
+struct ieee80211_conf {
+	int channel;			/* IEEE 802.11 channel number */
+	int freq;			/* MHz */
+	int channel_val;		/* hw specific value for the channel */
+
+	int phymode;			/* MODE_IEEE80211A, .. */
+	struct ieee80211_channel *chan;
+	struct ieee80211_hw_mode *mode;
+	unsigned int regulatory_domain;
+	int radio_enabled;
+
+	int beacon_int;
+
+#define IEEE80211_CONF_SHORT_SLOT_TIME	(1<<0) /* use IEEE 802.11g Short Slot
+						* Time */
+#define IEEE80211_CONF_SSID_HIDDEN	(1<<1) /* do not broadcast the ssid */
+#define IEEE80211_CONF_RADIOTAP		(1<<2) /* use radiotap if supported
+						  check this bit at RX time */
+	u32 flags;			/* configuration flags defined above */
+
+	u8 power_level;			/* transmit power limit for current
+					 * regulatory domain; in dBm */
+	u8 antenna_max;			/* maximum antenna gain */
+	short tx_power_reduction; /* in 0.1 dBm */
+
+	/* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+	u8 antenna_sel_tx;
+	u8 antenna_sel_rx;
+
+	int antenna_def;
+	int antenna_mode;
+
+	/* Following five fields are used for IEEE 802.11H */
+	unsigned int radar_detect;
+	unsigned int spect_mgmt;
+	/* All following fields are currently unused. */
+	unsigned int quiet_duration; /* duration of quiet period */
+	unsigned int quiet_offset; /* how far into the beacon is the quiet
+				    * period */
+	unsigned int quiet_period;
+	u8 radar_firpwr_threshold;
+	u8 radar_rssi_threshold;
+	u8 pulse_height_threshold;
+	u8 pulse_rssi_threshold;
+	u8 pulse_inband_threshold;
+};
+
+/**
+ * enum ieee80211_if_types - types of 802.11 network interfaces
+ *
+ * @IEEE80211_IF_TYPE_AP: interface in AP mode.
+ * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap
+ *	daemon. Drivers should never see this type.
+ * @IEEE80211_IF_TYPE_STA: interface in STA (client) mode.
+ * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
+ * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
+ * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
+ * @IEEE80211_IF_TYPE_VLAN: not used.
+ */
+enum ieee80211_if_types {
+	IEEE80211_IF_TYPE_AP = 0x00000000,
+	IEEE80211_IF_TYPE_MGMT = 0x00000001,
+	IEEE80211_IF_TYPE_STA = 0x00000002,
+	IEEE80211_IF_TYPE_IBSS = 0x00000003,
+	IEEE80211_IF_TYPE_MNTR = 0x00000004,
+	IEEE80211_IF_TYPE_WDS = 0x5A580211,
+	IEEE80211_IF_TYPE_VLAN = 0x00080211,
+};
+
+/**
+ * struct ieee80211_if_init_conf - initial configuration of an interface
+ *
+ * @if_id: internal interface ID. This number has no particular meaning to
+ *	drivers and the only allowed usage is to pass it to
+ *	ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
+ *	This field is not valid for monitor interfaces
+ *	(interfaces of %IEEE80211_IF_TYPE_MNTR type).
+ * @type: one of &enum ieee80211_if_types constants. Determines the type of
+ *	added/removed interface.
+ * @mac_addr: pointer to MAC address of the interface. This pointer is valid
+ *	until the interface is removed (i.e. it cannot be used after
+ *	remove_interface() callback was called for this interface).
+ *
+ * This structure is used in add_interface() and remove_interface()
+ * callbacks of &struct ieee80211_hw.
+ */
+struct ieee80211_if_init_conf {
+	int if_id;
+	int type;
+	void *mac_addr;
+};
+
+/**
+ * struct ieee80211_if_conf - configuration of an interface
+ *
+ * @type: type of the interface. This is always the same as was specified in
+ *	&struct ieee80211_if_init_conf. The type of an interface never changes
+ *	during the life of the interface; this field is present only for
+ *	convenience.
+ * @bssid: BSSID of the network we are associated to/creating.
+ * @ssid: used (together with @ssid_len) by drivers for hardware that
+ *	generate beacons independently. The pointer is valid only during the
+ *	config_interface() call, so copy the value somewhere if you need
+ *	it.
+ * @ssid_len: length of the @ssid field.
+ * @generic_elem: used (together with @generic_elem_len) by drivers for
+ *	hardware that generate beacons independently. The pointer is valid
+ *	only during the config_interface() call, so copy the value somewhere
+ *	if you need it.
+ * @generic_elem_len: length of the generic element.
+ * @beacon: beacon template. Valid only if @host_gen_beacon_template in
+ *	&struct ieee80211_hw is set. The driver is responsible of freeing
+ *	the sk_buff.
+ * @beacon_control: tx_control for the beacon template, this field is only
+ *	valid when the @beacon field was set.
+ *
+ * This structure is passed to the config_interface() callback of
+ * &struct ieee80211_hw.
+ */
+struct ieee80211_if_conf {
+	int type;
+	u8 *bssid;
+	u8 *ssid;
+	size_t ssid_len;
+	u8 *generic_elem;
+	size_t generic_elem_len;
+	struct sk_buff *beacon;
+	struct ieee80211_tx_control *beacon_control;
+};
+
+typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL }
+ieee80211_key_alg;
+
+
+struct ieee80211_key_conf {
+
+	int hw_key_idx;			/* filled + used by low-level driver */
+	ieee80211_key_alg alg;
+	int keylen;
+
+#define IEEE80211_KEY_FORCE_SW_ENCRYPT (1<<0) /* to be cleared by low-level
+						 driver */
+#define IEEE80211_KEY_DEFAULT_TX_KEY   (1<<1) /* This key is the new default TX
+						 key (used only for broadcast
+						 keys). */
+#define IEEE80211_KEY_DEFAULT_WEP_ONLY (1<<2) /* static WEP is the only
+						 configured security policy;
+						 this allows some low-level
+						 drivers to determine when
+						 hwaccel can be used */
+	u32 flags; /* key configuration flags defined above */
+
+	s8 keyidx;			/* WEP key index */
+	u8 key[0];
+};
+
+#define IEEE80211_SEQ_COUNTER_RX	0
+#define IEEE80211_SEQ_COUNTER_TX	1
+
+typedef enum {
+	SET_KEY, DISABLE_KEY, REMOVE_ALL_KEYS,
+} set_key_cmd;
+
+/* This is driver-visible part of the per-hw state the stack keeps. */
+struct ieee80211_hw {
+	/* points to the cfg80211 wiphy for this piece. Note
+	 * that you must fill in the perm_addr and dev fields
+	 * of this structure, use the macros provided below. */
+	struct wiphy *wiphy;
+
+	/* assigned by mac80211, don't write */
+	struct ieee80211_conf conf;
+
+	/* Single thread workqueue available for driver use
+	 * Allocated by mac80211 on registration */
+	struct workqueue_struct *workqueue;
+
+	/* Pointer to the private area that was
+	 * allocated with this struct for you. */
+	void *priv;
+
+	/* The rest is information about your hardware */
+
+	/* TODO: frame_type 802.11/802.3, sw_encryption requirements */
+
+	/* Some wireless LAN chipsets generate beacons in the hardware/firmware
+	 * and others rely on host generated beacons. This option is used to
+	 * configure the upper layer IEEE 802.11 module to generate beacons.
+	 * The low-level driver can use ieee80211_beacon_get() to fetch the
+	 * next beacon frame. */
+#define IEEE80211_HW_HOST_GEN_BEACON (1<<0)
+
+	/* The device needs to be supplied with a beacon template only. */
+#define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1)
+
+	/* Some devices handle decryption internally and do not
+	 * indicate whether the frame was encrypted (unencrypted frames
+	 * will be dropped by the hardware, unless specifically allowed
+	 * through) */
+#define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2)
+
+	/* Whether RX frames passed to ieee80211_rx() include FCS in the end */
+#define IEEE80211_HW_RX_INCLUDES_FCS (1<<3)
+
+	/* Some wireless LAN chipsets buffer broadcast/multicast frames for
+	 * power saving stations in the hardware/firmware and others rely on
+	 * the host system for such buffering. This option is used to
+	 * configure the IEEE 802.11 upper layer to buffer broadcast/multicast
+	 * frames when there are power saving stations so that low-level driver
+	 * can fetch them with ieee80211_get_buffered_bc(). */
+#define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4)
+
+#define IEEE80211_HW_WEP_INCLUDE_IV (1<<5)
+
+	/* will data nullfunc frames get proper TX status callback */
+#define IEEE80211_HW_DATA_NULLFUNC_ACK (1<<6)
+
+	/* Force software encryption for TKIP packets if WMM is enabled. */
+#define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7)
+
+	/* Some devices handle Michael MIC internally and do not include MIC in
+	 * the received packets passed up. device_strips_mic must be set
+	 * for such devices. The 'encryption' frame control bit is expected to
+	 * be still set in the IEEE 802.11 header with this option unlike with
+	 * the device_hides_wep configuration option.
+	 */
+#define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8)
+
+	/* Device is capable of performing full monitor mode even during
+	 * normal operation. */
+#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+
+	/* Device does not need BSSID filter set to broadcast in order to
+	 * receive all probe responses while scanning */
+#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10)
+
+	/* Channels are already configured to the default regulatory domain
+	 * specified in the device's EEPROM */
+#define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11)
+
+	/* calculate Michael MIC for an MSDU when doing hwcrypto */
+#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12)
+	/* Do TKIP phase1 key mixing in stack to support cards only do
+	 * phase2 key mixing when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13)
+	/* Do TKIP phase1 and phase2 key mixing in stack and send the generated
+	 * per-packet RC4 key with each TX frame when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14)
+
+	u32 flags;			/* hardware flags defined above */
+
+	/* Set to the size of a needed device specific skb headroom for TX skbs. */
+	unsigned int extra_tx_headroom;
+
+	/* This is the time in us to change channels
+	 */
+	int channel_change_time;
+	/* Maximum values for various statistics.
+	 * Leave at 0 to indicate no support. Use negative numbers for dBm. */
+	s8 max_rssi;
+	s8 max_signal;
+	s8 max_noise;
+
+	/* Number of available hardware TX queues for data packets.
+	 * WMM requires at least four queues. */
+	int queues;
+};
+
+static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev)
+{
+	set_wiphy_dev(hw->wiphy, dev);
+}
+
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+{
+	memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
+}
+
+/* Configuration block used by the low-level driver to tell the 802.11 code
+ * about supported hardware features and to pass function pointers to callback
+ * functions. */
+struct ieee80211_ops {
+	/* Handler that 802.11 module calls for each transmitted frame.
+	 * skb contains the buffer starting from the IEEE 802.11 header.
+	 * The low-level driver should send the frame out based on
+	 * configuration in the TX control data.
+	 * Must be atomic. */
+	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
+		  struct ieee80211_tx_control *control);
+
+	/* Handler for performing hardware reset. */
+	int (*reset)(struct ieee80211_hw *hw);
+
+	/* Handler that is called when any netdevice attached to the hardware
+	 * device is set UP for the first time. This can be used, e.g., to
+	 * enable interrupts and beacon sending. */
+	int (*open)(struct ieee80211_hw *hw);
+
+	/* Handler that is called when the last netdevice attached to the
+	 * hardware device is set DOWN. This can be used, e.g., to disable
+	 * interrupts and beacon sending. */
+	int (*stop)(struct ieee80211_hw *hw);
+
+	/* Handler for asking a driver if a new interface can be added (or,
+	 * more exactly, set UP). If the handler returns zero, the interface
+	 * is added. Driver should perform any initialization it needs prior
+	 * to returning zero. By returning non-zero addition of the interface
+	 * is inhibited. Unless monitor_during_oper is set, it is guaranteed
+	 * that monitor interfaces and normal interfaces are mutually
+	 * exclusive. The open() handler is called after add_interface()
+	 * if this is the first device added. At least one of the open()
+	 * open() and add_interface() callbacks has to be assigned. If
+	 * add_interface() is NULL, one STA interface is permitted only. */
+	int (*add_interface)(struct ieee80211_hw *hw,
+			     struct ieee80211_if_init_conf *conf);
+
+	/* Notify a driver that an interface is going down. The stop() handler
+	 * is called prior to this if this is a last interface. */
+	void (*remove_interface)(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf);
+
+	/* Handler for configuration requests. IEEE 802.11 code calls this
+	 * function to change hardware configuration, e.g., channel. */
+	int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+	/* Handler for configuration requests related to interfaces (e.g.
+	 * BSSID). */
+	int (*config_interface)(struct ieee80211_hw *hw,
+				int if_id, struct ieee80211_if_conf *conf);
+
+	/* ieee80211 drivers do not have access to the &struct net_device
+	 * that is (are) connected with their device. Hence (and because
+	 * we need to combine the multicast lists and flags for multiple
+	 * virtual interfaces), they cannot assign set_multicast_list.
+	 * The parameters here replace dev->flags and dev->mc_count,
+	 * dev->mc_list is replaced by calling ieee80211_get_mc_list_item.
+	 * Must be atomic. */
+	void (*set_multicast_list)(struct ieee80211_hw *hw,
+				   unsigned short flags, int mc_count);
+
+	/* Set TIM bit handler. If the hardware/firmware takes care of beacon
+	 * generation, IEEE 802.11 code uses this function to tell the
+	 * low-level to set (or clear if set==0) TIM bit for the given aid. If
+	 * host system is used to generate beacons, this handler is not used
+	 * and low-level driver should set it to NULL.
+	 * Must be atomic. */
+	int (*set_tim)(struct ieee80211_hw *hw, int aid, int set);
+
+	/* Set encryption key. IEEE 802.11 module calls this function to set
+	 * encryption keys. addr is ff:ff:ff:ff:ff:ff for default keys and
+	 * station hwaddr for individual keys. aid of the station is given
+	 * to help low-level driver in selecting which key->hw_key_idx to use
+	 * for this key. TX control data will use the hw_key_idx selected by
+	 * the low-level driver.
+	 * Must be atomic. */
+	int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd,
+		       u8 *addr, struct ieee80211_key_conf *key, int aid);
+
+	/* Set TX key index for default/broadcast keys. This is needed in cases
+	 * where wlan card is doing full WEP/TKIP encapsulation (wep_include_iv
+	 * is not set), in other cases, this function pointer can be set to
+	 * NULL since the IEEE 802. 11 module takes care of selecting the key
+	 * index for each TX frame. */
+	int (*set_key_idx)(struct ieee80211_hw *hw, int idx);
+
+	/* Enable/disable IEEE 802.1X. This item requests wlan card to pass
+	 * unencrypted EAPOL-Key frames even when encryption is configured.
+	 * If the wlan card does not require such a configuration, this
+	 * function pointer can be set to NULL. */
+	int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
+
+	/* Set port authorization state (IEEE 802.1X PAE) to be authorized
+	 * (authorized=1) or unauthorized (authorized=0). This function can be
+	 * used if the wlan hardware or low-level driver implements PAE.
+	 * 80211.o module will anyway filter frames based on authorization
+	 * state, so this function pointer can be NULL if low-level driver does
+	 * not require event notification about port state changes.
+	 * Currently unused. */
+	int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
+			     int authorized);
+
+	/* Ask the hardware to service the scan request, no need to start
+	 * the scan state machine in stack. */
+	int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
+
+	/* return low-level statistics */
+	int (*get_stats)(struct ieee80211_hw *hw,
+			 struct ieee80211_low_level_stats *stats);
+
+	/* For devices that generate their own beacons and probe response
+	 * or association responses this updates the state of privacy_invoked
+	 * returns 0 for success or an error number */
+	int (*set_privacy_invoked)(struct ieee80211_hw *hw,
+				   int privacy_invoked);
+
+	/* For devices that have internal sequence counters, allow 802.11
+	 * code to access the current value of a counter */
+	int (*get_sequence_counter)(struct ieee80211_hw *hw,
+				    u8* addr, u8 keyidx, u8 txrx,
+				    u32* iv32, u16* iv16);
+
+	/* Configuration of RTS threshold (if device needs it) */
+	int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
+
+	/* Configuration of fragmentation threshold.
+	 * Assign this if the device does fragmentation by itself,
+	 * if this method is assigned then the stack will not do
+	 * fragmentation. */
+	int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
+
+	/* Configuration of retry limits (if device needs it) */
+	int (*set_retry_limit)(struct ieee80211_hw *hw,
+			       u32 short_retry, u32 long_retr);
+
+	/* Number of STAs in STA table notification (NULL = disabled).
+	 * Must be atomic. */
+	void (*sta_table_notification)(struct ieee80211_hw *hw,
+				       int num_sta);
+
+	/* Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
+	 * bursting) for a hardware TX queue.
+	 * queue = IEEE80211_TX_QUEUE_*.
+	 * Must be atomic. */
+	int (*conf_tx)(struct ieee80211_hw *hw, int queue,
+		       const struct ieee80211_tx_queue_params *params);
+
+	/* Get statistics of the current TX queue status. This is used to get
+	 * number of currently queued packets (queue length), maximum queue
+	 * size (limit), and total number of packets sent using each TX queue
+	 * (count).
+	 * Currently unused. */
+	int (*get_tx_stats)(struct ieee80211_hw *hw,
+			    struct ieee80211_tx_queue_stats *stats);
+
+	/* Get the current TSF timer value from firmware/hardware. Currently,
+	 * this is only used for IBSS mode debugging and, as such, is not a
+	 * required function.
+	 * Must be atomic. */
+	u64 (*get_tsf)(struct ieee80211_hw *hw);
+
+	/* Reset the TSF timer and allow firmware/hardware to synchronize with
+	 * other STAs in the IBSS. This is only used in IBSS mode. This
+	 * function is optional if the firmware/hardware takes full care of
+	 * TSF synchronization. */
+	void (*reset_tsf)(struct ieee80211_hw *hw);
+
+	/* Setup beacon data for IBSS beacons. Unlike access point (Master),
+	 * IBSS uses a fixed beacon frame which is configured using this
+	 * function. This handler is required only for IBSS mode. */
+	int (*beacon_update)(struct ieee80211_hw *hw,
+			     struct sk_buff *skb,
+			     struct ieee80211_tx_control *control);
+
+	/* Determine whether the last IBSS beacon was sent by us. This is
+	 * needed only for IBSS mode and the result of this function is used to
+	 * determine whether to reply to Probe Requests. */
+	int (*tx_last_beacon)(struct ieee80211_hw *hw);
+};
+
+/* Allocate a new hardware device. This must be called once for each
+ * hardware device. The returned pointer must be used to refer to this
+ * device when calling other functions. 802.11 code allocates a private data
+ * area for the low-level driver. The size of this area is given as
+ * priv_data_len.
+ */
+struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
+					const struct ieee80211_ops *ops);
+
+/* Register hardware device to the IEEE 802.11 code and kernel. Low-level
+ * drivers must call this function before using any other IEEE 802.11
+ * function except ieee80211_register_hwmode. */
+int ieee80211_register_hw(struct ieee80211_hw *hw);
+
+/* driver can use this and ieee80211_get_rx_led_name to get the
+ * name of the registered LEDs after ieee80211_register_hw
+ * was called.
+ * This is useful to set the default trigger on the LED class
+ * device that your driver should export for each LED the device
+ * has, that way the default behaviour will be as expected but
+ * the user can still change it/turn off the LED etc.
+ */
+#ifdef CONFIG_MAC80211_LEDS
+extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
+extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
+#endif
+static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+	return __ieee80211_get_tx_led_name(hw);
+#else
+	return NULL;
+#endif
+}
+
+static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+	return __ieee80211_get_rx_led_name(hw);
+#else
+	return NULL;
+#endif
+}
+
+/* Register a new hardware PHYMODE capability to the stack. */
+int ieee80211_register_hwmode(struct ieee80211_hw *hw,
+			      struct ieee80211_hw_mode *mode);
+
+/* Unregister a hardware device. This function instructs 802.11 code to free
+ * allocated resources and unregister netdevices from the kernel. */
+void ieee80211_unregister_hw(struct ieee80211_hw *hw);
+
+/* Free everything that was allocated including private data of a driver. */
+void ieee80211_free_hw(struct ieee80211_hw *hw);
+
+/* Receive frame callback function. The low-level driver uses this function to
+ * send received frames to the IEEE 802.11 code. Receive buffer (skb) must
+ * start with IEEE 802.11 header. */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		    struct ieee80211_rx_status *status);
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
+			  struct sk_buff *skb,
+			  struct ieee80211_rx_status *status);
+
+/* Transmit status callback function. The low-level driver must call this
+ * function to report transmit status for all the TX frames that had
+ * req_tx_status set in the transmit control fields. In addition, this should
+ * be called at least for all unicast frames to provide information for TX rate
+ * control algorithm. In order to maintain all statistics, this function is
+ * recommended to be called after each frame, including multicast/broadcast, is
+ * sent. */
+void ieee80211_tx_status(struct ieee80211_hw *hw,
+			 struct sk_buff *skb,
+			 struct ieee80211_tx_status *status);
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+				 struct sk_buff *skb,
+				 struct ieee80211_tx_status *status);
+
+/**
+ * ieee80211_beacon_get - beacon generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send this beacon.
+ *
+ * If the beacon frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next beacon frame from the 802.11 code. The low-level is responsible
+ * for calling this function before beacon data is needed (e.g., based on
+ * hardware interrupt). Returned skb is used only once and low-level driver
+ * is responsible of freeing it.
+ */
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
+				     int if_id,
+				     struct ieee80211_tx_control *control);
+
+/**
+ * ieee80211_rts_get - RTS frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the RTS.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @rts: The buffer where to store the RTS frame.
+ *
+ * If the RTS frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next RTS frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and RTS frame is needed.
+ */
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+		       const void *frame, size_t frame_len,
+		       const struct ieee80211_tx_control *frame_txctl,
+		       struct ieee80211_rts *rts);
+
+/**
+ * ieee80211_rts_duration - Get the duration field for an RTS frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame that is going to be protected by the RTS.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the RTS is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      size_t frame_len,
+			      const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_ctstoself_get - CTS-to-self frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @cts: The buffer where to store the CTS-to-self frame.
+ *
+ * If the CTS-to-self frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and CTS-to-self frame is needed.
+ */
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+			     const void *frame, size_t frame_len,
+			     const struct ieee80211_tx_control *frame_txctl,
+			     struct ieee80211_cts *cts);
+
+/**
+ * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the CTS-to-self is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    size_t frame_len,
+				    const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_generic_frame_duration - Calculate the duration field for a frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame.
+ * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
+ *
+ * Calculate the duration field of some generic frame, given its
+ * length and transmission rate (in 100kbps).
+ */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					size_t frame_len,
+					int rate);
+
+/**
+ * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send returned frame.
+ *
+ * Function for accessing buffered broadcast and multicast frames. If
+ * hardware/firmware does not implement buffering of broadcast/multicast
+ * frames when power saving is used, 802.11 code buffers them in the host
+ * memory. The low-level driver uses this function to fetch next buffered
+ * frame. In most cases, this is used when generating beacon frame. This
+ * function returns a pointer to the next buffered skb or NULL if no more
+ * buffered frames are available.
+ *
+ * Note: buffered frames are returned only after DTIM beacon frame was
+ * generated with ieee80211_beacon_get() and the low-level driver must thus
+ * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns
+ * NULL if the previous generated beacon was not DTIM, so the low-level driver
+ * does not need to check for DTIM beacons separately and should be able to
+ * use common code for all beacons.
+ */
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+			  struct ieee80211_tx_control *control);
+
+/* Low level drivers that have their own MLME and MAC indicate
+ * the aid for an associating station with this call */
+int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw,
+			      u8 *peer_address, u16 aid);
+
+
+/* Given an sk_buff with a raw 802.11 header at the data pointer this function
+ * returns the 802.11 header length in bytes (not including encryption
+ * headers). If the data in the sk_buff is too short to contain a valid 802.11
+ * header the function returns 0.
+ */
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
+
+/* Like ieee80211_get_hdrlen_from_skb() but takes a FC in CPU order. */
+int ieee80211_get_hdrlen(u16 fc);
+
+/**
+ * ieee80211_wake_queue - wake specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_stop_queue - stop specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_start_queues - start all queues
+ * @hw: pointer to as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_start_queue.
+ */
+void ieee80211_start_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_stop_queues - stop all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_wake_queues - wake all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_get_mc_list_item - iteration over items in multicast list
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @prev: value returned by previous call to ieee80211_get_mc_list_item() or
+ *	NULL to start a new iteration.
+ * @ptr: pointer to buffer of void * type for internal usage of
+ *	ieee80211_get_mc_list_item().
+ *
+ * Iterates over items in multicast list of given device. To get the first
+ * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the
+ * value returned by previous call in @prev. Don't alter *@ptr during
+ * iteration. When there are no more items, NULL is returned.
+ */
+struct dev_mc_list *
+ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
+			   struct dev_mc_list *prev,
+			   void **ptr);
+
+/* called by driver to notify scan status completed */
+void ieee80211_scan_completed(struct ieee80211_hw *hw);
+
+/* Function to indicate Radar Detection. The low level driver must call this
+ * function to indicate the presence of radar in the current channel.
+ * Additionally the radar type also could be sent */
+int  ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
+			    int radar, int radar_type);
+
+/* return a pointer to the source address (SA) */
+static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
+{
+	u8 *raw = (u8 *) hdr;
+	u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */
+
+	switch (tofrom) {
+		case 2:
+			return hdr->addr3;
+		case 3:
+			return hdr->addr4;
+	}
+	return hdr->addr2;
+}
+
+/* return a pointer to the destination address (DA) */
+static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
+{
+	u8 *raw = (u8 *) hdr;
+	u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */
+
+	if (to_ds)
+		return hdr->addr3;
+	return hdr->addr1;
+}
+
+static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
+{
+	return (le16_to_cpu(hdr->frame_control) &
+		IEEE80211_FCTL_MOREFRAGS) != 0;
+}
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
+		   ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+
+#endif /* MAC80211_H */
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index ad7fe11..a4f2618 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -24,6 +24,7 @@ #include <linux/seq_file.h>
 
 #include <linux/err.h>
 #include <linux/sysctl.h>
+#include <net/rtnetlink.h>
 
 #define NUD_IN_TIMER	(NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)
 #define NUD_VALID	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
@@ -213,16 +214,7 @@ extern void			pneigh_enqueue(struct neig
 extern struct pneigh_entry	*pneigh_lookup(struct neigh_table *tbl, const void *key, struct net_device *dev, int creat);
 extern int			pneigh_delete(struct neigh_table *tbl, const void *key, struct net_device *dev);
 
-struct netlink_callback;
-struct nlmsghdr;
-extern int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb);
-extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern void neigh_app_ns(struct neighbour *n);
-
-extern int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb);
-extern int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-
 extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
 extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *));
 extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *));
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 0e690e3..1c6b8bd 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -250,6 +250,11 @@ static inline int nf_ct_is_dying(struct 
 	return test_bit(IPS_DYING_BIT, &ct->status);
 }
 
+static inline int nf_ct_is_untracked(const struct sk_buff *skb)
+{
+	return (skb->nfct == &nf_conntrack_untracked.ct_general);
+}
+
 extern unsigned int nf_conntrack_htable_size;
 extern int nf_conntrack_checksum;
 extern atomic_t nf_conntrack_count;
diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h
deleted file mode 100644
index 6f84c1f..0000000
--- a/include/net/netfilter/nf_conntrack_compat.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef _NF_CONNTRACK_COMPAT_H
-#define _NF_CONNTRACK_COMPAT_H
-
-#ifdef __KERNEL__
-
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/socket.h>
-
-#ifdef CONFIG_IP_NF_CONNTRACK_MARK
-static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
-					u_int32_t *ctinfo)
-{
-	struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
-
-	if (ct)
-		return &ct->mark;
-	else
-		return NULL;
-}
-#endif /* CONFIG_IP_NF_CONNTRACK_MARK */
-
-#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
-static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb,
-					   u_int32_t *ctinfo)
-{
-	struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
-
-	if (ct)
-		return &ct->secmark;
-	else
-		return NULL;
-}
-#endif /* CONFIG_IP_NF_CONNTRACK_SECMARK */
-
-#ifdef CONFIG_IP_NF_CT_ACCT
-static inline struct ip_conntrack_counter *
-nf_ct_get_counters(const struct sk_buff *skb)
-{
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct = ip_conntrack_get(skb, &ctinfo);
-
-	if (ct)
-		return ct->counters;
-	else
-		return NULL;
-}
-#endif /* CONFIG_IP_NF_CT_ACCT */
-
-static inline int nf_ct_is_untracked(const struct sk_buff *skb)
-{
-	return (skb->nfct == &ip_conntrack_untracked.ct_general);
-}
-
-static inline void nf_ct_untrack(struct sk_buff *skb)
-{
-	skb->nfct = &ip_conntrack_untracked.ct_general;
-}
-
-static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
-				   enum ip_conntrack_info *ctinfo)
-{
-	struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
-	return (ct != NULL);
-}
-
-static inline int nf_ct_l3proto_try_module_get(unsigned short l3proto)
-{
-	need_conntrack();
-	return l3proto == PF_INET ? 0 : -1;
-}
-
-static inline void nf_ct_l3proto_module_put(unsigned short l3proto)
-{
-}
-
-#else /* CONFIG_IP_NF_CONNTRACK */
-
-#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
-#include <net/netfilter/nf_conntrack.h>
-
-#ifdef CONFIG_NF_CONNTRACK_MARK
-
-static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
-					u_int32_t *ctinfo)
-{
-	struct nf_conn *ct = nf_ct_get(skb, ctinfo);
-
-	if (ct)
-		return &ct->mark;
-	else
-		return NULL;
-}
-#endif /* CONFIG_NF_CONNTRACK_MARK */
-
-#ifdef CONFIG_NF_CONNTRACK_SECMARK
-static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb,
-					   u_int32_t *ctinfo)
-{
-	struct nf_conn *ct = nf_ct_get(skb, ctinfo);
-
-	if (ct)
-		return &ct->secmark;
-	else
-		return NULL;
-}
-#endif /* CONFIG_NF_CONNTRACK_MARK */
-
-#ifdef CONFIG_NF_CT_ACCT
-static inline struct ip_conntrack_counter *
-nf_ct_get_counters(const struct sk_buff *skb)
-{
-	enum ip_conntrack_info ctinfo;
-	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
-
-	if (ct)
-		return ct->counters;
-	else
-		return NULL;
-}
-#endif /* CONFIG_NF_CT_ACCT */
-
-static inline int nf_ct_is_untracked(const struct sk_buff *skb)
-{
-	return (skb->nfct == &nf_conntrack_untracked.ct_general);
-}
-
-static inline void nf_ct_untrack(struct sk_buff *skb)
-{
-	skb->nfct = &nf_conntrack_untracked.ct_general;
-}
-
-static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
-				   enum ip_conntrack_info *ctinfo)
-{
-	struct nf_conn *ct = nf_ct_get(skb, ctinfo);
-	return (ct != NULL);
-}
-
-#endif /* CONFIG_IP_NF_CONNTRACK */
-
-#endif /* __KERNEL__ */
-
-#endif /* _NF_CONNTRACK_COMPAT_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 85634e1..9fb9066 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -27,6 +27,9 @@ extern unsigned int nf_conntrack_in(int 
 extern int nf_conntrack_init(void);
 extern void nf_conntrack_cleanup(void);
 
+extern int nf_conntrack_proto_init(void);
+extern void nf_conntrack_proto_fini(void);
+
 struct nf_conntrack_l3proto;
 extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf);
 /* Like above, but you already have conntrack read lock. */
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index b62a8a9..811c907 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -20,30 +20,8 @@ DECLARE_PER_CPU(struct nf_conntrack_ecac
 #define CONNTRACK_ECACHE(x)	(__get_cpu_var(nf_conntrack_ecache).x)
 
 extern struct atomic_notifier_head nf_conntrack_chain;
-extern struct atomic_notifier_head nf_conntrack_expect_chain;
-
-static inline int nf_conntrack_register_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&nf_conntrack_chain, nb);
-}
-
-static inline int nf_conntrack_unregister_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb);
-}
-
-static inline int
-nf_conntrack_expect_register_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb);
-}
-
-static inline int
-nf_conntrack_expect_unregister_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain,
-			nb);
-}
+extern int nf_conntrack_register_notifier(struct notifier_block *nb);
+extern int nf_conntrack_unregister_notifier(struct notifier_block *nb);
 
 extern void nf_ct_deliver_cached_events(const struct nf_conn *ct);
 extern void __nf_ct_event_cache_init(struct nf_conn *ct);
@@ -71,6 +49,10 @@ static inline void nf_conntrack_event(en
 		atomic_notifier_call_chain(&nf_conntrack_chain, event, ct);
 }
 
+extern struct atomic_notifier_head nf_conntrack_expect_chain;
+extern int nf_conntrack_expect_register_notifier(struct notifier_block *nb);
+extern int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb);
+
 static inline void
 nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
 			  struct nf_conntrack_expect *exp)
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index eb575cb..f32f714 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -90,10 +90,7 @@ extern struct nf_conntrack_l3proto *nf_c
 /* Protocol registration. */
 extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
 extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
-
-extern struct nf_conntrack_l3proto *
-nf_ct_l3proto_find_get(u_int16_t l3proto);
-
+extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
 extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
 
 /* Existing built-in protocols */
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 8415182..f46cb93 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -97,7 +97,6 @@ extern struct nf_conntrack_l4proto nf_co
 extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
 
 #define MAX_NF_CT_PROTO 256
-extern struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX];
 
 extern struct nf_conntrack_l4proto *
 __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto);
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index f191c67..e765654 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -4,16 +4,6 @@ #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_nat.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
-/* Compatibility definitions for ipt_FOO modules */
-#define ip_nat_range			nf_nat_range
-#define ip_conntrack_tuple		nf_conntrack_tuple
-#define ip_conntrack_get		nf_ct_get
-#define ip_conntrack			nf_conn
-#define ip_nat_setup_info		nf_nat_setup_info
-#define ip_nat_multi_range_compat	nf_nat_multi_range_compat
-#define ip_ct_iterate_cleanup		nf_ct_iterate_cleanup
-#define	IP_NF_ASSERT			NF_CT_ASSERT
-
 extern int nf_nat_rule_init(void) __init;
 extern void nf_nat_rule_cleanup(void);
 extern int nf_nat_rule_find(struct sk_buff **pskb,
diff --git a/include/net/netlink.h b/include/net/netlink.h
index bcaf67b..0bf325c 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -171,6 +171,7 @@ enum {
 	NLA_MSECS,
 	NLA_NESTED,
 	NLA_NUL_STRING,
+	NLA_BINARY,
 	__NLA_TYPE_MAX,
 };
 
@@ -188,12 +189,13 @@ #define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1
  *    NLA_STRING           Maximum length of string
  *    NLA_NUL_STRING       Maximum length of string (excluding NUL)
  *    NLA_FLAG             Unused
+ *    NLA_BINARY           Maximum length of attribute payload
  *    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, len = BARSIZ },
+ *	[ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
  *	[ATTR_BAZ] = { .len = sizeof(struct mystruct) },
  * };
  */
@@ -214,9 +216,7 @@ struct nl_info {
 
 extern void		netlink_run_queue(struct sock *sk, unsigned int *qlen,
 					  int (*cb)(struct sk_buff *,
-						    struct nlmsghdr *, int *));
-extern void		netlink_queue_skip(struct nlmsghdr *nlh,
-					   struct sk_buff *skb);
+						    struct nlmsghdr *));
 extern int		nlmsg_notify(struct sock *sk, struct sk_buff *skb,
 				     u32 pid, unsigned int group, int report,
 				     gfp_t flags);
@@ -525,7 +525,7 @@ static inline struct sk_buff *nlmsg_new(
  */
 static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	nlh->nlmsg_len = skb->tail - (unsigned char *) nlh;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - (unsigned char *)nlh;
 
 	return skb->len;
 }
@@ -538,7 +538,7 @@ static inline int nlmsg_end(struct sk_bu
  */
 static inline void *nlmsg_get_pos(struct sk_buff *skb)
 {
-	return skb->tail;
+	return skb_tail_pointer(skb);
 }
 
 /**
@@ -548,7 +548,7 @@ static inline void *nlmsg_get_pos(struct
  *
  * Trims the message to the provided mark. Returns -1.
  */
-static inline int nlmsg_trim(struct sk_buff *skb, void *mark)
+static inline int nlmsg_trim(struct sk_buff *skb, const void *mark)
 {
 	if (mark)
 		skb_trim(skb, (unsigned char *) mark - skb->data);
@@ -940,7 +940,7 @@ static inline unsigned long nla_get_msec
  */
 static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype)
 {
-	struct nlattr *start = (struct nlattr *) skb->tail;
+	struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb);
 
 	if (nla_put(skb, attrtype, 0, NULL) < 0)
 		return NULL;
@@ -960,7 +960,7 @@ static inline struct nlattr *nla_nest_st
  */
 static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)
 {
-	start->nla_len = skb->tail - (unsigned char *) start;
+	start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start;
 	return skb->len;
 }
 
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 02647fe..4129df7 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -326,18 +326,18 @@ static inline unsigned char * tcf_get_ba
 		case TCF_LAYER_LINK:
 			return skb->data;
 		case TCF_LAYER_NETWORK:
-			return skb->nh.raw;
+			return skb_network_header(skb);
 		case TCF_LAYER_TRANSPORT:
-			return skb->h.raw;
+			return skb_transport_header(skb);
 	}
 
 	return NULL;
 }
 
-static inline int tcf_valid_offset(struct sk_buff *skb, unsigned char *ptr,
-				   int len)
+static inline int tcf_valid_offset(const struct sk_buff *skb,
+				   const unsigned char *ptr, const int len)
 {
-	return unlikely((ptr + len) < skb->tail && ptr > skb->head);
+	return unlikely((ptr + len) < skb_tail_pointer(skb) && ptr > skb->head);
 }
 
 #ifdef CONFIG_NET_CLS_IND
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index f6afee7..5754d53 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -2,6 +2,7 @@ #ifndef __NET_PKT_SCHED_H
 #define __NET_PKT_SCHED_H
 
 #include <linux/jiffies.h>
+#include <linux/ktime.h>
 #include <net/sch_generic.h>
 
 struct qdisc_walker
@@ -12,8 +13,6 @@ struct qdisc_walker
 	int	(*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
 };
 
-extern rwlock_t qdisc_tree_lock;
-
 #define QDISC_ALIGNTO		32
 #define QDISC_ALIGN(len)	(((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1))
 
@@ -37,175 +36,38 @@ static inline void *qdisc_priv(struct Qd
    The things are not so bad, because we may use artifical
    clock evaluated by integration of network data flow
    in the most critical places.
-
-   Note: we do not use fastgettimeofday.
-   The reason is that, when it is not the same thing as
-   gettimeofday, it returns invalid timestamp, which is
-   not updated, when net_bh is active.
- */
-
-/* General note about internal clock.
-
-   Any clock source returns time intervals, measured in units
-   close to 1usec. With source CONFIG_NET_SCH_CLK_GETTIMEOFDAY it is precisely
-   microseconds, otherwise something close but different chosen to minimize
-   arithmetic cost. Ratio usec/internal untis in form nominator/denominator
-   may be read from /proc/net/psched.
  */
 
-
-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
-
-typedef struct timeval	psched_time_t;
-typedef long		psched_tdiff_t;
-
-#define PSCHED_GET_TIME(stamp) do_gettimeofday(&(stamp))
-#define PSCHED_US2JIFFIE(usecs) usecs_to_jiffies(usecs)
-#define PSCHED_JIFFIE2US(delay) jiffies_to_usecs(delay)
-
-#else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
-
 typedef u64	psched_time_t;
 typedef long	psched_tdiff_t;
 
-#ifdef CONFIG_NET_SCH_CLK_JIFFIES
-
-#if HZ < 96
-#define PSCHED_JSCALE 14
-#elif HZ >= 96 && HZ < 192
-#define PSCHED_JSCALE 13
-#elif HZ >= 192 && HZ < 384
-#define PSCHED_JSCALE 12
-#elif HZ >= 384 && HZ < 768
-#define PSCHED_JSCALE 11
-#elif HZ >= 768
-#define PSCHED_JSCALE 10
-#endif
+/* Avoid doing 64 bit divide by 1000 */
+#define PSCHED_US2NS(x)			((s64)(x) << 10)
+#define PSCHED_NS2US(x)			((x) >> 10)
 
-#define PSCHED_GET_TIME(stamp) ((stamp) = (get_jiffies_64()<<PSCHED_JSCALE))
-#define PSCHED_US2JIFFIE(delay) (((delay)+(1<<PSCHED_JSCALE)-1)>>PSCHED_JSCALE)
-#define PSCHED_JIFFIE2US(delay) ((delay)<<PSCHED_JSCALE)
-
-#endif /* CONFIG_NET_SCH_CLK_JIFFIES */
-#ifdef CONFIG_NET_SCH_CLK_CPU
-#include <asm/timex.h>
-
-extern psched_tdiff_t psched_clock_per_hz;
-extern int psched_clock_scale;
-extern psched_time_t psched_time_base;
-extern cycles_t psched_time_mark;
-
-#define PSCHED_GET_TIME(stamp)						\
-do {									\
-	cycles_t cur = get_cycles();					\
-	if (sizeof(cycles_t) == sizeof(u32)) {				\
-		if (cur <= psched_time_mark)				\
-			psched_time_base += 0x100000000ULL;		\
-		psched_time_mark = cur;					\
-		(stamp) = (psched_time_base + cur)>>psched_clock_scale;	\
-	} else {							\
-		(stamp) = cur>>psched_clock_scale;			\
-	}								\
-} while (0)
-#define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
-#define PSCHED_JIFFIE2US(delay) ((delay)*psched_clock_per_hz)
-
-#endif /* CONFIG_NET_SCH_CLK_CPU */
-
-#endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
-
-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
-#define PSCHED_TDIFF(tv1, tv2) \
-({ \
-	   int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
-	   int __delta = (tv1).tv_usec - (tv2).tv_usec; \
-	   if (__delta_sec) { \
-	           switch (__delta_sec) { \
-		   default: \
-			   __delta = 0; \
-		   case 2: \
-			   __delta += USEC_PER_SEC; \
-		   case 1: \
-			   __delta += USEC_PER_SEC; \
-	           } \
-	   } \
-	   __delta; \
-})
-
-static inline int
-psched_tod_diff(int delta_sec, int bound)
+#define PSCHED_TICKS_PER_SEC		PSCHED_NS2US(NSEC_PER_SEC)
+#define PSCHED_PASTPERFECT		0
+
+static inline psched_time_t psched_get_time(void)
 {
-	int delta;
-
-	if (bound <= USEC_PER_SEC || delta_sec > (0x7FFFFFFF/USEC_PER_SEC)-1)
-		return bound;
-	delta = delta_sec * USEC_PER_SEC;
-	if (delta > bound || delta < 0)
-		delta = bound;
-	return delta;
+	return PSCHED_NS2US(ktime_to_ns(ktime_get()));
 }
 
-#define PSCHED_TDIFF_SAFE(tv1, tv2, bound) \
-({ \
-	   int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
-	   int __delta = (tv1).tv_usec - (tv2).tv_usec; \
-	   switch (__delta_sec) { \
-	   default: \
-		   __delta = psched_tod_diff(__delta_sec, bound);  break; \
-	   case 2: \
-		   __delta += USEC_PER_SEC; \
-	   case 1: \
-		   __delta += USEC_PER_SEC; \
-	   case 0: \
- 		   if (__delta > bound || __delta < 0) \
- 			__delta = bound; \
-	   } \
-	   __delta; \
-})
-
-#define PSCHED_TLESS(tv1, tv2) (((tv1).tv_usec < (tv2).tv_usec && \
-				(tv1).tv_sec <= (tv2).tv_sec) || \
-				 (tv1).tv_sec < (tv2).tv_sec)
-
-#define PSCHED_TADD2(tv, delta, tv_res) \
-({ \
-	   int __delta = (tv).tv_usec + (delta); \
-	   (tv_res).tv_sec = (tv).tv_sec; \
-	   while (__delta >= USEC_PER_SEC) { (tv_res).tv_sec++; __delta -= USEC_PER_SEC; } \
-	   (tv_res).tv_usec = __delta; \
-})
-
-#define PSCHED_TADD(tv, delta) \
-({ \
-	   (tv).tv_usec += (delta); \
-	   while ((tv).tv_usec >= USEC_PER_SEC) { (tv).tv_sec++; \
-		 (tv).tv_usec -= USEC_PER_SEC; } \
-})
-
-/* Set/check that time is in the "past perfect";
-   it depends on concrete representation of system time
- */
-
-#define PSCHED_SET_PASTPERFECT(t)	((t).tv_sec = 0)
-#define PSCHED_IS_PASTPERFECT(t)	((t).tv_sec == 0)
-
-#define	PSCHED_AUDIT_TDIFF(t) ({ if ((t) > 2000000) (t) = 2000000; })
-
-#else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
-
-#define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
-#define PSCHED_TDIFF_SAFE(tv1, tv2, bound) \
-	min_t(long long, (tv1) - (tv2), bound)
-
+static inline psched_tdiff_t
+psched_tdiff_bounded(psched_time_t tv1, psched_time_t tv2, psched_time_t bound)
+{
+	return min(tv1 - tv2, bound);
+}
 
-#define PSCHED_TLESS(tv1, tv2) ((tv1) < (tv2))
-#define PSCHED_TADD2(tv, delta, tv_res) ((tv_res) = (tv) + (delta))
-#define PSCHED_TADD(tv, delta) ((tv) += (delta))
-#define PSCHED_SET_PASTPERFECT(t)	((t) = 0)
-#define PSCHED_IS_PASTPERFECT(t)	((t) == 0)
-#define	PSCHED_AUDIT_TDIFF(t)
+struct qdisc_watchdog {
+	struct hrtimer	timer;
+	struct Qdisc	*qdisc;
+};
 
-#endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
+extern void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc);
+extern void qdisc_watchdog_schedule(struct qdisc_watchdog *wd,
+				    psched_time_t expires);
+extern void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
 
 extern struct Qdisc_ops pfifo_qdisc_ops;
 extern struct Qdisc_ops bfifo_qdisc_ops;
diff --git a/include/net/red.h b/include/net/red.h
index a4eb379..3cf31d4 100644
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -151,17 +151,17 @@ static inline void red_set_parms(struct 
 
 static inline int red_is_idling(struct red_parms *p)
 {
-	return !PSCHED_IS_PASTPERFECT(p->qidlestart);
+	return p->qidlestart != PSCHED_PASTPERFECT;
 }
 
 static inline void red_start_of_idle_period(struct red_parms *p)
 {
-	PSCHED_GET_TIME(p->qidlestart);
+	p->qidlestart = psched_get_time();
 }
 
 static inline void red_end_of_idle_period(struct red_parms *p)
 {
-	PSCHED_SET_PASTPERFECT(p->qidlestart);
+	p->qidlestart = PSCHED_PASTPERFECT;
 }
 
 static inline void red_restart(struct red_parms *p)
@@ -177,8 +177,8 @@ static inline unsigned long red_calc_qav
 	long us_idle;
 	int  shift;
 
-	PSCHED_GET_TIME(now);
-	us_idle = PSCHED_TDIFF_SAFE(now, p->qidlestart, p->Scell_max);
+	now = psched_get_time();
+	us_idle = psched_tdiff_bounded(now, p->qidlestart, p->Scell_max);
 
 	/*
 	 * The problem: ideally, average length queue recalcultion should
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
new file mode 100644
index 0000000..3b3d474
--- /dev/null
+++ b/include/net/rtnetlink.h
@@ -0,0 +1,25 @@
+#ifndef __NET_RTNETLINK_H
+#define __NET_RTNETLINK_H
+
+#include <linux/rtnetlink.h>
+#include <net/netlink.h>
+
+typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
+typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
+
+extern int	__rtnl_register(int protocol, int msgtype,
+				rtnl_doit_func, rtnl_dumpit_func);
+extern void	rtnl_register(int protocol, int msgtype,
+			      rtnl_doit_func, rtnl_dumpit_func);
+extern int	rtnl_unregister(int protocol, int msgtype);
+extern void	rtnl_unregister_all(int protocol);
+
+static inline int rtnl_msg_family(struct nlmsghdr *nlh)
+{
+	if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg))
+		return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family;
+	else
+		return AF_UNSPEC;
+}
+
+#endif
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 8208639..1b8e351 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -5,10 +5,10 @@ #include <linux/netdevice.h>
 #include <linux/types.h>
 #include <linux/rcupdate.h>
 #include <linux/module.h>
-#include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
 #include <linux/pkt_cls.h>
 #include <net/gen_stats.h>
+#include <net/rtnetlink.h>
 
 struct Qdisc_ops;
 struct qdisc_walker;
@@ -177,14 +177,8 @@ extern void qdisc_tree_decrease_qlen(str
 extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops);
 extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
 				       struct Qdisc_ops *ops, u32 parentid);
-
-static inline void
-tcf_destroy(struct tcf_proto *tp)
-{
-	tp->ops->destroy(tp);
-	module_put(tp->ops->owner);
-	kfree(tp);
-}
+extern void tcf_destroy(struct tcf_proto *tp);
+extern void tcf_destroy_chain(struct tcf_proto *fl);
 
 static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 				       struct sk_buff_head *list)
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 6114c4f..f56c8d6 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -100,6 +100,8 @@ typedef enum {
 	SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */
 	SCTP_CMD_FORCE_PRIM_RETRAN,  /* Forces retrans. over primary path. */
 	SCTP_CMD_SET_SK_ERR,	 /* Set sk_err */
+	SCTP_CMD_ASSOC_CHANGE,	 /* generate and send assoc_change event */
+	SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
 	SCTP_CMD_LAST
 } sctp_verb_t;
 
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index 5ddb855..bb37724 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -283,7 +283,7 @@ #define SCTP_RTO_ALPHA          3   /* 1
 #define SCTP_RTO_BETA           2   /* 1/4 when converted to right shifts. */
 
 /* Maximum number of new data packets that can be sent in a burst.  */
-#define SCTP_MAX_BURST		4
+#define SCTP_DEFAULT_MAX_BURST		4
 
 #define SCTP_CLOCK_GRANULARITY	1	/* 1 jiffy */
 
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 28af680..dda72bf 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -378,11 +378,15 @@ #if defined(CONFIG_IPV6) || defined(CONF
 
 int sctp_v6_init(void);
 void sctp_v6_exit(void);
+int sctp_v6_add_protocol(void);
+void sctp_v6_del_protocol(void);
 
 #else /* #ifdef defined(CONFIG_IPV6) */
 
 static inline int sctp_v6_init(void) { return 0; }
 static inline void sctp_v6_exit(void) { return; }
+static inline int sctp_v6_add_protocol(void) { return 0; }
+static inline void sctp_v6_del_protocol(void) { return; }
 
 #endif /* #if defined(CONFIG_IPV6) */
 
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index f431acf..5e81984 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -276,6 +276,7 @@ struct sctp_sock {
 	__u32 default_context;
 	__u32 default_timetolive;
 	__u32 default_rcv_context;
+	int max_burst;
 
 	/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
 	 * the destination address every heartbeat interval. This value
@@ -304,10 +305,12 @@ struct sctp_sock {
 	__u32 autoclose;
 	__u8 nodelay;
 	__u8 disable_fragments;
-	__u8 pd_mode;
 	__u8 v4mapped;
+	__u8 frag_interleave;
 	__u32 adaptation_ind;
+	__u32 pd_point;
 
+	atomic_t pd_mode;
 	/* Receive to here while partial delivery is in effect. */
 	struct sk_buff_head pd_lobby;
 };
@@ -1854,6 +1857,7 @@ int sctp_assoc_set_bind_addr_from_ep(str
 int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
 					 struct sctp_cookie*,
 					 gfp_t gfp);
+int sctp_assoc_set_id(struct sctp_association *, gfp_t);
 
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 			const union sctp_addr *ss2);
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
index 2923e3d..de88ed5 100644
--- a/include/net/sctp/ulpevent.h
+++ b/include/net/sctp/ulpevent.h
@@ -89,6 +89,7 @@ struct sctp_ulpevent *sctp_ulpevent_make
 	__u16 error,
 	__u16 outbound,
 	__u16 inbound,
+	struct sctp_chunk *chunk,
 	gfp_t gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h
index ab26ab3..39ea3f4 100644
--- a/include/net/sctp/ulpqueue.h
+++ b/include/net/sctp/ulpqueue.h
@@ -78,7 +78,7 @@ void sctp_ulpq_partial_delivery(struct s
 void sctp_ulpq_abort_pd(struct sctp_ulpq *, gfp_t);
 
 /* Clear the partial data delivery condition on this socket. */
-int sctp_clear_pd(struct sock *sk);
+int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc);
 
 /* Skip over an SSN. */
 void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn);
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index 67a30eb..6d2b577 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -97,6 +97,12 @@ #define SCTP_GET_PEER_ADDR_INFO SCTP_GET
 #define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME
 	SCTP_CONTEXT,	/* Receive Context */
 #define SCTP_CONTEXT SCTP_CONTEXT
+	SCTP_FRAGMENT_INTERLEAVE,
+#define SCTP_FRAGMENT_INTERLEAVE SCTP_FRAGMENT_INTERLEAVE
+	SCTP_PARTIAL_DELIVERY_POINT,	/* Set/Get partial delivery point */
+#define SCTP_PARTIAL_DELIVERY_POINT SCTP_PARTIAL_DELIVERY_POINT
+	SCTP_MAX_BURST,		/* Set/Get max burst */
+#define SCTP_MAX_BURST SCTP_MAX_BURST
 
 	/* Internal Socket Options. Some of the sctp library functions are 
 	 * implemented using these socket options.
@@ -213,6 +219,7 @@ struct sctp_assoc_change {
 	__u16 sac_outbound_streams;
 	__u16 sac_inbound_streams;
 	sctp_assoc_t sac_assoc_id;
+	__u8 sac_info[0];
 };
 
 /*
@@ -261,6 +268,7 @@ enum sctp_spc_state {
 	SCTP_ADDR_REMOVED,
 	SCTP_ADDR_ADDED,
 	SCTP_ADDR_MADE_PRIM,
+	SCTP_ADDR_CONFIRMED,
 };
 
 
@@ -508,16 +516,17 @@ struct sctp_setadaptation {
  *   address's parameters:
  */
 enum  sctp_spp_flags {
-	SPP_HB_ENABLE = 1,		/*Enable heartbeats*/
-	SPP_HB_DISABLE = 2,		/*Disable heartbeats*/
+	SPP_HB_ENABLE = 1<<0,		/*Enable heartbeats*/
+	SPP_HB_DISABLE = 1<<1,		/*Disable heartbeats*/
 	SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE,
-	SPP_HB_DEMAND = 4,		/*Send heartbeat immediately*/
-	SPP_PMTUD_ENABLE = 8,		/*Enable PMTU discovery*/
-	SPP_PMTUD_DISABLE = 16,		/*Disable PMTU discovery*/
+	SPP_HB_DEMAND = 1<<2,		/*Send heartbeat immediately*/
+	SPP_PMTUD_ENABLE = 1<<3,	/*Enable PMTU discovery*/
+	SPP_PMTUD_DISABLE = 1<<4,	/*Disable PMTU discovery*/
 	SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE,
-	SPP_SACKDELAY_ENABLE = 32,	/*Enable SACK*/
-	SPP_SACKDELAY_DISABLE = 64,	/*Disable SACK*/
+	SPP_SACKDELAY_ENABLE = 1<<5,	/*Enable SACK*/
+	SPP_SACKDELAY_DISABLE = 1<<6,	/*Disable SACK*/
 	SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
+	SPP_HB_TIME_IS_ZERO = 1<<7,	/* Set HB delay to 0 */
 };
 
 struct sctp_paddrparams {
@@ -530,7 +539,7 @@ struct sctp_paddrparams {
 	__u32			spp_flags;
 } __attribute__((packed, aligned(4)));
 
-/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
  *
  *   This options will get or set the delayed ack timer.  The time is set
  *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
diff --git a/include/net/sock.h b/include/net/sock.h
index 2c7d60c..689b886 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -202,6 +202,15 @@ #define sk_prot			__sk_common.skc_prot
 	unsigned short		sk_type;
 	int			sk_rcvbuf;
 	socket_lock_t		sk_lock;
+	/*
+	 * The backlog queue is special, it is always used with
+	 * the per-socket spinlock held and requires low latency
+	 * access. Therefore we special case it's implementation.
+	 */
+	struct {
+		struct sk_buff *head;
+		struct sk_buff *tail;
+	} sk_backlog;
 	wait_queue_head_t	*sk_sleep;
 	struct dst_entry	*sk_dst_cache;
 	struct xfrm_policy	*sk_policy[2];
@@ -221,15 +230,6 @@ #define sk_prot			__sk_common.skc_prot
 	int			sk_rcvlowat;
 	unsigned long 		sk_flags;
 	unsigned long	        sk_lingertime;
-	/*
-	 * The backlog queue is special, it is always used with
-	 * the per-socket spinlock held and requires low latency
-	 * access. Therefore we special case it's implementation.
-	 */
-	struct {
-		struct sk_buff *head;
-		struct sk_buff *tail;
-	} sk_backlog;
 	struct sk_buff_head	sk_error_queue;
 	struct proto		*sk_prot_creator;
 	rwlock_t		sk_callback_lock;
@@ -244,7 +244,7 @@ #define sk_prot			__sk_common.skc_prot
 	struct sk_filter      	*sk_filter;
 	void			*sk_protinfo;
 	struct timer_list	sk_timer;
-	struct timeval		sk_stamp;
+	ktime_t			sk_stamp;
 	struct socket		*sk_socket;
 	void			*sk_user_data;
 	struct page		*sk_sndmsg_page;
@@ -390,6 +390,7 @@ enum sock_flags {
 	SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */
 	SOCK_DBG, /* %SO_DEBUG setting */
 	SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */
+	SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */
 	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
 	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
 };
@@ -710,15 +711,6 @@ static inline void sk_stream_mem_reclaim
 		__sk_stream_mem_reclaim(sk);
 }
 
-static inline void sk_stream_writequeue_purge(struct sock *sk)
-{
-	struct sk_buff *skb;
-
-	while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
-		sk_stream_free_skb(sk, skb);
-	sk_stream_mem_reclaim(sk);
-}
-
 static inline int sk_stream_rmem_schedule(struct sock *sk, struct sk_buff *skb)
 {
 	return (int)skb->truesize <= sk->sk_forward_alloc ||
@@ -1083,19 +1075,7 @@ static inline int sk_can_gso(const struc
 	return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
 }
 
-static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
-{
-	__sk_dst_set(sk, dst);
-	sk->sk_route_caps = dst->dev->features;
-	if (sk->sk_route_caps & NETIF_F_GSO)
-		sk->sk_route_caps |= NETIF_F_GSO_MASK;
-	if (sk_can_gso(sk)) {
-		if (dst->header_len)
-			sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
-		else 
-			sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
-	}
-}
+extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
 
 static inline void sk_charge_skb(struct sock *sk, struct sk_buff *skb)
 {
@@ -1256,18 +1236,6 @@ static inline struct page *sk_stream_all
 	return page;
 }
 
-#define sk_stream_for_retrans_queue(skb, sk)				\
-		for (skb = (sk)->sk_write_queue.next;			\
-		     (skb != (sk)->sk_send_head) &&			\
-		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
-		     skb = skb->next)
-
-/*from STCP for fast SACK Process*/
-#define sk_stream_for_retrans_queue_from(skb, sk)			\
-		for (; (skb != (sk)->sk_send_head) &&                   \
-		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
-		     skb = skb->next)
-
 /*
  *	Default write policy as shown to user space via poll/select/SIGIO
  */
@@ -1304,22 +1272,18 @@ static inline int sock_intr_errno(long t
 	return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR;
 }
 
+extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb);
+
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
-	struct timeval stamp;
+	ktime_t kt = skb->tstamp;
 
-	skb_get_timestamp(skb, &stamp);
-	if (sock_flag(sk, SOCK_RCVTSTAMP)) {
-		/* Race occurred between timestamp enabling and packet
-		   receiving.  Fill in the current time for now. */
-		if (stamp.tv_sec == 0)
-			do_gettimeofday(&stamp);
-		skb_set_timestamp(skb, &stamp);
-		put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(struct timeval),
-			 &stamp);
-	} else
-		sk->sk_stamp = stamp;
+	if (sock_flag(sk, SOCK_RCVTSTAMP))
+		__sock_recv_timestamp(msg, sk, skb);
+	else
+		sk->sk_stamp = kt;
 }
 
 /**
@@ -1350,18 +1314,17 @@ #endif
 
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
+extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
 /* 
  *	Enable debug/info messages 
  */
+extern int net_msg_warn;
+#define NETDEBUG(fmt, args...) \
+	do { if (net_msg_warn) printk(fmt,##args); } while (0)
 
-#ifdef CONFIG_NETDEBUG
-#define NETDEBUG(fmt, args...)	printk(fmt,##args)
-#define LIMIT_NETDEBUG(fmt, args...) do { if (net_ratelimit()) printk(fmt,##args); } while(0)
-#else
-#define NETDEBUG(fmt, args...)	do { } while (0)
-#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
-#endif
+#define LIMIT_NETDEBUG(fmt, args...) \
+	do { if (net_msg_warn && net_ratelimit()) printk(fmt,##args); } while(0)
 
 /*
  * Macros for sleeping on a socket. Use them like this:
@@ -1398,15 +1361,6 @@ static inline void sock_valbool_flag(str
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
 
-#ifdef CONFIG_NET
-int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-#else
-static inline int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return -ENODEV;
-}
-#endif
-
 extern void sk_init(void);
 
 #ifdef CONFIG_SYSCTL
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5c472f2..e22b4f0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -220,6 +220,7 @@ extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
 extern int sysctl_tcp_tw_reuse;
 extern int sysctl_tcp_frto;
+extern int sysctl_tcp_frto_response;
 extern int sysctl_tcp_low_latency;
 extern int sysctl_tcp_dma_copybreak;
 extern int sysctl_tcp_nometrics_save;
@@ -230,6 +231,7 @@ extern int sysctl_tcp_mtu_probing;
 extern int sysctl_tcp_base_mss;
 extern int sysctl_tcp_workaround_signed_windows;
 extern int sysctl_tcp_slow_start_after_idle;
+extern int sysctl_tcp_max_ssthresh;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -341,6 +343,7 @@ extern struct sock *		tcp_check_req(stru
 extern int			tcp_child_process(struct sock *parent,
 						  struct sock *child,
 						  struct sk_buff *skb);
+extern int			tcp_use_frto(struct sock *sk);
 extern void			tcp_enter_frto(struct sock *sk);
 extern void			tcp_enter_loss(struct sock *sk, int how);
 extern void			tcp_clear_retrans(struct tcp_sock *tp);
@@ -417,9 +420,9 @@ extern __u32 cookie_v4_init_sequence(str
 
 /* tcp_output.c */
 
-extern void __tcp_push_pending_frames(struct sock *sk, struct tcp_sock *tp,
-				      unsigned int cur_mss, int nonagle);
-extern int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp);
+extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
+				      int nonagle);
+extern int tcp_may_send_now(struct sock *sk);
 extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_xmit_retransmit_queue(struct sock *);
 extern void tcp_simple_retransmit(struct sock *);
@@ -476,8 +479,10 @@ static inline void tcp_fast_path_on(stru
 	__tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale);
 }
 
-static inline void tcp_fast_path_check(struct sock *sk, struct tcp_sock *tp)
+static inline void tcp_fast_path_check(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (skb_queue_empty(&tp->out_of_order_queue) &&
 	    tp->rcv_wnd &&
 	    atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
@@ -588,10 +593,10 @@ static inline void tcp_dec_pcount_approx
 	}
 }
 
-static inline void tcp_packets_out_inc(struct sock *sk, 
-				       struct tcp_sock *tp,
+static inline void tcp_packets_out_inc(struct sock *sk,
 				       const struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	int orig = tp->packets_out;
 
 	tp->packets_out += tcp_skb_pcount(skb);
@@ -624,9 +629,12 @@ #define TCP_CA_NAME_MAX	16
 #define TCP_CA_MAX	128
 #define TCP_CA_BUF_MAX	(TCP_CA_NAME_MAX*TCP_CA_MAX)
 
+#define TCP_CONG_NON_RESTRICTED 0x1
+#define TCP_CONG_RTT_STAMP	0x2
+
 struct tcp_congestion_ops {
 	struct list_head	list;
-	int	non_restricted;
+	unsigned long flags;
 
 	/* initialize private data (optional) */
 	void (*init)(struct sock *sk);
@@ -640,8 +648,6 @@ struct tcp_congestion_ops {
 	/* do new cwnd calculation (required) */
 	void (*cong_avoid)(struct sock *sk, u32 ack,
 			   u32 rtt, u32 in_flight, int good_ack);
-	/* round trip time sample per acked packet (optional) */
-	void (*rtt_sample)(struct sock *sk, u32 usrtt);
 	/* call before changing ca_state (optional) */
 	void (*set_state)(struct sock *sk, u8 new_state);
 	/* call when cwnd event occurs (optional) */
@@ -649,7 +655,7 @@ struct tcp_congestion_ops {
 	/* new value of cwnd after loss (optional) */
 	u32  (*undo_cwnd)(struct sock *sk);
 	/* hook for packet ack accounting (optional) */
-	void (*pkts_acked)(struct sock *sk, u32 num_acked);
+	void (*pkts_acked)(struct sock *sk, u32 num_acked, ktime_t last);
 	/* get info for inet_diag (optional) */
 	void (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb);
 
@@ -730,13 +736,12 @@ static inline __u32 tcp_current_ssthresh
 
 static inline void tcp_sync_left_out(struct tcp_sock *tp)
 {
-	if (tp->rx_opt.sack_ok &&
-	    (tp->sacked_out >= tp->packets_out - tp->lost_out))
-		tp->sacked_out = tp->packets_out - tp->lost_out;
+	BUG_ON(tp->rx_opt.sack_ok &&
+	       (tp->sacked_out + tp->lost_out > tp->packets_out));
 	tp->left_out = tp->sacked_out + tp->lost_out;
 }
 
-extern void tcp_enter_cwr(struct sock *sk);
+extern void tcp_enter_cwr(struct sock *sk, const int set_ssthresh);
 extern __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst);
 
 /* Slow start with delack produces 3 packets of burst, so that
@@ -775,18 +780,21 @@ static inline void tcp_minshall_update(s
 		tp->snd_sml = TCP_SKB_CB(skb)->end_seq;
 }
 
-static inline void tcp_check_probe_timer(struct sock *sk, struct tcp_sock *tp)
+static inline void tcp_check_probe_timer(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	const struct inet_connection_sock *icsk = inet_csk(sk);
+
 	if (!tp->packets_out && !icsk->icsk_pending)
 		inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0,
 					  icsk->icsk_rto, TCP_RTO_MAX);
 }
 
-static inline void tcp_push_pending_frames(struct sock *sk,
-					   struct tcp_sock *tp)
+static inline void tcp_push_pending_frames(struct sock *sk)
 {
-	__tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1), tp->nonagle);
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	__tcp_push_pending_frames(sk, tcp_current_mss(sk, 1), tp->nonagle);
 }
 
 static inline void tcp_init_wl(struct tcp_sock *tp, u32 ack, u32 seq)
@@ -815,7 +823,7 @@ static inline __sum16 __tcp_checksum_com
 
 static inline int tcp_checksum_complete(struct sk_buff *skb)
 {
-	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
+	return !skb_csum_unnecessary(skb) &&
 		__tcp_checksum_complete(skb);
 }
 
@@ -918,21 +926,7 @@ #ifdef STATE_TRACE
 #endif	
 }
 
-static inline void tcp_done(struct sock *sk)
-{
-	if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
-		TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
-
-	tcp_set_state(sk, TCP_CLOSE);
-	tcp_clear_xmit_timers(sk);
-
-	sk->sk_shutdown = SHUTDOWN_MASK;
-
-	if (!sock_flag(sk, SOCK_DEAD))
-		sk->sk_state_change(sk);
-	else
-		inet_csk_destroy_sock(sk);
-}
+extern void tcp_done(struct sock *sk);
 
 static inline void tcp_sack_reset(struct tcp_options_received *rx_opt)
 {
@@ -981,7 +975,7 @@ static inline void tcp_openreq_init(stru
 	ireq->wscale_ok = rx_opt->wscale_ok;
 	ireq->acked = 0;
 	ireq->ecn_ok = 0;
-	ireq->rmt_port = skb->h.th->source;
+	ireq->rmt_port = tcp_hdr(skb)->source;
 }
 
 extern void tcp_enter_memory_pressure(void);
@@ -1011,7 +1005,7 @@ static inline int tcp_paws_check(const s
 {
 	if ((s32)(rx_opt->rcv_tsval - rx_opt->ts_recent) >= 0)
 		return 0;
-	if (xtime.tv_sec >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)
+	if (get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)
 		return 0;
 
 	/* RST segments are not recommended to carry timestamp,
@@ -1026,26 +1020,13 @@ static inline int tcp_paws_check(const s
 
 	   However, we can relax time bounds for RST segments to MSL.
 	 */
-	if (rst && xtime.tv_sec >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL)
+	if (rst && get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL)
 		return 0;
 	return 1;
 }
 
 #define TCP_CHECK_TIMER(sk) do { } while (0)
 
-static inline int tcp_use_frto(const struct sock *sk)
-{
-	const struct tcp_sock *tp = tcp_sk(sk);
-	
-	/* F-RTO must be activated in sysctl and there must be some
-	 * unsent new data, and the advertised window should allow
-	 * sending it.
-	 */
-	return (sysctl_tcp_frto && sk->sk_send_head &&
-		!after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
-		       tp->snd_una + tp->snd_wnd));
-}
-
 static inline void tcp_mib_init(void)
 {
 	/* See RFC 2012 */
@@ -1172,6 +1153,125 @@ static inline void		tcp_put_md5sig_pool(
 	put_cpu();
 }
 
+/* write queue abstraction */
+static inline void tcp_write_queue_purge(struct sock *sk)
+{
+	struct sk_buff *skb;
+
+	while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL)
+		sk_stream_free_skb(sk, skb);
+	sk_stream_mem_reclaim(sk);
+}
+
+static inline struct sk_buff *tcp_write_queue_head(struct sock *sk)
+{
+	struct sk_buff *skb = sk->sk_write_queue.next;
+	if (skb == (struct sk_buff *) &sk->sk_write_queue)
+		return NULL;
+	return skb;
+}
+
+static inline struct sk_buff *tcp_write_queue_tail(struct sock *sk)
+{
+	struct sk_buff *skb = sk->sk_write_queue.prev;
+	if (skb == (struct sk_buff *) &sk->sk_write_queue)
+		return NULL;
+	return skb;
+}
+
+static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_buff *skb)
+{
+	return skb->next;
+}
+
+#define tcp_for_write_queue(skb, sk)					\
+		for (skb = (sk)->sk_write_queue.next;			\
+		     (skb != (struct sk_buff *)&(sk)->sk_write_queue);	\
+		     skb = skb->next)
+
+#define tcp_for_write_queue_from(skb, sk)				\
+		for (; (skb != (struct sk_buff *)&(sk)->sk_write_queue);\
+		     skb = skb->next)
+
+static inline struct sk_buff *tcp_send_head(struct sock *sk)
+{
+	return sk->sk_send_head;
+}
+
+static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	sk->sk_send_head = skb->next;
+	if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
+		sk->sk_send_head = NULL;
+	/* Don't override Nagle indefinately with F-RTO */
+	if (tp->frto_counter == 2)
+		tp->frto_counter = 3;
+}
+
+static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked)
+{
+	if (sk->sk_send_head == skb_unlinked)
+		sk->sk_send_head = NULL;
+}
+
+static inline void tcp_init_send_head(struct sock *sk)
+{
+	sk->sk_send_head = NULL;
+}
+
+static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb)
+{
+	__skb_queue_tail(&sk->sk_write_queue, skb);
+}
+
+static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb)
+{
+	__tcp_add_write_queue_tail(sk, skb);
+
+	/* Queue it, remembering where we must start sending. */
+	if (sk->sk_send_head == NULL)
+		sk->sk_send_head = skb;
+}
+
+static inline void __tcp_add_write_queue_head(struct sock *sk, struct sk_buff *skb)
+{
+	__skb_queue_head(&sk->sk_write_queue, skb);
+}
+
+/* Insert buff after skb on the write queue of sk.  */
+static inline void tcp_insert_write_queue_after(struct sk_buff *skb,
+						struct sk_buff *buff,
+						struct sock *sk)
+{
+	__skb_append(skb, buff, &sk->sk_write_queue);
+}
+
+/* Insert skb between prev and next on the write queue of sk.  */
+static inline void tcp_insert_write_queue_before(struct sk_buff *new,
+						  struct sk_buff *skb,
+						  struct sock *sk)
+{
+	__skb_insert(new, skb->prev, skb, &sk->sk_write_queue);
+}
+
+static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk)
+{
+	__skb_unlink(skb, &sk->sk_write_queue);
+}
+
+static inline int tcp_skb_is_last(const struct sock *sk,
+				  const struct sk_buff *skb)
+{
+	return skb->next == (struct sk_buff *)&sk->sk_write_queue;
+}
+
+static inline int tcp_write_queue_empty(struct sock *sk)
+{
+	return skb_queue_empty(&sk->sk_write_queue);
+}
+
 /* /proc */
 enum tcp_seq_states {
 	TCP_SEQ_STATE_LISTENING,
diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h
index 4629d77..89eb3e0 100644
--- a/include/net/tcp_ecn.h
+++ b/include/net/tcp_ecn.h
@@ -27,9 +27,10 @@ static inline void TCP_ECN_send_synack(s
 		TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
 }
 
-static inline void TCP_ECN_send_syn(struct sock *sk, struct tcp_sock *tp,
-				    struct sk_buff *skb)
+static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	tp->ecn_flags = 0;
 	if (sysctl_tcp_ecn) {
 		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR;
@@ -44,9 +45,11 @@ TCP_ECN_make_synack(struct request_sock 
 		th->ece = 1;
 }
 
-static inline void TCP_ECN_send(struct sock *sk, struct tcp_sock *tp,
-				struct sk_buff *skb, int tcp_header_len)
+static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
+				int tcp_header_len)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (tp->ecn_flags & TCP_ECN_OK) {
 		/* Not-retransmitted data segment: set ECT and inject CWR. */
 		if (skb->len != tcp_header_len &&
@@ -54,7 +57,7 @@ static inline void TCP_ECN_send(struct s
 			INET_ECN_xmit(sk);
 			if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) {
 				tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
-				skb->h.th->cwr = 1;
+				tcp_hdr(skb)->cwr = 1;
 				skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
 			}
 		} else {
@@ -62,7 +65,7 @@ static inline void TCP_ECN_send(struct s
 			INET_ECN_dontxmit(sk);
 		}
 		if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)
-			skb->h.th->ece = 1;
+			tcp_hdr(skb)->ece = 1;
 	}
 }
 
@@ -70,7 +73,7 @@ static inline void TCP_ECN_send(struct s
 
 static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, struct sk_buff *skb)
 {
-	if (skb->h.th->cwr)
+	if (tcp_hdr(skb)->cwr)
 		tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
 }
 
diff --git a/include/net/udp.h b/include/net/udp.h
index 1b921fa..98755eb 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -72,15 +72,12 @@ struct sk_buff;
  */
 static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb)
 {
-	if (! UDP_SKB_CB(skb)->partial_cov)
-		return __skb_checksum_complete(skb);
-	return csum_fold(skb_checksum(skb, 0, UDP_SKB_CB(skb)->cscov,
-				      skb->csum));
+	return __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov);
 }
 
 static inline int udp_lib_checksum_complete(struct sk_buff *skb)
 {
-	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
+	return !skb_csum_unnecessary(skb) &&
 		__udp_lib_checksum_complete(skb);
 }
 
@@ -92,8 +89,8 @@ static inline int udp_lib_checksum_compl
  */
 static inline __wsum udp_csum_outgoing(struct sock *sk, struct sk_buff *skb)
 {
-	__wsum csum = csum_partial(skb->h.raw, sizeof(struct udphdr), 0);
-
+	__wsum csum = csum_partial(skb_transport_header(skb),
+				   sizeof(struct udphdr), 0);
 	skb_queue_walk(&sk->sk_write_queue, skb) {
 		csum = csum_add(csum, skb->csum);
 	}
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 67ac514..635b0ea 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -47,11 +47,10 @@ static inline int udplite_checksum_init(
 		return 1;
 	}
 
-        UDP_SKB_CB(skb)->partial_cov = 0;
 	cscov = ntohs(uh->len);
 
 	if (cscov == 0)		 /* Indicates that full coverage is required. */
-		cscov = skb->len;
+		;
 	else if (cscov < 8  || cscov > skb->len) {
 		/*
 		 * Coverage length violates RFC 3828: log and discard silently.
@@ -60,42 +59,16 @@ static inline int udplite_checksum_init(
 			       cscov, skb->len);
 		return 1;
 
-	} else if (cscov < skb->len)
+	} else if (cscov < skb->len) {
         	UDP_SKB_CB(skb)->partial_cov = 1;
-
-        UDP_SKB_CB(skb)->cscov = cscov;
-
-	/*
-	 * There is no known NIC manufacturer supporting UDP-Lite yet,
-	 * hence ip_summed is always (re-)set to CHECKSUM_NONE.
-	 */
-	skb->ip_summed = CHECKSUM_NONE;
+		UDP_SKB_CB(skb)->cscov = cscov;
+		if (skb->ip_summed == CHECKSUM_COMPLETE)
+			skb->ip_summed = CHECKSUM_NONE;
+        }
 
 	return 0;
 }
 
-static __inline__ int udplite4_csum_init(struct sk_buff *skb, struct udphdr *uh)
-{
-	int rc = udplite_checksum_init(skb, uh);
-
-	if (!rc)
-		skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr,
-					       skb->nh.iph->daddr,
-					       skb->len, IPPROTO_UDPLITE, 0);
-	return rc;
-}
-
-static __inline__ int udplite6_csum_init(struct sk_buff *skb, struct udphdr *uh)
-{
-	int rc = udplite_checksum_init(skb, uh);
-
-	if (!rc)
-		skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-					     &skb->nh.ipv6h->daddr,
-					     skb->len, IPPROTO_UDPLITE, 0));
-	return rc;
-}
-
 static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh)
 {
 	int cscov = up->len;
@@ -128,14 +101,14 @@ static inline int udplite_sender_cscov(s
 
 static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
 {
-	int off, len, cscov = udplite_sender_cscov(udp_sk(sk), skb->h.uh);
+	int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb));
 	__wsum csum = 0;
 
 	skb->ip_summed = CHECKSUM_NONE;     /* no HW support for checksumming */
 
 	skb_queue_walk(&sk->sk_write_queue, skb) {
-		off = skb->h.raw - skb->data;
-		len = skb->len - off;
+		const int off = skb_transport_offset(skb);
+		const int len = skb->len - off;
 
 		csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum);
 
diff --git a/include/net/wext.h b/include/net/wext.h
new file mode 100644
index 0000000..c02b8de
--- /dev/null
+++ b/include/net/wext.h
@@ -0,0 +1,24 @@
+#ifndef __NET_WEXT_H
+#define __NET_WEXT_H
+
+/*
+ * wireless extensions interface to the core code
+ */
+
+#ifdef CONFIG_WIRELESS_EXT
+extern int wext_proc_init(void);
+extern int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
+			     void __user *arg);
+#else
+static inline int wext_proc_init(void)
+{
+	return 0;
+}
+static inline int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
+				    void __user *arg)
+{
+	return -EINVAL;
+}
+#endif
+
+#endif /* __NET_WEXT_H */
diff --git a/include/net/wireless.h b/include/net/wireless.h
new file mode 100644
index 0000000..d30c4ba
--- /dev/null
+++ b/include/net/wireless.h
@@ -0,0 +1,139 @@
+#ifndef __NET_WIRELESS_H
+#define __NET_WIRELESS_H
+
+/*
+ * 802.11 device management
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <net/cfg80211.h>
+
+/**
+ * struct wiphy - wireless hardware description
+ * @idx: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ */
+struct wiphy {
+	/* assign these fields before you register the wiphy */
+
+	/* permanent MAC address */
+	u8 perm_addr[ETH_ALEN];
+
+	/* If multiple wiphys are registered and you're handed e.g.
+	 * a regular netdev with assigned ieee80211_ptr, you won't
+	 * know whether it points to a wiphy your driver has registered
+	 * or not. Assign this to something global to your driver to
+	 * help determine whether you own this wiphy or not. */
+	void *privid;
+
+	/* fields below are read-only, assigned by cfg80211 */
+
+	/* the item in /sys/class/ieee80211/ points to this,
+	 * you need use set_wiphy_dev() (see below) */
+	struct device dev;
+
+	/* dir in debugfs: ieee80211/<wiphyname> */
+	struct dentry *debugfsdir;
+
+	char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+/** struct wireless_dev - wireless per-netdev state
+ *
+ * This structure must be allocated by the driver/stack
+ * that uses the ieee80211_ptr field in struct net_device
+ * (this is intentional so it can be allocated along with
+ * the netdev.)
+ *
+ * @wiphy: pointer to hardware description
+ */
+struct wireless_dev {
+	struct wiphy *wiphy;
+
+	/* private to the generic wireless code */
+	struct list_head list;
+	struct net_device *netdev;
+};
+
+/**
+ * wiphy_priv - return priv from wiphy
+ */
+static inline void *wiphy_priv(struct wiphy *wiphy)
+{
+	BUG_ON(!wiphy);
+	return &wiphy->priv;
+}
+
+/**
+ * set_wiphy_dev - set device pointer for wiphy
+ */
+static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
+{
+	wiphy->dev.parent = dev;
+}
+
+/**
+ * wiphy_dev - get wiphy dev pointer
+ */
+static inline struct device *wiphy_dev(struct wiphy *wiphy)
+{
+	return wiphy->dev.parent;
+}
+
+/**
+ * wiphy_name - get wiphy name
+ */
+static inline char *wiphy_name(struct wiphy *wiphy)
+{
+	return wiphy->dev.bus_id;
+}
+
+/**
+ * wdev_priv - return wiphy priv from wireless_dev
+ */
+static inline void *wdev_priv(struct wireless_dev *wdev)
+{
+	BUG_ON(!wdev);
+	return wiphy_priv(wdev->wiphy);
+}
+
+/**
+ * wiphy_new - create a new wiphy for use with cfg80211
+ *
+ * create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * the returned pointer must be assigned to each netdev's
+ * ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
+
+/**
+ * wiphy_register - register a wiphy with cfg80211
+ *
+ * register the given wiphy
+ *
+ * Returns a non-negative wiphy index or a negative error code.
+ */
+extern int wiphy_register(struct wiphy *wiphy);
+
+/**
+ * wiphy_unregister - deregister a wiphy from cfg80211
+ *
+ * unregister a device with the given priv pointer.
+ * After this call, no more requests can be made with this priv
+ * pointer, but the call may sleep to wait for an outstanding
+ * request that is being handled.
+ */
+extern void wiphy_unregister(struct wiphy *wiphy);
+
+/**
+ * wiphy_free - free wiphy
+ */
+extern void wiphy_free(struct wiphy *wiphy);
+
+#endif /* __NET_WIRELESS_H */
diff --git a/include/net/x25device.h b/include/net/x25device.h
index 1d10c87..1415bcf 100644
--- a/include/net/x25device.h
+++ b/include/net/x25device.h
@@ -7,8 +7,8 @@ #include <linux/skbuff.h>
 
 static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
-	skb->mac.raw = skb->data;
 	skb->dev = dev;
+	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_HOST;
 	
 	return htons(ETH_P_X25);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 5a00aa8..39ef925 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -279,7 +279,7 @@ #define XFRM_TYPE_NON_FRAGMENT	1
 	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);
+	u32			(*get_mtu)(struct xfrm_state *, int size);
 };
 
 extern int xfrm_register_type(struct xfrm_type *type, unsigned short family);
@@ -584,6 +584,10 @@ struct xfrm_dst
 		struct rt6_info		rt6;
 	} u;
 	struct dst_entry *route;
+#ifdef CONFIG_XFRM_SUB_POLICY
+	struct flowi *origin;
+	struct xfrm_selector *partner;
+#endif
 	u32 genid;
 	u32 route_mtu_cached;
 	u32 child_mtu_cached;
@@ -596,6 +600,12 @@ static inline void xfrm_dst_destroy(stru
 	dst_release(xdst->route);
 	if (likely(xdst->u.dst.xfrm))
 		xfrm_state_put(xdst->u.dst.xfrm);
+#ifdef CONFIG_XFRM_SUB_POLICY
+	kfree(xdst->origin);
+	xdst->origin = NULL;
+	kfree(xdst->partner);
+	xdst->partner = NULL;
+#endif
 }
 
 extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
@@ -935,9 +945,29 @@ static inline int xfrm_state_sort(struct
 	return -ENOSYS;
 }
 #endif
+
+struct xfrmk_sadinfo {
+	u32 sadhcnt; /* current hash bkts */
+	u32 sadhmcnt; /* max allowed hash bkts */
+	u32 sadcnt; /* current running count */
+};
+
+struct xfrmk_spdinfo {
+	u32 incnt;
+	u32 outcnt;
+	u32 fwdcnt;
+	u32 inscnt;
+	u32 outscnt;
+	u32 fwdscnt;
+	u32 spdhcnt;
+	u32 spdhmcnt;
+};
+
 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, struct xfrm_audit *audit_info);
+extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
+extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
 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);
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 8c339f5..90ef552 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -108,6 +108,11 @@ typedef struct dev_node_t {
 struct pcmcia_socket;
 struct config_t;
 
+struct pcmcia_dynids {
+	spinlock_t		lock;
+	struct list_head	list;
+};
+
 struct pcmcia_driver {
 	int (*probe)		(struct pcmcia_device *dev);
 	void (*remove)		(struct pcmcia_device *dev);
@@ -118,6 +123,7 @@ struct pcmcia_driver {
 	struct module		*owner;
 	struct pcmcia_device_id	*id_table;
 	struct device_driver	drv;
+	struct pcmcia_dynids	dynids;
 };
 
 /* driver registration */
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 585d28e..739fa4d 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -39,8 +39,6 @@
 #if !defined( IB_MAD_H )
 #define IB_MAD_H
 
-#include <linux/pci.h>
-
 #include <rdma/ib_verbs.h>
 
 /* Management base version */
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 765589f..5342ac6 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -431,9 +431,11 @@ struct ib_wc {
 	u8			port_num;	/* valid only for DR SMPs on switches */
 };
 
-enum ib_cq_notify {
-	IB_CQ_SOLICITED,
-	IB_CQ_NEXT_COMP
+enum ib_cq_notify_flags {
+	IB_CQ_SOLICITED			= 1 << 0,
+	IB_CQ_NEXT_COMP			= 1 << 1,
+	IB_CQ_SOLICITED_MASK		= IB_CQ_SOLICITED | IB_CQ_NEXT_COMP,
+	IB_CQ_REPORT_MISSED_EVENTS	= 1 << 2,
 };
 
 enum ib_srq_attr_mask {
@@ -912,6 +914,8 @@ struct ib_device {
 
 	u32                           flags;
 
+	int			      num_comp_vectors;
+
 	struct iw_cm_verbs	     *iwcm;
 
 	int		           (*query_device)(struct ib_device *device,
@@ -978,6 +982,7 @@ struct ib_device {
 						struct ib_recv_wr *recv_wr,
 						struct ib_recv_wr **bad_recv_wr);
 	struct ib_cq *             (*create_cq)(struct ib_device *device, int cqe,
+						int comp_vector,
 						struct ib_ucontext *context,
 						struct ib_udata *udata);
 	int                        (*destroy_cq)(struct ib_cq *cq);
@@ -987,7 +992,7 @@ struct ib_device {
 					      struct ib_wc *wc);
 	int                        (*peek_cq)(struct ib_cq *cq, int wc_cnt);
 	int                        (*req_notify_cq)(struct ib_cq *cq,
-						    enum ib_cq_notify cq_notify);
+						    enum ib_cq_notify_flags flags);
 	int                        (*req_ncomp_notif)(struct ib_cq *cq,
 						      int wc_cnt);
 	struct ib_mr *             (*get_dma_mr)(struct ib_pd *pd,
@@ -1358,13 +1363,15 @@ static inline int ib_post_recv(struct ib
  * @cq_context: Context associated with the CQ returned to the user via
  *   the associated completion and event handlers.
  * @cqe: The minimum size of the CQ.
+ * @comp_vector - Completion vector used to signal completion events.
+ *     Must be >= 0 and < context->num_comp_vectors.
  *
  * Users can examine the cq structure to determine the actual CQ size.
  */
 struct ib_cq *ib_create_cq(struct ib_device *device,
 			   ib_comp_handler comp_handler,
 			   void (*event_handler)(struct ib_event *, void *),
-			   void *cq_context, int cqe);
+			   void *cq_context, int cqe, int comp_vector);
 
 /**
  * ib_resize_cq - Modifies the capacity of the CQ.
@@ -1414,14 +1421,34 @@ int ib_peek_cq(struct ib_cq *cq, int wc_
 /**
  * ib_req_notify_cq - Request completion notification on a CQ.
  * @cq: The CQ to generate an event for.
- * @cq_notify: If set to %IB_CQ_SOLICITED, completion notification will
- *   occur on the next solicited event. If set to %IB_CQ_NEXT_COMP,
- *   notification will occur on the next completion.
+ * @flags:
+ *   Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP
+ *   to request an event on the next solicited event or next work
+ *   completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS
+ *   may also be |ed in to request a hint about missed events, as
+ *   described below.
+ *
+ * Return Value:
+ *    < 0 means an error occurred while requesting notification
+ *   == 0 means notification was requested successfully, and if
+ *        IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events
+ *        were missed and it is safe to wait for another event.  In
+ *        this case is it guaranteed that any work completions added
+ *        to the CQ since the last CQ poll will trigger a completion
+ *        notification event.
+ *    > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed
+ *        in.  It means that the consumer must poll the CQ again to
+ *        make sure it is empty to avoid missing an event because of a
+ *        race between requesting notification and an entry being
+ *        added to the CQ.  This return value means it is possible
+ *        (but not guaranteed) that a work completion has been added
+ *        to the CQ since the last poll without triggering a
+ *        completion notification event.
  */
 static inline int ib_req_notify_cq(struct ib_cq *cq,
-				   enum ib_cq_notify cq_notify)
+				   enum ib_cq_notify_flags flags)
 {
-	return cq->device->req_notify_cq(cq, cq_notify);
+	return cq->device->req_notify_cq(cq, flags);
 }
 
 /**
diff --git a/include/rxrpc/call.h b/include/rxrpc/call.h
deleted file mode 100644
index b86f837..0000000
--- a/include/rxrpc/call.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/* call.h: Rx call record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_CALL_H
-#define _LINUX_RXRPC_CALL_H
-
-#include <rxrpc/types.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/packet.h>
-#include <linux/timer.h>
-
-#define RXRPC_CALL_ACK_WINDOW_SIZE	16
-
-extern unsigned rxrpc_call_rcv_timeout;		/* receive activity timeout (secs) */
-
-/* application call state
- * - only state 0 and ffff are reserved, the state is set to 1 after an opid is received
- */
-enum rxrpc_app_cstate {
-	RXRPC_CSTATE_COMPLETE		= 0,	/* operation complete */
-	RXRPC_CSTATE_ERROR,			/* operation ICMP error or aborted */
-	RXRPC_CSTATE_SRVR_RCV_OPID,		/* [SERVER] receiving operation ID */
-	RXRPC_CSTATE_SRVR_RCV_ARGS,		/* [SERVER] receiving operation data */
-	RXRPC_CSTATE_SRVR_GOT_ARGS,		/* [SERVER] completely received operation data */
-	RXRPC_CSTATE_SRVR_SND_REPLY,		/* [SERVER] sending operation reply */
-	RXRPC_CSTATE_SRVR_RCV_FINAL_ACK,	/* [SERVER] receiving final ACK */
-	RXRPC_CSTATE_CLNT_SND_ARGS,		/* [CLIENT] sending operation args */
-	RXRPC_CSTATE_CLNT_RCV_REPLY,		/* [CLIENT] receiving operation reply */
-	RXRPC_CSTATE_CLNT_GOT_REPLY,		/* [CLIENT] completely received operation reply */
-} __attribute__((packed));
-
-extern const char *rxrpc_call_states[];
-
-enum rxrpc_app_estate {
-	RXRPC_ESTATE_NO_ERROR		= 0,	/* no error */
-	RXRPC_ESTATE_LOCAL_ABORT,		/* aborted locally by application layer */
-	RXRPC_ESTATE_PEER_ABORT,		/* aborted remotely by peer */
-	RXRPC_ESTATE_LOCAL_ERROR,		/* local ICMP network error */
-	RXRPC_ESTATE_REMOTE_ERROR,		/* remote ICMP network error */
-} __attribute__((packed));
-
-extern const char *rxrpc_call_error_states[];
-
-/*****************************************************************************/
-/*
- * Rx call record and application scratch buffer
- * - the call record occupies the bottom of a complete page
- * - the application scratch buffer occupies the rest
- */
-struct rxrpc_call
-{
-	atomic_t		usage;
-	struct rxrpc_connection	*conn;		/* connection upon which active */
-	spinlock_t		lock;		/* access lock */
-	struct module		*owner;		/* owner module */
-	wait_queue_head_t	waitq;		/* wait queue for events to happen */
-	struct list_head	link;		/* general internal list link */
-	struct list_head	call_link;	/* master call list link */
-	__be32			chan_ix;	/* connection channel index  */
-	__be32			call_id;	/* call ID on connection  */
-	unsigned long		cjif;		/* jiffies at call creation */
-	unsigned long		flags;		/* control flags */
-#define RXRPC_CALL_ACKS_TIMO	0x00000001	/* ACKS timeout reached */
-#define RXRPC_CALL_ACKR_TIMO	0x00000002	/* ACKR timeout reached */
-#define RXRPC_CALL_RCV_TIMO	0x00000004	/* RCV timeout reached */
-#define RXRPC_CALL_RCV_PKT	0x00000008	/* received packet */
-
-	/* transmission */
-	rxrpc_seq_t		snd_seq_count;	/* outgoing packet sequence number counter */
-	struct rxrpc_message	*snd_nextmsg;	/* next message being constructed for sending */
-	struct rxrpc_message	*snd_ping;	/* last ping message sent */
-	unsigned short		snd_resend_cnt;	/* count of resends since last ACK */
-
-	/* transmission ACK tracking */
-	struct list_head	acks_pendq;	/* messages pending ACK (ordered by seq) */
-	unsigned		acks_pend_cnt;	/* number of un-ACK'd packets */
-	rxrpc_seq_t		acks_dftv_seq;	/* highest definitively ACK'd msg seq */
-	struct timer_list	acks_timeout;	/* timeout on expected ACK */
-
-	/* reception */
-	struct list_head	rcv_receiveq;	/* messages pending reception (ordered by seq) */
-	struct list_head	rcv_krxiodq_lk;	/* krxiod queue for new inbound packets */
-	struct timer_list	rcv_timeout;	/* call receive activity timeout */
-
-	/* reception ACK'ing */
-	rxrpc_seq_t		ackr_win_bot;	/* bottom of ACK window */
-	rxrpc_seq_t		ackr_win_top;	/* top of ACK window */
-	rxrpc_seq_t		ackr_high_seq;	/* highest seqno yet received */
-	rxrpc_seq_net_t		ackr_prev_seq;	/* previous seqno received */
-	unsigned		ackr_pend_cnt;	/* number of pending ACKs */
-	struct timer_list	ackr_dfr_timo;	/* timeout on deferred ACK */
-	char			ackr_dfr_perm;	/* request for deferred ACKs permitted */
-	rxrpc_seq_t		ackr_dfr_seq;	/* seqno for deferred ACK */
-	struct rxrpc_ackpacket	ackr;		/* pending normal ACK packet */
-	uint8_t			ackr_array[RXRPC_CALL_ACK_WINDOW_SIZE];	/* ACK records */
-
-	/* presentation layer */
-	char			app_last_rcv;	/* T if received last packet from remote end */
-	enum rxrpc_app_cstate	app_call_state;	/* call state */
-	enum rxrpc_app_estate	app_err_state;	/* abort/error state */
-	struct list_head	app_readyq;	/* ordered ready received packet queue */
-	struct list_head	app_unreadyq;	/* ordered post-hole recv'd packet queue */
-	rxrpc_seq_t		app_ready_seq;	/* last seq number dropped into readyq */
-	size_t			app_ready_qty;	/* amount of data ready in readyq */
-	unsigned		app_opcode;	/* operation ID */
-	unsigned		app_abort_code;	/* abort code (when aborted) */
-	int			app_errno;	/* error number (when ICMP error received) */
-
-	/* statisics */
-	unsigned		pkt_rcv_count;	/* count of received packets on this call */
-	unsigned		pkt_snd_count;	/* count of sent packets on this call */
-	unsigned		app_read_count;	/* number of reads issued */
-
-	/* bits for the application to use */
-	rxrpc_call_attn_func_t	app_attn_func;	/* callback when attention required */
-	rxrpc_call_error_func_t	app_error_func;	/* callback when abort sent (cleanup and put) */
-	rxrpc_call_aemap_func_t	app_aemap_func;	/* callback to map abort code to/from errno */
-	void			*app_user;	/* application data */
-	struct list_head	app_link;	/* application list linkage */
-	struct list_head	app_attn_link;	/* application attention list linkage */
-	size_t			app_mark;	/* trigger callback when app_ready_qty>=app_mark */
-	char			app_async_read;	/* T if in async-read mode */
-	uint8_t			*app_read_buf;	/* application async read buffer (app_mark size) */
-	uint8_t			*app_scr_alloc;	/* application scratch allocation pointer */
-	void			*app_scr_ptr;	/* application pointer into scratch buffer */
-
-#define RXRPC_APP_MARK_EOF 0xFFFFFFFFU	/* mark at end of input */
-
-	/* application scratch buffer */
-	uint8_t			app_scratch[0] __attribute__((aligned(sizeof(long))));
-};
-
-#define RXRPC_CALL_SCRATCH_SIZE (PAGE_SIZE - sizeof(struct rxrpc_call))
-
-#define rxrpc_call_reset_scratch(CALL) \
-do { (CALL)->app_scr_alloc = (CALL)->app_scratch; } while(0)
-
-#define rxrpc_call_alloc_scratch(CALL,SIZE)						\
-({											\
-	void *ptr;									\
-	ptr = (CALL)->app_scr_alloc;							\
-	(CALL)->app_scr_alloc += (SIZE);						\
-	if ((SIZE)>RXRPC_CALL_SCRATCH_SIZE ||						\
-	    (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) {	\
-		printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),(size_t)(SIZE));	\
-		BUG();									\
-	}										\
-	ptr;										\
-})
-
-#define rxrpc_call_alloc_scratch_s(CALL,TYPE)						\
-({											\
-	size_t size = sizeof(TYPE);							\
-	TYPE *ptr;									\
-	ptr = (TYPE*)(CALL)->app_scr_alloc;						\
-	(CALL)->app_scr_alloc += size;							\
-	if (size>RXRPC_CALL_SCRATCH_SIZE ||						\
-	    (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) {	\
-		printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),size);		\
-		BUG();									\
-	}										\
-	ptr;										\
-})
-
-#define rxrpc_call_is_ack_pending(CALL) ((CALL)->ackr.reason != 0)
-
-extern int rxrpc_create_call(struct rxrpc_connection *conn,
-			     rxrpc_call_attn_func_t attn,
-			     rxrpc_call_error_func_t error,
-			     rxrpc_call_aemap_func_t aemap,
-			     struct rxrpc_call **_call);
-
-extern int rxrpc_incoming_call(struct rxrpc_connection *conn,
-			       struct rxrpc_message *msg,
-			       struct rxrpc_call **_call);
-
-static inline void rxrpc_get_call(struct rxrpc_call *call)
-{
-	BUG_ON(atomic_read(&call->usage)<=0);
-	atomic_inc(&call->usage);
-	/*printk("rxrpc_get_call(%p{u=%d})\n",(C),atomic_read(&(C)->usage));*/
-}
-
-extern void rxrpc_put_call(struct rxrpc_call *call);
-
-extern void rxrpc_call_do_stuff(struct rxrpc_call *call);
-
-extern int rxrpc_call_abort(struct rxrpc_call *call, int error);
-
-#define RXRPC_CALL_READ_BLOCK	0x0001	/* block if not enough data and not yet EOF */
-#define RXRPC_CALL_READ_ALL	0x0002	/* error if insufficient data received */
-extern int rxrpc_call_read_data(struct rxrpc_call *call, void *buffer, size_t size, int flags);
-
-extern int rxrpc_call_write_data(struct rxrpc_call *call,
-				 size_t sioc,
-				 struct kvec *siov,
-				 uint8_t rxhdr_flags,
-				 gfp_t alloc_flags,
-				 int dup_data,
-				 size_t *size_sent);
-
-extern void rxrpc_call_handle_error(struct rxrpc_call *conn, int local, int errno);
-
-#endif /* _LINUX_RXRPC_CALL_H */
diff --git a/include/rxrpc/connection.h b/include/rxrpc/connection.h
deleted file mode 100644
index 41e6781..0000000
--- a/include/rxrpc/connection.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* connection.h: Rx connection record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_CONNECTION_H
-#define _LINUX_RXRPC_CONNECTION_H
-
-#include <rxrpc/types.h>
-#include <rxrpc/krxtimod.h>
-
-struct sk_buff;
-
-/*****************************************************************************/
-/*
- * Rx connection
- * - connections are matched by (rmt_port,rmt_addr,service_id,conn_id,clientflag)
- * - connections only retain a refcount on the peer when they are active
- * - connections with refcount==0 are inactive and reside in the peer's graveyard
- */
-struct rxrpc_connection
-{
-	atomic_t		usage;
-	struct rxrpc_transport	*trans;		/* transport endpoint */
-	struct rxrpc_peer	*peer;		/* peer from/to which connected */
-	struct rxrpc_service	*service;	/* responsible service (inbound conns) */
-	struct rxrpc_timer	timeout;	/* decaching timer */
-	struct list_head	link;		/* link in peer's list */
-	struct list_head	proc_link;	/* link in proc list */
-	struct list_head	err_link;	/* link in ICMP error processing list */
-	struct list_head	id_link;	/* link in ID grant list */
-	struct sockaddr_in	addr;		/* remote address */
-	struct rxrpc_call	*channels[4];	/* channels (active calls) */
-	wait_queue_head_t	chanwait;	/* wait for channel to become available */
-	spinlock_t		lock;		/* access lock */
-	struct timeval		atime;		/* last access time */
-	size_t			mtu_size;	/* MTU size for outbound messages */
-	unsigned		call_counter;	/* call ID counter */
-	rxrpc_serial_t		serial_counter;	/* packet serial number counter */
-
-	/* the following should all be in net order */
-	__be32			in_epoch;	/* peer's epoch */
-	__be32			out_epoch;	/* my epoch */
-	__be32			conn_id;	/* connection ID, appropriately shifted */
-	__be16			service_id;	/* service ID */
-	uint8_t			security_ix;	/* security ID */
-	uint8_t			in_clientflag;	/* RXRPC_CLIENT_INITIATED if we are server */
-	uint8_t			out_clientflag;	/* RXRPC_CLIENT_INITIATED if we are client */
-};
-
-extern int rxrpc_create_connection(struct rxrpc_transport *trans,
-				   __be16 port,
-				   __be32 addr,
-				   uint16_t service_id,
-				   void *security,
-				   struct rxrpc_connection **_conn);
-
-extern int rxrpc_connection_lookup(struct rxrpc_peer *peer,
-				   struct rxrpc_message *msg,
-				   struct rxrpc_connection **_conn);
-
-static inline void rxrpc_get_connection(struct rxrpc_connection *conn)
-{
-	BUG_ON(atomic_read(&conn->usage)<0);
-	atomic_inc(&conn->usage);
-	//printk("rxrpc_get_conn(%p{u=%d})\n",conn,atomic_read(&conn->usage));
-}
-
-extern void rxrpc_put_connection(struct rxrpc_connection *conn);
-
-extern int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn,
-					  struct rxrpc_call *call,
-					  struct rxrpc_message *msg);
-
-extern void rxrpc_conn_handle_error(struct rxrpc_connection *conn, int local, int errno);
-
-#endif /* _LINUX_RXRPC_CONNECTION_H */
diff --git a/include/rxrpc/krxiod.h b/include/rxrpc/krxiod.h
deleted file mode 100644
index c0e0e82..0000000
--- a/include/rxrpc/krxiod.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* krxiod.h: Rx RPC I/O kernel thread interface
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_KRXIOD_H
-#define _LINUX_RXRPC_KRXIOD_H
-
-#include <rxrpc/types.h>
-
-extern int rxrpc_krxiod_init(void);
-extern void rxrpc_krxiod_kill(void);
-extern void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans);
-extern void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans);
-extern void rxrpc_krxiod_queue_peer(struct rxrpc_peer *peer);
-extern void rxrpc_krxiod_dequeue_peer(struct rxrpc_peer *peer);
-extern void rxrpc_krxiod_clear_peers(struct rxrpc_transport *trans);
-extern void rxrpc_krxiod_queue_call(struct rxrpc_call *call);
-extern void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call);
-
-#endif /* _LINUX_RXRPC_KRXIOD_H */
diff --git a/include/rxrpc/krxsecd.h b/include/rxrpc/krxsecd.h
deleted file mode 100644
index 55ce43a..0000000
--- a/include/rxrpc/krxsecd.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* krxsecd.h: Rx RPC security kernel thread interface
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_KRXSECD_H
-#define _LINUX_RXRPC_KRXSECD_H
-
-#include <rxrpc/types.h>
-
-extern int rxrpc_krxsecd_init(void);
-extern void rxrpc_krxsecd_kill(void);
-extern void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans);
-extern void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg);
-
-#endif /* _LINUX_RXRPC_KRXSECD_H */
diff --git a/include/rxrpc/krxtimod.h b/include/rxrpc/krxtimod.h
deleted file mode 100644
index b3d298b..0000000
--- a/include/rxrpc/krxtimod.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* krxtimod.h: RxRPC timeout daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_KRXTIMOD_H
-#define _LINUX_RXRPC_KRXTIMOD_H
-
-#include <rxrpc/types.h>
-
-struct rxrpc_timer_ops {
-	/* called when the front of the timer queue has timed out */
-	void (*timed_out)(struct rxrpc_timer *timer);
-};
-
-/*****************************************************************************/
-/*
- * RXRPC timer/timeout record
- */
-struct rxrpc_timer
-{
-	struct list_head		link;		/* link in timer queue */
-	unsigned long			timo_jif;	/* timeout time */
-	const struct rxrpc_timer_ops	*ops;		/* timeout expiry function */
-};
-
-static inline void rxrpc_timer_init(rxrpc_timer_t *timer, const struct rxrpc_timer_ops *ops)
-{
-	INIT_LIST_HEAD(&timer->link);
-	timer->ops = ops;
-}
-
-extern int rxrpc_krxtimod_start(void);
-extern void rxrpc_krxtimod_kill(void);
-
-extern void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout);
-extern int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer);
-
-#endif /* _LINUX_RXRPC_KRXTIMOD_H */
diff --git a/include/rxrpc/message.h b/include/rxrpc/message.h
deleted file mode 100644
index b318f27..0000000
--- a/include/rxrpc/message.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* message.h: Rx message caching
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_MESSAGE_H
-#define _LINUX_RXRPC_MESSAGE_H
-
-#include <rxrpc/packet.h>
-
-/*****************************************************************************/
-/*
- * Rx message record
- */
-struct rxrpc_message
-{
-	atomic_t		usage;
-	struct list_head	link;		/* list link */
-	struct timeval		stamp;		/* time received or last sent */
-	rxrpc_seq_t		seq;		/* message sequence number */
-
-	int			state;		/* the state the message is currently in */
-#define RXRPC_MSG_PREPARED	0
-#define RXRPC_MSG_SENT		1
-#define RXRPC_MSG_ACKED		2		/* provisionally ACK'd */
-#define RXRPC_MSG_DONE		3		/* definitively ACK'd (msg->seq<ack.firstPacket) */
-#define RXRPC_MSG_RECEIVED	4
-#define RXRPC_MSG_ERROR		-1
-	char			rttdone;	/* used for RTT */
-
-	struct rxrpc_transport	*trans;		/* transport received through */
-	struct rxrpc_connection	*conn;		/* connection received over */
-	struct sk_buff		*pkt;		/* received packet */
-	off_t			offset;		/* offset into pkt of next byte of data */
-
-	struct rxrpc_header	hdr;		/* message header */
-
-	int			dcount;		/* data part count */
-	size_t			dsize;		/* data size */
-#define RXRPC_MSG_MAX_IOCS 8
-	struct kvec		data[RXRPC_MSG_MAX_IOCS]; /* message data */
-	unsigned long		dfree;		/* bit mask indicating kfree(data[x]) if T */
-};
-
-#define rxrpc_get_message(M) do { atomic_inc(&(M)->usage); } while(0)
-
-extern void __rxrpc_put_message(struct rxrpc_message *msg);
-static inline void rxrpc_put_message(struct rxrpc_message *msg)
-{
-	BUG_ON(atomic_read(&msg->usage)<=0);
-	if (atomic_dec_and_test(&msg->usage))
-		__rxrpc_put_message(msg);
-}
-
-extern int rxrpc_conn_newmsg(struct rxrpc_connection *conn,
-			     struct rxrpc_call *call,
-			     uint8_t type,
-			     int count,
-			     struct kvec *diov,
-			     gfp_t alloc_flags,
-			     struct rxrpc_message **_msg);
-
-extern int rxrpc_conn_sendmsg(struct rxrpc_connection *conn, struct rxrpc_message *msg);
-
-#endif /* _LINUX_RXRPC_MESSAGE_H */
diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h
index 1447f0a..b69e6e1 100644
--- a/include/rxrpc/packet.h
+++ b/include/rxrpc/packet.h
@@ -1,6 +1,6 @@
 /* packet.h: Rx packet layout and definitions
  *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -12,28 +12,25 @@
 #ifndef _LINUX_RXRPC_PACKET_H
 #define _LINUX_RXRPC_PACKET_H
 
-#include <rxrpc/types.h>
-
-#define RXRPC_IPUDP_SIZE		28
-extern size_t RXRPC_MAX_PACKET_SIZE;
-#define RXRPC_MAX_PACKET_DATA_SIZE	(RXRPC_MAX_PACKET_SIZE - sizeof(struct rxrpc_header))
-#define RXRPC_LOCAL_PACKET_SIZE		RXRPC_MAX_PACKET_SIZE
-#define RXRPC_REMOTE_PACKET_SIZE	(576 - RXRPC_IPUDP_SIZE)
+typedef u32	rxrpc_seq_t;	/* Rx message sequence number */
+typedef u32	rxrpc_serial_t;	/* Rx message serial number */
+typedef __be32	rxrpc_seq_net_t; /* on-the-wire Rx message sequence number */
+typedef __be32	rxrpc_serial_net_t; /* on-the-wire Rx message serial number */
 
 /*****************************************************************************/
 /*
  * on-the-wire Rx packet header
  * - all multibyte fields should be in network byte order
  */
-struct rxrpc_header
-{
+struct rxrpc_header {
 	__be32		epoch;		/* client boot timestamp */
 
 	__be32		cid;		/* connection and channel ID */
 #define RXRPC_MAXCALLS		4			/* max active calls per conn */
 #define RXRPC_CHANNELMASK	(RXRPC_MAXCALLS-1)	/* mask for channel ID */
 #define RXRPC_CIDMASK		(~RXRPC_CHANNELMASK)	/* mask for connection ID */
-#define RXRPC_CIDSHIFT		2			/* shift for connection ID */
+#define RXRPC_CIDSHIFT		ilog2(RXRPC_MAXCALLS)	/* shift for connection ID */
+#define RXRPC_CID_INC		(1 << RXRPC_CIDSHIFT)	/* connection ID increment */
 
 	__be32		callNumber;	/* call ID (0 for connection-level packets) */
 #define RXRPC_PROCESS_MAXCALLS	(1<<2)	/* maximum number of active calls per conn (power of 2) */
@@ -62,7 +59,10 @@ #define RXRPC_SLOW_START_OK	0x20		/* [AC
 
 	uint8_t		userStatus;	/* app-layer defined status */
 	uint8_t		securityIndex;	/* security protocol ID */
-	__be16		_rsvd;		/* reserved (used by kerberos security as cksum) */
+	union {
+		__be16	_rsvd;		/* reserved */
+		__be16	cksum;		/* kerberos security checksum */
+	};
 	__be16		serviceId;	/* service ID */
 
 } __attribute__((packed));
@@ -81,8 +81,7 @@ extern const char *rxrpc_pkts[];
  *   - new__rsvd = j__rsvd
  *   - duplicating all other fields
  */
-struct rxrpc_jumbo_header
-{
+struct rxrpc_jumbo_header {
 	uint8_t		flags;		/* packet flags (as per rxrpc_header) */
 	uint8_t		pad;
 	__be16		_rsvd;		/* reserved (used by kerberos security as cksum) */
@@ -95,8 +94,7 @@ #define RXRPC_JUMBO_DATALEN	1412	/* non-
  * on-the-wire Rx ACK packet data payload
  * - all multibyte fields should be in network byte order
  */
-struct rxrpc_ackpacket
-{
+struct rxrpc_ackpacket {
 	__be16		bufferSpace;	/* number of packet buffers available */
 	__be16		maxSkew;	/* diff between serno being ACK'd and highest serial no
 					 * received */
@@ -124,4 +122,93 @@ #define RXRPC_ACK_TYPE_ACK		1
 
 } __attribute__((packed));
 
+/*
+ * ACK packets can have a further piece of information tagged on the end
+ */
+struct rxrpc_ackinfo {
+	__be32		rxMTU;		/* maximum Rx MTU size (bytes) [AFS 3.3] */
+	__be32		maxMTU;		/* maximum interface MTU size (bytes) [AFS 3.3] */
+	__be32		rwind;		/* Rx window size (packets) [AFS 3.4] */
+	__be32		jumbo_max;	/* max packets to stick into a jumbo packet [AFS 3.5] */
+};
+
+/*****************************************************************************/
+/*
+ * Kerberos security type-2 challenge packet
+ */
+struct rxkad_challenge {
+	__be32		version;	/* version of this challenge type */
+	__be32		nonce;		/* encrypted random number */
+	__be32		min_level;	/* minimum security level */
+	__be32		__padding;	/* padding to 8-byte boundary */
+} __attribute__((packed));
+
+/*****************************************************************************/
+/*
+ * Kerberos security type-2 response packet
+ */
+struct rxkad_response {
+	__be32		version;	/* version of this reponse type */
+	__be32		__pad;
+
+	/* encrypted bit of the response */
+	struct {
+		__be32		epoch;		/* current epoch */
+		__be32		cid;		/* parent connection ID */
+		__be32		checksum;	/* checksum */
+		__be32		securityIndex;	/* security type */
+		__be32		call_id[4];	/* encrypted call IDs */
+		__be32		inc_nonce;	/* challenge nonce + 1 */
+		__be32		level;		/* desired level */
+	} encrypted;
+
+	__be32		kvno;		/* Kerberos key version number */
+	__be32		ticket_len;	/* Kerberos ticket length  */
+} __attribute__((packed));
+
+/*****************************************************************************/
+/*
+ * RxRPC-level abort codes
+ */
+#define RX_CALL_DEAD		-1	/* call/conn has been inactive and is shut down */
+#define RX_INVALID_OPERATION	-2	/* invalid operation requested / attempted */
+#define RX_CALL_TIMEOUT		-3	/* call timeout exceeded */
+#define RX_EOF			-4	/* unexpected end of data on read op */
+#define RX_PROTOCOL_ERROR	-5	/* low-level protocol error */
+#define RX_USER_ABORT		-6	/* generic user abort */
+#define RX_ADDRINUSE		-7	/* UDP port in use */
+#define RX_DEBUGI_BADTYPE	-8	/* bad debugging packet type */
+
+/*
+ * (un)marshalling abort codes (rxgen)
+ */
+#define	RXGEN_CC_MARSHAL    -450
+#define	RXGEN_CC_UNMARSHAL  -451
+#define	RXGEN_SS_MARSHAL    -452
+#define	RXGEN_SS_UNMARSHAL  -453
+#define	RXGEN_DECODE	    -454
+#define	RXGEN_OPCODE	    -455
+#define	RXGEN_SS_XDRFREE    -456
+#define	RXGEN_CC_XDRFREE    -457
+
+/*
+ * Rx kerberos security abort codes
+ * - unfortunately we have no generalised security abort codes to say things
+ *   like "unsupported security", so we have to use these instead and hope the
+ *   other side understands
+ */
+#define RXKADINCONSISTENCY	19270400	/* security module structure inconsistent */
+#define RXKADPACKETSHORT	19270401	/* packet too short for security challenge */
+#define RXKADLEVELFAIL		19270402	/* security level negotiation failed */
+#define RXKADTICKETLEN		19270403	/* ticket length too short or too long */
+#define RXKADOUTOFSEQUENCE	19270404	/* packet had bad sequence number */
+#define RXKADNOAUTH		19270405	/* caller not authorised */
+#define RXKADBADKEY		19270406	/* illegal key: bad parity or weak */
+#define RXKADBADTICKET		19270407	/* security object was passed a bad ticket */
+#define RXKADUNKNOWNKEY		19270408	/* ticket contained unknown key version number */
+#define RXKADEXPIRED		19270409	/* authentication expired */
+#define RXKADSEALEDINCON	19270410	/* sealed data inconsistent */
+#define RXKADDATALEN		19270411	/* user data too long */
+#define RXKADILLEGALLEVEL	19270412	/* caller not authorised to use encrypted conns */
+
 #endif /* _LINUX_RXRPC_PACKET_H */
diff --git a/include/rxrpc/peer.h b/include/rxrpc/peer.h
deleted file mode 100644
index 8b8fe97..0000000
--- a/include/rxrpc/peer.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* peer.h: Rx RPC per-transport peer record
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_PEER_H
-#define _LINUX_RXRPC_PEER_H
-
-#include <linux/wait.h>
-#include <rxrpc/types.h>
-#include <rxrpc/krxtimod.h>
-
-struct rxrpc_peer_ops
-{
-	/* peer record being added */
-	int (*adding)(struct rxrpc_peer *peer);
-
-	/* peer record being discarded from graveyard */
-	void (*discarding)(struct rxrpc_peer *peer);
-
-	/* change of epoch detected on connection */
-	void (*change_of_epoch)(struct rxrpc_connection *conn);
-};
-
-/*****************************************************************************/
-/*
- * Rx RPC per-transport peer record
- * - peers only retain a refcount on the transport when they are active
- * - peers with refcount==0 are inactive and reside in the transport's graveyard
- */
-struct rxrpc_peer
-{
-	atomic_t		usage;
-	struct rxrpc_peer_ops	*ops;		/* operations on this peer */
-	struct rxrpc_transport	*trans;		/* owner transport */
-	struct rxrpc_timer	timeout;	/* timeout for grave destruction */
-	struct list_head	link;		/* link in transport's peer list */
-	struct list_head	proc_link;	/* link in /proc list */
-	rwlock_t		conn_idlock;	/* lock for connection IDs */
-	struct list_head	conn_idlist;	/* list of connections granted IDs */
-	uint32_t		conn_idcounter;	/* connection ID counter */
-	rwlock_t		conn_lock;	/* lock for active/dead connections */
-	struct list_head	conn_active;	/* active connections to/from this peer */
-	struct list_head	conn_graveyard;	/* graveyard for inactive connections */
-	spinlock_t		conn_gylock;	/* lock for conn_graveyard */
-	wait_queue_head_t	conn_gy_waitq;	/* wait queue hit when graveyard is empty */
-	atomic_t		conn_count;	/* number of attached connections */
-	struct in_addr		addr;		/* remote address */
-	size_t			if_mtu;		/* interface MTU for this peer */
-	spinlock_t		lock;		/* access lock */
-
-	void			*user;		/* application layer data */
-
-	/* calculated RTT cache */
-#define RXRPC_RTT_CACHE_SIZE 32
-	suseconds_t		rtt;		/* current RTT estimate (in uS) */
-	unsigned		rtt_point;	/* next entry at which to insert */
-	unsigned		rtt_usage;	/* amount of cache actually used */
-	suseconds_t		rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */
-};
-
-
-extern int rxrpc_peer_lookup(struct rxrpc_transport *trans,
-			     __be32 addr,
-			     struct rxrpc_peer **_peer);
-
-static inline void rxrpc_get_peer(struct rxrpc_peer *peer)
-{
-	BUG_ON(atomic_read(&peer->usage)<0);
-	atomic_inc(&peer->usage);
-	//printk("rxrpc_get_peer(%p{u=%d})\n",peer,atomic_read(&peer->usage));
-}
-
-extern void rxrpc_put_peer(struct rxrpc_peer *peer);
-
-#endif /* _LINUX_RXRPC_PEER_H */
diff --git a/include/rxrpc/rxrpc.h b/include/rxrpc/rxrpc.h
deleted file mode 100644
index 8d9874c..0000000
--- a/include/rxrpc/rxrpc.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* rx.h: Rx RPC interface
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_RXRPC_H
-#define _LINUX_RXRPC_RXRPC_H
-
-#ifdef __KERNEL__
-
-extern __be32 rxrpc_epoch;
-
-#ifdef CONFIG_SYSCTL
-extern int rxrpc_ktrace;
-extern int rxrpc_kdebug;
-extern int rxrpc_kproto;
-extern int rxrpc_knet;
-#else
-#define rxrpc_ktrace	0
-#define rxrpc_kdebug	0
-#define rxrpc_kproto	0
-#define rxrpc_knet	0
-#endif
-
-extern int rxrpc_sysctl_init(void);
-extern void rxrpc_sysctl_cleanup(void);
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_RXRPC_RXRPC_H */
diff --git a/include/rxrpc/transport.h b/include/rxrpc/transport.h
deleted file mode 100644
index 7c7b968..0000000
--- a/include/rxrpc/transport.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* transport.h: Rx transport management
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_TRANSPORT_H
-#define _LINUX_RXRPC_TRANSPORT_H
-
-#include <rxrpc/types.h>
-#include <rxrpc/krxiod.h>
-#include <rxrpc/rxrpc.h>
-#include <linux/skbuff.h>
-#include <linux/rwsem.h>
-
-typedef int (*rxrpc_newcall_fnx_t)(struct rxrpc_call *call);
-
-extern wait_queue_head_t rxrpc_krxiod_wq;
-
-/*****************************************************************************/
-/*
- * Rx operation specification
- * - tables of these must be sorted by op ID so that they can be binary-chop searched
- */
-struct rxrpc_operation
-{
-	unsigned		id;		/* operation ID */
-	size_t			asize;		/* minimum size of argument block */
-	const char		*name;		/* name of operation */
-	void			*user;		/* initial user data */
-};
-
-/*****************************************************************************/
-/*
- * Rx transport service record
- */
-struct rxrpc_service
-{
-	struct list_head	link;		/* link in services list on transport */
-	struct module		*owner;		/* owner module */
-	rxrpc_newcall_fnx_t	new_call;	/* new call handler function */
-	const char		*name;		/* name of service */
-	unsigned short		service_id;	/* Rx service ID */
-	rxrpc_call_attn_func_t	attn_func;	/* call requires attention callback */
-	rxrpc_call_error_func_t	error_func;	/* call error callback */
-	rxrpc_call_aemap_func_t	aemap_func;	/* abort -> errno mapping callback */
-
-	const struct rxrpc_operation	*ops_begin;	/* beginning of operations table */
-	const struct rxrpc_operation	*ops_end;	/* end of operations table */
-};
-
-/*****************************************************************************/
-/*
- * Rx transport endpoint record
- */
-struct rxrpc_transport
-{
-	atomic_t		usage;
-	struct socket		*socket;	/* my UDP socket */
-	struct list_head	services;	/* services listening on this socket */
-	struct list_head	link;		/* link in transport list */
-	struct list_head	proc_link;	/* link in transport proc list */
-	struct list_head	krxiodq_link;	/* krxiod attention queue link */
-	spinlock_t		lock;		/* access lock */
-	struct list_head	peer_active;	/* active peers connected to over this socket */
-	struct list_head	peer_graveyard;	/* inactive peer list */
-	spinlock_t		peer_gylock;	/* peer graveyard lock */
-	wait_queue_head_t	peer_gy_waitq;	/* wait queue hit when peer graveyard is empty */
-	rwlock_t		peer_lock;	/* peer list access lock */
-	atomic_t		peer_count;	/* number of peers */
-	struct rxrpc_peer_ops	*peer_ops;	/* default peer operations */
-	unsigned short		port;		/* port upon which listening */
-	volatile char		error_rcvd;	/* T if received ICMP error outstanding */
-};
-
-extern int rxrpc_create_transport(unsigned short port,
-				  struct rxrpc_transport **_trans);
-
-static inline void rxrpc_get_transport(struct rxrpc_transport *trans)
-{
-	BUG_ON(atomic_read(&trans->usage) <= 0);
-	atomic_inc(&trans->usage);
-	//printk("rxrpc_get_transport(%p{u=%d})\n",
-	//       trans, atomic_read(&trans->usage));
-}
-
-extern void rxrpc_put_transport(struct rxrpc_transport *trans);
-
-extern int rxrpc_add_service(struct rxrpc_transport *trans,
-			     struct rxrpc_service *srv);
-
-extern void rxrpc_del_service(struct rxrpc_transport *trans,
-			      struct rxrpc_service *srv);
-
-extern void rxrpc_trans_receive_packet(struct rxrpc_transport *trans);
-
-extern int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans,
-				       struct rxrpc_message *msg,
-				       int error);
-
-#endif /* _LINUX_RXRPC_TRANSPORT_H */
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 4a44278..8d1e4e8 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -588,7 +588,17 @@ #define KEY_MAXLEN		64
 #define VALUE_MAXLEN		255
 #define TARGET_NAME_MAXLEN	VALUE_MAXLEN
 
-#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH	8192
+#define ISCSI_DEF_MAX_RECV_SEG_LEN		8192
+#define ISCSI_MIN_MAX_RECV_SEG_LEN		512
+#define ISCSI_MAX_MAX_RECV_SEG_LEN		16777215
+
+#define ISCSI_DEF_FIRST_BURST_LEN		65536
+#define ISCSI_MIN_FIRST_BURST_LEN		512
+#define ISCSI_MAX_FIRST_BURST_LEN		16777215
+
+#define ISCSI_DEF_MAX_BURST_LEN			262144
+#define ISCSI_MIN_MAX_BURST_LEN			512
+#define ISCSI_MAX_MAX_BURST_LEN			16777215
 
 /************************* RFC 3720 End *****************************/
 
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 5c0e979..9f8f80a 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -203,6 +203,7 @@ #define MISCOMPARE          0x0e
 
 /*
  *  DEVICE TYPES
+ *  Please keep them in 0x%02x format for $MODALIAS to work
  */
 
 #define TYPE_DISK           0x00
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index d6948d0..a2e0c10 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -73,9 +73,6 @@ #define MAX_COMMAND_SIZE	16
 	unsigned short use_sg;	/* Number of pieces of scatter-gather */
 	unsigned short sglist_len;	/* size of malloc'd scatter-gather list */
 
-	/* offset in cmd we are at (for multi-transfer tgt cmds) */
-	unsigned offset;
-
 	unsigned underflow;	/* Return error if less than
 				   this amount is transferred */
 
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index 3bbbfbe..5a43a4c 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -5,14 +5,16 @@ struct scsi_cmnd;
 struct scsi_sense_hdr;
 
 extern void scsi_print_command(struct scsi_cmnd *);
-extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
 extern void __scsi_print_command(unsigned char *);
-extern void scsi_print_sense(const char *, struct scsi_cmnd *);
+extern void scsi_show_extd_sense(unsigned char, unsigned char);
+extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
+extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
+extern void scsi_print_sense(char *, struct scsi_cmnd *);
 extern void __scsi_print_sense(const char *name,
 			       const unsigned char *sense_buffer,
 			       int sense_len);
-extern void scsi_print_driverbyte(int);
-extern void scsi_print_hostbyte(int);
+extern void scsi_show_result(int);
+extern void scsi_print_result(struct scsi_cmnd *);
 extern void scsi_print_status(unsigned char);
 extern const char *scsi_sense_key_string(unsigned char);
 extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 9dd37e2..2f3c5b8 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -5,6 +5,7 @@ #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
+#include <linux/blkdev.h>
 #include <asm/atomic.h>
 
 struct request_queue;
@@ -119,6 +120,7 @@ struct scsi_device {
 	unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
 	unsigned no_start_on_add:1;	/* do not issue start on add */
 	unsigned allow_restart:1; /* issue START_UNIT in error handler */
+	unsigned manage_start_stop:1;	/* Let HLD (sd) manage start/stop */
 	unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
 	unsigned select_no_atn:1;
 	unsigned fix_capacity:1;	/* READ_CAPACITY is too high by 1 */
@@ -154,8 +156,11 @@ #define transport_class_to_sdev(class_de
 #define sdev_printk(prefix, sdev, fmt, a...)	\
 	dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
 
-#define scmd_printk(prefix, scmd, fmt, a...)	\
-	dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a)
+#define scmd_printk(prefix, scmd, fmt, a...)				\
+        (scmd)->request->rq_disk ?					\
+	sdev_printk(prefix, (scmd)->device, "[%s] " fmt,		\
+		    (scmd)->request->rq_disk->disk_name, ##a) :		\
+	sdev_printk(prefix, (scmd)->device, fmt, ##a)
 
 enum scsi_target_state {
 	STARGET_RUNNING = 1,
@@ -353,4 +358,9 @@ static inline int scsi_device_qas(struct
 		return 0;
 	return sdev->inquiry[56] & 0x02;
 }
+
+#define MODULE_ALIAS_SCSI_DEVICE(type) \
+	MODULE_ALIAS("scsi:t-" __stringify(type) "*")
+#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"
+
 #endif /* _SCSI_SCSI_DEVICE_H */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7f1f411..68f461b 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -129,6 +129,11 @@ #endif
 	 * the LLD. When the driver is finished processing the command
 	 * the done callback is invoked.
 	 *
+	 * This is called to inform the LLD to transfer
+	 * cmd->request_bufflen bytes. The cmd->use_sg speciefies the
+	 * number of scatterlist entried in the command and
+	 * cmd->request_buffer contains the scatterlist.
+	 *
 	 * return values: see queuecommand
 	 *
 	 * If the LLD accepts the cmd, it should set the result to an
@@ -139,20 +144,6 @@ #endif
 	/* TODO: rename */
 	int (* transfer_response)(struct scsi_cmnd *,
 				  void (*done)(struct scsi_cmnd *));
-	/*
-	 * This is called to inform the LLD to transfer cmd->request_bufflen
-	 * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
-	 * speciefies the number of scatterlist entried in the command
-	 * and cmd->request_buffer contains the scatterlist.
-	 *
-	 * If the command cannot be processed in one transfer_data call
-	 * becuase a scatterlist within the LLD's limits cannot be
-	 * created then transfer_data will be called multiple times.
-	 * It is initially called from process context, and later
-	 * calls are from the interrup context.
-	 */
-	int (* transfer_data)(struct scsi_cmnd *,
-			      void (*done)(struct scsi_cmnd *));
 
 	/* Used as callback for the completion of task management request. */
 	int (* tsk_mgmt_response)(u64 mid, int result);
@@ -335,6 +326,19 @@ #endif
 	int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
 
 	/*
+	 * This is an optional routine that allows the transport to become
+	 * involved when a scsi io timer fires. The return value tells the
+	 * timer routine how to finish the io timeout handling:
+	 * EH_HANDLED:		I fixed the error, please complete the command
+	 * EH_RESET_TIMER:	I need more time, reset the timer and
+	 *			begin counting again
+	 * EH_NOT_HANDLED	Begin normal error recovery
+	 *
+	 * Status: OPTIONAL
+	 */
+	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
+	/*
 	 * suspend support
 	 */
 	int (*resume)(struct scsi_device *);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index 07d6e77..4cf9dff 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -45,11 +45,13 @@ struct tgt_event {
 		/* user-> kernel */
 		struct {
 			int host_no;
-			uint32_t len;
 			int result;
+			aligned_u64 tag;
 			aligned_u64 uaddr;
+			aligned_u64 sense_uaddr;
+			uint32_t len;
+			uint32_t sense_len;
 			uint8_t rw;
-			aligned_u64 tag;
 		} cmd_rsp;
 		struct {
 			int host_no;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 798f7c7..1e79730 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -108,6 +108,8 @@ #define FC_PORTSPEED_1GBIT		1
 #define FC_PORTSPEED_2GBIT		2
 #define FC_PORTSPEED_4GBIT		4
 #define FC_PORTSPEED_10GBIT		8
+#define FC_PORTSPEED_8GBIT		0x10
+#define FC_PORTSPEED_16GBIT		0x20
 #define FC_PORTSPEED_NOT_NEGOTIATED	(1 << 15) /* Speed not established */
 
 /*
diff --git a/include/scsi/sd.h b/include/scsi/sd.h
new file mode 100644
index 0000000..5261488
--- /dev/null
+++ b/include/scsi/sd.h
@@ -0,0 +1,72 @@
+#ifndef _SCSI_DISK_H
+#define _SCSI_DISK_H
+
+/*
+ * More than enough for everybody ;)  The huge number of majors
+ * is a leftover from 16bit dev_t days, we don't really need that
+ * much numberspace.
+ */
+#define SD_MAJORS	16
+
+/*
+ * This is limited by the naming scheme enforced in sd_probe,
+ * add another character to it if you really need more disks.
+ */
+#define SD_MAX_DISKS	(((26 * 26) + 26 + 1) * 26)
+
+/*
+ * Time out in seconds for disks and Magneto-opticals (which are slower).
+ */
+#define SD_TIMEOUT		(30 * HZ)
+#define SD_MOD_TIMEOUT		(75 * HZ)
+
+/*
+ * Number of allowed retries
+ */
+#define SD_MAX_RETRIES		5
+#define SD_PASSTHROUGH_RETRIES	1
+
+/*
+ * Size of the initial data buffer for mode and read capacity data
+ */
+#define SD_BUF_SIZE		512
+
+struct scsi_disk {
+	struct scsi_driver *driver;	/* always &sd_template */
+	struct scsi_device *device;
+	struct class_device cdev;
+	struct gendisk	*disk;
+	unsigned int	openers;	/* protected by BKL for now, yuck */
+	sector_t	capacity;	/* size in 512-byte sectors */
+	u32		index;
+	u8		media_present;
+	u8		write_prot;
+	unsigned	WCE : 1;	/* state of disk WCE bit */
+	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
+	unsigned	DPOFUA : 1;	/* state of disk DPOFUA bit */
+};
+#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
+
+static int  sd_revalidate_disk(struct gendisk *disk);
+static void sd_rw_intr(struct scsi_cmnd * SCpnt);
+static int  sd_probe(struct device *);
+static int  sd_remove(struct device *);
+static void sd_shutdown(struct device *dev);
+static int sd_suspend(struct device *dev, pm_message_t state);
+static int sd_resume(struct device *dev);
+static void sd_rescan(struct device *);
+static int  sd_init_command(struct scsi_cmnd *);
+static int  sd_issue_flush(struct device *, sector_t *);
+static void sd_prepare_flush(request_queue_t *, struct request *);
+static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
+static void scsi_disk_release(struct class_device *cdev);
+static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
+static void sd_print_result(struct scsi_disk *, int);
+
+#define sd_printk(prefix, sdsk, fmt, a...)				\
+        (sdsk)->disk ?							\
+	sdev_printk(prefix, (sdsk)->device, "[%s] " fmt,		\
+		    (sdsk)->disk->disk_name, ##a) :			\
+	sdev_printk(prefix, (sdsk)->device, fmt, ##a)
+
+#endif /* _SCSI_DISK_H */
diff --git a/include/video/mach64.h b/include/video/mach64.h
index 09a7f4a..a8332e5 100644
--- a/include/video/mach64.h
+++ b/include/video/mach64.h
@@ -885,6 +885,7 @@ #define PSEUDO_EDO		3
 #define SDRAM			4
 #define SGRAM			5
 #define WRAM			6
+#define SDRAM32			6
 
 #define DAC_INTERNAL		0x00
 #define DAC_IBMRGB514		0x01
diff --git a/include/video/permedia2.h b/include/video/permedia2.h
index b95d362..9e49c95 100644
--- a/include/video/permedia2.h
+++ b/include/video/permedia2.h
@@ -154,6 +154,10 @@ #define PM2VI_RD_CLK0_POSTSCALE				0x203
 #define PM2VI_RD_CLK1_PRESCALE				0x204
 #define PM2VI_RD_CLK1_FEEDBACK				0x205
 #define PM2VI_RD_CLK1_POSTSCALE				0x206
+#define PM2VI_RD_MCLK_CONTROL				0x20D
+#define PM2VI_RD_MCLK_PRESCALE				0x20E
+#define PM2VI_RD_MCLK_FEEDBACK				0x20F
+#define PM2VI_RD_MCLK_POSTSCALE				0x210
 #define PM2VI_RD_CURSOR_PALETTE				0x303
 #define PM2VI_RD_CURSOR_PATTERN				0x400
 
diff --git a/include/video/tgafb.h b/include/video/tgafb.h
index be2b3e9..03d0dbe 100644
--- a/include/video/tgafb.h
+++ b/include/video/tgafb.h
@@ -39,6 +39,7 @@ #define	TGA_MODE_REG			0x0030
 #define	TGA_RASTEROP_REG		0x0034
 #define	TGA_PIXELSHIFT_REG		0x0038
 #define	TGA_DEEP_REG			0x0050
+#define	TGA_START_REG			0x0054
 #define	TGA_PIXELMASK_REG		0x005c
 #define	TGA_CURSOR_BASE_REG		0x0060
 #define	TGA_HORIZ_REG			0x0064
@@ -140,7 +141,7 @@ #define	BT485_CUR_HIGH_Y		0x1e
 
 
 /*
- * Useful defines for managing the BT463 on the 24-plane TGAs
+ * Useful defines for managing the BT463 on the 24-plane TGAs/SFB+s
  */
 
 #define	BT463_ADDR_LO		0x0
@@ -168,12 +169,35 @@ #define	BT463_BLINK_MASK_3	0x020c
 #define	BT463_WINDOW_TYPE_BASE	0x0300
 
 /*
+ * Useful defines for managing the BT459 on the 8-plane SFB+s
+ */
+
+#define	BT459_ADDR_LO		0x0
+#define	BT459_ADDR_HI		0x1
+#define	BT459_REG_ACC		0x2
+#define	BT459_PALETTE		0x3
+
+#define	BT459_CUR_CLR_1		0x0181
+#define	BT459_CUR_CLR_2		0x0182
+#define	BT459_CUR_CLR_3		0x0183
+
+#define	BT459_CMD_REG_0		0x0201
+#define	BT459_CMD_REG_1		0x0202
+#define	BT459_CMD_REG_2		0x0203
+
+#define	BT459_READ_MASK		0x0204
+
+#define	BT459_BLINK_MASK	0x0206
+
+#define	BT459_CUR_CMD_REG	0x0300
+
+/*
  * The framebuffer driver private data.
  */
 
 struct tga_par {
-	/* PCI device.  */
-	struct pci_dev *pdev;
+	/* PCI/TC device.  */
+	struct device *dev;
 
 	/* Device dependent information.  */
 	void __iomem *tga_mem_base;
@@ -235,4 +259,21 @@ BT463_WRITE(struct tga_par *par, u32 m, 
 	TGA_WRITE_REG(par, m << 10 | v, TGA_RAMDAC_REG);
 }
 
+static inline void
+BT459_LOAD_ADDR(struct tga_par *par, u16 a)
+{
+	TGA_WRITE_REG(par, BT459_ADDR_LO << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, a & 0xff, TGA_RAMDAC_REG);
+	TGA_WRITE_REG(par, BT459_ADDR_HI << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, a >> 8, TGA_RAMDAC_REG);
+}
+
+static inline void
+BT459_WRITE(struct tga_par *par, u32 m, u16 a, u8 v)
+{
+	BT459_LOAD_ADDR(par, a);
+	TGA_WRITE_REG(par, m << 2, TGA_RAMDAC_SETUP_REG);
+	TGA_WRITE_REG(par, v, TGA_RAMDAC_REG);
+}
+
 #endif /* TGAFB_H */
diff --git a/init/Kconfig b/init/Kconfig
index b170aa1..d0edf42 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -80,16 +80,20 @@ config LOCALVERSION_AUTO
 	default y
 	help
 	  This will try to automatically determine if the current tree is a
-	  release tree by looking for git tags that
-	  belong to the current top of tree revision.
+	  release tree by looking for git tags that belong to the current
+	  top of tree revision.
 
 	  A string of the format -gxxxxxxxx will be added to the localversion
-	  if a git based tree is found.  The string generated by this will be
+	  if a git-based tree is found.  The string generated by this will be
 	  appended after any matching localversion* files, and after the value
-	  set in CONFIG_LOCALVERSION
+	  set in CONFIG_LOCALVERSION.
 
-	  Note: This requires Perl, and a git repository, but not necessarily
-	  the git or cogito tools to be installed.
+	  (The actual string used here is the first eight characters produced
+	  by running the command:
+
+	    $ git rev-parse --verify HEAD
+
+	  which is done within the script "scripts/setlocalversion".)
 
 config SWAP
 	bool "Support for paging of anonymous memory (swap)"
@@ -262,6 +266,23 @@ config IKCONFIG_PROC
 	  This option enables access to the kernel configuration file
 	  through /proc/config.gz.
 
+config LOG_BUF_SHIFT
+	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
+	range 12 21
+	default 17 if S390 || LOCKDEP
+	default 16 if X86_NUMAQ || IA64
+	default 15 if SMP
+	default 14
+	help
+	  Select kernel log buffer size as a power of 2.
+	  Defaults and Examples:
+	  	     17 => 128 KB for S/390
+		     16 => 64 KB for x86 NUMAQ or IA-64
+	             15 => 32 KB for SMP
+	             14 => 16 KB for uniprocessor
+		     13 =>  8 KB
+		     12 =>  4 KB
+
 config CPUSETS
 	bool "Cpuset support"
 	depends on SMP
@@ -352,7 +373,7 @@ menuconfig EMBEDDED
 
 config UID16
 	bool "Enable 16-bit UID system calls" if EMBEDDED
-	depends on ARM || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && SPARC32_COMPAT) || UML || (X86_64 && IA32_EMULATION)
+	depends on ARM || BFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && SPARC32_COMPAT) || UML || (X86_64 && IA32_EMULATION)
 	default y
 	help
 	  This enables the legacy 16-bit UID syscall wrappers.
@@ -474,15 +495,6 @@ config SHMEM
 	  option replaces shmem and tmpfs with the much simpler ramfs code,
 	  which may be appropriate on small systems without swap.
 
-config SLAB
-	default y
-	bool "Use full SLAB allocator" if (EMBEDDED && !SMP && !SPARSEMEM)
-	help
-	  Disabling this replaces the advanced SLAB allocator and
-	  kmalloc support with the drastically simpler SLOB allocator.
-	  SLOB is more space efficient but does not scale well and is
-	  more susceptible to fragmentation.
-
 config VM_EVENT_COUNTERS
 	default y
 	bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
@@ -492,6 +504,46 @@ config VM_EVENT_COUNTERS
 	  on EMBEDDED systems.  /proc/vmstat will only show page counts
 	  if VM event counters are disabled.
 
+choice
+	prompt "Choose SLAB allocator"
+	default SLAB
+	help
+	   This option allows to select a slab allocator.
+
+config SLAB
+	bool "SLAB"
+	help
+	  The regular slab allocator that is established and known to work
+	  well in all environments. It organizes chache hot objects in
+	  per cpu and per node queues. SLAB is the default choice for
+	  slab allocator.
+
+config SLUB
+	depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
+	bool "SLUB (Unqueued Allocator)"
+	help
+	   SLUB is a slab allocator that minimizes cache line usage
+	   instead of managing queues of cached objects (SLAB approach).
+	   Per cpu caching is realized using slabs of objects instead
+	   of queues of objects. SLUB can use memory efficiently
+	   way and has enhanced diagnostics.
+
+config SLOB
+#
+#	SLOB cannot support SMP because SLAB_DESTROY_BY_RCU does not work
+#	properly.
+#
+	depends on EMBEDDED && !SMP && !SPARSEMEM
+	bool "SLOB (Simple Allocator)"
+	help
+	   SLOB replaces the SLAB allocator with a drastically simpler
+	   allocator.  SLOB is more space efficient that SLAB but does not
+	   scale well (single lock for all operations) and is more susceptible
+	   to fragmentation. SLOB it is a great choice to reduce
+	   memory usage and code size for embedded systems.
+
+endchoice
+
 endmenu		# General setup
 
 config RT_MUTEXES
@@ -507,10 +559,6 @@ config BASE_SMALL
 	default 0 if BASE_FULL
 	default 1 if !BASE_FULL
 
-config SLOB
-	default !SLAB
-	bool
-
 menu "Loadable module support"
 
 config MODULES
diff --git a/init/do_mounts.c b/init/do_mounts.c
index dc1ec08..3f57ed4 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -9,6 +9,7 @@ #include <linux/security.h>
 #include <linux/delay.h>
 #include <linux/mount.h>
 #include <linux/device.h>
+#include <linux/init.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index 2cfd7cb..b222ce9 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -55,11 +55,12 @@ static void __init handle_initrd(void)
 	sys_mount(".", "/", NULL, MS_MOVE, NULL);
 	sys_chroot(".");
 
-	current->flags |= PF_NOFREEZE;
 	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 	if (pid > 0) {
-		while (pid != sys_wait4(-1, NULL, 0, NULL))
+		while (pid != sys_wait4(-1, NULL, 0, NULL)) {
+			try_to_freeze();
 			yield();
+		}
 	}
 
 	/* move initrd to rootfs' /old */
diff --git a/init/main.c b/init/main.c
index a92989e..c1537e0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -82,7 +82,7 @@ #if __GNUC__ == 4 && __GNUC_MINOR__ == 1
 #warning gcc-4.1.0 is known to miscompile the kernel.  A different compiler version is recommended.
 #endif
 
-static int init(void *);
+static int kernel_init(void *);
 
 extern void init_IRQ(void);
 extern void fork_init(unsigned long);
@@ -94,7 +94,6 @@ extern void pidmap_init(void);
 extern void prio_tree_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
-extern void prepare_namespace(void);
 #ifdef	CONFIG_ACPI
 extern void acpi_early_init(void);
 #else
@@ -369,12 +368,8 @@ static void __init setup_per_cpu_areas(v
 	unsigned long nr_possible_cpus = num_possible_cpus();
 
 	/* 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
-	ptr = alloc_bootmem(size * nr_possible_cpus);
+	size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+	ptr = alloc_bootmem_pages(size * nr_possible_cpus);
 
 	for_each_possible_cpu(i) {
 		__per_cpu_offset[i] = ptr - __per_cpu_start;
@@ -388,11 +383,6 @@ #endif /* !__GENERIC_PER_CPU */
 static void __init smp_init(void)
 {
 	unsigned int cpu;
-	unsigned highest = 0;
-
-	for_each_cpu_mask(cpu, cpu_possible_map)
-		highest = cpu;
-	nr_cpu_ids = highest + 1;
 
 	/* FIXME: This should be done in userspace --RR */
 	for_each_present_cpu(cpu) {
@@ -435,7 +425,7 @@ static void __init setup_command_line(ch
 static void noinline rest_init(void)
 	__releases(kernel_lock)
 {
-	kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
+	kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
 	numa_default_policy();
 	unlock_kernel();
 
@@ -658,6 +648,7 @@ static void __init do_initcalls(void)
 	int count = preempt_count();
 
 	for (call = __initcall_start; call < __initcall_end; call++) {
+		ktime_t t0, t1, delta;
 		char *msg = NULL;
 		char msgbuf[40];
 		int result;
@@ -667,10 +658,26 @@ static void __init do_initcalls(void)
 			print_fn_descriptor_symbol(": %s()",
 					(unsigned long) *call);
 			printk("\n");
+			t0 = ktime_get();
 		}
 
 		result = (*call)();
 
+		if (initcall_debug) {
+			t1 = ktime_get();
+			delta = ktime_sub(t1, t0);
+
+			printk("initcall 0x%p", *call);
+			print_fn_descriptor_symbol(": %s()",
+					(unsigned long) *call);
+			printk(" returned %d.\n", result);
+
+			printk("initcall 0x%p ran for %Ld msecs: ",
+				*call, (unsigned long long)delta.tv64 >> 20);
+			print_fn_descriptor_symbol("%s()\n",
+				(unsigned long) *call);
+		}
+
 		if (result && result != -ENODEV && initcall_debug) {
 			sprintf(msgbuf, "error code %d", result);
 			msg = msgbuf;
@@ -772,7 +779,7 @@ static int noinline init_post(void)
 	panic("No init found.  Try passing init= option to kernel.");
 }
 
-static int __init init(void * unused)
+static int __init kernel_init(void * unused)
 {
 	lock_kernel();
 	/*
diff --git a/ipc/compat.c b/ipc/compat.c
index fa18141..8b44aa9 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -542,6 +542,8 @@ static inline int put_compat_shminfo64(s
 
 	if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
 		return -EFAULT;
+	if (smi->shmmax > INT_MAX)
+		smi->shmmax = INT_MAX;
 	err  = __put_user(smi->shmmax, &up64->shmmax);
 	err |= __put_user(smi->shmmin, &up64->shmmin);
 	err |= __put_user(smi->shmmni, &up64->shmmni);
@@ -557,6 +559,8 @@ static inline int put_compat_shminfo(str
 
 	if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
 		return -EFAULT;
+	if (smi->shmmax > INT_MAX)
+		smi->shmmax = INT_MAX;
 	err  = __put_user(smi->shmmax, &up->shmmax);
 	err |= __put_user(smi->shmmin, &up->shmmin);
 	err |= __put_user(smi->shmmni, &up->shmmni);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 554ac36..d17821d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -215,8 +215,7 @@ static void init_once(void *foo, struct 
 {
 	struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-		SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&p->vfs_inode);
 }
 
diff --git a/ipc/sem.c b/ipc/sem.c
index d3e12ef..9964b22 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -75,7 +75,6 @@ #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/audit.h>
diff --git a/ipc/util.c b/ipc/util.c
index 0b65238..7536a72 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -21,7 +21,6 @@ #include <linux/mm.h>
 #include <linux/shm.h>
 #include <linux/init.h>
 #include <linux/msg.h>
-#include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/capability.h>
@@ -85,53 +84,20 @@ err_mem:
 	return ERR_PTR(err);
 }
 
-int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
+struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
 {
-	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);
+	BUG_ON(!ns);
+	get_ipc_ns(ns);
 
 	if (!(flags & CLONE_NEWIPC))
-		return 0;
+		return ns;
 
-	if (!capable(CAP_SYS_ADMIN)) {
-		err = -EPERM;
-		goto out;
-	}
+	new_ns = clone_ipc_ns(ns);
 
-	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;
+	put_ipc_ns(ns);
+	return new_ns;
 }
 
 void free_ipc_ns(struct kref *kref)
@@ -145,11 +111,11 @@ void free_ipc_ns(struct kref *kref)
 	kfree(ns);
 }
 #else
-int copy_ipcs(unsigned long flags, struct task_struct *tsk)
+struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
 {
 	if (flags & CLONE_NEWIPC)
-		return -EINVAL;
-	return 0;
+		return ERR_PTR(-EINVAL);
+	return ns;
 }
 #endif
 
diff --git a/kernel/Makefile b/kernel/Makefile
index ac6b27a..642d427 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 latency.o nsproxy.o srcu.o
+	    hrtimer.o rwsem.o latency.o nsproxy.o srcu.o die_notifier.o
 
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
diff --git a/kernel/audit.c b/kernel/audit.c
index 76c9a11..d13276d 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -151,7 +151,7 @@ struct audit_buffer {
 
 static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
 {
-	struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
+	struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
 	nlh->nlmsg_pid = pid;
 }
 
@@ -515,8 +515,8 @@ static int audit_netlink_ok(struct sk_bu
 			err = -EPERM;
 		break;
 	case AUDIT_USER:
-	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
-	case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
+	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
+	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
 		if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
 			err = -EPERM;
 		break;
@@ -614,8 +614,8 @@ static int audit_receive_msg(struct sk_b
 							loginuid, sid);
 		break;
 	case AUDIT_USER:
-	case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
-	case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
+	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
+	case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
 		if (!audit_enabled && msg_type != AUDIT_USER_AVC)
 			return 0;
 
@@ -750,7 +750,7 @@ static void audit_receive_skb(struct sk_
 	u32		rlen;
 
 	while (skb->len >= NLMSG_SPACE(0)) {
-		nlh = (struct nlmsghdr *)skb->data;
+		nlh = nlmsg_hdr(skb);
 		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
 			return;
 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
@@ -795,7 +795,7 @@ static int __init audit_init(void)
 	printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
 	       audit_default ? "enabled" : "disabled");
 	audit_sock = netlink_kernel_create(NETLINK_AUDIT, 0, audit_receive,
-					   THIS_MODULE);
+					   NULL, THIS_MODULE);
 	if (!audit_sock)
 		audit_panic("cannot initialize netlink socket");
 	else
@@ -1073,7 +1073,7 @@ static void audit_log_vformat(struct aud
 			goto out;
 	}
 	va_copy(args2, args);
-	len = vsnprintf(skb->tail, avail, fmt, args);
+	len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args);
 	if (len >= avail) {
 		/* The printk buffer is 1024 bytes long, so if we get
 		 * here and AUDIT_BUFSIZ is at least 1024, then we can
@@ -1082,7 +1082,7 @@ static void audit_log_vformat(struct aud
 			max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
 		if (!avail)
 			goto out;
-		len = vsnprintf(skb->tail, avail, fmt, args2);
+		len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
 	}
 	if (len > 0)
 		skb_put(skb, len);
@@ -1143,7 +1143,7 @@ void audit_log_hex(struct audit_buffer *
 			return;
 	}
 
-	ptr = skb->tail;
+	ptr = skb_tail_pointer(skb);
 	for (i=0; i<len; i++) {
 		*ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
 		*ptr++ = hex[buf[i] & 0x0F];	  /* Lower nibble */
@@ -1175,7 +1175,7 @@ static void audit_log_n_string(struct au
 		if (!avail)
 			return;
 	}
-	ptr = skb->tail;
+	ptr = skb_tail_pointer(skb);
 	*ptr++ = '"';
 	memcpy(ptr, string, slen);
 	ptr += slen;
@@ -1268,7 +1268,7 @@ void audit_log_end(struct audit_buffer *
 		audit_log_lost("rate limit exceeded");
 	} else {
 		if (audit_pid) {
-			struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->data;
+			struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
 			nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);
 			skb_queue_tail(&audit_skb_queue, ab->skb);
 			ab->skb = NULL;
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index f382b0f..88b416d 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -42,7 +42,6 @@ #include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/security.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/stat.h>
 #include <linux/string.h>
@@ -822,11 +821,22 @@ static int update_cpumask(struct cpuset 
 		return -EACCES;
 
 	trialcs = *cs;
-	retval = cpulist_parse(buf, trialcs.cpus_allowed);
-	if (retval < 0)
-		return retval;
+
+	/*
+	 * We allow a cpuset's cpus_allowed to be empty; if it has attached
+	 * tasks, we'll catch it later when we validate the change and return
+	 * -ENOSPC.
+	 */
+	if (!buf[0] || (buf[0] == '\n' && !buf[1])) {
+		cpus_clear(trialcs.cpus_allowed);
+	} else {
+		retval = cpulist_parse(buf, trialcs.cpus_allowed);
+		if (retval < 0)
+			return retval;
+	}
 	cpus_and(trialcs.cpus_allowed, trialcs.cpus_allowed, cpu_online_map);
-	if (cpus_empty(trialcs.cpus_allowed))
+	/* cpus_allowed cannot be empty for a cpuset with attached tasks. */
+	if (atomic_read(&cs->count) && cpus_empty(trialcs.cpus_allowed))
 		return -ENOSPC;
 	retval = validate_change(cs, &trialcs);
 	if (retval < 0)
@@ -919,16 +929,27 @@ static int update_nodemask(struct cpuset
 		return -EACCES;
 
 	trialcs = *cs;
-	retval = nodelist_parse(buf, trialcs.mems_allowed);
-	if (retval < 0)
-		goto done;
+
+	/*
+	 * We allow a cpuset's mems_allowed to be empty; if it has attached
+	 * tasks, we'll catch it later when we validate the change and return
+	 * -ENOSPC.
+	 */
+	if (!buf[0] || (buf[0] == '\n' && !buf[1])) {
+		nodes_clear(trialcs.mems_allowed);
+	} else {
+		retval = nodelist_parse(buf, trialcs.mems_allowed);
+		if (retval < 0)
+			goto done;
+	}
 	nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map);
 	oldmem = cs->mems_allowed;
 	if (nodes_equal(oldmem, trialcs.mems_allowed)) {
 		retval = 0;		/* Too easy - nothing to do */
 		goto done;
 	}
-	if (nodes_empty(trialcs.mems_allowed)) {
+	/* mems_allowed cannot be empty for a cpuset with attached tasks. */
+	if (atomic_read(&cs->count) && nodes_empty(trialcs.mems_allowed)) {
 		retval = -ENOSPC;
 		goto done;
 	}
@@ -2200,10 +2221,6 @@ void cpuset_fork(struct task_struct *chi
  * it is holding that mutex while calling check_for_release(),
  * which calls kmalloc(), so can't be called holding callback_mutex().
  *
- * We don't need to task_lock() this reference to tsk->cpuset,
- * because tsk is already marked PF_EXITING, so attach_task() won't
- * mess with it, or task is a failed fork, never visible to attach_task.
- *
  * the_top_cpuset_hack:
  *
  *    Set the exiting tasks cpuset to the root cpuset (top_cpuset).
@@ -2242,8 +2259,10 @@ void cpuset_exit(struct task_struct *tsk
 {
 	struct cpuset *cs;
 
+	task_lock(current);
 	cs = tsk->cpuset;
 	tsk->cpuset = &top_cpuset;	/* the_top_cpuset_hack - see above */
+	task_unlock(current);
 
 	if (notify_on_release(cs)) {
 		char *pathbuf = NULL;
@@ -2351,6 +2370,8 @@ static const struct cpuset *nearest_excl
  * z's node is in our tasks mems_allowed, yes.  If it's not a
  * __GFP_HARDWALL request and this zone's nodes is in the nearest
  * mem_exclusive cpuset ancestor to this tasks cpuset, yes.
+ * If the task has been OOM killed and has access to memory reserves
+ * as specified by the TIF_MEMDIE flag, yes.
  * Otherwise, no.
  *
  * If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
@@ -2368,7 +2389,8 @@ static const struct cpuset *nearest_excl
  * calls get to this routine, we should just shut up and say 'yes'.
  *
  * GFP_USER allocations are marked with the __GFP_HARDWALL bit,
- * and do not allow allocations outside the current tasks cpuset.
+ * and do not allow allocations outside the current tasks cpuset
+ * unless the task has been OOM killed as is marked TIF_MEMDIE.
  * GFP_KERNEL allocations are not so marked, so can escape to the
  * nearest enclosing mem_exclusive ancestor cpuset.
  *
@@ -2392,6 +2414,7 @@ static const struct cpuset *nearest_excl
  * affect that:
  *	in_interrupt - any node ok (current task context irrelevant)
  *	GFP_ATOMIC   - any node ok
+ *	TIF_MEMDIE   - any node ok
  *	GFP_KERNEL   - any node in enclosing mem_exclusive cpuset ok
  *	GFP_USER     - only nodes in current tasks mems allowed ok.
  *
@@ -2413,6 +2436,12 @@ int __cpuset_zone_allowed_softwall(struc
 	might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
 	if (node_isset(node, current->mems_allowed))
 		return 1;
+	/*
+	 * Allow tasks that have access to memory reserves because they have
+	 * been OOM killed to get memory anywhere.
+	 */
+	if (unlikely(test_thread_flag(TIF_MEMDIE)))
+		return 1;
 	if (gfp_mask & __GFP_HARDWALL)	/* If hardwall request, stop here */
 		return 0;
 
@@ -2438,7 +2467,9 @@ int __cpuset_zone_allowed_softwall(struc
  *
  * If we're in interrupt, yes, we can always allocate.
  * If __GFP_THISNODE is set, yes, we can always allocate.  If zone
- * z's node is in our tasks mems_allowed, yes.   Otherwise, no.
+ * z's node is in our tasks mems_allowed, yes.   If the task has been
+ * OOM killed and has access to memory reserves as specified by the
+ * TIF_MEMDIE flag, yes.  Otherwise, no.
  *
  * The __GFP_THISNODE placement logic is really handled elsewhere,
  * by forcibly using a zonelist starting at a specified node, and by
@@ -2462,6 +2493,12 @@ int __cpuset_zone_allowed_hardwall(struc
 	node = zone_to_nid(z);
 	if (node_isset(node, current->mems_allowed))
 		return 1;
+        /*
+         * Allow tasks that have access to memory reserves because they have
+         * been OOM killed to get memory anywhere.
+         */
+        if (unlikely(test_thread_flag(TIF_MEMDIE)))
+                return 1;
 	return 0;
 }
 
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index 766d591..c0148ae 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -31,11 +31,7 @@ __setup("nodelayacct", delayacct_setup_d
 
 void delayacct_init(void)
 {
-	delayacct_cache = kmem_cache_create("delayacct_cache",
-					sizeof(struct task_delay_info),
-					0,
-					SLAB_PANIC,
-					NULL, NULL);
+	delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC);
 	delayacct_tsk_init(&init_task);
 }
 
diff --git a/kernel/die_notifier.c b/kernel/die_notifier.c
new file mode 100644
index 0000000..0d98827
--- /dev/null
+++ b/kernel/die_notifier.c
@@ -0,0 +1,38 @@
+
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/vmalloc.h>
+#include <linux/kdebug.h>
+
+
+static ATOMIC_NOTIFIER_HEAD(die_chain);
+
+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(&die_chain, val, &args);
+}
+
+int register_die_notifier(struct notifier_block *nb)
+{
+	vmalloc_sync_all();
+	return atomic_notifier_chain_register(&die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_die_notifier);
+
+
diff --git a/kernel/exit.c b/kernel/exit.c
index b55ed4c..f5a7abb 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -7,7 +7,6 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/capability.h>
 #include <linux/completion.h>
@@ -1033,6 +1032,8 @@ asmlinkage void sys_exit_group(int error
 
 static int eligible_child(pid_t pid, int options, struct task_struct *p)
 {
+	int err;
+
 	if (pid > 0) {
 		if (p->pid != pid)
 			return 0;
@@ -1066,8 +1067,9 @@ static int eligible_child(pid_t pid, int
 	if (delay_group_leader(p))
 		return 2;
 
-	if (security_task_wait(p))
-		return 0;
+	err = security_task_wait(p);
+	if (err)
+		return err;
 
 	return 1;
 }
@@ -1449,6 +1451,7 @@ static long do_wait(pid_t pid, int optio
 	DECLARE_WAITQUEUE(wait, current);
 	struct task_struct *tsk;
 	int flag, retval;
+	int allowed, denied;
 
 	add_wait_queue(&current->signal->wait_chldexit,&wait);
 repeat:
@@ -1457,6 +1460,7 @@ repeat:
 	 * match our criteria, even if we are not able to reap it yet.
 	 */
 	flag = 0;
+	allowed = denied = 0;
 	current->state = TASK_INTERRUPTIBLE;
 	read_lock(&tasklist_lock);
 	tsk = current;
@@ -1472,6 +1476,12 @@ repeat:
 			if (!ret)
 				continue;
 
+			if (unlikely(ret < 0)) {
+				denied = ret;
+				continue;
+			}
+			allowed = 1;
+
 			switch (p->state) {
 			case TASK_TRACED:
 				/*
@@ -1570,6 +1580,8 @@ check_continued:
 		goto repeat;
 	}
 	retval = -ECHILD;
+	if (unlikely(denied) && !allowed)
+		retval = denied;
 end:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&current->signal->wait_chldexit,&wait);
diff --git a/kernel/fork.c b/kernel/fork.c
index 6af959c..a8dd75d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -14,7 +14,6 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/unistd.h>
-#include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/completion.h>
@@ -286,6 +285,8 @@ static inline int dup_mmap(struct mm_str
 		if (retval)
 			goto out;
 	}
+	/* a new mm has just been created */
+	arch_dup_mmap(oldmm, mm);
 	retval = 0;
 out:
 	up_write(&mm->mmap_sem);
@@ -1423,8 +1424,7 @@ static void sighand_ctor(void *data, str
 {
 	struct sighand_struct *sighand = data;
 
-	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
-					SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		spin_lock_init(&sighand->siglock);
 }
 
@@ -1515,26 +1515,6 @@ static int unshare_fs(unsigned long unsh
 }
 
 /*
- * Unshare the mnt_namespace structure if it is being shared
- */
-static int unshare_mnt_namespace(unsigned long unshare_flags,
-		struct mnt_namespace **new_nsp, struct fs_struct *new_fs)
-{
-	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
-
-	if ((unshare_flags & CLONE_NEWNS) && ns) {
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-
-		*new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs);
-		if (!*new_nsp)
-			return -ENOMEM;
-	}
-
-	return 0;
-}
-
-/*
  * Unsharing of sighand is not supported yet
  */
 static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
@@ -1592,16 +1572,6 @@ 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_*
@@ -1614,14 +1584,11 @@ asmlinkage long sys_unshare(unsigned lon
 {
 	int err = 0;
 	struct fs_struct *fs, *new_fs = NULL;
-	struct mnt_namespace *ns, *new_ns = NULL;
 	struct sighand_struct *new_sigh = NULL;
 	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);
 
@@ -1636,36 +1603,24 @@ asmlinkage long sys_unshare(unsigned lon
 		goto bad_unshare_out;
 	if ((err = unshare_fs(unshare_flags, &new_fs)))
 		goto bad_unshare_cleanup_thread;
-	if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs)))
-		goto bad_unshare_cleanup_fs;
 	if ((err = unshare_sighand(unshare_flags, &new_sigh)))
-		goto bad_unshare_cleanup_ns;
+		goto bad_unshare_cleanup_fs;
 	if ((err = unshare_vm(unshare_flags, &new_mm)))
 		goto bad_unshare_cleanup_sigh;
 	if ((err = unshare_fd(unshare_flags, &new_fd)))
 		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)))
+	if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
+			new_fs)))
 		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_mm || new_fd || new_ulist ||
-				new_uts || new_ipc) {
+	if (new_fs ||  new_mm || new_fd || new_ulist || new_nsproxy) {
 
 		task_lock(current);
 
 		if (new_nsproxy) {
+			old_nsproxy = current->nsproxy;
 			current->nsproxy = new_nsproxy;
 			new_nsproxy = old_nsproxy;
 		}
@@ -1676,12 +1631,6 @@ asmlinkage long sys_unshare(unsigned lon
 			new_fs = fs;
 		}
 
-		if (new_ns) {
-			ns = current->nsproxy->mnt_ns;
-			current->nsproxy->mnt_ns = new_ns;
-			new_ns = ns;
-		}
-
 		if (new_mm) {
 			mm = current->mm;
 			active_mm = current->active_mm;
@@ -1697,32 +1646,12 @@ 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)
@@ -1737,10 +1666,6 @@ bad_unshare_cleanup_sigh:
 		if (atomic_dec_and_test(&new_sigh->count))
 			kmem_cache_free(sighand_cachep, new_sigh);
 
-bad_unshare_cleanup_ns:
-	if (new_ns)
-		put_mnt_ns(new_ns);
-
 bad_unshare_cleanup_fs:
 	if (new_fs)
 		put_fs_struct(new_fs);
diff --git a/kernel/futex.c b/kernel/futex.c
index 5a270b5..600bc9d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -48,6 +48,7 @@ #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/syscalls.h>
 #include <linux/signal.h>
+#include <linux/module.h>
 #include <asm/futex.h>
 
 #include "rtmutex_common.h"
@@ -55,32 +56,6 @@ #include "rtmutex_common.h"
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
- * Futexes are matched on equal values of this key.
- * The key type depends on whether it's a shared or private mapping.
- * Don't rearrange members without looking at hash_futex().
- *
- * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
- * We set bit 0 to indicate if it's an inode-based key.
- */
-union futex_key {
-	struct {
-		unsigned long pgoff;
-		struct inode *inode;
-		int offset;
-	} shared;
-	struct {
-		unsigned long address;
-		struct mm_struct *mm;
-		int offset;
-	} private;
-	struct {
-		unsigned long word;
-		void *ptr;
-		int offset;
-	} both;
-};
-
-/*
  * Priority Inheritance state:
  */
 struct futex_pi_state {
@@ -175,7 +150,7 @@ static inline int match_futex(union fute
  *
  * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
  */
-static int get_futex_key(u32 __user *uaddr, union futex_key *key)
+int get_futex_key(u32 __user *uaddr, union futex_key *key)
 {
 	unsigned long address = (unsigned long)uaddr;
 	struct mm_struct *mm = current->mm;
@@ -246,6 +221,7 @@ static int get_futex_key(u32 __user *uad
 	}
 	return err;
 }
+EXPORT_SYMBOL_GPL(get_futex_key);
 
 /*
  * Take a reference to the resource addressed by a key.
@@ -254,7 +230,7 @@ static int get_futex_key(u32 __user *uad
  * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
  * function, if it is called at all.  mmap_sem keeps key->shared.inode valid.
  */
-static inline void get_key_refs(union futex_key *key)
+inline void get_futex_key_refs(union futex_key *key)
 {
 	if (key->both.ptr != 0) {
 		if (key->both.offset & 1)
@@ -263,12 +239,13 @@ static inline void get_key_refs(union fu
 			atomic_inc(&key->private.mm->mm_count);
 	}
 }
+EXPORT_SYMBOL_GPL(get_futex_key_refs);
 
 /*
  * Drop a reference to the resource addressed by a key.
  * The hash bucket spinlock must not be held.
  */
-static void drop_key_refs(union futex_key *key)
+void drop_futex_key_refs(union futex_key *key)
 {
 	if (key->both.ptr != 0) {
 		if (key->both.offset & 1)
@@ -277,6 +254,7 @@ static void drop_key_refs(union futex_ke
 			mmdrop(key->private.mm);
 	}
 }
+EXPORT_SYMBOL_GPL(drop_futex_key_refs);
 
 static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
 {
@@ -873,7 +851,7 @@ static int futex_requeue(u32 __user *uad
 				this->lock_ptr = &hb2->lock;
 			}
 			this->key = key2;
-			get_key_refs(&key2);
+			get_futex_key_refs(&key2);
 			drop_count++;
 
 			if (ret - nr_wake >= nr_requeue)
@@ -886,9 +864,9 @@ out_unlock:
 	if (hb1 != hb2)
 		spin_unlock(&hb2->lock);
 
-	/* drop_key_refs() must be called outside the spinlocks. */
+	/* drop_futex_key_refs() must be called outside the spinlocks. */
 	while (--drop_count >= 0)
-		drop_key_refs(&key1);
+		drop_futex_key_refs(&key1);
 
 out:
 	up_read(&current->mm->mmap_sem);
@@ -906,7 +884,7 @@ queue_lock(struct futex_q *q, int fd, st
 
 	init_waitqueue_head(&q->waiters);
 
-	get_key_refs(&q->key);
+	get_futex_key_refs(&q->key);
 	hb = hash_futex(&q->key);
 	q->lock_ptr = &hb->lock;
 
@@ -925,7 +903,7 @@ static inline void
 queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
 {
 	spin_unlock(&hb->lock);
-	drop_key_refs(&q->key);
+	drop_futex_key_refs(&q->key);
 }
 
 /*
@@ -980,7 +958,7 @@ static int unqueue_me(struct futex_q *q)
 		ret = 1;
 	}
 
-	drop_key_refs(&q->key);
+	drop_futex_key_refs(&q->key);
 	return ret;
 }
 
@@ -999,15 +977,18 @@ static void unqueue_me_pi(struct futex_q
 
 	spin_unlock(&hb->lock);
 
-	drop_key_refs(&q->key);
+	drop_futex_key_refs(&q->key);
 }
 
-static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
+static long futex_wait_restart(struct restart_block *restart);
+static int futex_wait_abstime(u32 __user *uaddr, u32 val,
+			int timed, unsigned long abs_time)
 {
 	struct task_struct *curr = current;
 	DECLARE_WAITQUEUE(wait, curr);
 	struct futex_hash_bucket *hb;
 	struct futex_q q;
+	unsigned long time_left = 0;
 	u32 uval;
 	int ret;
 
@@ -1087,8 +1068,21 @@ static int futex_wait(u32 __user *uaddr,
 	 * !list_empty() is safe here without any lock.
 	 * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
 	 */
-	if (likely(!list_empty(&q.list)))
-		time = schedule_timeout(time);
+	time_left = 0;
+	if (likely(!list_empty(&q.list))) {
+		unsigned long rel_time;
+
+		if (timed) {
+			unsigned long now = jiffies;
+			if (time_after(now, abs_time))
+				rel_time = 0;
+			else
+				rel_time = abs_time - now;
+		} else
+			rel_time = MAX_SCHEDULE_TIMEOUT;
+
+		time_left = schedule_timeout(rel_time);
+	}
 	__set_current_state(TASK_RUNNING);
 
 	/*
@@ -1099,13 +1093,25 @@ static int futex_wait(u32 __user *uaddr,
 	/* If we were woken (and unqueued), we succeeded, whatever. */
 	if (!unqueue_me(&q))
 		return 0;
-	if (time == 0)
+	if (time_left == 0)
 		return -ETIMEDOUT;
+
 	/*
 	 * We expect signal_pending(current), but another thread may
 	 * have handled it for us already.
 	 */
-	return -EINTR;
+	if (time_left == MAX_SCHEDULE_TIMEOUT)
+		return -ERESTARTSYS;
+	else {
+		struct restart_block *restart;
+		restart = &current_thread_info()->restart_block;
+		restart->fn = futex_wait_restart;
+		restart->arg0 = (unsigned long)uaddr;
+		restart->arg1 = (unsigned long)val;
+		restart->arg2 = (unsigned long)timed;
+		restart->arg3 = abs_time;
+		return -ERESTART_RESTARTBLOCK;
+	}
 
  out_unlock_release_sem:
 	queue_unlock(&q, hb);
@@ -1115,6 +1121,24 @@ static int futex_wait(u32 __user *uaddr,
 	return ret;
 }
 
+static int futex_wait(u32 __user *uaddr, u32 val, unsigned long rel_time)
+{
+	int timed = (rel_time != MAX_SCHEDULE_TIMEOUT);
+	return futex_wait_abstime(uaddr, val, timed, jiffies+rel_time);
+}
+
+static long futex_wait_restart(struct restart_block *restart)
+{
+	u32 __user *uaddr = (u32 __user *)restart->arg0;
+	u32 val = (u32)restart->arg1;
+	int timed = (int)restart->arg2;
+	unsigned long abs_time = restart->arg3;
+
+	restart->fn = do_no_restart_syscall;
+	return (long)futex_wait_abstime(uaddr, val, timed, abs_time);
+}
+
+
 /*
  * Userspace tried a 0 -> TID atomic transition of the futex value
  * and failed. The kernel side here does the whole locking operation:
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index b74860a..c9f4f04 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -59,6 +59,7 @@ ktime_t ktime_get(void)
 
 	return timespec_to_ktime(now);
 }
+EXPORT_SYMBOL_GPL(ktime_get);
 
 /**
  * ktime_get_real - get the real (wall-) time in ktime_t format
@@ -278,6 +279,8 @@ ktime_t ktime_add_ns(const ktime_t kt, u
 
 	return ktime_add(kt, tmp);
 }
+
+EXPORT_SYMBOL_GPL(ktime_add_ns);
 # endif /* !CONFIG_KTIME_SCALAR */
 
 /*
@@ -666,6 +669,7 @@ hrtimer_forward(struct hrtimer *timer, k
 
 	return orun;
 }
+EXPORT_SYMBOL_GPL(hrtimer_forward);
 
 /*
  * enqueue_hrtimer - internal function to (re)start a timer
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 0133f4f..615ce97 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/irq.h>
+#include <linux/msi.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
@@ -185,6 +186,8 @@ int set_irq_msi(unsigned int irq, struct
 	desc = irq_desc + irq;
 	spin_lock_irqsave(&desc->lock, flags);
 	desc->msi_desc = entry;
+	if (entry)
+		entry->irq = irq;
 	spin_unlock_irqrestore(&desc->lock, flags);
 	return 0;
 }
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index aff1f0f..32e1ab1 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -48,7 +48,7 @@ handle_bad_irq(unsigned int irq, struct 
  *
  * Controller mappings for all interrupt sources:
  */
-struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
+struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
 	[0 ... NR_IRQS-1] = {
 		.status = IRQ_DISABLED,
 		.chip = &no_irq_chip,
@@ -180,6 +180,8 @@ fastcall unsigned int __do_IRQ(unsigned 
 		if (desc->chip->ack)
 			desc->chip->ack(irq);
 		action_ret = handle_IRQ_event(irq, desc->action);
+		if (!noirqdebug)
+			note_interrupt(irq, desc, action_ret);
 		desc->chip->end(irq);
 		return 1;
 	}
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 5597c15..203a518 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -317,10 +317,7 @@ #endif
 	}
 
 	*p = new;
-#if defined(CONFIG_IRQ_PER_CPU)
-	if (new->flags & IRQF_PERCPU)
-		desc->status |= IRQ_PER_CPU;
-#endif
+
 	/* Exclude IRQ from balancing */
 	if (new->flags & IRQF_NOBALANCING)
 		desc->status |= IRQ_NO_BALANCING;
@@ -328,6 +325,11 @@ #endif
 	if (!shared) {
 		irq_chip_set_defaults(desc->chip);
 
+#if defined(CONFIG_IRQ_PER_CPU)
+		if (new->flags & IRQF_PERCPU)
+			desc->status |= IRQ_PER_CPU;
+#endif
+
 		/* Setup the type (level, edge polarity) if configured: */
 		if (new->flags & IRQF_TRIGGER_MASK) {
 			if (desc->chip && desc->chip->set_type)
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 2db91eb..ddde0ef 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -66,12 +66,19 @@ static int name_unique(unsigned int irq,
 {
 	struct irq_desc *desc = irq_desc + irq;
 	struct irqaction *action;
+	unsigned long flags;
+	int ret = 1;
 
-	for (action = desc->action ; action; action = action->next)
+	spin_lock_irqsave(&desc->lock, flags);
+	for (action = desc->action ; action; action = action->next) {
 		if ((action != new_action) && action->name &&
-				!strcmp(new_action->name, action->name))
-			return 0;
-	return 1;
+				!strcmp(new_action->name, action->name)) {
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+	return ret;
 }
 
 void register_handler_proc(unsigned int irq, struct irqaction *action)
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 9d8c79b..b0d81aa 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -146,7 +146,9 @@ void note_interrupt(unsigned int irq, st
 
 	if (unlikely(irqfixup)) {
 		/* Don't punish working computers */
-		if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
+		if ((irqfixup == 2 && ((irq == 0) ||
+				(desc->action->flags & IRQF_IRQPOLL))) ||
+				action_ret == IRQ_NONE) {
 			int ok = misrouted_irq(irq);
 			if (action_ret == IRQ_NONE)
 				desc->irqs_unhandled -= ok;
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 307c6a6..3205e8e 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -7,7 +7,6 @@
 /* These are all the functions necessary to implement itimers */
 
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/syscalls.h>
 #include <linux/time.h>
@@ -139,59 +138,11 @@ enum hrtimer_restart it_real_fn(struct h
 }
 
 /*
- * We do not care about correctness. We just sanitize the values so
- * the ktime_t operations which expect normalized values do not
- * break. This converts negative values to long timeouts similar to
- * the code in kernel versions < 2.6.16
- *
- * Print a limited number of warning messages when an invalid timeval
- * is detected.
- */
-static void fixup_timeval(struct timeval *tv, int interval)
-{
-	static int warnlimit = 10;
-	unsigned long tmp;
-
-	if (warnlimit > 0) {
-		warnlimit--;
-		printk(KERN_WARNING
-		       "setitimer: %s (pid = %d) provided "
-		       "invalid timeval %s: tv_sec = %ld tv_usec = %ld\n",
-		       current->comm, current->pid,
-		       interval ? "it_interval" : "it_value",
-		       tv->tv_sec, (long) tv->tv_usec);
-	}
-
-	tmp = tv->tv_usec;
-	if (tmp >= USEC_PER_SEC) {
-		tv->tv_usec = tmp % USEC_PER_SEC;
-		tv->tv_sec += tmp / USEC_PER_SEC;
-	}
-
-	tmp = tv->tv_sec;
-	if (tmp > LONG_MAX)
-		tv->tv_sec = LONG_MAX;
-}
-
-/*
  * Returns true if the timeval is in canonical form
  */
 #define timeval_valid(t) \
 	(((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
 
-/*
- * Check for invalid timevals, sanitize them and print a limited
- * number of warnings.
- */
-static void check_itimerval(struct itimerval *value) {
-
-	if (unlikely(!timeval_valid(&value->it_value)))
-		fixup_timeval(&value->it_value, 0);
-
-	if (unlikely(!timeval_valid(&value->it_interval)))
-		fixup_timeval(&value->it_interval, 1);
-}
-
 int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
 {
 	struct task_struct *tsk = current;
@@ -201,15 +152,10 @@ int do_setitimer(int which, struct itime
 
 	/*
 	 * Validate the timevals in value.
-	 *
-	 * Note: Although the spec requires that invalid values shall
-	 * return -EINVAL, we just fixup the value and print a limited
-	 * number of warnings in order not to break users of this
-	 * historical misfeature.
-	 *
-	 * Scheduled for replacement in March 2007
 	 */
-	check_itimerval(value);
+	if (!timeval_valid(&value->it_value) ||
+	    !timeval_valid(&value->it_interval))
+		return -EINVAL;
 
 	switch (which) {
 	case ITIMER_REAL:
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 6f294ff..f1bda23 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -214,8 +214,10 @@ static unsigned long get_symbol_pos(unsi
 			symbol_end = (unsigned long)_etext;
 	}
 
-	*symbolsize = symbol_end - symbol_start;
-	*offset = addr - symbol_start;
+	if (symbolsize)
+		*symbolsize = symbol_end - symbol_start;
+	if (offset)
+		*offset = addr - symbol_start;
 
 	return low;
 }
@@ -267,27 +269,69 @@ const char *kallsyms_lookup(unsigned lon
 	return NULL;
 }
 
-/* Replace "%s" in format with address, or returns -errno. */
-void __print_symbol(const char *fmt, unsigned long address)
+int lookup_symbol_name(unsigned long addr, char *symname)
+{
+	symname[0] = '\0';
+	symname[KSYM_NAME_LEN] = '\0';
+
+	if (is_ksym_addr(addr)) {
+		unsigned long pos;
+
+		pos = get_symbol_pos(addr, NULL, NULL);
+		/* Grab name */
+		kallsyms_expand_symbol(get_symbol_offset(pos), symname);
+		return 0;
+	}
+	/* see if it's in a module */
+	return lookup_module_symbol_name(addr, symname);
+}
+
+int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
+			unsigned long *offset, char *modname, char *name)
+{
+	name[0] = '\0';
+	name[KSYM_NAME_LEN] = '\0';
+
+	if (is_ksym_addr(addr)) {
+		unsigned long pos;
+
+		pos = get_symbol_pos(addr, size, offset);
+		/* Grab name */
+		kallsyms_expand_symbol(get_symbol_offset(pos), name);
+		modname[0] = '\0';
+		return 0;
+	}
+	/* see if it's in a module */
+	return lookup_module_symbol_attrs(addr, size, offset, modname, name);
+}
+
+/* Look up a kernel symbol and return it in a text buffer. */
+int sprint_symbol(char *buffer, unsigned long address)
 {
 	char *modname;
 	const char *name;
 	unsigned long offset, size;
 	char namebuf[KSYM_NAME_LEN+1];
-	char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +
-		    2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1];
 
 	name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
-
 	if (!name)
-		sprintf(buffer, "0x%lx", address);
+		return sprintf(buffer, "0x%lx", address);
 	else {
 		if (modname)
-			sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
+			return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
 				size, modname);
 		else
-			sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+			return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
 	}
+}
+
+/* Look up a kernel symbol and print it to the kernel messages. */
+void __print_symbol(const char *fmt, unsigned long address)
+{
+	char buffer[KSYM_SYMBOL_LEN];
+
+	sprint_symbol(buffer, address);
+
 	printk(fmt, buffer);
 }
 
@@ -295,25 +339,20 @@ void __print_symbol(const char *fmt, uns
 struct kallsym_iter
 {
 	loff_t pos;
-	struct module *owner;
 	unsigned long value;
 	unsigned int nameoff; /* If iterating in core kernel symbols */
 	char type;
 	char name[KSYM_NAME_LEN+1];
+	char module_name[MODULE_NAME_LEN + 1];
+	int exported;
 };
 
 static int get_ksymbol_mod(struct kallsym_iter *iter)
 {
-	iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms,
-					 &iter->value, &iter->type,
-					 iter->name, sizeof(iter->name));
-	if (iter->owner == NULL)
+	if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
+				&iter->type, iter->name, iter->module_name,
+				&iter->exported) < 0)
 		return 0;
-
-	/* Label it "global" if it is exported, "local" if not exported. */
-	iter->type = is_exported(iter->name, iter->owner)
-		? toupper(iter->type) : tolower(iter->type);
-
 	return 1;
 }
 
@@ -322,7 +361,7 @@ static unsigned long get_ksymbol_core(st
 {
 	unsigned off = iter->nameoff;
 
-	iter->owner = NULL;
+	iter->module_name[0] = '\0';
 	iter->value = kallsyms_addresses[iter->pos];
 
 	iter->type = kallsyms_get_symbol_type(off);
@@ -386,12 +425,17 @@ static int s_show(struct seq_file *m, vo
 	if (!iter->name[0])
 		return 0;
 
-	if (iter->owner)
+	if (iter->module_name[0]) {
+		char type;
+
+		/* Label it "global" if it is exported,
+		 * "local" if not exported. */
+		type = iter->exported ? toupper(iter->type) :
+					tolower(iter->type);
 		seq_printf(m, "%0*lx %c %s\t[%s]\n",
 			   (int)(2*sizeof(void*)),
-			   iter->value, iter->type, iter->name,
-			   module_name(iter->owner));
-	else
+			   iter->value, type, iter->name, iter->module_name);
+	} else
 		seq_printf(m, "%0*lx %c %s\n",
 			   (int)(2*sizeof(void*)),
 			   iter->value, iter->type, iter->name);
@@ -426,18 +470,11 @@ static int kallsyms_open(struct inode *i
 	return ret;
 }
 
-static int kallsyms_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	kfree(m->private);
-	return seq_release(inode, file);
-}
-
 static const struct file_operations kallsyms_operations = {
 	.open = kallsyms_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = kallsyms_release,
+	.release = seq_release_private,
 };
 
 static int __init kallsyms_init(void)
@@ -452,3 +489,4 @@ static int __init kallsyms_init(void)
 __initcall(kallsyms_init);
 
 EXPORT_SYMBOL(__print_symbol);
+EXPORT_SYMBOL_GPL(sprint_symbol);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 2a59c8a..25db14b 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1118,8 +1118,8 @@ void crash_save_cpu(struct pt_regs *regs
 	memset(&prstatus, 0, sizeof(prstatus));
 	prstatus.pr_pid = current->pid;
 	elf_core_copy_regs(&prstatus.pr_reg, regs);
-	buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
-				sizeof(prstatus));
+	buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS,
+		      	      &prstatus, sizeof(prstatus));
 	final_note(buf);
 }
 
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 7962761..49cc4b9 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -23,7 +23,6 @@ #include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
 #include <linux/kmod.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/mnt_namespace.h>
 #include <linux/completion.h>
@@ -166,6 +165,12 @@ static int ____call_usermodehelper(void 
 	/* We can run anywhere, unlike our parent keventd(). */
 	set_cpus_allowed(current, CPU_MASK_ALL);
 
+	/*
+	 * Our parent is keventd, which runs with elevated scheduling priority.
+	 * Avoid propagating that into the userspace child.
+	 */
+	set_user_nice(current, 0);
+
 	retval = -EPERM;
 	if (current->fs->root)
 		retval = kernel_execve(sub_info->path,
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index d25a9ad..9e47d8c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -35,16 +35,19 @@ #include <linux/kprobes.h>
 #include <linux/hash.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/kallsyms.h>
 #include <linux/freezer.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
+#include <linux/kdebug.h>
+
 #include <asm-generic/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
-#include <asm/kdebug.h>
+#include <asm/uaccess.h>
 
 #define KPROBE_HASH_BITS 6
 #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
@@ -63,6 +66,9 @@ static struct hlist_head kprobe_table[KP
 static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
 static atomic_t kprobe_count;
 
+/* NOTE: change this value only with kprobe_mutex held */
+static bool kprobe_enabled;
+
 DEFINE_MUTEX(kprobe_mutex);		/* Protects kprobe_table */
 DEFINE_SPINLOCK(kretprobe_lock);	/* Protects kretprobe_inst_table */
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
@@ -132,9 +138,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos;
 
-      retry:
-	hlist_for_each(pos, &kprobe_insn_pages) {
-		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ retry:
+	hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
 		if (kip->nused < INSNS_PER_PAGE) {
 			int i;
 			for (i = 0; i < INSNS_PER_PAGE; i++) {
@@ -155,9 +160,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
 	}
 	/* All out of space.  Need to allocate a new page. Use slot 0. */
 	kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
-	if (!kip) {
+	if (!kip)
 		return NULL;
-	}
 
 	/*
 	 * Use module_alloc so this page is within +/- 2GB of where the
@@ -213,9 +217,8 @@ static int __kprobes collect_garbage_slo
 	if (check_safety() != 0)
 		return -EAGAIN;
 
-	hlist_for_each_safe(pos, next, &kprobe_insn_pages) {
+	hlist_for_each_entry_safe(kip, pos, next, &kprobe_insn_pages, hlist) {
 		int i;
-		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 		if (kip->ngarbage == 0)
 			continue;
 		kip->ngarbage = 0;	/* we will collect all garbages */
@@ -234,8 +237,7 @@ void __kprobes free_insn_slot(kprobe_opc
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos;
 
-	hlist_for_each(pos, &kprobe_insn_pages) {
-		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+	hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
 		if (kip->insns <= slot &&
 		    slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
 			int i = (slot - kip->insns) / MAX_INSN_SIZE;
@@ -248,9 +250,9 @@ void __kprobes free_insn_slot(kprobe_opc
 			break;
 		}
 	}
-	if (dirty && (++kprobe_garbage_slots > INSNS_PER_PAGE)) {
+
+	if (dirty && ++kprobe_garbage_slots > INSNS_PER_PAGE)
 		collect_garbage_slots();
-	}
 }
 #endif
 
@@ -316,7 +318,6 @@ static void __kprobes aggr_post_handler(
 			reset_kprobe_instance();
 		}
 	}
-	return;
 }
 
 static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
@@ -362,46 +363,6 @@ void __kprobes kprobes_inc_nmissed_count
 }
 
 /* Called with kretprobe_lock held */
-struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
-{
-	struct hlist_node *node;
-	struct kretprobe_instance *ri;
-	hlist_for_each_entry(ri, node, &rp->free_instances, uflist)
-		return ri;
-	return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe
-							      *rp)
-{
-	struct hlist_node *node;
-	struct kretprobe_instance *ri;
-	hlist_for_each_entry(ri, node, &rp->used_instances, uflist)
-		return ri;
-	return NULL;
-}
-
-/* Called with kretprobe_lock held */
-void __kprobes add_rp_inst(struct kretprobe_instance *ri)
-{
-	/*
-	 * Remove rp inst off the free list -
-	 * Add it back when probed function returns
-	 */
-	hlist_del(&ri->uflist);
-
-	/* Add rp inst onto table */
-	INIT_HLIST_NODE(&ri->hlist);
-	hlist_add_head(&ri->hlist,
-			&kretprobe_inst_table[hash_ptr(ri->task, KPROBE_HASH_BITS)]);
-
-	/* Also add this rp inst to the used list. */
-	INIT_HLIST_NODE(&ri->uflist);
-	hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with kretprobe_lock held */
 void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
 				struct hlist_head *head)
 {
@@ -454,7 +415,9 @@ void __kprobes kprobe_flush_task(struct 
 static inline void free_rp_inst(struct kretprobe *rp)
 {
 	struct kretprobe_instance *ri;
-	while ((ri = get_free_rp_inst(rp)) != NULL) {
+	struct hlist_node *pos, *next;
+
+	hlist_for_each_entry_safe(ri, pos, next, &rp->free_instances, uflist) {
 		hlist_del(&ri->uflist);
 		kfree(ri);
 	}
@@ -535,8 +498,8 @@ static int __kprobes register_aggr_kprob
 
 static int __kprobes in_kprobes_functions(unsigned long addr)
 {
-	if (addr >= (unsigned long)__kprobes_text_start
-		&& addr < (unsigned long)__kprobes_text_end)
+	if (addr >= (unsigned long)__kprobes_text_start &&
+	    addr < (unsigned long)__kprobes_text_end)
 		return -EINVAL;
 	return 0;
 }
@@ -563,19 +526,24 @@ static int __kprobes __register_kprobe(s
 		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))
+	if (!kernel_text_address((unsigned long) p->addr) ||
+	    in_kprobes_functions((unsigned long) p->addr))
 		return -EINVAL;
 
 	p->mod_refcounted = 0;
-	/* Check are we probing a module */
-	if ((probed_mod = module_text_address((unsigned long) p->addr))) {
+
+	/*
+	 * Check if are we probing a module.
+	 */
+	probed_mod = module_text_address((unsigned long) p->addr);
+	if (probed_mod) {
 		struct module *calling_mod = module_text_address(called_from);
-		/* We must allow modules to probe themself and
-		 * in this case avoid incrementing the module refcount,
-		 * so as to allow unloading of self probing modules.
+		/*
+		 * We must allow modules to probe themself and in this case
+		 * avoid incrementing the module refcount, so as to allow
+		 * unloading of self probing modules.
 		 */
-		if (calling_mod && (calling_mod != probed_mod)) {
+		if (calling_mod && calling_mod != probed_mod) {
 			if (unlikely(!try_module_get(probed_mod)))
 				return -EINVAL;
 			p->mod_refcounted = 1;
@@ -593,19 +561,21 @@ static int __kprobes __register_kprobe(s
 		goto out;
 	}
 
-	if ((ret = arch_prepare_kprobe(p)) != 0)
+	ret = arch_prepare_kprobe(p);
+	if (ret)
 		goto out;
 
 	INIT_HLIST_NODE(&p->hlist);
 	hlist_add_head_rcu(&p->hlist,
 		       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
-	if (atomic_add_return(1, &kprobe_count) == \
+	if (kprobe_enabled) {
+		if (atomic_add_return(1, &kprobe_count) == \
 				(ARCH_INACTIVE_KPROBE_COUNT + 1))
-		register_page_fault_notifier(&kprobe_page_fault_nb);
-
-	arch_arm_kprobe(p);
+			register_page_fault_notifier(&kprobe_page_fault_nb);
 
+		arch_arm_kprobe(p);
+	}
 out:
 	mutex_unlock(&kprobe_mutex);
 
@@ -616,8 +586,7 @@ out:
 
 int __kprobes register_kprobe(struct kprobe *p)
 {
-	return __register_kprobe(p,
-		(unsigned long)__builtin_return_address(0));
+	return __register_kprobe(p, (unsigned long)__builtin_return_address(0));
 }
 
 void __kprobes unregister_kprobe(struct kprobe *p)
@@ -641,11 +610,16 @@ void __kprobes unregister_kprobe(struct 
 		return;
 	}
 valid_p:
-	if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
-		(p->list.next == &old_p->list) &&
-		(p->list.prev == &old_p->list))) {
-		/* Only probe on the hash list */
-		arch_disarm_kprobe(p);
+	if (old_p == p ||
+	    (old_p->pre_handler == aggr_pre_handler &&
+	     p->list.next == &old_p->list && p->list.prev == &old_p->list)) {
+		/*
+		 * Only probe on the hash list. Disarm only if kprobes are
+		 * enabled - otherwise, the breakpoint would already have
+		 * been removed. We save on flushing icache.
+		 */
+		if (kprobe_enabled)
+			arch_disarm_kprobe(p);
 		hlist_del_rcu(&old_p->hlist);
 		cleanup_p = 1;
 	} else {
@@ -656,9 +630,11 @@ valid_p:
 	mutex_unlock(&kprobe_mutex);
 
 	synchronize_sched();
-	if (p->mod_refcounted &&
-	    (mod = module_text_address((unsigned long)p->addr)))
-		module_put(mod);
+	if (p->mod_refcounted) {
+		mod = module_text_address((unsigned long)p->addr);
+		if (mod)
+			module_put(mod);
+	}
 
 	if (cleanup_p) {
 		if (p != old_p) {
@@ -729,7 +705,21 @@ static int __kprobes pre_handler_kretpro
 
 	/*TODO: consider to only swap the RA after the last pre_handler fired */
 	spin_lock_irqsave(&kretprobe_lock, flags);
-	arch_prepare_kretprobe(rp, regs);
+	if (!hlist_empty(&rp->free_instances)) {
+		struct kretprobe_instance *ri;
+
+		ri = hlist_entry(rp->free_instances.first,
+				 struct kretprobe_instance, uflist);
+		ri->rp = rp;
+		ri->task = current;
+		arch_prepare_kretprobe(ri, regs);
+
+		/* XXX(hch): why is there no hlist_move_head? */
+		hlist_del(&ri->uflist);
+		hlist_add_head(&ri->uflist, &ri->rp->used_instances);
+		hlist_add_head(&ri->hlist, kretprobe_inst_table_head(ri->task));
+	} else
+		rp->nmissed++;
 	spin_unlock_irqrestore(&kretprobe_lock, flags);
 	return 0;
 }
@@ -792,11 +782,13 @@ void __kprobes unregister_kretprobe(stru
 {
 	unsigned long flags;
 	struct kretprobe_instance *ri;
+	struct hlist_node *pos, *next;
 
 	unregister_kprobe(&rp->kp);
+
 	/* No race here */
 	spin_lock_irqsave(&kretprobe_lock, flags);
-	while ((ri = get_used_rp_inst(rp)) != NULL) {
+	hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) {
 		ri->rp = NULL;
 		hlist_del(&ri->uflist);
 	}
@@ -816,6 +808,9 @@ static int __init init_kprobes(void)
 	}
 	atomic_set(&kprobe_count, 0);
 
+	/* By default, kprobes are enabled */
+	kprobe_enabled = true;
+
 	err = arch_init_kprobes();
 	if (!err)
 		err = register_die_notifier(&kprobe_exceptions_nb);
@@ -825,7 +820,7 @@ static int __init init_kprobes(void)
 
 #ifdef CONFIG_DEBUG_FS
 static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p,
-               const char *sym, int offset,char *modname)
+		const char *sym, int offset,char *modname)
 {
 	char *kprobe_type;
 
@@ -867,13 +862,13 @@ static int __kprobes show_kprobe_addr(st
 	struct kprobe *p, *kp;
 	const char *sym = NULL;
 	unsigned int i = *(loff_t *) v;
-	unsigned long size, offset = 0;
+	unsigned long offset = 0;
 	char *modname, namebuf[128];
 
 	head = &kprobe_table[i];
 	preempt_disable();
 	hlist_for_each_entry_rcu(p, node, head, hlist) {
-		sym = kallsyms_lookup((unsigned long)p->addr, &size,
+		sym = kallsyms_lookup((unsigned long)p->addr, NULL,
 					&offset, &modname, namebuf);
 		if (p->pre_handler == aggr_pre_handler) {
 			list_for_each_entry_rcu(kp, &p->list, list)
@@ -904,21 +899,149 @@ static struct file_operations debugfs_kp
 	.release        = seq_release,
 };
 
+static void __kprobes enable_all_kprobes(void)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct kprobe *p;
+	unsigned int i;
+
+	mutex_lock(&kprobe_mutex);
+
+	/* If kprobes are already enabled, just return */
+	if (kprobe_enabled)
+		goto already_enabled;
+
+	/*
+	 * Re-register the page fault notifier only if there are any
+	 * active probes at the time of enabling kprobes globally
+	 */
+	if (atomic_read(&kprobe_count) > ARCH_INACTIVE_KPROBE_COUNT)
+		register_page_fault_notifier(&kprobe_page_fault_nb);
+
+	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+		head = &kprobe_table[i];
+		hlist_for_each_entry_rcu(p, node, head, hlist)
+			arch_arm_kprobe(p);
+	}
+
+	kprobe_enabled = true;
+	printk(KERN_INFO "Kprobes globally enabled\n");
+
+already_enabled:
+	mutex_unlock(&kprobe_mutex);
+	return;
+}
+
+static void __kprobes disable_all_kprobes(void)
+{
+	struct hlist_head *head;
+	struct hlist_node *node;
+	struct kprobe *p;
+	unsigned int i;
+
+	mutex_lock(&kprobe_mutex);
+
+	/* If kprobes are already disabled, just return */
+	if (!kprobe_enabled)
+		goto already_disabled;
+
+	kprobe_enabled = false;
+	printk(KERN_INFO "Kprobes globally disabled\n");
+	for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+		head = &kprobe_table[i];
+		hlist_for_each_entry_rcu(p, node, head, hlist) {
+			if (!arch_trampoline_kprobe(p))
+				arch_disarm_kprobe(p);
+		}
+	}
+
+	mutex_unlock(&kprobe_mutex);
+	/* Allow all currently running kprobes to complete */
+	synchronize_sched();
+
+	mutex_lock(&kprobe_mutex);
+	/* Unconditionally unregister the page_fault notifier */
+	unregister_page_fault_notifier(&kprobe_page_fault_nb);
+
+already_disabled:
+	mutex_unlock(&kprobe_mutex);
+	return;
+}
+
+/*
+ * XXX: The debugfs bool file interface doesn't allow for callbacks
+ * when the bool state is switched. We can reuse that facility when
+ * available
+ */
+static ssize_t read_enabled_file_bool(struct file *file,
+	       char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[3];
+
+	if (kprobe_enabled)
+		buf[0] = '1';
+	else
+		buf[0] = '0';
+	buf[1] = '\n';
+	buf[2] = 0x00;
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled_file_bool(struct file *file,
+	       const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buf[32];
+	int buf_size;
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	switch (buf[0]) {
+	case 'y':
+	case 'Y':
+	case '1':
+		enable_all_kprobes();
+		break;
+	case 'n':
+	case 'N':
+	case '0':
+		disable_all_kprobes();
+		break;
+	}
+
+	return count;
+}
+
+static struct file_operations fops_kp = {
+	.read =         read_enabled_file_bool,
+	.write =        write_enabled_file_bool,
+};
+
 static int __kprobes debugfs_kprobe_init(void)
 {
 	struct dentry *dir, *file;
+	unsigned int value = 1;
 
 	dir = debugfs_create_dir("kprobes", NULL);
 	if (!dir)
 		return -ENOMEM;
 
-	file = debugfs_create_file("list", 0444, dir , 0 ,
+	file = debugfs_create_file("list", 0444, dir, NULL,
 				&debugfs_kprobes_operations);
 	if (!file) {
 		debugfs_remove(dir);
 		return -ENOMEM;
 	}
 
+	file = debugfs_create_file("enabled", 0600, dir,
+					&value, &fops_kp);
+	if (!file) {
+		debugfs_remove(dir);
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index e0ffe4a..559deca 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -24,18 +24,18 @@ static struct subsys_attribute _name##_a
 
 #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
 /* current uevent sequence number */
-static ssize_t uevent_seqnum_show(struct subsystem *subsys, char *page)
+static ssize_t uevent_seqnum_show(struct kset *kset, char *page)
 {
 	return sprintf(page, "%llu\n", (unsigned long long)uevent_seqnum);
 }
 KERNEL_ATTR_RO(uevent_seqnum);
 
 /* uevent helper program, used during early boo */
-static ssize_t uevent_helper_show(struct subsystem *subsys, char *page)
+static ssize_t uevent_helper_show(struct kset *kset, char *page)
 {
 	return sprintf(page, "%s\n", uevent_helper);
 }
-static ssize_t uevent_helper_store(struct subsystem *subsys, const char *page, size_t count)
+static ssize_t uevent_helper_store(struct kset *kset, const char *page, size_t count)
 {
 	if (count+1 > UEVENT_HELPER_PATH_LEN)
 		return -ENOENT;
@@ -49,13 +49,13 @@ KERNEL_ATTR_RW(uevent_helper);
 #endif
 
 #ifdef CONFIG_KEXEC
-static ssize_t kexec_loaded_show(struct subsystem *subsys, char *page)
+static ssize_t kexec_loaded_show(struct kset *kset, char *page)
 {
 	return sprintf(page, "%d\n", !!kexec_image);
 }
 KERNEL_ATTR_RO(kexec_loaded);
 
-static ssize_t kexec_crash_loaded_show(struct subsystem *subsys, char *page)
+static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page)
 {
 	return sprintf(page, "%d\n", !!kexec_crash_image);
 }
@@ -85,7 +85,7 @@ static int __init ksysfs_init(void)
 {
 	int error = subsystem_register(&kernel_subsys);
 	if (!error)
-		error = sysfs_create_group(&kernel_subsys.kset.kobj,
+		error = sysfs_create_group(&kernel_subsys.kobj,
 					   &kernel_attr_group);
 
 	return error;
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 7065a68..1a5ff22 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -257,9 +257,8 @@ static int save_trace(struct stack_trace
 	trace->entries = stack_trace + nr_stack_trace_entries;
 
 	trace->skip = 3;
-	trace->all_contexts = 0;
 
-	save_stack_trace(trace, NULL);
+	save_stack_trace(trace);
 
 	trace->max_entries = trace->nr_entries;
 
@@ -341,10 +340,7 @@ static const char *usage_str[] =
 
 const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
 {
-	unsigned long offs, size;
-	char *modname;
-
-	return kallsyms_lookup((unsigned long)key, &size, &offs, &modname, str);
+	return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str);
 }
 
 void
@@ -1313,8 +1309,9 @@ out_unlock_set:
 
 /*
  * Look up a dependency chain. If the key is not present yet then
- * add it and return 0 - in this case the new dependency chain is
- * validated. If the key is already hashed, return 1.
+ * add it and return 1 - in this case the new dependency chain is
+ * validated. If the key is already hashed, return 0.
+ * (On return with 1 graph_lock is held.)
  */
 static inline int lookup_chain_cache(u64 chain_key, struct lock_class *class)
 {
@@ -1577,7 +1574,7 @@ #define STRICT_READ_CHECKS	1
  * Mark a lock with a usage bit, and validate the state transition:
  */
 static int mark_lock(struct task_struct *curr, struct held_lock *this,
-		     enum lock_usage_bit new_bit, unsigned long ip)
+		     enum lock_usage_bit new_bit)
 {
 	unsigned int new_mask = 1 << new_bit, ret = 1;
 
@@ -1600,14 +1597,6 @@ static int mark_lock(struct task_struct 
 
 	this->class->usage_mask |= new_mask;
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-	if (new_bit == LOCK_ENABLED_HARDIRQS ||
-			new_bit == LOCK_ENABLED_HARDIRQS_READ)
-		ip = curr->hardirq_enable_ip;
-	else if (new_bit == LOCK_ENABLED_SOFTIRQS ||
-			new_bit == LOCK_ENABLED_SOFTIRQS_READ)
-		ip = curr->softirq_enable_ip;
-#endif
 	if (!save_trace(this->class->usage_traces + new_bit))
 		return 0;
 
@@ -1806,7 +1795,7 @@ #ifdef CONFIG_TRACE_IRQFLAGS
  * Mark all held locks with a usage bit:
  */
 static int
-mark_held_locks(struct task_struct *curr, int hardirq, unsigned long ip)
+mark_held_locks(struct task_struct *curr, int hardirq)
 {
 	enum lock_usage_bit usage_bit;
 	struct held_lock *hlock;
@@ -1826,7 +1815,7 @@ mark_held_locks(struct task_struct *curr
 			else
 				usage_bit = LOCK_ENABLED_SOFTIRQS;
 		}
-		if (!mark_lock(curr, hlock, usage_bit, ip))
+		if (!mark_lock(curr, hlock, usage_bit))
 			return 0;
 	}
 
@@ -1879,7 +1868,7 @@ void trace_hardirqs_on(void)
 	 * We are going to turn hardirqs on, so set the
 	 * usage bit for all held locks:
 	 */
-	if (!mark_held_locks(curr, 1, ip))
+	if (!mark_held_locks(curr, 1))
 		return;
 	/*
 	 * If we have softirqs enabled, then set the usage
@@ -1887,7 +1876,7 @@ void trace_hardirqs_on(void)
 	 * this bit from being set before)
 	 */
 	if (curr->softirqs_enabled)
-		if (!mark_held_locks(curr, 0, ip))
+		if (!mark_held_locks(curr, 0))
 			return;
 
 	curr->hardirq_enable_ip = ip;
@@ -1955,7 +1944,7 @@ void trace_softirqs_on(unsigned long ip)
 	 * enabled too:
 	 */
 	if (curr->hardirqs_enabled)
-		mark_held_locks(curr, 0, ip);
+		mark_held_locks(curr, 0);
 }
 
 /*
@@ -2093,43 +2082,43 @@ #ifdef CONFIG_TRACE_IRQFLAGS
 		if (read) {
 			if (curr->hardirq_context)
 				if (!mark_lock(curr, hlock,
-						LOCK_USED_IN_HARDIRQ_READ, ip))
+						LOCK_USED_IN_HARDIRQ_READ))
 					return 0;
 			if (curr->softirq_context)
 				if (!mark_lock(curr, hlock,
-						LOCK_USED_IN_SOFTIRQ_READ, ip))
+						LOCK_USED_IN_SOFTIRQ_READ))
 					return 0;
 		} else {
 			if (curr->hardirq_context)
-				if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ, ip))
+				if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
 					return 0;
 			if (curr->softirq_context)
-				if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ, ip))
+				if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
 					return 0;
 		}
 	}
 	if (!hardirqs_off) {
 		if (read) {
 			if (!mark_lock(curr, hlock,
-					LOCK_ENABLED_HARDIRQS_READ, ip))
+					LOCK_ENABLED_HARDIRQS_READ))
 				return 0;
 			if (curr->softirqs_enabled)
 				if (!mark_lock(curr, hlock,
-						LOCK_ENABLED_SOFTIRQS_READ, ip))
+						LOCK_ENABLED_SOFTIRQS_READ))
 					return 0;
 		} else {
 			if (!mark_lock(curr, hlock,
-					LOCK_ENABLED_HARDIRQS, ip))
+					LOCK_ENABLED_HARDIRQS))
 				return 0;
 			if (curr->softirqs_enabled)
 				if (!mark_lock(curr, hlock,
-						LOCK_ENABLED_SOFTIRQS, ip))
+						LOCK_ENABLED_SOFTIRQS))
 					return 0;
 		}
 	}
 #endif
 	/* mark it as used: */
-	if (!mark_lock(curr, hlock, LOCK_USED, ip))
+	if (!mark_lock(curr, hlock, LOCK_USED))
 		return 0;
 out_calc_hash:
 	/*
diff --git a/kernel/module.c b/kernel/module.c
index dcdb32b..d36e454 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/init.h>
+#include <linux/kallsyms.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -45,6 +46,8 @@ #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
 #include <linux/license.h>
 
+extern int module_sysfs_initialized;
+
 #if 0
 #define DEBUGP printk
 #else
@@ -308,14 +311,14 @@ static int split_block(unsigned int i, u
 {
 	/* Reallocation required? */
 	if (pcpu_num_used + 1 > pcpu_num_allocated) {
-		int *new = kmalloc(sizeof(new[0]) * pcpu_num_allocated*2,
-				   GFP_KERNEL);
+		int *new;
+
+		new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
+			       GFP_KERNEL);
 		if (!new)
 			return 0;
 
-		memcpy(new, pcpu_size, sizeof(new[0])*pcpu_num_allocated);
 		pcpu_num_allocated *= 2;
-		kfree(pcpu_size);
 		pcpu_size = new;
 	}
 
@@ -346,10 +349,10 @@ static void *percpu_modalloc(unsigned lo
 	unsigned int i;
 	void *ptr;
 
-	if (align > SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "%s: per-cpu alignment %li > %i\n",
-		       name, align, SMP_CACHE_BYTES);
-		align = SMP_CACHE_BYTES;
+	if (align > PAGE_SIZE) {
+		printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
+		       name, align, PAGE_SIZE);
+		align = PAGE_SIZE;
 	}
 
 	ptr = __per_cpu_start;
@@ -430,7 +433,7 @@ static int percpu_modinit(void)
 	pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
 			    GFP_KERNEL);
 	/* Static in-kernel percpu data (used). */
-	pcpu_size[0] = -ALIGN(__per_cpu_end-__per_cpu_start, SMP_CACHE_BYTES);
+	pcpu_size[0] = -(__per_cpu_end-__per_cpu_start);
 	/* Free room. */
 	pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
 	if (pcpu_size[1] < 0) {
@@ -1117,8 +1120,8 @@ int mod_sysfs_init(struct module *mod)
 {
 	int err;
 
-	if (!module_subsys.kset.subsys) {
-		printk(KERN_ERR "%s: module_subsys not initialized\n",
+	if (!module_sysfs_initialized) {
+		printk(KERN_ERR "%s: module sysfs not initialized\n",
 		       mod->name);
 		err = -EINVAL;
 		goto out;
@@ -1148,8 +1151,10 @@ int mod_sysfs_setup(struct module *mod,
 		goto out;
 
 	mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
-	if (!mod->holders_dir)
+	if (!mod->holders_dir) {
+		err = -ENOMEM;
 		goto out_unreg;
+	}
 
 	err = module_param_sysfs_setup(mod, kparam, num_params);
 	if (err)
@@ -1467,7 +1472,7 @@ static void setup_modinfo(struct module 
 }
 
 #ifdef CONFIG_KALLSYMS
-int is_exported(const char *name, const struct module *mod)
+static int is_exported(const char *name, const struct module *mod)
 {
 	if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
 		return 1;
@@ -2093,8 +2098,10 @@ static const char *get_ksymbol(struct mo
 	if (!best)
 		return NULL;
 
-	*size = nextval - mod->symtab[best].st_value;
-	*offset = addr - mod->symtab[best].st_value;
+	if (size)
+		*size = nextval - mod->symtab[best].st_value;
+	if (offset)
+		*offset = addr - mod->symtab[best].st_value;
 	return mod->strtab + mod->symtab[best].st_name;
 }
 
@@ -2119,8 +2126,58 @@ const char *module_address_lookup(unsign
 	return NULL;
 }
 
-struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
-				char *type, char *name, size_t namelen)
+int lookup_module_symbol_name(unsigned long addr, char *symname)
+{
+	struct module *mod;
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(mod, &modules, list) {
+		if (within(addr, mod->module_init, mod->init_size) ||
+		    within(addr, mod->module_core, mod->core_size)) {
+			const char *sym;
+
+			sym = get_ksymbol(mod, addr, NULL, NULL);
+			if (!sym)
+				goto out;
+			strlcpy(symname, sym, KSYM_NAME_LEN + 1);
+			mutex_unlock(&module_mutex);
+			return 0;
+		}
+	}
+out:
+	mutex_unlock(&module_mutex);
+	return -ERANGE;
+}
+
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
+			unsigned long *offset, char *modname, char *name)
+{
+	struct module *mod;
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(mod, &modules, list) {
+		if (within(addr, mod->module_init, mod->init_size) ||
+		    within(addr, mod->module_core, mod->core_size)) {
+			const char *sym;
+
+			sym = get_ksymbol(mod, addr, size, offset);
+			if (!sym)
+				goto out;
+			if (modname)
+				strlcpy(modname, mod->name, MODULE_NAME_LEN + 1);
+			if (name)
+				strlcpy(name, sym, KSYM_NAME_LEN + 1);
+			mutex_unlock(&module_mutex);
+			return 0;
+		}
+	}
+out:
+	mutex_unlock(&module_mutex);
+	return -ERANGE;
+}
+
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+			char *name, char *module_name, int *exported)
 {
 	struct module *mod;
 
@@ -2130,14 +2187,16 @@ struct module *module_get_kallsym(unsign
 			*value = mod->symtab[symnum].st_value;
 			*type = mod->symtab[symnum].st_info;
 			strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
-				namelen);
+				KSYM_NAME_LEN + 1);
+			strlcpy(module_name, mod->name, MODULE_NAME_LEN + 1);
+			*exported = is_exported(name, mod);
 			mutex_unlock(&module_mutex);
-			return mod;
+			return 0;
 		}
 		symnum -= mod->num_symtab;
 	}
 	mutex_unlock(&module_mutex);
-	return NULL;
+	return -ERANGE;
 }
 
 static unsigned long mod_find_symname(struct module *mod, const char *name)
@@ -2383,7 +2442,7 @@ void module_add_driver(struct module *mo
 		struct kobject *mkobj;
 
 		/* Lookup built-in module entry in /sys/modules */
-		mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
+		mkobj = kset_find_obj(&module_subsys, drv->mod_name);
 		if (mkobj) {
 			mk = container_of(mkobj, struct module_kobject, kobj);
 			/* remember our module structure */
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f5b9ee6..1bc4b55 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -38,10 +38,8 @@ void get_task_namespaces(struct task_str
 
 /*
  * 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)
+static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
 {
 	struct nsproxy *ns;
 
@@ -52,26 +50,49 @@ static inline struct nsproxy *clone_name
 }
 
 /*
- * copies the nsproxy, setting refcount to 1, and grabbing a
- * reference to all contained namespaces.  Called from
- * sys_unshare()
+ * Create new nsproxy and all of its the associated namespaces.
+ * Return the newly created nsproxy.  Do not attach this to the task,
+ * leave it to the caller to do proper locking and attach it to task.
  */
-struct nsproxy *dup_namespaces(struct nsproxy *orig)
+static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
+			struct fs_struct *new_fs)
 {
-	struct nsproxy *ns = clone_namespaces(orig);
+	struct nsproxy *new_nsp;
 
-	if (ns) {
-		if (ns->mnt_ns)
-			get_mnt_ns(ns->mnt_ns);
-		if (ns->uts_ns)
-			get_uts_ns(ns->uts_ns);
-		if (ns->ipc_ns)
-			get_ipc_ns(ns->ipc_ns);
-		if (ns->pid_ns)
-			get_pid_ns(ns->pid_ns);
-	}
+	new_nsp = clone_nsproxy(tsk->nsproxy);
+	if (!new_nsp)
+		return ERR_PTR(-ENOMEM);
 
-	return ns;
+	new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
+	if (IS_ERR(new_nsp->mnt_ns))
+		goto out_ns;
+
+	new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
+	if (IS_ERR(new_nsp->uts_ns))
+		goto out_uts;
+
+	new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
+	if (IS_ERR(new_nsp->ipc_ns))
+		goto out_ipc;
+
+	new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns);
+	if (IS_ERR(new_nsp->pid_ns))
+		goto out_pid;
+
+	return new_nsp;
+
+out_pid:
+	if (new_nsp->ipc_ns)
+		put_ipc_ns(new_nsp->ipc_ns);
+out_ipc:
+	if (new_nsp->uts_ns)
+		put_uts_ns(new_nsp->uts_ns);
+out_uts:
+	if (new_nsp->mnt_ns)
+		put_mnt_ns(new_nsp->mnt_ns);
+out_ns:
+	kfree(new_nsp);
+	return ERR_PTR(-ENOMEM);
 }
 
 /*
@@ -92,47 +113,21 @@ int copy_namespaces(int flags, struct ta
 	if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
 		return 0;
 
-	new_ns = clone_namespaces(old_ns);
-	if (!new_ns) {
-		err = -ENOMEM;
+	if (!capable(CAP_SYS_ADMIN)) {
+		err = -EPERM;
 		goto out;
 	}
 
-	tsk->nsproxy = new_ns;
-
-	err = copy_mnt_ns(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;
-
-	err = copy_pid_ns(flags, tsk);
-	if (err)
-		goto out_pid;
+	new_ns = create_new_namespaces(flags, tsk, tsk->fs);
+	if (IS_ERR(new_ns)) {
+		err = PTR_ERR(new_ns);
+		goto out;
+	}
 
+	tsk->nsproxy = new_ns;
 out:
 	put_nsproxy(old_ns);
 	return err;
-
-out_pid:
-	if (new_ns->ipc_ns)
-		put_ipc_ns(new_ns->ipc_ns);
-out_ipc:
-	if (new_ns->uts_ns)
-		put_uts_ns(new_ns->uts_ns);
-out_uts:
-	if (new_ns->mnt_ns)
-		put_mnt_ns(new_ns->mnt_ns);
-out_ns:
-	tsk->nsproxy = old_ns;
-	kfree(new_ns);
-	goto out;
 }
 
 void free_nsproxy(struct nsproxy *ns)
@@ -147,3 +142,41 @@ void free_nsproxy(struct nsproxy *ns)
 		put_pid_ns(ns->pid_ns);
 	kfree(ns);
 }
+
+/*
+ * Called from unshare. Unshare all the namespaces part of nsproxy.
+ * On sucess, returns the new nsproxy and a reference to old nsproxy
+ * to make sure it stays around.
+ */
+int unshare_nsproxy_namespaces(unsigned long unshare_flags,
+		struct nsproxy **new_nsp, struct fs_struct *new_fs)
+{
+	struct nsproxy *old_ns = current->nsproxy;
+	int err = 0;
+
+	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
+		return 0;
+
+#ifndef CONFIG_IPC_NS
+	if (unshare_flags & CLONE_NEWIPC)
+		return -EINVAL;
+#endif
+
+#ifndef CONFIG_UTS_NS
+	if (unshare_flags & CLONE_NEWUTS)
+		return -EINVAL;
+#endif
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	get_nsproxy(old_ns);
+
+	*new_nsp = create_new_namespaces(unshare_flags, current,
+				new_fs ? new_fs : current->fs);
+	if (IS_ERR(*new_nsp)) {
+		err = PTR_ERR(*new_nsp);
+		put_nsproxy(old_ns);
+	}
+	return err;
+}
diff --git a/kernel/params.c b/kernel/params.c
index 1fc4ac7..e61c46c 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -269,7 +269,7 @@ int param_get_invbool(char *buffer, stru
 	return param_get_bool(buffer, &dummy);
 }
 
-/* We cheat here and temporarily mangle the string. */
+/* We break the rule and mangle the string. */
 static int param_array(const char *name,
 		       const char *val,
 		       unsigned int min, unsigned int max,
@@ -691,6 +691,7 @@ static struct kset_uevent_ops module_uev
 };
 
 decl_subsys(module, &module_ktype, &module_uevent_ops);
+int module_sysfs_initialized;
 
 static struct kobj_type module_ktype = {
 	.sysfs_ops =	&module_sysfs_ops,
@@ -709,6 +710,7 @@ static int __init param_sysfs_init(void)
 			__FILE__, __LINE__, ret);
 		return ret;
 	}
+	module_sysfs_initialized = 1;
 
 	param_sysfs_builtin();
 
diff --git a/kernel/pid.c b/kernel/pid.c
index 78f2aee..d3ad724 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -360,16 +360,11 @@ struct pid *find_ge_pid(int nr)
 }
 EXPORT_SYMBOL_GPL(find_get_pid);
 
-int copy_pid_ns(int flags, struct task_struct *tsk)
+struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *old_ns)
 {
-	struct pid_namespace *old_ns = tsk->nsproxy->pid_ns;
-	int err = 0;
-
-	if (!old_ns)
-		return 0;
-
+	BUG_ON(!old_ns);
 	get_pid_ns(old_ns);
-	return err;
+	return old_ns;
 }
 
 void free_pid_ns(struct kref *kref)
@@ -412,7 +407,5 @@ void __init pidmap_init(void)
 	set_bit(0, init_pid_ns.pidmap[0].page);
 	atomic_dec(&init_pid_ns.pidmap[0].nr_free);
 
-	pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
-					__alignof__(struct pid),
-					SLAB_PANIC, NULL, NULL);
+	pid_cachep = KMEM_CACHE(pid, SLAB_PANIC);
 }
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 657f776..1de710e 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -971,7 +971,7 @@ static void check_thread_timers(struct t
 	maxfire = 20;
 	tsk->it_prof_expires = cputime_zero;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
@@ -986,7 +986,7 @@ static void check_thread_timers(struct t
 	maxfire = 20;
 	tsk->it_virt_expires = cputime_zero;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
@@ -1001,7 +1001,7 @@ static void check_thread_timers(struct t
 	maxfire = 20;
 	tsk->it_sched_expires = 0;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || tsk->sched_time < t->expires.sched) {
@@ -1057,7 +1057,7 @@ static void check_process_timers(struct 
 	maxfire = 20;
 	prof_expires = cputime_zero;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) {
@@ -1072,7 +1072,7 @@ static void check_process_timers(struct 
 	maxfire = 20;
 	virt_expires = cputime_zero;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || cputime_lt(utime, t->expires.cpu)) {
@@ -1087,7 +1087,7 @@ static void check_process_timers(struct 
 	maxfire = 20;
 	sched_expires = 0;
 	while (!list_empty(timers)) {
-		struct cpu_timer_list *t = list_entry(timers->next,
+		struct cpu_timer_list *t = list_first_entry(timers,
 						      struct cpu_timer_list,
 						      entry);
 		if (!--maxfire || sched_time < t->expires.sched) {
@@ -1400,7 +1400,7 @@ void set_process_cpu_timer(struct task_s
 	 */
 	head = &tsk->signal->cpu_timers[clock_idx];
 	if (list_empty(head) ||
-	    cputime_ge(list_entry(head->next,
+	    cputime_ge(list_first_entry(head,
 				  struct cpu_timer_list, entry)->expires.cpu,
 		       *newval)) {
 		/*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 44318ca..588c99d 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -31,7 +31,6 @@
  * POSIX clocks & timers
  */
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/time.h>
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 51a4dd0..495b7d4 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -78,17 +78,22 @@ config PM_SYSFS_DEPRECATED
 	  are likely to be bus or driver specific.
 
 config SOFTWARE_SUSPEND
-	bool "Software Suspend"
-	depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
+	bool "Software Suspend (Hibernation)"
+	depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
 	---help---
-	  Enable the suspend to disk (STD) functionality.
+	  Enable the suspend to disk (STD) functionality, which is usually
+	  called "hibernation" in user interfaces.  STD checkpoints the
+	  system and powers it off; and restores that checkpoint on reboot.
 
 	  You can suspend your machine with 'echo disk > /sys/power/state'.
 	  Alternatively, you can use the additional userland tools available
 	  from <http://suspend.sf.net>.
 
 	  In principle it does not require ACPI or APM, although for example
-	  ACPI will be used if available.
+	  ACPI will be used for the final steps when it is available.  One
+	  of the reasons to use software suspend is that the firmware hooks
+	  for suspend states like suspend-to-RAM (STR) often don't work very
+	  well with Linux.
 
 	  It creates an image which is saved in your active swap. Upon the next
 	  boot, pass the 'resume=/dev/swappartition' argument to the kernel to
@@ -134,7 +139,7 @@ config PM_STD_PARTITION
 
 config SUSPEND_SMP
 	bool
-	depends on HOTPLUG_CPU && X86 && PM
+	depends on HOTPLUG_CPU && (X86 || PPC64) && PM
 	default y
 
 config APM_EMULATION
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index aec19b0..0633137 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -39,7 +39,13 @@ static inline int platform_prepare(void)
 {
 	int error = 0;
 
-	if (pm_disk_mode == PM_DISK_PLATFORM) {
+	switch (pm_disk_mode) {
+	case PM_DISK_TEST:
+	case PM_DISK_TESTPROC:
+	case PM_DISK_SHUTDOWN:
+	case PM_DISK_REBOOT:
+		break;
+	default:
 		if (pm_ops && pm_ops->prepare)
 			error = pm_ops->prepare(PM_SUSPEND_DISK);
 	}
@@ -48,40 +54,48 @@ static inline int platform_prepare(void)
 
 /**
  *	power_down - Shut machine down for hibernate.
- *	@mode:		Suspend-to-disk mode
  *
- *	Use the platform driver, if configured so, and return gracefully if it
- *	fails.
- *	Otherwise, try to power off and reboot. If they fail, halt the machine,
- *	there ain't no turning back.
+ *	Use the platform driver, if configured so; otherwise try
+ *	to power off or reboot.
  */
 
-static void power_down(suspend_disk_method_t mode)
+static void power_down(void)
 {
-	switch(mode) {
-	case PM_DISK_PLATFORM:
-		if (pm_ops && pm_ops->enter) {
-			kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-			pm_ops->enter(PM_SUSPEND_DISK);
-			break;
-		}
+	switch (pm_disk_mode) {
+	case PM_DISK_TEST:
+	case PM_DISK_TESTPROC:
+		break;
 	case PM_DISK_SHUTDOWN:
 		kernel_power_off();
 		break;
 	case PM_DISK_REBOOT:
 		kernel_restart(NULL);
 		break;
+	default:
+		if (pm_ops && pm_ops->enter) {
+			kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+			pm_ops->enter(PM_SUSPEND_DISK);
+			break;
+		}
 	}
 	kernel_halt();
-	/* Valid image is on the disk, if we continue we risk serious data corruption
-	   after resume. */
+	/*
+	 * Valid image is on the disk, if we continue we risk serious data
+	 * corruption after resume.
+	 */
 	printk(KERN_CRIT "Please power me down manually\n");
 	while(1);
 }
 
 static inline void platform_finish(void)
 {
-	if (pm_disk_mode == PM_DISK_PLATFORM) {
+	switch (pm_disk_mode) {
+	case PM_DISK_TEST:
+	case PM_DISK_TESTPROC:
+	case PM_DISK_SHUTDOWN:
+	case PM_DISK_REBOOT:
+		break;
+	default:
 		if (pm_ops && pm_ops->finish)
 			pm_ops->finish(PM_SUSPEND_DISK);
 	}
@@ -108,8 +122,6 @@ static int prepare_processes(void)
 /**
  *	pm_suspend_disk - The granpappy of hibernation power management.
  *
- *	If we're going through the firmware, then get it over with quickly.
- *
  *	If not, then call swsusp to do its thing, then figure out how
  *	to power down the system.
  */
@@ -118,15 +130,25 @@ int pm_suspend_disk(void)
 {
 	int error;
 
+	/* The snapshot device should not be opened while we're running */
+	if (!atomic_add_unless(&snapshot_device_available, -1, 0))
+		return -EBUSY;
+
+	/* Allocate memory management structures */
+	error = create_basic_memory_bitmaps();
+	if (error)
+		goto Exit;
+
 	error = prepare_processes();
 	if (error)
-		return error;
+		goto Finish;
 
 	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. */
 	error = swsusp_shrink_memory();
 	if (error)
@@ -166,7 +188,7 @@ int pm_suspend_disk(void)
 		pr_debug("PM: writing image.\n");
 		error = swsusp_write();
 		if (!error)
-			power_down(pm_disk_mode);
+			power_down();
 		else {
 			swsusp_free();
 			goto Thaw;
@@ -184,6 +206,10 @@ int pm_suspend_disk(void)
 	resume_console();
  Thaw:
 	unprepare_processes();
+ Finish:
+	free_basic_memory_bitmaps();
+ Exit:
+	atomic_inc(&snapshot_device_available);
 	return error;
 }
 
@@ -227,13 +253,21 @@ static int software_resume(void)
 	}
 
 	pr_debug("PM: Checking swsusp image.\n");
-
 	error = swsusp_check();
 	if (error)
-		goto Done;
+		goto Unlock;
 
-	pr_debug("PM: Preparing processes for restore.\n");
+	/* The snapshot device should not be opened while we're running */
+	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+		error = -EBUSY;
+		goto Unlock;
+	}
 
+	error = create_basic_memory_bitmaps();
+	if (error)
+		goto Finish;
+
+	pr_debug("PM: Preparing processes for restore.\n");
 	error = prepare_processes();
 	if (error) {
 		swsusp_close();
@@ -268,7 +302,11 @@ static int software_resume(void)
 	printk(KERN_ERR "PM: Restore failed, recovering.\n");
 	unprepare_processes();
  Done:
+	free_basic_memory_bitmaps();
+ Finish:
+	atomic_inc(&snapshot_device_available);
 	/* For success case, the suspend path will release the lock */
+ Unlock:
 	mutex_unlock(&pm_mutex);
 	pr_debug("PM: Resume from disk failed.\n");
 	return 0;
@@ -278,7 +316,6 @@ late_initcall(software_resume);
 
 
 static const char * const pm_disk_modes[] = {
-	[PM_DISK_FIRMWARE]	= "firmware",
 	[PM_DISK_PLATFORM]	= "platform",
 	[PM_DISK_SHUTDOWN]	= "shutdown",
 	[PM_DISK_REBOOT]	= "reboot",
@@ -289,37 +326,62 @@ static const char * const pm_disk_modes[
 /**
  *	disk - Control suspend-to-disk mode
  *
- *	Suspend-to-disk can be handled in several ways. The greatest
- *	distinction is who writes memory to disk - the firmware or the OS.
- *	If the firmware does it, we assume that it also handles suspending
- *	the system.
- *	If the OS does it, then we have three options for putting the system
- *	to sleep - using the platform driver (e.g. ACPI or other PM registers),
- *	powering off the system or rebooting the system (for testing).
+ *	Suspend-to-disk can be handled in several ways. We have a few options
+ *	for putting the system to sleep - using the platform driver (e.g. ACPI
+ *	or other pm_ops), powering off the system or rebooting the system
+ *	(for testing) as well as the two test modes.
  *
- *	The system will support either 'firmware' or 'platform', and that is
- *	known a priori (and encoded in pm_ops). But, the user may choose
- *	'shutdown' or 'reboot' as alternatives.
+ *	The system can support 'platform', and that is known a priori (and
+ *	encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
+ *	as alternatives, as well as the test modes 'test' and 'testproc'.
  *
  *	show() will display what the mode is currently set to.
  *	store() will accept one of
  *
- *	'firmware'
  *	'platform'
  *	'shutdown'
  *	'reboot'
+ *	'test'
+ *	'testproc'
  *
- *	It will only change to 'firmware' or 'platform' if the system
+ *	It will only change to 'platform' if the system
  *	supports it (as determined from pm_ops->pm_disk_mode).
  */
 
-static ssize_t disk_show(struct subsystem * subsys, char * buf)
+static ssize_t disk_show(struct kset *kset, char *buf)
 {
-	return sprintf(buf, "%s\n", pm_disk_modes[pm_disk_mode]);
+	int i;
+	char *start = buf;
+
+	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
+		if (!pm_disk_modes[i])
+			continue;
+		switch (i) {
+		case PM_DISK_SHUTDOWN:
+		case PM_DISK_REBOOT:
+		case PM_DISK_TEST:
+		case PM_DISK_TESTPROC:
+			break;
+		default:
+			if (pm_ops && pm_ops->enter &&
+			    (i == pm_ops->pm_disk_mode))
+				break;
+			/* not a valid mode, continue with loop */
+			continue;
+		}
+		if (i == pm_disk_mode)
+			buf += sprintf(buf, "[%s]", pm_disk_modes[i]);
+		else
+			buf += sprintf(buf, "%s", pm_disk_modes[i]);
+		if (i+1 != PM_DISK_MAX)
+			buf += sprintf(buf, " ");
+	}
+	buf += sprintf(buf, "\n");
+	return buf-start;
 }
 
 
-static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
+static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
 {
 	int error = 0;
 	int i;
@@ -331,17 +393,21 @@ static ssize_t disk_store(struct subsyst
 	len = p ? p - buf : n;
 
 	mutex_lock(&pm_mutex);
-	for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) {
+	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
 		if (!strncmp(buf, pm_disk_modes[i], len)) {
 			mode = i;
 			break;
 		}
 	}
 	if (mode) {
-		if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
-		     mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
+		switch (mode) {
+		case PM_DISK_SHUTDOWN:
+		case PM_DISK_REBOOT:
+		case PM_DISK_TEST:
+		case PM_DISK_TESTPROC:
 			pm_disk_mode = mode;
-		} else {
+			break;
+		default:
 			if (pm_ops && pm_ops->enter &&
 			    (mode == pm_ops->pm_disk_mode))
 				pm_disk_mode = mode;
@@ -360,13 +426,13 @@ static ssize_t disk_store(struct subsyst
 
 power_attr(disk);
 
-static ssize_t resume_show(struct subsystem * subsys, char *buf)
+static ssize_t resume_show(struct kset *kset, char *buf)
 {
 	return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
 		       MINOR(swsusp_resume_device));
 }
 
-static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
+static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
 {
 	unsigned int maj, min;
 	dev_t res;
@@ -392,12 +458,12 @@ static ssize_t resume_store(struct subsy
 
 power_attr(resume);
 
-static ssize_t image_size_show(struct subsystem * subsys, char *buf)
+static ssize_t image_size_show(struct kset *kset, char *buf)
 {
 	return sprintf(buf, "%lu\n", image_size);
 }
 
-static ssize_t image_size_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
 {
 	unsigned long size;
 
@@ -426,7 +492,7 @@ static struct attribute_group attr_group
 
 static int __init pm_disk_init(void)
 {
-	return sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+	return sysfs_create_group(&power_subsys.kobj, &attr_group);
 }
 
 core_initcall(pm_disk_init);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index a064dfd..f6dda68 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,7 @@ #define FREE_PAGE_NUMBER (100)
 DEFINE_MUTEX(pm_mutex);
 
 struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
+suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
 
 /**
  *	pm_set_ops - Set the global power method table. 
@@ -41,9 +41,26 @@ void pm_set_ops(struct pm_ops * ops)
 {
 	mutex_lock(&pm_mutex);
 	pm_ops = ops;
+	if (ops && ops->pm_disk_mode != PM_DISK_INVALID) {
+		pm_disk_mode = ops->pm_disk_mode;
+	} else
+		pm_disk_mode = PM_DISK_SHUTDOWN;
 	mutex_unlock(&pm_mutex);
 }
 
+/**
+ * pm_valid_only_mem - generic memory-only valid callback
+ *
+ * pm_ops drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int pm_valid_only_mem(suspend_state_t state)
+{
+	return state == PM_SUSPEND_MEM;
+}
+
+
 static inline void pm_finish(suspend_state_t state)
 {
 	if (pm_ops->finish)
@@ -111,13 +128,24 @@ static int suspend_prepare(suspend_state
 	return error;
 }
 
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+{
+	local_irq_disable();
+}
+
+/* default implementation */
+void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+{
+	local_irq_enable();
+}
 
 int suspend_enter(suspend_state_t state)
 {
 	int error = 0;
-	unsigned long flags;
 
-	local_irq_save(flags);
+	arch_suspend_disable_irqs();
+	BUG_ON(!irqs_disabled());
 
 	if ((error = device_power_down(PMSG_SUSPEND))) {
 		printk(KERN_ERR "Some devices failed to power down\n");
@@ -126,7 +154,8 @@ int suspend_enter(suspend_state_t state)
 	error = pm_ops->enter(state);
 	device_power_up();
  Done:
-	local_irq_restore(flags);
+	arch_suspend_enable_irqs();
+	BUG_ON(irqs_disabled());
 	return error;
 }
 
@@ -155,22 +184,26 @@ static void suspend_finish(suspend_state
 static const char * const pm_states[PM_SUSPEND_MAX] = {
 	[PM_SUSPEND_STANDBY]	= "standby",
 	[PM_SUSPEND_MEM]	= "mem",
-#ifdef CONFIG_SOFTWARE_SUSPEND
 	[PM_SUSPEND_DISK]	= "disk",
-#endif
 };
 
 static inline int valid_state(suspend_state_t state)
 {
 	/* Suspend-to-disk does not really need low-level support.
-	 * It can work with reboot if needed. */
+	 * It can work with shutdown/reboot if needed. If it isn't
+	 * configured, then it cannot be supported.
+	 */
 	if (state == PM_SUSPEND_DISK)
+#ifdef CONFIG_SOFTWARE_SUSPEND
 		return 1;
+#else
+		return 0;
+#endif
 
 	/* all other states need lowlevel support and need to be
 	 * valid to the lowlevel implementation, no valid callback
-	 * implies that all are valid. */
-	if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state)))
+	 * implies that none are valid. */
+	if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
 		return 0;
 	return 1;
 }
@@ -215,15 +248,6 @@ static int enter_state(suspend_state_t s
 	return error;
 }
 
-/*
- * This is main interface to the outside world. It needs to be
- * called from process context.
- */
-int software_suspend(void)
-{
-	return enter_state(PM_SUSPEND_DISK);
-}
-
 
 /**
  *	pm_suspend - Externally visible function for suspending system.
@@ -256,7 +280,7 @@ decl_subsys(power,NULL,NULL);
  *	proper enumerated value, and initiates a suspend transition.
  */
 
-static ssize_t state_show(struct subsystem * subsys, char * buf)
+static ssize_t state_show(struct kset *kset, char *buf)
 {
 	int i;
 	char * s = buf;
@@ -269,7 +293,7 @@ static ssize_t state_show(struct subsyst
 	return (s - buf);
 }
 
-static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
 {
 	suspend_state_t state = PM_SUSPEND_STANDBY;
 	const char * const *s;
@@ -296,13 +320,13 @@ power_attr(state);
 #ifdef CONFIG_PM_TRACE
 int pm_trace_enabled;
 
-static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+static ssize_t pm_trace_show(struct kset *kset, 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)
+pm_trace_store(struct kset *kset, const char *buf, size_t n)
 {
 	int val;
 
@@ -336,7 +360,7 @@ static int __init pm_init(void)
 {
 	int error = subsystem_register(&power_subsys);
 	if (!error)
-		error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+		error = sysfs_create_group(&power_subsys.kobj,&attr_group);
 	return error;
 }
 
diff --git a/kernel/power/power.h b/kernel/power/power.h
index eb461b8..34b4354 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -14,8 +14,18 @@ struct swsusp_info {
 
 
 #ifdef CONFIG_SOFTWARE_SUSPEND
-extern int pm_suspend_disk(void);
+/*
+ * Keep some memory free so that I/O operations can succeed without paging
+ * [Might this be more than 4 MB?]
+ */
+#define PAGES_FOR_IO	((4096 * 1024) >> PAGE_SHIFT)
+/*
+ * Keep 1 MB of memory free so that device drivers can allocate some pages in
+ * their .suspend() routines without breaking the suspend to disk.
+ */
+#define SPARE_PAGES	((1024 * 1024) >> PAGE_SHIFT)
 
+extern int pm_suspend_disk(void);
 #else
 static inline int pm_suspend_disk(void)
 {
@@ -23,6 +33,8 @@ static inline int pm_suspend_disk(void)
 }
 #endif
 
+extern int pfn_is_nosave(unsigned long);
+
 extern struct mutex pm_mutex;
 
 #define power_attr(_name) \
@@ -35,10 +47,7 @@ static struct subsys_attribute _name##_a
 	.store	= _name##_store,		\
 }
 
-extern struct subsystem power_subsys;
-
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
+extern struct kset power_subsys;
 
 /* Preferred image size in bytes (default 500 MB) */
 extern unsigned long image_size;
@@ -49,6 +58,8 @@ extern sector_t swsusp_resume_block;
 extern asmlinkage int swsusp_arch_suspend(void);
 extern asmlinkage int swsusp_arch_resume(void);
 
+extern int create_basic_memory_bitmaps(void);
+extern void free_basic_memory_bitmaps(void);
 extern unsigned int count_data_pages(void);
 
 /**
@@ -139,30 +150,12 @@ #define PMOPS_PREPARE	1
 #define PMOPS_ENTER	2
 #define PMOPS_FINISH	3
 
-/**
- *	The bitmap is used for tracing allocated swap pages
- *
- *	The entire bitmap consists of a number of bitmap_page
- *	structures linked with the help of the .next member.
- *	Thus each page can be allocated individually, so we only
- *	need to make 0-order memory allocations to create
- *	the bitmap.
- */
-
-#define BITMAP_PAGE_SIZE	(PAGE_SIZE - sizeof(void *))
-#define BITMAP_PAGE_CHUNKS	(BITMAP_PAGE_SIZE / sizeof(long))
-#define BITS_PER_CHUNK		(sizeof(long) * 8)
-#define BITMAP_PAGE_BITS	(BITMAP_PAGE_CHUNKS * BITS_PER_CHUNK)
-
-struct bitmap_page {
-	unsigned long		chunks[BITMAP_PAGE_CHUNKS];
-	struct bitmap_page	*next;
-};
+/* If unset, the snapshot device cannot be open. */
+extern atomic_t snapshot_device_available;
 
-extern void free_bitmap(struct bitmap_page *bitmap);
-extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
-extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap);
-extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
+extern sector_t alloc_swapdev_block(int swap);
+extern void free_all_swap_pages(int swap);
+extern int swsusp_swap_in_use(void);
 
 extern int swsusp_check(void);
 extern int swsusp_shrink_memory(void);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 6d566bf..0884193 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -8,7 +8,6 @@
 
 #undef DEBUG
 
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
@@ -25,10 +24,9 @@ #define FREEZER_USER_SPACE 1
 
 static inline int freezeable(struct task_struct * p)
 {
-	if ((p == current) || 
+	if ((p == current) ||
 	    (p->flags & PF_NOFREEZE) ||
-	    (p->exit_state == EXIT_ZOMBIE) ||
-	    (p->exit_state == EXIT_DEAD))
+	    (p->exit_state != 0))
 		return 0;
 	return 1;
 }
@@ -47,8 +45,10 @@ void refrigerator(void)
 	recalc_sigpending(); /* We sent fake signal, clean it up */
 	spin_unlock_irq(&current->sighand->siglock);
 
-	while (frozen(current)) {
-		current->state = TASK_UNINTERRUPTIBLE;
+	for (;;) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!frozen(current))
+			break;
 		schedule();
 	}
 	pr_debug("%s left refrigerator\n", current->comm);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index fc53ad0..b703977 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -14,13 +14,13 @@ #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/suspend.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/pm.h>
 #include <linux/device.h>
+#include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/console.h>
@@ -34,6 +34,10 @@ #include <asm/io.h>
 
 #include "power.h"
 
+static int swsusp_page_is_free(struct page *);
+static void swsusp_set_page_forbidden(struct page *);
+static void swsusp_unset_page_forbidden(struct page *);
+
 /* List of PBEs needed for restoring the pages that were allocated before
  * the suspend and included in the suspend image, but have also been
  * allocated by the "resume" kernel, so their contents cannot be written
@@ -67,15 +71,15 @@ static void *get_image_page(gfp_t gfp_ma
 
 	res = (void *)get_zeroed_page(gfp_mask);
 	if (safe_needed)
-		while (res && PageNosaveFree(virt_to_page(res))) {
+		while (res && swsusp_page_is_free(virt_to_page(res))) {
 			/* The page is unsafe, mark it for swsusp_free() */
-			SetPageNosave(virt_to_page(res));
+			swsusp_set_page_forbidden(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));
+		swsusp_set_page_forbidden(virt_to_page(res));
+		swsusp_set_page_free(virt_to_page(res));
 	}
 	return res;
 }
@@ -91,8 +95,8 @@ static struct page *alloc_image_page(gfp
 
 	page = alloc_page(gfp_mask);
 	if (page) {
-		SetPageNosave(page);
-		SetPageNosaveFree(page);
+		swsusp_set_page_forbidden(page);
+		swsusp_set_page_free(page);
 	}
 	return page;
 }
@@ -110,9 +114,9 @@ static inline void free_image_page(void 
 
 	page = virt_to_page(addr);
 
-	ClearPageNosave(page);
+	swsusp_unset_page_forbidden(page);
 	if (clear_nosave_free)
-		ClearPageNosaveFree(page);
+		swsusp_unset_page_free(page);
 
 	__free_page(page);
 }
@@ -224,11 +228,6 @@ static void chain_free(struct chain_allo
  *	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.
  */
 
 #define BM_END_OF_MAP	(~0UL)
@@ -443,15 +442,13 @@ static void memory_bm_free(struct memory
 }
 
 /**
- *	memory_bm_set_bit - set the bit in the bitmap @bm that corresponds
+ *	memory_bm_find_bit - find 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.
- *
- *	If the bit cannot be set, the function returns -EINVAL .
  */
 
-static int
-memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
+static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
+				void **addr, unsigned int *bit_nr)
 {
 	struct zone_bitmap *zone_bm;
 	struct bm_block *bb;
@@ -463,8 +460,8 @@ memory_bm_set_bit(struct memory_bitmap *
 		/* 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;
+
+			BUG_ON(!zone_bm);
 		}
 		bm->cur.zone_bm = zone_bm;
 	}
@@ -475,13 +472,40 @@ memory_bm_set_bit(struct memory_bitmap *
 
 	while (pfn >= bb->end_pfn) {
 		bb = bb->next;
-		if (unlikely(!bb))
-			return -EINVAL;
+
+		BUG_ON(!bb);
 	}
 	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;
+	*bit_nr = pfn % BM_BITS_PER_CHUNK;
+	*addr = bb->data + pfn / BM_BITS_PER_CHUNK;
+}
+
+static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+	void *addr;
+	unsigned int bit;
+
+	memory_bm_find_bit(bm, pfn, &addr, &bit);
+	set_bit(bit, addr);
+}
+
+static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+	void *addr;
+	unsigned int bit;
+
+	memory_bm_find_bit(bm, pfn, &addr, &bit);
+	clear_bit(bit, addr);
+}
+
+static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+	void *addr;
+	unsigned int bit;
+
+	memory_bm_find_bit(bm, pfn, &addr, &bit);
+	return test_bit(bit, addr);
 }
 
 /* Two auxiliary functions for memory_bm_next_pfn */
@@ -564,6 +588,199 @@ static unsigned long memory_bm_next_pfn(
 }
 
 /**
+ *	This structure represents a range of page frames the contents of which
+ *	should not be saved during the suspend.
+ */
+
+struct nosave_region {
+	struct list_head list;
+	unsigned long start_pfn;
+	unsigned long end_pfn;
+};
+
+static LIST_HEAD(nosave_regions);
+
+/**
+ *	register_nosave_region - register a range of page frames the contents
+ *	of which should not be saved during the suspend (to be used in the early
+ *	initialization code)
+ */
+
+void __init
+register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
+{
+	struct nosave_region *region;
+
+	if (start_pfn >= end_pfn)
+		return;
+
+	if (!list_empty(&nosave_regions)) {
+		/* Try to extend the previous region (they should be sorted) */
+		region = list_entry(nosave_regions.prev,
+					struct nosave_region, list);
+		if (region->end_pfn == start_pfn) {
+			region->end_pfn = end_pfn;
+			goto Report;
+		}
+	}
+	/* This allocation cannot fail */
+	region = alloc_bootmem_low(sizeof(struct nosave_region));
+	region->start_pfn = start_pfn;
+	region->end_pfn = end_pfn;
+	list_add_tail(&region->list, &nosave_regions);
+ Report:
+	printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
+		start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+}
+
+/*
+ * Set bits in this map correspond to the page frames the contents of which
+ * should not be saved during the suspend.
+ */
+static struct memory_bitmap *forbidden_pages_map;
+
+/* Set bits in this map correspond to free page frames. */
+static struct memory_bitmap *free_pages_map;
+
+/*
+ * Each page frame allocated for creating the image is marked by setting the
+ * corresponding bits in forbidden_pages_map and free_pages_map simultaneously
+ */
+
+void swsusp_set_page_free(struct page *page)
+{
+	if (free_pages_map)
+		memory_bm_set_bit(free_pages_map, page_to_pfn(page));
+}
+
+static int swsusp_page_is_free(struct page *page)
+{
+	return free_pages_map ?
+		memory_bm_test_bit(free_pages_map, page_to_pfn(page)) : 0;
+}
+
+void swsusp_unset_page_free(struct page *page)
+{
+	if (free_pages_map)
+		memory_bm_clear_bit(free_pages_map, page_to_pfn(page));
+}
+
+static void swsusp_set_page_forbidden(struct page *page)
+{
+	if (forbidden_pages_map)
+		memory_bm_set_bit(forbidden_pages_map, page_to_pfn(page));
+}
+
+int swsusp_page_is_forbidden(struct page *page)
+{
+	return forbidden_pages_map ?
+		memory_bm_test_bit(forbidden_pages_map, page_to_pfn(page)) : 0;
+}
+
+static void swsusp_unset_page_forbidden(struct page *page)
+{
+	if (forbidden_pages_map)
+		memory_bm_clear_bit(forbidden_pages_map, page_to_pfn(page));
+}
+
+/**
+ *	mark_nosave_pages - set bits corresponding to the page frames the
+ *	contents of which should not be saved in a given bitmap.
+ */
+
+static void mark_nosave_pages(struct memory_bitmap *bm)
+{
+	struct nosave_region *region;
+
+	if (list_empty(&nosave_regions))
+		return;
+
+	list_for_each_entry(region, &nosave_regions, list) {
+		unsigned long pfn;
+
+		printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
+				region->start_pfn << PAGE_SHIFT,
+				region->end_pfn << PAGE_SHIFT);
+
+		for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
+			memory_bm_set_bit(bm, pfn);
+	}
+}
+
+/**
+ *	create_basic_memory_bitmaps - create bitmaps needed for marking page
+ *	frames that should not be saved and free page frames.  The pointers
+ *	forbidden_pages_map and free_pages_map are only modified if everything
+ *	goes well, because we don't want the bits to be used before both bitmaps
+ *	are set up.
+ */
+
+int create_basic_memory_bitmaps(void)
+{
+	struct memory_bitmap *bm1, *bm2;
+	int error = 0;
+
+	BUG_ON(forbidden_pages_map || free_pages_map);
+
+	bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
+	if (!bm1)
+		return -ENOMEM;
+
+	error = memory_bm_create(bm1, GFP_KERNEL, PG_ANY);
+	if (error)
+		goto Free_first_object;
+
+	bm2 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
+	if (!bm2)
+		goto Free_first_bitmap;
+
+	error = memory_bm_create(bm2, GFP_KERNEL, PG_ANY);
+	if (error)
+		goto Free_second_object;
+
+	forbidden_pages_map = bm1;
+	free_pages_map = bm2;
+	mark_nosave_pages(forbidden_pages_map);
+
+	printk("swsusp: Basic memory bitmaps created\n");
+
+	return 0;
+
+ Free_second_object:
+	kfree(bm2);
+ Free_first_bitmap:
+ 	memory_bm_free(bm1, PG_UNSAFE_CLEAR);
+ Free_first_object:
+	kfree(bm1);
+	return -ENOMEM;
+}
+
+/**
+ *	free_basic_memory_bitmaps - free memory bitmaps allocated by
+ *	create_basic_memory_bitmaps().  The auxiliary pointers are necessary
+ *	so that the bitmaps themselves are not referred to while they are being
+ *	freed.
+ */
+
+void free_basic_memory_bitmaps(void)
+{
+	struct memory_bitmap *bm1, *bm2;
+
+	BUG_ON(!(forbidden_pages_map && free_pages_map));
+
+	bm1 = forbidden_pages_map;
+	bm2 = free_pages_map;
+	forbidden_pages_map = NULL;
+	free_pages_map = NULL;
+	memory_bm_free(bm1, PG_UNSAFE_CLEAR);
+	kfree(bm1);
+	memory_bm_free(bm2, PG_UNSAFE_CLEAR);
+	kfree(bm2);
+
+	printk("swsusp: Basic memory bitmaps freed\n");
+}
+
+/**
  *	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)
@@ -615,7 +832,8 @@ static struct page *saveable_highmem_pag
 
 	BUG_ON(!PageHighMem(page));
 
-	if (PageNosave(page) || PageReserved(page) || PageNosaveFree(page))
+	if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
+	    PageReserved(page))
 		return NULL;
 
 	return page;
@@ -651,17 +869,6 @@ static inline unsigned int count_highmem
 #endif /* CONFIG_HIGHMEM */
 
 /**
- *	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 non-highmem page should be included in
  *	the suspend image.
  *
@@ -681,7 +888,7 @@ static struct page *saveable_page(unsign
 
 	BUG_ON(PageHighMem(page));
 
-	if (PageNosave(page) || PageNosaveFree(page))
+	if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
 		return NULL;
 
 	if (PageReserved(page) && pfn_is_nosave(pfn))
@@ -821,9 +1028,10 @@ void swsusp_free(void)
 			if (pfn_valid(pfn)) {
 				struct page *page = pfn_to_page(pfn);
 
-				if (PageNosave(page) && PageNosaveFree(page)) {
-					ClearPageNosave(page);
-					ClearPageNosaveFree(page);
+				if (swsusp_page_is_forbidden(page) &&
+				    swsusp_page_is_free(page)) {
+					swsusp_unset_page_forbidden(page);
+					swsusp_unset_page_free(page);
 					__free_page(page);
 				}
 			}
@@ -1146,7 +1354,7 @@ static int mark_unsafe_pages(struct memo
 		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));
+				swsusp_unset_page_free(pfn_to_page(pfn));
 	}
 
 	/* Mark pages that correspond to the "original" pfns as "unsafe" */
@@ -1155,7 +1363,7 @@ static int mark_unsafe_pages(struct memo
 		pfn = memory_bm_next_pfn(bm);
 		if (likely(pfn != BM_END_OF_MAP)) {
 			if (likely(pfn_valid(pfn)))
-				SetPageNosaveFree(pfn_to_page(pfn));
+				swsusp_set_page_free(pfn_to_page(pfn));
 			else
 				return -EFAULT;
 		}
@@ -1321,14 +1529,14 @@ prepare_highmem_image(struct memory_bitm
 		struct page *page;
 
 		page = alloc_page(__GFP_HIGHMEM);
-		if (!PageNosaveFree(page)) {
+		if (!swsusp_page_is_free(page)) {
 			/* The page is "safe", set its bit the bitmap */
 			memory_bm_set_bit(bm, page_to_pfn(page));
 			safe_highmem_pages++;
 		}
 		/* Mark the page as allocated */
-		SetPageNosave(page);
-		SetPageNosaveFree(page);
+		swsusp_set_page_forbidden(page);
+		swsusp_set_page_free(page);
 	}
 	memory_bm_position_reset(bm);
 	safe_highmem_bm = bm;
@@ -1360,7 +1568,7 @@ get_highmem_page_buffer(struct page *pag
 	struct highmem_pbe *pbe;
 	void *kaddr;
 
-	if (PageNosave(page) && PageNosaveFree(page)) {
+	if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) {
 		/* We have allocated the "original" page frame and we can
 		 * use it directly to store the loaded page.
 		 */
@@ -1522,14 +1730,14 @@ prepare_image(struct memory_bitmap *new_
 			error = -ENOMEM;
 			goto Free;
 		}
-		if (!PageNosaveFree(virt_to_page(lp))) {
+		if (!swsusp_page_is_free(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));
+		swsusp_set_page_forbidden(virt_to_page(lp));
+		swsusp_set_page_free(virt_to_page(lp));
 		nr_pages--;
 	}
 	/* Free the reserved safe pages so that chain_alloc() can use them */
@@ -1558,7 +1766,7 @@ static void *get_buffer(struct memory_bi
 	if (PageHighMem(page))
 		return get_highmem_page_buffer(page, ca);
 
-	if (PageNosave(page) && PageNosaveFree(page))
+	if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page))
 		/* We have allocated the "original" page frame and we can
 		 * use it directly to store the loaded page.
 		 */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 3581f8f..b8b235c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
 #include <linux/version.h>
@@ -33,12 +32,14 @@ extern char resume_file[];
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
-static struct swsusp_header {
+struct swsusp_header {
 	char reserved[PAGE_SIZE - 20 - sizeof(sector_t)];
 	sector_t image;
 	char	orig_sig[10];
 	char	sig[10];
-} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
+} __attribute__((packed));
+
+static struct swsusp_header *swsusp_header;
 
 /*
  * General things
@@ -141,14 +142,14 @@ static int mark_swapfiles(sector_t start
 {
 	int error;
 
-	bio_read_page(swsusp_resume_block, &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;
+	bio_read_page(swsusp_resume_block, 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 = bio_write_page(swsusp_resume_block,
-					&swsusp_header, NULL);
+					swsusp_header, NULL);
 	} else {
 		printk(KERN_ERR "swsusp: Swap header not found!\n");
 		error = -ENODEV;
@@ -241,7 +242,6 @@ struct swap_map_page {
 struct swap_map_handle {
 	struct swap_map_page *cur;
 	sector_t cur_swap;
-	struct bitmap_page *bitmap;
 	unsigned int k;
 };
 
@@ -250,9 +250,6 @@ static void release_swap_writer(struct s
 	if (handle->cur)
 		free_page((unsigned long)handle->cur);
 	handle->cur = NULL;
-	if (handle->bitmap)
-		free_bitmap(handle->bitmap);
-	handle->bitmap = NULL;
 }
 
 static int get_swap_writer(struct swap_map_handle *handle)
@@ -260,12 +257,7 @@ static int get_swap_writer(struct swap_m
 	handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
 	if (!handle->cur)
 		return -ENOMEM;
-	handle->bitmap = alloc_bitmap(count_swap_pages(root_swap, 0));
-	if (!handle->bitmap) {
-		release_swap_writer(handle);
-		return -ENOMEM;
-	}
-	handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap);
+	handle->cur_swap = alloc_swapdev_block(root_swap);
 	if (!handle->cur_swap) {
 		release_swap_writer(handle);
 		return -ENOSPC;
@@ -282,7 +274,7 @@ static int swap_write_page(struct swap_m
 
 	if (!handle->cur)
 		return -EINVAL;
-	offset = alloc_swapdev_block(root_swap, handle->bitmap);
+	offset = alloc_swapdev_block(root_swap);
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
@@ -291,7 +283,7 @@ static int swap_write_page(struct swap_m
 		error = wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
-		offset = alloc_swapdev_block(root_swap, handle->bitmap);
+		offset = alloc_swapdev_block(root_swap);
 		if (!offset)
 			return -ENOSPC;
 		handle->cur->next_swap = offset;
@@ -428,7 +420,8 @@ int swsusp_write(void)
 		}
 	}
 	if (error)
-		free_all_swap_pages(root_swap, handle.bitmap);
+		free_all_swap_pages(root_swap);
+
 	release_swap_writer(&handle);
  out:
 	swsusp_close();
@@ -564,7 +557,7 @@ int swsusp_read(void)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(&handle, swsusp_header.image);
+	error = get_swap_reader(&handle, swsusp_header->image);
 	if (!error)
 		error = swap_read_page(&handle, header, NULL);
 	if (!error)
@@ -591,17 +584,17 @@ int swsusp_check(void)
 	resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
 	if (!IS_ERR(resume_bdev)) {
 		set_blocksize(resume_bdev, PAGE_SIZE);
-		memset(&swsusp_header, 0, sizeof(swsusp_header));
+		memset(swsusp_header, 0, sizeof(PAGE_SIZE));
 		error = bio_read_page(swsusp_resume_block,
-					&swsusp_header, NULL);
+					swsusp_header, NULL);
 		if (error)
 			return error;
 
-		if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
-			memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+		if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
+			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 			/* Reset swap signature now */
 			error = bio_write_page(swsusp_resume_block,
-						&swsusp_header, NULL);
+						swsusp_header, NULL);
 		} else {
 			return -EINVAL;
 		}
@@ -632,3 +625,13 @@ void swsusp_close(void)
 
 	blkdev_put(resume_bdev);
 }
+
+static int swsusp_header_init(void)
+{
+	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
+	if (!swsusp_header)
+		panic("Could not allocate memory for swsusp_header\n");
+	return 0;
+}
+
+core_initcall(swsusp_header_init);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 1753708..5da304c 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -50,6 +50,7 @@ #include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/highmem.h>
 #include <linux/time.h>
+#include <linux/rbtree.h>
 
 #include "power.h"
 
@@ -74,72 +75,69 @@ #endif
 /**
  *	The following functions are used for tracing the allocated
  *	swap pages, so that they can be freed in case of an error.
- *
- *	The functions operate on a linked bitmap structure defined
- *	in power.h
  */
 
-void free_bitmap(struct bitmap_page *bitmap)
-{
-	struct bitmap_page *bp;
+struct swsusp_extent {
+	struct rb_node node;
+	unsigned long start;
+	unsigned long end;
+};
 
-	while (bitmap) {
-		bp = bitmap->next;
-		free_page((unsigned long)bitmap);
-		bitmap = bp;
-	}
-}
+static struct rb_root swsusp_extents = RB_ROOT;
 
-struct bitmap_page *alloc_bitmap(unsigned int nr_bits)
+static int swsusp_extents_insert(unsigned long swap_offset)
 {
-	struct bitmap_page *bitmap, *bp;
-	unsigned int n;
-
-	if (!nr_bits)
-		return NULL;
-
-	bitmap = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
-	bp = bitmap;
-	for (n = BITMAP_PAGE_BITS; n < nr_bits; n += BITMAP_PAGE_BITS) {
-		bp->next = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
-		bp = bp->next;
-		if (!bp) {
-			free_bitmap(bitmap);
-			return NULL;
+	struct rb_node **new = &(swsusp_extents.rb_node);
+	struct rb_node *parent = NULL;
+	struct swsusp_extent *ext;
+
+	/* Figure out where to put the new node */
+	while (*new) {
+		ext = container_of(*new, struct swsusp_extent, node);
+		parent = *new;
+		if (swap_offset < ext->start) {
+			/* Try to merge */
+			if (swap_offset == ext->start - 1) {
+				ext->start--;
+				return 0;
+			}
+			new = &((*new)->rb_left);
+		} else if (swap_offset > ext->end) {
+			/* Try to merge */
+			if (swap_offset == ext->end + 1) {
+				ext->end++;
+				return 0;
+			}
+			new = &((*new)->rb_right);
+		} else {
+			/* It already is in the tree */
+			return -EINVAL;
 		}
 	}
-	return bitmap;
-}
-
-static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit)
-{
-	unsigned int n;
-
-	n = BITMAP_PAGE_BITS;
-	while (bitmap && n <= bit) {
-		n += BITMAP_PAGE_BITS;
-		bitmap = bitmap->next;
-	}
-	if (!bitmap)
-		return -EINVAL;
-	n -= BITMAP_PAGE_BITS;
-	bit -= n;
-	n = 0;
-	while (bit >= BITS_PER_CHUNK) {
-		bit -= BITS_PER_CHUNK;
-		n++;
-	}
-	bitmap->chunks[n] |= (1UL << bit);
+	/* Add the new node and rebalance the tree. */
+	ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	ext->start = swap_offset;
+	ext->end = swap_offset;
+	rb_link_node(&ext->node, parent, new);
+	rb_insert_color(&ext->node, &swsusp_extents);
 	return 0;
 }
 
-sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
+/**
+ *	alloc_swapdev_block - allocate a swap page and register that it has
+ *	been allocated, so that it can be freed in case of an error.
+ */
+
+sector_t alloc_swapdev_block(int swap)
 {
 	unsigned long offset;
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (bitmap_set(bitmap, offset))
+		if (swsusp_extents_insert(offset))
 			swap_free(swp_entry(swap, offset));
 		else
 			return swapdev_block(swap, offset);
@@ -147,23 +145,34 @@ sector_t alloc_swapdev_block(int swap, s
 	return 0;
 }
 
-void free_all_swap_pages(int swap, struct bitmap_page *bitmap)
+/**
+ *	free_all_swap_pages - free swap pages allocated for saving image data.
+ *	It also frees the extents used to register which swap entres had been
+ *	allocated.
+ */
+
+void free_all_swap_pages(int swap)
 {
-	unsigned int bit, n;
-	unsigned long test;
-
-	bit = 0;
-	while (bitmap) {
-		for (n = 0; n < BITMAP_PAGE_CHUNKS; n++)
-			for (test = 1UL; test; test <<= 1) {
-				if (bitmap->chunks[n] & test)
-					swap_free(swp_entry(swap, bit));
-				bit++;
-			}
-		bitmap = bitmap->next;
+	struct rb_node *node;
+
+	while ((node = swsusp_extents.rb_node)) {
+		struct swsusp_extent *ext;
+		unsigned long offset;
+
+		ext = container_of(node, struct swsusp_extent, node);
+		rb_erase(node, &swsusp_extents);
+		for (offset = ext->start; offset <= ext->end; offset++)
+			swap_free(swp_entry(swap, offset));
+
+		kfree(ext);
 	}
 }
 
+int swsusp_swap_in_use(void)
+{
+	return (swsusp_extents.rb_node != NULL);
+}
+
 /**
  *	swsusp_show_speed - print the time elapsed between two events represented by
  *	@start and @stop
@@ -224,7 +233,7 @@ int swsusp_shrink_memory(void)
 		long size, highmem_size;
 
 		highmem_size = count_highmem_pages();
-		size = count_data_pages() + PAGES_FOR_IO;
+		size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
 		tmp = size;
 		size += highmem_size;
 		for_each_zone (zone)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 7cf6713..040560d 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -33,25 +33,29 @@ #define SNAPSHOT_MINOR	231
 static struct snapshot_data {
 	struct snapshot_handle handle;
 	int swap;
-	struct bitmap_page *bitmap;
 	int mode;
 	char frozen;
 	char ready;
 	char platform_suspend;
 } snapshot_state;
 
-static atomic_t device_available = ATOMIC_INIT(1);
+atomic_t snapshot_device_available = ATOMIC_INIT(1);
 
 static int snapshot_open(struct inode *inode, struct file *filp)
 {
 	struct snapshot_data *data;
 
-	if (!atomic_add_unless(&device_available, -1, 0))
+	if (!atomic_add_unless(&snapshot_device_available, -1, 0))
 		return -EBUSY;
 
-	if ((filp->f_flags & O_ACCMODE) == O_RDWR)
+	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
+		atomic_inc(&snapshot_device_available);
 		return -ENOSYS;
-
+	}
+	if(create_basic_memory_bitmaps()) {
+		atomic_inc(&snapshot_device_available);
+		return -ENOMEM;
+	}
 	nonseekable_open(inode, filp);
 	data = &snapshot_state;
 	filp->private_data = data;
@@ -64,7 +68,6 @@ static int snapshot_open(struct inode *i
 		data->swap = -1;
 		data->mode = O_WRONLY;
 	}
-	data->bitmap = NULL;
 	data->frozen = 0;
 	data->ready = 0;
 	data->platform_suspend = 0;
@@ -77,16 +80,15 @@ static int snapshot_release(struct inode
 	struct snapshot_data *data;
 
 	swsusp_free();
+	free_basic_memory_bitmaps();
 	data = filp->private_data;
-	free_all_swap_pages(data->swap, data->bitmap);
-	free_bitmap(data->bitmap);
+	free_all_swap_pages(data->swap);
 	if (data->frozen) {
 		mutex_lock(&pm_mutex);
 		thaw_processes();
-		enable_nonboot_cpus();
 		mutex_unlock(&pm_mutex);
 	}
-	atomic_inc(&device_available);
+	atomic_inc(&snapshot_device_available);
 	return 0;
 }
 
@@ -294,14 +296,7 @@ static int snapshot_ioctl(struct inode *
 			error = -ENODEV;
 			break;
 		}
-		if (!data->bitmap) {
-			data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0));
-			if (!data->bitmap) {
-				error = -ENOMEM;
-				break;
-			}
-		}
-		offset = alloc_swapdev_block(data->swap, data->bitmap);
+		offset = alloc_swapdev_block(data->swap);
 		if (offset) {
 			offset <<= PAGE_SHIFT;
 			error = put_user(offset, (sector_t __user *)arg);
@@ -315,13 +310,11 @@ static int snapshot_ioctl(struct inode *
 			error = -ENODEV;
 			break;
 		}
-		free_all_swap_pages(data->swap, data->bitmap);
-		free_bitmap(data->bitmap);
-		data->bitmap = NULL;
+		free_all_swap_pages(data->swap);
 		break;
 
 	case SNAPSHOT_SET_SWAP_FILE:
-		if (!data->bitmap) {
+		if (!swsusp_swap_in_use()) {
 			/*
 			 * User space encodes device types as two-byte values,
 			 * so we need to recode them
@@ -420,7 +413,7 @@ static int snapshot_ioctl(struct inode *
 		break;
 
 	case SNAPSHOT_SET_SWAP_AREA:
-		if (data->bitmap) {
+		if (swsusp_swap_in_use()) {
 			error = -EPERM;
 		} else {
 			struct resume_swap_area swap_area;
diff --git a/kernel/printk.c b/kernel/printk.c
index 4b47e59..0bbdeac 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -20,7 +20,6 @@ #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
-#include <linux/smp_lock.h>
 #include <linux/console.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -931,8 +930,16 @@ void register_console(struct console *co
 {
 	int i;
 	unsigned long flags;
+	struct console *bootconsole = NULL;
 
-	if (preferred_console < 0)
+	if (console_drivers) {
+		if (console->flags & CON_BOOT)
+			return;
+		if (console_drivers->flags & CON_BOOT)
+			bootconsole = console_drivers;
+	}
+
+	if (preferred_console < 0 || bootconsole || !console_drivers)
 		preferred_console = selected_console;
 
 	/*
@@ -978,8 +985,11 @@ void register_console(struct console *co
 	if (!(console->flags & CON_ENABLED))
 		return;
 
-	if (console_drivers && (console_drivers->flags & CON_BOOT)) {
-		unregister_console(console_drivers);
+	if (bootconsole) {
+		printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n",
+		       bootconsole->name, bootconsole->index,
+		       console->name, console->index);
+		unregister_console(bootconsole);
 		console->flags &= ~CON_PRINTBUFFER;
 	}
 
@@ -1030,16 +1040,11 @@ int unregister_console(struct console *c
 		}
 	}
 
-	/* If last console is removed, we re-enable picking the first
-	 * one that gets registered. Without that, pmac early boot console
-	 * would prevent fbcon from taking over.
-	 *
+	/*
 	 * If this isn't the last console and it has CON_CONSDEV set, we
 	 * need to set it on the next preferred console.
 	 */
-	if (console_drivers == NULL)
-		preferred_console = selected_console;
-	else if (console->flags & CON_CONSDEV)
+	if (console_drivers != NULL && console->flags & CON_CONSDEV)
 		console_drivers->flags |= CON_CONSDEV;
 
 	release_console_sem();
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index bcd14e8..55ba82a 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -502,10 +502,6 @@ static struct rcu_torture_ops sched_ops 
 	.name = "sched"
 };
 
-static struct rcu_torture_ops *torture_ops[] =
-	{ &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
  * for that pointed to by rcu_torture_current, freeing the old structure
@@ -534,7 +530,7 @@ rcu_torture_writer(void *arg)
 		rp->rtort_mbtest = 1;
 		rcu_assign_pointer(rcu_torture_current, rp);
 		smp_wmb();
-		if (old_rp != NULL) {
+		if (old_rp) {
 			i = old_rp->rtort_pipe_count;
 			if (i > RCU_TORTURE_PIPE_LEN)
 				i = RCU_TORTURE_PIPE_LEN;
@@ -685,7 +681,7 @@ rcu_torture_printk(char *page)
 			       atomic_read(&rcu_torture_wcount[i]));
 	}
 	cnt += sprintf(&page[cnt], "\n");
-	if (cur_ops->stats != NULL)
+	if (cur_ops->stats)
 		cnt += cur_ops->stats(&page[cnt]);
 	return cnt;
 }
@@ -749,13 +745,13 @@ static void rcu_torture_shuffle_tasks(vo
 
 	set_cpus_allowed(current, tmp_mask);
 
-	if (reader_tasks != NULL) {
+	if (reader_tasks) {
 		for (i = 0; i < nrealreaders; i++)
 			if (reader_tasks[i])
 				set_cpus_allowed(reader_tasks[i], tmp_mask);
 	}
 
-	if (fakewriter_tasks != NULL) {
+	if (fakewriter_tasks) {
 		for (i = 0; i < nfakewriters; i++)
 			if (fakewriter_tasks[i])
 				set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
@@ -808,21 +804,21 @@ rcu_torture_cleanup(void)
 	int i;
 
 	fullstop = 1;
-	if (shuffler_task != NULL) {
+	if (shuffler_task) {
 		VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
 		kthread_stop(shuffler_task);
 	}
 	shuffler_task = NULL;
 
-	if (writer_task != NULL) {
+	if (writer_task) {
 		VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
 		kthread_stop(writer_task);
 	}
 	writer_task = NULL;
 
-	if (reader_tasks != NULL) {
+	if (reader_tasks) {
 		for (i = 0; i < nrealreaders; i++) {
-			if (reader_tasks[i] != NULL) {
+			if (reader_tasks[i]) {
 				VERBOSE_PRINTK_STRING(
 					"Stopping rcu_torture_reader task");
 				kthread_stop(reader_tasks[i]);
@@ -834,9 +830,9 @@ rcu_torture_cleanup(void)
 	}
 	rcu_torture_current = NULL;
 
-	if (fakewriter_tasks != NULL) {
+	if (fakewriter_tasks) {
 		for (i = 0; i < nfakewriters; i++) {
-			if (fakewriter_tasks[i] != NULL) {
+			if (fakewriter_tasks[i]) {
 				VERBOSE_PRINTK_STRING(
 					"Stopping rcu_torture_fakewriter task");
 				kthread_stop(fakewriter_tasks[i]);
@@ -847,7 +843,7 @@ rcu_torture_cleanup(void)
 		fakewriter_tasks = NULL;
 	}
 
-	if (stats_task != NULL) {
+	if (stats_task) {
 		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
 		kthread_stop(stats_task);
 	}
@@ -858,7 +854,7 @@ rcu_torture_cleanup(void)
 
 	rcu_torture_stats_print();  /* -After- the stats thread is stopped! */
 
-	if (cur_ops->cleanup != NULL)
+	if (cur_ops->cleanup)
 		cur_ops->cleanup();
 	if (atomic_read(&n_rcu_torture_error))
 		rcu_torture_print_module_parms("End of test: FAILURE");
@@ -866,27 +862,28 @@ rcu_torture_cleanup(void)
 		rcu_torture_print_module_parms("End of test: SUCCESS");
 }
 
-static int
+static int __init
 rcu_torture_init(void)
 {
 	int i;
 	int cpu;
 	int firsterr = 0;
+	static struct rcu_torture_ops *torture_ops[] =
+		{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
+		  &srcu_ops, &sched_ops, };
 
 	/* Process args and tell the world that the torturer is on the job. */
-
-	for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) {
+	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
 		cur_ops = torture_ops[i];
-		if (strcmp(torture_type, cur_ops->name) == 0) {
+		if (strcmp(torture_type, cur_ops->name) == 0)
 			break;
-		}
 	}
-	if (cur_ops == NULL) {
+	if (i == ARRAY_SIZE(torture_ops)) {
 		printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
 		       torture_type);
 		return (-EINVAL);
 	}
-	if (cur_ops->init != NULL)
+	if (cur_ops->init)
 		cur_ops->init(); /* no "goto unwind" prior to this point!!! */
 
 	if (nreaders >= 0)
@@ -899,7 +896,7 @@ rcu_torture_init(void)
 	/* Set up the freelist. */
 
 	INIT_LIST_HEAD(&rcu_torture_freelist);
-	for (i = 0; i < sizeof(rcu_tortures) / sizeof(rcu_tortures[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
 		rcu_tortures[i].rtort_mbtest = 0;
 		list_add_tail(&rcu_tortures[i].rtort_free,
 			      &rcu_torture_freelist);
diff --git a/kernel/resource.c b/kernel/resource.c
index bdb55a3..9bd14fd 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -213,27 +213,6 @@ 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;
-
-	write_lock(&resource_lock);
-	conflict = __request_resource(root, new);
-	write_unlock(&resource_lock);
-	return conflict;
-}
-
-EXPORT_SYMBOL(____request_resource);
-
-/**
  * release_resource - release a previously reserved resource
  * @old: resource pointer
  */
diff --git a/kernel/rwsem.c b/kernel/rwsem.c
index 291ded5..9a87886 100644
--- a/kernel/rwsem.c
+++ b/kernel/rwsem.c
@@ -60,7 +60,7 @@ int down_write_trylock(struct rw_semapho
 	int ret = __down_write_trylock(sem);
 
 	if (ret == 1)
-		rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
+		rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
 	return ret;
 }
 
diff --git a/kernel/sched.c b/kernel/sched.c
index b9a6837..a3a0408 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -52,8 +52,9 @@ #include <linux/times.h>
 #include <linux/tsacct_kern.h>
 #include <linux/kprobes.h>
 #include <linux/delayacct.h>
-#include <asm/tlb.h>
+#include <linux/reciprocal_div.h>
 
+#include <asm/tlb.h>
 #include <asm/unistd.h>
 
 /*
@@ -168,7 +169,7 @@ #define INTERACTIVE_SLEEP(p) \
 		(MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1))
 
 #define TASK_PREEMPTS_CURR(p, rq) \
-	((p)->prio < (rq)->curr->prio)
+	(((p)->prio < (rq)->curr->prio) && ((p)->array == (rq)->active))
 
 #define SCALE_PRIO(x, prio) \
 	max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
@@ -181,6 +182,27 @@ static unsigned int static_prio_timeslic
 		return SCALE_PRIO(DEF_TIMESLICE, static_prio);
 }
 
+#ifdef CONFIG_SMP
+/*
+ * Divide a load by a sched group cpu_power : (load / sg->__cpu_power)
+ * Since cpu_power is a 'constant', we can use a reciprocal divide.
+ */
+static inline u32 sg_div_cpu_power(const struct sched_group *sg, u32 load)
+{
+	return reciprocal_divide(load, sg->reciprocal_cpu_power);
+}
+
+/*
+ * Each time a sched group cpu_power is changed,
+ * we must compute its reciprocal value
+ */
+static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val)
+{
+	sg->__cpu_power += val;
+	sg->reciprocal_cpu_power = reciprocal_value(sg->__cpu_power);
+}
+#endif
+
 /*
  * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
  * to time slice values: [800ms ... 100ms ... 5ms]
@@ -223,6 +245,10 @@ struct rq {
 	unsigned long raw_weighted_load;
 #ifdef CONFIG_SMP
 	unsigned long cpu_load[3];
+	unsigned char idle_at_tick;
+#ifdef CONFIG_NO_HZ
+	unsigned char in_nohz_recently;
+#endif
 #endif
 	unsigned long long nr_switches;
 
@@ -278,7 +304,7 @@ #endif
 	struct lock_class_key rq_lock_key;
 };
 
-static DEFINE_PER_CPU(struct rq, runqueues);
+static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
 
 static inline int cpu_of(struct rq *rq)
 {
@@ -1049,6 +1075,17 @@ static void resched_task(struct task_str
 	if (!tsk_is_polling(p))
 		smp_send_reschedule(cpu);
 }
+
+static void resched_cpu(int cpu)
+{
+	struct rq *rq = cpu_rq(cpu);
+	unsigned long flags;
+
+	if (!spin_trylock_irqsave(&rq->lock, flags))
+		return;
+	resched_task(cpu_curr(cpu));
+	spin_unlock_irqrestore(&rq->lock, flags);
+}
 #else
 static inline void resched_task(struct task_struct *p)
 {
@@ -1241,7 +1278,8 @@ find_idlest_group(struct sched_domain *s
 		}
 
 		/* Adjust by relative CPU power of the group */
-		avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+		avg_load = sg_div_cpu_power(group,
+				avg_load * SCHED_LOAD_SCALE);
 
 		if (local_group) {
 			this_load = avg_load;
@@ -1368,7 +1406,16 @@ static int wake_idle(int cpu, struct tas
 	struct sched_domain *sd;
 	int i;
 
-	if (idle_cpu(cpu))
+	/*
+	 * If it is idle, then it is the best cpu to run this task.
+	 *
+	 * This cpu is also the best, if it has more than one task already.
+	 * Siblings must be also busy(in most cases) as they didn't already
+	 * pickup the extra load from this cpu and hence we need not check
+	 * sibling runqueue info. This will avoid the checks and cache miss
+	 * penalities associated with that.
+	 */
+	if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1)
 		return cpu;
 
 	for_each_domain(cpu, sd) {
@@ -2352,12 +2399,13 @@ #endif
 		}
 
 		total_load += avg_load;
-		total_pwr += group->cpu_power;
+		total_pwr += group->__cpu_power;
 
 		/* Adjust by relative CPU power of the group */
-		avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+		avg_load = sg_div_cpu_power(group,
+				avg_load * SCHED_LOAD_SCALE);
 
-		group_capacity = group->cpu_power / SCHED_LOAD_SCALE;
+		group_capacity = group->__cpu_power / SCHED_LOAD_SCALE;
 
 		if (local_group) {
 			this_load = avg_load;
@@ -2468,8 +2516,8 @@ #endif
 	max_pull = min(max_load - avg_load, max_load - busiest_load_per_task);
 
 	/* How much load to actually move to equalise the imbalance */
-	*imbalance = min(max_pull * busiest->cpu_power,
-				(avg_load - this_load) * this->cpu_power)
+	*imbalance = min(max_pull * busiest->__cpu_power,
+				(avg_load - this_load) * this->__cpu_power)
 			/ SCHED_LOAD_SCALE;
 
 	/*
@@ -2503,28 +2551,29 @@ small_imbalance:
 		 * moving them.
 		 */
 
-		pwr_now += busiest->cpu_power *
-			min(busiest_load_per_task, max_load);
-		pwr_now += this->cpu_power *
-			min(this_load_per_task, this_load);
+		pwr_now += busiest->__cpu_power *
+				min(busiest_load_per_task, max_load);
+		pwr_now += this->__cpu_power *
+				min(this_load_per_task, this_load);
 		pwr_now /= SCHED_LOAD_SCALE;
 
 		/* Amount of load we'd subtract */
-		tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
-			busiest->cpu_power;
+		tmp = sg_div_cpu_power(busiest,
+				busiest_load_per_task * SCHED_LOAD_SCALE);
 		if (max_load > tmp)
-			pwr_move += busiest->cpu_power *
+			pwr_move += busiest->__cpu_power *
 				min(busiest_load_per_task, max_load - tmp);
 
 		/* Amount of load we'd add */
-		if (max_load * busiest->cpu_power <
+		if (max_load * busiest->__cpu_power <
 				busiest_load_per_task * SCHED_LOAD_SCALE)
-			tmp = max_load * busiest->cpu_power / this->cpu_power;
+			tmp = sg_div_cpu_power(this,
+					max_load * busiest->__cpu_power);
 		else
-			tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
-				this->cpu_power;
-		pwr_move += this->cpu_power *
-			min(this_load_per_task, this_load + tmp);
+			tmp = sg_div_cpu_power(this,
+				busiest_load_per_task * SCHED_LOAD_SCALE);
+		pwr_move += this->__cpu_power *
+				min(this_load_per_task, this_load + tmp);
 		pwr_move /= SCHED_LOAD_SCALE;
 
 		/* Move if we gain throughput */
@@ -2657,6 +2706,12 @@ redo:
 		double_rq_unlock(this_rq, busiest);
 		local_irq_restore(flags);
 
+		/*
+		 * some other cpu did the load balance for us.
+		 */
+		if (nr_moved && this_cpu != smp_processor_id())
+			resched_cpu(this_cpu);
+
 		/* All tasks on this runqueue were pinned by CPU affinity */
 		if (unlikely(all_pinned)) {
 			cpu_clear(cpu_of(busiest), cpus);
@@ -2927,32 +2982,98 @@ static void update_load(struct rq *this_
 	}
 }
 
+#ifdef CONFIG_NO_HZ
+static struct {
+	atomic_t load_balancer;
+	cpumask_t  cpu_mask;
+} nohz ____cacheline_aligned = {
+	.load_balancer = ATOMIC_INIT(-1),
+	.cpu_mask = CPU_MASK_NONE,
+};
+
 /*
- * run_rebalance_domains is triggered when needed from the scheduler tick.
+ * This routine will try to nominate the ilb (idle load balancing)
+ * owner among the cpus whose ticks are stopped. ilb owner will do the idle
+ * load balancing on behalf of all those cpus. If all the cpus in the system
+ * go into this tickless mode, then there will be no ilb owner (as there is
+ * no need for one) and all the cpus will sleep till the next wakeup event
+ * arrives...
  *
+ * For the ilb owner, tick is not stopped. And this tick will be used
+ * for idle load balancing. ilb owner will still be part of
+ * nohz.cpu_mask..
+ *
+ * While stopping the tick, this cpu will become the ilb owner if there
+ * is no other owner. And will be the owner till that cpu becomes busy
+ * or if all cpus in the system stop their ticks at which point
+ * there is no need for ilb owner.
+ *
+ * When the ilb owner becomes busy, it nominates another owner, during the
+ * next busy scheduler_tick()
+ */
+int select_nohz_load_balancer(int stop_tick)
+{
+	int cpu = smp_processor_id();
+
+	if (stop_tick) {
+		cpu_set(cpu, nohz.cpu_mask);
+		cpu_rq(cpu)->in_nohz_recently = 1;
+
+		/*
+		 * If we are going offline and still the leader, give up!
+		 */
+		if (cpu_is_offline(cpu) &&
+		    atomic_read(&nohz.load_balancer) == cpu) {
+			if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+				BUG();
+			return 0;
+		}
+
+		/* time for ilb owner also to sleep */
+		if (cpus_weight(nohz.cpu_mask) == num_online_cpus()) {
+			if (atomic_read(&nohz.load_balancer) == cpu)
+				atomic_set(&nohz.load_balancer, -1);
+			return 0;
+		}
+
+		if (atomic_read(&nohz.load_balancer) == -1) {
+			/* make me the ilb owner */
+			if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1)
+				return 1;
+		} else if (atomic_read(&nohz.load_balancer) == cpu)
+			return 1;
+	} else {
+		if (!cpu_isset(cpu, nohz.cpu_mask))
+			return 0;
+
+		cpu_clear(cpu, nohz.cpu_mask);
+
+		if (atomic_read(&nohz.load_balancer) == cpu)
+			if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+				BUG();
+	}
+	return 0;
+}
+#endif
+
+static DEFINE_SPINLOCK(balancing);
+
+/*
  * It checks each scheduling domain to see if it is due to be balanced,
  * and initiates a balancing operation if so.
  *
  * Balancing parameters are set up in arch_init_sched_domains.
  */
-static DEFINE_SPINLOCK(balancing);
-
-static void run_rebalance_domains(struct softirq_action *h)
+static inline void rebalance_domains(int cpu, enum idle_type idle)
 {
-	int this_cpu = smp_processor_id(), balance = 1;
-	struct rq *this_rq = cpu_rq(this_cpu);
+	int balance = 1;
+	struct rq *rq = cpu_rq(cpu);
 	unsigned long interval;
 	struct sched_domain *sd;
-	/*
-	 * We are idle if there are no processes running. This
-	 * is valid even if we are the idle process (SMT).
-	 */
-	enum idle_type idle = !this_rq->nr_running ?
-				SCHED_IDLE : NOT_IDLE;
-	/* Earliest time when we have to call run_rebalance_domains again */
+	/* Earliest time when we have to do rebalance again */
 	unsigned long next_balance = jiffies + 60*HZ;
 
-	for_each_domain(this_cpu, sd) {
+	for_each_domain(cpu, sd) {
 		if (!(sd->flags & SD_LOAD_BALANCE))
 			continue;
 
@@ -2971,7 +3092,7 @@ static void run_rebalance_domains(struct
 		}
 
 		if (time_after_eq(jiffies, sd->last_balance + interval)) {
-			if (load_balance(this_cpu, this_rq, sd, idle, &balance)) {
+			if (load_balance(cpu, rq, sd, idle, &balance)) {
 				/*
 				 * We've pulled tasks over so either we're no
 				 * longer idle, or one of our SMT siblings is
@@ -2995,7 +3116,114 @@ out:
 		if (!balance)
 			break;
 	}
-	this_rq->next_balance = next_balance;
+	rq->next_balance = next_balance;
+}
+
+/*
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
+ * In CONFIG_NO_HZ case, the idle load balance owner will do the
+ * rebalancing for all the cpus for whom scheduler ticks are stopped.
+ */
+static void run_rebalance_domains(struct softirq_action *h)
+{
+	int local_cpu = smp_processor_id();
+	struct rq *local_rq = cpu_rq(local_cpu);
+	enum idle_type idle = local_rq->idle_at_tick ? SCHED_IDLE : NOT_IDLE;
+
+	rebalance_domains(local_cpu, idle);
+
+#ifdef CONFIG_NO_HZ
+	/*
+	 * If this cpu is the owner for idle load balancing, then do the
+	 * balancing on behalf of the other idle cpus whose ticks are
+	 * stopped.
+	 */
+	if (local_rq->idle_at_tick &&
+	    atomic_read(&nohz.load_balancer) == local_cpu) {
+		cpumask_t cpus = nohz.cpu_mask;
+		struct rq *rq;
+		int balance_cpu;
+
+		cpu_clear(local_cpu, cpus);
+		for_each_cpu_mask(balance_cpu, cpus) {
+			/*
+			 * If this cpu gets work to do, stop the load balancing
+			 * work being done for other cpus. Next load
+			 * balancing owner will pick it up.
+			 */
+			if (need_resched())
+				break;
+
+			rebalance_domains(balance_cpu, SCHED_IDLE);
+
+			rq = cpu_rq(balance_cpu);
+			if (time_after(local_rq->next_balance, rq->next_balance))
+				local_rq->next_balance = rq->next_balance;
+		}
+	}
+#endif
+}
+
+/*
+ * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
+ *
+ * In case of CONFIG_NO_HZ, this is the place where we nominate a new
+ * idle load balancing owner or decide to stop the periodic load balancing,
+ * if the whole system is idle.
+ */
+static inline void trigger_load_balance(int cpu)
+{
+	struct rq *rq = cpu_rq(cpu);
+#ifdef CONFIG_NO_HZ
+	/*
+	 * If we were in the nohz mode recently and busy at the current
+	 * scheduler tick, then check if we need to nominate new idle
+	 * load balancer.
+	 */
+	if (rq->in_nohz_recently && !rq->idle_at_tick) {
+		rq->in_nohz_recently = 0;
+
+		if (atomic_read(&nohz.load_balancer) == cpu) {
+			cpu_clear(cpu, nohz.cpu_mask);
+			atomic_set(&nohz.load_balancer, -1);
+		}
+
+		if (atomic_read(&nohz.load_balancer) == -1) {
+			/*
+			 * simple selection for now: Nominate the
+			 * first cpu in the nohz list to be the next
+			 * ilb owner.
+			 *
+			 * TBD: Traverse the sched domains and nominate
+			 * the nearest cpu in the nohz.cpu_mask.
+			 */
+			int ilb = first_cpu(nohz.cpu_mask);
+
+			if (ilb != NR_CPUS)
+				resched_cpu(ilb);
+		}
+	}
+
+	/*
+	 * If this cpu is idle and doing idle load balancing for all the
+	 * cpus with ticks stopped, is it time for that to stop?
+	 */
+	if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu &&
+	    cpus_weight(nohz.cpu_mask) == num_online_cpus()) {
+		resched_cpu(cpu);
+		return;
+	}
+
+	/*
+	 * If this cpu is idle and the idle load balancing is done by
+	 * someone else, then no need raise the SCHED_SOFTIRQ
+	 */
+	if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu &&
+	    cpu_isset(cpu, nohz.cpu_mask))
+		return;
+#endif
+	if (time_after_eq(jiffies, rq->next_balance))
+		raise_softirq(SCHED_SOFTIRQ);
 }
 #else
 /*
@@ -3218,16 +3446,17 @@ void scheduler_tick(void)
 	unsigned long long now = sched_clock();
 	struct task_struct *p = current;
 	int cpu = smp_processor_id();
+	int idle_at_tick = idle_cpu(cpu);
 	struct rq *rq = cpu_rq(cpu);
 
 	update_cpu_clock(p, rq, now);
 
-	if (p != rq->idle)
+	if (!idle_at_tick)
 		task_running_tick(rq, p);
 #ifdef CONFIG_SMP
 	update_load(rq);
-	if (time_after_eq(jiffies, rq->next_balance))
-		raise_softirq(SCHED_SOFTIRQ);
+	rq->idle_at_tick = idle_at_tick;
+	trigger_load_balance(cpu);
 #endif
 }
 
@@ -3847,13 +4076,13 @@ void rt_mutex_setprio(struct task_struct
 	struct prio_array *array;
 	unsigned long flags;
 	struct rq *rq;
-	int oldprio;
+	int delta;
 
 	BUG_ON(prio < 0 || prio > MAX_PRIO);
 
 	rq = task_rq_lock(p, &flags);
 
-	oldprio = p->prio;
+	delta = prio - p->prio;
 	array = p->array;
 	if (array)
 		dequeue_task(p, array);
@@ -3869,13 +4098,11 @@ void rt_mutex_setprio(struct task_struct
 		enqueue_task(p, array);
 		/*
 		 * Reschedule if we are currently running on this runqueue and
-		 * our priority decreased, or if we are not currently running on
-		 * this runqueue and our priority is higher than the current's
+		 * our priority decreased, or if our priority became higher
+		 * than the current's.
 		 */
-		if (task_running(rq, p)) {
-			if (p->prio > oldprio)
-				resched_task(rq->curr);
-		} else if (TASK_PREEMPTS_CURR(p, rq))
+		if (TASK_PREEMPTS_CURR(p, rq) ||
+				(delta > 0 && task_running(rq, p)))
 			resched_task(rq->curr);
 	}
 	task_rq_unlock(rq, &flags);
@@ -3923,10 +4150,12 @@ void set_user_nice(struct task_struct *p
 		enqueue_task(p, array);
 		inc_raw_weighted_load(rq, p);
 		/*
-		 * If the task increased its priority or is running and
-		 * lowered its priority, then reschedule its CPU:
+		 * Reschedule if we are currently running on this runqueue and
+		 * our priority decreased, or if our priority became higher
+		 * than the current's.
 		 */
-		if (delta < 0 || (delta > 0 && task_running(rq, p)))
+		if (TASK_PREEMPTS_CURR(p, rq) ||
+				(delta > 0 && task_running(rq, p)))
 			resched_task(rq->curr);
 	}
 out_unlock:
@@ -4153,13 +4382,11 @@ recheck:
 		__activate_task(p, rq);
 		/*
 		 * Reschedule if we are currently running on this runqueue and
-		 * our priority decreased, or if we are not currently running on
-		 * this runqueue and our priority is higher than the current's
+		 * our priority decreased, or our priority became higher
+		 * than the current's.
 		 */
-		if (task_running(rq, p)) {
-			if (p->prio > oldprio)
-				resched_task(rq->curr);
-		} else if (TASK_PREEMPTS_CURR(p, rq))
+		if (TASK_PREEMPTS_CURR(p, rq) ||
+				(task_running(rq, p) && p->prio > oldprio))
 			resched_task(rq->curr);
 	}
 	__task_rq_unlock(rq);
@@ -4746,10 +4973,12 @@ #endif
 		 * console might take alot of time:
 		 */
 		touch_nmi_watchdog();
-		if (p->state & state_filter)
+		if (!state_filter || (p->state & state_filter))
 			show_task(p);
 	} while_each_thread(g, p);
 
+	touch_all_softlockup_watchdogs();
+
 	read_unlock(&tasklist_lock);
 	/*
 	 * Only show locks if all tasks are dumped:
@@ -5244,6 +5473,11 @@ int __init migration_init(void)
 #endif
 
 #ifdef CONFIG_SMP
+
+/* Number of possible processor ids */
+int nr_cpu_ids __read_mostly = NR_CPUS;
+EXPORT_SYMBOL(nr_cpu_ids);
+
 #undef SCHED_DOMAIN_DEBUG
 #ifdef SCHED_DOMAIN_DEBUG
 static void sched_domain_debug(struct sched_domain *sd, int cpu)
@@ -5299,7 +5533,7 @@ static void sched_domain_debug(struct sc
 				break;
 			}
 
-			if (!group->cpu_power) {
+			if (!group->__cpu_power) {
 				printk("\n");
 				printk(KERN_ERR "ERROR: domain->cpu_power not "
 						"set\n");
@@ -5476,7 +5710,7 @@ init_sched_build_groups(cpumask_t span, 
 			continue;
 
 		sg->cpumask = CPU_MASK_NONE;
-		sg->cpu_power = 0;
+		sg->__cpu_power = 0;
 
 		for_each_cpu_mask(j, span) {
 			if (group_fn(j, cpu_map, NULL) != group)
@@ -6165,7 +6399,7 @@ next_sg:
 			continue;
 		}
 
-		sg->cpu_power += sd->groups->cpu_power;
+		sg_inc_cpu_power(sg, sd->groups->__cpu_power);
 	}
 	sg = sg->next;
 	if (sg != group_head)
@@ -6240,6 +6474,8 @@ static void init_sched_groups_power(int 
 
 	child = sd->child;
 
+	sd->groups->__cpu_power = 0;
+
 	/*
 	 * For perf policy, if the groups in child domain share resources
 	 * (for example cores sharing some portions of the cache hierarchy
@@ -6250,18 +6486,16 @@ static void init_sched_groups_power(int 
 	if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) &&
 		       (child->flags &
 			(SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) {
-		sd->groups->cpu_power = SCHED_LOAD_SCALE;
+		sg_inc_cpu_power(sd->groups, 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;
+		sg_inc_cpu_power(sd->groups, group->__cpu_power);
 		group = group->next;
 	} while (group != child->groups);
 }
@@ -6421,7 +6655,7 @@ #ifdef CONFIG_NUMA
 			sd = &per_cpu(node_domains, j);
 			sd->groups = sg;
 		}
-		sg->cpu_power = 0;
+		sg->__cpu_power = 0;
 		sg->cpumask = nodemask;
 		sg->next = sg;
 		cpus_or(covered, covered, nodemask);
@@ -6449,7 +6683,7 @@ #ifdef CONFIG_NUMA
 				"Can not alloc domain group for node %d\n", j);
 				goto error;
 			}
-			sg->cpu_power = 0;
+			sg->__cpu_power = 0;
 			sg->cpumask = tmp;
 			sg->next = prev->next;
 			cpus_or(covered, covered, tmp);
@@ -6726,6 +6960,7 @@ int in_sched_functions(unsigned long add
 void __init sched_init(void)
 {
 	int i, j, k;
+	int highest_cpu = 0;
 
 	for_each_possible_cpu(i) {
 		struct prio_array *array;
@@ -6760,11 +6995,13 @@ #endif
 			// delimiter for bitsearch
 			__set_bit(MAX_PRIO, array->bitmap);
 		}
+		highest_cpu = i;
 	}
 
 	set_load_weight(&init_task);
 
 #ifdef CONFIG_SMP
+	nr_cpu_ids = highest_cpu + 1;
 	open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);
 #endif
 
diff --git a/kernel/signal.c b/kernel/signal.c
index 3670225..1368e67 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -12,7 +12,6 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -2636,9 +2635,5 @@ __attribute__((weak)) const char *arch_v
 
 void __init signals_init(void)
 {
-	sigqueue_cachep =
-		kmem_cache_create("sigqueue",
-				  sizeof(struct sigqueue),
-				  __alignof__(struct sigqueue),
-				  SLAB_PANIC, NULL, NULL);
+	sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
 }
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 50afeb8..8fa7040 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -34,12 +34,32 @@ static struct notifier_block panic_block
 	.notifier_call = softlock_panic,
 };
 
+/*
+ * Returns seconds, approximately.  We don't need nanosecond
+ * resolution, and we don't need to waste time with a big divide when
+ * 2^30ns == 1.074s.
+ */
+static unsigned long get_timestamp(void)
+{
+	return sched_clock() >> 30;  /* 2^30 ~= 10^9 */
+}
+
 void touch_softlockup_watchdog(void)
 {
-	__raw_get_cpu_var(touch_timestamp) = jiffies;
+	__raw_get_cpu_var(touch_timestamp) = get_timestamp();
 }
 EXPORT_SYMBOL(touch_softlockup_watchdog);
 
+void touch_all_softlockup_watchdogs(void)
+{
+	int cpu;
+
+	/* Cause each CPU to re-update its timestamp rather than complain */
+	for_each_online_cpu(cpu)
+		per_cpu(touch_timestamp, cpu) = 0;
+}
+EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
+
 /*
  * This callback runs from the timer interrupt, and checks
  * whether the watchdog thread has hung or not:
@@ -48,9 +68,18 @@ void softlockup_tick(void)
 {
 	int this_cpu = smp_processor_id();
 	unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu);
+	unsigned long print_timestamp;
+	unsigned long now;
+
+	if (touch_timestamp == 0) {
+		touch_softlockup_watchdog();
+		return;
+	}
+
+	print_timestamp = per_cpu(print_timestamp, this_cpu);
 
-	/* prevent double reports: */
-	if (per_cpu(print_timestamp, this_cpu) == touch_timestamp ||
+	/* report at most once a second */
+	if (print_timestamp < (touch_timestamp + 1) ||
 		did_panic ||
 			!per_cpu(watchdog_task, this_cpu))
 		return;
@@ -61,12 +90,14 @@ void softlockup_tick(void)
 		return;
 	}
 
+	now = get_timestamp();
+
 	/* Wake up the high-prio watchdog task every second: */
-	if (time_after(jiffies, touch_timestamp + HZ))
+	if (now > (touch_timestamp + 1))
 		wake_up_process(per_cpu(watchdog_task, this_cpu));
 
 	/* Warn about unreasonable 10+ seconds delays: */
-	if (time_after(jiffies, touch_timestamp + 10*HZ)) {
+	if (now > (touch_timestamp + 10)) {
 		per_cpu(print_timestamp, this_cpu) = touch_timestamp;
 
 		spin_lock(&print_lock);
@@ -82,11 +113,14 @@ void softlockup_tick(void)
  */
 static int watchdog(void * __bind_cpu)
 {
-	struct sched_param param = { .sched_priority = 99 };
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
 	current->flags |= PF_NOFREEZE;
 
+	/* initialize timestamp */
+	touch_softlockup_watchdog();
+
 	/*
 	 * Run briefly once per second to reset the softlockup timestamp.
 	 * If this gets delayed for more than 10 seconds then the
@@ -118,7 +152,7 @@ cpu_callback(struct notifier_block *nfb,
 			printk("watchdog for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
 		}
-  		per_cpu(touch_timestamp, hotcpu) = jiffies;
+  		per_cpu(touch_timestamp, hotcpu) = 0;
   		per_cpu(watchdog_task, hotcpu) = p;
 		kthread_bind(p, hotcpu);
  		break;
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 1245804..daabb74 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -1,11 +1,12 @@
 /* Copyright 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation.
  * GPL v2 and any later version.
  */
-#include <linux/stop_machine.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
 #include <linux/cpu.h>
 #include <linux/err.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stop_machine.h>
 #include <linux/syscalls.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -208,3 +209,4 @@ int stop_machine_run(int (*fn)(void *), 
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(stop_machine_run);
diff --git a/kernel/sys.c b/kernel/sys.c
index 123b165..926bf9d 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -881,7 +881,7 @@ asmlinkage long sys_reboot(int magic1, i
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	case LINUX_REBOOT_CMD_SW_SUSPEND:
 		{
-			int ret = software_suspend();
+			int ret = pm_suspend(PM_SUSPEND_DISK);
 			unlock_kernel();
 			return ret;
 		}
@@ -1923,6 +1923,16 @@ asmlinkage long sys_setrlimit(unsigned i
 	if (retval)
 		return retval;
 
+	if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) {
+		/*
+		 * The caller is asking for an immediate RLIMIT_CPU
+		 * expiry.  But we use the zero value to mean "it was
+		 * never set".  So let's cheat and make it one second
+		 * instead
+		 */
+		new_rlim.rlim_cur = 1;
+	}
+
 	task_lock(current->group_leader);
 	*old_rlim = new_rlim;
 	task_unlock(current->group_leader);
@@ -1944,15 +1954,6 @@ asmlinkage long sys_setrlimit(unsigned i
 		unsigned long rlim_cur = new_rlim.rlim_cur;
 		cputime_t cputime;
 
-		if (rlim_cur == 0) {
-			/*
-			 * The caller is asking for an immediate RLIMIT_CPU
-			 * expiry.  But we use the zero value to mean "it was
-			 * never set".  So let's cheat and make it one second
-			 * instead
-			 */
-			rlim_cur = 1;
-		}
 		cputime = secs_to_cputime(rlim_cur);
 		read_lock(&tasklist_lock);
 		spin_lock_irq(&current->sighand->siglock);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c904748..f0664bd 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,7 @@ extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
+extern int maps_protect;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -603,6 +604,16 @@ #ifdef CONFIG_RT_MUTEXES
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_PROC_FS
+	{
+		.ctl_name       = CTL_UNNUMBERED,
+		.procname       = "maps_protect",
+		.data           = &maps_protect,
+		.maxlen         = sizeof(int),
+		.mode           = 0644,
+		.proc_handler   = &proc_dointvec,
+	},
+#endif
 
 	{ .ctl_name = 0 }
 };
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 4c3476f..906cae7 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -102,7 +102,7 @@ static int prepare_reply(struct genl_inf
  */
 static int send_reply(struct sk_buff *skb, pid_t pid)
 {
-	struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
 	void *reply = genlmsg_data(genlhdr);
 	int rc;
 
@@ -121,7 +121,7 @@ static int send_reply(struct sk_buff *sk
 static void send_cpu_listeners(struct sk_buff *skb,
 					struct listener_list *listeners)
 {
-	struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
 	struct listener *s, *tmp;
 	struct sk_buff *skb_next, *skb_cur = skb;
 	void *reply = genlmsg_data(genlhdr);
@@ -524,9 +524,7 @@ void __init taskstats_init_early(void)
 {
 	unsigned int i;
 
-	taskstats_cache = kmem_cache_create("taskstats_cache",
-						sizeof(struct taskstats),
-						0, SLAB_PANIC, NULL, NULL);
+	taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
 	for_each_possible_cpu(i) {
 		INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
 		init_rwsem(&(per_cpu(listener_array, i).sem));
diff --git a/kernel/time.c b/kernel/time.c
index 2f47888..f04791f 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -31,7 +31,6 @@ #include <linux/module.h>
 #include <linux/timex.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/security.h>
 #include <linux/fs.h>
@@ -247,6 +246,36 @@ struct timespec current_fs_time(struct s
 }
 EXPORT_SYMBOL(current_fs_time);
 
+/*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+unsigned int inline jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+	return (MSEC_PER_SEC / HZ) * j;
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
+#else
+	return (j * MSEC_PER_SEC) / HZ;
+#endif
+}
+EXPORT_SYMBOL(jiffies_to_msecs);
+
+unsigned int inline jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
+	return (USEC_PER_SEC / HZ) * j;
+#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
+	return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC);
+#else
+	return (j * USEC_PER_SEC) / HZ;
+#endif
+}
+EXPORT_SYMBOL(jiffies_to_usecs);
+
 /**
  * timespec_trunc - Truncate timespec to a granularity
  * @t: Timespec
@@ -452,6 +481,7 @@ struct timespec ns_to_timespec(const s64
 
 	return ts;
 }
+EXPORT_SYMBOL(ns_to_timespec);
 
 /**
  * ns_to_timeval - Convert nanoseconds to timeval
@@ -469,36 +499,7 @@ struct timeval ns_to_timeval(const s64 n
 
 	return tv;
 }
-
-/*
- * Convert jiffies to milliseconds and back.
- *
- * Avoid unnecessary multiplications/divisions in the
- * two most common HZ cases:
- */
-unsigned int jiffies_to_msecs(const unsigned long j)
-{
-#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
-	return (MSEC_PER_SEC / HZ) * j;
-#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
-	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
-#else
-	return (j * MSEC_PER_SEC) / HZ;
-#endif
-}
-EXPORT_SYMBOL(jiffies_to_msecs);
-
-unsigned int jiffies_to_usecs(const unsigned long j)
-{
-#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
-	return (USEC_PER_SEC / HZ) * j;
-#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
-	return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC);
-#else
-	return (j * USEC_PER_SEC) / HZ;
-#endif
-}
-EXPORT_SYMBOL(jiffies_to_usecs);
+EXPORT_SYMBOL(ns_to_timeval);
 
 /*
  * When we convert to jiffies then we interpret incoming values
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 93bccba..99b6034 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,4 +1,4 @@
-obj-y += ntp.o clocksource.o jiffies.o timer_list.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= tick-common.o
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index bfda3f7..a96ec9a 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -31,7 +31,7 @@ DEFINE_PER_CPU(struct tick_device, tick_
  */
 ktime_t tick_next_period;
 ktime_t tick_period;
-static int tick_do_timer_cpu = -1;
+int tick_do_timer_cpu __read_mostly = -1;
 DEFINE_SPINLOCK(tick_device_lock);
 
 /*
@@ -295,6 +295,12 @@ static void tick_shutdown(unsigned int *
 		clockevents_exchange_device(dev, NULL);
 		td->evtdev = NULL;
 	}
+	/* Transfer the do_timer job away from this cpu */
+	if (*cpup == tick_do_timer_cpu) {
+		int cpu = first_cpu(cpu_online_map);
+
+		tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1;
+	}
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 }
 
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index c9d203b..bb13f27 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -5,6 +5,7 @@ DECLARE_PER_CPU(struct tick_device, tick
 extern spinlock_t tick_device_lock;
 extern ktime_t tick_next_period;
 extern ktime_t tick_period;
+extern int tick_do_timer_cpu __read_mostly;
 
 extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
 extern void tick_handle_periodic(struct clock_event_device *dev);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 51556b9..3483e6c 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,10 +217,30 @@ void tick_nohz_stop_sched_tick(void)
 		 * the scheduler tick in nohz_restart_sched_tick.
 		 */
 		if (!ts->tick_stopped) {
+			if (select_nohz_load_balancer(1)) {
+				/*
+				 * sched tick not stopped!
+				 */
+				cpu_clear(cpu, nohz_cpu_mask);
+				goto out;
+			}
+
 			ts->idle_tick = ts->sched_timer.expires;
 			ts->tick_stopped = 1;
 			ts->idle_jiffies = last_jiffies;
 		}
+
+		/*
+		 * If this cpu is the one which updates jiffies, then
+		 * give up the assignment and let it be taken by the
+		 * cpu which runs the tick timer next, which might be
+		 * this cpu as well. If we don't drop this here the
+		 * jiffies might be stale and do_timer() never
+		 * invoked.
+		 */
+		if (cpu == tick_do_timer_cpu)
+			tick_do_timer_cpu = -1;
+
 		/*
 		 * calculate the expiry time for the next timer wheel
 		 * timer
@@ -273,6 +293,7 @@ void tick_nohz_restart_sched_tick(void)
 	now = ktime_get();
 
 	local_irq_disable();
+	select_nohz_load_balancer(0);
 	tick_do_update_jiffies64(now);
 	cpu_clear(cpu, nohz_cpu_mask);
 
@@ -338,12 +359,24 @@ static void tick_nohz_handler(struct clo
 {
 	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 	struct pt_regs *regs = get_irq_regs();
+	int cpu = smp_processor_id();
 	ktime_t now = ktime_get();
 
 	dev->next_event.tv64 = KTIME_MAX;
 
+	/*
+	 * Check if the do_timer duty was dropped. We don't care about
+	 * concurrency: This happens only when the cpu in charge went
+	 * into a long sleep. If two cpus happen to assign themself to
+	 * this duty, then the jiffies update is still serialized by
+	 * xtime_lock.
+	 */
+	if (unlikely(tick_do_timer_cpu == -1))
+		tick_do_timer_cpu = cpu;
+
 	/* Check, if the jiffies need an update */
-	tick_do_update_jiffies64(now);
+	if (tick_do_timer_cpu == cpu)
+		tick_do_update_jiffies64(now);
 
 	/*
 	 * When we are idle and the tick is stopped, we have to touch
@@ -431,9 +464,23 @@ static enum hrtimer_restart tick_sched_t
 	struct hrtimer_cpu_base *base = timer->base->cpu_base;
 	struct pt_regs *regs = get_irq_regs();
 	ktime_t now = ktime_get();
+	int cpu = smp_processor_id();
+
+#ifdef CONFIG_NO_HZ
+	/*
+	 * Check if the do_timer duty was dropped. We don't care about
+	 * concurrency: This happens only when the cpu in charge went
+	 * into a long sleep. If two cpus happen to assign themself to
+	 * this duty, then the jiffies update is still serialized by
+	 * xtime_lock.
+	 */
+	if (unlikely(tick_do_timer_cpu == -1))
+		tick_do_timer_cpu = cpu;
+#endif
 
 	/* Check, if the jiffies need an update */
-	tick_do_update_jiffies64(now);
+	if (tick_do_timer_cpu == cpu)
+		tick_do_update_jiffies64(now);
 
 	/*
 	 * Do not call, when we are not in irq context and have
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
new file mode 100644
index 0000000..f9217bf
--- /dev/null
+++ b/kernel/time/timekeeping.c
@@ -0,0 +1,476 @@
+/*
+ *  linux/kernel/time/timekeeping.c
+ *
+ *  Kernel timekeeping code and accessor functions
+ *
+ *  This code was moved from linux/kernel/timer.c.
+ *  Please see that file for copyright and history logs.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sysdev.h>
+#include <linux/clocksource.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <linux/tick.h>
+
+
+/*
+ * This read-write spinlock protects us from races in SMP while
+ * playing with xtime and avenrun.
+ */
+__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
+
+EXPORT_SYMBOL(xtime_lock);
+
+
+/*
+ * The current time
+ * wall_to_monotonic is what we need to add to xtime (or xtime corrected
+ * for sub jiffie times) to get to monotonic time.  Monotonic is pegged
+ * at zero at system boot time, so wall_to_monotonic will be negative,
+ * however, we will ALWAYS keep the tv_nsec part positive so we can use
+ * the usual normalization.
+ */
+struct timespec xtime __attribute__ ((aligned (16)));
+struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+
+EXPORT_SYMBOL(xtime);
+
+
+static struct clocksource *clock; /* pointer to current clocksource */
+
+
+#ifdef CONFIG_GENERIC_TIME
+/**
+ * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
+ *
+ * private function, must hold xtime_lock lock when being
+ * called. Returns the number of nanoseconds since the
+ * last call to update_wall_time() (adjusted by NTP scaling)
+ */
+static inline s64 __get_nsec_offset(void)
+{
+	cycle_t cycle_now, cycle_delta;
+	s64 ns_offset;
+
+	/* read clocksource: */
+	cycle_now = clocksource_read(clock);
+
+	/* calculate the delta since the last update_wall_time: */
+	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+	/* convert to nanoseconds: */
+	ns_offset = cyc2ns(clock, cycle_delta);
+
+	return ns_offset;
+}
+
+/**
+ * __get_realtime_clock_ts - Returns the time of day in a timespec
+ * @ts:		pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec. Used by
+ * do_gettimeofday() and get_realtime_clock_ts().
+ */
+static inline void __get_realtime_clock_ts(struct timespec *ts)
+{
+	unsigned long seq;
+	s64 nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+
+		*ts = xtime;
+		nsecs = __get_nsec_offset();
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	timespec_add_ns(ts, nsecs);
+}
+
+/**
+ * getnstimeofday - Returns the time of day in a timespec
+ * @ts:		pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ */
+void getnstimeofday(struct timespec *ts)
+{
+	__get_realtime_clock_ts(ts);
+}
+
+EXPORT_SYMBOL(getnstimeofday);
+
+/**
+ * do_gettimeofday - Returns the time of day in a timeval
+ * @tv:		pointer to the timeval to be set
+ *
+ * NOTE: Users should be converted to using get_realtime_clock_ts()
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	struct timespec now;
+
+	__get_realtime_clock_ts(&now);
+	tv->tv_sec = now.tv_sec;
+	tv->tv_usec = now.tv_nsec/1000;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+/**
+ * do_settimeofday - Sets the time of day
+ * @tv:		pointer to the timespec variable containing the new time
+ *
+ * Sets the time of day to the new time and update NTP and notify hrtimers
+ */
+int do_settimeofday(struct timespec *tv)
+{
+	unsigned long flags;
+	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_irqsave(&xtime_lock, flags);
+
+	nsec -= __get_nsec_offset();
+
+	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+	set_normalized_timespec(&xtime, sec, nsec);
+	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+	clock->error = 0;
+	ntp_clear();
+
+	update_vsyscall(&xtime, clock);
+
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	/* signal hrtimers about time change */
+	clock_was_set();
+
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/**
+ * change_clocksource - Swaps clocksources if a new one is available
+ *
+ * Accumulates current time interval and initializes new clocksource
+ */
+static void change_clocksource(void)
+{
+	struct clocksource *new;
+	cycle_t now;
+	u64 nsec;
+
+	new = clocksource_get_next();
+
+	if (clock == new)
+		return;
+
+	now = clocksource_read(new);
+	nsec =  __get_nsec_offset();
+	timespec_add_ns(&xtime, nsec);
+
+	clock = new;
+	clock->cycle_last = now;
+
+	clock->error = 0;
+	clock->xtime_nsec = 0;
+	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+
+	tick_clock_notify();
+
+	printk(KERN_INFO "Time: %s clocksource has been installed.\n",
+	       clock->name);
+}
+#else
+static inline void change_clocksource(void) { }
+#endif
+
+/**
+ * timekeeping_is_continuous - check to see if timekeeping is free running
+ */
+int timekeeping_is_continuous(void)
+{
+	unsigned long seq;
+	int ret;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+
+		ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	return ret;
+}
+
+/**
+ * read_persistent_clock -  Return time in seconds from the persistent clock.
+ *
+ * Weak dummy function for arches that do not yet support it.
+ * Returns seconds from epoch using the battery backed persistent clock.
+ * Returns zero if unsupported.
+ *
+ *  XXX - Do be sure to remove it once all arches implement it.
+ */
+unsigned long __attribute__((weak)) read_persistent_clock(void)
+{
+	return 0;
+}
+
+/*
+ * timekeeping_init - Initializes the clocksource and common timekeeping values
+ */
+void __init timekeeping_init(void)
+{
+	unsigned long flags;
+	unsigned long sec = read_persistent_clock();
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+
+	ntp_clear();
+
+	clock = clocksource_get_next();
+	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+	clock->cycle_last = clocksource_read(clock);
+
+	xtime.tv_sec = sec;
+	xtime.tv_nsec = 0;
+	set_normalized_timespec(&wall_to_monotonic,
+		-xtime.tv_sec, -xtime.tv_nsec);
+
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
+/* flag for if timekeeping is suspended */
+static int timekeeping_suspended;
+/* time in seconds when suspend began */
+static unsigned long timekeeping_suspend_time;
+
+/**
+ * timekeeping_resume - Resumes the generic timekeeping subsystem.
+ * @dev:	unused
+ *
+ * This is for the generic clocksource timekeeping.
+ * xtime/wall_to_monotonic/jiffies/etc are
+ * still managed by arch specific suspend/resume code.
+ */
+static int timekeeping_resume(struct sys_device *dev)
+{
+	unsigned long flags;
+	unsigned long now = read_persistent_clock();
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+
+	if (now && (now > timekeeping_suspend_time)) {
+		unsigned long sleep_length = now - timekeeping_suspend_time;
+
+		xtime.tv_sec += sleep_length;
+		wall_to_monotonic.tv_sec -= sleep_length;
+	}
+	/* re-base the last cycle value */
+	clock->cycle_last = clocksource_read(clock);
+	clock->error = 0;
+	timekeeping_suspended = 0;
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	touch_softlockup_watchdog();
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+
+	/* Resume hrtimers */
+	hres_timers_resume();
+
+	return 0;
+}
+
+static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
+{
+	unsigned long flags;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	timekeeping_suspended = 1;
+	timekeeping_suspend_time = read_persistent_clock();
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+
+	return 0;
+}
+
+/* sysfs resume/suspend bits for timekeeping */
+static struct sysdev_class timekeeping_sysclass = {
+	.resume		= timekeeping_resume,
+	.suspend	= timekeeping_suspend,
+	set_kset_name("timekeeping"),
+};
+
+static struct sys_device device_timer = {
+	.id		= 0,
+	.cls		= &timekeeping_sysclass,
+};
+
+static int __init timekeeping_init_device(void)
+{
+	int error = sysdev_class_register(&timekeeping_sysclass);
+	if (!error)
+		error = sysdev_register(&device_timer);
+	return error;
+}
+
+device_initcall(timekeeping_init_device);
+
+/*
+ * If the error is already larger, we look ahead even further
+ * to compensate for late or lost adjustments.
+ */
+static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
+						 s64 *offset)
+{
+	s64 tick_error, i;
+	u32 look_ahead, adj;
+	s32 error2, mult;
+
+	/*
+	 * Use the current error value to determine how much to look ahead.
+	 * The larger the error the slower we adjust for it to avoid problems
+	 * with losing too many ticks, otherwise we would overadjust and
+	 * produce an even larger error.  The smaller the adjustment the
+	 * faster we try to adjust for it, as lost ticks can do less harm
+	 * here.  This is tuned so that an error of about 1 msec is adusted
+	 * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
+	 */
+	error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
+	error2 = abs(error2);
+	for (look_ahead = 0; error2 > 0; look_ahead++)
+		error2 >>= 2;
+
+	/*
+	 * Now calculate the error in (1 << look_ahead) ticks, but first
+	 * remove the single look ahead already included in the error.
+	 */
+	tick_error = current_tick_length() >>
+		(TICK_LENGTH_SHIFT - clock->shift + 1);
+	tick_error -= clock->xtime_interval >> 1;
+	error = ((error - tick_error) >> look_ahead) + tick_error;
+
+	/* Finally calculate the adjustment shift value.  */
+	i = *interval;
+	mult = 1;
+	if (error < 0) {
+		error = -error;
+		*interval = -*interval;
+		*offset = -*offset;
+		mult = -1;
+	}
+	for (adj = 0; error > i; adj++)
+		error >>= 1;
+
+	*interval <<= adj;
+	*offset <<= adj;
+	return mult << adj;
+}
+
+/*
+ * Adjust the multiplier to reduce the error value,
+ * this is optimized for the most common adjustments of -1,0,1,
+ * for other values we can do a bit more work.
+ */
+static void clocksource_adjust(struct clocksource *clock, s64 offset)
+{
+	s64 error, interval = clock->cycle_interval;
+	int adj;
+
+	error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+	if (error > interval) {
+		error >>= 2;
+		if (likely(error <= interval))
+			adj = 1;
+		else
+			adj = clocksource_bigadjust(error, &interval, &offset);
+	} else if (error < -interval) {
+		error >>= 2;
+		if (likely(error >= -interval)) {
+			adj = -1;
+			interval = -interval;
+			offset = -offset;
+		} else
+			adj = clocksource_bigadjust(error, &interval, &offset);
+	} else
+		return;
+
+	clock->mult += adj;
+	clock->xtime_interval += interval;
+	clock->xtime_nsec -= offset;
+	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.
+ */
+void update_wall_time(void)
+{
+	cycle_t offset;
+
+	/* Make sure we're fully resumed: */
+	if (unlikely(timekeeping_suspended))
+		return;
+
+#ifdef CONFIG_GENERIC_TIME
+	offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
+#else
+	offset = clock->cycle_interval;
+#endif
+	clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
+
+	/* normally this loop will run just once, however in the
+	 * case of lost or late ticks, it will accumulate correctly.
+	 */
+	while (offset >= clock->cycle_interval) {
+		/* accumulate one interval */
+		clock->xtime_nsec += clock->xtime_interval;
+		clock->cycle_last += clock->cycle_interval;
+		offset -= clock->cycle_interval;
+
+		if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
+			clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
+			xtime.tv_sec++;
+			second_overflow();
+		}
+
+		/* interpolator bits */
+		time_interpolator_update(clock->xtime_interval
+						>> clock->shift);
+
+		/* accumulate error between NTP and clock interval */
+		clock->error += current_tick_length();
+		clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+	}
+
+	/* correct the clock when NTP error is too big */
+	clocksource_adjust(clock, offset);
+
+	/* store full nanoseconds into xtime */
+	xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
+	clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
+
+	/* check to see if there is a new clocksource to use */
+	change_clocksource();
+	update_vsyscall(&xtime, clock);
+}
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 59df5e8..b734ca4 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -38,17 +38,12 @@ #define SEQ_printf(m, x...)			\
 
 static void print_name_offset(struct seq_file *m, void *sym)
 {
-	unsigned long addr = (unsigned long)sym;
-	char namebuf[KSYM_NAME_LEN+1];
-	unsigned long size, offset;
-	const char *sym_name;
-	char *modname;
-
-	sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf);
-	if (sym_name)
-		SEQ_printf(m, "%s", sym_name);
-	else
+	char symname[KSYM_NAME_LEN+1];
+
+	if (lookup_symbol_name((unsigned long)sym, symname) < 0)
 		SEQ_printf(m, "<%p>", sym);
+	else
+		SEQ_printf(m, "%s", symname);
 }
 
 static void
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c
index 1bc4882..868f1bc 100644
--- a/kernel/time/timer_stats.c
+++ b/kernel/time/timer_stats.c
@@ -257,16 +257,12 @@ void timer_stats_update_stats(void *time
 
 static void print_name_offset(struct seq_file *m, unsigned long addr)
 {
-	char namebuf[KSYM_NAME_LEN+1];
-	unsigned long size, offset;
-	const char *sym_name;
-	char *modname;
-
-	sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf);
-	if (sym_name)
-		seq_printf(m, "%s", sym_name);
-	else
+	char symname[KSYM_NAME_LEN+1];
+
+	if (lookup_symbol_name(addr, symname) < 0)
 		seq_printf(m, "<%p>", (void *)addr);
+	else
+		seq_printf(m, "%s", symname);
 }
 
 static int tstats_show(struct seq_file *m, void *v)
diff --git a/kernel/timer.c b/kernel/timer.c
index dd6c2c1..7a64483 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1,7 +1,7 @@
 /*
  *  linux/kernel/timer.c
  *
- *  Kernel internal timers, kernel timekeeping, basic process system calls
+ *  Kernel internal timers, basic process system calls
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
@@ -74,7 +74,7 @@ struct tvec_t_base_s {
 	tvec_t tv3;
 	tvec_t tv4;
 	tvec_t tv5;
-} ____cacheline_aligned_in_smp;
+} ____cacheline_aligned;
 
 typedef struct tvec_t_base_s tvec_base_t;
 
@@ -82,6 +82,37 @@ tvec_base_t boot_tvec_bases;
 EXPORT_SYMBOL(boot_tvec_bases);
 static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases;
 
+/*
+ * Note that all tvec_bases is 2 byte aligned and lower bit of
+ * base in timer_list is guaranteed to be zero. Use the LSB for
+ * the new flag to indicate whether the timer is deferrable
+ */
+#define TBASE_DEFERRABLE_FLAG		(0x1)
+
+/* Functions below help us manage 'deferrable' flag */
+static inline unsigned int tbase_get_deferrable(tvec_base_t *base)
+{
+	return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG);
+}
+
+static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
+{
+	return ((tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG));
+}
+
+static inline void timer_set_deferrable(struct timer_list *timer)
+{
+	timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
+	                               TBASE_DEFERRABLE_FLAG));
+}
+
+static inline void
+timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
+{
+	timer->base = (tvec_base_t *)((unsigned long)(new_base) |
+	                              tbase_get_deferrable(timer->base));
+}
+
 /**
  * __round_jiffies - function to round jiffies to a full second
  * @j: the time in (absolute) jiffies that should be rounded
@@ -295,6 +326,13 @@ #endif
 }
 EXPORT_SYMBOL(init_timer);
 
+void fastcall init_timer_deferrable(struct timer_list *timer)
+{
+	init_timer(timer);
+	timer_set_deferrable(timer);
+}
+EXPORT_SYMBOL(init_timer_deferrable);
+
 static inline void detach_timer(struct timer_list *timer,
 				int clear_pending)
 {
@@ -325,10 +363,11 @@ static tvec_base_t *lock_timer_base(stru
 	tvec_base_t *base;
 
 	for (;;) {
-		base = timer->base;
+		tvec_base_t *prelock_base = timer->base;
+		base = tbase_get_base(prelock_base);
 		if (likely(base != NULL)) {
 			spin_lock_irqsave(&base->lock, *flags);
-			if (likely(base == timer->base))
+			if (likely(prelock_base == timer->base))
 				return base;
 			/* The timer has migrated to another CPU */
 			spin_unlock_irqrestore(&base->lock, *flags);
@@ -365,11 +404,11 @@ int __mod_timer(struct timer_list *timer
 		 */
 		if (likely(base->running_timer != timer)) {
 			/* See the comment in lock_timer_base() */
-			timer->base = NULL;
+			timer_set_base(timer, NULL);
 			spin_unlock(&base->lock);
 			base = new_base;
 			spin_lock(&base->lock);
-			timer->base = base;
+			timer_set_base(timer, base);
 		}
 	}
 
@@ -397,7 +436,7 @@ void add_timer_on(struct timer_list *tim
 	timer_stats_timer_set_start_info(timer);
   	BUG_ON(timer_pending(timer) || !timer->function);
 	spin_lock_irqsave(&base->lock, flags);
-	timer->base = base;
+	timer_set_base(timer, base);
 	internal_add_timer(base, timer);
 	spin_unlock_irqrestore(&base->lock, flags);
 }
@@ -505,6 +544,8 @@ out:
 	return ret;
 }
 
+EXPORT_SYMBOL(try_to_del_timer_sync);
+
 /**
  * del_timer_sync - deactivate a timer and wait for the handler to finish.
  * @timer: the timer to be deactivated
@@ -548,7 +589,7 @@ static int cascade(tvec_base_t *base, tv
 	 * don't have to detach them individually.
 	 */
 	list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
-		BUG_ON(timer->base != base);
+		BUG_ON(tbase_get_base(timer->base) != base);
 		internal_add_timer(base, timer);
 	}
 
@@ -588,7 +629,7 @@ static inline void __run_timers(tvec_bas
 			void (*fn)(unsigned long);
 			unsigned long data;
 
-			timer = list_entry(head->next,struct timer_list,entry);
+			timer = list_first_entry(head, struct timer_list,entry);
  			fn = timer->function;
  			data = timer->data;
 
@@ -634,6 +675,9 @@ static unsigned long __next_timer_interr
 	index = slot = timer_jiffies & TVR_MASK;
 	do {
 		list_for_each_entry(nte, base->tv1.vec + slot, entry) {
+ 			if (tbase_get_deferrable(nte->base))
+ 				continue;
+
 			found = 1;
 			expires = nte->expires;
 			/* Look at the cascade bucket(s)? */
@@ -750,455 +794,6 @@ #endif
 
 #endif
 
-/******************************************************************/
-
-/* 
- * The current time 
- * wall_to_monotonic is what we need to add to xtime (or xtime corrected 
- * for sub jiffie times) to get to monotonic time.  Monotonic is pegged
- * at zero at system boot time, so wall_to_monotonic will be negative,
- * however, we will ALWAYS keep the tv_nsec part positive so we can use
- * the usual normalization.
- */
-struct timespec xtime __attribute__ ((aligned (16)));
-struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
-
-EXPORT_SYMBOL(xtime);
-
-
-/* XXX - all of this timekeeping code should be later moved to time.c */
-#include <linux/clocksource.h>
-static struct clocksource *clock; /* pointer to current clocksource */
-
-#ifdef CONFIG_GENERIC_TIME
-/**
- * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
- *
- * private function, must hold xtime_lock lock when being
- * called. Returns the number of nanoseconds since the
- * last call to update_wall_time() (adjusted by NTP scaling)
- */
-static inline s64 __get_nsec_offset(void)
-{
-	cycle_t cycle_now, cycle_delta;
-	s64 ns_offset;
-
-	/* read clocksource: */
-	cycle_now = clocksource_read(clock);
-
-	/* calculate the delta since the last update_wall_time: */
-	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
-
-	/* convert to nanoseconds: */
-	ns_offset = cyc2ns(clock, cycle_delta);
-
-	return ns_offset;
-}
-
-/**
- * __get_realtime_clock_ts - Returns the time of day in a timespec
- * @ts:		pointer to the timespec to be set
- *
- * Returns the time of day in a timespec. Used by
- * do_gettimeofday() and get_realtime_clock_ts().
- */
-static inline void __get_realtime_clock_ts(struct timespec *ts)
-{
-	unsigned long seq;
-	s64 nsecs;
-
-	do {
-		seq = read_seqbegin(&xtime_lock);
-
-		*ts = xtime;
-		nsecs = __get_nsec_offset();
-
-	} while (read_seqretry(&xtime_lock, seq));
-
-	timespec_add_ns(ts, nsecs);
-}
-
-/**
- * getnstimeofday - Returns the time of day in a timespec
- * @ts:		pointer to the timespec to be set
- *
- * Returns the time of day in a timespec.
- */
-void getnstimeofday(struct timespec *ts)
-{
-	__get_realtime_clock_ts(ts);
-}
-
-EXPORT_SYMBOL(getnstimeofday);
-
-/**
- * do_gettimeofday - Returns the time of day in a timeval
- * @tv:		pointer to the timeval to be set
- *
- * NOTE: Users should be converted to using get_realtime_clock_ts()
- */
-void do_gettimeofday(struct timeval *tv)
-{
-	struct timespec now;
-
-	__get_realtime_clock_ts(&now);
-	tv->tv_sec = now.tv_sec;
-	tv->tv_usec = now.tv_nsec/1000;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-/**
- * do_settimeofday - Sets the time of day
- * @tv:		pointer to the timespec variable containing the new time
- *
- * Sets the time of day to the new time and update NTP and notify hrtimers
- */
-int do_settimeofday(struct timespec *tv)
-{
-	unsigned long flags;
-	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_irqsave(&xtime_lock, flags);
-
-	nsec -= __get_nsec_offset();
-
-	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-	set_normalized_timespec(&xtime, sec, nsec);
-	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-	clock->error = 0;
-	ntp_clear();
-
-	update_vsyscall(&xtime, clock);
-
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-
-	/* signal hrtimers about time change */
-	clock_was_set();
-
-	return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-/**
- * change_clocksource - Swaps clocksources if a new one is available
- *
- * Accumulates current time interval and initializes new clocksource
- */
-static void change_clocksource(void)
-{
-	struct clocksource *new;
-	cycle_t now;
-	u64 nsec;
-
-	new = clocksource_get_next();
-
-	if (clock == new)
-		return;
-
-	now = clocksource_read(new);
-	nsec =  __get_nsec_offset();
-	timespec_add_ns(&xtime, nsec);
-
-	clock = new;
-	clock->cycle_last = now;
-
-	clock->error = 0;
-	clock->xtime_nsec = 0;
-	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
-
-	tick_clock_notify();
-
-	printk(KERN_INFO "Time: %s clocksource has been installed.\n",
-	       clock->name);
-}
-#else
-static inline void change_clocksource(void) { }
-#endif
-
-/**
- * timekeeping_is_continuous - check to see if timekeeping is free running
- */
-int timekeeping_is_continuous(void)
-{
-	unsigned long seq;
-	int ret;
-
-	do {
-		seq = read_seqbegin(&xtime_lock);
-
-		ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
-
-	} while (read_seqretry(&xtime_lock, seq));
-
-	return ret;
-}
-
-/**
- * read_persistent_clock -  Return time in seconds from the persistent clock.
- *
- * Weak dummy function for arches that do not yet support it.
- * Returns seconds from epoch using the battery backed persistent clock.
- * Returns zero if unsupported.
- *
- *  XXX - Do be sure to remove it once all arches implement it.
- */
-unsigned long __attribute__((weak)) read_persistent_clock(void)
-{
-	return 0;
-}
-
-/*
- * timekeeping_init - Initializes the clocksource and common timekeeping values
- */
-void __init timekeeping_init(void)
-{
-	unsigned long flags;
-	unsigned long sec = read_persistent_clock();
-
-	write_seqlock_irqsave(&xtime_lock, flags);
-
-	ntp_clear();
-
-	clock = clocksource_get_next();
-	clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
-	clock->cycle_last = clocksource_read(clock);
-
-	xtime.tv_sec = sec;
-	xtime.tv_nsec = 0;
-	set_normalized_timespec(&wall_to_monotonic,
-		-xtime.tv_sec, -xtime.tv_nsec);
-
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-}
-
-/* flag for if timekeeping is suspended */
-static int timekeeping_suspended;
-/* time in seconds when suspend began */
-static unsigned long timekeeping_suspend_time;
-
-/**
- * timekeeping_resume - Resumes the generic timekeeping subsystem.
- * @dev:	unused
- *
- * This is for the generic clocksource timekeeping.
- * xtime/wall_to_monotonic/jiffies/etc are
- * still managed by arch specific suspend/resume code.
- */
-static int timekeeping_resume(struct sys_device *dev)
-{
-	unsigned long flags;
-	unsigned long now = read_persistent_clock();
-
-	write_seqlock_irqsave(&xtime_lock, flags);
-
-	if (now && (now > timekeeping_suspend_time)) {
-		unsigned long sleep_length = now - timekeeping_suspend_time;
-
-		xtime.tv_sec += sleep_length;
-		wall_to_monotonic.tv_sec -= sleep_length;
-	}
-	/* re-base the last cycle value */
-	clock->cycle_last = clocksource_read(clock);
-	clock->error = 0;
-	timekeeping_suspended = 0;
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-
-	touch_softlockup_watchdog();
-
-	clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
-
-	/* Resume hrtimers */
-	hres_timers_resume();
-
-	return 0;
-}
-
-static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
-{
-	unsigned long flags;
-
-	write_seqlock_irqsave(&xtime_lock, flags);
-	timekeeping_suspended = 1;
-	timekeeping_suspend_time = read_persistent_clock();
-	write_sequnlock_irqrestore(&xtime_lock, flags);
-
-	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
-
-	return 0;
-}
-
-/* sysfs resume/suspend bits for timekeeping */
-static struct sysdev_class timekeeping_sysclass = {
-	.resume		= timekeeping_resume,
-	.suspend	= timekeeping_suspend,
-	set_kset_name("timekeeping"),
-};
-
-static struct sys_device device_timer = {
-	.id		= 0,
-	.cls		= &timekeeping_sysclass,
-};
-
-static int __init timekeeping_init_device(void)
-{
-	int error = sysdev_class_register(&timekeeping_sysclass);
-	if (!error)
-		error = sysdev_register(&device_timer);
-	return error;
-}
-
-device_initcall(timekeeping_init_device);
-
-/*
- * If the error is already larger, we look ahead even further
- * to compensate for late or lost adjustments.
- */
-static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
-						 s64 *offset)
-{
-	s64 tick_error, i;
-	u32 look_ahead, adj;
-	s32 error2, mult;
-
-	/*
-	 * Use the current error value to determine how much to look ahead.
-	 * The larger the error the slower we adjust for it to avoid problems
-	 * with losing too many ticks, otherwise we would overadjust and
-	 * produce an even larger error.  The smaller the adjustment the
-	 * faster we try to adjust for it, as lost ticks can do less harm
-	 * here.  This is tuned so that an error of about 1 msec is adusted
-	 * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
-	 */
-	error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
-	error2 = abs(error2);
-	for (look_ahead = 0; error2 > 0; look_ahead++)
-		error2 >>= 2;
-
-	/*
-	 * Now calculate the error in (1 << look_ahead) ticks, but first
-	 * remove the single look ahead already included in the error.
-	 */
-	tick_error = current_tick_length() >>
-		(TICK_LENGTH_SHIFT - clock->shift + 1);
-	tick_error -= clock->xtime_interval >> 1;
-	error = ((error - tick_error) >> look_ahead) + tick_error;
-
-	/* Finally calculate the adjustment shift value.  */
-	i = *interval;
-	mult = 1;
-	if (error < 0) {
-		error = -error;
-		*interval = -*interval;
-		*offset = -*offset;
-		mult = -1;
-	}
-	for (adj = 0; error > i; adj++)
-		error >>= 1;
-
-	*interval <<= adj;
-	*offset <<= adj;
-	return mult << adj;
-}
-
-/*
- * Adjust the multiplier to reduce the error value,
- * this is optimized for the most common adjustments of -1,0,1,
- * for other values we can do a bit more work.
- */
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
-{
-	s64 error, interval = clock->cycle_interval;
-	int adj;
-
-	error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
-	if (error > interval) {
-		error >>= 2;
-		if (likely(error <= interval))
-			adj = 1;
-		else
-			adj = clocksource_bigadjust(error, &interval, &offset);
-	} else if (error < -interval) {
-		error >>= 2;
-		if (likely(error >= -interval)) {
-			adj = -1;
-			interval = -interval;
-			offset = -offset;
-		} else
-			adj = clocksource_bigadjust(error, &interval, &offset);
-	} else
-		return;
-
-	clock->mult += adj;
-	clock->xtime_interval += interval;
-	clock->xtime_nsec -= offset;
-	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.
- */
-static void update_wall_time(void)
-{
-	cycle_t offset;
-
-	/* Make sure we're fully resumed: */
-	if (unlikely(timekeeping_suspended))
-		return;
-
-#ifdef CONFIG_GENERIC_TIME
-	offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
-#else
-	offset = clock->cycle_interval;
-#endif
-	clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
-
-	/* normally this loop will run just once, however in the
-	 * case of lost or late ticks, it will accumulate correctly.
-	 */
-	while (offset >= clock->cycle_interval) {
-		/* accumulate one interval */
-		clock->xtime_nsec += clock->xtime_interval;
-		clock->cycle_last += clock->cycle_interval;
-		offset -= clock->cycle_interval;
-
-		if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
-			clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
-			xtime.tv_sec++;
-			second_overflow();
-		}
-
-		/* interpolator bits */
-		time_interpolator_update(clock->xtime_interval
-						>> clock->shift);
-
-		/* accumulate error between NTP and clock interval */
-		clock->error += current_tick_length();
-		clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
-	}
-
-	/* correct the clock when NTP error is too big */
-	clocksource_adjust(clock, offset);
-
-	/* store full nanoseconds into xtime */
-	xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
-	clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
-
-	/* check to see if there is a new clocksource to use */
-	change_clocksource();
-	update_vsyscall(&xtime, clock);
-}
-
 /*
  * Called from the timer interrupt handler to charge one tick to the current 
  * process.  user_tick is 1 if the tick is user time, 0 for system.
@@ -1262,14 +857,6 @@ static inline void calc_load(unsigned lo
 }
 
 /*
- * This read-write spinlock protects us from races in SMP while
- * playing with xtime and avenrun.
- */
-__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
-
-EXPORT_SYMBOL(xtime_lock);
-
-/*
  * This function runs timers and the timer-tq in bottom half context.
  */
 static void run_timer_softirq(struct softirq_action *h)
@@ -1615,6 +1202,13 @@ static int __devinit init_timers_cpu(int
 						cpu_to_node(cpu));
 			if (!base)
 				return -ENOMEM;
+
+			/* Make sure that tvec_base is 2 byte aligned */
+			if (tbase_get_deferrable(base)) {
+				WARN_ON(1);
+				kfree(base);
+				return -ENOMEM;
+			}
 			memset(base, 0, sizeof(*base));
 			per_cpu(tvec_bases, cpu) = base;
 		} else {
@@ -1654,9 +1248,9 @@ static void migrate_timer_list(tvec_base
 	struct timer_list *timer;
 
 	while (!list_empty(head)) {
-		timer = list_entry(head->next, struct timer_list, entry);
+		timer = list_first_entry(head, struct timer_list, entry);
 		detach_timer(timer, 0);
-		timer->base = new_base;
+		timer_set_base(timer, new_base);
 		internal_add_timer(new_base, timer);
 	}
 }
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 187e2a4..dd308ba 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -6,7 +6,6 @@
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/mman.h>
-#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/prctl.h>
diff --git a/kernel/utsname.c b/kernel/utsname.c
index c859164..160c8c5 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -32,58 +32,25 @@ static struct uts_namespace *clone_uts_n
 }
 
 /*
- * 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 *copy_utsname(int flags, struct uts_namespace *old_ns)
 {
-	struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
 	struct uts_namespace *new_ns;
-	int err = 0;
-
-	if (!old_ns)
-		return 0;
 
+	BUG_ON(!old_ns);
 	get_uts_ns(old_ns);
 
 	if (!(flags & CLONE_NEWUTS))
-		return 0;
-
-	if (!capable(CAP_SYS_ADMIN)) {
-		err = -EPERM;
-		goto out;
-	}
+		return old_ns;
 
 	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;
+	return new_ns;
 }
 
 void free_uts_ns(struct kref *kref)
diff --git a/lib/Kconfig b/lib/Kconfig
index 3842499..96d6e8c 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -111,4 +111,9 @@ config HAS_IOPORT
 	depends on HAS_IOMEM && !NO_IOPORT
 	default y
 
+config HAS_DMA
+	boolean
+	depends on !NO_DMA
+	default y
+
 endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 3f3e740..ee05b8a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -86,23 +86,6 @@ config DEBUG_SHIRQ
 	  Drivers ought to be able to handle interrupts coming in at those
 	  points; some don't and need to be caught.
 
-config LOG_BUF_SHIFT
-	int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
-	range 12 21
-	default 17 if S390 || LOCKDEP
-	default 16 if X86_NUMAQ || IA64
-	default 15 if SMP
-	default 14
-	help
-	  Select kernel log buffer size as a power of 2.
-	  Defaults and Examples:
-	  	     17 => 128 KB for S/390
-		     16 => 64 KB for x86 NUMAQ or IA-64
-	             15 => 32 KB for SMP
-	             14 => 16 KB for uniprocessor
-		     13 =>  8 KB
-		     12 =>  4 KB
-
 config DETECT_SOFTLOCKUP
 	bool "Detect Soft Lockups"
 	depends on DEBUG_KERNEL && !S390
@@ -201,6 +184,16 @@ config DEBUG_MUTEXES
 	 This feature allows mutex semantics violations to be detected and
 	 reported.
 
+config DEBUG_SEMAPHORE
+	bool "Semaphore debugging"
+	depends on DEBUG_KERNEL
+	depends on ALPHA || FRV
+	default n
+	help
+	  If you say Y here then semaphore processing will issue lots of
+	  verbose debugging messages.  If you suspect a semaphore problem or a
+	  kernel hacker asks for this option then say Y.  Otherwise say N.
+
 config DEBUG_LOCK_ALLOC
 	bool "Lock debugging: detect incorrect freeing of live locks"
 	depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
@@ -261,7 +254,7 @@ config LOCKDEP
 	bool
 	depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
 	select STACKTRACE
-	select FRAME_POINTER if !X86
+	select FRAME_POINTER if !X86 && !MIPS
 	select KALLSYMS
 	select KALLSYMS_ALL
 
@@ -320,7 +313,7 @@ config DEBUG_HIGHMEM
 config DEBUG_BUGVERBOSE
 	bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
 	depends on BUG
-	depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG
+	depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG || BFIN
 	default !EMBEDDED
 	help
 	  Say Y here to make BUG() panics output the file name and line number
@@ -333,6 +326,9 @@ config DEBUG_INFO
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
+	  This adds debug symbols to the kernel and modules (gcc -g), and
+	  is needed if you intend to use kernel crashdump or binary object
+	  tools like crash, kgdb, LKCD, gdb, etc on the kernel.
 	  Say Y here only if you plan to debug the kernel.
 
 	  If unsure, say N.
@@ -357,7 +353,7 @@ config DEBUG_LIST
 
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
-	depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH)
+	depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH || BFIN)
 	default y if DEBUG_INFO && UML
 	help
 	  If you say Y here the resulting kernel image will be slightly larger
diff --git a/lib/Makefile b/lib/Makefile
index 992a39e..ae57f35 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,7 +4,7 @@ #
 
 lib-y := ctype.o string.o vsprintf.o cmdline.o \
 	 rbtree.o radix-tree.o dump_stack.o \
-	 idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
+	 idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \
 	 sha1.o irq_regs.o reciprocal_div.o
 
 lib-$(CONFIG_MMU) += ioremap.o
@@ -12,7 +12,8 @@ lib-$(CONFIG_SMP) += cpumask.o
 
 lib-y	+= kobject.o kref.o kobject_uevent.o klist.o
 
-obj-y += sort.o parser.o halfmd4.o debug_locks.o random32.o bust_spinlocks.o
+obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
+	 bust_spinlocks.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/cpumask.c b/lib/cpumask.c
index 1ea2c18..bb4f76d 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -15,9 +15,6 @@ int __next_cpu(int n, const cpumask_t *s
 }
 EXPORT_SYMBOL(__next_cpu);
 
-int nr_cpu_ids;
-EXPORT_SYMBOL(nr_cpu_ids);
-
 int __any_online_cpu(const cpumask_t *mask)
 {
 	int cpu;
diff --git a/lib/devres.c b/lib/devres.c
index eb38849..b1d336c 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -296,5 +296,31 @@ int pcim_iomap_regions(struct pci_dev *p
 	return rc;
 }
 EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unamp and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+{
+	void __iomem * const *iomap;
+	int i;
+
+	iomap = pcim_iomap_table(pdev);
+	if (!iomap)
+		return;
+
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		if (!(mask & (1 << i)))
+			continue;
+
+		pcim_iounmap(pdev, iomap[i]);
+		pci_release_region(pdev, i);
+	}
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
 #endif
 #endif
diff --git a/lib/div64.c b/lib/div64.c
index 365719f..b71cf93 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -23,7 +23,7 @@ #include <asm/div64.h>
 /* Not needed on 64bit architectures */
 #if BITS_PER_LONG == 32
 
-uint32_t __div64_32(uint64_t *n, uint32_t base)
+uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
 {
 	uint64_t rem = *n;
 	uint64_t b = base;
@@ -58,4 +58,24 @@ uint32_t __div64_32(uint64_t *n, uint32_
 
 EXPORT_SYMBOL(__div64_32);
 
+/* 64bit divisor, dividend and result. dynamic precision */
+uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+{
+	uint32_t high, d;
+
+	high = divisor >> 32;
+	if (high) {
+		unsigned int shift = fls(high);
+
+		d = divisor >> shift;
+		dividend >>= shift;
+	} else
+		d = divisor;
+
+	do_div(dividend, d);
+
+	return dividend;
+}
+EXPORT_SYMBOL(div64_64);
+
 #endif /* BITS_PER_LONG == 32 */
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index 0fabd12..b18fc2f 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -72,9 +72,8 @@ static bool fail_stacktrace(struct fault
 	trace.entries = entries;
 	trace.max_entries = depth;
 	trace.skip = 1;
-	trace.all_contexts = 0;
 
-	save_stack_trace(&trace, NULL);
+	save_stack_trace(&trace);
 	for (n = 0; n < trace.nr_entries; n++) {
 		if (attr->reject_start <= entries[n] &&
 			       entries[n] < attr->reject_end)
diff --git a/lib/inflate.c b/lib/inflate.c
index 6db6e98..845f91d 100644
--- a/lib/inflate.c
+++ b/lib/inflate.c
@@ -292,7 +292,6 @@ STATIC int INIT huft_build(
    oversubscribed set of lengths), and three if not enough memory. */
 {
   unsigned a;                   /* counter for codes of length k */
-  unsigned c[BMAX+1];           /* bit length count table */
   unsigned f;                   /* i repeats in table every f entries */
   int g;                        /* maximum code length */
   int h;                        /* table level */
@@ -303,18 +302,33 @@ STATIC int INIT huft_build(
   register unsigned *p;         /* pointer into c[], b[], or v[] */
   register struct huft *q;      /* points to current table */
   struct huft r;                /* table entry for structure assignment */
-  struct huft *u[BMAX];         /* table stack */
-  unsigned v[N_MAX];            /* values in order of bit length */
   register int w;               /* bits before this table == (l * h) */
-  unsigned x[BMAX+1];           /* bit offsets, then code stack */
   unsigned *xp;                 /* pointer into x */
   int y;                        /* number of dummy codes added */
   unsigned z;                   /* number of entries in current table */
+  struct {
+    unsigned c[BMAX+1];           /* bit length count table */
+    struct huft *u[BMAX];         /* table stack */
+    unsigned v[N_MAX];            /* values in order of bit length */
+    unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  } *stk;
+  unsigned *c, *v, *x;
+  struct huft **u;
+  int ret;
 
 DEBG("huft1 ");
 
+  stk = malloc(sizeof(*stk));
+  if (stk == NULL)
+    return 3;			/* out of memory */
+
+  c = stk->c;
+  v = stk->v;
+  x = stk->x;
+  u = stk->u;
+
   /* Generate counts for each bit length */
-  memzero(c, sizeof(c));
+  memzero(stk->c, sizeof(stk->c));
   p = b;  i = n;
   do {
     Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), 
@@ -326,7 +340,8 @@ DEBG("huft1 ");
   {
     *t = (struct huft *)NULL;
     *m = 0;
-    return 2;
+    ret = 2;
+    goto out;
   }
 
 DEBG("huft2 ");
@@ -351,10 +366,14 @@ DEBG("huft3 ");
 
   /* Adjust last length count to fill out codes, if needed */
   for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return 2;                 /* bad input: more codes than bits */
-  if ((y -= c[i]) < 0)
-    return 2;
+    if ((y -= c[j]) < 0) {
+      ret = 2;                 /* bad input: more codes than bits */
+      goto out;
+    }
+  if ((y -= c[i]) < 0) {
+    ret = 2;
+    goto out;
+  }
   c[i] += y;
 
 DEBG("huft4 ");
@@ -428,7 +447,8 @@ DEBG1("3 ");
         {
           if (h)
             huft_free(u[0]);
-          return 3;             /* not enough memory */
+          ret = 3;             /* not enough memory */
+	  goto out;
         }
 DEBG1("4 ");
         hufts += z + 1;         /* track memory usage */
@@ -492,7 +512,11 @@ DEBG("h6f ");
 DEBG("huft7 ");
 
   /* Return true (1) if we were given an incomplete table */
-  return y != 0 && g != 1;
+  ret = y != 0 && g != 1;
+
+  out:
+  free(stk);
+  return ret;
 }
 
 
@@ -705,10 +729,14 @@ STATIC int noinline INIT inflate_fixed(v
   struct huft *td;      /* distance code table */
   int bl;               /* lookup bits for tl */
   int bd;               /* lookup bits for td */
-  unsigned l[288];      /* length list for huft_build */
+  unsigned *l;          /* length list for huft_build */
 
 DEBG("<fix");
 
+  l = malloc(sizeof(*l) * 288);
+  if (l == NULL)
+    return 3;			/* out of memory */
+
   /* set up literal table */
   for (i = 0; i < 144; i++)
     l[i] = 8;
@@ -719,9 +747,10 @@ DEBG("<fix");
   for (; i < 288; i++)          /* make a complete, but wrong code set */
     l[i] = 8;
   bl = 7;
-  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+    free(l);
     return i;
-
+  }
 
   /* set up distance table */
   for (i = 0; i < 30; i++)      /* make an incomplete code set */
@@ -730,6 +759,7 @@ DEBG("<fix");
   if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
   {
     huft_free(tl);
+    free(l);
 
     DEBG(">");
     return i;
@@ -737,11 +767,13 @@ DEBG("<fix");
 
 
   /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
+  if (inflate_codes(tl, td, bl, bd)) {
+    free(l);
     return 1;
-
+  }
 
   /* free the decoding tables, return */
+  free(l);
   huft_free(tl);
   huft_free(td);
   return 0;
@@ -766,16 +798,19 @@ STATIC int noinline INIT inflate_dynamic
   unsigned nb;          /* number of bit length codes */
   unsigned nl;          /* number of literal/length codes */
   unsigned nd;          /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
-  unsigned ll[288+32];  /* literal/length and distance code lengths */
-#else
-  unsigned ll[286+30];  /* literal/length and distance code lengths */
-#endif
+  unsigned *ll;         /* literal/length and distance code lengths */
   register ulg b;       /* bit buffer */
   register unsigned k;  /* number of bits in bit buffer */
+  int ret;
 
 DEBG("<dyn");
 
+#ifdef PKZIP_BUG_WORKAROUND
+  ll = malloc(sizeof(*ll) * (288+32));  /* literal/length and distance code lengths */
+#else
+  ll = malloc(sizeof(*ll) * (286+30));  /* literal/length and distance code lengths */
+#endif
+
   /* make local bit buffer */
   b = bb;
   k = bk;
@@ -796,7 +831,10 @@ #ifdef PKZIP_BUG_WORKAROUND
 #else
   if (nl > 286 || nd > 30)
 #endif
-    return 1;                   /* bad lengths */
+  {
+    ret = 1;             /* bad lengths */
+    goto out;
+  }
 
 DEBG("dyn1 ");
 
@@ -818,7 +856,8 @@ DEBG("dyn2 ");
   {
     if (i == 1)
       huft_free(tl);
-    return i;                   /* incomplete code set */
+    ret = i;                   /* incomplete code set */
+    goto out;
   }
 
 DEBG("dyn3 ");
@@ -840,8 +879,10 @@ DEBG("dyn3 ");
       NEEDBITS(2)
       j = 3 + ((unsigned)b & 3);
       DUMPBITS(2)
-      if ((unsigned)i + j > n)
-        return 1;
+      if ((unsigned)i + j > n) {
+        ret = 1;
+	goto out;
+      }
       while (j--)
         ll[i++] = l;
     }
@@ -850,8 +891,10 @@ DEBG("dyn3 ");
       NEEDBITS(3)
       j = 3 + ((unsigned)b & 7);
       DUMPBITS(3)
-      if ((unsigned)i + j > n)
-        return 1;
+      if ((unsigned)i + j > n) {
+        ret = 1;
+	goto out;
+      }
       while (j--)
         ll[i++] = 0;
       l = 0;
@@ -861,8 +904,10 @@ DEBG("dyn3 ");
       NEEDBITS(7)
       j = 11 + ((unsigned)b & 0x7f);
       DUMPBITS(7)
-      if ((unsigned)i + j > n)
-        return 1;
+      if ((unsigned)i + j > n) {
+        ret = 1;
+	goto out;
+      }
       while (j--)
         ll[i++] = 0;
       l = 0;
@@ -891,7 +936,8 @@ DEBG("dyn5b ");
       error("incomplete literal tree");
       huft_free(tl);
     }
-    return i;                   /* incomplete code set */
+    ret = i;                   /* incomplete code set */
+    goto out;
   }
 DEBG("dyn5c ");
   bd = dbits;
@@ -907,15 +953,18 @@ #else
       huft_free(td);
     }
     huft_free(tl);
-    return i;                   /* incomplete code set */
+    ret = i;                   /* incomplete code set */
+    goto out;
 #endif
   }
 
 DEBG("dyn6 ");
 
   /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
-    return 1;
+  if (inflate_codes(tl, td, bl, bd)) {
+    ret = 1;
+    goto out;
+  }
 
 DEBG("dyn7 ");
 
@@ -924,10 +973,14 @@ DEBG("dyn7 ");
   huft_free(td);
 
   DEBG(">");
-  return 0;
-
- underrun:
-  return 4;			/* Input underrun */
+  ret = 0;
+out:
+  free(ll);
+  return ret;
+
+underrun:
+  ret = 4;			/* Input underrun */
+  goto out;
 }
 
 
diff --git a/lib/iomap.c b/lib/iomap.c
index 4d43f37..a57d262 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -35,20 +35,28 @@ #define PIO_MASK	0x0ffffUL
 #define PIO_RESERVED	0x40000UL
 #endif
 
+static void bad_io_access(unsigned long port, const char *access)
+{
+	static int count = 10;
+	if (count) {
+		count--;
+		printk(KERN_ERR "Bad IO access at port %lx (%s)\n", port, access);
+		WARN_ON(1);
+	}
+}
+
 /*
  * Ugly macros are a way of life.
  */
-#define VERIFY_PIO(port) BUG_ON((port & ~PIO_MASK) != PIO_OFFSET)
-
 #define IO_COND(addr, is_pio, is_mmio) do {			\
 	unsigned long port = (unsigned long __force)addr;	\
-	if (port < PIO_RESERVED) {				\
-		VERIFY_PIO(port);				\
+	if (port >= PIO_RESERVED) {				\
+		is_mmio;					\
+	} else if (port > PIO_OFFSET) {				\
 		port &= PIO_MASK;				\
 		is_pio;						\
-	} else {						\
-		is_mmio;					\
-	}							\
+	} else							\
+		bad_io_access(port, #is_pio );			\
 } while (0)
 
 #ifndef pio_read16be
@@ -64,22 +72,27 @@ #endif
 unsigned int fastcall ioread8(void __iomem *addr)
 {
 	IO_COND(addr, return inb(port), return readb(addr));
+	return 0xff;
 }
 unsigned int fastcall ioread16(void __iomem *addr)
 {
 	IO_COND(addr, return inw(port), return readw(addr));
+	return 0xffff;
 }
 unsigned int fastcall ioread16be(void __iomem *addr)
 {
 	IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr));
+	return 0xffff;
 }
 unsigned int fastcall ioread32(void __iomem *addr)
 {
 	IO_COND(addr, return inl(port), return readl(addr));
+	return 0xffffffff;
 }
 unsigned int fastcall ioread32be(void __iomem *addr)
 {
 	IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr));
+	return 0xffffffff;
 }
 EXPORT_SYMBOL(ioread8);
 EXPORT_SYMBOL(ioread16);
diff --git a/lib/kobject.c b/lib/kobject.c
index 057921c..fc5f3f6 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -157,7 +157,7 @@ static void unlink(struct kobject * kobj
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
+ *	kobject_shadow_add - add an object to the hierarchy.
  *	@kobj:	object.
  *	@shadow_parent: sysfs directory to add to.
  */
@@ -174,6 +174,7 @@ int kobject_shadow_add(struct kobject * 
 	if (!*kobj->k_name) {
 		pr_debug("kobject attempted to be registered with no name!\n");
 		WARN_ON(1);
+		kobject_put(kobj);
 		return -EINVAL;
 	}
 	parent = kobject_get(kobj->parent);
@@ -190,8 +191,8 @@ int kobject_shadow_add(struct kobject * 
 
 		list_add_tail(&kobj->entry,&kobj->kset->list);
 		spin_unlock(&kobj->kset->list_lock);
+		kobj->parent = parent;
 	}
-	kobj->parent = parent;
 
 	error = create_dir(kobj, shadow_parent);
 	if (error) {
@@ -311,13 +312,43 @@ EXPORT_SYMBOL(kobject_set_name);
 int kobject_rename(struct kobject * kobj, const char *new_name)
 {
 	int error = 0;
+	const char *devpath = NULL;
+	char *devpath_string = NULL;
+	char *envp[2];
 
 	kobj = kobject_get(kobj);
 	if (!kobj)
 		return -EINVAL;
 	if (!kobj->parent)
 		return -EINVAL;
+
+	devpath = kobject_get_path(kobj, GFP_KERNEL);
+	if (!devpath) {
+		error = -ENOMEM;
+		goto out;
+	}
+	devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
+	if (!devpath_string) {
+		error = -ENOMEM;
+		goto out;
+	}
+	sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
+	envp[0] = devpath_string;
+	envp[1] = NULL;
+	/* Note : if we want to send the new name alone, not the full path,
+	 * we could probably use kobject_name(kobj); */
+
 	error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+
+	/* This function is mostly/only used for network interface.
+	 * Some hotplug package track interfaces by their name and
+	 * therefore want to know when the name is changed by the user. */
+	if (!error)
+		kobject_uevent_env(kobj, KOBJ_MOVE, envp);
+
+out:
+	kfree(devpath_string);
+	kfree(devpath);
 	kobject_put(kobj);
 
 	return error;
@@ -488,13 +519,15 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *	kobject_add_dir - add sub directory of object.
+ *	kobject_kset_add_dir - add sub directory of object.
+ *	@kset:		kset the directory is belongs to.
  *	@parent:	object in which a directory is created.
  *	@name:	directory name.
  *
  *	Add a plain directory object as child of given object.
  */
-struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+struct kobject *kobject_kset_add_dir(struct kset *kset,
+				     struct kobject *parent, const char *name)
 {
 	struct kobject *k;
 	int ret;
@@ -506,13 +539,14 @@ struct kobject *kobject_add_dir(struct k
 	if (!k)
 		return NULL;
 
+	k->kset = kset;
 	k->parent = parent;
 	k->ktype = &dir_ktype;
 	kobject_set_name(k, name);
 	ret = kobject_register(k);
 	if (ret < 0) {
-		printk(KERN_WARNING "kobject_add_dir: "
-			"kobject_register error: %d\n", ret);
+		printk(KERN_WARNING "%s: kobject_register error: %d\n",
+			__func__, ret);
 		kobject_del(k);
 		return NULL;
 	}
@@ -521,6 +555,18 @@ struct kobject *kobject_add_dir(struct k
 }
 
 /**
+ *	kobject_add_dir - add sub directory of object.
+ *	@parent:	object in which a directory is created.
+ *	@name:	directory name.
+ *
+ *	Add a plain directory object as child of given object.
+ */
+struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
+{
+	return kobject_kset_add_dir(NULL, parent, name);
+}
+
+/**
  *	kset_init - initialize a kset for use
  *	@k:	kset 
  */
@@ -536,22 +582,10 @@ void kset_init(struct kset * k)
 /**
  *	kset_add - add a kset object to the hierarchy.
  *	@k:	kset.
- *
- *	Simply, this adds the kset's embedded kobject to the 
- *	hierarchy. 
- *	We also try to make sure that the kset's embedded kobject
- *	has a parent before it is added. We only care if the embedded
- *	kobject is not part of a kset itself, since kobject_add()
- *	assigns a parent in that case. 
- *	If that is the case, and the kset has a controlling subsystem,
- *	then we set the kset's parent to be said subsystem. 
  */
 
 int kset_add(struct kset * k)
 {
-	if (!k->kobj.parent && !k->kobj.kset && k->subsys)
-		k->kobj.parent = &k->subsys->kset.kobj;
-
 	return kobject_add(&k->kobj);
 }
 
@@ -610,55 +644,28 @@ struct kobject * kset_find_obj(struct ks
 	return ret;
 }
 
-
-void subsystem_init(struct subsystem * s)
+void subsystem_init(struct kset *s)
 {
-	init_rwsem(&s->rwsem);
-	kset_init(&s->kset);
+	kset_init(s);
 }
 
-/**
- *	subsystem_register - register a subsystem.
- *	@s:	the subsystem we're registering.
- *
- *	Once we register the subsystem, we want to make sure that 
- *	the kset points back to this subsystem for correct usage of 
- *	the rwsem. 
- */
-
-int subsystem_register(struct subsystem * s)
+int subsystem_register(struct kset *s)
 {
-	int error;
-
-	if (!s)
-		return -EINVAL;
-
-	subsystem_init(s);
-	pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
-
-	if (!(error = kset_add(&s->kset))) {
-		if (!s->kset.subsys)
-			s->kset.subsys = s;
-	}
-	return error;
+	return kset_register(s);
 }
 
-void subsystem_unregister(struct subsystem * s)
+void subsystem_unregister(struct kset *s)
 {
-	if (!s)
-		return;
-	pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
-	kset_unregister(&s->kset);
+	kset_unregister(s);
 }
 
-
 /**
  *	subsystem_create_file - export sysfs attribute file.
  *	@s:	subsystem.
  *	@a:	subsystem attribute descriptor.
  */
 
-int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
+int subsys_create_file(struct kset *s, struct subsys_attribute *a)
 {
 	int error = 0;
 
@@ -666,28 +673,12 @@ int subsys_create_file(struct subsystem 
 		return -EINVAL;
 
 	if (subsys_get(s)) {
-		error = sysfs_create_file(&s->kset.kobj,&a->attr);
+		error = sysfs_create_file(&s->kobj, &a->attr);
 		subsys_put(s);
 	}
 	return error;
 }
 
-
-/**
- *	subsystem_remove_file - remove sysfs attribute file.
- *	@s:	subsystem.
- *	@a:	attribute desciptor.
- */
-#if 0
-void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
-{
-	if (subsys_get(s)) {
-		sysfs_remove_file(&s->kset.kobj,&a->attr);
-		subsys_put(s);
-	}
-}
-#endif  /*  0  */
-
 EXPORT_SYMBOL(kobject_init);
 EXPORT_SYMBOL(kobject_register);
 EXPORT_SYMBOL(kobject_unregister);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 84272ed..12e311d 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -42,10 +42,6 @@ static char *action_to_string(enum kobje
 		return "remove";
 	case KOBJ_CHANGE:
 		return "change";
-	case KOBJ_MOUNT:
-		return "mount";
-	case KOBJ_UMOUNT:
-		return "umount";
 	case KOBJ_OFFLINE:
 		return "offline";
 	case KOBJ_ONLINE:
@@ -95,10 +91,8 @@ int kobject_uevent_env(struct kobject *k
 
 	/* search the kset we belong to */
 	top_kobj = kobj;
-	if (!top_kobj->kset && top_kobj->parent) {
-		do {
-			top_kobj = top_kobj->parent;
-		} while (!top_kobj->kset && top_kobj->parent);
+	while (!top_kobj->kset && top_kobj->parent) {
+		top_kobj = top_kobj->parent;
 	}
 	if (!top_kobj->kset) {
 		pr_debug("kobject attempted to send uevent without kset!\n");
@@ -115,6 +109,16 @@ int kobject_uevent_env(struct kobject *k
 			return 0;
 		}
 
+	/* originating subsystem */
+	if (uevent_ops && uevent_ops->name)
+		subsystem = uevent_ops->name(kset, kobj);
+	else
+		subsystem = kobject_name(&kset->kobj);
+	if (!subsystem) {
+		pr_debug("unset subsytem caused the event to drop!\n");
+		return 0;
+	}
+
 	/* environment index */
 	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
 	if (!envp)
@@ -134,12 +138,6 @@ int kobject_uevent_env(struct kobject *k
 		goto exit;
 	}
 
-	/* originating subsystem */
-	if (uevent_ops && uevent_ops->name)
-		subsystem = uevent_ops->name(kset, kobj);
-	else
-		subsystem = kobject_name(&kset->kobj);
-
 	/* event environemnt for helper process only */
 	envp[i++] = "HOME=/";
 	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
@@ -293,7 +291,7 @@ #if defined(CONFIG_NET)
 static int __init kobject_uevent_init(void)
 {
 	uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, 1, NULL,
-					    THIS_MODULE);
+					    NULL, THIS_MODULE);
 
 	if (!uevent_sock) {
 		printk(KERN_ERR
diff --git a/lib/kref.c b/lib/kref.c
index 0d07cc3..a6dc3ec 100644
--- a/lib/kref.c
+++ b/lib/kref.c
@@ -21,6 +21,7 @@ #include <linux/module.h>
 void kref_init(struct kref *kref)
 {
 	atomic_set(&kref->refcount,1);
+	smp_mb();
 }
 
 /**
@@ -31,6 +32,7 @@ void kref_get(struct kref *kref)
 {
 	WARN_ON(!atomic_read(&kref->refcount));
 	atomic_inc(&kref->refcount);
+	smp_mb__after_atomic_inc();
 }
 
 /**
diff --git a/lib/parser.c b/lib/parser.c
index 7ad2a48..703c8c1 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -22,7 +22,7 @@ #include <linux/string.h>
  * match extremely simple token=arg style patterns. If the pattern is found,
  * the location(s) of the arguments will be returned in the @args array.
  */
-static int match_one(char *s, char *p, substring_t args[])
+static int match_one(char *s, const char *p, substring_t args[])
 {
 	char *meta;
 	int argc = 0;
@@ -43,7 +43,7 @@ static int match_one(char *s, char *p, s
 		p = meta + 1;
 
 		if (isdigit(*p))
-			len = simple_strtoul(p, &p, 10);
+			len = simple_strtoul(p, (char **) &p, 10);
 		else if (*p == '%') {
 			if (*s++ != '%')
 				return 0;
@@ -102,7 +102,7 @@ static int match_one(char *s, char *p, s
  */
 int match_token(char *s, match_table_t table, substring_t args[])
 {
-	struct match_token *p;
+	const struct match_token *p;
 
 	for (p = table; !match_one(s, p->pattern, args) ; p++)
 		;
@@ -190,7 +190,7 @@ int match_hex(substring_t *s, int *resul
  * &substring_t @s to the c-style string @to. Caller guarantees that @to is
  * large enough to hold the characters of @s.
  */
-void match_strcpy(char *to, substring_t *s)
+void match_strcpy(char *to, const substring_t *s)
 {
 	memcpy(to, s->from, s->to - s->from);
 	to[s->to - s->from] = '\0';
@@ -204,7 +204,7 @@ void match_strcpy(char *to, substring_t 
  * the &substring_t @s. The caller is responsible for freeing the returned
  * string with kfree().
  */
-char *match_strdup(substring_t *s)
+char *match_strdup(const substring_t *s)
 {
 	char *p = kmalloc(s->to - s->from + 1, GFP_KERNEL);
 	if (p)
diff --git a/lib/string.c b/lib/string.c
index bab440f..5efafed 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -60,6 +60,34 @@ int strnicmp(const char *s1, const char 
 EXPORT_SYMBOL(strnicmp);
 #endif
 
+#ifndef __HAVE_ARCH_STRCASECMP
+int strcasecmp(const char *s1, const char *s2)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while (c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
+EXPORT_SYMBOL(strcasecmp);
+#endif
+
+#ifndef __HAVE_ARCH_STRNCASECMP
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while ((--n > 0) && c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
+EXPORT_SYMBOL(strncasecmp);
+#endif
+
 #ifndef __HAVE_ARCH_STRCPY
 /**
  * strcpy - Copy a %NUL terminated string
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 9970e55..10c13ad 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -778,7 +778,6 @@ swiotlb_dma_supported(struct device *hwd
 	return virt_to_bus(io_tlb_end - 1) <= mask;
 }
 
-EXPORT_SYMBOL(swiotlb_init);
 EXPORT_SYMBOL(swiotlb_map_single);
 EXPORT_SYMBOL(swiotlb_unmap_single);
 EXPORT_SYMBOL(swiotlb_map_sg);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b025864..0172902 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -825,6 +825,17 @@ int vsscanf(const char * buf, const char
 			break;
 		str = next;
 	}
+
+	/*
+	 * Now we've come all the way through so either the input string or the
+	 * format ended. In the former case, there can be a %n at the current
+	 * position in the format that needs to be filled.
+	 */
+	if (*fmt == '%' && *(fmt + 1) == 'n') {
+		int *p = (int *)va_arg(args, int *);
+		*p = str - buf;
+	}
+
 	return num;
 }
 
@@ -851,23 +862,35 @@ EXPORT_SYMBOL(sscanf);
 
 
 /* Simplified asprintf. */
-char *kasprintf(gfp_t gfp, const char *fmt, ...)
+char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
 {
-	va_list ap;
 	unsigned int len;
 	char *p;
+	va_list aq;
 
-	va_start(ap, fmt);
-	len = vsnprintf(NULL, 0, fmt, ap);
-	va_end(ap);
+	va_copy(aq, ap);
+	len = vsnprintf(NULL, 0, fmt, aq);
+	va_end(aq);
 
 	p = kmalloc(len+1, gfp);
 	if (!p)
 		return NULL;
-	va_start(ap, fmt);
+
 	vsnprintf(p, len+1, fmt, ap);
-	va_end(ap);
+
 	return p;
 }
+EXPORT_SYMBOL(kvasprintf);
 
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+	va_list ap;
+	char *p;
+
+	va_start(ap, fmt);
+	p = kvasprintf(gfp, fmt, ap);
+	va_end(ap);
+
+	return p;
+}
 EXPORT_SYMBOL(kasprintf);
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index fceb97c..7e1e311 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -743,12 +743,14 @@ #endif
 
     strm->data_type = state->bits + (state->last ? 64 : 0) +
                       (state->mode == TYPE ? 128 : 0);
-    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
-        ret = Z_BUF_ERROR;
 
     if (flush == Z_PACKET_FLUSH && ret == Z_OK &&
-            (strm->avail_out != 0 || strm->avail_in == 0))
+            strm->avail_out != 0 && strm->avail_in == 0)
 		return zlib_inflateSyncPacket(strm);
+
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+
     return ret;
 }
 
diff --git a/mm/Kconfig b/mm/Kconfig
index 7942b33..1ac718f 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -163,3 +163,8 @@ config ZONE_DMA_FLAG
 	default "0" if !ZONE_DMA
 	default "1"
 
+config NR_QUICK
+	int
+	depends on QUICKLIST
+	default "1"
+
diff --git a/mm/Makefile b/mm/Makefile
index f3c077e..a9148ea 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -25,7 +25,10 @@ obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_a
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
 obj-$(CONFIG_SLOB) += slob.o
 obj-$(CONFIG_SLAB) += slab.o
+obj-$(CONFIG_SLUB) += slub.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
+obj-$(CONFIG_QUICKLIST) += quicklist.o
+
diff --git a/mm/filemap.c b/mm/filemap.c
index 5dfc093..9cbf4fe 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -868,6 +868,7 @@ void do_generic_mapping_read(struct addr
 	unsigned long last_index;
 	unsigned long next_index;
 	unsigned long prev_index;
+	unsigned int prev_offset;
 	loff_t isize;
 	struct page *cached_page;
 	int error;
@@ -876,7 +877,8 @@ void do_generic_mapping_read(struct addr
 	cached_page = NULL;
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	next_index = index;
-	prev_index = ra.prev_page;
+	prev_index = ra.prev_index;
+	prev_offset = ra.prev_offset;
 	last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
 	offset = *ppos & ~PAGE_CACHE_MASK;
 
@@ -924,10 +926,10 @@ page_ok:
 			flush_dcache_page(page);
 
 		/*
-		 * When (part of) the same page is read multiple times
-		 * in succession, only mark it as accessed the first time.
+		 * When a sequential read accesses a page several times,
+		 * only mark it as accessed the first time.
 		 */
-		if (prev_index != index)
+		if (prev_index != index || offset != prev_offset)
 			mark_page_accessed(page);
 		prev_index = index;
 
@@ -945,6 +947,8 @@ page_ok:
 		offset += ret;
 		index += offset >> PAGE_CACHE_SHIFT;
 		offset &= ~PAGE_CACHE_MASK;
+		prev_offset = offset;
+		ra.prev_offset = offset;
 
 		page_cache_release(page);
 		if (ret == nr && desc->count)
@@ -1106,6 +1110,45 @@ success:
 	return size;
 }
 
+/*
+ * Performs necessary checks before doing a write
+ * @iov:	io vector request
+ * @nr_segs:	number of segments in the iovec
+ * @count:	number of bytes to write
+ * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE
+ *
+ * Adjust number of segments and amount of bytes to write (nr_segs should be
+ * properly initialized first). Returns appropriate error code that caller
+ * should return or zero in case that write should be allowed.
+ */
+int generic_segment_checks(const struct iovec *iov,
+			unsigned long *nr_segs, size_t *count, int access_flags)
+{
+	unsigned long   seg;
+	size_t cnt = 0;
+	for (seg = 0; seg < *nr_segs; seg++) {
+		const struct iovec *iv = &iov[seg];
+
+		/*
+		 * If any segment has a negative length, or the cumulative
+		 * length ever wraps negative then return -EINVAL.
+		 */
+		cnt += iv->iov_len;
+		if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
+			return -EINVAL;
+		if (access_ok(access_flags, iv->iov_base, iv->iov_len))
+			continue;
+		if (seg == 0)
+			return -EFAULT;
+		*nr_segs = seg;
+		cnt -= iv->iov_len;	/* This segment is no good */
+		break;
+	}
+	*count = cnt;
+	return 0;
+}
+EXPORT_SYMBOL(generic_segment_checks);
+
 /**
  * generic_file_aio_read - generic filesystem read routine
  * @iocb:	kernel I/O control block
@@ -1127,24 +1170,9 @@ generic_file_aio_read(struct kiocb *iocb
 	loff_t *ppos = &iocb->ki_pos;
 
 	count = 0;
-	for (seg = 0; seg < nr_segs; seg++) {
-		const struct iovec *iv = &iov[seg];
-
-		/*
-		 * If any segment has a negative length, or the cumulative
-		 * length ever wraps negative then return -EINVAL.
-		 */
-		count += iv->iov_len;
-		if (unlikely((ssize_t)(count|iv->iov_len) < 0))
-			return -EINVAL;
-		if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
-			continue;
-		if (seg == 0)
-			return -EFAULT;
-		nr_segs = seg;
-		count -= iv->iov_len;	/* This segment is no good */
-		break;
-	}
+	retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
+	if (retval)
+		return retval;
 
 	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
 	if (filp->f_flags & O_DIRECT) {
@@ -1446,30 +1474,6 @@ page_not_uptodate:
 		majmin = VM_FAULT_MAJOR;
 		count_vm_event(PGMAJFAULT);
 	}
-	lock_page(page);
-
-	/* Did it get unhashed while we waited for it? */
-	if (!page->mapping) {
-		unlock_page(page);
-		page_cache_release(page);
-		goto retry_all;
-	}
-
-	/* Did somebody else get it up-to-date? */
-	if (PageUptodate(page)) {
-		unlock_page(page);
-		goto success;
-	}
-
-	error = mapping->a_ops->readpage(file, page);
-	if (!error) {
-		wait_on_page_locked(page);
-		if (PageUptodate(page))
-			goto success;
-	} else if (error == AOP_TRUNCATED_PAGE) {
-		page_cache_release(page);
-		goto retry_find;
-	}
 
 	/*
 	 * Umm, take care of errors if the page isn't up-to-date.
@@ -1726,7 +1730,7 @@ #endif /* CONFIG_MMU */
 EXPORT_SYMBOL(generic_file_mmap);
 EXPORT_SYMBOL(generic_file_readonly_mmap);
 
-static inline struct page *__read_cache_page(struct address_space *mapping,
+static struct page *__read_cache_page(struct address_space *mapping,
 				unsigned long index,
 				int (*filler)(void *,struct page*),
 				void *data)
@@ -1763,17 +1767,11 @@ repeat:
 	return page;
 }
 
-/**
- * read_cache_page - read into page cache, fill it if needed
- * @mapping:	the page's address_space
- * @index:	the page index
- * @filler:	function to perform the read
- * @data:	destination for read data
- *
- * Read into the page cache. If a page already exists,
- * and PageUptodate() is not set, try to fill the page.
+/*
+ * Same as read_cache_page, but don't wait for page to become unlocked
+ * after submitting it to the filler.
  */
-struct page *read_cache_page(struct address_space *mapping,
+struct page *read_cache_page_async(struct address_space *mapping,
 				unsigned long index,
 				int (*filler)(void *,struct page*),
 				void *data)
@@ -1805,6 +1803,39 @@ retry:
 		page = ERR_PTR(err);
 	}
  out:
+	mark_page_accessed(page);
+	return page;
+}
+EXPORT_SYMBOL(read_cache_page_async);
+
+/**
+ * read_cache_page - read into page cache, fill it if needed
+ * @mapping:	the page's address_space
+ * @index:	the page index
+ * @filler:	function to perform the read
+ * @data:	destination for read data
+ *
+ * Read into the page cache. If a page already exists, and PageUptodate() is
+ * not set, try to fill the page then wait for it to become unlocked.
+ *
+ * If the page does not get brought uptodate, return -EIO.
+ */
+struct page *read_cache_page(struct address_space *mapping,
+				unsigned long index,
+				int (*filler)(void *,struct page*),
+				void *data)
+{
+	struct page *page;
+
+	page = read_cache_page_async(mapping, index, filler, data);
+	if (IS_ERR(page))
+		goto out;
+	wait_on_page_locked(page);
+	if (!PageUptodate(page)) {
+		page_cache_release(page);
+		page = ERR_PTR(-EIO);
+	}
+ out:
 	return page;
 }
 EXPORT_SYMBOL(read_cache_page);
@@ -2211,30 +2242,14 @@ __generic_file_aio_write_nolock(struct k
 	size_t ocount;		/* original count */
 	size_t count;		/* after file limit checks */
 	struct inode 	*inode = mapping->host;
-	unsigned long	seg;
 	loff_t		pos;
 	ssize_t		written;
 	ssize_t		err;
 
 	ocount = 0;
-	for (seg = 0; seg < nr_segs; seg++) {
-		const struct iovec *iv = &iov[seg];
-
-		/*
-		 * If any segment has a negative length, or the cumulative
-		 * length ever wraps negative then return -EINVAL.
-		 */
-		ocount += iv->iov_len;
-		if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
-			return -EINVAL;
-		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
-			continue;
-		if (seg == 0)
-			return -EFAULT;
-		nr_segs = seg;
-		ocount -= iv->iov_len;	/* This segment is no good */
-		break;
-	}
+	err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
+	if (err)
+		return err;
 
 	count = ocount;
 	pos = *ppos;
@@ -2294,10 +2309,10 @@ __generic_file_aio_write_nolock(struct k
 		 * 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);
+		err = do_sync_mapping_range(file->f_mapping, 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,
diff --git a/mm/highmem.c b/mm/highmem.c
index 51e1c19..be8f8d3 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -99,6 +99,15 @@ static void flush_all_zero_pkmaps(void)
 	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
+/* Flush all unused kmap mappings in order to remove stray
+   mappings. */
+void kmap_flush_unused(void)
+{
+	spin_lock(&kmap_lock);
+	flush_all_zero_pkmaps();
+	spin_unlock(&kmap_lock);
+}
+
 static inline unsigned long map_new_virtual(struct page *page)
 {
 	unsigned long vaddr;
diff --git a/mm/internal.h b/mm/internal.h
index d527b80..a3110c0 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -24,7 +24,7 @@ static inline void set_page_count(struct
  */
 static inline void set_page_refcounted(struct page *page)
 {
-	VM_BUG_ON(PageCompound(page) && page_private(page) != (unsigned long)page);
+	VM_BUG_ON(PageCompound(page) && PageTail(page));
 	VM_BUG_ON(atomic_read(&page->_count));
 	set_page_count(page, 1);
 }
diff --git a/mm/madvise.c b/mm/madvise.c
index 603c525..e75096b 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -12,6 +12,24 @@ #include <linux/mempolicy.h>
 #include <linux/hugetlb.h>
 
 /*
+ * Any behaviour which results in changes to the vma->vm_flags needs to
+ * take mmap_sem for writing. Others, which simply traverse vmas, need
+ * to only take it for reading.
+ */
+static int madvise_need_mmap_write(int behavior)
+{
+	switch (behavior) {
+	case MADV_REMOVE:
+	case MADV_WILLNEED:
+	case MADV_DONTNEED:
+		return 0;
+	default:
+		/* be safe, default to 1. list exceptions explicitly */
+		return 1;
+	}
+}
+
+/*
  * We can potentially split a vm area into separate
  * areas, each area with its own behavior.
  */
@@ -183,9 +201,9 @@ static long madvise_remove(struct vm_are
 			+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
 
 	/* vmtruncate_range needs to take i_mutex and i_alloc_sem */
-	up_write(&current->mm->mmap_sem);
+	up_read(&current->mm->mmap_sem);
 	error = vmtruncate_range(mapping->host, offset, endoff);
-	down_write(&current->mm->mmap_sem);
+	down_read(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -270,7 +288,10 @@ asmlinkage long sys_madvise(unsigned lon
 	int error = -EINVAL;
 	size_t len;
 
-	down_write(&current->mm->mmap_sem);
+	if (madvise_need_mmap_write(behavior))
+		down_write(&current->mm->mmap_sem);
+	else
+		down_read(&current->mm->mmap_sem);
 
 	if (start & ~PAGE_MASK)
 		goto out;
@@ -332,6 +353,10 @@ asmlinkage long sys_madvise(unsigned lon
 			vma = find_vma(current->mm, start);
 	}
 out:
-	up_write(&current->mm->mmap_sem);
+	if (madvise_need_mmap_write(behavior))
+		up_write(&current->mm->mmap_sem);
+	else
+		up_read(&current->mm->mmap_sem);
+
 	return error;
 }
diff --git a/mm/memory.c b/mm/memory.c
index e7066e7..1d647ab 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1448,6 +1448,100 @@ int remap_pfn_range(struct vm_area_struc
 }
 EXPORT_SYMBOL(remap_pfn_range);
 
+static 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 *uninitialized_var(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 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 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);
+
 /*
  * handle_pte_fault chooses page fault handler according to an entry
  * which was read non-atomically.  Before making any commitment, on
@@ -2539,12 +2633,6 @@ int __pud_alloc(struct mm_struct *mm, pg
 	spin_unlock(&mm->page_table_lock);
 	return 0;
 }
-#else
-/* Workaround for gcc 2.96 */
-int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
-{
-	return 0;
-}
 #endif /* __PAGETABLE_PUD_FOLDED */
 
 #ifndef __PAGETABLE_PMD_FOLDED
@@ -2573,12 +2661,6 @@ #endif /* __ARCH_HAS_4LEVEL_HACK */
 	spin_unlock(&mm->page_table_lock);
 	return 0;
 }
-#else
-/* Workaround for gcc 2.96 */
-int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
-{
-	return 0;
-}
 #endif /* __PAGETABLE_PMD_FOLDED */
 
 int make_pages_present(unsigned long addr, unsigned long end)
diff --git a/mm/mmap.c b/mm/mmap.c
index 84f997d..cc1f543 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -29,6 +29,7 @@ #include <linux/rmap.h>
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
+#include <asm/mmu_context.h>
 
 #ifndef arch_mmap_check
 #define arch_mmap_check(addr, len, flags)	(0)
@@ -1199,6 +1200,9 @@ arch_get_unmapped_area(struct file *filp
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED)
+		return addr;
+
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
 		vma = find_vma(mm, addr);
@@ -1272,6 +1276,9 @@ arch_get_unmapped_area_topdown(struct fi
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
+	if (flags & MAP_FIXED)
+		return addr;
+
 	/* requesting a specific address */
 	if (addr) {
 		addr = PAGE_ALIGN(addr);
@@ -1359,39 +1366,21 @@ unsigned long
 get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
 		unsigned long pgoff, unsigned long flags)
 {
-	unsigned long ret;
-
-	if (!(flags & MAP_FIXED)) {
-		unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
-
-		get_area = current->mm->get_unmapped_area;
-		if (file && file->f_op && file->f_op->get_unmapped_area)
-			get_area = file->f_op->get_unmapped_area;
-		addr = get_area(file, addr, len, pgoff, flags);
-		if (IS_ERR_VALUE(addr))
-			return addr;
-	}
+	unsigned long (*get_area)(struct file *, unsigned long,
+				  unsigned long, unsigned long, unsigned long);
+
+	get_area = current->mm->get_unmapped_area;
+	if (file && file->f_op && file->f_op->get_unmapped_area)
+		get_area = file->f_op->get_unmapped_area;
+	addr = get_area(file, addr, len, pgoff, flags);
+	if (IS_ERR_VALUE(addr))
+		return addr;
 
 	if (addr > TASK_SIZE - len)
 		return -ENOMEM;
 	if (addr & ~PAGE_MASK)
 		return -EINVAL;
-	if (file && is_file_hugepages(file))  {
-		/*
-		 * Check if the given range is hugepage aligned, and
-		 * can be made suitable for hugepages.
-		 */
-		ret = prepare_hugepage_range(addr, len, pgoff);
-	} else {
-		/*
-		 * Ensure that a normal request is not falling in a
-		 * reserved hugepage range.  For some archs like IA-64,
-		 * there is a separate region for hugepages.
-		 */
-		ret = is_hugepage_only_range(current->mm, addr, len);
-	}
-	if (ret)
-		return -EINVAL;
+
 	return addr;
 }
 
@@ -1979,6 +1968,9 @@ void exit_mmap(struct mm_struct *mm)
 	unsigned long nr_accounted = 0;
 	unsigned long end;
 
+	/* mm's last user has gone, and its about to be pulled down */
+	arch_exit_mmap(mm);
+
 	lru_add_drain();
 	flush_cache_mm(mm);
 	tlb = tlb_gather_mmu(mm, 1);
diff --git a/mm/nommu.c b/mm/nommu.c
index 1f60194..2b16b00 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -262,6 +262,14 @@ void vunmap(void *addr)
 }
 
 /*
+ * Implement a stub for vmalloc_sync_all() if the architecture chose not to
+ * have one.
+ */
+void  __attribute__((weak)) vmalloc_sync_all(void)
+{
+}
+
+/*
  *  sys_brk() for the most part doesn't need the global kernel
  *  lock, except when an application is doing something nasty
  *  like trying to un-brk an area that has already been mapped
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 3791edf..a700141 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -147,9 +147,11 @@ unsigned long badness(struct task_struct
 	 * Adjust the score by oomkilladj.
 	 */
 	if (p->oomkilladj) {
-		if (p->oomkilladj > 0)
+		if (p->oomkilladj > 0) {
+			if (!points)
+				points = 1;
 			points <<= p->oomkilladj;
-		else
+		} else
 			points >>= -(p->oomkilladj);
 	}
 
@@ -397,6 +399,7 @@ void out_of_memory(struct zonelist *zone
 	struct task_struct *p;
 	unsigned long points = 0;
 	unsigned long freed = 0;
+	int constraint;
 
 	blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
 	if (freed > 0)
@@ -411,14 +414,18 @@ void out_of_memory(struct zonelist *zone
 		show_mem();
 	}
 
-	cpuset_lock();
-	read_lock(&tasklist_lock);
+	if (sysctl_panic_on_oom == 2)
+		panic("out of memory. Compulsory panic_on_oom is selected.\n");
 
 	/*
 	 * Check if there were limitations on the allocation (only relevant for
 	 * NUMA) that may require different handling.
 	 */
-	switch (constrained_alloc(zonelist, gfp_mask)) {
+	constraint = constrained_alloc(zonelist, gfp_mask);
+	cpuset_lock();
+	read_lock(&tasklist_lock);
+
+	switch (constraint) {
 	case CONSTRAINT_MEMORY_POLICY:
 		oom_kill_process(current, points,
 				"No available memory (MPOL_BIND)");
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index f469e3c..63cd888 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -67,12 +67,12 @@ static inline long sync_writeback_pages(
 /*
  * Start background writeback (via pdflush) at this percentage
  */
-int dirty_background_ratio = 10;
+int dirty_background_ratio = 5;
 
 /*
  * The generator of dirty data starts writeback at this percentage
  */
-int vm_dirty_ratio = 40;
+int vm_dirty_ratio = 10;
 
 /*
  * The interval between `kupdate'-style writebacks, in jiffies
@@ -119,6 +119,44 @@ static void background_writeout(unsigned
  * We make sure that the background writeout level is below the adjusted
  * clamping level.
  */
+
+static unsigned long highmem_dirtyable_memory(unsigned long total)
+{
+#ifdef CONFIG_HIGHMEM
+	int node;
+	unsigned long x = 0;
+
+	for_each_online_node(node) {
+		struct zone *z =
+			&NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
+
+		x += zone_page_state(z, NR_FREE_PAGES)
+			+ zone_page_state(z, NR_INACTIVE)
+			+ zone_page_state(z, NR_ACTIVE);
+	}
+	/*
+	 * Make sure that the number of highmem pages is never larger
+	 * than the number of the total dirtyable memory. This can only
+	 * occur in very strange VM situations but we want to make sure
+	 * that this does not occur.
+	 */
+	return min(x, total);
+#else
+	return 0;
+#endif
+}
+
+static unsigned long determine_dirtyable_memory(void)
+{
+	unsigned long x;
+
+	x = global_page_state(NR_FREE_PAGES)
+		+ global_page_state(NR_INACTIVE)
+		+ global_page_state(NR_ACTIVE);
+	x -= highmem_dirtyable_memory(x);
+	return x + 1;	/* Ensure that we never return 0 */
+}
+
 static void
 get_dirty_limits(long *pbackground, long *pdirty,
 					struct address_space *mapping)
@@ -128,20 +166,12 @@ get_dirty_limits(long *pbackground, long
 	int unmapped_ratio;
 	long background;
 	long dirty;
-	unsigned long available_memory = vm_total_pages;
+	unsigned long available_memory = determine_dirtyable_memory();
 	struct task_struct *tsk;
 
-#ifdef CONFIG_HIGHMEM
-	/*
-	 * We always exclude high memory from our count.
-	 */
-	available_memory -= totalhigh_pages;
-#endif
-
-
 	unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) +
 				global_page_state(NR_ANON_PAGES)) * 100) /
-					vm_total_pages;
+					available_memory;
 
 	dirty_ratio = vm_dirty_ratio;
 	if (dirty_ratio > unmapped_ratio / 2)
@@ -653,12 +683,7 @@ retry:
 			}
 
 			ret = (*writepage)(page, wbc);
-			if (ret) {
-				if (ret == -ENOSPC)
-					set_bit(AS_ENOSPC, &mapping->flags);
-				else
-					set_bit(AS_EIO, &mapping->flags);
-			}
+			mapping_set_error(mapping, ret);
 
 			if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
 				unlock_page(page);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 353ce90..6fd0b74 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -103,7 +103,7 @@ int min_free_kbytes = 1024;
 
 unsigned long __meminitdata nr_kernel_pages;
 unsigned long __meminitdata nr_all_pages;
-static unsigned long __initdata dma_reserve;
+static unsigned long __meminitdata dma_reserve;
 
 #ifdef CONFIG_ARCH_POPULATES_NODE_MAP
   /*
@@ -126,10 +126,10 @@ #ifdef CONFIG_ARCH_POPULATES_NODE_MAP
     #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];
+  struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS];
+  int __meminitdata nr_nodemap_entries;
+  unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
+  unsigned long __meminitdata 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];
@@ -156,10 +156,8 @@ static int page_outside_zone_boundaries(
 
 static int page_is_consistent(struct zone *zone, struct page *page)
 {
-#ifdef CONFIG_HOLES_IN_ZONE
-	if (!pfn_valid(page_to_pfn(page)))
+	if (!pfn_valid_within(page_to_pfn(page)))
 		return 0;
-#endif
 	if (zone != page_zone(page))
 		return 0;
 
@@ -227,7 +225,7 @@ static void bad_page(struct page *page)
 
 static void free_compound_page(struct page *page)
 {
-	__free_pages_ok(page, (unsigned long)page[1].lru.prev);
+	__free_pages_ok(page, compound_order(page));
 }
 
 static void prep_compound_page(struct page *page, unsigned long order)
@@ -236,12 +234,13 @@ static void prep_compound_page(struct pa
 	int nr_pages = 1 << order;
 
 	set_compound_page_dtor(page, free_compound_page);
-	page[1].lru.prev = (void *)order;
-	for (i = 0; i < nr_pages; i++) {
+	set_compound_order(page, order);
+	__SetPageHead(page);
+	for (i = 1; i < nr_pages; i++) {
 		struct page *p = page + i;
 
-		__SetPageCompound(p);
-		set_page_private(p, (unsigned long)page);
+		__SetPageTail(p);
+		p->first_page = page;
 	}
 }
 
@@ -250,16 +249,19 @@ static void destroy_compound_page(struct
 	int i;
 	int nr_pages = 1 << order;
 
-	if (unlikely((unsigned long)page[1].lru.prev != order))
+	if (unlikely(compound_order(page) != order))
 		bad_page(page);
 
-	for (i = 0; i < nr_pages; i++) {
+	if (unlikely(!PageHead(page)))
+			bad_page(page);
+	__ClearPageHead(page);
+	for (i = 1; i < nr_pages; i++) {
 		struct page *p = page + i;
 
-		if (unlikely(!PageCompound(p) |
-				(page_private(p) != (unsigned long)page)))
+		if (unlikely(!PageTail(p) |
+				(p->first_page != page)))
 			bad_page(page);
-		__ClearPageCompound(p);
+		__ClearPageTail(p);
 	}
 }
 
@@ -346,10 +348,8 @@ __find_combined_index(unsigned long page
 static inline int page_is_buddy(struct page *page, struct page *buddy,
 								int order)
 {
-#ifdef CONFIG_HOLES_IN_ZONE
-	if (!pfn_valid(page_to_pfn(buddy)))
+	if (!pfn_valid_within(page_to_pfn(buddy)))
 		return 0;
-#endif
 
 	if (page_zone_id(page) != page_zone_id(buddy))
 		return 0;
@@ -433,13 +433,18 @@ static inline int free_pages_check(struc
 			1 << PG_private |
 			1 << PG_locked	|
 			1 << PG_active	|
-			1 << PG_reclaim	|
 			1 << PG_slab	|
 			1 << PG_swapcache |
 			1 << PG_writeback |
 			1 << PG_reserved |
 			1 << PG_buddy ))))
 		bad_page(page);
+	/*
+	 * PageReclaim == PageTail. It is only an error
+	 * for PageReclaim to be set if PageCompound is clear.
+	 */
+	if (unlikely(!PageCompound(page) && PageReclaim(page)))
+		bad_page(page);
 	if (PageDirty(page))
 		__ClearPageDirty(page);
 	/*
@@ -665,7 +670,7 @@ static int rmqueue_bulk(struct zone *zon
 }
 
 #if MAX_NUMNODES > 1
-int nr_node_ids __read_mostly;
+int nr_node_ids __read_mostly = MAX_NUMNODES;
 EXPORT_SYMBOL(nr_node_ids);
 
 /*
@@ -770,8 +775,8 @@ void mark_free_pages(struct zone *zone)
 		if (pfn_valid(pfn)) {
 			struct page *page = pfn_to_page(pfn);
 
-			if (!PageNosave(page))
-				ClearPageNosaveFree(page);
+			if (!swsusp_page_is_forbidden(page))
+				swsusp_unset_page_free(page);
 		}
 
 	for (order = MAX_ORDER - 1; order >= 0; --order)
@@ -780,7 +785,7 @@ void mark_free_pages(struct zone *zone)
 
 			pfn = page_to_pfn(list_entry(curr, struct page, lru));
 			for (i = 0; i < (1UL << order); i++)
-				SetPageNosaveFree(pfn_to_page(pfn + i));
+				swsusp_set_page_free(pfn_to_page(pfn + i));
 		}
 
 	spin_unlock_irqrestore(&zone->lock, flags);
@@ -2174,7 +2179,7 @@ void __init setup_per_cpu_pageset(void)
 
 #endif
 
-static __meminit
+static __meminit noinline
 int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
 {
 	int i;
@@ -2262,7 +2267,7 @@ #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)
+static int __meminit first_active_region_index_in_nid(int nid)
 {
 	int i;
 
@@ -2277,7 +2282,7 @@ static int __init first_active_region_in
  * 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)
+static int __meminit 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)
@@ -2430,7 +2435,7 @@ #endif
  * 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,
+void __meminit get_pfn_range_for_nid(unsigned int nid,
 			unsigned long *start_pfn, unsigned long *end_pfn)
 {
 	int i;
@@ -2455,7 +2460,7 @@ void __init get_pfn_range_for_nid(unsign
  * 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 __meminit zone_spanned_pages_in_node(int nid,
 					unsigned long zone_type,
 					unsigned long *ignored)
 {
@@ -2483,7 +2488,7 @@ unsigned long __init zone_spanned_pages_
  * 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 __meminit __absent_pages_in_range(int nid,
 				unsigned long range_start_pfn,
 				unsigned long range_end_pfn)
 {
@@ -2543,7 +2548,7 @@ unsigned long __init absent_pages_in_ran
 }
 
 /* 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 __meminit zone_absent_pages_in_node(int nid,
 					unsigned long zone_type,
 					unsigned long *ignored)
 {
@@ -2579,7 +2584,7 @@ static inline unsigned long zone_absent_
 
 #endif
 
-static void __init calculate_node_totalpages(struct pglist_data *pgdat,
+static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
 		unsigned long *zones_size, unsigned long *zholes_size)
 {
 	unsigned long realtotalpages, totalpages = 0;
@@ -2687,7 +2692,7 @@ #endif
 	}
 }
 
-static void __init alloc_node_mem_map(struct pglist_data *pgdat)
+static void __meminit alloc_node_mem_map(struct pglist_data *pgdat)
 {
 	/* Skip empty nodes */
 	if (!pgdat->node_spanned_pages)
@@ -3203,7 +3208,8 @@ int min_free_kbytes_sysctl_handler(ctl_t
 	struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
 {
 	proc_dointvec(table, write, file, buffer, length, ppos);
-	setup_per_zone_pages_min();
+	if (write)
+		setup_per_zone_pages_min();
 	return 0;
 }
 
diff --git a/mm/quicklist.c b/mm/quicklist.c
new file mode 100644
index 0000000..ae8189c
--- /dev/null
+++ b/mm/quicklist.c
@@ -0,0 +1,88 @@
+/*
+ * Quicklist support.
+ *
+ * Quicklists are light weight lists of pages that have a defined state
+ * on alloc and free. Pages must be in the quicklist specific defined state
+ * (zero by default) when the page is freed. It seems that the initial idea
+ * for such lists first came from Dave Miller and then various other people
+ * improved on it.
+ *
+ * Copyright (C) 2007 SGI,
+ * 	Christoph Lameter <clameter@sgi.com>
+ * 		Generalized, added support for multiple lists and
+ * 		constructors / destructors.
+ */
+#include <linux/kernel.h>
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/module.h>
+#include <linux/quicklist.h>
+
+DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+
+#define FRACTION_OF_NODE_MEM	16
+
+static unsigned long max_pages(unsigned long min_pages)
+{
+	unsigned long node_free_pages, max;
+
+	node_free_pages = node_page_state(numa_node_id(),
+			NR_FREE_PAGES);
+	max = node_free_pages / FRACTION_OF_NODE_MEM;
+	return max(max, min_pages);
+}
+
+static long min_pages_to_free(struct quicklist *q,
+	unsigned long min_pages, long max_free)
+{
+	long pages_to_free;
+
+	pages_to_free = q->nr_pages - max_pages(min_pages);
+
+	return min(pages_to_free, max_free);
+}
+
+/*
+ * Trim down the number of pages in the quicklist
+ */
+void quicklist_trim(int nr, void (*dtor)(void *),
+	unsigned long min_pages, unsigned long max_free)
+{
+	long pages_to_free;
+	struct quicklist *q;
+
+	q = &get_cpu_var(quicklist)[nr];
+	if (q->nr_pages > min_pages) {
+		pages_to_free = min_pages_to_free(q, min_pages, max_free);
+
+		while (pages_to_free > 0) {
+			/*
+			 * We pass a gfp_t of 0 to quicklist_alloc here
+			 * because we will never call into the page allocator.
+			 */
+			void *p = quicklist_alloc(nr, 0, NULL);
+
+			if (dtor)
+				dtor(p);
+			free_page((unsigned long)p);
+			pages_to_free--;
+		}
+	}
+	put_cpu_var(quicklist);
+}
+
+unsigned long quicklist_total_size(void)
+{
+	unsigned long count = 0;
+	int cpu;
+	struct quicklist *ql, *q;
+
+	for_each_online_cpu(cpu) {
+		ql = per_cpu(quicklist, cpu);
+		for (q = ql; q < ql + CONFIG_NR_QUICK; q++)
+			count += q->nr_pages;
+	}
+	return count;
+}
+
diff --git a/mm/readahead.c b/mm/readahead.c
index 93d9ee6..9861e88 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -37,7 +37,7 @@ void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
 {
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
-	ra->prev_page = -1;
+	ra->prev_index = -1;
 }
 EXPORT_SYMBOL_GPL(file_ra_state_init);
 
@@ -202,17 +202,19 @@ out:
  * size:	Number of pages in that read
  *              Together, these form the "current window".
  *              Together, start and size represent the `readahead window'.
- * prev_page:   The page which the readahead algorithm most-recently inspected.
+ * prev_index:  The page which the readahead algorithm most-recently inspected.
  *              It is mainly used to detect sequential file reading.
  *              If page_cache_readahead sees that it is again being called for
  *              a page which it just looked at, it can return immediately without
  *              making any state changes.
+ * offset:      Offset in the prev_index where the last read ended - used for
+ *              detection of sequential file reading.
  * ahead_start,
  * ahead_size:  Together, these form the "ahead window".
  * ra_pages:	The externally controlled max readahead for this fd.
  *
  * When readahead is in the off state (size == 0), readahead is disabled.
- * In this state, prev_page is used to detect the resumption of sequential I/O.
+ * In this state, prev_index is used to detect the resumption of sequential I/O.
  *
  * The readahead code manages two windows - the "current" and the "ahead"
  * windows.  The intent is that while the application is walking the pages
@@ -415,7 +417,7 @@ static int make_ahead_window(struct addr
 	ra->ahead_size = get_next_ra_size(ra);
 	ra->ahead_start = ra->start + ra->size;
 
-	block = force || (ra->prev_page >= ra->ahead_start);
+	block = force || (ra->prev_index >= ra->ahead_start);
 	ret = blockable_page_cache_readahead(mapping, filp,
 			ra->ahead_start, ra->ahead_size, ra, block);
 
@@ -467,12 +469,13 @@ page_cache_readahead(struct address_spac
 	 * We avoid doing extra work and bogusly perturbing the readahead
 	 * window expansion logic.
 	 */
-	if (offset == ra->prev_page && --req_size)
+	if (offset == ra->prev_index && --req_size)
 		++offset;
 
-	/* Note that prev_page == -1 if it is a first read */
-	sequential = (offset == ra->prev_page + 1);
-	ra->prev_page = offset;
+	/* Note that prev_index == -1 if it is a first read */
+	sequential = (offset == ra->prev_index + 1);
+	ra->prev_index = offset;
+	ra->prev_offset = 0;
 
 	max = get_max_readahead(ra);
 	newsize = min(req_size, max);
@@ -481,7 +484,7 @@ page_cache_readahead(struct address_spac
 	if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE))
 		goto out;
 
-	ra->prev_page += newsize - 1;
+	ra->prev_index += newsize - 1;
 
 	/*
 	 * Special case - first read at start of file. We'll assume it's
@@ -537,18 +540,18 @@ page_cache_readahead(struct address_spac
 	 * we get called back on the first page of the ahead window which
 	 * will allow us to submit more IO.
 	 */
-	if (ra->prev_page >= ra->ahead_start) {
+	if (ra->prev_index >= ra->ahead_start) {
 		ra->start = ra->ahead_start;
 		ra->size = ra->ahead_size;
 		make_ahead_window(mapping, filp, ra, 0);
 recheck:
-		/* prev_page shouldn't overrun the ahead window */
-		ra->prev_page = min(ra->prev_page,
+		/* prev_index shouldn't overrun the ahead window */
+		ra->prev_index = min(ra->prev_index,
 			ra->ahead_start + ra->ahead_size - 1);
 	}
 
 out:
-	return ra->prev_page + 1;
+	return ra->prev_index + 1;
 }
 EXPORT_SYMBOL_GPL(page_cache_readahead);
 
diff --git a/mm/rmap.c b/mm/rmap.c
index b82146e..304f519 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -162,8 +162,7 @@ void anon_vma_unlink(struct vm_area_stru
 static void anon_vma_ctor(void *data, struct kmem_cache *cachep,
 			  unsigned long flags)
 {
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-						SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		struct anon_vma *anon_vma = data;
 
 		spin_lock_init(&anon_vma->lock);
@@ -498,12 +497,15 @@ int page_mkclean(struct page *page)
 		struct address_space *mapping = page_mapping(page);
 		if (mapping)
 			ret = page_mkclean_file(mapping, page);
-		if (page_test_and_clear_dirty(page))
+		if (page_test_dirty(page)) {
+			page_clear_dirty(page);
 			ret = 1;
+		}
 	}
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(page_mkclean);
 
 /**
  * page_set_anon_rmap - setup new anonymous rmap
@@ -605,8 +607,10 @@ void page_remove_rmap(struct page *page,
 		 * Leaving it set also helps swapoff to reinstate ptes
 		 * faster for those pages still in swapcache.
 		 */
-		if (page_test_and_clear_dirty(page))
+		if (page_test_dirty(page)) {
+			page_clear_dirty(page);
 			set_page_dirty(page);
+		}
 		__dec_zone_page_state(page,
 				PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED);
 	}
diff --git a/mm/shmem.c b/mm/shmem.c
index b2a35eb..f01e8de 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2358,8 +2358,7 @@ static void init_once(void *foo, struct 
 {
 	struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&p->vfs_inode);
 #ifdef CONFIG_TMPFS_POSIX_ACL
 		p->i_acl = NULL;
diff --git a/mm/slab.c b/mm/slab.c
index 4cbac24..acda7e2 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -116,8 +116,7 @@ #include	<asm/tlbflush.h>
 #include	<asm/page.h>
 
 /*
- * DEBUG	- 1 for kmem_cache_create() to honour; SLAB_DEBUG_INITIAL,
- *		  SLAB_RED_ZONE & SLAB_POISON.
+ * DEBUG	- 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON.
  *		  0 for faster, smaller code (especially in the critical paths).
  *
  * STATS	- 1 to collect stats for /proc/slabinfo.
@@ -149,10 +148,11 @@ #ifndef ARCH_KMALLOC_MINALIGN
  * Usually, the kmalloc caches are cache_line_size() aligned, except when
  * DEBUG and FORCED_DEBUG are enabled, then they are BYTES_PER_WORD aligned.
  * Some archs want to perform DMA into kmalloc caches and need a guaranteed
- * alignment larger than BYTES_PER_WORD. ARCH_KMALLOC_MINALIGN allows that.
- * Note that this flag disables some debug features.
+ * alignment larger than the alignment of a 64-bit integer.
+ * ARCH_KMALLOC_MINALIGN allows that.
+ * Note that increasing this value may disable some debug features.
  */
-#define ARCH_KMALLOC_MINALIGN 0
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
 #endif
 
 #ifndef ARCH_SLAB_MINALIGN
@@ -172,15 +172,15 @@ #endif
 
 /* Legal flag mask for kmem_cache_create(). */
 #if DEBUG
-# define CREATE_MASK	(SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
+# define CREATE_MASK	(SLAB_RED_ZONE | \
 			 SLAB_POISON | SLAB_HWCACHE_ALIGN | \
 			 SLAB_CACHE_DMA | \
-			 SLAB_MUST_HWCACHE_ALIGN | SLAB_STORE_USER | \
+			 SLAB_STORE_USER | \
 			 SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
 			 SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
 #else
 # define CREATE_MASK	(SLAB_HWCACHE_ALIGN | \
-			 SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN | \
+			 SLAB_CACHE_DMA | \
 			 SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
 			 SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
 #endif
@@ -389,7 +389,6 @@ struct kmem_cache {
 	unsigned int buffer_size;
 	u32 reciprocal_buffer_size;
 /* 3) touched by every alloc & free from the backend */
-	struct kmem_list3 *nodelists[MAX_NUMNODES];
 
 	unsigned int flags;		/* constant flags */
 	unsigned int num;		/* # of objs per slab */
@@ -444,6 +443,17 @@ #if DEBUG
 	int obj_offset;
 	int obj_size;
 #endif
+	/*
+	 * We put nodelists[] at the end of kmem_cache, because we want to size
+	 * this array to nr_node_ids slots instead of MAX_NUMNODES
+	 * (see kmem_cache_init())
+	 * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache
+	 * is statically defined, so we reserve the max number of nodes.
+	 */
+	struct kmem_list3 *nodelists[MAX_NUMNODES];
+	/*
+	 * Do not add fields after nodelists[]
+	 */
 };
 
 #define CFLGS_OFF_SLAB		(0x80000000UL)
@@ -527,19 +537,22 @@ static int obj_size(struct kmem_cache *c
 	return cachep->obj_size;
 }
 
-static unsigned long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
+static unsigned long long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
 {
 	BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
-	return (unsigned long*) (objp+obj_offset(cachep)-BYTES_PER_WORD);
+	return (unsigned long long*) (objp + obj_offset(cachep) -
+				      sizeof(unsigned long long));
 }
 
-static unsigned long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
+static unsigned long long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
 {
 	BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
 	if (cachep->flags & SLAB_STORE_USER)
-		return (unsigned long *)(objp + cachep->buffer_size -
-					 2 * BYTES_PER_WORD);
-	return (unsigned long *)(objp + cachep->buffer_size - BYTES_PER_WORD);
+		return (unsigned long long *)(objp + cachep->buffer_size -
+					      sizeof(unsigned long long) -
+					      BYTES_PER_WORD);
+	return (unsigned long long *) (objp + cachep->buffer_size -
+				       sizeof(unsigned long long));
 }
 
 static void **dbg_userword(struct kmem_cache *cachep, void *objp)
@@ -552,8 +565,8 @@ #else
 
 #define obj_offset(x)			0
 #define obj_size(cachep)		(cachep->buffer_size)
-#define dbg_redzone1(cachep, objp)	({BUG(); (unsigned long *)NULL;})
-#define dbg_redzone2(cachep, objp)	({BUG(); (unsigned long *)NULL;})
+#define dbg_redzone1(cachep, objp)	({BUG(); (unsigned long long *)NULL;})
+#define dbg_redzone2(cachep, objp)	({BUG(); (unsigned long long *)NULL;})
 #define dbg_userword(cachep, objp)	({BUG(); (void **)NULL;})
 
 #endif
@@ -592,8 +605,7 @@ static inline void page_set_cache(struct
 
 static inline struct kmem_cache *page_get_cache(struct page *page)
 {
-	if (unlikely(PageCompound(page)))
-		page = (struct page *)page_private(page);
+	page = compound_head(page);
 	BUG_ON(!PageSlab(page));
 	return (struct kmem_cache *)page->lru.next;
 }
@@ -605,21 +617,19 @@ static inline void page_set_slab(struct 
 
 static inline struct slab *page_get_slab(struct page *page)
 {
-	if (unlikely(PageCompound(page)))
-		page = (struct page *)page_private(page);
 	BUG_ON(!PageSlab(page));
 	return (struct slab *)page->lru.prev;
 }
 
 static inline struct kmem_cache *virt_to_cache(const void *obj)
 {
-	struct page *page = virt_to_page(obj);
+	struct page *page = virt_to_head_page(obj);
 	return page_get_cache(page);
 }
 
 static inline struct slab *virt_to_slab(const void *obj)
 {
-	struct page *page = virt_to_page(obj);
+	struct page *page = virt_to_head_page(obj);
 	return page_get_slab(page);
 }
 
@@ -678,9 +688,6 @@ static struct kmem_cache cache_cache = {
 	.shared = 1,
 	.buffer_size = sizeof(struct kmem_cache),
 	.name = "kmem_cache",
-#if DEBUG
-	.obj_size = sizeof(struct kmem_cache),
-#endif
 };
 
 #define BAD_ALIEN_MAGIC 0x01020304ul
@@ -1146,7 +1153,7 @@ static inline int cache_free_alien(struc
 	 * Make sure we are not freeing a object from another node to the array
 	 * cache on this cpu.
 	 */
-	if (likely(slabp->nodeid == node) || unlikely(!use_alien_caches))
+	if (likely(slabp->nodeid == node))
 		return 0;
 
 	l3 = cachep->nodelists[node];
@@ -1223,19 +1230,20 @@ static int __cpuinit cpuup_callback(stru
 		 */
 		list_for_each_entry(cachep, &cache_chain, next) {
 			struct array_cache *nc;
-			struct array_cache *shared;
+			struct array_cache *shared = NULL;
 			struct array_cache **alien = NULL;
 
 			nc = alloc_arraycache(node, cachep->limit,
 						cachep->batchcount);
 			if (!nc)
 				goto bad;
-			shared = alloc_arraycache(node,
+			if (cachep->shared) {
+				shared = alloc_arraycache(node,
 					cachep->shared * cachep->batchcount,
 					0xbaadf00d);
-			if (!shared)
-				goto bad;
-
+				if (!shared)
+					goto bad;
+			}
 			if (use_alien_caches) {
                                 alien = alloc_alien_cache(node, cachep->limit);
                                 if (!alien)
@@ -1317,8 +1325,8 @@ #endif
 
 			shared = l3->shared;
 			if (shared) {
-				free_block(cachep, l3->shared->entry,
-					   l3->shared->avail, node);
+				free_block(cachep, shared->entry,
+					   shared->avail, node);
 				l3->shared = NULL;
 			}
 
@@ -1394,6 +1402,9 @@ void __init kmem_cache_init(void)
 	int order;
 	int node;
 
+	if (num_possible_nodes() == 1)
+		use_alien_caches = 0;
+
 	for (i = 0; i < NUM_INIT_LISTS; i++) {
 		kmem_list3_init(&initkmem_list3[i]);
 		if (i < MAX_NUMNODES)
@@ -1436,6 +1447,15 @@ void __init kmem_cache_init(void)
 	cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
 	cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];
 
+	/*
+	 * struct kmem_cache size depends on nr_node_ids, which
+	 * can be less than MAX_NUMNODES.
+	 */
+	cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
+				 nr_node_ids * sizeof(struct kmem_list3 *);
+#if DEBUG
+	cache_cache.obj_size = cache_cache.buffer_size;
+#endif
 	cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
 					cache_line_size());
 	cache_cache.reciprocal_buffer_size =
@@ -1760,7 +1780,7 @@ static void print_objinfo(struct kmem_ca
 	char *realobj;
 
 	if (cachep->flags & SLAB_RED_ZONE) {
-		printk(KERN_ERR "Redzone: 0x%lx/0x%lx.\n",
+		printk(KERN_ERR "Redzone: 0x%llx/0x%llx.\n",
 			*dbg_redzone1(cachep, objp),
 			*dbg_redzone2(cachep, objp));
 	}
@@ -1929,7 +1949,7 @@ static void slab_destroy(struct kmem_cac
  * For setting up all the kmem_list3s for cache whose buffer_size is same as
  * size of kmem_list3.
  */
-static void set_up_list3s(struct kmem_cache *cachep, int index)
+static void __init set_up_list3s(struct kmem_cache *cachep, int index)
 {
 	int node;
 
@@ -2151,13 +2171,15 @@ kmem_cache_create (const char *name, siz
 		 */
 		res = probe_kernel_address(pc->name, tmp);
 		if (res) {
-			printk("SLAB: cache with size %d has lost its name\n",
+			printk(KERN_ERR
+			       "SLAB: cache with size %d has lost its name\n",
 			       pc->buffer_size);
 			continue;
 		}
 
 		if (!strcmp(pc->name, name)) {
-			printk("kmem_cache_create: duplicate cache %s\n", name);
+			printk(KERN_ERR
+			       "kmem_cache_create: duplicate cache %s\n", name);
 			dump_stack();
 			goto oops;
 		}
@@ -2165,12 +2187,6 @@ kmem_cache_create (const char *name, siz
 
 #if DEBUG
 	WARN_ON(strchr(name, ' '));	/* It confuses parsers */
-	if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
-		/* No constructor, but inital state check requested */
-		printk(KERN_ERR "%s: No con, but init state check "
-		       "requested - %s\n", __FUNCTION__, name);
-		flags &= ~SLAB_DEBUG_INITIAL;
-	}
 #if FORCED_DEBUG
 	/*
 	 * Enable redzoning and last user accounting, except for caches with
@@ -2227,7 +2243,7 @@ #endif
 	 * is greater than BYTES_PER_WORD.
 	 */
 	if (flags & SLAB_RED_ZONE || flags & SLAB_STORE_USER)
-		ralign = BYTES_PER_WORD;
+		ralign = __alignof__(unsigned long long);
 
 	/* 2) arch mandated alignment */
 	if (ralign < ARCH_SLAB_MINALIGN) {
@@ -2238,7 +2254,7 @@ #endif
 		ralign = align;
 	}
 	/* disable debug if necessary */
-	if (ralign > BYTES_PER_WORD)
+	if (ralign > __alignof__(unsigned long long))
 		flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
 	/*
 	 * 4) Store it.
@@ -2259,8 +2275,8 @@ #if DEBUG
 	 */
 	if (flags & SLAB_RED_ZONE) {
 		/* add space for red zone words */
-		cachep->obj_offset += BYTES_PER_WORD;
-		size += 2 * BYTES_PER_WORD;
+		cachep->obj_offset += sizeof(unsigned long long);
+		size += 2 * sizeof(unsigned long long);
 	}
 	if (flags & SLAB_STORE_USER) {
 		/* user store requires one word storage behind the end of
@@ -2294,7 +2310,8 @@ #endif
 	left_over = calculate_slab_order(cachep, size, align, flags);
 
 	if (!cachep->num) {
-		printk("kmem_cache_create: couldn't create cache %s.\n", name);
+		printk(KERN_ERR
+		       "kmem_cache_create: couldn't create cache %s.\n", name);
 		kmem_cache_free(&cache_cache, cachep);
 		cachep = NULL;
 		goto oops;
@@ -2733,19 +2750,10 @@ static int cache_grow(struct kmem_cache 
 	 * Be lazy and only check for valid flags here,  keeping it out of the
 	 * critical path in kmem_cache_alloc().
 	 */
-	BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK | __GFP_NO_GROW));
-	if (flags & __GFP_NO_GROW)
-		return 0;
+	BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
 
 	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
 	local_flags = (flags & GFP_LEVEL_MASK);
-	if (!(local_flags & __GFP_WAIT))
-		/*
-		 * Not allowed to sleep.  Need to tell a constructor about
-		 * this - it might need to know...
-		 */
-		ctor_flags |= SLAB_CTOR_ATOMIC;
-
 	/* Take the l3 list lock to change the colour_next on this node */
 	check_irq_off();
 	l3 = cachep->nodelists[nodeid];
@@ -2829,7 +2837,7 @@ static void kfree_debugcheck(const void 
 
 static inline void verify_redzone_free(struct kmem_cache *cache, void *obj)
 {
-	unsigned long redzone1, redzone2;
+	unsigned long long redzone1, redzone2;
 
 	redzone1 = *dbg_redzone1(cache, obj);
 	redzone2 = *dbg_redzone2(cache, obj);
@@ -2845,7 +2853,7 @@ static inline void verify_redzone_free(s
 	else
 		slab_error(cache, "memory outside object was overwritten");
 
-	printk(KERN_ERR "%p: redzone 1:0x%lx, redzone 2:0x%lx.\n",
+	printk(KERN_ERR "%p: redzone 1:0x%llx, redzone 2:0x%llx.\n",
 			obj, redzone1, redzone2);
 }
 
@@ -2858,7 +2866,7 @@ static void *cache_free_debugcheck(struc
 
 	objp -= obj_offset(cachep);
 	kfree_debugcheck(objp);
-	page = virt_to_page(objp);
+	page = virt_to_head_page(objp);
 
 	slabp = page_get_slab(page);
 
@@ -2875,15 +2883,6 @@ static void *cache_free_debugcheck(struc
 	BUG_ON(objnr >= cachep->num);
 	BUG_ON(objp != index_to_obj(cachep, slabp, objnr));
 
-	if (cachep->flags & SLAB_DEBUG_INITIAL) {
-		/*
-		 * Need to call the slab's constructor so the caller can
-		 * perform a verify of its state (debugging).  Called without
-		 * the cache-lock held.
-		 */
-		cachep->ctor(objp + obj_offset(cachep),
-			     cachep, SLAB_CTOR_CONSTRUCTOR | SLAB_CTOR_VERIFY);
-	}
 	if (cachep->flags & SLAB_POISON && cachep->dtor) {
 		/* we want to cache poison the object,
 		 * call the destruction callback
@@ -2987,6 +2986,14 @@ retry:
 		slabp = list_entry(entry, struct slab, list);
 		check_slabp(cachep, slabp);
 		check_spinlock_acquired(cachep);
+
+		/*
+		 * The slab was either on partial or free list so
+		 * there must be at least one object available for
+		 * allocation.
+		 */
+		BUG_ON(slabp->inuse < 0 || slabp->inuse >= cachep->num);
+
 		while (slabp->inuse < cachep->num && batchcount--) {
 			STATS_INC_ALLOCED(cachep);
 			STATS_INC_ACTIVE(cachep);
@@ -3062,7 +3069,7 @@ #endif
 			slab_error(cachep, "double free, or memory outside"
 						" object was overwritten");
 			printk(KERN_ERR
-				"%p: redzone 1:0x%lx, redzone 2:0x%lx\n",
+				"%p: redzone 1:0x%llx, redzone 2:0x%llx\n",
 				objp, *dbg_redzone1(cachep, objp),
 				*dbg_redzone2(cachep, objp));
 		}
@@ -3074,20 +3081,14 @@ #ifdef CONFIG_DEBUG_SLAB_LEAK
 		struct slab *slabp;
 		unsigned objnr;
 
-		slabp = page_get_slab(virt_to_page(objp));
+		slabp = page_get_slab(virt_to_head_page(objp));
 		objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
 		slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
 	}
 #endif
 	objp += obj_offset(cachep);
-	if (cachep->ctor && cachep->flags & SLAB_POISON) {
-		unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR;
-
-		if (!(flags & __GFP_WAIT))
-			ctor_flags |= SLAB_CTOR_ATOMIC;
-
-		cachep->ctor(objp, cachep, ctor_flags);
-	}
+	if (cachep->ctor && cachep->flags & SLAB_POISON)
+		cachep->ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR);
 #if ARCH_SLAB_MINALIGN
 	if ((u32)objp & (ARCH_SLAB_MINALIGN-1)) {
 		printk(KERN_ERR "0x%p: not aligned to ARCH_SLAB_MINALIGN=%d\n",
@@ -3142,7 +3143,7 @@ static int __init failslab_debugfs(void)
 	struct dentry *dir;
 	int err;
 
-       	err = init_fault_attr_dentries(&failslab.attr, "failslab");
+	err = init_fault_attr_dentries(&failslab.attr, "failslab");
 	if (err)
 		return err;
 	dir = failslab.attr.dentries.dir;
@@ -3180,9 +3181,6 @@ static inline void *____cache_alloc(stru
 
 	check_irq_off();
 
-	if (should_failslab(cachep, flags))
-		return NULL;
-
 	ac = cpu_cache_get(cachep);
 	if (likely(ac->avail)) {
 		STATS_INC_ALLOCHIT(cachep);
@@ -3256,7 +3254,7 @@ retry:
 					flags | GFP_THISNODE, nid);
 	}
 
-	if (!obj && !(flags & __GFP_NO_GROW)) {
+	if (!obj) {
 		/*
 		 * This allocation will be performed within the constraints
 		 * of the current cpuset / memory policy requirements.
@@ -3374,6 +3372,9 @@ __cache_alloc_node(struct kmem_cache *ca
 	unsigned long save_flags;
 	void *ptr;
 
+	if (should_failslab(cachep, flags))
+		return NULL;
+
 	cache_alloc_debugcheck_before(cachep, flags);
 	local_irq_save(save_flags);
 
@@ -3444,6 +3445,9 @@ __cache_alloc(struct kmem_cache *cachep,
 	unsigned long save_flags;
 	void *objp;
 
+	if (should_failslab(cachep, flags))
+		return NULL;
+
 	cache_alloc_debugcheck_before(cachep, flags);
 	local_irq_save(save_flags);
 	objp = __do_cache_alloc(cachep, flags);
@@ -3563,7 +3567,7 @@ static inline void __cache_free(struct k
 	check_irq_off();
 	objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
 
-	if (cache_free_alien(cachep, objp))
+	if (use_alien_caches && cache_free_alien(cachep, objp))
 		return;
 
 	if (likely(ac->avail < ac->limit)) {
@@ -3737,6 +3741,53 @@ EXPORT_SYMBOL(__kmalloc);
 #endif
 
 /**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ *
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes.  If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc().  If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+	struct kmem_cache *cache, *new_cache;
+	void *ret;
+
+	if (unlikely(!p))
+		return kmalloc_track_caller(new_size, flags);
+
+	if (unlikely(!new_size)) {
+		kfree(p);
+		return NULL;
+	}
+
+	cache = virt_to_cache(p);
+	new_cache = __find_general_cachep(new_size, flags);
+
+	/*
+ 	 * If new size fits in the current cache, bail out.
+ 	 */
+	if (likely(cache == new_cache))
+		return (void *)p;
+
+	/*
+ 	 * We are on the slow-path here so do not use __cache_alloc
+ 	 * because it bloats kernel text.
+ 	 */
+	ret = kmalloc_track_caller(new_size, flags);
+	if (ret) {
+		memcpy(ret, p, min(new_size, ksize(p)));
+		kfree(p);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
+/**
  * kmem_cache_free - Deallocate an object
  * @cachep: The cache the allocation was from.
  * @objp: The previously allocated object.
@@ -3812,12 +3863,15 @@ static int alloc_kmemlist(struct kmem_ca
                                 goto fail;
                 }
 
-		new_shared = alloc_arraycache(node,
+		new_shared = NULL;
+		if (cachep->shared) {
+			new_shared = alloc_arraycache(node,
 				cachep->shared*cachep->batchcount,
 					0xbaadf00d);
-		if (!new_shared) {
-			free_alien_cache(new_alien);
-			goto fail;
+			if (!new_shared) {
+				free_alien_cache(new_alien);
+				goto fail;
+			}
 		}
 
 		l3 = cachep->nodelists[node];
@@ -3975,10 +4029,8 @@ static int enable_cpucache(struct kmem_c
 	 * to a larger limit. Thus disabled by default.
 	 */
 	shared = 0;
-#ifdef CONFIG_SMP
-	if (cachep->buffer_size <= PAGE_SIZE)
+	if (cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)
 		shared = 8;
-#endif
 
 #if DEBUG
 	/*
@@ -4380,16 +4432,12 @@ static void handle_slab(unsigned long *n
 static void show_symbol(struct seq_file *m, unsigned long address)
 {
 #ifdef CONFIG_KALLSYMS
-	char *modname;
-	const char *name;
 	unsigned long offset, size;
-	char namebuf[KSYM_NAME_LEN+1];
-
-	name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
+	char modname[MODULE_NAME_LEN + 1], name[KSYM_NAME_LEN + 1];
 
-	if (name) {
+	if (lookup_symbol_attrs(address, &size, &offset, modname, name) == 0) {
 		seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
-		if (modname)
+		if (modname[0])
 			seq_printf(m, " [%s]", modname);
 		return;
 	}
@@ -4478,7 +4526,7 @@ #endif
  * allocated with either kmalloc() or kmem_cache_alloc(). The object
  * must not be freed during the duration of the call.
  */
-unsigned int ksize(const void *objp)
+size_t ksize(const void *objp)
 {
 	if (unlikely(objp == NULL))
 		return 0;
diff --git a/mm/slob.c b/mm/slob.c
index 5adc29c..c6933bc 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -21,7 +21,7 @@
  *
  * SLAB is emulated on top of SLOB by simply calling constructors and
  * destructors for every SLAB allocation. Objects are returned with
- * the 8-byte alignment unless the SLAB_MUST_HWCACHE_ALIGN flag is
+ * the 8-byte alignment unless the SLAB_HWCACHE_ALIGN flag is
  * set, in which case the low-level allocator will fragment blocks to
  * create the proper alignment. Again, objects of page-size or greater
  * are allocated by calling __get_free_pages. As SLAB objects know
@@ -150,15 +150,6 @@ static void slob_free(void *block, int s
 	spin_unlock_irqrestore(&slob_lock, flags);
 }
 
-static int FASTCALL(find_order(int size));
-static int fastcall find_order(int size)
-{
-	int order = 0;
-	for ( ; size > 4096 ; size >>=1)
-		order++;
-	return order;
-}
-
 void *__kmalloc(size_t size, gfp_t gfp)
 {
 	slob_t *m;
@@ -174,7 +165,7 @@ void *__kmalloc(size_t size, gfp_t gfp)
 	if (!bb)
 		return 0;
 
-	bb->order = find_order(size);
+	bb->order = get_order(size);
 	bb->pages = (void *)__get_free_pages(gfp, bb->order);
 
 	if (bb->pages) {
@@ -190,6 +181,39 @@ void *__kmalloc(size_t size, gfp_t gfp)
 }
 EXPORT_SYMBOL(__kmalloc);
 
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ *
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes.  If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc().  If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+	void *ret;
+
+	if (unlikely(!p))
+		return kmalloc_track_caller(new_size, flags);
+
+	if (unlikely(!new_size)) {
+		kfree(p);
+		return NULL;
+	}
+
+	ret = kmalloc_track_caller(new_size, flags);
+	if (ret) {
+		memcpy(ret, p, min(new_size, ksize(p)));
+		kfree(p);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
 void kfree(const void *block)
 {
 	bigblock_t *bb, **last = &bigblocks;
@@ -219,7 +243,7 @@ void kfree(const void *block)
 
 EXPORT_SYMBOL(kfree);
 
-unsigned int ksize(const void *block)
+size_t ksize(const void *block)
 {
 	bigblock_t *bb;
 	unsigned long flags;
@@ -262,10 +286,11 @@ struct kmem_cache *kmem_cache_create(con
 		c->ctor = ctor;
 		c->dtor = dtor;
 		/* ignore alignment unless it's forced */
-		c->align = (flags & SLAB_MUST_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
+		c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
 		if (c->align < align)
 			c->align = align;
-	}
+	} else if (flags & SLAB_PANIC)
+		panic("Cannot create slab cache %s\n", name);
 
 	return c;
 }
@@ -284,7 +309,7 @@ void *kmem_cache_alloc(struct kmem_cache
 	if (c->size < PAGE_SIZE)
 		b = slob_alloc(c->size, flags, c->align);
 	else
-		b = (void *)__get_free_pages(flags, find_order(c->size));
+		b = (void *)__get_free_pages(flags, get_order(c->size));
 
 	if (c->ctor)
 		c->ctor(b, c, SLAB_CTOR_CONSTRUCTOR);
@@ -311,7 +336,7 @@ void kmem_cache_free(struct kmem_cache *
 	if (c->size < PAGE_SIZE)
 		slob_free(b, c->size);
 	else
-		free_pages((unsigned long)b, find_order(c->size));
+		free_pages((unsigned long)b, get_order(c->size));
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
diff --git a/mm/slub.c b/mm/slub.c
new file mode 100644
index 0000000..5db3da5
--- /dev/null
+++ b/mm/slub.c
@@ -0,0 +1,3520 @@
+/*
+ * SLUB: A slab allocator that limits cache line use instead of queuing
+ * objects in per cpu and per node lists.
+ *
+ * The allocator synchronizes using per slab locks and only
+ * uses a centralized lock to manage a pool of partial slabs.
+ *
+ * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bit_spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/cpuset.h>
+#include <linux/mempolicy.h>
+#include <linux/ctype.h>
+#include <linux/kallsyms.h>
+
+/*
+ * Lock order:
+ *   1. slab_lock(page)
+ *   2. slab->list_lock
+ *
+ *   The slab_lock protects operations on the object of a particular
+ *   slab and its metadata in the page struct. If the slab lock
+ *   has been taken then no allocations nor frees can be performed
+ *   on the objects in the slab nor can the slab be added or removed
+ *   from the partial or full lists since this would mean modifying
+ *   the page_struct of the slab.
+ *
+ *   The list_lock protects the partial and full list on each node and
+ *   the partial slab counter. If taken then no new slabs may be added or
+ *   removed from the lists nor make the number of partial slabs be modified.
+ *   (Note that the total number of slabs is an atomic value that may be
+ *   modified without taking the list lock).
+ *
+ *   The list_lock is a centralized lock and thus we avoid taking it as
+ *   much as possible. As long as SLUB does not have to handle partial
+ *   slabs, operations can continue without any centralized lock. F.e.
+ *   allocating a long series of objects that fill up slabs does not require
+ *   the list lock.
+ *
+ *   The lock order is sometimes inverted when we are trying to get a slab
+ *   off a list. We take the list_lock and then look for a page on the list
+ *   to use. While we do that objects in the slabs may be freed. We can
+ *   only operate on the slab if we have also taken the slab_lock. So we use
+ *   a slab_trylock() on the slab. If trylock was successful then no frees
+ *   can occur anymore and we can use the slab for allocations etc. If the
+ *   slab_trylock() does not succeed then frees are in progress in the slab and
+ *   we must stay away from it for a while since we may cause a bouncing
+ *   cacheline if we try to acquire the lock. So go onto the next slab.
+ *   If all pages are busy then we may allocate a new slab instead of reusing
+ *   a partial slab. A new slab has noone operating on it and thus there is
+ *   no danger of cacheline contention.
+ *
+ *   Interrupts are disabled during allocation and deallocation in order to
+ *   make the slab allocator safe to use in the context of an irq. In addition
+ *   interrupts are disabled to ensure that the processor does not change
+ *   while handling per_cpu slabs, due to kernel preemption.
+ *
+ * SLUB assigns one slab for allocation to each processor.
+ * Allocations only occur from these slabs called cpu slabs.
+ *
+ * Slabs with free elements are kept on a partial list.
+ * There is no list for full slabs. If an object in a full slab is
+ * freed then the slab will show up again on the partial lists.
+ * Otherwise there is no need to track full slabs unless we have to
+ * track full slabs for debugging purposes.
+ *
+ * Slabs are freed when they become empty. Teardown and setup is
+ * minimal so we rely on the page allocators per cpu caches for
+ * fast frees and allocs.
+ *
+ * Overloading of page flags that are otherwise used for LRU management.
+ *
+ * PageActive 		The slab is used as a cpu cache. Allocations
+ * 			may be performed from the slab. The slab is not
+ * 			on any slab list and cannot be moved onto one.
+ *
+ * PageError		Slab requires special handling due to debug
+ * 			options set. This moves	slab handling out of
+ * 			the fast path.
+ */
+
+/*
+ * Issues still to be resolved:
+ *
+ * - The per cpu array is updated for each new slab and and is a remote
+ *   cacheline for most nodes. This could become a bouncing cacheline given
+ *   enough frequent updates. There are 16 pointers in a cacheline.so at
+ *   max 16 cpus could compete. Likely okay.
+ *
+ * - Support PAGE_ALLOC_DEBUG. Should be easy to do.
+ *
+ * - Variable sizing of the per node arrays
+ */
+
+/* Enable to test recovery from slab corruption on boot */
+#undef SLUB_RESILIENCY_TEST
+
+#if PAGE_SHIFT <= 12
+
+/*
+ * Small page size. Make sure that we do not fragment memory
+ */
+#define DEFAULT_MAX_ORDER 1
+#define DEFAULT_MIN_OBJECTS 4
+
+#else
+
+/*
+ * Large page machines are customarily able to handle larger
+ * page orders.
+ */
+#define DEFAULT_MAX_ORDER 2
+#define DEFAULT_MIN_OBJECTS 8
+
+#endif
+
+/*
+ * Mininum number of partial slabs. These will be left on the partial
+ * lists even if they are empty. kmem_cache_shrink may reclaim them.
+ */
+#define MIN_PARTIAL 2
+
+/*
+ * Maximum number of desirable partial slabs.
+ * The existence of more partial slabs makes kmem_cache_shrink
+ * sort the partial list by the number of objects in the.
+ */
+#define MAX_PARTIAL 10
+
+#define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
+				SLAB_POISON | SLAB_STORE_USER)
+/*
+ * Set of flags that will prevent slab merging
+ */
+#define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
+		SLAB_TRACE | SLAB_DESTROY_BY_RCU)
+
+#define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
+		SLAB_CACHE_DMA)
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+/* Internal SLUB flags */
+#define __OBJECT_POISON 0x80000000	/* Poison object */
+
+static int kmem_size = sizeof(struct kmem_cache);
+
+#ifdef CONFIG_SMP
+static struct notifier_block slab_notifier;
+#endif
+
+static enum {
+	DOWN,		/* No slab functionality available */
+	PARTIAL,	/* kmem_cache_open() works but kmalloc does not */
+	UP,		/* Everything works */
+	SYSFS		/* Sysfs up */
+} slab_state = DOWN;
+
+/* A list of all slab caches on the system */
+static DECLARE_RWSEM(slub_lock);
+LIST_HEAD(slab_caches);
+
+#ifdef CONFIG_SYSFS
+static int sysfs_slab_add(struct kmem_cache *);
+static int sysfs_slab_alias(struct kmem_cache *, const char *);
+static void sysfs_slab_remove(struct kmem_cache *);
+#else
+static int sysfs_slab_add(struct kmem_cache *s) { return 0; }
+static int sysfs_slab_alias(struct kmem_cache *s, const char *p) { return 0; }
+static void sysfs_slab_remove(struct kmem_cache *s) {}
+#endif
+
+/********************************************************************
+ * 			Core slab cache functions
+ *******************************************************************/
+
+int slab_is_available(void)
+{
+	return slab_state >= UP;
+}
+
+static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
+{
+#ifdef CONFIG_NUMA
+	return s->node[node];
+#else
+	return &s->local_node;
+#endif
+}
+
+/*
+ * Object debugging
+ */
+static void print_section(char *text, u8 *addr, unsigned int length)
+{
+	int i, offset;
+	int newline = 1;
+	char ascii[17];
+
+	ascii[16] = 0;
+
+	for (i = 0; i < length; i++) {
+		if (newline) {
+			printk(KERN_ERR "%10s 0x%p: ", text, addr + i);
+			newline = 0;
+		}
+		printk(" %02x", addr[i]);
+		offset = i % 16;
+		ascii[offset] = isgraph(addr[i]) ? addr[i] : '.';
+		if (offset == 15) {
+			printk(" %s\n",ascii);
+			newline = 1;
+		}
+	}
+	if (!newline) {
+		i %= 16;
+		while (i < 16) {
+			printk("   ");
+			ascii[i] = ' ';
+			i++;
+		}
+		printk(" %s\n", ascii);
+	}
+}
+
+/*
+ * Slow version of get and set free pointer.
+ *
+ * This requires touching the cache lines of kmem_cache.
+ * The offset can also be obtained from the page. In that
+ * case it is in the cacheline that we already need to touch.
+ */
+static void *get_freepointer(struct kmem_cache *s, void *object)
+{
+	return *(void **)(object + s->offset);
+}
+
+static void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+{
+	*(void **)(object + s->offset) = fp;
+}
+
+/*
+ * Tracking user of a slab.
+ */
+struct track {
+	void *addr;		/* Called from address */
+	int cpu;		/* Was running on cpu */
+	int pid;		/* Pid context */
+	unsigned long when;	/* When did the operation occur */
+};
+
+enum track_item { TRACK_ALLOC, TRACK_FREE };
+
+static struct track *get_track(struct kmem_cache *s, void *object,
+	enum track_item alloc)
+{
+	struct track *p;
+
+	if (s->offset)
+		p = object + s->offset + sizeof(void *);
+	else
+		p = object + s->inuse;
+
+	return p + alloc;
+}
+
+static void set_track(struct kmem_cache *s, void *object,
+				enum track_item alloc, void *addr)
+{
+	struct track *p;
+
+	if (s->offset)
+		p = object + s->offset + sizeof(void *);
+	else
+		p = object + s->inuse;
+
+	p += alloc;
+	if (addr) {
+		p->addr = addr;
+		p->cpu = smp_processor_id();
+		p->pid = current ? current->pid : -1;
+		p->when = jiffies;
+	} else
+		memset(p, 0, sizeof(struct track));
+}
+
+static void init_tracking(struct kmem_cache *s, void *object)
+{
+	if (s->flags & SLAB_STORE_USER) {
+		set_track(s, object, TRACK_FREE, NULL);
+		set_track(s, object, TRACK_ALLOC, NULL);
+	}
+}
+
+static void print_track(const char *s, struct track *t)
+{
+	if (!t->addr)
+		return;
+
+	printk(KERN_ERR "%s: ", s);
+	__print_symbol("%s", (unsigned long)t->addr);
+	printk(" jiffies_ago=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+}
+
+static void print_trailer(struct kmem_cache *s, u8 *p)
+{
+	unsigned int off;	/* Offset of last byte */
+
+	if (s->flags & SLAB_RED_ZONE)
+		print_section("Redzone", p + s->objsize,
+			s->inuse - s->objsize);
+
+	printk(KERN_ERR "FreePointer 0x%p -> 0x%p\n",
+			p + s->offset,
+			get_freepointer(s, p));
+
+	if (s->offset)
+		off = s->offset + sizeof(void *);
+	else
+		off = s->inuse;
+
+	if (s->flags & SLAB_STORE_USER) {
+		print_track("Last alloc", get_track(s, p, TRACK_ALLOC));
+		print_track("Last free ", get_track(s, p, TRACK_FREE));
+		off += 2 * sizeof(struct track);
+	}
+
+	if (off != s->size)
+		/* Beginning of the filler is the free pointer */
+		print_section("Filler", p + off, s->size - off);
+}
+
+static void object_err(struct kmem_cache *s, struct page *page,
+			u8 *object, char *reason)
+{
+	u8 *addr = page_address(page);
+
+	printk(KERN_ERR "*** SLUB %s: %s@0x%p slab 0x%p\n",
+			s->name, reason, object, page);
+	printk(KERN_ERR "    offset=%tu flags=0x%04lx inuse=%u freelist=0x%p\n",
+		object - addr, page->flags, page->inuse, page->freelist);
+	if (object > addr + 16)
+		print_section("Bytes b4", object - 16, 16);
+	print_section("Object", object, min(s->objsize, 128));
+	print_trailer(s, object);
+	dump_stack();
+}
+
+static void slab_err(struct kmem_cache *s, struct page *page, char *reason, ...)
+{
+	va_list args;
+	char buf[100];
+
+	va_start(args, reason);
+	vsnprintf(buf, sizeof(buf), reason, args);
+	va_end(args);
+	printk(KERN_ERR "*** SLUB %s: %s in slab @0x%p\n", s->name, buf,
+		page);
+	dump_stack();
+}
+
+static void init_object(struct kmem_cache *s, void *object, int active)
+{
+	u8 *p = object;
+
+	if (s->flags & __OBJECT_POISON) {
+		memset(p, POISON_FREE, s->objsize - 1);
+		p[s->objsize -1] = POISON_END;
+	}
+
+	if (s->flags & SLAB_RED_ZONE)
+		memset(p + s->objsize,
+			active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE,
+			s->inuse - s->objsize);
+}
+
+static int check_bytes(u8 *start, unsigned int value, unsigned int bytes)
+{
+	while (bytes) {
+		if (*start != (u8)value)
+			return 0;
+		start++;
+		bytes--;
+	}
+	return 1;
+}
+
+
+static int check_valid_pointer(struct kmem_cache *s, struct page *page,
+					 void *object)
+{
+	void *base;
+
+	if (!object)
+		return 1;
+
+	base = page_address(page);
+	if (object < base || object >= base + s->objects * s->size ||
+		(object - base) % s->size) {
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Object layout:
+ *
+ * object address
+ * 	Bytes of the object to be managed.
+ * 	If the freepointer may overlay the object then the free
+ * 	pointer is the first word of the object.
+ * 	Poisoning uses 0x6b (POISON_FREE) and the last byte is
+ * 	0xa5 (POISON_END)
+ *
+ * object + s->objsize
+ * 	Padding to reach word boundary. This is also used for Redzoning.
+ * 	Padding is extended to word size if Redzoning is enabled
+ * 	and objsize == inuse.
+ * 	We fill with 0xbb (RED_INACTIVE) for inactive objects and with
+ * 	0xcc (RED_ACTIVE) for objects in use.
+ *
+ * object + s->inuse
+ * 	A. Free pointer (if we cannot overwrite object on free)
+ * 	B. Tracking data for SLAB_STORE_USER
+ * 	C. Padding to reach required alignment boundary
+ * 		Padding is done using 0x5a (POISON_INUSE)
+ *
+ * object + s->size
+ *
+ * If slabcaches are merged then the objsize and inuse boundaries are to
+ * be ignored. And therefore no slab options that rely on these boundaries
+ * may be used with merged slabcaches.
+ */
+
+static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
+						void *from, void *to)
+{
+	printk(KERN_ERR "@@@ SLUB %s: Restoring %s (0x%x) from 0x%p-0x%p\n",
+		s->name, message, data, from, to - 1);
+	memset(from, data, to - from);
+}
+
+static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
+{
+	unsigned long off = s->inuse;	/* The end of info */
+
+	if (s->offset)
+		/* Freepointer is placed after the object. */
+		off += sizeof(void *);
+
+	if (s->flags & SLAB_STORE_USER)
+		/* We also have user information there */
+		off += 2 * sizeof(struct track);
+
+	if (s->size == off)
+		return 1;
+
+	if (check_bytes(p + off, POISON_INUSE, s->size - off))
+		return 1;
+
+	object_err(s, page, p, "Object padding check fails");
+
+	/*
+	 * Restore padding
+	 */
+	restore_bytes(s, "object padding", POISON_INUSE, p + off, p + s->size);
+	return 0;
+}
+
+static int slab_pad_check(struct kmem_cache *s, struct page *page)
+{
+	u8 *p;
+	int length, remainder;
+
+	if (!(s->flags & SLAB_POISON))
+		return 1;
+
+	p = page_address(page);
+	length = s->objects * s->size;
+	remainder = (PAGE_SIZE << s->order) - length;
+	if (!remainder)
+		return 1;
+
+	if (!check_bytes(p + length, POISON_INUSE, remainder)) {
+		slab_err(s, page, "Padding check failed");
+		restore_bytes(s, "slab padding", POISON_INUSE, p + length,
+			p + length + remainder);
+		return 0;
+	}
+	return 1;
+}
+
+static int check_object(struct kmem_cache *s, struct page *page,
+					void *object, int active)
+{
+	u8 *p = object;
+	u8 *endobject = object + s->objsize;
+
+	if (s->flags & SLAB_RED_ZONE) {
+		unsigned int red =
+			active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;
+
+		if (!check_bytes(endobject, red, s->inuse - s->objsize)) {
+			object_err(s, page, object,
+			active ? "Redzone Active" : "Redzone Inactive");
+			restore_bytes(s, "redzone", red,
+				endobject, object + s->inuse);
+			return 0;
+		}
+	} else {
+		if ((s->flags & SLAB_POISON) && s->objsize < s->inuse &&
+			!check_bytes(endobject, POISON_INUSE,
+					s->inuse - s->objsize)) {
+		object_err(s, page, p, "Alignment padding check fails");
+		/*
+		 * Fix it so that there will not be another report.
+		 *
+		 * Hmmm... We may be corrupting an object that now expects
+		 * to be longer than allowed.
+		 */
+		restore_bytes(s, "alignment padding", POISON_INUSE,
+			endobject, object + s->inuse);
+		}
+	}
+
+	if (s->flags & SLAB_POISON) {
+		if (!active && (s->flags & __OBJECT_POISON) &&
+			(!check_bytes(p, POISON_FREE, s->objsize - 1) ||
+				p[s->objsize - 1] != POISON_END)) {
+
+			object_err(s, page, p, "Poison check failed");
+			restore_bytes(s, "Poison", POISON_FREE,
+						p, p + s->objsize -1);
+			restore_bytes(s, "Poison", POISON_END,
+					p + s->objsize - 1, p + s->objsize);
+			return 0;
+		}
+		/*
+		 * check_pad_bytes cleans up on its own.
+		 */
+		check_pad_bytes(s, page, p);
+	}
+
+	if (!s->offset && active)
+		/*
+		 * Object and freepointer overlap. Cannot check
+		 * freepointer while object is allocated.
+		 */
+		return 1;
+
+	/* Check free pointer validity */
+	if (!check_valid_pointer(s, page, get_freepointer(s, p))) {
+		object_err(s, page, p, "Freepointer corrupt");
+		/*
+		 * No choice but to zap it and thus loose the remainder
+		 * of the free objects in this slab. May cause
+		 * another error because the object count maybe
+		 * wrong now.
+		 */
+		set_freepointer(s, p, NULL);
+		return 0;
+	}
+	return 1;
+}
+
+static int check_slab(struct kmem_cache *s, struct page *page)
+{
+	VM_BUG_ON(!irqs_disabled());
+
+	if (!PageSlab(page)) {
+		slab_err(s, page, "Not a valid slab page flags=%lx "
+			"mapping=0x%p count=%d", page->flags, page->mapping,
+			page_count(page));
+		return 0;
+	}
+	if (page->offset * sizeof(void *) != s->offset) {
+		slab_err(s, page, "Corrupted offset %lu flags=0x%lx "
+			"mapping=0x%p count=%d",
+			(unsigned long)(page->offset * sizeof(void *)),
+			page->flags,
+			page->mapping,
+			page_count(page));
+		return 0;
+	}
+	if (page->inuse > s->objects) {
+		slab_err(s, page, "inuse %u > max %u @0x%p flags=%lx "
+			"mapping=0x%p count=%d",
+			s->name, page->inuse, s->objects, page->flags,
+			page->mapping, page_count(page));
+		return 0;
+	}
+	/* Slab_pad_check fixes things up after itself */
+	slab_pad_check(s, page);
+	return 1;
+}
+
+/*
+ * Determine if a certain object on a page is on the freelist and
+ * therefore free. Must hold the slab lock for cpu slabs to
+ * guarantee that the chains are consistent.
+ */
+static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
+{
+	int nr = 0;
+	void *fp = page->freelist;
+	void *object = NULL;
+
+	while (fp && nr <= s->objects) {
+		if (fp == search)
+			return 1;
+		if (!check_valid_pointer(s, page, fp)) {
+			if (object) {
+				object_err(s, page, object,
+					"Freechain corrupt");
+				set_freepointer(s, object, NULL);
+				break;
+			} else {
+				slab_err(s, page, "Freepointer 0x%p corrupt",
+									fp);
+				page->freelist = NULL;
+				page->inuse = s->objects;
+				printk(KERN_ERR "@@@ SLUB %s: Freelist "
+					"cleared. Slab 0x%p\n",
+					s->name, page);
+				return 0;
+			}
+			break;
+		}
+		object = fp;
+		fp = get_freepointer(s, object);
+		nr++;
+	}
+
+	if (page->inuse != s->objects - nr) {
+		slab_err(s, page, "Wrong object count. Counter is %d but "
+			"counted were %d", s, page, page->inuse,
+							s->objects - nr);
+		page->inuse = s->objects - nr;
+		printk(KERN_ERR "@@@ SLUB %s: Object count adjusted. "
+			"Slab @0x%p\n", s->name, page);
+	}
+	return search == NULL;
+}
+
+/*
+ * Tracking of fully allocated slabs for debugging
+ */
+static void add_full(struct kmem_cache_node *n, struct page *page)
+{
+	spin_lock(&n->list_lock);
+	list_add(&page->lru, &n->full);
+	spin_unlock(&n->list_lock);
+}
+
+static void remove_full(struct kmem_cache *s, struct page *page)
+{
+	struct kmem_cache_node *n;
+
+	if (!(s->flags & SLAB_STORE_USER))
+		return;
+
+	n = get_node(s, page_to_nid(page));
+
+	spin_lock(&n->list_lock);
+	list_del(&page->lru);
+	spin_unlock(&n->list_lock);
+}
+
+static int alloc_object_checks(struct kmem_cache *s, struct page *page,
+							void *object)
+{
+	if (!check_slab(s, page))
+		goto bad;
+
+	if (object && !on_freelist(s, page, object)) {
+		slab_err(s, page, "Object 0x%p already allocated", object);
+		goto bad;
+	}
+
+	if (!check_valid_pointer(s, page, object)) {
+		object_err(s, page, object, "Freelist Pointer check fails");
+		goto bad;
+	}
+
+	if (!object)
+		return 1;
+
+	if (!check_object(s, page, object, 0))
+		goto bad;
+
+	return 1;
+bad:
+	if (PageSlab(page)) {
+		/*
+		 * If this is a slab page then lets do the best we can
+		 * to avoid issues in the future. Marking all objects
+		 * as used avoids touching the remainder.
+		 */
+		printk(KERN_ERR "@@@ SLUB: %s slab 0x%p. Marking all objects used.\n",
+			s->name, page);
+		page->inuse = s->objects;
+		page->freelist = NULL;
+		/* Fix up fields that may be corrupted */
+		page->offset = s->offset / sizeof(void *);
+	}
+	return 0;
+}
+
+static int free_object_checks(struct kmem_cache *s, struct page *page,
+							void *object)
+{
+	if (!check_slab(s, page))
+		goto fail;
+
+	if (!check_valid_pointer(s, page, object)) {
+		slab_err(s, page, "Invalid object pointer 0x%p", object);
+		goto fail;
+	}
+
+	if (on_freelist(s, page, object)) {
+		slab_err(s, page, "Object 0x%p already free", object);
+		goto fail;
+	}
+
+	if (!check_object(s, page, object, 1))
+		return 0;
+
+	if (unlikely(s != page->slab)) {
+		if (!PageSlab(page))
+			slab_err(s, page, "Attempt to free object(0x%p) "
+				"outside of slab", object);
+		else
+		if (!page->slab) {
+			printk(KERN_ERR
+				"SLUB <none>: no slab for object 0x%p.\n",
+						object);
+			dump_stack();
+		}
+		else
+			slab_err(s, page, "object at 0x%p belongs "
+				"to slab %s", object, page->slab->name);
+		goto fail;
+	}
+	return 1;
+fail:
+	printk(KERN_ERR "@@@ SLUB: %s slab 0x%p object at 0x%p not freed.\n",
+		s->name, page, object);
+	return 0;
+}
+
+/*
+ * Slab allocation and freeing
+ */
+static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+{
+	struct page * page;
+	int pages = 1 << s->order;
+
+	if (s->order)
+		flags |= __GFP_COMP;
+
+	if (s->flags & SLAB_CACHE_DMA)
+		flags |= SLUB_DMA;
+
+	if (node == -1)
+		page = alloc_pages(flags, s->order);
+	else
+		page = alloc_pages_node(node, flags, s->order);
+
+	if (!page)
+		return NULL;
+
+	mod_zone_page_state(page_zone(page),
+		(s->flags & SLAB_RECLAIM_ACCOUNT) ?
+		NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+		pages);
+
+	return page;
+}
+
+static void setup_object(struct kmem_cache *s, struct page *page,
+				void *object)
+{
+	if (PageError(page)) {
+		init_object(s, object, 0);
+		init_tracking(s, object);
+	}
+
+	if (unlikely(s->ctor))
+		s->ctor(object, s, SLAB_CTOR_CONSTRUCTOR);
+}
+
+static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
+{
+	struct page *page;
+	struct kmem_cache_node *n;
+	void *start;
+	void *end;
+	void *last;
+	void *p;
+
+	BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
+
+	if (flags & __GFP_WAIT)
+		local_irq_enable();
+
+	page = allocate_slab(s, flags & GFP_LEVEL_MASK, node);
+	if (!page)
+		goto out;
+
+	n = get_node(s, page_to_nid(page));
+	if (n)
+		atomic_long_inc(&n->nr_slabs);
+	page->offset = s->offset / sizeof(void *);
+	page->slab = s;
+	page->flags |= 1 << PG_slab;
+	if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
+			SLAB_STORE_USER | SLAB_TRACE))
+		page->flags |= 1 << PG_error;
+
+	start = page_address(page);
+	end = start + s->objects * s->size;
+
+	if (unlikely(s->flags & SLAB_POISON))
+		memset(start, POISON_INUSE, PAGE_SIZE << s->order);
+
+	last = start;
+	for (p = start + s->size; p < end; p += s->size) {
+		setup_object(s, page, last);
+		set_freepointer(s, last, p);
+		last = p;
+	}
+	setup_object(s, page, last);
+	set_freepointer(s, last, NULL);
+
+	page->freelist = start;
+	page->inuse = 0;
+out:
+	if (flags & __GFP_WAIT)
+		local_irq_disable();
+	return page;
+}
+
+static void __free_slab(struct kmem_cache *s, struct page *page)
+{
+	int pages = 1 << s->order;
+
+	if (unlikely(PageError(page) || s->dtor)) {
+		void *start = page_address(page);
+		void *end = start + (pages << PAGE_SHIFT);
+		void *p;
+
+		slab_pad_check(s, page);
+		for (p = start; p <= end - s->size; p += s->size) {
+			if (s->dtor)
+				s->dtor(p, s, 0);
+			check_object(s, page, p, 0);
+		}
+	}
+
+	mod_zone_page_state(page_zone(page),
+		(s->flags & SLAB_RECLAIM_ACCOUNT) ?
+		NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+		- pages);
+
+	page->mapping = NULL;
+	__free_pages(page, s->order);
+}
+
+static void rcu_free_slab(struct rcu_head *h)
+{
+	struct page *page;
+
+	page = container_of((struct list_head *)h, struct page, lru);
+	__free_slab(page->slab, page);
+}
+
+static void free_slab(struct kmem_cache *s, struct page *page)
+{
+	if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
+		/*
+		 * RCU free overloads the RCU head over the LRU
+		 */
+		struct rcu_head *head = (void *)&page->lru;
+
+		call_rcu(head, rcu_free_slab);
+	} else
+		__free_slab(s, page);
+}
+
+static void discard_slab(struct kmem_cache *s, struct page *page)
+{
+	struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+	atomic_long_dec(&n->nr_slabs);
+	reset_page_mapcount(page);
+	page->flags &= ~(1 << PG_slab | 1 << PG_error);
+	free_slab(s, page);
+}
+
+/*
+ * Per slab locking using the pagelock
+ */
+static __always_inline void slab_lock(struct page *page)
+{
+	bit_spin_lock(PG_locked, &page->flags);
+}
+
+static __always_inline void slab_unlock(struct page *page)
+{
+	bit_spin_unlock(PG_locked, &page->flags);
+}
+
+static __always_inline int slab_trylock(struct page *page)
+{
+	int rc = 1;
+
+	rc = bit_spin_trylock(PG_locked, &page->flags);
+	return rc;
+}
+
+/*
+ * Management of partially allocated slabs
+ */
+static void add_partial_tail(struct kmem_cache_node *n, struct page *page)
+{
+	spin_lock(&n->list_lock);
+	n->nr_partial++;
+	list_add_tail(&page->lru, &n->partial);
+	spin_unlock(&n->list_lock);
+}
+
+static void add_partial(struct kmem_cache_node *n, struct page *page)
+{
+	spin_lock(&n->list_lock);
+	n->nr_partial++;
+	list_add(&page->lru, &n->partial);
+	spin_unlock(&n->list_lock);
+}
+
+static void remove_partial(struct kmem_cache *s,
+						struct page *page)
+{
+	struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+	spin_lock(&n->list_lock);
+	list_del(&page->lru);
+	n->nr_partial--;
+	spin_unlock(&n->list_lock);
+}
+
+/*
+ * Lock page and remove it from the partial list
+ *
+ * Must hold list_lock
+ */
+static int lock_and_del_slab(struct kmem_cache_node *n, struct page *page)
+{
+	if (slab_trylock(page)) {
+		list_del(&page->lru);
+		n->nr_partial--;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Try to get a partial slab from a specific node
+ */
+static struct page *get_partial_node(struct kmem_cache_node *n)
+{
+	struct page *page;
+
+	/*
+	 * Racy check. If we mistakenly see no partial slabs then we
+	 * just allocate an empty slab. If we mistakenly try to get a
+	 * partial slab then get_partials() will return NULL.
+	 */
+	if (!n || !n->nr_partial)
+		return NULL;
+
+	spin_lock(&n->list_lock);
+	list_for_each_entry(page, &n->partial, lru)
+		if (lock_and_del_slab(n, page))
+			goto out;
+	page = NULL;
+out:
+	spin_unlock(&n->list_lock);
+	return page;
+}
+
+/*
+ * Get a page from somewhere. Search in increasing NUMA
+ * distances.
+ */
+static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
+{
+#ifdef CONFIG_NUMA
+	struct zonelist *zonelist;
+	struct zone **z;
+	struct page *page;
+
+	/*
+	 * The defrag ratio allows to configure the tradeoffs between
+	 * inter node defragmentation and node local allocations.
+	 * A lower defrag_ratio increases the tendency to do local
+	 * allocations instead of scanning throught the partial
+	 * lists on other nodes.
+	 *
+	 * If defrag_ratio is set to 0 then kmalloc() always
+	 * returns node local objects. If its higher then kmalloc()
+	 * may return off node objects in order to avoid fragmentation.
+	 *
+	 * A higher ratio means slabs may be taken from other nodes
+	 * thus reducing the number of partial slabs on those nodes.
+	 *
+	 * If /sys/slab/xx/defrag_ratio is set to 100 (which makes
+	 * defrag_ratio = 1000) then every (well almost) allocation
+	 * will first attempt to defrag slab caches on other nodes. This
+	 * means scanning over all nodes to look for partial slabs which
+	 * may be a bit expensive to do on every slab allocation.
+	 */
+	if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
+		return NULL;
+
+	zonelist = &NODE_DATA(slab_node(current->mempolicy))
+					->node_zonelists[gfp_zone(flags)];
+	for (z = zonelist->zones; *z; z++) {
+		struct kmem_cache_node *n;
+
+		n = get_node(s, zone_to_nid(*z));
+
+		if (n && cpuset_zone_allowed_hardwall(*z, flags) &&
+				n->nr_partial > MIN_PARTIAL) {
+			page = get_partial_node(n);
+			if (page)
+				return page;
+		}
+	}
+#endif
+	return NULL;
+}
+
+/*
+ * Get a partial page, lock it and return it.
+ */
+static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
+{
+	struct page *page;
+	int searchnode = (node == -1) ? numa_node_id() : node;
+
+	page = get_partial_node(get_node(s, searchnode));
+	if (page || (flags & __GFP_THISNODE))
+		return page;
+
+	return get_any_partial(s, flags);
+}
+
+/*
+ * Move a page back to the lists.
+ *
+ * Must be called with the slab lock held.
+ *
+ * On exit the slab lock will have been dropped.
+ */
+static void putback_slab(struct kmem_cache *s, struct page *page)
+{
+	struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+	if (page->inuse) {
+
+		if (page->freelist)
+			add_partial(n, page);
+		else if (PageError(page) && (s->flags & SLAB_STORE_USER))
+			add_full(n, page);
+		slab_unlock(page);
+
+	} else {
+		if (n->nr_partial < MIN_PARTIAL) {
+			/*
+			 * Adding an empty page to the partial slabs in order
+			 * to avoid page allocator overhead. This page needs to
+			 * come after all the others that are not fully empty
+			 * in order to make sure that we do maximum
+			 * defragmentation.
+			 */
+			add_partial_tail(n, page);
+			slab_unlock(page);
+		} else {
+			slab_unlock(page);
+			discard_slab(s, page);
+		}
+	}
+}
+
+/*
+ * Remove the cpu slab
+ */
+static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu)
+{
+	s->cpu_slab[cpu] = NULL;
+	ClearPageActive(page);
+
+	putback_slab(s, page);
+}
+
+static void flush_slab(struct kmem_cache *s, struct page *page, int cpu)
+{
+	slab_lock(page);
+	deactivate_slab(s, page, cpu);
+}
+
+/*
+ * Flush cpu slab.
+ * Called from IPI handler with interrupts disabled.
+ */
+static void __flush_cpu_slab(struct kmem_cache *s, int cpu)
+{
+	struct page *page = s->cpu_slab[cpu];
+
+	if (likely(page))
+		flush_slab(s, page, cpu);
+}
+
+static void flush_cpu_slab(void *d)
+{
+	struct kmem_cache *s = d;
+	int cpu = smp_processor_id();
+
+	__flush_cpu_slab(s, cpu);
+}
+
+static void flush_all(struct kmem_cache *s)
+{
+#ifdef CONFIG_SMP
+	on_each_cpu(flush_cpu_slab, s, 1, 1);
+#else
+	unsigned long flags;
+
+	local_irq_save(flags);
+	flush_cpu_slab(s);
+	local_irq_restore(flags);
+#endif
+}
+
+/*
+ * slab_alloc is optimized to only modify two cachelines on the fast path
+ * (aside from the stack):
+ *
+ * 1. The page struct
+ * 2. The first cacheline of the object to be allocated.
+ *
+ * The only cache lines that are read (apart from code) is the
+ * per cpu array in the kmem_cache struct.
+ *
+ * Fastpath is not possible if we need to get a new slab or have
+ * debugging enabled (which means all slabs are marked with PageError)
+ */
+static void *slab_alloc(struct kmem_cache *s,
+				gfp_t gfpflags, int node, void *addr)
+{
+	struct page *page;
+	void **object;
+	unsigned long flags;
+	int cpu;
+
+	local_irq_save(flags);
+	cpu = smp_processor_id();
+	page = s->cpu_slab[cpu];
+	if (!page)
+		goto new_slab;
+
+	slab_lock(page);
+	if (unlikely(node != -1 && page_to_nid(page) != node))
+		goto another_slab;
+redo:
+	object = page->freelist;
+	if (unlikely(!object))
+		goto another_slab;
+	if (unlikely(PageError(page)))
+		goto debug;
+
+have_object:
+	page->inuse++;
+	page->freelist = object[page->offset];
+	slab_unlock(page);
+	local_irq_restore(flags);
+	return object;
+
+another_slab:
+	deactivate_slab(s, page, cpu);
+
+new_slab:
+	page = get_partial(s, gfpflags, node);
+	if (likely(page)) {
+have_slab:
+		s->cpu_slab[cpu] = page;
+		SetPageActive(page);
+		goto redo;
+	}
+
+	page = new_slab(s, gfpflags, node);
+	if (page) {
+		cpu = smp_processor_id();
+		if (s->cpu_slab[cpu]) {
+			/*
+			 * Someone else populated the cpu_slab while we enabled
+			 * interrupts, or we have got scheduled on another cpu.
+			 * The page may not be on the requested node.
+			 */
+			if (node == -1 ||
+				page_to_nid(s->cpu_slab[cpu]) == node) {
+				/*
+				 * Current cpuslab is acceptable and we
+				 * want the current one since its cache hot
+				 */
+				discard_slab(s, page);
+				page = s->cpu_slab[cpu];
+				slab_lock(page);
+				goto redo;
+			}
+			/* Dump the current slab */
+			flush_slab(s, s->cpu_slab[cpu], cpu);
+		}
+		slab_lock(page);
+		goto have_slab;
+	}
+	local_irq_restore(flags);
+	return NULL;
+debug:
+	if (!alloc_object_checks(s, page, object))
+		goto another_slab;
+	if (s->flags & SLAB_STORE_USER)
+		set_track(s, object, TRACK_ALLOC, addr);
+	if (s->flags & SLAB_TRACE) {
+		printk(KERN_INFO "TRACE %s alloc 0x%p inuse=%d fp=0x%p\n",
+			s->name, object, page->inuse,
+			page->freelist);
+		dump_stack();
+	}
+	init_object(s, object, 1);
+	goto have_object;
+}
+
+void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
+{
+	return slab_alloc(s, gfpflags, -1, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_alloc);
+
+#ifdef CONFIG_NUMA
+void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
+{
+	return slab_alloc(s, gfpflags, node, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_alloc_node);
+#endif
+
+/*
+ * The fastpath only writes the cacheline of the page struct and the first
+ * cacheline of the object.
+ *
+ * No special cachelines need to be read
+ */
+static void slab_free(struct kmem_cache *s, struct page *page,
+					void *x, void *addr)
+{
+	void *prior;
+	void **object = (void *)x;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	slab_lock(page);
+
+	if (unlikely(PageError(page)))
+		goto debug;
+checks_ok:
+	prior = object[page->offset] = page->freelist;
+	page->freelist = object;
+	page->inuse--;
+
+	if (unlikely(PageActive(page)))
+		/*
+		 * Cpu slabs are never on partial lists and are
+		 * never freed.
+		 */
+		goto out_unlock;
+
+	if (unlikely(!page->inuse))
+		goto slab_empty;
+
+	/*
+	 * Objects left in the slab. If it
+	 * was not on the partial list before
+	 * then add it.
+	 */
+	if (unlikely(!prior))
+		add_partial(get_node(s, page_to_nid(page)), page);
+
+out_unlock:
+	slab_unlock(page);
+	local_irq_restore(flags);
+	return;
+
+slab_empty:
+	if (prior)
+		/*
+		 * Slab on the partial list.
+		 */
+		remove_partial(s, page);
+
+	slab_unlock(page);
+	discard_slab(s, page);
+	local_irq_restore(flags);
+	return;
+
+debug:
+	if (!free_object_checks(s, page, x))
+		goto out_unlock;
+	if (!PageActive(page) && !page->freelist)
+		remove_full(s, page);
+	if (s->flags & SLAB_STORE_USER)
+		set_track(s, x, TRACK_FREE, addr);
+	if (s->flags & SLAB_TRACE) {
+		printk(KERN_INFO "TRACE %s free 0x%p inuse=%d fp=0x%p\n",
+			s->name, object, page->inuse,
+			page->freelist);
+		print_section("Object", (void *)object, s->objsize);
+		dump_stack();
+	}
+	init_object(s, object, 0);
+	goto checks_ok;
+}
+
+void kmem_cache_free(struct kmem_cache *s, void *x)
+{
+	struct page *page;
+
+	page = virt_to_head_page(x);
+
+	slab_free(s, page, x, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_free);
+
+/* Figure out on which slab object the object resides */
+static struct page *get_object_page(const void *x)
+{
+	struct page *page = virt_to_head_page(x);
+
+	if (!PageSlab(page))
+		return NULL;
+
+	return page;
+}
+
+/*
+ * kmem_cache_open produces objects aligned at "size" and the first object
+ * is placed at offset 0 in the slab (We have no metainformation on the
+ * slab, all slabs are in essence "off slab").
+ *
+ * In order to get the desired alignment one just needs to align the
+ * size.
+ *
+ * Notice that the allocation order determines the sizes of the per cpu
+ * caches. Each processor has always one slab available for allocations.
+ * Increasing the allocation order reduces the number of times that slabs
+ * must be moved on and off the partial lists and therefore may influence
+ * locking overhead.
+ *
+ * The offset is used to relocate the free list link in each object. It is
+ * therefore possible to move the free list link behind the object. This
+ * is necessary for RCU to work properly and also useful for debugging.
+ */
+
+/*
+ * Mininum / Maximum order of slab pages. This influences locking overhead
+ * and slab fragmentation. A higher order reduces the number of partial slabs
+ * and increases the number of allocations possible without having to
+ * take the list_lock.
+ */
+static int slub_min_order;
+static int slub_max_order = DEFAULT_MAX_ORDER;
+
+/*
+ * Minimum number of objects per slab. This is necessary in order to
+ * reduce locking overhead. Similar to the queue size in SLAB.
+ */
+static int slub_min_objects = DEFAULT_MIN_OBJECTS;
+
+/*
+ * Merge control. If this is set then no merging of slab caches will occur.
+ */
+static int slub_nomerge;
+
+/*
+ * Debug settings:
+ */
+static int slub_debug;
+
+static char *slub_debug_slabs;
+
+/*
+ * Calculate the order of allocation given an slab object size.
+ *
+ * The order of allocation has significant impact on other elements
+ * of the system. Generally order 0 allocations should be preferred
+ * since they do not cause fragmentation in the page allocator. Larger
+ * objects may have problems with order 0 because there may be too much
+ * space left unused in a slab. We go to a higher order if more than 1/8th
+ * of the slab would be wasted.
+ *
+ * In order to reach satisfactory performance we must ensure that
+ * a minimum number of objects is in one slab. Otherwise we may
+ * generate too much activity on the partial lists. This is less a
+ * concern for large slabs though. slub_max_order specifies the order
+ * where we begin to stop considering the number of objects in a slab.
+ *
+ * Higher order allocations also allow the placement of more objects
+ * in a slab and thereby reduce object handling overhead. If the user
+ * has requested a higher mininum order then we start with that one
+ * instead of zero.
+ */
+static int calculate_order(int size)
+{
+	int order;
+	int rem;
+
+	for (order = max(slub_min_order, fls(size - 1) - PAGE_SHIFT);
+			order < MAX_ORDER; order++) {
+		unsigned long slab_size = PAGE_SIZE << order;
+
+		if (slub_max_order > order &&
+				slab_size < slub_min_objects * size)
+			continue;
+
+		if (slab_size < size)
+			continue;
+
+		rem = slab_size % size;
+
+		if (rem <= (PAGE_SIZE << order) / 8)
+			break;
+
+	}
+	if (order >= MAX_ORDER)
+		return -E2BIG;
+	return order;
+}
+
+/*
+ * Function to figure out which alignment to use from the
+ * various ways of specifying it.
+ */
+static unsigned long calculate_alignment(unsigned long flags,
+		unsigned long align, unsigned long size)
+{
+	/*
+	 * If the user wants hardware cache aligned objects then
+	 * follow that suggestion if the object is sufficiently
+	 * large.
+	 *
+	 * The hardware cache alignment cannot override the
+	 * specified alignment though. If that is greater
+	 * then use it.
+	 */
+	if ((flags & SLAB_HWCACHE_ALIGN) &&
+			size > L1_CACHE_BYTES / 2)
+		return max_t(unsigned long, align, L1_CACHE_BYTES);
+
+	if (align < ARCH_SLAB_MINALIGN)
+		return ARCH_SLAB_MINALIGN;
+
+	return ALIGN(align, sizeof(void *));
+}
+
+static void init_kmem_cache_node(struct kmem_cache_node *n)
+{
+	n->nr_partial = 0;
+	atomic_long_set(&n->nr_slabs, 0);
+	spin_lock_init(&n->list_lock);
+	INIT_LIST_HEAD(&n->partial);
+	INIT_LIST_HEAD(&n->full);
+}
+
+#ifdef CONFIG_NUMA
+/*
+ * No kmalloc_node yet so do it by hand. We know that this is the first
+ * slab on the node for this slabcache. There are no concurrent accesses
+ * possible.
+ *
+ * Note that this function only works on the kmalloc_node_cache
+ * when allocating for the kmalloc_node_cache.
+ */
+static struct kmem_cache_node * __init early_kmem_cache_node_alloc(gfp_t gfpflags,
+								int node)
+{
+	struct page *page;
+	struct kmem_cache_node *n;
+
+	BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node));
+
+	page = new_slab(kmalloc_caches, gfpflags | GFP_THISNODE, node);
+	/* new_slab() disables interupts */
+	local_irq_enable();
+
+	BUG_ON(!page);
+	n = page->freelist;
+	BUG_ON(!n);
+	page->freelist = get_freepointer(kmalloc_caches, n);
+	page->inuse++;
+	kmalloc_caches->node[node] = n;
+	init_object(kmalloc_caches, n, 1);
+	init_kmem_cache_node(n);
+	atomic_long_inc(&n->nr_slabs);
+	add_partial(n, page);
+	return n;
+}
+
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+	int node;
+
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = s->node[node];
+		if (n && n != &s->local_node)
+			kmem_cache_free(kmalloc_caches, n);
+		s->node[node] = NULL;
+	}
+}
+
+static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
+{
+	int node;
+	int local_node;
+
+	if (slab_state >= UP)
+		local_node = page_to_nid(virt_to_page(s));
+	else
+		local_node = 0;
+
+	for_each_online_node(node) {
+		struct kmem_cache_node *n;
+
+		if (local_node == node)
+			n = &s->local_node;
+		else {
+			if (slab_state == DOWN) {
+				n = early_kmem_cache_node_alloc(gfpflags,
+								node);
+				continue;
+			}
+			n = kmem_cache_alloc_node(kmalloc_caches,
+							gfpflags, node);
+
+			if (!n) {
+				free_kmem_cache_nodes(s);
+				return 0;
+			}
+
+		}
+		s->node[node] = n;
+		init_kmem_cache_node(n);
+	}
+	return 1;
+}
+#else
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+}
+
+static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
+{
+	init_kmem_cache_node(&s->local_node);
+	return 1;
+}
+#endif
+
+/*
+ * calculate_sizes() determines the order and the distribution of data within
+ * a slab object.
+ */
+static int calculate_sizes(struct kmem_cache *s)
+{
+	unsigned long flags = s->flags;
+	unsigned long size = s->objsize;
+	unsigned long align = s->align;
+
+	/*
+	 * Determine if we can poison the object itself. If the user of
+	 * the slab may touch the object after free or before allocation
+	 * then we should never poison the object itself.
+	 */
+	if ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) &&
+			!s->ctor && !s->dtor)
+		s->flags |= __OBJECT_POISON;
+	else
+		s->flags &= ~__OBJECT_POISON;
+
+	/*
+	 * Round up object size to the next word boundary. We can only
+	 * place the free pointer at word boundaries and this determines
+	 * the possible location of the free pointer.
+	 */
+	size = ALIGN(size, sizeof(void *));
+
+	/*
+	 * If we are redzoning then check if there is some space between the
+	 * end of the object and the free pointer. If not then add an
+	 * additional word, so that we can establish a redzone between
+	 * the object and the freepointer to be able to check for overwrites.
+	 */
+	if ((flags & SLAB_RED_ZONE) && size == s->objsize)
+		size += sizeof(void *);
+
+	/*
+	 * With that we have determined how much of the slab is in actual
+	 * use by the object. This is the potential offset to the free
+	 * pointer.
+	 */
+	s->inuse = size;
+
+	if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) ||
+		s->ctor || s->dtor)) {
+		/*
+		 * Relocate free pointer after the object if it is not
+		 * permitted to overwrite the first word of the object on
+		 * kmem_cache_free.
+		 *
+		 * This is the case if we do RCU, have a constructor or
+		 * destructor or are poisoning the objects.
+		 */
+		s->offset = size;
+		size += sizeof(void *);
+	}
+
+	if (flags & SLAB_STORE_USER)
+		/*
+		 * Need to store information about allocs and frees after
+		 * the object.
+		 */
+		size += 2 * sizeof(struct track);
+
+	if (flags & DEBUG_DEFAULT_FLAGS)
+		/*
+		 * Add some empty padding so that we can catch
+		 * overwrites from earlier objects rather than let
+		 * tracking information or the free pointer be
+		 * corrupted if an user writes before the start
+		 * of the object.
+		 */
+		size += sizeof(void *);
+	/*
+	 * Determine the alignment based on various parameters that the
+	 * user specified (this is unecessarily complex due to the attempt
+	 * to be compatible with SLAB. Should be cleaned up some day).
+	 */
+	align = calculate_alignment(flags, align, s->objsize);
+
+	/*
+	 * SLUB stores one object immediately after another beginning from
+	 * offset 0. In order to align the objects we have to simply size
+	 * each object to conform to the alignment.
+	 */
+	size = ALIGN(size, align);
+	s->size = size;
+
+	s->order = calculate_order(size);
+	if (s->order < 0)
+		return 0;
+
+	/*
+	 * Determine the number of objects per slab
+	 */
+	s->objects = (PAGE_SIZE << s->order) / size;
+
+	/*
+	 * Verify that the number of objects is within permitted limits.
+	 * The page->inuse field is only 16 bit wide! So we cannot have
+	 * more than 64k objects per slab.
+	 */
+	if (!s->objects || s->objects > 65535)
+		return 0;
+	return 1;
+
+}
+
+static int __init finish_bootstrap(void)
+{
+	struct list_head *h;
+	int err;
+
+	slab_state = SYSFS;
+
+	list_for_each(h, &slab_caches) {
+		struct kmem_cache *s =
+			container_of(h, struct kmem_cache, list);
+
+		err = sysfs_slab_add(s);
+		BUG_ON(err);
+	}
+	return 0;
+}
+
+static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
+		const char *name, size_t size,
+		size_t align, unsigned long flags,
+		void (*ctor)(void *, struct kmem_cache *, unsigned long),
+		void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+	memset(s, 0, kmem_size);
+	s->name = name;
+	s->ctor = ctor;
+	s->dtor = dtor;
+	s->objsize = size;
+	s->flags = flags;
+	s->align = align;
+
+	/*
+	 * The page->offset field is only 16 bit wide. This is an offset
+	 * in units of words from the beginning of an object. If the slab
+	 * size is bigger then we cannot move the free pointer behind the
+	 * object anymore.
+	 *
+	 * On 32 bit platforms the limit is 256k. On 64bit platforms
+	 * the limit is 512k.
+	 *
+	 * Debugging or ctor/dtors may create a need to move the free
+	 * pointer. Fail if this happens.
+	 */
+	if (s->size >= 65535 * sizeof(void *)) {
+		BUG_ON(flags & (SLAB_RED_ZONE | SLAB_POISON |
+				SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
+		BUG_ON(ctor || dtor);
+	}
+	else
+		/*
+		 * Enable debugging if selected on the kernel commandline.
+		 */
+		if (slub_debug && (!slub_debug_slabs ||
+		    strncmp(slub_debug_slabs, name,
+		    	strlen(slub_debug_slabs)) == 0))
+				s->flags |= slub_debug;
+
+	if (!calculate_sizes(s))
+		goto error;
+
+	s->refcount = 1;
+#ifdef CONFIG_NUMA
+	s->defrag_ratio = 100;
+#endif
+
+	if (init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA))
+		return 1;
+error:
+	if (flags & SLAB_PANIC)
+		panic("Cannot create slab %s size=%lu realsize=%u "
+			"order=%u offset=%u flags=%lx\n",
+			s->name, (unsigned long)size, s->size, s->order,
+			s->offset, flags);
+	return 0;
+}
+EXPORT_SYMBOL(kmem_cache_open);
+
+/*
+ * Check if a given pointer is valid
+ */
+int kmem_ptr_validate(struct kmem_cache *s, const void *object)
+{
+	struct page * page;
+	void *addr;
+
+	page = get_object_page(object);
+
+	if (!page || s != page->slab)
+		/* No slab or wrong slab */
+		return 0;
+
+	addr = page_address(page);
+	if (object < addr || object >= addr + s->objects * s->size)
+		/* Out of bounds */
+		return 0;
+
+	if ((object - addr) % s->size)
+		/* Improperly aligned */
+		return 0;
+
+	/*
+	 * We could also check if the object is on the slabs freelist.
+	 * But this would be too expensive and it seems that the main
+	 * purpose of kmem_ptr_valid is to check if the object belongs
+	 * to a certain slab.
+	 */
+	return 1;
+}
+EXPORT_SYMBOL(kmem_ptr_validate);
+
+/*
+ * Determine the size of a slab object
+ */
+unsigned int kmem_cache_size(struct kmem_cache *s)
+{
+	return s->objsize;
+}
+EXPORT_SYMBOL(kmem_cache_size);
+
+const char *kmem_cache_name(struct kmem_cache *s)
+{
+	return s->name;
+}
+EXPORT_SYMBOL(kmem_cache_name);
+
+/*
+ * Attempt to free all slabs on a node
+ */
+static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
+			struct list_head *list)
+{
+	int slabs_inuse = 0;
+	unsigned long flags;
+	struct page *page, *h;
+
+	spin_lock_irqsave(&n->list_lock, flags);
+	list_for_each_entry_safe(page, h, list, lru)
+		if (!page->inuse) {
+			list_del(&page->lru);
+			discard_slab(s, page);
+		} else
+			slabs_inuse++;
+	spin_unlock_irqrestore(&n->list_lock, flags);
+	return slabs_inuse;
+}
+
+/*
+ * Release all resources used by slab cache
+ */
+static int kmem_cache_close(struct kmem_cache *s)
+{
+	int node;
+
+	flush_all(s);
+
+	/* Attempt to free all objects */
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+
+		n->nr_partial -= free_list(s, n, &n->partial);
+		if (atomic_long_read(&n->nr_slabs))
+			return 1;
+	}
+	free_kmem_cache_nodes(s);
+	return 0;
+}
+
+/*
+ * Close a cache and release the kmem_cache structure
+ * (must be used for caches created using kmem_cache_create)
+ */
+void kmem_cache_destroy(struct kmem_cache *s)
+{
+	down_write(&slub_lock);
+	s->refcount--;
+	if (!s->refcount) {
+		list_del(&s->list);
+		if (kmem_cache_close(s))
+			WARN_ON(1);
+		sysfs_slab_remove(s);
+		kfree(s);
+	}
+	up_write(&slub_lock);
+}
+EXPORT_SYMBOL(kmem_cache_destroy);
+
+/********************************************************************
+ *		Kmalloc subsystem
+ *******************************************************************/
+
+struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __cacheline_aligned;
+EXPORT_SYMBOL(kmalloc_caches);
+
+#ifdef CONFIG_ZONE_DMA
+static struct kmem_cache *kmalloc_caches_dma[KMALLOC_SHIFT_HIGH + 1];
+#endif
+
+static int __init setup_slub_min_order(char *str)
+{
+	get_option (&str, &slub_min_order);
+
+	return 1;
+}
+
+__setup("slub_min_order=", setup_slub_min_order);
+
+static int __init setup_slub_max_order(char *str)
+{
+	get_option (&str, &slub_max_order);
+
+	return 1;
+}
+
+__setup("slub_max_order=", setup_slub_max_order);
+
+static int __init setup_slub_min_objects(char *str)
+{
+	get_option (&str, &slub_min_objects);
+
+	return 1;
+}
+
+__setup("slub_min_objects=", setup_slub_min_objects);
+
+static int __init setup_slub_nomerge(char *str)
+{
+	slub_nomerge = 1;
+	return 1;
+}
+
+__setup("slub_nomerge", setup_slub_nomerge);
+
+static int __init setup_slub_debug(char *str)
+{
+	if (!str || *str != '=')
+		slub_debug = DEBUG_DEFAULT_FLAGS;
+	else {
+		str++;
+		if (*str == 0 || *str == ',')
+			slub_debug = DEBUG_DEFAULT_FLAGS;
+		else
+		for( ;*str && *str != ','; str++)
+			switch (*str) {
+			case 'f' : case 'F' :
+				slub_debug |= SLAB_DEBUG_FREE;
+				break;
+			case 'z' : case 'Z' :
+				slub_debug |= SLAB_RED_ZONE;
+				break;
+			case 'p' : case 'P' :
+				slub_debug |= SLAB_POISON;
+				break;
+			case 'u' : case 'U' :
+				slub_debug |= SLAB_STORE_USER;
+				break;
+			case 't' : case 'T' :
+				slub_debug |= SLAB_TRACE;
+				break;
+			default:
+				printk(KERN_ERR "slub_debug option '%c' "
+					"unknown. skipped\n",*str);
+			}
+	}
+
+	if (*str == ',')
+		slub_debug_slabs = str + 1;
+	return 1;
+}
+
+__setup("slub_debug", setup_slub_debug);
+
+static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
+		const char *name, int size, gfp_t gfp_flags)
+{
+	unsigned int flags = 0;
+
+	if (gfp_flags & SLUB_DMA)
+		flags = SLAB_CACHE_DMA;
+
+	down_write(&slub_lock);
+	if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN,
+			flags, NULL, NULL))
+		goto panic;
+
+	list_add(&s->list, &slab_caches);
+	up_write(&slub_lock);
+	if (sysfs_slab_add(s))
+		goto panic;
+	return s;
+
+panic:
+	panic("Creation of kmalloc slab %s size=%d failed.\n", name, size);
+}
+
+static struct kmem_cache *get_slab(size_t size, gfp_t flags)
+{
+	int index = kmalloc_index(size);
+
+	if (!index)
+		return NULL;
+
+	/* Allocation too large? */
+	BUG_ON(index < 0);
+
+#ifdef CONFIG_ZONE_DMA
+	if ((flags & SLUB_DMA)) {
+		struct kmem_cache *s;
+		struct kmem_cache *x;
+		char *text;
+		size_t realsize;
+
+		s = kmalloc_caches_dma[index];
+		if (s)
+			return s;
+
+		/* Dynamically create dma cache */
+		x = kmalloc(kmem_size, flags & ~SLUB_DMA);
+		if (!x)
+			panic("Unable to allocate memory for dma cache\n");
+
+		if (index <= KMALLOC_SHIFT_HIGH)
+			realsize = 1 << index;
+		else {
+			if (index == 1)
+				realsize = 96;
+			else
+				realsize = 192;
+		}
+
+		text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
+				(unsigned int)realsize);
+		s = create_kmalloc_cache(x, text, realsize, flags);
+		kmalloc_caches_dma[index] = s;
+		return s;
+	}
+#endif
+	return &kmalloc_caches[index];
+}
+
+void *__kmalloc(size_t size, gfp_t flags)
+{
+	struct kmem_cache *s = get_slab(size, flags);
+
+	if (s)
+		return slab_alloc(s, flags, -1, __builtin_return_address(0));
+	return NULL;
+}
+EXPORT_SYMBOL(__kmalloc);
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node)
+{
+	struct kmem_cache *s = get_slab(size, flags);
+
+	if (s)
+		return slab_alloc(s, flags, node, __builtin_return_address(0));
+	return NULL;
+}
+EXPORT_SYMBOL(__kmalloc_node);
+#endif
+
+size_t ksize(const void *object)
+{
+	struct page *page = get_object_page(object);
+	struct kmem_cache *s;
+
+	BUG_ON(!page);
+	s = page->slab;
+	BUG_ON(!s);
+
+	/*
+	 * Debugging requires use of the padding between object
+	 * and whatever may come after it.
+	 */
+	if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
+		return s->objsize;
+
+	/*
+	 * If we have the need to store the freelist pointer
+	 * back there or track user information then we can
+	 * only use the space before that information.
+	 */
+	if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
+		return s->inuse;
+
+	/*
+	 * Else we can use all the padding etc for the allocation
+	 */
+	return s->size;
+}
+EXPORT_SYMBOL(ksize);
+
+void kfree(const void *x)
+{
+	struct kmem_cache *s;
+	struct page *page;
+
+	if (!x)
+		return;
+
+	page = virt_to_head_page(x);
+	s = page->slab;
+
+	slab_free(s, page, (void *)x, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kfree);
+
+/*
+ *  kmem_cache_shrink removes empty slabs from the partial lists
+ *  and then sorts the partially allocated slabs by the number
+ *  of items in use. The slabs with the most items in use
+ *  come first. New allocations will remove these from the
+ *  partial list because they are full. The slabs with the
+ *  least items are placed last. If it happens that the objects
+ *  are freed then the page can be returned to the page allocator.
+ */
+int kmem_cache_shrink(struct kmem_cache *s)
+{
+	int node;
+	int i;
+	struct kmem_cache_node *n;
+	struct page *page;
+	struct page *t;
+	struct list_head *slabs_by_inuse =
+		kmalloc(sizeof(struct list_head) * s->objects, GFP_KERNEL);
+	unsigned long flags;
+
+	if (!slabs_by_inuse)
+		return -ENOMEM;
+
+	flush_all(s);
+	for_each_online_node(node) {
+		n = get_node(s, node);
+
+		if (!n->nr_partial)
+			continue;
+
+		for (i = 0; i < s->objects; i++)
+			INIT_LIST_HEAD(slabs_by_inuse + i);
+
+		spin_lock_irqsave(&n->list_lock, flags);
+
+		/*
+		 * Build lists indexed by the items in use in
+		 * each slab or free slabs if empty.
+		 *
+		 * Note that concurrent frees may occur while
+		 * we hold the list_lock. page->inuse here is
+		 * the upper limit.
+		 */
+		list_for_each_entry_safe(page, t, &n->partial, lru) {
+			if (!page->inuse && slab_trylock(page)) {
+				/*
+				 * Must hold slab lock here because slab_free
+				 * may have freed the last object and be
+				 * waiting to release the slab.
+				 */
+				list_del(&page->lru);
+				n->nr_partial--;
+				slab_unlock(page);
+				discard_slab(s, page);
+			} else {
+				if (n->nr_partial > MAX_PARTIAL)
+					list_move(&page->lru,
+					slabs_by_inuse + page->inuse);
+			}
+		}
+
+		if (n->nr_partial <= MAX_PARTIAL)
+			goto out;
+
+		/*
+		 * Rebuild the partial list with the slabs filled up
+		 * most first and the least used slabs at the end.
+		 */
+		for (i = s->objects - 1; i >= 0; i--)
+			list_splice(slabs_by_inuse + i, n->partial.prev);
+
+	out:
+		spin_unlock_irqrestore(&n->list_lock, flags);
+	}
+
+	kfree(slabs_by_inuse);
+	return 0;
+}
+EXPORT_SYMBOL(kmem_cache_shrink);
+
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ *
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes.  If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc().  If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+	struct kmem_cache *new_cache;
+	void *ret;
+	struct page *page;
+
+	if (unlikely(!p))
+		return kmalloc(new_size, flags);
+
+	if (unlikely(!new_size)) {
+		kfree(p);
+		return NULL;
+	}
+
+	page = virt_to_head_page(p);
+
+	new_cache = get_slab(new_size, flags);
+
+	/*
+ 	 * If new size fits in the current cache, bail out.
+ 	 */
+	if (likely(page->slab == new_cache))
+		return (void *)p;
+
+	ret = kmalloc(new_size, flags);
+	if (ret) {
+		memcpy(ret, p, min(new_size, ksize(p)));
+		kfree(p);
+	}
+	return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
+/********************************************************************
+ *			Basic setup of slabs
+ *******************************************************************/
+
+void __init kmem_cache_init(void)
+{
+	int i;
+
+#ifdef CONFIG_NUMA
+	/*
+	 * Must first have the slab cache available for the allocations of the
+	 * struct kmalloc_cache_node's. There is special bootstrap code in
+	 * kmem_cache_open for slab_state == DOWN.
+	 */
+	create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
+		sizeof(struct kmem_cache_node), GFP_KERNEL);
+#endif
+
+	/* Able to allocate the per node structures */
+	slab_state = PARTIAL;
+
+	/* Caches that are not of the two-to-the-power-of size */
+	create_kmalloc_cache(&kmalloc_caches[1],
+				"kmalloc-96", 96, GFP_KERNEL);
+	create_kmalloc_cache(&kmalloc_caches[2],
+				"kmalloc-192", 192, GFP_KERNEL);
+
+	for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+		create_kmalloc_cache(&kmalloc_caches[i],
+			"kmalloc", 1 << i, GFP_KERNEL);
+
+	slab_state = UP;
+
+	/* Provide the correct kmalloc names now that the caches are up */
+	for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+		kmalloc_caches[i]. name =
+			kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i);
+
+#ifdef CONFIG_SMP
+	register_cpu_notifier(&slab_notifier);
+#endif
+
+	if (nr_cpu_ids)	/* Remove when nr_cpu_ids is fixed upstream ! */
+		kmem_size = offsetof(struct kmem_cache, cpu_slab)
+			 + nr_cpu_ids * sizeof(struct page *);
+
+	printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
+		" Processors=%d, Nodes=%d\n",
+		KMALLOC_SHIFT_HIGH, L1_CACHE_BYTES,
+		slub_min_order, slub_max_order, slub_min_objects,
+		nr_cpu_ids, nr_node_ids);
+}
+
+/*
+ * Find a mergeable slab cache
+ */
+static int slab_unmergeable(struct kmem_cache *s)
+{
+	if (slub_nomerge || (s->flags & SLUB_NEVER_MERGE))
+		return 1;
+
+	if (s->ctor || s->dtor)
+		return 1;
+
+	return 0;
+}
+
+static struct kmem_cache *find_mergeable(size_t size,
+		size_t align, unsigned long flags,
+		void (*ctor)(void *, struct kmem_cache *, unsigned long),
+		void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+	struct list_head *h;
+
+	if (slub_nomerge || (flags & SLUB_NEVER_MERGE))
+		return NULL;
+
+	if (ctor || dtor)
+		return NULL;
+
+	size = ALIGN(size, sizeof(void *));
+	align = calculate_alignment(flags, align, size);
+	size = ALIGN(size, align);
+
+	list_for_each(h, &slab_caches) {
+		struct kmem_cache *s =
+			container_of(h, struct kmem_cache, list);
+
+		if (slab_unmergeable(s))
+			continue;
+
+		if (size > s->size)
+			continue;
+
+		if (((flags | slub_debug) & SLUB_MERGE_SAME) !=
+			(s->flags & SLUB_MERGE_SAME))
+				continue;
+		/*
+		 * Check if alignment is compatible.
+		 * Courtesy of Adrian Drzewiecki
+		 */
+		if ((s->size & ~(align -1)) != s->size)
+			continue;
+
+		if (s->size - size >= sizeof(void *))
+			continue;
+
+		return s;
+	}
+	return NULL;
+}
+
+struct kmem_cache *kmem_cache_create(const char *name, size_t size,
+		size_t align, unsigned long flags,
+		void (*ctor)(void *, struct kmem_cache *, unsigned long),
+		void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+	struct kmem_cache *s;
+
+	down_write(&slub_lock);
+	s = find_mergeable(size, align, flags, dtor, ctor);
+	if (s) {
+		s->refcount++;
+		/*
+		 * Adjust the object sizes so that we clear
+		 * the complete object on kzalloc.
+		 */
+		s->objsize = max(s->objsize, (int)size);
+		s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
+		if (sysfs_slab_alias(s, name))
+			goto err;
+	} else {
+		s = kmalloc(kmem_size, GFP_KERNEL);
+		if (s && kmem_cache_open(s, GFP_KERNEL, name,
+				size, align, flags, ctor, dtor)) {
+			if (sysfs_slab_add(s)) {
+				kfree(s);
+				goto err;
+			}
+			list_add(&s->list, &slab_caches);
+		} else
+			kfree(s);
+	}
+	up_write(&slub_lock);
+	return s;
+
+err:
+	up_write(&slub_lock);
+	if (flags & SLAB_PANIC)
+		panic("Cannot create slabcache %s\n", name);
+	else
+		s = NULL;
+	return s;
+}
+EXPORT_SYMBOL(kmem_cache_create);
+
+void *kmem_cache_zalloc(struct kmem_cache *s, gfp_t flags)
+{
+	void *x;
+
+	x = slab_alloc(s, flags, -1, __builtin_return_address(0));
+	if (x)
+		memset(x, 0, s->objsize);
+	return x;
+}
+EXPORT_SYMBOL(kmem_cache_zalloc);
+
+#ifdef CONFIG_SMP
+static void for_all_slabs(void (*func)(struct kmem_cache *, int), int cpu)
+{
+	struct list_head *h;
+
+	down_read(&slub_lock);
+	list_for_each(h, &slab_caches) {
+		struct kmem_cache *s =
+			container_of(h, struct kmem_cache, list);
+
+		func(s, cpu);
+	}
+	up_read(&slub_lock);
+}
+
+/*
+ * Use the cpu notifier to insure that the slab are flushed
+ * when necessary.
+ */
+static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
+		unsigned long action, void *hcpu)
+{
+	long cpu = (long)hcpu;
+
+	switch (action) {
+	case CPU_UP_CANCELED:
+	case CPU_DEAD:
+		for_all_slabs(__flush_cpu_slab, cpu);
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata slab_notifier =
+	{ &slab_cpuup_callback, NULL, 0 };
+
+#endif
+
+#ifdef CONFIG_NUMA
+
+/*****************************************************************
+ * Generic reaper used to support the page allocator
+ * (the cpu slabs are reaped by a per slab workqueue).
+ *
+ * Maybe move this to the page allocator?
+ ****************************************************************/
+
+static DEFINE_PER_CPU(unsigned long, reap_node);
+
+static void init_reap_node(int cpu)
+{
+	int node;
+
+	node = next_node(cpu_to_node(cpu), node_online_map);
+	if (node == MAX_NUMNODES)
+		node = first_node(node_online_map);
+
+	__get_cpu_var(reap_node) = node;
+}
+
+static void next_reap_node(void)
+{
+	int node = __get_cpu_var(reap_node);
+
+	/*
+	 * Also drain per cpu pages on remote zones
+	 */
+	if (node != numa_node_id())
+		drain_node_pages(node);
+
+	node = next_node(node, node_online_map);
+	if (unlikely(node >= MAX_NUMNODES))
+		node = first_node(node_online_map);
+	__get_cpu_var(reap_node) = node;
+}
+#else
+#define init_reap_node(cpu) do { } while (0)
+#define next_reap_node(void) do { } while (0)
+#endif
+
+#define REAPTIMEOUT_CPUC	(2*HZ)
+
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct delayed_work, reap_work);
+
+static void cache_reap(struct work_struct *unused)
+{
+	next_reap_node();
+	refresh_cpu_vm_stats(smp_processor_id());
+	schedule_delayed_work(&__get_cpu_var(reap_work),
+				      REAPTIMEOUT_CPUC);
+}
+
+static void __devinit start_cpu_timer(int cpu)
+{
+	struct delayed_work *reap_work = &per_cpu(reap_work, cpu);
+
+	/*
+	 * When this gets called from do_initcalls via cpucache_init(),
+	 * init_workqueues() has already run, so keventd will be setup
+	 * at that time.
+	 */
+	if (keventd_up() && reap_work->work.func == NULL) {
+		init_reap_node(cpu);
+		INIT_DELAYED_WORK(reap_work, cache_reap);
+		schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu);
+	}
+}
+
+static int __init cpucache_init(void)
+{
+	int cpu;
+
+	/*
+	 * Register the timers that drain pcp pages and update vm statistics
+	 */
+	for_each_online_cpu(cpu)
+		start_cpu_timer(cpu);
+	return 0;
+}
+__initcall(cpucache_init);
+#endif
+
+#ifdef SLUB_RESILIENCY_TEST
+static unsigned long validate_slab_cache(struct kmem_cache *s);
+
+static void resiliency_test(void)
+{
+	u8 *p;
+
+	printk(KERN_ERR "SLUB resiliency testing\n");
+	printk(KERN_ERR "-----------------------\n");
+	printk(KERN_ERR "A. Corruption after allocation\n");
+
+	p = kzalloc(16, GFP_KERNEL);
+	p[16] = 0x12;
+	printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
+			" 0x12->0x%p\n\n", p + 16);
+
+	validate_slab_cache(kmalloc_caches + 4);
+
+	/* Hmmm... The next two are dangerous */
+	p = kzalloc(32, GFP_KERNEL);
+	p[32 + sizeof(void *)] = 0x34;
+	printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
+		 	" 0x34 -> -0x%p\n", p);
+	printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+
+	validate_slab_cache(kmalloc_caches + 5);
+	p = kzalloc(64, GFP_KERNEL);
+	p += 64 + (get_cycles() & 0xff) * sizeof(void *);
+	*p = 0x56;
+	printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
+									p);
+	printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+	validate_slab_cache(kmalloc_caches + 6);
+
+	printk(KERN_ERR "\nB. Corruption after free\n");
+	p = kzalloc(128, GFP_KERNEL);
+	kfree(p);
+	*p = 0x78;
+	printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
+	validate_slab_cache(kmalloc_caches + 7);
+
+	p = kzalloc(256, GFP_KERNEL);
+	kfree(p);
+	p[50] = 0x9a;
+	printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p);
+	validate_slab_cache(kmalloc_caches + 8);
+
+	p = kzalloc(512, GFP_KERNEL);
+	kfree(p);
+	p[512] = 0xab;
+	printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
+	validate_slab_cache(kmalloc_caches + 9);
+}
+#else
+static void resiliency_test(void) {};
+#endif
+
+/*
+ * These are not as efficient as kmalloc for the non debug case.
+ * We do not have the page struct available so we have to touch one
+ * cacheline in struct kmem_cache to check slab flags.
+ */
+void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
+{
+	struct kmem_cache *s = get_slab(size, gfpflags);
+
+	if (!s)
+		return NULL;
+
+	return slab_alloc(s, gfpflags, -1, caller);
+}
+
+void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
+					int node, void *caller)
+{
+	struct kmem_cache *s = get_slab(size, gfpflags);
+
+	if (!s)
+		return NULL;
+
+	return slab_alloc(s, gfpflags, node, caller);
+}
+
+#ifdef CONFIG_SYSFS
+
+static int validate_slab(struct kmem_cache *s, struct page *page)
+{
+	void *p;
+	void *addr = page_address(page);
+	unsigned long map[BITS_TO_LONGS(s->objects)];
+
+	if (!check_slab(s, page) ||
+			!on_freelist(s, page, NULL))
+		return 0;
+
+	/* Now we know that a valid freelist exists */
+	bitmap_zero(map, s->objects);
+
+	for(p = page->freelist; p; p = get_freepointer(s, p)) {
+		set_bit((p - addr) / s->size, map);
+		if (!check_object(s, page, p, 0))
+			return 0;
+	}
+
+	for(p = addr; p < addr + s->objects * s->size; p += s->size)
+		if (!test_bit((p - addr) / s->size, map))
+			if (!check_object(s, page, p, 1))
+				return 0;
+	return 1;
+}
+
+static void validate_slab_slab(struct kmem_cache *s, struct page *page)
+{
+	if (slab_trylock(page)) {
+		validate_slab(s, page);
+		slab_unlock(page);
+	} else
+		printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
+			s->name, page);
+
+	if (s->flags & DEBUG_DEFAULT_FLAGS) {
+		if (!PageError(page))
+			printk(KERN_ERR "SLUB %s: PageError not set "
+				"on slab 0x%p\n", s->name, page);
+	} else {
+		if (PageError(page))
+			printk(KERN_ERR "SLUB %s: PageError set on "
+				"slab 0x%p\n", s->name, page);
+	}
+}
+
+static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
+{
+	unsigned long count = 0;
+	struct page *page;
+	unsigned long flags;
+
+	spin_lock_irqsave(&n->list_lock, flags);
+
+	list_for_each_entry(page, &n->partial, lru) {
+		validate_slab_slab(s, page);
+		count++;
+	}
+	if (count != n->nr_partial)
+		printk(KERN_ERR "SLUB %s: %ld partial slabs counted but "
+			"counter=%ld\n", s->name, count, n->nr_partial);
+
+	if (!(s->flags & SLAB_STORE_USER))
+		goto out;
+
+	list_for_each_entry(page, &n->full, lru) {
+		validate_slab_slab(s, page);
+		count++;
+	}
+	if (count != atomic_long_read(&n->nr_slabs))
+		printk(KERN_ERR "SLUB: %s %ld slabs counted but "
+			"counter=%ld\n", s->name, count,
+			atomic_long_read(&n->nr_slabs));
+
+out:
+	spin_unlock_irqrestore(&n->list_lock, flags);
+	return count;
+}
+
+static unsigned long validate_slab_cache(struct kmem_cache *s)
+{
+	int node;
+	unsigned long count = 0;
+
+	flush_all(s);
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+
+		count += validate_slab_node(s, n);
+	}
+	return count;
+}
+
+/*
+ * Generate lists of locations where slabcache objects are allocated
+ * and freed.
+ */
+
+struct location {
+	unsigned long count;
+	void *addr;
+};
+
+struct loc_track {
+	unsigned long max;
+	unsigned long count;
+	struct location *loc;
+};
+
+static void free_loc_track(struct loc_track *t)
+{
+	if (t->max)
+		free_pages((unsigned long)t->loc,
+			get_order(sizeof(struct location) * t->max));
+}
+
+static int alloc_loc_track(struct loc_track *t, unsigned long max)
+{
+	struct location *l;
+	int order;
+
+	if (!max)
+		max = PAGE_SIZE / sizeof(struct location);
+
+	order = get_order(sizeof(struct location) * max);
+
+	l = (void *)__get_free_pages(GFP_KERNEL, order);
+
+	if (!l)
+		return 0;
+
+	if (t->count) {
+		memcpy(l, t->loc, sizeof(struct location) * t->count);
+		free_loc_track(t);
+	}
+	t->max = max;
+	t->loc = l;
+	return 1;
+}
+
+static int add_location(struct loc_track *t, struct kmem_cache *s,
+						void *addr)
+{
+	long start, end, pos;
+	struct location *l;
+	void *caddr;
+
+	start = -1;
+	end = t->count;
+
+	for ( ; ; ) {
+		pos = start + (end - start + 1) / 2;
+
+		/*
+		 * There is nothing at "end". If we end up there
+		 * we need to add something to before end.
+		 */
+		if (pos == end)
+			break;
+
+		caddr = t->loc[pos].addr;
+		if (addr == caddr) {
+			t->loc[pos].count++;
+			return 1;
+		}
+
+		if (addr < caddr)
+			end = pos;
+		else
+			start = pos;
+	}
+
+	/*
+	 * Not found. Insert new tracking element
+	 */
+	if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max))
+		return 0;
+
+	l = t->loc + pos;
+	if (pos < t->count)
+		memmove(l + 1, l,
+			(t->count - pos) * sizeof(struct location));
+	t->count++;
+	l->count = 1;
+	l->addr = addr;
+	return 1;
+}
+
+static void process_slab(struct loc_track *t, struct kmem_cache *s,
+		struct page *page, enum track_item alloc)
+{
+	void *addr = page_address(page);
+	unsigned long map[BITS_TO_LONGS(s->objects)];
+	void *p;
+
+	bitmap_zero(map, s->objects);
+	for (p = page->freelist; p; p = get_freepointer(s, p))
+		set_bit((p - addr) / s->size, map);
+
+	for (p = addr; p < addr + s->objects * s->size; p += s->size)
+		if (!test_bit((p - addr) / s->size, map)) {
+			void *addr = get_track(s, p, alloc)->addr;
+
+			add_location(t, s, addr);
+		}
+}
+
+static int list_locations(struct kmem_cache *s, char *buf,
+					enum track_item alloc)
+{
+	int n = 0;
+	unsigned long i;
+	struct loc_track t;
+	int node;
+
+	t.count = 0;
+	t.max = 0;
+
+	/* Push back cpu slabs */
+	flush_all(s);
+
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+		unsigned long flags;
+		struct page *page;
+
+		if (!atomic_read(&n->nr_slabs))
+			continue;
+
+		spin_lock_irqsave(&n->list_lock, flags);
+		list_for_each_entry(page, &n->partial, lru)
+			process_slab(&t, s, page, alloc);
+		list_for_each_entry(page, &n->full, lru)
+			process_slab(&t, s, page, alloc);
+		spin_unlock_irqrestore(&n->list_lock, flags);
+	}
+
+	for (i = 0; i < t.count; i++) {
+		void *addr = t.loc[i].addr;
+
+		if (n > PAGE_SIZE - 100)
+			break;
+		n += sprintf(buf + n, "%7ld ", t.loc[i].count);
+		if (addr)
+			n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr);
+		else
+			n += sprintf(buf + n, "<not-available>");
+		n += sprintf(buf + n, "\n");
+	}
+
+	free_loc_track(&t);
+	if (!t.count)
+		n += sprintf(buf, "No data\n");
+	return n;
+}
+
+static unsigned long count_partial(struct kmem_cache_node *n)
+{
+	unsigned long flags;
+	unsigned long x = 0;
+	struct page *page;
+
+	spin_lock_irqsave(&n->list_lock, flags);
+	list_for_each_entry(page, &n->partial, lru)
+		x += page->inuse;
+	spin_unlock_irqrestore(&n->list_lock, flags);
+	return x;
+}
+
+enum slab_stat_type {
+	SL_FULL,
+	SL_PARTIAL,
+	SL_CPU,
+	SL_OBJECTS
+};
+
+#define SO_FULL		(1 << SL_FULL)
+#define SO_PARTIAL	(1 << SL_PARTIAL)
+#define SO_CPU		(1 << SL_CPU)
+#define SO_OBJECTS	(1 << SL_OBJECTS)
+
+static unsigned long slab_objects(struct kmem_cache *s,
+			char *buf, unsigned long flags)
+{
+	unsigned long total = 0;
+	int cpu;
+	int node;
+	int x;
+	unsigned long *nodes;
+	unsigned long *per_cpu;
+
+	nodes = kzalloc(2 * sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
+	per_cpu = nodes + nr_node_ids;
+
+	for_each_possible_cpu(cpu) {
+		struct page *page = s->cpu_slab[cpu];
+		int node;
+
+		if (page) {
+			node = page_to_nid(page);
+			if (flags & SO_CPU) {
+				int x = 0;
+
+				if (flags & SO_OBJECTS)
+					x = page->inuse;
+				else
+					x = 1;
+				total += x;
+				nodes[node] += x;
+			}
+			per_cpu[node]++;
+		}
+	}
+
+	for_each_online_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+
+		if (flags & SO_PARTIAL) {
+			if (flags & SO_OBJECTS)
+				x = count_partial(n);
+			else
+				x = n->nr_partial;
+			total += x;
+			nodes[node] += x;
+		}
+
+		if (flags & SO_FULL) {
+			int full_slabs = atomic_read(&n->nr_slabs)
+					- per_cpu[node]
+					- n->nr_partial;
+
+			if (flags & SO_OBJECTS)
+				x = full_slabs * s->objects;
+			else
+				x = full_slabs;
+			total += x;
+			nodes[node] += x;
+		}
+	}
+
+	x = sprintf(buf, "%lu", total);
+#ifdef CONFIG_NUMA
+	for_each_online_node(node)
+		if (nodes[node])
+			x += sprintf(buf + x, " N%d=%lu",
+					node, nodes[node]);
+#endif
+	kfree(nodes);
+	return x + sprintf(buf + x, "\n");
+}
+
+static int any_slab_objects(struct kmem_cache *s)
+{
+	int node;
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		if (s->cpu_slab[cpu])
+			return 1;
+
+	for_each_node(node) {
+		struct kmem_cache_node *n = get_node(s, node);
+
+		if (n->nr_partial || atomic_read(&n->nr_slabs))
+			return 1;
+	}
+	return 0;
+}
+
+#define to_slab_attr(n) container_of(n, struct slab_attribute, attr)
+#define to_slab(n) container_of(n, struct kmem_cache, kobj);
+
+struct slab_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kmem_cache *s, char *buf);
+	ssize_t (*store)(struct kmem_cache *s, const char *x, size_t count);
+};
+
+#define SLAB_ATTR_RO(_name) \
+	static struct slab_attribute _name##_attr = __ATTR_RO(_name)
+
+#define SLAB_ATTR(_name) \
+	static struct slab_attribute _name##_attr =  \
+	__ATTR(_name, 0644, _name##_show, _name##_store)
+
+static ssize_t slab_size_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->size);
+}
+SLAB_ATTR_RO(slab_size);
+
+static ssize_t align_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->align);
+}
+SLAB_ATTR_RO(align);
+
+static ssize_t object_size_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->objsize);
+}
+SLAB_ATTR_RO(object_size);
+
+static ssize_t objs_per_slab_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->objects);
+}
+SLAB_ATTR_RO(objs_per_slab);
+
+static ssize_t order_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->order);
+}
+SLAB_ATTR_RO(order);
+
+static ssize_t ctor_show(struct kmem_cache *s, char *buf)
+{
+	if (s->ctor) {
+		int n = sprint_symbol(buf, (unsigned long)s->ctor);
+
+		return n + sprintf(buf + n, "\n");
+	}
+	return 0;
+}
+SLAB_ATTR_RO(ctor);
+
+static ssize_t dtor_show(struct kmem_cache *s, char *buf)
+{
+	if (s->dtor) {
+		int n = sprint_symbol(buf, (unsigned long)s->dtor);
+
+		return n + sprintf(buf + n, "\n");
+	}
+	return 0;
+}
+SLAB_ATTR_RO(dtor);
+
+static ssize_t aliases_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->refcount - 1);
+}
+SLAB_ATTR_RO(aliases);
+
+static ssize_t slabs_show(struct kmem_cache *s, char *buf)
+{
+	return slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU);
+}
+SLAB_ATTR_RO(slabs);
+
+static ssize_t partial_show(struct kmem_cache *s, char *buf)
+{
+	return slab_objects(s, buf, SO_PARTIAL);
+}
+SLAB_ATTR_RO(partial);
+
+static ssize_t cpu_slabs_show(struct kmem_cache *s, char *buf)
+{
+	return slab_objects(s, buf, SO_CPU);
+}
+SLAB_ATTR_RO(cpu_slabs);
+
+static ssize_t objects_show(struct kmem_cache *s, char *buf)
+{
+	return slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU|SO_OBJECTS);
+}
+SLAB_ATTR_RO(objects);
+
+static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
+}
+
+static ssize_t sanity_checks_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	s->flags &= ~SLAB_DEBUG_FREE;
+	if (buf[0] == '1')
+		s->flags |= SLAB_DEBUG_FREE;
+	return length;
+}
+SLAB_ATTR(sanity_checks);
+
+static ssize_t trace_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE));
+}
+
+static ssize_t trace_store(struct kmem_cache *s, const char *buf,
+							size_t length)
+{
+	s->flags &= ~SLAB_TRACE;
+	if (buf[0] == '1')
+		s->flags |= SLAB_TRACE;
+	return length;
+}
+SLAB_ATTR(trace);
+
+static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
+}
+
+static ssize_t reclaim_account_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	s->flags &= ~SLAB_RECLAIM_ACCOUNT;
+	if (buf[0] == '1')
+		s->flags |= SLAB_RECLAIM_ACCOUNT;
+	return length;
+}
+SLAB_ATTR(reclaim_account);
+
+static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN));
+}
+SLAB_ATTR_RO(hwcache_align);
+
+#ifdef CONFIG_ZONE_DMA
+static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA));
+}
+SLAB_ATTR_RO(cache_dma);
+#endif
+
+static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU));
+}
+SLAB_ATTR_RO(destroy_by_rcu);
+
+static ssize_t red_zone_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_RED_ZONE));
+}
+
+static ssize_t red_zone_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	if (any_slab_objects(s))
+		return -EBUSY;
+
+	s->flags &= ~SLAB_RED_ZONE;
+	if (buf[0] == '1')
+		s->flags |= SLAB_RED_ZONE;
+	calculate_sizes(s);
+	return length;
+}
+SLAB_ATTR(red_zone);
+
+static ssize_t poison_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_POISON));
+}
+
+static ssize_t poison_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	if (any_slab_objects(s))
+		return -EBUSY;
+
+	s->flags &= ~SLAB_POISON;
+	if (buf[0] == '1')
+		s->flags |= SLAB_POISON;
+	calculate_sizes(s);
+	return length;
+}
+SLAB_ATTR(poison);
+
+static ssize_t store_user_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", !!(s->flags & SLAB_STORE_USER));
+}
+
+static ssize_t store_user_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	if (any_slab_objects(s))
+		return -EBUSY;
+
+	s->flags &= ~SLAB_STORE_USER;
+	if (buf[0] == '1')
+		s->flags |= SLAB_STORE_USER;
+	calculate_sizes(s);
+	return length;
+}
+SLAB_ATTR(store_user);
+
+static ssize_t validate_show(struct kmem_cache *s, char *buf)
+{
+	return 0;
+}
+
+static ssize_t validate_store(struct kmem_cache *s,
+			const char *buf, size_t length)
+{
+	if (buf[0] == '1')
+		validate_slab_cache(s);
+	else
+		return -EINVAL;
+	return length;
+}
+SLAB_ATTR(validate);
+
+static ssize_t shrink_show(struct kmem_cache *s, char *buf)
+{
+	return 0;
+}
+
+static ssize_t shrink_store(struct kmem_cache *s,
+			const char *buf, size_t length)
+{
+	if (buf[0] == '1') {
+		int rc = kmem_cache_shrink(s);
+
+		if (rc)
+			return rc;
+	} else
+		return -EINVAL;
+	return length;
+}
+SLAB_ATTR(shrink);
+
+static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)
+{
+	if (!(s->flags & SLAB_STORE_USER))
+		return -ENOSYS;
+	return list_locations(s, buf, TRACK_ALLOC);
+}
+SLAB_ATTR_RO(alloc_calls);
+
+static ssize_t free_calls_show(struct kmem_cache *s, char *buf)
+{
+	if (!(s->flags & SLAB_STORE_USER))
+		return -ENOSYS;
+	return list_locations(s, buf, TRACK_FREE);
+}
+SLAB_ATTR_RO(free_calls);
+
+#ifdef CONFIG_NUMA
+static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf)
+{
+	return sprintf(buf, "%d\n", s->defrag_ratio / 10);
+}
+
+static ssize_t defrag_ratio_store(struct kmem_cache *s,
+				const char *buf, size_t length)
+{
+	int n = simple_strtoul(buf, NULL, 10);
+
+	if (n < 100)
+		s->defrag_ratio = n * 10;
+	return length;
+}
+SLAB_ATTR(defrag_ratio);
+#endif
+
+static struct attribute * slab_attrs[] = {
+	&slab_size_attr.attr,
+	&object_size_attr.attr,
+	&objs_per_slab_attr.attr,
+	&order_attr.attr,
+	&objects_attr.attr,
+	&slabs_attr.attr,
+	&partial_attr.attr,
+	&cpu_slabs_attr.attr,
+	&ctor_attr.attr,
+	&dtor_attr.attr,
+	&aliases_attr.attr,
+	&align_attr.attr,
+	&sanity_checks_attr.attr,
+	&trace_attr.attr,
+	&hwcache_align_attr.attr,
+	&reclaim_account_attr.attr,
+	&destroy_by_rcu_attr.attr,
+	&red_zone_attr.attr,
+	&poison_attr.attr,
+	&store_user_attr.attr,
+	&validate_attr.attr,
+	&shrink_attr.attr,
+	&alloc_calls_attr.attr,
+	&free_calls_attr.attr,
+#ifdef CONFIG_ZONE_DMA
+	&cache_dma_attr.attr,
+#endif
+#ifdef CONFIG_NUMA
+	&defrag_ratio_attr.attr,
+#endif
+	NULL
+};
+
+static struct attribute_group slab_attr_group = {
+	.attrs = slab_attrs,
+};
+
+static ssize_t slab_attr_show(struct kobject *kobj,
+				struct attribute *attr,
+				char *buf)
+{
+	struct slab_attribute *attribute;
+	struct kmem_cache *s;
+	int err;
+
+	attribute = to_slab_attr(attr);
+	s = to_slab(kobj);
+
+	if (!attribute->show)
+		return -EIO;
+
+	err = attribute->show(s, buf);
+
+	return err;
+}
+
+static ssize_t slab_attr_store(struct kobject *kobj,
+				struct attribute *attr,
+				const char *buf, size_t len)
+{
+	struct slab_attribute *attribute;
+	struct kmem_cache *s;
+	int err;
+
+	attribute = to_slab_attr(attr);
+	s = to_slab(kobj);
+
+	if (!attribute->store)
+		return -EIO;
+
+	err = attribute->store(s, buf, len);
+
+	return err;
+}
+
+static struct sysfs_ops slab_sysfs_ops = {
+	.show = slab_attr_show,
+	.store = slab_attr_store,
+};
+
+static struct kobj_type slab_ktype = {
+	.sysfs_ops = &slab_sysfs_ops,
+};
+
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	if (ktype == &slab_ktype)
+		return 1;
+	return 0;
+}
+
+static struct kset_uevent_ops slab_uevent_ops = {
+	.filter = uevent_filter,
+};
+
+decl_subsys(slab, &slab_ktype, &slab_uevent_ops);
+
+#define ID_STR_LENGTH 64
+
+/* Create a unique string id for a slab cache:
+ * format
+ * :[flags-]size:[memory address of kmemcache]
+ */
+static char *create_unique_id(struct kmem_cache *s)
+{
+	char *name = kmalloc(ID_STR_LENGTH, GFP_KERNEL);
+	char *p = name;
+
+	BUG_ON(!name);
+
+	*p++ = ':';
+	/*
+	 * First flags affecting slabcache operations. We will only
+	 * get here for aliasable slabs so we do not need to support
+	 * too many flags. The flags here must cover all flags that
+	 * are matched during merging to guarantee that the id is
+	 * unique.
+	 */
+	if (s->flags & SLAB_CACHE_DMA)
+		*p++ = 'd';
+	if (s->flags & SLAB_RECLAIM_ACCOUNT)
+		*p++ = 'a';
+	if (s->flags & SLAB_DEBUG_FREE)
+		*p++ = 'F';
+	if (p != name + 1)
+		*p++ = '-';
+	p += sprintf(p, "%07d", s->size);
+	BUG_ON(p > name + ID_STR_LENGTH - 1);
+	return name;
+}
+
+static int sysfs_slab_add(struct kmem_cache *s)
+{
+	int err;
+	const char *name;
+	int unmergeable;
+
+	if (slab_state < SYSFS)
+		/* Defer until later */
+		return 0;
+
+	unmergeable = slab_unmergeable(s);
+	if (unmergeable) {
+		/*
+		 * Slabcache can never be merged so we can use the name proper.
+		 * This is typically the case for debug situations. In that
+		 * case we can catch duplicate names easily.
+		 */
+		sysfs_remove_link(&slab_subsys.kobj, s->name);
+		name = s->name;
+	} else {
+		/*
+		 * Create a unique name for the slab as a target
+		 * for the symlinks.
+		 */
+		name = create_unique_id(s);
+	}
+
+	kobj_set_kset_s(s, slab_subsys);
+	kobject_set_name(&s->kobj, name);
+	kobject_init(&s->kobj);
+	err = kobject_add(&s->kobj);
+	if (err)
+		return err;
+
+	err = sysfs_create_group(&s->kobj, &slab_attr_group);
+	if (err)
+		return err;
+	kobject_uevent(&s->kobj, KOBJ_ADD);
+	if (!unmergeable) {
+		/* Setup first alias */
+		sysfs_slab_alias(s, s->name);
+		kfree(name);
+	}
+	return 0;
+}
+
+static void sysfs_slab_remove(struct kmem_cache *s)
+{
+	kobject_uevent(&s->kobj, KOBJ_REMOVE);
+	kobject_del(&s->kobj);
+}
+
+/*
+ * Need to buffer aliases during bootup until sysfs becomes
+ * available lest we loose that information.
+ */
+struct saved_alias {
+	struct kmem_cache *s;
+	const char *name;
+	struct saved_alias *next;
+};
+
+struct saved_alias *alias_list;
+
+static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
+{
+	struct saved_alias *al;
+
+	if (slab_state == SYSFS) {
+		/*
+		 * If we have a leftover link then remove it.
+		 */
+		sysfs_remove_link(&slab_subsys.kobj, name);
+		return sysfs_create_link(&slab_subsys.kobj,
+						&s->kobj, name);
+	}
+
+	al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL);
+	if (!al)
+		return -ENOMEM;
+
+	al->s = s;
+	al->name = name;
+	al->next = alias_list;
+	alias_list = al;
+	return 0;
+}
+
+static int __init slab_sysfs_init(void)
+{
+	int err;
+
+	err = subsystem_register(&slab_subsys);
+	if (err) {
+		printk(KERN_ERR "Cannot register slab subsystem.\n");
+		return -ENOSYS;
+	}
+
+	finish_bootstrap();
+
+	while (alias_list) {
+		struct saved_alias *al = alias_list;
+
+		alias_list = alias_list->next;
+		err = sysfs_slab_alias(al->s, al->name);
+		BUG_ON(err);
+		kfree(al);
+	}
+
+	resiliency_test();
+	return 0;
+}
+
+__initcall(slab_sysfs_init);
+#else
+__initcall(finish_bootstrap);
+#endif
diff --git a/mm/sparse.c b/mm/sparse.c
index ac26eb0..6f3fff9 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(page_to_nid);
 #endif
 
 #ifdef CONFIG_SPARSEMEM_EXTREME
-static struct mem_section *sparse_index_alloc(int nid)
+static struct mem_section noinline *sparse_index_alloc(int nid)
 {
 	struct mem_section *section = NULL;
 	unsigned long array_size = SECTIONS_PER_ROOT *
@@ -61,7 +61,7 @@ static struct mem_section *sparse_index_
 	return section;
 }
 
-static int sparse_index_init(unsigned long section_nr, int nid)
+static int __meminit sparse_index_init(unsigned long section_nr, int nid)
 {
 	static DEFINE_SPINLOCK(index_init_lock);
 	unsigned long root = SECTION_NR_TO_ROOT(section_nr);
@@ -138,7 +138,7 @@ static inline int sparse_early_nid(struc
 }
 
 /* Record a memory area against a node. */
-void memory_present(int nid, unsigned long start, unsigned long end)
+void __init memory_present(int nid, unsigned long start, unsigned long end)
 {
 	unsigned long pfn;
 
@@ -197,7 +197,7 @@ struct page *sparse_decode_mem_map(unsig
 	return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
 }
 
-static int sparse_init_one_section(struct mem_section *ms,
+static int __meminit sparse_init_one_section(struct mem_section *ms,
 		unsigned long pnum, struct page *mem_map)
 {
 	if (!valid_section(ms))
@@ -209,7 +209,7 @@ static int sparse_init_one_section(struc
 	return 1;
 }
 
-static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
+static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
 {
 	struct page *map;
 	struct mem_section *ms = __nr_to_section(pnum);
@@ -272,7 +272,7 @@ static void __kfree_section_memmap(struc
  * Allocate the accumulated non-linear sections, allocate a mem_map
  * for each and record the physical to section mapping.
  */
-void sparse_init(void)
+void __init sparse_init(void)
 {
 	unsigned long pnum;
 	struct page *map;
@@ -288,6 +288,7 @@ void sparse_init(void)
 	}
 }
 
+#ifdef CONFIG_MEMORY_HOTPLUG
 /*
  * returns the number of sections whose mem_maps were properly
  * set.  If this is <=0, then that means that the passed-in
@@ -327,3 +328,4 @@ out:
 		__kfree_section_memmap(memmap, nr_pages);
 	return ret;
 }
+#endif
diff --git a/mm/swap.c b/mm/swap.c
index 2ed7be3..218c52a 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -55,7 +55,7 @@ static void fastcall __page_cache_releas
 
 static void put_compound_page(struct page *page)
 {
-	page = (struct page *)page_private(page);
+	page = compound_head(page);
 	if (put_page_testzero(page)) {
 		compound_page_dtor *dtor;
 
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a2d9bb4..acc172c 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1531,9 +1531,6 @@ asmlinkage long sys_swapon(const char __
 		error = PTR_ERR(page);
 		goto bad_swap;
 	}
-	wait_on_page_locked(page);
-	if (!PageUptodate(page))
-		goto bad_swap;
 	kmap(page);
 	swap_header = page_address(page);
 
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9eef486..faa2a52 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -431,7 +431,7 @@ void *__vmalloc_area_node(struct vm_stru
 		area->flags |= VM_VPAGES;
 	} else {
 		pages = kmalloc_node(array_size,
-				(gfp_mask & ~(__GFP_HIGHMEM | __GFP_ZERO)),
+				(gfp_mask & GFP_LEVEL_MASK),
 				node);
 	}
 	area->pages = pages;
@@ -577,6 +577,14 @@ void *vmalloc_exec(unsigned long size)
 	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
 }
 
+#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
+#define GFP_VMALLOC32 GFP_DMA32
+#elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
+#define GFP_VMALLOC32 GFP_DMA
+#else
+#define GFP_VMALLOC32 GFP_KERNEL
+#endif
+
 /**
  *	vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  *	@size:		allocation size
@@ -586,7 +594,7 @@ void *vmalloc_exec(unsigned long size)
  */
 void *vmalloc_32(unsigned long size)
 {
-	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
+	return __vmalloc(size, GFP_VMALLOC32, PAGE_KERNEL);
 }
 EXPORT_SYMBOL(vmalloc_32);
 
@@ -602,7 +610,7 @@ void *vmalloc_32_user(unsigned long size
 	struct vm_struct *area;
 	void *ret;
 
-	ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+	ret = __vmalloc(size, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL);
 	if (ret) {
 		write_lock(&vmlist_lock);
 		area = __find_vm_area(ret);
@@ -747,3 +755,10 @@ out_einval_locked:
 }
 EXPORT_SYMBOL(remap_vmalloc_range);
 
+/*
+ * Implement a stub for vmalloc_sync_all() if the architecture chose not to
+ * have one.
+ */
+void  __attribute__((weak)) vmalloc_sync_all(void)
+{
+}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index db023e2..1c8e75a 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -284,12 +284,8 @@ static void handle_write_error(struct ad
 				struct page *page, int error)
 {
 	lock_page(page);
-	if (page_mapping(page) == mapping) {
-		if (error == -ENOSPC)
-			set_bit(AS_ENOSPC, &mapping->flags);
-		else
-			set_bit(AS_EIO, &mapping->flags);
-	}
+	if (page_mapping(page) == mapping)
+		mapping_set_error(mapping, error);
 	unlock_page(page);
 }
 
@@ -1323,8 +1319,6 @@ static int kswapd(void *p)
 	for ( ; ; ) {
 		unsigned long new_order;
 
-		try_to_freeze();
-
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		new_order = pgdat->kswapd_max_order;
 		pgdat->kswapd_max_order = 0;
@@ -1335,12 +1329,19 @@ static int kswapd(void *p)
 			 */
 			order = new_order;
 		} else {
-			schedule();
+			if (!freezing(current))
+				schedule();
+
 			order = pgdat->kswapd_max_order;
 		}
 		finish_wait(&pgdat->kswapd_wait, &wait);
 
-		balance_pgdat(pgdat, order);
+		if (!try_to_freeze()) {
+			/* We can speed up thawing tasks if we don't call
+			 * balance_pgdat after returning from the refrigerator
+			 */
+			balance_pgdat(pgdat, order);
+		}
 	}
 	return 0;
 }
diff --git a/net/802/fddi.c b/net/802/fddi.c
index ace6386..91dde41 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -100,7 +100,7 @@ static int fddi_rebuild_header(struct sk
 	struct fddihdr *fddi = (struct fddihdr *)skb->data;
 
 #ifdef CONFIG_INET
-	if (fddi->hdr.llc_snap.ethertype == __constant_htons(ETH_P_IP))
+	if (fddi->hdr.llc_snap.ethertype == htons(ETH_P_IP))
 		/* Try to get ARP to resolve the header and fill destination address */
 		return arp_find(fddi->daddr, skb);
 	else
@@ -130,12 +130,13 @@ __be16 fddi_type_trans(struct sk_buff *s
 	 * to start of packet data.  Assume 802.2 SNAP frames for now.
 	 */
 
-	skb->mac.raw = skb->data;	/* point to frame control (FC) */
+	skb->dev = dev;
+	skb_reset_mac_header(skb);	/* point to frame control (FC) */
 
 	if(fddi->hdr.llc_8022_1.dsap==0xe0)
 	{
 		skb_pull(skb, FDDI_K_8022_HLEN-3);
-		type = __constant_htons(ETH_P_802_2);
+		type = htons(ETH_P_802_2);
 	}
 	else
 	{
diff --git a/net/802/hippi.c b/net/802/hippi.c
index 578f2a3..87ffc12 100644
--- a/net/802/hippi.c
+++ b/net/802/hippi.c
@@ -60,7 +60,7 @@ static int hippi_header(struct sk_buff *
 	 * Due to the stupidity of the little endian byte-order we
 	 * have to set the fp field this way.
 	 */
-	hip->fp.fixed		= __constant_htonl(0x04800018);
+	hip->fp.fixed		= htonl(0x04800018);
 	hip->fp.d2_size		= htonl(len + 8);
 	hip->le.fc		= 0;
 	hip->le.double_wide	= 0;	/* only HIPPI 800 for the time being */
@@ -104,7 +104,7 @@ static int hippi_rebuild_header(struct s
 	 * Only IP is currently supported
 	 */
 
-	if(hip->snap.ethertype != __constant_htons(ETH_P_IP))
+	if(hip->snap.ethertype != htons(ETH_P_IP))
 	{
 		printk(KERN_DEBUG "%s: unable to resolve type %X addresses.\n",skb->dev->name,ntohs(hip->snap.ethertype));
 		return 0;
@@ -126,14 +126,14 @@ __be16 hippi_type_trans(struct sk_buff *
 {
 	struct hippi_hdr *hip;
 
-	hip = (struct hippi_hdr *) skb->data;
-
 	/*
 	 * This is actually wrong ... question is if we really should
 	 * set the raw address here.
 	 */
-	 skb->mac.raw = skb->data;
-	 skb_pull(skb, HIPPI_HLEN);
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
+	hip = (struct hippi_hdr *)skb_mac_header(skb);
+	skb_pull(skb, HIPPI_HLEN);
 
 	/*
 	 * No fancy promisc stuff here now.
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 6e7c212..04ee43e 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -56,10 +56,10 @@ static int snap_rcv(struct sk_buff *skb,
 	};
 
 	rcu_read_lock();
-	proto = find_snap_client(skb->h.raw);
+	proto = find_snap_client(skb_transport_header(skb));
 	if (proto) {
 		/* Pass the frame on. */
-		skb->h.raw  += 5;
+		skb->transport_header += 5;
 		skb_pull_rcsum(skb, 5);
 		rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
 	} else {
diff --git a/net/802/tr.c b/net/802/tr.c
index 96bd144..0ba1946 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -189,11 +189,13 @@ #endif
 __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 
-	struct trh_hdr *trh=(struct trh_hdr *)skb->data;
+	struct trh_hdr *trh;
 	struct trllc *trllc;
 	unsigned riflen=0;
 
-	skb->mac.raw = skb->data;
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
+	trh = tr_hdr(skb);
 
 	if(trh->saddr[0] & TR_RII)
 		riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
@@ -552,7 +554,8 @@ static int rif_seq_show(struct seq_file 
 					if(j==1) {
 						segment=ntohs(entry->rseg[j-1])>>4;
 						seq_printf(seq,"  %03X",segment);
-					};
+					}
+
 					segment=ntohs(entry->rseg[j])>>4;
 					brdgnmb=ntohs(entry->rseg[j-1])&0x00f;
 					seq_printf(seq,"-%01X-%03X",brdgnmb,segment);
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index eb1c71e..bd93c45 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -117,8 +117,7 @@ static void __exit vlan_cleanup_devices(
 	struct net_device *dev, *nxt;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = nxt) {
-		nxt = dev->next;
+	for_each_netdev_safe(dev, nxt) {
 		if (dev->priv_flags & IFF_802_1Q_VLAN) {
 			unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
 					    VLAN_DEV_INFO(dev)->vlan_id);
@@ -470,7 +469,7 @@ #endif
 		 */
 	default:
 		snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID);
-	};
+	}
 
 	new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
 			       vlan_setup);
@@ -685,7 +684,7 @@ static int vlan_device_event(struct noti
 				break;
 		}
 		break;
-	};
+	}
 
 out:
 	return NOTIFY_DONE;
@@ -819,7 +818,7 @@ #endif
 		printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
 			__FUNCTION__, args.cmd);
 		return -EINVAL;
-	};
+	}
 out:
 	return err;
 }
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index b6e0eea..ec46084 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -66,7 +66,7 @@ #endif
 
 		memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
 		break;
-	};
+	}
 
 	return 0;
 }
@@ -83,7 +83,7 @@ static inline struct sk_buff *vlan_check
 			/* Lifted from Gleb's VLAN code... */
 			memmove(skb->data - ETH_HLEN,
 				skb->data - VLAN_ETH_HLEN, 12);
-			skb->mac.raw += VLAN_HLEN;
+			skb->mac_header += VLAN_HLEN;
 		}
 	}
 
@@ -219,7 +219,7 @@ #endif
 		break;
 	default:
 		break;
-	};
+	}
 
 	/*  Was a VLAN packet, grab the encapsulated protocol, which the layer
 	 * three protocols care about.
@@ -258,7 +258,7 @@ #endif
 	 * won't work for fault tolerant netware but does for the rest.
 	 */
 	if (*(unsigned short *)rawp == 0xFFFF) {
-		skb->protocol = __constant_htons(ETH_P_802_3);
+		skb->protocol = htons(ETH_P_802_3);
 		/* place it back on the queue to be handled by true layer 3 protocols.
 		 */
 
@@ -281,7 +281,7 @@ #endif
 	/*
 	 *	Real 802.2 LLC
 	 */
-	skb->protocol = __constant_htons(ETH_P_802_2);
+	skb->protocol = htons(ETH_P_802_2);
 	/* place it back on the queue to be handled by upper layer protocols.
 	 */
 
@@ -382,7 +382,7 @@ #endif
 		}
 
 		skb->protocol = htons(ETH_P_8021Q);
-		skb->nh.raw = skb->data;
+		skb_reset_network_header(skb);
 	}
 
 	/* Before delegating work to the lower layer, enter our MAC-address */
@@ -448,7 +448,7 @@ int vlan_dev_hard_start_xmit(struct sk_b
 	 * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
 	 */
 
-	if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) {
+	if (veth->h_vlan_proto != htons(ETH_P_8021Q)) {
 		int orig_headroom = skb_headroom(skb);
 		unsigned short veth_TCI;
 
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index 5e24f72..d216a64 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -237,13 +237,9 @@ #endif
  * The following few functions build the content of /proc/net/vlan/config
  */
 
-/* starting at dev, find a VLAN device */
-static struct net_device *vlan_skip(struct net_device *dev)
+static inline int is_vlan_dev(struct net_device *dev)
 {
-	while (dev && !(dev->priv_flags & IFF_802_1Q_VLAN))
-		dev = dev->next;
-
-	return dev;
+	return dev->priv_flags & IFF_802_1Q_VLAN;
 }
 
 /* start read of /proc/net/vlan/config */
@@ -257,19 +253,35 @@ static void *vlan_seq_start(struct seq_f
 	if (*pos == 0)
 		return SEQ_START_TOKEN;
 
-	for (dev = vlan_skip(dev_base); dev && i < *pos;
-	     dev = vlan_skip(dev->next), ++i);
+	for_each_netdev(dev) {
+		if (!is_vlan_dev(dev))
+			continue;
+
+		if (i++ == *pos)
+			return dev;
+	}
 
-	return  (i == *pos) ? dev : NULL;
+	return  NULL;
 }
 
 static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	struct net_device *dev;
+
 	++*pos;
 
-	return vlan_skip((v == SEQ_START_TOKEN)
-			    ? dev_base
-			    : ((struct net_device *)v)->next);
+	dev = (struct net_device *)v;
+	if (v == SEQ_START_TOKEN)
+		dev = net_device_entry(&dev_base_head);
+
+	for_each_netdev_continue(dev) {
+		if (!is_vlan_dev(dev))
+			continue;
+
+		return dev;
+	}
+
+	return NULL;
 }
 
 static void vlan_seq_stop(struct seq_file *seq, void *v)
diff --git a/net/Kconfig b/net/Kconfig
index 9156578..caeacd1 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -27,13 +27,6 @@ if NET
 
 menu "Networking options"
 
-config NETDEBUG
-	bool "Network packet debugging"
-	help
-	  You can say Y here if you want to get additional messages useful in
-	  debugging bad packets, but can overwhelm logs under denial of service
-	  attacks.
-
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
@@ -219,14 +212,21 @@ endmenu
 source "net/ax25/Kconfig"
 source "net/irda/Kconfig"
 source "net/bluetooth/Kconfig"
-source "net/ieee80211/Kconfig"
-
-config WIRELESS_EXT
-	bool
+source "net/rxrpc/Kconfig"
 
 config FIB_RULES
 	bool
 
+menu "Wireless"
+
+source "net/wireless/Kconfig"
+source "net/mac80211/Kconfig"
+source "net/ieee80211/Kconfig"
+
+endmenu
+
+source "net/rfkill/Kconfig"
+
 endif   # if NET
 endmenu # Networking
 
diff --git a/net/Makefile b/net/Makefile
index 4854ac5..34e5b2d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -38,16 +38,20 @@ obj-$(CONFIG_IRDA)		+= irda/
 obj-$(CONFIG_BT)		+= bluetooth/
 obj-$(CONFIG_SUNRPC)		+= sunrpc/
 obj-$(CONFIG_RXRPC)		+= rxrpc/
+obj-$(CONFIG_AF_RXRPC)		+= rxrpc/
 obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
 obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
+obj-y				+= wireless/
+obj-$(CONFIG_MAC80211)		+= mac80211/
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
 obj-$(CONFIG_NETLABEL)		+= netlabel/
 obj-$(CONFIG_IUCV)		+= iucv/
+obj-$(CONFIG_RFKILL)		+= rfkill/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index d89d62f..5ef6a23 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -118,7 +118,9 @@ static void __aarp_send_query(struct aar
 
 	/* Set up the buffer */
 	skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb_put(skb, sizeof(*eah));
 	skb->protocol    = htons(ETH_P_ATALK);
 	skb->dev	 = dev;
 	eah		 = aarp_hdr(skb);
@@ -163,7 +165,9 @@ static void aarp_send_reply(struct net_d
 
 	/* Set up the buffer */
 	skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb_put(skb, sizeof(*eah));
 	skb->protocol    = htons(ETH_P_ATALK);
 	skb->dev	 = dev;
 	eah		 = aarp_hdr(skb);
@@ -212,7 +216,9 @@ static void aarp_send_probe(struct net_d
 
 	/* Set up the buffer */
 	skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb_put(skb, sizeof(*eah));
 	skb->protocol    = htons(ETH_P_ATALK);
 	skb->dev	 = dev;
 	eah		 = aarp_hdr(skb);
@@ -539,7 +545,7 @@ int aarp_send_ddp(struct net_device *dev
 	int hash;
 	struct aarp_entry *a;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	/* Check for LocalTalk first */
 	if (dev->type == ARPHRD_LOCALTLK) {
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index c8b7dc2..fbdfb12 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1275,7 +1275,7 @@ static int handle_ip_over_ddp(struct sk_
 	skb->protocol = htons(ETH_P_IP);
 	skb_pull(skb, 13);
 	skb->dev   = dev;
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	stats = dev->priv;
 	stats->rx_packets++;
@@ -1383,10 +1383,10 @@ free_it:
  *	@pt - packet type
  *
  *	Receive a packet (in skb) from device dev. This has come from the SNAP
- *	decoder, and on entry skb->h.raw is the DDP header, skb->len is the DDP
- *	header, skb->len is the DDP length. The physical headers have been
- *	extracted. PPP should probably pass frames marked as for this layer.
- *	[ie ARPHRD_ETHERTALK]
+ *	decoder, and on entry skb->transport_header is the DDP header, skb->len
+ *	is the DDP header, skb->len is the DDP length. The physical headers
+ *	have been extracted. PPP should probably pass frames marked as for this
+ *	layer.  [ie ARPHRD_ETHERTALK]
  */
 static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
 		     struct packet_type *pt, struct net_device *orig_dev)
@@ -1484,7 +1484,7 @@ static int ltalk_rcv(struct sk_buff *skb
 		     struct packet_type *pt, struct net_device *orig_dev)
 {
 	/* Expand any short form frames */
-	if (skb->mac.raw[2] == 1) {
+	if (skb_mac_header(skb)[2] == 1) {
 		struct ddpehdr *ddp;
 		/* Find our address */
 		struct atalk_addr *ap = atalk_find_dev_addr(dev);
@@ -1510,8 +1510,8 @@ static int ltalk_rcv(struct sk_buff *skb
 		 * we write the network numbers !
 		 */
 
-		ddp->deh_dnode = skb->mac.raw[0];     /* From physical header */
-		ddp->deh_snode = skb->mac.raw[1];     /* From physical header */
+		ddp->deh_dnode = skb_mac_header(skb)[0];     /* From physical header */
+		ddp->deh_snode = skb_mac_header(skb)[1];     /* From physical header */
 
 		ddp->deh_dnet  = ap->s_net;	/* Network number */
 		ddp->deh_snet  = ap->s_net;
@@ -1522,7 +1522,7 @@ static int ltalk_rcv(struct sk_buff *skb
 		/* 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;
+	skb_reset_transport_header(skb);
 
 	return atalk_rcv(skb, dev, pt, orig_dev);
 freeit:
@@ -1771,6 +1771,9 @@ static int atalk_ioctl(struct socket *so
 		case SIOCGSTAMP:
 			rc = sock_get_timestamp(sk, argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = sock_get_timestampns(sk, argp);
+			break;
 		/* Routing */
 		case SIOCADDRT:
 		case SIOCDELRT:
@@ -1841,7 +1844,6 @@ #endif
 	.sendpage	= sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
 SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK);
 
 static struct notifier_block ddp_notifier = {
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index ec4ebd3..0e9f00c 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -173,7 +173,7 @@ #else
 	}
 	skb_push(skb, minheadroom);
 	if (brvcc->encaps == e_llc)
-		memcpy(skb->data, llc_oui_pid_pad, 10);
+		skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10);
 	else
 		memset(skb->data, 0, 2);
 #endif /* FASTER_VERSION */
@@ -375,11 +375,11 @@ packet_fails_filter(__be16 type, struct 
 {
 	if (brvcc->filter.netmask == 0)
 		return 0;			/* no filter in place */
-	if (type == __constant_htons(ETH_P_IP) &&
+	if (type == htons(ETH_P_IP) &&
 	    (((struct iphdr *) (skb->data))->daddr & brvcc->filter.
 	     netmask) == brvcc->filter.prefix)
 		return 0;
-	if (type == __constant_htons(ETH_P_ARP))
+	if (type == htons(ETH_P_ARP))
 		return 0;
 	/* TODO: we should probably filter ARPs too.. don't want to have
 	 *   them returning values that don't make sense, or is that ok?
@@ -458,7 +458,7 @@ #ifdef FASTER_VERSION
 	/* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier,
 	   than should be. What else should I set? */
 	skb_pull(skb, plen);
-	skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN;
+	skb_set_mac_header(skb, -ETH_HLEN);
 	skb->pkt_type = PACKET_HOST;
 #ifdef CONFIG_BR2684_FAST_TRANS
 	skb->protocol = ((u16 *) skb->data)[-1];
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 8c38258..876b77f 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -213,7 +213,7 @@ static void clip_push(struct atm_vcc *vc
 		return;
 	}
 	ATM_SKB(skb)->vcc = vcc;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	if (!clip_vcc->encap
 	    || skb->len < RFC1483LLC_LEN
 	    || memcmp(skb->data, llc_oui, sizeof (llc_oui)))
@@ -702,7 +702,7 @@ static struct atm_dev atmarpd_dev = {
 	.ops =			&atmarpd_dev_ops,
 	.type =			"arpd",
 	.number = 		999,
-	.lock =			SPIN_LOCK_UNLOCKED
+	.lock =			__SPIN_LOCK_UNLOCKED(atmarpd_dev.lock)
 };
 
 
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 8ccee45..7afd8e7 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -82,6 +82,9 @@ int vcc_ioctl(struct socket *sock, unsig
 		case SIOCGSTAMP: /* borrowed from IP */
 			error = sock_get_timestamp(sk, argp);
 			goto done;
+		case SIOCGSTAMPNS: /* borrowed from IP */
+			error = sock_get_timestampns(sk, argp);
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
 			error = 0;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 3d804d6..4dc5f2b 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -283,8 +283,8 @@ #endif /* DUMP_PACKETS >0 */
 	}
 
 	DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
-		(long)skb->head, (long)skb->data, (long)skb->tail,
-		(long)skb->end);
+		(long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
+		(long)skb_end_pointer(skb));
 #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);
@@ -576,8 +576,8 @@ #if defined(CONFIG_BRIDGE) || defined(CO
 					break;
 				}
 				skb2->len = sizeof(struct atmlec_msg);
-				memcpy(skb2->data, mesg,
-				       sizeof(struct atmlec_msg));
+				skb_copy_to_linear_data(skb2, mesg,
+							sizeof(*mesg));
 				atm_force_charge(priv->lecd, skb2->truesize);
 				sk = sk_atm(priv->lecd);
 				skb_queue_tail(&sk->sk_receive_queue, skb2);
@@ -630,7 +630,7 @@ static struct atm_dev lecatm_dev = {
 	.ops = &lecdev_ops,
 	.type = "lec",
 	.number = 999,		/* dummy device number */
-	.lock = SPIN_LOCK_UNLOCKED
+	.lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)
 };
 
 /*
@@ -825,7 +825,6 @@ #endif
 		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)
@@ -1338,7 +1337,7 @@ static int lane2_resolve(struct net_devi
 		if (skb == NULL)
 			return -1;
 		skb->len = *sizeoftlvs;
-		memcpy(skb->data, *tlvs, *sizeoftlvs);
+		skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs);
 		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
 	}
 	return retval;
@@ -1372,7 +1371,7 @@ static int lane2_associate_req(struct ne
 	if (skb == NULL)
 		return 0;
 	skb->len = sizeoftlvs;
-	memcpy(skb->data, tlvs, sizeoftlvs);
+	skb_copy_to_linear_data(skb, tlvs, sizeoftlvs);
 	retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
 	if (retval != 0)
 		printk("lec.c: lane2_associate_req() failed\n");
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index cb3c004..7c85aa5 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -504,11 +504,13 @@ static int send_via_shortcut(struct sk_b
 		tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
 		skb_pull(skb, ETH_HLEN);                       /* get rid of Eth header */
 		skb_push(skb, sizeof(tagged_llc_snap_hdr));    /* add LLC/SNAP header   */
-		memcpy(skb->data, &tagged_llc_snap_hdr, sizeof(tagged_llc_snap_hdr));
+		skb_copy_to_linear_data(skb, &tagged_llc_snap_hdr,
+					sizeof(tagged_llc_snap_hdr));
 	} else {
 		skb_pull(skb, ETH_HLEN);                        /* get rid of Eth header */
 		skb_push(skb, sizeof(struct llc_snap_hdr));     /* add LLC/SNAP header + tag  */
-		memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr));
+		skb_copy_to_linear_data(skb, &llc_snap_mpoa_data,
+					sizeof(struct llc_snap_hdr));
 	}
 
 	atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
@@ -711,11 +713,12 @@ static void mpc_push(struct atm_vcc *vcc
 		return;
 	}
 	skb_push(new_skb, eg->ctrl_info.DH_length);     /* add MAC header */
-	memcpy(new_skb->data, eg->ctrl_info.DLL_header, eg->ctrl_info.DH_length);
+	skb_copy_to_linear_data(new_skb, eg->ctrl_info.DLL_header,
+				eg->ctrl_info.DH_length);
 	new_skb->protocol = eth_type_trans(new_skb, dev);
-	new_skb->nh.raw = new_skb->data;
+	skb_reset_network_header(new_skb);
 
-	eg->latest_ip_addr = new_skb->nh.iph->saddr;
+	eg->latest_ip_addr = ip_hdr(new_skb)->saddr;
 	eg->packets_rcvd++;
 	mpc->eg_ops->put(eg);
 
@@ -734,7 +737,7 @@ static struct atm_dev mpc_dev = {
 	.ops	= &mpc_ops,
 	.type	= "mpc",
 	.number	= 42,
-	.lock	= SPIN_LOCK_UNLOCKED
+	.lock	= __SPIN_LOCK_UNLOCKED(mpc_dev.lock)
 	/* members not explicitly initialised will be 0 */
 };
 
@@ -936,7 +939,7 @@ int msg_to_mpoad(struct k_message *mesg,
 	if (skb == NULL)
 		return -ENOMEM;
 	skb_put(skb, sizeof(struct k_message));
-	memcpy(skb->data, mesg, sizeof(struct k_message));
+	skb_copy_to_linear_data(skb, mesg, sizeof(*mesg));
 	atm_force_charge(mpc->mpoad_vcc, skb->truesize);
 
 	sk = sk_atm(mpc->mpoad_vcc);
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index 31d98b5..d14baaf 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -256,7 +256,7 @@ static struct atm_dev sigd_dev = {
 	.ops =		&sigd_dev_ops,
 	.type =		"sig",
 	.number =	999,
-	.lock =		SPIN_LOCK_UNLOCKED
+	.lock =		__SPIN_LOCK_UNLOCKED(sigd_dev.lock)
 };
 
 
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 1c07c6a..429e13a 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -23,7 +23,6 @@ #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
 #include <net/ax25.h>
@@ -1127,22 +1126,22 @@ static int __must_check ax25_connect(str
 		switch (sk->sk_state) {
 		case TCP_SYN_SENT: /* still trying */
 			err = -EINPROGRESS;
-			goto out;
+			goto out_release;
 
 		case TCP_ESTABLISHED: /* connection established */
 			sock->state = SS_CONNECTED;
-			goto out;
+			goto out_release;
 
 		case TCP_CLOSE: /* connection refused */
 			sock->state = SS_UNCONNECTED;
 			err = -ECONNREFUSED;
-			goto out;
+			goto out_release;
 		}
 	}
 
 	if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) {
 		err = -EISCONN;	/* No reconnect on a seqpacket socket */
-		goto out;
+		goto out_release;
 	}
 
 	sk->sk_state   = TCP_CLOSE;
@@ -1159,12 +1158,12 @@ static int __must_check ax25_connect(str
 		/* Valid number of digipeaters ? */
 		if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
 			err = -EINVAL;
-			goto out;
+			goto out_release;
 		}
 
 		if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
 			err = -ENOBUFS;
-			goto out;
+			goto out_release;
 		}
 
 		digi->ndigi      = fsa->fsa_ax25.sax25_ndigis;
@@ -1194,7 +1193,7 @@ static int __must_check ax25_connect(str
 			current->comm);
 		if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) {
 			kfree(digi);
-			goto out;
+			goto out_release;
 		}
 
 		ax25_fillin_cb(ax25, ax25->ax25_dev);
@@ -1203,7 +1202,7 @@ static int __must_check ax25_connect(str
 		if (ax25->ax25_dev == NULL) {
 			kfree(digi);
 			err = -EHOSTUNREACH;
-			goto out;
+			goto out_release;
 		}
 	}
 
@@ -1213,7 +1212,7 @@ static int __must_check ax25_connect(str
 		kfree(digi);
 		err = -EADDRINUSE;		/* Already such a connection */
 		ax25_cb_put(ax25t);
-		goto out;
+		goto out_release;
 	}
 
 	ax25->dest_addr = fsa->fsa_ax25.sax25_call;
@@ -1223,7 +1222,7 @@ static int __must_check ax25_connect(str
 	if (sk->sk_type != SOCK_SEQPACKET) {
 		sock->state = SS_CONNECTED;
 		sk->sk_state   = TCP_ESTABLISHED;
-		goto out;
+		goto out_release;
 	}
 
 	/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
@@ -1255,55 +1254,53 @@ #endif
 	/* Now the loop */
 	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
 		err = -EINPROGRESS;
-		goto out;
+		goto out_release;
 	}
 
 	if (sk->sk_state == TCP_SYN_SENT) {
-		struct task_struct *tsk = current;
-		DECLARE_WAITQUEUE(wait, tsk);
+		DEFINE_WAIT(wait);
 
-		add_wait_queue(sk->sk_sleep, &wait);
 		for (;;) {
+			prepare_to_wait(sk->sk_sleep, &wait,
+			                TASK_INTERRUPTIBLE);
 			if (sk->sk_state != TCP_SYN_SENT)
 				break;
-			set_current_state(TASK_INTERRUPTIBLE);
-			release_sock(sk);
-			if (!signal_pending(tsk)) {
+			if (!signal_pending(current)) {
+				release_sock(sk);
 				schedule();
 				lock_sock(sk);
 				continue;
 			}
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -ERESTARTSYS;
+			err = -ERESTARTSYS;
+			break;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
+
+		if (err)
+			goto out_release;
 	}
 
 	if (sk->sk_state != TCP_ESTABLISHED) {
 		/* Not in ABM, not in WAIT_UA -> failed */
 		sock->state = SS_UNCONNECTED;
 		err = sock_error(sk);	/* Always set at this point */
-		goto out;
+		goto out_release;
 	}
 
 	sock->state = SS_CONNECTED;
 
-	err=0;
-out:
+	err = 0;
+out_release:
 	release_sock(sk);
 
 	return err;
 }
 
-
 static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
 	struct sock *newsk;
+	DEFINE_WAIT(wait);
 	struct sock *sk;
 	int err = 0;
 
@@ -1328,30 +1325,29 @@ static int ax25_accept(struct socket *so
 	 *	The read queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	add_wait_queue(sk->sk_sleep, &wait);
 	for (;;) {
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 		skb = skb_dequeue(&sk->sk_receive_queue);
 		if (skb)
 			break;
 
-		release_sock(sk);
-		current->state = TASK_INTERRUPTIBLE;
 		if (flags & O_NONBLOCK) {
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -EWOULDBLOCK;
+			err = -EWOULDBLOCK;
+			break;
 		}
-		if (!signal_pending(tsk)) {
+		if (!signal_pending(current)) {
+			release_sock(sk);
 			schedule();
 			lock_sock(sk);
 			continue;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
-		return -ERESTARTSYS;
+		err = -ERESTARTSYS;
+		break;
 	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sk_sleep, &wait);
+	finish_wait(sk->sk_sleep, &wait);
+
+	if (err)
+		goto out;
 
 	newsk		 = skb->sk;
 	newsk->sk_socket = newsock;
@@ -1425,7 +1421,6 @@ static int ax25_sendmsg(struct kiocb *io
 	struct sockaddr_ax25 sax;
 	struct sk_buff *skb;
 	ax25_digi dtmp, *dp;
-	unsigned char *asmptr;
 	ax25_cb *ax25;
 	size_t size;
 	int lv, err, addr_len = msg->msg_namelen;
@@ -1548,13 +1543,11 @@ static int ax25_sendmsg(struct kiocb *io
 		goto out;
 	}
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	/* Add the PID if one is not supplied by the user in the skb */
-	if (!ax25->pidincl) {
-		asmptr  = skb_push(skb, 1);
-		*asmptr = sk->sk_protocol;
-	}
+	if (!ax25->pidincl)
+		*skb_push(skb, 1) = sk->sk_protocol;
 
 	SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n");
 
@@ -1573,7 +1566,7 @@ static int ax25_sendmsg(struct kiocb *io
 		goto out;
 	}
 
-	asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
+	skb_push(skb, 1 + ax25_addr_size(dp));
 
 	SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
 
@@ -1581,17 +1574,17 @@ static int ax25_sendmsg(struct kiocb *io
 		SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
 
 	/* Build an AX.25 header */
-	asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
-					&sax.sax25_call, dp,
-					AX25_COMMAND, AX25_MODULUS));
+	lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call,
+			     dp, AX25_COMMAND, AX25_MODULUS);
 
 	SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
 
-	skb->h.raw = asmptr;
+	skb_set_transport_header(skb, lv);
 
-	SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);
+	SOCK_DEBUG(sk, "base=%p pos=%p\n",
+		   skb->data, skb_transport_header(skb));
 
-	*asmptr = AX25_UI;
+	*skb_transport_header(skb) = AX25_UI;
 
 	/* Datagram frames go straight out of the door as UI */
 	ax25_queue_xmit(skb, ax25->ax25_dev->dev);
@@ -1631,8 +1624,8 @@ static int ax25_recvmsg(struct kiocb *io
 	if (!ax25_sk(sk)->pidincl)
 		skb_pull(skb, 1);		/* Remove PID */
 
-	skb->h.raw = skb->data;
-	copied     = skb->len;
+	skb_reset_transport_header(skb);
+	copied = skb->len;
 
 	if (copied > size) {
 		copied = size;
@@ -1645,9 +1638,10 @@ static int ax25_recvmsg(struct kiocb *io
 		struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
 		ax25_digi digi;
 		ax25_address src;
+		const unsigned char *mac = skb_mac_header(skb);
 
-		ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, &src, NULL, &digi, NULL, NULL);
-
+		ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
+				&digi, NULL, NULL);
 		sax->sax25_family = AF_AX25;
 		/* We set this correctly, even though we may not let the
 		   application know the digi calls further down (because it
@@ -1711,6 +1705,10 @@ static int ax25_ioctl(struct socket *soc
 		res = sock_get_timestamp(sk, argp);
 		break;
 
+	case SIOCGSTAMPNS:
+		res = sock_get_timestampns(sk, argp);
+		break;
+
 	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
 	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
 	case SIOCAX25GETUID: {
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
index 9569dd3..a49773f 100644
--- a/net/ax25/ax25_ds_subr.c
+++ b/net/ax25/ax25_ds_subr.c
@@ -136,7 +136,7 @@ static void ax25_kiss_cmd(ax25_dev *ax25
 	if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
 		return;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 	p = skb_put(skb, 2);
 
 	*p++ = cmd;
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 4a6b26b..0ddaff0 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -61,12 +61,14 @@ static int ax25_rx_fragment(ax25_cb *ax2
 					skb_reserve(skbn, AX25_MAX_HEADER_LEN);
 
 					skbn->dev   = ax25->ax25_dev->dev;
-					skbn->h.raw = skbn->data;
-					skbn->nh.raw = skbn->data;
+					skb_reset_network_header(skbn);
+					skb_reset_transport_header(skbn);
 
 					/* Copy data from the fragments */
 					while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
-						memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+						skb_copy_from_linear_data(skbo,
+							  skb_put(skbn, skbo->len),
+									  skbo->len);
 						kfree_skb(skbo);
 					}
 
@@ -122,8 +124,8 @@ int ax25_rx_iframe(ax25_cb *ax25, struct
 		}
 
 		skb_pull(skb, 1);	/* Remove PID */
-		skb->mac.raw  = skb->nh.raw;
-		skb->nh.raw   = skb->data;
+		skb_reset_mac_header(skb);
+		skb_reset_network_header(skb);
 		skb->dev      = ax25->ax25_dev->dev;
 		skb->pkt_type = PACKET_HOST;
 		skb->protocol = htons(ETH_P_IP);
@@ -196,7 +198,7 @@ static int ax25_rcv(struct sk_buff *skb,
 	 *	Process the AX.25/LAPB frame.
 	 */
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
 		kfree_skb(skb);
@@ -233,7 +235,7 @@ static int ax25_rcv(struct sk_buff *skb,
 
 	/* UI frame - bypass LAPB processing */
 	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
-		skb->h.raw = skb->data + 2;		/* skip control and pid */
+		skb_set_transport_header(skb, 2); /* skip control and pid */
 
 		ax25_send_to_raw(&dest, skb, skb->data[1]);
 
@@ -246,8 +248,8 @@ static int ax25_rcv(struct sk_buff *skb,
 		switch (skb->data[1]) {
 		case AX25_P_IP:
 			skb_pull(skb,2);		/* drop PID/CTRL */
-			skb->h.raw    = skb->data;
-			skb->nh.raw   = skb->data;
+			skb_reset_transport_header(skb);
+			skb_reset_network_header(skb);
 			skb->dev      = dev;
 			skb->pkt_type = PACKET_HOST;
 			skb->protocol = htons(ETH_P_IP);
@@ -256,8 +258,8 @@ static int ax25_rcv(struct sk_buff *skb,
 
 		case AX25_P_ARP:
 			skb_pull(skb,2);
-			skb->h.raw    = skb->data;
-			skb->nh.raw   = skb->data;
+			skb_reset_transport_header(skb);
+			skb_reset_network_header(skb);
 			skb->dev      = dev;
 			skb->pkt_type = PACKET_HOST;
 			skb->protocol = htons(ETH_P_ARP);
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 7f818bb..930e491 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -121,7 +121,7 @@ int ax25_rebuild_header(struct sk_buff *
 		digipeat = route->digipeat;
 		dev = route->dev;
 		ip_mode = route->ip_mode;
-	};
+	}
 
 	if (dev == NULL)
 		dev = skb->dev;
@@ -171,7 +171,7 @@ int ax25_rebuild_header(struct sk_buff *
 			src_c = *(ax25_address *)(bp + 8);
 
 			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
-			ourskb->nh.raw = ourskb->data;
+			skb_reset_network_header(ourskb);
 
 			ax25=ax25_send_frame(
 			    ourskb,
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index 2238350..92b517a 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -148,8 +148,9 @@ void ax25_output(ax25_cb *ax25, int pacl
 
 			if (ka9qfrag == 1) {
 				skb_reserve(skbn, frontlen + 2);
-				skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
-				memcpy(skb_put(skbn, len), skb->data, len);
+				skb_set_network_header(skbn,
+						      skb_network_offset(skb));
+				skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
 				p = skb_push(skbn, 2);
 
 				*p++ = AX25_P_SEGMENT;
@@ -161,8 +162,9 @@ void ax25_output(ax25_cb *ax25, int pacl
 				}
 			} else {
 				skb_reserve(skbn, frontlen + 1);
-				skbn->nh.raw = skbn->data + (skb->nh.raw - skb->data);
-				memcpy(skb_put(skbn, len), skb->data, len);
+				skb_set_network_header(skbn,
+						      skb_network_offset(skb));
+				skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
 				p = skb_push(skbn, 1);
 				*p = AX25_P_TEXT;
 			}
@@ -205,7 +207,7 @@ static void ax25_send_iframe(ax25_cb *ax
 	if (skb == NULL)
 		return;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	if (ax25->modulus == AX25_MODULUS) {
 		frame = skb_push(skb, 1);
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
index b6c577e..5fe9b2a 100644
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -162,7 +162,7 @@ void ax25_send_control(ax25_cb *ax25, in
 
 	skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len);
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	/* Assume a response - address structure for DTE */
 	if (ax25->modulus == AX25_MODULUS) {
@@ -205,7 +205,7 @@ void ax25_return_dm(struct net_device *d
 		return;	/* Next SABM will get DM'd */
 
 	skb_reserve(skb, dev->hard_header_len);
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	ax25_digi_invert(digi, &retdigi);
 
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index c7228cf..d942b94 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -221,7 +221,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, 
 		copied = len;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
 	skb_free_datagram(sk, skb);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index b85d149..1c8f4a0 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -37,7 +37,6 @@ #include <linux/signal.h>
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
 #include <linux/net.h>
 #include <net/sock.h>
 
@@ -326,7 +325,7 @@ static inline int bnep_rx_frame(struct b
 		return 0;
 	}
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 
 	/* Verify and pull out header */
 	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
@@ -364,26 +363,28 @@ static inline int bnep_rx_frame(struct b
 
 	case BNEP_COMPRESSED_SRC_ONLY:
 		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
-		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
+		memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
 		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 		break;
 
 	case BNEP_COMPRESSED_DST_ONLY:
-		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
+		memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
+		       ETH_ALEN);
+		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
+		       ETH_ALEN + 2);
 		break;
 
 	case BNEP_GENERAL:
-		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
+		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
+		       ETH_ALEN * 2);
 		put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
 		break;
 	}
 
-	memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
+	skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
 	kfree_skb(skb);
 
 	s->stats.rx_packets++;
-	nskb->dev       = dev;
 	nskb->ip_summed = CHECKSUM_NONE;
 	nskb->protocol  = eth_type_trans(nskb, dev);
 	netif_rx_ni(nskb);
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 3933608..66bef1c 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -124,7 +124,7 @@ static inline void cmtp_add_msgpart(stru
 	}
 
 	if (skb && (skb->len > 0))
-		memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
 
 	memcpy(skb_put(nskb, count), buf, count);
 
@@ -256,7 +256,7 @@ static void cmtp_process_transmit(struct
 			hdr[2] = size >> 8;
 		}
 
-		memcpy(skb_put(nskb, size), skb->data, size);
+		skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
 		skb_pull(skb, size);
 
 		if (skb->len > 0) {
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index f3403fd..63980bd 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -72,11 +72,11 @@ void hci_acl_connect(struct hci_conn *co
 			inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
 		cp.pscan_rep_mode = ie->data.pscan_rep_mode;
 		cp.pscan_mode     = ie->data.pscan_mode;
-		cp.clock_offset   = ie->data.clock_offset | __cpu_to_le16(0x8000);
+		cp.clock_offset   = ie->data.clock_offset | cpu_to_le16(0x8000);
 		memcpy(conn->dev_class, ie->data.dev_class, 3);
 	}
 
-	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
+	cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
 	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
 		cp.role_switch	= 0x01;
 	else
@@ -107,7 +107,7 @@ void hci_acl_disconn(struct hci_conn *co
 
 	conn->state = BT_DISCONN;
 
-	cp.handle = __cpu_to_le16(conn->handle);
+	cp.handle = cpu_to_le16(conn->handle);
 	cp.reason = reason;
 	hci_send_cmd(conn->hdev, OGF_LINK_CTL,
 				OCF_DISCONNECT, sizeof(cp), &cp);
@@ -123,8 +123,8 @@ void hci_add_sco(struct hci_conn *conn, 
 	conn->state = BT_CONNECT;
 	conn->out = 1;
 
-	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-	cp.handle   = __cpu_to_le16(handle);
+	cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+	cp.handle   = cpu_to_le16(handle);
 
 	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
 }
@@ -348,7 +348,7 @@ int hci_conn_auth(struct hci_conn *conn)
 
 	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_auth_requested cp;
-		cp.handle = __cpu_to_le16(conn->handle);
+		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
 	}
 	return 0;
@@ -368,7 +368,7 @@ int hci_conn_encrypt(struct hci_conn *co
 
 	if (hci_conn_auth(conn)) {
 		struct hci_cp_set_conn_encrypt cp;
-		cp.handle  = __cpu_to_le16(conn->handle);
+		cp.handle  = cpu_to_le16(conn->handle);
 		cp.encrypt = 1;
 		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
 	}
@@ -383,7 +383,7 @@ int hci_conn_change_link_key(struct hci_
 
 	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
 		struct hci_cp_change_conn_link_key cp;
-		cp.handle = __cpu_to_le16(conn->handle);
+		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
 	}
 	return 0;
@@ -423,7 +423,7 @@ void hci_conn_enter_active_mode(struct h
 
 	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
 		struct hci_cp_exit_sniff_mode cp;
-		cp.handle = __cpu_to_le16(conn->handle);
+		cp.handle = cpu_to_le16(conn->handle);
 		hci_send_cmd(hdev, OGF_LINK_POLICY,
 				OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
 	}
@@ -452,21 +452,21 @@ void hci_conn_enter_sniff_mode(struct hc
 
 	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
 		struct hci_cp_sniff_subrate cp;
-		cp.handle             = __cpu_to_le16(conn->handle);
-		cp.max_latency        = __constant_cpu_to_le16(0);
-		cp.min_remote_timeout = __constant_cpu_to_le16(0);
-		cp.min_local_timeout  = __constant_cpu_to_le16(0);
+		cp.handle             = cpu_to_le16(conn->handle);
+		cp.max_latency        = cpu_to_le16(0);
+		cp.min_remote_timeout = cpu_to_le16(0);
+		cp.min_local_timeout  = cpu_to_le16(0);
 		hci_send_cmd(hdev, OGF_LINK_POLICY,
 				OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
 	}
 
 	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
 		struct hci_cp_sniff_mode cp;
-		cp.handle       = __cpu_to_le16(conn->handle);
-		cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval);
-		cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval);
-		cp.attempt      = __constant_cpu_to_le16(4);
-		cp.timeout      = __constant_cpu_to_le16(1);
+		cp.handle       = cpu_to_le16(conn->handle);
+		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
+		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
+		cp.attempt      = cpu_to_le16(4);
+		cp.timeout      = cpu_to_le16(1);
 		hci_send_cmd(hdev, OGF_LINK_POLICY,
 				OCF_SNIFF_MODE, sizeof(cp), &cp);
 	}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4917919..aa4b56a 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -149,7 +149,7 @@ static int __hci_request(struct hci_dev 
 	default:
 		err = -ETIMEDOUT;
 		break;
-	};
+	}
 
 	hdev->req_status = hdev->req_result = 0;
 
@@ -216,10 +216,10 @@ #if 0
 	/* Host buffer size */
 	{
 		struct hci_cp_host_buffer_size cp;
-		cp.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
+		cp.acl_mtu = cpu_to_le16(HCI_MAX_ACL_SIZE);
 		cp.sco_mtu = HCI_MAX_SCO_SIZE;
-		cp.acl_max_pkt = __cpu_to_le16(0xffff);
-		cp.sco_max_pkt = __cpu_to_le16(0xffff);
+		cp.acl_max_pkt = cpu_to_le16(0xffff);
+		cp.sco_max_pkt = cpu_to_le16(0xffff);
 		hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp);
 	}
 #endif
@@ -240,11 +240,11 @@ #endif
 	}
 
 	/* Page timeout ~20 secs */
-	param = __cpu_to_le16(0x8000);
+	param = cpu_to_le16(0x8000);
 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
 
 	/* Connection accept timeout ~20 secs */
-	param = __cpu_to_le16(0x7d00);
+	param = cpu_to_le16(0x7d00);
 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
 }
 
@@ -1034,7 +1034,7 @@ int hci_send_cmd(struct hci_dev *hdev, _
 	}
 
 	hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
-	hdr->opcode = __cpu_to_le16(hci_opcode_pack(ogf, ocf));
+	hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf));
 	hdr->plen   = plen;
 
 	if (plen)
@@ -1060,7 +1060,7 @@ void *hci_sent_cmd_data(struct hci_dev *
 
 	hdr = (void *) hdev->sent_cmd->data;
 
-	if (hdr->opcode != __cpu_to_le16(hci_opcode_pack(ogf, ocf)))
+	if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf)))
 		return NULL;
 
 	BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
@@ -1074,11 +1074,11 @@ static void hci_add_acl_hdr(struct sk_bu
 	struct hci_acl_hdr *hdr;
 	int len = skb->len;
 
-	hdr = (struct hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
-	hdr->handle = __cpu_to_le16(hci_handle_pack(handle, flags));
-	hdr->dlen   = __cpu_to_le16(len);
-
-	skb->h.raw = (void *) hdr;
+	skb_push(skb, HCI_ACL_HDR_SIZE);
+	skb_reset_transport_header(skb);
+	hdr = (struct hci_acl_hdr *)skb_transport_header(skb);
+	hdr->handle = cpu_to_le16(hci_handle_pack(handle, flags));
+	hdr->dlen   = cpu_to_le16(len);
 }
 
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
@@ -1140,11 +1140,12 @@ int hci_send_sco(struct hci_conn *conn, 
 		return -EINVAL;
 	}
 
-	hdr.handle = __cpu_to_le16(conn->handle);
+	hdr.handle = cpu_to_le16(conn->handle);
 	hdr.dlen   = skb->len;
 
-	skb->h.raw = skb_push(skb, HCI_SCO_HDR_SIZE);
-	memcpy(skb->h.raw, &hdr, HCI_SCO_HDR_SIZE);
+	skb_push(skb, HCI_SCO_HDR_SIZE);
+	skb_reset_transport_header(skb);
+	memcpy(skb_transport_header(skb), &hdr, HCI_SCO_HDR_SIZE);
 
 	skb->dev = (void *) hdev;
 	bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
@@ -1387,7 +1388,7 @@ static void hci_rx_task(unsigned long ar
 			case HCI_SCODATA_PKT:
 				kfree_skb(skb);
 				continue;
-			};
+			}
 		}
 
 		/* Process frame */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 936d3fc..447ba71 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -783,7 +783,7 @@ static inline void hci_conn_complete_evt
 		if (conn->type == ACL_LINK && hdev->link_policy) {
 			struct hci_cp_write_link_policy cp;
 			cp.handle = ev->handle;
-			cp.policy = __cpu_to_le16(hdev->link_policy);
+			cp.policy = cpu_to_le16(hdev->link_policy);
 			hci_send_cmd(hdev, OGF_LINK_POLICY,
 				OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
 		}
@@ -793,8 +793,8 @@ static inline void hci_conn_complete_evt
 			struct hci_cp_change_conn_ptype cp;
 			cp.handle = ev->handle;
 			cp.pkt_type = (conn->type == ACL_LINK) ?
-				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
-				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
+				cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
+				cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
 			hci_send_cmd(hdev, OGF_LINK_CTL,
 				OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
@@ -970,7 +970,7 @@ static inline void hci_auth_complete_evt
 		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
 			if (!ev->status) {
 				struct hci_cp_set_conn_encrypt cp;
-				cp.handle  = __cpu_to_le16(conn->handle);
+				cp.handle  = cpu_to_le16(conn->handle);
 				cp.encrypt = 1;
 				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
 					OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 71f5cfb..bfc9a35 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -375,7 +375,7 @@ static int hci_sock_recvmsg(struct kiocb
 		copied = len;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
 	hci_sock_cmsg(sk, msg, skb);
@@ -499,6 +499,15 @@ static int hci_sock_setsockopt(struct so
 		break;
 
 	case HCI_FILTER:
+		{
+			struct hci_filter *f = &hci_pi(sk)->filter;
+
+			uf.type_mask = f->type_mask;
+			uf.opcode    = f->opcode;
+			uf.event_mask[0] = *((u32 *) f->event_mask + 0);
+			uf.event_mask[1] = *((u32 *) f->event_mask + 1);
+		}
+
 		len = min_t(unsigned int, len, sizeof(uf));
 		if (copy_from_user(&uf, optval, len)) {
 			err = -EFAULT;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 801d687..2583540 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -305,7 +305,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;
+	dev->bus = &bt_bus;
 	dev->parent = hdev->parent;
 
 	strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
@@ -322,6 +322,10 @@ int hci_register_sysfs(struct hci_dev *h
 		if (device_create_file(dev, bt_attrs[i]) < 0)
 			BT_ERR("Failed to create device attribute");
 
+	if (sysfs_create_link(&bt_class->subsys.kobj,
+				&dev->kobj, kobject_name(&dev->kobj)) < 0)
+		BT_ERR("Failed to create class symlink");
+
 	return 0;
 }
 
@@ -329,6 +333,9 @@ void hci_unregister_sysfs(struct hci_dev
 {
 	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
 
+	sysfs_remove_link(&bt_class->subsys.kobj,
+					kobject_name(&hdev->dev.kobj));
+
 	device_del(&hdev->dev);
 }
 
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index e83ee82..a59b1fb 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -459,8 +459,8 @@ static void __l2cap_sock_close(struct so
 			sk->sk_state = BT_DISCONN;
 			l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
-			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			l2cap_send_cmd(conn, l2cap_get_ident(conn),
 					L2CAP_DISCONN_REQ, sizeof(req), &req);
 		} else {
@@ -652,7 +652,7 @@ static int l2cap_do_connect(struct sock 
 		if (sk->sk_type == SOCK_SEQPACKET) {
 			struct l2cap_conn_req req;
 			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			req.psm  = l2cap_pi(sk)->psm;
 			l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 					L2CAP_CONN_REQ, sizeof(req), &req);
@@ -868,8 +868,8 @@ static inline int l2cap_do_send(struct s
 
 	/* Create L2CAP header */
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+	lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid);
+	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
 
 	if (sk->sk_type == SOCK_DGRAM)
 		put_unaligned(l2cap_pi(sk)->psm, (u16 *) skb_put(skb, 2));
@@ -954,11 +954,17 @@ static int l2cap_sock_setsockopt(struct 
 
 	switch (optname) {
 	case L2CAP_OPTIONS:
+		opts.imtu     = l2cap_pi(sk)->imtu;
+		opts.omtu     = l2cap_pi(sk)->omtu;
+		opts.flush_to = l2cap_pi(sk)->flush_to;
+		opts.mode     = 0x00;
+
 		len = min_t(unsigned int, sizeof(opts), optlen);
 		if (copy_from_user((char *) &opts, optval, len)) {
 			err = -EFAULT;
 			break;
 		}
+
 		l2cap_pi(sk)->imtu  = opts.imtu;
 		l2cap_pi(sk)->omtu  = opts.omtu;
 		break;
@@ -1096,7 +1102,7 @@ static void l2cap_conn_ready(struct l2ca
 		} else if (sk->sk_state == BT_CONNECT) {
 			struct l2cap_conn_req req;
 			l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			req.psm  = l2cap_pi(sk)->psm;
 			l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
 		}
@@ -1192,13 +1198,13 @@ static struct sk_buff *l2cap_build_cmd(s
 		return NULL;
 
 	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-	lh->cid = __cpu_to_le16(0x0001);
+	lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
+	lh->cid = cpu_to_le16(0x0001);
 
 	cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
 	cmd->code  = code;
 	cmd->ident = ident;
-	cmd->len   = __cpu_to_le16(dlen);
+	cmd->len   = cpu_to_le16(dlen);
 
 	if (dlen) {
 		count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
@@ -1316,11 +1322,11 @@ static void l2cap_add_conf_opt(void **pt
 		break;
 
 	case 2:
-		*((u16 *) opt->val) = __cpu_to_le16(val);
+		*((u16 *) opt->val) = cpu_to_le16(val);
 		break;
 
 	case 4:
-		*((u32 *) opt->val) = __cpu_to_le32(val);
+		*((u32 *) opt->val) = cpu_to_le32(val);
 		break;
 
 	default:
@@ -1346,8 +1352,8 @@ static int l2cap_build_conf_req(struct s
 	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
 	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
 
-	req->dcid  = __cpu_to_le16(pi->dcid);
-	req->flags = __cpu_to_le16(0);
+	req->dcid  = cpu_to_le16(pi->dcid);
+	req->flags = cpu_to_le16(0);
 
 	return ptr - data;
 }
@@ -1383,9 +1389,9 @@ static int l2cap_build_conf_rsp(struct s
 	else
 		flags = 0x0001;
 
-	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-	rsp->result = __cpu_to_le16(result ? *result : 0);
-	rsp->flags  = __cpu_to_le16(flags);
+	rsp->scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp->result = cpu_to_le16(result ? *result : 0);
+	rsp->flags  = cpu_to_le16(flags);
 
 	return ptr - data;
 }
@@ -1470,10 +1476,10 @@ response:
 	bh_unlock_sock(parent);
 
 sendresp:
-	rsp.scid   = __cpu_to_le16(scid);
-	rsp.dcid   = __cpu_to_le16(dcid);
-	rsp.result = __cpu_to_le16(result);
-	rsp.status = __cpu_to_le16(status);
+	rsp.scid   = cpu_to_le16(scid);
+	rsp.dcid   = cpu_to_le16(dcid);
+	rsp.result = cpu_to_le16(result);
+	rsp.status = cpu_to_le16(status);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 	return 0;
 }
@@ -1613,8 +1619,8 @@ static inline int l2cap_config_rsp(struc
 		l2cap_sock_set_timer(sk, HZ * 5);
 		{
 			struct l2cap_disconn_req req;
-			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid);
+			req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
 			l2cap_send_cmd(conn, l2cap_get_ident(conn),
 					L2CAP_DISCONN_REQ, sizeof(req), &req);
 		}
@@ -1652,8 +1658,8 @@ static inline int l2cap_disconnect_req(s
 	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
 		return 0;
 
-	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+	rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
+	rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
 
 	sk->sk_shutdown = SHUTDOWN_MASK;
@@ -1696,8 +1702,8 @@ static inline int l2cap_information_req(
 
 	BT_DBG("type 0x%4.4x", type);
 
-	rsp.type   = __cpu_to_le16(type);
-	rsp.result = __cpu_to_le16(L2CAP_IR_NOTSUPP);
+	rsp.type   = cpu_to_le16(type);
+	rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
 	l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
 
 	return 0;
@@ -1794,7 +1800,7 @@ static inline void l2cap_sig_channel(str
 			BT_DBG("error %d", err);
 
 			/* FIXME: Map err to a valid reason */
-			rej.reason = __cpu_to_le16(0);
+			rej.reason = cpu_to_le16(0);
 			l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
 		}
 
@@ -1993,10 +1999,10 @@ static int l2cap_auth_cfm(struct hci_con
 			result = L2CAP_CR_SEC_BLOCK;
 		}
 
-		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
-		rsp.result = __cpu_to_le16(result);
-		rsp.status = __cpu_to_le16(0);
+		rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+		rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+		rsp.result = cpu_to_le16(result);
+		rsp.status = cpu_to_le16(0);
 		l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 				L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
@@ -2041,10 +2047,10 @@ static int l2cap_encrypt_cfm(struct hci_
 			result = L2CAP_CR_SEC_BLOCK;
 		}
 
-		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
-		rsp.result = __cpu_to_le16(result);
-		rsp.status = __cpu_to_le16(0);
+		rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+		rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+		rsp.result = cpu_to_le16(result);
+		rsp.status = cpu_to_le16(0);
 		l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
 				L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
@@ -2107,7 +2113,8 @@ static int l2cap_recv_acldata(struct hci
 		if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC)))
 			goto drop;
 
-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
+			      skb->len);
 		conn->rx_len = len - skb->len;
 	} else {
 		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
@@ -2128,7 +2135,8 @@ static int l2cap_recv_acldata(struct hci
 			goto drop;
 		}
 
-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
+			      skb->len);
 		conn->rx_len -= skb->len;
 
 		if (!conn->rx_len) {
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 94f4573..52e04df 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -622,7 +622,7 @@ static struct rfcomm_session *rfcomm_ses
 	bacpy(&addr.l2_bdaddr, src);
 	addr.l2_family = AF_BLUETOOTH;
 	addr.l2_psm    = 0;
-	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	*err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
 	if (*err < 0)
 		goto failed;
 
@@ -643,7 +643,7 @@ static struct rfcomm_session *rfcomm_ses
 	bacpy(&addr.l2_bdaddr, dst);
 	addr.l2_family = AF_BLUETOOTH;
 	addr.l2_psm    = htobs(RFCOMM_PSM);
-	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+	*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
 	if (*err == 0 || *err == -EINPROGRESS)
 		return s;
 
@@ -1058,6 +1058,12 @@ static int rfcomm_recv_ua(struct rfcomm_
 		case BT_DISCONN:
 			d->state = BT_CLOSED;
 			__rfcomm_dlc_close(d, 0);
+
+			if (list_empty(&s->dlcs)) {
+				s->state = BT_DISCONN;
+				rfcomm_send_disc(s, 0);
+			}
+
 			break;
 		}
 	} else {
@@ -1067,6 +1073,10 @@ static int rfcomm_recv_ua(struct rfcomm_
 			s->state = BT_CONNECTED;
 			rfcomm_process_connect(s);
 			break;
+
+		case BT_DISCONN:
+			rfcomm_session_put(s);
+			break;
 		}
 	}
 	return 0;
@@ -1567,7 +1577,7 @@ static int rfcomm_recv_frame(struct rfco
 
 	/* Trim FCS */
 	skb->len--; skb->tail--;
-	fcs = *(u8 *) skb->tail;
+	fcs = *(u8 *)skb_tail_pointer(skb);
 
 	if (__check_fcs(skb->data, type, fcs)) {
 		BT_ERR("bad checksum in packet");
@@ -1757,19 +1767,12 @@ static inline void rfcomm_accept_connect
 
 	BT_DBG("session %p", s);
 
-	if (sock_create_lite(PF_BLUETOOTH, sock->type, BTPROTO_L2CAP, &nsock))
+	err = kernel_accept(sock, &nsock, O_NONBLOCK);
+	if (err < 0)
 		return;
 
-	nsock->ops  = sock->ops;
-
 	__module_get(nsock->ops->owner);
 
-	err = sock->ops->accept(sock, nsock, O_NONBLOCK);
-	if (err < 0) {
-		sock_release(nsock);
-		return;
-	}
-
 	/* Set our callbacks */
 	nsock->sk->sk_data_ready   = rfcomm_l2data_ready;
 	nsock->sk->sk_state_change = rfcomm_l2state_change;
@@ -1851,18 +1854,18 @@ static void rfcomm_worker(void)
 	BT_DBG("");
 
 	while (!atomic_read(&terminate)) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
 			/* No pending events. Let's sleep.
 			 * Incoming connections and data will wake us up. */
-			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 		}
+		set_current_state(TASK_RUNNING);
 
 		/* Process stuff */
 		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
 		rfcomm_process_sessions();
 	}
-	set_current_state(TASK_RUNNING);
 	return;
 }
 
@@ -1885,7 +1888,7 @@ static int rfcomm_add_listener(bdaddr_t 
 	bacpy(&addr.l2_bdaddr, ba);
 	addr.l2_family = AF_BLUETOOTH;
 	addr.l2_psm    = htobs(RFCOMM_PSM);
-	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
 	if (err < 0) {
 		BT_ERR("Bind failed %d", err);
 		goto failed;
@@ -1898,7 +1901,7 @@ static int rfcomm_add_listener(bdaddr_t 
 	release_sock(sk);
 
 	/* Start listening on the socket */
-	err = sock->ops->listen(sock, 10);
+	err = kernel_listen(sock, 10);
 	if (err) {
 		BT_ERR("Listen failed %d", err);
 		goto failed;
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 9a7a44f..b2b1cce 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -517,9 +517,10 @@ static void rfcomm_dev_state_change(stru
 	if (dlc->state == BT_CLOSED) {
 		if (!dev->tty) {
 			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-				rfcomm_dev_hold(dev);
-				rfcomm_dev_del(dev);
+				if (rfcomm_dev_get(dev->id) == NULL)
+					return;
 
+				rfcomm_dev_del(dev);
 				/* We have to drop DLC lock here, otherwise
 				   rfcomm_dev_put() will dead lock if it's
 				   the last reference. */
@@ -974,8 +975,12 @@ static void rfcomm_tty_hangup(struct tty
 
 	rfcomm_tty_flush_buffer(tty);
 
-	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+		if (rfcomm_dev_get(dev->id) == NULL)
+			return;
 		rfcomm_dev_del(dev);
+		rfcomm_dev_put(dev);
+	}
 }
 
 static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index ae43914..3f5163e 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -393,7 +393,7 @@ static void sco_sock_close(struct sock *
 	default:
 		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
-	};
+	}
 
 	release_sock(sk);
 
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 2994387..848b8fa 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -37,7 +37,9 @@ static int __init br_init(void)
 		return -EADDRINUSE;
 	}
 
-	br_fdb_init();
+	err = br_fdb_init();
+	if (err)
+		goto err_out1;
 
 	err = br_netfilter_init();
 	if (err)
@@ -47,7 +49,10 @@ static int __init br_init(void)
 	if (err)
 		goto err_out2;
 
-	br_netlink_init();
+	err = br_netlink_init();
+	if (err)
+		goto err_out3;
+
 	brioctl_set(br_ioctl_deviceless_stub);
 	br_handle_frame_hook = br_handle_frame;
 
@@ -55,7 +60,8 @@ static int __init br_init(void)
 	br_fdb_put_hook = br_fdb_put;
 
 	return 0;
-
+err_out3:
+	unregister_netdevice_notifier(&br_device_notifier);
 err_out2:
 	br_netfilter_fini();
 err_out1:
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 905a39c..5e1892d 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -37,7 +37,7 @@ int br_dev_xmit(struct sk_buff *skb, str
 	br->statistics.tx_packets++;
 	br->statistics.tx_bytes += skb->len;
 
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
 
 	if (dest[0] & 1)
@@ -83,27 +83,21 @@ static int br_change_mtu(struct net_devi
 	return 0;
 }
 
-/* Allow setting mac address of pseudo-bridge to be same as
- * any of the bound interfaces
- */
+/* Allow setting mac address to any valid ethernet address. */
 static int br_set_mac_address(struct net_device *dev, void *p)
 {
 	struct net_bridge *br = netdev_priv(dev);
 	struct sockaddr *addr = p;
-	struct net_bridge_port *port;
-	int err = -EADDRNOTAVAIL;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
 
 	spin_lock_bh(&br->lock);
-	list_for_each_entry(port, &br->port_list, list) {
-		if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) {
-			br_stp_change_bridge_id(br, addr->sa_data);
-			err = 0;
-			break;
-		}
-	}
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+	br_stp_change_bridge_id(br, addr->sa_data);
 	spin_unlock_bh(&br->lock);
 
-	return err;
+	return 0;
 }
 
 static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 8d566c1..91b0170 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -20,19 +20,28 @@ #include <linux/times.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/jhash.h>
+#include <linux/random.h>
 #include <asm/atomic.h>
+#include <asm/unaligned.h>
 #include "br_private.h"
 
 static struct kmem_cache *br_fdb_cache __read_mostly;
 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 		      const unsigned char *addr);
 
-void __init br_fdb_init(void)
+static u32 fdb_salt __read_mostly;
+
+int __init br_fdb_init(void)
 {
 	br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
 					 sizeof(struct net_bridge_fdb_entry),
 					 0,
 					 SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!br_fdb_cache)
+		return -ENOMEM;
+
+	get_random_bytes(&fdb_salt, sizeof(fdb_salt));
+	return 0;
 }
 
 void __exit br_fdb_fini(void)
@@ -44,24 +53,26 @@ void __exit br_fdb_fini(void)
 /* if topology_changing then use forward_delay (default 15 sec)
  * otherwise keep longer (default 5 minutes)
  */
-static __inline__ unsigned long hold_time(const struct net_bridge *br)
+static inline unsigned long hold_time(const struct net_bridge *br)
 {
 	return br->topology_change ? br->forward_delay : br->ageing_time;
 }
 
-static __inline__ int has_expired(const struct net_bridge *br,
+static inline int has_expired(const struct net_bridge *br,
 				  const struct net_bridge_fdb_entry *fdb)
 {
 	return !fdb->is_static
 		&& time_before_eq(fdb->ageing_timer + hold_time(br), jiffies);
 }
 
-static __inline__ int br_mac_hash(const unsigned char *mac)
+static inline int br_mac_hash(const unsigned char *mac)
 {
-	return jhash(mac, ETH_ALEN, 0) & (BR_HASH_SIZE - 1);
+	/* use 1 byte of OUI cnd 3 bytes of NIC */
+	u32 key = get_unaligned((u32 *)(mac + 2));
+	return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1);
 }
 
-static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)
+static inline void fdb_delete(struct net_bridge_fdb_entry *f)
 {
 	hlist_del_rcu(&f->hlist);
 	br_fdb_put(f);
@@ -128,7 +139,26 @@ void br_fdb_cleanup(unsigned long _data)
 	mod_timer(&br->gc_timer, jiffies + HZ/10);
 }
 
+/* Completely flush all dynamic entries in forwarding database.*/
+void br_fdb_flush(struct net_bridge *br)
+{
+	int i;
 
+	spin_lock_bh(&br->hash_lock);
+	for (i = 0; i < BR_HASH_SIZE; i++) {
+		struct net_bridge_fdb_entry *f;
+		struct hlist_node *h, *n;
+		hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) {
+			if (!f->is_static)
+				fdb_delete(f);
+		}
+	}
+	spin_unlock_bh(&br->hash_lock);
+}
+
+/* Flush all entries refering to a specific port.
+ * if do_all is set also flush static entries
+ */
 void br_fdb_delete_by_port(struct net_bridge *br,
 			   const struct net_bridge_port *p,
 			   int do_all)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 3e45c1a..ada7f49 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -71,7 +71,7 @@ static void __br_forward(const struct ne
 
 	indev = skb->dev;
 	skb->dev = to->dev;
-	skb->ip_summed = CHECKSUM_NONE;
+	skb_forward_csum(skb);
 
 	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
 			br_forward_finish);
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index f3a2e29..849deaf 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -152,6 +152,8 @@ static void del_nbp(struct net_bridge_po
 	br_stp_disable_port(p);
 	spin_unlock_bh(&br->lock);
 
+	br_ifinfo_notify(RTM_DELLINK, p);
+
 	br_fdb_delete_by_port(br, p, 1);
 
 	list_del_rcu(&p->list);
@@ -203,7 +205,7 @@ static struct net_device *new_bridge_dev
 	memcpy(br->group_addr, br_group_address, ETH_ALEN);
 
 	br->feature_mask = dev->features;
-	br->stp_enabled = 0;
+	br->stp_enabled = BR_NO_STP;
 	br->designated_root = br->bridge_id;
 	br->root_path_cost = 0;
 	br->root_port = 0;
@@ -434,6 +436,8 @@ int br_add_if(struct net_bridge *br, str
 		br_stp_enable_port(p);
 	spin_unlock_bh(&br->lock);
 
+	br_ifinfo_notify(RTM_NEWLINK, p);
+
 	dev_set_mtu(br->dev, br_min_mtu(br));
 
 	kobject_uevent(&p->kobj, KOBJ_ADD);
@@ -471,11 +475,9 @@ void __exit br_cleanup_bridges(void)
 	struct net_device *dev, *nxt;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = nxt) {
-		nxt = dev->next;
+	for_each_netdev_safe(dev, nxt)
 		if (dev->priv_flags & IFF_EBRIDGE)
 			del_br(dev->priv);
-	}
 	rtnl_unlock();
 
 }
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 35b94f9..420bbb9 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -112,46 +112,59 @@ static int br_handle_local_finish(struct
  */
 static inline int is_link_local(const unsigned char *dest)
 {
-	return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0;
+	const u16 *a = (const u16 *) dest;
+	static const u16 *const b = (const u16 *const ) br_group_address;
+	static const u16 m = __constant_cpu_to_be16(0xfff0);
+
+	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
 }
 
 /*
  * Called via br_handle_frame_hook.
- * Return 0 if *pskb should be processed furthur
- *	  1 if *pskb is handled
+ * Return NULL if skb is handled
  * note: already called with rcu_read_lock (preempt_disabled)
  */
-int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb)
+struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
 {
-	struct sk_buff *skb = *pskb;
 	const unsigned char *dest = eth_hdr(skb)->h_dest;
 
 	if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
-		goto err;
+		goto drop;
 
 	if (unlikely(is_link_local(dest))) {
-		skb->pkt_type = PACKET_HOST;
-		return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
-			       NULL, br_handle_local_finish) != 0;
+		/* Pause frames shouldn't be passed up by driver anyway */
+		if (skb->protocol == htons(ETH_P_PAUSE))
+			goto drop;
+
+		/* Process STP BPDU's through normal netif_receive_skb() path */
+		if (p->br->stp_enabled != BR_NO_STP) {
+			if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
+				    NULL, br_handle_local_finish))
+				return NULL;
+			else
+				return skb;
+		}
 	}
 
-	if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) {
+	switch (p->state) {
+	case BR_STATE_FORWARDING:
+
 		if (br_should_route_hook) {
-			if (br_should_route_hook(pskb))
-				return 0;
-			skb = *pskb;
+			if (br_should_route_hook(&skb))
+				return skb;
 			dest = eth_hdr(skb)->h_dest;
 		}
-
+		/* fall through */
+	case BR_STATE_LEARNING:
 		if (!compare_ether_addr(p->br->dev->dev_addr, dest))
 			skb->pkt_type = PACKET_HOST;
 
 		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 			br_handle_frame_finish);
-		return 1;
+		break;
+	default:
+drop:
+		kfree_skb(skb);
 	}
-
-err:
-	kfree_skb(skb);
-	return 1;
+	return NULL;
 }
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 147015f..bb15e9e 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -27,7 +27,9 @@ static int get_bridge_ifindices(int *ind
 	struct net_device *dev;
 	int i = 0;
 
-	for (dev = dev_base; dev && i < num; dev = dev->next) {
+	for_each_netdev(dev) {
+		if (i >= num)
+			break;
 		if (dev->priv_flags & IFF_EBRIDGE)
 			indices[i++] = dev->ifindex;
 	}
@@ -137,7 +139,8 @@ static int old_dev_ioctl(struct net_devi
 		b.topology_change = br->topology_change;
 		b.topology_change_detected = br->topology_change_detected;
 		b.root_port = br->root_port;
-		b.stp_enabled = br->stp_enabled;
+
+		b.stp_enabled = (br->stp_enabled != BR_NO_STP);
 		b.ageing_time = jiffies_to_clock_t(br->ageing_time);
 		b.hello_timer_value = br_timer_value(&br->hello_timer);
 		b.tcn_timer_value = br_timer_value(&br->tcn_timer);
@@ -251,7 +254,7 @@ static int old_dev_ioctl(struct net_devi
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		br->stp_enabled = args[1]?1:0;
+		br_stp_set_enabled(br, args[1]);
 		return 0;
 
 	case BRCTL_SET_BRIDGE_PRIORITY:
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 5439a3c..fa77987 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -29,6 +29,8 @@ #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
+#include <linux/ppp_defs.h>
 #include <linux/netfilter_bridge.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
@@ -48,8 +50,8 @@ #endif
 
 #define skb_origaddr(skb)	 (((struct bridge_skb_cb *) \
 				 (skb->nf_bridge->data))->daddr.ipv4)
-#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = (skb)->nh.iph->daddr)
-#define dnat_took_place(skb)	 (skb_origaddr(skb) != (skb)->nh.iph->daddr)
+#define store_orig_dstaddr(skb)	 (skb_origaddr(skb) = ip_hdr(skb)->daddr)
+#define dnat_took_place(skb)	 (skb_origaddr(skb) != ip_hdr(skb)->daddr)
 
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *brnf_sysctl_header;
@@ -57,8 +59,10 @@ static int brnf_call_iptables __read_mos
 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;
+static int brnf_filter_pppoe_tagged __read_mostly = 1;
 #else
 #define brnf_filter_vlan_tagged 1
+#define brnf_filter_pppoe_tagged 1
 #endif
 
 static inline __be16 vlan_proto(const struct sk_buff *skb)
@@ -81,6 +85,22 @@ #define IS_VLAN_ARP(skb) \
 	 vlan_proto(skb) == htons(ETH_P_ARP) &&	\
 	 brnf_filter_vlan_tagged)
 
+static inline __be16 pppoe_proto(const struct sk_buff *skb)
+{
+	return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
+			    sizeof(struct pppoe_hdr)));
+}
+
+#define IS_PPPOE_IP(skb) \
+	(skb->protocol == htons(ETH_P_PPP_SES) && \
+	 pppoe_proto(skb) == htons(PPP_IP) && \
+	 brnf_filter_pppoe_tagged)
+
+#define IS_PPPOE_IPV6(skb) \
+	(skb->protocol == htons(ETH_P_PPP_SES) && \
+	 pppoe_proto(skb) == htons(PPP_IPV6) && \
+	 brnf_filter_pppoe_tagged)
+
 /* We need these fake structures to make netfilter happy --
  * lots of places assume that skb->dst != NULL, which isn't
  * all that unreasonable.
@@ -122,14 +142,36 @@ static inline struct nf_bridge_info *nf_
 	return skb->nf_bridge;
 }
 
-static inline void nf_bridge_save_header(struct sk_buff *skb)
+static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
+{
+	unsigned int len = nf_bridge_encap_header_len(skb);
+
+	skb_push(skb, len);
+	skb->network_header -= len;
+}
+
+static inline void nf_bridge_pull_encap_header(struct sk_buff *skb)
 {
-	int header_size = ETH_HLEN;
+	unsigned int len = nf_bridge_encap_header_len(skb);
 
-	if (skb->protocol == htons(ETH_P_8021Q))
-		header_size += VLAN_HLEN;
+	skb_pull(skb, len);
+	skb->network_header += len;
+}
+
+static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
+{
+	unsigned int len = nf_bridge_encap_header_len(skb);
+
+	skb_pull_rcsum(skb, len);
+	skb->network_header += len;
+}
 
-	memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
+static inline void nf_bridge_save_header(struct sk_buff *skb)
+{
+	int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
+
+	skb_copy_from_linear_data_offset(skb, -header_size,
+					 skb->nf_bridge->data, header_size);
 }
 
 /*
@@ -139,19 +181,15 @@ static inline void nf_bridge_save_header
 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;
+	int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
 
 	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);
+	skb_copy_to_linear_data_offset(skb, -header_size,
+				       skb->nf_bridge->data, header_size);
+	__skb_push(skb, nf_bridge_encap_header_len(skb));
 	return 0;
 }
 
@@ -172,10 +210,7 @@ static int br_nf_pre_routing_finish_ipv6
 	dst_hold(skb->dst);
 
 	skb->dev = nf_bridge->physindev;
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_push(skb, VLAN_HLEN);
-		skb->nh.raw -= VLAN_HLEN;
-	}
+	nf_bridge_push_encap_header(skb);
 	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 		       br_handle_frame_finish, 1);
 
@@ -253,10 +288,7 @@ static int br_nf_pre_routing_finish_brid
 	if (!skb->dev)
 		kfree_skb(skb);
 	else {
-		if (skb->protocol == htons(ETH_P_8021Q)) {
-			skb_pull(skb, VLAN_HLEN);
-			skb->nh.raw += VLAN_HLEN;
-		}
+		nf_bridge_pull_encap_header(skb);
 		skb->dst->output(skb);
 	}
 	return 0;
@@ -265,7 +297,7 @@ static int br_nf_pre_routing_finish_brid
 static int br_nf_pre_routing_finish(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 	int err;
 
@@ -322,11 +354,7 @@ bridged_dnat:
 				 * bridged frame */
 				nf_bridge->mask |= BRNF_BRIDGED_DNAT;
 				skb->dev = nf_bridge->physindev;
-				if (skb->protocol ==
-				    htons(ETH_P_8021Q)) {
-					skb_push(skb, VLAN_HLEN);
-					skb->nh.raw -= VLAN_HLEN;
-				}
+				nf_bridge_push_encap_header(skb);
 				NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
 					       skb, skb->dev, NULL,
 					       br_nf_pre_routing_finish_bridge,
@@ -342,10 +370,7 @@ bridged_dnat:
 	}
 
 	skb->dev = nf_bridge->physindev;
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_push(skb, VLAN_HLEN);
-		skb->nh.raw -= VLAN_HLEN;
-	}
+	nf_bridge_push_encap_header(skb);
 	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 		       br_handle_frame_finish, 1);
 
@@ -372,9 +397,10 @@ static struct net_device *setup_pre_rout
 /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
 static int check_hbh_len(struct sk_buff *skb)
 {
-	unsigned char *raw = (u8 *) (skb->nh.ipv6h + 1);
+	unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1);
 	u32 pkt_len;
-	int off = raw - skb->nh.raw;
+	const unsigned char *nh = skb_network_header(skb);
+	int off = raw - nh;
 	int len = (raw[1] + 1) << 3;
 
 	if ((raw + len) - skb->data > skb_headlen(skb))
@@ -384,9 +410,9 @@ static int check_hbh_len(struct sk_buff 
 	len -= 2;
 
 	while (len > 0) {
-		int optlen = skb->nh.raw[off + 1] + 2;
+		int optlen = nh[off + 1] + 2;
 
-		switch (skb->nh.raw[off]) {
+		switch (nh[off]) {
 		case IPV6_TLV_PAD0:
 			optlen = 1;
 			break;
@@ -395,17 +421,18 @@ static int check_hbh_len(struct sk_buff 
 			break;
 
 		case IPV6_TLV_JUMBO:
-			if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2)
+			if (nh[off + 1] != 4 || (off & 3) != 2)
 				goto bad;
-			pkt_len = ntohl(*(__be32 *) (skb->nh.raw + off + 2));
+			pkt_len = ntohl(*(__be32 *) (nh + off + 2));
 			if (pkt_len <= IPV6_MAXPLEN ||
-			    skb->nh.ipv6h->payload_len)
+			    ipv6_hdr(skb)->payload_len)
 				goto bad;
 			if (pkt_len > skb->len - sizeof(struct ipv6hdr))
 				goto bad;
 			if (pskb_trim_rcsum(skb,
 					    pkt_len + sizeof(struct ipv6hdr)))
 				goto bad;
+			nh = skb_network_header(skb);
 			break;
 		default:
 			if (optlen > len)
@@ -439,7 +466,7 @@ static unsigned int br_nf_pre_routing_ip
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		goto inhdr_error;
 
-	hdr = skb->nh.ipv6h;
+	hdr = ipv6_hdr(skb);
 
 	if (hdr->version != 6)
 		goto inhdr_error;
@@ -485,18 +512,15 @@ static unsigned int br_nf_pre_routing(un
 	__u32 len;
 	struct sk_buff *skb = *pskb;
 
-	if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb)) {
+	if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) ||
+	    IS_PPPOE_IPV6(skb)) {
 #ifdef CONFIG_SYSCTL
 		if (!brnf_call_ip6tables)
 			return NF_ACCEPT;
 #endif
 		if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
 			goto out;
-
-		if (skb->protocol == htons(ETH_P_8021Q)) {
-			skb_pull_rcsum(skb, VLAN_HLEN);
-			skb->nh.raw += VLAN_HLEN;
-		}
+		nf_bridge_pull_encap_header_rcsum(skb);
 		return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
 	}
 #ifdef CONFIG_SYSCTL
@@ -504,28 +528,25 @@ #ifdef CONFIG_SYSCTL
 		return NF_ACCEPT;
 #endif
 
-	if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb))
+	if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) &&
+	    !IS_PPPOE_IP(skb))
 		return NF_ACCEPT;
 
 	if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
 		goto out;
-
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_pull_rcsum(skb, VLAN_HLEN);
-		skb->nh.raw += VLAN_HLEN;
-	}
+	nf_bridge_pull_encap_header_rcsum(skb);
 
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 		goto inhdr_error;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	if (iph->ihl < 5 || iph->version != 4)
 		goto inhdr_error;
 
 	if (!pskb_may_pull(skb, 4 * iph->ihl))
 		goto inhdr_error;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0)
 		goto inhdr_error;
 
@@ -591,10 +612,7 @@ static int br_nf_forward_finish(struct s
 	} else {
 		in = *((struct net_device **)(skb->cb));
 	}
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_push(skb, VLAN_HLEN);
-		skb->nh.raw -= VLAN_HLEN;
-	}
+	nf_bridge_push_encap_header(skb);
 	NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
 		       skb->dev, br_forward_finish, 1);
 	return 0;
@@ -622,15 +640,13 @@ static unsigned int br_nf_forward_ip(uns
 	if (!parent)
 		return NF_DROP;
 
-	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
+	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
+	    IS_PPPOE_IP(skb))
 		pf = PF_INET;
 	else
 		pf = PF_INET6;
 
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_pull(*pskb, VLAN_HLEN);
-		(*pskb)->nh.raw += VLAN_HLEN;
-	}
+	nf_bridge_pull_encap_header(*pskb);
 
 	nf_bridge = skb->nf_bridge;
 	if (skb->pkt_type == PACKET_OTHERHOST) {
@@ -664,15 +680,12 @@ #endif
 	if (skb->protocol != htons(ETH_P_ARP)) {
 		if (!IS_VLAN_ARP(skb))
 			return NF_ACCEPT;
-		skb_pull(*pskb, VLAN_HLEN);
-		(*pskb)->nh.raw += VLAN_HLEN;
+		nf_bridge_pull_encap_header(*pskb);
 	}
 
-	if (skb->nh.arph->ar_pln != 4) {
-		if (IS_VLAN_ARP(skb)) {
-			skb_push(*pskb, VLAN_HLEN);
-			(*pskb)->nh.raw -= VLAN_HLEN;
-		}
+	if (arp_hdr(skb)->ar_pln != 4) {
+		if (IS_VLAN_ARP(skb))
+			nf_bridge_push_encap_header(*pskb);
 		return NF_ACCEPT;
 	}
 	*d = (struct net_device *)in;
@@ -719,10 +732,7 @@ static unsigned int br_nf_local_out(unsi
 		skb->pkt_type = PACKET_OTHERHOST;
 		nf_bridge->mask ^= BRNF_PKT_TYPE;
 	}
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_push(skb, VLAN_HLEN);
-		skb->nh.raw -= VLAN_HLEN;
-	}
+	nf_bridge_push_encap_header(skb);
 
 	NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev,
 		br_forward_finish);
@@ -753,7 +763,8 @@ static unsigned int br_nf_post_routing(u
 #ifdef CONFIG_NETFILTER_DEBUG
 	/* Be very paranoid. This probably won't happen anymore, but let's
 	 * keep the check just to be sure... */
-	if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
+	if (skb_mac_header(skb) < skb->head ||
+	    skb_mac_header(skb) + ETH_HLEN > skb->data) {
 		printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
 		       "bad mac.raw pointer.\n");
 		goto print_error;
@@ -766,7 +777,8 @@ #endif
 	if (!realoutdev)
 		return NF_DROP;
 
-	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
+	if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) ||
+	    IS_PPPOE_IP(skb))
 		pf = PF_INET;
 	else
 		pf = PF_INET6;
@@ -785,11 +797,7 @@ #endif
 		nf_bridge->mask |= BRNF_PKT_TYPE;
 	}
 
-	if (skb->protocol == htons(ETH_P_8021Q)) {
-		skb_pull(skb, VLAN_HLEN);
-		skb->nh.raw += VLAN_HLEN;
-	}
-
+	nf_bridge_pull_encap_header(skb);
 	nf_bridge_save_header(skb);
 
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -808,7 +816,7 @@ print_error:
 		if (realoutdev)
 			printk("[%s]", realoutdev->name);
 	}
-	printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
+	printk(" head:%p, raw:%p, data:%p\n", skb->head, skb_mac_header(skb),
 	       skb->data);
 	dump_stack();
 	return NF_ACCEPT;
@@ -925,6 +933,14 @@ static ctl_table brnf_table[] = {
 		.mode		= 0644,
 		.proc_handler	= &brnf_sysctl_call_tables,
 	},
+	{
+		.ctl_name	= NET_BRIDGE_NF_FILTER_PPPOE_TAGGED,
+		.procname	= "bridge-nf-filter-pppoe-tagged",
+		.data		= &brnf_filter_pppoe_tagged,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &brnf_sysctl_call_tables,
+	},
 	{ .ctl_name = 0 }
 };
 
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 7d68b24..0fcf6f0 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -11,8 +11,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/rtnetlink.h>
-#include <net/netlink.h>
+#include <net/rtnetlink.h>
 #include "br_private.h"
 
 static inline size_t br_nlmsg_size(void)
@@ -110,8 +109,8 @@ static int br_dump_ifinfo(struct sk_buff
 	struct net_device *dev;
 	int idx;
 
-	read_lock(&dev_base_lock);
-	for (dev = dev_base, idx = 0; dev; dev = dev->next) {
+	idx = 0;
+	for_each_netdev(dev) {
 		/* not a bridge port */
 		if (dev->br_port == NULL || idx < cb->args[0])
 			goto skip;
@@ -123,7 +122,6 @@ static int br_dump_ifinfo(struct sk_buff
 skip:
 		++idx;
 	}
-	read_unlock(&dev_base_lock);
 
 	cb->args[0] = idx;
 
@@ -166,7 +164,7 @@ static int br_rtm_setlink(struct sk_buff
 		return -EINVAL;
 
 	/* if kernel STP is running, don't allow changes */
-	if (p->br->stp_enabled)
+	if (p->br->stp_enabled == BR_KERNEL_STP)
 		return -EBUSY;
 
 	if (!netif_running(dev) ||
@@ -179,18 +177,19 @@ static int br_rtm_setlink(struct sk_buff
 }
 
 
-static struct rtnetlink_link bridge_rtnetlink_table[RTM_NR_MSGTYPES] = {
-	[RTM_GETLINK - RTM_BASE] = { .dumpit	= br_dump_ifinfo, },
-	[RTM_SETLINK - RTM_BASE] = { .doit      = br_rtm_setlink, },
-};
-
-void __init br_netlink_init(void)
+int __init br_netlink_init(void)
 {
-	rtnetlink_links[PF_BRIDGE] = bridge_rtnetlink_table;
+	if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo))
+		return -ENOBUFS;
+
+	/* Only the first call to __rtnl_register can fail */
+	__rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL);
+
+	return 0;
 }
 
 void __exit br_netlink_fini(void)
 {
-	rtnetlink_links[PF_BRIDGE] = NULL;
+	rtnl_unregister_all(PF_BRIDGE);
 }
 
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 37357ed..c8451d3 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -50,7 +50,6 @@ static int br_device_event(struct notifi
 	case NETDEV_CHANGEADDR:
 		spin_lock_bh(&br->lock);
 		br_fdb_changeaddr(p, dev->dev_addr);
-		br_ifinfo_notify(RTM_NEWLINK, p);
 		br_stp_recalculate_bridge_id(br);
 		spin_unlock_bh(&br->lock);
 		break;
@@ -74,10 +73,11 @@ static int br_device_event(struct notifi
 		break;
 
 	case NETDEV_UP:
-		spin_lock_bh(&br->lock);
-		if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP))
+		if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) {
+			spin_lock_bh(&br->lock);
 			br_stp_enable_port(p);
-		spin_unlock_bh(&br->lock);
+			spin_unlock_bh(&br->lock);
+		}
 		break;
 
 	case NETDEV_UNREGISTER:
@@ -85,5 +85,10 @@ static int br_device_event(struct notifi
 		break;
 	}
 
+	/* Events that may cause spanning tree to refresh */
+	if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
+	    event == NETDEV_CHANGE || event == NETDEV_DOWN)
+		br_ifinfo_notify(RTM_NEWLINK, p);
+
 	return NOTIFY_DONE;
 }
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index cc3f1c9..21bf3a9 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -26,7 +26,10 @@ #define BR_HOLD_TIME (1*HZ)
 #define BR_PORT_BITS	10
 #define BR_MAX_PORTS	(1<<BR_PORT_BITS)
 
-#define BR_VERSION	"2.2"
+#define BR_VERSION	"2.3"
+
+/* Path to usermode spanning tree program */
+#define BR_STP_PROG	"/sbin/bridge-stp"
 
 typedef struct bridge_id bridge_id;
 typedef struct mac_addr mac_addr;
@@ -107,7 +110,13 @@ struct net_bridge
 
 	u8				group_addr[ETH_ALEN];
 	u16				root_port;
-	unsigned char			stp_enabled;
+
+	enum {
+		BR_NO_STP, 		/* no spanning tree */
+		BR_KERNEL_STP,		/* old STP in kernel */
+		BR_USER_STP,		/* new RSTP in userspace */
+	} stp_enabled;
+
 	unsigned char			topology_change;
 	unsigned char			topology_change_detected;
 
@@ -127,14 +136,14 @@ static inline int br_is_root_bridge(cons
 	return !memcmp(&br->bridge_id, &br->designated_root, 8);
 }
 
-
 /* br_device.c */
 extern void br_dev_setup(struct net_device *dev);
 extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* br_fdb.c */
-extern void br_fdb_init(void);
+extern int br_fdb_init(void);
 extern void br_fdb_fini(void);
+extern void br_fdb_flush(struct net_bridge *br);
 extern void br_fdb_changeaddr(struct net_bridge_port *p,
 			      const unsigned char *newaddr);
 extern void br_fdb_cleanup(unsigned long arg);
@@ -182,7 +191,8 @@ extern void br_features_recompute(struct
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
-extern int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb);
+extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
+				       struct sk_buff *skb);
 
 /* br_ioctl.c */
 extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -207,6 +217,7 @@ extern void br_become_designated_port(st
 /* br_stp_if.c */
 extern void br_stp_enable_bridge(struct net_bridge *br);
 extern void br_stp_disable_bridge(struct net_bridge *br);
+extern void br_stp_set_enabled(struct net_bridge *br, unsigned long val);
 extern void br_stp_enable_port(struct net_bridge_port *p);
 extern void br_stp_disable_port(struct net_bridge_port *p);
 extern void br_stp_recalculate_bridge_id(struct net_bridge *br);
@@ -235,7 +246,7 @@ extern void (*br_fdb_put_hook)(struct ne
 
 
 /* br_netlink.c */
-extern void br_netlink_init(void);
+extern int br_netlink_init(void);
 extern void br_netlink_fini(void);
 extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
 
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index f9ff4d5..0e035d6 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -13,7 +13,6 @@
  *	2 of the License, or (at your option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
@@ -370,11 +369,11 @@ static void br_make_blocking(struct net_
 static void br_make_forwarding(struct net_bridge_port *p)
 {
 	if (p->state == BR_STATE_BLOCKING) {
-		if (p->br->stp_enabled) {
+		if (p->br->stp_enabled == BR_KERNEL_STP)
 			p->state = BR_STATE_LISTENING;
-		} else {
+		else
 			p->state = BR_STATE_LEARNING;
-		}
+
 		br_log_state(p);
 		mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay);	}
 }
@@ -384,6 +383,10 @@ void br_port_state_selection(struct net_
 {
 	struct net_bridge_port *p;
 
+	/* Don't change port states if userspace is handling STP */
+	if (br->stp_enabled == BR_USER_STP)
+		return;
+
 	list_for_each_entry(p, &br->port_list, list) {
 		if (p->state != BR_STATE_DISABLED) {
 			if (p->port_no == br->root_port) {
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index b9fb0dc..60112bc 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -33,9 +33,6 @@ static void br_send_bpdu(struct net_brid
 {
 	struct sk_buff *skb;
 
-	if (!p->br->stp_enabled)
-		return;
-
 	skb = dev_alloc_skb(length+LLC_RESERVE);
 	if (!skb)
 		return;
@@ -75,6 +72,9 @@ void br_send_config_bpdu(struct net_brid
 {
 	unsigned char buf[35];
 
+	if (p->br->stp_enabled != BR_KERNEL_STP)
+		return;
+
 	buf[0] = 0;
 	buf[1] = 0;
 	buf[2] = 0;
@@ -117,6 +117,9 @@ void br_send_tcn_bpdu(struct net_bridge_
 {
 	unsigned char buf[4];
 
+	if (p->br->stp_enabled != BR_KERNEL_STP)
+		return;
+
 	buf[0] = 0;
 	buf[1] = 0;
 	buf[2] = 0;
@@ -157,9 +160,13 @@ int br_stp_rcv(struct sk_buff *skb, stru
 	br = p->br;
 	spin_lock(&br->lock);
 
-	if (p->state == BR_STATE_DISABLED
-	    || !br->stp_enabled
-	    || !(br->dev->flags & IFF_UP))
+	if (br->stp_enabled != BR_KERNEL_STP)
+		goto out;
+
+	if (!(br->dev->flags & IFF_UP))
+		goto out;
+
+	if (p->state == BR_STATE_DISABLED)
 		goto out;
 
 	if (compare_ether_addr(dest, br->group_addr) != 0)
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index a285897..a786e78 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -14,7 +14,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
 
@@ -87,7 +86,6 @@ void br_stp_disable_bridge(struct net_br
 void br_stp_enable_port(struct net_bridge_port *p)
 {
 	br_init_port(p);
-	br_ifinfo_notify(RTM_NEWLINK, p);
 	br_port_state_selection(p->br);
 }
 
@@ -101,8 +99,6 @@ void br_stp_disable_port(struct net_brid
 	printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
 	       br->dev->name, p->port_no, p->dev->name, "disabled");
 
-	br_ifinfo_notify(RTM_DELLINK, p);
-
 	wasroot = br_is_root_bridge(br);
 	br_become_designated_port(p);
 	p->state = BR_STATE_DISABLED;
@@ -123,6 +119,62 @@ void br_stp_disable_port(struct net_brid
 		br_become_root_bridge(br);
 }
 
+static void br_stp_start(struct net_bridge *br)
+{
+	int r;
+	char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
+	char *envp[] = { NULL };
+
+	r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+	if (r == 0) {
+		br->stp_enabled = BR_USER_STP;
+		printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
+	} else {
+		br->stp_enabled = BR_KERNEL_STP;
+		printk(KERN_INFO "%s: starting userspace STP failed, "
+				"staring kernel STP\n", br->dev->name);
+
+		/* To start timers on any ports left in blocking */
+		spin_lock_bh(&br->lock);
+		br_port_state_selection(br);
+		spin_unlock_bh(&br->lock);
+	}
+}
+
+static void br_stp_stop(struct net_bridge *br)
+{
+	int r;
+	char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL };
+	char *envp[] = { NULL };
+
+	if (br->stp_enabled == BR_USER_STP) {
+		r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+		printk(KERN_INFO "%s: userspace STP stopped, return code %d\n",
+			br->dev->name, r);
+
+
+		/* To start timers on any ports left in blocking */
+		spin_lock_bh(&br->lock);
+		br_port_state_selection(br);
+		spin_unlock_bh(&br->lock);
+	}
+
+	br->stp_enabled = BR_NO_STP;
+}
+
+void br_stp_set_enabled(struct net_bridge *br, unsigned long val)
+{
+	ASSERT_RTNL();
+
+	if (val) {
+		if (br->stp_enabled == BR_NO_STP)
+			br_stp_start(br);
+	} else {
+		if (br->stp_enabled != BR_NO_STP)
+			br_stp_stop(br);
+	}
+}
+
 /* called under bridge lock */
 void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
 {
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 030aa79..24e0ca4 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/times.h>
-#include <linux/smp_lock.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 01a22ad..33c6c4a 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -149,7 +149,11 @@ static ssize_t show_stp_state(struct dev
 
 static void set_stp_state(struct net_bridge *br, unsigned long val)
 {
-	br->stp_enabled = val;
+	rtnl_lock();
+	spin_unlock_bh(&br->lock);
+	br_stp_set_enabled(br, val);
+	spin_lock_bh(&br->lock);
+	rtnl_unlock();
 }
 
 static ssize_t store_stp_state(struct device *d,
@@ -309,6 +313,19 @@ static ssize_t store_group_addr(struct d
 static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
 		   show_group_addr, store_group_addr);
 
+static ssize_t store_flush(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t len)
+{
+	struct net_bridge *br = to_bridge(d);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	br_fdb_flush(br);
+	return len;
+}
+static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
 
 static struct attribute *bridge_attrs[] = {
 	&dev_attr_forward_delay.attr,
@@ -328,6 +345,7 @@ static struct attribute *bridge_attrs[] 
 	&dev_attr_topology_change_timer.attr,
 	&dev_attr_gc_timer.attr,
 	&dev_attr_group_addr.attr,
+	&dev_attr_flush.attr,
 	NULL
 };
 
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 0bc2aef..2da2292 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -137,6 +137,13 @@ static ssize_t show_hold_timer(struct ne
 }
 static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
 
+static ssize_t store_flush(struct net_bridge_port *p, unsigned long v)
+{
+	br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry
+	return 0;
+}
+static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush);
+
 static struct brport_attribute *brport_attrs[] = {
 	&brport_attr_path_cost,
 	&brport_attr_priority,
@@ -152,6 +159,7 @@ static struct brport_attribute *brport_a
 	&brport_attr_message_age_timer,
 	&brport_attr_forward_delay_timer,
 	&brport_attr_hold_timer,
+	&brport_attr_flush,
 	NULL
 };
 
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index 9c59980..1a46952 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -35,40 +35,36 @@ static int ebt_filter_arp(const struct s
 		return EBT_NOMATCH;
 
 	if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
-		__be32 _addr, *ap;
+		__be32 saddr, daddr, *sap, *dap;
 
-		/* IPv4 addresses are always 4 bytes */
-		if (ah->ar_pln != sizeof(__be32))
+		if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
+			return EBT_NOMATCH;
+		sap = skb_header_pointer(skb, sizeof(struct arphdr) +
+					ah->ar_hln, sizeof(saddr),
+					&saddr);
+		if (sap == NULL)
+			return EBT_NOMATCH;
+		dap = skb_header_pointer(skb, sizeof(struct arphdr) +
+					2*ah->ar_hln+sizeof(saddr),
+					sizeof(daddr), &daddr);
+		if (dap == NULL)
+			return EBT_NOMATCH;
+		if (info->bitmask & EBT_ARP_SRC_IP &&
+		    FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP))
+			return EBT_NOMATCH;
+		if (info->bitmask & EBT_ARP_DST_IP &&
+		    FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP))
+			return EBT_NOMATCH;
+		if (info->bitmask & EBT_ARP_GRAT &&
+		    FWINV(*dap != *sap, EBT_ARP_GRAT))
 			return EBT_NOMATCH;
-		if (info->bitmask & EBT_ARP_SRC_IP) {
-			ap = skb_header_pointer(skb, sizeof(struct arphdr) +
-						ah->ar_hln, sizeof(_addr),
-						&_addr);
-			if (ap == NULL)
-				return EBT_NOMATCH;
-			if (FWINV(info->saddr != (*ap & info->smsk),
-			   EBT_ARP_SRC_IP))
-				return EBT_NOMATCH;
-		}
-
-		if (info->bitmask & EBT_ARP_DST_IP) {
-			ap = skb_header_pointer(skb, sizeof(struct arphdr) +
-						2*ah->ar_hln+sizeof(__be32),
-						sizeof(_addr), &_addr);
-			if (ap == NULL)
-				return EBT_NOMATCH;
-			if (FWINV(info->daddr != (*ap & info->dmsk),
-			   EBT_ARP_DST_IP))
-				return EBT_NOMATCH;
-		}
 	}
 
 	if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
 		unsigned char _mac[ETH_ALEN], *mp;
 		uint8_t verdict, i;
 
-		/* MAC addresses are 6 bytes */
-		if (ah->ar_hln != ETH_ALEN)
+		if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
 			return EBT_NOMATCH;
 		if (info->bitmask & EBT_ARP_SRC_MAC) {
 			mp = skb_header_pointer(skb, sizeof(struct arphdr),
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 45712ae..031bfa4 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -196,14 +196,10 @@ static int __init ebt_log_init(void)
 	ret = ebt_register_watcher(&log);
 	if (ret < 0)
 		return ret;
-	if (nf_log_register(PF_BRIDGE, &ebt_log_logger) < 0) {
-		printk(KERN_WARNING "ebt_log: not logging via system console "
-		       "since somebody else already registered for PF_INET\n");
-		/* we cannot make module load fail here, since otherwise
-		 * ebtables userspace would abort */
-	}
-
-	return 0;
+	ret = nf_log_register(PF_BRIDGE, &ebt_log_logger);
+	if (ret < 0 && ret != -EEXIST)
+		ebt_unregister_watcher(&log);
+	return ret;
 }
 
 static void __exit ebt_log_fini(void)
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 8e15cc4..9411db6 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int
 	unsigned int group = uloginfo->nlgroup;
 	ebt_ulog_buff_t *ub = &ulog_buffers[group];
 	spinlock_t *lock = &ub->lock;
+	ktime_t kt;
 
 	if ((uloginfo->cprange == 0) ||
 	    (uloginfo->cprange > skb->len + ETH_HLEN))
@@ -164,9 +165,10 @@ static void ebt_ulog_packet(unsigned int
 
 	/* Fill in the ulog data */
 	pm->version = EBT_ULOG_VERSION;
-	do_gettimeofday(&pm->stamp);
+	kt = ktime_get_real();
+	pm->stamp = ktime_to_timeval(kt);
 	if (ub->qlen == 1)
-		skb_set_timestamp(ub->skb, &pm->stamp);
+		ub->skb->tstamp = kt;
 	pm->data_len = copy_len;
 	pm->mark = skb->mark;
 	pm->hook = hooknr;
@@ -295,14 +297,12 @@ static int __init ebt_ulog_init(void)
 
 	/* initialize ulog_buffers */
 	for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
-		init_timer(&ulog_buffers[i].timer);
-		ulog_buffers[i].timer.function = ulog_timer;
-		ulog_buffers[i].timer.data = i;
+		setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
 		spin_lock_init(&ulog_buffers[i].lock);
 	}
 
 	ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS,
-					  NULL, THIS_MODULE);
+					  NULL, NULL, THIS_MODULE);
 	if (!ebtulognl)
 		ret = -ENOMEM;
 	else if ((ret = ebt_register_watcher(&ulog)))
diff --git a/net/compat.c b/net/compat.c
index 1f32866..9a0f5f2 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -34,11 +34,11 @@ static inline int iov_from_user_compat_t
 {
 	int tot_len = 0;
 
-	while(niov > 0) {
+	while (niov > 0) {
 		compat_uptr_t buf;
 		compat_size_t len;
 
-		if(get_user(len, &uiov32->iov_len) ||
+		if (get_user(len, &uiov32->iov_len) ||
 		   get_user(buf, &uiov32->iov_base)) {
 			tot_len = -EFAULT;
 			break;
@@ -78,12 +78,12 @@ int verify_compat_iovec(struct msghdr *k
 {
 	int tot_len;
 
-	if(kern_msg->msg_namelen) {
-		if(mode==VERIFY_READ) {
+	if (kern_msg->msg_namelen) {
+		if (mode==VERIFY_READ) {
 			int err = move_addr_to_kernel(kern_msg->msg_name,
 						      kern_msg->msg_namelen,
 						      kern_address);
-			if(err < 0)
+			if (err < 0)
 				return err;
 		}
 		kern_msg->msg_name = kern_address;
@@ -93,7 +93,7 @@ int verify_compat_iovec(struct msghdr *k
 	tot_len = iov_from_user_compat_to_kern(kern_iov,
 					  (struct compat_iovec __user *)kern_msg->msg_iov,
 					  kern_msg->msg_iovlen);
-	if(tot_len >= 0)
+	if (tot_len >= 0)
 		kern_msg->msg_iov = kern_iov;
 
 	return tot_len;
@@ -146,8 +146,8 @@ int cmsghdr_from_user_compat_to_kern(str
 	kcmlen = 0;
 	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
 	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
-	while(ucmsg != NULL) {
-		if(get_user(ucmlen, &ucmsg->cmsg_len))
+	while (ucmsg != NULL) {
+		if (get_user(ucmlen, &ucmsg->cmsg_len))
 			return -EFAULT;
 
 		/* Catch bogons. */
@@ -160,7 +160,7 @@ int cmsghdr_from_user_compat_to_kern(str
 		kcmlen += tmp;
 		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
 	}
-	if(kcmlen == 0)
+	if (kcmlen == 0)
 		return -EINVAL;
 
 	/* The kcmlen holds the 64-bit version of the control length.
@@ -176,7 +176,7 @@ int cmsghdr_from_user_compat_to_kern(str
 	/* Now copy them over neatly. */
 	memset(kcmsg, 0, kcmlen);
 	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
-	while(ucmsg != NULL) {
+	while (ucmsg != NULL) {
 		if (__get_user(ucmlen, &ucmsg->cmsg_len))
 			goto Efault;
 		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
@@ -215,11 +215,12 @@ Efault:
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
 	struct compat_timeval ctv;
+	struct compat_timespec cts;
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
 
-	if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
 		kmsg->msg_flags |= MSG_CTRUNC;
 		return 0; /* XXX: return error? check spec. */
 	}
@@ -229,11 +230,18 @@ int put_cmsg_compat(struct msghdr *kmsg,
 		ctv.tv_sec = tv->tv_sec;
 		ctv.tv_usec = tv->tv_usec;
 		data = &ctv;
-		len = sizeof(struct compat_timeval);
+		len = sizeof(ctv);
+	}
+	if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) {
+		struct timespec *ts = (struct timespec *)data;
+		cts.tv_sec = ts->tv_sec;
+		cts.tv_nsec = ts->tv_nsec;
+		data = &cts;
+		len = sizeof(cts);
 	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
-	if(kmsg->msg_controllen < cmlen) {
+	if (kmsg->msg_controllen < cmlen) {
 		kmsg->msg_flags |= MSG_CTRUNC;
 		cmlen = kmsg->msg_controllen;
 	}
@@ -241,9 +249,9 @@ int put_cmsg_compat(struct msghdr *kmsg,
 	cmhdr.cmsg_type = type;
 	cmhdr.cmsg_len = cmlen;
 
-	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
 		return -EFAULT;
-	if(copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
+	if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
 		return -EFAULT;
 	cmlen = CMSG_COMPAT_SPACE(len);
 	kmsg->msg_control += cmlen;
@@ -545,20 +553,49 @@ int compat_sock_get_timestamp(struct soc
 	struct compat_timeval __user *ctv =
 			(struct compat_timeval __user*) userstamp;
 	int err = -ENOENT;
+	struct timeval tv;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
-	if (sk->sk_stamp.tv_sec == -1)
+	tv = ktime_to_timeval(sk->sk_stamp);
+	if (tv.tv_sec == -1)
 		return err;
-	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) ||
-			put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec))
+	if (tv.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		tv = ktime_to_timeval(sk->sk_stamp);
+	}
+	err = 0;
+	if (put_user(tv.tv_sec, &ctv->tv_sec) ||
+			put_user(tv.tv_usec, &ctv->tv_usec))
 		err = -EFAULT;
 	return err;
 }
 EXPORT_SYMBOL(compat_sock_get_timestamp);
 
+int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct compat_timespec __user *ctv =
+			(struct compat_timespec __user*) userstamp;
+	int err = -ENOENT;
+	struct timespec ts;
+
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	ts = ktime_to_timespec(sk->sk_stamp);
+	if (ts.tv_sec == -1)
+		return err;
+	if (ts.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		ts = ktime_to_timespec(sk->sk_stamp);
+	}
+	err = 0;
+	if (put_user(ts.tv_sec, &ctv->tv_sec) ||
+			put_user(ts.tv_nsec, &ctv->tv_nsec))
+		err = -EFAULT;
+	return err;
+}
+EXPORT_SYMBOL(compat_sock_get_timestampns);
+
 asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
@@ -617,7 +654,7 @@ asmlinkage long compat_sys_socketcall(in
 	a0 = a[0];
 	a1 = a[1];
 
-	switch(call) {
+	switch (call) {
 	case SYS_SOCKET:
 		ret = sys_socket(a0, a1, a[2]);
 		break;
diff --git a/net/core/Makefile b/net/core/Makefile
index 73272d5..4751613 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -13,7 +13,6 @@ obj-y		     += dev.o ethtool.o dev_mcast
 obj-$(CONFIG_XFRM) += flow.o
 obj-$(CONFIG_SYSFS) += net-sysfs.o
 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 186212b..cb056f4 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -411,11 +411,11 @@ fault:
 	return -EFAULT;
 }
 
-__sum16 __skb_checksum_complete(struct sk_buff *skb)
+__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
 {
 	__sum16 sum;
 
-	sum = csum_fold(skb_checksum(skb, 0, skb->len, skb->csum));
+	sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
 	if (likely(!sum)) {
 		if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
 			netdev_rx_csum_fault(skb->dev);
@@ -423,6 +423,12 @@ __sum16 __skb_checksum_complete(struct s
 	}
 	return sum;
 }
+EXPORT_SYMBOL(__skb_checksum_complete_head);
+
+__sum16 __skb_checksum_complete(struct sk_buff *skb)
+{
+	return __skb_checksum_complete_head(skb, skb->len);
+}
 EXPORT_SYMBOL(__skb_checksum_complete);
 
 /**
diff --git a/net/core/dev.c b/net/core/dev.c
index 4dc93cc..4317c1b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -109,7 +109,7 @@ #include <linux/kallsyms.h>
 #include <linux/netpoll.h>
 #include <linux/rcupdate.h>
 #include <linux/delay.h>
-#include <linux/wireless.h>
+#include <net/wext.h>
 #include <net/iw_handler.h>
 #include <asm/current.h>
 #include <linux/audit.h>
@@ -146,8 +146,8 @@ #include <linux/ctype.h>
  */
 
 static DEFINE_SPINLOCK(ptype_lock);
-static struct list_head ptype_base[16];	/* 16 way hashed list */
-static struct list_head ptype_all;		/* Taps */
+static struct list_head ptype_base[16] __read_mostly;	/* 16 way hashed list */
+static struct list_head ptype_all __read_mostly;	/* Taps */
 
 #ifdef CONFIG_NET_DMA
 static struct dma_client *net_dma_client;
@@ -156,13 +156,13 @@ static spinlock_t net_dma_event_lock;
 #endif
 
 /*
- * The @dev_base list is protected by @dev_base_lock and the rtnl
+ * The @dev_base_head list is protected by @dev_base_lock and the rtnl
  * semaphore.
  *
  * Pure readers hold dev_base_lock for reading.
  *
  * Writers must hold the rtnl semaphore while they loop through the
- * dev_base list, and hold dev_base_lock for writing when they do the
+ * dev_base_head list, and hold dev_base_lock for writing when they do the
  * actual updates.  This allows pure readers to access the list even
  * while a writer is preparing to update it.
  *
@@ -174,11 +174,10 @@ #endif
  * unregister_netdevice(), which must be called with the rtnl
  * semaphore held.
  */
-struct net_device *dev_base;
-static struct net_device **dev_tail = &dev_base;
+LIST_HEAD(dev_base_head);
 DEFINE_RWLOCK(dev_base_lock);
 
-EXPORT_SYMBOL(dev_base);
+EXPORT_SYMBOL(dev_base_head);
 EXPORT_SYMBOL(dev_base_lock);
 
 #define NETDEV_HASHBITS	8
@@ -226,12 +225,6 @@ #endif
 *******************************************************************************/
 
 /*
- *	For efficiency
- */
-
-static int netdev_nit;
-
-/*
  *	Add a protocol ID to the list. Now that the input handler is
  *	smarter we can dispense with all the messy stuff that used to be
  *	here.
@@ -265,10 +258,9 @@ void dev_add_pack(struct packet_type *pt
 	int hash;
 
 	spin_lock_bh(&ptype_lock);
-	if (pt->type == htons(ETH_P_ALL)) {
-		netdev_nit++;
+	if (pt->type == htons(ETH_P_ALL))
 		list_add_rcu(&pt->list, &ptype_all);
-	} else {
+	else {
 		hash = ntohs(pt->type) & 15;
 		list_add_rcu(&pt->list, &ptype_base[hash]);
 	}
@@ -295,10 +287,9 @@ void __dev_remove_pack(struct packet_typ
 
 	spin_lock_bh(&ptype_lock);
 
-	if (pt->type == htons(ETH_P_ALL)) {
-		netdev_nit--;
+	if (pt->type == htons(ETH_P_ALL))
 		head = &ptype_all;
-	} else
+	else
 		head = &ptype_base[ntohs(pt->type) & 15];
 
 	list_for_each_entry(pt1, head, list) {
@@ -575,26 +566,38 @@ struct net_device *dev_getbyhwaddr(unsig
 
 	ASSERT_RTNL();
 
-	for (dev = dev_base; dev; dev = dev->next)
+	for_each_netdev(dev)
 		if (dev->type == type &&
 		    !memcmp(dev->dev_addr, ha, dev->addr_len))
-			break;
-	return dev;
+			return dev;
+
+	return NULL;
 }
 
 EXPORT_SYMBOL(dev_getbyhwaddr);
 
+struct net_device *__dev_getfirstbyhwtype(unsigned short type)
+{
+	struct net_device *dev;
+
+	ASSERT_RTNL();
+	for_each_netdev(dev)
+		if (dev->type == type)
+			return dev;
+
+	return NULL;
+}
+
+EXPORT_SYMBOL(__dev_getfirstbyhwtype);
+
 struct net_device *dev_getfirstbyhwtype(unsigned short type)
 {
 	struct net_device *dev;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
-		if (dev->type == type) {
-			dev_hold(dev);
-			break;
-		}
-	}
+	dev = __dev_getfirstbyhwtype(type);
+	if (dev)
+		dev_hold(dev);
 	rtnl_unlock();
 	return dev;
 }
@@ -614,17 +617,19 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
 struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
 {
-	struct net_device *dev;
+	struct net_device *dev, *ret;
 
+	ret = NULL;
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (((dev->flags ^ if_flags) & mask) == 0) {
 			dev_hold(dev);
+			ret = dev;
 			break;
 		}
 	}
 	read_unlock(&dev_base_lock);
-	return dev;
+	return ret;
 }
 
 /**
@@ -690,7 +695,7 @@ int dev_alloc_name(struct net_device *de
 		if (!inuse)
 			return -ENOMEM;
 
-		for (d = dev_base; d; d = d->next) {
+		for_each_netdev(d) {
 			if (!sscanf(d->name, name, &i))
 				continue;
 			if (i < 0 || i >= max_netdevices)
@@ -817,7 +822,6 @@ static int default_rebuild_header(struct
 	return 1;
 }
 
-
 /**
  *	dev_open	- prepare an interface for use.
  *	@dev:	device to open
@@ -973,7 +977,7 @@ int register_netdevice_notifier(struct n
 	rtnl_lock();
 	err = raw_notifier_chain_register(&netdev_chain, nb);
 	if (!err) {
-		for (dev = dev_base; dev; dev = dev->next) {
+		for_each_netdev(dev) {
 			nb->notifier_call(nb, NETDEV_REGISTER, dev);
 
 			if (dev->flags & IFF_UP)
@@ -1031,23 +1035,12 @@ void net_disable_timestamp(void)
 	atomic_dec(&netstamp_needed);
 }
 
-void __net_timestamp(struct sk_buff *skb)
-{
-	struct timeval tv;
-
-	do_gettimeofday(&tv);
-	skb_set_timestamp(skb, &tv);
-}
-EXPORT_SYMBOL(__net_timestamp);
-
 static inline void net_timestamp(struct sk_buff *skb)
 {
 	if (atomic_read(&netstamp_needed))
 		__net_timestamp(skb);
-	else {
-		skb->tstamp.off_sec = 0;
-		skb->tstamp.off_usec = 0;
-	}
+	else
+		skb->tstamp.tv64 = 0;
 }
 
 /*
@@ -1077,18 +1070,18 @@ static void dev_queue_xmit_nit(struct sk
 			   set by sender, so that the second statement is
 			   just protection against buggy protocols.
 			 */
-			skb2->mac.raw = skb2->data;
+			skb_reset_mac_header(skb2);
 
-			if (skb2->nh.raw < skb2->data ||
-			    skb2->nh.raw > skb2->tail) {
+			if (skb_network_header(skb2) < skb2->data ||
+			    skb2->network_header > skb2->tail) {
 				if (net_ratelimit())
 					printk(KERN_CRIT "protocol %04x is "
 					       "buggy, dev %s\n",
 					       skb2->protocol, dev->name);
-				skb2->nh.raw = skb2->data;
+				skb_reset_network_header(skb2);
 			}
 
-			skb2->h.raw = skb2->nh.raw;
+			skb2->transport_header = skb2->network_header;
 			skb2->pkt_type = PACKET_OUTGOING;
 			ptype->func(skb2, skb->dev, ptype, skb->dev);
 		}
@@ -1167,7 +1160,7 @@ EXPORT_SYMBOL(netif_device_attach);
 int skb_checksum_help(struct sk_buff *skb)
 {
 	__wsum csum;
-	int ret = 0, offset = skb->h.raw - skb->data;
+	int ret = 0, offset;
 
 	if (skb->ip_summed == CHECKSUM_COMPLETE)
 		goto out_set_summed;
@@ -1183,15 +1176,16 @@ int skb_checksum_help(struct sk_buff *sk
 			goto out;
 	}
 
+	offset = skb->csum_start - skb_headroom(skb);
 	BUG_ON(offset > (int)skb->len);
 	csum = skb_checksum(skb, offset, skb->len-offset, 0);
 
-	offset = skb->tail - skb->h.raw;
+	offset = skb_headlen(skb) - offset;
 	BUG_ON(offset <= 0);
 	BUG_ON(skb->csum_offset + 2 > offset);
 
-	*(__sum16*)(skb->h.raw + skb->csum_offset) = csum_fold(csum);
-
+	*(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) =
+		csum_fold(csum);
 out_set_summed:
 	skb->ip_summed = CHECKSUM_NONE;
 out:
@@ -1217,11 +1211,11 @@ struct sk_buff *skb_gso_segment(struct s
 
 	BUG_ON(skb_shinfo(skb)->frag_list);
 
-	skb->mac.raw = skb->data;
-	skb->mac_len = skb->nh.raw - skb->data;
+	skb_reset_mac_header(skb);
+	skb->mac_len = skb->network_header - skb->mac_header;
 	__skb_pull(skb, skb->mac_len);
 
-	if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
+	if (WARN_ON(skb->ip_summed != CHECKSUM_PARTIAL)) {
 		if (skb_header_cloned(skb) &&
 		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 			return ERR_PTR(err);
@@ -1235,7 +1229,8 @@ struct sk_buff *skb_gso_segment(struct s
 				segs = ERR_PTR(err);
 				if (err || skb_gso_ok(skb, features))
 					break;
-				__skb_push(skb, skb->data - skb->nh.raw);
+				__skb_push(skb, (skb->data -
+						 skb_network_header(skb)));
 			}
 			segs = ptype->gso_segment(skb, features);
 			break;
@@ -1243,7 +1238,7 @@ struct sk_buff *skb_gso_segment(struct s
 	}
 	rcu_read_unlock();
 
-	__skb_push(skb, skb->data - skb->mac.raw);
+	__skb_push(skb, skb->data - skb_mac_header(skb));
 
 	return segs;
 }
@@ -1340,7 +1335,7 @@ static int dev_gso_segment(struct sk_buf
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	if (likely(!skb->next)) {
-		if (netdev_nit)
+		if (!list_empty(&ptype_all))
 			dev_queue_xmit_nit(skb, dev);
 
 		if (netif_needs_gso(dev, skb)) {
@@ -1442,12 +1437,16 @@ 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_PARTIAL &&
-	    (!(dev->features & NETIF_F_GEN_CSUM) &&
-	     (!(dev->features & NETIF_F_IP_CSUM) ||
-	      skb->protocol != htons(ETH_P_IP))))
-		if (skb_checksum_help(skb))
-			goto out_kfree_skb;
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		skb_set_transport_header(skb, skb->csum_start -
+					      skb_headroom(skb));
+
+		if (!(dev->features & NETIF_F_GEN_CSUM) &&
+		    (!(dev->features & NETIF_F_IP_CSUM) ||
+		     skb->protocol != htons(ETH_P_IP)))
+			if (skb_checksum_help(skb))
+				goto out_kfree_skb;
+	}
 
 gso:
 	spin_lock_prefetch(&dev->queue_lock);
@@ -1543,9 +1542,9 @@ out:
 			Receiver routines
   =======================================================================*/
 
-int netdev_max_backlog = 1000;
-int netdev_budget = 300;
-int weight_p = 64;            /* old backlog weight */
+int netdev_max_backlog __read_mostly = 1000;
+int netdev_budget __read_mostly = 300;
+int weight_p __read_mostly = 64;            /* old backlog weight */
 
 DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
@@ -1577,7 +1576,7 @@ int netif_rx(struct sk_buff *skb)
 	if (netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	/*
@@ -1684,40 +1683,46 @@ static void net_tx_action(struct softirq
 	}
 }
 
-static __inline__ int deliver_skb(struct sk_buff *skb,
-				  struct packet_type *pt_prev,
-				  struct net_device *orig_dev)
+static inline int deliver_skb(struct sk_buff *skb,
+			      struct packet_type *pt_prev,
+			      struct net_device *orig_dev)
 {
 	atomic_inc(&skb->users);
 	return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
 }
 
 #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
+/* These hooks defined here for ATM */
 struct net_bridge;
 struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
 						unsigned char *addr);
-void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly;
 
-static __inline__ int handle_bridge(struct sk_buff **pskb,
-				    struct packet_type **pt_prev, int *ret,
-				    struct net_device *orig_dev)
+/*
+ * If bridge module is loaded call bridging hook.
+ *  returns NULL if packet was consumed.
+ */
+struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
+					struct sk_buff *skb) __read_mostly;
+static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
+					    struct packet_type **pt_prev, int *ret,
+					    struct net_device *orig_dev)
 {
 	struct net_bridge_port *port;
 
-	if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
-	    (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
-		return 0;
+	if (skb->pkt_type == PACKET_LOOPBACK ||
+	    (port = rcu_dereference(skb->dev->br_port)) == NULL)
+		return skb;
 
 	if (*pt_prev) {
-		*ret = deliver_skb(*pskb, *pt_prev, orig_dev);
+		*ret = deliver_skb(skb, *pt_prev, orig_dev);
 		*pt_prev = NULL;
 	}
 
-	return br_handle_frame_hook(port, pskb);
+	return br_handle_frame_hook(port, skb);
 }
 #else
-#define handle_bridge(skb, pt_prev, ret, orig_dev)	(0)
+#define handle_bridge(skb, pt_prev, ret, orig_dev)	(skb)
 #endif
 
 #ifdef CONFIG_NET_CLS_ACT
@@ -1747,10 +1752,10 @@ static int ing_filter(struct sk_buff *sk
 
 		skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
 
-		spin_lock(&dev->queue_lock);
+		spin_lock(&dev->ingress_lock);
 		if ((q = dev->qdisc_ingress) != NULL)
 			result = q->enqueue(skb, q);
-		spin_unlock(&dev->queue_lock);
+		spin_unlock(&dev->ingress_lock);
 
 	}
 
@@ -1769,7 +1774,7 @@ int netif_receive_skb(struct sk_buff *sk
 	if (skb->dev->poll && netpoll_rx(skb))
 		return NET_RX_DROP;
 
-	if (!skb->tstamp.off_sec)
+	if (!skb->tstamp.tv64)
 		net_timestamp(skb);
 
 	if (!skb->iif)
@@ -1782,8 +1787,9 @@ int netif_receive_skb(struct sk_buff *sk
 
 	__get_cpu_var(netdev_rx_stat).total++;
 
-	skb->h.raw = skb->nh.raw = skb->data;
-	skb->mac_len = skb->nh.raw - skb->mac.raw;
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb->mac_len = skb->network_header - skb->mac_header;
 
 	pt_prev = NULL;
 
@@ -1823,7 +1829,8 @@ #ifdef CONFIG_NET_CLS_ACT
 ncls:
 #endif
 
-	if (handle_bridge(&skb, &pt_prev, &ret, orig_dev))
+	skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
+	if (!skb)
 		goto out;
 
 	type = skb->protocol;
@@ -2044,7 +2051,7 @@ static int dev_ifconf(char __user *arg)
 	 */
 
 	total = 0;
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		for (i = 0; i < NPROTO; i++) {
 			if (gifconf_list[i]) {
 				int done;
@@ -2076,26 +2083,28 @@ #ifdef CONFIG_PROC_FS
  *	This is invoked by the /proc filesystem handler to display a device
  *	in detail.
  */
-static __inline__ struct net_device *dev_get_idx(loff_t pos)
+void *dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	loff_t off;
 	struct net_device *dev;
-	loff_t i;
 
-	for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
+	read_lock(&dev_base_lock);
+	if (!*pos)
+		return SEQ_START_TOKEN;
 
-	return i == pos ? dev : NULL;
-}
+	off = 1;
+	for_each_netdev(dev)
+		if (off++ == *pos)
+			return dev;
 
-void *dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-	read_lock(&dev_base_lock);
-	return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
+	return NULL;
 }
 
 void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	++*pos;
-	return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;
+	return v == SEQ_START_TOKEN ?
+		first_net_device() : next_net_device((struct net_device *)v);
 }
 
 void dev_seq_stop(struct seq_file *seq, void *v)
@@ -2105,28 +2114,25 @@ void dev_seq_stop(struct seq_file *seq, 
 
 static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
 {
-	if (dev->get_stats) {
-		struct net_device_stats *stats = dev->get_stats(dev);
-
-		seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
-				"%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
-			   dev->name, stats->rx_bytes, stats->rx_packets,
-			   stats->rx_errors,
-			   stats->rx_dropped + stats->rx_missed_errors,
-			   stats->rx_fifo_errors,
-			   stats->rx_length_errors + stats->rx_over_errors +
-			     stats->rx_crc_errors + stats->rx_frame_errors,
-			   stats->rx_compressed, stats->multicast,
-			   stats->tx_bytes, stats->tx_packets,
-			   stats->tx_errors, stats->tx_dropped,
-			   stats->tx_fifo_errors, stats->collisions,
-			   stats->tx_carrier_errors +
-			     stats->tx_aborted_errors +
-			     stats->tx_window_errors +
-			     stats->tx_heartbeat_errors,
-			   stats->tx_compressed);
-	} else
-		seq_printf(seq, "%6s: No statistics available.\n", dev->name);
+	struct net_device_stats *stats = dev->get_stats(dev);
+
+	seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
+		   "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+		   dev->name, stats->rx_bytes, stats->rx_packets,
+		   stats->rx_errors,
+		   stats->rx_dropped + stats->rx_missed_errors,
+		   stats->rx_fifo_errors,
+		   stats->rx_length_errors + stats->rx_over_errors +
+		    stats->rx_crc_errors + stats->rx_frame_errors,
+		   stats->rx_compressed, stats->multicast,
+		   stats->tx_bytes, stats->tx_packets,
+		   stats->tx_errors, stats->tx_dropped,
+		   stats->tx_fifo_errors, stats->collisions,
+		   stats->tx_carrier_errors +
+		    stats->tx_aborted_errors +
+		    stats->tx_window_errors +
+		    stats->tx_heartbeat_errors,
+		   stats->tx_compressed);
 }
 
 /*
@@ -2185,7 +2191,7 @@ static int softnet_seq_show(struct seq_f
 	return 0;
 }
 
-static struct seq_operations dev_seq_ops = {
+static const struct seq_operations dev_seq_ops = {
 	.start = dev_seq_start,
 	.next  = dev_seq_next,
 	.stop  = dev_seq_stop,
@@ -2205,7 +2211,7 @@ static const struct file_operations dev_
 	.release = seq_release,
 };
 
-static struct seq_operations softnet_seq_ops = {
+static const struct seq_operations softnet_seq_ops = {
 	.start = softnet_seq_start,
 	.next  = softnet_seq_next,
 	.stop  = softnet_seq_stop,
@@ -2225,12 +2231,135 @@ static const struct file_operations soft
 	.release = seq_release,
 };
 
-#ifdef CONFIG_WIRELESS_EXT
-extern int wireless_proc_init(void);
-#else
-#define wireless_proc_init() 0
+static void *ptype_get_idx(loff_t pos)
+{
+	struct packet_type *pt = NULL;
+	loff_t i = 0;
+	int t;
+
+	list_for_each_entry_rcu(pt, &ptype_all, list) {
+		if (i == pos)
+			return pt;
+		++i;
+	}
+
+	for (t = 0; t < 16; t++) {
+		list_for_each_entry_rcu(pt, &ptype_base[t], list) {
+			if (i == pos)
+				return pt;
+			++i;
+		}
+	}
+	return NULL;
+}
+
+static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	rcu_read_lock();
+	return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct packet_type *pt;
+	struct list_head *nxt;
+	int hash;
+
+	++*pos;
+	if (v == SEQ_START_TOKEN)
+		return ptype_get_idx(0);
+
+	pt = v;
+	nxt = pt->list.next;
+	if (pt->type == htons(ETH_P_ALL)) {
+		if (nxt != &ptype_all)
+			goto found;
+		hash = 0;
+		nxt = ptype_base[0].next;
+	} else
+		hash = ntohs(pt->type) & 15;
+
+	while (nxt == &ptype_base[hash]) {
+		if (++hash >= 16)
+			return NULL;
+		nxt = ptype_base[hash].next;
+	}
+found:
+	return list_entry(nxt, struct packet_type, list);
+}
+
+static void ptype_seq_stop(struct seq_file *seq, void *v)
+{
+	rcu_read_unlock();
+}
+
+static void ptype_seq_decode(struct seq_file *seq, void *sym)
+{
+#ifdef CONFIG_KALLSYMS
+	unsigned long offset = 0, symsize;
+	const char *symname;
+	char *modname;
+	char namebuf[128];
+
+	symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset,
+				  &modname, namebuf);
+
+	if (symname) {
+		char *delim = ":";
+
+		if (!modname)
+			modname = delim = "";
+		seq_printf(seq, "%s%s%s%s+0x%lx", delim, modname, delim,
+			   symname, offset);
+		return;
+	}
 #endif
 
+	seq_printf(seq, "[%p]", sym);
+}
+
+static int ptype_seq_show(struct seq_file *seq, void *v)
+{
+	struct packet_type *pt = v;
+
+	if (v == SEQ_START_TOKEN)
+		seq_puts(seq, "Type Device      Function\n");
+	else {
+		if (pt->type == htons(ETH_P_ALL))
+			seq_puts(seq, "ALL ");
+		else
+			seq_printf(seq, "%04x", ntohs(pt->type));
+
+		seq_printf(seq, " %-8s ",
+			   pt->dev ? pt->dev->name : "");
+		ptype_seq_decode(seq,  pt->func);
+		seq_putc(seq, '\n');
+	}
+
+	return 0;
+}
+
+static const struct seq_operations ptype_seq_ops = {
+	.start = ptype_seq_start,
+	.next  = ptype_seq_next,
+	.stop  = ptype_seq_stop,
+	.show  = ptype_seq_show,
+};
+
+static int ptype_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &ptype_seq_ops);
+}
+
+static const struct file_operations ptype_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = ptype_seq_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+
 static int __init dev_proc_init(void)
 {
 	int rc = -ENOMEM;
@@ -2239,12 +2368,17 @@ static int __init dev_proc_init(void)
 		goto out;
 	if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops))
 		goto out_dev;
-	if (wireless_proc_init())
+	if (!proc_net_fops_create("ptype", S_IRUGO, &ptype_seq_fops))
+		goto out_dev2;
+
+	if (wext_proc_init())
 		goto out_softnet;
 	rc = 0;
 out:
 	return rc;
 out_softnet:
+	proc_net_remove("ptype");
+out_dev2:
 	proc_net_remove("softnet_stat");
 out_dev:
 	proc_net_remove("dev");
@@ -2795,29 +2929,9 @@ int dev_ioctl(unsigned int cmd, void __u
 					ret = -EFAULT;
 				return ret;
 			}
-#ifdef CONFIG_WIRELESS_EXT
 			/* Take care of Wireless Extensions */
-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				/* If command is `set a parameter', or
-				 * `get the encoding parameters', check if
-				 * the user has the right to do it */
-				if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE
-				    || cmd == SIOCGIWENCODEEXT) {
-					if (!capable(CAP_NET_ADMIN))
-						return -EPERM;
-				}
-				dev_load(ifr.ifr_name);
-				rtnl_lock();
-				/* Follow me in net/core/wireless.c */
-				ret = wireless_process_ioctl(&ifr, cmd);
-				rtnl_unlock();
-				if (IW_IS_GET(cmd) &&
-				    copy_to_user(arg, &ifr,
-						 sizeof(struct ifreq)))
-					ret = -EFAULT;
-				return ret;
-			}
-#endif	/* CONFIG_WIRELESS_EXT */
+			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+				return wext_handle_ioctl(&ifr, cmd, arg);
 			return -EINVAL;
 	}
 }
@@ -2847,7 +2961,7 @@ static int dev_boot_phase = 1;
 static DEFINE_SPINLOCK(net_todo_list_lock);
 static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list);
 
-static inline void net_set_todo(struct net_device *dev)
+static void net_set_todo(struct net_device *dev)
 {
 	spin_lock(&net_todo_list_lock);
 	list_add_tail(&dev->todo_list, &net_todo_list);
@@ -2888,9 +3002,7 @@ int register_netdevice(struct net_device
 	spin_lock_init(&dev->queue_lock);
 	spin_lock_init(&dev->_xmit_lock);
 	dev->xmit_lock_owner = -1;
-#ifdef CONFIG_NET_CLS_ACT
 	spin_lock_init(&dev->ingress_lock);
-#endif
 
 	dev->iflink = -1;
 
@@ -2974,11 +3086,9 @@ #endif
 
 	set_bit(__LINK_STATE_PRESENT, &dev->state);
 
-	dev->next = NULL;
 	dev_init_scheduler(dev);
 	write_lock_bh(&dev_base_lock);
-	*dev_tail = dev;
-	dev_tail = &dev->next;
+	list_add_tail(&dev->dev_list, &dev_base_head);
 	hlist_add_head(&dev->name_hlist, head);
 	hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
 	dev_hold(dev);
@@ -3002,7 +3112,7 @@ out:
  *	chain. 0 is returned on success. A negative errno code is returned
  *	on a failure to set up the device, or if the name is a duplicate.
  *
- *	This is a wrapper around register_netdev that takes the rtnl semaphore
+ *	This is a wrapper around register_netdevice that takes the rtnl semaphore
  *	and expands the device name if you passed a format string to
  *	alloc_netdev.
  */
@@ -3157,6 +3267,11 @@ out:
 	mutex_unlock(&net_todo_run_mutex);
 }
 
+static struct net_device_stats *internal_stats(struct net_device *dev)
+{
+	return &dev->stats;
+}
+
 /**
  *	alloc_netdev - allocate network device
  *	@sizeof_priv:	size of private data to allocate space for
@@ -3192,6 +3307,7 @@ struct net_device *alloc_netdev(int size
 	if (sizeof_priv)
 		dev->priv = netdev_priv(dev);
 
+	dev->get_stats = internal_stats;
 	setup(dev);
 	strcpy(dev->name, name);
 	return dev;
@@ -3246,8 +3362,6 @@ void synchronize_net(void)
 
 void unregister_netdevice(struct net_device *dev)
 {
-	struct net_device *d, **dp;
-
 	BUG_ON(dev_boot_phase);
 	ASSERT_RTNL();
 
@@ -3267,19 +3381,11 @@ void unregister_netdevice(struct net_dev
 		dev_close(dev);
 
 	/* And unlink it from device chain. */
-	for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
-		if (d == dev) {
-			write_lock_bh(&dev_base_lock);
-			hlist_del(&dev->name_hlist);
-			hlist_del(&dev->index_hlist);
-			if (dev_tail == &dev->next)
-				dev_tail = dp;
-			*dp = d->next;
-			write_unlock_bh(&dev_base_lock);
-			break;
-		}
-	}
-	BUG_ON(!d);
+	write_lock_bh(&dev_base_lock);
+	list_del(&dev->dev_list);
+	hlist_del(&dev->name_hlist);
+	hlist_del(&dev->index_hlist);
+	write_unlock_bh(&dev_base_lock);
 
 	dev->reg_state = NETREG_UNREGISTERING;
 
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 56b310c..5a54053 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -223,7 +223,7 @@ static void *dev_mc_seq_start(struct seq
 	loff_t off = 0;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (off++ == *pos)
 			return dev;
 	}
@@ -232,9 +232,8 @@ static void *dev_mc_seq_start(struct seq
 
 static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct net_device *dev = v;
 	++*pos;
-	return dev->next;
+	return next_net_device((struct net_device *)v);
 }
 
 static void dev_mc_seq_stop(struct seq_file *seq, void *v)
@@ -264,7 +263,7 @@ static int dev_mc_seq_show(struct seq_fi
 	return 0;
 }
 
-static struct seq_operations dev_mc_seq_ops = {
+static const struct seq_operations dev_mc_seq_ops = {
 	.start = dev_mc_seq_start,
 	.next  = dev_mc_seq_next,
 	.stop  = dev_mc_seq_stop,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6168edd..8d5e5a0 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -836,7 +836,7 @@ int dev_ethtool(struct ifreq *ifr)
 			return -EPERM;
 	}
 
-	if(dev->ethtool_ops->begin)
+	if (dev->ethtool_ops->begin)
 		if ((rc = dev->ethtool_ops->begin(dev)) < 0)
 			return rc;
 
@@ -952,7 +952,7 @@ int dev_ethtool(struct ifreq *ifr)
 		rc =  -EOPNOTSUPP;
 	}
 
-	if(dev->ethtool_ops->complete)
+	if (dev->ethtool_ops->complete)
 		dev->ethtool_ops->complete(dev);
 
 	if (old_features != dev->features)
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 7174ced..8c5474e 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -44,6 +44,12 @@ static void rules_ops_put(struct fib_rul
 		module_put(ops->owner);
 }
 
+static void flush_route_cache(struct fib_rules_ops *ops)
+{
+	if (ops->flush_cache)
+		ops->flush_cache();
+}
+
 int fib_rules_register(struct fib_rules_ops *ops)
 {
 	int err = -EEXIST;
@@ -132,10 +138,25 @@ int fib_rules_lookup(struct fib_rules_op
 	rcu_read_lock();
 
 	list_for_each_entry_rcu(rule, ops->rules_list, list) {
+jumped:
 		if (!fib_rule_match(rule, ops, fl, flags))
 			continue;
 
-		err = ops->action(rule, fl, flags, arg);
+		if (rule->action == FR_ACT_GOTO) {
+			struct fib_rule *target;
+
+			target = rcu_dereference(rule->ctarget);
+			if (target == NULL) {
+				continue;
+			} else {
+				rule = target;
+				goto jumped;
+			}
+		} else if (rule->action == FR_ACT_NOP)
+			continue;
+		else
+			err = ops->action(rule, fl, flags, arg);
+
 		if (err != -EAGAIN) {
 			fib_rule_get(rule);
 			arg->rule = rule;
@@ -174,13 +195,13 @@ errout:
 	return err;
 }
 
-int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static 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;
+	int err = -EINVAL, unresolved = 0;
 
 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh)))
 		goto errout;
@@ -237,6 +258,28 @@ int fib_nl_newrule(struct sk_buff *skb, 
 	if (!rule->pref && ops->default_pref)
 		rule->pref = ops->default_pref();
 
+	err = -EINVAL;
+	if (tb[FRA_GOTO]) {
+		if (rule->action != FR_ACT_GOTO)
+			goto errout_free;
+
+		rule->target = nla_get_u32(tb[FRA_GOTO]);
+		/* Backward jumps are prohibited to avoid endless loops */
+		if (rule->target <= rule->pref)
+			goto errout_free;
+
+		list_for_each_entry(r, ops->rules_list, list) {
+			if (r->pref == rule->target) {
+				rule->ctarget = r;
+				break;
+			}
+		}
+
+		if (rule->ctarget == NULL)
+			unresolved = 1;
+	} else if (rule->action == FR_ACT_GOTO)
+		goto errout_free;
+
 	err = ops->configure(rule, skb, nlh, frh, tb);
 	if (err < 0)
 		goto errout_free;
@@ -249,12 +292,35 @@ int fib_nl_newrule(struct sk_buff *skb, 
 
 	fib_rule_get(rule);
 
+	if (ops->unresolved_rules) {
+		/*
+		 * There are unresolved goto rules in the list, check if
+		 * any of them are pointing to this new rule.
+		 */
+		list_for_each_entry(r, ops->rules_list, list) {
+			if (r->action == FR_ACT_GOTO &&
+			    r->target == rule->pref) {
+				BUG_ON(r->ctarget != NULL);
+				rcu_assign_pointer(r->ctarget, rule);
+				if (--ops->unresolved_rules == 0)
+					break;
+			}
+		}
+	}
+
+	if (rule->action == FR_ACT_GOTO)
+		ops->nr_goto_rules++;
+
+	if (unresolved)
+		ops->unresolved_rules++;
+
 	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);
+	flush_route_cache(ops);
 	rules_ops_put(ops);
 	return 0;
 
@@ -265,11 +331,11 @@ errout:
 	return err;
 }
 
-int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static 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 fib_rule *rule, *tmp;
 	struct nlattr *tb[FRA_MAX+1];
 	int err = -EINVAL;
 
@@ -322,10 +388,30 @@ int fib_nl_delrule(struct sk_buff *skb, 
 		}
 
 		list_del_rcu(&rule->list);
+
+		if (rule->action == FR_ACT_GOTO)
+			ops->nr_goto_rules--;
+
+		/*
+		 * Check if this rule is a target to any of them. If so,
+		 * disable them. As this operation is eventually very
+		 * expensive, it is only performed if goto rules have
+		 * actually been added.
+		 */
+		if (ops->nr_goto_rules > 0) {
+			list_for_each_entry(tmp, ops->rules_list, list) {
+				if (tmp->ctarget == rule) {
+					rcu_assign_pointer(tmp->ctarget, NULL);
+					ops->unresolved_rules++;
+				}
+			}
+		}
+
 		synchronize_rcu();
 		notify_rule_change(RTM_DELRULE, rule, ops, nlh,
 				   NETLINK_CB(skb).pid);
 		fib_rule_put(rule);
+		flush_route_cache(ops);
 		rules_ops_put(ops);
 		return 0;
 	}
@@ -371,9 +457,16 @@ static int fib_nl_fill_rule(struct sk_bu
 	frh->action = rule->action;
 	frh->flags = rule->flags;
 
-	if (rule->ifname[0])
+	if (rule->action == FR_ACT_GOTO && rule->ctarget == NULL)
+		frh->flags |= FIB_RULE_UNRESOLVED;
+
+	if (rule->ifname[0]) {
 		NLA_PUT_STRING(skb, FRA_IFNAME, rule->ifname);
 
+		if (rule->ifindex == -1)
+			frh->flags |= FIB_RULE_DEV_DETACHED;
+	}
+
 	if (rule->pref)
 		NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref);
 
@@ -383,6 +476,9 @@ static int fib_nl_fill_rule(struct sk_bu
 	if (rule->mark_mask || rule->mark)
 		NLA_PUT_U32(skb, FRA_FWMASK, rule->mark_mask);
 
+	if (rule->target)
+		NLA_PUT_U32(skb, FRA_GOTO, rule->target);
+
 	if (ops->fill(rule, skb, nlh, frh) < 0)
 		goto nla_put_failure;
 
@@ -393,19 +489,14 @@ nla_put_failure:
 	return -EMSGSIZE;
 }
 
-int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family)
+static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
+		      struct fib_rules_ops *ops)
 {
 	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_rcu(rule, ops->rules_list, list) {
-		if (idx < cb->args[0])
+	list_for_each_entry(rule, ops->rules_list, list) {
+		if (idx < cb->args[1])
 			goto skip;
 
 		if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid,
@@ -415,14 +506,44 @@ int fib_rules_dump(struct sk_buff *skb, 
 skip:
 		idx++;
 	}
-	rcu_read_unlock();
-	cb->args[0] = idx;
+	cb->args[1] = idx;
 	rules_ops_put(ops);
 
 	return skb->len;
 }
 
-EXPORT_SYMBOL_GPL(fib_rules_dump);
+static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct fib_rules_ops *ops;
+	int idx = 0, family;
+
+	family = rtnl_msg_family(cb->nlh);
+	if (family != AF_UNSPEC) {
+		/* Protocol specific dump request */
+		ops = lookup_rules_ops(family);
+		if (ops == NULL)
+			return -EAFNOSUPPORT;
+
+		return dump_rules(skb, cb, ops);
+	}
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ops, &rules_ops, list) {
+		if (idx < cb->args[0] || !try_module_get(ops->owner))
+			goto skip;
+
+		if (dump_rules(skb, cb, ops) < 0)
+			break;
+
+		cb->args[1] = 0;
+	skip:
+		idx++;
+	}
+	rcu_read_unlock();
+	cb->args[0] = idx;
+
+	return skb->len;
+}
 
 static void notify_rule_change(int event, struct fib_rule *rule,
 			       struct fib_rules_ops *ops, struct nlmsghdr *nlh,
@@ -501,6 +622,10 @@ static struct notifier_block fib_rules_n
 
 static int __init fib_rules_init(void)
 {
+	rtnl_register(PF_UNSPEC, RTM_NEWRULE, fib_nl_newrule, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule);
+
 	return register_netdevice_notifier(&fib_rules_notifier);
 }
 
diff --git a/net/core/filter.c b/net/core/filter.c
index 8d185a0..bd903aa 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -42,11 +42,11 @@ static void *__load_pointer(struct sk_bu
 	u8 *ptr = NULL;
 
 	if (k >= SKF_NET_OFF)
-		ptr = skb->nh.raw + k - SKF_NET_OFF;
+		ptr = skb_network_header(skb) + k - SKF_NET_OFF;
 	else if (k >= SKF_LL_OFF)
-		ptr = skb->mac.raw + k - SKF_LL_OFF;
+		ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
 
-	if (ptr >= skb->head && ptr < skb->tail)
+	if (ptr >= skb->head && ptr < skb_tail_pointer(skb))
 		return ptr;
 	return NULL;
 }
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 259473d..bcc2559 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -61,7 +61,7 @@ gnet_stats_start_copy_compat(struct sk_b
 	spin_lock_bh(lock);
 	d->lock = lock;
 	if (type)
-		d->tail = (struct rtattr *) skb->tail;
+		d->tail = (struct rtattr *)skb_tail_pointer(skb);
 	d->skb = skb;
 	d->compat_tc_stats = tc_stats_type;
 	d->compat_xstats = xstats_type;
@@ -212,7 +212,7 @@ int
 gnet_stats_finish_copy(struct gnet_dump *d)
 {
 	if (d->tail)
-		d->tail->rta_len = d->skb->tail - (u8 *) d->tail;
+		d->tail->rta_len = skb_tail_pointer(d->skb) - (u8 *)d->tail;
 
 	if (d->compat_tc_stats)
 		if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats,
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index 8b45c9d..e3c26a9 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -79,7 +79,7 @@ static void rfc2863_policy(struct net_de
 	case IF_LINK_MODE_DEFAULT:
 	default:
 		break;
-	};
+	}
 
 	dev->operstate = operstate;
 
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 841e3f3..6f3bb73 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1125,7 +1125,7 @@ int neigh_compat_output(struct sk_buff *
 {
 	struct net_device *dev = skb->dev;
 
-	__skb_pull(skb, skb->nh.raw - skb->data);
+	__skb_pull(skb, skb_network_offset(skb));
 
 	if (dev->hard_header &&
 	    dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
@@ -1147,7 +1147,7 @@ int neigh_resolve_output(struct sk_buff 
 	if (!dst || !(neigh = dst->neighbour))
 		goto discard;
 
-	__skb_pull(skb, skb->nh.raw - skb->data);
+	__skb_pull(skb, skb_network_offset(skb));
 
 	if (!neigh_event_send(neigh, skb)) {
 		int err;
@@ -1190,7 +1190,7 @@ int neigh_connected_output(struct sk_buf
 	struct neighbour *neigh = dst->neighbour;
 	struct net_device *dev = neigh->dev;
 
-	__skb_pull(skb, skb->nh.raw - skb->data);
+	__skb_pull(skb, skb_network_offset(skb));
 
 	read_lock_bh(&neigh->lock);
 	err = dev->hard_header(skb, dev, ntohs(skb->protocol),
@@ -1441,7 +1441,7 @@ int neigh_table_clear(struct neigh_table
 	return 0;
 }
 
-int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct ndmsg *ndm;
 	struct nlattr *dst_attr;
@@ -1506,7 +1506,7 @@ out:
 	return err;
 }
 
-int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct ndmsg *ndm;
 	struct nlattr *tb[NDA_MAX+1];
@@ -1786,7 +1786,7 @@ static struct nla_policy nl_ntbl_parm_po
 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
 };
 
-int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct neigh_table *tbl;
 	struct ndtmsg *ndtmsg;
@@ -1910,7 +1910,7 @@ errout:
 	return err;
 }
 
-int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int family, tidx, nidx = 0;
 	int tbl_skip = cb->args[0];
@@ -2034,7 +2034,7 @@ out:
 	return rc;
 }
 
-int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
+static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct neigh_table *tbl;
 	int t, family, s_t;
@@ -2393,7 +2393,7 @@ static int neigh_stat_seq_show(struct se
 	return 0;
 }
 
-static struct seq_operations neigh_stat_seq_ops = {
+static const struct seq_operations neigh_stat_seq_ops = {
 	.start	= neigh_stat_seq_start,
 	.next	= neigh_stat_seq_next,
 	.stop	= neigh_stat_seq_stop,
@@ -2746,14 +2746,26 @@ void neigh_sysctl_unregister(struct neig
 
 #endif	/* CONFIG_SYSCTL */
 
+static int __init neigh_init(void)
+{
+	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
+
+	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
+	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
+
+	return 0;
+}
+
+subsys_initcall(neigh_init);
+
 EXPORT_SYMBOL(__neigh_event_send);
 EXPORT_SYMBOL(neigh_changeaddr);
 EXPORT_SYMBOL(neigh_compat_output);
 EXPORT_SYMBOL(neigh_connected_output);
 EXPORT_SYMBOL(neigh_create);
-EXPORT_SYMBOL(neigh_delete);
 EXPORT_SYMBOL(neigh_destroy);
-EXPORT_SYMBOL(neigh_dump_info);
 EXPORT_SYMBOL(neigh_event_ns);
 EXPORT_SYMBOL(neigh_ifdown);
 EXPORT_SYMBOL(neigh_lookup);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 4cbb129..b21307b 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -352,8 +352,8 @@ static ssize_t wireless_show(struct devi
 
 	read_lock(&dev_base_lock);
 	if (dev_isalive(dev)) {
-		if(dev->wireless_handlers &&
-		   dev->wireless_handlers->get_wireless_stats)
+		if (dev->wireless_handlers &&
+		    dev->wireless_handlers->get_wireless_stats)
 			iw = dev->wireless_handlers->get_wireless_stats(dev);
 		if (iw != NULL)
 			ret = (*format)(iw, buf);
@@ -412,20 +412,25 @@ static int netdev_uevent(struct device *
 			 int num_envp, char *buf, int size)
 {
 	struct net_device *dev = to_net_dev(d);
-	int i = 0;
-	int n;
+	int retval, len = 0, i = 0;
 
 	/* pass interface to uevent. */
-	envp[i++] = buf;
-	n = snprintf(buf, size, "INTERFACE=%s", dev->name) + 1;
-	buf += n;
-	size -= n;
-
-	if ((size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-
+	retval = add_uevent_var(envp, num_envp, &i,
+				buf, size, &len,
+				"INTERFACE=%s", dev->name);
+	if (retval)
+		goto exit;
+
+	/* pass ifindex to uevent.
+	 * ifindex is useful as it won't change (interface name may change)
+	 * and is what RtNetlink uses natively. */
+	retval = add_uevent_var(envp, num_envp, &i,
+				buf, size, &len,
+				"IFINDEX=%d", dev->ifindex);
+
+exit:
 	envp[i] = NULL;
-	return 0;
+	return retval;
 }
 #endif
 
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 4581ece..758dafe 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -9,7 +9,6 @@
  * Copyright (C) 2002  Red Hat, Inc.
  */
 
-#include <linux/smp_lock.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/string.h>
@@ -86,7 +85,7 @@ static __sum16 checksum_udp(struct sk_bu
 {
 	__wsum psum;
 
-	if (uh->check == 0 || skb->ip_summed == CHECKSUM_UNNECESSARY)
+	if (uh->check == 0 || skb_csum_unnecessary(skb))
 		return 0;
 
 	psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
@@ -293,10 +292,12 @@ void netpoll_send_udp(struct netpoll *np
 	if (!skb)
 		return;
 
-	memcpy(skb->data, msg, len);
+	skb_copy_to_linear_data(skb, msg, len);
 	skb->len += len;
 
-	skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+	skb_push(skb, sizeof(*udph));
+	skb_reset_transport_header(skb);
+	udph = udp_hdr(skb);
 	udph->source = htons(np->local_port);
 	udph->dest = htons(np->remote_port);
 	udph->len = htons(udp_len);
@@ -308,7 +309,9 @@ void netpoll_send_udp(struct netpoll *np
 	if (udph->check == 0)
 		udph->check = CSUM_MANGLED_0;
 
-	skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+	skb_push(skb, sizeof(*iph));
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
 
 	/* iph->version = 4; iph->ihl = 5; */
 	put_unaligned(0x45, (unsigned char *)iph);
@@ -324,7 +327,7 @@ 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);
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	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);
@@ -359,8 +362,9 @@ static void arp_reply(struct sk_buff *sk
 				 (2 * sizeof(u32)))))
 		return;
 
-	skb->h.raw = skb->nh.raw = skb->data;
-	arp = skb->nh.arph;
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	arp = arp_hdr(skb);
 
 	if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
 	     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
@@ -389,7 +393,7 @@ static void arp_reply(struct sk_buff *sk
 	if (!send_skb)
 		return;
 
-	send_skb->nh.raw = send_skb->data;
+	skb_reset_network_header(send_skb);
 	arp = (struct arphdr *) skb_put(send_skb, size);
 	send_skb->dev = skb->dev;
 	send_skb->protocol = htons(ETH_P_ARP);
@@ -443,7 +447,7 @@ int __netpoll_rx(struct sk_buff *skb)
 		goto out;
 
 	/* check if netpoll clients need ARP */
-	if (skb->protocol == __constant_htons(ETH_P_ARP) &&
+	if (skb->protocol == htons(ETH_P_ARP) &&
 	    atomic_read(&trapped)) {
 		skb_queue_tail(&npi->arp_tx, skb);
 		return 1;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 4b01496..9cd3a1c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -117,7 +117,6 @@ #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -164,14 +163,11 @@ #include <asm/timex.h>
 
 #define VERSION  "pktgen v2.68: Packet Generator for packet performance testing.\n"
 
-/* #define PG_DEBUG(a) a */
-#define PG_DEBUG(a)
-
 /* The buckets are exponential in 'width' */
 #define LAT_BUCKETS_MAX 32
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
-#define MPLS_STACK_BOTTOM __constant_htonl(0x00000100)
+#define MPLS_STACK_BOTTOM htonl(0x00000100)
 
 /* Device flag bits */
 #define F_IPSRC_RND   (1<<0)	/* IP-Src Random  */
@@ -214,15 +210,11 @@ struct flow_state {
 };
 
 struct pktgen_dev {
-
 	/*
 	 * Try to keep frequent/infrequent used vars. separated.
 	 */
-
-	char ifname[IFNAMSIZ];
-	char result[512];
-
-	struct pktgen_thread *pg_thread;	/* the owner */
+	struct proc_dir_entry *entry;	/* proc file */
+	struct pktgen_thread *pg_thread;/* the owner */
 	struct list_head list;		/* Used for chaining in the thread's run-queue */
 
 	int running;		/* if this changes to false, the test will stop */
@@ -349,6 +341,8 @@ struct pktgen_dev {
 	unsigned cflows;	/* Concurrent flows (config) */
 	unsigned lflow;		/* Flow length  (config) */
 	unsigned nflows;	/* accumulated flows (stats) */
+
+	char result[512];
 };
 
 struct pktgen_hdr {
@@ -468,17 +462,6 @@ #endif
 	return tmp;
 }
 
-static inline u32 pktgen_random(void)
-{
-#if 0
-	__u32 n;
-	get_random_bytes(&n, 4);
-	return n;
-#else
-	return net_random();
-#endif
-}
-
 static inline __u64 getCurMs(void)
 {
 	struct timeval tv;
@@ -512,7 +495,7 @@ static void pktgen_stop_all_threads_ifs(
 static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
 static void pktgen_stop(struct pktgen_thread *t);
 static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
-static int pktgen_mark_device(const char *ifname);
+
 static unsigned int scan_ip6(const char *s, char ip[16]);
 static unsigned int fmt_ip6(char *s, const char ip[16]);
 
@@ -606,7 +589,7 @@ static int pktgen_if_show(struct seq_fil
 		   "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
 		   pkt_dev->nfrags,
 		   1000 * pkt_dev->delay_us + pkt_dev->delay_ns,
-		   pkt_dev->clone_skb, pkt_dev->ifname);
+		   pkt_dev->clone_skb, pkt_dev->odev->name);
 
 	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
 		   pkt_dev->lflow);
@@ -661,7 +644,7 @@ static int pktgen_if_show(struct seq_fil
 	if (pkt_dev->nr_labels) {
 		unsigned i;
 		seq_printf(seq, "     mpls: ");
-		for(i = 0; i < pkt_dev->nr_labels; i++)
+		for (i = 0; i < pkt_dev->nr_labels; i++)
 			seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
 				   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
 	}
@@ -766,7 +749,7 @@ static int hex32_arg(const char __user *
 	int i = 0;
 	*num = 0;
 
-	for(; i < maxlen; i++) {
+	for (; i < maxlen; i++) {
 		char c;
 		*num <<= 4;
 		if (get_user(c, &user_buffer[i]))
@@ -802,7 +785,7 @@ static int count_trail_chars(const char 
 			break;
 		default:
 			goto done;
-		};
+		}
 	}
 done:
 	return i;
@@ -845,7 +828,7 @@ static int strn_len(const char __user * 
 			break;
 		default:
 			break;
-		};
+		}
 	}
 done_str:
 	return i;
@@ -874,7 +857,7 @@ static ssize_t get_labels(const char __u
 		n++;
 		if (n >= MAX_MPLS_LABELS)
 			return -E2BIG;
-	} while(c == ',');
+	} while (c == ',');
 
 	pkt_dev->nr_labels = n;
 	return i;
@@ -1503,7 +1486,7 @@ static ssize_t pktgen_if_write(struct fi
 		if (len < 0) { return len; }
 		i += len;
 		offset = sprintf(pg_result, "OK: mpls=");
-		for(n = 0; n < pkt_dev->nr_labels; n++)
+		for (n = 0; n < pkt_dev->nr_labels; n++)
 			offset += sprintf(pg_result + offset,
 					  "%08x%s", ntohl(pkt_dev->labels[n]),
 					  n == pkt_dev->nr_labels-1 ? "" : ",");
@@ -1697,13 +1680,13 @@ static int pktgen_thread_show(struct seq
 	if_lock(t);
 	list_for_each_entry(pkt_dev, &t->if_list, list)
 		if (pkt_dev->running)
-			seq_printf(seq, "%s ", pkt_dev->ifname);
+			seq_printf(seq, "%s ", pkt_dev->odev->name);
 
 	seq_printf(seq, "\nStopped: ");
 
 	list_for_each_entry(pkt_dev, &t->if_list, list)
 		if (!pkt_dev->running)
-			seq_printf(seq, "%s ", pkt_dev->ifname);
+			seq_printf(seq, "%s ", pkt_dev->odev->name);
 
 	if (t->result[0])
 		seq_printf(seq, "\nResult: %s\n", t->result);
@@ -1849,16 +1832,14 @@ static struct pktgen_dev *__pktgen_NN_th
 /*
  * mark a device for removal
  */
-static int pktgen_mark_device(const char *ifname)
+static void pktgen_mark_device(const char *ifname)
 {
 	struct pktgen_dev *pkt_dev = NULL;
 	const int max_tries = 10, msec_per_try = 125;
 	int i = 0;
-	int ret = 0;
 
 	mutex_lock(&pktgen_thread_lock);
-	PG_DEBUG(printk("pktgen: pktgen_mark_device marking %s for removal\n",
-			ifname));
+	pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname);
 
 	while (1) {
 
@@ -1867,8 +1848,8 @@ static int pktgen_mark_device(const char
 			break;	/* success */
 
 		mutex_unlock(&pktgen_thread_lock);
-		PG_DEBUG(printk("pktgen: pktgen_mark_device waiting for %s "
-				"to disappear....\n", ifname));
+		pr_debug("pktgen: pktgen_mark_device waiting for %s "
+				"to disappear....\n", ifname);
 		schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
 		mutex_lock(&pktgen_thread_lock);
 
@@ -1876,79 +1857,91 @@ static int pktgen_mark_device(const char
 			printk("pktgen_mark_device: timed out after waiting "
 			       "%d msec for device %s to be removed\n",
 			       msec_per_try * i, ifname);
-			ret = 1;
 			break;
 		}
 
 	}
 
 	mutex_unlock(&pktgen_thread_lock);
+}
 
-	return ret;
+static void pktgen_change_name(struct net_device *dev)
+{
+	struct pktgen_thread *t;
+
+	list_for_each_entry(t, &pktgen_threads, th_list) {
+		struct pktgen_dev *pkt_dev;
+
+		list_for_each_entry(pkt_dev, &t->if_list, list) {
+			if (pkt_dev->odev != dev)
+				continue;
+
+			remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
+
+			pkt_dev->entry = create_proc_entry(dev->name, 0600,
+							   pg_proc_dir);
+			if (!pkt_dev->entry)
+				printk(KERN_ERR "pktgen: can't move proc "
+				       " entry for '%s'\n", dev->name);
+			break;
+		}
+	}
 }
 
 static int pktgen_device_event(struct notifier_block *unused,
 			       unsigned long event, void *ptr)
 {
-	struct net_device *dev = (struct net_device *)(ptr);
+	struct net_device *dev = ptr;
 
 	/* It is OK that we do not hold the group lock right now,
 	 * as we run under the RTNL lock.
 	 */
 
 	switch (event) {
-	case NETDEV_CHANGEADDR:
-	case NETDEV_GOING_DOWN:
-	case NETDEV_DOWN:
-	case NETDEV_UP:
-		/* Ignore for now */
+	case NETDEV_CHANGENAME:
+		pktgen_change_name(dev);
 		break;
 
 	case NETDEV_UNREGISTER:
 		pktgen_mark_device(dev->name);
 		break;
-	};
+	}
 
 	return NOTIFY_DONE;
 }
 
 /* Associate pktgen_dev with a device. */
 
-static struct net_device *pktgen_setup_dev(struct pktgen_dev *pkt_dev)
+static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
 {
 	struct net_device *odev;
+	int err;
 
 	/* Clean old setups */
-
 	if (pkt_dev->odev) {
 		dev_put(pkt_dev->odev);
 		pkt_dev->odev = NULL;
 	}
 
-	odev = dev_get_by_name(pkt_dev->ifname);
-
+	odev = dev_get_by_name(ifname);
 	if (!odev) {
-		printk("pktgen: no such netdevice: \"%s\"\n", pkt_dev->ifname);
-		goto out;
+		printk("pktgen: no such netdevice: \"%s\"\n", ifname);
+		return -ENODEV;
 	}
+
 	if (odev->type != ARPHRD_ETHER) {
-		printk("pktgen: not an ethernet device: \"%s\"\n",
-		       pkt_dev->ifname);
-		goto out_put;
-	}
-	if (!netif_running(odev)) {
-		printk("pktgen: device is down: \"%s\"\n", pkt_dev->ifname);
-		goto out_put;
+		printk("pktgen: not an ethernet device: \"%s\"\n", ifname);
+		err = -EINVAL;
+	} else if (!netif_running(odev)) {
+		printk("pktgen: device is down: \"%s\"\n", ifname);
+		err = -ENETDOWN;
+	} else {
+		pkt_dev->odev = odev;
+		return 0;
 	}
-	pkt_dev->odev = odev;
 
-	return pkt_dev->odev;
-
-out_put:
 	dev_put(odev);
-out:
-	return NULL;
-
+	return err;
 }
 
 /* Read pkt_dev from the interface and set up internal pktgen_dev
@@ -1956,10 +1949,6 @@ out:
  */
 static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
 {
-	/* Try once more, just in case it works now. */
-	if (!pkt_dev->odev)
-		pktgen_setup_dev(pkt_dev);
-
 	if (!pkt_dev->odev) {
 		printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n");
 		sprintf(pkt_dev->result,
@@ -2096,7 +2085,7 @@ static void mod_cur_headers(struct pktge
 	int flow = 0;
 
 	if (pkt_dev->cflows) {
-		flow = pktgen_random() % pkt_dev->cflows;
+		flow = random32() % pkt_dev->cflows;
 
 		if (pkt_dev->flows[flow].count > pkt_dev->lflow)
 			pkt_dev->flows[flow].count = 0;
@@ -2108,7 +2097,7 @@ static void mod_cur_headers(struct pktge
 		__u32 tmp;
 
 		if (pkt_dev->flags & F_MACSRC_RND)
-			mc = pktgen_random() % (pkt_dev->src_mac_count);
+			mc = random32() % pkt_dev->src_mac_count;
 		else {
 			mc = pkt_dev->cur_src_mac_offset++;
 			if (pkt_dev->cur_src_mac_offset >
@@ -2134,7 +2123,7 @@ static void mod_cur_headers(struct pktge
 		__u32 tmp;
 
 		if (pkt_dev->flags & F_MACDST_RND)
-			mc = pktgen_random() % (pkt_dev->dst_mac_count);
+			mc = random32() % pkt_dev->dst_mac_count;
 
 		else {
 			mc = pkt_dev->cur_dst_mac_offset++;
@@ -2158,27 +2147,26 @@ static void mod_cur_headers(struct pktge
 
 	if (pkt_dev->flags & F_MPLS_RND) {
 		unsigned i;
-		for(i = 0; i < pkt_dev->nr_labels; i++)
+		for (i = 0; i < pkt_dev->nr_labels; i++)
 			if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
 				pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
-					     ((__force __be32)pktgen_random() &
+					     ((__force __be32)random32() &
 						      htonl(0x000fffff));
 	}
 
 	if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
-		pkt_dev->vlan_id = pktgen_random() % 4096;
+		pkt_dev->vlan_id = random32() & (4096-1);
 	}
 
 	if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
-		pkt_dev->svlan_id = pktgen_random() % 4096;
+		pkt_dev->svlan_id = random32() & (4096 - 1);
 	}
 
 	if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
 		if (pkt_dev->flags & F_UDPSRC_RND)
-			pkt_dev->cur_udp_src =
-			    ((pktgen_random() %
-			      (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) +
-			     pkt_dev->udp_src_min);
+			pkt_dev->cur_udp_src = random32() %
+				(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
+				+ pkt_dev->udp_src_min;
 
 		else {
 			pkt_dev->cur_udp_src++;
@@ -2189,10 +2177,9 @@ static void mod_cur_headers(struct pktge
 
 	if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
 		if (pkt_dev->flags & F_UDPDST_RND) {
-			pkt_dev->cur_udp_dst =
-			    ((pktgen_random() %
-			      (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) +
-			     pkt_dev->udp_dst_min);
+			pkt_dev->cur_udp_dst = random32() %
+				(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
+				+ pkt_dev->udp_dst_min;
 		} else {
 			pkt_dev->cur_udp_dst++;
 			if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
@@ -2207,7 +2194,7 @@ static void mod_cur_headers(struct pktge
 							       saddr_max))) {
 			__u32 t;
 			if (pkt_dev->flags & F_IPSRC_RND)
-				t = ((pktgen_random() % (imx - imn)) + imn);
+				t = random32() % (imx - imn) + imn;
 			else {
 				t = ntohl(pkt_dev->cur_saddr);
 				t++;
@@ -2228,14 +2215,13 @@ static void mod_cur_headers(struct pktge
 				__be32 s;
 				if (pkt_dev->flags & F_IPDST_RND) {
 
-					t = pktgen_random() % (imx - imn) + imn;
+					t = random32() % (imx - imn) + imn;
 					s = htonl(t);
 
 					while (LOOPBACK(s) || MULTICAST(s)
 					       || BADCLASS(s) || ZERONET(s)
 					       || LOCAL_MCAST(s)) {
-						t = (pktgen_random() %
-						      (imx - imn)) + imn;
+						t = random32() % (imx - imn) + imn;
 						s = htonl(t);
 					}
 					pkt_dev->cur_daddr = s;
@@ -2267,7 +2253,7 @@ static void mod_cur_headers(struct pktge
 
 			for (i = 0; i < 4; i++) {
 				pkt_dev->cur_in6_daddr.s6_addr32[i] =
-				    (((__force __be32)pktgen_random() |
+				    (((__force __be32)random32() |
 				      pkt_dev->min_in6_daddr.s6_addr32[i]) &
 				     pkt_dev->max_in6_daddr.s6_addr32[i]);
 			}
@@ -2277,9 +2263,9 @@ static void mod_cur_headers(struct pktge
 	if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
 		__u32 t;
 		if (pkt_dev->flags & F_TXSIZE_RND) {
-			t = ((pktgen_random() %
-			      (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size))
-			     + pkt_dev->min_pkt_size);
+			t = random32() %
+				(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
+				+ pkt_dev->min_pkt_size;
 		} else {
 			t = pkt_dev->cur_pkt_size + 1;
 			if (t > pkt_dev->max_pkt_size)
@@ -2294,7 +2280,7 @@ static void mod_cur_headers(struct pktge
 static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
 {
 	unsigned i;
-	for(i = 0; i < pkt_dev->nr_labels; i++) {
+	for (i = 0; i < pkt_dev->nr_labels; i++) {
 		*mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
 	}
 	mpls--;
@@ -2316,7 +2302,7 @@ static struct sk_buff *fill_packet_ipv4(
 	int datalen, iplen;
 	struct iphdr *iph;
 	struct pktgen_hdr *pgh = NULL;
-	__be16 protocol = __constant_htons(ETH_P_IP);
+	__be16 protocol = 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 */
@@ -2325,10 +2311,10 @@ static struct sk_buff *fill_packet_ipv4(
 
 
 	if (pkt_dev->nr_labels)
-		protocol = __constant_htons(ETH_P_MPLS_UC);
+		protocol = htons(ETH_P_MPLS_UC);
 
 	if (pkt_dev->vlan_id != 0xffff)
-		protocol = __constant_htons(ETH_P_8021Q);
+		protocol = htons(ETH_P_8021Q);
 
 	/* Update any of the values, used when we're incrementing various
 	 * fields.
@@ -2354,24 +2340,28 @@ static struct sk_buff *fill_packet_ipv4(
 		mpls_push(mpls, pkt_dev);
 
 	if (pkt_dev->vlan_id != 0xffff) {
-		if(pkt_dev->svlan_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);
+			*svlan_encapsulated_proto = 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);
+		*vlan_encapsulated_proto = htons(ETH_P_IP);
 	}
 
-	iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
-	udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+	skb->network_header = skb->tail;
+	skb->transport_header = skb->network_header + sizeof(struct iphdr);
+	skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
+
+	iph = ip_hdr(skb);
+	udph = udp_hdr(skb);
 
 	memcpy(eth, pkt_dev->hh, 12);
 	*(__be16 *) & eth[12] = protocol;
@@ -2400,12 +2390,11 @@ 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) -
-		VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+	skb->mac_header = (skb->network_header - ETH_HLEN -
+			   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;
-	skb->h.uh = udph;
 
 	if (pkt_dev->nfrags <= 0)
 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
@@ -2654,7 +2643,7 @@ static struct sk_buff *fill_packet_ipv6(
 	int datalen;
 	struct ipv6hdr *iph;
 	struct pktgen_hdr *pgh = NULL;
-	__be16 protocol = __constant_htons(ETH_P_IPV6);
+	__be16 protocol = 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 */
@@ -2662,10 +2651,10 @@ static struct sk_buff *fill_packet_ipv6(
 	__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);
+		protocol = htons(ETH_P_MPLS_UC);
 
 	if (pkt_dev->vlan_id != 0xffff)
-		protocol = __constant_htons(ETH_P_8021Q);
+		protocol = htons(ETH_P_8021Q);
 
 	/* Update any of the values, used when we're incrementing various
 	 * fields.
@@ -2690,24 +2679,28 @@ static struct sk_buff *fill_packet_ipv6(
 		mpls_push(mpls, pkt_dev);
 
 	if (pkt_dev->vlan_id != 0xffff) {
-		if(pkt_dev->svlan_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);
+			*svlan_encapsulated_proto = 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);
+		*vlan_encapsulated_proto = htons(ETH_P_IPV6);
 	}
 
-	iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
-	udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+	skb->network_header = skb->tail;
+	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
+	skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
+
+	iph = ipv6_hdr(skb);
+	udph = udp_hdr(skb);
 
 	memcpy(eth, pkt_dev->hh, 12);
 	*(__be16 *) & eth[12] = protocol;
@@ -2729,7 +2722,7 @@ static struct sk_buff *fill_packet_ipv6(
 	udph->len = htons(datalen + sizeof(struct udphdr));
 	udph->check = 0;	/* No checksum */
 
-	*(__be32 *) iph = __constant_htonl(0x60000000);	/* Version + flow */
+	*(__be32 *) iph = htonl(0x60000000);	/* Version + flow */
 
 	if (pkt_dev->traffic_class) {
 		/* Version + traffic class + flow (0) */
@@ -2744,13 +2737,12 @@ 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) -
-		VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+	skb->mac_header = (skb->network_header - ETH_HLEN -
+			   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;
-	skb->nh.ipv6h = iph;
-	skb->h.uh = udph;
 
 	if (pkt_dev->nfrags <= 0)
 		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
@@ -2848,7 +2840,7 @@ static void pktgen_run(struct pktgen_thr
 	struct pktgen_dev *pkt_dev;
 	int started = 0;
 
-	PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t));
+	pr_debug("pktgen: entering pktgen_run. %p\n", t);
 
 	if_lock(t);
 	list_for_each_entry(pkt_dev, &t->if_list, list) {
@@ -2880,7 +2872,7 @@ static void pktgen_stop_all_threads_ifs(
 {
 	struct pktgen_thread *t;
 
-	PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads_ifs.\n"));
+	pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n");
 
 	mutex_lock(&pktgen_thread_lock);
 
@@ -2948,7 +2940,7 @@ static void pktgen_run_all_threads(void)
 {
 	struct pktgen_thread *t;
 
-	PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n"));
+	pr_debug("pktgen: entering pktgen_run_all_threads.\n");
 
 	mutex_lock(&pktgen_thread_lock);
 
@@ -3006,7 +2998,7 @@ static int pktgen_stop_device(struct pkt
 
 	if (!pkt_dev->running) {
 		printk("pktgen: interface: %s is already stopped\n",
-		       pkt_dev->ifname);
+		       pkt_dev->odev->name);
 		return -EINVAL;
 	}
 
@@ -3040,7 +3032,7 @@ static void pktgen_stop(struct pktgen_th
 {
 	struct pktgen_dev *pkt_dev;
 
-	PG_DEBUG(printk("pktgen: entering pktgen_stop\n"));
+	pr_debug("pktgen: entering pktgen_stop\n");
 
 	if_lock(t);
 
@@ -3064,7 +3056,7 @@ static void pktgen_rem_one_if(struct pkt
 	struct list_head *q, *n;
 	struct pktgen_dev *cur;
 
-	PG_DEBUG(printk("pktgen: entering pktgen_rem_one_if\n"));
+	pr_debug("pktgen: entering pktgen_rem_one_if\n");
 
 	if_lock(t);
 
@@ -3093,7 +3085,7 @@ static void pktgen_rem_all_ifs(struct pk
 
 	/* Remove all devices, free mem */
 
-	PG_DEBUG(printk("pktgen: entering pktgen_rem_all_ifs\n"));
+	pr_debug("pktgen: entering pktgen_rem_all_ifs\n");
 	if_lock(t);
 
 	list_for_each_safe(q, n, &t->if_list) {
@@ -3276,7 +3268,7 @@ static int pktgen_thread_worker(void *ar
 
 	t->pid = current->pid;
 
-	PG_DEBUG(printk("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid));
+	pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid);
 
 	max_before_softirq = t->max_before_softirq;
 
@@ -3339,13 +3331,13 @@ static int pktgen_thread_worker(void *ar
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
 
-	PG_DEBUG(printk("pktgen: %s stopping all device\n", t->tsk->comm));
+	pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
 	pktgen_stop(t);
 
-	PG_DEBUG(printk("pktgen: %s removing all device\n", t->tsk->comm));
+	pr_debug("pktgen: %s removing all device\n", t->tsk->comm);
 	pktgen_rem_all_ifs(t);
 
-	PG_DEBUG(printk("pktgen: %s removing thread.\n", t->tsk->comm));
+	pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
 	pktgen_rem_thread(t);
 
 	return 0;
@@ -3358,13 +3350,13 @@ static struct pktgen_dev *pktgen_find_de
 	if_lock(t);
 
 	list_for_each_entry(p, &t->if_list, list)
-		if (strncmp(p->ifname, ifname, IFNAMSIZ) == 0) {
+		if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) {
 			pkt_dev = p;
 			break;
 		}
 
 	if_unlock(t);
-	PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev));
+	pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev);
 	return pkt_dev;
 }
 
@@ -3399,7 +3391,7 @@ out:
 static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 {
 	struct pktgen_dev *pkt_dev;
-	struct proc_dir_entry *pe;
+	int err;
 
 	/* We don't allow a device to be on several threads */
 
@@ -3441,29 +3433,28 @@ static int pktgen_add_device(struct pktg
 	pkt_dev->svlan_cfi = 0;
 	pkt_dev->svlan_id = 0xffff;
 
-	strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);
+	err = pktgen_setup_dev(pkt_dev, ifname);
+	if (err)
+		goto out1;
 
-	if (!pktgen_setup_dev(pkt_dev)) {
-		printk("pktgen: ERROR: pktgen_setup_dev failed.\n");
-		if (pkt_dev->flows)
-			vfree(pkt_dev->flows);
-		kfree(pkt_dev);
-		return -ENODEV;
-	}
-
-	pe = create_proc_entry(ifname, 0600, pg_proc_dir);
-	if (!pe) {
+	pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir);
+	if (!pkt_dev->entry) {
 		printk("pktgen: cannot create %s/%s procfs entry.\n",
 		       PG_PROC_DIR, ifname);
-		if (pkt_dev->flows)
-			vfree(pkt_dev->flows);
-		kfree(pkt_dev);
-		return -EINVAL;
+		err = -EINVAL;
+		goto out2;
 	}
-	pe->proc_fops = &pktgen_if_fops;
-	pe->data = pkt_dev;
+	pkt_dev->entry->proc_fops = &pktgen_if_fops;
+	pkt_dev->entry->data = pkt_dev;
 
 	return add_dev_to_thread(t, pkt_dev);
+out2:
+	dev_put(pkt_dev->odev);
+out1:
+	if (pkt_dev->flows)
+		vfree(pkt_dev->flows);
+	kfree(pkt_dev);
+	return err;
 }
 
 static int __init pktgen_create_thread(int cpu)
@@ -3533,7 +3524,7 @@ static int pktgen_remove_device(struct p
 				struct pktgen_dev *pkt_dev)
 {
 
-	PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev));
+	pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev);
 
 	if (pkt_dev->running) {
 		printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n");
@@ -3551,9 +3542,8 @@ static int pktgen_remove_device(struct p
 
 	_rem_dev_from_if_list(t, pkt_dev);
 
-	/* Clean up proc file system */
-
-	remove_proc_entry(pkt_dev->ifname, pg_proc_dir);
+	if (pkt_dev->entry)
+		remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
 
 	if (pkt_dev->flows)
 		vfree(pkt_dev->flows);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 33ea8ea..8c971a2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -50,11 +50,13 @@ #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>
-#include <net/iw_handler.h>
-#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */
+#include <net/rtnetlink.h>
+
+struct rtnl_link
+{
+	rtnl_doit_func		doit;
+	rtnl_dumpit_func	dumpit;
+};
 
 static DEFINE_MUTEX(rtnl_mutex);
 static struct sock *rtnl;
@@ -95,7 +97,151 @@ int rtattr_parse(struct rtattr *tb[], in
 	return 0;
 }
 
-struct rtnetlink_link * rtnetlink_links[NPROTO];
+static struct rtnl_link *rtnl_msg_handlers[NPROTO];
+
+static inline int rtm_msgindex(int msgtype)
+{
+	int msgindex = msgtype - RTM_BASE;
+
+	/*
+	 * msgindex < 0 implies someone tried to register a netlink
+	 * control code. msgindex >= RTM_NR_MSGTYPES may indicate that
+	 * the message type has not been added to linux/rtnetlink.h
+	 */
+	BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES);
+
+	return msgindex;
+}
+
+static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex)
+{
+	struct rtnl_link *tab;
+
+	tab = rtnl_msg_handlers[protocol];
+	if (tab == NULL || tab[msgindex].doit == NULL)
+		tab = rtnl_msg_handlers[PF_UNSPEC];
+
+	return tab ? tab[msgindex].doit : NULL;
+}
+
+static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
+{
+	struct rtnl_link *tab;
+
+	tab = rtnl_msg_handlers[protocol];
+	if (tab == NULL || tab[msgindex].dumpit == NULL)
+		tab = rtnl_msg_handlers[PF_UNSPEC];
+
+	return tab ? tab[msgindex].dumpit : NULL;
+}
+
+/**
+ * __rtnl_register - Register a rtnetlink message type
+ * @protocol: Protocol family or PF_UNSPEC
+ * @msgtype: rtnetlink message type
+ * @doit: Function pointer called for each request message
+ * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
+ *
+ * Registers the specified function pointers (at least one of them has
+ * to be non-NULL) to be called whenever a request message for the
+ * specified protocol family and message type is received.
+ *
+ * The special protocol family PF_UNSPEC may be used to define fallback
+ * function pointers for the case when no entry for the specific protocol
+ * family exists.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int __rtnl_register(int protocol, int msgtype,
+		    rtnl_doit_func doit, rtnl_dumpit_func dumpit)
+{
+	struct rtnl_link *tab;
+	int msgindex;
+
+	BUG_ON(protocol < 0 || protocol >= NPROTO);
+	msgindex = rtm_msgindex(msgtype);
+
+	tab = rtnl_msg_handlers[protocol];
+	if (tab == NULL) {
+		tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);
+		if (tab == NULL)
+			return -ENOBUFS;
+
+		rtnl_msg_handlers[protocol] = tab;
+	}
+
+	if (doit)
+		tab[msgindex].doit = doit;
+
+	if (dumpit)
+		tab[msgindex].dumpit = dumpit;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(__rtnl_register);
+
+/**
+ * rtnl_register - Register a rtnetlink message type
+ *
+ * Identical to __rtnl_register() but panics on failure. This is useful
+ * as failure of this function is very unlikely, it can only happen due
+ * to lack of memory when allocating the chain to store all message
+ * handlers for a protocol. Meant for use in init functions where lack
+ * of memory implies no sense in continueing.
+ */
+void rtnl_register(int protocol, int msgtype,
+		   rtnl_doit_func doit, rtnl_dumpit_func dumpit)
+{
+	if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)
+		panic("Unable to register rtnetlink message handler, "
+		      "protocol = %d, message type = %d\n",
+		      protocol, msgtype);
+}
+
+EXPORT_SYMBOL_GPL(rtnl_register);
+
+/**
+ * rtnl_unregister - Unregister a rtnetlink message type
+ * @protocol: Protocol family or PF_UNSPEC
+ * @msgtype: rtnetlink message type
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int rtnl_unregister(int protocol, int msgtype)
+{
+	int msgindex;
+
+	BUG_ON(protocol < 0 || protocol >= NPROTO);
+	msgindex = rtm_msgindex(msgtype);
+
+	if (rtnl_msg_handlers[protocol] == NULL)
+		return -ENOENT;
+
+	rtnl_msg_handlers[protocol][msgindex].doit = NULL;
+	rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;
+
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(rtnl_unregister);
+
+/**
+ * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol
+ * @protocol : Protocol family or PF_UNSPEC
+ *
+ * Identical to calling rtnl_unregster() for all registered message types
+ * of a certain protocol family.
+ */
+void rtnl_unregister_all(int protocol)
+{
+	BUG_ON(protocol < 0 || protocol >= NPROTO);
+
+	kfree(rtnl_msg_handlers[protocol]);
+	rtnl_msg_handlers[protocol] = NULL;
+}
+
+EXPORT_SYMBOL_GPL(rtnl_unregister_all);
 
 static const int rtm_min[RTM_NR_FAMILIES] =
 {
@@ -249,7 +395,7 @@ static void set_operstate(struct net_dev
 		    operstate == IF_OPER_UNKNOWN)
 			operstate = IF_OPER_DORMANT;
 		break;
-	};
+	}
 
 	if (dev->operstate != operstate) {
 		write_lock_bh(&dev_base_lock);
@@ -393,16 +539,17 @@ static int rtnl_dump_ifinfo(struct sk_bu
 	int s_idx = cb->args[0];
 	struct net_device *dev;
 
-	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		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;
+cont:
+		idx++;
 	}
-	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
 
 	return skb->len;
@@ -536,17 +683,6 @@ static int rtnl_setlink(struct sk_buff *
 		modified = 1;
 	}
 
-#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 */
-
 	if (tb[IFLA_BROADCAST]) {
 		nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
 		send_addr_notify = 1;
@@ -610,22 +746,6 @@ static int rtnl_getlink(struct sk_buff *
 	} else
 		return -EINVAL;
 
-
-#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, nla_data(tb[IFLA_WIRELESS]),
-					     nla_len(tb[IFLA_WIRELESS]),
-					     &iw_buf, &iw_buf_len);
-		if (err < 0)
-			goto errout;
-
-		/* Payload is at an offset in buffer */
-		iw = iw_buf + IW_EV_POINT_OFF;
-	}
-#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */
-
 	nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL);
 	if (nskb == NULL) {
 		err = -ENOBUFS;
@@ -659,12 +779,12 @@ static int rtnl_dump_all(struct sk_buff 
 		int type = cb->nlh->nlmsg_type-RTM_BASE;
 		if (idx < s_idx || idx == PF_PACKET)
 			continue;
-		if (rtnetlink_links[idx] == NULL ||
-		    rtnetlink_links[idx][type].dumpit == NULL)
+		if (rtnl_msg_handlers[idx] == NULL ||
+		    rtnl_msg_handlers[idx][type].dumpit == NULL)
 			continue;
 		if (idx > s_idx)
 			memset(&cb->args[0], 0, sizeof(cb->args));
-		if (rtnetlink_links[idx][type].dumpit(skb, cb))
+		if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))
 			break;
 	}
 	cb->family = idx;
@@ -700,30 +820,18 @@ static int rtattr_max;
 
 /* Process one rtnetlink message. */
 
-static __inline__ int
-rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	struct rtnetlink_link *link;
-	struct rtnetlink_link *link_tab;
+	rtnl_doit_func doit;
 	int sz_idx, kind;
 	int min_len;
 	int family;
 	int type;
 	int err;
 
-	/* Only requests are handled by kernel now */
-	if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
-		return 0;
-
 	type = nlh->nlmsg_type;
-
-	/* A control message: ignore them */
-	if (type < RTM_BASE)
-		return 0;
-
-	/* Unknown message: reply with EINVAL */
 	if (type > RTM_MAX)
-		goto err_inval;
+		return -EOPNOTSUPP;
 
 	type -= RTM_BASE;
 
@@ -732,45 +840,33 @@ rtnetlink_rcv_msg(struct sk_buff *skb, s
 		return 0;
 
 	family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
-	if (family >= NPROTO) {
-		*errp = -EAFNOSUPPORT;
-		return -1;
-	}
-
-	link_tab = rtnetlink_links[family];
-	if (link_tab == NULL)
-		link_tab = rtnetlink_links[PF_UNSPEC];
-	link = &link_tab[type];
+	if (family >= NPROTO)
+		return -EAFNOSUPPORT;
 
 	sz_idx = type>>2;
 	kind = type&3;
 
-	if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) {
-		*errp = -EPERM;
-		return -1;
-	}
+	if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
+		return -EPERM;
 
 	if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
-		if (link->dumpit == NULL)
-			link = &(rtnetlink_links[PF_UNSPEC][type]);
-
-		if (link->dumpit == NULL)
-			goto err_inval;
+		rtnl_dumpit_func dumpit;
 
-		if ((*errp = netlink_dump_start(rtnl, skb, nlh,
-						link->dumpit, NULL)) != 0) {
-			return -1;
-		}
+		dumpit = rtnl_get_dumpit(family, type);
+		if (dumpit == NULL)
+			return -EOPNOTSUPP;
 
-		netlink_queue_skip(nlh, skb);
-		return -1;
+		__rtnl_unlock();
+		err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+		rtnl_lock();
+		return err;
 	}
 
 	memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
 
 	min_len = rtm_min[sz_idx];
 	if (nlh->nlmsg_len < min_len)
-		goto err_inval;
+		return -EINVAL;
 
 	if (nlh->nlmsg_len > min_len) {
 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
@@ -780,25 +876,18 @@ rtnetlink_rcv_msg(struct sk_buff *skb, s
 			unsigned flavor = attr->rta_type;
 			if (flavor) {
 				if (flavor > rta_max[sz_idx])
-					goto err_inval;
+					return -EINVAL;
 				rta_buf[flavor-1] = attr;
 			}
 			attr = RTA_NEXT(attr, attrlen);
 		}
 	}
 
-	if (link->doit == NULL)
-		link = &(rtnetlink_links[PF_UNSPEC][type]);
-	if (link->doit == NULL)
-		goto err_inval;
-	err = link->doit(skb, nlh, (void *)&rta_buf[0]);
+	doit = rtnl_get_doit(family, type);
+	if (doit == NULL)
+		return -EOPNOTSUPP;
 
-	*errp = err;
-	return err;
-
-err_inval:
-	*errp = -EINVAL;
-	return -1;
+	return doit(skb, nlh, (void *)&rta_buf[0]);
 }
 
 static void rtnetlink_rcv(struct sock *sk, int len)
@@ -814,25 +903,6 @@ static void rtnetlink_rcv(struct sock *s
 	} while (qlen);
 }
 
-static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
-{
-	[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	 },
-#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		 },
-};
-
 static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
@@ -874,19 +944,22 @@ void __init rtnetlink_init(void)
 		panic("rtnetlink_init: cannot allocate rta_buf\n");
 
 	rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv,
-				     THIS_MODULE);
+				     &rtnl_mutex, THIS_MODULE);
 	if (rtnl == NULL)
 		panic("rtnetlink_init: cannot initialize rtnetlink\n");
 	netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
 	register_netdevice_notifier(&rtnetlink_dev_notifier);
-	rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table;
-	rtnetlink_links[PF_PACKET] = link_rtnetlink_table;
+
+	rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
+	rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
+
+	rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
+	rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);
 }
 
 EXPORT_SYMBOL(__rta_fill);
 EXPORT_SYMBOL(rtattr_strlcpy);
 EXPORT_SYMBOL(rtattr_parse);
-EXPORT_SYMBOL(rtnetlink_links);
 EXPORT_SYMBOL(rtnetlink_put_metrics);
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_trylock);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 336958f..1422573 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -55,6 +55,7 @@ #include <linux/skbuff.h>
 #include <linux/cache.h>
 #include <linux/rtnetlink.h>
 #include <linux/init.h>
+#include <linux/scatterlist.h>
 
 #include <net/protocol.h>
 #include <net/dst.h>
@@ -87,8 +88,9 @@ static struct kmem_cache *skbuff_fclone_
 void skb_over_panic(struct sk_buff *skb, int sz, void *here)
 {
 	printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "
-			  "data:%p tail:%p end:%p dev:%s\n",
-	       here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end,
+			  "data:%p tail:%#lx end:%#lx dev:%s\n",
+	       here, skb->len, sz, skb->head, skb->data,
+	       (unsigned long)skb->tail, (unsigned long)skb->end,
 	       skb->dev ? skb->dev->name : "<NULL>");
 	BUG();
 }
@@ -105,8 +107,9 @@ void skb_over_panic(struct sk_buff *skb,
 void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
 	printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "
-			  "data:%p tail:%p end:%p dev:%s\n",
-	       here, skb->len, sz, skb->head, skb->data, skb->tail, skb->end,
+			  "data:%p tail:%#lx end:%#lx dev:%s\n",
+	       here, skb->len, sz, skb->head, skb->data,
+	       (unsigned long)skb->tail, (unsigned long)skb->end,
 	       skb->dev ? skb->dev->name : "<NULL>");
 	BUG();
 }
@@ -155,20 +158,22 @@ struct sk_buff *__alloc_skb(unsigned int
 	if (!skb)
 		goto out;
 
-	/* Get the DATA. Size must match skb_add_mtu(). */
 	size = SKB_DATA_ALIGN(size);
 	data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
 			gfp_mask, node);
 	if (!data)
 		goto nodata;
 
-	memset(skb, 0, offsetof(struct sk_buff, truesize));
+	/*
+	 * See comment in sk_buff definition, just before the 'tail' member
+	 */
+	memset(skb, 0, offsetof(struct sk_buff, tail));
 	skb->truesize = size + sizeof(struct sk_buff);
 	atomic_set(&skb->users, 1);
 	skb->head = data;
 	skb->data = data;
-	skb->tail = data;
-	skb->end  = data + size;
+	skb_reset_tail_pointer(skb);
+	skb->end = skb->tail + size;
 	/* make sure we initialize shinfo sequentially */
 	shinfo = skb_shinfo(skb);
 	atomic_set(&shinfo->dataref, 1);
@@ -299,7 +304,7 @@ void kfree_skbmem(struct sk_buff *skb)
 		if (atomic_dec_and_test(fclone_ref))
 			kmem_cache_free(skbuff_fclone_cache, other);
 		break;
-	};
+	}
 }
 
 /**
@@ -321,15 +326,13 @@ #endif
 		WARN_ON(in_irq());
 		skb->destructor(skb);
 	}
-#ifdef CONFIG_NETFILTER
-	nf_conntrack_put(skb->nfct);
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	nf_conntrack_put(skb->nfct);
 	nf_conntrack_put_reasm(skb->nfct_reasm);
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	nf_bridge_put(skb->nf_bridge);
 #endif
-#endif
 /* XXX: IS this still necessary? - JHS */
 #ifdef CONFIG_NET_SCHED
 	skb->tc_index = 0;
@@ -396,9 +399,9 @@ #define C(x) n->x = skb->x
 	n->sk = NULL;
 	C(tstamp);
 	C(dev);
-	C(h);
-	C(nh);
-	C(mac);
+	C(transport_header);
+	C(network_header);
+	C(mac_header);
 	C(dst);
 	dst_clone(skb->dst);
 	C(sp);
@@ -422,19 +425,7 @@ #endif
 	C(protocol);
 	n->destructor = NULL;
 	C(mark);
-#ifdef CONFIG_NETFILTER
-	C(nfct);
-	nf_conntrack_get(skb->nfct);
-	C(nfctinfo);
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-	C(nfct_reasm);
-	nf_conntrack_get_reasm(skb->nfct_reasm);
-#endif
-#ifdef CONFIG_BRIDGE_NETFILTER
-	C(nf_bridge);
-	nf_bridge_get(skb->nf_bridge);
-#endif
-#endif /*CONFIG_NETFILTER*/
+	__nf_copy(n, skb);
 #ifdef CONFIG_NET_SCHED
 	C(tc_index);
 #ifdef CONFIG_NET_CLS_ACT
@@ -460,11 +451,12 @@ #endif
 
 static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
 	/*
 	 *	Shift between the two data areas in bytes
 	 */
 	unsigned long offset = new->data - old->data;
-
+#endif
 	new->sk		= NULL;
 	new->dev	= old->dev;
 	new->priority	= old->priority;
@@ -473,9 +465,15 @@ static void copy_skb_header(struct sk_bu
 #ifdef CONFIG_INET
 	new->sp		= secpath_get(old->sp);
 #endif
-	new->h.raw	= old->h.raw + offset;
-	new->nh.raw	= old->nh.raw + offset;
-	new->mac.raw	= old->mac.raw + offset;
+	new->transport_header = old->transport_header;
+	new->network_header   = old->network_header;
+	new->mac_header	      = old->mac_header;
+#ifndef NET_SKBUFF_DATA_USES_OFFSET
+	/* {transport,network,mac}_header are relative to skb->head */
+	new->transport_header += offset;
+	new->network_header   += offset;
+	new->mac_header	      += offset;
+#endif
 	memcpy(new->cb, old->cb, sizeof(old->cb));
 	new->local_df	= old->local_df;
 	new->fclone	= SKB_FCLONE_UNAVAILABLE;
@@ -483,22 +481,10 @@ #endif
 	new->tstamp	= old->tstamp;
 	new->destructor = NULL;
 	new->mark	= old->mark;
-#ifdef CONFIG_NETFILTER
-	new->nfct	= old->nfct;
-	nf_conntrack_get(old->nfct);
-	new->nfctinfo	= old->nfctinfo;
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-	new->nfct_reasm = old->nfct_reasm;
-	nf_conntrack_get_reasm(old->nfct_reasm);
-#endif
+	__nf_copy(new, old);
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	new->ipvs_property = old->ipvs_property;
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
-	new->nf_bridge	= old->nf_bridge;
-	nf_bridge_get(old->nf_bridge);
-#endif
-#endif
 #ifdef CONFIG_NET_SCHED
 #ifdef CONFIG_NET_CLS_ACT
 	new->tc_verd = old->tc_verd;
@@ -535,8 +521,12 @@ struct sk_buff *skb_copy(const struct sk
 	/*
 	 *	Allocate the copy buffer
 	 */
-	struct sk_buff *n = alloc_skb(skb->end - skb->head + skb->data_len,
-				      gfp_mask);
+	struct sk_buff *n;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	n = alloc_skb(skb->end + skb->data_len, gfp_mask);
+#else
+	n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
+#endif
 	if (!n)
 		return NULL;
 
@@ -573,8 +563,12 @@ struct sk_buff *pskb_copy(struct sk_buff
 	/*
 	 *	Allocate the copy buffer
 	 */
-	struct sk_buff *n = alloc_skb(skb->end - skb->head, gfp_mask);
-
+	struct sk_buff *n;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	n = alloc_skb(skb->end, gfp_mask);
+#else
+	n = alloc_skb(skb->end - skb->head, gfp_mask);
+#endif
 	if (!n)
 		goto out;
 
@@ -583,7 +577,7 @@ struct sk_buff *pskb_copy(struct sk_buff
 	/* Set the tail pointer and length */
 	skb_put(n, skb_headlen(skb));
 	/* Copy the bytes */
-	memcpy(n->data, skb->data, n->len);
+	skb_copy_from_linear_data(skb, n->data, n->len);
 	n->csum	     = skb->csum;
 	n->ip_summed = skb->ip_summed;
 
@@ -632,7 +626,11 @@ int pskb_expand_head(struct sk_buff *skb
 {
 	int i;
 	u8 *data;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	int size = nhead + skb->end + ntail;
+#else
 	int size = nhead + (skb->end - skb->head) + ntail;
+#endif
 	long off;
 
 	if (skb_shared(skb))
@@ -646,8 +644,14 @@ int pskb_expand_head(struct sk_buff *skb
 
 	/* Copy only real data... and, alas, header. This should be
 	 * optimized for the cases when header is void. */
-	memcpy(data + nhead, skb->head, skb->tail - skb->head);
-	memcpy(data + size, skb->end, sizeof(struct skb_shared_info));
+	memcpy(data + nhead, skb->head,
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+		skb->tail);
+#else
+		skb->tail - skb->head);
+#endif
+	memcpy(data + size, skb_end_pointer(skb),
+	       sizeof(struct skb_shared_info));
 
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 		get_page(skb_shinfo(skb)->frags[i].page);
@@ -660,12 +664,18 @@ int pskb_expand_head(struct sk_buff *skb
 	off = (data + nhead) - skb->head;
 
 	skb->head     = data;
-	skb->end      = data + size;
 	skb->data    += off;
-	skb->tail    += off;
-	skb->mac.raw += off;
-	skb->h.raw   += off;
-	skb->nh.raw  += off;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	skb->end      = size;
+	off           = nhead;
+#else
+	skb->end      = skb->head + size;
+#endif
+	/* {transport,network,mac}_header and tail are relative to skb->head */
+	skb->tail	      += off;
+	skb->transport_header += off;
+	skb->network_header   += off;
+	skb->mac_header	      += off;
 	skb->cloned   = 0;
 	skb->nohdr    = 0;
 	atomic_set(&skb_shinfo(skb)->dataref, 1);
@@ -726,7 +736,9 @@ struct sk_buff *skb_copy_expand(const st
 	 */
 	struct sk_buff *n = alloc_skb(newheadroom + skb->len + newtailroom,
 				      gfp_mask);
+	int oldheadroom = skb_headroom(skb);
 	int head_copy_len, head_copy_off;
+	int off = 0;
 
 	if (!n)
 		return NULL;
@@ -736,7 +748,7 @@ struct sk_buff *skb_copy_expand(const st
 	/* Set the tail pointer and length */
 	skb_put(n, skb->len);
 
-	head_copy_len = skb_headroom(skb);
+	head_copy_len = oldheadroom;
 	head_copy_off = 0;
 	if (newheadroom <= head_copy_len)
 		head_copy_len = newheadroom;
@@ -750,6 +762,13 @@ struct sk_buff *skb_copy_expand(const st
 
 	copy_skb_header(n, skb);
 
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+	off                  = newheadroom - oldheadroom;
+#endif
+	n->transport_header += off;
+	n->network_header   += off;
+	n->mac_header	    += off;
+
 	return n;
 }
 
@@ -877,7 +896,7 @@ done:
 	} else {
 		skb->len       = len;
 		skb->data_len  = 0;
-		skb->tail      = skb->data + len;
+		skb_set_tail_pointer(skb, len);
 	}
 
 	return 0;
@@ -922,7 +941,7 @@ unsigned char *__pskb_pull_tail(struct s
 			return NULL;
 	}
 
-	if (skb_copy_bits(skb, skb_headlen(skb), skb->tail, delta))
+	if (skb_copy_bits(skb, skb_headlen(skb), skb_tail_pointer(skb), delta))
 		BUG();
 
 	/* Optimization: no fragments, no reasons to preestimate
@@ -1018,7 +1037,7 @@ pull_pages:
 	skb->tail     += delta;
 	skb->data_len -= delta;
 
-	return skb->tail;
+	return skb_tail_pointer(skb);
 }
 
 /* Copy some data bits from skb to kernel buffer. */
@@ -1035,7 +1054,7 @@ int skb_copy_bits(const struct sk_buff *
 	if ((copy = start - offset) > 0) {
 		if (copy > len)
 			copy = len;
-		memcpy(to, skb->data + offset, copy);
+		skb_copy_from_linear_data_offset(skb, offset, to, copy);
 		if ((len -= copy) == 0)
 			return 0;
 		offset += copy;
@@ -1110,7 +1129,7 @@ fault:
  *	traversing fragment lists and such.
  */
 
-int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len)
+int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
 {
 	int i, copy;
 	int start = skb_headlen(skb);
@@ -1121,7 +1140,7 @@ int skb_store_bits(const struct sk_buff 
 	if ((copy = start - offset) > 0) {
 		if (copy > len)
 			copy = len;
-		memcpy(skb->data + offset, from, copy);
+		skb_copy_to_linear_data_offset(skb, offset, from, copy);
 		if ((len -= copy) == 0)
 			return 0;
 		offset += copy;
@@ -1348,13 +1367,13 @@ void skb_copy_and_csum_dev(const struct 
 	long csstart;
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL)
-		csstart = skb->h.raw - skb->data;
+		csstart = skb->csum_start - skb_headroom(skb);
 	else
 		csstart = skb_headlen(skb);
 
 	BUG_ON(csstart > skb_headlen(skb));
 
-	memcpy(to, skb->data, csstart);
+	skb_copy_from_linear_data(skb, to, csstart);
 
 	csum = 0;
 	if (csstart != skb->len)
@@ -1522,27 +1541,14 @@ void skb_insert(struct sk_buff *old, str
 	spin_unlock_irqrestore(&list->lock, flags);
 }
 
-#if 0
-/*
- * 	Tune the memory allocator for a new MTU size.
- */
-void skb_add_mtu(int mtu)
-{
-	/* Must match allocation in alloc_skb */
-	mtu = SKB_DATA_ALIGN(mtu) + sizeof(struct skb_shared_info);
-
-	kmem_add_cache_size(mtu);
-}
-#endif
-
 static inline void skb_split_inside_header(struct sk_buff *skb,
 					   struct sk_buff* skb1,
 					   const u32 len, const int pos)
 {
 	int i;
 
-	memcpy(skb_put(skb1, pos - len), skb->data + len, pos - len);
-
+	skb_copy_from_linear_data_offset(skb, len, skb_put(skb1, pos - len),
+					 pos - len);
 	/* And move data appendix as is. */
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 		skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i];
@@ -1553,7 +1559,7 @@ static inline void skb_split_inside_head
 	skb1->len		   += skb1->data_len;
 	skb->data_len		   = 0;
 	skb->len		   = len;
-	skb->tail		   = skb->data + len;
+	skb_set_tail_pointer(skb, len);
 }
 
 static inline void skb_split_no_header(struct sk_buff *skb,
@@ -1878,7 +1884,7 @@ struct sk_buff *skb_segment(struct sk_bu
 	struct sk_buff *segs = NULL;
 	struct sk_buff *tail = NULL;
 	unsigned int mss = skb_shinfo(skb)->gso_size;
-	unsigned int doffset = skb->data - skb->mac.raw;
+	unsigned int doffset = skb->data - skb_mac_header(skb);
 	unsigned int offset = doffset;
 	unsigned int headroom;
 	unsigned int len;
@@ -1928,11 +1934,12 @@ struct sk_buff *skb_segment(struct sk_bu
 		nskb->mac_len = skb->mac_len;
 
 		skb_reserve(nskb, headroom);
-		nskb->mac.raw = nskb->data;
-		nskb->nh.raw = nskb->data + skb->mac_len;
-		nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
-		memcpy(skb_put(nskb, doffset), skb->data, doffset);
-
+		skb_reset_mac_header(nskb);
+		skb_set_network_header(nskb, skb->mac_len);
+		nskb->transport_header = (nskb->network_header +
+					  skb_network_header_len(skb));
+		skb_copy_from_linear_data(skb, skb_put(nskb, doffset),
+					  doffset);
 		if (!sg) {
 			nskb->csum = skb_copy_and_csum_bits(skb, offset,
 							    skb_put(nskb, len),
@@ -1945,7 +1952,8 @@ struct sk_buff *skb_segment(struct sk_bu
 
 		nskb->ip_summed = CHECKSUM_PARTIAL;
 		nskb->csum = skb->csum;
-		memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
+		skb_copy_from_linear_data_offset(skb, offset,
+						 skb_put(nskb, hsize), hsize);
 
 		while (pos < offset + len) {
 			BUG_ON(i >= nfrags);
@@ -2005,6 +2013,190 @@ void __init skb_init(void)
 						NULL, NULL);
 }
 
+/**
+ *	skb_to_sgvec - Fill a scatter-gather list from a socket buffer
+ *	@skb: Socket buffer containing the buffers to be mapped
+ *	@sg: The scatter-gather list to map into
+ *	@offset: The offset into the buffer's contents to start mapping
+ *	@len: Length of buffer space to be mapped
+ *
+ *	Fill the specified scatter-gather list with mappings/pointers into a
+ *	region of the buffer space attached to a socket buffer.
+ */
+int
+skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+	int start = skb_headlen(skb);
+	int i, copy = start - offset;
+	int elt = 0;
+
+	if (copy > 0) {
+		if (copy > len)
+			copy = len;
+		sg[elt].page = virt_to_page(skb->data + offset);
+		sg[elt].offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
+		sg[elt].length = copy;
+		elt++;
+		if ((len -= copy) == 0)
+			return elt;
+		offset += copy;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end - offset) > 0) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			if (copy > len)
+				copy = len;
+			sg[elt].page = frag->page;
+			sg[elt].offset = frag->page_offset+offset-start;
+			sg[elt].length = copy;
+			elt++;
+			if (!(len -= copy))
+				return elt;
+			offset += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+		for (; list; list = list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
+			if ((copy = end - offset) > 0) {
+				if (copy > len)
+					copy = len;
+				elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
+				if ((len -= copy) == 0)
+					return elt;
+				offset += copy;
+			}
+			start = end;
+		}
+	}
+	BUG_ON(len);
+	return elt;
+}
+
+/**
+ *	skb_cow_data - Check that a socket buffer's data buffers are writable
+ *	@skb: The socket buffer to check.
+ *	@tailbits: Amount of trailing space to be added
+ *	@trailer: Returned pointer to the skb where the @tailbits space begins
+ *
+ *	Make sure that the data buffers attached to a socket buffer are
+ *	writable. If they are not, private copies are made of the data buffers
+ *	and the socket buffer is set to use these instead.
+ *
+ *	If @tailbits is given, make sure that there is space to write @tailbits
+ *	bytes of data beyond current end of socket buffer.  @trailer will be
+ *	set to point to the skb in which this space begins.
+ *
+ *	The number of scatterlist elements required to completely map the
+ *	COW'd and extended socket buffer will be returned.
+ */
+int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
+{
+	int copyflag;
+	int elt;
+	struct sk_buff *skb1, **skb_p;
+
+	/* If skb is cloned or its head is paged, reallocate
+	 * head pulling out all the pages (pages are considered not writable
+	 * at the moment even if they are anonymous).
+	 */
+	if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) &&
+	    __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL)
+		return -ENOMEM;
+
+	/* Easy case. Most of packets will go this way. */
+	if (!skb_shinfo(skb)->frag_list) {
+		/* A little of trouble, not enough of space for trailer.
+		 * This should not happen, when stack is tuned to generate
+		 * good frames. OK, on miss we reallocate and reserve even more
+		 * space, 128 bytes is fair. */
+
+		if (skb_tailroom(skb) < tailbits &&
+		    pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC))
+			return -ENOMEM;
+
+		/* Voila! */
+		*trailer = skb;
+		return 1;
+	}
+
+	/* Misery. We are in troubles, going to mincer fragments... */
+
+	elt = 1;
+	skb_p = &skb_shinfo(skb)->frag_list;
+	copyflag = 0;
+
+	while ((skb1 = *skb_p) != NULL) {
+		int ntail = 0;
+
+		/* The fragment is partially pulled by someone,
+		 * this can happen on input. Copy it and everything
+		 * after it. */
+
+		if (skb_shared(skb1))
+			copyflag = 1;
+
+		/* If the skb is the last, worry about trailer. */
+
+		if (skb1->next == NULL && tailbits) {
+			if (skb_shinfo(skb1)->nr_frags ||
+			    skb_shinfo(skb1)->frag_list ||
+			    skb_tailroom(skb1) < tailbits)
+				ntail = tailbits + 128;
+		}
+
+		if (copyflag ||
+		    skb_cloned(skb1) ||
+		    ntail ||
+		    skb_shinfo(skb1)->nr_frags ||
+		    skb_shinfo(skb1)->frag_list) {
+			struct sk_buff *skb2;
+
+			/* Fuck, we are miserable poor guys... */
+			if (ntail == 0)
+				skb2 = skb_copy(skb1, GFP_ATOMIC);
+			else
+				skb2 = skb_copy_expand(skb1,
+						       skb_headroom(skb1),
+						       ntail,
+						       GFP_ATOMIC);
+			if (unlikely(skb2 == NULL))
+				return -ENOMEM;
+
+			if (skb1->sk)
+				skb_set_owner_w(skb2, skb1->sk);
+
+			/* Looking around. Are we still alive?
+			 * OK, link new skb, drop old one */
+
+			skb2->next = skb1->next;
+			*skb_p = skb2;
+			kfree_skb(skb1);
+			skb1 = skb2;
+		}
+		elt++;
+		*trailer = skb1;
+		skb_p = &skb1->next;
+	}
+
+	return elt;
+}
+
 EXPORT_SYMBOL(___pskb_trim);
 EXPORT_SYMBOL(__kfree_skb);
 EXPORT_SYMBOL(kfree_skb);
@@ -2039,3 +2231,6 @@ EXPORT_SYMBOL(skb_seq_read);
 EXPORT_SYMBOL(skb_abort_seq_read);
 EXPORT_SYMBOL(skb_find_text);
 EXPORT_SYMBOL(skb_append_datato_frags);
+
+EXPORT_SYMBOL_GPL(skb_to_sgvec);
+EXPORT_SYMBOL_GPL(skb_cow_data);
diff --git a/net/core/sock.c b/net/core/sock.c
index 27c4f62..22183c2 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -154,7 +154,8 @@ static const char *af_family_key_strings
   "sk_lock-21"       , "sk_lock-AF_SNA"      , "sk_lock-AF_IRDA"     ,
   "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE"  , "sk_lock-AF_LLC"      ,
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-29"          ,
-  "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-AF_MAX"
+  "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
+  "sk_lock-AF_RXRPC" , "sk_lock-AF_MAX"
 };
 static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
@@ -167,7 +168,8 @@ static const char *af_family_slock_key_s
   "slock-21"       , "slock-AF_SNA"      , "slock-AF_IRDA"     ,
   "slock-AF_PPPOX" , "slock-AF_WANPIPE"  , "slock-AF_LLC"      ,
   "slock-27"       , "slock-28"          , "slock-29"          ,
-  "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_MAX"
+  "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
+  "slock-AF_RXRPC" , "slock-AF_MAX"
 };
 #endif
 
@@ -361,8 +363,8 @@ #ifdef SO_DONTLINGER		/* Compatibility i
 	}
 #endif
 
-	if(optlen<sizeof(int))
-		return(-EINVAL);
+	if (optlen < sizeof(int))
+		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
 		return -EFAULT;
@@ -371,265 +373,270 @@ #endif
 
 	lock_sock(sk);
 
-	switch(optname)
-	{
-		case SO_DEBUG:
-			if(val && !capable(CAP_NET_ADMIN))
-			{
-				ret = -EACCES;
-			}
-			else if (valbool)
-				sock_set_flag(sk, SOCK_DBG);
-			else
-				sock_reset_flag(sk, SOCK_DBG);
-			break;
-		case SO_REUSEADDR:
-			sk->sk_reuse = valbool;
-			break;
-		case SO_TYPE:
-		case SO_ERROR:
-			ret = -ENOPROTOOPT;
-			break;
-		case SO_DONTROUTE:
-			if (valbool)
-				sock_set_flag(sk, SOCK_LOCALROUTE);
-			else
-				sock_reset_flag(sk, SOCK_LOCALROUTE);
-			break;
-		case SO_BROADCAST:
-			sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
-			break;
-		case SO_SNDBUF:
-			/* Don't error on this BSD doesn't and if you think
-			   about it this is right. Otherwise apps have to
-			   play 'guess the biggest size' games. RCVBUF/SNDBUF
-			   are treated in BSD as hints */
-
-			if (val > sysctl_wmem_max)
-				val = sysctl_wmem_max;
+	switch(optname) {
+	case SO_DEBUG:
+		if (val && !capable(CAP_NET_ADMIN)) {
+			ret = -EACCES;
+		}
+		else if (valbool)
+			sock_set_flag(sk, SOCK_DBG);
+		else
+			sock_reset_flag(sk, SOCK_DBG);
+		break;
+	case SO_REUSEADDR:
+		sk->sk_reuse = valbool;
+		break;
+	case SO_TYPE:
+	case SO_ERROR:
+		ret = -ENOPROTOOPT;
+		break;
+	case SO_DONTROUTE:
+		if (valbool)
+			sock_set_flag(sk, SOCK_LOCALROUTE);
+		else
+			sock_reset_flag(sk, SOCK_LOCALROUTE);
+		break;
+	case SO_BROADCAST:
+		sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
+		break;
+	case SO_SNDBUF:
+		/* Don't error on this BSD doesn't and if you think
+		   about it this is right. Otherwise apps have to
+		   play 'guess the biggest size' games. RCVBUF/SNDBUF
+		   are treated in BSD as hints */
+
+		if (val > sysctl_wmem_max)
+			val = sysctl_wmem_max;
 set_sndbuf:
-			sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-			if ((val * 2) < SOCK_MIN_SNDBUF)
-				sk->sk_sndbuf = SOCK_MIN_SNDBUF;
-			else
-				sk->sk_sndbuf = val * 2;
+		sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+		if ((val * 2) < SOCK_MIN_SNDBUF)
+			sk->sk_sndbuf = SOCK_MIN_SNDBUF;
+		else
+			sk->sk_sndbuf = val * 2;
 
-			/*
-			 *	Wake up sending tasks if we
-			 *	upped the value.
-			 */
-			sk->sk_write_space(sk);
-			break;
+		/*
+		 *	Wake up sending tasks if we
+		 *	upped the value.
+		 */
+		sk->sk_write_space(sk);
+		break;
 
-		case SO_SNDBUFFORCE:
-			if (!capable(CAP_NET_ADMIN)) {
-				ret = -EPERM;
-				break;
-			}
-			goto set_sndbuf;
+	case SO_SNDBUFFORCE:
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			break;
+		}
+		goto set_sndbuf;
 
-		case SO_RCVBUF:
-			/* Don't error on this BSD doesn't and if you think
-			   about it this is right. Otherwise apps have to
-			   play 'guess the biggest size' games. RCVBUF/SNDBUF
-			   are treated in BSD as hints */
+	case SO_RCVBUF:
+		/* Don't error on this BSD doesn't and if you think
+		   about it this is right. Otherwise apps have to
+		   play 'guess the biggest size' games. RCVBUF/SNDBUF
+		   are treated in BSD as hints */
 
-			if (val > sysctl_rmem_max)
-				val = sysctl_rmem_max;
+		if (val > sysctl_rmem_max)
+			val = sysctl_rmem_max;
 set_rcvbuf:
-			sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
-			/*
-			 * We double it on the way in to account for
-			 * "struct sk_buff" etc. overhead.   Applications
-			 * assume that the SO_RCVBUF setting they make will
-			 * allow that much actual data to be received on that
-			 * socket.
-			 *
-			 * Applications are unaware that "struct sk_buff" and
-			 * other overheads allocate from the receive buffer
-			 * during socket buffer allocation.
-			 *
-			 * And after considering the possible alternatives,
-			 * returning the value we actually used in getsockopt
-			 * is the most desirable behavior.
-			 */
-			if ((val * 2) < SOCK_MIN_RCVBUF)
-				sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
-			else
-				sk->sk_rcvbuf = val * 2;
+		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+		/*
+		 * We double it on the way in to account for
+		 * "struct sk_buff" etc. overhead.   Applications
+		 * assume that the SO_RCVBUF setting they make will
+		 * allow that much actual data to be received on that
+		 * socket.
+		 *
+		 * Applications are unaware that "struct sk_buff" and
+		 * other overheads allocate from the receive buffer
+		 * during socket buffer allocation.
+		 *
+		 * And after considering the possible alternatives,
+		 * returning the value we actually used in getsockopt
+		 * is the most desirable behavior.
+		 */
+		if ((val * 2) < SOCK_MIN_RCVBUF)
+			sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
+		else
+			sk->sk_rcvbuf = val * 2;
+		break;
+
+	case SO_RCVBUFFORCE:
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
 			break;
+		}
+		goto set_rcvbuf;
 
-		case SO_RCVBUFFORCE:
-			if (!capable(CAP_NET_ADMIN)) {
-				ret = -EPERM;
-				break;
-			}
-			goto set_rcvbuf;
-
-		case SO_KEEPALIVE:
+	case SO_KEEPALIVE:
 #ifdef CONFIG_INET
-			if (sk->sk_protocol == IPPROTO_TCP)
-				tcp_set_keepalive(sk, valbool);
+		if (sk->sk_protocol == IPPROTO_TCP)
+			tcp_set_keepalive(sk, valbool);
 #endif
-			sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
-			break;
-
-		case SO_OOBINLINE:
-			sock_valbool_flag(sk, SOCK_URGINLINE, valbool);
+		sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
+		break;
+
+	case SO_OOBINLINE:
+		sock_valbool_flag(sk, SOCK_URGINLINE, valbool);
+		break;
+
+	case SO_NO_CHECK:
+		sk->sk_no_check = valbool;
+		break;
+
+	case SO_PRIORITY:
+		if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN))
+			sk->sk_priority = val;
+		else
+			ret = -EPERM;
+		break;
+
+	case SO_LINGER:
+		if (optlen < sizeof(ling)) {
+			ret = -EINVAL;	/* 1003.1g */
 			break;
-
-		case SO_NO_CHECK:
-			sk->sk_no_check = valbool;
-			break;
-
-		case SO_PRIORITY:
-			if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN))
-				sk->sk_priority = val;
-			else
-				ret = -EPERM;
+		}
+		if (copy_from_user(&ling,optval,sizeof(ling))) {
+			ret = -EFAULT;
 			break;
-
-		case SO_LINGER:
-			if(optlen<sizeof(ling)) {
-				ret = -EINVAL;	/* 1003.1g */
-				break;
-			}
-			if (copy_from_user(&ling,optval,sizeof(ling))) {
-				ret = -EFAULT;
-				break;
-			}
-			if (!ling.l_onoff)
-				sock_reset_flag(sk, SOCK_LINGER);
-			else {
+		}
+		if (!ling.l_onoff)
+			sock_reset_flag(sk, SOCK_LINGER);
+		else {
 #if (BITS_PER_LONG == 32)
-				if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
-					sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
-				else
+			if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
+				sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT;
+			else
 #endif
-					sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
-				sock_set_flag(sk, SOCK_LINGER);
-			}
-			break;
-
-		case SO_BSDCOMPAT:
-			sock_warn_obsolete_bsdism("setsockopt");
-			break;
-
-		case SO_PASSCRED:
-			if (valbool)
-				set_bit(SOCK_PASSCRED, &sock->flags);
+				sk->sk_lingertime = (unsigned int)ling.l_linger * HZ;
+			sock_set_flag(sk, SOCK_LINGER);
+		}
+		break;
+
+	case SO_BSDCOMPAT:
+		sock_warn_obsolete_bsdism("setsockopt");
+		break;
+
+	case SO_PASSCRED:
+		if (valbool)
+			set_bit(SOCK_PASSCRED, &sock->flags);
+		else
+			clear_bit(SOCK_PASSCRED, &sock->flags);
+		break;
+
+	case SO_TIMESTAMP:
+	case SO_TIMESTAMPNS:
+		if (valbool)  {
+			if (optname == SO_TIMESTAMP)
+				sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
 			else
-				clear_bit(SOCK_PASSCRED, &sock->flags);
-			break;
+				sock_set_flag(sk, SOCK_RCVTSTAMPNS);
+			sock_set_flag(sk, SOCK_RCVTSTAMP);
+			sock_enable_timestamp(sk);
+		} else {
+			sock_reset_flag(sk, SOCK_RCVTSTAMP);
+			sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
+		}
+		break;
 
-		case SO_TIMESTAMP:
-			if (valbool)  {
-				sock_set_flag(sk, SOCK_RCVTSTAMP);
-				sock_enable_timestamp(sk);
-			} else
-				sock_reset_flag(sk, SOCK_RCVTSTAMP);
-			break;
+	case SO_RCVLOWAT:
+		if (val < 0)
+			val = INT_MAX;
+		sk->sk_rcvlowat = val ? : 1;
+		break;
 
-		case SO_RCVLOWAT:
-			if (val < 0)
-				val = INT_MAX;
-			sk->sk_rcvlowat = val ? : 1;
-			break;
+	case SO_RCVTIMEO:
+		ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen);
+		break;
 
-		case SO_RCVTIMEO:
-			ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen);
-			break;
+	case SO_SNDTIMEO:
+		ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen);
+		break;
 
-		case SO_SNDTIMEO:
-			ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen);
+#ifdef CONFIG_NETDEVICES
+	case SO_BINDTODEVICE:
+	{
+		char devname[IFNAMSIZ];
+
+		/* Sorry... */
+		if (!capable(CAP_NET_RAW)) {
+			ret = -EPERM;
 			break;
+		}
 
-#ifdef CONFIG_NETDEVICES
-		case SO_BINDTODEVICE:
-		{
-			char devname[IFNAMSIZ];
+		/* Bind this socket to a particular device like "eth0",
+		 * as specified in the passed interface name. If the
+		 * name is "" or the option length is zero the socket
+		 * is not bound.
+		 */
 
-			/* Sorry... */
-			if (!capable(CAP_NET_RAW)) {
-				ret = -EPERM;
+		if (!valbool) {
+			sk->sk_bound_dev_if = 0;
+		} else {
+			if (optlen > IFNAMSIZ - 1)
+				optlen = IFNAMSIZ - 1;
+			memset(devname, 0, sizeof(devname));
+			if (copy_from_user(devname, optval, optlen)) {
+				ret = -EFAULT;
 				break;
 			}
 
-			/* Bind this socket to a particular device like "eth0",
-			 * as specified in the passed interface name. If the
-			 * name is "" or the option length is zero the socket
-			 * is not bound.
-			 */
+			/* Remove any cached route for this socket. */
+			sk_dst_reset(sk);
 
-			if (!valbool) {
+			if (devname[0] == '\0') {
 				sk->sk_bound_dev_if = 0;
 			} else {
-				if (optlen > IFNAMSIZ - 1)
-					optlen = IFNAMSIZ - 1;
-				memset(devname, 0, sizeof(devname));
-				if (copy_from_user(devname, optval, optlen)) {
-					ret = -EFAULT;
+				struct net_device *dev = dev_get_by_name(devname);
+				if (!dev) {
+					ret = -ENODEV;
 					break;
 				}
-
-				/* Remove any cached route for this socket. */
-				sk_dst_reset(sk);
-
-				if (devname[0] == '\0') {
-					sk->sk_bound_dev_if = 0;
-				} else {
-					struct net_device *dev = dev_get_by_name(devname);
-					if (!dev) {
-						ret = -ENODEV;
-						break;
-					}
-					sk->sk_bound_dev_if = dev->ifindex;
-					dev_put(dev);
-				}
+				sk->sk_bound_dev_if = dev->ifindex;
+				dev_put(dev);
 			}
-			break;
 		}
+		break;
+	}
 #endif
 
 
-		case SO_ATTACH_FILTER:
-			ret = -EINVAL;
-			if (optlen == sizeof(struct sock_fprog)) {
-				struct sock_fprog fprog;
+	case SO_ATTACH_FILTER:
+		ret = -EINVAL;
+		if (optlen == sizeof(struct sock_fprog)) {
+			struct sock_fprog fprog;
 
-				ret = -EFAULT;
-				if (copy_from_user(&fprog, optval, sizeof(fprog)))
-					break;
-
-				ret = sk_attach_filter(&fprog, sk);
-			}
-			break;
-
-		case SO_DETACH_FILTER:
-			rcu_read_lock_bh();
-			filter = rcu_dereference(sk->sk_filter);
-			if (filter) {
-				rcu_assign_pointer(sk->sk_filter, NULL);
-				sk_filter_release(sk, filter);
-				rcu_read_unlock_bh();
+			ret = -EFAULT;
+			if (copy_from_user(&fprog, optval, sizeof(fprog)))
 				break;
-			}
+
+			ret = sk_attach_filter(&fprog, sk);
+		}
+		break;
+
+	case SO_DETACH_FILTER:
+		rcu_read_lock_bh();
+		filter = rcu_dereference(sk->sk_filter);
+		if (filter) {
+			rcu_assign_pointer(sk->sk_filter, NULL);
+			sk_filter_release(sk, filter);
 			rcu_read_unlock_bh();
-			ret = -ENONET;
 			break;
+		}
+		rcu_read_unlock_bh();
+		ret = -ENONET;
+		break;
 
-		case SO_PASSSEC:
-			if (valbool)
-				set_bit(SOCK_PASSSEC, &sock->flags);
-			else
-				clear_bit(SOCK_PASSSEC, &sock->flags);
-			break;
+	case SO_PASSSEC:
+		if (valbool)
+			set_bit(SOCK_PASSSEC, &sock->flags);
+		else
+			clear_bit(SOCK_PASSSEC, &sock->flags);
+		break;
 
 		/* We implement the SO_SNDLOWAT etc to
 		   not be settable (1003.1g 5.3) */
-		default:
-			ret = -ENOPROTOOPT;
-			break;
+	default:
+		ret = -ENOPROTOOPT;
+		break;
 	}
 	release_sock(sk);
 	return ret;
@@ -641,8 +648,7 @@ int sock_getsockopt(struct socket *sock,
 {
 	struct sock *sk = sock->sk;
 
-	union
-	{
+	union {
 		int val;
 		struct linger ling;
 		struct timeval tm;
@@ -651,148 +657,153 @@ int sock_getsockopt(struct socket *sock,
 	unsigned int lv = sizeof(int);
 	int len;
 
-	if(get_user(len,optlen))
+	if (get_user(len, optlen))
 		return -EFAULT;
-	if(len < 0)
+	if (len < 0)
 		return -EINVAL;
 
-	switch(optname)
-	{
-		case SO_DEBUG:
-			v.val = sock_flag(sk, SOCK_DBG);
-			break;
-
-		case SO_DONTROUTE:
-			v.val = sock_flag(sk, SOCK_LOCALROUTE);
-			break;
-
-		case SO_BROADCAST:
-			v.val = !!sock_flag(sk, SOCK_BROADCAST);
-			break;
-
-		case SO_SNDBUF:
-			v.val = sk->sk_sndbuf;
-			break;
-
-		case SO_RCVBUF:
-			v.val = sk->sk_rcvbuf;
-			break;
-
-		case SO_REUSEADDR:
-			v.val = sk->sk_reuse;
-			break;
-
-		case SO_KEEPALIVE:
-			v.val = !!sock_flag(sk, SOCK_KEEPOPEN);
-			break;
-
-		case SO_TYPE:
-			v.val = sk->sk_type;
-			break;
-
-		case SO_ERROR:
-			v.val = -sock_error(sk);
-			if(v.val==0)
-				v.val = xchg(&sk->sk_err_soft, 0);
-			break;
-
-		case SO_OOBINLINE:
-			v.val = !!sock_flag(sk, SOCK_URGINLINE);
-			break;
-
-		case SO_NO_CHECK:
-			v.val = sk->sk_no_check;
-			break;
-
-		case SO_PRIORITY:
-			v.val = sk->sk_priority;
-			break;
-
-		case SO_LINGER:
-			lv		= sizeof(v.ling);
-			v.ling.l_onoff	= !!sock_flag(sk, SOCK_LINGER);
-			v.ling.l_linger	= sk->sk_lingertime / HZ;
-			break;
-
-		case SO_BSDCOMPAT:
-			sock_warn_obsolete_bsdism("getsockopt");
-			break;
-
-		case SO_TIMESTAMP:
-			v.val = sock_flag(sk, SOCK_RCVTSTAMP);
-			break;
+	switch(optname) {
+	case SO_DEBUG:
+		v.val = sock_flag(sk, SOCK_DBG);
+		break;
+
+	case SO_DONTROUTE:
+		v.val = sock_flag(sk, SOCK_LOCALROUTE);
+		break;
+
+	case SO_BROADCAST:
+		v.val = !!sock_flag(sk, SOCK_BROADCAST);
+		break;
+
+	case SO_SNDBUF:
+		v.val = sk->sk_sndbuf;
+		break;
+
+	case SO_RCVBUF:
+		v.val = sk->sk_rcvbuf;
+		break;
+
+	case SO_REUSEADDR:
+		v.val = sk->sk_reuse;
+		break;
+
+	case SO_KEEPALIVE:
+		v.val = !!sock_flag(sk, SOCK_KEEPOPEN);
+		break;
+
+	case SO_TYPE:
+		v.val = sk->sk_type;
+		break;
+
+	case SO_ERROR:
+		v.val = -sock_error(sk);
+		if (v.val==0)
+			v.val = xchg(&sk->sk_err_soft, 0);
+		break;
+
+	case SO_OOBINLINE:
+		v.val = !!sock_flag(sk, SOCK_URGINLINE);
+		break;
+
+	case SO_NO_CHECK:
+		v.val = sk->sk_no_check;
+		break;
+
+	case SO_PRIORITY:
+		v.val = sk->sk_priority;
+		break;
+
+	case SO_LINGER:
+		lv		= sizeof(v.ling);
+		v.ling.l_onoff	= !!sock_flag(sk, SOCK_LINGER);
+		v.ling.l_linger	= sk->sk_lingertime / HZ;
+		break;
+
+	case SO_BSDCOMPAT:
+		sock_warn_obsolete_bsdism("getsockopt");
+		break;
+
+	case SO_TIMESTAMP:
+		v.val = sock_flag(sk, SOCK_RCVTSTAMP) &&
+				!sock_flag(sk, SOCK_RCVTSTAMPNS);
+		break;
+
+	case SO_TIMESTAMPNS:
+		v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
+		break;
+
+	case SO_RCVTIMEO:
+		lv=sizeof(struct timeval);
+		if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
+			v.tm.tv_sec = 0;
+			v.tm.tv_usec = 0;
+		} else {
+			v.tm.tv_sec = sk->sk_rcvtimeo / HZ;
+			v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000000) / HZ;
+		}
+		break;
+
+	case SO_SNDTIMEO:
+		lv=sizeof(struct timeval);
+		if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {
+			v.tm.tv_sec = 0;
+			v.tm.tv_usec = 0;
+		} else {
+			v.tm.tv_sec = sk->sk_sndtimeo / HZ;
+			v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000000) / HZ;
+		}
+		break;
 
-		case SO_RCVTIMEO:
-			lv=sizeof(struct timeval);
-			if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
-				v.tm.tv_sec = 0;
-				v.tm.tv_usec = 0;
-			} else {
-				v.tm.tv_sec = sk->sk_rcvtimeo / HZ;
-				v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000000) / HZ;
-			}
-			break;
+	case SO_RCVLOWAT:
+		v.val = sk->sk_rcvlowat;
+		break;
 
-		case SO_SNDTIMEO:
-			lv=sizeof(struct timeval);
-			if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {
-				v.tm.tv_sec = 0;
-				v.tm.tv_usec = 0;
-			} else {
-				v.tm.tv_sec = sk->sk_sndtimeo / HZ;
-				v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000000) / HZ;
-			}
-			break;
+	case SO_SNDLOWAT:
+		v.val=1;
+		break;
 
-		case SO_RCVLOWAT:
-			v.val = sk->sk_rcvlowat;
-			break;
+	case SO_PASSCRED:
+		v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
+		break;
 
-		case SO_SNDLOWAT:
-			v.val=1;
-			break;
+	case SO_PEERCRED:
+		if (len > sizeof(sk->sk_peercred))
+			len = sizeof(sk->sk_peercred);
+		if (copy_to_user(optval, &sk->sk_peercred, len))
+			return -EFAULT;
+		goto lenout;
 
-		case SO_PASSCRED:
-			v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
-			break;
-
-		case SO_PEERCRED:
-			if (len > sizeof(sk->sk_peercred))
-				len = sizeof(sk->sk_peercred);
-			if (copy_to_user(optval, &sk->sk_peercred, len))
-				return -EFAULT;
-			goto lenout;
-
-		case SO_PEERNAME:
-		{
-			char address[128];
-
-			if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2))
-				return -ENOTCONN;
-			if (lv < len)
-				return -EINVAL;
-			if (copy_to_user(optval, address, len))
-				return -EFAULT;
-			goto lenout;
-		}
+	case SO_PEERNAME:
+	{
+		char address[128];
+
+		if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2))
+			return -ENOTCONN;
+		if (lv < len)
+			return -EINVAL;
+		if (copy_to_user(optval, address, len))
+			return -EFAULT;
+		goto lenout;
+	}
 
-		/* Dubious BSD thing... Probably nobody even uses it, but
-		 * the UNIX standard wants it for whatever reason... -DaveM
-		 */
-		case SO_ACCEPTCONN:
-			v.val = sk->sk_state == TCP_LISTEN;
-			break;
+	/* Dubious BSD thing... Probably nobody even uses it, but
+	 * the UNIX standard wants it for whatever reason... -DaveM
+	 */
+	case SO_ACCEPTCONN:
+		v.val = sk->sk_state == TCP_LISTEN;
+		break;
 
-		case SO_PASSSEC:
-			v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
-			break;
+	case SO_PASSSEC:
+		v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+		break;
 
-		case SO_PEERSEC:
-			return security_socket_getpeersec_stream(sock, optval, optlen, len);
+	case SO_PEERSEC:
+		return security_socket_getpeersec_stream(sock, optval, optlen, len);
 
-		default:
-			return(-ENOPROTOOPT);
+	default:
+		return -ENOPROTOOPT;
 	}
+
 	if (len > lv)
 		len = lv;
 	if (copy_to_user(optval, &v, len))
@@ -904,6 +915,7 @@ struct sock *sk_clone(const struct sock 
 		sk_node_init(&newsk->sk_node);
 		sock_lock_init(newsk);
 		bh_lock_sock(newsk);
+		newsk->sk_backlog.head	= newsk->sk_backlog.tail = NULL;
 
 		atomic_set(&newsk->sk_rmem_alloc, 0);
 		atomic_set(&newsk->sk_wmem_alloc, 0);
@@ -923,7 +935,6 @@ #endif
 		newsk->sk_wmem_queued	= 0;
 		newsk->sk_forward_alloc = 0;
 		newsk->sk_send_head	= NULL;
-		newsk->sk_backlog.head	= newsk->sk_backlog.tail = NULL;
 		newsk->sk_userlocks	= sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;
 
 		sock_reset_flag(newsk, SOCK_DONE);
@@ -970,6 +981,21 @@ out:
 
 EXPORT_SYMBOL_GPL(sk_clone);
 
+void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
+{
+	__sk_dst_set(sk, dst);
+	sk->sk_route_caps = dst->dev->features;
+	if (sk->sk_route_caps & NETIF_F_GSO)
+		sk->sk_route_caps |= NETIF_F_GSO_MASK;
+	if (sk_can_gso(sk)) {
+		if (dst->header_len)
+			sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+		else
+			sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
+	}
+}
+EXPORT_SYMBOL_GPL(sk_setup_caps);
+
 void __init sk_init(void)
 {
 	if (num_physpages <= 4096) {
@@ -1220,13 +1246,13 @@ static void __lock_sock(struct sock *sk)
 {
 	DEFINE_WAIT(wait);
 
-	for(;;) {
+	for (;;) {
 		prepare_to_wait_exclusive(&sk->sk_lock.wq, &wait,
 					TASK_UNINTERRUPTIBLE);
 		spin_unlock_bh(&sk->sk_lock.slock);
 		schedule();
 		spin_lock_bh(&sk->sk_lock.slock);
-		if(!sock_owned_by_user(sk))
+		if (!sock_owned_by_user(sk))
 			break;
 	}
 	finish_wait(&sk->sk_lock.wq, &wait);
@@ -1258,7 +1284,7 @@ static void __release_sock(struct sock *
 		} while (skb != NULL);
 
 		bh_lock_sock(sk);
-	} while((skb = sk->sk_backlog.head) != NULL);
+	} while ((skb = sk->sk_backlog.head) != NULL);
 }
 
 /**
@@ -1420,7 +1446,7 @@ static void sock_def_write_space(struct 
 	/* Do not wake up a writer until he can make "significant"
 	 * progress.  --DaveM
 	 */
-	if((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
+	if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
 		if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
 			wake_up_interruptible(sk->sk_sleep);
 
@@ -1482,8 +1508,7 @@ #endif
 
 	sock_set_flag(sk, SOCK_ZAPPED);
 
-	if(sock)
-	{
+	if (sock) {
 		sk->sk_type	=	sock->type;
 		sk->sk_sleep	=	&sock->wait;
 		sock->sk	=	sk;
@@ -1512,8 +1537,7 @@ #endif
 	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
 	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;
 
-	sk->sk_stamp.tv_sec     = -1L;
-	sk->sk_stamp.tv_usec    = -1L;
+	sk->sk_stamp = ktime_set(-1L, -1L);
 
 	atomic_set(&sk->sk_refcnt, 1);
 }
@@ -1554,17 +1578,36 @@ EXPORT_SYMBOL(release_sock);
 
 int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 {
+	struct timeval tv;
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
 		sock_enable_timestamp(sk);
-	if (sk->sk_stamp.tv_sec == -1)
+	tv = ktime_to_timeval(sk->sk_stamp);
+	if (tv.tv_sec == -1)
 		return -ENOENT;
-	if (sk->sk_stamp.tv_sec == 0)
-		do_gettimeofday(&sk->sk_stamp);
-	return copy_to_user(userstamp, &sk->sk_stamp, sizeof(struct timeval)) ?
-		-EFAULT : 0;
+	if (tv.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		tv = ktime_to_timeval(sk->sk_stamp);
+	}
+	return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0;
 }
 EXPORT_SYMBOL(sock_get_timestamp);
 
+int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
+{
+	struct timespec ts;
+	if (!sock_flag(sk, SOCK_TIMESTAMP))
+		sock_enable_timestamp(sk);
+	ts = ktime_to_timespec(sk->sk_stamp);
+	if (ts.tv_sec == -1)
+		return -ENOENT;
+	if (ts.tv_sec == 0) {
+		sk->sk_stamp = ktime_get_real();
+		ts = ktime_to_timespec(sk->sk_stamp);
+	}
+	return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0;
+}
+EXPORT_SYMBOL(sock_get_timestampns);
+
 void sock_enable_timestamp(struct sock *sk)
 {
 	if (!sock_flag(sk, SOCK_TIMESTAMP)) {
@@ -1899,7 +1942,7 @@ static int proto_seq_show(struct seq_fil
 	return 0;
 }
 
-static struct seq_operations proto_seq_ops = {
+static const struct seq_operations proto_seq_ops = {
 	.start  = proto_seq_start,
 	.next   = proto_seq_next,
 	.stop   = proto_seq_stop,
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 1e75b15..b297120 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -136,6 +136,14 @@ #endif /* CONFIG_NET */
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
 	},
+	{
+		.ctl_name	= NET_CORE_WARNINGS,
+		.procname	= "warnings",
+		.data		= &net_msg_warn,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
 	{ .ctl_name = 0 }
 };
 
diff --git a/net/core/utils.c b/net/core/utils.c
index 07236c1..adecfd2 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -30,8 +30,10 @@ #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-int net_msg_cost = 5*HZ;
-int net_msg_burst = 10;
+int net_msg_cost __read_mostly = 5*HZ;
+int net_msg_burst __read_mostly = 10;
+int net_msg_warn __read_mostly = 1;
+EXPORT_SYMBOL(net_msg_warn);
 
 /*
  * All net warning printk()s should be guarded by this function.
diff --git a/net/core/wireless.c b/net/core/wireless.c
deleted file mode 100644
index b07fe27..0000000
--- a/net/core/wireless.c
+++ /dev/null
@@ -1,2371 +0,0 @@
-/*
- * This file implement the Wireless Extensions APIs.
- *
- * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- *
- * (As all part of the Linux kernel, this file is GPL)
- */
-
-/************************** DOCUMENTATION **************************/
-/*
- * API definition :
- * --------------
- * See <linux/wireless.h> for details of the APIs and the rest.
- *
- * History :
- * -------
- *
- * v1 - 5.12.01 - Jean II
- *	o Created this file.
- *
- * v2 - 13.12.01 - Jean II
- *	o Move /proc/net/wireless stuff from net/core/dev.c to here
- *	o Make Wireless Extension IOCTLs go through here
- *	o Added iw_handler handling ;-)
- *	o Added standard ioctl description
- *	o Initial dumb commit strategy based on orinoco.c
- *
- * v3 - 19.12.01 - Jean II
- *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
- *	o Add event dispatcher function
- *	o Add event description
- *	o Propagate events as rtnetlink IFLA_WIRELESS option
- *	o Generate event on selected SET requests
- *
- * v4 - 18.04.02 - Jean II
- *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- *
- * v5 - 21.06.02 - Jean II
- *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
- *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- *	o Add IWEVCUSTOM for driver specific event/scanning token
- *	o Turn on WE_STRICT_WRITE by default + kernel warning
- *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- *
- * v6 - 9.01.03 - Jean II
- *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
- *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
- *	o Add WIRELESS_EXT version display in /proc/net/wireless
- *
- * v6 - 18.06.04 - Jean II
- *	o Change get_spydata() method for added safety
- *	o Remove spy #ifdef, they are always on -> cleaner code
- *	o Allow any size GET request if user specifies length > max
- *		and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
- *	o Start migrating get_wireless_stats to struct iw_handler_def
- *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
- * Based on patch from Pavel Roskin <proski@gnu.org> :
- *	o Fix kernel data leak to user space in private handler handling
- *
- * v7 - 18.3.05 - Jean II
- *	o Remove (struct iw_point *)->pointer from events and streams
- *	o Remove spy_offset from struct iw_handler_def
- *	o Start deprecating dev->get_wireless_stats, output a warning
- *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
- *
- * 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()
- *
- * v10 - 16.3.07 - Jean II
- *	o Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/***************************** INCLUDES *****************************/
-
-#include <linux/module.h>
-#include <linux/types.h>		/* off_t */
-#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
-#include <linux/proc_fs.h>
-#include <linux/rtnetlink.h>		/* rtnetlink stuff */
-#include <linux/seq_file.h>
-#include <linux/init.h>			/* for __init */
-#include <linux/if_arp.h>		/* ARPHRD_ETHER */
-#include <linux/etherdevice.h>		/* compare_ether_addr */
-#include <linux/interrupt.h>
-
-#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() */
-
-/**************************** CONSTANTS ****************************/
-
-/* Debugging stuff */
-#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
-#undef WE_RTNETLINK_DEBUG	/* Debug RtNetlink API */
-#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
-#undef WE_SPY_DEBUG		/* Debug enhanced spy support */
-
-/* Options */
-//CONFIG_NET_WIRELESS_RTNETLINK	/* Wireless requests over RtNetlink */
-#define WE_EVENT_RTNETLINK	/* Propagate events using RtNetlink */
-#define WE_SET_EVENT		/* Generate an event on some set commands */
-
-/************************* GLOBAL VARIABLES *************************/
-/*
- * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
-/*
- * Meta-data about all the standard Wireless Extension request we
- * know about.
- */
-static const struct iw_ioctl_description standard_ioctl[] = {
-	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWNAME	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_CHAR,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWNWID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWNWID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWFREQ	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_FREQ,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWFREQ	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_FREQ,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWMODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_UINT,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWMODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_UINT,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWSENS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWSENS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRANGE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWRANGE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_range),
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWPRIV	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_priv_args),
-		.max_tokens	= 16,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWSTATS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_statistics),
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr),
-		.max_tokens	= IW_MAX_SPY,
-	},
-	[SIOCGIWSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr) +
-				  sizeof(struct iw_quality),
-		.max_tokens	= IW_MAX_SPY,
-	},
-	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_thrspy),
-		.min_tokens	= 1,
-		.max_tokens	= 1,
-	},
-	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_thrspy),
-		.min_tokens	= 1,
-		.max_tokens	= 1,
-	},
-	[SIOCSIWAP	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[SIOCGIWAP	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWMLME	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_mlme),
-		.max_tokens	= sizeof(struct iw_mlme),
-	},
-	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr) +
-				  sizeof(struct iw_quality),
-		.max_tokens	= IW_MAX_AP,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWSCAN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= 0,
-		.max_tokens	= sizeof(struct iw_scan_req),
-	},
-	[SIOCGIWSCAN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_SCAN_MAX_DATA,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWESSID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_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,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWNICKN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_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,
-	},
-	[SIOCSIWRATE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRATE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRTS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRTS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWFRAG	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWFRAG	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRETRY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRETRY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWENCODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ENCODING_TOKEN_MAX,
-		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
-	},
-	[SIOCGIWENCODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ENCODING_TOKEN_MAX,
-		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
-	},
-	[SIOCSIWPOWER	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWPOWER	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWGENIE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[SIOCGIWGENIE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[SIOCSIWAUTH	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWAUTH	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_encode_ext),
-		.max_tokens	= sizeof(struct iw_encode_ext) +
-				  IW_ENCODING_TOKEN_MAX,
-	},
-	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_encode_ext),
-		.max_tokens	= sizeof(struct iw_encode_ext) +
-				  IW_ENCODING_TOKEN_MAX,
-	},
-	[SIOCSIWPMKSA - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_pmksa),
-		.max_tokens	= sizeof(struct iw_pmksa),
-	},
-};
-static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) /
-					    sizeof(struct iw_ioctl_description));
-
-/*
- * Meta-data about all the additional standard Wireless Extension events
- * we know about.
- */
-static const struct iw_ioctl_description standard_event[] = {
-	[IWEVTXDROP	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[IWEVQUAL	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_QUAL,
-	},
-	[IWEVCUSTOM	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_CUSTOM_MAX,
-	},
-	[IWEVREGISTERED	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[IWEVEXPIRED	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[IWEVGENIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_michaelmicfailure),
-	},
-	[IWEVASSOCREQIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVASSOCRESPIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVPMKIDCAND	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_pmkid_cand),
-	},
-};
-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[] = {
-	0,				/* IW_PRIV_TYPE_NONE */
-	1,				/* IW_PRIV_TYPE_BYTE */
-	1,				/* IW_PRIV_TYPE_CHAR */
-	0,				/* Not defined */
-	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
-	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
-	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
-	0,				/* Not defined */
-};
-
-/* Size (in bytes) of various events */
-static const int event_type_size[] = {
-	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
-	0,
-	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
-	0,
-	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
-	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
-	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
-	0,
-	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
-	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
-};
-
-/* Size (in bytes) of various events, as packed */
-static const int event_type_pk_size[] = {
-	IW_EV_LCP_PK_LEN,		/* IW_HEADER_TYPE_NULL */
-	0,
-	IW_EV_CHAR_PK_LEN,		/* IW_HEADER_TYPE_CHAR */
-	0,
-	IW_EV_UINT_PK_LEN,		/* IW_HEADER_TYPE_UINT */
-	IW_EV_FREQ_PK_LEN,		/* IW_HEADER_TYPE_FREQ */
-	IW_EV_ADDR_PK_LEN,		/* IW_HEADER_TYPE_ADDR */
-	0,
-	IW_EV_POINT_PK_LEN,		/* Without variable payload */
-	IW_EV_PARAM_PK_LEN,		/* IW_HEADER_TYPE_PARAM */
-	IW_EV_QUAL_PK_LEN,		/* IW_HEADER_TYPE_QUAL */
-};
-
-/************************ COMMON SUBROUTINES ************************/
-/*
- * Stuff that may be used in various place or doesn't fit in one
- * of the section below.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the driver handler associated with a specific Wireless Extension.
- * Called from various place, so make sure it remains efficient.
- */
-static inline iw_handler get_handler(struct net_device *dev,
-				     unsigned int cmd)
-{
-	/* Don't "optimise" the following variable, it will crash */
-	unsigned int	index;		/* *MUST* be unsigned */
-
-	/* Check if we have some wireless handlers defined */
-	if(dev->wireless_handlers == NULL)
-		return NULL;
-
-	/* Try as a standard command */
-	index = cmd - SIOCIWFIRST;
-	if(index < dev->wireless_handlers->num_standard)
-		return dev->wireless_handlers->standard[index];
-
-	/* Try as a private command */
-	index = cmd - SIOCIWFIRSTPRIV;
-	if(index < dev->wireless_handlers->num_private)
-		return dev->wireless_handlers->private[index];
-
-	/* Not found */
-	return NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Get statistics out of the driver
- */
-static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
-{
-	/* New location */
-	if((dev->wireless_handlers != NULL) &&
-	   (dev->wireless_handlers->get_wireless_stats != NULL))
-		return dev->wireless_handlers->get_wireless_stats(dev);
-
-	/* Not found */
-	return (struct iw_statistics *) NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call the commit handler in the driver
- * (if exist and if conditions are right)
- *
- * Note : our current commit strategy is currently pretty dumb,
- * but we will be able to improve on that...
- * The goal is to try to agreagate as many changes as possible
- * before doing the commit. Drivers that will define a commit handler
- * are usually those that need a reset after changing parameters, so
- * we want to minimise the number of reset.
- * A cool idea is to use a timer : at each "set" command, we re-set the
- * timer, when the timer eventually fires, we call the driver.
- * Hopefully, more on that later.
- *
- * Also, I'm waiting to see how many people will complain about the
- * netif_running(dev) test. I'm open on that one...
- * Hopefully, the driver will remember to do a commit in "open()" ;-)
- */
-static inline int call_commit_handler(struct net_device *	dev)
-{
-	if((netif_running(dev)) &&
-	   (dev->wireless_handlers->standard[0] != NULL)) {
-		/* Call the commit handler on the driver */
-		return dev->wireless_handlers->standard[0](dev, NULL,
-							   NULL, NULL);
-	} else
-		return 0;		/* Command completed successfully */
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Calculate size of private arguments
- */
-static inline int get_priv_size(__u16	args)
-{
-	int	num = args & IW_PRIV_SIZE_MASK;
-	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
-
-	return num * iw_priv_type_size[type];
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Re-calculate the size of private arguments
- */
-static inline int adjust_priv_size(__u16		args,
-				   union iwreq_data *	wrqu)
-{
-	int	num = wrqu->data.length;
-	int	max = args & IW_PRIV_SIZE_MASK;
-	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
-
-	/* Make sure the driver doesn't goof up */
-	if (max < num)
-		num = max;
-
-	return num * iw_priv_type_size[type];
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get wireless stats
- *	Allow programatic access to /proc/net/wireless even if /proc
- *	doesn't exist... Also more efficient...
- */
-static int iw_handler_get_iwstats(struct net_device *		dev,
-				  struct iw_request_info *	info,
-				  union iwreq_data *		wrqu,
-				  char *			extra)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats;
-
-	stats = get_wireless_stats(dev);
-	if (stats != (struct iw_statistics *) NULL) {
-
-		/* Copy statistics to extra */
-		memcpy(extra, stats, sizeof(struct iw_statistics));
-		wrqu->data.length = sizeof(struct iw_statistics);
-
-		/* Check if we need to clear the updated flag */
-		if(wrqu->data.flags != 0)
-			stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
-		return 0;
-	} else
-		return -EOPNOTSUPP;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get iwpriv definitions
- * Export the driver private handler definition
- * They will be picked up by tools like iwpriv...
- */
-static int iw_handler_get_private(struct net_device *		dev,
-				  struct iw_request_info *	info,
-				  union iwreq_data *		wrqu,
-				  char *			extra)
-{
-	/* Check if the driver has something to export */
-	if((dev->wireless_handlers->num_private_args == 0) ||
-	   (dev->wireless_handlers->private_args == NULL))
-		return -EOPNOTSUPP;
-
-	/* Check if there is enough buffer up there */
-	if(wrqu->data.length < dev->wireless_handlers->num_private_args) {
-		/* User space can't know in advance how large the buffer
-		 * needs to be. Give it a hint, so that we can support
-		 * any size buffer we want somewhat efficiently... */
-		wrqu->data.length = dev->wireless_handlers->num_private_args;
-		return -E2BIG;
-	}
-
-	/* Set the number of available ioctls. */
-	wrqu->data.length = dev->wireless_handlers->num_private_args;
-
-	/* Copy structure to the user buffer. */
-	memcpy(extra, dev->wireless_handlers->private_args,
-	       sizeof(struct iw_priv_args) * wrqu->data.length);
-
-	return 0;
-}
-
-
-/******************** /proc/net/wireless SUPPORT ********************/
-/*
- * The /proc/net/wireless file is a human readable user-space interface
- * exporting various wireless specific statistics from the wireless devices.
- * This is the most popular part of the Wireless Extensions ;-)
- *
- * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
- * The content of the file is basically the content of "struct iw_statistics".
- */
-
-#ifdef CONFIG_PROC_FS
-
-/* ---------------------------------------------------------------- */
-/*
- * Print one entry (line) of /proc/net/wireless
- */
-static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
-						 struct net_device *dev)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = get_wireless_stats(dev);
-
-	if (stats) {
-		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
-				"%6d %6d   %6d\n",
-			   dev->name, stats->status, stats->qual.qual,
-			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
-			   ? '.' : ' ',
-			   ((__s32) stats->qual.level) -
-			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
-			   ? '.' : ' ',
-			   ((__s32) stats->qual.noise) -
-			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
-			   ? '.' : ' ',
-			   stats->discard.nwid, stats->discard.code,
-			   stats->discard.fragment, stats->discard.retries,
-			   stats->discard.misc, stats->miss.beacon);
-		stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
-	}
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Print info for /proc/net/wireless (print all entries)
- */
-static int wireless_seq_show(struct seq_file *seq, void *v)
-{
-	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
-				"packets               | Missed | WE\n"
-				" face | tus | link level noise |  nwid  "
-				"crypt   frag  retry   misc | beacon | %d\n",
-			   WIRELESS_EXT);
-	else
-		wireless_seq_printf_stats(seq, v);
-	return 0;
-}
-
-static struct seq_operations wireless_seq_ops = {
-	.start = dev_seq_start,
-	.next  = dev_seq_next,
-	.stop  = dev_seq_stop,
-	.show  = wireless_seq_show,
-};
-
-static int wireless_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &wireless_seq_ops);
-}
-
-static const struct file_operations wireless_seq_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = wireless_seq_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-int __init wireless_proc_init(void)
-{
-	/* Create /proc/net/wireless entry */
-	if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
-		return -ENOMEM;
-
-	return 0;
-}
-#endif	/* CONFIG_PROC_FS */
-
-/************************** IOCTL SUPPORT **************************/
-/*
- * The original user space API to configure all those Wireless Extensions
- * is through IOCTLs.
- * In there, we check if we need to call the new driver API (iw_handler)
- * or just call the driver ioctl handler.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a standard Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- */
-static int ioctl_standard_call(struct net_device *	dev,
-			       struct ifreq *		ifr,
-			       unsigned int		cmd,
-			       iw_handler		handler)
-{
-	struct iwreq *				iwr = (struct iwreq *) ifr;
-	const struct iw_ioctl_description *	descr;
-	struct iw_request_info			info;
-	int					ret = -EINVAL;
-
-	/* Get the description of the IOCTL */
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
-#ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_IOCTL_DEBUG */
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have a pointer to user space data or not */
-	if(descr->header_type != IW_HEADER_TYPE_POINT) {
-
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, &(iwr->u), NULL);
-
-#ifdef WE_SET_EVENT
-		/* Generate an event to notify listeners of the change */
-		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
-		   ((ret == 0) || (ret == -EIWCOMMIT)))
-			wireless_send_event(dev, cmd, &(iwr->u), NULL);
-#endif	/* WE_SET_EVENT */
-	} else {
-		char *	extra;
-		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 */
-			if((iwr->u.data.pointer == NULL) &&
-			   (iwr->u.data.length != 0))
-				return -EFAULT;
-			/* Check if number of token fits within bounds */
-			if(iwr->u.data.length > descr->max_tokens)
-				return -E2BIG;
-			if(iwr->u.data.length < descr->min_tokens)
-				return -EINVAL;
-		} else {
-			/* Check NULL pointer */
-			if(iwr->u.data.pointer == NULL)
-				return -EFAULT;
-			/* Save user space buffer size for checking */
-			user_length = iwr->u.data.length;
-
-			/* Don't check if user_length > max to allow forward
-			 * compatibility. The test user_length < min is
-			 * implied by the test at the end. */
-
-			/* Support for very large requests */
-			if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
-			   (user_length > descr->max_tokens)) {
-				/* Allow userspace to GET more than max so
-				 * we can support any size GET requests.
-				 * There is still a limit : -ENOMEM. */
-				extra_size = user_length * descr->token_size;
-				/* Note : user_length is originally a __u16,
-				 * and token_size is controlled by us,
-				 * so extra_size won't get negative and
-				 * won't overflow... */
-			}
-		}
-
-#ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_IOCTL_DEBUG */
-
-		/* Create the kernel buffer */
-		/*    kzalloc ensures NULL-termination for essid_compat */
-		extra = kzalloc(extra_size, GFP_KERNEL);
-		if (extra == NULL) {
-			return -ENOMEM;
-		}
-
-		/* If it is a SET, get all the extra data in here */
-		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-			err = copy_from_user(extra, iwr->u.data.pointer,
-					     iwr->u.data.length *
-					     descr->token_size);
-			if (err) {
-				kfree(extra);
-				return -EFAULT;
-			}
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
-			       dev->name,
-			       iwr->u.data.length * descr->token_size);
-#endif	/* WE_IOCTL_DEBUG */
-		}
-
-		/* 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 */
-			if(user_length < iwr->u.data.length) {
-				kfree(extra);
-				return -E2BIG;
-			}
-
-			err = copy_to_user(iwr->u.data.pointer, extra,
-					   iwr->u.data.length *
-					   descr->token_size);
-			if (err)
-				ret =  -EFAULT;
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
-			       dev->name,
-			       iwr->u.data.length * descr->token_size);
-#endif	/* WE_IOCTL_DEBUG */
-		}
-
-#ifdef WE_SET_EVENT
-		/* Generate an event to notify listeners of the change */
-		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
-		   ((ret == 0) || (ret == -EIWCOMMIT))) {
-			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
-				/* If the event is restricted, don't
-				 * export the payload */
-				wireless_send_event(dev, cmd, &(iwr->u), NULL);
-			else
-				wireless_send_event(dev, cmd, &(iwr->u),
-						    extra);
-		}
-#endif	/* WE_SET_EVENT */
-
-		/* Cleanup - I told you it wasn't that long ;-) */
-		kfree(extra);
-	}
-
-	/* Call commit handler if needed and defined */
-	if(ret == -EIWCOMMIT)
-		ret = call_commit_handler(dev);
-
-	/* Here, we will generate the appropriate event if needed */
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
- *
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
- */
-static inline int ioctl_private_call(struct net_device *	dev,
-				     struct ifreq *		ifr,
-				     unsigned int		cmd,
-				     iw_handler		handler)
-{
-	struct iwreq *			iwr = (struct iwreq *) ifr;
-	const struct iw_priv_args *	descr = NULL;
-	struct iw_request_info		info;
-	int				extra_size = 0;
-	int				i;
-	int				ret = -EINVAL;
-
-	/* Get the description of the IOCTL */
-	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
-		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
-			descr = &(dev->wireless_handlers->private_args[i]);
-			break;
-		}
-
-#ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	if(descr) {
-		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
-		       dev->name, descr->name,
-		       descr->set_args, descr->get_args);
-	}
-#endif	/* WE_IOCTL_DEBUG */
-
-	/* Compute the size of the set/get arguments */
-	if(descr != NULL) {
-		if(IW_IS_SET(cmd)) {
-			int	offset = 0;	/* For sub-ioctls */
-			/* Check for sub-ioctl handler */
-			if(descr->name[0] == '\0')
-				/* Reserve one int for sub-ioctl index */
-				offset = sizeof(__u32);
-
-			/* Size of set arguments */
-			extra_size = get_priv_size(descr->set_args);
-
-			/* Does it fits in iwr ? */
-			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-			   ((extra_size + offset) <= IFNAMSIZ))
-				extra_size = 0;
-		} else {
-			/* Size of get arguments */
-			extra_size = get_priv_size(descr->get_args);
-
-			/* Does it fits in iwr ? */
-			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size <= IFNAMSIZ))
-				extra_size = 0;
-		}
-	}
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have a pointer to user space data or not. */
-	if(extra_size == 0) {
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
-	} else {
-		char *	extra;
-		int	err;
-
-		/* Check what user space is giving us */
-		if(IW_IS_SET(cmd)) {
-			/* Check NULL pointer */
-			if((iwr->u.data.pointer == NULL) &&
-			   (iwr->u.data.length != 0))
-				return -EFAULT;
-
-			/* Does it fits within bounds ? */
-			if(iwr->u.data.length > (descr->set_args &
-						 IW_PRIV_SIZE_MASK))
-				return -E2BIG;
-		} else {
-			/* Check NULL pointer */
-			if(iwr->u.data.pointer == NULL)
-				return -EFAULT;
-		}
-
-#ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_IOCTL_DEBUG */
-
-		/* Always allocate for max space. Easier, and won't last
-		 * long... */
-		extra = kmalloc(extra_size, GFP_KERNEL);
-		if (extra == NULL) {
-			return -ENOMEM;
-		}
-
-		/* If it is a SET, get all the extra data in here */
-		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
-			err = copy_from_user(extra, iwr->u.data.pointer,
-					     extra_size);
-			if (err) {
-				kfree(extra);
-				return -EFAULT;
-			}
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
-			       dev->name, iwr->u.data.length);
-#endif	/* WE_IOCTL_DEBUG */
-		}
-
-		/* Call the handler */
-		ret = handler(dev, &info, &(iwr->u), extra);
-
-		/* If we have something to return to the user */
-		if (!ret && IW_IS_GET(cmd)) {
-
-			/* Adjust for the actual length if it's variable,
-			 * avoid leaking kernel bits outside. */
-			if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
-				extra_size = adjust_priv_size(descr->get_args,
-							      &(iwr->u));
-			}
-
-			err = copy_to_user(iwr->u.data.pointer, extra,
-					   extra_size);
-			if (err)
-				ret =  -EFAULT;
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
-			       dev->name, iwr->u.data.length);
-#endif	/* WE_IOCTL_DEBUG */
-		}
-
-		/* Cleanup - I told you it wasn't that long ;-) */
-		kfree(extra);
-	}
-
-
-	/* Call commit handler if needed and defined */
-	if(ret == -EIWCOMMIT)
-		ret = call_commit_handler(dev);
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Main IOCTl dispatcher. Called from the main networking code
- * (dev_ioctl() in net/core/dev.c).
- * Check the type of IOCTL and call the appropriate wrapper...
- */
-int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
-{
-	struct net_device *dev;
-	iw_handler	handler;
-
-	/* Permissions are already checked in dev_ioctl() before calling us.
-	 * The copy_to/from_user() of ifr is also dealt with in there */
-
-	/* Make sure the device exist */
-	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
-		return -ENODEV;
-
-	/* A bunch of special cases, then the generic case...
-	 * Note that 'cmd' is already filtered in dev_ioctl() with
-	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
-	switch(cmd)
-	{
-		case SIOCGIWSTATS:
-			/* Get Wireless Stats */
-			return ioctl_standard_call(dev,
-						   ifr,
-						   cmd,
-						   &iw_handler_get_iwstats);
-
-		case SIOCGIWPRIV:
-			/* Check if we have some wireless handlers defined */
-			if(dev->wireless_handlers != NULL) {
-				/* We export to user space the definition of
-				 * the private handler ourselves */
-				return ioctl_standard_call(dev,
-							   ifr,
-							   cmd,
-							   &iw_handler_get_private);
-			}
-			// ## Fall-through for old API ##
-		default:
-			/* Generic IOCTL */
-			/* Basic check */
-			if (!netif_device_present(dev))
-				return -ENODEV;
-			/* New driver API : try to find the handler */
-			handler = get_handler(dev, cmd);
-			if(handler != NULL) {
-				/* Standard and private are not the same */
-				if(cmd < SIOCIWFIRSTPRIV)
-					return ioctl_standard_call(dev,
-								   ifr,
-								   cmd,
-								   handler);
-				else
-					return ioctl_private_call(dev,
-								  ifr,
-								  cmd,
-								  handler);
-			}
-			/* Old driver API : call driver ioctl handler */
-			if (dev->do_ioctl) {
-				return dev->do_ioctl(dev, ifr, cmd);
-			}
-			return -EOPNOTSUPP;
-	}
-	/* Not reached */
-	return -EINVAL;
-}
-
-/********************** RTNETLINK REQUEST API **********************/
-/*
- * The alternate user space API to configure all those Wireless Extensions
- * is through RtNetlink.
- * This API support only the new driver API (iw_handler).
- *
- * This RtNetlink API use the same query/reply model as the ioctl API.
- * Maximum effort has been done to fit in the RtNetlink model, and
- * we support both RtNetlink Set and RtNelink Get operations.
- * On the other hand, we don't offer Dump operations because of the
- * following reasons :
- *	o Large number of parameters, most optional
- *	o Large size of some parameters (> 100 bytes)
- *	o Each parameters need to be extracted from hardware
- *	o Scan requests can take seconds and disable network activity.
- * Because of this high cost/overhead, we want to return only the
- * parameters the user application is really interested in.
- * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag.
- *
- * The API uses the standard RtNetlink socket. When the RtNetlink code
- * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request,
- * it calls here.
- */
-
-#ifdef CONFIG_NET_WIRELESS_RTNETLINK
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a standard Wireless Extension GET handler.
- * We do various checks and call the handler with the proper args.
- */
-static int rtnetlink_standard_get(struct net_device *	dev,
-				  struct iw_event *	request,
-				  int			request_len,
-				  iw_handler		handler,
-				  char **		p_buf,
-				  int *			p_len)
-{
-	const struct iw_ioctl_description *	descr = NULL;
-	unsigned int				cmd;
-	union iwreq_data *			wrqu;
-	int					hdr_len;
-	struct iw_request_info			info;
-	char *					buffer = NULL;
-	int					buffer_size = 0;
-	int					ret = -EINVAL;
-
-	/* Get the description of the Request */
-	cmd = request->cmd;
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-	/* Check if wrqu is complete */
-	hdr_len = event_type_size[descr->header_type];
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
-		return -EINVAL;
-	}
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have extra data in the reply or not */
-	if(descr->header_type != IW_HEADER_TYPE_POINT) {
-
-		/* Create the kernel buffer that we will return.
-		 * It's at an offset to match the TYPE_POINT case... */
-		buffer_size = request_len + IW_EV_POINT_OFF;
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (buffer == NULL) {
-			return -ENOMEM;
-		}
-		/* Copy event data */
-		memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
-		/* Use our own copy of wrqu */
-		wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
-					     + IW_EV_LCP_PK_LEN);
-
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, wrqu, NULL);
-
-	} else {
-		union iwreq_data	wrqu_point;
-		char *			extra = NULL;
-		int			extra_size = 0;
-
-		/* Get a temp copy of wrqu (skip pointer) */
-		memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
-		       ((char *) request) + IW_EV_LCP_PK_LEN,
-		       IW_EV_POINT_LEN - IW_EV_LCP_PK_LEN);
-
-		/* Calculate space needed by arguments. Always allocate
-		 * for max space. Easier, and won't last long... */
-		extra_size = descr->max_tokens * descr->token_size;
-		/* Support for very large requests */
-		if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
-		   (wrqu_point.data.length > descr->max_tokens))
-			extra_size = (wrqu_point.data.length
-				      * descr->token_size);
-		buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF;
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
-		       dev->name, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-		/* Create the kernel buffer that we will return */
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (buffer == NULL) {
-			return -ENOMEM;
-		}
-
-		/* Put wrqu in the right place (just before extra).
-		 * Leave space for IWE header and dummy pointer...
-		 * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned.
-		 */
-		memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF,
-		       ((char *) &wrqu_point) + IW_EV_POINT_OFF,
-		       IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-		wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN);
-
-		/* Extra comes logically after that. Offset +12 bytes. */
-		extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN;
-
-		/* Call the handler */
-		ret = handler(dev, &info, wrqu, extra);
-
-		/* Calculate real returned length */
-		extra_size = (wrqu->data.length * descr->token_size);
-		/* Re-adjust reply size */
-		request->len = extra_size + IW_EV_POINT_PK_LEN;
-
-		/* Put the iwe header where it should, i.e. scrap the
-		 * dummy pointer. */
-		memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN);
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-		/* Check if there is enough buffer up there */
-		if(wrqu_point.data.length < wrqu->data.length)
-			ret = -E2BIG;
-	}
-
-	/* Return the buffer to the caller */
-	if (!ret) {
-		*p_buf = buffer;
-		*p_len = request->len;
-	} else {
-		/* Cleanup */
-		if(buffer)
-			kfree(buffer);
-	}
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a standard Wireless Extension SET handler.
- * We do various checks and call the handler with the proper args.
- */
-static inline int rtnetlink_standard_set(struct net_device *	dev,
-					 struct iw_event *	request,
-					 int			request_len,
-					 iw_handler		handler)
-{
-	const struct iw_ioctl_description *	descr = NULL;
-	unsigned int				cmd;
-	union iwreq_data *			wrqu;
-	union iwreq_data			wrqu_point;
-	int					hdr_len;
-	char *					extra = NULL;
-	int					extra_size = 0;
-	struct iw_request_info			info;
-	int					ret = -EINVAL;
-
-	/* Get the description of the Request */
-	cmd = request->cmd;
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
-		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-	/* Extract fixed header from request. This is properly aligned. */
-	wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN);
-
-	/* Check if wrqu is complete */
-	hdr_len = event_type_pk_size[descr->header_type];
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
-		return -EINVAL;
-	}
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have extra data in the request or not */
-	if(descr->header_type != IW_HEADER_TYPE_POINT) {
-
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, wrqu, NULL);
-
-	} else {
-		int	extra_len;
-
-		/* Put wrqu in the right place (skip pointer) */
-		memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
-		       wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-		/* Don't forget about the event code... */
-		wrqu = &wrqu_point;
-
-		/* Check if number of token fits within bounds */
-		if(wrqu_point.data.length > descr->max_tokens)
-			return -E2BIG;
-		if(wrqu_point.data.length < descr->min_tokens)
-			return -EINVAL;
-
-		/* Real length of payload */
-		extra_len = wrqu_point.data.length * descr->token_size;
-
-		/* Check if request is self consistent */
-		if((request_len - hdr_len) < extra_len) {
-#ifdef WE_RTNETLINK_DEBUG
-			printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
-			       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-			return -EINVAL;
-		}
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-		/* Always allocate for max space. Easier, and won't last
-		 * long... */
-		extra_size = descr->max_tokens * descr->token_size;
-		extra = kmalloc(extra_size, GFP_KERNEL);
-		if (extra == NULL)
-			return -ENOMEM;
-
-		/* Copy extra in aligned buffer */
-		memcpy(extra, ((char *) request) + hdr_len, extra_len);
-
-		/* Call the handler */
-		ret = handler(dev, &info, &wrqu_point, extra);
-	}
-
-#ifdef WE_SET_EVENT
-	/* Generate an event to notify listeners of the change */
-	if((descr->flags & IW_DESCR_FLAG_EVENT) &&
-	   ((ret == 0) || (ret == -EIWCOMMIT))) {
-		if(descr->flags & IW_DESCR_FLAG_RESTRICT)
-			/* If the event is restricted, don't
-			 * export the payload */
-			wireless_send_event(dev, cmd, wrqu, NULL);
-		else
-			wireless_send_event(dev, cmd, wrqu, extra);
-	}
-#endif	/* WE_SET_EVENT */
-
-	/* Cleanup - I told you it wasn't that long ;-) */
-	if(extra)
-		kfree(extra);
-
-	/* Call commit handler if needed and defined */
-	if(ret == -EIWCOMMIT)
-		ret = call_commit_handler(dev);
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension GET handler.
- * Same as above...
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
- *
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
- */
-static inline int rtnetlink_private_get(struct net_device *	dev,
-					struct iw_event *	request,
-					int			request_len,
-					iw_handler		handler,
-					char **			p_buf,
-					int *			p_len)
-{
-	const struct iw_priv_args *	descr = NULL;
-	unsigned int			cmd;
-	union iwreq_data *		wrqu;
-	int				hdr_len;
-	struct iw_request_info		info;
-	int				extra_size = 0;
-	int				i;
-	char *				buffer = NULL;
-	int				buffer_size = 0;
-	int				ret = -EINVAL;
-
-	/* Get the description of the Request */
-	cmd = request->cmd;
-	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
-		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
-			descr = &(dev->wireless_handlers->private_args[i]);
-			break;
-		}
-	if(descr == NULL)
-		return -EOPNOTSUPP;
-
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
-	       dev->name, descr->name, descr->set_args, descr->get_args);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-	/* Compute the max size of the get arguments */
-	extra_size = get_priv_size(descr->get_args);
-
-	/* Does it fits in wrqu ? */
-	if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-	   (extra_size <= IFNAMSIZ)) {
-		hdr_len = extra_size;
-		extra_size = 0;
-	} else {
-		hdr_len = IW_EV_POINT_PK_LEN;
-	}
-
-	/* Check if wrqu is complete */
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
-		return -EINVAL;
-	}
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have a pointer to user space data or not. */
-	if(extra_size == 0) {
-
-		/* Create the kernel buffer that we will return.
-		 * It's at an offset to match the TYPE_POINT case... */
-		buffer_size = request_len + IW_EV_POINT_OFF;
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (buffer == NULL) {
-			return -ENOMEM;
-		}
-		/* Copy event data */
-		memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
-		/* Use our own copy of wrqu */
-		wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
-					     + IW_EV_LCP_PK_LEN);
-
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, wrqu, (char *) wrqu);
-
-	} else {
-		char *	extra;
-
-		/* Buffer for full reply */
-		buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF;
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
-		       dev->name, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-		/* Create the kernel buffer that we will return */
-		buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (buffer == NULL) {
-			return -ENOMEM;
-		}
-
-		/* Put wrqu in the right place (just before extra).
-		 * Leave space for IWE header and dummy pointer...
-		 * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned.
-		 */
-		memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF,
-		       ((char *) request) + IW_EV_LCP_PK_LEN,
-		       IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-		wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN);
-
-		/* Extra comes logically after that. Offset +12 bytes. */
-		extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN;
-
-		/* Call the handler */
-		ret = handler(dev, &info, wrqu, extra);
-
-		/* Adjust for the actual length if it's variable,
-		 * avoid leaking kernel bits outside. */
-		if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
-			extra_size = adjust_priv_size(descr->get_args, wrqu);
-		/* Re-adjust reply size */
-		request->len = extra_size + IW_EV_POINT_PK_LEN;
-
-		/* Put the iwe header where it should, i.e. scrap the
-		 * dummy pointer. */
-		memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN);
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-	}
-
-	/* Return the buffer to the caller */
-	if (!ret) {
-		*p_buf = buffer;
-		*p_len = request->len;
-	} else {
-		/* Cleanup */
-		if(buffer)
-			kfree(buffer);
-	}
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension SET handler.
- * Same as above...
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
- *
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
- */
-static inline int rtnetlink_private_set(struct net_device *	dev,
-					struct iw_event *	request,
-					int			request_len,
-					iw_handler		handler)
-{
-	const struct iw_priv_args *	descr = NULL;
-	unsigned int			cmd;
-	union iwreq_data *		wrqu;
-	union iwreq_data		wrqu_point;
-	int				hdr_len;
-	char *				extra = NULL;
-	int				extra_size = 0;
-	int				offset = 0;	/* For sub-ioctls */
-	struct iw_request_info		info;
-	int				i;
-	int				ret = -EINVAL;
-
-	/* Get the description of the Request */
-	cmd = request->cmd;
-	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
-		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
-			descr = &(dev->wireless_handlers->private_args[i]);
-			break;
-		}
-	if(descr == NULL)
-		return -EOPNOTSUPP;
-
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
-	       dev->name, descr->name, descr->set_args, descr->get_args);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-	/* Compute the size of the set arguments */
-	/* Check for sub-ioctl handler */
-	if(descr->name[0] == '\0')
-		/* Reserve one int for sub-ioctl index */
-		offset = sizeof(__u32);
-
-	/* Size of set arguments */
-	extra_size = get_priv_size(descr->set_args);
-
-	/* Does it fits in wrqu ? */
-	if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-	   (extra_size <= IFNAMSIZ)) {
-		hdr_len = IW_EV_LCP_PK_LEN + extra_size;
-		extra_size = 0;
-	} else {
-		hdr_len = IW_EV_POINT_PK_LEN;
-	}
-
-	/* Extract fixed header from request. This is properly aligned. */
-	wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN);
-
-	/* Check if wrqu is complete */
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
-		return -EINVAL;
-	}
-
-	/* Prepare the call */
-	info.cmd = cmd;
-	info.flags = 0;
-
-	/* Check if we have a pointer to user space data or not. */
-	if(extra_size == 0) {
-
-		/* No extra arguments. Trivial to handle */
-		ret = handler(dev, &info, wrqu, (char *) wrqu);
-
-	} else {
-		int	extra_len;
-
-		/* Put wrqu in the right place (skip pointer) */
-		memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
-		       wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
-
-		/* Does it fits within bounds ? */
-		if(wrqu_point.data.length > (descr->set_args &
-					     IW_PRIV_SIZE_MASK))
-			return -E2BIG;
-
-		/* Real length of payload */
-		extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
-
-		/* Check if request is self consistent */
-		if((request_len - hdr_len) < extra_len) {
-#ifdef WE_RTNETLINK_DEBUG
-			printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
-			       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-			return -EINVAL;
-		}
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
-		/* Always allocate for max space. Easier, and won't last
-		 * long... */
-		extra = kmalloc(extra_size, GFP_KERNEL);
-		if (extra == NULL)
-			return -ENOMEM;
-
-		/* Copy extra in aligned buffer */
-		memcpy(extra, ((char *) request) + hdr_len, extra_len);
-
-		/* Call the handler */
-		ret = handler(dev, &info, &wrqu_point, extra);
-
-		/* Cleanup - I told you it wasn't that long ;-) */
-		kfree(extra);
-	}
-
-	/* Call commit handler if needed and defined */
-	if(ret == -EIWCOMMIT)
-		ret = call_commit_handler(dev);
-
-	return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Main RtNetlink dispatcher. Called from the main networking code
- * (do_getlink() in net/core/rtnetlink.c).
- * Check the type of Request and call the appropriate wrapper...
- */
-int wireless_rtnetlink_get(struct net_device *	dev,
-			   char *		data,
-			   int			len,
-			   char **		p_buf,
-			   int *		p_len)
-{
-	struct iw_event *	request = (struct iw_event *) data;
-	iw_handler		handler;
-
-	/* Check length */
-	if(len < IW_EV_LCP_PK_LEN) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
-		       dev->name, len);
-		return -EINVAL;
-	}
-
-	/* ReCheck length (len may have padding) */
-	if(request->len > len) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
-		       dev->name, request->len, len);
-		return -EINVAL;
-	}
-
-	/* Only accept GET requests in here */
-	if(!IW_IS_GET(request->cmd))
-		return -EOPNOTSUPP;
-
-	/* If command is `get the encoding parameters', check if
-	 * the user has the right to do it */
-	if (request->cmd == SIOCGIWENCODE ||
-	    request->cmd == SIOCGIWENCODEEXT) {
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-	}
-
-	/* Special cases */
-	if(request->cmd == SIOCGIWSTATS)
-		/* Get Wireless Stats */
-		return rtnetlink_standard_get(dev,
-					      request,
-					      request->len,
-					      &iw_handler_get_iwstats,
-					      p_buf, p_len);
-	if(request->cmd == SIOCGIWPRIV) {
-		/* Check if we have some wireless handlers defined */
-		if(dev->wireless_handlers == NULL)
-			return -EOPNOTSUPP;
-		/* Get Wireless Stats */
-		return rtnetlink_standard_get(dev,
-					      request,
-					      request->len,
-					      &iw_handler_get_private,
-					      p_buf, p_len);
-	}
-
-	/* Basic check */
-	if (!netif_device_present(dev))
-		return -ENODEV;
-
-	/* Try to find the handler */
-	handler = get_handler(dev, request->cmd);
-	if(handler != NULL) {
-		/* Standard and private are not the same */
-		if(request->cmd < SIOCIWFIRSTPRIV)
-			return rtnetlink_standard_get(dev,
-						      request,
-						      request->len,
-						      handler,
-						      p_buf, p_len);
-		else
-			return rtnetlink_private_get(dev,
-						     request,
-						     request->len,
-						     handler,
-						     p_buf, p_len);
-	}
-
-	return -EOPNOTSUPP;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Main RtNetlink dispatcher. Called from the main networking code
- * (do_setlink() in net/core/rtnetlink.c).
- * Check the type of Request and call the appropriate wrapper...
- */
-int wireless_rtnetlink_set(struct net_device *	dev,
-			   char *		data,
-			   int			len)
-{
-	struct iw_event *	request = (struct iw_event *) data;
-	iw_handler		handler;
-
-	/* Check length */
-	if(len < IW_EV_LCP_PK_LEN) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
-		       dev->name, len);
-		return -EINVAL;
-	}
-
-	/* ReCheck length (len may have padding) */
-	if(request->len > len) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
-		       dev->name, request->len, len);
-		return -EINVAL;
-	}
-
-	/* Only accept SET requests in here */
-	if(!IW_IS_SET(request->cmd))
-		return -EOPNOTSUPP;
-
-	/* Basic check */
-	if (!netif_device_present(dev))
-		return -ENODEV;
-
-	/* New driver API : try to find the handler */
-	handler = get_handler(dev, request->cmd);
-	if(handler != NULL) {
-		/* Standard and private are not the same */
-		if(request->cmd < SIOCIWFIRSTPRIV)
-			return rtnetlink_standard_set(dev,
-						      request,
-						      request->len,
-						      handler);
-		else
-			return rtnetlink_private_set(dev,
-						     request,
-						     request->len,
-						     handler);
-	}
-
-	return -EOPNOTSUPP;
-}
-#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */
-
-
-/************************* EVENT PROCESSING *************************/
-/*
- * Process events generated by the wireless layer or the driver.
- * Most often, the event will be propagated through rtnetlink
- */
-
-#ifdef WE_EVENT_RTNETLINK
-/* ---------------------------------------------------------------- */
-/*
- * Locking...
- * ----------
- *
- * Thanks to Herbert Xu <herbert@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)))
-		rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
-}
-
-static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
-
-/* ---------------------------------------------------------------- */
-/*
- * Fill a rtnetlink message with our event data.
- * Note that we propage only the specified event and don't dump the
- * current wireless config. Dumping the wireless config is far too
- * expensive (for each parameter, the driver need to query the hardware).
- */
-static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
-					struct net_device *	dev,
-					int			type,
-					char *			event,
-					int			event_len)
-{
-	struct ifinfomsg *r;
-	struct nlmsghdr  *nlh;
-	unsigned char	 *b = skb->tail;
-
-	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
-	r = NLMSG_DATA(nlh);
-	r->ifi_family = AF_UNSPEC;
-	r->__ifi_pad = 0;
-	r->ifi_type = dev->type;
-	r->ifi_index = dev->ifindex;
-	r->ifi_flags = dev_get_flags(dev);
-	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
-
-	/* Add the wireless events in the netlink packet */
-	RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Create and broadcast and send it on the standard rtnetlink socket
- * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
- * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
- * within a RTM_NEWLINK event.
- */
-static inline void rtmsg_iwinfo(struct net_device *	dev,
-				char *			event,
-				int			event_len)
-{
-	struct sk_buff *skb;
-	int size = NLMSG_GOODSIZE;
-
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
-				  event, event_len) < 0) {
-		kfree_skb(skb);
-		return;
-	}
-	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
-	skb_queue_tail(&wireless_nlevent_queue, skb);
-	tasklet_schedule(&wireless_nlevent_tasklet);
-}
-
-#endif	/* WE_EVENT_RTNETLINK */
-
-/* ---------------------------------------------------------------- */
-/*
- * Main event dispatcher. Called from other parts and drivers.
- * Send the event on the appropriate channels.
- * May be called from interrupt context.
- */
-void wireless_send_event(struct net_device *	dev,
-			 unsigned int		cmd,
-			 union iwreq_data *	wrqu,
-			 char *			extra)
-{
-	const struct iw_ioctl_description *	descr = NULL;
-	int extra_len = 0;
-	struct iw_event  *event;		/* Mallocated whole event */
-	int event_len;				/* Its size */
-	int hdr_len;				/* Size of the event header */
-	int wrqu_off = 0;			/* Offset in wrqu */
-	/* Don't "optimise" the following variable, it will crash */
-	unsigned	cmd_index;		/* *MUST* be unsigned */
-
-	/* Get the description of the Event */
-	if(cmd <= SIOCIWLAST) {
-		cmd_index = cmd - SIOCIWFIRST;
-		if(cmd_index < standard_ioctl_num)
-			descr = &(standard_ioctl[cmd_index]);
-	} else {
-		cmd_index = cmd - IWEVFIRST;
-		if(cmd_index < standard_event_num)
-			descr = &(standard_event[cmd_index]);
-	}
-	/* Don't accept unknown events */
-	if(descr == NULL) {
-		/* Note : we don't return an error to the driver, because
-		 * the driver would not know what to do about it. It can't
-		 * return an error to the user, because the event is not
-		 * initiated by a user request.
-		 * The best the driver could do is to log an error message.
-		 * We will do it ourselves instead...
-		 */
-		printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
-		       dev->name, cmd);
-		return;
-	}
-#ifdef WE_EVENT_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_EVENT_DEBUG */
-
-	/* Check extra parameters and set extra_len */
-	if(descr->header_type == IW_HEADER_TYPE_POINT) {
-		/* Check if number of token fits within bounds */
-		if(wrqu->data.length > descr->max_tokens) {
-			printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
-			return;
-		}
-		if(wrqu->data.length < descr->min_tokens) {
-			printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
-			return;
-		}
-		/* Calculate extra_len - extra is NULL for restricted events */
-		if(extra != NULL)
-			extra_len = wrqu->data.length * descr->token_size;
-		/* Always at an offset in wrqu */
-		wrqu_off = IW_EV_POINT_OFF;
-#ifdef WE_EVENT_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
-#endif	/* WE_EVENT_DEBUG */
-	}
-
-	/* Total length of the event */
-	hdr_len = event_type_size[descr->header_type];
-	event_len = hdr_len + extra_len;
-
-#ifdef WE_EVENT_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len);
-#endif	/* WE_EVENT_DEBUG */
-
-	/* Create temporary buffer to hold the event */
-	event = kmalloc(event_len, GFP_ATOMIC);
-	if(event == NULL)
-		return;
-
-	/* Fill event */
-	event->len = event_len;
-	event->cmd = cmd;
-	memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
-	if(extra != NULL)
-		memcpy(((char *) event) + hdr_len, extra, extra_len);
-
-#ifdef WE_EVENT_RTNETLINK
-	/* Send via the RtNetlink event channel */
-	rtmsg_iwinfo(dev, (char *) event, event_len);
-#endif	/* WE_EVENT_RTNETLINK */
-
-	/* Cleanup */
-	kfree(event);
-
-	return;		/* Always success, I guess ;-) */
-}
-
-/********************** ENHANCED IWSPY SUPPORT **********************/
-/*
- * In the old days, the driver was handling spy support all by itself.
- * Now, the driver can delegate this task to Wireless Extensions.
- * It needs to use those standard spy iw_handler in struct iw_handler_def,
- * push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and export it in net_device->wireless_data->spy_data).
- * One of the main advantage of centralising spy support here is that
- * it becomes much easier to improve and extend it without having to touch
- * the drivers. One example is the addition of the Spy-Threshold events.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the pointer to the spy data in the driver.
- * Because this is called on the Rx path via wireless_spy_update(),
- * we want it to be efficient...
- */
-static inline struct iw_spy_data * get_spydata(struct net_device *dev)
-{
-	/* This is the new way */
-	if(dev->wireless_data)
-		return(dev->wireless_data->spy_data);
-	return NULL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set Spy List
- */
-int iw_handler_set_spy(struct net_device *	dev,
-		       struct iw_request_info *	info,
-		       union iwreq_data *	wrqu,
-		       char *			extra)
-{
-	struct iw_spy_data *	spydata = get_spydata(dev);
-	struct sockaddr *	address = (struct sockaddr *) extra;
-
-	/* Make sure driver is not buggy or using the old API */
-	if(!spydata)
-		return -EOPNOTSUPP;
-
-	/* Disable spy collection while we copy the addresses.
-	 * While we copy addresses, any call to wireless_spy_update()
-	 * will NOP. This is OK, as anyway the addresses are changing. */
-	spydata->spy_number = 0;
-
-	/* We want to operate without locking, because wireless_spy_update()
-	 * most likely will happen in the interrupt handler, and therefore
-	 * have its own locking constraints and needs performance.
-	 * The rtnl_lock() make sure we don't race with the other iw_handlers.
-	 * This make sure wireless_spy_update() "see" that the spy list
-	 * is temporarily disabled. */
-	smp_wmb();
-
-	/* Are there are addresses to copy? */
-	if(wrqu->data.length > 0) {
-		int i;
-
-		/* Copy addresses */
-		for(i = 0; i < wrqu->data.length; i++)
-			memcpy(spydata->spy_address[i], address[i].sa_data,
-			       ETH_ALEN);
-		/* Reset stats */
-		memset(spydata->spy_stat, 0,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-
-#ifdef WE_SPY_DEBUG
-		printk(KERN_DEBUG "iw_handler_set_spy() :  wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length);
-		for (i = 0; i < wrqu->data.length; i++)
-			printk(KERN_DEBUG
-			       "%02X:%02X:%02X:%02X:%02X:%02X \n",
-			       spydata->spy_address[i][0],
-			       spydata->spy_address[i][1],
-			       spydata->spy_address[i][2],
-			       spydata->spy_address[i][3],
-			       spydata->spy_address[i][4],
-			       spydata->spy_address[i][5]);
-#endif	/* WE_SPY_DEBUG */
-	}
-
-	/* Make sure above is updated before re-enabling */
-	smp_wmb();
-
-	/* Enable addresses */
-	spydata->spy_number = wrqu->data.length;
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get Spy List
- */
-int iw_handler_get_spy(struct net_device *	dev,
-		       struct iw_request_info *	info,
-		       union iwreq_data *	wrqu,
-		       char *			extra)
-{
-	struct iw_spy_data *	spydata = get_spydata(dev);
-	struct sockaddr *	address = (struct sockaddr *) extra;
-	int			i;
-
-	/* Make sure driver is not buggy or using the old API */
-	if(!spydata)
-		return -EOPNOTSUPP;
-
-	wrqu->data.length = spydata->spy_number;
-
-	/* Copy addresses. */
-	for(i = 0; i < spydata->spy_number; i++) 	{
-		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
-		address[i].sa_family = AF_UNIX;
-	}
-	/* Copy stats to the user buffer (just after). */
-	if(spydata->spy_number > 0)
-		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
-		       spydata->spy_stat,
-		       sizeof(struct iw_quality) * spydata->spy_number);
-	/* Reset updated flags. */
-	for(i = 0; i < spydata->spy_number; i++)
-		spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set spy threshold
- */
-int iw_handler_set_thrspy(struct net_device *	dev,
-			  struct iw_request_info *info,
-			  union iwreq_data *	wrqu,
-			  char *		extra)
-{
-	struct iw_spy_data *	spydata = get_spydata(dev);
-	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
-
-	/* Make sure driver is not buggy or using the old API */
-	if(!spydata)
-		return -EOPNOTSUPP;
-
-	/* Just do it */
-	memcpy(&(spydata->spy_thr_low), &(threshold->low),
-	       2 * sizeof(struct iw_quality));
-
-	/* Clear flag */
-	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
-#endif	/* WE_SPY_DEBUG */
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get spy threshold
- */
-int iw_handler_get_thrspy(struct net_device *	dev,
-			  struct iw_request_info *info,
-			  union iwreq_data *	wrqu,
-			  char *		extra)
-{
-	struct iw_spy_data *	spydata = get_spydata(dev);
-	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
-
-	/* Make sure driver is not buggy or using the old API */
-	if(!spydata)
-		return -EOPNOTSUPP;
-
-	/* Just do it */
-	memcpy(&(threshold->low), &(spydata->spy_thr_low),
-	       2 * sizeof(struct iw_quality));
-
-	return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare and send a Spy Threshold event
- */
-static void iw_send_thrspy_event(struct net_device *	dev,
-				 struct iw_spy_data *	spydata,
-				 unsigned char *	address,
-				 struct iw_quality *	wstats)
-{
-	union iwreq_data	wrqu;
-	struct iw_thrspy	threshold;
-
-	/* Init */
-	wrqu.data.length = 1;
-	wrqu.data.flags = 0;
-	/* Copy address */
-	memcpy(threshold.addr.sa_data, address, ETH_ALEN);
-	threshold.addr.sa_family = ARPHRD_ETHER;
-	/* Copy stats */
-	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
-	/* Copy also thresholds */
-	memcpy(&(threshold.low), &(spydata->spy_thr_low),
-	       2 * sizeof(struct iw_quality));
-
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
-	       threshold.addr.sa_data[0],
-	       threshold.addr.sa_data[1],
-	       threshold.addr.sa_data[2],
-	       threshold.addr.sa_data[3],
-	       threshold.addr.sa_data[4],
-	       threshold.addr.sa_data[5], threshold.qual.level);
-#endif	/* WE_SPY_DEBUG */
-
-	/* Send event to user space */
-	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call for the driver to update the spy data.
- * For now, the spy data is a simple array. As the size of the array is
- * small, this is good enough. If we wanted to support larger number of
- * spy addresses, we should use something more efficient...
- */
-void wireless_spy_update(struct net_device *	dev,
-			 unsigned char *	address,
-			 struct iw_quality *	wstats)
-{
-	struct iw_spy_data *	spydata = get_spydata(dev);
-	int			i;
-	int			match = -1;
-
-	/* Make sure driver is not buggy or using the old API */
-	if(!spydata)
-		return;
-
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "wireless_spy_update() :  wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
-#endif	/* WE_SPY_DEBUG */
-
-	/* Update all records that match */
-	for(i = 0; i < spydata->spy_number; i++)
-		if(!compare_ether_addr(address, spydata->spy_address[i])) {
-			memcpy(&(spydata->spy_stat[i]), wstats,
-			       sizeof(struct iw_quality));
-			match = i;
-		}
-
-	/* Generate an event if we cross the spy threshold.
-	 * To avoid event storms, we have a simple hysteresis : we generate
-	 * event only when we go under the low threshold or above the
-	 * high threshold. */
-	if(match >= 0) {
-		if(spydata->spy_thr_under[match]) {
-			if(wstats->level > spydata->spy_thr_high.level) {
-				spydata->spy_thr_under[match] = 0;
-				iw_send_thrspy_event(dev, spydata,
-						     address, wstats);
-			}
-		} else {
-			if(wstats->level < spydata->spy_thr_low.level) {
-				spydata->spy_thr_under[match] = 1;
-				iw_send_thrspy_event(dev, spydata,
-						     address, wstats);
-			}
-		}
-	}
-}
-
-EXPORT_SYMBOL(iw_handler_get_spy);
-EXPORT_SYMBOL(iw_handler_get_thrspy);
-EXPORT_SYMBOL(iw_handler_set_spy);
-EXPORT_SYMBOL(iw_handler_set_thrspy);
-EXPORT_SYMBOL(wireless_send_event);
-EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index a086c63..01030f3 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -157,7 +157,7 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
 
 	if (av != NULL) {
 		av->dccpav_buf_head	= DCCP_MAX_ACKVEC_LEN - 1;
-		av->dccpav_buf_ackno	= DCCP_MAX_SEQNO + 1;
+		av->dccpav_buf_ackno	= UINT48_MAX + 1;
 		av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
 		av->dccpav_time.tv_sec	= 0;
 		av->dccpav_time.tv_usec	= 0;
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 746f79d..d7d9ce7 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -33,7 +33,6 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
 #include "../ccid.h"
 #include "../dccp.h"
 #include "lib/packet_history.h"
@@ -52,6 +51,9 @@ static struct dccp_tx_hist *ccid3_tx_his
 static struct dccp_rx_hist *ccid3_rx_hist;
 static struct dccp_li_hist *ccid3_li_hist;
 
+/*
+ *	Transmitter Half-Connection Routines
+ */
 #ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
 {
@@ -80,23 +82,37 @@ static void ccid3_hc_tx_set_state(struct
 }
 
 /*
- * Recalculate scheduled nominal send time t_nom, inter-packet interval
- * t_ipi, and delta value. Should be called after each change to X.
+ * Compute the initial sending rate X_init according to RFC 3390:
+ *	w_init   =    min(4 * MSS, max(2 * MSS, 4380 bytes))
+ *	X_init   =    w_init / RTT
+ * For consistency with other parts of the code, X_init is scaled by 2^6.
  */
-static inline void ccid3_update_send_time(struct ccid3_hc_tx_sock *hctx)
+static inline u64 rfc3390_initial_rate(struct sock *sk)
 {
-	timeval_sub_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
+	const struct dccp_sock *dp = dccp_sk(sk);
+	const __u32 w_init = min(4 * dp->dccps_mss_cache,
+				 max(2 * dp->dccps_mss_cache, 4380U));
 
-	/* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
-	hctx->ccid3hctx_t_ipi = scaled_div(hctx->ccid3hctx_s,
-					   hctx->ccid3hctx_x >> 6);
+	return scaled_div(w_init << 6, ccid3_hc_tx_sk(sk)->ccid3hctx_rtt);
+}
 
-	/* Update nominal send time with regard to the new t_ipi */
-	timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
+/*
+ * Recalculate t_ipi and delta (should be called whenever X changes)
+ */
+static inline void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx)
+{
+	/* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
+	hctx->ccid3hctx_t_ipi = scaled_div32(((u64)hctx->ccid3hctx_s) << 6,
+					     hctx->ccid3hctx_x);
 
 	/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
 	hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,
 					   TFRC_OPSYS_HALF_TIME_GRAN);
+
+	ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n",
+		       hctx->ccid3hctx_t_ipi, hctx->ccid3hctx_delta,
+		       hctx->ccid3hctx_s, (unsigned)(hctx->ccid3hctx_x >> 6));
+
 }
 /*
  * Update X by
@@ -112,19 +128,28 @@ static inline void ccid3_update_send_tim
  *       fine-grained resolution of sending rates. This requires scaling by 2^6
  *       throughout the code. Only X_calc is unscaled (in bytes/second).
  *
- * If X has changed, we also update the scheduled send time t_now,
- * the inter-packet interval t_ipi, and the delta value.
  */
 static void ccid3_hc_tx_update_x(struct sock *sk, struct timeval *now)
 
 {
 	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+	__u64 min_rate = 2 * hctx->ccid3hctx_x_recv;
 	const  __u64 old_x = hctx->ccid3hctx_x;
 
+	/*
+	 * Handle IDLE periods: do not reduce below RFC3390 initial sending rate
+	 * when idling [RFC 4342, 5.1]. See also draft-ietf-dccp-rfc3448bis.
+	 * For consistency with X and X_recv, min_rate is also scaled by 2^6.
+	 */
+	if (unlikely(hctx->ccid3hctx_idle)) {
+		min_rate = rfc3390_initial_rate(sk);
+		min_rate = max(min_rate, 2 * hctx->ccid3hctx_x_recv);
+	}
+
 	if (hctx->ccid3hctx_p > 0) {
 
 		hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6,
-					hctx->ccid3hctx_x_recv * 2);
+					min_rate);
 		hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
 					(((__u64)hctx->ccid3hctx_s) << 6) /
 								TFRC_T_MBI);
@@ -133,14 +158,21 @@ static void ccid3_hc_tx_update_x(struct 
 			(suseconds_t)hctx->ccid3hctx_rtt >= 0) {
 
 		hctx->ccid3hctx_x =
-			max(2 * min(hctx->ccid3hctx_x, hctx->ccid3hctx_x_recv),
+			max(min(2 * hctx->ccid3hctx_x, min_rate),
 			    scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
 				       hctx->ccid3hctx_rtt));
 		hctx->ccid3hctx_t_ld = *now;
 	}
 
-	if (hctx->ccid3hctx_x != old_x)
-		ccid3_update_send_time(hctx);
+	if (hctx->ccid3hctx_x != old_x) {
+		ccid3_pr_debug("X_prev=%u, X_now=%u, X_calc=%u, "
+			       "X_recv=%u\n", (unsigned)(old_x >> 6),
+			       (unsigned)(hctx->ccid3hctx_x >> 6),
+			       hctx->ccid3hctx_x_calc,
+			       (unsigned)(hctx->ccid3hctx_x_recv >> 6));
+
+		ccid3_update_send_interval(hctx);
+	}
 }
 
 /*
@@ -149,17 +181,12 @@ static void ccid3_hc_tx_update_x(struct 
  */
 static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
 {
-	if (unlikely(len == 0))
-		ccid3_pr_debug("Packet payload length is 0 - not updating\n");
-	else
-		hctx->ccid3hctx_s = hctx->ccid3hctx_s == 0 ? len :
-				    (9 * hctx->ccid3hctx_s + len) / 10;
-	/*
-	 * Note: We could do a potential optimisation here - when `s' changes,
-	 *	 recalculate sending rate and consequently t_ipi, t_delta, and
-	 *	 t_now. This is however non-standard, and the benefits are not
-	 *	 clear, so it is currently left out.
-	 */
+	const u16 old_s = hctx->ccid3hctx_s;
+
+	hctx->ccid3hctx_s = old_s == 0 ? len : (9 * old_s + len) / 10;
+
+	if (hctx->ccid3hctx_s != old_s)
+		ccid3_update_send_interval(hctx);
 }
 
 /*
@@ -193,6 +220,7 @@ static void ccid3_hc_tx_no_feedback_time
 {
 	struct sock *sk = (struct sock *)data;
 	struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+	struct timeval now;
 	unsigned long t_nfb = USEC_PER_SEC / 5;
 
 	bh_lock_sock(sk);
@@ -205,6 +233,8 @@ static void ccid3_hc_tx_no_feedback_time
 	ccid3_pr_debug("%s(%p, state=%s) - entry \n", dccp_role(sk), sk,
 		       ccid3_tx_state_name(hctx->ccid3hctx_state));
 
+	hctx->ccid3hctx_idle = 1;
+
 	switch (hctx->ccid3hctx_state) {
 	case TFRC_SSTATE_NO_FBACK:
 		/* RFC 3448, 4.4: Halve send rate directly */
@@ -219,53 +249,37 @@ static void ccid3_hc_tx_no_feedback_time
 		/* The value of R is still undefined and so we can not recompute
 		 * the timout value. Keep initial value as per [RFC 4342, 5]. */
 		t_nfb = TFRC_INITIAL_TIMEOUT;
-		ccid3_update_send_time(hctx);
+		ccid3_update_send_interval(hctx);
 		break;
 	case TFRC_SSTATE_FBACK:
 		/*
-		 * Check if IDLE since last timeout and recv rate is less than
-		 * 4 packets (in units of 64*bytes/sec) per RTT
+		 *  Modify the cached value of X_recv [RFC 3448, 4.4]
+		 *
+		 *  If (p == 0 || X_calc > 2 * X_recv)
+		 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
+		 *  Else
+		 *    X_recv = X_calc / 4;
+		 *
+		 *  Note that X_recv is scaled by 2^6 while X_calc is not
 		 */
-		if (!hctx->ccid3hctx_idle ||
-		    (hctx->ccid3hctx_x_recv >= 4 *
-		     scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
-				hctx->ccid3hctx_rtt))) {
-			struct timeval now;
+		BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
 
-			ccid3_pr_debug("%s(%p, state=%s), not idle\n",
-				       dccp_role(sk), sk,
-				   ccid3_tx_state_name(hctx->ccid3hctx_state));
+		if (hctx->ccid3hctx_p == 0 ||
+		    (hctx->ccid3hctx_x_calc > (hctx->ccid3hctx_x_recv >> 5))) {
 
-			/*
-			 *  Modify the cached value of X_recv [RFC 3448, 4.4]
-			 *
-			 *  If (p == 0 || X_calc > 2 * X_recv)
-			 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
-			 *  Else
-			 *    X_recv = X_calc / 4;
-			 *
-			 *  Note that X_recv is scaled by 2^6 while X_calc is not
-			 */
-			BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
-
-			if (hctx->ccid3hctx_p  == 0 ||
-			    (hctx->ccid3hctx_x_calc >
-			     (hctx->ccid3hctx_x_recv >> 5))) {
-
-				hctx->ccid3hctx_x_recv =
-					max(hctx->ccid3hctx_x_recv / 2,
-					    (((__u64)hctx->ccid3hctx_s) << 6) /
-							  (2 * TFRC_T_MBI));
-
-				if (hctx->ccid3hctx_p == 0)
-					dccp_timestamp(sk, &now);
-			} else {
-				hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
-				hctx->ccid3hctx_x_recv <<= 4;
-			}
-			/* Now recalculate X [RFC 3448, 4.3, step (4)] */
-			ccid3_hc_tx_update_x(sk, &now);
+			hctx->ccid3hctx_x_recv =
+				max(hctx->ccid3hctx_x_recv / 2,
+				    (((__u64)hctx->ccid3hctx_s) << 6) /
+							      (2 * TFRC_T_MBI));
+
+			if (hctx->ccid3hctx_p == 0)
+				dccp_timestamp(sk, &now);
+		} else {
+			hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
+			hctx->ccid3hctx_x_recv <<= 4;
 		}
+		/* Now recalculate X [RFC 3448, 4.3, step (4)] */
+		ccid3_hc_tx_update_x(sk, &now);
 		/*
 		 * Schedule no feedback timer to expire in
 		 * max(t_RTO, 2 * s/X)  =  max(t_RTO, 2 * t_ipi)
@@ -280,8 +294,6 @@ static void ccid3_hc_tx_no_feedback_time
 		goto out;
 	}
 
-	hctx->ccid3hctx_idle = 1;
-
 restart_timer:
 	sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
 			   jiffies + usecs_to_jiffies(t_nfb));
@@ -322,24 +334,35 @@ static int ccid3_hc_tx_send_packet(struc
 				usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
 		hctx->ccid3hctx_last_win_count	 = 0;
 		hctx->ccid3hctx_t_last_win_count = now;
-		ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
-
-		/* Set initial sending rate X/s to 1pps (X is scaled by 2^6) */
-		ccid3_hc_tx_update_s(hctx, skb->len);
-		hctx->ccid3hctx_x = hctx->ccid3hctx_s;
-		hctx->ccid3hctx_x <<= 6;
-
-		/* First timeout, according to [RFC 3448, 4.2], is 1 second */
-		hctx->ccid3hctx_t_ipi = USEC_PER_SEC;
-		/* Initial delta: minimum of 0.5 sec and t_gran/2 */
-		hctx->ccid3hctx_delta = TFRC_OPSYS_HALF_TIME_GRAN;
 
 		/* Set t_0 for initial packet */
 		hctx->ccid3hctx_t_nom = now;
+
+		hctx->ccid3hctx_s = skb->len;
+
+		/*
+		 * Use initial RTT sample when available: recommended by erratum
+		 * to RFC 4342. This implements the initialisation procedure of
+		 * draft rfc3448bis, section 4.2. Remember, X is scaled by 2^6.
+		 */
+		if (dp->dccps_syn_rtt) {
+			ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt);
+			hctx->ccid3hctx_rtt  = dp->dccps_syn_rtt;
+			hctx->ccid3hctx_x    = rfc3390_initial_rate(sk);
+			hctx->ccid3hctx_t_ld = now;
+		} else {
+			/* Sender does not have RTT sample: X = MSS/second */
+			hctx->ccid3hctx_x = dp->dccps_mss_cache;
+			hctx->ccid3hctx_x <<= 6;
+		}
+		ccid3_update_send_interval(hctx);
+
+		ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
 		break;
 	case TFRC_SSTATE_NO_FBACK:
 	case TFRC_SSTATE_FBACK:
 		delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now);
+		ccid3_pr_debug("delay=%ld\n", (long)delay);
 		/*
 		 *	Scheduling of packet transmissions [RFC 3448, 4.6]
 		 *
@@ -361,6 +384,7 @@ static int ccid3_hc_tx_send_packet(struc
 	/* prepare to send now (add options etc.) */
 	dp->dccps_hc_tx_insert_options = 1;
 	DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+	hctx->ccid3hctx_idle = 0;
 
 	/* set the nominal send time for the next following packet */
 	timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
@@ -391,7 +415,6 @@ static void ccid3_hc_tx_packet_sent(stru
 	packet->dccphtx_seqno  = dccp_sk(sk)->dccps_gss;
 	packet->dccphtx_rtt    = hctx->ccid3hctx_rtt;
 	packet->dccphtx_sent   = 1;
-	hctx->ccid3hctx_idle   = 0;
 }
 
 static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
@@ -402,8 +425,7 @@ static void ccid3_hc_tx_packet_recv(stru
 	struct dccp_tx_hist_entry *packet;
 	struct timeval now;
 	unsigned long t_nfb;
-	u32 pinv;
-	suseconds_t r_sample, t_elapsed;
+	u32 pinv, r_sample;
 
 	BUG_ON(hctx == NULL);
 
@@ -445,18 +467,10 @@ static void ccid3_hc_tx_packet_recv(stru
 		 * Calculate new round trip sample as per [RFC 3448, 4.3] by
 		 *	R_sample  =  (now - t_recvdata) - t_elapsed
 		 */
-		r_sample  = timeval_delta(&now, &packet->dccphtx_tstamp);
-		t_elapsed = dp->dccps_options_received.dccpor_elapsed_time * 10;
-
-		DCCP_BUG_ON(r_sample < 0);
-		if (unlikely(r_sample <= t_elapsed))
-			DCCP_WARN("WARNING: r_sample=%dus <= t_elapsed=%dus\n",
-				  (int)r_sample, (int)t_elapsed);
-		else
-			r_sample -= t_elapsed;
-		CCID3_RTT_SANITY_CHECK(r_sample);
+		r_sample = dccp_sample_rtt(sk, &now, &packet->dccphtx_tstamp);
 
-		/* Update RTT estimate by
+		/*
+		 * Update RTT estimate by
 		 * If (No feedback recv)
 		 *    R = R_sample;
 		 * Else
@@ -467,27 +481,23 @@ static void ccid3_hc_tx_packet_recv(stru
 		if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
 			/*
 			 * Larger Initial Windows [RFC 4342, sec. 5]
-			 * We deviate in that we use `s' instead of `MSS'.
 			 */
-			__u64 w_init = min(4 * hctx->ccid3hctx_s,
-					   max(2 * hctx->ccid3hctx_s, 4380));
 			hctx->ccid3hctx_rtt  = r_sample;
-			hctx->ccid3hctx_x    = scaled_div(w_init << 6, r_sample);
+			hctx->ccid3hctx_x    = rfc3390_initial_rate(sk);
 			hctx->ccid3hctx_t_ld = now;
 
-			ccid3_update_send_time(hctx);
+			ccid3_update_send_interval(hctx);
 
-			ccid3_pr_debug("%s(%p), s=%u, w_init=%llu, "
-				       "R_sample=%dus, X=%u\n", dccp_role(sk),
+			ccid3_pr_debug("%s(%p), s=%u, MSS=%u, "
+				       "R_sample=%uus, X=%u\n", dccp_role(sk),
 				       sk, hctx->ccid3hctx_s,
-				       (unsigned long long)w_init,
-				       (int)r_sample,
+				       dp->dccps_mss_cache, r_sample,
 				       (unsigned)(hctx->ccid3hctx_x >> 6));
 
 			ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
 		} else {
 			hctx->ccid3hctx_rtt = (9 * hctx->ccid3hctx_rtt +
-						   (u32)r_sample) / 10;
+						   r_sample) / 10;
 
 			/* Update sending rate (step 4 of [RFC 3448, 4.3]) */
 			if (hctx->ccid3hctx_p > 0)
@@ -497,10 +507,10 @@ static void ccid3_hc_tx_packet_recv(stru
 						    hctx->ccid3hctx_p);
 			ccid3_hc_tx_update_x(sk, &now);
 
-			ccid3_pr_debug("%s(%p), RTT=%uus (sample=%dus), s=%u, "
+			ccid3_pr_debug("%s(%p), RTT=%uus (sample=%uus), s=%u, "
 				       "p=%u, X_calc=%u, X_recv=%u, X=%u\n",
 				       dccp_role(sk),
-				       sk, hctx->ccid3hctx_rtt, (int)r_sample,
+				       sk, hctx->ccid3hctx_rtt, r_sample,
 				       hctx->ccid3hctx_s, hctx->ccid3hctx_p,
 				       hctx->ccid3hctx_x_calc,
 				       (unsigned)(hctx->ccid3hctx_x_recv >> 6),
@@ -644,10 +654,50 @@ static void ccid3_hc_tx_exit(struct sock
 	dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
 }
 
+static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
+{
+	const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+
+	/* Listen socks doesn't have a private CCID block */
+	if (sk->sk_state == DCCP_LISTEN)
+		return;
+
+	BUG_ON(hctx == NULL);
+
+	info->tcpi_rto = hctx->ccid3hctx_t_rto;
+	info->tcpi_rtt = hctx->ccid3hctx_rtt;
+}
+
+static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
+				  u32 __user *optval, int __user *optlen)
+{
+	const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+	const void *val;
+
+	/* Listen socks doesn't have a private CCID block */
+	if (sk->sk_state == DCCP_LISTEN)
+		return -EINVAL;
+
+	switch (optname) {
+	case DCCP_SOCKOPT_CCID_TX_INFO:
+		if (len < sizeof(hctx->ccid3hctx_tfrc))
+			return -EINVAL;
+		len = sizeof(hctx->ccid3hctx_tfrc);
+		val = &hctx->ccid3hctx_tfrc;
+		break;
+	default:
+		return -ENOPROTOOPT;
+	}
+
+	if (put_user(len, optlen) || copy_to_user(optval, val, len))
+		return -EFAULT;
+
+	return 0;
+}
+
 /*
- * RX Half Connection methods
+ *	Receiver Half-Connection Routines
  */
-
 #ifdef CONFIG_IP_DCCP_CCID3_DEBUG
 static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
 {
@@ -977,8 +1027,7 @@ static void ccid3_hc_rx_packet_recv(stru
 	const struct dccp_options_received *opt_recv;
 	struct dccp_rx_hist_entry *packet;
 	struct timeval now;
-	u32 p_prev, rtt_prev;
-	suseconds_t r_sample, t_elapsed;
+	u32 p_prev, r_sample, rtt_prev;
 	int loss, payload_size;
 
 	BUG_ON(hcrx == NULL);
@@ -994,17 +1043,7 @@ static void ccid3_hc_rx_packet_recv(stru
 			break;
 		rtt_prev = hcrx->ccid3hcrx_rtt;
 		dccp_timestamp(sk, &now);
-		timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10);
-		r_sample = timeval_usecs(&now);
-		t_elapsed = opt_recv->dccpor_elapsed_time * 10;
-
-		DCCP_BUG_ON(r_sample < 0);
-		if (unlikely(r_sample <= t_elapsed))
-			DCCP_WARN("r_sample=%ldus, t_elapsed=%ldus\n",
-				  (long)r_sample, (long)t_elapsed);
-		else
-			r_sample -= t_elapsed;
-		CCID3_RTT_SANITY_CHECK(r_sample);
+		r_sample = dccp_sample_rtt(sk, &now, NULL);
 
 		if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
 			hcrx->ccid3hcrx_rtt = r_sample;
@@ -1132,20 +1171,6 @@ static void ccid3_hc_rx_get_info(struct 
 	info->tcpi_rcv_rtt  = hcrx->ccid3hcrx_rtt;
 }
 
-static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
-{
-	const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-
-	/* Listen socks doesn't have a private CCID block */
-	if (sk->sk_state == DCCP_LISTEN)
-		return;
-
-	BUG_ON(hctx == NULL);
-
-	info->tcpi_rto = hctx->ccid3hctx_t_rto;
-	info->tcpi_rtt = hctx->ccid3hctx_rtt;
-}
-
 static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
 				  u32 __user *optval, int __user *optlen)
 {
@@ -1173,33 +1198,6 @@ static int ccid3_hc_rx_getsockopt(struct
 	return 0;
 }
 
-static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
-				  u32 __user *optval, int __user *optlen)
-{
-	const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
-	const void *val;
-
-	/* Listen socks doesn't have a private CCID block */
-	if (sk->sk_state == DCCP_LISTEN)
-		return -EINVAL;
-
-	switch (optname) {
-	case DCCP_SOCKOPT_CCID_TX_INFO:
-		if (len < sizeof(hctx->ccid3hctx_tfrc))
-			return -EINVAL;
-		len = sizeof(hctx->ccid3hctx_tfrc);
-		val = &hctx->ccid3hctx_tfrc;
-		break;
-	default:
-		return -ENOPROTOOPT;
-	}
-
-	if (put_user(len, optlen) || copy_to_user(optval, val, len))
-		return -EFAULT;
-
-	return 0;
-}
-
 static struct ccid_operations ccid3 = {
 	.ccid_id		   = DCCPC_CCID3,
 	.ccid_name		   = "ccid3",
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index 15776a8..8d31b38 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -51,16 +51,6 @@ #define TFRC_OPSYS_HALF_TIME_GRAN  (USEC
 /* Parameter t_mbi from [RFC 3448, 4.3]: backoff interval in seconds */
 #define TFRC_T_MBI		   64
 
-/* What we think is a reasonable upper limit on RTT values */
-#define CCID3_SANE_RTT_MAX	   ((suseconds_t)(4 * USEC_PER_SEC))
-
-#define CCID3_RTT_SANITY_CHECK(rtt) 			do {		   \
-		if (rtt > CCID3_SANE_RTT_MAX) {				   \
-			DCCP_CRIT("RTT (%d) too large, substituting %d",   \
-				  (int)rtt, (int)CCID3_SANE_RTT_MAX);	   \
-			rtt = CCID3_SANE_RTT_MAX;			   \
-		} 					} while (0)
-
 enum ccid3_options {
 	TFRC_OPT_LOSS_EVENT_RATE = 192,
 	TFRC_OPT_LOSS_INTERVALS	 = 193,
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index 0a0baef..372d7e7 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -91,7 +91,7 @@ u32 dccp_li_hist_calc_i_mean(struct list
 	u32 w_tot  = 0;
 
 	list_for_each_entry_safe(li_entry, li_next, list, dccplih_node) {
-		if (li_entry->dccplih_interval != ~0) {
+		if (li_entry->dccplih_interval != ~0U) {
 			i_tot0 += li_entry->dccplih_interval * dccp_li_hist_w[i];
 			w_tot  += dccp_li_hist_w[i];
 			if (i != 0)
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index e33a9ed..d8ad27b 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -31,13 +31,9 @@ #define DCCP_BUG_ON(cond)    do { if (un
 					      __stringify(cond));          \
 			     } while (0)
 
-#ifdef MODULE
 #define DCCP_PRINTK(enable, fmt, args...)	do { if (enable)	     \
 							printk(fmt, ##args); \
 						} while(0)
-#else
-#define DCCP_PRINTK(enable, fmt, args...)	printk(fmt, ##args)
-#endif
 #define DCCP_PR_DEBUG(enable, fmt, a...)	DCCP_PRINTK(enable, KERN_DEBUG \
 						  "%s: " fmt, __FUNCTION__, ##a)
 
@@ -75,11 +71,15 @@ #define DCCP_TIMEWAIT_LEN (60 * HZ) /* h
 /* RFC 1122, 4.2.3.1 initial RTO value */
 #define DCCP_TIMEOUT_INIT ((unsigned)(3 * HZ))
 
+#define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
+
+/* bounds for sampled RTT values from packet exchanges (in usec) */
+#define DCCP_SANE_RTT_MIN	100
+#define DCCP_SANE_RTT_MAX	(4 * USEC_PER_SEC)
+
 /* Maximal interval between probes for local resources.  */
 #define DCCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ / 2U))
 
-#define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */
-
 /* sysctl variables for DCCP */
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
@@ -92,17 +92,43 @@ extern int  sysctl_dccp_feat_send_ack_ve
 extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 
+/*
+ *	48-bit sequence number arithmetic (signed and unsigned)
+ */
+#define INT48_MIN	  0x800000000000LL		/* 2^47	    */
+#define UINT48_MAX	  0xFFFFFFFFFFFFLL		/* 2^48 - 1 */
+#define COMPLEMENT48(x)	 (0x1000000000000LL - (x))	/* 2^48 - x */
+#define TO_SIGNED48(x)	 (((x) < INT48_MIN)? (x) : -COMPLEMENT48( (x)))
+#define TO_UNSIGNED48(x) (((x) >= 0)?	     (x) :  COMPLEMENT48(-(x)))
+#define ADD48(a, b)	 (((a) + (b)) & UINT48_MAX)
+#define SUB48(a, b)	 ADD48((a), COMPLEMENT48(b))
+
+static inline void dccp_set_seqno(u64 *seqno, u64 value)
+{
+	*seqno = value & UINT48_MAX;
+}
+
+static inline void dccp_inc_seqno(u64 *seqno)
+{
+	*seqno = ADD48(*seqno, 1);
+}
+
+/* signed mod-2^48 distance: pos. if seqno1 < seqno2, neg. if seqno1 > seqno2 */
+static inline s64 dccp_delta_seqno(const u64 seqno1, const u64 seqno2)
+{
+	u64 delta = SUB48(seqno2, seqno1);
+
+	return TO_SIGNED48(delta);
+}
+
 /* is seq1 < seq2 ? */
 static inline int before48(const u64 seq1, const u64 seq2)
 {
-	return (s64)((seq1 << 16) - (seq2 << 16)) < 0;
+	return (s64)((seq2 << 16) - (seq1 << 16)) > 0;
 }
 
 /* is seq1 > seq2 ? */
-static inline int after48(const u64 seq1, const u64 seq2)
-{
-	return (s64)((seq2 << 16) - (seq1 << 16)) < 0;
-}
+#define after48(seq1, seq2)	before48(seq2, seq1)
 
 /* is seq2 <= seq1 <= seq3 ? */
 static inline int between48(const u64 seq1, const u64 seq2, const u64 seq3)
@@ -118,9 +144,7 @@ static inline u64 max48(const u64 seq1, 
 /* is seq1 next seqno after seq2 */
 static inline int follows48(const u64 seq1, const u64 seq2)
 {
-	int diff = (seq1 & 0xFFFF) - (seq2 & 0xFFFF);
-
-	return diff==1;
+	return dccp_delta_seqno(seq2, seq1) == 1;
 }
 
 enum {
@@ -272,6 +296,8 @@ extern int	   dccp_v4_connect(struct soc
 extern int	   dccp_send_reset(struct sock *sk, enum dccp_reset_codes code);
 extern void	   dccp_send_close(struct sock *sk, const int active);
 extern int	   dccp_invalid_packet(struct sk_buff *skb);
+extern u32	   dccp_sample_rtt(struct sock *sk, struct timeval *t_recv,
+						    struct timeval *t_history);
 
 static inline int dccp_bad_service_code(const struct sock *sk,
 					const __be32 service)
@@ -313,26 +339,7 @@ static inline int dccp_packet_without_ac
 	return type == DCCP_PKT_DATA || type == DCCP_PKT_REQUEST;
 }
 
-#define DCCP_MAX_SEQNO ((((u64)1) << 48) - 1)
-#define DCCP_PKT_WITHOUT_ACK_SEQ (DCCP_MAX_SEQNO << 2)
-
-static inline void dccp_set_seqno(u64 *seqno, u64 value)
-{
-	if (value > DCCP_MAX_SEQNO)
-		value -= DCCP_MAX_SEQNO + 1;
-	*seqno = value;
-}
-
-static inline u64 dccp_delta_seqno(u64 seqno1, u64 seqno2)
-{
-	return ((seqno2 << 16) - (seqno1 << 16)) >> 16;
-}
-
-static inline void dccp_inc_seqno(u64 *seqno)
-{
-	if (++*seqno > DCCP_MAX_SEQNO)
-		*seqno = 0;
-}
+#define DCCP_PKT_WITHOUT_ACK_SEQ (UINT48_MAX << 2)
 
 static inline void dccp_hdr_set_seq(struct dccp_hdr *dh, const u64 gss)
 {
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 78b043c..da6ec18 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -86,7 +86,8 @@ static int dccp_check_seqno(struct sock 
 	    dh->dccph_type == DCCP_PKT_SYNCACK) {
 		if (between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
 			      dp->dccps_awl, dp->dccps_awh) &&
-		    !before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_swl))
+		    dccp_delta_seqno(dp->dccps_swl,
+				     DCCP_SKB_CB(skb)->dccpd_seq) >= 0)
 			dccp_update_gsr(sk, DCCP_SKB_CB(skb)->dccpd_seq);
 		else
 			return -1;
@@ -203,7 +204,8 @@ static int __dccp_rcv_established(struct
 		if (dp->dccps_role != DCCP_ROLE_CLIENT)
 			goto send_sync;
 check_seq:
-		if (!before48(DCCP_SKB_CB(skb)->dccpd_seq, dp->dccps_osr)) {
+		if (dccp_delta_seqno(dp->dccps_osr,
+				     DCCP_SKB_CB(skb)->dccpd_seq) >= 0) {
 send_sync:
 			dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq,
 				       DCCP_PKT_SYNC);
@@ -298,6 +300,14 @@ static int dccp_rcv_request_sent_state_p
 		if (dccp_parse_options(sk, skb))
 			goto out_invalid_packet;
 
+		/* Obtain RTT sample from SYN exchange (used by CCID 3) */
+		if (dp->dccps_options_received.dccpor_timestamp_echo) {
+			struct timeval now;
+
+			dccp_timestamp(sk, &now);
+			dp->dccps_syn_rtt = dccp_sample_rtt(sk, &now, NULL);
+		}
+
 		if (dccp_msk(sk)->dccpms_send_ack_vector &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
@@ -575,3 +585,43 @@ discard:
 }
 
 EXPORT_SYMBOL_GPL(dccp_rcv_state_process);
+
+/**
+ * dccp_sample_rtt  -  Sample RTT from packet exchange
+ *
+ * @sk:     connected dccp_sock
+ * @t_recv: receive timestamp of packet with timestamp echo
+ * @t_hist: packet history timestamp or NULL
+ */
+u32 dccp_sample_rtt(struct sock *sk, struct timeval *t_recv,
+				     struct timeval *t_hist)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_options_received *or = &dp->dccps_options_received;
+	suseconds_t delta;
+
+	if (t_hist == NULL) {
+		if (!or->dccpor_timestamp_echo) {
+			DCCP_WARN("packet without timestamp echo\n");
+			return DCCP_SANE_RTT_MAX;
+		}
+		timeval_sub_usecs(t_recv, or->dccpor_timestamp_echo * 10);
+		delta = timeval_usecs(t_recv);
+	} else
+		delta = timeval_delta(t_recv, t_hist);
+
+	delta -= or->dccpor_elapsed_time * 10;		/* either set or 0 */
+
+	if (unlikely(delta <= 0)) {
+		DCCP_WARN("unusable RTT sample %ld, using min\n", (long)delta);
+		return DCCP_SANE_RTT_MIN;
+	}
+	if (unlikely(delta - (suseconds_t)DCCP_SANE_RTT_MAX > 0)) {
+		DCCP_WARN("RTT sample %ld too large, using max\n", (long)delta);
+		return DCCP_SANE_RTT_MAX;
+	}
+
+	return delta;
+}
+
+EXPORT_SYMBOL_GPL(dccp_sample_rtt);
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 4a83978..718f2fa 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -207,8 +207,8 @@ static void dccp_v4_err(struct sk_buff *
 							(iph->ihl << 2));
 	struct dccp_sock *dp;
 	struct inet_sock *inet;
-	const int type = skb->h.icmph->type;
-	const int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct sock *sk;
 	__u64 seq;
 	int err;
@@ -363,8 +363,8 @@ EXPORT_SYMBOL_GPL(dccp_v4_send_check);
 
 static inline u64 dccp_v4_init_sequence(const struct sk_buff *skb)
 {
-	return secure_dccp_sequence_number(skb->nh.iph->daddr,
-					   skb->nh.iph->saddr,
+	return secure_dccp_sequence_number(ip_hdr(skb)->daddr,
+					   ip_hdr(skb)->saddr,
 					   dccp_hdr(skb)->dccph_dport,
 					   dccp_hdr(skb)->dccph_sport);
 }
@@ -405,7 +405,7 @@ struct sock *dccp_v4_request_recv_sock(s
 	newinet->opt	   = ireq->opt;
 	ireq->opt	   = NULL;
 	newinet->mc_index  = inet_iif(skb);
-	newinet->mc_ttl	   = skb->nh.iph->ttl;
+	newinet->mc_ttl	   = ip_hdr(skb)->ttl;
 	newinet->id	   = jiffies;
 
 	dccp_sync_mss(newsk, dst_mtu(dst));
@@ -428,7 +428,7 @@ EXPORT_SYMBOL_GPL(dccp_v4_request_recv_s
 static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
 	const struct dccp_hdr *dh = dccp_hdr(skb);
-	const struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 	struct sock *nsk;
 	struct request_sock **prev;
 	/* Find possible connection requests. */
@@ -460,8 +460,8 @@ static struct dst_entry* dccp_v4_route_s
 	struct rtable *rt;
 	struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
 			    .nl_u = { .ip4_u =
-				      { .daddr = skb->nh.iph->saddr,
-					.saddr = skb->nh.iph->daddr,
+				      { .daddr = ip_hdr(skb)->saddr,
+					.saddr = ip_hdr(skb)->daddr,
 					.tos = RT_CONN_FLAGS(sk) } },
 			    .proto = sk->sk_protocol,
 			    .uli_u = { .ports =
@@ -513,6 +513,7 @@ static void dccp_v4_ctl_send_reset(struc
 {
 	int err;
 	struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
+	const struct iphdr *rxiph;
 	const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
 				       sizeof(struct dccp_hdr_ext) +
 				       sizeof(struct dccp_hdr_reset);
@@ -559,13 +560,13 @@ static void dccp_v4_ctl_send_reset(struc
 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
 
 	dccp_csum_outgoing(skb);
-	dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr,
-						      rxskb->nh.iph->daddr);
+	rxiph = ip_hdr(rxskb);
+	dh->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr,
+						 rxiph->daddr);
 
 	bh_lock_sock(dccp_v4_ctl_socket->sk);
 	err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
-				    rxskb->nh.iph->daddr,
-				    rxskb->nh.iph->saddr, NULL);
+				    rxiph->daddr, rxiph->saddr, NULL);
 	bh_unlock_sock(dccp_v4_ctl_socket->sk);
 
 	if (net_xmit_eval(err) == 0) {
@@ -640,8 +641,8 @@ int dccp_v4_conn_request(struct sock *sk
 		goto drop_and_free;
 
 	ireq = inet_rsk(req);
-	ireq->loc_addr = skb->nh.iph->daddr;
-	ireq->rmt_addr = skb->nh.iph->saddr;
+	ireq->loc_addr = ip_hdr(skb)->daddr;
+	ireq->rmt_addr = ip_hdr(skb)->saddr;
 	ireq->opt	= NULL;
 
 	/*
@@ -809,6 +810,7 @@ EXPORT_SYMBOL_GPL(dccp_invalid_packet);
 static int dccp_v4_rcv(struct sk_buff *skb)
 {
 	const struct dccp_hdr *dh;
+	const struct iphdr *iph;
 	struct sock *sk;
 	int min_cov;
 
@@ -817,8 +819,9 @@ static int dccp_v4_rcv(struct sk_buff *s
 	if (dccp_invalid_packet(skb))
 		goto discard_it;
 
+	iph = ip_hdr(skb);
 	/* Step 1: If header checksum is incorrect, drop packet and return */
-	if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) {
+	if (dccp_v4_csum_finish(skb, iph->saddr, iph->daddr)) {
 		DCCP_WARN("dropped packet with invalid checksum\n");
 		goto discard_it;
 	}
@@ -832,8 +835,8 @@ static int dccp_v4_rcv(struct sk_buff *s
 		      "src=%u.%u.%u.%u@%-5d "
 		      "dst=%u.%u.%u.%u@%-5d seq=%llu",
 		      dccp_packet_name(dh->dccph_type),
-		      NIPQUAD(skb->nh.iph->saddr), ntohs(dh->dccph_sport),
-		      NIPQUAD(skb->nh.iph->daddr), ntohs(dh->dccph_dport),
+		      NIPQUAD(iph->saddr), ntohs(dh->dccph_sport),
+		      NIPQUAD(iph->daddr), ntohs(dh->dccph_dport),
 		      (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
 
 	if (dccp_packet_without_ack(skb)) {
@@ -848,10 +851,8 @@ static int dccp_v4_rcv(struct sk_buff *s
 	/* Step 2:
 	 *	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, dh->dccph_dport,
-			   inet_iif(skb));
-
+			   iph->saddr, dh->dccph_sport,
+			   iph->daddr, dh->dccph_dport, inet_iif(skb));
 	/*
 	 * Step 2:
 	 *	If no socket ...
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 7f51e8d..64eac25 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -84,8 +84,8 @@ static inline __u32 secure_dccpv6_sequen
 
 static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb)
 {
-	return secure_dccpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
-					     skb->nh.ipv6h->saddr.s6_addr32,
+	return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
+					     ipv6_hdr(skb)->saddr.s6_addr32,
 					     dccp_hdr(skb)->dccph_dport,
 					     dccp_hdr(skb)->dccph_sport     );
 
@@ -261,8 +261,8 @@ static int dccp_v6_send_response(struct 
 
 			if (rxopt->srcrt)
 				opt = ipv6_invert_rthdr(sk,
-					(struct ipv6_rt_hdr *)(pktopts->nh.raw +
-							       rxopt->srcrt));
+			  (struct ipv6_rt_hdr *)(skb_network_header(pktopts) +
+						 rxopt->srcrt));
 		}
 
 		if (opt != NULL && opt->srcrt != NULL) {
@@ -313,6 +313,7 @@ static void dccp_v6_reqsk_destructor(str
 static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
 {
 	struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
+	struct ipv6hdr *rxip6h;
 	const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
 				       sizeof(struct dccp_hdr_ext) +
 				       sizeof(struct dccp_hdr_reset);
@@ -352,12 +353,13 @@ static void dccp_v6_ctl_send_reset(struc
 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
 
 	dccp_csum_outgoing(skb);
-	dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxskb->nh.ipv6h->saddr,
-						      &rxskb->nh.ipv6h->daddr);
+	rxip6h = ipv6_hdr(rxskb);
+	dh->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,
+						      &rxip6h->daddr);
 
 	memset(&fl, 0, sizeof(fl));
-	ipv6_addr_copy(&fl.fl6_dst, &rxskb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&fl.fl6_src, &rxskb->nh.ipv6h->daddr);
+	ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr);
+	ipv6_addr_copy(&fl.fl6_src, &rxip6h->daddr);
 
 	fl.proto = IPPROTO_DCCP;
 	fl.oif = inet6_iif(rxskb);
@@ -390,7 +392,7 @@ static struct request_sock_ops dccp6_req
 static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 {
 	const struct dccp_hdr *dh = dccp_hdr(skb);
-	const struct ipv6hdr *iph = skb->nh.ipv6h;
+	const struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct sock *nsk;
 	struct request_sock **prev;
 	/* Find possible connection requests. */
@@ -460,8 +462,8 @@ static int dccp_v6_conn_request(struct s
 		goto drop_and_free;
 
 	ireq6 = inet6_rsk(req);
-	ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
+	ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
 	ireq6->pktopts	= NULL;
 
 	if (ipv6_opt_accepted(sk, skb) ||
@@ -546,7 +548,7 @@ static struct sock *dccp_v6_request_recv
 		newnp->pktoptions  = NULL;
 		newnp->opt	   = NULL;
 		newnp->mcast_oif   = inet6_iif(skb);
-		newnp->mcast_hops  = skb->nh.ipv6h->hop_limit;
+		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
 
 		/*
 		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
@@ -573,8 +575,8 @@ static struct sock *dccp_v6_request_recv
 
 		if (rxopt->srcrt)
 			opt = ipv6_invert_rthdr(sk,
-				(struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw +
-						       rxopt->srcrt));
+		   (struct ipv6_rt_hdr *)(skb_network_header(ireq6->pktopts) +
+					  rxopt->srcrt));
 	}
 
 	if (dst == NULL) {
@@ -653,7 +655,7 @@ static struct sock *dccp_v6_request_recv
 	}
 	newnp->opt	  = NULL;
 	newnp->mcast_oif  = inet6_iif(skb);
-	newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
+	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
 
 	/*
 	 * Clone native IPv6 options from listening socket (if any)
@@ -826,8 +828,8 @@ static int dccp_v6_rcv(struct sk_buff **
 		goto discard_it;
 
 	/* Step 1: If header checksum is incorrect, drop packet and return. */
-	if (dccp_v6_csum_finish(skb, &skb->nh.ipv6h->saddr,
-				     &skb->nh.ipv6h->daddr)) {
+	if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,
+				     &ipv6_hdr(skb)->daddr)) {
 		DCCP_WARN("dropped packet with invalid checksum\n");
 		goto discard_it;
 	}
@@ -844,9 +846,9 @@ static int dccp_v6_rcv(struct sk_buff **
 
 	/* Step 2:
 	 *	Look up flow ID in table and get corresponding socket */
-	sk = __inet6_lookup(&dccp_hashinfo, &skb->nh.ipv6h->saddr,
+	sk = __inet6_lookup(&dccp_hashinfo, &ipv6_hdr(skb)->saddr,
 			    dh->dccph_sport,
-			    &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport),
+			    &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
 			    inet6_iif(skb));
 	/*
 	 * Step 2:
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 6d235b3..e18e249 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -27,7 +27,7 @@ #include "feat.h"
 struct inet_timewait_death_row dccp_death_row = {
 	.sysctl_max_tw_buckets = NR_FILE * 2,
 	.period		= DCCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
-	.death_lock	= SPIN_LOCK_UNLOCKED,
+	.death_lock	= __SPIN_LOCK_UNLOCKED(dccp_death_row.death_lock),
 	.hashinfo	= &dccp_hashinfo,
 	.tw_timer	= TIMER_INITIALIZER(inet_twdr_hangman, 0,
 					    (unsigned long)&dccp_death_row),
diff --git a/net/dccp/options.c b/net/dccp/options.c
index ca13f77..34d536d 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -29,8 +29,6 @@ int sysctl_dccp_feat_ack_ratio	      = D
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-EXPORT_SYMBOL_GPL(sysctl_dccp_feat_sequence_window);
-
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
@@ -174,21 +172,25 @@ int dccp_parse_options(struct sock *sk, 
 			opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value);
 
 			dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
-				      "ackno=%llu, ",  dccp_role(sk),
+				      "ackno=%llu", dccp_role(sk),
 				      opt_recv->dccpor_timestamp_echo,
 				      len + 2,
 				      (unsigned long long)
 				      DCCP_SKB_CB(skb)->dccpd_ack_seq);
 
 
-			if (len == 4)
+			if (len == 4) {
+				dccp_pr_debug_cat("\n");
 				break;
+			}
 
 			if (len == 6)
 				elapsed_time = ntohs(*(__be16 *)(value + 4));
 			else
 				elapsed_time = ntohl(*(__be32 *)(value + 4));
 
+			dccp_pr_debug_cat(", ELAPSED_TIME=%d\n", elapsed_time);
+
 			/* Give precedence to the biggest ELAPSED_TIME */
 			if (elapsed_time > opt_recv->dccpor_elapsed_time)
 				opt_recv->dccpor_elapsed_time = elapsed_time;
@@ -565,6 +567,14 @@ int dccp_insert_options(struct sock *sk,
 	    dccp_insert_options_feat(sk, skb))
 		return -1;
 
+	/*
+	 * Obtain RTT sample from Request/Response exchange.
+	 * This is currently used in CCID 3 initialisation.
+	 */
+	if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
+	    dccp_insert_option_timestamp(sk, skb))
+		return -1;
+
 	/* XXX: insert other options when appropriate */
 
 	if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
diff --git a/net/dccp/output.c b/net/dccp/output.c
index aa21cc4..c8d843e 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -194,6 +194,7 @@ static int dccp_wait_for_ccid(struct soc
 		rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
 		if (rc <= 0)
 			break;
+		dccp_pr_debug("delayed send by %d msec\n", rc);
 		delay = msecs_to_jiffies(rc);
 		sk->sk_write_pending++;
 		release_sock(sk);
@@ -255,7 +256,7 @@ void dccp_write_xmit(struct sock *sk, in
 				DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
 					 err);
 		} else {
-			dccp_pr_debug("packet discarded\n");
+			dccp_pr_debug("packet discarded due to err=%d\n", err);
 			kfree_skb(skb);
 		}
 	}
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 3b1f509..1f5e3ba 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -90,15 +90,18 @@ static int jdccp_sendmsg(struct kiocb *i
 	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);
+			printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %u "
+			       "%llu %llu %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_x_calc,
+			       hctx->ccid3hctx_x_recv >> 6,
+			       hctx->ccid3hctx_x >> 6, 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);
+			       NIPQUAD(inet->saddr), ntohs(inet->sport),
+			       NIPQUAD(inet->daddr), ntohs(inet->dport), size);
 	}
 
 	jprobe_return();
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index c6568d6..9fbe87c 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -721,7 +721,7 @@ static int dn_bind(struct socket *sock, 
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
 	struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
-	struct net_device *dev;
+	struct net_device *dev, *ldev;
 	int rv;
 
 	if (addr_len != sizeof(struct sockaddr_dn))
@@ -746,14 +746,17 @@ static int dn_bind(struct socket *sock, 
 	if (!(saddr->sdn_flags & SDF_WILD)) {
 		if (dn_ntohs(saddr->sdn_nodeaddrl)) {
 			read_lock(&dev_base_lock);
-			for(dev = dev_base; dev; dev = dev->next) {
+			ldev = NULL;
+			for_each_netdev(dev) {
 				if (!dev->dn_ptr)
 					continue;
-				if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+				if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {
+					ldev = dev;
 					break;
+				}
 			}
 			read_unlock(&dev_base_lock);
-			if (dev == NULL)
+			if (ldev == NULL)
 				return -EADDRNOTAVAIL;
 		}
 	}
@@ -2413,6 +2416,7 @@ #if 0
 static void __exit decnet_exit(void)
 {
 	sock_unregister(AF_DECnet);
+	rtnl_unregister_all(PF_DECnet);
 	dev_remove_pack(&dn_dix_packet_type);
 
 	dn_unregister_sysctl();
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 060d725..764a56a 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -799,10 +799,10 @@ static int dn_nl_dump_ifaddr(struct sk_b
 	skip_ndevs = cb->args[0];
 	skip_naddr = cb->args[1];
 
-	read_lock(&dev_base_lock);
-	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < skip_ndevs)
-			continue;
+			goto cont;
 		else if (idx > skip_ndevs) {
 			/* Only skip over addresses for first dev dumped
 			 * in this iteration (idx == skip_ndevs) */
@@ -810,22 +810,22 @@ static int dn_nl_dump_ifaddr(struct sk_b
 		}
 
 		if ((dn_db = dev->dn_ptr) == NULL)
-			continue;
+			goto cont;
 
 		for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;
 		     ifa = ifa->ifa_next, dn_idx++) {
 			if (dn_idx < skip_naddr)
-				continue;
+				goto cont;
 
 			if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
 					      cb->nlh->nlmsg_seq, RTM_NEWADDR,
 					      NLM_F_MULTI) < 0)
 				goto done;
 		}
+cont:
+		idx++;
 	}
 done:
-	read_unlock(&dev_base_lock);
-
 	cb->args[0] = idx;
 	cb->args[1] = dn_idx;
 
@@ -913,7 +913,7 @@ static void dn_send_endnode_hello(struct
 	pktlen = (__le16 *)skb_push(skb,2);
 	*pktlen = dn_htons(skb->len - 2);
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
 }
@@ -1005,7 +1005,7 @@ static void dn_send_router_hello(struct 
 	pktlen = (__le16 *)skb_push(skb, 2);
 	*pktlen = dn_htons(skb->len - 2);
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	if (dn_am_i_a_router(dn, dn_db, ifa)) {
 		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
@@ -1299,7 +1299,7 @@ void dn_dev_devices_off(void)
 	struct net_device *dev;
 
 	rtnl_lock();
-	for(dev = dev_base; dev; dev = dev->next)
+	for_each_netdev(dev)
 		dn_dev_down(dev);
 	rtnl_unlock();
 
@@ -1310,7 +1310,7 @@ void dn_dev_devices_on(void)
 	struct net_device *dev;
 
 	rtnl_lock();
-	for(dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (dev->flags & IFF_UP)
 			dn_dev_up(dev);
 	}
@@ -1328,62 +1328,56 @@ int unregister_dnaddr_notifier(struct no
 }
 
 #ifdef CONFIG_PROC_FS
-static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+static inline int is_dn_dev(struct net_device *dev)
 {
-	do {
-		dev = dev->next;
-	} while(dev && !dev->dn_ptr);
-
-	return dev;
+	return dev->dn_ptr != NULL;
 }
 
-static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	int i;
 	struct net_device *dev;
 
-	dev = dev_base;
-	if (dev && !dev->dn_ptr)
-		dev = dn_dev_get_next(seq, dev);
-	if (pos) {
-		while(dev && (dev = dn_dev_get_next(seq, dev)))
-			--pos;
-	}
-	return dev;
-}
+	read_lock(&dev_base_lock);
 
-static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-	if (*pos) {
-		struct net_device *dev;
-		read_lock(&dev_base_lock);
-		dev = dn_dev_get_idx(seq, *pos - 1);
-		if (dev == NULL)
-			read_unlock(&dev_base_lock);
-		return dev;
+	if (*pos == 0)
+		return SEQ_START_TOKEN;
+
+	i = 1;
+	for_each_netdev(dev) {
+		if (!is_dn_dev(dev))
+			continue;
+
+		if (i++ == *pos)
+			return dev;
 	}
-	return SEQ_START_TOKEN;
+
+	return NULL;
 }
 
 static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-	struct net_device *dev = v;
-	loff_t one = 1;
+	struct net_device *dev;
 
-	if (v == SEQ_START_TOKEN) {
-		dev = dn_dev_seq_start(seq, &one);
-	} else {
-		dev = dn_dev_get_next(seq, dev);
-		if (dev == NULL)
-			read_unlock(&dev_base_lock);
-	}
 	++*pos;
-	return dev;
+
+	dev = (struct net_device *)v;
+	if (v == SEQ_START_TOKEN)
+		dev = net_device_entry(&dev_base_head);
+
+	for_each_netdev_continue(dev) {
+		if (!is_dn_dev(dev))
+			continue;
+
+		return dev;
+	}
+
+	return NULL;
 }
 
 static void dn_dev_seq_stop(struct seq_file *seq, void *v)
 {
-	if (v && v != SEQ_START_TOKEN)
-		read_unlock(&dev_base_lock);
+	read_unlock(&dev_base_lock);
 }
 
 static char *dn_type2asc(char type)
@@ -1447,24 +1441,6 @@ static const struct file_operations dn_d
 
 #endif /* CONFIG_PROC_FS */
 
-static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =
-{
-	[RTM_NEWADDR  - RTM_BASE] = { .doit	= dn_nl_newaddr,	},
-	[RTM_DELADDR  - RTM_BASE] = { .doit	= dn_nl_deladdr,	},
-	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= dn_nl_dump_ifaddr,	},
-#ifdef CONFIG_DECNET_ROUTER
-	[RTM_NEWROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_newroute,	},
-	[RTM_DELROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_delroute,	},
-	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute,
-				      .dumpit	= dn_fib_dump,		},
-	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= dn_fib_dump_rules,	},
-#else
-	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute,
-				      .dumpit	= dn_cache_dump,	},
-#endif
-
-};
-
 static int __initdata addr[2];
 module_param_array(addr, int, NULL, 0444);
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
@@ -1485,7 +1461,9 @@ void __init dn_dev_init(void)
 
 	dn_dev_devices_on();
 
-	rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
+	rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL);
+	rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL);
+	rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr);
 
 	proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
 
@@ -1500,8 +1478,6 @@ #endif /* CONFIG_SYSCTL */
 
 void __exit dn_dev_cleanup(void)
 {
-	rtnetlink_links[PF_DECnet] = NULL;
-
 #ifdef CONFIG_SYSCTL
 	{
 		int i;
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 82d58a9..d2bc19d 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -504,7 +504,7 @@ static int dn_fib_check_attr(struct rtms
 	return 0;
 }
 
-int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
@@ -520,7 +520,7 @@ int dn_fib_rtm_delroute(struct sk_buff *
 	return -ESRCH;
 }
 
-int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
@@ -602,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_
 
 	/* Scan device list */
 	read_lock(&dev_base_lock);
-	for(dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		dn_db = dev->dn_ptr;
 		if (dn_db == NULL)
 			continue;
@@ -748,11 +748,13 @@ void __exit dn_fib_cleanup(void)
 
 void __init dn_fib_init(void)
 {
-
 	dn_fib_table_init();
 	dn_fib_rules_init();
 
 	register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
+
+	rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL);
+	rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL);
 }
 
 
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index bf701cf..4bf066c 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -261,7 +261,7 @@ static int dn_long_output(struct sk_buff
 	lp->s_class  = 0;
 	lp->pt       = 0;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
 }
@@ -300,7 +300,7 @@ static int dn_short_output(struct sk_buf
 	sp->srcnode    = cb->src;
 	sp->forward    = cb->hops & 0x3f;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
 }
@@ -342,7 +342,7 @@ static int dn_phase3_output(struct sk_bu
 	sp->srcnode  = cb->src & dn_htons(0x03ff);
 	sp->forward  = cb->hops & 0x3f;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
 }
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 9d20904..4074a6e 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -362,7 +362,8 @@ static void dn_nsp_conn_conf(struct sock
 			u16 dlen = *skb->data;
 			if ((dlen <= 16) && (dlen <= skb->len)) {
 				scp->conndata_in.opt_optl = dn_htons(dlen);
-				memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen);
+				skb_copy_from_linear_data_offset(skb, 1,
+					      scp->conndata_in.opt_data, dlen);
 			}
 		}
 		dn_nsp_send_link(sk, DN_NOCHANGE, 0);
@@ -406,7 +407,7 @@ static void dn_nsp_disc_init(struct sock
 		u16 dlen = *skb->data;
 		if ((dlen <= 16) && (dlen <= skb->len)) {
 			scp->discdata_in.opt_optl = dn_htons(dlen);
-			memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen);
+			skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
 		}
 	}
 
@@ -725,7 +726,7 @@ static int dn_nsp_rx_packet(struct sk_bu
 	if (!pskb_may_pull(skb, 2))
 		goto free_out;
 
-	skb->h.raw    = skb->data;
+	skb_reset_transport_header(skb);
 	cb->nsp_flags = *ptr++;
 
 	if (decnet_debug_level & 2)
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 2d2cda8..7404653 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -79,7 +79,7 @@ static void dn_nsp_send(struct sk_buff *
 	struct dst_entry *dst;
 	struct flowi fl;
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	scp->stamp = jiffies;
 
 	dst = sk_dst_check(sk, 0);
@@ -681,8 +681,10 @@ void dn_nsp_send_conninit(struct sock *s
 	if (scp->peer.sdn_objnum)
 		type = 0;
 
-	skb_put(skb, dn_sockaddr2username(&scp->peer, skb->tail, type));
-	skb_put(skb, dn_sockaddr2username(&scp->addr, skb->tail, 2));
+	skb_put(skb, dn_sockaddr2username(&scp->peer,
+					  skb_tail_pointer(skb), type));
+	skb_put(skb, dn_sockaddr2username(&scp->addr,
+					  skb_tail_pointer(skb), 2));
 
 	menuver = DN_MENUVER_ACC | DN_MENUVER_USR;
 	if (scp->peer.sdn_flags & SDF_PROXY)
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index c1b5502..a8bf106 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -77,6 +77,7 @@ #include <linux/netfilter_decnet.h>
 #include <linux/rcupdate.h>
 #include <linux/times.h>
 #include <asm/errno.h>
+#include <net/netlink.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/flow.h>
@@ -386,7 +387,7 @@ static int dn_return_short(struct sk_buf
 	__le16 tmp;
 
 	/* Add back headers */
-	skb_push(skb, skb->data - skb->nh.raw);
+	skb_push(skb, skb->data - skb_network_header(skb));
 
 	if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
 		return NET_RX_DROP;
@@ -425,7 +426,7 @@ static int dn_return_long(struct sk_buff
 	unsigned char tmp[ETH_ALEN];
 
 	/* Add back all headers */
-	skb_push(skb, skb->data - skb->nh.raw);
+	skb_push(skb, skb->data - skb_network_header(skb));
 
 	if ((skb = skb_unshare(skb, GFP_ATOMIC)) == NULL)
 		return NET_RX_DROP;
@@ -504,7 +505,7 @@ static int dn_route_rx_long(struct sk_bu
 		goto drop_it;
 
 	skb_pull(skb, 20);
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	/* Destination info */
 	ptr += 2;
@@ -542,7 +543,7 @@ static int dn_route_rx_short(struct sk_b
 		goto drop_it;
 
 	skb_pull(skb, 5);
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	cb->dst = *(__le16 *)ptr;
 	ptr += 2;
@@ -615,7 +616,7 @@ int dn_route_rcv(struct sk_buff *skb, st
 		flags = *skb->data;
 	}
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	/*
 	 * Weed out future version DECnet
@@ -885,7 +886,7 @@ static int dn_route_output_slow(struct d
 			    .iif = loopback_dev.ifindex,
 			    .oif = oldflp->oif };
 	struct dn_route *rt = NULL;
-	struct net_device *dev_out = NULL;
+	struct net_device *dev_out = NULL, *dev;
 	struct neighbour *neigh = NULL;
 	unsigned hash;
 	unsigned flags = 0;
@@ -924,15 +925,17 @@ static int dn_route_output_slow(struct d
 			goto out;
 		}
 		read_lock(&dev_base_lock);
-		for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
-			if (!dev_out->dn_ptr)
+		for_each_netdev(dev) {
+			if (!dev->dn_ptr)
 				continue;
-			if (!dn_dev_islocal(dev_out, oldflp->fld_src))
+			if (!dn_dev_islocal(dev, oldflp->fld_src))
 				continue;
-			if ((dev_out->flags & IFF_LOOPBACK) &&
+			if ((dev->flags & IFF_LOOPBACK) &&
 			    oldflp->fld_dst &&
-			    !dn_dev_islocal(dev_out, oldflp->fld_dst))
+			    !dn_dev_islocal(dev, oldflp->fld_dst))
 				continue;
+
+			dev_out = dev;
 			break;
 		}
 		read_unlock(&dev_base_lock);
@@ -1468,7 +1471,7 @@ static int dn_rt_fill_info(struct sk_buf
 	struct dn_route *rt = (struct dn_route *)skb->dst;
 	struct rtmsg *r;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	long expires;
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
@@ -1509,19 +1512,19 @@ static int dn_rt_fill_info(struct sk_buf
 	if (rt->fl.iif)
 		RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 /*
  * This is called by both endnodes and routers now.
  */
-int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
+static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct rtattr **rta = arg;
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
@@ -1537,7 +1540,7 @@ int dn_cache_getroute(struct sk_buff *in
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
 		return -ENOBUFS;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	cb = DN_SKB_CB(skb);
 
 	if (rta[RTA_SRC-1])
@@ -1812,6 +1815,13 @@ void __init dn_route_init(void)
 	dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
 
 	proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
+
+#ifdef CONFIG_DECNET_ROUTER
+	rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute, dn_fib_dump);
+#else
+	rtnl_register(PF_DECnet, RTM_GETROUTE, dn_cache_getroute,
+		      dn_cache_dump);
+#endif
 }
 
 void __exit dn_route_cleanup(void)
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index 5e86dd5..17a1932 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -31,6 +31,7 @@ #include <net/dn.h>
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
 #include <net/dn_dev.h>
+#include <net/dn_route.h>
 
 static struct fib_rules_ops dn_fib_rules_ops;
 
@@ -239,9 +240,9 @@ static u32 dn_fib_rule_default_pref(void
 	return 0;
 }
 
-int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
+static void dn_fib_rule_flush_cache(void)
 {
-	return fib_rules_dump(skb, cb, AF_DECnet);
+	dn_rt_cache_flush(-1);
 }
 
 static struct fib_rules_ops dn_fib_rules_ops = {
@@ -254,6 +255,7 @@ static struct fib_rules_ops dn_fib_rules
 	.compare	= dn_fib_rule_compare,
 	.fill		= dn_fib_rule_fill,
 	.default_pref	= dn_fib_rule_default_pref,
+	.flush_cache	= dn_fib_rule_flush_cache,
 	.nlgroup	= RTNLGRP_DECnet_RULE,
 	.policy		= dn_fib_rule_policy,
 	.rules_list	= &dn_fib_rules,
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 780a141..d6615c9 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -28,6 +28,7 @@ #include <asm/atomic.h>
 #include <asm/uaccess.h>
 #include <linux/route.h> /* RTF_xxx */
 #include <net/neighbour.h>
+#include <net/netlink.h>
 #include <net/dst.h>
 #include <net/flow.h>
 #include <net/fib_rules.h>
@@ -295,7 +296,7 @@ static int dn_fib_dump_info(struct sk_bu
 {
 	struct rtmsg *rtm;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags);
 	rtm = NLMSG_DATA(nlh);
@@ -337,19 +338,19 @@ static int dn_fib_dump_info(struct sk_bu
 			nhp->rtnh_ifindex = nh->nh_oif;
 			if (nh->nh_gw)
 				RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw);
-			nhp->rtnh_len = skb->tail - (unsigned char *)nhp;
+			nhp->rtnh_len = skb_tail_pointer(skb) - (unsigned char *)nhp;
 		} endfor_nexthops(fi);
 		mp_head->rta_type = RTA_MULTIPATH;
-		mp_head->rta_len = skb->tail - (u8*)mp_head;
+		mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
 	}
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -EMSGSIZE;
 }
 
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 0e62def..6962346 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -33,7 +33,7 @@ static struct sk_buff *dnrmg_build_messa
 {
 	struct sk_buff *skb = NULL;
 	size_t size;
-	unsigned char *old_tail;
+	sk_buff_data_t old_tail;
 	struct nlmsghdr *nlh;
 	unsigned char *ptr;
 	struct nf_dn_rtmsg *rtm;
@@ -48,7 +48,7 @@ static struct sk_buff *dnrmg_build_messa
 	rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
 	rtm->nfdn_ifindex = rt_skb->dev->ifindex;
 	ptr = NFDN_RTMSG(rtm);
-	memcpy(ptr, rt_skb->data, rt_skb->len);
+	skb_copy_from_linear_data(rt_skb, ptr, rt_skb->len);
 	nlh->nlmsg_len = skb->tail - old_tail;
 	return skb;
 
@@ -102,7 +102,7 @@ #define RCV_SKB_FAIL(err) do { netlink_a
 
 static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
 {
-	struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
+	struct nlmsghdr *nlh = nlmsg_hdr(skb);
 
 	if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
 		return;
@@ -138,7 +138,7 @@ static int __init dn_rtmsg_init(void)
 	int rv = 0;
 
 	dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, DNRNG_NLGRP_MAX,
-				      dnrmg_receive_user_sk, THIS_MODULE);
+				      dnrmg_receive_user_sk, NULL, THIS_MODULE);
 	if (dnrmg == NULL) {
 		printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
 		return -ENOMEM;
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index bc12e36..b5524f3 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -162,7 +162,7 @@ static int econet_recvmsg(struct kiocb *
 	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
 	if (err)
 		goto out_free;
-	skb_get_timestamp(skb, &sk->sk_stamp);
+	sk->sk_stamp = skb->tstamp;
 
 	if (msg->msg_name)
 		memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
@@ -345,7 +345,7 @@ #ifdef CONFIG_ECONET_NATIVE
 			goto out_unlock;
 
 		skb_reserve(skb, LL_RESERVED_SPACE(dev));
-		skb->nh.raw = skb->data;
+		skb_reset_network_header(skb);
 
 		eb = (struct ec_cb *)&skb->cb;
 
@@ -366,7 +366,7 @@ #ifdef CONFIG_ECONET_NATIVE
 			fh->cb = cb;
 			fh->port = port;
 			if (sock->type != SOCK_DGRAM) {
-				skb->tail = skb->data;
+				skb_reset_tail_pointer(skb);
 				skb->len = 0;
 			} else if (res < 0)
 				goto out_free;
@@ -727,6 +727,9 @@ static int econet_ioctl(struct socket *s
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, argp);
 
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, argp);
+
 		case SIOCSIFADDR:
 		case SIOCGIFADDR:
 			return ec_dev_ioctl(sock, cmd, argp);
@@ -845,7 +848,7 @@ static void aun_send_response(__u32 addr
 
 static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
 {
-	struct iphdr *ip = skb->nh.iph;
+	struct iphdr *ip = ip_hdr(skb);
 	unsigned char stn = ntohl(ip->saddr) & 0xff;
 	struct sock *sk;
 	struct sk_buff *newskb;
@@ -940,10 +943,10 @@ static void aun_data_available(struct so
 		printk(KERN_DEBUG "AUN: recvfrom() error %d\n", -err);
 	}
 
-	data = skb->h.raw + sizeof(struct udphdr);
+	data = skb_transport_header(skb) + sizeof(struct udphdr);
 	ah = (struct aunhdr *)data;
 	len = skb->len - sizeof(struct udphdr);
-	ip = skb->nh.iph;
+	ip = ip_hdr(skb);
 
 	switch (ah->code)
 	{
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 7391f55..0ac2524 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -156,7 +156,8 @@ __be16 eth_type_trans(struct sk_buff *sk
 	struct ethhdr *eth;
 	unsigned char *rawp;
 
-	skb->mac.raw = skb->data;
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
 	eth = eth_hdr(skb);
 
@@ -228,7 +229,7 @@ int eth_header_cache(struct neighbour *n
 	eth = (struct ethhdr *)
 	    (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
 
-	if (type == __constant_htons(ETH_P_802_3))
+	if (type == htons(ETH_P_802_3))
 		return -1;
 
 	eth->h_proto = type;
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index 6ef766e..1438ade 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -56,7 +56,8 @@ config IEEE80211_CRYPT_CCMP
 
 config IEEE80211_CRYPT_TKIP
 	tristate "IEEE 802.11i TKIP encryption"
-	depends on IEEE80211 && NET_RADIO
+	depends on IEEE80211
+	select WIRELESS_EXT
 	select CRYPTO
 	select CRYPTO_MICHAEL_MIC
 	select CRYPTO_ECB
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 5ed0a98..df5592c 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypto routines
  *
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index 35aa342..b016b41 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.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
@@ -338,7 +338,7 @@ static int ieee80211_ccmp_decrypt(struct
 
 	if (ccmp_replay_check(pn, key->rx_pn)) {
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+			IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT
 			       " previous PN %02x%02x%02x%02x%02x%02x "
 			       "received PN %02x%02x%02x%02x%02x%02x\n",
 			       MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index fc1f99a..5a48d8e 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.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
@@ -465,7 +465,7 @@ static int ieee80211_tkip_decrypt(struct
 
 	if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+			IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT
 			       " previous TSC %08x%04x received TSC "
 			       "%08x%04x\n", MAC_ARG(hdr->addr2),
 			       tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
@@ -507,7 +507,7 @@ static int ieee80211_tkip_decrypt(struct
 			tkey->rx_phase1_done = 0;
 		}
 		if (net_ratelimit()) {
-			printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+			IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
 			       MAC_FMT "\n", MAC_ARG(hdr->addr2));
 		}
 		tkey->dot11RSNAStatsTKIPICVErrors++;
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index ec6d885..8d18245 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
  *
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.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
@@ -152,7 +152,7 @@ static int prism2_wep_encrypt(struct sk_
 		return -1;
 
 	/* Copy the IV into the first 3 bytes of the key */
-	memcpy(key, skb->data + hdr_len, 3);
+	skb_copy_from_linear_data_offset(skb, hdr_len, key, 3);
 
 	/* Copy rest of the WEP key (the secret part) */
 	memcpy(key + 3, wep->key, wep->key_len);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index b1c6d1f..7ec6610 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   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
@@ -229,6 +229,7 @@ #ifdef CONFIG_IEEE80211_DEBUG
 
 static int debug = 0;
 u32 ieee80211_debug_level = 0;
+EXPORT_SYMBOL_GPL(ieee80211_debug_level);
 static struct proc_dir_entry *ieee80211_proc = NULL;
 
 static int show_debug_level(char *page, char **start, off_t offset,
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 4084909..f2de2e4 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004-2005, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
@@ -42,7 +42,7 @@ static void ieee80211_monitor_rx(struct 
 	u16 fc = le16_to_cpu(hdr->frame_ctl);
 
 	skb->dev = ieee->dev;
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_pull(skb, ieee80211_get_hdrlen(fc));
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->protocol = __constant_htons(ETH_P_80211_RAW);
@@ -606,12 +606,12 @@ #endif
 		if (frag == 0) {
 			/* copy first fragment (including full headers) into
 			 * beginning of the fragment cache skb */
-			memcpy(skb_put(frag_skb, flen), skb->data, flen);
+			skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
 		} else {
 			/* append frame payload to the end of the fragment
 			 * cache skb */
-			memcpy(skb_put(frag_skb, flen), skb->data + hdrlen,
-			       flen);
+			skb_copy_from_linear_data_offset(skb, hdrlen,
+				      skb_put(frag_skb, flen), flen);
 		}
 		dev_kfree_skb_any(skb);
 		skb = NULL;
@@ -759,8 +759,9 @@ #ifdef NOT_YET
 		    IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
 		/* Non-standard frame: get addr4 from its bogus location after
 		 * the payload */
-		memcpy(skb->data + ETH_ALEN,
-		       skb->data + skb->len - ETH_ALEN, ETH_ALEN);
+		skb_copy_to_linear_data_offset(skb, ETH_ALEN,
+					       skb->data + skb->len - ETH_ALEN,
+					       ETH_ALEN);
 		skb_trim(skb, skb->len - ETH_ALEN);
 	}
 #endif
@@ -789,10 +790,11 @@ #ifdef NOT_YET
 
 	if (skb2 != NULL) {
 		/* send to wireless media */
-		skb2->protocol = __constant_htons(ETH_P_802_3);
-		skb2->mac.raw = skb2->nh.raw = skb2->data;
-		/* skb2->nh.raw = skb2->data + ETH_HLEN; */
 		skb2->dev = dev;
+		skb2->protocol = __constant_htons(ETH_P_802_3);
+		skb_reset_mac_header(skb2);
+		skb_reset_network_header(skb2);
+		/* skb2->network_header += ETH_HLEN; */
 		dev_queue_xmit(skb2);
 	}
 #endif
@@ -800,7 +802,6 @@ #endif
 	if (skb) {
 		skb->protocol = eth_type_trans(skb, dev);
 		memset(skb->cb, 0, sizeof(skb->cb));
-		skb->dev = dev;
 		skb->ip_summed = CHECKSUM_NONE;	/* 802.11 crc not sufficient */
 		if (netif_rx(skb) == NET_RX_DROP) {
 			/* netif_rx always succeeds, but it might drop
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 0292d63..a4c3c51 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -225,10 +225,10 @@ static int ieee80211_classify(struct sk_
 	struct iphdr *ip;
 
 	eth = (struct ethhdr *)skb->data;
-	if (eth->h_proto != __constant_htons(ETH_P_IP))
+	if (eth->h_proto != htons(ETH_P_IP))
 		return 0;
 
-	ip = skb->nh.iph;
+	ip = ip_hdr(skb);
 	switch (ip->tos & 0xfc) {
 	case 0x20:
 		return 2;
@@ -309,8 +309,8 @@ int ieee80211_xmit(struct sk_buff *skb, 
 	}
 
 	/* Save source and destination addresses */
-	memcpy(dest, skb->data, ETH_ALEN);
-	memcpy(src, skb->data + ETH_ALEN, ETH_ALEN);
+	skb_copy_from_linear_data(skb, dest, ETH_ALEN);
+	skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
 
 	if (host_encrypt || host_build_iv)
 		fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
@@ -363,7 +363,7 @@ int ieee80211_xmit(struct sk_buff *skb, 
 		snapped = 1;
 		ieee80211_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
 				    ether_type);
-		memcpy(skb_put(skb_new, skb->len), skb->data, skb->len);
+		skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
 		res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
 		if (res < 0) {
 			IEEE80211_ERROR("msdu encryption failed\n");
@@ -492,7 +492,7 @@ int ieee80211_xmit(struct sk_buff *skb, 
 			bytes -= SNAP_SIZE + sizeof(u16);
 		}
 
-		memcpy(skb_put(skb_frag, bytes), skb->data, bytes);
+		skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
 
 		/* Advance the SKB... */
 		skb_pull(skb, bytes);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 40d7a55..cee5e13 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   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
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 9e8ef50..e62aee0 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -574,6 +574,33 @@ config TCP_CONG_VENO
 	loss packets.
 	See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
 
+config TCP_CONG_YEAH
+	tristate "YeAH TCP"
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	YeAH-TCP is a sender-side high-speed enabled TCP congestion control
+	algorithm, which uses a mixed loss/delay approach to compute the
+	congestion window. It's design goals target high efficiency,
+	internal, RTT and Reno fairness, resilience to link loss while
+	keeping network elements load as low as possible.
+
+	For further details look here:
+	  http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf
+
+config TCP_CONG_ILLINOIS
+	tristate "TCP Illinois"
+	depends on EXPERIMENTAL
+	default n
+	---help---
+	TCP-Illinois is a sender-side modificatio of TCP Reno for
+	high speed long delay links. It uses round-trip-time to
+	adjust the alpha and beta parameters to achieve a higher average
+	throughput and maintain fairness.
+
+	For further details see:
+	  http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html
+
 choice
 	prompt "Default TCP congestion control"
 	default DEFAULT_CUBIC
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 7a06862..4ff6c15 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -49,6 +49,8 @@ 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_TCP_CONG_YEAH) += tcp_yeah.o
+obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
 obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index cf358c8..041fba3 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -87,11 +87,11 @@ #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/random.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#include <linux/smp_lock.h>
 #include <linux/inet.h>
 #include <linux/igmp.h>
 #include <linux/inetdevice.h>
@@ -217,6 +217,26 @@ out:
 	return err;
 }
 
+u32 inet_ehash_secret __read_mostly;
+EXPORT_SYMBOL(inet_ehash_secret);
+
+/*
+ * inet_ehash_secret must be set exactly once
+ * Instead of using a dedicated spinlock, we (ab)use inetsw_lock
+ */
+void build_ehash_secret(void)
+{
+	u32 rnd;
+	do {
+		get_random_bytes(&rnd, sizeof(rnd));
+	} while (rnd == 0);
+	spin_lock_bh(&inetsw_lock);
+	if (!inet_ehash_secret)
+		inet_ehash_secret = rnd;
+	spin_unlock_bh(&inetsw_lock);
+}
+EXPORT_SYMBOL(build_ehash_secret);
+
 /*
  *	Create an inet socket.
  */
@@ -233,6 +253,11 @@ static int inet_create(struct socket *so
 	int try_loading_module = 0;
 	int err;
 
+	if (sock->type != SOCK_RAW &&
+	    sock->type != SOCK_DGRAM &&
+	    !inet_ehash_secret)
+		build_ehash_secret();
+
 	sock->state = SS_UNCONNECTED;
 
 	/* Look for the requested type/protocol pair. */
@@ -755,6 +780,9 @@ int inet_ioctl(struct socket *sock, unsi
 		case SIOCGSTAMP:
 			err = sock_get_timestamp(sk, (struct timeval __user *)arg);
 			break;
+		case SIOCGSTAMPNS:
+			err = sock_get_timestampns(sk, (struct timespec __user *)arg);
+			break;
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
@@ -1109,7 +1137,7 @@ static int inet_gso_send_check(struct sk
 	if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
 		goto out;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	ihl = iph->ihl * 4;
 	if (ihl < sizeof(*iph))
 		goto out;
@@ -1117,8 +1145,9 @@ static int inet_gso_send_check(struct sk
 	if (unlikely(!pskb_may_pull(skb, ihl)))
 		goto out;
 
-	skb->h.raw = __skb_pull(skb, ihl);
-	iph = skb->nh.iph;
+	__skb_pull(skb, ihl);
+	skb_reset_transport_header(skb);
+	iph = ip_hdr(skb);
 	proto = iph->protocol & (MAX_INET_PROTOS - 1);
 	err = -EPROTONOSUPPORT;
 
@@ -1152,7 +1181,7 @@ static struct sk_buff *inet_gso_segment(
 	if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
 		goto out;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	ihl = iph->ihl * 4;
 	if (ihl < sizeof(*iph))
 		goto out;
@@ -1160,8 +1189,9 @@ static struct sk_buff *inet_gso_segment(
 	if (unlikely(!pskb_may_pull(skb, ihl)))
 		goto out;
 
-	skb->h.raw = __skb_pull(skb, ihl);
-	iph = skb->nh.iph;
+	__skb_pull(skb, ihl);
+	skb_reset_transport_header(skb);
+	iph = ip_hdr(skb);
 	id = ntohs(iph->id);
 	proto = iph->protocol & (MAX_INET_PROTOS - 1);
 	segs = ERR_PTR(-EPROTONOSUPPORT);
@@ -1177,17 +1207,57 @@ static struct sk_buff *inet_gso_segment(
 
 	skb = segs;
 	do {
-		iph = skb->nh.iph;
+		iph = ip_hdr(skb);
 		iph->id = htons(id++);
 		iph->tot_len = htons(skb->len - skb->mac_len);
 		iph->check = 0;
-		iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+		iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
 	} while ((skb = skb->next));
 
 out:
 	return segs;
 }
 
+unsigned long snmp_fold_field(void *mib[], int offt)
+{
+	unsigned long res = 0;
+	int i;
+
+	for_each_possible_cpu(i) {
+		res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt);
+		res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt);
+	}
+	return res;
+}
+EXPORT_SYMBOL_GPL(snmp_fold_field);
+
+int snmp_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
+{
+	BUG_ON(ptr == NULL);
+	ptr[0] = __alloc_percpu(mibsize);
+	if (!ptr[0])
+		goto err0;
+	ptr[1] = __alloc_percpu(mibsize);
+	if (!ptr[1])
+		goto err1;
+	return 0;
+err1:
+	free_percpu(ptr[0]);
+	ptr[0] = NULL;
+err0:
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(snmp_mib_init);
+
+void snmp_mib_free(void *ptr[2])
+{
+	BUG_ON(ptr == NULL);
+	free_percpu(ptr[0]);
+	free_percpu(ptr[1]);
+	ptr[0] = ptr[1] = NULL;
+}
+EXPORT_SYMBOL_GPL(snmp_mib_free);
+
 #ifdef CONFIG_IP_MULTICAST
 static struct net_protocol igmp_protocol = {
 	.handler =	igmp_rcv,
@@ -1214,28 +1284,47 @@ static struct net_protocol icmp_protocol
 
 static int __init init_ipv4_mibs(void)
 {
-	net_statistics[0] = alloc_percpu(struct linux_mib);
-	net_statistics[1] = alloc_percpu(struct linux_mib);
-	ip_statistics[0] = alloc_percpu(struct ipstats_mib);
-	ip_statistics[1] = alloc_percpu(struct ipstats_mib);
-	icmp_statistics[0] = alloc_percpu(struct icmp_mib);
-	icmp_statistics[1] = alloc_percpu(struct icmp_mib);
-	tcp_statistics[0] = alloc_percpu(struct tcp_mib);
-	tcp_statistics[1] = alloc_percpu(struct tcp_mib);
-	udp_statistics[0] = alloc_percpu(struct udp_mib);
-	udp_statistics[1] = alloc_percpu(struct udp_mib);
-	udplite_statistics[0] = alloc_percpu(struct udp_mib);
-	udplite_statistics[1] = alloc_percpu(struct udp_mib);
-	if (!
-	    (net_statistics[0] && net_statistics[1] && ip_statistics[0]
-	     && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
-	     && udp_statistics[0] && udp_statistics[1]
-	     && udplite_statistics[0] && udplite_statistics[1]             ) )
-		return -ENOMEM;
-
-	(void) tcp_mib_init();
+	if (snmp_mib_init((void **)net_statistics,
+			  sizeof(struct linux_mib),
+			  __alignof__(struct linux_mib)) < 0)
+		goto err_net_mib;
+	if (snmp_mib_init((void **)ip_statistics,
+			  sizeof(struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
+		goto err_ip_mib;
+	if (snmp_mib_init((void **)icmp_statistics,
+			  sizeof(struct icmp_mib),
+			  __alignof__(struct icmp_mib)) < 0)
+		goto err_icmp_mib;
+	if (snmp_mib_init((void **)tcp_statistics,
+			  sizeof(struct tcp_mib),
+			  __alignof__(struct tcp_mib)) < 0)
+		goto err_tcp_mib;
+	if (snmp_mib_init((void **)udp_statistics,
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
+		goto err_udp_mib;
+	if (snmp_mib_init((void **)udplite_statistics,
+			  sizeof(struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
+		goto err_udplite_mib;
+
+	tcp_mib_init();
 
 	return 0;
+
+err_udplite_mib:
+	snmp_mib_free((void **)udp_statistics);
+err_udp_mib:
+	snmp_mib_free((void **)tcp_statistics);
+err_tcp_mib:
+	snmp_mib_free((void **)icmp_statistics);
+err_icmp_mib:
+	snmp_mib_free((void **)ip_statistics);
+err_ip_mib:
+	snmp_mib_free((void **)net_statistics);
+err_net_mib:
+	return -ENOMEM;
 }
 
 static int ipv4_proc_init(void);
@@ -1336,7 +1425,7 @@ #endif
 	 *	Initialise per-cpu ipv4 mibs
 	 */
 
-	if(init_ipv4_mibs())
+	if (init_ipv4_mibs())
 		printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;
 
 	ipv4_proc_init();
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 7194eb4..6da8ff5 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -65,7 +65,7 @@ static int ah_output(struct xfrm_state *
 		char 		buf[60];
 	} tmp_iph;
 
-	top_iph = skb->nh.iph;
+	top_iph = ip_hdr(skb);
 	iph = &tmp_iph.iph;
 
 	iph->tos = top_iph->tos;
@@ -152,9 +152,9 @@ static int ah_input(struct xfrm_state *x
 	skb->ip_summed = CHECKSUM_NONE;
 
 	ah = (struct ip_auth_hdr*)skb->data;
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
-	ihl = skb->data - skb->nh.raw;
+	ihl = skb->data - skb_network_header(skb);
 	memcpy(work_buf, iph, ihl);
 
 	iph->ttl = 0;
@@ -181,7 +181,9 @@ static int ah_input(struct xfrm_state *x
 		}
 	}
 	((struct iphdr*)work_buf)->protocol = ah->nexthdr;
-	skb->h.raw = memcpy(skb->nh.raw += ah_hlen, work_buf, ihl);
+	skb->network_header += ah_hlen;
+	memcpy(skb_network_header(skb), work_buf, ihl);
+	skb->transport_header = skb->network_header;
 	__skb_pull(skb, ah_hlen + ihl);
 
 	return 0;
@@ -196,8 +198,8 @@ static void ah4_err(struct sk_buff *skb,
 	struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
-	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
-	    skb->h.icmph->code != ICMP_FRAG_NEEDED)
+	if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
+	    icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
 		return;
 
 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 1a3488a..7110779 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -342,13 +342,13 @@ static void arp_solicit(struct neighbour
 	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
 	default:
 	case 0:		/* By default announce any local IP */
-		if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
-			saddr = skb->nh.iph->saddr;
+		if (skb && inet_addr_type(ip_hdr(skb)->saddr) == RTN_LOCAL)
+			saddr = ip_hdr(skb)->saddr;
 		break;
 	case 1:		/* Restrict announcements of saddr in same subnet */
 		if (!skb)
 			break;
-		saddr = skb->nh.iph->saddr;
+		saddr = ip_hdr(skb)->saddr;
 		if (inet_addr_type(saddr) == RTN_LOCAL) {
 			/* saddr should be known to target */
 			if (inet_addr_onlink(in_dev, target, saddr))
@@ -578,7 +578,7 @@ struct sk_buff *arp_create(int type, int
 		return NULL;
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_ARP);
@@ -721,7 +721,7 @@ static int arp_process(struct sk_buff *s
 	if (in_dev == NULL)
 		goto out;
 
-	arp = skb->nh.arph;
+	arp = arp_hdr(skb);
 
 	switch (dev_type) {
 	default:
@@ -937,7 +937,7 @@ static int arp_rcv(struct sk_buff *skb, 
 				 (2 * sizeof(u32)))))
 		goto freeskb;
 
-	arp = skb->nh.arph;
+	arp = arp_hdr(skb);
 	if (arp->ar_hln != dev->addr_len ||
 	    dev->flags & IFF_NOARP ||
 	    skb->pkt_type == PACKET_OTHERHOST ||
@@ -1178,7 +1178,7 @@ int arp_ioctl(unsigned int cmd, void __u
 		goto out;
 	}
 
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCDARP:
 		err = arp_req_delete(&r, dev);
 		break;
@@ -1360,7 +1360,7 @@ static void *arp_seq_start(struct seq_fi
 
 /* ------------------------------------------------------------------------ */
 
-static struct seq_operations arp_seq_ops = {
+static const struct seq_operations arp_seq_ops = {
 	.start  = arp_seq_start,
 	.next   = neigh_seq_next,
 	.stop   = neigh_seq_stop,
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 2ce5b69..e1f1848 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -92,6 +92,33 @@ int cipso_v4_rbm_optfmt = 0;
 int cipso_v4_rbm_strictvalid = 1;
 
 /*
+ * Protocol Constants
+ */
+
+/* Maximum size of the CIPSO IP option, derived from the fact that the maximum
+ * IPv4 header size is 60 bytes and the base IPv4 header is 20 bytes long. */
+#define CIPSO_V4_OPT_LEN_MAX          40
+
+/* Length of the base CIPSO option, this includes the option type (1 byte), the
+ * option length (1 byte), and the DOI (4 bytes). */
+#define CIPSO_V4_HDR_LEN              6
+
+/* Base length of the restrictive category bitmap tag (tag #1). */
+#define CIPSO_V4_TAG_RBM_BLEN         4
+
+/* Base length of the enumerated category tag (tag #2). */
+#define CIPSO_V4_TAG_ENUM_BLEN        4
+
+/* Base length of the ranged categories bitmap tag (tag #5). */
+#define CIPSO_V4_TAG_RNG_BLEN         4
+/* The maximum number of category ranges permitted in the ranged category tag
+ * (tag #5).  You may note that the IETF draft states that the maximum number
+ * of category ranges is 7, but if the low end of the last category range is
+ * zero then it is possibile to fit 8 category ranges because the zero should
+ * be omitted. */
+#define CIPSO_V4_TAG_RNG_CAT_MAX      8
+
+/*
  * Helper Functions
  */
 
@@ -1109,16 +1136,15 @@ static int cipso_v4_map_cat_rng_hton(con
 				     unsigned char *net_cat,
 				     u32 net_cat_len)
 {
-	/* The constant '16' is not random, it is the maximum number of
-	 * high/low category range pairs as permitted by the CIPSO draft based
-	 * on a maximum IPv4 header length of 60 bytes - the BUG_ON() assertion
-	 * does a sanity check to make sure we don't overflow the array. */
 	int iter = -1;
-	u16 array[16];
+	u16 array[CIPSO_V4_TAG_RNG_CAT_MAX * 2];
 	u32 array_cnt = 0;
 	u32 cat_size = 0;
 
-	BUG_ON(net_cat_len > 30);
+	/* make sure we don't overflow the 'array[]' variable */
+	if (net_cat_len >
+	    (CIPSO_V4_OPT_LEN_MAX - CIPSO_V4_HDR_LEN - CIPSO_V4_TAG_RNG_BLEN))
+		return -ENOSPC;
 
 	for (;;) {
 		iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1);
@@ -1174,7 +1200,7 @@ static int cipso_v4_map_cat_rng_ntoh(con
 	u16 cat_low;
 	u16 cat_high;
 
-	for(net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
+	for (net_iter = 0; net_iter < net_cat_len; net_iter += 4) {
 		cat_high = ntohs(*((__be16 *)&net_cat[net_iter]));
 		if ((net_iter + 4) <= net_cat_len)
 			cat_low = ntohs(*((__be16 *)&net_cat[net_iter + 2]));
@@ -1196,9 +1222,6 @@ static int cipso_v4_map_cat_rng_ntoh(con
  * Protocol Handling Functions
  */
 
-#define CIPSO_V4_OPT_LEN_MAX          40
-#define CIPSO_V4_HDR_LEN              6
-
 /**
  * cipso_v4_gentag_hdr - Generate a CIPSO option header
  * @doi_def: the DOI definition
@@ -1676,7 +1699,7 @@ validate_return:
  */
 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 {
-	if (skb->nh.iph->protocol == IPPROTO_ICMP || error != -EACCES)
+	if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
 		return;
 
 	if (gateway)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 98a00d0..7f95e6e 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -48,7 +48,6 @@ #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <linux/notifier.h>
 #include <linux/inetdevice.h>
@@ -62,7 +61,7 @@ #include <net/arp.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
-#include <net/netlink.h>
+#include <net/rtnetlink.h>
 
 struct ipv4_devconf ipv4_devconf = {
 	.accept_redirects = 1,
@@ -633,7 +632,7 @@ #ifdef CONFIG_KMOD
 	dev_load(ifr.ifr_name);
 #endif
 
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCGIFADDR:	/* Get interface address */
 	case SIOCGIFBRDADDR:	/* Get the broadcast address */
 	case SIOCGIFDSTADDR:	/* Get the destination address */
@@ -708,7 +707,7 @@ #endif
 	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
 		goto done;
 
-	switch(cmd) {
+	switch (cmd) {
 	case SIOCGIFADDR:	/* Get interface address */
 		sin->sin_addr.s_addr = ifa->ifa_local;
 		goto rarok;
@@ -911,7 +910,7 @@ no_in_dev:
 	 */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
 			continue;
 
@@ -990,7 +989,7 @@ __be32 inet_confirm_addr(const struct ne
 
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((in_dev = __in_dev_get_rcu(dev))) {
 			addr = confirm_addr_indev(in_dev, dst, local, scope);
 			if (addr)
@@ -1183,34 +1182,29 @@ static int inet_dump_ifaddr(struct sk_bu
 	int s_ip_idx, s_idx = cb->args[0];
 
 	s_ip_idx = ip_idx = cb->args[1];
-	read_lock(&dev_base_lock);
-	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_ip_idx = 0;
-		rcu_read_lock();
-		if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
-			rcu_read_unlock();
-			continue;
-		}
+		if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
+			goto cont;
 
 		for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
 		     ifa = ifa->ifa_next, ip_idx++) {
 			if (ip_idx < s_ip_idx)
-				continue;
+				goto cont;
 			if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
 					     cb->nlh->nlmsg_seq,
-					     RTM_NEWADDR, NLM_F_MULTI) <= 0) {
-				rcu_read_unlock();
+					     RTM_NEWADDR, NLM_F_MULTI) <= 0)
 				goto done;
-			}
 		}
-		rcu_read_unlock();
+cont:
+		idx++;
 	}
 
 done:
-	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
 	cb->args[1] = ip_idx;
 
@@ -1241,19 +1235,6 @@ errout:
 		rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);
 }
 
-static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
-	[RTM_NEWADDR  - RTM_BASE] = { .doit	= inet_rtm_newaddr,	},
-	[RTM_DELADDR  - RTM_BASE] = { .doit	= inet_rtm_deladdr,	},
-	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= inet_dump_ifaddr,	},
-	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet_rtm_newroute,	},
-	[RTM_DELROUTE - RTM_BASE] = { .doit	= inet_rtm_delroute,	},
-	[RTM_GETROUTE - RTM_BASE] = { .doit	= inet_rtm_getroute,
-				      .dumpit	= inet_dump_fib,	},
-#ifdef CONFIG_IP_MULTIPLE_TABLES
-	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= fib4_rules_dump,	},
-#endif
-};
-
 #ifdef CONFIG_SYSCTL
 
 void inet_forward_change(void)
@@ -1265,7 +1246,7 @@ void inet_forward_change(void)
 	ipv4_devconf_dflt.forwarding = on;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		struct in_device *in_dev;
 		rcu_read_lock();
 		in_dev = __in_dev_get_rcu(dev);
@@ -1636,7 +1617,10 @@ void __init devinet_init(void)
 {
 	register_gifconf(PF_INET, inet_gifconf);
 	register_netdevice_notifier(&ip_netdev_notifier);
-	rtnetlink_links[PF_INET] = inet_rtnetlink_table;
+
+	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);
+	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
+	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
 #ifdef CONFIG_SYSCTL
 	devinet_sysctl.sysctl_header =
 		register_sysctl_table(devinet_sysctl.devinet_root_dir);
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 3104112..47c95e8 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -21,13 +21,14 @@ static int esp_output(struct xfrm_state 
 	struct blkcipher_desc desc;
 	struct esp_data *esp;
 	struct sk_buff *trailer;
+	u8 *tail;
 	int blksize;
 	int clen;
 	int alen;
 	int nfrags;
 
 	/* Strip IP+ESP header. */
-	__skb_pull(skb, skb->h.raw - skb->data);
+	__skb_pull(skb, skb_transport_offset(skb));
 	/* Now skb is pure payload to encrypt */
 
 	err = -ENOMEM;
@@ -49,19 +50,21 @@ static int esp_output(struct xfrm_state 
 		goto error;
 
 	/* Fill padding... */
+	tail = skb_tail_pointer(trailer);
 	do {
 		int i;
 		for (i=0; i<clen-skb->len - 2; i++)
-			*(u8*)(trailer->tail + i) = i+1;
+			tail[i] = i + 1;
 	} while (0);
-	*(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
+	tail[clen - skb->len - 2] = (clen - skb->len) - 2;
 	pskb_put(skb, trailer, clen - skb->len);
 
-	__skb_push(skb, skb->data - skb->nh.raw);
-	top_iph = skb->nh.iph;
-	esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4);
+	__skb_push(skb, skb->data - skb_network_header(skb));
+	top_iph = ip_hdr(skb);
+	esph = (struct ip_esp_hdr *)(skb_network_header(skb) +
+				     top_iph->ihl * 4);
 	top_iph->tot_len = htons(skb->len + alen);
-	*(u8*)(trailer->tail - 1) = top_iph->protocol;
+	*(skb_tail_pointer(trailer) - 1) = top_iph->protocol;
 
 	/* this is non-NULL only with UDP Encapsulation */
 	if (x->encap) {
@@ -217,12 +220,12 @@ static int esp_input(struct xfrm_state *
 
 	/* ... check padding bits here. Silly. :-) */
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	ihl = iph->ihl * 4;
 
 	if (x->encap) {
 		struct xfrm_encap_tmpl *encap = x->encap;
-		struct udphdr *uh = (void *)(skb->nh.raw + ihl);
+		struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
 
 		/*
 		 * 1) if the NAT-T peer's IP or port changed then
@@ -260,7 +263,8 @@ static int esp_input(struct xfrm_state *
 
 	iph->protocol = nexthdr[1];
 	pskb_trim(skb, skb->len - alen - padlen - 2);
-	skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl;
+	__skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
+	skb_set_transport_header(skb, -ihl);
 
 	return 0;
 
@@ -268,32 +272,33 @@ out:
 	return -EINVAL;
 }
 
-static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
+static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
 {
 	struct esp_data *esp = x->data;
 	u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-	int enclen = 0;
+	u32 align = max_t(u32, blksize, esp->conf.padlen);
+	u32 rem;
+
+	mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+	rem = mtu & (align - 1);
+	mtu &= ~(align - 1);
 
 	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;
+		mtu -= blksize - 4;
+		mtu += min_t(u32, blksize - 4, rem);
 		break;
 	case XFRM_MODE_BEET:
 		/* The worst case. */
-		enclen = IPV4_BEET_PHMAXLEN;
-		mtu = ALIGN(mtu + enclen + 2, blksize);
+		mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem);
 		break;
 	}
 
-	if (esp->conf.padlen)
-		mtu = ALIGN(mtu, esp->conf.padlen);
-
-	return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
+	return mtu - 2;
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
@@ -302,8 +307,8 @@ static void esp4_err(struct sk_buff *skb
 	struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
-	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
-	    skb->h.icmph->code != ICMP_FRAG_NEEDED)
+	if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
+	    icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
 		return;
 
 	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
@@ -336,6 +341,7 @@ static int esp_init_state(struct xfrm_st
 {
 	struct esp_data *esp = NULL;
 	struct crypto_blkcipher *tfm;
+	u32 align;
 
 	/* null auth and encryption can have zero length keys */
 	if (x->aalg) {
@@ -402,6 +408,8 @@ static int esp_init_state(struct xfrm_st
 	x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
 	if (x->props.mode == XFRM_MODE_TUNNEL)
 		x->props.header_len += sizeof(struct iphdr);
+	else if (x->props.mode == XFRM_MODE_BEET)
+		x->props.header_len += IPV4_BEET_PHMAXLEN;
 	if (x->encap) {
 		struct xfrm_encap_tmpl *encap = x->encap;
 
@@ -417,7 +425,10 @@ static int esp_init_state(struct xfrm_st
 		}
 	}
 	x->data = esp;
-	x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len;
+	align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+	if (esp->conf.padlen)
+		align = max_t(u32, align, esp->conf.padlen);
+	x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len;
 	return 0;
 
 error:
@@ -434,7 +445,7 @@ static struct xfrm_type esp_type =
 	.proto	     	= IPPROTO_ESP,
 	.init_state	= esp_init_state,
 	.destructor	= esp_destroy,
-	.get_max_size	= esp4_get_max_size,
+	.get_mtu	= esp4_get_mtu,
 	.input		= esp_input,
 	.output		= esp_output
 };
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index cac06c4..837f295 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -34,7 +34,6 @@ #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>
 
@@ -46,6 +45,7 @@ #include <net/sock.h>
 #include <net/icmp.h>
 #include <net/arp.h>
 #include <net/ip_fib.h>
+#include <net/rtnetlink.h>
 
 #define FFprint(a...) printk(KERN_DEBUG a)
 
@@ -540,7 +540,7 @@ errout:
 	return err;
 }
 
-int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct fib_config cfg;
 	struct fib_table *tb;
@@ -561,7 +561,7 @@ errout:
 	return err;
 }
 
-int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct fib_config cfg;
 	struct fib_table *tb;
@@ -582,7 +582,7 @@ errout:
 	return err;
 }
 
-int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	unsigned int h, s_h;
 	unsigned int e = 0, s_e;
@@ -777,6 +777,10 @@ static void nl_fib_lookup(struct fib_res
 							    .tos = frn->fl_tos,
 							    .scope = frn->fl_scope } } };
 
+#ifdef CONFIG_IP_MULTIPLE_TABLES
+	res.r = NULL;
+#endif
+
 	frn->err = -ENOENT;
 	if (tb) {
 		local_bh_disable();
@@ -807,7 +811,7 @@ static void nl_fib_input(struct sock *sk
 	if (skb == NULL)
 		return;
 
-	nlh = (struct nlmsghdr *)skb->data;
+	nlh = nlmsg_hdr(skb);
 	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
 	    nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
 		kfree_skb(skb);
@@ -827,7 +831,8 @@ static void nl_fib_input(struct sock *sk
 
 static void nl_fib_lookup_init(void)
 {
-      netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE);
+      netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL,
+      			    THIS_MODULE);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)
@@ -925,6 +930,10 @@ #endif
 	register_netdevice_notifier(&fib_netdev_notifier);
 	register_inetaddr_notifier(&fib_inetaddr_notifier);
 	nl_fib_lookup_init();
+
+	rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL);
+	rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL);
+	rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib);
 }
 
 EXPORT_SYMBOL(inet_addr_type);
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index a4949f9..9cfecf1 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -1027,7 +1027,7 @@ out:
 	return 0;
 }
 
-static struct seq_operations fib_seq_ops = {
+static const struct seq_operations fib_seq_ops = {
 	.start  = fib_seq_start,
 	.next   = fib_seq_next,
 	.stop   = fib_seq_stop,
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index c660c07..33083ad 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -274,11 +274,6 @@ nla_put_failure:
 	return -ENOBUFS;
 }
 
-int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb)
-{
-	return fib_rules_dump(skb, cb, AF_INET);
-}
-
 static u32 fib4_rule_default_pref(void)
 {
 	struct list_head *pos;
@@ -303,6 +298,11 @@ static size_t fib4_rule_nlmsg_payload(st
 	       + nla_total_size(4); /* flow */
 }
 
+static void fib4_rule_flush_cache(void)
+{
+	rt_cache_flush(-1);
+}
+
 static struct fib_rules_ops fib4_rules_ops = {
 	.family		= AF_INET,
 	.rule_size	= sizeof(struct fib4_rule),
@@ -314,6 +314,7 @@ static struct fib_rules_ops fib4_rules_o
 	.fill		= fib4_rule_fill,
 	.default_pref	= fib4_rule_default_pref,
 	.nlmsg_payload	= fib4_rule_nlmsg_payload,
+	.flush_cache	= fib4_rule_flush_cache,
 	.nlgroup	= RTNLGRP_IPV4_RULE,
 	.policy		= fib4_rule_policy,
 	.rules_list	= &fib4_rules,
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 3dad12e..406ea70 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -927,7 +927,7 @@ #endif
 			default:
 				printk(KERN_DEBUG "impossible 102\n");
 				return -EINVAL;
-			};
+			}
 		}
 		return err;
 	}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 214c347..9be7da7 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -50,7 +50,7 @@
  *		Patrick McHardy <kaber@trash.net>
  */
 
-#define VERSION "0.407"
+#define VERSION "0.408"
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -292,8 +292,8 @@ static inline void check_tnode(const str
 
 static int halve_threshold = 25;
 static int inflate_threshold = 50;
-static int halve_threshold_root = 15;
-static int inflate_threshold_root = 25;
+static int halve_threshold_root = 8;
+static int inflate_threshold_root = 15;
 
 
 static void __alias_free_mem(struct rcu_head *head)
@@ -350,11 +350,10 @@ static void __tnode_free_rcu(struct rcu_
 
 static inline void tnode_free(struct tnode *tn)
 {
-	if(IS_LEAF(tn)) {
+	if (IS_LEAF(tn)) {
 		struct leaf *l = (struct leaf *) tn;
 		call_rcu_bh(&l->rcu, __leaf_free_rcu);
-	}
-	else
+	} else
 		call_rcu(&tn->rcu, __tnode_free_rcu);
 }
 
@@ -459,6 +458,7 @@ static struct node *resize(struct trie *
 	struct tnode *old_tn;
 	int inflate_threshold_use;
 	int halve_threshold_use;
+	int max_resize;
 
 	if (!tn)
 		return NULL;
@@ -553,13 +553,14 @@ static struct node *resize(struct trie *
 
 	/* Keep root node larger  */
 
-	if(!tn->parent)
+	if (!tn->parent)
 		inflate_threshold_use = inflate_threshold_root;
 	else
 		inflate_threshold_use = inflate_threshold;
 
 	err = 0;
-	while ((tn->full_children > 0 &&
+	max_resize = 10;
+	while ((tn->full_children > 0 &&  max_resize-- &&
 	       50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
 				inflate_threshold_use * tnode_child_length(tn))) {
 
@@ -574,6 +575,15 @@ #endif
 		}
 	}
 
+	if (max_resize < 0) {
+		if (!tn->parent)
+			printk(KERN_WARNING "Fix inflate_threshold_root. Now=%d size=%d bits\n",
+			       inflate_threshold_root, tn->bits);
+		else
+			printk(KERN_WARNING "Fix inflate_threshold. Now=%d size=%d bits\n",
+			       inflate_threshold, tn->bits);
+	}
+
 	check_tnode(tn);
 
 	/*
@@ -584,13 +594,14 @@ #endif
 
 	/* Keep root node larger  */
 
-	if(!tn->parent)
+	if (!tn->parent)
 		halve_threshold_use = halve_threshold_root;
 	else
 		halve_threshold_use = halve_threshold;
 
 	err = 0;
-	while (tn->bits > 1 &&
+	max_resize = 10;
+	while (tn->bits > 1 &&  max_resize-- &&
 	       100 * (tnode_child_length(tn) - tn->empty_children) <
 	       halve_threshold_use * tnode_child_length(tn)) {
 
@@ -605,6 +616,14 @@ #endif
 		}
 	}
 
+	if (max_resize < 0) {
+		if (!tn->parent)
+			printk(KERN_WARNING "Fix halve_threshold_root. Now=%d size=%d bits\n",
+			       halve_threshold_root, tn->bits);
+		else
+			printk(KERN_WARNING "Fix halve_threshold. Now=%d size=%d bits\n",
+			       halve_threshold, tn->bits);
+	}
 
 	/* Only one child remains */
 	if (tn->empty_children == tnode_child_length(tn) - 1)
@@ -2039,12 +2058,12 @@ static struct node *fib_trie_get_first(s
 {
 	struct node *n ;
 
-	if(!t)
+	if (!t)
 		return NULL;
 
 	n = rcu_dereference(t->trie);
 
-	if(!iter)
+	if (!iter)
 		return NULL;
 
 	if (n) {
@@ -2084,7 +2103,7 @@ static void trie_collect_stats(struct tr
 			int i;
 
 			s->tnodes++;
-			if(tn->bits < MAX_STAT_DEPTH)
+			if (tn->bits < MAX_STAT_DEPTH)
 				s->nodesizes[tn->bits]++;
 
 			for (i = 0; i < (1<<tn->bits); i++)
@@ -2250,7 +2269,7 @@ static inline const char *rtn_scope(enum
 {
 	static char buf[32];
 
-	switch(s) {
+	switch (s) {
 	case RT_SCOPE_UNIVERSE: return "universe";
 	case RT_SCOPE_SITE:	return "site";
 	case RT_SCOPE_LINK:	return "link";
@@ -2340,7 +2359,7 @@ static int fib_trie_seq_show(struct seq_
 	return 0;
 }
 
-static struct seq_operations fib_trie_seq_ops = {
+static const struct seq_operations fib_trie_seq_ops = {
 	.start  = fib_trie_seq_start,
 	.next   = fib_trie_seq_next,
 	.stop   = fib_trie_seq_stop,
@@ -2461,7 +2480,7 @@ static int fib_route_seq_show(struct seq
 	return 0;
 }
 
-static struct seq_operations fib_route_seq_ops = {
+static const struct seq_operations fib_route_seq_ops = {
 	.start  = fib_trie_seq_start,
 	.next   = fib_trie_seq_next,
 	.stop   = fib_trie_seq_stop,
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 4b7a0d9..d38cbba 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -355,7 +355,7 @@ static void icmp_push_reply(struct icmp_
 			   ipc, rt, MSG_DONTWAIT) < 0)
 		ip_flush_pending_frames(icmp_socket->sk);
 	else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) {
-		struct icmphdr *icmph = skb->h.icmph;
+		struct icmphdr *icmph = icmp_hdr(skb);
 		__wsum csum = 0;
 		struct sk_buff *skb1;
 
@@ -392,7 +392,7 @@ static void icmp_reply(struct icmp_bxm *
 	icmp_param->data.icmph.checksum = 0;
 	icmp_out_count(icmp_param->data.icmph.type);
 
-	inet->tos = skb->nh.iph->tos;
+	inet->tos = ip_hdr(skb)->tos;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
 	if (icmp_param->replyopts.optlen) {
@@ -404,7 +404,7 @@ static void icmp_reply(struct icmp_bxm *
 		struct flowi fl = { .nl_u = { .ip4_u =
 					      { .daddr = daddr,
 						.saddr = rt->rt_spec_dst,
-						.tos = RT_TOS(skb->nh.iph->tos) } },
+						.tos = RT_TOS(ip_hdr(skb)->tos) } },
 				    .proto = IPPROTO_ICMP };
 		security_skb_classify_flow(skb, &fl);
 		if (ip_route_output_key(&rt, &fl))
@@ -448,9 +448,10 @@ void icmp_send(struct sk_buff *skb_in, i
 	 *	Check this, icmp_send is called from the most obscure devices
 	 *	sometimes.
 	 */
-	iph = skb_in->nh.iph;
+	iph = ip_hdr(skb_in);
 
-	if ((u8 *)iph < skb_in->head || (u8 *)(iph + 1) > skb_in->tail)
+	if ((u8 *)iph < skb_in->head ||
+	    (skb_in->network_header + sizeof(*iph)) > skb_in->tail)
 		goto out;
 
 	/*
@@ -484,7 +485,7 @@ void icmp_send(struct sk_buff *skb_in, i
 			u8 _inner_type, *itp;
 
 			itp = skb_header_pointer(skb_in,
-						 skb_in->nh.raw +
+						 skb_network_header(skb_in) +
 						 (iph->ihl << 2) +
 						 offsetof(struct icmphdr,
 							  type) -
@@ -536,7 +537,7 @@ void icmp_send(struct sk_buff *skb_in, i
 	icmp_param.data.icmph.un.gateway = info;
 	icmp_param.data.icmph.checksum	 = 0;
 	icmp_param.skb	  = skb_in;
-	icmp_param.offset = skb_in->nh.raw - skb_in->data;
+	icmp_param.offset = skb_network_offset(skb_in);
 	icmp_out_count(icmp_param.data.icmph.type);
 	inet_sk(icmp_socket->sk)->tos = tos;
 	ipc.addr = iph->saddr;
@@ -613,7 +614,7 @@ static void icmp_unreach(struct sk_buff 
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 		goto out_err;
 
-	icmph = skb->h.icmph;
+	icmph = icmp_hdr(skb);
 	iph   = (struct iphdr *)skb->data;
 
 	if (iph->ihl < 5) /* Mangled header, drop. */
@@ -676,7 +677,7 @@ static void icmp_unreach(struct sk_buff 
 			printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
 					    "type %u, code %u "
 					    "error to a broadcast: %u.%u.%u.%u on %s\n",
-			       NIPQUAD(skb->nh.iph->saddr),
+			       NIPQUAD(ip_hdr(skb)->saddr),
 			       icmph->type, icmph->code,
 			       NIPQUAD(iph->daddr),
 			       skb->dev->name);
@@ -743,7 +744,7 @@ static void icmp_redirect(struct sk_buff
 
 	iph = (struct iphdr *)skb->data;
 
-	switch (skb->h.icmph->code & 7) {
+	switch (icmp_hdr(skb)->code & 7) {
 	case ICMP_REDIR_NET:
 	case ICMP_REDIR_NETTOS:
 		/*
@@ -751,8 +752,8 @@ static void icmp_redirect(struct sk_buff
 		 */
 	case ICMP_REDIR_HOST:
 	case ICMP_REDIR_HOSTTOS:
-		ip_rt_redirect(skb->nh.iph->saddr, iph->daddr,
-			       skb->h.icmph->un.gateway,
+		ip_rt_redirect(ip_hdr(skb)->saddr, iph->daddr,
+			       icmp_hdr(skb)->un.gateway,
 			       iph->saddr, skb->dev);
 		break;
 	}
@@ -780,7 +781,7 @@ static void icmp_echo(struct sk_buff *sk
 	if (!sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
-		icmp_param.data.icmph	   = *skb->h.icmph;
+		icmp_param.data.icmph	   = *icmp_hdr(skb);
 		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
 		icmp_param.skb		   = skb;
 		icmp_param.offset	   = 0;
@@ -816,7 +817,7 @@ static void icmp_timestamp(struct sk_buf
 	icmp_param.data.times[2] = icmp_param.data.times[1];
 	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
 		BUG();
-	icmp_param.data.icmph	   = *skb->h.icmph;
+	icmp_param.data.icmph	   = *icmp_hdr(skb);
 	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
 	icmp_param.data.icmph.code = 0;
 	icmp_param.skb		   = skb;
@@ -943,7 +944,7 @@ int icmp_rcv(struct sk_buff *skb)
 	if (!pskb_pull(skb, sizeof(struct icmphdr)))
 		goto error;
 
-	icmph = skb->h.icmph;
+	icmph = icmp_hdr(skb);
 
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 8cedb2a..f4dd474 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -314,7 +314,9 @@ static struct sk_buff *igmpv3_newpack(st
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
-	skb->nh.iph = pip =(struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
+	skb_reset_network_header(skb);
+	pip = ip_hdr(skb);
+	skb_put(skb, sizeof(struct iphdr) + 4);
 
 	pip->version  = 4;
 	pip->ihl      = (sizeof(struct iphdr)+4)>>2;
@@ -331,8 +333,9 @@ static struct sk_buff *igmpv3_newpack(st
 	((u8*)&pip[1])[2] = 0;
 	((u8*)&pip[1])[3] = 0;
 
-	pig =(struct igmpv3_report *)skb_put(skb, sizeof(*pig));
-	skb->h.igmph = (struct igmphdr *)pig;
+	skb->transport_header = skb->network_header + sizeof(struct iphdr) + 4;
+	skb_put(skb, sizeof(*pig));
+	pig = igmpv3_report_hdr(skb);
 	pig->type = IGMPV3_HOST_MEMBERSHIP_REPORT;
 	pig->resv1 = 0;
 	pig->csum = 0;
@@ -343,16 +346,14 @@ static struct sk_buff *igmpv3_newpack(st
 
 static int igmpv3_sendpack(struct sk_buff *skb)
 {
-	struct iphdr *pip = skb->nh.iph;
-	struct igmphdr *pig = skb->h.igmph;
-	int iplen, igmplen;
+	struct iphdr *pip = ip_hdr(skb);
+	struct igmphdr *pig = igmp_hdr(skb);
+	const int iplen = skb->tail - skb->network_header;
+	const int igmplen = skb->tail - skb->transport_header;
 
-	iplen = skb->tail - (unsigned char *)skb->nh.iph;
 	pip->tot_len = htons(iplen);
 	ip_send_check(pip);
-
-	igmplen = skb->tail - (unsigned char *)skb->h.igmph;
-	pig->csum = ip_compute_csum((void *)skb->h.igmph, igmplen);
+	pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen);
 
 	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev,
 		       dst_output);
@@ -379,7 +380,7 @@ static struct sk_buff *add_grhead(struct
 	pgr->grec_auxwords = 0;
 	pgr->grec_nsrcs = 0;
 	pgr->grec_mca = pmc->multiaddr;
-	pih = (struct igmpv3_report *)skb->h.igmph;
+	pih = igmpv3_report_hdr(skb);
 	pih->ngrec = htons(ntohs(pih->ngrec)+1);
 	*ppgr = pgr;
 	return skb;
@@ -412,7 +413,7 @@ static struct sk_buff *add_grec(struct s
 	if (!*psf_list)
 		goto empty_source;
 
-	pih = skb ? (struct igmpv3_report *)skb->h.igmph : NULL;
+	pih = skb ? igmpv3_report_hdr(skb) : NULL;
 
 	/* EX and TO_EX get a fresh packet, if needed */
 	if (truncate) {
@@ -664,7 +665,9 @@ static int igmp_send_report(struct in_de
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
-	skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+	skb_put(skb, sizeof(struct iphdr) + 4);
 
 	iph->version  = 4;
 	iph->ihl      = (sizeof(struct iphdr)+4)>>2;
@@ -827,8 +830,8 @@ static void igmp_heard_report(struct in_
 static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 	int len)
 {
-	struct igmphdr 		*ih = skb->h.igmph;
-	struct igmpv3_query *ih3 = (struct igmpv3_query *)ih;
+	struct igmphdr 		*ih = igmp_hdr(skb);
+	struct igmpv3_query *ih3 = igmpv3_query_hdr(skb);
 	struct ip_mc_list	*im;
 	__be32			group = ih->group;
 	int			max_delay;
@@ -861,12 +864,12 @@ static void igmp_heard_query(struct in_d
 		if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
 			return;
 
-		ih3 = (struct igmpv3_query *) skb->h.raw;
+		ih3 = igmpv3_query_hdr(skb);
 		if (ih3->nsrcs) {
 			if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
 					   + ntohs(ih3->nsrcs)*sizeof(__be32)))
 				return;
-			ih3 = (struct igmpv3_query *) skb->h.raw;
+			ih3 = igmpv3_query_hdr(skb);
 		}
 
 		max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
@@ -943,7 +946,7 @@ int igmp_rcv(struct sk_buff *skb)
 			goto drop;
 	}
 
-	ih = skb->h.igmph;
+	ih = igmp_hdr(skb);
 	switch (ih->type) {
 	case IGMP_HOST_MEMBERSHIP_QUERY:
 		igmp_heard_query(in_dev, skb, len);
@@ -2285,9 +2288,8 @@ static inline struct ip_mc_list *igmp_mc
 	struct ip_mc_list *im = NULL;
 	struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
 
-	for (state->dev = dev_base, state->in_dev = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->in_dev = NULL;
+	for_each_netdev(state->dev) {
 		struct in_device *in_dev;
 		in_dev = in_dev_get(state->dev);
 		if (!in_dev)
@@ -2313,7 +2315,7 @@ static struct ip_mc_list *igmp_mc_get_ne
 			read_unlock(&state->in_dev->mc_list_lock);
 			in_dev_put(state->in_dev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_net_device(state->dev);
 		if (!state->dev) {
 			state->in_dev = NULL;
 			break;
@@ -2397,7 +2399,7 @@ #endif
 	return 0;
 }
 
-static struct seq_operations igmp_mc_seq_ops = {
+static const struct seq_operations igmp_mc_seq_ops = {
 	.start	=	igmp_mc_seq_start,
 	.next	=	igmp_mc_seq_next,
 	.stop	=	igmp_mc_seq_stop,
@@ -2447,9 +2449,9 @@ static inline struct ip_sf_list *igmp_mc
 	struct ip_mc_list *im = NULL;
 	struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->idev = NULL;
+	state->im = NULL;
+	for_each_netdev(state->dev) {
 		struct in_device *idev;
 		idev = in_dev_get(state->dev);
 		if (unlikely(idev == NULL))
@@ -2485,7 +2487,7 @@ static struct ip_sf_list *igmp_mcf_get_n
 				read_unlock(&state->idev->mc_list_lock);
 				in_dev_put(state->idev);
 			}
-			state->dev = state->dev->next;
+			state->dev = next_net_device(state->dev);
 			if (!state->dev) {
 				state->idev = NULL;
 				goto out;
@@ -2571,7 +2573,7 @@ static int igmp_mcf_seq_show(struct seq_
 	return 0;
 }
 
-static struct seq_operations igmp_mcf_seq_ops = {
+static const struct seq_operations igmp_mcf_seq_ops = {
 	.start	=	igmp_mcf_seq_start,
 	.next	=	igmp_mcf_seq_next,
 	.stop	=	igmp_mcf_seq_stop,
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 5df71cd..dbeacd8 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -27,6 +27,7 @@ #include <net/inet_connection_sock.h>
 #include <net/inet_hashtables.h>
 #include <net/inet_timewait_sock.h>
 #include <net/inet6_hashtables.h>
+#include <net/netlink.h>
 
 #include <linux/inet.h>
 #include <linux/stddef.h>
@@ -60,7 +61,7 @@ static int inet_csk_diag_fill(struct soc
 	struct nlmsghdr  *nlh;
 	void *info = NULL;
 	struct inet_diag_meminfo  *minfo = NULL;
-	unsigned char	 *b = skb->tail;
+	unsigned char	 *b = skb_tail_pointer(skb);
 	const struct inet_diag_handler *handler;
 
 	handler = inet_diag_table[unlh->nlmsg_type];
@@ -147,12 +148,12 @@ #undef EXPIRES_IN_MS
 	    icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
 		icsk->icsk_ca_ops->get_info(sk, ext, skb);
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -EMSGSIZE;
 }
 
@@ -163,7 +164,7 @@ static int inet_twsk_diag_fill(struct in
 {
 	long tmo;
 	struct inet_diag_msg *r;
-	const unsigned char *previous_tail = skb->tail;
+	const unsigned char *previous_tail = skb_tail_pointer(skb);
 	struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
 					 unlh->nlmsg_type, sizeof(*r));
 
@@ -205,10 +206,10 @@ #if defined(CONFIG_IPV6) || defined (CON
 			       &tw6->tw_v6_daddr);
 	}
 #endif
-	nlh->nlmsg_len = skb->tail - previous_tail;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - previous_tail;
 	return skb->len;
 nlmsg_failure:
-	skb_trim(skb, previous_tail - skb->data);
+	nlmsg_trim(skb, previous_tail);
 	return -EMSGSIZE;
 }
 
@@ -535,7 +536,7 @@ static int inet_diag_fill_req(struct sk_
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	struct inet_sock *inet = inet_sk(sk);
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct inet_diag_msg *r;
 	struct nlmsghdr *nlh;
 	long tmo;
@@ -574,12 +575,12 @@ #if defined(CONFIG_IPV6) || defined (CON
 			       &inet6_rsk(req)->rmt_addr);
 	}
 #endif
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 
 	return skb->len;
 
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -805,68 +806,43 @@ done:
 	return skb->len;
 }
 
-static inline int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
-		return 0;
+	int hdrlen = sizeof(struct inet_diag_req);
 
-	if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX)
-		goto err_inval;
+	if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
+	    nlmsg_len(nlh) < hdrlen)
+		return -EINVAL;
 
 	if (inet_diag_table[nlh->nlmsg_type] == NULL)
 		return -ENOENT;
 
-	if (NLMSG_LENGTH(sizeof(struct inet_diag_req)) > skb->len)
-		goto err_inval;
-
-	if (nlh->nlmsg_flags&NLM_F_DUMP) {
-		if (nlh->nlmsg_len >
-		    (4 + NLMSG_SPACE(sizeof(struct inet_diag_req)))) {
-			struct rtattr *rta = (void *)(NLMSG_DATA(nlh) +
-						 sizeof(struct inet_diag_req));
-			if (rta->rta_type != INET_DIAG_REQ_BYTECODE ||
-			    rta->rta_len < 8 ||
-			    rta->rta_len >
-			    (nlh->nlmsg_len -
-			     NLMSG_SPACE(sizeof(struct inet_diag_req))))
-				goto err_inval;
-			if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
-				goto err_inval;
+	if (nlh->nlmsg_flags & NLM_F_DUMP) {
+		if (nlmsg_attrlen(nlh, hdrlen)) {
+			struct nlattr *attr;
+
+			attr = nlmsg_find_attr(nlh, hdrlen,
+					       INET_DIAG_REQ_BYTECODE);
+			if (attr == NULL ||
+			    nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
+			    inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
+				return -EINVAL;
 		}
+
 		return netlink_dump_start(idiagnl, skb, nlh,
 					  inet_diag_dump, NULL);
-	} else
-		return inet_diag_get_exact(skb, nlh);
-
-err_inval:
-	return -EINVAL;
-}
-
-
-static inline void inet_diag_rcv_skb(struct sk_buff *skb)
-{
-	if (skb->len >= NLMSG_SPACE(0)) {
-		int err;
-		struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
-
-		if (nlh->nlmsg_len < sizeof(*nlh) ||
-		    skb->len < nlh->nlmsg_len)
-			return;
-		err = inet_diag_rcv_msg(skb, nlh);
-		if (err || nlh->nlmsg_flags & NLM_F_ACK)
-			netlink_ack(skb, nlh, err);
 	}
+
+	return inet_diag_get_exact(skb, nlh);
 }
 
 static void inet_diag_rcv(struct sock *sk, int len)
 {
-	struct sk_buff *skb;
-	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
+	unsigned int qlen = 0;
 
-	while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {
-		inet_diag_rcv_skb(skb);
-		kfree_skb(skb);
-	}
+	do {
+		netlink_run_queue(sk, &qlen, &inet_diag_rcv_msg);
+	} while (qlen);
 }
 
 static DEFINE_SPINLOCK(inet_diag_register_lock);
@@ -917,7 +893,7 @@ static int __init inet_diag_init(void)
 		goto out;
 
 	idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv,
-					THIS_MODULE);
+					NULL, THIS_MODULE);
 	if (idiagnl == NULL)
 		goto out_free_table;
 	err = 0;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index db3ef96..2f44e61 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -87,10 +87,12 @@ #define PEER_MAXDEPTH 40 /* sufficient f
 
 static int peer_total;
 /* Exported for sysctl_net_ipv4.  */
-int inet_peer_threshold = 65536 + 128;	/* start to throw entries more
+int inet_peer_threshold __read_mostly = 65536 + 128;	/* start to throw entries more
 					 * aggressively at this stage */
-int inet_peer_minttl = 120 * HZ;	/* TTL under high load: 120 sec */
-int inet_peer_maxttl = 10 * 60 * HZ;	/* usual time to live: 10 min */
+int inet_peer_minttl __read_mostly = 120 * HZ;	/* TTL under high load: 120 sec */
+int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;	/* usual time to live: 10 min */
+int inet_peer_gc_mintime __read_mostly = 10 * HZ;
+int inet_peer_gc_maxtime __read_mostly = 120 * HZ;
 
 static struct inet_peer *inet_peer_unused_head;
 static struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
@@ -99,9 +101,6 @@ static DEFINE_SPINLOCK(inet_peer_unused_
 static void peer_check_expire(unsigned long dummy);
 static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
 
-/* Exported for sysctl_net_ipv4.  */
-int inet_peer_gc_mintime = 10 * HZ,
-    inet_peer_gc_maxtime = 120 * HZ;
 
 /* Called from ip_output.c:ip_init  */
 void __init inet_initpeers(void)
@@ -151,20 +150,27 @@ static void unlink_from_unused(struct in
 	spin_unlock_bh(&inet_peer_unused_lock);
 }
 
-/* Called with local BH disabled and the pool lock held. */
-#define lookup(daddr) 						\
+/*
+ * Called with local BH disabled and the pool lock held.
+ * _stack is known to be NULL or not at compile time,
+ * so compiler will optimize the if (_stack) tests.
+ */
+#define lookup(_daddr,_stack) 					\
 ({								\
 	struct inet_peer *u, **v;				\
-	stackptr = stack;					\
-	*stackptr++ = &peer_root;				\
+	if (_stack) {						\
+		stackptr = _stack;				\
+		*stackptr++ = &peer_root;			\
+	}							\
 	for (u = peer_root; u != peer_avl_empty; ) {		\
-		if (daddr == u->v4daddr)			\
+		if (_daddr == u->v4daddr)			\
 			break;					\
-		if ((__force __u32)daddr < (__force __u32)u->v4daddr)	\
+		if ((__force __u32)_daddr < (__force __u32)u->v4daddr)	\
 			v = &u->avl_left;			\
 		else						\
 			v = &u->avl_right;			\
-		*stackptr++ = v;				\
+		if (_stack)					\
+			*stackptr++ = v;			\
 		u = *v;						\
 	}							\
 	u;							\
@@ -288,7 +294,7 @@ static void unlink_from_pool(struct inet
 	if (atomic_read(&p->refcnt) == 1) {
 		struct inet_peer **stack[PEER_MAXDEPTH];
 		struct inet_peer ***stackptr, ***delp;
-		if (lookup(p->v4daddr) != p)
+		if (lookup(p->v4daddr, stack) != p)
 			BUG();
 		delp = stackptr - 1; /* *delp[0] == p */
 		if (p->avl_left == peer_avl_empty) {
@@ -373,7 +379,7 @@ struct inet_peer *inet_getpeer(__be32 da
 
 	/* Look up for the address quickly. */
 	read_lock_bh(&peer_pool_lock);
-	p = lookup(daddr);
+	p = lookup(daddr, NULL);
 	if (p != peer_avl_empty)
 		atomic_inc(&p->refcnt);
 	read_unlock_bh(&peer_pool_lock);
@@ -400,7 +406,7 @@ struct inet_peer *inet_getpeer(__be32 da
 
 	write_lock_bh(&peer_pool_lock);
 	/* Check if an entry has suddenly appeared. */
-	p = lookup(daddr);
+	p = lookup(daddr, stack);
 	if (p != peer_avl_empty)
 		goto out_free;
 
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 369e721..9cb04df 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -67,14 +67,14 @@ int ip_forward(struct sk_buff *skb)
 	if (skb->pkt_type != PACKET_HOST)
 		goto drop;
 
-	skb->ip_summed = CHECKSUM_NONE;
+	skb_forward_csum(skb);
 
 	/*
 	 *	According to the RFC, we must first decrease the TTL field. If
 	 *	that reaches zero, we must reply an ICMP control message telling
 	 *	that the packet's lifetime expired.
 	 */
-	if (skb->nh.iph->ttl <= 1)
+	if (ip_hdr(skb)->ttl <= 1)
 		goto too_many_hops;
 
 	if (!xfrm4_route_forward(skb))
@@ -85,10 +85,18 @@ int ip_forward(struct sk_buff *skb)
 	if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto sr_failed;
 
+	if (unlikely(skb->len > dst_mtu(&rt->u.dst) &&
+	             (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
+		IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+			  htonl(dst_mtu(&rt->u.dst)));
+		goto drop;
+	}
+
 	/* We are about to mangle packet. Copy it! */
 	if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))
 		goto drop;
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	/* Decrease ttl after skb cow done */
 	ip_decrease_ttl(iph);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index b6f0553..0231bdc 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -92,7 +92,7 @@ #define LAST_IN			1
 	spinlock_t	lock;
 	atomic_t	refcnt;
 	struct timer_list timer;	/* when will this queue expire?		*/
-	struct timeval	stamp;
+	ktime_t		stamp;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -184,7 +184,7 @@ static __inline__ struct ipq *frag_alloc
 {
 	struct ipq *qp = kmalloc(sizeof(struct ipq), GFP_ATOMIC);
 
-	if(!qp)
+	if (!qp)
 		return NULL;
 	atomic_add(sizeof(struct ipq), &ip_frag_mem);
 	return qp;
@@ -321,11 +321,11 @@ #ifdef CONFIG_SMP
 	 * promoted read lock to write lock.
 	 */
 	hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
-		if(qp->id == qp_in->id		&&
-		   qp->saddr == qp_in->saddr	&&
-		   qp->daddr == qp_in->daddr	&&
-		   qp->protocol == qp_in->protocol &&
-		   qp->user == qp_in->user) {
+		if (qp->id == qp_in->id		&&
+		    qp->saddr == qp_in->saddr	&&
+		    qp->daddr == qp_in->daddr	&&
+		    qp->protocol == qp_in->protocol &&
+		    qp->user == qp_in->user) {
 			atomic_inc(&qp->refcnt);
 			write_unlock(&ipfrag_lock);
 			qp_in->last_in |= COMPLETE;
@@ -398,11 +398,11 @@ static inline struct ipq *ip_find(struct
 	read_lock(&ipfrag_lock);
 	hash = ipqhashfn(id, saddr, daddr, protocol);
 	hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
-		if(qp->id == id		&&
-		   qp->saddr == saddr	&&
-		   qp->daddr == daddr	&&
-		   qp->protocol == protocol &&
-		   qp->user == user) {
+		if (qp->id == id		&&
+		    qp->saddr == saddr	&&
+		    qp->daddr == daddr	&&
+		    qp->protocol == protocol &&
+		    qp->user == user) {
 			atomic_inc(&qp->refcnt);
 			read_unlock(&ipfrag_lock);
 			return qp;
@@ -479,11 +479,11 @@ static void ip_frag_queue(struct ipq *qp
 		goto err;
 	}
 
-	offset = ntohs(skb->nh.iph->frag_off);
+	offset = ntohs(ip_hdr(skb)->frag_off);
 	flags = offset & ~IP_OFFSET;
 	offset &= IP_OFFSET;
 	offset <<= 3;		/* offset is in 8-byte chunks */
-	ihl = skb->nh.iph->ihl * 4;
+	ihl = ip_hdrlen(skb);
 
 	/* Determine the position of this fragment. */
 	end = offset + skb->len - ihl;
@@ -524,7 +524,7 @@ static void ip_frag_queue(struct ipq *qp
 	 * this fragment, right?
 	 */
 	prev = NULL;
-	for(next = qp->fragments; next != NULL; next = next->next) {
+	for (next = qp->fragments; next != NULL; next = next->next) {
 		if (FRAG_CB(next)->offset >= offset)
 			break;	/* bingo! */
 		prev = next;
@@ -592,7 +592,7 @@ static void ip_frag_queue(struct ipq *qp
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &qp->stamp);
+	qp->stamp = skb->tstamp;
 	qp->meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
@@ -624,10 +624,10 @@ static struct sk_buff *ip_frag_reasm(str
 	BUG_TRAP(FRAG_CB(head)->offset == 0);
 
 	/* Allocate a new buffer for the datagram. */
-	ihlen = head->nh.iph->ihl*4;
+	ihlen = ip_hdrlen(head);
 	len = ihlen + qp->len;
 
-	if(len > 65535)
+	if (len > 65535)
 		goto out_oversize;
 
 	/* Head of list must not be cloned. */
@@ -658,7 +658,7 @@ static struct sk_buff *ip_frag_reasm(str
 	}
 
 	skb_shinfo(head)->frag_list = head->next;
-	skb_push(head, head->data - head->nh.raw);
+	skb_push(head, head->data - skb_network_header(head));
 	atomic_sub(head->truesize, &ip_frag_mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
@@ -674,9 +674,9 @@ static struct sk_buff *ip_frag_reasm(str
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &qp->stamp);
+	head->tstamp = qp->stamp;
 
-	iph = head->nh.iph;
+	iph = ip_hdr(head);
 	iph->frag_off = 0;
 	iph->tot_len = htons(len);
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
@@ -700,7 +700,6 @@ out_fail:
 /* Process an incoming IP datagram fragment. */
 struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 {
-	struct iphdr *iph = skb->nh.iph;
 	struct ipq *qp;
 	struct net_device *dev;
 
@@ -713,7 +712,7 @@ struct sk_buff *ip_defrag(struct sk_buff
 	dev = skb->dev;
 
 	/* Lookup (or create) queue header */
-	if ((qp = ip_find(iph, user)) != NULL) {
+	if ((qp = ip_find(ip_hdr(skb), user)) != NULL) {
 		struct sk_buff *ret = NULL;
 
 		spin_lock(&qp->lock);
@@ -734,7 +733,7 @@ struct sk_buff *ip_defrag(struct sk_buff
 	return NULL;
 }
 
-void ipfrag_init(void)
+void __init ipfrag_init(void)
 {
 	ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
 				 (jiffies ^ (jiffies >> 6)));
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 9151da6..6328293 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -191,11 +191,11 @@ static struct ip_tunnel * ipgre_tunnel_l
 	return NULL;
 }
 
-static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t)
+static struct ip_tunnel **__ipgre_bucket(struct ip_tunnel_parm *parms)
 {
-	__be32 remote = t->parms.iph.daddr;
-	__be32 local = t->parms.iph.saddr;
-	__be32 key = t->parms.i_key;
+	__be32 remote = parms->iph.daddr;
+	__be32 local = parms->iph.saddr;
+	__be32 key = parms->i_key;
 	unsigned h = HASH(key);
 	int prio = 0;
 
@@ -209,6 +209,11 @@ static struct ip_tunnel **ipgre_bucket(s
 	return &tunnels[prio][h];
 }
 
+static inline struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t)
+{
+	return __ipgre_bucket(&t->parms);
+}
+
 static void ipgre_tunnel_link(struct ip_tunnel *t)
 {
 	struct ip_tunnel **tp = ipgre_bucket(t);
@@ -240,17 +245,9 @@ static struct ip_tunnel * ipgre_tunnel_l
 	__be32 key = parms->i_key;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
-	unsigned h = HASH(key);
-	int prio = 0;
 	char name[IFNAMSIZ];
 
-	if (local)
-		prio |= 1;
-	if (remote && !MULTICAST(remote)) {
-		prio |= 2;
-		h ^= HASH(remote);
-	}
-	for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
+	for (tp = __ipgre_bucket(parms); (t = *tp) != NULL; tp = &t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
 			if (key == t->parms.i_key)
 				return t;
@@ -320,8 +317,8 @@ #ifndef I_WISH_WORLD_WERE_PERFECT
 	struct iphdr *iph = (struct iphdr*)skb->data;
 	__be16	     *p = (__be16*)(skb->data+(iph->ihl<<2));
 	int grehlen = (iph->ihl<<2) + 4;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct ip_tunnel *t;
 	__be16 flags;
 
@@ -388,8 +385,8 @@ #else
 	struct iphdr *iph = (struct iphdr*)dp;
 	struct iphdr *eiph;
 	__be16	     *p = (__be16*)(dp+(iph->ihl<<2));
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	int rel_type = 0;
 	int rel_code = 0;
 	__be32 rel_info = 0;
@@ -422,7 +419,7 @@ #else
 	default:
 		return;
 	case ICMP_PARAMETERPROB:
-		n = ntohl(skb->h.icmph->un.gateway) >> 24;
+		n = ntohl(icmp_hdr(skb)->un.gateway) >> 24;
 		if (n < (iph->ihl<<2))
 			return;
 
@@ -442,7 +439,7 @@ #else
 			return;
 		case ICMP_FRAG_NEEDED:
 			/* And it is the only really necessary thing :-) */
-			n = ntohs(skb->h.icmph->un.frag.mtu);
+			n = ntohs(icmp_hdr(skb)->un.frag.mtu);
 			if (n < grehlen+68)
 				return;
 			n -= grehlen;
@@ -474,7 +471,7 @@ #else
 	dst_release(skb2->dst);
 	skb2->dst = NULL;
 	skb_pull(skb2, skb->data - (u8*)eiph);
-	skb2->nh.raw = skb2->data;
+	skb_reset_network_header(skb2);
 
 	/* Try to guess incoming interface */
 	memset(&fl, 0, sizeof(fl));
@@ -533,9 +530,9 @@ static inline void ipgre_ecn_decapsulate
 {
 	if (INET_ECN_is_ce(iph->tos)) {
 		if (skb->protocol == htons(ETH_P_IP)) {
-			IP_ECN_set_ce(skb->nh.iph);
+			IP_ECN_set_ce(ip_hdr(skb));
 		} else if (skb->protocol == htons(ETH_P_IPV6)) {
-			IP6_ECN_set_ce(skb->nh.ipv6h);
+			IP6_ECN_set_ce(ipv6_hdr(skb));
 		}
 	}
 }
@@ -565,7 +562,7 @@ static int ipgre_rcv(struct sk_buff *skb
 	if (!pskb_may_pull(skb, 16))
 		goto drop_nolock;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	h = skb->data;
 	flags = *(__be16*)h;
 
@@ -616,9 +613,10 @@ static int ipgre_rcv(struct sk_buff *skb
 				offset += 4;
 		}
 
-		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = __pskb_pull(skb, offset);
-		skb_postpull_rcsum(skb, skb->h.raw, offset);
+		skb_reset_mac_header(skb);
+		__pskb_pull(skb, offset);
+		skb_reset_network_header(skb);
+		skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
 		skb->pkt_type = PACKET_HOST;
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 		if (MULTICAST(iph->daddr)) {
@@ -669,7 +667,7 @@ static int ipgre_tunnel_xmit(struct sk_b
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct net_device_stats *stats = &tunnel->stat;
-	struct iphdr  *old_iph = skb->nh.iph;
+	struct iphdr  *old_iph = ip_hdr(skb);
 	struct iphdr  *tiph;
 	u8     tos;
 	__be16 df;
@@ -720,7 +718,7 @@ #ifdef CONFIG_IPV6
 			addr_type = ipv6_addr_type(addr6);
 
 			if (addr_type == IPV6_ADDR_ANY) {
-				addr6 = &skb->nh.ipv6h->daddr;
+				addr6 = &ipv6_hdr(skb)->daddr;
 				addr_type = ipv6_addr_type(addr6);
 			}
 
@@ -824,11 +822,12 @@ #endif
 			skb_set_owner_w(new_skb, skb->sk);
 		dev_kfree_skb(skb);
 		skb = new_skb;
-		old_iph = skb->nh.iph;
+		old_iph = ip_hdr(skb);
 	}
 
-	skb->h.raw = skb->nh.raw;
-	skb->nh.raw = skb_push(skb, gre_hlen);
+	skb->transport_header = skb->network_header;
+	skb_push(skb, gre_hlen);
+	skb_reset_network_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
@@ -839,7 +838,7 @@ #endif
 	 *	Push down and install the IPIP header.
 	 */
 
-	iph 			=	skb->nh.iph;
+	iph 			=	ip_hdr(skb);
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr) >> 2;
 	iph->frag_off		=	df;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index f38e976..9706939 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -158,7 +158,7 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ip_
 int ip_call_ra_chain(struct sk_buff *skb)
 {
 	struct ip_ra_chain *ra;
-	u8 protocol = skb->nh.iph->protocol;
+	u8 protocol = ip_hdr(skb)->protocol;
 	struct sock *last = NULL;
 
 	read_lock(&ip_ra_lock);
@@ -171,7 +171,7 @@ int ip_call_ra_chain(struct sk_buff *skb
 		if (sk && inet_sk(sk)->num == protocol &&
 		    (!sk->sk_bound_dev_if ||
 		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
-			if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+			if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 				skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN);
 				if (skb == NULL) {
 					read_unlock(&ip_ra_lock);
@@ -198,17 +198,15 @@ int ip_call_ra_chain(struct sk_buff *skb
 
 static inline int ip_local_deliver_finish(struct sk_buff *skb)
 {
-	int ihl = skb->nh.iph->ihl*4;
-
-	__skb_pull(skb, ihl);
+	__skb_pull(skb, ip_hdrlen(skb));
 
 	/* Point into the IP datagram, just past the header. */
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 
 	rcu_read_lock();
 	{
 		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
-		int protocol = skb->nh.iph->protocol;
+		int protocol = ip_hdr(skb)->protocol;
 		int hash;
 		struct sock *raw_sk;
 		struct net_protocol *ipprot;
@@ -220,7 +218,7 @@ static inline int ip_local_deliver_finis
 		/* If there maybe a raw socket we must check - if not we
 		 * don't care less
 		 */
-		if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
+		if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
 			raw_sk = NULL;
 
 		if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
@@ -266,7 +264,7 @@ int ip_local_deliver(struct sk_buff *skb
 	 *	Reassemble IP fragments.
 	 */
 
-	if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 		skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);
 		if (!skb)
 			return 0;
@@ -294,7 +292,7 @@ static inline int ip_rcv_options(struct 
 		goto drop;
 	}
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	if (ip_options_compile(NULL, skb)) {
 		IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
@@ -330,7 +328,8 @@ drop:
 
 static inline int ip_rcv_finish(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
+	struct rtable *rt;
 
 	/*
 	 *	Initialise the virtual path cache for the packet. It describes
@@ -342,6 +341,8 @@ static inline int ip_rcv_finish(struct s
 		if (unlikely(err)) {
 			if (err == -EHOSTUNREACH)
 				IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+			else if (err == -ENETUNREACH)
+				IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES);
 			goto drop;
 		}
 	}
@@ -360,6 +361,12 @@ #endif
 	if (iph->ihl > 5 && ip_rcv_options(skb))
 		goto drop;
 
+	rt = (struct rtable*)skb->dst;
+	if (rt->rt_type == RTN_MULTICAST)
+		IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
+	else if (rt->rt_type == RTN_BROADCAST)
+		IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS);
+
 	return dst_input(skb);
 
 drop:
@@ -391,7 +398,7 @@ int ip_rcv(struct sk_buff *skb, struct n
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
 		goto inhdr_error;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	/*
 	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
@@ -410,13 +417,16 @@ int ip_rcv(struct sk_buff *skb, struct n
 	if (!pskb_may_pull(skb, iph->ihl*4))
 		goto inhdr_error;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
 		goto inhdr_error;
 
 	len = ntohs(iph->tot_len);
-	if (skb->len < len || len < (iph->ihl*4))
+	if (skb->len < len) {
+		IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
+		goto drop;
+	} else if (len < (iph->ihl*4))
 		goto inhdr_error;
 
 	/* Our transport medium may have padded the buffer out. Now we know it
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index f906a80..2513468 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -40,7 +40,7 @@ #include <net/cipso_ipv4.h>
 void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
 			    __be32 daddr, struct rtable *rt, int is_frag)
 {
-	unsigned char * iph = skb->nh.raw;
+	unsigned char *iph = skb_network_header(skb);
 
 	memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
 	memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
@@ -104,13 +104,13 @@ int ip_options_echo(struct ip_options * 
 		return 0;
 	}
 
-	sptr = skb->nh.raw;
+	sptr = skb_network_header(skb);
 	dptr = dopt->__data;
 
 	if (skb->dst)
 		daddr = ((struct rtable*)skb->dst)->rt_spec_dst;
 	else
-		daddr = skb->nh.iph->daddr;
+		daddr = ip_hdr(skb)->daddr;
 
 	if (sopt->rr) {
 		optlen  = sptr[sopt->rr+1];
@@ -180,7 +180,8 @@ int ip_options_echo(struct ip_options * 
 			/*
 			 * RFC1812 requires to fix illegal source routes.
 			 */
-			if (memcmp(&skb->nh.iph->saddr, &start[soffset+3], 4) == 0)
+			if (memcmp(&ip_hdr(skb)->saddr,
+				   &start[soffset + 3], 4) == 0)
 				doffset -= 4;
 		}
 		if (doffset > 3) {
@@ -217,7 +218,7 @@ int ip_options_echo(struct ip_options * 
 
 void ip_options_fragment(struct sk_buff * skb)
 {
-	unsigned char * optptr = skb->nh.raw + sizeof(struct iphdr);
+	unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr);
 	struct ip_options * opt = &(IPCB(skb)->opt);
 	int  l = opt->optlen;
 	int  optlen;
@@ -264,12 +265,13 @@ int ip_options_compile(struct ip_options
 
 	if (!opt) {
 		opt = &(IPCB(skb)->opt);
-		iph = skb->nh.raw;
+		iph = skb_network_header(skb);
 		opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
 		optptr = iph + sizeof(struct iphdr);
 		opt->is_data = 0;
 	} else {
-		optptr = opt->is_data ? opt->__data : (unsigned char*)&(skb->nh.iph[1]);
+		optptr = opt->is_data ? opt->__data :
+					(unsigned char *)&(ip_hdr(skb)[1]);
 		iph = optptr - sizeof(struct iphdr);
 	}
 
@@ -563,7 +565,7 @@ void ip_forward_options(struct sk_buff *
 	struct   ip_options * opt	= &(IPCB(skb)->opt);
 	unsigned char * optptr;
 	struct rtable *rt = (struct rtable*)skb->dst;
-	unsigned char *raw = skb->nh.raw;
+	unsigned char *raw = skb_network_header(skb);
 
 	if (opt->rr_needaddr) {
 		optptr = (unsigned char *)raw + opt->rr;
@@ -587,7 +589,7 @@ void ip_forward_options(struct sk_buff *
 		if (srrptr + 3 <= srrspace) {
 			opt->is_changed = 1;
 			ip_rt_get_source(&optptr[srrptr-1], rt);
-			skb->nh.iph->daddr = rt->rt_dst;
+			ip_hdr(skb)->daddr = rt->rt_dst;
 			optptr[2] = srrptr+4;
 		} else if (net_ratelimit())
 			printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");
@@ -599,7 +601,7 @@ void ip_forward_options(struct sk_buff *
 	}
 	if (opt->is_changed) {
 		opt->is_changed = 0;
-		ip_send_check(skb->nh.iph);
+		ip_send_check(ip_hdr(skb));
 	}
 }
 
@@ -608,8 +610,8 @@ int ip_options_rcv_srr(struct sk_buff *s
 	struct ip_options *opt = &(IPCB(skb)->opt);
 	int srrspace, srrptr;
 	__be32 nexthop;
-	struct iphdr *iph = skb->nh.iph;
-	unsigned char * optptr = skb->nh.raw + opt->srr;
+	struct iphdr *iph = ip_hdr(skb);
+	unsigned char *optptr = skb_network_header(skb) + opt->srr;
 	struct rtable *rt = (struct rtable*)skb->dst;
 	struct rtable *rt2;
 	int err;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d096332..d6427d9 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -95,8 +95,8 @@ __inline__ void ip_send_check(struct iph
 /* dev_loopback_xmit for use with netfilter. */
 static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 {
-	newskb->mac.raw = newskb->data;
-	__skb_pull(newskb, newskb->nh.raw - newskb->data);
+	skb_reset_mac_header(newskb);
+	__skb_pull(newskb, skb_network_offset(newskb));
 	newskb->pkt_type = PACKET_LOOPBACK;
 	newskb->ip_summed = CHECKSUM_UNNECESSARY;
 	BUG_TRAP(newskb->dst);
@@ -125,11 +125,9 @@ int ip_build_and_send_pkt(struct sk_buff
 	struct iphdr *iph;
 
 	/* Build the IP header. */
-	if (opt)
-		iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
-	else
-		iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr));
-
+	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
 	iph->version  = 4;
 	iph->ihl      = 5;
 	iph->tos      = inet->tos;
@@ -143,7 +141,6 @@ int ip_build_and_send_pkt(struct sk_buff
 	iph->protocol = sk->sk_protocol;
 	iph->tot_len  = htons(skb->len);
 	ip_select_ident(iph, &rt->u.dst, sk);
-	skb->nh.iph   = iph;
 
 	if (opt && opt->optlen) {
 		iph->ihl += opt->optlen>>2;
@@ -163,9 +160,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt)
 static inline int ip_finish_output2(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
+	struct rtable *rt = (struct rtable *)dst;
 	struct net_device *dev = dst->dev;
 	int hh_len = LL_RESERVED_SPACE(dev);
 
+	if (rt->rt_type == RTN_MULTICAST)
+		IP_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+	else if (rt->rt_type == RTN_BROADCAST)
+		IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS);
+
 	/* Be paranoid, rather than too clever. */
 	if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
 		struct sk_buff *skb2;
@@ -192,6 +195,14 @@ static inline int ip_finish_output2(stru
 	return -EINVAL;
 }
 
+static inline int ip_skb_dst_mtu(struct sk_buff *skb)
+{
+	struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
+
+	return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
+	       skb->dst->dev->mtu : dst_mtu(skb->dst);
+}
+
 static inline int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
@@ -201,7 +212,7 @@ #if defined(CONFIG_NETFILTER) && defined
 		return dst_output(skb);
 	}
 #endif
-	if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
+	if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
 		return ip_fragment(skb, ip_finish_output2);
 	else
 		return ip_finish_output2(skb);
@@ -248,7 +259,7 @@ #endif
 
 		/* Multicasts with ttl 0 must not go beyond the host */
 
-		if (skb->nh.iph->ttl == 0) {
+		if (ip_hdr(skb)->ttl == 0) {
 			kfree_skb(skb);
 			return 0;
 		}
@@ -333,7 +344,9 @@ packet_routed:
 		goto no_route;
 
 	/* OK, we know where to send it, allocate and build IP header. */
-	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+	skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
 	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
 	iph->tot_len = htons(skb->len);
 	if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
@@ -344,7 +357,6 @@ packet_routed:
 	iph->protocol = sk->sk_protocol;
 	iph->saddr    = rt->rt_src;
 	iph->daddr    = rt->rt_dst;
-	skb->nh.iph   = iph;
 	/* Transport layer set skb->h.foo itself. */
 
 	if (opt && opt->optlen) {
@@ -386,21 +398,10 @@ static void ip_copy_metadata(struct sk_b
 #ifdef CONFIG_NET_SCHED
 	to->tc_index = from->tc_index;
 #endif
-#ifdef CONFIG_NETFILTER
-	/* Connection association is same as pre-frag packet */
-	nf_conntrack_put(to->nfct);
-	to->nfct = from->nfct;
-	nf_conntrack_get(to->nfct);
-	to->nfctinfo = from->nfctinfo;
+	nf_copy(to, from);
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
 	to->ipvs_property = from->ipvs_property;
 #endif
-#ifdef CONFIG_BRIDGE_NETFILTER
-	nf_bridge_put(to->nf_bridge);
-	to->nf_bridge = from->nf_bridge;
-	nf_bridge_get(to->nf_bridge);
-#endif
-#endif
 	skb_copy_secmark(to, from);
 }
 
@@ -430,12 +431,12 @@ int ip_fragment(struct sk_buff *skb, int
 	 *	Point into the IP datagram header.
 	 */
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
 		IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-			  htonl(dst_mtu(&rt->u.dst)));
+			  htonl(ip_skb_dst_mtu(skb)));
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
@@ -502,10 +503,11 @@ int ip_fragment(struct sk_buff *skb, int
 			 * before previous one went down. */
 			if (frag) {
 				frag->ip_summed = CHECKSUM_NONE;
-				frag->h.raw = frag->data;
-				frag->nh.raw = __skb_push(frag, hlen);
-				memcpy(frag->nh.raw, iph, hlen);
-				iph = frag->nh.iph;
+				skb_reset_transport_header(frag);
+				__skb_push(frag, hlen);
+				skb_reset_network_header(frag);
+				memcpy(skb_network_header(frag), iph, hlen);
+				iph = ip_hdr(frag);
 				iph->tot_len = htons(frag->len);
 				ip_copy_metadata(frag, skb);
 				if (offset == 0)
@@ -566,7 +568,7 @@ slow_path:
 	 *	Keep copying data until we run out.
 	 */
 
-	while(left > 0)	{
+	while (left > 0) {
 		len = left;
 		/* IF: it doesn't fit, use 'mtu' - the data space left */
 		if (len > mtu)
@@ -593,8 +595,8 @@ slow_path:
 		ip_copy_metadata(skb2, skb);
 		skb_reserve(skb2, ll_rs);
 		skb_put(skb2, len + hlen);
-		skb2->nh.raw = skb2->data;
-		skb2->h.raw = skb2->data + hlen;
+		skb_reset_network_header(skb2);
+		skb2->transport_header = skb2->network_header + hlen;
 
 		/*
 		 *	Charge the memory for the fragment to any owner
@@ -608,19 +610,19 @@ slow_path:
 		 *	Copy the packet header into the new buffer.
 		 */
 
-		memcpy(skb2->nh.raw, skb->data, hlen);
+		skb_copy_from_linear_data(skb, skb_network_header(skb2), hlen);
 
 		/*
 		 *	Copy a block of the IP datagram.
 		 */
-		if (skb_copy_bits(skb, ptr, skb2->h.raw, len))
+		if (skb_copy_bits(skb, ptr, skb_transport_header(skb2), len))
 			BUG();
 		left -= len;
 
 		/*
 		 *	Fill in the new header fields.
 		 */
-		iph = skb2->nh.iph;
+		iph = ip_hdr(skb2);
 		iph->frag_off = htons((offset >> 3));
 
 		/* ANK: dirty, but effective trick. Upgrade options only if
@@ -722,10 +724,10 @@ static inline int ip_ufo_append_data(str
 		skb_put(skb,fragheaderlen + transhdrlen);
 
 		/* initialize network header pointer */
-		skb->nh.raw = skb->data;
+		skb_reset_network_header(skb);
 
 		/* initialize protocol header pointer */
-		skb->h.raw = skb->data + fragheaderlen;
+		skb->transport_header = skb->network_header + fragheaderlen;
 
 		skb->ip_summed = CHECKSUM_PARTIAL;
 		skb->csum = 0;
@@ -799,7 +801,9 @@ int ip_append_data(struct sock *sk,
 			inet->cork.addr = ipc->addr;
 		}
 		dst_hold(&rt->u.dst);
-		inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
+		inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
+					    rt->u.dst.dev->mtu :
+					    dst_mtu(rt->u.dst.path);
 		inet->cork.rt = rt;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
@@ -929,9 +933,10 @@ alloc_new_skb:
 			 *	Find where to start putting bytes.
 			 */
 			data = skb_put(skb, fraglen);
-			skb->nh.raw = data + exthdrlen;
+			skb_set_network_header(skb, exthdrlen);
+			skb->transport_header = (skb->network_header +
+						 fragheaderlen);
 			data += fragheaderlen;
-			skb->h.raw = data + exthdrlen;
 
 			if (fraggap) {
 				skb->csum = skb_copy_and_csum_bits(
@@ -1100,8 +1105,6 @@ ssize_t	ip_append_page(struct sock *sk, 
 		}
 		if (len <= 0) {
 			struct sk_buff *skb_prev;
-			char *data;
-			struct iphdr *iph;
 			int alloclen;
 
 			skb_prev = skb;
@@ -1124,15 +1127,15 @@ ssize_t	ip_append_page(struct sock *sk, 
 			/*
 			 *	Find where to start putting bytes.
 			 */
-			data = skb_put(skb, fragheaderlen + fraggap);
-			skb->nh.iph = iph = (struct iphdr *)data;
-			data += fragheaderlen;
-			skb->h.raw = data;
-
+			skb_put(skb, fragheaderlen + fraggap);
+			skb_reset_network_header(skb);
+			skb->transport_header = (skb->network_header +
+						 fragheaderlen);
 			if (fraggap) {
-				skb->csum = skb_copy_and_csum_bits(
-					skb_prev, maxfraglen,
-					data, fraggap, 0);
+				skb->csum = skb_copy_and_csum_bits(skb_prev,
+								   maxfraglen,
+						    skb_transport_header(skb),
+								   fraggap, 0);
 				skb_prev->csum = csum_sub(skb_prev->csum,
 							  skb->csum);
 				pskb_trim_unique(skb_prev, maxfraglen);
@@ -1198,10 +1201,10 @@ int ip_push_pending_frames(struct sock *
 	tail_skb = &(skb_shinfo(skb)->frag_list);
 
 	/* move skb->data to ip header from ext header */
-	if (skb->data < skb->nh.raw)
-		__skb_pull(skb, skb->nh.raw - skb->data);
+	if (skb->data < skb_network_header(skb))
+		__skb_pull(skb, skb_network_offset(skb));
 	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
-		__skb_pull(tmp_skb, skb->h.raw - skb->nh.raw);
+		__skb_pull(tmp_skb, skb_network_header_len(skb));
 		*tail_skb = tmp_skb;
 		tail_skb = &(tmp_skb->next);
 		skb->len += tmp_skb->len;
@@ -1216,13 +1219,13 @@ int ip_push_pending_frames(struct sock *
 	 * to fragment the frame generated here. No matter, what transforms
 	 * how transforms change size of the packet, it will come out.
 	 */
-	if (inet->pmtudisc != IP_PMTUDISC_DO)
+	if (inet->pmtudisc < IP_PMTUDISC_DO)
 		skb->local_df = 1;
 
 	/* DF bit is set when we want to see DF on outgoing frames.
 	 * If local_df is set too, we still allow to fragment this frame
 	 * locally. */
-	if (inet->pmtudisc == IP_PMTUDISC_DO ||
+	if (inet->pmtudisc >= IP_PMTUDISC_DO ||
 	    (skb->len <= dst_mtu(&rt->u.dst) &&
 	     ip_dont_fragment(sk, &rt->u.dst)))
 		df = htons(IP_DF);
@@ -1352,11 +1355,11 @@ void ip_send_reply(struct sock *sk, stru
 		struct flowi fl = { .nl_u = { .ip4_u =
 					      { .daddr = daddr,
 						.saddr = rt->rt_spec_dst,
-						.tos = RT_TOS(skb->nh.iph->tos) } },
+						.tos = RT_TOS(ip_hdr(skb)->tos) } },
 				    /* Not quite clean, but right. */
 				    .uli_u = { .ports =
-					       { .sport = skb->h.th->dest,
-						 .dport = skb->h.th->source } },
+					       { .sport = tcp_hdr(skb)->dest,
+						 .dport = tcp_hdr(skb)->source } },
 				    .proto = sk->sk_protocol };
 		security_skb_classify_flow(skb, &fl);
 		if (ip_route_output_key(&rt, &fl))
@@ -1370,14 +1373,16 @@ void ip_send_reply(struct sock *sk, stru
 	   with locally disabled BH and that sk cannot be already spinlocked.
 	 */
 	bh_lock_sock(sk);
-	inet->tos = skb->nh.iph->tos;
+	inet->tos = ip_hdr(skb)->tos;
 	sk->sk_priority = skb->priority;
-	sk->sk_protocol = skb->nh.iph->protocol;
+	sk->sk_protocol = ip_hdr(skb)->protocol;
 	ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
 		       &ipc, rt, MSG_DONTWAIT);
 	if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
 		if (arg->csumoffset >= 0)
-			*((__sum16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum));
+			*((__sum16 *)skb_transport_header(skb) +
+			  arg->csumoffset) = csum_fold(csum_add(skb->csum,
+								arg->csum));
 		skb->ip_summed = CHECKSUM_NONE;
 		ip_push_pending_frames(sk);
 	}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 23048d9..4d54457 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -59,7 +59,7 @@ static void ip_cmsg_recv_pktinfo(struct 
 	struct in_pktinfo info;
 	struct rtable *rt = (struct rtable *)skb->dst;
 
-	info.ipi_addr.s_addr = skb->nh.iph->daddr;
+	info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
 	if (rt) {
 		info.ipi_ifindex = rt->rt_iif;
 		info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
@@ -73,13 +73,13 @@ static void ip_cmsg_recv_pktinfo(struct 
 
 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
 {
-	int ttl = skb->nh.iph->ttl;
+	int ttl = ip_hdr(skb)->ttl;
 	put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
 }
 
 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
 {
-	put_cmsg(msg, SOL_IP, IP_TOS, 1, &skb->nh.iph->tos);
+	put_cmsg(msg, SOL_IP, IP_TOS, 1, &ip_hdr(skb)->tos);
 }
 
 static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
@@ -87,7 +87,8 @@ static void ip_cmsg_recv_opts(struct msg
 	if (IPCB(skb)->opt.optlen == 0)
 		return;
 
-	put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen, skb->nh.iph+1);
+	put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen,
+		 ip_hdr(skb) + 1);
 }
 
 
@@ -268,18 +269,21 @@ void ip_icmp_error(struct sock *sk, stru
 	serr = SKB_EXT_ERR(skb);
 	serr->ee.ee_errno = err;
 	serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
-	serr->ee.ee_type = skb->h.icmph->type;
-	serr->ee.ee_code = skb->h.icmph->code;
+	serr->ee.ee_type = icmp_hdr(skb)->type;
+	serr->ee.ee_code = icmp_hdr(skb)->code;
 	serr->ee.ee_pad = 0;
 	serr->ee.ee_info = info;
 	serr->ee.ee_data = 0;
-	serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
+	serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) -
+				   skb_network_header(skb);
 	serr->port = port;
 
-	skb->h.raw = payload;
-	if (!skb_pull(skb, payload - skb->data) ||
-	    sock_queue_err_skb(sk, skb))
-		kfree_skb(skb);
+	if (skb_pull(skb, payload - skb->data) != NULL) {
+		skb_reset_transport_header(skb);
+		if (sock_queue_err_skb(sk, skb) == 0)
+			return;
+	}
+	kfree_skb(skb);
 }
 
 void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
@@ -296,8 +300,9 @@ void ip_local_error(struct sock *sk, int
 	if (!skb)
 		return;
 
-	iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
-	skb->nh.iph = iph;
+	skb_put(skb, sizeof(struct iphdr));
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
 	iph->daddr = daddr;
 
 	serr = SKB_EXT_ERR(skb);
@@ -308,11 +313,11 @@ void ip_local_error(struct sock *sk, int
 	serr->ee.ee_pad = 0;
 	serr->ee.ee_info = info;
 	serr->ee.ee_data = 0;
-	serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+	serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
 	serr->port = port;
 
-	skb->h.raw = skb->tail;
-	__skb_pull(skb, skb->tail - skb->data);
+	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);
+	skb_reset_transport_header(skb);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -354,7 +359,8 @@ int ip_recv_error(struct sock *sk, struc
 	sin = (struct sockaddr_in *)msg->msg_name;
 	if (sin) {
 		sin->sin_family = AF_INET;
-		sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset);
+		sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) +
+						   serr->addr_offset);
 		sin->sin_port = serr->port;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
@@ -366,7 +372,7 @@ int ip_recv_error(struct sock *sk, struc
 		struct inet_sock *inet = inet_sk(sk);
 
 		sin->sin_family = AF_INET;
-		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		sin->sin_port = 0;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 		if (inet->cmsg_flags)
@@ -403,20 +409,20 @@ out:
  */
 
 static int do_ip_setsockopt(struct sock *sk, int level,
-		int optname, char __user *optval, int optlen)
+			    int optname, char __user *optval, int optlen)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	int val=0,err;
 
 	if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
-			    (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
-			    (1<<IP_RETOPTS) | (1<<IP_TOS) |
-			    (1<<IP_TTL) | (1<<IP_HDRINCL) |
-			    (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
-			    (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
-			    (1<<IP_PASSSEC))) ||
-				optname == IP_MULTICAST_TTL ||
-				optname == IP_MULTICAST_LOOP) {
+			     (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
+			     (1<<IP_RETOPTS) | (1<<IP_TOS) |
+			     (1<<IP_TTL) | (1<<IP_HDRINCL) |
+			     (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
+			     (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
+			     (1<<IP_PASSSEC))) ||
+	    optname == IP_MULTICAST_TTL ||
+	    optname == IP_MULTICAST_LOOP) {
 		if (optlen >= sizeof(int)) {
 			if (get_user(val, (int __user *) optval))
 				return -EFAULT;
@@ -440,444 +446,444 @@ #endif
 	lock_sock(sk);
 
 	switch (optname) {
-		case IP_OPTIONS:
-		{
-			struct ip_options * opt = NULL;
-			if (optlen > 40 || optlen < 0)
-				goto e_inval;
-			err = ip_options_get_from_user(&opt, optval, optlen);
-			if (err)
-				break;
-			if (inet->is_icsk) {
-				struct inet_connection_sock *icsk = inet_csk(sk);
+	case IP_OPTIONS:
+	{
+		struct ip_options * opt = NULL;
+		if (optlen > 40 || optlen < 0)
+			goto e_inval;
+		err = ip_options_get_from_user(&opt, optval, optlen);
+		if (err)
+			break;
+		if (inet->is_icsk) {
+			struct inet_connection_sock *icsk = inet_csk(sk);
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-				if (sk->sk_family == PF_INET ||
-				    (!((1 << sk->sk_state) &
-				       (TCPF_LISTEN | TCPF_CLOSE)) &&
-				     inet->daddr != LOOPBACK4_IPV6)) {
+			if (sk->sk_family == PF_INET ||
+			    (!((1 << sk->sk_state) &
+			       (TCPF_LISTEN | TCPF_CLOSE)) &&
+			     inet->daddr != LOOPBACK4_IPV6)) {
 #endif
-					if (inet->opt)
-						icsk->icsk_ext_hdr_len -= inet->opt->optlen;
-					if (opt)
-						icsk->icsk_ext_hdr_len += opt->optlen;
-					icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
+				if (inet->opt)
+					icsk->icsk_ext_hdr_len -= inet->opt->optlen;
+				if (opt)
+					icsk->icsk_ext_hdr_len += opt->optlen;
+				icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-				}
-#endif
 			}
-			opt = xchg(&inet->opt, opt);
-			kfree(opt);
-			break;
+#endif
 		}
-		case IP_PKTINFO:
-			if (val)
-				inet->cmsg_flags |= IP_CMSG_PKTINFO;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_PKTINFO;
-			break;
-		case IP_RECVTTL:
-			if (val)
-				inet->cmsg_flags |=  IP_CMSG_TTL;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_TTL;
-			break;
-		case IP_RECVTOS:
-			if (val)
-				inet->cmsg_flags |=  IP_CMSG_TOS;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_TOS;
-			break;
-		case IP_RECVOPTS:
-			if (val)
-				inet->cmsg_flags |=  IP_CMSG_RECVOPTS;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_RECVOPTS;
-			break;
-		case IP_RETOPTS:
-			if (val)
-				inet->cmsg_flags |= IP_CMSG_RETOPTS;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
+		opt = xchg(&inet->opt, opt);
+		kfree(opt);
+		break;
+	}
+	case IP_PKTINFO:
+		if (val)
+			inet->cmsg_flags |= IP_CMSG_PKTINFO;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_PKTINFO;
+		break;
+	case IP_RECVTTL:
+		if (val)
+			inet->cmsg_flags |=  IP_CMSG_TTL;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_TTL;
+		break;
+	case IP_RECVTOS:
+		if (val)
+			inet->cmsg_flags |=  IP_CMSG_TOS;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_TOS;
+		break;
+	case IP_RECVOPTS:
+		if (val)
+			inet->cmsg_flags |=  IP_CMSG_RECVOPTS;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_RECVOPTS;
+		break;
+	case IP_RETOPTS:
+		if (val)
+			inet->cmsg_flags |= IP_CMSG_RETOPTS;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
+		break;
+	case IP_PASSSEC:
+		if (val)
+			inet->cmsg_flags |= IP_CMSG_PASSSEC;
+		else
+			inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
+		break;
+	case IP_TOS:	/* This sets both TOS and Precedence */
+		if (sk->sk_type == SOCK_STREAM) {
+			val &= ~3;
+			val |= inet->tos & 3;
+		}
+		if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP &&
+		    !capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
 			break;
-		case IP_PASSSEC:
-			if (val)
-				inet->cmsg_flags |= IP_CMSG_PASSSEC;
-			else
-				inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
+		}
+		if (inet->tos != val) {
+			inet->tos = val;
+			sk->sk_priority = rt_tos2priority(val);
+			sk_dst_reset(sk);
+		}
+		break;
+	case IP_TTL:
+		if (optlen<1)
+			goto e_inval;
+		if (val != -1 && (val < 1 || val>255))
+			goto e_inval;
+		inet->uc_ttl = val;
+		break;
+	case IP_HDRINCL:
+		if (sk->sk_type != SOCK_RAW) {
+			err = -ENOPROTOOPT;
 			break;
-		case IP_TOS:	/* This sets both TOS and Precedence */
-			if (sk->sk_type == SOCK_STREAM) {
-				val &= ~3;
-				val |= inet->tos & 3;
-			}
-			if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP &&
-			    !capable(CAP_NET_ADMIN)) {
-				err = -EPERM;
+		}
+		inet->hdrincl = val ? 1 : 0;
+		break;
+	case IP_MTU_DISCOVER:
+		if (val<0 || val>3)
+			goto e_inval;
+		inet->pmtudisc = val;
+		break;
+	case IP_RECVERR:
+		inet->recverr = !!val;
+		if (!val)
+			skb_queue_purge(&sk->sk_error_queue);
+		break;
+	case IP_MULTICAST_TTL:
+		if (sk->sk_type == SOCK_STREAM)
+			goto e_inval;
+		if (optlen<1)
+			goto e_inval;
+		if (val==-1)
+			val = 1;
+		if (val < 0 || val > 255)
+			goto e_inval;
+		inet->mc_ttl = val;
+		break;
+	case IP_MULTICAST_LOOP:
+		if (optlen<1)
+			goto e_inval;
+		inet->mc_loop = !!val;
+		break;
+	case IP_MULTICAST_IF:
+	{
+		struct ip_mreqn mreq;
+		struct net_device *dev = NULL;
+
+		if (sk->sk_type == SOCK_STREAM)
+			goto e_inval;
+		/*
+		 *	Check the arguments are allowable
+		 */
+
+		err = -EFAULT;
+		if (optlen >= sizeof(struct ip_mreqn)) {
+			if (copy_from_user(&mreq,optval,sizeof(mreq)))
 				break;
-			}
-			if (inet->tos != val) {
-				inet->tos = val;
-				sk->sk_priority = rt_tos2priority(val);
-				sk_dst_reset(sk);
-			}
-			break;
-		case IP_TTL:
-			if (optlen<1)
-				goto e_inval;
-			if (val != -1 && (val < 1 || val>255))
-				goto e_inval;
-			inet->uc_ttl = val;
-			break;
-		case IP_HDRINCL:
-			if (sk->sk_type != SOCK_RAW) {
-				err = -ENOPROTOOPT;
+		} else {
+			memset(&mreq, 0, sizeof(mreq));
+			if (optlen >= sizeof(struct in_addr) &&
+			    copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
+				break;
+		}
+
+		if (!mreq.imr_ifindex) {
+			if (mreq.imr_address.s_addr == INADDR_ANY) {
+				inet->mc_index = 0;
+				inet->mc_addr  = 0;
+				err = 0;
 				break;
 			}
-			inet->hdrincl = val ? 1 : 0;
-			break;
-		case IP_MTU_DISCOVER:
-			if (val<0 || val>2)
-				goto e_inval;
-			inet->pmtudisc = val;
-			break;
-		case IP_RECVERR:
-			inet->recverr = !!val;
-			if (!val)
-				skb_queue_purge(&sk->sk_error_queue);
-			break;
-		case IP_MULTICAST_TTL:
-			if (sk->sk_type == SOCK_STREAM)
-				goto e_inval;
-			if (optlen<1)
-				goto e_inval;
-			if (val==-1)
-				val = 1;
-			if (val < 0 || val > 255)
-				goto e_inval;
-			inet->mc_ttl = val;
-			break;
-		case IP_MULTICAST_LOOP:
-			if (optlen<1)
-				goto e_inval;
-			inet->mc_loop = !!val;
-			break;
-		case IP_MULTICAST_IF:
-		{
-			struct ip_mreqn mreq;
-			struct net_device *dev = NULL;
+			dev = ip_dev_find(mreq.imr_address.s_addr);
+			if (dev) {
+				mreq.imr_ifindex = dev->ifindex;
+				dev_put(dev);
+			}
+		} else
+			dev = __dev_get_by_index(mreq.imr_ifindex);
 
-			if (sk->sk_type == SOCK_STREAM)
-				goto e_inval;
-			/*
-			 *	Check the arguments are allowable
-			 */
 
-			err = -EFAULT;
-			if (optlen >= sizeof(struct ip_mreqn)) {
-				if (copy_from_user(&mreq,optval,sizeof(mreq)))
-					break;
-			} else {
-				memset(&mreq, 0, sizeof(mreq));
-				if (optlen >= sizeof(struct in_addr) &&
-				    copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
-					break;
-			}
+		err = -EADDRNOTAVAIL;
+		if (!dev)
+			break;
 
-			if (!mreq.imr_ifindex) {
-				if (mreq.imr_address.s_addr == INADDR_ANY) {
-					inet->mc_index = 0;
-					inet->mc_addr  = 0;
-					err = 0;
-					break;
-				}
-				dev = ip_dev_find(mreq.imr_address.s_addr);
-				if (dev) {
-					mreq.imr_ifindex = dev->ifindex;
-					dev_put(dev);
-				}
-			} else
-				dev = __dev_get_by_index(mreq.imr_ifindex);
+		err = -EINVAL;
+		if (sk->sk_bound_dev_if &&
+		    mreq.imr_ifindex != sk->sk_bound_dev_if)
+			break;
 
+		inet->mc_index = mreq.imr_ifindex;
+		inet->mc_addr  = mreq.imr_address.s_addr;
+		err = 0;
+		break;
+	}
 
-			err = -EADDRNOTAVAIL;
-			if (!dev)
-				break;
+	case IP_ADD_MEMBERSHIP:
+	case IP_DROP_MEMBERSHIP:
+	{
+		struct ip_mreqn mreq;
 
-			err = -EINVAL;
-			if (sk->sk_bound_dev_if &&
-			    mreq.imr_ifindex != sk->sk_bound_dev_if)
+		if (optlen < sizeof(struct ip_mreq))
+			goto e_inval;
+		err = -EFAULT;
+		if (optlen >= sizeof(struct ip_mreqn)) {
+			if (copy_from_user(&mreq,optval,sizeof(mreq)))
 				break;
+		} else {
+			memset(&mreq, 0, sizeof(mreq));
+			if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
+				break;
+		}
 
-			inet->mc_index = mreq.imr_ifindex;
-			inet->mc_addr  = mreq.imr_address.s_addr;
-			err = 0;
+		if (optname == IP_ADD_MEMBERSHIP)
+			err = ip_mc_join_group(sk, &mreq);
+		else
+			err = ip_mc_leave_group(sk, &mreq);
+		break;
+	}
+	case IP_MSFILTER:
+	{
+		extern int sysctl_igmp_max_msf;
+		struct ip_msfilter *msf;
+
+		if (optlen < IP_MSFILTER_SIZE(0))
+			goto e_inval;
+		if (optlen > sysctl_optmem_max) {
+			err = -ENOBUFS;
 			break;
 		}
+		msf = kmalloc(optlen, GFP_KERNEL);
+		if (msf == 0) {
+			err = -ENOBUFS;
+			break;
+		}
+		err = -EFAULT;
+		if (copy_from_user(msf, optval, optlen)) {
+			kfree(msf);
+			break;
+		}
+		/* numsrc >= (1G-4) overflow in 32 bits */
+		if (msf->imsf_numsrc >= 0x3ffffffcU ||
+		    msf->imsf_numsrc > sysctl_igmp_max_msf) {
+			kfree(msf);
+			err = -ENOBUFS;
+			break;
+		}
+		if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
+			kfree(msf);
+			err = -EINVAL;
+			break;
+		}
+		err = ip_mc_msfilter(sk, msf, 0);
+		kfree(msf);
+		break;
+	}
+	case IP_BLOCK_SOURCE:
+	case IP_UNBLOCK_SOURCE:
+	case IP_ADD_SOURCE_MEMBERSHIP:
+	case IP_DROP_SOURCE_MEMBERSHIP:
+	{
+		struct ip_mreq_source mreqs;
+		int omode, add;
 
-		case IP_ADD_MEMBERSHIP:
-		case IP_DROP_MEMBERSHIP:
-		{
-			struct ip_mreqn mreq;
-
-			if (optlen < sizeof(struct ip_mreq))
-				goto e_inval;
+		if (optlen != sizeof(struct ip_mreq_source))
+			goto e_inval;
+		if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
 			err = -EFAULT;
-			if (optlen >= sizeof(struct ip_mreqn)) {
-				if(copy_from_user(&mreq,optval,sizeof(mreq)))
-					break;
-			} else {
-				memset(&mreq, 0, sizeof(mreq));
-				if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
-					break;
-			}
-
-			if (optname == IP_ADD_MEMBERSHIP)
-				err = ip_mc_join_group(sk, &mreq);
-			else
-				err = ip_mc_leave_group(sk, &mreq);
 			break;
 		}
-		case IP_MSFILTER:
-		{
-			extern int sysctl_igmp_max_msf;
-			struct ip_msfilter *msf;
+		if (optname == IP_BLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 1;
+		} else if (optname == IP_UNBLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 0;
+		} else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
+			struct ip_mreqn mreq;
 
-			if (optlen < IP_MSFILTER_SIZE(0))
-				goto e_inval;
-			if (optlen > sysctl_optmem_max) {
-				err = -ENOBUFS;
-				break;
-			}
-			msf = kmalloc(optlen, GFP_KERNEL);
-			if (msf == 0) {
-				err = -ENOBUFS;
+			mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
+			mreq.imr_address.s_addr = mreqs.imr_interface;
+			mreq.imr_ifindex = 0;
+			err = ip_mc_join_group(sk, &mreq);
+			if (err && err != -EADDRINUSE)
 				break;
-			}
+			omode = MCAST_INCLUDE;
+			add = 1;
+		} else /* IP_DROP_SOURCE_MEMBERSHIP */ {
+			omode = MCAST_INCLUDE;
+			add = 0;
+		}
+		err = ip_mc_source(add, omode, sk, &mreqs, 0);
+		break;
+	}
+	case MCAST_JOIN_GROUP:
+	case MCAST_LEAVE_GROUP:
+	{
+		struct group_req greq;
+		struct sockaddr_in *psin;
+		struct ip_mreqn mreq;
+
+		if (optlen < sizeof(struct group_req))
+			goto e_inval;
+		err = -EFAULT;
+		if (copy_from_user(&greq, optval, sizeof(greq)))
+			break;
+		psin = (struct sockaddr_in *)&greq.gr_group;
+		if (psin->sin_family != AF_INET)
+			goto e_inval;
+		memset(&mreq, 0, sizeof(mreq));
+		mreq.imr_multiaddr = psin->sin_addr;
+		mreq.imr_ifindex = greq.gr_interface;
+
+		if (optname == MCAST_JOIN_GROUP)
+			err = ip_mc_join_group(sk, &mreq);
+		else
+			err = ip_mc_leave_group(sk, &mreq);
+		break;
+	}
+	case MCAST_JOIN_SOURCE_GROUP:
+	case MCAST_LEAVE_SOURCE_GROUP:
+	case MCAST_BLOCK_SOURCE:
+	case MCAST_UNBLOCK_SOURCE:
+	{
+		struct group_source_req greqs;
+		struct ip_mreq_source mreqs;
+		struct sockaddr_in *psin;
+		int omode, add;
+
+		if (optlen != sizeof(struct group_source_req))
+			goto e_inval;
+		if (copy_from_user(&greqs, optval, sizeof(greqs))) {
 			err = -EFAULT;
-			if (copy_from_user(msf, optval, optlen)) {
-				kfree(msf);
-				break;
-			}
-			/* numsrc >= (1G-4) overflow in 32 bits */
-			if (msf->imsf_numsrc >= 0x3ffffffcU ||
-			    msf->imsf_numsrc > sysctl_igmp_max_msf) {
-				kfree(msf);
-				err = -ENOBUFS;
-				break;
-			}
-			if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {
-				kfree(msf);
-				err = -EINVAL;
-				break;
-			}
-			err = ip_mc_msfilter(sk, msf, 0);
-			kfree(msf);
 			break;
 		}
-		case IP_BLOCK_SOURCE:
-		case IP_UNBLOCK_SOURCE:
-		case IP_ADD_SOURCE_MEMBERSHIP:
-		case IP_DROP_SOURCE_MEMBERSHIP:
-		{
-			struct ip_mreq_source mreqs;
-			int omode, add;
-
-			if (optlen != sizeof(struct ip_mreq_source))
-				goto e_inval;
-			if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {
-				err = -EFAULT;
-				break;
-			}
-			if (optname == IP_BLOCK_SOURCE) {
-				omode = MCAST_EXCLUDE;
-				add = 1;
-			} else if (optname == IP_UNBLOCK_SOURCE) {
-				omode = MCAST_EXCLUDE;
-				add = 0;
-			} else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {
-				struct ip_mreqn mreq;
-
-				mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
-				mreq.imr_address.s_addr = mreqs.imr_interface;
-				mreq.imr_ifindex = 0;
-				err = ip_mc_join_group(sk, &mreq);
-				if (err && err != -EADDRINUSE)
-					break;
-				omode = MCAST_INCLUDE;
-				add = 1;
-			} else /* IP_DROP_SOURCE_MEMBERSHIP */ {
-				omode = MCAST_INCLUDE;
-				add = 0;
-			}
-			err = ip_mc_source(add, omode, sk, &mreqs, 0);
+		if (greqs.gsr_group.ss_family != AF_INET ||
+		    greqs.gsr_source.ss_family != AF_INET) {
+			err = -EADDRNOTAVAIL;
 			break;
 		}
-		case MCAST_JOIN_GROUP:
-		case MCAST_LEAVE_GROUP:
-		{
-			struct group_req greq;
-			struct sockaddr_in *psin;
+		psin = (struct sockaddr_in *)&greqs.gsr_group;
+		mreqs.imr_multiaddr = psin->sin_addr.s_addr;
+		psin = (struct sockaddr_in *)&greqs.gsr_source;
+		mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
+		mreqs.imr_interface = 0; /* use index for mc_source */
+
+		if (optname == MCAST_BLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 1;
+		} else if (optname == MCAST_UNBLOCK_SOURCE) {
+			omode = MCAST_EXCLUDE;
+			add = 0;
+		} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
 			struct ip_mreqn mreq;
 
-			if (optlen < sizeof(struct group_req))
-				goto e_inval;
-			err = -EFAULT;
-			if(copy_from_user(&greq, optval, sizeof(greq)))
-				break;
-			psin = (struct sockaddr_in *)&greq.gr_group;
-			if (psin->sin_family != AF_INET)
-				goto e_inval;
-			memset(&mreq, 0, sizeof(mreq));
+			psin = (struct sockaddr_in *)&greqs.gsr_group;
 			mreq.imr_multiaddr = psin->sin_addr;
-			mreq.imr_ifindex = greq.gr_interface;
-
-			if (optname == MCAST_JOIN_GROUP)
-				err = ip_mc_join_group(sk, &mreq);
-			else
-				err = ip_mc_leave_group(sk, &mreq);
+			mreq.imr_address.s_addr = 0;
+			mreq.imr_ifindex = greqs.gsr_interface;
+			err = ip_mc_join_group(sk, &mreq);
+			if (err && err != -EADDRINUSE)
+				break;
+			greqs.gsr_interface = mreq.imr_ifindex;
+			omode = MCAST_INCLUDE;
+			add = 1;
+		} else /* MCAST_LEAVE_SOURCE_GROUP */ {
+			omode = MCAST_INCLUDE;
+			add = 0;
+		}
+		err = ip_mc_source(add, omode, sk, &mreqs,
+				   greqs.gsr_interface);
+		break;
+	}
+	case MCAST_MSFILTER:
+	{
+		extern int sysctl_igmp_max_msf;
+		struct sockaddr_in *psin;
+		struct ip_msfilter *msf = NULL;
+		struct group_filter *gsf = NULL;
+		int msize, i, ifindex;
+
+		if (optlen < GROUP_FILTER_SIZE(0))
+			goto e_inval;
+		if (optlen > sysctl_optmem_max) {
+			err = -ENOBUFS;
 			break;
 		}
-		case MCAST_JOIN_SOURCE_GROUP:
-		case MCAST_LEAVE_SOURCE_GROUP:
-		case MCAST_BLOCK_SOURCE:
-		case MCAST_UNBLOCK_SOURCE:
-		{
-			struct group_source_req greqs;
-			struct ip_mreq_source mreqs;
-			struct sockaddr_in *psin;
-			int omode, add;
-
-			if (optlen != sizeof(struct group_source_req))
-				goto e_inval;
-			if (copy_from_user(&greqs, optval, sizeof(greqs))) {
-				err = -EFAULT;
-				break;
-			}
-			if (greqs.gsr_group.ss_family != AF_INET ||
-			    greqs.gsr_source.ss_family != AF_INET) {
-				err = -EADDRNOTAVAIL;
-				break;
-			}
-			psin = (struct sockaddr_in *)&greqs.gsr_group;
-			mreqs.imr_multiaddr = psin->sin_addr.s_addr;
-			psin = (struct sockaddr_in *)&greqs.gsr_source;
-			mreqs.imr_sourceaddr = psin->sin_addr.s_addr;
-			mreqs.imr_interface = 0; /* use index for mc_source */
-
-			if (optname == MCAST_BLOCK_SOURCE) {
-				omode = MCAST_EXCLUDE;
-				add = 1;
-			} else if (optname == MCAST_UNBLOCK_SOURCE) {
-				omode = MCAST_EXCLUDE;
-				add = 0;
-			} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
-				struct ip_mreqn mreq;
-
-				psin = (struct sockaddr_in *)&greqs.gsr_group;
-				mreq.imr_multiaddr = psin->sin_addr;
-				mreq.imr_address.s_addr = 0;
-				mreq.imr_ifindex = greqs.gsr_interface;
-				err = ip_mc_join_group(sk, &mreq);
-				if (err && err != -EADDRINUSE)
-					break;
-				greqs.gsr_interface = mreq.imr_ifindex;
-				omode = MCAST_INCLUDE;
-				add = 1;
-			} else /* MCAST_LEAVE_SOURCE_GROUP */ {
-				omode = MCAST_INCLUDE;
-				add = 0;
-			}
-			err = ip_mc_source(add, omode, sk, &mreqs,
-				greqs.gsr_interface);
+		gsf = kmalloc(optlen,GFP_KERNEL);
+		if (gsf == 0) {
+			err = -ENOBUFS;
 			break;
 		}
-		case MCAST_MSFILTER:
-		{
-			extern int sysctl_igmp_max_msf;
-			struct sockaddr_in *psin;
-			struct ip_msfilter *msf = NULL;
-			struct group_filter *gsf = NULL;
-			int msize, i, ifindex;
-
-			if (optlen < GROUP_FILTER_SIZE(0))
-				goto e_inval;
-			if (optlen > sysctl_optmem_max) {
-				err = -ENOBUFS;
-				break;
-			}
-			gsf = kmalloc(optlen,GFP_KERNEL);
-			if (gsf == 0) {
-				err = -ENOBUFS;
-				break;
-			}
-			err = -EFAULT;
-			if (copy_from_user(gsf, optval, optlen)) {
-				goto mc_msf_out;
-			}
-			/* numsrc >= (4G-140)/128 overflow in 32 bits */
-			if (gsf->gf_numsrc >= 0x1ffffff ||
-			    gsf->gf_numsrc > sysctl_igmp_max_msf) {
-				err = -ENOBUFS;
-				goto mc_msf_out;
-			}
-			if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
-				err = -EINVAL;
-				goto mc_msf_out;
-			}
-			msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
-			msf = kmalloc(msize,GFP_KERNEL);
-			if (msf == 0) {
-				err = -ENOBUFS;
-				goto mc_msf_out;
-			}
-			ifindex = gsf->gf_interface;
-			psin = (struct sockaddr_in *)&gsf->gf_group;
-			if (psin->sin_family != AF_INET) {
-				err = -EADDRNOTAVAIL;
-				goto mc_msf_out;
-			}
-			msf->imsf_multiaddr = psin->sin_addr.s_addr;
-			msf->imsf_interface = 0;
-			msf->imsf_fmode = gsf->gf_fmode;
-			msf->imsf_numsrc = gsf->gf_numsrc;
+		err = -EFAULT;
+		if (copy_from_user(gsf, optval, optlen)) {
+			goto mc_msf_out;
+		}
+		/* numsrc >= (4G-140)/128 overflow in 32 bits */
+		if (gsf->gf_numsrc >= 0x1ffffff ||
+		    gsf->gf_numsrc > sysctl_igmp_max_msf) {
+			err = -ENOBUFS;
+			goto mc_msf_out;
+		}
+		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
+			err = -EINVAL;
+			goto mc_msf_out;
+		}
+		msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
+		msf = kmalloc(msize,GFP_KERNEL);
+		if (msf == 0) {
+			err = -ENOBUFS;
+			goto mc_msf_out;
+		}
+		ifindex = gsf->gf_interface;
+		psin = (struct sockaddr_in *)&gsf->gf_group;
+		if (psin->sin_family != AF_INET) {
 			err = -EADDRNOTAVAIL;
-			for (i=0; i<gsf->gf_numsrc; ++i) {
-				psin = (struct sockaddr_in *)&gsf->gf_slist[i];
-
-				if (psin->sin_family != AF_INET)
-					goto mc_msf_out;
-				msf->imsf_slist[i] = psin->sin_addr.s_addr;
-			}
-			kfree(gsf);
-			gsf = NULL;
-
-			err = ip_mc_msfilter(sk, msf, ifindex);
-mc_msf_out:
-			kfree(msf);
-			kfree(gsf);
-			break;
+			goto mc_msf_out;
 		}
-		case IP_ROUTER_ALERT:
-			err = ip_ra_control(sk, val ? 1 : 0, NULL);
-			break;
-
-		case IP_FREEBIND:
-			if (optlen<1)
-				goto e_inval;
-			inet->freebind = !!val;
-			break;
+		msf->imsf_multiaddr = psin->sin_addr.s_addr;
+		msf->imsf_interface = 0;
+		msf->imsf_fmode = gsf->gf_fmode;
+		msf->imsf_numsrc = gsf->gf_numsrc;
+		err = -EADDRNOTAVAIL;
+		for (i=0; i<gsf->gf_numsrc; ++i) {
+			psin = (struct sockaddr_in *)&gsf->gf_slist[i];
 
-		case IP_IPSEC_POLICY:
-		case IP_XFRM_POLICY:
-			err = -EPERM;
-			if (!capable(CAP_NET_ADMIN))
-				break;
-			err = xfrm_user_policy(sk, optname, optval, optlen);
+			if (psin->sin_family != AF_INET)
+				goto mc_msf_out;
+			msf->imsf_slist[i] = psin->sin_addr.s_addr;
+		}
+		kfree(gsf);
+		gsf = NULL;
+
+		err = ip_mc_msfilter(sk, msf, ifindex);
+	mc_msf_out:
+		kfree(msf);
+		kfree(gsf);
+		break;
+	}
+	case IP_ROUTER_ALERT:
+		err = ip_ra_control(sk, val ? 1 : 0, NULL);
+		break;
+
+	case IP_FREEBIND:
+		if (optlen<1)
+			goto e_inval;
+		inet->freebind = !!val;
+		break;
+
+	case IP_IPSEC_POLICY:
+	case IP_XFRM_POLICY:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
 			break;
+		err = xfrm_user_policy(sk, optname, optval, optlen);
+		break;
 
-		default:
-			err = -ENOPROTOOPT;
-			break;
+	default:
+		err = -ENOPROTOOPT;
+		break;
 	}
 	release_sock(sk);
 	return err;
@@ -948,214 +954,213 @@ #endif
  */
 
 static int do_ip_getsockopt(struct sock *sk, int level, int optname,
-		char __user *optval, int __user *optlen)
+			    char __user *optval, int __user *optlen)
 {
 	struct inet_sock *inet = inet_sk(sk);
 	int val;
 	int len;
 
-	if(level!=SOL_IP)
+	if (level != SOL_IP)
 		return -EOPNOTSUPP;
 
 #ifdef CONFIG_IP_MROUTE
-	if(optname>=MRT_BASE && optname <=MRT_BASE+10)
-	{
+	if (optname >= MRT_BASE && optname <= MRT_BASE+10) {
 		return ip_mroute_getsockopt(sk,optname,optval,optlen);
 	}
 #endif
 
-	if(get_user(len,optlen))
+	if (get_user(len,optlen))
 		return -EFAULT;
-	if(len < 0)
+	if (len < 0)
 		return -EINVAL;
 
 	lock_sock(sk);
 
-	switch(optname)	{
-		case IP_OPTIONS:
-			{
-				unsigned char optbuf[sizeof(struct ip_options)+40];
-				struct ip_options * opt = (struct ip_options*)optbuf;
-				opt->optlen = 0;
-				if (inet->opt)
-					memcpy(optbuf, inet->opt,
-					       sizeof(struct ip_options)+
-					       inet->opt->optlen);
-				release_sock(sk);
-
-				if (opt->optlen == 0)
-					return put_user(0, optlen);
-
-				ip_options_undo(opt);
-
-				len = min_t(unsigned int, len, opt->optlen);
-				if(put_user(len, optlen))
-					return -EFAULT;
-				if(copy_to_user(optval, opt->__data, len))
-					return -EFAULT;
-				return 0;
-			}
-		case IP_PKTINFO:
-			val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;
-			break;
-		case IP_RECVTTL:
-			val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;
-			break;
-		case IP_RECVTOS:
-			val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;
-			break;
-		case IP_RECVOPTS:
-			val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;
-			break;
-		case IP_RETOPTS:
-			val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
-			break;
-		case IP_PASSSEC:
-			val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
-			break;
-		case IP_TOS:
-			val = inet->tos;
-			break;
-		case IP_TTL:
-			val = (inet->uc_ttl == -1 ?
-			       sysctl_ip_default_ttl :
-			       inet->uc_ttl);
-			break;
-		case IP_HDRINCL:
-			val = inet->hdrincl;
-			break;
-		case IP_MTU_DISCOVER:
-			val = inet->pmtudisc;
-			break;
-		case IP_MTU:
-		{
-			struct dst_entry *dst;
-			val = 0;
-			dst = sk_dst_get(sk);
-			if (dst) {
-				val = dst_mtu(dst);
-				dst_release(dst);
-			}
-			if (!val) {
-				release_sock(sk);
-				return -ENOTCONN;
-			}
-			break;
+	switch (optname) {
+	case IP_OPTIONS:
+	{
+		unsigned char optbuf[sizeof(struct ip_options)+40];
+		struct ip_options * opt = (struct ip_options*)optbuf;
+		opt->optlen = 0;
+		if (inet->opt)
+			memcpy(optbuf, inet->opt,
+			       sizeof(struct ip_options)+
+			       inet->opt->optlen);
+		release_sock(sk);
+
+		if (opt->optlen == 0)
+			return put_user(0, optlen);
+
+		ip_options_undo(opt);
+
+		len = min_t(unsigned int, len, opt->optlen);
+		if (put_user(len, optlen))
+			return -EFAULT;
+		if (copy_to_user(optval, opt->__data, len))
+			return -EFAULT;
+		return 0;
+	}
+	case IP_PKTINFO:
+		val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;
+		break;
+	case IP_RECVTTL:
+		val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;
+		break;
+	case IP_RECVTOS:
+		val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;
+		break;
+	case IP_RECVOPTS:
+		val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;
+		break;
+	case IP_RETOPTS:
+		val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
+		break;
+	case IP_PASSSEC:
+		val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
+		break;
+	case IP_TOS:
+		val = inet->tos;
+		break;
+	case IP_TTL:
+		val = (inet->uc_ttl == -1 ?
+		       sysctl_ip_default_ttl :
+		       inet->uc_ttl);
+		break;
+	case IP_HDRINCL:
+		val = inet->hdrincl;
+		break;
+	case IP_MTU_DISCOVER:
+		val = inet->pmtudisc;
+		break;
+	case IP_MTU:
+	{
+		struct dst_entry *dst;
+		val = 0;
+		dst = sk_dst_get(sk);
+		if (dst) {
+			val = dst_mtu(dst);
+			dst_release(dst);
 		}
-		case IP_RECVERR:
-			val = inet->recverr;
-			break;
-		case IP_MULTICAST_TTL:
-			val = inet->mc_ttl;
-			break;
-		case IP_MULTICAST_LOOP:
-			val = inet->mc_loop;
-			break;
-		case IP_MULTICAST_IF:
-		{
-			struct in_addr addr;
-			len = min_t(unsigned int, len, sizeof(struct in_addr));
-			addr.s_addr = inet->mc_addr;
+		if (!val) {
 			release_sock(sk);
-
-			if(put_user(len, optlen))
-				return -EFAULT;
-			if(copy_to_user(optval, &addr, len))
-				return -EFAULT;
-			return 0;
+			return -ENOTCONN;
 		}
-		case IP_MSFILTER:
-		{
-			struct ip_msfilter msf;
-			int err;
+		break;
+	}
+	case IP_RECVERR:
+		val = inet->recverr;
+		break;
+	case IP_MULTICAST_TTL:
+		val = inet->mc_ttl;
+		break;
+	case IP_MULTICAST_LOOP:
+		val = inet->mc_loop;
+		break;
+	case IP_MULTICAST_IF:
+	{
+		struct in_addr addr;
+		len = min_t(unsigned int, len, sizeof(struct in_addr));
+		addr.s_addr = inet->mc_addr;
+		release_sock(sk);
 
-			if (len < IP_MSFILTER_SIZE(0)) {
-				release_sock(sk);
-				return -EINVAL;
-			}
-			if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
-				release_sock(sk);
-				return -EFAULT;
-			}
-			err = ip_mc_msfget(sk, &msf,
-				(struct ip_msfilter __user *)optval, optlen);
+		if (put_user(len, optlen))
+			return -EFAULT;
+		if (copy_to_user(optval, &addr, len))
+			return -EFAULT;
+		return 0;
+	}
+	case IP_MSFILTER:
+	{
+		struct ip_msfilter msf;
+		int err;
+
+		if (len < IP_MSFILTER_SIZE(0)) {
 			release_sock(sk);
-			return err;
+			return -EINVAL;
 		}
-		case MCAST_MSFILTER:
-		{
-			struct group_filter gsf;
-			int err;
-
-			if (len < GROUP_FILTER_SIZE(0)) {
-				release_sock(sk);
-				return -EINVAL;
-			}
-			if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
-				release_sock(sk);
-				return -EFAULT;
-			}
-			err = ip_mc_gsfget(sk, &gsf,
-				(struct group_filter __user *)optval, optlen);
+		if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
 			release_sock(sk);
-			return err;
+			return -EFAULT;
 		}
-		case IP_PKTOPTIONS:
-		{
-			struct msghdr msg;
+		err = ip_mc_msfget(sk, &msf,
+				   (struct ip_msfilter __user *)optval, optlen);
+		release_sock(sk);
+		return err;
+	}
+	case MCAST_MSFILTER:
+	{
+		struct group_filter gsf;
+		int err;
 
+		if (len < GROUP_FILTER_SIZE(0)) {
 			release_sock(sk);
+			return -EINVAL;
+		}
+		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
+			release_sock(sk);
+			return -EFAULT;
+		}
+		err = ip_mc_gsfget(sk, &gsf,
+				   (struct group_filter __user *)optval, optlen);
+		release_sock(sk);
+		return err;
+	}
+	case IP_PKTOPTIONS:
+	{
+		struct msghdr msg;
+
+		release_sock(sk);
 
-			if (sk->sk_type != SOCK_STREAM)
-				return -ENOPROTOOPT;
+		if (sk->sk_type != SOCK_STREAM)
+			return -ENOPROTOOPT;
 
-			msg.msg_control = optval;
-			msg.msg_controllen = len;
-			msg.msg_flags = 0;
+		msg.msg_control = optval;
+		msg.msg_controllen = len;
+		msg.msg_flags = 0;
 
-			if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
-				struct in_pktinfo info;
+		if (inet->cmsg_flags & IP_CMSG_PKTINFO) {
+			struct in_pktinfo info;
 
-				info.ipi_addr.s_addr = inet->rcv_saddr;
-				info.ipi_spec_dst.s_addr = inet->rcv_saddr;
-				info.ipi_ifindex = inet->mc_index;
-				put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
-			}
-			if (inet->cmsg_flags & IP_CMSG_TTL) {
-				int hlim = inet->mc_ttl;
-				put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
-			}
-			len -= msg.msg_controllen;
-			return put_user(len, optlen);
+			info.ipi_addr.s_addr = inet->rcv_saddr;
+			info.ipi_spec_dst.s_addr = inet->rcv_saddr;
+			info.ipi_ifindex = inet->mc_index;
+			put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
 		}
-		case IP_FREEBIND:
-			val = inet->freebind;
-			break;
-		default:
-			release_sock(sk);
-			return -ENOPROTOOPT;
+		if (inet->cmsg_flags & IP_CMSG_TTL) {
+			int hlim = inet->mc_ttl;
+			put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);
+		}
+		len -= msg.msg_controllen;
+		return put_user(len, optlen);
+	}
+	case IP_FREEBIND:
+		val = inet->freebind;
+		break;
+	default:
+		release_sock(sk);
+		return -ENOPROTOOPT;
 	}
 	release_sock(sk);
 
 	if (len < sizeof(int) && len > 0 && val>=0 && val<255) {
 		unsigned char ucval = (unsigned char)val;
 		len = 1;
-		if(put_user(len, optlen))
+		if (put_user(len, optlen))
 			return -EFAULT;
-		if(copy_to_user(optval,&ucval,1))
+		if (copy_to_user(optval,&ucval,1))
 			return -EFAULT;
 	} else {
 		len = min_t(unsigned int, sizeof(int), len);
-		if(put_user(len, optlen))
+		if (put_user(len, optlen))
 			return -EFAULT;
-		if(copy_to_user(optval,&val,len))
+		if (copy_to_user(optval,&val,len))
 			return -EFAULT;
 	}
 	return 0;
 }
 
 int ip_getsockopt(struct sock *sk, int level,
-		int optname, char __user *optval, int __user *optlen)
+		  int optname, char __user *optval, int __user *optlen)
 {
 	int err;
 
@@ -1169,7 +1174,7 @@ #endif
 	   ) {
 		int len;
 
-		if(get_user(len,optlen))
+		if (get_user(len,optlen))
 			return -EFAULT;
 
 		lock_sock(sk);
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index aa704b8..ab86137 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -43,21 +43,15 @@ static LIST_HEAD(ipcomp_tfms_list);
 
 static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 {
-	int err, plen, dlen;
 	struct ipcomp_data *ipcd = x->data;
-	u8 *start, *scratch;
-	struct crypto_comp *tfm;
-	int cpu;
-
-	plen = skb->len;
-	dlen = IPCOMP_SCRATCH_SIZE;
-	start = skb->data;
+	const int plen = skb->len;
+	int dlen = IPCOMP_SCRATCH_SIZE;
+	const u8 *start = skb->data;
+	const int cpu = get_cpu();
+	u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
+	struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
+	int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
 
-	cpu = get_cpu();
-	scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
-	tfm = *per_cpu_ptr(ipcd->tfms, cpu);
-
-	err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
 	if (err)
 		goto out;
 
@@ -72,7 +66,7 @@ static int ipcomp_decompress(struct xfrm
 
 	skb->truesize += dlen - plen;
 	__skb_put(skb, dlen - plen);
-	memcpy(skb->data, scratch, dlen);
+	skb_copy_to_linear_data(skb, scratch, dlen);
 out:
 	put_cpu();
 	return err;
@@ -90,10 +84,10 @@ static int ipcomp_input(struct xfrm_stat
 	skb->ip_summed = CHECKSUM_NONE;
 
 	/* Remove ipcomp header and decompress original payload */
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	ipch = (void *)skb->data;
 	iph->protocol = ipch->nexthdr;
-	skb->h.raw = skb->nh.raw + sizeof(*ipch);
+	skb->transport_header = skb->network_header + sizeof(*ipch);
 	__skb_pull(skb, sizeof(*ipch));
 	err = ipcomp_decompress(x, skb);
 
@@ -103,23 +97,16 @@ out:
 
 static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
 {
-	int err, plen, dlen, ihlen;
-	struct iphdr *iph = skb->nh.iph;
 	struct ipcomp_data *ipcd = x->data;
-	u8 *start, *scratch;
-	struct crypto_comp *tfm;
-	int cpu;
+	const int ihlen = ip_hdrlen(skb);
+	const int plen = skb->len - ihlen;
+	int dlen = IPCOMP_SCRATCH_SIZE;
+	u8 *start = skb->data + ihlen;
+	const int cpu = get_cpu();
+	u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
+	struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
+	int err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
 
-	ihlen = iph->ihl * 4;
-	plen = skb->len - ihlen;
-	dlen = IPCOMP_SCRATCH_SIZE;
-	start = skb->data + ihlen;
-
-	cpu = get_cpu();
-	scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
-	tfm = *per_cpu_ptr(ipcd->tfms, cpu);
-
-	err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
 	if (err)
 		goto out;
 
@@ -142,12 +129,11 @@ out:
 static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	struct iphdr *iph;
 	struct ip_comp_hdr *ipch;
 	struct ipcomp_data *ipcd = x->data;
 	int hdr_len = 0;
+	struct iphdr *iph = ip_hdr(skb);
 
-	iph = skb->nh.iph;
 	iph->tot_len = htons(skb->len);
 	hdr_len = iph->ihl * 4;
 	if ((skb->len - hdr_len) < ipcd->threshold) {
@@ -159,7 +145,7 @@ static int ipcomp_output(struct xfrm_sta
 		goto out_ok;
 
 	err = ipcomp_compress(x, skb);
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	if (err) {
 		goto out_ok;
@@ -188,8 +174,8 @@ static void ipcomp4_err(struct sk_buff *
 	struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
-	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
-	    skb->h.icmph->code != ICMP_FRAG_NEEDED)
+	if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH ||
+	    icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
 		return;
 
 	spi = htonl(ntohs(ipch->cpi));
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index cf49de1..342ca8d 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -192,7 +192,7 @@ static int __init ic_open_devs(void)
 	if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
 		printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name);
 
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (dev == &loopback_dev)
 			continue;
 		if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
@@ -432,7 +432,7 @@ ic_rarp_recv(struct sk_buff *skb, struct
 		goto drop;
 
 	/* Basic sanity checks can be done without the lock.  */
-	rarp = (struct arphdr *)skb->h.raw;
+	rarp = (struct arphdr *)skb_transport_header(skb);
 
 	/* If this test doesn't pass, it's not IP, or we should
 	 * ignore it anyway.
@@ -455,7 +455,7 @@ ic_rarp_recv(struct sk_buff *skb, struct
 		goto drop;
 
 	/* OK, it is all there and looks valid, process... */
-	rarp = (struct arphdr *)skb->h.raw;
+	rarp = (struct arphdr *)skb_transport_header(skb);
 	rarp_ptr = (unsigned char *) (rarp + 1);
 
 	/* One reply at a time, please. */
@@ -702,7 +702,8 @@ static void __init ic_bootp_send_if(stru
 	memset(b, 0, sizeof(struct bootp_pkt));
 
 	/* Construct IP header */
-	skb->nh.iph = h = &b->iph;
+	skb_reset_network_header(skb);
+	h = ip_hdr(skb);
 	h->version = 4;
 	h->ihl = 5;
 	h->tot_len = htons(sizeof(struct bootp_pkt));
@@ -782,7 +783,7 @@ #ifdef IPCONFIG_DEBUG
 	u8 *c;
 
 	printk("DHCP/BOOTP: Got extension %d:",*ext);
-	for(c=ext+2; c<ext+2+ext[1]; c++)
+	for (c=ext+2; c<ext+2+ext[1]; c++)
 		printk(" %02x", *c);
 	printk("\n");
 #endif
@@ -845,7 +846,7 @@ static int __init ic_bootp_recv(struct s
 			   sizeof(struct udphdr)))
 		goto drop;
 
-	b = (struct bootp_pkt *) skb->nh.iph;
+	b = (struct bootp_pkt *)skb_network_header(skb);
 	h = &b->iph;
 
 	if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP)
@@ -883,7 +884,7 @@ static int __init ic_bootp_recv(struct s
 	if (!pskb_may_pull(skb, skb->len))
 		goto drop;
 
-	b = (struct bootp_pkt *) skb->nh.iph;
+	b = (struct bootp_pkt *)skb_network_header(skb);
 	h = &b->iph;
 
 	/* One reply at a time, please. */
@@ -938,7 +939,7 @@ #ifdef IPCONFIG_DHCP
 					if (opt[1] >= 4)
 						memcpy(&server_id, opt + 2, 4);
 					break;
-				};
+				}
 			}
 
 #ifdef IPCONFIG_DEBUG
@@ -983,7 +984,7 @@ #endif
 				ic_myaddr = NONE;
 				ic_servaddr = NONE;
 				goto drop_unlock;
-			};
+			}
 
 			ic_dhcp_msgtype = mt;
 
@@ -1094,7 +1095,7 @@ #endif
 	retries = CONF_SEND_RETRIES;
 	get_random_bytes(&timeout, sizeof(timeout));
 	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
-	for(;;) {
+	for (;;) {
 #ifdef IPCONFIG_BOOTP
 		if (do_bootp && (d->able & IC_BOOTP))
 			ic_bootp_send_if(d, jiffies - start_jiffies);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 3ec5ce0..ebd2f2d 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -157,10 +157,10 @@ static struct ip_tunnel * ipip_tunnel_lo
 	return NULL;
 }
 
-static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
+static struct ip_tunnel **__ipip_bucket(struct ip_tunnel_parm *parms)
 {
-	__be32 remote = t->parms.iph.daddr;
-	__be32 local = t->parms.iph.saddr;
+	__be32 remote = parms->iph.daddr;
+	__be32 local = parms->iph.saddr;
 	unsigned h = 0;
 	int prio = 0;
 
@@ -175,6 +175,10 @@ static struct ip_tunnel **ipip_bucket(st
 	return &tunnels[prio][h];
 }
 
+static inline struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
+{
+	return __ipip_bucket(&t->parms);
+}
 
 static void ipip_tunnel_unlink(struct ip_tunnel *t)
 {
@@ -206,19 +210,9 @@ static struct ip_tunnel * ipip_tunnel_lo
 	__be32 local = parms->iph.saddr;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
-	unsigned h = 0;
-	int prio = 0;
 	char name[IFNAMSIZ];
 
-	if (remote) {
-		prio |= 2;
-		h ^= HASH(remote);
-	}
-	if (local) {
-		prio |= 1;
-		h ^= HASH(local);
-	}
-	for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
+	for (tp = __ipip_bucket(parms); (t = *tp) != NULL; tp = &t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
 			return t;
 	}
@@ -280,8 +274,8 @@ #ifndef I_WISH_WORLD_WERE_PERFECT
    ICMP in the real Internet is absolutely infeasible.
  */
 	struct iphdr *iph = (struct iphdr*)skb->data;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct ip_tunnel *t;
 	int err;
 
@@ -336,8 +330,8 @@ #else
 	struct iphdr *iph = (struct iphdr*)dp;
 	int hlen = iph->ihl<<2;
 	struct iphdr *eiph;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	int rel_type = 0;
 	int rel_code = 0;
 	__be32 rel_info = 0;
@@ -354,7 +348,7 @@ #else
 	default:
 		return 0;
 	case ICMP_PARAMETERPROB:
-		n = ntohl(skb->h.icmph->un.gateway) >> 24;
+		n = ntohl(icmp_hdr(skb)->un.gateway) >> 24;
 		if (n < hlen)
 			return 0;
 
@@ -373,7 +367,7 @@ #else
 			return 0;
 		case ICMP_FRAG_NEEDED:
 			/* And it is the only really necessary thing :-) */
-			n = ntohs(skb->h.icmph->un.frag.mtu);
+			n = ntohs(icmp_hdr(skb)->un.frag.mtu);
 			if (n < hlen+68)
 				return 0;
 			n -= hlen;
@@ -405,7 +399,7 @@ #else
 	dst_release(skb2->dst);
 	skb2->dst = NULL;
 	skb_pull(skb2, skb->data - (u8*)eiph);
-	skb2->nh.raw = skb2->data;
+	skb_reset_network_header(skb2);
 
 	/* Try to guess incoming interface */
 	memset(&fl, 0, sizeof(fl));
@@ -461,9 +455,10 @@ #else
 #endif
 }
 
-static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
+static inline void ipip_ecn_decapsulate(const struct iphdr *outer_iph,
+					struct sk_buff *skb)
 {
-	struct iphdr *inner_iph = skb->nh.iph;
+	struct iphdr *inner_iph = ip_hdr(skb);
 
 	if (INET_ECN_is_ce(outer_iph->tos))
 		IP_ECN_set_ce(inner_iph);
@@ -471,10 +466,8 @@ static inline void ipip_ecn_decapsulate(
 
 static int ipip_rcv(struct sk_buff *skb)
 {
-	struct iphdr *iph;
 	struct ip_tunnel *tunnel;
-
-	iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 
 	read_lock(&ipip_lock);
 	if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
@@ -486,8 +479,8 @@ static int ipip_rcv(struct sk_buff *skb)
 
 		secpath_reset(skb);
 
-		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = skb->data;
+		skb->mac_header = skb->network_header;
+		skb_reset_network_header(skb);
 		skb->protocol = htons(ETH_P_IP);
 		skb->pkt_type = PACKET_HOST;
 
@@ -521,7 +514,7 @@ static int ipip_tunnel_xmit(struct sk_bu
 	__be16 df = tiph->frag_off;
 	struct rtable *rt;     			/* Route to the other host */
 	struct net_device *tdev;			/* Device to other host */
-	struct iphdr  *old_iph = skb->nh.iph;
+	struct iphdr  *old_iph = ip_hdr(skb);
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
 	__be32 dst = tiph->daddr;
@@ -615,11 +608,12 @@ static int ipip_tunnel_xmit(struct sk_bu
 			skb_set_owner_w(new_skb, skb->sk);
 		dev_kfree_skb(skb);
 		skb = new_skb;
-		old_iph = skb->nh.iph;
+		old_iph = ip_hdr(skb);
 	}
 
-	skb->h.raw = skb->nh.raw;
-	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+	skb->transport_header = skb->network_header;
+	skb_push(skb, sizeof(struct iphdr));
+	skb_reset_network_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
@@ -630,7 +624,7 @@ static int ipip_tunnel_xmit(struct sk_bu
 	 *	Push down and install the IPIP header.
 	 */
 
-	iph 			=	skb->nh.iph;
+	iph 			=	ip_hdr(skb);
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr)>>2;
 	iph->frag_off		=	df;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 601e3df..0ebae41 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -62,6 +62,7 @@ #include <linux/if_arp.h>
 #include <linux/netfilter_ipv4.h>
 #include <net/ipip.h>
 #include <net/checksum.h>
+#include <net/netlink.h>
 
 #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
 #define CONFIG_IP_PIMSM	1
@@ -302,8 +303,8 @@ static void ipmr_destroy_unres(struct mf
 
 	atomic_dec(&cache_resolve_queue_len);
 
-	while((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
-		if (skb->nh.iph->version == 0) {
+	while ((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) {
+		if (ip_hdr(skb)->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 			nlh->nlmsg_type = NLMSG_ERROR;
 			nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
@@ -479,7 +480,7 @@ static struct mfc_cache *ipmr_cache_find
 static struct mfc_cache *ipmr_cache_alloc(void)
 {
 	struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
-	if(c==NULL)
+	if (c==NULL)
 		return NULL;
 	c->mfc_un.res.minvif = MAXVIFS;
 	return c;
@@ -488,7 +489,7 @@ static struct mfc_cache *ipmr_cache_allo
 static struct mfc_cache *ipmr_cache_alloc_unres(void)
 {
 	struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
-	if(c==NULL)
+	if (c==NULL)
 		return NULL;
 	skb_queue_head_init(&c->mfc_un.unres.unresolved);
 	c->mfc_un.unres.expires = jiffies + 10*HZ;
@@ -508,12 +509,13 @@ static void ipmr_cache_resolve(struct mf
 	 *	Play the pending entries through our router
 	 */
 
-	while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
-		if (skb->nh.iph->version == 0) {
+	while ((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+		if (ip_hdr(skb)->version == 0) {
 			struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 
 			if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
-				nlh->nlmsg_len = skb->tail - (u8*)nlh;
+				nlh->nlmsg_len = (skb_tail_pointer(skb) -
+						  (u8 *)nlh);
 			} else {
 				nlh->nlmsg_type = NLMSG_ERROR;
 				nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
@@ -539,7 +541,7 @@ static void ipmr_cache_resolve(struct mf
 static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
 {
 	struct sk_buff *skb;
-	int ihl = pkt->nh.iph->ihl<<2;
+	const int ihl = ip_hdrlen(pkt);
 	struct igmphdr *igmp;
 	struct igmpmsg *msg;
 	int ret;
@@ -551,7 +553,7 @@ #ifdef CONFIG_IP_PIMSM
 #endif
 		skb = alloc_skb(128, GFP_ATOMIC);
 
-	if(!skb)
+	if (!skb)
 		return -ENOBUFS;
 
 #ifdef CONFIG_IP_PIMSM
@@ -561,14 +563,17 @@ #ifdef CONFIG_IP_PIMSM
 		   And all this only to mangle msg->im_msgtype and
 		   to set msg->im_mbz to "mbz" :-)
 		 */
-		msg = (struct igmpmsg*)skb_push(skb, sizeof(struct iphdr));
-		skb->nh.raw = skb->h.raw = (u8*)msg;
-		memcpy(msg, pkt->nh.raw, sizeof(struct iphdr));
+		skb_push(skb, sizeof(struct iphdr));
+		skb_reset_network_header(skb);
+		skb_reset_transport_header(skb);
+		msg = (struct igmpmsg *)skb_network_header(skb);
+		memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
 		msg->im_msgtype = IGMPMSG_WHOLEPKT;
 		msg->im_mbz = 0;
 		msg->im_vif = reg_vif_num;
-		skb->nh.iph->ihl = sizeof(struct iphdr) >> 2;
-		skb->nh.iph->tot_len = htons(ntohs(pkt->nh.iph->tot_len) + sizeof(struct iphdr));
+		ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
+		ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
+					     sizeof(struct iphdr));
 	} else
 #endif
 	{
@@ -577,10 +582,11 @@ #endif
 	 *	Copy the IP header
 	 */
 
-	skb->nh.iph = (struct iphdr *)skb_put(skb, ihl);
-	memcpy(skb->data,pkt->data,ihl);
-	skb->nh.iph->protocol = 0;			/* Flag to the kernel this is a route add */
-	msg = (struct igmpmsg*)skb->nh.iph;
+	skb->network_header = skb->tail;
+	skb_put(skb, ihl);
+	skb_copy_to_linear_data(skb, pkt->data, ihl);
+	ip_hdr(skb)->protocol = 0;			/* Flag to the kernel this is a route add */
+	msg = (struct igmpmsg *)skb_network_header(skb);
 	msg->im_vif = vifi;
 	skb->dst = dst_clone(pkt->dst);
 
@@ -592,8 +598,8 @@ #endif
 	igmp->type	=
 	msg->im_msgtype = assert;
 	igmp->code 	=	0;
-	skb->nh.iph->tot_len=htons(skb->len);			/* Fix the length */
-	skb->h.raw = skb->nh.raw;
+	ip_hdr(skb)->tot_len = htons(skb->len);			/* Fix the length */
+	skb->transport_header = skb->network_header;
 	}
 
 	if (mroute_socket == NULL) {
@@ -622,11 +628,12 @@ ipmr_cache_unresolved(vifi_t vifi, struc
 {
 	int err;
 	struct mfc_cache *c;
+	const struct iphdr *iph = ip_hdr(skb);
 
 	spin_lock_bh(&mfc_unres_lock);
 	for (c=mfc_unres_queue; c; c=c->next) {
-		if (c->mfc_mcastgrp == skb->nh.iph->daddr &&
-		    c->mfc_origin == skb->nh.iph->saddr)
+		if (c->mfc_mcastgrp == iph->daddr &&
+		    c->mfc_origin == iph->saddr)
 			break;
 	}
 
@@ -646,9 +653,9 @@ ipmr_cache_unresolved(vifi_t vifi, struc
 		/*
 		 *	Fill in the new cache entry
 		 */
-		c->mfc_parent=-1;
-		c->mfc_origin=skb->nh.iph->saddr;
-		c->mfc_mcastgrp=skb->nh.iph->daddr;
+		c->mfc_parent	= -1;
+		c->mfc_origin	= iph->saddr;
+		c->mfc_mcastgrp	= iph->daddr;
 
 		/*
 		 *	Reflect first query at mrouted.
@@ -734,7 +741,7 @@ static int ipmr_mfc_add(struct mfcctl *m
 		return 0;
 	}
 
-	if(!MULTICAST(mfc->mfcc_mcastgrp.s_addr))
+	if (!MULTICAST(mfc->mfcc_mcastgrp.s_addr))
 		return -EINVAL;
 
 	c=ipmr_cache_alloc();
@@ -788,7 +795,7 @@ static void mroute_clean_tables(struct s
 	/*
 	 *	Shut down all active vif entries
 	 */
-	for(i=0; i<maxvif; i++) {
+	for (i=0; i<maxvif; i++) {
 		if (!(vif_table[i].flags&VIFF_STATIC))
 			vif_delete(i);
 	}
@@ -858,119 +865,117 @@ int ip_mroute_setsockopt(struct sock *sk
 	struct vifctl vif;
 	struct mfcctl mfc;
 
-	if(optname!=MRT_INIT)
-	{
-		if(sk!=mroute_socket && !capable(CAP_NET_ADMIN))
+	if (optname != MRT_INIT) {
+		if (sk != mroute_socket && !capable(CAP_NET_ADMIN))
 			return -EACCES;
 	}
 
-	switch(optname)
-	{
-		case MRT_INIT:
-			if (sk->sk_type != SOCK_RAW ||
-			    inet_sk(sk)->num != IPPROTO_IGMP)
-				return -EOPNOTSUPP;
-			if(optlen!=sizeof(int))
-				return -ENOPROTOOPT;
-
-			rtnl_lock();
-			if (mroute_socket) {
-				rtnl_unlock();
-				return -EADDRINUSE;
-			}
-
-			ret = ip_ra_control(sk, 1, mrtsock_destruct);
-			if (ret == 0) {
-				write_lock_bh(&mrt_lock);
-				mroute_socket=sk;
-				write_unlock_bh(&mrt_lock);
+	switch (optname) {
+	case MRT_INIT:
+		if (sk->sk_type != SOCK_RAW ||
+		    inet_sk(sk)->num != IPPROTO_IGMP)
+			return -EOPNOTSUPP;
+		if (optlen!=sizeof(int))
+			return -ENOPROTOOPT;
 
-				ipv4_devconf.mc_forwarding++;
-			}
+		rtnl_lock();
+		if (mroute_socket) {
 			rtnl_unlock();
-			return ret;
-		case MRT_DONE:
-			if (sk!=mroute_socket)
-				return -EACCES;
-			return ip_ra_control(sk, 0, NULL);
-		case MRT_ADD_VIF:
-		case MRT_DEL_VIF:
-			if(optlen!=sizeof(vif))
-				return -EINVAL;
-			if (copy_from_user(&vif,optval,sizeof(vif)))
-				return -EFAULT;
-			if(vif.vifc_vifi >= MAXVIFS)
-				return -ENFILE;
-			rtnl_lock();
-			if (optname==MRT_ADD_VIF) {
-				ret = vif_add(&vif, sk==mroute_socket);
-			} else {
-				ret = vif_delete(vif.vifc_vifi);
-			}
-			rtnl_unlock();
-			return ret;
+			return -EADDRINUSE;
+		}
+
+		ret = ip_ra_control(sk, 1, mrtsock_destruct);
+		if (ret == 0) {
+			write_lock_bh(&mrt_lock);
+			mroute_socket=sk;
+			write_unlock_bh(&mrt_lock);
+
+			ipv4_devconf.mc_forwarding++;
+		}
+		rtnl_unlock();
+		return ret;
+	case MRT_DONE:
+		if (sk!=mroute_socket)
+			return -EACCES;
+		return ip_ra_control(sk, 0, NULL);
+	case MRT_ADD_VIF:
+	case MRT_DEL_VIF:
+		if (optlen!=sizeof(vif))
+			return -EINVAL;
+		if (copy_from_user(&vif,optval,sizeof(vif)))
+			return -EFAULT;
+		if (vif.vifc_vifi >= MAXVIFS)
+			return -ENFILE;
+		rtnl_lock();
+		if (optname==MRT_ADD_VIF) {
+			ret = vif_add(&vif, sk==mroute_socket);
+		} else {
+			ret = vif_delete(vif.vifc_vifi);
+		}
+		rtnl_unlock();
+		return ret;
 
 		/*
 		 *	Manipulate the forwarding caches. These live
 		 *	in a sort of kernel/user symbiosis.
 		 */
-		case MRT_ADD_MFC:
-		case MRT_DEL_MFC:
-			if(optlen!=sizeof(mfc))
-				return -EINVAL;
-			if (copy_from_user(&mfc,optval, sizeof(mfc)))
-				return -EFAULT;
-			rtnl_lock();
-			if (optname==MRT_DEL_MFC)
-				ret = ipmr_mfc_delete(&mfc);
-			else
-				ret = ipmr_mfc_add(&mfc, sk==mroute_socket);
-			rtnl_unlock();
-			return ret;
+	case MRT_ADD_MFC:
+	case MRT_DEL_MFC:
+		if (optlen!=sizeof(mfc))
+			return -EINVAL;
+		if (copy_from_user(&mfc,optval, sizeof(mfc)))
+			return -EFAULT;
+		rtnl_lock();
+		if (optname==MRT_DEL_MFC)
+			ret = ipmr_mfc_delete(&mfc);
+		else
+			ret = ipmr_mfc_add(&mfc, sk==mroute_socket);
+		rtnl_unlock();
+		return ret;
 		/*
 		 *	Control PIM assert.
 		 */
-		case MRT_ASSERT:
-		{
-			int v;
-			if(get_user(v,(int __user *)optval))
-				return -EFAULT;
-			mroute_do_assert=(v)?1:0;
-			return 0;
-		}
+	case MRT_ASSERT:
+	{
+		int v;
+		if (get_user(v,(int __user *)optval))
+			return -EFAULT;
+		mroute_do_assert=(v)?1:0;
+		return 0;
+	}
 #ifdef CONFIG_IP_PIMSM
-		case MRT_PIM:
-		{
-			int v, ret;
-			if(get_user(v,(int __user *)optval))
-				return -EFAULT;
-			v = (v)?1:0;
-			rtnl_lock();
-			ret = 0;
-			if (v != mroute_do_pim) {
-				mroute_do_pim = v;
-				mroute_do_assert = v;
+	case MRT_PIM:
+	{
+		int v, ret;
+		if (get_user(v,(int __user *)optval))
+			return -EFAULT;
+		v = (v)?1:0;
+		rtnl_lock();
+		ret = 0;
+		if (v != mroute_do_pim) {
+			mroute_do_pim = v;
+			mroute_do_assert = v;
 #ifdef CONFIG_IP_PIMSM_V2
-				if (mroute_do_pim)
-					ret = inet_add_protocol(&pim_protocol,
-								IPPROTO_PIM);
-				else
-					ret = inet_del_protocol(&pim_protocol,
-								IPPROTO_PIM);
-				if (ret < 0)
-					ret = -EAGAIN;
+			if (mroute_do_pim)
+				ret = inet_add_protocol(&pim_protocol,
+							IPPROTO_PIM);
+			else
+				ret = inet_del_protocol(&pim_protocol,
+							IPPROTO_PIM);
+			if (ret < 0)
+				ret = -EAGAIN;
 #endif
-			}
-			rtnl_unlock();
-			return ret;
 		}
+		rtnl_unlock();
+		return ret;
+	}
 #endif
-		/*
-		 *	Spurious command, or MRT_VERSION which you cannot
-		 *	set.
-		 */
-		default:
-			return -ENOPROTOOPT;
+	/*
+	 *	Spurious command, or MRT_VERSION which you cannot
+	 *	set.
+	 */
+	default:
+		return -ENOPROTOOPT;
 	}
 }
 
@@ -983,7 +988,7 @@ int ip_mroute_getsockopt(struct sock *sk
 	int olr;
 	int val;
 
-	if(optname!=MRT_VERSION &&
+	if (optname!=MRT_VERSION &&
 #ifdef CONFIG_IP_PIMSM
 	   optname!=MRT_PIM &&
 #endif
@@ -997,17 +1002,17 @@ #endif
 	if (olr < 0)
 		return -EINVAL;
 
-	if(put_user(olr,optlen))
+	if (put_user(olr,optlen))
 		return -EFAULT;
-	if(optname==MRT_VERSION)
+	if (optname==MRT_VERSION)
 		val=0x0305;
 #ifdef CONFIG_IP_PIMSM
-	else if(optname==MRT_PIM)
+	else if (optname==MRT_PIM)
 		val=mroute_do_pim;
 #endif
 	else
 		val=mroute_do_assert;
-	if(copy_to_user(optval,&val,olr))
+	if (copy_to_user(optval,&val,olr))
 		return -EFAULT;
 	return 0;
 }
@@ -1023,48 +1028,47 @@ int ipmr_ioctl(struct sock *sk, int cmd,
 	struct vif_device *vif;
 	struct mfc_cache *c;
 
-	switch(cmd)
-	{
-		case SIOCGETVIFCNT:
-			if (copy_from_user(&vr,arg,sizeof(vr)))
-				return -EFAULT;
-			if(vr.vifi>=maxvif)
-				return -EINVAL;
-			read_lock(&mrt_lock);
-			vif=&vif_table[vr.vifi];
-			if(VIF_EXISTS(vr.vifi))	{
-				vr.icount=vif->pkt_in;
-				vr.ocount=vif->pkt_out;
-				vr.ibytes=vif->bytes_in;
-				vr.obytes=vif->bytes_out;
-				read_unlock(&mrt_lock);
-
-				if (copy_to_user(arg,&vr,sizeof(vr)))
-					return -EFAULT;
-				return 0;
-			}
+	switch (cmd) {
+	case SIOCGETVIFCNT:
+		if (copy_from_user(&vr,arg,sizeof(vr)))
+			return -EFAULT;
+		if (vr.vifi>=maxvif)
+			return -EINVAL;
+		read_lock(&mrt_lock);
+		vif=&vif_table[vr.vifi];
+		if (VIF_EXISTS(vr.vifi))	{
+			vr.icount=vif->pkt_in;
+			vr.ocount=vif->pkt_out;
+			vr.ibytes=vif->bytes_in;
+			vr.obytes=vif->bytes_out;
 			read_unlock(&mrt_lock);
-			return -EADDRNOTAVAIL;
-		case SIOCGETSGCNT:
-			if (copy_from_user(&sr,arg,sizeof(sr)))
-				return -EFAULT;
 
-			read_lock(&mrt_lock);
-			c = ipmr_cache_find(sr.src.s_addr, sr.grp.s_addr);
-			if (c) {
-				sr.pktcnt = c->mfc_un.res.pkt;
-				sr.bytecnt = c->mfc_un.res.bytes;
-				sr.wrong_if = c->mfc_un.res.wrong_if;
-				read_unlock(&mrt_lock);
-
-				if (copy_to_user(arg,&sr,sizeof(sr)))
-					return -EFAULT;
-				return 0;
-			}
+			if (copy_to_user(arg,&vr,sizeof(vr)))
+				return -EFAULT;
+			return 0;
+		}
+		read_unlock(&mrt_lock);
+		return -EADDRNOTAVAIL;
+	case SIOCGETSGCNT:
+		if (copy_from_user(&sr,arg,sizeof(sr)))
+			return -EFAULT;
+
+		read_lock(&mrt_lock);
+		c = ipmr_cache_find(sr.src.s_addr, sr.grp.s_addr);
+		if (c) {
+			sr.pktcnt = c->mfc_un.res.pkt;
+			sr.bytecnt = c->mfc_un.res.bytes;
+			sr.wrong_if = c->mfc_un.res.wrong_if;
 			read_unlock(&mrt_lock);
-			return -EADDRNOTAVAIL;
-		default:
-			return -ENOIOCTLCMD;
+
+			if (copy_to_user(arg,&sr,sizeof(sr)))
+				return -EFAULT;
+			return 0;
+		}
+		read_unlock(&mrt_lock);
+		return -EADDRNOTAVAIL;
+	default:
+		return -ENOIOCTLCMD;
 	}
 }
 
@@ -1076,7 +1080,7 @@ static int ipmr_device_event(struct noti
 	if (event != NETDEV_UNREGISTER)
 		return NOTIFY_DONE;
 	v=&vif_table[0];
-	for(ct=0;ct<maxvif;ct++,v++) {
+	for (ct=0;ct<maxvif;ct++,v++) {
 		if (v->dev==ptr)
 			vif_delete(ct);
 	}
@@ -1096,11 +1100,17 @@ static struct notifier_block ip_mr_notif
 
 static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
 {
-	struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
+	struct iphdr *iph;
+	struct iphdr *old_iph = ip_hdr(skb);
+
+	skb_push(skb, sizeof(struct iphdr));
+	skb->transport_header = skb->network_header;
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
 
 	iph->version	= 	4;
-	iph->tos	=	skb->nh.iph->tos;
-	iph->ttl	=	skb->nh.iph->ttl;
+	iph->tos	=	old_iph->tos;
+	iph->ttl	=	old_iph->ttl;
 	iph->frag_off	=	0;
 	iph->daddr	=	daddr;
 	iph->saddr	=	saddr;
@@ -1110,8 +1120,6 @@ static void ip_encap(struct sk_buff *skb
 	ip_select_ident(iph, skb->dst, NULL);
 	ip_send_check(iph);
 
-	skb->h.ipiph = skb->nh.iph;
-	skb->nh.iph = iph;
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	nf_reset(skb);
 }
@@ -1134,7 +1142,7 @@ static inline int ipmr_forward_finish(st
 
 static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
 {
-	struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 	struct vif_device *vif = &vif_table[vifi];
 	struct net_device *dev;
 	struct rtable *rt;
@@ -1200,8 +1208,7 @@ #endif
 
 	dst_release(skb->dst);
 	skb->dst = &rt->u.dst;
-	iph = skb->nh.iph;
-	ip_decrease_ttl(iph);
+	ip_decrease_ttl(ip_hdr(skb));
 
 	/* FIXME: forward and output firewalls used to be called here.
 	 * What do we do with netfilter? -- RR */
@@ -1301,7 +1308,7 @@ static int ip_mr_forward(struct sk_buff 
 	 *	Forward the frame
 	 */
 	for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
-		if (skb->nh.iph->ttl > cache->mfc_un.res.ttls[ct]) {
+		if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
 			if (psend != -1) {
 				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 				if (skb2)
@@ -1347,7 +1354,7 @@ int ip_mr_input(struct sk_buff *skb)
 		    if (IPCB(skb)->opt.router_alert) {
 			    if (ip_call_ra_chain(skb))
 				    return 0;
-		    } else if (skb->nh.iph->protocol == IPPROTO_IGMP){
+		    } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
 			    /* IGMPv1 (and broken IGMPv2 implementations sort of
 			       Cisco IOS <= 11.2(8)) do not put router alert
 			       option to IGMP packets destined to routable
@@ -1366,7 +1373,7 @@ int ip_mr_input(struct sk_buff *skb)
 	}
 
 	read_lock(&mrt_lock);
-	cache = ipmr_cache_find(skb->nh.iph->saddr, skb->nh.iph->daddr);
+	cache = ipmr_cache_find(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
 
 	/*
 	 *	No usable cache entry
@@ -1426,14 +1433,15 @@ int pim_rcv_v1(struct sk_buff * skb)
 	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
 		goto drop;
 
-	pim = (struct igmphdr*)skb->h.raw;
+	pim = igmp_hdr(skb);
 
 	if (!mroute_do_pim ||
 	    skb->len < sizeof(*pim) + sizeof(*encap) ||
 	    pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
 		goto drop;
 
-	encap = (struct iphdr*)(skb->h.raw + sizeof(struct igmphdr));
+	encap = (struct iphdr *)(skb_transport_header(skb) +
+				 sizeof(struct igmphdr));
 	/*
 	   Check that:
 	   a. packet is really destinted to a multicast group
@@ -1455,9 +1463,9 @@ int pim_rcv_v1(struct sk_buff * skb)
 	if (reg_dev == NULL)
 		goto drop;
 
-	skb->mac.raw = skb->nh.raw;
+	skb->mac_header = skb->network_header;
 	skb_pull(skb, (u8*)encap - skb->data);
-	skb->nh.iph = (struct iphdr *)skb->data;
+	skb_reset_network_header(skb);
 	skb->dev = reg_dev;
 	skb->protocol = htons(ETH_P_IP);
 	skb->ip_summed = 0;
@@ -1486,7 +1494,7 @@ static int pim_rcv(struct sk_buff * skb)
 	if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
 		goto drop;
 
-	pim = (struct pimreghdr*)skb->h.raw;
+	pim = (struct pimreghdr *)skb_transport_header(skb);
 	if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
 	    (pim->flags&PIM_NULL_REGISTER) ||
 	    (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
@@ -1494,7 +1502,8 @@ static int pim_rcv(struct sk_buff * skb)
 		goto drop;
 
 	/* check if the inner packet is destined to mcast group */
-	encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr));
+	encap = (struct iphdr *)(skb_transport_header(skb) +
+				 sizeof(struct pimreghdr));
 	if (!MULTICAST(encap->daddr) ||
 	    encap->tot_len == 0 ||
 	    ntohs(encap->tot_len) + sizeof(*pim) > skb->len)
@@ -1510,9 +1519,9 @@ static int pim_rcv(struct sk_buff * skb)
 	if (reg_dev == NULL)
 		goto drop;
 
-	skb->mac.raw = skb->nh.raw;
+	skb->mac_header = skb->network_header;
 	skb_pull(skb, (u8*)encap - skb->data);
-	skb->nh.iph = (struct iphdr *)skb->data;
+	skb_reset_network_header(skb);
 	skb->dev = reg_dev;
 	skb->protocol = htons(ETH_P_IP);
 	skb->ip_summed = 0;
@@ -1537,7 +1546,7 @@ ipmr_fill_mroute(struct sk_buff *skb, st
 	int ct;
 	struct rtnexthop *nhp;
 	struct net_device *dev = vif_table[c->mfc_parent].dev;
-	u8 *b = skb->tail;
+	u8 *b = skb_tail_pointer(skb);
 	struct rtattr *mp_head;
 
 	if (dev)
@@ -1557,12 +1566,12 @@ ipmr_fill_mroute(struct sk_buff *skb, st
 		}
 	}
 	mp_head->rta_type = RTA_MULTIPATH;
-	mp_head->rta_len = skb->tail - (u8*)mp_head;
+	mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
 	rtm->rtm_type = RTN_MULTICAST;
 	return 1;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -EMSGSIZE;
 }
 
@@ -1577,6 +1586,7 @@ int ipmr_get_route(struct sk_buff *skb, 
 
 	if (cache==NULL) {
 		struct sk_buff *skb2;
+		struct iphdr *iph;
 		struct net_device *dev;
 		int vif;
 
@@ -1596,11 +1606,13 @@ int ipmr_get_route(struct sk_buff *skb, 
 			return -ENOMEM;
 		}
 
-		skb2->nh.raw = skb_push(skb2, sizeof(struct iphdr));
-		skb2->nh.iph->ihl = sizeof(struct iphdr)>>2;
-		skb2->nh.iph->saddr = rt->rt_src;
-		skb2->nh.iph->daddr = rt->rt_dst;
-		skb2->nh.iph->version = 0;
+		skb_push(skb2, sizeof(struct iphdr));
+		skb_reset_network_header(skb2);
+		iph = ip_hdr(skb2);
+		iph->ihl = sizeof(struct iphdr) >> 2;
+		iph->saddr = rt->rt_src;
+		iph->daddr = rt->rt_dst;
+		iph->version = 0;
 		err = ipmr_cache_unresolved(vif, skb2);
 		read_unlock(&mrt_lock);
 		return err;
@@ -1625,7 +1637,7 @@ static struct vif_device *ipmr_vif_seq_i
 					   loff_t pos)
 {
 	for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) {
-		if(!VIF_EXISTS(iter->ct))
+		if (!VIF_EXISTS(iter->ct))
 			continue;
 		if (pos-- == 0)
 			return &vif_table[iter->ct];
@@ -1649,7 +1661,7 @@ static void *ipmr_vif_seq_next(struct se
 		return ipmr_vif_seq_idx(iter, 0);
 
 	while (++iter->ct < maxvif) {
-		if(!VIF_EXISTS(iter->ct))
+		if (!VIF_EXISTS(iter->ct))
 			continue;
 		return &vif_table[iter->ct];
 	}
@@ -1680,7 +1692,7 @@ static int ipmr_vif_seq_show(struct seq_
 	return 0;
 }
 
-static struct seq_operations ipmr_vif_seq_ops = {
+static const struct seq_operations ipmr_vif_seq_ops = {
 	.start = ipmr_vif_seq_start,
 	.next  = ipmr_vif_seq_next,
 	.stop  = ipmr_vif_seq_stop,
@@ -1732,14 +1744,14 @@ static struct mfc_cache *ipmr_mfc_seq_id
 	it->cache = mfc_cache_array;
 	read_lock(&mrt_lock);
 	for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
-		for(mfc = mfc_cache_array[it->ct]; mfc; mfc = mfc->next)
+		for (mfc = mfc_cache_array[it->ct]; mfc; mfc = mfc->next)
 			if (pos-- == 0)
 				return mfc;
 	read_unlock(&mrt_lock);
 
 	it->cache = &mfc_unres_queue;
 	spin_lock_bh(&mfc_unres_lock);
-	for(mfc = mfc_unres_queue; mfc; mfc = mfc->next)
+	for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
 		if (pos-- == 0)
 			return mfc;
 	spin_unlock_bh(&mfc_unres_lock);
@@ -1829,9 +1841,9 @@ static int ipmr_mfc_seq_show(struct seq_
 			   mfc->mfc_un.res.wrong_if);
 
 		if (it->cache != &mfc_unres_queue) {
-			for(n = mfc->mfc_un.res.minvif;
-			    n < mfc->mfc_un.res.maxvif; n++ ) {
-				if(VIF_EXISTS(n)
+			for (n = mfc->mfc_un.res.minvif;
+			     n < mfc->mfc_un.res.maxvif; n++ ) {
+				if (VIF_EXISTS(n)
 				   && mfc->mfc_un.res.ttls[n] < 255)
 				seq_printf(seq,
 					   " %2d:%-3d",
@@ -1843,7 +1855,7 @@ static int ipmr_mfc_seq_show(struct seq_
 	return 0;
 }
 
-static struct seq_operations ipmr_mfc_seq_ops = {
+static const struct seq_operations ipmr_mfc_seq_ops = {
 	.start = ipmr_mfc_seq_start,
 	.next  = ipmr_mfc_seq_next,
 	.stop  = ipmr_mfc_seq_stop,
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 22e104c..15ad5dd 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -331,14 +331,14 @@ static inline int app_tcp_pkt_out(struct
 				  struct ip_vs_app *app)
 {
 	int diff;
-	unsigned int tcp_offset = (*pskb)->nh.iph->ihl*4;
+	const unsigned int tcp_offset = ip_hdrlen(*pskb);
 	struct tcphdr *th;
 	__u32 seq;
 
 	if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th)))
 		return 0;
 
-	th = (struct tcphdr *)((*pskb)->nh.raw + tcp_offset);
+	th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset);
 
 	/*
 	 *	Remember seq number in case this pkt gets resized
@@ -406,14 +406,14 @@ static inline int app_tcp_pkt_in(struct 
 				 struct ip_vs_app *app)
 {
 	int diff;
-	unsigned int tcp_offset = (*pskb)->nh.iph->ihl*4;
+	const unsigned int tcp_offset = ip_hdrlen(*pskb);
 	struct tcphdr *th;
 	__u32 seq;
 
 	if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th)))
 		return 0;
 
-	th = (struct tcphdr *)((*pskb)->nh.raw + tcp_offset);
+	th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset);
 
 	/*
 	 *	Remember seq number in case this pkt gets resized
@@ -577,7 +577,6 @@ #endif
 int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri,
 		      char *o_buf, int o_len, char *n_buf, int n_len)
 {
-	struct iphdr *iph;
 	int diff;
 	int o_offset;
 	int o_left;
@@ -603,12 +602,11 @@ int ip_vs_skb_replace(struct sk_buff *sk
 		skb_put(skb, diff);
 		memmove(skb->data + o_offset + n_len,
 			skb->data + o_offset + o_len, o_left);
-		memcpy(skb->data + o_offset, n_buf, n_len);
+		skb_copy_to_linear_data_offset(skb, o_offset, n_buf, n_len);
 	}
 
 	/* must update the iph total length here */
-	iph = skb->nh.iph;
-	iph->tot_len = htons(skb->len);
+	ip_hdr(skb)->tot_len = htons(skb->len);
 
 	LeaveFunction(9);
 	return 0;
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 24d7b66..f005a2f 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -212,7 +212,7 @@ ip_vs_sched_persist(struct ip_vs_service
 		    __be16 ports[2])
 {
 	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	struct ip_vs_dest *dest;
 	struct ip_vs_conn *ct;
 	__be16  dport;	 /* destination port to forward */
@@ -381,7 +381,7 @@ struct ip_vs_conn *
 ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 {
 	struct ip_vs_conn *cp = NULL;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	struct ip_vs_dest *dest;
 	__be16 _ports[2], *pptr;
 
@@ -447,7 +447,7 @@ int ip_vs_leave(struct ip_vs_service *sv
 		struct ip_vs_protocol *pp)
 {
 	__be16 _ports[2], *pptr;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	pptr = skb_header_pointer(skb, iph->ihl*4,
 				  sizeof(_ports), _ports);
@@ -546,7 +546,7 @@ ip_vs_gather_frags(struct sk_buff *skb, 
 {
 	skb = ip_defrag(skb, user);
 	if (skb)
-		ip_send_check(skb->nh.iph);
+		ip_send_check(ip_hdr(skb));
 	return skb;
 }
 
@@ -557,9 +557,10 @@ ip_vs_gather_frags(struct sk_buff *skb, 
 void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		    struct ip_vs_conn *cp, int inout)
 {
-	struct iphdr *iph	 = skb->nh.iph;
+	struct iphdr *iph	 = ip_hdr(skb);
 	unsigned int icmp_offset = iph->ihl*4;
-	struct icmphdr *icmph	 = (struct icmphdr *)(skb->nh.raw + icmp_offset);
+	struct icmphdr *icmph	 = (struct icmphdr *)(skb_network_header(skb) +
+						      icmp_offset);
 	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
 
 	if (inout) {
@@ -617,14 +618,14 @@ static int ip_vs_out_icmp(struct sk_buff
 	*related = 1;
 
 	/* reassemble IP fragments */
-	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
 		if (!skb)
 			return NF_STOLEN;
 		*pskb = skb;
 	}
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	offset = ihl = iph->ihl * 4;
 	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
 	if (ic == NULL)
@@ -659,7 +660,7 @@ static int ip_vs_out_icmp(struct sk_buff
 		return NF_ACCEPT;
 
 	/* Is the embedded protocol header present? */
-	if (unlikely(cih->frag_off & __constant_htons(IP_OFFSET) &&
+	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
 		     pp->dont_defrag))
 		return NF_ACCEPT;
 
@@ -680,8 +681,7 @@ static int ip_vs_out_icmp(struct sk_buff
 	}
 
 	/* Ensure the checksum is correct */
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	    ip_vs_checksum_complete(skb, ihl)) {
+	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
 		/* Failed checksum! */
 		IP_VS_DBG(1, "Forward ICMP: failed checksum from %d.%d.%d.%d!\n",
 			  NIPQUAD(iph->saddr));
@@ -712,8 +712,7 @@ static inline int is_tcp_reset(const str
 {
 	struct tcphdr _tcph, *th;
 
-	th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
 	if (th == NULL)
 		return 0;
 	return th->rst;
@@ -740,14 +739,14 @@ ip_vs_out(unsigned int hooknum, struct s
 	if (skb->ipvs_property)
 		return NF_ACCEPT;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
 		int related, verdict = ip_vs_out_icmp(pskb, &related);
 
 		if (related)
 			return verdict;
 		skb = *pskb;
-		iph = skb->nh.iph;
+		iph = ip_hdr(skb);
 	}
 
 	pp = ip_vs_proto_get(iph->protocol);
@@ -755,12 +754,12 @@ ip_vs_out(unsigned int hooknum, struct s
 		return NF_ACCEPT;
 
 	/* reassemble IP fragments */
-	if (unlikely(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET) &&
+	if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) &&
 		     !pp->dont_defrag)) {
 		skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT);
 		if (!skb)
 			return NF_STOLEN;
-		iph = skb->nh.iph;
+		iph = ip_hdr(skb);
 		*pskb = skb;
 	}
 
@@ -810,8 +809,8 @@ ip_vs_out(unsigned int hooknum, struct s
 	if (pp->snat_handler && !pp->snat_handler(pskb, pp, cp))
 		goto drop;
 	skb = *pskb;
-	skb->nh.iph->saddr = cp->vaddr;
-	ip_send_check(skb->nh.iph);
+	ip_hdr(skb)->saddr = cp->vaddr;
+	ip_send_check(ip_hdr(skb));
 
 	/* For policy routing, packets originating from this
 	 * machine itself may be routed differently to packets
@@ -861,7 +860,7 @@ ip_vs_in_icmp(struct sk_buff **pskb, int
 	*related = 1;
 
 	/* reassemble IP fragments */
-	if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 		skb = ip_vs_gather_frags(skb,
 					 hooknum == NF_IP_LOCAL_IN ?
 					 IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD);
@@ -870,7 +869,7 @@ ip_vs_in_icmp(struct sk_buff **pskb, int
 		*pskb = skb;
 	}
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	offset = ihl = iph->ihl * 4;
 	ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
 	if (ic == NULL)
@@ -905,7 +904,7 @@ ip_vs_in_icmp(struct sk_buff **pskb, int
 		return NF_ACCEPT;
 
 	/* Is the embedded protocol header present? */
-	if (unlikely(cih->frag_off & __constant_htons(IP_OFFSET) &&
+	if (unlikely(cih->frag_off & htons(IP_OFFSET) &&
 		     pp->dont_defrag))
 		return NF_ACCEPT;
 
@@ -921,8 +920,7 @@ ip_vs_in_icmp(struct sk_buff **pskb, int
 	verdict = NF_DROP;
 
 	/* Ensure the checksum is correct */
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	    ip_vs_checksum_complete(skb, ihl)) {
+	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
 		/* Failed checksum! */
 		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %d.%d.%d.%d!\n",
 			  NIPQUAD(iph->saddr));
@@ -966,19 +964,19 @@ ip_vs_in(unsigned int hooknum, struct sk
 		     || skb->dev == &loopback_dev || skb->sk)) {
 		IP_VS_DBG(12, "packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
 			  skb->pkt_type,
-			  skb->nh.iph->protocol,
-			  NIPQUAD(skb->nh.iph->daddr));
+			  ip_hdr(skb)->protocol,
+			  NIPQUAD(ip_hdr(skb)->daddr));
 		return NF_ACCEPT;
 	}
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	if (unlikely(iph->protocol == IPPROTO_ICMP)) {
 		int related, verdict = ip_vs_in_icmp(pskb, &related, hooknum);
 
 		if (related)
 			return verdict;
 		skb = *pskb;
-		iph = skb->nh.iph;
+		iph = ip_hdr(skb);
 	}
 
 	/* Protocol supported? */
@@ -1064,7 +1062,7 @@ ip_vs_forward_icmp(unsigned int hooknum,
 {
 	int r;
 
-	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP)
+	if (ip_hdr(*pskb)->protocol != IPPROTO_ICMP)
 		return NF_ACCEPT;
 
 	return ip_vs_in_icmp(pskb, &r, hooknum);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index 502111f..dcf5d46 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -204,7 +204,7 @@ ip_vs_dh_schedule(struct ip_vs_service *
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_dh_bucket *tbl;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
 
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 847c47a..344ddbb 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -159,10 +159,10 @@ static int ip_vs_ftp_out(struct ip_vs_ap
 		return 0;
 
 	if (cp->app_data == &ip_vs_ftp_pasv) {
-		iph = (*pskb)->nh.iph;
+		iph = ip_hdr(*pskb);
 		th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 		data = (char *)th + (th->doff << 2);
-		data_limit = (*pskb)->tail;
+		data_limit = skb_tail_pointer(*pskb);
 
 		if (ip_vs_ftp_get_addrport(data, data_limit,
 					   SERVER_STRING,
@@ -262,14 +262,14 @@ static int ip_vs_ftp_in(struct ip_vs_app
 	/*
 	 * Detecting whether it is passive
 	 */
-	iph = (*pskb)->nh.iph;
+	iph = ip_hdr(*pskb);
 	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
 
 	/* Since there may be OPTIONS in the TCP packet and the HLEN is
 	   the length of the header in 32-bit multiples, it is accurate
 	   to calculate data address by th+HLEN*4 */
 	data = data_start = (char *)th + (th->doff << 2);
-	data_limit = (*pskb)->tail;
+	data_limit = skb_tail_pointer(*pskb);
 
 	while (data <= data_limit - 6) {
 		if (strnicmp(data, "PASV\r\n", 6) == 0) {
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index c801273..052f4ed 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -521,7 +521,7 @@ ip_vs_lblc_schedule(struct ip_vs_service
 	struct ip_vs_dest *dest;
 	struct ip_vs_lblc_table *tbl;
 	struct ip_vs_lblc_entry *en;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n");
 
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 23f9b9e..6225aca 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -775,7 +775,7 @@ ip_vs_lblcr_schedule(struct ip_vs_servic
 	struct ip_vs_dest *dest;
 	struct ip_vs_lblcr_table *tbl;
 	struct ip_vs_lblcr_entry *en;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n");
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index 8b0505b..a842676 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -52,15 +52,15 @@ ah_conn_in_get(const struct sk_buff *skb
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_in_get(IPPROTO_UDP,
 				       iph->saddr,
-				       __constant_htons(PORT_ISAKMP),
+				       htons(PORT_ISAKMP),
 				       iph->daddr,
-				       __constant_htons(PORT_ISAKMP));
+				       htons(PORT_ISAKMP));
 	} else {
 		cp = ip_vs_conn_in_get(IPPROTO_UDP,
 				       iph->daddr,
-				       __constant_htons(PORT_ISAKMP),
+				       htons(PORT_ISAKMP),
 				       iph->saddr,
-				       __constant_htons(PORT_ISAKMP));
+				       htons(PORT_ISAKMP));
 	}
 
 	if (!cp) {
@@ -89,15 +89,15 @@ ah_conn_out_get(const struct sk_buff *sk
 	if (likely(!inverse)) {
 		cp = ip_vs_conn_out_get(IPPROTO_UDP,
 					iph->saddr,
-					__constant_htons(PORT_ISAKMP),
+					htons(PORT_ISAKMP),
 					iph->daddr,
-					__constant_htons(PORT_ISAKMP));
+					htons(PORT_ISAKMP));
 	} else {
 		cp = ip_vs_conn_out_get(IPPROTO_UDP,
 					iph->daddr,
-					__constant_htons(PORT_ISAKMP),
+					htons(PORT_ISAKMP),
 					iph->saddr,
-					__constant_htons(PORT_ISAKMP));
+					htons(PORT_ISAKMP));
 	}
 
 	if (!cp) {
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 16a9ebe..e65577a 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -76,16 +76,15 @@ tcp_conn_schedule(struct sk_buff *skb,
 	struct ip_vs_service *svc;
 	struct tcphdr _tcph, *th;
 
-	th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-				sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
 	if (th == NULL) {
 		*verdict = NF_DROP;
 		return 0;
 	}
 
 	if (th->syn &&
-	    (svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol,
-				     skb->nh.iph->daddr, th->dest))) {
+	    (svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
+				     ip_hdr(skb)->daddr, th->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -127,7 +126,7 @@ tcp_snat_handler(struct sk_buff **pskb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct tcphdr *tcph;
-	unsigned int tcphoff = (*pskb)->nh.iph->ihl * 4;
+	const unsigned int tcphoff = ip_hdrlen(*pskb);
 
 	/* csum_check requires unshared skb */
 	if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph)))
@@ -143,7 +142,7 @@ tcp_snat_handler(struct sk_buff **pskb,
 			return 0;
 	}
 
-	tcph = (void *)(*pskb)->nh.iph + tcphoff;
+	tcph = (void *)ip_hdr(*pskb) + tcphoff;
 	tcph->source = cp->vport;
 
 	/* Adjust TCP checksums */
@@ -175,7 +174,7 @@ tcp_dnat_handler(struct sk_buff **pskb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct tcphdr *tcph;
-	unsigned int tcphoff = (*pskb)->nh.iph->ihl * 4;
+	const unsigned int tcphoff = ip_hdrlen(*pskb);
 
 	/* csum_check requires unshared skb */
 	if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph)))
@@ -194,7 +193,7 @@ tcp_dnat_handler(struct sk_buff **pskb,
 			return 0;
 	}
 
-	tcph = (void *)(*pskb)->nh.iph + tcphoff;
+	tcph = (void *)ip_hdr(*pskb) + tcphoff;
 	tcph->dest = cp->dport;
 
 	/*
@@ -224,15 +223,15 @@ tcp_dnat_handler(struct sk_buff **pskb,
 static int
 tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
-	unsigned int tcphoff = skb->nh.iph->ihl*4;
+	const unsigned int tcphoff = ip_hdrlen(skb);
 
 	switch (skb->ip_summed) {
 	case CHECKSUM_NONE:
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
 	case CHECKSUM_COMPLETE:
-		if (csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
+		if (csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
 				      skb->len - tcphoff,
-				      skb->nh.iph->protocol, skb->csum)) {
+				      ip_hdr(skb)->protocol, skb->csum)) {
 			IP_VS_DBG_RL_PKT(0, pp, skb, 0,
 					 "Failed checksum for");
 			return 0;
@@ -467,8 +466,7 @@ tcp_state_transition(struct ip_vs_conn *
 {
 	struct tcphdr _tcph, *th;
 
-	th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-				sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
 	if (th == NULL)
 		return 0;
 
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 03f0a41..8ee5fe6 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -22,7 +22,7 @@ #include <linux/netfilter_ipv4.h>
 #include <linux/udp.h>
 
 #include <net/ip_vs.h>
-
+#include <net/ip.h>
 
 static struct ip_vs_conn *
 udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
@@ -56,7 +56,7 @@ udp_conn_out_get(const struct sk_buff *s
 	struct ip_vs_conn *cp;
 	__be16 _ports[2], *pptr;
 
-	pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+	pptr = skb_header_pointer(skb, ip_hdrlen(skb),
 				  sizeof(_ports), _ports);
 	if (pptr == NULL)
 		return NULL;
@@ -82,15 +82,15 @@ udp_conn_schedule(struct sk_buff *skb, s
 	struct ip_vs_service *svc;
 	struct udphdr _udph, *uh;
 
-	uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+	uh = skb_header_pointer(skb, ip_hdrlen(skb),
 				sizeof(_udph), &_udph);
 	if (uh == NULL) {
 		*verdict = NF_DROP;
 		return 0;
 	}
 
-	if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol,
-				     skb->nh.iph->daddr, uh->dest))) {
+	if ((svc = ip_vs_service_get(skb->mark, ip_hdr(skb)->protocol,
+				     ip_hdr(skb)->daddr, uh->dest))) {
 		if (ip_vs_todrop()) {
 			/*
 			 * It seems that we are very loaded.
@@ -133,7 +133,7 @@ udp_snat_handler(struct sk_buff **pskb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct udphdr *udph;
-	unsigned int udphoff = (*pskb)->nh.iph->ihl * 4;
+	const unsigned int udphoff = ip_hdrlen(*pskb);
 
 	/* csum_check requires unshared skb */
 	if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph)))
@@ -151,7 +151,7 @@ udp_snat_handler(struct sk_buff **pskb,
 			return 0;
 	}
 
-	udph = (void *)(*pskb)->nh.iph + udphoff;
+	udph = (void *)ip_hdr(*pskb) + udphoff;
 	udph->source = cp->vport;
 
 	/*
@@ -187,7 +187,7 @@ udp_dnat_handler(struct sk_buff **pskb,
 		 struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
 {
 	struct udphdr *udph;
-	unsigned int udphoff = (*pskb)->nh.iph->ihl * 4;
+	unsigned int udphoff = ip_hdrlen(*pskb);
 
 	/* csum_check requires unshared skb */
 	if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph)))
@@ -206,7 +206,7 @@ udp_dnat_handler(struct sk_buff **pskb,
 			return 0;
 	}
 
-	udph = (void *)(*pskb)->nh.iph + udphoff;
+	udph = (void *)ip_hdr(*pskb) + udphoff;
 	udph->dest = cp->dport;
 
 	/*
@@ -239,7 +239,7 @@ static int
 udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
 {
 	struct udphdr _udph, *uh;
-	unsigned int udphoff = skb->nh.iph->ihl*4;
+	const unsigned int udphoff = ip_hdrlen(skb);
 
 	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
 	if (uh == NULL)
@@ -251,10 +251,10 @@ udp_csum_check(struct sk_buff *skb, stru
 			skb->csum = skb_checksum(skb, udphoff,
 						 skb->len - udphoff, 0);
 		case CHECKSUM_COMPLETE:
-			if (csum_tcpudp_magic(skb->nh.iph->saddr,
-					      skb->nh.iph->daddr,
+			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+					      ip_hdr(skb)->daddr,
 					      skb->len - udphoff,
-					      skb->nh.iph->protocol,
+					      ip_hdr(skb)->protocol,
 					      skb->csum)) {
 				IP_VS_DBG_RL_PKT(0, pp, skb, 0,
 						 "Failed checksum for");
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 338668f..1b25b00 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -201,7 +201,7 @@ ip_vs_sh_schedule(struct ip_vs_service *
 {
 	struct ip_vs_dest *dest;
 	struct ip_vs_sh_bucket *tbl;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
 
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index e1f77bd..900ce29 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -156,7 +156,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, s
 		  struct ip_vs_protocol *pp)
 {
 	struct rtable *rt;			/* Route to the other host */
-	struct iphdr  *iph = skb->nh.iph;
+	struct iphdr  *iph = ip_hdr(skb);
 	u8     tos = iph->tos;
 	int    mtu;
 	struct flowi fl = {
@@ -178,7 +178,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, s
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
+	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		IP_VS_DBG_RL("ip_vs_bypass_xmit(): frag needed\n");
@@ -193,7 +193,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, s
 		ip_rt_put(rt);
 		return NF_STOLEN;
 	}
-	ip_send_check(skb->nh.iph);
+	ip_send_check(ip_hdr(skb));
 
 	/* drop old route */
 	dst_release(skb->dst);
@@ -226,7 +226,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, stru
 {
 	struct rtable *rt;		/* Route to the other host */
 	int mtu;
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 
 	EnterFunction(10);
 
@@ -245,7 +245,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, stru
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
+	if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for");
@@ -266,8 +266,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, stru
 	/* mangle the packet */
 	if (pp->dnat_handler && !pp->dnat_handler(&skb, pp, cp))
 		goto tx_error;
-	skb->nh.iph->daddr = cp->daddr;
-	ip_send_check(skb->nh.iph);
+	ip_hdr(skb)->daddr = cp->daddr;
+	ip_send_check(ip_hdr(skb));
 
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
 
@@ -320,19 +320,20 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, s
 {
 	struct rtable *rt;			/* Route to the other host */
 	struct net_device *tdev;		/* Device to other host */
-	struct iphdr  *old_iph = skb->nh.iph;
+	struct iphdr  *old_iph = ip_hdr(skb);
 	u8     tos = old_iph->tos;
 	__be16 df = old_iph->frag_off;
+	sk_buff_data_t old_transport_header = skb->transport_header;
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
 	int    mtu;
 
 	EnterFunction(10);
 
-	if (skb->protocol != __constant_htons(ETH_P_IP)) {
+	if (skb->protocol != htons(ETH_P_IP)) {
 		IP_VS_DBG_RL("ip_vs_tunnel_xmit(): protocol error, "
 			     "ETH_P_IP: %d, skb protocol: %d\n",
-			     __constant_htons(ETH_P_IP), skb->protocol);
+			     htons(ETH_P_IP), skb->protocol);
 		goto tx_error;
 	}
 
@@ -350,9 +351,9 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, s
 	if (skb->dst)
 		skb->dst->ops->update_pmtu(skb->dst, mtu);
 
-	df |= (old_iph->frag_off&__constant_htons(IP_DF));
+	df |= (old_iph->frag_off & htons(IP_DF));
 
-	if ((old_iph->frag_off&__constant_htons(IP_DF))
+	if ((old_iph->frag_off & htons(IP_DF))
 	    && mtu < ntohs(old_iph->tot_len)) {
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		ip_rt_put(rt);
@@ -377,15 +378,16 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, s
 		}
 		kfree_skb(skb);
 		skb = new_skb;
-		old_iph = skb->nh.iph;
+		old_iph = ip_hdr(skb);
 	}
 
-	skb->h.raw = (void *) old_iph;
+	skb->transport_header = old_transport_header;
 
 	/* fix old IP header checksum */
 	ip_send_check(old_iph);
 
-	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+	skb_push(skb, sizeof(struct iphdr));
+	skb_reset_network_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
 	/* drop old route */
@@ -395,7 +397,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, s
 	/*
 	 *	Push down and install the IPIP header.
 	 */
-	iph			=	skb->nh.iph;
+	iph			=	ip_hdr(skb);
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr)>>2;
 	iph->frag_off		=	df;
@@ -435,7 +437,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struc
 	      struct ip_vs_protocol *pp)
 {
 	struct rtable *rt;			/* Route to the other host */
-	struct iphdr  *iph = skb->nh.iph;
+	struct iphdr  *iph = ip_hdr(skb);
 	int    mtu;
 
 	EnterFunction(10);
@@ -445,7 +447,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struc
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->u.dst);
-	if ((iph->frag_off&__constant_htons(IP_DF)) && skb->len > mtu) {
+	if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu) {
 		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
 		ip_rt_put(rt);
 		IP_VS_DBG_RL("ip_vs_dr_xmit(): frag needed\n");
@@ -460,7 +462,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struc
 		ip_rt_put(rt);
 		return NF_STOLEN;
 	}
-	ip_send_check(skb->nh.iph);
+	ip_send_check(ip_hdr(skb));
 
 	/* drop old route */
 	dst_release(skb->dst);
@@ -514,12 +516,12 @@ ip_vs_icmp_xmit(struct sk_buff *skb, str
 	 * mangle and send the packet here (only for VS/NAT)
 	 */
 
-	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(skb->nh.iph->tos))))
+	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(ip_hdr(skb)->tos))))
 		goto tx_error_icmp;
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->u.dst);
-	if ((skb->len > mtu) && (skb->nh.iph->frag_off&__constant_htons(IP_DF))) {
+	if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF))) {
 		ip_rt_put(rt);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
 		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c
index 574c735..b03c5ca 100644
--- a/net/ipv4/multipath_drr.c
+++ b/net/ipv4/multipath_drr.c
@@ -100,7 +100,7 @@ static int drr_dev_event(struct notifier
 
 		spin_unlock_bh(&state_lock);
 		break;
-	};
+	}
 
 	return NOTIFY_DONE;
 }
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 6069a11..b441929 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -10,7 +10,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, unsigned addr_type)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
+	const struct iphdr *iph = ip_hdr(*pskb);
 	struct rtable *rt;
 	struct flowi fl = {};
 	struct dst_entry *odst;
@@ -142,7 +142,7 @@ static void nf_ip_saveroute(const struct
 	struct ip_rt_info *rt_info = nf_info_reroute(info);
 
 	if (info->hook == NF_IP_LOCAL_OUT) {
-		const struct iphdr *iph = skb->nh.iph;
+		const struct iphdr *iph = ip_hdr(skb);
 
 		rt_info->tos = iph->tos;
 		rt_info->daddr = iph->daddr;
@@ -155,7 +155,7 @@ static int nf_ip_reroute(struct sk_buff 
 	const struct ip_rt_info *rt_info = nf_info_reroute(info);
 
 	if (info->hook == NF_IP_LOCAL_OUT) {
-		struct iphdr *iph = (*pskb)->nh.iph;
+		const struct iphdr *iph = ip_hdr(*pskb);
 
 		if (!(iph->tos == rt_info->tos
 		      && iph->daddr == rt_info->daddr
@@ -168,7 +168,7 @@ static int nf_ip_reroute(struct sk_buff 
 __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
 			    unsigned int dataoff, u_int8_t protocol)
 {
-	struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 	__sum16 csum = 0;
 
 	switch (skb->ip_summed) {
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 601808c..46509fa 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -30,188 +30,6 @@ config NF_CONNTRACK_PROC_COMPAT
 
 	  If unsure, say Y.
 
-# connection tracking, helpers and protocols
-config IP_NF_CT_ACCT
-	bool "Connection tracking flow accounting"
-	depends on IP_NF_CONNTRACK
-	help
-	  If this option is enabled, the connection tracking code will
-	  keep per-flow packet and byte counters.
-
-	  Those counters can be used for flow-based accounting or the
-	  `connbytes' match.
-
-	  If unsure, say `N'.
-
-config IP_NF_CONNTRACK_MARK
-	bool  'Connection mark tracking support'
-	depends on IP_NF_CONNTRACK
-	help
-	  This option enables support for connection marks, used by the
-	  `CONNMARK' target and `connmark' match. Similar to the mark value
-	  of packets, but this mark value is kept in the conntrack session
-	  instead of the individual packets.
-	
-config IP_NF_CONNTRACK_SECMARK
-	bool  'Connection tracking security mark support'
-	depends on IP_NF_CONNTRACK && NETWORK_SECMARK
-	help
-	  This option enables security markings to be applied to
-	  connections.  Typically they are copied to connections from
-	  packets using the CONNSECMARK target and copied back from
-	  connections to packets with the same target, with the packets
-	  being originally labeled via SECMARK.
-
-	  If unsure, say 'N'.
-
-config IP_NF_CONNTRACK_EVENTS
-	bool "Connection tracking events (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && IP_NF_CONNTRACK
-	help
-	  If this option is enabled, the connection tracking code will
-	  provide a notifier chain that can be used by other kernel code
-	  to get notified about changes in the connection tracking state.
-	  
-	  IF unsure, say `N'.
-
-config IP_NF_CONNTRACK_NETLINK
-	tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
-	depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK
-	depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
-	depends on IP_NF_NAT=n || IP_NF_NAT
-	help
-	  This option enables support for a netlink-based userspace interface
-
-
-config IP_NF_CT_PROTO_SCTP
-	tristate  'SCTP protocol connection tracking support (EXPERIMENTAL)'
-	depends on IP_NF_CONNTRACK && EXPERIMENTAL
-	help
-	  With this option enabled, the connection tracking code will
-	  be able to do state tracking on SCTP connections.
-
-	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
-
-config IP_NF_FTP
-	tristate "FTP protocol support"
-	depends on IP_NF_CONNTRACK
-	help
-	  Tracking FTP connections is problematic: special helpers are
-	  required for tracking them, and doing masquerading and other forms
-	  of Network Address Translation on them.
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_IRC
-	tristate "IRC protocol support"
-	depends on IP_NF_CONNTRACK
-	---help---
-	  There is a commonly-used extension to IRC called
-	  Direct Client-to-Client Protocol (DCC).  This enables users to send
-	  files to each other, and also chat to each other without the need
-	  of a server.  DCC Sending is used anywhere you send files over IRC,
-	  and DCC Chat is most commonly used by Eggdrop bots.  If you are
-	  using NAT, this extension will enable you to send files and initiate
-	  chats.  Note that you do NOT need this extension to get files or
-	  have others initiate chats, or everything else in IRC.
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_NETBIOS_NS
-	tristate "NetBIOS name service protocol support (EXPERIMENTAL)"
-	depends on IP_NF_CONNTRACK && EXPERIMENTAL
-	help
-	  NetBIOS name service requests are sent as broadcast messages from an
-	  unprivileged port and responded to with unicast messages to the
-	  same port. This make them hard to firewall properly because connection
-	  tracking doesn't deal with broadcasts. This helper tracks locally
-	  originating NetBIOS name service requests and the corresponding
-	  responses. It relies on correct IP address configuration, specifically
-	  netmask and broadcast address. When properly configured, the output
-	  of "ip address show" should look similar to this:
-
-	  $ ip -4 address show eth0
-	  4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
-	      inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0
-	  
-	  To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_TFTP
-	tristate "TFTP protocol support"
-	depends on IP_NF_CONNTRACK
-	help
-	  TFTP connection tracking helper, this is required depending
-	  on how restrictive your ruleset is.
-	  If you are using a tftp client behind -j SNAT or -j MASQUERADING
-	  you will need this.
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_AMANDA
-	tristate "Amanda backup protocol support"
-	depends on IP_NF_CONNTRACK
-	select TEXTSEARCH
-	select TEXTSEARCH_KMP
-	help
-	  If you are running the Amanda backup package <http://www.amanda.org/>
-	  on this machine or machines that will be MASQUERADED through this
-	  machine, then you may want to enable this feature.  This allows the
-	  connection tracking and natting code to allow the sub-channels that
-	  Amanda requires for communication of the backup data, messages and
-	  index.
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_PPTP
-	tristate  'PPTP protocol support'
-	depends on IP_NF_CONNTRACK
-	help
-	  This module adds support for PPTP (Point to Point Tunnelling
-	  Protocol, RFC2637) connection tracking and NAT. 
-	
-	  If you are running PPTP sessions over a stateful firewall or NAT
-	  box, you may want to enable this feature.  
-	
-	  Please note that not all PPTP modes of operation are supported yet.
-	  For more info, read top of the file
-	  net/ipv4/netfilter/ip_conntrack_pptp.c
-	
-	  If you want to compile it as a module, say M here and read
-	  Documentation/modules.txt.  If unsure, say `N'.
-
-config IP_NF_H323
-	tristate  'H.323 protocol support (EXPERIMENTAL)'
-	depends on IP_NF_CONNTRACK && EXPERIMENTAL
-	help
-	  H.323 is a VoIP signalling protocol from ITU-T. As one of the most
-	  important VoIP protocols, it is widely used by voice hardware and
-	  software including voice gateways, IP phones, Netmeeting, OpenPhone,
-	  Gnomemeeting, etc.
-
-	  With this module you can support H.323 on a connection tracking/NAT
-	  firewall.
-
-	  This module supports RAS, Fast Start, H.245 Tunnelling, Call
-	  Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat,
-	  whiteboard, file transfer, etc. For more information, please
-	  visit http://nath323.sourceforge.net/.
-
-	  If you want to compile it as a module, say 'M' here and read
-	  Documentation/modules.txt.  If unsure, say 'N'.
-
-config IP_NF_SIP
-	tristate "SIP protocol support (EXPERIMENTAL)"
-	depends on IP_NF_CONNTRACK && EXPERIMENTAL
-	help
-	  SIP is an application-layer control protocol that can establish,
-	  modify, and terminate multimedia sessions (conferences) such as
-	  Internet telephony calls. With the ip_conntrack_sip and
-	  the ip_nat_sip modules you can support the protocol on a connection
-	  tracking/NATing firewall.
-
-	  To compile it as a module, choose M here.  If unsure, say Y.
-
 config IP_NF_QUEUE
 	tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
 	help
@@ -361,17 +179,6 @@ config IP_NF_TARGET_ULOG
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-# NAT + specific targets: ip_conntrack
-config IP_NF_NAT
-	tristate "Full NAT"
-	depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
-	help
-	  The Full NAT option allows masquerading, port forwarding and other
-	  forms of full Network Address Port Translation.  It is controlled by
-	  the `nat' table in iptables: see the man page for iptables(8).
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 # NAT + specific targets: nf_conntrack
 config NF_NAT
 	tristate "Full NAT"
@@ -383,11 +190,6 @@ config NF_NAT
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_NAT_NEEDED
-	bool
-	depends on IP_NF_NAT
-	default y
-
 config NF_NAT_NEEDED
 	bool
 	depends on NF_NAT
@@ -395,7 +197,7 @@ config NF_NAT_NEEDED
 
 config IP_NF_TARGET_MASQUERADE
 	tristate "MASQUERADE target support"
-	depends on (NF_NAT || IP_NF_NAT)
+	depends on NF_NAT
 	help
 	  Masquerading is a special case of NAT: all outgoing connections are
 	  changed to seem to come from a particular interface's address, and
@@ -407,7 +209,7 @@ config IP_NF_TARGET_MASQUERADE
 
 config IP_NF_TARGET_REDIRECT
 	tristate "REDIRECT target support"
-	depends on (NF_NAT || IP_NF_NAT)
+	depends on NF_NAT
 	help
 	  REDIRECT is a special case of NAT: all incoming connections are
 	  mapped onto the incoming interface's address, causing the packets to
@@ -418,7 +220,7 @@ config IP_NF_TARGET_REDIRECT
 
 config IP_NF_TARGET_NETMAP
 	tristate "NETMAP target support"
-	depends on (NF_NAT || IP_NF_NAT)
+	depends on NF_NAT
 	help
 	  NETMAP is an implementation of static 1:1 NAT mapping of network
 	  addresses. It maps the network address part, while keeping the host
@@ -429,28 +231,13 @@ config IP_NF_TARGET_NETMAP
 
 config IP_NF_TARGET_SAME
 	tristate "SAME target support"
-	depends on (NF_NAT || IP_NF_NAT)
+	depends on NF_NAT
 	help
 	  This option adds a `SAME' target, which works like the standard SNAT
 	  target, but attempts to give clients the same IP for all connections.
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_NAT_SNMP_BASIC
-	tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && IP_NF_NAT
-	---help---
-
-	  This module implements an Application Layer Gateway (ALG) for
-	  SNMP payloads.  In conjunction with NAT, it allows a network
-	  management system to access multiple private networks with
-	  conflicting addresses.  It works by modifying IP addresses
-	  inside SNMP payloads to match IP-layer NAT mapping.
-
-	  This is the "basic" form of SNMP-ALG, as described in RFC 2962
-
-	  To compile it as a module, choose M here.  If unsure, say N.
-
 config NF_NAT_SNMP_BASIC
 	tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && NF_NAT
@@ -477,78 +264,37 @@ config NF_NAT_PROTO_GRE
 	tristate
 	depends on NF_NAT && NF_CT_PROTO_GRE
 
-config IP_NF_NAT_FTP
-	tristate
-	depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
-	default IP_NF_NAT && IP_NF_FTP
-
 config NF_NAT_FTP
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_FTP
 
-config IP_NF_NAT_IRC
-	tristate
-	depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
-	default IP_NF_NAT if IP_NF_IRC=y
-	default m if IP_NF_IRC=m
-
 config NF_NAT_IRC
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_IRC
 
-config IP_NF_NAT_TFTP
-	tristate
-	depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
-	default IP_NF_NAT if IP_NF_TFTP=y
-	default m if IP_NF_TFTP=m
-
 config NF_NAT_TFTP
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_TFTP
 
-config IP_NF_NAT_AMANDA
-	tristate
-	depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
-	default IP_NF_NAT if IP_NF_AMANDA=y
-	default m if IP_NF_AMANDA=m
-
 config NF_NAT_AMANDA
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_AMANDA
 
-config IP_NF_NAT_PPTP
-	tristate
-	depends on IP_NF_NAT!=n && IP_NF_PPTP!=n
-	default IP_NF_NAT if IP_NF_PPTP=y
-	default m if IP_NF_PPTP=m
-
 config NF_NAT_PPTP
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_PPTP
 	select NF_NAT_PROTO_GRE
 
-config IP_NF_NAT_H323
-	tristate
-	depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
-	default IP_NF_NAT if IP_NF_H323=y
-	default m if IP_NF_H323=m
-
 config NF_NAT_H323
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_H323
 
-config IP_NF_NAT_SIP
-	tristate
-	depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
-	default IP_NF_NAT if IP_NF_SIP=y
-	default m if IP_NF_SIP=m
-
 config NF_NAT_SIP
 	tristate
 	depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
@@ -606,9 +352,8 @@ config IP_NF_TARGET_TTL
 config IP_NF_TARGET_CLUSTERIP
 	tristate "CLUSTERIP target support (EXPERIMENTAL)"
 	depends on IP_NF_MANGLE && EXPERIMENTAL
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-	select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
-	select NF_CONNTRACK_MARK if NF_CONNTRACK_IPV4
+	depends on NF_CONNTRACK_IPV4
+	select NF_CONNTRACK_MARK
 	help
 	  The CLUSTERIP target allows you to build load-balancing clusters of
 	  network servers without having a dedicated load-balancing
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 6625ec6..409d273 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -2,8 +2,6 @@ #
 # Makefile for the netfilter modules on top of IPv4.
 #
 
-# objects for the standalone - connection tracking / NAT
-ip_conntrack-objs	:= ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
 # objects for l3 independent conntrack
 nf_conntrack_ipv4-objs  :=  nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
 ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y)
@@ -12,53 +10,14 @@ nf_conntrack_ipv4-objs	+= nf_conntrack_l
 endif
 endif
 
-ip_nat-objs	:= ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
-nf_nat-objs	:= nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
-ifneq ($(CONFIG_NF_NAT),)
+nf_nat-objs		:= nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
 iptable_nat-objs	:= nf_nat_rule.o nf_nat_standalone.o
-else
-iptable_nat-objs	:= ip_nat_rule.o ip_nat_standalone.o
-endif
-
-ip_conntrack_pptp-objs	:= ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
-ip_nat_pptp-objs	:= ip_nat_helper_pptp.o ip_nat_proto_gre.o
-
-ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o
-ip_nat_h323-objs := ip_nat_helper_h323.o
 
 # connection tracking
-obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
 obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
 
-obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
 obj-$(CONFIG_NF_NAT) += nf_nat.o
 
-# conntrack netlink interface
-obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
-
-
-# SCTP protocol connection tracking
-obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
-
-# connection tracking helpers
-obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
-obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
-obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
-obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
-obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
-obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
-obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
-obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
-
-# NAT helpers (ip_conntrack)
-obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
-obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
-obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
-obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
-obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
-obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
-obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
-
 # NAT helpers (nf_conntrack)
 obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
@@ -78,7 +37,6 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_table
 # the three instances of ip_tables
 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
-obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
 
@@ -100,7 +58,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) +=
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
-obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 57b0221..cae4121 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -245,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buf
 	e = get_entry(table_base, private->hook_entry[hook]);
 	back = get_entry(table_base, private->underflow[hook]);
 
-	arp = (*pskb)->nh.arph;
+	arp = arp_hdr(*pskb);
 	do {
 		if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) {
 			struct arpt_entry_target *t;
@@ -297,7 +297,7 @@ unsigned int arpt_do_table(struct sk_buf
 								     t->data);
 
 				/* Target might have changed stuff. */
-				arp = (*pskb)->nh.arph;
+				arp = arp_hdr(*pskb);
 
 				if (verdict == ARPT_CONTINUE)
 					e = (void *)e + e->next_offset;
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index 709db4d..6298d40 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -30,35 +30,35 @@ target(struct sk_buff **pskb,
 		*pskb = nskb;
 	}
 
-	arp = (*pskb)->nh.arph;
-	arpptr = (*pskb)->nh.raw + sizeof(*arp);
+	arp = arp_hdr(*pskb);
+	arpptr = skb_network_header(*pskb) + sizeof(*arp);
 	pln = arp->ar_pln;
 	hln = arp->ar_hln;
 	/* We assume that pln and hln were checked in the match */
 	if (mangle->flags & ARPT_MANGLE_SDEV) {
 		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
-		   (arpptr + hln > (**pskb).tail))
+		   (arpptr + hln > skb_tail_pointer(*pskb)))
 			return NF_DROP;
 		memcpy(arpptr, mangle->src_devaddr, hln);
 	}
 	arpptr += hln;
 	if (mangle->flags & ARPT_MANGLE_SIP) {
 		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
-		   (arpptr + pln > (**pskb).tail))
+		   (arpptr + pln > skb_tail_pointer(*pskb)))
 			return NF_DROP;
 		memcpy(arpptr, &mangle->u_s.src_ip, pln);
 	}
 	arpptr += pln;
 	if (mangle->flags & ARPT_MANGLE_TDEV) {
 		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
-		   (arpptr + hln > (**pskb).tail))
+		   (arpptr + hln > skb_tail_pointer(*pskb)))
 			return NF_DROP;
 		memcpy(arpptr, mangle->tgt_devaddr, hln);
 	}
 	arpptr += hln;
 	if (mangle->flags & ARPT_MANGLE_TIP) {
 		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
-		   (arpptr + pln > (**pskb).tail))
+		   (arpptr + pln > skb_tail_pointer(*pskb)))
 			return NF_DROP;
 		memcpy(arpptr, &mangle->u_t.tgt_ip, pln);
 	}
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
deleted file mode 100644
index 4f561f5..0000000
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/* Amanda extension for IP connection tracking, Version 0.2
- * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
- * based on HW's ip_conntrack_irc.c as well as other modules
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- *	Module load syntax:
- * 	insmod ip_conntrack_amanda.o [master_timeout=n]
- *
- *	Where master_timeout is the timeout (in seconds) of the master
- *	connection (port 10080).  This defaults to 5 minutes but if
- *	your clients take longer than 5 minutes to do their work
- *	before getting back to the Amanda server, you can increase
- *	this value.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/textsearch.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
-
-static unsigned int master_timeout = 300;
-static char *ts_algo = "kmp";
-
-MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
-MODULE_DESCRIPTION("Amanda connection tracking module");
-MODULE_LICENSE("GPL");
-module_param(master_timeout, uint, 0600);
-MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
-module_param(ts_algo, charp, 0400);
-MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
-
-unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
-				   enum ip_conntrack_info ctinfo,
-				   unsigned int matchoff,
-				   unsigned int matchlen,
-				   struct ip_conntrack_expect *exp);
-EXPORT_SYMBOL_GPL(ip_nat_amanda_hook);
-
-enum amanda_strings {
-	SEARCH_CONNECT,
-	SEARCH_NEWLINE,
-	SEARCH_DATA,
-	SEARCH_MESG,
-	SEARCH_INDEX,
-};
-
-static struct {
-	char			*string;
-	size_t			len;
-	struct ts_config	*ts;
-} search[] = {
-	[SEARCH_CONNECT] = {
-		.string	= "CONNECT ",
-		.len	= 8,
-	},
-	[SEARCH_NEWLINE] = {
-		.string	= "\n",
-		.len	= 1,
-	},
-	[SEARCH_DATA] = {
-		.string	= "DATA ",
-		.len	= 5,
-	},
-	[SEARCH_MESG] = {
-		.string	= "MESG ",
-		.len	= 5,
-	},
-	[SEARCH_INDEX] = {
-		.string = "INDEX ",
-		.len	= 6,
-	},
-};
-
-static int help(struct sk_buff **pskb,
-		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
-{
-	struct ts_state ts;
-	struct ip_conntrack_expect *exp;
-	unsigned int dataoff, start, stop, off, i;
-	char pbuf[sizeof("65535")], *tmp;
-	u_int16_t port, len;
-	int ret = NF_ACCEPT;
-	typeof(ip_nat_amanda_hook) ip_nat_amanda;
-
-	/* Only look at packets from the Amanda server */
-	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
-		return NF_ACCEPT;
-
-	/* increase the UDP timeout of the master connection as replies from
-	 * Amanda clients to the server can be quite delayed */
-	ip_ct_refresh(ct, *pskb, master_timeout * HZ);
-
-	/* No data? */
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-	if (dataoff >= (*pskb)->len) {
-		if (net_ratelimit())
-			printk("amanda_help: skblen = %u\n", (*pskb)->len);
-		return NF_ACCEPT;
-	}
-
-	memset(&ts, 0, sizeof(ts));
-	start = skb_find_text(*pskb, dataoff, (*pskb)->len,
-			      search[SEARCH_CONNECT].ts, &ts);
-	if (start == UINT_MAX)
-		goto out;
-	start += dataoff + search[SEARCH_CONNECT].len;
-
-	memset(&ts, 0, sizeof(ts));
-	stop = skb_find_text(*pskb, start, (*pskb)->len,
-			     search[SEARCH_NEWLINE].ts, &ts);
-	if (stop == UINT_MAX)
-		goto out;
-	stop += start;
-
-	for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
-		memset(&ts, 0, sizeof(ts));
-		off = skb_find_text(*pskb, start, stop, search[i].ts, &ts);
-		if (off == UINT_MAX)
-			continue;
-		off += start + search[i].len;
-
-		len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
-		if (skb_copy_bits(*pskb, off, pbuf, len))
-			break;
-		pbuf[len] = '\0';
-
-		port = simple_strtoul(pbuf, &tmp, 10);
-		len = tmp - pbuf;
-		if (port == 0 || len > 5)
-			break;
-
-		exp = ip_conntrack_expect_alloc(ct);
-		if (exp == NULL) {
-			ret = NF_DROP;
-			goto out;
-		}
-
-		exp->expectfn = NULL;
-		exp->flags = 0;
-
-		exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-		exp->tuple.src.u.tcp.port = 0;
-		exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
-		exp->tuple.dst.protonum = IPPROTO_TCP;
-		exp->tuple.dst.u.tcp.port = htons(port);
-
-		exp->mask.src.ip = htonl(0xFFFFFFFF);
-		exp->mask.src.u.tcp.port = 0;
-		exp->mask.dst.ip = htonl(0xFFFFFFFF);
-		exp->mask.dst.protonum = 0xFF;
-		exp->mask.dst.u.tcp.port = htons(0xFFFF);
-
-		/* RCU read locked by nf_hook_slow */
-		ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook);
-		if (ip_nat_amanda)
-			ret = ip_nat_amanda(pskb, ctinfo, off - dataoff,
-					    len, exp);
-		else if (ip_conntrack_expect_related(exp) != 0)
-			ret = NF_DROP;
-		ip_conntrack_expect_put(exp);
-	}
-
-out:
-	return ret;
-}
-
-static struct ip_conntrack_helper amanda_helper = {
-	.max_expected = 3,
-	.timeout = 180,
-	.me = THIS_MODULE,
-	.help = help,
-	.name = "amanda",
-
-	.tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } },
-		   .dst = { .protonum = IPPROTO_UDP },
-	},
-	.mask = { .src = { .u = { 0xFFFF } },
-		 .dst = { .protonum = 0xFF },
-	},
-};
-
-static void __exit ip_conntrack_amanda_fini(void)
-{
-	int i;
-
-	ip_conntrack_helper_unregister(&amanda_helper);
-	for (i = 0; i < ARRAY_SIZE(search); i++)
-		textsearch_destroy(search[i].ts);
-}
-
-static int __init ip_conntrack_amanda_init(void)
-{
-	int ret, i;
-
-	ret = -ENOMEM;
-	for (i = 0; i < ARRAY_SIZE(search); i++) {
-		search[i].ts = textsearch_prepare(ts_algo, search[i].string,
-						  search[i].len,
-						  GFP_KERNEL, TS_AUTOLOAD);
-		if (search[i].ts == NULL)
-			goto err;
-	}
-	ret = ip_conntrack_helper_register(&amanda_helper);
-	if (ret < 0)
-		goto err;
-	return 0;
-
-err:
-	for (; i >= 0; i--) {
-		if (search[i].ts)
-			textsearch_destroy(search[i].ts);
-	}
-	return ret;
-}
-
-module_init(ip_conntrack_amanda_init);
-module_exit(ip_conntrack_amanda_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
deleted file mode 100644
index 23b99ae..0000000
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ /dev/null
@@ -1,1550 +0,0 @@
-/* Connection state tracking for netfilter.  This is separated from,
-   but required by, the NAT layer; it can also be used by an iptables
-   extension. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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.
- *
- * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
- * 	- new API and handling of conntrack/nat helpers
- * 	- now capable of multiple expectations for one master
- * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
- * 	- add usage/reference counts to ip_conntrack_expect
- *	- export ip_conntrack[_expect]_{find_get,put} functions
- * */
-
-#include <linux/types.h>
-#include <linux/icmp.h>
-#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/vmalloc.h>
-#include <net/checksum.h>
-#include <net/ip.h>
-#include <linux/stddef.h>
-#include <linux/sysctl.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/jhash.h>
-#include <linux/err.h>
-#include <linux/percpu.h>
-#include <linux/moduleparam.h>
-#include <linux/notifier.h>
-
-/* ip_conntrack_lock protects the main hash table, protocol/helper/expected
-   registrations, conntrack timers*/
-#include <linux/netfilter_ipv4/ip_conntrack.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>
-
-#define IP_CONNTRACK_VERSION	"2.4"
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-DEFINE_RWLOCK(ip_conntrack_lock);
-
-/* ip_conntrack_standalone needs this */
-atomic_t ip_conntrack_count = ATOMIC_INIT(0);
-
-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] __read_mostly;
-static LIST_HEAD(helpers);
-unsigned int ip_conntrack_htable_size __read_mostly = 0;
-int ip_conntrack_max __read_mostly;
-struct list_head *ip_conntrack_hash __read_mostly;
-static struct kmem_cache *ip_conntrack_cachep __read_mostly;
-static struct kmem_cache *ip_conntrack_expect_cachep __read_mostly;
-struct ip_conntrack ip_conntrack_untracked;
-unsigned int ip_ct_log_invalid __read_mostly;
-static LIST_HEAD(unconfirmed);
-static int ip_conntrack_vmalloc __read_mostly;
-
-static unsigned int ip_conntrack_next_id;
-static unsigned int ip_conntrack_expect_next_id;
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain);
-ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain);
-
-DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
-
-/* deliver cached events and clear cache entry - must be called with locally
- * disabled softirqs */
-static inline void
-__ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
-{
-	DEBUGP("ecache: delivering events for %p\n", ecache->ct);
-	if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
-		atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events,
-				    ecache->ct);
-	ecache->events = 0;
-	ip_conntrack_put(ecache->ct);
-	ecache->ct = NULL;
-}
-
-/* Deliver all cached events for a particular conntrack. This is called
- * by code prior to async packet handling or freeing the skb */
-void ip_ct_deliver_cached_events(const struct ip_conntrack *ct)
-{
-	struct ip_conntrack_ecache *ecache;
-
-	local_bh_disable();
-	ecache = &__get_cpu_var(ip_conntrack_ecache);
-	if (ecache->ct == ct)
-		__ip_ct_deliver_cached_events(ecache);
-	local_bh_enable();
-}
-
-void __ip_ct_event_cache_init(struct ip_conntrack *ct)
-{
-	struct ip_conntrack_ecache *ecache;
-
-	/* take care of delivering potentially old events */
-	ecache = &__get_cpu_var(ip_conntrack_ecache);
-	BUG_ON(ecache->ct == ct);
-	if (ecache->ct)
-		__ip_ct_deliver_cached_events(ecache);
-	/* initialize for this conntrack/packet */
-	ecache->ct = ct;
-	nf_conntrack_get(&ct->ct_general);
-}
-
-/* flush the event cache - touches other CPU's data and must not be called while
- * packets are still passing through the code */
-static void ip_ct_event_cache_flush(void)
-{
-	struct ip_conntrack_ecache *ecache;
-	int cpu;
-
-	for_each_possible_cpu(cpu) {
-		ecache = &per_cpu(ip_conntrack_ecache, cpu);
-		if (ecache->ct)
-			ip_conntrack_put(ecache->ct);
-	}
-}
-#else
-static inline void ip_ct_event_cache_flush(void) {}
-#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-
-DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
-
-static int ip_conntrack_hash_rnd_initted;
-static unsigned int ip_conntrack_hash_rnd;
-
-static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple,
-			    unsigned int size, unsigned int rnd)
-{
-	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);
-}
-
-static u_int32_t
-hash_conntrack(const struct ip_conntrack_tuple *tuple)
-{
-	return __hash_conntrack(tuple, ip_conntrack_htable_size,
-				ip_conntrack_hash_rnd);
-}
-
-int
-ip_ct_get_tuple(const struct iphdr *iph,
-		const struct sk_buff *skb,
-		unsigned int dataoff,
-		struct ip_conntrack_tuple *tuple,
-		const struct ip_conntrack_protocol *protocol)
-{
-	/* Never happen */
-	if (iph->frag_off & htons(IP_OFFSET)) {
-		printk("ip_conntrack_core: Frag of proto %u.\n",
-		       iph->protocol);
-		return 0;
-	}
-
-	tuple->src.ip = iph->saddr;
-	tuple->dst.ip = iph->daddr;
-	tuple->dst.protonum = iph->protocol;
-	tuple->dst.dir = IP_CT_DIR_ORIGINAL;
-
-	return protocol->pkt_to_tuple(skb, dataoff, tuple);
-}
-
-int
-ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
-		   const struct ip_conntrack_tuple *orig,
-		   const struct ip_conntrack_protocol *protocol)
-{
-	inverse->src.ip = orig->dst.ip;
-	inverse->dst.ip = orig->src.ip;
-	inverse->dst.protonum = orig->dst.protonum;
-	inverse->dst.dir = !orig->dst.dir;
-
-	return protocol->invert_tuple(inverse, orig);
-}
-
-
-/* ip_conntrack_expect helper functions */
-void ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
-{
-	IP_NF_ASSERT(!timer_pending(&exp->timeout));
-	list_del(&exp->list);
-	CONNTRACK_STAT_INC(expect_delete);
-	exp->master->expecting--;
-	ip_conntrack_expect_put(exp);
-}
-
-static void expectation_timed_out(unsigned long ul_expect)
-{
-	struct ip_conntrack_expect *exp = (void *)ul_expect;
-
-	write_lock_bh(&ip_conntrack_lock);
-	ip_ct_unlink_expect(exp);
-	write_unlock_bh(&ip_conntrack_lock);
-	ip_conntrack_expect_put(exp);
-}
-
-struct ip_conntrack_expect *
-__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple)
-{
-	struct ip_conntrack_expect *i;
-
-	list_for_each_entry(i, &ip_conntrack_expect_list, list) {
-		if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
-			return i;
-	}
-	return NULL;
-}
-
-/* Just find a expectation corresponding to a tuple. */
-struct ip_conntrack_expect *
-ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
-{
-	struct ip_conntrack_expect *i;
-
-	read_lock_bh(&ip_conntrack_lock);
-	i = __ip_conntrack_expect_find(tuple);
-	if (i)
-		atomic_inc(&i->use);
-	read_unlock_bh(&ip_conntrack_lock);
-
-	return i;
-}
-
-/* If an expectation for this connection is found, it gets delete from
- * global list then returned. */
-static struct ip_conntrack_expect *
-find_expectation(const struct ip_conntrack_tuple *tuple)
-{
-	struct ip_conntrack_expect *i;
-
-	list_for_each_entry(i, &ip_conntrack_expect_list, list) {
-		/* If master is not in hash table yet (ie. packet hasn't left
-		   this machine yet), how can other end know about expected?
-		   Hence these are not the droids you are looking for (if
-		   master ct never got confirmed, we'd hold a reference to it
-		   and weird things would happen to future packets). */
-		if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)
-		    && is_confirmed(i->master)) {
-			if (i->flags & IP_CT_EXPECT_PERMANENT) {
-				atomic_inc(&i->use);
-				return i;
-			} else if (del_timer(&i->timeout)) {
-				ip_ct_unlink_expect(i);
-				return i;
-			}
-		}
-	}
-	return NULL;
-}
-
-/* delete all expectations for this conntrack */
-void ip_ct_remove_expectations(struct ip_conntrack *ct)
-{
-	struct ip_conntrack_expect *i, *tmp;
-
-	/* Optimization: most connection never expect any others. */
-	if (ct->expecting == 0)
-		return;
-
-	list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) {
-		if (i->master == ct && del_timer(&i->timeout)) {
-			ip_ct_unlink_expect(i);
-			ip_conntrack_expect_put(i);
-		}
-	}
-}
-
-static void
-clean_from_lists(struct ip_conntrack *ct)
-{
-	DEBUGP("clean_from_lists(%p)\n", ct);
-	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);
-}
-
-static void
-destroy_conntrack(struct nf_conntrack *nfct)
-{
-	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
-	struct ip_conntrack_protocol *proto;
-	struct ip_conntrack_helper *helper;
-	typeof(ip_conntrack_destroyed) destroyed;
-
-	DEBUGP("destroy_conntrack(%p)\n", ct);
-	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
-	IP_NF_ASSERT(!timer_pending(&ct->timeout));
-
-	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 */
-	rcu_read_lock();
-	proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
-	if (proto && proto->destroy)
-		proto->destroy(ct);
-
-	destroyed = rcu_dereference(ip_conntrack_destroyed);
-	if (destroyed)
-		destroyed(ct);
-
-	rcu_read_unlock();
-
-	write_lock_bh(&ip_conntrack_lock);
-	/* Expectations will have been removed in clean_from_lists,
-	 * except TFTP can create an expectation on the first packet,
-	 * before connection is in the list, so we need to clean here,
-	 * too. */
-	ip_ct_remove_expectations(ct);
-
-	/* We overload first tuple to link into unconfirmed list. */
-	if (!is_confirmed(ct)) {
-		BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
-		list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
-	}
-
-	CONNTRACK_STAT_INC(delete);
-	write_unlock_bh(&ip_conntrack_lock);
-
-	if (ct->master)
-		ip_conntrack_put(ct->master);
-
-	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
-	ip_conntrack_free(ct);
-}
-
-static void death_by_timeout(unsigned long ul_conntrack)
-{
-	struct ip_conntrack *ct = (void *)ul_conntrack;
-
-	write_lock_bh(&ip_conntrack_lock);
-	/* Inside lock so preempt is disabled on module removal path.
-	 * Otherwise we can get spurious warnings. */
-	CONNTRACK_STAT_INC(delete_list);
-	clean_from_lists(ct);
-	write_unlock_bh(&ip_conntrack_lock);
-	ip_conntrack_put(ct);
-}
-
-struct ip_conntrack_tuple_hash *
-__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
-		    const struct ip_conntrack *ignored_conntrack)
-{
-	struct ip_conntrack_tuple_hash *h;
-	unsigned int hash = hash_conntrack(tuple);
-
-	list_for_each_entry(h, &ip_conntrack_hash[hash], list) {
-		if (tuplehash_to_ctrack(h) != ignored_conntrack &&
-		    ip_ct_tuple_equal(tuple, &h->tuple)) {
-			CONNTRACK_STAT_INC(found);
-			return h;
-		}
-		CONNTRACK_STAT_INC(searched);
-	}
-
-	return NULL;
-}
-
-/* Find a connection corresponding to a tuple. */
-struct ip_conntrack_tuple_hash *
-ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
-		      const struct ip_conntrack *ignored_conntrack)
-{
-	struct ip_conntrack_tuple_hash *h;
-
-	read_lock_bh(&ip_conntrack_lock);
-	h = __ip_conntrack_find(tuple, ignored_conntrack);
-	if (h)
-		atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use);
-	read_unlock_bh(&ip_conntrack_lock);
-
-	return h;
-}
-
-static void __ip_conntrack_hash_insert(struct ip_conntrack *ct,
-					unsigned int hash,
-					unsigned int repl_hash)
-{
-	ct->id = ++ip_conntrack_next_id;
-	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)
-{
-	unsigned int hash, repl_hash;
-
-	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-
-	write_lock_bh(&ip_conntrack_lock);
-	__ip_conntrack_hash_insert(ct, hash, repl_hash);
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-/* Confirm a connection given skb; places it in hash table */
-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;
-
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-
-	/* ipt_REJECT uses ip_conntrack_attach to attach related
-	   ICMP/TCP RST packets in other direction.  Actual packet
-	   which created connection will be IP_CT_NEW or for an
-	   expected connection, IP_CT_RELATED. */
-	if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
-		return NF_ACCEPT;
-
-	hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-	repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-
-	/* We're not in hash table, and we refuse to set up related
-	   connections for unconfirmed conns.  But packet copies and
-	   REJECT will give spurious warnings here. */
-	/* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
-
-	/* No external references means noone else could have
-	   confirmed us. */
-	IP_NF_ASSERT(!is_confirmed(ct));
-	DEBUGP("Confirming conntrack %p\n", ct);
-
-	write_lock_bh(&ip_conntrack_lock);
-
-	/* 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. */
-	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;
-
-	/* 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);
-#endif
-	ip_conntrack_event_cache(master_ct(ct) ?
-				 IPCT_RELATED : IPCT_NEW, *pskb);
-
-	return NF_ACCEPT;
-
-out:
-	CONNTRACK_STAT_INC(insert_failed);
-	write_unlock_bh(&ip_conntrack_lock);
-	return NF_DROP;
-}
-
-/* Returns true if a connection correspondings to the tuple (required
-   for NAT). */
-int
-ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
-			 const struct ip_conntrack *ignored_conntrack)
-{
-	struct ip_conntrack_tuple_hash *h;
-
-	read_lock_bh(&ip_conntrack_lock);
-	h = __ip_conntrack_find(tuple, ignored_conntrack);
-	read_unlock_bh(&ip_conntrack_lock);
-
-	return h != NULL;
-}
-
-/* There's a small race here where we may free a just-assured
-   connection.  Too bad: we're in trouble anyway. */
-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, *tmp;
-	int dropped = 0;
-
-	read_lock_bh(&ip_conntrack_lock);
-	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);
-
-	if (!ct)
-		return dropped;
-
-	if (del_timer(&ct->timeout)) {
-		death_by_timeout((unsigned long)ct);
-		dropped = 1;
-		CONNTRACK_STAT_INC_ATOMIC(early_drop);
-	}
-	ip_conntrack_put(ct);
-	return dropped;
-}
-
-static struct ip_conntrack_helper *
-__ip_conntrack_helper_find( const struct ip_conntrack_tuple *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 *
-ip_conntrack_helper_find_get( const struct ip_conntrack_tuple *tuple)
-{
-	struct ip_conntrack_helper *helper;
-
-	/* need ip_conntrack_lock to assure that helper exists until
-	 * try_module_get() is called */
-	read_lock_bh(&ip_conntrack_lock);
-
-	helper = __ip_conntrack_helper_find(tuple);
-	if (helper) {
-		/* need to increase module usage count to assure helper will
-		 * not go away while the caller is e.g. busy putting a
-		 * conntrack in the hash that uses the helper */
-		if (!try_module_get(helper->me))
-			helper = NULL;
-	}
-
-	read_unlock_bh(&ip_conntrack_lock);
-
-	return helper;
-}
-
-void ip_conntrack_helper_put(struct ip_conntrack_helper *helper)
-{
-	module_put(helper->me);
-}
-
-struct ip_conntrack_protocol *
-__ip_conntrack_proto_find(u_int8_t protocol)
-{
-	return ip_ct_protos[protocol];
-}
-
-/* this is guaranteed to always return a valid protocol helper, since
- * it falls back to generic_protocol */
-struct ip_conntrack_protocol *
-ip_conntrack_proto_find_get(u_int8_t protocol)
-{
-	struct ip_conntrack_protocol *p;
-
-	rcu_read_lock();
-	p = __ip_conntrack_proto_find(protocol);
-	if (p) {
-		if (!try_module_get(p->me))
-			p = &ip_conntrack_generic_protocol;
-	}
-	rcu_read_unlock();
-
-	return p;
-}
-
-void ip_conntrack_proto_put(struct ip_conntrack_protocol *p)
-{
-	module_put(p->me);
-}
-
-struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig,
-					struct ip_conntrack_tuple *repl)
-{
-	struct ip_conntrack *conntrack;
-
-	if (!ip_conntrack_hash_rnd_initted) {
-		get_random_bytes(&ip_conntrack_hash_rnd, 4);
-		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) {
-		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"
-				       " packet.\n");
-			return ERR_PTR(-ENOMEM);
-		}
-	}
-
-	conntrack = kmem_cache_zalloc(ip_conntrack_cachep, GFP_ATOMIC);
-	if (!conntrack) {
-		DEBUGP("Can't allocate conntrack.\n");
-		atomic_dec(&ip_conntrack_count);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	atomic_set(&conntrack->ct_general.use, 1);
-	conntrack->ct_general.destroy = destroy_conntrack;
-	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
-	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
-	/* Don't set timer yet: wait for confirmation */
-	init_timer(&conntrack->timeout);
-	conntrack->timeout.data = (unsigned long)conntrack;
-	conntrack->timeout.function = death_by_timeout;
-
-	return conntrack;
-}
-
-void
-ip_conntrack_free(struct ip_conntrack *conntrack)
-{
-	atomic_dec(&ip_conntrack_count);
-	kmem_cache_free(ip_conntrack_cachep, conntrack);
-}
-
-/* Allocate a new conntrack: we return -ENOMEM if classification
- * failed due to stress.   Otherwise it really is unclassifiable */
-static struct ip_conntrack_tuple_hash *
-init_conntrack(struct ip_conntrack_tuple *tuple,
-	       struct ip_conntrack_protocol *protocol,
-	       struct sk_buff *skb)
-{
-	struct ip_conntrack *conntrack;
-	struct ip_conntrack_tuple repl_tuple;
-	struct ip_conntrack_expect *exp;
-
-	if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) {
-		DEBUGP("Can't invert tuple.\n");
-		return NULL;
-	}
-
-	conntrack = ip_conntrack_alloc(tuple, &repl_tuple);
-	if (conntrack == NULL || IS_ERR(conntrack))
-		return (struct ip_conntrack_tuple_hash *)conntrack;
-
-	if (!protocol->new(conntrack, skb)) {
-		ip_conntrack_free(conntrack);
-		return NULL;
-	}
-
-	write_lock_bh(&ip_conntrack_lock);
-	exp = find_expectation(tuple);
-
-	if (exp) {
-		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
-			conntrack, exp);
-		/* Welcome, Mr. Bond.  We've been expecting you... */
-		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
-		conntrack->master = exp->master;
-#ifdef CONFIG_IP_NF_CONNTRACK_MARK
-		conntrack->mark = exp->master->mark;
-#endif
-#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
-    defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
-		/* this is ugly, but there is no other place where to put it */
-		conntrack->nat.masq_index = exp->master->nat.masq_index;
-#endif
-#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
-		conntrack->secmark = exp->master->secmark;
-#endif
-		nf_conntrack_get(&conntrack->master->ct_general);
-		CONNTRACK_STAT_INC(expect_new);
-	} else {
-		conntrack->helper = __ip_conntrack_helper_find(&repl_tuple);
-
-		CONNTRACK_STAT_INC(new);
-	}
-
-	/* Overload tuple linked list to put us in unconfirmed list. */
-	list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
-
-	write_unlock_bh(&ip_conntrack_lock);
-
-	if (exp) {
-		if (exp->expectfn)
-			exp->expectfn(conntrack, exp);
-		ip_conntrack_expect_put(exp);
-	}
-
-	return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
-}
-
-/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
-static inline struct ip_conntrack *
-resolve_normal_ct(struct sk_buff *skb,
-		  struct ip_conntrack_protocol *proto,
-		  int *set_reply,
-		  unsigned int hooknum,
-		  enum ip_conntrack_info *ctinfo)
-{
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack *ct;
-
-	IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
-
-	if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4,
-				&tuple,proto))
-		return NULL;
-
-	/* look for tuple match */
-	h = ip_conntrack_find_get(&tuple, NULL);
-	if (!h) {
-		h = init_conntrack(&tuple, proto, skb);
-		if (!h)
-			return NULL;
-		if (IS_ERR(h))
-			return (void *)h;
-	}
-	ct = tuplehash_to_ctrack(h);
-
-	/* It exists; we have (non-exclusive) reference. */
-	if (DIRECTION(h) == IP_CT_DIR_REPLY) {
-		*ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
-		/* Please set reply bit if this packet OK */
-		*set_reply = 1;
-	} else {
-		/* Once we've had two way comms, always ESTABLISHED. */
-		if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
-			DEBUGP("ip_conntrack_in: normal packet for %p\n",
-			       ct);
-			*ctinfo = IP_CT_ESTABLISHED;
-		} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
-			DEBUGP("ip_conntrack_in: related packet for %p\n",
-			       ct);
-			*ctinfo = IP_CT_RELATED;
-		} else {
-			DEBUGP("ip_conntrack_in: new packet for %p\n",
-			       ct);
-			*ctinfo = IP_CT_NEW;
-		}
-		*set_reply = 0;
-	}
-	skb->nfct = &ct->ct_general;
-	skb->nfctinfo = *ctinfo;
-	return ct;
-}
-
-/* Netfilter hook itself. */
-unsigned int ip_conntrack_in(unsigned int hooknum,
-			     struct sk_buff **pskb,
-			     const struct net_device *in,
-			     const struct net_device *out,
-			     int (*okfn)(struct sk_buff *))
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack_protocol *proto;
-	int set_reply = 0;
-	int ret;
-
-	/* Previously seen (loopback or untracked)?  Ignore. */
-	if ((*pskb)->nfct) {
-		CONNTRACK_STAT_INC_ATOMIC(ignore);
-		return NF_ACCEPT;
-	}
-
-	/* Never happen */
-	if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
-		if (net_ratelimit()) {
-		printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
-		       (*pskb)->nh.iph->protocol, hooknum);
-		}
-		return NF_DROP;
-	}
-
-/* Doesn't cover locally-generated broadcast, so not worth it. */
-#if 0
-	/* Ignore broadcast: no `connection'. */
-	if ((*pskb)->pkt_type == PACKET_BROADCAST) {
-		printk("Broadcast packet!\n");
-		return NF_ACCEPT;
-	} else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
-		   == htonl(0x000000FF)) {
-		printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
-		       NIPQUAD((*pskb)->nh.iph->saddr),
-		       NIPQUAD((*pskb)->nh.iph->daddr),
-		       (*pskb)->sk, (*pskb)->pkt_type);
-	}
-#endif
-
-	/* rcu_read_lock()ed by nf_hook_slow */
-	proto = __ip_conntrack_proto_find((*pskb)->nh.iph->protocol);
-
-	/* It may be an special packet, error, unclean...
-	 * inverse of the return code tells to the netfilter
-	 * core what to do with the packet. */
-	if (proto->error != NULL
-	    && (ret = proto->error(*pskb, &ctinfo, hooknum)) <= 0) {
-		CONNTRACK_STAT_INC_ATOMIC(error);
-		CONNTRACK_STAT_INC_ATOMIC(invalid);
-		return -ret;
-	}
-
-	if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) {
-		/* Not valid part of a connection */
-		CONNTRACK_STAT_INC_ATOMIC(invalid);
-		return NF_ACCEPT;
-	}
-
-	if (IS_ERR(ct)) {
-		/* Too stressed to deal. */
-		CONNTRACK_STAT_INC_ATOMIC(drop);
-		return NF_DROP;
-	}
-
-	IP_NF_ASSERT((*pskb)->nfct);
-
-	ret = proto->packet(ct, *pskb, ctinfo);
-	if (ret < 0) {
-		/* Invalid: inverse of the return code tells
-		 * the netfilter core what to do*/
-		nf_conntrack_put((*pskb)->nfct);
-		(*pskb)->nfct = NULL;
-		CONNTRACK_STAT_INC_ATOMIC(invalid);
-		return -ret;
-	}
-
-	if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
-		ip_conntrack_event_cache(IPCT_STATUS, *pskb);
-
-	return ret;
-}
-
-int invert_tuplepr(struct ip_conntrack_tuple *inverse,
-		   const struct ip_conntrack_tuple *orig)
-{
-	struct ip_conntrack_protocol *proto;
-	int ret;
-
-	rcu_read_lock();
-	proto = __ip_conntrack_proto_find(orig->dst.protonum);
-	ret = ip_ct_invert_tuple(inverse, orig, proto);
-	rcu_read_unlock();
-
-	return ret;
-}
-
-/* Would two expected things clash? */
-static inline int expect_clash(const struct ip_conntrack_expect *a,
-			       const struct ip_conntrack_expect *b)
-{
-	/* Part covered by intersection of masks must be unequal,
-	   otherwise they clash */
-	struct ip_conntrack_tuple intersect_mask
-		= { { a->mask.src.ip & b->mask.src.ip,
-		      { a->mask.src.u.all & b->mask.src.u.all } },
-		    { a->mask.dst.ip & b->mask.dst.ip,
-		      { a->mask.dst.u.all & b->mask.dst.u.all },
-		      a->mask.dst.protonum & b->mask.dst.protonum } };
-
-	return ip_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
-}
-
-static inline int expect_matches(const struct ip_conntrack_expect *a,
-				 const struct ip_conntrack_expect *b)
-{
-	return a->master == b->master
-		&& ip_ct_tuple_equal(&a->tuple, &b->tuple)
-		&& ip_ct_tuple_equal(&a->mask, &b->mask);
-}
-
-/* Generally a bad idea to call this: could have matched already. */
-void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp)
-{
-	struct ip_conntrack_expect *i;
-
-	write_lock_bh(&ip_conntrack_lock);
-	/* choose the the oldest expectation to evict */
-	list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
-		if (expect_matches(i, exp) && del_timer(&i->timeout)) {
-			ip_ct_unlink_expect(i);
-			write_unlock_bh(&ip_conntrack_lock);
-			ip_conntrack_expect_put(i);
-			return;
-		}
-	}
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-/* We don't increase the master conntrack refcount for non-fulfilled
- * conntracks. During the conntrack destruction, the expectations are
- * always killed before the conntrack itself */
-struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me)
-{
-	struct ip_conntrack_expect *new;
-
-	new = kmem_cache_alloc(ip_conntrack_expect_cachep, GFP_ATOMIC);
-	if (!new) {
-		DEBUGP("expect_related: OOM allocating expect\n");
-		return NULL;
-	}
-	new->master = me;
-	atomic_set(&new->use, 1);
-	return new;
-}
-
-void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
-{
-	if (atomic_dec_and_test(&exp->use))
-		kmem_cache_free(ip_conntrack_expect_cachep, exp);
-}
-
-static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp)
-{
-	atomic_inc(&exp->use);
-	exp->master->expecting++;
-	list_add(&exp->list, &ip_conntrack_expect_list);
-
-	init_timer(&exp->timeout);
-	exp->timeout.data = (unsigned long)exp;
-	exp->timeout.function = expectation_timed_out;
-	exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ;
-	add_timer(&exp->timeout);
-
-	exp->id = ++ip_conntrack_expect_next_id;
-	atomic_inc(&exp->use);
-	CONNTRACK_STAT_INC(expect_create);
-}
-
-/* Race with expectations being used means we could have none to find; OK. */
-static void evict_oldest_expect(struct ip_conntrack *master)
-{
-	struct ip_conntrack_expect *i;
-
-	list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) {
-		if (i->master == master) {
-			if (del_timer(&i->timeout)) {
-				ip_ct_unlink_expect(i);
-				ip_conntrack_expect_put(i);
-			}
-			break;
-		}
-	}
-}
-
-static inline int refresh_timer(struct ip_conntrack_expect *i)
-{
-	if (!del_timer(&i->timeout))
-		return 0;
-
-	i->timeout.expires = jiffies + i->master->helper->timeout*HZ;
-	add_timer(&i->timeout);
-	return 1;
-}
-
-int ip_conntrack_expect_related(struct ip_conntrack_expect *expect)
-{
-	struct ip_conntrack_expect *i;
-	int ret;
-
-	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
-	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
-	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
-
-	write_lock_bh(&ip_conntrack_lock);
-	list_for_each_entry(i, &ip_conntrack_expect_list, list) {
-		if (expect_matches(i, expect)) {
-			/* Refresh timer: if it's dying, ignore.. */
-			if (refresh_timer(i)) {
-				ret = 0;
-				goto out;
-			}
-		} else if (expect_clash(i, expect)) {
-			ret = -EBUSY;
-			goto out;
-		}
-	}
-
-	/* Will be over limit? */
-	if (expect->master->helper->max_expected &&
-	    expect->master->expecting >= expect->master->helper->max_expected)
-		evict_oldest_expect(expect->master);
-
-	ip_conntrack_expect_insert(expect);
-	ip_conntrack_expect_event(IPEXP_NEW, expect);
-	ret = 0;
-out:
-	write_unlock_bh(&ip_conntrack_lock);
-	return ret;
-}
-
-/* Alter reply tuple (maybe alter helper).  This is for NAT, and is
-   implicitly racy: see __ip_conntrack_confirm */
-void ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
-			      const struct ip_conntrack_tuple *newreply)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	/* Should be unconfirmed, so not in hash table yet */
-	IP_NF_ASSERT(!is_confirmed(conntrack));
-
-	DEBUGP("Altering reply tuple of %p to ", conntrack);
-	DUMP_TUPLE(newreply);
-
-	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	if (!conntrack->master && conntrack->expecting == 0)
-		conntrack->helper = __ip_conntrack_helper_find(newreply);
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
-{
-	BUG_ON(me->timeout == 0);
-	write_lock_bh(&ip_conntrack_lock);
-	list_add(&me->list, &helpers);
-	write_unlock_bh(&ip_conntrack_lock);
-
-	return 0;
-}
-
-struct ip_conntrack_helper *
-__ip_conntrack_helper_find_byname(const char *name)
-{
-	struct ip_conntrack_helper *h;
-
-	list_for_each_entry(h, &helpers, list) {
-		if (!strcmp(h->name, name))
-			return h;
-	}
-
-	return NULL;
-}
-
-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;
-	}
-}
-
-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_del(&me->list);
-
-	/* Get rid of expectations */
-	list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) {
-		if (exp->master->helper == me && del_timer(&exp->timeout)) {
-			ip_ct_unlink_expect(exp);
-			ip_conntrack_expect_put(exp);
-		}
-	}
-	/* Get rid of expecteds, set helpers to NULL. */
-	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. */
-	synchronize_net();
-}
-
-/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
-void __ip_ct_refresh_acct(struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			const struct sk_buff *skb,
-			unsigned long extra_jiffies,
-			int do_acct)
-{
-	int event = 0;
-
-	IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
-	IP_NF_ASSERT(skb);
-
-	write_lock_bh(&ip_conntrack_lock);
-
-	/* Only update if this is not a fixed timeout */
-	if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
-		write_unlock_bh(&ip_conntrack_lock);
-		return;
-	}
-
-	/* If not in hash table, timer will not be active yet */
-	if (!is_confirmed(ct)) {
-		ct->timeout.expires = extra_jiffies;
-		event = IPCT_REFRESH;
-	} else {
-		/* Need del_timer for race avoidance (may already be dying). */
-		if (del_timer(&ct->timeout)) {
-			ct->timeout.expires = jiffies + extra_jiffies;
-			add_timer(&ct->timeout);
-			event = IPCT_REFRESH;
-		}
-	}
-
-#ifdef CONFIG_IP_NF_CT_ACCT
-	if (do_acct) {
-		ct->counters[CTINFO2DIR(ctinfo)].packets++;
-		ct->counters[CTINFO2DIR(ctinfo)].bytes +=
-						ntohs(skb->nh.iph->tot_len);
-		if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000)
-		    || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000))
-			event |= IPCT_COUNTER_FILLING;
-	}
-#endif
-
-	write_unlock_bh(&ip_conntrack_lock);
-
-	/* must be unlocked when calling event cache */
-	if (event)
-		ip_conntrack_event_cache(event, skb);
-}
-
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-/* Generic function for tcp/udp/sctp/dccp and alike. This needs to be
- * in ip_conntrack_core, since we don't want the protocols to autoload
- * or depend on ctnetlink */
-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(__be16),
-		&tuple->src.u.tcp.port);
-	NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16),
-		&tuple->dst.u.tcp.port);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
-			       struct ip_conntrack_tuple *t)
-{
-	if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1])
-		return -EINVAL;
-
-	t->src.u.tcp.port =
-		*(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
-	t->dst.u.tcp.port =
-		*(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
-
-	return 0;
-}
-#endif
-
-/* Returns new sk_buff, or NULL */
-struct sk_buff *
-ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
-{
-	skb_orphan(skb);
-
-	local_bh_disable();
-	skb = ip_defrag(skb, user);
-	local_bh_enable();
-
-	if (skb)
-		ip_send_check(skb->nh.iph);
-	return skb;
-}
-
-/* Used by ipt_REJECT. */
-static void ip_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb)
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-
-	/* This ICMP is in reverse direction to the packet which caused it */
-	ct = ip_conntrack_get(skb, &ctinfo);
-
-	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
-		ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
-	else
-		ctinfo = IP_CT_RELATED;
-
-	/* Attach to new skbuff, and increment count */
-	nskb->nfct = &ct->ct_general;
-	nskb->nfctinfo = ctinfo;
-	nf_conntrack_get(nskb->nfct);
-}
-
-/* Bring out ya dead! */
-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;
-	struct ip_conntrack *ct;
-
-	write_lock_bh(&ip_conntrack_lock);
-	for (; *bucket < ip_conntrack_htable_size; (*bucket)++) {
-		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))
-			set_bit(IPS_DYING_BIT, &ct->status);
-	}
-	write_unlock_bh(&ip_conntrack_lock);
-	return NULL;
-
-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 *ct;
-	unsigned int bucket = 0;
-
-	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);
-		/* ... else the timer will get him soon. */
-
-		ip_conntrack_put(ct);
-	}
-}
-
-/* Fast function for those who don't want to parse /proc (and I don't
-   blame them). */
-/* Reversing the socket's dst/src point of view gives us the reply
-   mapping. */
-static int
-getorigdst(struct sock *sk, int optval, void __user *user, int *len)
-{
-	struct inet_sock *inet = inet_sk(sk);
-	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_tuple tuple;
-
-	IP_CT_TUPLE_U_BLANK(&tuple);
-	tuple.src.ip = inet->rcv_saddr;
-	tuple.src.u.tcp.port = inet->sport;
-	tuple.dst.ip = inet->daddr;
-	tuple.dst.u.tcp.port = inet->dport;
-	tuple.dst.protonum = IPPROTO_TCP;
-
-	/* We only do TCP at the moment: is there a better way? */
-	if (strcmp(sk->sk_prot->name, "TCP")) {
-		DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
-		return -ENOPROTOOPT;
-	}
-
-	if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
-		DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
-		       *len, sizeof(struct sockaddr_in));
-		return -EINVAL;
-	}
-
-	h = ip_conntrack_find_get(&tuple, NULL);
-	if (h) {
-		struct sockaddr_in sin;
-		struct ip_conntrack *ct = tuplehash_to_ctrack(h);
-
-		sin.sin_family = AF_INET;
-		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
-			.tuple.dst.u.tcp.port;
-		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
-			.tuple.dst.ip;
-		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
-
-		DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
-		       NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
-		ip_conntrack_put(ct);
-		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
-			return -EFAULT;
-		else
-			return 0;
-	}
-	DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
-	       NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
-	       NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
-	return -ENOENT;
-}
-
-static struct nf_sockopt_ops so_getorigdst = {
-	.pf		= PF_INET,
-	.get_optmin	= SO_ORIGINAL_DST,
-	.get_optmax	= SO_ORIGINAL_DST+1,
-	.get		= &getorigdst,
-};
-
-static int kill_all(struct ip_conntrack *i, void *data)
-{
-	return 1;
-}
-
-void ip_conntrack_flush(void)
-{
-	ip_ct_iterate_cleanup(kill_all, NULL);
-}
-
-static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size)
-{
-	if (vmalloced)
-		vfree(hash);
-	else
-		free_pages((unsigned long)hash,
-			   get_order(sizeof(struct list_head) * size));
-}
-
-/* Mishearing the voices in his head, our hero wonders how he's
-   supposed to kill the mall. */
-void ip_conntrack_cleanup(void)
-{
-	rcu_assign_pointer(ip_ct_attach, NULL);
-
-	/* This makes sure all current packets have passed through
-	   netfilter framework.  Roll on, two-stage module
-	   delete... */
-	synchronize_net();
-
-	ip_ct_event_cache_flush();
- i_see_dead_people:
-	ip_conntrack_flush();
-	if (atomic_read(&ip_conntrack_count) != 0) {
-		schedule();
-		goto i_see_dead_people;
-	}
-	/* wait until all references to ip_conntrack_untracked are dropped */
-	while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1)
-		schedule();
-
-	kmem_cache_destroy(ip_conntrack_cachep);
-	kmem_cache_destroy(ip_conntrack_expect_cachep);
-	free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc,
-			    ip_conntrack_htable_size);
-	nf_unregister_sockopt(&so_getorigdst);
-}
-
-static struct list_head *alloc_hashtable(int size, int *vmalloced)
-{
-	struct list_head *hash;
-	unsigned int i;
-
-	*vmalloced = 0;
-	hash = (void*)__get_free_pages(GFP_KERNEL,
-				       get_order(sizeof(struct list_head)
-						 * size));
-	if (!hash) {
-		*vmalloced = 1;
-		printk(KERN_WARNING"ip_conntrack: falling back to vmalloc.\n");
-		hash = vmalloc(sizeof(struct list_head) * size);
-	}
-
-	if (hash)
-		for (i = 0; i < size; i++)
-			INIT_LIST_HEAD(&hash[i]);
-
-	return hash;
-}
-
-static int set_hashsize(const char *val, struct kernel_param *kp)
-{
-	int i, bucket, hashsize, vmalloced;
-	int old_vmalloced, old_size;
-	int rnd;
-	struct list_head *hash, *old_hash;
-	struct ip_conntrack_tuple_hash *h;
-
-	/* On boot, we can set this without any fancy locking. */
-	if (!ip_conntrack_htable_size)
-		return param_set_int(val, kp);
-
-	hashsize = simple_strtol(val, NULL, 0);
-	if (!hashsize)
-		return -EINVAL;
-
-	hash = alloc_hashtable(hashsize, &vmalloced);
-	if (!hash)
-		return -ENOMEM;
-
-	/* We have to rehash for the new table anyway, so we also can
-	 * use a new random seed */
-	get_random_bytes(&rnd, 4);
-
-	write_lock_bh(&ip_conntrack_lock);
-	for (i = 0; i < ip_conntrack_htable_size; i++) {
-		while (!list_empty(&ip_conntrack_hash[i])) {
-			h = list_entry(ip_conntrack_hash[i].next,
-				       struct ip_conntrack_tuple_hash, list);
-			list_del(&h->list);
-			bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
-			list_add_tail(&h->list, &hash[bucket]);
-		}
-	}
-	old_size = ip_conntrack_htable_size;
-	old_vmalloced = ip_conntrack_vmalloc;
-	old_hash = ip_conntrack_hash;
-
-	ip_conntrack_htable_size = hashsize;
-	ip_conntrack_vmalloc = vmalloced;
-	ip_conntrack_hash = hash;
-	ip_conntrack_hash_rnd = rnd;
-	write_unlock_bh(&ip_conntrack_lock);
-
-	free_conntrack_hash(old_hash, old_vmalloced, old_size);
-	return 0;
-}
-
-module_param_call(hashsize, set_hashsize, param_get_uint,
-		  &ip_conntrack_htable_size, 0600);
-
-int __init ip_conntrack_init(void)
-{
-	unsigned int i;
-	int ret;
-
-	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
-	 * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
-	if (!ip_conntrack_htable_size) {
-		ip_conntrack_htable_size
-			= (((num_physpages << PAGE_SHIFT) / 16384)
-			   / sizeof(struct list_head));
-		if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
-			ip_conntrack_htable_size = 8192;
-		if (ip_conntrack_htable_size < 16)
-			ip_conntrack_htable_size = 16;
-	}
-	ip_conntrack_max = 8 * ip_conntrack_htable_size;
-
-	printk("ip_conntrack version %s (%u buckets, %d max)"
-	       " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
-	       ip_conntrack_htable_size, ip_conntrack_max,
-	       sizeof(struct ip_conntrack));
-
-	ret = nf_register_sockopt(&so_getorigdst);
-	if (ret != 0) {
-		printk(KERN_ERR "Unable to register netfilter socket option\n");
-		return ret;
-	}
-
-	ip_conntrack_hash = alloc_hashtable(ip_conntrack_htable_size,
-					    &ip_conntrack_vmalloc);
-	if (!ip_conntrack_hash) {
-		printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
-		goto err_unreg_sockopt;
-	}
-
-	ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
-						sizeof(struct ip_conntrack), 0,
-						0, NULL, NULL);
-	if (!ip_conntrack_cachep) {
-		printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
-		goto err_free_hash;
-	}
-
-	ip_conntrack_expect_cachep = kmem_cache_create("ip_conntrack_expect",
-					sizeof(struct ip_conntrack_expect),
-					0, 0, NULL, NULL);
-	if (!ip_conntrack_expect_cachep) {
-		printk(KERN_ERR "Unable to create ip_expect slab cache\n");
-		goto err_free_conntrack_slab;
-	}
-
-	/* Don't NEED lock here, but good form anyway. */
-	write_lock_bh(&ip_conntrack_lock);
-	for (i = 0; i < MAX_IP_CT_PROTO; i++)
-		rcu_assign_pointer(ip_ct_protos[i], &ip_conntrack_generic_protocol);
-	/* Sew in builtin protocols. */
-	rcu_assign_pointer(ip_ct_protos[IPPROTO_TCP], &ip_conntrack_protocol_tcp);
-	rcu_assign_pointer(ip_ct_protos[IPPROTO_UDP], &ip_conntrack_protocol_udp);
-	rcu_assign_pointer(ip_ct_protos[IPPROTO_ICMP], &ip_conntrack_protocol_icmp);
-	write_unlock_bh(&ip_conntrack_lock);
-
-	/* For use by ipt_REJECT */
-	rcu_assign_pointer(ip_ct_attach, ip_conntrack_attach);
-
-	/* Set up fake conntrack:
-	    - to never be deleted, not in any hashes */
-	atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
-	/*  - and look it like as a confirmed connection */
-	set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
-
-	return ret;
-
-err_free_conntrack_slab:
-	kmem_cache_destroy(ip_conntrack_cachep);
-err_free_hash:
-	free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc,
-			    ip_conntrack_htable_size);
-err_unreg_sockopt:
-	nf_unregister_sockopt(&so_getorigdst);
-
-	return -ENOMEM;
-}
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
deleted file mode 100644
index 1faa68a..0000000
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* FTP extension for IP connection tracking. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/netfilter.h>
-#include <linux/ip.h>
-#include <linux/ctype.h>
-#include <net/checksum.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/moduleparam.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
-MODULE_DESCRIPTION("ftp connection tracking helper");
-
-/* This is slow, but it's simple. --RR */
-static char *ftp_buffer;
-static DEFINE_SPINLOCK(ip_ftp_lock);
-
-#define MAX_PORTS 8
-static unsigned short ports[MAX_PORTS];
-static int ports_c;
-module_param_array(ports, ushort, &ports_c, 0400);
-
-static int loose;
-module_param(loose, bool, 0600);
-
-unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
-				enum ip_conntrack_info ctinfo,
-				enum ip_ct_ftp_type type,
-				unsigned int matchoff,
-				unsigned int matchlen,
-				struct ip_conntrack_expect *exp,
-				u32 *seq);
-EXPORT_SYMBOL_GPL(ip_nat_ftp_hook);
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int try_rfc959(const char *, size_t, u_int32_t [], char);
-static int try_eprt(const char *, size_t, u_int32_t [], char);
-static int try_epsv_response(const char *, size_t, u_int32_t [], char);
-
-static const struct ftp_search {
-	const char *pattern;
-	size_t plen;
-	char skip;
-	char term;
-	enum ip_ct_ftp_type ftptype;
-	int (*getnum)(const char *, size_t, u_int32_t[], char);
-} search[IP_CT_DIR_MAX][2] = {
-	[IP_CT_DIR_ORIGINAL] = {
-		{
-			.pattern	=  "PORT",
-			.plen		= sizeof("PORT") - 1,
-			.skip		= ' ',
-			.term		= '\r',
-			.ftptype	= IP_CT_FTP_PORT,
-			.getnum		= try_rfc959,
-		},
-		{
-			.pattern	= "EPRT",
-			.plen		= sizeof("EPRT") - 1,
-			.skip		= ' ',
-			.term		= '\r',
-			.ftptype	= IP_CT_FTP_EPRT,
-			.getnum		= try_eprt,
-		},
-	},
-	[IP_CT_DIR_REPLY] = {
-		{
-			.pattern	= "227 ",
-			.plen		= sizeof("227 ") - 1,
-			.skip		= '(',
-			.term		= ')',
-			.ftptype	= IP_CT_FTP_PASV,
-			.getnum		= try_rfc959,
-		},
-		{
-			.pattern	= "229 ",
-			.plen		= sizeof("229 ") - 1,
-			.skip		= '(',
-			.term		= ')',
-			.ftptype	= IP_CT_FTP_EPSV,
-			.getnum		= try_epsv_response,
-		},
-	},
-};
-
-static int try_number(const char *data, size_t dlen, u_int32_t array[],
-		      int array_size, char sep, char term)
-{
-	u_int32_t i, len;
-
-	memset(array, 0, sizeof(array[0])*array_size);
-
-	/* Keep data pointing at next char. */
-	for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
-		if (*data >= '0' && *data <= '9') {
-			array[i] = array[i]*10 + *data - '0';
-		}
-		else if (*data == sep)
-			i++;
-		else {
-			/* Unexpected character; true if it's the
-			   terminator and we're finished. */
-			if (*data == term && i == array_size - 1)
-				return len;
-
-			DEBUGP("Char %u (got %u nums) `%u' unexpected\n",
-			       len, i, *data);
-			return 0;
-		}
-	}
-	DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep);
-
-	return 0;
-}
-
-/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
-static int try_rfc959(const char *data, size_t dlen, u_int32_t array[6],
-		       char term)
-{
-	return try_number(data, dlen, array, 6, ',', term);
-}
-
-/* Grab port: number up to delimiter */
-static int get_port(const char *data, int start, size_t dlen, char delim,
-		    u_int32_t array[2])
-{
-	u_int16_t port = 0;
-	int i;
-
-	for (i = start; i < dlen; i++) {
-		/* Finished? */
-		if (data[i] == delim) {
-			if (port == 0)
-				break;
-			array[0] = port >> 8;
-			array[1] = port;
-			return i + 1;
-		}
-		else if (data[i] >= '0' && data[i] <= '9')
-			port = port*10 + data[i] - '0';
-		else /* Some other crap */
-			break;
-	}
-	return 0;
-}
-
-/* Returns 0, or length of numbers: |1|132.235.1.2|6275| */
-static int try_eprt(const char *data, size_t dlen, u_int32_t array[6],
-		    char term)
-{
-	char delim;
-	int length;
-
-	/* First character is delimiter, then "1" for IPv4, then
-	   delimiter again. */
-	if (dlen <= 3) return 0;
-	delim = data[0];
-	if (isdigit(delim) || delim < 33 || delim > 126
-	    || data[1] != '1' || data[2] != delim)
-		return 0;
-
-	DEBUGP("EPRT: Got |1|!\n");
-	/* Now we have IP address. */
-	length = try_number(data + 3, dlen - 3, array, 4, '.', delim);
-	if (length == 0)
-		return 0;
-
-	DEBUGP("EPRT: Got IP address!\n");
-	/* Start offset includes initial "|1|", and trailing delimiter */
-	return get_port(data, 3 + length + 1, dlen, delim, array+4);
-}
-
-/* Returns 0, or length of numbers: |||6446| */
-static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6],
-			     char term)
-{
-	char delim;
-
-	/* Three delimiters. */
-	if (dlen <= 3) return 0;
-	delim = data[0];
-	if (isdigit(delim) || delim < 33 || delim > 126
-	    || data[1] != delim || data[2] != delim)
-		return 0;
-
-	return get_port(data, 3, dlen, delim, array+4);
-}
-
-/* Return 1 for match, 0 for accept, -1 for partial. */
-static int find_pattern(const char *data, size_t dlen,
-			const char *pattern, size_t plen,
-			char skip, char term,
-			unsigned int *numoff,
-			unsigned int *numlen,
-			u_int32_t array[6],
-			int (*getnum)(const char *, size_t, u_int32_t[], char))
-{
-	size_t i;
-
-	DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
-	if (dlen == 0)
-		return 0;
-
-	if (dlen <= plen) {
-		/* Short packet: try for partial? */
-		if (strnicmp(data, pattern, dlen) == 0)
-			return -1;
-		else return 0;
-	}
-
-	if (strnicmp(data, pattern, plen) != 0) {
-#if 0
-		size_t i;
-
-		DEBUGP("ftp: string mismatch\n");
-		for (i = 0; i < plen; i++) {
-			DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
-				i, data[i], data[i],
-				pattern[i], pattern[i]);
-		}
-#endif
-		return 0;
-	}
-
-	DEBUGP("Pattern matches!\n");
-	/* Now we've found the constant string, try to skip
-	   to the 'skip' character */
-	for (i = plen; data[i] != skip; i++)
-		if (i == dlen - 1) return -1;
-
-	/* Skip over the last character */
-	i++;
-
-	DEBUGP("Skipped up to `%c'!\n", skip);
-
-	*numoff = i;
-	*numlen = getnum(data + i, dlen - i, array, term);
-	if (!*numlen)
-		return -1;
-
-	DEBUGP("Match succeeded!\n");
-	return 1;
-}
-
-/* Look up to see if we're just after a \n. */
-static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
-{
-	unsigned int i;
-
-	for (i = 0; i < info->seq_aft_nl_num[dir]; i++)
-		if (info->seq_aft_nl[dir][i] == seq)
-			return 1;
-	return 0;
-}
-
-/* We don't update if it's older than what we have. */
-static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir,
-			  struct sk_buff *skb)
-{
-	unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
-
-	/* Look for oldest: if we find exact match, we're done. */
-	for (i = 0; i < info->seq_aft_nl_num[dir]; i++) {
-		if (info->seq_aft_nl[dir][i] == nl_seq)
-			return;
-
-		if (oldest == info->seq_aft_nl_num[dir]
-		    || before(info->seq_aft_nl[dir][i], oldest))
-			oldest = i;
-	}
-
-	if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
-		info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
-		ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
-	} else if (oldest != NUM_SEQ_TO_REMEMBER) {
-		info->seq_aft_nl[dir][oldest] = nl_seq;
-		ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
-	}
-}
-
-static int help(struct sk_buff **pskb,
-		struct ip_conntrack *ct,
-		enum ip_conntrack_info ctinfo)
-{
-	unsigned int dataoff, datalen;
-	struct tcphdr _tcph, *th;
-	char *fb_ptr;
-	int ret;
-	u32 seq, array[6] = { 0 };
-	int dir = CTINFO2DIR(ctinfo);
-	unsigned int matchlen, matchoff;
-	struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
-	struct ip_conntrack_expect *exp;
-	unsigned int i;
-	int found = 0, ends_in_nl;
-	typeof(ip_nat_ftp_hook) ip_nat_ftp;
-
-	/* Until there's been traffic both ways, don't look in packets. */
-	if (ctinfo != IP_CT_ESTABLISHED
-	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
-		DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo);
-		return NF_ACCEPT;
-	}
-
-	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		return NF_ACCEPT;
-
-	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
-	/* No data? */
-	if (dataoff >= (*pskb)->len) {
-		DEBUGP("ftp: pskblen = %u\n", (*pskb)->len);
-		return NF_ACCEPT;
-	}
-	datalen = (*pskb)->len - dataoff;
-
-	spin_lock_bh(&ip_ftp_lock);
-	fb_ptr = skb_header_pointer(*pskb, dataoff,
-				    (*pskb)->len - dataoff, ftp_buffer);
-	BUG_ON(fb_ptr == NULL);
-
-	ends_in_nl = (fb_ptr[datalen - 1] == '\n');
-	seq = ntohl(th->seq) + datalen;
-
-	/* Look up to see if we're just after a \n. */
-	if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
-		/* Now if this ends in \n, update ftp info. */
-		DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n",
-		       ct_ftp_info->seq_aft_nl[0][dir]
-		       old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
-		ret = NF_ACCEPT;
-		goto out_update_nl;
-	}
-
-	/* Initialize IP array to expected address (it's not mentioned
-	   in EPSV responses) */
-	array[0] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 24) & 0xFF;
-	array[1] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 16) & 0xFF;
-	array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF;
-	array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF;
-
-	for (i = 0; i < ARRAY_SIZE(search[dir]); i++) {
-		found = find_pattern(fb_ptr, (*pskb)->len - dataoff,
-				     search[dir][i].pattern,
-				     search[dir][i].plen,
-				     search[dir][i].skip,
-				     search[dir][i].term,
-				     &matchoff, &matchlen,
-				     array,
-				     search[dir][i].getnum);
-		if (found) break;
-	}
-	if (found == -1) {
-		/* We don't usually drop packets.  After all, this is
-		   connection tracking, not packet filtering.
-		   However, it is necessary for accurate tracking in
-		   this case. */
-		if (net_ratelimit())
-			printk("conntrack_ftp: partial %s %u+%u\n",
-			       search[dir][i].pattern,
-			       ntohl(th->seq), datalen);
-		ret = NF_DROP;
-		goto out;
-	} else if (found == 0) { /* No match */
-		ret = NF_ACCEPT;
-		goto out_update_nl;
-	}
-
-	DEBUGP("conntrack_ftp: match `%s' (%u bytes at %u)\n",
-	       fb_ptr + matchoff, matchlen, ntohl(th->seq) + matchoff);
-
-	/* Allocate expectation which will be inserted */
-	exp = ip_conntrack_expect_alloc(ct);
-	if (exp == NULL) {
-		ret = NF_DROP;
-		goto out;
-	}
-
-	/* We refer to the reverse direction ("!dir") tuples here,
-	 * because we're expecting something in the other direction.
-	 * Doesn't matter unless NAT is happening.  */
-	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
-
-	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
-	    != ct->tuplehash[dir].tuple.src.ip) {
-		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
-		   server: it really wants us to connect to a
-		   different IP address.  Simply don't record it for
-		   NAT. */
-		DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
-		       array[0], array[1], array[2], array[3],
-		       NIPQUAD(ct->tuplehash[dir].tuple.src.ip));
-
-		/* Thanks to Cristiano Lincoln Mattos
-		   <lincoln@cesar.org.br> for reporting this potential
-		   problem (DMZ machines opening holes to internal
-		   networks, or the packet filter itself). */
-		if (!loose) {
-			ret = NF_ACCEPT;
-			goto out_put_expect;
-		}
-		exp->tuple.dst.ip = htonl((array[0] << 24) | (array[1] << 16)
-					 | (array[2] << 8) | array[3]);
-	}
-
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.dst.u.tcp.port = htons(array[4] << 8 | array[5]);
-	exp->tuple.src.u.tcp.port = 0; /* Don't care. */
-	exp->tuple.dst.protonum = IPPROTO_TCP;
-	exp->mask = ((struct ip_conntrack_tuple)
-		{ { htonl(0xFFFFFFFF), { 0 } },
-		  { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }});
-
-	exp->expectfn = NULL;
-	exp->flags = 0;
-
-	/* Now, NAT might want to mangle the packet, and register the
-	 * (possibly changed) expectation itself. */
-	ip_nat_ftp = rcu_dereference(ip_nat_ftp_hook);
-	if (ip_nat_ftp)
-		ret = ip_nat_ftp(pskb, ctinfo, search[dir][i].ftptype,
-				 matchoff, matchlen, exp, &seq);
-	else {
-		/* Can't expect this?  Best to drop packet now. */
-		if (ip_conntrack_expect_related(exp) != 0)
-			ret = NF_DROP;
-		else
-			ret = NF_ACCEPT;
-	}
-
-out_put_expect:
-	ip_conntrack_expect_put(exp);
-
-out_update_nl:
-	/* Now if this ends in \n, update ftp info.  Seq may have been
-	 * adjusted by NAT code. */
-	if (ends_in_nl)
-		update_nl_seq(seq, ct_ftp_info,dir, *pskb);
- out:
-	spin_unlock_bh(&ip_ftp_lock);
-	return ret;
-}
-
-static struct ip_conntrack_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][sizeof("ftp-65535")];
-
-/* Not __exit: called from init() */
-static void ip_conntrack_ftp_fini(void)
-{
-	int i;
-	for (i = 0; i < ports_c; i++) {
-		DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
-				ports[i]);
-		ip_conntrack_helper_unregister(&ftp[i]);
-	}
-
-	kfree(ftp_buffer);
-}
-
-static int __init ip_conntrack_ftp_init(void)
-{
-	int i, ret;
-	char *tmpname;
-
-	ftp_buffer = kmalloc(65536, GFP_KERNEL);
-	if (!ftp_buffer)
-		return -ENOMEM;
-
-	if (ports_c == 0)
-		ports[ports_c++] = FTP_PORT;
-
-	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 = htons(0xFFFF);
-		ftp[i].mask.dst.protonum = 0xFF;
-		ftp[i].max_expected = 1;
-		ftp[i].timeout = 5 * 60; /* 5 minutes */
-		ftp[i].me = THIS_MODULE;
-		ftp[i].help = help;
-
-		tmpname = &ftp_names[i][0];
-		if (ports[i] == FTP_PORT)
-			sprintf(tmpname, "ftp");
-		else
-			sprintf(tmpname, "ftp-%d", ports[i]);
-		ftp[i].name = tmpname;
-
-		DEBUGP("ip_ct_ftp: registering helper for port %d\n",
-				ports[i]);
-		ret = ip_conntrack_helper_register(&ftp[i]);
-
-		if (ret) {
-			ip_conntrack_ftp_fini();
-			return ret;
-		}
-	}
-	return 0;
-}
-
-module_init(ip_conntrack_ftp_init);
-module_exit(ip_conntrack_ftp_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
deleted file mode 100644
index 53eb365..0000000
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ /dev/null
@@ -1,1841 +0,0 @@
-/*
- * H.323 connection tracking helper
- *
- * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
- *
- * This source code is licensed under General Public License version 2.
- *
- * Based on the 'brute force' H.323 connection tracking module by
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- * For more information, please see http://nath323.sourceforge.net/
- */
-
-#include <linux/module.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <net/tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
-#include <linux/moduleparam.h>
-#include <linux/ctype.h>
-#include <linux/inet.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/* Parameters */
-static unsigned int default_rrq_ttl = 300;
-module_param(default_rrq_ttl, uint, 0600);
-MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ");
-
-static int gkrouted_only = 1;
-module_param(gkrouted_only, int, 0600);
-MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
-
-static int callforward_filter = 1;
-module_param(callforward_filter, bool, 0600);
-MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "
-				     "if both endpoints are on different sides "
-				     "(determined by routing information)");
-
-/* Hooks for NAT */
-int (*set_h245_addr_hook) (struct sk_buff ** pskb,
-			   unsigned char **data, int dataoff,
-			   H245_TransportAddress * addr,
-			   __be32 ip, u_int16_t port);
-int (*set_h225_addr_hook) (struct sk_buff ** pskb,
-			   unsigned char **data, int dataoff,
-			   TransportAddress * addr,
-			   __be32 ip, u_int16_t port);
-int (*set_sig_addr_hook) (struct sk_buff ** pskb,
-			  struct ip_conntrack * ct,
-			  enum ip_conntrack_info ctinfo,
-			  unsigned char **data,
-			  TransportAddress * addr, int count);
-int (*set_ras_addr_hook) (struct sk_buff ** pskb,
-			  struct ip_conntrack * ct,
-			  enum ip_conntrack_info ctinfo,
-			  unsigned char **data,
-			  TransportAddress * addr, int count);
-int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
-			  struct ip_conntrack * ct,
-			  enum ip_conntrack_info ctinfo,
-			  unsigned char **data, int dataoff,
-			  H245_TransportAddress * addr,
-			  u_int16_t port, u_int16_t rtp_port,
-			  struct ip_conntrack_expect * rtp_exp,
-			  struct ip_conntrack_expect * rtcp_exp);
-int (*nat_t120_hook) (struct sk_buff ** pskb,
-		      struct ip_conntrack * ct,
-		      enum ip_conntrack_info ctinfo,
-		      unsigned char **data, int dataoff,
-		      H245_TransportAddress * addr, u_int16_t port,
-		      struct ip_conntrack_expect * exp);
-int (*nat_h245_hook) (struct sk_buff ** pskb,
-		      struct ip_conntrack * ct,
-		      enum ip_conntrack_info ctinfo,
-		      unsigned char **data, int dataoff,
-		      TransportAddress * addr, u_int16_t port,
-		      struct ip_conntrack_expect * exp);
-int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
-				struct ip_conntrack * ct,
-				enum ip_conntrack_info ctinfo,
-				unsigned char **data, int dataoff,
-				TransportAddress * addr, u_int16_t port,
-				struct ip_conntrack_expect * exp);
-int (*nat_q931_hook) (struct sk_buff ** pskb,
-		      struct ip_conntrack * ct,
-		      enum ip_conntrack_info ctinfo,
-		      unsigned char **data, TransportAddress * addr, int idx,
-		      u_int16_t port, struct ip_conntrack_expect * exp);
-
-
-static DEFINE_SPINLOCK(ip_h323_lock);
-static char *h323_buffer;
-
-/****************************************************************************/
-static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned char **data, int *datalen, int *dataoff)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	struct tcphdr _tcph, *th;
-	int tcpdatalen;
-	int tcpdataoff;
-	unsigned char *tpkt;
-	int tpktlen;
-	int tpktoff;
-
-	/* Get TCP header */
-	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		return 0;
-
-	/* Get TCP data offset */
-	tcpdataoff = (*pskb)->nh.iph->ihl * 4 + th->doff * 4;
-
-	/* Get TCP data length */
-	tcpdatalen = (*pskb)->len - tcpdataoff;
-	if (tcpdatalen <= 0)	/* No TCP data */
-		goto clear_out;
-
-	if (*data == NULL) {	/* first TPKT */
-		/* Get first TPKT pointer */
-		tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen,
-					  h323_buffer);
-		BUG_ON(tpkt == NULL);
-
-		/* Validate TPKT identifier */
-		if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {
-			/* Netmeeting sends TPKT header and data separately */
-			if (info->tpkt_len[dir] > 0) {
-				DEBUGP("ip_ct_h323: previous packet "
-				       "indicated separate TPKT data of %hu "
-				       "bytes\n", info->tpkt_len[dir]);
-				if (info->tpkt_len[dir] <= tcpdatalen) {
-					/* Yes, there was a TPKT header
-					 * received */
-					*data = tpkt;
-					*datalen = info->tpkt_len[dir];
-					*dataoff = 0;
-					goto out;
-				}
-
-				/* Fragmented TPKT */
-				if (net_ratelimit())
-					printk("ip_ct_h323: "
-					       "fragmented TPKT\n");
-				goto clear_out;
-			}
-
-			/* It is not even a TPKT */
-			return 0;
-		}
-		tpktoff = 0;
-	} else {		/* Next TPKT */
-		tpktoff = *dataoff + *datalen;
-		tcpdatalen -= tpktoff;
-		if (tcpdatalen <= 4)	/* No more TPKT */
-			goto clear_out;
-		tpkt = *data + *datalen;
-
-		/* Validate TPKT identifier */
-		if (tpkt[0] != 0x03 || tpkt[1] != 0)
-			goto clear_out;
-	}
-
-	/* Validate TPKT length */
-	tpktlen = tpkt[2] * 256 + tpkt[3];
-	if (tpktlen < 4)
-		goto clear_out;
-	if (tpktlen > tcpdatalen) {
-		if (tcpdatalen == 4) {	/* Separate TPKT header */
-			/* Netmeeting sends TPKT header and data separately */
-			DEBUGP("ip_ct_h323: separate TPKT header indicates "
-			       "there will be TPKT data of %hu bytes\n",
-			       tpktlen - 4);
-			info->tpkt_len[dir] = tpktlen - 4;
-			return 0;
-		}
-
-		if (net_ratelimit())
-			printk("ip_ct_h323: incomplete TPKT (fragmented?)\n");
-		goto clear_out;
-	}
-
-	/* This is the encapsulated data */
-	*data = tpkt + 4;
-	*datalen = tpktlen - 4;
-	*dataoff = tpktoff + 4;
-
-      out:
-	/* Clear TPKT length */
-	info->tpkt_len[dir] = 0;
-	return 1;
-
-      clear_out:
-	info->tpkt_len[dir] = 0;
-	return 0;
-}
-
-/****************************************************************************/
-static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
-			 __be32 * ip, u_int16_t * port)
-{
-	unsigned char *p;
-
-	if (addr->choice != eH245_TransportAddress_unicastAddress ||
-	    addr->unicastAddress.choice != eUnicastAddress_iPAddress)
-		return 0;
-
-	p = data + addr->unicastAddress.iPAddress.network;
-	*ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
-	*port = (p[4] << 8) | (p[5]);
-
-	return 1;
-}
-
-/****************************************************************************/
-static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
-			   enum ip_conntrack_info ctinfo,
-			   unsigned char **data, int dataoff,
-			   H245_TransportAddress * addr)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	u_int16_t rtp_port;
-	struct ip_conntrack_expect *rtp_exp;
-	struct ip_conntrack_expect *rtcp_exp;
-	typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
-
-	/* Read RTP or RTCP address */
-	if (!get_h245_addr(*data, addr, &ip, &port) ||
-	    ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
-		return 0;
-
-	/* RTP port is even */
-	rtp_port = port & (~1);
-
-	/* Create expect for RTP */
-	if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	rtp_exp->tuple.src.u.udp.port = 0;
-	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 = htonl(0xFFFFFFFF);
-	rtp_exp->mask.src.u.udp.port = 0;
-	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;
-
-	/* Create expect for RTCP */
-	if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) {
-		ip_conntrack_expect_put(rtp_exp);
-		return -1;
-	}
-	rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	rtcp_exp->tuple.src.u.udp.port = 0;
-	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 = htonl(0xFFFFFFFF);
-	rtcp_exp->mask.src.u.udp.port = 0;
-	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;
-
-	if (ct->tuplehash[dir].tuple.src.ip !=
-	    ct->tuplehash[!dir].tuple.dst.ip &&
-	    (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook))) {
-		/* NAT needed */
-		ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
-				   addr, port, rtp_port, rtp_exp, rtcp_exp);
-	} else {		/* Conntrack only */
-		rtp_exp->expectfn = NULL;
-		rtcp_exp->expectfn = NULL;
-
-		if (ip_conntrack_expect_related(rtp_exp) == 0) {
-			if (ip_conntrack_expect_related(rtcp_exp) == 0) {
-				DEBUGP("ip_ct_h323: expect RTP "
-				       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-				       NIPQUAD(rtp_exp->tuple.src.ip),
-				       ntohs(rtp_exp->tuple.src.u.udp.port),
-				       NIPQUAD(rtp_exp->tuple.dst.ip),
-				       ntohs(rtp_exp->tuple.dst.u.udp.port));
-				DEBUGP("ip_ct_h323: expect RTCP "
-				       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-				       NIPQUAD(rtcp_exp->tuple.src.ip),
-				       ntohs(rtcp_exp->tuple.src.u.udp.port),
-				       NIPQUAD(rtcp_exp->tuple.dst.ip),
-				       ntohs(rtcp_exp->tuple.dst.u.udp.port));
-			} else {
-				ip_conntrack_unexpect_related(rtp_exp);
-				ret = -1;
-			}
-		} else
-			ret = -1;
-	}
-
-	ip_conntrack_expect_put(rtp_exp);
-	ip_conntrack_expect_put(rtcp_exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int expect_t120(struct sk_buff **pskb,
-		       struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, int dataoff,
-		       H245_TransportAddress * addr)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp = NULL;
-	typeof(nat_t120_hook) nat_t120;
-
-	/* Read T.120 address */
-	if (!get_h245_addr(*data, addr, &ip, &port) ||
-	    ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
-		return 0;
-
-	/* Create expect for T.120 connections */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	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 = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	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 */
-
-	if (ct->tuplehash[dir].tuple.src.ip !=
-	    ct->tuplehash[!dir].tuple.dst.ip &&
-	    (nat_t120 = rcu_dereference(nat_t120_hook))) {
-		/* NAT needed */
-		ret = nat_t120(pskb, ct, ctinfo, data, dataoff, addr,
-			       port, exp);
-	} else {		/* Conntrack only */
-		exp->expectfn = NULL;
-		if (ip_conntrack_expect_related(exp) == 0) {
-			DEBUGP("ip_ct_h323: expect T.120 "
-			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-			       NIPQUAD(exp->tuple.src.ip),
-			       ntohs(exp->tuple.src.u.tcp.port),
-			       NIPQUAD(exp->tuple.dst.ip),
-			       ntohs(exp->tuple.dst.u.tcp.port));
-		} else
-			ret = -1;
-	}
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_h245_channel(struct sk_buff **pskb,
-				struct ip_conntrack *ct,
-				enum ip_conntrack_info ctinfo,
-				unsigned char **data, int dataoff,
-				H2250LogicalChannelParameters * channel)
-{
-	int ret;
-
-	if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
-		/* RTP */
-		ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
-				      &channel->mediaChannel);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (channel->
-	    options & eH2250LogicalChannelParameters_mediaControlChannel) {
-		/* RTCP */
-		ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
-				      &channel->mediaControlChannel);
-		if (ret < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, int dataoff,
-		       OpenLogicalChannel * olc)
-{
-	int ret;
-
-	DEBUGP("ip_ct_h323: OpenLogicalChannel\n");
-
-	if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==
-	    eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
-	{
-		ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
-					   &olc->
-					   forwardLogicalChannelParameters.
-					   multiplexParameters.
-					   h2250LogicalChannelParameters);
-		if (ret < 0)
-			return -1;
-	}
-
-	if ((olc->options &
-	     eOpenLogicalChannel_reverseLogicalChannelParameters) &&
-	    (olc->reverseLogicalChannelParameters.options &
-	     eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters)
-	    && (olc->reverseLogicalChannelParameters.multiplexParameters.
-		choice ==
-		eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
-	{
-		ret =
-		    process_h245_channel(pskb, ct, ctinfo, data, dataoff,
-					 &olc->
-					 reverseLogicalChannelParameters.
-					 multiplexParameters.
-					 h2250LogicalChannelParameters);
-		if (ret < 0)
-			return -1;
-	}
-
-	if ((olc->options & eOpenLogicalChannel_separateStack) &&
-	    olc->forwardLogicalChannelParameters.dataType.choice ==
-	    eDataType_data &&
-	    olc->forwardLogicalChannelParameters.dataType.data.application.
-	    choice == eDataApplicationCapability_application_t120 &&
-	    olc->forwardLogicalChannelParameters.dataType.data.application.
-	    t120.choice == eDataProtocolCapability_separateLANStack &&
-	    olc->separateStack.networkAddress.choice ==
-	    eNetworkAccessParameters_networkAddress_localAreaAddress) {
-		ret = expect_t120(pskb, ct, ctinfo, data, dataoff,
-				  &olc->separateStack.networkAddress.
-				  localAreaAddress);
-		if (ret < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data, int dataoff,
-			OpenLogicalChannelAck * olca)
-{
-	H2250LogicalChannelAckParameters *ack;
-	int ret;
-
-	DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n");
-
-	if ((olca->options &
-	     eOpenLogicalChannelAck_reverseLogicalChannelParameters) &&
-	    (olca->reverseLogicalChannelParameters.options &
-	     eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters)
-	    && (olca->reverseLogicalChannelParameters.multiplexParameters.
-		choice ==
-		eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
-	{
-		ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
-					   &olca->
-					   reverseLogicalChannelParameters.
-					   multiplexParameters.
-					   h2250LogicalChannelParameters);
-		if (ret < 0)
-			return -1;
-	}
-
-	if ((olca->options &
-	     eOpenLogicalChannelAck_forwardMultiplexAckParameters) &&
-	    (olca->forwardMultiplexAckParameters.choice ==
-	     eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters))
-	{
-		ack = &olca->forwardMultiplexAckParameters.
-		    h2250LogicalChannelAckParameters;
-		if (ack->options &
-		    eH2250LogicalChannelAckParameters_mediaChannel) {
-			/* RTP */
-			ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
-					      &ack->mediaChannel);
-			if (ret < 0)
-				return -1;
-		}
-
-		if (ack->options &
-		    eH2250LogicalChannelAckParameters_mediaControlChannel) {
-			/* RTCP */
-			ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
-					      &ack->mediaControlChannel);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data, int dataoff,
-			MultimediaSystemControlMessage * mscm)
-{
-	switch (mscm->choice) {
-	case eMultimediaSystemControlMessage_request:
-		if (mscm->request.choice ==
-		    eRequestMessage_openLogicalChannel) {
-			return process_olc(pskb, ct, ctinfo, data, dataoff,
-					   &mscm->request.openLogicalChannel);
-		}
-		DEBUGP("ip_ct_h323: H.245 Request %d\n",
-		       mscm->request.choice);
-		break;
-	case eMultimediaSystemControlMessage_response:
-		if (mscm->response.choice ==
-		    eResponseMessage_openLogicalChannelAck) {
-			return process_olca(pskb, ct, ctinfo, data, dataoff,
-					    &mscm->response.
-					    openLogicalChannelAck);
-		}
-		DEBUGP("ip_ct_h323: H.245 Response %d\n",
-		       mscm->response.choice);
-		break;
-	default:
-		DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice);
-		break;
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct,
-		     enum ip_conntrack_info ctinfo)
-{
-	static MultimediaSystemControlMessage mscm;
-	unsigned char *data = NULL;
-	int datalen;
-	int dataoff;
-	int ret;
-
-	/* Until there's been traffic both ways, don't look in packets. */
-	if (ctinfo != IP_CT_ESTABLISHED
-	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
-		return NF_ACCEPT;
-	}
-	DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len);
-
-	spin_lock_bh(&ip_h323_lock);
-
-	/* Process each TPKT */
-	while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
-		DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
-		       NIPQUAD((*pskb)->nh.iph->saddr),
-		       NIPQUAD((*pskb)->nh.iph->daddr), datalen);
-
-		/* Decode H.245 signal */
-		ret = DecodeMultimediaSystemControlMessage(data, datalen,
-							   &mscm);
-		if (ret < 0) {
-			if (net_ratelimit())
-				printk("ip_ct_h245: decoding error: %s\n",
-				       ret == H323_ERROR_BOUND ?
-				       "out of bound" : "out of range");
-			/* We don't drop when decoding error */
-			break;
-		}
-
-		/* Process H.245 signal */
-		if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0)
-			goto drop;
-	}
-
-	spin_unlock_bh(&ip_h323_lock);
-	return NF_ACCEPT;
-
-      drop:
-	spin_unlock_bh(&ip_h323_lock);
-	if (net_ratelimit())
-		printk("ip_ct_h245: packet dropped\n");
-	return NF_DROP;
-}
-
-/****************************************************************************/
-static struct ip_conntrack_helper ip_conntrack_helper_h245 = {
-	.name = "H.245",
-	.me = THIS_MODULE,
-	.max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ ,
-	.timeout = 240,
-	.tuple = {.dst = {.protonum = IPPROTO_TCP}},
-	.mask = {.src = {.u = {0xFFFF}},
-		 .dst = {.protonum = 0xFF}},
-	.help = h245_help
-};
-
-/****************************************************************************/
-void ip_conntrack_h245_expect(struct ip_conntrack *new,
-			      struct ip_conntrack_expect *this)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	new->helper = &ip_conntrack_helper_h245;
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-/****************************************************************************/
-int get_h225_addr(unsigned char *data, TransportAddress * addr,
-		  __be32 * ip, u_int16_t * port)
-{
-	unsigned char *p;
-
-	if (addr->choice != eTransportAddress_ipAddress)
-		return 0;
-
-	p = data + addr->ipAddress.ip;
-	*ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
-	*port = (p[4] << 8) | (p[5]);
-
-	return 1;
-}
-
-/****************************************************************************/
-static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, int dataoff,
-		       TransportAddress * addr)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp = NULL;
-	typeof(nat_h245_hook) nat_h245;
-
-	/* Read h245Address */
-	if (!get_h225_addr(*data, addr, &ip, &port) ||
-	    ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
-		return 0;
-
-	/* Create expect for h245 connection */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	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 = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	exp->mask.dst.ip = htonl(0xFFFFFFFF);
-	exp->mask.dst.u.tcp.port = htons(0xFFFF);
-	exp->mask.dst.protonum = 0xFF;
-	exp->flags = 0;
-
-	if (ct->tuplehash[dir].tuple.src.ip !=
-	    ct->tuplehash[!dir].tuple.dst.ip &&
-	    (nat_h245 = rcu_dereference(nat_h245_hook))) {
-		/* NAT needed */
-		ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr,
-			       port, exp);
-	} else {		/* Conntrack only */
-		exp->expectfn = ip_conntrack_h245_expect;
-
-		if (ip_conntrack_expect_related(exp) == 0) {
-			DEBUGP("ip_ct_q931: expect H.245 "
-			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-			       NIPQUAD(exp->tuple.src.ip),
-			       ntohs(exp->tuple.src.u.tcp.port),
-			       NIPQUAD(exp->tuple.dst.ip),
-			       ntohs(exp->tuple.dst.u.tcp.port));
-		} else
-			ret = -1;
-	}
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/* Forwarding declaration */
-void ip_conntrack_q931_expect(struct ip_conntrack *new,
-			      struct ip_conntrack_expect *this);
-
-/****************************************************************************/
-static int expect_callforwarding(struct sk_buff **pskb,
-				 struct ip_conntrack *ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data, int dataoff,
-				 TransportAddress * addr)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp = NULL;
-	typeof(nat_callforwarding_hook) nat_callforwarding;
-
-	/* Read alternativeAddress */
-	if (!get_h225_addr(*data, addr, &ip, &port) || port == 0)
-		return 0;
-
-	/* If the calling party is on the same side of the forward-to party,
-	 * we don't need to track the second call */
-	if (callforward_filter) {
-		struct rtable *rt1, *rt2;
-		struct flowi fl1 = {
-			.fl4_dst = ip,
-		};
-		struct flowi fl2 = {
-			.fl4_dst = ct->tuplehash[!dir].tuple.src.ip,
-		};
-
-		if (ip_route_output_key(&rt1, &fl1) == 0) {
-			if (ip_route_output_key(&rt2, &fl2) == 0) {
-				if (rt1->rt_gateway == rt2->rt_gateway &&
-				    rt1->u.dst.dev  == rt2->u.dst.dev)
-					ret = 1;
-				dst_release(&rt2->u.dst);
-			}
-			dst_release(&rt1->u.dst);
-		}
-		if (ret) {
-			DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
-			return 0;
-		}
-	}
-
-	/* Create expect for the second call leg */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	exp->tuple.dst.ip = ip;
-	exp->tuple.dst.u.tcp.port = htons(port);
-	exp->tuple.dst.protonum = IPPROTO_TCP;
-	exp->mask.src.ip = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	exp->mask.dst.ip = htonl(0xFFFFFFFF);
-	exp->mask.dst.u.tcp.port = htons(0xFFFF);
-	exp->mask.dst.protonum = 0xFF;
-	exp->flags = 0;
-
-	if (ct->tuplehash[dir].tuple.src.ip !=
-	    ct->tuplehash[!dir].tuple.dst.ip &&
-	    (nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) {
-		/* Need NAT */
-		ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff,
-					 addr, port, exp);
-	} else {		/* Conntrack only */
-		exp->expectfn = ip_conntrack_q931_expect;
-
-		if (ip_conntrack_expect_related(exp) == 0) {
-			DEBUGP("ip_ct_q931: expect Call Forwarding "
-			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-			       NIPQUAD(exp->tuple.src.ip),
-			       ntohs(exp->tuple.src.u.tcp.port),
-			       NIPQUAD(exp->tuple.dst.ip),
-			       ntohs(exp->tuple.dst.u.tcp.port));
-		} else
-			ret = -1;
-	}
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned char **data, int dataoff,
-			 Setup_UUIE * setup)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret;
-	int i;
-	__be32 ip;
-	u_int16_t port;
-	typeof(set_h225_addr_hook) set_h225_addr;
-
-	DEBUGP("ip_ct_q931: Setup\n");
-
-	if (setup->options & eSetup_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &setup->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	set_h225_addr = rcu_dereference(set_h225_addr_hook);
-
-	if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
-	    (set_h225_addr) &&
-	    get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) &&
-	    ip != ct->tuplehash[!dir].tuple.src.ip) {
-		DEBUGP("ip_ct_q931: set destCallSignalAddress "
-		       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		       NIPQUAD(ip), port,
-		       NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
-		       ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
-		ret = set_h225_addr(pskb, data, dataoff,
-				    &setup->destCallSignalAddress,
-				    ct->tuplehash[!dir].tuple.src.ip,
-				    ntohs(ct->tuplehash[!dir].tuple.src.
-					  u.tcp.port));
-		if (ret < 0)
-			return -1;
-	}
-
-	if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
-	    (set_h225_addr) &&
-	    get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port)
-	    && ip != ct->tuplehash[!dir].tuple.dst.ip) {
-		DEBUGP("ip_ct_q931: set sourceCallSignalAddress "
-		       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		       NIPQUAD(ip), port,
-		       NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
-		       ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
-		ret = set_h225_addr(pskb, data, dataoff,
-				    &setup->sourceCallSignalAddress,
-				    ct->tuplehash[!dir].tuple.dst.ip,
-				    ntohs(ct->tuplehash[!dir].tuple.dst.
-					  u.tcp.port));
-		if (ret < 0)
-			return -1;
-	}
-
-	if (setup->options & eSetup_UUIE_fastStart) {
-		for (i = 0; i < setup->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &setup->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_callproceeding(struct sk_buff **pskb,
-				  struct ip_conntrack *ct,
-				  enum ip_conntrack_info ctinfo,
-				  unsigned char **data, int dataoff,
-				  CallProceeding_UUIE * callproc)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: CallProceeding\n");
-
-	if (callproc->options & eCallProceeding_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &callproc->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (callproc->options & eCallProceeding_UUIE_fastStart) {
-		for (i = 0; i < callproc->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &callproc->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct,
-			   enum ip_conntrack_info ctinfo,
-			   unsigned char **data, int dataoff,
-			   Connect_UUIE * connect)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: Connect\n");
-
-	if (connect->options & eConnect_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &connect->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (connect->options & eConnect_UUIE_fastStart) {
-		for (i = 0; i < connect->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &connect->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct,
-			    enum ip_conntrack_info ctinfo,
-			    unsigned char **data, int dataoff,
-			    Alerting_UUIE * alert)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: Alerting\n");
-
-	if (alert->options & eAlerting_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &alert->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (alert->options & eAlerting_UUIE_fastStart) {
-		for (i = 0; i < alert->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &alert->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_information(struct sk_buff **pskb,
-			       struct ip_conntrack *ct,
-			       enum ip_conntrack_info ctinfo,
-			       unsigned char **data, int dataoff,
-			       Information_UUIE * info)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: Information\n");
-
-	if (info->options & eInformation_UUIE_fastStart) {
-		for (i = 0; i < info->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &info->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct,
-			    enum ip_conntrack_info ctinfo,
-			    unsigned char **data, int dataoff,
-			    Facility_UUIE * facility)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: Facility\n");
-
-	if (facility->reason.choice == eFacilityReason_callForwarded) {
-		if (facility->options & eFacility_UUIE_alternativeAddress)
-			return expect_callforwarding(pskb, ct, ctinfo, data,
-						     dataoff,
-						     &facility->
-						     alternativeAddress);
-		return 0;
-	}
-
-	if (facility->options & eFacility_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &facility->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (facility->options & eFacility_UUIE_fastStart) {
-		for (i = 0; i < facility->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &facility->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct,
-			    enum ip_conntrack_info ctinfo,
-			    unsigned char **data, int dataoff,
-			    Progress_UUIE * progress)
-{
-	int ret;
-	int i;
-
-	DEBUGP("ip_ct_q931: Progress\n");
-
-	if (progress->options & eProgress_UUIE_h245Address) {
-		ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
-				  &progress->h245Address);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (progress->options & eProgress_UUIE_fastStart) {
-		for (i = 0; i < progress->fastStart.count; i++) {
-			ret = process_olc(pskb, ct, ctinfo, data, dataoff,
-					  &progress->fastStart.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data, int dataoff, Q931 * q931)
-{
-	H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
-	int i;
-	int ret = 0;
-
-	switch (pdu->h323_message_body.choice) {
-	case eH323_UU_PDU_h323_message_body_setup:
-		ret = process_setup(pskb, ct, ctinfo, data, dataoff,
-				    &pdu->h323_message_body.setup);
-		break;
-	case eH323_UU_PDU_h323_message_body_callProceeding:
-		ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff,
-					     &pdu->h323_message_body.
-					     callProceeding);
-		break;
-	case eH323_UU_PDU_h323_message_body_connect:
-		ret = process_connect(pskb, ct, ctinfo, data, dataoff,
-				      &pdu->h323_message_body.connect);
-		break;
-	case eH323_UU_PDU_h323_message_body_alerting:
-		ret = process_alerting(pskb, ct, ctinfo, data, dataoff,
-				       &pdu->h323_message_body.alerting);
-		break;
-	case eH323_UU_PDU_h323_message_body_information:
-		ret = process_information(pskb, ct, ctinfo, data, dataoff,
-					  &pdu->h323_message_body.
-					  information);
-		break;
-	case eH323_UU_PDU_h323_message_body_facility:
-		ret = process_facility(pskb, ct, ctinfo, data, dataoff,
-				       &pdu->h323_message_body.facility);
-		break;
-	case eH323_UU_PDU_h323_message_body_progress:
-		ret = process_progress(pskb, ct, ctinfo, data, dataoff,
-				       &pdu->h323_message_body.progress);
-		break;
-	default:
-		DEBUGP("ip_ct_q931: Q.931 signal %d\n",
-		       pdu->h323_message_body.choice);
-		break;
-	}
-
-	if (ret < 0)
-		return -1;
-
-	if (pdu->options & eH323_UU_PDU_h245Control) {
-		for (i = 0; i < pdu->h245Control.count; i++) {
-			ret = process_h245(pskb, ct, ctinfo, data, dataoff,
-					   &pdu->h245Control.item[i]);
-			if (ret < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct,
-		     enum ip_conntrack_info ctinfo)
-{
-	static Q931 q931;
-	unsigned char *data = NULL;
-	int datalen;
-	int dataoff;
-	int ret;
-
-	/* Until there's been traffic both ways, don't look in packets. */
-	if (ctinfo != IP_CT_ESTABLISHED
-	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
-		return NF_ACCEPT;
-	}
-	DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len);
-
-	spin_lock_bh(&ip_h323_lock);
-
-	/* Process each TPKT */
-	while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
-		DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
-		       NIPQUAD((*pskb)->nh.iph->saddr),
-		       NIPQUAD((*pskb)->nh.iph->daddr), datalen);
-
-		/* Decode Q.931 signal */
-		ret = DecodeQ931(data, datalen, &q931);
-		if (ret < 0) {
-			if (net_ratelimit())
-				printk("ip_ct_q931: decoding error: %s\n",
-				       ret == H323_ERROR_BOUND ?
-				       "out of bound" : "out of range");
-			/* We don't drop when decoding error */
-			break;
-		}
-
-		/* Process Q.931 signal */
-		if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0)
-			goto drop;
-	}
-
-	spin_unlock_bh(&ip_h323_lock);
-	return NF_ACCEPT;
-
-      drop:
-	spin_unlock_bh(&ip_h323_lock);
-	if (net_ratelimit())
-		printk("ip_ct_q931: packet dropped\n");
-	return NF_DROP;
-}
-
-/****************************************************************************/
-static struct ip_conntrack_helper ip_conntrack_helper_q931 = {
-	.name = "Q.931",
-	.me = THIS_MODULE,
-	.max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ ,
-	.timeout = 240,
-	.tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}},
-		  .dst = {.protonum = IPPROTO_TCP}},
-	.mask = {.src = {.u = {0xFFFF}},
-		 .dst = {.protonum = 0xFF}},
-	.help = q931_help
-};
-
-/****************************************************************************/
-void ip_conntrack_q931_expect(struct ip_conntrack *new,
-			      struct ip_conntrack_expect *this)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	new->helper = &ip_conntrack_helper_q931;
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-/****************************************************************************/
-static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen)
-{
-	struct udphdr _uh, *uh;
-	int dataoff;
-
-	uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_uh),
-				&_uh);
-	if (uh == NULL)
-		return NULL;
-	dataoff = (*pskb)->nh.iph->ihl * 4 + sizeof(_uh);
-	if (dataoff >= (*pskb)->len)
-		return NULL;
-	*datalen = (*pskb)->len - dataoff;
-	return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer);
-}
-
-/****************************************************************************/
-static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
-					       __be32 ip, u_int16_t port)
-{
-	struct ip_conntrack_expect *exp;
-	struct ip_conntrack_tuple tuple;
-
-	tuple.src.ip = 0;
-	tuple.src.u.tcp.port = 0;
-	tuple.dst.ip = ip;
-	tuple.dst.u.tcp.port = htons(port);
-	tuple.dst.protonum = IPPROTO_TCP;
-
-	exp = __ip_conntrack_expect_find(&tuple);
-	if (exp && exp->master == ct)
-		return exp;
-	return NULL;
-}
-
-/****************************************************************************/
-static int set_expect_timeout(struct ip_conntrack_expect *exp,
-			      unsigned timeout)
-{
-	if (!exp || !del_timer(&exp->timeout))
-		return 0;
-
-	exp->timeout.expires = jiffies + timeout * HZ;
-	add_timer(&exp->timeout);
-
-	return 1;
-}
-
-/****************************************************************************/
-static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data,
-		       TransportAddress * addr, int count)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	int i;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp;
-	typeof(nat_q931_hook) nat_q931;
-
-	/* Look for the first related address */
-	for (i = 0; i < count; i++) {
-		if (get_h225_addr(*data, &addr[i], &ip, &port) &&
-		    ip == ct->tuplehash[dir].tuple.src.ip && port != 0)
-			break;
-	}
-
-	if (i >= count)		/* Not found */
-		return 0;
-
-	/* Create expect for Q.931 */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = gkrouted_only ?	/* only accept calls from GK? */
-	    ct->tuplehash[!dir].tuple.src.ip : 0;
-	exp->tuple.src.u.tcp.port = 0;
-	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 ? htonl(0xFFFFFFFF) : 0;
-	exp->mask.src.u.tcp.port = 0;
-	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 */
-
-	nat_q931 = rcu_dereference(nat_q931_hook);
-	if (nat_q931) {	/* Need NAT */
-		ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp);
-	} else {		/* Conntrack only */
-		exp->expectfn = ip_conntrack_q931_expect;
-
-		if (ip_conntrack_expect_related(exp) == 0) {
-			DEBUGP("ip_ct_ras: expect Q.931 "
-			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-			       NIPQUAD(exp->tuple.src.ip),
-			       ntohs(exp->tuple.src.u.tcp.port),
-			       NIPQUAD(exp->tuple.dst.ip),
-			       ntohs(exp->tuple.dst.u.tcp.port));
-
-			/* Save port for looking up expect in processing RCF */
-			info->sig_port[dir] = port;
-		} else
-			ret = -1;
-	}
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, GatekeeperRequest * grq)
-{
-	typeof(set_ras_addr_hook) set_ras_addr;
-
-	DEBUGP("ip_ct_ras: GRQ\n");
-
-	set_ras_addr = rcu_dereference(set_ras_addr_hook);
-	if (set_ras_addr)	/* NATed */
-		return set_ras_addr(pskb, ct, ctinfo, data,
-				    &grq->rasAddress, 1);
-	return 0;
-}
-
-/* Declare before using */
-static void ip_conntrack_ras_expect(struct ip_conntrack *new,
-				    struct ip_conntrack_expect *this);
-
-/****************************************************************************/
-static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, GatekeeperConfirm * gcf)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp;
-
-	DEBUGP("ip_ct_ras: GCF\n");
-
-	if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port))
-		return 0;
-
-	/* Registration port is the same as discovery port */
-	if (ip == ct->tuplehash[dir].tuple.src.ip &&
-	    port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port))
-		return 0;
-
-	/* Avoid RAS expectation loops. A GCF is never expected. */
-	if (test_bit(IPS_EXPECTED_BIT, &ct->status))
-		return 0;
-
-	/* Need new expect */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	exp->tuple.dst.ip = ip;
-	exp->tuple.dst.u.tcp.port = htons(port);
-	exp->tuple.dst.protonum = IPPROTO_UDP;
-	exp->mask.src.ip = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	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;
-	if (ip_conntrack_expect_related(exp) == 0) {
-		DEBUGP("ip_ct_ras: expect RAS "
-		       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		       NIPQUAD(exp->tuple.src.ip),
-		       ntohs(exp->tuple.src.u.tcp.port),
-		       NIPQUAD(exp->tuple.dst.ip),
-		       ntohs(exp->tuple.dst.u.tcp.port));
-	} else
-		ret = -1;
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, RegistrationRequest * rrq)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int ret;
-	typeof(set_ras_addr_hook) set_ras_addr;
-
-	DEBUGP("ip_ct_ras: RRQ\n");
-
-	ret = expect_q931(pskb, ct, ctinfo, data,
-			  rrq->callSignalAddress.item,
-			  rrq->callSignalAddress.count);
-	if (ret < 0)
-		return -1;
-
-	set_ras_addr = rcu_dereference(set_ras_addr_hook);
-	if (set_ras_addr) {
-		ret = set_ras_addr(pskb, ct, ctinfo, data,
-				   rrq->rasAddress.item,
-				   rrq->rasAddress.count);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (rrq->options & eRegistrationRequest_timeToLive) {
-		DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
-		info->timeout = rrq->timeToLive;
-	} else
-		info->timeout = default_rrq_ttl;
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, RegistrationConfirm * rcf)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	int ret;
-	struct ip_conntrack_expect *exp;
-	typeof(set_sig_addr_hook) set_sig_addr;
-
-	DEBUGP("ip_ct_ras: RCF\n");
-
-	set_sig_addr = rcu_dereference(set_sig_addr_hook);
-	if (set_sig_addr) {
-		ret = set_sig_addr(pskb, ct, ctinfo, data,
-				   rcf->callSignalAddress.item,
-				   rcf->callSignalAddress.count);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (rcf->options & eRegistrationConfirm_timeToLive) {
-		DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
-		info->timeout = rcf->timeToLive;
-	}
-
-	if (info->timeout > 0) {
-		DEBUGP
-		    ("ip_ct_ras: set RAS connection timeout to %u seconds\n",
-		     info->timeout);
-		ip_ct_refresh(ct, *pskb, info->timeout * HZ);
-
-		/* Set expect timeout */
-		read_lock_bh(&ip_conntrack_lock);
-		exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip,
-				  info->sig_port[!dir]);
-		if (exp) {
-			DEBUGP("ip_ct_ras: set Q.931 expect "
-			       "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) "
-			       "timeout to %u seconds\n",
-			       NIPQUAD(exp->tuple.src.ip),
-			       ntohs(exp->tuple.src.u.tcp.port),
-			       NIPQUAD(exp->tuple.dst.ip),
-			       ntohs(exp->tuple.dst.u.tcp.port),
-			       info->timeout);
-			set_expect_timeout(exp, info->timeout);
-		}
-		read_unlock_bh(&ip_conntrack_lock);
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, UnregistrationRequest * urq)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	int ret;
-	typeof(set_sig_addr_hook) set_sig_addr;
-
-	DEBUGP("ip_ct_ras: URQ\n");
-
-	set_sig_addr = rcu_dereference(set_sig_addr_hook);
-	if (set_sig_addr) {
-		ret = set_sig_addr(pskb, ct, ctinfo, data,
-				   urq->callSignalAddress.item,
-				   urq->callSignalAddress.count);
-		if (ret < 0)
-			return -1;
-	}
-
-	/* Clear old expect */
-	ip_ct_remove_expectations(ct);
-	info->sig_port[dir] = 0;
-	info->sig_port[!dir] = 0;
-
-	/* Give it 30 seconds for UCF or URJ */
-	ip_ct_refresh(ct, *pskb, 30 * HZ);
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, AdmissionRequest * arq)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	__be32 ip;
-	u_int16_t port;
-	typeof(set_h225_addr_hook) set_h225_addr;
-
-	DEBUGP("ip_ct_ras: ARQ\n");
-
-	set_h225_addr = rcu_dereference(set_h225_addr_hook);
-	if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
-	    get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) &&
-	    ip == ct->tuplehash[dir].tuple.src.ip &&
-	    port == info->sig_port[dir] && set_h225_addr) {
-		/* Answering ARQ */
-		return set_h225_addr(pskb, data, 0,
-				     &arq->destCallSignalAddress,
-				     ct->tuplehash[!dir].tuple.dst.ip,
-				     info->sig_port[!dir]);
-	}
-
-	if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
-	    get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) &&
-	    ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) {
-		/* Calling ARQ */
-		return set_h225_addr(pskb, data, 0,
-				     &arq->srcCallSignalAddress,
-				     ct->tuplehash[!dir].tuple.dst.ip,
-				     port);
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, AdmissionConfirm * acf)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp;
-	typeof(set_sig_addr_hook) set_sig_addr;
-
-	DEBUGP("ip_ct_ras: ACF\n");
-
-	if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port))
-		return 0;
-
-	if (ip == ct->tuplehash[dir].tuple.dst.ip) {	/* Answering ACF */
-		set_sig_addr = rcu_dereference(set_sig_addr_hook);
-		if (set_sig_addr)
-			return set_sig_addr(pskb, ct, ctinfo, data,
-					    &acf->destCallSignalAddress, 1);
-		return 0;
-	}
-
-	/* Need new expect */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	exp->tuple.dst.ip = ip;
-	exp->tuple.dst.u.tcp.port = htons(port);
-	exp->tuple.dst.protonum = IPPROTO_TCP;
-	exp->mask.src.ip = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	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;
-
-	if (ip_conntrack_expect_related(exp) == 0) {
-		DEBUGP("ip_ct_ras: expect Q.931 "
-		       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		       NIPQUAD(exp->tuple.src.ip),
-		       ntohs(exp->tuple.src.u.tcp.port),
-		       NIPQUAD(exp->tuple.dst.ip),
-		       ntohs(exp->tuple.dst.u.tcp.port));
-	} else
-		ret = -1;
-
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, LocationRequest * lrq)
-{
-	typeof(set_ras_addr_hook) set_ras_addr;
-
-	DEBUGP("ip_ct_ras: LRQ\n");
-
-	set_ras_addr = rcu_dereference(set_ras_addr_hook);
-	if (set_ras_addr)
-		return set_ras_addr(pskb, ct, ctinfo, data,
-				    &lrq->replyAddress, 1);
-	return 0;
-}
-
-/****************************************************************************/
-static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, LocationConfirm * lcf)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int ret = 0;
-	__be32 ip;
-	u_int16_t port;
-	struct ip_conntrack_expect *exp = NULL;
-
-	DEBUGP("ip_ct_ras: LCF\n");
-
-	if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port))
-		return 0;
-
-	/* Need new expect for call signal */
-	if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
-		return -1;
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.tcp.port = 0;
-	exp->tuple.dst.ip = ip;
-	exp->tuple.dst.u.tcp.port = htons(port);
-	exp->tuple.dst.protonum = IPPROTO_TCP;
-	exp->mask.src.ip = htonl(0xFFFFFFFF);
-	exp->mask.src.u.tcp.port = 0;
-	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;
-
-	if (ip_conntrack_expect_related(exp) == 0) {
-		DEBUGP("ip_ct_ras: expect Q.931 "
-		       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-		       NIPQUAD(exp->tuple.src.ip),
-		       ntohs(exp->tuple.src.u.tcp.port),
-		       NIPQUAD(exp->tuple.dst.ip),
-		       ntohs(exp->tuple.dst.u.tcp.port));
-	} else
-		ret = -1;
-
-	ip_conntrack_expect_put(exp);
-
-	/* Ignore rasAddress */
-
-	return ret;
-}
-
-/****************************************************************************/
-static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, InfoRequestResponse * irr)
-{
-	int ret;
-	typeof(set_ras_addr_hook) set_ras_addr;
-	typeof(set_sig_addr_hook) set_sig_addr;
-
-	DEBUGP("ip_ct_ras: IRR\n");
-
-	set_ras_addr = rcu_dereference(set_ras_addr_hook);
-	if (set_ras_addr) {
-		ret = set_ras_addr(pskb, ct, ctinfo, data,
-				   &irr->rasAddress, 1);
-		if (ret < 0)
-			return -1;
-	}
-
-	set_sig_addr = rcu_dereference(set_sig_addr_hook);
-	if (set_sig_addr) {
-		ret = set_sig_addr(pskb, ct, ctinfo, data,
-				   irr->callSignalAddress.item,
-				   irr->callSignalAddress.count);
-		if (ret < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct,
-		       enum ip_conntrack_info ctinfo,
-		       unsigned char **data, RasMessage * ras)
-{
-	switch (ras->choice) {
-	case eRasMessage_gatekeeperRequest:
-		return process_grq(pskb, ct, ctinfo, data,
-				   &ras->gatekeeperRequest);
-	case eRasMessage_gatekeeperConfirm:
-		return process_gcf(pskb, ct, ctinfo, data,
-				   &ras->gatekeeperConfirm);
-	case eRasMessage_registrationRequest:
-		return process_rrq(pskb, ct, ctinfo, data,
-				   &ras->registrationRequest);
-	case eRasMessage_registrationConfirm:
-		return process_rcf(pskb, ct, ctinfo, data,
-				   &ras->registrationConfirm);
-	case eRasMessage_unregistrationRequest:
-		return process_urq(pskb, ct, ctinfo, data,
-				   &ras->unregistrationRequest);
-	case eRasMessage_admissionRequest:
-		return process_arq(pskb, ct, ctinfo, data,
-				   &ras->admissionRequest);
-	case eRasMessage_admissionConfirm:
-		return process_acf(pskb, ct, ctinfo, data,
-				   &ras->admissionConfirm);
-	case eRasMessage_locationRequest:
-		return process_lrq(pskb, ct, ctinfo, data,
-				   &ras->locationRequest);
-	case eRasMessage_locationConfirm:
-		return process_lcf(pskb, ct, ctinfo, data,
-				   &ras->locationConfirm);
-	case eRasMessage_infoRequestResponse:
-		return process_irr(pskb, ct, ctinfo, data,
-				   &ras->infoRequestResponse);
-	default:
-		DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice);
-		break;
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo)
-{
-	static RasMessage ras;
-	unsigned char *data;
-	int datalen = 0;
-	int ret;
-
-	DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len);
-
-	spin_lock_bh(&ip_h323_lock);
-
-	/* Get UDP data */
-	data = get_udp_data(pskb, &datalen);
-	if (data == NULL)
-		goto accept;
-	DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
-	       NIPQUAD((*pskb)->nh.iph->saddr),
-	       NIPQUAD((*pskb)->nh.iph->daddr), datalen);
-
-	/* Decode RAS message */
-	ret = DecodeRasMessage(data, datalen, &ras);
-	if (ret < 0) {
-		if (net_ratelimit())
-			printk("ip_ct_ras: decoding error: %s\n",
-			       ret == H323_ERROR_BOUND ?
-			       "out of bound" : "out of range");
-		goto accept;
-	}
-
-	/* Process RAS message */
-	if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0)
-		goto drop;
-
-      accept:
-	spin_unlock_bh(&ip_h323_lock);
-	return NF_ACCEPT;
-
-      drop:
-	spin_unlock_bh(&ip_h323_lock);
-	if (net_ratelimit())
-		printk("ip_ct_ras: packet dropped\n");
-	return NF_DROP;
-}
-
-/****************************************************************************/
-static struct ip_conntrack_helper ip_conntrack_helper_ras = {
-	.name = "RAS",
-	.me = THIS_MODULE,
-	.max_expected = 32,
-	.timeout = 240,
-	.tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}},
-		  .dst = {.protonum = IPPROTO_UDP}},
-	.mask = {.src = {.u = {0xFFFE}},
-		 .dst = {.protonum = 0xFF}},
-	.help = ras_help,
-};
-
-/****************************************************************************/
-static void ip_conntrack_ras_expect(struct ip_conntrack *new,
-				    struct ip_conntrack_expect *this)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	new->helper = &ip_conntrack_helper_ras;
-	write_unlock_bh(&ip_conntrack_lock);
-}
-
-/****************************************************************************/
-/* Not __exit - called from init() */
-static void fini(void)
-{
-	ip_conntrack_helper_unregister(&ip_conntrack_helper_ras);
-	ip_conntrack_helper_unregister(&ip_conntrack_helper_q931);
-	kfree(h323_buffer);
-	DEBUGP("ip_ct_h323: fini\n");
-}
-
-/****************************************************************************/
-static int __init init(void)
-{
-	int ret;
-
-	h323_buffer = kmalloc(65536, GFP_KERNEL);
-	if (!h323_buffer)
-		return -ENOMEM;
-	if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) ||
-	    (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) {
-		fini();
-		return ret;
-	}
-	DEBUGP("ip_ct_h323: init success\n");
-	return 0;
-}
-
-/****************************************************************************/
-module_init(init);
-module_exit(fini);
-
-EXPORT_SYMBOL_GPL(get_h225_addr);
-EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect);
-EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect);
-EXPORT_SYMBOL_GPL(set_h245_addr_hook);
-EXPORT_SYMBOL_GPL(set_h225_addr_hook);
-EXPORT_SYMBOL_GPL(set_sig_addr_hook);
-EXPORT_SYMBOL_GPL(set_ras_addr_hook);
-EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook);
-EXPORT_SYMBOL_GPL(nat_t120_hook);
-EXPORT_SYMBOL_GPL(nat_h245_hook);
-EXPORT_SYMBOL_GPL(nat_callforwarding_hook);
-EXPORT_SYMBOL_GPL(nat_q931_hook);
-
-MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
-MODULE_DESCRIPTION("H.323 connection tracking helper");
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
deleted file mode 100644
index 2b760c5..0000000
--- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * ip_conntrack_pptp.c	- Version 3.0
- *
- * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
- * PPTP is a a protocol for creating virtual private networks.
- * It is a specification defined by Microsoft and some vendors
- * working with Microsoft.  PPTP is built on top of a modified
- * version of the Internet Generic Routing Encapsulation Protocol.
- * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
- * PPTP can be found in RFC 2637
- *
- * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- *
- * Limitations:
- * 	 - We blindly assume that control connections are always
- * 	   established in PNS->PAC direction.  This is a violation
- * 	   of RFFC2673
- * 	 - We can only support one single call within each session
- *
- * TODO:
- *	 - testing of incoming PPTP calls
- *
- * Changes:
- * 	2002-02-05 - Version 1.3
- * 	  - 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@snapgear.com>)
- * 	  - Add Version information at module loadtime
- * 	2002-02-10 - Version 1.6
- * 	  - move to C99 style initializers
- * 	  - remove second expectation if first arrives
- * 	2004-10-22 - Version 2.0
- * 	  - merge Mandrake's 2.6.x port with recent 2.6.x API changes
- * 	  - fix lots of linear skb assumptions from Mandrake's port
- * 	2005-06-10 - Version 2.1
- * 	  - use ip_conntrack_expect_free() instead of kfree() on the
- * 	    expect's (which are from the slab for quite some time)
- * 	2005-06-10 - Version 3.0
- * 	  - port helper to post-2.6.11 API changes,
- * 	    funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
- * 	2005-07-30 - Version 3.1
- * 	  - port helper to 2.6.13 API changes
- *
- */
-
-#include <linux/module.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-
-#define IP_CT_PPTP_VERSION "3.1"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
-
-static DEFINE_SPINLOCK(ip_pptp_lock);
-
-int
-(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
-			  struct ip_conntrack *ct,
-			  enum ip_conntrack_info ctinfo,
-			  struct PptpControlHeader *ctlh,
-			  union pptp_ctrl_union *pptpReq);
-
-int
-(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
-			  struct ip_conntrack *ct,
-			  enum ip_conntrack_info ctinfo,
-			  struct PptpControlHeader *ctlh,
-			  union pptp_ctrl_union *pptpReq);
-
-void
-(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig,
-			    struct ip_conntrack_expect *expect_reply);
-
-void
-(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
-			     struct ip_conntrack_expect *exp);
-
-#if 0
-/* PptpControlMessageType names */
-const char *pptp_msg_name[] = {
-	"UNKNOWN_MESSAGE",
-	"START_SESSION_REQUEST",
-	"START_SESSION_REPLY",
-	"STOP_SESSION_REQUEST",
-	"STOP_SESSION_REPLY",
-	"ECHO_REQUEST",
-	"ECHO_REPLY",
-	"OUT_CALL_REQUEST",
-	"OUT_CALL_REPLY",
-	"IN_CALL_REQUEST",
-	"IN_CALL_REPLY",
-	"IN_CALL_CONNECT",
-	"CALL_CLEAR_REQUEST",
-	"CALL_DISCONNECT_NOTIFY",
-	"WAN_ERROR_NOTIFY",
-	"SET_LINK_INFO"
-};
-EXPORT_SYMBOL(pptp_msg_name);
-#define DEBUGP(format, args...)	printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
-#define SECS *HZ
-#define MINS * 60 SECS
-#define HOURS * 60 MINS
-
-#define PPTP_GRE_TIMEOUT 		(10 MINS)
-#define PPTP_GRE_STREAM_TIMEOUT 	(5 HOURS)
-
-static void pptp_expectfn(struct ip_conntrack *ct,
-			 struct ip_conntrack_expect *exp)
-{
-	typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn;
-
-	DEBUGP("increasing timeouts\n");
-
-	/* increase timeout of GRE data channel conntrack entry */
-	ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
-	ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
-
-	/* Can you see how rusty this code is, compared with the pre-2.6.11
-	 * one? That's what happened to my shiny newnat of 2002 ;( -HW */
-
-	rcu_read_lock();
-	ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn);
-	if (!ip_nat_pptp_expectfn) {
-		struct ip_conntrack_tuple inv_t;
-		struct ip_conntrack_expect *exp_other;
-
-		/* obviously this tuple inversion only works until you do NAT */
-		invert_tuplepr(&inv_t, &exp->tuple);
-		DEBUGP("trying to unexpect other dir: ");
-		DUMP_TUPLE(&inv_t);
-
-		exp_other = ip_conntrack_expect_find_get(&inv_t);
-		if (exp_other) {
-			/* delete other expectation.  */
-			DEBUGP("found\n");
-			ip_conntrack_unexpect_related(exp_other);
-			ip_conntrack_expect_put(exp_other);
-		} else {
-			DEBUGP("not found\n");
-		}
-	} else {
-		/* we need more than simple inversion */
-		ip_nat_pptp_expectfn(ct, exp);
-	}
-	rcu_read_unlock();
-}
-
-static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
-{
-	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_expect *exp;
-
-	DEBUGP("trying to timeout ct or exp for tuple ");
-	DUMP_TUPLE(t);
-
-	h = ip_conntrack_find_get(t, NULL);
-	if (h)  {
-		struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
-		DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
-		sibling->proto.gre.timeout = 0;
-		sibling->proto.gre.stream_timeout = 0;
-		if (del_timer(&sibling->timeout))
-			sibling->timeout.function((unsigned long)sibling);
-		ip_conntrack_put(sibling);
-		return 1;
-	} else {
-		exp = ip_conntrack_expect_find_get(t);
-		if (exp) {
-			DEBUGP("unexpect_related of expect %p\n", exp);
-			ip_conntrack_unexpect_related(exp);
-			ip_conntrack_expect_put(exp);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-
-/* timeout GRE data connections */
-static void pptp_destroy_siblings(struct ip_conntrack *ct)
-{
-	struct ip_conntrack_tuple t;
-
-	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 = 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");
-
-	/* 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 = 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");
-}
-
-/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
-static inline int
-exp_gre(struct ip_conntrack *ct,
-	__be16 callid,
-	__be16 peer_callid)
-{
-	struct ip_conntrack_expect *exp_orig, *exp_reply;
-	int ret = 1;
-	typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre;
-
-	exp_orig = ip_conntrack_expect_alloc(ct);
-	if (exp_orig == NULL)
-		goto out;
-
-	exp_reply = ip_conntrack_expect_alloc(ct);
-	if (exp_reply == NULL)
-		goto out_put_orig;
-
-	/* 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 = htonl(0xffffffff);
-	exp_orig->mask.src.u.all = 0;
-	exp_orig->mask.dst.u.gre.key = htons(0xffff);
-	exp_orig->mask.dst.ip = htonl(0xffffffff);
-	exp_orig->mask.dst.protonum = 0xff;
-
-	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));
-
-	/* 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;
-
-	ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre);
-	if (ip_nat_pptp_exp_gre)
-		ip_nat_pptp_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);
-out_put_orig:
-	ip_conntrack_expect_put(exp_orig);
-out:
-	return ret;
-
-out_unexpect_both:
-	ip_conntrack_unexpect_related(exp_reply);
-out_unexpect_orig:
-	ip_conntrack_unexpect_related(exp_orig);
-	goto out_put_both;
-}
-
-static inline int
-pptp_inbound_pkt(struct sk_buff **pskb,
-		 struct PptpControlHeader *ctlh,
-		 union pptp_ctrl_union *pptpReq,
-		 unsigned int reqlen,
-		 struct ip_conntrack *ct,
-		 enum ip_conntrack_info ctinfo)
-{
-	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-	u_int16_t msg;
-	__be16 cid = 0, pcid = 0;
-	typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound;
-
-	msg = ntohs(ctlh->messageType);
-	DEBUGP("inbound control message %s\n", pptp_msg_name[msg]);
-
-	switch (msg) {
-	case PPTP_START_SESSION_REPLY:
-		/* server confirms new control session */
-		if (info->sstate < PPTP_SESSION_REQUESTED)
-			goto invalid;
-		if (pptpReq->srep.resultCode == PPTP_START_OK)
-			info->sstate = PPTP_SESSION_CONFIRMED;
-		else
-			info->sstate = PPTP_SESSION_ERROR;
-		break;
-
-	case PPTP_STOP_SESSION_REPLY:
-		/* server confirms end of control session */
-		if (info->sstate > PPTP_SESSION_STOPREQ)
-			goto invalid;
-		if (pptpReq->strep.resultCode == PPTP_STOP_OK)
-			info->sstate = PPTP_SESSION_NONE;
-		else
-			info->sstate = PPTP_SESSION_ERROR;
-		break;
-
-	case PPTP_OUT_CALL_REPLY:
-		/* server accepted call, we now expect GRE frames */
-		if (info->sstate != PPTP_SESSION_CONFIRMED)
-			goto invalid;
-		if (info->cstate != PPTP_CALL_OUT_REQ &&
-		    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;
-
-	case PPTP_IN_CALL_REQUEST:
-		/* server tells us about incoming call request */
-		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 = cid;
-		break;
-
-	case PPTP_IN_CALL_CONNECT:
-		/* server tells us about incoming call established */
-		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;
-
-		if (info->pns_call_id != pcid)
-			goto invalid;
-
-		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 */
-		exp_gre(ct, cid, pcid);
-		break;
-
-	case PPTP_CALL_DISCONNECT_NOTIFY:
-		/* server confirms disconnect */
-		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 */
-		pptp_destroy_siblings(ct);
-		break;
-
-	case PPTP_WAN_ERROR_NOTIFY:
-	case PPTP_ECHO_REQUEST:
-	case PPTP_ECHO_REPLY:
-		/* I don't have to explain these ;) */
-		break;
-	default:
-		goto invalid;
-	}
-
-	ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound);
-	if (ip_nat_pptp_inbound)
-		return ip_nat_pptp_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 PptpControlHeader *ctlh,
-		  union pptp_ctrl_union *pptpReq,
-		  unsigned int reqlen,
-		  struct ip_conntrack *ct,
-		  enum ip_conntrack_info ctinfo)
-{
-	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-	u_int16_t msg;
-	__be16 cid = 0, pcid = 0;
-	typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound;
-
-	msg = ntohs(ctlh->messageType);
-	DEBUGP("outbound control message %s\n", pptp_msg_name[msg]);
-
-	switch (msg) {
-	case PPTP_START_SESSION_REQUEST:
-		/* client requests for new control session */
-		if (info->sstate != PPTP_SESSION_NONE)
-			goto invalid;
-		info->sstate = PPTP_SESSION_REQUESTED;
-		break;
-	case PPTP_STOP_SESSION_REQUEST:
-		/* client requests end of control session */
-		info->sstate = PPTP_SESSION_STOPREQ;
-		break;
-
-	case PPTP_OUT_CALL_REQUEST:
-		/* client initiating connection to server */
-		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 = cid;
-		break;
-	case PPTP_IN_CALL_REPLY:
-		/* client answers incoming call */
-		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;
-
-	case PPTP_CALL_CLEAR_REQUEST:
-		/* client requests hangup of call */
-		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:
-	case PPTP_ECHO_REQUEST:
-	case PPTP_ECHO_REPLY:
-		/* I don't have to explain these ;) */
-		break;
-	default:
-		goto invalid;
-	}
-
-	ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound);
-	if (ip_nat_pptp_outbound)
-		return ip_nat_pptp_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
-conntrack_pptp_help(struct sk_buff **pskb,
-		    struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
-
-{
-	int dir = CTINFO2DIR(ctinfo);
-	struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
-	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
-	    && 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;
-
-	pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
-	if (!pptph) {
-		DEBUGP("no full PPTP header, can't track\n");
-		return NF_ACCEPT;
-	}
-	nexthdr_off += sizeof(_pptph);
-	datalen -= sizeof(_pptph);
-
-	/* if it's not a control message we can't do anything with it */
-	if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
-	    ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
-		DEBUGP("not a control packet\n");
-		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;
-
-	spin_lock_bh(&ip_pptp_lock);
-
-	/* FIXME: We just blindly assume that the control connection is always
-	 * established from PNS->PAC.  However, RFC makes no guarantee */
-	if (dir == IP_CT_DIR_ORIGINAL)
-		/* client -> server (PNS -> PAC) */
-		ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
-					ctinfo);
-	else
-		/* server -> client (PAC -> PNS) */
-		ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
-				       ctinfo);
-	DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
-		oldsstate, info->sstate, oldcstate, info->cstate);
-	spin_unlock_bh(&ip_pptp_lock);
-
-	return ret;
-}
-
-/* control protocol helper */
-static struct ip_conntrack_helper pptp = {
-	.list = { NULL, NULL },
-	.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,
-			    .u = { .all = 0 },
-			    .protonum = IPPROTO_TCP
-			  }
-		 },
-	.mask = { .src = { .ip = 0,
-			   .u = { .tcp = { .port = __constant_htons(0xffff) } }
-			 },
-		  .dst = { .ip = 0,
-			   .u = { .all = 0 },
-			   .protonum = 0xff
-			 }
-		},
-	.help = conntrack_pptp_help,
-	.destroy = pptp_destroy_siblings,
-};
-
-extern void ip_ct_proto_gre_fini(void);
-extern int __init ip_ct_proto_gre_init(void);
-
-/* ip_conntrack_pptp initialization */
-static int __init ip_conntrack_helper_pptp_init(void)
-{
-	int retcode;
-
-	retcode = ip_ct_proto_gre_init();
-	if (retcode < 0)
-		return retcode;
-
-	DEBUGP(" registering helper\n");
-	if ((retcode = ip_conntrack_helper_register(&pptp))) {
-		printk(KERN_ERR "Unable to register conntrack application "
-				"helper for pptp: %d\n", retcode);
-		ip_ct_proto_gre_fini();
-		return retcode;
-	}
-
-	printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
-	return 0;
-}
-
-static void __exit ip_conntrack_helper_pptp_fini(void)
-{
-	ip_conntrack_helper_unregister(&pptp);
-	ip_ct_proto_gre_fini();
-	printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
-}
-
-module_init(ip_conntrack_helper_pptp_init);
-module_exit(ip_conntrack_helper_pptp_fini);
-
-EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);
-EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);
-EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre);
-EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
deleted file mode 100644
index 053e591..0000000
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* IRC extension for IP connection tracking, Version 1.21
- * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
- * based on RR's ip_conntrack_ftp.c
- *
- * ip_conntrack_irc.c,v 1.21 2002/02/05 14:49:26 laforge Exp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- **
- *	Module load syntax:
- * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
- *			    max_dcc_channels=n dcc_timeout=secs
- *
- * 	please give the ports of all IRC servers You wish to connect to.
- *	If You don't specify ports, the default will be port 6667.
- *	With max_dcc_channels you can define the maximum number of not
- *	yet answered DCC channels per IRC session (default 8).
- *	With dcc_timeout you can specify how long the system waits for
- *	an expected DCC channel (default 300 seconds).
- *
- */
-
-#include <linux/module.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
-#include <linux/moduleparam.h>
-
-#define MAX_PORTS 8
-static unsigned short ports[MAX_PORTS];
-static int ports_c;
-static unsigned int max_dcc_channels = 8;
-static unsigned int dcc_timeout = 300;
-/* This is slow, but it's simple. --RR */
-static char *irc_buffer;
-static DEFINE_SPINLOCK(irc_buffer_lock);
-
-unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
-				enum ip_conntrack_info ctinfo,
-				unsigned int matchoff,
-				unsigned int matchlen,
-				struct ip_conntrack_expect *exp);
-EXPORT_SYMBOL_GPL(ip_nat_irc_hook);
-
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
-MODULE_LICENSE("GPL");
-module_param_array(ports, ushort, &ports_c, 0400);
-MODULE_PARM_DESC(ports, "port numbers of IRC servers");
-module_param(max_dcc_channels, uint, 0400);
-MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
-module_param(dcc_timeout, uint, 0400);
-MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
-
-static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
-#define MINMATCHLEN	5
-
-#if 0
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
-				       __FILE__, __FUNCTION__ , ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
-		     u_int16_t *port, char **ad_beg_p, char **ad_end_p)
-/* tries to get the ip_addr and port out of a dcc command
-   return value: -1 on failure, 0 on success
-	data		pointer to first byte of DCC command data
-	data_end	pointer to last byte of dcc command data
-	ip		returns parsed ip of dcc command
-	port		returns parsed port of dcc command
-	ad_beg_p	returns pointer to first byte of addr data
-	ad_end_p	returns pointer to last byte of addr data */
-{
-
-	/* at least 12: "AAAAAAAA P\1\n" */
-	while (*data++ != ' ')
-		if (data > data_end - 12)
-			return -1;
-
-	*ad_beg_p = data;
-	*ip = simple_strtoul(data, &data, 10);
-
-	/* skip blanks between ip and port */
-	while (*data == ' ') {
-		if (data >= data_end)
-			return -1;
-		data++;
-	}
-
-	*port = simple_strtoul(data, &data, 10);
-	*ad_end_p = data;
-
-	return 0;
-}
-
-static int help(struct sk_buff **pskb,
-		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
-{
-	unsigned int dataoff;
-	struct tcphdr _tcph, *th;
-	char *data, *data_limit, *ib_ptr;
-	int dir = CTINFO2DIR(ctinfo);
-	struct ip_conntrack_expect *exp;
-	u32 seq;
-	u_int32_t dcc_ip;
-	u_int16_t dcc_port;
-	int i, ret = NF_ACCEPT;
-	char *addr_beg_p, *addr_end_p;
-	typeof(ip_nat_irc_hook) ip_nat_irc;
-
-	DEBUGP("entered\n");
-
-	/* If packet is coming from IRC server */
-	if (dir == IP_CT_DIR_REPLY)
-		return NF_ACCEPT;
-
-	/* Until there's been traffic both ways, don't look in packets. */
-	if (ctinfo != IP_CT_ESTABLISHED
-	    && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
-		DEBUGP("Conntrackinfo = %u\n", ctinfo);
-		return NF_ACCEPT;
-	}
-
-	/* Not a full tcp header? */
-	th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL)
-		return NF_ACCEPT;
-
-	/* No data? */
-	dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
-	if (dataoff >= (*pskb)->len)
-		return NF_ACCEPT;
-
-	spin_lock_bh(&irc_buffer_lock);
-	ib_ptr = skb_header_pointer(*pskb, dataoff,
-				    (*pskb)->len - dataoff, irc_buffer);
-	BUG_ON(ib_ptr == NULL);
-
-	data = ib_ptr;
-	data_limit = ib_ptr + (*pskb)->len - dataoff;
-
-	/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
-	 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
-	while (data < (data_limit - (19 + MINMATCHLEN))) {
-		if (memcmp(data, "\1DCC ", 5)) {
-			data++;
-			continue;
-		}
-
-		data += 5;
-		/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
-
-		DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
-			NIPQUAD(iph->saddr), ntohs(th->source),
-			NIPQUAD(iph->daddr), ntohs(th->dest));
-
-		for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
-			if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
-				/* no match */
-				continue;
-			}
-
-			DEBUGP("DCC %s detected\n", dccprotos[i]);
-			data += strlen(dccprotos[i]);
-			/* we have at least
-			 * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
-			 * data left (== 14/13 bytes) */
-			if (parse_dcc((char *)data, data_limit, &dcc_ip,
-				       &dcc_port, &addr_beg_p, &addr_end_p)) {
-				/* unable to parse */
-				DEBUGP("unable to parse dcc command\n");
-				continue;
-			}
-			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
-				HIPQUAD(dcc_ip), dcc_port);
-
-			/* dcc_ip can be the internal OR external (NAT'ed) IP
-			 * Tiago Sousa <mirage@kaotik.org> */
-			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
-			    && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
-				if (net_ratelimit())
-					printk(KERN_WARNING
-						"Forged DCC command from "
-						"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
-				NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
-						HIPQUAD(dcc_ip), dcc_port);
-
-				continue;
-			}
-
-			exp = ip_conntrack_expect_alloc(ct);
-			if (exp == NULL) {
-				ret = NF_DROP;
-				goto out;
-			}
-
-			/* save position of address in dcc string,
-			 * necessary for NAT */
-			DEBUGP("tcph->seq = %u\n", th->seq);
-			seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
-
-			/* We refer to the reverse direction ("!dir")
-			 * tuples here, because we're expecting
-			 * something in the other * direction.
-			 * Doesn't matter unless NAT is happening.  */
-			exp->tuple = ((struct ip_conntrack_tuple)
-				{ { 0, { 0 } },
-				  { ct->tuplehash[!dir].tuple.dst.ip,
-				    { .tcp = { htons(dcc_port) } },
-				    IPPROTO_TCP }});
-			exp->mask = ((struct ip_conntrack_tuple)
-				{ { 0, { 0 } },
-				  { htonl(0xFFFFFFFF),
-					{ .tcp = { htons(0xFFFF) } }, 0xFF }});
-			exp->expectfn = NULL;
-			exp->flags = 0;
-			ip_nat_irc = rcu_dereference(ip_nat_irc_hook);
-			if (ip_nat_irc)
-				ret = ip_nat_irc(pskb, ctinfo,
-						 addr_beg_p - ib_ptr,
-						 addr_end_p - addr_beg_p,
-						 exp);
-			else if (ip_conntrack_expect_related(exp) != 0)
-				ret = NF_DROP;
-			ip_conntrack_expect_put(exp);
-			goto out;
-		} /* for .. NUM_DCCPROTO */
-	} /* while data < ... */
-
- out:
-	spin_unlock_bh(&irc_buffer_lock);
-	return ret;
-}
-
-static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
-static char irc_names[MAX_PORTS][sizeof("irc-65535")];
-
-static void ip_conntrack_irc_fini(void);
-
-static int __init ip_conntrack_irc_init(void)
-{
-	int i, ret;
-	struct ip_conntrack_helper *hlpr;
-	char *tmpname;
-
-	if (max_dcc_channels < 1) {
-		printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
-		return -EBUSY;
-	}
-
-	irc_buffer = kmalloc(65536, GFP_KERNEL);
-	if (!irc_buffer)
-		return -ENOMEM;
-
-	/* If no port given, default to standard irc port */
-	if (ports_c == 0)
-		ports[ports_c++] = IRC_PORT;
-
-	for (i = 0; i < ports_c; i++) {
-		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 = htons(0xFFFF);
-		hlpr->mask.dst.protonum = 0xFF;
-		hlpr->max_expected = max_dcc_channels;
-		hlpr->timeout = dcc_timeout;
-		hlpr->me = THIS_MODULE;
-		hlpr->help = help;
-
-		tmpname = &irc_names[i][0];
-		if (ports[i] == IRC_PORT)
-			sprintf(tmpname, "irc");
-		else
-			sprintf(tmpname, "irc-%d", i);
-		hlpr->name = tmpname;
-
-		DEBUGP("port #%d: %d\n", i, ports[i]);
-
-		ret = ip_conntrack_helper_register(hlpr);
-
-		if (ret) {
-			printk("ip_conntrack_irc: ERROR registering port %d\n",
-				ports[i]);
-			ip_conntrack_irc_fini();
-			return -EBUSY;
-		}
-	}
-	return 0;
-}
-
-/* This function is intentionally _NOT_ defined as __exit, because
- * it is needed by the init function */
-static void ip_conntrack_irc_fini(void)
-{
-	int i;
-	for (i = 0; i < ports_c; i++) {
-		DEBUGP("unregistering port %d\n",
-		       ports[i]);
-		ip_conntrack_helper_unregister(&irc_helpers[i]);
-	}
-	kfree(irc_buffer);
-}
-
-module_init(ip_conntrack_irc_init);
-module_exit(ip_conntrack_irc_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
deleted file mode 100644
index cc6dd49..0000000
--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- *      NetBIOS name service broadcast connection tracking helper
- *
- *      (c) 2005 Patrick McHardy <kaber@trash.net>
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-/*
- *      This helper tracks locally originating NetBIOS name service
- *      requests by issuing permanent expectations (valid until
- *      timing out) matching all reply connections from the
- *      destination network. The only NetBIOS specific thing is
- *      actually the port number.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#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>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-
-#define NMBD_PORT	137
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
-MODULE_LICENSE("GPL");
-
-static unsigned int timeout = 3;
-module_param(timeout, uint, 0400);
-MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
-
-static int help(struct sk_buff **pskb,
-		struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
-{
-	struct ip_conntrack_expect *exp;
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct rtable *rt = (struct rtable *)(*pskb)->dst;
-	struct in_device *in_dev;
-	__be32 mask = 0;
-
-	/* we're only interested in locally generated packets */
-	if ((*pskb)->sk == NULL)
-		goto out;
-	if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
-		goto out;
-	if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
-		goto out;
-
-	rcu_read_lock();
-	in_dev = __in_dev_get_rcu(rt->u.dst.dev);
-	if (in_dev != NULL) {
-		for_primary_ifa(in_dev) {
-			if (ifa->ifa_broadcast == iph->daddr) {
-				mask = ifa->ifa_mask;
-				break;
-			}
-		} endfor_ifa(in_dev);
-	}
-	rcu_read_unlock();
-
-	if (mask == 0)
-		goto out;
-
-	exp = ip_conntrack_expect_alloc(ct);
-	if (exp == NULL)
-		goto out;
-
-	exp->tuple                = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-	exp->tuple.src.u.udp.port = htons(NMBD_PORT);
-
-	exp->mask.src.ip          = mask;
-	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;
-	exp->flags                = IP_CT_EXPECT_PERMANENT;
-
-	ip_conntrack_expect_related(exp);
-	ip_conntrack_expect_put(exp);
-
-	ip_ct_refresh(ct, *pskb, timeout * HZ);
-out:
-	return NF_ACCEPT;
-}
-
-static struct ip_conntrack_helper helper = {
-	.name			= "netbios-ns",
-	.tuple = {
-		.src = {
-			.u = {
-				.udp = {
-					.port	= __constant_htons(NMBD_PORT),
-				}
-			}
-		},
-		.dst = {
-			.protonum	= IPPROTO_UDP,
-		},
-	},
-	.mask = {
-		.src = {
-			.u = {
-				.udp = {
-					.port	= __constant_htons(0xFFFF),
-				}
-			}
-		},
-		.dst = {
-			.protonum	= 0xFF,
-		},
-	},
-	.max_expected		= 1,
-	.me			= THIS_MODULE,
-	.help			= help,
-};
-
-static int __init ip_conntrack_netbios_ns_init(void)
-{
-	helper.timeout = timeout;
-	return ip_conntrack_helper_register(&helper);
-}
-
-static void __exit ip_conntrack_netbios_ns_fini(void)
-{
-	ip_conntrack_helper_unregister(&helper);
-}
-
-module_init(ip_conntrack_netbios_ns_init);
-module_exit(ip_conntrack_netbios_ns_fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
deleted file mode 100644
index 9228b76..0000000
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ /dev/null
@@ -1,1577 +0,0 @@
-/* Connection tracking via netlink socket. Allows for user space
- * protocol helpers and general trouble making from userspace.
- *
- * (C) 2001 by Jay Schulist <jschlst@samba.org>
- * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
- * (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net>
- *
- * I've reworked this stuff to use attributes instead of conntrack
- * structures. 5.44 am. I need more tea. --pablo 05/07/11.
- *
- * Initial connection tracking via netlink development funded and
- * generally made possible by Network Robots, Inc. (www.networkrobots.com)
- *
- * Further development of this code funded by Astaro AG (http://www.astaro.com)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/netlink.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/notifier.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nfnetlink_conntrack.h>
-
-MODULE_LICENSE("GPL");
-
-static char __initdata version[] = "0.90";
-
-static inline int
-ctnetlink_dump_tuples_proto(struct sk_buff *skb,
-			    const struct ip_conntrack_tuple *tuple,
-			    struct ip_conntrack_protocol *proto)
-{
-	int ret = 0;
-	struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);
-
-	NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
-
-	if (likely(proto->tuple_to_nfattr))
-		ret = proto->tuple_to_nfattr(skb, tuple);
-
-	NFA_NEST_END(skb, nest_parms);
-
-	return ret;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_tuples_ip(struct sk_buff *skb,
-			 const struct ip_conntrack_tuple *tuple)
-{
-	struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_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);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_tuples(struct sk_buff *skb,
-		      const struct ip_conntrack_tuple *tuple)
-{
-	int ret;
-	struct ip_conntrack_protocol *proto;
-
-	ret = ctnetlink_dump_tuples_ip(skb, tuple);
-	if (unlikely(ret < 0))
-		return ret;
-
-	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
-	ret = ctnetlink_dump_tuples_proto(skb, tuple, proto);
-	ip_conntrack_proto_put(proto);
-
-	return ret;
-}
-
-static inline int
-ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	__be32 status = htonl((u_int32_t) ct->status);
-	NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	long timeout_l = ct->timeout.expires - jiffies;
-	__be32 timeout;
-
-	if (timeout_l < 0)
-		timeout = 0;
-	else
-		timeout = htonl(timeout_l / HZ);
-
-	NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
-
-	struct nfattr *nest_proto;
-	int ret;
-
-	if (!proto->to_nfattr) {
-		ip_conntrack_proto_put(proto);
-		return 0;
-	}
-
-	nest_proto = NFA_NEST(skb, CTA_PROTOINFO);
-
-	ret = proto->to_nfattr(skb, nest_proto, ct);
-
-	ip_conntrack_proto_put(proto);
-
-	NFA_NEST_END(skb, nest_proto);
-
-	return ret;
-
-nfattr_failure:
-	ip_conntrack_proto_put(proto);
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	struct nfattr *nest_helper;
-
-	if (!ct->helper)
-		return 0;
-
-	nest_helper = NFA_NEST(skb, CTA_HELP);
-	NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name);
-
-	if (ct->helper->to_nfattr)
-		ct->helper->to_nfattr(skb, ct);
-
-	NFA_NEST_END(skb, nest_helper);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-#ifdef CONFIG_IP_NF_CT_ACCT
-static inline int
-ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,
-			enum ip_conntrack_dir dir)
-{
-	enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
-	struct nfattr *nest_count = NFA_NEST(skb, type);
-	__be32 tmp;
-
-	tmp = htonl(ct->counters[dir].packets);
-	NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp);
-
-	tmp = htonl(ct->counters[dir].bytes);
-	NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
-
-	NFA_NEST_END(skb, nest_count);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-#else
-#define ctnetlink_dump_counters(a, b, c) (0)
-#endif
-
-#ifdef CONFIG_IP_NF_CONNTRACK_MARK
-static inline int
-ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	__be32 mark = htonl(ct->mark);
-
-	NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-#else
-#define ctnetlink_dump_mark(a, b) (0)
-#endif
-
-static inline int
-ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	__be32 id = htonl(ct->id);
-	NFA_PUT(skb, CTA_ID, sizeof(__be32), &id);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
-{
-	__be32 use = htonl(atomic_read(&ct->ct_general.use));
-
-	NFA_PUT(skb, CTA_USE, sizeof(__be32), &use);
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
-
-static int
-ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
-		    int event, int nowait,
-		    const struct ip_conntrack *ct)
-{
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	struct nfattr *nest_parms;
-	unsigned char *b;
-
-	b = skb->tail;
-
-	event |= NFNL_SUBSYS_CTNETLINK << 8;
-	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
-	nfmsg  = NLMSG_DATA(nlh);
-
-	nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
-	nfmsg->nfgen_family = AF_INET;
-	nfmsg->version      = NFNETLINK_V0;
-	nfmsg->res_id	    = 0;
-
-	nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
-	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
-		goto nfattr_failure;
-	NFA_NEST_END(skb, nest_parms);
-
-	nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
-	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
-		goto nfattr_failure;
-	NFA_NEST_END(skb, nest_parms);
-
-	if (ctnetlink_dump_status(skb, ct) < 0 ||
-	    ctnetlink_dump_timeout(skb, ct) < 0 ||
-	    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
-	    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
-	    ctnetlink_dump_protoinfo(skb, ct) < 0 ||
-	    ctnetlink_dump_helpinfo(skb, ct) < 0 ||
-	    ctnetlink_dump_mark(skb, ct) < 0 ||
-	    ctnetlink_dump_id(skb, ct) < 0 ||
-	    ctnetlink_dump_use(skb, ct) < 0)
-		goto nfattr_failure;
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-nfattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-static int ctnetlink_conntrack_event(struct notifier_block *this,
-				     unsigned long events, void *ptr)
-{
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	struct nfattr *nest_parms;
-	struct ip_conntrack *ct = (struct ip_conntrack *)ptr;
-	struct sk_buff *skb;
-	unsigned int type;
-	unsigned char *b;
-	unsigned int flags = 0, group;
-
-	/* ignore our fake conntrack entry */
-	if (ct == &ip_conntrack_untracked)
-		return NOTIFY_DONE;
-
-	if (events & IPCT_DESTROY) {
-		type = IPCTNL_MSG_CT_DELETE;
-		group = NFNLGRP_CONNTRACK_DESTROY;
-	} else if (events & (IPCT_NEW | IPCT_RELATED)) {
-		type = IPCTNL_MSG_CT_NEW;
-		flags = NLM_F_CREATE|NLM_F_EXCL;
-		group = NFNLGRP_CONNTRACK_NEW;
-	} else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) {
-		type = IPCTNL_MSG_CT_NEW;
-		group = NFNLGRP_CONNTRACK_UPDATE;
-	} else
-		return NOTIFY_DONE;
-
-	if (!nfnetlink_has_listeners(group))
-		return NOTIFY_DONE;
-
-	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
-	if (!skb)
-		return NOTIFY_DONE;
-
-	b = skb->tail;
-
-	type |= NFNL_SUBSYS_CTNETLINK << 8;
-	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
-	nfmsg = NLMSG_DATA(nlh);
-
-	nlh->nlmsg_flags    = flags;
-	nfmsg->nfgen_family = AF_INET;
-	nfmsg->version	= NFNETLINK_V0;
-	nfmsg->res_id	= 0;
-
-	nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);
-	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
-		goto nfattr_failure;
-	NFA_NEST_END(skb, nest_parms);
-
-	nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);
-	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
-		goto nfattr_failure;
-	NFA_NEST_END(skb, nest_parms);
-
-	if (events & IPCT_DESTROY) {
-		if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
-		    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
-			goto nfattr_failure;
-	} else {
-		if (ctnetlink_dump_status(skb, ct) < 0)
-			goto nfattr_failure;
-
-		if (ctnetlink_dump_timeout(skb, ct) < 0)
-			goto nfattr_failure;
-
-		if (events & IPCT_PROTOINFO
-		    && ctnetlink_dump_protoinfo(skb, ct) < 0)
-			goto nfattr_failure;
-
-		if ((events & IPCT_HELPER || ct->helper)
-		    && ctnetlink_dump_helpinfo(skb, ct) < 0)
-			goto nfattr_failure;
-
-#ifdef CONFIG_IP_NF_CONNTRACK_MARK
-		if ((events & IPCT_MARK || ct->mark)
-		    && ctnetlink_dump_mark(skb, ct) < 0)
-			goto nfattr_failure;
-#endif
-
-		if (events & IPCT_COUNTER_FILLING &&
-		    (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
-		     ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0))
-			goto nfattr_failure;
-	}
-
-	nlh->nlmsg_len = skb->tail - b;
-	nfnetlink_send(skb, 0, group, 0);
-	return NOTIFY_DONE;
-
-nlmsg_failure:
-nfattr_failure:
-	kfree_skb(skb);
-	return NOTIFY_DONE;
-}
-#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
-
-static int ctnetlink_done(struct netlink_callback *cb)
-{
-	if (cb->args[1])
-		ip_conntrack_put((struct ip_conntrack *)cb->args[1]);
-	return 0;
-}
-
-static int
-ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
-{
-	struct ip_conntrack *ct, *last;
-	struct ip_conntrack_tuple_hash *h;
-	struct list_head *i;
-
-	read_lock_bh(&ip_conntrack_lock);
-	last = (struct ip_conntrack *)cb->args[1];
-	for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
-restart:
-		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 (cb->args[1]) {
-				if (ct != last)
-					continue;
-				cb->args[1] = 0;
-			}
-			if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
-						cb->nlh->nlmsg_seq,
-						IPCTNL_MSG_CT_NEW,
-						1, ct) < 0) {
-				nf_conntrack_get(&ct->ct_general);
-				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;
-			goto restart;
-		}
-	}
-out:
-	read_unlock_bh(&ip_conntrack_lock);
-	if (last)
-		ip_conntrack_put(last);
-
-	return skb->len;
-}
-
-static const size_t cta_min_ip[CTA_IP_MAX] = {
-	[CTA_IP_V4_SRC-1]	= sizeof(__be32),
-	[CTA_IP_V4_DST-1]	= sizeof(__be32),
-};
-
-static inline int
-ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
-{
-	struct nfattr *tb[CTA_IP_MAX];
-
-	nfattr_parse_nested(tb, CTA_IP_MAX, attr);
-
-	if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
-		return -EINVAL;
-
-	if (!tb[CTA_IP_V4_SRC-1])
-		return -EINVAL;
-	tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
-
-	if (!tb[CTA_IP_V4_DST-1])
-		return -EINVAL;
-	tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
-
-	return 0;
-}
-
-static const size_t cta_min_proto[CTA_PROTO_MAX] = {
-	[CTA_PROTO_NUM-1]	= sizeof(u_int8_t),
-	[CTA_PROTO_SRC_PORT-1]	= sizeof(u_int16_t),
-	[CTA_PROTO_DST_PORT-1]	= sizeof(u_int16_t),
-	[CTA_PROTO_ICMP_TYPE-1]	= sizeof(u_int8_t),
-	[CTA_PROTO_ICMP_CODE-1]	= sizeof(u_int8_t),
-	[CTA_PROTO_ICMP_ID-1]	= sizeof(u_int16_t),
-};
-
-static inline int
-ctnetlink_parse_tuple_proto(struct nfattr *attr,
-			    struct ip_conntrack_tuple *tuple)
-{
-	struct nfattr *tb[CTA_PROTO_MAX];
-	struct ip_conntrack_protocol *proto;
-	int ret = 0;
-
-	nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
-
-	if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
-		return -EINVAL;
-
-	if (!tb[CTA_PROTO_NUM-1])
-		return -EINVAL;
-	tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
-
-	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
-
-	if (likely(proto->nfattr_to_tuple))
-		ret = proto->nfattr_to_tuple(tb, tuple);
-
-	ip_conntrack_proto_put(proto);
-
-	return ret;
-}
-
-static inline int
-ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
-		      enum ctattr_tuple type)
-{
-	struct nfattr *tb[CTA_TUPLE_MAX];
-	int err;
-
-	memset(tuple, 0, sizeof(*tuple));
-
-	nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
-
-	if (!tb[CTA_TUPLE_IP-1])
-		return -EINVAL;
-
-	err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);
-	if (err < 0)
-		return err;
-
-	if (!tb[CTA_TUPLE_PROTO-1])
-		return -EINVAL;
-
-	err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);
-	if (err < 0)
-		return err;
-
-	/* orig and expect tuples get DIR_ORIGINAL */
-	if (type == CTA_TUPLE_REPLY)
-		tuple->dst.dir = IP_CT_DIR_REPLY;
-	else
-		tuple->dst.dir = IP_CT_DIR_ORIGINAL;
-
-	return 0;
-}
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
-	[CTA_PROTONAT_PORT_MIN-1]	= sizeof(u_int16_t),
-	[CTA_PROTONAT_PORT_MAX-1]	= sizeof(u_int16_t),
-};
-
-static int ctnetlink_parse_nat_proto(struct nfattr *attr,
-				     const struct ip_conntrack *ct,
-				     struct ip_nat_range *range)
-{
-	struct nfattr *tb[CTA_PROTONAT_MAX];
-	struct ip_nat_protocol *npt;
-
-	nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
-
-	if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
-		return -EINVAL;
-
-	npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
-
-	if (!npt->nfattr_to_range) {
-		ip_nat_proto_put(npt);
-		return 0;
-	}
-
-	/* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
-	if (npt->nfattr_to_range(tb, range) > 0)
-		range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-
-	ip_nat_proto_put(npt);
-
-	return 0;
-}
-
-static const size_t cta_min_nat[CTA_NAT_MAX] = {
-	[CTA_NAT_MINIP-1]       = sizeof(__be32),
-	[CTA_NAT_MAXIP-1]       = sizeof(__be32),
-};
-
-static inline int
-ctnetlink_parse_nat(struct nfattr *nat,
-		    const struct ip_conntrack *ct, struct ip_nat_range *range)
-{
-	struct nfattr *tb[CTA_NAT_MAX];
-	int err;
-
-	memset(range, 0, sizeof(*range));
-
-	nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
-
-	if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
-		return -EINVAL;
-
-	if (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 = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
-
-	if (range->min_ip)
-		range->flags |= IP_NAT_RANGE_MAP_IPS;
-
-	if (!tb[CTA_NAT_PROTO-1])
-		return 0;
-
-	err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-#endif
-
-static inline int
-ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
-{
-	struct nfattr *tb[CTA_HELP_MAX];
-
-	nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
-
-	if (!tb[CTA_HELP_NAME-1])
-		return -EINVAL;
-
-	*helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
-
-	return 0;
-}
-
-static const size_t cta_min[CTA_MAX] = {
-	[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
-ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack *ct;
-	int err = 0;
-
-	if (nfattr_bad_size(cda, CTA_MAX, cta_min))
-		return -EINVAL;
-
-	if (cda[CTA_TUPLE_ORIG-1])
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
-	else if (cda[CTA_TUPLE_REPLY-1])
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
-	else {
-		/* Flush the whole table */
-		ip_conntrack_flush();
-		return 0;
-	}
-
-	if (err < 0)
-		return err;
-
-	h = ip_conntrack_find_get(&tuple, NULL);
-	if (!h)
-		return -ENOENT;
-
-	ct = tuplehash_to_ctrack(h);
-
-	if (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;
-		}
-	}
-	if (del_timer(&ct->timeout))
-		ct->timeout.function((unsigned long)ct);
-
-	ip_conntrack_put(ct);
-
-	return 0;
-}
-
-static int
-ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack *ct;
-	struct sk_buff *skb2 = NULL;
-	int err = 0;
-
-	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-		struct nfgenmsg *msg = NLMSG_DATA(nlh);
-		u32 rlen;
-
-		if (msg->nfgen_family != AF_INET)
-			return -EAFNOSUPPORT;
-
-#ifndef CONFIG_IP_NF_CT_ACCT
-		if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
-			return -ENOTSUPP;
-#endif
-		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)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
-		return 0;
-	}
-
-	if (nfattr_bad_size(cda, CTA_MAX, cta_min))
-		return -EINVAL;
-
-	if (cda[CTA_TUPLE_ORIG-1])
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
-	else if (cda[CTA_TUPLE_REPLY-1])
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);
-	else
-		return -EINVAL;
-
-	if (err < 0)
-		return err;
-
-	h = ip_conntrack_find_get(&tuple, NULL);
-	if (!h)
-		return -ENOENT;
-
-	ct = tuplehash_to_ctrack(h);
-
-	err = -ENOMEM;
-	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb2) {
-		ip_conntrack_put(ct);
-		return -ENOMEM;
-	}
-
-	err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
-				  IPCTNL_MSG_CT_NEW, 1, ct);
-	ip_conntrack_put(ct);
-	if (err <= 0)
-		goto free;
-
-	err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
-	if (err < 0)
-		goto out;
-
-	return 0;
-
-free:
-	kfree_skb(skb2);
-out:
-	return err;
-}
-
-static inline int
-ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
-{
-	unsigned long d;
-	unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1]));
-	d = ct->status ^ status;
-
-	if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
-		/* unchangeable */
-		return -EINVAL;
-
-	if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
-		/* SEEN_REPLY bit can only be set */
-		return -EINVAL;
-
-
-	if (d & IPS_ASSURED && !(status & IPS_ASSURED))
-		/* ASSURED bit can only be set */
-		return -EINVAL;
-
-	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
-#ifndef CONFIG_IP_NF_NAT_NEEDED
-		return -EINVAL;
-#else
-		struct ip_nat_range range;
-
-		if (cda[CTA_NAT_DST-1]) {
-			if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct,
-						&range) < 0)
-				return -EINVAL;
-			if (ip_nat_initialized(ct,
-					       HOOK2MANIP(NF_IP_PRE_ROUTING)))
-				return -EEXIST;
-			ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
-		}
-		if (cda[CTA_NAT_SRC-1]) {
-			if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct,
-						&range) < 0)
-				return -EINVAL;
-			if (ip_nat_initialized(ct,
-					       HOOK2MANIP(NF_IP_POST_ROUTING)))
-				return -EEXIST;
-			ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
-		}
-#endif
-	}
-
-	/* Be careful here, modifying NAT bits can screw up things,
-	 * so don't let users modify them directly if they don't pass
-	 * ip_nat_range. */
-	ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
-	return 0;
-}
-
-
-static inline int
-ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
-{
-	struct ip_conntrack_helper *helper;
-	char *helpname;
-	int err;
-
-	/* don't change helper of sibling connections */
-	if (ct->master)
-		return -EINVAL;
-
-	err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);
-	if (err < 0)
-		return err;
-
-	helper = __ip_conntrack_helper_find_byname(helpname);
-	if (!helper) {
-		if (!strcmp(helpname, ""))
-			helper = NULL;
-		else
-			return -EINVAL;
-	}
-
-	if (ct->helper) {
-		if (!helper) {
-			/* we had a helper before ... */
-			ip_ct_remove_expectations(ct);
-			ct->helper = NULL;
-		} else {
-			/* need to zero data of old helper */
-			memset(&ct->help, 0, sizeof(ct->help));
-		}
-	}
-
-	ct->helper = helper;
-
-	return 0;
-}
-
-static inline int
-ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
-{
-	u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
-
-	if (!del_timer(&ct->timeout))
-		return -ETIME;
-
-	ct->timeout.expires = jiffies + timeout * HZ;
-	add_timer(&ct->timeout);
-
-	return 0;
-}
-
-static inline int
-ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
-{
-	struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
-	struct ip_conntrack_protocol *proto;
-	u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
-	int err = 0;
-
-	nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
-
-	proto = ip_conntrack_proto_find_get(npt);
-
-	if (proto->from_nfattr)
-		err = proto->from_nfattr(tb, ct);
-	ip_conntrack_proto_put(proto);
-
-	return err;
-}
-
-static int
-ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
-{
-	int err;
-
-	if (cda[CTA_HELP-1]) {
-		err = ctnetlink_change_helper(ct, cda);
-		if (err < 0)
-			return err;
-	}
-
-	if (cda[CTA_TIMEOUT-1]) {
-		err = ctnetlink_change_timeout(ct, cda);
-		if (err < 0)
-			return err;
-	}
-
-	if (cda[CTA_STATUS-1]) {
-		err = ctnetlink_change_status(ct, cda);
-		if (err < 0)
-			return err;
-	}
-
-	if (cda[CTA_PROTOINFO-1]) {
-		err = ctnetlink_change_protoinfo(ct, cda);
-		if (err < 0)
-			return err;
-	}
-
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-	if (cda[CTA_MARK-1])
-		ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
-#endif
-
-	return 0;
-}
-
-static int
-ctnetlink_create_conntrack(struct nfattr *cda[],
-			   struct ip_conntrack_tuple *otuple,
-			   struct ip_conntrack_tuple *rtuple)
-{
-	struct ip_conntrack *ct;
-	int err = -EINVAL;
-
-	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(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
-
-	ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
-	ct->status |= IPS_CONFIRMED;
-
-	if (cda[CTA_STATUS-1]) {
-		err = ctnetlink_change_status(ct, cda);
-		if (err < 0)
-			goto err;
-	}
-
-	if (cda[CTA_PROTOINFO-1]) {
-		err = ctnetlink_change_protoinfo(ct, cda);
-		if (err < 0)
-			goto err;
-	}
-
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-	if (cda[CTA_MARK-1])
-		ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
-#endif
-
-	ct->helper = ip_conntrack_helper_find_get(rtuple);
-
-	add_timer(&ct->timeout);
-	ip_conntrack_hash_insert(ct);
-
-	if (ct->helper)
-		ip_conntrack_helper_put(ct->helper);
-
-	return 0;
-
-err:
-	ip_conntrack_free(ct);
-	return err;
-}
-
-static int
-ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_tuple otuple, rtuple;
-	struct ip_conntrack_tuple_hash *h = NULL;
-	int err = 0;
-
-	if (nfattr_bad_size(cda, CTA_MAX, cta_min))
-		return -EINVAL;
-
-	if (cda[CTA_TUPLE_ORIG-1]) {
-		err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
-		if (err < 0)
-			return err;
-	}
-
-	if (cda[CTA_TUPLE_REPLY-1]) {
-		err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);
-		if (err < 0)
-			return err;
-	}
-
-	write_lock_bh(&ip_conntrack_lock);
-	if (cda[CTA_TUPLE_ORIG-1])
-		h = __ip_conntrack_find(&otuple, NULL);
-	else if (cda[CTA_TUPLE_REPLY-1])
-		h = __ip_conntrack_find(&rtuple, NULL);
-
-	if (h == NULL) {
-		write_unlock_bh(&ip_conntrack_lock);
-		err = -ENOENT;
-		if (nlh->nlmsg_flags & NLM_F_CREATE)
-			err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
-		return err;
-	}
-	/* implicit 'else' */
-
-	/* we only allow nat config for new conntracks */
-	if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) {
-		err = -EINVAL;
-		goto out_unlock;
-	}
-
-	/* We manipulate the conntrack inside the global conntrack table lock,
-	 * so there's no need to increase the refcount */
-	err = -EEXIST;
-	if (!(nlh->nlmsg_flags & NLM_F_EXCL))
-		err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
-
-out_unlock:
-	write_unlock_bh(&ip_conntrack_lock);
-	return err;
-}
-
-/***********************************************************************
- * EXPECT
- ***********************************************************************/
-
-static inline int
-ctnetlink_exp_dump_tuple(struct sk_buff *skb,
-			 const struct ip_conntrack_tuple *tuple,
-			 enum ctattr_expect type)
-{
-	struct nfattr *nest_parms = NFA_NEST(skb, type);
-
-	if (ctnetlink_dump_tuples(skb, tuple) < 0)
-		goto nfattr_failure;
-
-	NFA_NEST_END(skb, nest_parms);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_exp_dump_mask(struct sk_buff *skb,
-			const struct ip_conntrack_tuple *tuple,
-			const struct ip_conntrack_tuple *mask)
-{
-	int ret;
-	struct ip_conntrack_protocol *proto;
-	struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK);
-
-	ret = ctnetlink_dump_tuples_ip(skb, mask);
-	if (unlikely(ret < 0))
-		goto nfattr_failure;
-
-	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
-	ret = ctnetlink_dump_tuples_proto(skb, mask, proto);
-	ip_conntrack_proto_put(proto);
-	if (unlikely(ret < 0))
-		goto nfattr_failure;
-
-	NFA_NEST_END(skb, nest_parms);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static inline int
-ctnetlink_exp_dump_expect(struct sk_buff *skb,
-			  const struct ip_conntrack_expect *exp)
-{
-	struct ip_conntrack *master = exp->master;
-	__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;
-	if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
-		goto nfattr_failure;
-	if (ctnetlink_exp_dump_tuple(skb,
-				 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
-				 CTA_EXPECT_MASTER) < 0)
-		goto nfattr_failure;
-
-	NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout);
-	NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static int
-ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
-		    int event,
-		    int nowait,
-		    const struct ip_conntrack_expect *exp)
-{
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	unsigned char *b;
-
-	b = skb->tail;
-
-	event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
-	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
-	nfmsg  = NLMSG_DATA(nlh);
-
-	nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;
-	nfmsg->nfgen_family = AF_INET;
-	nfmsg->version	    = NFNETLINK_V0;
-	nfmsg->res_id	    = 0;
-
-	if (ctnetlink_exp_dump_expect(skb, exp) < 0)
-		goto nfattr_failure;
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-nfattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-static int ctnetlink_expect_event(struct notifier_block *this,
-				  unsigned long events, void *ptr)
-{
-	struct nlmsghdr *nlh;
-	struct nfgenmsg *nfmsg;
-	struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;
-	struct sk_buff *skb;
-	unsigned int type;
-	unsigned char *b;
-	int flags = 0;
-
-	if (events & IPEXP_NEW) {
-		type = IPCTNL_MSG_EXP_NEW;
-		flags = NLM_F_CREATE|NLM_F_EXCL;
-	} 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;
-
-	b = skb->tail;
-
-	type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
-	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
-	nfmsg = NLMSG_DATA(nlh);
-
-	nlh->nlmsg_flags    = flags;
-	nfmsg->nfgen_family = AF_INET;
-	nfmsg->version	    = NFNETLINK_V0;
-	nfmsg->res_id	    = 0;
-
-	if (ctnetlink_exp_dump_expect(skb, exp) < 0)
-		goto nfattr_failure;
-
-	nlh->nlmsg_len = skb->tail - b;
-	nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);
-	return NOTIFY_DONE;
-
-nlmsg_failure:
-nfattr_failure:
-	kfree_skb(skb);
-	return NOTIFY_DONE;
-}
-#endif
-
-static int
-ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
-{
-	struct ip_conntrack_expect *exp = NULL;
-	struct list_head *i;
-	u_int32_t *id = (u_int32_t *) &cb->args[0];
-
-	read_lock_bh(&ip_conntrack_lock);
-	list_for_each_prev(i, &ip_conntrack_expect_list) {
-		exp = (struct ip_conntrack_expect *) i;
-		if (exp->id <= *id)
-			continue;
-		if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
-					    cb->nlh->nlmsg_seq,
-					    IPCTNL_MSG_EXP_NEW,
-					    1, exp) < 0)
-			goto out;
-		*id = exp->id;
-	}
-out:
-	read_unlock_bh(&ip_conntrack_lock);
-
-	return skb->len;
-}
-
-static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
-	[CTA_EXPECT_TIMEOUT-1]          = sizeof(__be32),
-	[CTA_EXPECT_ID-1]               = sizeof(__be32)
-};
-
-static int
-ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack_expect *exp;
-	struct sk_buff *skb2;
-	int err = 0;
-
-	if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
-		return -EINVAL;
-
-	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-		struct nfgenmsg *msg = NLMSG_DATA(nlh);
-		u32 rlen;
-
-		if (msg->nfgen_family != AF_INET)
-			return -EAFNOSUPPORT;
-
-		if ((*errp = netlink_dump_start(ctnl, skb, nlh,
-						ctnetlink_exp_dump_table,
-						ctnetlink_done)) != 0)
-			return -EINVAL;
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
-		return 0;
-	}
-
-	if (cda[CTA_EXPECT_MASTER-1])
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);
-	else
-		return -EINVAL;
-
-	if (err < 0)
-		return err;
-
-	exp = ip_conntrack_expect_find_get(&tuple);
-	if (!exp)
-		return -ENOENT;
-
-	if (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;
-		}
-	}
-
-	err = -ENOMEM;
-	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
-	if (!skb2)
-		goto out;
-
-	err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
-				      nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
-				      1, exp);
-	if (err <= 0)
-		goto free;
-
-	ip_conntrack_expect_put(exp);
-
-	return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
-
-free:
-	kfree_skb(skb2);
-out:
-	ip_conntrack_expect_put(exp);
-	return err;
-}
-
-static int
-ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_expect *exp, *tmp;
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack_helper *h;
-	int err;
-
-	if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
-		return -EINVAL;
-
-	if (cda[CTA_EXPECT_TUPLE-1]) {
-		/* delete a single expect by tuple */
-		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
-		if (err < 0)
-			return err;
-
-		/* bump usage count to 2 */
-		exp = ip_conntrack_expect_find_get(&tuple);
-		if (!exp)
-			return -ENOENT;
-
-		if (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;
-			}
-		}
-
-		/* after list removal, usage count == 1 */
-		ip_conntrack_unexpect_related(exp);
-		/* have to put what we 'get' above.
-		 * after this line usage count == 0 */
-		ip_conntrack_expect_put(exp);
-	} else if (cda[CTA_EXPECT_HELP_NAME-1]) {
-		char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
-
-		/* delete all expectations for this helper */
-		write_lock_bh(&ip_conntrack_lock);
-		h = __ip_conntrack_helper_find_byname(name);
-		if (!h) {
-			write_unlock_bh(&ip_conntrack_lock);
-			return -EINVAL;
-		}
-		list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
-					 list) {
-			if (exp->master->helper == h
-			    && del_timer(&exp->timeout)) {
-				ip_ct_unlink_expect(exp);
-				ip_conntrack_expect_put(exp);
-			}
-		}
-		write_unlock_bh(&ip_conntrack_lock);
-	} else {
-		/* This basically means we have to flush everything*/
-		write_lock_bh(&ip_conntrack_lock);
-		list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,
-					 list) {
-			if (del_timer(&exp->timeout)) {
-				ip_ct_unlink_expect(exp);
-				ip_conntrack_expect_put(exp);
-			}
-		}
-		write_unlock_bh(&ip_conntrack_lock);
-	}
-
-	return 0;
-}
-static int
-ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[])
-{
-	return -EOPNOTSUPP;
-}
-
-static int
-ctnetlink_create_expect(struct nfattr *cda[])
-{
-	struct ip_conntrack_tuple tuple, mask, master_tuple;
-	struct ip_conntrack_tuple_hash *h = NULL;
-	struct ip_conntrack_expect *exp;
-	struct ip_conntrack *ct;
-	int err = 0;
-
-	/* caller guarantees that those three CTA_EXPECT_* exist */
-	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
-	if (err < 0)
-		return err;
-	err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);
-	if (err < 0)
-		return err;
-	err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);
-	if (err < 0)
-		return err;
-
-	/* Look for master conntrack of this expectation */
-	h = ip_conntrack_find_get(&master_tuple, NULL);
-	if (!h)
-		return -ENOENT;
-	ct = tuplehash_to_ctrack(h);
-
-	if (!ct->helper) {
-		/* such conntrack hasn't got any helper, abort */
-		err = -EINVAL;
-		goto out;
-	}
-
-	exp = ip_conntrack_expect_alloc(ct);
-	if (!exp) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	exp->expectfn = NULL;
-	exp->flags = 0;
-	exp->master = ct;
-	memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));
-	memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));
-
-	err = ip_conntrack_expect_related(exp);
-	ip_conntrack_expect_put(exp);
-
-out:
-	ip_conntrack_put(tuplehash_to_ctrack(h));
-	return err;
-}
-
-static int
-ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
-{
-	struct ip_conntrack_tuple tuple;
-	struct ip_conntrack_expect *exp;
-	int err = 0;
-
-	if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
-		return -EINVAL;
-
-	if (!cda[CTA_EXPECT_TUPLE-1]
-	    || !cda[CTA_EXPECT_MASK-1]
-	    || !cda[CTA_EXPECT_MASTER-1])
-		return -EINVAL;
-
-	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
-	if (err < 0)
-		return err;
-
-	write_lock_bh(&ip_conntrack_lock);
-	exp = __ip_conntrack_expect_find(&tuple);
-
-	if (!exp) {
-		write_unlock_bh(&ip_conntrack_lock);
-		err = -ENOENT;
-		if (nlh->nlmsg_flags & NLM_F_CREATE)
-			err = ctnetlink_create_expect(cda);
-		return err;
-	}
-
-	err = -EEXIST;
-	if (!(nlh->nlmsg_flags & NLM_F_EXCL))
-		err = ctnetlink_change_expect(exp, cda);
-	write_unlock_bh(&ip_conntrack_lock);
-
-	return err;
-}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-static struct notifier_block ctnl_notifier = {
-	.notifier_call	= ctnetlink_conntrack_event,
-};
-
-static struct notifier_block ctnl_notifier_exp = {
-	.notifier_call	= ctnetlink_expect_event,
-};
-#endif
-
-static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
-	[IPCTNL_MSG_CT_NEW]		= { .call = ctnetlink_new_conntrack,
-					    .attr_count = CTA_MAX, },
-	[IPCTNL_MSG_CT_GET] 		= { .call = ctnetlink_get_conntrack,
-					    .attr_count = CTA_MAX, },
-	[IPCTNL_MSG_CT_DELETE]  	= { .call = ctnetlink_del_conntrack,
-					    .attr_count = CTA_MAX, },
-	[IPCTNL_MSG_CT_GET_CTRZERO] 	= { .call = ctnetlink_get_conntrack,
-					    .attr_count = CTA_MAX, },
-};
-
-static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
-	[IPCTNL_MSG_EXP_GET]		= { .call = ctnetlink_get_expect,
-					    .attr_count = CTA_EXPECT_MAX, },
-	[IPCTNL_MSG_EXP_NEW]		= { .call = ctnetlink_new_expect,
-					    .attr_count = CTA_EXPECT_MAX, },
-	[IPCTNL_MSG_EXP_DELETE]		= { .call = ctnetlink_del_expect,
-					    .attr_count = CTA_EXPECT_MAX, },
-};
-
-static struct nfnetlink_subsystem ctnl_subsys = {
-	.name				= "conntrack",
-	.subsys_id			= NFNL_SUBSYS_CTNETLINK,
-	.cb_count			= IPCTNL_MSG_MAX,
-	.cb				= ctnl_cb,
-};
-
-static struct nfnetlink_subsystem ctnl_exp_subsys = {
-	.name				= "conntrack_expect",
-	.subsys_id			= NFNL_SUBSYS_CTNETLINK_EXP,
-	.cb_count			= IPCTNL_MSG_EXP_MAX,
-	.cb				= ctnl_exp_cb,
-};
-
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
-
-static int __init ctnetlink_init(void)
-{
-	int ret;
-
-	printk("ctnetlink v%s: registering with nfnetlink.\n", version);
-	ret = nfnetlink_subsys_register(&ctnl_subsys);
-	if (ret < 0) {
-		printk("ctnetlink_init: cannot register with nfnetlink.\n");
-		goto err_out;
-	}
-
-	ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
-	if (ret < 0) {
-		printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
-		goto err_unreg_subsys;
-	}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-	ret = ip_conntrack_register_notifier(&ctnl_notifier);
-	if (ret < 0) {
-		printk("ctnetlink_init: cannot register notifier.\n");
-		goto err_unreg_exp_subsys;
-	}
-
-	ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp);
-	if (ret < 0) {
-		printk("ctnetlink_init: cannot expect register notifier.\n");
-		goto err_unreg_notifier;
-	}
-#endif
-
-	return 0;
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-err_unreg_notifier:
-	ip_conntrack_unregister_notifier(&ctnl_notifier);
-err_unreg_exp_subsys:
-	nfnetlink_subsys_unregister(&ctnl_exp_subsys);
-#endif
-err_unreg_subsys:
-	nfnetlink_subsys_unregister(&ctnl_subsys);
-err_out:
-	return ret;
-}
-
-static void __exit ctnetlink_exit(void)
-{
-	printk("ctnetlink: unregistering from nfnetlink.\n");
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-	ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
-	ip_conntrack_unregister_notifier(&ctnl_notifier);
-#endif
-
-	nfnetlink_subsys_unregister(&ctnl_exp_subsys);
-	nfnetlink_subsys_unregister(&ctnl_subsys);
-	return;
-}
-
-module_init(ctnetlink_init);
-module_exit(ctnetlink_exit);
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
deleted file mode 100644
index 88af82e..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/timer.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-
-unsigned int ip_ct_generic_timeout __read_mostly = 600*HZ;
-
-static int generic_pkt_to_tuple(const struct sk_buff *skb,
-				unsigned int dataoff,
-				struct ip_conntrack_tuple *tuple)
-{
-	tuple->src.u.all = 0;
-	tuple->dst.u.all = 0;
-
-	return 1;
-}
-
-static int generic_invert_tuple(struct ip_conntrack_tuple *tuple,
-				const struct ip_conntrack_tuple *orig)
-{
-	tuple->src.u.all = 0;
-	tuple->dst.u.all = 0;
-
-	return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static int generic_print_tuple(struct seq_file *s,
-			       const struct ip_conntrack_tuple *tuple)
-{
-	return 0;
-}
-
-/* Print out the private part of the conntrack. */
-static int generic_print_conntrack(struct seq_file *s,
-				   const struct ip_conntrack *state)
-{
-	return 0;
-}
-
-/* Returns verdict for packet, or -1 for invalid. */
-static int packet(struct ip_conntrack *conntrack,
-		  const struct sk_buff *skb,
-		  enum ip_conntrack_info ctinfo)
-{
-	ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout);
-	return NF_ACCEPT;
-}
-
-/* Called when a new connection for this protocol found. */
-static int new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
-{
-	return 1;
-}
-
-struct ip_conntrack_protocol ip_conntrack_generic_protocol =
-{
-	.proto			= 0,
-	.name			= "unknown",
-	.pkt_to_tuple		= generic_pkt_to_tuple,
-	.invert_tuple		= generic_invert_tuple,
-	.print_tuple		= generic_print_tuple,
-	.print_conntrack	= generic_print_conntrack,
-	.packet			= packet,
-	.new			= new,
-};
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c
deleted file mode 100644
index ac1c49e..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+++ /dev/null
@@ -1,328 +0,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
- * connections between the same two hosts.
- *
- * 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
- * field in plain GRE.
- *
- * Documentation about PPTP can be found in RFC 2637
- *
- * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/list.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-
-static DEFINE_RWLOCK(ip_ct_gre_lock);
-
-#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/ip_conntrack_proto_gre.h>
-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
-
-/* shamelessly stolen from ip_conntrack_proto_udp.c */
-#define GRE_TIMEOUT		(30*HZ)
-#define GRE_STREAM_TIMEOUT	(180*HZ)
-
-#if 0
-#define DEBUGP(format, args...)	printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
-#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \
-			NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \
-			NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key))
-#else
-#define DEBUGP(x, args...)
-#define DUMP_TUPLE_GRE(x)
-#endif
-
-/* GRE KEYMAP HANDLING FUNCTIONS */
-static LIST_HEAD(gre_keymap_list);
-
-static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
-				const struct ip_conntrack_tuple *t)
-{
-	return ((km->tuple.src.ip == t->src.ip) &&
-		(km->tuple.dst.ip == t->dst.ip) &&
-		(km->tuple.dst.protonum == t->dst.protonum) &&
-		(km->tuple.dst.u.all == t->dst.u.all));
-}
-
-/* look up the source key for a given tuple */
-static __be16 gre_keymap_lookup(struct ip_conntrack_tuple *t)
-{
-	struct ip_ct_gre_keymap *km;
-	__be16 key = 0;
-
-	read_lock_bh(&ip_ct_gre_lock);
-	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);
-
-	return key;
-}
-
-/* add a single keymap entry, associate with specified master ct */
-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;
-
-	if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
-		DEBUGP("refusing to add GRE keymap to non-pptp session\n");
-		return -1;
-	}
-
-	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 */
-		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",
-			reply? "reply":"orig", ct);
-		return -EEXIST;
-	}
-
-	km = kmalloc(sizeof(*km), GFP_ATOMIC);
-	if (!km)
-		return -ENOMEM;
-
-	memcpy(&km->tuple, t, sizeof(*t));
-	*exist_km = km;
-
-	DEBUGP("adding new entry %p: ", km);
-	DUMP_TUPLE_GRE(&km->tuple);
-
-	write_lock_bh(&ip_ct_gre_lock);
-	list_add_tail(&km->list, &gre_keymap_list);
-	write_unlock_bh(&ip_ct_gre_lock);
-
-	return 0;
-}
-
-/* destroy the keymap entries associated with specified master ct */
-void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)
-{
-	DEBUGP("entering for ct %p\n", ct);
-
-	if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
-		DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");
-		return;
-	}
-
-	write_lock_bh(&ip_ct_gre_lock);
-	if (ct->help.ct_pptp_info.keymap_orig) {
-		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);
-		ct->help.ct_pptp_info.keymap_orig = NULL;
-	}
-	if (ct->help.ct_pptp_info.keymap_reply) {
-		DEBUGP("removing %p from list\n",
-			ct->help.ct_pptp_info.keymap_reply);
-		list_del(&ct->help.ct_pptp_info.keymap_reply->list);
-		kfree(ct->help.ct_pptp_info.keymap_reply);
-		ct->help.ct_pptp_info.keymap_reply = NULL;
-	}
-	write_unlock_bh(&ip_ct_gre_lock);
-}
-
-
-/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
-
-/* invert gre part of tuple */
-static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
-			    const struct ip_conntrack_tuple *orig)
-{
-	tuple->dst.u.gre.key = orig->src.u.gre.key;
-	tuple->src.u.gre.key = orig->dst.u.gre.key;
-
-	return 1;
-}
-
-/* gre hdr info to tuple */
-static int gre_pkt_to_tuple(const struct sk_buff *skb,
-			   unsigned int dataoff,
-			   struct ip_conntrack_tuple *tuple)
-{
-	struct gre_hdr_pptp _pgrehdr, *pgrehdr;
-	__be16 srckey;
-	struct gre_hdr _grehdr, *grehdr;
-
-	/* first only delinearize old RFC1701 GRE header */
-	grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
-	if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {
-		/* try to behave like "ip_conntrack_proto_generic" */
-		tuple->src.u.all = 0;
-		tuple->dst.u.all = 0;
-		return 1;
-	}
-
-	/* PPTP header is variable length, only need up to the call_id field */
-	pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
-	if (!pgrehdr)
-		return 1;
-
-	if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
-		DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
-		return 0;
-	}
-
-	tuple->dst.u.gre.key = pgrehdr->call_id;
-	srckey = gre_keymap_lookup(tuple);
-	tuple->src.u.gre.key = srckey;
-
-	return 1;
-}
-
-/* print gre part of tuple */
-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 ",
-			  ntohs(tuple->src.u.gre.key),
-			  ntohs(tuple->dst.u.gre.key));
-}
-
-/* print private data for conntrack */
-static int gre_print_conntrack(struct seq_file *s,
-			       const struct ip_conntrack *ct)
-{
-	return seq_printf(s, "timeout=%u, stream_timeout=%u ",
-			  (ct->proto.gre.timeout / HZ),
-			  (ct->proto.gre.stream_timeout / HZ));
-}
-
-/* Returns verdict for packet, and may modify conntrack */
-static int gre_packet(struct ip_conntrack *ct,
-		      const struct sk_buff *skb,
-		      enum ip_conntrack_info conntrackinfo)
-{
-	/* If we've seen traffic both ways, this is a GRE connection.
-	 * Extend timeout. */
-	if (ct->status & IPS_SEEN_REPLY) {
-		ip_ct_refresh_acct(ct, conntrackinfo, skb,
-				   ct->proto.gre.stream_timeout);
-		/* Also, more likely to be important, and not a probe. */
-		set_bit(IPS_ASSURED_BIT, &ct->status);
-		ip_conntrack_event_cache(IPCT_STATUS, skb);
-	} 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);
-
-	/* initialize to sane value.  Ideally a conntrack helper
-	 * (e.g. in case of pptp) is increasing them */
-	ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
-	ct->proto.gre.timeout = GRE_TIMEOUT;
-
-	return 1;
-}
-
-/* Called when a conntrack entry has already been removed from the hashes
- * and is about to be deleted from memory */
-static void gre_destroy(struct ip_conntrack *ct)
-{
-	struct ip_conntrack *master = ct->master;
-	DEBUGP(" entering\n");
-
-	if (!master)
-		DEBUGP("no master !?!\n");
-	else
-		ip_ct_gre_keymap_destroy(master);
-}
-
-/* protocol helper struct */
-static struct ip_conntrack_protocol gre = {
-	.proto		 = IPPROTO_GRE,
-	.name		 = "gre",
-	.pkt_to_tuple	 = gre_pkt_to_tuple,
-	.invert_tuple	 = gre_invert_tuple,
-	.print_tuple	 = gre_print_tuple,
-	.print_conntrack = gre_print_conntrack,
-	.packet		 = gre_packet,
-	.new		 = gre_new,
-	.destroy	 = gre_destroy,
-	.me 		 = THIS_MODULE,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
-	.nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
-#endif
-};
-
-/* ip_conntrack_proto_gre initialization */
-int __init ip_ct_proto_gre_init(void)
-{
-	return ip_conntrack_protocol_register(&gre);
-}
-
-/* This cannot be __exit, as it is invoked from ip_conntrack_helper_pptp.c's
- * init() code on errors.
- */
-void ip_ct_proto_gre_fini(void)
-{
-	struct list_head *pos, *n;
-
-	/* delete all keymap entries */
-	write_lock_bh(&ip_ct_gre_lock);
-	list_for_each_safe(pos, n, &gre_keymap_list) {
-		DEBUGP("deleting keymap %p at module unload time\n", pos);
-		list_del(pos);
-		kfree(pos);
-	}
-	write_unlock_bh(&ip_ct_gre_lock);
-
-	ip_conntrack_protocol_unregister(&gre);
-}
-
-EXPORT_SYMBOL(ip_ct_gre_keymap_add);
-EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
deleted file mode 100644
index ad70c81..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/timer.h>
-#include <linux/netfilter.h>
-#include <linux/in.h>
-#include <linux/icmp.h>
-#include <linux/seq_file.h>
-#include <linux/skbuff.h>
-#include <net/ip.h>
-#include <net/checksum.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-
-unsigned int ip_ct_icmp_timeout __read_mostly = 30*HZ;
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int icmp_pkt_to_tuple(const struct sk_buff *skb,
-			     unsigned int dataoff,
-			     struct ip_conntrack_tuple *tuple)
-{
-	struct icmphdr _hdr, *hp;
-
-	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
-	if (hp == NULL)
-		return 0;
-
-	tuple->dst.u.icmp.type = hp->type;
-	tuple->src.u.icmp.id = hp->un.echo.id;
-	tuple->dst.u.icmp.code = hp->code;
-
-	return 1;
-}
-
-/* Add 1; spaces filled with 0. */
-static const u_int8_t invmap[] = {
-	[ICMP_ECHO] = ICMP_ECHOREPLY + 1,
-	[ICMP_ECHOREPLY] = ICMP_ECHO + 1,
-	[ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
-	[ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
-	[ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
-	[ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
-	[ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
-	[ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
-};
-
-static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
-			     const struct ip_conntrack_tuple *orig)
-{
-	if (orig->dst.u.icmp.type >= sizeof(invmap)
-	    || !invmap[orig->dst.u.icmp.type])
-		return 0;
-
-	tuple->src.u.icmp.id = orig->src.u.icmp.id;
-	tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
-	tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
-	return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static int icmp_print_tuple(struct seq_file *s,
-			    const struct ip_conntrack_tuple *tuple)
-{
-	return seq_printf(s, "type=%u code=%u id=%u ",
-			  tuple->dst.u.icmp.type,
-			  tuple->dst.u.icmp.code,
-			  ntohs(tuple->src.u.icmp.id));
-}
-
-/* Print out the private part of the conntrack. */
-static int icmp_print_conntrack(struct seq_file *s,
-				const struct ip_conntrack *conntrack)
-{
-	return 0;
-}
-
-/* Returns verdict for packet, or -1 for invalid. */
-static int icmp_packet(struct ip_conntrack *ct,
-		       const struct sk_buff *skb,
-		       enum ip_conntrack_info ctinfo)
-{
-	/* Try to delete connection immediately after all replies:
-	   won't actually vanish as we still have skb, and del_timer
-	   means this will only run once even if count hits zero twice
-	   (theoretically possible with SMP) */
-	if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
-		if (atomic_dec_and_test(&ct->proto.icmp.count)
-		    && del_timer(&ct->timeout))
-			ct->timeout.function((unsigned long)ct);
-	} else {
-		atomic_inc(&ct->proto.icmp.count);
-		ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
-		ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
-	}
-
-	return NF_ACCEPT;
-}
-
-/* Called when a new connection for this protocol found. */
-static int icmp_new(struct ip_conntrack *conntrack,
-		    const struct sk_buff *skb)
-{
-	static const u_int8_t valid_new[] = {
-		[ICMP_ECHO] = 1,
-		[ICMP_TIMESTAMP] = 1,
-		[ICMP_INFO_REQUEST] = 1,
-		[ICMP_ADDRESS] = 1
-	};
-
-	if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
-	    || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
-		/* Can't create a new ICMP `conn' with this. */
-		DEBUGP("icmp: can't create new conn with type %u\n",
-		       conntrack->tuplehash[0].tuple.dst.u.icmp.type);
-		DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
-		return 0;
-	}
-	atomic_set(&conntrack->proto.icmp.count, 0);
-	return 1;
-}
-
-static int
-icmp_error_message(struct sk_buff *skb,
-		   enum ip_conntrack_info *ctinfo,
-		   unsigned int hooknum)
-{
-	struct ip_conntrack_tuple innertuple, origtuple;
-	struct {
-		struct icmphdr icmp;
-		struct iphdr ip;
-	} _in, *inside;
-	struct ip_conntrack_protocol *innerproto;
-	struct ip_conntrack_tuple_hash *h;
-	int dataoff;
-
-	IP_NF_ASSERT(skb->nfct == NULL);
-
-	/* Not enough header? */
-	inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
-	if (inside == NULL)
-		return -NF_ACCEPT;
-
-	/* Ignore ICMP's containing fragments (shouldn't happen) */
-	if (inside->ip.frag_off & htons(IP_OFFSET)) {
-		DEBUGP("icmp_error_track: fragment of proto %u\n",
-		       inside->ip.protocol);
-		return -NF_ACCEPT;
-	}
-
-	innerproto = ip_conntrack_proto_find_get(inside->ip.protocol);
-	dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp) + inside->ip.ihl*4;
-	/* Are they talking about one of our connections? */
-	if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
-		DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
-		ip_conntrack_proto_put(innerproto);
-		return -NF_ACCEPT;
-	}
-
-	/* Ordinarily, we'd expect the inverted tupleproto, but it's
-	   been preserved inside the ICMP. */
-	if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
-		DEBUGP("icmp_error_track: Can't invert tuple\n");
-		ip_conntrack_proto_put(innerproto);
-		return -NF_ACCEPT;
-	}
-	ip_conntrack_proto_put(innerproto);
-
-	*ctinfo = IP_CT_RELATED;
-
-	h = ip_conntrack_find_get(&innertuple, NULL);
-	if (!h) {
-		/* Locally generated ICMPs will match inverted if they
-		   haven't been SNAT'ed yet */
-		/* FIXME: NAT code has to handle half-done double NAT --RR */
-		if (hooknum == NF_IP_LOCAL_OUT)
-			h = ip_conntrack_find_get(&origtuple, NULL);
-
-		if (!h) {
-			DEBUGP("icmp_error_track: no match\n");
-			return -NF_ACCEPT;
-		}
-		/* Reverse direction from that found */
-		if (DIRECTION(h) != IP_CT_DIR_REPLY)
-			*ctinfo += IP_CT_IS_REPLY;
-	} else {
-		if (DIRECTION(h) == IP_CT_DIR_REPLY)
-			*ctinfo += IP_CT_IS_REPLY;
-	}
-
-	/* Update skb to refer to this connection */
-	skb->nfct = &tuplehash_to_ctrack(h)->ct_general;
-	skb->nfctinfo = *ctinfo;
-	return -NF_ACCEPT;
-}
-
-/* Small and modified version of icmp_rcv */
-static int
-icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
-	   unsigned int hooknum)
-{
-	struct icmphdr _ih, *icmph;
-
-	/* Not enough header? */
-	icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
-	if (icmph == NULL) {
-		if (LOG_INVALID(IPPROTO_ICMP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				      "ip_ct_icmp: short packet ");
-		return -NF_ACCEPT;
-	}
-
-	/* See ip_conntrack_proto_tcp.c */
-	if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
-	    nf_ip_checksum(skb, hooknum, skb->nh.iph->ihl * 4, 0)) {
-		if (LOG_INVALID(IPPROTO_ICMP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				      "ip_ct_icmp: bad ICMP checksum ");
-		return -NF_ACCEPT;
-	}
-
-	/*
-	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
-	 *
-	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
-	 *		  discarded.
-	 */
-	if (icmph->type > NR_ICMP_TYPES) {
-		if (LOG_INVALID(IPPROTO_ICMP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				      "ip_ct_icmp: invalid ICMP type ");
-		return -NF_ACCEPT;
-	}
-
-	/* Need to track icmp error message? */
-	if (icmph->type != ICMP_DEST_UNREACH
-	    && icmph->type != ICMP_SOURCE_QUENCH
-	    && icmph->type != ICMP_TIME_EXCEEDED
-	    && icmph->type != ICMP_PARAMETERPROB
-	    && icmph->type != ICMP_REDIRECT)
-		return NF_ACCEPT;
-
-	return icmp_error_message(skb, ctinfo, hooknum);
-}
-
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-static int icmp_tuple_to_nfattr(struct sk_buff *skb,
-				const struct ip_conntrack_tuple *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);
-	NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
-		&t->dst.u.icmp.code);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-static int icmp_nfattr_to_tuple(struct nfattr *tb[],
-				struct ip_conntrack_tuple *tuple)
-{
-	if (!tb[CTA_PROTO_ICMP_TYPE-1]
-	    || !tb[CTA_PROTO_ICMP_CODE-1]
-	    || !tb[CTA_PROTO_ICMP_ID-1])
-		return -EINVAL;
-
-	tuple->dst.u.icmp.type =
-			*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
-	tuple->dst.u.icmp.code =
-			*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
-	tuple->src.u.icmp.id =
-			*(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
-
-	if (tuple->dst.u.icmp.type >= sizeof(invmap)
-	    || !invmap[tuple->dst.u.icmp.type])
-		return -EINVAL;
-
-	return 0;
-}
-#endif
-
-struct ip_conntrack_protocol ip_conntrack_protocol_icmp =
-{
-	.proto 			= IPPROTO_ICMP,
-	.name 			= "icmp",
-	.pkt_to_tuple		= icmp_pkt_to_tuple,
-	.invert_tuple		= icmp_invert_tuple,
-	.print_tuple		= icmp_print_tuple,
-	.print_conntrack	= icmp_print_conntrack,
-	.packet			= icmp_packet,
-	.new			= icmp_new,
-	.error			= icmp_error,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.tuple_to_nfattr	= icmp_tuple_to_nfattr,
-	.nfattr_to_tuple	= icmp_nfattr_to_tuple,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
deleted file mode 100644
index e694299..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Connection tracking protocol helper module for SCTP.
- *
- * SCTP is defined in RFC 2960. References to various sections in this code
- * are to this RFC.
- *
- * This program is free software; you can 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 support for proc manipulation of timeouts.
- */
-
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/netfilter.h>
-#include <linux/module.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/sctp.h>
-#include <linux/string.h>
-#include <linux/seq_file.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-
-#if 0
-#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/* Protects conntrack->proto.sctp */
-static DEFINE_RWLOCK(sctp_lock);
-
-/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
-   closely.  They're more complex. --RR
-
-   And so for me for SCTP :D -Kiran */
-
-static const char *sctp_conntrack_names[] = {
-	"NONE",
-	"CLOSED",
-	"COOKIE_WAIT",
-	"COOKIE_ECHOED",
-	"ESTABLISHED",
-	"SHUTDOWN_SENT",
-	"SHUTDOWN_RECD",
-	"SHUTDOWN_ACK_SENT",
-};
-
-#define SECS  * HZ
-#define MINS  * 60 SECS
-#define HOURS * 60 MINS
-#define DAYS  * 24 HOURS
-
-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  */
-    &ip_ct_sctp_timeout_closed,	           /* SCTP_CONNTRACK_CLOSED */
-    &ip_ct_sctp_timeout_cookie_wait,       /* SCTP_CONNTRACK_COOKIE_WAIT */
-    &ip_ct_sctp_timeout_cookie_echoed,     /* SCTP_CONNTRACK_COOKIE_ECHOED */
-    &ip_ct_sctp_timeout_established,       /* SCTP_CONNTRACK_ESTABLISHED */
-    &ip_ct_sctp_timeout_shutdown_sent,     /* SCTP_CONNTRACK_SHUTDOWN_SENT */
-    &ip_ct_sctp_timeout_shutdown_recd,     /* SCTP_CONNTRACK_SHUTDOWN_RECD */
-    &ip_ct_sctp_timeout_shutdown_ack_sent  /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */
- };
-
-#define sNO SCTP_CONNTRACK_NONE
-#define	sCL SCTP_CONNTRACK_CLOSED
-#define	sCW SCTP_CONNTRACK_COOKIE_WAIT
-#define	sCE SCTP_CONNTRACK_COOKIE_ECHOED
-#define	sES SCTP_CONNTRACK_ESTABLISHED
-#define	sSS SCTP_CONNTRACK_SHUTDOWN_SENT
-#define	sSR SCTP_CONNTRACK_SHUTDOWN_RECD
-#define	sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
-#define	sIV SCTP_CONNTRACK_MAX
-
-/*
-	These are the descriptions of the states:
-
-NOTE: These state names are tantalizingly similar to the states of an
-SCTP endpoint. But the interpretation of the states is a little different,
-considering that these are the states of the connection and not of an end
-point. Please note the subtleties. -Kiran
-
-NONE              - Nothing so far.
-COOKIE WAIT       - We have seen an INIT chunk in the original direction, or also
-		    an INIT_ACK chunk in the reply direction.
-COOKIE ECHOED     - We have seen a COOKIE_ECHO chunk in the original direction.
-ESTABLISHED       - We have seen a COOKIE_ACK in the reply direction.
-SHUTDOWN_SENT     - We have seen a SHUTDOWN chunk in the original direction.
-SHUTDOWN_RECD     - We have seen a SHUTDOWN chunk in the reply directoin.
-SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
-		    to that of the SHUTDOWN chunk.
-CLOSED            - We have seen a SHUTDOWN_COMPLETE chunk in the direction of
-		    the SHUTDOWN chunk. Connection is closed.
-*/
-
-/* TODO
- - I have assumed that the first INIT is in the original direction.
- This messes things when an INIT comes in the reply direction in CLOSED
- state.
- - Check the error type in the reply dir before transitioning from
-cookie echoed to closed.
- - Sec 5.2.4 of RFC 2960
- - Multi Homing support.
-*/
-
-/* SCTP conntrack state transitions */
-static const enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
-	{
-/*	ORIGINAL	*/
-/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
-/* init         */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},
-/* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},
-/* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
-/* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
-/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
-/* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
-/* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
-/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
-/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
-	},
-	{
-/*	REPLY	*/
-/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
-/* init         */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */
-/* init_ack     */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},
-/* abort        */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
-/* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
-/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
-/* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
-/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
-/* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
-/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
-	}
-};
-
-static int sctp_pkt_to_tuple(const struct sk_buff *skb,
-			     unsigned int dataoff,
-			     struct ip_conntrack_tuple *tuple)
-{
-	sctp_sctphdr_t _hdr, *hp;
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	/* Actually only need first 8 bytes. */
-	hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
-	if (hp == NULL)
-		return 0;
-
-	tuple->src.u.sctp.port = hp->source;
-	tuple->dst.u.sctp.port = hp->dest;
-	return 1;
-}
-
-static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple,
-			     const struct ip_conntrack_tuple *orig)
-{
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	tuple->src.u.sctp.port = orig->dst.u.sctp.port;
-	tuple->dst.u.sctp.port = orig->src.u.sctp.port;
-	return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static int sctp_print_tuple(struct seq_file *s,
-			    const struct ip_conntrack_tuple *tuple)
-{
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	return seq_printf(s, "sport=%hu dport=%hu ",
-			  ntohs(tuple->src.u.sctp.port),
-			  ntohs(tuple->dst.u.sctp.port));
-}
-
-/* Print out the private part of the conntrack. */
-static int sctp_print_conntrack(struct seq_file *s,
-				const struct ip_conntrack *conntrack)
-{
-	enum sctp_conntrack state;
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	read_lock_bh(&sctp_lock);
-	state = conntrack->proto.sctp.state;
-	read_unlock_bh(&sctp_lock);
-
-	return seq_printf(s, "%s ", sctp_conntrack_names[state]);
-}
-
-#define for_each_sctp_chunk(skb, sch, _sch, offset, count)		\
-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 += (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,
-			   const struct sk_buff *skb,
-			   char *map)
-{
-	u_int32_t offset, count;
-	sctp_chunkhdr_t _sch, *sch;
-	int flag;
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	flag = 0;
-
-	for_each_sctp_chunk (skb, sch, _sch, offset, count) {
-		DEBUGP("Chunk Num: %d  Type: %d\n", count, sch->type);
-
-		if (sch->type == SCTP_CID_INIT
-			|| sch->type == SCTP_CID_INIT_ACK
-			|| sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
-			flag = 1;
-		}
-
-		/*
-		 * Cookie Ack/Echo chunks not the first OR
-		 * Init / Init Ack / Shutdown compl chunks not the only chunks
-		 * OR zero-length.
-		 */
-		if (((sch->type == SCTP_CID_COOKIE_ACK
-			|| sch->type == SCTP_CID_COOKIE_ECHO
-			|| flag)
-		      && count !=0) || !sch->length) {
-			DEBUGP("Basic checks failed\n");
-			return 1;
-		}
-
-		if (map) {
-			set_bit(sch->type, (void *)map);
-		}
-	}
-
-	DEBUGP("Basic checks passed\n");
-	return count == 0;
-}
-
-static int new_state(enum ip_conntrack_dir dir,
-		     enum sctp_conntrack cur_state,
-		     int chunk_type)
-{
-	int i;
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	DEBUGP("Chunk type: %d\n", chunk_type);
-
-	switch (chunk_type) {
-		case SCTP_CID_INIT:
-			DEBUGP("SCTP_CID_INIT\n");
-			i = 0; break;
-		case SCTP_CID_INIT_ACK:
-			DEBUGP("SCTP_CID_INIT_ACK\n");
-			i = 1; break;
-		case SCTP_CID_ABORT:
-			DEBUGP("SCTP_CID_ABORT\n");
-			i = 2; break;
-		case SCTP_CID_SHUTDOWN:
-			DEBUGP("SCTP_CID_SHUTDOWN\n");
-			i = 3; break;
-		case SCTP_CID_SHUTDOWN_ACK:
-			DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
-			i = 4; break;
-		case SCTP_CID_ERROR:
-			DEBUGP("SCTP_CID_ERROR\n");
-			i = 5; break;
-		case SCTP_CID_COOKIE_ECHO:
-			DEBUGP("SCTP_CID_COOKIE_ECHO\n");
-			i = 6; break;
-		case SCTP_CID_COOKIE_ACK:
-			DEBUGP("SCTP_CID_COOKIE_ACK\n");
-			i = 7; break;
-		case SCTP_CID_SHUTDOWN_COMPLETE:
-			DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
-			i = 8; break;
-		default:
-			/* Other chunks like DATA, SACK, HEARTBEAT and
-			its ACK do not cause a change in state */
-			DEBUGP("Unknown chunk type, Will stay in %s\n",
-						sctp_conntrack_names[cur_state]);
-			return cur_state;
-	}
-
-	DEBUGP("dir: %d   cur_state: %s  chunk_type: %d  new_state: %s\n",
-			dir, sctp_conntrack_names[cur_state], chunk_type,
-			sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
-
-	return sctp_conntracks[dir][i][cur_state];
-}
-
-/* Returns verdict for packet, or -1 for invalid. */
-static int sctp_packet(struct ip_conntrack *conntrack,
-		       const struct sk_buff *skb,
-		       enum ip_conntrack_info ctinfo)
-{
-	enum sctp_conntrack newconntrack, oldsctpstate;
-	struct iphdr *iph = skb->nh.iph;
-	sctp_sctphdr_t _sctph, *sh;
-	sctp_chunkhdr_t _sch, *sch;
-	u_int32_t offset, count;
-	char map[256 / sizeof (char)] = {0};
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
-	if (sh == NULL)
-		return -1;
-
-	if (do_basic_checks(conntrack, skb, map) != 0)
-		return -1;
-
-	/* Check the verification tag (Sec 8.5) */
-	if (!test_bit(SCTP_CID_INIT, (void *)map)
-		&& !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)
-		&& !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
-		&& !test_bit(SCTP_CID_ABORT, (void *)map)
-		&& !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
-		&& (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
-		DEBUGP("Verification tag check failed\n");
-		return -1;
-	}
-
-	oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
-	for_each_sctp_chunk (skb, sch, _sch, offset, count) {
-		write_lock_bh(&sctp_lock);
-
-		/* Special cases of Verification tag check (Sec 8.5.1) */
-		if (sch->type == SCTP_CID_INIT) {
-			/* Sec 8.5.1 (A) */
-			if (sh->vtag != 0) {
-				write_unlock_bh(&sctp_lock);
-				return -1;
-			}
-		} else if (sch->type == SCTP_CID_ABORT) {
-			/* Sec 8.5.1 (B) */
-			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
-				&& !(sh->vtag == conntrack->proto.sctp.vtag
-							[1 - CTINFO2DIR(ctinfo)])) {
-				write_unlock_bh(&sctp_lock);
-				return -1;
-			}
-		} else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
-			/* Sec 8.5.1 (C) */
-			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
-				&& !(sh->vtag == conntrack->proto.sctp.vtag
-							[1 - CTINFO2DIR(ctinfo)]
-					&& (sch->flags & 1))) {
-				write_unlock_bh(&sctp_lock);
-				return -1;
-			}
-		} else if (sch->type == SCTP_CID_COOKIE_ECHO) {
-			/* Sec 8.5.1 (D) */
-			if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
-				write_unlock_bh(&sctp_lock);
-				return -1;
-			}
-		}
-
-		oldsctpstate = conntrack->proto.sctp.state;
-		newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type);
-
-		/* Invalid */
-		if (newconntrack == SCTP_CONNTRACK_MAX) {
-			DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
-			       CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
-			write_unlock_bh(&sctp_lock);
-			return -1;
-		}
-
-		/* If it is an INIT or an INIT ACK note down the vtag */
-		if (sch->type == SCTP_CID_INIT
-			|| sch->type == SCTP_CID_INIT_ACK) {
-			sctp_inithdr_t _inithdr, *ih;
-
-			ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
-						sizeof(_inithdr), &_inithdr);
-			if (ih == NULL) {
-					write_unlock_bh(&sctp_lock);
-					return -1;
-			}
-			DEBUGP("Setting vtag %x for dir %d\n",
-					ih->init_tag, !CTINFO2DIR(ctinfo));
-			conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag;
-		}
-
-		conntrack->proto.sctp.state = newconntrack;
-		if (oldsctpstate != newconntrack)
-			ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
-		write_unlock_bh(&sctp_lock);
-	}
-
-	ip_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]);
-
-	if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
-		&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
-		&& newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
-		DEBUGP("Setting assured bit\n");
-		set_bit(IPS_ASSURED_BIT, &conntrack->status);
-		ip_conntrack_event_cache(IPCT_STATUS, skb);
-	}
-
-	return NF_ACCEPT;
-}
-
-/* Called when a new connection for this protocol found. */
-static int sctp_new(struct ip_conntrack *conntrack,
-		    const struct sk_buff *skb)
-{
-	enum sctp_conntrack newconntrack;
-	struct iphdr *iph = skb->nh.iph;
-	sctp_sctphdr_t _sctph, *sh;
-	sctp_chunkhdr_t _sch, *sch;
-	u_int32_t offset, count;
-	char map[256 / sizeof (char)] = {0};
-
-	DEBUGP(__FUNCTION__);
-	DEBUGP("\n");
-
-	sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
-	if (sh == NULL)
-		return 0;
-
-	if (do_basic_checks(conntrack, skb, map) != 0)
-		return 0;
-
-	/* If an OOTB packet has any of these chunks discard (Sec 8.4) */
-	if ((test_bit (SCTP_CID_ABORT, (void *)map))
-		|| (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map))
-		|| (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) {
-		return 0;
-	}
-
-	newconntrack = SCTP_CONNTRACK_MAX;
-	for_each_sctp_chunk (skb, sch, _sch, offset, count) {
-		/* Don't need lock here: this conntrack not in circulation yet */
-		newconntrack = new_state (IP_CT_DIR_ORIGINAL,
-						SCTP_CONNTRACK_NONE, sch->type);
-
-		/* Invalid: delete conntrack */
-		if (newconntrack == SCTP_CONNTRACK_MAX) {
-			DEBUGP("ip_conntrack_sctp: invalid new deleting.\n");
-			return 0;
-		}
-
-		/* Copy the vtag into the state info */
-		if (sch->type == SCTP_CID_INIT) {
-			if (sh->vtag == 0) {
-				sctp_inithdr_t _inithdr, *ih;
-
-				ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
-							sizeof(_inithdr), &_inithdr);
-				if (ih == NULL)
-					return 0;
-
-				DEBUGP("Setting vtag %x for new conn\n",
-					ih->init_tag);
-
-				conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] =
-								ih->init_tag;
-			} else {
-				/* Sec 8.5.1 (A) */
-				return 0;
-			}
-		}
-		/* If it is a shutdown ack OOTB packet, we expect a return
-		   shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
-		else {
-			DEBUGP("Setting vtag %x for new conn OOTB\n",
-				sh->vtag);
-			conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
-		}
-
-		conntrack->proto.sctp.state = newconntrack;
-	}
-
-	return 1;
-}
-
-static struct ip_conntrack_protocol ip_conntrack_protocol_sctp = {
-	.proto 		 = IPPROTO_SCTP,
-	.name 		 = "sctp",
-	.pkt_to_tuple 	 = sctp_pkt_to_tuple,
-	.invert_tuple 	 = sctp_invert_tuple,
-	.print_tuple 	 = sctp_print_tuple,
-	.print_conntrack = sctp_print_conntrack,
-	.packet 	 = sctp_packet,
-	.new 		 = sctp_new,
-	.destroy 	 = NULL,
-	.me 		 = THIS_MODULE,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
-	.nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
-#endif
-};
-
-#ifdef CONFIG_SYSCTL
-static ctl_table ip_ct_sysctl_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,
-		.procname	= "ip_conntrack_sctp_timeout_closed",
-		.data		= &ip_ct_sctp_timeout_closed,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,
-		.procname	= "ip_conntrack_sctp_timeout_cookie_wait",
-		.data		= &ip_ct_sctp_timeout_cookie_wait,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,
-		.procname	= "ip_conntrack_sctp_timeout_cookie_echoed",
-		.data		= &ip_ct_sctp_timeout_cookie_echoed,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,
-		.procname	= "ip_conntrack_sctp_timeout_established",
-		.data		= &ip_ct_sctp_timeout_established,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,
-		.procname	= "ip_conntrack_sctp_timeout_shutdown_sent",
-		.data		= &ip_ct_sctp_timeout_shutdown_sent,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,
-		.procname	= "ip_conntrack_sctp_timeout_shutdown_recd",
-		.data		= &ip_ct_sctp_timeout_shutdown_recd,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,
-		.procname	= "ip_conntrack_sctp_timeout_shutdown_ack_sent",
-		.data		= &ip_ct_sctp_timeout_shutdown_ack_sent,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ip_ct_netfilter_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NETFILTER,
-		.procname	= "netfilter",
-		.mode		= 0555,
-		.child		= ip_ct_sysctl_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ip_ct_ipv4_table[] = {
-	{
-		.ctl_name	= NET_IPV4,
-		.procname	= "ipv4",
-		.mode		= 0555,
-		.child		= ip_ct_netfilter_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ip_ct_net_table[] = {
-	{
-		.ctl_name	= CTL_NET,
-		.procname	= "net",
-		.mode		= 0555,
-		.child		= ip_ct_ipv4_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static struct ctl_table_header *ip_ct_sysctl_header;
-#endif
-
-static int __init ip_conntrack_proto_sctp_init(void)
-{
-	int ret;
-
-	ret = ip_conntrack_protocol_register(&ip_conntrack_protocol_sctp);
-	if (ret) {
-		printk("ip_conntrack_proto_sctp: protocol register failed\n");
-		goto out;
-	}
-
-#ifdef CONFIG_SYSCTL
-	ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table);
-	if (ip_ct_sysctl_header == NULL) {
-		ret = -ENOMEM;
-		printk("ip_conntrack_proto_sctp: can't register to sysctl.\n");
-		goto cleanup;
-	}
-#endif
-
-	return ret;
-
-#ifdef CONFIG_SYSCTL
- cleanup:
-	ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
-#endif
- out:
-	DEBUGP("SCTP conntrack module loading %s\n",
-					ret ? "failed": "succeeded");
-	return ret;
-}
-
-static void __exit ip_conntrack_proto_sctp_fini(void)
-{
-	ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
-#ifdef CONFIG_SYSCTL
-	unregister_sysctl_table(ip_ct_sysctl_header);
-#endif
-	DEBUGP("SCTP conntrack module unloaded\n");
-}
-
-module_init(ip_conntrack_proto_sctp_init);
-module_exit(ip_conntrack_proto_sctp_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kiran Kumar Immidi");
-MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP");
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
deleted file mode 100644
index 0a72eab..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ /dev/null
@@ -1,1164 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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.
- *
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>:
- *	- Real stateful connection tracking
- *	- Modified state transitions table
- *	- Window scaling support added
- *	- SACK support added
- *
- * Willy Tarreau:
- *	- State table bugfixes
- *	- More robust state changes
- *	- Tuning timer parameters
- *
- * version 2.2
- */
-
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/netfilter.h>
-#include <linux/module.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/spinlock.h>
-
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-
-#if 0
-#define DEBUGP printk
-#define DEBUGP_VARS
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/* Protects conntrack->proto.tcp */
-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 __read_mostly = 0;
-
-/* If it is set to zero, we disable picking up already established
-   connections. */
-int ip_ct_tcp_loose __read_mostly = 1;
-
-/* 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 __read_mostly = 3;
-
-  /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
-     closely.  They're more complex. --RR */
-
-static const char *tcp_conntrack_names[] = {
-	"NONE",
-	"SYN_SENT",
-	"SYN_RECV",
-	"ESTABLISHED",
-	"FIN_WAIT",
-	"CLOSE_WAIT",
-	"LAST_ACK",
-	"TIME_WAIT",
-	"CLOSE",
-	"LISTEN"
-};
-
-#define SECS * HZ
-#define MINS * 60 SECS
-#define HOURS * 60 MINS
-#define DAYS * 24 HOURS
-
-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 __read_mostly =   5 MINS;
-
-static const unsigned int * tcp_timeouts[]
-= { NULL,                              /*      TCP_CONNTRACK_NONE */
-    &ip_ct_tcp_timeout_syn_sent,       /*      TCP_CONNTRACK_SYN_SENT, */
-    &ip_ct_tcp_timeout_syn_recv,       /*      TCP_CONNTRACK_SYN_RECV, */
-    &ip_ct_tcp_timeout_established,    /*      TCP_CONNTRACK_ESTABLISHED,      */
-    &ip_ct_tcp_timeout_fin_wait,       /*      TCP_CONNTRACK_FIN_WAIT, */
-    &ip_ct_tcp_timeout_close_wait,     /*      TCP_CONNTRACK_CLOSE_WAIT,       */
-    &ip_ct_tcp_timeout_last_ack,       /*      TCP_CONNTRACK_LAST_ACK, */
-    &ip_ct_tcp_timeout_time_wait,      /*      TCP_CONNTRACK_TIME_WAIT,        */
-    &ip_ct_tcp_timeout_close,          /*      TCP_CONNTRACK_CLOSE,    */
-    NULL,                              /*      TCP_CONNTRACK_LISTEN */
- };
-
-#define sNO TCP_CONNTRACK_NONE
-#define sSS TCP_CONNTRACK_SYN_SENT
-#define sSR TCP_CONNTRACK_SYN_RECV
-#define sES TCP_CONNTRACK_ESTABLISHED
-#define sFW TCP_CONNTRACK_FIN_WAIT
-#define sCW TCP_CONNTRACK_CLOSE_WAIT
-#define sLA TCP_CONNTRACK_LAST_ACK
-#define sTW TCP_CONNTRACK_TIME_WAIT
-#define sCL TCP_CONNTRACK_CLOSE
-#define sLI TCP_CONNTRACK_LISTEN
-#define sIV TCP_CONNTRACK_MAX
-#define sIG TCP_CONNTRACK_IGNORE
-
-/* What TCP flags are set from RST/SYN/FIN/ACK. */
-enum tcp_bit_set {
-	TCP_SYN_SET,
-	TCP_SYNACK_SET,
-	TCP_FIN_SET,
-	TCP_ACK_SET,
-	TCP_RST_SET,
-	TCP_NONE_SET,
-};
-
-/*
- * The TCP state transition table needs a few words...
- *
- * We are the man in the middle. All the packets go through us
- * but might get lost in transit to the destination.
- * It is assumed that the destinations can't receive segments
- * we haven't seen.
- *
- * The checked segment is in window, but our windows are *not*
- * equivalent with the ones of the sender/receiver. We always
- * try to guess the state of the current sender.
- *
- * The meaning of the states are:
- *
- * NONE:	initial state
- * SYN_SENT:	SYN-only packet seen
- * SYN_RECV:	SYN-ACK packet seen
- * ESTABLISHED:	ACK packet seen
- * FIN_WAIT:	FIN packet seen
- * CLOSE_WAIT:	ACK seen (after FIN)
- * LAST_ACK:	FIN seen (after FIN)
- * TIME_WAIT:	last ACK seen
- * CLOSE:	closed connection
- *
- * LISTEN state is not used.
- *
- * Packets marked as IGNORED (sIG):
- *	if they may be either invalid or valid
- *	and the receiver may send back a connection
- *	closing RST or a SYN/ACK.
- *
- * Packets marked as INVALID (sIV):
- *	if they are invalid
- *	or we do not support the request (simultaneous open)
- */
-static const enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
-	{
-/* ORIGINAL */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*syn*/	   { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV },
-/*
- *	sNO -> sSS	Initialize a new connection
- *	sSS -> sSS	Retransmitted SYN
- *	sSR -> sIG	Late retransmitted SYN?
- *	sES -> sIG	Error: SYNs in window outside the SYN_SENT state
- *			are errors. Receiver will reply with RST
- *			and close the connection.
- *			Or we are not in sync and hold a dead connection.
- *	sFW -> sIG
- *	sCW -> sIG
- *	sLA -> sIG
- *	sTW -> sSS	Reopened connection (RFC 1122).
- *	sCL -> sSS
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
-/*
- * A SYN/ACK from the client is always invalid:
- *	- either it tries to set up a simultaneous open, which is
- *	  not supported;
- *	- or the firewall has just been inserted between the two hosts
- *	  during the session set-up. The SYN will be retransmitted
- *	  by the true client (or it'll time out).
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*fin*/    { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
-/*
- *	sNO -> sIV	Too late and no reason to do anything...
- *	sSS -> sIV	Client migth not send FIN in this state:
- *			we enforce waiting for a SYN/ACK reply first.
- *	sSR -> sFW	Close started.
- *	sES -> sFW
- *	sFW -> sLA	FIN seen in both directions, waiting for
- *			the last ACK.
- *			Migth be a retransmitted FIN as well...
- *	sCW -> sLA
- *	sLA -> sLA	Retransmitted FIN. Remain in the same state.
- *	sTW -> sTW
- *	sCL -> sCL
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*ack*/	   { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV },
-/*
- *	sNO -> sES	Assumed.
- *	sSS -> sIV	ACK is invalid: we haven't seen a SYN/ACK yet.
- *	sSR -> sES	Established state is reached.
- *	sES -> sES	:-)
- *	sFW -> sCW	Normal close request answered by ACK.
- *	sCW -> sCW
- *	sLA -> sTW	Last ACK detected.
- *	sTW -> sTW	Retransmitted last ACK. Remain in the same state.
- *	sCL -> sCL
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*rst*/    { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
-/*none*/   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
-	},
-	{
-/* REPLY */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*syn*/	   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV },
-/*
- *	sNO -> sIV	Never reached.
- *	sSS -> sIV	Simultaneous open, not supported
- *	sSR -> sIV	Simultaneous open, not supported.
- *	sES -> sIV	Server may not initiate a connection.
- *	sFW -> sIV
- *	sCW -> sIV
- *	sLA -> sIV
- *	sTW -> sIV	Reopened connection, but server may not do it.
- *	sCL -> sIV
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV },
-/*
- *	sSS -> sSR	Standard open.
- *	sSR -> sSR	Retransmitted SYN/ACK.
- *	sES -> sIG	Late retransmitted SYN/ACK?
- *	sFW -> sIG	Might be SYN/ACK answering ignored SYN
- *	sCW -> sIG
- *	sLA -> sIG
- *	sTW -> sIG
- *	sCL -> sIG
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*fin*/    { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV },
-/*
- *	sSS -> sIV	Server might not send FIN in this state.
- *	sSR -> sFW	Close started.
- *	sES -> sFW
- *	sFW -> sLA	FIN seen in both directions.
- *	sCW -> sLA
- *	sLA -> sLA	Retransmitted FIN.
- *	sTW -> sTW
- *	sCL -> sCL
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*ack*/	   { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV },
-/*
- *	sSS -> sIG	Might be a half-open connection.
- *	sSR -> sSR	Might answer late resent SYN.
- *	sES -> sES	:-)
- *	sFW -> sCW	Normal close request answered by ACK.
- *	sCW -> sCW
- *	sLA -> sTW	Last ACK detected.
- *	sTW -> sTW	Retransmitted last ACK.
- *	sCL -> sCL
- */
-/* 	     sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI	*/
-/*rst*/    { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV },
-/*none*/   { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
-	}
-};
-
-static int tcp_pkt_to_tuple(const struct sk_buff *skb,
-			    unsigned int dataoff,
-			    struct ip_conntrack_tuple *tuple)
-{
-	struct tcphdr _hdr, *hp;
-
-	/* Actually only need first 8 bytes. */
-	hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
-	if (hp == NULL)
-		return 0;
-
-	tuple->src.u.tcp.port = hp->source;
-	tuple->dst.u.tcp.port = hp->dest;
-
-	return 1;
-}
-
-static int tcp_invert_tuple(struct ip_conntrack_tuple *tuple,
-			    const struct ip_conntrack_tuple *orig)
-{
-	tuple->src.u.tcp.port = orig->dst.u.tcp.port;
-	tuple->dst.u.tcp.port = orig->src.u.tcp.port;
-	return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static int tcp_print_tuple(struct seq_file *s,
-			   const struct ip_conntrack_tuple *tuple)
-{
-	return seq_printf(s, "sport=%hu dport=%hu ",
-			  ntohs(tuple->src.u.tcp.port),
-			  ntohs(tuple->dst.u.tcp.port));
-}
-
-/* Print out the private part of the conntrack. */
-static int tcp_print_conntrack(struct seq_file *s,
-			       const struct ip_conntrack *conntrack)
-{
-	enum tcp_conntrack state;
-
-	read_lock_bh(&tcp_lock);
-	state = conntrack->proto.tcp.state;
-	read_unlock_bh(&tcp_lock);
-
-	return seq_printf(s, "%s ", tcp_conntrack_names[state]);
-}
-
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
-			 const struct ip_conntrack *ct)
-{
-	struct nfattr *nest_parms;
-
-	read_lock_bh(&tcp_lock);
-	nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
-	NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
-		&ct->proto.tcp.state);
-	read_unlock_bh(&tcp_lock);
-
-	NFA_NEST_END(skb, nest_parms);
-
-	return 0;
-
-nfattr_failure:
-	read_unlock_bh(&tcp_lock);
-	return -1;
-}
-
-static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = {
-	[CTA_PROTOINFO_TCP_STATE-1]	= sizeof(u_int8_t),
-};
-
-static int nfattr_to_tcp(struct nfattr *cda[], struct ip_conntrack *ct)
-{
-	struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
-	struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
-
-	/* updates could not contain anything about the private
-	 * protocol info, in that case skip the parsing */
-	if (!attr)
-		return 0;
-
-	nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
-
-	if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
-		return -EINVAL;
-
-	if (!tb[CTA_PROTOINFO_TCP_STATE-1])
-		return -EINVAL;
-
-	write_lock_bh(&tcp_lock);
-	ct->proto.tcp.state =
-		*(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
-	write_unlock_bh(&tcp_lock);
-
-	return 0;
-}
-#endif
-
-static unsigned int get_conntrack_index(const struct tcphdr *tcph)
-{
-	if (tcph->rst) return TCP_RST_SET;
-	else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET);
-	else if (tcph->fin) return TCP_FIN_SET;
-	else if (tcph->ack) return TCP_ACK_SET;
-	else return TCP_NONE_SET;
-}
-
-/* TCP connection tracking based on 'Real Stateful TCP Packet Filtering
-   in IP Filter' by Guido van Rooij.
-
-   http://www.nluug.nl/events/sane2000/papers.html
-   http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz
-
-   The boundaries and the conditions are changed according to RFC793:
-   the packet must intersect the window (i.e. segments may be
-   after the right or before the left edge) and thus receivers may ACK
-   segments after the right edge of the window.
-
-	td_maxend = max(sack + max(win,1)) seen in reply packets
-	td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets
-	td_maxwin += seq + len - sender.td_maxend
-			if seq + len > sender.td_maxend
-	td_end    = max(seq + len) seen in sent packets
-
-   I.   Upper bound for valid data:	seq <= sender.td_maxend
-   II.  Lower bound for valid data:	seq + len >= sender.td_end - receiver.td_maxwin
-   III.	Upper bound for valid ack:      sack <= receiver.td_end
-   IV.	Lower bound for valid ack:	ack >= receiver.td_end - MAXACKWINDOW
-
-   where sack is the highest right edge of sack block found in the packet.
-
-   The upper bound limit for a valid ack is not ignored -
-   we doesn't have to deal with fragments.
-*/
-
-static inline __u32 segment_seq_plus_len(__u32 seq,
-					 size_t len,
-					 struct iphdr *iph,
-					 struct tcphdr *tcph)
-{
-	return (seq + len - (iph->ihl + tcph->doff)*4
-		+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
-}
-
-/* Fixme: what about big packets? */
-#define MAXACKWINCONST			66000
-#define MAXACKWINDOW(sender)						\
-	((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin	\
-					      : MAXACKWINCONST)
-
-/*
- * Simplified tcp_parse_options routine from tcp_input.c
- */
-static void tcp_options(const struct sk_buff *skb,
-			struct iphdr *iph,
-			struct tcphdr *tcph,
-			struct ip_ct_tcp_state *state)
-{
-	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-	unsigned char *ptr;
-	int length = (tcph->doff*4) - sizeof(struct tcphdr);
-
-	if (!length)
-		return;
-
-	ptr = skb_header_pointer(skb,
-				 (iph->ihl * 4) + sizeof(struct tcphdr),
-				 length, buff);
-	BUG_ON(ptr == NULL);
-
-	state->td_scale =
-	state->flags = 0;
-
-	while (length > 0) {
-		int opcode=*ptr++;
-		int opsize;
-
-		switch (opcode) {
-		case TCPOPT_EOL:
-			return;
-		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
-			length--;
-			continue;
-		default:
-			opsize=*ptr++;
-			if (opsize < 2) /* "silly options" */
-				return;
-			if (opsize > length)
-				break;	/* don't parse partial options */
-
-			if (opcode == TCPOPT_SACK_PERM
-			    && opsize == TCPOLEN_SACK_PERM)
-				state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
-			else if (opcode == TCPOPT_WINDOW
-				 && opsize == TCPOLEN_WINDOW) {
-				state->td_scale = *(u_int8_t *)ptr;
-
-				if (state->td_scale > 14) {
-					/* See RFC1323 */
-					state->td_scale = 14;
-				}
-				state->flags |=
-					IP_CT_TCP_FLAG_WINDOW_SCALE;
-			}
-			ptr += opsize - 2;
-			length -= opsize;
-		}
-	}
-}
-
-static void tcp_sack(const struct sk_buff *skb,
-		     struct iphdr *iph,
-		     struct tcphdr *tcph,
-		     __u32 *sack)
-{
-	unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-	unsigned char *ptr;
-	int length = (tcph->doff*4) - sizeof(struct tcphdr);
-	__u32 tmp;
-
-	if (!length)
-		return;
-
-	ptr = skb_header_pointer(skb,
-				 (iph->ihl * 4) + sizeof(struct tcphdr),
-				 length, buff);
-	BUG_ON(ptr == NULL);
-
-	/* Fast path for timestamp-only option */
-	if (length == TCPOLEN_TSTAMP_ALIGNED*4
-	    && *(__be32 *)ptr ==
-		__constant_htonl((TCPOPT_NOP << 24)
-				 | (TCPOPT_NOP << 16)
-				 | (TCPOPT_TIMESTAMP << 8)
-				 | TCPOLEN_TIMESTAMP))
-		return;
-
-	while (length > 0) {
-		int opcode=*ptr++;
-		int opsize, i;
-
-		switch (opcode) {
-		case TCPOPT_EOL:
-			return;
-		case TCPOPT_NOP:	/* Ref: RFC 793 section 3.1 */
-			length--;
-			continue;
-		default:
-			opsize=*ptr++;
-			if (opsize < 2) /* "silly options" */
-				return;
-			if (opsize > length)
-				break;	/* don't parse partial options */
-
-			if (opcode == TCPOPT_SACK
-			    && opsize >= (TCPOLEN_SACK_BASE
-					  + TCPOLEN_SACK_PERBLOCK)
-			    && !((opsize - TCPOLEN_SACK_BASE)
-				 % TCPOLEN_SACK_PERBLOCK)) {
-				for (i = 0;
-				     i < (opsize - TCPOLEN_SACK_BASE);
-				     i += TCPOLEN_SACK_PERBLOCK) {
-					tmp = ntohl(*((__be32 *)(ptr+i)+1));
-
-					if (after(tmp, *sack))
-						*sack = tmp;
-				}
-				return;
-			}
-			ptr += opsize - 2;
-			length -= opsize;
-		}
-	}
-}
-
-static int tcp_in_window(struct ip_ct_tcp *state,
-			 enum ip_conntrack_dir dir,
-			 unsigned int index,
-			 const struct sk_buff *skb,
-			 struct iphdr *iph,
-			 struct tcphdr *tcph)
-{
-	struct ip_ct_tcp_state *sender = &state->seen[dir];
-	struct ip_ct_tcp_state *receiver = &state->seen[!dir];
-	__u32 seq, ack, sack, end, win, swin;
-	int res;
-
-	/*
-	 * Get the required data from the packet.
-	 */
-	seq = ntohl(tcph->seq);
-	ack = sack = ntohl(tcph->ack_seq);
-	win = ntohs(tcph->window);
-	end = segment_seq_plus_len(seq, skb->len, iph, tcph);
-
-	if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
-		tcp_sack(skb, iph, tcph, &sack);
-
-	DEBUGP("tcp_in_window: START\n");
-	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
-	       "seq=%u ack=%u sack=%u win=%u end=%u\n",
-		NIPQUAD(iph->saddr), ntohs(tcph->source),
-		NIPQUAD(iph->daddr), ntohs(tcph->dest),
-		seq, ack, sack, win, end);
-	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
-	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
-		sender->td_end, sender->td_maxend, sender->td_maxwin,
-		sender->td_scale,
-		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
-		receiver->td_scale);
-
-	if (sender->td_end == 0) {
-		/*
-		 * Initialize sender data.
-		 */
-		if (tcph->syn && tcph->ack) {
-			/*
-			 * Outgoing SYN-ACK in reply to a SYN.
-			 */
-			sender->td_end =
-			sender->td_maxend = end;
-			sender->td_maxwin = (win == 0 ? 1 : win);
-
-			tcp_options(skb, iph, tcph, sender);
-			/*
-			 * RFC 1323:
-			 * Both sides must send the Window Scale option
-			 * to enable window scaling in either direction.
-			 */
-			if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE
-			      && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE))
-				sender->td_scale =
-				receiver->td_scale = 0;
-		} else {
-			/*
-			 * We are in the middle of a connection,
-			 * its history is lost for us.
-			 * Let's try to use the data from the packet.
-			 */
-			sender->td_end = end;
-			sender->td_maxwin = (win == 0 ? 1 : win);
-			sender->td_maxend = end + sender->td_maxwin;
-		}
-	} else if (((state->state == TCP_CONNTRACK_SYN_SENT
-		     && dir == IP_CT_DIR_ORIGINAL)
-		    || (state->state == TCP_CONNTRACK_SYN_RECV
-			&& dir == IP_CT_DIR_REPLY))
-		    && after(end, sender->td_end)) {
-		/*
-		 * RFC 793: "if a TCP is reinitialized ... then it need
-		 * not wait at all; it must only be sure to use sequence
-		 * numbers larger than those recently used."
-		 */
-		sender->td_end =
-		sender->td_maxend = end;
-		sender->td_maxwin = (win == 0 ? 1 : win);
-
-		tcp_options(skb, iph, tcph, sender);
-	}
-
-	if (!(tcph->ack)) {
-		/*
-		 * If there is no ACK, just pretend it was set and OK.
-		 */
-		ack = sack = receiver->td_end;
-	} else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) ==
-		    (TCP_FLAG_ACK|TCP_FLAG_RST))
-		   && (ack == 0)) {
-		/*
-		 * Broken TCP stacks, that set ACK in RST packets as well
-		 * with zero ack value.
-		 */
-		ack = sack = receiver->td_end;
-	}
-
-	if (seq == end
-	    && (!tcph->rst
-		|| (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT)))
-		/*
-		 * Packets contains no data: we assume it is valid
-		 * and check the ack value only.
-		 * However RST segments are always validated by their
-		 * SEQ number, except when seq == 0 (reset sent answering
-		 * SYN.
-		 */
-		seq = end = sender->td_end;
-
-	DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
-	       "seq=%u ack=%u sack =%u win=%u end=%u\n",
-		NIPQUAD(iph->saddr), ntohs(tcph->source),
-		NIPQUAD(iph->daddr), ntohs(tcph->dest),
-		seq, ack, sack, win, end);
-	DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
-	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
-		sender->td_end, sender->td_maxend, sender->td_maxwin,
-		sender->td_scale,
-		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
-		receiver->td_scale);
-
-	DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
-		before(seq, sender->td_maxend + 1),
-		after(end, sender->td_end - receiver->td_maxwin - 1),
-		before(sack, receiver->td_end + 1),
-		after(ack, receiver->td_end - MAXACKWINDOW(sender)));
-
-	if (before(seq, sender->td_maxend + 1) &&
-	    after(end, sender->td_end - receiver->td_maxwin - 1) &&
-	    before(sack, receiver->td_end + 1) &&
-	    after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
-		/*
-		 * Take into account window scaling (RFC 1323).
-		 */
-		if (!tcph->syn)
-			win <<= sender->td_scale;
-
-		/*
-		 * Update sender data.
-		 */
-		swin = win + (sack - ack);
-		if (sender->td_maxwin < swin)
-			sender->td_maxwin = swin;
-		if (after(end, sender->td_end))
-			sender->td_end = end;
-		/*
-		 * Update receiver data.
-		 */
-		if (after(end, sender->td_maxend))
-			receiver->td_maxwin += end - sender->td_maxend;
-		if (after(sack + win, receiver->td_maxend - 1)) {
-			receiver->td_maxend = sack + win;
-			if (win == 0)
-				receiver->td_maxend++;
-		}
-
-		/*
-		 * Check retransmissions.
-		 */
-		if (index == TCP_ACK_SET) {
-			if (state->last_dir == dir
-			    && state->last_seq == seq
-			    && state->last_ack == ack
-			    && 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;
-			}
-		}
-		res = 1;
-	} else {
-		res = 0;
-		if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
-		    ip_ct_tcp_be_liberal)
-			res = 1;
-		if (!res && LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-			"ip_ct_tcp: %s ",
-			before(seq, sender->td_maxend + 1) ?
-			after(end, sender->td_end - receiver->td_maxwin - 1) ?
-			before(sack, receiver->td_end + 1) ?
-			after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG"
-			: "ACK is under the lower bound (possible overly delayed ACK)"
-			: "ACK is over the upper bound (ACKed data not seen yet)"
-			: "SEQ is under the lower bound (already ACKed data retransmitted)"
-			: "SEQ is over the upper bound (over the window of the receiver)");
-	}
-
-	DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
-	       "receiver end=%u maxend=%u maxwin=%u\n",
-		res, sender->td_end, sender->td_maxend, sender->td_maxwin,
-		receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
-
-	return res;
-}
-
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-/* Update sender->td_end after NAT successfully mangled the packet */
-void ip_conntrack_tcp_update(struct sk_buff *skb,
-			     struct ip_conntrack *conntrack,
-			     enum ip_conntrack_dir dir)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4;
-	__u32 end;
-#ifdef DEBUGP_VARS
-	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
-	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
-#endif
-
-	end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, iph, tcph);
-
-	write_lock_bh(&tcp_lock);
-	/*
-	 * We have to worry for the ack in the reply packet only...
-	 */
-	if (after(end, conntrack->proto.tcp.seen[dir].td_end))
-		conntrack->proto.tcp.seen[dir].td_end = end;
-	conntrack->proto.tcp.last_end = end;
-	write_unlock_bh(&tcp_lock);
-	DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
-	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
-		sender->td_end, sender->td_maxend, sender->td_maxwin,
-		sender->td_scale,
-		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
-		receiver->td_scale);
-}
-
-#endif
-
-#define	TH_FIN	0x01
-#define	TH_SYN	0x02
-#define	TH_RST	0x04
-#define	TH_PUSH	0x08
-#define	TH_ACK	0x10
-#define	TH_URG	0x20
-#define	TH_ECE	0x40
-#define	TH_CWR	0x80
-
-/* table of valid flag combinations - ECE and CWR are always valid */
-static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
-{
-	[TH_SYN]			= 1,
-	[TH_SYN|TH_PUSH]		= 1,
-	[TH_SYN|TH_URG]			= 1,
-	[TH_SYN|TH_PUSH|TH_URG]		= 1,
-	[TH_SYN|TH_ACK]			= 1,
-	[TH_SYN|TH_ACK|TH_PUSH]		= 1,
-	[TH_RST]			= 1,
-	[TH_RST|TH_ACK]			= 1,
-	[TH_RST|TH_ACK|TH_PUSH]		= 1,
-	[TH_FIN|TH_ACK]			= 1,
-	[TH_ACK]			= 1,
-	[TH_ACK|TH_PUSH]		= 1,
-	[TH_ACK|TH_URG]			= 1,
-	[TH_ACK|TH_URG|TH_PUSH]		= 1,
-	[TH_FIN|TH_ACK|TH_PUSH]		= 1,
-	[TH_FIN|TH_ACK|TH_URG]		= 1,
-	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1,
-};
-
-/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */
-static int tcp_error(struct sk_buff *skb,
-		     enum ip_conntrack_info *ctinfo,
-		     unsigned int hooknum)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr _tcph, *th;
-	unsigned int tcplen = skb->len - iph->ihl * 4;
-	u_int8_t tcpflags;
-
-	/* Smaller that minimal TCP header? */
-	th = skb_header_pointer(skb, iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
-	if (th == NULL) {
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				"ip_ct_tcp: short packet ");
-		return -NF_ACCEPT;
-	}
-
-	/* Not whole TCP header or malformed packet */
-	if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				"ip_ct_tcp: truncated/malformed packet ");
-		return -NF_ACCEPT;
-	}
-
-	/* Checksum invalid? Ignore.
-	 * We skip checking packets on the outgoing path
-	 * because it 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_TCP)) {
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_tcp: bad TCP checksum ");
-		return -NF_ACCEPT;
-	}
-
-	/* Check TCP flags. */
-	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
-	if (!tcp_valid_flags[tcpflags]) {
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_tcp: invalid TCP flag combination ");
-		return -NF_ACCEPT;
-	}
-
-	return NF_ACCEPT;
-}
-
-/* Returns verdict for packet, or -1 for invalid. */
-static int tcp_packet(struct ip_conntrack *conntrack,
-		      const struct sk_buff *skb,
-		      enum ip_conntrack_info ctinfo)
-{
-	enum tcp_conntrack new_state, old_state;
-	enum ip_conntrack_dir dir;
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr *th, _tcph;
-	unsigned long timeout;
-	unsigned int index;
-
-	th = skb_header_pointer(skb, iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
-	BUG_ON(th == NULL);
-
-	write_lock_bh(&tcp_lock);
-	old_state = conntrack->proto.tcp.state;
-	dir = CTINFO2DIR(ctinfo);
-	index = get_conntrack_index(th);
-	new_state = tcp_conntracks[dir][index][old_state];
-
-	switch (new_state) {
-	case TCP_CONNTRACK_IGNORE:
-		/* Ignored packets:
-		 *
-		 * a) SYN in ORIGINAL
-		 * b) SYN/ACK in REPLY
-		 * c) ACK in reply direction after initial SYN in original.
-		 */
-		if (index == TCP_SYNACK_SET
-		    && conntrack->proto.tcp.last_index == TCP_SYN_SET
-		    && conntrack->proto.tcp.last_dir != dir
-		    && ntohl(th->ack_seq) ==
-			     conntrack->proto.tcp.last_end) {
-			/* This SYN/ACK acknowledges a SYN that we earlier
-			 * ignored as invalid. This means that the client and
-			 * the server are both in sync, while the firewall is
-			 * not. We kill this session and block the SYN/ACK so
-			 * that the client cannot but retransmit its SYN and
-			 * thus initiate a clean new session.
-			 */
-			write_unlock_bh(&tcp_lock);
-			if (LOG_INVALID(IPPROTO_TCP))
-				nf_log_packet(PF_INET, 0, skb, NULL, NULL,
-					      NULL, "ip_ct_tcp: "
-					      "killing out of sync session ");
-			if (del_timer(&conntrack->timeout))
-				conntrack->timeout.function((unsigned long)
-							    conntrack);
-			return -NF_DROP;
-		}
-		conntrack->proto.tcp.last_index = index;
-		conntrack->proto.tcp.last_dir = dir;
-		conntrack->proto.tcp.last_seq = ntohl(th->seq);
-		conntrack->proto.tcp.last_end =
-		    segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th);
-
-		write_unlock_bh(&tcp_lock);
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_tcp: invalid packet ignored ");
-		return NF_ACCEPT;
-	case TCP_CONNTRACK_MAX:
-		/* Invalid packet */
-		DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
-		       dir, get_conntrack_index(th),
-		       old_state);
-		write_unlock_bh(&tcp_lock);
-		if (LOG_INVALID(IPPROTO_TCP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_tcp: invalid state ");
-		return -NF_ACCEPT;
-	case TCP_CONNTRACK_SYN_SENT:
-		if (old_state < TCP_CONNTRACK_TIME_WAIT)
-			break;
-		if ((conntrack->proto.tcp.seen[dir].flags &
-			 IP_CT_TCP_FLAG_CLOSE_INIT)
-		    || after(ntohl(th->seq),
-			     conntrack->proto.tcp.seen[dir].td_end)) {
-			/* Attempt to reopen a closed connection.
-			* Delete this connection and look up again. */
-			write_unlock_bh(&tcp_lock);
-			if (del_timer(&conntrack->timeout))
-				conntrack->timeout.function((unsigned long)
-							    conntrack);
-			return -NF_REPEAT;
-		} else {
-			write_unlock_bh(&tcp_lock);
-			if (LOG_INVALID(IPPROTO_TCP))
-				nf_log_packet(PF_INET, 0, skb, NULL, NULL,
-					      NULL, "ip_ct_tcp: invalid SYN");
-			return -NF_ACCEPT;
-		}
-	case TCP_CONNTRACK_CLOSE:
-		if (index == TCP_RST_SET
-		    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
-			 && conntrack->proto.tcp.last_index == TCP_SYN_SET)
-			|| (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
-			    && conntrack->proto.tcp.last_index == TCP_ACK_SET))
-		    && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) {
-			/* RST sent to invalid SYN or ACK we had let through
-			 * at a) and c) above:
-			 *
-			 * a) SYN was in window then
-			 * c) we hold a half-open connection.
-			 *
-			 * Delete our connection entry.
-			 * We skip window checking, because packet might ACK
-			 * segments we ignored. */
-			goto in_window;
-		}
-		/* Just fall through */
-	default:
-		/* Keep compilers happy. */
-		break;
-	}
-
-	if (!tcp_in_window(&conntrack->proto.tcp, dir, index,
-			   skb, iph, th)) {
-		write_unlock_bh(&tcp_lock);
-		return -NF_ACCEPT;
-	}
-    in_window:
-	/* From now on we have got in-window packets */
-	conntrack->proto.tcp.last_index = index;
-
-	DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
-	       "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
-		NIPQUAD(iph->saddr), ntohs(th->source),
-		NIPQUAD(iph->daddr), ntohs(th->dest),
-		(th->syn ? 1 : 0), (th->ack ? 1 : 0),
-		(th->fin ? 1 : 0), (th->rst ? 1 : 0),
-		old_state, new_state);
-
-	conntrack->proto.tcp.state = new_state;
-	if (old_state != new_state
-	    && (new_state == TCP_CONNTRACK_FIN_WAIT
-		|| new_state == TCP_CONNTRACK_CLOSE))
-		conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
-	timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans
-		  && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans
-		  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
-	write_unlock_bh(&tcp_lock);
-
-	ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
-	if (new_state != old_state)
-		ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
-
-	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
-		/* If only reply is a RST, we can consider ourselves not to
-		   have an established connection: this is a fairly common
-		   problem case, so we can delete the conntrack
-		   immediately.  --RR */
-		if (th->rst) {
-			if (del_timer(&conntrack->timeout))
-				conntrack->timeout.function((unsigned long)
-							    conntrack);
-			return NF_ACCEPT;
-		}
-	} else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
-		   && (old_state == TCP_CONNTRACK_SYN_RECV
-		       || old_state == TCP_CONNTRACK_ESTABLISHED)
-		   && new_state == TCP_CONNTRACK_ESTABLISHED) {
-		/* Set ASSURED if we see see valid ack in ESTABLISHED
-		   after SYN_RECV or a valid answer for a picked up
-		   connection. */
-		set_bit(IPS_ASSURED_BIT, &conntrack->status);
-		ip_conntrack_event_cache(IPCT_STATUS, skb);
-	}
-	ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
-
-	return NF_ACCEPT;
-}
-
-/* Called when a new connection for this protocol found. */
-static int tcp_new(struct ip_conntrack *conntrack,
-		   const struct sk_buff *skb)
-{
-	enum tcp_conntrack new_state;
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr *th, _tcph;
-#ifdef DEBUGP_VARS
-	struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
-	struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
-#endif
-
-	th = skb_header_pointer(skb, iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
-	BUG_ON(th == NULL);
-
-	/* Don't need lock here: this conntrack not in circulation yet */
-	new_state
-		= tcp_conntracks[0][get_conntrack_index(th)]
-		[TCP_CONNTRACK_NONE];
-
-	/* Invalid: delete conntrack */
-	if (new_state >= TCP_CONNTRACK_MAX) {
-		DEBUGP("ip_ct_tcp: invalid new deleting.\n");
-		return 0;
-	}
-
-	if (new_state == TCP_CONNTRACK_SYN_SENT) {
-		/* SYN packet */
-		conntrack->proto.tcp.seen[0].td_end =
-			segment_seq_plus_len(ntohl(th->seq), skb->len,
-					     iph, th);
-		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
-		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
-			conntrack->proto.tcp.seen[0].td_maxwin = 1;
-		conntrack->proto.tcp.seen[0].td_maxend =
-			conntrack->proto.tcp.seen[0].td_end;
-
-		tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
-		conntrack->proto.tcp.seen[1].flags = 0;
-	} else if (ip_ct_tcp_loose == 0) {
-		/* Don't try to pick up connections. */
-		return 0;
-	} else {
-		/*
-		 * We are in the middle of a connection,
-		 * its history is lost for us.
-		 * Let's try to use the data from the packet.
-		 */
-		conntrack->proto.tcp.seen[0].td_end =
-			segment_seq_plus_len(ntohl(th->seq), skb->len,
-					     iph, th);
-		conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
-		if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
-			conntrack->proto.tcp.seen[0].td_maxwin = 1;
-		conntrack->proto.tcp.seen[0].td_maxend =
-			conntrack->proto.tcp.seen[0].td_end +
-			conntrack->proto.tcp.seen[0].td_maxwin;
-		conntrack->proto.tcp.seen[0].td_scale = 0;
-
-		/* We assume SACK and liberal window checking to handle
-		 * window scaling */
-		conntrack->proto.tcp.seen[0].flags =
-		conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
-						     IP_CT_TCP_FLAG_BE_LIBERAL;
-	}
-
-	conntrack->proto.tcp.seen[1].td_end = 0;
-	conntrack->proto.tcp.seen[1].td_maxend = 0;
-	conntrack->proto.tcp.seen[1].td_maxwin = 1;
-	conntrack->proto.tcp.seen[1].td_scale = 0;
-
-	/* tcp_packet will set them */
-	conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
-	conntrack->proto.tcp.last_index = TCP_NONE_SET;
-
-	DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
-	       "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
-		sender->td_end, sender->td_maxend, sender->td_maxwin,
-		sender->td_scale,
-		receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
-		receiver->td_scale);
-	return 1;
-}
-
-struct ip_conntrack_protocol ip_conntrack_protocol_tcp =
-{
-	.proto 			= IPPROTO_TCP,
-	.name 			= "tcp",
-	.pkt_to_tuple 		= tcp_pkt_to_tuple,
-	.invert_tuple 		= tcp_invert_tuple,
-	.print_tuple 		= tcp_print_tuple,
-	.print_conntrack 	= tcp_print_conntrack,
-	.packet 		= tcp_packet,
-	.new 			= tcp_new,
-	.error			= tcp_error,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.to_nfattr		= tcp_to_nfattr,
-	.from_nfattr		= nfattr_to_tcp,
-	.tuple_to_nfattr	= ip_ct_port_tuple_to_nfattr,
-	.nfattr_to_tuple	= ip_ct_port_nfattr_to_tuple,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
deleted file mode 100644
index 14c30c6..0000000
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/timer.h>
-#include <linux/netfilter.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/seq_file.h>
-#include <net/checksum.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-
-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,
-			     struct ip_conntrack_tuple *tuple)
-{
-	struct udphdr _hdr, *hp;
-
-	/* Actually only need first 8 bytes. */
-	hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
-	if (hp == NULL)
-		return 0;
-
-	tuple->src.u.udp.port = hp->source;
-	tuple->dst.u.udp.port = hp->dest;
-
-	return 1;
-}
-
-static int udp_invert_tuple(struct ip_conntrack_tuple *tuple,
-			    const struct ip_conntrack_tuple *orig)
-{
-	tuple->src.u.udp.port = orig->dst.u.udp.port;
-	tuple->dst.u.udp.port = orig->src.u.udp.port;
-	return 1;
-}
-
-/* Print out the per-protocol part of the tuple. */
-static int udp_print_tuple(struct seq_file *s,
-			   const struct ip_conntrack_tuple *tuple)
-{
-	return seq_printf(s, "sport=%hu dport=%hu ",
-			  ntohs(tuple->src.u.udp.port),
-			  ntohs(tuple->dst.u.udp.port));
-}
-
-/* Print out the private part of the conntrack. */
-static int udp_print_conntrack(struct seq_file *s,
-			       const struct ip_conntrack *conntrack)
-{
-	return 0;
-}
-
-/* Returns verdict for packet, and may modify conntracktype */
-static int udp_packet(struct ip_conntrack *conntrack,
-		      const struct sk_buff *skb,
-		      enum ip_conntrack_info ctinfo)
-{
-	/* If we've seen traffic both ways, this is some kind of UDP
-	   stream.  Extend timeout. */
-	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
-		ip_ct_refresh_acct(conntrack, ctinfo, skb,
-				   ip_ct_udp_timeout_stream);
-		/* Also, more likely to be important, and not a probe */
-		if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
-			ip_conntrack_event_cache(IPCT_STATUS, skb);
-	} else
-		ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
-
-	return NF_ACCEPT;
-}
-
-/* Called when a new connection for this protocol found. */
-static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
-{
-	return 1;
-}
-
-static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
-		     unsigned int hooknum)
-{
-	struct iphdr *iph = skb->nh.iph;
-	unsigned int udplen = skb->len - iph->ihl * 4;
-	struct udphdr _hdr, *hdr;
-
-	/* Header is too small? */
-	hdr = skb_header_pointer(skb, iph->ihl*4, sizeof(_hdr), &_hdr);
-	if (hdr == NULL) {
-		if (LOG_INVALID(IPPROTO_UDP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_udp: short packet ");
-		return -NF_ACCEPT;
-	}
-
-	/* Truncated/malformed packets */
-	if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
-		if (LOG_INVALID(IPPROTO_UDP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_udp: truncated/malformed packet ");
-		return -NF_ACCEPT;
-	}
-
-	/* Packet with no checksum */
-	if (!hdr->check)
-		return NF_ACCEPT;
-
-	/* Checksum invalid? Ignore.
-	 * We skip checking packets on the outgoing path
-	 * 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)) {
-		if (LOG_INVALID(IPPROTO_UDP))
-			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-				  "ip_ct_udp: bad UDP checksum ");
-		return -NF_ACCEPT;
-	}
-
-	return NF_ACCEPT;
-}
-
-struct ip_conntrack_protocol ip_conntrack_protocol_udp =
-{
-	.proto 			= IPPROTO_UDP,
-	.name			= "udp",
-	.pkt_to_tuple		= udp_pkt_to_tuple,
-	.invert_tuple		= udp_invert_tuple,
-	.print_tuple		= udp_print_tuple,
-	.print_conntrack	= udp_print_conntrack,
-	.packet			= udp_packet,
-	.new			= udp_new,
-	.error			= udp_error,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.tuple_to_nfattr	= ip_ct_port_tuple_to_nfattr,
-	.nfattr_to_tuple	= ip_ct_port_nfattr_to_tuple,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
deleted file mode 100644
index c59a962..0000000
--- a/net/ipv4/netfilter/ip_conntrack_sip.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* SIP extension for IP connection tracking.
- *
- * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
- * based on RR's ip_conntrack_ftp.c and other modules.
- *
- * This program is free software; you can 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/ctype.h>
-#include <linux/skbuff.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
-MODULE_DESCRIPTION("SIP connection tracking helper");
-
-#define MAX_PORTS	8
-static unsigned short ports[MAX_PORTS];
-static int ports_c;
-module_param_array(ports, ushort, &ports_c, 0400);
-MODULE_PARM_DESC(ports, "port numbers of sip servers");
-
-static unsigned int sip_timeout = SIP_TIMEOUT;
-module_param(sip_timeout, uint, 0600);
-MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
-
-unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
-				enum ip_conntrack_info ctinfo,
-				struct ip_conntrack *ct,
-				const char **dptr);
-EXPORT_SYMBOL_GPL(ip_nat_sip_hook);
-
-unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
-				enum ip_conntrack_info ctinfo,
-				struct ip_conntrack_expect *exp,
-				const char *dptr);
-EXPORT_SYMBOL_GPL(ip_nat_sdp_hook);
-
-static int digits_len(const char *dptr, const char *limit, int *shift);
-static int epaddr_len(const char *dptr, const char *limit, int *shift);
-static int skp_digits_len(const char *dptr, const char *limit, int *shift);
-static int skp_epaddr_len(const char *dptr, const char *limit, int *shift);
-
-struct sip_header_nfo {
-	const char	*lname;
-	const char	*sname;
-	const char	*ln_str;
-	size_t		lnlen;
-	size_t		snlen;
-	size_t		ln_strlen;
-	int		case_sensitive;
-	int		(*match_len)(const char *, const char *, int *);
-};
-
-static struct sip_header_nfo ct_sip_hdrs[] = {
-	[POS_REG_REQ_URI] = { 	/* SIP REGISTER request URI */
-		.lname		= "sip:",
-		.lnlen		= sizeof("sip:") - 1,
-		.ln_str		= ":",
-		.ln_strlen	= sizeof(":") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_REQ_URI] = { 	/* SIP request URI */
-		.lname		= "sip:",
-		.lnlen		= sizeof("sip:") - 1,
-		.ln_str		= "@",
-		.ln_strlen	= sizeof("@") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_FROM] = {		/* SIP From header */
-		.lname		= "From:",
-		.lnlen		= sizeof("From:") - 1,
-		.sname		= "\r\nf:",
-		.snlen		= sizeof("\r\nf:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len,
-	},
-	[POS_TO] = {		/* SIP To header */
-		.lname		= "To:",
-		.lnlen		= sizeof("To:") - 1,
-		.sname		= "\r\nt:",
-		.snlen		= sizeof("\r\nt:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len,
-	},
-	[POS_VIA] = { 		/* SIP Via header */
-		.lname		= "Via:",
-		.lnlen		= sizeof("Via:") - 1,
-		.sname		= "\r\nv:",
-		.snlen		= sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
-		.ln_str		= "UDP ",
-		.ln_strlen	= sizeof("UDP ") - 1,
-		.match_len	= epaddr_len,
-	},
-	[POS_CONTACT] = { 	/* SIP Contact header */
-		.lname		= "Contact:",
-		.lnlen		= sizeof("Contact:") - 1,
-		.sname		= "\r\nm:",
-		.snlen		= sizeof("\r\nm:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len
-	},
-	[POS_CONTENT] = { 	/* SIP Content length header */
-		.lname		= "Content-Length:",
-		.lnlen		= sizeof("Content-Length:") - 1,
-		.sname		= "\r\nl:",
-		.snlen		= sizeof("\r\nl:") - 1,
-		.ln_str		= ":",
-		.ln_strlen	= sizeof(":") - 1,
-		.match_len	= skp_digits_len
-	},
-	[POS_MEDIA] = {		/* SDP media info */
-		.case_sensitive	= 1,
-		.lname		= "\nm=",
-		.lnlen		= sizeof("\nm=") - 1,
-		.sname		= "\rm=",
-		.snlen		= sizeof("\rm=") - 1,
-		.ln_str		= "audio ",
-		.ln_strlen	= sizeof("audio ") - 1,
-		.match_len	= digits_len
-	},
-	[POS_OWNER] = { 	/* SDP owner address*/
-		.case_sensitive	= 1,
-		.lname		= "\no=",
-		.lnlen		= sizeof("\no=") - 1,
-		.sname		= "\ro=",
-		.snlen		= sizeof("\ro=") - 1,
-		.ln_str		= "IN IP4 ",
-		.ln_strlen	= sizeof("IN IP4 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_CONNECTION] = { 	/* SDP connection info */
-		.case_sensitive	= 1,
-		.lname		= "\nc=",
-		.lnlen		= sizeof("\nc=") - 1,
-		.sname		= "\rc=",
-		.snlen		= sizeof("\rc=") - 1,
-		.ln_str		= "IN IP4 ",
-		.ln_strlen	= sizeof("IN IP4 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_SDP_HEADER] = { 	/* SDP version header */
-		.case_sensitive	= 1,
-		.lname		= "\nv=",
-		.lnlen		= sizeof("\nv=") - 1,
-		.sname		= "\rv=",
-		.snlen		= sizeof("\rv=") - 1,
-		.ln_str		= "=",
-		.ln_strlen	= sizeof("=") - 1,
-		.match_len	= digits_len
-	}
-};
-
-/* get line lenght until first CR or LF seen. */
-int ct_sip_lnlen(const char *line, const char *limit)
-{
-	const char *k = line;
-
-	while ((line <= limit) && (*line == '\r' || *line == '\n'))
-		line++;
-
-	while (line <= limit) {
-		if (*line == '\r' || *line == '\n')
-			break;
-		line++;
-	}
-	return line - k;
-}
-EXPORT_SYMBOL_GPL(ct_sip_lnlen);
-
-/* Linear string search, case sensitive. */
-const char *ct_sip_search(const char *needle, const char *haystack,
-			  size_t needle_len, size_t haystack_len,
-			  int case_sensitive)
-{
-	const char *limit = haystack + (haystack_len - needle_len);
-
-	while (haystack <= limit) {
-		if (case_sensitive) {
-			if (strncmp(haystack, needle, needle_len) == 0)
-				return haystack;
-		} else {
-			if (strnicmp(haystack, needle, needle_len) == 0)
-				return haystack;
-		}
-		haystack++;
-	}
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(ct_sip_search);
-
-static int digits_len(const char *dptr, const char *limit, int *shift)
-{
-	int len = 0;
-	while (dptr <= limit && isdigit(*dptr)) {
-		dptr++;
-		len++;
-	}
-	return len;
-}
-
-/* get digits lenght, skiping blank spaces. */
-static int skp_digits_len(const char *dptr, const char *limit, int *shift)
-{
-	for (; dptr <= limit && *dptr == ' '; dptr++)
-		(*shift)++;
-
-	return digits_len(dptr, limit, shift);
-}
-
-/* Simple ipaddr parser.. */
-static int parse_ipaddr(const char *cp,	const char **endp,
-			__be32 *ipaddr, const char *limit)
-{
-	unsigned long int val;
-	int i, digit = 0;
-
-	for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) {
-		digit = 0;
-		if (!isdigit(*cp))
-			break;
-
-		val = simple_strtoul(cp, (char **)&cp, 10);
-		if (val > 0xFF)
-			return -1;
-
-		((u_int8_t *)ipaddr)[i] = val;
-		digit = 1;
-
-		if (*cp != '.')
-			break;
-		cp++;
-	}
-	if (!digit)
-		return -1;
-
-	if (endp)
-		*endp = cp;
-
-	return 0;
-}
-
-/* skip ip address. returns it lenght. */
-static int epaddr_len(const char *dptr, const char *limit, int *shift)
-{
-	const char *aux = dptr;
-	__be32 ip;
-
-	if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
-		DEBUGP("ip: %s parse failed.!\n", dptr);
-		return 0;
-	}
-
-	/* Port number */
-	if (*dptr == ':') {
-		dptr++;
-		dptr += digits_len(dptr, limit, shift);
-	}
-	return dptr - aux;
-}
-
-/* get address length, skiping user info. */
-static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
-{
-	int s = *shift;
-
-	/* Search for @, but stop at the end of the line.
-	 * We are inside a sip: URI, so we don't need to worry about
-	 * continuation lines. */
-	while (dptr <= limit &&
-	       *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
-		(*shift)++;
-		dptr++;
-	}
-
-	if (dptr <= limit && *dptr == '@') {
-		dptr++;
-		(*shift)++;
-	} else
-		*shift = s;
-
-	return epaddr_len(dptr, limit, shift);
-}
-
-/* Returns 0 if not found, -1 error parsing. */
-int ct_sip_get_info(const char *dptr, size_t dlen,
-		    unsigned int *matchoff,
-		    unsigned int *matchlen,
-		    enum sip_header_pos pos)
-{
-	struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
-	const char *limit, *aux, *k = dptr;
-	int shift = 0;
-
-	limit = dptr + (dlen - hnfo->lnlen);
-
-	while (dptr <= limit) {
-		if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
-		    (hnfo->sname == NULL ||
-		     strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
-			dptr++;
-			continue;
-		}
-		aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
-				    ct_sip_lnlen(dptr, limit),
-				    hnfo->case_sensitive);
-		if (!aux) {
-			DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
-			       hnfo->lname);
-			return -1;
-		}
-		aux += hnfo->ln_strlen;
-
-		*matchlen = hnfo->match_len(aux, limit, &shift);
-		if (!*matchlen)
-			return -1;
-
-		*matchoff = (aux - k) + shift;
-
-		DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname,
-		       *matchlen);
-		return 1;
-	}
-	DEBUGP("%s header not found.\n", hnfo->lname);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ct_sip_get_info);
-
-static int set_expected_rtp(struct sk_buff **pskb,
-			    struct ip_conntrack *ct,
-			    enum ip_conntrack_info ctinfo,
-			    __be32 ipaddr, u_int16_t port,
-			    const char *dptr)
-{
-	struct ip_conntrack_expect *exp;
-	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	int ret;
-	typeof(ip_nat_sdp_hook) ip_nat_sdp;
-
-	exp = ip_conntrack_expect_alloc(ct);
-	if (exp == NULL)
-		return NF_DROP;
-
-	exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
-	exp->tuple.src.u.udp.port = 0;
-	exp->tuple.dst.ip = ipaddr;
-	exp->tuple.dst.u.udp.port = htons(port);
-	exp->tuple.dst.protonum = IPPROTO_UDP;
-
-	exp->mask.src.ip = htonl(0xFFFFFFFF);
-	exp->mask.src.u.udp.port = 0;
-	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;
-
-	ip_nat_sdp = rcu_dereference(ip_nat_sdp_hook);
-	if (ip_nat_sdp)
-		ret = ip_nat_sdp(pskb, ctinfo, exp, dptr);
-	else {
-		if (ip_conntrack_expect_related(exp) != 0)
-			ret = NF_DROP;
-		else
-			ret = NF_ACCEPT;
-	}
-	ip_conntrack_expect_put(exp);
-
-	return ret;
-}
-
-static int sip_help(struct sk_buff **pskb,
-		    struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo)
-{
-	unsigned int dataoff, datalen;
-	const char *dptr;
-	int ret = NF_ACCEPT;
-	int matchoff, matchlen;
-	__be32 ipaddr;
-	u_int16_t port;
-	typeof(ip_nat_sip_hook) ip_nat_sip;
-
-	/* No Data ? */
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-	if (dataoff >= (*pskb)->len) {
-		DEBUGP("skb->len = %u\n", (*pskb)->len);
-		return NF_ACCEPT;
-	}
-
-	ip_ct_refresh(ct, *pskb, sip_timeout * HZ);
-
-	if (!skb_is_nonlinear(*pskb))
-		dptr = (*pskb)->data + dataoff;
-	else {
-		DEBUGP("Copy of skbuff not supported yet.\n");
-		goto out;
-	}
-
-	ip_nat_sip = rcu_dereference(ip_nat_sip_hook);
-	if (ip_nat_sip) {
-		if (!ip_nat_sip(pskb, ctinfo, ct, &dptr)) {
-			ret = NF_DROP;
-			goto out;
-		}
-	}
-
-	/* After this point NAT, could have mangled skb, so
-	   we need to recalculate payload lenght. */
-	datalen = (*pskb)->len - dataoff;
-
-	if (datalen < (sizeof("SIP/2.0 200") - 1))
-		goto out;
-
-	/* RTP info only in some SDP pkts */
-	if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
-	    memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
-		goto out;
-	}
-	/* Get ip and port address from SDP packet. */
-	if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
-			    POS_CONNECTION) > 0) {
-
-		/* We'll drop only if there are parse problems. */
-		if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr,
-				 dptr + datalen) < 0) {
-			ret = NF_DROP;
-			goto out;
-		}
-		if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
-				    POS_MEDIA) > 0) {
-
-			port = simple_strtoul(dptr + matchoff, NULL, 10);
-			if (port < 1024) {
-				ret = NF_DROP;
-				goto out;
-			}
-			ret = set_expected_rtp(pskb, ct, ctinfo,
-					       ipaddr, port, dptr);
-		}
-	}
-out:
-	return ret;
-}
-
-static struct ip_conntrack_helper sip[MAX_PORTS];
-static char sip_names[MAX_PORTS][10];
-
-static void fini(void)
-{
-	int i;
-	for (i = 0; i < ports_c; i++) {
-		DEBUGP("unregistering helper for port %d\n", ports[i]);
-		ip_conntrack_helper_unregister(&sip[i]);
-	}
-}
-
-static int __init init(void)
-{
-	int i, ret;
-	char *tmpname;
-
-	if (ports_c == 0)
-		ports[ports_c++] = SIP_PORT;
-
-	for (i = 0; i < ports_c; i++) {
-		/* Create helper structure */
-		memset(&sip[i], 0, sizeof(struct ip_conntrack_helper));
-
-		sip[i].tuple.dst.protonum = IPPROTO_UDP;
-		sip[i].tuple.src.u.udp.port = htons(ports[i]);
-		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 */
-		sip[i].me = THIS_MODULE;
-		sip[i].help = sip_help;
-
-		tmpname = &sip_names[i][0];
-		if (ports[i] == SIP_PORT)
-			sprintf(tmpname, "sip");
-		else
-			sprintf(tmpname, "sip-%d", i);
-		sip[i].name = tmpname;
-
-		DEBUGP("port #%d: %d\n", i, ports[i]);
-
-		ret = ip_conntrack_helper_register(&sip[i]);
-		if (ret) {
-			printk("ERROR registering helper for port %d\n",
-				ports[i]);
-			fini();
-			return ret;
-		}
-	}
-	return 0;
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
deleted file mode 100644
index 56b2f75..0000000
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/* This file contains all the functions required for the standalone
-   ip_conntrack module.
-
-   These are not required by the compatibility layer.
-*/
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2005 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/percpu.h>
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-#endif
-#include <net/checksum.h>
-#include <net/ip.h>
-#include <net/route.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-MODULE_LICENSE("GPL");
-
-extern atomic_t ip_conntrack_count;
-DECLARE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
-
-static int kill_proto(struct ip_conntrack *i, void *data)
-{
-	return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
-			*((u_int8_t *) data));
-}
-
-#ifdef CONFIG_PROC_FS
-static int
-print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple,
-	    struct ip_conntrack_protocol *proto)
-{
-	seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
-		   NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
-	return proto->print_tuple(s, tuple);
-}
-
-#ifdef CONFIG_IP_NF_CT_ACCT
-static unsigned int
-seq_print_counters(struct seq_file *s,
-		   const struct ip_conntrack_counter *counter)
-{
-	return seq_printf(s, "packets=%llu bytes=%llu ",
-			  (unsigned long long)counter->packets,
-			  (unsigned long long)counter->bytes);
-}
-#else
-#define seq_print_counters(x, y)	0
-#endif
-
-struct ct_iter_state {
-	unsigned int bucket;
-};
-
-static struct list_head *ct_get_first(struct seq_file *seq)
-{
-	struct ct_iter_state *st = seq->private;
-
-	for (st->bucket = 0;
-	     st->bucket < ip_conntrack_htable_size;
-	     st->bucket++) {
-		if (!list_empty(&ip_conntrack_hash[st->bucket]))
-			return ip_conntrack_hash[st->bucket].next;
-	}
-	return NULL;
-}
-
-static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
-{
-	struct ct_iter_state *st = seq->private;
-
-	head = head->next;
-	while (head == &ip_conntrack_hash[st->bucket]) {
-		if (++st->bucket >= ip_conntrack_htable_size)
-			return NULL;
-		head = ip_conntrack_hash[st->bucket].next;
-	}
-	return head;
-}
-
-static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
-{
-	struct list_head *head = ct_get_first(seq);
-
-	if (head)
-		while (pos && (head = ct_get_next(seq, head)))
-			pos--;
-	return pos ? NULL : head;
-}
-
-static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
-{
-	read_lock_bh(&ip_conntrack_lock);
-	return ct_get_idx(seq, *pos);
-}
-
-static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
-	(*pos)++;
-	return ct_get_next(s, v);
-}
-
-static void ct_seq_stop(struct seq_file *s, void *v)
-{
-	read_unlock_bh(&ip_conntrack_lock);
-}
-
-static int ct_seq_show(struct seq_file *s, void *v)
-{
-	const struct ip_conntrack_tuple_hash *hash = v;
-	const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
-	struct ip_conntrack_protocol *proto;
-
-	IP_NF_ASSERT(conntrack);
-
-	/* we only want to print DIR_ORIGINAL */
-	if (DIRECTION(hash))
-		return 0;
-
-	proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
-	IP_NF_ASSERT(proto);
-
-	if (seq_printf(s, "%-8s %u %ld ",
-		      proto->name,
-		      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
-		      timer_pending(&conntrack->timeout)
-		      ? (long)(conntrack->timeout.expires - jiffies)/HZ
-		      : 0) != 0)
-		return -ENOSPC;
-
-	if (proto->print_conntrack(s, conntrack))
-		return -ENOSPC;
-
-	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
-			proto))
-		return -ENOSPC;
-
-	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
-		return -ENOSPC;
-
-	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
-		if (seq_printf(s, "[UNREPLIED] "))
-			return -ENOSPC;
-
-	if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
-			proto))
-		return -ENOSPC;
-
-	if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
-		return -ENOSPC;
-
-	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
-		if (seq_printf(s, "[ASSURED] "))
-			return -ENOSPC;
-
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
-	if (seq_printf(s, "mark=%u ", conntrack->mark))
-		return -ENOSPC;
-#endif
-
-#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
-	if (seq_printf(s, "secmark=%u ", conntrack->secmark))
-		return -ENOSPC;
-#endif
-
-	if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
-		return -ENOSPC;
-
-	return 0;
-}
-
-static struct seq_operations ct_seq_ops = {
-	.start = ct_seq_start,
-	.next  = ct_seq_next,
-	.stop  = ct_seq_stop,
-	.show  = ct_seq_show
-};
-
-static int ct_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *seq;
-	struct ct_iter_state *st;
-	int ret;
-
-	st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
-	if (st == NULL)
-		return -ENOMEM;
-	ret = seq_open(file, &ct_seq_ops);
-	if (ret)
-		goto out_free;
-	seq          = file->private_data;
-	seq->private = st;
-	memset(st, 0, sizeof(struct ct_iter_state));
-	return ret;
-out_free:
-	kfree(st);
-	return ret;
-}
-
-static const struct file_operations ct_file_ops = {
-	.owner   = THIS_MODULE,
-	.open    = ct_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release_private,
-};
-
-/* expects */
-static void *exp_seq_start(struct seq_file *s, loff_t *pos)
-{
-	struct list_head *e = &ip_conntrack_expect_list;
-	loff_t i;
-
-	/* strange seq_file api calls stop even if we fail,
-	 * thus we need to grab lock since stop unlocks */
-	read_lock_bh(&ip_conntrack_lock);
-
-	if (list_empty(e))
-		return NULL;
-
-	for (i = 0; i <= *pos; i++) {
-		e = e->next;
-		if (e == &ip_conntrack_expect_list)
-			return NULL;
-	}
-	return e;
-}
-
-static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
-	struct list_head *e = v;
-
-	++*pos;
-	e = e->next;
-
-	if (e == &ip_conntrack_expect_list)
-		return NULL;
-
-	return e;
-}
-
-static void exp_seq_stop(struct seq_file *s, void *v)
-{
-	read_unlock_bh(&ip_conntrack_lock);
-}
-
-static int exp_seq_show(struct seq_file *s, void *v)
-{
-	struct ip_conntrack_expect *expect = v;
-
-	if (expect->timeout.function)
-		seq_printf(s, "%ld ", timer_pending(&expect->timeout)
-			   ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
-	else
-		seq_printf(s, "- ");
-
-	seq_printf(s, "proto=%u ", expect->tuple.dst.protonum);
-
-	print_tuple(s, &expect->tuple,
-		    __ip_conntrack_proto_find(expect->tuple.dst.protonum));
-	return seq_putc(s, '\n');
-}
-
-static struct seq_operations exp_seq_ops = {
-	.start = exp_seq_start,
-	.next = exp_seq_next,
-	.stop = exp_seq_stop,
-	.show = exp_seq_show
-};
-
-static int exp_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &exp_seq_ops);
-}
-
-static const struct file_operations exp_file_ops = {
-	.owner   = THIS_MODULE,
-	.open    = exp_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release
-};
-
-static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
-{
-	int cpu;
-
-	if (*pos == 0)
-		return SEQ_START_TOKEN;
-
-	for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
-		if (!cpu_possible(cpu))
-			continue;
-		*pos = cpu+1;
-		return &per_cpu(ip_conntrack_stat, cpu);
-	}
-
-	return NULL;
-}
-
-static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-	int cpu;
-
-	for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
-		if (!cpu_possible(cpu))
-			continue;
-		*pos = cpu+1;
-		return &per_cpu(ip_conntrack_stat, cpu);
-	}
-
-	return NULL;
-}
-
-static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
-{
-}
-
-static int ct_cpu_seq_show(struct seq_file *seq, void *v)
-{
-	unsigned int nr_conntracks = atomic_read(&ip_conntrack_count);
-	struct ip_conntrack_stat *st = v;
-
-	if (v == SEQ_START_TOKEN) {
-		seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
-		return 0;
-	}
-
-	seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
-			"%08x %08x %08x %08x %08x  %08x %08x %08x \n",
-		   nr_conntracks,
-		   st->searched,
-		   st->found,
-		   st->new,
-		   st->invalid,
-		   st->ignore,
-		   st->delete,
-		   st->delete_list,
-		   st->insert,
-		   st->insert_failed,
-		   st->drop,
-		   st->early_drop,
-		   st->error,
-
-		   st->expect_new,
-		   st->expect_create,
-		   st->expect_delete
-		);
-	return 0;
-}
-
-static struct seq_operations ct_cpu_seq_ops = {
-	.start  = ct_cpu_seq_start,
-	.next   = ct_cpu_seq_next,
-	.stop   = ct_cpu_seq_stop,
-	.show   = ct_cpu_seq_show,
-};
-
-static int ct_cpu_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &ct_cpu_seq_ops);
-}
-
-static const struct file_operations ct_cpu_seq_fops = {
-	.owner   = THIS_MODULE,
-	.open    = ct_cpu_seq_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release_private,
-};
-#endif
-
-static unsigned int ip_confirm(unsigned int hooknum,
-			       struct sk_buff **pskb,
-			       const struct net_device *in,
-			       const struct net_device *out,
-			       int (*okfn)(struct sk_buff *))
-{
-	/* We've seen it coming out the other side: confirm it */
-	return ip_conntrack_confirm(pskb);
-}
-
-static unsigned int ip_conntrack_help(unsigned int hooknum,
-				      struct sk_buff **pskb,
-				      const struct net_device *in,
-				      const struct net_device *out,
-				      int (*okfn)(struct sk_buff *))
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-
-	/* This is where we call the helper: as the packet goes out. */
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-	if (ct && ct->helper && ctinfo != IP_CT_RELATED + IP_CT_IS_REPLY) {
-		unsigned int ret;
-		ret = ct->helper->help(pskb, ct, ctinfo);
-		if (ret != NF_ACCEPT)
-			return ret;
-	}
-	return NF_ACCEPT;
-}
-
-static unsigned int ip_conntrack_defrag(unsigned int hooknum,
-					struct sk_buff **pskb,
-					const struct net_device *in,
-					const struct net_device *out,
-					int (*okfn)(struct sk_buff *))
-{
-#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
-	/* Previously seen (loopback)?  Ignore.  Do this before
-	   fragment check. */
-	if ((*pskb)->nfct)
-		return NF_ACCEPT;
-#endif
-
-	/* Gather fragments. */
-	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
-		*pskb = ip_ct_gather_frags(*pskb,
-					   hooknum == NF_IP_PRE_ROUTING ?
-					   IP_DEFRAG_CONNTRACK_IN :
-					   IP_DEFRAG_CONNTRACK_OUT);
-		if (!*pskb)
-			return NF_STOLEN;
-	}
-	return NF_ACCEPT;
-}
-
-static unsigned int ip_conntrack_local(unsigned int hooknum,
-				       struct sk_buff **pskb,
-				       const struct net_device *in,
-				       const struct net_device *out,
-				       int (*okfn)(struct sk_buff *))
-{
-	/* root is playing with raw sockets. */
-	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
-		if (net_ratelimit())
-			printk("ipt_hook: happy cracking.\n");
-		return NF_ACCEPT;
-	}
-	return ip_conntrack_in(hooknum, pskb, in, out, okfn);
-}
-
-/* Connection tracking may drop packets, but never alters them, so
-   make it the first hook. */
-static struct nf_hook_ops ip_conntrack_ops[] = {
-	{
-		.hook		= ip_conntrack_defrag,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_PRE_ROUTING,
-		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-	},
-	{
-		.hook		= ip_conntrack_in,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_PRE_ROUTING,
-		.priority	= NF_IP_PRI_CONNTRACK,
-	},
-	{
-		.hook		= ip_conntrack_defrag,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_OUT,
-		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-	},
-	{
-		.hook		= ip_conntrack_local,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_OUT,
-		.priority	= NF_IP_PRI_CONNTRACK,
-	},
-	{
-		.hook		= ip_conntrack_help,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_POST_ROUTING,
-		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-	},
-	{
-		.hook		= ip_conntrack_help,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_IN,
-		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-	},
-	{
-		.hook		= ip_confirm,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_POST_ROUTING,
-		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
-	},
-	{
-		.hook		= ip_confirm,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_IN,
-		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
-	},
-};
-
-/* Sysctl support */
-
-int ip_conntrack_checksum __read_mostly = 1;
-
-#ifdef CONFIG_SYSCTL
-
-/* From ip_conntrack_core.c */
-extern int ip_conntrack_max;
-extern unsigned int ip_conntrack_htable_size;
-
-/* From ip_conntrack_proto_tcp.c */
-extern unsigned int ip_ct_tcp_timeout_syn_sent;
-extern unsigned int ip_ct_tcp_timeout_syn_recv;
-extern unsigned int ip_ct_tcp_timeout_established;
-extern unsigned int ip_ct_tcp_timeout_fin_wait;
-extern unsigned int ip_ct_tcp_timeout_close_wait;
-extern unsigned int ip_ct_tcp_timeout_last_ack;
-extern unsigned int ip_ct_tcp_timeout_time_wait;
-extern unsigned int ip_ct_tcp_timeout_close;
-extern unsigned int ip_ct_tcp_timeout_max_retrans;
-extern int ip_ct_tcp_loose;
-extern int ip_ct_tcp_be_liberal;
-extern int ip_ct_tcp_max_retrans;
-
-/* From ip_conntrack_proto_udp.c */
-extern unsigned int ip_ct_udp_timeout;
-extern unsigned int ip_ct_udp_timeout_stream;
-
-/* From ip_conntrack_proto_icmp.c */
-extern unsigned int ip_ct_icmp_timeout;
-
-/* From ip_conntrack_proto_generic.c */
-extern unsigned int ip_ct_generic_timeout;
-
-/* Log invalid packets of a given protocol */
-static int log_invalid_proto_min = 0;
-static int log_invalid_proto_max = 255;
-
-static struct ctl_table_header *ip_ct_sysctl_header;
-
-static ctl_table ip_ct_sysctl_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_MAX,
-		.procname	= "ip_conntrack_max",
-		.data		= &ip_conntrack_max,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_COUNT,
-		.procname	= "ip_conntrack_count",
-		.data		= &ip_conntrack_count,
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_BUCKETS,
-		.procname	= "ip_conntrack_buckets",
-		.data		= &ip_conntrack_htable_size,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_CHECKSUM,
-		.procname	= "ip_conntrack_checksum",
-		.data		= &ip_conntrack_checksum,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
-		.procname	= "ip_conntrack_tcp_timeout_syn_sent",
-		.data		= &ip_ct_tcp_timeout_syn_sent,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
-		.procname	= "ip_conntrack_tcp_timeout_syn_recv",
-		.data		= &ip_ct_tcp_timeout_syn_recv,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
-		.procname	= "ip_conntrack_tcp_timeout_established",
-		.data		= &ip_ct_tcp_timeout_established,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
-		.procname	= "ip_conntrack_tcp_timeout_fin_wait",
-		.data		= &ip_ct_tcp_timeout_fin_wait,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
-		.procname	= "ip_conntrack_tcp_timeout_close_wait",
-		.data		= &ip_ct_tcp_timeout_close_wait,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
-		.procname	= "ip_conntrack_tcp_timeout_last_ack",
-		.data		= &ip_ct_tcp_timeout_last_ack,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
-		.procname	= "ip_conntrack_tcp_timeout_time_wait",
-		.data		= &ip_ct_tcp_timeout_time_wait,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
-		.procname	= "ip_conntrack_tcp_timeout_close",
-		.data		= &ip_ct_tcp_timeout_close,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
-		.procname	= "ip_conntrack_udp_timeout",
-		.data		= &ip_ct_udp_timeout,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
-		.procname	= "ip_conntrack_udp_timeout_stream",
-		.data		= &ip_ct_udp_timeout_stream,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
-		.procname	= "ip_conntrack_icmp_timeout",
-		.data		= &ip_ct_icmp_timeout,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
-		.procname	= "ip_conntrack_generic_timeout",
-		.data		= &ip_ct_generic_timeout,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_LOG_INVALID,
-		.procname	= "ip_conntrack_log_invalid",
-		.data		= &ip_ct_log_invalid,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_minmax,
-		.strategy	= &sysctl_intvec,
-		.extra1		= &log_invalid_proto_min,
-		.extra2		= &log_invalid_proto_max,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,
-		.procname	= "ip_conntrack_tcp_timeout_max_retrans",
-		.data		= &ip_ct_tcp_timeout_max_retrans,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec_jiffies,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_LOOSE,
-		.procname	= "ip_conntrack_tcp_loose",
-		.data		= &ip_ct_tcp_loose,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,
-		.procname	= "ip_conntrack_tcp_be_liberal",
-		.data		= &ip_ct_tcp_be_liberal,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,
-		.procname	= "ip_conntrack_tcp_max_retrans",
-		.data		= &ip_ct_tcp_max_retrans,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{ .ctl_name = 0 }
-};
-
-#define NET_IP_CONNTRACK_MAX 2089
-
-static ctl_table ip_ct_netfilter_table[] = {
-	{
-		.ctl_name	= NET_IPV4_NETFILTER,
-		.procname	= "netfilter",
-		.mode		= 0555,
-		.child		= ip_ct_sysctl_table,
-	},
-	{
-		.ctl_name	= NET_IP_CONNTRACK_MAX,
-		.procname	= "ip_conntrack_max",
-		.data		= &ip_conntrack_max,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ip_ct_ipv4_table[] = {
-	{
-		.ctl_name	= NET_IPV4,
-		.procname	= "ipv4",
-		.mode		= 0555,
-		.child		= ip_ct_netfilter_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table ip_ct_net_table[] = {
-	{
-		.ctl_name	= CTL_NET,
-		.procname	= "net",
-		.mode		= 0555,
-		.child		= ip_ct_ipv4_table,
-	},
-	{ .ctl_name = 0 }
-};
-
-EXPORT_SYMBOL(ip_ct_log_invalid);
-#endif /* CONFIG_SYSCTL */
-
-/* FIXME: Allow NULL functions and sub in pointers to generic for
-   them. --RR */
-int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
-{
-	int ret = 0;
-
-	write_lock_bh(&ip_conntrack_lock);
-	if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) {
-		ret = -EBUSY;
-		goto out;
-	}
-	rcu_assign_pointer(ip_ct_protos[proto->proto], proto);
- out:
-	write_unlock_bh(&ip_conntrack_lock);
-	return ret;
-}
-
-void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	rcu_assign_pointer(ip_ct_protos[proto->proto],
-			   &ip_conntrack_generic_protocol);
-	write_unlock_bh(&ip_conntrack_lock);
-	synchronize_rcu();
-
-	/* Remove all contrack entries for this protocol */
-	ip_ct_iterate_cleanup(kill_proto, &proto->proto);
-}
-
-static int __init ip_conntrack_standalone_init(void)
-{
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
-#endif
-	int ret = 0;
-
-	ret = ip_conntrack_init();
-	if (ret < 0)
-		return ret;
-
-#ifdef CONFIG_PROC_FS
-	ret = -ENOMEM;
-	proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops);
-	if (!proc) goto cleanup_init;
-
-	proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440,
-					&exp_file_ops);
-	if (!proc_exp) goto cleanup_proc;
-
-	proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat);
-	if (!proc_stat)
-		goto cleanup_proc_exp;
-
-	proc_stat->proc_fops = &ct_cpu_seq_fops;
-	proc_stat->owner = THIS_MODULE;
-#endif
-
-	ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
-	if (ret < 0) {
-		printk("ip_conntrack: can't register hooks.\n");
-		goto cleanup_proc_stat;
-	}
-#ifdef CONFIG_SYSCTL
-	ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table);
-	if (ip_ct_sysctl_header == NULL) {
-		printk("ip_conntrack: can't register to sysctl.\n");
-		ret = -ENOMEM;
-		goto cleanup_hooks;
-	}
-#endif
-	return ret;
-
-#ifdef CONFIG_SYSCTL
- cleanup_hooks:
-	nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
-#endif
- cleanup_proc_stat:
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("ip_conntrack", proc_net_stat);
- cleanup_proc_exp:
-	proc_net_remove("ip_conntrack_expect");
- cleanup_proc:
-	proc_net_remove("ip_conntrack");
- cleanup_init:
-#endif /* CONFIG_PROC_FS */
-	ip_conntrack_cleanup();
-	return ret;
-}
-
-static void __exit ip_conntrack_standalone_fini(void)
-{
-	synchronize_net();
-#ifdef CONFIG_SYSCTL
-	unregister_sysctl_table(ip_ct_sysctl_header);
-#endif
-	nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("ip_conntrack", proc_net_stat);
-	proc_net_remove("ip_conntrack_expect");
-	proc_net_remove("ip_conntrack");
-#endif /* CONFIG_PROC_FS */
-	ip_conntrack_cleanup();
-}
-
-module_init(ip_conntrack_standalone_init);
-module_exit(ip_conntrack_standalone_fini);
-
-/* Some modules need us, but don't depend directly on any symbol.
-   They should call this. */
-void need_conntrack(void)
-{
-}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-EXPORT_SYMBOL_GPL(ip_conntrack_chain);
-EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
-EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
-EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
-EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init);
-EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
-#endif
-EXPORT_SYMBOL(ip_conntrack_protocol_register);
-EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
-EXPORT_SYMBOL(ip_ct_get_tuple);
-EXPORT_SYMBOL(invert_tuplepr);
-EXPORT_SYMBOL(ip_conntrack_alter_reply);
-EXPORT_SYMBOL(ip_conntrack_destroyed);
-EXPORT_SYMBOL(need_conntrack);
-EXPORT_SYMBOL(ip_conntrack_helper_register);
-EXPORT_SYMBOL(ip_conntrack_helper_unregister);
-EXPORT_SYMBOL(ip_ct_iterate_cleanup);
-EXPORT_SYMBOL(__ip_ct_refresh_acct);
-
-EXPORT_SYMBOL(ip_conntrack_expect_alloc);
-EXPORT_SYMBOL(ip_conntrack_expect_put);
-EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find);
-EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
-EXPORT_SYMBOL(ip_conntrack_expect_related);
-EXPORT_SYMBOL(ip_conntrack_unexpect_related);
-EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
-EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
-
-EXPORT_SYMBOL(ip_conntrack_tuple_taken);
-EXPORT_SYMBOL(ip_ct_gather_frags);
-EXPORT_SYMBOL(ip_conntrack_htable_size);
-EXPORT_SYMBOL(ip_conntrack_lock);
-EXPORT_SYMBOL(ip_conntrack_hash);
-EXPORT_SYMBOL(ip_conntrack_untracked);
-EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
-#ifdef CONFIG_IP_NF_NAT_NEEDED
-EXPORT_SYMBOL(ip_conntrack_tcp_update);
-#endif
-
-EXPORT_SYMBOL_GPL(ip_conntrack_flush);
-EXPORT_SYMBOL_GPL(__ip_conntrack_find);
-
-EXPORT_SYMBOL_GPL(ip_conntrack_alloc);
-EXPORT_SYMBOL_GPL(ip_conntrack_free);
-EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert);
-
-EXPORT_SYMBOL_GPL(ip_ct_remove_expectations);
-
-EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get);
-EXPORT_SYMBOL_GPL(ip_conntrack_helper_put);
-EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname);
-
-EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get);
-EXPORT_SYMBOL_GPL(ip_conntrack_proto_put);
-EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find);
-EXPORT_SYMBOL_GPL(ip_conntrack_checksum);
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr);
-EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple);
-#endif
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
deleted file mode 100644
index 76e175e..0000000
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Version: 0.0.7
- *
- * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
- * 	- port to newnat API
- *
- */
-
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
-#include <linux/moduleparam.h>
-
-MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
-MODULE_DESCRIPTION("tftp connection tracking helper");
-MODULE_LICENSE("GPL");
-
-#define MAX_PORTS 8
-static unsigned short ports[MAX_PORTS];
-static int ports_c;
-module_param_array(ports, ushort, &ports_c, 0400);
-MODULE_PARM_DESC(ports, "port numbers of tftp servers");
-
-#if 0
-#define DEBUGP(format, args...) printk("%s:%s:" format, \
-				       __FILE__, __FUNCTION__ , ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
-unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb,
-				 enum ip_conntrack_info ctinfo,
-				 struct ip_conntrack_expect *exp);
-EXPORT_SYMBOL_GPL(ip_nat_tftp_hook);
-
-static int tftp_help(struct sk_buff **pskb,
-		     struct ip_conntrack *ct,
-		     enum ip_conntrack_info ctinfo)
-{
-	struct tftphdr _tftph, *tfh;
-	struct ip_conntrack_expect *exp;
-	unsigned int ret = NF_ACCEPT;
-	typeof(ip_nat_tftp_hook) ip_nat_tftp;
-
-	tfh = skb_header_pointer(*pskb,
-				 (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
-				 sizeof(_tftph), &_tftph);
-	if (tfh == NULL)
-		return NF_ACCEPT;
-
-	switch (ntohs(tfh->opcode)) {
-	/* RRQ and WRQ works the same way */
-	case TFTP_OPCODE_READ:
-	case TFTP_OPCODE_WRITE:
-		DEBUGP("");
-		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-		DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-
-		exp = ip_conntrack_expect_alloc(ct);
-		if (exp == NULL)
-			return NF_DROP;
-
-		exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-		exp->mask.src.ip = htonl(0xffffffff);
-		exp->mask.src.u.udp.port = 0;
-		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;
-
-		DEBUGP("expect: ");
-		DUMP_TUPLE(&exp->tuple);
-		DUMP_TUPLE(&exp->mask);
-		ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook);
-		if (ip_nat_tftp)
-			ret = ip_nat_tftp(pskb, ctinfo, exp);
-		else if (ip_conntrack_expect_related(exp) != 0)
-			ret = NF_DROP;
-		ip_conntrack_expect_put(exp);
-		break;
-	case TFTP_OPCODE_DATA:
-	case TFTP_OPCODE_ACK:
-		DEBUGP("Data/ACK opcode\n");
-		break;
-	case TFTP_OPCODE_ERROR:
-		DEBUGP("Error opcode\n");
-		break;
-	default:
-		DEBUGP("Unknown opcode\n");
-	}
-	return NF_ACCEPT;
-}
-
-static struct ip_conntrack_helper tftp[MAX_PORTS];
-static char tftp_names[MAX_PORTS][sizeof("tftp-65535")];
-
-static void ip_conntrack_tftp_fini(void)
-{
-	int i;
-
-	for (i = 0 ; i < ports_c; i++) {
-		DEBUGP("unregistering helper for port %d\n",
-			ports[i]);
-		ip_conntrack_helper_unregister(&tftp[i]);
-	}
-}
-
-static int __init ip_conntrack_tftp_init(void)
-{
-	int i, ret;
-	char *tmpname;
-
-	if (ports_c == 0)
-		ports[ports_c++] = TFTP_PORT;
-
-	for (i = 0; i < ports_c; i++) {
-		/* Create helper structure */
-		memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
-
-		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 = htons(0xFFFF);
-		tftp[i].max_expected = 1;
-		tftp[i].timeout = 5 * 60; /* 5 minutes */
-		tftp[i].me = THIS_MODULE;
-		tftp[i].help = tftp_help;
-
-		tmpname = &tftp_names[i][0];
-		if (ports[i] == TFTP_PORT)
-			sprintf(tmpname, "tftp");
-		else
-			sprintf(tmpname, "tftp-%d", i);
-		tftp[i].name = tmpname;
-
-		DEBUGP("port #%d: %d\n", i, ports[i]);
-
-		ret=ip_conntrack_helper_register(&tftp[i]);
-		if (ret) {
-			printk("ERROR registering helper for port %d\n",
-				ports[i]);
-			ip_conntrack_tftp_fini();
-			return(ret);
-		}
-	}
-	return(0);
-}
-
-module_init(ip_conntrack_tftp_init);
-module_exit(ip_conntrack_tftp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c
deleted file mode 100644
index 85df1a9..0000000
--- a/net/ipv4/netfilter/ip_nat_amanda.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Amanda extension for TCP NAT alteration.
- * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
- * based on a copy of HW's ip_nat_irc.c as well as other modules
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- *	Module load syntax:
- * 	insmod ip_nat_amanda.o
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netfilter.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
-
-
-MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
-MODULE_DESCRIPTION("Amanda NAT helper");
-MODULE_LICENSE("GPL");
-
-static unsigned int help(struct sk_buff **pskb,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned int matchoff,
-			 unsigned int matchlen,
-			 struct ip_conntrack_expect *exp)
-{
-	char buffer[sizeof("65535")];
-	u_int16_t port;
-	unsigned int ret;
-
-	/* Connection comes from client. */
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->dir = IP_CT_DIR_ORIGINAL;
-
-	/* When you see the packet, we need to NAT it the same as the
-	 * this one (ie. same IP: it will be TCP and master is UDP). */
-	exp->expectfn = ip_nat_follow_master;
-
-	/* Try to get same port: if not, try to change it. */
-	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
-		exp->tuple.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (port == 0)
-		return NF_DROP;
-
-	sprintf(buffer, "%u", port);
-	ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
-				       matchoff, matchlen,
-				       buffer, strlen(buffer));
-	if (ret != NF_ACCEPT)
-		ip_conntrack_unexpect_related(exp);
-	return ret;
-}
-
-static void __exit ip_nat_amanda_fini(void)
-{
-	rcu_assign_pointer(ip_nat_amanda_hook, NULL);
-	synchronize_rcu();
-}
-
-static int __init ip_nat_amanda_init(void)
-{
-	BUG_ON(rcu_dereference(ip_nat_amanda_hook));
-	rcu_assign_pointer(ip_nat_amanda_hook, help);
-	return 0;
-}
-
-module_init(ip_nat_amanda_init);
-module_exit(ip_nat_amanda_fini);
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
deleted file mode 100644
index 40737fd..0000000
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/* NAT for netfilter; shared with compatibility layer. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/vmalloc.h>
-#include <net/checksum.h>
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/tcp.h>  /* For tcp_prot in getorigdst */
-#include <linux/icmp.h>
-#include <linux/udp.h>
-#include <linux/jhash.h>
-
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_protocol.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/ip_conntrack_helper.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-DEFINE_RWLOCK(ip_nat_lock);
-
-/* Calculated at init based on memory size */
-static unsigned int ip_nat_htable_size;
-
-static struct list_head *bysource;
-
-#define MAX_IP_NAT_PROTO 256
-static struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
-
-static inline struct ip_nat_protocol *
-__ip_nat_proto_find(u_int8_t protonum)
-{
-	return rcu_dereference(ip_nat_protos[protonum]);
-}
-
-struct ip_nat_protocol *
-ip_nat_proto_find_get(u_int8_t protonum)
-{
-	struct ip_nat_protocol *p;
-
-	rcu_read_lock();
-	p = __ip_nat_proto_find(protonum);
-	if (!try_module_get(p->me))
-		p = &ip_nat_unknown_protocol;
-	rcu_read_unlock();
-
-	return p;
-}
-EXPORT_SYMBOL_GPL(ip_nat_proto_find_get);
-
-void
-ip_nat_proto_put(struct ip_nat_protocol *p)
-{
-	module_put(p->me);
-}
-EXPORT_SYMBOL_GPL(ip_nat_proto_put);
-
-/* We keep an extra hash for each conntrack, for fast searching. */
-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((__force u32)tuple->src.ip, tuple->src.u.all,
-			    tuple->dst.protonum, 0) % ip_nat_htable_size;
-}
-
-/* Noone using conntrack by the time this called. */
-static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
-{
-	if (!(conn->status & IPS_NAT_DONE_MASK))
-		return;
-
-	write_lock_bh(&ip_nat_lock);
-	list_del(&conn->nat.info.bysource);
-	write_unlock_bh(&ip_nat_lock);
-}
-
-/* Is this tuple already taken? (not by us) */
-int
-ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
-		  const struct ip_conntrack *ignored_conntrack)
-{
-	/* Conntrack tracking doesn't keep track of outgoing tuples; only
-	   incoming ones.  NAT means they don't have a fixed mapping,
-	   so we invert the tuple and look for the incoming reply.
-
-	   We could keep a separate hash if this proves too slow. */
-	struct ip_conntrack_tuple reply;
-
-	invert_tuplepr(&reply, tuple);
-	return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
-}
-EXPORT_SYMBOL(ip_nat_used_tuple);
-
-/* If we source map this tuple so reply looks like reply_tuple, will
- * that meet the constraints of range. */
-static int
-in_range(const struct ip_conntrack_tuple *tuple,
-	 const struct ip_nat_range *range)
-{
-	struct ip_nat_protocol *proto;
-	int ret = 0;
-
-	/* If we are supposed to map IPs, then we must be in the
-	   range specified, otherwise let this drag us onto a new src IP. */
-	if (range->flags & IP_NAT_RANGE_MAP_IPS) {
-		if (ntohl(tuple->src.ip) < ntohl(range->min_ip)
-		    || ntohl(tuple->src.ip) > ntohl(range->max_ip))
-			return 0;
-	}
-
-	rcu_read_lock();
-	proto = __ip_nat_proto_find(tuple->dst.protonum);
-	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
-	    || proto->in_range(tuple, IP_NAT_MANIP_SRC,
-			       &range->min, &range->max))
-		ret = 1;
-	rcu_read_unlock();
-
-	return ret;
-}
-
-static inline int
-same_src(const struct ip_conntrack *ct,
-	 const struct ip_conntrack_tuple *tuple)
-{
-	return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
-		== tuple->dst.protonum
-		&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
-		== tuple->src.ip
-		&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
-		== tuple->src.u.all);
-}
-
-/* Only called for SRC manip */
-static int
-find_appropriate_src(const struct ip_conntrack_tuple *tuple,
-		     struct ip_conntrack_tuple *result,
-		     const struct ip_nat_range *range)
-{
-	unsigned int h = hash_by_src(tuple);
-	struct ip_conntrack *ct;
-
-	read_lock_bh(&ip_nat_lock);
-	list_for_each_entry(ct, &bysource[h], nat.info.bysource) {
-		if (same_src(ct, tuple)) {
-			/* Copy source part from reply tuple. */
-			invert_tuplepr(result,
-				       &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
-			result->dst = tuple->dst;
-
-			if (in_range(result, range)) {
-				read_unlock_bh(&ip_nat_lock);
-				return 1;
-			}
-		}
-	}
-	read_unlock_bh(&ip_nat_lock);
-	return 0;
-}
-
-/* For [FUTURE] fragmentation handling, we want the least-used
-   src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
-   if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
-   1-65535, we don't do pro-rata allocation based on ports; we choose
-   the ip with the lowest src-ip/dst-ip/proto usage.
-*/
-static void
-find_best_ips_proto(struct ip_conntrack_tuple *tuple,
-		    const struct ip_nat_range *range,
-		    const struct ip_conntrack *conntrack,
-		    enum ip_nat_manip_type maniptype)
-{
-	__be32 *var_ipp;
-	/* Host order */
-	u_int32_t minip, maxip, j;
-
-	/* No IP mapping?  Do nothing. */
-	if (!(range->flags & IP_NAT_RANGE_MAP_IPS))
-		return;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		var_ipp = &tuple->src.ip;
-	else
-		var_ipp = &tuple->dst.ip;
-
-	/* Fast path: only one choice. */
-	if (range->min_ip == range->max_ip) {
-		*var_ipp = range->min_ip;
-		return;
-	}
-
-	/* Hashing source and destination IPs gives a fairly even
-	 * spread in practice (if there are a small number of IPs
-	 * involved, there usually aren't that many connections
-	 * anyway).  The consistency means that servers see the same
-	 * client coming from the same IP (some Internet Banking sites
-	 * like this), even across reboots. */
-	minip = ntohl(range->min_ip);
-	maxip = ntohl(range->max_ip);
-	j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0);
-	*var_ipp = htonl(minip + j % (maxip - minip + 1));
-}
-
-/* Manipulate the tuple into the range given.  For NF_IP_POST_ROUTING,
- * we change the source to map into the range.  For NF_IP_PRE_ROUTING
- * and NF_IP_LOCAL_OUT, we change the destination to map into the
- * range.  It might not be possible to get a unique tuple, but we try.
- * At worst (or if we race), we will end up with a final duplicate in
- * __ip_conntrack_confirm and drop the packet. */
-static void
-get_unique_tuple(struct ip_conntrack_tuple *tuple,
-		 const struct ip_conntrack_tuple *orig_tuple,
-		 const struct ip_nat_range *range,
-		 struct ip_conntrack *conntrack,
-		 enum ip_nat_manip_type maniptype)
-{
-	struct ip_nat_protocol *proto;
-
-	/* 1) If this srcip/proto/src-proto-part is currently mapped,
-	   and that same mapping gives a unique tuple within the given
-	   range, use that.
-
-	   This is only required for source (ie. NAT/masq) mappings.
-	   So far, we don't do local source mappings, so multiple
-	   manips not an issue.  */
-	if (maniptype == IP_NAT_MANIP_SRC) {
-		if (find_appropriate_src(orig_tuple, tuple, range)) {
-			DEBUGP("get_unique_tuple: Found current src map\n");
-			if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
-				if (!ip_nat_used_tuple(tuple, conntrack))
-					return;
-		}
-	}
-
-	/* 2) Select the least-used IP/proto combination in the given
-	   range. */
-	*tuple = *orig_tuple;
-	find_best_ips_proto(tuple, range, conntrack, maniptype);
-
-	/* 3) The per-protocol part of the manip is made to map into
-	   the range to make a unique tuple. */
-
-	rcu_read_lock();
-	proto = __ip_nat_proto_find(orig_tuple->dst.protonum);
-
-	/* Change protocol info to have some randomization */
-	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
-		proto->unique_tuple(tuple, range, maniptype, conntrack);
-		goto out;
-	}
-
-	/* Only bother mapping if it's not already in range and unique */
-	if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
-	     || proto->in_range(tuple, maniptype, &range->min, &range->max))
-	    && !ip_nat_used_tuple(tuple, conntrack))
-		goto out;
-
-	/* Last change: get protocol to try to obtain unique tuple. */
-	proto->unique_tuple(tuple, range, maniptype, conntrack);
-out:
-	rcu_read_unlock();
-}
-
-unsigned int
-ip_nat_setup_info(struct ip_conntrack *conntrack,
-		  const struct ip_nat_range *range,
-		  unsigned int hooknum)
-{
-	struct ip_conntrack_tuple curr_tuple, new_tuple;
-	struct ip_nat_info *info = &conntrack->nat.info;
-	int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
-	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
-
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
-		     || hooknum == NF_IP_POST_ROUTING
-		     || hooknum == NF_IP_LOCAL_IN
-		     || hooknum == NF_IP_LOCAL_OUT);
-	BUG_ON(ip_nat_initialized(conntrack, maniptype));
-
-	/* What we've got will look like inverse of reply. Normally
-	   this is what is in the conntrack, except for prior
-	   manipulations (future optimization: if num_manips == 0,
-	   orig_tp =
-	   conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
-	invert_tuplepr(&curr_tuple,
-		       &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
-
-	get_unique_tuple(&new_tuple, &curr_tuple, range, conntrack, maniptype);
-
-	if (!ip_ct_tuple_equal(&new_tuple, &curr_tuple)) {
-		struct ip_conntrack_tuple reply;
-
-		/* Alter conntrack table so will recognize replies. */
-		invert_tuplepr(&reply, &new_tuple);
-		ip_conntrack_alter_reply(conntrack, &reply);
-
-		/* Non-atomic: we own this at the moment. */
-		if (maniptype == IP_NAT_MANIP_SRC)
-			conntrack->status |= IPS_SRC_NAT;
-		else
-			conntrack->status |= IPS_DST_NAT;
-	}
-
-	/* Place in source hash if this is the first time. */
-	if (have_to_hash) {
-		unsigned int srchash
-			= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
-				      .tuple);
-		write_lock_bh(&ip_nat_lock);
-		list_add(&info->bysource, &bysource[srchash]);
-		write_unlock_bh(&ip_nat_lock);
-	}
-
-	/* It's done. */
-	if (maniptype == IP_NAT_MANIP_DST)
-		set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
-	else
-		set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
-
-	return NF_ACCEPT;
-}
-EXPORT_SYMBOL(ip_nat_setup_info);
-
-/* Returns true if succeeded. */
-static int
-manip_pkt(u_int16_t proto,
-	  struct sk_buff **pskb,
-	  unsigned int iphdroff,
-	  const struct ip_conntrack_tuple *target,
-	  enum ip_nat_manip_type maniptype)
-{
-	struct iphdr *iph;
-	struct ip_nat_protocol *p;
-
-	if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
-		return 0;
-
-	iph = (void *)(*pskb)->data + iphdroff;
-
-	/* Manipulate protcol part. */
-
-	/* rcu_read_lock()ed by nf_hook_slow */
-	p = __ip_nat_proto_find(proto);
-	if (!p->manip_pkt(pskb, iphdroff, target, maniptype))
-		return 0;
-
-	iph = (void *)(*pskb)->data + iphdroff;
-
-	if (maniptype == IP_NAT_MANIP_SRC) {
-		nf_csum_replace4(&iph->check, iph->saddr, target->src.ip);
-		iph->saddr = target->src.ip;
-	} else {
-		nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip);
-		iph->daddr = target->dst.ip;
-	}
-	return 1;
-}
-
-/* Do packet manipulations according to ip_nat_setup_info. */
-unsigned int ip_nat_packet(struct ip_conntrack *ct,
-			   enum ip_conntrack_info ctinfo,
-			   unsigned int hooknum,
-			   struct sk_buff **pskb)
-{
-	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	unsigned long statusbit;
-	enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
-
-	if (mtype == IP_NAT_MANIP_SRC)
-		statusbit = IPS_SRC_NAT;
-	else
-		statusbit = IPS_DST_NAT;
-
-	/* Invert if this is reply dir. */
-	if (dir == IP_CT_DIR_REPLY)
-		statusbit ^= IPS_NAT_MASK;
-
-	/* Non-atomic: these bits don't change. */
-	if (ct->status & statusbit) {
-		struct ip_conntrack_tuple target;
-
-		/* We are aiming to look like inverse of other direction. */
-		invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
-
-		if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
-			return NF_DROP;
-	}
-	return NF_ACCEPT;
-}
-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 ip_conntrack *ct,
-				  enum ip_conntrack_info ctinfo,
-				  unsigned int hooknum,
-				  struct sk_buff **pskb)
-{
-	struct {
-		struct icmphdr icmp;
-		struct iphdr ip;
-	} *inside;
-	struct ip_conntrack_protocol *proto;
-	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;
-
-	inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
-
-	/* We're actually going to mangle it beyond trivial checksum
-	   adjustment, so make sure the current checksum is correct. */
-	if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
-		return 0;
-
-	/* Must be RELATED */
-	IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
-		     (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
-
-	/* Redirects on non-null nats must be dropped, else they'll
-	   start talking to each other without our translation, and be
-	   confused... --RR */
-	if (inside->icmp.type == ICMP_REDIRECT) {
-		/* If NAT isn't finished, assume it and drop. */
-		if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
-			return 0;
-
-		if (ct->status & IPS_NAT_MASK)
-			return 0;
-	}
-
-	DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
-	       *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
-
-	/* rcu_read_lock()ed by nf_hook_slow */
-	proto = __ip_conntrack_proto_find(inside->ip.protocol);
-	if (!ip_ct_get_tuple(&inside->ip, *pskb, (*pskb)->nh.iph->ihl*4 +
-			     sizeof(struct icmphdr) + inside->ip.ihl*4,
-			     &inner, proto))
-		return 0;
-
-	/* Change inner back to look like incoming packet.  We do the
-	   opposite manip on this hook to normal, because it might not
-	   pass all hooks (locally-generated ICMP).  Consider incoming
-	   packet: PREROUTING (DST manip), routing produces ICMP, goes
-	   through POSTROUTING (which must correct the DST manip). */
-	if (!manip_pkt(inside->ip.protocol, pskb,
-		       (*pskb)->nh.iph->ihl*4
-		       + sizeof(inside->icmp),
-		       &ct->tuplehash[!dir].tuple,
-		       !manip))
-		return 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). */
-	if (manip == IP_NAT_MANIP_SRC)
-		statusbit = IPS_SRC_NAT;
-	else
-		statusbit = IPS_DST_NAT;
-
-	/* Invert if this is reply dir. */
-	if (dir == IP_CT_DIR_REPLY)
-		statusbit ^= IPS_NAT_MASK;
-
-	if (ct->status & statusbit) {
-		invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
-		if (!manip_pkt(0, pskb, 0, &target, manip))
-			return 0;
-	}
-
-	return 1;
-}
-EXPORT_SYMBOL_GPL(ip_nat_icmp_reply_translation);
-
-/* Protocol registration. */
-int ip_nat_protocol_register(struct ip_nat_protocol *proto)
-{
-	int ret = 0;
-
-	write_lock_bh(&ip_nat_lock);
-	if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) {
-		ret = -EBUSY;
-		goto out;
-	}
-	rcu_assign_pointer(ip_nat_protos[proto->protonum], proto);
- out:
-	write_unlock_bh(&ip_nat_lock);
-	return ret;
-}
-EXPORT_SYMBOL(ip_nat_protocol_register);
-
-/* Noone stores the protocol anywhere; simply delete it. */
-void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
-{
-	write_lock_bh(&ip_nat_lock);
-	rcu_assign_pointer(ip_nat_protos[proto->protonum],
-			   &ip_nat_unknown_protocol);
-	write_unlock_bh(&ip_nat_lock);
-	synchronize_rcu();
-}
-EXPORT_SYMBOL(ip_nat_protocol_unregister);
-
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-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(__be16),
-		&range->min.tcp.port);
-	NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
-		&range->max.tcp.port);
-
-	return 0;
-
-nfattr_failure:
-	return -1;
-}
-
-int
-ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range)
-{
-	int ret = 0;
-
-	/* we have to return whether we actually parsed something or not */
-
-	if (tb[CTA_PROTONAT_PORT_MIN-1]) {
-		ret = 1;
-		range->min.tcp.port =
-			*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
-	}
-
-	if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
-		if (ret)
-			range->max.tcp.port = range->min.tcp.port;
-	} else {
-		ret = 1;
-		range->max.tcp.port =
-			*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range);
-EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr);
-#endif
-
-static int __init ip_nat_init(void)
-{
-	size_t i;
-
-	/* Leave them the same for the moment. */
-	ip_nat_htable_size = ip_conntrack_htable_size;
-
-	/* One vmalloc for both hash tables */
-	bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
-	if (!bysource)
-		return -ENOMEM;
-
-	/* Sew in builtin protocols. */
-	write_lock_bh(&ip_nat_lock);
-	for (i = 0; i < MAX_IP_NAT_PROTO; i++)
-		rcu_assign_pointer(ip_nat_protos[i], &ip_nat_unknown_protocol);
-	rcu_assign_pointer(ip_nat_protos[IPPROTO_TCP], &ip_nat_protocol_tcp);
-	rcu_assign_pointer(ip_nat_protos[IPPROTO_UDP], &ip_nat_protocol_udp);
-	rcu_assign_pointer(ip_nat_protos[IPPROTO_ICMP], &ip_nat_protocol_icmp);
-	write_unlock_bh(&ip_nat_lock);
-
-	for (i = 0; i < ip_nat_htable_size; i++) {
-		INIT_LIST_HEAD(&bysource[i]);
-	}
-
-	/* FIXME: Man, this is a hack.  <SIGH> */
-	IP_NF_ASSERT(rcu_dereference(ip_conntrack_destroyed) == NULL);
-	rcu_assign_pointer(ip_conntrack_destroyed, ip_nat_cleanup_conntrack);
-
-	/* Initialize fake conntrack so that NAT will skip it */
-	ip_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
-	return 0;
-}
-
-/* Clear NAT section of all conntracks, in case we're loaded again. */
-static int clean_nat(struct ip_conntrack *i, void *data)
-{
-	memset(&i->nat, 0, sizeof(i->nat));
-	i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
-	return 0;
-}
-
-static void __exit ip_nat_cleanup(void)
-{
-	ip_ct_iterate_cleanup(&clean_nat, NULL);
-	rcu_assign_pointer(ip_conntrack_destroyed, NULL);
-	synchronize_rcu();
-	vfree(bysource);
-}
-
-MODULE_LICENSE("GPL");
-
-module_init(ip_nat_init);
-module_exit(ip_nat_cleanup);
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
deleted file mode 100644
index 32e01d8..0000000
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* FTP extension for TCP NAT alteration. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/netfilter_ipv4.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/moduleparam.h>
-#include <net/tcp.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
-MODULE_DESCRIPTION("ftp NAT helper");
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/* FIXME: Time out? --RR */
-
-static int
-mangle_rfc959_packet(struct sk_buff **pskb,
-		     __be32 newip,
-		     u_int16_t port,
-		     unsigned int matchoff,
-		     unsigned int matchlen,
-		     struct ip_conntrack *ct,
-		     enum ip_conntrack_info ctinfo,
-		     u32 *seq)
-{
-	char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
-
-	sprintf(buffer, "%u,%u,%u,%u,%u,%u",
-		NIPQUAD(newip), port>>8, port&0xFF);
-
-	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
-
-	*seq += strlen(buffer) - matchlen;
-	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
-					matchlen, buffer, strlen(buffer));
-}
-
-/* |1|132.235.1.2|6275| */
-static int
-mangle_eprt_packet(struct sk_buff **pskb,
-		   __be32 newip,
-		   u_int16_t port,
-		   unsigned int matchoff,
-		   unsigned int matchlen,
-		   struct ip_conntrack *ct,
-		   enum ip_conntrack_info ctinfo,
-		   u32 *seq)
-{
-	char buffer[sizeof("|1|255.255.255.255|65535|")];
-
-	sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
-
-	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
-
-	*seq += strlen(buffer) - matchlen;
-	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
-					matchlen, buffer, strlen(buffer));
-}
-
-/* |1|132.235.1.2|6275| */
-static int
-mangle_epsv_packet(struct sk_buff **pskb,
-		   __be32 newip,
-		   u_int16_t port,
-		   unsigned int matchoff,
-		   unsigned int matchlen,
-		   struct ip_conntrack *ct,
-		   enum ip_conntrack_info ctinfo,
-		   u32 *seq)
-{
-	char buffer[sizeof("|||65535|")];
-
-	sprintf(buffer, "|||%u|", port);
-
-	DEBUGP("calling ip_nat_mangle_tcp_packet\n");
-
-	*seq += strlen(buffer) - matchlen;
-	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
-					matchlen, buffer, strlen(buffer));
-}
-
-static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
-		     unsigned int,
-		     unsigned int,
-		     struct ip_conntrack *,
-		     enum ip_conntrack_info,
-		     u32 *seq)
-= { [IP_CT_FTP_PORT] = mangle_rfc959_packet,
-    [IP_CT_FTP_PASV] = mangle_rfc959_packet,
-    [IP_CT_FTP_EPRT] = mangle_eprt_packet,
-    [IP_CT_FTP_EPSV] = mangle_epsv_packet
-};
-
-/* So, this packet has hit the connection tracking matching code.
-   Mangle it, and change the expectation to match the new version. */
-static unsigned int ip_nat_ftp(struct sk_buff **pskb,
-			       enum ip_conntrack_info ctinfo,
-			       enum ip_ct_ftp_type type,
-			       unsigned int matchoff,
-			       unsigned int matchlen,
-			       struct ip_conntrack_expect *exp,
-			       u32 *seq)
-{
-	__be32 newip;
-	u_int16_t port;
-	int dir = CTINFO2DIR(ctinfo);
-	struct ip_conntrack *ct = exp->master;
-
-	DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
-
-	/* Connection will come from wherever this packet goes, hence !dir */
-	newip = ct->tuplehash[!dir].tuple.dst.ip;
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->dir = !dir;
-
-	/* When you see the packet, we need to NAT it the same as the
-	 * this one. */
-	exp->expectfn = ip_nat_follow_master;
-
-	/* Try to get same port: if not, try to change it. */
-	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
-		exp->tuple.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (port == 0)
-		return NF_DROP;
-
-	if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
-			  seq)) {
-		ip_conntrack_unexpect_related(exp);
-		return NF_DROP;
-	}
-	return NF_ACCEPT;
-}
-
-static void __exit ip_nat_ftp_fini(void)
-{
-	rcu_assign_pointer(ip_nat_ftp_hook, NULL);
-	synchronize_rcu();
-}
-
-static int __init ip_nat_ftp_init(void)
-{
-	BUG_ON(rcu_dereference(ip_nat_ftp_hook));
-	rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp);
-	return 0;
-}
-
-/* Prior to 2.6.11, we had a ports param.  No longer, but don't break users. */
-static int warn_set(const char *val, struct kernel_param *kp)
-{
-	printk(KERN_INFO KBUILD_MODNAME
-	       ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
-	return 0;
-}
-module_param_call(ports, warn_set, NULL, NULL, 0);
-
-module_init(ip_nat_ftp_init);
-module_exit(ip_nat_ftp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
deleted file mode 100644
index dc778cf..0000000
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/* ip_nat_helper.c - generic support functions for NAT helpers
- *
- * (C) 2000-2002 Harald Welte <laforge@netfilter.org>
- * (C) 2003-2004 Netfilter Core Team <coreteam@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.
- *
- * 	14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
- *		- add support for SACK adjustment
- *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
- *		- merge SACK support into newnat API
- *	16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>:
- *		- make ip_nat_resize_packet more generic (TCP and UDP)
- *		- add ip_nat_mangle_udp_packet
- */
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/checksum.h>
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-
-#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>
-
-#if 0
-#define DEBUGP printk
-#define DUMP_OFFSET(x)	printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
-#else
-#define DEBUGP(format, args...)
-#define DUMP_OFFSET(x)
-#endif
-
-static DEFINE_SPINLOCK(ip_nat_seqofs_lock);
-
-/* Setup TCP sequence correction given this change at this sequence */
-static inline void
-adjust_tcp_sequence(u32 seq,
-		    int sizediff,
-		    struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo)
-{
-	int dir;
-	struct ip_nat_seq *this_way, *other_way;
-
-	DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
-		(*skb)->len, new_size);
-
-	dir = CTINFO2DIR(ctinfo);
-
-	this_way = &ct->nat.info.seq[dir];
-	other_way = &ct->nat.info.seq[!dir];
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
-	DUMP_OFFSET(this_way);
-
-	spin_lock_bh(&ip_nat_seqofs_lock);
-
-	/* SYN adjust. If it's uninitialized, or this is after last
-	 * correction, record it: we don't handle more than one
-	 * adjustment in the window, but do deal with common case of a
-	 * retransmit */
-	if (this_way->offset_before == this_way->offset_after
-	    || before(this_way->correction_pos, seq)) {
-		    this_way->correction_pos = seq;
-		    this_way->offset_before = this_way->offset_after;
-		    this_way->offset_after += sizediff;
-	}
-	spin_unlock_bh(&ip_nat_seqofs_lock);
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
-	DUMP_OFFSET(this_way);
-}
-
-/* Frobs data inside this packet, which is linear. */
-static void mangle_contents(struct sk_buff *skb,
-			    unsigned int dataoff,
-			    unsigned int match_offset,
-			    unsigned int match_len,
-			    const char *rep_buffer,
-			    unsigned int rep_len)
-{
-	unsigned char *data;
-
-	BUG_ON(skb_is_nonlinear(skb));
-	data = (unsigned char *)skb->nh.iph + dataoff;
-
-	/* move post-replacement */
-	memmove(data + match_offset + rep_len,
-		data + match_offset + match_len,
-		skb->tail - (data + match_offset + match_len));
-
-	/* insert data from buffer */
-	memcpy(data + match_offset, rep_buffer, rep_len);
-
-	/* update skb info */
-	if (rep_len > match_len) {
-		DEBUGP("ip_nat_mangle_packet: Extending packet by "
-			"%u from %u bytes\n", rep_len - match_len,
-		       skb->len);
-		skb_put(skb, rep_len - match_len);
-	} else {
-		DEBUGP("ip_nat_mangle_packet: Shrinking packet from "
-			"%u from %u bytes\n", match_len - rep_len,
-		       skb->len);
-		__skb_trim(skb, skb->len + rep_len - match_len);
-	}
-
-	/* fix IP hdr checksum information */
-	skb->nh.iph->tot_len = htons(skb->len);
-	ip_send_check(skb->nh.iph);
-}
-
-/* Unusual, but possible case. */
-static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
-{
-	struct sk_buff *nskb;
-
-	if ((*pskb)->len + extra > 65535)
-		return 0;
-
-	nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
-	if (!nskb)
-		return 0;
-
-	/* Transfer socket to new skb. */
-	if ((*pskb)->sk)
-		skb_set_owner_w(nskb, (*pskb)->sk);
-	kfree_skb(*pskb);
-	*pskb = nskb;
-	return 1;
-}
-
-/* Generic function for mangling variable-length address changes inside
- * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
- * command in FTP).
- *
- * Takes care about all the nasty sequence number changes, checksumming,
- * skb enlargement, ...
- *
- * */
-int
-ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
-			 struct ip_conntrack *ct,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned int match_offset,
-			 unsigned int match_len,
-			 const char *rep_buffer,
-			 unsigned int rep_len)
-{
-	struct iphdr *iph;
-	struct tcphdr *tcph;
-	int oldlen, datalen;
-
-	if (!skb_make_writable(pskb, (*pskb)->len))
-		return 0;
-
-	if (rep_len > match_len
-	    && rep_len - match_len > skb_tailroom(*pskb)
-	    && !enlarge_skb(pskb, rep_len - match_len))
-		return 0;
-
-	SKB_LINEAR_ASSERT(*pskb);
-
-	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;
-	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
-		tcph->check = 0;
-		tcph->check = tcp_v4_check(datalen,
-					   iph->saddr, iph->daddr,
-					   csum_partial((char *)tcph,
-							datalen, 0));
-	} else
-		nf_proto_csum_replace2(&tcph->check, *pskb,
-					htons(oldlen), htons(datalen), 1);
-
-	if (rep_len != match_len) {
-		set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
-		adjust_tcp_sequence(ntohl(tcph->seq),
-				    (int)rep_len - (int)match_len,
-				    ct, ctinfo);
-		/* Tell TCP window tracking about seq change */
-		ip_conntrack_tcp_update(*pskb, ct, CTINFO2DIR(ctinfo));
-	}
-	return 1;
-}
-EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
-
-/* Generic function for mangling variable-length address changes inside
- * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
- * command in the Amanda protocol)
- *
- * Takes care about all the nasty sequence number changes, checksumming,
- * skb enlargement, ...
- *
- * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
- *       should be fairly easy to do.
- */
-int
-ip_nat_mangle_udp_packet(struct sk_buff **pskb,
-			 struct ip_conntrack *ct,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned int match_offset,
-			 unsigned int match_len,
-			 const char *rep_buffer,
-			 unsigned int rep_len)
-{
-	struct iphdr *iph;
-	struct udphdr *udph;
-	int datalen, oldlen;
-
-	/* UDP helpers might accidentally mangle the wrong packet */
-	iph = (*pskb)->nh.iph;
-	if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
-			       match_offset + match_len)
-		return 0;
-
-	if (!skb_make_writable(pskb, (*pskb)->len))
-		return 0;
-
-	if (rep_len > match_len
-	    && rep_len - match_len > skb_tailroom(*pskb)
-	    && !enlarge_skb(pskb, rep_len - match_len))
-		return 0;
-
-	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 */
-	datalen = (*pskb)->len - iph->ihl*4;
-	udph->len = htons(datalen);
-
-	/* fix udp checksum if udp checksum was previously calculated */
-	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 = CSUM_MANGLED_0;
-	} else
-		nf_proto_csum_replace2(&udph->check, *pskb,
-					htons(oldlen), htons(datalen), 1);
-	return 1;
-}
-EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
-
-/* Adjust one found SACK option including checksum correction */
-static void
-sack_adjust(struct sk_buff *skb,
-	    struct tcphdr *tcph,
-	    unsigned int sackoff,
-	    unsigned int sackend,
-	    struct ip_nat_seq *natseq)
-{
-	while (sackoff < sackend) {
-		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 = htonl(ntohl(sack->start_seq)
-					- natseq->offset_after);
-		else
-			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 = htonl(ntohl(sack->end_seq)
-				      - natseq->offset_after);
-		else
-			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);
-
-		nf_proto_csum_replace4(&tcph->check, skb,
-					sack->start_seq, new_start_seq, 0);
-		nf_proto_csum_replace4(&tcph->check, skb,
-					sack->end_seq, new_end_seq, 0);
-		sack->start_seq = new_start_seq;
-		sack->end_seq = new_end_seq;
-		sackoff += sizeof(*sack);
-	}
-}
-
-/* TCP SACK sequence number adjustment */
-static inline unsigned int
-ip_nat_sack_adjust(struct sk_buff **pskb,
-		   struct tcphdr *tcph,
-		   struct ip_conntrack *ct,
-		   enum ip_conntrack_info ctinfo)
-{
-	unsigned int dir, optoff, optend;
-
-	optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
-	optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
-
-	if (!skb_make_writable(pskb, optend))
-		return 0;
-
-	dir = CTINFO2DIR(ctinfo);
-
-	while (optoff < optend) {
-		/* Usually: option, length. */
-		unsigned char *op = (*pskb)->data + optoff;
-
-		switch (op[0]) {
-		case TCPOPT_EOL:
-			return 1;
-		case TCPOPT_NOP:
-			optoff++;
-			continue;
-		default:
-			/* no partial options */
-			if (optoff + 1 == optend
-			    || optoff + op[1] > optend
-			    || op[1] < 2)
-				return 0;
-			if (op[0] == TCPOPT_SACK
-			    && op[1] >= 2+TCPOLEN_SACK_PERBLOCK
-			    && ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
-				sack_adjust(*pskb, tcph, optoff+2,
-					    optoff+op[1],
-					    &ct->nat.info.seq[!dir]);
-			optoff += op[1];
-		}
-	}
-	return 1;
-}
-
-/* TCP sequence number adjustment.  Returns 1 on success, 0 on failure */
-int
-ip_nat_seq_adjust(struct sk_buff **pskb,
-		  struct ip_conntrack *ct,
-		  enum ip_conntrack_info ctinfo)
-{
-	struct tcphdr *tcph;
-	int dir;
-	__be32 newseq, newack;
-	struct ip_nat_seq *this_way, *other_way;
-
-	dir = CTINFO2DIR(ctinfo);
-
-	this_way = &ct->nat.info.seq[dir];
-	other_way = &ct->nat.info.seq[!dir];
-
-	if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
-		return 0;
-
-	tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
-	if (after(ntohl(tcph->seq), this_way->correction_pos))
-		newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
-	else
-		newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
-
-	if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
-		  other_way->correction_pos))
-		newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
-	else
-		newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
-
-	nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
-	nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
-
-	DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
-		ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
-		ntohl(newack));
-
-	tcph->seq = newseq;
-	tcph->ack_seq = newack;
-
-	if (!ip_nat_sack_adjust(pskb, tcph, ct, ctinfo))
-		return 0;
-
-	ip_conntrack_tcp_update(*pskb, ct, dir);
-
-	return 1;
-}
-EXPORT_SYMBOL(ip_nat_seq_adjust);
-
-/* Setup NAT on this expected conntrack so it follows master. */
-/* If we fail to get a free NAT slot, we'll get dropped on confirm */
-void ip_nat_follow_master(struct ip_conntrack *ct,
-			  struct ip_conntrack_expect *exp)
-{
-	struct ip_nat_range range;
-
-	/* This must be a fresh one. */
-	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
-
-	/* Change src to where master sends to */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
-	/* hook doesn't matter, but it has to do source manip */
-	ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
-
-	/* For DST manip, map port here to where it's expected. */
-	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = exp->saved_proto;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.src.ip;
-	/* hook doesn't matter, but it has to do destination manip */
-	ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
-}
-EXPORT_SYMBOL(ip_nat_follow_master);
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
deleted file mode 100644
index bdc99ef..0000000
--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * H.323 extension for NAT alteration.
- *
- * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
- *
- * This source code is licensed under General Public License version 2.
- *
- * Based on the 'brute force' H.323 NAT module by
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- */
-
-#include <linux/module.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/moduleparam.h>
-#include <net/tcp.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-/****************************************************************************/
-static int set_addr(struct sk_buff **pskb,
-		    unsigned char **data, int dataoff,
-		    unsigned int addroff, __be32 ip, u_int16_t port)
-{
-	enum ip_conntrack_info ctinfo;
-	struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
-	struct {
-		__be32 ip;
-		__be16 port;
-	} __attribute__ ((__packed__)) buf;
-	struct tcphdr _tcph, *th;
-
-	buf.ip = ip;
-	buf.port = htons(port);
-	addroff += dataoff;
-
-	if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
-		if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
-					      addroff, sizeof(buf),
-					      (char *) &buf, sizeof(buf))) {
-			if (net_ratelimit())
-				printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
-				       " error\n");
-			return -1;
-		}
-
-		/* Relocate data pointer */
-		th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
-					sizeof(_tcph), &_tcph);
-		if (th == NULL)
-			return -1;
-		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
-		    th->doff * 4 + dataoff;
-	} else {
-		if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
-					      addroff, sizeof(buf),
-					      (char *) &buf, sizeof(buf))) {
-			if (net_ratelimit())
-				printk("ip_nat_h323: ip_nat_mangle_udp_packet"
-				       " error\n");
-			return -1;
-		}
-		/* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
-		 * or pull everything in a linear buffer, so we can safely
-		 * use the skb pointers now */
-		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
-		    sizeof(struct udphdr);
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int set_h225_addr(struct sk_buff **pskb,
-			 unsigned char **data, int dataoff,
-			 TransportAddress * addr,
-			 __be32 ip, u_int16_t port)
-{
-	return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
-}
-
-/****************************************************************************/
-static int set_h245_addr(struct sk_buff **pskb,
-			 unsigned char **data, int dataoff,
-			 H245_TransportAddress * addr,
-			 __be32 ip, u_int16_t port)
-{
-	return set_addr(pskb, data, dataoff,
-			addr->unicastAddress.iPAddress.network, ip, port);
-}
-
-/****************************************************************************/
-static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data,
-			TransportAddress * addr, int count)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	int i;
-	__be32 ip;
-	u_int16_t port;
-
-	for (i = 0; i < count; i++) {
-		if (get_h225_addr(*data, &addr[i], &ip, &port)) {
-			if (ip == ct->tuplehash[dir].tuple.src.ip &&
-			    port == info->sig_port[dir]) {
-				/* GW->GK */
-
-				/* Fix for Gnomemeeting */
-				if (i > 0 &&
-				    get_h225_addr(*data, &addr[0],
-						  &ip, &port) &&
-				    (ntohl(ip) & 0xff000000) == 0x7f000000)
-					i = 0;
-
-				DEBUGP
-				    ("ip_nat_ras: set signal address "
-				     "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-				     NIPQUAD(ip), port,
-				     NIPQUAD(ct->tuplehash[!dir].tuple.dst.
-					     ip), info->sig_port[!dir]);
-				return set_h225_addr(pskb, data, 0, &addr[i],
-						     ct->tuplehash[!dir].
-						     tuple.dst.ip,
-						     info->sig_port[!dir]);
-			} else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
-				   port == info->sig_port[dir]) {
-				/* GK->GW */
-				DEBUGP
-				    ("ip_nat_ras: set signal address "
-				     "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-				     NIPQUAD(ip), port,
-				     NIPQUAD(ct->tuplehash[!dir].tuple.src.
-					     ip), info->sig_port[!dir]);
-				return set_h225_addr(pskb, data, 0, &addr[i],
-						     ct->tuplehash[!dir].
-						     tuple.src.ip,
-						     info->sig_port[!dir]);
-			}
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data,
-			TransportAddress * addr, int count)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	int i;
-	__be32 ip;
-	u_int16_t port;
-
-	for (i = 0; i < count; i++) {
-		if (get_h225_addr(*data, &addr[i], &ip, &port) &&
-		    ip == ct->tuplehash[dir].tuple.src.ip &&
-		    port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
-			DEBUGP("ip_nat_ras: set rasAddress "
-			       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-			       NIPQUAD(ip), port,
-			       NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
-			       ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
-				     port));
-			return set_h225_addr(pskb, data, 0, &addr[i],
-					     ct->tuplehash[!dir].tuple.dst.ip,
-					     ntohs(ct->tuplehash[!dir].tuple.
-						   dst.u.udp.port));
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************/
-static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo,
-			unsigned char **data, int dataoff,
-			H245_TransportAddress * addr,
-			u_int16_t port, u_int16_t rtp_port,
-			struct ip_conntrack_expect *rtp_exp,
-			struct ip_conntrack_expect *rtcp_exp)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	int i;
-	u_int16_t nated_port;
-
-	/* Set expectations for NAT */
-	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
-	rtp_exp->expectfn = ip_nat_follow_master;
-	rtp_exp->dir = !dir;
-	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
-	rtcp_exp->expectfn = ip_nat_follow_master;
-	rtcp_exp->dir = !dir;
-
-	/* Lookup existing expects */
-	for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
-		if (info->rtp_port[i][dir] == rtp_port) {
-			/* Expected */
-
-			/* Use allocated ports first. This will refresh
-			 * the expects */
-			rtp_exp->tuple.dst.u.udp.port =
-			    htons(info->rtp_port[i][dir]);
-			rtcp_exp->tuple.dst.u.udp.port =
-			    htons(info->rtp_port[i][dir] + 1);
-			break;
-		} else if (info->rtp_port[i][dir] == 0) {
-			/* Not expected */
-			break;
-		}
-	}
-
-	/* Run out of expectations */
-	if (i >= H323_RTP_CHANNEL_MAX) {
-		if (net_ratelimit())
-			printk("ip_nat_h323: out of expectations\n");
-		return 0;
-	}
-
-	/* Try to get a pair of ports. */
-	for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
-	     nated_port != 0; nated_port += 2) {
-		rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
-		if (ip_conntrack_expect_related(rtp_exp) == 0) {
-			rtcp_exp->tuple.dst.u.udp.port =
-			    htons(nated_port + 1);
-			if (ip_conntrack_expect_related(rtcp_exp) == 0)
-				break;
-			ip_conntrack_unexpect_related(rtp_exp);
-		}
-	}
-
-	if (nated_port == 0) {	/* No port available */
-		if (net_ratelimit())
-			printk("ip_nat_h323: out of RTP ports\n");
-		return 0;
-	}
-
-	/* Modify signal */
-	if (set_h245_addr(pskb, data, dataoff, addr,
-			  ct->tuplehash[!dir].tuple.dst.ip,
-			  (port & 1) ? nated_port + 1 : nated_port) == 0) {
-		/* Save ports */
-		info->rtp_port[i][dir] = rtp_port;
-		info->rtp_port[i][!dir] = nated_port;
-	} else {
-		ip_conntrack_unexpect_related(rtp_exp);
-		ip_conntrack_unexpect_related(rtcp_exp);
-		return -1;
-	}
-
-	/* Success */
-	DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(rtp_exp->tuple.src.ip),
-	       ntohs(rtp_exp->tuple.src.u.udp.port),
-	       NIPQUAD(rtp_exp->tuple.dst.ip),
-	       ntohs(rtp_exp->tuple.dst.u.udp.port));
-	DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(rtcp_exp->tuple.src.ip),
-	       ntohs(rtcp_exp->tuple.src.u.udp.port),
-	       NIPQUAD(rtcp_exp->tuple.dst.ip),
-	       ntohs(rtcp_exp->tuple.dst.u.udp.port));
-
-	return 0;
-}
-
-/****************************************************************************/
-static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo,
-		    unsigned char **data, int dataoff,
-		    H245_TransportAddress * addr, u_int16_t port,
-		    struct ip_conntrack_expect *exp)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	u_int16_t nated_port = port;
-
-	/* Set expectations for NAT */
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->expectfn = ip_nat_follow_master;
-	exp->dir = !dir;
-
-	/* Try to get same port: if not, try to change it. */
-	for (; nated_port != 0; nated_port++) {
-		exp->tuple.dst.u.tcp.port = htons(nated_port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (nated_port == 0) {	/* No port available */
-		if (net_ratelimit())
-			printk("ip_nat_h323: out of TCP ports\n");
-		return 0;
-	}
-
-	/* Modify signal */
-	if (set_h245_addr(pskb, data, dataoff, addr,
-			  ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
-		ip_conntrack_unexpect_related(exp);
-		return -1;
-	}
-
-	DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
-	       NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
-
-	return 0;
-}
-
-/****************************************************************************
- * This conntrack expect function replaces ip_conntrack_h245_expect()
- * which was set by ip_conntrack_helper_h323.c. It calls both
- * ip_nat_follow_master() and ip_conntrack_h245_expect()
- ****************************************************************************/
-static void ip_nat_h245_expect(struct ip_conntrack *new,
-			       struct ip_conntrack_expect *this)
-{
-	ip_nat_follow_master(new, this);
-	ip_conntrack_h245_expect(new, this);
-}
-
-/****************************************************************************/
-static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo,
-		    unsigned char **data, int dataoff,
-		    TransportAddress * addr, u_int16_t port,
-		    struct ip_conntrack_expect *exp)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	u_int16_t nated_port = port;
-
-	/* Set expectations for NAT */
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->expectfn = ip_nat_h245_expect;
-	exp->dir = !dir;
-
-	/* Check existing expects */
-	if (info->sig_port[dir] == port)
-		nated_port = info->sig_port[!dir];
-
-	/* Try to get same port: if not, try to change it. */
-	for (; nated_port != 0; nated_port++) {
-		exp->tuple.dst.u.tcp.port = htons(nated_port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (nated_port == 0) {	/* No port available */
-		if (net_ratelimit())
-			printk("ip_nat_q931: out of TCP ports\n");
-		return 0;
-	}
-
-	/* Modify signal */
-	if (set_h225_addr(pskb, data, dataoff, addr,
-			  ct->tuplehash[!dir].tuple.dst.ip,
-			  nated_port) == 0) {
-		/* Save ports */
-		info->sig_port[dir] = port;
-		info->sig_port[!dir] = nated_port;
-	} else {
-		ip_conntrack_unexpect_related(exp);
-		return -1;
-	}
-
-	DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
-	       NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
-
-	return 0;
-}
-
-/****************************************************************************
- * This conntrack expect function replaces ip_conntrack_q931_expect()
- * which was set by ip_conntrack_helper_h323.c.
- ****************************************************************************/
-static void ip_nat_q931_expect(struct ip_conntrack *new,
-			       struct ip_conntrack_expect *this)
-{
-	struct ip_nat_range range;
-
-	if (this->tuple.src.ip != 0) {	/* Only accept calls from GK */
-		ip_nat_follow_master(new, this);
-		goto out;
-	}
-
-	/* This must be a fresh one. */
-	BUG_ON(new->status & IPS_NAT_DONE_MASK);
-
-	/* Change src to where master sends to */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
-
-	/* hook doesn't matter, but it has to do source manip */
-	ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
-
-	/* For DST manip, map port here to where it's expected. */
-	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = this->saved_proto;
-	range.min_ip = range.max_ip =
-	    new->master->tuplehash[!this->dir].tuple.src.ip;
-
-	/* hook doesn't matter, but it has to do destination manip */
-	ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
-
-      out:
-	ip_conntrack_q931_expect(new, this);
-}
-
-/****************************************************************************/
-static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
-		    enum ip_conntrack_info ctinfo,
-		    unsigned char **data, TransportAddress * addr, int idx,
-		    u_int16_t port, struct ip_conntrack_expect *exp)
-{
-	struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
-	int dir = CTINFO2DIR(ctinfo);
-	u_int16_t nated_port = port;
-	__be32 ip;
-
-	/* Set expectations for NAT */
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->expectfn = ip_nat_q931_expect;
-	exp->dir = !dir;
-
-	/* Check existing expects */
-	if (info->sig_port[dir] == port)
-		nated_port = info->sig_port[!dir];
-
-	/* Try to get same port: if not, try to change it. */
-	for (; nated_port != 0; nated_port++) {
-		exp->tuple.dst.u.tcp.port = htons(nated_port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (nated_port == 0) {	/* No port available */
-		if (net_ratelimit())
-			printk("ip_nat_ras: out of TCP ports\n");
-		return 0;
-	}
-
-	/* Modify signal */
-	if (set_h225_addr(pskb, data, 0, &addr[idx],
-			  ct->tuplehash[!dir].tuple.dst.ip,
-			  nated_port) == 0) {
-		/* Save ports */
-		info->sig_port[dir] = port;
-		info->sig_port[!dir] = nated_port;
-
-		/* Fix for Gnomemeeting */
-		if (idx > 0 &&
-		    get_h225_addr(*data, &addr[0], &ip, &port) &&
-		    (ntohl(ip) & 0xff000000) == 0x7f000000) {
-			set_h225_addr_hook(pskb, data, 0, &addr[0],
-					   ct->tuplehash[!dir].tuple.dst.ip,
-					   info->sig_port[!dir]);
-		}
-	} else {
-		ip_conntrack_unexpect_related(exp);
-		return -1;
-	}
-
-	/* Success */
-	DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
-	       NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
-
-	return 0;
-}
-
-/****************************************************************************/
-static void ip_nat_callforwarding_expect(struct ip_conntrack *new,
-					 struct ip_conntrack_expect *this)
-{
-	struct ip_nat_range range;
-
-	/* This must be a fresh one. */
-	BUG_ON(new->status & IPS_NAT_DONE_MASK);
-
-	/* Change src to where master sends to */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
-
-	/* hook doesn't matter, but it has to do source manip */
-	ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
-
-	/* For DST manip, map port here to where it's expected. */
-	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = this->saved_proto;
-	range.min_ip = range.max_ip = this->saved_ip;
-
-	/* hook doesn't matter, but it has to do destination manip */
-	ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
-
-	ip_conntrack_q931_expect(new, this);
-}
-
-/****************************************************************************/
-static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct,
-			      enum ip_conntrack_info ctinfo,
-			      unsigned char **data, int dataoff,
-			      TransportAddress * addr, u_int16_t port,
-			      struct ip_conntrack_expect *exp)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	u_int16_t nated_port;
-
-	/* Set expectations for NAT */
-	exp->saved_ip = exp->tuple.dst.ip;
-	exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->expectfn = ip_nat_callforwarding_expect;
-	exp->dir = !dir;
-
-	/* Try to get same port: if not, try to change it. */
-	for (nated_port = port; nated_port != 0; nated_port++) {
-		exp->tuple.dst.u.tcp.port = htons(nated_port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (nated_port == 0) {	/* No port available */
-		if (net_ratelimit())
-			printk("ip_nat_q931: out of TCP ports\n");
-		return 0;
-	}
-
-	/* Modify signal */
-	if (!set_h225_addr(pskb, data, dataoff, addr,
-			   ct->tuplehash[!dir].tuple.dst.ip,
-			   nated_port) == 0) {
-		ip_conntrack_unexpect_related(exp);
-		return -1;
-	}
-
-	/* Success */
-	DEBUGP("ip_nat_q931: expect Call Forwarding "
-	       "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
-	       NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
-	       NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
-
-	return 0;
-}
-
-/****************************************************************************/
-static int __init init(void)
-{
-	BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL);
-	BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL);
-	BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL);
-	BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL);
-	BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL);
-	BUG_ON(rcu_dereference(nat_t120_hook) != NULL);
-	BUG_ON(rcu_dereference(nat_h245_hook) != NULL);
-	BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL);
-	BUG_ON(rcu_dereference(nat_q931_hook) != NULL);
-
-	rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
-	rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
-	rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
-	rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
-	rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
-	rcu_assign_pointer(nat_t120_hook, nat_t120);
-	rcu_assign_pointer(nat_h245_hook, nat_h245);
-	rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
-	rcu_assign_pointer(nat_q931_hook, nat_q931);
-
-	DEBUGP("ip_nat_h323: init success\n");
-	return 0;
-}
-
-/****************************************************************************/
-static void __exit fini(void)
-{
-	rcu_assign_pointer(set_h245_addr_hook, NULL);
-	rcu_assign_pointer(set_h225_addr_hook, NULL);
-	rcu_assign_pointer(set_sig_addr_hook, NULL);
-	rcu_assign_pointer(set_ras_addr_hook, NULL);
-	rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
-	rcu_assign_pointer(nat_t120_hook, NULL);
-	rcu_assign_pointer(nat_h245_hook, NULL);
-	rcu_assign_pointer(nat_callforwarding_hook, NULL);
-	rcu_assign_pointer(nat_q931_hook, NULL);
-	synchronize_rcu();
-}
-
-/****************************************************************************/
-module_init(init);
-module_exit(fini);
-
-MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
-MODULE_DESCRIPTION("H.323 NAT helper");
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
deleted file mode 100644
index 24ce4a5..0000000
--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * ip_nat_pptp.c	- Version 3.0
- *
- * NAT support for PPTP (Point to Point Tunneling Protocol).
- * PPTP is a a protocol for creating virtual private networks.
- * It is a specification defined by Microsoft and some vendors
- * working with Microsoft.  PPTP is built on top of a modified
- * version of the Internet Generic Routing Encapsulation Protocol.
- * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
- * PPTP can be found in RFC 2637
- *
- * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- *
- * TODO: - NAT to a unique tuple, not to TCP source port
- * 	   (needs netfilter tuple reservation)
- *
- * Changes:
- *     2002-02-10 - Version 1.3
- *       - Use ip_nat_mangle_tcp_packet() because of cloned skb's
- *	   in local connections (Philip Craig <philipc@snapgear.com>)
- *       - add checks for magicCookie and pptp version
- *       - make argument list of pptp_{out,in}bound_packet() shorter
- *       - move to C99 style initializers
- *       - print version number at module loadtime
- *     2003-09-22 - Version 1.5
- *       - use SNATed tcp sourceport as callid, since we get called before
- *	   TCP header is mangled (Philip Craig <philipc@snapgear.com>)
- *     2004-10-22 - Version 2.0
- *       - kernel 2.6.x version
- *     2005-06-10 - Version 3.0
- *       - kernel >= 2.6.11 version,
- *	   funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
- *
- */
-
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_pptp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
-
-#define IP_NAT_PPTP_VERSION "3.0"
-
-#define REQ_CID(req, off)		(*(__be16 *)((char *)(req) + (off)))
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
-
-
-#if 0
-extern const char *pptp_msg_name[];
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
-				       __FUNCTION__, ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static void pptp_nat_expected(struct ip_conntrack *ct,
-			      struct ip_conntrack_expect *exp)
-{
-	struct ip_conntrack *master = ct->master;
-	struct ip_conntrack_expect *other_exp;
-	struct ip_conntrack_tuple t;
-	struct ip_ct_pptp_master *ct_pptp_info;
-	struct ip_nat_pptp *nat_pptp_info;
-	struct ip_nat_range range;
-
-	ct_pptp_info = &master->help.ct_pptp_info;
-	nat_pptp_info = &master->nat.help.nat_pptp_info;
-
-	/* And here goes the grand finale of corrosion... */
-
-	if (exp->dir == IP_CT_DIR_ORIGINAL) {
-		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 = 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 = 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 = 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 = master->nat.help.nat_pptp_info.pac_call_id;
-		t.dst.protonum = IPPROTO_GRE;
-	}
-
-	DEBUGP("trying to unexpect other dir: ");
-	DUMP_TUPLE(&t);
-	other_exp = ip_conntrack_expect_find_get(&t);
-	if (other_exp) {
-		ip_conntrack_unexpect_related(other_exp);
-		ip_conntrack_expect_put(other_exp);
-		DEBUGP("success\n");
-	} else {
-		DEBUGP("not found!\n");
-	}
-
-	/* This must be a fresh one. */
-	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
-
-	/* Change src to where master sends to */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
-	if (exp->dir == IP_CT_DIR_ORIGINAL) {
-		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-		range.min = range.max = exp->saved_proto;
-	}
-	/* hook doesn't matter, but it has to do source manip */
-	ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
-
-	/* For DST manip, map port here to where it's expected. */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.src.ip;
-	if (exp->dir == IP_CT_DIR_REPLY) {
-		range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-		range.min = range.max = exp->saved_proto;
-	}
-	/* hook doesn't matter, but it has to do destination manip */
-	ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
-}
-
-/* outbound packets == from PNS to PAC */
-static int
-pptp_outbound_pkt(struct sk_buff **pskb,
-		  struct ip_conntrack *ct,
-		  enum ip_conntrack_info ctinfo,
-		  struct PptpControlHeader *ctlh,
-		  union pptp_ctrl_union *pptpReq)
-
-{
-	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;
-	__be16 new_callid;
-	unsigned int cid_off;
-
-	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 = 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
-	 * down to here */
-	DEBUGP("altering call id from 0x%04x to 0x%04x\n",
-		ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
-
-	/* mangle packet */
-	if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
-				     cid_off + sizeof(struct pptp_pkt_hdr) +
-				     sizeof(struct PptpControlHeader),
-				     sizeof(new_callid), (char *)&new_callid,
-				     sizeof(new_callid)) == 0)
-		return NF_DROP;
-
-	return NF_ACCEPT;
-}
-
-static void
-pptp_exp_gre(struct ip_conntrack_expect *expect_orig,
-	     struct ip_conntrack_expect *expect_reply)
-{
-	struct ip_conntrack *ct = expect_orig->master;
-	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 for PNS->PAC direction */
-	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;
-
-	/* alter expectation for PAC->PNS direction */
-	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;
-}
-
-/* inbound packets == from PAC to PNS */
-static int
-pptp_inbound_pkt(struct sk_buff **pskb,
-		 struct ip_conntrack *ct,
-		 enum ip_conntrack_info ctinfo,
-		 struct PptpControlHeader *ctlh,
-		 union pptp_ctrl_union *pptpReq)
-{
-	struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
-	u_int16_t msg;
-	__be16 new_pcid;
-	unsigned int pcid_off;
-
-	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);
-		break;
-	case PPTP_IN_CALL_CONNECT:
-		pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID);
-		break;
-	case PPTP_IN_CALL_REQUEST:
-		/* only need to nat in case PAC is behind NAT box */
-		return NF_ACCEPT;
-	case PPTP_WAN_ERROR_NOTIFY:
-		pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID);
-		break;
-	case PPTP_CALL_DISCONNECT_NOTIFY:
-		pcid_off = offsetof(union pptp_ctrl_union, disc.callID);
-		break;
-	case PPTP_SET_LINK_INFO:
-		pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID);
-		break;
-
-	default:
-		DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)?
-			pptp_msg_name[msg]:pptp_msg_name[0]);
-		/* fall through */
-
-	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_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST,
-	 * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */
-
-	/* mangle packet */
-	DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
-		ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
-
-	if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
-				     pcid_off + sizeof(struct pptp_pkt_hdr) +
-				     sizeof(struct PptpControlHeader),
-				     sizeof(new_pcid), (char *)&new_pcid,
-				     sizeof(new_pcid)) == 0)
-		return NF_DROP;
-	return NF_ACCEPT;
-}
-
-
-extern int __init ip_nat_proto_gre_init(void);
-extern void __exit ip_nat_proto_gre_fini(void);
-
-static int __init ip_nat_helper_pptp_init(void)
-{
-	int ret;
-
-	DEBUGP("%s: registering NAT helper\n", __FILE__);
-
-	ret = ip_nat_proto_gre_init();
-	if (ret < 0)
-		return ret;
-
-	BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound));
-	rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt);
-
-	BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound));
-	rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt);
-
-	BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre));
-	rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre);
-
-	BUG_ON(rcu_dereference(ip_nat_pptp_hook_expectfn));
-	rcu_assign_pointer(ip_nat_pptp_hook_expectfn, pptp_nat_expected);
-
-	printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
-	return 0;
-}
-
-static void __exit ip_nat_helper_pptp_fini(void)
-{
-	DEBUGP("cleanup_module\n" );
-
-	rcu_assign_pointer(ip_nat_pptp_hook_expectfn, NULL);
-	rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, NULL);
-	rcu_assign_pointer(ip_nat_pptp_hook_inbound, NULL);
-	rcu_assign_pointer(ip_nat_pptp_hook_outbound, NULL);
-	synchronize_rcu();
-
-	ip_nat_proto_gre_fini();
-
-	printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
-}
-
-module_init(ip_nat_helper_pptp_init);
-module_exit(ip_nat_helper_pptp_fini);
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c
deleted file mode 100644
index cfaeea3..0000000
--- a/net/ipv4/netfilter/ip_nat_irc.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* IRC extension for TCP NAT alteration.
- * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
- * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
- * based on a copy of RR's ip_nat_ftp.c
- *
- * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/kernel.h>
-#include <net/tcp.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/moduleparam.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("IRC (DCC) NAT helper");
-MODULE_LICENSE("GPL");
-
-static unsigned int help(struct sk_buff **pskb,
-			 enum ip_conntrack_info ctinfo,
-			 unsigned int matchoff,
-			 unsigned int matchlen,
-			 struct ip_conntrack_expect *exp)
-{
-	u_int16_t port;
-	unsigned int ret;
-
-	/* "4294967296 65635 " */
-	char buffer[18];
-
-	DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
-	       expect->seq, exp_irc_info->len,
-	       ntohl(tcph->seq));
-
-	/* Reply comes from server. */
-	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
-	exp->dir = IP_CT_DIR_REPLY;
-
-	/* When you see the packet, we need to NAT it the same as the
-	 * this one. */
-	exp->expectfn = ip_nat_follow_master;
-
-	/* Try to get same port: if not, try to change it. */
-	for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
-		exp->tuple.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (port == 0)
-		return NF_DROP;
-
-	/*      strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
-	 *      strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
-	 *      strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
-	 *      strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
-	 *      strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
-	 *              AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
-	 *                      255.255.255.255==4294967296, 10 digits)
-	 *              P:         bound port (min 1 d, max 5d (65635))
-	 *              F:         filename   (min 1 d )
-	 *              S:         size       (min 1 d )
-	 *              0x01, \n:  terminators
-	 */
-
-	/* AAA = "us", ie. where server normally talks to. */
-	sprintf(buffer, "%u %u",
-		ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip),
-		port);
-	DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n",
-	       buffer, NIPQUAD(exp->tuple.src.ip), port);
-
-	ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
-				       matchoff, matchlen, buffer,
-				       strlen(buffer));
-	if (ret != NF_ACCEPT)
-		ip_conntrack_unexpect_related(exp);
-	return ret;
-}
-
-static void __exit ip_nat_irc_fini(void)
-{
-	rcu_assign_pointer(ip_nat_irc_hook, NULL);
-	synchronize_rcu();
-}
-
-static int __init ip_nat_irc_init(void)
-{
-	BUG_ON(rcu_dereference(ip_nat_irc_hook));
-	rcu_assign_pointer(ip_nat_irc_hook, help);
-	return 0;
-}
-
-/* Prior to 2.6.11, we had a ports param.  No longer, but don't break users. */
-static int warn_set(const char *val, struct kernel_param *kp)
-{
-	printk(KERN_INFO KBUILD_MODNAME
-	       ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
-	return 0;
-}
-module_param_call(ports, warn_set, NULL, NULL, 0);
-
-module_init(ip_nat_irc_init);
-module_exit(ip_nat_irc_fini);
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c
deleted file mode 100644
index 9581020..0000000
--- a/net/ipv4/netfilter/ip_nat_proto_gre.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * ip_nat_proto_gre.c - Version 2.0
- *
- * NAT 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
- * connections between the same two hosts.
- *
- * 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
- * field in plain GRE.
- *
- * Documentation about PPTP can be found in RFC 2637
- *
- * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- *
- */
-
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
-MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
-
-#if 0
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
-				       __FUNCTION__, ## args)
-#else
-#define DEBUGP(x, args...)
-#endif
-
-/* is key in given range between min and max */
-static int
-gre_in_range(const struct ip_conntrack_tuple *tuple,
-	     enum ip_nat_manip_type maniptype,
-	     const union ip_conntrack_manip_proto *min,
-	     const union ip_conntrack_manip_proto *max)
-{
-	__be16 key;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		key = tuple->src.u.gre.key;
-	else
-		key = tuple->dst.u.gre.key;
-
-	return ntohs(key) >= ntohs(min->gre.key)
-		&& ntohs(key) <= ntohs(max->gre.key);
-}
-
-/* generate unique tuple ... */
-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;
-	__be16 *keyptr;
-	unsigned int min, i, range_size;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		keyptr = &tuple->src.u.gre.key;
-	else
-		keyptr = &tuple->dst.u.gre.key;
-
-	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
-		DEBUGP("%p: NATing GRE PPTP\n", conntrack);
-		min = 1;
-		range_size = 0xffff;
-	} else {
-		min = ntohs(range->min.gre.key);
-		range_size = ntohs(range->max.gre.key) - min + 1;
-	}
-
-	DEBUGP("min = %u, range_size = %u\n", min, range_size);
-
-	for (i = 0; i < range_size; i++, key++) {
-		*keyptr = htons(min + key % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack))
-			return 1;
-	}
-
-	DEBUGP("%p: no NAT mapping\n", conntrack);
-
-	return 0;
-}
-
-/* manipulate a GRE packet according to maniptype */
-static int
-gre_manip_pkt(struct sk_buff **pskb,
-	      unsigned int iphdroff,
-	      const struct ip_conntrack_tuple *tuple,
-	      enum ip_nat_manip_type maniptype)
-{
-	struct gre_hdr *greh;
-	struct gre_hdr_pptp *pgreh;
-	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	unsigned int hdroff = iphdroff + iph->ihl*4;
-
-	/* pgreh includes two optional 32bit fields which are not required
-	 * to be there.  That's where the magic '8' comes from */
-	if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8))
-		return 0;
-
-	greh = (void *)(*pskb)->data + hdroff;
-	pgreh = (struct gre_hdr_pptp *) greh;
-
-	/* 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 */
-		switch (greh->version) {
-		case 0:
-			if (!greh->key) {
-				DEBUGP("can't nat GRE w/o key\n");
-				break;
-			}
-			if (greh->csum) {
-				/* FIXME: Never tested this code... */
-				nf_proto_csum_replace4(gre_csum(greh), *pskb,
-							*(gre_key(greh)),
-							tuple->dst.u.gre.key, 0);
-			}
-			*(gre_key(greh)) = tuple->dst.u.gre.key;
-			break;
-		case GRE_VERSION_PPTP:
-			DEBUGP("call_id -> 0x%04x\n",
-				ntohs(tuple->dst.u.gre.key));
-			pgreh->call_id = tuple->dst.u.gre.key;
-			break;
-		default:
-			DEBUGP("can't nat unknown GRE version\n");
-			return 0;
-			break;
-		}
-	}
-	return 1;
-}
-
-/* nat helper struct */
-static struct ip_nat_protocol gre = {
-	.name		= "GRE",
-	.protonum	= IPPROTO_GRE,
-	.manip_pkt	= gre_manip_pkt,
-	.in_range	= gre_in_range,
-	.unique_tuple	= gre_unique_tuple,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.range_to_nfattr	= ip_nat_port_range_to_nfattr,
-	.nfattr_to_range	= ip_nat_port_nfattr_to_range,
-#endif
-};
-
-int __init ip_nat_proto_gre_init(void)
-{
-	return ip_nat_protocol_register(&gre);
-}
-
-void __exit ip_nat_proto_gre_fini(void)
-{
-	ip_nat_protocol_unregister(&gre);
-}
diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c
deleted file mode 100644
index 22a528a..0000000
--- a/net/ipv4/netfilter/ip_nat_proto_icmp.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/init.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <linux/icmp.h>
-#include <linux/if.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/ip_nat_protocol.h>
-
-static int
-icmp_in_range(const struct ip_conntrack_tuple *tuple,
-	      enum ip_nat_manip_type maniptype,
-	      const union ip_conntrack_manip_proto *min,
-	      const union ip_conntrack_manip_proto *max)
-{
-	return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
-	       ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
-}
-
-static int
-icmp_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 id;
-	unsigned int range_size;
-	unsigned int i;
-
-	range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1;
-	/* If no range specified... */
-	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
-		range_size = 0xFFFF;
-
-	for (i = 0; i < range_size; i++, id++) {
-		tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
-					     (id % range_size));
-		if (!ip_nat_used_tuple(tuple, conntrack))
-			return 1;
-	}
-	return 0;
-}
-
-static int
-icmp_manip_pkt(struct sk_buff **pskb,
-	       unsigned int iphdroff,
-	       const struct ip_conntrack_tuple *tuple,
-	       enum ip_nat_manip_type maniptype)
-{
-	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	struct icmphdr *hdr;
-	unsigned int hdroff = iphdroff + iph->ihl*4;
-
-	if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
-		return 0;
-
-	hdr = (struct icmphdr *)((*pskb)->data + hdroff);
-	nf_proto_csum_replace2(&hdr->checksum, *pskb,
-			       hdr->un.echo.id, tuple->src.u.icmp.id, 0);
-	hdr->un.echo.id = tuple->src.u.icmp.id;
-	return 1;
-}
-
-struct ip_nat_protocol ip_nat_protocol_icmp = {
-	.name			= "ICMP",
-	.protonum		= IPPROTO_ICMP,
-	.me			= THIS_MODULE,
-	.manip_pkt		= icmp_manip_pkt,
-	.in_range		= icmp_in_range,
-	.unique_tuple		= icmp_unique_tuple,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.range_to_nfattr	= ip_nat_port_range_to_nfattr,
-	.nfattr_to_range	= ip_nat_port_nfattr_to_range,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
deleted file mode 100644
index 14ff24f..0000000
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/if.h>
-#include <linux/netfilter/nfnetlink_conntrack.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-#include <linux/netfilter_ipv4/ip_nat_core.h>
-
-static int
-tcp_in_range(const struct ip_conntrack_tuple *tuple,
-	     enum ip_nat_manip_type maniptype,
-	     const union ip_conntrack_manip_proto *min,
-	     const union ip_conntrack_manip_proto *max)
-{
-	__be16 port;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		port = tuple->src.u.tcp.port;
-	else
-		port = tuple->dst.u.tcp.port;
-
-	return ntohs(port) >= ntohs(min->tcp.port)
-		&& ntohs(port) <= ntohs(max->tcp.port);
-}
-
-static int
-tcp_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 port;
-	__be16 *portptr;
-	unsigned int range_size, min, i;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		portptr = &tuple->src.u.tcp.port;
-	else
-		portptr = &tuple->dst.u.tcp.port;
-
-	/* If no range specified... */
-	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
-		/* If it's dst rewrite, can't change port */
-		if (maniptype == IP_NAT_MANIP_DST)
-			return 0;
-
-		/* Map privileged onto privileged. */
-		if (ntohs(*portptr) < 1024) {
-			/* Loose convention: >> 512 is credential passing */
-			if (ntohs(*portptr)<512) {
-				min = 1;
-				range_size = 511 - min + 1;
-			} else {
-				min = 600;
-				range_size = 1023 - min + 1;
-			}
-		} else {
-			min = 1024;
-			range_size = 65535 - 1024 + 1;
-		}
-	} else {
-		min = ntohs(range->min.tcp.port);
-		range_size = ntohs(range->max.tcp.port) - min + 1;
-	}
-
-	/* Start from random port to avoid prediction */
-	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
-		port =  net_random();
-
-	for (i = 0; i < range_size; i++, port++) {
-		*portptr = htons(min + port % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack)) {
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int
-tcp_manip_pkt(struct sk_buff **pskb,
-	      unsigned int iphdroff,
-	      const struct ip_conntrack_tuple *tuple,
-	      enum ip_nat_manip_type maniptype)
-{
-	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	struct tcphdr *hdr;
-	unsigned int hdroff = iphdroff + iph->ihl*4;
-	__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
-	   cases we cannot update the checksum field since it is outside of
-	   the 8 bytes of transport layer headers we are guaranteed */
-	if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
-		hdrsize = sizeof(struct tcphdr);
-
-	if (!skb_make_writable(pskb, hdroff + hdrsize))
-		return 0;
-
-	iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	hdr = (struct tcphdr *)((*pskb)->data + hdroff);
-
-	if (maniptype == IP_NAT_MANIP_SRC) {
-		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
-		newip = tuple->src.ip;
-		newport = tuple->src.u.tcp.port;
-		portptr = &hdr->source;
-	} else {
-		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
-		newip = tuple->dst.ip;
-		newport = tuple->dst.u.tcp.port;
-		portptr = &hdr->dest;
-	}
-
-	oldport = *portptr;
-	*portptr = newport;
-
-	if (hdrsize < sizeof(*hdr))
-		return 1;
-
-	nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
-	nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
-	return 1;
-}
-
-struct ip_nat_protocol ip_nat_protocol_tcp = {
-	.name			= "TCP",
-	.protonum		= IPPROTO_TCP,
-	.me			= THIS_MODULE,
-	.manip_pkt		= tcp_manip_pkt,
-	.in_range		= tcp_in_range,
-	.unique_tuple		= tcp_unique_tuple,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.range_to_nfattr	= ip_nat_port_range_to_nfattr,
-	.nfattr_to_range	= ip_nat_port_nfattr_to_range,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
deleted file mode 100644
index dfd5216..0000000
--- a/net/ipv4/netfilter/ip_nat_proto_udp.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/netfilter.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/if.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/ip_nat_protocol.h>
-
-static int
-udp_in_range(const struct ip_conntrack_tuple *tuple,
-	     enum ip_nat_manip_type maniptype,
-	     const union ip_conntrack_manip_proto *min,
-	     const union ip_conntrack_manip_proto *max)
-{
-	__be16 port;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		port = tuple->src.u.udp.port;
-	else
-		port = tuple->dst.u.udp.port;
-
-	return ntohs(port) >= ntohs(min->udp.port)
-		&& ntohs(port) <= ntohs(max->udp.port);
-}
-
-static int
-udp_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 port;
-	__be16 *portptr;
-	unsigned int range_size, min, i;
-
-	if (maniptype == IP_NAT_MANIP_SRC)
-		portptr = &tuple->src.u.udp.port;
-	else
-		portptr = &tuple->dst.u.udp.port;
-
-	/* If no range specified... */
-	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
-		/* If it's dst rewrite, can't change port */
-		if (maniptype == IP_NAT_MANIP_DST)
-			return 0;
-
-		if (ntohs(*portptr) < 1024) {
-			/* Loose convention: >> 512 is credential passing */
-			if (ntohs(*portptr)<512) {
-				min = 1;
-				range_size = 511 - min + 1;
-			} else {
-				min = 600;
-				range_size = 1023 - min + 1;
-			}
-		} else {
-			min = 1024;
-			range_size = 65535 - 1024 + 1;
-		}
-	} else {
-		min = ntohs(range->min.udp.port);
-		range_size = ntohs(range->max.udp.port) - min + 1;
-	}
-
-	/* Start from random port to avoid prediction */
-	if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
-		port = net_random();
-
-	for (i = 0; i < range_size; i++, port++) {
-		*portptr = htons(min + port % range_size);
-		if (!ip_nat_used_tuple(tuple, conntrack))
-			return 1;
-	}
-	return 0;
-}
-
-static int
-udp_manip_pkt(struct sk_buff **pskb,
-	      unsigned int iphdroff,
-	      const struct ip_conntrack_tuple *tuple,
-	      enum ip_nat_manip_type maniptype)
-{
-	struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	struct udphdr *hdr;
-	unsigned int hdroff = iphdroff + iph->ihl*4;
-	__be32 oldip, newip;
-	__be16 *portptr, newport;
-
-	if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
-		return 0;
-
-	iph = (struct iphdr *)((*pskb)->data + iphdroff);
-	hdr = (struct udphdr *)((*pskb)->data + hdroff);
-
-	if (maniptype == IP_NAT_MANIP_SRC) {
-		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
-		newip = tuple->src.ip;
-		newport = tuple->src.u.udp.port;
-		portptr = &hdr->source;
-	} else {
-		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
-		newip = tuple->dst.ip;
-		newport = tuple->dst.u.udp.port;
-		portptr = &hdr->dest;
-	}
-
-	if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
-		nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
-		nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0);
-		if (!hdr->check)
-			hdr->check = CSUM_MANGLED_0;
-	}
-	*portptr = newport;
-	return 1;
-}
-
-struct ip_nat_protocol ip_nat_protocol_udp = {
-	.name			= "UDP",
-	.protonum		= IPPROTO_UDP,
-	.me			= THIS_MODULE,
-	.manip_pkt		= udp_manip_pkt,
-	.in_range		= udp_in_range,
-	.unique_tuple		= udp_unique_tuple,
-#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
-    defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
-	.range_to_nfattr	= ip_nat_port_range_to_nfattr,
-	.nfattr_to_range	= ip_nat_port_nfattr_to_range,
-#endif
-};
diff --git a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c
deleted file mode 100644
index 3bf0495..0000000
--- a/net/ipv4/netfilter/ip_nat_proto_unknown.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* The "unknown" protocol.  This is what is used for protocols we
- * don't understand.  It's returned by ip_ct_find_proto().
- */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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/types.h>
-#include <linux/init.h>
-#include <linux/netfilter.h>
-#include <linux/if.h>
-
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/netfilter_ipv4/ip_nat_protocol.h>
-
-static int unknown_in_range(const struct ip_conntrack_tuple *tuple,
-			    enum ip_nat_manip_type manip_type,
-			    const union ip_conntrack_manip_proto *min,
-			    const union ip_conntrack_manip_proto *max)
-{
-	return 1;
-}
-
-static int unknown_unique_tuple(struct ip_conntrack_tuple *tuple,
-				const struct ip_nat_range *range,
-				enum ip_nat_manip_type maniptype,
-				const struct ip_conntrack *conntrack)
-{
-	/* Sorry: we can't help you; if it's not unique, we can't frob
-	   anything. */
-	return 0;
-}
-
-static int
-unknown_manip_pkt(struct sk_buff **pskb,
-		  unsigned int iphdroff,
-		  const struct ip_conntrack_tuple *tuple,
-		  enum ip_nat_manip_type maniptype)
-{
-	return 1;
-}
-
-struct ip_nat_protocol ip_nat_unknown_protocol = {
-	.name			= "unknown",
-	/* .me isn't set: getting a ref to this cannot fail. */
-	.manip_pkt		= unknown_manip_pkt,
-	.in_range		= unknown_in_range,
-	.unique_tuple		= unknown_unique_tuple,
-};
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
deleted file mode 100644
index 080eb1d..0000000
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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.
- */
-
-/* Everything about the rules for NAT. */
-#include <linux/types.h>
-#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <net/checksum.h>
-#include <net/route.h>
-#include <linux/bitops.h>
-
-#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>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-#define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))
-
-static struct
-{
-	struct ipt_replace repl;
-	struct ipt_standard entries[3];
-	struct ipt_error term;
-} nat_initial_table __initdata
-= { { "nat", NAT_VALID_HOOKS, 4,
-      sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] = 0,
-	[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      { [NF_IP_PRE_ROUTING] = 0,
-	[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-	[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      0, NULL, { } },
-    {
-	    /* PRE_ROUTING */
-	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ipt_entry),
-		sizeof(struct ipt_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* POST_ROUTING */
-	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ipt_entry),
-		sizeof(struct ipt_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } },
-	    /* LOCAL_OUT */
-	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-		0,
-		sizeof(struct ipt_entry),
-		sizeof(struct ipt_standard),
-		0, { 0, 0 }, { } },
-	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-	0,
-	sizeof(struct ipt_entry),
-	sizeof(struct ipt_error),
-	0, { 0, 0 }, { } },
-      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
-	  { } },
-	"ERROR"
-      }
-    }
-};
-
-static struct xt_table nat_table = {
-	.name		= "nat",
-	.valid_hooks	= NAT_VALID_HOOKS,
-	.lock		= RW_LOCK_UNLOCKED,
-	.me		= THIS_MODULE,
-	.af		= AF_INET,
-};
-
-/* Source NAT */
-static unsigned int ipt_snat_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)
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	const struct ip_nat_multi_range_compat *mr = targinfo;
-
-	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
-
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-
-	/* Connection must be valid and new. */
-	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
-			    || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
-	IP_NF_ASSERT(out);
-
-	return ip_nat_setup_info(ct, &mr->range[0], hooknum);
-}
-
-/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
-{
-	static int warned = 0;
-	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
-	struct rtable *rt;
-
-	if (ip_route_output_key(&rt, &fl) != 0)
-		return;
-
-	if (rt->rt_src != srcip && !warned) {
-		printk("NAT: no longer support implicit source local NAT\n");
-		printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n",
-		       NIPQUAD(srcip), NIPQUAD(dstip));
-		warned = 1;
-	}
-	ip_rt_put(rt);
-}
-
-static unsigned int ipt_dnat_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)
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	const struct ip_nat_multi_range_compat *mr = targinfo;
-
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
-		     || hooknum == NF_IP_LOCAL_OUT);
-
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-
-	/* Connection must be valid and new. */
-	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
-
-	if (hooknum == NF_IP_LOCAL_OUT
-	    && mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
-		warn_if_extra_mangle((*pskb)->nh.iph->daddr,
-				     mr->range[0].min_ip);
-
-	return ip_nat_setup_info(ct, &mr->range[0], hooknum);
-}
-
-static int ipt_snat_checkentry(const char *tablename,
-			       const void *entry,
-			       const struct xt_target *target,
-			       void *targinfo,
-			       unsigned int hook_mask)
-{
-	struct ip_nat_multi_range_compat *mr = targinfo;
-
-	/* Must be a valid range */
-	if (mr->rangesize != 1) {
-		printk("SNAT: multiple ranges no longer supported\n");
-		return 0;
-	}
-	return 1;
-}
-
-static int ipt_dnat_checkentry(const char *tablename,
-			       const void *entry,
-			       const struct xt_target *target,
-			       void *targinfo,
-			       unsigned int hook_mask)
-{
-	struct ip_nat_multi_range_compat *mr = targinfo;
-
-	/* Must be a valid range */
-	if (mr->rangesize != 1) {
-		printk("DNAT: multiple ranges no longer supported\n");
-		return 0;
-	}
-	if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
-		printk("DNAT: port randomization not supported\n");
-		return 0;
-	}
-	return 1;
-}
-
-inline unsigned int
-alloc_null_binding(struct ip_conntrack *conntrack,
-		   struct ip_nat_info *info,
-		   unsigned int hooknum)
-{
-	/* Force range to this IP; let proto decide mapping for
-	   per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
-	   Use reply in case it's already been mangled (eg local packet).
-	*/
-	__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);
-	struct ip_nat_range range
-		= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
-
-	DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack,
-	       NIPQUAD(ip));
-	return ip_nat_setup_info(conntrack, &range, hooknum);
-}
-
-unsigned int
-alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
-			     struct ip_nat_info *info,
-			     unsigned int hooknum)
-{
-	__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);
-	u_int16_t all
-		= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
-		   ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
-		   : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
-	struct ip_nat_range range
-		= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
-
-	DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
-	       conntrack, NIPQUAD(ip));
-	return ip_nat_setup_info(conntrack, &range, hooknum);
-}
-
-int ip_nat_rule_find(struct sk_buff **pskb,
-		     unsigned int hooknum,
-		     const struct net_device *in,
-		     const struct net_device *out,
-		     struct ip_conntrack *ct,
-		     struct ip_nat_info *info)
-{
-	int ret;
-
-	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
-
-	if (ret == NF_ACCEPT) {
-		if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
-			/* NUL mapping */
-			ret = alloc_null_binding(ct, info, hooknum);
-	}
-	return ret;
-}
-
-static struct xt_target ipt_snat_reg = {
-	.name		= "SNAT",
-	.family		= AF_INET,
-	.target		= ipt_snat_target,
-	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
-	.table		= "nat",
-	.hooks		= 1 << NF_IP_POST_ROUTING,
-	.checkentry	= ipt_snat_checkentry,
-};
-
-static struct xt_target ipt_dnat_reg = {
-	.name		= "DNAT",
-	.family		= AF_INET,
-	.target		= ipt_dnat_target,
-	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
-	.table		= "nat",
-	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
-	.checkentry	= ipt_dnat_checkentry,
-};
-
-int __init ip_nat_rule_init(void)
-{
-	int ret;
-
-	ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
-	if (ret != 0)
-		return ret;
-	ret = xt_register_target(&ipt_snat_reg);
-	if (ret != 0)
-		goto unregister_table;
-
-	ret = xt_register_target(&ipt_dnat_reg);
-	if (ret != 0)
-		goto unregister_snat;
-
-	return ret;
-
- unregister_snat:
-	xt_unregister_target(&ipt_snat_reg);
- unregister_table:
-	xt_unregister_table(&nat_table);
-
-	return ret;
-}
-
-void ip_nat_rule_cleanup(void)
-{
-	xt_unregister_target(&ipt_dnat_reg);
-	xt_unregister_target(&ipt_snat_reg);
-	ipt_unregister_table(&nat_table);
-}
diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c
deleted file mode 100644
index 325c5a9..0000000
--- a/net/ipv4/netfilter/ip_nat_sip.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/* SIP extension for UDP NAT alteration.
- *
- * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
- * based on RR's ip_nat_ftp.c and other modules.
- *
- * This program is free software; you can 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/udp.h>
-
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
-MODULE_DESCRIPTION("SIP NAT helper");
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-struct addr_map {
-	struct {
-		char		src[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
-		char		dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
-		unsigned int	srclen, srciplen;
-		unsigned int	dstlen, dstiplen;
-	} addr[IP_CT_DIR_MAX];
-};
-
-static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map)
-{
-	struct ip_conntrack_tuple *t;
-	enum ip_conntrack_dir dir;
-	unsigned int n;
-
-	for (dir = 0; dir < IP_CT_DIR_MAX; dir++) {
-		t = &ct->tuplehash[dir].tuple;
-
-		n = sprintf(map->addr[dir].src, "%u.%u.%u.%u",
-			    NIPQUAD(t->src.ip));
-		map->addr[dir].srciplen = n;
-		n += sprintf(map->addr[dir].src + n, ":%u",
-			     ntohs(t->src.u.udp.port));
-		map->addr[dir].srclen = n;
-
-		n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u",
-			    NIPQUAD(t->dst.ip));
-		map->addr[dir].dstiplen = n;
-		n += sprintf(map->addr[dir].dst + n, ":%u",
-			     ntohs(t->dst.u.udp.port));
-		map->addr[dir].dstlen = n;
-	}
-}
-
-static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
-			struct ip_conntrack *ct, const char **dptr, size_t dlen,
-			enum sip_header_pos pos, struct addr_map *map)
-{
-	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	unsigned int matchlen, matchoff, addrlen;
-	char *addr;
-
-	if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0)
-		return 1;
-
-	if ((matchlen == map->addr[dir].srciplen ||
-	     matchlen == map->addr[dir].srclen) &&
-	    memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
-		addr    = map->addr[!dir].dst;
-		addrlen = map->addr[!dir].dstlen;
-	} else if ((matchlen == map->addr[dir].dstiplen ||
-		    matchlen == map->addr[dir].dstlen) &&
-		   memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
-		addr    = map->addr[!dir].src;
-		addrlen = map->addr[!dir].srclen;
-	} else
-		return 1;
-
-	if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
-				      matchoff, matchlen, addr, addrlen))
-		return 0;
-	*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-	return 1;
-
-}
-
-static unsigned int ip_nat_sip(struct sk_buff **pskb,
-			       enum ip_conntrack_info ctinfo,
-			       struct ip_conntrack *ct,
-			       const char **dptr)
-{
-	enum sip_header_pos pos;
-	struct addr_map map;
-	int dataoff, datalen;
-
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-	datalen = (*pskb)->len - dataoff;
-	if (datalen < sizeof("SIP/2.0") - 1)
-		return NF_DROP;
-
-	addr_map_init(ct, &map);
-
-	/* Basic rules: requests and responses. */
-	if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) {
-		/* 10.2: Constructing the REGISTER Request:
-		 *
-		 * The "userinfo" and "@" components of the SIP URI MUST NOT
-		 * be present.
-		 */
-		if (datalen >= sizeof("REGISTER") - 1 &&
-		    strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
-			pos = POS_REG_REQ_URI;
-		else
-			pos = POS_REQ_URI;
-
-		if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map))
-			return NF_DROP;
-	}
-
-	if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
-		return NF_DROP;
-	return NF_ACCEPT;
-}
-
-static unsigned int mangle_sip_packet(struct sk_buff **pskb,
-				      enum ip_conntrack_info ctinfo,
-				      struct ip_conntrack *ct,
-				      const char **dptr, size_t dlen,
-				      char *buffer, int bufflen,
-				      enum sip_header_pos pos)
-{
-	unsigned int matchlen, matchoff;
-
-	if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0)
-		return 0;
-
-	if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
-				      matchoff, matchlen, buffer, bufflen))
-		return 0;
-
-	/* We need to reload this. Thanks Patrick. */
-	*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-	return 1;
-}
-
-static int mangle_content_len(struct sk_buff **pskb,
-			      enum ip_conntrack_info ctinfo,
-			      struct ip_conntrack *ct,
-			      const char *dptr)
-{
-	unsigned int dataoff, matchoff, matchlen;
-	char buffer[sizeof("65536")];
-	int bufflen;
-
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-
-	/* Get actual SDP lenght */
-	if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
-			    &matchlen, POS_SDP_HEADER) > 0) {
-
-		/* since ct_sip_get_info() give us a pointer passing 'v='
-		   we need to add 2 bytes in this count. */
-		int c_len = (*pskb)->len - dataoff - matchoff + 2;
-
-		/* Now, update SDP lenght */
-		if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
-				    &matchlen, POS_CONTENT) > 0) {
-
-			bufflen = sprintf(buffer, "%u", c_len);
-
-			return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
-							matchoff, matchlen,
-							buffer, bufflen);
-		}
-	}
-	return 0;
-}
-
-static unsigned int mangle_sdp(struct sk_buff **pskb,
-			       enum ip_conntrack_info ctinfo,
-			       struct ip_conntrack *ct,
-			       __be32 newip, u_int16_t port,
-			       const char *dptr)
-{
-	char buffer[sizeof("nnn.nnn.nnn.nnn")];
-	unsigned int dataoff, bufflen;
-
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
-
-	/* Mangle owner and contact info. */
-	bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
-	if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
-			       buffer, bufflen, POS_OWNER))
-		return 0;
-
-	if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
-			       buffer, bufflen, POS_CONNECTION))
-		return 0;
-
-	/* Mangle media port. */
-	bufflen = sprintf(buffer, "%u", port);
-	if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
-			       buffer, bufflen, POS_MEDIA))
-		return 0;
-
-	return mangle_content_len(pskb, ctinfo, ct, dptr);
-}
-
-/* So, this packet has hit the connection tracking matching code.
-   Mangle it, and change the expectation to match the new version. */
-static unsigned int ip_nat_sdp(struct sk_buff **pskb,
-			       enum ip_conntrack_info ctinfo,
-			       struct ip_conntrack_expect *exp,
-			       const char *dptr)
-{
-	struct ip_conntrack *ct = exp->master;
-	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	__be32 newip;
-	u_int16_t port;
-
-	DEBUGP("ip_nat_sdp():\n");
-
-	/* Connection will come from reply */
-	newip = ct->tuplehash[!dir].tuple.dst.ip;
-
-	exp->tuple.dst.ip = newip;
-	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
-	exp->dir = !dir;
-
-	/* When you see the packet, we need to NAT it the same as the
-	   this one. */
-	exp->expectfn = ip_nat_follow_master;
-
-	/* Try to get same port: if not, try to change it. */
-	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
-		exp->tuple.dst.u.udp.port = htons(port);
-		if (ip_conntrack_expect_related(exp) == 0)
-			break;
-	}
-
-	if (port == 0)
-		return NF_DROP;
-
-	if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
-		ip_conntrack_unexpect_related(exp);
-		return NF_DROP;
-	}
-	return NF_ACCEPT;
-}
-
-static void __exit fini(void)
-{
-	rcu_assign_pointer(ip_nat_sip_hook, NULL);
-	rcu_assign_pointer(ip_nat_sdp_hook, NULL);
-	synchronize_rcu();
-}
-
-static int __init init(void)
-{
-	BUG_ON(rcu_dereference(ip_nat_sip_hook));
-	BUG_ON(rcu_dereference(ip_nat_sdp_hook));
-	rcu_assign_pointer(ip_nat_sip_hook, ip_nat_sip);
-	rcu_assign_pointer(ip_nat_sdp_hook, ip_nat_sdp);
-	return 0;
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
deleted file mode 100644
index e41d0ef..0000000
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ /dev/null
@@ -1,1333 +0,0 @@
-/*
- * ip_nat_snmp_basic.c
- *
- * Basic SNMP Application Layer Gateway
- *
- * This IP NAT module is intended for use with SNMP network
- * discovery and monitoring applications where target networks use
- * conflicting private address realms.
- *
- * Static NAT is used to remap the networks from the view of the network
- * management system at the IP layer, and this module remaps some application
- * layer addresses to match.
- *
- * The simplest form of ALG is performed, where only tagged IP addresses
- * are modified.  The module does not need to be MIB aware and only scans
- * messages at the ASN.1/BER level.
- *
- * Currently, only SNMPv1 and SNMPv2 are supported.
- *
- * More information on ALG and associated issues can be found in
- * RFC 2962
- *
- * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory
- * McLean & Jochen Friedrich, stripped down for use in the kernel.
- *
- * Copyright (c) 2000 RP Internet (www.rpi.net.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
- *
- * Author: James Morris <jmorris@intercode.com.au>
- *
- * Updates:
- * 2000-08-06: Convert to new helper API (Harald Welte).
- *
- */
-#include <linux/in.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/moduleparam.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <net/checksum.h>
-#include <net/udp.h>
-#include <asm/uaccess.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
-MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway");
-
-#define SNMP_PORT 161
-#define SNMP_TRAP_PORT 162
-#define NOCT1(n) (*(u8 *)n)
-
-static int debug;
-static DEFINE_SPINLOCK(snmp_lock);
-
-/*
- * Application layer address mapping mimics the NAT mapping, but
- * only for the first octet in this case (a more flexible system
- * can be implemented if needed).
- */
-struct oct1_map
-{
-	u_int8_t from;
-	u_int8_t to;
-};
-
-
-/*****************************************************************************
- *
- * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
- *
- *****************************************************************************/
-
-/* Class */
-#define ASN1_UNI	0	/* Universal */
-#define ASN1_APL	1	/* Application */
-#define ASN1_CTX	2	/* Context */
-#define ASN1_PRV	3	/* Private */
-
-/* Tag */
-#define ASN1_EOC	0	/* End Of Contents */
-#define ASN1_BOL	1	/* Boolean */
-#define ASN1_INT	2	/* Integer */
-#define ASN1_BTS	3	/* Bit String */
-#define ASN1_OTS	4	/* Octet String */
-#define ASN1_NUL	5	/* Null */
-#define ASN1_OJI	6	/* Object Identifier  */
-#define ASN1_OJD	7	/* Object Description */
-#define ASN1_EXT	8	/* External */
-#define ASN1_SEQ	16	/* Sequence */
-#define ASN1_SET	17	/* Set */
-#define ASN1_NUMSTR	18	/* Numerical String */
-#define ASN1_PRNSTR	19	/* Printable String */
-#define ASN1_TEXSTR	20	/* Teletext String */
-#define ASN1_VIDSTR	21	/* Video String */
-#define ASN1_IA5STR	22	/* IA5 String */
-#define ASN1_UNITIM	23	/* Universal Time */
-#define ASN1_GENTIM	24	/* General Time */
-#define ASN1_GRASTR	25	/* Graphical String */
-#define ASN1_VISSTR	26	/* Visible String */
-#define ASN1_GENSTR	27	/* General String */
-
-/* Primitive / Constructed methods*/
-#define ASN1_PRI	0	/* Primitive */
-#define ASN1_CON	1	/* Constructed */
-
-/*
- * Error codes.
- */
-#define ASN1_ERR_NOERROR		0
-#define ASN1_ERR_DEC_EMPTY		2
-#define ASN1_ERR_DEC_EOC_MISMATCH	3
-#define ASN1_ERR_DEC_LENGTH_MISMATCH	4
-#define ASN1_ERR_DEC_BADVALUE		5
-
-/*
- * ASN.1 context.
- */
-struct asn1_ctx
-{
-	int error;			/* Error condition */
-	unsigned char *pointer;		/* Octet just to be decoded */
-	unsigned char *begin;		/* First octet */
-	unsigned char *end;		/* Octet after last octet */
-};
-
-/*
- * Octet string (not null terminated)
- */
-struct asn1_octstr
-{
-	unsigned char *data;
-	unsigned int len;
-};
-
-static void asn1_open(struct asn1_ctx *ctx,
-		      unsigned char *buf,
-		      unsigned int len)
-{
-	ctx->begin = buf;
-	ctx->end = buf + len;
-	ctx->pointer = buf;
-	ctx->error = ASN1_ERR_NOERROR;
-}
-
-static unsigned char asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
-{
-	if (ctx->pointer >= ctx->end) {
-		ctx->error = ASN1_ERR_DEC_EMPTY;
-		return 0;
-	}
-	*ch = *(ctx->pointer)++;
-	return 1;
-}
-
-static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
-{
-	unsigned char ch;
-
-	*tag = 0;
-
-	do
-	{
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-		*tag <<= 7;
-		*tag |= ch & 0x7F;
-	} while ((ch & 0x80) == 0x80);
-	return 1;
-}
-
-static unsigned char asn1_id_decode(struct asn1_ctx *ctx,
-				    unsigned int *cls,
-				    unsigned int *con,
-				    unsigned int *tag)
-{
-	unsigned char ch;
-
-	if (!asn1_octet_decode(ctx, &ch))
-		return 0;
-
-	*cls = (ch & 0xC0) >> 6;
-	*con = (ch & 0x20) >> 5;
-	*tag = (ch & 0x1F);
-
-	if (*tag == 0x1F) {
-		if (!asn1_tag_decode(ctx, tag))
-			return 0;
-	}
-	return 1;
-}
-
-static unsigned char asn1_length_decode(struct asn1_ctx *ctx,
-					unsigned int *def,
-					unsigned int *len)
-{
-	unsigned char ch, cnt;
-
-	if (!asn1_octet_decode(ctx, &ch))
-		return 0;
-
-	if (ch == 0x80)
-		*def = 0;
-	else {
-		*def = 1;
-
-		if (ch < 0x80)
-			*len = ch;
-		else {
-			cnt = (unsigned char) (ch & 0x7F);
-			*len = 0;
-
-			while (cnt > 0) {
-				if (!asn1_octet_decode(ctx, &ch))
-					return 0;
-				*len <<= 8;
-				*len |= ch;
-				cnt--;
-			}
-		}
-	}
-	return 1;
-}
-
-static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
-					unsigned char **eoc,
-					unsigned int *cls,
-					unsigned int *con,
-					unsigned int *tag)
-{
-	unsigned int def, len;
-
-	if (!asn1_id_decode(ctx, cls, con, tag))
-		return 0;
-
-	def = len = 0;
-	if (!asn1_length_decode(ctx, &def, &len))
-		return 0;
-
-	if (def)
-		*eoc = ctx->pointer + len;
-	else
-		*eoc = NULL;
-	return 1;
-}
-
-static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
-{
-	unsigned char ch;
-
-	if (eoc == 0) {
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		if (ch != 0x00) {
-			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-			return 0;
-		}
-
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		if (ch != 0x00) {
-			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-			return 0;
-		}
-		return 1;
-	} else {
-		if (ctx->pointer != eoc) {
-			ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
-			return 0;
-		}
-		return 1;
-	}
-}
-
-static unsigned char asn1_null_decode(struct asn1_ctx *ctx, unsigned char *eoc)
-{
-	ctx->pointer = eoc;
-	return 1;
-}
-
-static unsigned char asn1_long_decode(struct asn1_ctx *ctx,
-				      unsigned char *eoc,
-				      long *integer)
-{
-	unsigned char ch;
-	unsigned int  len;
-
-	if (!asn1_octet_decode(ctx, &ch))
-		return 0;
-
-	*integer = (signed char) ch;
-	len = 1;
-
-	while (ctx->pointer < eoc) {
-		if (++len > sizeof (long)) {
-			ctx->error = ASN1_ERR_DEC_BADVALUE;
-			return 0;
-		}
-
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		*integer <<= 8;
-		*integer |= ch;
-	}
-	return 1;
-}
-
-static unsigned char asn1_uint_decode(struct asn1_ctx *ctx,
-				      unsigned char *eoc,
-				      unsigned int *integer)
-{
-	unsigned char ch;
-	unsigned int  len;
-
-	if (!asn1_octet_decode(ctx, &ch))
-		return 0;
-
-	*integer = ch;
-	if (ch == 0) len = 0;
-	else len = 1;
-
-	while (ctx->pointer < eoc) {
-		if (++len > sizeof (unsigned int)) {
-			ctx->error = ASN1_ERR_DEC_BADVALUE;
-			return 0;
-		}
-
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		*integer <<= 8;
-		*integer |= ch;
-	}
-	return 1;
-}
-
-static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
-				       unsigned char *eoc,
-				       unsigned long *integer)
-{
-	unsigned char ch;
-	unsigned int  len;
-
-	if (!asn1_octet_decode(ctx, &ch))
-		return 0;
-
-	*integer = ch;
-	if (ch == 0) len = 0;
-	else len = 1;
-
-	while (ctx->pointer < eoc) {
-		if (++len > sizeof (unsigned long)) {
-			ctx->error = ASN1_ERR_DEC_BADVALUE;
-			return 0;
-		}
-
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		*integer <<= 8;
-		*integer |= ch;
-	}
-	return 1;
-}
-
-static unsigned char asn1_octets_decode(struct asn1_ctx *ctx,
-					unsigned char *eoc,
-					unsigned char **octets,
-					unsigned int *len)
-{
-	unsigned char *ptr;
-
-	*len = 0;
-
-	*octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);
-	if (*octets == NULL) {
-		if (net_ratelimit())
-			printk("OOM in bsalg (%d)\n", __LINE__);
-		return 0;
-	}
-
-	ptr = *octets;
-	while (ctx->pointer < eoc) {
-		if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) {
-			kfree(*octets);
-			*octets = NULL;
-			return 0;
-		}
-		(*len)++;
-	}
-	return 1;
-}
-
-static unsigned char asn1_subid_decode(struct asn1_ctx *ctx,
-				       unsigned long *subid)
-{
-	unsigned char ch;
-
-	*subid = 0;
-
-	do {
-		if (!asn1_octet_decode(ctx, &ch))
-			return 0;
-
-		*subid <<= 7;
-		*subid |= ch & 0x7F;
-	} while ((ch & 0x80) == 0x80);
-	return 1;
-}
-
-static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
-				     unsigned char *eoc,
-				     unsigned long **oid,
-				     unsigned int *len)
-{
-	unsigned long subid;
-	unsigned int  size;
-	unsigned long *optr;
-
-	size = eoc - ctx->pointer + 1;
-	*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
-	if (*oid == NULL) {
-		if (net_ratelimit())
-			printk("OOM in bsalg (%d)\n", __LINE__);
-		return 0;
-	}
-
-	optr = *oid;
-
-	if (!asn1_subid_decode(ctx, &subid)) {
-		kfree(*oid);
-		*oid = NULL;
-		return 0;
-	}
-
-	if (subid < 40) {
-		optr [0] = 0;
-		optr [1] = subid;
-	} else if (subid < 80) {
-		optr [0] = 1;
-		optr [1] = subid - 40;
-	} else {
-		optr [0] = 2;
-		optr [1] = subid - 80;
-	}
-
-	*len = 2;
-	optr += 2;
-
-	while (ctx->pointer < eoc) {
-		if (++(*len) > size) {
-			ctx->error = ASN1_ERR_DEC_BADVALUE;
-			kfree(*oid);
-			*oid = NULL;
-			return 0;
-		}
-
-		if (!asn1_subid_decode(ctx, optr++)) {
-			kfree(*oid);
-			*oid = NULL;
-			return 0;
-		}
-	}
-	return 1;
-}
-
-/*****************************************************************************
- *
- * SNMP decoding routines (gxsnmp author Dirk Wisse)
- *
- *****************************************************************************/
-
-/* SNMP Versions */
-#define SNMP_V1				0
-#define SNMP_V2C			1
-#define SNMP_V2				2
-#define SNMP_V3				3
-
-/* Default Sizes */
-#define SNMP_SIZE_COMM			256
-#define SNMP_SIZE_OBJECTID		128
-#define SNMP_SIZE_BUFCHR		256
-#define SNMP_SIZE_BUFINT		128
-#define SNMP_SIZE_SMALLOBJECTID		16
-
-/* Requests */
-#define SNMP_PDU_GET			0
-#define SNMP_PDU_NEXT			1
-#define SNMP_PDU_RESPONSE		2
-#define SNMP_PDU_SET			3
-#define SNMP_PDU_TRAP1			4
-#define SNMP_PDU_BULK			5
-#define SNMP_PDU_INFORM			6
-#define SNMP_PDU_TRAP2			7
-
-/* Errors */
-#define SNMP_NOERROR			0
-#define SNMP_TOOBIG			1
-#define SNMP_NOSUCHNAME			2
-#define SNMP_BADVALUE			3
-#define SNMP_READONLY			4
-#define SNMP_GENERROR			5
-#define SNMP_NOACCESS			6
-#define SNMP_WRONGTYPE			7
-#define SNMP_WRONGLENGTH		8
-#define SNMP_WRONGENCODING		9
-#define SNMP_WRONGVALUE			10
-#define SNMP_NOCREATION			11
-#define SNMP_INCONSISTENTVALUE		12
-#define SNMP_RESOURCEUNAVAILABLE	13
-#define SNMP_COMMITFAILED		14
-#define SNMP_UNDOFAILED			15
-#define SNMP_AUTHORIZATIONERROR		16
-#define SNMP_NOTWRITABLE		17
-#define SNMP_INCONSISTENTNAME		18
-
-/* General SNMP V1 Traps */
-#define SNMP_TRAP_COLDSTART		0
-#define SNMP_TRAP_WARMSTART		1
-#define SNMP_TRAP_LINKDOWN		2
-#define SNMP_TRAP_LINKUP		3
-#define SNMP_TRAP_AUTFAILURE		4
-#define SNMP_TRAP_EQPNEIGHBORLOSS	5
-#define SNMP_TRAP_ENTSPECIFIC		6
-
-/* SNMPv1 Types */
-#define SNMP_NULL                0
-#define SNMP_INTEGER             1    /* l  */
-#define SNMP_OCTETSTR            2    /* c  */
-#define SNMP_DISPLAYSTR          2    /* c  */
-#define SNMP_OBJECTID            3    /* ul */
-#define SNMP_IPADDR              4    /* uc */
-#define SNMP_COUNTER             5    /* ul */
-#define SNMP_GAUGE               6    /* ul */
-#define SNMP_TIMETICKS           7    /* ul */
-#define SNMP_OPAQUE              8    /* c  */
-
-/* Additional SNMPv2 Types */
-#define SNMP_UINTEGER            5    /* ul */
-#define SNMP_BITSTR              9    /* uc */
-#define SNMP_NSAP               10    /* uc */
-#define SNMP_COUNTER64          11    /* ul */
-#define SNMP_NOSUCHOBJECT       12
-#define SNMP_NOSUCHINSTANCE     13
-#define SNMP_ENDOFMIBVIEW       14
-
-union snmp_syntax
-{
-	unsigned char uc[0];	/* 8 bit unsigned */
-	char c[0];		/* 8 bit signed */
-	unsigned long ul[0];	/* 32 bit unsigned */
-	long l[0];		/* 32 bit signed */
-};
-
-struct snmp_object
-{
-	unsigned long *id;
-	unsigned int id_len;
-	unsigned short type;
-	unsigned int syntax_len;
-	union snmp_syntax syntax;
-};
-
-struct snmp_request
-{
-	unsigned long id;
-	unsigned int error_status;
-	unsigned int error_index;
-};
-
-struct snmp_v1_trap
-{
-	unsigned long *id;
-	unsigned int id_len;
-	unsigned long ip_address;	/* pointer  */
-	unsigned int general;
-	unsigned int specific;
-	unsigned long time;
-};
-
-/* SNMP types */
-#define SNMP_IPA    0
-#define SNMP_CNT    1
-#define SNMP_GGE    2
-#define SNMP_TIT    3
-#define SNMP_OPQ    4
-#define SNMP_C64    6
-
-/* SNMP errors */
-#define SERR_NSO    0
-#define SERR_NSI    1
-#define SERR_EOM    2
-
-static inline void mangle_address(unsigned char *begin,
-				  unsigned char *addr,
-				  const struct oct1_map *map,
-				  __sum16 *check);
-struct snmp_cnv
-{
-	unsigned int class;
-	unsigned int tag;
-	int syntax;
-};
-
-static struct snmp_cnv snmp_conv [] =
-{
-	{ASN1_UNI, ASN1_NUL, SNMP_NULL},
-	{ASN1_UNI, ASN1_INT, SNMP_INTEGER},
-	{ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR},
-	{ASN1_UNI, ASN1_OTS, SNMP_DISPLAYSTR},
-	{ASN1_UNI, ASN1_OJI, SNMP_OBJECTID},
-	{ASN1_APL, SNMP_IPA, SNMP_IPADDR},
-	{ASN1_APL, SNMP_CNT, SNMP_COUNTER},	/* Counter32 */
-	{ASN1_APL, SNMP_GGE, SNMP_GAUGE},	/* Gauge32 == Unsigned32  */
-	{ASN1_APL, SNMP_TIT, SNMP_TIMETICKS},
-	{ASN1_APL, SNMP_OPQ, SNMP_OPAQUE},
-
-	/* SNMPv2 data types and errors */
-	{ASN1_UNI, ASN1_BTS, SNMP_BITSTR},
-	{ASN1_APL, SNMP_C64, SNMP_COUNTER64},
-	{ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT},
-	{ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE},
-	{ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW},
-	{0,       0,       -1}
-};
-
-static unsigned char snmp_tag_cls2syntax(unsigned int tag,
-					 unsigned int cls,
-					 unsigned short *syntax)
-{
-	struct snmp_cnv *cnv;
-
-	cnv = snmp_conv;
-
-	while (cnv->syntax != -1) {
-		if (cnv->tag == tag && cnv->class == cls) {
-			*syntax = cnv->syntax;
-			return 1;
-		}
-		cnv++;
-	}
-	return 0;
-}
-
-static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
-					struct snmp_object **obj)
-{
-	unsigned int cls, con, tag, len, idlen;
-	unsigned short type;
-	unsigned char *eoc, *end, *p;
-	unsigned long *lp, *id;
-	unsigned long ul;
-	long l;
-
-	*obj = NULL;
-	id = NULL;
-
-	if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
-		return 0;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI)
-		return 0;
-
-	if (!asn1_oid_decode(ctx, end, &id, &idlen))
-		return 0;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) {
-		kfree(id);
-		return 0;
-	}
-
-	if (con != ASN1_PRI) {
-		kfree(id);
-		return 0;
-	}
-
-	type = 0;
-	if (!snmp_tag_cls2syntax(tag, cls, &type)) {
-		kfree(id);
-		return 0;
-	}
-
-	l = 0;
-	switch (type) {
-		case SNMP_INTEGER:
-			len = sizeof(long);
-			if (!asn1_long_decode(ctx, end, &l)) {
-				kfree(id);
-				return 0;
-			}
-			*obj = kmalloc(sizeof(struct snmp_object) + len,
-				       GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			(*obj)->syntax.l[0] = l;
-			break;
-		case SNMP_OCTETSTR:
-		case SNMP_OPAQUE:
-			if (!asn1_octets_decode(ctx, end, &p, &len)) {
-				kfree(id);
-				return 0;
-			}
-			*obj = kmalloc(sizeof(struct snmp_object) + len,
-				       GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			memcpy((*obj)->syntax.c, p, len);
-			kfree(p);
-			break;
-		case SNMP_NULL:
-		case SNMP_NOSUCHOBJECT:
-		case SNMP_NOSUCHINSTANCE:
-		case SNMP_ENDOFMIBVIEW:
-			len = 0;
-			*obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			if (!asn1_null_decode(ctx, end)) {
-				kfree(id);
-				kfree(*obj);
-				*obj = NULL;
-				return 0;
-			}
-			break;
-		case SNMP_OBJECTID:
-			if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) {
-				kfree(id);
-				return 0;
-			}
-			len *= sizeof(unsigned long);
-			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(lp);
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			memcpy((*obj)->syntax.ul, lp, len);
-			kfree(lp);
-			break;
-		case SNMP_IPADDR:
-			if (!asn1_octets_decode(ctx, end, &p, &len)) {
-				kfree(id);
-				return 0;
-			}
-			if (len != 4) {
-				kfree(p);
-				kfree(id);
-				return 0;
-			}
-			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(p);
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			memcpy((*obj)->syntax.uc, p, len);
-			kfree(p);
-			break;
-		case SNMP_COUNTER:
-		case SNMP_GAUGE:
-		case SNMP_TIMETICKS:
-			len = sizeof(unsigned long);
-			if (!asn1_ulong_decode(ctx, end, &ul)) {
-				kfree(id);
-				return 0;
-			}
-			*obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC);
-			if (*obj == NULL) {
-				kfree(id);
-				if (net_ratelimit())
-					printk("OOM in bsalg (%d)\n", __LINE__);
-				return 0;
-			}
-			(*obj)->syntax.ul[0] = ul;
-			break;
-		default:
-			kfree(id);
-			return 0;
-	}
-
-	(*obj)->syntax_len = len;
-	(*obj)->type = type;
-	(*obj)->id = id;
-	(*obj)->id_len = idlen;
-
-	if (!asn1_eoc_decode(ctx, eoc)) {
-		kfree(id);
-		kfree(*obj);
-		*obj = NULL;
-		return 0;
-	}
-	return 1;
-}
-
-static unsigned char snmp_request_decode(struct asn1_ctx *ctx,
-					 struct snmp_request *request)
-{
-	unsigned int cls, con, tag;
-	unsigned char *end;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		return 0;
-
-	if (!asn1_ulong_decode(ctx, end, &request->id))
-		return 0;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		return 0;
-
-	if (!asn1_uint_decode(ctx, end, &request->error_status))
-		return 0;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		return 0;
-
-	if (!asn1_uint_decode(ctx, end, &request->error_index))
-		return 0;
-
-	return 1;
-}
-
-/*
- * Fast checksum update for possibly oddly-aligned UDP byte, from the
- * code example in the draft.
- */
-static void fast_csum(__sum16 *csum,
-		      const unsigned char *optr,
-		      const unsigned char *nptr,
-		      int offset)
-{
-	unsigned char s[4];
-
-	if (offset & 1) {
-		s[0] = s[2] = 0;
-		s[1] = ~*optr;
-		s[3] = *nptr;
-	} else {
-		s[1] = s[3] = 0;
-		s[0] = ~*optr;
-		s[2] = *nptr;
-	}
-
-	*csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum)));
-}
-
-/*
- * Mangle IP address.
- * 	- begin points to the start of the snmp messgae
- *      - addr points to the start of the address
- */
-static inline void mangle_address(unsigned char *begin,
-				  unsigned char *addr,
-				  const struct oct1_map *map,
-				  __sum16 *check)
-{
-	if (map->from == NOCT1(addr)) {
-		u_int32_t old;
-
-		if (debug)
-			memcpy(&old, (unsigned char *)addr, sizeof(old));
-
-		*addr = map->to;
-
-		/* Update UDP checksum if being used */
-		if (*check) {
-			fast_csum(check,
-				  &map->from, &map->to, addr - begin);
-		}
-
-		if (debug)
-			printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to "
-			       "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr));
-	}
-}
-
-static unsigned char snmp_trap_decode(struct asn1_ctx *ctx,
-				      struct snmp_v1_trap *trap,
-				      const struct oct1_map *map,
-				      __sum16 *check)
-{
-	unsigned int cls, con, tag, len;
-	unsigned char *end;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI)
-		return 0;
-
-	if (!asn1_oid_decode(ctx, end, &trap->id, &trap->id_len))
-		return 0;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		goto err_id_free;
-
-	if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
-	      (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS)))
-		goto err_id_free;
-
-	if (!asn1_octets_decode(ctx, end, (unsigned char **)&trap->ip_address, &len))
-		goto err_id_free;
-
-	/* IPv4 only */
-	if (len != 4)
-		goto err_addr_free;
-
-	mangle_address(ctx->begin, ctx->pointer - 4, map, check);
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		goto err_addr_free;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		goto err_addr_free;
-
-	if (!asn1_uint_decode(ctx, end, &trap->general))
-		goto err_addr_free;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		goto err_addr_free;
-
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		goto err_addr_free;
-
-	if (!asn1_uint_decode(ctx, end, &trap->specific))
-		goto err_addr_free;
-
-	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
-		goto err_addr_free;
-
-	if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
-	      (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT)))
-		goto err_addr_free;
-
-	if (!asn1_ulong_decode(ctx, end, &trap->time))
-		goto err_addr_free;
-
-	return 1;
-
-err_addr_free:
-	kfree((unsigned long *)trap->ip_address);
-
-err_id_free:
-	kfree(trap->id);
-
-	return 0;
-}
-
-/*****************************************************************************
- *
- * Misc. routines
- *
- *****************************************************************************/
-
-static void hex_dump(unsigned char *buf, size_t len)
-{
-	size_t i;
-
-	for (i = 0; i < len; i++) {
-		if (i && !(i % 16))
-			printk("\n");
-		printk("%02x ", *(buf + i));
-	}
-	printk("\n");
-}
-
-/*
- * Parse and mangle SNMP message according to mapping.
- * (And this is the fucking 'basic' method).
- */
-static int snmp_parse_mangle(unsigned char *msg,
-			     u_int16_t len,
-			     const struct oct1_map *map,
-			     __sum16 *check)
-{
-	unsigned char *eoc, *end;
-	unsigned int cls, con, tag, vers, pdutype;
-	struct asn1_ctx ctx;
-	struct asn1_octstr comm;
-	struct snmp_object **obj;
-
-	if (debug > 1)
-		hex_dump(msg, len);
-
-	asn1_open(&ctx, msg, len);
-
-	/*
-	 * Start of SNMP message.
-	 */
-	if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag))
-		return 0;
-	if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
-		return 0;
-
-	/*
-	 * Version 1 or 2 handled.
-	 */
-	if (!asn1_header_decode(&ctx, &end, &cls, &con, &tag))
-		return 0;
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		return 0;
-	if (!asn1_uint_decode (&ctx, end, &vers))
-		return 0;
-	if (debug > 1)
-		printk(KERN_DEBUG "bsalg: snmp version: %u\n", vers + 1);
-	if (vers > 1)
-		return 1;
-
-	/*
-	 * Community.
-	 */
-	if (!asn1_header_decode (&ctx, &end, &cls, &con, &tag))
-		return 0;
-	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS)
-		return 0;
-	if (!asn1_octets_decode(&ctx, end, &comm.data, &comm.len))
-		return 0;
-	if (debug > 1) {
-		unsigned int i;
-
-		printk(KERN_DEBUG "bsalg: community: ");
-		for (i = 0; i < comm.len; i++)
-			printk("%c", comm.data[i]);
-		printk("\n");
-	}
-	kfree(comm.data);
-
-	/*
-	 * PDU type
-	 */
-	if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &pdutype))
-		return 0;
-	if (cls != ASN1_CTX || con != ASN1_CON)
-		return 0;
-	if (debug > 1) {
-		unsigned char *pdus[] = {
-			[SNMP_PDU_GET] = "get",
-			[SNMP_PDU_NEXT] = "get-next",
-			[SNMP_PDU_RESPONSE] = "response",
-			[SNMP_PDU_SET] = "set",
-			[SNMP_PDU_TRAP1] = "trapv1",
-			[SNMP_PDU_BULK] = "bulk",
-			[SNMP_PDU_INFORM] = "inform",
-			[SNMP_PDU_TRAP2] = "trapv2"
-		};
-
-		if (pdutype > SNMP_PDU_TRAP2)
-			printk(KERN_DEBUG "bsalg: bad pdu type %u\n", pdutype);
-		else
-			printk(KERN_DEBUG "bsalg: pdu: %s\n", pdus[pdutype]);
-	}
-	if (pdutype != SNMP_PDU_RESPONSE &&
-	    pdutype != SNMP_PDU_TRAP1 && pdutype != SNMP_PDU_TRAP2)
-		return 1;
-
-	/*
-	 * Request header or v1 trap
-	 */
-	if (pdutype == SNMP_PDU_TRAP1) {
-		struct snmp_v1_trap trap;
-		unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check);
-
-		if (ret) {
-			kfree(trap.id);
-			kfree((unsigned long *)trap.ip_address);
-		} else
-			return ret;
-
-	} else {
-		struct snmp_request req;
-
-		if (!snmp_request_decode(&ctx, &req))
-			return 0;
-
-		if (debug > 1)
-			printk(KERN_DEBUG "bsalg: request: id=0x%lx error_status=%u "
-			"error_index=%u\n", req.id, req.error_status,
-			req.error_index);
-	}
-
-	/*
-	 * Loop through objects, look for IP addresses to mangle.
-	 */
-	if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag))
-		return 0;
-
-	if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
-		return 0;
-
-	obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC);
-	if (obj == NULL) {
-		if (net_ratelimit())
-			printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__);
-		return 0;
-	}
-
-	while (!asn1_eoc_decode(&ctx, eoc)) {
-		unsigned int i;
-
-		if (!snmp_object_decode(&ctx, obj)) {
-			if (*obj) {
-				kfree((*obj)->id);
-				kfree(*obj);
-			}
-			kfree(obj);
-			return 0;
-		}
-
-		if (debug > 1) {
-			printk(KERN_DEBUG "bsalg: object: ");
-			for (i = 0; i < (*obj)->id_len; i++) {
-				if (i > 0)
-					printk(".");
-				printk("%lu", (*obj)->id[i]);
-			}
-			printk(": type=%u\n", (*obj)->type);
-
-		}
-
-		if ((*obj)->type == SNMP_IPADDR)
-			mangle_address(ctx.begin, ctx.pointer - 4 , map, check);
-
-		kfree((*obj)->id);
-		kfree(*obj);
-	}
-	kfree(obj);
-
-	if (!asn1_eoc_decode(&ctx, eoc))
-		return 0;
-
-	return 1;
-}
-
-/*****************************************************************************
- *
- * NAT routines.
- *
- *****************************************************************************/
-
-/*
- * SNMP translation routine.
- */
-static int snmp_translate(struct ip_conntrack *ct,
-			  enum ip_conntrack_info ctinfo,
-			  struct sk_buff **pskb)
-{
-	struct iphdr *iph = (*pskb)->nh.iph;
-	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);
-	struct oct1_map map;
-
-	/*
-	 * Determine mappping for application layer addresses based
-	 * on NAT manipulations for the packet.
-	 */
-	if (dir == IP_CT_DIR_ORIGINAL) {
-		/* SNAT traps */
-		map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip);
-		map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip);
-	} else {
-		/* DNAT replies */
-		map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
-		map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip);
-	}
-
-	if (map.from == map.to)
-		return NF_ACCEPT;
-
-	if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr),
-			       paylen, &map, &udph->check)) {
-		if (net_ratelimit())
-			printk(KERN_WARNING "bsalg: parser failed\n");
-		return NF_DROP;
-	}
-	return NF_ACCEPT;
-}
-
-/* We don't actually set up expectations, just adjust internal IP
- * addresses if this is being NATted */
-static int help(struct sk_buff **pskb,
-		struct ip_conntrack *ct,
-		enum ip_conntrack_info ctinfo)
-{
-	int dir = CTINFO2DIR(ctinfo);
-	unsigned int ret;
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
-
-	/* SNMP replies and originating SNMP traps get mangled */
-	if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY)
-		return NF_ACCEPT;
-	if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL)
-		return NF_ACCEPT;
-
-	/* No NAT? */
-	if (!(ct->status & IPS_NAT_MASK))
-		return NF_ACCEPT;
-
-	/*
-	 * Make sure the packet length is ok.  So far, we were only guaranteed
-	 * to have a valid length IP header plus 8 bytes, which means we have
-	 * enough room for a UDP header.  Just verify the UDP length field so we
-	 * can mess around with the payload.
-	 */
-	if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) {
-		 if (net_ratelimit())
-			 printk(KERN_WARNING "SNMP: dropping malformed packet "
-				"src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
-				NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
-		 return NF_DROP;
-	}
-
-	if (!skb_make_writable(pskb, (*pskb)->len))
-		return NF_DROP;
-
-	spin_lock_bh(&snmp_lock);
-	ret = snmp_translate(ct, ctinfo, pskb);
-	spin_unlock_bh(&snmp_lock);
-	return ret;
-}
-
-static struct ip_conntrack_helper snmp_helper = {
-	.max_expected = 0,
-	.timeout = 180,
-	.me = THIS_MODULE,
-	.help = help,
-	.name = "snmp",
-
-	.tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_PORT)}}},
-		  .dst = {.protonum = IPPROTO_UDP},
-	},
-	.mask = {.src = {.u = {0xFFFF}},
-		 .dst = {.protonum = 0xFF},
-	},
-};
-
-static struct ip_conntrack_helper snmp_trap_helper = {
-	.max_expected = 0,
-	.timeout = 180,
-	.me = THIS_MODULE,
-	.help = help,
-	.name = "snmp_trap",
-
-	.tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}},
-		  .dst = {.protonum = IPPROTO_UDP},
-	},
-	.mask = {.src = {.u = {0xFFFF}},
-		 .dst = {.protonum = 0xFF},
-	},
-};
-
-/*****************************************************************************
- *
- * Module stuff.
- *
- *****************************************************************************/
-
-static int __init ip_nat_snmp_basic_init(void)
-{
-	int ret = 0;
-
-	ret = ip_conntrack_helper_register(&snmp_helper);
-	if (ret < 0)
-		return ret;
-	ret = ip_conntrack_helper_register(&snmp_trap_helper);
-	if (ret < 0) {
-		ip_conntrack_helper_unregister(&snmp_helper);
-		return ret;
-	}
-	return ret;
-}
-
-static void __exit ip_nat_snmp_basic_fini(void)
-{
-	ip_conntrack_helper_unregister(&snmp_helper);
-	ip_conntrack_helper_unregister(&snmp_trap_helper);
-}
-
-module_init(ip_nat_snmp_basic_init);
-module_exit(ip_nat_snmp_basic_fini);
-
-module_param(debug, int, 0600);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
deleted file mode 100644
index 6bcfdf6..0000000
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/* This file contains all the functions required for the standalone
-   ip_nat module.
-
-   These are not required by the compatibility layer.
-*/
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@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.
- */
-
-/*
- * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
- * 	- new API and handling of conntrack/nat helpers
- * 	- now capable of multiple expectations for one master
- * */
-
-#include <linux/types.h>
-#include <linux/icmp.h>
-#include <linux/ip.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/proc_fs.h>
-#include <net/ip.h>
-#include <net/checksum.h>
-#include <linux/spinlock.h>
-
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.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/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-#ifdef CONFIG_XFRM
-static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
-{
-	struct ip_conntrack *ct;
-	struct ip_conntrack_tuple *t;
-	enum ip_conntrack_info ctinfo;
-	enum ip_conntrack_dir dir;
-	unsigned long statusbit;
-
-	ct = ip_conntrack_get(skb, &ctinfo);
-	if (ct == NULL)
-		return;
-	dir = CTINFO2DIR(ctinfo);
-	t = &ct->tuplehash[dir].tuple;
-
-	if (dir == IP_CT_DIR_ORIGINAL)
-		statusbit = IPS_DST_NAT;
-	else
-		statusbit = IPS_SRC_NAT;
-
-	if (ct->status & statusbit) {
-		fl->fl4_dst = t->dst.ip;
-		if (t->dst.protonum == IPPROTO_TCP ||
-		    t->dst.protonum == IPPROTO_UDP)
-			fl->fl_ip_dport = t->dst.u.tcp.port;
-	}
-
-	statusbit ^= IPS_NAT_MASK;
-
-	if (ct->status & statusbit) {
-		fl->fl4_src = t->src.ip;
-		if (t->dst.protonum == IPPROTO_TCP ||
-		    t->dst.protonum == IPPROTO_UDP)
-			fl->fl_ip_sport = t->src.u.tcp.port;
-	}
-}
-#endif
-
-static unsigned int
-ip_nat_fn(unsigned int hooknum,
-	  struct sk_buff **pskb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  int (*okfn)(struct sk_buff *))
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	struct ip_nat_info *info;
-	/* maniptype == SRC for postrouting. */
-	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
-
-	/* We never see fragments: conntrack defrags on pre-routing
-	   and local-out, and ip_nat_out protects post-routing. */
-	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
-		       & htons(IP_MF|IP_OFFSET)));
-
-	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
-	   packet filter it out, or implement conntrack/NAT for that
-	   protocol. 8) --RR */
-	if (!ct) {
-		/* Exception: ICMP redirect to new connection (not in
-		   hash table yet).  We must not let this through, in
-		   case we're doing NAT to the same network. */
-		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
-			struct icmphdr _hdr, *hp;
-
-			hp = skb_header_pointer(*pskb,
-						(*pskb)->nh.iph->ihl*4,
-						sizeof(_hdr), &_hdr);
-			if (hp != NULL &&
-			    hp->type == ICMP_REDIRECT)
-				return NF_DROP;
-		}
-		return NF_ACCEPT;
-	}
-
-	/* Don't try to NAT if this packet is not conntracked */
-	if (ct == &ip_conntrack_untracked)
-		return NF_ACCEPT;
-
-	switch (ctinfo) {
-	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(ct, ctinfo,
-							   hooknum, pskb))
-				return NF_DROP;
-			else
-				return NF_ACCEPT;
-		}
-		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
-	case IP_CT_NEW:
-		info = &ct->nat.info;
-
-		/* Seen it before?  This can happen for loopback, retrans,
-		   or local packets.. */
-		if (!ip_nat_initialized(ct, maniptype)) {
-			unsigned int ret;
-
-			if (unlikely(is_confirmed(ct)))
-				/* NAT module was loaded late */
-				ret = alloc_null_binding_confirmed(ct, info,
-								   hooknum);
-			else if (hooknum == NF_IP_LOCAL_IN)
-				/* LOCAL_IN hook doesn't have a chain!  */
-				ret = alloc_null_binding(ct, info, hooknum);
-			else
-				ret = ip_nat_rule_find(pskb, hooknum,
-						       in, out, ct,
-						       info);
-
-			if (ret != NF_ACCEPT) {
-				return ret;
-			}
-		} else
-			DEBUGP("Already setup manip %s for ct %p\n",
-			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
-			       ct);
-		break;
-
-	default:
-		/* ESTABLISHED */
-		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
-			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
-		info = &ct->nat.info;
-	}
-
-	IP_NF_ASSERT(info);
-	return ip_nat_packet(ct, ctinfo, hooknum, pskb);
-}
-
-static unsigned int
-ip_nat_in(unsigned int hooknum,
-	  struct sk_buff **pskb,
-	  const struct net_device *in,
-	  const struct net_device *out,
-	  int (*okfn)(struct sk_buff *))
-{
-	unsigned int ret;
-	__be32 daddr = (*pskb)->nh.iph->daddr;
-
-	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
-	if (ret != NF_DROP && ret != NF_STOLEN
-	    && daddr != (*pskb)->nh.iph->daddr) {
-		dst_release((*pskb)->dst);
-		(*pskb)->dst = NULL;
-	}
-	return ret;
-}
-
-static unsigned int
-ip_nat_out(unsigned int hooknum,
-	   struct sk_buff **pskb,
-	   const struct net_device *in,
-	   const struct net_device *out,
-	   int (*okfn)(struct sk_buff *))
-{
-#ifdef CONFIG_XFRM
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-#endif
-	unsigned int ret;
-
-	/* root is playing with raw sockets. */
-	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
-		return NF_ACCEPT;
-
-	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
-#ifdef CONFIG_XFRM
-	if (ret != NF_DROP && ret != NF_STOLEN
-	    && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
-		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-
-		if (ct->tuplehash[dir].tuple.src.ip !=
-		    ct->tuplehash[!dir].tuple.dst.ip
-		    || ct->tuplehash[dir].tuple.src.u.all !=
-		       ct->tuplehash[!dir].tuple.dst.u.all
-		    )
-			return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP;
-	}
-#endif
-	return ret;
-}
-
-static unsigned int
-ip_nat_local_fn(unsigned int hooknum,
-		struct sk_buff **pskb,
-		const struct net_device *in,
-		const struct net_device *out,
-		int (*okfn)(struct sk_buff *))
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	unsigned int ret;
-
-	/* root is playing with raw sockets. */
-	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
-		return NF_ACCEPT;
-
-	ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
-	if (ret != NF_DROP && ret != NF_STOLEN
-	    && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
-		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-
-		if (ct->tuplehash[dir].tuple.dst.ip !=
-		    ct->tuplehash[!dir].tuple.src.ip) {
-			if (ip_route_me_harder(pskb, RTN_UNSPEC))
-				ret = NF_DROP;
-		}
-#ifdef CONFIG_XFRM
-		else if (ct->tuplehash[dir].tuple.dst.u.all !=
-			 ct->tuplehash[!dir].tuple.src.u.all)
-			if (ip_xfrm_me_harder(pskb))
-				ret = NF_DROP;
-#endif
-
-	}
-	return ret;
-}
-
-static unsigned int
-ip_nat_adjust(unsigned int hooknum,
-	      struct sk_buff **pskb,
-	      const struct net_device *in,
-	      const struct net_device *out,
-	      int (*okfn)(struct sk_buff *))
-{
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-	if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
-		DEBUGP("ip_nat_standalone: adjusting sequence number\n");
-		if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
-			return NF_DROP;
-	}
-	return NF_ACCEPT;
-}
-
-/* We must be after connection tracking and before packet filtering. */
-
-static struct nf_hook_ops ip_nat_ops[] = {
-	/* Before packet filtering, change destination */
-	{
-		.hook		= ip_nat_in,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_PRE_ROUTING,
-		.priority	= NF_IP_PRI_NAT_DST,
-	},
-	/* After packet filtering, change source */
-	{
-		.hook		= ip_nat_out,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_POST_ROUTING,
-		.priority	= NF_IP_PRI_NAT_SRC,
-	},
-	/* After conntrack, adjust sequence number */
-	{
-		.hook		= ip_nat_adjust,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_POST_ROUTING,
-		.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
-	},
-	/* Before packet filtering, change destination */
-	{
-		.hook		= ip_nat_local_fn,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_OUT,
-		.priority	= NF_IP_PRI_NAT_DST,
-	},
-	/* After packet filtering, change source */
-	{
-		.hook		= ip_nat_fn,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_IN,
-		.priority	= NF_IP_PRI_NAT_SRC,
-	},
-	/* After conntrack, adjust sequence number */
-	{
-		.hook		= ip_nat_adjust,
-		.owner		= THIS_MODULE,
-		.pf		= PF_INET,
-		.hooknum	= NF_IP_LOCAL_IN,
-		.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
-	},
-};
-
-static int __init ip_nat_standalone_init(void)
-{
-	int ret = 0;
-
-	need_conntrack();
-
-#ifdef CONFIG_XFRM
-	BUG_ON(ip_nat_decode_session != NULL);
-	ip_nat_decode_session = nat_decode_session;
-#endif
-	ret = ip_nat_rule_init();
-	if (ret < 0) {
-		printk("ip_nat_init: can't setup rules.\n");
-		goto cleanup_decode_session;
-	}
-	ret = nf_register_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
-	if (ret < 0) {
-		printk("ip_nat_init: can't register hooks.\n");
-		goto cleanup_rule_init;
-	}
-	return ret;
-
- cleanup_rule_init:
-	ip_nat_rule_cleanup();
- cleanup_decode_session:
-#ifdef CONFIG_XFRM
-	ip_nat_decode_session = NULL;
-	synchronize_net();
-#endif
-	return ret;
-}
-
-static void __exit ip_nat_standalone_fini(void)
-{
-	nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
-	ip_nat_rule_cleanup();
-#ifdef CONFIG_XFRM
-	ip_nat_decode_session = NULL;
-	synchronize_net();
-#endif
-}
-
-module_init(ip_nat_standalone_init);
-module_exit(ip_nat_standalone_fini);
-
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c
deleted file mode 100644
index 6047935..0000000
--- a/net/ipv4/netfilter/ip_nat_tftp.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Version: 0.0.7
- *
- * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
- * 	- Port to newnat API
- *
- * This module currently supports DNAT:
- * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y
- *
- * and SNAT:
- * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x }
- *
- * It has not been tested with
- * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip
- * If you do test this please let me know if it works or not.
- *
- */
-
-#include <linux/module.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
-#include <linux/netfilter_ipv4/ip_nat_helper.h>
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#include <linux/moduleparam.h>
-
-MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
-MODULE_DESCRIPTION("tftp NAT helper");
-MODULE_LICENSE("GPL");
-
-static unsigned int help(struct sk_buff **pskb,
-			 enum ip_conntrack_info ctinfo,
-			 struct ip_conntrack_expect *exp)
-{
-	struct ip_conntrack *ct = exp->master;
-
-	exp->saved_proto.udp.port
-		= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
-	exp->dir = IP_CT_DIR_REPLY;
-	exp->expectfn = ip_nat_follow_master;
-	if (ip_conntrack_expect_related(exp) != 0)
-		return NF_DROP;
-	return NF_ACCEPT;
-}
-
-static void __exit ip_nat_tftp_fini(void)
-{
-	rcu_assign_pointer(ip_nat_tftp_hook, NULL);
-	synchronize_rcu();
-}
-
-static int __init ip_nat_tftp_init(void)
-{
-	BUG_ON(rcu_dereference(ip_nat_tftp_hook));
-	rcu_assign_pointer(ip_nat_tftp_hook, help);
-	return 0;
-}
-
-module_init(ip_nat_tftp_init);
-module_exit(ip_nat_tftp_fini);
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index a14798a..702d94d 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -8,18 +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.
- *
- * 2000-03-27: Simplified code (thanks to Andi Kleen for clues).
- * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report).
- * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian
- *             Zander).
- * 2000-08-01: Added Nick Williams' MAC support.
- * 2002-06-25: Code cleanup.
- * 2005-01-10: Added /proc counter for dropped packets; fixed so
- *             packets aren't delivered to user space if they're going
- *             to be dropped.
- * 2005-05-26: local_bh_{disable,enable} around nf_reinject (Harald Welte)
- *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -191,12 +179,13 @@ ipq_flush(int verdict)
 static struct sk_buff *
 ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
 {
-	unsigned char *old_tail;
+	sk_buff_data_t old_tail;
 	size_t size = 0;
 	size_t data_len = 0;
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -234,15 +223,16 @@ ipq_build_packet_message(struct ipq_queu
 	if (!skb)
 		goto nlmsg_failure;
 
-	old_tail= skb->tail;
+	old_tail = skb->tail;
 	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
 	pmsg = NLMSG_DATA(nlh);
 	memset(pmsg, 0, sizeof(*pmsg));
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
@@ -378,7 +368,7 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, st
 	}
 	if (!skb_make_writable(&e->skb, v->data_len))
 		return -ENOMEM;
-	memcpy(e->skb->data, v->payload, v->data_len);
+	skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
 	e->skb->ip_summed = CHECKSUM_NONE;
 
 	return 0;
@@ -495,7 +485,7 @@ ipq_rcv_skb(struct sk_buff *skb)
 	if (skblen < sizeof(*nlh))
 		return;
 
-	nlh = (struct nlmsghdr *)skb->data;
+	nlh = nlmsg_hdr(skb);
 	nlmsglen = nlh->nlmsg_len;
 	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
 		return;
@@ -678,7 +668,7 @@ static int __init ip_queue_init(void)
 
 	netlink_register_notifier(&ipq_nl_notifier);
 	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk,
-				      THIS_MODULE);
+				      NULL, THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
 		goto cleanup_netlink_notifier;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 50cc4b9..e3f83bf 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -7,12 +7,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.
- *
- * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
- * 	- increase module usage count as soon as we have rules inside
- * 	  a table
- * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
- * 	- Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
  */
 #include <linux/cache.h>
 #include <linux/capability.h>
@@ -198,7 +192,7 @@ int do_match(struct ipt_entry_match *m,
 {
 	/* Stop iteration if it doesn't match */
 	if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
-				      offset, skb->nh.iph->ihl*4, hotdrop))
+				      offset, ip_hdrlen(skb), hotdrop))
 		return 1;
 	else
 		return 0;
@@ -231,7 +225,7 @@ ipt_do_table(struct sk_buff **pskb,
 	struct xt_table_info *private;
 
 	/* Initialization */
-	ip = (*pskb)->nh.iph;
+	ip = ip_hdr(*pskb);
 	datalen = (*pskb)->len - ip->ihl * 4;
 	indev = in ? in->name : nulldevname;
 	outdev = out ? out->name : nulldevname;
@@ -320,7 +314,7 @@ #ifdef CONFIG_NETFILTER_DEBUG
 					= 0x57acc001;
 #endif
 				/* Target might have changed stuff. */
-				ip = (*pskb)->nh.iph;
+				ip = ip_hdr(*pskb);
 				datalen = (*pskb)->len - ip->ihl * 4;
 
 				if (verdict == IPT_CONTINUE)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 42b0802..40e2734 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -21,15 +21,12 @@ #include <linux/icmp.h>
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-
-#include <net/checksum.h>
-
 #include <linux/netfilter_arp.h>
-
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
-#include <net/netfilter/nf_conntrack_compat.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/checksum.h>
 
 #define CLUSTERIP_VERSION "0.8"
 
@@ -240,7 +237,7 @@ #endif
 static inline u_int32_t
 clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
 {
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	unsigned long hashval;
 	u_int16_t sport, dport;
 	u_int16_t *ports;
@@ -310,15 +307,16 @@ target(struct sk_buff **pskb,
        const void *targinfo)
 {
 	const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
-	u_int32_t *mark, hash;
+	u_int32_t hash;
 
 	/* don't need to clusterip_config_get() here, since refcount
 	 * is only decremented by destroy() - and ip_tables guarantees
 	 * that the ->target() function isn't called after ->destroy() */
 
-	mark = nf_ct_get_mark((*pskb), &ctinfo);
-	if (mark == NULL) {
+	ct = nf_ct_get(*pskb, &ctinfo);
+	if (ct == NULL) {
 		printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
 			/* FIXME: need to drop invalid ones, since replies
 			 * to outgoing connections of other nodes will be
@@ -328,7 +326,7 @@ target(struct sk_buff **pskb,
 
 	/* special case: ICMP error handling. conntrack distinguishes between
 	 * error messages (RELATED) and information requests (see below) */
-	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
+	if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP
 	    && (ctinfo == IP_CT_RELATED
 		|| ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY))
 		return XT_CONTINUE;
@@ -341,7 +339,7 @@ target(struct sk_buff **pskb,
 
 	switch (ctinfo) {
 		case IP_CT_NEW:
-			*mark = hash;
+			ct->mark = hash;
 			break;
 		case IP_CT_RELATED:
 		case IP_CT_RELATED+IP_CT_IS_REPLY:
@@ -358,7 +356,7 @@ target(struct sk_buff **pskb,
 #ifdef DEBUG_CLUSTERP
 	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 #endif
-	DEBUGP("hash=%u ct_hash=%u ", hash, *mark);
+	DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
 	if (!clusterip_responsible(cipinfo->config, hash)) {
 		DEBUGP("not responsible\n");
 		return NF_DROP;
@@ -521,7 +519,7 @@ arp_mangle(unsigned int hook,
 	   const struct net_device *out,
 	   int (*okfn)(struct sk_buff *))
 {
-	struct arphdr *arp = (*pskb)->nh.arph;
+	struct arphdr *arp = arp_hdr(*pskb);
 	struct arp_payload *payload;
 	struct clusterip_config *c;
 
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 4f56563..918ca92 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -5,14 +5,13 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp
 */
 
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
 
@@ -29,13 +28,13 @@ MODULE_DESCRIPTION("iptables ECN modific
 static inline int
 set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 
 	if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
 		__u8 oldtos;
 		if (!skb_make_writable(pskb, sizeof(struct iphdr)))
 			return 0;
-		iph = (*pskb)->nh.iph;
+		iph = ip_hdr(*pskb);
 		oldtos = iph->tos;
 		iph->tos &= ~IPT_ECN_IP_MASK;
 		iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
@@ -52,7 +51,7 @@ set_ect_tcp(struct sk_buff **pskb, const
 	__be16 oldval;
 
 	/* Not enought header? */
-	tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
+	tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
 				  sizeof(_tcph), &_tcph);
 	if (!tcph)
 		return 0;
@@ -63,9 +62,9 @@ set_ect_tcp(struct sk_buff **pskb, const
 	     tcph->cwr == einfo->proto.tcp.cwr)))
 		return 1;
 
-	if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+	if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
 		return 0;
-	tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4;
+	tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb);
 
 	oldval = ((__be16 *)tcph)[6];
 	if (einfo->operation & IPT_ECN_OP_SET_ECE)
@@ -93,7 +92,7 @@ target(struct sk_buff **pskb,
 			return NF_DROP;
 
 	if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
-	    && (*pskb)->nh.iph->protocol == IPPROTO_TCP)
+	    && ip_hdr(*pskb)->protocol == IPPROTO_TCP)
 		if (!set_ect_tcp(pskb, einfo))
 			return NF_DROP;
 
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index d9c37fd..a42c5cd 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -399,9 +399,9 @@ #endif
 		/* MAC logging for input chain only. */
 		printk("MAC=");
 		if (skb->dev && skb->dev->hard_header_len
-		    && skb->mac.raw != (void*)skb->nh.iph) {
+		    && skb->mac_header != skb->network_header) {
 			int i;
-			unsigned char *p = skb->mac.raw;
+			const unsigned char *p = skb_mac_header(skb);
 			for (i = 0; i < skb->dev->hard_header_len; i++,p++)
 				printk("%02x%c", *p,
 				       i==skb->dev->hard_header_len - 1
@@ -477,14 +477,10 @@ static int __init ipt_log_init(void)
 	ret = xt_register_target(&ipt_log_reg);
 	if (ret < 0)
 		return ret;
-	if (nf_log_register(PF_INET, &ipt_log_logger) < 0) {
-		printk(KERN_WARNING "ipt_LOG: not logging via system console "
-		       "since somebody else already registered for PF_INET\n");
-		/* we cannot make module load fail here, since otherwise
-		 * iptables userspace would abort */
-	}
-
-	return 0;
+	ret = nf_log_register(PF_INET, &ipt_log_logger);
+	if (ret < 0 && ret != -EEXIST)
+		xt_unregister_target(&ipt_log_reg);
+	return ret;
 }
 
 static void __exit ipt_log_fini(void)
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index b5955f3..d4f2d77 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -19,12 +19,8 @@ #include <net/protocol.h>
 #include <net/ip.h>
 #include <net/checksum.h>
 #include <net/route.h>
-#include <linux/netfilter_ipv4.h>
-#ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
-#else
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#endif
+#include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
@@ -48,7 +44,7 @@ masquerade_check(const char *tablename,
 		 void *targinfo,
 		 unsigned int hook_mask)
 {
-	const struct ip_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = targinfo;
 
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		DEBUGP("masquerade_check: bad MAP_IPS.\n");
@@ -69,33 +65,26 @@ masquerade_target(struct sk_buff **pskb,
 		  const struct xt_target *target,
 		  const void *targinfo)
 {
-#ifdef CONFIG_NF_NAT_NEEDED
+	struct nf_conn *ct;
 	struct nf_conn_nat *nat;
-#endif
-	struct ip_conntrack *ct;
 	enum ip_conntrack_info ctinfo;
-	struct ip_nat_range newrange;
-	const struct ip_nat_multi_range_compat *mr;
+	struct nf_nat_range newrange;
+	const struct nf_nat_multi_range_compat *mr;
 	struct rtable *rt;
 	__be32 newsrc;
 
-	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+	NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
 
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-#ifdef CONFIG_NF_NAT_NEEDED
+	ct = nf_ct_get(*pskb, &ctinfo);
 	nat = nfct_nat(ct);
-#endif
-	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+
+	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
 			    || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
 
 	/* Source address is 0.0.0.0 - locally generated packet that is
 	 * probably not supposed to be masqueraded.
 	 */
-#ifdef CONFIG_NF_NAT_NEEDED
 	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
-#else
-	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0)
-#endif
 		return NF_ACCEPT;
 
 	mr = targinfo;
@@ -107,40 +96,30 @@ #endif
 	}
 
 	write_lock_bh(&masq_lock);
-#ifdef CONFIG_NF_NAT_NEEDED
 	nat->masq_index = out->ifindex;
-#else
-	ct->nat.masq_index = out->ifindex;
-#endif
 	write_unlock_bh(&masq_lock);
 
 	/* Transfer from original range. */
-	newrange = ((struct ip_nat_range)
+	newrange = ((struct nf_nat_range)
 		{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 		  newsrc, newsrc,
 		  mr->range[0].min, mr->range[0].max });
 
 	/* Hand modified range to generic setup. */
-	return ip_nat_setup_info(ct, &newrange, hooknum);
+	return nf_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static inline int
-device_cmp(struct ip_conntrack *i, void *ifindex)
+device_cmp(struct nf_conn *i, void *ifindex)
 {
-	int ret;
-#ifdef CONFIG_NF_NAT_NEEDED
 	struct nf_conn_nat *nat = nfct_nat(i);
+	int ret;
 
 	if (!nat)
 		return 0;
-#endif
 
 	read_lock_bh(&masq_lock);
-#ifdef CONFIG_NF_NAT_NEEDED
 	ret = (nat->masq_index == (int)(long)ifindex);
-#else
-	ret = (i->nat.masq_index == (int)(long)ifindex);
-#endif
 	read_unlock_bh(&masq_lock);
 
 	return ret;
@@ -156,9 +135,9 @@ static int masq_device_event(struct noti
 		/* Device was downed.  Search entire table for
 		   conntracks which were associated with that device,
 		   and forget them. */
-		IP_NF_ASSERT(dev->ifindex != 0);
+		NF_CT_ASSERT(dev->ifindex != 0);
 
-		ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
+		nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
 	}
 
 	return NOTIFY_DONE;
@@ -174,9 +153,9 @@ static int masq_inet_event(struct notifi
 		/* IP address was deleted.  Search entire table for
 		   conntracks which were associated with that device,
 		   and forget them. */
-		IP_NF_ASSERT(dev->ifindex != 0);
+		NF_CT_ASSERT(dev->ifindex != 0);
 
-		ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
+		nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
 	}
 
 	return NOTIFY_DONE;
@@ -194,7 +173,7 @@ static struct xt_target masquerade = {
 	.name		= "MASQUERADE",
 	.family		= AF_INET,
 	.target		= masquerade_target,
-	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
 	.hooks		= 1 << NF_IP_POST_ROUTING,
 	.checkentry	= masquerade_check,
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index fd7aaa3..068c69b 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -16,11 +16,7 @@ #include <linux/netdevice.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
-#ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
-#else
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#endif
 
 #define MODULENAME "NETMAP"
 MODULE_LICENSE("GPL");
@@ -40,7 +36,7 @@ check(const char *tablename,
       void *targinfo,
       unsigned int hook_mask)
 {
-	const struct ip_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = targinfo;
 
 	if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
 		DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
@@ -61,39 +57,39 @@ target(struct sk_buff **pskb,
        const struct xt_target *target,
        const void *targinfo)
 {
-	struct ip_conntrack *ct;
+	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	__be32 new_ip, netmask;
-	const struct ip_nat_multi_range_compat *mr = targinfo;
-	struct ip_nat_range newrange;
+	const struct nf_nat_multi_range_compat *mr = targinfo;
+	struct nf_nat_range newrange;
 
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
+	NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
 		     || hooknum == NF_IP_POST_ROUTING
 		     || hooknum == NF_IP_LOCAL_OUT);
-	ct = ip_conntrack_get(*pskb, &ctinfo);
+	ct = nf_ct_get(*pskb, &ctinfo);
 
 	netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
 
 	if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT)
-		new_ip = (*pskb)->nh.iph->daddr & ~netmask;
+		new_ip = ip_hdr(*pskb)->daddr & ~netmask;
 	else
-		new_ip = (*pskb)->nh.iph->saddr & ~netmask;
+		new_ip = ip_hdr(*pskb)->saddr & ~netmask;
 	new_ip |= mr->range[0].min_ip & netmask;
 
-	newrange = ((struct ip_nat_range)
+	newrange = ((struct nf_nat_range)
 		{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 		  new_ip, new_ip,
 		  mr->range[0].min, mr->range[0].max });
 
 	/* Hand modified range to generic setup. */
-	return ip_nat_setup_info(ct, &newrange, hooknum);
+	return nf_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static struct xt_target target_module = {
 	.name 		= MODULENAME,
 	.family		= AF_INET,
 	.target 	= target,
-	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
 	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
 			  (1 << NF_IP_LOCAL_OUT),
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index c2b6b80..68cc76a 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -19,11 +19,7 @@ #include <net/protocol.h>
 #include <net/checksum.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
-#ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
-#else
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#endif
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -43,7 +39,7 @@ redirect_check(const char *tablename,
 	       void *targinfo,
 	       unsigned int hook_mask)
 {
-	const struct ip_nat_multi_range_compat *mr = targinfo;
+	const struct nf_nat_multi_range_compat *mr = targinfo;
 
 	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
 		DEBUGP("redirect_check: bad MAP_IPS.\n");
@@ -64,17 +60,17 @@ redirect_target(struct sk_buff **pskb,
 		const struct xt_target *target,
 		const void *targinfo)
 {
-	struct ip_conntrack *ct;
+	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	__be32 newdst;
-	const struct ip_nat_multi_range_compat *mr = targinfo;
-	struct ip_nat_range newrange;
+	const struct nf_nat_multi_range_compat *mr = targinfo;
+	struct nf_nat_range newrange;
 
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
+	NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
 		     || hooknum == NF_IP_LOCAL_OUT);
 
-	ct = ip_conntrack_get(*pskb, &ctinfo);
-	IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
+	ct = nf_ct_get(*pskb, &ctinfo);
+	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
 
 	/* Local packets: make them go to loopback */
 	if (hooknum == NF_IP_LOCAL_OUT)
@@ -96,20 +92,20 @@ redirect_target(struct sk_buff **pskb,
 	}
 
 	/* Transfer from original range. */
-	newrange = ((struct ip_nat_range)
+	newrange = ((struct nf_nat_range)
 		{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
 		  newdst, newdst,
 		  mr->range[0].min, mr->range[0].max });
 
 	/* Hand modified range to generic setup. */
-	return ip_nat_setup_info(ct, &newrange, hooknum);
+	return nf_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static struct xt_target redirect_reg = {
 	.name		= "REDIRECT",
 	.family		= AF_INET,
 	.target		= redirect_target,
-	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
+	.targetsize	= sizeof(struct nf_nat_multi_range_compat),
 	.table		= "nat",
 	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
 	.checkentry	= redirect_check,
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 80f739e..9041e07 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -1,7 +1,5 @@
 /*
  * This is a module which is used for rejecting packets.
- * Added support for customized reject packets (Jozsef Kadlecsik).
- * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
  */
 
 /* (C) 1999-2001 Paul `Rusty' Russell
@@ -43,7 +41,7 @@ #endif
 static void send_reset(struct sk_buff *oldskb, int hook)
 {
 	struct sk_buff *nskb;
-	struct iphdr *iph = oldskb->nh.iph;
+	struct iphdr *niph;
 	struct tcphdr _otcph, *oth, *tcph;
 	__be16 tmp_port;
 	__be32 tmp_addr;
@@ -51,10 +49,10 @@ static void send_reset(struct sk_buff *o
 	unsigned int addr_type;
 
 	/* IP header checks: fragment. */
-	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
+	if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
 		return;
 
-	oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4,
+	oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
 				 sizeof(_otcph), &_otcph);
 	if (oth == NULL)
 		return;
@@ -64,7 +62,7 @@ static void send_reset(struct sk_buff *o
 		return;
 
 	/* Check checksum */
-	if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
+	if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
 		return;
 
 	/* We need a linear, writeable skb.  We also need to expand
@@ -84,20 +82,21 @@ static void send_reset(struct sk_buff *o
 	skb_shinfo(nskb)->gso_segs = 0;
 	skb_shinfo(nskb)->gso_type = 0;
 
-	tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
+	tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
 
 	/* Swap source and dest */
-	tmp_addr = nskb->nh.iph->saddr;
-	nskb->nh.iph->saddr = nskb->nh.iph->daddr;
-	nskb->nh.iph->daddr = tmp_addr;
+	niph = ip_hdr(nskb);
+	tmp_addr = niph->saddr;
+	niph->saddr = niph->daddr;
+	niph->daddr = tmp_addr;
 	tmp_port = tcph->source;
 	tcph->source = tcph->dest;
 	tcph->dest = tmp_port;
 
 	/* Truncate to length (no data) */
 	tcph->doff = sizeof(struct tcphdr)/4;
-	skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
-	nskb->nh.iph->tot_len = htons(nskb->len);
+	skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
+	niph->tot_len = htons(nskb->len);
 
 	if (tcph->ack) {
 		needs_ack = 0;
@@ -105,9 +104,9 @@ static void send_reset(struct sk_buff *o
 		tcph->ack_seq = 0;
 	} else {
 		needs_ack = 1;
-		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin
-				      + oldskb->len - oldskb->nh.iph->ihl*4
-				      - (oth->doff<<2));
+		tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
+				      oldskb->len - ip_hdrlen(oldskb) -
+				      (oth->doff << 2));
 		tcph->seq = 0;
 	}
 
@@ -122,14 +121,13 @@ static void send_reset(struct sk_buff *o
 	/* Adjust TCP checksum */
 	tcph->check = 0;
 	tcph->check = tcp_v4_check(sizeof(struct tcphdr),
-				   nskb->nh.iph->saddr,
-				   nskb->nh.iph->daddr,
+				   niph->saddr, niph->daddr,
 				   csum_partial((char *)tcph,
 						sizeof(struct tcphdr), 0));
 
 	/* Set DF, id = 0 */
-	nskb->nh.iph->frag_off = htons(IP_DF);
-	nskb->nh.iph->id = 0;
+	niph->frag_off = htons(IP_DF);
+	niph->id = 0;
 
 	addr_type = RTN_UNSPEC;
 	if (hook != NF_IP_FORWARD
@@ -145,12 +143,11 @@ #endif
 	nskb->ip_summed = CHECKSUM_NONE;
 
 	/* Adjust IP TTL */
-	nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+	niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
 
 	/* Adjust IP checksum */
-	nskb->nh.iph->check = 0;
-	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
-					   nskb->nh.iph->ihl);
+	niph->check = 0;
+	niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
 
 	/* "Never happens" */
 	if (nskb->len > dst_mtu(nskb->dst))
@@ -182,7 +179,7 @@ static unsigned int reject(struct sk_buf
 
 	/* Our naive response construction doesn't deal with IP
 	   options, and probably shouldn't try. */
-	if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr))
+	if (ip_hdrlen(*pskb) != sizeof(struct iphdr))
 		return NF_DROP;
 
 	/* WARNING: This code causes reentry within iptables.
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index bd4404e..511e5ff 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -7,21 +7,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.
- *
- * 010320 Martin Josefsson <gandalf@wlug.westbo.se>
- * 	* copied ipt_BALANCE.c to ipt_SAME.c and changed a few things.
- * 010728 Martin Josefsson <gandalf@wlug.westbo.se>
- * 	* added --nodst to not include destination-ip in new source
- * 	  calculations.
- *	* added some more sanity-checks.
- * 010729 Martin Josefsson <gandalf@wlug.westbo.se>
- * 	* fixed a buggy if-statement in same_check(), should have
- * 	  used ntohl() but didn't.
- * 	* added support for multiple ranges. IPT_SAME_MAX_RANGE is
- * 	  defined in linux/include/linux/netfilter_ipv4/ipt_SAME.h
- * 	  and is currently set to 10.
- * 	* added support for 1-address range, nice to have now that
- * 	  we have multiple ranges.
  */
 #include <linux/types.h>
 #include <linux/ip.h>
@@ -35,11 +20,7 @@ #include <net/protocol.h>
 #include <net/checksum.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
-#ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_rule.h>
-#else
-#include <linux/netfilter_ipv4/ip_nat_rule.h>
-#endif
 #include <linux/netfilter_ipv4/ipt_SAME.h>
 
 MODULE_LICENSE("GPL");
@@ -138,17 +119,17 @@ same_target(struct sk_buff **pskb,
 		const struct xt_target *target,
 		const void *targinfo)
 {
-	struct ip_conntrack *ct;
+	struct nf_conn *ct;
 	enum ip_conntrack_info ctinfo;
 	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;
+	struct nf_nat_range newrange;
+	const struct nf_conntrack_tuple *t;
 
-	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
+	NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
 			hooknum == NF_IP_POST_ROUTING);
-	ct = ip_conntrack_get(*pskb, &ctinfo);
+	ct = nf_ct_get(*pskb, &ctinfo);
 
 	t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
 
@@ -157,17 +138,10 @@ same_target(struct sk_buff **pskb,
 	   Here we calculate the index in same->iparray which
 	   holds the ipaddress we should use */
 
-#ifdef CONFIG_NF_NAT_NEEDED
 	tmpip = ntohl(t->src.u3.ip);
 
 	if (!(same->info & IPT_SAME_NODST))
 		tmpip += ntohl(t->dst.u3.ip);
-#else
-	tmpip = ntohl(t->src.ip);
-
-	if (!(same->info & IPT_SAME_NODST))
-		tmpip += ntohl(t->dst.ip);
-#endif
 	aindex = tmpip % same->ipnum;
 
 	new_ip = htonl(same->iparray[aindex]);
@@ -178,13 +152,13 @@ #endif
 			NIPQUAD(new_ip));
 
 	/* Transfer from original range. */
-	newrange = ((struct ip_nat_range)
+	newrange = ((struct nf_nat_range)
 		{ same->range[0].flags, new_ip, new_ip,
 		  /* FIXME: Use ports from correct range! */
 		  same->range[0].min, same->range[0].max });
 
 	/* Hand modified range to generic setup. */
-	return ip_nat_setup_info(ct, &newrange, hooknum);
+	return nf_nat_setup_info(ct, &newrange, hooknum);
 }
 
 static struct xt_target same_reg = {
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index cedf9f7..0ad02f2 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -29,13 +29,13 @@ target(struct sk_buff **pskb,
        const void *targinfo)
 {
 	const struct ipt_tos_target_info *tosinfo = targinfo;
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 
 	if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
 		__u8 oldtos;
 		if (!skb_make_writable(pskb, sizeof(struct iphdr)))
 			return NF_DROP;
-		iph = (*pskb)->nh.iph;
+		iph = ip_hdr(*pskb);
 		oldtos = iph->tos;
 		iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
 		nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index 64be31c..a991ec7 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -32,7 +32,7 @@ ipt_ttl_target(struct sk_buff **pskb,
 	if (!skb_make_writable(pskb, (*pskb)->len))
 		return NF_DROP;
 
-	iph = (*pskb)->nh.iph;
+	iph = ip_hdr(*pskb);
 
 	switch (info->mode) {
 		case IPT_TTL_SET:
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 9acc018..23b607b 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -2,20 +2,6 @@
  * netfilter module for userspace packet logging daemons
  *
  * (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
- *
- * 2000/09/22 ulog-cprange feature added
- * 2001/01/04 in-kernel queue as proposed by Sebastian Zander
- * 						<zander@fokus.gmd.de>
- * 2001/01/30 per-rule nlgroup conflicts with global queue.
- *            nlgroup now global (sysctl)
- * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
- * 	      module loadtime -HW
- * 2002/07/07 remove broken nflog_rcv() function -HW
- * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
- * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
- * 2004/10/25 fix erroneous calculation of 'len' parameter to NLMSG_PUT
- *	      resulting in bogus 'error during NLMSG_PUT' messages.
- *
  * (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  *
@@ -42,8 +28,6 @@
  * flushtimeout:
  *   Specify, after how many hundredths of a second the queue should be
  *   flushed even if it is not full yet.
- *
- * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp
  */
 
 #include <linux/module.h>
@@ -187,6 +171,7 @@ static void ipt_ulog_packet(unsigned int
 	ulog_packet_msg_t *pm;
 	size_t size, copy_len;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	/* ffs == find first bit set, necessary because userspace
 	 * is already shifting groupnumber, but we need unshifted.
@@ -232,13 +217,14 @@ static void ipt_ulog_packet(unsigned int
 	pm = NLMSG_DATA(nlh);
 
 	/* We might not have a timestamp, get one */
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp((struct sk_buff *)skb);
 
 	/* copy hook, prefix, timestamp, payload, etc. */
 	pm->data_len = copy_len;
-	put_unaligned(skb->tstamp.off_sec, &pm->timestamp_sec);
-	put_unaligned(skb->tstamp.off_usec, &pm->timestamp_usec);
+	tv = ktime_to_timeval(skb->tstamp);
+	put_unaligned(tv.tv_sec, &pm->timestamp_sec);
+	put_unaligned(tv.tv_usec, &pm->timestamp_usec);
 	put_unaligned(skb->mark, &pm->mark);
 	pm->hook = hooknum;
 	if (prefix != NULL)
@@ -249,9 +235,9 @@ static void ipt_ulog_packet(unsigned int
 		*(pm->prefix) = '\0';
 
 	if (in && in->hard_header_len > 0
-	    && skb->mac.raw != (void *) skb->nh.iph
+	    && skb->mac_header != skb->network_header
 	    && in->hard_header_len <= ULOG_MAC_LEN) {
-		memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
+		memcpy(pm->mac, skb_mac_header(skb), in->hard_header_len);
 		pm->mac_len = in->hard_header_len;
 	} else
 		pm->mac_len = 0;
@@ -363,12 +349,52 @@ static int ipt_ulog_checkentry(const cha
 	return 1;
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_ipt_ulog_info {
+	compat_uint_t	nl_group;
+	compat_size_t	copy_range;
+	compat_size_t	qthreshold;
+	char		prefix[ULOG_PREFIX_LEN];
+};
+
+static void compat_from_user(void *dst, void *src)
+{
+	struct compat_ipt_ulog_info *cl = src;
+	struct ipt_ulog_info l = {
+		.nl_group	= cl->nl_group,
+		.copy_range	= cl->copy_range,
+		.qthreshold	= cl->qthreshold,
+	};
+
+	memcpy(l.prefix, cl->prefix, sizeof(l.prefix));
+	memcpy(dst, &l, sizeof(l));
+}
+
+static int compat_to_user(void __user *dst, void *src)
+{
+	struct ipt_ulog_info *l = src;
+	struct compat_ipt_ulog_info cl = {
+		.nl_group	= l->nl_group,
+		.copy_range	= l->copy_range,
+		.qthreshold	= l->qthreshold,
+	};
+
+	memcpy(cl.prefix, l->prefix, sizeof(cl.prefix));
+	return copy_to_user(dst, &cl, sizeof(cl)) ? -EFAULT : 0;
+}
+#endif /* CONFIG_COMPAT */
+
 static struct xt_target ipt_ulog_reg = {
 	.name		= "ULOG",
 	.family		= AF_INET,
 	.target		= ipt_ulog_target,
 	.targetsize	= sizeof(struct ipt_ulog_info),
 	.checkentry	= ipt_ulog_checkentry,
+#ifdef CONFIG_COMPAT
+	.compatsize	= sizeof(struct compat_ipt_ulog_info),
+	.compat_from_user = compat_from_user,
+	.compat_to_user	= compat_to_user,
+#endif
 	.me		= THIS_MODULE,
 };
 
@@ -390,14 +416,11 @@ static int __init ipt_ulog_init(void)
 	}
 
 	/* initialize ulog_buffers */
-	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
-		init_timer(&ulog_buffers[i].timer);
-		ulog_buffers[i].timer.function = ulog_timer;
-		ulog_buffers[i].timer.data = i;
-	}
+	for (i = 0; i < ULOG_MAXNLGROUPS; i++)
+		setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
 
 	nflognl = netlink_kernel_create(NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL,
-					THIS_MODULE);
+					NULL, THIS_MODULE);
 	if (!nflognl)
 		return -ENOMEM;
 
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index cfa0472..a652a14 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -33,7 +33,7 @@ static int match(const struct sk_buff *s
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_addrtype_info *info = matchinfo;
-	const struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 	int ret = 1;
 
 	if (info->source)
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index 37508b2..2621812 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -1,7 +1,5 @@
 /* IP tables module for matching the value of the IPv4 and TCP ECN bits
  *
- * ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
- *
  * (C) 2002 by Harald Welte <laforge@gnumonks.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -11,6 +9,7 @@
 
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/tcp.h>
@@ -26,7 +25,7 @@ MODULE_LICENSE("GPL");
 static inline int match_ip(const struct sk_buff *skb,
 			   const struct ipt_ecn_info *einfo)
 {
-	return ((skb->nh.iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
+	return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect;
 }
 
 static inline int match_tcp(const struct sk_buff *skb,
@@ -38,8 +37,7 @@ static inline int match_tcp(const struct
 	/* In practice, TCP match does this, so can't fail.  But let's
 	 * be good citizens.
 	 */
-	th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
-				sizeof(_tcph), &_tcph);
+	th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
 	if (th == NULL) {
 		*hotdrop = 0;
 		return 0;
@@ -80,7 +78,7 @@ static int match(const struct sk_buff *s
 			return 0;
 
 	if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
-		if (skb->nh.iph->protocol != IPPROTO_TCP)
+		if (ip_hdr(skb)->protocol != IPPROTO_TCP)
 			return 0;
 		if (!match_tcp(skb, info, hotdrop))
 			return 0;
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index bc5d5e6..33af9e9 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -32,7 +32,7 @@ match(const struct sk_buff *skb,
       int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_iprange_info *info = matchinfo;
-	const struct iphdr *iph = skb->nh.iph;
+	const struct iphdr *iph = ip_hdr(skb);
 
 	if (info->flags & IPRANGE_SRC) {
 		if (((ntohl(iph->saddr) < ntohl(info->src.min_ip))
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index aecb9c4..15a9e8b 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -183,11 +183,11 @@ ipt_recent_match(const struct sk_buff *s
 	int ret = info->invert;
 
 	if (info->side == IPT_RECENT_DEST)
-		addr = skb->nh.iph->daddr;
+		addr = ip_hdr(skb)->daddr;
 	else
-		addr = skb->nh.iph->saddr;
+		addr = ip_hdr(skb)->saddr;
 
-	ttl = skb->nh.iph->ttl;
+	ttl = ip_hdr(skb)->ttl;
 	/* use TTL as seen before forwarding */
 	if (out && !skb->sk)
 		ttl++;
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index 5d33b51..d314844 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -30,7 +30,7 @@ match(const struct sk_buff *skb,
 {
 	const struct ipt_tos_info *info = matchinfo;
 
-	return (skb->nh.iph->tos == info->tos) ^ info->invert;
+	return (ip_hdr(skb)->tos == info->tos) ^ info->invert;
 }
 
 static struct xt_match tos_match = {
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index 1eca9f4..ab02d9e 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -1,7 +1,5 @@
 /* IP tables module for matching the value of the TTL
  *
- * ipt_ttl.c,v 1.5 2000/11/13 11:16:08 laforge Exp
- *
  * (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -26,19 +24,20 @@ static int match(const struct sk_buff *s
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ipt_ttl_info *info = matchinfo;
+	const u8 ttl = ip_hdr(skb)->ttl;
 
 	switch (info->mode) {
 		case IPT_TTL_EQ:
-			return (skb->nh.iph->ttl == info->ttl);
+			return (ttl == info->ttl);
 			break;
 		case IPT_TTL_NE:
-			return (!(skb->nh.iph->ttl == info->ttl));
+			return (!(ttl == info->ttl));
 			break;
 		case IPT_TTL_LT:
-			return (skb->nh.iph->ttl < info->ttl);
+			return (ttl < info->ttl);
 			break;
 		case IPT_TTL_GT:
-			return (skb->nh.iph->ttl > info->ttl);
+			return (ttl > info->ttl);
 			break;
 		default:
 			printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index d1d61e9..4272890 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -102,7 +103,7 @@ ipt_local_out_hook(unsigned int hook,
 {
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
 			printk("ipt_hook: happy cracking.\n");
 		return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 98b66ef..9278802 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -7,8 +7,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.
- *
- * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -17,6 +15,7 @@ #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/route.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -130,13 +129,14 @@ ipt_local_hook(unsigned int hook,
 		   int (*okfn)(struct sk_buff *))
 {
 	unsigned int ret;
+	const struct iphdr *iph;
 	u_int8_t tos;
 	__be32 saddr, daddr;
 	u_int32_t mark;
 
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
 			printk("ipt_hook: happy cracking.\n");
 		return NF_ACCEPT;
@@ -144,19 +144,23 @@ ipt_local_hook(unsigned int hook,
 
 	/* Save things which could affect route */
 	mark = (*pskb)->mark;
-	saddr = (*pskb)->nh.iph->saddr;
-	daddr = (*pskb)->nh.iph->daddr;
-	tos = (*pskb)->nh.iph->tos;
+	iph = ip_hdr(*pskb);
+	saddr = iph->saddr;
+	daddr = iph->daddr;
+	tos = iph->tos;
 
 	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
-		|| (*pskb)->nh.iph->daddr != daddr
-		|| (*pskb)->mark != mark
-		|| (*pskb)->nh.iph->tos != tos))
-		if (ip_route_me_harder(pskb, RTN_UNSPEC))
-			ret = NF_DROP;
+	if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
+		iph = ip_hdr(*pskb);
+
+		if (iph->saddr != saddr ||
+		    iph->daddr != daddr ||
+		    (*pskb)->mark != mark ||
+		    iph->tos != tos)
+			if (ip_route_me_harder(pskb, RTN_UNSPEC))
+				ret = NF_DROP;
+	}
 
 	return ret;
 }
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 8f3e92d..0654eaa 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -4,14 +4,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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- move L3 protocol dependent part to this file.
- * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- add get_features() to support various size of conntrack
- *	  structures.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c
  */
 
 #include <linux/types.h>
@@ -87,7 +79,7 @@ nf_ct_ipv4_gather_frags(struct sk_buff *
 	local_bh_enable();
 
 	if (skb)
-		ip_send_check(skb->nh.iph);
+		ip_send_check(ip_hdr(skb));
 
 	return skb;
 }
@@ -97,16 +89,16 @@ ipv4_prepare(struct sk_buff **pskb, unsi
 	     u_int8_t *protonum)
 {
 	/* Never happen */
-	if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
+	if (ip_hdr(*pskb)->frag_off & htons(IP_OFFSET)) {
 		if (net_ratelimit()) {
 			printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
-			(*pskb)->nh.iph->protocol, hooknum);
+			ip_hdr(*pskb)->protocol, hooknum);
 		}
 		return -NF_DROP;
 	}
 
-	*dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4;
-	*protonum = (*pskb)->nh.iph->protocol;
+	*dataoff = skb_network_offset(*pskb) + ip_hdrlen(*pskb);
+	*protonum = ip_hdr(*pskb)->protocol;
 
 	return NF_ACCEPT;
 }
@@ -152,9 +144,8 @@ static unsigned int ipv4_conntrack_help(
 		return NF_ACCEPT;
 
 	return help->helper->help(pskb,
-			       (*pskb)->nh.raw - (*pskb)->data
-					       + (*pskb)->nh.iph->ihl*4,
-			       ct, ctinfo);
+				  skb_network_offset(*pskb) + ip_hdrlen(*pskb),
+				  ct, ctinfo);
 }
 
 static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
@@ -171,7 +162,7 @@ #if !defined(CONFIG_IP_NF_NAT) && !defin
 #endif
 
 	/* Gather fragments. */
-	if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+	if (ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 		*pskb = nf_ct_ipv4_gather_frags(*pskb,
 						hooknum == NF_IP_PRE_ROUTING ?
 						IP_DEFRAG_CONNTRACK_IN :
@@ -199,7 +190,7 @@ static unsigned int ipv4_conntrack_local
 {
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
 			printk("ipt_hook: happy cracking.\n");
 		return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 5fd1e53..f4fc657 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -4,11 +4,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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- enable working with Layer 3 protocol independent connection tracking.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_proto_icmp.c
  */
 
 #include <linux/types.h>
@@ -158,7 +153,7 @@ icmp_error_message(struct sk_buff *skb,
 	NF_CT_ASSERT(skb->nfct == NULL);
 
 	/* Not enough header? */
-	inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
+	inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in);
 	if (inside == NULL)
 		return -NF_ACCEPT;
 
@@ -172,7 +167,7 @@ icmp_error_message(struct sk_buff *skb,
 	/* rcu_read_lock()ed by nf_hook_slow */
 	innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
 
-	dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
+	dataoff = ip_hdrlen(skb) + sizeof(inside->icmp);
 	/* Are they talking about one of our connections? */
 	if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
 			     inside->ip.protocol, &origtuple,
@@ -227,7 +222,7 @@ icmp_error(struct sk_buff *skb, unsigned
 	struct icmphdr _ih, *icmph;
 
 	/* Not enough header? */
-	icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
+	icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
 	if (icmph == NULL) {
 		if (LOG_INVALID(IPPROTO_ICMP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 452e9d3..ea02f00 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -431,7 +431,7 @@ int nf_nat_icmp_reply_translation(struct
 	} *inside;
 	struct nf_conntrack_l4proto *l4proto;
 	struct nf_conntrack_tuple inner, target;
-	int hdrlen = (*pskb)->nh.iph->ihl * 4;
+	int hdrlen = ip_hdrlen(*pskb);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	unsigned long statusbit;
 	enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
@@ -439,7 +439,7 @@ int nf_nat_icmp_reply_translation(struct
 	if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
 		return 0;
 
-	inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+	inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
 
 	/* We're actually going to mangle it beyond trivial checksum
 	   adjustment, so make sure the current checksum is correct. */
@@ -469,9 +469,9 @@ int nf_nat_icmp_reply_translation(struct
 	l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
 
 	if (!nf_ct_get_tuple(*pskb,
-			     (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr),
-			     (*pskb)->nh.iph->ihl*4 +
-			     sizeof(struct icmphdr) + inside->ip.ihl*4,
+			     ip_hdrlen(*pskb) + sizeof(struct icmphdr),
+			     (ip_hdrlen(*pskb) +
+			      sizeof(struct icmphdr) + inside->ip.ihl * 4),
 			     (u_int16_t)AF_INET,
 			     inside->ip.protocol,
 			     &inner, l3proto, l4proto))
@@ -483,14 +483,14 @@ int nf_nat_icmp_reply_translation(struct
 	   packet: PREROUTING (DST manip), routing produces ICMP, goes
 	   through POSTROUTING (which must correct the DST manip). */
 	if (!manip_pkt(inside->ip.protocol, pskb,
-		       (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp),
+		       ip_hdrlen(*pskb) + sizeof(inside->icmp),
 		       &ct->tuplehash[!dir].tuple,
 		       !manip))
 		return 0;
 
 	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
 		/* Reloading "inside" here since manip_pkt inner. */
-		inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+		inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
 		inside->icmp.checksum = 0;
 		inside->icmp.checksum =
 			csum_fold(skb_checksum(*pskb, hdrlen,
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 9cbf3f9..fcebc96 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -33,7 +33,7 @@ static int set_addr(struct sk_buff **psk
 		    unsigned int addroff, __be32 ip, __be16 port)
 {
 	enum ip_conntrack_info ctinfo;
-	struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo);
+	struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo);
 	struct {
 		__be32 ip;
 		__be16 port;
@@ -44,7 +44,7 @@ static int set_addr(struct sk_buff **psk
 	buf.port = port;
 	addroff += dataoff;
 
-	if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
+	if (ip_hdr(*pskb)->protocol == IPPROTO_TCP) {
 		if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
 					      addroff, sizeof(buf),
 					      (char *) &buf, sizeof(buf))) {
@@ -55,11 +55,11 @@ static int set_addr(struct sk_buff **psk
 		}
 
 		/* Relocate data pointer */
-		th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
+		th = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
 					sizeof(_tcph), &_tcph);
 		if (th == NULL)
 			return -1;
-		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
+		*data = (*pskb)->data + ip_hdrlen(*pskb) +
 		    th->doff * 4 + dataoff;
 	} else {
 		if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
@@ -73,8 +73,8 @@ static int set_addr(struct sk_buff **psk
 		/* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
 		 * or pull everything in a linear buffer, so we can safely
 		 * use the skb pointers now */
-		*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
-		    sizeof(struct udphdr);
+		*data = ((*pskb)->data + ip_hdrlen(*pskb) +
+			 sizeof(struct udphdr));
 	}
 
 	return 0;
@@ -383,7 +383,7 @@ static int nat_h245(struct sk_buff **psk
 static void ip_nat_q931_expect(struct nf_conn *new,
 			       struct nf_conntrack_expect *this)
 {
-	struct ip_nat_range range;
+	struct nf_nat_range range;
 
 	if (this->tuple.src.u3.ip != 0) {	/* Only accept calls from GK */
 		nf_nat_follow_master(new, this);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 49a90c3..15b6e5c 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -87,12 +87,13 @@ static void mangle_contents(struct sk_bu
 	unsigned char *data;
 
 	BUG_ON(skb_is_nonlinear(skb));
-	data = (unsigned char *)skb->nh.iph + dataoff;
+	data = skb_network_header(skb) + dataoff;
 
 	/* move post-replacement */
 	memmove(data + match_offset + rep_len,
 		data + match_offset + match_len,
-		skb->tail - (data + match_offset + match_len));
+		skb->tail - (skb->network_header + dataoff +
+			     match_offset + match_len));
 
 	/* insert data from buffer */
 	memcpy(data + match_offset, rep_buffer, rep_len);
@@ -111,8 +112,8 @@ static void mangle_contents(struct sk_bu
 	}
 
 	/* fix IP hdr checksum information */
-	skb->nh.iph->tot_len = htons(skb->len);
-	ip_send_check(skb->nh.iph);
+	ip_hdr(skb)->tot_len = htons(skb->len);
+	ip_send_check(ip_hdr(skb));
 }
 
 /* Unusual, but possible case. */
@@ -152,6 +153,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff 
 			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
+	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 	struct iphdr *iph;
 	struct tcphdr *tcph;
 	int oldlen, datalen;
@@ -166,7 +168,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff 
 
 	SKB_LINEAR_ASSERT(*pskb);
 
-	iph = (*pskb)->nh.iph;
+	iph = ip_hdr(*pskb);
 	tcph = (void *)iph + iph->ihl*4;
 
 	oldlen = (*pskb)->len - iph->ihl*4;
@@ -175,11 +177,22 @@ nf_nat_mangle_tcp_packet(struct sk_buff 
 
 	datalen = (*pskb)->len - iph->ihl*4;
 	if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
-		tcph->check = 0;
-		tcph->check = tcp_v4_check(datalen,
-					   iph->saddr, iph->daddr,
-					   csum_partial((char *)tcph,
-							datalen, 0));
+		if (!(rt->rt_flags & RTCF_LOCAL) &&
+		    (*pskb)->dev->features & NETIF_F_ALL_CSUM) {
+			(*pskb)->ip_summed = CHECKSUM_PARTIAL;
+			(*pskb)->csum_start = skb_headroom(*pskb) +
+					      skb_network_offset(*pskb) +
+					      iph->ihl * 4;
+			(*pskb)->csum_offset = offsetof(struct tcphdr, check);
+			tcph->check = ~tcp_v4_check(datalen,
+						    iph->saddr, iph->daddr, 0);
+		} else {
+			tcph->check = 0;
+			tcph->check = tcp_v4_check(datalen,
+						   iph->saddr, iph->daddr,
+						   csum_partial((char *)tcph,
+								datalen, 0));
+		}
 	} else
 		nf_proto_csum_replace2(&tcph->check, *pskb,
 				       htons(oldlen), htons(datalen), 1);
@@ -190,7 +203,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff 
 				    (int)rep_len - (int)match_len,
 				    ct, ctinfo);
 		/* Tell TCP window tracking about seq change */
-		nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4,
+		nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb),
 					ct, CTINFO2DIR(ctinfo));
 	}
 	return 1;
@@ -216,12 +229,13 @@ nf_nat_mangle_udp_packet(struct sk_buff 
 			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
+	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 	struct iphdr *iph;
 	struct udphdr *udph;
 	int datalen, oldlen;
 
 	/* UDP helpers might accidentally mangle the wrong packet */
-	iph = (*pskb)->nh.iph;
+	iph = ip_hdr(*pskb);
 	if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
 			       match_offset + match_len)
 		return 0;
@@ -234,7 +248,7 @@ nf_nat_mangle_udp_packet(struct sk_buff 
 	    !enlarge_skb(pskb, rep_len - match_len))
 		return 0;
 
-	iph = (*pskb)->nh.iph;
+	iph = ip_hdr(*pskb);
 	udph = (void *)iph + iph->ihl*4;
 
 	oldlen = (*pskb)->len - iph->ihl*4;
@@ -250,13 +264,25 @@ nf_nat_mangle_udp_packet(struct sk_buff 
 		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 = CSUM_MANGLED_0;
+		if (!(rt->rt_flags & RTCF_LOCAL) &&
+		    (*pskb)->dev->features & NETIF_F_ALL_CSUM) {
+			(*pskb)->ip_summed = CHECKSUM_PARTIAL;
+			(*pskb)->csum_start = skb_headroom(*pskb) +
+					      skb_network_offset(*pskb) +
+					      iph->ihl * 4;
+			(*pskb)->csum_offset = offsetof(struct udphdr, check);
+			udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+							 datalen, IPPROTO_UDP,
+							 0);
+		} else {
+			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 = CSUM_MANGLED_0;
+		}
 	} else
 		nf_proto_csum_replace2(&udph->check, *pskb,
 				       htons(oldlen), htons(datalen), 1);
@@ -318,8 +344,8 @@ nf_nat_sack_adjust(struct sk_buff **pskb
 	unsigned int dir, optoff, optend;
 	struct nf_conn_nat *nat = nfct_nat(ct);
 
-	optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
-	optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+	optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
+	optend = ip_hdrlen(*pskb) + tcph->doff * 4;
 
 	if (!skb_make_writable(pskb, optend))
 		return 0;
@@ -371,10 +397,10 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
 	this_way = &nat->info.seq[dir];
 	other_way = &nat->info.seq[!dir];
 
-	if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+	if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
 		return 0;
 
-	tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+	tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
 	if (after(ntohl(tcph->seq), this_way->correction_pos))
 		newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
 	else
@@ -399,7 +425,7 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
 	if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
 		return 0;
 
-	nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir);
+	nf_conntrack_tcp_update(*pskb, ip_hdrlen(*pskb), ct, dir);
 
 	return 1;
 }
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 7ba341c..a668887 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -53,7 +53,7 @@ static void pptp_nat_expected(struct nf_
 	struct nf_conntrack_tuple t;
 	struct nf_ct_pptp_master *ct_pptp_info;
 	struct nf_nat_pptp *nat_pptp_info;
-	struct ip_nat_range range;
+	struct nf_nat_range range;
 
 	ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
 	nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index e5a34c1..c3908bc 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -72,6 +72,11 @@ gre_unique_tuple(struct nf_conntrack_tup
 	__be16 *keyptr;
 	unsigned int min, i, range_size;
 
+	/* If there is no master conntrack we are not PPTP,
+	   do not change tuples */
+	if (!conntrack->master)
+		return 0;
+
 	if (maniptype == IP_NAT_MANIP_SRC)
 		keyptr = &tuple->src.u.gre.key;
 	else
@@ -122,18 +127,9 @@ gre_manip_pkt(struct sk_buff **pskb, uns
 	if (maniptype != IP_NAT_MANIP_DST)
 		return 1;
 	switch (greh->version) {
-	case 0:
-		if (!greh->key) {
-			DEBUGP("can't nat GRE w/o key\n");
-			break;
-		}
-		if (greh->csum) {
-			/* FIXME: Never tested this code... */
-			nf_proto_csum_replace4(gre_csum(greh), *pskb,
-					       *(gre_key(greh)),
-					       tuple->dst.u.gre.key, 0);
-		}
-		*(gre_key(greh)) = tuple->dst.u.gre.key;
+	case GRE_VERSION_1701:
+		/* We do not currently NAT any GREv0 packets.
+		 * Try to behave like "nf_nat_proto_unknown" */
 		break;
 	case GRE_VERSION_PPTP:
 		DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 147a437..2534f71 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -191,7 +191,7 @@ static unsigned int ipt_dnat_target(stru
 
 	if (hooknum == NF_IP_LOCAL_OUT &&
 	    mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
-		warn_if_extra_mangle((*pskb)->nh.iph->daddr,
+		warn_if_extra_mangle(ip_hdr(*pskb)->daddr,
 				     mr->range[0].min_ip);
 
 	return nf_nat_setup_info(ct, &mr->range[0], hooknum);
@@ -226,10 +226,6 @@ static int ipt_dnat_checkentry(const cha
 		printk("DNAT: multiple ranges no longer supported\n");
 		return 0;
 	}
-	if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
-		printk("DNAT: port randomization not supported\n");
-		return 0;
-	}
 	return 1;
 }
 
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b12cd7c..fac97cf 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/udp.h>
 
 #include <net/netfilter/nf_nat.h>
@@ -92,7 +93,7 @@ static int map_sip_addr(struct sk_buff *
 	if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
 				      matchoff, matchlen, addr, addrlen))
 		return 0;
-	*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	*dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
 	return 1;
 
 }
@@ -106,7 +107,7 @@ static unsigned int ip_nat_sip(struct sk
 	struct addr_map map;
 	int dataoff, datalen;
 
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
 	datalen = (*pskb)->len - dataoff;
 	if (datalen < sizeof("SIP/2.0") - 1)
 		return NF_DROP;
@@ -155,7 +156,7 @@ static unsigned int mangle_sip_packet(st
 		return 0;
 
 	/* We need to reload this. Thanks Patrick. */
-	*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	*dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
 	return 1;
 }
 
@@ -168,7 +169,7 @@ static int mangle_content_len(struct sk_
 	char buffer[sizeof("65536")];
 	int bufflen;
 
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
 
 	/* Get actual SDP lenght */
 	if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff,
@@ -200,7 +201,7 @@ static unsigned int mangle_sdp(struct sk
 	char buffer[sizeof("nnn.nnn.nnn.nnn")];
 	unsigned int dataoff, bufflen;
 
-	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
 
 	/* Mangle owner and contact info. */
 	bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
@@ -221,6 +222,29 @@ static unsigned int mangle_sdp(struct sk
 	return mangle_content_len(pskb, ctinfo, ct, dptr);
 }
 
+static void ip_nat_sdp_expect(struct nf_conn *ct,
+			      struct nf_conntrack_expect *exp)
+{
+	struct nf_nat_range range;
+
+	/* This must be a fresh one. */
+	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+	/* Change src to where master sends to */
+	range.flags = IP_NAT_RANGE_MAP_IPS;
+	range.min_ip = range.max_ip
+		= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+	/* hook doesn't matter, but it has to do source manip */
+	nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+
+	/* For DST manip, map port here to where it's expected. */
+	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+	range.min = range.max = exp->saved_proto;
+	range.min_ip = range.max_ip = exp->saved_ip;
+	/* hook doesn't matter, but it has to do destination manip */
+	nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+}
+
 /* So, this packet has hit the connection tracking matching code.
    Mangle it, and change the expectation to match the new version. */
 static unsigned int ip_nat_sdp(struct sk_buff **pskb,
@@ -238,13 +262,14 @@ static unsigned int ip_nat_sdp(struct sk
 	/* Connection will come from reply */
 	newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 
+	exp->saved_ip = exp->tuple.dst.u3.ip;
 	exp->tuple.dst.u3.ip = newip;
 	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
 	exp->dir = !dir;
 
 	/* When you see the packet, we need to NAT it the same as the
 	   this one. */
-	exp->expectfn = nf_nat_follow_master;
+	exp->expectfn = ip_nat_sdp_expect;
 
 	/* Try to get same port: if not, try to change it. */
 	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index ce5c493..6e88505 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -38,10 +38,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  * Author: James Morris <jmorris@intercode.com.au>
- *
- * Updates:
- * 2000-08-06: Convert to new helper API (Harald Welte).
- *
  */
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -1194,7 +1190,7 @@ static int snmp_translate(struct nf_conn
 			  enum ip_conntrack_info ctinfo,
 			  struct sk_buff **pskb)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 	struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
 	u_int16_t udplen = ntohs(udph->len);
 	u_int16_t paylen = udplen - sizeof(struct udphdr);
@@ -1235,7 +1231,7 @@ static int help(struct sk_buff **pskb, u
 {
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int ret;
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 	struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
 
 	/* SNMP replies and originating SNMP traps get mangled */
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 15aa3db..64bbed2 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -86,8 +86,7 @@ nf_nat_fn(unsigned int hooknum,
 
 	/* We never see fragments: conntrack defrags on pre-routing
 	   and local-out, and nf_nat_out protects post-routing. */
-	NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off
-		       & htons(IP_MF|IP_OFFSET)));
+	NF_CT_ASSERT(!(ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)));
 
 	ct = nf_ct_get(*pskb, &ctinfo);
 	/* Can't track?  It's not due to stress, or conntrack would
@@ -98,11 +97,10 @@ nf_nat_fn(unsigned int hooknum,
 		/* Exception: ICMP redirect to new connection (not in
 		   hash table yet).  We must not let this through, in
 		   case we're doing NAT to the same network. */
-		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
+		if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
 			struct icmphdr _hdr, *hp;
 
-			hp = skb_header_pointer(*pskb,
-						(*pskb)->nh.iph->ihl*4,
+			hp = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
 						sizeof(_hdr), &_hdr);
 			if (hp != NULL &&
 			    hp->type == ICMP_REDIRECT)
@@ -122,7 +120,7 @@ nf_nat_fn(unsigned int hooknum,
 	switch (ctinfo) {
 	case IP_CT_RELATED:
 	case IP_CT_RELATED+IP_CT_IS_REPLY:
-		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
+		if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
 			if (!nf_nat_icmp_reply_translation(ct, ctinfo,
 							   hooknum, pskb))
 				return NF_DROP;
@@ -177,11 +175,11 @@ nf_nat_in(unsigned int hooknum,
 	  int (*okfn)(struct sk_buff *))
 {
 	unsigned int ret;
-	__be32 daddr = (*pskb)->nh.iph->daddr;
+	__be32 daddr = ip_hdr(*pskb)->daddr;
 
 	ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
 	if (ret != NF_DROP && ret != NF_STOLEN &&
-	    daddr != (*pskb)->nh.iph->daddr) {
+	    daddr != ip_hdr(*pskb)->daddr) {
 		dst_release((*pskb)->dst);
 		(*pskb)->dst = NULL;
 	}
@@ -203,7 +201,7 @@ #endif
 
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr) ||
-	    (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+	    ip_hdrlen(*pskb) < sizeof(struct iphdr))
 		return NF_ACCEPT;
 
 	ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
@@ -236,7 +234,7 @@ nf_nat_local_fn(unsigned int hooknum,
 
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr) ||
-	    (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+	    ip_hdrlen(*pskb) < sizeof(struct iphdr))
 		return NF_ACCEPT;
 
 	ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index ae68a69..37ab580 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -87,19 +87,6 @@ static const struct file_operations sock
 	.release = single_release,
 };
 
-static unsigned long
-fold_field(void *mib[], int offt)
-{
-	unsigned long res = 0;
-	int i;
-
-	for_each_possible_cpu(i) {
-		res += *(((unsigned long *) per_cpu_ptr(mib[0], i)) + offt);
-		res += *(((unsigned long *) per_cpu_ptr(mib[1], i)) + offt);
-	}
-	return res;
-}
-
 /* snmp items */
 static const struct snmp_mib snmp4_ipstats_list[] = {
 	SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INRECEIVES),
@@ -266,8 +253,8 @@ static int snmp_seq_show(struct seq_file
 
 	for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   fold_field((void **) ip_statistics,
-				      snmp4_ipstats_list[i].entry));
+			   snmp_fold_field((void **)ip_statistics,
+					   snmp4_ipstats_list[i].entry));
 
 	seq_puts(seq, "\nIcmp:");
 	for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
@@ -276,8 +263,8 @@ static int snmp_seq_show(struct seq_file
 	seq_puts(seq, "\nIcmp:");
 	for (i = 0; snmp4_icmp_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   fold_field((void **) icmp_statistics,
-				      snmp4_icmp_list[i].entry));
+			   snmp_fold_field((void **)icmp_statistics,
+					   snmp4_icmp_list[i].entry));
 
 	seq_puts(seq, "\nTcp:");
 	for (i = 0; snmp4_tcp_list[i].name != NULL; i++)
@@ -288,12 +275,12 @@ static int snmp_seq_show(struct seq_file
 		/* MaxConn field is signed, RFC 2012 */
 		if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN)
 			seq_printf(seq, " %ld",
-				   fold_field((void **) tcp_statistics,
-					      snmp4_tcp_list[i].entry));
+				   snmp_fold_field((void **)tcp_statistics,
+						   snmp4_tcp_list[i].entry));
 		else
 			seq_printf(seq, " %lu",
-				   fold_field((void **) tcp_statistics,
-					      snmp4_tcp_list[i].entry));
+				   snmp_fold_field((void **)tcp_statistics,
+						   snmp4_tcp_list[i].entry));
 	}
 
 	seq_puts(seq, "\nUdp:");
@@ -303,8 +290,8 @@ static int snmp_seq_show(struct seq_file
 	seq_puts(seq, "\nUdp:");
 	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   fold_field((void **) udp_statistics,
-				      snmp4_udp_list[i].entry));
+			   snmp_fold_field((void **)udp_statistics,
+					   snmp4_udp_list[i].entry));
 
 	/* the UDP and UDP-Lite MIBs are the same */
 	seq_puts(seq, "\nUdpLite:");
@@ -314,8 +301,8 @@ static int snmp_seq_show(struct seq_file
 	seq_puts(seq, "\nUdpLite:");
 	for (i = 0; snmp4_udp_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   fold_field((void **) udplite_statistics,
-				      snmp4_udp_list[i].entry)     );
+			   snmp_fold_field((void **)udplite_statistics,
+					   snmp4_udp_list[i].entry));
 
 	seq_putc(seq, '\n');
 	return 0;
@@ -348,8 +335,8 @@ static int netstat_seq_show(struct seq_f
 	seq_puts(seq, "\nTcpExt:");
 	for (i = 0; snmp4_net_list[i].name != NULL; i++)
 		seq_printf(seq, " %lu",
-			   fold_field((void **) net_statistics,
-				      snmp4_net_list[i].entry));
+			   snmp_fold_field((void **)net_statistics,
+					   snmp4_net_list[i].entry));
 
 	seq_putc(seq, '\n');
 	return 0;
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index da70fef..971ab93 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -45,7 +45,7 @@ #include <net/udp.h>
 #include <net/ipip.h>
 #include <linux/igmp.h>
 
-struct net_protocol *inet_protos[MAX_INET_PROTOS];
+struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp;
 static DEFINE_SPINLOCK(inet_proto_lock);
 
 /*
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 87e9c16..24d7c9f 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -132,7 +132,7 @@ static __inline__ int icmp_filter(struct
 	if (!pskb_may_pull(skb, sizeof(struct icmphdr)))
 		return 1;
 
-	type = skb->h.icmph->type;
+	type = icmp_hdr(skb)->type;
 	if (type < 32) {
 		__u32 data = raw_sk(sk)->filter.data;
 
@@ -184,8 +184,8 @@ out:
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
 {
 	struct inet_sock *inet = inet_sk(sk);
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	int err = 0;
 	int harderr = 0;
 
@@ -256,7 +256,7 @@ int raw_rcv(struct sock *sk, struct sk_b
 	}
 	nf_reset(skb);
 
-	skb_push(skb, skb->data - skb->nh.raw);
+	skb_push(skb, skb->data - skb_network_header(skb));
 
 	raw_rcv_skb(sk, skb);
 	return 0;
@@ -291,11 +291,13 @@ static int raw_send_hdrinc(struct sock *
 	skb->priority = sk->sk_priority;
 	skb->dst = dst_clone(&rt->u.dst);
 
-	skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+	skb_put(skb, length);
 
 	skb->ip_summed = CHECKSUM_NONE;
 
-	skb->h.raw = skb->nh.raw;
+	skb->transport_header = skb->network_header;
 	err = memcpy_fromiovecend((void *)iph, from, 0, length);
 	if (err)
 		goto error_fault;
@@ -613,7 +615,7 @@ static int raw_recvmsg(struct kiocb *ioc
 	/* Copy the address. */
 	if (sin) {
 		sin->sin_family = AF_INET;
-		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		sin->sin_port = 0;
 		memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
@@ -887,7 +889,7 @@ static int raw_seq_show(struct seq_file 
 	return 0;
 }
 
-static struct seq_operations raw_seq_ops = {
+static const struct seq_operations raw_seq_ops = {
 	.start = raw_seq_start,
 	.next  = raw_seq_next,
 	.stop  = raw_seq_stop,
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 37e0d4d..cb76e3c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -82,7 +82,6 @@ #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
 #include <linux/pkt_sched.h>
@@ -104,6 +103,7 @@ #include <net/icmp.h>
 #include <net/xfrm.h>
 #include <net/ip_mp_alg.h>
 #include <net/netevent.h>
+#include <net/rtnetlink.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 #endif
@@ -364,7 +364,7 @@ static int rt_cache_seq_show(struct seq_
 	return 0;
 }
 
-static struct seq_operations rt_cache_seq_ops = {
+static const struct seq_operations rt_cache_seq_ops = {
 	.start  = rt_cache_seq_start,
 	.next   = rt_cache_seq_next,
 	.stop   = rt_cache_seq_stop,
@@ -470,7 +470,7 @@ static int rt_cpu_seq_show(struct seq_fi
 	return 0;
 }
 
-static struct seq_operations rt_cpu_seq_ops = {
+static const struct seq_operations rt_cpu_seq_ops = {
 	.start  = rt_cpu_seq_start,
 	.next   = rt_cpu_seq_next,
 	.stop   = rt_cpu_seq_stop,
@@ -1519,7 +1519,7 @@ static void ipv4_link_failure(struct sk_
 static int ip_rt_bug(struct sk_buff *skb)
 {
 	printk(KERN_DEBUG "ip_rt_bug: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n",
-		NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr),
+		NIPQUAD(ip_hdr(skb)->saddr), NIPQUAD(ip_hdr(skb)->daddr),
 		skb->dev ? skb->dev->name : "?");
 	kfree_skb(skb);
 	return 0;
@@ -1698,9 +1698,9 @@ #ifdef CONFIG_IP_ROUTE_VERBOSE
 		printk(KERN_WARNING "martian source %u.%u.%u.%u from "
 			"%u.%u.%u.%u, on dev %s\n",
 			NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
-		if (dev->hard_header_len && skb->mac.raw) {
+		if (dev->hard_header_len && skb_mac_header_was_set(skb)) {
 			int i;
-			unsigned char *p = skb->mac.raw;
+			const unsigned char *p = skb_mac_header(skb);
 			printk(KERN_WARNING "ll header: ");
 			for (i = 0; i < dev->hard_header_len; i++, p++) {
 				printk("%02x", *p);
@@ -2134,7 +2134,7 @@ int ip_route_input(struct sk_buff *skb, 
 		rcu_read_lock();
 		if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
 			int our = ip_check_mc(in_dev, daddr, saddr,
-				skb->nh.iph->protocol);
+				ip_hdr(skb)->protocol);
 			if (our
 #ifdef CONFIG_IP_MROUTE
 			    || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))
@@ -2396,7 +2396,7 @@ #endif
 
 		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
 		dev_out = ip_dev_find(oldflp->fl4_src);
-		if (dev_out == NULL)
+		if ((dev_out == NULL) && !(sysctl_ip_nonlocal_bind))
 			goto out;
 
 		/* I removed check for oif == dev_out->oif here.
@@ -2407,7 +2407,7 @@ #endif
 		      of another iface. --ANK
 		 */
 
-		if (oldflp->oif == 0
+		if (dev_out && oldflp->oif == 0
 		    && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
@@ -2683,7 +2683,7 @@ #endif
 		id = rt->peer->ip_id_count;
 		if (rt->peer->tcp_ts_stamp) {
 			ts = rt->peer->tcp_ts;
-			tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
+			tsage = get_seconds() - rt->peer->tcp_ts_stamp;
 		}
 	}
 
@@ -2721,7 +2721,7 @@ nla_put_failure:
 	return -EMSGSIZE;
 }
 
-int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct rtmsg *rtm;
 	struct nlattr *tb[RTA_MAX+1];
@@ -2747,10 +2747,11 @@ int inet_rtm_getroute(struct sk_buff *in
 	/* Reserve room for dummy headers, this skb can pass
 	   through good chunk of routing engine.
 	 */
-	skb->mac.raw = skb->nh.raw = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
 
 	/* Bugfix: need to give ip_route_input enough of an IP header to not gag. */
-	skb->nh.iph->protocol = IPPROTO_ICMP;
+	ip_hdr(skb)->protocol = IPPROTO_ICMP;
 	skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
 
 	src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
@@ -3193,6 +3194,8 @@ #ifdef CONFIG_XFRM
 	xfrm_init();
 	xfrm4_init();
 #endif
+	rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL);
+
 	return rc;
 }
 
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 33016cc..2da1be0 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -125,10 +125,11 @@ #define NUM_MSS (ARRAY_SIZE(msstab) - 1)
 __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
+	const struct iphdr *iph = ip_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
 	int mssind;
 	const __u16 mss = *mssp;
 
-
 	tp->last_synq_overflow = jiffies;
 
 	/* XXX sort msstab[] by probability?  Binary search? */
@@ -138,9 +139,8 @@ __u32 cookie_v4_init_sequence(struct soc
 
 	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT);
 
-	return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
-				     skb->h.th->source, skb->h.th->dest,
-				     ntohl(skb->h.th->seq),
+	return secure_tcp_syn_cookie(iph->saddr, iph->daddr,
+				     th->source, th->dest, ntohl(th->seq),
 				     jiffies / (HZ * 60), mssind);
 }
 
@@ -157,14 +157,13 @@ #define COUNTER_TRIES 4
  */
 static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
 {
-	__u32 seq;
-	__u32 mssind;
-
-	seq = ntohl(skb->h.th->seq)-1;
-	mssind = check_tcp_syn_cookie(cookie,
-				      skb->nh.iph->saddr, skb->nh.iph->daddr,
-				      skb->h.th->source, skb->h.th->dest,
-				      seq, jiffies / (HZ * 60), COUNTER_TRIES);
+	const struct iphdr *iph = ip_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 seq = ntohl(th->seq) - 1;
+	__u32 mssind = check_tcp_syn_cookie(cookie, iph->saddr, iph->daddr,
+					    th->source, th->dest, seq,
+					    jiffies / (HZ * 60),
+					    COUNTER_TRIES);
 
 	return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
 }
@@ -191,14 +190,15 @@ struct sock *cookie_v4_check(struct sock
 	struct inet_request_sock *ireq;
 	struct tcp_request_sock *treq;
 	struct tcp_sock *tp = tcp_sk(sk);
-	__u32 cookie = ntohl(skb->h.th->ack_seq) - 1;
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 cookie = ntohl(th->ack_seq) - 1;
 	struct sock *ret = sk;
 	struct request_sock *req;
 	int mss;
 	struct rtable *rt;
 	__u8 rcv_wscale;
 
-	if (!sysctl_tcp_syncookies || !skb->h.th->ack)
+	if (!sysctl_tcp_syncookies || !th->ack)
 		goto out;
 
 	if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
@@ -220,12 +220,12 @@ struct sock *cookie_v4_check(struct sock
 	}
 	ireq = inet_rsk(req);
 	treq = tcp_rsk(req);
-	treq->rcv_isn		= ntohl(skb->h.th->seq) - 1;
+	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
 	req->mss		= mss;
-	ireq->rmt_port		= skb->h.th->source;
-	ireq->loc_addr		= skb->nh.iph->daddr;
-	ireq->rmt_addr		= skb->nh.iph->saddr;
+	ireq->rmt_port		= th->source;
+	ireq->loc_addr		= ip_hdr(skb)->daddr;
+	ireq->rmt_addr		= ip_hdr(skb)->saddr;
 	ireq->opt		= NULL;
 
 	/* We throwed the options of the initial SYN away, so we hope
@@ -261,8 +261,8 @@ struct sock *cookie_v4_check(struct sock
 						.tos = RT_CONN_FLAGS(sk) } },
 				    .proto = IPPROTO_TCP,
 				    .uli_u = { .ports =
-					       { .sport = skb->h.th->dest,
-						 .dport = skb->h.th->source } } };
+					       { .sport = th->dest,
+						 .dport = th->source } } };
 		security_req_classify_flow(req, &fl);
 		if (ip_route_output_key(&rt, &fl)) {
 			reqsk_free(req);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 0aa3047..6817d64 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -647,6 +647,14 @@ #endif
 		.proc_handler	= &proc_dointvec
 	},
 	{
+		.ctl_name	= NET_TCP_FRTO_RESPONSE,
+		.procname	= "tcp_frto_response",
+		.data		= &sysctl_tcp_frto_response,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
 		.ctl_name	= NET_TCP_LOW_LATENCY,
 		.procname	= "tcp_low_latency",
 		.data		= &sysctl_tcp_low_latency,
@@ -803,6 +811,14 @@ #endif /* CONFIG_NETLABEL */
 		.proc_handler   = &proc_allowed_congestion_control,
 		.strategy	= &strategy_allowed_congestion_control,
 	},
+	{
+		.ctl_name	= NET_TCP_MAX_SSTHRESH,
+		.procname	= "tcp_max_ssthresh",
+		.data		= &sysctl_tcp_max_ssthresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 	{ .ctl_name = 0 }
 };
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3834b10..bd4c295 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -252,7 +252,6 @@ #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/random.h>
 #include <linux/bootmem.h>
@@ -297,7 +296,7 @@ EXPORT_SYMBOL(tcp_sockets_allocated);
  * All the sk_stream_mem_schedule() is of this nature: accounting
  * is strict, actions are advisory and have some latency.
  */
-int tcp_memory_pressure;
+int tcp_memory_pressure __read_mostly;
 
 EXPORT_SYMBOL(tcp_memory_pressure);
 
@@ -425,7 +424,7 @@ int tcp_ioctl(struct sock *sk, int cmd, 
 			/* Subtract 1, if FIN is in queue. */
 			if (answ && !skb_queue_empty(&sk->sk_receive_queue))
 				answ -=
-		       ((struct sk_buff *)sk->sk_receive_queue.prev)->h.th->fin;
+		       tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin;
 		} else
 			answ = tp->urg_seq - tp->copied_seq;
 		release_sock(sk);
@@ -444,7 +443,7 @@ int tcp_ioctl(struct sock *sk, int cmd, 
 		break;
 	default:
 		return -ENOIOCTLCMD;
-	};
+	}
 
 	return put_user(answ, (int __user *)arg);
 }
@@ -460,9 +459,9 @@ static inline int forced_push(struct tcp
 	return after(tp->write_seq, tp->pushed_seq + (tp->max_window >> 1));
 }
 
-static inline void skb_entail(struct sock *sk, struct tcp_sock *tp,
-			      struct sk_buff *skb)
+static inline void skb_entail(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
 
 	skb->csum    = 0;
@@ -470,10 +469,8 @@ static inline void skb_entail(struct soc
 	tcb->flags   = TCPCB_FLAG_ACK;
 	tcb->sacked  = 0;
 	skb_header_release(skb);
-	__skb_queue_tail(&sk->sk_write_queue, skb);
+	tcp_add_write_queue_tail(sk, skb);
 	sk_charge_skb(sk, skb);
-	if (!sk->sk_send_head)
-		sk->sk_send_head = skb;
 	if (tp->nonagle & TCP_NAGLE_PUSH)
 		tp->nonagle &= ~TCP_NAGLE_PUSH;
 }
@@ -488,15 +485,17 @@ static inline void tcp_mark_urg(struct t
 	}
 }
 
-static inline void tcp_push(struct sock *sk, struct tcp_sock *tp, int flags,
-			    int mss_now, int nonagle)
+static inline void tcp_push(struct sock *sk, int flags, int mss_now,
+			    int nonagle)
 {
-	if (sk->sk_send_head) {
-		struct sk_buff *skb = sk->sk_write_queue.prev;
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (tcp_send_head(sk)) {
+		struct sk_buff *skb = tcp_write_queue_tail(sk);
 		if (!(flags & MSG_MORE) || forced_push(tp))
 			tcp_mark_push(tp, skb);
 		tcp_mark_urg(tp, flags, skb);
-		__tcp_push_pending_frames(sk, tp, mss_now,
+		__tcp_push_pending_frames(sk, mss_now,
 					  (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle);
 	}
 }
@@ -526,13 +525,13 @@ static ssize_t do_tcp_sendpages(struct s
 		goto do_error;
 
 	while (psize > 0) {
-		struct sk_buff *skb = sk->sk_write_queue.prev;
+		struct sk_buff *skb = tcp_write_queue_tail(sk);
 		struct page *page = pages[poffset / PAGE_SIZE];
 		int copy, i, can_coalesce;
 		int offset = poffset % PAGE_SIZE;
 		int size = min_t(size_t, psize, PAGE_SIZE - offset);
 
-		if (!sk->sk_send_head || (copy = size_goal - skb->len) <= 0) {
+		if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0) {
 new_segment:
 			if (!sk_stream_memory_free(sk))
 				goto wait_for_sndbuf;
@@ -542,7 +541,7 @@ new_segment:
 			if (!skb)
 				goto wait_for_memory;
 
-			skb_entail(sk, tp, skb);
+			skb_entail(sk, skb);
 			copy = size_goal;
 		}
 
@@ -588,8 +587,8 @@ new_segment:
 
 		if (forced_push(tp)) {
 			tcp_mark_push(tp, skb);
-			__tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH);
-		} else if (skb == sk->sk_send_head)
+			__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH);
+		} else if (skb == tcp_send_head(sk))
 			tcp_push_one(sk, mss_now);
 		continue;
 
@@ -597,7 +596,7 @@ wait_for_sndbuf:
 		set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 wait_for_memory:
 		if (copied)
-			tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+			tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
 
 		if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
 			goto do_error;
@@ -608,7 +607,7 @@ wait_for_memory:
 
 out:
 	if (copied)
-		tcp_push(sk, tp, flags, mss_now, tp->nonagle);
+		tcp_push(sk, flags, mss_now, tp->nonagle);
 	return copied;
 
 do_error:
@@ -639,8 +638,9 @@ ssize_t tcp_sendpage(struct socket *sock
 #define TCP_PAGE(sk)	(sk->sk_sndmsg_page)
 #define TCP_OFF(sk)	(sk->sk_sndmsg_off)
 
-static inline int select_size(struct sock *sk, struct tcp_sock *tp)
+static inline int select_size(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	int tmp = tp->mss_cache;
 
 	if (sk->sk_route_caps & NETIF_F_SG) {
@@ -704,9 +704,9 @@ int tcp_sendmsg(struct kiocb *iocb, stru
 		while (seglen > 0) {
 			int copy;
 
-			skb = sk->sk_write_queue.prev;
+			skb = tcp_write_queue_tail(sk);
 
-			if (!sk->sk_send_head ||
+			if (!tcp_send_head(sk) ||
 			    (copy = size_goal - skb->len) <= 0) {
 
 new_segment:
@@ -716,7 +716,7 @@ new_segment:
 				if (!sk_stream_memory_free(sk))
 					goto wait_for_sndbuf;
 
-				skb = sk_stream_alloc_pskb(sk, select_size(sk, tp),
+				skb = sk_stream_alloc_pskb(sk, select_size(sk),
 							   0, sk->sk_allocation);
 				if (!skb)
 					goto wait_for_memory;
@@ -727,7 +727,7 @@ new_segment:
 				if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
 					skb->ip_summed = CHECKSUM_PARTIAL;
 
-				skb_entail(sk, tp, skb);
+				skb_entail(sk, skb);
 				copy = size_goal;
 			}
 
@@ -832,8 +832,8 @@ new_segment:
 
 			if (forced_push(tp)) {
 				tcp_mark_push(tp, skb);
-				__tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH);
-			} else if (skb == sk->sk_send_head)
+				__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH);
+			} else if (skb == tcp_send_head(sk))
 				tcp_push_one(sk, mss_now);
 			continue;
 
@@ -841,7 +841,7 @@ wait_for_sndbuf:
 			set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
 wait_for_memory:
 			if (copied)
-				tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+				tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
 
 			if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
 				goto do_error;
@@ -853,16 +853,18 @@ wait_for_memory:
 
 out:
 	if (copied)
-		tcp_push(sk, tp, flags, mss_now, tp->nonagle);
+		tcp_push(sk, flags, mss_now, tp->nonagle);
 	TCP_CHECK_TIMER(sk);
 	release_sock(sk);
 	return copied;
 
 do_fault:
 	if (!skb->len) {
-		if (sk->sk_send_head == skb)
-			sk->sk_send_head = NULL;
-		__skb_unlink(skb, &sk->sk_write_queue);
+		tcp_unlink_write_queue(skb, sk);
+		/* It is the one place in all of TCP, except connection
+		 * reset, where we can be unlinking the send_head.
+		 */
+		tcp_check_send_head(sk, skb);
 		sk_stream_free_skb(sk, skb);
 	}
 
@@ -1016,9 +1018,9 @@ static inline struct sk_buff *tcp_recv_s
 
 	skb_queue_walk(&sk->sk_receive_queue, skb) {
 		offset = seq - TCP_SKB_CB(skb)->seq;
-		if (skb->h.th->syn)
+		if (tcp_hdr(skb)->syn)
 			offset--;
-		if (offset < skb->len || skb->h.th->fin) {
+		if (offset < skb->len || tcp_hdr(skb)->fin) {
 			*off = offset;
 			return skb;
 		}
@@ -1070,7 +1072,7 @@ int tcp_read_sock(struct sock *sk, read_
 			if (offset != skb->len)
 				break;
 		}
-		if (skb->h.th->fin) {
+		if (tcp_hdr(skb)->fin) {
 			sk_eat_skb(sk, skb, 0);
 			++seq;
 			break;
@@ -1174,11 +1176,11 @@ #endif
 				break;
 			}
 			offset = *seq - TCP_SKB_CB(skb)->seq;
-			if (skb->h.th->syn)
+			if (tcp_hdr(skb)->syn)
 				offset--;
 			if (offset < skb->len)
 				goto found_ok_skb;
-			if (skb->h.th->fin)
+			if (tcp_hdr(skb)->fin)
 				goto found_fin_ok;
 			BUG_TRAP(flags & MSG_PEEK);
 			skb = skb->next;
@@ -1389,12 +1391,12 @@ #endif
 skip_copy:
 		if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) {
 			tp->urg_data = 0;
-			tcp_fast_path_check(sk, tp);
+			tcp_fast_path_check(sk);
 		}
 		if (used + offset < skb->len)
 			continue;
 
-		if (skb->h.th->fin)
+		if (tcp_hdr(skb)->fin)
 			goto found_fin_ok;
 		if (!(flags & MSG_PEEK)) {
 			sk_eat_skb(sk, skb, copied_early);
@@ -1563,21 +1565,19 @@ void tcp_close(struct sock *sk, long tim
 	 */
 	while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 		u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq -
-			  skb->h.th->fin;
+			  tcp_hdr(skb)->fin;
 		data_was_unread += len;
 		__kfree_skb(skb);
 	}
 
 	sk_stream_mem_reclaim(sk);
 
-	/* As outlined in draft-ietf-tcpimpl-prob-03.txt, section
-	 * 3.10, we send a RST here because data was lost.  To
-	 * witness the awful effects of the old behavior of always
-	 * doing a FIN, run an older 2.1.x kernel or 2.0.x, start
-	 * a bulk GET in an FTP client, suspend the process, wait
-	 * for the client to advertise a zero window, then kill -9
-	 * the FTP client, wheee...  Note: timeout is always zero
-	 * in such a case.
+	/* As outlined in RFC 2525, section 2.17, we send a RST here because
+	 * data was lost. To witness the awful effects of the old behavior of
+	 * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
+	 * GET in an FTP client, suspend the process, wait for the client to
+	 * advertise a zero window, then kill -9 the FTP client, wheee...
+	 * Note: timeout is always zero in such a case.
 	 */
 	if (data_was_unread) {
 		/* Unread data was tossed, zap the connection. */
@@ -1732,7 +1732,7 @@ int tcp_disconnect(struct sock *sk, int 
 
 	tcp_clear_xmit_timers(sk);
 	__skb_queue_purge(&sk->sk_receive_queue);
-	sk_stream_writequeue_purge(sk);
+	tcp_write_queue_purge(sk);
 	__skb_queue_purge(&tp->out_of_order_queue);
 #ifdef CONFIG_NET_DMA
 	__skb_queue_purge(&sk->sk_async_wait_queue);
@@ -1758,9 +1758,8 @@ #endif
 	tcp_set_ca_state(sk, TCP_CA_Open);
 	tcp_clear_retrans(tp);
 	inet_csk_delack_init(sk);
-	sk->sk_send_head = NULL;
-	tp->rx_opt.saw_tstamp = 0;
-	tcp_sack_reset(&tp->rx_opt);
+	tcp_init_send_head(sk);
+	memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
 	__sk_dst_reset(sk);
 
 	BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
@@ -1830,7 +1829,7 @@ static int do_tcp_setsockopt(struct sock
 			 * for currently queued segments.
 			 */
 			tp->nonagle |= TCP_NAGLE_OFF|TCP_NAGLE_PUSH;
-			tcp_push_pending_frames(sk, tp);
+			tcp_push_pending_frames(sk);
 		} else {
 			tp->nonagle &= ~TCP_NAGLE_OFF;
 		}
@@ -1854,7 +1853,7 @@ static int do_tcp_setsockopt(struct sock
 			tp->nonagle &= ~TCP_NAGLE_CORK;
 			if (tp->nonagle&TCP_NAGLE_OFF)
 				tp->nonagle |= TCP_NAGLE_PUSH;
-			tcp_push_pending_frames(sk, tp);
+			tcp_push_pending_frames(sk);
 		}
 		break;
 
@@ -1954,7 +1953,8 @@ #endif
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
+
 	release_sock(sk);
 	return err;
 }
@@ -2124,7 +2124,7 @@ static int do_tcp_getsockopt(struct sock
 		return 0;
 	default:
 		return -ENOPROTOOPT;
-	};
+	}
 
 	if (put_user(len, optlen))
 		return -EFAULT;
@@ -2170,7 +2170,7 @@ struct sk_buff *tcp_tso_segment(struct s
 	if (!pskb_may_pull(skb, sizeof(*th)))
 		goto out;
 
-	th = skb->h.th;
+	th = tcp_hdr(skb);
 	thlen = th->doff * 4;
 	if (thlen < sizeof(*th))
 		goto out;
@@ -2210,7 +2210,7 @@ struct sk_buff *tcp_tso_segment(struct s
 	delta = htonl(oldlen + (thlen + len));
 
 	skb = segs;
-	th = skb->h.th;
+	th = tcp_hdr(skb);
 	seq = ntohl(th->seq);
 
 	do {
@@ -2219,23 +2219,25 @@ struct sk_buff *tcp_tso_segment(struct s
 		th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
 				       (__force u32)delta));
 		if (skb->ip_summed != CHECKSUM_PARTIAL)
-			th->check = csum_fold(csum_partial(skb->h.raw, thlen,
-							   skb->csum));
+			th->check =
+			     csum_fold(csum_partial(skb_transport_header(skb),
+						    thlen, skb->csum));
 
 		seq += len;
 		skb = skb->next;
-		th = skb->h.th;
+		th = tcp_hdr(skb);
 
 		th->seq = htonl(seq);
 		th->cwr = 0;
 	} while (skb->next);
 
-	delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
+	delta = htonl(oldlen + (skb->tail - skb->transport_header) +
+		      skb->data_len);
 	th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
 				(__force u32)delta));
 	if (skb->ip_summed != CHECKSUM_PARTIAL)
-		th->check = csum_fold(csum_partial(skb->h.raw, thlen,
-						   skb->csum));
+		th->check = csum_fold(csum_partial(skb_transport_header(skb),
+						   thlen, skb->csum));
 
 out:
 	return segs;
@@ -2372,6 +2374,23 @@ void __tcp_put_md5sig_pool(void)
 EXPORT_SYMBOL(__tcp_put_md5sig_pool);
 #endif
 
+void tcp_done(struct sock *sk)
+{
+	if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
+		TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
+
+	tcp_set_state(sk, TCP_CLOSE);
+	tcp_clear_xmit_timers(sk);
+
+	sk->sk_shutdown = SHUTDOWN_MASK;
+
+	if (!sock_flag(sk, SOCK_DEAD))
+		sk->sk_state_change(sk);
+	else
+		inet_csk_destroy_sock(sk);
+}
+EXPORT_SYMBOL_GPL(tcp_done);
+
 extern void __skb_cb_too_small_for_tcp(int, int);
 extern struct tcp_congestion_ops tcp_reno;
 
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index 5730333..281c9f9 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -206,7 +206,7 @@ static void bictcp_state(struct sock *sk
 /* Track delayed acknowledgment ratio using sliding window
  * ratio = (15*ratio + sample) / 16
  */
-static void bictcp_acked(struct sock *sk, u32 cnt)
+static void bictcp_acked(struct sock *sk, u32 cnt, ktime_t last)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 34ae3f1..86b2653 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -12,6 +12,8 @@ #include <linux/types.h>
 #include <linux/list.h>
 #include <net/tcp.h>
 
+int sysctl_tcp_max_ssthresh = 0;
+
 static DEFINE_SPINLOCK(tcp_cong_list_lock);
 static LIST_HEAD(tcp_cong_list);
 
@@ -124,7 +126,7 @@ #ifdef CONFIG_KMOD
 #endif
 
 	if (ca) {
-		ca->non_restricted = 1;	/* default is always allowed */
+		ca->flags |= TCP_CONG_NON_RESTRICTED;	/* default is always allowed */
 		list_move(&ca->list, &tcp_cong_list);
 		ret = 0;
 	}
@@ -179,7 +181,7 @@ void tcp_get_allowed_congestion_control(
 	*buf = '\0';
 	rcu_read_lock();
 	list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
-		if (!ca->non_restricted)
+		if (!(ca->flags & TCP_CONG_NON_RESTRICTED))
 			continue;
 		offs += snprintf(buf + offs, maxlen - offs,
 				 "%s%s",
@@ -210,16 +212,16 @@ int tcp_set_allowed_congestion_control(c
 		}
 	}
 
-	/* pass 2 clear */
+	/* pass 2 clear old values */
 	list_for_each_entry_rcu(ca, &tcp_cong_list, list)
-		ca->non_restricted = 0;
+		ca->flags &= ~TCP_CONG_NON_RESTRICTED;
 
 	/* pass 3 mark as allowed */
 	while ((name = strsep(&val, " ")) && *name) {
 		ca = tcp_ca_find(name);
 		WARN_ON(!ca);
 		if (ca)
-			ca->non_restricted = 1;
+			ca->flags |= TCP_CONG_NON_RESTRICTED;
 	}
 out:
 	spin_unlock(&tcp_cong_list_lock);
@@ -254,7 +256,7 @@ #endif
 	if (!ca)
 		err = -ENOENT;
 
-	else if (!(ca->non_restricted || capable(CAP_NET_ADMIN)))
+	else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || capable(CAP_NET_ADMIN)))
 		err = -EPERM;
 
 	else if (!try_module_get(ca->owner))
@@ -274,10 +276,13 @@ #endif
 
 
 /*
- * Linear increase during slow start
+ * Slow start (exponential increase) with
+ * RFC3742 Limited Slow Start (fast linear increase) support.
  */
 void tcp_slow_start(struct tcp_sock *tp)
 {
+	int cnt = 0;
+
 	if (sysctl_tcp_abc) {
 		/* RFC3465: Slow Start
 		 * TCP sender SHOULD increase cwnd by the number of
@@ -286,17 +291,25 @@ void tcp_slow_start(struct tcp_sock *tp)
 		 */
 		if (tp->bytes_acked < tp->mss_cache)
 			return;
-
-		/* We MAY increase by 2 if discovered delayed ack */
-		if (sysctl_tcp_abc > 1 && tp->bytes_acked >= 2*tp->mss_cache) {
-			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-				tp->snd_cwnd++;
-		}
 	}
+
+	if (sysctl_tcp_max_ssthresh > 0 &&
+	    tp->snd_cwnd > sysctl_tcp_max_ssthresh)
+		cnt += sysctl_tcp_max_ssthresh>>1;
+	else
+		cnt += tp->snd_cwnd;
+
+	/* RFC3465: We MAY increase by 2 if discovered delayed ack */
+	if (sysctl_tcp_abc > 1 && tp->bytes_acked >= 2*tp->mss_cache)
+		cnt <<= 1;
 	tp->bytes_acked = 0;
 
-	if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-		tp->snd_cwnd++;
+	tp->snd_cwnd_cnt += cnt;
+	while (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+		tp->snd_cwnd_cnt -= tp->snd_cwnd;
+		if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+			tp->snd_cwnd++;
+	}
 }
 EXPORT_SYMBOL_GPL(tcp_slow_start);
 
@@ -358,8 +371,8 @@ u32 tcp_reno_min_cwnd(const struct sock 
 EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
 
 struct tcp_congestion_ops tcp_reno = {
+	.flags		= TCP_CONG_NON_RESTRICTED,
 	.name		= "reno",
-	.non_restricted = 1,
 	.owner		= THIS_MODULE,
 	.ssthresh	= tcp_reno_ssthresh,
 	.cong_avoid	= tcp_reno_cong_avoid,
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index 9a582fb..1422448 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -1,5 +1,5 @@
 /*
- * TCP CUBIC: Binary Increase Congestion control for TCP v2.0
+ * TCP CUBIC: Binary Increase Congestion control for TCP v2.1
  *
  * This is from the implementation of CUBIC TCP in
  * Injong Rhee, Lisong Xu.
@@ -51,8 +51,6 @@ MODULE_PARM_DESC(bic_scale, "scale (scal
 module_param(tcp_friendliness, int, 0644);
 MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness");
 
-#include <asm/div64.h>
-
 /* BIC TCP Parameters */
 struct bictcp {
 	u32	cnt;		/* increase cwnd by 1 after ACKs */
@@ -93,50 +91,51 @@ static void bictcp_init(struct sock *sk)
 		tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
 }
 
-/* 64bit divisor, dividend and result. dynamic precision */
-static inline u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
-{
-	u_int32_t d = divisor;
-
-	if (divisor > 0xffffffffULL) {
-		unsigned int shift = fls(divisor >> 32);
-
-		d = divisor >> shift;
-		dividend >>= shift;
-	}
-
-	/* avoid 64 bit division if possible */
-	if (dividend >> 32)
-		do_div(dividend, d);
-	else
-		dividend = (uint32_t) dividend / d;
-
-	return dividend;
-}
-
-/*
- * calculate the cubic root of x using Newton-Raphson
+/* calculate the cubic root of x using a table lookup followed by one
+ * Newton-Raphson iteration.
+ * Avg err ~= 0.195%
  */
 static u32 cubic_root(u64 a)
 {
-	u32 x, x1;
-
-	/* Initial estimate is based on:
-	 * cbrt(x) = exp(log(x) / 3)
+	u32 x, b, shift;
+	/*
+	 * cbrt(x) MSB values for x MSB values in [0..63].
+	 * Precomputed then refined by hand - Willy Tarreau
+	 *
+	 * For x in [0..63],
+	 *   v = cbrt(x << 18) - 1
+	 *   cbrt(x) = (v[x] + 10) >> 6
 	 */
-	x = 1u << (fls64(a)/3);
+	static const u8 v[] = {
+		/* 0x00 */    0,   54,   54,   54,  118,  118,  118,  118,
+		/* 0x08 */  123,  129,  134,  138,  143,  147,  151,  156,
+		/* 0x10 */  157,  161,  164,  168,  170,  173,  176,  179,
+		/* 0x18 */  181,  185,  187,  190,  192,  194,  197,  199,
+		/* 0x20 */  200,  202,  204,  206,  209,  211,  213,  215,
+		/* 0x28 */  217,  219,  221,  222,  224,  225,  227,  229,
+		/* 0x30 */  231,  232,  234,  236,  237,  239,  240,  242,
+		/* 0x38 */  244,  245,  246,  248,  250,  251,  252,  254,
+	};
+
+	b = fls64(a);
+	if (b < 7) {
+		/* a in [0..63] */
+		return ((u32)v[(u32)a] + 35) >> 6;
+	}
+
+	b = ((b * 84) >> 8) - 1;
+	shift = (a >> (b * 3));
+
+	x = ((u32)(((u32)v[shift] + 10) << b)) >> 6;
 
 	/*
-	 * Iteration based on:
+	 * Newton-Raphson iteration
 	 *                         2
 	 * x    = ( 2 * x  +  a / x  ) / 3
 	 *  k+1          k         k
 	 */
-	do {
-		x1 = x;
-		x = (2 * x + (uint32_t) div64_64(a, x*x)) / 3;
-	} while (abs(x1 - x) > 1);
-
+	x = (2 * x + (u32)div64_64(a, (u64)x * (u64)(x - 1)));
+	x = ((x * 341) >> 10);
 	return x;
 }
 
@@ -215,7 +214,9 @@ static inline void bictcp_update(struct 
 	if (ca->delay_min > 0) {
 		/* max increment = Smax * rtt / 0.1  */
 		min_cnt = (cwnd * HZ * 8)/(10 * max_increment * ca->delay_min);
-		if (ca->cnt < min_cnt)
+
+		/* use concave growth when the target is above the origin */
+		if (ca->cnt < min_cnt && t >= ca->bic_K)
 			ca->cnt = min_cnt;
 	}
 
@@ -333,7 +334,7 @@ static void bictcp_state(struct sock *sk
 /* Track delayed acknowledgment ratio using sliding window
  * ratio = (15*ratio + sample) / 16
  */
-static void bictcp_acked(struct sock *sk, u32 cnt)
+static void bictcp_acked(struct sock *sk, u32 cnt, ktime_t last)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -401,4 +402,4 @@ module_exit(cubictcp_unregister);
 MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("CUBIC TCP");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index a291097..43d624e 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -97,10 +97,6 @@ struct hstcp {
 	u32	ai;
 };
 
-static int max_ssthresh = 100;
-module_param(max_ssthresh, int, 0644);
-MODULE_PARM_DESC(max_ssthresh, "limited slow start threshold (RFC3742)");
-
 static void hstcp_init(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -122,23 +118,9 @@ static void hstcp_cong_avoid(struct sock
 	if (!tcp_is_cwnd_limited(sk, in_flight))
 		return;
 
-	if (tp->snd_cwnd <= tp->snd_ssthresh) {
-		/* RFC3742: limited slow start
-		 * the window is increased by 1/K MSS for each arriving ACK,
-		 * for K = int(cwnd/(0.5 max_ssthresh))
-		 */
-		if (max_ssthresh > 0 && tp->snd_cwnd > max_ssthresh) {
-			u32 k = max(tp->snd_cwnd / (max_ssthresh >> 1), 1U);
-			if (++tp->snd_cwnd_cnt >= k) {
-				if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-					tp->snd_cwnd++;
-				tp->snd_cwnd_cnt = 0;
-			}
-		} else {
-			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-				tp->snd_cwnd++;
-		}
-	} else {
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+	else {
 		/* Update AIMD parameters.
 		 *
 		 * We want to guarantee that:
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 1020eb4..4ba4a7a 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -98,7 +98,7 @@ static inline void measure_rtt(struct so
 	}
 }
 
-static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked)
+static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, ktime_t last)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	const struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index 59e691d..e5be351 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -144,7 +144,7 @@ static void hybla_cong_avoid(struct sock
 	ca->snd_cwnd_cents += odd;
 
 	/* check when fractions goes >=128 and increase cwnd by 1. */
-	while(ca->snd_cwnd_cents >= 128) {
+	while (ca->snd_cwnd_cents >= 128) {
 		tp->snd_cwnd++;
 		ca->snd_cwnd_cents -= 128;
 		tp->snd_cwnd_cnt = 0;
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
new file mode 100644
index 0000000..4adc47c
--- /dev/null
+++ b/net/ipv4/tcp_illinois.c
@@ -0,0 +1,356 @@
+/*
+ * TCP Illinois congestion control.
+ * Home page:
+ *	http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html
+ *
+ * The algorithm is described in:
+ * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm
+ *  for High-Speed Networks"
+ * http://www.ews.uiuc.edu/~shaoliu/papersandslides/liubassri06perf.pdf
+ *
+ * Implemented from description in paper and ns-2 simulation.
+ * Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/inet_diag.h>
+#include <asm/div64.h>
+#include <net/tcp.h>
+
+#define ALPHA_SHIFT	7
+#define ALPHA_SCALE	(1u<<ALPHA_SHIFT)
+#define ALPHA_MIN	((3*ALPHA_SCALE)/10)	/* ~0.3 */
+#define ALPHA_MAX	(10*ALPHA_SCALE)	/* 10.0 */
+#define ALPHA_BASE	ALPHA_SCALE		/* 1.0 */
+#define U32_MAX		((u32)~0U)
+#define RTT_MAX		(U32_MAX / ALPHA_MAX)	/* 3.3 secs */
+
+#define BETA_SHIFT	6
+#define BETA_SCALE	(1u<<BETA_SHIFT)
+#define BETA_MIN	(BETA_SCALE/8)		/* 0.125 */
+#define BETA_MAX	(BETA_SCALE/2)		/* 0.5 */
+#define BETA_BASE	BETA_MAX
+
+static int win_thresh __read_mostly = 15;
+module_param(win_thresh, int, 0);
+MODULE_PARM_DESC(win_thresh, "Window threshold for starting adaptive sizing");
+
+static int theta __read_mostly = 5;
+module_param(theta, int, 0);
+MODULE_PARM_DESC(theta, "# of fast RTT's before full growth");
+
+/* TCP Illinois Parameters */
+struct illinois {
+	u64	sum_rtt;	/* sum of rtt's measured within last rtt */
+	u16	cnt_rtt;	/* # of rtts measured within last rtt */
+	u32	base_rtt;	/* min of all rtt in usec */
+	u32	max_rtt;	/* max of all rtt in usec */
+	u32	end_seq;	/* right edge of current RTT */
+	u32	alpha;		/* Additive increase */
+	u32	beta;		/* Muliplicative decrease */
+	u16	acked;		/* # packets acked by current ACK */
+	u8	rtt_above;	/* average rtt has gone above threshold */
+	u8	rtt_low;	/* # of rtts measurements below threshold */
+};
+
+static void rtt_reset(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct illinois *ca = inet_csk_ca(sk);
+
+	ca->end_seq = tp->snd_nxt;
+	ca->cnt_rtt = 0;
+	ca->sum_rtt = 0;
+
+	/* TODO: age max_rtt? */
+}
+
+static void tcp_illinois_init(struct sock *sk)
+{
+	struct illinois *ca = inet_csk_ca(sk);
+
+	ca->alpha = ALPHA_MAX;
+	ca->beta = BETA_BASE;
+	ca->base_rtt = 0x7fffffff;
+	ca->max_rtt = 0;
+
+	ca->acked = 0;
+	ca->rtt_low = 0;
+	ca->rtt_above = 0;
+
+	rtt_reset(sk);
+}
+
+/* Measure RTT for each ack. */
+static void tcp_illinois_acked(struct sock *sk, u32 pkts_acked, ktime_t last)
+{
+	struct illinois *ca = inet_csk_ca(sk);
+	u32 rtt;
+
+	ca->acked = pkts_acked;
+
+	rtt = ktime_to_us(net_timedelta(last));
+
+	/* ignore bogus values, this prevents wraparound in alpha math */
+	if (rtt > RTT_MAX)
+		rtt = RTT_MAX;
+
+	/* keep track of minimum RTT seen so far */
+	if (ca->base_rtt > rtt)
+		ca->base_rtt = rtt;
+
+	/* and max */
+	if (ca->max_rtt < rtt)
+		ca->max_rtt = rtt;
+
+	++ca->cnt_rtt;
+	ca->sum_rtt += rtt;
+}
+
+/* Maximum queuing delay */
+static inline u32 max_delay(const struct illinois *ca)
+{
+	return ca->max_rtt - ca->base_rtt;
+}
+
+/* Average queuing delay */
+static inline u32 avg_delay(const struct illinois *ca)
+{
+	u64 t = ca->sum_rtt;
+
+	do_div(t, ca->cnt_rtt);
+	return t - ca->base_rtt;
+}
+
+/*
+ * Compute value of alpha used for additive increase.
+ * If small window then use 1.0, equivalent to Reno.
+ *
+ * For larger windows, adjust based on average delay.
+ * A. If average delay is at minimum (we are uncongested),
+ *    then use large alpha (10.0) to increase faster.
+ * B. If average delay is at maximum (getting congested)
+ *    then use small alpha (0.3)
+ *
+ * The result is a convex window growth curve.
+ */
+static u32 alpha(struct illinois *ca, u32 da, u32 dm)
+{
+	u32 d1 = dm / 100;	/* Low threshold */
+
+	if (da <= d1) {
+		/* If never got out of low delay zone, then use max */
+		if (!ca->rtt_above)
+			return ALPHA_MAX;
+
+		/* Wait for 5 good RTT's before allowing alpha to go alpha max.
+		 * This prevents one good RTT from causing sudden window increase.
+		 */
+		if (++ca->rtt_low < theta)
+			return ca->alpha;
+
+		ca->rtt_low = 0;
+		ca->rtt_above = 0;
+		return ALPHA_MAX;
+	}
+
+	ca->rtt_above = 1;
+
+	/*
+	 * Based on:
+	 *
+	 *      (dm - d1) amin amax
+	 * k1 = -------------------
+	 *         amax - amin
+	 *
+	 *       (dm - d1) amin
+	 * k2 = ----------------  - d1
+	 *        amax - amin
+	 *
+	 *             k1
+	 * alpha = ----------
+	 *          k2 + da
+	 */
+
+	dm -= d1;
+	da -= d1;
+	return (dm * ALPHA_MAX) /
+		(dm + (da  * (ALPHA_MAX - ALPHA_MIN)) / ALPHA_MIN);
+}
+
+/*
+ * Beta used for multiplicative decrease.
+ * For small window sizes returns same value as Reno (0.5)
+ *
+ * If delay is small (10% of max) then beta = 1/8
+ * If delay is up to 80% of max then beta = 1/2
+ * In between is a linear function
+ */
+static u32 beta(u32 da, u32 dm)
+{
+	u32 d2, d3;
+
+	d2 = dm / 10;
+	if (da <= d2)
+		return BETA_MIN;
+
+	d3 = (8 * dm) / 10;
+	if (da >= d3 || d3 <= d2)
+		return BETA_MAX;
+
+	/*
+	 * Based on:
+	 *
+	 *       bmin d3 - bmax d2
+	 * k3 = -------------------
+	 *         d3 - d2
+	 *
+	 *       bmax - bmin
+	 * k4 = -------------
+	 *         d3 - d2
+	 *
+	 * b = k3 + k4 da
+	 */
+	return (BETA_MIN * d3 - BETA_MAX * d2 + (BETA_MAX - BETA_MIN) * da)
+		/ (d3 - d2);
+}
+
+/* Update alpha and beta values once per RTT */
+static void update_params(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct illinois *ca = inet_csk_ca(sk);
+
+	if (tp->snd_cwnd < win_thresh) {
+		ca->alpha = ALPHA_BASE;
+		ca->beta = BETA_BASE;
+	} else if (ca->cnt_rtt > 0) {
+		u32 dm = max_delay(ca);
+		u32 da = avg_delay(ca);
+
+		ca->alpha = alpha(ca, da, dm);
+		ca->beta = beta(da, dm);
+	}
+
+	rtt_reset(sk);
+}
+
+/*
+ * In case of loss, reset to default values
+ */
+static void tcp_illinois_state(struct sock *sk, u8 new_state)
+{
+	struct illinois *ca = inet_csk_ca(sk);
+
+	if (new_state == TCP_CA_Loss) {
+		ca->alpha = ALPHA_BASE;
+		ca->beta = BETA_BASE;
+		ca->rtt_low = 0;
+		ca->rtt_above = 0;
+		rtt_reset(sk);
+	}
+}
+
+/*
+ * Increase window in response to successful acknowledgment.
+ */
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+				    u32 in_flight, int flag)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct illinois *ca = inet_csk_ca(sk);
+
+	if (after(ack, ca->end_seq))
+		update_params(sk);
+
+	/* RFC2861 only increase cwnd if fully utilized */
+	if (!tcp_is_cwnd_limited(sk, in_flight))
+		return;
+
+	/* In slow start */
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+
+	else {
+		u32 delta;
+
+		/* snd_cwnd_cnt is # of packets since last cwnd increment */
+		tp->snd_cwnd_cnt += ca->acked;
+		ca->acked = 1;
+
+		/* This is close approximation of:
+		 * tp->snd_cwnd += alpha/tp->snd_cwnd
+		*/
+		delta = (tp->snd_cwnd_cnt * ca->alpha) >> ALPHA_SHIFT;
+		if (delta >= tp->snd_cwnd) {
+			tp->snd_cwnd = min(tp->snd_cwnd + delta / tp->snd_cwnd,
+					   (u32) tp->snd_cwnd_clamp);
+			tp->snd_cwnd_cnt = 0;
+		}
+	}
+}
+
+static u32 tcp_illinois_ssthresh(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct illinois *ca = inet_csk_ca(sk);
+
+	/* Multiplicative decrease */
+	return max((tp->snd_cwnd * ca->beta) >> BETA_SHIFT, 2U);
+}
+
+
+/* Extract info for Tcp socket info provided via netlink. */
+static void tcp_illinois_info(struct sock *sk, u32 ext,
+			      struct sk_buff *skb)
+{
+	const struct illinois *ca = inet_csk_ca(sk);
+
+	if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
+		struct tcpvegas_info info = {
+			.tcpv_enabled = 1,
+			.tcpv_rttcnt = ca->cnt_rtt,
+			.tcpv_minrtt = ca->base_rtt,
+		};
+		u64 t = ca->sum_rtt;
+
+		do_div(t, ca->cnt_rtt);
+		info.tcpv_rtt = t;
+
+		nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
+	}
+}
+
+static struct tcp_congestion_ops tcp_illinois = {
+	.flags		= TCP_CONG_RTT_STAMP,
+	.init		= tcp_illinois_init,
+	.ssthresh	= tcp_illinois_ssthresh,
+	.min_cwnd	= tcp_reno_min_cwnd,
+	.cong_avoid	= tcp_illinois_cong_avoid,
+	.set_state	= tcp_illinois_state,
+	.get_info	= tcp_illinois_info,
+	.pkts_acked	= tcp_illinois_acked,
+
+	.owner		= THIS_MODULE,
+	.name		= "illinois",
+};
+
+static int __init tcp_illinois_register(void)
+{
+	BUILD_BUG_ON(sizeof(struct illinois) > ICSK_CA_PRIV_SIZE);
+	return tcp_register_congestion_control(&tcp_illinois);
+}
+
+static void __exit tcp_illinois_unregister(void)
+{
+	tcp_unregister_congestion_control(&tcp_illinois);
+}
+
+module_init(tcp_illinois_register);
+module_exit(tcp_illinois_unregister);
+
+MODULE_AUTHOR("Stephen Hemminger, Shao Liu");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TCP Illinois");
+MODULE_VERSION("1.0");
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1a14191..7641b27 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -86,6 +86,7 @@ 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_frto_response __read_mostly;
 int sysctl_tcp_nometrics_save __read_mostly;
 
 int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
@@ -100,6 +101,7 @@ #define FLAG_DATA_SACKED	0x20 /* New SAC
 #define FLAG_ECE		0x40 /* ECE in this ACK				*/
 #define FLAG_DATA_LOST		0x80 /* SACK detected data lossage.		*/
 #define FLAG_SLOWPATH		0x100 /* Do not skip RFC checks for window update.*/
+#define FLAG_ONLY_ORIG_SACKED	0x200 /* SACKs only non-rexmit sent before RTO */
 
 #define FLAG_ACKED		(FLAG_DATA_ACKED|FLAG_SYN_ACKED)
 #define FLAG_NOT_DUP		(FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -110,6 +112,8 @@ #define IsReno(tp) ((tp)->rx_opt.sack_ok
 #define IsFack(tp) ((tp)->rx_opt.sack_ok & 2)
 #define IsDSack(tp) ((tp)->rx_opt.sack_ok & 4)
 
+#define IsSackFrto() (sysctl_tcp_frto == 0x2)
+
 #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH)
 
 /* Adapt the MSS value used to make delayed ack decision to the
@@ -136,7 +140,7 @@ static void tcp_measure_rcv_mss(struct s
 		 *
 		 * "len" is invariant segment length, including TCP header.
 		 */
-		len += skb->data - skb->h.raw;
+		len += skb->data - skb_transport_header(skb);
 		if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) ||
 		    /* If PSH is not set, packet should be
 		     * full sized, provided peer TCP is not badly broken.
@@ -144,7 +148,7 @@ static void tcp_measure_rcv_mss(struct s
 		     * to handle super-low mtu links fairly.
 		     */
 		    (len >= TCP_MIN_MSS + sizeof(struct tcphdr) &&
-		     !(tcp_flag_word(skb->h.th)&TCP_REMNANT))) {
+		     !(tcp_flag_word(tcp_hdr(skb)) & TCP_REMNANT))) {
 			/* Subtract also invariant (if peer is RFC compliant),
 			 * tcp header plus fixed timestamp option length.
 			 * Resulting "len" is MSS free of SACK jitter.
@@ -231,9 +235,9 @@ static void tcp_fixup_sndbuf(struct sock
  */
 
 /* Slow part of check#2. */
-static int __tcp_grow_window(const struct sock *sk, struct tcp_sock *tp,
-			     const struct sk_buff *skb)
+static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	/* Optimize this! */
 	int truesize = tcp_win_from_space(skb->truesize)/2;
 	int window = tcp_win_from_space(sysctl_tcp_rmem[2])/2;
@@ -248,9 +252,11 @@ static int __tcp_grow_window(const struc
 	return 0;
 }
 
-static void tcp_grow_window(struct sock *sk, struct tcp_sock *tp,
+static void tcp_grow_window(struct sock *sk,
 			    struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	/* Check #1 */
 	if (tp->rcv_ssthresh < tp->window_clamp &&
 	    (int)tp->rcv_ssthresh < tcp_space(sk) &&
@@ -263,7 +269,7 @@ static void tcp_grow_window(struct sock 
 		if (tcp_win_from_space(skb->truesize) <= skb->len)
 			incr = 2*tp->advmss;
 		else
-			incr = __tcp_grow_window(sk, tp, skb);
+			incr = __tcp_grow_window(sk, skb);
 
 		if (incr) {
 			tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, tp->window_clamp);
@@ -326,8 +332,9 @@ static void tcp_init_buffer_space(struct
 }
 
 /* 5. Recalculate window clamp after socket hit its memory bounds. */
-static void tcp_clamp_window(struct sock *sk, struct tcp_sock *tp)
+static void tcp_clamp_window(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	icsk->icsk_ack.quick = 0;
@@ -499,8 +506,9 @@ new_measure:
  * each ACK we send, he increments snd_cwnd and transmits more of his
  * queue.  -DaveM
  */
-static void tcp_event_data_recv(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
+static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 	u32 now;
 
@@ -541,7 +549,7 @@ static void tcp_event_data_recv(struct s
 	TCP_ECN_check_ce(tp, skb);
 
 	if (skb->len >= 128)
-		tcp_grow_window(sk, tp, skb);
+		tcp_grow_window(sk, skb);
 }
 
 /* Called to compute a smoothed rtt estimate. The data fed to this
@@ -574,7 +582,7 @@ static void tcp_rtt_estimator(struct soc
 	 * does not matter how to _calculate_ it. Seems, it was trap
 	 * that VJ failed to avoid. 8)
 	 */
-	if(m == 0)
+	if (m == 0)
 		m = 1;
 	if (tp->srtt != 0) {
 		m -= (tp->srtt >> 3);	/* m is now error in rtt est */
@@ -759,15 +767,17 @@ __u32 tcp_init_cwnd(struct tcp_sock *tp,
 }
 
 /* Set slow start threshold and cwnd not falling to slow start */
-void tcp_enter_cwr(struct sock *sk)
+void tcp_enter_cwr(struct sock *sk, const int set_ssthresh)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
+	const struct inet_connection_sock *icsk = inet_csk(sk);
 
 	tp->prior_ssthresh = 0;
 	tp->bytes_acked = 0;
-	if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
+	if (icsk->icsk_ca_state < TCP_CA_CWR) {
 		tp->undo_marker = 0;
-		tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk);
+		if (set_ssthresh)
+			tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
 		tp->snd_cwnd = min(tp->snd_cwnd,
 				   tcp_packets_in_flight(tp) + 1U);
 		tp->snd_cwnd_cnt = 0;
@@ -934,7 +944,8 @@ 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;
+	unsigned char *ptr = (skb_transport_header(ack_skb) +
+			      TCP_SKB_CB(ack_skb)->sacked);
 	struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
 	struct sk_buff *cached_skb;
 	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
@@ -1038,7 +1049,7 @@ tcp_sacktag_write_queue(struct sock *sk,
 	cached_skb = tp->fastpath_skb_hint;
 	cached_fack_count = tp->fastpath_cnt_hint;
 	if (!cached_skb) {
-		cached_skb = sk->sk_write_queue.next;
+		cached_skb = tcp_write_queue_head(sk);
 		cached_fack_count = 0;
 	}
 
@@ -1055,10 +1066,13 @@ tcp_sacktag_write_queue(struct sock *sk,
 		if (after(end_seq, tp->high_seq))
 			flag |= FLAG_DATA_LOST;
 
-		sk_stream_for_retrans_queue_from(skb, sk) {
+		tcp_for_write_queue_from(skb, sk) {
 			int in_sack, pcount;
 			u8 sacked;
 
+			if (skb == tcp_send_head(sk))
+				break;
+
 			cached_skb = skb;
 			cached_fack_count = fack_count;
 			if (i == first_sack_index) {
@@ -1159,6 +1173,18 @@ tcp_sacktag_write_queue(struct sock *sk,
 						/* clear lost hint */
 						tp->retransmit_skb_hint = NULL;
 					}
+					/* SACK enhanced F-RTO detection.
+					 * Set flag if and only if non-rexmitted
+					 * segments below frto_highmark are
+					 * SACKed (RFC4138; Appendix B).
+					 * Clearing correct due to in-order walk
+					 */
+					if (after(end_seq, tp->frto_highmark)) {
+						flag &= ~FLAG_ONLY_ORIG_SACKED;
+					} else {
+						if (!(sacked & TCPCB_RETRANS))
+							flag |= FLAG_ONLY_ORIG_SACKED;
+					}
 				}
 
 				TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
@@ -1195,7 +1221,9 @@ tcp_sacktag_write_queue(struct sock *sk,
 	if (lost_retrans && icsk->icsk_ca_state == TCP_CA_Recovery) {
 		struct sk_buff *skb;
 
-		sk_stream_for_retrans_queue(skb, sk) {
+		tcp_for_write_queue(skb, sk) {
+			if (skb == tcp_send_head(sk))
+				break;
 			if (after(TCP_SKB_CB(skb)->seq, lost_retrans))
 				break;
 			if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una))
@@ -1224,7 +1252,8 @@ tcp_sacktag_write_queue(struct sock *sk,
 
 	tp->left_out = tp->sacked_out + tp->lost_out;
 
-	if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss)
+	if ((reord < tp->fackets_out) && icsk->icsk_ca_state != TCP_CA_Loss &&
+	    (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark)))
 		tcp_update_reordering(sk, ((tp->fackets_out + 1) - reord), 0);
 
 #if FASTRETRANS_DEBUG > 0
@@ -1236,9 +1265,49 @@ #endif
 	return flag;
 }
 
-/* RTO occurred, but do not yet enter loss state. Instead, transmit two new
- * segments to see from the next ACKs whether any data was really missing.
- * If the RTO was spurious, new ACKs should arrive.
+/* F-RTO can only be used if TCP has never retransmitted anything other than
+ * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here)
+ */
+int tcp_use_frto(struct sock *sk)
+{
+	const struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+
+	if (!sysctl_tcp_frto)
+		return 0;
+
+	if (IsSackFrto())
+		return 1;
+
+	/* Avoid expensive walking of rexmit queue if possible */
+	if (tp->retrans_out > 1)
+		return 0;
+
+	skb = tcp_write_queue_head(sk);
+	skb = tcp_write_queue_next(sk, skb);	/* Skips head */
+	tcp_for_write_queue_from(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
+		if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
+			return 0;
+		/* Short-circuit when first non-SACKed skb has been checked */
+		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED))
+			break;
+	}
+	return 1;
+}
+
+/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO
+ * recovery a bit and use heuristics in tcp_process_frto() to detect if
+ * the RTO was spurious. Only clear SACKED_RETRANS of the head here to
+ * keep retrans_out counting accurate (with SACK F-RTO, other than head
+ * may still have that bit set); TCPCB_LOST and remaining SACKED_RETRANS
+ * bits are handled if the Loss state is really to be entered (in
+ * tcp_enter_frto_loss).
+ *
+ * Do like tcp_enter_loss() would; when RTO expires the second time it
+ * does:
+ *  "Reduce ssthresh if it has not yet been made inside this window."
  */
 void tcp_enter_frto(struct sock *sk)
 {
@@ -1246,39 +1315,69 @@ void tcp_enter_frto(struct sock *sk)
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 
-	tp->frto_counter = 1;
-
-	if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
+	if ((!tp->frto_counter && icsk->icsk_ca_state <= TCP_CA_Disorder) ||
 	    tp->snd_una == tp->high_seq ||
-	    (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
+	    ((icsk->icsk_ca_state == TCP_CA_Loss || tp->frto_counter) &&
+	     !icsk->icsk_retransmits)) {
 		tp->prior_ssthresh = tcp_current_ssthresh(sk);
-		tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+		/* Our state is too optimistic in ssthresh() call because cwnd
+		 * is not reduced until tcp_enter_frto_loss() when previous FRTO
+		 * recovery has not yet completed. Pattern would be this: RTO,
+		 * Cumulative ACK, RTO (2xRTO for the same segment does not end
+		 * up here twice).
+		 * RFC4138 should be more specific on what to do, even though
+		 * RTO is quite unlikely to occur after the first Cumulative ACK
+		 * due to back-off and complexity of triggering events ...
+		 */
+		if (tp->frto_counter) {
+			u32 stored_cwnd;
+			stored_cwnd = tp->snd_cwnd;
+			tp->snd_cwnd = 2;
+			tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+			tp->snd_cwnd = stored_cwnd;
+		} else {
+			tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
+		}
+		/* ... in theory, cong.control module could do "any tricks" in
+		 * ssthresh(), which means that ca_state, lost bits and lost_out
+		 * counter would have to be faked before the call occurs. We
+		 * consider that too expensive, unlikely and hacky, so modules
+		 * using these in ssthresh() must deal these incompatibility
+		 * issues if they receives CA_EVENT_FRTO and frto_counter != 0
+		 */
 		tcp_ca_event(sk, CA_EVENT_FRTO);
 	}
 
-	/* Have to clear retransmission markers here to keep the bookkeeping
-	 * in shape, even though we are not yet in Loss state.
-	 * If something was really lost, it is eventually caught up
-	 * in tcp_enter_frto_loss.
-	 */
-	tp->retrans_out = 0;
 	tp->undo_marker = tp->snd_una;
 	tp->undo_retrans = 0;
 
-	sk_stream_for_retrans_queue(skb, sk) {
-		TCP_SKB_CB(skb)->sacked &= ~TCPCB_RETRANS;
+	skb = tcp_write_queue_head(sk);
+	if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
+		TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
+		tp->retrans_out -= tcp_skb_pcount(skb);
 	}
 	tcp_sync_left_out(tp);
 
-	tcp_set_ca_state(sk, TCP_CA_Open);
-	tp->frto_highmark = tp->snd_nxt;
+	/* Earlier loss recovery underway (see RFC4138; Appendix B).
+	 * The last condition is necessary at least in tp->frto_counter case.
+	 */
+	if (IsSackFrto() && (tp->frto_counter ||
+	    ((1 << icsk->icsk_ca_state) & (TCPF_CA_Recovery|TCPF_CA_Loss))) &&
+	    after(tp->high_seq, tp->snd_una)) {
+		tp->frto_highmark = tp->high_seq;
+	} else {
+		tp->frto_highmark = tp->snd_nxt;
+	}
+	tcp_set_ca_state(sk, TCP_CA_Disorder);
+	tp->high_seq = tp->snd_nxt;
+	tp->frto_counter = 1;
 }
 
 /* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
  * which indicates that we should follow the traditional RTO recovery,
  * i.e. mark everything lost and do go-back-N retransmission.
  */
-static void tcp_enter_frto_loss(struct sock *sk)
+static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
@@ -1287,10 +1386,23 @@ static void tcp_enter_frto_loss(struct s
 	tp->sacked_out = 0;
 	tp->lost_out = 0;
 	tp->fackets_out = 0;
+	tp->retrans_out = 0;
 
-	sk_stream_for_retrans_queue(skb, sk) {
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
 		cnt += tcp_skb_pcount(skb);
-		TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+		/*
+		 * Count the retransmission made on RTO correctly (only when
+		 * waiting for the first ACK and did not get it)...
+		 */
+		if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
+			tp->retrans_out += tcp_skb_pcount(skb);
+			/* ...enter this if branch just for the first segment */
+			flag |= FLAG_DATA_ACKED;
+		} else {
+			TCP_SKB_CB(skb)->sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS);
+		}
 		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) {
 
 			/* Do not mark those segments lost that were
@@ -1308,7 +1420,7 @@ static void tcp_enter_frto_loss(struct s
 	}
 	tcp_sync_left_out(tp);
 
-	tp->snd_cwnd = tp->frto_counter + tcp_packets_in_flight(tp)+1;
+	tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments;
 	tp->snd_cwnd_cnt = 0;
 	tp->snd_cwnd_stamp = tcp_time_stamp;
 	tp->undo_marker = 0;
@@ -1366,7 +1478,9 @@ void tcp_enter_loss(struct sock *sk, int
 	if (!how)
 		tp->undo_marker = tp->snd_una;
 
-	sk_stream_for_retrans_queue(skb, sk) {
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
 		cnt += tcp_skb_pcount(skb);
 		if (TCP_SKB_CB(skb)->sacked&TCPCB_RETRANS)
 			tp->undo_marker = 0;
@@ -1401,14 +1515,14 @@ static int tcp_check_sack_reneging(struc
 	 * receiver _host_ is heavily congested (or buggy).
 	 * Do processing similar to RTO timeout.
 	 */
-	if ((skb = skb_peek(&sk->sk_write_queue)) != NULL &&
+	if ((skb = tcp_write_queue_head(sk)) != NULL &&
 	    (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
 		struct inet_connection_sock *icsk = inet_csk(sk);
 		NET_INC_STATS_BH(LINUX_MIB_TCPSACKRENEGING);
 
 		tcp_enter_loss(sk, 1);
 		icsk->icsk_retransmits++;
-		tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue));
+		tcp_retransmit_skb(sk, tcp_write_queue_head(sk));
 		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
 					  icsk->icsk_rto, TCP_RTO_MAX);
 		return 1;
@@ -1426,10 +1540,12 @@ static inline int tcp_skb_timedout(struc
 	return (tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto);
 }
 
-static inline int tcp_head_timedout(struct sock *sk, struct tcp_sock *tp)
+static inline int tcp_head_timedout(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	return tp->packets_out &&
-	       tcp_skb_timedout(sk, skb_peek(&sk->sk_write_queue));
+	       tcp_skb_timedout(sk, tcp_write_queue_head(sk));
 }
 
 /* Linux NewReno/SACK/FACK/ECN state machine.
@@ -1525,10 +1641,15 @@ static inline int tcp_head_timedout(stru
  * Main question: may we further continue forward transmission
  * with the same cwnd?
  */
-static int tcp_time_to_recover(struct sock *sk, struct tcp_sock *tp)
+static int tcp_time_to_recover(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	__u32 packets_out;
 
+	/* Do not perform any recovery during FRTO algorithm */
+	if (tp->frto_counter)
+		return 0;
+
 	/* Trick#1: The loss is proven. */
 	if (tp->lost_out)
 		return 1;
@@ -1540,7 +1661,7 @@ static int tcp_time_to_recover(struct so
 	/* Trick#3 : when we use RFC2988 timer restart, fast
 	 * retransmit can be triggered by timeout of queue head.
 	 */
-	if (tcp_head_timedout(sk, tp))
+	if (tcp_head_timedout(sk))
 		return 1;
 
 	/* Trick#4: It is still not OK... But will it be useful to delay
@@ -1549,7 +1670,7 @@ static int tcp_time_to_recover(struct so
 	packets_out = tp->packets_out;
 	if (packets_out <= tp->reordering &&
 	    tp->sacked_out >= max_t(__u32, packets_out/2, sysctl_tcp_reordering) &&
-	    !tcp_may_send_now(sk, tp)) {
+	    !tcp_may_send_now(sk)) {
 		/* We have nothing to send. This connection is limited
 		 * either by receiver window or by application.
 		 */
@@ -1589,8 +1710,10 @@ static void tcp_add_reno_sack(struct soc
 
 /* Account for ACK, ACKing some data in Reno Recovery phase. */
 
-static void tcp_remove_reno_sacks(struct sock *sk, struct tcp_sock *tp, int acked)
+static void tcp_remove_reno_sacks(struct sock *sk, int acked)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (acked > 0) {
 		/* One ACK acked hole. The rest eat duplicate ACKs. */
 		if (acked-1 >= tp->sacked_out)
@@ -1609,9 +1732,10 @@ static inline void tcp_reset_reno_sack(s
 }
 
 /* Mark head of queue up as lost. */
-static void tcp_mark_head_lost(struct sock *sk, struct tcp_sock *tp,
+static void tcp_mark_head_lost(struct sock *sk,
 			       int packets, u32 high_seq)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 	int cnt;
 
@@ -1620,11 +1744,13 @@ static void tcp_mark_head_lost(struct so
 		skb = tp->lost_skb_hint;
 		cnt = tp->lost_cnt_hint;
 	} else {
-		skb = sk->sk_write_queue.next;
+		skb = tcp_write_queue_head(sk);
 		cnt = 0;
 	}
 
-	sk_stream_for_retrans_queue_from(skb, sk) {
+	tcp_for_write_queue_from(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
 		/* TODO: do this better */
 		/* this is not the most efficient way to do this... */
 		tp->lost_skb_hint = skb;
@@ -1638,12 +1764,11 @@ static void tcp_mark_head_lost(struct so
 
 			/* clear xmit_retransmit_queue hints
 			 *  if this is beyond hint */
-			if(tp->retransmit_skb_hint != NULL &&
-			   before(TCP_SKB_CB(skb)->seq,
-				  TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) {
-
+			if (tp->retransmit_skb_hint != NULL &&
+			    before(TCP_SKB_CB(skb)->seq,
+				   TCP_SKB_CB(tp->retransmit_skb_hint)->seq))
 				tp->retransmit_skb_hint = NULL;
-			}
+
 		}
 	}
 	tcp_sync_left_out(tp);
@@ -1651,15 +1776,17 @@ static void tcp_mark_head_lost(struct so
 
 /* Account newly detected lost packet(s) */
 
-static void tcp_update_scoreboard(struct sock *sk, struct tcp_sock *tp)
+static void tcp_update_scoreboard(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (IsFack(tp)) {
 		int lost = tp->fackets_out - tp->reordering;
 		if (lost <= 0)
 			lost = 1;
-		tcp_mark_head_lost(sk, tp, lost, tp->high_seq);
+		tcp_mark_head_lost(sk, lost, tp->high_seq);
 	} else {
-		tcp_mark_head_lost(sk, tp, 1, tp->high_seq);
+		tcp_mark_head_lost(sk, 1, tp->high_seq);
 	}
 
 	/* New heuristics: it is possible only after we switched
@@ -1667,13 +1794,15 @@ static void tcp_update_scoreboard(struct
 	 * Hence, we can detect timed out packets during fast
 	 * retransmit without falling to slow start.
 	 */
-	if (!IsReno(tp) && tcp_head_timedout(sk, tp)) {
+	if (!IsReno(tp) && tcp_head_timedout(sk)) {
 		struct sk_buff *skb;
 
 		skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint
-			: sk->sk_write_queue.next;
+			: tcp_write_queue_head(sk);
 
-		sk_stream_for_retrans_queue_from(skb, sk) {
+		tcp_for_write_queue_from(skb, sk) {
+			if (skb == tcp_send_head(sk))
+				break;
 			if (!tcp_skb_timedout(sk, skb))
 				break;
 
@@ -1745,9 +1874,11 @@ static inline int tcp_packet_delayed(str
 /* Undo procedures. */
 
 #if FASTRETRANS_DEBUG > 1
-static void DBGUNDO(struct sock *sk, struct tcp_sock *tp, const char *msg)
+static void DBGUNDO(struct sock *sk, const char *msg)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	struct inet_sock *inet = inet_sk(sk);
+
 	printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n",
 	       msg,
 	       NIPQUAD(inet->daddr), ntohs(inet->dport),
@@ -1793,13 +1924,15 @@ static inline int tcp_may_undo(struct tc
 }
 
 /* People celebrate: "We love our President!" */
-static int tcp_try_undo_recovery(struct sock *sk, struct tcp_sock *tp)
+static int tcp_try_undo_recovery(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (tcp_may_undo(tp)) {
 		/* Happy end! We did not retransmit anything
 		 * or our original transmission succeeded.
 		 */
-		DBGUNDO(sk, tp, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans");
+		DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans");
 		tcp_undo_cwr(sk, 1);
 		if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
 			NET_INC_STATS_BH(LINUX_MIB_TCPLOSSUNDO);
@@ -1819,10 +1952,12 @@ static int tcp_try_undo_recovery(struct 
 }
 
 /* Try to undo cwnd reduction, because D-SACKs acked all retransmitted data */
-static void tcp_try_undo_dsack(struct sock *sk, struct tcp_sock *tp)
+static void tcp_try_undo_dsack(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (tp->undo_marker && !tp->undo_retrans) {
-		DBGUNDO(sk, tp, "D-SACK");
+		DBGUNDO(sk, "D-SACK");
 		tcp_undo_cwr(sk, 1);
 		tp->undo_marker = 0;
 		NET_INC_STATS_BH(LINUX_MIB_TCPDSACKUNDO);
@@ -1831,9 +1966,9 @@ static void tcp_try_undo_dsack(struct so
 
 /* Undo during fast recovery after partial ACK. */
 
-static int tcp_try_undo_partial(struct sock *sk, struct tcp_sock *tp,
-				int acked)
+static int tcp_try_undo_partial(struct sock *sk, int acked)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	/* Partial ACK arrived. Force Hoe's retransmit. */
 	int failed = IsReno(tp) || tp->fackets_out>tp->reordering;
 
@@ -1846,7 +1981,7 @@ static int tcp_try_undo_partial(struct s
 
 		tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1);
 
-		DBGUNDO(sk, tp, "Hoe");
+		DBGUNDO(sk, "Hoe");
 		tcp_undo_cwr(sk, 0);
 		NET_INC_STATS_BH(LINUX_MIB_TCPPARTIALUNDO);
 
@@ -1860,17 +1995,21 @@ static int tcp_try_undo_partial(struct s
 }
 
 /* Undo during loss recovery after partial ACK. */
-static int tcp_try_undo_loss(struct sock *sk, struct tcp_sock *tp)
+static int tcp_try_undo_loss(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (tcp_may_undo(tp)) {
 		struct sk_buff *skb;
-		sk_stream_for_retrans_queue(skb, sk) {
+		tcp_for_write_queue(skb, sk) {
+			if (skb == tcp_send_head(sk))
+				break;
 			TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
 		}
 
 		clear_all_retrans_hints(tp);
 
-		DBGUNDO(sk, tp, "partial loss");
+		DBGUNDO(sk, "partial loss");
 		tp->lost_out = 0;
 		tp->left_out = tp->sacked_out;
 		tcp_undo_cwr(sk, 1);
@@ -1892,15 +2031,17 @@ static inline void tcp_complete_cwr(stru
 	tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);
 }
 
-static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
+static void tcp_try_to_open(struct sock *sk, int flag)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	tp->left_out = tp->sacked_out;
 
 	if (tp->retrans_out == 0)
 		tp->retrans_stamp = 0;
 
 	if (flag&FLAG_ECE)
-		tcp_enter_cwr(sk);
+		tcp_enter_cwr(sk, 1);
 
 	if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
 		int state = TCP_CA_Open;
@@ -1987,7 +2128,7 @@ tcp_fastretrans_alert(struct sock *sk, u
 	    before(tp->snd_una, tp->high_seq) &&
 	    icsk->icsk_ca_state != TCP_CA_Open &&
 	    tp->fackets_out > tp->reordering) {
-		tcp_mark_head_lost(sk, tp, tp->fackets_out-tp->reordering, tp->high_seq);
+		tcp_mark_head_lost(sk, tp->fackets_out-tp->reordering, tp->high_seq);
 		NET_INC_STATS_BH(LINUX_MIB_TCPLOSS);
 	}
 
@@ -1997,14 +2138,13 @@ tcp_fastretrans_alert(struct sock *sk, u
 	/* E. Check state exit conditions. State can be terminated
 	 *    when high_seq is ACKed. */
 	if (icsk->icsk_ca_state == TCP_CA_Open) {
-		if (!sysctl_tcp_frto)
-			BUG_TRAP(tp->retrans_out == 0);
+		BUG_TRAP(tp->retrans_out == 0);
 		tp->retrans_stamp = 0;
 	} else if (!before(tp->snd_una, tp->high_seq)) {
 		switch (icsk->icsk_ca_state) {
 		case TCP_CA_Loss:
 			icsk->icsk_retransmits = 0;
-			if (tcp_try_undo_recovery(sk, tp))
+			if (tcp_try_undo_recovery(sk))
 				return;
 			break;
 
@@ -2018,7 +2158,7 @@ tcp_fastretrans_alert(struct sock *sk, u
 			break;
 
 		case TCP_CA_Disorder:
-			tcp_try_undo_dsack(sk, tp);
+			tcp_try_undo_dsack(sk);
 			if (!tp->undo_marker ||
 			    /* For SACK case do not Open to allow to undo
 			     * catching for all duplicate ACKs. */
@@ -2031,7 +2171,7 @@ tcp_fastretrans_alert(struct sock *sk, u
 		case TCP_CA_Recovery:
 			if (IsReno(tp))
 				tcp_reset_reno_sack(tp);
-			if (tcp_try_undo_recovery(sk, tp))
+			if (tcp_try_undo_recovery(sk))
 				return;
 			tcp_complete_cwr(sk);
 			break;
@@ -2047,14 +2187,14 @@ tcp_fastretrans_alert(struct sock *sk, u
 		} else {
 			int acked = prior_packets - tp->packets_out;
 			if (IsReno(tp))
-				tcp_remove_reno_sacks(sk, tp, acked);
-			is_dupack = tcp_try_undo_partial(sk, tp, acked);
+				tcp_remove_reno_sacks(sk, acked);
+			is_dupack = tcp_try_undo_partial(sk, acked);
 		}
 		break;
 	case TCP_CA_Loss:
 		if (flag&FLAG_DATA_ACKED)
 			icsk->icsk_retransmits = 0;
-		if (!tcp_try_undo_loss(sk, tp)) {
+		if (!tcp_try_undo_loss(sk)) {
 			tcp_moderate_cwnd(tp);
 			tcp_xmit_retransmit_queue(sk);
 			return;
@@ -2071,10 +2211,10 @@ tcp_fastretrans_alert(struct sock *sk, u
 		}
 
 		if (icsk->icsk_ca_state == TCP_CA_Disorder)
-			tcp_try_undo_dsack(sk, tp);
+			tcp_try_undo_dsack(sk);
 
-		if (!tcp_time_to_recover(sk, tp)) {
-			tcp_try_to_open(sk, tp, flag);
+		if (!tcp_time_to_recover(sk)) {
+			tcp_try_to_open(sk, flag);
 			return;
 		}
 
@@ -2113,8 +2253,8 @@ tcp_fastretrans_alert(struct sock *sk, u
 		tcp_set_ca_state(sk, TCP_CA_Recovery);
 	}
 
-	if (is_dupack || tcp_head_timedout(sk, tp))
-		tcp_update_scoreboard(sk, tp);
+	if (is_dupack || tcp_head_timedout(sk))
+		tcp_update_scoreboard(sk);
 	tcp_cwnd_down(sk);
 	tcp_xmit_retransmit_queue(sk);
 }
@@ -2190,8 +2330,10 @@ static void tcp_cong_avoid(struct sock *
  * RFC2988 recommends to restart timer to now+rto.
  */
 
-static void tcp_ack_packets_out(struct sock *sk, struct tcp_sock *tp)
+static void tcp_ack_packets_out(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (!tp->packets_out) {
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 	} else {
@@ -2255,14 +2397,6 @@ static int tcp_tso_acked(struct sock *sk
 	return acked;
 }
 
-static u32 tcp_usrtt(struct timeval *tv)
-{
-	struct timeval now;
-
-	do_gettimeofday(&now);
-	return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - tv->tv_usec);
-}
-
 /* Remove acknowledged frames from the retransmission queue. */
 static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
 {
@@ -2273,12 +2407,10 @@ static int tcp_clean_rtx_queue(struct so
 	int acked = 0;
 	__s32 seq_rtt = -1;
 	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 };
+	ktime_t last_ackt = ktime_set(0,0);
 
-	while ((skb = skb_peek(&sk->sk_write_queue)) &&
-	       skb != sk->sk_send_head) {
+	while ((skb = tcp_write_queue_head(sk)) &&
+	       skb != tcp_send_head(sk)) {
 		struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
 		__u8 sacked = scb->sacked;
 
@@ -2318,13 +2450,13 @@ static int tcp_clean_rtx_queue(struct so
 
 		if (sacked) {
 			if (sacked & TCPCB_RETRANS) {
-				if(sacked & TCPCB_SACKED_RETRANS)
+				if (sacked & TCPCB_SACKED_RETRANS)
 					tp->retrans_out -= tcp_skb_pcount(skb);
 				acked |= FLAG_RETRANS_DATA_ACKED;
 				seq_rtt = -1;
 			} else if (seq_rtt < 0) {
 				seq_rtt = now - scb->when;
-				skb_get_timestamp(skb, &tv);
+				last_ackt = skb->tstamp;
 			}
 			if (sacked & TCPCB_SACKED_ACKED)
 				tp->sacked_out -= tcp_skb_pcount(skb);
@@ -2337,23 +2469,24 @@ static int tcp_clean_rtx_queue(struct so
 			}
 		} else if (seq_rtt < 0) {
 			seq_rtt = now - scb->when;
-			skb_get_timestamp(skb, &tv);
+			last_ackt = skb->tstamp;
 		}
 		tcp_dec_pcount_approx(&tp->fackets_out, skb);
 		tcp_packets_out_dec(tp, skb);
-		__skb_unlink(skb, &sk->sk_write_queue);
+		tcp_unlink_write_queue(skb, sk);
 		sk_stream_free_skb(sk, skb);
 		clear_all_retrans_hints(tp);
 	}
 
 	if (acked&FLAG_ACKED) {
+		const struct tcp_congestion_ops *ca_ops
+			= inet_csk(sk)->icsk_ca_ops;
+
 		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));
+		tcp_ack_packets_out(sk);
 
-		if (icsk->icsk_ca_ops->pkts_acked)
-			icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked);
+		if (ca_ops->pkts_acked)
+			ca_ops->pkts_acked(sk, pkts_acked, last_ackt);
 	}
 
 #if FASTRETRANS_DEBUG > 0
@@ -2390,7 +2523,7 @@ static void tcp_ack_probe(struct sock *s
 
 	/* Was it a usable window open? */
 
-	if (!after(TCP_SKB_CB(sk->sk_send_head)->end_seq,
+	if (!after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
 		   tp->snd_una + tp->snd_wnd)) {
 		icsk->icsk_backoff = 0;
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_PROBE0);
@@ -2433,13 +2566,14 @@ static inline int tcp_may_update_window(
  * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2
  * and in FreeBSD. NetBSD's one is even worse.) is wrong.
  */
-static int tcp_ack_update_window(struct sock *sk, struct tcp_sock *tp,
-				 struct sk_buff *skb, u32 ack, u32 ack_seq)
+static int tcp_ack_update_window(struct sock *sk, struct sk_buff *skb, u32 ack,
+				 u32 ack_seq)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	int flag = 0;
-	u32 nwin = ntohs(skb->h.th->window);
+	u32 nwin = ntohs(tcp_hdr(skb)->window);
 
-	if (likely(!skb->h.th->syn))
+	if (likely(!tcp_hdr(skb)->syn))
 		nwin <<= tp->rx_opt.snd_wscale;
 
 	if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
@@ -2453,7 +2587,7 @@ static int tcp_ack_update_window(struct 
 			 * fast path is recovered for sending TCP.
 			 */
 			tp->pred_flags = 0;
-			tcp_fast_path_check(sk, tp);
+			tcp_fast_path_check(sk);
 
 			if (nwin > tp->max_window) {
 				tp->max_window = nwin;
@@ -2467,39 +2601,139 @@ static int tcp_ack_update_window(struct 
 	return flag;
 }
 
-static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
+/* A very conservative spurious RTO response algorithm: reduce cwnd and
+ * continue in congestion avoidance.
+ */
+static void tcp_conservative_spur_to_response(struct tcp_sock *tp)
+{
+	tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+	tp->snd_cwnd_cnt = 0;
+	tcp_moderate_cwnd(tp);
+}
+
+/* A conservative spurious RTO response algorithm: reduce cwnd using
+ * rate halving and continue in congestion avoidance.
+ */
+static void tcp_ratehalving_spur_to_response(struct sock *sk)
+{
+	tcp_enter_cwr(sk, 0);
+}
+
+static void tcp_undo_spur_to_response(struct sock *sk, int flag)
+{
+	if (flag&FLAG_ECE)
+		tcp_ratehalving_spur_to_response(sk);
+	else
+		tcp_undo_cwr(sk, 1);
+}
+
+/* F-RTO spurious RTO detection algorithm (RFC4138)
+ *
+ * F-RTO affects during two new ACKs following RTO (well, almost, see inline
+ * comments). State (ACK number) is kept in frto_counter. When ACK advances
+ * window (but not to or beyond highest sequence sent before RTO):
+ *   On First ACK,  send two new segments out.
+ *   On Second ACK, RTO was likely spurious. Do spurious response (response
+ *                  algorithm is not part of the F-RTO detection algorithm
+ *                  given in RFC4138 but can be selected separately).
+ * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss
+ * and TCP falls back to conventional RTO recovery. F-RTO allows overriding
+ * of Nagle, this is done using frto_counter states 2 and 3, when a new data
+ * segment of any size sent during F-RTO, state 2 is upgraded to 3.
+ *
+ * Rationale: if the RTO was spurious, new ACKs should arrive from the
+ * original window even after we transmit two new data segments.
+ *
+ * SACK version:
+ *   on first step, wait until first cumulative ACK arrives, then move to
+ *   the second step. In second step, the next ACK decides.
+ *
+ * F-RTO is implemented (mainly) in four functions:
+ *   - tcp_use_frto() is used to determine if TCP is can use F-RTO
+ *   - tcp_enter_frto() prepares TCP state on RTO if F-RTO is used, it is
+ *     called when tcp_use_frto() showed green light
+ *   - tcp_process_frto() handles incoming ACKs during F-RTO algorithm
+ *   - tcp_enter_frto_loss() is called if there is not enough evidence
+ *     to prove that the RTO is indeed spurious. It transfers the control
+ *     from F-RTO to the conventional RTO recovery
+ */
+static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	tcp_sync_left_out(tp);
 
-	if (tp->snd_una == prior_snd_una ||
-	    !before(tp->snd_una, tp->frto_highmark)) {
-		/* RTO was caused by loss, start retransmitting in
-		 * go-back-N slow start
+	/* Duplicate the behavior from Loss state (fastretrans_alert) */
+	if (flag&FLAG_DATA_ACKED)
+		inet_csk(sk)->icsk_retransmits = 0;
+
+	if (!before(tp->snd_una, tp->frto_highmark)) {
+		tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag);
+		return 1;
+	}
+
+	if (!IsSackFrto() || IsReno(tp)) {
+		/* RFC4138 shortcoming in step 2; should also have case c):
+		 * ACK isn't duplicate nor advances window, e.g., opposite dir
+		 * data, winupdate
 		 */
-		tcp_enter_frto_loss(sk);
-		return;
+		if ((tp->snd_una == prior_snd_una) && (flag&FLAG_NOT_DUP) &&
+		    !(flag&FLAG_FORWARD_PROGRESS))
+			return 1;
+
+		if (!(flag&FLAG_DATA_ACKED)) {
+			tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3),
+					    flag);
+			return 1;
+		}
+	} else {
+		if (!(flag&FLAG_DATA_ACKED) && (tp->frto_counter == 1)) {
+			/* Prevent sending of new data. */
+			tp->snd_cwnd = min(tp->snd_cwnd,
+					   tcp_packets_in_flight(tp));
+			return 1;
+		}
+
+		if ((tp->frto_counter >= 2) &&
+		    (!(flag&FLAG_FORWARD_PROGRESS) ||
+		     ((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) {
+			/* RFC4138 shortcoming (see comment above) */
+			if (!(flag&FLAG_FORWARD_PROGRESS) && (flag&FLAG_NOT_DUP))
+				return 1;
+
+			tcp_enter_frto_loss(sk, 3, flag);
+			return 1;
+		}
 	}
 
 	if (tp->frto_counter == 1) {
-		/* First ACK after RTO advances the window: allow two new
-		 * segments out.
-		 */
+		/* Sending of the next skb must be allowed or no FRTO */
+		if (!tcp_send_head(sk) ||
+		    after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
+				     tp->snd_una + tp->snd_wnd)) {
+			tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3),
+					    flag);
+			return 1;
+		}
+
 		tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
+		tp->frto_counter = 2;
+		return 1;
 	} else {
-		/* Also the second ACK after RTO advances the window.
-		 * The RTO was likely spurious. Reduce cwnd and continue
-		 * in congestion avoidance
-		 */
-		tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
-		tcp_moderate_cwnd(tp);
+		switch (sysctl_tcp_frto_response) {
+		case 2:
+			tcp_undo_spur_to_response(sk, flag);
+			break;
+		case 1:
+			tcp_conservative_spur_to_response(tp);
+			break;
+		default:
+			tcp_ratehalving_spur_to_response(sk);
+			break;
+		}
+		tp->frto_counter = 0;
 	}
-
-	/* F-RTO affects on two new ACKs following RTO.
-	 * At latest on third ACK the TCP behavior is back to normal.
-	 */
-	tp->frto_counter = (tp->frto_counter + 1) % 3;
+	return 0;
 }
 
 /* This routine deals with incoming acks, but not outgoing ones. */
@@ -2513,6 +2747,7 @@ static int tcp_ack(struct sock *sk, stru
 	u32 prior_in_flight;
 	s32 seq_rtt;
 	int prior_packets;
+	int frto_cwnd = 0;
 
 	/* If the ack is newer than sent or older than previous acks
 	 * then we can probably ignore it.
@@ -2549,12 +2784,12 @@ static int tcp_ack(struct sock *sk, stru
 		else
 			NET_INC_STATS_BH(LINUX_MIB_TCPPUREACKS);
 
-		flag |= tcp_ack_update_window(sk, tp, skb, ack, ack_seq);
+		flag |= tcp_ack_update_window(sk, skb, ack, ack_seq);
 
 		if (TCP_SKB_CB(skb)->sacked)
 			flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
 
-		if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th))
+		if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
 			flag |= FLAG_ECE;
 
 		tcp_ca_event(sk, CA_EVENT_SLOW_ACK);
@@ -2575,15 +2810,16 @@ static int tcp_ack(struct sock *sk, stru
 	flag |= tcp_clean_rtx_queue(sk, &seq_rtt);
 
 	if (tp->frto_counter)
-		tcp_process_frto(sk, prior_snd_una);
+		frto_cwnd = tcp_process_frto(sk, prior_snd_una, flag);
 
 	if (tcp_ack_is_dubious(sk, flag)) {
 		/* Advance CWND, if state allows this. */
-		if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag))
+		if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
+		    tcp_may_raise_cwnd(sk, flag))
 			tcp_cong_avoid(sk, ack,  seq_rtt, prior_in_flight, 0);
 		tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
 	} else {
-		if ((flag & FLAG_DATA_ACKED))
+		if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
 			tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
 	}
 
@@ -2599,7 +2835,7 @@ no_queue:
 	 * being used to time the probes, and is probably far higher than
 	 * it needs to be for normal retransmission.
 	 */
-	if (sk->sk_send_head)
+	if (tcp_send_head(sk))
 		tcp_ack_probe(sk);
 	return 1;
 
@@ -2620,13 +2856,13 @@ uninteresting_ack:
 void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx, int estab)
 {
 	unsigned char *ptr;
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 	int length=(th->doff*4)-sizeof(struct tcphdr);
 
 	ptr = (unsigned char *)(th + 1);
 	opt_rx->saw_tstamp = 0;
 
-	while(length>0) {
+	while (length > 0) {
 		int opcode=*ptr++;
 		int opsize;
 
@@ -2642,9 +2878,9 @@ void tcp_parse_options(struct sk_buff *s
 					return;
 				if (opsize > length)
 					return;	/* don't parse partial options */
-				switch(opcode) {
+				switch (opcode) {
 				case TCPOPT_MSS:
-					if(opsize==TCPOLEN_MSS && th->syn && !estab) {
+					if (opsize==TCPOLEN_MSS && th->syn && !estab) {
 						u16 in_mss = ntohs(get_unaligned((__be16 *)ptr));
 						if (in_mss) {
 							if (opt_rx->user_mss && opt_rx->user_mss < in_mss)
@@ -2654,12 +2890,12 @@ void tcp_parse_options(struct sk_buff *s
 					}
 					break;
 				case TCPOPT_WINDOW:
-					if(opsize==TCPOLEN_WINDOW && th->syn && !estab)
+					if (opsize==TCPOLEN_WINDOW && th->syn && !estab)
 						if (sysctl_tcp_window_scaling) {
 							__u8 snd_wscale = *(__u8 *) ptr;
 							opt_rx->wscale_ok = 1;
 							if (snd_wscale > 14) {
-								if(net_ratelimit())
+								if (net_ratelimit())
 									printk(KERN_INFO "tcp_parse_options: Illegal window "
 									       "scaling value %d >14 received.\n",
 									       snd_wscale);
@@ -2669,7 +2905,7 @@ void tcp_parse_options(struct sk_buff *s
 						}
 					break;
 				case TCPOPT_TIMESTAMP:
-					if(opsize==TCPOLEN_TIMESTAMP) {
+					if (opsize==TCPOLEN_TIMESTAMP) {
 						if ((estab && opt_rx->tstamp_ok) ||
 						    (!estab && sysctl_tcp_timestamps)) {
 							opt_rx->saw_tstamp = 1;
@@ -2679,7 +2915,7 @@ void tcp_parse_options(struct sk_buff *s
 					}
 					break;
 				case TCPOPT_SACK_PERM:
-					if(opsize==TCPOLEN_SACK_PERM && th->syn && !estab) {
+					if (opsize==TCPOLEN_SACK_PERM && th->syn && !estab) {
 						if (sysctl_tcp_sack) {
 							opt_rx->sack_ok = 1;
 							tcp_sack_reset(opt_rx);
@@ -2688,7 +2924,7 @@ void tcp_parse_options(struct sk_buff *s
 					break;
 
 				case TCPOPT_SACK:
-					if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
+					if ((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
 					   !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) &&
 					   opt_rx->sack_ok) {
 						TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th;
@@ -2701,10 +2937,11 @@ #ifdef CONFIG_TCP_MD5SIG
 					 */
 					break;
 #endif
-				};
+				}
+
 				ptr+=opsize-2;
 				length-=opsize;
-		};
+		}
 	}
 }
 
@@ -2737,7 +2974,7 @@ static int tcp_fast_parse_options(struct
 static inline void tcp_store_ts_recent(struct tcp_sock *tp)
 {
 	tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
-	tp->rx_opt.ts_recent_stamp = xtime.tv_sec;
+	tp->rx_opt.ts_recent_stamp = get_seconds();
 }
 
 static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
@@ -2750,8 +2987,8 @@ static inline void tcp_replace_ts_recent
 		 * Not only, also it occurs for expired timestamps.
 		 */
 
-		if((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) >= 0 ||
-		   xtime.tv_sec >= tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS)
+		if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) >= 0 ||
+		   get_seconds() >= tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS)
 			tcp_store_ts_recent(tp);
 	}
 }
@@ -2782,7 +3019,7 @@ static inline void tcp_replace_ts_recent
 static int tcp_disordered_ack(const struct sock *sk, const struct sk_buff *skb)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 	u32 seq = TCP_SKB_CB(skb)->seq;
 	u32 ack = TCP_SKB_CB(skb)->ack_seq;
 
@@ -2803,7 +3040,7 @@ static inline int tcp_paws_discard(const
 {
 	const struct tcp_sock *tp = tcp_sk(sk);
 	return ((s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) > TCP_PAWS_WINDOW &&
-		xtime.tv_sec < tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS &&
+		get_seconds() < tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS &&
 		!tcp_disordered_ack(sk, skb));
 }
 
@@ -2910,7 +3147,7 @@ static void tcp_fin(struct sk_buff *skb,
 			printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n",
 			       __FUNCTION__, sk->sk_state);
 			break;
-	};
+	}
 
 	/* It _is_ possible, that we have something out-of-order _after_ FIN.
 	 * Probably, we should reset in this case. For now drop them.
@@ -3009,7 +3246,7 @@ static void tcp_sack_maybe_coalesce(stru
 			 */
 			tp->rx_opt.num_sacks--;
 			tp->rx_opt.eff_sacks = min(tp->rx_opt.num_sacks + tp->rx_opt.dsack, 4 - tp->rx_opt.tstamp_ok);
-			for(i=this_sack; i < tp->rx_opt.num_sacks; i++)
+			for (i=this_sack; i < tp->rx_opt.num_sacks; i++)
 				sp[i] = sp[i+1];
 			continue;
 		}
@@ -3062,7 +3299,7 @@ static void tcp_sack_new_ofo_skb(struct 
 		tp->rx_opt.num_sacks--;
 		sp--;
 	}
-	for(; this_sack > 0; this_sack--, sp--)
+	for (; this_sack > 0; this_sack--, sp--)
 		*sp = *(sp-1);
 
 new_sack:
@@ -3088,7 +3325,7 @@ static void tcp_sack_remove(struct tcp_s
 		return;
 	}
 
-	for(this_sack = 0; this_sack < num_sacks; ) {
+	for (this_sack = 0; this_sack < num_sacks; ) {
 		/* Check if the start of the sack is covered by RCV.NXT. */
 		if (!before(tp->rcv_nxt, sp->start_seq)) {
 			int i;
@@ -3144,8 +3381,8 @@ static void tcp_ofo_queue(struct sock *s
 		__skb_unlink(skb, &tp->out_of_order_queue);
 		__skb_queue_tail(&sk->sk_receive_queue, skb);
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-		if(skb->h.th->fin)
-			tcp_fin(skb, sk, skb->h.th);
+		if (tcp_hdr(skb)->fin)
+			tcp_fin(skb, sk, tcp_hdr(skb));
 	}
 }
 
@@ -3153,7 +3390,7 @@ static int tcp_prune_queue(struct sock *
 
 static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 {
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 	struct tcp_sock *tp = tcp_sk(sk);
 	int eaten = -1;
 
@@ -3210,9 +3447,9 @@ queue_and_out:
 			__skb_queue_tail(&sk->sk_receive_queue, skb);
 		}
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-		if(skb->len)
-			tcp_event_data_recv(sk, tp, skb);
-		if(th->fin)
+		if (skb->len)
+			tcp_event_data_recv(sk, skb);
+		if (th->fin)
 			tcp_fin(skb, sk, th);
 
 		if (!skb_queue_empty(&tp->out_of_order_queue)) {
@@ -3228,7 +3465,7 @@ queue_and_out:
 		if (tp->rx_opt.num_sacks)
 			tcp_sack_remove(tp);
 
-		tcp_fast_path_check(sk, tp);
+		tcp_fast_path_check(sk);
 
 		if (eaten > 0)
 			__kfree_skb(skb);
@@ -3392,7 +3629,7 @@ tcp_collapse(struct sock *sk, struct sk_
 		 * - bloated or contains data before "start" or
 		 *   overlaps to the next one.
 		 */
-		if (!skb->h.th->syn && !skb->h.th->fin &&
+		if (!tcp_hdr(skb)->syn && !tcp_hdr(skb)->fin &&
 		    (tcp_win_from_space(skb->truesize) > skb->len ||
 		     before(TCP_SKB_CB(skb)->seq, start) ||
 		     (skb->next != tail &&
@@ -3403,7 +3640,7 @@ tcp_collapse(struct sock *sk, struct sk_
 		start = TCP_SKB_CB(skb)->end_seq;
 		skb = skb->next;
 	}
-	if (skb == tail || skb->h.th->syn || skb->h.th->fin)
+	if (skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin)
 		return;
 
 	while (before(start, end)) {
@@ -3419,11 +3656,14 @@ tcp_collapse(struct sock *sk, struct sk_
 		nskb = alloc_skb(copy+header, GFP_ATOMIC);
 		if (!nskb)
 			return;
+
+		skb_set_mac_header(nskb, skb_mac_header(skb) - skb->head);
+		skb_set_network_header(nskb, (skb_network_header(skb) -
+					      skb->head));
+		skb_set_transport_header(nskb, (skb_transport_header(skb) -
+						skb->head));
 		skb_reserve(nskb, header);
 		memcpy(nskb->head, skb->head, header);
-		nskb->nh.raw = nskb->head + (skb->nh.raw-skb->head);
-		nskb->h.raw = nskb->head + (skb->h.raw-skb->head);
-		nskb->mac.raw = nskb->head + (skb->mac.raw-skb->head);
 		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 		TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
 		__skb_insert(nskb, skb->prev, skb, list);
@@ -3449,7 +3689,9 @@ tcp_collapse(struct sock *sk, struct sk_
 				__kfree_skb(skb);
 				NET_INC_STATS_BH(LINUX_MIB_TCPRCVCOLLAPSED);
 				skb = next;
-				if (skb == tail || skb->h.th->syn || skb->h.th->fin)
+				if (skb == tail ||
+				    tcp_hdr(skb)->syn ||
+				    tcp_hdr(skb)->fin)
 					return;
 			}
 		}
@@ -3514,7 +3756,7 @@ static int tcp_prune_queue(struct sock *
 	NET_INC_STATS_BH(LINUX_MIB_PRUNECALLED);
 
 	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
-		tcp_clamp_window(sk, tp);
+		tcp_clamp_window(sk);
 	else if (tcp_memory_pressure)
 		tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss);
 
@@ -3583,8 +3825,10 @@ void tcp_cwnd_application_limited(struct
 	tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
-static int tcp_should_expand_sndbuf(struct sock *sk, struct tcp_sock *tp)
+static int tcp_should_expand_sndbuf(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	/* If the user specified a specific send buffer setting, do
 	 * not modify it.
 	 */
@@ -3616,7 +3860,7 @@ static void tcp_new_space(struct sock *s
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
-	if (tcp_should_expand_sndbuf(sk, tp)) {
+	if (tcp_should_expand_sndbuf(sk)) {
 		int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) +
 			MAX_TCP_HEADER + 16 + sizeof(struct sk_buff),
 		    demanded = max_t(unsigned int, tp->snd_cwnd,
@@ -3640,9 +3884,9 @@ static void tcp_check_space(struct sock 
 	}
 }
 
-static inline void tcp_data_snd_check(struct sock *sk, struct tcp_sock *tp)
+static inline void tcp_data_snd_check(struct sock *sk)
 {
-	tcp_push_pending_frames(sk, tp);
+	tcp_push_pending_frames(sk);
 	tcp_check_space(sk);
 }
 
@@ -3790,7 +4034,7 @@ static int tcp_copy_to_iovec(struct sock
 	int err;
 
 	local_bh_enable();
-	if (skb->ip_summed==CHECKSUM_UNNECESSARY)
+	if (skb_csum_unnecessary(skb))
 		err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk);
 	else
 		err = skb_copy_and_csum_datagram_iovec(skb, hlen,
@@ -3822,7 +4066,7 @@ static __sum16 __tcp_checksum_complete_u
 
 static inline int tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb)
 {
-	return skb->ip_summed != CHECKSUM_UNNECESSARY &&
+	return !skb_csum_unnecessary(skb) &&
 		__tcp_checksum_complete_user(sk, skb);
 }
 
@@ -3840,7 +4084,7 @@ static int tcp_dma_try_early_copy(struct
 	if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list)
 		tp->ucopy.dma_chan = get_softnet_dma();
 
-	if (tp->ucopy.dma_chan && skb->ip_summed == CHECKSUM_UNNECESSARY) {
+	if (tp->ucopy.dma_chan && skb_csum_unnecessary(skb)) {
 
 		dma_cookie = dma_skb_copy_datagram_iovec(tp->ucopy.dma_chan,
 			skb, hlen, tp->ucopy.iov, chunk, tp->ucopy.pinned_list);
@@ -3856,7 +4100,7 @@ static int tcp_dma_try_early_copy(struct
 		tcp_rcv_space_adjust(sk);
 
 		if ((tp->ucopy.len == 0) ||
-		    (tcp_flag_word(skb->h.th) & TCP_FLAG_PSH) ||
+		    (tcp_flag_word(tcp_hdr(skb)) & TCP_FLAG_PSH) ||
 		    (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1))) {
 			tp->ucopy.wakeup = 1;
 			sk->sk_data_ready(sk, 0);
@@ -3976,7 +4220,7 @@ int tcp_rcv_established(struct sock *sk,
 				 */
 				tcp_ack(sk, skb, 0);
 				__kfree_skb(skb);
-				tcp_data_snd_check(sk, tp);
+				tcp_data_snd_check(sk);
 				return 0;
 			} else { /* Header too small */
 				TCP_INC_STATS_BH(TCP_MIB_INERRS);
@@ -4047,12 +4291,12 @@ #endif
 				tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 			}
 
-			tcp_event_data_recv(sk, tp, skb);
+			tcp_event_data_recv(sk, skb);
 
 			if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) {
 				/* Well, only one small jumplet in fast path... */
 				tcp_ack(sk, skb, FLAG_DATA);
-				tcp_data_snd_check(sk, tp);
+				tcp_data_snd_check(sk);
 				if (!inet_csk_ack_scheduled(sk))
 					goto no_ack;
 			}
@@ -4109,7 +4353,7 @@ slow_path:
 		goto discard;
 	}
 
-	if(th->rst) {
+	if (th->rst) {
 		tcp_reset(sk);
 		goto discard;
 	}
@@ -4124,7 +4368,7 @@ slow_path:
 	}
 
 step5:
-	if(th->ack)
+	if (th->ack)
 		tcp_ack(sk, skb, FLAG_SLOWPATH);
 
 	tcp_rcv_rtt_measure_ts(sk, skb);
@@ -4135,7 +4379,7 @@ step5:
 	/* step 7: process the segment text */
 	tcp_data_queue(sk, skb);
 
-	tcp_data_snd_check(sk, tp);
+	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
 	return 0;
 
@@ -4412,13 +4656,13 @@ int tcp_rcv_state_process(struct sock *s
 		goto discard;
 
 	case TCP_LISTEN:
-		if(th->ack)
+		if (th->ack)
 			return 1;
 
-		if(th->rst)
+		if (th->rst)
 			goto discard;
 
-		if(th->syn) {
+		if (th->syn) {
 			if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)
 				return 1;
 
@@ -4452,7 +4696,7 @@ int tcp_rcv_state_process(struct sock *s
 		/* Do step6 onward by hand. */
 		tcp_urg(sk, skb, th);
 		__kfree_skb(skb);
-		tcp_data_snd_check(sk, tp);
+		tcp_data_snd_check(sk);
 		return 0;
 	}
 
@@ -4474,7 +4718,7 @@ int tcp_rcv_state_process(struct sock *s
 	}
 
 	/* step 2: check RST bit */
-	if(th->rst) {
+	if (th->rst) {
 		tcp_reset(sk);
 		goto discard;
 	}
@@ -4497,7 +4741,7 @@ int tcp_rcv_state_process(struct sock *s
 	if (th->ack) {
 		int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
 
-		switch(sk->sk_state) {
+		switch (sk->sk_state) {
 		case TCP_SYN_RECV:
 			if (acceptable) {
 				tp->copied_seq = tp->rcv_nxt;
@@ -4644,7 +4888,7 @@ int tcp_rcv_state_process(struct sock *s
 
 	/* tcp_data could move socket to TIME-WAIT */
 	if (sk->sk_state != TCP_CLOSE) {
-		tcp_data_snd_check(sk, tp);
+		tcp_data_snd_check(sk);
 		tcp_ack_snd_check(sk);
 	}
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0ba74bb..5a3e7f8 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -88,7 +88,7 @@ int sysctl_tcp_low_latency __read_mostly
 #define ICMP_MIN_LENGTH 8
 
 /* Socket used for sending RSTs */
-static struct socket *tcp_socket;
+static struct socket *tcp_socket __read_mostly;
 
 void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);
 
@@ -125,10 +125,10 @@ void tcp_unhash(struct sock *sk)
 
 static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb)
 {
-	return secure_tcp_sequence_number(skb->nh.iph->daddr,
-					  skb->nh.iph->saddr,
-					  skb->h.th->dest,
-					  skb->h.th->source);
+	return secure_tcp_sequence_number(ip_hdr(skb)->daddr,
+					  ip_hdr(skb)->saddr,
+					  tcp_hdr(skb)->dest,
+					  tcp_hdr(skb)->source);
 }
 
 int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
@@ -149,7 +149,7 @@ int tcp_twsk_unique(struct sock *sk, str
 	 */
 	if (tcptw->tw_ts_recent_stamp &&
 	    (twp == NULL || (sysctl_tcp_tw_reuse &&
-			     xtime.tv_sec - tcptw->tw_ts_recent_stamp > 1))) {
+			     get_seconds() - tcptw->tw_ts_recent_stamp > 1))) {
 		tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
 		if (tp->write_seq == 0)
 			tp->write_seq = 1;
@@ -224,7 +224,7 @@ int tcp_v4_connect(struct sock *sk, stru
 		 * when trying new connection.
 		 */
 		if (peer != NULL &&
-		    peer->tcp_ts_stamp + TCP_PAWS_MSL >= xtime.tv_sec) {
+		    peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) {
 			tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
 			tp->rx_opt.ts_recent = peer->tcp_ts;
 		}
@@ -354,8 +354,8 @@ void tcp_v4_err(struct sk_buff *skb, u32
 	struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
 	struct tcp_sock *tp;
 	struct inet_sock *inet;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct sock *sk;
 	__u32 seq;
 	int err;
@@ -499,11 +499,12 @@ out:
 void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
 {
 	struct inet_sock *inet = inet_sk(sk);
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		th->check = ~tcp_v4_check(len, inet->saddr,
 					  inet->daddr, 0);
+		skb->csum_start = skb_transport_header(skb) - skb->head;
 		skb->csum_offset = offsetof(struct tcphdr, check);
 	} else {
 		th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
@@ -515,17 +516,18 @@ void tcp_v4_send_check(struct sock *sk, 
 
 int tcp_v4_gso_send_check(struct sk_buff *skb)
 {
-	struct iphdr *iph;
+	const struct iphdr *iph;
 	struct tcphdr *th;
 
 	if (!pskb_may_pull(skb, sizeof(*th)))
 		return -EINVAL;
 
-	iph = skb->nh.iph;
-	th = skb->h.th;
+	iph = ip_hdr(skb);
+	th = tcp_hdr(skb);
 
 	th->check = 0;
 	th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0);
+	skb->csum_start = skb_transport_header(skb) - skb->head;
 	skb->csum_offset = offsetof(struct tcphdr, check);
 	skb->ip_summed = CHECKSUM_PARTIAL;
 	return 0;
@@ -546,7 +548,7 @@ int tcp_v4_gso_send_check(struct sk_buff
 
 static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
 {
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 	struct {
 		struct tcphdr th;
 #ifdef CONFIG_TCP_MD5SIG
@@ -585,7 +587,7 @@ #endif
 	arg.iov[0].iov_len  = sizeof(rep.th);
 
 #ifdef CONFIG_TCP_MD5SIG
-	key = sk ? tcp_v4_md5_do_lookup(sk, skb->nh.iph->daddr) : NULL;
+	key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr) : NULL;
 	if (key) {
 		rep.opt[0] = htonl((TCPOPT_NOP << 24) |
 				   (TCPOPT_NOP << 16) |
@@ -597,14 +599,14 @@ #ifdef CONFIG_TCP_MD5SIG
 
 		tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1],
 					key,
-					skb->nh.iph->daddr,
-					skb->nh.iph->saddr,
+					ip_hdr(skb)->daddr,
+					ip_hdr(skb)->saddr,
 					&rep.th, IPPROTO_TCP,
 					arg.iov[0].iov_len);
 	}
 #endif
-	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
-				      skb->nh.iph->saddr, /* XXX */
+	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
+				      ip_hdr(skb)->saddr, /* XXX */
 				      sizeof(struct tcphdr), IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 
@@ -622,7 +624,7 @@ static void tcp_v4_send_ack(struct tcp_t
 			    struct sk_buff *skb, u32 seq, u32 ack,
 			    u32 win, u32 ts)
 {
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 	struct {
 		struct tcphdr th;
 		__be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
@@ -670,7 +672,7 @@ #ifdef CONFIG_TCP_MD5SIG
 	 * skb->sk) holds true, but we program defensively.
 	 */
 	if (!twsk && skb->sk) {
-		key = tcp_v4_md5_do_lookup(skb->sk, skb->nh.iph->daddr);
+		key = tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr);
 	} else if (twsk && twsk->tw_md5_keylen) {
 		tw_key.key = twsk->tw_md5_key;
 		tw_key.keylen = twsk->tw_md5_keylen;
@@ -690,14 +692,14 @@ #ifdef CONFIG_TCP_MD5SIG
 
 		tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset],
 					key,
-					skb->nh.iph->daddr,
-					skb->nh.iph->saddr,
+					ip_hdr(skb)->daddr,
+					ip_hdr(skb)->saddr,
 					&rep.th, IPPROTO_TCP,
 					arg.iov[0].iov_len);
 	}
 #endif
-	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
-				      skb->nh.iph->saddr, /* XXX */
+	arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
+				      ip_hdr(skb)->saddr, /* XXX */
 				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 
@@ -745,7 +747,7 @@ static int tcp_v4_send_synack(struct soc
 	skb = tcp_make_synack(sk, dst, req);
 
 	if (skb) {
-		struct tcphdr *th = skb->h.th;
+		struct tcphdr *th = tcp_hdr(skb);
 
 		th->check = tcp_v4_check(skb->len,
 					 ireq->loc_addr,
@@ -781,7 +783,7 @@ static void syn_flood_warning(struct sk_
 		warntime = jiffies;
 		printk(KERN_INFO
 		       "possible SYN flooding on port %d. Sending cookies.\n",
-		       ntohs(skb->h.th->dest));
+		       ntohs(tcp_hdr(skb)->dest));
 	}
 }
 #endif
@@ -1133,8 +1135,8 @@ static int tcp_v4_inbound_md5_hash(struc
 	 */
 	__u8 *hash_location = NULL;
 	struct tcp_md5sig_key *hash_expected;
-	struct iphdr *iph = skb->nh.iph;
-	struct tcphdr *th = skb->h.th;
+	const struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
 	int length = (th->doff << 2) - sizeof(struct tcphdr);
 	int genhash;
 	unsigned char *ptr;
@@ -1251,8 +1253,8 @@ int tcp_v4_conn_request(struct sock *sk,
 	struct inet_request_sock *ireq;
 	struct tcp_options_received tmp_opt;
 	struct request_sock *req;
-	__be32 saddr = skb->nh.iph->saddr;
-	__be32 daddr = skb->nh.iph->daddr;
+	__be32 saddr = ip_hdr(skb)->saddr;
+	__be32 daddr = ip_hdr(skb)->daddr;
 	__u32 isn = TCP_SKB_CB(skb)->when;
 	struct dst_entry *dst = NULL;
 #ifdef CONFIG_SYN_COOKIES
@@ -1327,7 +1329,7 @@ #endif
 	ireq->rmt_addr = saddr;
 	ireq->opt = tcp_v4_save_options(sk, skb);
 	if (!want_cookie)
-		TCP_ECN_create_request(req, skb->h.th);
+		TCP_ECN_create_request(req, tcp_hdr(skb));
 
 	if (want_cookie) {
 #ifdef CONFIG_SYN_COOKIES
@@ -1351,7 +1353,7 @@ #endif
 		    (dst = inet_csk_route_req(sk, req)) != NULL &&
 		    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
 		    peer->v4daddr == saddr) {
-			if (xtime.tv_sec < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
+			if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
 			    (s32)(peer->tcp_ts - req->ts_recent) >
 							TCP_PAWS_WINDOW) {
 				NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED);
@@ -1375,7 +1377,7 @@ #endif
 			LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open "
 				       "request from %u.%u.%u.%u/%u\n",
 				       NIPQUAD(saddr),
-				       ntohs(skb->h.th->source));
+				       ntohs(tcp_hdr(skb)->source));
 			dst_release(dst);
 			goto drop_and_free;
 		}
@@ -1439,7 +1441,7 @@ #endif
 	newinet->opt	      = ireq->opt;
 	ireq->opt	      = NULL;
 	newinet->mc_index     = inet_iif(skb);
-	newinet->mc_ttl	      = skb->nh.iph->ttl;
+	newinet->mc_ttl	      = ip_hdr(skb)->ttl;
 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
 	if (newinet->opt)
 		inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
@@ -1481,8 +1483,8 @@ exit:
 
 static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
-	struct tcphdr *th = skb->h.th;
-	struct iphdr *iph = skb->nh.iph;
+	struct tcphdr *th = tcp_hdr(skb);
+	const struct iphdr *iph = ip_hdr(skb);
 	struct sock *nsk;
 	struct request_sock **prev;
 	/* Find possible connection requests. */
@@ -1491,9 +1493,8 @@ 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,
-				      th->dest, inet_iif(skb));
+	nsk = inet_lookup_established(&tcp_hashinfo, iph->saddr, th->source,
+				      iph->daddr, th->dest, inet_iif(skb));
 
 	if (nsk) {
 		if (nsk->sk_state != TCP_TIME_WAIT) {
@@ -1513,15 +1514,17 @@ #endif
 
 static __sum16 tcp_v4_checksum_init(struct sk_buff *skb)
 {
+	const struct iphdr *iph = ip_hdr(skb);
+
 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
-		if (!tcp_v4_check(skb->len, skb->nh.iph->saddr,
-				  skb->nh.iph->daddr, skb->csum)) {
+		if (!tcp_v4_check(skb->len, iph->saddr,
+				  iph->daddr, skb->csum)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			return 0;
 		}
 	}
 
-	skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, skb->nh.iph->daddr,
+	skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
 				       skb->len, IPPROTO_TCP, 0);
 
 	if (skb->len <= 76) {
@@ -1555,7 +1558,7 @@ #endif
 
 	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
 		TCP_CHECK_TIMER(sk);
-		if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) {
+		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
 			rsk = sk;
 			goto reset;
 		}
@@ -1563,7 +1566,7 @@ #endif
 		return 0;
 	}
 
-	if (skb->len < (skb->h.th->doff << 2) || tcp_checksum_complete(skb))
+	if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
 		goto csum_err;
 
 	if (sk->sk_state == TCP_LISTEN) {
@@ -1581,7 +1584,7 @@ #endif
 	}
 
 	TCP_CHECK_TIMER(sk);
-	if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len)) {
+	if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {
 		rsk = sk;
 		goto reset;
 	}
@@ -1610,6 +1613,7 @@ csum_err:
 
 int tcp_v4_rcv(struct sk_buff *skb)
 {
+	const struct iphdr *iph;
 	struct tcphdr *th;
 	struct sock *sk;
 	int ret;
@@ -1623,7 +1627,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
 		goto discard_it;
 
-	th = skb->h.th;
+	th = tcp_hdr(skb);
 
 	if (th->doff < sizeof(struct tcphdr) / 4)
 		goto bad_packet;
@@ -1634,23 +1638,21 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	 * Packet length and doff are validated by header prediction,
 	 * provided case of th->doff==0 is eliminated.
 	 * So, we defer the checks. */
-	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	     tcp_v4_checksum_init(skb)))
+	if (!skb_csum_unnecessary(skb) && tcp_v4_checksum_init(skb))
 		goto bad_packet;
 
-	th = skb->h.th;
+	th = tcp_hdr(skb);
+	iph = ip_hdr(skb);
 	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
 	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
 				    skb->len - th->doff * 4);
 	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
 	TCP_SKB_CB(skb)->when	 = 0;
-	TCP_SKB_CB(skb)->flags	 = skb->nh.iph->tos;
+	TCP_SKB_CB(skb)->flags	 = iph->tos;
 	TCP_SKB_CB(skb)->sacked	 = 0;
 
-	sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source,
-			   skb->nh.iph->daddr, th->dest,
-			   inet_iif(skb));
-
+	sk = __inet_lookup(&tcp_hashinfo, iph->saddr, th->source,
+			   iph->daddr, th->dest, inet_iif(skb));
 	if (!sk)
 		goto no_tcp_socket;
 
@@ -1724,8 +1726,7 @@ do_time_wait:
 	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,
-							th->dest,
+							iph->daddr, th->dest,
 							inet_iif(skb));
 		if (sk2) {
 			inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
@@ -1770,7 +1771,7 @@ int tcp_v4_remember_stamp(struct sock *s
 
 	if (peer) {
 		if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 ||
-		    (peer->tcp_ts_stamp + TCP_PAWS_MSL < xtime.tv_sec &&
+		    (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() &&
 		     peer->tcp_ts_stamp <= tp->rx_opt.ts_recent_stamp)) {
 			peer->tcp_ts_stamp = tp->rx_opt.ts_recent_stamp;
 			peer->tcp_ts = tp->rx_opt.ts_recent;
@@ -1791,7 +1792,7 @@ int tcp_v4_tw_remember_stamp(struct inet
 		const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
 
 		if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
-		    (peer->tcp_ts_stamp + TCP_PAWS_MSL < xtime.tv_sec &&
+		    (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() &&
 		     peer->tcp_ts_stamp <= tcptw->tw_ts_recent_stamp)) {
 			peer->tcp_ts_stamp = tcptw->tw_ts_recent_stamp;
 			peer->tcp_ts	   = tcptw->tw_ts_recent;
@@ -1890,7 +1891,7 @@ int tcp_v4_destroy_sock(struct sock *sk)
 	tcp_cleanup_congestion_control(sk);
 
 	/* Cleanup up the write buffer. */
-	sk_stream_writequeue_purge(sk);
+	tcp_write_queue_purge(sk);
 
 	/* Cleans up our, hopefully empty, out_of_order_queue. */
 	__skb_queue_purge(&tp->out_of_order_queue);
@@ -2293,13 +2294,13 @@ static void get_openreq4(struct sock *sk
 		req);
 }
 
-static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
+static void get_tcp4_sock(struct sock *sk, char *tmpbuf, int i)
 {
 	int timer_active;
 	unsigned long timer_expires;
-	struct tcp_sock *tp = tcp_sk(sp);
-	const struct inet_connection_sock *icsk = inet_csk(sp);
-	struct inet_sock *inet = inet_sk(sp);
+	struct tcp_sock *tp = tcp_sk(sk);
+	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct inet_sock *inet = inet_sk(sk);
 	__be32 dest = inet->daddr;
 	__be32 src = inet->rcv_saddr;
 	__u16 destp = ntohs(inet->dport);
@@ -2311,9 +2312,9 @@ static void get_tcp4_sock(struct sock *s
 	} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
 		timer_active	= 4;
 		timer_expires	= icsk->icsk_timeout;
-	} else if (timer_pending(&sp->sk_timer)) {
+	} else if (timer_pending(&sk->sk_timer)) {
 		timer_active	= 2;
-		timer_expires	= sp->sk_timer.expires;
+		timer_expires	= sk->sk_timer.expires;
 	} else {
 		timer_active	= 0;
 		timer_expires = jiffies;
@@ -2321,17 +2322,17 @@ static void get_tcp4_sock(struct sock *s
 
 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
 			"%08X %5d %8d %lu %d %p %u %u %u %u %d",
-		i, src, srcp, dest, destp, sp->sk_state,
+		i, src, srcp, dest, destp, sk->sk_state,
 		tp->write_seq - tp->snd_una,
-		sp->sk_state == TCP_LISTEN ? sp->sk_ack_backlog :
+		sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog :
 					     (tp->rcv_nxt - tp->copied_seq),
 		timer_active,
 		jiffies_to_clock_t(timer_expires - jiffies),
 		icsk->icsk_retransmits,
-		sock_i_uid(sp),
+		sock_i_uid(sk),
 		icsk->icsk_probes_out,
-		sock_i_ino(sp),
-		atomic_read(&sp->sk_refcnt), sp,
+		sock_i_ino(sk),
+		atomic_read(&sk->sk_refcnt), sk,
 		icsk->icsk_rto,
 		icsk->icsk_ack.ato,
 		(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index f0ebaf0..43294ad 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -218,7 +218,7 @@ static u32 tcp_lp_owd_calculator(struct 
  *   3. calc smoothed OWD (SOWD).
  * Most ideas come from the original TCP-LP implementation.
  */
-static void tcp_lp_rtt_sample(struct sock *sk, u32 usrtt)
+static void tcp_lp_rtt_sample(struct sock *sk, u32 rtt)
 {
 	struct lp *lp = inet_csk_ca(sk);
 	s64 mowd = tcp_lp_owd_calculator(sk);
@@ -261,11 +261,13 @@ static void tcp_lp_rtt_sample(struct soc
  * newReno in increase case.
  * We work it out by following the idea from TCP-LP's paper directly
  */
-static void tcp_lp_pkts_acked(struct sock *sk, u32 num_acked)
+static void tcp_lp_pkts_acked(struct sock *sk, u32 num_acked, ktime_t last)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct lp *lp = inet_csk_ca(sk);
 
+	tcp_lp_rtt_sample(sk,  ktime_to_us(net_timedelta(last)));
+
 	/* calc inference */
 	if (tcp_time_stamp > tp->rx_opt.rcv_tsecr)
 		lp->inference = 3 * (tcp_time_stamp - tp->rx_opt.rcv_tsecr);
@@ -312,11 +314,11 @@ static void tcp_lp_pkts_acked(struct soc
 }
 
 static struct tcp_congestion_ops tcp_lp = {
+	.flags = TCP_CONG_RTT_STAMP,
 	.init = tcp_lp_init,
 	.ssthresh = tcp_reno_ssthresh,
 	.cong_avoid = tcp_lp_cong_avoid,
 	.min_cwnd = tcp_reno_min_cwnd,
-	.rtt_sample = tcp_lp_rtt_sample,
 	.pkts_acked = tcp_lp_pkts_acked,
 
 	.owner = THIS_MODULE,
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 6b5c64f..a12b08f 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -149,7 +149,7 @@ kill_with_rst:
 		tw->tw_substate	  = TCP_TIME_WAIT;
 		tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 		if (tmp_opt.saw_tstamp) {
-			tcptw->tw_ts_recent_stamp = xtime.tv_sec;
+			tcptw->tw_ts_recent_stamp = get_seconds();
 			tcptw->tw_ts_recent	  = tmp_opt.rcv_tsval;
 		}
 
@@ -208,7 +208,7 @@ kill:
 
 		if (tmp_opt.saw_tstamp) {
 			tcptw->tw_ts_recent	  = tmp_opt.rcv_tsval;
-			tcptw->tw_ts_recent_stamp = xtime.tv_sec;
+			tcptw->tw_ts_recent_stamp = get_seconds();
 		}
 
 		inet_twsk_put(tw);
@@ -246,7 +246,7 @@ kill:
 	if (paws_reject)
 		NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
 
-	if(!th->rst) {
+	if (!th->rst) {
 		/* In this case we must reset the TIMEWAIT timer.
 		 *
 		 * If it is ACKless SYN it may be both old duplicate
@@ -324,7 +324,7 @@ #ifdef CONFIG_TCP_MD5SIG
 				if (tcp_alloc_md5sig_pool() == NULL)
 					BUG();
 			}
-		} while(0);
+		} while (0);
 #endif
 
 		/* Linkage updates. */
@@ -387,8 +387,8 @@ struct sock *tcp_create_openreq_child(st
 		/* Now setup tcp_sock */
 		newtp = tcp_sk(newsk);
 		newtp->pred_flags = 0;
-		newtp->rcv_nxt = treq->rcv_isn + 1;
-		newtp->snd_nxt = newtp->snd_una = newtp->snd_sml = treq->snt_isn + 1;
+		newtp->rcv_wup = newtp->copied_seq = newtp->rcv_nxt = treq->rcv_isn + 1;
+		newtp->snd_sml = newtp->snd_una = newtp->snd_nxt = treq->snt_isn + 1;
 
 		tcp_prequeue_init(newtp);
 
@@ -422,10 +422,8 @@ struct sock *tcp_create_openreq_child(st
 		tcp_set_ca_state(newsk, TCP_CA_Open);
 		tcp_init_xmit_timers(newsk);
 		skb_queue_head_init(&newtp->out_of_order_queue);
-		newtp->rcv_wup = treq->rcv_isn + 1;
 		newtp->write_seq = treq->snt_isn + 1;
 		newtp->pushed_seq = newtp->write_seq;
-		newtp->copied_seq = treq->rcv_isn + 1;
 
 		newtp->rx_opt.saw_tstamp = 0;
 
@@ -440,7 +438,7 @@ struct sock *tcp_create_openreq_child(st
 						       keepalive_time_when(newtp));
 
 		newtp->rx_opt.tstamp_ok = ireq->tstamp_ok;
-		if((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
+		if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
 			if (sysctl_tcp_fack)
 				newtp->rx_opt.sack_ok |= 2;
 		}
@@ -455,12 +453,13 @@ struct sock *tcp_create_openreq_child(st
 			newtp->rx_opt.snd_wscale = newtp->rx_opt.rcv_wscale = 0;
 			newtp->window_clamp = min(newtp->window_clamp, 65535U);
 		}
-		newtp->snd_wnd = ntohs(skb->h.th->window) << newtp->rx_opt.snd_wscale;
+		newtp->snd_wnd = (ntohs(tcp_hdr(skb)->window) <<
+				  newtp->rx_opt.snd_wscale);
 		newtp->max_window = newtp->snd_wnd;
 
 		if (newtp->rx_opt.tstamp_ok) {
 			newtp->rx_opt.ts_recent = req->ts_recent;
-			newtp->rx_opt.ts_recent_stamp = xtime.tv_sec;
+			newtp->rx_opt.ts_recent_stamp = get_seconds();
 			newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
 		} else {
 			newtp->rx_opt.ts_recent_stamp = 0;
@@ -490,7 +489,7 @@ struct sock *tcp_check_req(struct sock *
 			   struct request_sock *req,
 			   struct request_sock **prev)
 {
-	struct tcphdr *th = skb->h.th;
+	const struct tcphdr *th = tcp_hdr(skb);
 	__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
 	int paws_reject = 0;
 	struct tcp_options_received tmp_opt;
@@ -506,7 +505,7 @@ struct sock *tcp_check_req(struct sock *
 			 * it can be estimated (approximately)
 			 * from another data.
 			 */
-			tmp_opt.ts_recent_stamp = xtime.tv_sec - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
+			tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
 			paws_reject = tcp_paws_check(&tmp_opt, th->rst);
 		}
 	}
@@ -712,8 +711,8 @@ int tcp_child_process(struct sock *paren
 	int state = child->sk_state;
 
 	if (!sock_owned_by_user(child)) {
-		ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len);
-
+		ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb),
+					    skb->len);
 		/* Wakeup parent, send SIGIO */
 		if (state == TCP_SYN_RECV && child->sk_state != state)
 			parent->sk_data_ready(parent, 0);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 3c24881..53232dd 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -40,7 +40,6 @@ #include <net/tcp.h>
 
 #include <linux/compiler.h>
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse __read_mostly = 1;
@@ -62,14 +61,13 @@ int sysctl_tcp_base_mss __read_mostly = 
 /* By default, RFC2861 behavior.  */
 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)
+static void update_send_head(struct sock *sk, struct sk_buff *skb)
 {
-	sk->sk_send_head = skb->next;
-	if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
-		sk->sk_send_head = NULL;
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	tcp_advance_send_head(sk, skb);
 	tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
-	tcp_packets_out_inc(sk, tp, skb);
+	tcp_packets_out_inc(sk, skb);
 }
 
 /* SND.NXT, if window was not shrunk.
@@ -78,8 +76,10 @@ static void update_send_head(struct sock
  * Anything in between SND.UNA...SND.UNA+SND.WND also can be already
  * invalid. OK, let's make this for now:
  */
-static inline __u32 tcp_acceptable_seq(struct sock *sk, struct tcp_sock *tp)
+static inline __u32 tcp_acceptable_seq(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
+
 	if (!before(tp->snd_una+tp->snd_wnd, tp->snd_nxt))
 		return tp->snd_nxt;
 	else
@@ -238,7 +238,7 @@ static u16 tcp_select_window(struct sock
 	u32 new_win = __tcp_select_window(sk);
 
 	/* Never shrink the offered window */
-	if(new_win < cur_win) {
+	if (new_win < cur_win) {
 		/* Danger Will Robinson!
 		 * Don't update rcv_wup/rcv_wnd here or else
 		 * we will not be able to advertise a zero
@@ -289,10 +289,12 @@ static void tcp_build_and_update_options
 			       (TCPOPT_SACK <<  8) |
 			       (TCPOLEN_SACK_BASE + (tp->rx_opt.eff_sacks *
 						     TCPOLEN_SACK_PERBLOCK)));
-		for(this_sack = 0; this_sack < tp->rx_opt.eff_sacks; this_sack++) {
+
+		for (this_sack = 0; this_sack < tp->rx_opt.eff_sacks; this_sack++) {
 			*ptr++ = htonl(sp[this_sack].start_seq);
 			*ptr++ = htonl(sp[this_sack].end_seq);
 		}
+
 		if (tp->rx_opt.dsack) {
 			tp->rx_opt.dsack = 0;
 			tp->rx_opt.eff_sacks--;
@@ -337,7 +339,7 @@ static void tcp_syn_build_options(__be32
 	 */
 	*ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
 	if (ts) {
-		if(sack)
+		if (sack)
 			*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
 				       (TCPOLEN_SACK_PERM << 16) |
 				       (TCPOPT_TIMESTAMP << 8) |
@@ -349,7 +351,7 @@ static void tcp_syn_build_options(__be32
 				       TCPOLEN_TIMESTAMP);
 		*ptr++ = htonl(tstamp);		/* TSVAL */
 		*ptr++ = htonl(ts_recent);	/* TSECR */
-	} else if(sack)
+	} else if (sack)
 		*ptr++ = htonl((TCPOPT_NOP << 24) |
 			       (TCPOPT_NOP << 16) |
 			       (TCPOPT_SACK_PERM << 8) |
@@ -406,7 +408,7 @@ #endif
 	/* If congestion control is doing timestamping, we must
 	 * take such a timestamp before we potentially clone/copy.
 	 */
-	if (icsk->icsk_ca_ops->rtt_sample)
+	if (icsk->icsk_ca_ops->flags & TCP_CONG_RTT_STAMP)
 		__net_timestamp(skb);
 
 	if (likely(clone_it)) {
@@ -430,7 +432,7 @@ #define SYSCTL_FLAG_SACK	0x4
 	sysctl_flags = 0;
 	if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
 		tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
-		if(sysctl_tcp_timestamps) {
+		if (sysctl_tcp_timestamps) {
 			tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
 			sysctl_flags |= SYSCTL_FLAG_TSTAMPS;
 		}
@@ -465,11 +467,12 @@ #ifdef CONFIG_TCP_MD5SIG
 		tcp_header_size += TCPOLEN_MD5SIG_ALIGNED;
 #endif
 
-	th = (struct tcphdr *) skb_push(skb, tcp_header_size);
-	skb->h.th = th;
+	skb_push(skb, tcp_header_size);
+	skb_reset_transport_header(skb);
 	skb_set_owner_w(skb, sk);
 
 	/* Build TCP header and checksum it. */
+	th = tcp_hdr(skb);
 	th->source		= inet->sport;
 	th->dest		= inet->dport;
 	th->seq			= htonl(tcb->seq);
@@ -515,7 +518,7 @@ #ifdef CONFIG_TCP_MD5SIG
 					     md5 ? &md5_hash_location :
 #endif
 					     NULL);
-		TCP_ECN_send(sk, tp, skb, tcp_header_size);
+		TCP_ECN_send(sk, skb, tcp_header_size);
 	}
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -524,7 +527,7 @@ #ifdef CONFIG_TCP_MD5SIG
 		tp->af_specific->calc_md5_hash(md5_hash_location,
 					       md5,
 					       sk, NULL, NULL,
-					       skb->h.th,
+					       tcp_hdr(skb),
 					       sk->sk_protocol,
 					       skb->len);
 	}
@@ -545,7 +548,7 @@ #endif
 	if (likely(err <= 0))
 		return err;
 
-	tcp_enter_cwr(sk);
+	tcp_enter_cwr(sk, 1);
 
 	return net_xmit_eval(err);
 
@@ -567,12 +570,8 @@ static void tcp_queue_skb(struct sock *s
 	/* Advance write_seq and place onto the write_queue. */
 	tp->write_seq = TCP_SKB_CB(skb)->end_seq;
 	skb_header_release(skb);
-	__skb_queue_tail(&sk->sk_write_queue, skb);
+	tcp_add_write_queue_tail(sk, skb);
 	sk_charge_skb(sk, skb);
-
-	/* Queue it, remembering where we must start sending. */
-	if (sk->sk_send_head == NULL)
-		sk->sk_send_head = skb;
 }
 
 static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned int mss_now)
@@ -705,7 +704,7 @@ int tcp_fragment(struct sock *sk, struct
 
 	/* Link BUFF into the send queue. */
 	skb_header_release(buff);
-	__skb_append(skb, buff, &sk->sk_write_queue);
+	tcp_insert_write_queue_after(skb, buff, sk);
 
 	return 0;
 }
@@ -736,7 +735,7 @@ static void __pskb_trim_head(struct sk_b
 	}
 	skb_shinfo(skb)->nr_frags = k;
 
-	skb->tail = skb->data;
+	skb_reset_tail_pointer(skb);
 	skb->data_len -= len;
 	skb->len = skb->data_len;
 }
@@ -930,8 +929,9 @@ #endif
 
 /* Congestion window validation. (RFC2861) */
 
-static void tcp_cwnd_validate(struct sock *sk, struct tcp_sock *tp)
+static void tcp_cwnd_validate(struct sock *sk)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	__u32 packets_out = tp->packets_out;
 
 	if (packets_out >= tp->snd_cwnd) {
@@ -1034,8 +1034,10 @@ static inline int tcp_nagle_test(struct 
 	if (nonagle & TCP_NAGLE_PUSH)
 		return 1;
 
-	/* Don't use the nagle rule for urgent data (or for the final FIN).  */
-	if (tp->urg_mode ||
+	/* Don't use the nagle rule for urgent data (or for the final FIN).
+	 * Nagle can be ignored during F-RTO too (see RFC4138).
+	 */
+	if (tp->urg_mode || (tp->frto_counter == 2) ||
 	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
 		return 1;
 
@@ -1056,7 +1058,7 @@ static inline int tcp_snd_wnd_test(struc
 	return !after(end_seq, tp->snd_una + tp->snd_wnd);
 }
 
-/* This checks if the data bearing packet SKB (usually sk->sk_send_head)
+/* This checks if the data bearing packet SKB (usually tcp_send_head(sk))
  * should be put on the wire right now.  If so, it returns the number of
  * packets allowed by the congestion window.
  */
@@ -1079,15 +1081,10 @@ static unsigned int tcp_snd_test(struct 
 	return cwnd_quota;
 }
 
-static inline int tcp_skb_is_last(const struct sock *sk,
-				  const struct sk_buff *skb)
+int tcp_may_send_now(struct sock *sk)
 {
-	return skb->next == (struct sk_buff *)&sk->sk_write_queue;
-}
-
-int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
-{
-	struct sk_buff *skb = sk->sk_send_head;
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct sk_buff *skb = tcp_send_head(sk);
 
 	return (skb &&
 		tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
@@ -1143,7 +1140,7 @@ static int tso_fragment(struct sock *sk,
 
 	/* Link BUFF into the send queue. */
 	skb_header_release(buff);
-	__skb_append(skb, buff, &sk->sk_write_queue);
+	tcp_insert_write_queue_after(skb, buff, sk);
 
 	return 0;
 }
@@ -1153,8 +1150,9 @@ static int tso_fragment(struct sock *sk,
  *
  * This algorithm is from John Heffner.
  */
-static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
+static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
 {
+	struct tcp_sock *tp = tcp_sk(sk);
 	const struct inet_connection_sock *icsk = inet_csk(sk);
 	u32 send_win, cong_win, limit, in_flight;
 
@@ -1249,10 +1247,10 @@ static int tcp_mtu_probe(struct sock *sk
 
 	/* Have enough data in the send queue to probe? */
 	len = 0;
-	if ((skb = sk->sk_send_head) == NULL)
+	if ((skb = tcp_send_head(sk)) == NULL)
 		return -1;
 	while ((len += skb->len) < probe_size && !tcp_skb_is_last(sk, skb))
-		skb = skb->next;
+		skb = tcp_write_queue_next(sk, skb);
 	if (len < probe_size)
 		return -1;
 
@@ -1279,9 +1277,9 @@ static int tcp_mtu_probe(struct sock *sk
 		return -1;
 	sk_charge_skb(sk, nskb);
 
-	skb = sk->sk_send_head;
-	__skb_insert(nskb, skb->prev, skb, &sk->sk_write_queue);
-	sk->sk_send_head = nskb;
+	skb = tcp_send_head(sk);
+	tcp_insert_write_queue_before(nskb, skb, sk);
+	tcp_advance_send_head(sk, skb);
 
 	TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq;
 	TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size;
@@ -1292,7 +1290,7 @@ static int tcp_mtu_probe(struct sock *sk
 
 	len = 0;
 	while (len < probe_size) {
-		next = skb->next;
+		next = tcp_write_queue_next(sk, skb);
 
 		copy = min_t(int, skb->len, probe_size - len);
 		if (nskb->ip_summed)
@@ -1305,7 +1303,7 @@ static int tcp_mtu_probe(struct sock *sk
 			/* We've eaten all the data from this skb.
 			 * Throw it away. */
 			TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags;
-			__skb_unlink(skb, &sk->sk_write_queue);
+			tcp_unlink_write_queue(skb, sk);
 			sk_stream_free_skb(sk, skb);
 		} else {
 			TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags &
@@ -1333,7 +1331,7 @@ static int tcp_mtu_probe(struct sock *sk
 		/* Decrement cwnd here because we are sending
 		* effectively two packets. */
 		tp->snd_cwnd--;
-		update_send_head(sk, tp, nskb);
+		update_send_head(sk, nskb);
 
 		icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len);
 		tp->mtu_probe.probe_seq_start = TCP_SKB_CB(nskb)->seq;
@@ -1377,7 +1375,7 @@ static int tcp_write_xmit(struct sock *s
 		sent_pkts = 1;
 	}
 
-	while ((skb = sk->sk_send_head)) {
+	while ((skb = tcp_send_head(sk))) {
 		unsigned int limit;
 
 		tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
@@ -1396,7 +1394,7 @@ static int tcp_write_xmit(struct sock *s
 						      nonagle : TCP_NAGLE_PUSH))))
 				break;
 		} else {
-			if (tcp_tso_should_defer(sk, tp, skb))
+			if (tcp_tso_should_defer(sk, skb))
 				break;
 		}
 
@@ -1425,31 +1423,31 @@ static int tcp_write_xmit(struct sock *s
 		/* Advance the send_head.  This one is sent out.
 		 * This call will increment packets_out.
 		 */
-		update_send_head(sk, tp, skb);
+		update_send_head(sk, skb);
 
 		tcp_minshall_update(tp, mss_now, skb);
 		sent_pkts++;
 	}
 
 	if (likely(sent_pkts)) {
-		tcp_cwnd_validate(sk, tp);
+		tcp_cwnd_validate(sk);
 		return 0;
 	}
-	return !tp->packets_out && sk->sk_send_head;
+	return !tp->packets_out && tcp_send_head(sk);
 }
 
 /* Push out any pending frames which were held back due to
  * TCP_CORK or attempt at coalescing tiny packets.
  * The socket must be locked by the caller.
  */
-void __tcp_push_pending_frames(struct sock *sk, struct tcp_sock *tp,
-			       unsigned int cur_mss, int nonagle)
+void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
+			       int nonagle)
 {
-	struct sk_buff *skb = sk->sk_send_head;
+	struct sk_buff *skb = tcp_send_head(sk);
 
 	if (skb) {
 		if (tcp_write_xmit(sk, cur_mss, nonagle))
-			tcp_check_probe_timer(sk, tp);
+			tcp_check_probe_timer(sk);
 	}
 }
 
@@ -1459,7 +1457,7 @@ void __tcp_push_pending_frames(struct so
 void tcp_push_one(struct sock *sk, unsigned int mss_now)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *skb = sk->sk_send_head;
+	struct sk_buff *skb = tcp_send_head(sk);
 	unsigned int tso_segs, cwnd_quota;
 
 	BUG_ON(!skb || skb->len < mss_now);
@@ -1493,8 +1491,8 @@ void tcp_push_one(struct sock *sk, unsig
 		TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
 		if (likely(!tcp_transmit_skb(sk, skb, 1, sk->sk_allocation))) {
-			update_send_head(sk, tp, skb);
-			tcp_cwnd_validate(sk, tp);
+			update_send_head(sk, skb);
+			tcp_cwnd_validate(sk);
 			return;
 		}
 	}
@@ -1620,7 +1618,7 @@ u32 __tcp_select_window(struct sock *sk)
 static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int mss_now)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *next_skb = skb->next;
+	struct sk_buff *next_skb = tcp_write_queue_next(sk, skb);
 
 	/* The first test we must make is that neither of these two
 	 * SKB's are still referenced by someone else.
@@ -1630,7 +1628,7 @@ static void tcp_retrans_try_collapse(str
 		u16 flags = TCP_SKB_CB(skb)->flags;
 
 		/* Also punt if next skb has been SACK'd. */
-		if(TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED)
+		if (TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED)
 			return;
 
 		/* Next skb is out of window. */
@@ -1652,9 +1650,11 @@ static void tcp_retrans_try_collapse(str
 		clear_all_retrans_hints(tp);
 
 		/* Ok.	We will be able to collapse the packet. */
-		__skb_unlink(next_skb, &sk->sk_write_queue);
+		tcp_unlink_write_queue(next_skb, sk);
 
-		memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
+		skb_copy_from_linear_data(next_skb,
+					  skb_put(skb, next_skb_size),
+					  next_skb_size);
 
 		if (next_skb->ip_summed == CHECKSUM_PARTIAL)
 			skb->ip_summed = CHECKSUM_PARTIAL;
@@ -1706,7 +1706,9 @@ void tcp_simple_retransmit(struct sock *
 	unsigned int mss = tcp_current_mss(sk, 0);
 	int lost = 0;
 
-	sk_stream_for_retrans_queue(skb, sk) {
+	tcp_for_write_queue(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
 		if (skb->len > mss &&
 		    !(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) {
 			if (TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_RETRANS) {
@@ -1788,13 +1790,13 @@ int tcp_retransmit_skb(struct sock *sk, 
 	}
 
 	/* Collapse two adjacent packets if worthwhile and we can. */
-	if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
-	   (skb->len < (cur_mss >> 1)) &&
-	   (skb->next != sk->sk_send_head) &&
-	   (skb->next != (struct sk_buff *)&sk->sk_write_queue) &&
-	   (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) &&
-	   (tcp_skb_pcount(skb) == 1 && tcp_skb_pcount(skb->next) == 1) &&
-	   (sysctl_tcp_retrans_collapse != 0))
+	if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) &&
+	    (skb->len < (cur_mss >> 1)) &&
+	    (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) &&
+	    (!tcp_skb_is_last(sk, skb)) &&
+	    (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) &&
+	    (tcp_skb_pcount(skb) == 1 && tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) &&
+	    (sysctl_tcp_retrans_collapse != 0))
 		tcp_retrans_try_collapse(sk, skb, cur_mss);
 
 	if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
@@ -1804,9 +1806,9 @@ int tcp_retransmit_skb(struct sock *sk, 
 	 * retransmit when old data is attached.  So strip it off
 	 * since it is cheap to do so and saves bytes on the network.
 	 */
-	if(skb->len > 0 &&
-	   (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
-	   tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
+	if (skb->len > 0 &&
+	    (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
+	    tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
 		if (!pskb_trim(skb, 0)) {
 			TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
 			skb_shinfo(skb)->gso_segs = 1;
@@ -1872,15 +1874,17 @@ void tcp_xmit_retransmit_queue(struct so
 		skb = tp->retransmit_skb_hint;
 		packet_cnt = tp->retransmit_cnt_hint;
 	}else{
-		skb = sk->sk_write_queue.next;
+		skb = tcp_write_queue_head(sk);
 		packet_cnt = 0;
 	}
 
 	/* First pass: retransmit lost packets. */
 	if (tp->lost_out) {
-		sk_stream_for_retrans_queue_from(skb, sk) {
+		tcp_for_write_queue_from(skb, sk) {
 			__u8 sacked = TCP_SKB_CB(skb)->sacked;
 
+			if (skb == tcp_send_head(sk))
+				break;
 			/* we could do better than to assign each time */
 			tp->retransmit_skb_hint = skb;
 			tp->retransmit_cnt_hint = packet_cnt;
@@ -1906,8 +1910,7 @@ void tcp_xmit_retransmit_queue(struct so
 					else
 						NET_INC_STATS_BH(LINUX_MIB_TCPSLOWSTARTRETRANS);
 
-					if (skb ==
-					    skb_peek(&sk->sk_write_queue))
+					if (skb == tcp_write_queue_head(sk))
 						inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
 									  inet_csk(sk)->icsk_rto,
 									  TCP_RTO_MAX);
@@ -1937,18 +1940,20 @@ void tcp_xmit_retransmit_queue(struct so
 	 * segments to send.
 	 */
 
-	if (tcp_may_send_now(sk, tp))
+	if (tcp_may_send_now(sk))
 		return;
 
 	if (tp->forward_skb_hint) {
 		skb = tp->forward_skb_hint;
 		packet_cnt = tp->forward_cnt_hint;
 	} else{
-		skb = sk->sk_write_queue.next;
+		skb = tcp_write_queue_head(sk);
 		packet_cnt = 0;
 	}
 
-	sk_stream_for_retrans_queue_from(skb, sk) {
+	tcp_for_write_queue_from(skb, sk) {
+		if (skb == tcp_send_head(sk))
+			break;
 		tp->forward_cnt_hint = packet_cnt;
 		tp->forward_skb_hint = skb;
 
@@ -1973,7 +1978,7 @@ void tcp_xmit_retransmit_queue(struct so
 			break;
 		}
 
-		if (skb == skb_peek(&sk->sk_write_queue))
+		if (skb == tcp_write_queue_head(sk))
 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
 						  inet_csk(sk)->icsk_rto,
 						  TCP_RTO_MAX);
@@ -1989,7 +1994,7 @@ void tcp_xmit_retransmit_queue(struct so
 void tcp_send_fin(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
-	struct sk_buff *skb = skb_peek_tail(&sk->sk_write_queue);
+	struct sk_buff *skb = tcp_write_queue_tail(sk);
 	int mss_now;
 
 	/* Optimization, tack on the FIN if we have a queue of
@@ -1998,7 +2003,7 @@ void tcp_send_fin(struct sock *sk)
 	 */
 	mss_now = tcp_current_mss(sk, 1);
 
-	if (sk->sk_send_head != NULL) {
+	if (tcp_send_head(sk) != NULL) {
 		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
 		TCP_SKB_CB(skb)->end_seq++;
 		tp->write_seq++;
@@ -2025,17 +2030,16 @@ void tcp_send_fin(struct sock *sk)
 		TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
 		tcp_queue_skb(sk, skb);
 	}
-	__tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_OFF);
+	__tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_OFF);
 }
 
 /* We get here when a process closes a file descriptor (either due to
  * an explicit close() or as a byproduct of exit()'ing) and there
  * was unread data in the receive queue.  This behavior is recommended
- * by draft-ietf-tcpimpl-prob-03.txt section 3.10.  -DaveM
+ * by RFC 2525, section 2.17.  -DaveM
  */
 void tcp_send_active_reset(struct sock *sk, gfp_t priority)
 {
-	struct tcp_sock *tp = tcp_sk(sk);
 	struct sk_buff *skb;
 
 	/* NOTE: No TCP options attached and we never retransmit this. */
@@ -2055,7 +2059,7 @@ void tcp_send_active_reset(struct sock *
 	skb_shinfo(skb)->gso_type = 0;
 
 	/* Send it off. */
-	TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
+	TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk);
 	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq;
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
 	if (tcp_transmit_skb(sk, skb, 0, priority))
@@ -2071,7 +2075,7 @@ int tcp_send_synack(struct sock *sk)
 {
 	struct sk_buff* skb;
 
-	skb = skb_peek(&sk->sk_write_queue);
+	skb = tcp_write_queue_head(sk);
 	if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SYN)) {
 		printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n");
 		return -EFAULT;
@@ -2081,9 +2085,9 @@ int tcp_send_synack(struct sock *sk)
 			struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
 			if (nskb == NULL)
 				return -ENOMEM;
-			__skb_unlink(skb, &sk->sk_write_queue);
+			tcp_unlink_write_queue(skb, sk);
 			skb_header_release(nskb);
-			__skb_queue_head(&sk->sk_write_queue, nskb);
+			__tcp_add_write_queue_head(sk, nskb);
 			sk_stream_free_skb(sk, skb);
 			sk_charge_skb(sk, nskb);
 			skb = nskb;
@@ -2133,8 +2137,10 @@ #ifdef CONFIG_TCP_MD5SIG
 	if (md5)
 		tcp_header_size += TCPOLEN_MD5SIG_ALIGNED;
 #endif
-	skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size);
+	skb_push(skb, tcp_header_size);
+	skb_reset_transport_header(skb);
 
+	th = tcp_hdr(skb);
 	memset(th, 0, sizeof(struct tcphdr));
 	th->syn = 1;
 	th->ack = 1;
@@ -2188,7 +2194,7 @@ #ifdef CONFIG_TCP_MD5SIG
 		tp->af_specific->calc_md5_hash(md5_hash_location,
 					       md5,
 					       NULL, dst, req,
-					       skb->h.th, sk->sk_protocol,
+					       tcp_hdr(skb), sk->sk_protocol,
 					       skb->len);
 	}
 #endif
@@ -2271,7 +2277,7 @@ int tcp_connect(struct sock *sk)
 	skb_reserve(buff, MAX_TCP_HEADER);
 
 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
-	TCP_ECN_send_syn(sk, tp, buff);
+	TCP_ECN_send_syn(sk, buff);
 	TCP_SKB_CB(buff)->sacked = 0;
 	skb_shinfo(buff)->gso_segs = 1;
 	skb_shinfo(buff)->gso_size = 0;
@@ -2285,7 +2291,7 @@ int tcp_connect(struct sock *sk)
 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
 	tp->retrans_stamp = TCP_SKB_CB(buff)->when;
 	skb_header_release(buff);
-	__skb_queue_tail(&sk->sk_write_queue, buff);
+	__tcp_add_write_queue_tail(sk, buff);
 	sk_charge_skb(sk, buff);
 	tp->packets_out += tcp_skb_pcount(buff);
 	tcp_transmit_skb(sk, buff, 1, GFP_KERNEL);
@@ -2363,7 +2369,6 @@ void tcp_send_ack(struct sock *sk)
 {
 	/* If we have been reset, we may not send again. */
 	if (sk->sk_state != TCP_CLOSE) {
-		struct tcp_sock *tp = tcp_sk(sk);
 		struct sk_buff *buff;
 
 		/* We are not putting this on the write queue, so
@@ -2389,7 +2394,7 @@ void tcp_send_ack(struct sock *sk)
 		skb_shinfo(buff)->gso_type = 0;
 
 		/* Send it off, this clears delayed acks for us. */
-		TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
+		TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk);
 		TCP_SKB_CB(buff)->when = tcp_time_stamp;
 		tcp_transmit_skb(sk, buff, 0, GFP_ATOMIC);
 	}
@@ -2441,7 +2446,7 @@ int tcp_write_wakeup(struct sock *sk)
 		struct tcp_sock *tp = tcp_sk(sk);
 		struct sk_buff *skb;
 
-		if ((skb = sk->sk_send_head) != NULL &&
+		if ((skb = tcp_send_head(sk)) != NULL &&
 		    before(TCP_SKB_CB(skb)->seq, tp->snd_una+tp->snd_wnd)) {
 			int err;
 			unsigned int mss = tcp_current_mss(sk, 0);
@@ -2467,7 +2472,7 @@ int tcp_write_wakeup(struct sock *sk)
 			TCP_SKB_CB(skb)->when = tcp_time_stamp;
 			err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 			if (!err) {
-				update_send_head(sk, tp, skb);
+				update_send_head(sk, skb);
 			}
 			return err;
 		} else {
@@ -2491,7 +2496,7 @@ void tcp_send_probe0(struct sock *sk)
 
 	err = tcp_write_wakeup(sk);
 
-	if (tp->packets_out || !sk->sk_send_head) {
+	if (tp->packets_out || !tcp_send_head(sk)) {
 		/* Cancel probe timer, if it is not required. */
 		icsk->icsk_probes_out = 0;
 		icsk->icsk_backoff = 0;
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 61f406f..3938d5d 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -26,6 +26,8 @@ #include <linux/tcp.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
 #include <linux/kfifo.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
 #include <linux/vmalloc.h>
 
 #include <net/tcp.h>
@@ -34,43 +36,45 @@ MODULE_AUTHOR("Stephen Hemminger <shemmi
 MODULE_DESCRIPTION("TCP cwnd snooper");
 MODULE_LICENSE("GPL");
 
-static int port = 0;
+static int port __read_mostly = 0;
 MODULE_PARM_DESC(port, "Port to match (0=all)");
 module_param(port, int, 0);
 
-static int bufsize = 64*1024;
+static int bufsize __read_mostly = 64*1024;
 MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
 module_param(bufsize, int, 0);
 
+static int full __read_mostly;
+MODULE_PARM_DESC(full, "Full log (1=every ack packet received,  0=only cwnd changes)");
+module_param(full, int, 0);
+
 static const char procname[] = "tcpprobe";
 
 struct {
-	struct kfifo  *fifo;
-	spinlock_t    lock;
+	struct kfifo	*fifo;
+	spinlock_t	lock;
 	wait_queue_head_t wait;
-	struct timeval tstart;
+	ktime_t		start;
+	u32		lastcwnd;
 } tcpw;
 
+/*
+ * Print to log with timestamps.
+ * FIXME: causes an extra copy
+ */
 static void printl(const char *fmt, ...)
 {
 	va_list args;
 	int len;
-	struct timeval now;
+	struct timespec tv;
 	char tbuf[256];
 
 	va_start(args, fmt);
-	do_gettimeofday(&now);
+	/* want monotonic time since start of tcp_probe */
+	tv = ktime_to_timespec(ktime_sub(ktime_get(), tcpw.start));
 
-	now.tv_sec -= tcpw.tstart.tv_sec;
-	now.tv_usec -= tcpw.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 = sprintf(tbuf, "%lu.%09lu ",
+		      (unsigned long) tv.tv_sec, (unsigned long) tv.tv_nsec);
 	len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
 	va_end(args);
 
@@ -78,38 +82,44 @@ static void printl(const char *fmt, ...)
 	wake_up(&tcpw.wait);
 }
 
-static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk,
-			struct msghdr *msg, size_t size)
+/*
+ * Hook inserted to be called before each receive packet.
+ * Note: arguments must match tcp_rcv_established()!
+ */
+static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
+			       struct tcphdr *th, unsigned len)
 {
 	const struct tcp_sock *tp = tcp_sk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
 
-	if (port == 0 || ntohs(inet->dport) == port ||
-	    ntohs(inet->sport) == port) {
+	/* Only update if port matches */
+	if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port)
+	    && (full || tp->snd_cwnd != tcpw.lastcwnd)) {
 		printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %#x %#x %u %u %u\n",
 		       NIPQUAD(inet->saddr), ntohs(inet->sport),
 		       NIPQUAD(inet->daddr), ntohs(inet->dport),
-		       size, tp->snd_nxt, tp->snd_una,
+		       skb->len, tp->snd_nxt, tp->snd_una,
 		       tp->snd_cwnd, tcp_current_ssthresh(sk),
-		       tp->snd_wnd);
+		       tp->snd_wnd, tp->srtt >> 3);
+		tcpw.lastcwnd = tp->snd_cwnd;
 	}
 
 	jprobe_return();
 	return 0;
 }
 
-static struct jprobe tcp_send_probe = {
+static struct jprobe tcp_probe = {
 	.kp = {
-		.symbol_name	= "tcp_sendmsg",
+		.symbol_name	= "tcp_rcv_established",
 	},
-	.entry	= JPROBE_ENTRY(jtcp_sendmsg),
+	.entry	= JPROBE_ENTRY(jtcp_rcv_established),
 };
 
 
 static int tcpprobe_open(struct inode * inode, struct file * file)
 {
 	kfifo_reset(tcpw.fifo);
-	do_gettimeofday(&tcpw.tstart);
+	tcpw.start = ktime_get();
 	return 0;
 }
 
@@ -162,7 +172,7 @@ static __init int tcpprobe_init(void)
 	if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops))
 		goto err0;
 
-	ret = register_jprobe(&tcp_send_probe);
+	ret = register_jprobe(&tcp_probe);
 	if (ret)
 		goto err1;
 
@@ -180,7 +190,7 @@ static __exit void tcpprobe_exit(void)
 {
 	kfifo_free(tcpw.fifo);
 	proc_net_remove(procname);
-	unregister_jprobe(&tcp_send_probe);
+	unregister_jprobe(&tcp_probe);
 
 }
 module_exit(tcpprobe_exit);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index a9243cf..2ca97b2 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -233,7 +233,7 @@ static void tcp_probe_timer(struct sock 
 	struct tcp_sock *tp = tcp_sk(sk);
 	int max_probes;
 
-	if (tp->packets_out || !sk->sk_send_head) {
+	if (tp->packets_out || !tcp_send_head(sk)) {
 		icsk->icsk_probes_out = 0;
 		return;
 	}
@@ -284,7 +284,7 @@ static void tcp_retransmit_timer(struct 
 	if (!tp->packets_out)
 		goto out;
 
-	BUG_TRAP(!skb_queue_empty(&sk->sk_write_queue));
+	BUG_TRAP(!tcp_write_queue_empty(sk));
 
 	if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) &&
 	    !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) {
@@ -306,7 +306,7 @@ #endif
 			goto out;
 		}
 		tcp_enter_loss(sk, 0);
-		tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue));
+		tcp_retransmit_skb(sk, tcp_write_queue_head(sk));
 		__sk_dst_reset(sk);
 		goto out_reset_timer;
 	}
@@ -341,7 +341,7 @@ #endif
 		tcp_enter_loss(sk, 0);
 	}
 
-	if (tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue)) > 0) {
+	if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) {
 		/* Retransmission failed because of local congestion,
 		 * do not backoff.
 		 */
@@ -482,7 +482,7 @@ static void tcp_keepalive_timer (unsigne
 	elapsed = keepalive_time_when(tp);
 
 	/* It is alive without keepalive 8) */
-	if (tp->packets_out || sk->sk_send_head)
+	if (tp->packets_out || tcp_send_head(sk))
 		goto resched;
 
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index 5c484dc..73e19cf 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -38,6 +38,8 @@ #include <linux/inet_diag.h>
 
 #include <net/tcp.h>
 
+#include "tcp_vegas.h"
+
 /* Default values of the Vegas variables, in fixed-point representation
  * with V_PARAM_SHIFT bits to the right of the binary point.
  */
@@ -54,17 +56,6 @@ module_param(gamma, int, 0644);
 MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)");
 
 
-/* Vegas variables */
-struct vegas {
-	u32	beg_snd_nxt;	/* right edge during last RTT */
-	u32	beg_snd_una;	/* left edge  during last RTT */
-	u32	beg_snd_cwnd;	/* saves the size of the cwnd */
-	u8	doing_vegas_now;/* if true, do vegas for this RTT */
-	u16	cntRTT;		/* # of RTTs measured within last RTT */
-	u32	minRTT;		/* min of RTTs measured within last RTT (in usec) */
-	u32	baseRTT;	/* the min of all Vegas RTT measurements seen (in usec) */
-};
-
 /* There are several situations when we must "re-start" Vegas:
  *
  *  o when a connection is established
@@ -81,7 +72,7 @@ struct vegas {
  * Instead we must wait until the completion of an RTT during
  * which we actually receive ACKs.
  */
-static inline void vegas_enable(struct sock *sk)
+static void vegas_enable(struct sock *sk)
 {
 	const struct tcp_sock *tp = tcp_sk(sk);
 	struct vegas *vegas = inet_csk_ca(sk);
@@ -104,13 +95,14 @@ static inline void vegas_disable(struct 
 	vegas->doing_vegas_now = 0;
 }
 
-static void tcp_vegas_init(struct sock *sk)
+void tcp_vegas_init(struct sock *sk)
 {
 	struct vegas *vegas = inet_csk_ca(sk);
 
 	vegas->baseRTT = 0x7fffffff;
 	vegas_enable(sk);
 }
+EXPORT_SYMBOL_GPL(tcp_vegas_init);
 
 /* Do RTT sampling needed for Vegas.
  * Basically we:
@@ -120,10 +112,13 @@ static void tcp_vegas_init(struct sock *
  *   o min-filter RTT samples from a much longer window (forever for now)
  *     to find the propagation delay (baseRTT)
  */
-static void tcp_vegas_rtt_calc(struct sock *sk, u32 usrtt)
+void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, ktime_t last)
 {
 	struct vegas *vegas = inet_csk_ca(sk);
-	u32 vrtt = usrtt + 1; /* Never allow zero rtt or baseRTT */
+	u32 vrtt;
+
+	/* Never allow zero rtt or baseRTT */
+	vrtt = ktime_to_us(net_timedelta(last)) + 1;
 
 	/* Filter to find propagation delay: */
 	if (vrtt < vegas->baseRTT)
@@ -135,8 +130,9 @@ static void tcp_vegas_rtt_calc(struct so
 	vegas->minRTT = min(vegas->minRTT, vrtt);
 	vegas->cntRTT++;
 }
+EXPORT_SYMBOL_GPL(tcp_vegas_pkts_acked);
 
-static void tcp_vegas_state(struct sock *sk, u8 ca_state)
+void tcp_vegas_state(struct sock *sk, u8 ca_state)
 {
 
 	if (ca_state == TCP_CA_Open)
@@ -144,6 +140,7 @@ static void tcp_vegas_state(struct sock 
 	else
 		vegas_disable(sk);
 }
+EXPORT_SYMBOL_GPL(tcp_vegas_state);
 
 /*
  * If the connection is idle and we are restarting,
@@ -154,12 +151,13 @@ static void tcp_vegas_state(struct sock 
  * packets, _then_ we can make Vegas calculations
  * again.
  */
-static void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
+void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 {
 	if (event == CA_EVENT_CWND_RESTART ||
 	    event == CA_EVENT_TX_START)
 		tcp_vegas_init(sk);
 }
+EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
 
 static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
 				 u32 seq_rtt, u32 in_flight, int flag)
@@ -336,30 +334,29 @@ static void tcp_vegas_cong_avoid(struct 
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
-static void tcp_vegas_get_info(struct sock *sk, u32 ext,
-			       struct sk_buff *skb)
+void tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb)
 {
 	const struct vegas *ca = inet_csk_ca(sk);
 	if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-		struct tcpvegas_info *info;
-
-		info = RTA_DATA(__RTA_PUT(skb, INET_DIAG_VEGASINFO,
-					  sizeof(*info)));
-
-		info->tcpv_enabled = ca->doing_vegas_now;
-		info->tcpv_rttcnt = ca->cntRTT;
-		info->tcpv_rtt = ca->baseRTT;
-		info->tcpv_minrtt = ca->minRTT;
-	rtattr_failure:	;
+		struct tcpvegas_info info = {
+			.tcpv_enabled = ca->doing_vegas_now,
+			.tcpv_rttcnt = ca->cntRTT,
+			.tcpv_rtt = ca->baseRTT,
+			.tcpv_minrtt = ca->minRTT,
+		};
+
+		nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
 	}
 }
+EXPORT_SYMBOL_GPL(tcp_vegas_get_info);
 
 static struct tcp_congestion_ops tcp_vegas = {
+	.flags		= TCP_CONG_RTT_STAMP,
 	.init		= tcp_vegas_init,
 	.ssthresh	= tcp_reno_ssthresh,
 	.cong_avoid	= tcp_vegas_cong_avoid,
 	.min_cwnd	= tcp_reno_min_cwnd,
-	.rtt_sample	= tcp_vegas_rtt_calc,
+	.pkts_acked	= tcp_vegas_pkts_acked,
 	.set_state	= tcp_vegas_state,
 	.cwnd_event	= tcp_vegas_cwnd_event,
 	.get_info	= tcp_vegas_get_info,
diff --git a/net/ipv4/tcp_vegas.h b/net/ipv4/tcp_vegas.h
new file mode 100644
index 0000000..502fa81
--- /dev/null
+++ b/net/ipv4/tcp_vegas.h
@@ -0,0 +1,24 @@
+/*
+ * TCP Vegas congestion control interface
+ */
+#ifndef __TCP_VEGAS_H
+#define __TCP_VEGAS_H 1
+
+/* Vegas variables */
+struct vegas {
+	u32	beg_snd_nxt;	/* right edge during last RTT */
+	u32	beg_snd_una;	/* left edge  during last RTT */
+	u32	beg_snd_cwnd;	/* saves the size of the cwnd */
+	u8	doing_vegas_now;/* if true, do vegas for this RTT */
+	u16	cntRTT;		/* # of RTTs measured within last RTT */
+	u32	minRTT;		/* min of RTTs measured within last RTT (in usec) */
+	u32	baseRTT;	/* the min of all Vegas RTT measurements seen (in usec) */
+};
+
+extern void tcp_vegas_init(struct sock *sk);
+extern void tcp_vegas_state(struct sock *sk, u8 ca_state);
+extern void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, ktime_t last);
+extern void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event);
+extern void tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb);
+
+#endif	/* __TCP_VEGAS_H */
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index ce57bf3..9edb340 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -69,10 +69,13 @@ static void tcp_veno_init(struct sock *s
 }
 
 /* Do rtt sampling needed for Veno. */
-static void tcp_veno_rtt_calc(struct sock *sk, u32 usrtt)
+static void tcp_veno_pkts_acked(struct sock *sk, u32 cnt, ktime_t last)
 {
 	struct veno *veno = inet_csk_ca(sk);
-	u32 vrtt = usrtt + 1;	/* Never allow zero rtt or basertt */
+	u32 vrtt;
+
+	/* Never allow zero rtt or baseRTT */
+	vrtt = ktime_to_us(net_timedelta(last)) + 1;
 
 	/* Filter to find propagation delay: */
 	if (vrtt < veno->basertt)
@@ -199,10 +202,11 @@ static u32 tcp_veno_ssthresh(struct sock
 }
 
 static struct tcp_congestion_ops tcp_veno = {
+	.flags		= TCP_CONG_RTT_STAMP,
 	.init		= tcp_veno_init,
 	.ssthresh	= tcp_veno_ssthresh,
 	.cong_avoid	= tcp_veno_cong_avoid,
-	.rtt_sample	= tcp_veno_rtt_calc,
+	.pkts_acked	= tcp_veno_pkts_acked,
 	.set_state	= tcp_veno_state,
 	.cwnd_event	= tcp_veno_cwnd_event,
 
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
index 4e1b610..e61e09d 100644
--- a/net/ipv4/tcp_westwood.c
+++ b/net/ipv4/tcp_westwood.c
@@ -100,7 +100,7 @@ static void westwood_filter(struct westw
  * Called after processing group of packets.
  * but all westwood needs is the last sample of srtt.
  */
-static void tcp_westwood_pkts_acked(struct sock *sk, u32 cnt)
+static void tcp_westwood_pkts_acked(struct sock *sk, u32 cnt, ktime_t last)
 {
 	struct westwood *w = inet_csk_ca(sk);
 	if (cnt > 0)
@@ -226,7 +226,7 @@ static void tcp_westwood_event(struct so
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct westwood *w = inet_csk_ca(sk);
 
-	switch(event) {
+	switch (event) {
 	case CA_EVENT_FAST_ACK:
 		westwood_fast_bw(sk);
 		break;
@@ -260,16 +260,13 @@ static void tcp_westwood_info(struct soc
 {
 	const struct westwood *ca = inet_csk_ca(sk);
 	if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
-		struct rtattr *rta;
-		struct tcpvegas_info *info;
-
-		rta = __RTA_PUT(skb, INET_DIAG_VEGASINFO, sizeof(*info));
-		info = RTA_DATA(rta);
-		info->tcpv_enabled = 1;
-		info->tcpv_rttcnt = 0;
-		info->tcpv_rtt = jiffies_to_usecs(ca->rtt);
-		info->tcpv_minrtt = jiffies_to_usecs(ca->rtt_min);
-	rtattr_failure:	;
+		struct tcpvegas_info info = {
+			.tcpv_enabled = 1,
+			.tcpv_rtt = jiffies_to_usecs(ca->rtt),
+			.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min),
+		};
+
+		nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info);
 	}
 }
 
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
new file mode 100644
index 0000000..545ed23
--- /dev/null
+++ b/net/ipv4/tcp_yeah.c
@@ -0,0 +1,268 @@
+/*
+ *
+ *   YeAH TCP
+ *
+ * For further details look at:
+ *    http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf
+ *
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/inet_diag.h>
+
+#include <net/tcp.h>
+
+#include "tcp_vegas.h"
+
+#define TCP_YEAH_ALPHA       80 //lin number of packets queued at the bottleneck
+#define TCP_YEAH_GAMMA        1 //lin fraction of queue to be removed per rtt
+#define TCP_YEAH_DELTA        3 //log minimum fraction of cwnd to be removed on loss
+#define TCP_YEAH_EPSILON      1 //log maximum fraction to be removed on early decongestion
+#define TCP_YEAH_PHY          8 //lin maximum delta from base
+#define TCP_YEAH_RHO         16 //lin minumum number of consecutive rtt to consider competition on loss
+#define TCP_YEAH_ZETA        50 //lin minimum number of state switchs to reset reno_count
+
+#define TCP_SCALABLE_AI_CNT	 100U
+
+/* YeAH variables */
+struct yeah {
+	struct vegas vegas;	/* must be first */
+
+	/* YeAH */
+	u32 lastQ;
+	u32 doing_reno_now;
+
+	u32 reno_count;
+	u32 fast_count;
+
+	u32 pkts_acked;
+};
+
+static void tcp_yeah_init(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct yeah *yeah = inet_csk_ca(sk);
+
+	tcp_vegas_init(sk);
+
+	yeah->doing_reno_now = 0;
+	yeah->lastQ = 0;
+
+	yeah->reno_count = 2;
+
+	/* Ensure the MD arithmetic works.  This is somewhat pedantic,
+	 * since I don't think we will see a cwnd this large. :) */
+	tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
+
+}
+
+
+static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, ktime_t last)
+{
+	const struct inet_connection_sock *icsk = inet_csk(sk);
+	struct yeah *yeah = inet_csk_ca(sk);
+
+	if (icsk->icsk_ca_state == TCP_CA_Open)
+		yeah->pkts_acked = pkts_acked;
+
+	tcp_vegas_pkts_acked(sk, pkts_acked, last);
+}
+
+static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack,
+				u32 seq_rtt, u32 in_flight, int flag)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	struct yeah *yeah = inet_csk_ca(sk);
+
+	if (!tcp_is_cwnd_limited(sk, in_flight))
+		return;
+
+	if (tp->snd_cwnd <= tp->snd_ssthresh)
+		tcp_slow_start(tp);
+
+	else if (!yeah->doing_reno_now) {
+		/* Scalable */
+
+		tp->snd_cwnd_cnt+=yeah->pkts_acked;
+		if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
+			if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+				tp->snd_cwnd++;
+			tp->snd_cwnd_cnt = 0;
+		}
+
+		yeah->pkts_acked = 1;
+
+	} else {
+		/* Reno */
+
+		if (tp->snd_cwnd_cnt < tp->snd_cwnd)
+			tp->snd_cwnd_cnt++;
+
+		if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+			tp->snd_cwnd++;
+			tp->snd_cwnd_cnt = 0;
+		}
+	}
+
+	/* The key players are v_vegas.beg_snd_una and v_beg_snd_nxt.
+	 *
+	 * These are so named because they represent the approximate values
+	 * of snd_una and snd_nxt at the beginning of the current RTT. More
+	 * precisely, they represent the amount of data sent during the RTT.
+	 * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt,
+	 * we will calculate that (v_beg_snd_nxt - v_vegas.beg_snd_una) outstanding
+	 * bytes of data have been ACKed during the course of the RTT, giving
+	 * an "actual" rate of:
+	 *
+	 *     (v_beg_snd_nxt - v_vegas.beg_snd_una) / (rtt duration)
+	 *
+	 * Unfortunately, v_vegas.beg_snd_una is not exactly equal to snd_una,
+	 * because delayed ACKs can cover more than one segment, so they
+	 * don't line up yeahly with the boundaries of RTTs.
+	 *
+	 * Another unfortunate fact of life is that delayed ACKs delay the
+	 * advance of the left edge of our send window, so that the number
+	 * of bytes we send in an RTT is often less than our cwnd will allow.
+	 * So we keep track of our cwnd separately, in v_beg_snd_cwnd.
+	 */
+
+	if (after(ack, yeah->vegas.beg_snd_nxt)) {
+
+		/* We do the Vegas calculations only if we got enough RTT
+		 * samples that we can be reasonably sure that we got
+		 * at least one RTT sample that wasn't from a delayed ACK.
+		 * If we only had 2 samples total,
+		 * then that means we're getting only 1 ACK per RTT, which
+		 * means they're almost certainly delayed ACKs.
+		 * If  we have 3 samples, we should be OK.
+		 */
+
+		if (yeah->vegas.cntRTT > 2) {
+			u32 rtt, queue;
+			u64 bw;
+
+			/* We have enough RTT samples, so, using the Vegas
+			 * algorithm, we determine if we should increase or
+			 * decrease cwnd, and by how much.
+			 */
+
+			/* Pluck out the RTT we are using for the Vegas
+			 * calculations. This is the min RTT seen during the
+			 * last RTT. Taking the min filters out the effects
+			 * of delayed ACKs, at the cost of noticing congestion
+			 * a bit later.
+			 */
+			rtt = yeah->vegas.minRTT;
+
+			/* Compute excess number of packets above bandwidth
+			 * Avoid doing full 64 bit divide.
+			 */
+			bw = tp->snd_cwnd;
+			bw *= rtt - yeah->vegas.baseRTT;
+			do_div(bw, rtt);
+			queue = bw;
+
+			if (queue > TCP_YEAH_ALPHA ||
+			    rtt - yeah->vegas.baseRTT > (yeah->vegas.baseRTT / TCP_YEAH_PHY)) {
+				if (queue > TCP_YEAH_ALPHA
+				    && tp->snd_cwnd > yeah->reno_count) {
+					u32 reduction = min(queue / TCP_YEAH_GAMMA ,
+							    tp->snd_cwnd >> TCP_YEAH_EPSILON);
+
+					tp->snd_cwnd -= reduction;
+
+					tp->snd_cwnd = max(tp->snd_cwnd,
+							   yeah->reno_count);
+
+					tp->snd_ssthresh = tp->snd_cwnd;
+				}
+
+				if (yeah->reno_count <= 2)
+					yeah->reno_count = max(tp->snd_cwnd>>1, 2U);
+				else
+					yeah->reno_count++;
+
+				yeah->doing_reno_now = min(yeah->doing_reno_now + 1,
+							   0xffffffU);
+			} else {
+				yeah->fast_count++;
+
+				if (yeah->fast_count > TCP_YEAH_ZETA) {
+					yeah->reno_count = 2;
+					yeah->fast_count = 0;
+				}
+
+				yeah->doing_reno_now = 0;
+			}
+
+			yeah->lastQ = queue;
+
+		}
+
+		/* Save the extent of the current window so we can use this
+		 * at the end of the next RTT.
+		 */
+		yeah->vegas.beg_snd_una  = yeah->vegas.beg_snd_nxt;
+		yeah->vegas.beg_snd_nxt  = tp->snd_nxt;
+		yeah->vegas.beg_snd_cwnd = tp->snd_cwnd;
+
+		/* Wipe the slate clean for the next RTT. */
+		yeah->vegas.cntRTT = 0;
+		yeah->vegas.minRTT = 0x7fffffff;
+	}
+}
+
+static u32 tcp_yeah_ssthresh(struct sock *sk) {
+	const struct tcp_sock *tp = tcp_sk(sk);
+	struct yeah *yeah = inet_csk_ca(sk);
+	u32 reduction;
+
+	if (yeah->doing_reno_now < TCP_YEAH_RHO) {
+		reduction = yeah->lastQ;
+
+		reduction = min( reduction, max(tp->snd_cwnd>>1, 2U) );
+
+		reduction = max( reduction, tp->snd_cwnd >> TCP_YEAH_DELTA);
+	} else
+		reduction = max(tp->snd_cwnd>>1,2U);
+
+	yeah->fast_count = 0;
+	yeah->reno_count = max(yeah->reno_count>>1, 2U);
+
+	return tp->snd_cwnd - reduction;
+}
+
+static struct tcp_congestion_ops tcp_yeah = {
+	.flags		= TCP_CONG_RTT_STAMP,
+	.init		= tcp_yeah_init,
+	.ssthresh	= tcp_yeah_ssthresh,
+	.cong_avoid	= tcp_yeah_cong_avoid,
+	.min_cwnd	= tcp_reno_min_cwnd,
+	.set_state	= tcp_vegas_state,
+	.cwnd_event	= tcp_vegas_cwnd_event,
+	.get_info	= tcp_vegas_get_info,
+	.pkts_acked	= tcp_yeah_pkts_acked,
+
+	.owner		= THIS_MODULE,
+	.name		= "yeah",
+};
+
+static int __init tcp_yeah_register(void)
+{
+	BUG_ON(sizeof(struct yeah) > ICSK_CA_PRIV_SIZE);
+	tcp_register_congestion_control(&tcp_yeah);
+	return 0;
+}
+
+static void __exit tcp_yeah_unregister(void)
+{
+	tcp_unregister_congestion_control(&tcp_yeah);
+}
+
+module_init(tcp_yeah_register);
+module_exit(tcp_yeah_unregister);
+
+MODULE_AUTHOR("Angelo P. Castellani");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("YeAH TCP");
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fc620a7..113e0c4 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -114,14 +114,33 @@ DEFINE_RWLOCK(udp_hash_lock);
 
 static int udp_port_rover;
 
-static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
+/*
+ * Note about this hash function :
+ * Typical use is probably daddr = 0, only dport is going to vary hash
+ */
+static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
+{
+	addr ^= addr >> 16;
+	addr ^= addr >> 8;
+	return port ^ addr;
+}
+
+static inline int __udp_lib_port_inuse(unsigned int hash, int port,
+	__be32 daddr, struct hlist_head udptable[])
 {
 	struct sock *sk;
 	struct hlist_node *node;
+	struct inet_sock *inet;
 
-	sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
-		if (sk->sk_hash == num)
+	sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
+		if (sk->sk_hash != hash)
+			continue;
+		inet = inet_sk(sk);
+		if (inet->num != port)
+			continue;
+		if (inet->rcv_saddr == daddr)
 			return 1;
+	}
 	return 0;
 }
 
@@ -142,6 +161,7 @@ int __udp_lib_get_port(struct sock *sk, 
 	struct hlist_node *node;
 	struct hlist_head *head;
 	struct sock *sk2;
+	unsigned int hash;
 	int    error = 1;
 
 	write_lock_bh(&udp_hash_lock);
@@ -156,7 +176,9 @@ int __udp_lib_get_port(struct sock *sk, 
 		for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
 			int size;
 
-			head = &udptable[result & (UDP_HTABLE_SIZE - 1)];
+			hash = hash_port_and_addr(result,
+					inet_sk(sk)->rcv_saddr);
+			head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 			if (hlist_empty(head)) {
 				if (result > sysctl_local_port_range[1])
 					result = sysctl_local_port_range[0] +
@@ -175,12 +197,23 @@ int __udp_lib_get_port(struct sock *sk, 
 			;
 		}
 		result = best;
-		for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
+		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_lib_lport_inuse(result, udptable))
+			hash = hash_port_and_addr(result, 0);
+			if (__udp_lib_port_inuse(hash, result,
+						 0, udptable))
+				continue;
+			if (!inet_sk(sk)->rcv_saddr)
+				break;
+
+			hash = hash_port_and_addr(result,
+					inet_sk(sk)->rcv_saddr);
+			if (! __udp_lib_port_inuse(hash, result,
+				inet_sk(sk)->rcv_saddr, udptable))
 				break;
 		}
 		if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -188,21 +221,41 @@ int __udp_lib_get_port(struct sock *sk, 
 gotit:
 		*port_rover = snum = result;
 	} else {
-		head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
+		hash = hash_port_and_addr(snum, 0);
+		head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 
 		sk_for_each(sk2, node, head)
-			if (sk2->sk_hash == 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_comp)(sk, sk2)                             )
+			if (sk2->sk_hash == hash &&
+			    sk2 != sk &&
+			    inet_sk(sk2)->num == snum &&
+			    (!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_comp)(sk, sk2))
 				goto fail;
+
+		if (inet_sk(sk)->rcv_saddr) {
+			hash = hash_port_and_addr(snum,
+						  inet_sk(sk)->rcv_saddr);
+			head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+
+			sk_for_each(sk2, node, head)
+				if (sk2->sk_hash == hash &&
+				    sk2 != sk &&
+				    inet_sk(sk2)->num == snum &&
+				    (!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_comp)(sk, sk2))
+					goto fail;
+		}
 	}
 	inet_sk(sk)->num = snum;
-	sk->sk_hash = snum;
+	sk->sk_hash = hash;
 	if (sk_unhashed(sk)) {
-		head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
+		head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 		sk_add_node(sk, head);
 		sock_prot_inc_use(sk->sk_prot);
 	}
@@ -212,13 +265,13 @@ fail:
 	return error;
 }
 
-__inline__ int udp_get_port(struct sock *sk, unsigned short snum,
+int udp_get_port(struct sock *sk, unsigned short snum,
 			int (*scmp)(const struct sock *, const struct sock *))
 {
 	return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
 }
 
-inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 {
 	struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
@@ -241,63 +294,77 @@ static struct sock *__udp4_lib_lookup(__
 {
 	struct sock *sk, *result = NULL;
 	struct hlist_node *node;
-	unsigned short hnum = ntohs(dport);
-	int badness = -1;
+	unsigned int hash, hashwild;
+	int score, best = -1, hport = ntohs(dport);
+
+ 	hash = hash_port_and_addr(hport, daddr);
+ 	hashwild = hash_port_and_addr(hport, 0);
 
 	read_lock(&udp_hash_lock);
-	sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
+
+lookup:
+
+	sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
 		struct inet_sock *inet = inet_sk(sk);
 
-		if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
-			int score = (sk->sk_family == PF_INET ? 1 : 0);
-			if (inet->rcv_saddr) {
-				if (inet->rcv_saddr != daddr)
-					continue;
-				score+=2;
-			}
-			if (inet->daddr) {
-				if (inet->daddr != saddr)
-					continue;
-				score+=2;
-			}
-			if (inet->dport) {
-				if (inet->dport != sport)
-					continue;
-				score+=2;
-			}
-			if (sk->sk_bound_dev_if) {
-				if (sk->sk_bound_dev_if != dif)
-					continue;
-				score+=2;
-			}
-			if(score == 9) {
-				result = sk;
-				break;
-			} else if(score > badness) {
-				result = sk;
-				badness = score;
-			}
+		if (sk->sk_hash != hash || ipv6_only_sock(sk) ||
+			inet->num != hport)
+			continue;
+
+		score = (sk->sk_family == PF_INET ? 1 : 0);
+		if (inet->rcv_saddr) {
+			if (inet->rcv_saddr != daddr)
+				continue;
+			score+=2;
+		}
+		if (inet->daddr) {
+			if (inet->daddr != saddr)
+				continue;
+			score+=2;
 		}
+		if (inet->dport) {
+			if (inet->dport != sport)
+				continue;
+			score+=2;
+		}
+		if (sk->sk_bound_dev_if) {
+			if (sk->sk_bound_dev_if != dif)
+				continue;
+			score+=2;
+		}
+		if (score == 9) {
+			result = sk;
+			goto found;
+		} else if (score > best) {
+			result = sk;
+			best = score;
+		}
+	}
+
+	if (hash != hashwild) {
+		hash = hashwild;
+		goto lookup;
 	}
+found:
 	if (result)
 		sock_hold(result);
 	read_unlock(&udp_hash_lock);
 	return result;
 }
 
-static inline struct sock *udp_v4_mcast_next(struct sock *sk,
-					     __be16 loc_port, __be32 loc_addr,
+static inline struct sock *udp_v4_mcast_next(struct sock *sk, unsigned int hnum,
+					     int hport, __be32 loc_addr,
 					     __be16 rmt_port, __be32 rmt_addr,
 					     int dif)
 {
 	struct hlist_node *node;
 	struct sock *s = sk;
-	unsigned short hnum = ntohs(loc_port);
 
 	sk_for_each_from(s, node) {
 		struct inet_sock *inet = inet_sk(s);
 
 		if (s->sk_hash != hnum					||
+		    inet->num != hport					||
 		    (inet->daddr && inet->daddr != rmt_addr)		||
 		    (inet->dport != rmt_port && inet->dport)		||
 		    (inet->rcv_saddr && inet->rcv_saddr != loc_addr)	||
@@ -329,8 +396,8 @@ void __udp4_lib_err(struct sk_buff *skb,
 	struct inet_sock *inet;
 	struct iphdr *iph = (struct iphdr*)skb->data;
 	struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2));
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct sock *sk;
 	int harderr;
 	int err;
@@ -390,7 +457,7 @@ out:
 	sock_put(sk);
 }
 
-__inline__ void udp_err(struct sk_buff *skb, u32 info)
+void udp_err(struct sk_buff *skb, u32 info)
 {
 	return __udp4_lib_err(skb, info, udp_hash);
 }
@@ -419,13 +486,14 @@ static void udp4_hwcsum_outgoing(struct 
 				 __be32 src, __be32 dst, int len      )
 {
 	unsigned int offset;
-	struct udphdr *uh = skb->h.uh;
+	struct udphdr *uh = udp_hdr(skb);
 	__wsum csum = 0;
 
 	if (skb_queue_len(&sk->sk_write_queue) == 1) {
 		/*
 		 * Only one fragment on the socket.
 		 */
+		skb->csum_start = skb_transport_header(skb) - skb->head;
 		skb->csum_offset = offsetof(struct udphdr, check);
 		uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0);
 	} else {
@@ -434,7 +502,7 @@ static void udp4_hwcsum_outgoing(struct 
 		 * fragments on the socket so that all csums of sk_buffs
 		 * should be together
 		 */
-		offset = skb->h.raw - skb->data;
+		offset = skb_transport_offset(skb);
 		skb->csum = skb_checksum(skb, offset, skb->len - offset, 0);
 
 		skb->ip_summed = CHECKSUM_NONE;
@@ -469,7 +537,7 @@ static int udp_push_pending_frames(struc
 	/*
 	 * Create a UDP header
 	 */
-	uh = skb->h.uh;
+	uh = udp_hdr(skb);
 	uh->source = fl->fl_ip_sport;
 	uh->dest = fl->fl_ip_dport;
 	uh->len = htons(up->len);
@@ -765,38 +833,38 @@ out:
 
 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-	switch(cmd)
+	switch (cmd) {
+	case SIOCOUTQ:
 	{
-		case SIOCOUTQ:
-		{
-			int amount = atomic_read(&sk->sk_wmem_alloc);
-			return put_user(amount, (int __user *)arg);
-		}
+		int amount = atomic_read(&sk->sk_wmem_alloc);
+		return put_user(amount, (int __user *)arg);
+	}
 
-		case SIOCINQ:
-		{
-			struct sk_buff *skb;
-			unsigned long amount;
-
-			amount = 0;
-			spin_lock_bh(&sk->sk_receive_queue.lock);
-			skb = skb_peek(&sk->sk_receive_queue);
-			if (skb != NULL) {
-				/*
-				 * We will only return the amount
-				 * of this packet since that is all
-				 * that will be read.
-				 */
-				amount = skb->len - sizeof(struct udphdr);
-			}
-			spin_unlock_bh(&sk->sk_receive_queue.lock);
-			return put_user(amount, (int __user *)arg);
+	case SIOCINQ:
+	{
+		struct sk_buff *skb;
+		unsigned long amount;
+
+		amount = 0;
+		spin_lock_bh(&sk->sk_receive_queue.lock);
+		skb = skb_peek(&sk->sk_receive_queue);
+		if (skb != NULL) {
+			/*
+			 * We will only return the amount
+			 * of this packet since that is all
+			 * that will be read.
+			 */
+			amount = skb->len - sizeof(struct udphdr);
 		}
+		spin_unlock_bh(&sk->sk_receive_queue.lock);
+		return put_user(amount, (int __user *)arg);
+	}
 
-		default:
-			return -ENOIOCTLCMD;
+	default:
+		return -ENOIOCTLCMD;
 	}
-	return(0);
+
+	return 0;
 }
 
 /*
@@ -810,7 +878,9 @@ int udp_recvmsg(struct kiocb *iocb, stru
 	struct inet_sock *inet = inet_sk(sk);
 	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
 	struct sk_buff *skb;
-	int copied, err, copy_only, is_udplite = IS_UDPLITE(sk);
+	unsigned int ulen, copied;
+	int err;
+	int is_udplite = IS_UDPLITE(sk);
 
 	/*
 	 *	Check any passed addresses
@@ -826,28 +896,25 @@ try_again:
 	if (!skb)
 		goto out;
 
-	copied = skb->len - sizeof(struct udphdr);
-	if (copied > len) {
-		copied = len;
+	ulen = skb->len - sizeof(struct udphdr);
+	copied = len;
+	if (copied > ulen)
+		copied = ulen;
+	else if (copied < ulen)
 		msg->msg_flags |= MSG_TRUNC;
-	}
 
 	/*
-	 * 	Decide whether to checksum and/or copy data.
-	 *
-	 * 	UDP:      checksum may have been computed in HW,
-	 * 	          (re-)compute it if message is truncated.
-	 * 	UDP-Lite: always needs to checksum, no HW support.
+	 * If checksum is needed at all, try to do it while copying the
+	 * data.  If the data is truncated, or if we only want a partial
+	 * coverage checksum (UDP-Lite), do it before the copy.
 	 */
-	copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY);
 
-	if (is_udplite  ||  (!copy_only  &&  msg->msg_flags&MSG_TRUNC)) {
-		if (__udp_lib_checksum_complete(skb))
+	if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+		if (udp_lib_checksum_complete(skb))
 			goto csum_copy_err;
-		copy_only = 1;
 	}
 
-	if (copy_only)
+	if (skb_csum_unnecessary(skb))
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
 					      msg->msg_iov, copied       );
 	else {
@@ -866,8 +933,8 @@ try_again:
 	if (sin)
 	{
 		sin->sin_family = AF_INET;
-		sin->sin_port = skb->h.uh->source;
-		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		sin->sin_port = udp_hdr(skb)->source;
+		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 		memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
 	}
 	if (inet->cmsg_flags)
@@ -875,7 +942,7 @@ try_again:
 
 	err = copied;
 	if (flags & MSG_TRUNC)
-		err = skb->len - sizeof(struct udphdr);
+		err = ulen;
 
 out_free:
 	skb_free_datagram(sk, skb);
@@ -949,7 +1016,7 @@ #else
 		return 1;
 
 	/* Now we can get the pointers */
-	uh = skb->h.uh;
+	uh = udp_hdr(skb);
 	udpdata = (__u8 *)uh + sizeof(struct udphdr);
 	udpdata32 = (__be32 *)udpdata;
 
@@ -959,7 +1026,7 @@ #else
 		/* Check if this is a keepalive packet.  If so, eat it. */
 		if (len == 1 && udpdata[0] == 0xff) {
 			return 0;
-		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0 ) {
+		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
 			/* ESP Packet without Non-ESP header */
 			len = sizeof(struct udphdr);
 		} else
@@ -990,7 +1057,7 @@ #else
 		return 0;
 
 	/* Now we can update and verify the packet length... */
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	iphlen = iph->ihl << 2;
 	iph->tot_len = htons(ntohs(iph->tot_len) - len);
 	if (skb->len < iphlen + len) {
@@ -1002,7 +1069,8 @@ #else
 	 * transport header to point to ESP.  Keep UDP on the stack
 	 * for later.
 	 */
-	skb->h.raw = skb_pull(skb, len);
+	__skb_pull(skb, len);
+	skb_reset_transport_header(skb);
 
 	/* modify the protocol (it's ESP!) */
 	iph->protocol = IPPROTO_ESP;
@@ -1095,10 +1163,9 @@ int udp_queue_rcv_skb(struct sock * sk, 
 		}
 	}
 
-	if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
-		if (__udp_lib_checksum_complete(skb))
+	if (sk->sk_filter) {
+		if (udp_lib_checksum_complete(skb))
 			goto drop;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
 	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
@@ -1128,33 +1195,49 @@ static int __udp4_lib_mcast_deliver(stru
 				    __be32 saddr, __be32 daddr,
 				    struct hlist_head udptable[])
 {
-	struct sock *sk;
+	struct sock *sk, *skw, *sknext;
 	int dif;
+	int hport = ntohs(uh->dest);
+	unsigned int hash = hash_port_and_addr(hport, daddr);
+	unsigned int hashwild = hash_port_and_addr(hport, 0);
 
-	read_lock(&udp_hash_lock);
-	sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]);
 	dif = skb->dev->ifindex;
-	sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
-	if (sk) {
-		struct sock *sknext = NULL;
 
+	read_lock(&udp_hash_lock);
+
+	sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]);
+	skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]);
+
+	sk = udp_v4_mcast_next(sk, hash, hport, daddr, uh->source, saddr, dif);
+	if (!sk) {
+		hash = hashwild;
+		sk = udp_v4_mcast_next(skw, hash, hport, daddr, uh->source,
+			saddr, dif);
+	}
+	if (sk) {
 		do {
 			struct sk_buff *skb1 = skb;
-
-			sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr,
-						   uh->source, saddr, dif);
-			if(sknext)
+			sknext = udp_v4_mcast_next(sk_next(sk), hash, hport,
+						daddr, uh->source, saddr, dif);
+			if (!sknext && hash != hashwild) {
+				hash = hashwild;
+				sknext = udp_v4_mcast_next(skw, hash, hport,
+					daddr, uh->source, saddr, dif);
+			}
+			if (sknext)
 				skb1 = skb_clone(skb, GFP_ATOMIC);
 
-			if(skb1) {
+			if (skb1) {
 				int ret = udp_queue_rcv_skb(sk, skb1);
 				if (ret > 0)
-					/* we should probably re-process instead
-					 * of dropping packets here. */
+					/*
+					 * we should probably re-process
+					 * instead of dropping packets here.
+					 */
 					kfree_skb(skb1);
 			}
 			sk = sknext;
-		} while(sknext);
+		} while (sknext);
 	} else
 		kfree_skb(skb);
 	read_unlock(&udp_hash_lock);
@@ -1166,25 +1249,37 @@ static int __udp4_lib_mcast_deliver(stru
  * Otherwise, csum completion requires chacksumming packet body,
  * including udp header and folding it to skb->csum.
  */
-static inline void udp4_csum_init(struct sk_buff *skb, struct udphdr *uh)
+static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
+				 int proto)
 {
+	const struct iphdr *iph;
+	int err;
+
+	UDP_SKB_CB(skb)->partial_cov = 0;
+	UDP_SKB_CB(skb)->cscov = skb->len;
+
+	if (proto == IPPROTO_UDPLITE) {
+		err = udplite_checksum_init(skb, uh);
+		if (err)
+			return err;
+	}
+
+	iph = ip_hdr(skb);
 	if (uh->check == 0) {
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else if (skb->ip_summed == CHECKSUM_COMPLETE) {
-	       if (!csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
-				      skb->len, IPPROTO_UDP, skb->csum       ))
+	       if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+				      proto, skb->csum))
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-		skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr,
-					       skb->nh.iph->daddr,
-					       skb->len, IPPROTO_UDP, 0);
+	if (!skb_csum_unnecessary(skb))
+		skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+					       skb->len, proto, 0);
 	/* Probably, we should checksum udp header (it should be in cache
 	 * in any case) and data in tiny packets (< rx copybreak).
 	 */
 
-	/* UDP = UDP-Lite with a non-partial checksum coverage */
-	UDP_SKB_CB(skb)->partial_cov = 0;
+	return 0;
 }
 
 /*
@@ -1192,14 +1287,14 @@ static inline void udp4_csum_init(struct
  */
 
 int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
-		   int is_udplite)
+		   int proto)
 {
 	struct sock *sk;
-	struct udphdr *uh = skb->h.uh;
+	struct udphdr *uh = udp_hdr(skb);
 	unsigned short ulen;
 	struct rtable *rt = (struct rtable*)skb->dst;
-	__be32 saddr = skb->nh.iph->saddr;
-	__be32 daddr = skb->nh.iph->daddr;
+	__be32 saddr = ip_hdr(skb)->saddr;
+	__be32 daddr = ip_hdr(skb)->daddr;
 
 	/*
 	 *  Validate the packet.
@@ -1211,24 +1306,21 @@ int __udp4_lib_rcv(struct sk_buff *skb, 
 	if (ulen > skb->len)
 		goto short_packet;
 
-	if(! is_udplite ) {		/* UDP validates ulen. */
-
+	if (proto == IPPROTO_UDP) {
+		/* UDP validates ulen. */
 		if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))
 			goto short_packet;
-		uh = skb->h.uh;
-
-		udp4_csum_init(skb, uh);
-
-	} else 	{			/* UDP-Lite validates cscov. */
-		if (udplite4_csum_init(skb, uh))
-			goto csum_error;
+		uh = udp_hdr(skb);
 	}
 
-	if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
+	if (udp4_csum_init(skb, uh, proto))
+		goto csum_error;
+
+	if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
 		return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
 
 	sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
-			       skb->dev->ifindex, udptable        );
+			       skb->dev->ifindex, udptable);
 
 	if (sk != NULL) {
 		int ret = udp_queue_rcv_skb(sk, skb);
@@ -1250,7 +1342,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, 
 	if (udp_lib_checksum_complete(skb))
 		goto csum_error;
 
-	UDP_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite);
+	UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 
 	/*
@@ -1258,11 +1350,11 @@ int __udp4_lib_rcv(struct sk_buff *skb, 
 	 * don't wanna listen.  Ignore it.
 	 */
 	kfree_skb(skb);
-	return(0);
+	return 0;
 
 short_packet:
 	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n",
-		       is_udplite? "-Lite" : "",
+		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
 		       NIPQUAD(saddr),
 		       ntohs(uh->source),
 		       ulen,
@@ -1277,21 +1369,21 @@ csum_error:
 	 * the network is concerned, anyway) as per 4.1.3.4 (MUST).
 	 */
 	LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
-		       is_udplite? "-Lite" : "",
+		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
 		       NIPQUAD(saddr),
 		       ntohs(uh->source),
 		       NIPQUAD(daddr),
 		       ntohs(uh->dest),
 		       ulen);
 drop:
-	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
+	UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
 	kfree_skb(skb);
-	return(0);
+	return 0;
 }
 
-__inline__ int udp_rcv(struct sk_buff *skb)
+int udp_rcv(struct sk_buff *skb)
 {
-	return __udp4_lib_rcv(skb, udp_hash, 0);
+	return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP);
 }
 
 int udp_destroy_sock(struct sock *sk)
@@ -1313,13 +1405,13 @@ int udp_lib_setsockopt(struct sock *sk, 
 	int val;
 	int err = 0;
 
-	if(optlen<sizeof(int))
+	if (optlen<sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
 		return -EFAULT;
 
-	switch(optname) {
+	switch (optname) {
 	case UDP_CORK:
 		if (val != 0) {
 			up->corkflag = 1;
@@ -1373,7 +1465,7 @@ int udp_lib_setsockopt(struct sock *sk, 
 	default:
 		err = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	return err;
 }
@@ -1404,15 +1496,15 @@ int udp_lib_getsockopt(struct sock *sk, 
 	struct udp_sock *up = udp_sk(sk);
 	int val, len;
 
-	if(get_user(len,optlen))
+	if (get_user(len,optlen))
 		return -EFAULT;
 
 	len = min_t(unsigned int, len, sizeof(int));
 
-	if(len < 0)
+	if (len < 0)
 		return -EINVAL;
 
-	switch(optname) {
+	switch (optname) {
 	case UDP_CORK:
 		val = up->corkflag;
 		break;
@@ -1433,11 +1525,11 @@ int udp_lib_getsockopt(struct sock *sk, 
 
 	default:
 		return -ENOPROTOOPT;
-	};
+	}
 
-	if(put_user(len, optlen))
+	if (put_user(len, optlen))
 		return -EFAULT;
-	if(copy_to_user(optval, &val,len))
+	if (copy_to_user(optval, &val,len))
 		return -EFAULT;
 	return 0;
 }
@@ -1486,15 +1578,11 @@ unsigned int udp_poll(struct file *file,
 		struct sk_buff *skb;
 
 		spin_lock_bh(&rcvq->lock);
-		while ((skb = skb_peek(rcvq)) != NULL) {
-			if (udp_lib_checksum_complete(skb)) {
-				UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite);
-				__skb_unlink(skb, rcvq);
-				kfree_skb(skb);
-			} else {
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
-				break;
-			}
+		while ((skb = skb_peek(rcvq)) != NULL &&
+		       udp_lib_checksum_complete(skb)) {
+			UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_lite);
+			__skb_unlink(skb, rcvq);
+			kfree_skb(skb);
 		}
 		spin_unlock_bh(&rcvq->lock);
 
@@ -1573,7 +1661,7 @@ static struct sock *udp_get_idx(struct s
 	struct sock *sk = udp_get_first(seq);
 
 	if (sk)
-		while(pos && (sk = udp_get_next(seq, sk)) != NULL)
+		while (pos && (sk = udp_get_next(seq, sk)) != NULL)
 			--pos;
 	return pos ? NULL : sk;
 }
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index b28fe1e..f34fd68 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -31,7 +31,7 @@ static int udplite_v4_get_port(struct so
 
 static int udplite_rcv(struct sk_buff *skb)
 {
-	return __udp4_lib_rcv(skb, udplite_hash, 1);
+	return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
 }
 
 static void udplite_err(struct sk_buff *skb, u32 info)
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 78e80de..5ceca95 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -28,7 +28,7 @@ static int xfrm4_parse_spi(struct sk_buf
 	switch (nexthdr) {
 	case IPPROTO_IPIP:
 	case IPPROTO_IPV6:
-		*spi = skb->nh.iph->saddr;
+		*spi = ip_hdr(skb)->saddr;
 		*seq = 0;
 		return 0;
 	}
@@ -39,9 +39,9 @@ static int xfrm4_parse_spi(struct sk_buf
 #ifdef CONFIG_NETFILTER
 static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
-
 	if (skb->dst == NULL) {
+		const struct iphdr *iph = ip_hdr(skb);
+
 		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
 				   skb->dev))
 			goto drop;
@@ -55,18 +55,18 @@ #endif
 
 int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 {
-	int err;
 	__be32 spi, seq;
 	struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
 	struct xfrm_state *x;
 	int xfrm_nr = 0;
 	int decaps = 0;
+	int err = xfrm4_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq);
 
-	if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
+	if (err != 0)
 		goto drop;
 
 	do {
-		struct iphdr *iph = skb->nh.iph;
+		const struct iphdr *iph = ip_hdr(skb);
 
 		if (xfrm_nr == XFRM_MAX_DEPTH)
 			goto drop;
@@ -113,7 +113,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb,
 			break;
 		}
 
-		if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
+		err = xfrm_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq);
+		if (err < 0)
 			goto drop;
 	} while (!err);
 
@@ -146,15 +147,15 @@ int xfrm4_rcv_encap(struct sk_buff *skb,
 		return 0;
 	} else {
 #ifdef CONFIG_NETFILTER
-		__skb_push(skb, skb->data - skb->nh.raw);
-		skb->nh.iph->tot_len = htons(skb->len);
-		ip_send_check(skb->nh.iph);
+		__skb_push(skb, skb->data - skb_network_header(skb));
+		ip_hdr(skb)->tot_len = htons(skb->len);
+		ip_send_check(ip_hdr(skb));
 
 		NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
 			xfrm4_rcv_encap_finish);
 		return 0;
 #else
-		return -skb->nh.iph->protocol;
+		return -ip_hdr(skb)->protocol;
 #endif
 	}
 
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index d419e15..a73e710 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -29,20 +29,21 @@ #include <net/xfrm.h>
  */
 static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct iphdr *iph, *top_iph = NULL;
+	struct iphdr *iph, *top_iph;
 	int hdrlen, optlen;
 
-	iph = skb->nh.iph;
-	skb->h.ipiph = iph;
+	iph = ip_hdr(skb);
+	skb->transport_header = skb->network_header;
 
 	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;
-	skb->h.raw += sizeof(*iph) - hdrlen;
+	skb_push(skb, x->props.header_len - IPV4_BEET_PHMAXLEN + hdrlen);
+	skb_reset_network_header(skb);
+	top_iph = ip_hdr(skb);
+	skb->transport_header += sizeof(*iph) - hdrlen;
 
 	memmove(top_iph, iph, sizeof(*iph));
 	if (unlikely(optlen)) {
@@ -50,7 +51,7 @@ static int xfrm4_beet_output(struct xfrm
 
 		BUG_ON(optlen < 0);
 
-		ph = (struct ip_beet_phdr *)skb->h.raw;
+		ph = (struct ip_beet_phdr *)skb_transport_header(skb);
 		ph->padlen = 4 - (optlen & 4);
 		ph->hdrlen = optlen / 8;
 		ph->nexthdr = top_iph->protocol;
@@ -69,20 +70,18 @@ static int xfrm4_beet_output(struct xfrm
 
 static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
 	int phlen = 0;
 	int optlen = 0;
-	__u8 ph_nexthdr = 0, protocol = 0;
+	u8 ph_nexthdr = 0;
 	int err = -EINVAL;
 
-	protocol = iph->protocol;
-
 	if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
 		struct ip_beet_phdr *ph;
 
 		if (!pskb_may_pull(skb, sizeof(*ph)))
 			goto out;
-		ph = (struct ip_beet_phdr *)(skb->h.ipiph + 1);
+		ph = (struct ip_beet_phdr *)(ipip_hdr(skb) + 1);
 
 		phlen = sizeof(*ph) + ph->padlen;
 		optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
@@ -96,22 +95,20 @@ static int xfrm4_beet_input(struct xfrm_
 		ph_nexthdr = ph->nexthdr;
 	}
 
-	skb->nh.raw = skb->data + (phlen - sizeof(*iph));
-	memmove(skb->nh.raw, iph, sizeof(*iph));
-	skb->h.raw = skb->data + (phlen + optlen);
-	skb->data = skb->h.raw;
+	skb_set_network_header(skb, phlen - sizeof(*iph));
+	memmove(skb_network_header(skb), iph, sizeof(*iph));
+	skb_set_transport_header(skb, phlen + optlen);
+	skb->data = skb_transport_header(skb);
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	iph->ihl = (sizeof(*iph) + optlen) / 4;
 	iph->tot_len = htons(skb->len + iph->ihl * 4);
 	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);
+	iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
 	err = 0;
 out:
 	return err;
diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c
index 92676b7..6010471 100644
--- a/net/ipv4/xfrm4_mode_transport.c
+++ b/net/ipv4/xfrm4_mode_transport.c
@@ -23,16 +23,13 @@ #include <net/xfrm.h>
  */
 static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct iphdr *iph;
-	int ihl;
+	struct iphdr *iph = ip_hdr(skb);
+	int ihl = iph->ihl * 4;
 
-	iph = skb->nh.iph;
-	skb->h.ipiph = iph;
-
-	ihl = iph->ihl * 4;
-	skb->h.raw += ihl;
-
-	skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl);
+	skb->transport_header = skb->network_header + ihl;
+	skb_push(skb, x->props.header_len);
+	skb_reset_network_header(skb);
+	memmove(skb_network_header(skb), iph, ihl);
 	return 0;
 }
 
@@ -46,12 +43,15 @@ static int xfrm4_transport_output(struct
  */
 static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	int ihl = skb->data - skb->h.raw;
+	int ihl = skb->data - skb_transport_header(skb);
 
-	if (skb->h.raw != skb->nh.raw)
-		skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);
-	skb->nh.iph->tot_len = htons(skb->len + ihl);
-	skb->h.raw = skb->data;
+	if (skb->transport_header != skb->network_header) {
+		memmove(skb_transport_header(skb),
+			skb_network_header(skb), ihl);
+		skb->network_header = skb->transport_header;
+	}
+	ip_hdr(skb)->tot_len = htons(skb->len + ihl);
+	skb_reset_transport_header(skb);
 	return 0;
 }
 
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index ceb4376..a2f2e6a 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -16,8 +16,8 @@ #include <net/xfrm.h>
 
 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
 {
-	struct iphdr *outer_iph = skb->nh.iph;
-	struct iphdr *inner_iph = skb->h.ipiph;
+	struct iphdr *outer_iph = ip_hdr(skb);
+	struct iphdr *inner_iph = ipip_hdr(skb);
 
 	if (INET_ECN_is_ce(outer_iph->tos))
 		IP_ECN_set_ce(inner_iph);
@@ -26,7 +26,7 @@ static inline void ipip_ecn_decapsulate(
 static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
 {
 	if (INET_ECN_is_ce(iph->tos))
-		IP6_ECN_set_ce(skb->nh.ipv6h);
+		IP6_ECN_set_ce(ipv6_hdr(skb));
 }
 
 /* Add encapsulation header.
@@ -46,11 +46,12 @@ static int xfrm4_tunnel_output(struct xf
 	struct iphdr *iph, *top_iph;
 	int flags;
 
-	iph = skb->nh.iph;
-	skb->h.ipiph = iph;
+	iph = ip_hdr(skb);
+	skb->transport_header = skb->network_header;
 
-	skb->nh.raw = skb_push(skb, x->props.header_len);
-	top_iph = skb->nh.iph;
+	skb_push(skb, x->props.header_len);
+	skb_reset_network_header(skb);
+	top_iph = ip_hdr(skb);
 
 	top_iph->ihl = 5;
 	top_iph->version = 4;
@@ -90,10 +91,11 @@ #endif
 
 static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct iphdr *iph = skb->nh.iph;
+	struct iphdr *iph = ip_hdr(skb);
+	const unsigned char *old_mac;
 	int err = -EINVAL;
 
-	switch(iph->protocol){
+	switch (iph->protocol){
 		case IPPROTO_IPIP:
 			break;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -111,10 +113,10 @@ #endif
 	    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 		goto out;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 	if (iph->protocol == IPPROTO_IPIP) {
 		if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-			ipv4_copy_dscp(iph, skb->h.ipiph);
+			ipv4_copy_dscp(iph, ipip_hdr(skb));
 		if (!(x->props.flags & XFRM_STATE_NOECN))
 			ipip_ecn_decapsulate(skb);
 	}
@@ -125,9 +127,10 @@ #if defined(CONFIG_IPV6) || defined (CON
 		skb->protocol = htons(ETH_P_IPV6);
 	}
 #endif
-	skb->mac.raw = memmove(skb->data - skb->mac_len,
-			       skb->mac.raw, skb->mac_len);
-	skb->nh.raw = skb->data;
+	old_mac = skb_mac_header(skb);
+	skb_set_mac_header(skb, -skb->mac_len);
+	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+	skb_reset_network_header(skb);
 	err = 0;
 
 out:
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 038ca16..44ef208 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -22,14 +22,13 @@ static int xfrm4_tunnel_check_size(struc
 {
 	int mtu, ret = 0;
 	struct dst_entry *dst;
-	struct iphdr *iph = skb->nh.iph;
 
 	if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
 		goto out;
 
 	IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
 
-	if (!(iph->frag_off & htons(IP_DF)) || skb->local_df)
+	if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
 		goto out;
 
 	dst = skb->dst;
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 5d51a2a..4ff8ed3 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -119,7 +119,7 @@ __xfrm4_bundle_create(struct xfrm_policy
 
 		if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) {
 			unsigned short encap_family = xfrm[i]->props.family;
-			switch(encap_family) {
+			switch (encap_family) {
 			case AF_INET:
 				fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
 				fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
@@ -209,8 +209,8 @@ error:
 static void
 _decode_session4(struct sk_buff *skb, struct flowi *fl)
 {
-	struct iphdr *iph = skb->nh.iph;
-	u8 *xprth = skb->nh.raw + iph->ihl*4;
+	struct iphdr *iph = ip_hdr(skb);
+	u8 *xprth = skb_network_header(skb) + iph->ihl * 4;
 
 	memset(fl, 0, sizeof(struct flowi));
 	if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {
@@ -263,7 +263,7 @@ _decode_session4(struct sk_buff *skb, st
 		default:
 			fl->fl_ipsec_spi = 0;
 			break;
-		};
+		}
 	}
 	fl->proto = iph->protocol;
 	fl->fl4_dst = iph->daddr;
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 3eef064..5685103 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -12,9 +12,8 @@ #include <net/protocol.h>
 
 static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct iphdr *iph;
+	struct iphdr *iph = ip_hdr(skb);
 
-	iph = skb->nh.iph;
 	iph->tot_len = htons(skb->len);
 	ip_send_check(iph);
 
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 79682ef..8e5d54f 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -57,6 +57,16 @@ config IPV6_ROUTE_INFO
 
 	  If unsure, say N.
 
+config IPV6_OPTIMISTIC_DAD
+	bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)"
+	depends on IPV6 && EXPERIMENTAL
+	---help---
+	  This is experimental support for optimistic Duplicate
+	  Address Detection.  It allows for autoconfigured addresses
+	  to be used more quickly.
+
+	  If unsure, say N.
+
 config INET6_AH
 	tristate "IPv6: AH transformation"
 	depends on IPV6
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index d460017..bb33309 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -7,14 +7,15 @@ obj-$(CONFIG_IPV6) += ipv6.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 udplite.o \
 		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
-		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
-		ip6_flowlabel.o ipv6_syms.o inet6_connection_sock.o
+		exthdrs.o sysctl_net_ipv6.o datagram.o \
+		ip6_flowlabel.o inet6_connection_sock.o
 
 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-$(CONFIG_PROC_FS) += proc.o
 
 ipv6-objs += $(ipv6-y)
 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 452a82c..d02685c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -81,6 +81,7 @@ #include <linux/random.h>
 #endif
 
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -208,9 +209,7 @@ #endif
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
-#if 0
 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-#endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -246,6 +245,37 @@ static void addrconf_mod_timer(struct in
 	add_timer(&ifp->timer);
 }
 
+static int snmp6_alloc_dev(struct inet6_dev *idev)
+{
+	int err = -ENOMEM;
+
+	if (!idev || !idev->dev)
+		return -EINVAL;
+
+	if (snmp_mib_init((void **)idev->stats.ipv6,
+			  sizeof(struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
+		goto err_ip;
+	if (snmp_mib_init((void **)idev->stats.icmpv6,
+			  sizeof(struct icmpv6_mib),
+			  __alignof__(struct icmpv6_mib)) < 0)
+		goto err_icmp;
+
+	return 0;
+
+err_icmp:
+	snmp_mib_free((void **)idev->stats.ipv6);
+err_ip:
+	return err;
+}
+
+static int snmp6_free_dev(struct inet6_dev *idev)
+{
+	snmp_mib_free((void **)idev->stats.icmpv6);
+	snmp_mib_free((void **)idev->stats.ipv6);
+	return 0;
+}
+
 /* Nobody refers to this device, we may destroy it. */
 
 static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
@@ -271,6 +301,8 @@ #endif
 	call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
 }
 
+EXPORT_SYMBOL(in6_dev_finish_destroy);
+
 static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 {
 	struct inet6_dev *ndev;
@@ -417,7 +449,7 @@ static void addrconf_forward_change(void
 	struct inet6_dev *idev;
 
 	read_lock(&dev_base_lock);
-	for (dev=dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		rcu_read_lock();
 		idev = __in6_dev_get(dev);
 		if (idev) {
@@ -528,6 +560,16 @@ ipv6_add_addr(struct inet6_dev *idev, co
 
 	ifa->rt = rt;
 
+	/*
+	 * part one of RFC 4429, section 3.3
+	 * We should not configure an address as
+	 * optimistic if we do not yet know the link
+	 * layer address of our nexhop router
+	 */
+
+	if (rt->rt6i_nexthop == NULL)
+		ifa->flags &= ~IFA_F_OPTIMISTIC;
+
 	ifa->idev = idev;
 	in6_dev_hold(idev);
 	/* For caller */
@@ -704,6 +746,7 @@ static int ipv6_create_tempaddr(struct i
 	int tmp_plen;
 	int ret = 0;
 	int max_addresses;
+	u32 addr_flags;
 
 	write_lock(&idev->lock);
 	if (ift) {
@@ -761,10 +804,17 @@ retry:
 	spin_unlock_bh(&ifp->lock);
 
 	write_unlock(&idev->lock);
+
+	addr_flags = IFA_F_TEMPORARY;
+	/* set in addrconf_prefix_rcv() */
+	if (ifp->flags & IFA_F_OPTIMISTIC)
+		addr_flags |= IFA_F_OPTIMISTIC;
+
 	ift = !max_addresses ||
 	      ipv6_count_addresses(idev) < max_addresses ?
 		ipv6_add_addr(idev, &addr, tmp_plen,
-			      ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
+			      ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
+			      addr_flags) : NULL;
 	if (!ift || IS_ERR(ift)) {
 		in6_ifa_put(ifp);
 		in6_dev_put(idev);
@@ -861,7 +911,7 @@ int ipv6_dev_get_saddr(struct net_device
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
 
-	for (dev = dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		struct inet6_dev *idev;
 		struct inet6_ifaddr *ifa;
 
@@ -896,13 +946,14 @@ int ipv6_dev_get_saddr(struct net_device
 			 * - Tentative Address (RFC2462 section 5.4)
 			 *  - A tentative address is not considered
 			 *    "assigned to an interface" in the traditional
-			 *    sense.
+			 *    sense, unless it is also flagged as optimistic.
 			 * - Candidate Source Address (section 4)
 			 *  - In any case, anycast addresses, multicast
 			 *    addresses, and the unspecified address MUST
 			 *    NOT be included in a candidate set.
 			 */
-			if (ifa->flags & IFA_F_TENTATIVE)
+			if ((ifa->flags & IFA_F_TENTATIVE) &&
+			    (!(ifa->flags & IFA_F_OPTIMISTIC)))
 				continue;
 			if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
 				     score.addr_type & IPV6_ADDR_MULTICAST)) {
@@ -961,15 +1012,17 @@ int ipv6_dev_get_saddr(struct net_device
 				}
 			}
 
-			/* Rule 3: Avoid deprecated address */
+			/* Rule 3: Avoid deprecated and optimistic addresses */
 			if (hiscore.rule < 3) {
 				if (ipv6_saddr_preferred(hiscore.addr_type) ||
-				    !(ifa_result->flags & IFA_F_DEPRECATED))
+				   (((ifa_result->flags &
+				    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
 					hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
 				hiscore.rule++;
 			}
 			if (ipv6_saddr_preferred(score.addr_type) ||
-			    !(ifa->flags & IFA_F_DEPRECATED)) {
+			   (((ifa_result->flags &
+			    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
 				score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
 				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
 					score.rule = 3;
@@ -1107,8 +1160,10 @@ int ipv6_get_saddr(struct dst_entry *dst
 	return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
 }
 
+EXPORT_SYMBOL(ipv6_get_saddr);
 
-int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
+int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
+		    unsigned char banned_flags)
 {
 	struct inet6_dev *idev;
 	int err = -EADDRNOTAVAIL;
@@ -1119,7 +1174,7 @@ int ipv6_get_lladdr(struct net_device *d
 
 		read_lock_bh(&idev->lock);
 		for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-			if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
+			if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
 				ipv6_addr_copy(addr, &ifp->addr);
 				err = 0;
 				break;
@@ -1161,6 +1216,8 @@ int ipv6_chk_addr(struct in6_addr *addr,
 	return ifp != NULL;
 }
 
+EXPORT_SYMBOL(ipv6_chk_addr);
+
 static
 int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
 {
@@ -1669,6 +1726,13 @@ ok:
 
 		if (ifp == NULL && valid_lft) {
 			int max_addresses = in6_dev->cnf.max_addresses;
+			u32 addr_flags = 0;
+
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+			if (in6_dev->cnf.optimistic_dad &&
+			    !ipv6_devconf.forwarding)
+				addr_flags = IFA_F_OPTIMISTIC;
+#endif
 
 			/* Do not allow to create too much of autoconfigured
 			 * addresses; this would be too easy way to crash kernel.
@@ -1676,7 +1740,8 @@ ok:
 			if (!max_addresses ||
 			    ipv6_count_addresses(in6_dev) < max_addresses)
 				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
-						    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
+						    addr_type&IPV6_ADDR_SCOPE_MASK,
+						    addr_flags);
 
 			if (!ifp || IS_ERR(ifp)) {
 				in6_dev_put(in6_dev);
@@ -1884,6 +1949,11 @@ static int inet6_addr_add(int ifindex, s
 
 		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
 				      jiffies_to_clock_t(valid_lft * HZ), flags);
+		/*
+		 * Note that section 3.1 of RFC 4429 indicates
+		 * that the Optimistic flag should not be set for
+		 * manually configured addresses
+		 */
 		addrconf_dad_start(ifp, 0);
 		in6_ifa_put(ifp);
 		addrconf_verify(0);
@@ -1994,7 +2064,7 @@ static void sit_add_v4_addrs(struct inet
 		return;
 	}
 
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		struct in_device * in_dev = __in_dev_get_rtnl(dev);
 		if (in_dev && (dev->flags & IFF_UP)) {
 			struct in_ifaddr * ifa;
@@ -2060,8 +2130,16 @@ static void init_loopback(struct net_dev
 static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
 {
 	struct inet6_ifaddr * ifp;
+	u32 addr_flags = IFA_F_PERMANENT;
+
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+	if (idev->cnf.optimistic_dad &&
+	    !ipv6_devconf.forwarding)
+		addr_flags |= IFA_F_OPTIMISTIC;
+#endif
+
 
-	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
+	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
 	if (!IS_ERR(ifp)) {
 		addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
 		addrconf_dad_start(ifp, 0);
@@ -2129,7 +2207,7 @@ ipv6_inherit_linklocal(struct inet6_dev 
 {
 	struct in6_addr lladdr;
 
-	if (!ipv6_get_lladdr(link_dev, &lladdr)) {
+	if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {
 		addrconf_add_linklocal(idev, &lladdr);
 		return 0;
 	}
@@ -2147,7 +2225,7 @@ static void ip6_tnl_add_linklocal(struct
 			return;
 	}
 	/* then try to inherit it from any device */
-	for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {
+	for_each_netdev(link_dev) {
 		if (!ipv6_inherit_linklocal(idev, link_dev))
 			return;
 	}
@@ -2240,7 +2318,7 @@ #endif
 		default:
 			addrconf_dev_config(dev);
 			break;
-		};
+		}
 		if (idev) {
 			if (run_pending)
 				addrconf_dad_run(idev);
@@ -2281,8 +2359,9 @@ #endif
 		break;
 
 	case NETDEV_CHANGENAME:
-#ifdef CONFIG_SYSCTL
 		if (idev) {
+			snmp6_unregister_dev(idev);
+#ifdef CONFIG_SYSCTL
 			addrconf_sysctl_unregister(&idev->cnf);
 			neigh_sysctl_unregister(idev->nd_parms);
 			neigh_sysctl_register(dev, idev->nd_parms,
@@ -2290,10 +2369,11 @@ #ifdef CONFIG_SYSCTL
 					      &ndisc_ifinfo_sysctl_change,
 					      NULL);
 			addrconf_sysctl_register(idev, &idev->cnf);
-		}
 #endif
+			snmp6_register_dev(idev);
+		}
 		break;
-	};
+	}
 
 	return NOTIFY_OK;
 }
@@ -2474,7 +2554,11 @@ static void addrconf_dad_kick(struct ine
 	unsigned long rand_num;
 	struct inet6_dev *idev = ifp->idev;
 
-	rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
+	if (ifp->flags & IFA_F_OPTIMISTIC)
+		rand_num = 0;
+	else
+		rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
+
 	ifp->probes = idev->cnf.dad_transmits;
 	addrconf_mod_timer(ifp, AC_DAD, rand_num);
 }
@@ -2496,7 +2580,7 @@ static void addrconf_dad_start(struct in
 	if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
 	    !(ifp->flags&IFA_F_TENTATIVE) ||
 	    ifp->flags & IFA_F_NODAD) {
-		ifp->flags &= ~IFA_F_TENTATIVE;
+		ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
 		spin_unlock_bh(&ifp->lock);
 		read_unlock_bh(&idev->lock);
 
@@ -2516,6 +2600,14 @@ static void addrconf_dad_start(struct in
 		addrconf_dad_stop(ifp);
 		return;
 	}
+
+	/*
+	 * Optimistic nodes can start receiving
+	 * Frames right away
+	 */
+	if(ifp->flags & IFA_F_OPTIMISTIC)
+		ip6_ins_rt(ifp->rt);
+
 	addrconf_dad_kick(ifp);
 	spin_unlock_bh(&ifp->lock);
 out:
@@ -2540,7 +2632,7 @@ static void addrconf_dad_timer(unsigned 
 		 * DAD was successful
 		 */
 
-		ifp->flags &= ~IFA_F_TENTATIVE;
+		ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
 		spin_unlock_bh(&ifp->lock);
 		read_unlock_bh(&idev->lock);
 
@@ -3164,16 +3256,16 @@ static int inet6_dump_addr(struct sk_buf
 
 	s_idx = cb->args[0];
 	s_ip_idx = ip_idx = cb->args[1];
-	read_lock(&dev_base_lock);
 
-	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_ip_idx = 0;
 		ip_idx = 0;
 		if ((idev = in6_dev_get(dev)) == NULL)
-			continue;
+			goto cont;
 		read_lock_bh(&idev->lock);
 		switch (type) {
 		case UNICAST_ADDR:
@@ -3220,13 +3312,14 @@ static int inet6_dump_addr(struct sk_buf
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);
+cont:
+		idx++;
 	}
 done:
 	if (err <= 0) {
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);
 	}
-	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
 	cb->args[1] = ip_idx;
 	return skb->len;
@@ -3359,6 +3452,9 @@ #endif
 #endif
 	array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
 	array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+	array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
+#endif
 }
 
 static inline size_t inet6_if_nlmsg_size(void)
@@ -3372,14 +3468,44 @@ static inline size_t inet6_if_nlmsg_size
 			nla_total_size(4) /* IFLA_INET6_FLAGS */
 			+ nla_total_size(sizeof(struct ifla_cacheinfo))
 			+ nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
+			+ nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
+			+ nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
 		 );
 }
 
+static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items,
+				      int bytes)
+{
+	int i;
+	int pad = bytes - sizeof(u64) * items;
+	BUG_ON(pad < 0);
+
+	/* Use put_unaligned() because stats may not be aligned for u64. */
+	put_unaligned(items, &stats[0]);
+	for (i = 1; i < items; i++)
+		put_unaligned(snmp_fold_field(mib, i), &stats[i]);
+
+	memset(&stats[items], 0, pad);
+}
+
+static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
+			     int bytes)
+{
+	switch(attrtype) {
+	case IFLA_INET6_STATS:
+		__snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+		break;
+	case IFLA_INET6_ICMP6STATS:
+		__snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+		break;
+	}
+}
+
 static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
 			     u32 pid, u32 seq, int event, unsigned int flags)
 {
 	struct net_device *dev = idev->dev;
-	struct nlattr *conf;
+	struct nlattr *nla;
 	struct ifinfomsg *hdr;
 	struct nlmsghdr *nlh;
 	void *protoinfo;
@@ -3419,12 +3545,22 @@ static int inet6_fill_ifinfo(struct sk_b
 	ci.retrans_time = idev->nd_parms->retrans_time;
 	NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
 
-	conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
-	if (conf == NULL)
+	nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
+	if (nla == NULL)
 		goto nla_put_failure;
-	ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf));
+	ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla));
 
-	/* XXX - Statistics/MC not implemented */
+	/* XXX - MC not implemented */
+
+	nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64));
+	if (nla == NULL)
+		goto nla_put_failure;
+	snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla));
+
+	nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64));
+	if (nla == NULL)
+		goto nla_put_failure;
+	snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
 
 	nla_nest_end(skb, protoinfo);
 	return nlmsg_end(skb, nlh);
@@ -3442,16 +3578,19 @@ static int inet6_dump_ifinfo(struct sk_b
 	struct inet6_dev *idev;
 
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if ((idev = in6_dev_get(dev)) == NULL)
-			continue;
+			goto cont;
 		err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
 				cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
 		in6_dev_put(idev);
 		if (err <= 0)
 			break;
+cont:
+		idx++;
 	}
 	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
@@ -3550,30 +3689,20 @@ errout:
 		rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err);
 }
 
-static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
-	[RTM_GETLINK - RTM_BASE] = { .dumpit	= inet6_dump_ifinfo, },
-	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },
-	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, },
-	[RTM_GETADDR - RTM_BASE] = { .doit	= inet6_rtm_getaddr,
-				     .dumpit	= inet6_dump_ifaddr, },
-	[RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
-	[RTM_GETANYCAST - RTM_BASE] = { .dumpit	= inet6_dump_ifacaddr, },
-	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet6_rtm_newroute, },
-	[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)
 {
 	inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
 
 	switch (event) {
 	case RTM_NEWADDR:
-		ip6_ins_rt(ifp->rt);
+		/*
+		 * If the address was optimistic
+		 * we inserted the route at the start of
+		 * our DAD process, so we don't need
+		 * to do it again
+		 */
+		if (!(ifp->rt->rt6i_node))
+			ip6_ins_rt(ifp->rt);
 		if (ifp->idev->cnf.forwarding)
 			addrconf_join_anycast(ifp);
 		break;
@@ -3894,6 +4023,17 @@ #endif
 			.mode		=	0644,
 			.proc_handler	=	&proc_dointvec,
 		},
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+		{
+			.ctl_name	=	CTL_UNNUMBERED,
+			.procname       =       "optimistic_dad",
+			.data           =       &ipv6_devconf.optimistic_dad,
+			.maxlen         =       sizeof(int),
+			.mode           =       0644,
+			.proc_handler   =       &proc_dointvec,
+
+		},
+#endif
 		{
 			.ctl_name	=	0,	/* sentinel */
 		}
@@ -4021,11 +4161,15 @@ int register_inet6addr_notifier(struct n
 	return atomic_notifier_chain_register(&inet6addr_chain, nb);
 }
 
+EXPORT_SYMBOL(register_inet6addr_notifier);
+
 int unregister_inet6addr_notifier(struct notifier_block *nb)
 {
 	return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
 }
 
+EXPORT_SYMBOL(unregister_inet6addr_notifier);
+
 /*
  *	Init / cleanup code
  */
@@ -4064,7 +4208,18 @@ int __init addrconf_init(void)
 	register_netdevice_notifier(&ipv6_dev_notf);
 
 	addrconf_verify(0);
-	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
+
+	err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo);
+	if (err < 0)
+		goto errout;
+
+	/* Only the first call to __rtnl_register can fail */
+	__rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL);
+	__rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL);
+	__rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr, inet6_dump_ifaddr);
+	__rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, inet6_dump_ifmcaddr);
+	__rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, inet6_dump_ifacaddr);
+
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl.sysctl_header =
 		register_sysctl_table(addrconf_sysctl.addrconf_root_dir);
@@ -4072,6 +4227,10 @@ #ifdef CONFIG_SYSCTL
 #endif
 
 	return 0;
+errout:
+	unregister_netdevice_notifier(&ipv6_dev_notf);
+
+	return err;
 }
 
 void __exit addrconf_cleanup(void)
@@ -4083,7 +4242,6 @@ void __exit addrconf_cleanup(void)
 
 	unregister_netdevice_notifier(&ipv6_dev_notf);
 
-	rtnetlink_links[PF_INET6] = NULL;
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl_unregister(&ipv6_devconf_dflt);
 	addrconf_sysctl_unregister(&ipv6_devconf);
@@ -4095,7 +4253,7 @@ #endif
 	 *	clean dev list.
 	 */
 
-	for (dev=dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		if ((idev = __in6_dev_get(dev)) == NULL)
 			continue;
 		addrconf_ifdown(dev, 1);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 5cac14a..6dd3772 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -42,7 +42,6 @@ #include <linux/init.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/icmpv6.h>
-#include <linux/smp_lock.h>
 #include <linux/netfilter_ipv6.h>
 
 #include <net/ip.h>
@@ -98,6 +97,11 @@ static int inet6_create(struct socket *s
 	int try_loading_module = 0;
 	int err;
 
+	if (sock->type != SOCK_RAW &&
+	    sock->type != SOCK_DGRAM &&
+	    !inet_ehash_secret)
+		build_ehash_secret();
+
 	/* Look for the requested type/protocol pair. */
 	answer = NULL;
 lookup_protocol:
@@ -349,6 +353,8 @@ out:
 	return err;
 }
 
+EXPORT_SYMBOL(inet6_bind);
+
 int inet6_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
@@ -365,6 +371,8 @@ int inet6_release(struct socket *sock)
 	return inet_release(sock);
 }
 
+EXPORT_SYMBOL(inet6_release);
+
 int inet6_destroy_sock(struct sock *sk)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -428,6 +436,8 @@ int inet6_getname(struct socket *sock, s
 	return(0);
 }
 
+EXPORT_SYMBOL(inet6_getname);
+
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
@@ -437,6 +447,9 @@ int inet6_ioctl(struct socket *sock, uns
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *)arg);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *)arg);
+
 	case SIOCADDRT:
 	case SIOCDELRT:
 
@@ -457,6 +470,8 @@ int inet6_ioctl(struct socket *sock, uns
 	return(0);
 }
 
+EXPORT_SYMBOL(inet6_ioctl);
+
 const struct proto_ops inet6_stream_ops = {
 	.family		   = PF_INET6,
 	.owner		   = THIS_MODULE,
@@ -603,6 +618,8 @@ out_illegal:
 	goto out;
 }
 
+EXPORT_SYMBOL(inet6_register_protosw);
+
 void
 inet6_unregister_protosw(struct inet_protosw *p)
 {
@@ -619,6 +636,8 @@ inet6_unregister_protosw(struct inet_pro
 	}
 }
 
+EXPORT_SYMBOL(inet6_unregister_protosw);
+
 int inet6_sk_rebuild_header(struct sock *sk)
 {
 	int err;
@@ -678,7 +697,8 @@ int ipv6_opt_accepted(struct sock *sk, s
 	if (np->rxopt.all) {
 		if ((opt->hop && (np->rxopt.bits.hopopts ||
 				  np->rxopt.bits.ohopopts)) ||
-		    ((IPV6_FLOWINFO_MASK & *(__be32*)skb->nh.raw) &&
+		    ((IPV6_FLOWINFO_MASK &
+		      *(__be32 *)skb_network_header(skb)) &&
 		     np->rxopt.bits.rxflow) ||
 		    (opt->srcrt && (np->rxopt.bits.srcrt ||
 		     np->rxopt.bits.osrcrt)) ||
@@ -691,61 +711,28 @@ int ipv6_opt_accepted(struct sock *sk, s
 
 EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
-int
-snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign)
-{
-	if (ptr == NULL)
-		return -EINVAL;
-
-	ptr[0] = __alloc_percpu(mibsize);
-	if (!ptr[0])
-		goto err0;
-
-	ptr[1] = __alloc_percpu(mibsize);
-	if (!ptr[1])
-		goto err1;
-
-	return 0;
-
-err1:
-	free_percpu(ptr[0]);
-	ptr[0] = NULL;
-err0:
-	return -ENOMEM;
-}
-
-void
-snmp6_mib_free(void *ptr[2])
-{
-	if (ptr == NULL)
-		return;
-	free_percpu(ptr[0]);
-	free_percpu(ptr[1]);
-	ptr[0] = ptr[1] = NULL;
-}
-
 static int __init init_ipv6_mibs(void)
 {
-	if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib),
-			   __alignof__(struct ipstats_mib)) < 0)
+	if (snmp_mib_init((void **)ipv6_statistics, sizeof (struct ipstats_mib),
+			  __alignof__(struct ipstats_mib)) < 0)
 		goto err_ip_mib;
-	if (snmp6_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib),
-			   __alignof__(struct icmpv6_mib)) < 0)
+	if (snmp_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib),
+			  __alignof__(struct icmpv6_mib)) < 0)
 		goto err_icmp_mib;
-	if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib),
-			   __alignof__(struct udp_mib)) < 0)
+	if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		goto err_udp_mib;
-	if (snmp6_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib),
-			   __alignof__(struct udp_mib)) < 0)
+	if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib),
+			  __alignof__(struct udp_mib)) < 0)
 		goto err_udplite_mib;
 	return 0;
 
 err_udplite_mib:
-	snmp6_mib_free((void **)udp_stats_in6);
+	snmp_mib_free((void **)udp_stats_in6);
 err_udp_mib:
-	snmp6_mib_free((void **)icmpv6_statistics);
+	snmp_mib_free((void **)icmpv6_statistics);
 err_icmp_mib:
-	snmp6_mib_free((void **)ipv6_statistics);
+	snmp_mib_free((void **)ipv6_statistics);
 err_ip_mib:
 	return -ENOMEM;
 
@@ -753,10 +740,10 @@ err_ip_mib:
 
 static void cleanup_ipv6_mibs(void)
 {
-	snmp6_mib_free((void **)ipv6_statistics);
-	snmp6_mib_free((void **)icmpv6_statistics);
-	snmp6_mib_free((void **)udp_stats_in6);
-	snmp6_mib_free((void **)udplite_stats_in6);
+	snmp_mib_free((void **)ipv6_statistics);
+	snmp_mib_free((void **)icmpv6_statistics);
+	snmp_mib_free((void **)udp_stats_in6);
+	snmp_mib_free((void **)udplite_stats_in6);
 }
 
 static int __init inet6_init(void)
@@ -929,6 +916,8 @@ static void __exit inet6_exit(void)
 {
 	/* First of all disallow new sockets creation. */
 	sock_unregister(PF_INET6);
+	/* Disallow any further netlink messages */
+	rtnl_unregister_all(PF_INET6);
 
 	/* Cleanup code parts. */
 	ipv6_packet_cleanup();
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index dc68b72..b696c84 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -238,8 +238,8 @@ #endif
 	top_iph = (struct ipv6hdr *)skb->data;
 	top_iph->payload_len = htons(skb->len - sizeof(*top_iph));
 
-	nexthdr = *skb->nh.raw;
-	*skb->nh.raw = IPPROTO_AH;
+	nexthdr = *skb_network_header(skb);
+	*skb_network_header(skb) = IPPROTO_AH;
 
 	/* When there are no extension headers, we only need to save the first
 	 * 8 bytes of the base IP header.
@@ -247,7 +247,7 @@ #endif
 	memcpy(tmp_base, top_iph, sizeof(tmp_base));
 
 	tmp_ext = NULL;
-	extlen = skb->h.raw - (unsigned char *)(top_iph + 1);
+	extlen = skb_transport_offset(skb) + sizeof(struct ipv6hdr);
 	if (extlen) {
 		extlen += sizeof(*tmp_ext);
 		tmp_ext = kmalloc(extlen, GFP_ATOMIC);
@@ -268,7 +268,7 @@ #endif
 			goto error_free_iph;
 	}
 
-	ah = (struct ip_auth_hdr *)skb->h.raw;
+	ah = (struct ip_auth_hdr *)skb_transport_header(skb);
 	ah->nexthdr = nexthdr;
 
 	top_iph->priority    = 0;
@@ -316,8 +316,8 @@ static int ah6_input(struct xfrm_state *
 	 *
 	 * To erase AH:
 	 * Keeping copy of cleared headers. After AH processing,
-	 * Moving the pointer of skb->nh.raw by using skb_pull as long as AH
-	 * header length. Then copy back the copy as long as hdr_len
+	 * Moving the pointer of skb->network_header by using skb_pull as long
+	 * as AH header length. Then copy back the copy as long as hdr_len
 	 * If destination header following AH exists, copy it into after [Ext2].
 	 *
 	 * |<>|[IPv6][Ext1][Ext2][Dest][Payload]
@@ -325,6 +325,7 @@ static int ah6_input(struct xfrm_state *
 	 */
 
 	struct ipv6_auth_hdr *ah;
+	struct ipv6hdr *ip6h;
 	struct ah_data *ahp;
 	unsigned char *tmp_hdr = NULL;
 	u16 hdr_len;
@@ -341,7 +342,7 @@ static int ah6_input(struct xfrm_state *
 	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
 		goto out;
 
-	hdr_len = skb->data - skb->nh.raw;
+	hdr_len = skb->data - skb_network_header(skb);
 	ah = (struct ipv6_auth_hdr*)skb->data;
 	ahp = x->data;
 	nexthdr = ah->nexthdr;
@@ -354,16 +355,17 @@ static int ah6_input(struct xfrm_state *
 	if (!pskb_may_pull(skb, ah_hlen))
 		goto out;
 
-	tmp_hdr = kmemdup(skb->nh.raw, hdr_len, GFP_ATOMIC);
+	tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC);
 	if (!tmp_hdr)
 		goto out;
-	if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN))
+	ip6h = ipv6_hdr(skb);
+	if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN))
 		goto free_out;
-	skb->nh.ipv6h->priority    = 0;
-	skb->nh.ipv6h->flow_lbl[0] = 0;
-	skb->nh.ipv6h->flow_lbl[1] = 0;
-	skb->nh.ipv6h->flow_lbl[2] = 0;
-	skb->nh.ipv6h->hop_limit   = 0;
+	ip6h->priority    = 0;
+	ip6h->flow_lbl[0] = 0;
+	ip6h->flow_lbl[1] = 0;
+	ip6h->flow_lbl[2] = 0;
+	ip6h->hop_limit   = 0;
 
 	{
 		u8 auth_data[MAX_AH_AUTH_LEN];
@@ -382,7 +384,9 @@ static int ah6_input(struct xfrm_state *
 		}
 	}
 
-	skb->h.raw = memcpy(skb->nh.raw += ah_hlen, tmp_hdr, hdr_len);
+	skb->network_header += ah_hlen;
+	memcpy(skb_network_header(skb), tmp_hdr, hdr_len);
+	skb->transport_header = skb->network_header;
 	__skb_pull(skb, ah_hlen + hdr_len);
 
 	kfree(tmp_hdr);
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 09117d6..9b81264 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -423,14 +423,18 @@ static int ipv6_chk_acast_dev(struct net
  */
 int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
 {
+	int found = 0;
+
 	if (dev)
 		return ipv6_chk_acast_dev(dev, addr);
 	read_lock(&dev_base_lock);
-	for (dev=dev_base; dev; dev=dev->next)
-		if (ipv6_chk_acast_dev(dev, addr))
+	for_each_netdev(dev)
+		if (ipv6_chk_acast_dev(dev, addr)) {
+			found = 1;
 			break;
+		}
 	read_unlock(&dev_base_lock);
-	return dev != 0;
+	return found;
 }
 
 
@@ -447,9 +451,8 @@ static inline struct ifacaddr6 *ac6_get_
 	struct ifacaddr6 *im = NULL;
 	struct ac6_iter_state *state = ac6_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->idev = NULL;
+	for_each_netdev(state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (!idev)
@@ -476,7 +479,7 @@ static struct ifacaddr6 *ac6_get_next(st
 			read_unlock_bh(&state->idev->lock);
 			in6_dev_put(state->idev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_net_device(state->dev);
 		if (!state->dev) {
 			state->idev = NULL;
 			break;
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 3b4e8dc..403eee6 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -209,7 +209,7 @@ void ipv6_icmp_error(struct sock *sk, st
 		     __be16 port, u32 info, u8 *payload)
 {
 	struct ipv6_pinfo *np  = inet6_sk(sk);
-	struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
+	struct icmp6hdr *icmph = icmp6_hdr(skb);
 	struct sock_exterr_skb *serr;
 
 	if (!np->recverr)
@@ -227,11 +227,12 @@ void ipv6_icmp_error(struct sock *sk, st
 	serr->ee.ee_pad = 0;
 	serr->ee.ee_info = info;
 	serr->ee.ee_data = 0;
-	serr->addr_offset = (u8*)&(((struct ipv6hdr*)(icmph+1))->daddr) - skb->nh.raw;
+	serr->addr_offset = (u8 *)&(((struct ipv6hdr *)(icmph + 1))->daddr) -
+				  skb_network_header(skb);
 	serr->port = port;
 
-	skb->h.raw = payload;
 	__skb_pull(skb, payload - skb->data);
+	skb_reset_transport_header(skb);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -251,8 +252,9 @@ void ipv6_local_error(struct sock *sk, i
 	if (!skb)
 		return;
 
-	iph = (struct ipv6hdr*)skb_put(skb, sizeof(struct ipv6hdr));
-	skb->nh.ipv6h = iph;
+	skb_put(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	iph = ipv6_hdr(skb);
 	ipv6_addr_copy(&iph->daddr, &fl->fl6_dst);
 
 	serr = SKB_EXT_ERR(skb);
@@ -263,11 +265,11 @@ void ipv6_local_error(struct sock *sk, i
 	serr->ee.ee_pad = 0;
 	serr->ee.ee_info = info;
 	serr->ee.ee_data = 0;
-	serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+	serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb);
 	serr->port = fl->fl_ip_dport;
 
-	skb->h.raw = skb->tail;
-	__skb_pull(skb, skb->tail - skb->data);
+	__skb_pull(skb, skb_tail_pointer(skb) - skb->data);
+	skb_reset_transport_header(skb);
 
 	if (sock_queue_err_skb(sk, skb))
 		kfree_skb(skb);
@@ -309,21 +311,24 @@ int ipv6_recv_error(struct sock *sk, str
 
 	sin = (struct sockaddr_in6 *)msg->msg_name;
 	if (sin) {
+		const unsigned char *nh = skb_network_header(skb);
 		sin->sin6_family = AF_INET6;
 		sin->sin6_flowinfo = 0;
 		sin->sin6_port = serr->port;
 		sin->sin6_scope_id = 0;
 		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
 			ipv6_addr_copy(&sin->sin6_addr,
-			  (struct in6_addr *)(skb->nh.raw + serr->addr_offset));
+				  (struct in6_addr *)(nh + serr->addr_offset));
 			if (np->sndflow)
-				sin->sin6_flowinfo = *(__be32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
+				sin->sin6_flowinfo =
+					(*(__be32 *)(nh + serr->addr_offset - 24) &
+					 IPV6_FLOWINFO_MASK);
 			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 				sin->sin6_scope_id = IP6CB(skb)->iif;
 		} else {
 			ipv6_addr_set(&sin->sin6_addr, 0, 0,
 				      htonl(0xffff),
-				      *(__be32*)(skb->nh.raw + serr->addr_offset));
+				      *(__be32 *)(nh + serr->addr_offset));
 		}
 	}
 
@@ -335,7 +340,7 @@ int ipv6_recv_error(struct sock *sk, str
 		sin->sin6_flowinfo = 0;
 		sin->sin6_scope_id = 0;
 		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
-			ipv6_addr_copy(&sin->sin6_addr, &skb->nh.ipv6h->saddr);
+			ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
 			if (np->rxopt.all)
 				datagram_recv_ctl(sk, msg, skb);
 			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -344,8 +349,7 @@ int ipv6_recv_error(struct sock *sk, str
 			struct inet_sock *inet = inet_sk(sk);
 
 			ipv6_addr_set(&sin->sin6_addr, 0, 0,
-				      htonl(0xffff),
-				      skb->nh.iph->saddr);
+				      htonl(0xffff), ip_hdr(skb)->saddr);
 			if (inet->cmsg_flags)
 				ip_cmsg_recv(msg, skb);
 		}
@@ -381,33 +385,34 @@ int datagram_recv_ctl(struct sock *sk, s
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct inet6_skb_parm *opt = IP6CB(skb);
+	unsigned char *nh = skb_network_header(skb);
 
 	if (np->rxopt.bits.rxinfo) {
 		struct in6_pktinfo src_info;
 
 		src_info.ipi6_ifindex = opt->iif;
-		ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
+		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
 		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
 	}
 
 	if (np->rxopt.bits.rxhlim) {
-		int hlim = skb->nh.ipv6h->hop_limit;
+		int hlim = ipv6_hdr(skb)->hop_limit;
 		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
 	}
 
 	if (np->rxopt.bits.rxtclass) {
-		int tclass = (ntohl(*(__be32 *)skb->nh.ipv6h) >> 20) & 0xff;
+		int tclass = (ntohl(*(__be32 *)ipv6_hdr(skb)) >> 20) & 0xff;
 		put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
 	}
 
-	if (np->rxopt.bits.rxflow && (*(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK)) {
-		__be32 flowinfo = *(__be32*)skb->nh.raw & IPV6_FLOWINFO_MASK;
+	if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) {
+		__be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK;
 		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
 	}
 
 	/* HbH is allowed only once */
 	if (np->rxopt.bits.hopopts && opt->hop) {
-		u8 *ptr = skb->nh.raw + opt->hop;
+		u8 *ptr = nh + opt->hop;
 		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
 	}
 
@@ -423,11 +428,11 @@ int datagram_recv_ctl(struct sock *sk, s
 		 * IPV6_RECVDSTOPTS is more generic. --yoshfuji
 		 */
 		unsigned int off = sizeof(struct ipv6hdr);
-		u8 nexthdr = skb->nh.ipv6h->nexthdr;
+		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
 
 		while (off <= opt->lastopt) {
 			unsigned len;
-			u8 *ptr = skb->nh.raw + off;
+			u8 *ptr = nh + off;
 
 			switch(nexthdr) {
 			case IPPROTO_DSTOPTS:
@@ -461,27 +466,27 @@ int datagram_recv_ctl(struct sock *sk, s
 		struct in6_pktinfo src_info;
 
 		src_info.ipi6_ifindex = opt->iif;
-		ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
+		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);
 		put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
 	}
 	if (np->rxopt.bits.rxohlim) {
-		int hlim = skb->nh.ipv6h->hop_limit;
+		int hlim = ipv6_hdr(skb)->hop_limit;
 		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
 	}
 	if (np->rxopt.bits.ohopopts && opt->hop) {
-		u8 *ptr = skb->nh.raw + opt->hop;
+		u8 *ptr = nh + opt->hop;
 		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr);
 	}
 	if (np->rxopt.bits.odstopts && opt->dst0) {
-		u8 *ptr = skb->nh.raw + opt->dst0;
+		u8 *ptr = nh + opt->dst0;
 		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
 	}
 	if (np->rxopt.bits.osrcrt && opt->srcrt) {
-		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(skb->nh.raw + opt->srcrt);
+		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt);
 		put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr);
 	}
 	if (np->rxopt.bits.odstopts && opt->dst1) {
-		u8 *ptr = skb->nh.raw + opt->dst1;
+		u8 *ptr = nh + opt->dst1;
 		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
 	}
 	return 0;
@@ -718,7 +723,7 @@ #endif
 				       cmsg->cmsg_type);
 			err = -EINVAL;
 			break;
-		};
+		}
 	}
 
 exit_f:
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 363e63f..7107bb7 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -42,21 +42,19 @@ #include <linux/icmpv6.h>
 static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
-	int hdr_len;
 	struct ipv6hdr *top_iph;
 	struct ipv6_esp_hdr *esph;
 	struct crypto_blkcipher *tfm;
 	struct blkcipher_desc desc;
-	struct esp_data *esp;
 	struct sk_buff *trailer;
 	int blksize;
 	int clen;
 	int alen;
 	int nfrags;
-
-	esp = x->data;
-	hdr_len = skb->h.raw - skb->data +
-		  sizeof(*esph) + esp->conf.ivlen;
+	u8 *tail;
+	struct esp_data *esp = x->data;
+	int hdr_len = (skb_transport_offset(skb) +
+		       sizeof(*esph) + esp->conf.ivlen);
 
 	/* Strip IP+ESP header. */
 	__skb_pull(skb, hdr_len);
@@ -81,19 +79,20 @@ static int esp6_output(struct xfrm_state
 	}
 
 	/* Fill padding... */
+	tail = skb_tail_pointer(trailer);
 	do {
 		int i;
 		for (i=0; i<clen-skb->len - 2; i++)
-			*(u8*)(trailer->tail + i) = i+1;
+			tail[i] = i + 1;
 	} while (0);
-	*(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
+	tail[clen-skb->len - 2] = (clen - skb->len) - 2;
 	pskb_put(skb, trailer, clen - skb->len);
 
 	top_iph = (struct ipv6hdr *)__skb_push(skb, hdr_len);
-	esph = (struct ipv6_esp_hdr *)skb->h.raw;
+	esph = (struct ipv6_esp_hdr *)skb_transport_header(skb);
 	top_iph->payload_len = htons(skb->len + alen - sizeof(*top_iph));
-	*(u8*)(trailer->tail - 1) = *skb->nh.raw;
-	*skb->nh.raw = IPPROTO_ESP;
+	*(skb_tail_pointer(trailer) - 1) = *skb_network_header(skb);
+	*skb_network_header(skb) = IPPROTO_ESP;
 
 	esph->spi = x->id.spi;
 	esph->seq_no = htonl(++x->replay.oseq);
@@ -150,8 +149,7 @@ static int esp6_input(struct xfrm_state 
 	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;
-
-	int hdr_len = skb->h.raw - skb->nh.raw;
+	int hdr_len = skb_network_header_len(skb);
 	int nfrags;
 	int ret = 0;
 
@@ -191,7 +189,7 @@ static int esp6_input(struct xfrm_state 
 	skb->ip_summed = CHECKSUM_NONE;
 
 	esph = (struct ipv6_esp_hdr*)skb->data;
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 
 	/* Get ivec. This can be wrong, check against another impls. */
 	if (esp->conf.ivlen)
@@ -231,28 +229,30 @@ static int esp6_input(struct xfrm_state 
 		ret = nexthdr[1];
 	}
 
-	skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - hdr_len;
-
+	__skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
+	skb_set_transport_header(skb, -hdr_len);
 out:
 	return ret;
 }
 
-static u32 esp6_get_max_size(struct xfrm_state *x, int mtu)
+static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
 {
 	struct esp_data *esp = x->data;
 	u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+	u32 align = max_t(u32, blksize, esp->conf.padlen);
+	u32 rem;
+
+	mtu -= x->props.header_len + esp->auth.icv_trunc_len;
+	rem = mtu & (align - 1);
+	mtu &= ~(align - 1);
 
-	if (x->props.mode == XFRM_MODE_TUNNEL) {
-		mtu = ALIGN(mtu + 2, blksize);
-	} else {
-		/* The worst case. */
+	if (x->props.mode != XFRM_MODE_TUNNEL) {
 		u32 padsize = ((blksize - 1) & 7) + 1;
-		mtu = ALIGN(mtu + 2, padsize) + blksize - padsize;
+		mtu -= blksize - padsize;
+		mtu += min_t(u32, blksize - padsize, rem);
 	}
-	if (esp->conf.padlen)
-		mtu = ALIGN(mtu, esp->conf.padlen);
 
-	return mtu + x->props.header_len + esp->auth.icv_trunc_len;
+	return mtu - 2;
 }
 
 static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
@@ -382,7 +382,7 @@ static struct xfrm_type esp6_type =
 	.proto	     	= IPPROTO_ESP,
 	.init_state	= esp6_init_state,
 	.destructor	= esp6_destroy,
-	.get_max_size	= esp6_get_max_size,
+	.get_mtu	= esp6_get_mtu,
 	.input		= esp6_input,
 	.output		= esp6_output,
 	.hdr_offset	= xfrm6_find_1stfragopt,
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index fb39604..6d8e4ac 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -50,13 +50,14 @@ #include <asm/uaccess.h>
 
 int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
 {
-	int packet_len = skb->tail - skb->nh.raw;
+	const unsigned char *nh = skb_network_header(skb);
+	int packet_len = skb->tail - skb->network_header;
 	struct ipv6_opt_hdr *hdr;
 	int len;
 
 	if (offset + 2 > packet_len)
 		goto bad;
-	hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+	hdr = (struct ipv6_opt_hdr *)(nh + offset);
 	len = ((hdr->hdrlen + 1) << 3);
 
 	if (offset + len > packet_len)
@@ -66,7 +67,7 @@ int ipv6_find_tlv(struct sk_buff *skb, i
 	len -= 2;
 
 	while (len > 0) {
-		int opttype = skb->nh.raw[offset];
+		int opttype = nh[offset];
 		int optlen;
 
 		if (opttype == type)
@@ -77,7 +78,7 @@ int ipv6_find_tlv(struct sk_buff *skb, i
 			optlen = 1;
 			break;
 		default:
-			optlen = skb->nh.raw[offset + 1] + 2;
+			optlen = nh[offset + 1] + 2;
 			if (optlen > len)
 				goto bad;
 			break;
@@ -113,7 +114,7 @@ static int ip6_tlvopt_unknown(struct sk_
 {
 	struct sk_buff *skb = *skbp;
 
-	switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {
+	switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
 	case 0: /* ignore */
 		return 1;
 
@@ -124,12 +125,12 @@ static int ip6_tlvopt_unknown(struct sk_
 		/* Actually, it is redundant check. icmp_send
 		   will recheck in any case.
 		 */
-		if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+		if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
 			break;
 	case 2: /* send ICMP PARM PROB regardless and drop packet */
 		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
 		return 0;
-	};
+	}
 
 	kfree_skb(skb);
 	return 0;
@@ -141,19 +142,20 @@ static int ip6_parse_tlv(struct tlvtype_
 {
 	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);
+	const unsigned char *nh = skb_network_header(skb);
+	int off = skb_network_header_len(skb);
+	int len = (skb_transport_header(skb)[1] + 1) << 3;
 
-	if ((skb->h.raw + len) - skb->data > skb_headlen(skb))
+	if (skb_transport_offset(skb) + len > skb_headlen(skb))
 		goto bad;
 
 	off += 2;
 	len -= 2;
 
 	while (len > 0) {
-		int optlen = skb->nh.raw[off+1]+2;
+		int optlen = nh[off + 1] + 2;
 
-		switch (skb->nh.raw[off]) {
+		switch (nh[off]) {
 		case IPV6_TLV_PAD0:
 			optlen = 1;
 			break;
@@ -165,7 +167,7 @@ static int ip6_parse_tlv(struct tlvtype_
 			if (optlen > len)
 				goto bad;
 			for (curr=procs; curr->type >= 0; curr++) {
-				if (curr->type == skb->nh.raw[off]) {
+				if (curr->type == nh[off]) {
 					/* type specific length/alignment
 					   checks will be performed in the
 					   func(). */
@@ -200,7 +202,7 @@ static int ipv6_dest_hao(struct sk_buff 
 	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 ipv6hdr *ipv6h = ipv6_hdr(skb);
 	struct in6_addr tmp_addr;
 	int ret;
 
@@ -211,7 +213,7 @@ static int ipv6_dest_hao(struct sk_buff 
 	opt->dsthao = opt->dst1;
 	opt->dst1 = 0;
 
-	hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff);
+	hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff);
 
 	if (hao->length != 16) {
 		LIMIT_NETDEBUG(
@@ -244,8 +246,9 @@ static int ipv6_dest_hao(struct sk_buff 
 
 		/* 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;
+		hao = (struct ipv6_destopt_hao *)(skb_network_header(skb2) +
+						  optoff);
+		ipv6h = ipv6_hdr(skb2);
 	}
 
 	if (skb->ip_summed == CHECKSUM_COMPLETE)
@@ -255,7 +258,7 @@ static int ipv6_dest_hao(struct sk_buff 
 	ipv6_addr_copy(&ipv6h->saddr, &hao->addr);
 	ipv6_addr_copy(&hao->addr, &tmp_addr);
 
-	if (skb->tstamp.off_sec == 0)
+	if (skb->tstamp.tv64 == 0)
 		__net_timestamp(skb);
 
 	return 1;
@@ -285,16 +288,16 @@ #ifdef CONFIG_IPV6_MIP6
 #endif
 	struct dst_entry *dst;
 
-	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))) {
+	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
+	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
+				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		kfree_skb(skb);
 		return -1;
 	}
 
-	opt->lastopt = skb->h.raw - skb->nh.raw;
-	opt->dst1 = skb->h.raw - skb->nh.raw;
+	opt->lastopt = opt->dst1 = skb_network_header_len(skb);
 #ifdef CONFIG_IPV6_MIP6
 	dstbuf = opt->dst1;
 #endif
@@ -303,7 +306,7 @@ #endif
 	if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
 		dst_release(dst);
 		skb = *skbp;
-		skb->h.raw += ((skb->h.raw[1]+1)<<3);
+		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
 		opt = IP6CB(skb);
 #ifdef CONFIG_IPV6_MIP6
 		opt->nhoff = dstbuf;
@@ -384,18 +387,20 @@ static int ipv6_rthdr_rcv(struct sk_buff
 
 	in6_dev_put(idev);
 
-	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))) {
+	if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
+	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
+				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		kfree_skb(skb);
 		return -1;
 	}
 
-	hdr = (struct ipv6_rt_hdr *) skb->h.raw;
+	hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
 
 	switch (hdr->type) {
 #ifdef CONFIG_IPV6_MIP6
+	case IPV6_SRCRT_TYPE_2:
 		break;
 #endif
 	case IPV6_SRCRT_TYPE_0:
@@ -406,11 +411,12 @@ #endif
 	default:
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+				  (&hdr->type) - skb_network_header(skb));
 		return -1;
 	}
 
-	if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
+	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
 	    skb->pkt_type != PACKET_HOST) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INADDRERRORS);
@@ -438,12 +444,11 @@ #endif
 			break;
 		}
 
-		opt->lastopt = skb->h.raw - skb->nh.raw;
-		opt->srcrt = skb->h.raw - skb->nh.raw;
-		skb->h.raw += (hdr->hdrlen + 1) << 3;
+		opt->lastopt = opt->srcrt = skb_network_header_len(skb);
+		skb->transport_header += (hdr->hdrlen + 1) << 3;
 		opt->dst0 = opt->dst1;
 		opt->dst1 = 0;
-		opt->nhoff = (&hdr->nexthdr) - skb->nh.raw;
+		opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
 		return 1;
 	}
 
@@ -452,7 +457,9 @@ #endif
 		if (hdr->hdrlen & 0x01) {
 			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INHDRERRORS);
-			icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
+			icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+					  ((&hdr->hdrlen) -
+					   skb_network_header(skb)));
 			return -1;
 		}
 		break;
@@ -479,7 +486,9 @@ #endif
 	if (hdr->segments_left > n) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+				  ((&hdr->segments_left) -
+				   skb_network_header(skb)));
 		return -1;
 	}
 
@@ -498,7 +507,7 @@ #endif
 		kfree_skb(skb);
 		*skbp = skb = skb2;
 		opt = IP6CB(skb2);
-		hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
+		hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb2);
 	}
 
 	if (skb->ip_summed == CHECKSUM_COMPLETE)
@@ -514,7 +523,7 @@ #endif
 #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,
+				     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
 				     IPPROTO_ROUTING) < 0) {
 			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INADDRERRORS);
@@ -541,19 +550,19 @@ #endif
 	}
 
 	ipv6_addr_copy(&daddr, addr);
-	ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);
-	ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);
+	ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
+	ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
 
 	dst_release(xchg(&skb->dst, NULL));
 	ip6_route_input(skb);
 	if (skb->dst->error) {
-		skb_push(skb, skb->data - skb->nh.raw);
+		skb_push(skb, skb->data - skb_network_header(skb));
 		dst_input(skb);
 		return -1;
 	}
 
 	if (skb->dst->dev->flags&IFF_LOOPBACK) {
-		if (skb->nh.ipv6h->hop_limit <= 1) {
+		if (ipv6_hdr(skb)->hop_limit <= 1) {
 			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 					 IPSTATS_MIB_INHDRERRORS);
 			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
@@ -561,11 +570,11 @@ #endif
 			kfree_skb(skb);
 			return -1;
 		}
-		skb->nh.ipv6h->hop_limit--;
+		ipv6_hdr(skb)->hop_limit--;
 		goto looped_back;
 	}
 
-	skb_push(skb, skb->data - skb->nh.raw);
+	skb_push(skb, skb->data - skb_network_header(skb));
 	dst_input(skb);
 	return -1;
 }
@@ -656,13 +665,14 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
 {
 	struct sk_buff *skb = *skbp;
+	const unsigned char *nh = skb_network_header(skb);
 
-	if (skb->nh.raw[optoff+1] == 2) {
+	if (nh[optoff + 1] == 2) {
 		IP6CB(skb)->ra = optoff;
 		return 1;
 	}
 	LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",
-		       skb->nh.raw[optoff+1]);
+		       nh[optoff + 1]);
 	kfree_skb(skb);
 	return 0;
 }
@@ -672,23 +682,24 @@ static int ipv6_hop_ra(struct sk_buff **
 static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
 {
 	struct sk_buff *skb = *skbp;
+	const unsigned char *nh = skb_network_header(skb);
 	u32 pkt_len;
 
-	if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
+	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
 		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
-			       skb->nh.raw[optoff+1]);
+			       nh[optoff+1]);
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
 		goto drop;
 	}
 
-	pkt_len = ntohl(*(__be32*)(skb->nh.raw+optoff+2));
+	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
 	if (pkt_len <= IPV6_MAXPLEN) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
 		return 0;
 	}
-	if (skb->nh.ipv6h->payload_len) {
+	if (ipv6_hdr(skb)->payload_len) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
 		return 0;
@@ -727,13 +738,14 @@ int ipv6_parse_hopopts(struct sk_buff **
 	struct inet6_skb_parm *opt = IP6CB(skb);
 
 	/*
-	 * skb->nh.raw is equal to skb->data, and
-	 * skb->h.raw - skb->nh.raw is always equal to
+	 * skb_network_header(skb) is equal to skb->data, and
+	 * skb_network_header_len(skb) is always equal to
 	 * sizeof(struct ipv6hdr) by definition of
 	 * hop-by-hop options.
 	 */
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||
-	    !pskb_may_pull(skb, sizeof(struct ipv6hdr) + ((skb->h.raw[1] + 1) << 3))) {
+	    !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +
+				 ((skb_transport_header(skb)[1] + 1) << 3)))) {
 		kfree_skb(skb);
 		return -1;
 	}
@@ -741,7 +753,7 @@ int ipv6_parse_hopopts(struct sk_buff **
 	opt->hop = sizeof(struct ipv6hdr);
 	if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) {
 		skb = *skbp;
-		skb->h.raw += (skb->h.raw[1]+1)<<3;
+		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
 		opt = IP6CB(skb);
 		opt->nhoff = sizeof(struct ipv6hdr);
 		return 1;
@@ -810,6 +822,8 @@ void ipv6_push_nfrag_opts(struct sk_buff
 		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
 }
 
+EXPORT_SYMBOL(ipv6_push_nfrag_opts);
+
 void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
 {
 	if (opt->dst1opt)
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index ea3035b..fc3882c 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -17,6 +17,7 @@ #include <linux/netdevice.h>
 
 #include <net/fib_rules.h>
 #include <net/ipv6.h>
+#include <net/addrconf.h>
 #include <net/ip6_route.h>
 #include <net/netlink.h>
 
@@ -95,8 +96,27 @@ static int fib6_rule_action(struct fib_r
 	if (table)
 		rt = lookup(table, flp, flags);
 
-	if (rt != &ip6_null_entry)
+	if (rt != &ip6_null_entry) {
+		struct fib6_rule *r = (struct fib6_rule *)rule;
+
+		/*
+		 * If we need to find a source address for this traffic,
+		 * we check the result if it meets requirement of the rule.
+		 */
+		if ((rule->flags & FIB_RULE_FIND_SADDR) &&
+		    r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
+			struct in6_addr saddr;
+			if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst,
+					   &saddr))
+				goto again;
+			if (!ipv6_prefix_equal(&saddr, &r->src.addr,
+					       r->src.plen))
+				goto again;
+			ipv6_addr_copy(&flp->fl6_src, &saddr);
+		}
 		goto out;
+	}
+again:
 	dst_release(&rt->u.dst);
 	rt = NULL;
 	goto out;
@@ -117,9 +137,17 @@ static int fib6_rule_match(struct fib_ru
 	    !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
 		return 0;
 
+	/*
+	 * If FIB_RULE_FIND_SADDR is set and we do not have a
+	 * source address for the traffic, we defer check for
+	 * source address.
+	 */
 	if (r->src.plen) {
-		if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
-		    !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
+		if (flags & RT6_LOOKUP_F_HAS_SADDR) {
+			if (!ipv6_prefix_equal(&fl->fl6_src, &r->src.addr,
+					       r->src.plen))
+				return 0;
+		} else if (!(r->common.flags & FIB_RULE_FIND_SADDR))
 			return 0;
 	}
 
@@ -216,11 +244,6 @@ 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;
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index edfe98b..e9bcce9 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -68,6 +68,7 @@ #include <asm/uaccess.h>
 #include <asm/system.h>
 
 DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly;
+EXPORT_SYMBOL(icmpv6_statistics);
 
 /*
  *	The ICMP socket(s). This is the most convenient way to flow control
@@ -128,9 +129,9 @@ void icmpv6_param_prob(struct sk_buff *s
 
 static int is_ineligible(struct sk_buff *skb)
 {
-	int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
+	int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
 	int len = skb->len - ptr;
-	__u8 nexthdr = skb->nh.ipv6h->nexthdr;
+	__u8 nexthdr = ipv6_hdr(skb)->nexthdr;
 
 	if (len < 0)
 		return 1;
@@ -205,7 +206,7 @@ static __inline__ int opt_unrec(struct s
 {
 	u8 _optval, *op;
 
-	offset += skb->nh.raw - skb->data;
+	offset += skb_network_offset(skb);
 	op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
 	if (op == NULL)
 		return 1;
@@ -221,7 +222,7 @@ static int icmpv6_push_pending_frames(st
 	if ((skb = skb_peek(&sk->sk_write_queue)) == NULL)
 		goto out;
 
-	icmp6h = (struct icmp6hdr*) skb->h.raw;
+	icmp6h = icmp6_hdr(skb);
 	memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
 	icmp6h->icmp6_cksum = 0;
 
@@ -274,7 +275,7 @@ static int icmpv6_getfrag(void *from, ch
 #ifdef CONFIG_IPV6_MIP6
 static void mip6_addr_swap(struct sk_buff *skb)
 {
-	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct inet6_skb_parm *opt = IP6CB(skb);
 	struct ipv6_destopt_hao *hao;
 	struct in6_addr tmp;
@@ -283,7 +284,8 @@ static void mip6_addr_swap(struct sk_buf
 	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);
+			hao = (struct ipv6_destopt_hao *)
+					(skb_network_header(skb) + off);
 			ipv6_addr_copy(&tmp, &iph->saddr);
 			ipv6_addr_copy(&iph->saddr, &hao->addr);
 			ipv6_addr_copy(&hao->addr, &tmp);
@@ -301,7 +303,7 @@ void icmpv6_send(struct sk_buff *skb, in
 		 struct net_device *dev)
 {
 	struct inet6_dev *idev = NULL;
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct sock *sk;
 	struct ipv6_pinfo *np;
 	struct in6_addr *saddr = NULL;
@@ -315,7 +317,8 @@ void icmpv6_send(struct sk_buff *skb, in
 	int hlimit, tclass;
 	int err = 0;
 
-	if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
+	if ((u8 *)hdr < skb->head ||
+	    (skb->network_header + sizeof(*hdr)) > skb->tail)
 		return;
 
 	/*
@@ -430,7 +433,7 @@ void icmpv6_send(struct sk_buff *skb, in
 		tclass = 0;
 
 	msg.skb = skb;
-	msg.offset = skb->nh.raw - skb->data;
+	msg.offset = skb_network_offset(skb);
 	msg.type = type;
 
 	len = skb->len - msg.offset;
@@ -466,13 +469,15 @@ out:
 	icmpv6_xmit_unlock();
 }
 
+EXPORT_SYMBOL(icmpv6_send);
+
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
 	struct sock *sk;
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *np;
 	struct in6_addr *saddr = NULL;
-	struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
+	struct icmp6hdr *icmph = icmp6_hdr(skb);
 	struct icmp6hdr tmp_hdr;
 	struct flowi fl;
 	struct icmpv6_msg msg;
@@ -481,7 +486,7 @@ static void icmpv6_echo_reply(struct sk_
 	int hlimit;
 	int tclass;
 
-	saddr = &skb->nh.ipv6h->daddr;
+	saddr = &ipv6_hdr(skb)->daddr;
 
 	if (!ipv6_unicast_destination(skb))
 		saddr = NULL;
@@ -491,7 +496,7 @@ static void icmpv6_echo_reply(struct sk_
 
 	memset(&fl, 0, sizeof(fl));
 	fl.proto = IPPROTO_ICMPV6;
-	ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
+	ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
 	if (saddr)
 		ipv6_addr_copy(&fl.fl6_src, saddr);
 	fl.oif = skb->dev->ifindex;
@@ -579,8 +584,8 @@ static void icmpv6_notify(struct sk_buff
 	if (!pskb_may_pull(skb, inner_offset+8))
 		return;
 
-	saddr = &skb->nh.ipv6h->saddr;
-	daddr = &skb->nh.ipv6h->daddr;
+	saddr = &ipv6_hdr(skb)->saddr;
+	daddr = &ipv6_hdr(skb)->daddr;
 
 	/* BUGGG_FUTURE: we should try to parse exthdrs in this packet.
 	   Without this we will not able f.e. to make source routed
@@ -624,8 +629,8 @@ static int icmpv6_rcv(struct sk_buff **p
 
 	ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INMSGS);
 
-	saddr = &skb->nh.ipv6h->saddr;
-	daddr = &skb->nh.ipv6h->daddr;
+	saddr = &ipv6_hdr(skb)->saddr;
+	daddr = &ipv6_hdr(skb)->daddr;
 
 	/* Perform checksum. */
 	switch (skb->ip_summed) {
@@ -647,7 +652,7 @@ static int icmpv6_rcv(struct sk_buff **p
 	if (!pskb_pull(skb, sizeof(struct icmp6hdr)))
 		goto discard_it;
 
-	hdr = (struct icmp6hdr *) skb->h.raw;
+	hdr = icmp6_hdr(skb);
 
 	type = hdr->icmp6_type;
 
@@ -673,7 +678,7 @@ static int icmpv6_rcv(struct sk_buff **p
 		 */
 		if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 			goto discard_it;
-		hdr = (struct icmp6hdr *) skb->h.raw;
+		hdr = icmp6_hdr(skb);
 		orig_hdr = (struct ipv6hdr *) (hdr + 1);
 		rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
 				   ntohl(hdr->icmp6_mtu));
@@ -727,7 +732,8 @@ static int icmpv6_rcv(struct sk_buff **p
 		 */
 
 		icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
-	};
+	}
+
 	kfree_skb(skb);
 	return 0;
 
@@ -860,11 +866,13 @@ int icmpv6_err_convert(int type, int cod
 	case ICMPV6_TIME_EXCEED:
 		*err = EHOSTUNREACH;
 		break;
-	};
+	}
 
 	return fatal;
 }
 
+EXPORT_SYMBOL(icmpv6_err_convert);
+
 #ifdef CONFIG_SYSCTL
 ctl_table ipv6_icmp_table[] = {
 	{
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 268f476..ca08ee8 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -359,7 +359,7 @@ end:
 	return res;
 }
 
-int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
+static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	unsigned int h, s_h;
 	unsigned int e = 0, s_e;
@@ -1486,6 +1486,8 @@ void __init fib6_init(void)
 					   NULL, NULL);
 
 	fib6_tables_init();
+
+	__rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 }
 
 void fib6_gc_cleanup(void)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 61e7a6c..be0ee8a 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -96,12 +96,12 @@ int ipv6_rcv(struct sk_buff *skb, struct
 	if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
 		goto err;
 
-	hdr = skb->nh.ipv6h;
+	hdr = ipv6_hdr(skb);
 
 	if (hdr->version != 6)
 		goto err;
 
-	skb->h.raw = (u8 *)(hdr + 1);
+	skb->transport_header = skb->network_header + sizeof(*hdr);
 	IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
 
 	pkt_len = ntohs(hdr->payload_len);
@@ -116,7 +116,7 @@ int ipv6_rcv(struct sk_buff *skb, struct
 			IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
 			goto drop;
 		}
-		hdr = skb->nh.ipv6h;
+		hdr = ipv6_hdr(skb);
 	}
 
 	if (hdr->nexthdr == NEXTHDR_HOP) {
@@ -160,10 +160,10 @@ static inline int ip6_input_finish(struc
 	rcu_read_lock();
 resubmit:
 	idev = ip6_dst_idev(skb->dst);
-	if (!pskb_pull(skb, skb->h.raw - skb->data))
+	if (!pskb_pull(skb, skb_transport_offset(skb)))
 		goto discard;
 	nhoff = IP6CB(skb)->nhoff;
-	nexthdr = skb->nh.raw[nhoff];
+	nexthdr = skb_network_header(skb)[nhoff];
 
 	raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
 	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
@@ -181,9 +181,9 @@ resubmit:
 			   indefinitely. */
 			nf_reset(skb);
 
-			skb_postpull_rcsum(skb, skb->nh.raw,
-					   skb->h.raw - skb->nh.raw);
-			hdr = skb->nh.ipv6h;
+			skb_postpull_rcsum(skb, skb_network_header(skb),
+					   skb_network_header_len(skb));
+			hdr = ipv6_hdr(skb);
 			if (ipv6_addr_is_multicast(&hdr->daddr) &&
 			    !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr,
 			    &hdr->saddr) &&
@@ -234,7 +234,7 @@ int ip6_mc_input(struct sk_buff *skb)
 
 	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);
 
-	hdr = skb->nh.ipv6h;
+	hdr = ipv6_hdr(skb);
 	deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||
 	    ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3055169..f508171 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -88,8 +88,8 @@ static inline int ip6_output_finish(stru
 /* dev_loopback_xmit for use with netfilter. */
 static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
 {
-	newskb->mac.raw = newskb->data;
-	__skb_pull(newskb, newskb->nh.raw - newskb->data);
+	skb_reset_mac_header(newskb);
+	__skb_pull(newskb, skb_network_offset(newskb));
 	newskb->pkt_type = PACKET_LOOPBACK;
 	newskb->ip_summed = CHECKSUM_UNNECESSARY;
 	BUG_TRAP(newskb->dst);
@@ -107,13 +107,13 @@ static int ip6_output2(struct sk_buff *s
 	skb->protocol = htons(ETH_P_IPV6);
 	skb->dev = dev;
 
-	if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
+	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
 		struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
 		struct inet6_dev *idev = ip6_dst_idev(skb->dst);
 
 		if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
-		    ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
-				&skb->nh.ipv6h->saddr)) {
+		    ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
+					&ipv6_hdr(skb)->saddr)) {
 			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
 
 			/* Do not check for IFF_ALLMULTI; multicast routing
@@ -124,7 +124,7 @@ static int ip6_output2(struct sk_buff *s
 					newskb->dev,
 					ip6_dev_loopback_xmit);
 
-			if (skb->nh.ipv6h->hop_limit == 0) {
+			if (ipv6_hdr(skb)->hop_limit == 0) {
 				IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
 				kfree_skb(skb);
 				return 0;
@@ -137,9 +137,17 @@ static int ip6_output2(struct sk_buff *s
 	return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
 }
 
+static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
+{
+	struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
+
+	return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
+	       skb->dst->dev->mtu : dst_mtu(skb->dst);
+}
+
 int ip6_output(struct sk_buff *skb)
 {
-	if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
+	if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
 				dst_allfrag(skb->dst))
 		return ip6_fragment(skb, ip6_output2);
 	else
@@ -191,7 +199,9 @@ int ip6_xmit(struct sock *sk, struct sk_
 			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
 	}
 
-	hdr = skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6hdr));
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	hdr = ipv6_hdr(skb);
 
 	/*
 	 *	Fill in the IPv6 header
@@ -239,6 +249,8 @@ int ip6_xmit(struct sock *sk, struct sk_
 	return -EMSGSIZE;
 }
 
+EXPORT_SYMBOL(ip6_xmit);
+
 /*
  *	To avoid extra problems ND packets are send through this
  *	routine. It's code duplication but I really want to avoid
@@ -259,8 +271,9 @@ int ip6_nd_hdr(struct sock *sk, struct s
 
 	totlen = len + sizeof(struct ipv6hdr);
 
-	hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
-	skb->nh.ipv6h = hdr;
+	skb_reset_network_header(skb);
+	skb_put(skb, sizeof(struct ipv6hdr));
+	hdr = ipv6_hdr(skb);
 
 	*(__be32*)hdr = htonl(0x60000000);
 
@@ -305,7 +318,7 @@ static int ip6_call_ra_chain(struct sk_b
 
 static int ip6_forward_proxy_check(struct sk_buff *skb)
 {
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	u8 nexthdr = hdr->nexthdr;
 	int offset;
 
@@ -319,10 +332,11 @@ static int ip6_forward_proxy_check(struc
 	if (nexthdr == IPPROTO_ICMPV6) {
 		struct icmp6hdr *icmp6;
 
-		if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data))
+		if (!pskb_may_pull(skb, (skb_network_header(skb) +
+					 offset + 1 - skb->data)))
 			return 0;
 
-		icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset);
+		icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
 
 		switch (icmp6->icmp6_type) {
 		case NDISC_ROUTER_SOLICITATION:
@@ -361,7 +375,7 @@ static inline int ip6_forward_finish(str
 int ip6_forward(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct inet6_skb_parm *opt = IP6CB(skb);
 
 	if (ipv6_devconf.forwarding == 0)
@@ -372,7 +386,7 @@ int ip6_forward(struct sk_buff *skb)
 		goto drop;
 	}
 
-	skb->ip_summed = CHECKSUM_NONE;
+	skb_forward_csum(skb);
 
 	/*
 	 *	We DO NOT make any processing on
@@ -388,7 +402,7 @@ int ip6_forward(struct sk_buff *skb)
 	 *	that different fragments will go along one path. --ANK
 	 */
 	if (opt->ra) {
-		u8 *ptr = skb->nh.raw + opt->ra;
+		u8 *ptr = skb_network_header(skb) + opt->ra;
 		if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))
 			return 0;
 	}
@@ -470,7 +484,7 @@ int ip6_forward(struct sk_buff *skb)
 		goto drop;
 	}
 
-	hdr = skb->nh.ipv6h;
+	hdr = ipv6_hdr(skb);
 
 	/* Mangling hops number delayed to point after skb COW */
 
@@ -499,33 +513,18 @@ static void ip6_copy_metadata(struct sk_
 #ifdef CONFIG_NET_SCHED
 	to->tc_index = from->tc_index;
 #endif
-#ifdef CONFIG_NETFILTER
-	/* Connection association is same as pre-frag packet */
-	nf_conntrack_put(to->nfct);
-	to->nfct = from->nfct;
-	nf_conntrack_get(to->nfct);
-	to->nfctinfo = from->nfctinfo;
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-	nf_conntrack_put_reasm(to->nfct_reasm);
-	to->nfct_reasm = from->nfct_reasm;
-	nf_conntrack_get_reasm(to->nfct_reasm);
-#endif
-#ifdef CONFIG_BRIDGE_NETFILTER
-	nf_bridge_put(to->nf_bridge);
-	to->nf_bridge = from->nf_bridge;
-	nf_bridge_get(to->nf_bridge);
-#endif
-#endif
+	nf_copy(to, from);
 	skb_copy_secmark(to, from);
 }
 
 int ip6_find_1stfragopt(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;
+	struct ipv6_opt_hdr *exthdr =
+				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
+	unsigned int packet_len = skb->tail - skb->network_header;
 	int found_rhdr = 0;
-	*nexthdr = &skb->nh.ipv6h->nexthdr;
+	*nexthdr = &ipv6_hdr(skb)->nexthdr;
 
 	while (offset + 1 <= packet_len) {
 
@@ -550,7 +549,8 @@ #endif
 
 		offset += ipv6_optlen(exthdr);
 		*nexthdr = &exthdr->nexthdr;
-		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
+						 offset);
 	}
 
 	return offset;
@@ -574,7 +574,20 @@ static int ip6_fragment(struct sk_buff *
 	hlen = ip6_find_1stfragopt(skb, &prevhdr);
 	nexthdr = *prevhdr;
 
-	mtu = dst_mtu(&rt->u.dst);
+	mtu = ip6_skb_dst_mtu(skb);
+
+	/* We must not fragment if the socket is set to force MTU discovery
+	 * or if the skb it not generated by a local socket.  (This last
+	 * check should be redundant, but it's free.)
+	 */
+	if (!np || np->pmtudisc >= IPV6_PMTUDISC_DO) {
+		skb->dev = skb->dst->dev;
+		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
+		kfree_skb(skb);
+		return -EMSGSIZE;
+	}
+
 	if (np && np->frag_size < mtu) {
 		if (np->frag_size)
 			mtu = np->frag_size;
@@ -616,7 +629,7 @@ static int ip6_fragment(struct sk_buff *
 		/* BUILD HEADER */
 
 		*prevhdr = NEXTHDR_FRAGMENT;
-		tmp_hdr = kmemdup(skb->nh.raw, hlen, GFP_ATOMIC);
+		tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
 		if (!tmp_hdr) {
 			IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
 			return -ENOMEM;
@@ -624,8 +637,9 @@ static int ip6_fragment(struct sk_buff *
 
 		__skb_pull(skb, hlen);
 		fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
-		skb->nh.raw = __skb_push(skb, hlen);
-		memcpy(skb->nh.raw, tmp_hdr, hlen);
+		__skb_push(skb, hlen);
+		skb_reset_network_header(skb);
+		memcpy(skb_network_header(skb), tmp_hdr, hlen);
 
 		ipv6_select_ident(skb, fh);
 		fh->nexthdr = nexthdr;
@@ -636,7 +650,8 @@ static int ip6_fragment(struct sk_buff *
 		first_len = skb_pagelen(skb);
 		skb->data_len = first_len - skb_headlen(skb);
 		skb->len = first_len;
-		skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
+		ipv6_hdr(skb)->payload_len = htons(first_len -
+						   sizeof(struct ipv6hdr));
 
 		dst_hold(&rt->u.dst);
 
@@ -645,10 +660,12 @@ static int ip6_fragment(struct sk_buff *
 			 * before previous one went down. */
 			if (frag) {
 				frag->ip_summed = CHECKSUM_NONE;
-				frag->h.raw = frag->data;
+				skb_reset_transport_header(frag);
 				fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
-				frag->nh.raw = __skb_push(frag, hlen);
-				memcpy(frag->nh.raw, tmp_hdr, hlen);
+				__skb_push(frag, hlen);
+				skb_reset_network_header(frag);
+				memcpy(skb_network_header(frag), tmp_hdr,
+				       hlen);
 				offset += skb->len - hlen - sizeof(struct frag_hdr);
 				fh->nexthdr = nexthdr;
 				fh->reserved = 0;
@@ -656,7 +673,9 @@ static int ip6_fragment(struct sk_buff *
 				if (frag->next != NULL)
 					fh->frag_off |= htons(IP6_MF);
 				fh->identification = frag_id;
-				frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
+				ipv6_hdr(frag)->payload_len =
+						htons(frag->len -
+						      sizeof(struct ipv6hdr));
 				ip6_copy_metadata(frag, skb);
 			}
 
@@ -733,9 +752,10 @@ slow_path:
 		ip6_copy_metadata(frag, skb);
 		skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev));
 		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
-		frag->nh.raw = frag->data;
-		fh = (struct frag_hdr*)(frag->data + hlen);
-		frag->h.raw = frag->data + hlen + sizeof(struct frag_hdr);
+		skb_reset_network_header(frag);
+		fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
+		frag->transport_header = (frag->network_header + hlen +
+					  sizeof(struct frag_hdr));
 
 		/*
 		 *	Charge the memory for the fragment to any owner
@@ -747,7 +767,7 @@ slow_path:
 		/*
 		 *	Copy the packet header into the new buffer.
 		 */
-		memcpy(frag->nh.raw, skb->data, hlen);
+		skb_copy_from_linear_data(skb, skb_network_header(frag), hlen);
 
 		/*
 		 *	Build fragment header.
@@ -763,14 +783,15 @@ slow_path:
 		/*
 		 *	Copy a block of the IP datagram.
 		 */
-		if (skb_copy_bits(skb, ptr, frag->h.raw, len))
+		if (skb_copy_bits(skb, ptr, skb_transport_header(skb), len))
 			BUG();
 		left -= len;
 
 		fh->frag_off = htons(offset);
 		if (left > 0)
 			fh->frag_off |= htons(IP6_MF);
-		frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
+		ipv6_hdr(frag)->payload_len = htons(frag->len -
+						    sizeof(struct ipv6hdr));
 
 		ptr += len;
 		offset += len;
@@ -861,6 +882,41 @@ static int ip6_dst_lookup_tail(struct so
 			goto out_err_release;
 	}
 
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+		/*
+		 * Here if the dst entry we've looked up
+		 * has a neighbour entry that is in the INCOMPLETE
+		 * state and the src address from the flow is
+		 * marked as OPTIMISTIC, we release the found
+		 * dst entry and replace it instead with the
+		 * dst entry of the nexthop router
+		 */
+		if (!((*dst)->neighbour->nud_state & NUD_VALID)) {
+			struct inet6_ifaddr *ifp;
+			struct flowi fl_gw;
+			int redirect;
+
+			ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1);
+
+			redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
+			if (ifp)
+				in6_ifa_put(ifp);
+
+			if (redirect) {
+				/*
+				 * We need to get the dst entry for the
+				 * default router instead
+				 */
+				dst_release(*dst);
+				memcpy(&fl_gw, fl, sizeof(struct flowi));
+				memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
+				*dst = ip6_route_output(sk, &fl_gw);
+				if ((err = (*dst)->error))
+					goto out_err_release;
+			}
+		}
+#endif
+
 	return 0;
 
 out_err_release:
@@ -939,10 +995,10 @@ static inline int ip6_ufo_append_data(st
 		skb_put(skb,fragheaderlen + transhdrlen);
 
 		/* initialize network header pointer */
-		skb->nh.raw = skb->data;
+		skb_reset_network_header(skb);
 
 		/* initialize protocol header pointer */
-		skb->h.raw = skb->data + fragheaderlen;
+		skb->transport_header = skb->network_header + fragheaderlen;
 
 		skb->ip_summed = CHECKSUM_PARTIAL;
 		skb->csum = 0;
@@ -1015,7 +1071,8 @@ int ip6_append_data(struct sock *sk, int
 		inet->cork.fl = *fl;
 		np->cork.hop_limit = hlimit;
 		np->cork.tclass = tclass;
-		mtu = dst_mtu(rt->u.dst.path);
+		mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
+		      rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path);
 		if (np->frag_size < mtu) {
 			if (np->frag_size)
 				mtu = np->frag_size;
@@ -1162,10 +1219,10 @@ alloc_new_skb:
 			 *	Find where to start putting bytes
 			 */
 			data = skb_put(skb, fraglen);
-			skb->nh.raw = data + exthdrlen;
+			skb_set_network_header(skb, exthdrlen);
 			data += fragheaderlen;
-			skb->h.raw = data + exthdrlen;
-
+			skb->transport_header = (skb->network_header +
+						 fragheaderlen);
 			if (fraggap) {
 				skb->csum = skb_copy_and_csum_bits(
 					skb_prev, maxfraglen,
@@ -1288,10 +1345,10 @@ int ip6_push_pending_frames(struct sock 
 	tail_skb = &(skb_shinfo(skb)->frag_list);
 
 	/* move skb->data to ip header from ext header */
-	if (skb->data < skb->nh.raw)
-		__skb_pull(skb, skb->nh.raw - skb->data);
+	if (skb->data < skb_network_header(skb))
+		__skb_pull(skb, skb_network_offset(skb));
 	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
-		__skb_pull(tmp_skb, skb->h.raw - skb->nh.raw);
+		__skb_pull(tmp_skb, skb_network_header_len(skb));
 		*tail_skb = tmp_skb;
 		tail_skb = &(tmp_skb->next);
 		skb->len += tmp_skb->len;
@@ -1303,13 +1360,15 @@ int ip6_push_pending_frames(struct sock 
 	}
 
 	ipv6_addr_copy(final_dst, &fl->fl6_dst);
-	__skb_pull(skb, skb->h.raw - skb->nh.raw);
+	__skb_pull(skb, skb_network_header_len(skb));
 	if (opt && opt->opt_flen)
 		ipv6_push_frag_opts(skb, opt, &proto);
 	if (opt && opt->opt_nflen)
 		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
 
-	skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	hdr = ipv6_hdr(skb);
 
 	*(__be32*)hdr = fl->fl6_flowlabel |
 		     htonl(0x60000000 | ((int)np->cork.tclass << 20));
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 08d9442..a0902fb 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1,14 +1,15 @@
 /*
- *	IPv6 over IPv6 tunnel device
+ *	IPv6 tunneling device
  *	Linux INET6 implementation
  *
  *	Authors:
  *	Ville Nuorvala		<vnuorval@tcs.hut.fi>
+ *	Yasuyuki Kozakai	<kozakai@linux-ipv6.org>
  *
  *	$Id$
  *
  *      Based on:
- *      linux/net/ipv6/sit.c
+ *      linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
  *
  *      RFC 2473
  *
@@ -24,6 +25,7 @@ #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/sockios.h>
+#include <linux/icmp.h>
 #include <linux/if.h>
 #include <linux/in.h>
 #include <linux/ip.h>
@@ -41,6 +43,7 @@ #include <linux/netfilter_ipv6.h>
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 
+#include <net/icmp.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
@@ -51,7 +54,7 @@ #include <net/dsfield.h>
 #include <net/inet_ecn.h>
 
 MODULE_AUTHOR("Ville Nuorvala");
-MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
+MODULE_DESCRIPTION("IPv6 tunneling device");
 MODULE_LICENSE("GPL");
 
 #define IPV6_TLV_TEL_DST_SIZE 8
@@ -63,6 +66,7 @@ #define IP6_TNL_TRACE(x...) do {;} while
 #endif
 
 #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+#define IPV6_TCLASS_SHIFT 20
 
 #define HASH_SIZE  32
 
@@ -70,12 +74,12 @@ #define HASH(addr) ((__force u32)((addr)
 		     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
 		    (HASH_SIZE - 1))
 
-static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
-static int ip6ip6_tnl_dev_init(struct net_device *dev);
-static void ip6ip6_tnl_dev_setup(struct net_device *dev);
+static int ip6_fb_tnl_dev_init(struct net_device *dev);
+static int ip6_tnl_dev_init(struct net_device *dev);
+static void ip6_tnl_dev_setup(struct net_device *dev);
 
 /* the IPv6 tunnel fallback device */
-static struct net_device *ip6ip6_fb_tnl_dev;
+static struct net_device *ip6_fb_tnl_dev;
 
 
 /* lists for storing tunnels in use */
@@ -84,7 +88,7 @@ static struct ip6_tnl *tnls_wc[1];
 static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
 
 /* lock for the tunnel lists */
-static DEFINE_RWLOCK(ip6ip6_lock);
+static DEFINE_RWLOCK(ip6_tnl_lock);
 
 static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
 {
@@ -115,7 +119,7 @@ static inline void ip6_tnl_dst_store(str
 }
 
 /**
- * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
  *   @remote: the address of the tunnel exit-point
  *   @local: the address of the tunnel entry-point
  *
@@ -126,7 +130,7 @@ static inline void ip6_tnl_dst_store(str
  **/
 
 static struct ip6_tnl *
-ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
+ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
 {
 	unsigned h0 = HASH(remote);
 	unsigned h1 = HASH(local);
@@ -145,18 +149,18 @@ ip6ip6_tnl_lookup(struct in6_addr *remot
 }
 
 /**
- * ip6ip6_bucket - get head of list matching given tunnel parameters
+ * ip6_tnl_bucket - get head of list matching given tunnel parameters
  *   @p: parameters containing tunnel end-points
  *
  * Description:
- *   ip6ip6_bucket() returns the head of the list matching the
+ *   ip6_tnl_bucket() returns the head of the list matching the
  *   &struct in6_addr entries laddr and raddr in @p.
  *
  * Return: head of IPv6 tunnel list
  **/
 
 static struct ip6_tnl **
-ip6ip6_bucket(struct ip6_tnl_parm *p)
+ip6_tnl_bucket(struct ip6_tnl_parm *p)
 {
 	struct in6_addr *remote = &p->raddr;
 	struct in6_addr *local = &p->laddr;
@@ -171,36 +175,36 @@ ip6ip6_bucket(struct ip6_tnl_parm *p)
 }
 
 /**
- * ip6ip6_tnl_link - add tunnel to hash table
+ * ip6_tnl_link - add tunnel to hash table
  *   @t: tunnel to be added
  **/
 
 static void
-ip6ip6_tnl_link(struct ip6_tnl *t)
+ip6_tnl_link(struct ip6_tnl *t)
 {
-	struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
+	struct ip6_tnl **tp = ip6_tnl_bucket(&t->parms);
 
 	t->next = *tp;
-	write_lock_bh(&ip6ip6_lock);
+	write_lock_bh(&ip6_tnl_lock);
 	*tp = t;
-	write_unlock_bh(&ip6ip6_lock);
+	write_unlock_bh(&ip6_tnl_lock);
 }
 
 /**
- * ip6ip6_tnl_unlink - remove tunnel from hash table
+ * ip6_tnl_unlink - remove tunnel from hash table
  *   @t: tunnel to be removed
  **/
 
 static void
-ip6ip6_tnl_unlink(struct ip6_tnl *t)
+ip6_tnl_unlink(struct ip6_tnl *t)
 {
 	struct ip6_tnl **tp;
 
-	for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
+	for (tp = ip6_tnl_bucket(&t->parms); *tp; tp = &(*tp)->next) {
 		if (t == *tp) {
-			write_lock_bh(&ip6ip6_lock);
+			write_lock_bh(&ip6_tnl_lock);
 			*tp = t->next;
-			write_unlock_bh(&ip6ip6_lock);
+			write_unlock_bh(&ip6_tnl_lock);
 			break;
 		}
 	}
@@ -237,12 +241,12 @@ static struct ip6_tnl *ip6_tnl_create(st
 		if (i == IP6_TNL_MAX)
 			goto failed;
 	}
-	dev = alloc_netdev(sizeof (*t), name, ip6ip6_tnl_dev_setup);
+	dev = alloc_netdev(sizeof (*t), name, ip6_tnl_dev_setup);
 	if (dev == NULL)
 		goto failed;
 
 	t = netdev_priv(dev);
-	dev->init = ip6ip6_tnl_dev_init;
+	dev->init = ip6_tnl_dev_init;
 	t->parms = *p;
 
 	if ((err = register_netdevice(dev)) < 0) {
@@ -250,19 +254,19 @@ static struct ip6_tnl *ip6_tnl_create(st
 		goto failed;
 	}
 	dev_hold(dev);
-	ip6ip6_tnl_link(t);
+	ip6_tnl_link(t);
 	return t;
 failed:
 	return NULL;
 }
 
 /**
- * ip6ip6_tnl_locate - find or create tunnel matching given parameters
+ * ip6_tnl_locate - find or create tunnel matching given parameters
  *   @p: tunnel parameters
  *   @create: != 0 if allowed to create new tunnel if no match found
  *
  * Description:
- *   ip6ip6_tnl_locate() first tries to locate an existing tunnel
+ *   ip6_tnl_locate() first tries to locate an existing tunnel
  *   based on @parms. If this is unsuccessful, but @create is set a new
  *   tunnel device is created and registered for use.
  *
@@ -270,13 +274,13 @@ failed:
  *   matching tunnel or NULL
  **/
 
-static struct ip6_tnl *ip6ip6_tnl_locate(struct ip6_tnl_parm *p, int create)
+static struct ip6_tnl *ip6_tnl_locate(struct ip6_tnl_parm *p, int create)
 {
 	struct in6_addr *remote = &p->raddr;
 	struct in6_addr *local = &p->laddr;
 	struct ip6_tnl *t;
 
-	for (t = *ip6ip6_bucket(p); t; t = t->next) {
+	for (t = *ip6_tnl_bucket(p); t; t = t->next) {
 		if (ipv6_addr_equal(local, &t->parms.laddr) &&
 		    ipv6_addr_equal(remote, &t->parms.raddr))
 			return t;
@@ -287,24 +291,24 @@ static struct ip6_tnl *ip6ip6_tnl_locate
 }
 
 /**
- * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
+ * ip6_tnl_dev_uninit - tunnel device uninitializer
  *   @dev: the device to be destroyed
  *
  * Description:
- *   ip6ip6_tnl_dev_uninit() removes tunnel from its list
+ *   ip6_tnl_dev_uninit() removes tunnel from its list
  **/
 
 static void
-ip6ip6_tnl_dev_uninit(struct net_device *dev)
+ip6_tnl_dev_uninit(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 
-	if (dev == ip6ip6_fb_tnl_dev) {
-		write_lock_bh(&ip6ip6_lock);
+	if (dev == ip6_fb_tnl_dev) {
+		write_lock_bh(&ip6_tnl_lock);
 		tnls_wc[0] = NULL;
-		write_unlock_bh(&ip6ip6_lock);
+		write_unlock_bh(&ip6_tnl_lock);
 	} else {
-		ip6ip6_tnl_unlink(t);
+		ip6_tnl_unlink(t);
 	}
 	ip6_tnl_dst_reset(t);
 	dev_put(dev);
@@ -372,16 +376,16 @@ parse_tlv_tnl_enc_lim(struct sk_buff *sk
 }
 
 /**
- * ip6ip6_err - tunnel error handler
+ * ip6_tnl_err - tunnel error handler
  *
  * Description:
- *   ip6ip6_err() should handle errors in the tunnel according
+ *   ip6_tnl_err() should handle errors in the tunnel according
  *   to the specifications in RFC 2473.
  **/
 
 static int
-ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-	   int type, int code, int offset, __be32 info)
+ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
+	    int *type, int *code, int *msg, __be32 *info, int offset)
 {
 	struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
 	struct ip6_tnl *t;
@@ -396,13 +400,16 @@ ip6ip6_err(struct sk_buff *skb, struct i
 	   in trouble since we might need the source address for further
 	   processing of the error. */
 
-	read_lock(&ip6ip6_lock);
-	if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
+	read_lock(&ip6_tnl_lock);
+	if ((t = ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
+		goto out;
+
+	if (t->parms.proto != ipproto && t->parms.proto != 0)
 		goto out;
 
 	err = 0;
 
-	switch (type) {
+	switch (*type) {
 		__u32 teli;
 		struct ipv6_tlv_tnl_enc_lim *tel;
 		__u32 mtu;
@@ -414,7 +421,7 @@ ip6ip6_err(struct sk_buff *skb, struct i
 		rel_msg = 1;
 		break;
 	case ICMPV6_TIME_EXCEED:
-		if (code == ICMPV6_EXC_HOPLIMIT) {
+		if ((*code) == ICMPV6_EXC_HOPLIMIT) {
 			if (net_ratelimit())
 				printk(KERN_WARNING
 				       "%s: Too small hop limit or "
@@ -425,10 +432,10 @@ ip6ip6_err(struct sk_buff *skb, struct i
 		break;
 	case ICMPV6_PARAMPROB:
 		teli = 0;
-		if (code == ICMPV6_HDR_FIELD)
+		if ((*code) == ICMPV6_HDR_FIELD)
 			teli = parse_tlv_tnl_enc_lim(skb, skb->data);
 
-		if (teli && teli == ntohl(info) - 2) {
+		if (teli && teli == ntohl(*info) - 2) {
 			tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
 			if (tel->encap_limit == 0) {
 				if (net_ratelimit())
@@ -445,7 +452,7 @@ ip6ip6_err(struct sk_buff *skb, struct i
 		}
 		break;
 	case ICMPV6_PKT_TOOBIG:
-		mtu = ntohl(info) - offset;
+		mtu = ntohl(*info) - offset;
 		if (mtu < IPV6_MIN_MTU)
 			mtu = IPV6_MIN_MTU;
 		t->dev->mtu = mtu;
@@ -458,20 +465,144 @@ ip6ip6_err(struct sk_buff *skb, struct i
 		}
 		break;
 	}
-	if (rel_msg &&  pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
+
+	*type = rel_type;
+	*code = rel_code;
+	*info = rel_info;
+	*msg = rel_msg;
+
+out:
+	read_unlock(&ip6_tnl_lock);
+	return err;
+}
+
+static int
+ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+	   int type, int code, int offset, __u32 info)
+{
+	int rel_msg = 0;
+	int rel_type = type;
+	int rel_code = code;
+	__u32 rel_info = info;
+	int err;
+	struct sk_buff *skb2;
+	struct iphdr *eiph;
+	struct flowi fl;
+	struct rtable *rt;
+
+	err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
+			  &rel_msg, &rel_info, offset);
+	if (err < 0)
+		return err;
+
+	if (rel_msg == 0)
+		return 0;
+
+	switch (rel_type) {
+	case ICMPV6_DEST_UNREACH:
+		if (rel_code != ICMPV6_ADDR_UNREACH)
+			return 0;
+		rel_type = ICMP_DEST_UNREACH;
+		rel_code = ICMP_HOST_UNREACH;
+		break;
+	case ICMPV6_PKT_TOOBIG:
+		if (rel_code != 0)
+			return 0;
+		rel_type = ICMP_DEST_UNREACH;
+		rel_code = ICMP_FRAG_NEEDED;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
+		return 0;
+
+	skb2 = skb_clone(skb, GFP_ATOMIC);
+	if (!skb2)
+		return 0;
+
+	dst_release(skb2->dst);
+	skb2->dst = NULL;
+	skb_pull(skb2, offset);
+	skb_reset_network_header(skb2);
+	eiph = ip_hdr(skb2);
+
+	/* Try to guess incoming interface */
+	memset(&fl, 0, sizeof(fl));
+	fl.fl4_dst = eiph->saddr;
+	fl.fl4_tos = RT_TOS(eiph->tos);
+	fl.proto = IPPROTO_IPIP;
+	if (ip_route_output_key(&rt, &fl))
+		goto out;
+
+	skb2->dev = rt->u.dst.dev;
+
+	/* route "incoming" packet */
+	if (rt->rt_flags & RTCF_LOCAL) {
+		ip_rt_put(rt);
+		rt = NULL;
+		fl.fl4_dst = eiph->daddr;
+		fl.fl4_src = eiph->saddr;
+		fl.fl4_tos = eiph->tos;
+		if (ip_route_output_key(&rt, &fl) ||
+		    rt->u.dst.dev->type != ARPHRD_TUNNEL) {
+			ip_rt_put(rt);
+			goto out;
+		}
+	} else {
+		ip_rt_put(rt);
+		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
+				   skb2->dev) ||
+		    skb2->dst->dev->type != ARPHRD_TUNNEL)
+			goto out;
+	}
+
+	/* change mtu on this route */
+	if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
+		if (rel_info > dst_mtu(skb2->dst))
+			goto out;
+
+		skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
+		rel_info = htonl(rel_info);
+	}
+
+	icmp_send(skb2, rel_type, rel_code, rel_info);
+
+out:
+	kfree_skb(skb2);
+	return 0;
+}
+
+static int
+ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+	   int type, int code, int offset, __u32 info)
+{
+	int rel_msg = 0;
+	int rel_type = type;
+	int rel_code = code;
+	__u32 rel_info = info;
+	int err;
+
+	err = ip6_tnl_err(skb, IPPROTO_IPV6, opt, &rel_type, &rel_code,
+			  &rel_msg, &rel_info, offset);
+	if (err < 0)
+		return err;
+
+	if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) {
 		struct rt6_info *rt;
 		struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
 		if (!skb2)
-			goto out;
+			return 0;
 
 		dst_release(skb2->dst);
 		skb2->dst = NULL;
 		skb_pull(skb2, offset);
-		skb2->nh.raw = skb2->data;
+		skb_reset_network_header(skb2);
 
 		/* Try to guess incoming interface */
-		rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
+		rt = rt6_lookup(&ipv6_hdr(skb2)->saddr, NULL, 0, 0);
 
 		if (rt && rt->rt6i_dev)
 			skb2->dev = rt->rt6i_dev;
@@ -483,19 +614,34 @@ ip6ip6_err(struct sk_buff *skb, struct i
 
 		kfree_skb(skb2);
 	}
-out:
-	read_unlock(&ip6ip6_lock);
-	return err;
+
+	return 0;
 }
 
-static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
-					  struct sk_buff *skb)
+static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
+					struct ipv6hdr *ipv6h,
+					struct sk_buff *skb)
 {
-	struct ipv6hdr *inner_iph = skb->nh.ipv6h;
+	__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
 
-	if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
-		IP6_ECN_set_ce(inner_iph);
+	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+		ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
+
+	if (INET_ECN_is_ce(dsfield))
+		IP_ECN_set_ce(ip_hdr(skb));
+}
+
+static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
+					struct ipv6hdr *ipv6h,
+					struct sk_buff *skb)
+{
+	if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+		ipv6_copy_dscp(ipv6h, ipv6_hdr(skb));
+
+	if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h)))
+		IP6_ECN_set_ce(ipv6_hdr(skb));
 }
+
 static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t)
 {
 	struct ip6_tnl_parm *p = &t->parms;
@@ -519,53 +665,61 @@ static inline int ip6_tnl_rcv_ctl(struct
 }
 
 /**
- * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
+ * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
  *   @skb: received socket buffer
+ *   @protocol: ethernet protocol ID
+ *   @dscp_ecn_decapsulate: the function to decapsulate DSCP code and ECN
  *
  * Return: 0
  **/
 
-static int
-ip6ip6_rcv(struct sk_buff *skb)
+static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
+		       __u8 ipproto,
+		       void (*dscp_ecn_decapsulate)(struct ip6_tnl *t,
+						    struct ipv6hdr *ipv6h,
+						    struct sk_buff *skb))
 {
-	struct ipv6hdr *ipv6h;
 	struct ip6_tnl *t;
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 
-	ipv6h = skb->nh.ipv6h;
+	read_lock(&ip6_tnl_lock);
 
-	read_lock(&ip6ip6_lock);
+	if ((t = ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
+		if (t->parms.proto != ipproto && t->parms.proto != 0) {
+			read_unlock(&ip6_tnl_lock);
+			goto discard;
+		}
 
-	if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
 		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-			read_unlock(&ip6ip6_lock);
+			read_unlock(&ip6_tnl_lock);
 			goto discard;
 		}
 
 		if (!ip6_tnl_rcv_ctl(t)) {
 			t->stat.rx_dropped++;
-			read_unlock(&ip6ip6_lock);
+			read_unlock(&ip6_tnl_lock);
 			goto discard;
 		}
 		secpath_reset(skb);
-		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = skb->data;
-		skb->protocol = htons(ETH_P_IPV6);
+		skb->mac_header = skb->network_header;
+		skb_reset_network_header(skb);
+		skb->protocol = htons(protocol);
 		skb->pkt_type = PACKET_HOST;
 		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
 		skb->dev = t->dev;
 		dst_release(skb->dst);
 		skb->dst = NULL;
 		nf_reset(skb);
-		if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
-			ipv6_copy_dscp(ipv6h, skb->nh.ipv6h);
-		ip6ip6_ecn_decapsulate(ipv6h, skb);
+
+		dscp_ecn_decapsulate(t, ipv6h, skb);
+
 		t->stat.rx_packets++;
 		t->stat.rx_bytes += skb->len;
 		netif_rx(skb);
-		read_unlock(&ip6ip6_lock);
+		read_unlock(&ip6_tnl_lock);
 		return 0;
 	}
-	read_unlock(&ip6ip6_lock);
+	read_unlock(&ip6_tnl_lock);
 	return 1;
 
 discard:
@@ -573,6 +727,18 @@ discard:
 	return 0;
 }
 
+static int ip4ip6_rcv(struct sk_buff *skb)
+{
+	return ip6_tnl_rcv(skb, ETH_P_IP, IPPROTO_IPIP,
+			   ip4ip6_dscp_ecn_decapsulate);
+}
+
+static int ip6ip6_rcv(struct sk_buff *skb)
+{
+	return ip6_tnl_rcv(skb, ETH_P_IPV6, IPPROTO_IPV6,
+			   ip6ip6_dscp_ecn_decapsulate);
+}
+
 struct ipv6_tel_txoption {
 	struct ipv6_txoptions ops;
 	__u8 dst_opt[8];
@@ -593,7 +759,7 @@ static void init_tel_txopt(struct ipv6_t
 }
 
 /**
- * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
  *   @t: the outgoing tunnel device
  *   @hdr: IPv6 header from the incoming packet
  *
@@ -607,7 +773,7 @@ static void init_tel_txopt(struct ipv6_t
  **/
 
 static inline int
-ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
 {
 	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
 }
@@ -641,72 +807,49 @@ static inline int ip6_tnl_xmit_ctl(struc
 	return ret;
 }
 /**
- * ip6ip6_tnl_xmit - encapsulate packet and send
+ * ip6_tnl_xmit2 - encapsulate packet and send
  *   @skb: the outgoing socket buffer
  *   @dev: the outgoing tunnel device
+ *   @dsfield: dscp code for outer header
+ *   @fl: flow of tunneled packet
+ *   @encap_limit: encapsulation limit
+ *   @pmtu: Path MTU is stored if packet is too big
  *
  * Description:
  *   Build new header and do some sanity checks on the packet before sending
  *   it.
  *
  * Return:
- *   0
+ *   0 on success
+ *   -1 fail
+ *   %-EMSGSIZE message too big. return mtu in this case.
  **/
 
-static int
-ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+static int ip6_tnl_xmit2(struct sk_buff *skb,
+			 struct net_device *dev,
+			 __u8 dsfield,
+			 struct flowi *fl,
+			 int encap_limit,
+			 __u32 *pmtu)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net_device_stats *stats = &t->stat;
-	struct ipv6hdr *ipv6h = skb->nh.ipv6h;
-	int encap_limit = -1;
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 	struct ipv6_tel_txoption opt;
-	__u16 offset;
-	struct flowi fl;
 	struct dst_entry *dst;
 	struct net_device *tdev;
 	int mtu;
 	int max_headroom = sizeof(struct ipv6hdr);
 	u8 proto;
-	int err;
+	int err = -1;
 	int pkt_len;
-	int dsfield;
-
-	if (t->recursion++) {
-		stats->collisions++;
-		goto tx_err;
-	}
-	if (skb->protocol != htons(ETH_P_IPV6) ||
-	    !ip6_tnl_xmit_ctl(t) || ip6ip6_tnl_addr_conflict(t, ipv6h))
-		goto tx_err;
-
-	if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
-		struct ipv6_tlv_tnl_enc_lim *tel;
-		tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
-		if (tel->encap_limit == 0) {
-			icmpv6_send(skb, ICMPV6_PARAMPROB,
-				    ICMPV6_HDR_FIELD, offset + 2, skb->dev);
-			goto tx_err;
-		}
-		encap_limit = tel->encap_limit - 1;
-	} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-		encap_limit = t->parms.encap_limit;
-
-	memcpy(&fl, &t->fl, sizeof (fl));
-	proto = fl.proto;
-
-	dsfield = ipv6_get_dsfield(ipv6h);
-	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
-		fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
-	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
-		fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK);
 
 	if ((dst = ip6_tnl_dst_check(t)) != NULL)
 		dst_hold(dst);
 	else {
-		dst = ip6_route_output(NULL, &fl);
+		dst = ip6_route_output(NULL, fl);
 
-		if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0) < 0)
+		if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0)
 			goto tx_err_link_failure;
 	}
 
@@ -730,7 +873,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
 	if (skb->dst)
 		skb->dst->ops->update_pmtu(skb->dst, mtu);
 	if (skb->len > mtu) {
-		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+		*pmtu = mtu;
+		err = -EMSGSIZE;
 		goto tx_err_dst_release;
 	}
 
@@ -754,22 +898,24 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
 	dst_release(skb->dst);
 	skb->dst = dst_clone(dst);
 
-	skb->h.raw = skb->nh.raw;
+	skb->transport_header = skb->network_header;
 
+	proto = fl->proto;
 	if (encap_limit >= 0) {
 		init_tel_txopt(&opt, encap_limit);
 		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
 	}
-	skb->nh.raw = skb_push(skb, sizeof(struct ipv6hdr));
-	ipv6h = skb->nh.ipv6h;
-	*(__be32*)ipv6h = fl.fl6_flowlabel | htonl(0x60000000);
+	skb_push(skb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(skb);
+	ipv6h = ipv6_hdr(skb);
+	*(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000);
 	dsfield = INET_ECN_encapsulate(0, dsfield);
 	ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
 	ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 	ipv6h->hop_limit = t->parms.hop_limit;
 	ipv6h->nexthdr = proto;
-	ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
-	ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
+	ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src);
+	ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst);
 	nf_reset(skb);
 	pkt_len = skb->len;
 	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
@@ -783,13 +929,131 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
 		stats->tx_aborted_errors++;
 	}
 	ip6_tnl_dst_store(t, dst);
-	t->recursion--;
 	return 0;
 tx_err_link_failure:
 	stats->tx_carrier_errors++;
 	dst_link_failure(skb);
 tx_err_dst_release:
 	dst_release(dst);
+	return err;
+}
+
+static inline int
+ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct iphdr  *iph = ip_hdr(skb);
+	int encap_limit = -1;
+	struct flowi fl;
+	__u8 dsfield;
+	__u32 mtu;
+	int err;
+
+	if ((t->parms.proto != IPPROTO_IPIP && t->parms.proto != 0) ||
+	    !ip6_tnl_xmit_ctl(t))
+		return -1;
+
+	if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+		encap_limit = t->parms.encap_limit;
+
+	memcpy(&fl, &t->fl, sizeof (fl));
+	fl.proto = IPPROTO_IPIP;
+
+	dsfield = ipv4_get_dsfield(iph);
+
+	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+		fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+					  & IPV6_TCLASS_MASK);
+
+	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
+	if (err != 0) {
+		/* XXX: send ICMP error even if DF is not set. */
+		if (err == -EMSGSIZE)
+			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+				  htonl(mtu));
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline int
+ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+	int encap_limit = -1;
+	__u16 offset;
+	struct flowi fl;
+	__u8 dsfield;
+	__u32 mtu;
+	int err;
+
+	if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
+	    !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
+		return -1;
+
+	offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb));
+	if (offset > 0) {
+		struct ipv6_tlv_tnl_enc_lim *tel;
+		tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
+		if (tel->encap_limit == 0) {
+			icmpv6_send(skb, ICMPV6_PARAMPROB,
+				    ICMPV6_HDR_FIELD, offset + 2, skb->dev);
+			return -1;
+		}
+		encap_limit = tel->encap_limit - 1;
+	} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+		encap_limit = t->parms.encap_limit;
+
+	memcpy(&fl, &t->fl, sizeof (fl));
+	fl.proto = IPPROTO_IPV6;
+
+	dsfield = ipv6_get_dsfield(ipv6h);
+	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+		fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
+	if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
+		fl.fl6_flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+
+	err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
+	if (err != 0) {
+		if (err == -EMSGSIZE)
+			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ip6_tnl *t = netdev_priv(dev);
+	struct net_device_stats *stats = &t->stat;
+	int ret;
+
+	if (t->recursion++) {
+		t->stat.collisions++;
+		goto tx_err;
+	}
+
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		ret = ip4ip6_tnl_xmit(skb, dev);
+		break;
+	case __constant_htons(ETH_P_IPV6):
+		ret = ip6ip6_tnl_xmit(skb, dev);
+		break;
+	default:
+		goto tx_err;
+	}
+
+	if (ret < 0)
+		goto tx_err;
+
+	t->recursion--;
+	return 0;
+
 tx_err:
 	stats->tx_errors++;
 	stats->tx_dropped++;
@@ -817,7 +1081,7 @@ static void ip6_tnl_set_cap(struct ip6_t
 	}
 }
 
-static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
+static void ip6_tnl_link_config(struct ip6_tnl *t)
 {
 	struct net_device *dev = t->dev;
 	struct ip6_tnl_parm *p = &t->parms;
@@ -870,17 +1134,17 @@ static void ip6ip6_tnl_link_config(struc
 }
 
 /**
- * ip6ip6_tnl_change - update the tunnel parameters
+ * ip6_tnl_change - update the tunnel parameters
  *   @t: tunnel to be changed
  *   @p: tunnel configuration parameters
  *   @active: != 0 if tunnel is ready for use
  *
  * Description:
- *   ip6ip6_tnl_change() updates the tunnel parameters
+ *   ip6_tnl_change() updates the tunnel parameters
  **/
 
 static int
-ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
 {
 	ipv6_addr_copy(&t->parms.laddr, &p->laddr);
 	ipv6_addr_copy(&t->parms.raddr, &p->raddr);
@@ -889,19 +1153,20 @@ ip6ip6_tnl_change(struct ip6_tnl *t, str
 	t->parms.encap_limit = p->encap_limit;
 	t->parms.flowinfo = p->flowinfo;
 	t->parms.link = p->link;
+	t->parms.proto = p->proto;
 	ip6_tnl_dst_reset(t);
-	ip6ip6_tnl_link_config(t);
+	ip6_tnl_link_config(t);
 	return 0;
 }
 
 /**
- * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
  *   @dev: virtual device associated with tunnel
  *   @ifr: parameters passed from userspace
  *   @cmd: command to be performed
  *
  * Description:
- *   ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
+ *   ip6_tnl_ioctl() is used for managing IPv6 tunnels
  *   from userspace.
  *
  *   The possible commands are the following:
@@ -923,7 +1188,7 @@ ip6ip6_tnl_change(struct ip6_tnl *t, str
  **/
 
 static int
-ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	int err = 0;
 	struct ip6_tnl_parm p;
@@ -931,12 +1196,12 @@ ip6ip6_tnl_ioctl(struct net_device *dev,
 
 	switch (cmd) {
 	case SIOCGETTUNNEL:
-		if (dev == ip6ip6_fb_tnl_dev) {
+		if (dev == ip6_fb_tnl_dev) {
 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
 				err = -EFAULT;
 				break;
 			}
-			t = ip6ip6_tnl_locate(&p, 0);
+			t = ip6_tnl_locate(&p, 0);
 		}
 		if (t == NULL)
 			t = netdev_priv(dev);
@@ -954,10 +1219,11 @@ ip6ip6_tnl_ioctl(struct net_device *dev,
 		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
 			break;
 		err = -EINVAL;
-		if (p.proto != IPPROTO_IPV6)
+		if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
+		    p.proto != 0)
 			break;
-		t = ip6ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL);
-		if (dev != ip6ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
+		t = ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL);
+		if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
 			if (t != NULL) {
 				if (t->dev != dev) {
 					err = -EEXIST;
@@ -966,9 +1232,9 @@ ip6ip6_tnl_ioctl(struct net_device *dev,
 			} else
 				t = netdev_priv(dev);
 
-			ip6ip6_tnl_unlink(t);
-			err = ip6ip6_tnl_change(t, &p);
-			ip6ip6_tnl_link(t);
+			ip6_tnl_unlink(t);
+			err = ip6_tnl_change(t, &p);
+			ip6_tnl_link(t);
 			netdev_state_change(dev);
 		}
 		if (t) {
@@ -984,15 +1250,15 @@ ip6ip6_tnl_ioctl(struct net_device *dev,
 		if (!capable(CAP_NET_ADMIN))
 			break;
 
-		if (dev == ip6ip6_fb_tnl_dev) {
+		if (dev == ip6_fb_tnl_dev) {
 			err = -EFAULT;
 			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
 				break;
 			err = -ENOENT;
-			if ((t = ip6ip6_tnl_locate(&p, 0)) == NULL)
+			if ((t = ip6_tnl_locate(&p, 0)) == NULL)
 				break;
 			err = -EPERM;
-			if (t->dev == ip6ip6_fb_tnl_dev)
+			if (t->dev == ip6_fb_tnl_dev)
 				break;
 			dev = t->dev;
 		}
@@ -1006,20 +1272,20 @@ ip6ip6_tnl_ioctl(struct net_device *dev,
 }
 
 /**
- * ip6ip6_tnl_get_stats - return the stats for tunnel device
+ * ip6_tnl_get_stats - return the stats for tunnel device
  *   @dev: virtual device associated with tunnel
  *
  * Return: stats for device
  **/
 
 static struct net_device_stats *
-ip6ip6_tnl_get_stats(struct net_device *dev)
+ip6_tnl_get_stats(struct net_device *dev)
 {
 	return &(((struct ip6_tnl *)netdev_priv(dev))->stat);
 }
 
 /**
- * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
+ * ip6_tnl_change_mtu - change mtu manually for tunnel device
  *   @dev: virtual device associated with tunnel
  *   @new_mtu: the new mtu
  *
@@ -1029,7 +1295,7 @@ ip6ip6_tnl_get_stats(struct net_device *
  **/
 
 static int
-ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 {
 	if (new_mtu < IPV6_MIN_MTU) {
 		return -EINVAL;
@@ -1039,22 +1305,22 @@ ip6ip6_tnl_change_mtu(struct net_device 
 }
 
 /**
- * ip6ip6_tnl_dev_setup - setup virtual tunnel device
+ * ip6_tnl_dev_setup - setup virtual tunnel device
  *   @dev: virtual device associated with tunnel
  *
  * Description:
  *   Initialize function pointers and device parameters
  **/
 
-static void ip6ip6_tnl_dev_setup(struct net_device *dev)
+static void ip6_tnl_dev_setup(struct net_device *dev)
 {
 	SET_MODULE_OWNER(dev);
-	dev->uninit = ip6ip6_tnl_dev_uninit;
+	dev->uninit = ip6_tnl_dev_uninit;
 	dev->destructor = free_netdev;
-	dev->hard_start_xmit = ip6ip6_tnl_xmit;
-	dev->get_stats = ip6ip6_tnl_get_stats;
-	dev->do_ioctl = ip6ip6_tnl_ioctl;
-	dev->change_mtu = ip6ip6_tnl_change_mtu;
+	dev->hard_start_xmit = ip6_tnl_xmit;
+	dev->get_stats = ip6_tnl_get_stats;
+	dev->do_ioctl = ip6_tnl_ioctl;
+	dev->change_mtu = ip6_tnl_change_mtu;
 
 	dev->type = ARPHRD_TUNNEL6;
 	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
@@ -1065,50 +1331,56 @@ static void ip6ip6_tnl_dev_setup(struct 
 
 
 /**
- * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
+ * ip6_tnl_dev_init_gen - general initializer for all tunnel devices
  *   @dev: virtual device associated with tunnel
  **/
 
 static inline void
-ip6ip6_tnl_dev_init_gen(struct net_device *dev)
+ip6_tnl_dev_init_gen(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
-	t->fl.proto = IPPROTO_IPV6;
 	t->dev = dev;
 	strcpy(t->parms.name, dev->name);
 }
 
 /**
- * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
+ * ip6_tnl_dev_init - initializer for all non fallback tunnel devices
  *   @dev: virtual device associated with tunnel
  **/
 
 static int
-ip6ip6_tnl_dev_init(struct net_device *dev)
+ip6_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
-	ip6ip6_tnl_dev_init_gen(dev);
-	ip6ip6_tnl_link_config(t);
+	ip6_tnl_dev_init_gen(dev);
+	ip6_tnl_link_config(t);
 	return 0;
 }
 
 /**
- * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
+ * ip6_fb_tnl_dev_init - initializer for fallback tunnel device
  *   @dev: fallback device
  *
  * Return: 0
  **/
 
 static int
-ip6ip6_fb_tnl_dev_init(struct net_device *dev)
+ip6_fb_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
-	ip6ip6_tnl_dev_init_gen(dev);
+	ip6_tnl_dev_init_gen(dev);
+	t->parms.proto = IPPROTO_IPV6;
 	dev_hold(dev);
 	tnls_wc[0] = t;
 	return 0;
 }
 
+static struct xfrm6_tunnel ip4ip6_handler = {
+	.handler	= ip4ip6_rcv,
+	.err_handler	= ip4ip6_err,
+	.priority	=	1,
+};
+
 static struct xfrm6_tunnel ip6ip6_handler = {
 	.handler	= ip6ip6_rcv,
 	.err_handler	= ip6ip6_err,
@@ -1125,30 +1397,40 @@ static int __init ip6_tunnel_init(void)
 {
 	int  err;
 
+	if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) {
+		printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n");
+		err = -EAGAIN;
+		goto out;
+	}
+
 	if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
-		printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
-		return -EAGAIN;
+		printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n");
+		err = -EAGAIN;
+		goto unreg_ip4ip6;
 	}
-	ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
-					 ip6ip6_tnl_dev_setup);
+	ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
+				      ip6_tnl_dev_setup);
 
-	if (!ip6ip6_fb_tnl_dev) {
+	if (!ip6_fb_tnl_dev) {
 		err = -ENOMEM;
 		goto fail;
 	}
-	ip6ip6_fb_tnl_dev->init = ip6ip6_fb_tnl_dev_init;
+	ip6_fb_tnl_dev->init = ip6_fb_tnl_dev_init;
 
-	if ((err = register_netdev(ip6ip6_fb_tnl_dev))) {
-		free_netdev(ip6ip6_fb_tnl_dev);
+	if ((err = register_netdev(ip6_fb_tnl_dev))) {
+		free_netdev(ip6_fb_tnl_dev);
 		goto fail;
 	}
 	return 0;
 fail:
 	xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
+unreg_ip4ip6:
+	xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
+out:
 	return err;
 }
 
-static void __exit ip6ip6_destroy_tunnels(void)
+static void __exit ip6_tnl_destroy_tunnels(void)
 {
 	int h;
 	struct ip6_tnl *t;
@@ -1168,11 +1450,14 @@ static void __exit ip6ip6_destroy_tunnel
 
 static void __exit ip6_tunnel_cleanup(void)
 {
+	if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
+		printk(KERN_INFO "ip6_tunnel close: can't deregister ip4ip6\n");
+
 	if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
-		printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
+		printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n");
 
 	rtnl_lock();
-	ip6ip6_destroy_tunnels();
+	ip6_tnl_destroy_tunnels();
 	rtnl_unlock();
 }
 
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 5724ba9..1ee50b5 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -79,9 +79,9 @@ static int ipcomp6_input(struct xfrm_sta
 	skb->ip_summed = CHECKSUM_NONE;
 
 	/* Remove ipcomp header and decompress original payload */
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 	ipch = (void *)skb->data;
-	skb->h.raw = skb->nh.raw + sizeof(*ipch);
+	skb->transport_header = skb->network_header + sizeof(*ipch);
 	__skb_pull(skb, sizeof(*ipch));
 
 	/* decompression */
@@ -111,7 +111,7 @@ static int ipcomp6_input(struct xfrm_sta
 
 	skb->truesize += dlen - plen;
 	__skb_put(skb, dlen - plen);
-	memcpy(skb->data, scratch, dlen);
+	skb_copy_to_linear_data(skb, scratch, dlen);
 	err = ipch->nexthdr;
 
 out_put_cpu:
@@ -124,15 +124,13 @@ static int ipcomp6_output(struct xfrm_st
 {
 	int err;
 	struct ipv6hdr *top_iph;
-	int hdr_len;
 	struct ipv6_comp_hdr *ipch;
 	struct ipcomp_data *ipcd = x->data;
 	int plen, dlen;
 	u8 *start, *scratch;
 	struct crypto_comp *tfm;
 	int cpu;
-
-	hdr_len = skb->h.raw - skb->data;
+	int hdr_len = skb_transport_offset(skb);
 
 	/* check whether datagram len is larger than threshold */
 	if ((skb->len - hdr_len) < ipcd->threshold) {
@@ -145,7 +143,7 @@ static int ipcomp6_output(struct xfrm_st
 	/* compression */
 	plen = skb->len - hdr_len;
 	dlen = IPCOMP_SCRATCH_SIZE;
-	start = skb->h.raw;
+	start = skb_transport_header(skb);
 
 	cpu = get_cpu();
 	scratch = *per_cpu_ptr(ipcomp6_scratches, cpu);
@@ -166,10 +164,10 @@ static int ipcomp6_output(struct xfrm_st
 	top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 
 	ipch = (struct ipv6_comp_hdr *)start;
-	ipch->nexthdr = *skb->nh.raw;
+	ipch->nexthdr = *skb_network_header(skb);
 	ipch->flags = 0;
 	ipch->cpi = htons((u16 )ntohl(x->id.spi));
-	*skb->nh.raw = IPPROTO_COMP;
+	*skb_network_header(skb) = IPPROTO_COMP;
 
 out_ok:
 	return 0;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index f5f9582..aa3d07c 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -101,14 +101,14 @@ static int ipv6_gso_send_check(struct sk
 	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
 		goto out;
 
-	ipv6h = skb->nh.ipv6h;
+	ipv6h = ipv6_hdr(skb);
 	__skb_pull(skb, sizeof(*ipv6h));
 	err = -EPROTONOSUPPORT;
 
 	rcu_read_lock();
 	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 	if (likely(ops && ops->gso_send_check)) {
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 		err = ops->gso_send_check(skb);
 	}
 	rcu_read_unlock();
@@ -137,14 +137,14 @@ static struct sk_buff *ipv6_gso_segment(
 	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
 		goto out;
 
-	ipv6h = skb->nh.ipv6h;
+	ipv6h = ipv6_hdr(skb);
 	__skb_pull(skb, sizeof(*ipv6h));
 	segs = ERR_PTR(-EPROTONOSUPPORT);
 
 	rcu_read_lock();
 	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 	if (likely(ops && ops->gso_segment)) {
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 		segs = ops->gso_segment(skb, features);
 	}
 	rcu_read_unlock();
@@ -153,7 +153,7 @@ static struct sk_buff *ipv6_gso_segment(
 		goto out;
 
 	for (skb = segs; skb; skb = skb->next) {
-		ipv6h = skb->nh.ipv6h;
+		ipv6h = ipv6_hdr(skb);
 		ipv6h->payload_len = htons(skb->len - skb->mac_len -
 					   sizeof(*ipv6h));
 	}
@@ -694,7 +694,7 @@ done:
 		retv = ip6_ra_control(sk, val, NULL);
 		break;
 	case IPV6_MTU_DISCOVER:
-		if (val<0 || val>2)
+		if (val<0 || val>3)
 			goto e_inval;
 		np->pmtudisc = val;
 		retv = 0;
@@ -761,6 +761,7 @@ #endif
 	return err;
 }
 
+EXPORT_SYMBOL(ipv6_setsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
@@ -796,18 +797,37 @@ EXPORT_SYMBOL(compat_ipv6_setsockopt);
 #endif
 
 static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
-				  char __user *optval, int len)
+				  int optname, char __user *optval, int len)
 {
 	struct ipv6_opt_hdr *hdr;
 
-	if (!opt || !opt->hopopt)
+	if (!opt)
+		return 0;
+
+	switch(optname) {
+	case IPV6_HOPOPTS:
+		hdr = opt->hopopt;
+		break;
+	case IPV6_RTHDRDSTOPTS:
+		hdr = opt->dst0opt;
+		break;
+	case IPV6_RTHDR:
+		hdr = (struct ipv6_opt_hdr *)opt->srcrt;
+		break;
+	case IPV6_DSTOPTS:
+		hdr = opt->dst1opt;
+		break;
+	default:
+		return -EINVAL;	/* should not happen */
+	}
+
+	if (!hdr)
 		return 0;
-	hdr = opt->hopopt;
 
 	len = min_t(unsigned int, len, ipv6_optlen(hdr));
-	if (copy_to_user(optval, hdr, ipv6_optlen(hdr)))
+	if (copy_to_user(optval, hdr, len));
 		return -EFAULT;
-	return len;
+	return ipv6_optlen(hdr);
 }
 
 static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
@@ -945,7 +965,7 @@ static int do_ipv6_getsockopt(struct soc
 
 		lock_sock(sk);
 		len = ipv6_getsockopt_sticky(sk, np->opt,
-					     optval, len);
+					     optname, optval, len);
 		release_sock(sk);
 		return put_user(len, optlen);
 	}
@@ -1066,6 +1086,8 @@ #endif
 	return err;
 }
 
+EXPORT_SYMBOL(ipv6_getsockopt);
+
 #ifdef CONFIG_COMPAT
 int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 			   char __user *optval, int __user *optlen)
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
deleted file mode 100644
index e12e3d4..0000000
--- a/net/ipv6/ipv6_syms.c
+++ /dev/null
@@ -1,36 +0,0 @@
-
-#include <linux/module.h>
-#include <net/protocol.h>
-#include <net/ipv6.h>
-#include <net/addrconf.h>
-#include <net/ip6_route.h>
-#include <net/xfrm.h>
-
-EXPORT_SYMBOL(icmpv6_send);
-EXPORT_SYMBOL(icmpv6_statistics);
-EXPORT_SYMBOL(icmpv6_err_convert);
-EXPORT_SYMBOL(ndisc_mc_map);
-EXPORT_SYMBOL(register_inet6addr_notifier);
-EXPORT_SYMBOL(unregister_inet6addr_notifier);
-EXPORT_SYMBOL(ip6_route_output);
-EXPORT_SYMBOL(ipv6_setsockopt);
-EXPORT_SYMBOL(ipv6_getsockopt);
-EXPORT_SYMBOL(inet6_register_protosw);
-EXPORT_SYMBOL(inet6_unregister_protosw);
-EXPORT_SYMBOL(inet6_add_protocol);
-EXPORT_SYMBOL(inet6_del_protocol);
-EXPORT_SYMBOL(ip6_xmit);
-EXPORT_SYMBOL(inet6_release);
-EXPORT_SYMBOL(inet6_bind);
-EXPORT_SYMBOL(inet6_getname);
-EXPORT_SYMBOL(inet6_ioctl);
-EXPORT_SYMBOL(ipv6_get_saddr);
-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 a8d6625..3e308fb 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -988,7 +988,7 @@ int ipv6_is_mld(struct sk_buff *skb, int
 	if (!pskb_may_pull(skb, sizeof(struct icmp6hdr)))
 		return 0;
 
-	pic = (struct icmp6hdr *)skb->h.raw;
+	pic = icmp6_hdr(skb);
 
 	switch (pic->icmp6_type) {
 	case ICMPV6_MGM_QUERY:
@@ -1167,11 +1167,11 @@ int igmp6_event_query(struct sk_buff *sk
 		return -EINVAL;
 
 	/* compute payload length excluding extension headers */
-	len = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
-	len -= (char *)skb->h.raw - (char *)skb->nh.ipv6h;
+	len = ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr);
+	len -= skb_network_header_len(skb);
 
 	/* Drop queries with not link local source */
-	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
+	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
 
 	idev = in6_dev_get(skb->dev);
@@ -1179,7 +1179,7 @@ int igmp6_event_query(struct sk_buff *sk
 	if (idev == NULL)
 		return 0;
 
-	hdr = (struct icmp6hdr *) skb->h.raw;
+	hdr = icmp6_hdr(skb);
 	group = (struct in6_addr *) (hdr + 1);
 	group_type = ipv6_addr_type(group);
 
@@ -1212,7 +1212,7 @@ int igmp6_event_query(struct sk_buff *sk
 			in6_dev_put(idev);
 			return -EINVAL;
 		}
-		mlh2 = (struct mld2_query *) skb->h.raw;
+		mlh2 = (struct mld2_query *)skb_transport_header(skb);
 		max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000;
 		if (!max_delay)
 			max_delay = 1;
@@ -1235,7 +1235,7 @@ int igmp6_event_query(struct sk_buff *sk
 				in6_dev_put(idev);
 				return -EINVAL;
 			}
-			mlh2 = (struct mld2_query *) skb->h.raw;
+			mlh2 = (struct mld2_query *)skb_transport_header(skb);
 			mark = 1;
 		}
 	} else {
@@ -1300,10 +1300,10 @@ int igmp6_event_report(struct sk_buff *s
 	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
 		return -EINVAL;
 
-	hdr = (struct icmp6hdr*) skb->h.raw;
+	hdr = icmp6_hdr(skb);
 
 	/* Drop reports with not link local source */
-	addr_type = ipv6_addr_type(&skb->nh.ipv6h->saddr);
+	addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
 	if (addr_type != IPV6_ADDR_ANY &&
 	    !(addr_type&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
@@ -1411,7 +1411,7 @@ static struct sk_buff *mld_newpack(struc
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
-	if (ipv6_get_lladdr(dev, &addr_buf)) {
+	if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
 		/* <draft-ietf-magma-mld-source-05.txt>:
 		 * use unspecified address as the source address
 		 * when a valid link-local address is not available.
@@ -1423,8 +1423,9 @@ static struct sk_buff *mld_newpack(struc
 
 	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
-	pmr =(struct mld2_report *)skb_put(skb, sizeof(*pmr));
-	skb->h.raw = (unsigned char *)pmr;
+	skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
+	skb_put(skb, sizeof(*pmr));
+	pmr = (struct mld2_report *)skb_transport_header(skb);
 	pmr->type = ICMPV6_MLD2_REPORT;
 	pmr->resv1 = 0;
 	pmr->csum = 0;
@@ -1441,7 +1442,7 @@ static inline int mld_dev_queue_xmit2(st
 		unsigned char ha[MAX_ADDR_LEN];
 		int err;
 
-		ndisc_mc_map(&skb->nh.ipv6h->daddr, ha, dev, 1);
+		ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1);
 		err = dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len);
 		if (err < 0) {
 			kfree_skb(skb);
@@ -1459,20 +1460,21 @@ static inline int mld_dev_queue_xmit(str
 
 static void mld_sendpack(struct sk_buff *skb)
 {
-	struct ipv6hdr *pip6 = skb->nh.ipv6h;
-	struct mld2_report *pmr = (struct mld2_report *)skb->h.raw;
+	struct ipv6hdr *pip6 = ipv6_hdr(skb);
+	struct mld2_report *pmr =
+			      (struct mld2_report *)skb_transport_header(skb);
 	int payload_len, mldlen;
 	struct inet6_dev *idev = in6_dev_get(skb->dev);
 	int err;
 
 	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
-	payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h -
-		sizeof(struct ipv6hdr);
-	mldlen = skb->tail - skb->h.raw;
+	payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
+	mldlen = skb->tail - skb->transport_header;
 	pip6->payload_len = htons(payload_len);
 
 	pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
-		IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0));
+		IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
+					     mldlen, 0));
 	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
 		mld_dev_queue_xmit);
 	if (!err) {
@@ -1506,7 +1508,7 @@ static struct sk_buff *add_grhead(struct
 	pgr->grec_auxwords = 0;
 	pgr->grec_nsrcs = 0;
 	pgr->grec_mca = pmc->mca_addr;	/* structure copy */
-	pmr = (struct mld2_report *)skb->h.raw;
+	pmr = (struct mld2_report *)skb_transport_header(skb);
 	pmr->ngrec = htons(ntohs(pmr->ngrec)+1);
 	*ppgr = pgr;
 	return skb;
@@ -1539,7 +1541,7 @@ static struct sk_buff *add_grec(struct s
 	if (!*psf_list)
 		goto empty_source;
 
-	pmr = skb ? (struct mld2_report *)skb->h.raw : NULL;
+	pmr = skb ? (struct mld2_report *)skb_transport_header(skb) : NULL;
 
 	/* EX and TO_EX get a fresh packet, if needed */
 	if (truncate) {
@@ -1791,7 +1793,7 @@ static void igmp6_send(struct in6_addr *
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
-	if (ipv6_get_lladdr(dev, &addr_buf)) {
+	if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
 		/* <draft-ietf-magma-mld-source-05.txt>:
 		 * use unspecified address as the source address
 		 * when a valid link-local address is not available.
@@ -2329,9 +2331,8 @@ static inline struct ifmcaddr6 *igmp6_mc
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->idev = NULL;
+	for_each_netdev(state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (!idev)
@@ -2358,7 +2359,7 @@ static struct ifmcaddr6 *igmp6_mc_get_ne
 			read_unlock_bh(&state->idev->lock);
 			in6_dev_put(state->idev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_net_device(state->dev);
 		if (!state->dev) {
 			state->idev = NULL;
 			break;
@@ -2473,9 +2474,9 @@ static inline struct ip6_sf_list *igmp6_
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->idev = NULL;
+	state->im = NULL;
+	for_each_netdev(state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (unlikely(idev == NULL))
@@ -2511,7 +2512,7 @@ static struct ip6_sf_list *igmp6_mcf_get
 				read_unlock_bh(&state->idev->lock);
 				in6_dev_put(state->idev);
 			}
-			state->dev = state->dev->next;
+			state->dev = next_net_device(state->dev);
 			if (!state->dev) {
 				state->idev = NULL;
 				goto out;
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 0afcabd..13b7160 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -90,23 +90,26 @@ int mip6_mh_filter(struct sock *sk, stru
 {
 	struct ip6_mh *mh;
 
-	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)))
+	if (!pskb_may_pull(skb, (skb_transport_offset(skb)) + 8) ||
+	    !pskb_may_pull(skb, (skb_transport_offset(skb) +
+				 ((skb_transport_header(skb)[1] + 1) << 3))))
 		return -1;
 
-	mh = (struct ip6_mh *)skb->h.raw;
+	mh = (struct ip6_mh *)skb_transport_header(skb);
 
 	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);
+		mip6_param_prob(skb, 0, ((&mh->ip6mh_hdrlen) -
+					 skb_network_header(skb)));
 		return -1;
 	}
 
 	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);
+		mip6_param_prob(skb, 0, ((&mh->ip6mh_proto) -
+					 skb_network_header(skb)));
 		return -1;
 	}
 
@@ -122,12 +125,12 @@ struct mip6_report_rate_limiter {
 };
 
 static struct mip6_report_rate_limiter mip6_report_rl = {
-	.lock = SPIN_LOCK_UNLOCKED
+	.lock = __SPIN_LOCK_UNLOCKED(mip6_report_rl.lock)
 };
 
 static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data;
 
 	if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
@@ -152,10 +155,10 @@ static int mip6_destopt_output(struct xf
 	iph = (struct ipv6hdr *)skb->data;
 	iph->payload_len = htons(skb->len - sizeof(*iph));
 
-	nexthdr = *skb->nh.raw;
-	*skb->nh.raw = IPPROTO_DSTOPTS;
+	nexthdr = *skb_network_header(skb);
+	*skb_network_header(skb) = IPPROTO_DSTOPTS;
 
-	dstopt = (struct ipv6_destopt_hdr *)skb->h.raw;
+	dstopt = (struct ipv6_destopt_hdr *)skb_transport_header(skb);
 	dstopt->nexthdr = nexthdr;
 
 	hao = mip6_padn((char *)(dstopt + 1),
@@ -215,21 +218,22 @@ static int mip6_destopt_reject(struct xf
 	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);
+			hao = (struct ipv6_destopt_hao *)
+					(skb_network_header(skb) + offset);
 	}
 
 	skb_get_timestamp(skb, &stamp);
 
-	if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr,
-				  hao ? &hao->addr : &skb->nh.ipv6h->saddr,
+	if (!mip6_report_rl_allow(&stamp, &ipv6_hdr(skb)->daddr,
+				  hao ? &hao->addr : &ipv6_hdr(skb)->saddr,
 				  opt->iif))
 		goto out;
 
 	memset(&sel, 0, sizeof(sel));
-	memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr,
+	memcpy(&sel.daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
 	       sizeof(sel.daddr));
 	sel.prefixlen_d = 128;
-	memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr,
+	memcpy(&sel.saddr, (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
 	       sizeof(sel.saddr));
 	sel.prefixlen_s = 128;
 	sel.family = AF_INET6;
@@ -253,11 +257,13 @@ static int mip6_destopt_offset(struct xf
 			       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;
+	struct ipv6_opt_hdr *exthdr =
+				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
+	const unsigned char *nh = skb_network_header(skb);
+	unsigned int packet_len = skb->tail - skb->network_header;
 	int found_rhdr = 0;
 
-	*nexthdr = &skb->nh.ipv6h->nexthdr;
+	*nexthdr = &ipv6_hdr(skb)->nexthdr;
 
 	while (offset + 1 <= packet_len) {
 
@@ -288,7 +294,7 @@ static int mip6_destopt_offset(struct xf
 
 		offset += ipv6_optlen(exthdr);
 		*nexthdr = &exthdr->nexthdr;
-		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 	}
 
 	return offset;
@@ -361,10 +367,10 @@ static int mip6_rthdr_output(struct xfrm
 	iph = (struct ipv6hdr *)skb->data;
 	iph->payload_len = htons(skb->len - sizeof(*iph));
 
-	nexthdr = *skb->nh.raw;
-	*skb->nh.raw = IPPROTO_ROUTING;
+	nexthdr = *skb_network_header(skb);
+	*skb_network_header(skb) = IPPROTO_ROUTING;
 
-	rt2 = (struct rt2_hdr *)skb->h.raw;
+	rt2 = (struct rt2_hdr *)skb_transport_header(skb);
 	rt2->rt_hdr.nexthdr = nexthdr;
 	rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1;
 	rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2;
@@ -383,11 +389,13 @@ static int mip6_rthdr_offset(struct xfrm
 			     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;
+	struct ipv6_opt_hdr *exthdr =
+				   (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
+	const unsigned char *nh = skb_network_header(skb);
+	unsigned int packet_len = skb->tail - skb->network_header;
 	int found_rhdr = 0;
 
-	*nexthdr = &skb->nh.ipv6h->nexthdr;
+	*nexthdr = &ipv6_hdr(skb)->nexthdr;
 
 	while (offset + 1 <= packet_len) {
 
@@ -397,7 +405,7 @@ static int mip6_rthdr_offset(struct xfrm
 		case NEXTHDR_ROUTING:
 			if (offset + 3 <= packet_len) {
 				struct ipv6_rt_hdr *rt;
-				rt = (struct ipv6_rt_hdr *)(skb->nh.raw + offset);
+				rt = (struct ipv6_rt_hdr *)(nh + offset);
 				if (rt->type != 0)
 					return offset;
 			}
@@ -417,7 +425,7 @@ static int mip6_rthdr_offset(struct xfrm
 
 		offset += ipv6_optlen(exthdr);
 		*nexthdr = &exthdr->nexthdr;
-		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 	}
 
 	return offset;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 121f31c..d8b3645 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -319,6 +319,8 @@ int ndisc_mc_map(struct in6_addr *addr, 
 	return -EINVAL;
 }
 
+EXPORT_SYMBOL(ndisc_mc_map);
+
 static u32 ndisc_hash(const void *pkey, const struct net_device *dev)
 {
 	const u32 *p32 = pkey;
@@ -425,36 +427,23 @@ static inline void ndisc_flow_init(struc
 	security_sk_classify_flow(ndisc_socket->sk, fl);
 }
 
-static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
-		   struct in6_addr *daddr, struct in6_addr *solicited_addr,
-		   int router, int solicited, int override, int inc_opt)
+static void __ndisc_send(struct net_device *dev,
+			 struct neighbour *neigh,
+			 struct in6_addr *daddr, struct in6_addr *saddr,
+			 struct icmp6hdr *icmp6h, struct in6_addr *target,
+			 int llinfo, int icmp6_mib_outnd)
 {
-	struct in6_addr tmpaddr;
-	struct inet6_ifaddr *ifp;
-	struct inet6_dev *idev;
 	struct flowi fl;
-	struct dst_entry* dst;
+	struct dst_entry *dst;
 	struct sock *sk = ndisc_socket->sk;
-	struct in6_addr *src_addr;
-	struct nd_msg *msg;
-	int len;
 	struct sk_buff *skb;
+	struct icmp6hdr *hdr;
+	struct inet6_dev *idev;
+	int len;
 	int err;
+	u8 *opt;
 
-	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-
-	/* for anycast or proxy, solicited_addr != src_addr */
-	ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
-	if (ifp) {
-		src_addr = solicited_addr;
-		in6_ifa_put(ifp);
-	} else {
-		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
-			return;
-		src_addr = &tmpaddr;
-	}
-
-	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr,
+	ndisc_flow_init(&fl, icmp6h->icmp6_type, saddr, daddr,
 			dev->ifindex);
 
 	dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
@@ -465,60 +454,57 @@ static void ndisc_send_na(struct net_dev
 	if (err < 0)
 		return;
 
-	if (inc_opt) {
-		if (dev->addr_len)
-			len += ndisc_opt_addr_space(dev);
-		else
-			inc_opt = 0;
-	}
+	if (!dev->addr_len)
+		llinfo = 0;
+
+	len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
+	if (llinfo)
+		len += ndisc_opt_addr_space(dev);
 
 	skb = sock_alloc_send_skb(sk,
 				  (MAX_HEADER + sizeof(struct ipv6hdr) +
 				   len + LL_RESERVED_SPACE(dev)),
 				  1, &err);
-
-	if (skb == NULL) {
+	if (!skb) {
 		ND_PRINTK0(KERN_ERR
-			   "ICMPv6 NA: %s() failed to allocate an skb.\n",
+			   "ICMPv6 ND: %s() failed to allocate an skb.\n",
 			   __FUNCTION__);
 		dst_release(dst);
 		return;
 	}
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len);
-
-	msg = (struct nd_msg *)skb_put(skb, len);
-	skb->h.raw = (unsigned char*)msg;
+	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
 
-	msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
-	msg->icmph.icmp6_code = 0;
-	msg->icmph.icmp6_cksum = 0;
+	skb->transport_header = skb->tail;
+	skb_put(skb, len);
 
-	msg->icmph.icmp6_unused = 0;
-	msg->icmph.icmp6_router    = router;
-	msg->icmph.icmp6_solicited = solicited;
-	msg->icmph.icmp6_override  = override;
+	hdr = (struct icmp6hdr *)skb_transport_header(skb);
+	memcpy(hdr, icmp6h, sizeof(*hdr));
 
-	/* Set the target address. */
-	ipv6_addr_copy(&msg->target, solicited_addr);
+	opt = skb_transport_header(skb) + sizeof(struct icmp6hdr);
+	if (target) {
+		ipv6_addr_copy((struct in6_addr *)opt, target);
+		opt += sizeof(*target);
+	}
 
-	if (inc_opt)
-		ndisc_fill_addr_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr,
+	if (llinfo)
+		ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
 				       dev->addr_len, dev->type);
 
-	/* checksum */
-	msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len,
-						 IPPROTO_ICMPV6,
-						 csum_partial((__u8 *) msg,
-							      len, 0));
+	hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
+					   IPPROTO_ICMPV6,
+					   csum_partial((__u8 *) hdr,
+							len, 0));
 
 	skb->dst = dst;
+
 	idev = in6_dev_get(dst->dev);
 	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
+
 	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
 	if (!err) {
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS);
+		ICMP6_INC_STATS(idev, icmp6_mib_outnd);
 		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
 	}
 
@@ -526,165 +512,95 @@ static void ndisc_send_na(struct net_dev
 		in6_dev_put(idev);
 }
 
+static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
+		   struct in6_addr *daddr, struct in6_addr *solicited_addr,
+		   int router, int solicited, int override, int inc_opt)
+{
+	struct in6_addr tmpaddr;
+	struct inet6_ifaddr *ifp;
+	struct in6_addr *src_addr;
+	struct icmp6hdr icmp6h = {
+		.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
+	};
+
+	/* for anycast or proxy, solicited_addr != src_addr */
+	ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
+	if (ifp) {
+		src_addr = solicited_addr;
+		if (ifp->flags & IFA_F_OPTIMISTIC)
+			override = 0;
+		in6_ifa_put(ifp);
+	} else {
+		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
+			return;
+		src_addr = &tmpaddr;
+	}
+
+	icmp6h.icmp6_router = router;
+	icmp6h.icmp6_solicited = solicited;
+	icmp6h.icmp6_override = override;
+
+	__ndisc_send(dev, neigh, daddr, src_addr,
+		     &icmp6h, solicited_addr,
+		     inc_opt ? ND_OPT_TARGET_LL_ADDR : 0,
+		     ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS);
+}
+
 void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
 		   struct in6_addr *solicit,
 		   struct in6_addr *daddr, struct in6_addr *saddr)
 {
-	struct flowi fl;
-	struct dst_entry* dst;
-	struct inet6_dev *idev;
-	struct sock *sk = ndisc_socket->sk;
-	struct sk_buff *skb;
-	struct nd_msg *msg;
 	struct in6_addr addr_buf;
-	int len;
-	int err;
-	int send_llinfo;
+	struct icmp6hdr icmp6h = {
+		.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
+	};
 
 	if (saddr == NULL) {
-		if (ipv6_get_lladdr(dev, &addr_buf))
+		if (ipv6_get_lladdr(dev, &addr_buf,
+				   (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
 			return;
 		saddr = &addr_buf;
 	}
 
-	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr,
-			dev->ifindex);
-
-	dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
-	if (!dst)
-		return;
-
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0)
-		return;
-
-	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-	send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
-	if (send_llinfo)
-		len += ndisc_opt_addr_space(dev);
-
-	skb = sock_alloc_send_skb(sk,
-				  (MAX_HEADER + sizeof(struct ipv6hdr) +
-				   len + LL_RESERVED_SPACE(dev)),
-				  1, &err);
-	if (skb == NULL) {
-		ND_PRINTK0(KERN_ERR
-			   "ICMPv6 NA: %s() failed to allocate an skb.\n",
-			   __FUNCTION__);
-		dst_release(dst);
-		return;
-	}
-
-	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
-
-	msg = (struct nd_msg *)skb_put(skb, len);
-	skb->h.raw = (unsigned char*)msg;
-	msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
-	msg->icmph.icmp6_code = 0;
-	msg->icmph.icmp6_cksum = 0;
-	msg->icmph.icmp6_unused = 0;
-
-	/* Set the target address. */
-	ipv6_addr_copy(&msg->target, solicit);
-
-	if (send_llinfo)
-		ndisc_fill_addr_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
-				       dev->addr_len, dev->type);
-
-	/* checksum */
-	msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-						 daddr, len,
-						 IPPROTO_ICMPV6,
-						 csum_partial((__u8 *) msg,
-							      len, 0));
-	/* send it! */
-	skb->dst = dst;
-	idev = in6_dev_get(dst->dev);
-	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
-	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
-	if (!err) {
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
-	}
-
-	if (likely(idev != NULL))
-		in6_dev_put(idev);
+	__ndisc_send(dev, neigh, daddr, saddr,
+		     &icmp6h, solicit,
+		     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0,
+		     ICMP6_MIB_OUTNEIGHBORSOLICITS);
 }
 
 void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
 		   struct in6_addr *daddr)
 {
-	struct flowi fl;
-	struct dst_entry* dst;
-	struct inet6_dev *idev;
-	struct sock *sk = ndisc_socket->sk;
-	struct sk_buff *skb;
-	struct icmp6hdr *hdr;
-	__u8 * opt;
-	int len;
-	int err;
-
-	ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr,
-			dev->ifindex);
-
-	dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output);
-	if (!dst)
-		return;
-
-	err = xfrm_lookup(&dst, &fl, NULL, 0);
-	if (err < 0)
-		return;
-
-	len = sizeof(struct icmp6hdr);
-	if (dev->addr_len)
-		len += ndisc_opt_addr_space(dev);
-
-	skb = sock_alloc_send_skb(sk,
-				  (MAX_HEADER + sizeof(struct ipv6hdr) +
-				   len + LL_RESERVED_SPACE(dev)),
-				  1, &err);
-	if (skb == NULL) {
-		ND_PRINTK0(KERN_ERR
-			   "ICMPv6 RS: %s() failed to allocate an skb.\n",
-			   __FUNCTION__);
-		dst_release(dst);
-		return;
-	}
-
-	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
-
-	hdr = (struct icmp6hdr *)skb_put(skb, len);
-	skb->h.raw = (unsigned char*)hdr;
-	hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
-	hdr->icmp6_code = 0;
-	hdr->icmp6_cksum = 0;
-	hdr->icmp6_unused = 0;
-
-	opt = (u8*) (hdr + 1);
-
-	if (dev->addr_len)
-		ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
-				       dev->addr_len, dev->type);
-
-	/* checksum */
-	hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
-					   IPPROTO_ICMPV6,
-					   csum_partial((__u8 *) hdr, len, 0));
+	struct icmp6hdr icmp6h = {
+		.icmp6_type = NDISC_ROUTER_SOLICITATION,
+	};
+	int send_sllao = dev->addr_len;
 
-	/* send it! */
-	skb->dst = dst;
-	idev = in6_dev_get(dst->dev);
-	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
-	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
-	if (!err) {
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS);
-		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+	/*
+	 * According to section 2.2 of RFC 4429, we must not
+	 * send router solicitations with a sllao from
+	 * optimistic addresses, but we may send the solicitation
+	 * if we don't include the sllao.  So here we check
+	 * if our address is optimistic, and if so, we
+	 * supress the inclusion of the sllao.
+	 */
+	if (send_sllao) {
+		struct inet6_ifaddr *ifp = ipv6_get_ifaddr(saddr, dev, 1);
+		if (ifp) {
+			if (ifp->flags & IFA_F_OPTIMISTIC)  {
+				send_sllao = 0;
+			}
+			in6_ifa_put(ifp);
+		} else {
+			send_sllao = 0;
+		}
 	}
-
-	if (likely(idev != NULL))
-		in6_dev_put(idev);
+#endif
+	__ndisc_send(dev, NULL, daddr, saddr,
+		     &icmp6h, NULL,
+		     send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0,
+		     ICMP6_MIB_OUTROUTERSOLICITS);
 }
 
 
@@ -708,8 +624,8 @@ static void ndisc_solicit(struct neighbo
 	struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 
-	if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1))
-		saddr = &skb->nh.ipv6h->saddr;
+	if (skb && ipv6_chk_addr(&ipv6_hdr(skb)->saddr, dev, 1))
+		saddr = &ipv6_hdr(skb)->saddr;
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
 		if (!(neigh->nud_state & NUD_VALID)) {
@@ -732,11 +648,12 @@ #endif
 
 static void ndisc_recv_ns(struct sk_buff *skb)
 {
-	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
+	struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+	struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
 	u8 *lladdr = NULL;
-	u32 ndoptlen = skb->tail - msg->opt;
+	u32 ndoptlen = skb->tail - (skb->transport_header +
+				    offsetof(struct nd_msg, opt));
 	struct ndisc_options ndopts;
 	struct net_device *dev = skb->dev;
 	struct inet6_ifaddr *ifp;
@@ -796,28 +713,40 @@ static void ndisc_recv_ns(struct sk_buff
 	inc = ipv6_addr_is_multicast(daddr);
 
 	if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
-		if (ifp->flags & IFA_F_TENTATIVE) {
-			/* Address is tentative. If the source
-			   is unspecified address, it is someone
-			   does DAD, otherwise we ignore solicitations
-			   until DAD timer expires.
-			 */
-			if (!dad)
+
+		if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
+			if (dad) {
+				if (dev->type == ARPHRD_IEEE802_TR) {
+					const unsigned char *sadr;
+					sadr = skb_mac_header(skb);
+					if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
+					    sadr[9] == dev->dev_addr[1] &&
+					    sadr[10] == dev->dev_addr[2] &&
+					    sadr[11] == dev->dev_addr[3] &&
+					    sadr[12] == dev->dev_addr[4] &&
+					    sadr[13] == dev->dev_addr[5]) {
+						/* looped-back to us */
+						goto out;
+					}
+				}
+
+				/*
+				 * We are colliding with another node
+				 * who is doing DAD
+				 * so fail our DAD process
+				 */
+				addrconf_dad_failure(ifp);
 				goto out;
-			if (dev->type == ARPHRD_IEEE802_TR) {
-				unsigned char *sadr = skb->mac.raw;
-				if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
-				    sadr[9] == dev->dev_addr[1] &&
-				    sadr[10] == dev->dev_addr[2] &&
-				    sadr[11] == dev->dev_addr[3] &&
-				    sadr[12] == dev->dev_addr[4] &&
-				    sadr[13] == dev->dev_addr[5]) {
-					/* looped-back to us */
+			} else {
+				/*
+				 * This is not a dad solicitation.
+				 * If we are an optimistic node,
+				 * we should respond.
+				 * Otherwise, we should ignore it.
+				 */
+				if (!(ifp->flags & IFA_F_OPTIMISTIC))
 					goto out;
-				}
 			}
-			addrconf_dad_failure(ifp);
-			return;
 		}
 
 		idev = ifp->idev;
@@ -898,11 +827,12 @@ out:
 
 static void ndisc_recv_na(struct sk_buff *skb)
 {
-	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
+	struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+	struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
 	u8 *lladdr = NULL;
-	u32 ndoptlen = skb->tail - msg->opt;
+	u32 ndoptlen = skb->tail - (skb->transport_header +
+				    offsetof(struct nd_msg, opt));
 	struct ndisc_options ndopts;
 	struct net_device *dev = skb->dev;
 	struct inet6_ifaddr *ifp;
@@ -1000,11 +930,11 @@ out:
 
 static void ndisc_recv_rs(struct sk_buff *skb)
 {
-	struct rs_msg *rs_msg = (struct rs_msg *) skb->h.raw;
+	struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb);
 	unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
 	struct neighbour *neigh;
 	struct inet6_dev *idev;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+	struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
 	struct ndisc_options ndopts;
 	u8 *lladdr = NULL;
 
@@ -1057,7 +987,7 @@ out:
 
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
-	struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
+	struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
 	struct neighbour *neigh = NULL;
 	struct inet6_dev *in6_dev;
 	struct rt6_info *rt = NULL;
@@ -1068,9 +998,9 @@ static void ndisc_router_discovery(struc
 
 	__u8 * opt = (__u8 *)(ra_msg + 1);
 
-	optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);
+	optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg);
 
-	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
 		ND_PRINTK2(KERN_WARNING
 			   "ICMPv6 RA: source address is not link-local.\n");
 		return;
@@ -1136,7 +1066,7 @@ #ifdef CONFIG_IPV6_ROUTER_PREF
 		pref = ICMPV6_ROUTER_PREF_MEDIUM;
 #endif
 
-	rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+	rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev);
 
 	if (rt)
 		neigh = rt->rt6i_nexthop;
@@ -1151,7 +1081,7 @@ #endif
 		ND_PRINTK3(KERN_DEBUG
 			   "ICMPv6 RA: adding default router.\n");
 
-		rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
+		rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref);
 		if (rt == NULL) {
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1223,7 +1153,7 @@ skip_defrtr:
 	 */
 
 	if (!neigh)
-		neigh = __neigh_lookup(&nd_tbl, &skb->nh.ipv6h->saddr,
+		neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr,
 				       skb->dev, 1);
 	if (neigh) {
 		u8 *lladdr = NULL;
@@ -1252,7 +1182,7 @@ #ifdef CONFIG_IPV6_ROUTE_INFO
 			if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
 				continue;
 			rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
-				      &skb->nh.ipv6h->saddr);
+				      &ipv6_hdr(skb)->saddr);
 		}
 	}
 #endif
@@ -1311,13 +1241,13 @@ static void ndisc_redirect_rcv(struct sk
 	int optlen;
 	u8 *lladdr = NULL;
 
-	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
 		ND_PRINTK2(KERN_WARNING
 			   "ICMPv6 Redirect: source address is not link-local.\n");
 		return;
 	}
 
-	optlen = skb->tail - skb->h.raw;
+	optlen = skb->tail - skb->transport_header;
 	optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
 
 	if (optlen < 0) {
@@ -1326,7 +1256,7 @@ static void ndisc_redirect_rcv(struct sk
 		return;
 	}
 
-	icmph = (struct icmp6hdr *) skb->h.raw;
+	icmph = icmp6_hdr(skb);
 	target = (struct in6_addr *) (icmph + 1);
 	dest = target + 1;
 
@@ -1376,8 +1306,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->daddr,
-			     &skb->nh.ipv6h->saddr, neigh, lladdr,
+		rt6_redirect(dest, &ipv6_hdr(skb)->daddr,
+			     &ipv6_hdr(skb)->saddr, neigh, lladdr,
 			     on_link);
 		neigh_release(neigh);
 	}
@@ -1406,21 +1336,21 @@ void ndisc_send_redirect(struct sk_buff 
 
 	dev = skb->dev;
 
-	if (ipv6_get_lladdr(dev, &saddr_buf)) {
+	if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
 		ND_PRINTK2(KERN_WARNING
 			   "ICMPv6 Redirect: no link-local address on %s\n",
 			   dev->name);
 		return;
 	}
 
-	if (!ipv6_addr_equal(&skb->nh.ipv6h->daddr, target) &&
+	if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) &&
 	    !(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
 		ND_PRINTK2(KERN_WARNING
 			"ICMPv6 Redirect: target address is not link-local.\n");
 		return;
 	}
 
-	ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr,
+	ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr,
 			dev->ifindex);
 
 	dst = ip6_route_output(NULL, &fl);
@@ -1475,11 +1405,12 @@ void ndisc_send_redirect(struct sk_buff 
 	hlen = 0;
 
 	skb_reserve(buff, LL_RESERVED_SPACE(dev));
-	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr,
+	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
 		   IPPROTO_ICMPV6, len);
 
-	icmph = (struct icmp6hdr *)skb_put(buff, len);
-	buff->h.raw = (unsigned char*)icmph;
+	skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
+	skb_put(buff, len);
+	icmph = icmp6_hdr(buff);
 
 	memset(icmph, 0, sizeof(struct icmp6hdr));
 	icmph->icmp6_type = NDISC_REDIRECT;
@@ -1491,7 +1422,7 @@ void ndisc_send_redirect(struct sk_buff 
 	addrp = (struct in6_addr *)(icmph + 1);
 	ipv6_addr_copy(addrp, target);
 	addrp++;
-	ipv6_addr_copy(addrp, &skb->nh.ipv6h->daddr);
+	ipv6_addr_copy(addrp, &ipv6_hdr(skb)->daddr);
 
 	opt = (u8*) (addrp + 1);
 
@@ -1512,9 +1443,9 @@ void ndisc_send_redirect(struct sk_buff 
 	*(opt++) = (rd_len >> 3);
 	opt += 6;
 
-	memcpy(opt, skb->nh.ipv6h, rd_len - 8);
+	memcpy(opt, ipv6_hdr(skb), rd_len - 8);
 
-	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &skb->nh.ipv6h->saddr,
+	icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
 					     len, IPPROTO_ICMPV6,
 					     csum_partial((u8 *) icmph, len, 0));
 
@@ -1544,14 +1475,14 @@ int ndisc_rcv(struct sk_buff *skb)
 	if (!pskb_may_pull(skb, skb->len))
 		return 0;
 
-	msg = (struct nd_msg *) skb->h.raw;
+	msg = (struct nd_msg *)skb_transport_header(skb);
 
-	__skb_push(skb, skb->data-skb->h.raw);
+	__skb_push(skb, skb->data - skb_transport_header(skb));
 
-	if (skb->nh.ipv6h->hop_limit != 255) {
+	if (ipv6_hdr(skb)->hop_limit != 255) {
 		ND_PRINTK2(KERN_WARNING
 			   "ICMPv6 NDISC: invalid hop-limit: %d\n",
-			   skb->nh.ipv6h->hop_limit);
+			   ipv6_hdr(skb)->hop_limit);
 		return 0;
 	}
 
@@ -1584,7 +1515,7 @@ int ndisc_rcv(struct sk_buff *skb)
 	case NDISC_REDIRECT:
 		ndisc_redirect_rcv(skb);
 		break;
-	};
+	}
 
 	return 0;
 }
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 1c405dd..38b1496 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -11,7 +11,7 @@ #include <net/ip6_checksum.h>
 
 int ip6_route_me_harder(struct sk_buff *skb)
 {
-	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
 	struct dst_entry *dst;
 	struct flowi fl = {
 		.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
@@ -61,7 +61,7 @@ static void nf_ip6_saveroute(const struc
 	struct ip6_rt_info *rt_info = nf_info_reroute(info);
 
 	if (info->hook == NF_IP6_LOCAL_OUT) {
-		struct ipv6hdr *iph = skb->nh.ipv6h;
+		struct ipv6hdr *iph = ipv6_hdr(skb);
 
 		rt_info->daddr = iph->daddr;
 		rt_info->saddr = iph->saddr;
@@ -73,7 +73,7 @@ static int nf_ip6_reroute(struct sk_buff
 	struct ip6_rt_info *rt_info = nf_info_reroute(info);
 
 	if (info->hook == NF_IP6_LOCAL_OUT) {
-		struct ipv6hdr *iph = (*pskb)->nh.ipv6h;
+		struct ipv6hdr *iph = ipv6_hdr(*pskb);
 		if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
 		    !ipv6_addr_equal(&iph->saddr, &rt_info->saddr))
 			return ip6_route_me_harder(*pskb);
@@ -84,7 +84,7 @@ static int nf_ip6_reroute(struct sk_buff
 __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
 			     unsigned int dataoff, u_int8_t protocol)
 {
-	struct ipv6hdr *ip6h = skb->nh.ipv6h;
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
 	__sum16 csum = 0;
 
 	switch (skb->ip_summed) {
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index da07e9a..bbe99f8 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -198,7 +198,7 @@ config IP6_NF_RAW
 	  and OUTPUT chains.
 	
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 endmenu
 
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index fdb30a5..0004db3 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -11,18 +11,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.
- *
- * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
- *             to adapt it to IPv6
- *             HEAVILY based in ipqueue.c by James Morris. It's just
- *             a little modified version of it, so he's nearly the
- *             real coder of this.
- *             Few changes needed, mainly the hard_routing code and
- *             the netlink socket protocol (we're NETLINK_IP6_FW).
- * 2002-06-25: Code cleanup. [JM: ported cleanup over from ip_queue.c]
- * 2005-02-04: Added /proc counter for dropped packets; fixed so
- *             packets aren't delivered to user space if they're going
- *             to be dropped.
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -189,12 +177,13 @@ ipq_flush(int verdict)
 static struct sk_buff *
 ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
 {
-	unsigned char *old_tail;
+	sk_buff_data_t old_tail;
 	size_t size = 0;
 	size_t data_len = 0;
 	struct sk_buff *skb;
 	struct ipq_packet_msg *pmsg;
 	struct nlmsghdr *nlh;
+	struct timeval tv;
 
 	read_lock_bh(&queue_lock);
 
@@ -232,15 +221,16 @@ ipq_build_packet_message(struct ipq_queu
 	if (!skb)
 		goto nlmsg_failure;
 
-	old_tail= skb->tail;
+	old_tail = skb->tail;
 	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
 	pmsg = NLMSG_DATA(nlh);
 	memset(pmsg, 0, sizeof(*pmsg));
 
 	pmsg->packet_id       = (unsigned long )entry;
 	pmsg->data_len        = data_len;
-	pmsg->timestamp_sec   = entry->skb->tstamp.off_sec;
-	pmsg->timestamp_usec  = entry->skb->tstamp.off_usec;
+	tv = ktime_to_timeval(entry->skb->tstamp);
+	pmsg->timestamp_sec   = tv.tv_sec;
+	pmsg->timestamp_usec  = tv.tv_usec;
 	pmsg->mark            = entry->skb->mark;
 	pmsg->hook            = entry->info->hook;
 	pmsg->hw_protocol     = entry->skb->protocol;
@@ -376,7 +366,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, st
 	}
 	if (!skb_make_writable(&e->skb, v->data_len))
 		return -ENOMEM;
-	memcpy(e->skb->data, v->payload, v->data_len);
+	skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
 	e->skb->ip_summed = CHECKSUM_NONE;
 
 	return 0;
@@ -485,7 +475,7 @@ ipq_rcv_skb(struct sk_buff *skb)
 	if (skblen < sizeof(*nlh))
 		return;
 
-	nlh = (struct nlmsghdr *)skb->data;
+	nlh = nlmsg_hdr(skb);
 	nlmsglen = nlh->nlmsg_len;
 	if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
 		return;
@@ -667,7 +657,7 @@ static int __init ip6_queue_init(void)
 	struct proc_dir_entry *proc;
 
 	netlink_register_notifier(&ipq_nl_notifier);
-	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk,
+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk, NULL,
 				      THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 7c512e1..9aa6240 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -7,15 +7,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.
- *
- * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
- * 	- increase module usage count as soon as we have rules inside
- * 	  a table
- * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
- *      - new extension header parser code
- * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
- * 	- Unification of {ip,ip6}_tables into x_tables
- * 	- Removed tcp and udp code, since it's not ipv6 specific
  */
 
 #include <linux/capability.h>
@@ -115,7 +106,7 @@ ip6_packet_match(const struct sk_buff *s
 {
 	size_t i;
 	unsigned long ret;
-	const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
+	const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
 
 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
 
@@ -301,7 +292,7 @@ ip6t_do_table(struct sk_buff **pskb,
 				goto no_match;
 
 			ADD_COUNTER(e->counters,
-				    ntohs((*pskb)->nh.ipv6h->payload_len)
+				    ntohs(ipv6_hdr(*pskb)->payload_len)
 				    + IPV6_HDR_LEN,
 				    1);
 
@@ -1448,8 +1439,8 @@ static void __exit ip6_tables_fini(void)
 int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
 		  int target, unsigned short *fragoff)
 {
-	unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
+	unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
+	u8 nexthdr = ipv6_hdr(skb)->nexthdr;
 	unsigned int len = skb->len - start;
 
 	if (fragoff)
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index ccbab66..4115a57 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -32,7 +32,7 @@ static unsigned int ip6t_hl_target(struc
 	if (!skb_make_writable(pskb, (*pskb)->len))
 		return NF_DROP;
 
-	ip6h = (*pskb)->nh.ipv6h;
+	ip6h = ipv6_hdr(*pskb);
 
 	switch (info->mode) {
 		case IP6T_HL_SET:
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index afaa039..5bb9cd3 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -396,8 +396,8 @@ ip6t_log_packet(unsigned int pf,
 		/* MAC logging for input chain only. */
 		printk("MAC=");
 		if (skb->dev && (len = skb->dev->hard_header_len) &&
-		    skb->mac.raw != skb->nh.raw) {
-			unsigned char *p = skb->mac.raw;
+		    skb->mac_header != skb->network_header) {
+			const unsigned char *p = skb_mac_header(skb);
 			int i;
 
 			if (skb->dev->type == ARPHRD_SIT &&
@@ -412,7 +412,8 @@ ip6t_log_packet(unsigned int pf,
 			printk(" ");
 
 			if (skb->dev->type == ARPHRD_SIT) {
-				struct iphdr *iph = (struct iphdr *)skb->mac.raw;
+				const struct iphdr *iph =
+					(struct iphdr *)skb_mac_header(skb);
 				printk("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ",
 				       NIPQUAD(iph->saddr),
 				       NIPQUAD(iph->daddr));
@@ -421,7 +422,7 @@ ip6t_log_packet(unsigned int pf,
 			printk(" ");
 	}
 
-	dump_packet(loginfo, skb, (u8*)skb->nh.ipv6h - skb->data, 1);
+	dump_packet(loginfo, skb, skb_network_offset(skb), 1);
 	printk("\n");
 	spin_unlock_bh(&log_lock);
 }
@@ -489,14 +490,10 @@ static int __init ip6t_log_init(void)
 	ret = xt_register_target(&ip6t_log_reg);
 	if (ret < 0)
 		return ret;
-	if (nf_log_register(PF_INET6, &ip6t_logger) < 0) {
-		printk(KERN_WARNING "ip6t_LOG: not logging via system console "
-		       "since somebody else already registered for PF_INET6\n");
-		/* we cannot make module load fail here, since otherwise
-		 * ip6tables userspace would abort */
-	}
-
-	return 0;
+	ret = nf_log_register(PF_INET6, &ip6t_logger);
+	if (ret < 0 && ret != -EEXIST)
+		xt_unregister_target(&ip6t_log_reg);
+	return ret;
 }
 
 static void __exit ip6t_log_fini(void)
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 6abee94..cb3d241 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -47,7 +47,7 @@ static void send_reset(struct sk_buff *o
 	struct tcphdr otcph, *tcph;
 	unsigned int otcplen, hh_len;
 	int tcphoff, needs_ack;
-	struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
+	struct ipv6hdr *oip6h = ipv6_hdr(oldskb), *ip6h;
 	struct dst_entry *dst = NULL;
 	u8 proto;
 	struct flowi fl;
@@ -120,8 +120,9 @@ static void send_reset(struct sk_buff *o
 
 	skb_reserve(nskb, hh_len + dst->header_len);
 
-	ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
-					skb_put(nskb, sizeof(struct ipv6hdr));
+	skb_put(nskb, sizeof(struct ipv6hdr));
+	skb_reset_network_header(nskb);
+	ip6h = ipv6_hdr(nskb);
 	ip6h->version = 6;
 	ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
 	ip6h->nexthdr = IPPROTO_TCP;
@@ -155,8 +156,8 @@ static void send_reset(struct sk_buff *o
 	tcph->check = 0;
 
 	/* Adjust TCP checksum */
-	tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
-				      &nskb->nh.ipv6h->daddr,
+	tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
+				      &ipv6_hdr(nskb)->daddr,
 				      sizeof(struct tcphdr), IPPROTO_TCP,
 				      csum_partial((char *)tcph,
 						   sizeof(struct tcphdr), 0));
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 967bed7..0f3dd93 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -32,8 +32,8 @@ match(const struct sk_buff *skb,
 	unsigned char eui64[8];
 	int i = 0;
 
-	if (!(skb->mac.raw >= skb->head &&
-	      (skb->mac.raw + ETH_HLEN) <= skb->data) &&
+	if (!(skb_mac_header(skb) >= skb->head &&
+	      (skb_mac_header(skb) + ETH_HLEN) <= skb->data) &&
 	    offset != 0) {
 		*hotdrop = 1;
 		return 0;
@@ -42,7 +42,7 @@ match(const struct sk_buff *skb,
 	memset(eui64, 0, sizeof(eui64));
 
 	if (eth_hdr(skb)->h_proto == htons(ETH_P_IPV6)) {
-		if (skb->nh.ipv6h->version == 0x6) {
+		if (ipv6_hdr(skb)->version == 0x6) {
 			memcpy(eui64, eth_hdr(skb)->h_source, 3);
 			memcpy(eui64 + 5, eth_hdr(skb)->h_source + 3, 3);
 			eui64[3] = 0xff;
@@ -50,7 +50,7 @@ match(const struct sk_buff *skb,
 			eui64[0] |= 0x02;
 
 			i = 0;
-			while ((skb->nh.ipv6h->saddr.s6_addr[8+i] == eui64[i])
+			while ((ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i])
 			       && (i < 8))
 				i++;
 
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index 37c8a4d..d606c0e 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -25,7 +25,7 @@ static int match(const struct sk_buff *s
 		 int offset, unsigned int protoff, int *hotdrop)
 {
 	const struct ip6t_hl_info *info = matchinfo;
-	const struct ipv6hdr *ip6h = skb->nh.ipv6h;
+	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
 
 	switch (info->mode) {
 		case IP6T_HL_EQ:
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 700a11d..fd6a086 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -45,7 +45,7 @@ ipv6header_match(const struct sk_buff *s
 	/* Make sure this isn't an evil packet */
 
 	/* type of the 1st exthdr */
-	nexthdr = skb->nh.ipv6h->nexthdr;
+	nexthdr = ipv6_hdr(skb)->nexthdr;
 	/* pointer to the 1st exthdr */
 	ptr = sizeof(struct ipv6hdr);
 	/* available length */
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 112a21d..76f0cf6 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -102,7 +102,7 @@ ip6t_local_out_hook(unsigned int hook,
 #if 0
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
 			printk("ip6t_hook: happy cracking.\n");
 		return NF_ACCEPT;
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 0c468d3..a9f10e3 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -7,8 +7,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.
- *
- * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
@@ -138,7 +136,7 @@ ip6t_local_hook(unsigned int hook,
 #if 0
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
-	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+	    || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
 		if (net_ratelimit())
 			printk("ip6t_hook: happy cracking.\n");
 		return NF_ACCEPT;
@@ -146,21 +144,21 @@ #if 0
 #endif
 
 	/* save source/dest address, mark, hoplimit, flowlabel, priority,  */
-	memcpy(&saddr, &(*pskb)->nh.ipv6h->saddr, sizeof(saddr));
-	memcpy(&daddr, &(*pskb)->nh.ipv6h->daddr, sizeof(daddr));
+	memcpy(&saddr, &ipv6_hdr(*pskb)->saddr, sizeof(saddr));
+	memcpy(&daddr, &ipv6_hdr(*pskb)->daddr, sizeof(daddr));
 	mark = (*pskb)->mark;
-	hop_limit = (*pskb)->nh.ipv6h->hop_limit;
+	hop_limit = ipv6_hdr(*pskb)->hop_limit;
 
 	/* flowlabel and prio (includes version, which shouldn't change either */
-	flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
+	flowlabel = *((u_int32_t *)ipv6_hdr(*pskb));
 
 	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))
+		&& (memcmp(&ipv6_hdr(*pskb)->saddr, &saddr, sizeof(saddr))
+		    || memcmp(&ipv6_hdr(*pskb)->daddr, &daddr, sizeof(daddr))
 		    || (*pskb)->mark != mark
-		    || (*pskb)->nh.ipv6h->hop_limit != hop_limit))
+		    || ipv6_hdr(*pskb)->hop_limit != hop_limit))
 		return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP;
 
 	return ret;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index d110245..6d2a082 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -7,17 +7,6 @@
  *
  * Author:
  *	Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- support Layer 3 protocol independent connection tracking.
- *	  Based on the original ip_conntrack code which	had the following
- *	  copyright information:
- *		(C) 1999-2001 Paul `Rusty' Russell
- *		(C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
- *
- * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- add get_features() to support various size of conntrack
- *	  structures.
  */
 
 #include <linux/types.h>
@@ -138,16 +127,10 @@ static int
 ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
 	     u_int8_t *protonum)
 {
-	unsigned int extoff;
-	unsigned char pnum;
-	int protoff;
-
-	extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data;
-	pnum = (*pskb)->nh.ipv6h->nexthdr;
-
-	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
-					 (*pskb)->len - extoff);
-
+	unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
+	unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;
+	int protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
+					     (*pskb)->len - extoff);
 	/*
 	 * (protoff == (*pskb)->len) mean that the packet doesn't have no data
 	 * except of IPv6 & ext headers. but it's tracked anyway. - YK
@@ -179,9 +162,8 @@ static unsigned int ipv6_confirm(unsigne
 	struct nf_conn_help *help;
 	enum ip_conntrack_info ctinfo;
 	unsigned int ret, protoff;
-	unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
-			      - (*pskb)->data;
-	unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
+	unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
+	unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;
 
 
 	/* This is where we call the helper: as the packet goes out. */
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 075da4f..0be790d 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -7,13 +7,6 @@
  *
  * Author:
  *	Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- ICMPv6 tracking support. Derived from the original ip_conntrack code
- *	  net/ipv4/netfilter/ip_conntrack_proto_icmp.c which had the following
- *	  copyright information:
- *		(C) 1999-2001 Paul `Rusty' Russell
- *		(C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  */
 
 #include <linux/types.h>
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 15ab1e3..347ab76 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -82,7 +82,7 @@ struct nf_ct_frag6_queue
 	struct sk_buff		*fragments;
 	int			len;
 	int			meat;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -353,9 +353,7 @@ nf_ct_frag6_create(unsigned int hash, __
 	ipv6_addr_copy(&fq->saddr, src);
 	ipv6_addr_copy(&fq->daddr, dst);
 
-	init_timer(&fq->timer);
-	fq->timer.function = nf_ct_frag6_expire;
-	fq->timer.data = (long) fq;
+	setup_timer(&fq->timer, nf_ct_frag6_expire, (unsigned long)fq);
 	spin_lock_init(&fq->lock);
 	atomic_set(&fq->refcnt, 1);
 
@@ -400,19 +398,20 @@ static int nf_ct_frag6_queue(struct nf_c
 	}
 
 	offset = ntohs(fhdr->frag_off) & ~0x7;
-	end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
-			((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
+			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
 		DEBUGP("offset is too large.\n");
 		return -1;
 	}
 
-	if (skb->ip_summed == CHECKSUM_COMPLETE)
+	if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		const unsigned char *nh = skb_network_header(skb);
 		skb->csum = csum_sub(skb->csum,
-				     csum_partial(skb->nh.raw,
-						  (u8*)(fhdr + 1) - skb->nh.raw,
+				     csum_partial(nh, (u8 *)(fhdr + 1) - nh,
 						  0));
+	}
 
 	/* Is this the final fragment? */
 	if (!(fhdr->frag_off & htons(IP6_MF))) {
@@ -542,7 +541,7 @@ static int nf_ct_frag6_queue(struct nf_c
 		fq->fragments = skb;
 
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
@@ -583,7 +582,9 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 	BUG_TRAP(NFCT_FRAG6_CB(head)->offset == 0);
 
 	/* Unfragmented part is taken from the first segment. */
-	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);
+	payload_len = ((head->data - skb_network_header(head)) -
+		       sizeof(struct ipv6hdr) + fq->len -
+		       sizeof(struct frag_hdr));
 	if (payload_len > IPV6_MAXPLEN) {
 		DEBUGP("payload len is too large.\n");
 		goto out_oversize;
@@ -624,15 +625,15 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	/* We have to remove fragment header from datagram and to relocate
 	 * header in order to calculate ICV correctly. */
-	head->nh.raw[fq->nhoffset] = head->h.raw[0];
+	skb_network_header(head)[fq->nhoffset] = skb_transport_header(head)[0];
 	memmove(head->head + sizeof(struct frag_hdr), head->head,
 		(head->data - head->head) - sizeof(struct frag_hdr));
-	head->mac.raw += sizeof(struct frag_hdr);
-	head->nh.raw += sizeof(struct frag_hdr);
+	head->mac_header += sizeof(struct frag_hdr);
+	head->network_header += sizeof(struct frag_hdr);
 
 	skb_shinfo(head)->frag_list = head->next;
-	head->h.raw = head->data;
-	skb_push(head, head->data - head->nh.raw);
+	skb_reset_transport_header(head);
+	skb_push(head, head->data - skb_network_header(head));
 	atomic_sub(head->truesize, &nf_ct_frag6_mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
@@ -648,12 +649,14 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_que
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
-	head->nh.ipv6h->payload_len = htons(payload_len);
+	head->tstamp = fq->stamp;
+	ipv6_hdr(head)->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
-		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+		head->csum = csum_partial(skb_network_header(head),
+					  skb_network_header_len(head),
+					  head->csum);
 
 	fq->fragments = NULL;
 
@@ -701,9 +704,10 @@ out_fail:
 static int
 find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
 {
-	u8 nexthdr = skb->nh.ipv6h->nexthdr;
-	u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
-	int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
+	u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+	const int netoff = skb_network_offset(skb);
+	u8 prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
+	int start = netoff + sizeof(struct ipv6hdr);
 	int len = skb->len - start;
 	u8 prevhdr = NEXTHDR_IPV6;
 
@@ -759,7 +763,7 @@ struct sk_buff *nf_ct_frag6_gather(struc
 	struct sk_buff *ret_skb = NULL;
 
 	/* Jumbo payload inhibits frag. header */
-	if (skb->nh.ipv6h->payload_len == 0) {
+	if (ipv6_hdr(skb)->payload_len == 0) {
 		DEBUGP("payload len = 0\n");
 		return skb;
 	}
@@ -780,9 +784,9 @@ struct sk_buff *nf_ct_frag6_gather(struc
 		goto ret_orig;
 	}
 
-	clone->h.raw = clone->data + fhoff;
-	hdr = clone->nh.ipv6h;
-	fhdr = (struct frag_hdr *)clone->h.raw;
+	skb_set_transport_header(clone, fhoff);
+	hdr = ipv6_hdr(clone);
+	fhdr = (struct frag_hdr *)skb_transport_header(clone);
 
 	if (!(fhdr->frag_off & htons(0xFFF9))) {
 		DEBUGP("Invalid fragment offset\n");
@@ -864,8 +868,7 @@ int nf_ct_frag6_init(void)
 	nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
 				   (jiffies ^ (jiffies >> 6)));
 
-	init_timer(&nf_ct_frag6_secret_timer);
-	nf_ct_frag6_secret_timer.function = nf_ct_frag6_secret_rebuild;
+	setup_timer(&nf_ct_frag6_secret_timer, nf_ct_frag6_secret_rebuild, 0);
 	nf_ct_frag6_secret_timer.expires = jiffies
 					   + nf_ct_frag6_secret_interval;
 	add_timer(&nf_ct_frag6_secret_timer);
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index fa3fb50..920dc9c 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -23,12 +23,12 @@ #include <linux/ipv6.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/stddef.h>
+#include <net/ip.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <net/transp_v6.h>
 #include <net/ipv6.h>
 
-#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *proc_net_devsnmp6;
 
 static int fold_prot_inuse(struct proto *proto)
@@ -142,26 +142,13 @@ static struct snmp_mib snmp6_udplite6_li
 	SNMP_MIB_SENTINEL
 };
 
-static unsigned long
-fold_field(void *mib[], int offt)
-{
-	unsigned long res = 0;
-	int i;
-
-	for_each_possible_cpu(i) {
-		res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt);
-		res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt);
-	}
-	return res;
-}
-
 static inline void
 snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist)
 {
 	int i;
 	for (i=0; itemlist[i].name; i++)
 		seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name,
-				fold_field(mib, itemlist[i].entry));
+			   snmp_fold_field(mib, itemlist[i].entry));
 }
 
 static int snmp6_seq_show(struct seq_file *seq, void *v)
@@ -236,6 +223,7 @@ int snmp6_unregister_dev(struct inet6_de
 		return -EINVAL;
 	remove_proc_entry(idev->stats.proc_dir_entry->name,
 			  proc_net_devsnmp6);
+	idev->stats.proc_dir_entry = NULL;
 	return 0;
 }
 
@@ -271,47 +259,3 @@ void ipv6_misc_proc_exit(void)
 	proc_net_remove("snmp6");
 }
 
-#else	/* CONFIG_PROC_FS */
-
-
-int snmp6_register_dev(struct inet6_dev *idev)
-{
-	return 0;
-}
-
-int snmp6_unregister_dev(struct inet6_dev *idev)
-{
-	return 0;
-}
-#endif	/* CONFIG_PROC_FS */
-
-int snmp6_alloc_dev(struct inet6_dev *idev)
-{
-	int err = -ENOMEM;
-
-	if (!idev || !idev->dev)
-		return -EINVAL;
-
-	if (snmp6_mib_init((void **)idev->stats.ipv6, sizeof(struct ipstats_mib),
-			   __alignof__(struct ipstats_mib)) < 0)
-		goto err_ip;
-	if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib),
-			   __alignof__(struct icmpv6_mib)) < 0)
-		goto err_icmp;
-
-	return 0;
-
-err_icmp:
-	snmp6_mib_free((void **)idev->stats.ipv6);
-err_ip:
-	return err;
-}
-
-int snmp6_free_dev(struct inet6_dev *idev)
-{
-	snmp6_mib_free((void **)idev->stats.icmpv6);
-	snmp6_mib_free((void **)idev->stats.ipv6);
-	return 0;
-}
-
-
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index ef43bd5..f929f47 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -60,6 +60,8 @@ int inet6_add_protocol(struct inet6_prot
 	return ret;
 }
 
+EXPORT_SYMBOL(inet6_add_protocol);
+
 /*
  *	Remove a protocol from the hash tables.
  */
@@ -83,3 +85,5 @@ int inet6_del_protocol(struct inet6_prot
 
 	return ret;
 }
+
+EXPORT_SYMBOL(inet6_del_protocol);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 203e069..009a104 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -152,7 +152,7 @@ int ipv6_raw_deliver(struct sk_buff *skb
 	int delivered = 0;
 	__u8 hash;
 
-	saddr = &skb->nh.ipv6h->saddr;
+	saddr = &ipv6_hdr(skb)->saddr;
 	daddr = saddr + 1;
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
@@ -361,17 +361,18 @@ int rawv6_rcv(struct sock *sk, struct sk
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
 	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,
-				     &skb->nh.ipv6h->daddr,
+		skb_postpull_rcsum(skb, skb_network_header(skb),
+				   skb_network_header_len(skb));
+		if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+				     &ipv6_hdr(skb)->daddr,
 				     skb->len, inet->num, skb->csum))
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-		skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-					     &skb->nh.ipv6h->daddr,
-					     skb->len, inet->num, 0));
+	if (!skb_csum_unnecessary(skb))
+		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+							 &ipv6_hdr(skb)->daddr,
+							 skb->len,
+							 inet->num, 0));
 
 	if (inet->hdrincl) {
 		if (skb_checksum_complete(skb)) {
@@ -420,7 +421,7 @@ static int rawv6_recvmsg(struct kiocb *i
 		msg->msg_flags |= MSG_TRUNC;
 	}
 
-	if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
+	if (skb_csum_unnecessary(skb)) {
 		err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	} else if (msg->msg_flags&MSG_TRUNC) {
 		if (__skb_checksum_complete(skb))
@@ -438,7 +439,7 @@ static int rawv6_recvmsg(struct kiocb *i
 	if (sin6) {
 		sin6->sin6_family = AF_INET6;
 		sin6->sin6_port = 0;
-		ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+		ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
 		sin6->sin6_flowinfo = 0;
 		sin6->sin6_scope_id = 0;
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
@@ -488,7 +489,8 @@ static int rawv6_push_pending_frames(str
 		goto out;
 
 	offset = rp->offset;
-	total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data);
+	total_len = inet_sk(sk)->cork.length - (skb_network_header(skb) -
+						skb->data);
 	if (offset >= total_len - 1) {
 		err = -EINVAL;
 		ip6_flush_pending_frames(sk);
@@ -511,7 +513,7 @@ static int rawv6_push_pending_frames(str
 			if (csum_skb)
 				continue;
 
-			len = skb->len - (skb->h.raw - skb->data);
+			len = skb->len - skb_transport_offset(skb);
 			if (offset >= len) {
 				offset -= len;
 				continue;
@@ -523,7 +525,7 @@ static int rawv6_push_pending_frames(str
 		skb = csum_skb;
 	}
 
-	offset += skb->h.raw - skb->data;
+	offset += skb_transport_offset(skb);
 	if (skb_copy_bits(skb, offset, &csum, 2))
 		BUG();
 
@@ -575,11 +577,13 @@ static int rawv6_send_hdrinc(struct sock
 	skb->priority = sk->sk_priority;
 	skb->dst = dst_clone(&rt->u.dst);
 
-	skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length);
+	skb_put(skb, length);
+	skb_reset_network_header(skb);
+	iph = ipv6_hdr(skb);
 
 	skb->ip_summed = CHECKSUM_NONE;
 
-	skb->h.raw = skb->nh.raw;
+	skb->transport_header = skb->network_header;
 	err = memcpy_fromiovecend((void *)iph, from, 0, length);
 	if (err)
 		goto error_fault;
@@ -878,7 +882,7 @@ static int rawv6_seticmpfilter(struct so
 		return 0;
 	default:
 		return -ENOPROTOOPT;
-	};
+	}
 
 	return 0;
 }
@@ -903,7 +907,7 @@ static int rawv6_geticmpfilter(struct so
 		return 0;
 	default:
 		return -ENOPROTOOPT;
-	};
+	}
 
 	return 0;
 }
@@ -957,7 +961,8 @@ static int rawv6_setsockopt(struct sock 
 		default:
 			return ipv6_setsockopt(sk, level, optname, optval,
 					       optlen);
-	};
+	}
+
 	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 
@@ -978,7 +983,7 @@ static int compat_rawv6_setsockopt(struc
 	default:
 		return compat_ipv6_setsockopt(sk, level, optname,
 					      optval, optlen);
-	};
+	}
 	return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
 }
 #endif
@@ -1031,7 +1036,8 @@ static int rawv6_getsockopt(struct sock 
 		default:
 			return ipv6_getsockopt(sk, level, optname, optval,
 					       optlen);
-	};
+	}
+
 	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
 }
 
@@ -1052,7 +1058,7 @@ static int compat_rawv6_getsockopt(struc
 	default:
 		return compat_ipv6_getsockopt(sk, level, optname,
 					      optval, optlen);
-	};
+	}
 	return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
 }
 #endif
@@ -1073,7 +1079,7 @@ static int rawv6_ioctl(struct sock *sk, 
 			spin_lock_bh(&sk->sk_receive_queue.lock);
 			skb = skb_peek(&sk->sk_receive_queue);
 			if (skb != NULL)
-				amount = skb->tail - skb->h.raw;
+				amount = skb->tail - skb->transport_header;
 			spin_unlock_bh(&sk->sk_receive_queue.lock);
 			return put_user(amount, (int __user *)arg);
 		}
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 7034c54..de795c0 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -88,7 +88,7 @@ struct frag_queue
 	int			len;
 	int			meat;
 	int			iif;
-	struct timeval		stamp;
+	ktime_t			stamp;
 	unsigned int		csum;
 	__u8			last_in;	/* has first/last segment arrived? */
 #define COMPLETE		4
@@ -430,19 +430,24 @@ static void ip6_frag_queue(struct frag_q
 		goto err;
 
 	offset = ntohs(fhdr->frag_off) & ~0x7;
-	end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
-			((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
+	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
+			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
 				 IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+				  ((u8 *)&fhdr->frag_off -
+				   skb_network_header(skb)));
 		return;
 	}
 
-	if (skb->ip_summed == CHECKSUM_COMPLETE)
+	if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		const unsigned char *nh = skb_network_header(skb);
 		skb->csum = csum_sub(skb->csum,
-				     csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
+				     csum_partial(nh, (u8 *)(fhdr + 1) - nh,
+						  0));
+	}
 
 	/* Is this the final fragment? */
 	if (!(fhdr->frag_off & htons(IP6_MF))) {
@@ -562,7 +567,7 @@ static void ip6_frag_queue(struct frag_q
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	skb_get_timestamp(skb, &fq->stamp);
+	fq->stamp = skb->tstamp;
 	fq->meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
@@ -605,7 +610,9 @@ static int ip6_frag_reasm(struct frag_qu
 	BUG_TRAP(FRAG6_CB(head)->offset == 0);
 
 	/* Unfragmented part is taken from the first segment. */
-	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);
+	payload_len = ((head->data - skb_network_header(head)) -
+		       sizeof(struct ipv6hdr) + fq->len -
+		       sizeof(struct frag_hdr));
 	if (payload_len > IPV6_MAXPLEN)
 		goto out_oversize;
 
@@ -639,15 +646,15 @@ static int ip6_frag_reasm(struct frag_qu
 	/* We have to remove fragment header from datagram and to relocate
 	 * header in order to calculate ICV correctly. */
 	nhoff = fq->nhoffset;
-	head->nh.raw[nhoff] = head->h.raw[0];
+	skb_network_header(head)[nhoff] = skb_transport_header(head)[0];
 	memmove(head->head + sizeof(struct frag_hdr), head->head,
 		(head->data - head->head) - sizeof(struct frag_hdr));
-	head->mac.raw += sizeof(struct frag_hdr);
-	head->nh.raw += sizeof(struct frag_hdr);
+	head->mac_header += sizeof(struct frag_hdr);
+	head->network_header += sizeof(struct frag_hdr);
 
 	skb_shinfo(head)->frag_list = head->next;
-	head->h.raw = head->data;
-	skb_push(head, head->data - head->nh.raw);
+	skb_reset_transport_header(head);
+	skb_push(head, head->data - skb_network_header(head));
 	atomic_sub(head->truesize, &ip6_frag_mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
@@ -663,15 +670,17 @@ static int ip6_frag_reasm(struct frag_qu
 
 	head->next = NULL;
 	head->dev = dev;
-	skb_set_timestamp(head, &fq->stamp);
-	head->nh.ipv6h->payload_len = htons(payload_len);
+	head->tstamp = fq->stamp;
+	ipv6_hdr(head)->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
 	*skb_in = head;
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
-		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
+		head->csum = csum_partial(skb_network_header(head),
+					  skb_network_header_len(head),
+					  head->csum);
 
 	rcu_read_lock();
 	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
@@ -699,33 +708,34 @@ static int ipv6_frag_rcv(struct sk_buff 
 	struct net_device *dev = skb->dev;
 	struct frag_hdr *fhdr;
 	struct frag_queue *fq;
-	struct ipv6hdr *hdr;
-
-	hdr = skb->nh.ipv6h;
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
 
 	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS);
 
 	/* Jumbo payload inhibits frag. header */
 	if (hdr->payload_len==0) {
 		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+				  skb_network_header_len(skb));
 		return -1;
 	}
-	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
+	if (!pskb_may_pull(skb, (skb_transport_offset(skb) +
+				 sizeof(struct frag_hdr)))) {
 		IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+				  skb_network_header_len(skb));
 		return -1;
 	}
 
-	hdr = skb->nh.ipv6h;
-	fhdr = (struct frag_hdr *)skb->h.raw;
+	hdr = ipv6_hdr(skb);
+	fhdr = (struct frag_hdr *)skb_transport_header(skb);
 
 	if (!(fhdr->frag_off & htons(0xFFF9))) {
 		/* It is not a fragmented frame */
-		skb->h.raw += sizeof(struct frag_hdr);
+		skb->transport_header += sizeof(struct frag_hdr);
 		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS);
 
-		IP6CB(skb)->nhoff = (u8*)fhdr - skb->nh.raw;
+		IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb);
 		return 1;
 	}
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index aebb4e2..b46ad53 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -575,6 +575,8 @@ struct rt6_info *rt6_lookup(struct in6_a
 	return NULL;
 }
 
+EXPORT_SYMBOL(rt6_lookup);
+
 /* 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
@@ -724,7 +726,7 @@ out2:
 
 void ip6_route_input(struct sk_buff *skb)
 {
-	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
 	int flags = RT6_LOOKUP_F_HAS_SADDR;
 	struct flowi fl = {
 		.iif = skb->dev->ifindex,
@@ -829,6 +831,7 @@ struct dst_entry * ip6_route_output(stru
 	return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
 }
 
+EXPORT_SYMBOL(ip6_route_output);
 
 /*
  *	Destination cache support functions
@@ -1757,7 +1760,7 @@ int ipv6_route_ioctl(unsigned int cmd, v
 		rtnl_unlock();
 
 		return err;
-	};
+	}
 
 	return -EINVAL;
 }
@@ -1772,7 +1775,7 @@ static inline int ip6_pkt_drop(struct sk
 	int type;
 	switch (ipstats_mib_noroutes) {
 	case IPSTATS_MIB_INNOROUTES:
-		type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
+		type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
 		if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) {
 			IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS);
 			break;
@@ -2012,7 +2015,7 @@ errout:
 	return err;
 }
 
-int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct fib6_config cfg;
 	int err;
@@ -2024,7 +2027,7 @@ int inet6_rtm_delroute(struct sk_buff *s
 	return ip6_route_del(&cfg);
 }
 
-int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct fib6_config cfg;
 	int err;
@@ -2161,7 +2164,7 @@ int rt6_dump_route(struct rt6_info *rt, 
 		     prefix, NLM_F_MULTI);
 }
 
-int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
 {
 	struct nlattr *tb[RTA_MAX+1];
 	struct rt6_info *rt;
@@ -2215,7 +2218,7 @@ int inet6_rtm_getroute(struct sk_buff *i
 	/* Reserve room for dummy headers, this skb can pass
 	   through good chunk of routing engine.
 	 */
-	skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
 	rt = (struct rt6_info*) ip6_route_output(NULL, &fl);
@@ -2486,8 +2489,9 @@ #endif
 
 void __init ip6_route_init(void)
 {
+#ifdef 	CONFIG_PROC_FS
 	struct proc_dir_entry *p;
-
+#endif
 	ip6_dst_ops.kmem_cachep =
 		kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
 				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
@@ -2505,6 +2509,10 @@ #endif
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	fib6_rules_init();
 #endif
+
+	__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL);
+	__rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL);
+	__rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL);
 }
 
 void ip6_route_cleanup(void)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 08d6ed3..1efa95a 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -99,10 +99,10 @@ static struct ip_tunnel * ipip6_tunnel_l
 	return NULL;
 }
 
-static struct ip_tunnel ** ipip6_bucket(struct ip_tunnel *t)
+static struct ip_tunnel **__ipip6_bucket(struct ip_tunnel_parm *parms)
 {
-	__be32 remote = t->parms.iph.daddr;
-	__be32 local = t->parms.iph.saddr;
+	__be32 remote = parms->iph.daddr;
+	__be32 local = parms->iph.saddr;
 	unsigned h = 0;
 	int prio = 0;
 
@@ -117,6 +117,11 @@ static struct ip_tunnel ** ipip6_bucket(
 	return &tunnels[prio][h];
 }
 
+static inline struct ip_tunnel **ipip6_bucket(struct ip_tunnel *t)
+{
+	return __ipip6_bucket(&t->parms);
+}
+
 static void ipip6_tunnel_unlink(struct ip_tunnel *t)
 {
 	struct ip_tunnel **tp;
@@ -147,19 +152,9 @@ static struct ip_tunnel * ipip6_tunnel_l
 	__be32 local = parms->iph.saddr;
 	struct ip_tunnel *t, **tp, *nt;
 	struct net_device *dev;
-	unsigned h = 0;
-	int prio = 0;
 	char name[IFNAMSIZ];
 
-	if (remote) {
-		prio |= 2;
-		h ^= HASH(remote);
-	}
-	if (local) {
-		prio |= 1;
-		h ^= HASH(local);
-	}
-	for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {
+	for (tp = __ipip6_bucket(parms); (t = *tp) != NULL; tp = &t->next) {
 		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
 			return t;
 	}
@@ -224,8 +219,8 @@ #ifndef I_WISH_WORLD_WERE_PERFECT
    ICMP in the real Internet is absolutely infeasible.
  */
 	struct iphdr *iph = (struct iphdr*)skb->data;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct ip_tunnel *t;
 	int err;
 
@@ -280,8 +275,8 @@ #else
 	struct iphdr *iph = (struct iphdr*)dp;
 	int hlen = iph->ihl<<2;
 	struct ipv6hdr *iph6;
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	int rel_type = 0;
 	int rel_code = 0;
 	int rel_info = 0;
@@ -296,14 +291,14 @@ #else
 	default:
 		return;
 	case ICMP_PARAMETERPROB:
-		if (skb->h.icmph->un.gateway < hlen)
+		if (icmp_hdr(skb)->un.gateway < hlen)
 			return;
 
 		/* So... This guy found something strange INSIDE encapsulated
 		   packet. Well, he is fool, but what can we do ?
 		 */
 		rel_type = ICMPV6_PARAMPROB;
-		rel_info = skb->h.icmph->un.gateway - hlen;
+		rel_info = icmp_hdr(skb)->un.gateway - hlen;
 		break;
 
 	case ICMP_DEST_UNREACH:
@@ -340,7 +335,7 @@ #else
 	dst_release(skb2->dst);
 	skb2->dst = NULL;
 	skb_pull(skb2, skb->data - (u8*)iph6);
-	skb2->nh.raw = skb2->data;
+	skb_reset_network_header(skb2);
 
 	/* Try to guess incoming interface */
 	rt6i = rt6_lookup(&iph6->saddr, NULL, NULL, 0);
@@ -366,7 +361,7 @@ #endif
 static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
 {
 	if (INET_ECN_is_ce(iph->tos))
-		IP6_ECN_set_ce(skb->nh.ipv6h);
+		IP6_ECN_set_ce(ipv6_hdr(skb));
 }
 
 static int ipip6_rcv(struct sk_buff *skb)
@@ -377,13 +372,13 @@ static int ipip6_rcv(struct sk_buff *skb
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		goto out;
 
-	iph = skb->nh.iph;
+	iph = ip_hdr(skb);
 
 	read_lock(&ipip6_lock);
 	if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
 		secpath_reset(skb);
-		skb->mac.raw = skb->nh.raw;
-		skb->nh.raw = skb->data;
+		skb->mac_header = skb->network_header;
+		skb_reset_network_header(skb);
 		IPCB(skb)->flags = 0;
 		skb->protocol = htons(ETH_P_IPV6);
 		skb->pkt_type = PACKET_HOST;
@@ -430,7 +425,7 @@ static int ipip6_tunnel_xmit(struct sk_b
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct net_device_stats *stats = &tunnel->stat;
 	struct iphdr  *tiph = &tunnel->parms.iph;
-	struct ipv6hdr *iph6 = skb->nh.ipv6h;
+	struct ipv6hdr *iph6 = ipv6_hdr(skb);
 	u8     tos = tunnel->parms.iph.tos;
 	struct rtable *rt;     			/* Route to the other host */
 	struct net_device *tdev;			/* Device to other host */
@@ -468,7 +463,7 @@ static int ipip6_tunnel_xmit(struct sk_b
 		addr_type = ipv6_addr_type(addr6);
 
 		if (addr_type == IPV6_ADDR_ANY) {
-			addr6 = &skb->nh.ipv6h->daddr;
+			addr6 = &ipv6_hdr(skb)->daddr;
 			addr_type = ipv6_addr_type(addr6);
 		}
 
@@ -550,11 +545,12 @@ static int ipip6_tunnel_xmit(struct sk_b
 			skb_set_owner_w(new_skb, skb->sk);
 		dev_kfree_skb(skb);
 		skb = new_skb;
-		iph6 = skb->nh.ipv6h;
+		iph6 = ipv6_hdr(skb);
 	}
 
-	skb->h.raw = skb->nh.raw;
-	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
+	skb->transport_header = skb->network_header;
+	skb_push(skb, sizeof(struct iphdr));
+	skb_reset_network_header(skb);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags = 0;
 	dst_release(skb->dst);
@@ -564,7 +560,7 @@ static int ipip6_tunnel_xmit(struct sk_b
 	 *	Push down and install the IPIP header.
 	 */
 
-	iph 			=	skb->nh.iph;
+	iph 			=	ip_hdr(skb);
 	iph->version		=	4;
 	iph->ihl		=	sizeof(struct iphdr)>>2;
 	if (mtu > IPV6_MIN_MTU)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 92f9992..e2f25ea 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -115,10 +115,10 @@ static __inline__ __sum16 tcp_v6_check(s
 
 static __u32 tcp_v6_init_sequence(struct sk_buff *skb)
 {
-	return secure_tcpv6_sequence_number(skb->nh.ipv6h->daddr.s6_addr32,
-					    skb->nh.ipv6h->saddr.s6_addr32,
-					    skb->h.th->dest,
-					    skb->h.th->source);
+	return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
+					    ipv6_hdr(skb)->saddr.s6_addr32,
+					    tcp_hdr(skb)->dest,
+					    tcp_hdr(skb)->source);
 }
 
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
@@ -486,7 +486,9 @@ static int tcp_v6_send_synack(struct soc
 			struct sk_buff *pktopts = treq->pktopts;
 			struct inet6_skb_parm *rxopt = IP6CB(pktopts);
 			if (rxopt->srcrt)
-				opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
+				opt = ipv6_invert_rthdr(sk,
+			  (struct ipv6_rt_hdr *)(skb_network_header(pktopts) +
+						 rxopt->srcrt));
 		}
 
 		if (opt && opt->srcrt) {
@@ -507,7 +509,7 @@ static int tcp_v6_send_synack(struct soc
 
 	skb = tcp_make_synack(sk, dst, req);
 	if (skb) {
-		struct tcphdr *th = skb->h.th;
+		struct tcphdr *th = tcp_hdr(skb);
 
 		th->check = tcp_v6_check(th, skb->len,
 					 &treq->loc_addr, &treq->rmt_addr,
@@ -835,8 +837,8 @@ static int tcp_v6_inbound_md5_hash (stru
 {
 	__u8 *hash_location = NULL;
 	struct tcp_md5sig_key *hash_expected;
-	struct ipv6hdr *ip6h = skb->nh.ipv6h;
-	struct tcphdr *th = skb->h.th;
+	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
 	int length = (th->doff << 2) - sizeof (*th);
 	int genhash;
 	u8 *ptr;
@@ -944,10 +946,11 @@ static struct timewait_sock_ops tcp6_tim
 static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
-	struct tcphdr *th = skb->h.th;
+	struct tcphdr *th = tcp_hdr(skb);
 
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,  0);
+		skb->csum_start = skb_transport_header(skb) - skb->head;
 		skb->csum_offset = offsetof(struct tcphdr, check);
 	} else {
 		th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
@@ -964,12 +967,13 @@ static int tcp_v6_gso_send_check(struct 
 	if (!pskb_may_pull(skb, sizeof(*th)))
 		return -EINVAL;
 
-	ipv6h = skb->nh.ipv6h;
-	th = skb->h.th;
+	ipv6h = ipv6_hdr(skb);
+	th = tcp_hdr(skb);
 
 	th->check = 0;
 	th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
 				     IPPROTO_TCP, 0);
+	skb->csum_start = skb_transport_header(skb) - skb->head;
 	skb->csum_offset = offsetof(struct tcphdr, check);
 	skb->ip_summed = CHECKSUM_PARTIAL;
 	return 0;
@@ -977,7 +981,7 @@ static int tcp_v6_gso_send_check(struct 
 
 static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
 {
-	struct tcphdr *th = skb->h.th, *t1;
+	struct tcphdr *th = tcp_hdr(skb), *t1;
 	struct sk_buff *buff;
 	struct flowi fl;
 	int tot_len = sizeof(*th);
@@ -993,7 +997,7 @@ #endif
 
 #ifdef CONFIG_TCP_MD5SIG
 	if (sk)
-		key = tcp_v6_md5_do_lookup(sk, &skb->nh.ipv6h->daddr);
+		key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr);
 	else
 		key = NULL;
 
@@ -1037,20 +1041,18 @@ #ifdef CONFIG_TCP_MD5SIG
 			       (TCPOPT_NOP << 16) |
 			       (TCPOPT_MD5SIG << 8) |
 			       TCPOLEN_MD5SIG);
-		tcp_v6_do_calc_md5_hash((__u8*)&opt[1],
-					key,
-					&skb->nh.ipv6h->daddr,
-					&skb->nh.ipv6h->saddr,
-					t1, IPPROTO_TCP,
-					tot_len);
+		tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
+					&ipv6_hdr(skb)->daddr,
+					&ipv6_hdr(skb)->saddr,
+					t1, IPPROTO_TCP, tot_len);
 	}
 #endif
 
 	buff->csum = csum_partial((char *)t1, sizeof(*t1), 0);
 
 	memset(&fl, 0, sizeof(fl));
-	ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
+	ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
 
 	t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
 				    sizeof(*t1), IPPROTO_TCP,
@@ -1079,7 +1081,7 @@ #endif
 static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
 			    struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
 {
-	struct tcphdr *th = skb->h.th, *t1;
+	struct tcphdr *th = tcp_hdr(skb), *t1;
 	struct sk_buff *buff;
 	struct flowi fl;
 	int tot_len = sizeof(struct tcphdr);
@@ -1091,7 +1093,7 @@ #endif
 
 #ifdef CONFIG_TCP_MD5SIG
 	if (!tw && skb->sk) {
-		key = tcp_v6_md5_do_lookup(skb->sk, &skb->nh.ipv6h->daddr);
+		key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr);
 	} else if (tw && tw->tw_md5_keylen) {
 		tw_key.key = tw->tw_md5_key;
 		tw_key.keylen = tw->tw_md5_keylen;
@@ -1140,20 +1142,18 @@ #ifdef CONFIG_TCP_MD5SIG
 	if (key) {
 		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
 				(TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
-		tcp_v6_do_calc_md5_hash((__u8 *)topt,
-					key,
-					&skb->nh.ipv6h->daddr,
-					&skb->nh.ipv6h->saddr,
-					t1, IPPROTO_TCP,
-					tot_len);
+		tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
+					&ipv6_hdr(skb)->daddr,
+					&ipv6_hdr(skb)->saddr,
+					t1, IPPROTO_TCP, tot_len);
 	}
 #endif
 
 	buff->csum = csum_partial((char *)t1, tot_len, 0);
 
 	memset(&fl, 0, sizeof(fl));
-	ipv6_addr_copy(&fl.fl6_dst, &skb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&fl.fl6_src, &skb->nh.ipv6h->daddr);
+	ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
 
 	t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
 				    tot_len, IPPROTO_TCP,
@@ -1197,18 +1197,18 @@ static void tcp_v6_reqsk_send_ack(struct
 static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 {
 	struct request_sock *req, **prev;
-	const struct tcphdr *th = skb->h.th;
+	const struct tcphdr *th = tcp_hdr(skb);
 	struct sock *nsk;
 
 	/* Find possible connection requests. */
 	req = inet6_csk_search_req(sk, &prev, th->source,
-				   &skb->nh.ipv6h->saddr,
-				   &skb->nh.ipv6h->daddr, inet6_iif(skb));
+				   &ipv6_hdr(skb)->saddr,
+				   &ipv6_hdr(skb)->daddr, inet6_iif(skb));
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
-	nsk = __inet6_lookup_established(&tcp_hashinfo, &skb->nh.ipv6h->saddr,
-					 th->source, &skb->nh.ipv6h->daddr,
+	nsk = __inet6_lookup_established(&tcp_hashinfo, &ipv6_hdr(skb)->saddr,
+					 th->source, &ipv6_hdr(skb)->daddr,
 					 ntohs(th->dest), inet6_iif(skb));
 
 	if (nsk) {
@@ -1275,9 +1275,9 @@ #endif
 	tcp_openreq_init(req, &tmp_opt, skb);
 
 	treq = inet6_rsk(req);
-	ipv6_addr_copy(&treq->rmt_addr, &skb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&treq->loc_addr, &skb->nh.ipv6h->daddr);
-	TCP_ECN_create_request(req, skb->h.th);
+	ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
+	TCP_ECN_create_request(req, tcp_hdr(skb));
 	treq->pktopts = NULL;
 	if (ipv6_opt_accepted(sk, skb) ||
 	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
@@ -1363,7 +1363,7 @@ #endif
 		newnp->pktoptions  = NULL;
 		newnp->opt	   = NULL;
 		newnp->mcast_oif   = inet6_iif(skb);
-		newnp->mcast_hops  = skb->nh.ipv6h->hop_limit;
+		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;
 
 		/*
 		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
@@ -1389,7 +1389,9 @@ #endif
 	    opt == NULL && treq->pktopts) {
 		struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
 		if (rxopt->srcrt)
-			opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr *)(treq->pktopts->nh.raw + rxopt->srcrt));
+			opt = ipv6_invert_rthdr(sk,
+		   (struct ipv6_rt_hdr *)(skb_network_header(treq->pktopts) +
+					  rxopt->srcrt));
 	}
 
 	if (dst == NULL) {
@@ -1469,7 +1471,7 @@ #endif
 	}
 	newnp->opt	  = NULL;
 	newnp->mcast_oif  = inet6_iif(skb);
-	newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
+	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;
 
 	/* Clone native IPv6 options from listening socket (if any)
 
@@ -1528,15 +1530,16 @@ out:
 static __sum16 tcp_v6_checksum_init(struct sk_buff *skb)
 {
 	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)) {
+		if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr,
+				  &ipv6_hdr(skb)->daddr, skb->csum)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			return 0;
 		}
 	}
 
-	skb->csum = ~csum_unfold(tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
-				  &skb->nh.ipv6h->daddr, 0));
+	skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len,
+					      &ipv6_hdr(skb)->saddr,
+					      &ipv6_hdr(skb)->daddr, 0));
 
 	if (skb->len <= 76) {
 		return __skb_checksum_complete(skb);
@@ -1600,7 +1603,7 @@ #endif
 
 	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
 		TCP_CHECK_TIMER(sk);
-		if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
+		if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
 			goto reset;
 		TCP_CHECK_TIMER(sk);
 		if (opt_skb)
@@ -1608,7 +1611,7 @@ #endif
 		return 0;
 	}
 
-	if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
+	if (skb->len < tcp_hdrlen(skb) || tcp_checksum_complete(skb))
 		goto csum_err;
 
 	if (sk->sk_state == TCP_LISTEN) {
@@ -1631,7 +1634,7 @@ #endif
 	}
 
 	TCP_CHECK_TIMER(sk);
-	if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
+	if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len))
 		goto reset;
 	TCP_CHECK_TIMER(sk);
 	if (opt_skb)
@@ -1664,7 +1667,7 @@ ipv6_pktoptions:
 		if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
 			np->mcast_oif = inet6_iif(opt_skb);
 		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
-			np->mcast_hops = opt_skb->nh.ipv6h->hop_limit;
+			np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit;
 		if (ipv6_opt_accepted(sk, opt_skb)) {
 			skb_set_owner_r(opt_skb, sk);
 			opt_skb = xchg(&np->pktoptions, opt_skb);
@@ -1697,28 +1700,27 @@ static int tcp_v6_rcv(struct sk_buff **p
 	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
 		goto discard_it;
 
-	th = skb->h.th;
+	th = tcp_hdr(skb);
 
 	if (th->doff < sizeof(struct tcphdr)/4)
 		goto bad_packet;
 	if (!pskb_may_pull(skb, th->doff*4))
 		goto discard_it;
 
-	if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
-	     tcp_v6_checksum_init(skb)))
+	if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
 		goto bad_packet;
 
-	th = skb->h.th;
+	th = tcp_hdr(skb);
 	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
 	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
 				    skb->len - th->doff*4);
 	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
 	TCP_SKB_CB(skb)->when = 0;
-	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
+	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
 	TCP_SKB_CB(skb)->sacked = 0;
 
-	sk = __inet6_lookup(&tcp_hashinfo, &skb->nh.ipv6h->saddr, th->source,
-			    &skb->nh.ipv6h->daddr, ntohs(th->dest),
+	sk = __inet6_lookup(&tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source,
+			    &ipv6_hdr(skb)->daddr, ntohs(th->dest),
 			    inet6_iif(skb));
 
 	if (!sk)
@@ -1798,7 +1800,7 @@ do_time_wait:
 		struct sock *sk2;
 
 		sk2 = inet6_lookup_listener(&tcp_hashinfo,
-					    &skb->nh.ipv6h->daddr,
+					    &ipv6_hdr(skb)->daddr,
 					    ntohs(th->dest), inet6_iif(skb));
 		if (sk2 != NULL) {
 			struct inet_timewait_sock *tw = inet_twsk(sk);
@@ -1945,6 +1947,7 @@ #endif
 	return inet6_destroy_sock(sk);
 }
 
+#ifdef CONFIG_PROC_FS
 /* Proc filesystem TCPv6 sock list dumping. */
 static void get_openreq6(struct seq_file *seq,
 			 struct sock *sk, struct request_sock *req, int i, int uid)
@@ -2061,7 +2064,6 @@ static void get_timewait6_sock(struct se
 		   atomic_read(&tw->tw_refcnt), tw);
 }
 
-#ifdef CONFIG_PROC_FS
 static int tcp6_seq_show(struct seq_file *seq, void *v)
 {
 	struct tcp_iter_state *st;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index f590db5..b083c09 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -93,10 +93,10 @@ static struct sock *__udp6_lib_lookup(st
 					continue;
 				score++;
 			}
-			if(score == 4) {
+			if (score == 4) {
 				result = sk;
 				break;
-			} else if(score > badness) {
+			} else if (score > badness) {
 				result = sk;
 				badness = score;
 			}
@@ -120,8 +120,9 @@ int udpv6_recvmsg(struct kiocb *iocb, st
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct inet_sock *inet = inet_sk(sk);
 	struct sk_buff *skb;
-	size_t copied;
-	int err, copy_only, is_udplite = IS_UDPLITE(sk);
+	unsigned int ulen, copied;
+	int err;
+	int is_udplite = IS_UDPLITE(sk);
 
 	if (addr_len)
 		*addr_len=sizeof(struct sockaddr_in6);
@@ -134,24 +135,25 @@ try_again:
 	if (!skb)
 		goto out;
 
-	copied = skb->len - sizeof(struct udphdr);
-	if (copied > len) {
-		copied = len;
+	ulen = skb->len - sizeof(struct udphdr);
+	copied = len;
+	if (copied > ulen)
+		copied = ulen;
+	else if (copied < ulen)
 		msg->msg_flags |= MSG_TRUNC;
-	}
 
 	/*
-	 * 	Decide whether to checksum and/or copy data.
+	 * If checksum is needed at all, try to do it while copying the
+	 * data.  If the data is truncated, or if we only want a partial
+	 * coverage checksum (UDP-Lite), do it before the copy.
 	 */
-	copy_only = (skb->ip_summed==CHECKSUM_UNNECESSARY);
 
-	if (is_udplite  ||  (!copy_only  &&  msg->msg_flags&MSG_TRUNC)) {
-		if (__udp_lib_checksum_complete(skb))
+	if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+		if (udp_lib_checksum_complete(skb))
 			goto csum_copy_err;
-		copy_only = 1;
 	}
 
-	if (copy_only)
+	if (skb_csum_unnecessary(skb))
 		err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
 					      msg->msg_iov, copied       );
 	else {
@@ -170,15 +172,16 @@ try_again:
 
 		sin6 = (struct sockaddr_in6 *) msg->msg_name;
 		sin6->sin6_family = AF_INET6;
-		sin6->sin6_port = skb->h.uh->source;
+		sin6->sin6_port = udp_hdr(skb)->source;
 		sin6->sin6_flowinfo = 0;
 		sin6->sin6_scope_id = 0;
 
 		if (skb->protocol == htons(ETH_P_IP))
 			ipv6_addr_set(&sin6->sin6_addr, 0, 0,
-				      htonl(0xffff), skb->nh.iph->saddr);
+				      htonl(0xffff), ip_hdr(skb)->saddr);
 		else {
-			ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+			ipv6_addr_copy(&sin6->sin6_addr,
+				       &ipv6_hdr(skb)->saddr);
 			if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 				sin6->sin6_scope_id = IP6CB(skb)->iif;
 		}
@@ -194,7 +197,7 @@ try_again:
 
 	err = copied;
 	if (flags & MSG_TRUNC)
-		err = skb->len - sizeof(struct udphdr);
+		err = ulen;
 
 out_free:
 	skb_free_datagram(sk, skb);
@@ -279,8 +282,10 @@ int udpv6_queue_rcv_skb(struct sock * sk
 		}
 	}
 
-	if (udp_lib_checksum_complete(skb))
-		goto drop;
+	if (sk->sk_filter) {
+		if (udp_lib_checksum_complete(skb))
+			goto drop;
+	}
 
 	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
 		/* Note that an ENOMEM error is charged twice */
@@ -325,7 +330,7 @@ static struct sock *udp_v6_mcast_next(st
 				if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr))
 					continue;
 			}
-			if(!inet6_mc_check(s, loc_addr, rmt_addr))
+			if (!inet6_mc_check(s, loc_addr, rmt_addr))
 				continue;
 			return s;
 		}
@@ -341,7 +346,7 @@ static int __udp6_lib_mcast_deliver(stru
 			   struct in6_addr *daddr, struct hlist_head udptable[])
 {
 	struct sock *sk, *sk2;
-	const struct udphdr *uh = skb->h.uh;
+	const struct udphdr *uh = udp_hdr(skb);
 	int dif;
 
 	read_lock(&udp_hash_lock);
@@ -366,9 +371,20 @@ out:
 	return 0;
 }
 
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh)
-
+static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
+				 int proto)
 {
+	int err;
+
+	UDP_SKB_CB(skb)->partial_cov = 0;
+	UDP_SKB_CB(skb)->cscov = skb->len;
+
+	if (proto == IPPROTO_UDPLITE) {
+		err = udplite_checksum_init(skb, uh);
+		if (err)
+			return err;
+	}
+
 	if (uh->check == 0) {
 		/* RFC 2460 section 8.1 says that we SHOULD log
 		   this error. Well, it is reasonable.
@@ -377,21 +393,20 @@ static inline int udp6_csum_init(struct 
 		return 1;
 	}
 	if (skb->ip_summed == CHECKSUM_COMPLETE &&
-	    !csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
-			     skb->len, IPPROTO_UDP, skb->csum             ))
+	    !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+			     skb->len, proto, skb->csum))
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-	if (skb->ip_summed != CHECKSUM_UNNECESSARY)
-		skb->csum = ~csum_unfold(csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-							 &skb->nh.ipv6h->daddr,
-							 skb->len, IPPROTO_UDP,
-							 0));
+	if (!skb_csum_unnecessary(skb))
+		skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+							 &ipv6_hdr(skb)->daddr,
+							 skb->len, proto, 0));
 
-	return (UDP_SKB_CB(skb)->partial_cov = 0);
+	return 0;
 }
 
 int __udp6_lib_rcv(struct sk_buff **pskb, struct hlist_head udptable[],
-		   int is_udplite)
+		   int proto)
 {
 	struct sk_buff *skb = *pskb;
 	struct sock *sk;
@@ -403,15 +418,16 @@ int __udp6_lib_rcv(struct sk_buff **pskb
 	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 		goto short_packet;
 
-	saddr = &skb->nh.ipv6h->saddr;
-	daddr = &skb->nh.ipv6h->daddr;
-	uh = skb->h.uh;
+	saddr = &ipv6_hdr(skb)->saddr;
+	daddr = &ipv6_hdr(skb)->daddr;
+	uh = udp_hdr(skb);
 
 	ulen = ntohs(uh->len);
 	if (ulen > skb->len)
 		goto short_packet;
 
-	if(! is_udplite ) {		/* UDP validates ulen. */
+	if (proto == IPPROTO_UDP) {
+		/* UDP validates ulen. */
 
 		/* Check for jumbo payload */
 		if (ulen == 0)
@@ -423,19 +439,15 @@ int __udp6_lib_rcv(struct sk_buff **pskb
 		if (ulen < skb->len) {
 			if (pskb_trim_rcsum(skb, ulen))
 				goto short_packet;
-			saddr = &skb->nh.ipv6h->saddr;
-			daddr = &skb->nh.ipv6h->daddr;
-			uh = skb->h.uh;
+			saddr = &ipv6_hdr(skb)->saddr;
+			daddr = &ipv6_hdr(skb)->daddr;
+			uh = udp_hdr(skb);
 		}
-
-		if (udp6_csum_init(skb, uh))
-			goto discard;
-
-	} else 	{			/* UDP-Lite validates cscov. */
-		if (udplite6_csum_init(skb, uh))
-			goto discard;
 	}
 
+	if (udp6_csum_init(skb, uh, proto))
+		goto discard;
+
 	/*
 	 *	Multicast receive code
 	 */
@@ -457,33 +469,34 @@ int __udp6_lib_rcv(struct sk_buff **pskb
 
 		if (udp_lib_checksum_complete(skb))
 			goto discard;
-		UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, is_udplite);
+		UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
 
 		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
 
 		kfree_skb(skb);
-		return(0);
+		return 0;
 	}
 
 	/* deliver */
 
 	udpv6_queue_rcv_skb(sk, skb);
 	sock_put(sk);
-	return(0);
+	return 0;
 
 short_packet:
 	LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n",
-		       is_udplite? "-Lite" : "",  ulen, skb->len);
+		       proto == IPPROTO_UDPLITE ? "-Lite" : "",
+		       ulen, skb->len);
 
 discard:
-	UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
+	UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
 	kfree_skb(skb);
-	return(0);
+	return 0;
 }
 
 static __inline__ int udpv6_rcv(struct sk_buff **pskb)
 {
-	return __udp6_lib_rcv(pskb, udp_hash, 0);
+	return __udp6_lib_rcv(pskb, udp_hash, IPPROTO_UDP);
 }
 
 /*
@@ -521,7 +534,7 @@ static int udp_v6_push_pending_frames(st
 	/*
 	 * Create a UDP header
 	 */
-	uh = skb->h.uh;
+	uh = udp_hdr(skb);
 	uh->source = fl->fl_ip_sport;
 	uh->dest = fl->fl_ip_dport;
 	uh->len = htons(up->len);
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 629f971..f54016a 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -19,7 +19,7 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite
 
 static int udplitev6_rcv(struct sk_buff **pskb)
 {
-	return __udp6_lib_rcv(pskb, udplite_hash, 1);
+	return __udp6_lib_rcv(pskb, udplite_hash, IPPROTO_UDPLITE);
 }
 
 static void udplitev6_err(struct sk_buff *skb,
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 31f651f..d7ed8aa 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -28,14 +28,14 @@ int xfrm6_rcv_spi(struct sk_buff *skb, _
 	unsigned int nhoff;
 
 	nhoff = IP6CB(skb)->nhoff;
-	nexthdr = skb->nh.raw[nhoff];
+	nexthdr = skb_network_header(skb)[nhoff];
 
 	seq = 0;
 	if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0)
 		goto drop;
 
 	do {
-		struct ipv6hdr *iph = skb->nh.ipv6h;
+		struct ipv6hdr *iph = ipv6_hdr(skb);
 
 		if (xfrm_nr == XFRM_MAX_DEPTH)
 			goto drop;
@@ -58,7 +58,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, _
 		if (nexthdr <= 0)
 			goto drop_unlock;
 
-		skb->nh.raw[nhoff] = nexthdr;
+		skb_network_header(skb)[nhoff] = nexthdr;
 
 		if (x->props.replay_window)
 			xfrm_replay_advance(x, seq);
@@ -112,8 +112,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, _
 		return -1;
 	} else {
 #ifdef CONFIG_NETFILTER
-		skb->nh.ipv6h->payload_len = htons(skb->len);
-		__skb_push(skb, skb->data - skb->nh.raw);
+		ipv6_hdr(skb)->payload_len = htons(skb->len);
+		__skb_push(skb, skb->data - skb_network_header(skb));
 
 		NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
 			ip6_rcv_finish);
@@ -140,19 +140,19 @@ int xfrm6_rcv(struct sk_buff **pskb)
 	return xfrm6_rcv_spi(*pskb, 0);
 }
 
+EXPORT_SYMBOL(xfrm6_rcv);
+
 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;
+	xany = (xfrm_address_t *)&in6addr_any;
 
 	for (i = 0; i < 3; i++) {
 		xfrm_address_t *dst, *src;
@@ -247,3 +247,5 @@ drop:
 		xfrm_state_put(xfrm_vec_one);
 	return -1;
 }
+
+EXPORT_SYMBOL(xfrm6_input_addr);
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index edcfffa..2e61d6d 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -38,17 +38,18 @@ static int xfrm6_beet_output(struct xfrm
 	int hdr_len;
 
 	skb_push(skb, x->props.header_len);
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 
 	hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
-	skb->nh.raw = prevhdr - x->props.header_len;
-	skb->h.raw = skb->data + hdr_len;
+	skb_set_network_header(skb,
+			       (prevhdr - x->props.header_len) - skb->data);
+	skb_set_transport_header(skb, 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;
+	skb_reset_network_header(skb);
+	top_iph = ipv6_hdr(skb);
+	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
+	skb->network_header += offsetof(struct ipv6hdr, nexthdr);
 
 	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
 	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
@@ -59,6 +60,7 @@ static int xfrm6_beet_output(struct xfrm
 static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct ipv6hdr *ip6h;
+	const unsigned char *old_mac;
 	int size = sizeof(struct ipv6hdr);
 	int err = -EINVAL;
 
@@ -66,13 +68,14 @@ static int xfrm6_beet_input(struct xfrm_
 		goto out;
 
 	skb_push(skb, size);
-	memmove(skb->data, skb->nh.raw, size);
-	skb->nh.raw = skb->data;
+	memmove(skb->data, skb_network_header(skb), size);
+	skb_reset_network_header(skb);
 
-	skb->mac.raw = memmove(skb->data - skb->mac_len,
-			       skb->mac.raw, skb->mac_len);
+	old_mac = skb_mac_header(skb);
+	skb_set_mac_header(skb, -skb->mac_len);
+	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
 
-	ip6h = skb->nh.ipv6h;
+	ip6h = ipv6_hdr(skb);
 	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);
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
index 6031c16..6ad6d7a 100644
--- a/net/ipv6/xfrm6_mode_ro.c
+++ b/net/ipv6/xfrm6_mode_ro.c
@@ -50,11 +50,12 @@ static int xfrm6_ro_output(struct xfrm_s
 	int hdr_len;
 
 	skb_push(skb, x->props.header_len);
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 
 	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
-	skb->nh.raw = prevhdr - x->props.header_len;
-	skb->h.raw = skb->data + hdr_len;
+	skb_set_network_header(skb,
+			       (prevhdr - x->props.header_len) - skb->data);
+	skb_set_transport_header(skb, hdr_len);
 	memmove(skb->data, iph, hdr_len);
 	return 0;
 }
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c
index 3a4b39b..c026bfe 100644
--- a/net/ipv6/xfrm6_mode_transport.c
+++ b/net/ipv6/xfrm6_mode_transport.c
@@ -32,11 +32,12 @@ static int xfrm6_transport_output(struct
 	int hdr_len;
 
 	skb_push(skb, x->props.header_len);
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 
 	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
-	skb->nh.raw = prevhdr - x->props.header_len;
-	skb->h.raw = skb->data + hdr_len;
+	skb_set_network_header(skb,
+			       (prevhdr - x->props.header_len) - skb->data);
+	skb_set_transport_header(skb, hdr_len);
 	memmove(skb->data, iph, hdr_len);
 	return 0;
 }
@@ -51,13 +52,16 @@ static int xfrm6_transport_output(struct
  */
 static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-	int ihl = skb->data - skb->h.raw;
+	int ihl = skb->data - skb_transport_header(skb);
 
-	if (skb->h.raw != skb->nh.raw)
-		skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);
-	skb->nh.ipv6h->payload_len = htons(skb->len + ihl -
+	if (skb->transport_header != skb->network_header) {
+		memmove(skb_transport_header(skb),
+			skb_network_header(skb), ihl);
+		skb->network_header = skb->transport_header;
+	}
+	ipv6_hdr(skb)->payload_len = htons(skb->len + ihl -
 					   sizeof(struct ipv6hdr));
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	return 0;
 }
 
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 0bc866c..a6c0cdf 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -18,8 +18,8 @@ #include <net/xfrm.h>
 
 static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
 {
-	struct ipv6hdr *outer_iph = skb->nh.ipv6h;
-	struct ipv6hdr *inner_iph = skb->h.ipv6h;
+	struct ipv6hdr *outer_iph = ipv6_hdr(skb);
+	struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
 
 	if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph)))
 		IP6_ECN_set_ce(inner_iph);
@@ -27,8 +27,8 @@ static inline void ipip6_ecn_decapsulate
 
 static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb)
 {
-	if (INET_ECN_is_ce(ipv6_get_dsfield(skb->nh.ipv6h)))
-			IP_ECN_set_ce(skb->h.ipiph);
+	if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6_hdr(skb))))
+			IP_ECN_set_ce(ipip_hdr(skb));
 }
 
 /* Add encapsulation header.
@@ -51,12 +51,12 @@ static int xfrm6_tunnel_output(struct xf
 	int dsfield;
 
 	skb_push(skb, x->props.header_len);
-	iph = skb->nh.ipv6h;
+	iph = ipv6_hdr(skb);
 
-	skb->nh.raw = skb->data;
-	top_iph = skb->nh.ipv6h;
-	skb->nh.raw = &top_iph->nexthdr;
-	skb->h.ipv6h = top_iph + 1;
+	skb_reset_network_header(skb);
+	top_iph = ipv6_hdr(skb);
+	skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
+	skb->network_header   += offsetof(struct ipv6hdr, nexthdr);
 
 	top_iph->version = 6;
 	if (xdst->route->ops->family == AF_INET6) {
@@ -86,9 +86,11 @@ static int xfrm6_tunnel_output(struct xf
 static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err = -EINVAL;
+	const unsigned char *old_mac;
+	const unsigned char *nh = skb_network_header(skb);
 
-	if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6
-	    && skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPIP)
+	if (nh[IP6CB(skb)->nhoff] != IPPROTO_IPV6 &&
+	    nh[IP6CB(skb)->nhoff] != IPPROTO_IPIP)
 		goto out;
 	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
 		goto out;
@@ -97,9 +99,10 @@ static int xfrm6_tunnel_input(struct xfr
 	    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
 		goto out;
 
-	if (skb->nh.raw[IP6CB(skb)->nhoff] == IPPROTO_IPV6) {
+	nh = skb_network_header(skb);
+	if (nh[IP6CB(skb)->nhoff] == IPPROTO_IPV6) {
 		if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-			ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h);
+			ipv6_copy_dscp(ipv6_hdr(skb), ipipv6_hdr(skb));
 		if (!(x->props.flags & XFRM_STATE_NOECN))
 			ipip6_ecn_decapsulate(skb);
 	} else {
@@ -107,9 +110,10 @@ static int xfrm6_tunnel_input(struct xfr
 			ip6ip_ecn_decapsulate(skb);
 		skb->protocol = htons(ETH_P_IP);
 	}
-	skb->mac.raw = memmove(skb->data - skb->mac_len,
-			       skb->mac.raw, skb->mac_len);
-	skb->nh.raw = skb->data;
+	old_mac = skb_mac_header(skb);
+	skb_set_mac_header(skb, -skb->mac_len);
+	memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+	skb_reset_network_header(skb);
 	err = 0;
 
 out:
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index d6d786b..56364a5 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -23,6 +23,8 @@ int xfrm6_find_1stfragopt(struct xfrm_st
 	return ip6_find_1stfragopt(skb, prevhdr);
 }
 
+EXPORT_SYMBOL(xfrm6_find_1stfragopt);
+
 static int xfrm6_tunnel_check_size(struct sk_buff *skb)
 {
 	int mtu, ret = 0;
@@ -76,11 +78,11 @@ 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;
+			x->lastused = get_seconds();
 
 		spin_unlock_bh(&x->lock);
 
-		skb->nh.raw = skb->data;
+		skb_reset_network_header(skb);
 
 		if (!(skb->dst = dst_pop(dst))) {
 			err = -EHOSTUNREACH;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index d8a585b..1faa2ea 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -240,7 +240,8 @@ __xfrm6_bundle_create(struct xfrm_policy
 		if (!afinfo) {
 			dst = *dst_p;
 			goto error;
-		};
+		}
+
 		dst_prev->output = afinfo->output;
 		xfrm_state_put_afinfo(afinfo);
 		/* Sheit... I remember I did this right. Apparently,
@@ -270,17 +271,19 @@ error:
 static inline void
 _decode_session6(struct sk_buff *skb, struct flowi *fl)
 {
-	u16 offset = skb->h.raw - skb->nh.raw;
-	struct ipv6hdr *hdr = skb->nh.ipv6h;
+	u16 offset = skb_network_header_len(skb);
+	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct ipv6_opt_hdr *exthdr;
-	u8 nexthdr = skb->nh.raw[IP6CB(skb)->nhoff];
+	const unsigned char *nh = skb_network_header(skb);
+	u8 nexthdr = nh[IP6CB(skb)->nhoff];
 
 	memset(fl, 0, sizeof(struct flowi));
 	ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr);
 	ipv6_addr_copy(&fl->fl6_src, &hdr->saddr);
 
-	while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) {
-		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+	while (pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
+		nh = skb_network_header(skb);
+		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 
 		switch (nexthdr) {
 		case NEXTHDR_ROUTING:
@@ -288,7 +291,7 @@ _decode_session6(struct sk_buff *skb, st
 		case NEXTHDR_DEST:
 			offset += ipv6_optlen(exthdr);
 			nexthdr = exthdr->nexthdr;
-			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+			exthdr = (struct ipv6_opt_hdr *)(nh + offset);
 			break;
 
 		case IPPROTO_UDP:
@@ -296,7 +299,7 @@ _decode_session6(struct sk_buff *skb, st
 		case IPPROTO_TCP:
 		case IPPROTO_SCTP:
 		case IPPROTO_DCCP:
-			if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) {
+			if (pskb_may_pull(skb, nh + offset + 4 - skb->data)) {
 				__be16 *ports = (__be16 *)exthdr;
 
 				fl->fl_ip_sport = ports[0];
@@ -306,7 +309,7 @@ _decode_session6(struct sk_buff *skb, st
 			return;
 
 		case IPPROTO_ICMPV6:
-			if (pskb_may_pull(skb, skb->nh.raw + offset + 2 - skb->data)) {
+			if (pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
 				u8 *icmp = (u8 *)exthdr;
 
 				fl->fl_icmp_type = icmp[0];
@@ -317,7 +320,7 @@ _decode_session6(struct sk_buff *skb, st
 
 #ifdef CONFIG_IPV6_MIP6
 		case IPPROTO_MH:
-			if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) {
+			if (pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
 				struct ip6_mh *mh;
 				mh = (struct ip6_mh *)exthdr;
 
@@ -335,7 +338,7 @@ #endif
 			fl->fl_ipsec_spi = 0;
 			fl->proto = nexthdr;
 			return;
-		};
+		}
 	}
 }
 
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 93c4223..5502cc9 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -257,11 +257,11 @@ static int xfrm6_tunnel_input(struct xfr
 
 static int xfrm6_tunnel_rcv(struct sk_buff *skb)
 {
-	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct ipv6hdr *iph = ipv6_hdr(skb);
 	__be32 spi;
 
 	spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
-	return xfrm6_rcv_spi(skb, spi);
+	return xfrm6_rcv_spi(skb, spi) > 0 ? : 0;
 }
 
 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index cac35a7..15419dd 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -576,7 +576,9 @@ static struct sk_buff *ipxitf_adjust_skb
 	skb2 = alloc_skb(len, GFP_ATOMIC);
 	if (skb2) {
 		skb_reserve(skb2, out_offset);
-		skb2->nh.raw = skb2->h.raw = skb_put(skb2, skb->len);
+		skb_reset_network_header(skb2);
+		skb_reset_transport_header(skb2);
+		skb_put(skb2, skb->len);
 		memcpy(ipx_hdr(skb2), ipx_hdr(skb), skb->len);
 		memcpy(skb2->cb, skb->cb, sizeof(skb->cb));
 	}
@@ -1807,8 +1809,8 @@ #endif	/* CONFIG_IPX_INTERN */
 				     copied);
 	if (rc)
 		goto out_free;
-	if (skb->tstamp.off_sec)
-		skb_get_timestamp(skb, &sk->sk_stamp);
+	if (skb->tstamp.tv64)
+		sk->sk_stamp = skb->tstamp;
 
 	msg->msg_namelen = sizeof(*sipx);
 
@@ -1959,7 +1961,6 @@ #endif
 	.sendpage	= sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
 SOCKOPS_WRAP(ipx_dgram, PF_IPX);
 
 static struct packet_type ipx_8023_packet_type = {
diff --git a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c
index 8e1cad9..e16c114 100644
--- a/net/ipx/ipx_route.c
+++ b/net/ipx/ipx_route.c
@@ -203,7 +203,9 @@ int ipxrtr_route_packet(struct sock *sk,
 	skb->sk = sk;
 
 	/* Fill in IPX header */
-	skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxhdr));
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
+	skb_put(skb, sizeof(struct ipxhdr));
 	ipx = ipx_hdr(skb);
 	ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
 	IPX_SKB_CB(skb)->ipx_tctrl = 0;
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 0eb7d59..dcd7e32 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -89,7 +89,6 @@ static int irda_data_indication(void *in
 
 	self = instance;
 	sk = instance;
-	IRDA_ASSERT(sk != NULL, return -1;);
 
 	err = sock_queue_rcv_skb(sk, skb);
 	if (err) {
@@ -131,14 +130,12 @@ static void irda_disconnect_indication(v
 	}
 
 	/* Prevent race conditions with irda_release() and irda_shutdown() */
+	bh_lock_sock(sk);
 	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);
-		release_sock(sk);
 
 		/* Close our TSAP.
 		 * If we leave it open, IrLMP put it back into the list of
@@ -158,6 +155,7 @@ static void irda_disconnect_indication(v
 			self->tsap = NULL;
 		}
 	}
+	bh_unlock_sock(sk);
 
 	/* Note : once we are there, there is not much you want to do
 	 * with the socket anymore, apart from closing it.
@@ -220,7 +218,7 @@ static void irda_connect_confirm(void *i
 		break;
 	default:
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
-	};
+	}
 
 	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
 		   self->max_data_size);
@@ -283,7 +281,7 @@ static void irda_connect_indication(void
 		break;
 	default:
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
-	};
+	}
 
 	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
 		   self->max_data_size);
@@ -306,8 +304,6 @@ static void irda_connect_response(struct
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	IRDA_ASSERT(self != NULL, return;);
-
 	skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
 			GFP_ATOMIC);
 	if (skb == NULL) {
@@ -337,7 +333,7 @@ static void irda_flow_indication(void *i
 
 	self = instance;
 	sk = instance;
-	IRDA_ASSERT(sk != NULL, return;);
+	BUG_ON(sk == NULL);
 
 	switch (flow) {
 	case FLOW_STOP:
@@ -449,7 +445,7 @@ static void irda_discovery_timeout(u_lon
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	self = (struct irda_sock *) priv;
-	IRDA_ASSERT(self != NULL, return;);
+	BUG_ON(self == NULL);
 
 	/* Nothing for the caller */
 	self->cachelog = NULL;
@@ -546,8 +542,6 @@ static int irda_find_lsap_sel(struct ird
 {
 	IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name);
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	if (self->iriap) {
 		IRDA_WARNING("%s(): busy with a previous query\n",
 			     __FUNCTION__);
@@ -635,8 +629,6 @@ static int irda_discover_daddr_and_lsap_
 
 	IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name);
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	/* Ask lmp for the current discovery log
 	 * Note : we have to use irlmp_get_discoveries(), as opposed
 	 * to play with the cachelog directly, because while we are
@@ -784,8 +776,6 @@ static int irda_bind(struct socket *sock
 	struct irda_sock *self = irda_sk(sk);
 	int err;
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
 	if (addr_len != sizeof(struct sockaddr_irda))
@@ -841,8 +831,6 @@ static int irda_accept(struct socket *so
 
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	err = irda_create(newsock, sk->sk_protocol);
 	if (err)
 		return err;
@@ -873,44 +861,28 @@ static int irda_accept(struct socket *so
 	 * calling us, the data is waiting for us ;-)
 	 * Jean II
 	 */
-	skb = skb_dequeue(&sk->sk_receive_queue);
-	if (skb == NULL) {
-		int ret = 0;
-		DECLARE_WAITQUEUE(waitq, current);
+	while (1) {
+		skb = skb_dequeue(&sk->sk_receive_queue);
+		if (skb)
+			break;
 
 		/* Non blocking operation */
 		if (flags & O_NONBLOCK)
 			return -EWOULDBLOCK;
 
-		/* The following code is a cut'n'paste of the
-		 * wait_event_interruptible() macro.
-		 * We don't us the macro because the condition has
-		 * side effects : we want to make sure that only one
-		 * skb get dequeued - Jean II */
-		add_wait_queue(sk->sk_sleep, &waitq);
-		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			skb = skb_dequeue(&sk->sk_receive_queue);
-			if (skb != NULL)
-				break;
-			if (!signal_pending(current)) {
-				schedule();
-				continue;
-			}
-			ret = -ERESTARTSYS;
-			break;
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &waitq);
-		if(ret)
-			return -ERESTARTSYS;
+		err = wait_event_interruptible(*(sk->sk_sleep),
+					skb_peek(&sk->sk_receive_queue));
+		if (err)
+			return err;
 	}
 
 	newsk = newsock->sk;
+	if (newsk == NULL)
+		return -EIO;
+
 	newsk->sk_state = TCP_ESTABLISHED;
 
 	new = irda_sk(newsk);
-	IRDA_ASSERT(new != NULL, return -1;);
 
 	/* Now attach up the new socket */
 	new->tsap = irttp_dup(self->tsap, new);
@@ -1061,7 +1033,8 @@ static int irda_connect(struct socket *s
 
 	if (sk->sk_state != TCP_ESTABLISHED) {
 		sock->state = SS_UNCONNECTED;
-		return sock_error(sk);	/* Always set at this point */
+		err = sock_error(sk);
+		return err? err : -ECONNRESET;
 	}
 
 	sock->state = SS_CONNECTED;
@@ -1171,8 +1144,6 @@ static void irda_destroy_socket(struct i
 {
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
-	IRDA_ASSERT(self != NULL, return;);
-
 	/* Unregister with IrLMP */
 	irlmp_unregister_client(self->ckey);
 	irlmp_unregister_service(self->skey);
@@ -1274,7 +1245,6 @@ static int irda_sendmsg(struct kiocb *io
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
 	struct sk_buff *skb;
-	unsigned char *asmptr;
 	int err;
 
 	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
@@ -1292,7 +1262,6 @@ static int irda_sendmsg(struct kiocb *io
 		return -ENOTCONN;
 
 	self = irda_sk(sk);
-	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Check if IrTTP is wants us to slow down */
 
@@ -1317,9 +1286,9 @@ static int irda_sendmsg(struct kiocb *io
 		return -ENOBUFS;
 
 	skb_reserve(skb, self->max_header_size + 16);
-
-	asmptr = skb->h.raw = skb_put(skb, len);
-	err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+	skb_reset_transport_header(skb);
+	skb_put(skb, len);
+	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
 		kfree_skb(skb);
 		return err;
@@ -1355,16 +1324,16 @@ 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;);
+	if ((err = sock_error(sk)) < 0)
+		return err;
 
 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
 				flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return err;
 
-	skb->h.raw = skb->data;
-	copied     = skb->len;
+	skb_reset_transport_header(skb);
+	copied = skb->len;
 
 	if (copied > size) {
 		IRDA_DEBUG(2, "%s(), Received truncated frame (%zd < %zd)!\n",
@@ -1403,13 +1372,13 @@ static int irda_recvmsg_stream(struct ki
 	struct irda_sock *self = irda_sk(sk);
 	int noblock = flags & MSG_DONTWAIT;
 	size_t copied = 0;
-	int target = 1;
-	DECLARE_WAITQUEUE(waitq, current);
+	int target, err;
+	long timeo;
 
 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
 
-	IRDA_ASSERT(self != NULL, return -1;);
-	IRDA_ASSERT(!sock_error(sk), return -1;);
+	if ((err = sock_error(sk)) < 0)
+		return err;
 
 	if (sock->flags & __SO_ACCEPTCON)
 		return(-EINVAL);
@@ -1417,8 +1386,8 @@ static int irda_recvmsg_stream(struct ki
 	if (flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
-	if (flags & MSG_WAITALL)
-		target = size;
+	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
+	timeo = sock_rcvtimeo(sk, noblock);
 
 	msg->msg_namelen = 0;
 
@@ -1426,19 +1395,14 @@ static int irda_recvmsg_stream(struct ki
 		int chunk;
 		struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
 
-		if (skb==NULL) {
+		if (skb == NULL) {
+			DEFINE_WAIT(wait);
 			int ret = 0;
 
 			if (copied >= target)
 				break;
 
-			/* The following code is a cut'n'paste of the
-			 * wait_event_interruptible() macro.
-			 * We don't us the macro because the test condition
-			 * is messy. - Jean II */
-			set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-			add_wait_queue(sk->sk_sleep, &waitq);
-			set_current_state(TASK_INTERRUPTIBLE);
+			prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 
 			/*
 			 *	POSIX 1003.1g mandates this order.
@@ -1451,17 +1415,17 @@ static int irda_recvmsg_stream(struct ki
 			else if (noblock)
 				ret = -EAGAIN;
 			else if (signal_pending(current))
-				ret = -ERESTARTSYS;
+				ret = sock_intr_errno(timeo);
+			else if (sk->sk_state != TCP_ESTABLISHED)
+				ret = -ENOTCONN;
 			else if (skb_peek(&sk->sk_receive_queue) == NULL)
 				/* Wait process until data arrives */
 				schedule();
 
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &waitq);
-			clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+			finish_wait(sk->sk_sleep, &wait);
 
-			if(ret)
-				return(ret);
+			if (ret)
+				return ret;
 			if (sk->sk_shutdown & RCV_SHUTDOWN)
 				break;
 
@@ -1530,7 +1494,6 @@ static int irda_sendmsg_dgram(struct kio
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
 	struct sk_buff *skb;
-	unsigned char *asmptr;
 	int err;
 
 	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
@@ -1547,7 +1510,6 @@ static int irda_sendmsg_dgram(struct kio
 		return -ENOTCONN;
 
 	self = irda_sk(sk);
-	IRDA_ASSERT(self != NULL, return -1;);
 
 	/*
 	 * Check that we don't send out too big frames. This is an unreliable
@@ -1566,10 +1528,11 @@ static int irda_sendmsg_dgram(struct kio
 		return -ENOBUFS;
 
 	skb_reserve(skb, self->max_header_size);
+	skb_reset_transport_header(skb);
 
 	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
-	asmptr = skb->h.raw = skb_put(skb, len);
-	err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+	skb_put(skb, len);
+	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
 		kfree_skb(skb);
 		return err;
@@ -1602,7 +1565,6 @@ static int irda_sendmsg_ultra(struct kio
 	__u8 pid = 0;
 	int bound = 0;
 	struct sk_buff *skb;
-	unsigned char *asmptr;
 	int err;
 
 	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
@@ -1616,7 +1578,6 @@ static int irda_sendmsg_ultra(struct kio
 	}
 
 	self = irda_sk(sk);
-	IRDA_ASSERT(self != NULL, return -1;);
 
 	/* Check if an address was specified with sendto. Jean II */
 	if (msg->msg_name) {
@@ -1662,10 +1623,11 @@ static int irda_sendmsg_ultra(struct kio
 		return -ENOBUFS;
 
 	skb_reserve(skb, self->max_header_size);
+	skb_reset_transport_header(skb);
 
 	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
-	asmptr = skb->h.raw = skb_put(skb, len);
-	err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+	skb_put(skb, len);
+	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
 		kfree_skb(skb);
 		return err;
@@ -1689,8 +1651,6 @@ static int irda_shutdown(struct socket *
 	struct sock *sk = sock->sk;
 	struct irda_sock *self = irda_sk(sk);
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self);
 
 	sk->sk_state       = TCP_CLOSE;
@@ -1863,8 +1823,6 @@ static int irda_setsockopt(struct socket
 	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int opt;
 
-	IRDA_ASSERT(self != NULL, return -1;);
-
 	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
 
 	if (level != SOL_IRLMP)
@@ -2580,7 +2538,6 @@ #endif
 };
 #endif /* CONFIG_IRDA_ULTRA */
 
-#include <linux/smp_lock.h>
 SOCKOPS_WRAP(irda_stream, PF_IRDA);
 SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
 SOCKOPS_WRAP(irda_dgram, PF_IRDA);
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 01d7c9c..e5e4792 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -133,8 +133,8 @@ int ircomm_param_request(struct ircomm_t
 	 * Inserting is a little bit tricky since we don't know how much
 	 * room we will need. But this should hopefully work OK
 	 */
-	count = irda_param_insert(self, pi, skb->tail, skb_tailroom(skb),
-				  &ircomm_param_info);
+	count = irda_param_insert(self, pi, skb_tail_pointer(skb),
+				  skb_tailroom(skb), &ircomm_param_info);
 	if (count < 0) {
 		IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
 		spin_unlock_irqrestore(&self->spinlock, flags);
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index e717801..7b5def1 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -375,7 +375,7 @@ EXPORT_SYMBOL(alloc_irdadev);
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
 {
 	struct dongle_reg *reg;
-	dongle_t *dongle = NULL;
+	dongle_t *dongle = kzalloc(sizeof(dongle_t), GFP_KERNEL);
 
 	might_sleep();
 
@@ -397,19 +397,14 @@ #endif
 	if (!reg || !try_module_get(reg->owner) ) {
 		IRDA_ERROR("IrDA: Unable to find requested dongle type %x\n",
 			   type);
-		goto out;
+		kfree(dongle);
+		dongle = NULL;
+	}
+	if (dongle) {
+		/* Bind the registration info to this particular instance */
+		dongle->issue = reg;
+		dongle->dev = dev;
 	}
-
-	/* Allocate dongle info for this instance */
-	dongle = kzalloc(sizeof(dongle_t), GFP_KERNEL);
-	if (!dongle)
-		goto out;
-
-	/* Bind the registration info to this particular instance */
-	dongle->issue = reg;
-	dongle->dev = dev;
-
- out:
 	spin_unlock(&dongles->hb_spinlock);
 	return dongle;
 }
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index fcf9d65..ed69773 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -1039,7 +1039,7 @@ static int __irlan_insert_param(struct s
 	}
 
 	/* Insert at end of sk-buffer */
-	frame = skb->tail;
+	frame = skb_tail_pointer(skb);
 
 	/* Make space for data */
 	if (skb_tailroom(skb) < (param_len+value_len+3)) {
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 672ab3f..c421521 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -234,8 +234,7 @@ int irlan_eth_receive(void *instance, vo
 	 * might have been previously set by the low level IrDA network
 	 * device driver
 	 */
-	skb->dev = self->dev;
-	skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
+	skb->protocol = eth_type_trans(skb, self->dev); /* Remove eth header */
 
 	self->stats.rx_packets++;
 	self->stats.rx_bytes += skb->len;
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 7b6433f..0b02073 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -590,7 +590,7 @@ static int irlap_state_query(struct irla
 		if (!self->discovery_log) {
 			IRDA_WARNING("%s: discovery log is gone! "
 				     "maybe the discovery timeout has been set"
-				     " to short?\n", __FUNCTION__);
+				     " too short?\n", __FUNCTION__);
 			break;
 		}
 		hashbin_insert(self->discovery_log,
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 0b04603..3c5a68e 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -93,7 +93,9 @@ void irlap_queue_xmit(struct irlap_cb *s
 {
 	/* Some common init stuff */
 	skb->dev = self->netdev;
-	skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
+	skb_reset_transport_header(skb);
 	skb->protocol = htons(ETH_P_IRDA);
 	skb->priority = TC_PRIO_BESTEFFORT;
 
@@ -411,7 +413,7 @@ static void irlap_recv_discovery_xid_rsp
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
 		return;
 	}
 
@@ -482,7 +484,7 @@ static void irlap_recv_discovery_xid_cmd
 	char *text;
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
 		return;
 	}
 
@@ -526,7 +528,7 @@ static void irlap_recv_discovery_xid_cmd
 		/* Check if things are sane at this point... */
 		if((discovery_info == NULL) ||
 		   !pskb_may_pull(skb, 3)) {
-			IRDA_ERROR("%s: discovery frame to short!\n",
+			IRDA_ERROR("%s: discovery frame too short!\n",
 				   __FUNCTION__);
 			return;
 		}
@@ -1171,7 +1173,7 @@ static void irlap_recv_frmr_frame(struct
 	IRDA_ASSERT(info != NULL, return;);
 
 	if (!pskb_may_pull(skb, 4)) {
-		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
 		return;
 	}
 
@@ -1260,7 +1262,7 @@ static void irlap_recv_test_frame(struct
 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	if (!pskb_may_pull(skb, sizeof(*frame))) {
-		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
 		return;
 	}
 	frame = (struct test_frame *) skb->data;
@@ -1268,7 +1270,7 @@ static void irlap_recv_test_frame(struct
 	/* Broadcast frames must carry saddr and daddr fields */
 	if (info->caddr == CBROADCAST) {
 		if (skb->len < sizeof(struct test_frame)) {
-			IRDA_DEBUG(0, "%s() test frame to short!\n",
+			IRDA_DEBUG(0, "%s() test frame too short!\n",
 				   __FUNCTION__);
 			return;
 		}
@@ -1334,7 +1336,7 @@ int irlap_driver_rcv(struct sk_buff *skb
 
 	/* Check if frame is large enough for parsing */
 	if (!pskb_may_pull(skb, 2)) {
-		IRDA_ERROR("%s: frame to short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
 		dev_kfree_skb(skb);
 		return -1;
 	}
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index 9266233..d058b46 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -384,6 +384,9 @@ EXPORT_SYMBOL(hashbin_new);
  *    for deallocating this structure if it's complex. If not the user can
  *    just supply kfree, which should take care of the job.
  */
+#ifdef CONFIG_LOCKDEP
+static int hashbin_lock_depth = 0;
+#endif
 int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
 {
 	irda_queue_t* queue;
@@ -395,7 +398,8 @@ int hashbin_delete( hashbin_t* hashbin, 
 
 	/* Synchronize */
 	if ( hashbin->hb_type & HB_LOCK ) {
-		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+		spin_lock_irqsave_nested(&hashbin->hb_spinlock, flags,
+					 hashbin_lock_depth++);
 	}
 
 	/*
@@ -419,6 +423,9 @@ int hashbin_delete( hashbin_t* hashbin, 
 	/* Release lock */
 	if ( hashbin->hb_type & HB_LOCK) {
 		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+#ifdef CONFIG_LOCKDEP
+		hashbin_lock_depth--;
+#endif
 	}
 
 	/*
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index da3f2bc..7069e4a 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -256,7 +256,7 @@ static struct sk_buff *irttp_reassemble_
 	 *  Copy all fragments to a new buffer
 	 */
 	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
-		memcpy(skb->data+n, frag->data, frag->len);
+		skb_copy_to_linear_data_offset(skb, n, frag->data, frag->len);
 		n += frag->len;
 
 		dev_kfree_skb(frag);
@@ -314,8 +314,8 @@ static inline void irttp_fragment_skb(st
 		skb_reserve(frag, self->max_header_size);
 
 		/* Copy data from the original skb into this fragment. */
-		memcpy(skb_put(frag, self->max_seg_size), skb->data,
-		       self->max_seg_size);
+		skb_copy_from_linear_data(skb, skb_put(frag, self->max_seg_size),
+			      self->max_seg_size);
 
 		/* Insert TTP header, with the more bit set */
 		frame = skb_push(frag, TTP_HEADER);
@@ -551,7 +551,7 @@ int irttp_udata_request(struct tsap_cb *
 	}
 
 	if (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(1, "%s(), UData is to large for IrLAP!\n",
+		IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",
 			   __FUNCTION__);
 		goto err;
 	}
@@ -598,7 +598,7 @@ int irttp_data_request(struct tsap_cb *s
 	 *  inside an IrLAP frame
 	 */
 	if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
-		IRDA_ERROR("%s: SAR disabled, and data is to large for IrLAP!\n",
+		IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n",
 			   __FUNCTION__);
 		ret = -EMSGSIZE;
 		goto err;
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index 75a72d2..2627dad 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -160,7 +160,7 @@ static int irda_insert_integer(void *sel
 	}
 	/* Check if buffer is long enough for insertion */
 	if (len < (2+p.pl)) {
-		IRDA_WARNING("%s: buffer to short for insertion!\n",
+		IRDA_WARNING("%s: buffer too short for insertion!\n",
 			     __FUNCTION__);
 		return -1;
 	}
@@ -216,7 +216,7 @@ static int irda_extract_integer(void *se
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		IRDA_WARNING("%s: buffer to short for parsing! "
+		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
 			     __FUNCTION__, p.pl, len);
 		return -1;
@@ -304,7 +304,7 @@ static int irda_extract_string(void *sel
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		IRDA_WARNING("%s: buffer to short for parsing! "
+		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
 			     __FUNCTION__, p.pl, len);
 		return -1;
@@ -343,7 +343,7 @@ static int irda_extract_octseq(void *sel
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
-		IRDA_WARNING("%s: buffer to short for parsing! "
+		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
 			     __FUNCTION__, p.pl, len);
 		return -1;
diff --git a/net/irda/qos.c b/net/irda/qos.c
index 349012c..aeb18cf 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -469,49 +469,49 @@ int irlap_insert_qos_negotiation_params(
 	int ret;
 
 	/* Insert data rate */
-	ret = irda_param_insert(self, PI_BAUD_RATE, skb->tail,
+	ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert max turnaround time */
-	ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb->tail,
+	ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert data size */
-	ret = irda_param_insert(self, PI_DATA_SIZE, skb->tail,
+	ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert window size */
-	ret = irda_param_insert(self, PI_WINDOW_SIZE, skb->tail,
+	ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert additional BOFs */
-	ret = irda_param_insert(self, PI_ADD_BOFS, skb->tail,
+	ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert minimum turnaround time */
-	ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb->tail,
+	ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
 	skb_put(skb, ret);
 
 	/* Insert link disconnect/threshold time */
-	ret = irda_param_insert(self, PI_LINK_DISC, skb->tail,
+	ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb),
 				skb_tailroom(skb), &irlap_param_info);
 	if (ret < 0)
 		return ret;
diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c
index 5abfb71..a7a7f19 100644
--- a/net/irda/wrapper.c
+++ b/net/irda/wrapper.c
@@ -239,7 +239,8 @@ async_bump(struct net_device *dev,
 
 	if(docopy) {
 		/* Copy data without CRC (lenght already checked) */
-		memcpy(newskb->data, rx_buff->data, rx_buff->len - 2);
+		skb_copy_to_linear_data(newskb, rx_buff->data,
+					rx_buff->len - 2);
 		/* Deliver this skb */
 		dataskb = newskb;
 	} else {
@@ -256,7 +257,7 @@ async_bump(struct net_device *dev,
 
 	/* Feed it to IrLAP layer */
 	dataskb->dev = dev;
-	dataskb->mac.raw  = dataskb->data;
+	skb_reset_mac_header(dataskb);
 	dataskb->protocol = htons(ETH_P_IRDA);
 
 	netif_rx(dataskb);
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index acc9421..d9e9ddb 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -45,7 +45,8 @@ static struct proto iucv_proto = {
 static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
 static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
 static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
-static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8],
+				 u8 ipuser[16]);
 static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
 
 static struct iucv_sock_list iucv_sk_list = {
@@ -147,11 +148,12 @@ static void iucv_sock_close(struct sock 
 	unsigned char user_data[16];
 	struct iucv_sock *iucv = iucv_sk(sk);
 	int err;
+	unsigned long timeo;
 
 	iucv_sock_clear_timer(sk);
 	lock_sock(sk);
 
-	switch(sk->sk_state) {
+	switch (sk->sk_state) {
 	case IUCV_LISTEN:
 		iucv_sock_cleanup_listen(sk);
 		break;
@@ -159,6 +161,21 @@ static void iucv_sock_close(struct sock 
 	case IUCV_CONNECTED:
 	case IUCV_DISCONN:
 		err = 0;
+
+		sk->sk_state = IUCV_CLOSING;
+		sk->sk_state_change(sk);
+
+		if (!skb_queue_empty(&iucv->send_skb_q)) {
+			if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+				timeo = sk->sk_lingertime;
+			else
+				timeo = IUCV_DISCONN_TIMEOUT;
+			err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, timeo);
+		}
+
+		sk->sk_state = IUCV_CLOSED;
+		sk->sk_state_change(sk);
+
 		if (iucv->path) {
 			low_nmcpy(user_data, iucv->src_name);
 			high_nmcpy(user_data, iucv->dst_name);
@@ -168,12 +185,11 @@ static void iucv_sock_close(struct sock 
 			iucv->path = NULL;
 		}
 
-		sk->sk_state = IUCV_CLOSED;
-		sk->sk_state_change(sk);
 		sk->sk_err = ECONNRESET;
 		sk->sk_state_change(sk);
 
 		skb_queue_purge(&iucv->send_skb_q);
+		skb_queue_purge(&iucv->backlog_skb_q);
 
 		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
@@ -181,7 +197,7 @@ static void iucv_sock_close(struct sock 
 	default:
 		sock_set_flag(sk, SOCK_ZAPPED);
 		break;
-	};
+	}
 
 	release_sock(sk);
 	iucv_sock_kill(sk);
@@ -204,6 +220,7 @@ static struct sock *iucv_sock_alloc(stru
 	sock_init_data(sock, sk);
 	INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
 	skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
+	skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
 	iucv_sk(sk)->send_tag = 0;
 
 	sk->sk_destruct = iucv_sock_destruct;
@@ -276,7 +293,7 @@ struct sock *iucv_accept_dequeue(struct 
 	struct iucv_sock *isk, *n;
 	struct sock *sk;
 
-	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
 		sk = (struct sock *) isk;
 		lock_sock(sk);
 
@@ -510,7 +527,7 @@ static int iucv_sock_accept(struct socke
 	long timeo;
 	int err = 0;
 
-	lock_sock(sk);
+	lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
 
 	if (sk->sk_state != IUCV_LISTEN) {
 		err = -EBADFD;
@@ -521,7 +538,7 @@ static int iucv_sock_accept(struct socke
 
 	/* Wait for an incoming connection */
 	add_wait_queue_exclusive(sk->sk_sleep, &wait);
-	while (!(nsk = iucv_accept_dequeue(sk, newsock))){
+	while (!(nsk = iucv_accept_dequeue(sk, newsock))) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (!timeo) {
 			err = -EAGAIN;
@@ -530,7 +547,7 @@ static int iucv_sock_accept(struct socke
 
 		release_sock(sk);
 		timeo = schedule_timeout(timeo);
-		lock_sock(sk);
+		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
 
 		if (sk->sk_state != IUCV_LISTEN) {
 			err = -EBADFD;
@@ -602,13 +619,13 @@ static int iucv_sock_sendmsg(struct kioc
 		goto out;
 	}
 
-	if (sk->sk_state == IUCV_CONNECTED){
-		if(!(skb = sock_alloc_send_skb(sk, len,
-				       msg->msg_flags & MSG_DONTWAIT,
-				       &err)))
-			return err;
+	if (sk->sk_state == IUCV_CONNECTED) {
+		if (!(skb = sock_alloc_send_skb(sk, len,
+						msg->msg_flags & MSG_DONTWAIT,
+						&err)))
+			goto out;
 
-		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)){
+		if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
 			err = -EFAULT;
 			goto fail;
 		}
@@ -647,10 +664,16 @@ static int iucv_sock_recvmsg(struct kioc
 {
 	int noblock = flags & MSG_DONTWAIT;
 	struct sock *sk = sock->sk;
+	struct iucv_sock *iucv = iucv_sk(sk);
 	int target, copied = 0;
-	struct sk_buff *skb;
+	struct sk_buff *skb, *rskb, *cskb;
 	int err = 0;
 
+	if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) &&
+		skb_queue_empty(&iucv->backlog_skb_q) &&
+		skb_queue_empty(&sk->sk_receive_queue))
+		return 0;
+
 	if (flags & (MSG_OOB))
 		return -EOPNOTSUPP;
 
@@ -665,10 +688,12 @@ static int iucv_sock_recvmsg(struct kioc
 
 	copied = min_t(unsigned int, skb->len, len);
 
-	if (memcpy_toiovec(msg->msg_iov, skb->data, copied)) {
+	cskb = skb;
+	if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
 		skb_queue_head(&sk->sk_receive_queue, skb);
 		if (copied == 0)
 			return -EFAULT;
+		goto done;
 	}
 
 	len -= copied;
@@ -683,6 +708,18 @@ static int iucv_sock_recvmsg(struct kioc
 		}
 
 		kfree_skb(skb);
+
+		/* Queue backlog skbs */
+		rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
+		while (rskb) {
+			if (sock_queue_rcv_skb(sk, rskb)) {
+				skb_queue_head(&iucv_sk(sk)->backlog_skb_q,
+						rskb);
+				break;
+			} else {
+				rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
+			}
+		}
 	} else
 		skb_queue_head(&sk->sk_receive_queue, skb);
 
@@ -695,7 +732,7 @@ static inline unsigned int iucv_accept_p
 	struct iucv_sock *isk, *n;
 	struct sock *sk;
 
-	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+	list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
 		sk = (struct sock *) isk;
 
 		if (sk->sk_state == IUCV_CONNECTED)
@@ -726,12 +763,15 @@ unsigned int iucv_sock_poll(struct file 
 		mask |= POLLHUP;
 
 	if (!skb_queue_empty(&sk->sk_receive_queue) ||
-			(sk->sk_shutdown & RCV_SHUTDOWN))
+	    (sk->sk_shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
 	if (sk->sk_state == IUCV_CLOSED)
 		mask |= POLLHUP;
 
+	if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED)
+		mask |= POLLIN;
+
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
@@ -754,7 +794,7 @@ static int iucv_sock_shutdown(struct soc
 		return -EINVAL;
 
 	lock_sock(sk);
-	switch(sk->sk_state) {
+	switch (sk->sk_state) {
 	case IUCV_CLOSED:
 		err = -ENOTCONN;
 		goto fail;
@@ -770,7 +810,7 @@ static int iucv_sock_shutdown(struct soc
 		err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
 					(void *) prmmsg, 8);
 		if (err) {
-			switch(err) {
+			switch (err) {
 			case 1:
 				err = -ENOTCONN;
 				break;
@@ -817,13 +857,6 @@ static int iucv_sock_release(struct sock
 		iucv_sk(sk)->path = NULL;
 	}
 
-	if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime){
-		lock_sock(sk);
-		err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0,
-					   sk->sk_lingertime);
-		release_sock(sk);
-	}
-
 	sock_orphan(sk);
 	iucv_sock_kill(sk);
 	return err;
@@ -880,7 +913,7 @@ static int iucv_callback_connreq(struct 
 
 	/* Create the new socket */
 	nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC);
-	if (!nsk){
+	if (!nsk) {
 		err = iucv_path_sever(path, user_data);
 		goto fail;
 	}
@@ -903,7 +936,7 @@ static int iucv_callback_connreq(struct 
 
 	path->msglim = IUCV_QUEUELEN_DEFAULT;
 	err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
-	if (err){
+	if (err) {
 		err = iucv_path_sever(path, user_data);
 		goto fail;
 	}
@@ -927,18 +960,53 @@ static void iucv_callback_connack(struct
 	sk->sk_state_change(sk);
 }
 
+static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len,
+			     struct sk_buff_head *fragmented_skb_q)
+{
+	int dataleft, size, copied = 0;
+	struct sk_buff *nskb;
+
+	dataleft = len;
+	while (dataleft) {
+		if (dataleft >= sk->sk_rcvbuf / 4)
+			size = sk->sk_rcvbuf / 4;
+		else
+			size = dataleft;
+
+		nskb = alloc_skb(size, GFP_ATOMIC | GFP_DMA);
+		if (!nskb)
+			return -ENOMEM;
+
+		memcpy(nskb->data, skb->data + copied, size);
+		copied += size;
+		dataleft -= size;
+
+		skb_reset_transport_header(nskb);
+		skb_reset_network_header(nskb);
+		nskb->len = size;
+
+		skb_queue_tail(fragmented_skb_q, nskb);
+	}
+
+	return 0;
+}
+
 static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
 {
 	struct sock *sk = path->private;
-	struct sk_buff *skb;
+	struct iucv_sock *iucv = iucv_sk(sk);
+	struct sk_buff *skb, *fskb;
+	struct sk_buff_head fragmented_skb_q;
 	int rc;
 
+	skb_queue_head_init(&fragmented_skb_q);
+
 	if (sk->sk_shutdown & RCV_SHUTDOWN)
 		return;
 
 	skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA);
 	if (!skb) {
-		iucv_message_reject(path, msg);
+		iucv_path_sever(path, NULL);
 		return;
 	}
 
@@ -952,14 +1020,39 @@ static void iucv_callback_rx(struct iucv
 			kfree_skb(skb);
 			return;
 		}
+		if (skb->truesize >= sk->sk_rcvbuf / 4) {
+			rc = iucv_fragment_skb(sk, skb, msg->length,
+					       &fragmented_skb_q);
+			kfree_skb(skb);
+			skb = NULL;
+			if (rc) {
+				iucv_path_sever(path, NULL);
+				return;
+			}
+		} else {
+			skb_reset_transport_header(skb);
+			skb_reset_network_header(skb);
+			skb->len = msg->length;
+		}
+	}
+	/* Queue the fragmented skb */
+	fskb = skb_dequeue(&fragmented_skb_q);
+	while (fskb) {
+		if (!skb_queue_empty(&iucv->backlog_skb_q))
+			skb_queue_tail(&iucv->backlog_skb_q, fskb);
+		else if (sock_queue_rcv_skb(sk, fskb))
+			skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, fskb);
+		fskb = skb_dequeue(&fragmented_skb_q);
+	}
 
-		skb->h.raw = skb->data;
-		skb->nh.raw = skb->data;
-		skb->len = msg->length;
+	/* Queue the original skb if it exists (was not fragmented) */
+	if (skb) {
+		if (!skb_queue_empty(&iucv->backlog_skb_q))
+			skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb);
+		else if (sock_queue_rcv_skb(sk, skb))
+			skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb);
 	}
 
-	if (sock_queue_rcv_skb(sk, skb))
-		kfree_skb(skb);
 }
 
 static void iucv_callback_txdone(struct iucv_path *path,
@@ -971,17 +1064,27 @@ static void iucv_callback_txdone(struct 
 	struct sk_buff *list_skb = list->next;
 	unsigned long flags;
 
-	spin_lock_irqsave(&list->lock, flags);
+	if (list_skb) {
+		spin_lock_irqsave(&list->lock, flags);
+
+		do {
+			this = list_skb;
+			list_skb = list_skb->next;
+		} while (memcmp(&msg->tag, this->cb, 4) && list_skb);
+
+		spin_unlock_irqrestore(&list->lock, flags);
 
-	do {
-		this = list_skb;
-		list_skb = list_skb->next;
-	} while (memcmp(&msg->tag, this->cb, 4));
+		skb_unlink(this, &iucv_sk(sk)->send_skb_q);
+		kfree_skb(this);
+	}
 
-	spin_unlock_irqrestore(&list->lock, flags);
+	if (sk->sk_state == IUCV_CLOSING) {
+		if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
+			sk->sk_state = IUCV_CLOSED;
+			sk->sk_state_change(sk);
+		}
+	}
 
-	skb_unlink(this, &iucv_sk(sk)->send_skb_q);
-	kfree_skb(this);
 }
 
 static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
@@ -1022,7 +1125,7 @@ static struct net_proto_family iucv_sock
 	.create	= iucv_sock_create,
 };
 
-static int afiucv_init(void)
+static int __init afiucv_init(void)
 {
 	int err;
 
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 1b10d57..fb3faf7 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -32,7 +32,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -69,7 +68,7 @@ #define IUCV_IPFGMID	0x04
 #define IUCV_IPNORPY	0x10
 #define IUCV_IPALL	0x80
 
-static int iucv_bus_match (struct device *dev, struct device_driver *drv)
+static int iucv_bus_match(struct device *dev, struct device_driver *drv)
 {
 	return 0;
 }
@@ -78,8 +77,11 @@ struct bus_type iucv_bus = {
 	.name = "iucv",
 	.match = iucv_bus_match,
 };
+EXPORT_SYMBOL(iucv_bus);
 
 struct device *iucv_root;
+EXPORT_SYMBOL(iucv_root);
+
 static int iucv_available;
 
 /* General IUCV interrupt structure */
@@ -90,20 +92,43 @@ struct iucv_irq_data {
 	u32 res2[8];
 };
 
-struct iucv_work {
+struct iucv_irq_list {
 	struct list_head list;
 	struct iucv_irq_data data;
 };
 
-static LIST_HEAD(iucv_work_queue);
-static DEFINE_SPINLOCK(iucv_work_lock);
-
 static struct iucv_irq_data *iucv_irq_data;
 static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE;
 static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE;
 
-static void iucv_tasklet_handler(unsigned long);
-static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_handler,0);
+/*
+ * Queue of interrupt buffers lock for delivery via the tasklet
+ * (fast but can't call smp_call_function).
+ */
+static LIST_HEAD(iucv_task_queue);
+
+/*
+ * The tasklet for fast delivery of iucv interrupts.
+ */
+static void iucv_tasklet_fn(unsigned long);
+static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_fn,0);
+
+/*
+ * Queue of interrupt buffers for delivery via a work queue
+ * (slower but can call smp_call_function).
+ */
+static LIST_HEAD(iucv_work_queue);
+
+/*
+ * The work element to deliver path pending interrupts.
+ */
+static void iucv_work_fn(struct work_struct *work);
+static DECLARE_WORK(iucv_work, iucv_work_fn);
+
+/*
+ * Spinlock protecting task and work queue.
+ */
+static DEFINE_SPINLOCK(iucv_queue_lock);
 
 enum iucv_command_codes {
 	IUCV_QUERY = 0,
@@ -147,10 +172,10 @@ static unsigned long iucv_max_pathid;
 static DEFINE_SPINLOCK(iucv_table_lock);
 
 /*
- * iucv_tasklet_cpu: contains the number of the cpu executing the tasklet.
- * Needed for iucv_path_sever called from tasklet.
+ * iucv_active_cpu: contains the number of the cpu executing the tasklet
+ * or the work handler. Needed for iucv_path_sever called from tasklet.
  */
-static int iucv_tasklet_cpu = -1;
+static int iucv_active_cpu = -1;
 
 /*
  * Mutex and wait queue for iucv_register/iucv_unregister.
@@ -382,7 +407,7 @@ static void iucv_declare_cpu(void *data)
 	rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
 	if (rc) {
 		char *err = "Unknown";
-		switch(rc) {
+		switch (rc) {
 		case 0x03:
 			err = "Directory error";
 			break;
@@ -449,17 +474,19 @@ static void iucv_setmask_mp(void)
 {
 	int cpu;
 
+	preempt_disable();
 	for_each_online_cpu(cpu)
 		/* Enable all cpus with a declared buffer. */
 		if (cpu_isset(cpu, iucv_buffer_cpumask) &&
 		    !cpu_isset(cpu, iucv_irq_cpumask))
 			smp_call_function_on(iucv_allow_cpu, NULL, 0, 1, cpu);
+	preempt_enable();
 }
 
 /**
  * iucv_setmask_up
  *
- * Allow iucv interrupts on a single cpus.
+ * Allow iucv interrupts on a single cpu.
  */
 static void iucv_setmask_up(void)
 {
@@ -493,8 +520,10 @@ static int iucv_enable(void)
 		goto out;
 	/* Declare per cpu buffers. */
 	rc = -EIO;
+	preempt_disable();
 	for_each_online_cpu(cpu)
 		smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+	preempt_enable();
 	if (cpus_empty(iucv_buffer_cpumask))
 		/* No cpu could declare an iucv buffer. */
 		goto out_path;
@@ -519,7 +548,6 @@ static void iucv_disable(void)
 	kfree(iucv_path_table);
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
 static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
 				     unsigned long action, void *hcpu)
 {
@@ -562,10 +590,9 @@ static int __cpuinit iucv_cpu_notify(str
 	return NOTIFY_OK;
 }
 
-static struct notifier_block iucv_cpu_notifier = {
+static struct notifier_block __cpuinitdata iucv_cpu_notifier = {
 	.notifier_call = iucv_cpu_notify,
 };
-#endif
 
 /**
  * iucv_sever_pathid
@@ -586,48 +613,49 @@ static int iucv_sever_pathid(u16 pathid,
 	return iucv_call_b2f0(IUCV_SEVER, parm);
 }
 
+#ifdef CONFIG_SMP
 /**
- * __iucv_cleanup_pathid
+ * __iucv_cleanup_queue
  * @dummy: unused dummy argument
  *
  * Nop function called via smp_call_function to force work items from
  * pending external iucv interrupts to the work queue.
  */
-static void __iucv_cleanup_pathid(void *dummy)
+static void __iucv_cleanup_queue(void *dummy)
 {
 }
+#endif
 
 /**
- * iucv_cleanup_pathid
- * @pathid: 16 bit pathid
+ * iucv_cleanup_queue
  *
  * Function called after a path has been severed to find all remaining
  * work items for the now stale pathid. The caller needs to hold the
  * iucv_table_lock.
  */
-static void iucv_cleanup_pathid(u16 pathid)
+static void iucv_cleanup_queue(void)
 {
-	struct iucv_work *p, *n;
+	struct iucv_irq_list *p, *n;
 
 	/*
-	 * Path is severed, the pathid can be reused immediatly on
-	 * a iucv connect or a connection pending interrupt.
-	 * iucv_path_connect and connection pending interrupt will
-	 * wait until the iucv_table_lock is released before the
-	 * recycled pathid enters the system.
-	 * Force remaining interrupts to the work queue, then
-	 * scan the work queue for items of this path.
+	 * When a path is severed, the pathid can be reused immediatly
+	 * on a iucv connect or a connection pending interrupt. Remove
+	 * all entries from the task queue that refer to a stale pathid
+	 * (iucv_path_table[ix] == NULL). Only then do the iucv connect
+	 * or deliver the connection pending interrupt. To get all the
+	 * pending interrupts force them to the work queue by calling
+	 * an empty function on all cpus.
 	 */
-	smp_call_function(__iucv_cleanup_pathid, NULL, 0, 1);
-	spin_lock_irq(&iucv_work_lock);
-	list_for_each_entry_safe(p, n, &iucv_work_queue, list) {
-		/* Remove work items for pathid except connection pending */
-		if (p->data.ippathid == pathid && p->data.iptype != 0x01) {
+	smp_call_function(__iucv_cleanup_queue, NULL, 0, 1);
+	spin_lock_irq(&iucv_queue_lock);
+	list_for_each_entry_safe(p, n, &iucv_task_queue, list) {
+		/* Remove stale work items from the task queue. */
+		if (iucv_path_table[p->data.ippathid] == NULL) {
 			list_del(&p->list);
 			kfree(p);
 		}
 	}
-	spin_unlock_irq(&iucv_work_lock);
+	spin_unlock_irq(&iucv_queue_lock);
 }
 
 /**
@@ -665,6 +693,7 @@ out_mutex:
 	mutex_unlock(&iucv_register_mutex);
 	return rc;
 }
+EXPORT_SYMBOL(iucv_register);
 
 /**
  * iucv_unregister
@@ -686,7 +715,6 @@ void iucv_unregister(struct iucv_handler
 		iucv_sever_pathid(p->pathid, NULL);
 		iucv_path_table[p->pathid] = NULL;
 		list_del(&p->list);
-		iucv_cleanup_pathid(p->pathid);
 		iucv_path_free(p);
 	}
 	spin_unlock_bh(&iucv_table_lock);
@@ -698,6 +726,7 @@ void iucv_unregister(struct iucv_handler
 		iucv_setmask_mp();
 	mutex_unlock(&iucv_register_mutex);
 }
+EXPORT_SYMBOL(iucv_unregister);
 
 /**
  * iucv_path_accept
@@ -736,6 +765,7 @@ int iucv_path_accept(struct iucv_path *p
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_path_accept);
 
 /**
  * iucv_path_connect
@@ -759,9 +789,9 @@ int iucv_path_connect(struct iucv_path *
 	union iucv_param *parm;
 	int rc;
 
-	preempt_disable();
-	if (iucv_tasklet_cpu != smp_processor_id())
-		spin_lock_bh(&iucv_table_lock);
+	BUG_ON(in_atomic());
+	spin_lock_bh(&iucv_table_lock);
+	iucv_cleanup_queue();
 	parm = percpu_ptr(iucv_param, smp_processor_id());
 	memset(parm, 0, sizeof(union iucv_param));
 	parm->ctrl.ipmsglim = path->msglim;
@@ -796,11 +826,10 @@ int iucv_path_connect(struct iucv_path *
 			rc = -EIO;
 		}
 	}
-	if (iucv_tasklet_cpu != smp_processor_id())
-		spin_unlock_bh(&iucv_table_lock);
-	preempt_enable();
+	spin_unlock_bh(&iucv_table_lock);
 	return rc;
 }
+EXPORT_SYMBOL(iucv_path_connect);
 
 /**
  * iucv_path_quiesce:
@@ -827,6 +856,7 @@ int iucv_path_quiesce(struct iucv_path *
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_path_quiesce);
 
 /**
  * iucv_path_resume:
@@ -867,21 +897,20 @@ int iucv_path_sever(struct iucv_path *pa
 {
 	int rc;
 
-
 	preempt_disable();
-	if (iucv_tasklet_cpu != smp_processor_id())
+	if (iucv_active_cpu != smp_processor_id())
 		spin_lock_bh(&iucv_table_lock);
 	rc = iucv_sever_pathid(path->pathid, userdata);
 	if (!rc) {
 		iucv_path_table[path->pathid] = NULL;
 		list_del_init(&path->list);
-		iucv_cleanup_pathid(path->pathid);
 	}
-	if (iucv_tasklet_cpu != smp_processor_id())
+	if (iucv_active_cpu != smp_processor_id())
 		spin_unlock_bh(&iucv_table_lock);
 	preempt_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_path_sever);
 
 /**
  * iucv_message_purge
@@ -914,6 +943,7 @@ int iucv_message_purge(struct iucv_path 
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_purge);
 
 /**
  * iucv_message_receive
@@ -984,6 +1014,7 @@ int iucv_message_receive(struct iucv_pat
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_receive);
 
 /**
  * iucv_message_reject
@@ -1012,6 +1043,7 @@ int iucv_message_reject(struct iucv_path
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_reject);
 
 /**
  * iucv_message_reply
@@ -1055,6 +1087,7 @@ int iucv_message_reply(struct iucv_path 
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_reply);
 
 /**
  * iucv_message_send
@@ -1103,6 +1136,7 @@ int iucv_message_send(struct iucv_path *
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_send);
 
 /**
  * iucv_message_send2way
@@ -1159,6 +1193,7 @@ int iucv_message_send2way(struct iucv_pa
 	local_bh_enable();
 	return rc;
 }
+EXPORT_SYMBOL(iucv_message_send2way);
 
 /**
  * iucv_path_pending
@@ -1246,8 +1281,7 @@ static void iucv_path_complete(struct iu
 	struct iucv_path_complete *ipc = (void *) data;
 	struct iucv_path *path = iucv_path_table[ipc->ippathid];
 
-	BUG_ON(!path || !path->handler);
-	if (path->handler->path_complete)
+	if (path && path->handler && path->handler->path_complete)
 		path->handler->path_complete(path, ipc->ipuser);
 }
 
@@ -1275,14 +1309,14 @@ static void iucv_path_severed(struct iuc
 	struct iucv_path_severed *ips = (void *) data;
 	struct iucv_path *path = iucv_path_table[ips->ippathid];
 
-	BUG_ON(!path || !path->handler);
+	if (!path || !path->handler)	/* Already severed */
+		return;
 	if (path->handler->path_severed)
 		path->handler->path_severed(path, ips->ipuser);
 	else {
 		iucv_sever_pathid(path->pathid, NULL);
 		iucv_path_table[path->pathid] = NULL;
 		list_del_init(&path->list);
-		iucv_cleanup_pathid(path->pathid);
 		iucv_path_free(path);
 	}
 }
@@ -1311,8 +1345,7 @@ static void iucv_path_quiesced(struct iu
 	struct iucv_path_quiesced *ipq = (void *) data;
 	struct iucv_path *path = iucv_path_table[ipq->ippathid];
 
-	BUG_ON(!path || !path->handler);
-	if (path->handler->path_quiesced)
+	if (path && path->handler && path->handler->path_quiesced)
 		path->handler->path_quiesced(path, ipq->ipuser);
 }
 
@@ -1340,8 +1373,7 @@ static void iucv_path_resumed(struct iuc
 	struct iucv_path_resumed *ipr = (void *) data;
 	struct iucv_path *path = iucv_path_table[ipr->ippathid];
 
-	BUG_ON(!path || !path->handler);
-	if (path->handler->path_resumed)
+	if (path && path->handler && path->handler->path_resumed)
 		path->handler->path_resumed(path, ipr->ipuser);
 }
 
@@ -1373,8 +1405,7 @@ static void iucv_message_complete(struct
 	struct iucv_path *path = iucv_path_table[imc->ippathid];
 	struct iucv_message msg;
 
-	BUG_ON(!path || !path->handler);
-	if (path->handler->message_complete) {
+	if (path && path->handler && path->handler->message_complete) {
 		msg.flags = imc->ipflags1;
 		msg.id = imc->ipmsgid;
 		msg.audit = imc->ipaudit;
@@ -1419,8 +1450,7 @@ static void iucv_message_pending(struct 
 	struct iucv_path *path = iucv_path_table[imp->ippathid];
 	struct iucv_message msg;
 
-	BUG_ON(!path || !path->handler);
-	if (path->handler->message_pending) {
+	if (path && path->handler && path->handler->message_pending) {
 		msg.flags = imp->ipflags1;
 		msg.id = imp->ipmsgid;
 		msg.class = imp->iptrgcls;
@@ -1435,17 +1465,16 @@ static void iucv_message_pending(struct 
 }
 
 /**
- * iucv_tasklet_handler:
+ * iucv_tasklet_fn:
  *
  * This tasklet loops over the queue of irq buffers created by
  * iucv_external_interrupt, calls the appropriate action handler
  * and then frees the buffer.
  */
-static void iucv_tasklet_handler(unsigned long ignored)
+static void iucv_tasklet_fn(unsigned long ignored)
 {
 	typedef void iucv_irq_fn(struct iucv_irq_data *);
 	static iucv_irq_fn *irq_fn[] = {
-		[0x01] = iucv_path_pending,
 		[0x02] = iucv_path_complete,
 		[0x03] = iucv_path_severed,
 		[0x04] = iucv_path_quiesced,
@@ -1455,38 +1484,70 @@ static void iucv_tasklet_handler(unsigne
 		[0x08] = iucv_message_pending,
 		[0x09] = iucv_message_pending,
 	};
-	struct iucv_work *p;
+	struct list_head task_queue = LIST_HEAD_INIT(task_queue);
+	struct iucv_irq_list *p, *n;
 
 	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
 	spin_lock(&iucv_table_lock);
-	iucv_tasklet_cpu = smp_processor_id();
+	iucv_active_cpu = smp_processor_id();
 
-	spin_lock_irq(&iucv_work_lock);
-	while (!list_empty(&iucv_work_queue)) {
-		p = list_entry(iucv_work_queue.next, struct iucv_work, list);
+	spin_lock_irq(&iucv_queue_lock);
+	list_splice_init(&iucv_task_queue, &task_queue);
+	spin_unlock_irq(&iucv_queue_lock);
+
+	list_for_each_entry_safe(p, n, &task_queue, list) {
 		list_del_init(&p->list);
-		spin_unlock_irq(&iucv_work_lock);
 		irq_fn[p->data.iptype](&p->data);
 		kfree(p);
-		spin_lock_irq(&iucv_work_lock);
 	}
-	spin_unlock_irq(&iucv_work_lock);
 
-	iucv_tasklet_cpu = -1;
+	iucv_active_cpu = -1;
 	spin_unlock(&iucv_table_lock);
 }
 
 /**
+ * iucv_work_fn:
+ *
+ * This work function loops over the queue of path pending irq blocks
+ * created by iucv_external_interrupt, calls the appropriate action
+ * handler and then frees the buffer.
+ */
+static void iucv_work_fn(struct work_struct *work)
+{
+	typedef void iucv_irq_fn(struct iucv_irq_data *);
+	struct list_head work_queue = LIST_HEAD_INIT(work_queue);
+	struct iucv_irq_list *p, *n;
+
+	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
+	spin_lock_bh(&iucv_table_lock);
+	iucv_active_cpu = smp_processor_id();
+
+	spin_lock_irq(&iucv_queue_lock);
+	list_splice_init(&iucv_work_queue, &work_queue);
+	spin_unlock_irq(&iucv_queue_lock);
+
+	iucv_cleanup_queue();
+	list_for_each_entry_safe(p, n, &work_queue, list) {
+		list_del_init(&p->list);
+		iucv_path_pending(&p->data);
+		kfree(p);
+	}
+
+	iucv_active_cpu = -1;
+	spin_unlock_bh(&iucv_table_lock);
+}
+
+/**
  * iucv_external_interrupt
  * @code: irq code
  *
  * Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
+ * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
  */
 static void iucv_external_interrupt(u16 code)
 {
 	struct iucv_irq_data *p;
-	struct iucv_work *work;
+	struct iucv_irq_list *work;
 
 	p = percpu_ptr(iucv_irq_data, smp_processor_id());
 	if (p->ippathid >= iucv_max_pathid) {
@@ -1500,16 +1561,23 @@ static void iucv_external_interrupt(u16 
 		printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");
 		return;
 	}
-	work = kmalloc(sizeof(struct iucv_work), GFP_ATOMIC);
+	work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
 	if (!work) {
 		printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
 		return;
 	}
 	memcpy(&work->data, p, sizeof(work->data));
-	spin_lock(&iucv_work_lock);
-	list_add_tail(&work->list, &iucv_work_queue);
-	spin_unlock(&iucv_work_lock);
-	tasklet_schedule(&iucv_tasklet);
+	spin_lock(&iucv_queue_lock);
+	if (p->iptype == 0x01) {
+		/* Path pending interrupt. */
+		list_add_tail(&work->list, &iucv_work_queue);
+		schedule_work(&iucv_work);
+	} else {
+		/* The other interrupts. */
+		list_add_tail(&work->list, &iucv_task_queue);
+		tasklet_schedule(&iucv_tasklet);
+	}
+	spin_unlock(&iucv_queue_lock);
 }
 
 /**
@@ -1517,7 +1585,7 @@ static void iucv_external_interrupt(u16 
  *
  * Allocates and initializes various data structures.
  */
-static int iucv_init(void)
+static int __init iucv_init(void)
 {
 	int rc;
 
@@ -1528,7 +1596,7 @@ static int iucv_init(void)
 	rc = iucv_query_maxconn();
 	if (rc)
 		goto out;
-	rc = register_external_interrupt (0x4000, iucv_external_interrupt);
+	rc = register_external_interrupt(0x4000, iucv_external_interrupt);
 	if (rc)
 		goto out;
 	rc = bus_register(&iucv_bus);
@@ -1539,7 +1607,7 @@ static int iucv_init(void)
 		rc = PTR_ERR(iucv_root);
 		goto out_bus;
 	}
-	/* Note: GFP_DMA used used to get memory below 2G */
+	/* Note: GFP_DMA used to get memory below 2G */
 	iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data),
 				     GFP_KERNEL|GFP_DMA);
 	if (!iucv_irq_data) {
@@ -1577,14 +1645,16 @@ out:
  *
  * Frees everything allocated from iucv_init.
  */
-static void iucv_exit(void)
+static void __exit iucv_exit(void)
 {
-	struct iucv_work *p, *n;
+	struct iucv_irq_list *p, *n;
 
-	spin_lock_irq(&iucv_work_lock);
+	spin_lock_irq(&iucv_queue_lock);
+	list_for_each_entry_safe(p, n, &iucv_task_queue, list)
+		kfree(p);
 	list_for_each_entry_safe(p, n, &iucv_work_queue, list)
 		kfree(p);
-	spin_unlock_irq(&iucv_work_lock);
+	spin_unlock_irq(&iucv_queue_lock);
 	unregister_hotcpu_notifier(&iucv_cpu_notifier);
 	percpu_free(iucv_param);
 	percpu_free(iucv_irq_data);
@@ -1596,24 +1666,6 @@ static void iucv_exit(void)
 subsys_initcall(iucv_init);
 module_exit(iucv_exit);
 
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_register);
-EXPORT_SYMBOL (iucv_unregister);
-EXPORT_SYMBOL (iucv_path_accept);
-EXPORT_SYMBOL (iucv_path_connect);
-EXPORT_SYMBOL (iucv_path_quiesce);
-EXPORT_SYMBOL (iucv_path_sever);
-EXPORT_SYMBOL (iucv_message_purge);
-EXPORT_SYMBOL (iucv_message_receive);
-EXPORT_SYMBOL (iucv_message_reject);
-EXPORT_SYMBOL (iucv_message_reply);
-EXPORT_SYMBOL (iucv_message_send);
-EXPORT_SYMBOL (iucv_message_send2way);
-
 MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
 MODULE_LICENSE("GPL");
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 3450193..a994441 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -379,7 +379,7 @@ #endif
 		 */
 		return -EINVAL;
 		break;
-	};
+	}
 
 	return 0;
 }
@@ -3667,7 +3667,7 @@ static int pfkey_recvmsg(struct kiocb *k
 		copied = len;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (err)
 		goto out_free;
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index d12413c..d4b13a0 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -160,8 +160,14 @@ static struct packet_type llc_tr_packet_
 
 static int __init llc_init(void)
 {
-	if (dev_base->next)
-		memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+	struct net_device *dev;
+
+	dev = first_net_device();
+	if (dev != NULL)
+		dev = next_net_device(dev);
+
+	if (dev != NULL)
+		memcpy(llc_station_mac_sa, dev->dev_addr, ETH_ALEN);
 	else
 		memset(llc_station_mac_sa, 0, ETH_ALEN);
 	dev_add_pack(&llc_packet_type);
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index b3f65d1..099ed8f 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -112,7 +112,7 @@ static inline int llc_fixup_skb(struct s
 	if (unlikely(!pskb_may_pull(skb, llc_len)))
 		return 0;
 
-	skb->h.raw += llc_len;
+	skb->transport_header += llc_len;
 	skb_pull(skb, llc_len);
 	if (skb->protocol == htons(ETH_P_802_2)) {
 		__be16 pdulen = eth_hdr(skb)->h_proto;
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c
index f4291f3..754f4fe 100644
--- a/net/llc/llc_output.c
+++ b/net/llc/llc_output.c
@@ -41,7 +41,8 @@ #ifdef CONFIG_TR
 		struct net_device *dev = skb->dev;
 		struct trh_hdr *trh;
 
-		skb->mac.raw = skb_push(skb, sizeof(*trh));
+		skb_push(skb, sizeof(*trh));
+		skb_reset_mac_header(skb);
 		trh = tr_hdr(skb);
 		trh->ac = AC;
 		trh->fc = LLC_FRAME;
@@ -52,7 +53,7 @@ #ifdef CONFIG_TR
 		if (da) {
 			memcpy(trh->daddr, da, dev->addr_len);
 			tr_source_route(skb, trh, dev);
-			skb->mac.raw = skb->data;
+			skb_reset_mac_header(skb);
 		}
 		break;
 	}
@@ -62,7 +63,8 @@ #endif
 		unsigned short len = skb->len;
 		struct ethhdr *eth;
 
-		skb->mac.raw = skb_push(skb, sizeof(*eth));
+		skb_push(skb, sizeof(*eth));
+		skb_reset_mac_header(skb);
 		eth = eth_hdr(skb);
 		eth->h_proto = htons(len);
 		memcpy(eth->h_dest, da, ETH_ALEN);
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 2615dc8..2525165 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -36,11 +36,12 @@ struct sk_buff *llc_alloc_frame(struct s
 	struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
 
 	if (skb) {
+		skb_reset_mac_header(skb);
 		skb_reserve(skb, 50);
-		skb->nh.raw   = skb->h.raw = skb->data;
+		skb_reset_network_header(skb);
+		skb_reset_transport_header(skb);
 		skb->protocol = htons(ETH_P_802_2);
 		skb->dev      = dev;
-		skb->mac.raw  = skb->head;
 		if (sk != NULL)
 			skb_set_owner_w(skb, sk);
 	}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
new file mode 100644
index 0000000..6fffb38
--- /dev/null
+++ b/net/mac80211/Kconfig
@@ -0,0 +1,78 @@
+config MAC80211
+	tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
+	depends on EXPERIMENTAL
+	select CRYPTO
+	select CRYPTO_ECB
+	select CRYPTO_ARC4
+	select CRYPTO_AES
+	select CRC32
+	select WIRELESS_EXT
+	select CFG80211
+	select NET_SCH_FIFO
+	---help---
+	This option enables the hardware independent IEEE 802.11
+	networking stack.
+
+config MAC80211_LEDS
+	bool "Enable LED triggers"
+	depends on MAC80211 && LEDS_TRIGGERS
+	---help---
+	This option enables a few LED triggers for different
+	packet receive/transmit events.
+
+config MAC80211_DEBUGFS
+	bool "Export mac80211 internals in DebugFS"
+	depends on MAC80211 && DEBUG_FS
+	---help---
+	  Select this to see extensive information about
+	  the internal state of mac80211 in debugfs.
+
+	  Say N unless you know you need this.
+
+config MAC80211_DEBUG
+	bool "Enable debugging output"
+	depends on MAC80211
+	---help---
+	  This option will enable debug tracing output for the
+	  ieee80211 network stack.
+
+	  If you are not trying to debug or develop the ieee80211
+	  subsystem, you most likely want to say N here.
+
+config MAC80211_VERBOSE_DEBUG
+	bool "Verbose debugging output"
+	depends on MAC80211_DEBUG
+
+config MAC80211_LOWTX_FRAME_DUMP
+	bool "Debug frame dumping"
+	depends on MAC80211_DEBUG
+	---help---
+	  Selecting this option will cause the stack to
+	  print a message for each frame that is handed
+	  to the lowlevel driver for transmission. This
+	  message includes all MAC addresses and the
+	  frame control field.
+
+	  If unsure, say N and insert the debugging code
+	  you require into the driver you are debugging.
+
+config TKIP_DEBUG
+	bool "TKIP debugging"
+	depends on MAC80211_DEBUG
+
+config MAC80211_DEBUG_COUNTERS
+	bool "Extra statistics for TX/RX debugging"
+	depends on MAC80211_DEBUG
+
+config MAC80211_IBSS_DEBUG
+	bool "Support for IBSS testing"
+	depends on MAC80211_DEBUG
+	---help---
+	  Say Y here if you intend to debug the IBSS code.
+
+config MAC80211_VERBOSE_PS_DEBUG
+	bool "Verbose powersave mode debugging"
+	depends on MAC80211_DEBUG
+	---help---
+	  Say Y here to print out verbose powersave
+	  mode debug messages.
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
new file mode 100644
index 0000000..e9738da
--- /dev/null
+++ b/net/mac80211/Makefile
@@ -0,0 +1,20 @@
+obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
+
+mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
+mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
+
+mac80211-objs := \
+	ieee80211.o \
+	ieee80211_ioctl.o \
+	sta_info.o \
+	wep.o \
+	wpa.o \
+	ieee80211_sta.o \
+	ieee80211_iface.o \
+	ieee80211_rate.o \
+	michael.o \
+	tkip.o \
+	aes_ccm.o \
+	wme.o \
+	ieee80211_cfg.o \
+	$(mac80211-objs-y)
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
new file mode 100644
index 0000000..e55569b
--- /dev/null
+++ b/net/mac80211/aes_ccm.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape 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/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <asm/scatterlist.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_key.h"
+#include "aes_ccm.h"
+
+
+static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
+				  const u8 pt[16], u8 ct[16])
+{
+	crypto_cipher_encrypt_one(tfm, ct, pt);
+}
+
+
+static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+				   u8 *b, u8 *s_0, u8 *a)
+{
+	int i;
+
+	ieee80211_aes_encrypt(tfm, b_0, b);
+
+	/* Extra Authenticate-only data (always two AES blocks) */
+	for (i = 0; i < AES_BLOCK_LEN; i++)
+		aad[i] ^= b[i];
+	ieee80211_aes_encrypt(tfm, aad, b);
+
+	aad += AES_BLOCK_LEN;
+
+	for (i = 0; i < AES_BLOCK_LEN; i++)
+		aad[i] ^= b[i];
+	ieee80211_aes_encrypt(tfm, aad, a);
+
+	/* Mask out bits from auth-only-b_0 */
+	b_0[0] &= 0x07;
+
+	/* S_0 is used to encrypt T (= MIC) */
+	b_0[14] = 0;
+	b_0[15] = 0;
+	ieee80211_aes_encrypt(tfm, b_0, s_0);
+}
+
+
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+			       u8 *b_0, u8 *aad, u8 *data, size_t data_len,
+			       u8 *cdata, u8 *mic)
+{
+	int i, j, last_len, num_blocks;
+	u8 *pos, *cpos, *b, *s_0, *e;
+
+	b = scratch;
+	s_0 = scratch + AES_BLOCK_LEN;
+	e = scratch + 2 * AES_BLOCK_LEN;
+
+	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+	last_len = data_len % AES_BLOCK_LEN;
+	aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
+
+	/* Process payload blocks */
+	pos = data;
+	cpos = cdata;
+	for (j = 1; j <= num_blocks; j++) {
+		int blen = (j == num_blocks && last_len) ?
+			last_len : AES_BLOCK_LEN;
+
+		/* Authentication followed by encryption */
+		for (i = 0; i < blen; i++)
+			b[i] ^= pos[i];
+		ieee80211_aes_encrypt(tfm, b, b);
+
+		b_0[14] = (j >> 8) & 0xff;
+		b_0[15] = j & 0xff;
+		ieee80211_aes_encrypt(tfm, b_0, e);
+		for (i = 0; i < blen; i++)
+			*cpos++ = *pos++ ^ e[i];
+	}
+
+	for (i = 0; i < CCMP_MIC_LEN; i++)
+		mic[i] = b[i] ^ s_0[i];
+}
+
+
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+			      u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
+			      u8 *mic, u8 *data)
+{
+	int i, j, last_len, num_blocks;
+	u8 *pos, *cpos, *b, *s_0, *a;
+
+	b = scratch;
+	s_0 = scratch + AES_BLOCK_LEN;
+	a = scratch + 2 * AES_BLOCK_LEN;
+
+	num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+	last_len = data_len % AES_BLOCK_LEN;
+	aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
+
+	/* Process payload blocks */
+	cpos = cdata;
+	pos = data;
+	for (j = 1; j <= num_blocks; j++) {
+		int blen = (j == num_blocks && last_len) ?
+			last_len : AES_BLOCK_LEN;
+
+		/* Decryption followed by authentication */
+		b_0[14] = (j >> 8) & 0xff;
+		b_0[15] = j & 0xff;
+		ieee80211_aes_encrypt(tfm, b_0, b);
+		for (i = 0; i < blen; i++) {
+			*pos = *cpos++ ^ b[i];
+			a[i] ^= *pos++;
+		}
+
+		ieee80211_aes_encrypt(tfm, a, a);
+	}
+
+	for (i = 0; i < CCMP_MIC_LEN; i++) {
+		if ((mic[i] ^ s_0[i]) != a[i])
+			return -1;
+	}
+
+	return 0;
+}
+
+
+struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
+{
+	struct crypto_cipher *tfm;
+
+	tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		return NULL;
+
+	crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
+
+	return tfm;
+}
+
+
+void ieee80211_aes_key_free(struct crypto_cipher *tfm)
+{
+	if (tfm)
+		crypto_free_cipher(tfm);
+}
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
new file mode 100644
index 0000000..885f190
--- /dev/null
+++ b/net/mac80211/aes_ccm.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape 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 AES_CCM_H
+#define AES_CCM_H
+
+#include <linux/crypto.h>
+
+#define AES_BLOCK_LEN 16
+
+struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]);
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+			       u8 *b_0, u8 *aad, u8 *data, size_t data_len,
+			       u8 *cdata, u8 *mic);
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+			      u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
+			      u8 *mic, u8 *data);
+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
+
+#endif /* AES_CCM_H */
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
new file mode 100644
index 0000000..bb6c0fe
--- /dev/null
+++ b/net/mac80211/debugfs.c
@@ -0,0 +1,433 @@
+/*
+ * mac80211 debugfs for wireless PHYs
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/rtnetlink.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+
+int mac80211_open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const char *ieee80211_mode_str(int mode)
+{
+	switch (mode) {
+	case MODE_IEEE80211A:
+		return "IEEE 802.11a";
+	case MODE_IEEE80211B:
+		return "IEEE 802.11b";
+	case MODE_IEEE80211G:
+		return "IEEE 802.11g";
+	case MODE_ATHEROS_TURBO:
+		return "Atheros Turbo (5 GHz)";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static ssize_t modes_read(struct file *file, char __user *userbuf,
+			  size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	struct ieee80211_hw_mode *mode;
+	char buf[150], *p = buf;
+
+	/* FIXME: locking! */
+	list_for_each_entry(mode, &local->modes_list, list) {
+		p += scnprintf(p, sizeof(buf)+buf-p,
+			       "%s\n", ieee80211_mode_str(mode->mode));
+	}
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations modes_ops = {
+	.read = modes_read,
+	.open = mac80211_open_file_generic,
+};
+
+#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)		\
+static ssize_t name## _read(struct file *file, char __user *userbuf,	\
+			    size_t count, loff_t *ppos)			\
+{									\
+	struct ieee80211_local *local = file->private_data;		\
+	char buf[buflen];						\
+	int res;							\
+									\
+	res = scnprintf(buf, buflen, fmt "\n", ##value);		\
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+}									\
+									\
+static const struct file_operations name## _ops = {			\
+	.read = name## _read,						\
+	.open = mac80211_open_file_generic,				\
+};
+
+#define DEBUGFS_ADD(name)						\
+	local->debugfs.name = debugfs_create_file(#name, 0444, phyd,	\
+						  local, &name## _ops);
+
+#define DEBUGFS_DEL(name)						\
+	debugfs_remove(local->debugfs.name);				\
+	local->debugfs.name = NULL;
+
+
+DEBUGFS_READONLY_FILE(channel, 20, "%d",
+		      local->hw.conf.channel);
+DEBUGFS_READONLY_FILE(frequency, 20, "%d",
+		      local->hw.conf.freq);
+DEBUGFS_READONLY_FILE(radar_detect, 20, "%d",
+		      local->hw.conf.radar_detect);
+DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
+		      local->hw.conf.antenna_sel_tx);
+DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
+		      local->hw.conf.antenna_sel_rx);
+DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d",
+		      local->bridge_packets);
+DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d",
+		      local->key_tx_rx_threshold);
+DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
+		      local->rts_threshold);
+DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
+		      local->fragmentation_threshold);
+DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
+		      local->short_retry_limit);
+DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
+		      local->long_retry_limit);
+DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
+		      local->total_ps_buffered);
+DEBUGFS_READONLY_FILE(mode, 20, "%s",
+		      ieee80211_mode_str(local->hw.conf.phymode));
+DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
+		      local->wep_iv & 0xffffff);
+DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm",
+		      local->hw.conf.tx_power_reduction / 10,
+		      local->hw.conf.tx_power_reduction & 10);
+DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
+		      local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+
+/* statistics stuff */
+
+static inline int rtnl_lock_local(struct ieee80211_local *local)
+{
+	rtnl_lock();
+	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+		rtnl_unlock();
+		return -ENODEV;
+	}
+	return 0;
+}
+
+#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...)			\
+	DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
+
+static ssize_t format_devstat_counter(struct ieee80211_local *local,
+	char __user *userbuf,
+	size_t count, loff_t *ppos,
+	int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
+			  int buflen))
+{
+	struct ieee80211_low_level_stats stats;
+	char buf[20];
+	int res;
+
+	if (!local->ops->get_stats)
+		return -EOPNOTSUPP;
+
+	res = rtnl_lock_local(local);
+	if (res)
+		return res;
+
+	res = local->ops->get_stats(local_to_hw(local), &stats);
+	rtnl_unlock();
+	if (!res)
+		res = printvalue(&stats, buf, sizeof(buf));
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+#define DEBUGFS_DEVSTATS_FILE(name)					\
+static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
+				 char *buf, int buflen)			\
+{									\
+	return scnprintf(buf, buflen, "%u\n", stats->name);		\
+}									\
+static ssize_t stats_ ##name## _read(struct file *file,			\
+				     char __user *userbuf,		\
+				     size_t count, loff_t *ppos)	\
+{									\
+	return format_devstat_counter(file->private_data,		\
+				      userbuf,				\
+				      count,				\
+				      ppos,				\
+				      print_devstats_##name);		\
+}									\
+									\
+static const struct file_operations stats_ ##name## _ops = {		\
+	.read = stats_ ##name## _read,					\
+	.open = mac80211_open_file_generic,				\
+};
+
+#define DEBUGFS_STATS_ADD(name)						\
+	local->debugfs.stats.name = debugfs_create_file(#name, 0444, statsd,\
+		local, &stats_ ##name## _ops);
+
+#define DEBUGFS_STATS_DEL(name)						\
+	debugfs_remove(local->debugfs.stats.name);			\
+	local->debugfs.stats.name = NULL;
+
+DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u",
+		   local->dot11TransmittedFragmentCount);
+DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u",
+		   local->dot11MulticastTransmittedFrameCount);
+DEBUGFS_STATS_FILE(failed_count, 20, "%u",
+		   local->dot11FailedCount);
+DEBUGFS_STATS_FILE(retry_count, 20, "%u",
+		   local->dot11RetryCount);
+DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u",
+		   local->dot11MultipleRetryCount);
+DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u",
+		   local->dot11FrameDuplicateCount);
+DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u",
+		   local->dot11ReceivedFragmentCount);
+DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u",
+		   local->dot11MulticastReceivedFrameCount);
+DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u",
+		   local->dot11TransmittedFrameCount);
+DEBUGFS_STATS_FILE(wep_undecryptable_count, 20, "%u",
+		   local->dot11WEPUndecryptableCount);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u",
+		   local->tx_handlers_drop);
+DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u",
+		   local->tx_handlers_queued);
+DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u",
+		   local->tx_handlers_drop_unencrypted);
+DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u",
+		   local->tx_handlers_drop_fragment);
+DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u",
+		   local->tx_handlers_drop_wep);
+DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u",
+		   local->tx_handlers_drop_not_assoc);
+DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u",
+		   local->tx_handlers_drop_unauth_port);
+DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u",
+		   local->rx_handlers_drop);
+DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u",
+		   local->rx_handlers_queued);
+DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u",
+		   local->rx_handlers_drop_nullfunc);
+DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u",
+		   local->rx_handlers_drop_defrag);
+DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u",
+		   local->rx_handlers_drop_short);
+DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u",
+		   local->rx_handlers_drop_passive_scan);
+DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u",
+		   local->tx_expand_skb_head);
+DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u",
+		   local->tx_expand_skb_head_cloned);
+DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u",
+		   local->rx_expand_skb_head);
+DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u",
+		   local->rx_expand_skb_head2);
+DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
+		   local->rx_handlers_fragments);
+DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
+		   local->tx_status_drop);
+
+static ssize_t stats_wme_rx_queue_read(struct file *file,
+				       char __user *userbuf,
+				       size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	char buf[NUM_RX_DATA_QUEUES*15], *p = buf;
+	int i;
+
+	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p,
+			       "%u\n", local->wme_rx_queue[i]);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations stats_wme_rx_queue_ops = {
+	.read = stats_wme_rx_queue_read,
+	.open = mac80211_open_file_generic,
+};
+
+static ssize_t stats_wme_tx_queue_read(struct file *file,
+				       char __user *userbuf,
+				       size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	char buf[NUM_TX_DATA_QUEUES*15], *p = buf;
+	int i;
+
+	for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p,
+			       "%u\n", local->wme_tx_queue[i]);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations stats_wme_tx_queue_ops = {
+	.read = stats_wme_tx_queue_read,
+	.open = mac80211_open_file_generic,
+};
+#endif
+
+DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
+DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
+DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
+DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
+
+
+void debugfs_hw_add(struct ieee80211_local *local)
+{
+	struct dentry *phyd = local->hw.wiphy->debugfsdir;
+	struct dentry *statsd;
+
+	if (!phyd)
+		return;
+
+	local->debugfs.stations = debugfs_create_dir("stations", phyd);
+	local->debugfs.keys = debugfs_create_dir("keys", phyd);
+
+	DEBUGFS_ADD(channel);
+	DEBUGFS_ADD(frequency);
+	DEBUGFS_ADD(radar_detect);
+	DEBUGFS_ADD(antenna_sel_tx);
+	DEBUGFS_ADD(antenna_sel_rx);
+	DEBUGFS_ADD(bridge_packets);
+	DEBUGFS_ADD(key_tx_rx_threshold);
+	DEBUGFS_ADD(rts_threshold);
+	DEBUGFS_ADD(fragmentation_threshold);
+	DEBUGFS_ADD(short_retry_limit);
+	DEBUGFS_ADD(long_retry_limit);
+	DEBUGFS_ADD(total_ps_buffered);
+	DEBUGFS_ADD(mode);
+	DEBUGFS_ADD(wep_iv);
+	DEBUGFS_ADD(tx_power_reduction);
+	DEBUGFS_ADD(modes);
+
+	statsd = debugfs_create_dir("statistics", phyd);
+	local->debugfs.statistics = statsd;
+
+	/* if the dir failed, don't put all the other things into the root! */
+	if (!statsd)
+		return;
+
+	DEBUGFS_STATS_ADD(transmitted_fragment_count);
+	DEBUGFS_STATS_ADD(multicast_transmitted_frame_count);
+	DEBUGFS_STATS_ADD(failed_count);
+	DEBUGFS_STATS_ADD(retry_count);
+	DEBUGFS_STATS_ADD(multiple_retry_count);
+	DEBUGFS_STATS_ADD(frame_duplicate_count);
+	DEBUGFS_STATS_ADD(received_fragment_count);
+	DEBUGFS_STATS_ADD(multicast_received_frame_count);
+	DEBUGFS_STATS_ADD(transmitted_frame_count);
+	DEBUGFS_STATS_ADD(wep_undecryptable_count);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	DEBUGFS_STATS_ADD(tx_handlers_drop);
+	DEBUGFS_STATS_ADD(tx_handlers_queued);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_fragment);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
+	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
+	DEBUGFS_STATS_ADD(rx_handlers_drop);
+	DEBUGFS_STATS_ADD(rx_handlers_queued);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_short);
+	DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan);
+	DEBUGFS_STATS_ADD(tx_expand_skb_head);
+	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
+	DEBUGFS_STATS_ADD(rx_expand_skb_head);
+	DEBUGFS_STATS_ADD(rx_expand_skb_head2);
+	DEBUGFS_STATS_ADD(rx_handlers_fragments);
+	DEBUGFS_STATS_ADD(tx_status_drop);
+	DEBUGFS_STATS_ADD(wme_tx_queue);
+	DEBUGFS_STATS_ADD(wme_rx_queue);
+#endif
+	DEBUGFS_STATS_ADD(dot11ACKFailureCount);
+	DEBUGFS_STATS_ADD(dot11RTSFailureCount);
+	DEBUGFS_STATS_ADD(dot11FCSErrorCount);
+	DEBUGFS_STATS_ADD(dot11RTSSuccessCount);
+}
+
+void debugfs_hw_del(struct ieee80211_local *local)
+{
+	DEBUGFS_DEL(channel);
+	DEBUGFS_DEL(frequency);
+	DEBUGFS_DEL(radar_detect);
+	DEBUGFS_DEL(antenna_sel_tx);
+	DEBUGFS_DEL(antenna_sel_rx);
+	DEBUGFS_DEL(bridge_packets);
+	DEBUGFS_DEL(key_tx_rx_threshold);
+	DEBUGFS_DEL(rts_threshold);
+	DEBUGFS_DEL(fragmentation_threshold);
+	DEBUGFS_DEL(short_retry_limit);
+	DEBUGFS_DEL(long_retry_limit);
+	DEBUGFS_DEL(total_ps_buffered);
+	DEBUGFS_DEL(mode);
+	DEBUGFS_DEL(wep_iv);
+	DEBUGFS_DEL(tx_power_reduction);
+	DEBUGFS_DEL(modes);
+
+	DEBUGFS_STATS_DEL(transmitted_fragment_count);
+	DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
+	DEBUGFS_STATS_DEL(failed_count);
+	DEBUGFS_STATS_DEL(retry_count);
+	DEBUGFS_STATS_DEL(multiple_retry_count);
+	DEBUGFS_STATS_DEL(frame_duplicate_count);
+	DEBUGFS_STATS_DEL(received_fragment_count);
+	DEBUGFS_STATS_DEL(multicast_received_frame_count);
+	DEBUGFS_STATS_DEL(transmitted_frame_count);
+	DEBUGFS_STATS_DEL(wep_undecryptable_count);
+	DEBUGFS_STATS_DEL(num_scans);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	DEBUGFS_STATS_DEL(tx_handlers_drop);
+	DEBUGFS_STATS_DEL(tx_handlers_queued);
+	DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted);
+	DEBUGFS_STATS_DEL(tx_handlers_drop_fragment);
+	DEBUGFS_STATS_DEL(tx_handlers_drop_wep);
+	DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc);
+	DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port);
+	DEBUGFS_STATS_DEL(rx_handlers_drop);
+	DEBUGFS_STATS_DEL(rx_handlers_queued);
+	DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc);
+	DEBUGFS_STATS_DEL(rx_handlers_drop_defrag);
+	DEBUGFS_STATS_DEL(rx_handlers_drop_short);
+	DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan);
+	DEBUGFS_STATS_DEL(tx_expand_skb_head);
+	DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned);
+	DEBUGFS_STATS_DEL(rx_expand_skb_head);
+	DEBUGFS_STATS_DEL(rx_expand_skb_head2);
+	DEBUGFS_STATS_DEL(rx_handlers_fragments);
+	DEBUGFS_STATS_DEL(tx_status_drop);
+	DEBUGFS_STATS_DEL(wme_tx_queue);
+	DEBUGFS_STATS_DEL(wme_rx_queue);
+#endif
+	DEBUGFS_STATS_DEL(dot11ACKFailureCount);
+	DEBUGFS_STATS_DEL(dot11RTSFailureCount);
+	DEBUGFS_STATS_DEL(dot11FCSErrorCount);
+	DEBUGFS_STATS_DEL(dot11RTSSuccessCount);
+
+	debugfs_remove(local->debugfs.statistics);
+	local->debugfs.statistics = NULL;
+	debugfs_remove(local->debugfs.stations);
+	local->debugfs.stations = NULL;
+	debugfs_remove(local->debugfs.keys);
+	local->debugfs.keys = NULL;
+}
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h
new file mode 100644
index 0000000..dd25419
--- /dev/null
+++ b/net/mac80211/debugfs.h
@@ -0,0 +1,16 @@
+#ifndef __MAC80211_DEBUGFS_H
+#define __MAC80211_DEBUGFS_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+extern void debugfs_hw_add(struct ieee80211_local *local);
+extern void debugfs_hw_del(struct ieee80211_local *local);
+extern int mac80211_open_file_generic(struct inode *inode, struct file *file);
+#else
+static inline void debugfs_hw_add(struct ieee80211_local *local)
+{
+	return;
+}
+static inline void debugfs_hw_del(struct ieee80211_local *local) {}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_H */
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
new file mode 100644
index 0000000..7d56dc9
--- /dev/null
+++ b/net/mac80211/debugfs_key.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2003-2005	Devicescape Software, Inc.
+ * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.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.
+ */
+
+#include <linux/kobject.h>
+#include "ieee80211_i.h"
+#include "ieee80211_key.h"
+#include "debugfs.h"
+#include "debugfs_key.h"
+
+#define KEY_READ(name, buflen, format_string)				\
+static ssize_t key_##name##_read(struct file *file,			\
+				 char __user *userbuf,			\
+				 size_t count, loff_t *ppos)		\
+{									\
+	char buf[buflen];						\
+	struct ieee80211_key *key = file->private_data;			\
+	int res = scnprintf(buf, buflen, format_string, key->name);	\
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+}
+#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n")
+
+#define KEY_OPS(name)							\
+static const struct file_operations key_ ##name## _ops = {		\
+	.read = key_##name##_read,					\
+	.open = mac80211_open_file_generic,				\
+}
+
+#define KEY_FILE(name, format)						\
+		 KEY_READ_##format(name)				\
+		 KEY_OPS(name)
+
+KEY_FILE(keylen, D);
+KEY_FILE(force_sw_encrypt, D);
+KEY_FILE(keyidx, D);
+KEY_FILE(hw_key_idx, D);
+KEY_FILE(tx_rx_count, D);
+
+static ssize_t key_algorithm_read(struct file *file,
+				  char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	char *alg;
+	struct ieee80211_key *key = file->private_data;
+
+	switch (key->alg) {
+	case ALG_WEP:
+		alg = "WEP\n";
+		break;
+	case ALG_TKIP:
+		alg = "TKIP\n";
+		break;
+	case ALG_CCMP:
+		alg = "CCMP\n";
+		break;
+	default:
+		return 0;
+	}
+	return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
+}
+KEY_OPS(algorithm);
+
+static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	const u8 *tpn;
+	char buf[20];
+	int len;
+	struct ieee80211_key *key = file->private_data;
+
+	switch (key->alg) {
+	case ALG_WEP:
+		len = scnprintf(buf, sizeof(buf), "\n");
+	case ALG_TKIP:
+		len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
+				key->u.tkip.iv32,
+				key->u.tkip.iv16);
+	case ALG_CCMP:
+		tpn = key->u.ccmp.tx_pn;
+		len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
+				tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
+	default:
+		return 0;
+	}
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(tx_spec);
+
+static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	struct ieee80211_key *key = file->private_data;
+	char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
+	int i, len;
+	const u8 *rpn;
+
+	switch (key->alg) {
+	case ALG_WEP:
+		len = scnprintf(buf, sizeof(buf), "\n");
+	case ALG_TKIP:
+		for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+			p += scnprintf(p, sizeof(buf)+buf-p,
+				       "%08x %04x\n",
+				       key->u.tkip.iv32_rx[i],
+				       key->u.tkip.iv16_rx[i]);
+		len = p - buf;
+	case ALG_CCMP:
+		for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+			rpn = key->u.ccmp.rx_pn[i];
+			p += scnprintf(p, sizeof(buf)+buf-p,
+				       "%02x%02x%02x%02x%02x%02x\n",
+				       rpn[0], rpn[1], rpn[2],
+				       rpn[3], rpn[4], rpn[5]);
+		}
+		len = p - buf;
+	default:
+		return 0;
+	}
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(rx_spec);
+
+static ssize_t key_replays_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	struct ieee80211_key *key = file->private_data;
+	char buf[20];
+	int len;
+
+	if (key->alg != ALG_CCMP)
+		return 0;
+	len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(replays);
+
+static ssize_t key_key_read(struct file *file, char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	struct ieee80211_key *key = file->private_data;
+	int i, res, bufsize = 2*key->keylen+2;
+	char *buf = kmalloc(bufsize, GFP_KERNEL);
+	char *p = buf;
+
+	for (i = 0; i < key->keylen; i++)
+		p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]);
+	p += scnprintf(p, bufsize+buf-p, "\n");
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+	kfree(buf);
+	return res;
+}
+KEY_OPS(key);
+
+#define DEBUGFS_ADD(name) \
+	key->debugfs.name = debugfs_create_file(#name, 0400,\
+				key->debugfs.dir, key, &key_##name##_ops);
+
+void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+			       struct ieee80211_key *key)
+{
+	char buf[20];
+
+	if (!local->debugfs.keys)
+		return;
+
+	sprintf(buf, "%d", key->keyidx);
+	key->debugfs.dir = debugfs_create_dir(buf,
+					local->debugfs.keys);
+
+	if (!key->debugfs.dir)
+		return;
+
+	DEBUGFS_ADD(keylen);
+	DEBUGFS_ADD(force_sw_encrypt);
+	DEBUGFS_ADD(keyidx);
+	DEBUGFS_ADD(hw_key_idx);
+	DEBUGFS_ADD(tx_rx_count);
+	DEBUGFS_ADD(algorithm);
+	DEBUGFS_ADD(tx_spec);
+	DEBUGFS_ADD(rx_spec);
+	DEBUGFS_ADD(replays);
+	DEBUGFS_ADD(key);
+};
+
+#define DEBUGFS_DEL(name) \
+	debugfs_remove(key->debugfs.name); key->debugfs.name = NULL;
+
+void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
+{
+	if (!key)
+		return;
+
+	DEBUGFS_DEL(keylen);
+	DEBUGFS_DEL(force_sw_encrypt);
+	DEBUGFS_DEL(keyidx);
+	DEBUGFS_DEL(hw_key_idx);
+	DEBUGFS_DEL(tx_rx_count);
+	DEBUGFS_DEL(algorithm);
+	DEBUGFS_DEL(tx_spec);
+	DEBUGFS_DEL(rx_spec);
+	DEBUGFS_DEL(replays);
+	DEBUGFS_DEL(key);
+
+	debugfs_remove(key->debugfs.stalink);
+	key->debugfs.stalink = NULL;
+	debugfs_remove(key->debugfs.dir);
+	key->debugfs.dir = NULL;
+}
+void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
+{
+	char buf[50];
+
+	if (!sdata->debugfsdir)
+		return;
+
+	sprintf(buf, "../keys/%d", sdata->default_key->keyidx);
+	sdata->debugfs.default_key =
+		debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
+}
+void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
+{
+	if (!sdata)
+		return;
+
+	debugfs_remove(sdata->debugfs.default_key);
+	sdata->debugfs.default_key = NULL;
+}
+void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
+				    struct sta_info *sta)
+{
+	char buf[50];
+
+	if (!key->debugfs.dir)
+		return;
+
+	sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr));
+	key->debugfs.stalink =
+		debugfs_create_symlink("station", key->debugfs.dir, buf);
+}
+
+void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+				   struct sta_info *sta)
+{
+	debugfs_remove(key->debugfs.stalink);
+	key->debugfs.stalink = NULL;
+}
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h
new file mode 100644
index 0000000..aecfce3
--- /dev/null
+++ b/net/mac80211/debugfs_key.h
@@ -0,0 +1,34 @@
+#ifndef __MAC80211_DEBUGFS_KEY_H
+#define __MAC80211_DEBUGFS_KEY_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+			       struct ieee80211_key *key);
+void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
+void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
+				    struct sta_info *sta);
+void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+				   struct sta_info *sta);
+#else
+static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+					     struct ieee80211_key *key)
+{}
+static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
+{}
+static inline void ieee80211_debugfs_key_add_default(
+	struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_key_remove_default(
+	struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_key_sta_link(
+	struct ieee80211_key *key, struct sta_info *sta)
+{}
+static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+						 struct sta_info *sta)
+{}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_KEY_H */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
new file mode 100644
index 0000000..9e39646
--- /dev/null
+++ b/net/mac80211/debugfs_netdev.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/if.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+#include "debugfs_netdev.h"
+
+static ssize_t ieee80211_if_read(
+	struct ieee80211_sub_if_data *sdata,
+	char __user *userbuf,
+	size_t count, loff_t *ppos,
+	ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
+{
+	char buf[70];
+	ssize_t ret = -EINVAL;
+
+	read_lock(&dev_base_lock);
+	if (sdata->dev->reg_state == NETREG_REGISTERED) {
+		ret = (*format)(sdata, buf, sizeof(buf));
+		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+	}
+	read_unlock(&dev_base_lock);
+	return ret;
+}
+
+#define IEEE80211_IF_FMT(name, field, format_string)			\
+static ssize_t ieee80211_if_fmt_##name(					\
+	const struct ieee80211_sub_if_data *sdata, char *buf,		\
+	int buflen)							\
+{									\
+	return scnprintf(buf, buflen, format_string, sdata->field);	\
+}
+#define IEEE80211_IF_FMT_DEC(name, field)				\
+		IEEE80211_IF_FMT(name, field, "%d\n")
+#define IEEE80211_IF_FMT_HEX(name, field)				\
+		IEEE80211_IF_FMT(name, field, "%#x\n")
+#define IEEE80211_IF_FMT_SIZE(name, field)				\
+		IEEE80211_IF_FMT(name, field, "%zd\n")
+
+#define IEEE80211_IF_FMT_ATOMIC(name, field)				\
+static ssize_t ieee80211_if_fmt_##name(					\
+	const struct ieee80211_sub_if_data *sdata,			\
+	char *buf, int buflen)						\
+{									\
+	return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
+}
+
+#define IEEE80211_IF_FMT_MAC(name, field)				\
+static ssize_t ieee80211_if_fmt_##name(					\
+	const struct ieee80211_sub_if_data *sdata, char *buf,		\
+	int buflen)							\
+{									\
+	return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\
+}
+
+#define __IEEE80211_IF_FILE(name)					\
+static ssize_t ieee80211_if_read_##name(struct file *file,		\
+					char __user *userbuf,		\
+					size_t count, loff_t *ppos)	\
+{									\
+	return ieee80211_if_read(file->private_data,			\
+				 userbuf, count, ppos,			\
+				 ieee80211_if_fmt_##name);		\
+}									\
+static const struct file_operations name##_ops = {			\
+	.read = ieee80211_if_read_##name,				\
+	.open = mac80211_open_file_generic,				\
+}
+
+#define IEEE80211_IF_FILE(name, field, format)				\
+		IEEE80211_IF_FMT_##format(name, field)			\
+		__IEEE80211_IF_FILE(name)
+
+/* common attributes */
+IEEE80211_IF_FILE(channel_use, channel_use, DEC);
+IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
+IEEE80211_IF_FILE(eapol, eapol, DEC);
+IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
+
+/* STA/IBSS attributes */
+IEEE80211_IF_FILE(state, u.sta.state, DEC);
+IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
+IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
+IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
+IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
+IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
+IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
+IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
+IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
+IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
+IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
+IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
+IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+
+static ssize_t ieee80211_if_fmt_flags(
+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+	return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
+			 sdata->u.sta.ssid_set ? "SSID\n" : "",
+			 sdata->u.sta.bssid_set ? "BSSID\n" : "",
+			 sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "",
+			 sdata->u.sta.authenticated ? "AUTH\n" : "",
+			 sdata->u.sta.associated ? "ASSOC\n" : "",
+			 sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "",
+			 sdata->u.sta.use_protection ? "CTS prot\n" : "");
+}
+__IEEE80211_IF_FILE(flags);
+
+/* AP attributes */
+IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
+IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
+IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
+IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
+IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
+IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
+
+static ssize_t ieee80211_if_fmt_num_buffered_multicast(
+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+	return scnprintf(buf, buflen, "%u\n",
+			 skb_queue_len(&sdata->u.ap.ps_bc_buf));
+}
+__IEEE80211_IF_FILE(num_buffered_multicast);
+
+static ssize_t ieee80211_if_fmt_beacon_head_len(
+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+	if (sdata->u.ap.beacon_head)
+		return scnprintf(buf, buflen, "%d\n",
+				 sdata->u.ap.beacon_head_len);
+	return scnprintf(buf, buflen, "\n");
+}
+__IEEE80211_IF_FILE(beacon_head_len);
+
+static ssize_t ieee80211_if_fmt_beacon_tail_len(
+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+	if (sdata->u.ap.beacon_tail)
+		return scnprintf(buf, buflen, "%d\n",
+				 sdata->u.ap.beacon_tail_len);
+	return scnprintf(buf, buflen, "\n");
+}
+__IEEE80211_IF_FILE(beacon_tail_len);
+
+/* WDS attributes */
+IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
+
+/* VLAN attributes */
+IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
+
+/* MONITOR attributes */
+static ssize_t ieee80211_if_fmt_mode(
+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+	struct ieee80211_local *local = sdata->local;
+
+	return scnprintf(buf, buflen, "%s\n",
+			 ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
+			  local->open_count == local->monitors) ?
+			 "hard" : "soft");
+}
+__IEEE80211_IF_FILE(mode);
+
+
+#define DEBUGFS_ADD(name, type)\
+	sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
+		sdata->debugfsdir, sdata, &name##_ops);
+
+static void add_sta_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(channel_use, sta);
+	DEBUGFS_ADD(drop_unencrypted, sta);
+	DEBUGFS_ADD(eapol, sta);
+	DEBUGFS_ADD(ieee8021_x, sta);
+	DEBUGFS_ADD(state, sta);
+	DEBUGFS_ADD(bssid, sta);
+	DEBUGFS_ADD(prev_bssid, sta);
+	DEBUGFS_ADD(ssid_len, sta);
+	DEBUGFS_ADD(aid, sta);
+	DEBUGFS_ADD(ap_capab, sta);
+	DEBUGFS_ADD(capab, sta);
+	DEBUGFS_ADD(extra_ie_len, sta);
+	DEBUGFS_ADD(auth_tries, sta);
+	DEBUGFS_ADD(assoc_tries, sta);
+	DEBUGFS_ADD(auth_algs, sta);
+	DEBUGFS_ADD(auth_alg, sta);
+	DEBUGFS_ADD(auth_transaction, sta);
+	DEBUGFS_ADD(flags, sta);
+}
+
+static void add_ap_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(channel_use, ap);
+	DEBUGFS_ADD(drop_unencrypted, ap);
+	DEBUGFS_ADD(eapol, ap);
+	DEBUGFS_ADD(ieee8021_x, ap);
+	DEBUGFS_ADD(num_sta_ps, ap);
+	DEBUGFS_ADD(dtim_period, ap);
+	DEBUGFS_ADD(dtim_count, ap);
+	DEBUGFS_ADD(num_beacons, ap);
+	DEBUGFS_ADD(force_unicast_rateidx, ap);
+	DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+	DEBUGFS_ADD(num_buffered_multicast, ap);
+	DEBUGFS_ADD(beacon_head_len, ap);
+	DEBUGFS_ADD(beacon_tail_len, ap);
+}
+
+static void add_wds_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(channel_use, wds);
+	DEBUGFS_ADD(drop_unencrypted, wds);
+	DEBUGFS_ADD(eapol, wds);
+	DEBUGFS_ADD(ieee8021_x, wds);
+	DEBUGFS_ADD(peer, wds);
+}
+
+static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(channel_use, vlan);
+	DEBUGFS_ADD(drop_unencrypted, vlan);
+	DEBUGFS_ADD(eapol, vlan);
+	DEBUGFS_ADD(ieee8021_x, vlan);
+	DEBUGFS_ADD(vlan_id, vlan);
+}
+
+static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_ADD(mode, monitor);
+}
+
+static void add_files(struct ieee80211_sub_if_data *sdata)
+{
+	if (!sdata->debugfsdir)
+		return;
+
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		add_sta_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		add_ap_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_WDS:
+		add_wds_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		add_monitor_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_VLAN:
+		add_vlan_files(sdata);
+		break;
+	default:
+		break;
+	}
+}
+
+#define DEBUGFS_DEL(name, type)\
+	debugfs_remove(sdata->debugfs.type.name);\
+	sdata->debugfs.type.name = NULL;
+
+static void del_sta_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_DEL(channel_use, sta);
+	DEBUGFS_DEL(drop_unencrypted, sta);
+	DEBUGFS_DEL(eapol, sta);
+	DEBUGFS_DEL(ieee8021_x, sta);
+	DEBUGFS_DEL(state, sta);
+	DEBUGFS_DEL(bssid, sta);
+	DEBUGFS_DEL(prev_bssid, sta);
+	DEBUGFS_DEL(ssid_len, sta);
+	DEBUGFS_DEL(aid, sta);
+	DEBUGFS_DEL(ap_capab, sta);
+	DEBUGFS_DEL(capab, sta);
+	DEBUGFS_DEL(extra_ie_len, sta);
+	DEBUGFS_DEL(auth_tries, sta);
+	DEBUGFS_DEL(assoc_tries, sta);
+	DEBUGFS_DEL(auth_algs, sta);
+	DEBUGFS_DEL(auth_alg, sta);
+	DEBUGFS_DEL(auth_transaction, sta);
+	DEBUGFS_DEL(flags, sta);
+}
+
+static void del_ap_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_DEL(channel_use, ap);
+	DEBUGFS_DEL(drop_unencrypted, ap);
+	DEBUGFS_DEL(eapol, ap);
+	DEBUGFS_DEL(ieee8021_x, ap);
+	DEBUGFS_DEL(num_sta_ps, ap);
+	DEBUGFS_DEL(dtim_period, ap);
+	DEBUGFS_DEL(dtim_count, ap);
+	DEBUGFS_DEL(num_beacons, ap);
+	DEBUGFS_DEL(force_unicast_rateidx, ap);
+	DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+	DEBUGFS_DEL(num_buffered_multicast, ap);
+	DEBUGFS_DEL(beacon_head_len, ap);
+	DEBUGFS_DEL(beacon_tail_len, ap);
+}
+
+static void del_wds_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_DEL(channel_use, wds);
+	DEBUGFS_DEL(drop_unencrypted, wds);
+	DEBUGFS_DEL(eapol, wds);
+	DEBUGFS_DEL(ieee8021_x, wds);
+	DEBUGFS_DEL(peer, wds);
+}
+
+static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_DEL(channel_use, vlan);
+	DEBUGFS_DEL(drop_unencrypted, vlan);
+	DEBUGFS_DEL(eapol, vlan);
+	DEBUGFS_DEL(ieee8021_x, vlan);
+	DEBUGFS_DEL(vlan_id, vlan);
+}
+
+static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
+{
+	DEBUGFS_DEL(mode, monitor);
+}
+
+static void del_files(struct ieee80211_sub_if_data *sdata, int type)
+{
+	if (!sdata->debugfsdir)
+		return;
+
+	switch (type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		del_sta_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		del_ap_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_WDS:
+		del_wds_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		del_monitor_files(sdata);
+		break;
+	case IEEE80211_IF_TYPE_VLAN:
+		del_vlan_files(sdata);
+		break;
+	default:
+		break;
+	}
+}
+
+static int notif_registered;
+
+void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
+{
+	char buf[10+IFNAMSIZ];
+
+	if (!notif_registered)
+		return;
+
+	sprintf(buf, "netdev:%s", sdata->dev->name);
+	sdata->debugfsdir = debugfs_create_dir(buf,
+		sdata->local->hw.wiphy->debugfsdir);
+}
+
+void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
+{
+	del_files(sdata, sdata->type);
+	debugfs_remove(sdata->debugfsdir);
+	sdata->debugfsdir = NULL;
+}
+
+void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
+				      int oldtype)
+{
+	del_files(sdata, oldtype);
+	add_files(sdata);
+}
+
+static int netdev_notify(struct notifier_block * nb,
+			 unsigned long state,
+			 void *ndev)
+{
+	struct net_device *dev = ndev;
+	char buf[10+IFNAMSIZ];
+
+	if (state != NETDEV_CHANGENAME)
+		return 0;
+
+	if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
+		return 0;
+
+	if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+		return 0;
+
+	/* TODO
+	sprintf(buf, "netdev:%s", dev->name);
+	debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf);
+	*/
+
+	return 0;
+}
+
+static struct notifier_block mac80211_debugfs_netdev_notifier = {
+	.notifier_call = netdev_notify,
+};
+
+void ieee80211_debugfs_netdev_init(void)
+{
+	int err;
+
+	err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
+	if (err) {
+		printk(KERN_ERR
+		       "mac80211: failed to install netdev notifier,"
+		       " disabling per-netdev debugfs!\n");
+	} else
+		notif_registered = 1;
+}
+
+void ieee80211_debugfs_netdev_exit(void)
+{
+	unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
+	notif_registered = 0;
+}
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h
new file mode 100644
index 0000000..a690071
--- /dev/null
+++ b/net/mac80211/debugfs_netdev.h
@@ -0,0 +1,30 @@
+/* routines exported for debugfs handling */
+
+#ifndef __IEEE80211_DEBUGFS_NETDEV_H
+#define __IEEE80211_DEBUGFS_NETDEV_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
+				     int oldtype);
+void ieee80211_debugfs_netdev_init(void);
+void ieee80211_debugfs_netdev_exit(void);
+#else
+static inline void ieee80211_debugfs_add_netdev(
+	struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_remove_netdev(
+	struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_change_if_type(
+	struct ieee80211_sub_if_data *sdata, int oldtype)
+{}
+static inline void ieee80211_debugfs_netdev_init(void)
+{}
+
+static inline void ieee80211_debugfs_netdev_exit(void)
+{}
+#endif
+
+#endif /* __IEEE80211_DEBUGFS_NETDEV_H */
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
new file mode 100644
index 0000000..d41e696
--- /dev/null
+++ b/net/mac80211/debugfs_sta.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2003-2005	Devicescape Software, Inc.
+ * Copyright (c) 2006	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.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.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include "ieee80211_i.h"
+#include "debugfs.h"
+#include "debugfs_sta.h"
+#include "sta_info.h"
+
+/* sta attributtes */
+
+#define STA_READ(name, buflen, field, format_string)			\
+static ssize_t sta_ ##name## _read(struct file *file,			\
+				   char __user *userbuf,		\
+				   size_t count, loff_t *ppos)		\
+{									\
+	int res;							\
+	struct sta_info *sta = file->private_data;			\
+	char buf[buflen];						\
+	res = scnprintf(buf, buflen, format_string, sta->field);	\
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+}
+#define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n")
+#define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n")
+#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
+#define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
+
+#define STA_READ_RATE(name, field)					\
+static ssize_t sta_##name##_read(struct file *file,			\
+				 char __user *userbuf,			\
+				 size_t count, loff_t *ppos)		\
+{									\
+	struct sta_info *sta = file->private_data;			\
+	struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
+	struct ieee80211_hw_mode *mode = local->oper_hw_mode;		\
+	char buf[20];							\
+	int res = scnprintf(buf, sizeof(buf), "%d\n",			\
+			    (sta->field >= 0 &&				\
+			    sta->field < mode->num_rates) ?		\
+			    mode->rates[sta->field].rate : -1);		\
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+}
+
+#define STA_OPS(name)							\
+static const struct file_operations sta_ ##name## _ops = {		\
+	.read = sta_##name##_read,					\
+	.open = mac80211_open_file_generic,				\
+}
+
+#define STA_FILE(name, field, format)					\
+		STA_READ_##format(name, field)				\
+		STA_OPS(name)
+
+STA_FILE(aid, aid, D);
+STA_FILE(key_idx_compression, key_idx_compression, D);
+STA_FILE(dev, dev->name, S);
+STA_FILE(vlan_id, vlan_id, D);
+STA_FILE(rx_packets, rx_packets, LU);
+STA_FILE(tx_packets, tx_packets, LU);
+STA_FILE(rx_bytes, rx_bytes, LU);
+STA_FILE(tx_bytes, tx_bytes, LU);
+STA_FILE(rx_duplicates, num_duplicates, LU);
+STA_FILE(rx_fragments, rx_fragments, LU);
+STA_FILE(rx_dropped, rx_dropped, LU);
+STA_FILE(tx_fragments, tx_fragments, LU);
+STA_FILE(tx_filtered, tx_filtered_count, LU);
+STA_FILE(txrate, txrate, RATE);
+STA_FILE(last_txrate, last_txrate, RATE);
+STA_FILE(tx_retry_failed, tx_retry_failed, LU);
+STA_FILE(tx_retry_count, tx_retry_count, LU);
+STA_FILE(last_rssi, last_rssi, D);
+STA_FILE(last_signal, last_signal, D);
+STA_FILE(last_noise, last_noise, D);
+STA_FILE(channel_use, channel_use, D);
+STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D);
+
+static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	char buf[100];
+	struct sta_info *sta = file->private_data;
+	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+		sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
+		sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+		sta->flags & WLAN_STA_PS ? "PS\n" : "",
+		sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
+		sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
+		sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+		sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+		sta->flags & WLAN_STA_WME ? "WME\n" : "",
+		sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(flags);
+
+static ssize_t sta_num_ps_buf_frames_read(struct file *file,
+					  char __user *userbuf,
+					  size_t count, loff_t *ppos)
+{
+	char buf[20];
+	struct sta_info *sta = file->private_data;
+	int res = scnprintf(buf, sizeof(buf), "%u\n",
+			    skb_queue_len(&sta->ps_tx_buf));
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(num_ps_buf_frames);
+
+static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf,
+				      size_t count, loff_t *ppos)
+{
+	char buf[100];
+	struct sta_info *sta = file->private_data;
+	int res = scnprintf(buf, sizeof(buf), "%d %d %d\n",
+			    sta->last_ack_rssi[0],
+			    sta->last_ack_rssi[1],
+			    sta->last_ack_rssi[2]);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(last_ack_rssi);
+
+static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	char buf[20];
+	struct sta_info *sta = file->private_data;
+	int res = scnprintf(buf, sizeof(buf), "%d\n",
+			    sta->last_ack ?
+			    jiffies_to_msecs(jiffies - sta->last_ack) : -1);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(last_ack_ms);
+
+static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	char buf[20];
+	struct sta_info *sta = file->private_data;
+	int res = scnprintf(buf, sizeof(buf), "%d\n",
+			    jiffies_to_msecs(jiffies - sta->last_rx));
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(inactive_ms);
+
+static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
+				      size_t count, loff_t *ppos)
+{
+	char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%x ",
+			       sta->last_seq_ctrl[i]);
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(last_seq_ctrl);
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf,
+				     size_t count, loff_t *ppos)
+{
+	char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
+			       sta->wme_rx_queue[i]);
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(wme_rx_queue);
+
+static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
+				     size_t count, loff_t *ppos)
+{
+	char buf[15*NUM_TX_DATA_QUEUES], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
+			       sta->wme_tx_queue[i]);
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(wme_tx_queue);
+#endif
+
+#define DEBUGFS_ADD(name) \
+	sta->debugfs.name = debugfs_create_file(#name, 0444, \
+		sta->debugfs.dir, sta, &sta_ ##name## _ops);
+
+#define DEBUGFS_DEL(name) \
+	debugfs_remove(sta->debugfs.name);\
+	sta->debugfs.name = NULL;
+
+
+void ieee80211_sta_debugfs_add(struct sta_info *sta)
+{
+	char buf[3*6];
+	struct dentry *stations_dir = sta->local->debugfs.stations;
+
+	if (!stations_dir)
+		return;
+
+	sprintf(buf, MAC_FMT, MAC_ARG(sta->addr));
+
+	sta->debugfs.dir = debugfs_create_dir(buf, stations_dir);
+	if (!sta->debugfs.dir)
+		return;
+
+	DEBUGFS_ADD(flags);
+	DEBUGFS_ADD(num_ps_buf_frames);
+	DEBUGFS_ADD(last_ack_rssi);
+	DEBUGFS_ADD(last_ack_ms);
+	DEBUGFS_ADD(inactive_ms);
+	DEBUGFS_ADD(last_seq_ctrl);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	DEBUGFS_ADD(wme_rx_queue);
+	DEBUGFS_ADD(wme_tx_queue);
+#endif
+}
+
+void ieee80211_sta_debugfs_remove(struct sta_info *sta)
+{
+	DEBUGFS_DEL(flags);
+	DEBUGFS_DEL(num_ps_buf_frames);
+	DEBUGFS_DEL(last_ack_rssi);
+	DEBUGFS_DEL(last_ack_ms);
+	DEBUGFS_DEL(inactive_ms);
+	DEBUGFS_DEL(last_seq_ctrl);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	DEBUGFS_DEL(wme_rx_queue);
+	DEBUGFS_DEL(wme_tx_queue);
+#endif
+
+	debugfs_remove(sta->debugfs.dir);
+	sta->debugfs.dir = NULL;
+}
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h
new file mode 100644
index 0000000..574a1cd
--- /dev/null
+++ b/net/mac80211/debugfs_sta.h
@@ -0,0 +1,12 @@
+#ifndef __MAC80211_DEBUGFS_STA_H
+#define __MAC80211_DEBUGFS_STA_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_sta_debugfs_add(struct sta_info *sta);
+void ieee80211_sta_debugfs_remove(struct sta_info *sta);
+#else
+static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {}
+static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_STA_H */
diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h
new file mode 100644
index 0000000..34fa128
--- /dev/null
+++ b/net/mac80211/hostapd_ioctl.h
@@ -0,0 +1,108 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver
+ * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape 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 HOSTAPD_IOCTL_H
+#define HOSTAPD_IOCTL_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif /* __KERNEL__ */
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes:
+ * This table is no longer added to, the whole sub-ioctl
+ * mess shall be deleted completely. */
+enum {
+	PRISM2_PARAM_IEEE_802_1X = 23,
+	PRISM2_PARAM_ANTSEL_TX = 24,
+	PRISM2_PARAM_ANTSEL_RX = 25,
+
+	/* Instant802 additions */
+	PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
+	PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
+	PRISM2_PARAM_PREAMBLE = 1003,
+	PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
+	PRISM2_PARAM_NEXT_MODE = 1008,
+	PRISM2_PARAM_CLEAR_KEYS = 1009,
+	PRISM2_PARAM_RADIO_ENABLED = 1010,
+	PRISM2_PARAM_ANTENNA_MODE = 1013,
+	PRISM2_PARAM_STAT_TIME = 1016,
+	PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
+	PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
+	PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
+	PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
+	PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
+	PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
+	PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
+	PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
+	PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033,
+	PRISM2_PARAM_SCAN_FLAGS = 1035,
+	PRISM2_PARAM_HW_MODES = 1036,
+	PRISM2_PARAM_CREATE_IBSS = 1037,
+	PRISM2_PARAM_WMM_ENABLED = 1038,
+	PRISM2_PARAM_MIXED_CELL = 1039,
+	PRISM2_PARAM_RADAR_DETECT = 1043,
+	PRISM2_PARAM_SPECTRUM_MGMT = 1044,
+};
+
+enum {
+	IEEE80211_KEY_MGMT_NONE = 0,
+	IEEE80211_KEY_MGMT_IEEE8021X = 1,
+	IEEE80211_KEY_MGMT_WPA_PSK = 2,
+	IEEE80211_KEY_MGMT_WPA_EAP = 3,
+};
+
+
+/* Data structures used for get_hw_features ioctl */
+struct hostapd_ioctl_hw_modes_hdr {
+	int mode;
+	int num_channels;
+	int num_rates;
+};
+
+struct ieee80211_channel_data {
+	short chan; /* channel number (IEEE 802.11) */
+	short freq; /* frequency in MHz */
+	int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+};
+
+struct ieee80211_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* IEEE80211_RATE_ flags */
+};
+
+
+/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */
+enum {
+	HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3,
+	HOSTAP_IF_STA = 4
+};
+
+struct hostapd_if_wds {
+	u8 remote_addr[ETH_ALEN];
+};
+
+struct hostapd_if_vlan {
+	u8 id;
+};
+
+struct hostapd_if_bss {
+	u8 bssid[ETH_ALEN];
+};
+
+struct hostapd_if_sta {
+};
+
+#endif /* HOSTAPD_IOCTL_H */
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
new file mode 100644
index 0000000..6e36df6
--- /dev/null
+++ b/net/mac80211/ieee80211.c
@@ -0,0 +1,4984 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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 <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <linux/compiler.h>
+#include <linux/bitmap.h>
+#include <net/cfg80211.h>
+
+#include "ieee80211_common.h"
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "wep.h"
+#include "wpa.h"
+#include "tkip.h"
+#include "wme.h"
+#include "aes_ccm.h"
+#include "ieee80211_led.h"
+#include "ieee80211_cfg.h"
+#include "debugfs.h"
+#include "debugfs_netdev.h"
+#include "debugfs_key.h"
+
+/* privid for wiphys to determine whether they belong to us or not */
+void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static const unsigned char rfc1042_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static const unsigned char bridge_tunnel_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+
+/* No encapsulation header if EtherType < 0x600 (=length) */
+static const unsigned char eapol_header[] =
+	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+
+
+static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+					      struct ieee80211_hdr *hdr)
+{
+	/* Set the sequence number for this frame. */
+	hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
+
+	/* Increase the sequence number. */
+	sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+			const struct ieee80211_key *data)
+{
+	struct ieee80211_key_conf *conf;
+
+	conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
+	if (!conf)
+		return NULL;
+
+	conf->hw_key_idx = data->hw_key_idx;
+	conf->alg = data->alg;
+	conf->keylen = data->keylen;
+	conf->flags = 0;
+	if (data->force_sw_encrypt)
+		conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+	conf->keyidx = data->keyidx;
+	if (data->default_tx_key)
+		conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
+	if (local->default_wep_only)
+		conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
+	memcpy(conf->key, data->key, data->keylen);
+
+	return conf;
+}
+
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+					  int idx, size_t key_len, gfp_t flags)
+{
+	struct ieee80211_key *key;
+
+	key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
+	if (!key)
+		return NULL;
+	kref_init(&key->kref);
+	return key;
+}
+
+static void ieee80211_key_release(struct kref *kref)
+{
+	struct ieee80211_key *key;
+
+	key = container_of(kref, struct ieee80211_key, kref);
+	if (key->alg == ALG_CCMP)
+		ieee80211_aes_key_free(key->u.ccmp.tfm);
+	ieee80211_debugfs_key_remove(key);
+	kfree(key);
+}
+
+void ieee80211_key_free(struct ieee80211_key *key)
+{
+	if (key)
+		kref_put(&key->kref, ieee80211_key_release);
+}
+
+static int rate_list_match(const int *rate_list, int rate)
+{
+	int i;
+
+	if (!rate_list)
+		return 0;
+
+	for (i = 0; rate_list[i] >= 0; i++)
+		if (rate_list[i] == rate)
+			return 1;
+
+	return 0;
+}
+
+
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+			     struct ieee80211_hw_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+
+		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
+				 IEEE80211_RATE_BASIC);
+
+		if (local->supp_rates[mode->mode]) {
+			if (!rate_list_match(local->supp_rates[mode->mode],
+					     rate->rate))
+				continue;
+		}
+
+		rate->flags |= IEEE80211_RATE_SUPPORTED;
+
+		/* Use configured basic rate set if it is available. If not,
+		 * use defaults that are sane for most cases. */
+		if (local->basic_rates[mode->mode]) {
+			if (rate_list_match(local->basic_rates[mode->mode],
+					    rate->rate))
+				rate->flags |= IEEE80211_RATE_BASIC;
+		} else switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10 || rate->rate == 20)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_ATHEROS_TURBO:
+			if (rate->rate == 120 || rate->rate == 240 ||
+			    rate->rate == 480)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110)
+				rate->flags |= IEEE80211_RATE_BASIC;
+			break;
+		}
+
+		/* Set ERP and MANDATORY flags based on phymode */
+		switch (mode->mode) {
+		case MODE_IEEE80211A:
+			if (rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_IEEE80211B:
+			if (rate->rate == 10)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		case MODE_ATHEROS_TURBO:
+			break;
+		case MODE_IEEE80211G:
+			if (rate->rate == 10 || rate->rate == 20 ||
+			    rate->rate == 55 || rate->rate == 110 ||
+			    rate->rate == 60 || rate->rate == 120 ||
+			    rate->rate == 240)
+				rate->flags |= IEEE80211_RATE_MANDATORY;
+			break;
+		}
+		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
+			rate->flags |= IEEE80211_RATE_ERP;
+	}
+}
+
+
+static void ieee80211_key_threshold_notify(struct net_device *dev,
+					   struct ieee80211_key *key,
+					   struct sta_info *sta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	struct ieee80211_msg_key_notification *msg;
+
+	/* if no one will get it anyway, don't even allocate it.
+	 * unlikely because this is only relevant for APs
+	 * where the device must be open... */
+	if (unlikely(!local->apdev))
+		return;
+
+	skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+			    sizeof(struct ieee80211_msg_key_notification));
+	if (!skb)
+		return;
+
+	skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+	msg = (struct ieee80211_msg_key_notification *)
+		skb_put(skb, sizeof(struct ieee80211_msg_key_notification));
+	msg->tx_rx_count = key->tx_rx_count;
+	memcpy(msg->ifname, dev->name, IFNAMSIZ);
+	if (sta)
+		memcpy(msg->addr, sta->addr, ETH_ALEN);
+	else
+		memset(msg->addr, 0xff, ETH_ALEN);
+
+	key->tx_rx_count = 0;
+
+	ieee80211_rx_mgmt(local, skb, NULL,
+			  ieee80211_msg_key_threshold_notification);
+}
+
+
+static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc;
+
+	if (len < 24)
+		return NULL;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+		case IEEE80211_FCTL_TODS:
+			return hdr->addr1;
+		case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+			return NULL;
+		case IEEE80211_FCTL_FROMDS:
+			return hdr->addr2;
+		case 0:
+			return hdr->addr3;
+		}
+		break;
+	case IEEE80211_FTYPE_MGMT:
+		return hdr->addr3;
+	case IEEE80211_FTYPE_CTL:
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
+			return hdr->addr1;
+		else
+			return NULL;
+	}
+
+	return NULL;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+	int hdrlen = 24;
+
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_DATA:
+		if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+			hdrlen = 30; /* Addr4 */
+		/*
+		 * The QoS Control field is two bytes and its presence is
+		 * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
+		 * hdrlen if that bit is set.
+		 * This works by masking out the bit and shifting it to
+		 * bit position 1 so the result has the value 0 or 2.
+		 */
+		hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
+				>> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
+		break;
+	case IEEE80211_FTYPE_CTL:
+		/*
+		 * ACK and CTS are 10 bytes, all others 16. To see how
+		 * to get this condition consider
+		 *   subtype mask:   0b0000000011110000 (0x00F0)
+		 *   ACK subtype:    0b0000000011010000 (0x00D0)
+		 *   CTS subtype:    0b0000000011000000 (0x00C0)
+		 *   bits that matter:         ^^^      (0x00E0)
+		 *   value of those: 0b0000000011000000 (0x00C0)
+		 */
+		if ((fc & 0xE0) == 0xC0)
+			hdrlen = 10;
+		else
+			hdrlen = 16;
+		break;
+	}
+
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen);
+
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
+	int hdrlen;
+
+	if (unlikely(skb->len < 10))
+		return 0;
+	hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+	if (unlikely(hdrlen > skb->len))
+		return 0;
+	return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+
+static int ieee80211_get_radiotap_len(struct sk_buff *skb)
+{
+	struct ieee80211_radiotap_header *hdr =
+		(struct ieee80211_radiotap_header *) skb->data;
+
+	return le16_to_cpu(hdr->it_len);
+}
+
+#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
+static void ieee80211_dump_frame(const char *ifname, const char *title,
+				 const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+
+	printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
+	if (skb->len < 4) {
+		printk("\n");
+		return;
+	}
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+	if (hdrlen > skb->len)
+		hdrlen = skb->len;
+	if (hdrlen >= 4)
+		printk(" FC=0x%04x DUR=0x%04x",
+		       fc, le16_to_cpu(hdr->duration_id));
+	if (hdrlen >= 10)
+		printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1));
+	if (hdrlen >= 16)
+		printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
+	if (hdrlen >= 24)
+		printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
+	if (hdrlen >= 30)
+		printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
+	printk("\n");
+}
+#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+static inline void ieee80211_dump_frame(const char *ifname, const char *title,
+					struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+
+
+static int ieee80211_is_eapol(const struct sk_buff *skb)
+{
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+	int hdrlen;
+
+	if (unlikely(skb->len < 10))
+		return 0;
+
+	hdr = (const struct ieee80211_hdr *) skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
+
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return 0;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
+		     memcmp(skb->data + hdrlen, eapol_header,
+			    sizeof(eapol_header)) == 0))
+		return 1;
+
+	return 0;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
+{
+	struct rate_control_extra extra;
+
+	memset(&extra, 0, sizeof(extra));
+	extra.mode = tx->u.tx.mode;
+	extra.mgmt_data = tx->sdata &&
+		tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
+	extra.ethertype = tx->ethertype;
+
+	tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
+					      &extra);
+	if (unlikely(extra.probe != NULL)) {
+		tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE;
+		tx->u.tx.probe_last_frag = 1;
+		tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
+		tx->u.tx.rate = extra.probe;
+	} else {
+		tx->u.tx.control->alt_retry_rate = -1;
+	}
+	if (!tx->u.tx.rate)
+		return TXRX_DROP;
+	if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
+	    tx->local->cts_protect_erp_frames && tx->fragmented &&
+	    extra.nonerp) {
+		tx->u.tx.last_frag_rate = tx->u.tx.rate;
+		tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
+
+		tx->u.tx.rate = extra.nonerp;
+		tx->u.tx.control->rate = extra.nonerp;
+		tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+	} else {
+		tx->u.tx.last_frag_rate = tx->u.tx.rate;
+		tx->u.tx.control->rate = tx->u.tx.rate;
+	}
+	tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+	if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+	    tx->local->short_preamble &&
+	    (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
+		tx->u.tx.short_preamble = 1;
+		tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
+{
+	if (tx->sta)
+		tx->u.tx.control->key_idx = tx->sta->key_idx_compression;
+	else
+		tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
+
+	if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+		tx->key = NULL;
+	else if (tx->sta && tx->sta->key)
+		tx->key = tx->sta->key;
+	else if (tx->sdata->default_key)
+		tx->key = tx->sdata->default_key;
+	else if (tx->sdata->drop_unencrypted &&
+		 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
+		I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
+		return TXRX_DROP;
+	} else
+		tx->key = NULL;
+
+	if (tx->key) {
+		tx->key->tx_rx_count++;
+		if (unlikely(tx->local->key_tx_rx_threshold &&
+			     tx->key->tx_rx_count >
+			     tx->local->key_tx_rx_threshold)) {
+			ieee80211_key_threshold_notify(tx->dev, tx->key,
+						       tx->sta);
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
+	struct sk_buff **frags, *first, *frag;
+	int i;
+	u16 seq;
+	u8 *pos;
+	int frag_threshold = tx->local->fragmentation_threshold;
+
+	if (!tx->fragmented)
+		return TXRX_CONTINUE;
+
+	first = tx->skb;
+
+	hdrlen = ieee80211_get_hdrlen(tx->fc);
+	payload_len = first->len - hdrlen;
+	per_fragm = frag_threshold - hdrlen - FCS_LEN;
+	num_fragm = (payload_len + per_fragm - 1) / per_fragm;
+
+	frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
+	if (!frags)
+		goto fail;
+
+	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+	seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
+	pos = first->data + hdrlen + per_fragm;
+	left = payload_len - per_fragm;
+	for (i = 0; i < num_fragm - 1; i++) {
+		struct ieee80211_hdr *fhdr;
+		size_t copylen;
+
+		if (left <= 0)
+			goto fail;
+
+		/* reserve enough extra head and tail room for possible
+		 * encryption */
+		frag = frags[i] =
+			dev_alloc_skb(tx->local->hw.extra_tx_headroom +
+				      frag_threshold +
+				      IEEE80211_ENCRYPT_HEADROOM +
+				      IEEE80211_ENCRYPT_TAILROOM);
+		if (!frag)
+			goto fail;
+		/* Make sure that all fragments use the same priority so
+		 * that they end up using the same TX queue */
+		frag->priority = first->priority;
+		skb_reserve(frag, tx->local->hw.extra_tx_headroom +
+			IEEE80211_ENCRYPT_HEADROOM);
+		fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
+		memcpy(fhdr, first->data, hdrlen);
+		if (i == num_fragm - 2)
+			fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+		fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
+		copylen = left > per_fragm ? per_fragm : left;
+		memcpy(skb_put(frag, copylen), pos, copylen);
+
+		pos += copylen;
+		left -= copylen;
+	}
+	skb_trim(first, hdrlen + per_fragm);
+
+	tx->u.tx.num_extra_frag = num_fragm - 1;
+	tx->u.tx.extra_frag = frags;
+
+	return TXRX_CONTINUE;
+
+ fail:
+	printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
+	if (frags) {
+		for (i = 0; i < num_fragm - 1; i++)
+			if (frags[i])
+				dev_kfree_skb(frags[i]);
+		kfree(frags);
+	}
+	I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
+	return TXRX_DROP;
+}
+
+
+static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
+{
+	if (tx->key->force_sw_encrypt) {
+		if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+			return -1;
+	} else {
+		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+			if (ieee80211_wep_add_iv(tx->local, skb, tx->key) ==
+			    NULL)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+
+	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	if (tx->u.tx.extra_frag) {
+		struct ieee80211_hdr *fhdr;
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			fhdr = (struct ieee80211_hdr *)
+				tx->u.tx.extra_frag[i]->data;
+			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		}
+	}
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	u16 fc;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	if (!tx->key || tx->key->alg != ALG_WEP ||
+	    ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+	     ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+	      (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
+		return TXRX_CONTINUE;
+
+	tx->u.tx.control->iv_len = WEP_IV_LEN;
+	tx->u.tx.control->icv_len = WEP_ICV_LEN;
+	ieee80211_tx_set_iswep(tx);
+
+	if (wep_encrypt_skb(tx, tx->skb) < 0) {
+		I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
+		return TXRX_DROP;
+	}
+
+	if (tx->u.tx.extra_frag) {
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
+				I802_DEBUG_INC(tx->local->
+					       tx_handlers_drop_wep);
+				return TXRX_DROP;
+			}
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+				    int rate, int erp, int short_preamble)
+{
+	int dur;
+
+	/* calculate duration (in microseconds, rounded up to next higher
+	 * integer if it includes a fractional microsecond) to send frame of
+	 * len bytes (does not include FCS) at the given rate. Duration will
+	 * also include SIFS.
+	 *
+	 * rate is in 100 kbps, so divident is multiplied by 10 in the
+	 * DIV_ROUND_UP() operations.
+	 */
+
+	if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
+	    local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
+		/*
+		 * OFDM:
+		 *
+		 * N_DBPS = DATARATE x 4
+		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
+		 *	(16 = SIGNAL time, 6 = tail bits)
+		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
+		 *
+		 * T_SYM = 4 usec
+		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
+		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
+		 *	signal ext = 6 usec
+		 */
+		/* FIX: Atheros Turbo may have different (shorter) duration? */
+		dur = 16; /* SIFS + signal ext */
+		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
+		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+					4 * rate); /* T_SYM x N_SYM */
+	} else {
+		/*
+		 * 802.11b or 802.11g with 802.11b compatibility:
+		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
+		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
+		 *
+		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
+		 * aSIFSTime = 10 usec
+		 * aPreambleLength = 144 usec or 72 usec with short preamble
+		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+		 */
+		dur = 10; /* aSIFSTime = 10 usec */
+		dur += short_preamble ? (72 + 24) : (144 + 48);
+
+		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+	}
+
+	return dur;
+}
+
+
+/* Exported duration function for driver use */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+					size_t frame_len, int rate)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	u16 dur;
+	int erp;
+
+	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
+	dur = ieee80211_frame_duration(local, frame_len, rate,
+				       erp, local->short_preamble);
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_generic_frame_duration);
+
+
+static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
+			      int next_frag_len)
+{
+	int rate, mrate, erp, dur, i;
+	struct ieee80211_rate *txrate = tx->u.tx.rate;
+	struct ieee80211_local *local = tx->local;
+	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+	erp = txrate->flags & IEEE80211_RATE_ERP;
+
+	/*
+	 * data and mgmt (except PS Poll):
+	 * - during CFP: 32768
+	 * - during contention period:
+	 *   if addr1 is group address: 0
+	 *   if more fragments = 0 and addr1 is individual address: time to
+	 *      transmit one ACK plus SIFS
+	 *   if more fragments = 1 and addr1 is individual address: time to
+	 *      transmit next fragment plus 2 x ACK plus 3 x SIFS
+	 *
+	 * IEEE 802.11, 9.6:
+	 * - control response frame (CTS or ACK) shall be transmitted using the
+	 *   same rate as the immediately previous frame in the frame exchange
+	 *   sequence, if this rate belongs to the PHY mandatory rates, or else
+	 *   at the highest possible rate belonging to the PHY rates in the
+	 *   BSSBasicRateSet
+	 */
+
+	if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {
+		/* TODO: These control frames are not currently sent by
+		 * 80211.o, but should they be implemented, this function
+		 * needs to be updated to support duration field calculation.
+		 *
+		 * RTS: time needed to transmit pending data/mgmt frame plus
+		 *    one CTS frame plus one ACK frame plus 3 x SIFS
+		 * CTS: duration of immediately previous RTS minus time
+		 *    required to transmit CTS and its SIFS
+		 * ACK: 0 if immediately previous directed data/mgmt had
+		 *    more=0, with more=1 duration in ACK frame is duration
+		 *    from previous frame minus time needed to transmit ACK
+		 *    and its SIFS
+		 * PS Poll: BIT(15) | BIT(14) | aid
+		 */
+		return 0;
+	}
+
+	/* data/mgmt */
+	if (0 /* FIX: data/mgmt during CFP */)
+		return 32768;
+
+	if (group_addr) /* Group address as the destination - no ACK */
+		return 0;
+
+	/* Individual destination address:
+	 * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
+	 * CTS and ACK frames shall be transmitted using the highest rate in
+	 * basic rate set that is less than or equal to the rate of the
+	 * immediately previous frame and that is using the same modulation
+	 * (CCK or OFDM). If no basic rate set matches with these requirements,
+	 * the highest mandatory rate of the PHY that is less than or equal to
+	 * the rate of the previous frame is used.
+	 * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
+	 */
+	rate = -1;
+	mrate = 10; /* use 1 Mbps if everything fails */
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *r = &mode->rates[i];
+		if (r->rate > txrate->rate)
+			break;
+
+		if (IEEE80211_RATE_MODULATION(txrate->flags) !=
+		    IEEE80211_RATE_MODULATION(r->flags))
+			continue;
+
+		if (r->flags & IEEE80211_RATE_BASIC)
+			rate = r->rate;
+		else if (r->flags & IEEE80211_RATE_MANDATORY)
+			mrate = r->rate;
+	}
+	if (rate == -1) {
+		/* No matching basic rate found; use highest suitable mandatory
+		 * PHY rate */
+		rate = mrate;
+	}
+
+	/* Time needed to transmit ACK
+	 * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
+	 * to closest integer */
+
+	dur = ieee80211_frame_duration(local, 10, rate, erp,
+				       local->short_preamble);
+
+	if (next_frag_len) {
+		/* Frame is fragmented: duration increases with time needed to
+		 * transmit next fragment plus ACK and 2 x SIFS. */
+		dur *= 2; /* ACK + SIFS */
+		/* next fragment */
+		dur += ieee80211_frame_duration(local, next_frag_len,
+						txrate->rate, erp,
+						local->short_preamble);
+	}
+
+	return dur;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	u16 dur;
+	struct ieee80211_tx_control *control = tx->u.tx.control;
+	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+	if (!is_multicast_ether_addr(hdr->addr1)) {
+		if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
+		    tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
+			control->flags |= IEEE80211_TXCTL_USE_RTS_CTS;
+			control->retry_limit =
+				tx->local->long_retry_limit;
+		} else {
+			control->retry_limit =
+				tx->local->short_retry_limit;
+		}
+	} else {
+		control->retry_limit = 1;
+	}
+
+	if (tx->fragmented) {
+		/* Do not use multiple retry rates when sending fragmented
+		 * frames.
+		 * TODO: The last fragment could still use multiple retry
+		 * rates. */
+		control->alt_retry_rate = -1;
+	}
+
+	/* Use CTS protection for unicast frames sent using extended rates if
+	 * there are associated non-ERP stations and RTS/CTS is not configured
+	 * for the frame. */
+	if (mode->mode == MODE_IEEE80211G &&
+	    (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
+	    tx->u.tx.unicast &&
+	    tx->local->cts_protect_erp_frames &&
+	    !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
+		control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
+
+	/* Setup duration field for the first fragment of the frame. Duration
+	 * for remaining fragments will be updated when they are being sent
+	 * to low-level driver in ieee80211_tx(). */
+	dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+				 tx->fragmented ? tx->u.tx.extra_frag[0]->len :
+				 0);
+	hdr->duration_id = cpu_to_le16(dur);
+
+	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+	    (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+		struct ieee80211_rate *rate;
+
+		/* Do not use multiple retry rates when using RTS/CTS */
+		control->alt_retry_rate = -1;
+
+		/* Use min(data rate, max base rate) as CTS/RTS rate */
+		rate = tx->u.tx.rate;
+		while (rate > mode->rates &&
+		       !(rate->flags & IEEE80211_RATE_BASIC))
+			rate--;
+
+		control->rts_cts_rate = rate->val;
+		control->rts_rate = rate;
+	}
+
+	if (tx->sta) {
+		tx->sta->tx_packets++;
+		tx->sta->tx_fragments++;
+		tx->sta->tx_bytes += tx->skb->len;
+		if (tx->u.tx.extra_frag) {
+			int i;
+			tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
+			for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+				tx->sta->tx_bytes +=
+					tx->u.tx.extra_frag[i]->len;
+			}
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	struct sk_buff *skb = tx->skb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	u32 sta_flags;
+
+	if (unlikely(tx->local->sta_scanning != 0) &&
+	    ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+	     (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
+		return TXRX_DROP;
+
+	if (tx->u.tx.ps_buffered)
+		return TXRX_CONTINUE;
+
+	sta_flags = tx->sta ? tx->sta->flags : 0;
+
+	if (likely(tx->u.tx.unicast)) {
+		if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
+			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+			     (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			printk(KERN_DEBUG "%s: dropped data frame to not "
+			       "associated station " MAC_FMT "\n",
+			       tx->dev->name, MAC_ARG(hdr->addr1));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
+			return TXRX_DROP;
+		}
+	} else {
+		if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+			     tx->local->num_sta == 0 &&
+			     !tx->local->allow_broadcast_always &&
+			     tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
+			/*
+			 * No associated STAs - no need to send multicast
+			 * frames.
+			 */
+			return TXRX_DROP;
+		}
+		return TXRX_CONTINUE;
+	}
+
+	if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
+		     !(sta_flags & WLAN_STA_AUTHORIZED))) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
+		       " (unauthorized port)\n", tx->dev->name,
+		       MAC_ARG(hdr->addr1));
+#endif
+		I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
+		return TXRX_DROP;
+	}
+
+	return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+	if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+		ieee80211_include_sequence(tx->sdata, hdr);
+
+	return TXRX_CONTINUE;
+}
+
+/* This function is called whenever the AP is about to exceed the maximum limit
+ * of buffered frames for power saving STAs. This situation should not really
+ * happen often during normal operation, so dropping the oldest buffered packet
+ * from each queue should be OK to make some room for new frames. */
+static void purge_old_ps_buffers(struct ieee80211_local *local)
+{
+	int total = 0, purged = 0;
+	struct sk_buff *skb;
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		struct ieee80211_if_ap *ap;
+		if (sdata->dev == local->mdev ||
+		    sdata->type != IEEE80211_IF_TYPE_AP)
+			continue;
+		ap = &sdata->u.ap;
+		skb = skb_dequeue(&ap->ps_bc_buf);
+		if (skb) {
+			purged++;
+			dev_kfree_skb(skb);
+		}
+		total += skb_queue_len(&ap->ps_bc_buf);
+	}
+	read_unlock(&local->sub_if_lock);
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		skb = skb_dequeue(&sta->ps_tx_buf);
+		if (skb) {
+			purged++;
+			dev_kfree_skb(skb);
+		}
+		total += skb_queue_len(&sta->ps_tx_buf);
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	local->total_ps_buffered = total;
+	printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
+	       local->mdev->name, purged);
+}
+
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+	/* broadcast/multicast frame */
+	/* If any of the associated stations is in power save mode,
+	 * the frame is buffered to be sent after DTIM beacon frame */
+	if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&
+	    tx->sdata->type != IEEE80211_IF_TYPE_WDS &&
+	    tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&
+	    !(tx->fc & IEEE80211_FCTL_ORDER)) {
+		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+			purge_old_ps_buffers(tx->local);
+		if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
+		    AP_MAX_BC_BUFFER) {
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: BC TX buffer full - "
+				       "dropping the oldest frame\n",
+				       tx->dev->name);
+			}
+			dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
+		} else
+			tx->local->total_ps_buffered++;
+		skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
+		return TXRX_QUEUED;
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+	struct sta_info *sta = tx->sta;
+
+	if (unlikely(!sta ||
+		     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+		      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
+		return TXRX_CONTINUE;
+
+	if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
+		struct ieee80211_tx_packet_data *pkt_data;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+		printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries "
+		       "before %d)\n",
+		       MAC_ARG(sta->addr), sta->aid,
+		       skb_queue_len(&sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+		sta->flags |= WLAN_STA_TIM;
+		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+			purge_old_ps_buffers(tx->local);
+		if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
+			struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: STA " MAC_FMT " TX "
+				       "buffer full - dropping oldest frame\n",
+				       tx->dev->name, MAC_ARG(sta->addr));
+			}
+			dev_kfree_skb(old);
+		} else
+			tx->local->total_ps_buffered++;
+		/* Queue frame to be sent after STA sends an PS Poll frame */
+		if (skb_queue_empty(&sta->ps_tx_buf)) {
+			if (tx->local->ops->set_tim)
+				tx->local->ops->set_tim(local_to_hw(tx->local),
+						       sta->aid, 1);
+			if (tx->sdata->bss)
+				bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
+		}
+		pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
+		pkt_data->jiffies = jiffies;
+		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+		return TXRX_QUEUED;
+	}
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+	else if (unlikely(sta->flags & WLAN_STA_PS)) {
+		printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll "
+		       "set -> send frame\n", tx->dev->name,
+		       MAC_ARG(sta->addr));
+	}
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+	sta->pspoll = 0;
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
+{
+	if (unlikely(tx->u.tx.ps_buffered))
+		return TXRX_CONTINUE;
+
+	if (tx->u.tx.unicast)
+		return ieee80211_tx_h_unicast_ps_buf(tx);
+	else
+		return ieee80211_tx_h_multicast_ps_buf(tx);
+}
+
+
+static void inline
+__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+		       struct sk_buff *skb,
+		       struct net_device *dev,
+		       struct ieee80211_tx_control *control)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	int hdrlen;
+
+	memset(tx, 0, sizeof(*tx));
+	tx->skb = skb;
+	tx->dev = dev; /* use original interface */
+	tx->local = local;
+	tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	tx->sta = sta_info_get(local, hdr->addr1);
+	tx->fc = le16_to_cpu(hdr->frame_control);
+	control->power_level = local->hw.conf.power_level;
+	tx->u.tx.control = control;
+	tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
+	if (is_multicast_ether_addr(hdr->addr1))
+		control->flags |= IEEE80211_TXCTL_NO_ACK;
+	else
+		control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+	tx->fragmented = local->fragmentation_threshold <
+		IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast &&
+		skb->len + FCS_LEN > local->fragmentation_threshold &&
+		(!local->ops->set_frag_threshold);
+	if (!tx->sta)
+		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+	else if (tx->sta->clear_dst_mask) {
+		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+		tx->sta->clear_dst_mask = 0;
+	}
+	control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+	if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
+		control->antenna_sel_tx = tx->sta->antenna_sel_tx;
+	hdrlen = ieee80211_get_hdrlen(tx->fc);
+	if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
+		u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
+		tx->ethertype = (pos[0] << 8) | pos[1];
+	}
+	control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+
+}
+
+static int inline is_ieee80211_device(struct net_device *dev,
+				      struct net_device *master)
+{
+	return (wdev_priv(dev->ieee80211_ptr) ==
+		wdev_priv(master->ieee80211_ptr));
+}
+
+/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
+ * finished with it. */
+static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+				       struct sk_buff *skb,
+				       struct net_device *mdev,
+				       struct ieee80211_tx_control *control)
+{
+	struct ieee80211_tx_packet_data *pkt_data;
+	struct net_device *dev;
+
+	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+	dev = dev_get_by_index(pkt_data->ifindex);
+	if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+		dev_put(dev);
+		dev = NULL;
+	}
+	if (unlikely(!dev))
+		return -ENODEV;
+	__ieee80211_tx_prepare(tx, skb, dev, control);
+	return 0;
+}
+
+static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
+					    int queue)
+{
+	return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+
+static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
+					    int queue)
+{
+	return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
+}
+
+#define IEEE80211_TX_OK		0
+#define IEEE80211_TX_AGAIN	1
+#define IEEE80211_TX_FRAG_AGAIN	2
+
+static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_tx_control *control = tx->u.tx.control;
+	int ret, i;
+
+	if (!ieee80211_qdisc_installed(local->mdev) &&
+	    __ieee80211_queue_stopped(local, 0)) {
+		netif_stop_queue(local->mdev);
+		return IEEE80211_TX_AGAIN;
+	}
+	if (skb) {
+		ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
+		ret = local->ops->tx(local_to_hw(local), skb, control);
+		if (ret)
+			return IEEE80211_TX_AGAIN;
+		local->mdev->trans_start = jiffies;
+		ieee80211_led_tx(local, 1);
+	}
+	if (tx->u.tx.extra_frag) {
+		control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+				    IEEE80211_TXCTL_USE_CTS_PROTECT |
+				    IEEE80211_TXCTL_CLEAR_DST_MASK |
+				    IEEE80211_TXCTL_FIRST_FRAGMENT);
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			if (!tx->u.tx.extra_frag[i])
+				continue;
+			if (__ieee80211_queue_stopped(local, control->queue))
+				return IEEE80211_TX_FRAG_AGAIN;
+			if (i == tx->u.tx.num_extra_frag) {
+				control->tx_rate = tx->u.tx.last_frag_hwrate;
+				control->rate = tx->u.tx.last_frag_rate;
+				if (tx->u.tx.probe_last_frag)
+					control->flags |=
+						IEEE80211_TXCTL_RATE_CTRL_PROBE;
+				else
+					control->flags &=
+						~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+			}
+
+			ieee80211_dump_frame(local->mdev->name,
+					     "TX to low-level driver",
+					     tx->u.tx.extra_frag[i]);
+			ret = local->ops->tx(local_to_hw(local),
+					    tx->u.tx.extra_frag[i],
+					    control);
+			if (ret)
+				return IEEE80211_TX_FRAG_AGAIN;
+			local->mdev->trans_start = jiffies;
+			ieee80211_led_tx(local, 1);
+			tx->u.tx.extra_frag[i] = NULL;
+		}
+		kfree(tx->u.tx.extra_frag);
+		tx->u.tx.extra_frag = NULL;
+	}
+	return IEEE80211_TX_OK;
+}
+
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
+			struct ieee80211_tx_control *control, int mgmt)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	ieee80211_tx_handler *handler;
+	struct ieee80211_txrx_data tx;
+	ieee80211_txrx_result res = TXRX_DROP;
+	int ret, i;
+
+	WARN_ON(__ieee80211_queue_pending(local, control->queue));
+
+	if (unlikely(skb->len < 10)) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	__ieee80211_tx_prepare(&tx, skb, dev, control);
+	sta = tx.sta;
+	tx.u.tx.mgmt_interface = mgmt;
+	tx.u.tx.mode = local->hw.conf.mode;
+
+	for (handler = local->tx_handlers; *handler != NULL; handler++) {
+		res = (*handler)(&tx);
+		if (res != TXRX_CONTINUE)
+			break;
+	}
+
+	skb = tx.skb; /* handlers are allowed to change skb */
+
+	if (sta)
+		sta_info_put(sta);
+
+	if (unlikely(res == TXRX_DROP)) {
+		I802_DEBUG_INC(local->tx_handlers_drop);
+		goto drop;
+	}
+
+	if (unlikely(res == TXRX_QUEUED)) {
+		I802_DEBUG_INC(local->tx_handlers_queued);
+		return 0;
+	}
+
+	if (tx.u.tx.extra_frag) {
+		for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
+			int next_len, dur;
+			struct ieee80211_hdr *hdr =
+				(struct ieee80211_hdr *)
+				tx.u.tx.extra_frag[i]->data;
+
+			if (i + 1 < tx.u.tx.num_extra_frag) {
+				next_len = tx.u.tx.extra_frag[i + 1]->len;
+			} else {
+				next_len = 0;
+				tx.u.tx.rate = tx.u.tx.last_frag_rate;
+				tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
+			}
+			dur = ieee80211_duration(&tx, 0, next_len);
+			hdr->duration_id = cpu_to_le16(dur);
+		}
+	}
+
+retry:
+	ret = __ieee80211_tx(local, skb, &tx);
+	if (ret) {
+		struct ieee80211_tx_stored_packet *store =
+			&local->pending_packet[control->queue];
+
+		if (ret == IEEE80211_TX_FRAG_AGAIN)
+			skb = NULL;
+		set_bit(IEEE80211_LINK_STATE_PENDING,
+			&local->state[control->queue]);
+		smp_mb();
+		/* When the driver gets out of buffers during sending of
+		 * fragments and calls ieee80211_stop_queue, there is
+		 * a small window between IEEE80211_LINK_STATE_XOFF and
+		 * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+		 * gets available in that window (i.e. driver calls
+		 * ieee80211_wake_queue), we would end up with ieee80211_tx
+		 * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+		 * continuing transmitting here when that situation is
+		 * possible to have happened. */
+		if (!__ieee80211_queue_stopped(local, control->queue)) {
+			clear_bit(IEEE80211_LINK_STATE_PENDING,
+				  &local->state[control->queue]);
+			goto retry;
+		}
+		memcpy(&store->control, control,
+		       sizeof(struct ieee80211_tx_control));
+		store->skb = skb;
+		store->extra_frag = tx.u.tx.extra_frag;
+		store->num_extra_frag = tx.u.tx.num_extra_frag;
+		store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
+		store->last_frag_rate = tx.u.tx.last_frag_rate;
+		store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
+	}
+	return 0;
+
+ drop:
+	if (skb)
+		dev_kfree_skb(skb);
+	for (i = 0; i < tx.u.tx.num_extra_frag; i++)
+		if (tx.u.tx.extra_frag[i])
+			dev_kfree_skb(tx.u.tx.extra_frag[i]);
+	kfree(tx.u.tx.extra_frag);
+	return 0;
+}
+
+static void ieee80211_tx_pending(unsigned long data)
+{
+	struct ieee80211_local *local = (struct ieee80211_local *)data;
+	struct net_device *dev = local->mdev;
+	struct ieee80211_tx_stored_packet *store;
+	struct ieee80211_txrx_data tx;
+	int i, ret, reschedule = 0;
+
+	netif_tx_lock_bh(dev);
+	for (i = 0; i < local->hw.queues; i++) {
+		if (__ieee80211_queue_stopped(local, i))
+			continue;
+		if (!__ieee80211_queue_pending(local, i)) {
+			reschedule = 1;
+			continue;
+		}
+		store = &local->pending_packet[i];
+		tx.u.tx.control = &store->control;
+		tx.u.tx.extra_frag = store->extra_frag;
+		tx.u.tx.num_extra_frag = store->num_extra_frag;
+		tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
+		tx.u.tx.last_frag_rate = store->last_frag_rate;
+		tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
+		ret = __ieee80211_tx(local, store->skb, &tx);
+		if (ret) {
+			if (ret == IEEE80211_TX_FRAG_AGAIN)
+				store->skb = NULL;
+		} else {
+			clear_bit(IEEE80211_LINK_STATE_PENDING,
+				  &local->state[i]);
+			reschedule = 1;
+		}
+	}
+	netif_tx_unlock_bh(dev);
+	if (reschedule) {
+		if (!ieee80211_qdisc_installed(dev)) {
+			if (!__ieee80211_queue_stopped(local, 0))
+				netif_wake_queue(dev);
+		} else
+			netif_schedule(dev);
+	}
+}
+
+static void ieee80211_clear_tx_pending(struct ieee80211_local *local)
+{
+	int i, j;
+	struct ieee80211_tx_stored_packet *store;
+
+	for (i = 0; i < local->hw.queues; i++) {
+		if (!__ieee80211_queue_pending(local, i))
+			continue;
+		store = &local->pending_packet[i];
+		kfree_skb(store->skb);
+		for (j = 0; j < store->num_extra_frag; j++)
+			kfree_skb(store->extra_frag[j]);
+		kfree(store->extra_frag);
+		clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+	}
+}
+
+static int ieee80211_master_start_xmit(struct sk_buff *skb,
+				       struct net_device *dev)
+{
+	struct ieee80211_tx_control control;
+	struct ieee80211_tx_packet_data *pkt_data;
+	struct net_device *odev = NULL;
+	struct ieee80211_sub_if_data *osdata;
+	int headroom;
+	int ret;
+
+	/*
+	 * copy control out of the skb so other people can use skb->cb
+	 */
+	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+	memset(&control, 0, sizeof(struct ieee80211_tx_control));
+
+	if (pkt_data->ifindex)
+		odev = dev_get_by_index(pkt_data->ifindex);
+	if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+		dev_put(odev);
+		odev = NULL;
+	}
+	if (unlikely(!odev)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
+		       "originating device\n", dev->name);
+#endif
+		dev_kfree_skb(skb);
+		return 0;
+	}
+	osdata = IEEE80211_DEV_TO_SUB_IF(odev);
+
+	headroom = osdata->local->hw.extra_tx_headroom +
+		IEEE80211_ENCRYPT_HEADROOM;
+	if (skb_headroom(skb) < headroom) {
+		if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	control.ifindex = odev->ifindex;
+	control.type = osdata->type;
+	if (pkt_data->req_tx_status)
+		control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
+	if (pkt_data->do_not_encrypt)
+		control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+	if (pkt_data->requeue)
+		control.flags |= IEEE80211_TXCTL_REQUEUE;
+	control.queue = pkt_data->queue;
+
+	ret = ieee80211_tx(odev, skb, &control,
+			   control.type == IEEE80211_IF_TYPE_MGMT);
+	dev_put(odev);
+
+	return ret;
+}
+
+
+/**
+ * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
+ * subinterfaces (wlan#, WDS, and VLAN interfaces)
+ * @skb: packet to be sent
+ * @dev: incoming interface
+ *
+ * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
+ * not be freed, and caller is responsible for either retrying later or freeing
+ * skb).
+ *
+ * This function takes in an Ethernet header and encapsulates it with suitable
+ * IEEE 802.11 header based on which interface the packet is coming in. The
+ * encapsulated packet will then be passed to master interface, wlan#.11, for
+ * transmission (through low-level driver).
+ */
+static int ieee80211_subif_start_xmit(struct sk_buff *skb,
+				      struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_tx_packet_data *pkt_data;
+	struct ieee80211_sub_if_data *sdata;
+	int ret = 1, head_need;
+	u16 ethertype, hdrlen, fc;
+	struct ieee80211_hdr hdr;
+	const u8 *encaps_data;
+	int encaps_len, skip_header_bytes;
+	int nh_pos, h_pos, no_encrypt = 0;
+	struct sta_info *sta;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (unlikely(skb->len < ETH_HLEN)) {
+		printk(KERN_DEBUG "%s: short skb (len=%d)\n",
+		       dev->name, skb->len);
+		ret = 0;
+		goto fail;
+	}
+
+	nh_pos = skb_network_header(skb) - skb->data;
+	h_pos = skb_transport_header(skb) - skb->data;
+
+	/* convert Ethernet header to proper 802.11 header (based on
+	 * operation mode) */
+	ethertype = (skb->data[12] << 8) | skb->data[13];
+	/* TODO: handling for 802.1x authorized/unauthorized port */
+	fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+	if (likely(sdata->type == IEEE80211_IF_TYPE_AP ||
+		   sdata->type == IEEE80211_IF_TYPE_VLAN)) {
+		fc |= IEEE80211_FCTL_FROMDS;
+		/* DA BSSID SA */
+		memcpy(hdr.addr1, skb->data, ETH_ALEN);
+		memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+		hdrlen = 24;
+	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+		fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+		/* RA TA DA SA */
+		memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
+		memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data, ETH_ALEN);
+		memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+		hdrlen = 30;
+	} else if (sdata->type == IEEE80211_IF_TYPE_STA) {
+		fc |= IEEE80211_FCTL_TODS;
+		/* BSSID SA DA */
+		memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
+		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data, ETH_ALEN);
+		hdrlen = 24;
+	} else if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		/* DA SA BSSID */
+		memcpy(hdr.addr1, skb->data, ETH_ALEN);
+		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+		memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
+		hdrlen = 24;
+	} else {
+		ret = 0;
+		goto fail;
+	}
+
+	/* receiver is QoS enabled, use a QoS type frame */
+	sta = sta_info_get(local, hdr.addr1);
+	if (sta) {
+		if (sta->flags & WLAN_STA_WME) {
+			fc |= IEEE80211_STYPE_QOS_DATA;
+			hdrlen += 2;
+		}
+		sta_info_put(sta);
+	}
+
+	hdr.frame_control = cpu_to_le16(fc);
+	hdr.duration_id = 0;
+	hdr.seq_ctrl = 0;
+
+	skip_header_bytes = ETH_HLEN;
+	if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+		encaps_data = bridge_tunnel_header;
+		encaps_len = sizeof(bridge_tunnel_header);
+		skip_header_bytes -= 2;
+	} else if (ethertype >= 0x600) {
+		encaps_data = rfc1042_header;
+		encaps_len = sizeof(rfc1042_header);
+		skip_header_bytes -= 2;
+	} else {
+		encaps_data = NULL;
+		encaps_len = 0;
+	}
+
+	skb_pull(skb, skip_header_bytes);
+	nh_pos -= skip_header_bytes;
+	h_pos -= skip_header_bytes;
+
+	/* TODO: implement support for fragments so that there is no need to
+	 * reallocate and copy payload; it might be enough to support one
+	 * extra fragment that would be copied in the beginning of the frame
+	 * data.. anyway, it would be nice to include this into skb structure
+	 * somehow
+	 *
+	 * There are few options for this:
+	 * use skb->cb as an extra space for 802.11 header
+	 * allocate new buffer if not enough headroom
+	 * make sure that there is enough headroom in every skb by increasing
+	 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
+	 * alloc_skb() (net/core/skbuff.c)
+	 */
+	head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom;
+	head_need -= skb_headroom(skb);
+
+	/* We are going to modify skb data, so make a copy of it if happens to
+	 * be cloned. This could happen, e.g., with Linux bridge code passing
+	 * us broadcast frames. */
+
+	if (head_need > 0 || skb_cloned(skb)) {
+#if 0
+		printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
+		       "of headroom\n", dev->name, head_need);
+#endif
+
+		if (skb_cloned(skb))
+			I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+		else
+			I802_DEBUG_INC(local->tx_expand_skb_head);
+		/* Since we have to reallocate the buffer, make sure that there
+		 * is enough room for possible WEP IV/ICV and TKIP (8 bytes
+		 * before payload and 12 after). */
+		if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
+				     12, GFP_ATOMIC)) {
+			printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
+			       "\n", dev->name);
+			goto fail;
+		}
+	}
+
+	if (encaps_data) {
+		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+		nh_pos += encaps_len;
+		h_pos += encaps_len;
+	}
+	memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+	nh_pos += hdrlen;
+	h_pos += hdrlen;
+
+	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+	pkt_data->ifindex = sdata->dev->ifindex;
+	pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+	pkt_data->do_not_encrypt = no_encrypt;
+
+	skb->dev = local->mdev;
+	sdata->stats.tx_packets++;
+	sdata->stats.tx_bytes += skb->len;
+
+	/* Update skb pointers to various headers since this modified frame
+	 * is going to go through Linux networking code that may potentially
+	 * need things like pointer to IP header. */
+	skb_set_mac_header(skb, 0);
+	skb_set_network_header(skb, nh_pos);
+	skb_set_transport_header(skb, h_pos);
+
+	dev->trans_start = jiffies;
+	dev_queue_xmit(skb);
+
+	return 0;
+
+ fail:
+	if (!ret)
+		dev_kfree_skb(skb);
+
+	return ret;
+}
+
+
+/*
+ * This is the transmit routine for the 802.11 type interfaces
+ * called by upper layers of the linux networking
+ * stack when it has a frame to transmit
+ */
+static int
+ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_tx_packet_data *pkt_data;
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (skb->len < 10) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) {
+		if (pskb_expand_head(skb,
+		    sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
+
+	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+	pkt_data->ifindex = sdata->dev->ifindex;
+	pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+
+	skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
+	skb->dev = sdata->local->mdev;
+
+	/*
+	 * We're using the protocol field of the the frame control header
+	 * to request TX callback for hostapd. BIT(1) is checked.
+	 */
+	if ((fc & BIT(1)) == BIT(1)) {
+		pkt_data->req_tx_status = 1;
+		fc &= ~BIT(1);
+		hdr->frame_control = cpu_to_le16(fc);
+	}
+
+	pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
+
+	sdata->stats.tx_packets++;
+	sdata->stats.tx_bytes += skb->len;
+
+	dev_queue_xmit(skb);
+
+	return 0;
+}
+
+
+static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
+				     struct ieee80211_if_ap *bss,
+				     struct sk_buff *skb)
+{
+	u8 *pos, *tim;
+	int aid0 = 0;
+	int i, have_bits = 0, n1, n2;
+
+	/* Generate bitmap for TIM only if there are any STAs in power save
+	 * mode. */
+	spin_lock_bh(&local->sta_lock);
+	if (atomic_read(&bss->num_sta_ps) > 0)
+		/* in the hope that this is faster than
+		 * checking byte-for-byte */
+		have_bits = !bitmap_empty((unsigned long*)bss->tim,
+					  IEEE80211_MAX_AID+1);
+
+	if (bss->dtim_count == 0)
+		bss->dtim_count = bss->dtim_period - 1;
+	else
+		bss->dtim_count--;
+
+	tim = pos = (u8 *) skb_put(skb, 6);
+	*pos++ = WLAN_EID_TIM;
+	*pos++ = 4;
+	*pos++ = bss->dtim_count;
+	*pos++ = bss->dtim_period;
+
+	if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
+		aid0 = 1;
+
+	if (have_bits) {
+		/* Find largest even number N1 so that bits numbered 1 through
+		 * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
+		 * (N2 + 1) x 8 through 2007 are 0. */
+		n1 = 0;
+		for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
+			if (bss->tim[i]) {
+				n1 = i & 0xfe;
+				break;
+			}
+		}
+		n2 = n1;
+		for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
+			if (bss->tim[i]) {
+				n2 = i;
+				break;
+			}
+		}
+
+		/* Bitmap control */
+		*pos++ = n1 | aid0;
+		/* Part Virt Bitmap */
+		memcpy(pos, bss->tim + n1, n2 - n1 + 1);
+
+		tim[1] = n2 - n1 + 4;
+		skb_put(skb, n2 - n1);
+	} else {
+		*pos++ = aid0; /* Bitmap control */
+		*pos++ = 0; /* Part Virt Bitmap */
+	}
+	spin_unlock_bh(&local->sta_lock);
+}
+
+
+struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
+				      struct ieee80211_tx_control *control)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sk_buff *skb;
+	struct net_device *bdev;
+	struct ieee80211_sub_if_data *sdata = NULL;
+	struct ieee80211_if_ap *ap = NULL;
+	struct ieee80211_rate *rate;
+	struct rate_control_extra extra;
+	u8 *b_head, *b_tail;
+	int bh_len, bt_len;
+
+	bdev = dev_get_by_index(if_id);
+	if (bdev) {
+		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+		ap = &sdata->u.ap;
+		dev_put(bdev);
+	}
+
+	if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
+	    !ap->beacon_head) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+		if (net_ratelimit())
+			printk(KERN_DEBUG "no beacon data avail for idx=%d "
+			       "(%s)\n", if_id, bdev ? bdev->name : "N/A");
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+		return NULL;
+	}
+
+	/* Assume we are generating the normal beacon locally */
+	b_head = ap->beacon_head;
+	b_tail = ap->beacon_tail;
+	bh_len = ap->beacon_head_len;
+	bt_len = ap->beacon_tail_len;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+		bh_len + bt_len + 256 /* maximum TIM len */);
+	if (!skb)
+		return NULL;
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	memcpy(skb_put(skb, bh_len), b_head, bh_len);
+
+	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
+
+	ieee80211_beacon_add_tim(local, ap, skb);
+
+	if (b_tail) {
+		memcpy(skb_put(skb, bt_len), b_tail, bt_len);
+	}
+
+	if (control) {
+		memset(&extra, 0, sizeof(extra));
+		extra.mode = local->oper_hw_mode;
+
+		rate = rate_control_get_rate(local, local->mdev, skb, &extra);
+		if (!rate) {
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
+				       "found\n", local->mdev->name);
+			}
+			dev_kfree_skb(skb);
+			return NULL;
+		}
+
+		control->tx_rate = (local->short_preamble &&
+				    (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+			rate->val2 : rate->val;
+		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+		control->power_level = local->hw.conf.power_level;
+		control->flags |= IEEE80211_TXCTL_NO_ACK;
+		control->retry_limit = 1;
+		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+	}
+
+	ap->num_beacons++;
+	return skb;
+}
+EXPORT_SYMBOL(ieee80211_beacon_get);
+
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+			      size_t frame_len,
+			      const struct ieee80211_tx_control *frame_txctl)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
+
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+	/* CTS duration */
+	dur = ieee80211_frame_duration(local, 10, rate->rate,
+				       erp, short_preamble);
+	/* Data frame duration */
+	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+					erp, short_preamble);
+	/* ACK duration */
+	dur += ieee80211_frame_duration(local, 10, rate->rate,
+					erp, short_preamble);
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_rts_duration);
+
+
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+				    size_t frame_len,
+				    const struct ieee80211_tx_control *frame_txctl)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int short_preamble = local->short_preamble;
+	int erp;
+	u16 dur;
+
+	rate = frame_txctl->rts_rate;
+	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+	/* Data frame duration */
+	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+				       erp, short_preamble);
+	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		/* ACK duration */
+		dur += ieee80211_frame_duration(local, 10, rate->rate,
+						erp, short_preamble);
+	}
+
+	return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+		       const void *frame, size_t frame_len,
+		       const struct ieee80211_tx_control *frame_txctl,
+		       struct ieee80211_rts *rts)
+{
+	const struct ieee80211_hdr *hdr = frame;
+	u16 fctl;
+
+	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
+	rts->frame_control = cpu_to_le16(fctl);
+	rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl);
+	memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
+	memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
+}
+EXPORT_SYMBOL(ieee80211_rts_get);
+
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+			     const void *frame, size_t frame_len,
+			     const struct ieee80211_tx_control *frame_txctl,
+			     struct ieee80211_cts *cts)
+{
+	const struct ieee80211_hdr *hdr = frame;
+	u16 fctl;
+
+	fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
+	cts->frame_control = cpu_to_le16(fctl);
+	cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl);
+	memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_get);
+
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+			  struct ieee80211_tx_control *control)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sk_buff *skb;
+	struct sta_info *sta;
+	ieee80211_tx_handler *handler;
+	struct ieee80211_txrx_data tx;
+	ieee80211_txrx_result res = TXRX_DROP;
+	struct net_device *bdev;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_ap *bss = NULL;
+
+	bdev = dev_get_by_index(if_id);
+	if (bdev) {
+		sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+		bss = &sdata->u.ap;
+		dev_put(bdev);
+	}
+	if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
+		return NULL;
+
+	if (bss->dtim_count != 0)
+		return NULL; /* send buffered bc/mc only after DTIM beacon */
+	memset(control, 0, sizeof(*control));
+	while (1) {
+		skb = skb_dequeue(&bss->ps_bc_buf);
+		if (!skb)
+			return NULL;
+		local->total_ps_buffered--;
+
+		if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
+			struct ieee80211_hdr *hdr =
+				(struct ieee80211_hdr *) skb->data;
+			/* more buffered multicast/broadcast frames ==> set
+			 * MoreData flag in IEEE 802.11 header to inform PS
+			 * STAs */
+			hdr->frame_control |=
+				cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+		}
+
+		if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0)
+			break;
+		dev_kfree_skb_any(skb);
+	}
+	sta = tx.sta;
+	tx.u.tx.ps_buffered = 1;
+
+	for (handler = local->tx_handlers; *handler != NULL; handler++) {
+		res = (*handler)(&tx);
+		if (res == TXRX_DROP || res == TXRX_QUEUED)
+			break;
+	}
+	dev_put(tx.dev);
+	skb = tx.skb; /* handlers are allowed to change skb */
+
+	if (res == TXRX_DROP) {
+		I802_DEBUG_INC(local->tx_handlers_drop);
+		dev_kfree_skb(skb);
+		skb = NULL;
+	} else if (res == TXRX_QUEUED) {
+		I802_DEBUG_INC(local->tx_handlers_queued);
+		skb = NULL;
+	}
+
+	if (sta)
+		sta_info_put(sta);
+
+	return skb;
+}
+EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+static int __ieee80211_if_config(struct net_device *dev,
+				 struct sk_buff *beacon,
+				 struct ieee80211_tx_control *control)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_if_conf conf;
+	static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	if (!local->ops->config_interface || !netif_running(dev))
+		return 0;
+
+	memset(&conf, 0, sizeof(conf));
+	conf.type = sdata->type;
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		if (local->sta_scanning &&
+		    local->scan_dev == dev)
+			conf.bssid = scan_bssid;
+		else
+			conf.bssid = sdata->u.sta.bssid;
+		conf.ssid = sdata->u.sta.ssid;
+		conf.ssid_len = sdata->u.sta.ssid_len;
+		conf.generic_elem = sdata->u.sta.extra_ie;
+		conf.generic_elem_len = sdata->u.sta.extra_ie_len;
+	} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+		conf.ssid = sdata->u.ap.ssid;
+		conf.ssid_len = sdata->u.ap.ssid_len;
+		conf.generic_elem = sdata->u.ap.generic_elem;
+		conf.generic_elem_len = sdata->u.ap.generic_elem_len;
+		conf.beacon = beacon;
+		conf.beacon_control = control;
+	}
+	return local->ops->config_interface(local_to_hw(local),
+					   dev->ifindex, &conf);
+}
+
+int ieee80211_if_config(struct net_device *dev)
+{
+	return __ieee80211_if_config(dev, NULL, NULL);
+}
+
+int ieee80211_if_config_beacon(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_tx_control control;
+	struct sk_buff *skb;
+
+	if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+		return 0;
+	skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+	if (!skb)
+		return -ENOMEM;
+	return __ieee80211_if_config(dev, skb, &control);
+}
+
+int ieee80211_hw_config(struct ieee80211_local *local)
+{
+	struct ieee80211_hw_mode *mode;
+	struct ieee80211_channel *chan;
+	int ret = 0;
+
+	if (local->sta_scanning) {
+		chan = local->scan_channel;
+		mode = local->scan_hw_mode;
+	} else {
+		chan = local->oper_channel;
+		mode = local->oper_hw_mode;
+	}
+
+	local->hw.conf.channel = chan->chan;
+	local->hw.conf.channel_val = chan->val;
+	local->hw.conf.power_level = chan->power_level;
+	local->hw.conf.freq = chan->freq;
+	local->hw.conf.phymode = mode->mode;
+	local->hw.conf.antenna_max = chan->antenna_max;
+	local->hw.conf.chan = chan;
+	local->hw.conf.mode = mode;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
+	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
+	       local->hw.conf.phymode);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+	if (local->ops->config)
+		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+
+	return ret;
+}
+
+
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* FIX: what would be proper limits for MTU?
+	 * This interface uses 802.3 frames. */
+	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+		printk(KERN_WARNING "%s: invalid MTU %d\n",
+		       dev->name, new_mtu);
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
+{
+	/* FIX: what would be proper limits for MTU?
+	 * This interface uses 802.11 frames. */
+	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
+		printk(KERN_WARNING "%s: invalid MTU %d\n",
+		       dev->name, new_mtu);
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+enum netif_tx_lock_class {
+	TX_LOCK_NORMAL,
+	TX_LOCK_MASTER,
+};
+
+static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
+{
+	spin_lock_nested(&dev->_xmit_lock, subclass);
+	dev->xmit_lock_owner = smp_processor_id();
+}
+
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	unsigned short flags;
+
+	netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
+	if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
+		if (sdata->allmulti) {
+			sdata->allmulti = 0;
+			local->iff_allmultis--;
+		} else {
+			sdata->allmulti = 1;
+			local->iff_allmultis++;
+		}
+	}
+	if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
+		if (sdata->promisc) {
+			sdata->promisc = 0;
+			local->iff_promiscs--;
+		} else {
+			sdata->promisc = 1;
+			local->iff_promiscs++;
+		}
+	}
+	if (dev->mc_count != sdata->mc_count) {
+		local->mc_count = local->mc_count - sdata->mc_count +
+				  dev->mc_count;
+		sdata->mc_count = dev->mc_count;
+	}
+	if (local->ops->set_multicast_list) {
+		flags = local->mdev->flags;
+		if (local->iff_allmultis)
+			flags |= IFF_ALLMULTI;
+		if (local->iff_promiscs)
+			flags |= IFF_PROMISC;
+		read_lock(&local->sub_if_lock);
+		local->ops->set_multicast_list(local_to_hw(local), flags,
+					      local->mc_count);
+		read_unlock(&local->sub_if_lock);
+	}
+	netif_tx_unlock(local->mdev);
+}
+
+struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
+					       struct dev_mc_list *prev,
+					       void **ptr)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = *ptr;
+	struct dev_mc_list *mc;
+
+	if (!prev) {
+		WARN_ON(sdata);
+		sdata = NULL;
+	}
+	if (!prev || !prev->next) {
+		if (sdata)
+			sdata = list_entry(sdata->list.next,
+					   struct ieee80211_sub_if_data, list);
+		else
+			sdata = list_entry(local->sub_if_list.next,
+					   struct ieee80211_sub_if_data, list);
+		if (&sdata->list != &local->sub_if_list)
+			mc = sdata->dev->mc_list;
+		else
+			mc = NULL;
+	} else
+		mc = prev->next;
+
+	*ptr = sdata;
+	return mc;
+}
+EXPORT_SYMBOL(ieee80211_get_mc_list_item);
+
+static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	return &(sdata->stats);
+}
+
+static void ieee80211_if_shutdown(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ASSERT_RTNL();
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		sdata->u.sta.state = IEEE80211_DISABLED;
+		del_timer_sync(&sdata->u.sta.timer);
+		skb_queue_purge(&sdata->u.sta.skb_queue);
+		if (!local->ops->hw_scan &&
+		    local->scan_dev == sdata->dev) {
+			local->sta_scanning = 0;
+			cancel_delayed_work(&local->scan_work);
+		}
+		flush_workqueue(local->hw.workqueue);
+		break;
+	}
+}
+
+static inline int identical_mac_addr_allowed(int type1, int type2)
+{
+	return (type1 == IEEE80211_IF_TYPE_MNTR ||
+		type2 == IEEE80211_IF_TYPE_MNTR ||
+		(type1 == IEEE80211_IF_TYPE_AP &&
+		 type2 == IEEE80211_IF_TYPE_WDS) ||
+		(type1 == IEEE80211_IF_TYPE_WDS &&
+		 (type2 == IEEE80211_IF_TYPE_WDS ||
+		  type2 == IEEE80211_IF_TYPE_AP)) ||
+		(type1 == IEEE80211_IF_TYPE_AP &&
+		 type2 == IEEE80211_IF_TYPE_VLAN) ||
+		(type1 == IEEE80211_IF_TYPE_VLAN &&
+		 (type2 == IEEE80211_IF_TYPE_AP ||
+		  type2 == IEEE80211_IF_TYPE_VLAN)));
+}
+
+static int ieee80211_master_open(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	int res = -EOPNOTSUPP;
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		if (sdata->dev != dev && netif_running(sdata->dev)) {
+			res = 0;
+			break;
+		}
+	}
+	read_unlock(&local->sub_if_lock);
+	return res;
+}
+
+static int ieee80211_master_stop(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list)
+		if (sdata->dev != dev && netif_running(sdata->dev))
+			dev_close(sdata->dev);
+	read_unlock(&local->sub_if_lock);
+
+	return 0;
+}
+
+static int ieee80211_mgmt_open(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (!netif_running(local->mdev))
+		return -EOPNOTSUPP;
+	return 0;
+}
+
+static int ieee80211_mgmt_stop(struct net_device *dev)
+{
+	return 0;
+}
+
+/* Check if running monitor interfaces should go to a "soft monitor" mode
+ * and switch them if necessary. */
+static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+{
+	struct ieee80211_if_init_conf conf;
+
+	if (local->open_count && local->open_count == local->monitors &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
+	    local->ops->remove_interface) {
+		conf.if_id = -1;
+		conf.type = IEEE80211_IF_TYPE_MNTR;
+		conf.mac_addr = NULL;
+		local->ops->remove_interface(local_to_hw(local), &conf);
+	}
+}
+
+/* Check if running monitor interfaces should go to a "hard monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
+{
+	struct ieee80211_if_init_conf conf;
+
+	if (local->open_count && local->open_count == local->monitors &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
+	    local->ops->add_interface) {
+		conf.if_id = -1;
+		conf.type = IEEE80211_IF_TYPE_MNTR;
+		conf.mac_addr = NULL;
+		local->ops->add_interface(local_to_hw(local), &conf);
+	}
+}
+
+static int ieee80211_open(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata, *nsdata;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_if_init_conf conf;
+	int res;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(nsdata, &local->sub_if_list, list) {
+		struct net_device *ndev = nsdata->dev;
+
+		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
+		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
+		    !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
+			read_unlock(&local->sub_if_lock);
+			return -ENOTUNIQ;
+		}
+	}
+	read_unlock(&local->sub_if_lock);
+
+	if (sdata->type == IEEE80211_IF_TYPE_WDS &&
+	    is_zero_ether_addr(sdata->u.wds.remote_addr))
+		return -ENOLINK;
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+		/* run the interface in a "soft monitor" mode */
+		local->monitors++;
+		local->open_count++;
+		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+		return 0;
+	}
+	ieee80211_start_soft_monitor(local);
+
+	if (local->ops->add_interface) {
+		conf.if_id = dev->ifindex;
+		conf.type = sdata->type;
+		conf.mac_addr = dev->dev_addr;
+		res = local->ops->add_interface(local_to_hw(local), &conf);
+		if (res) {
+			if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+				ieee80211_start_hard_monitor(local);
+			return res;
+		}
+	} else {
+		if (sdata->type != IEEE80211_IF_TYPE_STA)
+			return -EOPNOTSUPP;
+		if (local->open_count > 0)
+			return -ENOBUFS;
+	}
+
+	if (local->open_count == 0) {
+		res = 0;
+		tasklet_enable(&local->tx_pending_tasklet);
+		tasklet_enable(&local->tasklet);
+		if (local->ops->open)
+			res = local->ops->open(local_to_hw(local));
+		if (res == 0) {
+			res = dev_open(local->mdev);
+			if (res) {
+				if (local->ops->stop)
+					local->ops->stop(local_to_hw(local));
+			} else {
+				res = ieee80211_hw_config(local);
+				if (res && local->ops->stop)
+					local->ops->stop(local_to_hw(local));
+				else if (!res && local->apdev)
+					dev_open(local->apdev);
+			}
+		}
+		if (res) {
+			if (local->ops->remove_interface)
+				local->ops->remove_interface(local_to_hw(local),
+							    &conf);
+			return res;
+		}
+	}
+	local->open_count++;
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		local->monitors++;
+		local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+	} else
+		ieee80211_if_config(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA &&
+	    !local->user_space_mlme)
+		netif_carrier_off(dev);
+
+	netif_start_queue(dev);
+	return 0;
+}
+
+
+static int ieee80211_stop(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
+	    local->open_count > 1 &&
+	    !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+		/* remove "soft monitor" interface */
+		local->open_count--;
+		local->monitors--;
+		if (!local->monitors)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+		return 0;
+	}
+
+	netif_stop_queue(dev);
+	ieee80211_if_shutdown(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		local->monitors--;
+		if (!local->monitors)
+			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+	}
+
+	local->open_count--;
+	if (local->open_count == 0) {
+		if (netif_running(local->mdev))
+			dev_close(local->mdev);
+		if (local->apdev)
+			dev_close(local->apdev);
+		if (local->ops->stop)
+			local->ops->stop(local_to_hw(local));
+		tasklet_disable(&local->tx_pending_tasklet);
+		tasklet_disable(&local->tasklet);
+	}
+	if (local->ops->remove_interface) {
+		struct ieee80211_if_init_conf conf;
+
+		conf.if_id = dev->ifindex;
+		conf.type = sdata->type;
+		conf.mac_addr = dev->dev_addr;
+		local->ops->remove_interface(local_to_hw(local), &conf);
+	}
+
+	ieee80211_start_hard_monitor(local);
+
+	return 0;
+}
+
+
+static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+{
+	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+	return ETH_ALEN;
+}
+
+static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
+{
+	return compare_ether_addr(raddr, addr) == 0 ||
+	       is_broadcast_ether_addr(raddr);
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+{
+	struct net_device *dev = rx->dev;
+	struct ieee80211_local *local = rx->local;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+	u16 fc, hdrlen, ethertype;
+	u8 *payload;
+	u8 dst[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	struct sk_buff *skb = rx->skb, *skb2;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	fc = rx->fc;
+	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+		return TXRX_CONTINUE;
+
+	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+		return TXRX_DROP;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
+	 * header
+	 * IEEE 802.11 address fields:
+	 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
+	 *   0     0   DA    SA    BSSID n/a
+	 *   0     1   DA    BSSID SA    n/a
+	 *   1     0   BSSID SA    DA    n/a
+	 *   1     1   RA    TA    DA    SA
+	 */
+
+	switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+	case IEEE80211_FCTL_TODS:
+		/* BSSID SA DA */
+		memcpy(dst, hdr->addr3, ETH_ALEN);
+		memcpy(src, hdr->addr2, ETH_ALEN);
+
+		if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
+			     sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+			printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID="
+			       MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n",
+			       dev->name, MAC_ARG(hdr->addr1),
+			       MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3));
+			return TXRX_DROP;
+		}
+		break;
+	case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+		/* RA TA DA SA */
+		memcpy(dst, hdr->addr3, ETH_ALEN);
+		memcpy(src, hdr->addr4, ETH_ALEN);
+
+		if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+			printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA="
+			       MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA="
+			       MAC_FMT ")\n",
+			       rx->dev->name, MAC_ARG(hdr->addr1),
+			       MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3),
+			       MAC_ARG(hdr->addr4));
+			return TXRX_DROP;
+		}
+		break;
+	case IEEE80211_FCTL_FROMDS:
+		/* DA BSSID SA */
+		memcpy(dst, hdr->addr1, ETH_ALEN);
+		memcpy(src, hdr->addr3, ETH_ALEN);
+
+		if (sdata->type != IEEE80211_IF_TYPE_STA) {
+			return TXRX_DROP;
+		}
+		break;
+	case 0:
+		/* DA SA BSSID */
+		memcpy(dst, hdr->addr1, ETH_ALEN);
+		memcpy(src, hdr->addr2, ETH_ALEN);
+
+		if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+			if (net_ratelimit()) {
+				printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
+				       MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
+				       ")\n",
+				       dev->name, MAC_ARG(hdr->addr1),
+				       MAC_ARG(hdr->addr2),
+				       MAC_ARG(hdr->addr3));
+			}
+			return TXRX_DROP;
+		}
+		break;
+	}
+
+	payload = skb->data + hdrlen;
+
+	if (unlikely(skb->len - hdrlen < 8)) {
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: RX too short data frame "
+			       "payload\n", dev->name);
+		}
+		return TXRX_DROP;
+	}
+
+	ethertype = (payload[6] << 8) | payload[7];
+
+	if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+		    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+		   compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
+		/* remove RFC1042 or Bridge-Tunnel encapsulation and
+		 * replace EtherType */
+		skb_pull(skb, hdrlen + 6);
+		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+	} else {
+		struct ethhdr *ehdr;
+		__be16 len;
+		skb_pull(skb, hdrlen);
+		len = htons(skb->len);
+		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
+		memcpy(ehdr->h_dest, dst, ETH_ALEN);
+		memcpy(ehdr->h_source, src, ETH_ALEN);
+		ehdr->h_proto = len;
+	}
+	skb->dev = dev;
+
+	skb2 = NULL;
+
+	sdata->stats.rx_packets++;
+	sdata->stats.rx_bytes += skb->len;
+
+	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
+	    || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) {
+		if (is_multicast_ether_addr(skb->data)) {
+			/* send multicast frames both to higher layers in
+			 * local net stack and back to the wireless media */
+			skb2 = skb_copy(skb, GFP_ATOMIC);
+			if (!skb2)
+				printk(KERN_DEBUG "%s: failed to clone "
+				       "multicast frame\n", dev->name);
+		} else {
+			struct sta_info *dsta;
+			dsta = sta_info_get(local, skb->data);
+			if (dsta && !dsta->dev) {
+				printk(KERN_DEBUG "Station with null dev "
+				       "structure!\n");
+			} else if (dsta && dsta->dev == dev) {
+				/* Destination station is associated to this
+				 * AP, so send the frame directly to it and
+				 * do not pass the frame to local net stack.
+				 */
+				skb2 = skb;
+				skb = NULL;
+			}
+			if (dsta)
+				sta_info_put(dsta);
+		}
+	}
+
+	if (skb) {
+		/* deliver to local stack */
+		skb->protocol = eth_type_trans(skb, dev);
+		memset(skb->cb, 0, sizeof(skb->cb));
+		netif_rx(skb);
+	}
+
+	if (skb2) {
+		/* send to wireless media */
+		skb2->protocol = __constant_htons(ETH_P_802_3);
+		skb_set_network_header(skb2, 0);
+		skb_set_mac_header(skb2, 0);
+		dev_queue_xmit(skb2);
+	}
+
+	return TXRX_QUEUED;
+}
+
+
+static struct ieee80211_rate *
+ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
+{
+	struct ieee80211_hw_mode *mode;
+	int r;
+
+	list_for_each_entry(mode, &local->modes_list, list) {
+		if (mode->mode != phymode)
+			continue;
+		for (r = 0; r < mode->num_rates; r++) {
+			struct ieee80211_rate *rate = &mode->rates[r];
+			if (rate->val == hw_rate ||
+			    (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
+			     rate->val2 == hw_rate))
+				return rate;
+		}
+	}
+
+	return NULL;
+}
+
+static void
+ieee80211_fill_frame_info(struct ieee80211_local *local,
+			  struct ieee80211_frame_info *fi,
+			  struct ieee80211_rx_status *status)
+{
+	if (status) {
+		struct timespec ts;
+		struct ieee80211_rate *rate;
+
+		jiffies_to_timespec(jiffies, &ts);
+		fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
+					   ts.tv_nsec / 1000);
+		fi->mactime = cpu_to_be64(status->mactime);
+		switch (status->phymode) {
+		case MODE_IEEE80211A:
+			fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
+			break;
+		case MODE_IEEE80211B:
+			fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
+			break;
+		case MODE_IEEE80211G:
+			fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
+			break;
+		case MODE_ATHEROS_TURBO:
+			fi->phytype =
+				htonl(ieee80211_phytype_dsss_dot11_turbo);
+			break;
+		default:
+			fi->phytype = htonl(0xAAAAAAAA);
+			break;
+		}
+		fi->channel = htonl(status->channel);
+		rate = ieee80211_get_rate(local, status->phymode,
+					  status->rate);
+		if (rate) {
+			fi->datarate = htonl(rate->rate);
+			if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
+				if (status->rate == rate->val)
+					fi->preamble = htonl(2); /* long */
+				else if (status->rate == rate->val2)
+					fi->preamble = htonl(1); /* short */
+			} else
+				fi->preamble = htonl(0);
+		} else {
+			fi->datarate = htonl(0);
+			fi->preamble = htonl(0);
+		}
+
+		fi->antenna = htonl(status->antenna);
+		fi->priority = htonl(0xffffffff); /* no clue */
+		fi->ssi_type = htonl(ieee80211_ssi_raw);
+		fi->ssi_signal = htonl(status->ssi);
+		fi->ssi_noise = 0x00000000;
+		fi->encoding = 0;
+	} else {
+		/* clear everything because we really don't know.
+		 * the msg_type field isn't present on monitor frames
+		 * so we don't know whether it will be present or not,
+		 * but it's ok to not clear it since it'll be assigned
+		 * anyway */
+		memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
+
+		fi->ssi_type = htonl(ieee80211_ssi_none);
+	}
+	fi->version = htonl(IEEE80211_FI_VERSION);
+	fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
+}
+
+/* this routine is actually not just for this, but also
+ * for pushing fake 'management' frames into userspace.
+ * it shall be replaced by a netlink-based system. */
+void
+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+		  struct ieee80211_rx_status *status, u32 msg_type)
+{
+	struct ieee80211_frame_info *fi;
+	const size_t hlen = sizeof(struct ieee80211_frame_info);
+	struct ieee80211_sub_if_data *sdata;
+
+	skb->dev = local->apdev;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev);
+
+	if (skb_headroom(skb) < hlen) {
+		I802_DEBUG_INC(local->rx_expand_skb_head);
+		if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+
+	fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+
+	ieee80211_fill_frame_info(local, fi, status);
+	fi->msg_type = htonl(msg_type);
+
+	sdata->stats.rx_packets++;
+	sdata->stats.rx_bytes += skb->len;
+
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	netif_rx(skb);
+}
+
+static void
+ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
+		     struct ieee80211_rx_status *status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_rate *rate;
+	struct ieee80211_rtap_hdr {
+		struct ieee80211_radiotap_header hdr;
+		u8 flags;
+		u8 rate;
+		__le16 chan_freq;
+		__le16 chan_flags;
+		u8 antsignal;
+	} __attribute__ ((packed)) *rthdr;
+
+	skb->dev = dev;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (status->flag & RX_FLAG_RADIOTAP)
+		goto out;
+
+	if (skb_headroom(skb) < sizeof(*rthdr)) {
+		I802_DEBUG_INC(local->rx_expand_skb_head);
+		if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+
+	rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
+	memset(rthdr, 0, sizeof(*rthdr));
+	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+	rthdr->hdr.it_present =
+		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+			    (1 << IEEE80211_RADIOTAP_RATE) |
+			    (1 << IEEE80211_RADIOTAP_CHANNEL) |
+			    (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
+	rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
+		       IEEE80211_RADIOTAP_F_FCS : 0;
+	rate = ieee80211_get_rate(local, status->phymode, status->rate);
+	if (rate)
+		rthdr->rate = rate->rate / 5;
+	rthdr->chan_freq = cpu_to_le16(status->freq);
+	rthdr->chan_flags =
+		status->phymode == MODE_IEEE80211A ?
+		cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
+		cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
+	rthdr->antsignal = status->ssi;
+
+ out:
+	sdata->stats.rx_packets++;
+	sdata->stats.rx_bytes += skb->len;
+
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+	netif_rx(skb);
+}
+
+int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
+			   int radar, int radar_type)
+{
+	struct sk_buff *skb;
+	struct ieee80211_radar_info *msg;
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (!local->apdev)
+		return 0;
+
+	skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+			    sizeof(struct ieee80211_radar_info));
+
+	if (!skb)
+		return -ENOMEM;
+	skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+
+	msg = (struct ieee80211_radar_info *)
+		skb_put(skb, sizeof(struct ieee80211_radar_info));
+	msg->channel = channel;
+	msg->radar = radar;
+	msg->radar_type = radar_type;
+
+	ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar);
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_radar_status);
+
+int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address,
+			      u16 aid)
+{
+	struct sk_buff *skb;
+	struct ieee80211_msg_set_aid_for_sta *msg;
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	/* unlikely because if this event only happens for APs,
+	 * which require an open ap device. */
+	if (unlikely(!local->apdev))
+		return 0;
+
+	skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+			    sizeof(struct ieee80211_msg_set_aid_for_sta));
+
+	if (!skb)
+		return -ENOMEM;
+	skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+
+	msg = (struct ieee80211_msg_set_aid_for_sta *)
+		skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta));
+	memcpy(msg->sta_address, peer_address, ETH_ALEN);
+	msg->aid = aid;
+
+	ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta);
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_set_aid_for_sta);
+
+static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+	if (sdata->bss)
+		atomic_inc(&sdata->bss->num_sta_ps);
+	sta->flags |= WLAN_STA_PS;
+	sta->pspoll = 0;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+	printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
+	       "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+}
+
+
+static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	int sent = 0;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_tx_packet_data *pkt_data;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if (sdata->bss)
+		atomic_dec(&sdata->bss->num_sta_ps);
+	sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
+	sta->pspoll = 0;
+	if (!skb_queue_empty(&sta->ps_tx_buf)) {
+		if (local->ops->set_tim)
+			local->ops->set_tim(local_to_hw(local), sta->aid, 0);
+		if (sdata->bss)
+			bss_tim_clear(local, sdata->bss, sta->aid);
+	}
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+	printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
+	       "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+	/* Send all buffered frames to the station */
+	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+		pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+		sent++;
+		pkt_data->requeue = 1;
+		dev_queue_xmit(skb);
+	}
+	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+		pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+		local->total_ps_buffered--;
+		sent++;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+		printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+		       "since STA not sleeping anymore\n", dev->name,
+		       MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+		pkt_data->requeue = 1;
+		dev_queue_xmit(skb);
+	}
+
+	return sent;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+{
+	struct sk_buff *skb;
+	int no_pending_pkts;
+
+	if (likely(!rx->sta ||
+		   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
+		   (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
+		   !rx->u.rx.ra_match))
+		return TXRX_CONTINUE;
+
+	skb = skb_dequeue(&rx->sta->tx_filtered);
+	if (!skb) {
+		skb = skb_dequeue(&rx->sta->ps_tx_buf);
+		if (skb)
+			rx->local->total_ps_buffered--;
+	}
+	no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
+		skb_queue_empty(&rx->sta->ps_tx_buf);
+
+	if (skb) {
+		struct ieee80211_hdr *hdr =
+			(struct ieee80211_hdr *) skb->data;
+
+		/* tell TX path to send one frame even though the STA may
+		 * still remain is PS mode after this frame exchange */
+		rx->sta->pspoll = 1;
+
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+		printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
+		       "after %d)\n",
+		       MAC_ARG(rx->sta->addr), rx->sta->aid,
+		       skb_queue_len(&rx->sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+		/* Use MoreData flag to indicate whether there are more
+		 * buffered frames for this STA */
+		if (no_pending_pkts) {
+			hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+			rx->sta->flags &= ~WLAN_STA_TIM;
+		} else
+			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+		dev_queue_xmit(skb);
+
+		if (no_pending_pkts) {
+			if (rx->local->ops->set_tim)
+				rx->local->ops->set_tim(local_to_hw(rx->local),
+						       rx->sta->aid, 0);
+			if (rx->sdata->bss)
+				bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
+		}
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+	} else if (!rx->u.rx.sent_ps_buffered) {
+		printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
+		       "though there is no buffered frames for it\n",
+		       rx->dev->name, MAC_ARG(rx->sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+	}
+
+	/* Free PS Poll skb here instead of returning TXRX_DROP that would
+	 * count as an dropped frame. */
+	dev_kfree_skb(rx->skb);
+
+	return TXRX_QUEUED;
+}
+
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
+			 unsigned int frag, unsigned int seq, int rx_queue,
+			 struct sk_buff **skb)
+{
+	struct ieee80211_fragment_entry *entry;
+	int idx;
+
+	idx = sdata->fragment_next;
+	entry = &sdata->fragments[sdata->fragment_next++];
+	if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
+		sdata->fragment_next = 0;
+
+	if (!skb_queue_empty(&entry->skb_list)) {
+#ifdef CONFIG_MAC80211_DEBUG
+		struct ieee80211_hdr *hdr =
+			(struct ieee80211_hdr *) entry->skb_list.next->data;
+		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
+		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
+		       "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
+		       sdata->dev->name, idx,
+		       jiffies - entry->first_frag_time, entry->seq,
+		       entry->last_frag, MAC_ARG(hdr->addr1),
+		       MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+		__skb_queue_purge(&entry->skb_list);
+	}
+
+	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
+	*skb = NULL;
+	entry->first_frag_time = jiffies;
+	entry->seq = seq;
+	entry->rx_queue = rx_queue;
+	entry->last_frag = frag;
+	entry->ccmp = 0;
+	entry->extra_len = 0;
+
+	return entry;
+}
+
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
+			  u16 fc, unsigned int frag, unsigned int seq,
+			  int rx_queue, struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_fragment_entry *entry;
+	int i, idx;
+
+	idx = sdata->fragment_next;
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+		struct ieee80211_hdr *f_hdr;
+		u16 f_fc;
+
+		idx--;
+		if (idx < 0)
+			idx = IEEE80211_FRAGMENT_MAX - 1;
+
+		entry = &sdata->fragments[idx];
+		if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
+		    entry->rx_queue != rx_queue ||
+		    entry->last_frag + 1 != frag)
+			continue;
+
+		f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
+		f_fc = le16_to_cpu(f_hdr->frame_control);
+
+		if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) ||
+		    compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
+		    compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
+			continue;
+
+		if (entry->first_frag_time + 2 * HZ < jiffies) {
+			__skb_queue_purge(&entry->skb_list);
+			continue;
+		}
+		return entry;
+	}
+
+	return NULL;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_hdr *hdr;
+	u16 sc;
+	unsigned int frag, seq;
+	struct ieee80211_fragment_entry *entry;
+	struct sk_buff *skb;
+
+	hdr = (struct ieee80211_hdr *) rx->skb->data;
+	sc = le16_to_cpu(hdr->seq_ctrl);
+	frag = sc & IEEE80211_SCTL_FRAG;
+
+	if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) ||
+		   (rx->skb)->len < 24 ||
+		   is_multicast_ether_addr(hdr->addr1))) {
+		/* not fragmented */
+		goto out;
+	}
+	I802_DEBUG_INC(rx->local->rx_handlers_fragments);
+
+	seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+
+	if (frag == 0) {
+		/* This is the first fragment of a new frame. */
+		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
+						 rx->u.rx.queue, &(rx->skb));
+		if (rx->key && rx->key->alg == ALG_CCMP &&
+		    (rx->fc & IEEE80211_FCTL_PROTECTED)) {
+			/* Store CCMP PN so that we can verify that the next
+			 * fragment has a sequential PN value. */
+			entry->ccmp = 1;
+			memcpy(entry->last_pn,
+			       rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+			       CCMP_PN_LEN);
+		}
+		return TXRX_QUEUED;
+	}
+
+	/* This is a fragment for a frame that should already be pending in
+	 * fragment cache. Add this fragment to the end of the pending entry.
+	 */
+	entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
+					  rx->u.rx.queue, hdr);
+	if (!entry) {
+		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+		return TXRX_DROP;
+	}
+
+	/* Verify that MPDUs within one MSDU have sequential PN values.
+	 * (IEEE 802.11i, 8.3.3.4.5) */
+	if (entry->ccmp) {
+		int i;
+		u8 pn[CCMP_PN_LEN], *rpn;
+		if (!rx->key || rx->key->alg != ALG_CCMP)
+			return TXRX_DROP;
+		memcpy(pn, entry->last_pn, CCMP_PN_LEN);
+		for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
+			pn[i]++;
+			if (pn[i])
+				break;
+		}
+		rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+		if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
+			printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential"
+			       " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x "
+			       "(expected %02x%02x%02x%02x%02x%02x)\n",
+			       rx->dev->name, MAC_ARG(hdr->addr2),
+			       rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5],
+			       pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
+			return TXRX_DROP;
+		}
+		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
+	}
+
+	skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
+	__skb_queue_tail(&entry->skb_list, rx->skb);
+	entry->last_frag = frag;
+	entry->extra_len += rx->skb->len;
+	if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
+		rx->skb = NULL;
+		return TXRX_QUEUED;
+	}
+
+	rx->skb = __skb_dequeue(&entry->skb_list);
+	if (skb_tailroom(rx->skb) < entry->extra_len) {
+		I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
+		if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
+					      GFP_ATOMIC))) {
+			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+			__skb_queue_purge(&entry->skb_list);
+			return TXRX_DROP;
+		}
+	}
+	while ((skb = __skb_dequeue(&entry->skb_list)))
+		memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len);
+
+	/* Complete frame has been reassembled - process it now */
+	rx->fragmented = 1;
+
+ out:
+	if (rx->sta)
+		rx->sta->rx_packets++;
+	if (is_multicast_ether_addr(hdr->addr1))
+		rx->local->dot11MulticastReceivedFrameCount++;
+	else
+		ieee80211_led_rx(rx->local);
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
+{
+	if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) {
+		ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status);
+		return TXRX_QUEUED;
+	}
+
+	if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP)
+		skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb));
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_hdr *hdr;
+	int always_sta_key;
+	hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+	/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
+	if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+		if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
+			     rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+			     hdr->seq_ctrl)) {
+			if (rx->u.rx.ra_match) {
+				rx->local->dot11FrameDuplicateCount++;
+				rx->sta->num_duplicates++;
+			}
+			return TXRX_DROP;
+		} else
+			rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+	}
+
+	if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) &&
+	    rx->skb->len > FCS_LEN)
+		skb_trim(rx->skb, rx->skb->len - FCS_LEN);
+
+	if (unlikely(rx->skb->len < 16)) {
+		I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
+		return TXRX_DROP;
+	}
+
+	if (!rx->u.rx.ra_match)
+		rx->skb->pkt_type = PACKET_OTHERHOST;
+	else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
+		rx->skb->pkt_type = PACKET_HOST;
+	else if (is_multicast_ether_addr(hdr->addr1)) {
+		if (is_broadcast_ether_addr(hdr->addr1))
+			rx->skb->pkt_type = PACKET_BROADCAST;
+		else
+			rx->skb->pkt_type = PACKET_MULTICAST;
+	} else
+		rx->skb->pkt_type = PACKET_OTHERHOST;
+
+	/* Drop disallowed frame classes based on STA auth/assoc state;
+	 * IEEE 802.11, Chap 5.5.
+	 *
+	 * 80211.o does filtering only based on association state, i.e., it
+	 * drops Class 3 frames from not associated stations. hostapd sends
+	 * deauth/disassoc frames when needed. In addition, hostapd is
+	 * responsible for filtering on both auth and assoc states.
+	 */
+	if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
+		      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
+		       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
+		     rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+		     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+		if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
+		     !(rx->fc & IEEE80211_FCTL_TODS) &&
+		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+		    || !rx->u.rx.ra_match) {
+			/* Drop IBSS frames and frames for other hosts
+			 * silently. */
+			return TXRX_DROP;
+		}
+
+		if (!rx->local->apdev)
+			return TXRX_DROP;
+
+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+				  ieee80211_msg_sta_not_assoc);
+		return TXRX_QUEUED;
+	}
+
+	if (rx->sdata->type == IEEE80211_IF_TYPE_STA)
+		always_sta_key = 0;
+	else
+		always_sta_key = 1;
+
+	if (rx->sta && rx->sta->key && always_sta_key) {
+		rx->key = rx->sta->key;
+	} else {
+		if (rx->sta && rx->sta->key)
+			rx->key = rx->sta->key;
+		else
+			rx->key = rx->sdata->default_key;
+
+		if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+		    rx->fc & IEEE80211_FCTL_PROTECTED) {
+			int keyidx = ieee80211_wep_get_keyidx(rx->skb);
+
+			if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS &&
+			    (!rx->sta || !rx->sta->key || keyidx > 0))
+				rx->key = rx->sdata->keys[keyidx];
+
+			if (!rx->key) {
+				if (!rx->u.rx.ra_match)
+					return TXRX_DROP;
+				printk(KERN_DEBUG "%s: RX WEP frame with "
+				       "unknown keyidx %d (A1=" MAC_FMT " A2="
+				       MAC_FMT " A3=" MAC_FMT ")\n",
+				       rx->dev->name, keyidx,
+				       MAC_ARG(hdr->addr1),
+				       MAC_ARG(hdr->addr2),
+				       MAC_ARG(hdr->addr3));
+				if (!rx->local->apdev)
+					return TXRX_DROP;
+				ieee80211_rx_mgmt(
+					rx->local, rx->skb, rx->u.rx.status,
+					ieee80211_msg_wep_frame_unknown_key);
+				return TXRX_QUEUED;
+			}
+		}
+	}
+
+	if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) {
+		rx->key->tx_rx_count++;
+		if (unlikely(rx->local->key_tx_rx_threshold &&
+			     rx->key->tx_rx_count >
+			     rx->local->key_tx_rx_threshold)) {
+			ieee80211_key_threshold_notify(rx->dev, rx->key,
+						       rx->sta);
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+{
+	struct sta_info *sta = rx->sta;
+	struct net_device *dev = rx->dev;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+	if (!sta)
+		return TXRX_CONTINUE;
+
+	/* Update last_rx only for IBSS packets which are for the current
+	 * BSSID to avoid keeping the current IBSS network alive in cases where
+	 * other STAs are using different BSSID. */
+	if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
+		if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+			sta->last_rx = jiffies;
+	} else
+	if (!is_multicast_ether_addr(hdr->addr1) ||
+	    rx->sdata->type == IEEE80211_IF_TYPE_STA) {
+		/* Update last_rx only for unicast frames in order to prevent
+		 * the Probe Request frames (the only broadcast frames from a
+		 * STA in infrastructure mode) from keeping a connection alive.
+		 */
+		sta->last_rx = jiffies;
+	}
+
+	if (!rx->u.rx.ra_match)
+		return TXRX_CONTINUE;
+
+	sta->rx_fragments++;
+	sta->rx_bytes += rx->skb->len;
+	sta->last_rssi = (sta->last_rssi * 15 +
+			  rx->u.rx.status->ssi) / 16;
+	sta->last_signal = (sta->last_signal * 15 +
+			    rx->u.rx.status->signal) / 16;
+	sta->last_noise = (sta->last_noise * 15 +
+			   rx->u.rx.status->noise) / 16;
+
+	if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
+		/* Change STA power saving mode only in the end of a frame
+		 * exchange sequence */
+		if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+			rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+		else if (!(sta->flags & WLAN_STA_PS) &&
+			 (rx->fc & IEEE80211_FCTL_PM))
+			ap_sta_ps_start(dev, sta);
+	}
+
+	/* Drop data::nullfunc frames silently, since they are used only to
+	 * control station power saving mode. */
+	if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+	    (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) {
+		I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
+		/* Update counter and free packet here to avoid counting this
+		 * as a dropped packed. */
+		sta->rx_packets++;
+		dev_kfree_skb(rx->skb);
+		return TXRX_QUEUED;
+	}
+
+	return TXRX_CONTINUE;
+} /* ieee80211_rx_h_sta_process */
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
+{
+	if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+	    !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match)
+		return TXRX_CONTINUE;
+
+	/* Check for weak IVs, if hwaccel did not remove IV from the frame */
+	if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) ||
+	    rx->key->force_sw_encrypt) {
+		u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key);
+		if (iv) {
+			rx->sta->wep_weak_iv_count++;
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
+{
+	/* If the device handles decryption totally, skip this test */
+	if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
+		return TXRX_CONTINUE;
+
+	if ((rx->key && rx->key->alg != ALG_WEP) ||
+	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+	     ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+	      (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
+		return TXRX_CONTINUE;
+
+	if (!rx->key) {
+		printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n",
+		       rx->dev->name);
+		return TXRX_DROP;
+	}
+
+	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) ||
+	    rx->key->force_sw_encrypt) {
+		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+			printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
+			       "failed\n", rx->dev->name);
+			return TXRX_DROP;
+		}
+	} else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+		ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
+		/* remove ICV */
+		skb_trim(rx->skb, rx->skb->len - 4);
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+{
+	if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
+	    rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) {
+		/* Pass both encrypted and unencrypted EAPOL frames to user
+		 * space for processing. */
+		if (!rx->local->apdev)
+			return TXRX_DROP;
+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+				  ieee80211_msg_normal);
+		return TXRX_QUEUED;
+	}
+
+	if (unlikely(rx->sdata->ieee802_1x &&
+		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+		     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+		     (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
+		     !ieee80211_is_eapol(rx->skb))) {
+#ifdef CONFIG_MAC80211_DEBUG
+		struct ieee80211_hdr *hdr =
+			(struct ieee80211_hdr *) rx->skb->data;
+		printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
+		       " (unauthorized port)\n", rx->dev->name,
+		       MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+		return TXRX_DROP;
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+{
+	/*  If the device handles decryption totally, skip this test */
+	if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
+		return TXRX_CONTINUE;
+
+	/* Drop unencrypted frames if key is set. */
+	if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
+		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+		     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+		     (rx->key || rx->sdata->drop_unencrypted) &&
+		     (rx->sdata->eapol == 0 ||
+		      !ieee80211_is_eapol(rx->skb)))) {
+		printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
+		       "encryption\n", rx->dev->name);
+		return TXRX_DROP;
+	}
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	if (!rx->u.rx.ra_match)
+		return TXRX_DROP;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+	if ((sdata->type == IEEE80211_IF_TYPE_STA ||
+	     sdata->type == IEEE80211_IF_TYPE_IBSS) &&
+	    !rx->local->user_space_mlme) {
+		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+	} else {
+		/* Management frames are sent to hostapd for processing */
+		if (!rx->local->apdev)
+			return TXRX_DROP;
+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+				  ieee80211_msg_normal);
+	}
+	return TXRX_QUEUED;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_local *local = rx->local;
+	struct sk_buff *skb = rx->skb;
+
+	if (unlikely(local->sta_scanning != 0)) {
+		ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+		return TXRX_QUEUED;
+	}
+
+	if (unlikely(rx->u.rx.in_scan)) {
+		/* scanning finished during invoking of handlers */
+		I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+		return TXRX_DROP;
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+static void ieee80211_rx_michael_mic_report(struct net_device *dev,
+					    struct ieee80211_hdr *hdr,
+					    struct sta_info *sta,
+					    struct ieee80211_txrx_data *rx)
+{
+	int keyidx, hdrlen;
+
+	hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
+	if (rx->skb->len >= hdrlen + 4)
+		keyidx = rx->skb->data[hdrlen + 3] >> 6;
+	else
+		keyidx = -1;
+
+	/* TODO: verify that this is not triggered by fragmented
+	 * frames (hw does not verify MIC for them). */
+	printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
+	       "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
+	       dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx);
+
+	if (!sta) {
+		/* Some hardware versions seem to generate incorrect
+		 * Michael MIC reports; ignore them to avoid triggering
+		 * countermeasures. */
+		printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+		       "error for unknown address " MAC_FMT "\n",
+		       dev->name, MAC_ARG(hdr->addr2));
+		goto ignore;
+	}
+
+	if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) {
+		printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+		       "error for a frame with no ISWEP flag (src "
+		       MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
+		goto ignore;
+	}
+
+	if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+	    rx->sdata->type == IEEE80211_IF_TYPE_AP) {
+		keyidx = ieee80211_wep_get_keyidx(rx->skb);
+		/* AP with Pairwise keys support should never receive Michael
+		 * MIC errors for non-zero keyidx because these are reserved
+		 * for group keys and only the AP is sending real multicast
+		 * frames in BSS. */
+		if (keyidx) {
+			printk(KERN_DEBUG "%s: ignored Michael MIC error for "
+			       "a frame with non-zero keyidx (%d) (src " MAC_FMT
+			       ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2));
+			goto ignore;
+		}
+	}
+
+	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+	     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) {
+		printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+		       "error for a frame that cannot be encrypted "
+		       "(fc=0x%04x) (src " MAC_FMT ")\n",
+		       dev->name, rx->fc, MAC_ARG(hdr->addr2));
+		goto ignore;
+	}
+
+	do {
+		union iwreq_data wrqu;
+		char *buf = kmalloc(128, GFP_ATOMIC);
+		if (!buf)
+			break;
+
+		/* TODO: needed parameters: count, key type, TSC */
+		sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+			"keyid=%d %scast addr=" MAC_FMT ")",
+			keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+			MAC_ARG(hdr->addr2));
+		memset(&wrqu, 0, sizeof(wrqu));
+		wrqu.data.length = strlen(buf);
+		wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
+		kfree(buf);
+	} while (0);
+
+	/* TODO: consider verifying the MIC error report with software
+	 * implementation if we get too many spurious reports from the
+	 * hardware. */
+	if (!rx->local->apdev)
+		goto ignore;
+	ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+			  ieee80211_msg_michael_mic_failure);
+	return;
+
+ ignore:
+	dev_kfree_skb(rx->skb);
+	rx->skb = NULL;
+}
+
+static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
+				struct ieee80211_local *local,
+				ieee80211_rx_handler *handlers,
+				struct ieee80211_txrx_data *rx,
+				struct sta_info *sta)
+{
+	ieee80211_rx_handler *handler;
+	ieee80211_txrx_result res = TXRX_DROP;
+
+	for (handler = handlers; *handler != NULL; handler++) {
+		res = (*handler)(rx);
+		if (res != TXRX_CONTINUE) {
+			if (res == TXRX_DROP) {
+				I802_DEBUG_INC(local->rx_handlers_drop);
+				if (sta)
+					sta->rx_dropped++;
+			}
+			if (res == TXRX_QUEUED)
+				I802_DEBUG_INC(local->rx_handlers_queued);
+			break;
+		}
+	}
+
+	if (res == TXRX_DROP) {
+		dev_kfree_skb(rx->skb);
+	}
+	return res;
+}
+
+static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
+						ieee80211_rx_handler *handlers,
+						struct ieee80211_txrx_data *rx,
+						struct sta_info *sta)
+{
+	if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
+	    TXRX_CONTINUE)
+		dev_kfree_skb(rx->skb);
+}
+
+/*
+ * This is the receive path handler. It is called by a low level driver when an
+ * 802.11 MPDU is received from the hardware.
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		    struct ieee80211_rx_status *status)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+	struct ieee80211_hdr *hdr;
+	struct ieee80211_txrx_data rx;
+	u16 type;
+	int multicast;
+	int radiotap_len = 0;
+
+	if (status->flag & RX_FLAG_RADIOTAP) {
+		radiotap_len = ieee80211_get_radiotap_len(skb);
+		skb_pull(skb, radiotap_len);
+	}
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	memset(&rx, 0, sizeof(rx));
+	rx.skb = skb;
+	rx.local = local;
+
+	rx.u.rx.status = status;
+	rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0;
+	type = rx.fc & IEEE80211_FCTL_FTYPE;
+	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
+		local->dot11ReceivedFragmentCount++;
+	multicast = is_multicast_ether_addr(hdr->addr1);
+
+	if (skb->len >= 16)
+		sta = rx.sta = sta_info_get(local, hdr->addr2);
+	else
+		sta = rx.sta = NULL;
+
+	if (sta) {
+		rx.dev = sta->dev;
+		rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+	}
+
+	if ((status->flag & RX_FLAG_MMIC_ERROR)) {
+		ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
+		goto end;
+	}
+
+	if (unlikely(local->sta_scanning))
+		rx.u.rx.in_scan = 1;
+
+	if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
+					   sta) != TXRX_CONTINUE)
+		goto end;
+	skb = rx.skb;
+
+	skb_push(skb, radiotap_len);
+	if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
+	    !local->iff_promiscs && !multicast) {
+		rx.u.rx.ra_match = 1;
+		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
+					     sta);
+	} else {
+		struct ieee80211_sub_if_data *prev = NULL;
+		struct sk_buff *skb_new;
+		u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
+
+		read_lock(&local->sub_if_lock);
+		list_for_each_entry(sdata, &local->sub_if_list, list) {
+			rx.u.rx.ra_match = 1;
+			switch (sdata->type) {
+			case IEEE80211_IF_TYPE_STA:
+				if (!bssid)
+					continue;
+				if (!ieee80211_bssid_match(bssid,
+							sdata->u.sta.bssid)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (!multicast &&
+					   compare_ether_addr(sdata->dev->dev_addr,
+							      hdr->addr1) != 0) {
+					if (!sdata->promisc)
+						continue;
+					rx.u.rx.ra_match = 0;
+				}
+				break;
+			case IEEE80211_IF_TYPE_IBSS:
+				if (!bssid)
+					continue;
+				if (!ieee80211_bssid_match(bssid,
+							sdata->u.sta.bssid)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (!multicast &&
+					   compare_ether_addr(sdata->dev->dev_addr,
+							      hdr->addr1) != 0) {
+					if (!sdata->promisc)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (!sta)
+					sta = rx.sta =
+						ieee80211_ibss_add_sta(sdata->dev,
+								       skb, bssid,
+								       hdr->addr2);
+				break;
+			case IEEE80211_IF_TYPE_AP:
+				if (!bssid) {
+					if (compare_ether_addr(sdata->dev->dev_addr,
+							       hdr->addr1) != 0)
+						continue;
+				} else if (!ieee80211_bssid_match(bssid,
+							sdata->dev->dev_addr)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				}
+				if (sdata->dev == local->mdev &&
+				    !rx.u.rx.in_scan)
+					/* do not receive anything via
+					 * master device when not scanning */
+					continue;
+				break;
+			case IEEE80211_IF_TYPE_WDS:
+				if (bssid ||
+				    (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+					continue;
+				if (compare_ether_addr(sdata->u.wds.remote_addr,
+						       hdr->addr2) != 0)
+					continue;
+				break;
+			}
+
+			if (prev) {
+				skb_new = skb_copy(skb, GFP_ATOMIC);
+				if (!skb_new) {
+					if (net_ratelimit())
+						printk(KERN_DEBUG "%s: failed to copy "
+						       "multicast frame for %s",
+						       local->mdev->name, prev->dev->name);
+					continue;
+				}
+				rx.skb = skb_new;
+				rx.dev = prev->dev;
+				rx.sdata = prev;
+				ieee80211_invoke_rx_handlers(local,
+							     local->rx_handlers,
+							     &rx, sta);
+			}
+			prev = sdata;
+		}
+		if (prev) {
+			rx.skb = skb;
+			rx.dev = prev->dev;
+			rx.sdata = prev;
+			ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+						     &rx, sta);
+		} else
+			dev_kfree_skb(skb);
+		read_unlock(&local->sub_if_lock);
+	}
+
+  end:
+	if (sta)
+		sta_info_put(sta);
+}
+EXPORT_SYMBOL(__ieee80211_rx);
+
+static ieee80211_txrx_result
+ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_local *local = tx->local;
+	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+	struct sk_buff *skb = tx->skb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u32 load = 0, hdrtime;
+
+	/* TODO: this could be part of tx_status handling, so that the number
+	 * of retries would be known; TX rate should in that case be stored
+	 * somewhere with the packet */
+
+	/* Estimate total channel use caused by this frame */
+
+	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+	if (mode->mode == MODE_IEEE80211A ||
+	    mode->mode == MODE_ATHEROS_TURBO ||
+	    mode->mode == MODE_ATHEROS_TURBOG ||
+	    (mode->mode == MODE_IEEE80211G &&
+	     tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+		hdrtime = CHAN_UTIL_HDR_SHORT;
+	else
+		hdrtime = CHAN_UTIL_HDR_LONG;
+
+	load = hdrtime;
+	if (!is_multicast_ether_addr(hdr->addr1))
+		load += hdrtime;
+
+	if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+		load += 2 * hdrtime;
+	else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		load += hdrtime;
+
+	load += skb->len * tx->u.tx.rate->rate_inv;
+
+	if (tx->u.tx.extra_frag) {
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			load += 2 * hdrtime;
+			load += tx->u.tx.extra_frag[i]->len *
+				tx->u.tx.rate->rate;
+		}
+	}
+
+	/* Divide channel_use by 8 to avoid wrapping around the counter */
+	load >>= CHAN_UTIL_SHIFT;
+	local->channel_use_raw += load;
+	if (tx->sta)
+		tx->sta->channel_use_raw += load;
+	tx->sdata->channel_use_raw += load;
+
+	return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_local *local = rx->local;
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u32 load = 0, hdrtime;
+	struct ieee80211_rate *rate;
+	struct ieee80211_hw_mode *mode = local->hw.conf.mode;
+	int i;
+
+	/* Estimate total channel use caused by this frame */
+
+	if (unlikely(mode->num_rates < 0))
+		return TXRX_CONTINUE;
+
+	rate = &mode->rates[0];
+	for (i = 0; i < mode->num_rates; i++) {
+		if (mode->rates[i].val == rx->u.rx.status->rate) {
+			rate = &mode->rates[i];
+			break;
+		}
+	}
+
+	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+	if (mode->mode == MODE_IEEE80211A ||
+	    mode->mode == MODE_ATHEROS_TURBO ||
+	    mode->mode == MODE_ATHEROS_TURBOG ||
+	    (mode->mode == MODE_IEEE80211G &&
+	     rate->flags & IEEE80211_RATE_ERP))
+		hdrtime = CHAN_UTIL_HDR_SHORT;
+	else
+		hdrtime = CHAN_UTIL_HDR_LONG;
+
+	load = hdrtime;
+	if (!is_multicast_ether_addr(hdr->addr1))
+		load += hdrtime;
+
+	load += skb->len * rate->rate_inv;
+
+	/* Divide channel_use by 8 to avoid wrapping around the counter */
+	load >>= CHAN_UTIL_SHIFT;
+	local->channel_use_raw += load;
+	if (rx->sta)
+		rx->sta->channel_use_raw += load;
+	rx->u.rx.load = load;
+
+	return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+{
+	rx->sdata->channel_use_raw += rx->u.rx.load;
+	return TXRX_CONTINUE;
+}
+
+static void ieee80211_stat_refresh(unsigned long data)
+{
+	struct ieee80211_local *local = (struct ieee80211_local *) data;
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+
+	if (!local->stat_time)
+		return;
+
+	/* go through all stations */
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		sta->channel_use = (sta->channel_use_raw / local->stat_time) /
+			CHAN_UTIL_PER_10MS;
+		sta->channel_use_raw = 0;
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	/* go through all subinterfaces */
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		sdata->channel_use = (sdata->channel_use_raw /
+				      local->stat_time) / CHAN_UTIL_PER_10MS;
+		sdata->channel_use_raw = 0;
+	}
+	read_unlock(&local->sub_if_lock);
+
+	/* hardware interface */
+	local->channel_use = (local->channel_use_raw /
+			      local->stat_time) / CHAN_UTIL_PER_10MS;
+	local->channel_use_raw = 0;
+
+	local->stat_timer.expires = jiffies + HZ * local->stat_time / 100;
+	add_timer(&local->stat_timer);
+}
+
+
+/* This is a version of the rx handler that can be called from hard irq
+ * context. Post the skb on the queue and schedule the tasklet */
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
+			  struct ieee80211_rx_status *status)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
+
+	skb->dev = local->mdev;
+	/* copy status into skb->cb for use by tasklet */
+	memcpy(skb->cb, status, sizeof(*status));
+	skb->pkt_type = IEEE80211_RX_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_rx_irqsafe);
+
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+				 struct sk_buff *skb,
+				 struct ieee80211_tx_status *status)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_tx_status *saved;
+	int tmp;
+
+	skb->dev = local->mdev;
+	saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
+	if (unlikely(!saved)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping tx status", skb->dev->name);
+		/* should be dev_kfree_skb_irq, but due to this function being
+		 * named _irqsafe instead of just _irq we can't be sure that
+		 * people won't call it from non-irq contexts */
+		dev_kfree_skb_any(skb);
+		return;
+	}
+	memcpy(saved, status, sizeof(struct ieee80211_tx_status));
+	/* copy pointer to saved status into skb->cb for use by tasklet */
+	memcpy(skb->cb, &saved, sizeof(saved));
+
+	skb->pkt_type = IEEE80211_TX_STATUS_MSG;
+	skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+		       &local->skb_queue : &local->skb_queue_unreliable, skb);
+	tmp = skb_queue_len(&local->skb_queue) +
+		skb_queue_len(&local->skb_queue_unreliable);
+	while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
+	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+		memcpy(&saved, skb->cb, sizeof(saved));
+		kfree(saved);
+		dev_kfree_skb_irq(skb);
+		tmp--;
+		I802_DEBUG_INC(local->tx_status_drop);
+	}
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
+
+static void ieee80211_tasklet_handler(unsigned long data)
+{
+	struct ieee80211_local *local = (struct ieee80211_local *) data;
+	struct sk_buff *skb;
+	struct ieee80211_rx_status rx_status;
+	struct ieee80211_tx_status *tx_status;
+
+	while ((skb = skb_dequeue(&local->skb_queue)) ||
+	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+		switch (skb->pkt_type) {
+		case IEEE80211_RX_MSG:
+			/* status is in skb->cb */
+			memcpy(&rx_status, skb->cb, sizeof(rx_status));
+			/* Clear skb->type in order to not confuse kernel
+			 * netstack. */
+			skb->pkt_type = 0;
+			__ieee80211_rx(local_to_hw(local), skb, &rx_status);
+			break;
+		case IEEE80211_TX_STATUS_MSG:
+			/* get pointer to saved status out of skb->cb */
+			memcpy(&tx_status, skb->cb, sizeof(tx_status));
+			skb->pkt_type = 0;
+			ieee80211_tx_status(local_to_hw(local),
+					    skb, tx_status);
+			kfree(tx_status);
+			break;
+		default: /* should never get here! */
+			printk(KERN_ERR "%s: Unknown message type (%d)\n",
+			       local->mdev->name, skb->pkt_type);
+			dev_kfree_skb(skb);
+			break;
+		}
+	}
+}
+
+
+/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
+ * make a prepared TX frame (one that has been given to hw) to look like brand
+ * new IEEE 802.11 frame that is ready to go through TX processing again.
+ * Also, tx_packet_data in cb is restored from tx_control. */
+static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
+				      struct ieee80211_key *key,
+				      struct sk_buff *skb,
+				      struct ieee80211_tx_control *control)
+{
+	int hdrlen, iv_len, mic_len;
+	struct ieee80211_tx_packet_data *pkt_data;
+
+	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+	pkt_data->ifindex = control->ifindex;
+	pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT);
+	pkt_data->req_tx_status = !!(control->flags & IEEE80211_TXCTL_REQ_TX_STATUS);
+	pkt_data->do_not_encrypt = !!(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT);
+	pkt_data->requeue = !!(control->flags & IEEE80211_TXCTL_REQUEUE);
+	pkt_data->queue = control->queue;
+
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+	if (!key)
+		goto no_key;
+
+	switch (key->alg) {
+	case ALG_WEP:
+		iv_len = WEP_IV_LEN;
+		mic_len = WEP_ICV_LEN;
+		break;
+	case ALG_TKIP:
+		iv_len = TKIP_IV_LEN;
+		mic_len = TKIP_ICV_LEN;
+		break;
+	case ALG_CCMP:
+		iv_len = CCMP_HDR_LEN;
+		mic_len = CCMP_MIC_LEN;
+		break;
+	default:
+		goto no_key;
+	}
+
+	if (skb->len >= mic_len && key->force_sw_encrypt)
+		skb_trim(skb, skb->len - mic_len);
+	if (skb->len >= iv_len && skb->len > hdrlen) {
+		memmove(skb->data + iv_len, skb->data, hdrlen);
+		skb_pull(skb, iv_len);
+	}
+
+no_key:
+	{
+		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+		u16 fc = le16_to_cpu(hdr->frame_control);
+		if ((fc & 0x8C) == 0x88) /* QoS Control Field */ {
+			fc &= ~IEEE80211_STYPE_QOS_DATA;
+			hdr->frame_control = cpu_to_le16(fc);
+			memmove(skb->data + 2, skb->data, hdrlen - 2);
+			skb_pull(skb, 2);
+		}
+	}
+}
+
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+			 struct ieee80211_tx_status *status)
+{
+	struct sk_buff *skb2;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_local *local = hw_to_local(hw);
+	u16 frag, type;
+	u32 msg_type;
+
+	if (!status) {
+		printk(KERN_ERR
+		       "%s: ieee80211_tx_status called with NULL status\n",
+		       local->mdev->name);
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if (status->excessive_retries) {
+		struct sta_info *sta;
+		sta = sta_info_get(local, hdr->addr1);
+		if (sta) {
+			if (sta->flags & WLAN_STA_PS) {
+				/* The STA is in power save mode, so assume
+				 * that this TX packet failed because of that.
+				 */
+				status->excessive_retries = 0;
+				status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+			}
+			sta_info_put(sta);
+		}
+	}
+
+	if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
+		struct sta_info *sta;
+		sta = sta_info_get(local, hdr->addr1);
+		if (sta) {
+			sta->tx_filtered_count++;
+
+			/* Clear the TX filter mask for this STA when sending
+			 * the next packet. If the STA went to power save mode,
+			 * this will happen when it is waking up for the next
+			 * time. */
+			sta->clear_dst_mask = 1;
+
+			/* TODO: Is the WLAN_STA_PS flag always set here or is
+			 * the race between RX and TX status causing some
+			 * packets to be filtered out before 80211.o gets an
+			 * update for PS status? This seems to be the case, so
+			 * no changes are likely to be needed. */
+			if (sta->flags & WLAN_STA_PS &&
+			    skb_queue_len(&sta->tx_filtered) <
+			    STA_MAX_TX_BUFFER) {
+				ieee80211_remove_tx_extra(local, sta->key,
+							  skb,
+							  &status->control);
+				skb_queue_tail(&sta->tx_filtered, skb);
+			} else if (!(sta->flags & WLAN_STA_PS) &&
+				   !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+				/* Software retry the packet once */
+				status->control.flags |= IEEE80211_TXCTL_REQUEUE;
+				ieee80211_remove_tx_extra(local, sta->key,
+							  skb,
+							  &status->control);
+				dev_queue_xmit(skb);
+			} else {
+				if (net_ratelimit()) {
+					printk(KERN_DEBUG "%s: dropped TX "
+					       "filtered frame queue_len=%d "
+					       "PS=%d @%lu\n",
+					       local->mdev->name,
+					       skb_queue_len(
+						       &sta->tx_filtered),
+					       !!(sta->flags & WLAN_STA_PS),
+					       jiffies);
+				}
+				dev_kfree_skb(skb);
+			}
+			sta_info_put(sta);
+			return;
+		}
+	} else {
+		/* FIXME: STUPID to call this with both local and local->mdev */
+		rate_control_tx_status(local, local->mdev, skb, status);
+	}
+
+	ieee80211_led_tx(local, 0);
+
+	/* SNMP counters
+	 * Fragments are passed to low-level drivers as separate skbs, so these
+	 * are actually fragments, not frames. Update frame counters only for
+	 * the first fragment of the frame. */
+
+	frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
+
+	if (status->flags & IEEE80211_TX_STATUS_ACK) {
+		if (frag == 0) {
+			local->dot11TransmittedFrameCount++;
+			if (is_multicast_ether_addr(hdr->addr1))
+				local->dot11MulticastTransmittedFrameCount++;
+			if (status->retry_count > 0)
+				local->dot11RetryCount++;
+			if (status->retry_count > 1)
+				local->dot11MultipleRetryCount++;
+		}
+
+		/* This counter shall be incremented for an acknowledged MPDU
+		 * with an individual address in the address 1 field or an MPDU
+		 * with a multicast address in the address 1 field of type Data
+		 * or Management. */
+		if (!is_multicast_ether_addr(hdr->addr1) ||
+		    type == IEEE80211_FTYPE_DATA ||
+		    type == IEEE80211_FTYPE_MGMT)
+			local->dot11TransmittedFragmentCount++;
+	} else {
+		if (frag == 0)
+			local->dot11FailedCount++;
+	}
+
+	if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)
+	    || unlikely(!local->apdev)) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
+		ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+
+	/* skb was the original skb used for TX. Clone it and give the clone
+	 * to netif_rx(). Free original skb. */
+	skb2 = skb_copy(skb, GFP_ATOMIC);
+	if (!skb2) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	dev_kfree_skb(skb);
+	skb = skb2;
+
+	/* Send frame to hostapd */
+	ieee80211_rx_mgmt(local, skb, NULL, msg_type);
+}
+EXPORT_SYMBOL(ieee80211_tx_status);
+
+/* TODO: implement register/unregister functions for adding TX/RX handlers
+ * into ordered list */
+
+/* rx_pre handlers don't have dev and sdata fields available in
+ * ieee80211_txrx_data */
+static ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
+{
+	ieee80211_rx_h_parse_qos,
+	ieee80211_rx_h_load_stats,
+	NULL
+};
+
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
+{
+	ieee80211_rx_h_if_stats,
+	ieee80211_rx_h_monitor,
+	ieee80211_rx_h_passive_scan,
+	ieee80211_rx_h_check,
+	ieee80211_rx_h_sta_process,
+	ieee80211_rx_h_ccmp_decrypt,
+	ieee80211_rx_h_tkip_decrypt,
+	ieee80211_rx_h_wep_weak_iv_detection,
+	ieee80211_rx_h_wep_decrypt,
+	ieee80211_rx_h_defragment,
+	ieee80211_rx_h_ps_poll,
+	ieee80211_rx_h_michael_mic_verify,
+	/* this must be after decryption - so header is counted in MPDU mic
+	 * must be before pae and data, so QOS_DATA format frames
+	 * are not passed to user space by these functions
+	 */
+	ieee80211_rx_h_remove_qos_control,
+	ieee80211_rx_h_802_1x_pae,
+	ieee80211_rx_h_drop_unencrypted,
+	ieee80211_rx_h_data,
+	ieee80211_rx_h_mgmt,
+	NULL
+};
+
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
+{
+	ieee80211_tx_h_check_assoc,
+	ieee80211_tx_h_sequence,
+	ieee80211_tx_h_ps_buf,
+	ieee80211_tx_h_select_key,
+	ieee80211_tx_h_michael_mic_add,
+	ieee80211_tx_h_fragment,
+	ieee80211_tx_h_tkip_encrypt,
+	ieee80211_tx_h_ccmp_encrypt,
+	ieee80211_tx_h_wep_encrypt,
+	ieee80211_tx_h_rate_ctrl,
+	ieee80211_tx_h_misc,
+	ieee80211_tx_h_load_stats,
+	NULL
+};
+
+
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+
+	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
+		return 0;
+
+	/* Create STA entry for the new peer */
+	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
+	if (!sta)
+		return -ENOMEM;
+	sta_info_put(sta);
+
+	/* Remove STA entry for the old peer */
+	sta = sta_info_get(local, sdata->u.wds.remote_addr);
+	if (sta) {
+		sta_info_put(sta);
+		sta_info_free(sta, 0);
+	} else {
+		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
+		       "peer " MAC_FMT "\n",
+		       dev->name, MAC_ARG(sdata->u.wds.remote_addr));
+	}
+
+	/* Update WDS link data */
+	memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
+
+	return 0;
+}
+
+/* Must not be called for mdev and apdev */
+void ieee80211_if_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ieee80211_subif_start_xmit;
+	dev->wireless_handlers = &ieee80211_iw_handler_def;
+	dev->set_multicast_list = ieee80211_set_multicast_list;
+	dev->change_mtu = ieee80211_change_mtu;
+	dev->get_stats = ieee80211_get_stats;
+	dev->open = ieee80211_open;
+	dev->stop = ieee80211_stop;
+	dev->uninit = ieee80211_if_reinit;
+	dev->destructor = ieee80211_if_free;
+}
+
+void ieee80211_if_mgmt_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+	dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
+	dev->change_mtu = ieee80211_change_mtu_apdev;
+	dev->get_stats = ieee80211_get_stats;
+	dev->open = ieee80211_mgmt_open;
+	dev->stop = ieee80211_mgmt_stop;
+	dev->type = ARPHRD_IEEE80211_PRISM;
+	dev->hard_header_parse = header_parse_80211;
+	dev->uninit = ieee80211_if_reinit;
+	dev->destructor = ieee80211_if_free;
+}
+
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+				 const char *name)
+{
+	struct rate_control_ref *ref, *old;
+
+	ASSERT_RTNL();
+	if (local->open_count || netif_running(local->mdev) ||
+	    (local->apdev && netif_running(local->apdev)))
+		return -EBUSY;
+
+	ref = rate_control_alloc(name, local);
+	if (!ref) {
+		printk(KERN_WARNING "%s: Failed to select rate control "
+		       "algorithm\n", local->mdev->name);
+		return -ENOENT;
+	}
+
+	old = local->rate_ctrl;
+	local->rate_ctrl = ref;
+	if (old) {
+		rate_control_put(old);
+		sta_info_flush(local, NULL);
+	}
+
+	printk(KERN_DEBUG "%s: Selected rate control "
+	       "algorithm '%s'\n", local->mdev->name,
+	       ref->ops->name);
+
+
+	return 0;
+}
+
+static void rate_control_deinitialize(struct ieee80211_local *local)
+{
+	struct rate_control_ref *ref;
+
+	ref = local->rate_ctrl;
+	local->rate_ctrl = NULL;
+	rate_control_put(ref);
+}
+
+struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
+					const struct ieee80211_ops *ops)
+{
+	struct net_device *mdev;
+	struct ieee80211_local *local;
+	struct ieee80211_sub_if_data *sdata;
+	int priv_size;
+	struct wiphy *wiphy;
+
+	/* Ensure 32-byte alignment of our private data and hw private data.
+	 * We use the wiphy priv data for both our ieee80211_local and for
+	 * the driver's private data
+	 *
+	 * In memory it'll be like this:
+	 *
+	 * +-------------------------+
+	 * | struct wiphy	    |
+	 * +-------------------------+
+	 * | struct ieee80211_local  |
+	 * +-------------------------+
+	 * | driver's private data   |
+	 * +-------------------------+
+	 *
+	 */
+	priv_size = ((sizeof(struct ieee80211_local) +
+		      NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
+		    priv_data_len;
+
+	wiphy = wiphy_new(&mac80211_config_ops, priv_size);
+
+	if (!wiphy)
+		return NULL;
+
+	wiphy->privid = mac80211_wiphy_privid;
+
+	local = wiphy_priv(wiphy);
+	local->hw.wiphy = wiphy;
+
+	local->hw.priv = (char *)local +
+			 ((sizeof(struct ieee80211_local) +
+			   NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+
+	local->ops = ops;
+
+	/* for now, mdev needs sub_if_data :/ */
+	mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+			    "wmaster%d", ether_setup);
+	if (!mdev) {
+		wiphy_free(wiphy);
+		return NULL;
+	}
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
+	mdev->ieee80211_ptr = &sdata->wdev;
+	sdata->wdev.wiphy = wiphy;
+
+	local->hw.queues = 1; /* default */
+
+	local->mdev = mdev;
+	local->rx_pre_handlers = ieee80211_rx_pre_handlers;
+	local->rx_handlers = ieee80211_rx_handlers;
+	local->tx_handlers = ieee80211_tx_handlers;
+
+	local->bridge_packets = 1;
+
+	local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+	local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+	local->short_retry_limit = 7;
+	local->long_retry_limit = 4;
+	local->hw.conf.radio_enabled = 1;
+	local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
+	local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
+
+	local->enabled_modes = (unsigned int) -1;
+
+	INIT_LIST_HEAD(&local->modes_list);
+
+	rwlock_init(&local->sub_if_lock);
+	INIT_LIST_HEAD(&local->sub_if_list);
+
+	INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
+	init_timer(&local->stat_timer);
+	local->stat_timer.function = ieee80211_stat_refresh;
+	local->stat_timer.data = (unsigned long) local;
+	ieee80211_rx_bss_list_init(mdev);
+
+	sta_info_init(local);
+
+	mdev->hard_start_xmit = ieee80211_master_start_xmit;
+	mdev->open = ieee80211_master_open;
+	mdev->stop = ieee80211_master_stop;
+	mdev->type = ARPHRD_IEEE80211;
+	mdev->hard_header_parse = header_parse_80211;
+
+	sdata->type = IEEE80211_IF_TYPE_AP;
+	sdata->dev = mdev;
+	sdata->local = local;
+	sdata->u.ap.force_unicast_rateidx = -1;
+	sdata->u.ap.max_ratectrl_rateidx = -1;
+	ieee80211_if_sdata_init(sdata);
+	list_add_tail(&sdata->list, &local->sub_if_list);
+
+	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
+		     (unsigned long)local);
+	tasklet_disable(&local->tx_pending_tasklet);
+
+	tasklet_init(&local->tasklet,
+		     ieee80211_tasklet_handler,
+		     (unsigned long) local);
+	tasklet_disable(&local->tasklet);
+
+	skb_queue_head_init(&local->skb_queue);
+	skb_queue_head_init(&local->skb_queue_unreliable);
+
+	return local_to_hw(local);
+}
+EXPORT_SYMBOL(ieee80211_alloc_hw);
+
+int ieee80211_register_hw(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	const char *name;
+	int result;
+
+	result = wiphy_register(local->hw.wiphy);
+	if (result < 0)
+		return result;
+
+	name = wiphy_dev(local->hw.wiphy)->driver->name;
+	local->hw.workqueue = create_singlethread_workqueue(name);
+	if (!local->hw.workqueue) {
+		result = -ENOMEM;
+		goto fail_workqueue;
+	}
+
+	debugfs_hw_add(local);
+
+	local->hw.conf.beacon_int = 1000;
+
+	local->wstats_flags |= local->hw.max_rssi ?
+			       IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
+	local->wstats_flags |= local->hw.max_signal ?
+			       IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+	local->wstats_flags |= local->hw.max_noise ?
+			       IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+	if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+		local->wstats_flags |= IW_QUAL_DBM;
+
+	result = sta_info_start(local);
+	if (result < 0)
+		goto fail_sta_info;
+
+	rtnl_lock();
+	result = dev_alloc_name(local->mdev, local->mdev->name);
+	if (result < 0)
+		goto fail_dev;
+
+	memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+	SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
+
+	result = register_netdevice(local->mdev);
+	if (result < 0)
+		goto fail_dev;
+
+	ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
+
+	result = ieee80211_init_rate_ctrl_alg(local, NULL);
+	if (result < 0) {
+		printk(KERN_DEBUG "%s: Failed to initialize rate control "
+		       "algorithm\n", local->mdev->name);
+		goto fail_rate;
+	}
+
+	result = ieee80211_wep_init(local);
+
+	if (result < 0) {
+		printk(KERN_DEBUG "%s: Failed to initialize wep\n",
+		       local->mdev->name);
+		goto fail_wep;
+	}
+
+	ieee80211_install_qdisc(local->mdev);
+
+	/* add one default STA interface */
+	result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+				  IEEE80211_IF_TYPE_STA);
+	if (result)
+		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
+		       local->mdev->name);
+
+	local->reg_state = IEEE80211_DEV_REGISTERED;
+	rtnl_unlock();
+
+	ieee80211_led_init(local);
+
+	return 0;
+
+fail_wep:
+	rate_control_deinitialize(local);
+fail_rate:
+	ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
+	unregister_netdevice(local->mdev);
+fail_dev:
+	rtnl_unlock();
+	sta_info_stop(local);
+fail_sta_info:
+	debugfs_hw_del(local);
+	destroy_workqueue(local->hw.workqueue);
+fail_workqueue:
+	wiphy_unregister(local->hw.wiphy);
+	return result;
+}
+EXPORT_SYMBOL(ieee80211_register_hw);
+
+int ieee80211_register_hwmode(struct ieee80211_hw *hw,
+			      struct ieee80211_hw_mode *mode)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_rate *rate;
+	int i;
+
+	INIT_LIST_HEAD(&mode->list);
+	list_add_tail(&mode->list, &local->modes_list);
+
+	local->hw_modes |= (1 << mode->mode);
+	for (i = 0; i < mode->num_rates; i++) {
+		rate = &(mode->rates[i]);
+		rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
+	}
+	ieee80211_prepare_rates(local, mode);
+
+	if (!local->oper_hw_mode) {
+		/* Default to this mode */
+		local->hw.conf.phymode = mode->mode;
+		local->oper_hw_mode = local->scan_hw_mode = mode;
+		local->oper_channel = local->scan_channel = &mode->channels[0];
+		local->hw.conf.mode = local->oper_hw_mode;
+		local->hw.conf.chan = local->oper_channel;
+	}
+
+	if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
+		ieee80211_init_client(local->mdev);
+
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_register_hwmode);
+
+void ieee80211_unregister_hw(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata, *tmp;
+	struct list_head tmp_list;
+	int i;
+
+	tasklet_kill(&local->tx_pending_tasklet);
+	tasklet_kill(&local->tasklet);
+
+	rtnl_lock();
+
+	BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
+
+	local->reg_state = IEEE80211_DEV_UNREGISTERED;
+	if (local->apdev)
+		ieee80211_if_del_mgmt(local);
+
+	write_lock_bh(&local->sub_if_lock);
+	list_replace_init(&local->sub_if_list, &tmp_list);
+	write_unlock_bh(&local->sub_if_lock);
+
+	list_for_each_entry_safe(sdata, tmp, &tmp_list, list)
+		__ieee80211_if_del(local, sdata);
+
+	rtnl_unlock();
+
+	if (local->stat_time)
+		del_timer_sync(&local->stat_timer);
+
+	ieee80211_rx_bss_list_deinit(local->mdev);
+	ieee80211_clear_tx_pending(local);
+	sta_info_stop(local);
+	rate_control_deinitialize(local);
+	debugfs_hw_del(local);
+
+	for (i = 0; i < NUM_IEEE80211_MODES; i++) {
+		kfree(local->supp_rates[i]);
+		kfree(local->basic_rates[i]);
+	}
+
+	if (skb_queue_len(&local->skb_queue)
+			|| skb_queue_len(&local->skb_queue_unreliable))
+		printk(KERN_WARNING "%s: skb_queue not empty\n",
+		       local->mdev->name);
+	skb_queue_purge(&local->skb_queue);
+	skb_queue_purge(&local->skb_queue_unreliable);
+
+	destroy_workqueue(local->hw.workqueue);
+	wiphy_unregister(local->hw.wiphy);
+	ieee80211_wep_free(local);
+	ieee80211_led_exit(local);
+}
+EXPORT_SYMBOL(ieee80211_unregister_hw);
+
+void ieee80211_free_hw(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	ieee80211_if_free(local->mdev);
+	wiphy_free(local->hw.wiphy);
+}
+EXPORT_SYMBOL(ieee80211_free_hw);
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
+			       &local->state[queue])) {
+		if (test_bit(IEEE80211_LINK_STATE_PENDING,
+			     &local->state[queue]))
+			tasklet_schedule(&local->tx_pending_tasklet);
+		else
+			if (!ieee80211_qdisc_installed(local->mdev)) {
+				if (queue == 0)
+					netif_wake_queue(local->mdev);
+			} else
+				__netif_schedule(local->mdev);
+	}
+}
+EXPORT_SYMBOL(ieee80211_wake_queue);
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+		netif_stop_queue(local->mdev);
+	set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+EXPORT_SYMBOL(ieee80211_stop_queue);
+
+void ieee80211_start_queues(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	int i;
+
+	for (i = 0; i < local->hw.queues; i++)
+		clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
+	if (!ieee80211_qdisc_installed(local->mdev))
+		netif_start_queue(local->mdev);
+}
+EXPORT_SYMBOL(ieee80211_start_queues);
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < hw->queues; i++)
+		ieee80211_stop_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_stop_queues);
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+	int i;
+
+	for (i = 0; i < hw->queues; i++)
+		ieee80211_wake_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_wake_queues);
+
+struct net_device_stats *ieee80211_dev_stats(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	return &sdata->stats;
+}
+
+static int __init ieee80211_init(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+
+	ret = ieee80211_wme_register();
+	if (ret) {
+		printk(KERN_DEBUG "ieee80211_init: failed to "
+		       "initialize WME (err=%d)\n", ret);
+		return ret;
+	}
+
+	ieee80211_debugfs_netdev_init();
+
+	return 0;
+}
+
+
+static void __exit ieee80211_exit(void)
+{
+	ieee80211_wme_unregister();
+	ieee80211_debugfs_netdev_exit();
+}
+
+
+module_init(ieee80211_init);
+module_exit(ieee80211_exit);
+
+MODULE_DESCRIPTION("IEEE 802.11 subsystem");
+MODULE_LICENSE("GPL");
diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c
new file mode 100644
index 0000000..509096e
--- /dev/null
+++ b/net/mac80211/ieee80211_cfg.c
@@ -0,0 +1,66 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ *
+ * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is GPLv2 as found in COPYING.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_cfg.h"
+
+static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
+			       unsigned int type)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	int itype;
+
+	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+		return -ENODEV;
+
+	switch (type) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		itype = IEEE80211_IF_TYPE_STA;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		itype = IEEE80211_IF_TYPE_IBSS;
+		break;
+	case NL80211_IFTYPE_STATION:
+		itype = IEEE80211_IF_TYPE_STA;
+		break;
+	case NL80211_IFTYPE_MONITOR:
+		itype = IEEE80211_IF_TYPE_MNTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ieee80211_if_add(local->mdev, name, NULL, itype);
+}
+
+static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct net_device *dev;
+	char *name;
+
+	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+		return -ENODEV;
+
+	dev = dev_get_by_index(ifindex);
+	if (!dev)
+		return 0;
+
+	name = dev->name;
+	dev_put(dev);
+
+	return ieee80211_if_remove(local->mdev, name, -1);
+}
+
+struct cfg80211_ops mac80211_config_ops = {
+	.add_virtual_intf = ieee80211_add_iface,
+	.del_virtual_intf = ieee80211_del_iface,
+};
diff --git a/net/mac80211/ieee80211_cfg.h b/net/mac80211/ieee80211_cfg.h
new file mode 100644
index 0000000..85ed2c9
--- /dev/null
+++ b/net/mac80211/ieee80211_cfg.h
@@ -0,0 +1,9 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ */
+#ifndef __IEEE80211_CFG_H
+#define __IEEE80211_CFG_H
+
+extern struct cfg80211_ops mac80211_config_ops;
+
+#endif /* __IEEE80211_CFG_H */
diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h
new file mode 100644
index 0000000..b9a73e7
--- /dev/null
+++ b/net/mac80211/ieee80211_common.h
@@ -0,0 +1,98 @@
+/*
+ * IEEE 802.11 driver (80211.o) -- hostapd interface
+ * Copyright 2002-2004, Instant802 Networks, 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 IEEE80211_COMMON_H
+#define IEEE80211_COMMON_H
+
+#include <linux/types.h>
+
+/*
+ * This is common header information with user space. It is used on all
+ * frames sent to wlan#ap interface.
+ */
+
+#define IEEE80211_FI_VERSION 0x80211001
+
+struct ieee80211_frame_info {
+	__be32 version;
+	__be32 length;
+	__be64 mactime;
+	__be64 hosttime;
+	__be32 phytype;
+	__be32 channel;
+	__be32 datarate;
+	__be32 antenna;
+	__be32 priority;
+	__be32 ssi_type;
+	__be32 ssi_signal;
+	__be32 ssi_noise;
+	__be32 preamble;
+	__be32 encoding;
+
+	/* Note: this structure is otherwise identical to capture format used
+	 * in linux-wlan-ng, but this additional field is used to provide meta
+	 * data about the frame to hostapd. This was the easiest method for
+	 * providing this information, but this might change in the future. */
+	__be32 msg_type;
+} __attribute__ ((packed));
+
+
+enum ieee80211_msg_type {
+	ieee80211_msg_normal = 0,
+	ieee80211_msg_tx_callback_ack = 1,
+	ieee80211_msg_tx_callback_fail = 2,
+	ieee80211_msg_passive_scan = 3,
+	ieee80211_msg_wep_frame_unknown_key = 4,
+	ieee80211_msg_michael_mic_failure = 5,
+	/* hole at 6, was monitor but never sent to userspace */
+	ieee80211_msg_sta_not_assoc = 7,
+	ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
+	ieee80211_msg_key_threshold_notification = 9,
+	ieee80211_msg_radar = 11,
+};
+
+struct ieee80211_msg_set_aid_for_sta {
+	char	sta_address[ETH_ALEN];
+	u16	aid;
+};
+
+struct ieee80211_msg_key_notification {
+	int tx_rx_count;
+	char ifname[IFNAMSIZ];
+	u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */
+};
+
+
+enum ieee80211_phytype {
+	ieee80211_phytype_fhss_dot11_97  = 1,
+	ieee80211_phytype_dsss_dot11_97  = 2,
+	ieee80211_phytype_irbaseband     = 3,
+	ieee80211_phytype_dsss_dot11_b   = 4,
+	ieee80211_phytype_pbcc_dot11_b   = 5,
+	ieee80211_phytype_ofdm_dot11_g   = 6,
+	ieee80211_phytype_pbcc_dot11_g   = 7,
+	ieee80211_phytype_ofdm_dot11_a   = 8,
+	ieee80211_phytype_dsss_dot11_turbog = 255,
+	ieee80211_phytype_dsss_dot11_turbo = 256,
+};
+
+enum ieee80211_ssi_type {
+	ieee80211_ssi_none = 0,
+	ieee80211_ssi_norm = 1, /* normalized, 0-1000 */
+	ieee80211_ssi_dbm = 2,
+	ieee80211_ssi_raw = 3, /* raw SSI */
+};
+
+struct ieee80211_radar_info {
+		int channel;
+		int radar;
+		int radar_type;
+};
+
+#endif /* IEEE80211_COMMON_H */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
new file mode 100644
index 0000000..af4d14d
--- /dev/null
+++ b/net/mac80211/ieee80211_i.h
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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 IEEE80211_I_H
+#define IEEE80211_I_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/if_ether.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <net/wireless.h>
+#include "ieee80211_key.h"
+#include "sta_info.h"
+
+/* ieee80211.o internal definitions, etc. These are not included into
+ * low-level drivers. */
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define WLAN_FC_DATA_PRESENT(fc) (((fc) & 0x4c) == 0x08)
+
+struct ieee80211_local;
+
+#define BIT(x) (1 << (x))
+
+#define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
+
+/* Maximum number of broadcast/multicast frames to buffer when some of the
+ * associated stations are using power saving. */
+#define AP_MAX_BC_BUFFER 128
+
+/* Maximum number of frames buffered to all STAs, including multicast frames.
+ * Note: increasing this limit increases the potential memory requirement. Each
+ * frame can be up to about 2 kB long. */
+#define TOTAL_MAX_TX_BUFFER 512
+
+/* Required encryption head and tailroom */
+#define IEEE80211_ENCRYPT_HEADROOM 8
+#define IEEE80211_ENCRYPT_TAILROOM 12
+
+/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
+ * reception of at least three fragmented frames. This limit can be increased
+ * by changing this define, at the cost of slower frame reassembly and
+ * increased memory use (about 2 kB of RAM per entry). */
+#define IEEE80211_FRAGMENT_MAX 4
+
+struct ieee80211_fragment_entry {
+	unsigned long first_frag_time;
+	unsigned int seq;
+	unsigned int rx_queue;
+	unsigned int last_frag;
+	unsigned int extra_len;
+	struct sk_buff_head skb_list;
+	int ccmp; /* Whether fragments were encrypted with CCMP */
+	u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
+};
+
+
+struct ieee80211_sta_bss {
+	struct list_head list;
+	struct ieee80211_sta_bss *hnext;
+	atomic_t users;
+
+	u8 bssid[ETH_ALEN];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	size_t ssid_len;
+	u16 capability; /* host byte order */
+	int hw_mode;
+	int channel;
+	int freq;
+	int rssi, signal, noise;
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+	u8 *rsn_ie;
+	size_t rsn_ie_len;
+	u8 *wmm_ie;
+	size_t wmm_ie_len;
+#define IEEE80211_MAX_SUPP_RATES 32
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+	size_t supp_rates_len;
+	int beacon_int;
+	u64 timestamp;
+
+	int probe_resp;
+	unsigned long last_update;
+
+};
+
+
+typedef enum {
+	TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
+} ieee80211_txrx_result;
+
+struct ieee80211_txrx_data {
+	struct sk_buff *skb;
+	struct net_device *dev;
+	struct ieee80211_local *local;
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+	u16 fc, ethertype;
+	struct ieee80211_key *key;
+	unsigned int fragmented:1; /* whether the MSDU was fragmented */
+	union {
+		struct {
+			struct ieee80211_tx_control *control;
+			unsigned int unicast:1;
+			unsigned int ps_buffered:1;
+			unsigned int short_preamble:1;
+			unsigned int probe_last_frag:1;
+			struct ieee80211_hw_mode *mode;
+			struct ieee80211_rate *rate;
+			/* use this rate (if set) for last fragment; rate can
+			 * be set to lower rate for the first fragments, e.g.,
+			 * when using CTS protection with IEEE 802.11g. */
+			struct ieee80211_rate *last_frag_rate;
+			int last_frag_hwrate;
+			int mgmt_interface;
+
+			/* Extra fragments (in addition to the first fragment
+			 * in skb) */
+			int num_extra_frag;
+			struct sk_buff **extra_frag;
+		} tx;
+		struct {
+			struct ieee80211_rx_status *status;
+			int sent_ps_buffered;
+			int queue;
+			int load;
+			unsigned int in_scan:1;
+			/* frame is destined to interface currently processed
+			 * (including multicast frames) */
+			unsigned int ra_match:1;
+		} rx;
+	} u;
+};
+
+/* Stored in sk_buff->cb */
+struct ieee80211_tx_packet_data {
+	int ifindex;
+	unsigned long jiffies;
+	unsigned int req_tx_status:1;
+	unsigned int do_not_encrypt:1;
+	unsigned int requeue:1;
+	unsigned int mgmt_iface:1;
+	unsigned int queue:4;
+};
+
+struct ieee80211_tx_stored_packet {
+	struct ieee80211_tx_control control;
+	struct sk_buff *skb;
+	int num_extra_frag;
+	struct sk_buff **extra_frag;
+	int last_frag_rateidx;
+	int last_frag_hwrate;
+	struct ieee80211_rate *last_frag_rate;
+	unsigned int last_frag_rate_ctrl_probe:1;
+};
+
+typedef ieee80211_txrx_result (*ieee80211_tx_handler)
+(struct ieee80211_txrx_data *tx);
+
+typedef ieee80211_txrx_result (*ieee80211_rx_handler)
+(struct ieee80211_txrx_data *rx);
+
+struct ieee80211_if_ap {
+	u8 *beacon_head, *beacon_tail;
+	int beacon_head_len, beacon_tail_len;
+
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	size_t ssid_len;
+	u8 *generic_elem;
+	size_t generic_elem_len;
+
+	/* yes, this looks ugly, but guarantees that we can later use
+	 * bitmap_empty :)
+	 * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */
+	u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
+	atomic_t num_sta_ps; /* number of stations in PS mode */
+	struct sk_buff_head ps_bc_buf;
+	int dtim_period, dtim_count;
+	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
+	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
+	int num_beacons; /* number of TXed beacon frames for this BSS */
+};
+
+struct ieee80211_if_wds {
+	u8 remote_addr[ETH_ALEN];
+	struct sta_info *sta;
+};
+
+struct ieee80211_if_vlan {
+	u8 id;
+};
+
+struct ieee80211_if_sta {
+	enum {
+		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
+		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
+		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
+	} state;
+	struct timer_list timer;
+	struct work_struct work;
+	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	size_t ssid_len;
+	u16 aid;
+	u16 ap_capab, capab;
+	u8 *extra_ie; /* to be added to the end of AssocReq */
+	size_t extra_ie_len;
+
+	/* The last AssocReq/Resp IEs */
+	u8 *assocreq_ies, *assocresp_ies;
+	size_t assocreq_ies_len, assocresp_ies_len;
+
+	int auth_tries, assoc_tries;
+
+	unsigned int ssid_set:1;
+	unsigned int bssid_set:1;
+	unsigned int prev_bssid_set:1;
+	unsigned int authenticated:1;
+	unsigned int associated:1;
+	unsigned int probereq_poll:1;
+	unsigned int use_protection:1;
+	unsigned int create_ibss:1;
+	unsigned int mixed_cell:1;
+	unsigned int wmm_enabled:1;
+	unsigned int auto_ssid_sel:1;
+	unsigned int auto_bssid_sel:1;
+	unsigned int auto_channel_sel:1;
+#define IEEE80211_STA_REQ_SCAN 0
+#define IEEE80211_STA_REQ_AUTH 1
+#define IEEE80211_STA_REQ_RUN  2
+	unsigned long request;
+	struct sk_buff_head skb_queue;
+
+	int key_mgmt;
+	unsigned long last_probe;
+
+#define IEEE80211_AUTH_ALG_OPEN BIT(0)
+#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
+#define IEEE80211_AUTH_ALG_LEAP BIT(2)
+	unsigned int auth_algs; /* bitfield of allowed auth algs */
+	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
+	int auth_transaction;
+
+	unsigned long ibss_join_req;
+	struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
+	u32 supp_rates_bits;
+
+	int wmm_last_param_set;
+};
+
+
+struct ieee80211_sub_if_data {
+	struct list_head list;
+	unsigned int type;
+
+	struct wireless_dev wdev;
+
+	struct net_device *dev;
+	struct ieee80211_local *local;
+
+	int mc_count;
+	unsigned int allmulti:1;
+	unsigned int promisc:1;
+
+	struct net_device_stats stats;
+	int drop_unencrypted;
+	int eapol; /* 0 = process EAPOL frames as normal data frames,
+		    * 1 = send EAPOL frames through wlan#ap to hostapd
+		    *     (default) */
+	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
+			 * port */
+
+	u16 sequence;
+
+	/* Fragment table for host-based reassembly */
+	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
+	unsigned int fragment_next;
+
+#define NUM_DEFAULT_KEYS 4
+	struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
+	struct ieee80211_key *default_key;
+
+	struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
+
+	union {
+		struct ieee80211_if_ap ap;
+		struct ieee80211_if_wds wds;
+		struct ieee80211_if_vlan vlan;
+		struct ieee80211_if_sta sta;
+	} u;
+	int channel_use;
+	int channel_use_raw;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *debugfsdir;
+	union {
+		struct {
+			struct dentry *channel_use;
+			struct dentry *drop_unencrypted;
+			struct dentry *eapol;
+			struct dentry *ieee8021_x;
+			struct dentry *state;
+			struct dentry *bssid;
+			struct dentry *prev_bssid;
+			struct dentry *ssid_len;
+			struct dentry *aid;
+			struct dentry *ap_capab;
+			struct dentry *capab;
+			struct dentry *extra_ie_len;
+			struct dentry *auth_tries;
+			struct dentry *assoc_tries;
+			struct dentry *auth_algs;
+			struct dentry *auth_alg;
+			struct dentry *auth_transaction;
+			struct dentry *flags;
+		} sta;
+		struct {
+			struct dentry *channel_use;
+			struct dentry *drop_unencrypted;
+			struct dentry *eapol;
+			struct dentry *ieee8021_x;
+			struct dentry *num_sta_ps;
+			struct dentry *dtim_period;
+			struct dentry *dtim_count;
+			struct dentry *num_beacons;
+			struct dentry *force_unicast_rateidx;
+			struct dentry *max_ratectrl_rateidx;
+			struct dentry *num_buffered_multicast;
+			struct dentry *beacon_head_len;
+			struct dentry *beacon_tail_len;
+		} ap;
+		struct {
+			struct dentry *channel_use;
+			struct dentry *drop_unencrypted;
+			struct dentry *eapol;
+			struct dentry *ieee8021_x;
+			struct dentry *peer;
+		} wds;
+		struct {
+			struct dentry *channel_use;
+			struct dentry *drop_unencrypted;
+			struct dentry *eapol;
+			struct dentry *ieee8021_x;
+			struct dentry *vlan_id;
+		} vlan;
+		struct {
+			struct dentry *mode;
+		} monitor;
+		struct dentry *default_key;
+	} debugfs;
+#endif
+};
+
+#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
+
+enum {
+	IEEE80211_RX_MSG	= 1,
+	IEEE80211_TX_STATUS_MSG	= 2,
+};
+
+struct ieee80211_local {
+	/* embed the driver visible part.
+	 * don't cast (use the static inlines below), but we keep
+	 * it first anyway so they become a no-op */
+	struct ieee80211_hw hw;
+
+	const struct ieee80211_ops *ops;
+
+	/* List of registered struct ieee80211_hw_mode */
+	struct list_head modes_list;
+
+	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
+	struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
+	int open_count;
+	int monitors;
+	struct iw_statistics wstats;
+	u8 wstats_flags;
+
+	enum {
+		IEEE80211_DEV_UNINITIALIZED = 0,
+		IEEE80211_DEV_REGISTERED,
+		IEEE80211_DEV_UNREGISTERED,
+	} reg_state;
+
+	/* Tasklet and skb queue to process calls from IRQ mode. All frames
+	 * added to skb_queue will be processed, but frames in
+	 * skb_queue_unreliable may be dropped if the total length of these
+	 * queues increases over the limit. */
+#define IEEE80211_IRQSAFE_QUEUE_LIMIT 128
+	struct tasklet_struct tasklet;
+	struct sk_buff_head skb_queue;
+	struct sk_buff_head skb_queue_unreliable;
+
+	/* Station data structures */
+	spinlock_t sta_lock; /* mutex for STA data structures */
+	int num_sta; /* number of stations in sta_list */
+	struct list_head sta_list;
+	struct list_head deleted_sta_list;
+	struct sta_info *sta_hash[STA_HASH_SIZE];
+	struct timer_list sta_cleanup;
+
+	unsigned long state[NUM_TX_DATA_QUEUES];
+	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+	struct tasklet_struct tx_pending_tasklet;
+
+	int mc_count;	/* total count of multicast entries in all interfaces */
+	int iff_allmultis, iff_promiscs;
+			/* number of interfaces with corresponding IFF_ flags */
+
+	struct rate_control_ref *rate_ctrl;
+
+	int next_mode; /* MODE_IEEE80211*
+			* The mode preference for next channel change. This is
+			* used to select .11g vs. .11b channels (or 4.9 GHz vs.
+			* .11a) when the channel number is not unique. */
+
+	/* Supported and basic rate filters for different modes. These are
+	 * pointers to -1 terminated lists and rates in 100 kbps units. */
+	int *supp_rates[NUM_IEEE80211_MODES];
+	int *basic_rates[NUM_IEEE80211_MODES];
+
+	int rts_threshold;
+	int cts_protect_erp_frames;
+	int fragmentation_threshold;
+	int short_retry_limit; /* dot11ShortRetryLimit */
+	int long_retry_limit; /* dot11LongRetryLimit */
+	int short_preamble; /* use short preamble with IEEE 802.11b */
+
+	struct crypto_blkcipher *wep_tx_tfm;
+	struct crypto_blkcipher *wep_rx_tfm;
+	u32 wep_iv;
+	int key_tx_rx_threshold; /* number of times any key can be used in TX
+				  * or RX before generating a rekey
+				  * notification; 0 = notification disabled. */
+
+	int bridge_packets; /* bridge packets between associated stations and
+			     * deliver multicast frames both back to wireless
+			     * media and to the local net stack */
+
+	ieee80211_rx_handler *rx_pre_handlers;
+	ieee80211_rx_handler *rx_handlers;
+	ieee80211_tx_handler *tx_handlers;
+
+	rwlock_t sub_if_lock; /* Protects sub_if_list. Cannot be taken under
+			       * sta_bss_lock or sta_lock. */
+	struct list_head sub_if_list;
+	int sta_scanning;
+	int scan_channel_idx;
+	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+	unsigned long last_scan_completed;
+	struct delayed_work scan_work;
+	struct net_device *scan_dev;
+	struct ieee80211_channel *oper_channel, *scan_channel;
+	struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
+	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
+	size_t scan_ssid_len;
+	struct list_head sta_bss_list;
+	struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
+	spinlock_t sta_bss_lock;
+#define IEEE80211_SCAN_MATCH_SSID BIT(0)
+#define IEEE80211_SCAN_WPA_ONLY BIT(1)
+#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
+	int scan_flags;
+
+	/* SNMP counters */
+	/* dot11CountersTable */
+	u32 dot11TransmittedFragmentCount;
+	u32 dot11MulticastTransmittedFrameCount;
+	u32 dot11FailedCount;
+	u32 dot11RetryCount;
+	u32 dot11MultipleRetryCount;
+	u32 dot11FrameDuplicateCount;
+	u32 dot11ReceivedFragmentCount;
+	u32 dot11MulticastReceivedFrameCount;
+	u32 dot11TransmittedFrameCount;
+	u32 dot11WEPUndecryptableCount;
+
+#ifdef CONFIG_MAC80211_LEDS
+	int tx_led_counter, rx_led_counter;
+	struct led_trigger *tx_led, *rx_led;
+	char tx_led_name[32], rx_led_name[32];
+#endif
+
+	u32 channel_use;
+	u32 channel_use_raw;
+	u32 stat_time;
+	struct timer_list stat_timer;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct work_struct sta_debugfs_add;
+#endif
+
+	enum {
+		STA_ANTENNA_SEL_AUTO = 0,
+		STA_ANTENNA_SEL_SW_CTRL = 1,
+		STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2
+	} sta_antenna_sel;
+
+	int rate_ctrl_num_up, rate_ctrl_num_down;
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	/* TX/RX handler statistics */
+	unsigned int tx_handlers_drop;
+	unsigned int tx_handlers_queued;
+	unsigned int tx_handlers_drop_unencrypted;
+	unsigned int tx_handlers_drop_fragment;
+	unsigned int tx_handlers_drop_wep;
+	unsigned int tx_handlers_drop_not_assoc;
+	unsigned int tx_handlers_drop_unauth_port;
+	unsigned int rx_handlers_drop;
+	unsigned int rx_handlers_queued;
+	unsigned int rx_handlers_drop_nullfunc;
+	unsigned int rx_handlers_drop_defrag;
+	unsigned int rx_handlers_drop_short;
+	unsigned int rx_handlers_drop_passive_scan;
+	unsigned int tx_expand_skb_head;
+	unsigned int tx_expand_skb_head_cloned;
+	unsigned int rx_expand_skb_head;
+	unsigned int rx_expand_skb_head2;
+	unsigned int rx_handlers_fragments;
+	unsigned int tx_status_drop;
+	unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
+#define I802_DEBUG_INC(c) (c)++
+#else /* CONFIG_MAC80211_DEBUG_COUNTERS */
+#define I802_DEBUG_INC(c) do { } while (0)
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+
+	int default_wep_only; /* only default WEP keys are used with this
+			       * interface; this is used to decide when hwaccel
+			       * can be used with default keys */
+	int total_ps_buffered; /* total number of all buffered unicast and
+				* multicast packets for power saving stations
+				*/
+	int allow_broadcast_always; /* whether to allow TX of broadcast frames
+				     * even when there are no associated STAs
+				     */
+
+	int wifi_wme_noack_test;
+	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
+
+	unsigned int enabled_modes; /* bitfield of allowed modes;
+				      * (1 << MODE_*) */
+	unsigned int hw_modes; /* bitfield of supported hardware modes;
+				* (1 << MODE_*) */
+
+	int user_space_mlme;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct local_debugfsdentries {
+		struct dentry *channel;
+		struct dentry *frequency;
+		struct dentry *radar_detect;
+		struct dentry *antenna_sel_tx;
+		struct dentry *antenna_sel_rx;
+		struct dentry *bridge_packets;
+		struct dentry *key_tx_rx_threshold;
+		struct dentry *rts_threshold;
+		struct dentry *fragmentation_threshold;
+		struct dentry *short_retry_limit;
+		struct dentry *long_retry_limit;
+		struct dentry *total_ps_buffered;
+		struct dentry *mode;
+		struct dentry *wep_iv;
+		struct dentry *tx_power_reduction;
+		struct dentry *modes;
+		struct dentry *statistics;
+		struct local_debugfsdentries_statsdentries {
+			struct dentry *transmitted_fragment_count;
+			struct dentry *multicast_transmitted_frame_count;
+			struct dentry *failed_count;
+			struct dentry *retry_count;
+			struct dentry *multiple_retry_count;
+			struct dentry *frame_duplicate_count;
+			struct dentry *received_fragment_count;
+			struct dentry *multicast_received_frame_count;
+			struct dentry *transmitted_frame_count;
+			struct dentry *wep_undecryptable_count;
+			struct dentry *num_scans;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+			struct dentry *tx_handlers_drop;
+			struct dentry *tx_handlers_queued;
+			struct dentry *tx_handlers_drop_unencrypted;
+			struct dentry *tx_handlers_drop_fragment;
+			struct dentry *tx_handlers_drop_wep;
+			struct dentry *tx_handlers_drop_not_assoc;
+			struct dentry *tx_handlers_drop_unauth_port;
+			struct dentry *rx_handlers_drop;
+			struct dentry *rx_handlers_queued;
+			struct dentry *rx_handlers_drop_nullfunc;
+			struct dentry *rx_handlers_drop_defrag;
+			struct dentry *rx_handlers_drop_short;
+			struct dentry *rx_handlers_drop_passive_scan;
+			struct dentry *tx_expand_skb_head;
+			struct dentry *tx_expand_skb_head_cloned;
+			struct dentry *rx_expand_skb_head;
+			struct dentry *rx_expand_skb_head2;
+			struct dentry *rx_handlers_fragments;
+			struct dentry *tx_status_drop;
+			struct dentry *wme_tx_queue;
+			struct dentry *wme_rx_queue;
+#endif
+			struct dentry *dot11ACKFailureCount;
+			struct dentry *dot11RTSFailureCount;
+			struct dentry *dot11FCSErrorCount;
+			struct dentry *dot11RTSSuccessCount;
+		} stats;
+		struct dentry *stations;
+		struct dentry *keys;
+	} debugfs;
+#endif
+};
+
+static inline struct ieee80211_local *hw_to_local(
+	struct ieee80211_hw *hw)
+{
+	return container_of(hw, struct ieee80211_local, hw);
+}
+
+static inline struct ieee80211_hw *local_to_hw(
+	struct ieee80211_local *local)
+{
+	return &local->hw;
+}
+
+enum ieee80211_link_state_t {
+	IEEE80211_LINK_STATE_XOFF = 0,
+	IEEE80211_LINK_STATE_PENDING,
+};
+
+struct sta_attribute {
+	struct attribute attr;
+	ssize_t (*show)(const struct sta_info *, char *buf);
+	ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
+};
+
+static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid)
+{
+	/*
+	 * This format has ben mandated by the IEEE specifications,
+	 * so this line may not be changed to use the __set_bit() format.
+	 */
+	bss->tim[(aid)/8] |= 1<<((aid) % 8);
+}
+
+static inline void bss_tim_set(struct ieee80211_local *local,
+			       struct ieee80211_if_ap *bss, int aid)
+{
+	spin_lock_bh(&local->sta_lock);
+	__bss_tim_set(bss, aid);
+	spin_unlock_bh(&local->sta_lock);
+}
+
+static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
+{
+	/*
+	 * This format has ben mandated by the IEEE specifications,
+	 * so this line may not be changed to use the __clear_bit() format.
+	 */
+	bss->tim[(aid)/8] &= !(1<<((aid) % 8));
+}
+
+static inline void bss_tim_clear(struct ieee80211_local *local,
+				 struct ieee80211_if_ap *bss, int aid)
+{
+	spin_lock_bh(&local->sta_lock);
+	__bss_tim_clear(bss, aid);
+	spin_unlock_bh(&local->sta_lock);
+}
+
+/**
+ * ieee80211_is_erp_rate - Check if a rate is an ERP rate
+ * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
+ * @rate: Transmission rate to check, in 100 kbps
+ *
+ * Check if a given rate is an Extended Rate PHY (ERP) rate.
+ */
+static inline int ieee80211_is_erp_rate(int phymode, int rate)
+{
+	if (phymode == MODE_IEEE80211G) {
+		if (rate != 10 && rate != 20 &&
+		    rate != 55 && rate != 110)
+			return 1;
+	}
+	return 0;
+}
+
+/* ieee80211.c */
+int ieee80211_hw_config(struct ieee80211_local *local);
+int ieee80211_if_config(struct net_device *dev);
+int ieee80211_if_config_beacon(struct net_device *dev);
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+			const struct ieee80211_key *data);
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+					  int idx, size_t key_len, gfp_t flags);
+void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+		       struct ieee80211_rx_status *status, u32 msg_type);
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+			     struct ieee80211_hw_mode *mode);
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+void ieee80211_if_setup(struct net_device *dev);
+void ieee80211_if_mgmt_setup(struct net_device *dev);
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+				 const char *name);
+struct net_device_stats *ieee80211_dev_stats(struct net_device *dev);
+
+/* ieee80211_ioctl.c */
+extern const struct iw_handler_def ieee80211_iw_handler_def;
+
+void ieee80211_update_default_wep_only(struct ieee80211_local *local);
+
+
+/* Least common multiple of the used rates (in 100 kbps). This is used to
+ * calculate rate_inv values for each rate so that only integers are needed. */
+#define CHAN_UTIL_RATE_LCM 95040
+/* 1 usec is 1/8 * (95040/10) = 1188 */
+#define CHAN_UTIL_PER_USEC 1188
+/* Amount of bits to shift the result right to scale the total utilization
+ * to values that will not wrap around 32-bit integers. */
+#define CHAN_UTIL_SHIFT 9
+/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1):
+ * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the
+ * raw value with about 23 should give utilization in 10th of a percentage
+ * (1/1000). However, utilization is only estimated and not all intervals
+ * between frames etc. are calculated. 18 seems to give numbers that are closer
+ * to the real maximum. */
+#define CHAN_UTIL_PER_10MS 18
+#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC)
+#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC)
+
+
+/* ieee80211_ioctl.c */
+int ieee80211_set_compression(struct ieee80211_local *local,
+			      struct net_device *dev, struct sta_info *sta);
+int ieee80211_init_client(struct net_device *dev);
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+/* ieee80211_sta.c */
+void ieee80211_sta_timer(unsigned long data);
+void ieee80211_sta_work(struct work_struct *work);
+void ieee80211_sta_scan_work(struct work_struct *work);
+void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
+			   struct ieee80211_rx_status *rx_status);
+int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
+int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
+int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
+int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta);
+int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
+void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+			   struct ieee80211_rx_status *rx_status);
+void ieee80211_rx_bss_list_init(struct net_device *dev);
+void ieee80211_rx_bss_list_deinit(struct net_device *dev);
+int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
+struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
+					 struct sk_buff *skb, u8 *bssid,
+					 u8 *addr);
+int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
+int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
+
+/* ieee80211_iface.c */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+		     struct net_device **new_dev, int type);
+void ieee80211_if_set_type(struct net_device *dev, int type);
+void ieee80211_if_reinit(struct net_device *dev);
+void __ieee80211_if_del(struct ieee80211_local *local,
+			struct ieee80211_sub_if_data *sdata);
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
+void ieee80211_if_free(struct net_device *dev);
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
+int ieee80211_if_add_mgmt(struct ieee80211_local *local);
+void ieee80211_if_del_mgmt(struct ieee80211_local *local);
+
+/* for wiphy privid */
+extern void *mac80211_wiphy_privid;
+
+#endif /* IEEE80211_I_H */
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
new file mode 100644
index 0000000..cf0f32e
--- /dev/null
+++ b/net/mac80211/ieee80211_iface.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+#include "debugfs_netdev.h"
+
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
+{
+	int i;
+
+	/* Default values for sub-interface parameters */
+	sdata->drop_unencrypted = 0;
+	sdata->eapol = 1;
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+		skb_queue_head_init(&sdata->fragments[i].skb_list);
+}
+
+static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
+{
+	int i;
+
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+		__skb_queue_purge(&sdata->fragments[i].skb_list);
+	}
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+		     struct net_device **new_dev, int type)
+{
+	struct net_device *ndev;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = NULL;
+	int ret;
+
+	ASSERT_RTNL();
+	ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+			    name, ieee80211_if_setup);
+	if (!ndev)
+		return -ENOMEM;
+
+	ret = dev_alloc_name(ndev, ndev->name);
+	if (ret < 0)
+		goto fail;
+
+	memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+	ndev->base_addr = dev->base_addr;
+	ndev->irq = dev->irq;
+	ndev->mem_start = dev->mem_start;
+	ndev->mem_end = dev->mem_end;
+	SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+	ndev->ieee80211_ptr = &sdata->wdev;
+	sdata->wdev.wiphy = local->hw.wiphy;
+	sdata->type = IEEE80211_IF_TYPE_AP;
+	sdata->dev = ndev;
+	sdata->local = local;
+	ieee80211_if_sdata_init(sdata);
+
+	ret = register_netdevice(ndev);
+	if (ret)
+		goto fail;
+
+	ieee80211_debugfs_add_netdev(sdata);
+	ieee80211_if_set_type(ndev, type);
+
+	write_lock_bh(&local->sub_if_lock);
+	if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
+		write_unlock_bh(&local->sub_if_lock);
+		__ieee80211_if_del(local, sdata);
+		return -ENODEV;
+	}
+	list_add(&sdata->list, &local->sub_if_list);
+	if (new_dev)
+		*new_dev = ndev;
+	write_unlock_bh(&local->sub_if_lock);
+
+	ieee80211_update_default_wep_only(local);
+
+	return 0;
+
+fail:
+	free_netdev(ndev);
+	return ret;
+}
+
+int ieee80211_if_add_mgmt(struct ieee80211_local *local)
+{
+	struct net_device *ndev;
+	struct ieee80211_sub_if_data *nsdata;
+	int ret;
+
+	ASSERT_RTNL();
+
+	ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
+			    ieee80211_if_mgmt_setup);
+	if (!ndev)
+		return -ENOMEM;
+	ret = dev_alloc_name(ndev, ndev->name);
+	if (ret < 0)
+		goto fail;
+
+	memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+	SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+	nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+	ndev->ieee80211_ptr = &nsdata->wdev;
+	nsdata->wdev.wiphy = local->hw.wiphy;
+	nsdata->type = IEEE80211_IF_TYPE_MGMT;
+	nsdata->dev = ndev;
+	nsdata->local = local;
+	ieee80211_if_sdata_init(nsdata);
+
+	ret = register_netdevice(ndev);
+	if (ret)
+		goto fail;
+
+	ieee80211_debugfs_add_netdev(nsdata);
+
+	if (local->open_count > 0)
+		dev_open(ndev);
+	local->apdev = ndev;
+	return 0;
+
+fail:
+	free_netdev(ndev);
+	return ret;
+}
+
+void ieee80211_if_del_mgmt(struct ieee80211_local *local)
+{
+	struct net_device *apdev;
+
+	ASSERT_RTNL();
+	apdev = local->apdev;
+	ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
+	local->apdev = NULL;
+	unregister_netdevice(apdev);
+}
+
+void ieee80211_if_set_type(struct net_device *dev, int type)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int oldtype = sdata->type;
+
+	sdata->type = type;
+	switch (type) {
+	case IEEE80211_IF_TYPE_WDS:
+		sdata->bss = NULL;
+		break;
+	case IEEE80211_IF_TYPE_VLAN:
+		break;
+	case IEEE80211_IF_TYPE_AP:
+		sdata->u.ap.dtim_period = 2;
+		sdata->u.ap.force_unicast_rateidx = -1;
+		sdata->u.ap.max_ratectrl_rateidx = -1;
+		skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
+		sdata->bss = &sdata->u.ap;
+		break;
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS: {
+		struct ieee80211_sub_if_data *msdata;
+		struct ieee80211_if_sta *ifsta;
+
+		ifsta = &sdata->u.sta;
+		INIT_WORK(&ifsta->work, ieee80211_sta_work);
+		setup_timer(&ifsta->timer, ieee80211_sta_timer,
+			    (unsigned long) sdata);
+		skb_queue_head_init(&ifsta->skb_queue);
+
+		ifsta->capab = WLAN_CAPABILITY_ESS;
+		ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+			IEEE80211_AUTH_ALG_SHARED_KEY;
+		ifsta->create_ibss = 1;
+		ifsta->wmm_enabled = 1;
+		ifsta->auto_channel_sel = 1;
+		ifsta->auto_bssid_sel = 1;
+
+		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
+		sdata->bss = &msdata->u.ap;
+		break;
+	}
+	case IEEE80211_IF_TYPE_MNTR:
+		dev->type = ARPHRD_IEEE80211_RADIOTAP;
+		break;
+	default:
+		printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
+		       dev->name, __FUNCTION__, type);
+	}
+	ieee80211_debugfs_change_if_type(sdata, oldtype);
+	ieee80211_update_default_wep_only(local);
+}
+
+/* Must be called with rtnl lock held. */
+void ieee80211_if_reinit(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+	int i;
+
+	ASSERT_RTNL();
+	ieee80211_if_sdata_deinit(sdata);
+	for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+		if (!sdata->keys[i])
+			continue;
+#if 0
+		/* The interface is down at the moment, so there is not
+		 * really much point in disabling the keys at this point. */
+		memset(addr, 0xff, ETH_ALEN);
+		if (local->ops->set_key)
+			local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
+					    local->keys[i], 0);
+#endif
+		ieee80211_key_free(sdata->keys[i]);
+		sdata->keys[i] = NULL;
+	}
+
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_AP: {
+		/* Remove all virtual interfaces that use this BSS
+		 * as their sdata->bss */
+		struct ieee80211_sub_if_data *tsdata, *n;
+		LIST_HEAD(tmp_list);
+
+		write_lock_bh(&local->sub_if_lock);
+		list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
+			if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
+				printk(KERN_DEBUG "%s: removing virtual "
+				       "interface %s because its BSS interface"
+				       " is being removed\n",
+				       sdata->dev->name, tsdata->dev->name);
+				list_move_tail(&tsdata->list, &tmp_list);
+			}
+		}
+		write_unlock_bh(&local->sub_if_lock);
+
+		list_for_each_entry_safe(tsdata, n, &tmp_list, list)
+			__ieee80211_if_del(local, tsdata);
+
+		kfree(sdata->u.ap.beacon_head);
+		kfree(sdata->u.ap.beacon_tail);
+		kfree(sdata->u.ap.generic_elem);
+
+		if (dev != local->mdev) {
+			struct sk_buff *skb;
+			while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+				local->total_ps_buffered--;
+				dev_kfree_skb(skb);
+			}
+		}
+
+		break;
+	}
+	case IEEE80211_IF_TYPE_WDS:
+		sta = sta_info_get(local, sdata->u.wds.remote_addr);
+		if (sta) {
+			sta_info_put(sta);
+			sta_info_free(sta, 0);
+		} else {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			printk(KERN_DEBUG "%s: Someone had deleted my STA "
+			       "entry for the WDS link\n", dev->name);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+		}
+		break;
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+		kfree(sdata->u.sta.extra_ie);
+		sdata->u.sta.extra_ie = NULL;
+		kfree(sdata->u.sta.assocreq_ies);
+		sdata->u.sta.assocreq_ies = NULL;
+		kfree(sdata->u.sta.assocresp_ies);
+		sdata->u.sta.assocresp_ies = NULL;
+		if (sdata->u.sta.probe_resp) {
+			dev_kfree_skb(sdata->u.sta.probe_resp);
+			sdata->u.sta.probe_resp = NULL;
+		}
+
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		dev->type = ARPHRD_ETHER;
+		break;
+	}
+
+	/* remove all STAs that are bound to this virtual interface */
+	sta_info_flush(local, dev);
+
+	memset(&sdata->u, 0, sizeof(sdata->u));
+	ieee80211_if_sdata_init(sdata);
+}
+
+/* Must be called with rtnl lock held. */
+void __ieee80211_if_del(struct ieee80211_local *local,
+			struct ieee80211_sub_if_data *sdata)
+{
+	struct net_device *dev = sdata->dev;
+
+	ieee80211_debugfs_remove_netdev(sdata);
+	unregister_netdevice(dev);
+	/* Except master interface, the net_device will be freed by
+	 * net_device->destructor (i. e. ieee80211_if_free). */
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata, *n;
+
+	ASSERT_RTNL();
+
+	write_lock_bh(&local->sub_if_lock);
+	list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+		if ((sdata->type == id || id == -1) &&
+		    strcmp(name, sdata->dev->name) == 0 &&
+		    sdata->dev != local->mdev) {
+			list_del(&sdata->list);
+			write_unlock_bh(&local->sub_if_lock);
+			__ieee80211_if_del(local, sdata);
+			ieee80211_update_default_wep_only(local);
+			return 0;
+		}
+	}
+	write_unlock_bh(&local->sub_if_lock);
+	return -ENODEV;
+}
+
+void ieee80211_if_free(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	/* local->apdev must be NULL when freeing management interface */
+	BUG_ON(dev == local->apdev);
+	ieee80211_if_sdata_deinit(sdata);
+	free_netdev(dev);
+}
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
new file mode 100644
index 0000000..352f03b
--- /dev/null
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape 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/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <asm/uaccess.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "hostapd_ioctl.h"
+#include "ieee80211_rate.h"
+#include "wpa.h"
+#include "aes_ccm.h"
+#include "debugfs_key.h"
+
+static int ieee80211_regdom = 0x10; /* FCC */
+module_param(ieee80211_regdom, int, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
+
+/*
+ * If firmware is upgraded by the vendor, additional channels can be used based
+ * on the new Japanese regulatory rules. This is indicated by setting
+ * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
+ * module.
+ */
+static int ieee80211_japan_5ghz /* = 0 */;
+module_param(ieee80211_japan_5ghz, int, 0444);
+MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
+
+static void ieee80211_set_hw_encryption(struct net_device *dev,
+					struct sta_info *sta, u8 addr[ETH_ALEN],
+					struct ieee80211_key *key)
+{
+	struct ieee80211_key_conf *keyconf = NULL;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	/* default to sw encryption; this will be cleared by low-level
+	 * driver if the hw supports requested encryption */
+	if (key)
+		key->force_sw_encrypt = 1;
+
+	if (key && local->ops->set_key &&
+	    (keyconf = ieee80211_key_data2conf(local, key))) {
+		if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
+				       keyconf, sta ? sta->aid : 0)) {
+			key->force_sw_encrypt = 1;
+			key->hw_key_idx = HW_KEY_IDX_INVALID;
+		} else {
+			key->force_sw_encrypt =
+				!!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
+			key->hw_key_idx =
+				keyconf->hw_key_idx;
+
+		}
+	}
+	kfree(keyconf);
+}
+
+
+static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
+				    int idx, int alg, int set_tx_key,
+				    const u8 *_key, size_t key_len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int ret = 0;
+	struct sta_info *sta;
+	struct ieee80211_key *key, *old_key;
+	int try_hwaccel = 1;
+	struct ieee80211_key_conf *keyconf;
+	struct ieee80211_sub_if_data *sdata;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (is_broadcast_ether_addr(sta_addr)) {
+		sta = NULL;
+		if (idx >= NUM_DEFAULT_KEYS) {
+			printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
+			       dev->name, idx);
+			return -EINVAL;
+		}
+		key = sdata->keys[idx];
+
+		/* TODO: consider adding hwaccel support for these; at least
+		 * Atheros key cache should be able to handle this since AP is
+		 * only transmitting frames with default keys. */
+		/* FIX: hw key cache can be used when only one virtual
+		 * STA is associated with each AP. If more than one STA
+		 * is associated to the same AP, software encryption
+		 * must be used. This should be done automatically
+		 * based on configured station devices. For the time
+		 * being, this can be only set at compile time. */
+	} else {
+		set_tx_key = 0;
+		if (idx != 0) {
+			printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
+			       "individual key\n", dev->name);
+			return -EINVAL;
+		}
+
+		sta = sta_info_get(local, sta_addr);
+		if (!sta) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
+			       MAC_FMT "\n",
+			       dev->name, MAC_ARG(sta_addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+			return -ENOENT;
+		}
+
+		key = sta->key;
+	}
+
+	/* FIX:
+	 * Cannot configure default hwaccel keys with WEP algorithm, if
+	 * any of the virtual interfaces is using static WEP
+	 * configuration because hwaccel would otherwise try to decrypt
+	 * these frames.
+	 *
+	 * For now, just disable WEP hwaccel for broadcast when there is
+	 * possibility of conflict with default keys. This can maybe later be
+	 * optimized by using non-default keys (at least with Atheros ar521x).
+	 */
+	if (!sta && alg == ALG_WEP && !local->default_wep_only &&
+	    sdata->type != IEEE80211_IF_TYPE_IBSS &&
+	    sdata->type != IEEE80211_IF_TYPE_AP) {
+		try_hwaccel = 0;
+	}
+
+	if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
+		/* Software encryption cannot be used with devices that hide
+		 * encryption from the host system, so always try to use
+		 * hardware acceleration with such devices. */
+		try_hwaccel = 1;
+	}
+
+	if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
+	    alg == ALG_TKIP) {
+		if (sta && (sta->flags & WLAN_STA_WME)) {
+		/* Hardware does not support hwaccel with TKIP when using WMM.
+		 */
+			try_hwaccel = 0;
+		}
+		else if (sdata->type == IEEE80211_IF_TYPE_STA) {
+			sta = sta_info_get(local, sdata->u.sta.bssid);
+			if (sta) {
+				if (sta->flags & WLAN_STA_WME) {
+					try_hwaccel = 0;
+				}
+				sta_info_put(sta);
+				sta = NULL;
+			}
+		}
+	}
+
+	if (alg == ALG_NONE) {
+		keyconf = NULL;
+		if (try_hwaccel && key &&
+		    key->hw_key_idx != HW_KEY_IDX_INVALID &&
+		    local->ops->set_key &&
+		    (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
+		    local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+				       sta_addr, keyconf, sta ? sta->aid : 0)) {
+			printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
+			       " failed\n", dev->name);
+			ret = -EINVAL;
+		}
+		kfree(keyconf);
+
+		if (set_tx_key || sdata->default_key == key) {
+			ieee80211_debugfs_key_remove_default(sdata);
+			sdata->default_key = NULL;
+		}
+		ieee80211_debugfs_key_remove(key);
+		if (sta)
+			sta->key = NULL;
+		else
+			sdata->keys[idx] = NULL;
+		ieee80211_key_free(key);
+		key = NULL;
+	} else {
+		old_key = key;
+		key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
+					  GFP_KERNEL);
+		if (!key) {
+			ret = -ENOMEM;
+			goto err_out;
+		}
+
+		/* default to sw encryption; low-level driver sets these if the
+		 * requested encryption is supported */
+		key->hw_key_idx = HW_KEY_IDX_INVALID;
+		key->force_sw_encrypt = 1;
+
+		key->alg = alg;
+		key->keyidx = idx;
+		key->keylen = key_len;
+		memcpy(key->key, _key, key_len);
+		if (set_tx_key)
+			key->default_tx_key = 1;
+
+		if (alg == ALG_CCMP) {
+			/* Initialize AES key state here as an optimization
+			 * so that it does not need to be initialized for every
+			 * packet. */
+			key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
+				key->key);
+			if (!key->u.ccmp.tfm) {
+				ret = -ENOMEM;
+				goto err_free;
+			}
+		}
+
+		if (set_tx_key || sdata->default_key == old_key) {
+			ieee80211_debugfs_key_remove_default(sdata);
+			sdata->default_key = NULL;
+		}
+		ieee80211_debugfs_key_remove(old_key);
+		if (sta)
+			sta->key = key;
+		else
+			sdata->keys[idx] = key;
+		ieee80211_key_free(old_key);
+		ieee80211_debugfs_key_add(local, key);
+		if (sta)
+			ieee80211_debugfs_key_sta_link(key, sta);
+
+		if (try_hwaccel &&
+		    (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
+			ieee80211_set_hw_encryption(dev, sta, sta_addr, key);
+	}
+
+	if (set_tx_key || (!sta && !sdata->default_key && key)) {
+		sdata->default_key = key;
+		if (key)
+			ieee80211_debugfs_key_add_default(sdata);
+
+		if (local->ops->set_key_idx &&
+		    local->ops->set_key_idx(local_to_hw(local), idx))
+			printk(KERN_DEBUG "%s: failed to set TX key idx for "
+			       "low-level driver\n", dev->name);
+	}
+
+	if (sta)
+		sta_info_put(sta);
+
+	return 0;
+
+err_free:
+	ieee80211_key_free(key);
+err_out:
+	if (sta)
+		sta_info_put(sta);
+	return ret;
+}
+
+static int ieee80211_ioctl_siwgenie(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *data, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (local->user_space_mlme)
+		return -EOPNOTSUPP;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
+		if (ret)
+			return ret;
+		sdata->u.sta.auto_bssid_sel = 0;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
+
+	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+		kfree(sdata->u.ap.generic_elem);
+		sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
+		if (!sdata->u.ap.generic_elem)
+			return -ENOMEM;
+		memcpy(sdata->u.ap.generic_elem, extra, data->length);
+		sdata->u.ap.generic_elem_len = data->length;
+		return ieee80211_if_config(dev);
+	}
+	return -EOPNOTSUPP;
+}
+
+static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev,
+					     int val)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
+
+	conf->radio_enabled = val;
+	return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr));
+}
+
+static int ieee80211_ioctl_giwname(struct net_device *dev,
+				   struct iw_request_info *info,
+				   char *name, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	switch (local->hw.conf.phymode) {
+	case MODE_IEEE80211A:
+		strcpy(name, "IEEE 802.11a");
+		break;
+	case MODE_IEEE80211B:
+		strcpy(name, "IEEE 802.11b");
+		break;
+	case MODE_IEEE80211G:
+		strcpy(name, "IEEE 802.11g");
+		break;
+	case MODE_ATHEROS_TURBO:
+		strcpy(name, "5GHz Turbo");
+		break;
+	default:
+		strcpy(name, "IEEE 802.11");
+		break;
+	}
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_giwrange(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct iw_point *data, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct iw_range *range = (struct iw_range *) extra;
+
+	data->length = sizeof(struct iw_range);
+	memset(range, 0, sizeof(struct iw_range));
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 21;
+	range->retry_capa = IW_RETRY_LIMIT;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->min_retry = 0;
+	range->max_retry = 255;
+	range->min_rts = 0;
+	range->max_rts = 2347;
+	range->min_frag = 256;
+	range->max_frag = 2346;
+
+	range->encoding_size[0] = 5;
+	range->encoding_size[1] = 13;
+	range->num_encoding_sizes = 2;
+	range->max_encoding_tokens = NUM_DEFAULT_KEYS;
+
+	range->max_qual.qual = local->hw.max_signal;
+	range->max_qual.level = local->hw.max_rssi;
+	range->max_qual.noise = local->hw.max_noise;
+	range->max_qual.updated = local->wstats_flags;
+
+	range->avg_qual.qual = local->hw.max_signal/2;
+	range->avg_qual.level = 0;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = local->wstats_flags;
+
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+
+	return 0;
+}
+
+
+struct ieee80211_channel_range {
+	short start_freq;
+	short end_freq;
+	unsigned char power_level;
+	unsigned char antenna_max;
+};
+
+static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
+	{ 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
+	{ 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
+	{ 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
+	{ 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
+	{ 0 }
+};
+
+static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
+	{ 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
+	{ 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
+	{ 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
+	{ 0 }
+};
+
+
+static const struct ieee80211_channel_range *channel_range =
+	ieee80211_fcc_channels;
+
+
+static void ieee80211_unmask_channel(struct net_device *dev, int mode,
+				     struct ieee80211_channel *chan)
+{
+	int i;
+
+	chan->flag = 0;
+
+	if (ieee80211_regdom == 64 &&
+	    (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
+		/* Do not allow Turbo modes in Japan. */
+		return;
+	}
+
+	for (i = 0; channel_range[i].start_freq; i++) {
+		const struct ieee80211_channel_range *r = &channel_range[i];
+		if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
+			if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
+			    chan->freq >= 5260 && chan->freq <= 5320) {
+				/*
+				 * Skip new channels in Japan since the
+				 * firmware was not marked having been upgraded
+				 * by the vendor.
+				 */
+				continue;
+			}
+
+			if (ieee80211_regdom == 0x10 &&
+			    (chan->freq == 5190 || chan->freq == 5210 ||
+			     chan->freq == 5230)) {
+				    /* Skip MKK channels when in FCC domain. */
+				    continue;
+			}
+
+			chan->flag |= IEEE80211_CHAN_W_SCAN |
+				IEEE80211_CHAN_W_ACTIVE_SCAN |
+				IEEE80211_CHAN_W_IBSS;
+			chan->power_level = r->power_level;
+			chan->antenna_max = r->antenna_max;
+
+			if (ieee80211_regdom == 64 &&
+			    (chan->freq == 5170 || chan->freq == 5190 ||
+			     chan->freq == 5210 || chan->freq == 5230)) {
+				/*
+				 * New regulatory rules in Japan have backwards
+				 * compatibility with old channels in 5.15-5.25
+				 * GHz band, but the station is not allowed to
+				 * use active scan on these old channels.
+				 */
+				chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
+			}
+
+			if (ieee80211_regdom == 64 &&
+			    (chan->freq == 5260 || chan->freq == 5280 ||
+			     chan->freq == 5300 || chan->freq == 5320)) {
+				/*
+				 * IBSS is not allowed on 5.25-5.35 GHz band
+				 * due to radar detection requirements.
+				 */
+				chan->flag &= ~IEEE80211_CHAN_W_IBSS;
+			}
+
+			break;
+		}
+	}
+}
+
+
+static int ieee80211_unmask_channels(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	int c;
+
+	list_for_each_entry(mode, &local->modes_list, list) {
+		for (c = 0; c < mode->num_channels; c++) {
+			ieee80211_unmask_channel(dev, mode->mode,
+						 &mode->channels[c]);
+		}
+	}
+	return 0;
+}
+
+
+int ieee80211_init_client(struct net_device *dev)
+{
+	if (ieee80211_regdom == 0x40)
+		channel_range = ieee80211_mkk_channels;
+	ieee80211_unmask_channels(dev);
+	return 0;
+}
+
+
+static int ieee80211_ioctl_siwmode(struct net_device *dev,
+				   struct iw_request_info *info,
+				   __u32 *mode, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int type;
+
+	if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+		return -EOPNOTSUPP;
+
+	switch (*mode) {
+	case IW_MODE_INFRA:
+		type = IEEE80211_IF_TYPE_STA;
+		break;
+	case IW_MODE_ADHOC:
+		type = IEEE80211_IF_TYPE_IBSS;
+		break;
+	case IW_MODE_MONITOR:
+		type = IEEE80211_IF_TYPE_MNTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (type == sdata->type)
+		return 0;
+	if (netif_running(dev))
+		return -EBUSY;
+
+	ieee80211_if_reinit(dev);
+	ieee80211_if_set_type(dev, type);
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_giwmode(struct net_device *dev,
+				   struct iw_request_info *info,
+				   __u32 *mode, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	switch (sdata->type) {
+	case IEEE80211_IF_TYPE_AP:
+		*mode = IW_MODE_MASTER;
+		break;
+	case IEEE80211_IF_TYPE_STA:
+		*mode = IW_MODE_INFRA;
+		break;
+	case IEEE80211_IF_TYPE_IBSS:
+		*mode = IW_MODE_ADHOC;
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		*mode = IW_MODE_MONITOR;
+		break;
+	case IEEE80211_IF_TYPE_WDS:
+		*mode = IW_MODE_REPEAT;
+		break;
+	case IEEE80211_IF_TYPE_VLAN:
+		*mode = IW_MODE_SECOND;		/* FIXME */
+		break;
+	default:
+		*mode = IW_MODE_AUTO;
+		break;
+	}
+	return 0;
+}
+
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+{
+	struct ieee80211_hw_mode *mode;
+	int c, set = 0;
+	int ret = -EINVAL;
+
+	list_for_each_entry(mode, &local->modes_list, list) {
+		if (!(local->enabled_modes & (1 << mode->mode)))
+			continue;
+		for (c = 0; c < mode->num_channels; c++) {
+			struct ieee80211_channel *chan = &mode->channels[c];
+			if (chan->flag & IEEE80211_CHAN_W_SCAN &&
+			    ((chan->chan == channel) || (chan->freq == freq))) {
+				/* Use next_mode as the mode preference to
+				 * resolve non-unique channel numbers. */
+				if (set && mode->mode != local->next_mode)
+					continue;
+
+				local->oper_channel = chan;
+				local->oper_hw_mode = mode;
+				set++;
+			}
+		}
+	}
+
+	if (set) {
+		if (local->sta_scanning)
+			ret = 0;
+		else
+			ret = ieee80211_hw_config(local);
+
+		rate_control_clear(local);
+	}
+
+	return ret;
+}
+
+static int ieee80211_ioctl_siwfreq(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_freq *freq, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA)
+		sdata->u.sta.auto_channel_sel = 0;
+
+	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
+	if (freq->e == 0) {
+		if (freq->m < 0) {
+			if (sdata->type == IEEE80211_IF_TYPE_STA)
+				sdata->u.sta.auto_channel_sel = 1;
+			return 0;
+		} else
+			return ieee80211_set_channel(local, freq->m, -1);
+	} else {
+		int i, div = 1000000;
+		for (i = 0; i < freq->e; i++)
+			div /= 10;
+		if (div > 0)
+			return ieee80211_set_channel(local, -1, freq->m / div);
+		else
+			return -EINVAL;
+	}
+}
+
+
+static int ieee80211_ioctl_giwfreq(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_freq *freq, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	/* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
+	 * driver for the current channel with firmware-based management */
+
+	freq->m = local->hw.conf.freq;
+	freq->e = 6;
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_siwessid(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *data, char *ssid)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	size_t len = data->length;
+
+	/* iwconfig uses nul termination in SSID.. */
+	if (len > 0 && ssid[len - 1] == '\0')
+		len--;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
+		if (local->user_space_mlme) {
+			if (len > IEEE80211_MAX_SSID_LEN)
+				return -EINVAL;
+			memcpy(sdata->u.sta.ssid, ssid, len);
+			sdata->u.sta.ssid_len = len;
+			return 0;
+		}
+		sdata->u.sta.auto_ssid_sel = !data->flags;
+		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
+
+	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+		memcpy(sdata->u.ap.ssid, ssid, len);
+		memset(sdata->u.ap.ssid + len, 0,
+		       IEEE80211_MAX_SSID_LEN - len);
+		sdata->u.ap.ssid_len = len;
+		return ieee80211_if_config(dev);
+	}
+	return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_giwessid(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_point *data, char *ssid)
+{
+	size_t len;
+
+	struct ieee80211_sub_if_data *sdata;
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int res = ieee80211_sta_get_ssid(dev, ssid, &len);
+		if (res == 0) {
+			data->length = len;
+			data->flags = 1;
+		} else
+			data->flags = 0;
+		return res;
+	}
+
+	if (sdata->type == IEEE80211_IF_TYPE_AP) {
+		len = sdata->u.ap.ssid_len;
+		if (len > IW_ESSID_MAX_SIZE)
+			len = IW_ESSID_MAX_SIZE;
+		memcpy(ssid, sdata->u.ap.ssid, len);
+		data->length = len;
+		data->flags = 1;
+		return 0;
+	}
+	return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_siwap(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct sockaddr *ap_addr, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
+		if (local->user_space_mlme) {
+			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
+			       ETH_ALEN);
+			return 0;
+		}
+		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+			sdata->u.sta.auto_bssid_sel = 1;
+			sdata->u.sta.auto_channel_sel = 1;
+		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+			sdata->u.sta.auto_bssid_sel = 1;
+		else
+			sdata->u.sta.auto_bssid_sel = 0;
+		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
+			   ETH_ALEN) == 0)
+			return 0;
+		return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
+	}
+
+	return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_giwap(struct net_device *dev,
+				 struct iw_request_info *info,
+				 struct sockaddr *ap_addr, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		ap_addr->sa_family = ARPHRD_ETHER;
+		memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
+		return 0;
+	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+		ap_addr->sa_family = ARPHRD_ETHER;
+		memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
+		return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_siwscan(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_point *data, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	u8 *ssid = NULL;
+	size_t ssid_len = 0;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
+		if (sdata->type == IEEE80211_IF_TYPE_STA ||
+		    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+			ssid = sdata->u.sta.ssid;
+			ssid_len = sdata->u.sta.ssid_len;
+		} else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+			ssid = sdata->u.ap.ssid;
+			ssid_len = sdata->u.ap.ssid_len;
+		} else
+			return -EINVAL;
+	}
+	return ieee80211_sta_req_scan(dev, ssid, ssid_len);
+}
+
+
+static int ieee80211_ioctl_giwscan(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_point *data, char *extra)
+{
+	int res;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	if (local->sta_scanning)
+		return -EAGAIN;
+	res = ieee80211_sta_scan_results(dev, extra, data->length);
+	if (res >= 0) {
+		data->length = res;
+		return 0;
+	}
+	data->length = 0;
+	return res;
+}
+
+
+static int ieee80211_ioctl_siwrts(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *rts, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (rts->disabled)
+		local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+	else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
+		return -EINVAL;
+	else
+		local->rts_threshold = rts->value;
+
+	/* If the wlan card performs RTS/CTS in hardware/firmware,
+	 * configure it here */
+
+	if (local->ops->set_rts_threshold)
+		local->ops->set_rts_threshold(local_to_hw(local),
+					     local->rts_threshold);
+
+	return 0;
+}
+
+static int ieee80211_ioctl_giwrts(struct net_device *dev,
+				  struct iw_request_info *info,
+				  struct iw_param *rts, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	rts->value = local->rts_threshold;
+	rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
+	rts->fixed = 1;
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_siwfrag(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_param *frag, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (frag->disabled)
+		local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+	else if (frag->value < 256 ||
+		 frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
+		return -EINVAL;
+	else {
+		/* Fragment length must be even, so strip LSB. */
+		local->fragmentation_threshold = frag->value & ~0x1;
+	}
+
+	/* If the wlan card performs fragmentation in hardware/firmware,
+	 * configure it here */
+
+	if (local->ops->set_frag_threshold)
+		local->ops->set_frag_threshold(
+			local_to_hw(local),
+			local->fragmentation_threshold);
+
+	return 0;
+}
+
+static int ieee80211_ioctl_giwfrag(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_param *frag, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	frag->value = local->fragmentation_threshold;
+	frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
+	frag->fixed = 1;
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_siwretry(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_param *retry, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (retry->disabled ||
+	    (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+		return -EINVAL;
+
+	if (retry->flags & IW_RETRY_MAX)
+		local->long_retry_limit = retry->value;
+	else if (retry->flags & IW_RETRY_MIN)
+		local->short_retry_limit = retry->value;
+	else {
+		local->long_retry_limit = retry->value;
+		local->short_retry_limit = retry->value;
+	}
+
+	if (local->ops->set_retry_limit) {
+		return local->ops->set_retry_limit(
+			local_to_hw(local),
+			local->short_retry_limit,
+			local->long_retry_limit);
+	}
+
+	return 0;
+}
+
+
+static int ieee80211_ioctl_giwretry(struct net_device *dev,
+				    struct iw_request_info *info,
+				    struct iw_param *retry, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	retry->disabled = 0;
+	if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
+		/* first return min value, iwconfig will ask max value
+		 * later if needed */
+		retry->flags |= IW_RETRY_LIMIT;
+		retry->value = local->short_retry_limit;
+		if (local->long_retry_limit != local->short_retry_limit)
+			retry->flags |= IW_RETRY_MIN;
+		return 0;
+	}
+	if (retry->flags & IW_RETRY_MAX) {
+		retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+		retry->value = local->long_retry_limit;
+	}
+
+	return 0;
+}
+
+static int ieee80211_ioctl_clear_keys(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_key_conf key;
+	int i;
+	u8 addr[ETH_ALEN];
+	struct ieee80211_key_conf *keyconf;
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
+
+	memset(addr, 0xff, ETH_ALEN);
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+			keyconf = NULL;
+			if (sdata->keys[i] &&
+			    !sdata->keys[i]->force_sw_encrypt &&
+			    local->ops->set_key &&
+			    (keyconf = ieee80211_key_data2conf(local,
+							       sdata->keys[i])))
+				local->ops->set_key(local_to_hw(local),
+						   DISABLE_KEY, addr,
+						   keyconf, 0);
+			kfree(keyconf);
+			ieee80211_key_free(sdata->keys[i]);
+			sdata->keys[i] = NULL;
+		}
+		sdata->default_key = NULL;
+	}
+	read_unlock(&local->sub_if_lock);
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		keyconf = NULL;
+		if (sta->key && !sta->key->force_sw_encrypt &&
+		    local->ops->set_key &&
+		    (keyconf = ieee80211_key_data2conf(local, sta->key)))
+			local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+					   sta->addr, keyconf, sta->aid);
+		kfree(keyconf);
+		ieee80211_key_free(sta->key);
+		sta->key = NULL;
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	memset(&key, 0, sizeof(key));
+	if (local->ops->set_key &&
+		    local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
+				       NULL, &key, 0))
+		printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
+		       dev->name);
+
+	return 0;
+}
+
+
+static int
+ieee80211_ioctl_force_unicast_rate(struct net_device *dev,
+				   struct ieee80211_sub_if_data *sdata,
+				   int rate)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	int i;
+
+	if (sdata->type != IEEE80211_IF_TYPE_AP)
+		return -ENOENT;
+
+	if (rate == 0) {
+		sdata->u.ap.force_unicast_rateidx = -1;
+		return 0;
+	}
+
+	mode = local->oper_hw_mode;
+	for (i = 0; i < mode->num_rates; i++) {
+		if (mode->rates[i].rate == rate) {
+			sdata->u.ap.force_unicast_rateidx = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+
+static int
+ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev,
+				  struct ieee80211_sub_if_data *sdata,
+				  int rate)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	int i;
+
+	if (sdata->type != IEEE80211_IF_TYPE_AP)
+		return -ENOENT;
+
+	if (rate == 0) {
+		sdata->u.ap.max_ratectrl_rateidx = -1;
+		return 0;
+	}
+
+	mode = local->oper_hw_mode;
+	for (i = 0; i < mode->num_rates; i++) {
+		if (mode->rates[i].rate == rate) {
+			sdata->u.ap.max_ratectrl_rateidx = i;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+
+static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
+					 struct ieee80211_key *key)
+{
+	struct ieee80211_key_conf *keyconf;
+	u8 addr[ETH_ALEN];
+
+	if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt ||
+	    (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
+		return;
+
+	memset(addr, 0xff, ETH_ALEN);
+	keyconf = ieee80211_key_data2conf(local, key);
+	if (keyconf && local->ops->set_key &&
+	    local->ops->set_key(local_to_hw(local),
+			       SET_KEY, addr, keyconf, 0) == 0) {
+		key->force_sw_encrypt =
+			!!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
+		key->hw_key_idx = keyconf->hw_key_idx;
+	}
+	kfree(keyconf);
+}
+
+
+static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local,
+					  struct ieee80211_key *key)
+{
+	struct ieee80211_key_conf *keyconf;
+	u8 addr[ETH_ALEN];
+
+	if (!key || key->alg != ALG_WEP || key->force_sw_encrypt ||
+	    (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
+		return;
+
+	memset(addr, 0xff, ETH_ALEN);
+	keyconf = ieee80211_key_data2conf(local, key);
+	if (keyconf && local->ops->set_key)
+		local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+				   addr, keyconf, 0);
+	kfree(keyconf);
+	key->force_sw_encrypt = 1;
+}
+
+
+static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local,
+					    int value)
+{
+	int i;
+	struct ieee80211_sub_if_data *sdata;
+
+	local->default_wep_only = value;
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list)
+		for (i = 0; i < NUM_DEFAULT_KEYS; i++)
+			if (value)
+				ieee80211_key_enable_hwaccel(local,
+							     sdata->keys[i]);
+			else
+				ieee80211_key_disable_hwaccel(local,
+							      sdata->keys[i]);
+	read_unlock(&local->sub_if_lock);
+
+	return 0;
+}
+
+
+void ieee80211_update_default_wep_only(struct ieee80211_local *local)
+{
+	int i = 0;
+	struct ieee80211_sub_if_data *sdata;
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+
+		if (sdata->dev == local->mdev)
+			continue;
+
+		/* If there is an AP interface then depend on userspace to
+		   set default_wep_only correctly. */
+		if (sdata->type == IEEE80211_IF_TYPE_AP) {
+			read_unlock(&local->sub_if_lock);
+			return;
+		}
+
+		i++;
+	}
+
+	read_unlock(&local->sub_if_lock);
+
+	if (i <= 1)
+		ieee80211_ioctl_default_wep_only(local, 1);
+	else
+		ieee80211_ioctl_default_wep_only(local, 0);
+}
+
+
+static int ieee80211_ioctl_prism2_param(struct net_device *dev,
+					struct iw_request_info *info,
+					void *wrqu, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	int *i = (int *) extra;
+	int param = *i;
+	int value = *(i + 1);
+	int ret = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	switch (param) {
+	case PRISM2_PARAM_IEEE_802_1X:
+		if (local->ops->set_ieee8021x)
+			ret = local->ops->set_ieee8021x(local_to_hw(local),
+							value);
+		if (ret)
+			printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
+			       "for low-level driver\n", dev->name, value);
+		else
+			sdata->ieee802_1x = value;
+		break;
+
+	case PRISM2_PARAM_ANTSEL_TX:
+		local->hw.conf.antenna_sel_tx = value;
+		if (ieee80211_hw_config(local))
+			ret = -EINVAL;
+		break;
+
+	case PRISM2_PARAM_ANTSEL_RX:
+		local->hw.conf.antenna_sel_rx = value;
+		if (ieee80211_hw_config(local))
+			ret = -EINVAL;
+		break;
+
+	case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
+		local->cts_protect_erp_frames = value;
+		break;
+
+	case PRISM2_PARAM_DROP_UNENCRYPTED:
+		sdata->drop_unencrypted = value;
+		break;
+
+	case PRISM2_PARAM_PREAMBLE:
+		local->short_preamble = value;
+		break;
+
+	case PRISM2_PARAM_STAT_TIME:
+		if (!local->stat_time && value) {
+			local->stat_timer.expires = jiffies + HZ * value / 100;
+			add_timer(&local->stat_timer);
+		} else if (local->stat_time && !value) {
+			del_timer_sync(&local->stat_timer);
+		}
+		local->stat_time = value;
+		break;
+	case PRISM2_PARAM_SHORT_SLOT_TIME:
+		if (value)
+			local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
+		else
+			local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
+		if (ieee80211_hw_config(local))
+			ret = -EINVAL;
+		break;
+
+	case PRISM2_PARAM_NEXT_MODE:
+		local->next_mode = value;
+		break;
+
+	case PRISM2_PARAM_CLEAR_KEYS:
+		ret = ieee80211_ioctl_clear_keys(dev);
+		break;
+
+	case PRISM2_PARAM_RADIO_ENABLED:
+		ret = ieee80211_ioctl_set_radio_enabled(dev, value);
+		break;
+
+	case PRISM2_PARAM_ANTENNA_MODE:
+		local->hw.conf.antenna_mode = value;
+		if (ieee80211_hw_config(local))
+			ret = -EINVAL;
+		break;
+
+	case PRISM2_PARAM_STA_ANTENNA_SEL:
+		local->sta_antenna_sel = value;
+		break;
+
+	case PRISM2_PARAM_FORCE_UNICAST_RATE:
+		ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value);
+		break;
+
+	case PRISM2_PARAM_MAX_RATECTRL_RATE:
+		ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value);
+		break;
+
+	case PRISM2_PARAM_RATE_CTRL_NUM_UP:
+		local->rate_ctrl_num_up = value;
+		break;
+
+	case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
+		local->rate_ctrl_num_down = value;
+		break;
+
+	case PRISM2_PARAM_TX_POWER_REDUCTION:
+		if (value < 0)
+			ret = -EINVAL;
+		else
+			local->hw.conf.tx_power_reduction = value;
+		break;
+
+	case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
+		local->key_tx_rx_threshold = value;
+		break;
+
+	case PRISM2_PARAM_DEFAULT_WEP_ONLY:
+		ret = ieee80211_ioctl_default_wep_only(local, value);
+		break;
+
+	case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
+		local->wifi_wme_noack_test = value;
+		break;
+
+	case PRISM2_PARAM_SCAN_FLAGS:
+		local->scan_flags = value;
+		break;
+
+	case PRISM2_PARAM_MIXED_CELL:
+		if (sdata->type != IEEE80211_IF_TYPE_STA &&
+		    sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			sdata->u.sta.mixed_cell = !!value;
+		break;
+
+	case PRISM2_PARAM_HW_MODES:
+		local->enabled_modes = value;
+		break;
+
+	case PRISM2_PARAM_CREATE_IBSS:
+		if (sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			sdata->u.sta.create_ibss = !!value;
+		break;
+	case PRISM2_PARAM_WMM_ENABLED:
+		if (sdata->type != IEEE80211_IF_TYPE_STA &&
+		    sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			sdata->u.sta.wmm_enabled = !!value;
+		break;
+	case PRISM2_PARAM_RADAR_DETECT:
+		local->hw.conf.radar_detect = value;
+		break;
+	case PRISM2_PARAM_SPECTRUM_MGMT:
+		local->hw.conf.spect_mgmt = value;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+
+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
+					    struct iw_request_info *info,
+					    void *wrqu, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	int *param = (int *) extra;
+	int ret = 0;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	switch (*param) {
+	case PRISM2_PARAM_IEEE_802_1X:
+		*param = sdata->ieee802_1x;
+		break;
+
+	case PRISM2_PARAM_ANTSEL_TX:
+		*param = local->hw.conf.antenna_sel_tx;
+		break;
+
+	case PRISM2_PARAM_ANTSEL_RX:
+		*param = local->hw.conf.antenna_sel_rx;
+		break;
+
+	case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
+		*param = local->cts_protect_erp_frames;
+		break;
+
+	case PRISM2_PARAM_DROP_UNENCRYPTED:
+		*param = sdata->drop_unencrypted;
+		break;
+
+	case PRISM2_PARAM_PREAMBLE:
+		*param = local->short_preamble;
+		break;
+
+	case PRISM2_PARAM_STAT_TIME:
+		*param = local->stat_time;
+		break;
+	case PRISM2_PARAM_SHORT_SLOT_TIME:
+		*param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
+		break;
+
+	case PRISM2_PARAM_NEXT_MODE:
+		*param = local->next_mode;
+		break;
+
+	case PRISM2_PARAM_ANTENNA_MODE:
+		*param = local->hw.conf.antenna_mode;
+		break;
+
+	case PRISM2_PARAM_STA_ANTENNA_SEL:
+		*param = local->sta_antenna_sel;
+		break;
+
+	case PRISM2_PARAM_RATE_CTRL_NUM_UP:
+		*param = local->rate_ctrl_num_up;
+		break;
+
+	case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
+		*param = local->rate_ctrl_num_down;
+		break;
+
+	case PRISM2_PARAM_TX_POWER_REDUCTION:
+		*param = local->hw.conf.tx_power_reduction;
+		break;
+
+	case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
+		*param = local->key_tx_rx_threshold;
+		break;
+
+	case PRISM2_PARAM_DEFAULT_WEP_ONLY:
+		*param = local->default_wep_only;
+		break;
+
+	case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
+		*param = local->wifi_wme_noack_test;
+		break;
+
+	case PRISM2_PARAM_SCAN_FLAGS:
+		*param = local->scan_flags;
+		break;
+
+	case PRISM2_PARAM_HW_MODES:
+		*param = local->enabled_modes;
+		break;
+
+	case PRISM2_PARAM_CREATE_IBSS:
+		if (sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			*param = !!sdata->u.sta.create_ibss;
+		break;
+
+	case PRISM2_PARAM_MIXED_CELL:
+		if (sdata->type != IEEE80211_IF_TYPE_STA &&
+		    sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			*param = !!sdata->u.sta.mixed_cell;
+		break;
+	case PRISM2_PARAM_WMM_ENABLED:
+		if (sdata->type != IEEE80211_IF_TYPE_STA &&
+		    sdata->type != IEEE80211_IF_TYPE_IBSS)
+			ret = -EINVAL;
+		else
+			*param = !!sdata->u.sta.wmm_enabled;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int ieee80211_ioctl_siwmlme(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_point *data, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct iw_mlme *mlme = (struct iw_mlme *) extra;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type != IEEE80211_IF_TYPE_STA &&
+	    sdata->type != IEEE80211_IF_TYPE_IBSS)
+		return -EINVAL;
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		/* TODO: mlme->addr.sa_data */
+		return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
+	case IW_MLME_DISASSOC:
+		/* TODO: mlme->addr.sa_data */
+		return ieee80211_sta_disassociate(dev, mlme->reason_code);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
+static int ieee80211_ioctl_siwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq, char *keybuf)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int idx, i, alg = ALG_WEP;
+	u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+	if (idx == 0) {
+		if (sdata->default_key)
+			for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+				if (sdata->default_key == sdata->keys[i]) {
+					idx = i;
+					break;
+				}
+			}
+	} else if (idx < 1 || idx > 4)
+		return -EINVAL;
+	else
+		idx--;
+
+	if (erq->flags & IW_ENCODE_DISABLED)
+		alg = ALG_NONE;
+	else if (erq->length == 0) {
+		/* No key data - just set the default TX key index */
+		if (sdata->default_key != sdata->keys[idx]) {
+			ieee80211_debugfs_key_remove_default(sdata);
+			sdata->default_key = sdata->keys[idx];
+			if (sdata->default_key)
+				ieee80211_debugfs_key_add_default(sdata);
+		}
+		return 0;
+	}
+
+	return ieee80211_set_encryption(
+		dev, bcaddr,
+		idx, alg,
+		!sdata->default_key,
+		keybuf, erq->length);
+}
+
+
+static int ieee80211_ioctl_giwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     struct iw_point *erq, char *key)
+{
+	struct ieee80211_sub_if_data *sdata;
+	int idx, i;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+	if (idx < 1 || idx > 4) {
+		idx = -1;
+		if (!sdata->default_key)
+			idx = 0;
+		else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+			if (sdata->default_key == sdata->keys[i]) {
+				idx = i;
+				break;
+			}
+		}
+		if (idx < 0)
+			return -EINVAL;
+	} else
+		idx--;
+
+	erq->flags = idx + 1;
+
+	if (!sdata->keys[idx]) {
+		erq->length = 0;
+		erq->flags |= IW_ENCODE_DISABLED;
+		return 0;
+	}
+
+	memcpy(key, sdata->keys[idx]->key,
+	       min((int)erq->length, sdata->keys[idx]->keylen));
+	erq->length = sdata->keys[idx]->keylen;
+	erq->flags |= IW_ENCODE_ENABLED;
+
+	return 0;
+}
+
+static int ieee80211_ioctl_siwauth(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_param *data, char *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int ret = 0;
+
+	switch (data->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_WPA_ENABLED:
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		break;
+	case IW_AUTH_KEY_MGMT:
+		if (sdata->type != IEEE80211_IF_TYPE_STA)
+			ret = -EINVAL;
+		else {
+			/*
+			 * TODO: sdata->u.sta.key_mgmt does not match with WE18
+			 * value completely; could consider modifying this to
+			 * be closer to WE18. For now, this value is not really
+			 * used for anything else than Privacy matching, so the
+			 * current code here should be more or less OK.
+			 */
+			if (data->value & IW_AUTH_KEY_MGMT_802_1X) {
+				sdata->u.sta.key_mgmt =
+					IEEE80211_KEY_MGMT_WPA_EAP;
+			} else if (data->value & IW_AUTH_KEY_MGMT_PSK) {
+				sdata->u.sta.key_mgmt =
+					IEEE80211_KEY_MGMT_WPA_PSK;
+			} else {
+				sdata->u.sta.key_mgmt =
+					IEEE80211_KEY_MGMT_NONE;
+			}
+		}
+		break;
+	case IW_AUTH_80211_AUTH_ALG:
+		if (sdata->type == IEEE80211_IF_TYPE_STA ||
+		    sdata->type == IEEE80211_IF_TYPE_IBSS)
+			sdata->u.sta.auth_algs = data->value;
+		else
+			ret = -EOPNOTSUPP;
+		break;
+	case IW_AUTH_PRIVACY_INVOKED:
+		if (local->ops->set_privacy_invoked)
+			ret = local->ops->set_privacy_invoked(
+					local_to_hw(local), data->value);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
+static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct iw_statistics *wstats = &local->wstats;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta = NULL;
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA ||
+	    sdata->type == IEEE80211_IF_TYPE_IBSS)
+		sta = sta_info_get(local, sdata->u.sta.bssid);
+	if (!sta) {
+		wstats->discard.fragment = 0;
+		wstats->discard.misc = 0;
+		wstats->qual.qual = 0;
+		wstats->qual.level = 0;
+		wstats->qual.noise = 0;
+		wstats->qual.updated = IW_QUAL_ALL_INVALID;
+	} else {
+		wstats->qual.level = sta->last_rssi;
+		wstats->qual.qual = sta->last_signal;
+		wstats->qual.noise = sta->last_noise;
+		wstats->qual.updated = local->wstats_flags;
+		sta_info_put(sta);
+	}
+	return wstats;
+}
+
+static int ieee80211_ioctl_giwauth(struct net_device *dev,
+				   struct iw_request_info *info,
+				   struct iw_param *data, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int ret = 0;
+
+	switch (data->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_80211_AUTH_ALG:
+		if (sdata->type == IEEE80211_IF_TYPE_STA ||
+		    sdata->type == IEEE80211_IF_TYPE_IBSS)
+			data->value = sdata->u.sta.auth_algs;
+		else
+			ret = -EOPNOTSUPP;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+
+static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
+					struct iw_request_info *info,
+					struct iw_point *erq, char *extra)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+	int alg, idx, i;
+
+	switch (ext->alg) {
+	case IW_ENCODE_ALG_NONE:
+		alg = ALG_NONE;
+		break;
+	case IW_ENCODE_ALG_WEP:
+		alg = ALG_WEP;
+		break;
+	case IW_ENCODE_ALG_TKIP:
+		alg = ALG_TKIP;
+		break;
+	case IW_ENCODE_ALG_CCMP:
+		alg = ALG_CCMP;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (erq->flags & IW_ENCODE_DISABLED)
+		alg = ALG_NONE;
+
+	idx = erq->flags & IW_ENCODE_INDEX;
+	if (idx < 1 || idx > 4) {
+		idx = -1;
+		if (!sdata->default_key)
+			idx = 0;
+		else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+			if (sdata->default_key == sdata->keys[i]) {
+				idx = i;
+				break;
+			}
+		}
+		if (idx < 0)
+			return -EINVAL;
+	} else
+		idx--;
+
+	return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+					ext->ext_flags &
+					IW_ENCODE_EXT_SET_TX_KEY,
+					ext->key, ext->key_len);
+}
+
+
+static const struct iw_priv_args ieee80211_ioctl_priv[] = {
+	{ PRISM2_IOCTL_PRISM2_PARAM,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
+	{ PRISM2_IOCTL_GET_PRISM2_PARAM,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
+};
+
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler ieee80211_handler[] =
+{
+	(iw_handler) NULL,				/* SIOCSIWCOMMIT */
+	(iw_handler) ieee80211_ioctl_giwname,		/* SIOCGIWNAME */
+	(iw_handler) NULL,				/* SIOCSIWNWID */
+	(iw_handler) NULL,				/* SIOCGIWNWID */
+	(iw_handler) ieee80211_ioctl_siwfreq,		/* SIOCSIWFREQ */
+	(iw_handler) ieee80211_ioctl_giwfreq,		/* SIOCGIWFREQ */
+	(iw_handler) ieee80211_ioctl_siwmode,		/* SIOCSIWMODE */
+	(iw_handler) ieee80211_ioctl_giwmode,		/* SIOCGIWMODE */
+	(iw_handler) NULL,				/* SIOCSIWSENS */
+	(iw_handler) NULL,				/* SIOCGIWSENS */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */
+	(iw_handler) ieee80211_ioctl_giwrange,		/* SIOCGIWRANGE */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWPRIV */
+	(iw_handler) NULL /* kernel code */,		/* SIOCGIWPRIV */
+	(iw_handler) NULL /* not used */,		/* SIOCSIWSTATS */
+	(iw_handler) NULL /* kernel code */,		/* SIOCGIWSTATS */
+	iw_handler_set_spy,				/* SIOCSIWSPY */
+	iw_handler_get_spy,				/* SIOCGIWSPY */
+	iw_handler_set_thrspy,				/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,				/* SIOCGIWTHRSPY */
+	(iw_handler) ieee80211_ioctl_siwap,		/* SIOCSIWAP */
+	(iw_handler) ieee80211_ioctl_giwap,		/* SIOCGIWAP */
+	(iw_handler) ieee80211_ioctl_siwmlme,		/* SIOCSIWMLME */
+	(iw_handler) NULL,				/* SIOCGIWAPLIST */
+	(iw_handler) ieee80211_ioctl_siwscan,		/* SIOCSIWSCAN */
+	(iw_handler) ieee80211_ioctl_giwscan,		/* SIOCGIWSCAN */
+	(iw_handler) ieee80211_ioctl_siwessid,		/* SIOCSIWESSID */
+	(iw_handler) ieee80211_ioctl_giwessid,		/* SIOCGIWESSID */
+	(iw_handler) NULL,				/* SIOCSIWNICKN */
+	(iw_handler) NULL,				/* SIOCGIWNICKN */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* SIOCSIWRATE */
+	(iw_handler) NULL,				/* SIOCGIWRATE */
+	(iw_handler) ieee80211_ioctl_siwrts,		/* SIOCSIWRTS */
+	(iw_handler) ieee80211_ioctl_giwrts,		/* SIOCGIWRTS */
+	(iw_handler) ieee80211_ioctl_siwfrag,		/* SIOCSIWFRAG */
+	(iw_handler) ieee80211_ioctl_giwfrag,		/* SIOCGIWFRAG */
+	(iw_handler) NULL,				/* SIOCSIWTXPOW */
+	(iw_handler) NULL,				/* SIOCGIWTXPOW */
+	(iw_handler) ieee80211_ioctl_siwretry,		/* SIOCSIWRETRY */
+	(iw_handler) ieee80211_ioctl_giwretry,		/* SIOCGIWRETRY */
+	(iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */
+	(iw_handler) ieee80211_ioctl_giwencode,		/* SIOCGIWENCODE */
+	(iw_handler) NULL,				/* SIOCSIWPOWER */
+	(iw_handler) NULL,				/* SIOCGIWPOWER */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) NULL,				/* -- hole -- */
+	(iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */
+	(iw_handler) NULL,				/* SIOCGIWGENIE */
+	(iw_handler) ieee80211_ioctl_siwauth,		/* SIOCSIWAUTH */
+	(iw_handler) ieee80211_ioctl_giwauth,		/* SIOCGIWAUTH */
+	(iw_handler) ieee80211_ioctl_siwencodeext,	/* SIOCSIWENCODEEXT */
+	(iw_handler) NULL,				/* SIOCGIWENCODEEXT */
+	(iw_handler) NULL,				/* SIOCSIWPMKSA */
+	(iw_handler) NULL,				/* -- hole -- */
+};
+
+static const iw_handler ieee80211_private_handler[] =
+{							/* SIOCIWFIRSTPRIV + */
+	(iw_handler) ieee80211_ioctl_prism2_param,	/* 0 */
+	(iw_handler) ieee80211_ioctl_get_prism2_param,	/* 1 */
+};
+
+const struct iw_handler_def ieee80211_iw_handler_def =
+{
+	.num_standard	= ARRAY_SIZE(ieee80211_handler),
+	.num_private	= ARRAY_SIZE(ieee80211_private_handler),
+	.num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
+	.standard	= (iw_handler *) ieee80211_handler,
+	.private	= (iw_handler *) ieee80211_private_handler,
+	.private_args	= (struct iw_priv_args *) ieee80211_ioctl_priv,
+	.get_wireless_stats = ieee80211_get_wireless_stats,
+};
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h
new file mode 100644
index 0000000..c333849
--- /dev/null
+++ b/net/mac80211/ieee80211_key.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape 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 IEEE80211_KEY_H
+#define IEEE80211_KEY_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/crypto.h>
+#include <net/mac80211.h>
+
+/* ALG_TKIP
+ * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block:
+ * Temporal Encryption Key (128 bits)
+ * Temporal Authenticator Tx MIC Key (64 bits)
+ * Temporal Authenticator Rx MIC Key (64 bits)
+ */
+
+#define WEP_IV_LEN 4
+#define WEP_ICV_LEN 4
+
+#define ALG_TKIP_KEY_LEN 32
+/* Starting offsets for each key */
+#define ALG_TKIP_TEMP_ENCR_KEY 0
+#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16
+#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24
+#define TKIP_IV_LEN 8
+#define TKIP_ICV_LEN 4
+
+#define ALG_CCMP_KEY_LEN 16
+#define CCMP_HDR_LEN 8
+#define CCMP_MIC_LEN 8
+#define CCMP_TK_LEN 16
+#define CCMP_PN_LEN 6
+
+#define NUM_RX_DATA_QUEUES 17
+
+struct ieee80211_key {
+	struct kref kref;
+
+	int hw_key_idx; /* filled and used by low-level driver */
+	ieee80211_key_alg alg;
+	union {
+		struct {
+			/* last used TSC */
+			u32 iv32;
+			u16 iv16;
+			u16 p1k[5];
+			int tx_initialized;
+
+			/* last received RSC */
+			u32 iv32_rx[NUM_RX_DATA_QUEUES];
+			u16 iv16_rx[NUM_RX_DATA_QUEUES];
+			u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
+			int rx_initialized[NUM_RX_DATA_QUEUES];
+		} tkip;
+		struct {
+			u8 tx_pn[6];
+			u8 rx_pn[NUM_RX_DATA_QUEUES][6];
+			struct crypto_cipher *tfm;
+			u32 replays; /* dot11RSNAStatsCCMPReplays */
+			/* scratch buffers for virt_to_page() (crypto API) */
+#ifndef AES_BLOCK_LEN
+#define AES_BLOCK_LEN 16
+#endif
+			u8 tx_crypto_buf[6 * AES_BLOCK_LEN];
+			u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
+		} ccmp;
+	} u;
+	int tx_rx_count; /* number of times this key has been used */
+	int keylen;
+
+	/* if the low level driver can provide hardware acceleration it should
+	 * clear this flag */
+	unsigned int force_sw_encrypt:1;
+	unsigned int default_tx_key:1; /* This key is the new default TX key
+					* (used only for broadcast keys). */
+	s8 keyidx; /* WEP key index */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct {
+		struct dentry *stalink;
+		struct dentry *dir;
+		struct dentry *keylen;
+		struct dentry *force_sw_encrypt;
+		struct dentry *keyidx;
+		struct dentry *hw_key_idx;
+		struct dentry *tx_rx_count;
+		struct dentry *algorithm;
+		struct dentry *tx_spec;
+		struct dentry *rx_spec;
+		struct dentry *replays;
+		struct dentry *key;
+	} debugfs;
+#endif
+
+	u8 key[0];
+};
+
+#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/ieee80211_led.c b/net/mac80211/ieee80211_led.c
new file mode 100644
index 0000000..719d75b
--- /dev/null
+++ b/net/mac80211/ieee80211_led.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006, Johannes Berg <johannes@sipsolutions.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.
+ */
+
+/* just for IFNAMSIZ */
+#include <linux/if.h>
+#include "ieee80211_led.h"
+
+void ieee80211_led_rx(struct ieee80211_local *local)
+{
+	if (unlikely(!local->rx_led))
+		return;
+	if (local->rx_led_counter++ % 2 == 0)
+		led_trigger_event(local->rx_led, LED_OFF);
+	else
+		led_trigger_event(local->rx_led, LED_FULL);
+}
+
+/* q is 1 if a packet was enqueued, 0 if it has been transmitted */
+void ieee80211_led_tx(struct ieee80211_local *local, int q)
+{
+	if (unlikely(!local->tx_led))
+		return;
+	/* not sure how this is supposed to work ... */
+	local->tx_led_counter += 2*q-1;
+	if (local->tx_led_counter % 2 == 0)
+		led_trigger_event(local->tx_led, LED_OFF);
+	else
+		led_trigger_event(local->tx_led, LED_FULL);
+}
+
+void ieee80211_led_init(struct ieee80211_local *local)
+{
+	local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+	if (!local->rx_led)
+		return;
+	snprintf(local->rx_led_name, sizeof(local->rx_led_name),
+		 "%srx", wiphy_name(local->hw.wiphy));
+	local->rx_led->name = local->rx_led_name;
+	if (led_trigger_register(local->rx_led)) {
+		kfree(local->rx_led);
+		local->rx_led = NULL;
+	}
+
+	local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+	if (!local->tx_led)
+		return;
+	snprintf(local->tx_led_name, sizeof(local->tx_led_name),
+		 "%stx", wiphy_name(local->hw.wiphy));
+	local->tx_led->name = local->tx_led_name;
+	if (led_trigger_register(local->tx_led)) {
+		kfree(local->tx_led);
+		local->tx_led = NULL;
+	}
+}
+
+void ieee80211_led_exit(struct ieee80211_local *local)
+{
+	if (local->tx_led) {
+		led_trigger_unregister(local->tx_led);
+		kfree(local->tx_led);
+	}
+	if (local->rx_led) {
+		led_trigger_unregister(local->rx_led);
+		kfree(local->rx_led);
+	}
+}
+
+char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (local->tx_led)
+		return local->tx_led_name;
+	return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
+
+char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (local->rx_led)
+		return local->rx_led_name;
+	return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
diff --git a/net/mac80211/ieee80211_led.h b/net/mac80211/ieee80211_led.h
new file mode 100644
index 0000000..5c8ab82
--- /dev/null
+++ b/net/mac80211/ieee80211_led.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006, Johannes Berg <johannes@sipsolutions.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.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include "ieee80211_i.h"
+
+#ifdef CONFIG_MAC80211_LEDS
+extern void ieee80211_led_rx(struct ieee80211_local *local);
+extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
+extern void ieee80211_led_init(struct ieee80211_local *local);
+extern void ieee80211_led_exit(struct ieee80211_local *local);
+#else
+static inline void ieee80211_led_rx(struct ieee80211_local *local)
+{
+}
+static inline void ieee80211_led_tx(struct ieee80211_local *local, int q)
+{
+}
+static inline void ieee80211_led_init(struct ieee80211_local *local)
+{
+}
+static inline void ieee80211_led_exit(struct ieee80211_local *local)
+{
+}
+#endif
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c
new file mode 100644
index 0000000..16e8508
--- /dev/null
+++ b/net/mac80211/ieee80211_rate.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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 "ieee80211_rate.h"
+#include "ieee80211_i.h"
+
+struct rate_control_alg {
+	struct list_head list;
+	struct rate_control_ops *ops;
+};
+
+static LIST_HEAD(rate_ctrl_algs);
+static DEFINE_MUTEX(rate_ctrl_mutex);
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops)
+{
+	struct rate_control_alg *alg;
+
+	alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+	if (alg == NULL) {
+		return -ENOMEM;
+	}
+	memset(alg, 0, sizeof(*alg));
+	alg->ops = ops;
+
+	mutex_lock(&rate_ctrl_mutex);
+	list_add_tail(&alg->list, &rate_ctrl_algs);
+	mutex_unlock(&rate_ctrl_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ieee80211_rate_control_register);
+
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
+{
+	struct rate_control_alg *alg;
+
+	mutex_lock(&rate_ctrl_mutex);
+	list_for_each_entry(alg, &rate_ctrl_algs, list) {
+		if (alg->ops == ops) {
+			list_del(&alg->list);
+			break;
+		}
+	}
+	mutex_unlock(&rate_ctrl_mutex);
+	kfree(alg);
+}
+EXPORT_SYMBOL(ieee80211_rate_control_unregister);
+
+static struct rate_control_ops *
+ieee80211_try_rate_control_ops_get(const char *name)
+{
+	struct rate_control_alg *alg;
+	struct rate_control_ops *ops = NULL;
+
+	mutex_lock(&rate_ctrl_mutex);
+	list_for_each_entry(alg, &rate_ctrl_algs, list) {
+		if (!name || !strcmp(alg->ops->name, name))
+			if (try_module_get(alg->ops->module)) {
+				ops = alg->ops;
+				break;
+			}
+	}
+	mutex_unlock(&rate_ctrl_mutex);
+	return ops;
+}
+
+/* Get the rate control algorithm. If `name' is NULL, get the first
+ * available algorithm. */
+static struct rate_control_ops *
+ieee80211_rate_control_ops_get(const char *name)
+{
+	struct rate_control_ops *ops;
+
+	ops = ieee80211_try_rate_control_ops_get(name);
+	if (!ops) {
+		request_module("rc80211_%s", name ? name : "default");
+		ops = ieee80211_try_rate_control_ops_get(name);
+	}
+	return ops;
+}
+
+static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
+{
+	module_put(ops->module);
+}
+
+struct rate_control_ref *rate_control_alloc(const char *name,
+					    struct ieee80211_local *local)
+{
+	struct rate_control_ref *ref;
+
+	ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
+	if (!ref)
+		goto fail_ref;
+	kref_init(&ref->kref);
+	ref->ops = ieee80211_rate_control_ops_get(name);
+	if (!ref->ops)
+		goto fail_ops;
+	ref->priv = ref->ops->alloc(local);
+	if (!ref->priv)
+		goto fail_priv;
+	return ref;
+
+fail_priv:
+	ieee80211_rate_control_ops_put(ref->ops);
+fail_ops:
+	kfree(ref);
+fail_ref:
+	return NULL;
+}
+
+static void rate_control_release(struct kref *kref)
+{
+	struct rate_control_ref *ctrl_ref;
+
+	ctrl_ref = container_of(kref, struct rate_control_ref, kref);
+	ctrl_ref->ops->free(ctrl_ref->priv);
+	ieee80211_rate_control_ops_put(ctrl_ref->ops);
+	kfree(ctrl_ref);
+}
+
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
+{
+	kref_get(&ref->kref);
+	return ref;
+}
+
+void rate_control_put(struct rate_control_ref *ref)
+{
+	kref_put(&ref->kref, rate_control_release);
+}
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h
new file mode 100644
index 0000000..f021a02
--- /dev/null
+++ b/net/mac80211/ieee80211_rate.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can 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 IEEE80211_RATE_H
+#define IEEE80211_RATE_H
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP   15
+
+
+struct rate_control_extra {
+	/* values from rate_control_get_rate() to the caller: */
+	struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
+				       * probing */
+	struct ieee80211_rate *nonerp;
+
+	/* parameters from the caller to rate_control_get_rate(): */
+	struct ieee80211_hw_mode *mode;
+	int mgmt_data; /* this is data frame that is used for management
+			* (e.g., IEEE 802.1X EAPOL) */
+	u16 ethertype;
+};
+
+
+struct rate_control_ops {
+	struct module *module;
+	const char *name;
+	void (*tx_status)(void *priv, struct net_device *dev,
+			  struct sk_buff *skb,
+			  struct ieee80211_tx_status *status);
+	struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
+					   struct sk_buff *skb,
+					   struct rate_control_extra *extra);
+	void (*rate_init)(void *priv, void *priv_sta,
+			  struct ieee80211_local *local, struct sta_info *sta);
+	void (*clear)(void *priv);
+
+	void *(*alloc)(struct ieee80211_local *local);
+	void (*free)(void *priv);
+	void *(*alloc_sta)(void *priv, gfp_t gfp);
+	void (*free_sta)(void *priv, void *priv_sta);
+
+	int (*add_attrs)(void *priv, struct kobject *kobj);
+	void (*remove_attrs)(void *priv, struct kobject *kobj);
+	void (*add_sta_debugfs)(void *priv, void *priv_sta,
+				struct dentry *dir);
+	void (*remove_sta_debugfs)(void *priv, void *priv_sta);
+};
+
+struct rate_control_ref {
+	struct rate_control_ops *ops;
+	void *priv;
+	struct kref kref;
+};
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops);
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
+
+/* Get a reference to the rate control algorithm. If `name' is NULL, get the
+ * first available algorithm. */
+struct rate_control_ref *rate_control_alloc(const char *name,
+					    struct ieee80211_local *local);
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
+void rate_control_put(struct rate_control_ref *ref);
+
+static inline void rate_control_tx_status(struct ieee80211_local *local,
+					  struct net_device *dev,
+					  struct sk_buff *skb,
+					  struct ieee80211_tx_status *status)
+{
+	struct rate_control_ref *ref = local->rate_ctrl;
+	ref->ops->tx_status(ref->priv, dev, skb, status);
+}
+
+
+static inline struct ieee80211_rate *
+rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
+		      struct sk_buff *skb, struct rate_control_extra *extra)
+{
+	struct rate_control_ref *ref = local->rate_ctrl;
+	return ref->ops->get_rate(ref->priv, dev, skb, extra);
+}
+
+
+static inline void rate_control_rate_init(struct sta_info *sta,
+					  struct ieee80211_local *local)
+{
+	struct rate_control_ref *ref = sta->rate_ctrl;
+	ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta);
+}
+
+
+static inline void rate_control_clear(struct ieee80211_local *local)
+{
+	struct rate_control_ref *ref = local->rate_ctrl;
+	ref->ops->clear(ref->priv);
+}
+
+static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
+					   gfp_t gfp)
+{
+	return ref->ops->alloc_sta(ref->priv, gfp);
+}
+
+static inline void rate_control_free_sta(struct rate_control_ref *ref,
+					 void *priv)
+{
+	ref->ops->free_sta(ref->priv, priv);
+}
+
+static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct rate_control_ref *ref = sta->rate_ctrl;
+	if (sta->debugfs.dir && ref->ops->add_sta_debugfs)
+		ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv,
+					  sta->debugfs.dir);
+#endif
+}
+
+static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct rate_control_ref *ref = sta->rate_ctrl;
+	if (ref->ops->remove_sta_debugfs)
+		ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv);
+#endif
+}
+
+#endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
new file mode 100644
index 0000000..822917d
--- /dev/null
+++ b/net/mac80211/ieee80211_sta.c
@@ -0,0 +1,3060 @@
+/*
+ * BSS client mode implementation
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.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.
+ */
+
+/* TODO:
+ * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
+ * order BSS list by RSSI(?) ("quality of AP")
+ * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
+ *    SSID)
+ */
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/random.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <asm/types.h>
+#include <asm/delay.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "hostapd_ioctl.h"
+
+#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
+#define IEEE80211_AUTH_MAX_TRIES 3
+#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
+#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
+#define IEEE80211_PROBE_INTERVAL (60 * HZ)
+#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
+#define IEEE80211_SCAN_INTERVAL (2 * HZ)
+#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)
+
+#define IEEE80211_PROBE_DELAY (HZ / 33)
+#define IEEE80211_CHANNEL_TIME (HZ / 33)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
+#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
+#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+
+#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+
+#define ERP_INFO_USE_PROTECTION BIT(1)
+
+static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
+				     u8 *ssid, size_t ssid_len);
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+static void ieee80211_rx_bss_put(struct net_device *dev,
+				 struct ieee80211_sta_bss *bss);
+static int ieee80211_sta_find_ibss(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta);
+static int ieee80211_sta_wep_configured(struct net_device *dev);
+static int ieee80211_sta_start_scan(struct net_device *dev,
+				    u8 *ssid, size_t ssid_len);
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta);
+
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	u8 *ssid;
+	u8 ssid_len;
+	u8 *supp_rates;
+	u8 supp_rates_len;
+	u8 *fh_params;
+	u8 fh_params_len;
+	u8 *ds_params;
+	u8 ds_params_len;
+	u8 *cf_params;
+	u8 cf_params_len;
+	u8 *tim;
+	u8 tim_len;
+	u8 *ibss_params;
+	u8 ibss_params_len;
+	u8 *challenge;
+	u8 challenge_len;
+	u8 *wpa;
+	u8 wpa_len;
+	u8 *rsn;
+	u8 rsn_len;
+	u8 *erp_info;
+	u8 erp_info_len;
+	u8 *ext_supp_rates;
+	u8 ext_supp_rates_len;
+	u8 *wmm_info;
+	u8 wmm_info_len;
+	u8 *wmm_param;
+	u8 wmm_param_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+
+static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
+				       struct ieee802_11_elems *elems)
+{
+	size_t left = len;
+	u8 *pos = start;
+	int unknown = 0;
+
+	memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left) {
+#if 0
+			if (net_ratelimit())
+				printk(KERN_DEBUG "IEEE 802.11 element parse "
+				       "failed (id=%d elen=%d left=%d)\n",
+				       id, elen, left);
+#endif
+			return ParseFailed;
+		}
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			elems->fh_params = pos;
+			elems->fh_params_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+			elems->cf_params = pos;
+			elems->cf_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_WPA:
+			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+			    pos[2] == 0xf2) {
+				/* Microsoft OUI (00:50:F2) */
+				if (pos[3] == 1) {
+					/* OUI Type 1 - WPA IE */
+					elems->wpa = pos;
+					elems->wpa_len = elen;
+				} else if (elen >= 5 && pos[3] == 2) {
+					if (pos[4] == 0) {
+						elems->wmm_info = pos;
+						elems->wmm_info_len = elen;
+					} else if (pos[4] == 1) {
+						elems->wmm_param = pos;
+						elems->wmm_param_len = elen;
+					}
+				}
+			}
+			break;
+		case WLAN_EID_RSN:
+			elems->rsn = pos;
+			elems->rsn_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		default:
+#if 0
+			printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
+				      "unknown element (id=%d elen=%d)\n",
+				      id, elen);
+#endif
+			unknown++;
+			break;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+
+	/* Do not trigger error if left == 1 as Apple Airport base stations
+	 * send AssocResps that are one spurious byte too long. */
+
+	return unknown ? ParseUnknown : ParseOK;
+}
+
+
+
+
+static int ecw2cw(int ecw)
+{
+	int cw = 1;
+	while (ecw > 0) {
+		cw <<= 1;
+		ecw--;
+	}
+	return cw - 1;
+}
+
+
+static void ieee80211_sta_wmm_params(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta,
+				     u8 *wmm_param, size_t wmm_param_len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_tx_queue_params params;
+	size_t left;
+	int count;
+	u8 *pos;
+
+	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
+		return;
+	count = wmm_param[6] & 0x0f;
+	if (count == ifsta->wmm_last_param_set)
+		return;
+	ifsta->wmm_last_param_set = count;
+
+	pos = wmm_param + 8;
+	left = wmm_param_len - 8;
+
+	memset(&params, 0, sizeof(params));
+
+	if (!local->ops->conf_tx)
+		return;
+
+	local->wmm_acm = 0;
+	for (; left >= 4; left -= 4, pos += 4) {
+		int aci = (pos[0] >> 5) & 0x03;
+		int acm = (pos[0] >> 4) & 0x01;
+		int queue;
+
+		switch (aci) {
+		case 1:
+			queue = IEEE80211_TX_QUEUE_DATA3;
+			if (acm) {
+				local->wmm_acm |= BIT(0) | BIT(3);
+			}
+			break;
+		case 2:
+			queue = IEEE80211_TX_QUEUE_DATA1;
+			if (acm) {
+				local->wmm_acm |= BIT(4) | BIT(5);
+			}
+			break;
+		case 3:
+			queue = IEEE80211_TX_QUEUE_DATA0;
+			if (acm) {
+				local->wmm_acm |= BIT(6) | BIT(7);
+			}
+			break;
+		case 0:
+		default:
+			queue = IEEE80211_TX_QUEUE_DATA2;
+			if (acm) {
+				local->wmm_acm |= BIT(1) | BIT(2);
+			}
+			break;
+		}
+
+		params.aifs = pos[0] & 0x0f;
+		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+		params.cw_min = ecw2cw(pos[1] & 0x0f);
+		/* TXOP is in units of 32 usec; burst_time in 0.1 ms */
+		params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
+		       "cWmin=%d cWmax=%d burst=%d\n",
+		       dev->name, queue, aci, acm, params.aifs, params.cw_min,
+		       params.cw_max, params.burst_time);
+		/* TODO: handle ACM (block TX, fallback to next lowest allowed
+		 * AC for now) */
+		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
+			printk(KERN_DEBUG "%s: failed to set TX queue "
+			       "parameters for queue %d\n", dev->name, queue);
+		}
+	}
+}
+
+
+static void ieee80211_sta_send_associnfo(struct net_device *dev,
+					 struct ieee80211_if_sta *ifsta)
+{
+	char *buf;
+	size_t len;
+	int i;
+	union iwreq_data wrqu;
+
+	if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+		return;
+
+	buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
+				ifsta->assocresp_ies_len), GFP_ATOMIC);
+	if (!buf)
+		return;
+
+	len = sprintf(buf, "ASSOCINFO(");
+	if (ifsta->assocreq_ies) {
+		len += sprintf(buf + len, "ReqIEs=");
+		for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocreq_ies[i]);
+		}
+	}
+	if (ifsta->assocresp_ies) {
+		if (ifsta->assocreq_ies)
+			len += sprintf(buf + len, " ");
+		len += sprintf(buf + len, "RespIEs=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
+	}
+	len += sprintf(buf + len, ")");
+
+	if (len > IW_CUSTOM_MAX) {
+		len = sprintf(buf, "ASSOCRESPIE=");
+		for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+			len += sprintf(buf + len, "%02x",
+				       ifsta->assocresp_ies[i]);
+		}
+	}
+
+	memset(&wrqu, 0, sizeof(wrqu));
+	wrqu.data.length = len;
+	wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+
+	kfree(buf);
+}
+
+
+static void ieee80211_set_associated(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta, int assoc)
+{
+	union iwreq_data wrqu;
+
+	if (ifsta->associated == assoc)
+		return;
+
+	ifsta->associated = assoc;
+
+	if (assoc) {
+		struct ieee80211_sub_if_data *sdata;
+		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+		if (sdata->type != IEEE80211_IF_TYPE_STA)
+			return;
+		netif_carrier_on(dev);
+		ifsta->prev_bssid_set = 1;
+		memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
+		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
+		ieee80211_sta_send_associnfo(dev, ifsta);
+	} else {
+		netif_carrier_off(dev);
+		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+	}
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+	ifsta->last_probe = jiffies;
+}
+
+static void ieee80211_set_disassoc(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta, int deauth)
+{
+	if (deauth)
+		ifsta->auth_tries = 0;
+	ifsta->assoc_tries = 0;
+	ieee80211_set_associated(dev, ifsta, 0);
+}
+
+static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+			     int encrypt)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_tx_packet_data *pkt_data;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	skb->dev = sdata->local->mdev;
+	skb_set_mac_header(skb, 0);
+	skb_set_network_header(skb, 0);
+	skb_set_transport_header(skb, 0);
+
+	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+	memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+	pkt_data->ifindex = sdata->dev->ifindex;
+	pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+	pkt_data->do_not_encrypt = !encrypt;
+
+	dev_queue_xmit(skb);
+}
+
+
+static void ieee80211_send_auth(struct net_device *dev,
+				struct ieee80211_if_sta *ifsta,
+				int transaction, u8 *extra, size_t extra_len,
+				int encrypt)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+			    sizeof(*mgmt) + 6 + extra_len);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
+		       "frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
+	memset(mgmt, 0, 24 + 6);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_AUTH);
+	if (encrypt)
+		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
+	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
+	ifsta->auth_transaction = transaction + 1;
+	mgmt->u.auth.status_code = cpu_to_le16(0);
+	if (extra)
+		memcpy(skb_put(skb, extra_len), extra, extra_len);
+
+	ieee80211_sta_tx(dev, skb, encrypt);
+}
+
+
+static void ieee80211_authenticate(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta)
+{
+	ifsta->auth_tries++;
+	if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT
+		       " timed out\n",
+		       dev->name, MAC_ARG(ifsta->bssid));
+		ifsta->state = IEEE80211_DISABLED;
+		return;
+	}
+
+	ifsta->state = IEEE80211_AUTHENTICATE;
+	printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n",
+	       dev->name, MAC_ARG(ifsta->bssid));
+
+	ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
+
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+}
+
+
+static void ieee80211_send_assoc(struct net_device *dev,
+				 struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos, *ies;
+	int i, len;
+	u16 capab;
+	struct ieee80211_sta_bss *bss;
+	int wmm = 0;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+			    sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
+			    ifsta->ssid_len);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
+		       "frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mode = local->oper_hw_mode;
+	capab = ifsta->capab;
+	if (mode->mode == MODE_IEEE80211G) {
+		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
+			WLAN_CAPABILITY_SHORT_PREAMBLE;
+	}
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+	if (bss) {
+		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+			capab |= WLAN_CAPABILITY_PRIVACY;
+		if (bss->wmm_ie) {
+			wmm = 1;
+		}
+		ieee80211_rx_bss_put(dev, bss);
+	}
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+	if (ifsta->prev_bssid_set) {
+		skb_put(skb, 10);
+		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						   IEEE80211_STYPE_REASSOC_REQ);
+		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
+		mgmt->u.reassoc_req.listen_interval = cpu_to_le16(1);
+		memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
+		       ETH_ALEN);
+	} else {
+		skb_put(skb, 4);
+		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						   IEEE80211_STYPE_ASSOC_REQ);
+		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
+		mgmt->u.assoc_req.listen_interval = cpu_to_le16(1);
+	}
+
+	/* SSID */
+	ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ifsta->ssid_len;
+	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+	len = mode->num_rates;
+	if (len > 8)
+		len = 8;
+	pos = skb_put(skb, len + 2);
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = len;
+	for (i = 0; i < len; i++) {
+		int rate = mode->rates[i].rate;
+		if (mode->mode == MODE_ATHEROS_TURBO)
+			rate /= 2;
+		*pos++ = (u8) (rate / 5);
+	}
+
+	if (mode->num_rates > len) {
+		pos = skb_put(skb, mode->num_rates - len + 2);
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = mode->num_rates - len;
+		for (i = len; i < mode->num_rates; i++) {
+			int rate = mode->rates[i].rate;
+			if (mode->mode == MODE_ATHEROS_TURBO)
+				rate /= 2;
+			*pos++ = (u8) (rate / 5);
+		}
+	}
+
+	if (ifsta->extra_ie) {
+		pos = skb_put(skb, ifsta->extra_ie_len);
+		memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
+	}
+
+	if (wmm && ifsta->wmm_enabled) {
+		pos = skb_put(skb, 9);
+		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+		*pos++ = 7; /* len */
+		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+		*pos++ = 0x50;
+		*pos++ = 0xf2;
+		*pos++ = 2; /* WME */
+		*pos++ = 0; /* WME info */
+		*pos++ = 1; /* WME ver */
+		*pos++ = 0;
+	}
+
+	kfree(ifsta->assocreq_ies);
+	ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
+	ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_ATOMIC);
+	if (ifsta->assocreq_ies)
+		memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static void ieee80211_send_deauth(struct net_device *dev,
+				  struct ieee80211_if_sta *ifsta, u16 reason)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for deauth "
+		       "frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_DEAUTH);
+	skb_put(skb, 2);
+	mgmt->u.deauth.reason_code = cpu_to_le16(reason);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static void ieee80211_send_disassoc(struct net_device *dev,
+				    struct ieee80211_if_sta *ifsta, u16 reason)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc "
+		       "frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_DISASSOC);
+	skb_put(skb, 2);
+	mgmt->u.disassoc.reason_code = cpu_to_le16(reason);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static int ieee80211_privacy_mismatch(struct net_device *dev,
+				      struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_sta_bss *bss;
+	int res = 0;
+
+	if (!ifsta || ifsta->mixed_cell ||
+	    ifsta->key_mgmt != IEEE80211_KEY_MGMT_NONE)
+		return 0;
+
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+	if (!bss)
+		return 0;
+
+	if (ieee80211_sta_wep_configured(dev) !=
+	    !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
+		res = 1;
+
+	ieee80211_rx_bss_put(dev, bss);
+
+	return res;
+}
+
+
+static void ieee80211_associate(struct net_device *dev,
+				struct ieee80211_if_sta *ifsta)
+{
+	ifsta->assoc_tries++;
+	if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+		printk(KERN_DEBUG "%s: association with AP " MAC_FMT
+		       " timed out\n",
+		       dev->name, MAC_ARG(ifsta->bssid));
+		ifsta->state = IEEE80211_DISABLED;
+		return;
+	}
+
+	ifsta->state = IEEE80211_ASSOCIATE;
+	printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n",
+	       dev->name, MAC_ARG(ifsta->bssid));
+	if (ieee80211_privacy_mismatch(dev, ifsta)) {
+		printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
+		       "mixed-cell disabled - abort association\n", dev->name);
+		ifsta->state = IEEE80211_DISABLED;
+		return;
+	}
+
+	ieee80211_send_assoc(dev, ifsta);
+
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+}
+
+
+static void ieee80211_associated(struct net_device *dev,
+				 struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	int disassoc;
+
+	/* TODO: start monitoring current AP signal quality and number of
+	 * missed beacons. Scan other channels every now and then and search
+	 * for better APs. */
+	/* TODO: remove expired BSSes */
+
+	ifsta->state = IEEE80211_ASSOCIATED;
+
+	sta = sta_info_get(local, ifsta->bssid);
+	if (!sta) {
+		printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n",
+		       dev->name, MAC_ARG(ifsta->bssid));
+		disassoc = 1;
+	} else {
+		disassoc = 0;
+		if (time_after(jiffies,
+			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
+			if (ifsta->probereq_poll) {
+				printk(KERN_DEBUG "%s: No ProbeResp from "
+				       "current AP " MAC_FMT " - assume out of "
+				       "range\n",
+				       dev->name, MAC_ARG(ifsta->bssid));
+				disassoc = 1;
+				sta_info_free(sta, 0);
+				ifsta->probereq_poll = 0;
+			} else {
+				ieee80211_send_probe_req(dev, ifsta->bssid,
+							 local->scan_ssid,
+							 local->scan_ssid_len);
+				ifsta->probereq_poll = 1;
+			}
+		} else {
+			ifsta->probereq_poll = 0;
+			if (time_after(jiffies, ifsta->last_probe +
+				       IEEE80211_PROBE_INTERVAL)) {
+				ifsta->last_probe = jiffies;
+				ieee80211_send_probe_req(dev, ifsta->bssid,
+							 ifsta->ssid,
+							 ifsta->ssid_len);
+			}
+		}
+		sta_info_put(sta);
+	}
+	if (disassoc) {
+		union iwreq_data wrqu;
+		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+	} else {
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_MONITORING_INTERVAL);
+	}
+}
+
+
+static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
+				     u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos, *supp_rates, *esupp_rates = NULL;
+	int i;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+		       "request\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_PROBE_REQ);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	if (dst) {
+		memcpy(mgmt->da, dst, ETH_ALEN);
+		memcpy(mgmt->bssid, dst, ETH_ALEN);
+	} else {
+		memset(mgmt->da, 0xff, ETH_ALEN);
+		memset(mgmt->bssid, 0xff, ETH_ALEN);
+	}
+	pos = skb_put(skb, 2 + ssid_len);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid_len;
+	memcpy(pos, ssid, ssid_len);
+
+	supp_rates = skb_put(skb, 2);
+	supp_rates[0] = WLAN_EID_SUPP_RATES;
+	supp_rates[1] = 0;
+	mode = local->oper_hw_mode;
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+		if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
+			continue;
+		if (esupp_rates) {
+			pos = skb_put(skb, 1);
+			esupp_rates[1]++;
+		} else if (supp_rates[1] == 8) {
+			esupp_rates = skb_put(skb, 3);
+			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
+			esupp_rates[1] = 1;
+			pos = &esupp_rates[2];
+		} else {
+			pos = skb_put(skb, 1);
+			supp_rates[1]++;
+		}
+		if (mode->mode == MODE_ATHEROS_TURBO)
+			*pos = rate->rate / 10;
+		else
+			*pos = rate->rate / 5;
+	}
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static int ieee80211_sta_wep_configured(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (!sdata || !sdata->default_key ||
+	    sdata->default_key->alg != ALG_WEP)
+		return 0;
+	return 1;
+}
+
+
+static void ieee80211_auth_completed(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	printk(KERN_DEBUG "%s: authenticated\n", dev->name);
+	ifsta->authenticated = 1;
+	ieee80211_associate(dev, ifsta);
+}
+
+
+static void ieee80211_auth_challenge(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	u8 *pos;
+	struct ieee802_11_elems elems;
+
+	printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
+	pos = mgmt->u.auth.variable;
+	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+	    == ParseFailed) {
+		printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
+		       dev->name);
+		return;
+	}
+	if (!elems.challenge) {
+		printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
+		       "frame\n", dev->name);
+		return;
+	}
+	ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
+			    elems.challenge_len + 2, 1);
+}
+
+
+static void ieee80211_rx_mgmt_auth(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta,
+				   struct ieee80211_mgmt *mgmt,
+				   size_t len)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	u16 auth_alg, auth_transaction, status_code;
+
+	if (ifsta->state != IEEE80211_AUTHENTICATE &&
+	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
+		printk(KERN_DEBUG "%s: authentication frame received from "
+		       MAC_FMT ", but not in authenticate state - ignored\n",
+		       dev->name, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (len < 24 + 6) {
+		printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
+		       "received from " MAC_FMT " - ignored\n",
+		       dev->name, len, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+	    memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+		printk(KERN_DEBUG "%s: authentication frame received from "
+		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+		       MAC_ARG(mgmt->bssid));
+		return;
+	}
+
+	if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
+		printk(KERN_DEBUG "%s: authentication frame received from "
+		       "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+		       MAC_ARG(mgmt->bssid));
+		return;
+	}
+
+	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+	status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+	printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d "
+	       "transaction=%d status=%d)\n",
+	       dev->name, MAC_ARG(mgmt->sa), auth_alg,
+	       auth_transaction, status_code);
+
+	if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		/* IEEE 802.11 standard does not require authentication in IBSS
+		 * networks and most implementations do not seem to use it.
+		 * However, try to reply to authentication attempts if someone
+		 * has actually implemented this.
+		 * TODO: Could implement shared key authentication. */
+		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
+			printk(KERN_DEBUG "%s: unexpected IBSS authentication "
+			       "frame (alg=%d transaction=%d)\n",
+			       dev->name, auth_alg, auth_transaction);
+			return;
+		}
+		ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
+	}
+
+	if (auth_alg != ifsta->auth_alg ||
+	    auth_transaction != ifsta->auth_transaction) {
+		printk(KERN_DEBUG "%s: unexpected authentication frame "
+		       "(alg=%d transaction=%d)\n",
+		       dev->name, auth_alg, auth_transaction);
+		return;
+	}
+
+	if (status_code != WLAN_STATUS_SUCCESS) {
+		printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d "
+		       "code=%d)\n", dev->name, ifsta->auth_alg, status_code);
+		if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
+			u8 algs[3];
+			const int num_algs = ARRAY_SIZE(algs);
+			int i, pos;
+			algs[0] = algs[1] = algs[2] = 0xff;
+			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+				algs[0] = WLAN_AUTH_OPEN;
+			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+				algs[1] = WLAN_AUTH_SHARED_KEY;
+			if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+				algs[2] = WLAN_AUTH_LEAP;
+			if (ifsta->auth_alg == WLAN_AUTH_OPEN)
+				pos = 0;
+			else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)
+				pos = 1;
+			else
+				pos = 2;
+			for (i = 0; i < num_algs; i++) {
+				pos++;
+				if (pos >= num_algs)
+					pos = 0;
+				if (algs[pos] == ifsta->auth_alg ||
+				    algs[pos] == 0xff)
+					continue;
+				if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
+				    !ieee80211_sta_wep_configured(dev))
+					continue;
+				ifsta->auth_alg = algs[pos];
+				printk(KERN_DEBUG "%s: set auth_alg=%d for "
+				       "next try\n",
+				       dev->name, ifsta->auth_alg);
+				break;
+			}
+		}
+		return;
+	}
+
+	switch (ifsta->auth_alg) {
+	case WLAN_AUTH_OPEN:
+	case WLAN_AUTH_LEAP:
+		ieee80211_auth_completed(dev, ifsta);
+		break;
+	case WLAN_AUTH_SHARED_KEY:
+		if (ifsta->auth_transaction == 4)
+			ieee80211_auth_completed(dev, ifsta);
+		else
+			ieee80211_auth_challenge(dev, ifsta, mgmt, len);
+		break;
+	}
+}
+
+
+static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len)
+{
+	u16 reason_code;
+
+	if (len < 24 + 2) {
+		printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
+		       "received from " MAC_FMT " - ignored\n",
+		       dev->name, len, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+		printk(KERN_DEBUG "%s: deauthentication frame received from "
+		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+		       MAC_ARG(mgmt->bssid));
+		return;
+	}
+
+	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
+	printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT
+	       " (reason=%d)\n",
+	       dev->name, MAC_ARG(mgmt->sa), reason_code);
+
+	if (ifsta->authenticated) {
+		printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
+	}
+
+	if (ifsta->state == IEEE80211_AUTHENTICATE ||
+	    ifsta->state == IEEE80211_ASSOCIATE ||
+	    ifsta->state == IEEE80211_ASSOCIATED) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_RETRY_AUTH_INTERVAL);
+	}
+
+	ieee80211_set_disassoc(dev, ifsta, 1);
+	ifsta->authenticated = 0;
+}
+
+
+static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
+				       struct ieee80211_if_sta *ifsta,
+				       struct ieee80211_mgmt *mgmt,
+				       size_t len)
+{
+	u16 reason_code;
+
+	if (len < 24 + 2) {
+		printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
+		       "received from " MAC_FMT " - ignored\n",
+		       dev->name, len, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+		printk(KERN_DEBUG "%s: disassociation frame received from "
+		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+		       MAC_ARG(mgmt->bssid));
+		return;
+	}
+
+	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+	printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT
+	       " (reason=%d)\n",
+	       dev->name, MAC_ARG(mgmt->sa), reason_code);
+
+	if (ifsta->associated)
+		printk(KERN_DEBUG "%s: disassociated\n", dev->name);
+
+	if (ifsta->state == IEEE80211_ASSOCIATED) {
+		ifsta->state = IEEE80211_ASSOCIATE;
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_RETRY_AUTH_INTERVAL);
+	}
+
+	ieee80211_set_disassoc(dev, ifsta, 0);
+}
+
+
+static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
+					 struct ieee80211_if_sta *ifsta,
+					 struct ieee80211_mgmt *mgmt,
+					 size_t len,
+					 int reassoc)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw_mode *mode;
+	struct sta_info *sta;
+	u32 rates;
+	u16 capab_info, status_code, aid;
+	struct ieee802_11_elems elems;
+	u8 *pos;
+	int i, j;
+
+	/* AssocResp and ReassocResp have identical structure, so process both
+	 * of them in this function. */
+
+	if (ifsta->state != IEEE80211_ASSOCIATE) {
+		printk(KERN_DEBUG "%s: association frame received from "
+		       MAC_FMT ", but not in associate state - ignored\n",
+		       dev->name, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (len < 24 + 6) {
+		printk(KERN_DEBUG "%s: too short (%zd) association frame "
+		       "received from " MAC_FMT " - ignored\n",
+		       dev->name, len, MAC_ARG(mgmt->sa));
+		return;
+	}
+
+	if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+		printk(KERN_DEBUG "%s: association frame received from "
+		       "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+		       "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+		       MAC_ARG(mgmt->bssid));
+		return;
+	}
+
+	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+		printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
+		       "set\n", dev->name, aid);
+	aid &= ~(BIT(15) | BIT(14));
+
+	printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x "
+	       "status=%d aid=%d)\n",
+	       dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa),
+	       capab_info, status_code, aid);
+
+	if (status_code != WLAN_STATUS_SUCCESS) {
+		printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
+		       dev->name, status_code);
+		return;
+	}
+
+	pos = mgmt->u.assoc_resp.variable;
+	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+	    == ParseFailed) {
+		printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
+		       dev->name);
+		return;
+	}
+
+	if (!elems.supp_rates) {
+		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
+		       dev->name);
+		return;
+	}
+
+	printk(KERN_DEBUG "%s: associated\n", dev->name);
+	ifsta->aid = aid;
+	ifsta->ap_capab = capab_info;
+
+	kfree(ifsta->assocresp_ies);
+	ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);
+	ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_ATOMIC);
+	if (ifsta->assocresp_ies)
+		memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
+
+	ieee80211_set_associated(dev, ifsta, 1);
+
+	/* Add STA entry for the AP */
+	sta = sta_info_get(local, ifsta->bssid);
+	if (!sta) {
+		struct ieee80211_sta_bss *bss;
+		sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC);
+		if (!sta) {
+			printk(KERN_DEBUG "%s: failed to add STA entry for the"
+			       " AP\n", dev->name);
+			return;
+		}
+		bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+		if (bss) {
+			sta->last_rssi = bss->rssi;
+			sta->last_signal = bss->signal;
+			sta->last_noise = bss->noise;
+			ieee80211_rx_bss_put(dev, bss);
+		}
+	}
+
+	sta->dev = dev;
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+	sta->assoc_ap = 1;
+
+	rates = 0;
+	mode = local->oper_hw_mode;
+	for (i = 0; i < elems.supp_rates_len; i++) {
+		int rate = (elems.supp_rates[i] & 0x7f) * 5;
+		if (mode->mode == MODE_ATHEROS_TURBO)
+			rate *= 2;
+		for (j = 0; j < mode->num_rates; j++)
+			if (mode->rates[j].rate == rate)
+				rates |= BIT(j);
+	}
+	for (i = 0; i < elems.ext_supp_rates_len; i++) {
+		int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
+		if (mode->mode == MODE_ATHEROS_TURBO)
+			rate *= 2;
+		for (j = 0; j < mode->num_rates; j++)
+			if (mode->rates[j].rate == rate)
+				rates |= BIT(j);
+	}
+	sta->supp_rates = rates;
+
+	rate_control_rate_init(sta, local);
+
+	if (elems.wmm_param && ifsta->wmm_enabled) {
+		sta->flags |= WLAN_STA_WME;
+		ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+					 elems.wmm_param_len);
+	}
+
+
+	sta_info_put(sta);
+
+	ieee80211_associated(dev, ifsta);
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
+					struct ieee80211_sta_bss *bss)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)];
+	local->sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
+					struct ieee80211_sta_bss *bss)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *b, *prev = NULL;
+	b = local->sta_bss_hash[STA_HASH(bss->bssid)];
+	while (b) {
+		if (b == bss) {
+			if (!prev)
+				local->sta_bss_hash[STA_HASH(bss->bssid)] =
+					bss->hnext;
+			else
+				prev->hnext = bss->hnext;
+			break;
+		}
+		prev = b;
+		b = b->hnext;
+	}
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+
+	bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+	if (!bss)
+		return NULL;
+	memset(bss, 0, sizeof(*bss));
+	atomic_inc(&bss->users);
+	atomic_inc(&bss->users);
+	memcpy(bss->bssid, bssid, ETH_ALEN);
+
+	spin_lock_bh(&local->sta_bss_lock);
+	/* TODO: order by RSSI? */
+	list_add_tail(&bss->list, &local->sta_bss_list);
+	__ieee80211_rx_bss_hash_add(dev, bss);
+	spin_unlock_bh(&local->sta_bss_lock);
+	return bss;
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+
+	spin_lock_bh(&local->sta_bss_lock);
+	bss = local->sta_bss_hash[STA_HASH(bssid)];
+	while (bss) {
+		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+			atomic_inc(&bss->users);
+			break;
+		}
+		bss = bss->hnext;
+	}
+	spin_unlock_bh(&local->sta_bss_lock);
+	return bss;
+}
+
+
+static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
+{
+	kfree(bss->wpa_ie);
+	kfree(bss->rsn_ie);
+	kfree(bss->wmm_ie);
+	kfree(bss);
+}
+
+
+static void ieee80211_rx_bss_put(struct net_device *dev,
+				 struct ieee80211_sta_bss *bss)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	if (!atomic_dec_and_test(&bss->users))
+		return;
+
+	spin_lock_bh(&local->sta_bss_lock);
+	__ieee80211_rx_bss_hash_del(dev, bss);
+	list_del(&bss->list);
+	spin_unlock_bh(&local->sta_bss_lock);
+	ieee80211_rx_bss_free(bss);
+}
+
+
+void ieee80211_rx_bss_list_init(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	spin_lock_init(&local->sta_bss_lock);
+	INIT_LIST_HEAD(&local->sta_bss_list);
+}
+
+
+void ieee80211_rx_bss_list_deinit(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss, *tmp;
+
+	list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
+		ieee80211_rx_bss_put(dev, bss);
+}
+
+
+static void ieee80211_rx_bss_info(struct net_device *dev,
+				  struct ieee80211_mgmt *mgmt,
+				  size_t len,
+				  struct ieee80211_rx_status *rx_status,
+				  int beacon)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee802_11_elems elems;
+	size_t baselen;
+	int channel, invalid = 0, clen;
+	struct ieee80211_sta_bss *bss;
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	u64 timestamp;
+
+	if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
+		return; /* ignore ProbeResp to foreign address */
+
+#if 0
+	printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n",
+	       dev->name, beacon ? "Beacon" : "Probe Response",
+	       MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da));
+#endif
+
+	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+	if (baselen > len)
+		return;
+
+	timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+
+	if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon &&
+	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+		static unsigned long last_tsf_debug = 0;
+		u64 tsf;
+		if (local->ops->get_tsf)
+			tsf = local->ops->get_tsf(local_to_hw(local));
+		else
+			tsf = -1LLU;
+		if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
+			printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID="
+			       MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld "
+			       "@%lu\n",
+			       MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid),
+			       (unsigned long long)tsf,
+			       (unsigned long long)timestamp,
+			       (unsigned long long)(tsf - timestamp),
+			       jiffies);
+			last_tsf_debug = jiffies;
+		}
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	}
+
+	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+				   &elems) == ParseFailed)
+		invalid = 1;
+
+	if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
+	    (sta = sta_info_get(local, mgmt->sa))) {
+		struct ieee80211_hw_mode *mode;
+		struct ieee80211_rate *rates;
+		size_t num_rates;
+		u32 supp_rates, prev_rates;
+		int i, j;
+
+		mode = local->sta_scanning ?
+		       local->scan_hw_mode : local->oper_hw_mode;
+		rates = mode->rates;
+		num_rates = mode->num_rates;
+
+		supp_rates = 0;
+		for (i = 0; i < elems.supp_rates_len +
+			     elems.ext_supp_rates_len; i++) {
+			u8 rate = 0;
+			int own_rate;
+			if (i < elems.supp_rates_len)
+				rate = elems.supp_rates[i];
+			else if (elems.ext_supp_rates)
+				rate = elems.ext_supp_rates
+					[i - elems.supp_rates_len];
+			own_rate = 5 * (rate & 0x7f);
+			if (mode->mode == MODE_ATHEROS_TURBO)
+				own_rate *= 2;
+			for (j = 0; j < num_rates; j++)
+				if (rates[j].rate == own_rate)
+					supp_rates |= BIT(j);
+		}
+
+		prev_rates = sta->supp_rates;
+		sta->supp_rates &= supp_rates;
+		if (sta->supp_rates == 0) {
+			/* No matching rates - this should not really happen.
+			 * Make sure that at least one rate is marked
+			 * supported to avoid issues with TX rate ctrl. */
+			sta->supp_rates = sdata->u.sta.supp_rates_bits;
+		}
+		if (sta->supp_rates != prev_rates) {
+			printk(KERN_DEBUG "%s: updated supp_rates set for "
+			       MAC_FMT " based on beacon info (0x%x & 0x%x -> "
+			       "0x%x)\n",
+			       dev->name, MAC_ARG(sta->addr), prev_rates,
+			       supp_rates, sta->supp_rates);
+		}
+		sta_info_put(sta);
+	}
+
+	if (!elems.ssid)
+		return;
+
+	if (elems.ds_params && elems.ds_params_len == 1)
+		channel = elems.ds_params[0];
+	else
+		channel = rx_status->channel;
+
+	bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
+	if (!bss) {
+		bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
+		if (!bss)
+			return;
+	} else {
+#if 0
+		/* TODO: order by RSSI? */
+		spin_lock_bh(&local->sta_bss_lock);
+		list_move_tail(&bss->list, &local->sta_bss_list);
+		spin_unlock_bh(&local->sta_bss_lock);
+#endif
+	}
+
+	if (bss->probe_resp && beacon) {
+		/* Do not allow beacon to override data from Probe Response. */
+		ieee80211_rx_bss_put(dev, bss);
+		return;
+	}
+
+	bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
+	bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
+	if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
+		memcpy(bss->ssid, elems.ssid, elems.ssid_len);
+		bss->ssid_len = elems.ssid_len;
+	}
+
+	bss->supp_rates_len = 0;
+	if (elems.supp_rates) {
+		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+		if (clen > elems.supp_rates_len)
+			clen = elems.supp_rates_len;
+		memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
+		       clen);
+		bss->supp_rates_len += clen;
+	}
+	if (elems.ext_supp_rates) {
+		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+		if (clen > elems.ext_supp_rates_len)
+			clen = elems.ext_supp_rates_len;
+		memcpy(&bss->supp_rates[bss->supp_rates_len],
+		       elems.ext_supp_rates, clen);
+		bss->supp_rates_len += clen;
+	}
+
+	if (elems.wpa &&
+	    (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
+	     memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+		kfree(bss->wpa_ie);
+		bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
+		if (bss->wpa_ie) {
+			memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
+			bss->wpa_ie_len = elems.wpa_len + 2;
+		} else
+			bss->wpa_ie_len = 0;
+	} else if (!elems.wpa && bss->wpa_ie) {
+		kfree(bss->wpa_ie);
+		bss->wpa_ie = NULL;
+		bss->wpa_ie_len = 0;
+	}
+
+	if (elems.rsn &&
+	    (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
+	     memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+		kfree(bss->rsn_ie);
+		bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
+		if (bss->rsn_ie) {
+			memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
+			bss->rsn_ie_len = elems.rsn_len + 2;
+		} else
+			bss->rsn_ie_len = 0;
+	} else if (!elems.rsn && bss->rsn_ie) {
+		kfree(bss->rsn_ie);
+		bss->rsn_ie = NULL;
+		bss->rsn_ie_len = 0;
+	}
+
+	if (elems.wmm_param &&
+	    (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
+	     memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+		kfree(bss->wmm_ie);
+		bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
+		if (bss->wmm_ie) {
+			memcpy(bss->wmm_ie, elems.wmm_param - 2,
+			       elems.wmm_param_len + 2);
+			bss->wmm_ie_len = elems.wmm_param_len + 2;
+		} else
+			bss->wmm_ie_len = 0;
+	} else if (!elems.wmm_param && bss->wmm_ie) {
+		kfree(bss->wmm_ie);
+		bss->wmm_ie = NULL;
+		bss->wmm_ie_len = 0;
+	}
+
+
+	bss->hw_mode = rx_status->phymode;
+	bss->channel = channel;
+	bss->freq = rx_status->freq;
+	if (channel != rx_status->channel &&
+	    (bss->hw_mode == MODE_IEEE80211G ||
+	     bss->hw_mode == MODE_IEEE80211B) &&
+	    channel >= 1 && channel <= 14) {
+		static const int freq_list[] = {
+			2412, 2417, 2422, 2427, 2432, 2437, 2442,
+			2447, 2452, 2457, 2462, 2467, 2472, 2484
+		};
+		/* IEEE 802.11g/b mode can receive packets from neighboring
+		 * channels, so map the channel into frequency. */
+		bss->freq = freq_list[channel - 1];
+	}
+	bss->timestamp = timestamp;
+	bss->last_update = jiffies;
+	bss->rssi = rx_status->ssi;
+	bss->signal = rx_status->signal;
+	bss->noise = rx_status->noise;
+	if (!beacon)
+		bss->probe_resp++;
+	ieee80211_rx_bss_put(dev, bss);
+}
+
+
+static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev,
+					 struct ieee80211_mgmt *mgmt,
+					 size_t len,
+					 struct ieee80211_rx_status *rx_status)
+{
+	ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);
+}
+
+
+static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
+				     struct ieee80211_mgmt *mgmt,
+				     size_t len,
+				     struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_sta *ifsta;
+	int use_protection;
+	size_t baselen;
+	struct ieee802_11_elems elems;
+
+	ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type != IEEE80211_IF_TYPE_STA)
+		return;
+	ifsta = &sdata->u.sta;
+
+	if (!ifsta->associated ||
+	    memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+		return;
+
+	/* Process beacon from the current BSS */
+	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+	if (baselen > len)
+		return;
+
+	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+				   &elems) == ParseFailed)
+		return;
+
+	use_protection = 0;
+	if (elems.erp_info && elems.erp_info_len >= 1) {
+		use_protection =
+			(elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
+	}
+
+	if (use_protection != !!ifsta->use_protection) {
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+			       MAC_FMT ")\n",
+			       dev->name,
+			       use_protection ? "enabled" : "disabled",
+			       MAC_ARG(ifsta->bssid));
+		}
+		ifsta->use_protection = use_protection ? 1 : 0;
+		local->cts_protect_erp_frames = use_protection;
+	}
+
+	if (elems.wmm_param && ifsta->wmm_enabled) {
+		ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+					 elems.wmm_param_len);
+	}
+}
+
+
+static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
+					struct ieee80211_if_sta *ifsta,
+					struct ieee80211_mgmt *mgmt,
+					size_t len,
+					struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int tx_last_beacon;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *resp;
+	u8 *pos, *end;
+
+	if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
+	    ifsta->state != IEEE80211_IBSS_JOINED ||
+	    len < 24 + 2 || !ifsta->probe_resp)
+		return;
+
+	if (local->ops->tx_last_beacon)
+		tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
+	else
+		tx_last_beacon = 1;
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID="
+	       MAC_FMT " (tx_last_beacon=%d)\n",
+	       dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da),
+	       MAC_ARG(mgmt->bssid), tx_last_beacon);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+	if (!tx_last_beacon)
+		return;
+
+	if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 &&
+	    memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+		return;
+
+	end = ((u8 *) mgmt) + len;
+	pos = mgmt->u.probe_req.variable;
+	if (pos[0] != WLAN_EID_SSID ||
+	    pos + 2 + pos[1] > end) {
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
+			       "from " MAC_FMT "\n",
+			       dev->name, MAC_ARG(mgmt->sa));
+		}
+		return;
+	}
+	if (pos[1] != 0 &&
+	    (pos[1] != ifsta->ssid_len ||
+	     memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) {
+		/* Ignore ProbeReq for foreign SSID */
+		return;
+	}
+
+	/* Reply with ProbeResp */
+	skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	resp = (struct ieee80211_mgmt *) skb->data;
+	memcpy(resp->da, mgmt->sa, ETH_ALEN);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n",
+	       dev->name, MAC_ARG(resp->da));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
+			   struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_sta *ifsta;
+	struct ieee80211_mgmt *mgmt;
+	u16 fc;
+
+	if (skb->len < 24)
+		goto fail;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ifsta = &sdata->u.sta;
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	switch (fc & IEEE80211_FCTL_STYPE) {
+	case IEEE80211_STYPE_PROBE_REQ:
+	case IEEE80211_STYPE_PROBE_RESP:
+	case IEEE80211_STYPE_BEACON:
+		memcpy(skb->cb, rx_status, sizeof(*rx_status));
+	case IEEE80211_STYPE_AUTH:
+	case IEEE80211_STYPE_ASSOC_RESP:
+	case IEEE80211_STYPE_REASSOC_RESP:
+	case IEEE80211_STYPE_DEAUTH:
+	case IEEE80211_STYPE_DISASSOC:
+		skb_queue_tail(&ifsta->skb_queue, skb);
+		queue_work(local->hw.workqueue, &ifsta->work);
+		return;
+	default:
+		printk(KERN_DEBUG "%s: received unknown management frame - "
+		       "stype=%d\n", dev->name,
+		       (fc & IEEE80211_FCTL_STYPE) >> 4);
+		break;
+	}
+
+ fail:
+	kfree_skb(skb);
+}
+
+
+static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
+					 struct sk_buff *skb)
+{
+	struct ieee80211_rx_status *rx_status;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_sta *ifsta;
+	struct ieee80211_mgmt *mgmt;
+	u16 fc;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ifsta = &sdata->u.sta;
+
+	rx_status = (struct ieee80211_rx_status *) skb->cb;
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	switch (fc & IEEE80211_FCTL_STYPE) {
+	case IEEE80211_STYPE_PROBE_REQ:
+		ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len,
+					    rx_status);
+		break;
+	case IEEE80211_STYPE_PROBE_RESP:
+		ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+		break;
+	case IEEE80211_STYPE_BEACON:
+		ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+		break;
+	case IEEE80211_STYPE_AUTH:
+		ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
+		break;
+	case IEEE80211_STYPE_ASSOC_RESP:
+		ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0);
+		break;
+	case IEEE80211_STYPE_REASSOC_RESP:
+		ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1);
+		break;
+	case IEEE80211_STYPE_DEAUTH:
+		ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
+		break;
+	case IEEE80211_STYPE_DISASSOC:
+		ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
+		break;
+	}
+
+	kfree_skb(skb);
+}
+
+
+void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+			   struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_mgmt *mgmt;
+	u16 fc;
+
+	if (skb->len < 24) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	mgmt = (struct ieee80211_mgmt *) skb->data;
+	fc = le16_to_cpu(mgmt->frame_control);
+
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
+			ieee80211_rx_mgmt_probe_resp(dev, mgmt,
+						     skb->len, rx_status);
+		} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
+			ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
+						 rx_status);
+		}
+	}
+
+	dev_kfree_skb(skb);
+}
+
+
+static int ieee80211_sta_active_ibss(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int active = 0;
+	struct sta_info *sta;
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		if (sta->dev == dev &&
+		    time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+			       jiffies)) {
+			active++;
+			break;
+		}
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	return active;
+}
+
+
+static void ieee80211_sta_expire(struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta, *tmp;
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+		if (time_after(jiffies, sta->last_rx +
+			       IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+			printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
+			       "\n", dev->name, MAC_ARG(sta->addr));
+			sta_info_free(sta, 1);
+		}
+	spin_unlock_bh(&local->sta_lock);
+}
+
+
+static void ieee80211_sta_merge_ibss(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+	ieee80211_sta_expire(dev);
+	if (ieee80211_sta_active_ibss(dev))
+		return;
+
+	printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
+	       "IBSS networks with same SSID (merge)\n", dev->name);
+	ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len);
+}
+
+
+void ieee80211_sta_timer(unsigned long data)
+{
+	struct ieee80211_sub_if_data *sdata =
+		(struct ieee80211_sub_if_data *) data;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+
+	set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+	queue_work(local->hw.workqueue, &ifsta->work);
+}
+
+
+void ieee80211_sta_work(struct work_struct *work)
+{
+	struct ieee80211_sub_if_data *sdata =
+		container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+	struct net_device *dev = sdata->dev;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_if_sta *ifsta;
+	struct sk_buff *skb;
+
+	if (!netif_running(dev))
+		return;
+
+	if (local->sta_scanning)
+		return;
+
+	if (sdata->type != IEEE80211_IF_TYPE_STA &&
+	    sdata->type != IEEE80211_IF_TYPE_IBSS) {
+		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
+		       "(type=%d)\n", dev->name, sdata->type);
+		return;
+	}
+	ifsta = &sdata->u.sta;
+
+	while ((skb = skb_dequeue(&ifsta->skb_queue)))
+		ieee80211_sta_rx_queued_mgmt(dev, skb);
+
+	if (ifsta->state != IEEE80211_AUTHENTICATE &&
+	    ifsta->state != IEEE80211_ASSOCIATE &&
+	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
+		ieee80211_sta_start_scan(dev, NULL, 0);
+		return;
+	}
+
+	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
+		if (ieee80211_sta_config_auth(dev, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+		return;
+
+	switch (ifsta->state) {
+	case IEEE80211_DISABLED:
+		break;
+	case IEEE80211_AUTHENTICATE:
+		ieee80211_authenticate(dev, ifsta);
+		break;
+	case IEEE80211_ASSOCIATE:
+		ieee80211_associate(dev, ifsta);
+		break;
+	case IEEE80211_ASSOCIATED:
+		ieee80211_associated(dev, ifsta);
+		break;
+	case IEEE80211_IBSS_SEARCH:
+		ieee80211_sta_find_ibss(dev, ifsta);
+		break;
+	case IEEE80211_IBSS_JOINED:
+		ieee80211_sta_merge_ibss(dev, ifsta);
+		break;
+	default:
+		printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
+		       ifsta->state);
+		break;
+	}
+
+	if (ieee80211_privacy_mismatch(dev, ifsta)) {
+		printk(KERN_DEBUG "%s: privacy configuration mismatch and "
+		       "mixed-cell disabled - disassociate\n", dev->name);
+
+		ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED);
+		ieee80211_set_disassoc(dev, ifsta, 0);
+	}
+}
+
+
+static void ieee80211_sta_reset_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (local->ops->reset_tsf) {
+		/* Reset own TSF to allow time synchronization work. */
+		local->ops->reset_tsf(local_to_hw(local));
+	}
+
+	ifsta->wmm_last_param_set = -1; /* allow any WMM update */
+
+
+	if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+		ifsta->auth_alg = WLAN_AUTH_OPEN;
+	else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+		ifsta->auth_alg = WLAN_AUTH_SHARED_KEY;
+	else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+		ifsta->auth_alg = WLAN_AUTH_LEAP;
+	else
+		ifsta->auth_alg = WLAN_AUTH_OPEN;
+	printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
+	       ifsta->auth_alg);
+	ifsta->auth_transaction = -1;
+	ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0;
+	netif_carrier_off(dev);
+}
+
+
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type != IEEE80211_IF_TYPE_STA)
+		return;
+
+	if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+	    (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		queue_work(local->hw.workqueue, &ifsta->work);
+	}
+}
+
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+				    const char *ssid, int ssid_len)
+{
+	int tmp, hidden_ssid;
+
+	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+		return 1;
+
+	if (ifsta->auto_bssid_sel)
+		return 0;
+
+	hidden_ssid = 1;
+	tmp = ssid_len;
+	while (tmp--) {
+		if (ssid[tmp] != '\0') {
+			hidden_ssid = 0;
+			break;
+		}
+	}
+
+	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+		return 1;
+
+	if (ssid_len == 1 && ssid[0] == ' ')
+		return 1;
+
+	return 0;
+}
+
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sta_bss *bss, *selected = NULL;
+	int top_rssi = 0, freq;
+
+	rtnl_lock();
+
+	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+	    !ifsta->auto_ssid_sel) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		rtnl_unlock();
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	}
+
+	spin_lock_bh(&local->sta_bss_lock);
+	freq = local->oper_channel->freq;
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (!(bss->capability & WLAN_CAPABILITY_ESS))
+			continue;
+
+		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+		    !!sdata->default_key)
+			continue;
+
+		if (!ifsta->auto_channel_sel && bss->freq != freq)
+			continue;
+
+		if (!ifsta->auto_bssid_sel &&
+		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+			continue;
+
+		if (!ifsta->auto_ssid_sel &&
+		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+			continue;
+
+		if (!selected || top_rssi < bss->rssi) {
+			selected = bss;
+			top_rssi = bss->rssi;
+		}
+	}
+	if (selected)
+		atomic_inc(&selected->users);
+	spin_unlock_bh(&local->sta_bss_lock);
+
+	if (selected) {
+		ieee80211_set_channel(local, -1, selected->freq);
+		if (!ifsta->ssid_set)
+			ieee80211_sta_set_ssid(dev, selected->ssid,
+					       selected->ssid_len);
+		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_rx_bss_put(dev, selected);
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		rtnl_unlock();
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	} else {
+		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+			ieee80211_sta_start_scan(dev, NULL, 0);
+			ifsta->state = IEEE80211_AUTHENTICATE;
+			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		} else
+			ifsta->state = IEEE80211_DISABLED;
+	}
+	rtnl_unlock();
+	return -1;
+}
+
+static int ieee80211_sta_join_ibss(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta,
+				   struct ieee80211_sta_bss *bss)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int res, rates, i, j;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_tx_control control;
+	struct ieee80211_rate *rate;
+	struct ieee80211_hw_mode *mode;
+	struct rate_control_extra extra;
+	u8 *pos;
+	struct ieee80211_sub_if_data *sdata;
+
+	/* Remove possible STA entries from other IBSS networks. */
+	sta_info_flush(local, NULL);
+
+	if (local->ops->reset_tsf) {
+		/* Reset own TSF to allow time synchronization work. */
+		local->ops->reset_tsf(local_to_hw(local));
+	}
+	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+	res = ieee80211_if_config(dev);
+	if (res)
+		return res;
+
+	local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	sdata->drop_unencrypted = bss->capability &
+		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+	res = ieee80211_set_channel(local, -1, bss->freq);
+
+	if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
+		printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
+		       "(%d MHz)\n", dev->name, local->hw.conf.channel,
+		       local->hw.conf.freq);
+		return -1;
+	}
+
+	/* Set beacon template based on scan results */
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	do {
+		if (!skb)
+			break;
+
+		skb_reserve(skb, local->hw.extra_tx_headroom);
+
+		mgmt = (struct ieee80211_mgmt *)
+			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						   IEEE80211_STYPE_BEACON);
+		memset(mgmt->da, 0xff, ETH_ALEN);
+		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+		mgmt->u.beacon.beacon_int =
+			cpu_to_le16(local->hw.conf.beacon_int);
+		mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+
+		pos = skb_put(skb, 2 + ifsta->ssid_len);
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = ifsta->ssid_len;
+		memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+		rates = bss->supp_rates_len;
+		if (rates > 8)
+			rates = 8;
+		pos = skb_put(skb, 2 + rates);
+		*pos++ = WLAN_EID_SUPP_RATES;
+		*pos++ = rates;
+		memcpy(pos, bss->supp_rates, rates);
+
+		pos = skb_put(skb, 2 + 1);
+		*pos++ = WLAN_EID_DS_PARAMS;
+		*pos++ = 1;
+		*pos++ = bss->channel;
+
+		pos = skb_put(skb, 2 + 2);
+		*pos++ = WLAN_EID_IBSS_PARAMS;
+		*pos++ = 2;
+		/* FIX: set ATIM window based on scan results */
+		*pos++ = 0;
+		*pos++ = 0;
+
+		if (bss->supp_rates_len > 8) {
+			rates = bss->supp_rates_len - 8;
+			pos = skb_put(skb, 2 + rates);
+			*pos++ = WLAN_EID_EXT_SUPP_RATES;
+			*pos++ = rates;
+			memcpy(pos, &bss->supp_rates[8], rates);
+		}
+
+		memset(&control, 0, sizeof(control));
+		memset(&extra, 0, sizeof(extra));
+		extra.mode = local->oper_hw_mode;
+		rate = rate_control_get_rate(local, dev, skb, &extra);
+		if (!rate) {
+			printk(KERN_DEBUG "%s: Failed to determine TX rate "
+			       "for IBSS beacon\n", dev->name);
+			break;
+		}
+		control.tx_rate = (local->short_preamble &&
+				   (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+			rate->val2 : rate->val;
+		control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+		control.power_level = local->hw.conf.power_level;
+		control.flags |= IEEE80211_TXCTL_NO_ACK;
+		control.retry_limit = 1;
+
+		ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
+		if (ifsta->probe_resp) {
+			mgmt = (struct ieee80211_mgmt *)
+				ifsta->probe_resp->data;
+			mgmt->frame_control =
+				IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					     IEEE80211_STYPE_PROBE_RESP);
+		} else {
+			printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
+			       "template for IBSS\n", dev->name);
+		}
+
+		if (local->ops->beacon_update &&
+		    local->ops->beacon_update(local_to_hw(local),
+					     skb, &control) == 0) {
+			printk(KERN_DEBUG "%s: Configured IBSS beacon "
+			       "template based on scan results\n", dev->name);
+			skb = NULL;
+		}
+
+		rates = 0;
+		mode = local->oper_hw_mode;
+		for (i = 0; i < bss->supp_rates_len; i++) {
+			int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+			if (mode->mode == MODE_ATHEROS_TURBO)
+				bitrate *= 2;
+			for (j = 0; j < mode->num_rates; j++)
+				if (mode->rates[j].rate == bitrate)
+					rates |= BIT(j);
+		}
+		ifsta->supp_rates_bits = rates;
+	} while (0);
+
+	if (skb) {
+		printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
+		       "template\n", dev->name);
+		dev_kfree_skb(skb);
+	}
+
+	ifsta->state = IEEE80211_IBSS_JOINED;
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+	ieee80211_rx_bss_put(dev, bss);
+
+	return res;
+}
+
+
+static int ieee80211_sta_create_ibss(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_hw_mode *mode;
+	u8 bssid[ETH_ALEN], *pos;
+	int i;
+
+#if 0
+	/* Easier testing, use fixed BSSID. */
+	memset(bssid, 0xfe, ETH_ALEN);
+#else
+	/* Generate random, not broadcast, locally administered BSSID. Mix in
+	 * own MAC address to make sure that devices that do not have proper
+	 * random number generator get different BSSID. */
+	get_random_bytes(bssid, ETH_ALEN);
+	for (i = 0; i < ETH_ALEN; i++)
+		bssid[i] ^= dev->dev_addr[i];
+	bssid[0] &= ~0x01;
+	bssid[0] |= 0x02;
+#endif
+
+	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
+	       dev->name, MAC_ARG(bssid));
+
+	bss = ieee80211_rx_bss_add(dev, bssid);
+	if (!bss)
+		return -ENOMEM;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	mode = local->oper_hw_mode;
+
+	if (local->hw.conf.beacon_int == 0)
+		local->hw.conf.beacon_int = 100;
+	bss->beacon_int = local->hw.conf.beacon_int;
+	bss->hw_mode = local->hw.conf.phymode;
+	bss->channel = local->hw.conf.channel;
+	bss->freq = local->hw.conf.freq;
+	bss->last_update = jiffies;
+	bss->capability = WLAN_CAPABILITY_IBSS;
+	if (sdata->default_key) {
+		bss->capability |= WLAN_CAPABILITY_PRIVACY;
+	} else
+		sdata->drop_unencrypted = 0;
+	bss->supp_rates_len = mode->num_rates;
+	pos = bss->supp_rates;
+	for (i = 0; i < mode->num_rates; i++) {
+		int rate = mode->rates[i].rate;
+		if (mode->mode == MODE_ATHEROS_TURBO)
+			rate /= 2;
+		*pos++ = (u8) (rate / 5);
+	}
+
+	return ieee80211_sta_join_ibss(dev, ifsta, bss);
+}
+
+
+static int ieee80211_sta_find_ibss(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+	int found = 0;
+	u8 bssid[ETH_ALEN];
+	int active_ibss;
+
+	if (ifsta->ssid_len == 0)
+		return -EINVAL;
+
+	active_ibss = ieee80211_sta_active_ibss(dev);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
+	       dev->name, active_ibss);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	spin_lock_bh(&local->sta_bss_lock);
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (ifsta->ssid_len != bss->ssid_len ||
+		    memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
+		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
+			continue;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+		printk(KERN_DEBUG "   bssid=" MAC_FMT " found\n",
+		       MAC_ARG(bss->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+		memcpy(bssid, bss->bssid, ETH_ALEN);
+		found = 1;
+		if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
+			break;
+	}
+	spin_unlock_bh(&local->sta_bss_lock);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "   sta_find_ibss: selected " MAC_FMT " current "
+	       MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
+	    (bss = ieee80211_rx_bss_get(dev, bssid))) {
+		printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
+		       " based on configured SSID\n",
+		       dev->name, MAC_ARG(bssid));
+		return ieee80211_sta_join_ibss(dev, ifsta, bss);
+	}
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+	printk(KERN_DEBUG "   did not try to join ibss\n");
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+	/* Selected IBSS not found in current scan results - try to scan */
+	if (ifsta->state == IEEE80211_IBSS_JOINED &&
+	    !ieee80211_sta_active_ibss(dev)) {
+		mod_timer(&ifsta->timer, jiffies +
+				      IEEE80211_IBSS_MERGE_INTERVAL);
+	} else if (time_after(jiffies, local->last_scan_completed +
+			      IEEE80211_SCAN_INTERVAL)) {
+		printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
+		       "join\n", dev->name);
+		return ieee80211_sta_req_scan(dev, ifsta->ssid,
+					      ifsta->ssid_len);
+	} else if (ifsta->state != IEEE80211_IBSS_JOINED) {
+		int interval = IEEE80211_SCAN_INTERVAL;
+
+		if (time_after(jiffies, ifsta->ibss_join_req +
+			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
+			if (ifsta->create_ibss &&
+			    local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+				return ieee80211_sta_create_ibss(dev, ifsta);
+			if (ifsta->create_ibss) {
+				printk(KERN_DEBUG "%s: IBSS not allowed on the"
+				       " configured channel %d (%d MHz)\n",
+				       dev->name, local->hw.conf.channel,
+				       local->hw.conf.freq);
+			}
+
+			/* No IBSS found - decrease scan interval and continue
+			 * scanning. */
+			interval = IEEE80211_SCAN_INTERVAL_SLOW;
+		}
+
+		ifsta->state = IEEE80211_IBSS_SEARCH;
+		mod_timer(&ifsta->timer, jiffies + interval);
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_sta *ifsta;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (len > IEEE80211_MAX_SSID_LEN)
+		return -EINVAL;
+
+	/* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
+	 * not defined. */
+	if (local->ops->conf_tx) {
+		struct ieee80211_tx_queue_params qparam;
+		int i;
+
+		memset(&qparam, 0, sizeof(qparam));
+		/* TODO: are these ok defaults for all hw_modes? */
+		qparam.aifs = 2;
+		qparam.cw_min =
+			local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
+		qparam.cw_max = 1023;
+		qparam.burst_time = 0;
+		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
+		{
+			local->ops->conf_tx(local_to_hw(local),
+					   i + IEEE80211_TX_QUEUE_DATA0,
+					   &qparam);
+		}
+		/* IBSS uses different parameters for Beacon sending */
+		qparam.cw_min++;
+		qparam.cw_min *= 2;
+		qparam.cw_min--;
+		local->ops->conf_tx(local_to_hw(local),
+				   IEEE80211_TX_QUEUE_BEACON, &qparam);
+	}
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ifsta = &sdata->u.sta;
+
+	if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+		ifsta->prev_bssid_set = 0;
+	memcpy(ifsta->ssid, ssid, len);
+	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
+	ifsta->ssid_len = len;
+
+	ifsta->ssid_set = len ? 1 : 0;
+	if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
+		ifsta->ibss_join_req = jiffies;
+		ifsta->state = IEEE80211_IBSS_SEARCH;
+		return ieee80211_sta_find_ibss(dev, ifsta);
+	}
+	return 0;
+}
+
+
+int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	memcpy(ssid, ifsta->ssid, ifsta->ssid_len);
+	*len = ifsta->ssid_len;
+	return 0;
+}
+
+
+int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_if_sta *ifsta;
+	int res;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ifsta = &sdata->u.sta;
+
+	if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
+		memcpy(ifsta->bssid, bssid, ETH_ALEN);
+		res = ieee80211_if_config(dev);
+		if (res) {
+			printk(KERN_DEBUG "%s: Failed to config new BSSID to "
+			       "the low-level driver\n", dev->name);
+			return res;
+		}
+	}
+
+	if (!is_valid_ether_addr(bssid))
+		ifsta->bssid_set = 0;
+	else
+		ifsta->bssid_set = 1;
+	return 0;
+}
+
+
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+				    struct ieee80211_sub_if_data *sdata,
+				    int powersave)
+{
+	struct sk_buff *skb;
+	struct ieee80211_hdr *nullfunc;
+	u16 fc;
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+	if (!skb) {
+		printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+		       "frame\n", sdata->dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+	memset(nullfunc, 0, 24);
+	fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+	     IEEE80211_FCTL_TODS;
+	if (powersave)
+		fc |= IEEE80211_FCTL_PM;
+	nullfunc->frame_control = cpu_to_le16(fc);
+	memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+	memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+	ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct net_device *dev = local->scan_dev;
+	struct ieee80211_sub_if_data *sdata;
+	union iwreq_data wrqu;
+
+	local->last_scan_completed = jiffies;
+	wmb();
+	local->sta_scanning = 0;
+
+	if (ieee80211_hw_config(local))
+		printk(KERN_DEBUG "%s: failed to restore operational"
+		       "channel after scan\n", dev->name);
+
+	if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
+	    ieee80211_if_config(dev))
+		printk(KERN_DEBUG "%s: failed to restore operational"
+		       "BSSID after scan\n", dev->name);
+
+	memset(&wrqu, 0, sizeof(wrqu));
+	wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		if (sdata->type == IEEE80211_IF_TYPE_STA) {
+			if (sdata->u.sta.associated)
+				ieee80211_send_nullfunc(local, sdata, 0);
+			ieee80211_sta_timer((unsigned long)sdata);
+		}
+		netif_wake_queue(sdata->dev);
+	}
+	read_unlock(&local->sub_if_lock);
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+		if (!ifsta->bssid_set ||
+		    (!ifsta->state == IEEE80211_IBSS_JOINED &&
+		    !ieee80211_sta_active_ibss(dev)))
+			ieee80211_sta_find_ibss(dev, ifsta);
+	}
+}
+EXPORT_SYMBOL(ieee80211_scan_completed);
+
+void ieee80211_sta_scan_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, scan_work.work);
+	struct net_device *dev = local->scan_dev;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_hw_mode *mode;
+	struct ieee80211_channel *chan;
+	int skip;
+	unsigned long next_delay = 0;
+
+	if (!local->sta_scanning)
+		return;
+
+	switch (local->scan_state) {
+	case SCAN_SET_CHANNEL:
+		mode = local->scan_hw_mode;
+		if (local->scan_hw_mode->list.next == &local->modes_list &&
+		    local->scan_channel_idx >= mode->num_channels) {
+			ieee80211_scan_completed(local_to_hw(local));
+			return;
+		}
+		skip = !(local->enabled_modes & (1 << mode->mode));
+		chan = &mode->channels[local->scan_channel_idx];
+		if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
+		    (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+		     !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
+		    (local->hw_modes & local->enabled_modes &
+		     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+			skip = 1;
+
+		if (!skip) {
+#if 0
+			printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
+			       dev->name, chan->chan, chan->freq);
+#endif
+
+			local->scan_channel = chan;
+			if (ieee80211_hw_config(local)) {
+				printk(KERN_DEBUG "%s: failed to set channel "
+				       "%d (%d MHz) for scan\n", dev->name,
+				       chan->chan, chan->freq);
+				skip = 1;
+			}
+		}
+
+		local->scan_channel_idx++;
+		if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
+			if (local->scan_hw_mode->list.next != &local->modes_list) {
+				local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
+								 struct ieee80211_hw_mode,
+								 list);
+				local->scan_channel_idx = 0;
+			}
+		}
+
+		if (skip)
+			break;
+
+		next_delay = IEEE80211_PROBE_DELAY +
+			     usecs_to_jiffies(local->hw.channel_change_time);
+		local->scan_state = SCAN_SEND_PROBE;
+		break;
+	case SCAN_SEND_PROBE:
+		if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
+			ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+						 local->scan_ssid_len);
+			next_delay = IEEE80211_CHANNEL_TIME;
+		} else
+			next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		local->scan_state = SCAN_SET_CHANNEL;
+		break;
+	}
+
+	if (local->sta_scanning)
+		queue_delayed_work(local->hw.workqueue, &local->scan_work,
+				   next_delay);
+}
+
+
+static int ieee80211_sta_start_scan(struct net_device *dev,
+				    u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+
+	if (ssid_len > IEEE80211_MAX_SSID_LEN)
+		return -EINVAL;
+
+	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
+	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
+	 * BSSID: MACAddress
+	 * SSID
+	 * ScanType: ACTIVE, PASSIVE
+	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
+	 *    a Probe frame during active scanning
+	 * ChannelList
+	 * MinChannelTime (>= ProbeDelay), in TU
+	 * MaxChannelTime: (>= MinChannelTime), in TU
+	 */
+
+	 /* MLME-SCAN.confirm
+	  * BSSDescriptionSet
+	  * ResultCode: SUCCESS, INVALID_PARAMETERS
+	 */
+
+	if (local->sta_scanning) {
+		if (local->scan_dev == dev)
+			return 0;
+		return -EBUSY;
+	}
+
+	if (local->ops->hw_scan) {
+		int rc = local->ops->hw_scan(local_to_hw(local),
+					    ssid, ssid_len);
+		if (!rc) {
+			local->sta_scanning = 1;
+			local->scan_dev = dev;
+		}
+		return rc;
+	}
+
+	local->sta_scanning = 1;
+
+	read_lock(&local->sub_if_lock);
+	list_for_each_entry(sdata, &local->sub_if_list, list) {
+		netif_stop_queue(sdata->dev);
+		if (sdata->type == IEEE80211_IF_TYPE_STA &&
+		    sdata->u.sta.associated)
+			ieee80211_send_nullfunc(local, sdata, 1);
+	}
+	read_unlock(&local->sub_if_lock);
+
+	if (ssid) {
+		local->scan_ssid_len = ssid_len;
+		memcpy(local->scan_ssid, ssid, ssid_len);
+	} else
+		local->scan_ssid_len = 0;
+	local->scan_state = SCAN_SET_CHANNEL;
+	local->scan_hw_mode = list_entry(local->modes_list.next,
+					 struct ieee80211_hw_mode,
+					 list);
+	local->scan_channel_idx = 0;
+	local->scan_dev = dev;
+
+	if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
+	    ieee80211_if_config(dev))
+		printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
+		       dev->name);
+
+	/* TODO: start scan as soon as all nullfunc frames are ACKed */
+	queue_delayed_work(local->hw.workqueue, &local->scan_work,
+			   IEEE80211_CHANNEL_TIME);
+
+	return 0;
+}
+
+
+int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+	if (sdata->type != IEEE80211_IF_TYPE_STA)
+		return ieee80211_sta_start_scan(dev, ssid, ssid_len);
+
+	if (local->sta_scanning) {
+		if (local->scan_dev == dev)
+			return 0;
+		return -EBUSY;
+	}
+
+	set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
+	queue_work(local->hw.workqueue, &ifsta->work);
+	return 0;
+}
+
+static char *
+ieee80211_sta_scan_result(struct net_device *dev,
+			  struct ieee80211_sta_bss *bss,
+			  char *current_ev, char *end_buf)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct iw_event iwe;
+
+	if (time_after(jiffies,
+		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
+		return current_ev;
+
+	if (!(local->enabled_modes & (1 << bss->hw_mode)))
+		return current_ev;
+
+	if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY &&
+	    !bss->wpa_ie && !bss->rsn_ie)
+		return current_ev;
+
+	if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID &&
+	    (local->scan_ssid_len != bss->ssid_len ||
+	     memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0))
+		return current_ev;
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+					  IW_EV_ADDR_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.length = bss->ssid_len;
+	iwe.u.data.flags = 1;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+					  bss->ssid);
+
+	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = SIOCGIWMODE;
+		if (bss->capability & WLAN_CAPABILITY_ESS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+						  IW_EV_UINT_LEN);
+	}
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = bss->channel;
+	iwe.u.freq.e = 0;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+	iwe.u.freq.m = bss->freq * 100000;
+	iwe.u.freq.e = 1;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+					  IW_EV_FREQ_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.qual = bss->signal;
+	iwe.u.qual.level = bss->rssi;
+	iwe.u.qual.noise = bss->noise;
+	iwe.u.qual.updated = local->wstats_flags;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+					  IW_EV_QUAL_LEN);
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWENCODE;
+	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+
+	if (bss && bss->wpa_ie) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = bss->wpa_ie_len;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  bss->wpa_ie);
+	}
+
+	if (bss && bss->rsn_ie) {
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = bss->rsn_ie_len;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  bss->rsn_ie);
+	}
+
+	if (bss && bss->supp_rates_len > 0) {
+		/* display all supported rates in readable format */
+		char *p = current_ev + IW_EV_LCP_LEN;
+		int i;
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+		for (i = 0; i < bss->supp_rates_len; i++) {
+			iwe.u.bitrate.value = ((bss->supp_rates[i] &
+							0x7f) * 500000);
+			p = iwe_stream_add_value(current_ev, p,
+					end_buf, &iwe, IW_EV_PARAM_LEN);
+		}
+		current_ev = p;
+	}
+
+	if (bss) {
+		char *buf;
+		buf = kmalloc(30, GFP_ATOMIC);
+		if (buf) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			kfree(buf);
+		}
+	}
+
+	do {
+		char *buf;
+
+		if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO))
+			break;
+
+		buf = kmalloc(100, GFP_ATOMIC);
+		if (!buf)
+			break;
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, "bcn_int=%d", bss->beacon_int);
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  buf);
+
+		memset(&iwe, 0, sizeof(iwe));
+		iwe.cmd = IWEVCUSTOM;
+		sprintf(buf, "capab=0x%04x", bss->capability);
+		iwe.u.data.length = strlen(buf);
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  buf);
+
+		kfree(buf);
+		break;
+	} while (0);
+
+	return current_ev;
+}
+
+
+int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	char *current_ev = buf;
+	char *end_buf = buf + len;
+	struct ieee80211_sta_bss *bss;
+
+	spin_lock_bh(&local->sta_bss_lock);
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
+			spin_unlock_bh(&local->sta_bss_lock);
+			return -E2BIG;
+		}
+		current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
+						       end_buf);
+	}
+	spin_unlock_bh(&local->sta_bss_lock);
+	return current_ev - buf;
+}
+
+
+int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	kfree(ifsta->extra_ie);
+	if (len == 0) {
+		ifsta->extra_ie = NULL;
+		ifsta->extra_ie_len = 0;
+		return 0;
+	}
+	ifsta->extra_ie = kmalloc(len, GFP_KERNEL);
+	if (!ifsta->extra_ie) {
+		ifsta->extra_ie_len = 0;
+		return -ENOMEM;
+	}
+	memcpy(ifsta->extra_ie, ie, len);
+	ifsta->extra_ie_len = len;
+	return 0;
+}
+
+
+struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
+					 struct sk_buff *skb, u8 *bssid,
+					 u8 *addr)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata = NULL;
+
+	/* TODO: Could consider removing the least recently used entry and
+	 * allow new one to be added. */
+	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s: No room for a new IBSS STA "
+			       "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr));
+		}
+		return NULL;
+	}
+
+	printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
+	       local->mdev->name, MAC_ARG(addr), dev->name);
+
+	sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
+	if (!sta)
+		return NULL;
+
+	sta->supp_rates = sdata->u.sta.supp_rates_bits;
+
+	rate_control_rate_init(sta, local);
+
+	return sta; /* caller will call sta_info_put() */
+}
+
+
+int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+	printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
+	       dev->name, reason);
+
+	if (sdata->type != IEEE80211_IF_TYPE_STA &&
+	    sdata->type != IEEE80211_IF_TYPE_IBSS)
+		return -EINVAL;
+
+	ieee80211_send_deauth(dev, ifsta, reason);
+	ieee80211_set_disassoc(dev, ifsta, 1);
+	return 0;
+}
+
+
+int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+	printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
+	       dev->name, reason);
+
+	if (sdata->type != IEEE80211_IF_TYPE_STA)
+		return -EINVAL;
+
+	if (!ifsta->associated)
+		return -1;
+
+	ieee80211_send_disassoc(dev, ifsta, reason);
+	ieee80211_set_disassoc(dev, ifsta, 0);
+	return 0;
+}
diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c
new file mode 100644
index 0000000..0f844f7
--- /dev/null
+++ b/net/mac80211/michael.c
@@ -0,0 +1,104 @@
+/*
+ * Michael MIC implementation - optimized for TKIP MIC operations
+ * Copyright 2002-2003, Instant802 Networks, 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/types.h>
+
+#include "michael.h"
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+
+static inline u32 rotl(u32 val, int bits)
+{
+	return (val << bits) | (val >> (32 - bits));
+}
+
+
+static inline u32 xswap(u32 val)
+{
+	return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+}
+
+
+#define michael_block(l, r) \
+do { \
+	r ^= rotl(l, 17); \
+	l += r; \
+	r ^= xswap(l); \
+	l += r; \
+	r ^= rotl(l, 3); \
+	l += r; \
+	r ^= rotr(l, 2); \
+	l += r; \
+} while (0)
+
+
+static inline u32 michael_get32(u8 *data)
+{
+	return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+
+static inline void michael_put32(u32 val, u8 *data)
+{
+	data[0] = val & 0xff;
+	data[1] = (val >> 8) & 0xff;
+	data[2] = (val >> 16) & 0xff;
+	data[3] = (val >> 24) & 0xff;
+}
+
+
+void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
+		 u8 *data, size_t data_len, u8 *mic)
+{
+	u32 l, r, val;
+	size_t block, blocks, left;
+
+	l = michael_get32(key);
+	r = michael_get32(key + 4);
+
+	/* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+	 * calculation, but it is _not_ transmitted */
+	l ^= michael_get32(da);
+	michael_block(l, r);
+	l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24);
+	michael_block(l, r);
+	l ^= michael_get32(&sa[2]);
+	michael_block(l, r);
+	l ^= priority;
+	michael_block(l, r);
+
+	/* Real data */
+	blocks = data_len / 4;
+	left = data_len % 4;
+
+	for (block = 0; block < blocks; block++) {
+		l ^= michael_get32(&data[block * 4]);
+		michael_block(l, r);
+	}
+
+	/* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
+	 * total length a multiple of 4. */
+	val = 0x5a;
+	while (left > 0) {
+		val <<= 8;
+		left--;
+		val |= data[blocks * 4 + left];
+	}
+	l ^= val;
+	michael_block(l, r);
+	/* last block is zero, so l ^ 0 = l */
+	michael_block(l, r);
+
+	michael_put32(l, mic);
+	michael_put32(r, mic + 4);
+}
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h
new file mode 100644
index 0000000..2e6aeba
--- /dev/null
+++ b/net/mac80211/michael.h
@@ -0,0 +1,20 @@
+/*
+ * Michael MIC implementation - optimized for TKIP MIC operations
+ * Copyright 2002-2003, Instant802 Networks, 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 MICHAEL_H
+#define MICHAEL_H
+
+#include <linux/types.h>
+
+#define MICHAEL_MIC_LEN 8
+
+void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
+		 u8 *data, size_t data_len, u8 *mic);
+
+#endif /* MICHAEL_H */
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
new file mode 100644
index 0000000..2048cfd
--- /dev/null
+++ b/net/mac80211/rc80211_simple.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape 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/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/compiler.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+
+
+/* This is a minimal implementation of TX rate controlling that can be used
+ * as the default when no improved mechanisms are available. */
+
+
+#define RATE_CONTROL_EMERG_DEC 2
+#define RATE_CONTROL_INTERVAL (HZ / 20)
+#define RATE_CONTROL_MIN_TX 10
+
+MODULE_ALIAS("rc80211_default");
+
+static void rate_control_rate_inc(struct ieee80211_local *local,
+				  struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_hw_mode *mode;
+	int i = sta->txrate;
+	int maxrate;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+		/* forced unicast rate - do not change STA rate */
+		return;
+	}
+
+	mode = local->oper_hw_mode;
+	maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+
+	if (i > mode->num_rates)
+		i = mode->num_rates - 2;
+
+	while (i + 1 < mode->num_rates) {
+		i++;
+		if (sta->supp_rates & BIT(i) &&
+		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+		    (maxrate < 0 || i <= maxrate)) {
+			sta->txrate = i;
+			break;
+		}
+	}
+}
+
+
+static void rate_control_rate_dec(struct ieee80211_local *local,
+				  struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_hw_mode *mode;
+	int i = sta->txrate;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+		/* forced unicast rate - do not change STA rate */
+		return;
+	}
+
+	mode = local->oper_hw_mode;
+	if (i > mode->num_rates)
+		i = mode->num_rates;
+
+	while (i > 0) {
+		i--;
+		if (sta->supp_rates & BIT(i) &&
+		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
+			sta->txrate = i;
+			break;
+		}
+	}
+}
+
+
+static struct ieee80211_rate *
+rate_control_lowest_rate(struct ieee80211_local *local,
+			 struct ieee80211_hw_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+
+		if (rate->flags & IEEE80211_RATE_SUPPORTED)
+			return rate;
+	}
+
+	printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
+	       "found\n");
+	return &mode->rates[0];
+}
+
+
+struct global_rate_control {
+	int dummy;
+};
+
+struct sta_rate_control {
+	unsigned long last_rate_change;
+	u32 tx_num_failures;
+	u32 tx_num_xmit;
+
+	unsigned long avg_rate_update;
+	u32 tx_avg_rate_sum;
+	u32 tx_avg_rate_num;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *tx_avg_rate_sum_dentry;
+	struct dentry *tx_avg_rate_num_dentry;
+#endif
+};
+
+
+static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
+					  struct sk_buff *skb,
+					  struct ieee80211_tx_status *status)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct sta_info *sta;
+	struct sta_rate_control *srctrl;
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	if (!sta)
+	    return;
+
+	srctrl = sta->rate_ctrl_priv;
+	srctrl->tx_num_xmit++;
+	if (status->excessive_retries) {
+		sta->antenna_sel_tx = sta->antenna_sel_tx == 1 ? 2 : 1;
+		sta->antenna_sel_rx = sta->antenna_sel_rx == 1 ? 2 : 1;
+		if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) {
+			printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d "
+			       "RX antenna --> %d (@%lu)\n",
+			       dev->name, MAC_ARG(hdr->addr1),
+			       sta->antenna_sel_tx, sta->antenna_sel_rx, jiffies);
+		}
+		srctrl->tx_num_failures++;
+		sta->tx_retry_failed++;
+		sta->tx_num_consecutive_failures++;
+		sta->tx_num_mpdu_fail++;
+	} else {
+		sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
+		sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
+		sta->last_ack_rssi[2] = status->ack_signal;
+		sta->tx_num_consecutive_failures = 0;
+		sta->tx_num_mpdu_ok++;
+	}
+	sta->tx_retry_count += status->retry_count;
+	sta->tx_num_mpdu_fail += status->retry_count;
+
+	if (time_after(jiffies,
+		       srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
+		srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
+		u32 per_failed;
+		srctrl->last_rate_change = jiffies;
+
+		per_failed = (100 * sta->tx_num_mpdu_fail) /
+			(sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
+		/* TODO: calculate average per_failed to make adjusting
+		 * parameters easier */
+#if 0
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
+			       sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
+			       per_failed);
+		}
+#endif
+
+		if (per_failed > local->rate_ctrl_num_down) {
+			rate_control_rate_dec(local, sta);
+		} else if (per_failed < local->rate_ctrl_num_up) {
+			rate_control_rate_inc(local, sta);
+		}
+		srctrl->tx_avg_rate_sum += status->control.rate->rate;
+		srctrl->tx_avg_rate_num++;
+		srctrl->tx_num_failures = 0;
+		srctrl->tx_num_xmit = 0;
+	} else if (sta->tx_num_consecutive_failures >=
+		   RATE_CONTROL_EMERG_DEC) {
+		rate_control_rate_dec(local, sta);
+	}
+
+	if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
+		srctrl->avg_rate_update = jiffies;
+		if (srctrl->tx_avg_rate_num > 0) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+			printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
+			       "%d (%d/%d)\n",
+			       dev->name, MAC_ARG(sta->addr),
+			       srctrl->tx_avg_rate_sum /
+			       srctrl->tx_avg_rate_num,
+			       srctrl->tx_avg_rate_sum,
+			       srctrl->tx_avg_rate_num);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+			srctrl->tx_avg_rate_sum = 0;
+			srctrl->tx_avg_rate_num = 0;
+		}
+	}
+
+	sta_info_put(sta);
+}
+
+
+static struct ieee80211_rate *
+rate_control_simple_get_rate(void *priv, struct net_device *dev,
+			     struct sk_buff *skb,
+			     struct rate_control_extra *extra)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_hw_mode *mode = extra->mode;
+	struct sta_info *sta;
+	int rateidx, nonerp_idx;
+	u16 fc;
+
+	memset(extra, 0, sizeof(*extra));
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+	    (hdr->addr1[0] & 0x01)) {
+		/* Send management frames and broadcast/multicast data using
+		 * lowest rate. */
+		/* TODO: this could probably be improved.. */
+		return rate_control_lowest_rate(local, mode);
+	}
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	if (!sta)
+		return rate_control_lowest_rate(local, mode);
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+		sta->txrate = sdata->bss->force_unicast_rateidx;
+
+	rateidx = sta->txrate;
+
+	if (rateidx >= mode->num_rates)
+		rateidx = mode->num_rates - 1;
+
+	sta->last_txrate = rateidx;
+	nonerp_idx = rateidx;
+	while (nonerp_idx > 0 &&
+	       ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
+		!(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
+		!(sta->supp_rates & BIT(nonerp_idx))))
+		nonerp_idx--;
+	extra->nonerp = &mode->rates[nonerp_idx];
+
+	sta_info_put(sta);
+
+	return &mode->rates[rateidx];
+}
+
+
+static void rate_control_simple_rate_init(void *priv, void *priv_sta,
+					  struct ieee80211_local *local,
+					  struct sta_info *sta)
+{
+	struct ieee80211_hw_mode *mode;
+	int i;
+	sta->txrate = 0;
+	mode = local->oper_hw_mode;
+	/* TODO: what is a good starting rate for STA? About middle? Maybe not
+	 * the lowest or the highest rate.. Could consider using RSSI from
+	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
+	 * after assoc.. */
+	for (i = 0; i < mode->num_rates; i++) {
+		if ((sta->supp_rates & BIT(i)) &&
+		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+			sta->txrate = i;
+	}
+}
+
+
+static void * rate_control_simple_alloc(struct ieee80211_local *local)
+{
+	struct global_rate_control *rctrl;
+
+	rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
+
+	return rctrl;
+}
+
+
+static void rate_control_simple_free(void *priv)
+{
+	struct global_rate_control *rctrl = priv;
+	kfree(rctrl);
+}
+
+
+static void rate_control_simple_clear(void *priv)
+{
+}
+
+
+static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp)
+{
+	struct sta_rate_control *rctrl;
+
+	rctrl = kzalloc(sizeof(*rctrl), gfp);
+
+	return rctrl;
+}
+
+
+static void rate_control_simple_free_sta(void *priv, void *priv_sta)
+{
+	struct sta_rate_control *rctrl = priv_sta;
+	kfree(rctrl);
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t sta_tx_avg_rate_sum_read(struct file *file,
+					char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	struct sta_rate_control *srctrl = file->private_data;
+	char buf[20];
+
+	sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations sta_tx_avg_rate_sum_ops = {
+	.read = sta_tx_avg_rate_sum_read,
+	.open = open_file_generic,
+};
+
+static ssize_t sta_tx_avg_rate_num_read(struct file *file,
+					char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	struct sta_rate_control *srctrl = file->private_data;
+	char buf[20];
+
+	sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
+	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations sta_tx_avg_rate_num_ops = {
+	.read = sta_tx_avg_rate_num_read,
+	.open = open_file_generic,
+};
+
+static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta,
+						struct dentry *dir)
+{
+	struct sta_rate_control *srctrl = priv_sta;
+
+	srctrl->tx_avg_rate_num_dentry =
+		debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400,
+				    dir, srctrl, &sta_tx_avg_rate_num_ops);
+	srctrl->tx_avg_rate_sum_dentry =
+		debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400,
+				    dir, srctrl, &sta_tx_avg_rate_sum_ops);
+}
+
+static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+	struct sta_rate_control *srctrl = priv_sta;
+
+	debugfs_remove(srctrl->tx_avg_rate_sum_dentry);
+	debugfs_remove(srctrl->tx_avg_rate_num_dentry);
+}
+#endif
+
+static struct rate_control_ops rate_control_simple = {
+	.module = THIS_MODULE,
+	.name = "simple",
+	.tx_status = rate_control_simple_tx_status,
+	.get_rate = rate_control_simple_get_rate,
+	.rate_init = rate_control_simple_rate_init,
+	.clear = rate_control_simple_clear,
+	.alloc = rate_control_simple_alloc,
+	.free = rate_control_simple_free,
+	.alloc_sta = rate_control_simple_alloc_sta,
+	.free_sta = rate_control_simple_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rate_control_simple_add_sta_debugfs,
+	.remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
+#endif
+};
+
+
+static int __init rate_control_simple_init(void)
+{
+	return ieee80211_rate_control_register(&rate_control_simple);
+}
+
+
+static void __exit rate_control_simple_exit(void)
+{
+	ieee80211_rate_control_unregister(&rate_control_simple);
+}
+
+
+module_init(rate_control_simple_init);
+module_exit(rate_control_simple_exit);
+
+MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
+MODULE_LICENSE("GPL");
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
new file mode 100644
index 0000000..ab7b1f0
--- /dev/null
+++ b/net/mac80211/sta_info.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "sta_info.h"
+#include "debugfs_key.h"
+#include "debugfs_sta.h"
+
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_add(struct ieee80211_local *local,
+			      struct sta_info *sta)
+{
+	sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
+	local->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_del(struct ieee80211_local *local,
+			      struct sta_info *sta)
+{
+	struct sta_info *s;
+
+	s = local->sta_hash[STA_HASH(sta->addr)];
+	if (!s)
+		return;
+	if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
+		local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
+		s = s->hnext;
+	if (s->hnext)
+		s->hnext = s->hnext->hnext;
+	else
+		printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from "
+		       "hash table\n", local->mdev->name, MAC_ARG(sta->addr));
+}
+
+static inline void __sta_info_get(struct sta_info *sta)
+{
+	kref_get(&sta->kref);
+}
+
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+{
+	struct sta_info *sta;
+
+	spin_lock_bh(&local->sta_lock);
+	sta = local->sta_hash[STA_HASH(addr)];
+	while (sta) {
+		if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
+			__sta_info_get(sta);
+			break;
+		}
+		sta = sta->hnext;
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	return sta;
+}
+EXPORT_SYMBOL(sta_info_get);
+
+int sta_info_min_txrate_get(struct ieee80211_local *local)
+{
+	struct sta_info *sta;
+	struct ieee80211_hw_mode *mode;
+	int min_txrate = 9999999;
+	int i;
+
+	spin_lock_bh(&local->sta_lock);
+	mode = local->oper_hw_mode;
+	for (i = 0; i < STA_HASH_SIZE; i++) {
+		sta = local->sta_hash[i];
+		while (sta) {
+			if (sta->txrate < min_txrate)
+				min_txrate = sta->txrate;
+			sta = sta->hnext;
+		}
+	}
+	spin_unlock_bh(&local->sta_lock);
+	if (min_txrate == 9999999)
+		min_txrate = 0;
+
+	return mode->rates[min_txrate].rate;
+}
+
+
+static void sta_info_release(struct kref *kref)
+{
+	struct sta_info *sta = container_of(kref, struct sta_info, kref);
+	struct ieee80211_local *local = sta->local;
+	struct sk_buff *skb;
+
+	/* free sta structure; it has already been removed from
+	 * hash table etc. external structures. Make sure that all
+	 * buffered frames are release (one might have been added
+	 * after sta_info_free() was called). */
+	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+		local->total_ps_buffered--;
+		dev_kfree_skb_any(skb);
+	}
+	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+		dev_kfree_skb_any(skb);
+	}
+	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
+	rate_control_put(sta->rate_ctrl);
+	if (sta->key)
+		ieee80211_debugfs_key_sta_del(sta->key, sta);
+	kfree(sta);
+}
+
+
+void sta_info_put(struct sta_info *sta)
+{
+	kref_put(&sta->kref, sta_info_release);
+}
+EXPORT_SYMBOL(sta_info_put);
+
+
+struct sta_info * sta_info_add(struct ieee80211_local *local,
+			       struct net_device *dev, u8 *addr, gfp_t gfp)
+{
+	struct sta_info *sta;
+
+	sta = kzalloc(sizeof(*sta), gfp);
+	if (!sta)
+		return NULL;
+
+	kref_init(&sta->kref);
+
+	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
+	if (!sta->rate_ctrl_priv) {
+		rate_control_put(sta->rate_ctrl);
+		kref_put(&sta->kref, sta_info_release);
+		kfree(sta);
+		return NULL;
+	}
+
+	memcpy(sta->addr, addr, ETH_ALEN);
+	sta->local = local;
+	sta->dev = dev;
+	skb_queue_head_init(&sta->ps_tx_buf);
+	skb_queue_head_init(&sta->tx_filtered);
+	__sta_info_get(sta);	/* sta used by caller, decremented by
+				 * sta_info_put() */
+	spin_lock_bh(&local->sta_lock);
+	list_add(&sta->list, &local->sta_list);
+	local->num_sta++;
+	sta_info_hash_add(local, sta);
+	spin_unlock_bh(&local->sta_lock);
+	if (local->ops->sta_table_notification)
+		local->ops->sta_table_notification(local_to_hw(local),
+						  local->num_sta);
+	sta->key_idx_compression = HW_KEY_IDX_INVALID;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
+	       local->mdev->name, MAC_ARG(addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	if (!in_interrupt()) {
+		sta->debugfs_registered = 1;
+		ieee80211_sta_debugfs_add(sta);
+		rate_control_add_sta_debugfs(sta);
+	} else {
+		/* debugfs entry adding might sleep, so schedule process
+		 * context task for adding entry for STAs that do not yet
+		 * have one. */
+		queue_work(local->hw.workqueue, &local->sta_debugfs_add);
+	}
+#endif
+
+	return sta;
+}
+
+static void finish_sta_info_free(struct ieee80211_local *local,
+				 struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
+	       local->mdev->name, MAC_ARG(sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+	if (sta->key) {
+		ieee80211_debugfs_key_remove(sta->key);
+		ieee80211_key_free(sta->key);
+		sta->key = NULL;
+	}
+
+	rate_control_remove_sta_debugfs(sta);
+	ieee80211_sta_debugfs_remove(sta);
+
+	sta_info_put(sta);
+}
+
+static void sta_info_remove(struct sta_info *sta)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata;
+
+	sta_info_hash_del(local, sta);
+	list_del(&sta->list);
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if (sta->flags & WLAN_STA_PS) {
+		sta->flags &= ~WLAN_STA_PS;
+		if (sdata->bss)
+			atomic_dec(&sdata->bss->num_sta_ps);
+	}
+	local->num_sta--;
+	sta_info_remove_aid_ptr(sta);
+}
+
+void sta_info_free(struct sta_info *sta, int locked)
+{
+	struct sk_buff *skb;
+	struct ieee80211_local *local = sta->local;
+
+	if (!locked) {
+		spin_lock_bh(&local->sta_lock);
+		sta_info_remove(sta);
+		spin_unlock_bh(&local->sta_lock);
+	} else {
+		sta_info_remove(sta);
+	}
+	if (local->ops->sta_table_notification)
+		local->ops->sta_table_notification(local_to_hw(local),
+						  local->num_sta);
+
+	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+		local->total_ps_buffered--;
+		dev_kfree_skb_any(skb);
+	}
+	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+		dev_kfree_skb_any(skb);
+	}
+
+	if (sta->key) {
+		if (local->ops->set_key) {
+			struct ieee80211_key_conf *key;
+			key = ieee80211_key_data2conf(local, sta->key);
+			if (key) {
+				local->ops->set_key(local_to_hw(local),
+						   DISABLE_KEY,
+						   sta->addr, key, sta->aid);
+				kfree(key);
+			}
+		}
+	} else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) {
+		struct ieee80211_key_conf conf;
+		memset(&conf, 0, sizeof(conf));
+		conf.hw_key_idx = sta->key_idx_compression;
+		conf.alg = ALG_NULL;
+		conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+		local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+				   sta->addr, &conf, sta->aid);
+		sta->key_idx_compression = HW_KEY_IDX_INVALID;
+	}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	if (in_atomic()) {
+		list_add(&sta->list, &local->deleted_sta_list);
+		queue_work(local->hw.workqueue, &local->sta_debugfs_add);
+	} else
+#endif
+		finish_sta_info_free(local, sta);
+}
+
+
+static inline int sta_info_buffer_expired(struct ieee80211_local *local,
+					  struct sta_info *sta,
+					  struct sk_buff *skb)
+{
+	struct ieee80211_tx_packet_data *pkt_data;
+	int timeout;
+
+	if (!skb)
+		return 0;
+
+	pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+
+	/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
+	timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
+		   15625) * HZ;
+	if (timeout < STA_TX_BUFFER_EXPIRE)
+		timeout = STA_TX_BUFFER_EXPIRE;
+	return time_after(jiffies, pkt_data->jiffies + timeout);
+}
+
+
+static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+					     struct sta_info *sta)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	if (skb_queue_empty(&sta->ps_tx_buf))
+		return;
+
+	for (;;) {
+		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
+		skb = skb_peek(&sta->ps_tx_buf);
+		if (sta_info_buffer_expired(local, sta, skb)) {
+			skb = __skb_dequeue(&sta->ps_tx_buf);
+			if (skb_queue_empty(&sta->ps_tx_buf))
+				sta->flags &= ~WLAN_STA_TIM;
+		} else
+			skb = NULL;
+		spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
+
+		if (skb) {
+			local->total_ps_buffered--;
+			printk(KERN_DEBUG "Buffered frame expired (STA "
+			       MAC_FMT ")\n", MAC_ARG(sta->addr));
+			dev_kfree_skb(skb);
+		} else
+			break;
+	}
+}
+
+
+static void sta_info_cleanup(unsigned long data)
+{
+	struct ieee80211_local *local = (struct ieee80211_local *) data;
+	struct sta_info *sta;
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry(sta, &local->sta_list, list) {
+		__sta_info_get(sta);
+		sta_info_cleanup_expire_buffered(local, sta);
+		sta_info_put(sta);
+	}
+	spin_unlock_bh(&local->sta_lock);
+
+	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+	add_timer(&local->sta_cleanup);
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void sta_info_debugfs_add_task(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, sta_debugfs_add);
+	struct sta_info *sta, *tmp;
+
+	while (1) {
+		spin_lock_bh(&local->sta_lock);
+		if (!list_empty(&local->deleted_sta_list)) {
+			sta = list_entry(local->deleted_sta_list.next,
+					 struct sta_info, list);
+			list_del(local->deleted_sta_list.next);
+		} else
+			sta = NULL;
+		spin_unlock_bh(&local->sta_lock);
+		if (!sta)
+			break;
+		finish_sta_info_free(local, sta);
+	}
+
+	while (1) {
+		sta = NULL;
+		spin_lock_bh(&local->sta_lock);
+		list_for_each_entry(tmp, &local->sta_list, list) {
+			if (!tmp->debugfs_registered) {
+				sta = tmp;
+				__sta_info_get(sta);
+				break;
+			}
+		}
+		spin_unlock_bh(&local->sta_lock);
+
+		if (!sta)
+			break;
+
+		sta->debugfs_registered = 1;
+		ieee80211_sta_debugfs_add(sta);
+		rate_control_add_sta_debugfs(sta);
+		sta_info_put(sta);
+	}
+}
+#endif
+
+void sta_info_init(struct ieee80211_local *local)
+{
+	spin_lock_init(&local->sta_lock);
+	INIT_LIST_HEAD(&local->sta_list);
+	INIT_LIST_HEAD(&local->deleted_sta_list);
+
+	init_timer(&local->sta_cleanup);
+	local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+	local->sta_cleanup.data = (unsigned long) local;
+	local->sta_cleanup.function = sta_info_cleanup;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task);
+#endif
+}
+
+int sta_info_start(struct ieee80211_local *local)
+{
+	add_timer(&local->sta_cleanup);
+	return 0;
+}
+
+void sta_info_stop(struct ieee80211_local *local)
+{
+	struct sta_info *sta, *tmp;
+
+	del_timer(&local->sta_cleanup);
+
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+		/* sta_info_free must be called with 0 as the last
+		 * parameter to ensure all debugfs sta entries are
+		 * unregistered. We don't need locking at this
+		 * point. */
+		sta_info_free(sta, 0);
+	}
+}
+
+void sta_info_remove_aid_ptr(struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata;
+
+	if (sta->aid <= 0)
+		return;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+	if (sdata->local->ops->set_tim)
+		sdata->local->ops->set_tim(local_to_hw(sdata->local),
+					  sta->aid, 0);
+	if (sdata->bss)
+		__bss_tim_clear(sdata->bss, sta->aid);
+}
+
+
+/**
+ * sta_info_flush - flush matching STA entries from the STA table
+ * @local: local interface data
+ * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
+ */
+void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
+{
+	struct sta_info *sta, *tmp;
+
+	spin_lock_bh(&local->sta_lock);
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+		if (!dev || dev == sta->dev)
+			sta_info_free(sta, 1);
+	spin_unlock_bh(&local->sta_lock);
+}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
new file mode 100644
index 0000000..b5591d2
--- /dev/null
+++ b/net/mac80211/sta_info.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2002-2005, Devicescape 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 STA_INFO_H
+#define STA_INFO_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/kref.h>
+#include "ieee80211_key.h"
+
+/* Stations flags (struct sta_info::flags) */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
+#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
+#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
+				    * controlling whether STA is authorized to
+				    * send and receive non-IEEE 802.1X frames
+				    */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_WDS BIT(27)
+
+
+struct sta_info {
+	struct kref kref;
+	struct list_head list;
+	struct sta_info *hnext; /* next entry in hash table list */
+
+	struct ieee80211_local *local;
+
+	u8 addr[ETH_ALEN];
+	u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */
+	u32 flags; /* WLAN_STA_ */
+
+	struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in
+					* power saving state */
+	int pspoll; /* whether STA has send a PS Poll frame */
+	struct sk_buff_head tx_filtered; /* buffer of TX frames that were
+					  * already given to low-level driver,
+					  * but were filtered */
+	int clear_dst_mask;
+
+	unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */
+	unsigned long rx_bytes, tx_bytes;
+	unsigned long tx_retry_failed, tx_retry_count;
+	unsigned long tx_filtered_count;
+
+	unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
+
+	unsigned long last_rx;
+	u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
+	int txrate; /* index in local->curr_rates */
+	int last_txrate; /* last rate used to send a frame to this STA */
+	int last_nonerp_idx;
+
+	struct net_device *dev; /* which net device is this station associated
+				 * to */
+
+	struct ieee80211_key *key;
+
+	u32 tx_num_consecutive_failures;
+	u32 tx_num_mpdu_ok;
+	u32 tx_num_mpdu_fail;
+
+	struct rate_control_ref *rate_ctrl;
+	void *rate_ctrl_priv;
+
+	/* last received seq/frag number from this STA (per RX queue) */
+	__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
+	unsigned long num_duplicates; /* number of duplicate frames received
+				       * from this STA */
+	unsigned long tx_fragments; /* number of transmitted MPDUs */
+	unsigned long rx_fragments; /* number of received MPDUs */
+	unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
+
+	int last_rssi; /* RSSI of last received frame from this STA */
+	int last_signal; /* signal of last received frame from this STA */
+	int last_noise; /* noise of last received frame from this STA */
+	int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */
+	unsigned long last_ack;
+	int channel_use;
+	int channel_use_raw;
+
+	u8 antenna_sel_tx;
+	u8 antenna_sel_rx;
+
+
+	int key_idx_compression; /* key table index for compression and TX
+				  * filtering; used only if sta->key is not
+				  * set */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	int debugfs_registered;
+#endif
+	int assoc_ap; /* whether this is an AP that we are
+		       * associated with as a client */
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+	int vlan_id;
+
+	u16 listen_interval;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct sta_info_debugfsdentries {
+		struct dentry *dir;
+		struct dentry *flags;
+		struct dentry *num_ps_buf_frames;
+		struct dentry *last_ack_rssi;
+		struct dentry *last_ack_ms;
+		struct dentry *inactive_ms;
+		struct dentry *last_seq_ctrl;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+		struct dentry *wme_rx_queue;
+		struct dentry *wme_tx_queue;
+#endif
+	} debugfs;
+#endif
+};
+
+
+/* Maximum number of concurrently registered stations */
+#define MAX_STA_COUNT 2007
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Maximum number of frames to buffer per power saving station */
+#define STA_MAX_TX_BUFFER 128
+
+/* Minimum buffered frame expiry time. If STA uses listen interval that is
+ * smaller than this value, the minimum value here is used instead. */
+#define STA_TX_BUFFER_EXPIRE (10 * HZ)
+
+/* How often station data is cleaned up (e.g., expiration of buffered frames)
+ */
+#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
+
+struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
+int sta_info_min_txrate_get(struct ieee80211_local *local);
+void sta_info_put(struct sta_info *sta);
+struct sta_info * sta_info_add(struct ieee80211_local *local,
+			       struct net_device *dev, u8 *addr, gfp_t gfp);
+void sta_info_free(struct sta_info *sta, int locked);
+void sta_info_init(struct ieee80211_local *local);
+int sta_info_start(struct ieee80211_local *local);
+void sta_info_stop(struct ieee80211_local *local);
+void sta_info_remove_aid_ptr(struct sta_info *sta);
+void sta_info_flush(struct ieee80211_local *local, struct net_device *dev);
+
+#endif /* STA_INFO_H */
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
new file mode 100644
index 0000000..4162172
--- /dev/null
+++ b/net/mac80211/tkip.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape 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/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_key.h"
+#include "tkip.h"
+#include "wep.h"
+
+
+/* TKIP key mixing functions */
+
+
+#define PHASE1_LOOP_COUNT 8
+
+
+/* 2-byte by 2-byte subset of the full AES S-box table; second part of this
+ * table is identical to first part but byte-swapped */
+static const u16 tkip_sbox[256] =
+{
+	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+
+static inline u16 Mk16(u8 x, u8 y)
+{
+	return ((u16) x << 8) | (u16) y;
+}
+
+
+static inline u8 Hi8(u16 v)
+{
+	return v >> 8;
+}
+
+
+static inline u8 Lo8(u16 v)
+{
+	return v & 0xff;
+}
+
+
+static inline u16 Hi16(u32 v)
+{
+	return v >> 16;
+}
+
+
+static inline u16 Lo16(u32 v)
+{
+	return v & 0xffff;
+}
+
+
+static inline u16 RotR1(u16 v)
+{
+	return (v >> 1) | ((v & 0x0001) << 15);
+}
+
+
+static inline u16 tkip_S(u16 val)
+{
+	u16 a = tkip_sbox[Hi8(val)];
+
+	return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8);
+}
+
+
+
+/* P1K := Phase1(TA, TK, TSC)
+ * TA = transmitter address (48 bits)
+ * TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
+ * TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
+ * P1K: 80 bits
+ */
+static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
+			       u16 *p1k)
+{
+	int i, j;
+
+	p1k[0] = Lo16(tsc_IV32);
+	p1k[1] = Hi16(tsc_IV32);
+	p1k[2] = Mk16(ta[1], ta[0]);
+	p1k[3] = Mk16(ta[3], ta[2]);
+	p1k[4] = Mk16(ta[5], ta[4]);
+
+	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+		j = 2 * (i & 1);
+		p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j]));
+		p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j]));
+		p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j]));
+		p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j]));
+		p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i;
+	}
+}
+
+
+static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
+			       u8 *rc4key)
+{
+	u16 ppk[6];
+	int i;
+
+	ppk[0] = p1k[0];
+	ppk[1] = p1k[1];
+	ppk[2] = p1k[2];
+	ppk[3] = p1k[3];
+	ppk[4] = p1k[4];
+	ppk[5] = p1k[4] + tsc_IV16;
+
+	ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0]));
+	ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2]));
+	ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4]));
+	ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6]));
+	ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8]));
+	ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10]));
+	ppk[0] +=  RotR1(ppk[5] ^ Mk16(tk[13], tk[12]));
+	ppk[1] +=  RotR1(ppk[0] ^ Mk16(tk[15], tk[14]));
+	ppk[2] +=  RotR1(ppk[1]);
+	ppk[3] +=  RotR1(ppk[2]);
+	ppk[4] +=  RotR1(ppk[3]);
+	ppk[5] +=  RotR1(ppk[4]);
+
+	rc4key[0] = Hi8(tsc_IV16);
+	rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f;
+	rc4key[2] = Lo8(tsc_IV16);
+	rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1);
+
+	for (i = 0; i < 6; i++) {
+		rc4key[4 + 2 * i] = Lo8(ppk[i]);
+		rc4key[5 + 2 * i] = Hi8(ppk[i]);
+	}
+}
+
+
+/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
+ * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
+ * the packet payload). */
+u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+			   u8 iv0, u8 iv1, u8 iv2)
+{
+	*pos++ = iv0;
+	*pos++ = iv1;
+	*pos++ = iv2;
+	*pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */;
+	*pos++ = key->u.tkip.iv32 & 0xff;
+	*pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
+	*pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
+	*pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
+	return pos;
+}
+
+
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+				  u16 *phase1key)
+{
+	tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+			   key->u.tkip.iv32, phase1key);
+}
+
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+			       u8 *rc4key)
+{
+	/* Calculate per-packet key */
+	if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
+		/* IV16 wrapped around - perform TKIP phase 1 */
+		tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+				   key->u.tkip.iv32, key->u.tkip.p1k);
+		key->u.tkip.tx_initialized = 1;
+	}
+
+	tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+			   key->u.tkip.iv16, rc4key);
+}
+
+/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the
+ * beginning of the buffer containing payload. This payload must include
+ * headroom of eight octets for IV and Ext. IV and taildroom of four octets
+ * for ICV. @payload_len is the length of payload (_not_ including extra
+ * headroom and tailroom). @ta is the transmitter addresses. */
+void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+				 struct ieee80211_key *key,
+				 u8 *pos, size_t payload_len, u8 *ta)
+{
+	u8 rc4key[16];
+
+	ieee80211_tkip_gen_rc4key(key, ta, rc4key);
+	pos = ieee80211_tkip_add_iv(pos, key, rc4key[0], rc4key[1], rc4key[2]);
+	ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
+}
+
+
+/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
+ * beginning of the buffer containing IEEE 802.11 header payload, i.e.,
+ * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
+ * length of payload, including IV, Ext. IV, MIC, ICV.  */
+int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+				struct ieee80211_key *key,
+				u8 *payload, size_t payload_len, u8 *ta,
+				int only_iv, int queue)
+{
+	u32 iv32;
+	u32 iv16;
+	u8 rc4key[16], keyid, *pos = payload;
+	int res;
+
+	if (payload_len < 12)
+		return -1;
+
+	iv16 = (pos[0] << 8) | pos[2];
+	keyid = pos[3];
+	iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+	pos += 8;
+#ifdef CONFIG_TKIP_DEBUG
+	{
+		int i;
+		printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
+		for (i = 0; i < payload_len; i++)
+			printk(" %02x", payload[i]);
+		printk("\n");
+		printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
+		       iv16, iv32);
+	}
+#endif /* CONFIG_TKIP_DEBUG */
+
+	if (!(keyid & (1 << 5)))
+		return TKIP_DECRYPT_NO_EXT_IV;
+
+	if ((keyid >> 6) != key->keyidx)
+		return TKIP_DECRYPT_INVALID_KEYIDX;
+
+	if (key->u.tkip.rx_initialized[queue] &&
+	    (iv32 < key->u.tkip.iv32_rx[queue] ||
+	     (iv32 == key->u.tkip.iv32_rx[queue] &&
+	      iv16 <= key->u.tkip.iv16_rx[queue]))) {
+#ifdef CONFIG_TKIP_DEBUG
+		printk(KERN_DEBUG "TKIP replay detected for RX frame from "
+		       MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+		       MAC_ARG(ta),
+		       iv32, iv16, key->u.tkip.iv32_rx[queue],
+		       key->u.tkip.iv16_rx[queue]);
+#endif /* CONFIG_TKIP_DEBUG */
+		return TKIP_DECRYPT_REPLAY;
+	}
+
+	if (only_iv) {
+		res = TKIP_DECRYPT_OK;
+		key->u.tkip.rx_initialized[queue] = 1;
+		goto done;
+	}
+
+	if (!key->u.tkip.rx_initialized[queue] ||
+	    key->u.tkip.iv32_rx[queue] != iv32) {
+		key->u.tkip.rx_initialized[queue] = 1;
+		/* IV16 wrapped around - perform TKIP phase 1 */
+		tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+				   iv32, key->u.tkip.p1k_rx[queue]);
+#ifdef CONFIG_TKIP_DEBUG
+		{
+			int i;
+			printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT
+			       " TK=", MAC_ARG(ta));
+			for (i = 0; i < 16; i++)
+				printk("%02x ",
+				       key->key[ALG_TKIP_TEMP_ENCR_KEY + i]);
+			printk("\n");
+			printk(KERN_DEBUG "TKIP decrypt: P1K=");
+			for (i = 0; i < 5; i++)
+				printk("%04x ", key->u.tkip.p1k_rx[queue][i]);
+			printk("\n");
+		}
+#endif /* CONFIG_TKIP_DEBUG */
+	}
+
+	tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
+			   &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+			   iv16, rc4key);
+#ifdef CONFIG_TKIP_DEBUG
+	{
+		int i;
+		printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
+		for (i = 0; i < 16; i++)
+			printk("%02x ", rc4key[i]);
+		printk("\n");
+	}
+#endif /* CONFIG_TKIP_DEBUG */
+
+	res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
+ done:
+	if (res == TKIP_DECRYPT_OK) {
+		/* FIX: these should be updated only after Michael MIC has been
+		 * verified */
+		/* Record previously received IV */
+		key->u.tkip.iv32_rx[queue] = iv32;
+		key->u.tkip.iv16_rx[queue] = iv16;
+	}
+
+	return res;
+}
+
+
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
new file mode 100644
index 0000000..a0d181a
--- /dev/null
+++ b/net/mac80211/tkip.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, 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 TKIP_H
+#define TKIP_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include "ieee80211_key.h"
+
+u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+			   u8 iv0, u8 iv1, u8 iv2);
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+				  u16 *phase1key);
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+			       u8 *rc4key);
+void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+				 struct ieee80211_key *key,
+				 u8 *pos, size_t payload_len, u8 *ta);
+enum {
+	TKIP_DECRYPT_OK = 0,
+	TKIP_DECRYPT_NO_EXT_IV = -1,
+	TKIP_DECRYPT_INVALID_KEYIDX = -2,
+	TKIP_DECRYPT_REPLAY = -3,
+};
+int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+				struct ieee80211_key *key,
+				u8 *payload, size_t payload_len, u8 *ta,
+				int only_iv, int queue);
+
+#endif /* TKIP_H */
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
new file mode 100644
index 0000000..1ad3d75
--- /dev/null
+++ b/net/mac80211/wep.c
@@ -0,0 +1,328 @@
+/*
+ * Software WEP encryption implementation
+ * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2003, Instant802 Networks, 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/netdevice.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wep.h"
+
+
+int ieee80211_wep_init(struct ieee80211_local *local)
+{
+	/* start WEP IV from a random value */
+	get_random_bytes(&local->wep_iv, WEP_IV_LEN);
+
+	local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
+						CRYPTO_ALG_ASYNC);
+	if (IS_ERR(local->wep_tx_tfm))
+		return -ENOMEM;
+
+	local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
+						CRYPTO_ALG_ASYNC);
+	if (IS_ERR(local->wep_rx_tfm)) {
+		crypto_free_blkcipher(local->wep_tx_tfm);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void ieee80211_wep_free(struct ieee80211_local *local)
+{
+	crypto_free_blkcipher(local->wep_tx_tfm);
+	crypto_free_blkcipher(local->wep_rx_tfm);
+}
+
+static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
+{
+	/* Fluhrer, Mantin, and Shamir have reported weaknesses in the
+	 * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
+	 * 0xff, N) can be used to speedup attacks, so avoid using them. */
+	if ((iv & 0xff00) == 0xff00) {
+		u8 B = (iv >> 16) & 0xff;
+		if (B >= 3 && B < 3 + keylen)
+			return 1;
+	}
+	return 0;
+}
+
+
+void ieee80211_wep_get_iv(struct ieee80211_local *local,
+			  struct ieee80211_key *key, u8 *iv)
+{
+	local->wep_iv++;
+	if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen))
+		local->wep_iv += 0x0100;
+
+	if (!iv)
+		return;
+
+	*iv++ = (local->wep_iv >> 16) & 0xff;
+	*iv++ = (local->wep_iv >> 8) & 0xff;
+	*iv++ = local->wep_iv & 0xff;
+	*iv++ = key->keyidx << 6;
+}
+
+
+u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  struct ieee80211_key *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+	u8 *newhdr;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	fc |= IEEE80211_FCTL_PROTECTED;
+	hdr->frame_control = cpu_to_le16(fc);
+
+	if ((skb_headroom(skb) < WEP_IV_LEN ||
+	     skb_tailroom(skb) < WEP_ICV_LEN)) {
+		I802_DEBUG_INC(local->tx_expand_skb_head);
+		if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
+					      GFP_ATOMIC)))
+			return NULL;
+	}
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+	newhdr = skb_push(skb, WEP_IV_LEN);
+	memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
+	ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
+	return newhdr + hdrlen;
+}
+
+
+void ieee80211_wep_remove_iv(struct ieee80211_local *local,
+			     struct sk_buff *skb,
+			     struct ieee80211_key *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+	memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
+	skb_pull(skb, WEP_IV_LEN);
+}
+
+
+/* Perform WEP encryption using given key. data buffer must have tailroom
+ * for 4-byte ICV. data_len must not include this ICV. Note: this function
+ * does _not_ add IV. data = RC4(data | CRC32(data)) */
+void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+				size_t klen, u8 *data, size_t data_len)
+{
+	struct blkcipher_desc desc = { .tfm = tfm };
+	struct scatterlist sg;
+	__le32 *icv;
+
+	icv = (__le32 *)(data + data_len);
+	*icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+
+	crypto_blkcipher_setkey(tfm, rc4key, klen);
+	sg.page = virt_to_page(data);
+	sg.offset = offset_in_page(data);
+	sg.length = data_len + WEP_ICV_LEN;
+	crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+}
+
+
+/* Perform WEP encryption on given skb. 4 bytes of extra space (IV) in the
+ * beginning of the buffer 4 bytes of extra space (ICV) in the end of the
+ * buffer will be added. Both IV and ICV will be transmitted, so the
+ * payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_key *key)
+{
+	u32 klen;
+	u8 *rc4key, *iv;
+	size_t len;
+
+	if (!key || key->alg != ALG_WEP)
+		return -1;
+
+	klen = 3 + key->keylen;
+	rc4key = kmalloc(klen, GFP_ATOMIC);
+	if (!rc4key)
+		return -1;
+
+	iv = ieee80211_wep_add_iv(local, skb, key);
+	if (!iv) {
+		kfree(rc4key);
+		return -1;
+	}
+
+	len = skb->len - (iv + WEP_IV_LEN - skb->data);
+
+	/* Prepend 24-bit IV to RC4 key */
+	memcpy(rc4key, iv, 3);
+
+	/* Copy rest of the WEP key (the secret part) */
+	memcpy(rc4key + 3, key->key, key->keylen);
+
+	/* Add room for ICV */
+	skb_put(skb, WEP_ICV_LEN);
+
+	ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen,
+				   iv + WEP_IV_LEN, len);
+
+	kfree(rc4key);
+
+	return 0;
+}
+
+
+/* Perform WEP decryption using given key. data buffer includes encrypted
+ * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
+ * Return 0 on success and -1 on ICV mismatch. */
+int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+			       size_t klen, u8 *data, size_t data_len)
+{
+	struct blkcipher_desc desc = { .tfm = tfm };
+	struct scatterlist sg;
+	__le32 crc;
+
+	crypto_blkcipher_setkey(tfm, rc4key, klen);
+	sg.page = virt_to_page(data);
+	sg.offset = offset_in_page(data);
+	sg.length = data_len + WEP_ICV_LEN;
+	crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
+
+	crc = cpu_to_le32(~crc32_le(~0, data, data_len));
+	if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0)
+		/* ICV mismatch */
+		return -1;
+
+	return 0;
+}
+
+
+/* Perform WEP decryption on given skb. Buffer includes whole WEP part of
+ * the frame: IV (4 bytes), encrypted payload (including SNAP header),
+ * ICV (4 bytes). skb->len includes both IV and ICV.
+ *
+ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
+ * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
+ * is moved to the beginning of the skb and skb length will be reduced.
+ */
+int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_key *key)
+{
+	u32 klen;
+	u8 *rc4key;
+	u8 keyidx;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+	size_t len;
+	int ret = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return -1;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (skb->len < 8 + hdrlen)
+		return -1;
+
+	len = skb->len - hdrlen - 8;
+
+	keyidx = skb->data[hdrlen + 3] >> 6;
+
+	if (!key || keyidx != key->keyidx || key->alg != ALG_WEP)
+		return -1;
+
+	klen = 3 + key->keylen;
+
+	rc4key = kmalloc(klen, GFP_ATOMIC);
+	if (!rc4key)
+		return -1;
+
+	/* Prepend 24-bit IV to RC4 key */
+	memcpy(rc4key, skb->data + hdrlen, 3);
+
+	/* Copy rest of the WEP key (the secret part) */
+	memcpy(rc4key + 3, key->key, key->keylen);
+
+	if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
+				       skb->data + hdrlen + WEP_IV_LEN,
+				       len)) {
+		printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
+		ret = -1;
+	}
+
+	kfree(rc4key);
+
+	/* Trim ICV */
+	skb_trim(skb, skb->len - WEP_ICV_LEN);
+
+	/* Remove IV */
+	memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
+	skb_pull(skb, WEP_IV_LEN);
+
+	return ret;
+}
+
+
+int ieee80211_wep_get_keyidx(struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return -1;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (skb->len < 8 + hdrlen)
+		return -1;
+
+	return skb->data[hdrlen + 3] >> 6;
+}
+
+
+u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 fc;
+	int hdrlen;
+	u8 *ivpos;
+	u32 iv;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return NULL;
+
+	hdrlen = ieee80211_get_hdrlen(fc);
+	ivpos = skb->data + hdrlen;
+	iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
+
+	if (ieee80211_wep_weak_iv(iv, key->keylen))
+		return ivpos;
+
+	return NULL;
+}
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
new file mode 100644
index 0000000..bfe29e8
--- /dev/null
+++ b/net/mac80211/wep.h
@@ -0,0 +1,40 @@
+/*
+ * Software WEP encryption implementation
+ * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2003, Instant802 Networks, 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 WEP_H
+#define WEP_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+#include "ieee80211_key.h"
+
+int ieee80211_wep_init(struct ieee80211_local *local);
+void ieee80211_wep_free(struct ieee80211_local *local);
+void ieee80211_wep_get_iv(struct ieee80211_local *local,
+			  struct ieee80211_key *key, u8 *iv);
+u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  struct ieee80211_key *key);
+void ieee80211_wep_remove_iv(struct ieee80211_local *local,
+			     struct sk_buff *skb,
+			     struct ieee80211_key *key);
+void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+				size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+			       size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_key *key);
+int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
+			  struct ieee80211_key *key);
+int ieee80211_wep_get_keyidx(struct sk_buff *skb);
+u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+
+#endif /* WEP_H */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
new file mode 100644
index 0000000..89ce815
--- /dev/null
+++ b/net/mac80211/wme.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2004, Instant802 Networks, 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/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/types.h>
+#include <net/ip.h>
+#include <net/pkt_sched.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wme.h"
+
+static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
+{
+	return (fc & 0x8C) == 0x88;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+{
+	u8 *data = rx->skb->data;
+	int tid;
+
+	/* does the frame have a qos control field? */
+	if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
+		u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
+		/* frame has qos control */
+		tid = qc[0] & QOS_CONTROL_TID_MASK;
+	} else {
+		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
+			/* Separate TID for management frames */
+			tid = NUM_RX_DATA_QUEUES - 1;
+		} else {
+			/* no qos control present */
+			tid = 0; /* 802.1d - Best Effort */
+		}
+	}
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+	I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
+	if (rx->sta) {
+		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
+	}
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+	rx->u.rx.queue = tid;
+	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
+	 * For now, set skb->priority to 0 for other cases. */
+	rx->skb->priority = (tid > 7) ? 0 : tid;
+
+	return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+{
+	u16 fc = rx->fc;
+	u8 *data = rx->skb->data;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
+
+	if (!WLAN_FC_IS_QOS_DATA(fc))
+		return TXRX_CONTINUE;
+
+	/* remove the qos control field, update frame type and meta-data */
+	memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
+	hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
+	/* change frame type to non QOS */
+	rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
+	hdr->frame_control = cpu_to_le16(fc);
+
+	return TXRX_CONTINUE;
+}
+
+
+#ifdef CONFIG_NET_SCHED
+/* maximum number of hardware queues we support. */
+#define TC_80211_MAX_QUEUES 8
+
+struct ieee80211_sched_data
+{
+	struct tcf_proto *filter_list;
+	struct Qdisc *queues[TC_80211_MAX_QUEUES];
+	struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
+};
+
+
+/* given a data frame determine the 802.1p/1d tag to use */
+static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
+{
+	struct iphdr *ip;
+	int dscp;
+	int offset;
+
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct tcf_result res = { -1, 0 };
+
+	/* if there is a user set filter list, call out to that */
+	if (q->filter_list) {
+		tc_classify(skb, q->filter_list, &res);
+		if (res.class != -1)
+			return res.class;
+	}
+
+	/* skb->priority values from 256->263 are magic values to
+	 * directly indicate a specific 802.1d priority.
+	 * This is used to allow 802.1d priority to be passed directly in
+	 * from VLAN tags, etc. */
+	if (skb->priority >= 256 && skb->priority <= 263)
+		return skb->priority - 256;
+
+	/* check there is a valid IP header present */
+	offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */;
+	if (skb->protocol != __constant_htons(ETH_P_IP) ||
+	    skb->len < offset + sizeof(*ip))
+		return 0;
+
+	ip = (struct iphdr *) (skb->data + offset);
+
+	dscp = ip->tos & 0xfc;
+	if (dscp & 0x1c)
+		return 0;
+	return dscp >> 5;
+}
+
+
+static inline int wme_downgrade_ac(struct sk_buff *skb)
+{
+	switch (skb->priority) {
+	case 6:
+	case 7:
+		skb->priority = 5; /* VO -> VI */
+		return 0;
+	case 4:
+	case 5:
+		skb->priority = 3; /* VI -> BE */
+		return 0;
+	case 0:
+	case 3:
+		skb->priority = 2; /* BE -> BK */
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+
+/* positive return value indicates which queue to use
+ * negative return value indicates to drop the frame */
+static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
+{
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_tx_packet_data *pkt_data =
+		(struct ieee80211_tx_packet_data *) skb->cb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	unsigned short fc = le16_to_cpu(hdr->frame_control);
+	int qos;
+	const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+	/* see if frame is data or non data frame */
+	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
+		/* management frames go on AC_VO queue, but are sent
+		* without QoS control fields */
+		return IEEE80211_TX_QUEUE_DATA0;
+	}
+
+	if (unlikely(pkt_data->mgmt_iface)) {
+		/* Data frames from hostapd (mainly, EAPOL) use AC_VO
+		* and they will include QoS control fields if
+		* the target STA is using WME. */
+		skb->priority = 7;
+		return ieee802_1d_to_ac[skb->priority];
+	}
+
+	/* is this a QoS frame? */
+	qos = fc & IEEE80211_STYPE_QOS_DATA;
+
+	if (!qos) {
+		skb->priority = 0; /* required for correct WPA/11i MIC */
+		return ieee802_1d_to_ac[skb->priority];
+	}
+
+	/* use the data classifier to determine what 802.1d tag the
+	* data frame has */
+	skb->priority = classify_1d(skb, qd);
+
+	/* incase we are a client verify acm is not set for this ac */
+	while (unlikely(local->wmm_acm & BIT(skb->priority))) {
+		if (wme_downgrade_ac(skb)) {
+			/* No AC with lower priority has acm=0,
+			* drop packet. */
+			return -1;
+		}
+	}
+
+	/* look up which queue to use for frames with this 1d tag */
+	return ieee802_1d_to_ac[skb->priority];
+}
+
+
+static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
+{
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_tx_packet_data *pkt_data =
+		(struct ieee80211_tx_packet_data *) skb->cb;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	unsigned short fc = le16_to_cpu(hdr->frame_control);
+	struct Qdisc *qdisc;
+	int err, queue;
+
+	if (pkt_data->requeue) {
+		skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+		qd->q.qlen++;
+		return 0;
+	}
+
+	queue = classify80211(skb, qd);
+
+	/* now we know the 1d priority, fill in the QoS header if there is one
+	 */
+	if (WLAN_FC_IS_QOS_DATA(fc)) {
+		u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
+		u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+		if (local->wifi_wme_noack_test)
+			qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+					QOS_CONTROL_ACK_POLICY_SHIFT;
+		/* qos header is 2 bytes, second reserved */
+		*p = qos_hdr;
+		p++;
+		*p = 0;
+	}
+
+	if (unlikely(queue >= local->hw.queues)) {
+#if 0
+		if (net_ratelimit()) {
+			printk(KERN_DEBUG "%s - queue=%d (hw does not "
+			       "support) -> %d\n",
+			       __func__, queue, local->hw.queues - 1);
+		}
+#endif
+		queue = local->hw.queues - 1;
+	}
+
+	if (unlikely(queue < 0)) {
+			kfree_skb(skb);
+			err = NET_XMIT_DROP;
+	} else {
+		pkt_data->queue = (unsigned int) queue;
+		qdisc = q->queues[queue];
+		err = qdisc->enqueue(skb, qdisc);
+		if (err == NET_XMIT_SUCCESS) {
+			qd->q.qlen++;
+			qd->bstats.bytes += skb->len;
+			qd->bstats.packets++;
+			return NET_XMIT_SUCCESS;
+		}
+	}
+	qd->qstats.drops++;
+	return err;
+}
+
+
+/* TODO: clean up the cases where master_hard_start_xmit
+ * returns non 0 - it shouldn't ever do that. Once done we
+ * can remove this function */
+static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_tx_packet_data *pkt_data =
+		(struct ieee80211_tx_packet_data *) skb->cb;
+	struct Qdisc *qdisc;
+	int err;
+
+	/* we recorded which queue to use earlier! */
+	qdisc = q->queues[pkt_data->queue];
+
+	if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) {
+		qd->q.qlen++;
+		return 0;
+	}
+	qd->qstats.drops++;
+	return err;
+}
+
+
+static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct net_device *dev = qd->dev;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	struct sk_buff *skb;
+	struct Qdisc *qdisc;
+	int queue;
+
+	/* check all the h/w queues in numeric/priority order */
+	for (queue = 0; queue < hw->queues; queue++) {
+		/* see if there is room in this hardware queue */
+		if (test_bit(IEEE80211_LINK_STATE_XOFF,
+			     &local->state[queue]) ||
+		    test_bit(IEEE80211_LINK_STATE_PENDING,
+			     &local->state[queue]))
+			continue;
+
+		/* there is space - try and get a frame */
+		skb = skb_dequeue(&q->requeued[queue]);
+		if (skb) {
+			qd->q.qlen--;
+			return skb;
+		}
+
+		qdisc = q->queues[queue];
+		skb = qdisc->dequeue(qdisc);
+		if (skb) {
+			qd->q.qlen--;
+			return skb;
+		}
+	}
+	/* returning a NULL here when all the h/w queues are full means we
+	 * never need to call netif_stop_queue in the driver */
+	return NULL;
+}
+
+
+static void wme_qdiscop_reset(struct Qdisc* qd)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	int queue;
+
+	/* QUESTION: should we have some hardware flush functionality here? */
+
+	for (queue = 0; queue < hw->queues; queue++) {
+		skb_queue_purge(&q->requeued[queue]);
+		qdisc_reset(q->queues[queue]);
+	}
+	qd->q.qlen = 0;
+}
+
+
+static void wme_qdiscop_destroy(struct Qdisc* qd)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	int queue;
+
+	tcf_destroy_chain(q->filter_list);
+	q->filter_list = NULL;
+
+	for (queue=0; queue < hw->queues; queue++) {
+		skb_queue_purge(&q->requeued[queue]);
+		qdisc_destroy(q->queues[queue]);
+		q->queues[queue] = &noop_qdisc;
+	}
+}
+
+
+/* called whenever parameters are updated on existing qdisc */
+static int wme_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt)
+{
+/*	struct ieee80211_sched_data *q = qdisc_priv(qd);
+*/
+	/* check our options block is the right size */
+	/* copy any options to our local structure */
+/*	Ignore options block for now - always use static mapping
+	struct tc_ieee80211_qopt *qopt = RTA_DATA(opt);
+
+	if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
+		return -EINVAL;
+	memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue));
+*/
+	return 0;
+}
+
+
+/* called during initial creation of qdisc on device */
+static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct net_device *dev = qd->dev;
+	struct ieee80211_local *local;
+	int queues;
+	int err = 0, i;
+
+	/* check that device is a mac80211 device */
+	if (!dev->ieee80211_ptr ||
+	    dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+		return -EINVAL;
+
+	/* check this device is an ieee80211 master type device */
+	if (dev->type != ARPHRD_IEEE80211)
+		return -EINVAL;
+
+	/* check that there is no qdisc currently attached to device
+	 * this ensures that we will be the root qdisc. (I can't find a better
+	 * way to test this explicitly) */
+	if (dev->qdisc_sleeping != &noop_qdisc)
+		return -EINVAL;
+
+	if (qd->flags & TCQ_F_INGRESS)
+		return -EINVAL;
+
+	local = wdev_priv(dev->ieee80211_ptr);
+	queues = local->hw.queues;
+
+	/* if options were passed in, set them */
+	if (opt) {
+		err = wme_qdiscop_tune(qd, opt);
+	}
+
+	/* create child queues */
+	for (i = 0; i < queues; i++) {
+		skb_queue_head_init(&q->requeued[i]);
+		q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
+						 qd->handle);
+		if (q->queues[i] == 0) {
+			q->queues[i] = &noop_qdisc;
+			printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i);
+		}
+	}
+
+	return err;
+}
+
+static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
+{
+/*	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	unsigned char *p = skb->tail;
+	struct tc_ieee80211_qopt opt;
+
+	memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1);
+	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+*/	return skb->len;
+/*
+rtattr_failure:
+	skb_trim(skb, p - skb->data);*/
+	return -1;
+}
+
+
+static int wme_classop_graft(struct Qdisc *qd, unsigned long arg,
+			     struct Qdisc *new, struct Qdisc **old)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	unsigned long queue = arg - 1;
+
+	if (queue >= hw->queues)
+		return -EINVAL;
+
+	if (!new)
+		new = &noop_qdisc;
+
+	sch_tree_lock(qd);
+	*old = q->queues[queue];
+	q->queues[queue] = new;
+	qdisc_reset(*old);
+	sch_tree_unlock(qd);
+
+	return 0;
+}
+
+
+static struct Qdisc *
+wme_classop_leaf(struct Qdisc *qd, unsigned long arg)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	unsigned long queue = arg - 1;
+
+	if (queue >= hw->queues)
+		return NULL;
+
+	return q->queues[queue];
+}
+
+
+static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid)
+{
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	unsigned long queue = TC_H_MIN(classid);
+
+	if (queue - 1 >= hw->queues)
+		return 0;
+
+	return queue;
+}
+
+
+static unsigned long wme_classop_bind(struct Qdisc *qd, unsigned long parent,
+				      u32 classid)
+{
+	return wme_classop_get(qd, classid);
+}
+
+
+static void wme_classop_put(struct Qdisc *q, unsigned long cl)
+{
+}
+
+
+static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent,
+			      struct rtattr **tca, unsigned long *arg)
+{
+	unsigned long cl = *arg;
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+
+	if (cl - 1 > hw->queues)
+		return -ENOENT;
+
+	/* TODO: put code to program hardware queue parameters here,
+	 * to allow programming from tc command line */
+
+	return 0;
+}
+
+
+/* we don't support deleting hardware queues
+ * when we add WMM-SA support - TSPECs may be deleted here */
+static int wme_classop_delete(struct Qdisc *qd, unsigned long cl)
+{
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+
+	if (cl - 1 > hw->queues)
+		return -ENOENT;
+	return 0;
+}
+
+
+static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl,
+				  struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+
+	if (cl - 1 > hw->queues)
+		return -ENOENT;
+	tcm->tcm_handle = TC_H_MIN(cl);
+	tcm->tcm_parent = qd->handle;
+	tcm->tcm_info = q->queues[cl-1]->handle; /* do we need this? */
+	return 0;
+}
+
+
+static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg)
+{
+	struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	int queue;
+
+	if (arg->stop)
+		return;
+
+	for (queue = 0; queue < hw->queues; queue++) {
+		if (arg->count < arg->skip) {
+			arg->count++;
+			continue;
+		}
+		/* we should return classids for our internal queues here
+		 * as well as the external ones */
+		if (arg->fn(qd, queue+1, arg) < 0) {
+			arg->stop = 1;
+			break;
+		}
+		arg->count++;
+	}
+}
+
+
+static struct tcf_proto ** wme_classop_find_tcf(struct Qdisc *qd,
+						unsigned long cl)
+{
+	struct ieee80211_sched_data *q = qdisc_priv(qd);
+
+	if (cl)
+		return NULL;
+
+	return &q->filter_list;
+}
+
+
+/* this qdisc is classful (i.e. has classes, some of which may have leaf qdiscs attached)
+ * - these are the operations on the classes */
+static struct Qdisc_class_ops class_ops =
+{
+	.graft = wme_classop_graft,
+	.leaf = wme_classop_leaf,
+
+	.get = wme_classop_get,
+	.put = wme_classop_put,
+	.change = wme_classop_change,
+	.delete = wme_classop_delete,
+	.walk = wme_classop_walk,
+
+	.tcf_chain = wme_classop_find_tcf,
+	.bind_tcf = wme_classop_bind,
+	.unbind_tcf = wme_classop_put,
+
+	.dump = wme_classop_dump_class,
+};
+
+
+/* queueing discipline operations */
+static struct Qdisc_ops wme_qdisc_ops =
+{
+	.next = NULL,
+	.cl_ops = &class_ops,
+	.id = "ieee80211",
+	.priv_size = sizeof(struct ieee80211_sched_data),
+
+	.enqueue = wme_qdiscop_enqueue,
+	.dequeue = wme_qdiscop_dequeue,
+	.requeue = wme_qdiscop_requeue,
+	.drop = NULL, /* drop not needed since we are always the root qdisc */
+
+	.init = wme_qdiscop_init,
+	.reset = wme_qdiscop_reset,
+	.destroy = wme_qdiscop_destroy,
+	.change = wme_qdiscop_tune,
+
+	.dump = wme_qdiscop_dump,
+};
+
+
+void ieee80211_install_qdisc(struct net_device *dev)
+{
+	struct Qdisc *qdisc;
+
+	qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT);
+	if (!qdisc) {
+		printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
+		return;
+	}
+
+	/* same handle as would be allocated by qdisc_alloc_handle() */
+	qdisc->handle = 0x80010000;
+
+	qdisc_lock_tree(dev);
+	list_add_tail(&qdisc->list, &dev->qdisc_list);
+	dev->qdisc_sleeping = qdisc;
+	qdisc_unlock_tree(dev);
+}
+
+
+int ieee80211_qdisc_installed(struct net_device *dev)
+{
+	return dev->qdisc_sleeping->ops == &wme_qdisc_ops;
+}
+
+
+int ieee80211_wme_register(void)
+{
+	return register_qdisc(&wme_qdisc_ops);
+}
+
+
+void ieee80211_wme_unregister(void)
+{
+	unregister_qdisc(&wme_qdisc_ops);
+}
+#endif /* CONFIG_NET_SCHED */
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
new file mode 100644
index 0000000..f0bff10
--- /dev/null
+++ b/net/mac80211/wme.h
@@ -0,0 +1,57 @@
+/*
+ * IEEE 802.11 driver (80211.o) - QoS datatypes
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape 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 _WME_H
+#define _WME_H
+
+#include <linux/netdevice.h>
+#include "ieee80211_i.h"
+
+#define QOS_CONTROL_LEN 2
+
+#define QOS_CONTROL_ACK_POLICY_NORMAL 0
+#define QOS_CONTROL_ACK_POLICY_NOACK 1
+
+#define QOS_CONTROL_TID_MASK 0x0f
+#define QOS_CONTROL_ACK_POLICY_SHIFT 5
+
+#define QOS_CONTROL_TAG1D_MASK 0x07
+
+ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx);
+
+#ifdef CONFIG_NET_SCHED
+void ieee80211_install_qdisc(struct net_device *dev);
+int ieee80211_qdisc_installed(struct net_device *dev);
+
+int ieee80211_wme_register(void);
+void ieee80211_wme_unregister(void);
+#else
+static inline void ieee80211_install_qdisc(struct net_device *dev)
+{
+}
+static inline int ieee80211_qdisc_installed(struct net_device *dev)
+{
+	return 0;
+}
+
+static inline int ieee80211_wme_register(void)
+{
+	return 0;
+}
+static inline void ieee80211_wme_unregister(void)
+{
+}
+#endif /* CONFIG_NET_SCHED */
+
+#endif /* _WME_H */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
new file mode 100644
index 0000000..783af32
--- /dev/null
+++ b/net/mac80211/wpa.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, 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/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/compiler.h>
+#include <net/iw_handler.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_common.h"
+#include "ieee80211_i.h"
+#include "michael.h"
+#include "tkip.h"
+#include "aes_ccm.h"
+#include "wpa.h"
+
+static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
+				  u8 *qos_tid, u8 **data, size_t *data_len)
+{
+	struct ieee80211_hdr *hdr;
+	size_t hdrlen;
+	u16 fc;
+	int a4_included;
+	u8 *pos;
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
+
+	hdrlen = 24;
+	if ((fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) ==
+	    (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+		hdrlen += ETH_ALEN;
+		*sa = hdr->addr4;
+		*da = hdr->addr3;
+	} else if (fc & IEEE80211_FCTL_FROMDS) {
+		*sa = hdr->addr3;
+		*da = hdr->addr1;
+	} else if (fc & IEEE80211_FCTL_TODS) {
+		*sa = hdr->addr2;
+		*da = hdr->addr3;
+	} else {
+		*sa = hdr->addr2;
+		*da = hdr->addr1;
+	}
+
+	if (fc & 0x80)
+		hdrlen += 2;
+
+	*data = skb->data + hdrlen;
+	*data_len = skb->len - hdrlen;
+
+	a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+		(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+	    fc & IEEE80211_STYPE_QOS_DATA) {
+		pos = (u8 *) &hdr->addr4;
+		if (a4_included)
+			pos += 6;
+		*qos_tid = pos[0] & 0x0f;
+		*qos_tid |= 0x80; /* qos_included flag */
+	} else
+		*qos_tid = 0;
+
+	return skb->len < hdrlen ? -1 : 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
+{
+	u8 *data, *sa, *da, *key, *mic, qos_tid;
+	size_t data_len;
+	u16 fc;
+	struct sk_buff *skb = tx->skb;
+	int authenticator;
+	int wpa_test = 0;
+
+	fc = tx->fc;
+
+	if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 ||
+	    !WLAN_FC_DATA_PRESENT(fc))
+		return TXRX_CONTINUE;
+
+	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
+		return TXRX_DROP;
+
+	if (!tx->key->force_sw_encrypt &&
+	    !tx->fragmented &&
+	    !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) &&
+	    !wpa_test) {
+		/* hwaccel - with no need for preallocated room for Michael MIC
+		 */
+		return TXRX_CONTINUE;
+	}
+
+	if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
+		I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+		if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
+					      MICHAEL_MIC_LEN + TKIP_ICV_LEN,
+					      GFP_ATOMIC))) {
+			printk(KERN_DEBUG "%s: failed to allocate more memory "
+			       "for Michael MIC\n", tx->dev->name);
+			return TXRX_DROP;
+		}
+	}
+
+#if 0
+	authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
+#else
+	authenticator = 1;
+#endif
+	key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
+			    ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
+	mic = skb_put(skb, MICHAEL_MIC_LEN);
+	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
+
+	return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
+{
+	u8 *data, *sa, *da, *key = NULL, qos_tid;
+	size_t data_len;
+	u16 fc;
+	u8 mic[MICHAEL_MIC_LEN];
+	struct sk_buff *skb = rx->skb;
+	int authenticator = 1, wpa_test = 0;
+
+	fc = rx->fc;
+
+	/* If device handles decryption totally, skip this check */
+	if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) ||
+	    (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC))
+		return TXRX_CONTINUE;
+
+	if (!rx->key || rx->key->alg != ALG_TKIP ||
+	    !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
+		return TXRX_CONTINUE;
+
+	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+	    !rx->key->force_sw_encrypt) {
+		if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+			if (skb->len < MICHAEL_MIC_LEN)
+				return TXRX_DROP;
+		}
+		/* Need to verify Michael MIC sometimes in software even when
+		 * hwaccel is used. Atheros ar5212: fragmented frames and QoS
+		 * frames. */
+		if (!rx->fragmented && !wpa_test)
+			goto remove_mic;
+	}
+
+	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
+	    || data_len < MICHAEL_MIC_LEN)
+		return TXRX_DROP;
+
+	data_len -= MICHAEL_MIC_LEN;
+
+#if 0
+	authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
+#else
+	authenticator = 1;
+#endif
+	key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
+			    ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
+	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
+	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
+		if (!rx->u.rx.ra_match)
+			return TXRX_DROP;
+
+		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
+		       MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
+
+		do {
+			struct ieee80211_hdr *hdr;
+			union iwreq_data wrqu;
+			char *buf = kmalloc(128, GFP_ATOMIC);
+			if (!buf)
+				break;
+
+			/* TODO: needed parameters: count, key type, TSC */
+			hdr = (struct ieee80211_hdr *) skb->data;
+			sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+				"keyid=%d %scast addr=" MAC_FMT ")",
+				rx->key->keyidx,
+				hdr->addr1[0] & 0x01 ? "broad" : "uni",
+				MAC_ARG(hdr->addr2));
+			memset(&wrqu, 0, sizeof(wrqu));
+			wrqu.data.length = strlen(buf);
+			wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
+			kfree(buf);
+		} while (0);
+
+		if (!rx->local->apdev)
+			return TXRX_DROP;
+
+		ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+				  ieee80211_msg_michael_mic_failure);
+
+		return TXRX_QUEUED;
+	}
+
+ remove_mic:
+	/* remove Michael MIC from payload */
+	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+
+	return TXRX_CONTINUE;
+}
+
+
+static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
+			    struct sk_buff *skb, int test)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_key *key = tx->key;
+	int hdrlen, len, tailneed;
+	u16 fc;
+	u8 *pos;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+	len = skb->len - hdrlen;
+
+	tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN;
+	if ((skb_headroom(skb) < TKIP_IV_LEN ||
+	     skb_tailroom(skb) < tailneed)) {
+		I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+		if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
+					      GFP_ATOMIC)))
+			return -1;
+	}
+
+	pos = skb_push(skb, TKIP_IV_LEN);
+	memmove(pos, pos + TKIP_IV_LEN, hdrlen);
+	pos += hdrlen;
+
+	/* Increase IV for the frame */
+	key->u.tkip.iv16++;
+	if (key->u.tkip.iv16 == 0)
+		key->u.tkip.iv32++;
+
+	if (!tx->key->force_sw_encrypt) {
+		u32 flags = tx->local->hw.flags;
+		hdr = (struct ieee80211_hdr *)skb->data;
+
+		/* hwaccel - with preallocated room for IV */
+		ieee80211_tkip_add_iv(pos, key,
+				      (u8) (key->u.tkip.iv16 >> 8),
+				      (u8) (((key->u.tkip.iv16 >> 8) | 0x20) &
+					    0x7f),
+				      (u8) key->u.tkip.iv16);
+
+		if (flags & IEEE80211_HW_TKIP_REQ_PHASE2_KEY)
+			ieee80211_tkip_gen_rc4key(key, hdr->addr2,
+						  tx->u.tx.control->tkip_key);
+		else if (flags & IEEE80211_HW_TKIP_REQ_PHASE1_KEY) {
+			if (key->u.tkip.iv16 == 0 ||
+			    !key->u.tkip.tx_initialized) {
+				ieee80211_tkip_gen_phase1key(key, hdr->addr2,
+					    (u16 *)tx->u.tx.control->tkip_key);
+				key->u.tkip.tx_initialized = 1;
+				tx->u.tx.control->flags |=
+					    IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
+			} else
+				tx->u.tx.control->flags &=
+					    ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
+		}
+
+		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		return 0;
+	}
+
+	/* Add room for ICV */
+	skb_put(skb, TKIP_ICV_LEN);
+
+	hdr = (struct ieee80211_hdr *) skb->data;
+	ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
+				    key, pos, len, hdr->addr2);
+	return 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	u16 fc;
+	struct ieee80211_key *key = tx->key;
+	struct sk_buff *skb = tx->skb;
+	int wpa_test = 0, test = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc))
+		return TXRX_CONTINUE;
+
+	tx->u.tx.control->icv_len = TKIP_ICV_LEN;
+	tx->u.tx.control->iv_len = TKIP_IV_LEN;
+	ieee80211_tx_set_iswep(tx);
+
+	if (!tx->key->force_sw_encrypt &&
+	    !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+	    !wpa_test) {
+		/* hwaccel - with no need for preallocated room for IV/ICV */
+		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		return TXRX_CONTINUE;
+	}
+
+	if (tkip_encrypt_skb(tx, skb, test) < 0)
+		return TXRX_DROP;
+
+	if (tx->u.tx.extra_frag) {
+		int i;
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+			    < 0)
+				return TXRX_DROP;
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+	u16 fc;
+	int hdrlen, res, hwaccel = 0, wpa_test = 0;
+	struct ieee80211_key *key = rx->key;
+	struct sk_buff *skb = rx->skb;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (!rx->key || rx->key->alg != ALG_TKIP ||
+	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+		return TXRX_CONTINUE;
+
+	if (!rx->sta || skb->len - hdrlen < 12)
+		return TXRX_DROP;
+
+	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+	    !rx->key->force_sw_encrypt) {
+		if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
+			/* Hardware takes care of all processing, including
+			 * replay protection, so no need to continue here. */
+			return TXRX_CONTINUE;
+		}
+
+		/* let TKIP code verify IV, but skip decryption */
+		hwaccel = 1;
+	}
+
+	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
+					  key, skb->data + hdrlen,
+					  skb->len - hdrlen, rx->sta->addr,
+					  hwaccel, rx->u.rx.queue);
+	if (res != TKIP_DECRYPT_OK || wpa_test) {
+		printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from "
+		       MAC_FMT " (res=%d)\n",
+		       rx->dev->name, MAC_ARG(rx->sta->addr), res);
+		return TXRX_DROP;
+	}
+
+	/* Trim ICV */
+	skb_trim(skb, skb->len - TKIP_ICV_LEN);
+
+	/* Remove IV */
+	memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
+	skb_pull(skb, TKIP_IV_LEN);
+
+	return TXRX_CONTINUE;
+}
+
+
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
+				int encrypted)
+{
+	u16 fc;
+	int a4_included, qos_included;
+	u8 qos_tid, *fc_pos, *data, *sa, *da;
+	int len_a;
+	size_t data_len;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+	fc_pos = (u8 *) &hdr->frame_control;
+	fc = fc_pos[0] ^ (fc_pos[1] << 8);
+	a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+		(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+
+	ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len);
+	data_len -= CCMP_HDR_LEN + (encrypted ? CCMP_MIC_LEN : 0);
+	if (qos_tid & 0x80) {
+		qos_included = 1;
+		qos_tid &= 0x0f;
+	} else
+		qos_included = 0;
+	/* First block, b_0 */
+
+	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
+	/* Nonce: QoS Priority | A2 | PN */
+	b_0[1] = qos_tid;
+	memcpy(&b_0[2], hdr->addr2, 6);
+	memcpy(&b_0[8], pn, CCMP_PN_LEN);
+	/* l(m) */
+	b_0[14] = (data_len >> 8) & 0xff;
+	b_0[15] = data_len & 0xff;
+
+
+	/* AAD (extra authenticate-only data) / masked 802.11 header
+	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
+
+	len_a = a4_included ? 28 : 22;
+	if (qos_included)
+		len_a += 2;
+
+	aad[0] = 0; /* (len_a >> 8) & 0xff; */
+	aad[1] = len_a & 0xff;
+	/* Mask FC: zero subtype b4 b5 b6 */
+	aad[2] = fc_pos[0] & ~(BIT(4) | BIT(5) | BIT(6));
+	/* Retry, PwrMgt, MoreData; set Protected */
+	aad[3] = (fc_pos[1] & ~(BIT(3) | BIT(4) | BIT(5))) | BIT(6);
+	memcpy(&aad[4], &hdr->addr1, 18);
+
+	/* Mask Seq#, leave Frag# */
+	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
+	aad[23] = 0;
+	if (a4_included) {
+		memcpy(&aad[24], hdr->addr4, 6);
+		aad[30] = 0;
+		aad[31] = 0;
+	} else
+		memset(&aad[24], 0, 8);
+	if (qos_included) {
+		u8 *dpos = &aad[a4_included ? 30 : 24];
+
+		/* Mask QoS Control field */
+		dpos[0] = qos_tid;
+		dpos[1] = 0;
+	}
+}
+
+
+static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
+{
+	hdr[0] = pn[5];
+	hdr[1] = pn[4];
+	hdr[2] = 0;
+	hdr[3] = 0x20 | (key_id << 6);
+	hdr[4] = pn[3];
+	hdr[5] = pn[2];
+	hdr[6] = pn[1];
+	hdr[7] = pn[0];
+}
+
+
+static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
+{
+	pn[0] = hdr[7];
+	pn[1] = hdr[6];
+	pn[2] = hdr[5];
+	pn[3] = hdr[4];
+	pn[4] = hdr[1];
+	pn[5] = hdr[0];
+	return (hdr[3] >> 6) & 0x03;
+}
+
+
+static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
+			    struct sk_buff *skb, int test)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_key *key = tx->key;
+	int hdrlen, len, tailneed;
+	u16 fc;
+	u8 *pos, *pn, *b_0, *aad, *scratch;
+	int i;
+
+	scratch = key->u.ccmp.tx_crypto_buf;
+	b_0 = scratch + 3 * AES_BLOCK_LEN;
+	aad = scratch + 4 * AES_BLOCK_LEN;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+	len = skb->len - hdrlen;
+
+	tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN;
+
+	if ((skb_headroom(skb) < CCMP_HDR_LEN ||
+	     skb_tailroom(skb) < tailneed)) {
+		I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+		if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
+					      GFP_ATOMIC)))
+			return -1;
+	}
+
+	pos = skb_push(skb, CCMP_HDR_LEN);
+	memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+	hdr = (struct ieee80211_hdr *) pos;
+	pos += hdrlen;
+
+	/* PN = PN + 1 */
+	pn = key->u.ccmp.tx_pn;
+
+	for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
+		pn[i]++;
+		if (pn[i])
+			break;
+	}
+
+	ccmp_pn2hdr(pos, pn, key->keyidx);
+
+	if (!key->force_sw_encrypt) {
+		/* hwaccel - with preallocated room for CCMP header */
+		tx->u.tx.control->key_idx = key->hw_key_idx;
+		return 0;
+	}
+
+	pos += CCMP_HDR_LEN;
+	ccmp_special_blocks(skb, pn, b_0, aad, 0);
+	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, b_0, aad, pos, len,
+				  pos, skb_put(skb, CCMP_MIC_LEN));
+
+	return 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+	struct ieee80211_key *key = tx->key;
+	u16 fc;
+	struct sk_buff *skb = tx->skb;
+	int test = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+	if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc))
+		return TXRX_CONTINUE;
+
+	tx->u.tx.control->icv_len = CCMP_MIC_LEN;
+	tx->u.tx.control->iv_len = CCMP_HDR_LEN;
+	ieee80211_tx_set_iswep(tx);
+
+	if (!tx->key->force_sw_encrypt &&
+	    !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
+		/* hwaccel - with no need for preallocated room for CCMP "
+		 * header or MIC fields */
+		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		return TXRX_CONTINUE;
+	}
+
+	if (ccmp_encrypt_skb(tx, skb, test) < 0)
+		return TXRX_DROP;
+
+	if (tx->u.tx.extra_frag) {
+		int i;
+
+		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+			    < 0)
+				return TXRX_DROP;
+		}
+	}
+
+	return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+	u16 fc;
+	int hdrlen;
+	struct ieee80211_key *key = rx->key;
+	struct sk_buff *skb = rx->skb;
+	u8 pn[CCMP_PN_LEN];
+	int data_len;
+
+	fc = le16_to_cpu(hdr->frame_control);
+	hdrlen = ieee80211_get_hdrlen(fc);
+
+	if (!key || key->alg != ALG_CCMP ||
+	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+		return TXRX_CONTINUE;
+
+	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
+	if (!rx->sta || data_len < 0)
+		return TXRX_DROP;
+
+	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+	    !key->force_sw_encrypt &&
+	    !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
+		return TXRX_CONTINUE;
+
+	(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
+
+	if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
+#ifdef CONFIG_MAC80211_DEBUG
+		u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+		printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
+		       MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
+		       "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
+		       MAC_ARG(rx->sta->addr),
+		       pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
+		       ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
+#endif /* CONFIG_MAC80211_DEBUG */
+		key->u.ccmp.replays++;
+		return TXRX_DROP;
+	}
+
+	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+	    !key->force_sw_encrypt) {
+		/* hwaccel has already decrypted frame and verified MIC */
+	} else {
+		u8 *scratch, *b_0, *aad;
+
+		scratch = key->u.ccmp.rx_crypto_buf;
+		b_0 = scratch + 3 * AES_BLOCK_LEN;
+		aad = scratch + 4 * AES_BLOCK_LEN;
+
+		ccmp_special_blocks(skb, pn, b_0, aad, 1);
+
+		if (ieee80211_aes_ccm_decrypt(
+			    key->u.ccmp.tfm, scratch, b_0, aad,
+			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
+			    skb->data + skb->len - CCMP_MIC_LEN,
+			    skb->data + hdrlen + CCMP_HDR_LEN)) {
+			printk(KERN_DEBUG "%s: CCMP decrypt failed for RX "
+			       "frame from " MAC_FMT "\n", rx->dev->name,
+			       MAC_ARG(rx->sta->addr));
+			return TXRX_DROP;
+		}
+	}
+
+	memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN);
+
+	/* Remove CCMP header and MIC */
+	skb_trim(skb, skb->len - CCMP_MIC_LEN);
+	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
+	skb_pull(skb, CCMP_HDR_LEN);
+
+	return TXRX_CONTINUE;
+}
+
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h
new file mode 100644
index 0000000..da3b959
--- /dev/null
+++ b/net/mac80211/wpa.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, 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 WPA_H
+#define WPA_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+
+ieee80211_txrx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx);
+
+#endif /* WPA_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 54698af..ea6211c 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -25,6 +25,7 @@ config NETFILTER_NETLINK_LOG
 	  and is also scheduled to replace the old syslog-based ipt_LOG
 	  and ip6t_LOG modules.
 
+# Rename this to NF_CONNTRACK in a 2.6.25
 config NF_CONNTRACK_ENABLED
 	tristate "Netfilter connection tracking support"
 	help
@@ -39,42 +40,9 @@ config NF_CONNTRACK_ENABLED
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
-choice
-	prompt "Netfilter connection tracking support"
-	depends on NF_CONNTRACK_ENABLED
-
-config NF_CONNTRACK_SUPPORT
-	bool "Layer 3 Independent Connection tracking"
-	help
-	  Layer 3 independent connection tracking is experimental scheme
-	  which generalize ip_conntrack to support other layer 3 protocols.
-
-	  This is required to do Masquerading or other kinds of Network
-	  Address Translation (except for Fast NAT).  It can also be used to
-	  enhance packet filtering (see `Connection state match support'
-	  below).
-
-config IP_NF_CONNTRACK_SUPPORT
-	bool "Layer 3 Dependent Connection tracking (OBSOLETE)"
-	help
-	  The old, Layer 3 dependent ip_conntrack subsystem of netfilter.
-
-	  This is required to do Masquerading or other kinds of Network
-	  Address Translation (except for Fast NAT).  It can also be used to
-	  enhance packet filtering (see `Connection state match support'
-	  below).
-
-endchoice
-
 config NF_CONNTRACK
 	tristate
-	default m if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m
-	default y if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y
-
-config IP_NF_CONNTRACK
-	tristate
-	default m if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m
-	default y if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y
+	default NF_CONNTRACK_ENABLED
 
 config NF_CT_ACCT
 	bool "Connection tracking flow accounting"
@@ -132,7 +100,7 @@ config NF_CT_PROTO_SCTP
 	  tracking code will be able to do state tracking on SCTP connections.
 
 	  If you want to compile it as a module, say M here and read
-	  Documentation/modules.txt.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NF_CONNTRACK_AMANDA
 	tristate "Amanda backup protocol support"
@@ -303,17 +271,16 @@ config NETFILTER_XT_TARGET_CONNMARK
 	tristate  '"CONNMARK" target support'
 	depends on NETFILTER_XTABLES
 	depends on IP_NF_MANGLE || IP6_NF_MANGLE
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
-	select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
-	select NF_CONNTRACK_MARK if NF_CONNTRACK
+	depends on NF_CONNTRACK
+	select NF_CONNTRACK_MARK
 	help
 	  This option adds a `CONNMARK' target, which allows one to manipulate
 	  the connection mark value.  Similar to the MARK target, but
 	  affects the connection mark value rather than the packet mark value.
 	
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  The module will be called
-	  ipt_CONNMARK.o.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  The module will be called
+	  ipt_CONNMARK.ko.  If unsure, say `N'.
 
 config NETFILTER_XT_TARGET_DSCP
 	tristate '"DSCP" target support'
@@ -366,7 +333,7 @@ config NETFILTER_XT_TARGET_NOTRACK
 	tristate  '"NOTRACK" target support'
 	depends on NETFILTER_XTABLES
 	depends on IP_NF_RAW || IP6_NF_RAW
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	depends on NF_CONNTRACK
 	help
 	  The NOTRACK target allows a select rule to specify
 	  which packets *not* to enter the conntrack/NAT
@@ -374,7 +341,7 @@ config NETFILTER_XT_TARGET_NOTRACK
 	  no protocol helpers for the selected packets).
 	
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_TARGET_SECMARK
 	tristate '"SECMARK" target support'
@@ -387,9 +354,7 @@ config NETFILTER_XT_TARGET_SECMARK
 
 config NETFILTER_XT_TARGET_CONNSECMARK
 	tristate '"CONNSECMARK" target support'
-	depends on NETFILTER_XTABLES && \
-		   ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \
-		    (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK))
+	depends on NETFILTER_XTABLES && NF_CONNTRACK && NF_CONNTRACK_SECMARK
 	help
 	  The CONNSECMARK target copies security markings from packets
 	  to connections, and restores security markings from connections
@@ -432,39 +397,37 @@ config NETFILTER_XT_MATCH_COMMENT
 	  comments in your iptables ruleset.
 
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_CONNBYTES
 	tristate  '"connbytes" per-connection counter match support'
 	depends on NETFILTER_XTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
-	select IP_NF_CT_ACCT if IP_NF_CONNTRACK
-	select NF_CT_ACCT if NF_CONNTRACK
+	depends on NF_CONNTRACK
+	select NF_CT_ACCT
 	help
 	  This option adds a `connbytes' match, which allows you to match the
 	  number of bytes and/or packets for each direction within a connection.
 
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_CONNMARK
 	tristate  '"connmark" connection mark match support'
 	depends on NETFILTER_XTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
-	select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
-	select NF_CONNTRACK_MARK if NF_CONNTRACK
+	depends on NF_CONNTRACK
+	select NF_CONNTRACK_MARK
 	help
 	  This option adds a `connmark' match, which allows you to match the
 	  connection mark value previously set for the session by `CONNMARK'. 
 	
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  The module will be called
-	  ipt_connmark.o.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  The module will be called
+	  ipt_connmark.ko.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_CONNTRACK
 	tristate '"conntrack" connection tracking match support'
 	depends on NETFILTER_XTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	depends on NF_CONNTRACK
 	help
 	  This is a general conntrack match module, a superset of the state match.
 
@@ -483,7 +446,7 @@ config NETFILTER_XT_MATCH_DCCP
 	  and DCCP flags.
 
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_DSCP
 	tristate '"DSCP" match support'
@@ -508,7 +471,7 @@ config NETFILTER_XT_MATCH_ESP
 config NETFILTER_XT_MATCH_HELPER
 	tristate '"helper" match support'
 	depends on NETFILTER_XTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	depends on NF_CONNTRACK
 	help
 	  Helper matching allows you to match packets in dynamic connections
 	  tracked by a conntrack-helper, ie. ip_conntrack_ftp
@@ -602,7 +565,7 @@ config NETFILTER_XT_MATCH_QUOTA
 	  byte counter.
 
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_REALM
 	tristate  '"realm" match support'
@@ -616,7 +579,7 @@ config NETFILTER_XT_MATCH_REALM
 	  in tc world.
 	
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_SCTP
 	tristate  '"sctp" protocol match support (EXPERIMENTAL)'
@@ -627,12 +590,12 @@ config NETFILTER_XT_MATCH_SCTP
 	  and SCTP chunk types.
 
 	  If you want to compile it as a module, say M here and read
-	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+	  <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_STATE
 	tristate '"state" match support'
 	depends on NETFILTER_XTABLES
-	depends on IP_NF_CONNTRACK || NF_CONNTRACK
+	depends on NF_CONNTRACK
 	help
 	  Connection state matching allows you to match packets based on their
 	  relationship to a tracked connection (ie. previous packets).  This
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index c3ebdbd..a84478e 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -5,10 +5,6 @@
  * way.
  *
  * Rusty Russell (C)2000 -- This code is GPL.
- *
- * February 2000: Modified by James Morris to have 1 queue per protocol.
- * 15-Mar-2000:   Added NF_REPEAT --RR.
- * 08-May-2003:	  Internal logging interface added by Jozsef Kadlecsik.
  */
 #include <linux/kernel.h>
 #include <linux/netfilter.h>
@@ -244,6 +240,7 @@ void nf_proto_csum_replace4(__sum16 *sum
 }
 EXPORT_SYMBOL(nf_proto_csum_replace4);
 
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 /* 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
    manufactured ICMP or RST packets will not be associated with it. */
@@ -264,6 +261,22 @@ void nf_ct_attach(struct sk_buff *new, s
 }
 EXPORT_SYMBOL(nf_ct_attach);
 
+void (*nf_ct_destroy)(struct nf_conntrack *);
+EXPORT_SYMBOL(nf_ct_destroy);
+
+void nf_conntrack_destroy(struct nf_conntrack *nfct)
+{
+	void (*destroy)(struct nf_conntrack *);
+
+	rcu_read_lock();
+	destroy = rcu_dereference(nf_ct_destroy);
+	BUG_ON(destroy == NULL);
+	destroy(nfct);
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_conntrack_destroy);
+#endif /* CONFIG_NF_CONNTRACK */
+
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry *proc_net_netfilter;
 EXPORT_SYMBOL(proc_net_netfilter);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index b3a70eb..e132c8a 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -9,24 +9,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.
- *
- * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
- *	- new API and handling of conntrack/nat helpers
- *	- now capable of multiple expectations for one master
- * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
- *	- add usage/reference counts to ip_conntrack_expect
- *	- export ip_conntrack[_expect]_{find_get,put} functions
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- generalize L3 protocol denendent part.
- * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- add support various size of conntrack structures.
- * 26 Jan 2006: Harald Welte <laforge@netfilter.org>
- * 	- restructure nf_conn (introduce nf_conn_help)
- * 	- redesign 'features' how they were originally intended
- * 26 Feb 2006: Pablo Neira Ayuso <pablo@eurodev.net>
- * 	- add support for L3 protocol module load on demand.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_core.c
  */
 
 #include <linux/types.h>
@@ -128,10 +110,11 @@ static u_int32_t __hash_conntrack(const 
 				  unsigned int size, unsigned int rnd)
 {
 	unsigned int a, b;
-	a = jhash((void *)tuple->src.u3.all, sizeof(tuple->src.u3.all),
-		  ((tuple->src.l3num) << 16) | tuple->dst.protonum);
-	b = jhash((void *)tuple->dst.u3.all, sizeof(tuple->dst.u3.all),
-			(tuple->src.u.all << 16) | tuple->dst.u.all);
+
+	a = jhash2(tuple->src.u3.all, ARRAY_SIZE(tuple->src.u3.all),
+		   (tuple->src.l3num << 16) | tuple->dst.protonum);
+	b = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
+		   (tuple->src.u.all << 16) | tuple->dst.u.all);
 
 	return jhash_2words(a, b, rnd) % size;
 }
@@ -633,13 +616,11 @@ __nf_conntrack_alloc(const struct nf_con
 	memset(conntrack, 0, nf_ct_cache[features].size);
 	conntrack->features = features;
 	atomic_set(&conntrack->ct_general.use, 1);
-	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
 	/* Don't set timer yet: wait for confirmation */
-	init_timer(&conntrack->timeout);
-	conntrack->timeout.data = (unsigned long)conntrack;
-	conntrack->timeout.function = death_by_timeout;
+	setup_timer(&conntrack->timeout, death_by_timeout,
+		    (unsigned long)conntrack);
 	read_unlock_bh(&nf_ct_cache_lock);
 
 	return conntrack;
@@ -768,7 +749,7 @@ resolve_normal_ct(struct sk_buff *skb,
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conn *ct;
 
-	if (!nf_ct_get_tuple(skb, (unsigned int)(skb->nh.raw - skb->data),
+	if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
 			     dataoff, l3num, protonum, &tuple, l3proto,
 			     l4proto)) {
 		DEBUGP("resolve_normal_ct: Can't get tuple\n");
@@ -960,7 +941,7 @@ #ifdef CONFIG_NF_CT_ACCT
 	if (do_acct) {
 		ct->counters[CTINFO2DIR(ctinfo)].packets++;
 		ct->counters[CTINFO2DIR(ctinfo)].bytes +=
-			skb->len - (unsigned int)(skb->nh.raw - skb->data);
+			skb->len - skb_network_offset(skb);
 
 		if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000)
 		    || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000))
@@ -1140,6 +1121,8 @@ void nf_conntrack_cleanup(void)
 	while (atomic_read(&nf_conntrack_untracked.ct_general.use) > 1)
 		schedule();
 
+	rcu_assign_pointer(nf_ct_destroy, NULL);
+
 	for (i = 0; i < NF_CT_F_NUM; i++) {
 		if (nf_ct_cache[i].use == 0)
 			continue;
@@ -1152,14 +1135,7 @@ void nf_conntrack_cleanup(void)
 	free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
 			    nf_conntrack_htable_size);
 
-	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_generic);
-
-	/* free l3proto protocol tables */
-	for (i = 0; i < PF_MAX; i++)
-		if (nf_ct_protos[i]) {
-			kfree(nf_ct_protos[i]);
-			nf_ct_protos[i] = NULL;
-		}
+	nf_conntrack_proto_fini();
 }
 
 static struct list_head *alloc_hashtable(int size, int *vmalloced)
@@ -1237,7 +1213,6 @@ module_param_call(hashsize, set_hashsize
 
 int __init nf_conntrack_init(void)
 {
-	unsigned int i;
 	int ret;
 
 	/* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
@@ -1279,18 +1254,13 @@ int __init nf_conntrack_init(void)
 		goto err_free_conntrack_slab;
 	}
 
-	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_generic);
+	ret = nf_conntrack_proto_init();
 	if (ret < 0)
 		goto out_free_expect_slab;
 
-	/* Don't NEED lock here, but good form anyway. */
-	write_lock_bh(&nf_conntrack_lock);
-	for (i = 0; i < AF_MAX; i++)
-		nf_ct_l3protos[i] = &nf_conntrack_l3proto_generic;
-	write_unlock_bh(&nf_conntrack_lock);
-
 	/* For use by REJECT target */
 	rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach);
+	rcu_assign_pointer(nf_ct_destroy, destroy_conntrack);
 
 	/* Set up fake conntrack:
 	    - to never be deleted, not in any hashes */
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 1a223e0..6bd421d 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -91,3 +91,26 @@ void nf_ct_event_cache_flush(void)
 	}
 }
 
+int nf_conntrack_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&nf_conntrack_chain, nb);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
+
+int nf_conntrack_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&nf_conntrack_chain, nb);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
+
+int nf_conntrack_expect_register_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_register_notifier);
+
+int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain, nb);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_unregister_notifier);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index ce70a6f..c31af29 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -290,9 +290,7 @@ static void nf_conntrack_expect_insert(s
 	master_help->expecting++;
 	list_add(&exp->list, &nf_conntrack_expect_list);
 
-	init_timer(&exp->timeout);
-	exp->timeout.data = (unsigned long)exp;
-	exp->timeout.function = expectation_timed_out;
+	setup_timer(&exp->timeout, expectation_timed_out, (unsigned long)exp);
 	exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
 	add_timer(&exp->timeout);
 
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 3089dfc..a186799 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -7,12 +7,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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- enable working with Layer 3 protocol independent connection tracking.
- *	- track EPRT and EPSV commands with IPv6 address.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_ftp.c
  */
 
 #include <linux/module.h>
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index bb26a65..1093478 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -46,7 +46,7 @@ static int help(struct sk_buff **pskb, u
 		struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 {
 	struct nf_conntrack_expect *exp;
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 	struct rtable *rt = (struct rtable *)(*pskb)->dst;
 	struct in_device *in_dev;
 	__be32 mask = 0;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 48f0531..aa1a97e 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -6,9 +6,6 @@
  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
  * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net>
  *
- * I've reworked this stuff to use attributes instead of conntrack
- * structures. 5.44 am. I need more tea. --pablo 05/07/11.
- *
  * Initial connection tracking via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
  *
@@ -16,8 +13,6 @@
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
- *
- * Derived from ip_conntrack_netlink.c: Port by Pablo Neira Ayuso (05/11/14)
  */
 
 #include <linux/init.h>
@@ -33,6 +28,7 @@ #include <linux/interrupt.h>
 #include <linux/notifier.h>
 
 #include <linux/netfilter.h>
+#include <net/netlink.h>
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_expect.h>
@@ -268,9 +264,7 @@ ctnetlink_fill_info(struct sk_buff *skb,
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
 	struct nfattr *nest_parms;
-	unsigned char *b;
-
-	b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	event |= NFNL_SUBSYS_CTNETLINK << 8;
 	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
@@ -303,12 +297,12 @@ ctnetlink_fill_info(struct sk_buff *skb,
 	    ctnetlink_dump_use(skb, ct) < 0)
 		goto nfattr_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 nfattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -322,7 +316,7 @@ static int ctnetlink_conntrack_event(str
 	struct nf_conn *ct = (struct nf_conn *)ptr;
 	struct sk_buff *skb;
 	unsigned int type;
-	unsigned char *b;
+	sk_buff_data_t b;
 	unsigned int flags = 0, group;
 
 	/* ignore our fake conntrack entry */
@@ -662,7 +656,7 @@ static const size_t cta_min[CTA_MAX] = {
 
 static int
 ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+			struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conntrack_tuple tuple;
@@ -710,7 +704,7 @@ ctnetlink_del_conntrack(struct sock *ctn
 
 static int
 ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+			struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_tuple_hash *h;
 	struct nf_conntrack_tuple tuple;
@@ -721,22 +715,12 @@ ctnetlink_get_conntrack(struct sock *ctn
 	int err = 0;
 
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-		u32 rlen;
-
 #ifndef CONFIG_NF_CT_ACCT
 		if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO)
 			return -ENOTSUPP;
 #endif
-		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)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
-		return 0;
+		return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
+					  ctnetlink_done);
 	}
 
 	if (nfattr_bad_size(cda, CTA_MAX, cta_min))
@@ -1010,7 +994,7 @@ err:
 
 static int
 ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
-			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+			struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_tuple otuple, rtuple;
 	struct nf_conntrack_tuple_hash *h = NULL;
@@ -1152,9 +1136,7 @@ ctnetlink_exp_fill_info(struct sk_buff *
 {
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
-	unsigned char *b;
-
-	b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
 	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));
@@ -1168,12 +1150,12 @@ ctnetlink_exp_fill_info(struct sk_buff *
 	if (ctnetlink_exp_dump_expect(skb, exp) < 0)
 		goto nfattr_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 nfattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1186,7 +1168,7 @@ static int ctnetlink_expect_event(struct
 	struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr;
 	struct sk_buff *skb;
 	unsigned int type;
-	unsigned char *b;
+	sk_buff_data_t b;
 	int flags = 0;
 
 	if (events & IPEXP_NEW) {
@@ -1263,7 +1245,7 @@ static const size_t cta_min_exp[CTA_EXPE
 
 static int
 ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+		     struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_tuple tuple;
 	struct nf_conntrack_expect *exp;
@@ -1276,17 +1258,9 @@ ctnetlink_get_expect(struct sock *ctnl, 
 		return -EINVAL;
 
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-		u32 rlen;
-
-		if ((*errp = netlink_dump_start(ctnl, skb, nlh,
-						ctnetlink_exp_dump_table,
-						ctnetlink_done)) != 0)
-			return -EINVAL;
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		skb_pull(skb, rlen);
-		return 0;
+		return netlink_dump_start(ctnl, skb, nlh,
+					  ctnetlink_exp_dump_table,
+					  ctnetlink_done);
 	}
 
 	if (cda[CTA_EXPECT_MASTER-1])
@@ -1333,7 +1307,7 @@ out:
 
 static int
 ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+		     struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_expect *exp, *tmp;
 	struct nf_conntrack_tuple tuple;
@@ -1467,7 +1441,7 @@ out:
 
 static int
 ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
-		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
+		     struct nlmsghdr *nlh, struct nfattr *cda[])
 {
 	struct nf_conntrack_tuple tuple;
 	struct nf_conntrack_expect *exp;
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 456155f..6d94706 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -28,13 +28,13 @@ #include <net/netfilter/nf_conntrack_l3p
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_core.h>
 
-struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
+static struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
 struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly;
 EXPORT_SYMBOL_GPL(nf_ct_l3protos);
 
-#ifdef CONFIG_SYSCTL
-static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex);
+static DEFINE_MUTEX(nf_ct_proto_mutex);
 
+#ifdef CONFIG_SYSCTL
 static int
 nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path,
 		      struct ctl_table *table, unsigned int *users)
@@ -164,13 +164,11 @@ static int nf_ct_l3proto_register_sysctl
 	int err = 0;
 
 #ifdef CONFIG_SYSCTL
-	mutex_lock(&nf_ct_proto_sysctl_mutex);
 	if (l3proto->ctl_table != NULL) {
 		err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
 					    l3proto->ctl_table_path,
 					    l3proto->ctl_table, NULL);
 	}
-	mutex_unlock(&nf_ct_proto_sysctl_mutex);
 #endif
 	return err;
 }
@@ -178,11 +176,9 @@ #endif
 static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
 {
 #ifdef CONFIG_SYSCTL
-	mutex_lock(&nf_ct_proto_sysctl_mutex);
 	if (l3proto->ctl_table_header != NULL)
 		nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
 					l3proto->ctl_table, NULL);
-	mutex_unlock(&nf_ct_proto_sysctl_mutex);
 #endif
 }
 
@@ -190,27 +186,23 @@ int nf_conntrack_l3proto_register(struct
 {
 	int ret = 0;
 
-	if (proto->l3proto >= AF_MAX) {
-		ret = -EBUSY;
-		goto out;
-	}
+	if (proto->l3proto >= AF_MAX)
+		return -EBUSY;
 
-	write_lock_bh(&nf_conntrack_lock);
+	mutex_lock(&nf_ct_proto_mutex);
 	if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) {
 		ret = -EBUSY;
 		goto out_unlock;
 	}
-	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
-	write_unlock_bh(&nf_conntrack_lock);
 
 	ret = nf_ct_l3proto_register_sysctl(proto);
 	if (ret < 0)
-		nf_conntrack_l3proto_unregister(proto);
-	return ret;
+		goto out_unlock;
+
+	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
 
 out_unlock:
-	write_unlock_bh(&nf_conntrack_lock);
-out:
+	mutex_unlock(&nf_ct_proto_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
@@ -219,14 +211,14 @@ void nf_conntrack_l3proto_unregister(str
 {
 	BUG_ON(proto->l3proto >= AF_MAX);
 
-	write_lock_bh(&nf_conntrack_lock);
+	mutex_lock(&nf_ct_proto_mutex);
 	BUG_ON(nf_ct_l3protos[proto->l3proto] != proto);
 	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
 			   &nf_conntrack_l3proto_generic);
-	write_unlock_bh(&nf_conntrack_lock);
-	synchronize_rcu();
-
 	nf_ct_l3proto_unregister_sysctl(proto);
+	mutex_unlock(&nf_ct_proto_mutex);
+
+	synchronize_rcu();
 
 	/* Remove all contrack entries for this protocol */
 	nf_ct_iterate_cleanup(kill_l3proto, proto);
@@ -238,7 +230,6 @@ static int nf_ct_l4proto_register_sysctl
 	int err = 0;
 
 #ifdef CONFIG_SYSCTL
-	mutex_lock(&nf_ct_proto_sysctl_mutex);
 	if (l4proto->ctl_table != NULL) {
 		err = nf_ct_register_sysctl(l4proto->ctl_table_header,
 					    nf_net_netfilter_sysctl_path,
@@ -260,7 +251,6 @@ #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 	}
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 out:
-	mutex_unlock(&nf_ct_proto_sysctl_mutex);
 #endif /* CONFIG_SYSCTL */
 	return err;
 }
@@ -268,7 +258,6 @@ #endif /* CONFIG_SYSCTL */
 static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
 {
 #ifdef CONFIG_SYSCTL
-	mutex_lock(&nf_ct_proto_sysctl_mutex);
 	if (l4proto->ctl_table_header != NULL &&
 	    *l4proto->ctl_table_header != NULL)
 		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
@@ -279,7 +268,6 @@ #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 		nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
 					l4proto->ctl_compat_table, NULL);
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
-	mutex_unlock(&nf_ct_proto_sysctl_mutex);
 #endif /* CONFIG_SYSCTL */
 }
 
@@ -289,68 +277,41 @@ int nf_conntrack_l4proto_register(struct
 {
 	int ret = 0;
 
-	if (l4proto->l3proto >= PF_MAX) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	if (l4proto == &nf_conntrack_l4proto_generic)
-		return nf_ct_l4proto_register_sysctl(l4proto);
+	if (l4proto->l3proto >= PF_MAX)
+		return -EBUSY;
 
-retry:
-	write_lock_bh(&nf_conntrack_lock);
-	if (nf_ct_protos[l4proto->l3proto]) {
-		if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto]
-				!= &nf_conntrack_l4proto_generic) {
-			ret = -EBUSY;
-			goto out_unlock;
-		}
-	} else {
+	mutex_lock(&nf_ct_proto_mutex);
+	if (!nf_ct_protos[l4proto->l3proto]) {
 		/* l3proto may be loaded latter. */
 		struct nf_conntrack_l4proto **proto_array;
 		int i;
 
-		write_unlock_bh(&nf_conntrack_lock);
-
-		proto_array = (struct nf_conntrack_l4proto **)
-				kmalloc(MAX_NF_CT_PROTO *
-					 sizeof(struct nf_conntrack_l4proto *),
-					GFP_KERNEL);
+		proto_array = kmalloc(MAX_NF_CT_PROTO *
+				      sizeof(struct nf_conntrack_l4proto *),
+				      GFP_KERNEL);
 		if (proto_array == NULL) {
 			ret = -ENOMEM;
-			goto out;
+			goto out_unlock;
 		}
+
 		for (i = 0; i < MAX_NF_CT_PROTO; i++)
 			proto_array[i] = &nf_conntrack_l4proto_generic;
-
-		write_lock_bh(&nf_conntrack_lock);
-		if (nf_ct_protos[l4proto->l3proto]) {
-			/* bad timing, but no problem */
-			write_unlock_bh(&nf_conntrack_lock);
-			kfree(proto_array);
-		} else {
-			nf_ct_protos[l4proto->l3proto] = proto_array;
-			write_unlock_bh(&nf_conntrack_lock);
-		}
-
-		/*
-		 * Just once because array is never freed until unloading
-		 * nf_conntrack.ko
-		 */
-		goto retry;
+		nf_ct_protos[l4proto->l3proto] = proto_array;
+	} else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] !=
+					&nf_conntrack_l4proto_generic) {
+		ret = -EBUSY;
+		goto out_unlock;
 	}
 
-	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto);
-	write_unlock_bh(&nf_conntrack_lock);
-
 	ret = nf_ct_l4proto_register_sysctl(l4proto);
 	if (ret < 0)
-		nf_conntrack_l4proto_unregister(l4proto);
-	return ret;
+		goto out_unlock;
+
+	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+			   l4proto);
 
 out_unlock:
-	write_unlock_bh(&nf_conntrack_lock);
-out:
+	mutex_unlock(&nf_ct_proto_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
@@ -359,21 +320,42 @@ void nf_conntrack_l4proto_unregister(str
 {
 	BUG_ON(l4proto->l3proto >= PF_MAX);
 
-	if (l4proto == &nf_conntrack_l4proto_generic) {
-		nf_ct_l4proto_unregister_sysctl(l4proto);
-		return;
-	}
-
-	write_lock_bh(&nf_conntrack_lock);
+	mutex_lock(&nf_ct_proto_mutex);
 	BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto);
 	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
 			   &nf_conntrack_l4proto_generic);
-	write_unlock_bh(&nf_conntrack_lock);
-	synchronize_rcu();
-
 	nf_ct_l4proto_unregister_sysctl(l4proto);
+	mutex_unlock(&nf_ct_proto_mutex);
+
+	synchronize_rcu();
 
 	/* Remove all contrack entries for this protocol */
 	nf_ct_iterate_cleanup(kill_l4proto, l4proto);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
+
+int nf_conntrack_proto_init(void)
+{
+	unsigned int i;
+	int err;
+
+	err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < AF_MAX; i++)
+		rcu_assign_pointer(nf_ct_l3protos[i],
+				   &nf_conntrack_l3proto_generic);
+	return 0;
+}
+
+void nf_conntrack_proto_fini(void)
+{
+	unsigned int i;
+
+	nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic);
+
+	/* free l3proto protocol tables */
+	for (i = 0; i < PF_MAX; i++)
+		kfree(nf_ct_protos[i]);
+}
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 7c06993..6faf1be 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -4,11 +4,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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- enable working with L3 protocol independent connection tracking.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_proto_generic.c
  */
 
 #include <linux/types.h>
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 3c80558..0d3254b 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -7,15 +7,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.
- *
- * 17 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- enable working with L3 protocol independent connection tracking.
- *
- * Derived from net/ipv4/ip_conntrack_sctp.c
- */
-
-/*
- * Added support for proc manipulation of timeouts.
  */
 
 #include <linux/types.h>
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 153d661..ccdd5d2 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -4,24 +4,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.
- *
- * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>:
- *	- Real stateful connection tracking
- *	- Modified state transitions table
- *	- Window scaling support added
- *	- SACK support added
- *
- * Willy Tarreau:
- *	- State table bugfixes
- *	- More robust state changes
- *	- Tuning timer parameters
- *
- * 27 Oct 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- genelized Layer 3 protocol part.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_proto_tcp.c
- *
- * version 2.2
  */
 
 #include <linux/types.h>
@@ -470,11 +452,10 @@ static void tcp_sack(const struct sk_buf
 
 	/* Fast path for timestamp-only option */
 	if (length == TCPOLEN_TSTAMP_ALIGNED*4
-	    && *(__be32 *)ptr ==
-		__constant_htonl((TCPOPT_NOP << 24)
-				 | (TCPOPT_NOP << 16)
-				 | (TCPOPT_TIMESTAMP << 8)
-				 | TCPOLEN_TIMESTAMP))
+	    && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24)
+				       | (TCPOPT_NOP << 16)
+				       | (TCPOPT_TIMESTAMP << 8)
+				       | TCPOLEN_TIMESTAMP))
 		return;
 
 	while (length > 0) {
@@ -765,26 +746,18 @@ #define	TH_URG	0x20
 #define	TH_ECE	0x40
 #define	TH_CWR	0x80
 
-/* table of valid flag combinations - ECE and CWR are always valid */
-static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
+/* table of valid flag combinations - PUSH, ECE and CWR are always valid */
+static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
 {
 	[TH_SYN]			= 1,
-	[TH_SYN|TH_PUSH]		= 1,
 	[TH_SYN|TH_URG]			= 1,
-	[TH_SYN|TH_PUSH|TH_URG]		= 1,
 	[TH_SYN|TH_ACK]			= 1,
-	[TH_SYN|TH_ACK|TH_PUSH]		= 1,
 	[TH_RST]			= 1,
 	[TH_RST|TH_ACK]			= 1,
-	[TH_RST|TH_ACK|TH_PUSH]		= 1,
 	[TH_FIN|TH_ACK]			= 1,
+	[TH_FIN|TH_ACK|TH_URG]		= 1,
 	[TH_ACK]			= 1,
-	[TH_ACK|TH_PUSH]		= 1,
 	[TH_ACK|TH_URG]			= 1,
-	[TH_ACK|TH_URG|TH_PUSH]		= 1,
-	[TH_FIN|TH_ACK|TH_PUSH]		= 1,
-	[TH_FIN|TH_ACK|TH_URG]		= 1,
-	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1,
 };
 
 /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c.  */
@@ -831,7 +804,7 @@ static int tcp_error(struct sk_buff *skb
 	}
 
 	/* Check TCP flags. */
-	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
+	tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
 	if (!tcp_valid_flags[tcpflags]) {
 		if (LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -1110,11 +1083,26 @@ static int tcp_to_nfattr(struct sk_buff 
 			 const struct nf_conn *ct)
 {
 	struct nfattr *nest_parms;
+	struct nf_ct_tcp_flags tmp = {};
 
 	read_lock_bh(&tcp_lock);
 	nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
 	NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
 		&ct->proto.tcp.state);
+
+	NFA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, sizeof(u_int8_t),
+		&ct->proto.tcp.seen[0].td_scale);
+
+	NFA_PUT(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY, sizeof(u_int8_t),
+		&ct->proto.tcp.seen[1].td_scale);
+
+	tmp.flags = ct->proto.tcp.seen[0].flags;
+	NFA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+		sizeof(struct nf_ct_tcp_flags), &tmp);
+
+	tmp.flags = ct->proto.tcp.seen[1].flags;
+	NFA_PUT(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY,
+		sizeof(struct nf_ct_tcp_flags), &tmp);
 	read_unlock_bh(&tcp_lock);
 
 	NFA_NEST_END(skb, nest_parms);
@@ -1127,7 +1115,11 @@ nfattr_failure:
 }
 
 static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = {
-	[CTA_PROTOINFO_TCP_STATE-1]	= sizeof(u_int8_t),
+	[CTA_PROTOINFO_TCP_STATE-1]	      = sizeof(u_int8_t),
+	[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1] = sizeof(u_int8_t),
+	[CTA_PROTOINFO_TCP_WSCALE_REPLY-1]    = sizeof(u_int8_t),
+	[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]  = sizeof(struct nf_ct_tcp_flags),
+	[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]     = sizeof(struct nf_ct_tcp_flags)
 };
 
 static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct)
@@ -1151,6 +1143,30 @@ static int nfattr_to_tcp(struct nfattr *
 	write_lock_bh(&tcp_lock);
 	ct->proto.tcp.state =
 		*(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
+
+	if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]) {
+		struct nf_ct_tcp_flags *attr =
+			NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]);
+		ct->proto.tcp.seen[0].flags &= ~attr->mask;
+		ct->proto.tcp.seen[0].flags |= attr->flags & attr->mask;
+	}
+
+	if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]) {
+		struct nf_ct_tcp_flags *attr =
+			NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]);
+		ct->proto.tcp.seen[1].flags &= ~attr->mask;
+		ct->proto.tcp.seen[1].flags |= attr->flags & attr->mask;
+	}
+
+	if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1] &&
+	    tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1] &&
+	    ct->proto.tcp.seen[0].flags & IP_CT_TCP_FLAG_WINDOW_SCALE &&
+	    ct->proto.tcp.seen[1].flags & IP_CT_TCP_FLAG_WINDOW_SCALE) {
+		ct->proto.tcp.seen[0].td_scale = *(u_int8_t *)
+			NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1]);
+		ct->proto.tcp.seen[1].td_scale = *(u_int8_t *)
+			NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1]);
+	}
 	write_unlock_bh(&tcp_lock);
 
 	return 0;
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index a5e5726..3620ecc 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -4,11 +4,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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- enable working with Layer 3 protocol independent connection tracking.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_proto_udp.c
  */
 
 #include <linux/types.h>
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index b858636..45baeb0 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -1,20 +1,9 @@
-/* This file contains all the functions required for the standalone
-   nf_conntrack module.
-
-   These are not required by the compatibility layer.
-*/
-
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@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.
- *
- * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
- *	- generalize L3 protocol dependent part.
- *
- * Derived from net/ipv4/netfilter/ip_conntrack_standalone.c
  */
 
 #include <linux/types.h>
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index bf23e48..8797e69 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -3,7 +3,7 @@
  *
  * (C) 2001 by Jay Schulist <jschlst@samba.org>,
  * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
- * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ * (C) 2005,2007 by Pablo Neira Ayuso <pablo@netfilter.org>
  *
  * Initial netfilter messages via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -28,10 +28,9 @@ #include <linux/skbuff.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <net/sock.h>
+#include <net/netlink.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
 
-#include <linux/netfilter.h>
 #include <linux/netlink.h>
 #include <linux/netfilter/nfnetlink.h>
 
@@ -41,32 +40,34 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NE
 
 static char __initdata nfversion[] = "0.30";
 
-#if 0
-#define DEBUGP(format, args...)	\
-		printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
-			__LINE__, __FUNCTION__, ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
 static struct sock *nfnl = NULL;
 static struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
-DECLARE_MUTEX(nfnl_sem);
+static DEFINE_MUTEX(nfnl_mutex);
 
-void nfnl_lock(void)
+static void nfnl_lock(void)
 {
-	nfnl_shlock();
+	mutex_lock(&nfnl_mutex);
 }
 
-void nfnl_unlock(void)
+static int nfnl_trylock(void)
 {
-	nfnl_shunlock();
+	return !mutex_trylock(&nfnl_mutex);
 }
 
-int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
+static void __nfnl_unlock(void)
 {
-	DEBUGP("registering subsystem ID %u\n", n->subsys_id);
+	mutex_unlock(&nfnl_mutex);
+}
+
+static void nfnl_unlock(void)
+{
+	mutex_unlock(&nfnl_mutex);
+	if (nfnl->sk_receive_queue.qlen)
+		nfnl->sk_data_ready(nfnl, 0);
+}
 
+int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
+{
 	nfnl_lock();
 	if (subsys_table[n->subsys_id]) {
 		nfnl_unlock();
@@ -77,24 +78,23 @@ int nfnetlink_subsys_register(struct nfn
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
 
 int nfnetlink_subsys_unregister(struct nfnetlink_subsystem *n)
 {
-	DEBUGP("unregistering subsystem ID %u\n", n->subsys_id);
-
 	nfnl_lock();
 	subsys_table[n->subsys_id] = NULL;
 	nfnl_unlock();
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
 
 static inline struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type)
 {
 	u_int8_t subsys_id = NFNL_SUBSYS_ID(type);
 
-	if (subsys_id >= NFNL_SUBSYS_COUNT
-	    || subsys_table[subsys_id] == NULL)
+	if (subsys_id >= NFNL_SUBSYS_COUNT)
 		return NULL;
 
 	return subsys_table[subsys_id];
@@ -105,10 +105,8 @@ nfnetlink_find_client(u_int16_t type, st
 {
 	u_int8_t cb_id = NFNL_MSG_TYPE(type);
 
-	if (cb_id >= ss->cb_count) {
-		DEBUGP("msgtype %u >= %u, returning\n", type, ss->cb_count);
+	if (cb_id >= ss->cb_count)
 		return NULL;
-	}
 
 	return &ss->cb[cb_id];
 }
@@ -125,6 +123,7 @@ void __nfa_fill(struct sk_buff *skb, int
 	memcpy(NFA_DATA(nfa), data, attrlen);
 	memset(NFA_DATA(nfa) + attrlen, 0, NFA_ALIGN(size) - size);
 }
+EXPORT_SYMBOL_GPL(__nfa_fill);
 
 void nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
 {
@@ -137,6 +136,7 @@ void nfattr_parse(struct nfattr *tb[], i
 		nfa = NFA_NEXT(nfa, len);
 	}
 }
+EXPORT_SYMBOL_GPL(nfattr_parse);
 
 /**
  * nfnetlink_check_attributes - check and parse nfnetlink attributes
@@ -150,37 +150,15 @@ static int
 nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
 			   struct nlmsghdr *nlh, struct nfattr *cda[])
 {
-	int min_len;
-	u_int16_t attr_count;
+	int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
 	u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
-
-	if (unlikely(cb_id >= subsys->cb_count)) {
-		DEBUGP("msgtype %u >= %u, returning\n",
-			cb_id, subsys->cb_count);
-		return -EINVAL;
-	}
-
-	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
-	if (unlikely(nlh->nlmsg_len < min_len))
-		return -EINVAL;
-
-	attr_count = subsys->cb[cb_id].attr_count;
-	memset(cda, 0, sizeof(struct nfattr *) * attr_count);
+	u_int16_t attr_count = subsys->cb[cb_id].attr_count;
 
 	/* check attribute lengths. */
 	if (likely(nlh->nlmsg_len > min_len)) {
 		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
-
-		while (NFA_OK(attr, attrlen)) {
-			unsigned flavor = NFA_TYPE(attr);
-			if (flavor) {
-				if (flavor > attr_count)
-					return -EINVAL;
-				cda[flavor - 1] = attr;
-			}
-			attr = NFA_NEXT(attr, attrlen);
-		}
+		nfattr_parse(cda, attr_count, attr, attrlen);
 	}
 
 	/* implicit: if nlmsg_len == min_len, we return 0, and an empty
@@ -208,62 +186,46 @@ int nfnetlink_send(struct sk_buff *skb, 
 
 	return err;
 }
+EXPORT_SYMBOL_GPL(nfnetlink_send);
 
 int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
 {
 	return netlink_unicast(nfnl, skb, pid, flags);
 }
+EXPORT_SYMBOL_GPL(nfnetlink_unicast);
 
 /* Process one complete nfnetlink message. */
-static int nfnetlink_rcv_msg(struct sk_buff *skb,
-				    struct nlmsghdr *nlh, int *errp)
+static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	struct nfnl_callback *nc;
 	struct nfnetlink_subsystem *ss;
-	int type, err = 0;
-
-	DEBUGP("entered; subsys=%u, msgtype=%u\n",
-		 NFNL_SUBSYS_ID(nlh->nlmsg_type),
-		 NFNL_MSG_TYPE(nlh->nlmsg_type));
-
-	if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
-		DEBUGP("missing CAP_NET_ADMIN\n");
-		*errp = -EPERM;
-		return -1;
-	}
+	int type, err;
 
-	/* Only requests are handled by kernel now. */
-	if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
-		DEBUGP("received non-request message\n");
-		return 0;
-	}
+	if (security_netlink_recv(skb, CAP_NET_ADMIN))
+		return -EPERM;
 
 	/* All the messages must at least contain nfgenmsg */
-	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
-		DEBUGP("received message was too short\n");
+	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg)))
 		return 0;
-	}
 
 	type = nlh->nlmsg_type;
 	ss = nfnetlink_get_subsys(type);
 	if (!ss) {
 #ifdef CONFIG_KMOD
-		/* don't call nfnl_shunlock, since it would reenter
+		/* don't call nfnl_unlock, since it would reenter
 		 * with further packet processing */
-		up(&nfnl_sem);
+		__nfnl_unlock();
 		request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
-		nfnl_shlock();
+		nfnl_lock();
 		ss = nfnetlink_get_subsys(type);
 		if (!ss)
 #endif
-			goto err_inval;
+			return -EINVAL;
 	}
 
 	nc = nfnetlink_find_client(type, ss);
-	if (!nc) {
-		DEBUGP("unable to find client for type %d\n", type);
-		goto err_inval;
-	}
+	if (!nc)
+		return -EINVAL;
 
 	{
 		u_int16_t attr_count =
@@ -274,73 +236,21 @@ #endif
 
 		err = nfnetlink_check_attributes(ss, nlh, cda);
 		if (err < 0)
-			goto err_inval;
-
-		DEBUGP("calling handler\n");
-		err = nc->call(nfnl, skb, nlh, cda, errp);
-		*errp = err;
-		return err;
-	}
-
-err_inval:
-	DEBUGP("returning -EINVAL\n");
-	*errp = -EINVAL;
-	return -1;
-}
-
-/* Process one packet of messages. */
-static inline int nfnetlink_rcv_skb(struct sk_buff *skb)
-{
-	int err;
-	struct nlmsghdr *nlh;
-
-	while (skb->len >= NLMSG_SPACE(0)) {
-		u32 rlen;
-
-		nlh = (struct nlmsghdr *)skb->data;
-		if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
-		    || skb->len < nlh->nlmsg_len)
-			return 0;
-		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (rlen > skb->len)
-			rlen = skb->len;
-		if (nfnetlink_rcv_msg(skb, nlh, &err)) {
-			if (!err)
-				return -1;
-			netlink_ack(skb, nlh, err);
-		} else
-			if (nlh->nlmsg_flags & NLM_F_ACK)
-				netlink_ack(skb, nlh, 0);
-		skb_pull(skb, rlen);
+			return err;
+		return nc->call(nfnl, skb, nlh, cda);
 	}
-
-	return 0;
 }
 
 static void nfnetlink_rcv(struct sock *sk, int len)
 {
-	do {
-		struct sk_buff *skb;
+	unsigned int qlen = 0;
 
-		if (nfnl_shlock_nowait())
+	do {
+		if (nfnl_trylock())
 			return;
-
-		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-			if (nfnetlink_rcv_skb(skb)) {
-				if (skb->len)
-					skb_queue_head(&sk->sk_receive_queue,
-						       skb);
-				else
-					kfree_skb(skb);
-				break;
-			}
-			kfree_skb(skb);
-		}
-
-		/* don't call nfnl_shunlock, since it would reenter
-		 * with further packet processing */
-		up(&nfnl_sem);
-	} while(nfnl && nfnl->sk_receive_queue.qlen);
+		netlink_run_queue(sk, &qlen, nfnetlink_rcv_msg);
+		__nfnl_unlock();
+	} while (qlen);
 }
 
 static void __exit nfnetlink_exit(void)
@@ -355,7 +265,7 @@ static int __init nfnetlink_init(void)
 	printk("Netfilter messages via NETLINK v%s.\n", nfversion);
 
 	nfnl = netlink_kernel_create(NETLINK_NETFILTER, NFNLGRP_MAX,
-				     nfnetlink_rcv, THIS_MODULE);
+				     nfnetlink_rcv, NULL, THIS_MODULE);
 	if (!nfnl) {
 		printk(KERN_ERR "cannot initialize nfnetlink!\n");
 		return -1;
@@ -366,10 +276,3 @@ static int __init nfnetlink_init(void)
 
 module_init(nfnetlink_init);
 module_exit(nfnetlink_exit);
-
-EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
-EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
-EXPORT_SYMBOL_GPL(nfnetlink_send);
-EXPORT_SYMBOL_GPL(nfnetlink_unicast);
-EXPORT_SYMBOL_GPL(nfattr_parse);
-EXPORT_SYMBOL_GPL(__nfa_fill);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 5cb30eb..e32e30e 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -10,11 +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.
- *
- * 2006-01-26 Harald Welte <laforge@netfilter.org>
- * 	- Add optional local and global sequence number to detect lost
- * 	  events from userspace
- *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -163,10 +158,7 @@ instance_create(u_int16_t group_num, int
 	/* needs to be two, since we _put() after creation */
 	atomic_set(&inst->use, 2);
 
-	init_timer(&inst->timer);
-	inst->timer.function = nfulnl_timer;
-	inst->timer.data = (unsigned long)inst;
-	/* don't start timer yet. (re)start it  with every packet */
+	setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
 
 	inst->peer_pid = pid;
 	inst->group_num = group_num;
@@ -200,20 +192,14 @@ out_unlock:
 static int __nfulnl_send(struct nfulnl_instance *inst);
 
 static void
-_instance_destroy2(struct nfulnl_instance *inst, int lock)
+__instance_destroy(struct nfulnl_instance *inst)
 {
 	/* first pull it out of the global list */
-	if (lock)
-		write_lock_bh(&instances_lock);
-
 	UDEBUG("removing instance %p (queuenum=%u) from hash\n",
 		inst, inst->group_num);
 
 	hlist_del(&inst->hlist);
 
-	if (lock)
-		write_unlock_bh(&instances_lock);
-
 	/* then flush all pending packets from skb */
 
 	spin_lock_bh(&inst->lock);
@@ -235,15 +221,11 @@ _instance_destroy2(struct nfulnl_instanc
 }
 
 static inline void
-__instance_destroy(struct nfulnl_instance *inst)
-{
-	_instance_destroy2(inst, 0);
-}
-
-static inline void
 instance_destroy(struct nfulnl_instance *inst)
 {
-	_instance_destroy2(inst, 1);
+	write_lock_bh(&instances_lock);
+	__instance_destroy(inst);
+	write_unlock_bh(&instances_lock);
 }
 
 static int
@@ -365,9 +347,6 @@ __nfulnl_send(struct nfulnl_instance *in
 {
 	int status;
 
-	if (!inst->skb)
-		return 0;
-
 	if (inst->qlen > 1)
 		inst->lastnlh->nlmsg_type = NLMSG_DONE;
 
@@ -391,7 +370,8 @@ static void nfulnl_timer(unsigned long d
 	UDEBUG("timer function called, flushing buffer\n");
 
 	spin_lock_bh(&inst->lock);
-	__nfulnl_send(inst);
+	if (inst->skb)
+		__nfulnl_send(inst);
 	spin_unlock_bh(&inst->lock);
 	instance_put(inst);
 }
@@ -409,15 +389,14 @@ __build_packet_message(struct nfulnl_ins
 			const struct nf_loginfo *li,
 			const char *prefix, unsigned int plen)
 {
-	unsigned char *old_tail;
 	struct nfulnl_msg_packet_hdr pmsg;
 	struct nlmsghdr *nlh;
 	struct nfgenmsg *nfmsg;
 	__be32 tmp_uint;
+	sk_buff_data_t old_tail = inst->skb->tail;
 
 	UDEBUG("entered\n");
 
-	old_tail = inst->skb->tail;
 	nlh = NLMSG_PUT(inst->skb, 0, 0,
 			NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,
 			sizeof(struct nfgenmsg));
@@ -509,11 +488,11 @@ #endif
 		NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (skb->tstamp.off_sec) {
+	if (skb->tstamp.tv64) {
 		struct nfulnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(skb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(skb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(skb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
 	}
@@ -596,7 +575,6 @@ nfulnl_log_packet(unsigned int pf,
 	struct nfulnl_instance *inst;
 	const struct nf_loginfo *li;
 	unsigned int qthreshold;
-	unsigned int nlbufsiz;
 	unsigned int plen;
 
 	if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
@@ -606,12 +584,7 @@ nfulnl_log_packet(unsigned int pf,
 
 	inst = instance_lookup_get(li->u.ulog.group);
 	if (!inst)
-		inst = instance_lookup_get(0);
-	if (!inst) {
-		PRINTR("nfnetlink_log: trying to log packet, "
-			"but no instance for group %u\n", li->u.ulog.group);
 		return;
-	}
 
 	plen = 0;
 	if (prefix)
@@ -667,24 +640,11 @@ #endif
 		break;
 
 	default:
-		spin_unlock_bh(&inst->lock);
-		instance_put(inst);
-		return;
+		goto unlock_and_release;
 	}
 
-	if (size > inst->nlbufsiz)
-		nlbufsiz = size;
-	else
-		nlbufsiz = inst->nlbufsiz;
-
-	if (!inst->skb) {
-		if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
-			UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
-				inst->nlbufsiz, size);
-			goto alloc_failure;
-		}
-	} else if (inst->qlen >= qthreshold ||
-		   size > skb_tailroom(inst->skb)) {
+	if (inst->qlen >= qthreshold ||
+	    (inst->skb && size > skb_tailroom(inst->skb))) {
 		/* either the queue len is too high or we don't have
 		 * enough room in the skb left. flush to userspace. */
 		UDEBUG("flushing old skb\n");
@@ -693,12 +653,12 @@ #endif
 		if (del_timer(&inst->timer))
 			instance_put(inst);
 		__nfulnl_send(inst);
+	}
 
-		if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
-			UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
-				inst->nlbufsiz, size);
+	if (!inst->skb) {
+		inst->skb = nfulnl_alloc_skb(inst->nlbufsiz, size);
+		if (!inst->skb)
 			goto alloc_failure;
-		}
 	}
 
 	UDEBUG("qlen %d, qthreshold %d\n", inst->qlen, qthreshold);
@@ -760,7 +720,7 @@ static struct notifier_block nfulnl_rtnl
 
 static int
 nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
-		  struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+		  struct nlmsghdr *nlh, struct nfattr *nfqa[])
 {
 	return -ENOTSUPP;
 }
@@ -798,7 +758,7 @@ static const int nfula_cfg_min[NFULA_CFG
 
 static int
 nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
-		   struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp)
+		   struct nlmsghdr *nlh, struct nfattr *nfula[])
 {
 	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
 	u_int16_t group_num = ntohs(nfmsg->res_id);
@@ -830,13 +790,13 @@ nfulnl_recv_config(struct sock *ctnl, st
 					       NETLINK_CB(skb).pid);
 			if (!inst) {
 				ret = -EINVAL;
-				goto out_put;
+				goto out;
 			}
 			break;
 		case NFULNL_CFG_CMD_UNBIND:
 			if (!inst) {
 				ret = -ENODEV;
-				goto out_put;
+				goto out;
 			}
 
 			if (inst->peer_pid != NETLINK_CB(skb).pid) {
@@ -845,7 +805,7 @@ nfulnl_recv_config(struct sock *ctnl, st
 			}
 
 			instance_destroy(inst);
-			break;
+			goto out;
 		case NFULNL_CFG_CMD_PF_BIND:
 			UDEBUG("registering log handler for pf=%u\n", pf);
 			ret = nf_log_register(pf, &nfulnl_logger);
@@ -869,7 +829,7 @@ nfulnl_recv_config(struct sock *ctnl, st
 				"group=%u pid=%u =>ENOENT\n",
 				group_num, NETLINK_CB(skb).pid);
 			ret = -ENOENT;
-			goto out_put;
+			goto out;
 		}
 
 		if (inst->peer_pid != NETLINK_CB(skb).pid) {
@@ -939,10 +899,8 @@ struct iter_state {
 	unsigned int bucket;
 };
 
-static struct hlist_node *get_first(struct seq_file *seq)
+static struct hlist_node *get_first(struct iter_state *st)
 {
-	struct iter_state *st = seq->private;
-
 	if (!st)
 		return NULL;
 
@@ -953,10 +911,8 @@ static struct hlist_node *get_first(stru
 	return NULL;
 }
 
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h)
 {
-	struct iter_state *st = seq->private;
-
 	h = h->next;
 	while (!h) {
 		if (++st->bucket >= INSTANCE_BUCKETS)
@@ -967,13 +923,13 @@ static struct hlist_node *get_next(struc
 	return h;
 }
 
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *get_idx(struct iter_state *st, loff_t pos)
 {
 	struct hlist_node *head;
-	head = get_first(seq);
+	head = get_first(st);
 
 	if (head)
-		while (pos && (head = get_next(seq, head)))
+		while (pos && (head = get_next(st, head)))
 			pos--;
 	return pos ? NULL : head;
 }
@@ -981,13 +937,13 @@ static struct hlist_node *get_idx(struct
 static void *seq_start(struct seq_file *seq, loff_t *pos)
 {
 	read_lock_bh(&instances_lock);
-	return get_idx(seq, *pos);
+	return get_idx(seq->private, *pos);
 }
 
 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
 	(*pos)++;
-	return get_next(s, v);
+	return get_next(s->private, v);
 }
 
 static void seq_stop(struct seq_file *s, void *v)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index d9ce4a7..7a97bec 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -338,7 +338,7 @@ static struct sk_buff *
 nfqnl_build_packet_message(struct nfqnl_instance *queue,
 			   struct nfqnl_queue_entry *entry, int *errp)
 {
-	unsigned char *old_tail;
+	sk_buff_data_t old_tail;
 	size_t size;
 	size_t data_len = 0;
 	struct sk_buff *skb;
@@ -404,7 +404,7 @@ #endif
 	if (!skb)
 		goto nlmsg_failure;
 
-	old_tail= skb->tail;
+	old_tail = skb->tail;
 	nlh = NLMSG_PUT(skb, 0, 0,
 			NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
 			sizeof(struct nfgenmsg));
@@ -495,11 +495,11 @@ #endif
 		NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
 	}
 
-	if (entskb->tstamp.off_sec) {
+	if (entskb->tstamp.tv64) {
 		struct nfqnl_msg_packet_timestamp ts;
-
-		ts.sec = cpu_to_be64(entskb->tstamp.off_sec);
-		ts.usec = cpu_to_be64(entskb->tstamp.off_usec);
+		struct timeval tv = ktime_to_timeval(entskb->tstamp);
+		ts.sec = cpu_to_be64(tv.tv_sec);
+		ts.usec = cpu_to_be64(tv.tv_usec);
 
 		NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
 	}
@@ -648,7 +648,7 @@ nfqnl_mangle(void *data, int data_len, s
 	}
 	if (!skb_make_writable(&e->skb, data_len))
 		return -ENOMEM;
-	memcpy(e->skb->data, data, data_len);
+	skb_copy_to_linear_data(e->skb, data, data_len);
 	e->skb->ip_summed = CHECKSUM_NONE;
 	return 0;
 }
@@ -783,7 +783,7 @@ static const int nfqa_verdict_min[NFQA_M
 
 static int
 nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
-		   struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+		   struct nlmsghdr *nlh, struct nfattr *nfqa[])
 {
 	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
 	u_int16_t queue_num = ntohs(nfmsg->res_id);
@@ -848,7 +848,7 @@ err_out_put:
 
 static int
 nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
-		  struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+		  struct nlmsghdr *nlh, struct nfattr *nfqa[])
 {
 	return -ENOTSUPP;
 }
@@ -865,7 +865,7 @@ static struct nf_queue_handler nfqh = {
 
 static int
 nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
-		  struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
+		  struct nlmsghdr *nlh, struct nfattr *nfqa[])
 {
 	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
 	u_int16_t queue_num = ntohs(nfmsg->res_id);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index ec607a4..0eb2504 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -56,8 +56,8 @@ enum {
 };
 
 static const char *xt_prefix[NPROTO] = {
-	[AF_INET] 	= "ip",
-	[AF_INET6] 	= "ip6",
+	[AF_INET]	= "ip",
+	[AF_INET6]	= "ip6",
 	[NF_ARP]	= "arp",
 };
 
@@ -651,12 +651,6 @@ void *xt_unregister_table(struct xt_tabl
 EXPORT_SYMBOL_GPL(xt_unregister_table);
 
 #ifdef CONFIG_PROC_FS
-static char *xt_proto_prefix[NPROTO] = {
-	[AF_INET]	= "ip",
-	[AF_INET6]	= "ip6",
-	[NF_ARP]	= "arp",
-};
-
 static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
 {
 	struct list_head *head = list->next;
@@ -798,7 +792,7 @@ #endif
 
 
 #ifdef CONFIG_PROC_FS
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
 	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
 	if (!proc)
@@ -806,14 +800,14 @@ #ifdef CONFIG_PROC_FS
 	proc->data = (void *) ((unsigned long) af | (TABLE << 16));
 
 
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
 	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
 	if (!proc)
 		goto out_remove_tables;
 	proc->data = (void *) ((unsigned long) af | (MATCH << 16));
 
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
 	proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
 	if (!proc)
@@ -825,12 +819,12 @@ #endif
 
 #ifdef CONFIG_PROC_FS
 out_remove_matches:
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
 	proc_net_remove(buf);
 
 out_remove_tables:
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
 	proc_net_remove(buf);
 out:
@@ -844,15 +838,15 @@ void xt_proto_fini(int af)
 #ifdef CONFIG_PROC_FS
 	char buf[XT_FUNCTION_MAXNAMELEN];
 
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_TABLES, sizeof(buf));
 	proc_net_remove(buf);
 
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_TARGETS, sizeof(buf));
 	proc_net_remove(buf);
 
-	strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+	strlcpy(buf, xt_prefix[af], sizeof(buf));
 	strlcat(buf, FORMAT_MATCHES, sizeof(buf));
 	proc_net_remove(buf);
 #endif /*CONFIG_PROC_FS*/
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index 795c058..b03ce00 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -30,10 +30,7 @@ MODULE_ALIAS("ipt_CONNMARK");
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_CONNMARK.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 #include <net/netfilter/nf_conntrack_ecache.h>
-#endif
 
 static unsigned int
 target(struct sk_buff **pskb,
@@ -44,40 +41,33 @@ target(struct sk_buff **pskb,
        const void *targinfo)
 {
 	const struct xt_connmark_target_info *markinfo = targinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 	u_int32_t diff;
 	u_int32_t mark;
 	u_int32_t newmark;
-	u_int32_t ctinfo;
-	u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
 
-	if (ctmark) {
+	ct = nf_ct_get(*pskb, &ctinfo);
+	if (ct) {
 		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
+			newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
+			if (newmark != ct->mark) {
+				ct->mark = newmark;
 				nf_conntrack_event_cache(IPCT_MARK, *pskb);
-#endif
 			}
 			break;
 		case XT_CONNMARK_SAVE:
-			newmark = (*ctmark & ~markinfo->mask) |
+			newmark = (ct->mark & ~markinfo->mask) |
 				  ((*pskb)->mark & 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
+			if (ct->mark != newmark) {
+				ct->mark = newmark;
 				nf_conntrack_event_cache(IPCT_MARK, *pskb);
-#endif
 			}
 			break;
 		case XT_CONNMARK_RESTORE:
 			mark = (*pskb)->mark;
-			diff = (*ctmark ^ mark) & markinfo->mask;
+			diff = (ct->mark ^ mark) & markinfo->mask;
 			(*pskb)->mark = mark ^ diff;
 			break;
 		}
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 1ab0db6..81c0c58 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -19,7 +19,7 @@ #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_CONNSECMARK.h>
-#include <net/netfilter/nf_conntrack_compat.h>
+#include <net/netfilter/nf_conntrack.h>
 
 #define PFX "CONNSECMARK: "
 
@@ -36,12 +36,12 @@ MODULE_ALIAS("ip6t_CONNSECMARK");
 static void secmark_save(struct sk_buff *skb)
 {
 	if (skb->secmark) {
-		u32 *connsecmark;
+		struct nf_conn *ct;
 		enum ip_conntrack_info ctinfo;
 
-		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
-		if (connsecmark && !*connsecmark)
-			*connsecmark = skb->secmark;
+		ct = nf_ct_get(skb, &ctinfo);
+		if (ct && !ct->secmark)
+			ct->secmark = skb->secmark;
 	}
 }
 
@@ -52,12 +52,12 @@ static void secmark_save(struct sk_buff 
 static void secmark_restore(struct sk_buff *skb)
 {
 	if (!skb->secmark) {
-		u32 *connsecmark;
+		struct nf_conn *ct;
 		enum ip_conntrack_info ctinfo;
 
-		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
-		if (connsecmark && *connsecmark)
-			skb->secmark = *connsecmark;
+		ct = nf_ct_get(skb, &ctinfo);
+		if (ct && ct->secmark)
+			skb->secmark = ct->secmark;
 	}
 }
 
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
index a7cc75a..9f2f220 100644
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -8,8 +8,6 @@
  * 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>
@@ -35,13 +33,13 @@ static unsigned int target(struct sk_buf
 			   const void *targinfo)
 {
 	const struct xt_DSCP_info *dinfo = targinfo;
-	u_int8_t dscp = ipv4_get_dsfield((*pskb)->nh.iph) >> XT_DSCP_SHIFT;
+	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(*pskb)) >> 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),
+		ipv4_change_dsfield(ip_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
 				    dinfo->dscp << XT_DSCP_SHIFT);
 
 	}
@@ -56,13 +54,13 @@ static unsigned int target6(struct sk_bu
 			    const void *targinfo)
 {
 	const struct xt_DSCP_info *dinfo = targinfo;
-	u_int8_t dscp = ipv6_get_dsfield((*pskb)->nh.ipv6h) >> XT_DSCP_SHIFT;
+	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(*pskb)) >> 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),
+		ipv6_change_dsfield(ipv6_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
 				    dinfo->dscp << XT_DSCP_SHIFT);
 	}
 	return XT_CONTINUE;
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index b874a20..5085fb3 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -5,7 +5,7 @@ #include <linux/module.h>
 #include <linux/skbuff.h>
 
 #include <linux/netfilter/x_tables.h>
-#include <net/netfilter/nf_conntrack_compat.h>
+#include <net/netfilter/nf_conntrack.h>
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_NOTRACK");
@@ -26,7 +26,7 @@ target(struct sk_buff **pskb,
 	   If there is a real ct entry correspondig to this packet,
 	   it'll hang aroun till timing out. We don't deal with it
 	   for performance reasons. JK */
-	nf_ct_untrack(*pskb);
+	(*pskb)->nfct = &nf_conntrack_untracked.ct_general;
 	(*pskb)->nfctinfo = IP_CT_NEW;
 	nf_conntrack_get((*pskb)->nfct);
 
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index db7e38c..15fe8f6 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -54,7 +54,7 @@ tcpmss_mangle_packet(struct sk_buff **ps
 		return -1;
 
 	tcplen = (*pskb)->len - tcphoff;
-	tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+	tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
 
 	/* Since it passed flags test in tcp match, we know it is is
 	   not a fragment, and has data >= tcp header length.  SYN
@@ -113,7 +113,7 @@ tcpmss_mangle_packet(struct sk_buff **ps
 			return -1;
 		kfree_skb(*pskb);
 		*pskb = newskb;
-		tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff);
+		tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
 	}
 
 	skb_put((*pskb), TCPOLEN_MSS);
@@ -145,7 +145,7 @@ xt_tcpmss_target4(struct sk_buff **pskb,
 		  const struct xt_target *target,
 		  const void *targinfo)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
+	struct iphdr *iph = ip_hdr(*pskb);
 	__be16 newlen;
 	int ret;
 
@@ -154,7 +154,7 @@ xt_tcpmss_target4(struct sk_buff **pskb,
 	if (ret < 0)
 		return NF_DROP;
 	if (ret > 0) {
-		iph = (*pskb)->nh.iph;
+		iph = ip_hdr(*pskb);
 		newlen = htons(ntohs(iph->tot_len) + ret);
 		nf_csum_replace2(&iph->check, iph->tot_len, newlen);
 		iph->tot_len = newlen;
@@ -171,7 +171,7 @@ xt_tcpmss_target6(struct sk_buff **pskb,
 		  const struct xt_target *target,
 		  const void *targinfo)
 {
-	struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
+	struct ipv6hdr *ipv6h = ipv6_hdr(*pskb);
 	u8 nexthdr;
 	int tcphoff;
 	int ret;
@@ -187,7 +187,7 @@ xt_tcpmss_target6(struct sk_buff **pskb,
 	if (ret < 0)
 		return NF_DROP;
 	if (ret > 0) {
-		ipv6h = (*pskb)->nh.ipv6h;
+		ipv6h = ipv6_hdr(*pskb);
 		ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
 	}
 	return XT_CONTINUE;
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 5e32dfa..804afe5 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -1,20 +1,11 @@
 /* Kernel module to match connection tracking byte counter.
  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
- *
- * 2004-07-20 Harald Welte <laforge@netfilter.org>
- * 	- reimplemented to use per-connection accounting counters
- * 	- add functionality to match number of packets
- * 	- add functionality to match average packet size
- * 	- add support to match directions seperately
- * 2005-10-16 Harald Welte <laforge@netfilter.org>
- * 	- Port to x_tables
- *
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <net/netfilter/nf_conntrack_compat.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_connbytes.h>
+#include <net/netfilter/nf_conntrack.h>
 
 #include <asm/div64.h>
 #include <asm/bitops.h>
@@ -24,22 +15,6 @@ MODULE_AUTHOR("Harald Welte <laforge@net
 MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
 MODULE_ALIAS("ipt_connbytes");
 
-/* 64bit divisor, dividend and result. dynamic precision */
-static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
-{
-	u_int32_t d = divisor;
-
-	if (divisor > 0xffffffffULL) {
-		unsigned int shift = fls(divisor >> 32);
-
-		d = divisor >> shift;
-		dividend >>= shift;
-	}
-
-	do_div(dividend, d);
-	return dividend;
-}
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -51,13 +26,17 @@ match(const struct sk_buff *skb,
       int *hotdrop)
 {
 	const struct xt_connbytes_info *sinfo = matchinfo;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 	u_int64_t what = 0;	/* initialize to make gcc happy */
 	u_int64_t bytes = 0;
 	u_int64_t pkts = 0;
 	const struct ip_conntrack_counter *counters;
 
-	if (!(counters = nf_ct_get_counters(skb)))
-		return 0; /* no match */
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		return 0;
+	counters = ct->counters;
 
 	switch (sinfo->what) {
 	case XT_CONNBYTES_PKTS:
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index 36c2def..e180325 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -21,16 +21,15 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connmark.h>
 
 MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
 MODULE_DESCRIPTION("IP tables connmark match module");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_connmark");
 
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_connmark.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -42,12 +41,14 @@ match(const struct sk_buff *skb,
       int *hotdrop)
 {
 	const struct xt_connmark_info *info = matchinfo;
-	u_int32_t ctinfo;
-	const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
-	if (!ctmark)
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
 		return 0;
 
-	return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
+	return (((ct->mark) & info->mask) == info->mark) ^ info->invert;
 }
 
 static int
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 2885c37..f4ea8fe 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -10,121 +10,15 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
-
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#else
-#include <net/netfilter/nf_conntrack.h>
-#endif
-
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_conntrack.h>
-#include <net/netfilter/nf_conntrack_compat.h>
+#include <net/netfilter/nf_conntrack.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables connection tracking match module");
 MODULE_ALIAS("ipt_conntrack");
 
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-
-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_conntrack_info *sinfo = matchinfo;
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	unsigned int statebit;
-
-	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
-
-#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg))
-
-	if (ct == &ip_conntrack_untracked)
-		statebit = XT_CONNTRACK_STATE_UNTRACKED;
-	else if (ct)
-		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
-	else
-		statebit = XT_CONNTRACK_STATE_INVALID;
-
-	if (sinfo->flags & XT_CONNTRACK_STATE) {
-		if (ct) {
-			if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
-				statebit |= XT_CONNTRACK_STATE_SNAT;
-			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 (ct == NULL) {
-		if (sinfo->flags & ~XT_CONNTRACK_STATE)
-			return 0;
-		return 1;
-	}
-
-	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_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_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_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 (sinfo->flags & XT_CONNTRACK_STATUS &&
-	    FWINV((ct->status & sinfo->statusmask) == 0,
-		  XT_CONNTRACK_STATUS))
-		return 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))
-			return 0;
-	}
-	return 1;
-}
-
-#else /* CONFIG_IP_NF_CONNTRACK */
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -220,8 +114,6 @@ #define FWINV(bool,invflg) ((bool) ^ !!(
 	return 1;
 }
 
-#endif /* CONFIG_NF_IP_CONNTRACK */
-
 static int
 checkentry(const char *tablename,
 	   const void *ip,
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
index 26c7f4a..56b247e 100644
--- a/net/netfilter/xt_dscp.c
+++ b/net/netfilter/xt_dscp.c
@@ -1,7 +1,5 @@
 /* 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@netfilter.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -34,7 +32,7 @@ static int match(const struct sk_buff *s
 		 int *hotdrop)
 {
 	const struct xt_dscp_info *info = matchinfo;
-	u_int8_t dscp = ipv4_get_dsfield(skb->nh.iph) >> XT_DSCP_SHIFT;
+	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	return (dscp == info->dscp) ^ !!info->invert;
 }
@@ -49,7 +47,7 @@ static int match6(const struct sk_buff *
 		  int *hotdrop)
 {
 	const struct xt_dscp_info *info = matchinfo;
-	u_int8_t dscp = ipv6_get_dsfield(skb->nh.ipv6h) >> XT_DSCP_SHIFT;
+	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
 
 	return (dscp == info->dscp) ^ !!info->invert;
 }
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 9f37d59..d3043fa 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -216,10 +216,8 @@ static int htable_create(struct xt_hashl
 	hinfo->pde->proc_fops = &dl_file_ops;
 	hinfo->pde->data = hinfo;
 
-	init_timer(&hinfo->timer);
+	setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo);
 	hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
-	hinfo->timer.data = (unsigned long )hinfo;
-	hinfo->timer.function = htable_gc;
 	add_timer(&hinfo->timer);
 
 	spin_lock_bh(&hashlimit_lock);
@@ -380,22 +378,22 @@ hashlimit_init_dst(struct xt_hashlimit_h
 	switch (hinfo->family) {
 	case AF_INET:
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
-			dst->addr.ip.dst = skb->nh.iph->daddr;
+			dst->addr.ip.dst = ip_hdr(skb)->daddr;
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
-			dst->addr.ip.src = skb->nh.iph->saddr;
+			dst->addr.ip.src = ip_hdr(skb)->saddr;
 
 		if (!(hinfo->cfg.mode &
 		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))
 			return 0;
-		nexthdr = skb->nh.iph->protocol;
+		nexthdr = ip_hdr(skb)->protocol;
 		break;
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 	case AF_INET6:
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)
-			memcpy(&dst->addr.ip6.dst, &skb->nh.ipv6h->daddr,
+			memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr,
 			       sizeof(dst->addr.ip6.dst));
 		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)
-			memcpy(&dst->addr.ip6.src, &skb->nh.ipv6h->saddr,
+			memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr,
 			       sizeof(dst->addr.ip6.src));
 
 		if (!(hinfo->cfg.mode &
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 407d1d5..c139b2f 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -5,26 +5,16 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
- *   		 - Port to newnat infrastructure
  */
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#else
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_helper.h>
-#endif
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_helper.h>
-#include <net/netfilter/nf_conntrack_compat.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
@@ -38,55 +28,6 @@ #else
 #define DEBUGP(format, args...)
 #endif
 
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-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_helper_info *info = matchinfo;
-	struct ip_conntrack *ct;
-	enum ip_conntrack_info ctinfo;
-	int ret = info->invert;
-
-	ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
-	if (!ct) {
-		DEBUGP("xt_helper: Eek! invalid conntrack?\n");
-		return ret;
-	}
-
-	if (!ct->master) {
-		DEBUGP("xt_helper: conntrack %p has no master\n", ct);
-		return ret;
-	}
-
-	read_lock_bh(&ip_conntrack_lock);
-	if (!ct->master->helper) {
-		DEBUGP("xt_helper: master ct %p has no helper\n",
-			exp->expectant);
-		goto out_unlock;
-	}
-
-	DEBUGP("master's name = %s , info->name = %s\n",
-		ct->master->helper->name, info->name);
-
-	if (info->name[0] == '\0')
-		ret ^= 1;
-	else
-		ret ^= !strncmp(ct->master->helper->name, info->name,
-				strlen(ct->master->helper->name));
-out_unlock:
-	read_unlock_bh(&ip_conntrack_lock);
-	return ret;
-}
-
-#else /* CONFIG_IP_NF_CONNTRACK */
-
 static int
 match(const struct sk_buff *skb,
       const struct net_device *in,
@@ -134,7 +75,6 @@ out_unlock:
 	read_unlock_bh(&nf_conntrack_lock);
 	return ret;
 }
-#endif
 
 static int check(const char *tablename,
 		 const void *inf,
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
index 32fb998..77288c5 100644
--- a/net/netfilter/xt_length.c
+++ b/net/netfilter/xt_length.c
@@ -31,7 +31,7 @@ match(const struct sk_buff *skb,
       int *hotdrop)
 {
 	const struct xt_length_info *info = matchinfo;
-	u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
+	u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len);
 
 	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
 }
@@ -47,7 +47,8 @@ match6(const struct sk_buff *skb,
        int *hotdrop)
 {
 	const struct xt_length_info *info = matchinfo;
-	u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+	const u_int16_t pktlen = (ntohs(ipv6_hdr(skb)->payload_len) +
+				  sizeof(struct ipv6hdr));
 
 	return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
 }
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 6fd8347..571a72a 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -1,10 +1,3 @@
-/* Kernel module to control the rate
- *
- * 2 September 1999: Changed from the target RATE to the match
- *                   `limit', removed logging.  Did I mention that
- *                   Alexey is a fucking genius?
- *                   Rusty Russell (rusty@rustcorp.com.au).  */
-
 /* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
  * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
  *
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index d430d90..1d3a1d9 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -37,8 +37,8 @@ match(const struct sk_buff *skb,
     const struct xt_mac_info *info = matchinfo;
 
     /* Is mac pointer valid? */
-    return (skb->mac.raw >= skb->head
-	    && (skb->mac.raw + ETH_HLEN) <= skb->data
+    return (skb_mac_header(skb) >= skb->head &&
+	    (skb_mac_header(skb) + ETH_HLEN) <= skb->data
 	    /* If so, compare... */
 	    && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
 		^ info->invert));
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
index 16e7b08..e1409fc 100644
--- a/net/netfilter/xt_pkttype.c
+++ b/net/netfilter/xt_pkttype.c
@@ -34,7 +34,7 @@ static int match(const struct sk_buff *s
 	const struct xt_pkttype_info *info = matchinfo;
 
 	if (skb->pkt_type == PACKET_LOOPBACK)
-		type = (MULTICAST(skb->nh.iph->daddr)
+		type = (MULTICAST(ip_hdr(skb)->daddr)
 			? PACKET_MULTICAST
 			: PACKET_BROADCAST);
 	else
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
index 97ffc2f..c2017f8 100644
--- a/net/netfilter/xt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -1,7 +1,5 @@
 /* IP tables module for matching the routing realm
  *
- * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $
- *
  * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index df37b91..149294f 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -10,7 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
-#include <net/netfilter/nf_conntrack_compat.h>
+#include <net/netfilter/nf_conntrack.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_state.h>
 
@@ -36,7 +36,7 @@ match(const struct sk_buff *skb,
 
 	if (nf_ct_is_untracked(skb))
 		statebit = XT_STATE_UNTRACKED;
-	else if (!nf_ct_get_ctinfo(skb, &ctinfo))
+	else if (!nf_ct_get(skb, &ctinfo))
 		statebit = XT_STATE_INVALID;
 	else
 		statebit = XT_STATE_BIT(ctinfo);
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index e03a328..f2535e7 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -263,9 +263,6 @@ int netlbl_socket_setattr(const struct s
 	int ret_val = -ENOENT;
 	struct netlbl_dom_map *dom_entry;
 
-	if ((secattr->flags & NETLBL_SECATTR_DOMAIN) == 0)
-		return -ENOENT;
-
 	rcu_read_lock();
 	dom_entry = netlbl_domhsh_getentry(secattr->domain);
 	if (dom_entry == NULL)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index c48b0f4..1f15821 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -45,7 +45,6 @@ #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
 #include <linux/jhash.h>
@@ -56,6 +55,7 @@ #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/audit.h>
 #include <linux/selinux.h>
+#include <linux/mutex.h>
 
 #include <net/sock.h>
 #include <net/scm.h>
@@ -76,7 +76,8 @@ struct netlink_sock {
 	unsigned long		state;
 	wait_queue_head_t	wait;
 	struct netlink_callback	*cb;
-	spinlock_t		cb_lock;
+	struct mutex		*cb_mutex;
+	struct mutex		cb_def_mutex;
 	void			(*data_ready)(struct sock *sk, int bytes);
 	struct module		*module;
 };
@@ -108,6 +109,7 @@ struct netlink_table {
 	unsigned long *listeners;
 	unsigned int nl_nonroot;
 	unsigned int groups;
+	struct mutex *cb_mutex;
 	struct module *module;
 	int registered;
 };
@@ -118,6 +120,7 @@ static DECLARE_WAIT_QUEUE_HEAD(nl_table_
 
 static int netlink_dump(struct sock *sk);
 static void netlink_destroy_callback(struct netlink_callback *cb);
+static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb);
 
 static DEFINE_RWLOCK(nl_table_lock);
 static atomic_t nl_table_users = ATOMIC_INIT(0);
@@ -136,6 +139,14 @@ static struct hlist_head *nl_pid_hashfn(
 
 static void netlink_sock_destruct(struct sock *sk)
 {
+	struct netlink_sock *nlk = nlk_sk(sk);
+
+	if (nlk->cb) {
+		if (nlk->cb->done)
+			nlk->cb->done(nlk->cb);
+		netlink_destroy_callback(nlk->cb);
+	}
+
 	skb_queue_purge(&sk->sk_receive_queue);
 
 	if (!sock_flag(sk, SOCK_DEAD)) {
@@ -144,7 +155,6 @@ static void netlink_sock_destruct(struct
 	}
 	BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
 	BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
-	BUG_TRAP(!nlk_sk(sk)->cb);
 	BUG_TRAP(!nlk_sk(sk)->groups);
 }
 
@@ -370,7 +380,8 @@ static struct proto netlink_proto = {
 	.obj_size = sizeof(struct netlink_sock),
 };
 
-static int __netlink_create(struct socket *sock, int protocol)
+static int __netlink_create(struct socket *sock, struct mutex *cb_mutex,
+			    int protocol)
 {
 	struct sock *sk;
 	struct netlink_sock *nlk;
@@ -384,7 +395,12 @@ static int __netlink_create(struct socke
 	sock_init_data(sock, sk);
 
 	nlk = nlk_sk(sk);
-	spin_lock_init(&nlk->cb_lock);
+	if (cb_mutex)
+		nlk->cb_mutex = cb_mutex;
+	else {
+		nlk->cb_mutex = &nlk->cb_def_mutex;
+		mutex_init(nlk->cb_mutex);
+	}
 	init_waitqueue_head(&nlk->wait);
 
 	sk->sk_destruct = netlink_sock_destruct;
@@ -395,8 +411,8 @@ static int __netlink_create(struct socke
 static int netlink_create(struct socket *sock, int protocol)
 {
 	struct module *module = NULL;
+	struct mutex *cb_mutex;
 	struct netlink_sock *nlk;
-	unsigned int groups;
 	int err = 0;
 
 	sock->state = SS_UNCONNECTED;
@@ -418,10 +434,10 @@ #endif
 	if (nl_table[protocol].registered &&
 	    try_module_get(nl_table[protocol].module))
 		module = nl_table[protocol].module;
-	groups = nl_table[protocol].groups;
+	cb_mutex = nl_table[protocol].cb_mutex;
 	netlink_unlock_table();
 
-	if ((err = __netlink_create(sock, protocol)) < 0)
+	if ((err = __netlink_create(sock, cb_mutex, protocol)) < 0)
 		goto out_module;
 
 	nlk = nlk_sk(sock->sk);
@@ -446,17 +462,10 @@ static int netlink_release(struct socket
 	sock_orphan(sk);
 	nlk = nlk_sk(sk);
 
-	spin_lock(&nlk->cb_lock);
-	if (nlk->cb) {
-		if (nlk->cb->done)
-			nlk->cb->done(nlk->cb);
-		netlink_destroy_callback(nlk->cb);
-		nlk->cb = NULL;
-	}
-	spin_unlock(&nlk->cb_lock);
-
-	/* OK. Socket is unlinked, and, therefore,
-	   no new packets will arrive */
+	/*
+	 * OK. Socket is unlinked, any packets that arrive now
+	 * will be purged.
+	 */
 
 	sock->sk = NULL;
 	wake_up_interruptible_all(&nlk->wait);
@@ -1215,7 +1224,7 @@ static int netlink_recvmsg(struct kiocb 
 		copied = len;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
 	if (msg->msg_name) {
@@ -1235,13 +1244,14 @@ static int netlink_recvmsg(struct kiocb 
 		siocb->scm = &scm;
 	}
 	siocb->scm->creds = *NETLINK_CREDS(skb);
+	if (flags & MSG_TRUNC)
+		copied = skb->len;
 	skb_free_datagram(sk, skb);
 
 	if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
 		netlink_dump(sk);
 
 	scm_recv(sock, msg, siocb->scm, flags);
-
 out:
 	netlink_rcv_wake(sk);
 	return err ? : copied;
@@ -1265,7 +1275,7 @@ static void netlink_data_ready(struct so
 struct sock *
 netlink_kernel_create(int unit, unsigned int groups,
 		      void (*input)(struct sock *sk, int len),
-		      struct module *module)
+		      struct mutex *cb_mutex, struct module *module)
 {
 	struct socket *sock;
 	struct sock *sk;
@@ -1280,7 +1290,7 @@ netlink_kernel_create(int unit, unsigned
 	if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
 		return NULL;
 
-	if (__netlink_create(sock, unit) < 0)
+	if (__netlink_create(sock, cb_mutex, unit) < 0)
 		goto out_sock_release;
 
 	if (groups < 32)
@@ -1304,6 +1314,7 @@ netlink_kernel_create(int unit, unsigned
 	netlink_table_grab();
 	nl_table[unit].groups = groups;
 	nl_table[unit].listeners = listeners;
+	nl_table[unit].cb_mutex = cb_mutex;
 	nl_table[unit].module = module;
 	nl_table[unit].registered = 1;
 	netlink_table_ungrab();
@@ -1346,7 +1357,7 @@ static int netlink_dump(struct sock *sk)
 	if (!skb)
 		goto errout;
 
-	spin_lock(&nlk->cb_lock);
+	mutex_lock(nlk->cb_mutex);
 
 	cb = nlk->cb;
 	if (cb == NULL) {
@@ -1357,7 +1368,7 @@ static int netlink_dump(struct sock *sk)
 	len = cb->dump(skb, cb);
 
 	if (len > 0) {
-		spin_unlock(&nlk->cb_lock);
+		mutex_unlock(nlk->cb_mutex);
 		skb_queue_tail(&sk->sk_receive_queue, skb);
 		sk->sk_data_ready(sk, len);
 		return 0;
@@ -1375,13 +1386,13 @@ static int netlink_dump(struct sock *sk)
 	if (cb->done)
 		cb->done(cb);
 	nlk->cb = NULL;
-	spin_unlock(&nlk->cb_lock);
+	mutex_unlock(nlk->cb_mutex);
 
 	netlink_destroy_callback(cb);
 	return 0;
 
 errout_skb:
-	spin_unlock(&nlk->cb_lock);
+	mutex_unlock(nlk->cb_mutex);
 	kfree_skb(skb);
 errout:
 	return err;
@@ -1412,20 +1423,25 @@ int netlink_dump_start(struct sock *ssk,
 		return -ECONNREFUSED;
 	}
 	nlk = nlk_sk(sk);
-	/* A dump or destruction is in progress... */
-	spin_lock(&nlk->cb_lock);
-	if (nlk->cb || sock_flag(sk, SOCK_DEAD)) {
-		spin_unlock(&nlk->cb_lock);
+	/* A dump is in progress... */
+	mutex_lock(nlk->cb_mutex);
+	if (nlk->cb) {
+		mutex_unlock(nlk->cb_mutex);
 		netlink_destroy_callback(cb);
 		sock_put(sk);
 		return -EBUSY;
 	}
 	nlk->cb = cb;
-	spin_unlock(&nlk->cb_lock);
+	mutex_unlock(nlk->cb_mutex);
 
 	netlink_dump(sk);
 	sock_put(sk);
-	return 0;
+
+	/* We successfully started a dump, by returning -EINTR we
+	 * signal the queue mangement to interrupt processing of
+	 * any netlink messages so userspace gets a chance to read
+	 * the results. */
+	return -EINTR;
 }
 
 void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
@@ -1462,27 +1478,35 @@ void netlink_ack(struct sk_buff *in_skb,
 }
 
 static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
-						     struct nlmsghdr *, int *))
+						     struct nlmsghdr *))
 {
 	struct nlmsghdr *nlh;
 	int err;
 
 	while (skb->len >= nlmsg_total_size(0)) {
-		nlh = (struct nlmsghdr *) skb->data;
+		nlh = nlmsg_hdr(skb);
+		err = 0;
 
 		if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
 			return 0;
 
-		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
-			 * message from skb, it will be processed later.
-			 */
-			if (err == 0)
-				return -1;
+		/* Only requests are handled by the kernel */
+		if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
+			goto skip;
+
+		/* Skip control messages */
+		if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
+			goto skip;
+
+		err = cb(skb, nlh);
+		if (err == -EINTR) {
+			/* Not an error, but we interrupt processing */
+			netlink_queue_skip(nlh, skb);
+			return err;
+		}
+skip:
+		if (nlh->nlmsg_flags & NLM_F_ACK || err)
 			netlink_ack(skb, nlh, err);
-		} else if (nlh->nlmsg_flags & NLM_F_ACK)
-			netlink_ack(skb, nlh, 0);
 
 		netlink_queue_skip(nlh, skb);
 	}
@@ -1504,9 +1528,14 @@ static int netlink_rcv_skb(struct sk_buf
  *
  * qlen must be initialized to 0 before the initial entry, afterwards
  * the function may be called repeatedly until qlen reaches 0.
+ *
+ * The callback function may return -EINTR to signal that processing
+ * of netlink messages shall be interrupted. In this case the message
+ * currently being processed will NOT be requeued onto the receive
+ * queue.
  */
 void netlink_run_queue(struct sock *sk, unsigned int *qlen,
-		       int (*cb)(struct sk_buff *, struct nlmsghdr *, int *))
+		       int (*cb)(struct sk_buff *, struct nlmsghdr *))
 {
 	struct sk_buff *skb;
 
@@ -1537,7 +1566,7 @@ void netlink_run_queue(struct sock *sk, 
  * Pulls the given netlink message off the socket buffer so the next
  * call to netlink_queue_run() will not reconsider the message.
  */
-void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
+static void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
 {
 	int msglen = NLMSG_ALIGN(nlh->nlmsg_len);
 
@@ -1820,12 +1849,10 @@ core_initcall(netlink_proto_init);
 
 EXPORT_SYMBOL(netlink_ack);
 EXPORT_SYMBOL(netlink_run_queue);
-EXPORT_SYMBOL(netlink_queue_skip);
 EXPORT_SYMBOL(netlink_broadcast);
 EXPORT_SYMBOL(netlink_dump_start);
 EXPORT_SYMBOL(netlink_kernel_create);
 EXPORT_SYMBOL(netlink_register_notifier);
-EXPORT_SYMBOL(netlink_set_err);
 EXPORT_SYMBOL(netlink_set_nonroot);
 EXPORT_SYMBOL(netlink_unicast);
 EXPORT_SYMBOL(netlink_unregister_notifier);
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index 0041395..df5f820 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -67,6 +67,11 @@ static int validate_nla(struct nlattr *n
 		}
 		break;
 
+	case NLA_BINARY:
+		if (pt->len && attrlen > pt->len)
+			return -ERANGE;
+		break;
+
 	default:
 		if (pt->len)
 			minlen = pt->len;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index c299679..6e31234 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -295,66 +295,46 @@ int genl_unregister_family(struct genl_f
 	return -ENOENT;
 }
 
-static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
-			       int *errp)
+static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	struct genl_ops *ops;
 	struct genl_family *family;
 	struct genl_info info;
 	struct genlmsghdr *hdr = nlmsg_data(nlh);
-	int hdrlen, err = -EINVAL;
-
-	if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
-		goto ignore;
-
-	if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
-		goto ignore;
+	int hdrlen, err;
 
 	family = genl_family_find_byid(nlh->nlmsg_type);
-	if (family == NULL) {
-		err = -ENOENT;
-		goto errout;
-	}
+	if (family == NULL)
+		return -ENOENT;
 
 	hdrlen = GENL_HDRLEN + family->hdrsize;
 	if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
-		goto errout;
+		return -EINVAL;
 
 	ops = genl_get_cmd(hdr->cmd, family);
-	if (ops == NULL) {
-		err = -EOPNOTSUPP;
-		goto errout;
-	}
+	if (ops == NULL)
+		return -EOPNOTSUPP;
 
-	if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) {
-		err = -EPERM;
-		goto errout;
-	}
+	if ((ops->flags & GENL_ADMIN_PERM) &&
+	    security_netlink_recv(skb, CAP_NET_ADMIN))
+		return -EPERM;
 
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
-		if (ops->dumpit == NULL) {
-			err = -EOPNOTSUPP;
-			goto errout;
-		}
+		if (ops->dumpit == NULL)
+			return -EOPNOTSUPP;
 
-		*errp = err = netlink_dump_start(genl_sock, skb, nlh,
-						 ops->dumpit, ops->done);
-		if (err == 0)
-			skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len),
-					  skb->len));
-		return -1;
+		return netlink_dump_start(genl_sock, skb, nlh,
+					  ops->dumpit, ops->done);
 	}
 
-	if (ops->doit == NULL) {
-		err = -EOPNOTSUPP;
-		goto errout;
-	}
+	if (ops->doit == NULL)
+		return -EOPNOTSUPP;
 
 	if (family->attrbuf) {
 		err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
 				  ops->policy);
 		if (err < 0)
-			goto errout;
+			return err;
 	}
 
 	info.snd_seq = nlh->nlmsg_seq;
@@ -364,15 +344,7 @@ static int genl_rcv_msg(struct sk_buff *
 	info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
 	info.attrs = family->attrbuf;
 
-	*errp = err = ops->doit(skb, &info);
-	return err;
-
-ignore:
-	return 0;
-
-errout:
-	*errp = err;
-	return -1;
+	return ops->doit(skb, &info);
 }
 
 static void genl_rcv(struct sock *sk, int len)
@@ -586,7 +558,7 @@ static int __init genl_init(void)
 
 	netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
 	genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
-					  genl_rcv, THIS_MODULE);
+					  genl_rcv, NULL, THIS_MODULE);
 	if (genl_sock == NULL)
 		panic("GENL: Cannot initialize generic netlink\n");
 
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index bf9837d..5d4a26c 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -625,42 +625,42 @@ static int nr_connect(struct socket *soc
 	ax25_address *source = NULL;
 	ax25_uid_assoc *user;
 	struct net_device *dev;
+	int err = 0;
 
 	lock_sock(sk);
 	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
-		release_sock(sk);
-		return 0;	/* Connect completed during a ERESTARTSYS event */
+		goto out_release;	/* Connect completed during a ERESTARTSYS event */
 	}
 
 	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
 		sock->state = SS_UNCONNECTED;
-		release_sock(sk);
-		return -ECONNREFUSED;
+		err = -ECONNREFUSED;
+		goto out_release;
 	}
 
 	if (sk->sk_state == TCP_ESTABLISHED) {
-		release_sock(sk);
-		return -EISCONN;	/* No reconnect on a seqpacket socket */
+		err = -EISCONN;	/* No reconnect on a seqpacket socket */
+		goto out_release;
 	}
 
 	sk->sk_state   = TCP_CLOSE;
 	sock->state = SS_UNCONNECTED;
 
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
-		release_sock(sk);
-		return -EINVAL;
+		err = -EINVAL;
+		goto out_release;
 	}
 	if (addr->sax25_family != AF_NETROM) {
-		release_sock(sk);
-		return -EINVAL;
+		err = -EINVAL;
+		goto out_release;
 	}
 	if (sock_flag(sk, SOCK_ZAPPED)) {	/* Must bind first - autobinding in this may or may not work */
 		sock_reset_flag(sk, SOCK_ZAPPED);
 
 		if ((dev = nr_dev_first()) == NULL) {
-			release_sock(sk);
-			return -ENETUNREACH;
+			err = -ENETUNREACH;
+			goto out_release;
 		}
 		source = (ax25_address *)dev->dev_addr;
 
@@ -671,8 +671,8 @@ static int nr_connect(struct socket *soc
 		} else {
 			if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
 				dev_put(dev);
-				release_sock(sk);
-				return -EPERM;
+				err = -EPERM;
+				goto out_release;
 			}
 			nr->user_addr   = *source;
 		}
@@ -707,8 +707,8 @@ static int nr_connect(struct socket *soc
 
 	/* Now the loop */
 	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
-		release_sock(sk);
-		return -EINPROGRESS;
+		err = -EINPROGRESS;
+		goto out_release;
 	}
 
 	/*
@@ -716,46 +716,46 @@ static int nr_connect(struct socket *soc
 	 * closed.
 	 */
 	if (sk->sk_state == TCP_SYN_SENT) {
-		struct task_struct *tsk = current;
-		DECLARE_WAITQUEUE(wait, tsk);
+		DEFINE_WAIT(wait);
 
-		add_wait_queue(sk->sk_sleep, &wait);
 		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
+			prepare_to_wait(sk->sk_sleep, &wait,
+			                TASK_INTERRUPTIBLE);
 			if (sk->sk_state != TCP_SYN_SENT)
 				break;
-			release_sock(sk);
-			if (!signal_pending(tsk)) {
+			if (!signal_pending(current)) {
+				release_sock(sk);
 				schedule();
 				lock_sock(sk);
 				continue;
 			}
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -ERESTARTSYS;
+			err = -ERESTARTSYS;
+			break;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
+		if (err)
+			goto out_release;
 	}
 
 	if (sk->sk_state != TCP_ESTABLISHED) {
 		sock->state = SS_UNCONNECTED;
-		release_sock(sk);
-		return sock_error(sk);	/* Always set at this point */
+		err = sock_error(sk);	/* Always set at this point */
+		goto out_release;
 	}
 
 	sock->state = SS_CONNECTED;
+
+out_release:
 	release_sock(sk);
 
-	return 0;
+	return err;
 }
 
 static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
 	struct sock *newsk;
+	DEFINE_WAIT(wait);
 	struct sock *sk;
 	int err = 0;
 
@@ -765,42 +765,40 @@ static int nr_accept(struct socket *sock
 	lock_sock(sk);
 	if (sk->sk_type != SOCK_SEQPACKET) {
 		err = -EOPNOTSUPP;
-		goto out;
+		goto out_release;
 	}
 
 	if (sk->sk_state != TCP_LISTEN) {
 		err = -EINVAL;
-		goto out;
+		goto out_release;
 	}
 
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	add_wait_queue(sk->sk_sleep, &wait);
 	for (;;) {
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
 		skb = skb_dequeue(&sk->sk_receive_queue);
 		if (skb)
 			break;
 
-		current->state = TASK_INTERRUPTIBLE;
-		release_sock(sk);
 		if (flags & O_NONBLOCK) {
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -EWOULDBLOCK;
+			err = -EWOULDBLOCK;
+			break;
 		}
-		if (!signal_pending(tsk)) {
+		if (!signal_pending(current)) {
+			release_sock(sk);
 			schedule();
 			lock_sock(sk);
 			continue;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
-		return -ERESTARTSYS;
+		err = -ERESTARTSYS;
+		break;
 	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sk_sleep, &wait);
+	finish_wait(sk->sk_sleep, &wait);
+	if (err)
+		goto out_release;
 
 	newsk = skb->sk;
 	newsk->sk_socket = newsock;
@@ -811,8 +809,9 @@ static int nr_accept(struct socket *sock
 	sk_acceptq_removed(sk);
 	newsock->sk = newsk;
 
-out:
+out_release:
 	release_sock(sk);
+
 	return err;
 }
 
@@ -878,7 +877,7 @@ int nr_rx_frame(struct sk_buff *skb, str
 	if (frametype == NR_PROTOEXT &&
 	    circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {
 		skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 
 		return nr_rx_ip(skb, dev);
 	}
@@ -904,7 +903,7 @@ int nr_rx_frame(struct sk_buff *skb, str
 	}
 
 	if (sk != NULL) {
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 
 		if (frametype == NR_CONNACK && skb->len == 22)
 			nr_sk(sk)->bpqext = 1;
@@ -1074,6 +1073,7 @@ static int nr_sendmsg(struct kiocb *iocb
 		goto out;
 
 	skb_reserve(skb, size - len);
+	skb_reset_transport_header(skb);
 
 	/*
 	 *	Push down the NET/ROM header
@@ -1094,14 +1094,12 @@ static int nr_sendmsg(struct kiocb *iocb
 	/*
 	 *	Put the data on the end
 	 */
+	skb_put(skb, len);
 
-	skb->h.raw = skb_put(skb, len);
-
-	asmptr = skb->h.raw;
 	SOCK_DEBUG(sk, "NET/ROM: Appending user data\n");
 
 	/* User data follows immediately after the NET/ROM transport header */
-	if (memcpy_fromiovec(asmptr, msg->msg_iov, len)) {
+	if (memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len)) {
 		kfree_skb(skb);
 		err = -EFAULT;
 		goto out;
@@ -1149,7 +1147,7 @@ static int nr_recvmsg(struct kiocb *iocb
 		return er;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	copied     = skb->len;
 
 	if (copied > size) {
@@ -1161,7 +1159,8 @@ static int nr_recvmsg(struct kiocb *iocb
 
 	if (sax != NULL) {
 		sax->sax25_family = AF_NETROM;
-		memcpy(sax->sax25_call.ax25_call, skb->data + 7, AX25_ADDR_LEN);
+		skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
+			      AX25_ADDR_LEN);
 	}
 
 	msg->msg_namelen = sizeof(*sax);
@@ -1209,6 +1208,12 @@ static int nr_ioctl(struct socket *sock,
 		release_sock(sk);
 		return ret;
 
+	case SIOCGSTAMPNS:
+		lock_sock(sk);
+		ret = sock_get_timestampns(sk, argp);
+		release_sock(sk);
+		return ret;
+
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 9a97ed6..c7b5d93 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -56,8 +56,8 @@ int nr_rx_ip(struct sk_buff *skb, struct
 
 	/* Spoof incoming device */
 	skb->dev      = dev;
-	skb->mac.raw  = skb->nh.raw;
-	skb->nh.raw   = skb->data;
+	skb_reset_mac_header(skb);
+	skb_reset_network_header(skb);
 	skb->pkt_type = PACKET_HOST;
 
 	netif_rx(skb);
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
index 5560acb..6817648 100644
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -51,10 +51,12 @@ static int nr_queue_rx_frame(struct sock
 		if ((skbn = alloc_skb(nr->fraglen, GFP_ATOMIC)) == NULL)
 			return 1;
 
-		skbn->h.raw = skbn->data;
+		skb_reset_transport_header(skbn);
 
 		while ((skbo = skb_dequeue(&nr->frag_queue)) != NULL) {
-			memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+			skb_copy_from_linear_data(skbo,
+						  skb_put(skbn, skbo->len),
+						  skbo->len);
 			kfree_skb(skbo);
 		}
 
diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
index e856ae1..f324d5d 100644
--- a/net/netrom/nr_loopback.c
+++ b/net/netrom/nr_loopback.c
@@ -34,8 +34,8 @@ int nr_loopback_queue(struct sk_buff *sk
 	struct sk_buff *skbn;
 
 	if ((skbn = alloc_skb(skb->len, GFP_ATOMIC)) != NULL) {
-		memcpy(skb_put(skbn, skb->len), skb->data, skb->len);
-		skbn->h.raw = skbn->data;
+		skb_copy_from_linear_data(skb, skb_put(skbn, skb->len), skb->len);
+		skb_reset_transport_header(skbn);
 
 		skb_queue_tail(&loopback_queue, skbn);
 
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
index 0cbfb61..e3e6c44 100644
--- a/net/netrom/nr_out.c
+++ b/net/netrom/nr_out.c
@@ -40,7 +40,7 @@ void nr_output(struct sock *sk, struct s
 
 	if (skb->len - NR_TRANSPORT_LEN > NR_MAX_PACKET_SIZE) {
 		/* Save a copy of the Transport Header */
-		memcpy(transport, skb->data, NR_TRANSPORT_LEN);
+		skb_copy_from_linear_data(skb, transport, NR_TRANSPORT_LEN);
 		skb_pull(skb, NR_TRANSPORT_LEN);
 
 		frontlen = skb_headroom(skb);
@@ -54,13 +54,13 @@ void nr_output(struct sock *sk, struct s
 			len = (NR_MAX_PACKET_SIZE > skb->len) ? skb->len : NR_MAX_PACKET_SIZE;
 
 			/* Copy the user data */
-			memcpy(skb_put(skbn, len), skb->data, len);
+			skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
 			skb_pull(skb, len);
 
 			/* Duplicate the Transport Header */
 			skb_push(skbn, NR_TRANSPORT_LEN);
-			memcpy(skbn->data, transport, NR_TRANSPORT_LEN);
-
+			skb_copy_to_linear_data(skbn, transport,
+						NR_TRANSPORT_LEN);
 			if (skb->len > 0)
 				skbn->data[4] |= NR_MORE_FLAG;
 
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 8e6bd4e..2f76e06 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -598,7 +598,7 @@ struct net_device *nr_dev_first(void)
 	struct net_device *dev, *first = NULL;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 				first = dev;
@@ -618,12 +618,13 @@ struct net_device *nr_dev_get(ax25_addre
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
 			dev_hold(dev);
 			goto out;
 		}
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev;
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
index 07b694d..04e7d0d 100644
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -226,13 +226,13 @@ void __nr_transmit_reply(struct sk_buff 
 
 	dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
-	memcpy(dptr, skb->data + 7, AX25_ADDR_LEN);
+	skb_copy_from_linear_data_offset(skb, 7, dptr, AX25_ADDR_LEN);
 	dptr[6] &= ~AX25_CBIT;
 	dptr[6] &= ~AX25_EBIT;
 	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
-	memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
+	skb_copy_from_linear_data(skb, dptr, AX25_ADDR_LEN);
 	dptr[6] &= ~AX25_CBIT;
 	dptr[6] |= AX25_EBIT;
 	dptr[6] |= AX25_SSSID_SPARE;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 28d47e8..02e401c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -114,22 +114,22 @@ On receive:
 -----------
 
 Incoming, dev->hard_header!=NULL
-   mac.raw -> ll header
-   data    -> data
+   mac_header -> ll header
+   data       -> data
 
 Outgoing, dev->hard_header!=NULL
-   mac.raw -> ll header
-   data    -> ll header
+   mac_header -> ll header
+   data       -> ll header
 
 Incoming, dev->hard_header==NULL
-   mac.raw -> UNKNOWN position. It is very likely, that it points to ll header.
-	      PPP makes it, that is wrong, because introduce assymetry
-	      between rx and tx paths.
-   data    -> data
+   mac_header -> UNKNOWN position. It is very likely, that it points to ll
+		 header.  PPP makes it, that is wrong, because introduce
+                 assymetry between rx and tx paths.
+   data       -> data
 
 Outgoing, dev->hard_header==NULL
-   mac.raw -> data. ll header is still not built!
-   data    -> data
+   mac_header -> data. ll header is still not built!
+   data       -> data
 
 Resume
   If dev->hard_header==NULL we are unlikely to restore sensible ll header.
@@ -139,12 +139,12 @@ On transmit:
 ------------
 
 dev->hard_header != NULL
-   mac.raw -> ll header
-   data    -> ll header
+   mac_header -> ll header
+   data       -> ll header
 
 dev->hard_header == NULL (ll header is added by device, we cannot control it)
-   mac.raw -> data
-   data -> data
+   mac_header -> data
+   data       -> data
 
    We should set nh.raw on output to correct posistion,
    packet classifier depends on it.
@@ -201,7 +201,8 @@ #endif
 	struct packet_type	prot_hook;
 	spinlock_t		bind_lock;
 	unsigned int		running:1,	/* prot_hook is attached*/
-				auxdata:1;
+				auxdata:1,
+				origdev:1;
 	int			ifindex;	/* bound device		*/
 	__be16			num;
 #ifdef CONFIG_PACKET_MULTICAST
@@ -284,7 +285,7 @@ static int packet_rcv_spkt(struct sk_buf
 	 *	Incoming packets have ll header pulled,
 	 *	push it back.
 	 *
-	 *	For outgoing ones skb->data == skb->mac.raw
+	 *	For outgoing ones skb->data == skb_mac_header(skb)
 	 *	so that this procedure is noop.
 	 */
 
@@ -303,7 +304,7 @@ static int packet_rcv_spkt(struct sk_buf
 
 	spkt = &PACKET_SKB_CB(skb)->sa.pkt;
 
-	skb_push(skb, skb->data-skb->mac.raw);
+	skb_push(skb, skb->data - skb_mac_header(skb));
 
 	/*
 	 *	The SOCK_PACKET socket receives _all_ frames.
@@ -401,14 +402,14 @@ static int packet_sendmsg_spkt(struct ki
 	 * notable one here. This should really be fixed at the driver level.
 	 */
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	/* Try to align data part correctly */
 	if (dev->hard_header) {
 		skb->data -= dev->hard_header_len;
 		skb->tail -= dev->hard_header_len;
 		if (len < dev->hard_header_len)
-			skb->nh.raw = skb->data;
+			skb_reset_network_header(skb);
 	}
 
 	/* Returns -EFAULT on error */
@@ -488,10 +489,10 @@ static int packet_rcv(struct sk_buff *sk
 		   never delivered to user.
 		 */
 		if (sk->sk_type != SOCK_DGRAM)
-			skb_push(skb, skb->data - skb->mac.raw);
+			skb_push(skb, skb->data - skb_mac_header(skb));
 		else if (skb->pkt_type == PACKET_OUTGOING) {
 			/* Special case: outgoing packets have ll header at head */
-			skb_pull(skb, skb->nh.raw - skb->data);
+			skb_pull(skb, skb_network_offset(skb));
 		}
 	}
 
@@ -528,7 +529,10 @@ static int packet_rcv(struct sk_buff *sk
 	sll->sll_hatype = dev->type;
 	sll->sll_protocol = skb->protocol;
 	sll->sll_pkttype = skb->pkt_type;
-	sll->sll_ifindex = dev->ifindex;
+	if (unlikely(po->origdev) && skb->pkt_type == PACKET_HOST)
+		sll->sll_ifindex = orig_dev->ifindex;
+	else
+		sll->sll_ifindex = dev->ifindex;
 	sll->sll_halen = 0;
 
 	if (dev->hard_header_parse)
@@ -582,6 +586,7 @@ static int tpacket_rcv(struct sk_buff *s
 	unsigned long status = TP_STATUS_LOSING|TP_STATUS_USER;
 	unsigned short macoff, netoff;
 	struct sk_buff *copy_skb = NULL;
+	struct timeval tv;
 
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		goto drop;
@@ -591,10 +596,10 @@ static int tpacket_rcv(struct sk_buff *s
 
 	if (dev->hard_header) {
 		if (sk->sk_type != SOCK_DGRAM)
-			skb_push(skb, skb->data - skb->mac.raw);
+			skb_push(skb, skb->data - skb_mac_header(skb));
 		else if (skb->pkt_type == PACKET_OUTGOING) {
 			/* Special case: outgoing packets have ll header at head */
-			skb_pull(skb, skb->nh.raw - skb->data);
+			skb_pull(skb, skb_network_offset(skb));
 		}
 	}
 
@@ -612,7 +617,7 @@ static int tpacket_rcv(struct sk_buff *s
 	if (sk->sk_type == SOCK_DGRAM) {
 		macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16;
 	} else {
-		unsigned maclen = skb->nh.raw - skb->data;
+		unsigned maclen = skb_network_offset(skb);
 		netoff = TPACKET_ALIGN(TPACKET_HDRLEN + (maclen < 16 ? 16 : maclen));
 		macoff = netoff - maclen;
 	}
@@ -656,12 +661,13 @@ static int tpacket_rcv(struct sk_buff *s
 	h->tp_snaplen = snaplen;
 	h->tp_mac = macoff;
 	h->tp_net = netoff;
-	if (skb->tstamp.off_sec == 0) {
+	if (skb->tstamp.tv64 == 0) {
 		__net_timestamp(skb);
 		sock_enable_timestamp(sk);
 	}
-	h->tp_sec = skb->tstamp.off_sec;
-	h->tp_usec = skb->tstamp.off_usec;
+	tv = ktime_to_timeval(skb->tstamp);
+	h->tp_sec = tv.tv_sec;
+	h->tp_usec = tv.tv_usec;
 
 	sll = (struct sockaddr_ll*)((u8*)h + TPACKET_ALIGN(sizeof(*h)));
 	sll->sll_halen = 0;
@@ -671,7 +677,10 @@ static int tpacket_rcv(struct sk_buff *s
 	sll->sll_hatype = dev->type;
 	sll->sll_protocol = skb->protocol;
 	sll->sll_pkttype = skb->pkt_type;
-	sll->sll_ifindex = dev->ifindex;
+	if (unlikely(po->origdev) && skb->pkt_type == PACKET_HOST)
+		sll->sll_ifindex = orig_dev->ifindex;
+	else
+		sll->sll_ifindex = dev->ifindex;
 
 	h->tp_status = status;
 	smp_mb();
@@ -766,14 +775,14 @@ static int packet_sendmsg(struct kiocb *
 		goto out_unlock;
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	if (dev->hard_header) {
 		int res;
 		err = -EINVAL;
 		res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
 		if (sock->type != SOCK_DGRAM) {
-			skb->tail = skb->data;
+			skb_reset_tail_pointer(skb);
 			skb->len = 0;
 		} else if (res < 0)
 			goto out_free;
@@ -1143,7 +1152,7 @@ #endif
 		aux.tp_len = PACKET_SKB_CB(skb)->origlen;
 		aux.tp_snaplen = skb->len;
 		aux.tp_mac = 0;
-		aux.tp_net = skb->nh.raw - skb->data;
+		aux.tp_net = skb_network_offset(skb);
 
 		put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
 	}
@@ -1411,6 +1420,18 @@ #endif
 		po->auxdata = !!val;
 		return 0;
 	}
+	case PACKET_ORIGDEV:
+	{
+		int val;
+
+		if (optlen < sizeof(val))
+			return -EINVAL;
+		if (copy_from_user(&val, optval, sizeof(val)))
+			return -EFAULT;
+
+		po->origdev = !!val;
+		return 0;
+	}
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -1454,6 +1475,13 @@ static int packet_getsockopt(struct sock
 
 		data = &val;
 		break;
+	case PACKET_ORIGDEV:
+		if (len > sizeof(int))
+			len = sizeof(int);
+		val = po->origdev;
+
+		data = &val;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -1543,6 +1571,8 @@ static int packet_ioctl(struct socket *s
 		}
 		case SIOCGSTAMP:
 			return sock_get_timestamp(sk, (struct timeval __user *)arg);
+		case SIOCGSTAMPNS:
+			return sock_get_timestampns(sk, (struct timespec __user *)arg);
 
 #ifdef CONFIG_INET
 		case SIOCADDRT:
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig
new file mode 100644
index 0000000..8b31759
--- /dev/null
+++ b/net/rfkill/Kconfig
@@ -0,0 +1,24 @@
+#
+# RF switch subsystem configuration
+#
+menuconfig RFKILL
+	tristate "RF switch subsystem support"
+	help
+	  Say Y here if you want to have control over RF switches
+	  found on many WiFi, Bluetooth and IRDA cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rfkill.
+
+config RFKILL_INPUT
+	tristate "Input layer to RF switch connector"
+	depends on RFKILL && INPUT
+	help
+	  Say Y here if you want kernel automatically toggle state
+	  of RF switches on and off when user presses appropriate
+	  button or a key on the keyboard. Without this module you
+	  need a some kind of userspace application to control
+	  state of the switches.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rfkill-input.
diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile
new file mode 100644
index 0000000..b38c430
--- /dev/null
+++ b/net/rfkill/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the RF switch subsystem.
+#
+
+obj-$(CONFIG_RFKILL)			+= rfkill.o
+obj-$(CONFIG_RFKILL_INPUT)		+= rfkill-input.o
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
new file mode 100644
index 0000000..e5c840c
--- /dev/null
+++ b/net/rfkill/rfkill-input.c
@@ -0,0 +1,174 @@
+/*
+ * Input layer to RF Kill interface connector
+ *
+ * Copyright (c) 2007 Dmitry Torokhov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/init.h>
+#include <linux/rfkill.h>
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("Input layer to RF switch connector");
+MODULE_LICENSE("GPL");
+
+struct rfkill_task {
+	struct work_struct work;
+	enum rfkill_type type;
+	struct mutex mutex; /* ensures that task is serialized */
+	spinlock_t lock; /* for accessing last and desired state */
+	unsigned long last; /* last schedule */
+	enum rfkill_state desired_state; /* on/off */
+	enum rfkill_state current_state; /* on/off */
+};
+
+static void rfkill_task_handler(struct work_struct *work)
+{
+	struct rfkill_task *task = container_of(work, struct rfkill_task, work);
+	enum rfkill_state state;
+
+	mutex_lock(&task->mutex);
+
+	/*
+	 * Use temp variable to fetch desired state to keep it
+	 * consistent even if rfkill_schedule_toggle() runs in
+	 * another thread or interrupts us.
+	 */
+	state = task->desired_state;
+
+	if (state != task->current_state) {
+		rfkill_switch_all(task->type, state);
+		task->current_state = state;
+	}
+
+	mutex_unlock(&task->mutex);
+}
+
+static void rfkill_schedule_toggle(struct rfkill_task *task)
+{
+	unsigned int flags;
+
+	spin_lock_irqsave(&task->lock, flags);
+
+	if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
+		task->desired_state = !task->desired_state;
+		task->last = jiffies;
+		schedule_work(&task->work);
+	}
+
+	spin_unlock_irqrestore(&task->lock, flags);
+}
+
+#define DEFINE_RFKILL_TASK(n, t)			\
+	struct rfkill_task n = {			\
+		.work = __WORK_INITIALIZER(n.work,	\
+				rfkill_task_handler),	\
+		.type = t,				\
+		.mutex = __MUTEX_INITIALIZER(n.mutex),	\
+		.lock = __SPIN_LOCK_UNLOCKED(n.lock),	\
+		.desired_state = RFKILL_STATE_ON,	\
+		.current_state = RFKILL_STATE_ON,	\
+	}
+
+static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
+static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
+
+static void rfkill_event(struct input_handle *handle, unsigned int type,
+		        unsigned int code, int down)
+{
+	if (type == EV_KEY && down == 1) {
+		switch (code) {
+		case KEY_WLAN:
+			rfkill_schedule_toggle(&rfkill_wlan);
+			break;
+		case KEY_BLUETOOTH:
+			rfkill_schedule_toggle(&rfkill_bt);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
+			  const struct input_device_id *id)
+{
+	struct input_handle *handle;
+	int error;
+
+	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
+
+	handle->dev = dev;
+	handle->handler = handler;
+	handle->name = "rfkill";
+
+	error = input_register_handle(handle);
+	if (error)
+		goto err_free_handle;
+
+	error = input_open_device(handle);
+	if (error)
+		goto err_unregister_handle;
+
+	return 0;
+
+ err_unregister_handle:
+	input_unregister_handle(handle);
+ err_free_handle:
+	kfree(handle);
+	return error;
+}
+
+static void rfkill_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	input_unregister_handle(handle);
+	kfree(handle);
+}
+
+static const struct input_device_id rfkill_ids[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+		.evbit = { BIT(EV_KEY) },
+		.keybit = { [LONG(KEY_WLAN)] = BIT(KEY_WLAN) },
+	},
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+		.evbit = { BIT(EV_KEY) },
+		.keybit = { [LONG(KEY_BLUETOOTH)] = BIT(KEY_BLUETOOTH) },
+	},
+	{ }
+};
+
+static struct input_handler rfkill_handler = {
+	.event =	rfkill_event,
+	.connect =	rfkill_connect,
+	.disconnect =	rfkill_disconnect,
+	.name =		"rfkill",
+	.id_table =	rfkill_ids,
+};
+
+static int __init rfkill_handler_init(void)
+{
+	return input_register_handler(&rfkill_handler);
+}
+
+static void __exit rfkill_handler_exit(void)
+{
+	input_unregister_handler(&rfkill_handler);
+	flush_scheduled_work();
+}
+
+module_init(rfkill_handler_init);
+module_exit(rfkill_handler_exit);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
new file mode 100644
index 0000000..a973603
--- /dev/null
+++ b/net/rfkill/rfkill.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2006 Ivo van Doorn
+ * Copyright (C) 2007 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/capability.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rfkill.h>
+
+MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("RF switch support");
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(rfkill_list);	/* list of registered rf switches */
+static DEFINE_MUTEX(rfkill_mutex);
+
+static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
+
+static int rfkill_toggle_radio(struct rfkill *rfkill,
+				enum rfkill_state state)
+{
+	int retval;
+
+	retval = mutex_lock_interruptible(&rfkill->mutex);
+	if (retval)
+		return retval;
+
+	if (state != rfkill->state) {
+		retval = rfkill->toggle_radio(rfkill->data, state);
+		if (!retval)
+			rfkill->state = state;
+	}
+
+	mutex_unlock(&rfkill->mutex);
+	return retval;
+}
+
+/**
+ * rfkill_switch_all - Toggle state of all switches of given type
+ * @type: type of interfaces to be affeceted
+ * @state: the new state
+ *
+ * This function toggles state of all switches of given type unless
+ * a specific switch is claimed by userspace in which case it is
+ * left alone.
+ */
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
+{
+	struct rfkill *rfkill;
+
+	mutex_lock(&rfkill_mutex);
+
+	rfkill_states[type] = state;
+
+	list_for_each_entry(rfkill, &rfkill_list, node) {
+		if (!rfkill->user_claim)
+			rfkill_toggle_radio(rfkill, state);
+	}
+
+	mutex_unlock(&rfkill_mutex);
+}
+EXPORT_SYMBOL(rfkill_switch_all);
+
+static ssize_t rfkill_name_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	return sprintf(buf, "%s\n", rfkill->name);
+}
+
+static ssize_t rfkill_type_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+	const char *type;
+
+	switch (rfkill->type) {
+	case RFKILL_TYPE_WLAN:
+		type = "wlan";
+		break;
+	case RFKILL_TYPE_BLUETOOTH:
+		type = "bluetooth";
+		break;
+	case RFKILL_TYPE_IRDA:
+		type = "irda";
+		break;
+	default:
+		BUG();
+	}
+
+	return sprintf(buf, "%s\n", type);
+}
+
+static ssize_t rfkill_state_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	return sprintf(buf, "%d\n", rfkill->state);
+}
+
+static ssize_t rfkill_state_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+	unsigned int state = simple_strtoul(buf, NULL, 0);
+	int error;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	error = rfkill_toggle_radio(rfkill,
+			state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
+	if (error)
+		return error;
+
+	return count;
+}
+
+static ssize_t rfkill_claim_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	return sprintf(buf, "%d", rfkill->user_claim);
+}
+
+static ssize_t rfkill_claim_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+	bool claim = !!simple_strtoul(buf, NULL, 0);
+	int error;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	/*
+	 * Take the global lock to make sure the kernel is not in
+	 * the middle of rfkill_switch_all
+	 */
+	error = mutex_lock_interruptible(&rfkill_mutex);
+	if (error)
+		return error;
+
+	if (rfkill->user_claim != claim) {
+		if (!claim)
+			rfkill_toggle_radio(rfkill,
+					    rfkill_states[rfkill->type]);
+		rfkill->user_claim = claim;
+	}
+
+	mutex_unlock(&rfkill_mutex);
+
+	return count;
+}
+
+static struct device_attribute rfkill_dev_attrs[] = {
+	__ATTR(name, S_IRUGO, rfkill_name_show, NULL),
+	__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
+	__ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
+	__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
+	__ATTR_NULL
+};
+
+static void rfkill_release(struct device *dev)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	kfree(rfkill);
+	module_put(THIS_MODULE);
+}
+
+#ifdef CONFIG_PM
+static int rfkill_suspend(struct device *dev, pm_message_t state)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	if (dev->power.power_state.event != state.event) {
+		if (state.event == PM_EVENT_SUSPEND) {
+			mutex_lock(&rfkill->mutex);
+
+			if (rfkill->state == RFKILL_STATE_ON)
+				rfkill->toggle_radio(rfkill->data,
+						     RFKILL_STATE_OFF);
+
+			mutex_unlock(&rfkill->mutex);
+		}
+
+		dev->power.power_state = state;
+	}
+
+	return 0;
+}
+
+static int rfkill_resume(struct device *dev)
+{
+	struct rfkill *rfkill = to_rfkill(dev);
+
+	if (dev->power.power_state.event != PM_EVENT_ON) {
+		mutex_lock(&rfkill->mutex);
+
+		if (rfkill->state == RFKILL_STATE_ON)
+			rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
+
+		mutex_unlock(&rfkill->mutex);
+	}
+
+	dev->power.power_state = PMSG_ON;
+	return 0;
+}
+#else
+#define rfkill_suspend NULL
+#define rfkill_resume NULL
+#endif
+
+static struct class rfkill_class = {
+	.name		= "rfkill",
+	.dev_release	= rfkill_release,
+	.dev_attrs	= rfkill_dev_attrs,
+	.suspend	= rfkill_suspend,
+	.resume		= rfkill_resume,
+};
+
+static int rfkill_add_switch(struct rfkill *rfkill)
+{
+	int retval;
+
+	retval = mutex_lock_interruptible(&rfkill_mutex);
+	if (retval)
+		return retval;
+
+	retval = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
+	if (retval)
+		goto out;
+
+	list_add_tail(&rfkill->node, &rfkill_list);
+
+ out:
+	mutex_unlock(&rfkill_mutex);
+	return retval;
+}
+
+static void rfkill_remove_switch(struct rfkill *rfkill)
+{
+	mutex_lock(&rfkill_mutex);
+	list_del_init(&rfkill->node);
+	rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
+	mutex_unlock(&rfkill_mutex);
+}
+
+/**
+ * rfkill_allocate - allocate memory for rfkill structure.
+ * @parent: device that has rf switch on it
+ * @type: type of the switch (wlan, bluetooth, irda)
+ *
+ * This function should be called by the network driver when it needs
+ * rfkill structure. Once the structure is allocated the driver shoud
+ * finish its initialization by setting name, private data, enable_radio
+ * and disable_radio methods and then register it with rfkill_register().
+ * NOTE: If registration fails the structure shoudl be freed by calling
+ * rfkill_free() otherwise rfkill_unregister() should be used.
+ */
+struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type)
+{
+	struct rfkill *rfkill;
+	struct device *dev;
+
+	rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
+	if (rfkill)
+		return NULL;
+
+	mutex_init(&rfkill->mutex);
+	INIT_LIST_HEAD(&rfkill->node);
+	rfkill->type = type;
+
+	dev = &rfkill->dev;
+	dev->class = &rfkill_class;
+	dev->parent = parent;
+	device_initialize(dev);
+
+	__module_get(THIS_MODULE);
+
+	return rfkill;
+}
+EXPORT_SYMBOL(rfkill_allocate);
+
+/**
+ * rfkill_free - Mark rfkill structure for deletion
+ * @rfkill: rfkill structure to be destroyed
+ *
+ * Decrements reference count of rfkill structure so it is destoryed.
+ * Note that rfkill_free() should _not_ be called after rfkill_unregister().
+ */
+void rfkill_free(struct rfkill *rfkill)
+{
+	if (rfkill)
+		put_device(&rfkill->dev);
+}
+EXPORT_SYMBOL(rfkill_free);
+
+/**
+ * rfkill_register - Register a rfkill structure.
+ * @rfkill: rfkill structure to be registered
+ *
+ * This function should be called by the network driver when the rfkill
+ * structure needs to be registered. Immediately from registration the
+ * switch driver should be able to service calls to toggle_radio.
+ */
+int rfkill_register(struct rfkill *rfkill)
+{
+	static atomic_t rfkill_no = ATOMIC_INIT(0);
+	struct device *dev = &rfkill->dev;
+	int error;
+
+	if (!rfkill->toggle_radio)
+		return -EINVAL;
+
+	error = rfkill_add_switch(rfkill);
+	if (error)
+		return error;
+
+	snprintf(dev->bus_id, sizeof(dev->bus_id),
+		 "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
+
+	error = device_add(dev);
+	if (error) {
+		rfkill_remove_switch(rfkill);
+		return error;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rfkill_register);
+
+/**
+ * rfkill_unregister - Uegister a rfkill structure.
+ * @rfkill: rfkill structure to be unregistered
+ *
+ * This function should be called by the network driver during device
+ * teardown to destroy rfkill structure. Note that rfkill_free() should
+ * _not_ be called after rfkill_unregister().
+ */
+void rfkill_unregister(struct rfkill *rfkill)
+{
+	device_del(&rfkill->dev);
+	rfkill_remove_switch(rfkill);
+	put_device(&rfkill->dev);
+}
+EXPORT_SYMBOL(rfkill_unregister);
+
+/*
+ * Rfkill module initialization/deinitialization.
+ */
+static int __init rfkill_init(void)
+{
+	int error;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
+		rfkill_states[i] = RFKILL_STATE_ON;
+
+	error = class_register(&rfkill_class);
+	if (error) {
+		printk(KERN_ERR "rfkill: unable to register rfkill class\n");
+		return error;
+	}
+
+	return 0;
+}
+
+static void __exit rfkill_exit(void)
+{
+	class_unregister(&rfkill_class);
+}
+
+module_init(rfkill_init);
+module_exit(rfkill_exit);
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index f92d531..d476c43 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -812,26 +812,26 @@ rose_try_next_neigh:
 	 * closed.
 	 */
 	if (sk->sk_state == TCP_SYN_SENT) {
-		struct task_struct *tsk = current;
-		DECLARE_WAITQUEUE(wait, tsk);
+		DEFINE_WAIT(wait);
 
-		add_wait_queue(sk->sk_sleep, &wait);
 		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
+			prepare_to_wait(sk->sk_sleep, &wait,
+			                TASK_INTERRUPTIBLE);
 			if (sk->sk_state != TCP_SYN_SENT)
 				break;
-			release_sock(sk);
-			if (!signal_pending(tsk)) {
+			if (!signal_pending(current)) {
+				release_sock(sk);
 				schedule();
 				lock_sock(sk);
 				continue;
 			}
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -ERESTARTSYS;
+			err = -ERESTARTSYS;
+			break;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
+		finish_wait(sk->sk_sleep, &wait);
+
+		if (err)
+			goto out_release;
 	}
 
 	if (sk->sk_state != TCP_ESTABLISHED) {
@@ -856,10 +856,9 @@ out_release:
 
 static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
 	struct sock *newsk;
+	DEFINE_WAIT(wait);
 	struct sock *sk;
 	int err = 0;
 
@@ -869,42 +868,41 @@ static int rose_accept(struct socket *so
 	lock_sock(sk);
 	if (sk->sk_type != SOCK_SEQPACKET) {
 		err = -EOPNOTSUPP;
-		goto out;
+		goto out_release;
 	}
 
 	if (sk->sk_state != TCP_LISTEN) {
 		err = -EINVAL;
-		goto out;
+		goto out_release;
 	}
 
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	add_wait_queue(sk->sk_sleep, &wait);
 	for (;;) {
+		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+
 		skb = skb_dequeue(&sk->sk_receive_queue);
 		if (skb)
 			break;
 
-		current->state = TASK_INTERRUPTIBLE;
-		release_sock(sk);
 		if (flags & O_NONBLOCK) {
-			current->state = TASK_RUNNING;
-			remove_wait_queue(sk->sk_sleep, &wait);
-			return -EWOULDBLOCK;
+			err = -EWOULDBLOCK;
+			break;
 		}
-		if (!signal_pending(tsk)) {
+		if (!signal_pending(current)) {
+			release_sock(sk);
 			schedule();
 			lock_sock(sk);
 			continue;
 		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(sk->sk_sleep, &wait);
-		return -ERESTARTSYS;
+		err = -ERESTARTSYS;
+		break;
 	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(sk->sk_sleep, &wait);
+	finish_wait(sk->sk_sleep, &wait);
+	if (err)
+		goto out_release;
 
 	newsk = skb->sk;
 	newsk->sk_socket = newsock;
@@ -916,7 +914,7 @@ static int rose_accept(struct socket *so
 	sk->sk_ack_backlog--;
 	newsock->sk = newsk;
 
-out:
+out_release:
 	release_sock(sk);
 
 	return err;
@@ -1105,9 +1103,10 @@ static int rose_sendmsg(struct kiocb *io
 	 */
 	SOCK_DEBUG(sk, "ROSE: Appending user data\n");
 
-	asmptr = skb->h.raw = skb_put(skb, len);
+	skb_reset_transport_header(skb);
+	skb_put(skb, len);
 
-	err = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
 		kfree_skb(skb);
 		return err;
@@ -1155,7 +1154,7 @@ #define ROSE_PACLEN (256-ROSE_MIN_LEN)
 		int lg;
 
 		/* Save a copy of the Header */
-		memcpy(header, skb->data, ROSE_MIN_LEN);
+		skb_copy_from_linear_data(skb, header, ROSE_MIN_LEN);
 		skb_pull(skb, ROSE_MIN_LEN);
 
 		frontlen = skb_headroom(skb);
@@ -1175,12 +1174,12 @@ #define ROSE_PACLEN (256-ROSE_MIN_LEN)
 			lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
 
 			/* Copy the user data */
-			memcpy(skb_put(skbn, lg), skb->data, lg);
+			skb_copy_from_linear_data(skb, skb_put(skbn, lg), lg);
 			skb_pull(skb, lg);
 
 			/* Duplicate the Header */
 			skb_push(skbn, ROSE_MIN_LEN);
-			memcpy(skbn->data, header, ROSE_MIN_LEN);
+			skb_copy_to_linear_data(skbn, header, ROSE_MIN_LEN);
 
 			if (skb->len > 0)
 				skbn->data[2] |= M_BIT;
@@ -1234,7 +1233,7 @@ static int rose_recvmsg(struct kiocb *io
 		*asmptr = qbit;
 	}
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	copied     = skb->len;
 
 	if (copied > size) {
@@ -1296,6 +1295,9 @@ static int rose_ioctl(struct socket *soc
 	case SIOCGSTAMP:
 		return sock_get_timestamp(sk, (struct timeval __user *) argp);
 
+	case SIOCGSTAMPNS:
+		return sock_get_timestampns(sk, (struct timespec __user *) argp);
+
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
index 3e41bd9..cd01642 100644
--- a/net/rose/rose_loopback.c
+++ b/net/rose/rose_loopback.c
@@ -77,7 +77,7 @@ static void rose_loopback_timer(unsigned
 		dest      = (rose_address *)(skb->data + 4);
 		lci_o     = 0xFFF - lci_i;
 
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 
 		sk = rose_find_socket(lci_o, &rose_loopback_neigh);
 		if (sk) {
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index a1233e1..929a784 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -596,7 +596,7 @@ struct net_device *rose_dev_first(void)
 	struct net_device *dev, *first = NULL;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 				first = dev;
@@ -614,12 +614,13 @@ struct net_device *rose_dev_get(rose_add
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
 			dev_hold(dev);
 			goto out;
 		}
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev;
@@ -630,10 +631,11 @@ static int rose_dev_exists(rose_address 
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
 			goto out;
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev != NULL;
@@ -906,7 +908,7 @@ #endif
 			}
 		}
 		else {
-			skb->h.raw = skb->data;
+			skb_reset_transport_header(skb);
 			res = rose_process_rx_frame(sk, skb);
 			goto out;
 		}
diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig
new file mode 100644
index 0000000..91b3d52
--- /dev/null
+++ b/net/rxrpc/Kconfig
@@ -0,0 +1,43 @@
+#
+# RxRPC session sockets
+#
+
+config AF_RXRPC
+	tristate "RxRPC session sockets"
+	depends on EXPERIMENTAL
+	select KEYS
+	help
+	  Say Y or M here to include support for RxRPC session sockets (just
+	  the transport part, not the presentation part: (un)marshalling is
+	  left to the application).
+
+	  These are used for AFS kernel filesystem and userspace utilities.
+
+	  This module at the moment only supports client operations and is
+	  currently incomplete.
+
+	  See Documentation/networking/rxrpc.txt.
+
+
+config AF_RXRPC_DEBUG
+	bool "RxRPC dynamic debugging"
+	depends on AF_RXRPC
+	help
+	  Say Y here to make runtime controllable debugging messages appear.
+
+	  See Documentation/networking/rxrpc.txt.
+
+
+config RXKAD
+	tristate "RxRPC Kerberos security"
+	depends on AF_RXRPC
+	select CRYPTO
+	select CRYPTO_MANAGER
+	select CRYPTO_BLKCIPHER
+	select CRYPTO_PCBC
+	select CRYPTO_FCRYPT
+	help
+	  Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC
+	  through the use of the key retention service.
+
+	  See Documentation/networking/rxrpc.txt.
diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile
index 6efcb6f..c46867c 100644
--- a/net/rxrpc/Makefile
+++ b/net/rxrpc/Makefile
@@ -1,25 +1,29 @@
 #
-# Makefile for Linux kernel Rx RPC
+# Makefile for Linux kernel RxRPC
 #
 
-#CFLAGS += -finstrument-functions
-
-rxrpc-objs := \
-	call.o \
-	connection.o \
-	krxiod.o \
-	krxsecd.o \
-	krxtimod.o \
-	main.o \
-	peer.o \
-	rxrpc_syms.o \
-	transport.o
+af-rxrpc-objs := \
+	af_rxrpc.o \
+	ar-accept.o \
+	ar-ack.o \
+	ar-call.o \
+	ar-connection.o \
+	ar-connevent.o \
+	ar-error.o \
+	ar-input.o \
+	ar-key.o \
+	ar-local.o \
+	ar-output.o \
+	ar-peer.o \
+	ar-recvmsg.o \
+	ar-security.o \
+	ar-skbuff.o \
+	ar-transport.o
 
 ifeq ($(CONFIG_PROC_FS),y)
-rxrpc-objs += proc.o
-endif
-ifeq ($(CONFIG_SYSCTL),y)
-rxrpc-objs += sysctl.o
+af-rxrpc-objs += ar-proc.o
 endif
 
-obj-$(CONFIG_RXRPC) := rxrpc.o
+obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
+
+obj-$(CONFIG_RXKAD) += rxkad.o
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
new file mode 100644
index 0000000..2c57df9
--- /dev/null
+++ b/net/rxrpc/af_rxrpc.c
@@ -0,0 +1,879 @@
+/* AF_RXRPC implementation
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+MODULE_DESCRIPTION("RxRPC network protocol");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_RXRPC);
+
+unsigned rxrpc_debug; // = RXRPC_DEBUG_KPROTO;
+module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(rxrpc_debug, "RxRPC debugging mask");
+
+static int sysctl_rxrpc_max_qlen __read_mostly = 10;
+
+static struct proto rxrpc_proto;
+static const struct proto_ops rxrpc_rpc_ops;
+
+/* local epoch for detecting local-end reset */
+__be32 rxrpc_epoch;
+
+/* current debugging ID */
+atomic_t rxrpc_debug_id;
+
+/* count of skbs currently in use */
+atomic_t rxrpc_n_skbs;
+
+struct workqueue_struct *rxrpc_workqueue;
+
+static void rxrpc_sock_destructor(struct sock *);
+
+/*
+ * see if an RxRPC socket is currently writable
+ */
+static inline int rxrpc_writable(struct sock *sk)
+{
+	return atomic_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;
+}
+
+/*
+ * wait for write bufferage to become available
+ */
+static void rxrpc_write_space(struct sock *sk)
+{
+	_enter("%p", sk);
+	read_lock(&sk->sk_callback_lock);
+	if (rxrpc_writable(sk)) {
+		if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+			wake_up_interruptible(sk->sk_sleep);
+		sk_wake_async(sk, 2, POLL_OUT);
+	}
+	read_unlock(&sk->sk_callback_lock);
+}
+
+/*
+ * validate an RxRPC address
+ */
+static int rxrpc_validate_address(struct rxrpc_sock *rx,
+				  struct sockaddr_rxrpc *srx,
+				  int len)
+{
+	if (len < sizeof(struct sockaddr_rxrpc))
+		return -EINVAL;
+
+	if (srx->srx_family != AF_RXRPC)
+		return -EAFNOSUPPORT;
+
+	if (srx->transport_type != SOCK_DGRAM)
+		return -ESOCKTNOSUPPORT;
+
+	len -= offsetof(struct sockaddr_rxrpc, transport);
+	if (srx->transport_len < sizeof(sa_family_t) ||
+	    srx->transport_len > len)
+		return -EINVAL;
+
+	if (srx->transport.family != rx->proto)
+		return -EAFNOSUPPORT;
+
+	switch (srx->transport.family) {
+	case AF_INET:
+		_debug("INET: %x @ %u.%u.%u.%u",
+		       ntohs(srx->transport.sin.sin_port),
+		       NIPQUAD(srx->transport.sin.sin_addr));
+		if (srx->transport_len > 8)
+			memset((void *)&srx->transport + 8, 0,
+			       srx->transport_len - 8);
+		break;
+
+	case AF_INET6:
+	default:
+		return -EAFNOSUPPORT;
+	}
+
+	return 0;
+}
+
+/*
+ * bind a local address to an RxRPC socket
+ */
+static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
+{
+	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) saddr;
+	struct sock *sk = sock->sk;
+	struct rxrpc_local *local;
+	struct rxrpc_sock *rx = rxrpc_sk(sk), *prx;
+	__be16 service_id;
+	int ret;
+
+	_enter("%p,%p,%d", rx, saddr, len);
+
+	ret = rxrpc_validate_address(rx, srx, len);
+	if (ret < 0)
+		goto error;
+
+	lock_sock(&rx->sk);
+
+	if (rx->sk.sk_state != RXRPC_UNCONNECTED) {
+		ret = -EINVAL;
+		goto error_unlock;
+	}
+
+	memcpy(&rx->srx, srx, sizeof(rx->srx));
+
+	/* find a local transport endpoint if we don't have one already */
+	local = rxrpc_lookup_local(&rx->srx);
+	if (IS_ERR(local)) {
+		ret = PTR_ERR(local);
+		goto error_unlock;
+	}
+
+	rx->local = local;
+	if (srx->srx_service) {
+		service_id = htons(srx->srx_service);
+		write_lock_bh(&local->services_lock);
+		list_for_each_entry(prx, &local->services, listen_link) {
+			if (prx->service_id == service_id)
+				goto service_in_use;
+		}
+
+		rx->service_id = service_id;
+		list_add_tail(&rx->listen_link, &local->services);
+		write_unlock_bh(&local->services_lock);
+
+		rx->sk.sk_state = RXRPC_SERVER_BOUND;
+	} else {
+		rx->sk.sk_state = RXRPC_CLIENT_BOUND;
+	}
+
+	release_sock(&rx->sk);
+	_leave(" = 0");
+	return 0;
+
+service_in_use:
+	ret = -EADDRINUSE;
+	write_unlock_bh(&local->services_lock);
+error_unlock:
+	release_sock(&rx->sk);
+error:
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * set the number of pending calls permitted on a listening socket
+ */
+static int rxrpc_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	struct rxrpc_sock *rx = rxrpc_sk(sk);
+	int ret;
+
+	_enter("%p,%d", rx, backlog);
+
+	lock_sock(&rx->sk);
+
+	switch (rx->sk.sk_state) {
+	case RXRPC_UNCONNECTED:
+		ret = -EADDRNOTAVAIL;
+		break;
+	case RXRPC_CLIENT_BOUND:
+	case RXRPC_CLIENT_CONNECTED:
+	default:
+		ret = -EBUSY;
+		break;
+	case RXRPC_SERVER_BOUND:
+		ASSERT(rx->local != NULL);
+		sk->sk_max_ack_backlog = backlog;
+		rx->sk.sk_state = RXRPC_SERVER_LISTENING;
+		ret = 0;
+		break;
+	}
+
+	release_sock(&rx->sk);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * find a transport by address
+ */
+static struct rxrpc_transport *rxrpc_name_to_transport(struct socket *sock,
+						       struct sockaddr *addr,
+						       int addr_len, int flags,
+						       gfp_t gfp)
+{
+	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;
+	struct rxrpc_transport *trans;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	struct rxrpc_peer *peer;
+
+	_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);
+
+	ASSERT(rx->local != NULL);
+	ASSERT(rx->sk.sk_state > RXRPC_UNCONNECTED);
+
+	if (rx->srx.transport_type != srx->transport_type)
+		return ERR_PTR(-ESOCKTNOSUPPORT);
+	if (rx->srx.transport.family != srx->transport.family)
+		return ERR_PTR(-EAFNOSUPPORT);
+
+	/* find a remote transport endpoint from the local one */
+	peer = rxrpc_get_peer(srx, gfp);
+	if (IS_ERR(peer))
+		return ERR_PTR(PTR_ERR(peer));
+
+	/* find a transport */
+	trans = rxrpc_get_transport(rx->local, peer, gfp);
+	rxrpc_put_peer(peer);
+	_leave(" = %p", trans);
+	return trans;
+}
+
+/**
+ * rxrpc_kernel_begin_call - Allow a kernel service to begin a call
+ * @sock: The socket on which to make the call
+ * @srx: The address of the peer to contact (defaults to socket setting)
+ * @key: The security context to use (defaults to socket setting)
+ * @user_call_ID: The ID to use
+ *
+ * Allow a kernel service to begin a call on the nominated socket.  This just
+ * sets up all the internal tracking structures and allocates connection and
+ * call IDs as appropriate.  The call to be used is returned.
+ *
+ * The default socket destination address and security may be overridden by
+ * supplying @srx and @key.
+ */
+struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
+					   struct sockaddr_rxrpc *srx,
+					   struct key *key,
+					   unsigned long user_call_ID,
+					   gfp_t gfp)
+{
+	struct rxrpc_conn_bundle *bundle;
+	struct rxrpc_transport *trans;
+	struct rxrpc_call *call;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	__be16 service_id;
+
+	_enter(",,%x,%lx", key_serial(key), user_call_ID);
+
+	lock_sock(&rx->sk);
+
+	if (srx) {
+		trans = rxrpc_name_to_transport(sock, (struct sockaddr *) srx,
+						sizeof(*srx), 0, gfp);
+		if (IS_ERR(trans)) {
+			call = ERR_PTR(PTR_ERR(trans));
+			trans = NULL;
+			goto out;
+		}
+	} else {
+		trans = rx->trans;
+		if (!trans) {
+			call = ERR_PTR(-ENOTCONN);
+			goto out;
+		}
+		atomic_inc(&trans->usage);
+	}
+
+	service_id = rx->service_id;
+	if (srx)
+		service_id = htons(srx->srx_service);
+
+	if (!key)
+		key = rx->key;
+	if (key && !key->payload.data)
+		key = NULL; /* a no-security key */
+
+	bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
+	if (IS_ERR(bundle)) {
+		call = ERR_PTR(PTR_ERR(bundle));
+		goto out;
+	}
+
+	call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID, true,
+				     gfp);
+	rxrpc_put_bundle(trans, bundle);
+out:
+	rxrpc_put_transport(trans);
+	release_sock(&rx->sk);
+	_leave(" = %p", call);
+	return call;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_begin_call);
+
+/**
+ * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
+ * @call: The call to end
+ *
+ * Allow a kernel service to end a call it was using.  The call must be
+ * complete before this is called (the call should be aborted if necessary).
+ */
+void rxrpc_kernel_end_call(struct rxrpc_call *call)
+{
+	_enter("%d{%d}", call->debug_id, atomic_read(&call->usage));
+	rxrpc_remove_user_ID(call->socket, call);
+	rxrpc_put_call(call);
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_end_call);
+
+/**
+ * rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages
+ * @sock: The socket to intercept received messages on
+ * @interceptor: The function to pass the messages to
+ *
+ * Allow a kernel service to intercept messages heading for the Rx queue on an
+ * RxRPC socket.  They get passed to the specified function instead.
+ * @interceptor should free the socket buffers it is given.  @interceptor is
+ * called with the socket receive queue spinlock held and softirqs disabled -
+ * this ensures that the messages will be delivered in the right order.
+ */
+void rxrpc_kernel_intercept_rx_messages(struct socket *sock,
+					rxrpc_interceptor_t interceptor)
+{
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+
+	_enter("");
+	rx->interceptor = interceptor;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages);
+
+/*
+ * connect an RxRPC socket
+ * - this just targets it at a specific destination; no actual connection
+ *   negotiation takes place
+ */
+static int rxrpc_connect(struct socket *sock, struct sockaddr *addr,
+			 int addr_len, int flags)
+{
+	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) addr;
+	struct sock *sk = sock->sk;
+	struct rxrpc_transport *trans;
+	struct rxrpc_local *local;
+	struct rxrpc_sock *rx = rxrpc_sk(sk);
+	int ret;
+
+	_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);
+
+	ret = rxrpc_validate_address(rx, srx, addr_len);
+	if (ret < 0) {
+		_leave(" = %d [bad addr]", ret);
+		return ret;
+	}
+
+	lock_sock(&rx->sk);
+
+	switch (rx->sk.sk_state) {
+	case RXRPC_UNCONNECTED:
+		/* find a local transport endpoint if we don't have one already */
+		ASSERTCMP(rx->local, ==, NULL);
+		rx->srx.srx_family = AF_RXRPC;
+		rx->srx.srx_service = 0;
+		rx->srx.transport_type = srx->transport_type;
+		rx->srx.transport_len = sizeof(sa_family_t);
+		rx->srx.transport.family = srx->transport.family;
+		local = rxrpc_lookup_local(&rx->srx);
+		if (IS_ERR(local)) {
+			release_sock(&rx->sk);
+			return PTR_ERR(local);
+		}
+		rx->local = local;
+		rx->sk.sk_state = RXRPC_CLIENT_BOUND;
+	case RXRPC_CLIENT_BOUND:
+		break;
+	case RXRPC_CLIENT_CONNECTED:
+		release_sock(&rx->sk);
+		return -EISCONN;
+	default:
+		release_sock(&rx->sk);
+		return -EBUSY; /* server sockets can't connect as well */
+	}
+
+	trans = rxrpc_name_to_transport(sock, addr, addr_len, flags,
+					GFP_KERNEL);
+	if (IS_ERR(trans)) {
+		release_sock(&rx->sk);
+		_leave(" = %ld", PTR_ERR(trans));
+		return PTR_ERR(trans);
+	}
+
+	rx->trans = trans;
+	rx->service_id = htons(srx->srx_service);
+	rx->sk.sk_state = RXRPC_CLIENT_CONNECTED;
+
+	release_sock(&rx->sk);
+	return 0;
+}
+
+/*
+ * send a message through an RxRPC socket
+ * - in a client this does a number of things:
+ *   - finds/sets up a connection for the security specified (if any)
+ *   - initiates a call (ID in control data)
+ *   - ends the request phase of a call (if MSG_MORE is not set)
+ *   - sends a call data packet
+ *   - may send an abort (abort code in control data)
+ */
+static int rxrpc_sendmsg(struct kiocb *iocb, struct socket *sock,
+			 struct msghdr *m, size_t len)
+{
+	struct rxrpc_transport *trans;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	int ret;
+
+	_enter(",{%d},,%zu", rx->sk.sk_state, len);
+
+	if (m->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (m->msg_name) {
+		ret = rxrpc_validate_address(rx, m->msg_name, m->msg_namelen);
+		if (ret < 0) {
+			_leave(" = %d [bad addr]", ret);
+			return ret;
+		}
+	}
+
+	trans = NULL;
+	lock_sock(&rx->sk);
+
+	if (m->msg_name) {
+		ret = -EISCONN;
+		trans = rxrpc_name_to_transport(sock, m->msg_name,
+						m->msg_namelen, 0, GFP_KERNEL);
+		if (IS_ERR(trans)) {
+			ret = PTR_ERR(trans);
+			trans = NULL;
+			goto out;
+		}
+	} else {
+		trans = rx->trans;
+		if (trans)
+			atomic_inc(&trans->usage);
+	}
+
+	switch (rx->sk.sk_state) {
+	case RXRPC_SERVER_LISTENING:
+		if (!m->msg_name) {
+			ret = rxrpc_server_sendmsg(iocb, rx, m, len);
+			break;
+		}
+	case RXRPC_SERVER_BOUND:
+	case RXRPC_CLIENT_BOUND:
+		if (!m->msg_name) {
+			ret = -ENOTCONN;
+			break;
+		}
+	case RXRPC_CLIENT_CONNECTED:
+		ret = rxrpc_client_sendmsg(iocb, rx, trans, m, len);
+		break;
+	default:
+		ret = -ENOTCONN;
+		break;
+	}
+
+out:
+	release_sock(&rx->sk);
+	if (trans)
+		rxrpc_put_transport(trans);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * set RxRPC socket options
+ */
+static int rxrpc_setsockopt(struct socket *sock, int level, int optname,
+			    char __user *optval, int optlen)
+{
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	unsigned min_sec_level;
+	int ret;
+
+	_enter(",%d,%d,,%d", level, optname, optlen);
+
+	lock_sock(&rx->sk);
+	ret = -EOPNOTSUPP;
+
+	if (level == SOL_RXRPC) {
+		switch (optname) {
+		case RXRPC_EXCLUSIVE_CONNECTION:
+			ret = -EINVAL;
+			if (optlen != 0)
+				goto error;
+			ret = -EISCONN;
+			if (rx->sk.sk_state != RXRPC_UNCONNECTED)
+				goto error;
+			set_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags);
+			goto success;
+
+		case RXRPC_SECURITY_KEY:
+			ret = -EINVAL;
+			if (rx->key)
+				goto error;
+			ret = -EISCONN;
+			if (rx->sk.sk_state != RXRPC_UNCONNECTED)
+				goto error;
+			ret = rxrpc_request_key(rx, optval, optlen);
+			goto error;
+
+		case RXRPC_SECURITY_KEYRING:
+			ret = -EINVAL;
+			if (rx->key)
+				goto error;
+			ret = -EISCONN;
+			if (rx->sk.sk_state != RXRPC_UNCONNECTED)
+				goto error;
+			ret = rxrpc_server_keyring(rx, optval, optlen);
+			goto error;
+
+		case RXRPC_MIN_SECURITY_LEVEL:
+			ret = -EINVAL;
+			if (optlen != sizeof(unsigned))
+				goto error;
+			ret = -EISCONN;
+			if (rx->sk.sk_state != RXRPC_UNCONNECTED)
+				goto error;
+			ret = get_user(min_sec_level,
+				       (unsigned __user *) optval);
+			if (ret < 0)
+				goto error;
+			ret = -EINVAL;
+			if (min_sec_level > RXRPC_SECURITY_MAX)
+				goto error;
+			rx->min_sec_level = min_sec_level;
+			goto success;
+
+		default:
+			break;
+		}
+	}
+
+success:
+	ret = 0;
+error:
+	release_sock(&rx->sk);
+	return ret;
+}
+
+/*
+ * permit an RxRPC socket to be polled
+ */
+static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
+			       poll_table *wait)
+{
+	unsigned int mask;
+	struct sock *sk = sock->sk;
+
+	poll_wait(file, sk->sk_sleep, wait);
+	mask = 0;
+
+	/* the socket is readable if there are any messages waiting on the Rx
+	 * queue */
+	if (!skb_queue_empty(&sk->sk_receive_queue))
+		mask |= POLLIN | POLLRDNORM;
+
+	/* the socket is writable if there is space to add new data to the
+	 * socket; there is no guarantee that any particular call in progress
+	 * on the socket may have space in the Tx ACK window */
+	if (rxrpc_writable(sk))
+		mask |= POLLOUT | POLLWRNORM;
+
+	return mask;
+}
+
+/*
+ * create an RxRPC socket
+ */
+static int rxrpc_create(struct socket *sock, int protocol)
+{
+	struct rxrpc_sock *rx;
+	struct sock *sk;
+
+	_enter("%p,%d", sock, protocol);
+
+	/* we support transport protocol UDP only */
+	if (protocol != PF_INET)
+		return -EPROTONOSUPPORT;
+
+	if (sock->type != SOCK_DGRAM)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &rxrpc_rpc_ops;
+	sock->state = SS_UNCONNECTED;
+
+	sk = sk_alloc(PF_RXRPC, GFP_KERNEL, &rxrpc_proto, 1);
+	if (!sk)
+		return -ENOMEM;
+
+	sock_init_data(sock, sk);
+	sk->sk_state		= RXRPC_UNCONNECTED;
+	sk->sk_write_space	= rxrpc_write_space;
+	sk->sk_max_ack_backlog	= sysctl_rxrpc_max_qlen;
+	sk->sk_destruct		= rxrpc_sock_destructor;
+
+	rx = rxrpc_sk(sk);
+	rx->proto = protocol;
+	rx->calls = RB_ROOT;
+
+	INIT_LIST_HEAD(&rx->listen_link);
+	INIT_LIST_HEAD(&rx->secureq);
+	INIT_LIST_HEAD(&rx->acceptq);
+	rwlock_init(&rx->call_lock);
+	memset(&rx->srx, 0, sizeof(rx->srx));
+
+	_leave(" = 0 [%p]", rx);
+	return 0;
+}
+
+/*
+ * RxRPC socket destructor
+ */
+static void rxrpc_sock_destructor(struct sock *sk)
+{
+	_enter("%p", sk);
+
+	rxrpc_purge_queue(&sk->sk_receive_queue);
+
+	BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
+	BUG_TRAP(sk_unhashed(sk));
+	BUG_TRAP(!sk->sk_socket);
+
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		printk("Attempt to release alive rxrpc socket: %p\n", sk);
+		return;
+	}
+}
+
+/*
+ * release an RxRPC socket
+ */
+static int rxrpc_release_sock(struct sock *sk)
+{
+	struct rxrpc_sock *rx = rxrpc_sk(sk);
+
+	_enter("%p{%d,%d}", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
+
+	/* declare the socket closed for business */
+	sock_orphan(sk);
+	sk->sk_shutdown = SHUTDOWN_MASK;
+
+	spin_lock_bh(&sk->sk_receive_queue.lock);
+	sk->sk_state = RXRPC_CLOSE;
+	spin_unlock_bh(&sk->sk_receive_queue.lock);
+
+	ASSERTCMP(rx->listen_link.next, !=, LIST_POISON1);
+
+	if (!list_empty(&rx->listen_link)) {
+		write_lock_bh(&rx->local->services_lock);
+		list_del(&rx->listen_link);
+		write_unlock_bh(&rx->local->services_lock);
+	}
+
+	/* try to flush out this socket */
+	rxrpc_release_calls_on_socket(rx);
+	flush_workqueue(rxrpc_workqueue);
+	rxrpc_purge_queue(&sk->sk_receive_queue);
+
+	if (rx->conn) {
+		rxrpc_put_connection(rx->conn);
+		rx->conn = NULL;
+	}
+
+	if (rx->bundle) {
+		rxrpc_put_bundle(rx->trans, rx->bundle);
+		rx->bundle = NULL;
+	}
+	if (rx->trans) {
+		rxrpc_put_transport(rx->trans);
+		rx->trans = NULL;
+	}
+	if (rx->local) {
+		rxrpc_put_local(rx->local);
+		rx->local = NULL;
+	}
+
+	key_put(rx->key);
+	rx->key = NULL;
+	key_put(rx->securities);
+	rx->securities = NULL;
+	sock_put(sk);
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * release an RxRPC BSD socket on close() or equivalent
+ */
+static int rxrpc_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	_enter("%p{%p}", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock->sk = NULL;
+
+	return rxrpc_release_sock(sk);
+}
+
+/*
+ * RxRPC network protocol
+ */
+static const struct proto_ops rxrpc_rpc_ops = {
+	.family		= PF_UNIX,
+	.owner		= THIS_MODULE,
+	.release	= rxrpc_release,
+	.bind		= rxrpc_bind,
+	.connect	= rxrpc_connect,
+	.socketpair	= sock_no_socketpair,
+	.accept		= sock_no_accept,
+	.getname	= sock_no_getname,
+	.poll		= rxrpc_poll,
+	.ioctl		= sock_no_ioctl,
+	.listen		= rxrpc_listen,
+	.shutdown	= sock_no_shutdown,
+	.setsockopt	= rxrpc_setsockopt,
+	.getsockopt	= sock_no_getsockopt,
+	.sendmsg	= rxrpc_sendmsg,
+	.recvmsg	= rxrpc_recvmsg,
+	.mmap		= sock_no_mmap,
+	.sendpage	= sock_no_sendpage,
+};
+
+static struct proto rxrpc_proto = {
+	.name		= "RXRPC",
+	.owner		= THIS_MODULE,
+	.obj_size	= sizeof(struct rxrpc_sock),
+	.max_header	= sizeof(struct rxrpc_header),
+};
+
+static struct net_proto_family rxrpc_family_ops = {
+	.family	= PF_RXRPC,
+	.create = rxrpc_create,
+	.owner	= THIS_MODULE,
+};
+
+/*
+ * initialise and register the RxRPC protocol
+ */
+static int __init af_rxrpc_init(void)
+{
+	struct sk_buff *dummy_skb;
+	int ret = -1;
+
+	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof(dummy_skb->cb));
+
+	rxrpc_epoch = htonl(xtime.tv_sec);
+
+	ret = -ENOMEM;
+	rxrpc_call_jar = kmem_cache_create(
+		"rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!rxrpc_call_jar) {
+		printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n");
+		goto error_call_jar;
+	}
+
+	rxrpc_workqueue = create_workqueue("krxrpcd");
+	if (!rxrpc_workqueue) {
+		printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
+		goto error_work_queue;
+	}
+
+	ret = proto_register(&rxrpc_proto, 1);
+        if (ret < 0) {
+                printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
+		goto error_proto;
+	}
+
+	ret = sock_register(&rxrpc_family_ops);
+	if (ret < 0) {
+                printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
+		goto error_sock;
+	}
+
+	ret = register_key_type(&key_type_rxrpc);
+	if (ret < 0) {
+                printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
+		goto error_key_type;
+	}
+
+	ret = register_key_type(&key_type_rxrpc_s);
+	if (ret < 0) {
+                printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
+		goto error_key_type_s;
+	}
+
+#ifdef CONFIG_PROC_FS
+	proc_net_fops_create("rxrpc_calls", 0, &rxrpc_call_seq_fops);
+	proc_net_fops_create("rxrpc_conns", 0, &rxrpc_connection_seq_fops);
+#endif
+	return 0;
+
+error_key_type_s:
+	unregister_key_type(&key_type_rxrpc);
+error_key_type:
+	sock_unregister(PF_RXRPC);
+error_sock:
+	proto_unregister(&rxrpc_proto);
+error_proto:
+	destroy_workqueue(rxrpc_workqueue);
+error_work_queue:
+	kmem_cache_destroy(rxrpc_call_jar);
+error_call_jar:
+	return ret;
+}
+
+/*
+ * unregister the RxRPC protocol
+ */
+static void __exit af_rxrpc_exit(void)
+{
+	_enter("");
+	unregister_key_type(&key_type_rxrpc_s);
+	unregister_key_type(&key_type_rxrpc);
+	sock_unregister(PF_RXRPC);
+	proto_unregister(&rxrpc_proto);
+	rxrpc_destroy_all_calls();
+	rxrpc_destroy_all_connections();
+	rxrpc_destroy_all_transports();
+	rxrpc_destroy_all_peers();
+	rxrpc_destroy_all_locals();
+
+	ASSERTCMP(atomic_read(&rxrpc_n_skbs), ==, 0);
+
+	_debug("flush scheduled work");
+	flush_workqueue(rxrpc_workqueue);
+	proc_net_remove("rxrpc_conns");
+	proc_net_remove("rxrpc_calls");
+	destroy_workqueue(rxrpc_workqueue);
+	kmem_cache_destroy(rxrpc_call_jar);
+	_leave("");
+}
+
+module_init(af_rxrpc_init);
+module_exit(af_rxrpc_exit);
diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c
new file mode 100644
index 0000000..92a87fd
--- /dev/null
+++ b/net/rxrpc/ar-accept.c
@@ -0,0 +1,504 @@
+/* incoming call handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/errqueue.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <net/ip.h>
+#include "ar-internal.h"
+
+/*
+ * generate a connection-level abort
+ */
+static int rxrpc_busy(struct rxrpc_local *local, struct sockaddr_rxrpc *srx,
+		      struct rxrpc_header *hdr)
+{
+	struct msghdr msg;
+	struct kvec iov[1];
+	size_t len;
+	int ret;
+
+	_enter("%d,,", local->debug_id);
+
+	msg.msg_name	= &srx->transport.sin;
+	msg.msg_namelen	= sizeof(srx->transport.sin);
+	msg.msg_control	= NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags	= 0;
+
+	hdr->seq	= 0;
+	hdr->type	= RXRPC_PACKET_TYPE_BUSY;
+	hdr->flags	= 0;
+	hdr->userStatus	= 0;
+	hdr->_rsvd	= 0;
+
+	iov[0].iov_base	= hdr;
+	iov[0].iov_len	= sizeof(*hdr);
+
+	len = iov[0].iov_len;
+
+	hdr->serial = htonl(1);
+	_proto("Tx BUSY %%%u", ntohl(hdr->serial));
+
+	ret = kernel_sendmsg(local->socket, &msg, iov, 1, len);
+	if (ret < 0) {
+		_leave(" = -EAGAIN [sendmsg failed: %d]", ret);
+		return -EAGAIN;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * accept an incoming call that needs peer, transport and/or connection setting
+ * up
+ */
+static int rxrpc_accept_incoming_call(struct rxrpc_local *local,
+				      struct rxrpc_sock *rx,
+				      struct sk_buff *skb,
+				      struct sockaddr_rxrpc *srx)
+{
+	struct rxrpc_connection *conn;
+	struct rxrpc_transport *trans;
+	struct rxrpc_skb_priv *sp, *nsp;
+	struct rxrpc_peer *peer;
+	struct rxrpc_call *call;
+	struct sk_buff *notification;
+	int ret;
+
+	_enter("");
+
+	sp = rxrpc_skb(skb);
+
+	/* get a notification message to send to the server app */
+	notification = alloc_skb(0, GFP_NOFS);
+	rxrpc_new_skb(notification);
+	notification->mark = RXRPC_SKB_MARK_NEW_CALL;
+
+	peer = rxrpc_get_peer(srx, GFP_NOIO);
+	if (IS_ERR(peer)) {
+		_debug("no peer");
+		ret = -EBUSY;
+		goto error;
+	}
+
+	trans = rxrpc_get_transport(local, peer, GFP_NOIO);
+	rxrpc_put_peer(peer);
+	if (!trans) {
+		_debug("no trans");
+		ret = -EBUSY;
+		goto error;
+	}
+
+	conn = rxrpc_incoming_connection(trans, &sp->hdr, GFP_NOIO);
+	rxrpc_put_transport(trans);
+	if (IS_ERR(conn)) {
+		_debug("no conn");
+		ret = PTR_ERR(conn);
+		goto error;
+	}
+
+	call = rxrpc_incoming_call(rx, conn, &sp->hdr, GFP_NOIO);
+	rxrpc_put_connection(conn);
+	if (IS_ERR(call)) {
+		_debug("no call");
+		ret = PTR_ERR(call);
+		goto error;
+	}
+
+	/* attach the call to the socket */
+	read_lock_bh(&local->services_lock);
+	if (rx->sk.sk_state == RXRPC_CLOSE)
+		goto invalid_service;
+
+	write_lock(&rx->call_lock);
+	if (!test_and_set_bit(RXRPC_CALL_INIT_ACCEPT, &call->flags)) {
+		rxrpc_get_call(call);
+
+		spin_lock(&call->conn->state_lock);
+		if (sp->hdr.securityIndex > 0 &&
+		    call->conn->state == RXRPC_CONN_SERVER_UNSECURED) {
+			_debug("await conn sec");
+			list_add_tail(&call->accept_link, &rx->secureq);
+			call->conn->state = RXRPC_CONN_SERVER_CHALLENGING;
+			atomic_inc(&call->conn->usage);
+			set_bit(RXRPC_CONN_CHALLENGE, &call->conn->events);
+			rxrpc_queue_conn(call->conn);
+		} else {
+			_debug("conn ready");
+			call->state = RXRPC_CALL_SERVER_ACCEPTING;
+			list_add_tail(&call->accept_link, &rx->acceptq);
+			rxrpc_get_call(call);
+			nsp = rxrpc_skb(notification);
+			nsp->call = call;
+
+			ASSERTCMP(atomic_read(&call->usage), >=, 3);
+
+			_debug("notify");
+			spin_lock(&call->lock);
+			ret = rxrpc_queue_rcv_skb(call, notification, true,
+						  false);
+			spin_unlock(&call->lock);
+			notification = NULL;
+			if (ret < 0)
+				BUG();
+		}
+		spin_unlock(&call->conn->state_lock);
+
+		_debug("queued");
+	}
+	write_unlock(&rx->call_lock);
+
+	_debug("process");
+	rxrpc_fast_process_packet(call, skb);
+
+	_debug("done");
+	read_unlock_bh(&local->services_lock);
+	rxrpc_free_skb(notification);
+	rxrpc_put_call(call);
+	_leave(" = 0");
+	return 0;
+
+invalid_service:
+	_debug("invalid");
+	read_unlock_bh(&local->services_lock);
+
+	read_lock_bh(&call->state_lock);
+	if (!test_bit(RXRPC_CALL_RELEASE, &call->flags) &&
+	    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) {
+		rxrpc_get_call(call);
+		rxrpc_queue_call(call);
+	}
+	read_unlock_bh(&call->state_lock);
+	rxrpc_put_call(call);
+	ret = -ECONNREFUSED;
+error:
+	rxrpc_free_skb(notification);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * accept incoming calls that need peer, transport and/or connection setting up
+ * - the packets we get are all incoming client DATA packets that have seq == 1
+ */
+void rxrpc_accept_incoming_calls(struct work_struct *work)
+{
+	struct rxrpc_local *local =
+		container_of(work, struct rxrpc_local, acceptor);
+	struct rxrpc_skb_priv *sp;
+	struct sockaddr_rxrpc srx;
+	struct rxrpc_sock *rx;
+	struct sk_buff *skb;
+	__be16 service_id;
+	int ret;
+
+	_enter("%d", local->debug_id);
+
+	read_lock_bh(&rxrpc_local_lock);
+	if (atomic_read(&local->usage) > 0)
+		rxrpc_get_local(local);
+	else
+		local = NULL;
+	read_unlock_bh(&rxrpc_local_lock);
+	if (!local) {
+		_leave(" [local dead]");
+		return;
+	}
+
+process_next_packet:
+	skb = skb_dequeue(&local->accept_queue);
+	if (!skb) {
+		rxrpc_put_local(local);
+		_leave("\n");
+		return;
+	}
+
+	_net("incoming call skb %p", skb);
+
+	sp = rxrpc_skb(skb);
+
+	/* determine the remote address */
+	memset(&srx, 0, sizeof(srx));
+	srx.srx_family = AF_RXRPC;
+	srx.transport.family = local->srx.transport.family;
+	srx.transport_type = local->srx.transport_type;
+	switch (srx.transport.family) {
+	case AF_INET:
+		srx.transport_len = sizeof(struct sockaddr_in);
+		srx.transport.sin.sin_port = udp_hdr(skb)->source;
+		srx.transport.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
+		break;
+	default:
+		goto busy;
+	}
+
+	/* get the socket providing the service */
+	service_id = sp->hdr.serviceId;
+	read_lock_bh(&local->services_lock);
+	list_for_each_entry(rx, &local->services, listen_link) {
+		if (rx->service_id == service_id &&
+		    rx->sk.sk_state != RXRPC_CLOSE)
+			goto found_service;
+	}
+	read_unlock_bh(&local->services_lock);
+	goto invalid_service;
+
+found_service:
+	_debug("found service %hd", ntohs(rx->service_id));
+	if (sk_acceptq_is_full(&rx->sk))
+		goto backlog_full;
+	sk_acceptq_added(&rx->sk);
+	sock_hold(&rx->sk);
+	read_unlock_bh(&local->services_lock);
+
+	ret = rxrpc_accept_incoming_call(local, rx, skb, &srx);
+	if (ret < 0)
+		sk_acceptq_removed(&rx->sk);
+	sock_put(&rx->sk);
+	switch (ret) {
+	case -ECONNRESET: /* old calls are ignored */
+	case -ECONNABORTED: /* aborted calls are reaborted or ignored */
+	case 0:
+		goto process_next_packet;
+	case -ECONNREFUSED:
+		goto invalid_service;
+	case -EBUSY:
+		goto busy;
+	case -EKEYREJECTED:
+		goto security_mismatch;
+	default:
+		BUG();
+	}
+
+backlog_full:
+	read_unlock_bh(&local->services_lock);
+busy:
+	rxrpc_busy(local, &srx, &sp->hdr);
+	rxrpc_free_skb(skb);
+	goto process_next_packet;
+
+invalid_service:
+	skb->priority = RX_INVALID_OPERATION;
+	rxrpc_reject_packet(local, skb);
+	goto process_next_packet;
+
+	/* can't change connection security type mid-flow */
+security_mismatch:
+	skb->priority = RX_PROTOCOL_ERROR;
+	rxrpc_reject_packet(local, skb);
+	goto process_next_packet;
+}
+
+/*
+ * handle acceptance of a call by userspace
+ * - assign the user call ID to the call at the front of the queue
+ */
+struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
+				     unsigned long user_call_ID)
+{
+	struct rxrpc_call *call;
+	struct rb_node *parent, **pp;
+	int ret;
+
+	_enter(",%lx", user_call_ID);
+
+	ASSERT(!irqs_disabled());
+
+	write_lock(&rx->call_lock);
+
+	ret = -ENODATA;
+	if (list_empty(&rx->acceptq))
+		goto out;
+
+	/* check the user ID isn't already in use */
+	ret = -EBADSLT;
+	pp = &rx->calls.rb_node;
+	parent = NULL;
+	while (*pp) {
+		parent = *pp;
+		call = rb_entry(parent, struct rxrpc_call, sock_node);
+
+		if (user_call_ID < call->user_call_ID)
+			pp = &(*pp)->rb_left;
+		else if (user_call_ID > call->user_call_ID)
+			pp = &(*pp)->rb_right;
+		else
+			goto out;
+	}
+
+	/* dequeue the first call and check it's still valid */
+	call = list_entry(rx->acceptq.next, struct rxrpc_call, accept_link);
+	list_del_init(&call->accept_link);
+	sk_acceptq_removed(&rx->sk);
+
+	write_lock_bh(&call->state_lock);
+	switch (call->state) {
+	case RXRPC_CALL_SERVER_ACCEPTING:
+		call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
+		break;
+	case RXRPC_CALL_REMOTELY_ABORTED:
+	case RXRPC_CALL_LOCALLY_ABORTED:
+		ret = -ECONNABORTED;
+		goto out_release;
+	case RXRPC_CALL_NETWORK_ERROR:
+		ret = call->conn->error;
+		goto out_release;
+	case RXRPC_CALL_DEAD:
+		ret = -ETIME;
+		goto out_discard;
+	default:
+		BUG();
+	}
+
+	/* formalise the acceptance */
+	call->user_call_ID = user_call_ID;
+	rb_link_node(&call->sock_node, parent, pp);
+	rb_insert_color(&call->sock_node, &rx->calls);
+	if (test_and_set_bit(RXRPC_CALL_HAS_USERID, &call->flags))
+		BUG();
+	if (test_and_set_bit(RXRPC_CALL_ACCEPTED, &call->events))
+		BUG();
+	rxrpc_queue_call(call);
+
+	rxrpc_get_call(call);
+	write_unlock_bh(&call->state_lock);
+	write_unlock(&rx->call_lock);
+	_leave(" = %p{%d}", call, call->debug_id);
+	return call;
+
+	/* if the call is already dying or dead, then we leave the socket's ref
+	 * on it to be released by rxrpc_dead_call_expired() as induced by
+	 * rxrpc_release_call() */
+out_release:
+	_debug("release %p", call);
+	if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+	    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+		rxrpc_queue_call(call);
+out_discard:
+	write_unlock_bh(&call->state_lock);
+	_debug("discard %p", call);
+out:
+	write_unlock(&rx->call_lock);
+	_leave(" = %d", ret);
+	return ERR_PTR(ret);
+}
+
+/*
+ * handle rejectance of a call by userspace
+ * - reject the call at the front of the queue
+ */
+int rxrpc_reject_call(struct rxrpc_sock *rx)
+{
+	struct rxrpc_call *call;
+	int ret;
+
+	_enter("");
+
+	ASSERT(!irqs_disabled());
+
+	write_lock(&rx->call_lock);
+
+	ret = -ENODATA;
+	if (list_empty(&rx->acceptq))
+		goto out;
+
+	/* dequeue the first call and check it's still valid */
+	call = list_entry(rx->acceptq.next, struct rxrpc_call, accept_link);
+	list_del_init(&call->accept_link);
+	sk_acceptq_removed(&rx->sk);
+
+	write_lock_bh(&call->state_lock);
+	switch (call->state) {
+	case RXRPC_CALL_SERVER_ACCEPTING:
+		call->state = RXRPC_CALL_SERVER_BUSY;
+		if (test_and_set_bit(RXRPC_CALL_REJECT_BUSY, &call->events))
+			rxrpc_queue_call(call);
+		ret = 0;
+		goto out_release;
+	case RXRPC_CALL_REMOTELY_ABORTED:
+	case RXRPC_CALL_LOCALLY_ABORTED:
+		ret = -ECONNABORTED;
+		goto out_release;
+	case RXRPC_CALL_NETWORK_ERROR:
+		ret = call->conn->error;
+		goto out_release;
+	case RXRPC_CALL_DEAD:
+		ret = -ETIME;
+		goto out_discard;
+	default:
+		BUG();
+	}
+
+	/* if the call is already dying or dead, then we leave the socket's ref
+	 * on it to be released by rxrpc_dead_call_expired() as induced by
+	 * rxrpc_release_call() */
+out_release:
+	_debug("release %p", call);
+	if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+	    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+		rxrpc_queue_call(call);
+out_discard:
+	write_unlock_bh(&call->state_lock);
+	_debug("discard %p", call);
+out:
+	write_unlock(&rx->call_lock);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/**
+ * rxrpc_kernel_accept_call - Allow a kernel service to accept an incoming call
+ * @sock: The socket on which the impending call is waiting
+ * @user_call_ID: The tag to attach to the call
+ *
+ * Allow a kernel service to accept an incoming call, assuming the incoming
+ * call is still valid.
+ */
+struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *sock,
+					    unsigned long user_call_ID)
+{
+	struct rxrpc_call *call;
+
+	_enter(",%lx", user_call_ID);
+	call = rxrpc_accept_call(rxrpc_sk(sock->sk), user_call_ID);
+	_leave(" = %p", call);
+	return call;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_accept_call);
+
+/**
+ * rxrpc_kernel_reject_call - Allow a kernel service to reject an incoming call
+ * @sock: The socket on which the impending call is waiting
+ *
+ * Allow a kernel service to reject an incoming call with a BUSY message,
+ * assuming the incoming call is still valid.
+ */
+int rxrpc_kernel_reject_call(struct socket *sock)
+{
+	int ret;
+
+	_enter("");
+	ret = rxrpc_reject_call(rxrpc_sk(sock->sk));
+	_leave(" = %d", ret);
+	return ret;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_reject_call);
diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c
new file mode 100644
index 0000000..657ee69
--- /dev/null
+++ b/net/rxrpc/ar-ack.c
@@ -0,0 +1,1306 @@
+/* Management of Tx window, Tx resend, ACKs and out-of-sequence reception
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/circ_buf.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/udp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static unsigned rxrpc_ack_defer = 1;
+
+static const char *rxrpc_acks[] = {
+	"---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL",
+	"-?-"
+};
+
+static const s8 rxrpc_ack_priority[] = {
+	[0]				= 0,
+	[RXRPC_ACK_DELAY]		= 1,
+	[RXRPC_ACK_REQUESTED]		= 2,
+	[RXRPC_ACK_IDLE]		= 3,
+	[RXRPC_ACK_PING_RESPONSE]	= 4,
+	[RXRPC_ACK_DUPLICATE]		= 5,
+	[RXRPC_ACK_OUT_OF_SEQUENCE]	= 6,
+	[RXRPC_ACK_EXCEEDS_WINDOW]	= 7,
+	[RXRPC_ACK_NOSPACE]		= 8,
+};
+
+/*
+ * propose an ACK be sent
+ */
+void __rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason,
+			 __be32 serial, bool immediate)
+{
+	unsigned long expiry;
+	s8 prior = rxrpc_ack_priority[ack_reason];
+
+	ASSERTCMP(prior, >, 0);
+
+	_enter("{%d},%s,%%%x,%u",
+	       call->debug_id, rxrpc_acks[ack_reason], ntohl(serial),
+	       immediate);
+
+	if (prior < rxrpc_ack_priority[call->ackr_reason]) {
+		if (immediate)
+			goto cancel_timer;
+		return;
+	}
+
+	/* update DELAY, IDLE, REQUESTED and PING_RESPONSE ACK serial
+	 * numbers */
+	if (prior == rxrpc_ack_priority[call->ackr_reason]) {
+		if (prior <= 4)
+			call->ackr_serial = serial;
+		if (immediate)
+			goto cancel_timer;
+		return;
+	}
+
+	call->ackr_reason = ack_reason;
+	call->ackr_serial = serial;
+
+	switch (ack_reason) {
+	case RXRPC_ACK_DELAY:
+		_debug("run delay timer");
+		call->ack_timer.expires = jiffies + rxrpc_ack_timeout * HZ;
+		add_timer(&call->ack_timer);
+		return;
+
+	case RXRPC_ACK_IDLE:
+		if (!immediate) {
+			_debug("run defer timer");
+			expiry = 1;
+			goto run_timer;
+		}
+		goto cancel_timer;
+
+	case RXRPC_ACK_REQUESTED:
+		if (!rxrpc_ack_defer)
+			goto cancel_timer;
+		if (!immediate || serial == cpu_to_be32(1)) {
+			_debug("run defer timer");
+			expiry = rxrpc_ack_defer;
+			goto run_timer;
+		}
+
+	default:
+		_debug("immediate ACK");
+		goto cancel_timer;
+	}
+
+run_timer:
+	expiry += jiffies;
+	if (!timer_pending(&call->ack_timer) ||
+	    time_after(call->ack_timer.expires, expiry))
+		mod_timer(&call->ack_timer, expiry);
+	return;
+
+cancel_timer:
+	_debug("cancel timer %%%u", ntohl(serial));
+	try_to_del_timer_sync(&call->ack_timer);
+	read_lock_bh(&call->state_lock);
+	if (call->state <= RXRPC_CALL_COMPLETE &&
+	    !test_and_set_bit(RXRPC_CALL_ACK, &call->events))
+		rxrpc_queue_call(call);
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * propose an ACK be sent, locking the call structure
+ */
+void rxrpc_propose_ACK(struct rxrpc_call *call, uint8_t ack_reason,
+		       __be32 serial, bool immediate)
+{
+	s8 prior = rxrpc_ack_priority[ack_reason];
+
+	if (prior > rxrpc_ack_priority[call->ackr_reason]) {
+		spin_lock_bh(&call->lock);
+		__rxrpc_propose_ACK(call, ack_reason, serial, immediate);
+		spin_unlock_bh(&call->lock);
+	}
+}
+
+/*
+ * set the resend timer
+ */
+static void rxrpc_set_resend(struct rxrpc_call *call, u8 resend,
+			     unsigned long resend_at)
+{
+	read_lock_bh(&call->state_lock);
+	if (call->state >= RXRPC_CALL_COMPLETE)
+		resend = 0;
+
+	if (resend & 1) {
+		_debug("SET RESEND");
+		set_bit(RXRPC_CALL_RESEND, &call->events);
+	}
+
+	if (resend & 2) {
+		_debug("MODIFY RESEND TIMER");
+		set_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+		mod_timer(&call->resend_timer, resend_at);
+	} else {
+		_debug("KILL RESEND TIMER");
+		del_timer_sync(&call->resend_timer);
+		clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+		clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+	}
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * resend packets
+ */
+static void rxrpc_resend(struct rxrpc_call *call)
+{
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_header *hdr;
+	struct sk_buff *txb;
+	unsigned long *p_txb, resend_at;
+	int loop, stop;
+	u8 resend;
+
+	_enter("{%d,%d,%d,%d},",
+	       call->acks_hard, call->acks_unacked,
+	       atomic_read(&call->sequence),
+	       CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz));
+
+	stop = 0;
+	resend = 0;
+	resend_at = 0;
+
+	for (loop = call->acks_tail;
+	     loop != call->acks_head || stop;
+	     loop = (loop + 1) &  (call->acks_winsz - 1)
+	     ) {
+		p_txb = call->acks_window + loop;
+		smp_read_barrier_depends();
+		if (*p_txb & 1)
+			continue;
+
+		txb = (struct sk_buff *) *p_txb;
+		sp = rxrpc_skb(txb);
+
+		if (sp->need_resend) {
+			sp->need_resend = 0;
+
+			/* each Tx packet has a new serial number */
+			sp->hdr.serial =
+				htonl(atomic_inc_return(&call->conn->serial));
+
+			hdr = (struct rxrpc_header *) txb->head;
+			hdr->serial = sp->hdr.serial;
+
+			_proto("Tx DATA %%%u { #%d }",
+			       ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+			if (rxrpc_send_packet(call->conn->trans, txb) < 0) {
+				stop = 0;
+				sp->resend_at = jiffies + 3;
+			} else {
+				sp->resend_at =
+					jiffies + rxrpc_resend_timeout * HZ;
+			}
+		}
+
+		if (time_after_eq(jiffies + 1, sp->resend_at)) {
+			sp->need_resend = 1;
+			resend |= 1;
+		} else if (resend & 2) {
+			if (time_before(sp->resend_at, resend_at))
+				resend_at = sp->resend_at;
+		} else {
+			resend_at = sp->resend_at;
+			resend |= 2;
+		}
+	}
+
+	rxrpc_set_resend(call, resend, resend_at);
+	_leave("");
+}
+
+/*
+ * handle resend timer expiry
+ */
+static void rxrpc_resend_timer(struct rxrpc_call *call)
+{
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *txb;
+	unsigned long *p_txb, resend_at;
+	int loop;
+	u8 resend;
+
+	_enter("%d,%d,%d",
+	       call->acks_tail, call->acks_unacked, call->acks_head);
+
+	resend = 0;
+	resend_at = 0;
+
+	for (loop = call->acks_unacked;
+	     loop != call->acks_head;
+	     loop = (loop + 1) &  (call->acks_winsz - 1)
+	     ) {
+		p_txb = call->acks_window + loop;
+		smp_read_barrier_depends();
+		txb = (struct sk_buff *) (*p_txb & ~1);
+		sp = rxrpc_skb(txb);
+
+		ASSERT(!(*p_txb & 1));
+
+		if (sp->need_resend) {
+			;
+		} else if (time_after_eq(jiffies + 1, sp->resend_at)) {
+			sp->need_resend = 1;
+			resend |= 1;
+		} else if (resend & 2) {
+			if (time_before(sp->resend_at, resend_at))
+				resend_at = sp->resend_at;
+		} else {
+			resend_at = sp->resend_at;
+			resend |= 2;
+		}
+	}
+
+	rxrpc_set_resend(call, resend, resend_at);
+	_leave("");
+}
+
+/*
+ * process soft ACKs of our transmitted packets
+ * - these indicate packets the peer has or has not received, but hasn't yet
+ *   given to the consumer, and so can still be discarded and re-requested
+ */
+static int rxrpc_process_soft_ACKs(struct rxrpc_call *call,
+				   struct rxrpc_ackpacket *ack,
+				   struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *txb;
+	unsigned long *p_txb, resend_at;
+	int loop;
+	u8 sacks[RXRPC_MAXACKS], resend;
+
+	_enter("{%d,%d},{%d},",
+	       call->acks_hard,
+	       CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz),
+	       ack->nAcks);
+
+	if (skb_copy_bits(skb, 0, sacks, ack->nAcks) < 0)
+		goto protocol_error;
+
+	resend = 0;
+	resend_at = 0;
+	for (loop = 0; loop < ack->nAcks; loop++) {
+		p_txb = call->acks_window;
+		p_txb += (call->acks_tail + loop) & (call->acks_winsz - 1);
+		smp_read_barrier_depends();
+		txb = (struct sk_buff *) (*p_txb & ~1);
+		sp = rxrpc_skb(txb);
+
+		switch (sacks[loop]) {
+		case RXRPC_ACK_TYPE_ACK:
+			sp->need_resend = 0;
+			*p_txb |= 1;
+			break;
+		case RXRPC_ACK_TYPE_NACK:
+			sp->need_resend = 1;
+			*p_txb &= ~1;
+			resend = 1;
+			break;
+		default:
+			_debug("Unsupported ACK type %d", sacks[loop]);
+			goto protocol_error;
+		}
+	}
+
+	smp_mb();
+	call->acks_unacked = (call->acks_tail + loop) & (call->acks_winsz - 1);
+
+	/* anything not explicitly ACK'd is implicitly NACK'd, but may just not
+	 * have been received or processed yet by the far end */
+	for (loop = call->acks_unacked;
+	     loop != call->acks_head;
+	     loop = (loop + 1) &  (call->acks_winsz - 1)
+	     ) {
+		p_txb = call->acks_window + loop;
+		smp_read_barrier_depends();
+		txb = (struct sk_buff *) (*p_txb & ~1);
+		sp = rxrpc_skb(txb);
+
+		if (*p_txb & 1) {
+			/* packet must have been discarded */
+			sp->need_resend = 1;
+			*p_txb &= ~1;
+			resend |= 1;
+		} else if (sp->need_resend) {
+			;
+		} else if (time_after_eq(jiffies + 1, sp->resend_at)) {
+			sp->need_resend = 1;
+			resend |= 1;
+		} else if (resend & 2) {
+			if (time_before(sp->resend_at, resend_at))
+				resend_at = sp->resend_at;
+		} else {
+			resend_at = sp->resend_at;
+			resend |= 2;
+		}
+	}
+
+	rxrpc_set_resend(call, resend, resend_at);
+	_leave(" = 0");
+	return 0;
+
+protocol_error:
+	_leave(" = -EPROTO");
+	return -EPROTO;
+}
+
+/*
+ * discard hard-ACK'd packets from the Tx window
+ */
+static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard)
+{
+	struct rxrpc_skb_priv *sp;
+	unsigned long _skb;
+	int tail = call->acks_tail, old_tail;
+	int win = CIRC_CNT(call->acks_head, tail, call->acks_winsz);
+
+	_enter("{%u,%u},%u", call->acks_hard, win, hard);
+
+	ASSERTCMP(hard - call->acks_hard, <=, win);
+
+	while (call->acks_hard < hard) {
+		smp_read_barrier_depends();
+		_skb = call->acks_window[tail] & ~1;
+		sp = rxrpc_skb((struct sk_buff *) _skb);
+		rxrpc_free_skb((struct sk_buff *) _skb);
+		old_tail = tail;
+		tail = (tail + 1) & (call->acks_winsz - 1);
+		call->acks_tail = tail;
+		if (call->acks_unacked == old_tail)
+			call->acks_unacked = tail;
+		call->acks_hard++;
+	}
+
+	wake_up(&call->tx_waitq);
+}
+
+/*
+ * clear the Tx window in the event of a failure
+ */
+static void rxrpc_clear_tx_window(struct rxrpc_call *call)
+{
+	rxrpc_rotate_tx_window(call, atomic_read(&call->sequence));
+}
+
+/*
+ * drain the out of sequence received packet queue into the packet Rx queue
+ */
+static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
+{
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *skb;
+	bool terminal;
+	int ret;
+
+	_enter("{%d,%d}", call->rx_data_post, call->rx_first_oos);
+
+	spin_lock_bh(&call->lock);
+
+	ret = -ECONNRESET;
+	if (test_bit(RXRPC_CALL_RELEASED, &call->flags))
+		goto socket_unavailable;
+
+	skb = skb_dequeue(&call->rx_oos_queue);
+	if (skb) {
+		sp = rxrpc_skb(skb);
+
+		_debug("drain OOS packet %d [%d]",
+		       ntohl(sp->hdr.seq), call->rx_first_oos);
+
+		if (ntohl(sp->hdr.seq) != call->rx_first_oos) {
+			skb_queue_head(&call->rx_oos_queue, skb);
+			call->rx_first_oos = ntohl(rxrpc_skb(skb)->hdr.seq);
+			_debug("requeue %p {%u}", skb, call->rx_first_oos);
+		} else {
+			skb->mark = RXRPC_SKB_MARK_DATA;
+			terminal = ((sp->hdr.flags & RXRPC_LAST_PACKET) &&
+				!(sp->hdr.flags & RXRPC_CLIENT_INITIATED));
+			ret = rxrpc_queue_rcv_skb(call, skb, true, terminal);
+			BUG_ON(ret < 0);
+			_debug("drain #%u", call->rx_data_post);
+			call->rx_data_post++;
+
+			/* find out what the next packet is */
+			skb = skb_peek(&call->rx_oos_queue);
+			if (skb)
+				call->rx_first_oos =
+					ntohl(rxrpc_skb(skb)->hdr.seq);
+			else
+				call->rx_first_oos = 0;
+			_debug("peek %p {%u}", skb, call->rx_first_oos);
+		}
+	}
+
+	ret = 0;
+socket_unavailable:
+	spin_unlock_bh(&call->lock);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * insert an out of sequence packet into the buffer
+ */
+static void rxrpc_insert_oos_packet(struct rxrpc_call *call,
+				    struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp, *psp;
+	struct sk_buff *p;
+	u32 seq;
+
+	sp = rxrpc_skb(skb);
+	seq = ntohl(sp->hdr.seq);
+	_enter(",,{%u}", seq);
+
+	skb->destructor = rxrpc_packet_destructor;
+	ASSERTCMP(sp->call, ==, NULL);
+	sp->call = call;
+	rxrpc_get_call(call);
+
+	/* insert into the buffer in sequence order */
+	spin_lock_bh(&call->lock);
+
+	skb_queue_walk(&call->rx_oos_queue, p) {
+		psp = rxrpc_skb(p);
+		if (ntohl(psp->hdr.seq) > seq) {
+			_debug("insert oos #%u before #%u",
+			       seq, ntohl(psp->hdr.seq));
+			skb_insert(p, skb, &call->rx_oos_queue);
+			goto inserted;
+		}
+	}
+
+	_debug("append oos #%u", seq);
+	skb_queue_tail(&call->rx_oos_queue, skb);
+inserted:
+
+	/* we might now have a new front to the queue */
+	if (call->rx_first_oos == 0 || seq < call->rx_first_oos)
+		call->rx_first_oos = seq;
+
+	read_lock(&call->state_lock);
+	if (call->state < RXRPC_CALL_COMPLETE &&
+	    call->rx_data_post == call->rx_first_oos) {
+		_debug("drain rx oos now");
+		set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events);
+	}
+	read_unlock(&call->state_lock);
+
+	spin_unlock_bh(&call->lock);
+	_leave(" [stored #%u]", call->rx_first_oos);
+}
+
+/*
+ * clear the Tx window on final ACK reception
+ */
+static void rxrpc_zap_tx_window(struct rxrpc_call *call)
+{
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *skb;
+	unsigned long _skb, *acks_window;
+	uint8_t winsz = call->acks_winsz;
+	int tail;
+
+	acks_window = call->acks_window;
+	call->acks_window = NULL;
+
+	while (CIRC_CNT(call->acks_head, call->acks_tail, winsz) > 0) {
+		tail = call->acks_tail;
+		smp_read_barrier_depends();
+		_skb = acks_window[tail] & ~1;
+		smp_mb();
+		call->acks_tail = (call->acks_tail + 1) & (winsz - 1);
+
+		skb = (struct sk_buff *) _skb;
+		sp = rxrpc_skb(skb);
+		_debug("+++ clear Tx %u", ntohl(sp->hdr.seq));
+		rxrpc_free_skb(skb);
+	}
+
+	kfree(acks_window);
+}
+
+/*
+ * process the extra information that may be appended to an ACK packet
+ */
+static void rxrpc_extract_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
+				  unsigned latest, int nAcks)
+{
+	struct rxrpc_ackinfo ackinfo;
+	struct rxrpc_peer *peer;
+	unsigned mtu;
+
+	if (skb_copy_bits(skb, nAcks + 3, &ackinfo, sizeof(ackinfo)) < 0) {
+		_leave(" [no ackinfo]");
+		return;
+	}
+
+	_proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }",
+	       latest,
+	       ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU),
+	       ntohl(ackinfo.rwind), ntohl(ackinfo.jumbo_max));
+
+	mtu = min(ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU));
+
+	peer = call->conn->trans->peer;
+	if (mtu < peer->maxdata) {
+		spin_lock_bh(&peer->lock);
+		peer->maxdata = mtu;
+		peer->mtu = mtu + peer->hdrsize;
+		spin_unlock_bh(&peer->lock);
+		_net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata);
+	}
+}
+
+/*
+ * process packets in the reception queue
+ */
+static int rxrpc_process_rx_queue(struct rxrpc_call *call,
+				  u32 *_abort_code)
+{
+	struct rxrpc_ackpacket ack;
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *skb;
+	bool post_ACK;
+	int latest;
+	u32 hard, tx;
+
+	_enter("");
+
+process_further:
+	skb = skb_dequeue(&call->rx_queue);
+	if (!skb)
+		return -EAGAIN;
+
+	_net("deferred skb %p", skb);
+
+	sp = rxrpc_skb(skb);
+
+	_debug("process %s [st %d]", rxrpc_pkts[sp->hdr.type], call->state);
+
+	post_ACK = false;
+
+	switch (sp->hdr.type) {
+		/* data packets that wind up here have been received out of
+		 * order, need security processing or are jumbo packets */
+	case RXRPC_PACKET_TYPE_DATA:
+		_proto("OOSQ DATA %%%u { #%u }",
+		       ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+
+		/* secured packets must be verified and possibly decrypted */
+		if (rxrpc_verify_packet(call, skb, _abort_code) < 0)
+			goto protocol_error;
+
+		rxrpc_insert_oos_packet(call, skb);
+		goto process_further;
+
+		/* partial ACK to process */
+	case RXRPC_PACKET_TYPE_ACK:
+		if (skb_copy_bits(skb, 0, &ack, sizeof(ack)) < 0) {
+			_debug("extraction failure");
+			goto protocol_error;
+		}
+		if (!skb_pull(skb, sizeof(ack)))
+			BUG();
+
+		latest = ntohl(sp->hdr.serial);
+		hard = ntohl(ack.firstPacket);
+		tx = atomic_read(&call->sequence);
+
+		_proto("Rx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
+		       latest,
+		       ntohs(ack.maxSkew),
+		       hard,
+		       ntohl(ack.previousPacket),
+		       ntohl(ack.serial),
+		       rxrpc_acks[ack.reason],
+		       ack.nAcks);
+
+		rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks);
+
+		if (ack.reason == RXRPC_ACK_PING) {
+			_proto("Rx ACK %%%u PING Request", latest);
+			rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
+					  sp->hdr.serial, true);
+		}
+
+		/* discard any out-of-order or duplicate ACKs */
+		if (latest - call->acks_latest <= 0) {
+			_debug("discard ACK %d <= %d",
+			       latest, call->acks_latest);
+			goto discard;
+		}
+		call->acks_latest = latest;
+
+		if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
+		    call->state != RXRPC_CALL_CLIENT_AWAIT_REPLY &&
+		    call->state != RXRPC_CALL_SERVER_SEND_REPLY &&
+		    call->state != RXRPC_CALL_SERVER_AWAIT_ACK)
+			goto discard;
+
+		_debug("Tx=%d H=%u S=%d", tx, call->acks_hard, call->state);
+
+		if (hard > 0) {
+			if (hard - 1 > tx) {
+				_debug("hard-ACK'd packet %d not transmitted"
+				       " (%d top)",
+				       hard - 1, tx);
+				goto protocol_error;
+			}
+
+			if ((call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY ||
+			     call->state == RXRPC_CALL_SERVER_AWAIT_ACK) &&
+			    hard > tx)
+				goto all_acked;
+
+			smp_rmb();
+			rxrpc_rotate_tx_window(call, hard - 1);
+		}
+
+		if (ack.nAcks > 0) {
+			if (hard - 1 + ack.nAcks > tx) {
+				_debug("soft-ACK'd packet %d+%d not"
+				       " transmitted (%d top)",
+				       hard - 1, ack.nAcks, tx);
+				goto protocol_error;
+			}
+
+			if (rxrpc_process_soft_ACKs(call, &ack, skb) < 0)
+				goto protocol_error;
+		}
+		goto discard;
+
+		/* complete ACK to process */
+	case RXRPC_PACKET_TYPE_ACKALL:
+		goto all_acked;
+
+		/* abort and busy are handled elsewhere */
+	case RXRPC_PACKET_TYPE_BUSY:
+	case RXRPC_PACKET_TYPE_ABORT:
+		BUG();
+
+		/* connection level events - also handled elsewhere */
+	case RXRPC_PACKET_TYPE_CHALLENGE:
+	case RXRPC_PACKET_TYPE_RESPONSE:
+	case RXRPC_PACKET_TYPE_DEBUG:
+		BUG();
+	}
+
+	/* if we've had a hard ACK that covers all the packets we've sent, then
+	 * that ends that phase of the operation */
+all_acked:
+	write_lock_bh(&call->state_lock);
+	_debug("ack all %d", call->state);
+
+	switch (call->state) {
+	case RXRPC_CALL_CLIENT_AWAIT_REPLY:
+		call->state = RXRPC_CALL_CLIENT_RECV_REPLY;
+		break;
+	case RXRPC_CALL_SERVER_AWAIT_ACK:
+		_debug("srv complete");
+		call->state = RXRPC_CALL_COMPLETE;
+		post_ACK = true;
+		break;
+	case RXRPC_CALL_CLIENT_SEND_REQUEST:
+	case RXRPC_CALL_SERVER_RECV_REQUEST:
+		goto protocol_error_unlock; /* can't occur yet */
+	default:
+		write_unlock_bh(&call->state_lock);
+		goto discard; /* assume packet left over from earlier phase */
+	}
+
+	write_unlock_bh(&call->state_lock);
+
+	/* if all the packets we sent are hard-ACK'd, then we can discard
+	 * whatever we've got left */
+	_debug("clear Tx %d",
+	       CIRC_CNT(call->acks_head, call->acks_tail, call->acks_winsz));
+
+	del_timer_sync(&call->resend_timer);
+	clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+	clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+
+	if (call->acks_window)
+		rxrpc_zap_tx_window(call);
+
+	if (post_ACK) {
+		/* post the final ACK message for userspace to pick up */
+		_debug("post ACK");
+		skb->mark = RXRPC_SKB_MARK_FINAL_ACK;
+		sp->call = call;
+		rxrpc_get_call(call);
+		spin_lock_bh(&call->lock);
+		if (rxrpc_queue_rcv_skb(call, skb, true, true) < 0)
+			BUG();
+		spin_unlock_bh(&call->lock);
+		goto process_further;
+	}
+
+discard:
+	rxrpc_free_skb(skb);
+	goto process_further;
+
+protocol_error_unlock:
+	write_unlock_bh(&call->state_lock);
+protocol_error:
+	rxrpc_free_skb(skb);
+	_leave(" = -EPROTO");
+	return -EPROTO;
+}
+
+/*
+ * post a message to the socket Rx queue for recvmsg() to pick up
+ */
+static int rxrpc_post_message(struct rxrpc_call *call, u32 mark, u32 error,
+			      bool fatal)
+{
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *skb;
+	int ret;
+
+	_enter("{%d,%lx},%u,%u,%d",
+	       call->debug_id, call->flags, mark, error, fatal);
+
+	/* remove timers and things for fatal messages */
+	if (fatal) {
+		del_timer_sync(&call->resend_timer);
+		del_timer_sync(&call->ack_timer);
+		clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+	}
+
+	if (mark != RXRPC_SKB_MARK_NEW_CALL &&
+	    !test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) {
+		_leave("[no userid]");
+		return 0;
+	}
+
+	if (!test_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags)) {
+		skb = alloc_skb(0, GFP_NOFS);
+		if (!skb)
+			return -ENOMEM;
+
+		rxrpc_new_skb(skb);
+
+		skb->mark = mark;
+
+		sp = rxrpc_skb(skb);
+		memset(sp, 0, sizeof(*sp));
+		sp->error = error;
+		sp->call = call;
+		rxrpc_get_call(call);
+
+		spin_lock_bh(&call->lock);
+		ret = rxrpc_queue_rcv_skb(call, skb, true, fatal);
+		spin_unlock_bh(&call->lock);
+		if (ret < 0)
+			BUG();
+	}
+
+	return 0;
+}
+
+/*
+ * handle background processing of incoming call packets and ACK / abort
+ * generation
+ */
+void rxrpc_process_call(struct work_struct *work)
+{
+	struct rxrpc_call *call =
+		container_of(work, struct rxrpc_call, processor);
+	struct rxrpc_ackpacket ack;
+	struct rxrpc_ackinfo ackinfo;
+	struct rxrpc_header hdr;
+	struct msghdr msg;
+	struct kvec iov[5];
+	unsigned long bits;
+	__be32 data, pad;
+	size_t len;
+	int genbit, loop, nbit, ioc, ret, mtu;
+	u32 abort_code = RX_PROTOCOL_ERROR;
+	u8 *acks = NULL;
+
+	//printk("\n--------------------\n");
+	_enter("{%d,%s,%lx} [%lu]",
+	       call->debug_id, rxrpc_call_states[call->state], call->events,
+	       (jiffies - call->creation_jif) / (HZ / 10));
+
+	if (test_and_set_bit(RXRPC_CALL_PROC_BUSY, &call->flags)) {
+		_debug("XXXXXXXXXXXXX RUNNING ON MULTIPLE CPUS XXXXXXXXXXXXX");
+		return;
+	}
+
+	/* there's a good chance we're going to have to send a message, so set
+	 * one up in advance */
+	msg.msg_name	= &call->conn->trans->peer->srx.transport.sin;
+	msg.msg_namelen	= sizeof(call->conn->trans->peer->srx.transport.sin);
+	msg.msg_control	= NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags	= 0;
+
+	hdr.epoch	= call->conn->epoch;
+	hdr.cid		= call->cid;
+	hdr.callNumber	= call->call_id;
+	hdr.seq		= 0;
+	hdr.type	= RXRPC_PACKET_TYPE_ACK;
+	hdr.flags	= call->conn->out_clientflag;
+	hdr.userStatus	= 0;
+	hdr.securityIndex = call->conn->security_ix;
+	hdr._rsvd	= 0;
+	hdr.serviceId	= call->conn->service_id;
+
+	memset(iov, 0, sizeof(iov));
+	iov[0].iov_base	= &hdr;
+	iov[0].iov_len	= sizeof(hdr);
+
+	/* deal with events of a final nature */
+	if (test_bit(RXRPC_CALL_RELEASE, &call->events)) {
+		rxrpc_release_call(call);
+		clear_bit(RXRPC_CALL_RELEASE, &call->events);
+	}
+
+	if (test_bit(RXRPC_CALL_RCVD_ERROR, &call->events)) {
+		int error;
+
+		clear_bit(RXRPC_CALL_CONN_ABORT, &call->events);
+		clear_bit(RXRPC_CALL_REJECT_BUSY, &call->events);
+		clear_bit(RXRPC_CALL_ABORT, &call->events);
+
+		error = call->conn->trans->peer->net_error;
+		_debug("post net error %d", error);
+
+		if (rxrpc_post_message(call, RXRPC_SKB_MARK_NET_ERROR,
+				       error, true) < 0)
+			goto no_mem;
+		clear_bit(RXRPC_CALL_RCVD_ERROR, &call->events);
+		goto kill_ACKs;
+	}
+
+	if (test_bit(RXRPC_CALL_CONN_ABORT, &call->events)) {
+		ASSERTCMP(call->state, >, RXRPC_CALL_COMPLETE);
+
+		clear_bit(RXRPC_CALL_REJECT_BUSY, &call->events);
+		clear_bit(RXRPC_CALL_ABORT, &call->events);
+
+		_debug("post conn abort");
+
+		if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
+				       call->conn->error, true) < 0)
+			goto no_mem;
+		clear_bit(RXRPC_CALL_CONN_ABORT, &call->events);
+		goto kill_ACKs;
+	}
+
+	if (test_bit(RXRPC_CALL_REJECT_BUSY, &call->events)) {
+		hdr.type = RXRPC_PACKET_TYPE_BUSY;
+		genbit = RXRPC_CALL_REJECT_BUSY;
+		goto send_message;
+	}
+
+	if (test_bit(RXRPC_CALL_ABORT, &call->events)) {
+		ASSERTCMP(call->state, >, RXRPC_CALL_COMPLETE);
+
+		if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
+				       ECONNABORTED, true) < 0)
+			goto no_mem;
+		hdr.type = RXRPC_PACKET_TYPE_ABORT;
+		data = htonl(call->abort_code);
+		iov[1].iov_base = &data;
+		iov[1].iov_len = sizeof(data);
+		genbit = RXRPC_CALL_ABORT;
+		goto send_message;
+	}
+
+	if (test_bit(RXRPC_CALL_ACK_FINAL, &call->events)) {
+		genbit = RXRPC_CALL_ACK_FINAL;
+
+		ack.bufferSpace	= htons(8);
+		ack.maxSkew	= 0;
+		ack.serial	= 0;
+		ack.reason	= RXRPC_ACK_IDLE;
+		ack.nAcks	= 0;
+		call->ackr_reason = 0;
+
+		spin_lock_bh(&call->lock);
+		ack.serial = call->ackr_serial;
+		ack.previousPacket = call->ackr_prev_seq;
+		ack.firstPacket = htonl(call->rx_data_eaten + 1);
+		spin_unlock_bh(&call->lock);
+
+		pad = 0;
+
+		iov[1].iov_base = &ack;
+		iov[1].iov_len	= sizeof(ack);
+		iov[2].iov_base = &pad;
+		iov[2].iov_len	= 3;
+		iov[3].iov_base = &ackinfo;
+		iov[3].iov_len	= sizeof(ackinfo);
+		goto send_ACK;
+	}
+
+	if (call->events & ((1 << RXRPC_CALL_RCVD_BUSY) |
+			    (1 << RXRPC_CALL_RCVD_ABORT))
+	    ) {
+		u32 mark;
+
+		if (test_bit(RXRPC_CALL_RCVD_ABORT, &call->events))
+			mark = RXRPC_SKB_MARK_REMOTE_ABORT;
+		else
+			mark = RXRPC_SKB_MARK_BUSY;
+
+		_debug("post abort/busy");
+		rxrpc_clear_tx_window(call);
+		if (rxrpc_post_message(call, mark, ECONNABORTED, true) < 0)
+			goto no_mem;
+
+		clear_bit(RXRPC_CALL_RCVD_BUSY, &call->events);
+		clear_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+		goto kill_ACKs;
+	}
+
+	if (test_and_clear_bit(RXRPC_CALL_RCVD_ACKALL, &call->events)) {
+		_debug("do implicit ackall");
+		rxrpc_clear_tx_window(call);
+	}
+
+	if (test_bit(RXRPC_CALL_LIFE_TIMER, &call->events)) {
+		write_lock_bh(&call->state_lock);
+		if (call->state <= RXRPC_CALL_COMPLETE) {
+			call->state = RXRPC_CALL_LOCALLY_ABORTED;
+			call->abort_code = RX_CALL_TIMEOUT;
+			set_bit(RXRPC_CALL_ABORT, &call->events);
+		}
+		write_unlock_bh(&call->state_lock);
+
+		_debug("post timeout");
+		if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
+				       ETIME, true) < 0)
+			goto no_mem;
+
+		clear_bit(RXRPC_CALL_LIFE_TIMER, &call->events);
+		goto kill_ACKs;
+	}
+
+	/* deal with assorted inbound messages */
+	if (!skb_queue_empty(&call->rx_queue)) {
+		switch (rxrpc_process_rx_queue(call, &abort_code)) {
+		case 0:
+		case -EAGAIN:
+			break;
+		case -ENOMEM:
+			goto no_mem;
+		case -EKEYEXPIRED:
+		case -EKEYREJECTED:
+		case -EPROTO:
+			rxrpc_abort_call(call, abort_code);
+			goto kill_ACKs;
+		}
+	}
+
+	/* handle resending */
+	if (test_and_clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+		rxrpc_resend_timer(call);
+	if (test_and_clear_bit(RXRPC_CALL_RESEND, &call->events))
+		rxrpc_resend(call);
+
+	/* consider sending an ordinary ACK */
+	if (test_bit(RXRPC_CALL_ACK, &call->events)) {
+		_debug("send ACK: window: %d - %d { %lx }",
+		       call->rx_data_eaten, call->ackr_win_top,
+		       call->ackr_window[0]);
+
+		if (call->state > RXRPC_CALL_SERVER_ACK_REQUEST &&
+		    call->ackr_reason != RXRPC_ACK_PING_RESPONSE) {
+			/* ACK by sending reply DATA packet in this state */
+			clear_bit(RXRPC_CALL_ACK, &call->events);
+			goto maybe_reschedule;
+		}
+
+		genbit = RXRPC_CALL_ACK;
+
+		acks = kzalloc(call->ackr_win_top - call->rx_data_eaten,
+			       GFP_NOFS);
+		if (!acks)
+			goto no_mem;
+
+		//hdr.flags	= RXRPC_SLOW_START_OK;
+		ack.bufferSpace	= htons(8);
+		ack.maxSkew	= 0;
+		ack.serial	= 0;
+		ack.reason	= 0;
+
+		spin_lock_bh(&call->lock);
+		ack.reason = call->ackr_reason;
+		ack.serial = call->ackr_serial;
+		ack.previousPacket = call->ackr_prev_seq;
+		ack.firstPacket = htonl(call->rx_data_eaten + 1);
+
+		ack.nAcks = 0;
+		for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) {
+			nbit = loop * BITS_PER_LONG;
+			for (bits = call->ackr_window[loop]; bits; bits >>= 1
+			     ) {
+				_debug("- l=%d n=%d b=%lx", loop, nbit, bits);
+				if (bits & 1) {
+					acks[nbit] = RXRPC_ACK_TYPE_ACK;
+					ack.nAcks = nbit + 1;
+				}
+				nbit++;
+			}
+		}
+		call->ackr_reason = 0;
+		spin_unlock_bh(&call->lock);
+
+		pad = 0;
+
+		iov[1].iov_base = &ack;
+		iov[1].iov_len	= sizeof(ack);
+		iov[2].iov_base = acks;
+		iov[2].iov_len	= ack.nAcks;
+		iov[3].iov_base = &pad;
+		iov[3].iov_len	= 3;
+		iov[4].iov_base = &ackinfo;
+		iov[4].iov_len	= sizeof(ackinfo);
+
+		switch (ack.reason) {
+		case RXRPC_ACK_REQUESTED:
+		case RXRPC_ACK_DUPLICATE:
+		case RXRPC_ACK_OUT_OF_SEQUENCE:
+		case RXRPC_ACK_EXCEEDS_WINDOW:
+		case RXRPC_ACK_NOSPACE:
+		case RXRPC_ACK_PING:
+		case RXRPC_ACK_PING_RESPONSE:
+			goto send_ACK_with_skew;
+		case RXRPC_ACK_DELAY:
+		case RXRPC_ACK_IDLE:
+			goto send_ACK;
+		}
+	}
+
+	/* handle completion of security negotiations on an incoming
+	 * connection */
+	if (test_and_clear_bit(RXRPC_CALL_SECURED, &call->events)) {
+		_debug("secured");
+		spin_lock_bh(&call->lock);
+
+		if (call->state == RXRPC_CALL_SERVER_SECURING) {
+			_debug("securing");
+			write_lock(&call->conn->lock);
+			if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+			    !test_bit(RXRPC_CALL_RELEASE, &call->events)) {
+				_debug("not released");
+				call->state = RXRPC_CALL_SERVER_ACCEPTING;
+				list_move_tail(&call->accept_link,
+					       &call->socket->acceptq);
+			}
+			write_unlock(&call->conn->lock);
+			read_lock(&call->state_lock);
+			if (call->state < RXRPC_CALL_COMPLETE)
+				set_bit(RXRPC_CALL_POST_ACCEPT, &call->events);
+			read_unlock(&call->state_lock);
+		}
+
+		spin_unlock_bh(&call->lock);
+		if (!test_bit(RXRPC_CALL_POST_ACCEPT, &call->events))
+			goto maybe_reschedule;
+	}
+
+	/* post a notification of an acceptable connection to the app */
+	if (test_bit(RXRPC_CALL_POST_ACCEPT, &call->events)) {
+		_debug("post accept");
+		if (rxrpc_post_message(call, RXRPC_SKB_MARK_NEW_CALL,
+				       0, false) < 0)
+			goto no_mem;
+		clear_bit(RXRPC_CALL_POST_ACCEPT, &call->events);
+		goto maybe_reschedule;
+	}
+
+	/* handle incoming call acceptance */
+	if (test_and_clear_bit(RXRPC_CALL_ACCEPTED, &call->events)) {
+		_debug("accepted");
+		ASSERTCMP(call->rx_data_post, ==, 0);
+		call->rx_data_post = 1;
+		read_lock_bh(&call->state_lock);
+		if (call->state < RXRPC_CALL_COMPLETE)
+			set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events);
+		read_unlock_bh(&call->state_lock);
+	}
+
+	/* drain the out of sequence received packet queue into the packet Rx
+	 * queue */
+	if (test_and_clear_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events)) {
+		while (call->rx_data_post == call->rx_first_oos)
+			if (rxrpc_drain_rx_oos_queue(call) < 0)
+				break;
+		goto maybe_reschedule;
+	}
+
+	/* other events may have been raised since we started checking */
+	goto maybe_reschedule;
+
+send_ACK_with_skew:
+	ack.maxSkew = htons(atomic_read(&call->conn->hi_serial) -
+			    ntohl(ack.serial));
+send_ACK:
+	mtu = call->conn->trans->peer->if_mtu;
+	mtu -= call->conn->trans->peer->hdrsize;
+	ackinfo.maxMTU	= htonl(mtu);
+	ackinfo.rwind	= htonl(32);
+
+	/* permit the peer to send us jumbo packets if it wants to */
+	ackinfo.rxMTU	= htonl(5692);
+	ackinfo.jumbo_max = htonl(4);
+
+	hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
+	_proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
+	       ntohl(hdr.serial),
+	       ntohs(ack.maxSkew),
+	       ntohl(ack.firstPacket),
+	       ntohl(ack.previousPacket),
+	       ntohl(ack.serial),
+	       rxrpc_acks[ack.reason],
+	       ack.nAcks);
+
+	del_timer_sync(&call->ack_timer);
+	if (ack.nAcks > 0)
+		set_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags);
+	goto send_message_2;
+
+send_message:
+	_debug("send message");
+
+	hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
+	_proto("Tx %s %%%u", rxrpc_pkts[hdr.type], ntohl(hdr.serial));
+send_message_2:
+
+	len = iov[0].iov_len;
+	ioc = 1;
+	if (iov[4].iov_len) {
+		ioc = 5;
+		len += iov[4].iov_len;
+		len += iov[3].iov_len;
+		len += iov[2].iov_len;
+		len += iov[1].iov_len;
+	} else if (iov[3].iov_len) {
+		ioc = 4;
+		len += iov[3].iov_len;
+		len += iov[2].iov_len;
+		len += iov[1].iov_len;
+	} else if (iov[2].iov_len) {
+		ioc = 3;
+		len += iov[2].iov_len;
+		len += iov[1].iov_len;
+	} else if (iov[1].iov_len) {
+		ioc = 2;
+		len += iov[1].iov_len;
+	}
+
+	ret = kernel_sendmsg(call->conn->trans->local->socket,
+			     &msg, iov, ioc, len);
+	if (ret < 0) {
+		_debug("sendmsg failed: %d", ret);
+		read_lock_bh(&call->state_lock);
+		if (call->state < RXRPC_CALL_DEAD)
+			rxrpc_queue_call(call);
+		read_unlock_bh(&call->state_lock);
+		goto error;
+	}
+
+	switch (genbit) {
+	case RXRPC_CALL_ABORT:
+		clear_bit(genbit, &call->events);
+		clear_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+		goto kill_ACKs;
+
+	case RXRPC_CALL_ACK_FINAL:
+		write_lock_bh(&call->state_lock);
+		if (call->state == RXRPC_CALL_CLIENT_FINAL_ACK)
+			call->state = RXRPC_CALL_COMPLETE;
+		write_unlock_bh(&call->state_lock);
+		goto kill_ACKs;
+
+	default:
+		clear_bit(genbit, &call->events);
+		switch (call->state) {
+		case RXRPC_CALL_CLIENT_AWAIT_REPLY:
+		case RXRPC_CALL_CLIENT_RECV_REPLY:
+		case RXRPC_CALL_SERVER_RECV_REQUEST:
+		case RXRPC_CALL_SERVER_ACK_REQUEST:
+			_debug("start ACK timer");
+			rxrpc_propose_ACK(call, RXRPC_ACK_DELAY,
+					  call->ackr_serial, false);
+		default:
+			break;
+		}
+		goto maybe_reschedule;
+	}
+
+kill_ACKs:
+	del_timer_sync(&call->ack_timer);
+	if (test_and_clear_bit(RXRPC_CALL_ACK_FINAL, &call->events))
+		rxrpc_put_call(call);
+	clear_bit(RXRPC_CALL_ACK, &call->events);
+
+maybe_reschedule:
+	if (call->events || !skb_queue_empty(&call->rx_queue)) {
+		read_lock_bh(&call->state_lock);
+		if (call->state < RXRPC_CALL_DEAD)
+			rxrpc_queue_call(call);
+		read_unlock_bh(&call->state_lock);
+	}
+
+	/* don't leave aborted connections on the accept queue */
+	if (call->state >= RXRPC_CALL_COMPLETE &&
+	    !list_empty(&call->accept_link)) {
+		_debug("X unlinking once-pending call %p { e=%lx f=%lx c=%x }",
+		       call, call->events, call->flags,
+		       ntohl(call->conn->cid));
+
+		read_lock_bh(&call->state_lock);
+		if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+		    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+			rxrpc_queue_call(call);
+		read_unlock_bh(&call->state_lock);
+	}
+
+error:
+	clear_bit(RXRPC_CALL_PROC_BUSY, &call->flags);
+	kfree(acks);
+
+	/* because we don't want two CPUs both processing the work item for one
+	 * call at the same time, we use a flag to note when it's busy; however
+	 * this means there's a race between clearing the flag and setting the
+	 * work pending bit and the work item being processed again */
+	if (call->events && !work_pending(&call->processor)) {
+		_debug("jumpstart %x", ntohl(call->conn->cid));
+		rxrpc_queue_call(call);
+	}
+
+	_leave("");
+	return;
+
+no_mem:
+	_debug("out of memory");
+	goto maybe_reschedule;
+}
diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c
new file mode 100644
index 0000000..4d92d88
--- /dev/null
+++ b/net/rxrpc/ar-call.c
@@ -0,0 +1,804 @@
+/* RxRPC individual remote procedure call handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/circ_buf.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+struct kmem_cache *rxrpc_call_jar;
+LIST_HEAD(rxrpc_calls);
+DEFINE_RWLOCK(rxrpc_call_lock);
+static unsigned rxrpc_call_max_lifetime = 60;
+static unsigned rxrpc_dead_call_timeout = 2;
+
+static void rxrpc_destroy_call(struct work_struct *work);
+static void rxrpc_call_life_expired(unsigned long _call);
+static void rxrpc_dead_call_expired(unsigned long _call);
+static void rxrpc_ack_time_expired(unsigned long _call);
+static void rxrpc_resend_time_expired(unsigned long _call);
+
+/*
+ * allocate a new call
+ */
+static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)
+{
+	struct rxrpc_call *call;
+
+	call = kmem_cache_zalloc(rxrpc_call_jar, gfp);
+	if (!call)
+		return NULL;
+
+	call->acks_winsz = 16;
+	call->acks_window = kmalloc(call->acks_winsz * sizeof(unsigned long),
+				    gfp);
+	if (!call->acks_window) {
+		kmem_cache_free(rxrpc_call_jar, call);
+		return NULL;
+	}
+
+	setup_timer(&call->lifetimer, &rxrpc_call_life_expired,
+		    (unsigned long) call);
+	setup_timer(&call->deadspan, &rxrpc_dead_call_expired,
+		    (unsigned long) call);
+	setup_timer(&call->ack_timer, &rxrpc_ack_time_expired,
+		    (unsigned long) call);
+	setup_timer(&call->resend_timer, &rxrpc_resend_time_expired,
+		    (unsigned long) call);
+	INIT_WORK(&call->destroyer, &rxrpc_destroy_call);
+	INIT_WORK(&call->processor, &rxrpc_process_call);
+	INIT_LIST_HEAD(&call->accept_link);
+	skb_queue_head_init(&call->rx_queue);
+	skb_queue_head_init(&call->rx_oos_queue);
+	init_waitqueue_head(&call->tx_waitq);
+	spin_lock_init(&call->lock);
+	rwlock_init(&call->state_lock);
+	atomic_set(&call->usage, 1);
+	call->debug_id = atomic_inc_return(&rxrpc_debug_id);
+	call->state = RXRPC_CALL_CLIENT_SEND_REQUEST;
+
+	memset(&call->sock_node, 0xed, sizeof(call->sock_node));
+
+	call->rx_data_expect = 1;
+	call->rx_data_eaten = 0;
+	call->rx_first_oos = 0;
+	call->ackr_win_top = call->rx_data_eaten + 1 + RXRPC_MAXACKS;
+	call->creation_jif = jiffies;
+	return call;
+}
+
+/*
+ * allocate a new client call and attempt to to get a connection slot for it
+ */
+static struct rxrpc_call *rxrpc_alloc_client_call(
+	struct rxrpc_sock *rx,
+	struct rxrpc_transport *trans,
+	struct rxrpc_conn_bundle *bundle,
+	gfp_t gfp)
+{
+	struct rxrpc_call *call;
+	int ret;
+
+	_enter("");
+
+	ASSERT(rx != NULL);
+	ASSERT(trans != NULL);
+	ASSERT(bundle != NULL);
+
+	call = rxrpc_alloc_call(gfp);
+	if (!call)
+		return ERR_PTR(-ENOMEM);
+
+	sock_hold(&rx->sk);
+	call->socket = rx;
+	call->rx_data_post = 1;
+
+	ret = rxrpc_connect_call(rx, trans, bundle, call, gfp);
+	if (ret < 0) {
+		kmem_cache_free(rxrpc_call_jar, call);
+		return ERR_PTR(ret);
+	}
+
+	spin_lock(&call->conn->trans->peer->lock);
+	list_add(&call->error_link, &call->conn->trans->peer->error_targets);
+	spin_unlock(&call->conn->trans->peer->lock);
+
+	call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+	add_timer(&call->lifetimer);
+
+	_leave(" = %p", call);
+	return call;
+}
+
+/*
+ * set up a call for the given data
+ * - called in process context with IRQs enabled
+ */
+struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *rx,
+					 struct rxrpc_transport *trans,
+					 struct rxrpc_conn_bundle *bundle,
+					 unsigned long user_call_ID,
+					 int create,
+					 gfp_t gfp)
+{
+	struct rxrpc_call *call, *candidate;
+	struct rb_node *p, *parent, **pp;
+
+	_enter("%p,%d,%d,%lx,%d",
+	       rx, trans ? trans->debug_id : -1, bundle ? bundle->debug_id : -1,
+	       user_call_ID, create);
+
+	/* search the extant calls first for one that matches the specified
+	 * user ID */
+	read_lock(&rx->call_lock);
+
+	p = rx->calls.rb_node;
+	while (p) {
+		call = rb_entry(p, struct rxrpc_call, sock_node);
+
+		if (user_call_ID < call->user_call_ID)
+			p = p->rb_left;
+		else if (user_call_ID > call->user_call_ID)
+			p = p->rb_right;
+		else
+			goto found_extant_call;
+	}
+
+	read_unlock(&rx->call_lock);
+
+	if (!create || !trans)
+		return ERR_PTR(-EBADSLT);
+
+	/* not yet present - create a candidate for a new record and then
+	 * redo the search */
+	candidate = rxrpc_alloc_client_call(rx, trans, bundle, gfp);
+	if (IS_ERR(candidate)) {
+		_leave(" = %ld", PTR_ERR(candidate));
+		return candidate;
+	}
+
+	candidate->user_call_ID = user_call_ID;
+	__set_bit(RXRPC_CALL_HAS_USERID, &candidate->flags);
+
+	write_lock(&rx->call_lock);
+
+	pp = &rx->calls.rb_node;
+	parent = NULL;
+	while (*pp) {
+		parent = *pp;
+		call = rb_entry(parent, struct rxrpc_call, sock_node);
+
+		if (user_call_ID < call->user_call_ID)
+			pp = &(*pp)->rb_left;
+		else if (user_call_ID > call->user_call_ID)
+			pp = &(*pp)->rb_right;
+		else
+			goto found_extant_second;
+	}
+
+	/* second search also failed; add the new call */
+	call = candidate;
+	candidate = NULL;
+	rxrpc_get_call(call);
+
+	rb_link_node(&call->sock_node, parent, pp);
+	rb_insert_color(&call->sock_node, &rx->calls);
+	write_unlock(&rx->call_lock);
+
+	write_lock_bh(&rxrpc_call_lock);
+	list_add_tail(&call->link, &rxrpc_calls);
+	write_unlock_bh(&rxrpc_call_lock);
+
+	_net("CALL new %d on CONN %d", call->debug_id, call->conn->debug_id);
+
+	_leave(" = %p [new]", call);
+	return call;
+
+	/* we found the call in the list immediately */
+found_extant_call:
+	rxrpc_get_call(call);
+	read_unlock(&rx->call_lock);
+	_leave(" = %p [extant %d]", call, atomic_read(&call->usage));
+	return call;
+
+	/* we found the call on the second time through the list */
+found_extant_second:
+	rxrpc_get_call(call);
+	write_unlock(&rx->call_lock);
+	rxrpc_put_call(candidate);
+	_leave(" = %p [second %d]", call, atomic_read(&call->usage));
+	return call;
+}
+
+/*
+ * set up an incoming call
+ * - called in process context with IRQs enabled
+ */
+struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
+				       struct rxrpc_connection *conn,
+				       struct rxrpc_header *hdr,
+				       gfp_t gfp)
+{
+	struct rxrpc_call *call, *candidate;
+	struct rb_node **p, *parent;
+	__be32 call_id;
+
+	_enter(",%d,,%x", conn->debug_id, gfp);
+
+	ASSERT(rx != NULL);
+
+	candidate = rxrpc_alloc_call(gfp);
+	if (!candidate)
+		return ERR_PTR(-EBUSY);
+
+	candidate->socket = rx;
+	candidate->conn = conn;
+	candidate->cid = hdr->cid;
+	candidate->call_id = hdr->callNumber;
+	candidate->channel = ntohl(hdr->cid) & RXRPC_CHANNELMASK;
+	candidate->rx_data_post = 0;
+	candidate->state = RXRPC_CALL_SERVER_ACCEPTING;
+	if (conn->security_ix > 0)
+		candidate->state = RXRPC_CALL_SERVER_SECURING;
+
+	write_lock_bh(&conn->lock);
+
+	/* set the channel for this call */
+	call = conn->channels[candidate->channel];
+	_debug("channel[%u] is %p", candidate->channel, call);
+	if (call && call->call_id == hdr->callNumber) {
+		/* already set; must've been a duplicate packet */
+		_debug("extant call [%d]", call->state);
+		ASSERTCMP(call->conn, ==, conn);
+
+		read_lock(&call->state_lock);
+		switch (call->state) {
+		case RXRPC_CALL_LOCALLY_ABORTED:
+			if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+				rxrpc_queue_call(call);
+		case RXRPC_CALL_REMOTELY_ABORTED:
+			read_unlock(&call->state_lock);
+			goto aborted_call;
+		default:
+			rxrpc_get_call(call);
+			read_unlock(&call->state_lock);
+			goto extant_call;
+		}
+	}
+
+	if (call) {
+		/* it seems the channel is still in use from the previous call
+		 * - ditch the old binding if its call is now complete */
+		_debug("CALL: %u { %s }",
+		       call->debug_id, rxrpc_call_states[call->state]);
+
+		if (call->state >= RXRPC_CALL_COMPLETE) {
+			conn->channels[call->channel] = NULL;
+		} else {
+			write_unlock_bh(&conn->lock);
+			kmem_cache_free(rxrpc_call_jar, candidate);
+			_leave(" = -EBUSY");
+			return ERR_PTR(-EBUSY);
+		}
+	}
+
+	/* check the call number isn't duplicate */
+	_debug("check dup");
+	call_id = hdr->callNumber;
+	p = &conn->calls.rb_node;
+	parent = NULL;
+	while (*p) {
+		parent = *p;
+		call = rb_entry(parent, struct rxrpc_call, conn_node);
+
+		if (call_id < call->call_id)
+			p = &(*p)->rb_left;
+		else if (call_id > call->call_id)
+			p = &(*p)->rb_right;
+		else
+			goto old_call;
+	}
+
+	/* make the call available */
+	_debug("new call");
+	call = candidate;
+	candidate = NULL;
+	rb_link_node(&call->conn_node, parent, p);
+	rb_insert_color(&call->conn_node, &conn->calls);
+	conn->channels[call->channel] = call;
+	sock_hold(&rx->sk);
+	atomic_inc(&conn->usage);
+	write_unlock_bh(&conn->lock);
+
+	spin_lock(&conn->trans->peer->lock);
+	list_add(&call->error_link, &conn->trans->peer->error_targets);
+	spin_unlock(&conn->trans->peer->lock);
+
+	write_lock_bh(&rxrpc_call_lock);
+	list_add_tail(&call->link, &rxrpc_calls);
+	write_unlock_bh(&rxrpc_call_lock);
+
+	_net("CALL incoming %d on CONN %d", call->debug_id, call->conn->debug_id);
+
+	call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+	add_timer(&call->lifetimer);
+	_leave(" = %p {%d} [new]", call, call->debug_id);
+	return call;
+
+extant_call:
+	write_unlock_bh(&conn->lock);
+	kmem_cache_free(rxrpc_call_jar, candidate);
+	_leave(" = %p {%d} [extant]", call, call ? call->debug_id : -1);
+	return call;
+
+aborted_call:
+	write_unlock_bh(&conn->lock);
+	kmem_cache_free(rxrpc_call_jar, candidate);
+	_leave(" = -ECONNABORTED");
+	return ERR_PTR(-ECONNABORTED);
+
+old_call:
+	write_unlock_bh(&conn->lock);
+	kmem_cache_free(rxrpc_call_jar, candidate);
+	_leave(" = -ECONNRESET [old]");
+	return ERR_PTR(-ECONNRESET);
+}
+
+/*
+ * find an extant server call
+ * - called in process context with IRQs enabled
+ */
+struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *rx,
+					  unsigned long user_call_ID)
+{
+	struct rxrpc_call *call;
+	struct rb_node *p;
+
+	_enter("%p,%lx", rx, user_call_ID);
+
+	/* search the extant calls for one that matches the specified user
+	 * ID */
+	read_lock(&rx->call_lock);
+
+	p = rx->calls.rb_node;
+	while (p) {
+		call = rb_entry(p, struct rxrpc_call, sock_node);
+
+		if (user_call_ID < call->user_call_ID)
+			p = p->rb_left;
+		else if (user_call_ID > call->user_call_ID)
+			p = p->rb_right;
+		else
+			goto found_extant_call;
+	}
+
+	read_unlock(&rx->call_lock);
+	_leave(" = NULL");
+	return NULL;
+
+	/* we found the call in the list immediately */
+found_extant_call:
+	rxrpc_get_call(call);
+	read_unlock(&rx->call_lock);
+	_leave(" = %p [%d]", call, atomic_read(&call->usage));
+	return call;
+}
+
+/*
+ * detach a call from a socket and set up for release
+ */
+void rxrpc_release_call(struct rxrpc_call *call)
+{
+	struct rxrpc_connection *conn = call->conn;
+	struct rxrpc_sock *rx = call->socket;
+
+	_enter("{%d,%d,%d,%d}",
+	       call->debug_id, atomic_read(&call->usage),
+	       atomic_read(&call->ackr_not_idle),
+	       call->rx_first_oos);
+
+	spin_lock_bh(&call->lock);
+	if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags))
+		BUG();
+	spin_unlock_bh(&call->lock);
+
+	/* dissociate from the socket
+	 * - the socket's ref on the call is passed to the death timer
+	 */
+	_debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn);
+
+	write_lock_bh(&rx->call_lock);
+	if (!list_empty(&call->accept_link)) {
+		_debug("unlinking once-pending call %p { e=%lx f=%lx }",
+		       call, call->events, call->flags);
+		ASSERT(!test_bit(RXRPC_CALL_HAS_USERID, &call->flags));
+		list_del_init(&call->accept_link);
+		sk_acceptq_removed(&rx->sk);
+	} else if (test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) {
+		rb_erase(&call->sock_node, &rx->calls);
+		memset(&call->sock_node, 0xdd, sizeof(call->sock_node));
+		clear_bit(RXRPC_CALL_HAS_USERID, &call->flags);
+	}
+	write_unlock_bh(&rx->call_lock);
+
+	/* free up the channel for reuse */
+	spin_lock(&conn->trans->client_lock);
+	write_lock_bh(&conn->lock);
+	write_lock(&call->state_lock);
+
+	if (conn->channels[call->channel] == call)
+		conn->channels[call->channel] = NULL;
+
+	if (conn->out_clientflag && conn->bundle) {
+		conn->avail_calls++;
+		switch (conn->avail_calls) {
+		case 1:
+			list_move_tail(&conn->bundle_link,
+				       &conn->bundle->avail_conns);
+		case 2 ... RXRPC_MAXCALLS - 1:
+			ASSERT(conn->channels[0] == NULL ||
+			       conn->channels[1] == NULL ||
+			       conn->channels[2] == NULL ||
+			       conn->channels[3] == NULL);
+			break;
+		case RXRPC_MAXCALLS:
+			list_move_tail(&conn->bundle_link,
+				       &conn->bundle->unused_conns);
+			ASSERT(conn->channels[0] == NULL &&
+			       conn->channels[1] == NULL &&
+			       conn->channels[2] == NULL &&
+			       conn->channels[3] == NULL);
+			break;
+		default:
+			printk(KERN_ERR "RxRPC: conn->avail_calls=%d\n",
+			       conn->avail_calls);
+			BUG();
+		}
+	}
+
+	spin_unlock(&conn->trans->client_lock);
+
+	if (call->state < RXRPC_CALL_COMPLETE &&
+	    call->state != RXRPC_CALL_CLIENT_FINAL_ACK) {
+		_debug("+++ ABORTING STATE %d +++\n", call->state);
+		call->state = RXRPC_CALL_LOCALLY_ABORTED;
+		call->abort_code = RX_CALL_DEAD;
+		set_bit(RXRPC_CALL_ABORT, &call->events);
+		rxrpc_queue_call(call);
+	}
+	write_unlock(&call->state_lock);
+	write_unlock_bh(&conn->lock);
+
+	/* clean up the Rx queue */
+	if (!skb_queue_empty(&call->rx_queue) ||
+	    !skb_queue_empty(&call->rx_oos_queue)) {
+		struct rxrpc_skb_priv *sp;
+		struct sk_buff *skb;
+
+		_debug("purge Rx queues");
+
+		spin_lock_bh(&call->lock);
+		while ((skb = skb_dequeue(&call->rx_queue)) ||
+		       (skb = skb_dequeue(&call->rx_oos_queue))) {
+			sp = rxrpc_skb(skb);
+			if (sp->call) {
+				ASSERTCMP(sp->call, ==, call);
+				rxrpc_put_call(call);
+				sp->call = NULL;
+			}
+			skb->destructor = NULL;
+			spin_unlock_bh(&call->lock);
+
+			_debug("- zap %s %%%u #%u",
+			       rxrpc_pkts[sp->hdr.type],
+			       ntohl(sp->hdr.serial),
+			       ntohl(sp->hdr.seq));
+			rxrpc_free_skb(skb);
+			spin_lock_bh(&call->lock);
+		}
+		spin_unlock_bh(&call->lock);
+
+		ASSERTCMP(call->state, !=, RXRPC_CALL_COMPLETE);
+	}
+
+	del_timer_sync(&call->resend_timer);
+	del_timer_sync(&call->ack_timer);
+	del_timer_sync(&call->lifetimer);
+	call->deadspan.expires = jiffies + rxrpc_dead_call_timeout * HZ;
+	add_timer(&call->deadspan);
+
+	_leave("");
+}
+
+/*
+ * handle a dead call being ready for reaping
+ */
+static void rxrpc_dead_call_expired(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_enter("{%d}", call->debug_id);
+
+	write_lock_bh(&call->state_lock);
+	call->state = RXRPC_CALL_DEAD;
+	write_unlock_bh(&call->state_lock);
+	rxrpc_put_call(call);
+}
+
+/*
+ * mark a call as to be released, aborting it if it's still in progress
+ * - called with softirqs disabled
+ */
+static void rxrpc_mark_call_released(struct rxrpc_call *call)
+{
+	bool sched;
+
+	write_lock(&call->state_lock);
+	if (call->state < RXRPC_CALL_DEAD) {
+		sched = false;
+		if (call->state < RXRPC_CALL_COMPLETE) {
+			_debug("abort call %p", call);
+			call->state = RXRPC_CALL_LOCALLY_ABORTED;
+			call->abort_code = RX_CALL_DEAD;
+			if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+				sched = true;
+		}
+		if (!test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+			sched = true;
+		if (sched)
+			rxrpc_queue_call(call);
+	}
+	write_unlock(&call->state_lock);
+}
+
+/*
+ * release all the calls associated with a socket
+ */
+void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
+{
+	struct rxrpc_call *call;
+	struct rb_node *p;
+
+	_enter("%p", rx);
+
+	read_lock_bh(&rx->call_lock);
+
+	/* mark all the calls as no longer wanting incoming packets */
+	for (p = rb_first(&rx->calls); p; p = rb_next(p)) {
+		call = rb_entry(p, struct rxrpc_call, sock_node);
+		rxrpc_mark_call_released(call);
+	}
+
+	/* kill the not-yet-accepted incoming calls */
+	list_for_each_entry(call, &rx->secureq, accept_link) {
+		rxrpc_mark_call_released(call);
+	}
+
+	list_for_each_entry(call, &rx->acceptq, accept_link) {
+		rxrpc_mark_call_released(call);
+	}
+
+	read_unlock_bh(&rx->call_lock);
+	_leave("");
+}
+
+/*
+ * release a call
+ */
+void __rxrpc_put_call(struct rxrpc_call *call)
+{
+	ASSERT(call != NULL);
+
+	_enter("%p{u=%d}", call, atomic_read(&call->usage));
+
+	ASSERTCMP(atomic_read(&call->usage), >, 0);
+
+	if (atomic_dec_and_test(&call->usage)) {
+		_debug("call %d dead", call->debug_id);
+		ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
+		rxrpc_queue_work(&call->destroyer);
+	}
+	_leave("");
+}
+
+/*
+ * clean up a call
+ */
+static void rxrpc_cleanup_call(struct rxrpc_call *call)
+{
+	_net("DESTROY CALL %d", call->debug_id);
+
+	ASSERT(call->socket);
+
+	memset(&call->sock_node, 0xcd, sizeof(call->sock_node));
+
+	del_timer_sync(&call->lifetimer);
+	del_timer_sync(&call->deadspan);
+	del_timer_sync(&call->ack_timer);
+	del_timer_sync(&call->resend_timer);
+
+	ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
+	ASSERTCMP(call->events, ==, 0);
+	if (work_pending(&call->processor)) {
+		_debug("defer destroy");
+		rxrpc_queue_work(&call->destroyer);
+		return;
+	}
+
+	if (call->conn) {
+		spin_lock(&call->conn->trans->peer->lock);
+		list_del(&call->error_link);
+		spin_unlock(&call->conn->trans->peer->lock);
+
+		write_lock_bh(&call->conn->lock);
+		rb_erase(&call->conn_node, &call->conn->calls);
+		write_unlock_bh(&call->conn->lock);
+		rxrpc_put_connection(call->conn);
+	}
+
+	if (call->acks_window) {
+		_debug("kill Tx window %d",
+		       CIRC_CNT(call->acks_head, call->acks_tail,
+				call->acks_winsz));
+		smp_mb();
+		while (CIRC_CNT(call->acks_head, call->acks_tail,
+				call->acks_winsz) > 0) {
+			struct rxrpc_skb_priv *sp;
+			unsigned long _skb;
+
+			_skb = call->acks_window[call->acks_tail] & ~1;
+			sp = rxrpc_skb((struct sk_buff *) _skb);
+			_debug("+++ clear Tx %u", ntohl(sp->hdr.seq));
+			rxrpc_free_skb((struct sk_buff *) _skb);
+			call->acks_tail =
+				(call->acks_tail + 1) & (call->acks_winsz - 1);
+		}
+
+		kfree(call->acks_window);
+	}
+
+	rxrpc_free_skb(call->tx_pending);
+
+	rxrpc_purge_queue(&call->rx_queue);
+	ASSERT(skb_queue_empty(&call->rx_oos_queue));
+	sock_put(&call->socket->sk);
+	kmem_cache_free(rxrpc_call_jar, call);
+}
+
+/*
+ * destroy a call
+ */
+static void rxrpc_destroy_call(struct work_struct *work)
+{
+	struct rxrpc_call *call =
+		container_of(work, struct rxrpc_call, destroyer);
+
+	_enter("%p{%d,%d,%p}",
+	       call, atomic_read(&call->usage), call->channel, call->conn);
+
+	ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
+
+	write_lock_bh(&rxrpc_call_lock);
+	list_del_init(&call->link);
+	write_unlock_bh(&rxrpc_call_lock);
+
+	rxrpc_cleanup_call(call);
+	_leave("");
+}
+
+/*
+ * preemptively destroy all the call records from a transport endpoint rather
+ * than waiting for them to time out
+ */
+void __exit rxrpc_destroy_all_calls(void)
+{
+	struct rxrpc_call *call;
+
+	_enter("");
+	write_lock_bh(&rxrpc_call_lock);
+
+	while (!list_empty(&rxrpc_calls)) {
+		call = list_entry(rxrpc_calls.next, struct rxrpc_call, link);
+		_debug("Zapping call %p", call);
+
+		list_del_init(&call->link);
+
+		switch (atomic_read(&call->usage)) {
+		case 0:
+			ASSERTCMP(call->state, ==, RXRPC_CALL_DEAD);
+			break;
+		case 1:
+			if (del_timer_sync(&call->deadspan) != 0 &&
+			    call->state != RXRPC_CALL_DEAD)
+				rxrpc_dead_call_expired((unsigned long) call);
+			if (call->state != RXRPC_CALL_DEAD)
+				break;
+		default:
+			printk(KERN_ERR "RXRPC:"
+			       " Call %p still in use (%d,%d,%s,%lx,%lx)!\n",
+			       call, atomic_read(&call->usage),
+			       atomic_read(&call->ackr_not_idle),
+			       rxrpc_call_states[call->state],
+			       call->flags, call->events);
+			if (!skb_queue_empty(&call->rx_queue))
+				printk(KERN_ERR"RXRPC: Rx queue occupied\n");
+			if (!skb_queue_empty(&call->rx_oos_queue))
+				printk(KERN_ERR"RXRPC: OOS queue occupied\n");
+			break;
+		}
+
+		write_unlock_bh(&rxrpc_call_lock);
+		cond_resched();
+		write_lock_bh(&rxrpc_call_lock);
+	}
+
+	write_unlock_bh(&rxrpc_call_lock);
+	_leave("");
+}
+
+/*
+ * handle call lifetime being exceeded
+ */
+static void rxrpc_call_life_expired(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	if (call->state >= RXRPC_CALL_COMPLETE)
+		return;
+
+	_enter("{%d}", call->debug_id);
+	read_lock_bh(&call->state_lock);
+	if (call->state < RXRPC_CALL_COMPLETE) {
+		set_bit(RXRPC_CALL_LIFE_TIMER, &call->events);
+		rxrpc_queue_call(call);
+	}
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * handle resend timer expiry
+ */
+static void rxrpc_resend_time_expired(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_enter("{%d}", call->debug_id);
+
+	if (call->state >= RXRPC_CALL_COMPLETE)
+		return;
+
+	read_lock_bh(&call->state_lock);
+	clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+	if (call->state < RXRPC_CALL_COMPLETE &&
+	    !test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+		rxrpc_queue_call(call);
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * handle ACK timer expiry
+ */
+static void rxrpc_ack_time_expired(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_enter("{%d}", call->debug_id);
+
+	if (call->state >= RXRPC_CALL_COMPLETE)
+		return;
+
+	read_lock_bh(&call->state_lock);
+	if (call->state < RXRPC_CALL_COMPLETE &&
+	    !test_and_set_bit(RXRPC_CALL_ACK, &call->events))
+		rxrpc_queue_call(call);
+	read_unlock_bh(&call->state_lock);
+}
diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c
new file mode 100644
index 0000000..43cb3e0
--- /dev/null
+++ b/net/rxrpc/ar-connection.c
@@ -0,0 +1,911 @@
+/* RxRPC virtual connection handler
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/crypto.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static void rxrpc_connection_reaper(struct work_struct *work);
+
+LIST_HEAD(rxrpc_connections);
+DEFINE_RWLOCK(rxrpc_connection_lock);
+static unsigned long rxrpc_connection_timeout = 10 * 60;
+static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
+
+/*
+ * allocate a new client connection bundle
+ */
+static struct rxrpc_conn_bundle *rxrpc_alloc_bundle(gfp_t gfp)
+{
+	struct rxrpc_conn_bundle *bundle;
+
+	_enter("");
+
+	bundle = kzalloc(sizeof(struct rxrpc_conn_bundle), gfp);
+	if (bundle) {
+		INIT_LIST_HEAD(&bundle->unused_conns);
+		INIT_LIST_HEAD(&bundle->avail_conns);
+		INIT_LIST_HEAD(&bundle->busy_conns);
+		init_waitqueue_head(&bundle->chanwait);
+		atomic_set(&bundle->usage, 1);
+	}
+
+	_leave(" = %p", bundle);
+	return bundle;
+}
+
+/*
+ * compare bundle parameters with what we're looking for
+ * - return -ve, 0 or +ve
+ */
+static inline
+int rxrpc_cmp_bundle(const struct rxrpc_conn_bundle *bundle,
+		     struct key *key, __be16 service_id)
+{
+	return (bundle->service_id - service_id) ?:
+		((unsigned long) bundle->key - (unsigned long) key);
+}
+
+/*
+ * get bundle of client connections that a client socket can make use of
+ */
+struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *rx,
+					   struct rxrpc_transport *trans,
+					   struct key *key,
+					   __be16 service_id,
+					   gfp_t gfp)
+{
+	struct rxrpc_conn_bundle *bundle, *candidate;
+	struct rb_node *p, *parent, **pp;
+
+	_enter("%p{%x},%x,%hx,",
+	       rx, key_serial(key), trans->debug_id, ntohl(service_id));
+
+	if (rx->trans == trans && rx->bundle) {
+		atomic_inc(&rx->bundle->usage);
+		return rx->bundle;
+	}
+
+	/* search the extant bundles first for one that matches the specified
+	 * user ID */
+	spin_lock(&trans->client_lock);
+
+	p = trans->bundles.rb_node;
+	while (p) {
+		bundle = rb_entry(p, struct rxrpc_conn_bundle, node);
+
+		if (rxrpc_cmp_bundle(bundle, key, service_id) < 0)
+			p = p->rb_left;
+		else if (rxrpc_cmp_bundle(bundle, key, service_id) > 0)
+			p = p->rb_right;
+		else
+			goto found_extant_bundle;
+	}
+
+	spin_unlock(&trans->client_lock);
+
+	/* not yet present - create a candidate for a new record and then
+	 * redo the search */
+	candidate = rxrpc_alloc_bundle(gfp);
+	if (!candidate) {
+		_leave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	candidate->key = key_get(key);
+	candidate->service_id = service_id;
+
+	spin_lock(&trans->client_lock);
+
+	pp = &trans->bundles.rb_node;
+	parent = NULL;
+	while (*pp) {
+		parent = *pp;
+		bundle = rb_entry(parent, struct rxrpc_conn_bundle, node);
+
+		if (rxrpc_cmp_bundle(bundle, key, service_id) < 0)
+			pp = &(*pp)->rb_left;
+		else if (rxrpc_cmp_bundle(bundle, key, service_id) > 0)
+			pp = &(*pp)->rb_right;
+		else
+			goto found_extant_second;
+	}
+
+	/* second search also failed; add the new bundle */
+	bundle = candidate;
+	candidate = NULL;
+
+	rb_link_node(&bundle->node, parent, pp);
+	rb_insert_color(&bundle->node, &trans->bundles);
+	spin_unlock(&trans->client_lock);
+	_net("BUNDLE new on trans %d", trans->debug_id);
+	if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
+		atomic_inc(&bundle->usage);
+		rx->bundle = bundle;
+	}
+	_leave(" = %p [new]", bundle);
+	return bundle;
+
+	/* we found the bundle in the list immediately */
+found_extant_bundle:
+	atomic_inc(&bundle->usage);
+	spin_unlock(&trans->client_lock);
+	_net("BUNDLE old on trans %d", trans->debug_id);
+	if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
+		atomic_inc(&bundle->usage);
+		rx->bundle = bundle;
+	}
+	_leave(" = %p [extant %d]", bundle, atomic_read(&bundle->usage));
+	return bundle;
+
+	/* we found the bundle on the second time through the list */
+found_extant_second:
+	atomic_inc(&bundle->usage);
+	spin_unlock(&trans->client_lock);
+	kfree(candidate);
+	_net("BUNDLE old2 on trans %d", trans->debug_id);
+	if (!rx->bundle && rx->sk.sk_state == RXRPC_CLIENT_CONNECTED) {
+		atomic_inc(&bundle->usage);
+		rx->bundle = bundle;
+	}
+	_leave(" = %p [second %d]", bundle, atomic_read(&bundle->usage));
+	return bundle;
+}
+
+/*
+ * release a bundle
+ */
+void rxrpc_put_bundle(struct rxrpc_transport *trans,
+		      struct rxrpc_conn_bundle *bundle)
+{
+	_enter("%p,%p{%d}",trans, bundle, atomic_read(&bundle->usage));
+
+	if (atomic_dec_and_lock(&bundle->usage, &trans->client_lock)) {
+		_debug("Destroy bundle");
+		rb_erase(&bundle->node, &trans->bundles);
+		spin_unlock(&trans->client_lock);
+		ASSERT(list_empty(&bundle->unused_conns));
+		ASSERT(list_empty(&bundle->avail_conns));
+		ASSERT(list_empty(&bundle->busy_conns));
+		ASSERTCMP(bundle->num_conns, ==, 0);
+		key_put(bundle->key);
+		kfree(bundle);
+	}
+
+	_leave("");
+}
+
+/*
+ * allocate a new connection
+ */
+static struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
+{
+	struct rxrpc_connection *conn;
+
+	_enter("");
+
+	conn = kzalloc(sizeof(struct rxrpc_connection), gfp);
+	if (conn) {
+		INIT_WORK(&conn->processor, &rxrpc_process_connection);
+		INIT_LIST_HEAD(&conn->bundle_link);
+		conn->calls = RB_ROOT;
+		skb_queue_head_init(&conn->rx_queue);
+		rwlock_init(&conn->lock);
+		spin_lock_init(&conn->state_lock);
+		atomic_set(&conn->usage, 1);
+		conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
+		conn->avail_calls = RXRPC_MAXCALLS;
+		conn->size_align = 4;
+		conn->header_size = sizeof(struct rxrpc_header);
+	}
+
+	_leave(" = %p{%d}", conn, conn->debug_id);
+	return conn;
+}
+
+/*
+ * assign a connection ID to a connection and add it to the transport's
+ * connection lookup tree
+ * - called with transport client lock held
+ */
+static void rxrpc_assign_connection_id(struct rxrpc_connection *conn)
+{
+	struct rxrpc_connection *xconn;
+	struct rb_node *parent, **p;
+	__be32 epoch;
+	u32 real_conn_id;
+
+	_enter("");
+
+	epoch = conn->epoch;
+
+	write_lock_bh(&conn->trans->conn_lock);
+
+	conn->trans->conn_idcounter += RXRPC_CID_INC;
+	if (conn->trans->conn_idcounter < RXRPC_CID_INC)
+		conn->trans->conn_idcounter = RXRPC_CID_INC;
+	real_conn_id = conn->trans->conn_idcounter;
+
+attempt_insertion:
+	parent = NULL;
+	p = &conn->trans->client_conns.rb_node;
+
+	while (*p) {
+		parent = *p;
+		xconn = rb_entry(parent, struct rxrpc_connection, node);
+
+		if (epoch < xconn->epoch)
+			p = &(*p)->rb_left;
+		else if (epoch > xconn->epoch)
+			p = &(*p)->rb_right;
+		else if (real_conn_id < xconn->real_conn_id)
+			p = &(*p)->rb_left;
+		else if (real_conn_id > xconn->real_conn_id)
+			p = &(*p)->rb_right;
+		else
+			goto id_exists;
+	}
+
+	/* we've found a suitable hole - arrange for this connection to occupy
+	 * it */
+	rb_link_node(&conn->node, parent, p);
+	rb_insert_color(&conn->node, &conn->trans->client_conns);
+
+	conn->real_conn_id = real_conn_id;
+	conn->cid = htonl(real_conn_id);
+	write_unlock_bh(&conn->trans->conn_lock);
+	_leave(" [CONNID %x CID %x]", real_conn_id, ntohl(conn->cid));
+	return;
+
+	/* we found a connection with the proposed ID - walk the tree from that
+	 * point looking for the next unused ID */
+id_exists:
+	for (;;) {
+		real_conn_id += RXRPC_CID_INC;
+		if (real_conn_id < RXRPC_CID_INC) {
+			real_conn_id = RXRPC_CID_INC;
+			conn->trans->conn_idcounter = real_conn_id;
+			goto attempt_insertion;
+		}
+
+		parent = rb_next(parent);
+		if (!parent)
+			goto attempt_insertion;
+
+		xconn = rb_entry(parent, struct rxrpc_connection, node);
+		if (epoch < xconn->epoch ||
+		    real_conn_id < xconn->real_conn_id)
+			goto attempt_insertion;
+	}
+}
+
+/*
+ * add a call to a connection's call-by-ID tree
+ */
+static void rxrpc_add_call_ID_to_conn(struct rxrpc_connection *conn,
+				      struct rxrpc_call *call)
+{
+	struct rxrpc_call *xcall;
+	struct rb_node *parent, **p;
+	__be32 call_id;
+
+	write_lock_bh(&conn->lock);
+
+	call_id = call->call_id;
+	p = &conn->calls.rb_node;
+	parent = NULL;
+	while (*p) {
+		parent = *p;
+		xcall = rb_entry(parent, struct rxrpc_call, conn_node);
+
+		if (call_id < xcall->call_id)
+			p = &(*p)->rb_left;
+		else if (call_id > xcall->call_id)
+			p = &(*p)->rb_right;
+		else
+			BUG();
+	}
+
+	rb_link_node(&call->conn_node, parent, p);
+	rb_insert_color(&call->conn_node, &conn->calls);
+
+	write_unlock_bh(&conn->lock);
+}
+
+/*
+ * connect a call on an exclusive connection
+ */
+static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,
+				   struct rxrpc_transport *trans,
+				   __be16 service_id,
+				   struct rxrpc_call *call,
+				   gfp_t gfp)
+{
+	struct rxrpc_connection *conn;
+	int chan, ret;
+
+	_enter("");
+
+	conn = rx->conn;
+	if (!conn) {
+		/* not yet present - create a candidate for a new connection
+		 * and then redo the check */
+		conn = rxrpc_alloc_connection(gfp);
+		if (IS_ERR(conn)) {
+			_leave(" = %ld", PTR_ERR(conn));
+			return PTR_ERR(conn);
+		}
+
+		conn->trans = trans;
+		conn->bundle = NULL;
+		conn->service_id = service_id;
+		conn->epoch = rxrpc_epoch;
+		conn->in_clientflag = 0;
+		conn->out_clientflag = RXRPC_CLIENT_INITIATED;
+		conn->cid = 0;
+		conn->state = RXRPC_CONN_CLIENT;
+		conn->avail_calls = RXRPC_MAXCALLS - 1;
+		conn->security_level = rx->min_sec_level;
+		conn->key = key_get(rx->key);
+
+		ret = rxrpc_init_client_conn_security(conn);
+		if (ret < 0) {
+			key_put(conn->key);
+			kfree(conn);
+			_leave(" = %d [key]", ret);
+			return ret;
+		}
+
+		write_lock_bh(&rxrpc_connection_lock);
+		list_add_tail(&conn->link, &rxrpc_connections);
+		write_unlock_bh(&rxrpc_connection_lock);
+
+		spin_lock(&trans->client_lock);
+		atomic_inc(&trans->usage);
+
+		_net("CONNECT EXCL new %d on TRANS %d",
+		     conn->debug_id, conn->trans->debug_id);
+
+		rxrpc_assign_connection_id(conn);
+		rx->conn = conn;
+	}
+
+	/* we've got a connection with a free channel and we can now attach the
+	 * call to it
+	 * - we're holding the transport's client lock
+	 * - we're holding a reference on the connection
+	 */
+	for (chan = 0; chan < RXRPC_MAXCALLS; chan++)
+		if (!conn->channels[chan])
+			goto found_channel;
+	goto no_free_channels;
+
+found_channel:
+	atomic_inc(&conn->usage);
+	conn->channels[chan] = call;
+	call->conn = conn;
+	call->channel = chan;
+	call->cid = conn->cid | htonl(chan);
+	call->call_id = htonl(++conn->call_counter);
+
+	_net("CONNECT client on conn %d chan %d as call %x",
+	     conn->debug_id, chan, ntohl(call->call_id));
+
+	spin_unlock(&trans->client_lock);
+
+	rxrpc_add_call_ID_to_conn(conn, call);
+	_leave(" = 0");
+	return 0;
+
+no_free_channels:
+	spin_unlock(&trans->client_lock);
+	_leave(" = -ENOSR");
+	return -ENOSR;
+}
+
+/*
+ * find a connection for a call
+ * - called in process context with IRQs enabled
+ */
+int rxrpc_connect_call(struct rxrpc_sock *rx,
+		       struct rxrpc_transport *trans,
+		       struct rxrpc_conn_bundle *bundle,
+		       struct rxrpc_call *call,
+		       gfp_t gfp)
+{
+	struct rxrpc_connection *conn, *candidate;
+	int chan, ret;
+
+	DECLARE_WAITQUEUE(myself, current);
+
+	_enter("%p,%lx,", rx, call->user_call_ID);
+
+	if (test_bit(RXRPC_SOCK_EXCLUSIVE_CONN, &rx->flags))
+		return rxrpc_connect_exclusive(rx, trans, bundle->service_id,
+					       call, gfp);
+
+	spin_lock(&trans->client_lock);
+	for (;;) {
+		/* see if the bundle has a call slot available */
+		if (!list_empty(&bundle->avail_conns)) {
+			_debug("avail");
+			conn = list_entry(bundle->avail_conns.next,
+					  struct rxrpc_connection,
+					  bundle_link);
+			if (--conn->avail_calls == 0)
+				list_move(&conn->bundle_link,
+					  &bundle->busy_conns);
+			ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS);
+			ASSERT(conn->channels[0] == NULL ||
+			       conn->channels[1] == NULL ||
+			       conn->channels[2] == NULL ||
+			       conn->channels[3] == NULL);
+			atomic_inc(&conn->usage);
+			break;
+		}
+
+		if (!list_empty(&bundle->unused_conns)) {
+			_debug("unused");
+			conn = list_entry(bundle->unused_conns.next,
+					  struct rxrpc_connection,
+					  bundle_link);
+			ASSERTCMP(conn->avail_calls, ==, RXRPC_MAXCALLS);
+			conn->avail_calls = RXRPC_MAXCALLS - 1;
+			ASSERT(conn->channels[0] == NULL &&
+			       conn->channels[1] == NULL &&
+			       conn->channels[2] == NULL &&
+			       conn->channels[3] == NULL);
+			atomic_inc(&conn->usage);
+			list_move(&conn->bundle_link, &bundle->avail_conns);
+			break;
+		}
+
+		/* need to allocate a new connection */
+		_debug("get new conn [%d]", bundle->num_conns);
+
+		spin_unlock(&trans->client_lock);
+
+		if (signal_pending(current))
+			goto interrupted;
+
+		if (bundle->num_conns >= 20) {
+			_debug("too many conns");
+
+			if (!(gfp & __GFP_WAIT)) {
+				_leave(" = -EAGAIN");
+				return -EAGAIN;
+			}
+
+			add_wait_queue(&bundle->chanwait, &myself);
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (bundle->num_conns < 20 ||
+				    !list_empty(&bundle->unused_conns) ||
+				    !list_empty(&bundle->avail_conns))
+					break;
+				if (signal_pending(current))
+					goto interrupted_dequeue;
+				schedule();
+			}
+			remove_wait_queue(&bundle->chanwait, &myself);
+			__set_current_state(TASK_RUNNING);
+			spin_lock(&trans->client_lock);
+			continue;
+		}
+
+		/* not yet present - create a candidate for a new connection and then
+		 * redo the check */
+		candidate = rxrpc_alloc_connection(gfp);
+		if (IS_ERR(candidate)) {
+			_leave(" = %ld", PTR_ERR(candidate));
+			return PTR_ERR(candidate);
+		}
+
+		candidate->trans = trans;
+		candidate->bundle = bundle;
+		candidate->service_id = bundle->service_id;
+		candidate->epoch = rxrpc_epoch;
+		candidate->in_clientflag = 0;
+		candidate->out_clientflag = RXRPC_CLIENT_INITIATED;
+		candidate->cid = 0;
+		candidate->state = RXRPC_CONN_CLIENT;
+		candidate->avail_calls = RXRPC_MAXCALLS;
+		candidate->security_level = rx->min_sec_level;
+		candidate->key = key_get(bundle->key);
+
+		ret = rxrpc_init_client_conn_security(candidate);
+		if (ret < 0) {
+			key_put(candidate->key);
+			kfree(candidate);
+			_leave(" = %d [key]", ret);
+			return ret;
+		}
+
+		write_lock_bh(&rxrpc_connection_lock);
+		list_add_tail(&candidate->link, &rxrpc_connections);
+		write_unlock_bh(&rxrpc_connection_lock);
+
+		spin_lock(&trans->client_lock);
+
+		list_add(&candidate->bundle_link, &bundle->unused_conns);
+		bundle->num_conns++;
+		atomic_inc(&bundle->usage);
+		atomic_inc(&trans->usage);
+
+		_net("CONNECT new %d on TRANS %d",
+		     candidate->debug_id, candidate->trans->debug_id);
+
+		rxrpc_assign_connection_id(candidate);
+		if (candidate->security)
+			candidate->security->prime_packet_security(candidate);
+
+		/* leave the candidate lurking in zombie mode attached to the
+		 * bundle until we're ready for it */
+		rxrpc_put_connection(candidate);
+		candidate = NULL;
+	}
+
+	/* we've got a connection with a free channel and we can now attach the
+	 * call to it
+	 * - we're holding the transport's client lock
+	 * - we're holding a reference on the connection
+	 * - we're holding a reference on the bundle
+	 */
+	for (chan = 0; chan < RXRPC_MAXCALLS; chan++)
+		if (!conn->channels[chan])
+			goto found_channel;
+	ASSERT(conn->channels[0] == NULL ||
+	       conn->channels[1] == NULL ||
+	       conn->channels[2] == NULL ||
+	       conn->channels[3] == NULL);
+	BUG();
+
+found_channel:
+	conn->channels[chan] = call;
+	call->conn = conn;
+	call->channel = chan;
+	call->cid = conn->cid | htonl(chan);
+	call->call_id = htonl(++conn->call_counter);
+
+	_net("CONNECT client on conn %d chan %d as call %x",
+	     conn->debug_id, chan, ntohl(call->call_id));
+
+	ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS);
+	spin_unlock(&trans->client_lock);
+
+	rxrpc_add_call_ID_to_conn(conn, call);
+
+	_leave(" = 0");
+	return 0;
+
+interrupted_dequeue:
+	remove_wait_queue(&bundle->chanwait, &myself);
+	__set_current_state(TASK_RUNNING);
+interrupted:
+	_leave(" = -ERESTARTSYS");
+	return -ERESTARTSYS;
+}
+
+/*
+ * get a record of an incoming connection
+ */
+struct rxrpc_connection *
+rxrpc_incoming_connection(struct rxrpc_transport *trans,
+			  struct rxrpc_header *hdr,
+			  gfp_t gfp)
+{
+	struct rxrpc_connection *conn, *candidate = NULL;
+	struct rb_node *p, **pp;
+	const char *new = "old";
+	__be32 epoch;
+	u32 conn_id;
+
+	_enter("");
+
+	ASSERT(hdr->flags & RXRPC_CLIENT_INITIATED);
+
+	epoch = hdr->epoch;
+	conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
+
+	/* search the connection list first */
+	read_lock_bh(&trans->conn_lock);
+
+	p = trans->server_conns.rb_node;
+	while (p) {
+		conn = rb_entry(p, struct rxrpc_connection, node);
+
+		_debug("maybe %x", conn->real_conn_id);
+
+		if (epoch < conn->epoch)
+			p = p->rb_left;
+		else if (epoch > conn->epoch)
+			p = p->rb_right;
+		else if (conn_id < conn->real_conn_id)
+			p = p->rb_left;
+		else if (conn_id > conn->real_conn_id)
+			p = p->rb_right;
+		else
+			goto found_extant_connection;
+	}
+	read_unlock_bh(&trans->conn_lock);
+
+	/* not yet present - create a candidate for a new record and then
+	 * redo the search */
+	candidate = rxrpc_alloc_connection(gfp);
+	if (!candidate) {
+		_leave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	candidate->trans = trans;
+	candidate->epoch = hdr->epoch;
+	candidate->cid = hdr->cid & __constant_cpu_to_be32(RXRPC_CIDMASK);
+	candidate->service_id = hdr->serviceId;
+	candidate->security_ix = hdr->securityIndex;
+	candidate->in_clientflag = RXRPC_CLIENT_INITIATED;
+	candidate->out_clientflag = 0;
+	candidate->real_conn_id = conn_id;
+	candidate->state = RXRPC_CONN_SERVER;
+	if (candidate->service_id)
+		candidate->state = RXRPC_CONN_SERVER_UNSECURED;
+
+	write_lock_bh(&trans->conn_lock);
+
+	pp = &trans->server_conns.rb_node;
+	p = NULL;
+	while (*pp) {
+		p = *pp;
+		conn = rb_entry(p, struct rxrpc_connection, node);
+
+		if (epoch < conn->epoch)
+			pp = &(*pp)->rb_left;
+		else if (epoch > conn->epoch)
+			pp = &(*pp)->rb_right;
+		else if (conn_id < conn->real_conn_id)
+			pp = &(*pp)->rb_left;
+		else if (conn_id > conn->real_conn_id)
+			pp = &(*pp)->rb_right;
+		else
+			goto found_extant_second;
+	}
+
+	/* we can now add the new candidate to the list */
+	conn = candidate;
+	candidate = NULL;
+	rb_link_node(&conn->node, p, pp);
+	rb_insert_color(&conn->node, &trans->server_conns);
+	atomic_inc(&conn->trans->usage);
+
+	write_unlock_bh(&trans->conn_lock);
+
+	write_lock_bh(&rxrpc_connection_lock);
+	list_add_tail(&conn->link, &rxrpc_connections);
+	write_unlock_bh(&rxrpc_connection_lock);
+
+	new = "new";
+
+success:
+	_net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->real_conn_id);
+
+	_leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
+	return conn;
+
+	/* we found the connection in the list immediately */
+found_extant_connection:
+	if (hdr->securityIndex != conn->security_ix) {
+		read_unlock_bh(&trans->conn_lock);
+		goto security_mismatch;
+	}
+	atomic_inc(&conn->usage);
+	read_unlock_bh(&trans->conn_lock);
+	goto success;
+
+	/* we found the connection on the second time through the list */
+found_extant_second:
+	if (hdr->securityIndex != conn->security_ix) {
+		write_unlock_bh(&trans->conn_lock);
+		goto security_mismatch;
+	}
+	atomic_inc(&conn->usage);
+	write_unlock_bh(&trans->conn_lock);
+	kfree(candidate);
+	goto success;
+
+security_mismatch:
+	kfree(candidate);
+	_leave(" = -EKEYREJECTED");
+	return ERR_PTR(-EKEYREJECTED);
+}
+
+/*
+ * find a connection based on transport and RxRPC connection ID for an incoming
+ * packet
+ */
+struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *trans,
+					       struct rxrpc_header *hdr)
+{
+	struct rxrpc_connection *conn;
+	struct rb_node *p;
+	__be32 epoch;
+	u32 conn_id;
+
+	_enter(",{%x,%x}", ntohl(hdr->cid), hdr->flags);
+
+	read_lock_bh(&trans->conn_lock);
+
+	conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
+	epoch = hdr->epoch;
+
+	if (hdr->flags & RXRPC_CLIENT_INITIATED)
+		p = trans->server_conns.rb_node;
+	else
+		p = trans->client_conns.rb_node;
+
+	while (p) {
+		conn = rb_entry(p, struct rxrpc_connection, node);
+
+		_debug("maybe %x", conn->real_conn_id);
+
+		if (epoch < conn->epoch)
+			p = p->rb_left;
+		else if (epoch > conn->epoch)
+			p = p->rb_right;
+		else if (conn_id < conn->real_conn_id)
+			p = p->rb_left;
+		else if (conn_id > conn->real_conn_id)
+			p = p->rb_right;
+		else
+			goto found;
+	}
+
+	read_unlock_bh(&trans->conn_lock);
+	_leave(" = NULL");
+	return NULL;
+
+found:
+	atomic_inc(&conn->usage);
+	read_unlock_bh(&trans->conn_lock);
+	_leave(" = %p", conn);
+	return conn;
+}
+
+/*
+ * release a virtual connection
+ */
+void rxrpc_put_connection(struct rxrpc_connection *conn)
+{
+	_enter("%p{u=%d,d=%d}",
+	       conn, atomic_read(&conn->usage), conn->debug_id);
+
+	ASSERTCMP(atomic_read(&conn->usage), >, 0);
+
+	conn->put_time = xtime.tv_sec;
+	if (atomic_dec_and_test(&conn->usage)) {
+		_debug("zombie");
+		rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
+	}
+
+	_leave("");
+}
+
+/*
+ * destroy a virtual connection
+ */
+static void rxrpc_destroy_connection(struct rxrpc_connection *conn)
+{
+	_enter("%p{%d}", conn, atomic_read(&conn->usage));
+
+	ASSERTCMP(atomic_read(&conn->usage), ==, 0);
+
+	_net("DESTROY CONN %d", conn->debug_id);
+
+	if (conn->bundle)
+		rxrpc_put_bundle(conn->trans, conn->bundle);
+
+	ASSERT(RB_EMPTY_ROOT(&conn->calls));
+	rxrpc_purge_queue(&conn->rx_queue);
+
+	rxrpc_clear_conn_security(conn);
+	rxrpc_put_transport(conn->trans);
+	kfree(conn);
+	_leave("");
+}
+
+/*
+ * reap dead connections
+ */
+void rxrpc_connection_reaper(struct work_struct *work)
+{
+	struct rxrpc_connection *conn, *_p;
+	unsigned long now, earliest, reap_time;
+
+	LIST_HEAD(graveyard);
+
+	_enter("");
+
+	now = xtime.tv_sec;
+	earliest = ULONG_MAX;
+
+	write_lock_bh(&rxrpc_connection_lock);
+	list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) {
+		_debug("reap CONN %d { u=%d,t=%ld }",
+		       conn->debug_id, atomic_read(&conn->usage),
+		       (long) now - (long) conn->put_time);
+
+		if (likely(atomic_read(&conn->usage) > 0))
+			continue;
+
+		spin_lock(&conn->trans->client_lock);
+		write_lock(&conn->trans->conn_lock);
+		reap_time = conn->put_time + rxrpc_connection_timeout;
+
+		if (atomic_read(&conn->usage) > 0) {
+			;
+		} else if (reap_time <= now) {
+			list_move_tail(&conn->link, &graveyard);
+			if (conn->out_clientflag)
+				rb_erase(&conn->node,
+					 &conn->trans->client_conns);
+			else
+				rb_erase(&conn->node,
+					 &conn->trans->server_conns);
+			if (conn->bundle) {
+				list_del_init(&conn->bundle_link);
+				conn->bundle->num_conns--;
+			}
+
+		} else if (reap_time < earliest) {
+			earliest = reap_time;
+		}
+
+		write_unlock(&conn->trans->conn_lock);
+		spin_unlock(&conn->trans->client_lock);
+	}
+	write_unlock_bh(&rxrpc_connection_lock);
+
+	if (earliest != ULONG_MAX) {
+		_debug("reschedule reaper %ld", (long) earliest - now);
+		ASSERTCMP(earliest, >, now);
+		rxrpc_queue_delayed_work(&rxrpc_connection_reap,
+					 (earliest - now) * HZ);
+	}
+
+	/* then destroy all those pulled out */
+	while (!list_empty(&graveyard)) {
+		conn = list_entry(graveyard.next, struct rxrpc_connection,
+				  link);
+		list_del_init(&conn->link);
+
+		ASSERTCMP(atomic_read(&conn->usage), ==, 0);
+		rxrpc_destroy_connection(conn);
+	}
+
+	_leave("");
+}
+
+/*
+ * preemptively destroy all the connection records rather than waiting for them
+ * to time out
+ */
+void __exit rxrpc_destroy_all_connections(void)
+{
+	_enter("");
+
+	rxrpc_connection_timeout = 0;
+	cancel_delayed_work(&rxrpc_connection_reap);
+	rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
+
+	_leave("");
+}
diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c
new file mode 100644
index 0000000..1ada43d
--- /dev/null
+++ b/net/rxrpc/ar-connevent.c
@@ -0,0 +1,403 @@
+/* connection-level event handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/errqueue.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <net/ip.h>
+#include "ar-internal.h"
+
+/*
+ * pass a connection-level abort onto all calls on that connection
+ */
+static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state,
+			      u32 abort_code)
+{
+	struct rxrpc_call *call;
+	struct rb_node *p;
+
+	_enter("{%d},%x", conn->debug_id, abort_code);
+
+	read_lock_bh(&conn->lock);
+
+	for (p = rb_first(&conn->calls); p; p = rb_next(p)) {
+		call = rb_entry(p, struct rxrpc_call, conn_node);
+		write_lock(&call->state_lock);
+		if (call->state <= RXRPC_CALL_COMPLETE) {
+			call->state = state;
+			call->abort_code = abort_code;
+			if (state == RXRPC_CALL_LOCALLY_ABORTED)
+				set_bit(RXRPC_CALL_CONN_ABORT, &call->events);
+			else
+				set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+			rxrpc_queue_call(call);
+		}
+		write_unlock(&call->state_lock);
+	}
+
+	read_unlock_bh(&conn->lock);
+	_leave("");
+}
+
+/*
+ * generate a connection-level abort
+ */
+static int rxrpc_abort_connection(struct rxrpc_connection *conn,
+				  u32 error, u32 abort_code)
+{
+	struct rxrpc_header hdr;
+	struct msghdr msg;
+	struct kvec iov[2];
+	__be32 word;
+	size_t len;
+	int ret;
+
+	_enter("%d,,%u,%u", conn->debug_id, error, abort_code);
+
+	/* generate a connection-level abort */
+	spin_lock_bh(&conn->state_lock);
+	if (conn->state < RXRPC_CONN_REMOTELY_ABORTED) {
+		conn->state = RXRPC_CONN_LOCALLY_ABORTED;
+		conn->error = error;
+		spin_unlock_bh(&conn->state_lock);
+	} else {
+		spin_unlock_bh(&conn->state_lock);
+		_leave(" = 0 [already dead]");
+		return 0;
+	}
+
+	rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, abort_code);
+
+	msg.msg_name	= &conn->trans->peer->srx.transport.sin;
+	msg.msg_namelen	= sizeof(conn->trans->peer->srx.transport.sin);
+	msg.msg_control	= NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags	= 0;
+
+	hdr.epoch	= conn->epoch;
+	hdr.cid		= conn->cid;
+	hdr.callNumber	= 0;
+	hdr.seq		= 0;
+	hdr.type	= RXRPC_PACKET_TYPE_ABORT;
+	hdr.flags	= conn->out_clientflag;
+	hdr.userStatus	= 0;
+	hdr.securityIndex = conn->security_ix;
+	hdr._rsvd	= 0;
+	hdr.serviceId	= conn->service_id;
+
+	word = htonl(abort_code);
+
+	iov[0].iov_base	= &hdr;
+	iov[0].iov_len	= sizeof(hdr);
+	iov[1].iov_base	= &word;
+	iov[1].iov_len	= sizeof(word);
+
+	len = iov[0].iov_len + iov[1].iov_len;
+
+	hdr.serial = htonl(atomic_inc_return(&conn->serial));
+	_proto("Tx CONN ABORT %%%u { %d }", ntohl(hdr.serial), abort_code);
+
+	ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 2, len);
+	if (ret < 0) {
+		_debug("sendmsg failed: %d", ret);
+		return -EAGAIN;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * mark a call as being on a now-secured channel
+ * - must be called with softirqs disabled
+ */
+void rxrpc_call_is_secure(struct rxrpc_call *call)
+{
+	_enter("%p", call);
+	if (call) {
+		read_lock(&call->state_lock);
+		if (call->state < RXRPC_CALL_COMPLETE &&
+		    !test_and_set_bit(RXRPC_CALL_SECURED, &call->events))
+			rxrpc_queue_call(call);
+		read_unlock(&call->state_lock);
+	}
+}
+
+/*
+ * connection-level Rx packet processor
+ */
+static int rxrpc_process_event(struct rxrpc_connection *conn,
+			       struct sk_buff *skb,
+			       u32 *_abort_code)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	__be32 tmp;
+	u32 serial;
+	int loop, ret;
+
+	if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED)
+		return -ECONNABORTED;
+
+	serial = ntohl(sp->hdr.serial);
+
+	switch (sp->hdr.type) {
+	case RXRPC_PACKET_TYPE_ABORT:
+		if (skb_copy_bits(skb, 0, &tmp, sizeof(tmp)) < 0)
+			return -EPROTO;
+		_proto("Rx ABORT %%%u { ac=%d }", serial, ntohl(tmp));
+
+		conn->state = RXRPC_CONN_REMOTELY_ABORTED;
+		rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
+				  ntohl(tmp));
+		return -ECONNABORTED;
+
+	case RXRPC_PACKET_TYPE_CHALLENGE:
+		if (conn->security)
+			return conn->security->respond_to_challenge(
+				conn, skb, _abort_code);
+		return -EPROTO;
+
+	case RXRPC_PACKET_TYPE_RESPONSE:
+		if (!conn->security)
+			return -EPROTO;
+
+		ret = conn->security->verify_response(conn, skb, _abort_code);
+		if (ret < 0)
+			return ret;
+
+		ret = conn->security->init_connection_security(conn);
+		if (ret < 0)
+			return ret;
+
+		conn->security->prime_packet_security(conn);
+		read_lock_bh(&conn->lock);
+		spin_lock(&conn->state_lock);
+
+		if (conn->state == RXRPC_CONN_SERVER_CHALLENGING) {
+			conn->state = RXRPC_CONN_SERVER;
+			for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
+				rxrpc_call_is_secure(conn->channels[loop]);
+		}
+
+		spin_unlock(&conn->state_lock);
+		read_unlock_bh(&conn->lock);
+		return 0;
+
+	default:
+		return -EPROTO;
+	}
+}
+
+/*
+ * set up security and issue a challenge
+ */
+static void rxrpc_secure_connection(struct rxrpc_connection *conn)
+{
+	u32 abort_code;
+	int ret;
+
+	_enter("{%d}", conn->debug_id);
+
+	ASSERT(conn->security_ix != 0);
+
+	if (!conn->key) {
+		_debug("set up security");
+		ret = rxrpc_init_server_conn_security(conn);
+		switch (ret) {
+		case 0:
+			break;
+		case -ENOENT:
+			abort_code = RX_CALL_DEAD;
+			goto abort;
+		default:
+			abort_code = RXKADNOAUTH;
+			goto abort;
+		}
+	}
+
+	ASSERT(conn->security != NULL);
+
+	if (conn->security->issue_challenge(conn) < 0) {
+		abort_code = RX_CALL_DEAD;
+		ret = -ENOMEM;
+		goto abort;
+	}
+
+	_leave("");
+	return;
+
+abort:
+	_debug("abort %d, %d", ret, abort_code);
+	rxrpc_abort_connection(conn, -ret, abort_code);
+	_leave(" [aborted]");
+}
+
+/*
+ * connection-level event processor
+ */
+void rxrpc_process_connection(struct work_struct *work)
+{
+	struct rxrpc_connection *conn =
+		container_of(work, struct rxrpc_connection, processor);
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *skb;
+	u32 abort_code = RX_PROTOCOL_ERROR;
+	int ret;
+
+	_enter("{%d}", conn->debug_id);
+
+	atomic_inc(&conn->usage);
+
+	if (test_and_clear_bit(RXRPC_CONN_CHALLENGE, &conn->events)) {
+		rxrpc_secure_connection(conn);
+		rxrpc_put_connection(conn);
+	}
+
+	/* go through the conn-level event packets, releasing the ref on this
+	 * connection that each one has when we've finished with it */
+	while ((skb = skb_dequeue(&conn->rx_queue))) {
+		sp = rxrpc_skb(skb);
+
+		ret = rxrpc_process_event(conn, skb, &abort_code);
+		switch (ret) {
+		case -EPROTO:
+		case -EKEYEXPIRED:
+		case -EKEYREJECTED:
+			goto protocol_error;
+		case -EAGAIN:
+			goto requeue_and_leave;
+		case -ECONNABORTED:
+		default:
+			rxrpc_put_connection(conn);
+			rxrpc_free_skb(skb);
+			break;
+		}
+	}
+
+out:
+	rxrpc_put_connection(conn);
+	_leave("");
+	return;
+
+requeue_and_leave:
+	skb_queue_head(&conn->rx_queue, skb);
+	goto out;
+
+protocol_error:
+	if (rxrpc_abort_connection(conn, -ret, abort_code) < 0)
+		goto requeue_and_leave;
+	rxrpc_put_connection(conn);
+	rxrpc_free_skb(skb);
+	_leave(" [EPROTO]");
+	goto out;
+}
+
+/*
+ * put a packet up for transport-level abort
+ */
+void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb)
+{
+	CHECK_SLAB_OKAY(&local->usage);
+
+	if (!atomic_inc_not_zero(&local->usage)) {
+		printk("resurrected on reject\n");
+		BUG();
+	}
+
+	skb_queue_tail(&local->reject_queue, skb);
+	rxrpc_queue_work(&local->rejecter);
+}
+
+/*
+ * reject packets through the local endpoint
+ */
+void rxrpc_reject_packets(struct work_struct *work)
+{
+	union {
+		struct sockaddr sa;
+		struct sockaddr_in sin;
+	} sa;
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_header hdr;
+	struct rxrpc_local *local;
+	struct sk_buff *skb;
+	struct msghdr msg;
+	struct kvec iov[2];
+	size_t size;
+	__be32 code;
+
+	local = container_of(work, struct rxrpc_local, rejecter);
+	rxrpc_get_local(local);
+
+	_enter("%d", local->debug_id);
+
+	iov[0].iov_base = &hdr;
+	iov[0].iov_len = sizeof(hdr);
+	iov[1].iov_base = &code;
+	iov[1].iov_len = sizeof(code);
+	size = sizeof(hdr) + sizeof(code);
+
+	msg.msg_name = &sa;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa.sa_family = local->srx.transport.family;
+	switch (sa.sa.sa_family) {
+	case AF_INET:
+		msg.msg_namelen = sizeof(sa.sin);
+		break;
+	default:
+		msg.msg_namelen = 0;
+		break;
+	}
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.type = RXRPC_PACKET_TYPE_ABORT;
+
+	while ((skb = skb_dequeue(&local->reject_queue))) {
+		sp = rxrpc_skb(skb);
+		switch (sa.sa.sa_family) {
+		case AF_INET:
+			sa.sin.sin_port = udp_hdr(skb)->source;
+			sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
+			code = htonl(skb->priority);
+
+			hdr.epoch = sp->hdr.epoch;
+			hdr.cid = sp->hdr.cid;
+			hdr.callNumber = sp->hdr.callNumber;
+			hdr.serviceId = sp->hdr.serviceId;
+			hdr.flags = sp->hdr.flags;
+			hdr.flags ^= RXRPC_CLIENT_INITIATED;
+			hdr.flags &= RXRPC_CLIENT_INITIATED;
+
+			kernel_sendmsg(local->socket, &msg, iov, 2, size);
+			break;
+
+		default:
+			break;
+		}
+
+		rxrpc_free_skb(skb);
+		rxrpc_put_local(local);
+	}
+
+	rxrpc_put_local(local);
+	_leave("");
+}
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
new file mode 100644
index 0000000..6cb3e88
--- /dev/null
+++ b/net/rxrpc/ar-error.c
@@ -0,0 +1,255 @@
+/* Error message handling (ICMP)
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/errqueue.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <net/ip.h>
+#include "ar-internal.h"
+
+/*
+ * handle an error received on the local endpoint
+ */
+void rxrpc_UDP_error_report(struct sock *sk)
+{
+	struct sock_exterr_skb *serr;
+	struct rxrpc_transport *trans;
+	struct rxrpc_local *local = sk->sk_user_data;
+	struct rxrpc_peer *peer;
+	struct sk_buff *skb;
+	__be32 addr;
+	__be16 port;
+
+	_enter("%p{%d}", sk, local->debug_id);
+
+	skb = skb_dequeue(&sk->sk_error_queue);
+	if (!skb) {
+		_leave("UDP socket errqueue empty");
+		return;
+	}
+
+	rxrpc_new_skb(skb);
+
+	serr = SKB_EXT_ERR(skb);
+	addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset);
+	port = serr->port;
+
+	_net("Rx UDP Error from "NIPQUAD_FMT":%hu",
+	     NIPQUAD(addr), ntohs(port));
+	_debug("Msg l:%d d:%d", skb->len, skb->data_len);
+
+	peer = rxrpc_find_peer(local, addr, port);
+	if (IS_ERR(peer)) {
+		rxrpc_free_skb(skb);
+		_leave(" [no peer]");
+		return;
+	}
+
+	trans = rxrpc_find_transport(local, peer);
+	if (!trans) {
+		rxrpc_put_peer(peer);
+		rxrpc_free_skb(skb);
+		_leave(" [no trans]");
+		return;
+	}
+
+	if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP &&
+	    serr->ee.ee_type == ICMP_DEST_UNREACH &&
+	    serr->ee.ee_code == ICMP_FRAG_NEEDED
+	    ) {
+		u32 mtu = serr->ee.ee_info;
+
+		_net("Rx Received ICMP Fragmentation Needed (%d)", mtu);
+
+		/* wind down the local interface MTU */
+		if (mtu > 0 && peer->if_mtu == 65535 && mtu < peer->if_mtu) {
+			peer->if_mtu = mtu;
+			_net("I/F MTU %u", mtu);
+		}
+
+		/* ip_rt_frag_needed() may have eaten the info */
+		if (mtu == 0)
+			mtu = ntohs(icmp_hdr(skb)->un.frag.mtu);
+
+		if (mtu == 0) {
+			/* they didn't give us a size, estimate one */
+			if (mtu > 1500) {
+				mtu >>= 1;
+				if (mtu < 1500)
+					mtu = 1500;
+			} else {
+				mtu -= 100;
+				if (mtu < peer->hdrsize)
+					mtu = peer->hdrsize + 4;
+			}
+		}
+
+		if (mtu < peer->mtu) {
+			spin_lock_bh(&peer->lock);
+			peer->mtu = mtu;
+			peer->maxdata = peer->mtu - peer->hdrsize;
+			spin_unlock_bh(&peer->lock);
+			_net("Net MTU %u (maxdata %u)",
+			     peer->mtu, peer->maxdata);
+		}
+	}
+
+	rxrpc_put_peer(peer);
+
+	/* pass the transport ref to error_handler to release */
+	skb_queue_tail(&trans->error_queue, skb);
+	rxrpc_queue_work(&trans->error_handler);
+
+	/* reset and regenerate socket error */
+	spin_lock_bh(&sk->sk_error_queue.lock);
+	sk->sk_err = 0;
+	skb = skb_peek(&sk->sk_error_queue);
+	if (skb) {
+		sk->sk_err = SKB_EXT_ERR(skb)->ee.ee_errno;
+		spin_unlock_bh(&sk->sk_error_queue.lock);
+		sk->sk_error_report(sk);
+	} else {
+		spin_unlock_bh(&sk->sk_error_queue.lock);
+	}
+
+	_leave("");
+}
+
+/*
+ * deal with UDP error messages
+ */
+void rxrpc_UDP_error_handler(struct work_struct *work)
+{
+	struct sock_extended_err *ee;
+	struct sock_exterr_skb *serr;
+	struct rxrpc_transport *trans =
+		container_of(work, struct rxrpc_transport, error_handler);
+	struct sk_buff *skb;
+	int local, err;
+
+	_enter("");
+
+	skb = skb_dequeue(&trans->error_queue);
+	if (!skb)
+		return;
+
+	serr = SKB_EXT_ERR(skb);
+	ee = &serr->ee;
+
+	_net("Rx Error o=%d t=%d c=%d e=%d",
+	     ee->ee_origin, ee->ee_type, ee->ee_code, ee->ee_errno);
+
+	err = ee->ee_errno;
+
+	switch (ee->ee_origin) {
+	case SO_EE_ORIGIN_ICMP:
+		local = 0;
+		switch (ee->ee_type) {
+		case ICMP_DEST_UNREACH:
+			switch (ee->ee_code) {
+			case ICMP_NET_UNREACH:
+				_net("Rx Received ICMP Network Unreachable");
+				err = ENETUNREACH;
+				break;
+			case ICMP_HOST_UNREACH:
+				_net("Rx Received ICMP Host Unreachable");
+				err = EHOSTUNREACH;
+				break;
+			case ICMP_PORT_UNREACH:
+				_net("Rx Received ICMP Port Unreachable");
+				err = ECONNREFUSED;
+				break;
+			case ICMP_FRAG_NEEDED:
+				_net("Rx Received ICMP Fragmentation Needed (%d)",
+				     ee->ee_info);
+				err = 0; /* dealt with elsewhere */
+				break;
+			case ICMP_NET_UNKNOWN:
+				_net("Rx Received ICMP Unknown Network");
+				err = ENETUNREACH;
+				break;
+			case ICMP_HOST_UNKNOWN:
+				_net("Rx Received ICMP Unknown Host");
+				err = EHOSTUNREACH;
+				break;
+			default:
+				_net("Rx Received ICMP DestUnreach code=%u",
+				     ee->ee_code);
+				break;
+			}
+			break;
+
+		case ICMP_TIME_EXCEEDED:
+			_net("Rx Received ICMP TTL Exceeded");
+			break;
+
+		default:
+			_proto("Rx Received ICMP error { type=%u code=%u }",
+			       ee->ee_type, ee->ee_code);
+			break;
+		}
+		break;
+
+	case SO_EE_ORIGIN_LOCAL:
+		_proto("Rx Received local error { error=%d }",
+		       ee->ee_errno);
+		local = 1;
+		break;
+
+	case SO_EE_ORIGIN_NONE:
+	case SO_EE_ORIGIN_ICMP6:
+	default:
+		_proto("Rx Received error report { orig=%u }",
+		       ee->ee_origin);
+		local = 0;
+		break;
+	}
+
+	/* terminate all the affected calls if there's an unrecoverable
+	 * error */
+	if (err) {
+		struct rxrpc_call *call, *_n;
+
+		_debug("ISSUE ERROR %d", err);
+
+		spin_lock_bh(&trans->peer->lock);
+		trans->peer->net_error = err;
+
+		list_for_each_entry_safe(call, _n, &trans->peer->error_targets,
+					 error_link) {
+			write_lock(&call->state_lock);
+			if (call->state != RXRPC_CALL_COMPLETE &&
+			    call->state < RXRPC_CALL_NETWORK_ERROR) {
+				call->state = RXRPC_CALL_NETWORK_ERROR;
+				set_bit(RXRPC_CALL_RCVD_ERROR, &call->events);
+				rxrpc_queue_call(call);
+			}
+			write_unlock(&call->state_lock);
+			list_del_init(&call->error_link);
+		}
+
+		spin_unlock_bh(&trans->peer->lock);
+	}
+
+	if (!skb_queue_empty(&trans->error_queue))
+		rxrpc_queue_work(&trans->error_handler);
+
+	rxrpc_free_skb(skb);
+	rxrpc_put_transport(trans);
+	_leave("");
+}
diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c
new file mode 100644
index 0000000..91b5bbb
--- /dev/null
+++ b/net/rxrpc/ar-input.c
@@ -0,0 +1,797 @@
+/* RxRPC packet reception
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/errqueue.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <net/ip.h>
+#include "ar-internal.h"
+
+unsigned long rxrpc_ack_timeout = 1;
+
+const char *rxrpc_pkts[] = {
+	"?00",
+	"DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG",
+	"?09", "?10", "?11", "?12", "?13", "?14", "?15"
+};
+
+/*
+ * queue a packet for recvmsg to pass to userspace
+ * - the caller must hold a lock on call->lock
+ * - must not be called with interrupts disabled (sk_filter() disables BH's)
+ * - eats the packet whether successful or not
+ * - there must be just one reference to the packet, which the caller passes to
+ *   this function
+ */
+int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
+			bool force, bool terminal)
+{
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_sock *rx = call->socket;
+	struct sock *sk;
+	int skb_len, ret;
+
+	_enter(",,%d,%d", force, terminal);
+
+	ASSERT(!irqs_disabled());
+
+	sp = rxrpc_skb(skb);
+	ASSERTCMP(sp->call, ==, call);
+
+	/* if we've already posted the terminal message for a call, then we
+	 * don't post any more */
+	if (test_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags)) {
+		_debug("already terminated");
+		ASSERTCMP(call->state, >=, RXRPC_CALL_COMPLETE);
+		skb->destructor = NULL;
+		sp->call = NULL;
+		rxrpc_put_call(call);
+		rxrpc_free_skb(skb);
+		return 0;
+	}
+
+	sk = &rx->sk;
+
+	if (!force) {
+		/* cast skb->rcvbuf to unsigned...  It's pointless, but
+		 * reduces number of warnings when compiling with -W
+		 * --ANK */
+//		ret = -ENOBUFS;
+//		if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+//		    (unsigned) sk->sk_rcvbuf)
+//			goto out;
+
+		ret = sk_filter(sk, skb);
+		if (ret < 0)
+			goto out;
+	}
+
+	spin_lock_bh(&sk->sk_receive_queue.lock);
+	if (!test_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags) &&
+	    !test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+	    call->socket->sk.sk_state != RXRPC_CLOSE) {
+		skb->destructor = rxrpc_packet_destructor;
+		skb->dev = NULL;
+		skb->sk = sk;
+		atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+
+		if (terminal) {
+			_debug("<<<< TERMINAL MESSAGE >>>>");
+			set_bit(RXRPC_CALL_TERMINAL_MSG, &call->flags);
+		}
+
+		/* allow interception by a kernel service */
+		if (rx->interceptor) {
+			rx->interceptor(sk, call->user_call_ID, skb);
+			spin_unlock_bh(&sk->sk_receive_queue.lock);
+		} else {
+
+			/* Cache the SKB length before we tack it onto the
+			 * receive queue.  Once it is added it no longer
+			 * belongs to us and may be freed by other threads of
+			 * control pulling packets from the queue */
+			skb_len = skb->len;
+
+			_net("post skb %p", skb);
+			__skb_queue_tail(&sk->sk_receive_queue, skb);
+			spin_unlock_bh(&sk->sk_receive_queue.lock);
+
+			if (!sock_flag(sk, SOCK_DEAD))
+				sk->sk_data_ready(sk, skb_len);
+		}
+		skb = NULL;
+	} else {
+		spin_unlock_bh(&sk->sk_receive_queue.lock);
+	}
+	ret = 0;
+
+out:
+	/* release the socket buffer */
+	if (skb) {
+		skb->destructor = NULL;
+		sp->call = NULL;
+		rxrpc_put_call(call);
+		rxrpc_free_skb(skb);
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * process a DATA packet, posting the packet to the appropriate queue
+ * - eats the packet if successful
+ */
+static int rxrpc_fast_process_data(struct rxrpc_call *call,
+				   struct sk_buff *skb, u32 seq)
+{
+	struct rxrpc_skb_priv *sp;
+	bool terminal;
+	int ret, ackbit, ack;
+
+	_enter("{%u,%u},,{%u}", call->rx_data_post, call->rx_first_oos, seq);
+
+	sp = rxrpc_skb(skb);
+	ASSERTCMP(sp->call, ==, NULL);
+
+	spin_lock(&call->lock);
+
+	if (call->state > RXRPC_CALL_COMPLETE)
+		goto discard;
+
+	ASSERTCMP(call->rx_data_expect, >=, call->rx_data_post);
+	ASSERTCMP(call->rx_data_post, >=, call->rx_data_recv);
+	ASSERTCMP(call->rx_data_recv, >=, call->rx_data_eaten);
+
+	if (seq < call->rx_data_post) {
+		_debug("dup #%u [-%u]", seq, call->rx_data_post);
+		ack = RXRPC_ACK_DUPLICATE;
+		ret = -ENOBUFS;
+		goto discard_and_ack;
+	}
+
+	/* we may already have the packet in the out of sequence queue */
+	ackbit = seq - (call->rx_data_eaten + 1);
+	ASSERTCMP(ackbit, >=, 0);
+	if (__test_and_set_bit(ackbit, call->ackr_window)) {
+		_debug("dup oos #%u [%u,%u]",
+		       seq, call->rx_data_eaten, call->rx_data_post);
+		ack = RXRPC_ACK_DUPLICATE;
+		goto discard_and_ack;
+	}
+
+	if (seq >= call->ackr_win_top) {
+		_debug("exceed #%u [%u]", seq, call->ackr_win_top);
+		__clear_bit(ackbit, call->ackr_window);
+		ack = RXRPC_ACK_EXCEEDS_WINDOW;
+		goto discard_and_ack;
+	}
+
+	if (seq == call->rx_data_expect) {
+		clear_bit(RXRPC_CALL_EXPECT_OOS, &call->flags);
+		call->rx_data_expect++;
+	} else if (seq > call->rx_data_expect) {
+		_debug("oos #%u [%u]", seq, call->rx_data_expect);
+		call->rx_data_expect = seq + 1;
+		if (test_and_set_bit(RXRPC_CALL_EXPECT_OOS, &call->flags)) {
+			ack = RXRPC_ACK_OUT_OF_SEQUENCE;
+			goto enqueue_and_ack;
+		}
+		goto enqueue_packet;
+	}
+
+	if (seq != call->rx_data_post) {
+		_debug("ahead #%u [%u]", seq, call->rx_data_post);
+		goto enqueue_packet;
+	}
+
+	if (test_bit(RXRPC_CALL_RCVD_LAST, &call->flags))
+		goto protocol_error;
+
+	/* if the packet need security things doing to it, then it goes down
+	 * the slow path */
+	if (call->conn->security)
+		goto enqueue_packet;
+
+	sp->call = call;
+	rxrpc_get_call(call);
+	terminal = ((sp->hdr.flags & RXRPC_LAST_PACKET) &&
+		    !(sp->hdr.flags & RXRPC_CLIENT_INITIATED));
+	ret = rxrpc_queue_rcv_skb(call, skb, false, terminal);
+	if (ret < 0) {
+		if (ret == -ENOMEM || ret == -ENOBUFS) {
+			__clear_bit(ackbit, call->ackr_window);
+			ack = RXRPC_ACK_NOSPACE;
+			goto discard_and_ack;
+		}
+		goto out;
+	}
+
+	skb = NULL;
+
+	_debug("post #%u", seq);
+	ASSERTCMP(call->rx_data_post, ==, seq);
+	call->rx_data_post++;
+
+	if (sp->hdr.flags & RXRPC_LAST_PACKET)
+		set_bit(RXRPC_CALL_RCVD_LAST, &call->flags);
+
+	/* if we've reached an out of sequence packet then we need to drain
+	 * that queue into the socket Rx queue now */
+	if (call->rx_data_post == call->rx_first_oos) {
+		_debug("drain rx oos now");
+		read_lock(&call->state_lock);
+		if (call->state < RXRPC_CALL_COMPLETE &&
+		    !test_and_set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events))
+			rxrpc_queue_call(call);
+		read_unlock(&call->state_lock);
+	}
+
+	spin_unlock(&call->lock);
+	atomic_inc(&call->ackr_not_idle);
+	rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, sp->hdr.serial, false);
+	_leave(" = 0 [posted]");
+	return 0;
+
+protocol_error:
+	ret = -EBADMSG;
+out:
+	spin_unlock(&call->lock);
+	_leave(" = %d", ret);
+	return ret;
+
+discard_and_ack:
+	_debug("discard and ACK packet %p", skb);
+	__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true);
+discard:
+	spin_unlock(&call->lock);
+	rxrpc_free_skb(skb);
+	_leave(" = 0 [discarded]");
+	return 0;
+
+enqueue_and_ack:
+	__rxrpc_propose_ACK(call, ack, sp->hdr.serial, true);
+enqueue_packet:
+	_net("defer skb %p", skb);
+	spin_unlock(&call->lock);
+	skb_queue_tail(&call->rx_queue, skb);
+	atomic_inc(&call->ackr_not_idle);
+	read_lock(&call->state_lock);
+	if (call->state < RXRPC_CALL_DEAD)
+		rxrpc_queue_call(call);
+	read_unlock(&call->state_lock);
+	_leave(" = 0 [queued]");
+	return 0;
+}
+
+/*
+ * assume an implicit ACKALL of the transmission phase of a client socket upon
+ * reception of the first reply packet
+ */
+static void rxrpc_assume_implicit_ackall(struct rxrpc_call *call, u32 serial)
+{
+	write_lock_bh(&call->state_lock);
+
+	switch (call->state) {
+	case RXRPC_CALL_CLIENT_AWAIT_REPLY:
+		call->state = RXRPC_CALL_CLIENT_RECV_REPLY;
+		call->acks_latest = serial;
+
+		_debug("implicit ACKALL %%%u", call->acks_latest);
+		set_bit(RXRPC_CALL_RCVD_ACKALL, &call->events);
+		write_unlock_bh(&call->state_lock);
+
+		if (try_to_del_timer_sync(&call->resend_timer) >= 0) {
+			clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+			clear_bit(RXRPC_CALL_RESEND, &call->events);
+			clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+		}
+		break;
+
+	default:
+		write_unlock_bh(&call->state_lock);
+		break;
+	}
+}
+
+/*
+ * post an incoming packet to the nominated call to deal with
+ * - must get rid of the sk_buff, either by freeing it or by queuing it
+ */
+void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	__be32 _abort_code;
+	u32 serial, hi_serial, seq, abort_code;
+
+	_enter("%p,%p", call, skb);
+
+	ASSERT(!irqs_disabled());
+
+#if 0 // INJECT RX ERROR
+	if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA) {
+		static int skip = 0;
+		if (++skip == 3) {
+			printk("DROPPED 3RD PACKET!!!!!!!!!!!!!\n");
+			skip = 0;
+			goto free_packet;
+		}
+	}
+#endif
+
+	/* track the latest serial number on this connection for ACK packet
+	 * information */
+	serial = ntohl(sp->hdr.serial);
+	hi_serial = atomic_read(&call->conn->hi_serial);
+	while (serial > hi_serial)
+		hi_serial = atomic_cmpxchg(&call->conn->hi_serial, hi_serial,
+					   serial);
+
+	/* request ACK generation for any ACK or DATA packet that requests
+	 * it */
+	if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
+		_proto("ACK Requested on %%%u", serial);
+		rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial,
+				  !(sp->hdr.flags & RXRPC_MORE_PACKETS));
+	}
+
+	switch (sp->hdr.type) {
+	case RXRPC_PACKET_TYPE_ABORT:
+		_debug("abort");
+
+		if (skb_copy_bits(skb, 0, &_abort_code,
+				  sizeof(_abort_code)) < 0)
+			goto protocol_error;
+
+		abort_code = ntohl(_abort_code);
+		_proto("Rx ABORT %%%u { %x }", serial, abort_code);
+
+		write_lock_bh(&call->state_lock);
+		if (call->state < RXRPC_CALL_COMPLETE) {
+			call->state = RXRPC_CALL_REMOTELY_ABORTED;
+			call->abort_code = abort_code;
+			set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+			rxrpc_queue_call(call);
+		}
+		goto free_packet_unlock;
+
+	case RXRPC_PACKET_TYPE_BUSY:
+		_proto("Rx BUSY %%%u", serial);
+
+		if (call->conn->out_clientflag)
+			goto protocol_error;
+
+		write_lock_bh(&call->state_lock);
+		switch (call->state) {
+		case RXRPC_CALL_CLIENT_SEND_REQUEST:
+			call->state = RXRPC_CALL_SERVER_BUSY;
+			set_bit(RXRPC_CALL_RCVD_BUSY, &call->events);
+			rxrpc_queue_call(call);
+		case RXRPC_CALL_SERVER_BUSY:
+			goto free_packet_unlock;
+		default:
+			goto protocol_error_locked;
+		}
+
+	default:
+		_proto("Rx %s %%%u", rxrpc_pkts[sp->hdr.type], serial);
+		goto protocol_error;
+
+	case RXRPC_PACKET_TYPE_DATA:
+		seq = ntohl(sp->hdr.seq);
+
+		_proto("Rx DATA %%%u { #%u }", serial, seq);
+
+		if (seq == 0)
+			goto protocol_error;
+
+		call->ackr_prev_seq = sp->hdr.seq;
+
+		/* received data implicitly ACKs all of the request packets we
+		 * sent when we're acting as a client */
+		if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY)
+			rxrpc_assume_implicit_ackall(call, serial);
+
+		switch (rxrpc_fast_process_data(call, skb, seq)) {
+		case 0:
+			skb = NULL;
+			goto done;
+
+		default:
+			BUG();
+
+			/* data packet received beyond the last packet */
+		case -EBADMSG:
+			goto protocol_error;
+		}
+
+	case RXRPC_PACKET_TYPE_ACK:
+		/* ACK processing is done in process context */
+		read_lock_bh(&call->state_lock);
+		if (call->state < RXRPC_CALL_DEAD) {
+			skb_queue_tail(&call->rx_queue, skb);
+			rxrpc_queue_call(call);
+			skb = NULL;
+		}
+		read_unlock_bh(&call->state_lock);
+		goto free_packet;
+	}
+
+protocol_error:
+	_debug("protocol error");
+	write_lock_bh(&call->state_lock);
+protocol_error_locked:
+	if (call->state <= RXRPC_CALL_COMPLETE) {
+		call->state = RXRPC_CALL_LOCALLY_ABORTED;
+		call->abort_code = RX_PROTOCOL_ERROR;
+		set_bit(RXRPC_CALL_ABORT, &call->events);
+		rxrpc_queue_call(call);
+	}
+free_packet_unlock:
+	write_unlock_bh(&call->state_lock);
+free_packet:
+	rxrpc_free_skb(skb);
+done:
+	_leave("");
+}
+
+/*
+ * split up a jumbo data packet
+ */
+static void rxrpc_process_jumbo_packet(struct rxrpc_call *call,
+				       struct sk_buff *jumbo)
+{
+	struct rxrpc_jumbo_header jhdr;
+	struct rxrpc_skb_priv *sp;
+	struct sk_buff *part;
+
+	_enter(",{%u,%u}", jumbo->data_len, jumbo->len);
+
+	sp = rxrpc_skb(jumbo);
+
+	do {
+		sp->hdr.flags &= ~RXRPC_JUMBO_PACKET;
+
+		/* make a clone to represent the first subpacket in what's left
+		 * of the jumbo packet */
+		part = skb_clone(jumbo, GFP_ATOMIC);
+		if (!part) {
+			/* simply ditch the tail in the event of ENOMEM */
+			pskb_trim(jumbo, RXRPC_JUMBO_DATALEN);
+			break;
+		}
+		rxrpc_new_skb(part);
+
+		pskb_trim(part, RXRPC_JUMBO_DATALEN);
+
+		if (!pskb_pull(jumbo, RXRPC_JUMBO_DATALEN))
+			goto protocol_error;
+
+		if (skb_copy_bits(jumbo, 0, &jhdr, sizeof(jhdr)) < 0)
+			goto protocol_error;
+		if (!pskb_pull(jumbo, sizeof(jhdr)))
+			BUG();
+
+		sp->hdr.seq	= htonl(ntohl(sp->hdr.seq) + 1);
+		sp->hdr.serial	= htonl(ntohl(sp->hdr.serial) + 1);
+		sp->hdr.flags	= jhdr.flags;
+		sp->hdr._rsvd	= jhdr._rsvd;
+
+		_proto("Rx DATA Jumbo %%%u", ntohl(sp->hdr.serial) - 1);
+
+		rxrpc_fast_process_packet(call, part);
+		part = NULL;
+
+	} while (sp->hdr.flags & RXRPC_JUMBO_PACKET);
+
+	rxrpc_fast_process_packet(call, jumbo);
+	_leave("");
+	return;
+
+protocol_error:
+	_debug("protocol error");
+	rxrpc_free_skb(part);
+	rxrpc_free_skb(jumbo);
+	write_lock_bh(&call->state_lock);
+	if (call->state <= RXRPC_CALL_COMPLETE) {
+		call->state = RXRPC_CALL_LOCALLY_ABORTED;
+		call->abort_code = RX_PROTOCOL_ERROR;
+		set_bit(RXRPC_CALL_ABORT, &call->events);
+		rxrpc_queue_call(call);
+	}
+	write_unlock_bh(&call->state_lock);
+	_leave("");
+}
+
+/*
+ * post an incoming packet to the appropriate call/socket to deal with
+ * - must get rid of the sk_buff, either by freeing it or by queuing it
+ */
+static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
+				      struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_call *call;
+	struct rb_node *p;
+	__be32 call_id;
+
+	_enter("%p,%p", conn, skb);
+
+	read_lock_bh(&conn->lock);
+
+	sp = rxrpc_skb(skb);
+
+	/* look at extant calls by channel number first */
+	call = conn->channels[ntohl(sp->hdr.cid) & RXRPC_CHANNELMASK];
+	if (!call || call->call_id != sp->hdr.callNumber)
+		goto call_not_extant;
+
+	_debug("extant call [%d]", call->state);
+	ASSERTCMP(call->conn, ==, conn);
+
+	read_lock(&call->state_lock);
+	switch (call->state) {
+	case RXRPC_CALL_LOCALLY_ABORTED:
+		if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+			rxrpc_queue_call(call);
+	case RXRPC_CALL_REMOTELY_ABORTED:
+	case RXRPC_CALL_NETWORK_ERROR:
+	case RXRPC_CALL_DEAD:
+		goto free_unlock;
+	default:
+		break;
+	}
+
+	read_unlock(&call->state_lock);
+	rxrpc_get_call(call);
+	read_unlock_bh(&conn->lock);
+
+	if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
+	    sp->hdr.flags & RXRPC_JUMBO_PACKET)
+		rxrpc_process_jumbo_packet(call, skb);
+	else
+		rxrpc_fast_process_packet(call, skb);
+
+	rxrpc_put_call(call);
+	goto done;
+
+call_not_extant:
+	/* search the completed calls in case what we're dealing with is
+	 * there */
+	_debug("call not extant");
+
+	call_id = sp->hdr.callNumber;
+	p = conn->calls.rb_node;
+	while (p) {
+		call = rb_entry(p, struct rxrpc_call, conn_node);
+
+		if (call_id < call->call_id)
+			p = p->rb_left;
+		else if (call_id > call->call_id)
+			p = p->rb_right;
+		else
+			goto found_completed_call;
+	}
+
+dead_call:
+	/* it's a either a really old call that we no longer remember or its a
+	 * new incoming call */
+	read_unlock_bh(&conn->lock);
+
+	if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
+	    sp->hdr.seq == __constant_cpu_to_be32(1)) {
+		_debug("incoming call");
+		skb_queue_tail(&conn->trans->local->accept_queue, skb);
+		rxrpc_queue_work(&conn->trans->local->acceptor);
+		goto done;
+	}
+
+	_debug("dead call");
+	skb->priority = RX_CALL_DEAD;
+	rxrpc_reject_packet(conn->trans->local, skb);
+	goto done;
+
+	/* resend last packet of a completed call
+	 * - client calls may have been aborted or ACK'd
+	 * - server calls may have been aborted
+	 */
+found_completed_call:
+	_debug("completed call");
+
+	if (atomic_read(&call->usage) == 0)
+		goto dead_call;
+
+	/* synchronise any state changes */
+	read_lock(&call->state_lock);
+	ASSERTIFCMP(call->state != RXRPC_CALL_CLIENT_FINAL_ACK,
+		    call->state, >=, RXRPC_CALL_COMPLETE);
+
+	if (call->state == RXRPC_CALL_LOCALLY_ABORTED ||
+	    call->state == RXRPC_CALL_REMOTELY_ABORTED ||
+	    call->state == RXRPC_CALL_DEAD) {
+		read_unlock(&call->state_lock);
+		goto dead_call;
+	}
+
+	if (call->conn->in_clientflag) {
+		read_unlock(&call->state_lock);
+		goto dead_call; /* complete server call */
+	}
+
+	_debug("final ack again");
+	rxrpc_get_call(call);
+	set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+	rxrpc_queue_call(call);
+
+free_unlock:
+	read_unlock(&call->state_lock);
+	read_unlock_bh(&conn->lock);
+	rxrpc_free_skb(skb);
+done:
+	_leave("");
+}
+
+/*
+ * post connection-level events to the connection
+ * - this includes challenges, responses and some aborts
+ */
+static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
+				      struct sk_buff *skb)
+{
+	_enter("%p,%p", conn, skb);
+
+	atomic_inc(&conn->usage);
+	skb_queue_tail(&conn->rx_queue, skb);
+	rxrpc_queue_conn(conn);
+}
+
+/*
+ * handle data received on the local endpoint
+ * - may be called in interrupt context
+ */
+void rxrpc_data_ready(struct sock *sk, int count)
+{
+	struct rxrpc_connection *conn;
+	struct rxrpc_transport *trans;
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_local *local;
+	struct rxrpc_peer *peer;
+	struct sk_buff *skb;
+	int ret;
+
+	_enter("%p, %d", sk, count);
+
+	ASSERT(!irqs_disabled());
+
+	read_lock_bh(&rxrpc_local_lock);
+	local = sk->sk_user_data;
+	if (local && atomic_read(&local->usage) > 0)
+		rxrpc_get_local(local);
+	else
+		local = NULL;
+	read_unlock_bh(&rxrpc_local_lock);
+	if (!local) {
+		_leave(" [local dead]");
+		return;
+	}
+
+	skb = skb_recv_datagram(sk, 0, 1, &ret);
+	if (!skb) {
+		rxrpc_put_local(local);
+		if (ret == -EAGAIN)
+			return;
+		_debug("UDP socket error %d", ret);
+		return;
+	}
+
+	rxrpc_new_skb(skb);
+
+	_net("recv skb %p", skb);
+
+	/* we'll probably need to checksum it (didn't call sock_recvmsg) */
+	if (skb_checksum_complete(skb)) {
+		rxrpc_free_skb(skb);
+		rxrpc_put_local(local);
+		_leave(" [CSUM failed]");
+		return;
+	}
+
+	/* the socket buffer we have is owned by UDP, with UDP's data all over
+	 * it, but we really want our own */
+	skb_orphan(skb);
+	sp = rxrpc_skb(skb);
+	memset(sp, 0, sizeof(*sp));
+
+	_net("Rx UDP packet from %08x:%04hu",
+	     ntohl(ip_hdr(skb)->saddr), ntohs(udp_hdr(skb)->source));
+
+	/* dig out the RxRPC connection details */
+	if (skb_copy_bits(skb, sizeof(struct udphdr), &sp->hdr,
+			  sizeof(sp->hdr)) < 0)
+		goto bad_message;
+	if (!pskb_pull(skb, sizeof(struct udphdr) + sizeof(sp->hdr)))
+		BUG();
+
+	_net("Rx RxRPC %s ep=%x call=%x:%x",
+	     sp->hdr.flags & RXRPC_CLIENT_INITIATED ? "ToServer" : "ToClient",
+	     ntohl(sp->hdr.epoch),
+	     ntohl(sp->hdr.cid),
+	     ntohl(sp->hdr.callNumber));
+
+	if (sp->hdr.type == 0 || sp->hdr.type >= RXRPC_N_PACKET_TYPES) {
+		_proto("Rx Bad Packet Type %u", sp->hdr.type);
+		goto bad_message;
+	}
+
+	if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
+	    (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))
+		goto bad_message;
+
+	peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, udp_hdr(skb)->source);
+	if (IS_ERR(peer))
+		goto cant_route_call;
+
+	trans = rxrpc_find_transport(local, peer);
+	rxrpc_put_peer(peer);
+	if (!trans)
+		goto cant_route_call;
+
+	conn = rxrpc_find_connection(trans, &sp->hdr);
+	rxrpc_put_transport(trans);
+	if (!conn)
+		goto cant_route_call;
+
+	_debug("CONN %p {%d}", conn, conn->debug_id);
+
+	if (sp->hdr.callNumber == 0)
+		rxrpc_post_packet_to_conn(conn, skb);
+	else
+		rxrpc_post_packet_to_call(conn, skb);
+	rxrpc_put_connection(conn);
+	rxrpc_put_local(local);
+	return;
+
+cant_route_call:
+	_debug("can't route call");
+	if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
+	    sp->hdr.type == RXRPC_PACKET_TYPE_DATA) {
+		if (sp->hdr.seq == __constant_cpu_to_be32(1)) {
+			_debug("first packet");
+			skb_queue_tail(&local->accept_queue, skb);
+			rxrpc_queue_work(&local->acceptor);
+			rxrpc_put_local(local);
+			_leave(" [incoming]");
+			return;
+		}
+		skb->priority = RX_INVALID_OPERATION;
+	} else {
+		skb->priority = RX_CALL_DEAD;
+	}
+
+	_debug("reject");
+	rxrpc_reject_packet(local, skb);
+	rxrpc_put_local(local);
+	_leave(" [no call]");
+	return;
+
+bad_message:
+	skb->priority = RX_PROTOCOL_ERROR;
+	rxrpc_reject_packet(local, skb);
+	rxrpc_put_local(local);
+	_leave(" [badmsg]");
+}
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
new file mode 100644
index 0000000..58aaf89
--- /dev/null
+++ b/net/rxrpc/ar-internal.h
@@ -0,0 +1,808 @@
+/* AF_RXRPC internal definitions
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <rxrpc/packet.h>
+
+#if 0
+#define CHECK_SLAB_OKAY(X)				     \
+	BUG_ON(atomic_read((X)) >> (sizeof(atomic_t) - 2) == \
+	       (POISON_FREE << 8 | POISON_FREE))
+#else
+#define CHECK_SLAB_OKAY(X) do {} while(0)
+#endif
+
+#define FCRYPT_BSIZE 8
+struct rxrpc_crypt {
+	union {
+		u8	x[FCRYPT_BSIZE];
+		u32	n[2];
+	};
+} __attribute__((aligned(8)));
+
+#define rxrpc_queue_work(WS)	queue_work(rxrpc_workqueue, (WS))
+#define rxrpc_queue_delayed_work(WS,D)	\
+	queue_delayed_work(rxrpc_workqueue, (WS), (D))
+
+#define rxrpc_queue_call(CALL)	rxrpc_queue_work(&(CALL)->processor)
+#define rxrpc_queue_conn(CONN)	rxrpc_queue_work(&(CONN)->processor)
+
+/*
+ * sk_state for RxRPC sockets
+ */
+enum {
+	RXRPC_UNCONNECTED = 0,
+	RXRPC_CLIENT_BOUND,		/* client local address bound */
+	RXRPC_CLIENT_CONNECTED,		/* client is connected */
+	RXRPC_SERVER_BOUND,		/* server local address bound */
+	RXRPC_SERVER_LISTENING,		/* server listening for connections */
+	RXRPC_CLOSE,			/* socket is being closed */
+};
+
+/*
+ * RxRPC socket definition
+ */
+struct rxrpc_sock {
+	/* WARNING: sk has to be the first member */
+	struct sock		sk;
+	rxrpc_interceptor_t	interceptor;	/* kernel service Rx interceptor function */
+	struct rxrpc_local	*local;		/* local endpoint */
+	struct rxrpc_transport	*trans;		/* transport handler */
+	struct rxrpc_conn_bundle *bundle;	/* virtual connection bundle */
+	struct rxrpc_connection	*conn;		/* exclusive virtual connection */
+	struct list_head	listen_link;	/* link in the local endpoint's listen list */
+	struct list_head	secureq;	/* calls awaiting connection security clearance */
+	struct list_head	acceptq;	/* calls awaiting acceptance */
+	struct key		*key;		/* security for this socket */
+	struct key		*securities;	/* list of server security descriptors */
+	struct rb_root		calls;		/* outstanding calls on this socket */
+	unsigned long		flags;
+#define RXRPC_SOCK_EXCLUSIVE_CONN	1	/* exclusive connection for a client socket */
+	rwlock_t		call_lock;	/* lock for calls */
+	u32			min_sec_level;	/* minimum security level */
+#define RXRPC_SECURITY_MAX	RXRPC_SECURITY_ENCRYPT
+	struct sockaddr_rxrpc	srx;		/* local address */
+	sa_family_t		proto;		/* protocol created with */
+	__be16			service_id;	/* service ID of local/remote service */
+};
+
+#define rxrpc_sk(__sk) container_of((__sk), struct rxrpc_sock, sk)
+
+/*
+ * RxRPC socket buffer private variables
+ * - max 48 bytes (struct sk_buff::cb)
+ */
+struct rxrpc_skb_priv {
+	struct rxrpc_call	*call;		/* call with which associated */
+	unsigned long		resend_at;	/* time in jiffies at which to resend */
+	union {
+		unsigned	offset;		/* offset into buffer of next read */
+		int		remain;		/* amount of space remaining for next write */
+		u32		error;		/* network error code */
+		bool		need_resend;	/* T if needs resending */
+	};
+
+	struct rxrpc_header	hdr;		/* RxRPC packet header from this packet */
+};
+
+#define rxrpc_skb(__skb) ((struct rxrpc_skb_priv *) &(__skb)->cb)
+
+enum rxrpc_command {
+	RXRPC_CMD_SEND_DATA,		/* send data message */
+	RXRPC_CMD_SEND_ABORT,		/* request abort generation */
+	RXRPC_CMD_ACCEPT,		/* [server] accept incoming call */
+	RXRPC_CMD_REJECT_BUSY,		/* [server] reject a call as busy */
+};
+
+/*
+ * RxRPC security module interface
+ */
+struct rxrpc_security {
+	struct module		*owner;		/* providing module */
+	struct list_head	link;		/* link in master list */
+	const char		*name;		/* name of this service */
+	u8			security_index;	/* security type provided */
+
+	/* initialise a connection's security */
+	int (*init_connection_security)(struct rxrpc_connection *);
+
+	/* prime a connection's packet security */
+	void (*prime_packet_security)(struct rxrpc_connection *);
+
+	/* impose security on a packet */
+	int (*secure_packet)(const struct rxrpc_call *,
+			     struct sk_buff *,
+			     size_t,
+			     void *);
+
+	/* verify the security on a received packet */
+	int (*verify_packet)(const struct rxrpc_call *, struct sk_buff *,
+			     u32 *);
+
+	/* issue a challenge */
+	int (*issue_challenge)(struct rxrpc_connection *);
+
+	/* respond to a challenge */
+	int (*respond_to_challenge)(struct rxrpc_connection *,
+				    struct sk_buff *,
+				    u32 *);
+
+	/* verify a response */
+	int (*verify_response)(struct rxrpc_connection *,
+			       struct sk_buff *,
+			       u32 *);
+
+	/* clear connection security */
+	void (*clear)(struct rxrpc_connection *);
+};
+
+/*
+ * RxRPC local transport endpoint definition
+ * - matched by local port, address and protocol type
+ */
+struct rxrpc_local {
+	struct socket		*socket;	/* my UDP socket */
+	struct work_struct	destroyer;	/* endpoint destroyer */
+	struct work_struct	acceptor;	/* incoming call processor */
+	struct work_struct	rejecter;	/* packet reject writer */
+	struct list_head	services;	/* services listening on this endpoint */
+	struct list_head	link;		/* link in endpoint list */
+	struct rw_semaphore	defrag_sem;	/* control re-enablement of IP DF bit */
+	struct sk_buff_head	accept_queue;	/* incoming calls awaiting acceptance */
+	struct sk_buff_head	reject_queue;	/* packets awaiting rejection */
+	spinlock_t		lock;		/* access lock */
+	rwlock_t		services_lock;	/* lock for services list */
+	atomic_t		usage;
+	int			debug_id;	/* debug ID for printks */
+	volatile char		error_rcvd;	/* T if received ICMP error outstanding */
+	struct sockaddr_rxrpc	srx;		/* local address */
+};
+
+/*
+ * RxRPC remote transport endpoint definition
+ * - matched by remote port, address and protocol type
+ * - holds the connection ID counter for connections between the two endpoints
+ */
+struct rxrpc_peer {
+	struct work_struct	destroyer;	/* peer destroyer */
+	struct list_head	link;		/* link in master peer list */
+	struct list_head	error_targets;	/* targets for net error distribution */
+	spinlock_t		lock;		/* access lock */
+	atomic_t		usage;
+	unsigned		if_mtu;		/* interface MTU for this peer */
+	unsigned		mtu;		/* network MTU for this peer */
+	unsigned		maxdata;	/* data size (MTU - hdrsize) */
+	unsigned short		hdrsize;	/* header size (IP + UDP + RxRPC) */
+	int			debug_id;	/* debug ID for printks */
+	int			net_error;	/* network error distributed */
+	struct sockaddr_rxrpc	srx;		/* remote address */
+
+	/* calculated RTT cache */
+#define RXRPC_RTT_CACHE_SIZE 32
+	suseconds_t		rtt;		/* current RTT estimate (in uS) */
+	unsigned		rtt_point;	/* next entry at which to insert */
+	unsigned		rtt_usage;	/* amount of cache actually used */
+	suseconds_t		rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */
+};
+
+/*
+ * RxRPC point-to-point transport / connection manager definition
+ * - handles a bundle of connections between two endpoints
+ * - matched by { local, peer }
+ */
+struct rxrpc_transport {
+	struct rxrpc_local	*local;		/* local transport endpoint */
+	struct rxrpc_peer	*peer;		/* remote transport endpoint */
+	struct work_struct	error_handler;	/* network error distributor */
+	struct rb_root		bundles;	/* client connection bundles on this transport */
+	struct rb_root		client_conns;	/* client connections on this transport */
+	struct rb_root		server_conns;	/* server connections on this transport */
+	struct list_head	link;		/* link in master session list */
+	struct sk_buff_head	error_queue;	/* error packets awaiting processing */
+	time_t			put_time;	/* time at which to reap */
+	spinlock_t		client_lock;	/* client connection allocation lock */
+	rwlock_t		conn_lock;	/* lock for active/dead connections */
+	atomic_t		usage;
+	int			debug_id;	/* debug ID for printks */
+	unsigned int		conn_idcounter;	/* connection ID counter (client) */
+};
+
+/*
+ * RxRPC client connection bundle
+ * - matched by { transport, service_id, key }
+ */
+struct rxrpc_conn_bundle {
+	struct rb_node		node;		/* node in transport's lookup tree */
+	struct list_head	unused_conns;	/* unused connections in this bundle */
+	struct list_head	avail_conns;	/* available connections in this bundle */
+	struct list_head	busy_conns;	/* busy connections in this bundle */
+	struct key		*key;		/* security for this bundle */
+	wait_queue_head_t	chanwait;	/* wait for channel to become available */
+	atomic_t		usage;
+	int			debug_id;	/* debug ID for printks */
+	unsigned short		num_conns;	/* number of connections in this bundle */
+	__be16			service_id;	/* service ID */
+	uint8_t			security_ix;	/* security type */
+};
+
+/*
+ * RxRPC connection definition
+ * - matched by { transport, service_id, conn_id, direction, key }
+ * - each connection can only handle four simultaneous calls
+ */
+struct rxrpc_connection {
+	struct rxrpc_transport	*trans;		/* transport session */
+	struct rxrpc_conn_bundle *bundle;	/* connection bundle (client) */
+	struct work_struct	processor;	/* connection event processor */
+	struct rb_node		node;		/* node in transport's lookup tree */
+	struct list_head	link;		/* link in master connection list */
+	struct list_head	bundle_link;	/* link in bundle */
+	struct rb_root		calls;		/* calls on this connection */
+	struct sk_buff_head	rx_queue;	/* received conn-level packets */
+	struct rxrpc_call	*channels[RXRPC_MAXCALLS]; /* channels (active calls) */
+	struct rxrpc_security	*security;	/* applied security module */
+	struct key		*key;		/* security for this connection (client) */
+	struct key		*server_key;	/* security for this service */
+	struct crypto_blkcipher	*cipher;	/* encryption handle */
+	struct rxrpc_crypt	csum_iv;	/* packet checksum base */
+	unsigned long		events;
+#define RXRPC_CONN_CHALLENGE	0		/* send challenge packet */
+	time_t			put_time;	/* time at which to reap */
+	rwlock_t		lock;		/* access lock */
+	spinlock_t		state_lock;	/* state-change lock */
+	atomic_t		usage;
+	u32			real_conn_id;	/* connection ID (host-endian) */
+	enum {					/* current state of connection */
+		RXRPC_CONN_UNUSED,		/* - connection not yet attempted */
+		RXRPC_CONN_CLIENT,		/* - client connection */
+		RXRPC_CONN_SERVER_UNSECURED,	/* - server unsecured connection */
+		RXRPC_CONN_SERVER_CHALLENGING,	/* - server challenging for security */
+		RXRPC_CONN_SERVER,		/* - server secured connection */
+		RXRPC_CONN_REMOTELY_ABORTED,	/* - conn aborted by peer */
+		RXRPC_CONN_LOCALLY_ABORTED,	/* - conn aborted locally */
+		RXRPC_CONN_NETWORK_ERROR,	/* - conn terminated by network error */
+	} state;
+	int			error;		/* error code for local abort */
+	int			debug_id;	/* debug ID for printks */
+	unsigned		call_counter;	/* call ID counter */
+	atomic_t		serial;		/* packet serial number counter */
+	atomic_t		hi_serial;	/* highest serial number received */
+	u8			avail_calls;	/* number of calls available */
+	u8			size_align;	/* data size alignment (for security) */
+	u8			header_size;	/* rxrpc + security header size */
+	u8			security_size;	/* security header size */
+	u32			security_level;	/* security level negotiated */
+	u32			security_nonce;	/* response re-use preventer */
+
+	/* the following are all in net order */
+	__be32			epoch;		/* epoch of this connection */
+	__be32			cid;		/* connection ID */
+	__be16			service_id;	/* service ID */
+	u8			security_ix;	/* security type */
+	u8			in_clientflag;	/* RXRPC_CLIENT_INITIATED if we are server */
+	u8			out_clientflag;	/* RXRPC_CLIENT_INITIATED if we are client */
+};
+
+/*
+ * RxRPC call definition
+ * - matched by { connection, call_id }
+ */
+struct rxrpc_call {
+	struct rxrpc_connection	*conn;		/* connection carrying call */
+	struct rxrpc_sock	*socket;	/* socket responsible */
+	struct timer_list	lifetimer;	/* lifetime remaining on call */
+	struct timer_list	deadspan;	/* reap timer for re-ACK'ing, etc  */
+	struct timer_list	ack_timer;	/* ACK generation timer */
+	struct timer_list	resend_timer;	/* Tx resend timer */
+	struct work_struct	destroyer;	/* call destroyer */
+	struct work_struct	processor;	/* packet processor and ACK generator */
+	struct list_head	link;		/* link in master call list */
+	struct list_head	error_link;	/* link in error distribution list */
+	struct list_head	accept_link;	/* calls awaiting acceptance */
+	struct rb_node		sock_node;	/* node in socket call tree */
+	struct rb_node		conn_node;	/* node in connection call tree */
+	struct sk_buff_head	rx_queue;	/* received packets */
+	struct sk_buff_head	rx_oos_queue;	/* packets received out of sequence */
+	struct sk_buff		*tx_pending;	/* Tx socket buffer being filled */
+	wait_queue_head_t	tx_waitq;	/* wait for Tx window space to become available */
+	unsigned long		user_call_ID;	/* user-defined call ID */
+	unsigned long		creation_jif;	/* time of call creation */
+	unsigned long		flags;
+#define RXRPC_CALL_RELEASED	0	/* call has been released - no more message to userspace */
+#define RXRPC_CALL_TERMINAL_MSG	1	/* call has given the socket its final message */
+#define RXRPC_CALL_RCVD_LAST	2	/* all packets received */
+#define RXRPC_CALL_RUN_RTIMER	3	/* Tx resend timer started */
+#define RXRPC_CALL_TX_SOFT_ACK	4	/* sent some soft ACKs */
+#define RXRPC_CALL_PROC_BUSY	5	/* the processor is busy */
+#define RXRPC_CALL_INIT_ACCEPT	6	/* acceptance was initiated */
+#define RXRPC_CALL_HAS_USERID	7	/* has a user ID attached */
+#define RXRPC_CALL_EXPECT_OOS	8	/* expect out of sequence packets */
+	unsigned long		events;
+#define RXRPC_CALL_RCVD_ACKALL	0	/* ACKALL or reply received */
+#define RXRPC_CALL_RCVD_BUSY	1	/* busy packet received */
+#define RXRPC_CALL_RCVD_ABORT	2	/* abort packet received */
+#define RXRPC_CALL_RCVD_ERROR	3	/* network error received */
+#define RXRPC_CALL_ACK_FINAL	4	/* need to generate final ACK (and release call) */
+#define RXRPC_CALL_ACK		5	/* need to generate ACK */
+#define RXRPC_CALL_REJECT_BUSY	6	/* need to generate busy message */
+#define RXRPC_CALL_ABORT	7	/* need to generate abort */
+#define RXRPC_CALL_CONN_ABORT	8	/* local connection abort generated */
+#define RXRPC_CALL_RESEND_TIMER	9	/* Tx resend timer expired */
+#define RXRPC_CALL_RESEND	10	/* Tx resend required */
+#define RXRPC_CALL_DRAIN_RX_OOS	11	/* drain the Rx out of sequence queue */
+#define RXRPC_CALL_LIFE_TIMER	12	/* call's lifetimer ran out */
+#define RXRPC_CALL_ACCEPTED	13	/* incoming call accepted by userspace app */
+#define RXRPC_CALL_SECURED	14	/* incoming call's connection is now secure */
+#define RXRPC_CALL_POST_ACCEPT	15	/* need to post an "accept?" message to the app */
+#define RXRPC_CALL_RELEASE	16	/* need to release the call's resources */
+
+	spinlock_t		lock;
+	rwlock_t		state_lock;	/* lock for state transition */
+	atomic_t		usage;
+	atomic_t		sequence;	/* Tx data packet sequence counter */
+	u32			abort_code;	/* local/remote abort code */
+	enum {					/* current state of call */
+		RXRPC_CALL_CLIENT_SEND_REQUEST,	/* - client sending request phase */
+		RXRPC_CALL_CLIENT_AWAIT_REPLY,	/* - client awaiting reply */
+		RXRPC_CALL_CLIENT_RECV_REPLY,	/* - client receiving reply phase */
+		RXRPC_CALL_CLIENT_FINAL_ACK,	/* - client sending final ACK phase */
+		RXRPC_CALL_SERVER_SECURING,	/* - server securing request connection */
+		RXRPC_CALL_SERVER_ACCEPTING,	/* - server accepting request */
+		RXRPC_CALL_SERVER_RECV_REQUEST,	/* - server receiving request */
+		RXRPC_CALL_SERVER_ACK_REQUEST,	/* - server pending ACK of request */
+		RXRPC_CALL_SERVER_SEND_REPLY,	/* - server sending reply */
+		RXRPC_CALL_SERVER_AWAIT_ACK,	/* - server awaiting final ACK */
+		RXRPC_CALL_COMPLETE,		/* - call completed */
+		RXRPC_CALL_SERVER_BUSY,		/* - call rejected by busy server */
+		RXRPC_CALL_REMOTELY_ABORTED,	/* - call aborted by peer */
+		RXRPC_CALL_LOCALLY_ABORTED,	/* - call aborted locally on error or close */
+		RXRPC_CALL_NETWORK_ERROR,	/* - call terminated by network error */
+		RXRPC_CALL_DEAD,		/* - call is dead */
+	} state;
+	int			debug_id;	/* debug ID for printks */
+	u8			channel;	/* connection channel occupied by this call */
+
+	/* transmission-phase ACK management */
+	uint8_t			acks_head;	/* offset into window of first entry */
+	uint8_t			acks_tail;	/* offset into window of last entry */
+	uint8_t			acks_winsz;	/* size of un-ACK'd window */
+	uint8_t			acks_unacked;	/* lowest unacked packet in last ACK received */
+	int			acks_latest;	/* serial number of latest ACK received */
+	rxrpc_seq_t		acks_hard;	/* highest definitively ACK'd msg seq */
+	unsigned long		*acks_window;	/* sent packet window
+						 * - elements are pointers with LSB set if ACK'd
+						 */
+
+	/* receive-phase ACK management */
+	rxrpc_seq_t		rx_data_expect;	/* next data seq ID expected to be received */
+	rxrpc_seq_t		rx_data_post;	/* next data seq ID expected to be posted */
+	rxrpc_seq_t		rx_data_recv;	/* last data seq ID encountered by recvmsg */
+	rxrpc_seq_t		rx_data_eaten;	/* last data seq ID consumed by recvmsg */
+	rxrpc_seq_t		rx_first_oos;	/* first packet in rx_oos_queue (or 0) */
+	rxrpc_seq_t		ackr_win_top;	/* top of ACK window (rx_data_eaten is bottom) */
+	rxrpc_seq_net_t		ackr_prev_seq;	/* previous sequence number received */
+	uint8_t			ackr_reason;	/* reason to ACK */
+	__be32			ackr_serial;	/* serial of packet being ACK'd */
+	atomic_t		ackr_not_idle;	/* number of packets in Rx queue */
+
+	/* received packet records, 1 bit per record */
+#define RXRPC_ACKR_WINDOW_ASZ DIV_ROUND_UP(RXRPC_MAXACKS, BITS_PER_LONG)
+	unsigned long		ackr_window[RXRPC_ACKR_WINDOW_ASZ + 1];
+
+	/* the following should all be in net order */
+	__be32			cid;		/* connection ID + channel index  */
+	__be32			call_id;	/* call ID on connection  */
+};
+
+/*
+ * RxRPC key for Kerberos (type-2 security)
+ */
+struct rxkad_key {
+	u16	security_index;		/* RxRPC header security index */
+	u16	ticket_len;		/* length of ticket[] */
+	u32	expiry;			/* time at which expires */
+	u32	kvno;			/* key version number */
+	u8	session_key[8];		/* DES session key */
+	u8	ticket[0];		/* the encrypted ticket */
+};
+
+struct rxrpc_key_payload {
+	struct rxkad_key k;
+};
+
+/*
+ * locally abort an RxRPC call
+ */
+static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code)
+{
+	write_lock_bh(&call->state_lock);
+	if (call->state < RXRPC_CALL_COMPLETE) {
+		call->abort_code = abort_code;
+		call->state = RXRPC_CALL_LOCALLY_ABORTED;
+		set_bit(RXRPC_CALL_ABORT, &call->events);
+	}
+	write_unlock_bh(&call->state_lock);
+}
+
+/*
+ * af_rxrpc.c
+ */
+extern atomic_t rxrpc_n_skbs;
+extern __be32 rxrpc_epoch;
+extern atomic_t rxrpc_debug_id;
+extern struct workqueue_struct *rxrpc_workqueue;
+
+/*
+ * ar-accept.c
+ */
+extern void rxrpc_accept_incoming_calls(struct work_struct *);
+extern struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *,
+					    unsigned long);
+extern int rxrpc_reject_call(struct rxrpc_sock *);
+
+/*
+ * ar-ack.c
+ */
+extern void __rxrpc_propose_ACK(struct rxrpc_call *, uint8_t, __be32, bool);
+extern void rxrpc_propose_ACK(struct rxrpc_call *, uint8_t, __be32, bool);
+extern void rxrpc_process_call(struct work_struct *);
+
+/*
+ * ar-call.c
+ */
+extern struct kmem_cache *rxrpc_call_jar;
+extern struct list_head rxrpc_calls;
+extern rwlock_t rxrpc_call_lock;
+
+extern struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *,
+						struct rxrpc_transport *,
+						struct rxrpc_conn_bundle *,
+						unsigned long, int, gfp_t);
+extern struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *,
+					      struct rxrpc_connection *,
+					      struct rxrpc_header *, gfp_t);
+extern struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *,
+						 unsigned long);
+extern void rxrpc_release_call(struct rxrpc_call *);
+extern void rxrpc_release_calls_on_socket(struct rxrpc_sock *);
+extern void __rxrpc_put_call(struct rxrpc_call *);
+extern void __exit rxrpc_destroy_all_calls(void);
+
+/*
+ * ar-connection.c
+ */
+extern struct list_head rxrpc_connections;
+extern rwlock_t rxrpc_connection_lock;
+
+extern struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *,
+						  struct rxrpc_transport *,
+						  struct key *,
+						  __be16, gfp_t);
+extern void rxrpc_put_bundle(struct rxrpc_transport *,
+			     struct rxrpc_conn_bundle *);
+extern int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_transport *,
+			      struct rxrpc_conn_bundle *, struct rxrpc_call *,
+			      gfp_t);
+extern void rxrpc_put_connection(struct rxrpc_connection *);
+extern void __exit rxrpc_destroy_all_connections(void);
+extern struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *,
+						      struct rxrpc_header *);
+extern struct rxrpc_connection *
+rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_header *,
+			  gfp_t);
+
+/*
+ * ar-connevent.c
+ */
+extern void rxrpc_process_connection(struct work_struct *);
+extern void rxrpc_reject_packet(struct rxrpc_local *, struct sk_buff *);
+extern void rxrpc_reject_packets(struct work_struct *);
+
+/*
+ * ar-error.c
+ */
+extern void rxrpc_UDP_error_report(struct sock *);
+extern void rxrpc_UDP_error_handler(struct work_struct *);
+
+/*
+ * ar-input.c
+ */
+extern unsigned long rxrpc_ack_timeout;
+extern const char *rxrpc_pkts[];
+
+extern void rxrpc_data_ready(struct sock *, int);
+extern int rxrpc_queue_rcv_skb(struct rxrpc_call *, struct sk_buff *, bool,
+			       bool);
+extern void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *);
+
+/*
+ * ar-local.c
+ */
+extern rwlock_t rxrpc_local_lock;
+extern struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *);
+extern void rxrpc_put_local(struct rxrpc_local *);
+extern void __exit rxrpc_destroy_all_locals(void);
+
+/*
+ * ar-key.c
+ */
+extern struct key_type key_type_rxrpc;
+extern struct key_type key_type_rxrpc_s;
+
+extern int rxrpc_request_key(struct rxrpc_sock *, char __user *, int);
+extern int rxrpc_server_keyring(struct rxrpc_sock *, char __user *, int);
+extern int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *,
+				     time_t, u32);
+
+/*
+ * ar-output.c
+ */
+extern int rxrpc_resend_timeout;
+
+extern int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *);
+extern int rxrpc_client_sendmsg(struct kiocb *, struct rxrpc_sock *,
+				struct rxrpc_transport *, struct msghdr *,
+				size_t);
+extern int rxrpc_server_sendmsg(struct kiocb *, struct rxrpc_sock *,
+				struct msghdr *, size_t);
+
+/*
+ * ar-peer.c
+ */
+extern struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *, gfp_t);
+extern void rxrpc_put_peer(struct rxrpc_peer *);
+extern struct rxrpc_peer *rxrpc_find_peer(struct rxrpc_local *,
+					  __be32, __be16);
+extern void __exit rxrpc_destroy_all_peers(void);
+
+/*
+ * ar-proc.c
+ */
+extern const char *rxrpc_call_states[];
+extern struct file_operations rxrpc_call_seq_fops;
+extern struct file_operations rxrpc_connection_seq_fops;
+
+/*
+ * ar-recvmsg.c
+ */
+extern void rxrpc_remove_user_ID(struct rxrpc_sock *, struct rxrpc_call *);
+extern int rxrpc_recvmsg(struct kiocb *, struct socket *, struct msghdr *,
+			 size_t, int);
+
+/*
+ * ar-security.c
+ */
+extern int rxrpc_register_security(struct rxrpc_security *);
+extern void rxrpc_unregister_security(struct rxrpc_security *);
+extern int rxrpc_init_client_conn_security(struct rxrpc_connection *);
+extern int rxrpc_init_server_conn_security(struct rxrpc_connection *);
+extern int rxrpc_secure_packet(const struct rxrpc_call *, struct sk_buff *,
+			       size_t, void *);
+extern int rxrpc_verify_packet(const struct rxrpc_call *, struct sk_buff *,
+			       u32 *);
+extern void rxrpc_clear_conn_security(struct rxrpc_connection *);
+
+/*
+ * ar-skbuff.c
+ */
+extern void rxrpc_packet_destructor(struct sk_buff *);
+
+/*
+ * ar-transport.c
+ */
+extern struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *,
+						   struct rxrpc_peer *,
+						   gfp_t);
+extern void rxrpc_put_transport(struct rxrpc_transport *);
+extern void __exit rxrpc_destroy_all_transports(void);
+extern struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *,
+						    struct rxrpc_peer *);
+
+/*
+ * debug tracing
+ */
+extern unsigned rxrpc_debug;
+
+#define dbgprintk(FMT,...) \
+	printk("[%x%-6.6s] "FMT"\n", smp_processor_id(), current->comm ,##__VA_ARGS__)
+
+/* make sure we maintain the format strings, even when debugging is disabled */
+static inline __attribute__((format(printf,1,2)))
+void _dbprintk(const char *fmt, ...)
+{
+}
+
+#define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kdebug(FMT,...)	dbgprintk("    "FMT ,##__VA_ARGS__)
+#define kproto(FMT,...)	dbgprintk("### "FMT ,##__VA_ARGS__)
+#define knet(FMT,...)	dbgprintk("@@@ "FMT ,##__VA_ARGS__)
+
+
+#if defined(__KDEBUG)
+#define _enter(FMT,...)	kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...)	kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...)	kdebug(FMT,##__VA_ARGS__)
+#define _proto(FMT,...)	kproto(FMT,##__VA_ARGS__)
+#define _net(FMT,...)	knet(FMT,##__VA_ARGS__)
+
+#elif defined(CONFIG_AF_RXRPC_DEBUG)
+#define RXRPC_DEBUG_KENTER	0x01
+#define RXRPC_DEBUG_KLEAVE	0x02
+#define RXRPC_DEBUG_KDEBUG	0x04
+#define RXRPC_DEBUG_KPROTO	0x08
+#define RXRPC_DEBUG_KNET	0x10
+
+#define _enter(FMT,...)					\
+do {							\
+	if (unlikely(rxrpc_debug & RXRPC_DEBUG_KENTER))	\
+		kenter(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _leave(FMT,...)					\
+do {							\
+	if (unlikely(rxrpc_debug & RXRPC_DEBUG_KLEAVE))	\
+		kleave(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _debug(FMT,...)					\
+do {							\
+	if (unlikely(rxrpc_debug & RXRPC_DEBUG_KDEBUG))	\
+		kdebug(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _proto(FMT,...)					\
+do {							\
+	if (unlikely(rxrpc_debug & RXRPC_DEBUG_KPROTO))	\
+		kproto(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#define _net(FMT,...)					\
+do {							\
+	if (unlikely(rxrpc_debug & RXRPC_DEBUG_KNET))	\
+		knet(FMT,##__VA_ARGS__);		\
+} while (0)
+
+#else
+#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _debug(FMT,...)	_dbprintk("    "FMT ,##__VA_ARGS__)
+#define _proto(FMT,...)	_dbprintk("### "FMT ,##__VA_ARGS__)
+#define _net(FMT,...)	_dbprintk("@@@ "FMT ,##__VA_ARGS__)
+#endif
+
+/*
+ * debug assertion checking
+ */
+#if 1 // defined(__KDEBUGALL)
+
+#define ASSERT(X)						\
+do {								\
+	if (unlikely(!(X))) {					\
+		printk(KERN_ERR "\n");				\
+		printk(KERN_ERR "RxRPC: Assertion failed\n");	\
+		BUG();						\
+	}							\
+} while(0)
+
+#define ASSERTCMP(X, OP, Y)						\
+do {									\
+	if (unlikely(!((X) OP (Y)))) {					\
+		printk(KERN_ERR "\n");					\
+		printk(KERN_ERR "RxRPC: Assertion failed\n");		\
+		printk(KERN_ERR "%lu " #OP " %lu is false\n",		\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",	\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		BUG();							\
+	}								\
+} while(0)
+
+#define ASSERTIF(C, X)						\
+do {								\
+	if (unlikely((C) && !(X))) {				\
+		printk(KERN_ERR "\n");				\
+		printk(KERN_ERR "RxRPC: Assertion failed\n");	\
+		BUG();						\
+	}							\
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y)					\
+do {									\
+	if (unlikely((C) && !((X) OP (Y)))) {				\
+		printk(KERN_ERR "\n");					\
+		printk(KERN_ERR "RxRPC: Assertion failed\n");		\
+		printk(KERN_ERR "%lu " #OP " %lu is false\n",		\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",	\
+		       (unsigned long)(X), (unsigned long)(Y));		\
+		BUG();							\
+	}								\
+} while(0)
+
+#else
+
+#define ASSERT(X)				\
+do {						\
+} while(0)
+
+#define ASSERTCMP(X, OP, Y)			\
+do {						\
+} while(0)
+
+#define ASSERTIF(C, X)				\
+do {						\
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y)		\
+do {						\
+} while(0)
+
+#endif /* __KDEBUGALL */
+
+/*
+ * socket buffer accounting / leak finding
+ */
+static inline void __rxrpc_new_skb(struct sk_buff *skb, const char *fn)
+{
+	//_net("new skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
+	//atomic_inc(&rxrpc_n_skbs);
+}
+
+#define rxrpc_new_skb(skb) __rxrpc_new_skb((skb), __func__)
+
+static inline void __rxrpc_kill_skb(struct sk_buff *skb, const char *fn)
+{
+	//_net("kill skb %p %s [%d]", skb, fn, atomic_read(&rxrpc_n_skbs));
+	//atomic_dec(&rxrpc_n_skbs);
+}
+
+#define rxrpc_kill_skb(skb) __rxrpc_kill_skb((skb), __func__)
+
+static inline void __rxrpc_free_skb(struct sk_buff *skb, const char *fn)
+{
+	if (skb) {
+		CHECK_SLAB_OKAY(&skb->users);
+		//_net("free skb %p %s [%d]",
+		//     skb, fn, atomic_read(&rxrpc_n_skbs));
+		//atomic_dec(&rxrpc_n_skbs);
+		kfree_skb(skb);
+	}
+}
+
+#define rxrpc_free_skb(skb) __rxrpc_free_skb((skb), __func__)
+
+static inline void rxrpc_purge_queue(struct sk_buff_head *list)
+{
+	struct sk_buff *skb;
+	while ((skb = skb_dequeue((list))) != NULL)
+		rxrpc_free_skb(skb);
+}
+
+static inline void __rxrpc_get_local(struct rxrpc_local *local, const char *f)
+{
+	CHECK_SLAB_OKAY(&local->usage);
+	if (atomic_inc_return(&local->usage) == 1)
+		printk("resurrected (%s)\n", f);
+}
+
+#define rxrpc_get_local(LOCAL) __rxrpc_get_local((LOCAL), __func__)
+
+#define rxrpc_get_call(CALL)				\
+do {							\
+	CHECK_SLAB_OKAY(&(CALL)->usage);		\
+	if (atomic_inc_return(&(CALL)->usage) == 1)	\
+		BUG();					\
+} while(0)
+
+#define rxrpc_put_call(CALL)				\
+do {							\
+	__rxrpc_put_call(CALL);				\
+} while(0)
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
new file mode 100644
index 0000000..7e049ff
--- /dev/null
+++ b/net/rxrpc/ar-key.c
@@ -0,0 +1,334 @@
+/* RxRPC key management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * RxRPC keys should have a description of describing their purpose:
+ *	"afs@CAMBRIDGE.REDHAT.COM>
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/key.h>
+#include <linux/crypto.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <keys/rxrpc-type.h>
+#include <keys/user-type.h>
+#include "ar-internal.h"
+
+static int rxrpc_instantiate(struct key *, const void *, size_t);
+static int rxrpc_instantiate_s(struct key *, const void *, size_t);
+static void rxrpc_destroy(struct key *);
+static void rxrpc_destroy_s(struct key *);
+static void rxrpc_describe(const struct key *, struct seq_file *);
+
+/*
+ * rxrpc defined keys take an arbitrary string as the description and an
+ * arbitrary blob of data as the payload
+ */
+struct key_type key_type_rxrpc = {
+	.name		= "rxrpc",
+	.instantiate	= rxrpc_instantiate,
+	.match		= user_match,
+	.destroy	= rxrpc_destroy,
+	.describe	= rxrpc_describe,
+};
+
+EXPORT_SYMBOL(key_type_rxrpc);
+
+/*
+ * rxrpc server defined keys take "<serviceId>:<securityIndex>" as the
+ * description and an 8-byte decryption key as the payload
+ */
+struct key_type key_type_rxrpc_s = {
+	.name		= "rxrpc_s",
+	.instantiate	= rxrpc_instantiate_s,
+	.match		= user_match,
+	.destroy	= rxrpc_destroy_s,
+	.describe	= rxrpc_describe,
+};
+
+/*
+ * instantiate an rxrpc defined key
+ * data should be of the form:
+ *	OFFSET	LEN	CONTENT
+ *	0	4	key interface version number
+ *	4	2	security index (type)
+ *	6	2	ticket length
+ *	8	4	key expiry time (time_t)
+ *	12	4	kvno
+ *	16	8	session key
+ *	24	[len]	ticket
+ *
+ * if no data is provided, then a no-security key is made
+ */
+static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
+{
+	const struct rxkad_key *tsec;
+	struct rxrpc_key_payload *upayload;
+	size_t plen;
+	u32 kver;
+	int ret;
+
+	_enter("{%x},,%zu", key_serial(key), datalen);
+
+	/* handle a no-security key */
+	if (!data && datalen == 0)
+		return 0;
+
+	/* get the key interface version number */
+	ret = -EINVAL;
+	if (datalen <= 4 || !data)
+		goto error;
+	memcpy(&kver, data, sizeof(kver));
+	data += sizeof(kver);
+	datalen -= sizeof(kver);
+
+	_debug("KEY I/F VERSION: %u", kver);
+
+	ret = -EKEYREJECTED;
+	if (kver != 1)
+		goto error;
+
+	/* deal with a version 1 key */
+	ret = -EINVAL;
+	if (datalen < sizeof(*tsec))
+		goto error;
+
+	tsec = data;
+	if (datalen != sizeof(*tsec) + tsec->ticket_len)
+		goto error;
+
+	_debug("SCIX: %u", tsec->security_index);
+	_debug("TLEN: %u", tsec->ticket_len);
+	_debug("EXPY: %x", tsec->expiry);
+	_debug("KVNO: %u", tsec->kvno);
+	_debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
+	       tsec->session_key[0], tsec->session_key[1],
+	       tsec->session_key[2], tsec->session_key[3],
+	       tsec->session_key[4], tsec->session_key[5],
+	       tsec->session_key[6], tsec->session_key[7]);
+	if (tsec->ticket_len >= 8)
+		_debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
+		       tsec->ticket[0], tsec->ticket[1],
+		       tsec->ticket[2], tsec->ticket[3],
+		       tsec->ticket[4], tsec->ticket[5],
+		       tsec->ticket[6], tsec->ticket[7]);
+
+	ret = -EPROTONOSUPPORT;
+	if (tsec->security_index != 2)
+		goto error;
+
+	key->type_data.x[0] = tsec->security_index;
+
+	plen = sizeof(*upayload) + tsec->ticket_len;
+	ret = key_payload_reserve(key, plen);
+	if (ret < 0)
+		goto error;
+
+	ret = -ENOMEM;
+	upayload = kmalloc(plen, GFP_KERNEL);
+	if (!upayload)
+		goto error;
+
+	/* attach the data */
+	memcpy(&upayload->k, tsec, sizeof(*tsec));
+	memcpy(&upayload->k.ticket, (void *)tsec + sizeof(*tsec),
+	       tsec->ticket_len);
+	key->payload.data = upayload;
+	key->expiry = tsec->expiry;
+	ret = 0;
+
+error:
+	return ret;
+}
+
+/*
+ * instantiate a server secret key
+ * data should be a pointer to the 8-byte secret key
+ */
+static int rxrpc_instantiate_s(struct key *key, const void *data,
+			       size_t datalen)
+{
+	struct crypto_blkcipher *ci;
+
+	_enter("{%x},,%zu", key_serial(key), datalen);
+
+	if (datalen != 8)
+		return -EINVAL;
+
+	memcpy(&key->type_data, data, 8);
+
+	ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ci)) {
+		_leave(" = %ld", PTR_ERR(ci));
+		return PTR_ERR(ci);
+	}
+
+	if (crypto_blkcipher_setkey(ci, data, 8) < 0)
+		BUG();
+
+	key->payload.data = ci;
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * dispose of the data dangling from the corpse of a rxrpc key
+ */
+static void rxrpc_destroy(struct key *key)
+{
+	kfree(key->payload.data);
+}
+
+/*
+ * dispose of the data dangling from the corpse of a rxrpc key
+ */
+static void rxrpc_destroy_s(struct key *key)
+{
+	if (key->payload.data) {
+		crypto_free_blkcipher(key->payload.data);
+		key->payload.data = NULL;
+	}
+}
+
+/*
+ * describe the rxrpc key
+ */
+static void rxrpc_describe(const struct key *key, struct seq_file *m)
+{
+	seq_puts(m, key->description);
+}
+
+/*
+ * grab the security key for a socket
+ */
+int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
+{
+	struct key *key;
+	char *description;
+
+	_enter("");
+
+	if (optlen <= 0 || optlen > PAGE_SIZE - 1)
+		return -EINVAL;
+
+	description = kmalloc(optlen + 1, GFP_KERNEL);
+	if (!description)
+		return -ENOMEM;
+
+	if (copy_from_user(description, optval, optlen)) {
+		kfree(description);
+		return -EFAULT;
+	}
+	description[optlen] = 0;
+
+	key = request_key(&key_type_rxrpc, description, NULL);
+	if (IS_ERR(key)) {
+		kfree(description);
+		_leave(" = %ld", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	rx->key = key;
+	kfree(description);
+	_leave(" = 0 [key %x]", key->serial);
+	return 0;
+}
+
+/*
+ * grab the security keyring for a server socket
+ */
+int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
+			 int optlen)
+{
+	struct key *key;
+	char *description;
+
+	_enter("");
+
+	if (optlen <= 0 || optlen > PAGE_SIZE - 1)
+		return -EINVAL;
+
+	description = kmalloc(optlen + 1, GFP_KERNEL);
+	if (!description)
+		return -ENOMEM;
+
+	if (copy_from_user(description, optval, optlen)) {
+		kfree(description);
+		return -EFAULT;
+	}
+	description[optlen] = 0;
+
+	key = request_key(&key_type_keyring, description, NULL);
+	if (IS_ERR(key)) {
+		kfree(description);
+		_leave(" = %ld", PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+
+	rx->securities = key;
+	kfree(description);
+	_leave(" = 0 [key %x]", key->serial);
+	return 0;
+}
+
+/*
+ * generate a server data key
+ */
+int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
+			      const void *session_key,
+			      time_t expiry,
+			      u32 kvno)
+{
+	struct key *key;
+	int ret;
+
+	struct {
+		u32 kver;
+		struct rxkad_key tsec;
+	} data;
+
+	_enter("");
+
+	key = key_alloc(&key_type_rxrpc, "x", 0, 0, current, 0,
+			KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(key)) {
+		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
+		return -ENOMEM;
+	}
+
+	_debug("key %d", key_serial(key));
+
+	data.kver = 1;
+	data.tsec.security_index = 2;
+	data.tsec.ticket_len = 0;
+	data.tsec.expiry = expiry;
+	data.tsec.kvno = 0;
+
+	memcpy(&data.tsec.session_key, session_key,
+	       sizeof(data.tsec.session_key));
+
+	ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
+	if (ret < 0)
+		goto error;
+
+	conn->key = key;
+	_leave(" = 0 [%d]", key_serial(key));
+	return 0;
+
+error:
+	key_revoke(key);
+	key_put(key);
+	_leave(" = -ENOMEM [ins %d]", ret);
+	return -ENOMEM;
+}
+
+EXPORT_SYMBOL(rxrpc_get_server_data_key);
diff --git a/net/rxrpc/ar-local.c b/net/rxrpc/ar-local.c
new file mode 100644
index 0000000..fe03f71
--- /dev/null
+++ b/net/rxrpc/ar-local.c
@@ -0,0 +1,309 @@
+/* AF_RXRPC local endpoint management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static LIST_HEAD(rxrpc_locals);
+DEFINE_RWLOCK(rxrpc_local_lock);
+static DECLARE_RWSEM(rxrpc_local_sem);
+static DECLARE_WAIT_QUEUE_HEAD(rxrpc_local_wq);
+
+static void rxrpc_destroy_local(struct work_struct *work);
+
+/*
+ * allocate a new local
+ */
+static
+struct rxrpc_local *rxrpc_alloc_local(struct sockaddr_rxrpc *srx)
+{
+	struct rxrpc_local *local;
+
+	local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
+	if (local) {
+		INIT_WORK(&local->destroyer, &rxrpc_destroy_local);
+		INIT_WORK(&local->acceptor, &rxrpc_accept_incoming_calls);
+		INIT_WORK(&local->rejecter, &rxrpc_reject_packets);
+		INIT_LIST_HEAD(&local->services);
+		INIT_LIST_HEAD(&local->link);
+		init_rwsem(&local->defrag_sem);
+		skb_queue_head_init(&local->accept_queue);
+		skb_queue_head_init(&local->reject_queue);
+		spin_lock_init(&local->lock);
+		rwlock_init(&local->services_lock);
+		atomic_set(&local->usage, 1);
+		local->debug_id = atomic_inc_return(&rxrpc_debug_id);
+		memcpy(&local->srx, srx, sizeof(*srx));
+	}
+
+	_leave(" = %p", local);
+	return local;
+}
+
+/*
+ * create the local socket
+ * - must be called with rxrpc_local_sem writelocked
+ */
+static int rxrpc_create_local(struct rxrpc_local *local)
+{
+	struct sock *sock;
+	int ret, opt;
+
+	_enter("%p{%d}", local, local->srx.transport_type);
+
+	/* create a socket to represent the local endpoint */
+	ret = sock_create_kern(PF_INET, local->srx.transport_type, IPPROTO_UDP,
+			       &local->socket);
+	if (ret < 0) {
+		_leave(" = %d [socket]", ret);
+		return ret;
+	}
+
+	/* if a local address was supplied then bind it */
+	if (local->srx.transport_len > sizeof(sa_family_t)) {
+		_debug("bind");
+		ret = kernel_bind(local->socket,
+				  (struct sockaddr *) &local->srx.transport,
+				  local->srx.transport_len);
+		if (ret < 0) {
+			_debug("bind failed");
+			goto error;
+		}
+	}
+
+	/* we want to receive ICMP errors */
+	opt = 1;
+	ret = kernel_setsockopt(local->socket, SOL_IP, IP_RECVERR,
+				(char *) &opt, sizeof(opt));
+	if (ret < 0) {
+		_debug("setsockopt failed");
+		goto error;
+	}
+
+	/* we want to set the don't fragment bit */
+	opt = IP_PMTUDISC_DO;
+	ret = kernel_setsockopt(local->socket, SOL_IP, IP_MTU_DISCOVER,
+				(char *) &opt, sizeof(opt));
+	if (ret < 0) {
+		_debug("setsockopt failed");
+		goto error;
+	}
+
+	write_lock_bh(&rxrpc_local_lock);
+	list_add(&local->link, &rxrpc_locals);
+	write_unlock_bh(&rxrpc_local_lock);
+
+	/* set the socket up */
+	sock = local->socket->sk;
+	sock->sk_user_data	= local;
+	sock->sk_data_ready	= rxrpc_data_ready;
+	sock->sk_error_report	= rxrpc_UDP_error_report;
+	_leave(" = 0");
+	return 0;
+
+error:
+	local->socket->ops->shutdown(local->socket, 2);
+	local->socket->sk->sk_user_data = NULL;
+	sock_release(local->socket);
+	local->socket = NULL;
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * create a new local endpoint using the specified UDP address
+ */
+struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx)
+{
+	struct rxrpc_local *local;
+	int ret;
+
+	_enter("{%d,%u,%u.%u.%u.%u+%hu}",
+	       srx->transport_type,
+	       srx->transport.family,
+	       NIPQUAD(srx->transport.sin.sin_addr),
+	       ntohs(srx->transport.sin.sin_port));
+
+	down_write(&rxrpc_local_sem);
+
+	/* see if we have a suitable local local endpoint already */
+	read_lock_bh(&rxrpc_local_lock);
+
+	list_for_each_entry(local, &rxrpc_locals, link) {
+		_debug("CMP {%d,%u,%u.%u.%u.%u+%hu}",
+		       local->srx.transport_type,
+		       local->srx.transport.family,
+		       NIPQUAD(local->srx.transport.sin.sin_addr),
+		       ntohs(local->srx.transport.sin.sin_port));
+
+		if (local->srx.transport_type != srx->transport_type ||
+		    local->srx.transport.family != srx->transport.family)
+			continue;
+
+		switch (srx->transport.family) {
+		case AF_INET:
+			if (local->srx.transport.sin.sin_port !=
+			    srx->transport.sin.sin_port)
+				continue;
+			if (memcmp(&local->srx.transport.sin.sin_addr,
+				   &srx->transport.sin.sin_addr,
+				   sizeof(struct in_addr)) != 0)
+				continue;
+			goto found_local;
+
+		default:
+			BUG();
+		}
+	}
+
+	read_unlock_bh(&rxrpc_local_lock);
+
+	/* we didn't find one, so we need to create one */
+	local = rxrpc_alloc_local(srx);
+	if (!local) {
+		up_write(&rxrpc_local_sem);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = rxrpc_create_local(local);
+	if (ret < 0) {
+		up_write(&rxrpc_local_sem);
+		kfree(local);
+		_leave(" = %d", ret);
+		return ERR_PTR(ret);
+	}
+
+	up_write(&rxrpc_local_sem);
+
+	_net("LOCAL new %d {%d,%u,%u.%u.%u.%u+%hu}",
+	     local->debug_id,
+	     local->srx.transport_type,
+	     local->srx.transport.family,
+	     NIPQUAD(local->srx.transport.sin.sin_addr),
+	     ntohs(local->srx.transport.sin.sin_port));
+
+	_leave(" = %p [new]", local);
+	return local;
+
+found_local:
+	rxrpc_get_local(local);
+	read_unlock_bh(&rxrpc_local_lock);
+	up_write(&rxrpc_local_sem);
+
+	_net("LOCAL old %d {%d,%u,%u.%u.%u.%u+%hu}",
+	     local->debug_id,
+	     local->srx.transport_type,
+	     local->srx.transport.family,
+	     NIPQUAD(local->srx.transport.sin.sin_addr),
+	     ntohs(local->srx.transport.sin.sin_port));
+
+	_leave(" = %p [reuse]", local);
+	return local;
+}
+
+/*
+ * release a local endpoint
+ */
+void rxrpc_put_local(struct rxrpc_local *local)
+{
+	_enter("%p{u=%d}", local, atomic_read(&local->usage));
+
+	ASSERTCMP(atomic_read(&local->usage), >, 0);
+
+	/* to prevent a race, the decrement and the dequeue must be effectively
+	 * atomic */
+	write_lock_bh(&rxrpc_local_lock);
+	if (unlikely(atomic_dec_and_test(&local->usage))) {
+		_debug("destroy local");
+		rxrpc_queue_work(&local->destroyer);
+	}
+	write_unlock_bh(&rxrpc_local_lock);
+	_leave("");
+}
+
+/*
+ * destroy a local endpoint
+ */
+static void rxrpc_destroy_local(struct work_struct *work)
+{
+	struct rxrpc_local *local =
+		container_of(work, struct rxrpc_local, destroyer);
+
+	_enter("%p{%d}", local, atomic_read(&local->usage));
+
+	down_write(&rxrpc_local_sem);
+
+	write_lock_bh(&rxrpc_local_lock);
+	if (atomic_read(&local->usage) > 0) {
+		write_unlock_bh(&rxrpc_local_lock);
+		up_read(&rxrpc_local_sem);
+		_leave(" [resurrected]");
+		return;
+	}
+
+	list_del(&local->link);
+	local->socket->sk->sk_user_data = NULL;
+	write_unlock_bh(&rxrpc_local_lock);
+
+	downgrade_write(&rxrpc_local_sem);
+
+	ASSERT(list_empty(&local->services));
+	ASSERT(!work_pending(&local->acceptor));
+	ASSERT(!work_pending(&local->rejecter));
+
+	/* finish cleaning up the local descriptor */
+	rxrpc_purge_queue(&local->accept_queue);
+	rxrpc_purge_queue(&local->reject_queue);
+	local->socket->ops->shutdown(local->socket, 2);
+	sock_release(local->socket);
+
+	up_read(&rxrpc_local_sem);
+
+	_net("DESTROY LOCAL %d", local->debug_id);
+	kfree(local);
+
+	if (list_empty(&rxrpc_locals))
+		wake_up_all(&rxrpc_local_wq);
+
+	_leave("");
+}
+
+/*
+ * preemptively destroy all local local endpoint rather than waiting for
+ * them to be destroyed
+ */
+void __exit rxrpc_destroy_all_locals(void)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	_enter("");
+
+	/* we simply have to wait for them to go away */
+	if (!list_empty(&rxrpc_locals)) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&rxrpc_local_wq, &myself);
+
+		while (!list_empty(&rxrpc_locals)) {
+			schedule();
+			set_current_state(TASK_UNINTERRUPTIBLE);
+		}
+
+		remove_wait_queue(&rxrpc_local_wq, &myself);
+		set_current_state(TASK_RUNNING);
+	}
+
+	_leave("");
+}
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c
new file mode 100644
index 0000000..591c442
--- /dev/null
+++ b/net/rxrpc/ar-output.c
@@ -0,0 +1,734 @@
+/* RxRPC packet transmission
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/circ_buf.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+int rxrpc_resend_timeout = 4;
+
+static int rxrpc_send_data(struct kiocb *iocb,
+			   struct rxrpc_sock *rx,
+			   struct rxrpc_call *call,
+			   struct msghdr *msg, size_t len);
+
+/*
+ * extract control messages from the sendmsg() control buffer
+ */
+static int rxrpc_sendmsg_cmsg(struct rxrpc_sock *rx, struct msghdr *msg,
+			      unsigned long *user_call_ID,
+			      enum rxrpc_command *command,
+			      u32 *abort_code,
+			      bool server)
+{
+	struct cmsghdr *cmsg;
+	int len;
+
+	*command = RXRPC_CMD_SEND_DATA;
+
+	if (msg->msg_controllen == 0)
+		return -EINVAL;
+
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		if (!CMSG_OK(msg, cmsg))
+			return -EINVAL;
+
+		len = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
+		_debug("CMSG %d, %d, %d",
+		       cmsg->cmsg_level, cmsg->cmsg_type, len);
+
+		if (cmsg->cmsg_level != SOL_RXRPC)
+			continue;
+
+		switch (cmsg->cmsg_type) {
+		case RXRPC_USER_CALL_ID:
+			if (msg->msg_flags & MSG_CMSG_COMPAT) {
+				if (len != sizeof(u32))
+					return -EINVAL;
+				*user_call_ID = *(u32 *) CMSG_DATA(cmsg);
+			} else {
+				if (len != sizeof(unsigned long))
+					return -EINVAL;
+				*user_call_ID = *(unsigned long *)
+					CMSG_DATA(cmsg);
+			}
+			_debug("User Call ID %lx", *user_call_ID);
+			break;
+
+		case RXRPC_ABORT:
+			if (*command != RXRPC_CMD_SEND_DATA)
+				return -EINVAL;
+			*command = RXRPC_CMD_SEND_ABORT;
+			if (len != sizeof(*abort_code))
+				return -EINVAL;
+			*abort_code = *(unsigned int *) CMSG_DATA(cmsg);
+			_debug("Abort %x", *abort_code);
+			if (*abort_code == 0)
+				return -EINVAL;
+			break;
+
+		case RXRPC_ACCEPT:
+			if (*command != RXRPC_CMD_SEND_DATA)
+				return -EINVAL;
+			*command = RXRPC_CMD_ACCEPT;
+			if (len != 0)
+				return -EINVAL;
+			if (!server)
+				return -EISCONN;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * abort a call, sending an ABORT packet to the peer
+ */
+static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code)
+{
+	write_lock_bh(&call->state_lock);
+
+	if (call->state <= RXRPC_CALL_COMPLETE) {
+		call->state = RXRPC_CALL_LOCALLY_ABORTED;
+		call->abort_code = abort_code;
+		set_bit(RXRPC_CALL_ABORT, &call->events);
+		del_timer_sync(&call->resend_timer);
+		del_timer_sync(&call->ack_timer);
+		clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+		clear_bit(RXRPC_CALL_ACK, &call->events);
+		clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+		rxrpc_queue_call(call);
+	}
+
+	write_unlock_bh(&call->state_lock);
+}
+
+/*
+ * send a message forming part of a client call through an RxRPC socket
+ * - caller holds the socket locked
+ * - the socket may be either a client socket or a server socket
+ */
+int rxrpc_client_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx,
+			 struct rxrpc_transport *trans, struct msghdr *msg,
+			 size_t len)
+{
+	struct rxrpc_conn_bundle *bundle;
+	enum rxrpc_command cmd;
+	struct rxrpc_call *call;
+	unsigned long user_call_ID = 0;
+	struct key *key;
+	__be16 service_id;
+	u32 abort_code = 0;
+	int ret;
+
+	_enter("");
+
+	ASSERT(trans != NULL);
+
+	ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code,
+				 false);
+	if (ret < 0)
+		return ret;
+
+	bundle = NULL;
+	if (trans) {
+		service_id = rx->service_id;
+		if (msg->msg_name) {
+			struct sockaddr_rxrpc *srx =
+				(struct sockaddr_rxrpc *) msg->msg_name;
+			service_id = htons(srx->srx_service);
+		}
+		key = rx->key;
+		if (key && !rx->key->payload.data)
+			key = NULL;
+		bundle = rxrpc_get_bundle(rx, trans, key, service_id,
+					  GFP_KERNEL);
+		if (IS_ERR(bundle))
+			return PTR_ERR(bundle);
+	}
+
+	call = rxrpc_get_client_call(rx, trans, bundle, user_call_ID,
+				     abort_code == 0, GFP_KERNEL);
+	if (trans)
+		rxrpc_put_bundle(trans, bundle);
+	if (IS_ERR(call)) {
+		_leave(" = %ld", PTR_ERR(call));
+		return PTR_ERR(call);
+	}
+
+	_debug("CALL %d USR %lx ST %d on CONN %p",
+	       call->debug_id, call->user_call_ID, call->state, call->conn);
+
+	if (call->state >= RXRPC_CALL_COMPLETE) {
+		/* it's too late for this call */
+		ret = -ESHUTDOWN;
+	} else if (cmd == RXRPC_CMD_SEND_ABORT) {
+		rxrpc_send_abort(call, abort_code);
+	} else if (cmd != RXRPC_CMD_SEND_DATA) {
+		ret = -EINVAL;
+	} else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST) {
+		/* request phase complete for this client call */
+		ret = -EPROTO;
+	} else {
+		ret = rxrpc_send_data(iocb, rx, call, msg, len);
+	}
+
+	rxrpc_put_call(call);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/**
+ * rxrpc_kernel_send_data - Allow a kernel service to send data on a call
+ * @call: The call to send data through
+ * @msg: The data to send
+ * @len: The amount of data to send
+ *
+ * Allow a kernel service to send data on a call.  The call must be in an state
+ * appropriate to sending data.  No control data should be supplied in @msg,
+ * nor should an address be supplied.  MSG_MORE should be flagged if there's
+ * more data to come, otherwise this data will end the transmission phase.
+ */
+int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,
+			   size_t len)
+{
+	int ret;
+
+	_enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]);
+
+	ASSERTCMP(msg->msg_name, ==, NULL);
+	ASSERTCMP(msg->msg_control, ==, NULL);
+
+	lock_sock(&call->socket->sk);
+
+	_debug("CALL %d USR %lx ST %d on CONN %p",
+	       call->debug_id, call->user_call_ID, call->state, call->conn);
+
+	if (call->state >= RXRPC_CALL_COMPLETE) {
+		ret = -ESHUTDOWN; /* it's too late for this call */
+	} else if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
+		   call->state != RXRPC_CALL_SERVER_ACK_REQUEST &&
+		   call->state != RXRPC_CALL_SERVER_SEND_REPLY) {
+		ret = -EPROTO; /* request phase complete for this client call */
+	} else {
+		mm_segment_t oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		ret = rxrpc_send_data(NULL, call->socket, call, msg, len);
+		set_fs(oldfs);
+	}
+
+	release_sock(&call->socket->sk);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_send_data);
+
+/*
+ * rxrpc_kernel_abort_call - Allow a kernel service to abort a call
+ * @call: The call to be aborted
+ * @abort_code: The abort code to stick into the ABORT packet
+ *
+ * Allow a kernel service to abort a call, if it's still in an abortable state.
+ */
+void rxrpc_kernel_abort_call(struct rxrpc_call *call, u32 abort_code)
+{
+	_enter("{%d},%d", call->debug_id, abort_code);
+
+	lock_sock(&call->socket->sk);
+
+	_debug("CALL %d USR %lx ST %d on CONN %p",
+	       call->debug_id, call->user_call_ID, call->state, call->conn);
+
+	if (call->state < RXRPC_CALL_COMPLETE)
+		rxrpc_send_abort(call, abort_code);
+
+	release_sock(&call->socket->sk);
+	_leave("");
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_abort_call);
+
+/*
+ * send a message through a server socket
+ * - caller holds the socket locked
+ */
+int rxrpc_server_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx,
+			 struct msghdr *msg, size_t len)
+{
+	enum rxrpc_command cmd;
+	struct rxrpc_call *call;
+	unsigned long user_call_ID = 0;
+	u32 abort_code = 0;
+	int ret;
+
+	_enter("");
+
+	ret = rxrpc_sendmsg_cmsg(rx, msg, &user_call_ID, &cmd, &abort_code,
+				 true);
+	if (ret < 0)
+		return ret;
+
+	if (cmd == RXRPC_CMD_ACCEPT) {
+		call = rxrpc_accept_call(rx, user_call_ID);
+		if (IS_ERR(call))
+			return PTR_ERR(call);
+		rxrpc_put_call(call);
+		return 0;
+	}
+
+	call = rxrpc_find_server_call(rx, user_call_ID);
+	if (!call)
+		return -EBADSLT;
+	if (call->state >= RXRPC_CALL_COMPLETE) {
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	switch (cmd) {
+	case RXRPC_CMD_SEND_DATA:
+		if (call->state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
+		    call->state != RXRPC_CALL_SERVER_ACK_REQUEST &&
+		    call->state != RXRPC_CALL_SERVER_SEND_REPLY) {
+			/* Tx phase not yet begun for this call */
+			ret = -EPROTO;
+			break;
+		}
+
+		ret = rxrpc_send_data(iocb, rx, call, msg, len);
+		break;
+
+	case RXRPC_CMD_SEND_ABORT:
+		rxrpc_send_abort(call, abort_code);
+		break;
+	default:
+		BUG();
+	}
+
+	out:
+	rxrpc_put_call(call);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * send a packet through the transport endpoint
+ */
+int rxrpc_send_packet(struct rxrpc_transport *trans, struct sk_buff *skb)
+{
+	struct kvec iov[1];
+	struct msghdr msg;
+	int ret, opt;
+
+	_enter(",{%d}", skb->len);
+
+	iov[0].iov_base = skb->head;
+	iov[0].iov_len = skb->len;
+
+	msg.msg_name = &trans->peer->srx.transport.sin;
+	msg.msg_namelen = sizeof(trans->peer->srx.transport.sin);
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+
+	/* send the packet with the don't fragment bit set if we currently
+	 * think it's small enough */
+	if (skb->len - sizeof(struct rxrpc_header) < trans->peer->maxdata) {
+		down_read(&trans->local->defrag_sem);
+		/* send the packet by UDP
+		 * - returns -EMSGSIZE if UDP would have to fragment the packet
+		 *   to go out of the interface
+		 *   - in which case, we'll have processed the ICMP error
+		 *     message and update the peer record
+		 */
+		ret = kernel_sendmsg(trans->local->socket, &msg, iov, 1,
+				     iov[0].iov_len);
+
+		up_read(&trans->local->defrag_sem);
+		if (ret == -EMSGSIZE)
+			goto send_fragmentable;
+
+		_leave(" = %d [%u]", ret, trans->peer->maxdata);
+		return ret;
+	}
+
+send_fragmentable:
+	/* attempt to send this message with fragmentation enabled */
+	_debug("send fragment");
+
+	down_write(&trans->local->defrag_sem);
+	opt = IP_PMTUDISC_DONT;
+	ret = kernel_setsockopt(trans->local->socket, SOL_IP, IP_MTU_DISCOVER,
+				(char *) &opt, sizeof(opt));
+	if (ret == 0) {
+		ret = kernel_sendmsg(trans->local->socket, &msg, iov, 1,
+				     iov[0].iov_len);
+
+		opt = IP_PMTUDISC_DO;
+		kernel_setsockopt(trans->local->socket, SOL_IP,
+				  IP_MTU_DISCOVER, (char *) &opt, sizeof(opt));
+	}
+
+	up_write(&trans->local->defrag_sem);
+	_leave(" = %d [frag %u]", ret, trans->peer->maxdata);
+	return ret;
+}
+
+/*
+ * wait for space to appear in the transmit/ACK window
+ * - caller holds the socket locked
+ */
+static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
+				    struct rxrpc_call *call,
+				    long *timeo)
+{
+	DECLARE_WAITQUEUE(myself, current);
+	int ret;
+
+	_enter(",{%d},%ld",
+	       CIRC_SPACE(call->acks_head, call->acks_tail, call->acks_winsz),
+	       *timeo);
+
+	add_wait_queue(&call->tx_waitq, &myself);
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		ret = 0;
+		if (CIRC_SPACE(call->acks_head, call->acks_tail,
+			       call->acks_winsz) > 0)
+			break;
+		if (signal_pending(current)) {
+			ret = sock_intr_errno(*timeo);
+			break;
+		}
+
+		release_sock(&rx->sk);
+		*timeo = schedule_timeout(*timeo);
+		lock_sock(&rx->sk);
+	}
+
+	remove_wait_queue(&call->tx_waitq, &myself);
+	set_current_state(TASK_RUNNING);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * attempt to schedule an instant Tx resend
+ */
+static inline void rxrpc_instant_resend(struct rxrpc_call *call)
+{
+	read_lock_bh(&call->state_lock);
+	if (try_to_del_timer_sync(&call->resend_timer) >= 0) {
+		clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
+		if (call->state < RXRPC_CALL_COMPLETE &&
+		    !test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+			rxrpc_queue_call(call);
+	}
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * queue a packet for transmission, set the resend timer and attempt
+ * to send the packet immediately
+ */
+static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
+			       bool last)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	int ret;
+
+	_net("queue skb %p [%d]", skb, call->acks_head);
+
+	ASSERT(call->acks_window != NULL);
+	call->acks_window[call->acks_head] = (unsigned long) skb;
+	smp_wmb();
+	call->acks_head = (call->acks_head + 1) & (call->acks_winsz - 1);
+
+	if (last || call->state == RXRPC_CALL_SERVER_ACK_REQUEST) {
+		_debug("________awaiting reply/ACK__________");
+		write_lock_bh(&call->state_lock);
+		switch (call->state) {
+		case RXRPC_CALL_CLIENT_SEND_REQUEST:
+			call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY;
+			break;
+		case RXRPC_CALL_SERVER_ACK_REQUEST:
+			call->state = RXRPC_CALL_SERVER_SEND_REPLY;
+			if (!last)
+				break;
+		case RXRPC_CALL_SERVER_SEND_REPLY:
+			call->state = RXRPC_CALL_SERVER_AWAIT_ACK;
+			break;
+		default:
+			break;
+		}
+		write_unlock_bh(&call->state_lock);
+	}
+
+	_proto("Tx DATA %%%u { #%u }",
+	       ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+
+	sp->need_resend = 0;
+	sp->resend_at = jiffies + rxrpc_resend_timeout * HZ;
+	if (!test_and_set_bit(RXRPC_CALL_RUN_RTIMER, &call->flags)) {
+		_debug("run timer");
+		call->resend_timer.expires = sp->resend_at;
+		add_timer(&call->resend_timer);
+	}
+
+	/* attempt to cancel the rx-ACK timer, deferring reply transmission if
+	 * we're ACK'ing the request phase of an incoming call */
+	ret = -EAGAIN;
+	if (try_to_del_timer_sync(&call->ack_timer) >= 0) {
+		/* the packet may be freed by rxrpc_process_call() before this
+		 * returns */
+		ret = rxrpc_send_packet(call->conn->trans, skb);
+		_net("sent skb %p", skb);
+	} else {
+		_debug("failed to delete ACK timer");
+	}
+
+	if (ret < 0) {
+		_debug("need instant resend %d", ret);
+		sp->need_resend = 1;
+		rxrpc_instant_resend(call);
+	}
+
+	_leave("");
+}
+
+/*
+ * send data through a socket
+ * - must be called in process context
+ * - caller holds the socket locked
+ */
+static int rxrpc_send_data(struct kiocb *iocb,
+			   struct rxrpc_sock *rx,
+			   struct rxrpc_call *call,
+			   struct msghdr *msg, size_t len)
+{
+	struct rxrpc_skb_priv *sp;
+	unsigned char __user *from;
+	struct sk_buff *skb;
+	struct iovec *iov;
+	struct sock *sk = &rx->sk;
+	long timeo;
+	bool more;
+	int ret, ioc, segment, copied;
+
+	_enter(",,,{%zu},%zu", msg->msg_iovlen, len);
+
+	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+
+	/* this should be in poll */
+	clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+	if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
+		return -EPIPE;
+
+	iov = msg->msg_iov;
+	ioc = msg->msg_iovlen - 1;
+	from = iov->iov_base;
+	segment = iov->iov_len;
+	iov++;
+	more = msg->msg_flags & MSG_MORE;
+
+	skb = call->tx_pending;
+	call->tx_pending = NULL;
+
+	copied = 0;
+	do {
+		int copy;
+
+		if (segment > len)
+			segment = len;
+
+		_debug("SEGMENT %d @%p", segment, from);
+
+		if (!skb) {
+			size_t size, chunk, max, space;
+
+			_debug("alloc");
+
+			if (CIRC_SPACE(call->acks_head, call->acks_tail,
+				       call->acks_winsz) <= 0) {
+				ret = -EAGAIN;
+				if (msg->msg_flags & MSG_DONTWAIT)
+					goto maybe_error;
+				ret = rxrpc_wait_for_tx_window(rx, call,
+							       &timeo);
+				if (ret < 0)
+					goto maybe_error;
+			}
+
+			max = call->conn->trans->peer->maxdata;
+			max -= call->conn->security_size;
+			max &= ~(call->conn->size_align - 1UL);
+
+			chunk = max;
+			if (chunk > len && !more)
+				chunk = len;
+
+			space = chunk + call->conn->size_align;
+			space &= ~(call->conn->size_align - 1UL);
+
+			size = space + call->conn->header_size;
+
+			_debug("SIZE: %zu/%zu/%zu", chunk, space, size);
+
+			/* create a buffer that we can retain until it's ACK'd */
+			skb = sock_alloc_send_skb(
+				sk, size, msg->msg_flags & MSG_DONTWAIT, &ret);
+			if (!skb)
+				goto maybe_error;
+
+			rxrpc_new_skb(skb);
+
+			_debug("ALLOC SEND %p", skb);
+
+			ASSERTCMP(skb->mark, ==, 0);
+
+			_debug("HS: %u", call->conn->header_size);
+			skb_reserve(skb, call->conn->header_size);
+			skb->len += call->conn->header_size;
+
+			sp = rxrpc_skb(skb);
+			sp->remain = chunk;
+			if (sp->remain > skb_tailroom(skb))
+				sp->remain = skb_tailroom(skb);
+
+			_net("skb: hr %d, tr %d, hl %d, rm %d",
+			       skb_headroom(skb),
+			       skb_tailroom(skb),
+			       skb_headlen(skb),
+			       sp->remain);
+
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+
+		_debug("append");
+		sp = rxrpc_skb(skb);
+
+		/* append next segment of data to the current buffer */
+		copy = skb_tailroom(skb);
+		ASSERTCMP(copy, >, 0);
+		if (copy > segment)
+			copy = segment;
+		if (copy > sp->remain)
+			copy = sp->remain;
+
+		_debug("add");
+		ret = skb_add_data(skb, from, copy);
+		_debug("added");
+		if (ret < 0)
+			goto efault;
+		sp->remain -= copy;
+		skb->mark += copy;
+
+		len -= copy;
+		segment -= copy;
+		from += copy;
+		while (segment == 0 && ioc > 0) {
+			from = iov->iov_base;
+			segment = iov->iov_len;
+			iov++;
+			ioc--;
+		}
+		if (len == 0) {
+			segment = 0;
+			ioc = 0;
+		}
+
+		/* check for the far side aborting the call or a network error
+		 * occurring */
+		if (call->state > RXRPC_CALL_COMPLETE)
+			goto call_aborted;
+
+		/* add the packet to the send queue if it's now full */
+		if (sp->remain <= 0 || (segment == 0 && !more)) {
+			struct rxrpc_connection *conn = call->conn;
+			size_t pad;
+
+			/* pad out if we're using security */
+			if (conn->security) {
+				pad = conn->security_size + skb->mark;
+				pad = conn->size_align - pad;
+				pad &= conn->size_align - 1;
+				_debug("pad %zu", pad);
+				if (pad)
+					memset(skb_put(skb, pad), 0, pad);
+			}
+
+			sp->hdr.epoch = conn->epoch;
+			sp->hdr.cid = call->cid;
+			sp->hdr.callNumber = call->call_id;
+			sp->hdr.seq =
+				htonl(atomic_inc_return(&call->sequence));
+			sp->hdr.serial =
+				htonl(atomic_inc_return(&conn->serial));
+			sp->hdr.type = RXRPC_PACKET_TYPE_DATA;
+			sp->hdr.userStatus = 0;
+			sp->hdr.securityIndex = conn->security_ix;
+			sp->hdr._rsvd = 0;
+			sp->hdr.serviceId = conn->service_id;
+
+			sp->hdr.flags = conn->out_clientflag;
+			if (len == 0 && !more)
+				sp->hdr.flags |= RXRPC_LAST_PACKET;
+			else if (CIRC_SPACE(call->acks_head, call->acks_tail,
+					    call->acks_winsz) > 1)
+				sp->hdr.flags |= RXRPC_MORE_PACKETS;
+
+			ret = rxrpc_secure_packet(
+				call, skb, skb->mark,
+				skb->head + sizeof(struct rxrpc_header));
+			if (ret < 0)
+				goto out;
+
+			memcpy(skb->head, &sp->hdr,
+			       sizeof(struct rxrpc_header));
+			rxrpc_queue_packet(call, skb, segment == 0 && !more);
+			skb = NULL;
+		}
+
+	} while (segment > 0);
+
+out:
+	call->tx_pending = skb;
+	_leave(" = %d", ret);
+	return ret;
+
+call_aborted:
+	rxrpc_free_skb(skb);
+	if (call->state == RXRPC_CALL_NETWORK_ERROR)
+		ret = call->conn->trans->peer->net_error;
+	else
+		ret = -ECONNABORTED;
+	_leave(" = %d", ret);
+	return ret;
+
+maybe_error:
+	if (copied)
+		ret = copied;
+	goto out;
+
+efault:
+	ret = -EFAULT;
+	goto out;
+}
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
new file mode 100644
index 0000000..ce08b78
--- /dev/null
+++ b/net/rxrpc/ar-peer.c
@@ -0,0 +1,316 @@
+/* RxRPC remote transport endpoint management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include "ar-internal.h"
+
+static LIST_HEAD(rxrpc_peers);
+static DEFINE_RWLOCK(rxrpc_peer_lock);
+static DECLARE_WAIT_QUEUE_HEAD(rxrpc_peer_wq);
+
+static void rxrpc_destroy_peer(struct work_struct *work);
+
+/*
+ * assess the MTU size for the network interface through which this peer is
+ * reached
+ */
+static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
+{
+	struct rtable *rt;
+	struct flowi fl;
+	int ret;
+
+	peer->if_mtu = 1500;
+
+	memset(&fl, 0, sizeof(fl));
+
+	switch (peer->srx.transport.family) {
+	case AF_INET:
+		fl.oif = 0;
+		fl.proto = IPPROTO_UDP,
+		fl.nl_u.ip4_u.saddr = 0;
+		fl.nl_u.ip4_u.daddr = peer->srx.transport.sin.sin_addr.s_addr;
+		fl.nl_u.ip4_u.tos = 0;
+		/* assume AFS.CM talking to AFS.FS */
+		fl.uli_u.ports.sport = htons(7001);
+		fl.uli_u.ports.dport = htons(7000);
+		break;
+	default:
+		BUG();
+	}
+
+	ret = ip_route_output_key(&rt, &fl);
+	if (ret < 0) {
+		kleave(" [route err %d]", ret);
+		return;
+	}
+
+	peer->if_mtu = dst_mtu(&rt->u.dst);
+	dst_release(&rt->u.dst);
+
+	kleave(" [if_mtu %u]", peer->if_mtu);
+}
+
+/*
+ * allocate a new peer
+ */
+static struct rxrpc_peer *rxrpc_alloc_peer(struct sockaddr_rxrpc *srx,
+					   gfp_t gfp)
+{
+	struct rxrpc_peer *peer;
+
+	_enter("");
+
+	peer = kzalloc(sizeof(struct rxrpc_peer), gfp);
+	if (peer) {
+		INIT_WORK(&peer->destroyer, &rxrpc_destroy_peer);
+		INIT_LIST_HEAD(&peer->link);
+		INIT_LIST_HEAD(&peer->error_targets);
+		spin_lock_init(&peer->lock);
+		atomic_set(&peer->usage, 1);
+		peer->debug_id = atomic_inc_return(&rxrpc_debug_id);
+		memcpy(&peer->srx, srx, sizeof(*srx));
+
+		rxrpc_assess_MTU_size(peer);
+		peer->mtu = peer->if_mtu;
+
+		if (srx->transport.family == AF_INET) {
+			peer->hdrsize = sizeof(struct iphdr);
+			switch (srx->transport_type) {
+			case SOCK_DGRAM:
+				peer->hdrsize += sizeof(struct udphdr);
+				break;
+			default:
+				BUG();
+				break;
+			}
+		} else {
+			BUG();
+		}
+
+		peer->hdrsize += sizeof(struct rxrpc_header);
+		peer->maxdata = peer->mtu - peer->hdrsize;
+	}
+
+	_leave(" = %p", peer);
+	return peer;
+}
+
+/*
+ * obtain a remote transport endpoint for the specified address
+ */
+struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *srx, gfp_t gfp)
+{
+	struct rxrpc_peer *peer, *candidate;
+	const char *new = "old";
+	int usage;
+
+	_enter("{%d,%d,%u.%u.%u.%u+%hu}",
+	       srx->transport_type,
+	       srx->transport_len,
+	       NIPQUAD(srx->transport.sin.sin_addr),
+	       ntohs(srx->transport.sin.sin_port));
+
+	/* search the peer list first */
+	read_lock_bh(&rxrpc_peer_lock);
+	list_for_each_entry(peer, &rxrpc_peers, link) {
+		_debug("check PEER %d { u=%d t=%d l=%d }",
+		       peer->debug_id,
+		       atomic_read(&peer->usage),
+		       peer->srx.transport_type,
+		       peer->srx.transport_len);
+
+		if (atomic_read(&peer->usage) > 0 &&
+		    peer->srx.transport_type == srx->transport_type &&
+		    peer->srx.transport_len == srx->transport_len &&
+		    memcmp(&peer->srx.transport,
+			   &srx->transport,
+			   srx->transport_len) == 0)
+			goto found_extant_peer;
+	}
+	read_unlock_bh(&rxrpc_peer_lock);
+
+	/* not yet present - create a candidate for a new record and then
+	 * redo the search */
+	candidate = rxrpc_alloc_peer(srx, gfp);
+	if (!candidate) {
+		_leave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	write_lock_bh(&rxrpc_peer_lock);
+
+	list_for_each_entry(peer, &rxrpc_peers, link) {
+		if (atomic_read(&peer->usage) > 0 &&
+		    peer->srx.transport_type == srx->transport_type &&
+		    peer->srx.transport_len == srx->transport_len &&
+		    memcmp(&peer->srx.transport,
+			   &srx->transport,
+			   srx->transport_len) == 0)
+			goto found_extant_second;
+	}
+
+	/* we can now add the new candidate to the list */
+	peer = candidate;
+	candidate = NULL;
+
+	list_add_tail(&peer->link, &rxrpc_peers);
+	write_unlock_bh(&rxrpc_peer_lock);
+	new = "new";
+
+success:
+	_net("PEER %s %d {%d,%u,%u.%u.%u.%u+%hu}",
+	     new,
+	     peer->debug_id,
+	     peer->srx.transport_type,
+	     peer->srx.transport.family,
+	     NIPQUAD(peer->srx.transport.sin.sin_addr),
+	     ntohs(peer->srx.transport.sin.sin_port));
+
+	_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
+	return peer;
+
+	/* we found the peer in the list immediately */
+found_extant_peer:
+	usage = atomic_inc_return(&peer->usage);
+	read_unlock_bh(&rxrpc_peer_lock);
+	goto success;
+
+	/* we found the peer on the second time through the list */
+found_extant_second:
+	usage = atomic_inc_return(&peer->usage);
+	write_unlock_bh(&rxrpc_peer_lock);
+	kfree(candidate);
+	goto success;
+}
+
+/*
+ * find the peer associated with a packet
+ */
+struct rxrpc_peer *rxrpc_find_peer(struct rxrpc_local *local,
+				   __be32 addr, __be16 port)
+{
+	struct rxrpc_peer *peer;
+
+	_enter("");
+
+	/* search the peer list */
+	read_lock_bh(&rxrpc_peer_lock);
+
+	if (local->srx.transport.family == AF_INET &&
+	    local->srx.transport_type == SOCK_DGRAM
+	    ) {
+		list_for_each_entry(peer, &rxrpc_peers, link) {
+			if (atomic_read(&peer->usage) > 0 &&
+			    peer->srx.transport_type == SOCK_DGRAM &&
+			    peer->srx.transport.family == AF_INET &&
+			    peer->srx.transport.sin.sin_port == port &&
+			    peer->srx.transport.sin.sin_addr.s_addr == addr)
+				goto found_UDP_peer;
+		}
+
+		goto new_UDP_peer;
+	}
+
+	read_unlock_bh(&rxrpc_peer_lock);
+	_leave(" = -EAFNOSUPPORT");
+	return ERR_PTR(-EAFNOSUPPORT);
+
+found_UDP_peer:
+	_net("Rx UDP DGRAM from peer %d", peer->debug_id);
+	atomic_inc(&peer->usage);
+	read_unlock_bh(&rxrpc_peer_lock);
+	_leave(" = %p", peer);
+	return peer;
+
+new_UDP_peer:
+	_net("Rx UDP DGRAM from NEW peer %d", peer->debug_id);
+	read_unlock_bh(&rxrpc_peer_lock);
+	_leave(" = -EBUSY [new]");
+	return ERR_PTR(-EBUSY);
+}
+
+/*
+ * release a remote transport endpoint
+ */
+void rxrpc_put_peer(struct rxrpc_peer *peer)
+{
+	_enter("%p{u=%d}", peer, atomic_read(&peer->usage));
+
+	ASSERTCMP(atomic_read(&peer->usage), >, 0);
+
+	if (likely(!atomic_dec_and_test(&peer->usage))) {
+		_leave(" [in use]");
+		return;
+	}
+
+	rxrpc_queue_work(&peer->destroyer);
+	_leave("");
+}
+
+/*
+ * destroy a remote transport endpoint
+ */
+static void rxrpc_destroy_peer(struct work_struct *work)
+{
+	struct rxrpc_peer *peer =
+		container_of(work, struct rxrpc_peer, destroyer);
+
+	_enter("%p{%d}", peer, atomic_read(&peer->usage));
+
+	write_lock_bh(&rxrpc_peer_lock);
+	list_del(&peer->link);
+	write_unlock_bh(&rxrpc_peer_lock);
+
+	_net("DESTROY PEER %d", peer->debug_id);
+	kfree(peer);
+
+	if (list_empty(&rxrpc_peers))
+		wake_up_all(&rxrpc_peer_wq);
+	_leave("");
+}
+
+/*
+ * preemptively destroy all the peer records from a transport endpoint rather
+ * than waiting for them to time out
+ */
+void __exit rxrpc_destroy_all_peers(void)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	_enter("");
+
+	/* we simply have to wait for them to go away */
+	if (!list_empty(&rxrpc_peers)) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&rxrpc_peer_wq, &myself);
+
+		while (!list_empty(&rxrpc_peers)) {
+			schedule();
+			set_current_state(TASK_UNINTERRUPTIBLE);
+		}
+
+		remove_wait_queue(&rxrpc_peer_wq, &myself);
+		set_current_state(TASK_RUNNING);
+	}
+
+	_leave("");
+}
diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c
new file mode 100644
index 0000000..58f4b4e
--- /dev/null
+++ b/net/rxrpc/ar-proc.c
@@ -0,0 +1,247 @@
+/* /proc/net/ support for AF_RXRPC
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static const char *rxrpc_conn_states[] = {
+	[RXRPC_CONN_UNUSED]		= "Unused  ",
+	[RXRPC_CONN_CLIENT]		= "Client  ",
+	[RXRPC_CONN_SERVER_UNSECURED]	= "SvUnsec ",
+	[RXRPC_CONN_SERVER_CHALLENGING]	= "SvChall ",
+	[RXRPC_CONN_SERVER]		= "SvSecure",
+	[RXRPC_CONN_REMOTELY_ABORTED]	= "RmtAbort",
+	[RXRPC_CONN_LOCALLY_ABORTED]	= "LocAbort",
+	[RXRPC_CONN_NETWORK_ERROR]	= "NetError",
+};
+
+const char *rxrpc_call_states[] = {
+	[RXRPC_CALL_CLIENT_SEND_REQUEST]	= "ClSndReq",
+	[RXRPC_CALL_CLIENT_AWAIT_REPLY]		= "ClAwtRpl",
+	[RXRPC_CALL_CLIENT_RECV_REPLY]		= "ClRcvRpl",
+	[RXRPC_CALL_CLIENT_FINAL_ACK]		= "ClFnlACK",
+	[RXRPC_CALL_SERVER_SECURING]		= "SvSecure",
+	[RXRPC_CALL_SERVER_ACCEPTING]		= "SvAccept",
+	[RXRPC_CALL_SERVER_RECV_REQUEST]	= "SvRcvReq",
+	[RXRPC_CALL_SERVER_ACK_REQUEST]		= "SvAckReq",
+	[RXRPC_CALL_SERVER_SEND_REPLY]		= "SvSndRpl",
+	[RXRPC_CALL_SERVER_AWAIT_ACK]		= "SvAwtACK",
+	[RXRPC_CALL_COMPLETE]			= "Complete",
+	[RXRPC_CALL_SERVER_BUSY]		= "SvBusy  ",
+	[RXRPC_CALL_REMOTELY_ABORTED]		= "RmtAbort",
+	[RXRPC_CALL_LOCALLY_ABORTED]		= "LocAbort",
+	[RXRPC_CALL_NETWORK_ERROR]		= "NetError",
+	[RXRPC_CALL_DEAD]			= "Dead    ",
+};
+
+/*
+ * generate a list of extant and dead calls in /proc/net/rxrpc_calls
+ */
+static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	read_lock(&rxrpc_call_lock);
+	if (!pos)
+		return SEQ_START_TOKEN;
+	pos--;
+
+	list_for_each(_p, &rxrpc_calls)
+		if (!pos--)
+			break;
+
+	return _p != &rxrpc_calls ? _p : NULL;
+}
+
+static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next;
+
+	return _p != &rxrpc_calls ? _p : NULL;
+}
+
+static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&rxrpc_call_lock);
+}
+
+static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
+{
+	struct rxrpc_transport *trans;
+	struct rxrpc_call *call;
+	char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1];
+
+	if (v == SEQ_START_TOKEN) {
+		seq_puts(seq,
+			 "Proto Local                  Remote                "
+			 " SvID ConnID   CallID   End Use State    Abort   "
+			 " UserID\n");
+		return 0;
+	}
+
+	call = list_entry(v, struct rxrpc_call, link);
+	trans = call->conn->trans;
+
+	sprintf(lbuff, NIPQUAD_FMT":%u",
+		NIPQUAD(trans->local->srx.transport.sin.sin_addr),
+		ntohs(trans->local->srx.transport.sin.sin_port));
+
+	sprintf(rbuff, NIPQUAD_FMT":%u",
+		NIPQUAD(trans->peer->srx.transport.sin.sin_addr),
+		ntohs(trans->peer->srx.transport.sin.sin_port));
+
+	seq_printf(seq,
+		   "UDP   %-22.22s %-22.22s %4x %08x %08x %s %3u"
+		   " %-8.8s %08x %lx\n",
+		   lbuff,
+		   rbuff,
+		   ntohs(call->conn->service_id),
+		   ntohl(call->conn->cid),
+		   ntohl(call->call_id),
+		   call->conn->in_clientflag ? "Svc" : "Clt",
+		   atomic_read(&call->usage),
+		   rxrpc_call_states[call->state],
+		   call->abort_code,
+		   call->user_call_ID);
+
+	return 0;
+}
+
+static struct seq_operations rxrpc_call_seq_ops = {
+	.start  = rxrpc_call_seq_start,
+	.next   = rxrpc_call_seq_next,
+	.stop   = rxrpc_call_seq_stop,
+	.show   = rxrpc_call_seq_show,
+};
+
+static int rxrpc_call_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &rxrpc_call_seq_ops);
+}
+
+struct file_operations rxrpc_call_seq_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rxrpc_call_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+/*
+ * generate a list of extant virtual connections in /proc/net/rxrpc_conns
+ */
+static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	read_lock(&rxrpc_connection_lock);
+	if (!pos)
+		return SEQ_START_TOKEN;
+	pos--;
+
+	list_for_each(_p, &rxrpc_connections)
+		if (!pos--)
+			break;
+
+	return _p != &rxrpc_connections ? _p : NULL;
+}
+
+static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
+				       loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = (v == SEQ_START_TOKEN) ? rxrpc_connections.next : _p->next;
+
+	return _p != &rxrpc_connections ? _p : NULL;
+}
+
+static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&rxrpc_connection_lock);
+}
+
+static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
+{
+	struct rxrpc_connection *conn;
+	struct rxrpc_transport *trans;
+	char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1];
+
+	if (v == SEQ_START_TOKEN) {
+		seq_puts(seq,
+			 "Proto Local                  Remote                "
+			 " SvID ConnID   Calls    End Use State    Key     "
+			 " Serial   ISerial\n"
+			 );
+		return 0;
+	}
+
+	conn = list_entry(v, struct rxrpc_connection, link);
+	trans = conn->trans;
+
+	sprintf(lbuff, NIPQUAD_FMT":%u",
+		NIPQUAD(trans->local->srx.transport.sin.sin_addr),
+		ntohs(trans->local->srx.transport.sin.sin_port));
+
+	sprintf(rbuff, NIPQUAD_FMT":%u",
+		NIPQUAD(trans->peer->srx.transport.sin.sin_addr),
+		ntohs(trans->peer->srx.transport.sin.sin_port));
+
+	seq_printf(seq,
+		   "UDP   %-22.22s %-22.22s %4x %08x %08x %s %3u"
+		   " %s %08x %08x %08x\n",
+		   lbuff,
+		   rbuff,
+		   ntohs(conn->service_id),
+		   ntohl(conn->cid),
+		   conn->call_counter,
+		   conn->in_clientflag ? "Svc" : "Clt",
+		   atomic_read(&conn->usage),
+		   rxrpc_conn_states[conn->state],
+		   key_serial(conn->key),
+		   atomic_read(&conn->serial),
+		   atomic_read(&conn->hi_serial));
+
+	return 0;
+}
+
+static struct seq_operations rxrpc_connection_seq_ops = {
+	.start  = rxrpc_connection_seq_start,
+	.next   = rxrpc_connection_seq_next,
+	.stop   = rxrpc_connection_seq_stop,
+	.show   = rxrpc_connection_seq_show,
+};
+
+
+static int rxrpc_connection_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &rxrpc_connection_seq_ops);
+}
+
+struct file_operations rxrpc_connection_seq_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rxrpc_connection_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
new file mode 100644
index 0000000..f19121d
--- /dev/null
+++ b/net/rxrpc/ar-recvmsg.c
@@ -0,0 +1,437 @@
+/* RxRPC recvmsg() implementation
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+/*
+ * removal a call's user ID from the socket tree to make the user ID available
+ * again and so that it won't be seen again in association with that call
+ */
+void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call)
+{
+	_debug("RELEASE CALL %d", call->debug_id);
+
+	if (test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) {
+		write_lock_bh(&rx->call_lock);
+		rb_erase(&call->sock_node, &call->socket->calls);
+		clear_bit(RXRPC_CALL_HAS_USERID, &call->flags);
+		write_unlock_bh(&rx->call_lock);
+	}
+
+	read_lock_bh(&call->state_lock);
+	if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+	    !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+		rxrpc_queue_call(call);
+	read_unlock_bh(&call->state_lock);
+}
+
+/*
+ * receive a message from an RxRPC socket
+ * - we need to be careful about two or more threads calling recvmsg
+ *   simultaneously
+ */
+int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
+		  struct msghdr *msg, size_t len, int flags)
+{
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_call *call = NULL, *continue_call = NULL;
+	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+	struct sk_buff *skb;
+	long timeo;
+	int copy, ret, ullen, offset, copied = 0;
+	u32 abort_code;
+
+	DEFINE_WAIT(wait);
+
+	_enter(",,,%zu,%d", len, flags);
+
+	if (flags & (MSG_OOB | MSG_TRUNC))
+		return -EOPNOTSUPP;
+
+	ullen = msg->msg_flags & MSG_CMSG_COMPAT ? 4 : sizeof(unsigned long);
+
+	timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT);
+	msg->msg_flags |= MSG_MORE;
+
+	lock_sock(&rx->sk);
+
+	for (;;) {
+		/* return immediately if a client socket has no outstanding
+		 * calls */
+		if (RB_EMPTY_ROOT(&rx->calls)) {
+			if (copied)
+				goto out;
+			if (rx->sk.sk_state != RXRPC_SERVER_LISTENING) {
+				release_sock(&rx->sk);
+				if (continue_call)
+					rxrpc_put_call(continue_call);
+				return -ENODATA;
+			}
+		}
+
+		/* get the next message on the Rx queue */
+		skb = skb_peek(&rx->sk.sk_receive_queue);
+		if (!skb) {
+			/* nothing remains on the queue */
+			if (copied &&
+			    (msg->msg_flags & MSG_PEEK || timeo == 0))
+				goto out;
+
+			/* wait for a message to turn up */
+			release_sock(&rx->sk);
+			prepare_to_wait_exclusive(rx->sk.sk_sleep, &wait,
+						  TASK_INTERRUPTIBLE);
+			ret = sock_error(&rx->sk);
+			if (ret)
+				goto wait_error;
+
+			if (skb_queue_empty(&rx->sk.sk_receive_queue)) {
+				if (signal_pending(current))
+					goto wait_interrupted;
+				timeo = schedule_timeout(timeo);
+			}
+			finish_wait(rx->sk.sk_sleep, &wait);
+			lock_sock(&rx->sk);
+			continue;
+		}
+
+	peek_next_packet:
+		sp = rxrpc_skb(skb);
+		call = sp->call;
+		ASSERT(call != NULL);
+
+		_debug("next pkt %s", rxrpc_pkts[sp->hdr.type]);
+
+		/* make sure we wait for the state to be updated in this call */
+		spin_lock_bh(&call->lock);
+		spin_unlock_bh(&call->lock);
+
+		if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
+			_debug("packet from released call");
+			if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
+				BUG();
+			rxrpc_free_skb(skb);
+			continue;
+		}
+
+		/* determine whether to continue last data receive */
+		if (continue_call) {
+			_debug("maybe cont");
+			if (call != continue_call ||
+			    skb->mark != RXRPC_SKB_MARK_DATA) {
+				release_sock(&rx->sk);
+				rxrpc_put_call(continue_call);
+				_leave(" = %d [noncont]", copied);
+				return copied;
+			}
+		}
+
+		rxrpc_get_call(call);
+
+		/* copy the peer address and timestamp */
+		if (!continue_call) {
+			if (msg->msg_name && msg->msg_namelen > 0)
+				memcpy(&msg->msg_name, &call->conn->trans->peer->srx,
+				       sizeof(call->conn->trans->peer->srx));
+			sock_recv_timestamp(msg, &rx->sk, skb);
+		}
+
+		/* receive the message */
+		if (skb->mark != RXRPC_SKB_MARK_DATA)
+			goto receive_non_data_message;
+
+		_debug("recvmsg DATA #%u { %d, %d }",
+		       ntohl(sp->hdr.seq), skb->len, sp->offset);
+
+		if (!continue_call) {
+			/* only set the control data once per recvmsg() */
+			ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
+				       ullen, &call->user_call_ID);
+			if (ret < 0)
+				goto copy_error;
+			ASSERT(test_bit(RXRPC_CALL_HAS_USERID, &call->flags));
+		}
+
+		ASSERTCMP(ntohl(sp->hdr.seq), >=, call->rx_data_recv);
+		ASSERTCMP(ntohl(sp->hdr.seq), <=, call->rx_data_recv + 1);
+		call->rx_data_recv = ntohl(sp->hdr.seq);
+
+		ASSERTCMP(ntohl(sp->hdr.seq), >, call->rx_data_eaten);
+
+		offset = sp->offset;
+		copy = skb->len - offset;
+		if (copy > len - copied)
+			copy = len - copied;
+
+		if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+			ret = skb_copy_datagram_iovec(skb, offset,
+						      msg->msg_iov, copy);
+		} else {
+			ret = skb_copy_and_csum_datagram_iovec(skb, offset,
+							       msg->msg_iov);
+			if (ret == -EINVAL)
+				goto csum_copy_error;
+		}
+
+		if (ret < 0)
+			goto copy_error;
+
+		/* handle piecemeal consumption of data packets */
+		_debug("copied %d+%d", copy, copied);
+
+		offset += copy;
+		copied += copy;
+
+		if (!(flags & MSG_PEEK))
+			sp->offset = offset;
+
+		if (sp->offset < skb->len) {
+			_debug("buffer full");
+			ASSERTCMP(copied, ==, len);
+			break;
+		}
+
+		/* we transferred the whole data packet */
+		if (sp->hdr.flags & RXRPC_LAST_PACKET) {
+			_debug("last");
+			if (call->conn->out_clientflag) {
+				 /* last byte of reply received */
+				ret = copied;
+				goto terminal_message;
+			}
+
+			/* last bit of request received */
+			if (!(flags & MSG_PEEK)) {
+				_debug("eat packet");
+				if (skb_dequeue(&rx->sk.sk_receive_queue) !=
+				    skb)
+					BUG();
+				rxrpc_free_skb(skb);
+			}
+			msg->msg_flags &= ~MSG_MORE;
+			break;
+		}
+
+		/* move on to the next data message */
+		_debug("next");
+		if (!continue_call)
+			continue_call = sp->call;
+		else
+			rxrpc_put_call(call);
+		call = NULL;
+
+		if (flags & MSG_PEEK) {
+			_debug("peek next");
+			skb = skb->next;
+			if (skb == (struct sk_buff *) &rx->sk.sk_receive_queue)
+				break;
+			goto peek_next_packet;
+		}
+
+		_debug("eat packet");
+		if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
+			BUG();
+		rxrpc_free_skb(skb);
+	}
+
+	/* end of non-terminal data packet reception for the moment */
+	_debug("end rcv data");
+out:
+	release_sock(&rx->sk);
+	if (call)
+		rxrpc_put_call(call);
+	if (continue_call)
+		rxrpc_put_call(continue_call);
+	_leave(" = %d [data]", copied);
+	return copied;
+
+	/* handle non-DATA messages such as aborts, incoming connections and
+	 * final ACKs */
+receive_non_data_message:
+	_debug("non-data");
+
+	if (skb->mark == RXRPC_SKB_MARK_NEW_CALL) {
+		_debug("RECV NEW CALL");
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NEW_CALL, 0, &abort_code);
+		if (ret < 0)
+			goto copy_error;
+		if (!(flags & MSG_PEEK)) {
+			if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
+				BUG();
+			rxrpc_free_skb(skb);
+		}
+		goto out;
+	}
+
+	ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
+		       ullen, &call->user_call_ID);
+	if (ret < 0)
+		goto copy_error;
+	ASSERT(test_bit(RXRPC_CALL_HAS_USERID, &call->flags));
+
+	switch (skb->mark) {
+	case RXRPC_SKB_MARK_DATA:
+		BUG();
+	case RXRPC_SKB_MARK_FINAL_ACK:
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ACK, 0, &abort_code);
+		break;
+	case RXRPC_SKB_MARK_BUSY:
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_BUSY, 0, &abort_code);
+		break;
+	case RXRPC_SKB_MARK_REMOTE_ABORT:
+		abort_code = call->abort_code;
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &abort_code);
+		break;
+	case RXRPC_SKB_MARK_NET_ERROR:
+		_debug("RECV NET ERROR %d", sp->error);
+		abort_code = sp->error;
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NET_ERROR, 4, &abort_code);
+		break;
+	case RXRPC_SKB_MARK_LOCAL_ERROR:
+		_debug("RECV LOCAL ERROR %d", sp->error);
+		abort_code = sp->error;
+		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4,
+			       &abort_code);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	if (ret < 0)
+		goto copy_error;
+
+terminal_message:
+	_debug("terminal");
+	msg->msg_flags &= ~MSG_MORE;
+	msg->msg_flags |= MSG_EOR;
+
+	if (!(flags & MSG_PEEK)) {
+		_net("free terminal skb %p", skb);
+		if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
+			BUG();
+		rxrpc_free_skb(skb);
+		rxrpc_remove_user_ID(rx, call);
+	}
+
+	release_sock(&rx->sk);
+	rxrpc_put_call(call);
+	if (continue_call)
+		rxrpc_put_call(continue_call);
+	_leave(" = %d", ret);
+	return ret;
+
+copy_error:
+	_debug("copy error");
+	release_sock(&rx->sk);
+	rxrpc_put_call(call);
+	if (continue_call)
+		rxrpc_put_call(continue_call);
+	_leave(" = %d", ret);
+	return ret;
+
+csum_copy_error:
+	_debug("csum error");
+	release_sock(&rx->sk);
+	if (continue_call)
+		rxrpc_put_call(continue_call);
+	rxrpc_kill_skb(skb);
+	skb_kill_datagram(&rx->sk, skb, flags);
+	rxrpc_put_call(call);
+	return -EAGAIN;
+
+wait_interrupted:
+	ret = sock_intr_errno(timeo);
+wait_error:
+	finish_wait(rx->sk.sk_sleep, &wait);
+	if (continue_call)
+		rxrpc_put_call(continue_call);
+	if (copied)
+		copied = ret;
+	_leave(" = %d [waitfail %d]", copied, ret);
+	return copied;
+
+}
+
+/**
+ * rxrpc_kernel_data_delivered - Record delivery of data message
+ * @skb: Message holding data
+ *
+ * Record the delivery of a data message.  This permits RxRPC to keep its
+ * tracking correct.  The socket buffer will be deleted.
+ */
+void rxrpc_kernel_data_delivered(struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	struct rxrpc_call *call = sp->call;
+
+	ASSERTCMP(ntohl(sp->hdr.seq), >=, call->rx_data_recv);
+	ASSERTCMP(ntohl(sp->hdr.seq), <=, call->rx_data_recv + 1);
+	call->rx_data_recv = ntohl(sp->hdr.seq);
+
+	ASSERTCMP(ntohl(sp->hdr.seq), >, call->rx_data_eaten);
+	rxrpc_free_skb(skb);
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_data_delivered);
+
+/**
+ * rxrpc_kernel_is_data_last - Determine if data message is last one
+ * @skb: Message holding data
+ *
+ * Determine if data message is last one for the parent call.
+ */
+bool rxrpc_kernel_is_data_last(struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+	ASSERTCMP(skb->mark, ==, RXRPC_SKB_MARK_DATA);
+
+	return sp->hdr.flags & RXRPC_LAST_PACKET;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_is_data_last);
+
+/**
+ * rxrpc_kernel_get_abort_code - Get the abort code from an RxRPC abort message
+ * @skb: Message indicating an abort
+ *
+ * Get the abort code from an RxRPC abort message.
+ */
+u32 rxrpc_kernel_get_abort_code(struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+	ASSERTCMP(skb->mark, ==, RXRPC_SKB_MARK_REMOTE_ABORT);
+
+	return sp->call->abort_code;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_get_abort_code);
+
+/**
+ * rxrpc_kernel_get_error - Get the error number from an RxRPC error message
+ * @skb: Message indicating an error
+ *
+ * Get the error number from an RxRPC error message.
+ */
+int rxrpc_kernel_get_error_number(struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+	return sp->error;
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_get_error_number);
diff --git a/net/rxrpc/ar-security.c b/net/rxrpc/ar-security.c
new file mode 100644
index 0000000..60d1d36
--- /dev/null
+++ b/net/rxrpc/ar-security.c
@@ -0,0 +1,258 @@
+/* RxRPC security handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/udp.h>
+#include <linux/crypto.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static LIST_HEAD(rxrpc_security_methods);
+static DECLARE_RWSEM(rxrpc_security_sem);
+
+/*
+ * get an RxRPC security module
+ */
+static struct rxrpc_security *rxrpc_security_get(struct rxrpc_security *sec)
+{
+	return try_module_get(sec->owner) ? sec : NULL;
+}
+
+/*
+ * release an RxRPC security module
+ */
+static void rxrpc_security_put(struct rxrpc_security *sec)
+{
+	module_put(sec->owner);
+}
+
+/*
+ * look up an rxrpc security module
+ */
+struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
+{
+	struct rxrpc_security *sec = NULL;
+
+	_enter("");
+
+	down_read(&rxrpc_security_sem);
+
+	list_for_each_entry(sec, &rxrpc_security_methods, link) {
+		if (sec->security_index == security_index) {
+			if (unlikely(!rxrpc_security_get(sec)))
+				break;
+			goto out;
+		}
+	}
+
+	sec = NULL;
+out:
+	up_read(&rxrpc_security_sem);
+	_leave(" = %p [%s]", sec, sec ? sec->name : "");
+	return sec;
+}
+
+/**
+ * rxrpc_register_security - register an RxRPC security handler
+ * @sec: security module
+ *
+ * register an RxRPC security handler for use by RxRPC
+ */
+int rxrpc_register_security(struct rxrpc_security *sec)
+{
+	struct rxrpc_security *psec;
+	int ret;
+
+	_enter("");
+	down_write(&rxrpc_security_sem);
+
+	ret = -EEXIST;
+	list_for_each_entry(psec, &rxrpc_security_methods, link) {
+		if (psec->security_index == sec->security_index)
+			goto out;
+	}
+
+	list_add(&sec->link, &rxrpc_security_methods);
+
+	printk(KERN_NOTICE "RxRPC: Registered security type %d '%s'\n",
+	       sec->security_index, sec->name);
+	ret = 0;
+
+out:
+	up_write(&rxrpc_security_sem);
+	_leave(" = %d", ret);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(rxrpc_register_security);
+
+/**
+ * rxrpc_unregister_security - unregister an RxRPC security handler
+ * @sec: security module
+ *
+ * unregister an RxRPC security handler
+ */
+void rxrpc_unregister_security(struct rxrpc_security *sec)
+{
+
+	_enter("");
+	down_write(&rxrpc_security_sem);
+	list_del_init(&sec->link);
+	up_write(&rxrpc_security_sem);
+
+	printk(KERN_NOTICE "RxRPC: Unregistered security type %d '%s'\n",
+	       sec->security_index, sec->name);
+}
+
+EXPORT_SYMBOL_GPL(rxrpc_unregister_security);
+
+/*
+ * initialise the security on a client connection
+ */
+int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
+{
+	struct rxrpc_security *sec;
+	struct key *key = conn->key;
+	int ret;
+
+	_enter("{%d},{%x}", conn->debug_id, key_serial(key));
+
+	if (!key)
+		return 0;
+
+	ret = key_validate(key);
+	if (ret < 0)
+		return ret;
+
+	sec = rxrpc_security_lookup(key->type_data.x[0]);
+	if (!sec)
+		return -EKEYREJECTED;
+	conn->security = sec;
+
+	ret = conn->security->init_connection_security(conn);
+	if (ret < 0) {
+		rxrpc_security_put(conn->security);
+		conn->security = NULL;
+		return ret;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * initialise the security on a server connection
+ */
+int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
+{
+	struct rxrpc_security *sec;
+	struct rxrpc_local *local = conn->trans->local;
+	struct rxrpc_sock *rx;
+	struct key *key;
+	key_ref_t kref;
+	char kdesc[5+1+3+1];
+
+	_enter("");
+
+	sprintf(kdesc, "%u:%u", ntohs(conn->service_id), conn->security_ix);
+
+	sec = rxrpc_security_lookup(conn->security_ix);
+	if (!sec) {
+		_leave(" = -ENOKEY [lookup]");
+		return -ENOKEY;
+	}
+
+	/* find the service */
+	read_lock_bh(&local->services_lock);
+	list_for_each_entry(rx, &local->services, listen_link) {
+		if (rx->service_id == conn->service_id)
+			goto found_service;
+	}
+
+	/* the service appears to have died */
+	read_unlock_bh(&local->services_lock);
+	rxrpc_security_put(sec);
+	_leave(" = -ENOENT");
+	return -ENOENT;
+
+found_service:
+	if (!rx->securities) {
+		read_unlock_bh(&local->services_lock);
+		rxrpc_security_put(sec);
+		_leave(" = -ENOKEY");
+		return -ENOKEY;
+	}
+
+	/* look through the service's keyring */
+	kref = keyring_search(make_key_ref(rx->securities, 1UL),
+			      &key_type_rxrpc_s, kdesc);
+	if (IS_ERR(kref)) {
+		read_unlock_bh(&local->services_lock);
+		rxrpc_security_put(sec);
+		_leave(" = %ld [search]", PTR_ERR(kref));
+		return PTR_ERR(kref);
+	}
+
+	key = key_ref_to_ptr(kref);
+	read_unlock_bh(&local->services_lock);
+
+	conn->server_key = key;
+	conn->security = sec;
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * secure a packet prior to transmission
+ */
+int rxrpc_secure_packet(const struct rxrpc_call *call,
+			struct sk_buff *skb,
+			size_t data_size,
+			void *sechdr)
+{
+	if (call->conn->security)
+		return call->conn->security->secure_packet(
+			call, skb, data_size, sechdr);
+	return 0;
+}
+
+/*
+ * secure a packet prior to transmission
+ */
+int rxrpc_verify_packet(const struct rxrpc_call *call, struct sk_buff *skb,
+			u32 *_abort_code)
+{
+	if (call->conn->security)
+		return call->conn->security->verify_packet(
+			call, skb, _abort_code);
+	return 0;
+}
+
+/*
+ * clear connection security
+ */
+void rxrpc_clear_conn_security(struct rxrpc_connection *conn)
+{
+	_enter("{%d}", conn->debug_id);
+
+	if (conn->security) {
+		conn->security->clear(conn);
+		rxrpc_security_put(conn->security);
+		conn->security = NULL;
+	}
+
+	key_put(conn->key);
+	key_put(conn->server_key);
+}
diff --git a/net/rxrpc/ar-skbuff.c b/net/rxrpc/ar-skbuff.c
new file mode 100644
index 0000000..de755e0
--- /dev/null
+++ b/net/rxrpc/ar-skbuff.c
@@ -0,0 +1,132 @@
+/* ar-skbuff.c: socket buffer destruction handling
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+/*
+ * set up for the ACK at the end of the receive phase when we discard the final
+ * receive phase data packet
+ * - called with softirqs disabled
+ */
+static void rxrpc_request_final_ACK(struct rxrpc_call *call)
+{
+	/* the call may be aborted before we have a chance to ACK it */
+	write_lock(&call->state_lock);
+
+	switch (call->state) {
+	case RXRPC_CALL_CLIENT_RECV_REPLY:
+		call->state = RXRPC_CALL_CLIENT_FINAL_ACK;
+		_debug("request final ACK");
+
+		/* get an extra ref on the call for the final-ACK generator to
+		 * release */
+		rxrpc_get_call(call);
+		set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+		if (try_to_del_timer_sync(&call->ack_timer) >= 0)
+			rxrpc_queue_call(call);
+		break;
+
+	case RXRPC_CALL_SERVER_RECV_REQUEST:
+		call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
+	default:
+		break;
+	}
+
+	write_unlock(&call->state_lock);
+}
+
+/*
+ * drop the bottom ACK off of the call ACK window and advance the window
+ */
+static void rxrpc_hard_ACK_data(struct rxrpc_call *call,
+				struct rxrpc_skb_priv *sp)
+{
+	int loop;
+	u32 seq;
+
+	spin_lock_bh(&call->lock);
+
+	_debug("hard ACK #%u", ntohl(sp->hdr.seq));
+
+	for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) {
+		call->ackr_window[loop] >>= 1;
+		call->ackr_window[loop] |=
+			call->ackr_window[loop + 1] << (BITS_PER_LONG - 1);
+	}
+
+	seq = ntohl(sp->hdr.seq);
+	ASSERTCMP(seq, ==, call->rx_data_eaten + 1);
+	call->rx_data_eaten = seq;
+
+	if (call->ackr_win_top < UINT_MAX)
+		call->ackr_win_top++;
+
+	ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE,
+		    call->rx_data_post, >=, call->rx_data_recv);
+	ASSERTIFCMP(call->state <= RXRPC_CALL_COMPLETE,
+		    call->rx_data_recv, >=, call->rx_data_eaten);
+
+	if (sp->hdr.flags & RXRPC_LAST_PACKET) {
+		rxrpc_request_final_ACK(call);
+	} else if (atomic_dec_and_test(&call->ackr_not_idle) &&
+		   test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) {
+		_debug("send Rx idle ACK");
+		__rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial,
+				    true);
+	}
+
+	spin_unlock_bh(&call->lock);
+}
+
+/*
+ * destroy a packet that has an RxRPC control buffer
+ * - advance the hard-ACK state of the parent call (done here in case something
+ *   in the kernel bypasses recvmsg() and steals the packet directly off of the
+ *   socket receive queue)
+ */
+void rxrpc_packet_destructor(struct sk_buff *skb)
+{
+	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+	struct rxrpc_call *call = sp->call;
+
+	_enter("%p{%p}", skb, call);
+
+	if (call) {
+		/* send the final ACK on a client call */
+		if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA)
+			rxrpc_hard_ACK_data(call, sp);
+		rxrpc_put_call(call);
+		sp->call = NULL;
+	}
+
+	if (skb->sk)
+		sock_rfree(skb);
+	_leave("");
+}
+
+/**
+ * rxrpc_kernel_free_skb - Free an RxRPC socket buffer
+ * @skb: The socket buffer to be freed
+ *
+ * Let RxRPC free its own socket buffer, permitting it to maintain debug
+ * accounting.
+ */
+void rxrpc_kernel_free_skb(struct sk_buff *skb)
+{
+	rxrpc_free_skb(skb);
+}
+
+EXPORT_SYMBOL(rxrpc_kernel_free_skb);
diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c
new file mode 100644
index 0000000..d43d78f
--- /dev/null
+++ b/net/rxrpc/ar-transport.c
@@ -0,0 +1,276 @@
+/* RxRPC point-to-point transport session management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static void rxrpc_transport_reaper(struct work_struct *work);
+
+static LIST_HEAD(rxrpc_transports);
+static DEFINE_RWLOCK(rxrpc_transport_lock);
+static unsigned long rxrpc_transport_timeout = 3600 * 24;
+static DECLARE_DELAYED_WORK(rxrpc_transport_reap, rxrpc_transport_reaper);
+
+/*
+ * allocate a new transport session manager
+ */
+static struct rxrpc_transport *rxrpc_alloc_transport(struct rxrpc_local *local,
+						     struct rxrpc_peer *peer,
+						     gfp_t gfp)
+{
+	struct rxrpc_transport *trans;
+
+	_enter("");
+
+	trans = kzalloc(sizeof(struct rxrpc_transport), gfp);
+	if (trans) {
+		trans->local = local;
+		trans->peer = peer;
+		INIT_LIST_HEAD(&trans->link);
+		trans->bundles = RB_ROOT;
+		trans->client_conns = RB_ROOT;
+		trans->server_conns = RB_ROOT;
+		skb_queue_head_init(&trans->error_queue);
+		spin_lock_init(&trans->client_lock);
+		rwlock_init(&trans->conn_lock);
+		atomic_set(&trans->usage, 1);
+		trans->debug_id = atomic_inc_return(&rxrpc_debug_id);
+
+		if (peer->srx.transport.family == AF_INET) {
+			switch (peer->srx.transport_type) {
+			case SOCK_DGRAM:
+				INIT_WORK(&trans->error_handler,
+					  rxrpc_UDP_error_handler);
+				break;
+			default:
+				BUG();
+				break;
+			}
+		} else {
+			BUG();
+		}
+	}
+
+	_leave(" = %p", trans);
+	return trans;
+}
+
+/*
+ * obtain a transport session for the nominated endpoints
+ */
+struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *local,
+					    struct rxrpc_peer *peer,
+					    gfp_t gfp)
+{
+	struct rxrpc_transport *trans, *candidate;
+	const char *new = "old";
+	int usage;
+
+	_enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},",
+	       NIPQUAD(local->srx.transport.sin.sin_addr),
+	       ntohs(local->srx.transport.sin.sin_port),
+	       NIPQUAD(peer->srx.transport.sin.sin_addr),
+	       ntohs(peer->srx.transport.sin.sin_port));
+
+	/* search the transport list first */
+	read_lock_bh(&rxrpc_transport_lock);
+	list_for_each_entry(trans, &rxrpc_transports, link) {
+		if (trans->local == local && trans->peer == peer)
+			goto found_extant_transport;
+	}
+	read_unlock_bh(&rxrpc_transport_lock);
+
+	/* not yet present - create a candidate for a new record and then
+	 * redo the search */
+	candidate = rxrpc_alloc_transport(local, peer, gfp);
+	if (!candidate) {
+		_leave(" = -ENOMEM");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	write_lock_bh(&rxrpc_transport_lock);
+
+	list_for_each_entry(trans, &rxrpc_transports, link) {
+		if (trans->local == local && trans->peer == peer)
+			goto found_extant_second;
+	}
+
+	/* we can now add the new candidate to the list */
+	trans = candidate;
+	candidate = NULL;
+
+	rxrpc_get_local(trans->local);
+	atomic_inc(&trans->peer->usage);
+	list_add_tail(&trans->link, &rxrpc_transports);
+	write_unlock_bh(&rxrpc_transport_lock);
+	new = "new";
+
+success:
+	_net("TRANSPORT %s %d local %d -> peer %d",
+	     new,
+	     trans->debug_id,
+	     trans->local->debug_id,
+	     trans->peer->debug_id);
+
+	_leave(" = %p {u=%d}", trans, atomic_read(&trans->usage));
+	return trans;
+
+	/* we found the transport in the list immediately */
+found_extant_transport:
+	usage = atomic_inc_return(&trans->usage);
+	read_unlock_bh(&rxrpc_transport_lock);
+	goto success;
+
+	/* we found the transport on the second time through the list */
+found_extant_second:
+	usage = atomic_inc_return(&trans->usage);
+	write_unlock_bh(&rxrpc_transport_lock);
+	kfree(candidate);
+	goto success;
+}
+
+/*
+ * find the transport connecting two endpoints
+ */
+struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *local,
+					     struct rxrpc_peer *peer)
+{
+	struct rxrpc_transport *trans;
+
+	_enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},",
+	       NIPQUAD(local->srx.transport.sin.sin_addr),
+	       ntohs(local->srx.transport.sin.sin_port),
+	       NIPQUAD(peer->srx.transport.sin.sin_addr),
+	       ntohs(peer->srx.transport.sin.sin_port));
+
+	/* search the transport list */
+	read_lock_bh(&rxrpc_transport_lock);
+
+	list_for_each_entry(trans, &rxrpc_transports, link) {
+		if (trans->local == local && trans->peer == peer)
+			goto found_extant_transport;
+	}
+
+	read_unlock_bh(&rxrpc_transport_lock);
+	_leave(" = NULL");
+	return NULL;
+
+found_extant_transport:
+	atomic_inc(&trans->usage);
+	read_unlock_bh(&rxrpc_transport_lock);
+	_leave(" = %p", trans);
+	return trans;
+}
+
+/*
+ * release a transport session
+ */
+void rxrpc_put_transport(struct rxrpc_transport *trans)
+{
+	_enter("%p{u=%d}", trans, atomic_read(&trans->usage));
+
+	ASSERTCMP(atomic_read(&trans->usage), >, 0);
+
+	trans->put_time = xtime.tv_sec;
+	if (unlikely(atomic_dec_and_test(&trans->usage)))
+		_debug("zombie");
+		/* let the reaper determine the timeout to avoid a race with
+		 * overextending the timeout if the reaper is running at the
+		 * same time */
+		rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0);
+	_leave("");
+}
+
+/*
+ * clean up a transport session
+ */
+static void rxrpc_cleanup_transport(struct rxrpc_transport *trans)
+{
+	_net("DESTROY TRANS %d", trans->debug_id);
+
+	rxrpc_purge_queue(&trans->error_queue);
+
+	rxrpc_put_local(trans->local);
+	rxrpc_put_peer(trans->peer);
+	kfree(trans);
+}
+
+/*
+ * reap dead transports that have passed their expiry date
+ */
+static void rxrpc_transport_reaper(struct work_struct *work)
+{
+	struct rxrpc_transport *trans, *_p;
+	unsigned long now, earliest, reap_time;
+
+	LIST_HEAD(graveyard);
+
+	_enter("");
+
+	now = xtime.tv_sec;
+	earliest = ULONG_MAX;
+
+	/* extract all the transports that have been dead too long */
+	write_lock_bh(&rxrpc_transport_lock);
+	list_for_each_entry_safe(trans, _p, &rxrpc_transports, link) {
+		_debug("reap TRANS %d { u=%d t=%ld }",
+		       trans->debug_id, atomic_read(&trans->usage),
+		       (long) now - (long) trans->put_time);
+
+		if (likely(atomic_read(&trans->usage) > 0))
+			continue;
+
+		reap_time = trans->put_time + rxrpc_transport_timeout;
+		if (reap_time <= now)
+			list_move_tail(&trans->link, &graveyard);
+		else if (reap_time < earliest)
+			earliest = reap_time;
+	}
+	write_unlock_bh(&rxrpc_transport_lock);
+
+	if (earliest != ULONG_MAX) {
+		_debug("reschedule reaper %ld", (long) earliest - now);
+		ASSERTCMP(earliest, >, now);
+		rxrpc_queue_delayed_work(&rxrpc_transport_reap,
+					 (earliest - now) * HZ);
+	}
+
+	/* then destroy all those pulled out */
+	while (!list_empty(&graveyard)) {
+		trans = list_entry(graveyard.next, struct rxrpc_transport,
+				   link);
+		list_del_init(&trans->link);
+
+		ASSERTCMP(atomic_read(&trans->usage), ==, 0);
+		rxrpc_cleanup_transport(trans);
+	}
+
+	_leave("");
+}
+
+/*
+ * preemptively destroy all the transport session records rather than waiting
+ * for them to time out
+ */
+void __exit rxrpc_destroy_all_transports(void)
+{
+	_enter("");
+
+	rxrpc_transport_timeout = 0;
+	cancel_delayed_work(&rxrpc_transport_reap);
+	rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0);
+
+	_leave("");
+}
diff --git a/net/rxrpc/call.c b/net/rxrpc/call.c
deleted file mode 100644
index d07122b..0000000
--- a/net/rxrpc/call.c
+++ /dev/null
@@ -1,2277 +0,0 @@
-/* call.c: Rx call routines
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include "internal.h"
-
-__RXACCT_DECL(atomic_t rxrpc_call_count);
-__RXACCT_DECL(atomic_t rxrpc_message_count);
-
-LIST_HEAD(rxrpc_calls);
-DECLARE_RWSEM(rxrpc_calls_sem);
-
-unsigned rxrpc_call_rcv_timeout			= HZ/3;
-static unsigned rxrpc_call_acks_timeout		= HZ/3;
-static unsigned rxrpc_call_dfr_ack_timeout	= HZ/20;
-static unsigned short rxrpc_call_max_resend	= HZ/10;
-
-const char *rxrpc_call_states[] = {
-	"COMPLETE",
-	"ERROR",
-	"SRVR_RCV_OPID",
-	"SRVR_RCV_ARGS",
-	"SRVR_GOT_ARGS",
-	"SRVR_SND_REPLY",
-	"SRVR_RCV_FINAL_ACK",
-	"CLNT_SND_ARGS",
-	"CLNT_RCV_REPLY",
-	"CLNT_GOT_REPLY"
-};
-
-const char *rxrpc_call_error_states[] = {
-	"NO_ERROR",
-	"LOCAL_ABORT",
-	"PEER_ABORT",
-	"LOCAL_ERROR",
-	"REMOTE_ERROR"
-};
-
-const char *rxrpc_pkts[] = {
-	"?00",
-	"data", "ack", "busy", "abort", "ackall", "chall", "resp", "debug",
-	"?09", "?10", "?11", "?12", "?13", "?14", "?15"
-};
-
-static const char *rxrpc_acks[] = {
-	"---", "REQ", "DUP", "SEQ", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL",
-	"-?-"
-};
-
-static const char _acktype[] = "NA-";
-
-static void rxrpc_call_receive_packet(struct rxrpc_call *call);
-static void rxrpc_call_receive_data_packet(struct rxrpc_call *call,
-					   struct rxrpc_message *msg);
-static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
-					  struct rxrpc_message *msg);
-static void rxrpc_call_definitively_ACK(struct rxrpc_call *call,
-					rxrpc_seq_t higest);
-static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest);
-static int __rxrpc_call_read_data(struct rxrpc_call *call);
-
-static int rxrpc_call_record_ACK(struct rxrpc_call *call,
-				 struct rxrpc_message *msg,
-				 rxrpc_seq_t seq,
-				 size_t count);
-
-static int rxrpc_call_flush(struct rxrpc_call *call);
-
-#define _state(call) \
-	_debug("[[[ state %s ]]]", rxrpc_call_states[call->app_call_state]);
-
-static void rxrpc_call_default_attn_func(struct rxrpc_call *call)
-{
-	wake_up(&call->waitq);
-}
-
-static void rxrpc_call_default_error_func(struct rxrpc_call *call)
-{
-	wake_up(&call->waitq);
-}
-
-static void rxrpc_call_default_aemap_func(struct rxrpc_call *call)
-{
-	switch (call->app_err_state) {
-	case RXRPC_ESTATE_LOCAL_ABORT:
-		call->app_abort_code = -call->app_errno;
-	case RXRPC_ESTATE_PEER_ABORT:
-		call->app_errno = -ECONNABORTED;
-	default:
-		break;
-	}
-}
-
-static void __rxrpc_call_acks_timeout(unsigned long _call)
-{
-	struct rxrpc_call *call = (struct rxrpc_call *) _call;
-
-	_debug("ACKS TIMEOUT %05lu", jiffies - call->cjif);
-
-	call->flags |= RXRPC_CALL_ACKS_TIMO;
-	rxrpc_krxiod_queue_call(call);
-}
-
-static void __rxrpc_call_rcv_timeout(unsigned long _call)
-{
-	struct rxrpc_call *call = (struct rxrpc_call *) _call;
-
-	_debug("RCV TIMEOUT %05lu", jiffies - call->cjif);
-
-	call->flags |= RXRPC_CALL_RCV_TIMO;
-	rxrpc_krxiod_queue_call(call);
-}
-
-static void __rxrpc_call_ackr_timeout(unsigned long _call)
-{
-	struct rxrpc_call *call = (struct rxrpc_call *) _call;
-
-	_debug("ACKR TIMEOUT %05lu",jiffies - call->cjif);
-
-	call->flags |= RXRPC_CALL_ACKR_TIMO;
-	rxrpc_krxiod_queue_call(call);
-}
-
-/*****************************************************************************/
-/*
- * calculate a timeout based on an RTT value
- */
-static inline unsigned long __rxrpc_rtt_based_timeout(struct rxrpc_call *call,
-						      unsigned long val)
-{
-	unsigned long expiry = call->conn->peer->rtt / (1000000 / HZ);
-
-	expiry += 10;
-	if (expiry < HZ / 25)
-		expiry = HZ / 25;
-	if (expiry > HZ)
-		expiry = HZ;
-
-	_leave(" = %lu jiffies", expiry);
-	return jiffies + expiry;
-} /* end __rxrpc_rtt_based_timeout() */
-
-/*****************************************************************************/
-/*
- * create a new call record
- */
-static inline int __rxrpc_create_call(struct rxrpc_connection *conn,
-				      struct rxrpc_call **_call)
-{
-	struct rxrpc_call *call;
-
-	_enter("%p", conn);
-
-	/* allocate and initialise a call record */
-	call = (struct rxrpc_call *) get_zeroed_page(GFP_KERNEL);
-	if (!call) {
-		_leave(" ENOMEM");
-		return -ENOMEM;
-	}
-
-	atomic_set(&call->usage, 1);
-
-	init_waitqueue_head(&call->waitq);
-	spin_lock_init(&call->lock);
-	INIT_LIST_HEAD(&call->link);
-	INIT_LIST_HEAD(&call->acks_pendq);
-	INIT_LIST_HEAD(&call->rcv_receiveq);
-	INIT_LIST_HEAD(&call->rcv_krxiodq_lk);
-	INIT_LIST_HEAD(&call->app_readyq);
-	INIT_LIST_HEAD(&call->app_unreadyq);
-	INIT_LIST_HEAD(&call->app_link);
-	INIT_LIST_HEAD(&call->app_attn_link);
-
-	init_timer(&call->acks_timeout);
-	call->acks_timeout.data = (unsigned long) call;
-	call->acks_timeout.function = __rxrpc_call_acks_timeout;
-
-	init_timer(&call->rcv_timeout);
-	call->rcv_timeout.data = (unsigned long) call;
-	call->rcv_timeout.function = __rxrpc_call_rcv_timeout;
-
-	init_timer(&call->ackr_dfr_timo);
-	call->ackr_dfr_timo.data = (unsigned long) call;
-	call->ackr_dfr_timo.function = __rxrpc_call_ackr_timeout;
-
-	call->conn = conn;
-	call->ackr_win_bot = 1;
-	call->ackr_win_top = call->ackr_win_bot + RXRPC_CALL_ACK_WINDOW_SIZE - 1;
-	call->ackr_prev_seq = 0;
-	call->app_mark = RXRPC_APP_MARK_EOF;
-	call->app_attn_func = rxrpc_call_default_attn_func;
-	call->app_error_func = rxrpc_call_default_error_func;
-	call->app_aemap_func = rxrpc_call_default_aemap_func;
-	call->app_scr_alloc = call->app_scratch;
-
-	call->cjif = jiffies;
-
-	_leave(" = 0 (%p)", call);
-
-	*_call = call;
-
-	return 0;
-} /* end __rxrpc_create_call() */
-
-/*****************************************************************************/
-/*
- * create a new call record for outgoing calls
- */
-int rxrpc_create_call(struct rxrpc_connection *conn,
-		      rxrpc_call_attn_func_t attn,
-		      rxrpc_call_error_func_t error,
-		      rxrpc_call_aemap_func_t aemap,
-		      struct rxrpc_call **_call)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	struct rxrpc_call *call;
-	int ret, cix, loop;
-
-	_enter("%p", conn);
-
-	/* allocate and initialise a call record */
-	ret = __rxrpc_create_call(conn, &call);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	call->app_call_state = RXRPC_CSTATE_CLNT_SND_ARGS;
-	if (attn)
-		call->app_attn_func = attn;
-	if (error)
-		call->app_error_func = error;
-	if (aemap)
-		call->app_aemap_func = aemap;
-
-	_state(call);
-
-	spin_lock(&conn->lock);
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&conn->chanwait, &myself);
-
- try_again:
-	/* try to find an unused channel */
-	for (cix = 0; cix < 4; cix++)
-		if (!conn->channels[cix])
-			goto obtained_chan;
-
-	/* no free channels - wait for one to become available */
-	ret = -EINTR;
-	if (signal_pending(current))
-		goto error_unwait;
-
-	spin_unlock(&conn->lock);
-
-	schedule();
-	set_current_state(TASK_INTERRUPTIBLE);
-
-	spin_lock(&conn->lock);
-	goto try_again;
-
-	/* got a channel - now attach to the connection */
- obtained_chan:
-	remove_wait_queue(&conn->chanwait, &myself);
-	set_current_state(TASK_RUNNING);
-
-	/* concoct a unique call number */
- next_callid:
-	call->call_id = htonl(++conn->call_counter);
-	for (loop = 0; loop < 4; loop++)
-		if (conn->channels[loop] &&
-		    conn->channels[loop]->call_id == call->call_id)
-			goto next_callid;
-
-	rxrpc_get_connection(conn);
-	conn->channels[cix] = call; /* assign _after_ done callid check loop */
-	do_gettimeofday(&conn->atime);
-	call->chan_ix = htonl(cix);
-
-	spin_unlock(&conn->lock);
-
-	down_write(&rxrpc_calls_sem);
-	list_add_tail(&call->call_link, &rxrpc_calls);
-	up_write(&rxrpc_calls_sem);
-
-	__RXACCT(atomic_inc(&rxrpc_call_count));
-	*_call = call;
-
-	_leave(" = 0 (call=%p cix=%u)", call, cix);
-	return 0;
-
- error_unwait:
-	remove_wait_queue(&conn->chanwait, &myself);
-	set_current_state(TASK_RUNNING);
-	spin_unlock(&conn->lock);
-
-	free_page((unsigned long) call);
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_create_call() */
-
-/*****************************************************************************/
-/*
- * create a new call record for incoming calls
- */
-int rxrpc_incoming_call(struct rxrpc_connection *conn,
-			struct rxrpc_message *msg,
-			struct rxrpc_call **_call)
-{
-	struct rxrpc_call *call;
-	unsigned cix;
-	int ret;
-
-	cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK;
-
-	_enter("%p,%u,%u", conn, ntohl(msg->hdr.callNumber), cix);
-
-	/* allocate and initialise a call record */
-	ret = __rxrpc_create_call(conn, &call);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	call->pkt_rcv_count = 1;
-	call->app_call_state = RXRPC_CSTATE_SRVR_RCV_OPID;
-	call->app_mark = sizeof(uint32_t);
-
-	_state(call);
-
-	/* attach to the connection */
-	ret = -EBUSY;
-	call->chan_ix = htonl(cix);
-	call->call_id = msg->hdr.callNumber;
-
-	spin_lock(&conn->lock);
-
-	if (!conn->channels[cix] ||
-	    conn->channels[cix]->app_call_state == RXRPC_CSTATE_COMPLETE ||
-	    conn->channels[cix]->app_call_state == RXRPC_CSTATE_ERROR
-	    ) {
-		conn->channels[cix] = call;
-		rxrpc_get_connection(conn);
-		ret = 0;
-	}
-
-	spin_unlock(&conn->lock);
-
-	if (ret < 0) {
-		free_page((unsigned long) call);
-		call = NULL;
-	}
-
-	if (ret == 0) {
-		down_write(&rxrpc_calls_sem);
-		list_add_tail(&call->call_link, &rxrpc_calls);
-		up_write(&rxrpc_calls_sem);
-		__RXACCT(atomic_inc(&rxrpc_call_count));
-		*_call = call;
-	}
-
-	_leave(" = %d [%p]", ret, call);
-	return ret;
-} /* end rxrpc_incoming_call() */
-
-/*****************************************************************************/
-/*
- * free a call record
- */
-void rxrpc_put_call(struct rxrpc_call *call)
-{
-	struct rxrpc_connection *conn = call->conn;
-	struct rxrpc_message *msg;
-
-	_enter("%p{u=%d}",call,atomic_read(&call->usage));
-
-	/* sanity check */
-	if (atomic_read(&call->usage) <= 0)
-		BUG();
-
-	/* to prevent a race, the decrement and the de-list must be effectively
-	 * atomic */
-	spin_lock(&conn->lock);
-	if (likely(!atomic_dec_and_test(&call->usage))) {
-		spin_unlock(&conn->lock);
-		_leave("");
-		return;
-	}
-
-	if (conn->channels[ntohl(call->chan_ix)] == call)
-		conn->channels[ntohl(call->chan_ix)] = NULL;
-
-	spin_unlock(&conn->lock);
-
-	wake_up(&conn->chanwait);
-
-	rxrpc_put_connection(conn);
-
-	/* clear the timers and dequeue from krxiod */
-	del_timer_sync(&call->acks_timeout);
-	del_timer_sync(&call->rcv_timeout);
-	del_timer_sync(&call->ackr_dfr_timo);
-
-	rxrpc_krxiod_dequeue_call(call);
-
-	/* clean up the contents of the struct */
-	if (call->snd_nextmsg)
-		rxrpc_put_message(call->snd_nextmsg);
-
-	if (call->snd_ping)
-		rxrpc_put_message(call->snd_ping);
-
-	while (!list_empty(&call->acks_pendq)) {
-		msg = list_entry(call->acks_pendq.next,
-				 struct rxrpc_message, link);
-		list_del(&msg->link);
-		rxrpc_put_message(msg);
-	}
-
-	while (!list_empty(&call->rcv_receiveq)) {
-		msg = list_entry(call->rcv_receiveq.next,
-				 struct rxrpc_message, link);
-		list_del(&msg->link);
-		rxrpc_put_message(msg);
-	}
-
-	while (!list_empty(&call->app_readyq)) {
-		msg = list_entry(call->app_readyq.next,
-				 struct rxrpc_message, link);
-		list_del(&msg->link);
-		rxrpc_put_message(msg);
-	}
-
-	while (!list_empty(&call->app_unreadyq)) {
-		msg = list_entry(call->app_unreadyq.next,
-				 struct rxrpc_message, link);
-		list_del(&msg->link);
-		rxrpc_put_message(msg);
-	}
-
-	module_put(call->owner);
-
-	down_write(&rxrpc_calls_sem);
-	list_del(&call->call_link);
-	up_write(&rxrpc_calls_sem);
-
-	__RXACCT(atomic_dec(&rxrpc_call_count));
-	free_page((unsigned long) call);
-
-	_leave(" [destroyed]");
-} /* end rxrpc_put_call() */
-
-/*****************************************************************************/
-/*
- * actually generate a normal ACK
- */
-static inline int __rxrpc_call_gen_normal_ACK(struct rxrpc_call *call,
-					      rxrpc_seq_t seq)
-{
-	struct rxrpc_message *msg;
-	struct kvec diov[3];
-	__be32 aux[4];
-	int delta, ret;
-
-	/* ACKs default to DELAY */
-	if (!call->ackr.reason)
-		call->ackr.reason = RXRPC_ACK_DELAY;
-
-	_proto("Rx %05lu Sending ACK { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
-	       jiffies - call->cjif,
-	       ntohs(call->ackr.maxSkew),
-	       ntohl(call->ackr.firstPacket),
-	       ntohl(call->ackr.previousPacket),
-	       ntohl(call->ackr.serial),
-	       rxrpc_acks[call->ackr.reason],
-	       call->ackr.nAcks);
-
-	aux[0] = htonl(call->conn->peer->if_mtu);	/* interface MTU */
-	aux[1] = htonl(1444);				/* max MTU */
-	aux[2] = htonl(16);				/* rwind */
-	aux[3] = htonl(4);				/* max packets */
-
-	diov[0].iov_len  = sizeof(struct rxrpc_ackpacket);
-	diov[0].iov_base = &call->ackr;
-	diov[1].iov_len  = call->ackr_pend_cnt + 3;
-	diov[1].iov_base = call->ackr_array;
-	diov[2].iov_len  = sizeof(aux);
-	diov[2].iov_base = &aux;
-
-	/* build and send the message */
-	ret = rxrpc_conn_newmsg(call->conn,call, RXRPC_PACKET_TYPE_ACK,
-				3, diov, GFP_KERNEL, &msg);
-	if (ret < 0)
-		goto out;
-
-	msg->seq = seq;
-	msg->hdr.seq = htonl(seq);
-	msg->hdr.flags |= RXRPC_SLOW_START_OK;
-
-	ret = rxrpc_conn_sendmsg(call->conn, msg);
-	rxrpc_put_message(msg);
-	if (ret < 0)
-		goto out;
-	call->pkt_snd_count++;
-
-	/* count how many actual ACKs there were at the front */
-	for (delta = 0; delta < call->ackr_pend_cnt; delta++)
-		if (call->ackr_array[delta] != RXRPC_ACK_TYPE_ACK)
-			break;
-
-	call->ackr_pend_cnt -= delta; /* all ACK'd to this point */
-
-	/* crank the ACK window around */
-	if (delta == 0) {
-		/* un-ACK'd window */
-	}
-	else if (delta < RXRPC_CALL_ACK_WINDOW_SIZE) {
-		/* partially ACK'd window
-		 * - shuffle down to avoid losing out-of-sequence packets
-		 */
-		call->ackr_win_bot += delta;
-		call->ackr_win_top += delta;
-
-		memmove(&call->ackr_array[0],
-			&call->ackr_array[delta],
-			call->ackr_pend_cnt);
-
-		memset(&call->ackr_array[call->ackr_pend_cnt],
-		       RXRPC_ACK_TYPE_NACK,
-		       sizeof(call->ackr_array) - call->ackr_pend_cnt);
-	}
-	else {
-		/* fully ACK'd window
-		 * - just clear the whole thing
-		 */
-		memset(&call->ackr_array,
-		       RXRPC_ACK_TYPE_NACK,
-		       sizeof(call->ackr_array));
-	}
-
-	/* clear this ACK */
-	memset(&call->ackr, 0, sizeof(call->ackr));
-
- out:
-	if (!call->app_call_state)
-		printk("___ STATE 0 ___\n");
-	return ret;
-} /* end __rxrpc_call_gen_normal_ACK() */
-
-/*****************************************************************************/
-/*
- * note the reception of a packet in the call's ACK records and generate an
- * appropriate ACK packet if necessary
- * - returns 0 if packet should be processed, 1 if packet should be ignored
- *   and -ve on an error
- */
-static int rxrpc_call_generate_ACK(struct rxrpc_call *call,
-				   struct rxrpc_header *hdr,
-				   struct rxrpc_ackpacket *ack)
-{
-	struct rxrpc_message *msg;
-	rxrpc_seq_t seq;
-	unsigned offset;
-	int ret = 0, err;
-	u8 special_ACK, do_ACK, force;
-
-	_enter("%p,%p { seq=%d tp=%d fl=%02x }",
-	       call, hdr, ntohl(hdr->seq), hdr->type, hdr->flags);
-
-	seq = ntohl(hdr->seq);
-	offset = seq - call->ackr_win_bot;
-	do_ACK = RXRPC_ACK_DELAY;
-	special_ACK = 0;
-	force = (seq == 1);
-
-	if (call->ackr_high_seq < seq)
-		call->ackr_high_seq = seq;
-
-	/* deal with generation of obvious special ACKs first */
-	if (ack && ack->reason == RXRPC_ACK_PING) {
-		special_ACK = RXRPC_ACK_PING_RESPONSE;
-		ret = 1;
-		goto gen_ACK;
-	}
-
-	if (seq < call->ackr_win_bot) {
-		special_ACK = RXRPC_ACK_DUPLICATE;
-		ret = 1;
-		goto gen_ACK;
-	}
-
-	if (seq >= call->ackr_win_top) {
-		special_ACK = RXRPC_ACK_EXCEEDS_WINDOW;
-		ret = 1;
-		goto gen_ACK;
-	}
-
-	if (call->ackr_array[offset] != RXRPC_ACK_TYPE_NACK) {
-		special_ACK = RXRPC_ACK_DUPLICATE;
-		ret = 1;
-		goto gen_ACK;
-	}
-
-	/* okay... it's a normal data packet inside the ACK window */
-	call->ackr_array[offset] = RXRPC_ACK_TYPE_ACK;
-
-	if (offset < call->ackr_pend_cnt) {
-	}
-	else if (offset > call->ackr_pend_cnt) {
-		do_ACK = RXRPC_ACK_OUT_OF_SEQUENCE;
-		call->ackr_pend_cnt = offset;
-		goto gen_ACK;
-	}
-
-	if (hdr->flags & RXRPC_REQUEST_ACK) {
-		do_ACK = RXRPC_ACK_REQUESTED;
-	}
-
-	/* generate an ACK on the final packet of a reply just received */
-	if (hdr->flags & RXRPC_LAST_PACKET) {
-		if (call->conn->out_clientflag)
-			force = 1;
-	}
-	else if (!(hdr->flags & RXRPC_MORE_PACKETS)) {
-		do_ACK = RXRPC_ACK_REQUESTED;
-	}
-
-	/* re-ACK packets previously received out-of-order */
-	for (offset++; offset < RXRPC_CALL_ACK_WINDOW_SIZE; offset++)
-		if (call->ackr_array[offset] != RXRPC_ACK_TYPE_ACK)
-			break;
-
-	call->ackr_pend_cnt = offset;
-
-	/* generate an ACK if we fill up the window */
-	if (call->ackr_pend_cnt >= RXRPC_CALL_ACK_WINDOW_SIZE)
-		force = 1;
-
- gen_ACK:
-	_debug("%05lu ACKs pend=%u norm=%s special=%s%s",
-	       jiffies - call->cjif,
-	       call->ackr_pend_cnt,
-	       rxrpc_acks[do_ACK],
-	       rxrpc_acks[special_ACK],
-	       force ? " immediate" :
-	       do_ACK == RXRPC_ACK_REQUESTED ? " merge-req" :
-	       hdr->flags & RXRPC_LAST_PACKET ? " finalise" :
-	       " defer"
-	       );
-
-	/* send any pending normal ACKs if need be */
-	if (call->ackr_pend_cnt > 0) {
-		/* fill out the appropriate form */
-		call->ackr.bufferSpace	= htons(RXRPC_CALL_ACK_WINDOW_SIZE);
-		call->ackr.maxSkew	= htons(min(call->ackr_high_seq - seq,
-						    65535U));
-		call->ackr.firstPacket	= htonl(call->ackr_win_bot);
-		call->ackr.previousPacket = call->ackr_prev_seq;
-		call->ackr.serial	= hdr->serial;
-		call->ackr.nAcks	= call->ackr_pend_cnt;
-
-		if (do_ACK == RXRPC_ACK_REQUESTED)
-			call->ackr.reason = do_ACK;
-
-		/* generate the ACK immediately if necessary */
-		if (special_ACK || force) {
-			err = __rxrpc_call_gen_normal_ACK(
-				call, do_ACK == RXRPC_ACK_DELAY ? 0 : seq);
-			if (err < 0) {
-				ret = err;
-				goto out;
-			}
-		}
-	}
-
-	if (call->ackr.reason == RXRPC_ACK_REQUESTED)
-		call->ackr_dfr_seq = seq;
-
-	/* start the ACK timer if not running if there are any pending deferred
-	 * ACKs */
-	if (call->ackr_pend_cnt > 0 &&
-	    call->ackr.reason != RXRPC_ACK_REQUESTED &&
-	    !timer_pending(&call->ackr_dfr_timo)
-	    ) {
-		unsigned long timo;
-
-		timo = rxrpc_call_dfr_ack_timeout + jiffies;
-
-		_debug("START ACKR TIMER for cj=%lu", timo - call->cjif);
-
-		spin_lock(&call->lock);
-		mod_timer(&call->ackr_dfr_timo, timo);
-		spin_unlock(&call->lock);
-	}
-	else if ((call->ackr_pend_cnt == 0 ||
-		  call->ackr.reason == RXRPC_ACK_REQUESTED) &&
-		 timer_pending(&call->ackr_dfr_timo)
-		 ) {
-		/* stop timer if no pending ACKs */
-		_debug("CLEAR ACKR TIMER");
-		del_timer_sync(&call->ackr_dfr_timo);
-	}
-
-	/* send a special ACK if one is required */
-	if (special_ACK) {
-		struct rxrpc_ackpacket ack;
-		struct kvec diov[2];
-		uint8_t acks[1] = { RXRPC_ACK_TYPE_ACK };
-
-		/* fill out the appropriate form */
-		ack.bufferSpace	= htons(RXRPC_CALL_ACK_WINDOW_SIZE);
-		ack.maxSkew	= htons(min(call->ackr_high_seq - seq,
-					    65535U));
-		ack.firstPacket	= htonl(call->ackr_win_bot);
-		ack.previousPacket = call->ackr_prev_seq;
-		ack.serial	= hdr->serial;
-		ack.reason	= special_ACK;
-		ack.nAcks	= 0;
-
-		_proto("Rx Sending s-ACK"
-		       " { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
-		       ntohs(ack.maxSkew),
-		       ntohl(ack.firstPacket),
-		       ntohl(ack.previousPacket),
-		       ntohl(ack.serial),
-		       rxrpc_acks[ack.reason],
-		       ack.nAcks);
-
-		diov[0].iov_len  = sizeof(struct rxrpc_ackpacket);
-		diov[0].iov_base = &ack;
-		diov[1].iov_len  = sizeof(acks);
-		diov[1].iov_base = acks;
-
-		/* build and send the message */
-		err = rxrpc_conn_newmsg(call->conn,call, RXRPC_PACKET_TYPE_ACK,
-					hdr->seq ? 2 : 1, diov,
-					GFP_KERNEL,
-					&msg);
-		if (err < 0) {
-			ret = err;
-			goto out;
-		}
-
-		msg->seq = seq;
-		msg->hdr.seq = htonl(seq);
-		msg->hdr.flags |= RXRPC_SLOW_START_OK;
-
-		err = rxrpc_conn_sendmsg(call->conn, msg);
-		rxrpc_put_message(msg);
-		if (err < 0) {
-			ret = err;
-			goto out;
-		}
-		call->pkt_snd_count++;
-	}
-
- out:
-	if (hdr->seq)
-		call->ackr_prev_seq = hdr->seq;
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_call_generate_ACK() */
-
-/*****************************************************************************/
-/*
- * handle work to be done on a call
- * - includes packet reception and timeout processing
- */
-void rxrpc_call_do_stuff(struct rxrpc_call *call)
-{
-	_enter("%p{flags=%lx}", call, call->flags);
-
-	/* handle packet reception */
-	if (call->flags & RXRPC_CALL_RCV_PKT) {
-		_debug("- receive packet");
-		call->flags &= ~RXRPC_CALL_RCV_PKT;
-		rxrpc_call_receive_packet(call);
-	}
-
-	/* handle overdue ACKs */
-	if (call->flags & RXRPC_CALL_ACKS_TIMO) {
-		_debug("- overdue ACK timeout");
-		call->flags &= ~RXRPC_CALL_ACKS_TIMO;
-		rxrpc_call_resend(call, call->snd_seq_count);
-	}
-
-	/* handle lack of reception */
-	if (call->flags & RXRPC_CALL_RCV_TIMO) {
-		_debug("- reception timeout");
-		call->flags &= ~RXRPC_CALL_RCV_TIMO;
-		rxrpc_call_abort(call, -EIO);
-	}
-
-	/* handle deferred ACKs */
-	if (call->flags & RXRPC_CALL_ACKR_TIMO ||
-	    (call->ackr.nAcks > 0 && call->ackr.reason == RXRPC_ACK_REQUESTED)
-	    ) {
-		_debug("- deferred ACK timeout: cj=%05lu r=%s n=%u",
-		       jiffies - call->cjif,
-		       rxrpc_acks[call->ackr.reason],
-		       call->ackr.nAcks);
-
-		call->flags &= ~RXRPC_CALL_ACKR_TIMO;
-
-		if (call->ackr.nAcks > 0 &&
-		    call->app_call_state != RXRPC_CSTATE_ERROR) {
-			/* generate ACK */
-			__rxrpc_call_gen_normal_ACK(call, call->ackr_dfr_seq);
-			call->ackr_dfr_seq = 0;
-		}
-	}
-
-	_leave("");
-
-} /* end rxrpc_call_do_stuff() */
-
-/*****************************************************************************/
-/*
- * send an abort message at call or connection level
- * - must be called with call->lock held
- * - the supplied error code is sent as the packet data
- */
-static int __rxrpc_call_abort(struct rxrpc_call *call, int errno)
-{
-	struct rxrpc_connection *conn = call->conn;
-	struct rxrpc_message *msg;
-	struct kvec diov[1];
-	int ret;
-	__be32 _error;
-
-	_enter("%p{%08x},%p{%d},%d",
-	       conn, ntohl(conn->conn_id), call, ntohl(call->call_id), errno);
-
-	/* if this call is already aborted, then just wake up any waiters */
-	if (call->app_call_state == RXRPC_CSTATE_ERROR) {
-		spin_unlock(&call->lock);
-		call->app_error_func(call);
-		_leave(" = 0");
-		return 0;
-	}
-
-	rxrpc_get_call(call);
-
-	/* change the state _with_ the lock still held */
-	call->app_call_state	= RXRPC_CSTATE_ERROR;
-	call->app_err_state	= RXRPC_ESTATE_LOCAL_ABORT;
-	call->app_errno		= errno;
-	call->app_mark		= RXRPC_APP_MARK_EOF;
-	call->app_read_buf	= NULL;
-	call->app_async_read	= 0;
-
-	_state(call);
-
-	/* ask the app to translate the error code */
-	call->app_aemap_func(call);
-
-	spin_unlock(&call->lock);
-
-	/* flush any outstanding ACKs */
-	del_timer_sync(&call->acks_timeout);
-	del_timer_sync(&call->rcv_timeout);
-	del_timer_sync(&call->ackr_dfr_timo);
-
-	if (rxrpc_call_is_ack_pending(call))
-		__rxrpc_call_gen_normal_ACK(call, 0);
-
-	/* send the abort packet only if we actually traded some other
-	 * packets */
-	ret = 0;
-	if (call->pkt_snd_count || call->pkt_rcv_count) {
-		/* actually send the abort */
-		_proto("Rx Sending Call ABORT { data=%d }",
-		       call->app_abort_code);
-
-		_error = htonl(call->app_abort_code);
-
-		diov[0].iov_len  = sizeof(_error);
-		diov[0].iov_base = &_error;
-
-		ret = rxrpc_conn_newmsg(conn, call, RXRPC_PACKET_TYPE_ABORT,
-					1, diov, GFP_KERNEL, &msg);
-		if (ret == 0) {
-			ret = rxrpc_conn_sendmsg(conn, msg);
-			rxrpc_put_message(msg);
-		}
-	}
-
-	/* tell the app layer to let go */
-	call->app_error_func(call);
-
-	rxrpc_put_call(call);
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end __rxrpc_call_abort() */
-
-/*****************************************************************************/
-/*
- * send an abort message at call or connection level
- * - the supplied error code is sent as the packet data
- */
-int rxrpc_call_abort(struct rxrpc_call *call, int error)
-{
-	spin_lock(&call->lock);
-
-	return __rxrpc_call_abort(call, error);
-
-} /* end rxrpc_call_abort() */
-
-/*****************************************************************************/
-/*
- * process packets waiting for this call
- */
-static void rxrpc_call_receive_packet(struct rxrpc_call *call)
-{
-	struct rxrpc_message *msg;
-	struct list_head *_p;
-
-	_enter("%p", call);
-
-	rxrpc_get_call(call); /* must not go away too soon if aborted by
-			       * app-layer */
-
-	while (!list_empty(&call->rcv_receiveq)) {
-		/* try to get next packet */
-		_p = NULL;
-		spin_lock(&call->lock);
-		if (!list_empty(&call->rcv_receiveq)) {
-			_p = call->rcv_receiveq.next;
-			list_del_init(_p);
-		}
-		spin_unlock(&call->lock);
-
-		if (!_p)
-			break;
-
-		msg = list_entry(_p, struct rxrpc_message, link);
-
-		_proto("Rx %05lu Received %s packet (%%%u,#%u,%c%c%c%c%c)",
-		       jiffies - call->cjif,
-		       rxrpc_pkts[msg->hdr.type],
-		       ntohl(msg->hdr.serial),
-		       msg->seq,
-		       msg->hdr.flags & RXRPC_JUMBO_PACKET	? 'j' : '-',
-		       msg->hdr.flags & RXRPC_MORE_PACKETS	? 'm' : '-',
-		       msg->hdr.flags & RXRPC_LAST_PACKET	? 'l' : '-',
-		       msg->hdr.flags & RXRPC_REQUEST_ACK	? 'r' : '-',
-		       msg->hdr.flags & RXRPC_CLIENT_INITIATED	? 'C' : 'S'
-		       );
-
-		switch (msg->hdr.type) {
-			/* deal with data packets */
-		case RXRPC_PACKET_TYPE_DATA:
-			/* ACK the packet if necessary */
-			switch (rxrpc_call_generate_ACK(call, &msg->hdr,
-							NULL)) {
-			case 0: /* useful packet */
-				rxrpc_call_receive_data_packet(call, msg);
-				break;
-			case 1: /* duplicate or out-of-window packet */
-				break;
-			default:
-				rxrpc_put_message(msg);
-				goto out;
-			}
-			break;
-
-			/* deal with ACK packets */
-		case RXRPC_PACKET_TYPE_ACK:
-			rxrpc_call_receive_ack_packet(call, msg);
-			break;
-
-			/* deal with abort packets */
-		case RXRPC_PACKET_TYPE_ABORT: {
-			__be32 _dbuf, *dp;
-
-			dp = skb_header_pointer(msg->pkt, msg->offset,
-						sizeof(_dbuf), &_dbuf);
-			if (dp == NULL)
-				printk("Rx Received short ABORT packet\n");
-
-			_proto("Rx Received Call ABORT { data=%d }",
-			       (dp ? ntohl(*dp) : 0));
-
-			spin_lock(&call->lock);
-			call->app_call_state	= RXRPC_CSTATE_ERROR;
-			call->app_err_state	= RXRPC_ESTATE_PEER_ABORT;
-			call->app_abort_code	= (dp ? ntohl(*dp) : 0);
-			call->app_errno		= -ECONNABORTED;
-			call->app_mark		= RXRPC_APP_MARK_EOF;
-			call->app_read_buf	= NULL;
-			call->app_async_read	= 0;
-
-			/* ask the app to translate the error code */
-			call->app_aemap_func(call);
-			_state(call);
-			spin_unlock(&call->lock);
-			call->app_error_func(call);
-			break;
-		}
-		default:
-			/* deal with other packet types */
-			_proto("Rx Unsupported packet type %u (#%u)",
-			       msg->hdr.type, msg->seq);
-			break;
-		}
-
-		rxrpc_put_message(msg);
-	}
-
- out:
-	rxrpc_put_call(call);
-	_leave("");
-} /* end rxrpc_call_receive_packet() */
-
-/*****************************************************************************/
-/*
- * process next data packet
- * - as the next data packet arrives:
- *   - it is queued on app_readyq _if_ it is the next one expected
- *     (app_ready_seq+1)
- *   - it is queued on app_unreadyq _if_ it is not the next one expected
- *   - if a packet placed on app_readyq completely fills a hole leading up to
- *     the first packet on app_unreadyq, then packets now in sequence are
- *     tranferred to app_readyq
- * - the application layer can only see packets on app_readyq
- *   (app_ready_qty bytes)
- * - the application layer is prodded every time a new packet arrives
- */
-static void rxrpc_call_receive_data_packet(struct rxrpc_call *call,
-					   struct rxrpc_message *msg)
-{
-	const struct rxrpc_operation *optbl, *op;
-	struct rxrpc_message *pmsg;
-	struct list_head *_p;
-	int ret, lo, hi, rmtimo;
-	__be32 opid;
-
-	_enter("%p{%u},%p{%u}", call, ntohl(call->call_id), msg, msg->seq);
-
-	rxrpc_get_message(msg);
-
-	/* add to the unready queue if we'd have to create a hole in the ready
-	 * queue otherwise */
-	if (msg->seq != call->app_ready_seq + 1) {
-		_debug("Call add packet %d to unreadyq", msg->seq);
-
-		/* insert in seq order */
-		list_for_each(_p, &call->app_unreadyq) {
-			pmsg = list_entry(_p, struct rxrpc_message, link);
-			if (pmsg->seq > msg->seq)
-				break;
-		}
-
-		list_add_tail(&msg->link, _p);
-
-		_leave(" [unreadyq]");
-		return;
-	}
-
-	/* next in sequence - simply append into the call's ready queue */
-	_debug("Call add packet %d to readyq (+%Zd => %Zd bytes)",
-	       msg->seq, msg->dsize, call->app_ready_qty);
-
-	spin_lock(&call->lock);
-	call->app_ready_seq = msg->seq;
-	call->app_ready_qty += msg->dsize;
-	list_add_tail(&msg->link, &call->app_readyq);
-
-	/* move unready packets to the readyq if we got rid of a hole */
-	while (!list_empty(&call->app_unreadyq)) {
-		pmsg = list_entry(call->app_unreadyq.next,
-				  struct rxrpc_message, link);
-
-		if (pmsg->seq != call->app_ready_seq + 1)
-			break;
-
-		/* next in sequence - just move list-to-list */
-		_debug("Call transfer packet %d to readyq (+%Zd => %Zd bytes)",
-		       pmsg->seq, pmsg->dsize, call->app_ready_qty);
-
-		call->app_ready_seq = pmsg->seq;
-		call->app_ready_qty += pmsg->dsize;
-		list_move_tail(&pmsg->link, &call->app_readyq);
-	}
-
-	/* see if we've got the last packet yet */
-	if (!list_empty(&call->app_readyq)) {
-		pmsg = list_entry(call->app_readyq.prev,
-				  struct rxrpc_message, link);
-		if (pmsg->hdr.flags & RXRPC_LAST_PACKET) {
-			call->app_last_rcv = 1;
-			_debug("Last packet on readyq");
-		}
-	}
-
-	switch (call->app_call_state) {
-		/* do nothing if call already aborted */
-	case RXRPC_CSTATE_ERROR:
-		spin_unlock(&call->lock);
-		_leave(" [error]");
-		return;
-
-		/* extract the operation ID from an incoming call if that's not
-		 * yet been done */
-	case RXRPC_CSTATE_SRVR_RCV_OPID:
-		spin_unlock(&call->lock);
-
-		/* handle as yet insufficient data for the operation ID */
-		if (call->app_ready_qty < 4) {
-			if (call->app_last_rcv)
-				/* trouble - last packet seen */
-				rxrpc_call_abort(call, -EINVAL);
-
-			_leave("");
-			return;
-		}
-
-		/* pull the operation ID out of the buffer */
-		ret = rxrpc_call_read_data(call, &opid, sizeof(opid), 0);
-		if (ret < 0) {
-			printk("Unexpected error from read-data: %d\n", ret);
-			if (call->app_call_state != RXRPC_CSTATE_ERROR)
-				rxrpc_call_abort(call, ret);
-			_leave("");
-			return;
-		}
-		call->app_opcode = ntohl(opid);
-
-		/* locate the operation in the available ops table */
-		optbl = call->conn->service->ops_begin;
-		lo = 0;
-		hi = call->conn->service->ops_end - optbl;
-
-		while (lo < hi) {
-			int mid = (hi + lo) / 2;
-			op = &optbl[mid];
-			if (call->app_opcode == op->id)
-				goto found_op;
-			if (call->app_opcode > op->id)
-				lo = mid + 1;
-			else
-				hi = mid;
-		}
-
-		/* search failed */
-		kproto("Rx Client requested operation %d from %s service",
-		       call->app_opcode, call->conn->service->name);
-		rxrpc_call_abort(call, -EINVAL);
-		_leave(" [inval]");
-		return;
-
-	found_op:
-		_proto("Rx Client requested operation %s from %s service",
-		       op->name, call->conn->service->name);
-
-		/* we're now waiting for the argument block (unless the call
-		 * was aborted) */
-		spin_lock(&call->lock);
-		if (call->app_call_state == RXRPC_CSTATE_SRVR_RCV_OPID ||
-		    call->app_call_state == RXRPC_CSTATE_SRVR_SND_REPLY) {
-			if (!call->app_last_rcv)
-				call->app_call_state =
-					RXRPC_CSTATE_SRVR_RCV_ARGS;
-			else if (call->app_ready_qty > 0)
-				call->app_call_state =
-					RXRPC_CSTATE_SRVR_GOT_ARGS;
-			else
-				call->app_call_state =
-					RXRPC_CSTATE_SRVR_SND_REPLY;
-			call->app_mark = op->asize;
-			call->app_user = op->user;
-		}
-		spin_unlock(&call->lock);
-
-		_state(call);
-		break;
-
-	case RXRPC_CSTATE_SRVR_RCV_ARGS:
-		/* change state if just received last packet of arg block */
-		if (call->app_last_rcv)
-			call->app_call_state = RXRPC_CSTATE_SRVR_GOT_ARGS;
-		spin_unlock(&call->lock);
-
-		_state(call);
-		break;
-
-	case RXRPC_CSTATE_CLNT_RCV_REPLY:
-		/* change state if just received last packet of reply block */
-		rmtimo = 0;
-		if (call->app_last_rcv) {
-			call->app_call_state = RXRPC_CSTATE_CLNT_GOT_REPLY;
-			rmtimo = 1;
-		}
-		spin_unlock(&call->lock);
-
-		if (rmtimo) {
-			del_timer_sync(&call->acks_timeout);
-			del_timer_sync(&call->rcv_timeout);
-			del_timer_sync(&call->ackr_dfr_timo);
-		}
-
-		_state(call);
-		break;
-
-	default:
-		/* deal with data reception in an unexpected state */
-		printk("Unexpected state [[[ %u ]]]\n", call->app_call_state);
-		__rxrpc_call_abort(call, -EBADMSG);
-		_leave("");
-		return;
-	}
-
-	if (call->app_call_state == RXRPC_CSTATE_CLNT_RCV_REPLY &&
-	    call->app_last_rcv)
-		BUG();
-
-	/* otherwise just invoke the data function whenever we can satisfy its desire for more
-	 * data
-	 */
-	_proto("Rx Received Op Data: st=%u qty=%Zu mk=%Zu%s",
-	       call->app_call_state, call->app_ready_qty, call->app_mark,
-	       call->app_last_rcv ? " last-rcvd" : "");
-
-	spin_lock(&call->lock);
-
-	ret = __rxrpc_call_read_data(call);
-	switch (ret) {
-	case 0:
-		spin_unlock(&call->lock);
-		call->app_attn_func(call);
-		break;
-	case -EAGAIN:
-		spin_unlock(&call->lock);
-		break;
-	case -ECONNABORTED:
-		spin_unlock(&call->lock);
-		break;
-	default:
-		__rxrpc_call_abort(call, ret);
-		break;
-	}
-
-	_state(call);
-
-	_leave("");
-
-} /* end rxrpc_call_receive_data_packet() */
-
-/*****************************************************************************/
-/*
- * received an ACK packet
- */
-static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
-					  struct rxrpc_message *msg)
-{
-	struct rxrpc_ackpacket _ack, *ap;
-	rxrpc_serial_net_t serial;
-	rxrpc_seq_t seq;
-	int ret;
-
-	_enter("%p{%u},%p{%u}", call, ntohl(call->call_id), msg, msg->seq);
-
-	/* extract the basic ACK record */
-	ap = skb_header_pointer(msg->pkt, msg->offset, sizeof(_ack), &_ack);
-	if (ap == NULL) {
-		printk("Rx Received short ACK packet\n");
-		return;
-	}
-	msg->offset += sizeof(_ack);
-
-	serial = ap->serial;
-	seq = ntohl(ap->firstPacket);
-
-	_proto("Rx Received ACK %%%d { b=%hu m=%hu f=%u p=%u s=%u r=%s n=%u }",
-	       ntohl(msg->hdr.serial),
-	       ntohs(ap->bufferSpace),
-	       ntohs(ap->maxSkew),
-	       seq,
-	       ntohl(ap->previousPacket),
-	       ntohl(serial),
-	       rxrpc_acks[ap->reason],
-	       call->ackr.nAcks
-	       );
-
-	/* check the other side isn't ACK'ing a sequence number I haven't sent
-	 * yet */
-	if (ap->nAcks > 0 &&
-	    (seq > call->snd_seq_count ||
-	     seq + ap->nAcks - 1 > call->snd_seq_count)) {
-		printk("Received ACK (#%u-#%u) for unsent packet\n",
-		       seq, seq + ap->nAcks - 1);
-		rxrpc_call_abort(call, -EINVAL);
-		_leave("");
-		return;
-	}
-
-	/* deal with RTT calculation */
-	if (serial) {
-		struct rxrpc_message *rttmsg;
-
-		/* find the prompting packet */
-		spin_lock(&call->lock);
-		if (call->snd_ping && call->snd_ping->hdr.serial == serial) {
-			/* it was a ping packet */
-			rttmsg = call->snd_ping;
-			call->snd_ping = NULL;
-			spin_unlock(&call->lock);
-
-			if (rttmsg) {
-				rttmsg->rttdone = 1;
-				rxrpc_peer_calculate_rtt(call->conn->peer,
-							 rttmsg, msg);
-				rxrpc_put_message(rttmsg);
-			}
-		}
-		else {
-			struct list_head *_p;
-
-			/* it ought to be a data packet - look in the pending
-			 * ACK list */
-			list_for_each(_p, &call->acks_pendq) {
-				rttmsg = list_entry(_p, struct rxrpc_message,
-						    link);
-				if (rttmsg->hdr.serial == serial) {
-					if (rttmsg->rttdone)
-						/* never do RTT twice without
-						 * resending */
-						break;
-
-					rttmsg->rttdone = 1;
-					rxrpc_peer_calculate_rtt(
-						call->conn->peer, rttmsg, msg);
-					break;
-				}
-			}
-			spin_unlock(&call->lock);
-		}
-	}
-
-	switch (ap->reason) {
-		/* deal with negative/positive acknowledgement of data
-		 * packets */
-	case RXRPC_ACK_REQUESTED:
-	case RXRPC_ACK_DELAY:
-	case RXRPC_ACK_IDLE:
-		rxrpc_call_definitively_ACK(call, seq - 1);
-
-	case RXRPC_ACK_DUPLICATE:
-	case RXRPC_ACK_OUT_OF_SEQUENCE:
-	case RXRPC_ACK_EXCEEDS_WINDOW:
-		call->snd_resend_cnt = 0;
-		ret = rxrpc_call_record_ACK(call, msg, seq, ap->nAcks);
-		if (ret < 0)
-			rxrpc_call_abort(call, ret);
-		break;
-
-		/* respond to ping packets immediately */
-	case RXRPC_ACK_PING:
-		rxrpc_call_generate_ACK(call, &msg->hdr, ap);
-		break;
-
-		/* only record RTT on ping response packets */
-	case RXRPC_ACK_PING_RESPONSE:
-		if (call->snd_ping) {
-			struct rxrpc_message *rttmsg;
-
-			/* only do RTT stuff if the response matches the
-			 * retained ping */
-			rttmsg = NULL;
-			spin_lock(&call->lock);
-			if (call->snd_ping &&
-			    call->snd_ping->hdr.serial == ap->serial) {
-				rttmsg = call->snd_ping;
-				call->snd_ping = NULL;
-			}
-			spin_unlock(&call->lock);
-
-			if (rttmsg) {
-				rttmsg->rttdone = 1;
-				rxrpc_peer_calculate_rtt(call->conn->peer,
-							 rttmsg, msg);
-				rxrpc_put_message(rttmsg);
-			}
-		}
-		break;
-
-	default:
-		printk("Unsupported ACK reason %u\n", ap->reason);
-		break;
-	}
-
-	_leave("");
-} /* end rxrpc_call_receive_ack_packet() */
-
-/*****************************************************************************/
-/*
- * record definitive ACKs for all messages up to and including the one with the
- * 'highest' seq
- */
-static void rxrpc_call_definitively_ACK(struct rxrpc_call *call,
-					rxrpc_seq_t highest)
-{
-	struct rxrpc_message *msg;
-	int now_complete;
-
-	_enter("%p{ads=%u},%u", call, call->acks_dftv_seq, highest);
-
-	while (call->acks_dftv_seq < highest) {
-		call->acks_dftv_seq++;
-
-		_proto("Definitive ACK on packet #%u", call->acks_dftv_seq);
-
-		/* discard those at front of queue until message with highest
-		 * ACK is found */
-		spin_lock(&call->lock);
-		msg = NULL;
-		if (!list_empty(&call->acks_pendq)) {
-			msg = list_entry(call->acks_pendq.next,
-					 struct rxrpc_message, link);
-			list_del_init(&msg->link); /* dequeue */
-			if (msg->state == RXRPC_MSG_SENT)
-				call->acks_pend_cnt--;
-		}
-		spin_unlock(&call->lock);
-
-		/* insanity check */
-		if (!msg)
-			panic("%s(): acks_pendq unexpectedly empty\n",
-			      __FUNCTION__);
-
-		if (msg->seq != call->acks_dftv_seq)
-			panic("%s(): Packet #%u expected at front of acks_pendq"
-			      " (#%u found)\n",
-			      __FUNCTION__, call->acks_dftv_seq, msg->seq);
-
-		/* discard the message */
-		msg->state = RXRPC_MSG_DONE;
-		rxrpc_put_message(msg);
-	}
-
-	/* if all sent packets are definitively ACK'd then prod any sleepers just in case */
-	now_complete = 0;
-	spin_lock(&call->lock);
-	if (call->acks_dftv_seq == call->snd_seq_count) {
-		if (call->app_call_state != RXRPC_CSTATE_COMPLETE) {
-			call->app_call_state = RXRPC_CSTATE_COMPLETE;
-			_state(call);
-			now_complete = 1;
-		}
-	}
-	spin_unlock(&call->lock);
-
-	if (now_complete) {
-		del_timer_sync(&call->acks_timeout);
-		del_timer_sync(&call->rcv_timeout);
-		del_timer_sync(&call->ackr_dfr_timo);
-		call->app_attn_func(call);
-	}
-
-	_leave("");
-} /* end rxrpc_call_definitively_ACK() */
-
-/*****************************************************************************/
-/*
- * record the specified amount of ACKs/NAKs
- */
-static int rxrpc_call_record_ACK(struct rxrpc_call *call,
-				 struct rxrpc_message *msg,
-				 rxrpc_seq_t seq,
-				 size_t count)
-{
-	struct rxrpc_message *dmsg;
-	struct list_head *_p;
-	rxrpc_seq_t highest;
-	unsigned ix;
-	size_t chunk;
-	char resend, now_complete;
-	u8 acks[16];
-
-	_enter("%p{apc=%u ads=%u},%p,%u,%Zu",
-	       call, call->acks_pend_cnt, call->acks_dftv_seq,
-	       msg, seq, count);
-
-	/* handle re-ACK'ing of definitively ACK'd packets (may be out-of-order
-	 * ACKs) */
-	if (seq <= call->acks_dftv_seq) {
-		unsigned delta = call->acks_dftv_seq - seq;
-
-		if (count <= delta) {
-			_leave(" = 0 [all definitively ACK'd]");
-			return 0;
-		}
-
-		seq += delta;
-		count -= delta;
-		msg->offset += delta;
-	}
-
-	highest = seq + count - 1;
-	resend = 0;
-	while (count > 0) {
-		/* extract up to 16 ACK slots at a time */
-		chunk = min(count, sizeof(acks));
-		count -= chunk;
-
-		memset(acks, 2, sizeof(acks));
-
-		if (skb_copy_bits(msg->pkt, msg->offset, &acks, chunk) < 0) {
-			printk("Rx Received short ACK packet\n");
-			_leave(" = -EINVAL");
-			return -EINVAL;
-		}
-		msg->offset += chunk;
-
-		/* check that the ACK set is valid */
-		for (ix = 0; ix < chunk; ix++) {
-			switch (acks[ix]) {
-			case RXRPC_ACK_TYPE_ACK:
-				break;
-			case RXRPC_ACK_TYPE_NACK:
-				resend = 1;
-				break;
-			default:
-				printk("Rx Received unsupported ACK state"
-				       " %u\n", acks[ix]);
-				_leave(" = -EINVAL");
-				return -EINVAL;
-			}
-		}
-
-		_proto("Rx ACK of packets #%u-#%u "
-		       "[%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c] (pend=%u)",
-		       seq, (unsigned) (seq + chunk - 1),
-		       _acktype[acks[0x0]],
-		       _acktype[acks[0x1]],
-		       _acktype[acks[0x2]],
-		       _acktype[acks[0x3]],
-		       _acktype[acks[0x4]],
-		       _acktype[acks[0x5]],
-		       _acktype[acks[0x6]],
-		       _acktype[acks[0x7]],
-		       _acktype[acks[0x8]],
-		       _acktype[acks[0x9]],
-		       _acktype[acks[0xA]],
-		       _acktype[acks[0xB]],
-		       _acktype[acks[0xC]],
-		       _acktype[acks[0xD]],
-		       _acktype[acks[0xE]],
-		       _acktype[acks[0xF]],
-		       call->acks_pend_cnt
-		       );
-
-		/* mark the packets in the ACK queue as being provisionally
-		 * ACK'd */
-		ix = 0;
-		spin_lock(&call->lock);
-
-		/* find the first packet ACK'd/NAK'd here */
-		list_for_each(_p, &call->acks_pendq) {
-			dmsg = list_entry(_p, struct rxrpc_message, link);
-			if (dmsg->seq == seq)
-				goto found_first;
-			_debug("- %u: skipping #%u", ix, dmsg->seq);
-		}
-		goto bad_queue;
-
-	found_first:
-		do {
-			_debug("- %u: processing #%u (%c) apc=%u",
-			       ix, dmsg->seq, _acktype[acks[ix]],
-			       call->acks_pend_cnt);
-
-			if (acks[ix] == RXRPC_ACK_TYPE_ACK) {
-				if (dmsg->state == RXRPC_MSG_SENT)
-					call->acks_pend_cnt--;
-				dmsg->state = RXRPC_MSG_ACKED;
-			}
-			else {
-				if (dmsg->state == RXRPC_MSG_ACKED)
-					call->acks_pend_cnt++;
-				dmsg->state = RXRPC_MSG_SENT;
-			}
-			ix++;
-			seq++;
-
-			_p = dmsg->link.next;
-			dmsg = list_entry(_p, struct rxrpc_message, link);
-		} while(ix < chunk &&
-			_p != &call->acks_pendq &&
-			dmsg->seq == seq);
-
-		if (ix < chunk)
-			goto bad_queue;
-
-		spin_unlock(&call->lock);
-	}
-
-	if (resend)
-		rxrpc_call_resend(call, highest);
-
-	/* if all packets are provisionally ACK'd, then wake up anyone who's
-	 * waiting for that */
-	now_complete = 0;
-	spin_lock(&call->lock);
-	if (call->acks_pend_cnt == 0) {
-		if (call->app_call_state == RXRPC_CSTATE_SRVR_RCV_FINAL_ACK) {
-			call->app_call_state = RXRPC_CSTATE_COMPLETE;
-			_state(call);
-		}
-		now_complete = 1;
-	}
-	spin_unlock(&call->lock);
-
-	if (now_complete) {
-		_debug("- wake up waiters");
-		del_timer_sync(&call->acks_timeout);
-		del_timer_sync(&call->rcv_timeout);
-		del_timer_sync(&call->ackr_dfr_timo);
-		call->app_attn_func(call);
-	}
-
-	_leave(" = 0 (apc=%u)", call->acks_pend_cnt);
-	return 0;
-
- bad_queue:
-	panic("%s(): acks_pendq in bad state (packet #%u absent)\n",
-	      __FUNCTION__, seq);
-
-} /* end rxrpc_call_record_ACK() */
-
-/*****************************************************************************/
-/*
- * transfer data from the ready packet queue to the asynchronous read buffer
- * - since this func is the only one going to look at packets queued on
- *   app_readyq, we don't need a lock to modify or access them, only to modify
- *   the queue pointers
- * - called with call->lock held
- * - the buffer must be in kernel space
- * - returns:
- *	0 if buffer filled
- *	-EAGAIN if buffer not filled and more data to come
- *	-EBADMSG if last packet received and insufficient data left
- *	-ECONNABORTED if the call has in an error state
- */
-static int __rxrpc_call_read_data(struct rxrpc_call *call)
-{
-	struct rxrpc_message *msg;
-	size_t qty;
-	int ret;
-
-	_enter("%p{as=%d buf=%p qty=%Zu/%Zu}",
-	       call,
-	       call->app_async_read, call->app_read_buf,
-	       call->app_ready_qty, call->app_mark);
-
-	/* check the state */
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_SRVR_RCV_ARGS:
-	case RXRPC_CSTATE_CLNT_RCV_REPLY:
-		if (call->app_last_rcv) {
-			printk("%s(%p,%p,%Zd):"
-			       " Inconsistent call state (%s, last pkt)",
-			       __FUNCTION__,
-			       call, call->app_read_buf, call->app_mark,
-			       rxrpc_call_states[call->app_call_state]);
-			BUG();
-		}
-		break;
-
-	case RXRPC_CSTATE_SRVR_RCV_OPID:
-	case RXRPC_CSTATE_SRVR_GOT_ARGS:
-	case RXRPC_CSTATE_CLNT_GOT_REPLY:
-		break;
-
-	case RXRPC_CSTATE_SRVR_SND_REPLY:
-		if (!call->app_last_rcv) {
-			printk("%s(%p,%p,%Zd):"
-			       " Inconsistent call state (%s, not last pkt)",
-			       __FUNCTION__,
-			       call, call->app_read_buf, call->app_mark,
-			       rxrpc_call_states[call->app_call_state]);
-			BUG();
-		}
-		_debug("Trying to read data from call in SND_REPLY state");
-		break;
-
-	case RXRPC_CSTATE_ERROR:
-		_leave(" = -ECONNABORTED");
-		return -ECONNABORTED;
-
-	default:
-		printk("reading in unexpected state [[[ %u ]]]\n",
-		       call->app_call_state);
-		BUG();
-	}
-
-	/* handle the case of not having an async buffer */
-	if (!call->app_async_read) {
-		if (call->app_mark == RXRPC_APP_MARK_EOF) {
-			ret = call->app_last_rcv ? 0 : -EAGAIN;
-		}
-		else {
-			if (call->app_mark >= call->app_ready_qty) {
-				call->app_mark = RXRPC_APP_MARK_EOF;
-				ret = 0;
-			}
-			else {
-				ret = call->app_last_rcv ? -EBADMSG : -EAGAIN;
-			}
-		}
-
-		_leave(" = %d [no buf]", ret);
-		return 0;
-	}
-
-	while (!list_empty(&call->app_readyq) && call->app_mark > 0) {
-		msg = list_entry(call->app_readyq.next,
-				 struct rxrpc_message, link);
-
-		/* drag as much data as we need out of this packet */
-		qty = min(call->app_mark, msg->dsize);
-
-		_debug("reading %Zu from skb=%p off=%lu",
-		       qty, msg->pkt, msg->offset);
-
-		if (call->app_read_buf)
-			if (skb_copy_bits(msg->pkt, msg->offset,
-					  call->app_read_buf, qty) < 0)
-				panic("%s: Failed to copy data from packet:"
-				      " (%p,%p,%Zd)",
-				      __FUNCTION__,
-				      call, call->app_read_buf, qty);
-
-		/* if that packet is now empty, discard it */
-		call->app_ready_qty -= qty;
-		msg->dsize -= qty;
-
-		if (msg->dsize == 0) {
-			list_del_init(&msg->link);
-			rxrpc_put_message(msg);
-		}
-		else {
-			msg->offset += qty;
-		}
-
-		call->app_mark -= qty;
-		if (call->app_read_buf)
-			call->app_read_buf += qty;
-	}
-
-	if (call->app_mark == 0) {
-		call->app_async_read = 0;
-		call->app_mark = RXRPC_APP_MARK_EOF;
-		call->app_read_buf = NULL;
-
-		/* adjust the state if used up all packets */
-		if (list_empty(&call->app_readyq) && call->app_last_rcv) {
-			switch (call->app_call_state) {
-			case RXRPC_CSTATE_SRVR_RCV_OPID:
-				call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY;
-				call->app_mark = RXRPC_APP_MARK_EOF;
-				_state(call);
-				del_timer_sync(&call->rcv_timeout);
-				break;
-			case RXRPC_CSTATE_SRVR_GOT_ARGS:
-				call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY;
-				_state(call);
-				del_timer_sync(&call->rcv_timeout);
-				break;
-			default:
-				call->app_call_state = RXRPC_CSTATE_COMPLETE;
-				_state(call);
-				del_timer_sync(&call->acks_timeout);
-				del_timer_sync(&call->ackr_dfr_timo);
-				del_timer_sync(&call->rcv_timeout);
-				break;
-			}
-		}
-
-		_leave(" = 0");
-		return 0;
-	}
-
-	if (call->app_last_rcv) {
-		_debug("Insufficient data (%Zu/%Zu)",
-		       call->app_ready_qty, call->app_mark);
-		call->app_async_read = 0;
-		call->app_mark = RXRPC_APP_MARK_EOF;
-		call->app_read_buf = NULL;
-
-		_leave(" = -EBADMSG");
-		return -EBADMSG;
-	}
-
-	_leave(" = -EAGAIN");
-	return -EAGAIN;
-} /* end __rxrpc_call_read_data() */
-
-/*****************************************************************************/
-/*
- * attempt to read the specified amount of data from the call's ready queue
- * into the buffer provided
- * - since this func is the only one going to look at packets queued on
- *   app_readyq, we don't need a lock to modify or access them, only to modify
- *   the queue pointers
- * - if the buffer pointer is NULL, then data is merely drained, not copied
- * - if flags&RXRPC_CALL_READ_BLOCK, then the function will wait until there is
- *   enough data or an error will be generated
- *   - note that the caller must have added the calling task to the call's wait
- *     queue beforehand
- * - if flags&RXRPC_CALL_READ_ALL, then an error will be generated if this
- *   function doesn't read all available data
- */
-int rxrpc_call_read_data(struct rxrpc_call *call,
-			 void *buffer, size_t size, int flags)
-{
-	int ret;
-
-	_enter("%p{arq=%Zu},%p,%Zd,%x",
-	       call, call->app_ready_qty, buffer, size, flags);
-
-	spin_lock(&call->lock);
-
-	if (unlikely(!!call->app_read_buf)) {
-		spin_unlock(&call->lock);
-		_leave(" = -EBUSY");
-		return -EBUSY;
-	}
-
-	call->app_mark = size;
-	call->app_read_buf = buffer;
-	call->app_async_read = 1;
-	call->app_read_count++;
-
-	/* read as much data as possible */
-	ret = __rxrpc_call_read_data(call);
-	switch (ret) {
-	case 0:
-		if (flags & RXRPC_CALL_READ_ALL &&
-		    (!call->app_last_rcv || call->app_ready_qty > 0)) {
-			_leave(" = -EBADMSG");
-			__rxrpc_call_abort(call, -EBADMSG);
-			return -EBADMSG;
-		}
-
-		spin_unlock(&call->lock);
-		call->app_attn_func(call);
-		_leave(" = 0");
-		return ret;
-
-	case -ECONNABORTED:
-		spin_unlock(&call->lock);
-		_leave(" = %d [aborted]", ret);
-		return ret;
-
-	default:
-		__rxrpc_call_abort(call, ret);
-		_leave(" = %d", ret);
-		return ret;
-
-	case -EAGAIN:
-		spin_unlock(&call->lock);
-
-		if (!(flags & RXRPC_CALL_READ_BLOCK)) {
-			_leave(" = -EAGAIN");
-			return -EAGAIN;
-		}
-
-		/* wait for the data to arrive */
-		_debug("blocking for data arrival");
-
-		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (!call->app_async_read || signal_pending(current))
-				break;
-			schedule();
-		}
-		set_current_state(TASK_RUNNING);
-
-		if (signal_pending(current)) {
-			_leave(" = -EINTR");
-			return -EINTR;
-		}
-
-		if (call->app_call_state == RXRPC_CSTATE_ERROR) {
-			_leave(" = -ECONNABORTED");
-			return -ECONNABORTED;
-		}
-
-		_leave(" = 0");
-		return 0;
-	}
-
-} /* end rxrpc_call_read_data() */
-
-/*****************************************************************************/
-/*
- * write data to a call
- * - the data may not be sent immediately if it doesn't fill a buffer
- * - if we can't queue all the data for buffering now, siov[] will have been
- *   adjusted to take account of what has been sent
- */
-int rxrpc_call_write_data(struct rxrpc_call *call,
-			  size_t sioc,
-			  struct kvec *siov,
-			  u8 rxhdr_flags,
-			  gfp_t alloc_flags,
-			  int dup_data,
-			  size_t *size_sent)
-{
-	struct rxrpc_message *msg;
-	struct kvec *sptr;
-	size_t space, size, chunk, tmp;
-	char *buf;
-	int ret;
-
-	_enter("%p,%Zu,%p,%02x,%x,%d,%p",
-	       call, sioc, siov, rxhdr_flags, alloc_flags, dup_data,
-	       size_sent);
-
-	*size_sent = 0;
-	size = 0;
-	ret = -EINVAL;
-
-	/* can't send more if we've sent last packet from this end */
-	switch (call->app_call_state) {
-	case RXRPC_CSTATE_SRVR_SND_REPLY:
-	case RXRPC_CSTATE_CLNT_SND_ARGS:
-		break;
-	case RXRPC_CSTATE_ERROR:
-		ret = call->app_errno;
-	default:
-		goto out;
-	}
-
-	/* calculate how much data we've been given */
-	sptr = siov;
-	for (; sioc > 0; sptr++, sioc--) {
-		if (!sptr->iov_len)
-			continue;
-
-		if (!sptr->iov_base)
-			goto out;
-
-		size += sptr->iov_len;
-	}
-
-	_debug("- size=%Zu mtu=%Zu", size, call->conn->mtu_size);
-
-	do {
-		/* make sure there's a message under construction */
-		if (!call->snd_nextmsg) {
-			/* no - allocate a message with no data yet attached */
-			ret = rxrpc_conn_newmsg(call->conn, call,
-						RXRPC_PACKET_TYPE_DATA,
-						0, NULL, alloc_flags,
-						&call->snd_nextmsg);
-			if (ret < 0)
-				goto out;
-			_debug("- allocated new message [ds=%Zu]",
-			       call->snd_nextmsg->dsize);
-		}
-
-		msg = call->snd_nextmsg;
-		msg->hdr.flags |= rxhdr_flags;
-
-		/* deal with zero-length terminal packet */
-		if (size == 0) {
-			if (rxhdr_flags & RXRPC_LAST_PACKET) {
-				ret = rxrpc_call_flush(call);
-				if (ret < 0)
-					goto out;
-			}
-			break;
-		}
-
-		/* work out how much space current packet has available */
-		space = call->conn->mtu_size - msg->dsize;
-		chunk = min(space, size);
-
-		_debug("- [before] space=%Zu chunk=%Zu", space, chunk);
-
-		while (!siov->iov_len)
-			siov++;
-
-		/* if we are going to have to duplicate the data then coalesce
-		 * it too */
-		if (dup_data) {
-			/* don't allocate more that 1 page at a time */
-			if (chunk > PAGE_SIZE)
-				chunk = PAGE_SIZE;
-
-			/* allocate a data buffer and attach to the message */
-			buf = kmalloc(chunk, alloc_flags);
-			if (unlikely(!buf)) {
-				if (msg->dsize ==
-				    sizeof(struct rxrpc_header)) {
-					/* discard an empty msg and wind back
-					 * the seq counter */
-					rxrpc_put_message(msg);
-					call->snd_nextmsg = NULL;
-					call->snd_seq_count--;
-				}
-
-				ret = -ENOMEM;
-				goto out;
-			}
-
-			tmp = msg->dcount++;
-			set_bit(tmp, &msg->dfree);
-			msg->data[tmp].iov_base = buf;
-			msg->data[tmp].iov_len = chunk;
-			msg->dsize += chunk;
-			*size_sent += chunk;
-			size -= chunk;
-
-			/* load the buffer with data */
-			while (chunk > 0) {
-				tmp = min(chunk, siov->iov_len);
-				memcpy(buf, siov->iov_base, tmp);
-				buf += tmp;
-				siov->iov_base += tmp;
-				siov->iov_len -= tmp;
-				if (!siov->iov_len)
-					siov++;
-				chunk -= tmp;
-			}
-		}
-		else {
-			/* we want to attach the supplied buffers directly */
-			while (chunk > 0 &&
-			       msg->dcount < RXRPC_MSG_MAX_IOCS) {
-				tmp = msg->dcount++;
-				msg->data[tmp].iov_base = siov->iov_base;
-				msg->data[tmp].iov_len = siov->iov_len;
-				msg->dsize += siov->iov_len;
-				*size_sent += siov->iov_len;
-				size -= siov->iov_len;
-				chunk -= siov->iov_len;
-				siov++;
-			}
-		}
-
-		_debug("- [loaded] chunk=%Zu size=%Zu", chunk, size);
-
-		/* dispatch the message when full, final or requesting ACK */
-		if (msg->dsize >= call->conn->mtu_size || rxhdr_flags) {
-			ret = rxrpc_call_flush(call);
-			if (ret < 0)
-				goto out;
-		}
-
-	} while(size > 0);
-
-	ret = 0;
- out:
-	_leave(" = %d (%Zd queued, %Zd rem)", ret, *size_sent, size);
-	return ret;
-
-} /* end rxrpc_call_write_data() */
-
-/*****************************************************************************/
-/*
- * flush outstanding packets to the network
- */
-static int rxrpc_call_flush(struct rxrpc_call *call)
-{
-	struct rxrpc_message *msg;
-	int ret = 0;
-
-	_enter("%p", call);
-
-	rxrpc_get_call(call);
-
-	/* if there's a packet under construction, then dispatch it now */
-	if (call->snd_nextmsg) {
-		msg = call->snd_nextmsg;
-		call->snd_nextmsg = NULL;
-
-		if (msg->hdr.flags & RXRPC_LAST_PACKET) {
-			msg->hdr.flags &= ~RXRPC_MORE_PACKETS;
-			if (call->app_call_state != RXRPC_CSTATE_CLNT_SND_ARGS)
-				msg->hdr.flags |= RXRPC_REQUEST_ACK;
-		}
-		else {
-			msg->hdr.flags |= RXRPC_MORE_PACKETS;
-		}
-
-		_proto("Sending DATA message { ds=%Zu dc=%u df=%02lu }",
-		       msg->dsize, msg->dcount, msg->dfree);
-
-		/* queue and adjust call state */
-		spin_lock(&call->lock);
-		list_add_tail(&msg->link, &call->acks_pendq);
-
-		/* decide what to do depending on current state and if this is
-		 * the last packet */
-		ret = -EINVAL;
-		switch (call->app_call_state) {
-		case RXRPC_CSTATE_SRVR_SND_REPLY:
-			if (msg->hdr.flags & RXRPC_LAST_PACKET) {
-				call->app_call_state =
-					RXRPC_CSTATE_SRVR_RCV_FINAL_ACK;
-				_state(call);
-			}
-			break;
-
-		case RXRPC_CSTATE_CLNT_SND_ARGS:
-			if (msg->hdr.flags & RXRPC_LAST_PACKET) {
-				call->app_call_state =
-					RXRPC_CSTATE_CLNT_RCV_REPLY;
-				_state(call);
-			}
-			break;
-
-		case RXRPC_CSTATE_ERROR:
-			ret = call->app_errno;
-		default:
-			spin_unlock(&call->lock);
-			goto out;
-		}
-
-		call->acks_pend_cnt++;
-
-		mod_timer(&call->acks_timeout,
-			  __rxrpc_rtt_based_timeout(call,
-						    rxrpc_call_acks_timeout));
-
-		spin_unlock(&call->lock);
-
-		ret = rxrpc_conn_sendmsg(call->conn, msg);
-		if (ret == 0)
-			call->pkt_snd_count++;
-	}
-
- out:
-	rxrpc_put_call(call);
-
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end rxrpc_call_flush() */
-
-/*****************************************************************************/
-/*
- * resend NAK'd or unacknowledged packets up to the highest one specified
- */
-static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest)
-{
-	struct rxrpc_message *msg;
-	struct list_head *_p;
-	rxrpc_seq_t seq = 0;
-
-	_enter("%p,%u", call, highest);
-
-	_proto("Rx Resend required");
-
-	/* handle too many resends */
-	if (call->snd_resend_cnt >= rxrpc_call_max_resend) {
-		_debug("Aborting due to too many resends (rcv=%d)",
-		       call->pkt_rcv_count);
-		rxrpc_call_abort(call,
-				 call->pkt_rcv_count > 0 ? -EIO : -ETIMEDOUT);
-		_leave("");
-		return;
-	}
-
-	spin_lock(&call->lock);
-	call->snd_resend_cnt++;
-	for (;;) {
-		/* determine which the next packet we might need to ACK is */
-		if (seq <= call->acks_dftv_seq)
-			seq = call->acks_dftv_seq;
-		seq++;
-
-		if (seq > highest)
-			break;
-
-		/* look for the packet in the pending-ACK queue */
-		list_for_each(_p, &call->acks_pendq) {
-			msg = list_entry(_p, struct rxrpc_message, link);
-			if (msg->seq == seq)
-				goto found_msg;
-		}
-
-		panic("%s(%p,%d):"
-		      " Inconsistent pending-ACK queue (ds=%u sc=%u sq=%u)\n",
-		      __FUNCTION__, call, highest,
-		      call->acks_dftv_seq, call->snd_seq_count, seq);
-
-	found_msg:
-		if (msg->state != RXRPC_MSG_SENT)
-			continue; /* only un-ACK'd packets */
-
-		rxrpc_get_message(msg);
-		spin_unlock(&call->lock);
-
-		/* send each message again (and ignore any errors we might
-		 * incur) */
-		_proto("Resending DATA message { ds=%Zu dc=%u df=%02lu }",
-		       msg->dsize, msg->dcount, msg->dfree);
-
-		if (rxrpc_conn_sendmsg(call->conn, msg) == 0)
-			call->pkt_snd_count++;
-
-		rxrpc_put_message(msg);
-
-		spin_lock(&call->lock);
-	}
-
-	/* reset the timeout */
-	mod_timer(&call->acks_timeout,
-		  __rxrpc_rtt_based_timeout(call, rxrpc_call_acks_timeout));
-
-	spin_unlock(&call->lock);
-
-	_leave("");
-} /* end rxrpc_call_resend() */
-
-/*****************************************************************************/
-/*
- * handle an ICMP error being applied to a call
- */
-void rxrpc_call_handle_error(struct rxrpc_call *call, int local, int errno)
-{
-	_enter("%p{%u},%d", call, ntohl(call->call_id), errno);
-
-	/* if this call is already aborted, then just wake up any waiters */
-	if (call->app_call_state == RXRPC_CSTATE_ERROR) {
-		call->app_error_func(call);
-	}
-	else {
-		/* tell the app layer what happened */
-		spin_lock(&call->lock);
-		call->app_call_state = RXRPC_CSTATE_ERROR;
-		_state(call);
-		if (local)
-			call->app_err_state = RXRPC_ESTATE_LOCAL_ERROR;
-		else
-			call->app_err_state = RXRPC_ESTATE_REMOTE_ERROR;
-		call->app_errno		= errno;
-		call->app_mark		= RXRPC_APP_MARK_EOF;
-		call->app_read_buf	= NULL;
-		call->app_async_read	= 0;
-
-		/* map the error */
-		call->app_aemap_func(call);
-
-		del_timer_sync(&call->acks_timeout);
-		del_timer_sync(&call->rcv_timeout);
-		del_timer_sync(&call->ackr_dfr_timo);
-
-		spin_unlock(&call->lock);
-
-		call->app_error_func(call);
-	}
-
-	_leave("");
-} /* end rxrpc_call_handle_error() */
diff --git a/net/rxrpc/connection.c b/net/rxrpc/connection.c
deleted file mode 100644
index a7c929a..0000000
--- a/net/rxrpc/connection.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/* connection.c: Rx connection routines
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include <linux/udp.h>
-#include <linux/ip.h>
-#include <net/sock.h>
-#include <asm/uaccess.h>
-#include "internal.h"
-
-__RXACCT_DECL(atomic_t rxrpc_connection_count);
-
-LIST_HEAD(rxrpc_conns);
-DECLARE_RWSEM(rxrpc_conns_sem);
-unsigned long rxrpc_conn_timeout = 60 * 60;
-
-static void rxrpc_conn_do_timeout(struct rxrpc_connection *conn);
-
-static void __rxrpc_conn_timeout(rxrpc_timer_t *timer)
-{
-	struct rxrpc_connection *conn =
-		list_entry(timer, struct rxrpc_connection, timeout);
-
-	_debug("Rx CONN TIMEOUT [%p{u=%d}]", conn, atomic_read(&conn->usage));
-
-	rxrpc_conn_do_timeout(conn);
-}
-
-static const struct rxrpc_timer_ops rxrpc_conn_timer_ops = {
-	.timed_out	= __rxrpc_conn_timeout,
-};
-
-/*****************************************************************************/
-/*
- * create a new connection record
- */
-static inline int __rxrpc_create_connection(struct rxrpc_peer *peer,
-					    struct rxrpc_connection **_conn)
-{
-	struct rxrpc_connection *conn;
-
-	_enter("%p",peer);
-
-	/* allocate and initialise a connection record */
-	conn = kzalloc(sizeof(struct rxrpc_connection), GFP_KERNEL);
-	if (!conn) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	atomic_set(&conn->usage, 1);
-
-	INIT_LIST_HEAD(&conn->link);
-	INIT_LIST_HEAD(&conn->id_link);
-	init_waitqueue_head(&conn->chanwait);
-	spin_lock_init(&conn->lock);
-	rxrpc_timer_init(&conn->timeout, &rxrpc_conn_timer_ops);
-
-	do_gettimeofday(&conn->atime);
-	conn->mtu_size = 1024;
-	conn->peer = peer;
-	conn->trans = peer->trans;
-
-	__RXACCT(atomic_inc(&rxrpc_connection_count));
-	*_conn = conn;
-	_leave(" = 0 (%p)", conn);
-
-	return 0;
-} /* end __rxrpc_create_connection() */
-
-/*****************************************************************************/
-/*
- * create a new connection record for outgoing connections
- */
-int rxrpc_create_connection(struct rxrpc_transport *trans,
-			    __be16 port,
-			    __be32 addr,
-			    uint16_t service_id,
-			    void *security,
-			    struct rxrpc_connection **_conn)
-{
-	struct rxrpc_connection *candidate, *conn;
-	struct rxrpc_peer *peer;
-	struct list_head *_p;
-	__be32 connid;
-	int ret;
-
-	_enter("%p{%hu},%u,%hu", trans, trans->port, ntohs(port), service_id);
-
-	/* get a peer record */
-	ret = rxrpc_peer_lookup(trans, addr, &peer);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* allocate and initialise a connection record */
-	ret = __rxrpc_create_connection(peer, &candidate);
-	if (ret < 0) {
-		rxrpc_put_peer(peer);
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* fill in the specific bits */
-	candidate->addr.sin_family	= AF_INET;
-	candidate->addr.sin_port	= port;
-	candidate->addr.sin_addr.s_addr	= addr;
-
-	candidate->in_epoch		= rxrpc_epoch;
-	candidate->out_epoch		= rxrpc_epoch;
-	candidate->in_clientflag	= 0;
-	candidate->out_clientflag	= RXRPC_CLIENT_INITIATED;
-	candidate->service_id		= htons(service_id);
-
-	/* invent a unique connection ID */
-	write_lock(&peer->conn_idlock);
-
- try_next_id:
-	connid = htonl(peer->conn_idcounter & RXRPC_CIDMASK);
-	peer->conn_idcounter += RXRPC_MAXCALLS;
-
-	list_for_each(_p, &peer->conn_idlist) {
-		conn = list_entry(_p, struct rxrpc_connection, id_link);
-		if (connid == conn->conn_id)
-			goto try_next_id;
-		if (connid > conn->conn_id)
-			break;
-	}
-
-	_debug("selected candidate conn ID %x.%u",
-	       ntohl(peer->addr.s_addr), ntohl(connid));
-
-	candidate->conn_id = connid;
-	list_add_tail(&candidate->id_link, _p);
-
-	write_unlock(&peer->conn_idlock);
-
-	/* attach to peer */
-	candidate->peer = peer;
-
-	write_lock(&peer->conn_lock);
-
-	/* search the peer's transport graveyard list */
-	spin_lock(&peer->conn_gylock);
-	list_for_each(_p, &peer->conn_graveyard) {
-		conn = list_entry(_p, struct rxrpc_connection, link);
-		if (conn->addr.sin_port	== candidate->addr.sin_port	&&
-		    conn->security_ix	== candidate->security_ix	&&
-		    conn->service_id	== candidate->service_id	&&
-		    conn->in_clientflag	== 0)
-			goto found_in_graveyard;
-	}
-	spin_unlock(&peer->conn_gylock);
-
-	/* pick the new candidate */
-	_debug("created connection: {%08x} [out]", ntohl(candidate->conn_id));
-	atomic_inc(&peer->conn_count);
-	conn = candidate;
-	candidate = NULL;
-
- make_active:
-	list_add_tail(&conn->link, &peer->conn_active);
-	write_unlock(&peer->conn_lock);
-
-	if (candidate) {
-		write_lock(&peer->conn_idlock);
-		list_del(&candidate->id_link);
-		write_unlock(&peer->conn_idlock);
-
-		__RXACCT(atomic_dec(&rxrpc_connection_count));
-		kfree(candidate);
-	}
-	else {
-		down_write(&rxrpc_conns_sem);
-		list_add_tail(&conn->proc_link, &rxrpc_conns);
-		up_write(&rxrpc_conns_sem);
-	}
-
-	*_conn = conn;
-	_leave(" = 0 (%p)", conn);
-
-	return 0;
-
-	/* handle resurrecting a connection from the graveyard */
- found_in_graveyard:
-	_debug("resurrecting connection: {%08x} [out]", ntohl(conn->conn_id));
-	rxrpc_get_connection(conn);
-	rxrpc_krxtimod_del_timer(&conn->timeout);
-	list_del_init(&conn->link);
-	spin_unlock(&peer->conn_gylock);
-	goto make_active;
-} /* end rxrpc_create_connection() */
-
-/*****************************************************************************/
-/*
- * lookup the connection for an incoming packet
- * - create a new connection record for unrecorded incoming connections
- */
-int rxrpc_connection_lookup(struct rxrpc_peer *peer,
-			    struct rxrpc_message *msg,
-			    struct rxrpc_connection **_conn)
-{
-	struct rxrpc_connection *conn, *candidate = NULL;
-	struct list_head *_p;
-	struct sk_buff *pkt = msg->pkt;
-	int ret, fresh = 0;
-	__be32 x_epoch, x_connid;
-	__be16 x_port, x_servid;
-	__u32 x_secix;
-	u8 x_clflag;
-
-	_enter("%p{{%hu}},%u,%hu",
-	       peer,
-	       peer->trans->port,
-	       ntohs(pkt->h.uh->source),
-	       ntohs(msg->hdr.serviceId));
-
-	x_port		= pkt->h.uh->source;
-	x_epoch		= msg->hdr.epoch;
-	x_clflag	= msg->hdr.flags & RXRPC_CLIENT_INITIATED;
-	x_connid	= htonl(ntohl(msg->hdr.cid) & RXRPC_CIDMASK);
-	x_servid	= msg->hdr.serviceId;
-	x_secix		= msg->hdr.securityIndex;
-
-	/* [common case] search the transport's active list first */
-	read_lock(&peer->conn_lock);
-	list_for_each(_p, &peer->conn_active) {
-		conn = list_entry(_p, struct rxrpc_connection, link);
-		if (conn->addr.sin_port		== x_port	&&
-		    conn->in_epoch		== x_epoch	&&
-		    conn->conn_id		== x_connid	&&
-		    conn->security_ix		== x_secix	&&
-		    conn->service_id		== x_servid	&&
-		    conn->in_clientflag		== x_clflag)
-			goto found_active;
-	}
-	read_unlock(&peer->conn_lock);
-
-	/* [uncommon case] not active
-	 * - create a candidate for a new record if an inbound connection
-	 * - only examine the graveyard for an outbound connection
-	 */
-	if (x_clflag) {
-		ret = __rxrpc_create_connection(peer, &candidate);
-		if (ret < 0) {
-			_leave(" = %d", ret);
-			return ret;
-		}
-
-		/* fill in the specifics */
-		candidate->addr.sin_family	= AF_INET;
-		candidate->addr.sin_port	= x_port;
-		candidate->addr.sin_addr.s_addr = pkt->nh.iph->saddr;
-		candidate->in_epoch		= x_epoch;
-		candidate->out_epoch		= x_epoch;
-		candidate->in_clientflag	= RXRPC_CLIENT_INITIATED;
-		candidate->out_clientflag	= 0;
-		candidate->conn_id		= x_connid;
-		candidate->service_id		= x_servid;
-		candidate->security_ix		= x_secix;
-	}
-
-	/* search the active list again, just in case it appeared whilst we
-	 * were busy */
-	write_lock(&peer->conn_lock);
-	list_for_each(_p, &peer->conn_active) {
-		conn = list_entry(_p, struct rxrpc_connection, link);
-		if (conn->addr.sin_port		== x_port	&&
-		    conn->in_epoch		== x_epoch	&&
-		    conn->conn_id		== x_connid	&&
-		    conn->security_ix		== x_secix	&&
-		    conn->service_id		== x_servid	&&
-		    conn->in_clientflag		== x_clflag)
-			goto found_active_second_chance;
-	}
-
-	/* search the transport's graveyard list */
-	spin_lock(&peer->conn_gylock);
-	list_for_each(_p, &peer->conn_graveyard) {
-		conn = list_entry(_p, struct rxrpc_connection, link);
-		if (conn->addr.sin_port		== x_port	&&
-		    conn->in_epoch		== x_epoch	&&
-		    conn->conn_id		== x_connid	&&
-		    conn->security_ix		== x_secix	&&
-		    conn->service_id		== x_servid	&&
-		    conn->in_clientflag		== x_clflag)
-			goto found_in_graveyard;
-	}
-	spin_unlock(&peer->conn_gylock);
-
-	/* outbound connections aren't created here */
-	if (!x_clflag) {
-		write_unlock(&peer->conn_lock);
-		_leave(" = -ENOENT");
-		return -ENOENT;
-	}
-
-	/* we can now add the new candidate to the list */
-	_debug("created connection: {%08x} [in]", ntohl(candidate->conn_id));
-	rxrpc_get_peer(peer);
-	conn = candidate;
-	candidate = NULL;
-	atomic_inc(&peer->conn_count);
-	fresh = 1;
-
- make_active:
-	list_add_tail(&conn->link, &peer->conn_active);
-
- success_uwfree:
-	write_unlock(&peer->conn_lock);
-
-	if (candidate) {
-		write_lock(&peer->conn_idlock);
-		list_del(&candidate->id_link);
-		write_unlock(&peer->conn_idlock);
-
-		__RXACCT(atomic_dec(&rxrpc_connection_count));
-		kfree(candidate);
-	}
-
-	if (fresh) {
-		down_write(&rxrpc_conns_sem);
-		list_add_tail(&conn->proc_link, &rxrpc_conns);
-		up_write(&rxrpc_conns_sem);
-	}
-
- success:
-	*_conn = conn;
-	_leave(" = 0 (%p)", conn);
-	return 0;
-
-	/* handle the connection being found in the active list straight off */
- found_active:
-	rxrpc_get_connection(conn);
-	read_unlock(&peer->conn_lock);
-	goto success;
-
-	/* handle resurrecting a connection from the graveyard */
- found_in_graveyard:
-	_debug("resurrecting connection: {%08x} [in]", ntohl(conn->conn_id));
-	rxrpc_get_peer(peer);
-	rxrpc_get_connection(conn);
-	rxrpc_krxtimod_del_timer(&conn->timeout);
-	list_del_init(&conn->link);
-	spin_unlock(&peer->conn_gylock);
-	goto make_active;
-
-	/* handle finding the connection on the second time through the active
-	 * list */
- found_active_second_chance:
-	rxrpc_get_connection(conn);
-	goto success_uwfree;
-
-} /* end rxrpc_connection_lookup() */
-
-/*****************************************************************************/
-/*
- * finish using a connection record
- * - it will be transferred to the peer's connection graveyard when refcount
- *   reaches 0
- */
-void rxrpc_put_connection(struct rxrpc_connection *conn)
-{
-	struct rxrpc_peer *peer;
-
-	if (!conn)
-		return;
-
-	_enter("%p{u=%d p=%hu}",
-	       conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port));
-
-	peer = conn->peer;
-	spin_lock(&peer->conn_gylock);
-
-	/* sanity check */
-	if (atomic_read(&conn->usage) <= 0)
-		BUG();
-
-	if (likely(!atomic_dec_and_test(&conn->usage))) {
-		spin_unlock(&peer->conn_gylock);
-		_leave("");
-		return;
-	}
-
-	/* move to graveyard queue */
-	_debug("burying connection: {%08x}", ntohl(conn->conn_id));
-	list_move_tail(&conn->link, &peer->conn_graveyard);
-
-	rxrpc_krxtimod_add_timer(&conn->timeout, rxrpc_conn_timeout * HZ);
-
-	spin_unlock(&peer->conn_gylock);
-
-	rxrpc_put_peer(conn->peer);
-
-	_leave(" [killed]");
-} /* end rxrpc_put_connection() */
-
-/*****************************************************************************/
-/*
- * free a connection record
- */
-static void rxrpc_conn_do_timeout(struct rxrpc_connection *conn)
-{
-	struct rxrpc_peer *peer;
-
-	_enter("%p{u=%d p=%hu}",
-	       conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port));
-
-	peer = conn->peer;
-
-	if (atomic_read(&conn->usage) < 0)
-		BUG();
-
-	/* remove from graveyard if still dead */
-	spin_lock(&peer->conn_gylock);
-	if (atomic_read(&conn->usage) == 0) {
-		list_del_init(&conn->link);
-	}
-	else {
-		conn = NULL;
-	}
-	spin_unlock(&peer->conn_gylock);
-
-	if (!conn) {
-		_leave("");
-		return; /* resurrected */
-	}
-
-	_debug("--- Destroying Connection %p{%08x} ---",
-	       conn, ntohl(conn->conn_id));
-
-	down_write(&rxrpc_conns_sem);
-	list_del(&conn->proc_link);
-	up_write(&rxrpc_conns_sem);
-
-	write_lock(&peer->conn_idlock);
-	list_del(&conn->id_link);
-	write_unlock(&peer->conn_idlock);
-
-	__RXACCT(atomic_dec(&rxrpc_connection_count));
-	kfree(conn);
-
-	/* if the graveyard is now empty, wake up anyone waiting for that */
-	if (atomic_dec_and_test(&peer->conn_count))
-		wake_up(&peer->conn_gy_waitq);
-
-	_leave(" [destroyed]");
-} /* end rxrpc_conn_do_timeout() */
-
-/*****************************************************************************/
-/*
- * clear all connection records from a peer endpoint
- */
-void rxrpc_conn_clearall(struct rxrpc_peer *peer)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	struct rxrpc_connection *conn;
-	int err;
-
-	_enter("%p", peer);
-
-	/* there shouldn't be any active conns remaining */
-	if (!list_empty(&peer->conn_active))
-		BUG();
-
-	/* manually timeout all conns in the graveyard */
-	spin_lock(&peer->conn_gylock);
-	while (!list_empty(&peer->conn_graveyard)) {
-		conn = list_entry(peer->conn_graveyard.next,
-				  struct rxrpc_connection, link);
-		err = rxrpc_krxtimod_del_timer(&conn->timeout);
-		spin_unlock(&peer->conn_gylock);
-
-		if (err == 0)
-			rxrpc_conn_do_timeout(conn);
-
-		spin_lock(&peer->conn_gylock);
-	}
-	spin_unlock(&peer->conn_gylock);
-
-	/* wait for the the conn graveyard to be completely cleared */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&peer->conn_gy_waitq, &myself);
-
-	while (atomic_read(&peer->conn_count) != 0) {
-		schedule();
-		set_current_state(TASK_UNINTERRUPTIBLE);
-	}
-
-	remove_wait_queue(&peer->conn_gy_waitq, &myself);
-	set_current_state(TASK_RUNNING);
-
-	_leave("");
-} /* end rxrpc_conn_clearall() */
-
-/*****************************************************************************/
-/*
- * allocate and prepare a message for sending out through the transport
- * endpoint
- */
-int rxrpc_conn_newmsg(struct rxrpc_connection *conn,
-		      struct rxrpc_call *call,
-		      uint8_t type,
-		      int dcount,
-		      struct kvec diov[],
-		      gfp_t alloc_flags,
-		      struct rxrpc_message **_msg)
-{
-	struct rxrpc_message *msg;
-	int loop;
-
-	_enter("%p{%d},%p,%u", conn, ntohs(conn->addr.sin_port), call, type);
-
-	if (dcount > 3) {
-		_leave(" = -EINVAL");
-		return -EINVAL;
-	}
-
-	msg = kzalloc(sizeof(struct rxrpc_message), alloc_flags);
-	if (!msg) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	atomic_set(&msg->usage, 1);
-
-	INIT_LIST_HEAD(&msg->link);
-
-	msg->state = RXRPC_MSG_PREPARED;
-
-	msg->hdr.epoch		= conn->out_epoch;
-	msg->hdr.cid		= conn->conn_id | (call ? call->chan_ix : 0);
-	msg->hdr.callNumber	= call ? call->call_id : 0;
-	msg->hdr.type		= type;
-	msg->hdr.flags		= conn->out_clientflag;
-	msg->hdr.securityIndex	= conn->security_ix;
-	msg->hdr.serviceId	= conn->service_id;
-
-	/* generate sequence numbers for data packets */
-	if (call) {
-		switch (type) {
-		case RXRPC_PACKET_TYPE_DATA:
-			msg->seq = ++call->snd_seq_count;
-			msg->hdr.seq = htonl(msg->seq);
-			break;
-		case RXRPC_PACKET_TYPE_ACK:
-			/* ACK sequence numbers are complicated. The following
-			 * may be wrong:
-			 * - jumbo packet ACKs should have a seq number
-			 * - normal ACKs should not
-			 */
-		default:
-			break;
-		}
-	}
-
-	msg->dcount = dcount + 1;
-	msg->dsize = sizeof(msg->hdr);
-	msg->data[0].iov_len = sizeof(msg->hdr);
-	msg->data[0].iov_base = &msg->hdr;
-
-	for (loop=0; loop < dcount; loop++) {
-		msg->dsize += diov[loop].iov_len;
-		msg->data[loop+1].iov_len  = diov[loop].iov_len;
-		msg->data[loop+1].iov_base = diov[loop].iov_base;
-	}
-
-	__RXACCT(atomic_inc(&rxrpc_message_count));
-	*_msg = msg;
-	_leave(" = 0 (%p) #%d", msg, atomic_read(&rxrpc_message_count));
-	return 0;
-} /* end rxrpc_conn_newmsg() */
-
-/*****************************************************************************/
-/*
- * free a message
- */
-void __rxrpc_put_message(struct rxrpc_message *msg)
-{
-	int loop;
-
-	_enter("%p #%d", msg, atomic_read(&rxrpc_message_count));
-
-	if (msg->pkt)
-		kfree_skb(msg->pkt);
-	rxrpc_put_connection(msg->conn);
-
-	for (loop = 0; loop < 8; loop++)
-		if (test_bit(loop, &msg->dfree))
-			kfree(msg->data[loop].iov_base);
-
-	__RXACCT(atomic_dec(&rxrpc_message_count));
-	kfree(msg);
-
-	_leave("");
-} /* end __rxrpc_put_message() */
-
-/*****************************************************************************/
-/*
- * send a message out through the transport endpoint
- */
-int rxrpc_conn_sendmsg(struct rxrpc_connection *conn,
-		       struct rxrpc_message *msg)
-{
-	struct msghdr msghdr;
-	int ret;
-
-	_enter("%p{%d}", conn, ntohs(conn->addr.sin_port));
-
-	/* fill in some fields in the header */
-	spin_lock(&conn->lock);
-	msg->hdr.serial = htonl(++conn->serial_counter);
-	msg->rttdone = 0;
-	spin_unlock(&conn->lock);
-
-	/* set up the message to be transmitted */
-	msghdr.msg_name		= &conn->addr;
-	msghdr.msg_namelen	= sizeof(conn->addr);
-	msghdr.msg_control	= NULL;
-	msghdr.msg_controllen	= 0;
-	msghdr.msg_flags	= MSG_CONFIRM | MSG_DONTWAIT;
-
-	_net("Sending message type %d of %Zd bytes to %08x:%d",
-	     msg->hdr.type,
-	     msg->dsize,
-	     ntohl(conn->addr.sin_addr.s_addr),
-	     ntohs(conn->addr.sin_port));
-
-	/* send the message */
-	ret = kernel_sendmsg(conn->trans->socket, &msghdr,
-			     msg->data, msg->dcount, msg->dsize);
-	if (ret < 0) {
-		msg->state = RXRPC_MSG_ERROR;
-	} else {
-		msg->state = RXRPC_MSG_SENT;
-		ret = 0;
-
-		spin_lock(&conn->lock);
-		do_gettimeofday(&conn->atime);
-		msg->stamp = conn->atime;
-		spin_unlock(&conn->lock);
-	}
-
-	_leave(" = %d", ret);
-
-	return ret;
-} /* end rxrpc_conn_sendmsg() */
-
-/*****************************************************************************/
-/*
- * deal with a subsequent call packet
- */
-int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn,
-				   struct rxrpc_call *call,
-				   struct rxrpc_message *msg)
-{
-	struct rxrpc_message *pmsg;
-	struct dst_entry *dst;
-	struct list_head *_p;
-	unsigned cix, seq;
-	int ret = 0;
-
-	_enter("%p,%p,%p", conn, call, msg);
-
-	if (!call) {
-		cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK;
-
-		spin_lock(&conn->lock);
-		call = conn->channels[cix];
-
-		if (!call || call->call_id != msg->hdr.callNumber) {
-			spin_unlock(&conn->lock);
-			rxrpc_trans_immediate_abort(conn->trans, msg, -ENOENT);
-			goto out;
-		}
-		else {
-			rxrpc_get_call(call);
-			spin_unlock(&conn->lock);
-		}
-	}
-	else {
-		rxrpc_get_call(call);
-	}
-
-	_proto("Received packet %%%u [%u] on call %hu:%u:%u",
-	       ntohl(msg->hdr.serial),
-	       ntohl(msg->hdr.seq),
-	       ntohs(msg->hdr.serviceId),
-	       ntohl(conn->conn_id),
-	       ntohl(call->call_id));
-
-	call->pkt_rcv_count++;
-
-	dst = msg->pkt->dst;
-	if (dst && dst->dev)
-		conn->peer->if_mtu =
-			dst->dev->mtu - dst->dev->hard_header_len;
-
-	/* queue on the call in seq order */
-	rxrpc_get_message(msg);
-	seq = msg->seq;
-
-	spin_lock(&call->lock);
-	list_for_each(_p, &call->rcv_receiveq) {
-		pmsg = list_entry(_p, struct rxrpc_message, link);
-		if (pmsg->seq > seq)
-			break;
-	}
-	list_add_tail(&msg->link, _p);
-
-	/* reset the activity timeout */
-	call->flags |= RXRPC_CALL_RCV_PKT;
-	mod_timer(&call->rcv_timeout,jiffies + rxrpc_call_rcv_timeout * HZ);
-
-	spin_unlock(&call->lock);
-
-	rxrpc_krxiod_queue_call(call);
-
-	rxrpc_put_call(call);
- out:
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_conn_receive_call_packet() */
-
-/*****************************************************************************/
-/*
- * handle an ICMP error being applied to a connection
- */
-void rxrpc_conn_handle_error(struct rxrpc_connection *conn,
-			     int local, int errno)
-{
-	struct rxrpc_call *calls[4];
-	int loop;
-
-	_enter("%p{%d},%d", conn, ntohs(conn->addr.sin_port), errno);
-
-	/* get a ref to all my calls in one go */
-	memset(calls, 0, sizeof(calls));
-	spin_lock(&conn->lock);
-
-	for (loop = 3; loop >= 0; loop--) {
-		if (conn->channels[loop]) {
-			calls[loop] = conn->channels[loop];
-			rxrpc_get_call(calls[loop]);
-		}
-	}
-
-	spin_unlock(&conn->lock);
-
-	/* now kick them all */
-	for (loop = 3; loop >= 0; loop--) {
-		if (calls[loop]) {
-			rxrpc_call_handle_error(calls[loop], local, errno);
-			rxrpc_put_call(calls[loop]);
-		}
-	}
-
-	_leave("");
-} /* end rxrpc_conn_handle_error() */
diff --git a/net/rxrpc/internal.h b/net/rxrpc/internal.h
deleted file mode 100644
index cc0c579..0000000
--- a/net/rxrpc/internal.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* internal.h: internal Rx RPC stuff
- *
- * Copyright (c) 2002   David Howells (dhowells@redhat.com).
- */
-
-#ifndef RXRPC_INTERNAL_H
-#define RXRPC_INTERNAL_H
-
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-
-/*
- * debug accounting
- */
-#if 1
-#define __RXACCT_DECL(X) X
-#define __RXACCT(X) do { X; } while(0)
-#else
-#define __RXACCT_DECL(X)
-#define __RXACCT(X) do { } while(0)
-#endif
-
-__RXACCT_DECL(extern atomic_t rxrpc_transport_count);
-__RXACCT_DECL(extern atomic_t rxrpc_peer_count);
-__RXACCT_DECL(extern atomic_t rxrpc_connection_count);
-__RXACCT_DECL(extern atomic_t rxrpc_call_count);
-__RXACCT_DECL(extern atomic_t rxrpc_message_count);
-
-/*
- * debug tracing
- */
-#define kenter(FMT, a...)	printk("==> %s("FMT")\n",__FUNCTION__ , ##a)
-#define kleave(FMT, a...)	printk("<== %s()"FMT"\n",__FUNCTION__ , ##a)
-#define kdebug(FMT, a...)	printk("    "FMT"\n" , ##a)
-#define kproto(FMT, a...)	printk("### "FMT"\n" , ##a)
-#define knet(FMT, a...)		printk("    "FMT"\n" , ##a)
-
-#if 0
-#define _enter(FMT, a...)	kenter(FMT , ##a)
-#define _leave(FMT, a...)	kleave(FMT , ##a)
-#define _debug(FMT, a...)	kdebug(FMT , ##a)
-#define _proto(FMT, a...)	kproto(FMT , ##a)
-#define _net(FMT, a...)		knet(FMT , ##a)
-#else
-#define _enter(FMT, a...)	do { if (rxrpc_ktrace) kenter(FMT , ##a); } while(0)
-#define _leave(FMT, a...)	do { if (rxrpc_ktrace) kleave(FMT , ##a); } while(0)
-#define _debug(FMT, a...)	do { if (rxrpc_kdebug) kdebug(FMT , ##a); } while(0)
-#define _proto(FMT, a...)	do { if (rxrpc_kproto) kproto(FMT , ##a); } while(0)
-#define _net(FMT, a...)		do { if (rxrpc_knet)   knet  (FMT , ##a); } while(0)
-#endif
-
-static inline void rxrpc_discard_my_signals(void)
-{
-	while (signal_pending(current)) {
-		siginfo_t sinfo;
-
-		spin_lock_irq(&current->sighand->siglock);
-		dequeue_signal(current, &current->blocked, &sinfo);
-		spin_unlock_irq(&current->sighand->siglock);
-	}
-}
-
-/*
- * call.c
- */
-extern struct list_head rxrpc_calls;
-extern struct rw_semaphore rxrpc_calls_sem;
-
-/*
- * connection.c
- */
-extern struct list_head rxrpc_conns;
-extern struct rw_semaphore rxrpc_conns_sem;
-extern unsigned long rxrpc_conn_timeout;
-
-extern void rxrpc_conn_clearall(struct rxrpc_peer *peer);
-
-/*
- * peer.c
- */
-extern struct list_head rxrpc_peers;
-extern struct rw_semaphore rxrpc_peers_sem;
-extern unsigned long rxrpc_peer_timeout;
-
-extern void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer,
-				     struct rxrpc_message *msg,
-				     struct rxrpc_message *resp);
-
-extern void rxrpc_peer_clearall(struct rxrpc_transport *trans);
-
-
-/*
- * proc.c
- */
-#ifdef CONFIG_PROC_FS
-extern int rxrpc_proc_init(void);
-extern void rxrpc_proc_cleanup(void);
-#endif
-
-/*
- * transport.c
- */
-extern struct list_head rxrpc_proc_transports;
-extern struct rw_semaphore rxrpc_proc_transports_sem;
-
-#endif /* RXRPC_INTERNAL_H */
diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c
deleted file mode 100644
index bbbcd6c..0000000
--- a/net/rxrpc/krxiod.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/* krxiod.c: Rx I/O daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/freezer.h>
-#include <rxrpc/krxiod.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/call.h>
-#include "internal.h"
-
-static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq);
-static DECLARE_COMPLETION(rxrpc_krxiod_dead);
-
-static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0);
-
-static LIST_HEAD(rxrpc_krxiod_transportq);
-static DEFINE_SPINLOCK(rxrpc_krxiod_transportq_lock);
-
-static LIST_HEAD(rxrpc_krxiod_callq);
-static DEFINE_SPINLOCK(rxrpc_krxiod_callq_lock);
-
-static volatile int rxrpc_krxiod_die;
-
-/*****************************************************************************/
-/*
- * Rx I/O daemon
- */
-static int rxrpc_krxiod(void *arg)
-{
-	DECLARE_WAITQUEUE(krxiod,current);
-
-	printk("Started krxiod %d\n",current->pid);
-
-	daemonize("krxiod");
-
-	/* loop around waiting for work to do */
-	do {
-		/* wait for work or to be told to exit */
-		_debug("### Begin Wait");
-		if (!atomic_read(&rxrpc_krxiod_qcount)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
-
-			for (;;) {
-				set_current_state(TASK_INTERRUPTIBLE);
-				if (atomic_read(&rxrpc_krxiod_qcount) ||
-				    rxrpc_krxiod_die ||
-				    signal_pending(current))
-					break;
-
-				schedule();
-			}
-
-			remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod);
-			set_current_state(TASK_RUNNING);
-		}
-		_debug("### End Wait");
-
-		/* do work if been given some to do */
-		_debug("### Begin Work");
-
-		/* see if there's a transport in need of attention */
-		if (!list_empty(&rxrpc_krxiod_transportq)) {
-			struct rxrpc_transport *trans = NULL;
-
-			spin_lock_irq(&rxrpc_krxiod_transportq_lock);
-
-			if (!list_empty(&rxrpc_krxiod_transportq)) {
-				trans = list_entry(
-					rxrpc_krxiod_transportq.next,
-					struct rxrpc_transport,
-					krxiodq_link);
-
-				list_del_init(&trans->krxiodq_link);
-				atomic_dec(&rxrpc_krxiod_qcount);
-
-				/* make sure it hasn't gone away and doesn't go
-				 * away */
-				if (atomic_read(&trans->usage)>0)
-					rxrpc_get_transport(trans);
-				else
-					trans = NULL;
-			}
-
-			spin_unlock_irq(&rxrpc_krxiod_transportq_lock);
-
-			if (trans) {
-				rxrpc_trans_receive_packet(trans);
-				rxrpc_put_transport(trans);
-			}
-		}
-
-		/* see if there's a call in need of attention */
-		if (!list_empty(&rxrpc_krxiod_callq)) {
-			struct rxrpc_call *call = NULL;
-
-			spin_lock_irq(&rxrpc_krxiod_callq_lock);
-
-			if (!list_empty(&rxrpc_krxiod_callq)) {
-				call = list_entry(rxrpc_krxiod_callq.next,
-						  struct rxrpc_call,
-						  rcv_krxiodq_lk);
-				list_del_init(&call->rcv_krxiodq_lk);
-				atomic_dec(&rxrpc_krxiod_qcount);
-
-				/* make sure it hasn't gone away and doesn't go
-				 * away */
-				if (atomic_read(&call->usage) > 0) {
-					_debug("@@@ KRXIOD"
-					       " Begin Attend Call %p", call);
-					rxrpc_get_call(call);
-				}
-				else {
-					call = NULL;
-				}
-			}
-
-			spin_unlock_irq(&rxrpc_krxiod_callq_lock);
-
-			if (call) {
-				rxrpc_call_do_stuff(call);
-				rxrpc_put_call(call);
-				_debug("@@@ KRXIOD End Attend Call %p", call);
-			}
-		}
-
-		_debug("### End Work");
-
-		try_to_freeze();
-
-		/* discard pending signals */
-		rxrpc_discard_my_signals();
-
-	} while (!rxrpc_krxiod_die);
-
-	/* and that's all */
-	complete_and_exit(&rxrpc_krxiod_dead, 0);
-
-} /* end rxrpc_krxiod() */
-
-/*****************************************************************************/
-/*
- * start up a krxiod daemon
- */
-int __init rxrpc_krxiod_init(void)
-{
-	return kernel_thread(rxrpc_krxiod, NULL, 0);
-
-} /* end rxrpc_krxiod_init() */
-
-/*****************************************************************************/
-/*
- * kill the krxiod daemon and wait for it to complete
- */
-void rxrpc_krxiod_kill(void)
-{
-	rxrpc_krxiod_die = 1;
-	wake_up_all(&rxrpc_krxiod_sleepq);
-	wait_for_completion(&rxrpc_krxiod_dead);
-
-} /* end rxrpc_krxiod_kill() */
-
-/*****************************************************************************/
-/*
- * queue a transport for attention by krxiod
- */
-void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans)
-{
-	unsigned long flags;
-
-	_enter("");
-
-	if (list_empty(&trans->krxiodq_link)) {
-		spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
-
-		if (list_empty(&trans->krxiodq_link)) {
-			if (atomic_read(&trans->usage) > 0) {
-				list_add_tail(&trans->krxiodq_link,
-					      &rxrpc_krxiod_transportq);
-				atomic_inc(&rxrpc_krxiod_qcount);
-			}
-		}
-
-		spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
-		wake_up_all(&rxrpc_krxiod_sleepq);
-	}
-
-	_leave("");
-
-} /* end rxrpc_krxiod_queue_transport() */
-
-/*****************************************************************************/
-/*
- * dequeue a transport from krxiod's attention queue
- */
-void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans)
-{
-	unsigned long flags;
-
-	_enter("");
-
-	spin_lock_irqsave(&rxrpc_krxiod_transportq_lock, flags);
-	if (!list_empty(&trans->krxiodq_link)) {
-		list_del_init(&trans->krxiodq_link);
-		atomic_dec(&rxrpc_krxiod_qcount);
-	}
-	spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock, flags);
-
-	_leave("");
-
-} /* end rxrpc_krxiod_dequeue_transport() */
-
-/*****************************************************************************/
-/*
- * queue a call for attention by krxiod
- */
-void rxrpc_krxiod_queue_call(struct rxrpc_call *call)
-{
-	unsigned long flags;
-
-	if (list_empty(&call->rcv_krxiodq_lk)) {
-		spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
-		if (atomic_read(&call->usage) > 0) {
-			list_add_tail(&call->rcv_krxiodq_lk,
-				      &rxrpc_krxiod_callq);
-			atomic_inc(&rxrpc_krxiod_qcount);
-		}
-		spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
-	}
-	wake_up_all(&rxrpc_krxiod_sleepq);
-
-} /* end rxrpc_krxiod_queue_call() */
-
-/*****************************************************************************/
-/*
- * dequeue a call from krxiod's attention queue
- */
-void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&rxrpc_krxiod_callq_lock, flags);
-	if (!list_empty(&call->rcv_krxiodq_lk)) {
-		list_del_init(&call->rcv_krxiodq_lk);
-		atomic_dec(&rxrpc_krxiod_qcount);
-	}
-	spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock, flags);
-
-} /* end rxrpc_krxiod_dequeue_call() */
diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
deleted file mode 100644
index 9a1e7f5..0000000
--- a/net/rxrpc/krxsecd.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/* krxsecd.c: Rx security daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This daemon deals with:
- * - consulting the application as to whether inbound peers and calls should be authorised
- * - generating security challenges for inbound connections
- * - responding to security challenges on outbound connections
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <rxrpc/krxsecd.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/message.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/call.h>
-#include <linux/udp.h>
-#include <linux/ip.h>
-#include <linux/freezer.h>
-#include <net/sock.h>
-#include "internal.h"
-
-static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxsecd_sleepq);
-static DECLARE_COMPLETION(rxrpc_krxsecd_dead);
-static volatile int rxrpc_krxsecd_die;
-
-static atomic_t rxrpc_krxsecd_qcount;
-
-/* queue of unprocessed inbound messages with seqno #1 and
- * RXRPC_CLIENT_INITIATED flag set */
-static LIST_HEAD(rxrpc_krxsecd_initmsgq);
-static DEFINE_SPINLOCK(rxrpc_krxsecd_initmsgq_lock);
-
-static void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg);
-
-/*****************************************************************************/
-/*
- * Rx security daemon
- */
-static int rxrpc_krxsecd(void *arg)
-{
-	DECLARE_WAITQUEUE(krxsecd, current);
-
-	int die;
-
-	printk("Started krxsecd %d\n", current->pid);
-
-	daemonize("krxsecd");
-
-	/* loop around waiting for work to do */
-	do {
-		/* wait for work or to be told to exit */
-		_debug("### Begin Wait");
-		if (!atomic_read(&rxrpc_krxsecd_qcount)) {
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			add_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd);
-
-			for (;;) {
-				set_current_state(TASK_INTERRUPTIBLE);
-				if (atomic_read(&rxrpc_krxsecd_qcount) ||
-				    rxrpc_krxsecd_die ||
-				    signal_pending(current))
-					break;
-
-				schedule();
-			}
-
-			remove_wait_queue(&rxrpc_krxsecd_sleepq, &krxsecd);
-			set_current_state(TASK_RUNNING);
-		}
-		die = rxrpc_krxsecd_die;
-		_debug("### End Wait");
-
-		/* see if there're incoming calls in need of authenticating */
-		_debug("### Begin Inbound Calls");
-
-		if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
-			struct rxrpc_message *msg = NULL;
-
-			spin_lock(&rxrpc_krxsecd_initmsgq_lock);
-
-			if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
-				msg = list_entry(rxrpc_krxsecd_initmsgq.next,
-						 struct rxrpc_message, link);
-				list_del_init(&msg->link);
-				atomic_dec(&rxrpc_krxsecd_qcount);
-			}
-
-			spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
-
-			if (msg) {
-				rxrpc_krxsecd_process_incoming_call(msg);
-				rxrpc_put_message(msg);
-			}
-		}
-
-		_debug("### End Inbound Calls");
-
-		try_to_freeze();
-
-		/* discard pending signals */
-		rxrpc_discard_my_signals();
-
-	} while (!die);
-
-	/* and that's all */
-	complete_and_exit(&rxrpc_krxsecd_dead, 0);
-
-} /* end rxrpc_krxsecd() */
-
-/*****************************************************************************/
-/*
- * start up a krxsecd daemon
- */
-int __init rxrpc_krxsecd_init(void)
-{
-	return kernel_thread(rxrpc_krxsecd, NULL, 0);
-
-} /* end rxrpc_krxsecd_init() */
-
-/*****************************************************************************/
-/*
- * kill the krxsecd daemon and wait for it to complete
- */
-void rxrpc_krxsecd_kill(void)
-{
-	rxrpc_krxsecd_die = 1;
-	wake_up_all(&rxrpc_krxsecd_sleepq);
-	wait_for_completion(&rxrpc_krxsecd_dead);
-
-} /* end rxrpc_krxsecd_kill() */
-
-/*****************************************************************************/
-/*
- * clear all pending incoming calls for the specified transport
- */
-void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans)
-{
-	LIST_HEAD(tmp);
-
-	struct rxrpc_message *msg;
-	struct list_head *_p, *_n;
-
-	_enter("%p",trans);
-
-	/* move all the messages for this transport onto a temp list */
-	spin_lock(&rxrpc_krxsecd_initmsgq_lock);
-
-	list_for_each_safe(_p, _n, &rxrpc_krxsecd_initmsgq) {
-		msg = list_entry(_p, struct rxrpc_message, link);
-		if (msg->trans == trans) {
-			list_move_tail(&msg->link, &tmp);
-			atomic_dec(&rxrpc_krxsecd_qcount);
-		}
-	}
-
-	spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
-
-	/* zap all messages on the temp list */
-	while (!list_empty(&tmp)) {
-		msg = list_entry(tmp.next, struct rxrpc_message, link);
-		list_del_init(&msg->link);
-		rxrpc_put_message(msg);
-	}
-
-	_leave("");
-} /* end rxrpc_krxsecd_clear_transport() */
-
-/*****************************************************************************/
-/*
- * queue a message on the incoming calls list
- */
-void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg)
-{
-	_enter("%p", msg);
-
-	/* queue for processing by krxsecd */
-	spin_lock(&rxrpc_krxsecd_initmsgq_lock);
-
-	if (!rxrpc_krxsecd_die) {
-		rxrpc_get_message(msg);
-		list_add_tail(&msg->link, &rxrpc_krxsecd_initmsgq);
-		atomic_inc(&rxrpc_krxsecd_qcount);
-	}
-
-	spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
-
-	wake_up(&rxrpc_krxsecd_sleepq);
-
-	_leave("");
-} /* end rxrpc_krxsecd_queue_incoming_call() */
-
-/*****************************************************************************/
-/*
- * process the initial message of an incoming call
- */
-void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg)
-{
-	struct rxrpc_transport *trans = msg->trans;
-	struct rxrpc_service *srv;
-	struct rxrpc_call *call;
-	struct list_head *_p;
-	unsigned short sid;
-	int ret;
-
-	_enter("%p{tr=%p}", msg, trans);
-
-	ret = rxrpc_incoming_call(msg->conn, msg, &call);
-	if (ret < 0)
-		goto out;
-
-	/* find the matching service on the transport */
-	sid = ntohs(msg->hdr.serviceId);
-	srv = NULL;
-
-	spin_lock(&trans->lock);
-	list_for_each(_p, &trans->services) {
-		srv = list_entry(_p, struct rxrpc_service, link);
-		if (srv->service_id == sid && try_module_get(srv->owner)) {
-			/* found a match (made sure it won't vanish) */
-			_debug("found service '%s'", srv->name);
-			call->owner = srv->owner;
-			break;
-		}
-	}
-	spin_unlock(&trans->lock);
-
-	/* report the new connection
-	 * - the func must inc the call's usage count to keep it
-	 */
-	ret = -ENOENT;
-	if (_p != &trans->services) {
-		/* attempt to accept the call */
-		call->conn->service = srv;
-		call->app_attn_func = srv->attn_func;
-		call->app_error_func = srv->error_func;
-		call->app_aemap_func = srv->aemap_func;
-
-		ret = srv->new_call(call);
-
-		/* send an abort if an error occurred */
-		if (ret < 0) {
-			rxrpc_call_abort(call, ret);
-		}
-		else {
-			/* formally receive and ACK the new packet */
-			ret = rxrpc_conn_receive_call_packet(call->conn,
-							     call, msg);
-		}
-	}
-
-	rxrpc_put_call(call);
- out:
-	if (ret < 0)
-		rxrpc_trans_immediate_abort(trans, msg, ret);
-
-	_leave(" (%d)", ret);
-} /* end rxrpc_krxsecd_process_incoming_call() */
diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c
deleted file mode 100644
index 9a9b613..0000000
--- a/net/rxrpc/krxtimod.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/* krxtimod.c: RXRPC timeout daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/completion.h>
-#include <linux/freezer.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/krxtimod.h>
-#include <asm/errno.h>
-#include "internal.h"
-
-static DECLARE_COMPLETION(krxtimod_alive);
-static DECLARE_COMPLETION(krxtimod_dead);
-static DECLARE_WAIT_QUEUE_HEAD(krxtimod_sleepq);
-static int krxtimod_die;
-
-static LIST_HEAD(krxtimod_list);
-static DEFINE_SPINLOCK(krxtimod_lock);
-
-static int krxtimod(void *arg);
-
-/*****************************************************************************/
-/*
- * start the timeout daemon
- */
-int rxrpc_krxtimod_start(void)
-{
-	int ret;
-
-	ret = kernel_thread(krxtimod, NULL, 0);
-	if (ret < 0)
-		return ret;
-
-	wait_for_completion(&krxtimod_alive);
-
-	return ret;
-} /* end rxrpc_krxtimod_start() */
-
-/*****************************************************************************/
-/*
- * stop the timeout daemon
- */
-void rxrpc_krxtimod_kill(void)
-{
-	/* get rid of my daemon */
-	krxtimod_die = 1;
-	wake_up(&krxtimod_sleepq);
-	wait_for_completion(&krxtimod_dead);
-
-} /* end rxrpc_krxtimod_kill() */
-
-/*****************************************************************************/
-/*
- * timeout processing daemon
- */
-static int krxtimod(void *arg)
-{
-	DECLARE_WAITQUEUE(myself, current);
-
-	rxrpc_timer_t *timer;
-
-	printk("Started krxtimod %d\n", current->pid);
-
-	daemonize("krxtimod");
-
-	complete(&krxtimod_alive);
-
-	/* loop around looking for things to attend to */
- loop:
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&krxtimod_sleepq, &myself);
-
-	for (;;) {
-		unsigned long jif;
-		long timeout;
-
-		/* deal with the server being asked to die */
-		if (krxtimod_die) {
-			remove_wait_queue(&krxtimod_sleepq, &myself);
-			_leave("");
-			complete_and_exit(&krxtimod_dead, 0);
-		}
-
-		try_to_freeze();
-
-		/* discard pending signals */
-		rxrpc_discard_my_signals();
-
-		/* work out the time to elapse before the next event */
-		spin_lock(&krxtimod_lock);
-		if (list_empty(&krxtimod_list)) {
-			timeout = MAX_SCHEDULE_TIMEOUT;
-		}
-		else {
-			timer = list_entry(krxtimod_list.next,
-					   rxrpc_timer_t, link);
-			timeout = timer->timo_jif;
-			jif = jiffies;
-
-			if (time_before_eq((unsigned long) timeout, jif))
-				goto immediate;
-
-			else {
-				timeout = (long) timeout - (long) jiffies;
-			}
-		}
-		spin_unlock(&krxtimod_lock);
-
-		schedule_timeout(timeout);
-
-		set_current_state(TASK_INTERRUPTIBLE);
-	}
-
-	/* the thing on the front of the queue needs processing
-	 * - we come here with the lock held and timer pointing to the expired
-	 *   entry
-	 */
- immediate:
-	remove_wait_queue(&krxtimod_sleepq, &myself);
-	set_current_state(TASK_RUNNING);
-
-	_debug("@@@ Begin Timeout of %p", timer);
-
-	/* dequeue the timer */
-	list_del_init(&timer->link);
-	spin_unlock(&krxtimod_lock);
-
-	/* call the timeout function */
-	timer->ops->timed_out(timer);
-
-	_debug("@@@ End Timeout");
-	goto loop;
-
-} /* end krxtimod() */
-
-/*****************************************************************************/
-/*
- * (re-)queue a timer
- */
-void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout)
-{
-	struct list_head *_p;
-	rxrpc_timer_t *ptimer;
-
-	_enter("%p,%lu", timer, timeout);
-
-	spin_lock(&krxtimod_lock);
-
-	list_del(&timer->link);
-
-	/* the timer was deferred or reset - put it back in the queue at the
-	 * right place */
-	timer->timo_jif = jiffies + timeout;
-
-	list_for_each(_p, &krxtimod_list) {
-		ptimer = list_entry(_p, rxrpc_timer_t, link);
-		if (time_before(timer->timo_jif, ptimer->timo_jif))
-			break;
-	}
-
-	list_add_tail(&timer->link, _p); /* insert before stopping point */
-
-	spin_unlock(&krxtimod_lock);
-
-	wake_up(&krxtimod_sleepq);
-
-	_leave("");
-} /* end rxrpc_krxtimod_add_timer() */
-
-/*****************************************************************************/
-/*
- * dequeue a timer
- * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
- */
-int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer)
-{
-	int ret = 0;
-
-	_enter("%p", timer);
-
-	spin_lock(&krxtimod_lock);
-
-	if (list_empty(&timer->link))
-		ret = -ENOENT;
-	else
-		list_del_init(&timer->link);
-
-	spin_unlock(&krxtimod_lock);
-
-	wake_up(&krxtimod_sleepq);
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_krxtimod_del_timer() */
diff --git a/net/rxrpc/main.c b/net/rxrpc/main.c
deleted file mode 100644
index baec1f7..0000000
--- a/net/rxrpc/main.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* main.c: Rx RPC interface
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/krxiod.h>
-#include <rxrpc/krxsecd.h>
-#include <rxrpc/krxtimod.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include "internal.h"
-
-MODULE_DESCRIPTION("Rx RPC implementation");
-MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL");
-
-__be32 rxrpc_epoch;
-
-/*****************************************************************************/
-/*
- * initialise the Rx module
- */
-static int __init rxrpc_initialise(void)
-{
-	int ret;
-
-	/* my epoch value */
-	rxrpc_epoch = htonl(xtime.tv_sec);
-
-	/* register the /proc interface */
-#ifdef CONFIG_PROC_FS
-	ret = rxrpc_proc_init();
-	if (ret<0)
-		return ret;
-#endif
-
-	/* register the sysctl files */
-#ifdef CONFIG_SYSCTL
-	ret = rxrpc_sysctl_init();
-	if (ret<0)
-		goto error_proc;
-#endif
-
-	/* start the krxtimod daemon */
-	ret = rxrpc_krxtimod_start();
-	if (ret<0)
-		goto error_sysctl;
-
-	/* start the krxiod daemon */
-	ret = rxrpc_krxiod_init();
-	if (ret<0)
-		goto error_krxtimod;
-
-	/* start the krxsecd daemon */
-	ret = rxrpc_krxsecd_init();
-	if (ret<0)
-		goto error_krxiod;
-
-	kdebug("\n\n");
-
-	return 0;
-
- error_krxiod:
-	rxrpc_krxiod_kill();
- error_krxtimod:
-	rxrpc_krxtimod_kill();
- error_sysctl:
-#ifdef CONFIG_SYSCTL
-	rxrpc_sysctl_cleanup();
- error_proc:
-#endif
-#ifdef CONFIG_PROC_FS
-	rxrpc_proc_cleanup();
-#endif
-	return ret;
-} /* end rxrpc_initialise() */
-
-module_init(rxrpc_initialise);
-
-/*****************************************************************************/
-/*
- * clean up the Rx module
- */
-static void __exit rxrpc_cleanup(void)
-{
-	kenter("");
-
-	__RXACCT(printk("Outstanding Messages   : %d\n",
-			atomic_read(&rxrpc_message_count)));
-	__RXACCT(printk("Outstanding Calls      : %d\n",
-			atomic_read(&rxrpc_call_count)));
-	__RXACCT(printk("Outstanding Connections: %d\n",
-			atomic_read(&rxrpc_connection_count)));
-	__RXACCT(printk("Outstanding Peers      : %d\n",
-			atomic_read(&rxrpc_peer_count)));
-	__RXACCT(printk("Outstanding Transports : %d\n",
-			atomic_read(&rxrpc_transport_count)));
-
-	rxrpc_krxsecd_kill();
-	rxrpc_krxiod_kill();
-	rxrpc_krxtimod_kill();
-#ifdef CONFIG_SYSCTL
-	rxrpc_sysctl_cleanup();
-#endif
-#ifdef CONFIG_PROC_FS
-	rxrpc_proc_cleanup();
-#endif
-
-	__RXACCT(printk("Outstanding Messages   : %d\n",
-			atomic_read(&rxrpc_message_count)));
-	__RXACCT(printk("Outstanding Calls      : %d\n",
-			atomic_read(&rxrpc_call_count)));
-	__RXACCT(printk("Outstanding Connections: %d\n",
-			atomic_read(&rxrpc_connection_count)));
-	__RXACCT(printk("Outstanding Peers      : %d\n",
-			atomic_read(&rxrpc_peer_count)));
-	__RXACCT(printk("Outstanding Transports : %d\n",
-			atomic_read(&rxrpc_transport_count)));
-
-	kleave("");
-} /* end rxrpc_cleanup() */
-
-module_exit(rxrpc_cleanup);
-
-/*****************************************************************************/
-/*
- * clear the dead space between task_struct and kernel stack
- * - called by supplying -finstrument-functions to gcc
- */
-#if 0
-void __cyg_profile_func_enter (void *this_fn, void *call_site)
-__attribute__((no_instrument_function));
-
-void __cyg_profile_func_enter (void *this_fn, void *call_site)
-{
-       asm volatile("  movl    %%esp,%%edi     \n"
-		    "  andl    %0,%%edi        \n"
-		    "  addl    %1,%%edi        \n"
-		    "  movl    %%esp,%%ecx     \n"
-		    "  subl    %%edi,%%ecx     \n"
-		    "  shrl    $2,%%ecx        \n"
-		    "  movl    $0xedededed,%%eax     \n"
-		    "  rep stosl               \n"
-		    :
-		    : "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info))
-		    : "eax", "ecx", "edi", "memory", "cc"
-		    );
-}
-
-void __cyg_profile_func_exit(void *this_fn, void *call_site)
-__attribute__((no_instrument_function));
-
-void __cyg_profile_func_exit(void *this_fn, void *call_site)
-{
-       asm volatile("  movl    %%esp,%%edi     \n"
-		    "  andl    %0,%%edi        \n"
-		    "  addl    %1,%%edi        \n"
-		    "  movl    %%esp,%%ecx     \n"
-		    "  subl    %%edi,%%ecx     \n"
-		    "  shrl    $2,%%ecx        \n"
-		    "  movl    $0xdadadada,%%eax     \n"
-		    "  rep stosl               \n"
-		    :
-		    : "i"(~(THREAD_SIZE-1)), "i"(sizeof(struct thread_info))
-		    : "eax", "ecx", "edi", "memory", "cc"
-		    );
-}
-#endif
diff --git a/net/rxrpc/peer.c b/net/rxrpc/peer.c
deleted file mode 100644
index 8a27515..0000000
--- a/net/rxrpc/peer.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/* peer.c: Rx RPC peer management
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include <linux/udp.h>
-#include <linux/ip.h>
-#include <net/sock.h>
-#include <asm/uaccess.h>
-#include <asm/div64.h>
-#include "internal.h"
-
-__RXACCT_DECL(atomic_t rxrpc_peer_count);
-LIST_HEAD(rxrpc_peers);
-DECLARE_RWSEM(rxrpc_peers_sem);
-unsigned long rxrpc_peer_timeout = 12 * 60 * 60;
-
-static void rxrpc_peer_do_timeout(struct rxrpc_peer *peer);
-
-static void __rxrpc_peer_timeout(rxrpc_timer_t *timer)
-{
-	struct rxrpc_peer *peer =
-		list_entry(timer, struct rxrpc_peer, timeout);
-
-	_debug("Rx PEER TIMEOUT [%p{u=%d}]", peer, atomic_read(&peer->usage));
-
-	rxrpc_peer_do_timeout(peer);
-}
-
-static const struct rxrpc_timer_ops rxrpc_peer_timer_ops = {
-	.timed_out	= __rxrpc_peer_timeout,
-};
-
-/*****************************************************************************/
-/*
- * create a peer record
- */
-static int __rxrpc_create_peer(struct rxrpc_transport *trans, __be32 addr,
-			       struct rxrpc_peer **_peer)
-{
-	struct rxrpc_peer *peer;
-
-	_enter("%p,%08x", trans, ntohl(addr));
-
-	/* allocate and initialise a peer record */
-	peer = kzalloc(sizeof(struct rxrpc_peer), GFP_KERNEL);
-	if (!peer) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	atomic_set(&peer->usage, 1);
-
-	INIT_LIST_HEAD(&peer->link);
-	INIT_LIST_HEAD(&peer->proc_link);
-	INIT_LIST_HEAD(&peer->conn_idlist);
-	INIT_LIST_HEAD(&peer->conn_active);
-	INIT_LIST_HEAD(&peer->conn_graveyard);
-	spin_lock_init(&peer->conn_gylock);
-	init_waitqueue_head(&peer->conn_gy_waitq);
-	rwlock_init(&peer->conn_idlock);
-	rwlock_init(&peer->conn_lock);
-	atomic_set(&peer->conn_count, 0);
-	spin_lock_init(&peer->lock);
-	rxrpc_timer_init(&peer->timeout, &rxrpc_peer_timer_ops);
-
-	peer->addr.s_addr = addr;
-
-	peer->trans = trans;
-	peer->ops = trans->peer_ops;
-
-	__RXACCT(atomic_inc(&rxrpc_peer_count));
-	*_peer = peer;
-	_leave(" = 0 (%p)", peer);
-
-	return 0;
-} /* end __rxrpc_create_peer() */
-
-/*****************************************************************************/
-/*
- * find a peer record on the specified transport
- * - returns (if successful) with peer record usage incremented
- * - resurrects it from the graveyard if found there
- */
-int rxrpc_peer_lookup(struct rxrpc_transport *trans, __be32 addr,
-		      struct rxrpc_peer **_peer)
-{
-	struct rxrpc_peer *peer, *candidate = NULL;
-	struct list_head *_p;
-	int ret;
-
-	_enter("%p{%hu},%08x", trans, trans->port, ntohl(addr));
-
-	/* [common case] search the transport's active list first */
-	read_lock(&trans->peer_lock);
-	list_for_each(_p, &trans->peer_active) {
-		peer = list_entry(_p, struct rxrpc_peer, link);
-		if (peer->addr.s_addr == addr)
-			goto found_active;
-	}
-	read_unlock(&trans->peer_lock);
-
-	/* [uncommon case] not active - create a candidate for a new record */
-	ret = __rxrpc_create_peer(trans, addr, &candidate);
-	if (ret < 0) {
-		_leave(" = %d", ret);
-		return ret;
-	}
-
-	/* search the active list again, just in case it appeared whilst we
-	 * were busy */
-	write_lock(&trans->peer_lock);
-	list_for_each(_p, &trans->peer_active) {
-		peer = list_entry(_p, struct rxrpc_peer, link);
-		if (peer->addr.s_addr == addr)
-			goto found_active_second_chance;
-	}
-
-	/* search the transport's graveyard list */
-	spin_lock(&trans->peer_gylock);
-	list_for_each(_p, &trans->peer_graveyard) {
-		peer = list_entry(_p, struct rxrpc_peer, link);
-		if (peer->addr.s_addr == addr)
-			goto found_in_graveyard;
-	}
-	spin_unlock(&trans->peer_gylock);
-
-	/* we can now add the new candidate to the list
-	 * - tell the application layer that this peer has been added
-	 */
-	rxrpc_get_transport(trans);
-	peer = candidate;
-	candidate = NULL;
-
-	if (peer->ops && peer->ops->adding) {
-		ret = peer->ops->adding(peer);
-		if (ret < 0) {
-			write_unlock(&trans->peer_lock);
-			__RXACCT(atomic_dec(&rxrpc_peer_count));
-			kfree(peer);
-			rxrpc_put_transport(trans);
-			_leave(" = %d", ret);
-			return ret;
-		}
-	}
-
-	atomic_inc(&trans->peer_count);
-
- make_active:
-	list_add_tail(&peer->link, &trans->peer_active);
-
- success_uwfree:
-	write_unlock(&trans->peer_lock);
-
-	if (candidate) {
-		__RXACCT(atomic_dec(&rxrpc_peer_count));
-		kfree(candidate);
-	}
-
-	if (list_empty(&peer->proc_link)) {
-		down_write(&rxrpc_peers_sem);
-		list_add_tail(&peer->proc_link, &rxrpc_peers);
-		up_write(&rxrpc_peers_sem);
-	}
-
- success:
-	*_peer = peer;
-
-	_leave(" = 0 (%p{u=%d cc=%d})",
-	       peer,
-	       atomic_read(&peer->usage),
-	       atomic_read(&peer->conn_count));
-	return 0;
-
-	/* handle the peer being found in the active list straight off */
- found_active:
-	rxrpc_get_peer(peer);
-	read_unlock(&trans->peer_lock);
-	goto success;
-
-	/* handle resurrecting a peer from the graveyard */
- found_in_graveyard:
-	rxrpc_get_peer(peer);
-	rxrpc_get_transport(peer->trans);
-	rxrpc_krxtimod_del_timer(&peer->timeout);
-	list_del_init(&peer->link);
-	spin_unlock(&trans->peer_gylock);
-	goto make_active;
-
-	/* handle finding the peer on the second time through the active
-	 * list */
- found_active_second_chance:
-	rxrpc_get_peer(peer);
-	goto success_uwfree;
-
-} /* end rxrpc_peer_lookup() */
-
-/*****************************************************************************/
-/*
- * finish with a peer record
- * - it gets sent to the graveyard from where it can be resurrected or timed
- *   out
- */
-void rxrpc_put_peer(struct rxrpc_peer *peer)
-{
-	struct rxrpc_transport *trans = peer->trans;
-
-	_enter("%p{cc=%d a=%08x}",
-	       peer,
-	       atomic_read(&peer->conn_count),
-	       ntohl(peer->addr.s_addr));
-
-	/* sanity check */
-	if (atomic_read(&peer->usage) <= 0)
-		BUG();
-
-	write_lock(&trans->peer_lock);
-	spin_lock(&trans->peer_gylock);
-	if (likely(!atomic_dec_and_test(&peer->usage))) {
-		spin_unlock(&trans->peer_gylock);
-		write_unlock(&trans->peer_lock);
-		_leave("");
-		return;
-	}
-
-	/* move to graveyard queue */
-	list_del(&peer->link);
-	write_unlock(&trans->peer_lock);
-
-	list_add_tail(&peer->link, &trans->peer_graveyard);
-
-	BUG_ON(!list_empty(&peer->conn_active));
-
-	rxrpc_krxtimod_add_timer(&peer->timeout, rxrpc_peer_timeout * HZ);
-
-	spin_unlock(&trans->peer_gylock);
-
-	rxrpc_put_transport(trans);
-
-	_leave(" [killed]");
-} /* end rxrpc_put_peer() */
-
-/*****************************************************************************/
-/*
- * handle a peer timing out in the graveyard
- * - called from krxtimod
- */
-static void rxrpc_peer_do_timeout(struct rxrpc_peer *peer)
-{
-	struct rxrpc_transport *trans = peer->trans;
-
-	_enter("%p{u=%d cc=%d a=%08x}",
-	       peer,
-	       atomic_read(&peer->usage),
-	       atomic_read(&peer->conn_count),
-	       ntohl(peer->addr.s_addr));
-
-	BUG_ON(atomic_read(&peer->usage) < 0);
-
-	/* remove from graveyard if still dead */
-	spin_lock(&trans->peer_gylock);
-	if (atomic_read(&peer->usage) == 0)
-		list_del_init(&peer->link);
-	else
-		peer = NULL;
-	spin_unlock(&trans->peer_gylock);
-
-	if (!peer) {
-		_leave("");
-		return; /* resurrected */
-	}
-
-	/* clear all connections on this peer */
-	rxrpc_conn_clearall(peer);
-
-	BUG_ON(!list_empty(&peer->conn_active));
-	BUG_ON(!list_empty(&peer->conn_graveyard));
-
-	/* inform the application layer */
-	if (peer->ops && peer->ops->discarding)
-		peer->ops->discarding(peer);
-
-	if (!list_empty(&peer->proc_link)) {
-		down_write(&rxrpc_peers_sem);
-		list_del(&peer->proc_link);
-		up_write(&rxrpc_peers_sem);
-	}
-
-	__RXACCT(atomic_dec(&rxrpc_peer_count));
-	kfree(peer);
-
-	/* if the graveyard is now empty, wake up anyone waiting for that */
-	if (atomic_dec_and_test(&trans->peer_count))
-		wake_up(&trans->peer_gy_waitq);
-
-	_leave(" [destroyed]");
-} /* end rxrpc_peer_do_timeout() */
-
-/*****************************************************************************/
-/*
- * clear all peer records from a transport endpoint
- */
-void rxrpc_peer_clearall(struct rxrpc_transport *trans)
-{
-	DECLARE_WAITQUEUE(myself,current);
-
-	struct rxrpc_peer *peer;
-	int err;
-
-	_enter("%p",trans);
-
-	/* there shouldn't be any active peers remaining */
-	BUG_ON(!list_empty(&trans->peer_active));
-
-	/* manually timeout all peers in the graveyard */
-	spin_lock(&trans->peer_gylock);
-	while (!list_empty(&trans->peer_graveyard)) {
-		peer = list_entry(trans->peer_graveyard.next,
-				  struct rxrpc_peer, link);
-		_debug("Clearing peer %p\n", peer);
-		err = rxrpc_krxtimod_del_timer(&peer->timeout);
-		spin_unlock(&trans->peer_gylock);
-
-		if (err == 0)
-			rxrpc_peer_do_timeout(peer);
-
-		spin_lock(&trans->peer_gylock);
-	}
-	spin_unlock(&trans->peer_gylock);
-
-	/* wait for the the peer graveyard to be completely cleared */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	add_wait_queue(&trans->peer_gy_waitq, &myself);
-
-	while (atomic_read(&trans->peer_count) != 0) {
-		schedule();
-		set_current_state(TASK_UNINTERRUPTIBLE);
-	}
-
-	remove_wait_queue(&trans->peer_gy_waitq, &myself);
-	set_current_state(TASK_RUNNING);
-
-	_leave("");
-} /* end rxrpc_peer_clearall() */
-
-/*****************************************************************************/
-/*
- * calculate and cache the Round-Trip-Time for a message and its response
- */
-void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer,
-			      struct rxrpc_message *msg,
-			      struct rxrpc_message *resp)
-{
-	unsigned long long rtt;
-	int loop;
-
-	_enter("%p,%p,%p", peer, msg, resp);
-
-	/* calculate the latest RTT */
-	rtt = resp->stamp.tv_sec - msg->stamp.tv_sec;
-	rtt *= 1000000UL;
-	rtt += resp->stamp.tv_usec - msg->stamp.tv_usec;
-
-	/* add to cache */
-	peer->rtt_cache[peer->rtt_point] = rtt;
-	peer->rtt_point++;
-	peer->rtt_point %= RXRPC_RTT_CACHE_SIZE;
-
-	if (peer->rtt_usage < RXRPC_RTT_CACHE_SIZE)
-		peer->rtt_usage++;
-
-	/* recalculate RTT */
-	rtt = 0;
-	for (loop = peer->rtt_usage - 1; loop >= 0; loop--)
-		rtt += peer->rtt_cache[loop];
-
-	do_div(rtt, peer->rtt_usage);
-	peer->rtt = rtt;
-
-	_leave(" RTT=%lu.%lums",
-	       (long) (peer->rtt / 1000), (long) (peer->rtt % 1000));
-
-} /* end rxrpc_peer_calculate_rtt() */
diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c
deleted file mode 100644
index 8551c87..0000000
--- a/net/rxrpc/proc.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/* proc.c: /proc interface for RxRPC
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <rxrpc/rxrpc.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include "internal.h"
-
-static struct proc_dir_entry *proc_rxrpc;
-
-static int rxrpc_proc_transports_open(struct inode *inode, struct file *file);
-static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos);
-static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos);
-static void rxrpc_proc_transports_stop(struct seq_file *p, void *v);
-static int rxrpc_proc_transports_show(struct seq_file *m, void *v);
-
-static struct seq_operations rxrpc_proc_transports_ops = {
-	.start	= rxrpc_proc_transports_start,
-	.next	= rxrpc_proc_transports_next,
-	.stop	= rxrpc_proc_transports_stop,
-	.show	= rxrpc_proc_transports_show,
-};
-
-static const struct file_operations rxrpc_proc_transports_fops = {
-	.open		= rxrpc_proc_transports_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static int rxrpc_proc_peers_open(struct inode *inode, struct file *file);
-static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos);
-static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos);
-static void rxrpc_proc_peers_stop(struct seq_file *p, void *v);
-static int rxrpc_proc_peers_show(struct seq_file *m, void *v);
-
-static struct seq_operations rxrpc_proc_peers_ops = {
-	.start	= rxrpc_proc_peers_start,
-	.next	= rxrpc_proc_peers_next,
-	.stop	= rxrpc_proc_peers_stop,
-	.show	= rxrpc_proc_peers_show,
-};
-
-static const struct file_operations rxrpc_proc_peers_fops = {
-	.open		= rxrpc_proc_peers_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static int rxrpc_proc_conns_open(struct inode *inode, struct file *file);
-static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos);
-static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos);
-static void rxrpc_proc_conns_stop(struct seq_file *p, void *v);
-static int rxrpc_proc_conns_show(struct seq_file *m, void *v);
-
-static struct seq_operations rxrpc_proc_conns_ops = {
-	.start	= rxrpc_proc_conns_start,
-	.next	= rxrpc_proc_conns_next,
-	.stop	= rxrpc_proc_conns_stop,
-	.show	= rxrpc_proc_conns_show,
-};
-
-static const struct file_operations rxrpc_proc_conns_fops = {
-	.open		= rxrpc_proc_conns_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static int rxrpc_proc_calls_open(struct inode *inode, struct file *file);
-static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos);
-static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos);
-static void rxrpc_proc_calls_stop(struct seq_file *p, void *v);
-static int rxrpc_proc_calls_show(struct seq_file *m, void *v);
-
-static struct seq_operations rxrpc_proc_calls_ops = {
-	.start	= rxrpc_proc_calls_start,
-	.next	= rxrpc_proc_calls_next,
-	.stop	= rxrpc_proc_calls_stop,
-	.show	= rxrpc_proc_calls_show,
-};
-
-static const struct file_operations rxrpc_proc_calls_fops = {
-	.open		= rxrpc_proc_calls_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static const char *rxrpc_call_states7[] = {
-	"complet",
-	"error  ",
-	"rcv_op ",
-	"rcv_arg",
-	"got_arg",
-	"snd_rpl",
-	"fin_ack",
-	"snd_arg",
-	"rcv_rpl",
-	"got_rpl"
-};
-
-static const char *rxrpc_call_error_states7[] = {
-	"no_err ",
-	"loc_abt",
-	"rmt_abt",
-	"loc_err",
-	"rmt_err"
-};
-
-/*****************************************************************************/
-/*
- * initialise the /proc/net/rxrpc/ directory
- */
-int rxrpc_proc_init(void)
-{
-	struct proc_dir_entry *p;
-
-	proc_rxrpc = proc_mkdir("rxrpc", proc_net);
-	if (!proc_rxrpc)
-		goto error;
-	proc_rxrpc->owner = THIS_MODULE;
-
-	p = create_proc_entry("calls", 0, proc_rxrpc);
-	if (!p)
-		goto error_proc;
-	p->proc_fops = &rxrpc_proc_calls_fops;
-	p->owner = THIS_MODULE;
-
-	p = create_proc_entry("connections", 0, proc_rxrpc);
-	if (!p)
-		goto error_calls;
-	p->proc_fops = &rxrpc_proc_conns_fops;
-	p->owner = THIS_MODULE;
-
-	p = create_proc_entry("peers", 0, proc_rxrpc);
-	if (!p)
-		goto error_calls;
-	p->proc_fops = &rxrpc_proc_peers_fops;
-	p->owner = THIS_MODULE;
-
-	p = create_proc_entry("transports", 0, proc_rxrpc);
-	if (!p)
-		goto error_conns;
-	p->proc_fops = &rxrpc_proc_transports_fops;
-	p->owner = THIS_MODULE;
-
-	return 0;
-
- error_conns:
-	remove_proc_entry("connections", proc_rxrpc);
- error_calls:
-	remove_proc_entry("calls", proc_rxrpc);
- error_proc:
-	remove_proc_entry("rxrpc", proc_net);
- error:
-	return -ENOMEM;
-} /* end rxrpc_proc_init() */
-
-/*****************************************************************************/
-/*
- * clean up the /proc/net/rxrpc/ directory
- */
-void rxrpc_proc_cleanup(void)
-{
-	remove_proc_entry("transports", proc_rxrpc);
-	remove_proc_entry("peers", proc_rxrpc);
-	remove_proc_entry("connections", proc_rxrpc);
-	remove_proc_entry("calls", proc_rxrpc);
-
-	remove_proc_entry("rxrpc", proc_net);
-
-} /* end rxrpc_proc_cleanup() */
-
-/*****************************************************************************/
-/*
- * open "/proc/net/rxrpc/transports" which provides a summary of extant transports
- */
-static int rxrpc_proc_transports_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *m;
-	int ret;
-
-	ret = seq_open(file, &rxrpc_proc_transports_ops);
-	if (ret < 0)
-		return ret;
-
-	m = file->private_data;
-	m->private = PDE(inode)->data;
-
-	return 0;
-} /* end rxrpc_proc_transports_open() */
-
-/*****************************************************************************/
-/*
- * set up the iterator to start reading from the transports list and return the first item
- */
-static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos)
-{
-	struct list_head *_p;
-	loff_t pos = *_pos;
-
-	/* lock the list against modification */
-	down_read(&rxrpc_proc_transports_sem);
-
-	/* allow for the header line */
-	if (!pos)
-		return SEQ_START_TOKEN;
-	pos--;
-
-	/* find the n'th element in the list */
-	list_for_each(_p, &rxrpc_proc_transports)
-		if (!pos--)
-			break;
-
-	return _p != &rxrpc_proc_transports ? _p : NULL;
-} /* end rxrpc_proc_transports_start() */
-
-/*****************************************************************************/
-/*
- * move to next call in transports list
- */
-static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct list_head *_p;
-
-	(*pos)++;
-
-	_p = v;
-	_p = (v == SEQ_START_TOKEN) ? rxrpc_proc_transports.next : _p->next;
-
-	return _p != &rxrpc_proc_transports ? _p : NULL;
-} /* end rxrpc_proc_transports_next() */
-
-/*****************************************************************************/
-/*
- * clean up after reading from the transports list
- */
-static void rxrpc_proc_transports_stop(struct seq_file *p, void *v)
-{
-	up_read(&rxrpc_proc_transports_sem);
-
-} /* end rxrpc_proc_transports_stop() */
-
-/*****************************************************************************/
-/*
- * display a header line followed by a load of call lines
- */
-static int rxrpc_proc_transports_show(struct seq_file *m, void *v)
-{
-	struct rxrpc_transport *trans =
-		list_entry(v, struct rxrpc_transport, proc_link);
-
-	/* display header on line 1 */
-	if (v == SEQ_START_TOKEN) {
-		seq_puts(m, "LOCAL USE\n");
-		return 0;
-	}
-
-	/* display one transport per line on subsequent lines */
-	seq_printf(m, "%5hu %3d\n",
-		   trans->port,
-		   atomic_read(&trans->usage)
-		   );
-
-	return 0;
-} /* end rxrpc_proc_transports_show() */
-
-/*****************************************************************************/
-/*
- * open "/proc/net/rxrpc/peers" which provides a summary of extant peers
- */
-static int rxrpc_proc_peers_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *m;
-	int ret;
-
-	ret = seq_open(file, &rxrpc_proc_peers_ops);
-	if (ret < 0)
-		return ret;
-
-	m = file->private_data;
-	m->private = PDE(inode)->data;
-
-	return 0;
-} /* end rxrpc_proc_peers_open() */
-
-/*****************************************************************************/
-/*
- * set up the iterator to start reading from the peers list and return the
- * first item
- */
-static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos)
-{
-	struct list_head *_p;
-	loff_t pos = *_pos;
-
-	/* lock the list against modification */
-	down_read(&rxrpc_peers_sem);
-
-	/* allow for the header line */
-	if (!pos)
-		return SEQ_START_TOKEN;
-	pos--;
-
-	/* find the n'th element in the list */
-	list_for_each(_p, &rxrpc_peers)
-		if (!pos--)
-			break;
-
-	return _p != &rxrpc_peers ? _p : NULL;
-} /* end rxrpc_proc_peers_start() */
-
-/*****************************************************************************/
-/*
- * move to next conn in peers list
- */
-static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct list_head *_p;
-
-	(*pos)++;
-
-	_p = v;
-	_p = (v == SEQ_START_TOKEN) ? rxrpc_peers.next : _p->next;
-
-	return _p != &rxrpc_peers ? _p : NULL;
-} /* end rxrpc_proc_peers_next() */
-
-/*****************************************************************************/
-/*
- * clean up after reading from the peers list
- */
-static void rxrpc_proc_peers_stop(struct seq_file *p, void *v)
-{
-	up_read(&rxrpc_peers_sem);
-
-} /* end rxrpc_proc_peers_stop() */
-
-/*****************************************************************************/
-/*
- * display a header line followed by a load of conn lines
- */
-static int rxrpc_proc_peers_show(struct seq_file *m, void *v)
-{
-	struct rxrpc_peer *peer = list_entry(v, struct rxrpc_peer, proc_link);
-	long timeout;
-
-	/* display header on line 1 */
-	if (v == SEQ_START_TOKEN) {
-		seq_puts(m, "LOCAL REMOTE   USAGE CONNS  TIMEOUT"
-			 "   MTU RTT(uS)\n");
-		return 0;
-	}
-
-	/* display one peer per line on subsequent lines */
-	timeout = 0;
-	if (!list_empty(&peer->timeout.link))
-		timeout = (long) peer->timeout.timo_jif -
-			(long) jiffies;
-
-	seq_printf(m, "%5hu %08x %5d %5d %8ld %5Zu %7lu\n",
-		   peer->trans->port,
-		   ntohl(peer->addr.s_addr),
-		   atomic_read(&peer->usage),
-		   atomic_read(&peer->conn_count),
-		   timeout,
-		   peer->if_mtu,
-		   (long) peer->rtt
-		   );
-
-	return 0;
-} /* end rxrpc_proc_peers_show() */
-
-/*****************************************************************************/
-/*
- * open "/proc/net/rxrpc/connections" which provides a summary of extant
- * connections
- */
-static int rxrpc_proc_conns_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *m;
-	int ret;
-
-	ret = seq_open(file, &rxrpc_proc_conns_ops);
-	if (ret < 0)
-		return ret;
-
-	m = file->private_data;
-	m->private = PDE(inode)->data;
-
-	return 0;
-} /* end rxrpc_proc_conns_open() */
-
-/*****************************************************************************/
-/*
- * set up the iterator to start reading from the conns list and return the
- * first item
- */
-static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos)
-{
-	struct list_head *_p;
-	loff_t pos = *_pos;
-
-	/* lock the list against modification */
-	down_read(&rxrpc_conns_sem);
-
-	/* allow for the header line */
-	if (!pos)
-		return SEQ_START_TOKEN;
-	pos--;
-
-	/* find the n'th element in the list */
-	list_for_each(_p, &rxrpc_conns)
-		if (!pos--)
-			break;
-
-	return _p != &rxrpc_conns ? _p : NULL;
-} /* end rxrpc_proc_conns_start() */
-
-/*****************************************************************************/
-/*
- * move to next conn in conns list
- */
-static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct list_head *_p;
-
-	(*pos)++;
-
-	_p = v;
-	_p = (v == SEQ_START_TOKEN) ? rxrpc_conns.next : _p->next;
-
-	return _p != &rxrpc_conns ? _p : NULL;
-} /* end rxrpc_proc_conns_next() */
-
-/*****************************************************************************/
-/*
- * clean up after reading from the conns list
- */
-static void rxrpc_proc_conns_stop(struct seq_file *p, void *v)
-{
-	up_read(&rxrpc_conns_sem);
-
-} /* end rxrpc_proc_conns_stop() */
-
-/*****************************************************************************/
-/*
- * display a header line followed by a load of conn lines
- */
-static int rxrpc_proc_conns_show(struct seq_file *m, void *v)
-{
-	struct rxrpc_connection *conn;
-	long timeout;
-
-	conn = list_entry(v, struct rxrpc_connection, proc_link);
-
-	/* display header on line 1 */
-	if (v == SEQ_START_TOKEN) {
-		seq_puts(m,
-			 "LOCAL REMOTE   RPORT SRVC CONN     END SERIALNO "
-			 "CALLNO     MTU  TIMEOUT"
-			 "\n");
-		return 0;
-	}
-
-	/* display one conn per line on subsequent lines */
-	timeout = 0;
-	if (!list_empty(&conn->timeout.link))
-		timeout = (long) conn->timeout.timo_jif -
-			(long) jiffies;
-
-	seq_printf(m,
-		   "%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n",
-		   conn->trans->port,
-		   ntohl(conn->addr.sin_addr.s_addr),
-		   ntohs(conn->addr.sin_port),
-		   ntohs(conn->service_id),
-		   ntohl(conn->conn_id),
-		   conn->out_clientflag ? "CLT" : "SRV",
-		   conn->serial_counter,
-		   conn->call_counter,
-		   conn->mtu_size,
-		   timeout
-		   );
-
-	return 0;
-} /* end rxrpc_proc_conns_show() */
-
-/*****************************************************************************/
-/*
- * open "/proc/net/rxrpc/calls" which provides a summary of extant calls
- */
-static int rxrpc_proc_calls_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *m;
-	int ret;
-
-	ret = seq_open(file, &rxrpc_proc_calls_ops);
-	if (ret < 0)
-		return ret;
-
-	m = file->private_data;
-	m->private = PDE(inode)->data;
-
-	return 0;
-} /* end rxrpc_proc_calls_open() */
-
-/*****************************************************************************/
-/*
- * set up the iterator to start reading from the calls list and return the
- * first item
- */
-static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos)
-{
-	struct list_head *_p;
-	loff_t pos = *_pos;
-
-	/* lock the list against modification */
-	down_read(&rxrpc_calls_sem);
-
-	/* allow for the header line */
-	if (!pos)
-		return SEQ_START_TOKEN;
-	pos--;
-
-	/* find the n'th element in the list */
-	list_for_each(_p, &rxrpc_calls)
-		if (!pos--)
-			break;
-
-	return _p != &rxrpc_calls ? _p : NULL;
-} /* end rxrpc_proc_calls_start() */
-
-/*****************************************************************************/
-/*
- * move to next call in calls list
- */
-static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct list_head *_p;
-
-	(*pos)++;
-
-	_p = v;
-	_p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next;
-
-	return _p != &rxrpc_calls ? _p : NULL;
-} /* end rxrpc_proc_calls_next() */
-
-/*****************************************************************************/
-/*
- * clean up after reading from the calls list
- */
-static void rxrpc_proc_calls_stop(struct seq_file *p, void *v)
-{
-	up_read(&rxrpc_calls_sem);
-
-} /* end rxrpc_proc_calls_stop() */
-
-/*****************************************************************************/
-/*
- * display a header line followed by a load of call lines
- */
-static int rxrpc_proc_calls_show(struct seq_file *m, void *v)
-{
-	struct rxrpc_call *call = list_entry(v, struct rxrpc_call, call_link);
-
-	/* display header on line 1 */
-	if (v == SEQ_START_TOKEN) {
-		seq_puts(m,
-			 "LOCAL REMOT SRVC CONN     CALL     DIR USE "
-			 " L STATE   OPCODE ABORT    ERRNO\n"
-			 );
-		return 0;
-	}
-
-	/* display one call per line on subsequent lines */
-	seq_printf(m,
-		   "%5hu %5hu %04hx %08x %08x %s %3u%c"
-		   " %c %-7.7s %6d %08x %5d\n",
-		   call->conn->trans->port,
-		   ntohs(call->conn->addr.sin_port),
-		   ntohs(call->conn->service_id),
-		   ntohl(call->conn->conn_id),
-		   ntohl(call->call_id),
-		   call->conn->service ? "SVC" : "CLT",
-		   atomic_read(&call->usage),
-		   waitqueue_active(&call->waitq) ? 'w' : ' ',
-		   call->app_last_rcv ? 'Y' : '-',
-		   (call->app_call_state!=RXRPC_CSTATE_ERROR ?
-		    rxrpc_call_states7[call->app_call_state] :
-		    rxrpc_call_error_states7[call->app_err_state]),
-		   call->app_opcode,
-		   call->app_abort_code,
-		   call->app_errno
-		   );
-
-	return 0;
-} /* end rxrpc_proc_calls_show() */
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
new file mode 100644
index 0000000..5ec7051
--- /dev/null
+++ b/net/rxrpc/rxkad.c
@@ -0,0 +1,1154 @@
+/* Kerberos-based RxRPC security
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/udp.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/ctype.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#define rxrpc_debug rxkad_debug
+#include "ar-internal.h"
+
+#define RXKAD_VERSION			2
+#define MAXKRB5TICKETLEN		1024
+#define RXKAD_TKT_TYPE_KERBEROS_V5	256
+#define ANAME_SZ			40	/* size of authentication name */
+#define INST_SZ				40	/* size of principal's instance */
+#define REALM_SZ			40	/* size of principal's auth domain */
+#define SNAME_SZ			40	/* size of service name */
+
+unsigned rxrpc_debug;
+module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(rxrpc_debug, "rxkad debugging mask");
+
+struct rxkad_level1_hdr {
+	__be32	data_size;	/* true data size (excluding padding) */
+};
+
+struct rxkad_level2_hdr {
+	__be32	data_size;	/* true data size (excluding padding) */
+	__be32	checksum;	/* decrypted data checksum */
+};
+
+MODULE_DESCRIPTION("RxRPC network protocol type-2 security (Kerberos)");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+/*
+ * this holds a pinned cipher so that keventd doesn't get called by the cipher
+ * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
+ * packets
+ */
+static struct crypto_blkcipher *rxkad_ci;
+static DEFINE_MUTEX(rxkad_ci_mutex);
+
+/*
+ * initialise connection security
+ */
+static int rxkad_init_connection_security(struct rxrpc_connection *conn)
+{
+	struct rxrpc_key_payload *payload;
+	struct crypto_blkcipher *ci;
+	int ret;
+
+	_enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
+
+	payload = conn->key->payload.data;
+	conn->security_ix = payload->k.security_index;
+
+	ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ci)) {
+		_debug("no cipher");
+		ret = PTR_ERR(ci);
+		goto error;
+	}
+
+	if (crypto_blkcipher_setkey(ci, payload->k.session_key,
+				    sizeof(payload->k.session_key)) < 0)
+		BUG();
+
+	switch (conn->security_level) {
+	case RXRPC_SECURITY_PLAIN:
+		break;
+	case RXRPC_SECURITY_AUTH:
+		conn->size_align = 8;
+		conn->security_size = sizeof(struct rxkad_level1_hdr);
+		conn->header_size += sizeof(struct rxkad_level1_hdr);
+		break;
+	case RXRPC_SECURITY_ENCRYPT:
+		conn->size_align = 8;
+		conn->security_size = sizeof(struct rxkad_level2_hdr);
+		conn->header_size += sizeof(struct rxkad_level2_hdr);
+		break;
+	default:
+		ret = -EKEYREJECTED;
+		goto error;
+	}
+
+	conn->cipher = ci;
+	ret = 0;
+error:
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * prime the encryption state with the invariant parts of a connection's
+ * description
+ */
+static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
+{
+	struct rxrpc_key_payload *payload;
+	struct blkcipher_desc desc;
+	struct scatterlist sg[2];
+	struct rxrpc_crypt iv;
+	struct {
+		__be32 x[4];
+	} tmpbuf __attribute__((aligned(16))); /* must all be in same page */
+
+	_enter("");
+
+	if (!conn->key)
+		return;
+
+	payload = conn->key->payload.data;
+	memcpy(&iv, payload->k.session_key, sizeof(iv));
+
+	desc.tfm = conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	tmpbuf.x[0] = conn->epoch;
+	tmpbuf.x[1] = conn->cid;
+	tmpbuf.x[2] = 0;
+	tmpbuf.x[3] = htonl(conn->security_ix);
+
+	memset(sg, 0, sizeof(sg));
+	sg_set_buf(&sg[0], &tmpbuf, sizeof(tmpbuf));
+	sg_set_buf(&sg[1], &tmpbuf, sizeof(tmpbuf));
+	crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
+
+	memcpy(&conn->csum_iv, &tmpbuf.x[2], sizeof(conn->csum_iv));
+	ASSERTCMP(conn->csum_iv.n[0], ==, tmpbuf.x[2]);
+
+	_leave("");
+}
+
+/*
+ * partially encrypt a packet (level 1 security)
+ */
+static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
+				    struct sk_buff *skb,
+				    u32 data_size,
+				    void *sechdr)
+{
+	struct rxrpc_skb_priv *sp;
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist sg[2];
+	struct {
+		struct rxkad_level1_hdr hdr;
+		__be32	first;	/* first four bytes of data and padding */
+	} tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+	u16 check;
+
+	sp = rxrpc_skb(skb);
+
+	_enter("");
+
+	check = ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+	data_size |= (u32) check << 16;
+
+	tmpbuf.hdr.data_size = htonl(data_size);
+	memcpy(&tmpbuf.first, sechdr + 4, sizeof(tmpbuf.first));
+
+	/* start the encryption afresh */
+	memset(&iv, 0, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	memset(sg, 0, sizeof(sg));
+	sg_set_buf(&sg[0], &tmpbuf, sizeof(tmpbuf));
+	sg_set_buf(&sg[1], &tmpbuf, sizeof(tmpbuf));
+	crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
+
+	memcpy(sechdr, &tmpbuf, sizeof(tmpbuf));
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * wholly encrypt a packet (level 2 security)
+ */
+static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
+					struct sk_buff *skb,
+					u32 data_size,
+					void *sechdr)
+{
+	const struct rxrpc_key_payload *payload;
+	struct rxkad_level2_hdr rxkhdr
+		__attribute__((aligned(8))); /* must be all on one page */
+	struct rxrpc_skb_priv *sp;
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist sg[16];
+	struct sk_buff *trailer;
+	unsigned len;
+	u16 check;
+	int nsg;
+
+	sp = rxrpc_skb(skb);
+
+	_enter("");
+
+	check = ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+
+	rxkhdr.data_size = htonl(data_size | (u32) check << 16);
+	rxkhdr.checksum = 0;
+
+	/* encrypt from the session key */
+	payload = call->conn->key->payload.data;
+	memcpy(&iv, payload->k.session_key, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	memset(sg, 0, sizeof(sg[0]) * 2);
+	sg_set_buf(&sg[0], sechdr, sizeof(rxkhdr));
+	sg_set_buf(&sg[1], &rxkhdr, sizeof(rxkhdr));
+	crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(rxkhdr));
+
+	/* we want to encrypt the skbuff in-place */
+	nsg = skb_cow_data(skb, 0, &trailer);
+	if (nsg < 0 || nsg > 16)
+		return -ENOMEM;
+
+	len = data_size + call->conn->size_align - 1;
+	len &= ~(call->conn->size_align - 1);
+
+	skb_to_sgvec(skb, sg, 0, len);
+	crypto_blkcipher_encrypt_iv(&desc, sg, sg, len);
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * checksum an RxRPC packet header
+ */
+static int rxkad_secure_packet(const struct rxrpc_call *call,
+				struct sk_buff *skb,
+				size_t data_size,
+				void *sechdr)
+{
+	struct rxrpc_skb_priv *sp;
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist sg[2];
+	struct {
+		__be32 x[2];
+	} tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+	__be32 x;
+	int ret;
+
+	sp = rxrpc_skb(skb);
+
+	_enter("{%d{%x}},{#%u},%zu,",
+	       call->debug_id, key_serial(call->conn->key), ntohl(sp->hdr.seq),
+	       data_size);
+
+	if (!call->conn->cipher)
+		return 0;
+
+	ret = key_validate(call->conn->key);
+	if (ret < 0)
+		return ret;
+
+	/* continue encrypting from where we left off */
+	memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	/* calculate the security checksum */
+	x = htonl(call->channel << (32 - RXRPC_CIDSHIFT));
+	x |= sp->hdr.seq & __constant_cpu_to_be32(0x3fffffff);
+	tmpbuf.x[0] = sp->hdr.callNumber;
+	tmpbuf.x[1] = x;
+
+	memset(&sg, 0, sizeof(sg));
+	sg_set_buf(&sg[0], &tmpbuf, sizeof(tmpbuf));
+	sg_set_buf(&sg[1], &tmpbuf, sizeof(tmpbuf));
+	crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
+
+	x = ntohl(tmpbuf.x[1]);
+	x = (x >> 16) & 0xffff;
+	if (x == 0)
+		x = 1; /* zero checksums are not permitted */
+	sp->hdr.cksum = htons(x);
+
+	switch (call->conn->security_level) {
+	case RXRPC_SECURITY_PLAIN:
+		ret = 0;
+		break;
+	case RXRPC_SECURITY_AUTH:
+		ret = rxkad_secure_packet_auth(call, skb, data_size, sechdr);
+		break;
+	case RXRPC_SECURITY_ENCRYPT:
+		ret = rxkad_secure_packet_encrypt(call, skb, data_size,
+						  sechdr);
+		break;
+	default:
+		ret = -EPERM;
+		break;
+	}
+
+	_leave(" = %d [set %hx]", ret, x);
+	return ret;
+}
+
+/*
+ * decrypt partial encryption on a packet (level 1 security)
+ */
+static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
+				    struct sk_buff *skb,
+				    u32 *_abort_code)
+{
+	struct rxkad_level1_hdr sechdr;
+	struct rxrpc_skb_priv *sp;
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist sg[2];
+	struct sk_buff *trailer;
+	u32 data_size, buf;
+	u16 check;
+
+	_enter("");
+
+	sp = rxrpc_skb(skb);
+
+	/* we want to decrypt the skbuff in-place */
+	if (skb_cow_data(skb, 0, &trailer) < 0)
+		goto nomem;
+
+	skb_to_sgvec(skb, sg, 0, 8);
+
+	/* start the decryption afresh */
+	memset(&iv, 0, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	crypto_blkcipher_decrypt_iv(&desc, sg, sg, 8);
+
+	/* remove the decrypted packet length */
+	if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0)
+		goto datalen_error;
+	if (!skb_pull(skb, sizeof(sechdr)))
+		BUG();
+
+	buf = ntohl(sechdr.data_size);
+	data_size = buf & 0xffff;
+
+	check = buf >> 16;
+	check ^= ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+	check &= 0xffff;
+	if (check != 0) {
+		*_abort_code = RXKADSEALEDINCON;
+		goto protocol_error;
+	}
+
+	/* shorten the packet to remove the padding */
+	if (data_size > skb->len)
+		goto datalen_error;
+	else if (data_size < skb->len)
+		skb->len = data_size;
+
+	_leave(" = 0 [dlen=%x]", data_size);
+	return 0;
+
+datalen_error:
+	*_abort_code = RXKADDATALEN;
+protocol_error:
+	_leave(" = -EPROTO");
+	return -EPROTO;
+
+nomem:
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+}
+
+/*
+ * wholly decrypt a packet (level 2 security)
+ */
+static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
+				       struct sk_buff *skb,
+				       u32 *_abort_code)
+{
+	const struct rxrpc_key_payload *payload;
+	struct rxkad_level2_hdr sechdr;
+	struct rxrpc_skb_priv *sp;
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist _sg[4], *sg;
+	struct sk_buff *trailer;
+	u32 data_size, buf;
+	u16 check;
+	int nsg;
+
+	_enter(",{%d}", skb->len);
+
+	sp = rxrpc_skb(skb);
+
+	/* we want to decrypt the skbuff in-place */
+	nsg = skb_cow_data(skb, 0, &trailer);
+	if (nsg < 0)
+		goto nomem;
+
+	sg = _sg;
+	if (unlikely(nsg > 4)) {
+		sg = kmalloc(sizeof(*sg) * nsg, GFP_NOIO);
+		if (!sg)
+			goto nomem;
+	}
+
+	skb_to_sgvec(skb, sg, 0, skb->len);
+
+	/* decrypt from the session key */
+	payload = call->conn->key->payload.data;
+	memcpy(&iv, payload->k.session_key, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	crypto_blkcipher_decrypt_iv(&desc, sg, sg, skb->len);
+	if (sg != _sg)
+		kfree(sg);
+
+	/* remove the decrypted packet length */
+	if (skb_copy_bits(skb, 0, &sechdr, sizeof(sechdr)) < 0)
+		goto datalen_error;
+	if (!skb_pull(skb, sizeof(sechdr)))
+		BUG();
+
+	buf = ntohl(sechdr.data_size);
+	data_size = buf & 0xffff;
+
+	check = buf >> 16;
+	check ^= ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+	check &= 0xffff;
+	if (check != 0) {
+		*_abort_code = RXKADSEALEDINCON;
+		goto protocol_error;
+	}
+
+	/* shorten the packet to remove the padding */
+	if (data_size > skb->len)
+		goto datalen_error;
+	else if (data_size < skb->len)
+		skb->len = data_size;
+
+	_leave(" = 0 [dlen=%x]", data_size);
+	return 0;
+
+datalen_error:
+	*_abort_code = RXKADDATALEN;
+protocol_error:
+	_leave(" = -EPROTO");
+	return -EPROTO;
+
+nomem:
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+}
+
+/*
+ * verify the security on a received packet
+ */
+static int rxkad_verify_packet(const struct rxrpc_call *call,
+			       struct sk_buff *skb,
+			       u32 *_abort_code)
+{
+	struct blkcipher_desc desc;
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_crypt iv;
+	struct scatterlist sg[2];
+	struct {
+		__be32 x[2];
+	} tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+	__be32 x;
+	__be16 cksum;
+	int ret;
+
+	sp = rxrpc_skb(skb);
+
+	_enter("{%d{%x}},{#%u}",
+	       call->debug_id, key_serial(call->conn->key),
+	       ntohl(sp->hdr.seq));
+
+	if (!call->conn->cipher)
+		return 0;
+
+	if (sp->hdr.securityIndex != 2) {
+		*_abort_code = RXKADINCONSISTENCY;
+		_leave(" = -EPROTO [not rxkad]");
+		return -EPROTO;
+	}
+
+	/* continue encrypting from where we left off */
+	memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
+	desc.tfm = call->conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	/* validate the security checksum */
+	x = htonl(call->channel << (32 - RXRPC_CIDSHIFT));
+	x |= sp->hdr.seq & __constant_cpu_to_be32(0x3fffffff);
+	tmpbuf.x[0] = call->call_id;
+	tmpbuf.x[1] = x;
+
+	memset(&sg, 0, sizeof(sg));
+	sg_set_buf(&sg[0], &tmpbuf, sizeof(tmpbuf));
+	sg_set_buf(&sg[1], &tmpbuf, sizeof(tmpbuf));
+	crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
+
+	x = ntohl(tmpbuf.x[1]);
+	x = (x >> 16) & 0xffff;
+	if (x == 0)
+		x = 1; /* zero checksums are not permitted */
+
+	cksum = htons(x);
+	if (sp->hdr.cksum != cksum) {
+		*_abort_code = RXKADSEALEDINCON;
+		_leave(" = -EPROTO [csum failed]");
+		return -EPROTO;
+	}
+
+	switch (call->conn->security_level) {
+	case RXRPC_SECURITY_PLAIN:
+		ret = 0;
+		break;
+	case RXRPC_SECURITY_AUTH:
+		ret = rxkad_verify_packet_auth(call, skb, _abort_code);
+		break;
+	case RXRPC_SECURITY_ENCRYPT:
+		ret = rxkad_verify_packet_encrypt(call, skb, _abort_code);
+		break;
+	default:
+		ret = -ENOANO;
+		break;
+	}
+
+	_leave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * issue a challenge
+ */
+static int rxkad_issue_challenge(struct rxrpc_connection *conn)
+{
+	struct rxkad_challenge challenge;
+	struct rxrpc_header hdr;
+	struct msghdr msg;
+	struct kvec iov[2];
+	size_t len;
+	int ret;
+
+	_enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
+
+	ret = key_validate(conn->key);
+	if (ret < 0)
+		return ret;
+
+	get_random_bytes(&conn->security_nonce, sizeof(conn->security_nonce));
+
+	challenge.version	= htonl(2);
+	challenge.nonce		= htonl(conn->security_nonce);
+	challenge.min_level	= htonl(0);
+	challenge.__padding	= 0;
+
+	msg.msg_name	= &conn->trans->peer->srx.transport.sin;
+	msg.msg_namelen	= sizeof(conn->trans->peer->srx.transport.sin);
+	msg.msg_control	= NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags	= 0;
+
+	hdr.epoch	= conn->epoch;
+	hdr.cid		= conn->cid;
+	hdr.callNumber	= 0;
+	hdr.seq		= 0;
+	hdr.type	= RXRPC_PACKET_TYPE_CHALLENGE;
+	hdr.flags	= conn->out_clientflag;
+	hdr.userStatus	= 0;
+	hdr.securityIndex = conn->security_ix;
+	hdr._rsvd	= 0;
+	hdr.serviceId	= conn->service_id;
+
+	iov[0].iov_base	= &hdr;
+	iov[0].iov_len	= sizeof(hdr);
+	iov[1].iov_base	= &challenge;
+	iov[1].iov_len	= sizeof(challenge);
+
+	len = iov[0].iov_len + iov[1].iov_len;
+
+	hdr.serial = htonl(atomic_inc_return(&conn->serial));
+	_proto("Tx CHALLENGE %%%u", ntohl(hdr.serial));
+
+	ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 2, len);
+	if (ret < 0) {
+		_debug("sendmsg failed: %d", ret);
+		return -EAGAIN;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * send a Kerberos security response
+ */
+static int rxkad_send_response(struct rxrpc_connection *conn,
+			       struct rxrpc_header *hdr,
+			       struct rxkad_response *resp,
+			       const struct rxkad_key *s2)
+{
+	struct msghdr msg;
+	struct kvec iov[3];
+	size_t len;
+	int ret;
+
+	_enter("");
+
+	msg.msg_name	= &conn->trans->peer->srx.transport.sin;
+	msg.msg_namelen	= sizeof(conn->trans->peer->srx.transport.sin);
+	msg.msg_control	= NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags	= 0;
+
+	hdr->epoch	= conn->epoch;
+	hdr->seq	= 0;
+	hdr->type	= RXRPC_PACKET_TYPE_RESPONSE;
+	hdr->flags	= conn->out_clientflag;
+	hdr->userStatus	= 0;
+	hdr->_rsvd	= 0;
+
+	iov[0].iov_base	= hdr;
+	iov[0].iov_len	= sizeof(*hdr);
+	iov[1].iov_base	= resp;
+	iov[1].iov_len	= sizeof(*resp);
+	iov[2].iov_base	= (void *) s2->ticket;
+	iov[2].iov_len	= s2->ticket_len;
+
+	len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
+
+	hdr->serial = htonl(atomic_inc_return(&conn->serial));
+	_proto("Tx RESPONSE %%%u", ntohl(hdr->serial));
+
+	ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 3, len);
+	if (ret < 0) {
+		_debug("sendmsg failed: %d", ret);
+		return -EAGAIN;
+	}
+
+	_leave(" = 0");
+	return 0;
+}
+
+/*
+ * calculate the response checksum
+ */
+static void rxkad_calc_response_checksum(struct rxkad_response *response)
+{
+	u32 csum = 1000003;
+	int loop;
+	u8 *p = (u8 *) response;
+
+	for (loop = sizeof(*response); loop > 0; loop--)
+		csum = csum * 0x10204081 + *p++;
+
+	response->encrypted.checksum = htonl(csum);
+}
+
+/*
+ * load a scatterlist with a potentially split-page buffer
+ */
+static void rxkad_sg_set_buf2(struct scatterlist sg[2],
+			      void *buf, size_t buflen)
+{
+
+	memset(sg, 0, sizeof(sg));
+
+	sg_set_buf(&sg[0], buf, buflen);
+	if (sg[0].offset + buflen > PAGE_SIZE) {
+		/* the buffer was split over two pages */
+		sg[0].length = PAGE_SIZE - sg[0].offset;
+		sg_set_buf(&sg[1], buf + sg[0].length, buflen - sg[0].length);
+	}
+
+	ASSERTCMP(sg[0].length + sg[1].length, ==, buflen);
+}
+
+/*
+ * encrypt the response packet
+ */
+static void rxkad_encrypt_response(struct rxrpc_connection *conn,
+				   struct rxkad_response *resp,
+				   const struct rxkad_key *s2)
+{
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv;
+	struct scatterlist ssg[2], dsg[2];
+
+	/* continue encrypting from where we left off */
+	memcpy(&iv, s2->session_key, sizeof(iv));
+	desc.tfm = conn->cipher;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	rxkad_sg_set_buf2(ssg, &resp->encrypted, sizeof(resp->encrypted));
+	memcpy(dsg, ssg, sizeof(dsg));
+	crypto_blkcipher_encrypt_iv(&desc, dsg, ssg, sizeof(resp->encrypted));
+}
+
+/*
+ * respond to a challenge packet
+ */
+static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
+				      struct sk_buff *skb,
+				      u32 *_abort_code)
+{
+	const struct rxrpc_key_payload *payload;
+	struct rxkad_challenge challenge;
+	struct rxkad_response resp
+		__attribute__((aligned(8))); /* must be aligned for crypto */
+	struct rxrpc_skb_priv *sp;
+	u32 version, nonce, min_level, abort_code;
+	int ret;
+
+	_enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
+
+	if (!conn->key) {
+		_leave(" = -EPROTO [no key]");
+		return -EPROTO;
+	}
+
+	ret = key_validate(conn->key);
+	if (ret < 0) {
+		*_abort_code = RXKADEXPIRED;
+		return ret;
+	}
+
+	abort_code = RXKADPACKETSHORT;
+	sp = rxrpc_skb(skb);
+	if (skb_copy_bits(skb, 0, &challenge, sizeof(challenge)) < 0)
+		goto protocol_error;
+
+	version = ntohl(challenge.version);
+	nonce = ntohl(challenge.nonce);
+	min_level = ntohl(challenge.min_level);
+
+	_proto("Rx CHALLENGE %%%u { v=%u n=%u ml=%u }",
+	       ntohl(sp->hdr.serial), version, nonce, min_level);
+
+	abort_code = RXKADINCONSISTENCY;
+	if (version != RXKAD_VERSION)
+		goto protocol_error;
+
+	abort_code = RXKADLEVELFAIL;
+	if (conn->security_level < min_level)
+		goto protocol_error;
+
+	payload = conn->key->payload.data;
+
+	/* build the response packet */
+	memset(&resp, 0, sizeof(resp));
+
+	resp.version = RXKAD_VERSION;
+	resp.encrypted.epoch = conn->epoch;
+	resp.encrypted.cid = conn->cid;
+	resp.encrypted.securityIndex = htonl(conn->security_ix);
+	resp.encrypted.call_id[0] =
+		(conn->channels[0] ? conn->channels[0]->call_id : 0);
+	resp.encrypted.call_id[1] =
+		(conn->channels[1] ? conn->channels[1]->call_id : 0);
+	resp.encrypted.call_id[2] =
+		(conn->channels[2] ? conn->channels[2]->call_id : 0);
+	resp.encrypted.call_id[3] =
+		(conn->channels[3] ? conn->channels[3]->call_id : 0);
+	resp.encrypted.inc_nonce = htonl(nonce + 1);
+	resp.encrypted.level = htonl(conn->security_level);
+	resp.kvno = htonl(payload->k.kvno);
+	resp.ticket_len = htonl(payload->k.ticket_len);
+
+	/* calculate the response checksum and then do the encryption */
+	rxkad_calc_response_checksum(&resp);
+	rxkad_encrypt_response(conn, &resp, &payload->k);
+	return rxkad_send_response(conn, &sp->hdr, &resp, &payload->k);
+
+protocol_error:
+	*_abort_code = abort_code;
+	_leave(" = -EPROTO [%d]", abort_code);
+	return -EPROTO;
+}
+
+/*
+ * decrypt the kerberos IV ticket in the response
+ */
+static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
+				void *ticket, size_t ticket_len,
+				struct rxrpc_crypt *_session_key,
+				time_t *_expiry,
+				u32 *_abort_code)
+{
+	struct blkcipher_desc desc;
+	struct rxrpc_crypt iv, key;
+	struct scatterlist ssg[1], dsg[1];
+	struct in_addr addr;
+	unsigned life;
+	time_t issue, now;
+	bool little_endian;
+	int ret;
+	u8 *p, *q, *name, *end;
+
+	_enter("{%d},{%x}", conn->debug_id, key_serial(conn->server_key));
+
+	*_expiry = 0;
+
+	ret = key_validate(conn->server_key);
+	if (ret < 0) {
+		switch (ret) {
+		case -EKEYEXPIRED:
+			*_abort_code = RXKADEXPIRED;
+			goto error;
+		default:
+			*_abort_code = RXKADNOAUTH;
+			goto error;
+		}
+	}
+
+	ASSERT(conn->server_key->payload.data != NULL);
+	ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
+
+	memcpy(&iv, &conn->server_key->type_data, sizeof(iv));
+
+	desc.tfm = conn->server_key->payload.data;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	sg_init_one(&ssg[0], ticket, ticket_len);
+	memcpy(dsg, ssg, sizeof(dsg));
+	crypto_blkcipher_decrypt_iv(&desc, dsg, ssg, ticket_len);
+
+	p = ticket;
+	end = p + ticket_len;
+
+#define Z(size)						\
+	({						\
+		u8 *__str = p;				\
+		q = memchr(p, 0, end - p);		\
+		if (!q || q - p > (size))		\
+			goto bad_ticket;		\
+		for (; p < q; p++)			\
+			if (!isprint(*p))		\
+				goto bad_ticket;	\
+		p++;					\
+		__str;					\
+	})
+
+	/* extract the ticket flags */
+	_debug("KIV FLAGS: %x", *p);
+	little_endian = *p & 1;
+	p++;
+
+	/* extract the authentication name */
+	name = Z(ANAME_SZ);
+	_debug("KIV ANAME: %s", name);
+
+	/* extract the principal's instance */
+	name = Z(INST_SZ);
+	_debug("KIV INST : %s", name);
+
+	/* extract the principal's authentication domain */
+	name = Z(REALM_SZ);
+	_debug("KIV REALM: %s", name);
+
+	if (end - p < 4 + 8 + 4 + 2)
+		goto bad_ticket;
+
+	/* get the IPv4 address of the entity that requested the ticket */
+	memcpy(&addr, p, sizeof(addr));
+	p += 4;
+	_debug("KIV ADDR : "NIPQUAD_FMT, NIPQUAD(addr));
+
+	/* get the session key from the ticket */
+	memcpy(&key, p, sizeof(key));
+	p += 8;
+	_debug("KIV KEY  : %08x %08x", ntohl(key.n[0]), ntohl(key.n[1]));
+	memcpy(_session_key, &key, sizeof(key));
+
+	/* get the ticket's lifetime */
+	life = *p++ * 5 * 60;
+	_debug("KIV LIFE : %u", life);
+
+	/* get the issue time of the ticket */
+	if (little_endian) {
+		__le32 stamp;
+		memcpy(&stamp, p, 4);
+		issue = le32_to_cpu(stamp);
+	} else {
+		__be32 stamp;
+		memcpy(&stamp, p, 4);
+		issue = be32_to_cpu(stamp);
+	}
+	p += 4;
+	now = xtime.tv_sec;
+	_debug("KIV ISSUE: %lx [%lx]", issue, now);
+
+	/* check the ticket is in date */
+	if (issue > now) {
+		*_abort_code = RXKADNOAUTH;
+		ret = -EKEYREJECTED;
+		goto error;
+	}
+
+	if (issue < now - life) {
+		*_abort_code = RXKADEXPIRED;
+		ret = -EKEYEXPIRED;
+		goto error;
+	}
+
+	*_expiry = issue + life;
+
+	/* get the service name */
+	name = Z(SNAME_SZ);
+	_debug("KIV SNAME: %s", name);
+
+	/* get the service instance name */
+	name = Z(INST_SZ);
+	_debug("KIV SINST: %s", name);
+
+	ret = 0;
+error:
+	_leave(" = %d", ret);
+	return ret;
+
+bad_ticket:
+	*_abort_code = RXKADBADTICKET;
+	ret = -EBADMSG;
+	goto error;
+}
+
+/*
+ * decrypt the response packet
+ */
+static void rxkad_decrypt_response(struct rxrpc_connection *conn,
+				   struct rxkad_response *resp,
+				   const struct rxrpc_crypt *session_key)
+{
+	struct blkcipher_desc desc;
+	struct scatterlist ssg[2], dsg[2];
+	struct rxrpc_crypt iv;
+
+	_enter(",,%08x%08x",
+	       ntohl(session_key->n[0]), ntohl(session_key->n[1]));
+
+	ASSERT(rxkad_ci != NULL);
+
+	mutex_lock(&rxkad_ci_mutex);
+	if (crypto_blkcipher_setkey(rxkad_ci, session_key->x,
+				    sizeof(*session_key)) < 0)
+		BUG();
+
+	memcpy(&iv, session_key, sizeof(iv));
+	desc.tfm = rxkad_ci;
+	desc.info = iv.x;
+	desc.flags = 0;
+
+	rxkad_sg_set_buf2(ssg, &resp->encrypted, sizeof(resp->encrypted));
+	memcpy(dsg, ssg, sizeof(dsg));
+	crypto_blkcipher_decrypt_iv(&desc, dsg, ssg, sizeof(resp->encrypted));
+	mutex_unlock(&rxkad_ci_mutex);
+
+	_leave("");
+}
+
+/*
+ * verify a response
+ */
+static int rxkad_verify_response(struct rxrpc_connection *conn,
+				 struct sk_buff *skb,
+				 u32 *_abort_code)
+{
+	struct rxkad_response response
+		__attribute__((aligned(8))); /* must be aligned for crypto */
+	struct rxrpc_skb_priv *sp;
+	struct rxrpc_crypt session_key;
+	time_t expiry;
+	void *ticket;
+	u32 abort_code, version, kvno, ticket_len, csum, level;
+	int ret;
+
+	_enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
+
+	abort_code = RXKADPACKETSHORT;
+	if (skb_copy_bits(skb, 0, &response, sizeof(response)) < 0)
+		goto protocol_error;
+	if (!pskb_pull(skb, sizeof(response)))
+		BUG();
+
+	version = ntohl(response.version);
+	ticket_len = ntohl(response.ticket_len);
+	kvno = ntohl(response.kvno);
+	sp = rxrpc_skb(skb);
+	_proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }",
+	       ntohl(sp->hdr.serial), version, kvno, ticket_len);
+
+	abort_code = RXKADINCONSISTENCY;
+	if (version != RXKAD_VERSION)
+
+	abort_code = RXKADTICKETLEN;
+	if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN)
+		goto protocol_error;
+
+	abort_code = RXKADUNKNOWNKEY;
+	if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5)
+		goto protocol_error;
+
+	/* extract the kerberos ticket and decrypt and decode it */
+	ticket = kmalloc(ticket_len, GFP_NOFS);
+	if (!ticket)
+		return -ENOMEM;
+
+	abort_code = RXKADPACKETSHORT;
+	if (skb_copy_bits(skb, 0, ticket, ticket_len) < 0)
+		goto protocol_error_free;
+
+	ret = rxkad_decrypt_ticket(conn, ticket, ticket_len, &session_key,
+				   &expiry, &abort_code);
+	if (ret < 0) {
+		*_abort_code = abort_code;
+		kfree(ticket);
+		return ret;
+	}
+
+	/* use the session key from inside the ticket to decrypt the
+	 * response */
+	rxkad_decrypt_response(conn, &response, &session_key);
+
+	abort_code = RXKADSEALEDINCON;
+	if (response.encrypted.epoch != conn->epoch)
+		goto protocol_error_free;
+	if (response.encrypted.cid != conn->cid)
+		goto protocol_error_free;
+	if (ntohl(response.encrypted.securityIndex) != conn->security_ix)
+		goto protocol_error_free;
+	csum = response.encrypted.checksum;
+	response.encrypted.checksum = 0;
+	rxkad_calc_response_checksum(&response);
+	if (response.encrypted.checksum != csum)
+		goto protocol_error_free;
+
+	if (ntohl(response.encrypted.call_id[0]) > INT_MAX ||
+	    ntohl(response.encrypted.call_id[1]) > INT_MAX ||
+	    ntohl(response.encrypted.call_id[2]) > INT_MAX ||
+	    ntohl(response.encrypted.call_id[3]) > INT_MAX)
+		goto protocol_error_free;
+
+	abort_code = RXKADOUTOFSEQUENCE;
+	if (response.encrypted.inc_nonce != htonl(conn->security_nonce + 1))
+		goto protocol_error_free;
+
+	abort_code = RXKADLEVELFAIL;
+	level = ntohl(response.encrypted.level);
+	if (level > RXRPC_SECURITY_ENCRYPT)
+		goto protocol_error_free;
+	conn->security_level = level;
+
+	/* create a key to hold the security data and expiration time - after
+	 * this the connection security can be handled in exactly the same way
+	 * as for a client connection */
+	ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
+	if (ret < 0) {
+		kfree(ticket);
+		return ret;
+	}
+
+	kfree(ticket);
+	_leave(" = 0");
+	return 0;
+
+protocol_error_free:
+	kfree(ticket);
+protocol_error:
+	*_abort_code = abort_code;
+	_leave(" = -EPROTO [%d]", abort_code);
+	return -EPROTO;
+}
+
+/*
+ * clear the connection security
+ */
+static void rxkad_clear(struct rxrpc_connection *conn)
+{
+	_enter("");
+
+	if (conn->cipher)
+		crypto_free_blkcipher(conn->cipher);
+}
+
+/*
+ * RxRPC Kerberos-based security
+ */
+static struct rxrpc_security rxkad = {
+	.owner				= THIS_MODULE,
+	.name				= "rxkad",
+	.security_index			= RXKAD_VERSION,
+	.init_connection_security	= rxkad_init_connection_security,
+	.prime_packet_security		= rxkad_prime_packet_security,
+	.secure_packet			= rxkad_secure_packet,
+	.verify_packet			= rxkad_verify_packet,
+	.issue_challenge		= rxkad_issue_challenge,
+	.respond_to_challenge		= rxkad_respond_to_challenge,
+	.verify_response		= rxkad_verify_response,
+	.clear				= rxkad_clear,
+};
+
+static __init int rxkad_init(void)
+{
+	_enter("");
+
+	/* pin the cipher we need so that the crypto layer doesn't invoke
+	 * keventd to go get it */
+	rxkad_ci = crypto_alloc_blkcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(rxkad_ci))
+		return PTR_ERR(rxkad_ci);
+
+	return rxrpc_register_security(&rxkad);
+}
+
+module_init(rxkad_init);
+
+static __exit void rxkad_exit(void)
+{
+	_enter("");
+
+	rxrpc_unregister_security(&rxkad);
+	crypto_free_blkcipher(rxkad_ci);
+}
+
+module_exit(rxkad_exit);
diff --git a/net/rxrpc/rxrpc_syms.c b/net/rxrpc/rxrpc_syms.c
deleted file mode 100644
index 9896fd8..0000000
--- a/net/rxrpc/rxrpc_syms.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* rxrpc_syms.c: exported Rx RPC layer interface symbols
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-
-#include <rxrpc/transport.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/krxiod.h>
-
-/* call.c */
-EXPORT_SYMBOL(rxrpc_create_call);
-EXPORT_SYMBOL(rxrpc_put_call);
-EXPORT_SYMBOL(rxrpc_call_abort);
-EXPORT_SYMBOL(rxrpc_call_read_data);
-EXPORT_SYMBOL(rxrpc_call_write_data);
-
-/* connection.c */
-EXPORT_SYMBOL(rxrpc_create_connection);
-EXPORT_SYMBOL(rxrpc_put_connection);
-
-/* transport.c */
-EXPORT_SYMBOL(rxrpc_create_transport);
-EXPORT_SYMBOL(rxrpc_put_transport);
-EXPORT_SYMBOL(rxrpc_add_service);
-EXPORT_SYMBOL(rxrpc_del_service);
diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c
deleted file mode 100644
index 8842907..0000000
--- a/net/rxrpc/sysctl.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* sysctl.c: Rx RPC control
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/sysctl.h>
-#include <rxrpc/types.h>
-#include <rxrpc/rxrpc.h>
-#include <asm/errno.h>
-#include "internal.h"
-
-int rxrpc_ktrace;
-int rxrpc_kdebug;
-int rxrpc_kproto;
-int rxrpc_knet;
-
-#ifdef CONFIG_SYSCTL
-static struct ctl_table_header *rxrpc_sysctl = NULL;
-
-static ctl_table rxrpc_sysctl_table[] = {
-	{
-		.ctl_name	= 1,
-		.procname	= "kdebug",
-		.data		= &rxrpc_kdebug,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= 2,
-		.procname	= "ktrace",
-		.data		= &rxrpc_ktrace,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= 3,
-		.procname	= "kproto",
-		.data		= &rxrpc_kproto,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= 4,
-		.procname	= "knet",
-		.data		= &rxrpc_knet,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= 5,
-		.procname	= "peertimo",
-		.data		= &rxrpc_peer_timeout,
-		.maxlen		= sizeof(unsigned long),
-		.mode		= 0644,
-		.proc_handler	= &proc_doulongvec_minmax
-	},
-	{
-		.ctl_name	= 6,
-		.procname	= "conntimo",
-		.data		= &rxrpc_conn_timeout,
-		.maxlen		= sizeof(unsigned long),
-		.mode		= 0644,
-		.proc_handler	= &proc_doulongvec_minmax
-	},
-	{ .ctl_name = 0 }
-};
-
-static ctl_table rxrpc_dir_sysctl_table[] = {
-	{
-		.ctl_name	= 1,
-		.procname	= "rxrpc",
-		.maxlen		= 0,
-		.mode		= 0555,
-		.child		= rxrpc_sysctl_table
-	},
-	{ .ctl_name = 0 }
-};
-#endif /* CONFIG_SYSCTL */
-
-/*****************************************************************************/
-/*
- * initialise the sysctl stuff for Rx RPC
- */
-int rxrpc_sysctl_init(void)
-{
-#ifdef CONFIG_SYSCTL
-	rxrpc_sysctl = register_sysctl_table(rxrpc_dir_sysctl_table);
-	if (!rxrpc_sysctl)
-		return -ENOMEM;
-#endif /* CONFIG_SYSCTL */
-
-	return 0;
-} /* end rxrpc_sysctl_init() */
-
-/*****************************************************************************/
-/*
- * clean up the sysctl stuff for Rx RPC
- */
-void rxrpc_sysctl_cleanup(void)
-{
-#ifdef CONFIG_SYSCTL
-	if (rxrpc_sysctl) {
-		unregister_sysctl_table(rxrpc_sysctl);
-		rxrpc_sysctl = NULL;
-	}
-#endif /* CONFIG_SYSCTL */
-
-} /* end rxrpc_sysctl_cleanup() */
diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c
deleted file mode 100644
index 8e57be2..0000000
--- a/net/rxrpc/transport.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/* transport.c: Rx Transport routines
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <rxrpc/transport.h>
-#include <rxrpc/peer.h>
-#include <rxrpc/connection.h>
-#include <rxrpc/call.h>
-#include <rxrpc/message.h>
-#include <rxrpc/krxiod.h>
-#include <rxrpc/krxsecd.h>
-#include <linux/udp.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/icmp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/ip.h>
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-#include <linux/ipv6.h>	/* this should _really_ be in errqueue.h.. */
-#endif
-#include <linux/errqueue.h>
-#include <asm/uaccess.h>
-#include "internal.h"
-
-struct errormsg {
-	struct cmsghdr			cmsg;		/* control message header */
-	struct sock_extended_err	ee;		/* extended error information */
-	struct sockaddr_in		icmp_src;	/* ICMP packet source address */
-};
-
-static DEFINE_SPINLOCK(rxrpc_transports_lock);
-static struct list_head rxrpc_transports = LIST_HEAD_INIT(rxrpc_transports);
-
-__RXACCT_DECL(atomic_t rxrpc_transport_count);
-LIST_HEAD(rxrpc_proc_transports);
-DECLARE_RWSEM(rxrpc_proc_transports_sem);
-
-static void rxrpc_data_ready(struct sock *sk, int count);
-static void rxrpc_error_report(struct sock *sk);
-static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans,
-					struct list_head *msgq);
-static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans);
-
-/*****************************************************************************/
-/*
- * create a new transport endpoint using the specified UDP port
- */
-int rxrpc_create_transport(unsigned short port,
-			   struct rxrpc_transport **_trans)
-{
-	struct rxrpc_transport *trans;
-	struct sockaddr_in sin;
-	mm_segment_t oldfs;
-	struct sock *sock;
-	int ret, opt;
-
-	_enter("%hu", port);
-
-	trans = kzalloc(sizeof(struct rxrpc_transport), GFP_KERNEL);
-	if (!trans)
-		return -ENOMEM;
-
-	atomic_set(&trans->usage, 1);
-	INIT_LIST_HEAD(&trans->services);
-	INIT_LIST_HEAD(&trans->link);
-	INIT_LIST_HEAD(&trans->krxiodq_link);
-	spin_lock_init(&trans->lock);
-	INIT_LIST_HEAD(&trans->peer_active);
-	INIT_LIST_HEAD(&trans->peer_graveyard);
-	spin_lock_init(&trans->peer_gylock);
-	init_waitqueue_head(&trans->peer_gy_waitq);
-	rwlock_init(&trans->peer_lock);
-	atomic_set(&trans->peer_count, 0);
-	trans->port = port;
-
-	/* create a UDP socket to be my actual transport endpoint */
-	ret = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &trans->socket);
-	if (ret < 0)
-		goto error;
-
-	/* use the specified port */
-	if (port) {
-		memset(&sin, 0, sizeof(sin));
-		sin.sin_family = AF_INET;
-		sin.sin_port = htons(port);
-		ret = trans->socket->ops->bind(trans->socket,
-					       (struct sockaddr *) &sin,
-					       sizeof(sin));
-		if (ret < 0)
-			goto error;
-	}
-
-	opt = 1;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = trans->socket->ops->setsockopt(trans->socket, SOL_IP, IP_RECVERR,
-					     (char *) &opt, sizeof(opt));
-	set_fs(oldfs);
-
-	spin_lock(&rxrpc_transports_lock);
-	list_add(&trans->link, &rxrpc_transports);
-	spin_unlock(&rxrpc_transports_lock);
-
-	/* set the socket up */
-	sock = trans->socket->sk;
-	sock->sk_user_data	= trans;
-	sock->sk_data_ready	= rxrpc_data_ready;
-	sock->sk_error_report	= rxrpc_error_report;
-
-	down_write(&rxrpc_proc_transports_sem);
-	list_add_tail(&trans->proc_link, &rxrpc_proc_transports);
-	up_write(&rxrpc_proc_transports_sem);
-
-	__RXACCT(atomic_inc(&rxrpc_transport_count));
-
-	*_trans = trans;
-	_leave(" = 0 (%p)", trans);
-	return 0;
-
- error:
-	/* finish cleaning up the transport (not really needed here, but...) */
-	if (trans->socket)
-		trans->socket->ops->shutdown(trans->socket, 2);
-
-	/* close the socket */
-	if (trans->socket) {
-		trans->socket->sk->sk_user_data = NULL;
-		sock_release(trans->socket);
-		trans->socket = NULL;
-	}
-
-	kfree(trans);
-
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_create_transport() */
-
-/*****************************************************************************/
-/*
- * destroy a transport endpoint
- */
-void rxrpc_put_transport(struct rxrpc_transport *trans)
-{
-	_enter("%p{u=%d p=%hu}",
-	       trans, atomic_read(&trans->usage), trans->port);
-
-	BUG_ON(atomic_read(&trans->usage) <= 0);
-
-	/* to prevent a race, the decrement and the dequeue must be
-	 * effectively atomic */
-	spin_lock(&rxrpc_transports_lock);
-	if (likely(!atomic_dec_and_test(&trans->usage))) {
-		spin_unlock(&rxrpc_transports_lock);
-		_leave("");
-		return;
-	}
-
-	list_del(&trans->link);
-	spin_unlock(&rxrpc_transports_lock);
-
-	/* finish cleaning up the transport */
-	if (trans->socket)
-		trans->socket->ops->shutdown(trans->socket, 2);
-
-	rxrpc_krxsecd_clear_transport(trans);
-	rxrpc_krxiod_dequeue_transport(trans);
-
-	/* discard all peer information */
-	rxrpc_peer_clearall(trans);
-
-	down_write(&rxrpc_proc_transports_sem);
-	list_del(&trans->proc_link);
-	up_write(&rxrpc_proc_transports_sem);
-	__RXACCT(atomic_dec(&rxrpc_transport_count));
-
-	/* close the socket */
-	if (trans->socket) {
-		trans->socket->sk->sk_user_data = NULL;
-		sock_release(trans->socket);
-		trans->socket = NULL;
-	}
-
-	kfree(trans);
-
-	_leave("");
-} /* end rxrpc_put_transport() */
-
-/*****************************************************************************/
-/*
- * add a service to a transport to be listened upon
- */
-int rxrpc_add_service(struct rxrpc_transport *trans,
-		      struct rxrpc_service *newsrv)
-{
-	struct rxrpc_service *srv;
-	struct list_head *_p;
-	int ret = -EEXIST;
-
-	_enter("%p{%hu},%p{%hu}",
-	       trans, trans->port, newsrv, newsrv->service_id);
-
-	/* verify that the service ID is not already present */
-	spin_lock(&trans->lock);
-
-	list_for_each(_p, &trans->services) {
-		srv = list_entry(_p, struct rxrpc_service, link);
-		if (srv->service_id == newsrv->service_id)
-			goto out;
-	}
-
-	/* okay - add the transport to the list */
-	list_add_tail(&newsrv->link, &trans->services);
-	rxrpc_get_transport(trans);
-	ret = 0;
-
- out:
-	spin_unlock(&trans->lock);
-
-	_leave("= %d", ret);
-	return ret;
-} /* end rxrpc_add_service() */
-
-/*****************************************************************************/
-/*
- * remove a service from a transport
- */
-void rxrpc_del_service(struct rxrpc_transport *trans, struct rxrpc_service *srv)
-{
-	_enter("%p{%hu},%p{%hu}", trans, trans->port, srv, srv->service_id);
-
-	spin_lock(&trans->lock);
-	list_del(&srv->link);
-	spin_unlock(&trans->lock);
-
-	rxrpc_put_transport(trans);
-
-	_leave("");
-} /* end rxrpc_del_service() */
-
-/*****************************************************************************/
-/*
- * INET callback when data has been received on the socket.
- */
-static void rxrpc_data_ready(struct sock *sk, int count)
-{
-	struct rxrpc_transport *trans;
-
-	_enter("%p{t=%p},%d", sk, sk->sk_user_data, count);
-
-	/* queue the transport for attention by krxiod */
-	trans = (struct rxrpc_transport *) sk->sk_user_data;
-	if (trans)
-		rxrpc_krxiod_queue_transport(trans);
-
-	/* wake up anyone waiting on the socket */
-	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible(sk->sk_sleep);
-
-	_leave("");
-} /* end rxrpc_data_ready() */
-
-/*****************************************************************************/
-/*
- * INET callback when an ICMP error packet is received
- * - sk->err is error (EHOSTUNREACH, EPROTO or EMSGSIZE)
- */
-static void rxrpc_error_report(struct sock *sk)
-{
-	struct rxrpc_transport *trans;
-
-	_enter("%p{t=%p}", sk, sk->sk_user_data);
-
-	/* queue the transport for attention by krxiod */
-	trans = (struct rxrpc_transport *) sk->sk_user_data;
-	if (trans) {
-		trans->error_rcvd = 1;
-		rxrpc_krxiod_queue_transport(trans);
-	}
-
-	/* wake up anyone waiting on the socket */
-	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible(sk->sk_sleep);
-
-	_leave("");
-} /* end rxrpc_error_report() */
-
-/*****************************************************************************/
-/*
- * split a message up, allocating message records and filling them in
- * from the contents of a socket buffer
- */
-static int rxrpc_incoming_msg(struct rxrpc_transport *trans,
-			      struct sk_buff *pkt,
-			      struct list_head *msgq)
-{
-	struct rxrpc_message *msg;
-	int ret;
-
-	_enter("");
-
-	msg = kzalloc(sizeof(struct rxrpc_message), GFP_KERNEL);
-	if (!msg) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	atomic_set(&msg->usage, 1);
-	list_add_tail(&msg->link,msgq);
-
-	/* dig out the Rx routing parameters */
-	if (skb_copy_bits(pkt, sizeof(struct udphdr),
-			  &msg->hdr, sizeof(msg->hdr)) < 0) {
-		ret = -EBADMSG;
-		goto error;
-	}
-
-	msg->trans = trans;
-	msg->state = RXRPC_MSG_RECEIVED;
-	skb_get_timestamp(pkt, &msg->stamp);
-	if (msg->stamp.tv_sec == 0) {
-		do_gettimeofday(&msg->stamp);
-		if (pkt->sk)
-			sock_enable_timestamp(pkt->sk);
-	}
-	msg->seq = ntohl(msg->hdr.seq);
-
-	/* attach the packet */
-	skb_get(pkt);
-	msg->pkt = pkt;
-
-	msg->offset = sizeof(struct udphdr) + sizeof(struct rxrpc_header);
-	msg->dsize = msg->pkt->len - msg->offset;
-
-	_net("Rx Received packet from %s (%08x;%08x,%1x,%d,%s,%02x,%d,%d)",
-	     msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server",
-	     ntohl(msg->hdr.epoch),
-	     (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT,
-	     ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK,
-	     ntohl(msg->hdr.callNumber),
-	     rxrpc_pkts[msg->hdr.type],
-	     msg->hdr.flags,
-	     ntohs(msg->hdr.serviceId),
-	     msg->hdr.securityIndex);
-
-	__RXACCT(atomic_inc(&rxrpc_message_count));
-
-	/* split off jumbo packets */
-	while (msg->hdr.type == RXRPC_PACKET_TYPE_DATA &&
-	       msg->hdr.flags & RXRPC_JUMBO_PACKET
-	       ) {
-		struct rxrpc_jumbo_header jumbo;
-		struct rxrpc_message *jumbomsg = msg;
-
-		_debug("split jumbo packet");
-
-		/* quick sanity check */
-		ret = -EBADMSG;
-		if (msg->dsize <
-		    RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header))
-			goto error;
-		if (msg->hdr.flags & RXRPC_LAST_PACKET)
-			goto error;
-
-		/* dig out the secondary header */
-		if (skb_copy_bits(pkt, msg->offset + RXRPC_JUMBO_DATALEN,
-				  &jumbo, sizeof(jumbo)) < 0)
-			goto error;
-
-		/* allocate a new message record */
-		ret = -ENOMEM;
-		msg = kmemdup(jumbomsg, sizeof(struct rxrpc_message), GFP_KERNEL);
-		if (!msg)
-			goto error;
-
-		list_add_tail(&msg->link, msgq);
-
-		/* adjust the jumbo packet */
-		jumbomsg->dsize = RXRPC_JUMBO_DATALEN;
-
-		/* attach the packet here too */
-		skb_get(pkt);
-
-		/* adjust the parameters */
-		msg->seq++;
-		msg->hdr.seq = htonl(msg->seq);
-		msg->hdr.serial = htonl(ntohl(msg->hdr.serial) + 1);
-		msg->offset += RXRPC_JUMBO_DATALEN +
-			sizeof(struct rxrpc_jumbo_header);
-		msg->dsize -= RXRPC_JUMBO_DATALEN +
-			sizeof(struct rxrpc_jumbo_header);
-		msg->hdr.flags = jumbo.flags;
-		msg->hdr._rsvd = jumbo._rsvd;
-
-		_net("Rx Split jumbo packet from %s"
-		     " (%08x;%08x,%1x,%d,%s,%02x,%d,%d)",
-		     msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server",
-		     ntohl(msg->hdr.epoch),
-		     (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT,
-		     ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK,
-		     ntohl(msg->hdr.callNumber),
-		     rxrpc_pkts[msg->hdr.type],
-		     msg->hdr.flags,
-		     ntohs(msg->hdr.serviceId),
-		     msg->hdr.securityIndex);
-
-		__RXACCT(atomic_inc(&rxrpc_message_count));
-	}
-
-	_leave(" = 0 #%d", atomic_read(&rxrpc_message_count));
-	return 0;
-
- error:
-	while (!list_empty(msgq)) {
-		msg = list_entry(msgq->next, struct rxrpc_message, link);
-		list_del_init(&msg->link);
-
-		rxrpc_put_message(msg);
-	}
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_incoming_msg() */
-
-/*****************************************************************************/
-/*
- * accept a new call
- * - called from krxiod in process context
- */
-void rxrpc_trans_receive_packet(struct rxrpc_transport *trans)
-{
-	struct rxrpc_message *msg;
-	struct rxrpc_peer *peer;
-	struct sk_buff *pkt;
-	int ret;
-	__be32 addr;
-	__be16 port;
-
-	LIST_HEAD(msgq);
-
-	_enter("%p{%d}", trans, trans->port);
-
-	for (;;) {
-		/* deal with outstanting errors first */
-		if (trans->error_rcvd)
-			rxrpc_trans_receive_error_report(trans);
-
-		/* attempt to receive a packet */
-		pkt = skb_recv_datagram(trans->socket->sk, 0, 1, &ret);
-		if (!pkt) {
-			if (ret == -EAGAIN) {
-				_leave(" EAGAIN");
-				return;
-			}
-
-			/* an icmp error may have occurred */
-			rxrpc_krxiod_queue_transport(trans);
-			_leave(" error %d\n", ret);
-			return;
-		}
-
-		/* we'll probably need to checksum it (didn't call
-		 * sock_recvmsg) */
-		if (skb_checksum_complete(pkt)) {
-			kfree_skb(pkt);
-			rxrpc_krxiod_queue_transport(trans);
-			_leave(" CSUM failed");
-			return;
-		}
-
-		addr = pkt->nh.iph->saddr;
-		port = pkt->h.uh->source;
-
-		_net("Rx Received UDP packet from %08x:%04hu",
-		     ntohl(addr), ntohs(port));
-
-		/* unmarshall the Rx parameters and split jumbo packets */
-		ret = rxrpc_incoming_msg(trans, pkt, &msgq);
-		if (ret < 0) {
-			kfree_skb(pkt);
-			rxrpc_krxiod_queue_transport(trans);
-			_leave(" bad packet");
-			return;
-		}
-
-		BUG_ON(list_empty(&msgq));
-
-		msg = list_entry(msgq.next, struct rxrpc_message, link);
-
-		/* locate the record for the peer from which it
-		 * originated */
-		ret = rxrpc_peer_lookup(trans, addr, &peer);
-		if (ret < 0) {
-			kdebug("Rx No connections from that peer");
-			rxrpc_trans_immediate_abort(trans, msg, -EINVAL);
-			goto finished_msg;
-		}
-
-		/* try and find a matching connection */
-		ret = rxrpc_connection_lookup(peer, msg, &msg->conn);
-		if (ret < 0) {
-			kdebug("Rx Unknown Connection");
-			rxrpc_trans_immediate_abort(trans, msg, -EINVAL);
-			rxrpc_put_peer(peer);
-			goto finished_msg;
-		}
-		rxrpc_put_peer(peer);
-
-		/* deal with the first packet of a new call */
-		if (msg->hdr.flags & RXRPC_CLIENT_INITIATED &&
-		    msg->hdr.type == RXRPC_PACKET_TYPE_DATA &&
-		    ntohl(msg->hdr.seq) == 1
-		    ) {
-			_debug("Rx New server call");
-			rxrpc_trans_receive_new_call(trans, &msgq);
-			goto finished_msg;
-		}
-
-		/* deal with subsequent packet(s) of call */
-		_debug("Rx Call packet");
-		while (!list_empty(&msgq)) {
-			msg = list_entry(msgq.next, struct rxrpc_message, link);
-			list_del_init(&msg->link);
-
-			ret = rxrpc_conn_receive_call_packet(msg->conn, NULL, msg);
-			if (ret < 0) {
-				rxrpc_trans_immediate_abort(trans, msg, ret);
-				rxrpc_put_message(msg);
-				goto finished_msg;
-			}
-
-			rxrpc_put_message(msg);
-		}
-
-		goto finished_msg;
-
-		/* dispose of the packets */
-	finished_msg:
-		while (!list_empty(&msgq)) {
-			msg = list_entry(msgq.next, struct rxrpc_message, link);
-			list_del_init(&msg->link);
-
-			rxrpc_put_message(msg);
-		}
-		kfree_skb(pkt);
-	}
-
-	_leave("");
-
-} /* end rxrpc_trans_receive_packet() */
-
-/*****************************************************************************/
-/*
- * accept a new call from a client trying to connect to one of my services
- * - called in process context
- */
-static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans,
-					struct list_head *msgq)
-{
-	struct rxrpc_message *msg;
-
-	_enter("");
-
-	/* only bother with the first packet */
-	msg = list_entry(msgq->next, struct rxrpc_message, link);
-	list_del_init(&msg->link);
-	rxrpc_krxsecd_queue_incoming_call(msg);
-	rxrpc_put_message(msg);
-
-	_leave(" = 0");
-
-	return 0;
-} /* end rxrpc_trans_receive_new_call() */
-
-/*****************************************************************************/
-/*
- * perform an immediate abort without connection or call structures
- */
-int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans,
-				struct rxrpc_message *msg,
-				int error)
-{
-	struct rxrpc_header ahdr;
-	struct sockaddr_in sin;
-	struct msghdr msghdr;
-	struct kvec iov[2];
-	__be32 _error;
-	int len, ret;
-
-	_enter("%p,%p,%d", trans, msg, error);
-
-	/* don't abort an abort packet */
-	if (msg->hdr.type == RXRPC_PACKET_TYPE_ABORT) {
-		_leave(" = 0");
-		return 0;
-	}
-
-	_error = htonl(-error);
-
-	/* set up the message to be transmitted */
-	memcpy(&ahdr, &msg->hdr, sizeof(ahdr));
-	ahdr.epoch	= msg->hdr.epoch;
-	ahdr.serial	= htonl(1);
-	ahdr.seq	= 0;
-	ahdr.type	= RXRPC_PACKET_TYPE_ABORT;
-	ahdr.flags	= RXRPC_LAST_PACKET;
-	ahdr.flags	|= ~msg->hdr.flags & RXRPC_CLIENT_INITIATED;
-
-	iov[0].iov_len	= sizeof(ahdr);
-	iov[0].iov_base	= &ahdr;
-	iov[1].iov_len	= sizeof(_error);
-	iov[1].iov_base	= &_error;
-
-	len = sizeof(ahdr) + sizeof(_error);
-
-	memset(&sin,0,sizeof(sin));
-	sin.sin_family		= AF_INET;
-	sin.sin_port		= msg->pkt->h.uh->source;
-	sin.sin_addr.s_addr	= msg->pkt->nh.iph->saddr;
-
-	msghdr.msg_name		= &sin;
-	msghdr.msg_namelen	= sizeof(sin);
-	msghdr.msg_control	= NULL;
-	msghdr.msg_controllen	= 0;
-	msghdr.msg_flags	= MSG_DONTWAIT;
-
-	_net("Sending message type %d of %d bytes to %08x:%d",
-	     ahdr.type,
-	     len,
-	     ntohl(sin.sin_addr.s_addr),
-	     ntohs(sin.sin_port));
-
-	/* send the message */
-	ret = kernel_sendmsg(trans->socket, &msghdr, iov, 2, len);
-
-	_leave(" = %d", ret);
-	return ret;
-} /* end rxrpc_trans_immediate_abort() */
-
-/*****************************************************************************/
-/*
- * receive an ICMP error report and percolate it to all connections
- * heading to the affected host or port
- */
-static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans)
-{
-	struct rxrpc_connection *conn;
-	struct sockaddr_in sin;
-	struct rxrpc_peer *peer;
-	struct list_head connq, *_p;
-	struct errormsg emsg;
-	struct msghdr msg;
-	__be16 port;
-	int local, err;
-
-	_enter("%p", trans);
-
-	for (;;) {
-		trans->error_rcvd = 0;
-
-		/* try and receive an error message */
-		msg.msg_name	= &sin;
-		msg.msg_namelen	= sizeof(sin);
-		msg.msg_control	= &emsg;
-		msg.msg_controllen = sizeof(emsg);
-		msg.msg_flags	= 0;
-
-		err = kernel_recvmsg(trans->socket, &msg, NULL, 0, 0,
-				   MSG_ERRQUEUE | MSG_DONTWAIT | MSG_TRUNC);
-
-		if (err == -EAGAIN) {
-			_leave("");
-			return;
-		}
-
-		if (err < 0) {
-			printk("%s: unable to recv an error report: %d\n",
-			       __FUNCTION__, err);
-			_leave("");
-			return;
-		}
-
-		msg.msg_controllen = (char *) msg.msg_control - (char *) &emsg;
-
-		if (msg.msg_controllen < sizeof(emsg.cmsg) ||
-		    msg.msg_namelen < sizeof(sin)) {
-			printk("%s: short control message"
-			       " (nlen=%u clen=%Zu fl=%x)\n",
-			       __FUNCTION__,
-			       msg.msg_namelen,
-			       msg.msg_controllen,
-			       msg.msg_flags);
-			continue;
-		}
-
-		_net("Rx Received control message"
-		     " { len=%Zu level=%u type=%u }",
-		     emsg.cmsg.cmsg_len,
-		     emsg.cmsg.cmsg_level,
-		     emsg.cmsg.cmsg_type);
-
-		if (sin.sin_family != AF_INET) {
-			printk("Rx Ignoring error report with non-INET address"
-			       " (fam=%u)",
-			       sin.sin_family);
-			continue;
-		}
-
-		_net("Rx Received message pertaining to host addr=%x port=%hu",
-		     ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port));
-
-		if (emsg.cmsg.cmsg_level != SOL_IP ||
-		    emsg.cmsg.cmsg_type != IP_RECVERR) {
-			printk("Rx Ignoring unknown error report"
-			       " { level=%u type=%u }",
-			       emsg.cmsg.cmsg_level,
-			       emsg.cmsg.cmsg_type);
-			continue;
-		}
-
-		if (msg.msg_controllen < sizeof(emsg.cmsg) + sizeof(emsg.ee)) {
-			printk("%s: short error message (%Zu)\n",
-			       __FUNCTION__, msg.msg_controllen);
-			_leave("");
-			return;
-		}
-
-		port = sin.sin_port;
-
-		switch (emsg.ee.ee_origin) {
-		case SO_EE_ORIGIN_ICMP:
-			local = 0;
-			switch (emsg.ee.ee_type) {
-			case ICMP_DEST_UNREACH:
-				switch (emsg.ee.ee_code) {
-				case ICMP_NET_UNREACH:
-					_net("Rx Received ICMP Network Unreachable");
-					port = 0;
-					err = -ENETUNREACH;
-					break;
-				case ICMP_HOST_UNREACH:
-					_net("Rx Received ICMP Host Unreachable");
-					port = 0;
-					err = -EHOSTUNREACH;
-					break;
-				case ICMP_PORT_UNREACH:
-					_net("Rx Received ICMP Port Unreachable");
-					err = -ECONNREFUSED;
-					break;
-				case ICMP_NET_UNKNOWN:
-					_net("Rx Received ICMP Unknown Network");
-					port = 0;
-					err = -ENETUNREACH;
-					break;
-				case ICMP_HOST_UNKNOWN:
-					_net("Rx Received ICMP Unknown Host");
-					port = 0;
-					err = -EHOSTUNREACH;
-					break;
-				default:
-					_net("Rx Received ICMP DestUnreach { code=%u }",
-					     emsg.ee.ee_code);
-					err = emsg.ee.ee_errno;
-					break;
-				}
-				break;
-
-			case ICMP_TIME_EXCEEDED:
-				_net("Rx Received ICMP TTL Exceeded");
-				err = emsg.ee.ee_errno;
-				break;
-
-			default:
-				_proto("Rx Received ICMP error { type=%u code=%u }",
-				       emsg.ee.ee_type, emsg.ee.ee_code);
-				err = emsg.ee.ee_errno;
-				break;
-			}
-			break;
-
-		case SO_EE_ORIGIN_LOCAL:
-			_proto("Rx Received local error { error=%d }",
-			       emsg.ee.ee_errno);
-			local = 1;
-			err = emsg.ee.ee_errno;
-			break;
-
-		case SO_EE_ORIGIN_NONE:
-		case SO_EE_ORIGIN_ICMP6:
-		default:
-			_proto("Rx Received error report { orig=%u }",
-			       emsg.ee.ee_origin);
-			local = 0;
-			err = emsg.ee.ee_errno;
-			break;
-		}
-
-		/* find all the connections between this transport and the
-		 * affected destination */
-		INIT_LIST_HEAD(&connq);
-
-		if (rxrpc_peer_lookup(trans, sin.sin_addr.s_addr,
-				      &peer) == 0) {
-			read_lock(&peer->conn_lock);
-			list_for_each(_p, &peer->conn_active) {
-				conn = list_entry(_p, struct rxrpc_connection,
-						  link);
-				if (port && conn->addr.sin_port != port)
-					continue;
-				if (!list_empty(&conn->err_link))
-					continue;
-
-				rxrpc_get_connection(conn);
-				list_add_tail(&conn->err_link, &connq);
-			}
-			read_unlock(&peer->conn_lock);
-
-			/* service all those connections */
-			while (!list_empty(&connq)) {
-				conn = list_entry(connq.next,
-						  struct rxrpc_connection,
-						  err_link);
-				list_del(&conn->err_link);
-
-				rxrpc_conn_handle_error(conn, local, err);
-
-				rxrpc_put_connection(conn);
-			}
-
-			rxrpc_put_peer(peer);
-		}
-	}
-
-	_leave("");
-	return;
-} /* end rxrpc_trans_receive_error_report() */
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index f4544dd..475df84 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -46,62 +46,6 @@ config NET_SCH_FIFO
 
 if NET_SCHED
 
-choice
-	prompt "Packet scheduler clock source"
-	default NET_SCH_CLK_GETTIMEOFDAY
-	---help---
-	  Packet schedulers need a monotonic clock that increments at a static
-	  rate. The kernel provides several suitable interfaces, each with
-	  different properties:
-	  
-	  - high resolution (us or better)
-	  - fast to read (minimal locking, no i/o access)
-	  - synchronized on all processors
-	  - handles cpu clock frequency changes
-
-	  but nothing provides all of the above.
-
-config NET_SCH_CLK_JIFFIES
-	bool "Timer interrupt"
-	---help---
-	  Say Y here if you want to use the timer interrupt (jiffies) as clock
-	  source. This clock source is fast, synchronized on all processors and
-	  handles cpu clock frequency changes, but its resolution is too low
-	  for accurate shaping except at very low speed.
-
-config NET_SCH_CLK_GETTIMEOFDAY
-	bool "gettimeofday"
-	---help---
-	  Say Y here if you want to use gettimeofday as clock source. This clock
-	  source has high resolution, is synchronized on all processors and
-	  handles cpu clock frequency changes, but it is slow.
-
-	  Choose this if you need a high resolution clock source but can't use
-	  the CPU's cycle counter.
-
-# don't allow on SMP x86 because they can have unsynchronized TSCs.
-# gettimeofday is a good alternative
-config NET_SCH_CLK_CPU
-	bool "CPU cycle counter"
-	depends on ((X86_TSC || X86_64) && !SMP) || ALPHA || SPARC64 || PPC64 || IA64
-	---help---
-	  Say Y here if you want to use the CPU's cycle counter as clock source.
-	  This is a cheap and high resolution clock source, but on some
-	  architectures it is not synchronized on all processors and doesn't
-	  handle cpu clock frequency changes.
-
-	  The useable cycle counters are:
-
-	  	x86/x86_64	- Timestamp Counter
-		alpha		- Cycle Counter
-		sparc64		- %ticks register
-		ppc64		- Time base
-		ia64		- Interval Time Counter
-
-	  Choose this if your CPU's cycle counter is working properly.
-
-endchoice
-
 comment "Queueing/Scheduling"
 
 config NET_SCH_CBQ
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index cb21617..711dd26 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -25,12 +25,12 @@ #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 <linux/kmod.h>
 #include <net/sock.h>
 #include <net/sch_generic.h>
 #include <net/act_api.h>
+#include <net/netlink.h>
 
 void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
 {
@@ -93,15 +93,15 @@ static int tcf_dump_walker(struct sk_buf
 				continue;
 			a->priv = p;
 			a->order = n_i;
-			r = (struct rtattr*) skb->tail;
+			r = (struct rtattr *)skb_tail_pointer(skb);
 			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);
+				nlmsg_trim(skb, r);
 				goto done;
 			}
-			r->rta_len = skb->tail - (u8*)r;
+			r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
 			n_i++;
 			if (n_i >= TCA_ACT_MAX_PRIO)
 				goto done;
@@ -114,7 +114,7 @@ done:
 	return n_i;
 
 rtattr_failure:
-	skb_trim(skb, (u8*)r - skb->data);
+	nlmsg_trim(skb, r);
 	goto done;
 }
 
@@ -125,7 +125,7 @@ static int tcf_del_walker(struct sk_buff
 	struct rtattr *r ;
 	int i= 0, n_i = 0;
 
-	r = (struct rtattr*) skb->tail;
+	r = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, a->order, 0, NULL);
 	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind);
 	for (i = 0; i < (hinfo->hmask + 1); i++) {
@@ -140,11 +140,11 @@ static int tcf_del_walker(struct sk_buff
 		}
 	}
 	RTA_PUT(skb, TCA_FCNT, 4, &n_i);
-	r->rta_len = skb->tail - (u8*)r;
+	r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
 
 	return n_i;
 rtattr_failure:
-	skb_trim(skb, (u8*)r - skb->data);
+	nlmsg_trim(skb, r);
 	return -EINVAL;
 }
 
@@ -423,7 +423,7 @@ int
 tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
 	int err = -EINVAL;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *r;
 
 	if (a->ops == NULL || a->ops->dump == NULL)
@@ -432,15 +432,15 @@ tcf_action_dump_1(struct sk_buff *skb, s
 	RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind);
 	if (tcf_action_copy_stats(skb, a, 0))
 		goto rtattr_failure;
-	r = (struct rtattr*) skb->tail;
+	r = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 	if ((err = tcf_action_dump_old(skb, a, bind, ref)) > 0) {
-		r->rta_len = skb->tail - (u8*)r;
+		r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
 		return err;
 	}
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -449,17 +449,17 @@ tcf_action_dump(struct sk_buff *skb, str
 {
 	struct tc_action *a;
 	int err = -EINVAL;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *r ;
 
 	while ((a = act) != NULL) {
-		r = (struct rtattr*) skb->tail;
+		r = (struct rtattr *)skb_tail_pointer(skb);
 		act = a->next;
 		RTA_PUT(skb, a->order, 0, NULL);
 		err = tcf_action_dump_1(skb, a, bind, ref);
 		if (err < 0)
 			goto errout;
-		r->rta_len = skb->tail - (u8*)r;
+		r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
 	}
 
 	return 0;
@@ -467,7 +467,7 @@ tcf_action_dump(struct sk_buff *skb, str
 rtattr_failure:
 	err = -EINVAL;
 errout:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return err;
 }
 
@@ -635,7 +635,7 @@ tca_get_fill(struct sk_buff *skb, struct
 {
 	struct tcamsg *t;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *x;
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);
@@ -645,20 +645,20 @@ tca_get_fill(struct sk_buff *skb, struct
 	t->tca__pad1 = 0;
 	t->tca__pad2 = 0;
 
-	x = (struct rtattr*) skb->tail;
+	x = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
 
 	if (tcf_action_dump(skb, a, bind, ref) < 0)
 		goto rtattr_failure;
 
-	x->rta_len = skb->tail - (u8*)x;
+	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -767,7 +767,7 @@ static int tca_action_flush(struct rtatt
 		return -ENOBUFS;
 	}
 
-	b = (unsigned char *)skb->tail;
+	b = skb_tail_pointer(skb);
 
 	if (rtattr_parse_nested(tb, TCA_ACT_MAX, rta) < 0)
 		goto err_out;
@@ -783,16 +783,16 @@ static int tca_action_flush(struct rtatt
 	t->tca__pad1 = 0;
 	t->tca__pad2 = 0;
 
-	x = (struct rtattr *) skb->tail;
+	x = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
 
 	err = a->ops->walk(skb, &dcb, RTM_DELACTION, a);
 	if (err < 0)
 		goto rtattr_failure;
 
-	x->rta_len = skb->tail - (u8 *) x;
+	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	nlh->nlmsg_flags |= NLM_F_ROOT;
 	module_put(a->ops->owner);
 	kfree(a);
@@ -884,7 +884,7 @@ static int tcf_add_notify(struct tc_acti
 	if (!skb)
 		return -ENOBUFS;
 
-	b = (unsigned char *)skb->tail;
+	b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);
 	t = NLMSG_DATA(nlh);
@@ -892,15 +892,15 @@ static int tcf_add_notify(struct tc_acti
 	t->tca__pad1 = 0;
 	t->tca__pad2 = 0;
 
-	x = (struct rtattr*) skb->tail;
+	x = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
 
 	if (tcf_action_dump(skb, a, 0, 0) < 0)
 		goto rtattr_failure;
 
-	x->rta_len = skb->tail - (u8*)x;
+	x->rta_len = skb_tail_pointer(skb) - (u8 *)x;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	NETLINK_CB(skb).dst_group = RTNLGRP_TC;
 
 	err = rtnetlink_send(skb, pid, RTNLGRP_TC, flags&NLM_F_ECHO);
@@ -1015,7 +1015,7 @@ static int
 tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *x;
 	struct tc_action_ops *a_o;
 	struct tc_action a;
@@ -1048,7 +1048,7 @@ tc_dump_action(struct sk_buff *skb, stru
 	t->tca__pad1 = 0;
 	t->tca__pad2 = 0;
 
-	x = (struct rtattr *) skb->tail;
+	x = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
 
 	ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
@@ -1056,12 +1056,12 @@ tc_dump_action(struct sk_buff *skb, stru
 		goto rtattr_failure;
 
 	if (ret > 0) {
-		x->rta_len = skb->tail - (u8 *) x;
+		x->rta_len = skb_tail_pointer(skb) - (u8 *)x;
 		ret = skb->len;
 	} else
-		skb_trim(skb, (u8*)x - skb->data);
+		nlmsg_trim(skb, x);
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	if (NETLINK_CB(cb->skb).pid && ret)
 		nlh->nlmsg_flags |= NLM_F_MULTI;
 	module_put(a_o->owner);
@@ -1070,20 +1070,15 @@ tc_dump_action(struct sk_buff *skb, stru
 rtattr_failure:
 nlmsg_failure:
 	module_put(a_o->owner);
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return skb->len;
 }
 
 static int __init tc_action_init(void)
 {
-	struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC];
-
-	if (link_p) {
-		link_p[RTM_NEWACTION-RTM_BASE].doit = tc_ctl_action;
-		link_p[RTM_DELACTION-RTM_BASE].doit = tc_ctl_action;
-		link_p[RTM_GETACTION-RTM_BASE].doit = tc_ctl_action;
-		link_p[RTM_GETACTION-RTM_BASE].dumpit = tc_dump_action;
-	}
+	rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action);
 
 	return 0;
 }
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index 87d0faf..7517f37 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -28,6 +28,7 @@ #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_gact.h>
@@ -155,7 +156,7 @@ #endif
 
 static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_gact opt;
 	struct tcf_gact *gact = a->priv;
 	struct tcf_t t;
@@ -181,7 +182,7 @@ #endif
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 47f0b13..00b05f4 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -30,6 +30,7 @@ #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/kmod.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_ipt.h>
@@ -245,7 +246,7 @@ static int tcf_ipt(struct sk_buff *skb, 
 
 static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_ipt *ipt = a->priv;
 	struct ipt_entry_target *t;
 	struct tcf_t tm;
@@ -277,7 +278,7 @@ static int tcf_ipt_dump(struct sk_buff *
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	kfree(t);
 	return -1;
 }
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 3e93683..de21c92 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -30,6 +30,7 @@ #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_mirred.h>
@@ -206,7 +207,7 @@ bad_mirred:
 
 static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_mirred *m = a->priv;
 	struct tc_mirred opt;
 	struct tcf_t t;
@@ -225,7 +226,7 @@ static int tcf_mirred_dump(struct sk_buf
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 3d6a2fc..45b3cda 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -27,6 +27,7 @@ #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_pedit.h>
@@ -136,7 +137,7 @@ static int tcf_pedit(struct sk_buff *skb
 		}
 	}
 
-	pptr = skb->nh.raw;
+	pptr = skb_network_header(skb);
 
 	spin_lock(&p->tcf_lock);
 
@@ -195,7 +196,7 @@ done:
 static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
 			  int bind, int ref)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_pedit *p = a->priv;
 	struct tc_pedit *opt;
 	struct tcf_t t;
@@ -226,7 +227,7 @@ static int tcf_pedit_dump(struct sk_buff
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	kfree(opt);
 	return -1;
 }
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 10a5a5c..616f465 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -30,6 +30,7 @@ #include <linux/rtnetlink.h>
 #include <linux/init.h>
 #include <net/sock.h>
 #include <net/act_api.h>
+#include <net/netlink.h>
 
 #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])
@@ -80,7 +81,7 @@ static int tcf_act_police_walker(struct 
 				continue;
 			a->priv = p;
 			a->order = index;
-			r = (struct rtattr*) skb->tail;
+			r = (struct rtattr *)skb_tail_pointer(skb);
 			RTA_PUT(skb, a->order, 0, NULL);
 			if (type == RTM_DELACTION)
 				err = tcf_action_dump_1(skb, a, 0, 1);
@@ -88,10 +89,10 @@ static int tcf_act_police_walker(struct 
 				err = tcf_action_dump_1(skb, a, 0, 0);
 			if (err < 0) {
 				index--;
-				skb_trim(skb, (u8*)r - skb->data);
+				nlmsg_trim(skb, r);
 				goto done;
 			}
-			r->rta_len = skb->tail - (u8*)r;
+			r->rta_len = skb_tail_pointer(skb) - (u8 *)r;
 			n_i++;
 		}
 	}
@@ -102,7 +103,7 @@ done:
 	return n_i;
 
 rtattr_failure:
-	skb_trim(skb, (u8*)r - skb->data);
+	nlmsg_trim(skb, r);
 	goto done;
 }
 #endif
@@ -240,7 +241,7 @@ #endif
 	if (ret != ACT_P_CREATED)
 		return ret;
 
-	PSCHED_GET_TIME(police->tcfp_t_c);
+	police->tcfp_t_c = psched_get_time();
 	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);
@@ -295,10 +296,9 @@ #endif
 			return police->tcfp_result;
 		}
 
-		PSCHED_GET_TIME(now);
-
-		toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c,
-					 police->tcfp_burst);
+		now = psched_get_time();
+		toks = psched_tdiff_bounded(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))
@@ -326,7 +326,7 @@ #endif
 static int
 tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_police *police = a->priv;
 	struct tc_police opt;
 
@@ -355,7 +355,7 @@ #endif
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -494,7 +494,7 @@ #endif
 	}
 	if (police->tcfp_P_tab)
 		police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
-	PSCHED_GET_TIME(police->tcfp_t_c);
+	police->tcfp_t_c = psched_get_time();
 	police->tcf_index = parm->index ? parm->index :
 		tcf_police_new_index();
 	police->tcf_action = parm->action;
@@ -542,9 +542,9 @@ #endif
 			return police->tcfp_result;
 		}
 
-		PSCHED_GET_TIME(now);
-		toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c,
-					 police->tcfp_burst);
+		now = psched_get_time();
+		toks = psched_tdiff_bounded(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))
@@ -572,7 +572,7 @@ EXPORT_SYMBOL(tcf_police);
 
 int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_police opt;
 
 	opt.index = police->tcf_index;
@@ -598,7 +598,7 @@ #endif
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index c797118..36e1eda 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -16,6 +16,7 @@ #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 
 #define TCA_ACT_SIMP 22
@@ -155,7 +156,7 @@ static inline int tcf_simp_cleanup(struc
 static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
 				int bind, int ref)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tcf_defact *d = a->priv;
 	struct tc_defact opt;
 	struct tcf_t t;
@@ -173,7 +174,7 @@ static inline int tcf_simp_dump(struct s
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 5c6ffdb..ebf94ed 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -29,9 +29,10 @@ #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 <linux/kmod.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
@@ -323,7 +324,7 @@ tcf_fill_node(struct sk_buff *skb, struc
 {
 	struct tcmsg *tcm;
 	struct nlmsghdr  *nlh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
 	tcm = NLMSG_DATA(nlh);
@@ -340,12 +341,12 @@ tcf_fill_node(struct sk_buff *skb, struc
 		if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0)
 			goto rtattr_failure;
 	}
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -399,7 +400,6 @@ static int tc_dump_tfilter(struct sk_buf
 	if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
 		return skb->len;
 
-	read_lock(&qdisc_tree_lock);
 	if (!tcm->tcm_parent)
 		q = dev->qdisc_sleeping;
 	else
@@ -456,7 +456,6 @@ errout:
 	if (cl)
 		cops->put(q, cl);
 out:
-	read_unlock(&qdisc_tree_lock);
 	dev_put(dev);
 	return skb->len;
 }
@@ -563,30 +562,30 @@ #ifdef CONFIG_NET_CLS_ACT
 		 * to work with both old and new modes of entering
 		 * tc data even if iproute2  was newer - jhs
 		 */
-		struct rtattr * p_rta = (struct rtattr*) skb->tail;
+		struct rtattr *p_rta = (struct rtattr *)skb_tail_pointer(skb);
 
 		if (exts->action->type != TCA_OLD_COMPAT) {
 			RTA_PUT(skb, map->action, 0, NULL);
 			if (tcf_action_dump(skb, exts->action, 0, 0) < 0)
 				goto rtattr_failure;
-			p_rta->rta_len = skb->tail - (u8*)p_rta;
+			p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
 		} else if (map->police) {
 			RTA_PUT(skb, map->police, 0, NULL);
 			if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0)
 				goto rtattr_failure;
-			p_rta->rta_len = skb->tail - (u8*)p_rta;
+			p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
 		}
 	}
 #elif defined CONFIG_NET_CLS_POLICE
 	if (map->police && exts->police) {
-		struct rtattr * p_rta = (struct rtattr*) skb->tail;
+		struct rtattr *p_rta = (struct rtattr *)skb_tail_pointer(skb);
 
 		RTA_PUT(skb, map->police, 0, NULL);
 
 		if (tcf_police_dump(skb, exts->police) < 0)
 			goto rtattr_failure;
 
-		p_rta->rta_len = skb->tail - (u8*)p_rta;
+		p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
 	}
 #endif
 	return 0;
@@ -614,18 +613,11 @@ rtattr_failure: __attribute__ ((unused))
 
 static int __init tc_filter_init(void)
 {
-	struct rtnetlink_link *link_p = rtnetlink_links[PF_UNSPEC];
+	rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
+						 tc_dump_tfilter);
 
-	/* Setup rtnetlink links. It is made here to avoid
-	   exporting large number of public symbols.
-	 */
-
-	if (link_p) {
-		link_p[RTM_NEWTFILTER-RTM_BASE].doit = tc_ctl_tfilter;
-		link_p[RTM_DELTFILTER-RTM_BASE].doit = tc_ctl_tfilter;
-		link_p[RTM_GETTFILTER-RTM_BASE].doit = tc_ctl_tfilter;
-		link_p[RTM_GETTFILTER-RTM_BASE].dumpit = tc_dump_tfilter;
-	}
 	return 0;
 }
 
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 4a91f08..c885412 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -17,6 +17,7 @@ #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
+#include <net/netlink.h>
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
 
@@ -245,7 +246,7 @@ static int basic_dump(struct tcf_proto *
 		      struct sk_buff *skb, struct tcmsg *t)
 {
 	struct basic_filter *f = (struct basic_filter *) fh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	if (f == NULL)
@@ -263,11 +264,11 @@ static int basic_dump(struct tcf_proto *
 	    tcf_em_tree_dump(skb, &f->ematches, TCA_BASIC_EMATCHES) < 0)
 		goto rtattr_failure;
 
-	rta->rta_len = (skb->tail - b);
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 5dbb9d4..bbec4a0 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -38,6 +38,7 @@ #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <linux/netfilter.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -348,7 +349,7 @@ static int fw_dump(struct tcf_proto *tp,
 {
 	struct fw_head *head = (struct fw_head *)tp->root;
 	struct fw_filter *f = (struct fw_filter*)fh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	if (f == NULL)
@@ -374,7 +375,7 @@ #endif /* CONFIG_NET_CLS_IND */
 	if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)
 		goto rtattr_failure;
 
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 
 	if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0)
 		goto rtattr_failure;
@@ -382,7 +383,7 @@ #endif /* CONFIG_NET_CLS_IND */
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index abc47cc..cc941d0 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -28,6 +28,7 @@ #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -88,9 +89,9 @@ static __inline__ int route4_fastmap_has
 static inline
 void route4_reset_fastmap(struct net_device *dev, struct route4_head *head, u32 id)
 {
-	spin_lock_bh(&dev->queue_lock);
+	qdisc_lock_tree(dev);
 	memset(head->fastmap, 0, sizeof(head->fastmap));
-	spin_unlock_bh(&dev->queue_lock);
+	qdisc_unlock_tree(dev);
 }
 
 static inline void
@@ -562,7 +563,7 @@ static int route4_dump(struct tcf_proto 
 		       struct sk_buff *skb, struct tcmsg *t)
 {
 	struct route4_filter *f = (struct route4_filter*)fh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 	u32 id;
 
@@ -591,7 +592,7 @@ static int route4_dump(struct tcf_proto 
 	if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0)
 		goto rtattr_failure;
 
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 
 	if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0)
 		goto rtattr_failure;
@@ -599,7 +600,7 @@ static int route4_dump(struct tcf_proto 
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_rsvp.c b/net/sched/cls_rsvp.c
index 1d4a1fb..0a683c0 100644
--- a/net/sched/cls_rsvp.c
+++ b/net/sched/cls_rsvp.c
@@ -31,6 +31,7 @@ #include <net/ip.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
+#include <net/netlink.h>
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
 
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 7853621..22f9ede 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -143,9 +143,9 @@ static int rsvp_classify(struct sk_buff 
 	u8 tunnelid = 0;
 	u8 *xprt;
 #if RSVP_DST_LEN == 4
-	struct ipv6hdr *nhptr = skb->nh.ipv6h;
+	struct ipv6hdr *nhptr = ipv6_hdr(skb);
 #else
-	struct iphdr *nhptr = skb->nh.iph;
+	struct iphdr *nhptr = ip_hdr(skb);
 #endif
 
 restart:
@@ -160,7 +160,7 @@ #else
 	dst = &nhptr->daddr;
 	protocol = nhptr->protocol;
 	xprt = ((u8*)nhptr) + (nhptr->ihl<<2);
-	if (nhptr->frag_off&__constant_htons(IP_MF|IP_OFFSET))
+	if (nhptr->frag_off & htons(IP_MF|IP_OFFSET))
 		return -1;
 #endif
 
@@ -593,7 +593,7 @@ static int rsvp_dump(struct tcf_proto *t
 {
 	struct rsvp_filter *f = (struct rsvp_filter*)fh;
 	struct rsvp_session *s;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 	struct tc_rsvp_pinfo pinfo;
 
@@ -623,14 +623,14 @@ static int rsvp_dump(struct tcf_proto *t
 	if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0)
 		goto rtattr_failure;
 
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 
 	if (tcf_exts_dump_stats(skb, &f->exts, &rsvp_ext_map) < 0)
 		goto rtattr_failure;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_rsvp6.c b/net/sched/cls_rsvp6.c
index a2979d8..93b6abe 100644
--- a/net/sched/cls_rsvp6.c
+++ b/net/sched/cls_rsvp6.c
@@ -34,6 +34,7 @@ #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
+#include <net/netlink.h>
 
 #define RSVP_DST_LEN	4
 #define RSVP_ID		"rsvp6"
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 7563fdc..47ac0c5 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -12,6 +12,7 @@ #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <net/ip.h>
 #include <net/act_api.h>
+#include <net/netlink.h>
 #include <net/pkt_cls.h>
 #include <net/route.h>
 
@@ -448,7 +449,7 @@ static int tcindex_dump(struct tcf_proto
 {
 	struct tcindex_data *p = PRIV(tp);
 	struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	DPRINTK("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %p\n",
@@ -463,7 +464,7 @@ static int tcindex_dump(struct tcf_proto
 		RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift);
 		RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through),
 		    &p->fall_through);
-		rta->rta_len = skb->tail-b;
+		rta->rta_len = skb_tail_pointer(skb) - b;
 	} else {
 		if (p->perfect) {
 			t->tcm_handle = r-p->perfect;
@@ -486,7 +487,7 @@ static int tcindex_dump(struct tcf_proto
 
 		if (tcf_exts_dump(skb, &r->exts, &tcindex_ext_map) < 0)
 			goto rtattr_failure;
-		rta->rta_len = skb->tail-b;
+		rta->rta_len = skb_tail_pointer(skb) - b;
 
 		if (tcf_exts_dump_stats(skb, &r->exts, &tcindex_ext_map) < 0)
 			goto rtattr_failure;
@@ -495,7 +496,7 @@ static int tcindex_dump(struct tcf_proto
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 0bcb169..c7a347b 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -50,6 +50,7 @@ #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <linux/rtnetlink.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -119,7 +120,7 @@ static int u32_classify(struct sk_buff *
 	} stack[TC_U32_MAXDEPTH];
 
 	struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;
-	u8 *ptr = skb->nh.raw;
+	u8 *ptr = skb_network_header(skb);
 	struct tc_u_knode *n;
 	int sdepth = 0;
 	int off2 = 0;
@@ -213,7 +214,7 @@ #endif
 			off2 = 0;
 		}
 
-		if (ptr < skb->tail)
+		if (ptr < skb_tail_pointer(skb))
 			goto next_ht;
 	}
 
@@ -435,7 +436,7 @@ static void u32_destroy(struct tcf_proto
 			BUG_TRAP(ht->refcnt == 0);
 
 			kfree(ht);
-		};
+		}
 
 		kfree(tp_c);
 	}
@@ -718,7 +719,7 @@ static int u32_dump(struct tcf_proto *tp
 		     struct sk_buff *skb, struct tcmsg *t)
 {
 	struct tc_u_knode *n = (struct tc_u_knode*)fh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	if (n == NULL)
@@ -765,14 +766,14 @@ #ifdef CONFIG_CLS_U32_PERF
 #endif
 	}
 
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	if (TC_U32_KEY(n->handle))
 		if (tcf_exts_dump_stats(skb, &n->exts, &u32_ext_map) < 0)
 			goto rtattr_failure;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/em_u32.c b/net/sched/em_u32.c
index cd0600c..0a2a7fe 100644
--- a/net/sched/em_u32.c
+++ b/net/sched/em_u32.c
@@ -22,7 +22,7 @@ static int em_u32_match(struct sk_buff *
 			struct tcf_pkt_info *info)
 {
 	struct tc_u32_key *key = (struct tc_u32_key *) em->data;
-	unsigned char *ptr = skb->nh.raw;
+	const unsigned char *ptr = skb_network_header(skb);
 
 	if (info) {
 		if (info->ptr)
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
index 959c306..63146d3 100644
--- a/net/sched/ematch.c
+++ b/net/sched/ematch.c
@@ -418,17 +418,19 @@ void tcf_em_tree_destroy(struct tcf_prot
 int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
 {
 	int i;
-	struct rtattr * top_start = (struct rtattr*) skb->tail;
-	struct rtattr * list_start;
+	u8 *tail;
+	struct rtattr *top_start = (struct rtattr *)skb_tail_pointer(skb);
+	struct rtattr *list_start;
 
 	RTA_PUT(skb, tlv, 0, NULL);
 	RTA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr);
 
-	list_start = (struct rtattr *) skb->tail;
+	list_start = (struct rtattr *)skb_tail_pointer(skb);
 	RTA_PUT(skb, TCA_EMATCH_TREE_LIST, 0, NULL);
 
+	tail = skb_tail_pointer(skb);
 	for (i = 0; i < tree->hdr.nmatches; i++) {
-		struct rtattr *match_start = (struct rtattr*) skb->tail;
+		struct rtattr *match_start = (struct rtattr *)tail;
 		struct tcf_ematch *em = tcf_em_get_match(tree, i);
 		struct tcf_ematch_hdr em_hdr = {
 			.kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER,
@@ -447,11 +449,12 @@ int tcf_em_tree_dump(struct sk_buff *skb
 		} else if (em->datalen > 0)
 			RTA_PUT_NOHDR(skb, em->datalen, (void *) em->data);
 
-		match_start->rta_len = skb->tail - (u8*) match_start;
+		tail = skb_tail_pointer(skb);
+		match_start->rta_len = tail - (u8 *)match_start;
 	}
 
-	list_start->rta_len = skb->tail - (u8 *) list_start;
-	top_start->rta_len = skb->tail - (u8 *) top_start;
+	list_start->rta_len = tail - (u8 *)list_start;
+	top_start->rta_len = tail - (u8 *)top_start;
 
 	return 0;
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index ecc988a..bec600a 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -27,14 +27,15 @@ #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 <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kmod.h>
 #include <linux/list.h>
 #include <linux/bitops.h>
+#include <linux/hrtimer.h>
 
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 
@@ -190,7 +191,7 @@ int unregister_qdisc(struct Qdisc_ops *q
    (root qdisc, all its children, children of children etc.)
  */
 
-static struct Qdisc *__qdisc_lookup(struct net_device *dev, u32 handle)
+struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
 {
 	struct Qdisc *q;
 
@@ -201,16 +202,6 @@ static struct Qdisc *__qdisc_lookup(stru
 	return NULL;
 }
 
-struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
-{
-	struct Qdisc *q;
-
-	read_lock(&qdisc_tree_lock);
-	q = __qdisc_lookup(dev, handle);
-	read_unlock(&qdisc_tree_lock);
-	return q;
-}
-
 static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
 {
 	unsigned long cl;
@@ -291,6 +282,48 @@ void qdisc_put_rtab(struct qdisc_rate_ta
 	}
 }
 
+static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
+{
+	struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,
+						 timer);
+	struct net_device *dev = wd->qdisc->dev;
+
+	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
+	smp_wmb();
+	if (spin_trylock(&dev->queue_lock)) {
+		qdisc_run(dev);
+		spin_unlock(&dev->queue_lock);
+	} else
+		netif_schedule(dev);
+
+	return HRTIMER_NORESTART;
+}
+
+void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc)
+{
+	hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	wd->timer.function = qdisc_watchdog;
+	wd->qdisc = qdisc;
+}
+EXPORT_SYMBOL(qdisc_watchdog_init);
+
+void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires)
+{
+	ktime_t time;
+
+	wd->qdisc->flags |= TCQ_F_THROTTLED;
+	time = ktime_set(0, 0);
+	time = ktime_add_ns(time, PSCHED_US2NS(expires));
+	hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS);
+}
+EXPORT_SYMBOL(qdisc_watchdog_schedule);
+
+void qdisc_watchdog_cancel(struct qdisc_watchdog *wd)
+{
+	hrtimer_cancel(&wd->timer);
+	wd->qdisc->flags &= ~TCQ_F_THROTTLED;
+}
+EXPORT_SYMBOL(qdisc_watchdog_cancel);
 
 /* Allocate an unique handle from space managed by kernel */
 
@@ -362,7 +395,7 @@ void qdisc_tree_decrease_qlen(struct Qdi
 	if (n == 0)
 		return;
 	while ((parentid = sch->parent)) {
-		sch = __qdisc_lookup(sch->dev, TC_H_MAJ(parentid));
+		sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid));
 		cops = sch->ops->cl_ops;
 		if (cops->qlen_notify) {
 			cl = cops->get(sch, parentid);
@@ -467,12 +500,16 @@ #endif
 
 	if (handle == TC_H_INGRESS) {
 		sch->flags |= TCQ_F_INGRESS;
+		sch->stats_lock = &dev->ingress_lock;
 		handle = TC_H_MAKE(TC_H_INGRESS, 0);
-	} else if (handle == 0) {
-		handle = qdisc_alloc_handle(dev);
-		err = -ENOMEM;
-		if (handle == 0)
-			goto err_out3;
+	} else {
+		sch->stats_lock = &dev->queue_lock;
+		if (handle == 0) {
+			handle = qdisc_alloc_handle(dev);
+			err = -ENOMEM;
+			if (handle == 0)
+				goto err_out3;
+		}
 	}
 
 	sch->handle = handle;
@@ -621,9 +658,9 @@ static int tc_get_qdisc(struct sk_buff *
 			return err;
 		if (q) {
 			qdisc_notify(skb, n, clid, q, NULL);
-			spin_lock_bh(&dev->queue_lock);
+			qdisc_lock_tree(dev);
 			qdisc_destroy(q);
-			spin_unlock_bh(&dev->queue_lock);
+			qdisc_unlock_tree(dev);
 		}
 	} else {
 		qdisc_notify(skb, n, clid, NULL, q);
@@ -756,17 +793,17 @@ graft:
 		err = qdisc_graft(dev, p, clid, q, &old_q);
 		if (err) {
 			if (q) {
-				spin_lock_bh(&dev->queue_lock);
+				qdisc_lock_tree(dev);
 				qdisc_destroy(q);
-				spin_unlock_bh(&dev->queue_lock);
+				qdisc_unlock_tree(dev);
 			}
 			return err;
 		}
 		qdisc_notify(skb, n, clid, old_q, q);
 		if (old_q) {
-			spin_lock_bh(&dev->queue_lock);
+			qdisc_lock_tree(dev);
 			qdisc_destroy(old_q);
-			spin_unlock_bh(&dev->queue_lock);
+			qdisc_unlock_tree(dev);
 		}
 	}
 	return 0;
@@ -777,7 +814,7 @@ static int tc_fill_qdisc(struct sk_buff 
 {
 	struct tcmsg *tcm;
 	struct nlmsghdr  *nlh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct gnet_dump d;
 
 	nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
@@ -811,12 +848,12 @@ #endif
 	if (gnet_stats_finish_copy(&d) < 0)
 		goto rtattr_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -857,12 +894,12 @@ static int tc_dump_qdisc(struct sk_buff 
 	s_idx = cb->args[0];
 	s_q_idx = q_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_q_idx = 0;
-		read_lock(&qdisc_tree_lock);
 		q_idx = 0;
 		list_for_each_entry(q, &dev->qdisc_list, list) {
 			if (q_idx < s_q_idx) {
@@ -870,13 +907,12 @@ static int tc_dump_qdisc(struct sk_buff 
 				continue;
 			}
 			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(&qdisc_tree_lock);
+					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0)
 				goto done;
-			}
 			q_idx++;
 		}
-		read_unlock(&qdisc_tree_lock);
+cont:
+		idx++;
 	}
 
 done:
@@ -1015,7 +1051,7 @@ static int tc_fill_tclass(struct sk_buff
 {
 	struct tcmsg *tcm;
 	struct nlmsghdr  *nlh;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct gnet_dump d;
 	struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
 
@@ -1040,12 +1076,12 @@ static int tc_fill_tclass(struct sk_buff
 	if (gnet_stats_finish_copy(&d) < 0)
 		goto rtattr_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1099,7 +1135,6 @@ static int tc_dump_tclass(struct sk_buff
 	s_t = cb->args[0];
 	t = 0;
 
-	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 &&
@@ -1121,7 +1156,6 @@ static int tc_dump_tclass(struct sk_buff
 			break;
 		t++;
 	}
-	read_unlock(&qdisc_tree_lock);
 
 	cb->args[0] = t;
 
@@ -1146,7 +1180,7 @@ #endif
 
 	for ( ; tp; tp = tp->next) {
 		if ((tp->protocol == protocol ||
-			tp->protocol == __constant_htons(ETH_P_ALL)) &&
+			tp->protocol == htons(ETH_P_ALL)) &&
 			(err = tp->classify(skb, tp, res)) >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
 			if ( TC_ACT_RECLASSIFY == err) {
@@ -1175,15 +1209,31 @@ #endif
 	return -1;
 }
 
-static int psched_us_per_tick = 1;
-static int psched_tick_per_us = 1;
+void tcf_destroy(struct tcf_proto *tp)
+{
+	tp->ops->destroy(tp);
+	module_put(tp->ops->owner);
+	kfree(tp);
+}
+
+void tcf_destroy_chain(struct tcf_proto *fl)
+{
+	struct tcf_proto *tp;
+
+	while ((tp = fl) != NULL) {
+		fl = tp->next;
+		tcf_destroy(tp);
+	}
+}
+EXPORT_SYMBOL(tcf_destroy_chain);
 
 #ifdef CONFIG_PROC_FS
 static int psched_show(struct seq_file *seq, void *v)
 {
 	seq_printf(seq, "%08x %08x %08x %08x\n",
-		      psched_tick_per_us, psched_us_per_tick,
-		      1000000, HZ);
+		   (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1),
+		   1000000,
+		   (u32)NSEC_PER_SEC/(u32)ktime_to_ns(KTIME_MONOTONIC_RES));
 
 	return 0;
 }
@@ -1202,101 +1252,19 @@ static const struct file_operations psch
 };
 #endif
 
-#ifdef CONFIG_NET_SCH_CLK_CPU
-psched_tdiff_t psched_clock_per_hz;
-int psched_clock_scale;
-EXPORT_SYMBOL(psched_clock_per_hz);
-EXPORT_SYMBOL(psched_clock_scale);
-
-psched_time_t psched_time_base;
-cycles_t psched_time_mark;
-EXPORT_SYMBOL(psched_time_mark);
-EXPORT_SYMBOL(psched_time_base);
-
-/*
- * Periodically adjust psched_time_base to avoid overflow
- * with 32-bit get_cycles(). Safe up to 4GHz CPU.
- */
-static void psched_tick(unsigned long);
-static DEFINE_TIMER(psched_timer, psched_tick, 0, 0);
-
-static void psched_tick(unsigned long dummy)
-{
-	if (sizeof(cycles_t) == sizeof(u32)) {
-		psched_time_t dummy_stamp;
-		PSCHED_GET_TIME(dummy_stamp);
-		psched_timer.expires = jiffies + 1*HZ;
-		add_timer(&psched_timer);
-	}
-}
-
-int __init psched_calibrate_clock(void)
-{
-	psched_time_t stamp, stamp1;
-	struct timeval tv, tv1;
-	psched_tdiff_t delay;
-	long rdelay;
-	unsigned long stop;
-
-	psched_tick(0);
-	stop = jiffies + HZ/10;
-	PSCHED_GET_TIME(stamp);
-	do_gettimeofday(&tv);
-	while (time_before(jiffies, stop)) {
-		barrier();
-		cpu_relax();
-	}
-	PSCHED_GET_TIME(stamp1);
-	do_gettimeofday(&tv1);
-
-	delay = PSCHED_TDIFF(stamp1, stamp);
-	rdelay = tv1.tv_usec - tv.tv_usec;
-	rdelay += (tv1.tv_sec - tv.tv_sec)*1000000;
-	if (rdelay > delay)
-		return -1;
-	delay /= rdelay;
-	psched_tick_per_us = delay;
-	while ((delay>>=1) != 0)
-		psched_clock_scale++;
-	psched_us_per_tick = 1<<psched_clock_scale;
-	psched_clock_per_hz = (psched_tick_per_us*(1000000/HZ))>>psched_clock_scale;
-	return 0;
-}
-#endif
-
 static int __init pktsched_init(void)
 {
-	struct rtnetlink_link *link_p;
-
-#ifdef CONFIG_NET_SCH_CLK_CPU
-	if (psched_calibrate_clock() < 0)
-		return -1;
-#elif defined(CONFIG_NET_SCH_CLK_JIFFIES)
-	psched_tick_per_us = HZ<<PSCHED_JSCALE;
-	psched_us_per_tick = 1000000;
-#endif
-
-	link_p = rtnetlink_links[PF_UNSPEC];
-
-	/* Setup rtnetlink links. It is made here to avoid
-	   exporting large number of public symbols.
-	 */
-
-	if (link_p) {
-		link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_modify_qdisc;
-		link_p[RTM_DELQDISC-RTM_BASE].doit = tc_get_qdisc;
-		link_p[RTM_GETQDISC-RTM_BASE].doit = tc_get_qdisc;
-		link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc;
-		link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass;
-		link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass;
-		link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass;
-		link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass;
-	}
-
 	register_qdisc(&pfifo_qdisc_ops);
 	register_qdisc(&bfifo_qdisc_ops);
 	proc_net_fops_create("psched", 0, &psched_fops);
 
+	rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc);
+	rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL);
+	rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL);
+	rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass);
+
 	return 0;
 }
 
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index afb3bbd..be7d299 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -14,6 +14,7 @@ #include <linux/atmclip.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/file.h> /* for fput */
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/sock.h>
 
@@ -157,19 +158,6 @@ static unsigned long atm_tc_bind_filter(
 	return atm_tc_get(sch,classid);
 }
 
-
-static void destroy_filters(struct atm_flow_data *flow)
-{
-	struct tcf_proto *filter;
-
-	while ((filter = flow->filter_list)) {
-		DPRINTK("destroy_filters: destroying filter %p\n",filter);
-		flow->filter_list = filter->next;
-		tcf_destroy(filter);
-	}
-}
-
-
 /*
  * atm_tc_put handles all destructions, including the ones that are explicitly
  * requested (atm_tc_destroy, etc.). The assumption here is that we never drop
@@ -194,7 +182,7 @@ static void atm_tc_put(struct Qdisc *sch
 	*prev = flow->next;
 	DPRINTK("atm_tc_put: qdisc %p\n",flow->q);
 	qdisc_destroy(flow->q);
-	destroy_filters(flow);
+	tcf_destroy_chain(flow->filter_list);
 	if (flow->sock) {
 		DPRINTK("atm_tc_put: f_count %d\n",
 		    file_count(flow->sock->file));
@@ -503,7 +491,7 @@ static void sch_atm_dequeue(unsigned lon
 			}
 			D2PRINTK("atm_tc_dequeue: sending on class %p\n",flow);
 			/* remove any LL header somebody else has attached */
-			skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data);
+			skb_pull(skb, skb_network_offset(skb));
 			if (skb_headroom(skb) < flow->hdr_len) {
 				struct sk_buff *new;
 
@@ -513,7 +501,7 @@ static void sch_atm_dequeue(unsigned lon
 				skb = new;
 			}
 			D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
-			    skb->nh.iph,skb->data);
+				 skb_network_header(skb), skb->data);
 			ATM_SKB(skb)->vcc = flow->vcc;
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
 			    flow->hdr_len);
@@ -610,7 +598,7 @@ static void atm_tc_destroy(struct Qdisc 
 	DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p);
 	/* races ? */
 	while ((flow = p->flows)) {
-		destroy_filters(flow);
+		tcf_destroy_chain(flow->filter_list);
 		if (flow->ref > 1)
 			printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
 			    flow->ref);
@@ -631,7 +619,7 @@ static int atm_tc_dump_class(struct Qdis
 {
 	struct atm_qdisc_data *p = PRIV(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *) cl;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
@@ -661,11 +649,11 @@ static int atm_tc_dump_class(struct Qdis
 
 		RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(zero),&zero);
 	}
-	rta->rta_len = skb->tail-b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb,b-skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 static int
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 76c92e7..a294542 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -29,6 +29,7 @@ #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -112,7 +113,7 @@ #endif
 
 	/* Overlimit strategy parameters */
 	void			(*overlimit)(struct cbq_class *cl);
-	long			penalty;
+	psched_tdiff_t		penalty;
 
 	/* General scheduler (WRR) parameters */
 	long			allot;
@@ -143,7 +144,7 @@ #endif
 	psched_time_t		undertime;
 	long			avgidle;
 	long			deficit;	/* Saved deficit for WRR */
-	unsigned long		penalized;
+	psched_time_t		penalized;
 	struct gnet_stats_basic bstats;
 	struct gnet_stats_queue qstats;
 	struct gnet_stats_rate_est rate_est;
@@ -180,12 +181,12 @@ #endif
 	psched_time_t		now_rt;		/* Cached real time */
 	unsigned		pmask;
 
-	struct timer_list	delay_timer;
-	struct timer_list	wd_timer;	/* Watchdog timer,
+	struct hrtimer		delay_timer;
+	struct qdisc_watchdog	watchdog;	/* Watchdog timer,
 						   started when CBQ has
 						   backlog, but cannot
 						   transmit just now */
-	long			wd_expires;
+	psched_tdiff_t		wd_expires;
 	int			toplevel;
 	u32			hgenerator;
 };
@@ -384,12 +385,12 @@ cbq_mark_toplevel(struct cbq_sched_data 
 		psched_time_t now;
 		psched_tdiff_t incr;
 
-		PSCHED_GET_TIME(now);
-		incr = PSCHED_TDIFF(now, q->now_rt);
-		PSCHED_TADD2(q->now, incr, now);
+		now = psched_get_time();
+		incr = now - q->now_rt;
+		now = q->now + incr;
 
 		do {
-			if (PSCHED_TLESS(cl->undertime, now)) {
+			if (cl->undertime < now) {
 				q->toplevel = cl->level;
 				return;
 			}
@@ -473,7 +474,7 @@ #endif
 static void cbq_ovl_classic(struct cbq_class *cl)
 {
 	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
-	psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now);
+	psched_tdiff_t delay = cl->undertime - q->now;
 
 	if (!cl->delayed) {
 		delay += cl->offtime;
@@ -491,7 +492,7 @@ static void cbq_ovl_classic(struct cbq_c
 			cl->avgidle = cl->minidle;
 		if (delay <= 0)
 			delay = 1;
-		PSCHED_TADD2(q->now, delay, cl->undertime);
+		cl->undertime = q->now + delay;
 
 		cl->xstats.overactions++;
 		cl->delayed = 1;
@@ -508,7 +509,7 @@ static void cbq_ovl_classic(struct cbq_c
 		psched_tdiff_t base_delay = q->wd_expires;
 
 		for (b = cl->borrow; b; b = b->borrow) {
-			delay = PSCHED_TDIFF(b->undertime, q->now);
+			delay = b->undertime - q->now;
 			if (delay < base_delay) {
 				if (delay <= 0)
 					delay = 1;
@@ -546,27 +547,32 @@ static void cbq_ovl_rclassic(struct cbq_
 static void cbq_ovl_delay(struct cbq_class *cl)
 {
 	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
-	psched_tdiff_t delay = PSCHED_TDIFF(cl->undertime, q->now);
+	psched_tdiff_t delay = cl->undertime - q->now;
 
 	if (!cl->delayed) {
-		unsigned long sched = jiffies;
+		psched_time_t sched = q->now;
+		ktime_t expires;
 
 		delay += cl->offtime;
 		if (cl->avgidle < 0)
 			delay -= (-cl->avgidle) - ((-cl->avgidle) >> cl->ewma_log);
 		if (cl->avgidle < cl->minidle)
 			cl->avgidle = cl->minidle;
-		PSCHED_TADD2(q->now, delay, cl->undertime);
+		cl->undertime = q->now + delay;
 
 		if (delay > 0) {
-			sched += PSCHED_US2JIFFIE(delay) + cl->penalty;
+			sched += delay + cl->penalty;
 			cl->penalized = sched;
 			cl->cpriority = TC_CBQ_MAXPRIO;
 			q->pmask |= (1<<TC_CBQ_MAXPRIO);
-			if (del_timer(&q->delay_timer) &&
-			    (long)(q->delay_timer.expires - sched) > 0)
-				q->delay_timer.expires = sched;
-			add_timer(&q->delay_timer);
+
+			expires = ktime_set(0, 0);
+			expires = ktime_add_ns(expires, PSCHED_US2NS(sched));
+			if (hrtimer_try_to_cancel(&q->delay_timer) &&
+			    ktime_to_ns(ktime_sub(q->delay_timer.expires,
+						  expires)) > 0)
+				q->delay_timer.expires = expires;
+			hrtimer_restart(&q->delay_timer);
 			cl->delayed = 1;
 			cl->xstats.overactions++;
 			return;
@@ -583,7 +589,7 @@ static void cbq_ovl_lowprio(struct cbq_c
 {
 	struct cbq_sched_data *q = qdisc_priv(cl->qdisc);
 
-	cl->penalized = jiffies + cl->penalty;
+	cl->penalized = q->now + cl->penalty;
 
 	if (cl->cpriority != cl->priority2) {
 		cl->cpriority = cl->priority2;
@@ -604,27 +610,19 @@ static void cbq_ovl_drop(struct cbq_clas
 	cbq_ovl_classic(cl);
 }
 
-static void cbq_watchdog(unsigned long arg)
-{
-	struct Qdisc *sch = (struct Qdisc*)arg;
-
-	sch->flags &= ~TCQ_F_THROTTLED;
-	netif_schedule(sch->dev);
-}
-
-static unsigned long cbq_undelay_prio(struct cbq_sched_data *q, int prio)
+static psched_tdiff_t cbq_undelay_prio(struct cbq_sched_data *q, int prio,
+				       psched_time_t now)
 {
 	struct cbq_class *cl;
 	struct cbq_class *cl_prev = q->active[prio];
-	unsigned long now = jiffies;
-	unsigned long sched = now;
+	psched_time_t sched = now;
 
 	if (cl_prev == NULL)
-		return now;
+		return 0;
 
 	do {
 		cl = cl_prev->next_alive;
-		if ((long)(now - cl->penalized) > 0) {
+		if (now - cl->penalized > 0) {
 			cl_prev->next_alive = cl->next_alive;
 			cl->next_alive = NULL;
 			cl->cpriority = cl->priority;
@@ -640,30 +638,34 @@ static unsigned long cbq_undelay_prio(st
 			}
 
 			cl = cl_prev->next_alive;
-		} else if ((long)(sched - cl->penalized) > 0)
+		} else if (sched - cl->penalized > 0)
 			sched = cl->penalized;
 	} while ((cl_prev = cl) != q->active[prio]);
 
-	return (long)(sched - now);
+	return sched - now;
 }
 
-static void cbq_undelay(unsigned long arg)
+static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
 {
-	struct Qdisc *sch = (struct Qdisc*)arg;
-	struct cbq_sched_data *q = qdisc_priv(sch);
-	long delay = 0;
+	struct cbq_sched_data *q = container_of(timer, struct cbq_sched_data,
+						delay_timer);
+	struct Qdisc *sch = q->watchdog.qdisc;
+	psched_time_t now;
+	psched_tdiff_t delay = 0;
 	unsigned pmask;
 
+	now = psched_get_time();
+
 	pmask = q->pmask;
 	q->pmask = 0;
 
 	while (pmask) {
 		int prio = ffz(~pmask);
-		long tmp;
+		psched_tdiff_t tmp;
 
 		pmask &= ~(1<<prio);
 
-		tmp = cbq_undelay_prio(q, prio);
+		tmp = cbq_undelay_prio(q, prio, now);
 		if (tmp > 0) {
 			q->pmask |= 1<<prio;
 			if (tmp < delay || delay == 0)
@@ -672,12 +674,16 @@ static void cbq_undelay(unsigned long ar
 	}
 
 	if (delay) {
-		q->delay_timer.expires = jiffies + delay;
-		add_timer(&q->delay_timer);
+		ktime_t time;
+
+		time = ktime_set(0, 0);
+		time = ktime_add_ns(time, PSCHED_US2NS(now + delay));
+		hrtimer_start(&q->delay_timer, time, HRTIMER_MODE_ABS);
 	}
 
 	sch->flags &= ~TCQ_F_THROTTLED;
 	netif_schedule(sch->dev);
+	return HRTIMER_NORESTART;
 }
 
 
@@ -732,7 +738,7 @@ cbq_update_toplevel(struct cbq_sched_dat
 	if (cl && q->toplevel >= borrowed->level) {
 		if (cl->q->q.qlen > 1) {
 			do {
-				if (PSCHED_IS_PASTPERFECT(borrowed->undertime)) {
+				if (borrowed->undertime == PSCHED_PASTPERFECT) {
 					q->toplevel = borrowed->level;
 					return;
 				}
@@ -770,7 +776,7 @@ cbq_update(struct cbq_sched_data *q)
 			 idle = (now - last) - last_pktlen/rate
 		 */
 
-		idle = PSCHED_TDIFF(q->now, cl->last);
+		idle = q->now - cl->last;
 		if ((unsigned long)idle > 128*1024*1024) {
 			avgidle = cl->maxidle;
 		} else {
@@ -814,13 +820,11 @@ cbq_update(struct cbq_sched_data *q)
 			idle -= L2T(&q->link, len);
 			idle += L2T(cl, len);
 
-			PSCHED_AUDIT_TDIFF(idle);
-
-			PSCHED_TADD2(q->now, idle, cl->undertime);
+			cl->undertime = q->now + idle;
 		} else {
 			/* Underlimit */
 
-			PSCHED_SET_PASTPERFECT(cl->undertime);
+			cl->undertime = PSCHED_PASTPERFECT;
 			if (avgidle > cl->maxidle)
 				cl->avgidle = cl->maxidle;
 			else
@@ -841,8 +845,7 @@ cbq_under_limit(struct cbq_class *cl)
 	if (cl->tparent == NULL)
 		return cl;
 
-	if (PSCHED_IS_PASTPERFECT(cl->undertime) ||
-	    !PSCHED_TLESS(q->now, cl->undertime)) {
+	if (cl->undertime == PSCHED_PASTPERFECT || q->now >= cl->undertime) {
 		cl->delayed = 0;
 		return cl;
 	}
@@ -865,8 +868,7 @@ cbq_under_limit(struct cbq_class *cl)
 		}
 		if (cl->level > q->toplevel)
 			return NULL;
-	} while (!PSCHED_IS_PASTPERFECT(cl->undertime) &&
-		 PSCHED_TLESS(q->now, cl->undertime));
+	} while (cl->undertime != PSCHED_PASTPERFECT && q->now < cl->undertime);
 
 	cl->delayed = 0;
 	return cl;
@@ -1001,8 +1003,8 @@ cbq_dequeue(struct Qdisc *sch)
 	psched_time_t now;
 	psched_tdiff_t incr;
 
-	PSCHED_GET_TIME(now);
-	incr = PSCHED_TDIFF(now, q->now_rt);
+	now = psched_get_time();
+	incr = now - q->now_rt;
 
 	if (q->tx_class) {
 		psched_tdiff_t incr2;
@@ -1014,12 +1016,12 @@ cbq_dequeue(struct Qdisc *sch)
 		   cbq_time = max(real_time, work);
 		 */
 		incr2 = L2T(&q->link, q->tx_len);
-		PSCHED_TADD(q->now, incr2);
+		q->now += incr2;
 		cbq_update(q);
 		if ((incr -= incr2) < 0)
 			incr = 0;
 	}
-	PSCHED_TADD(q->now, incr);
+	q->now += incr;
 	q->now_rt = now;
 
 	for (;;) {
@@ -1051,11 +1053,11 @@ cbq_dequeue(struct Qdisc *sch)
 		*/
 
 		if (q->toplevel == TC_CBQ_MAXLEVEL &&
-		    PSCHED_IS_PASTPERFECT(q->link.undertime))
+		    q->link.undertime == PSCHED_PASTPERFECT)
 			break;
 
 		q->toplevel = TC_CBQ_MAXLEVEL;
-		PSCHED_SET_PASTPERFECT(q->link.undertime);
+		q->link.undertime = PSCHED_PASTPERFECT;
 	}
 
 	/* No packets in scheduler or nobody wants to give them to us :-(
@@ -1063,13 +1065,9 @@ cbq_dequeue(struct Qdisc *sch)
 
 	if (sch->q.qlen) {
 		sch->qstats.overlimits++;
-		if (q->wd_expires) {
-			long delay = PSCHED_US2JIFFIE(q->wd_expires);
-			if (delay <= 0)
-				delay = 1;
-			mod_timer(&q->wd_timer, jiffies + delay);
-			sch->flags |= TCQ_F_THROTTLED;
-		}
+		if (q->wd_expires)
+			qdisc_watchdog_schedule(&q->watchdog,
+						now + q->wd_expires);
 	}
 	return NULL;
 }
@@ -1276,10 +1274,10 @@ cbq_reset(struct Qdisc* sch)
 	q->pmask = 0;
 	q->tx_class = NULL;
 	q->tx_borrowed = NULL;
-	del_timer(&q->wd_timer);
-	del_timer(&q->delay_timer);
+	qdisc_watchdog_cancel(&q->watchdog);
+	hrtimer_cancel(&q->delay_timer);
 	q->toplevel = TC_CBQ_MAXLEVEL;
-	PSCHED_GET_TIME(q->now);
+	q->now = psched_get_time();
 	q->now_rt = q->now;
 
 	for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
@@ -1290,7 +1288,7 @@ cbq_reset(struct Qdisc* sch)
 			qdisc_reset(cl->q);
 
 			cl->next_alive = NULL;
-			PSCHED_SET_PASTPERFECT(cl->undertime);
+			cl->undertime = PSCHED_PASTPERFECT;
 			cl->avgidle = cl->maxidle;
 			cl->deficit = cl->quantum;
 			cl->cpriority = cl->priority;
@@ -1379,7 +1377,7 @@ static int cbq_set_overlimit(struct cbq_
 	default:
 		return -EINVAL;
 	}
-	cl->penalty = (ovl->penalty*HZ)/1000;
+	cl->penalty = ovl->penalty;
 	return 0;
 }
 
@@ -1446,14 +1444,11 @@ static int cbq_init(struct Qdisc *sch, s
 	q->link.minidle = -0x7FFFFFFF;
 	q->link.stats_lock = &sch->dev->queue_lock;
 
-	init_timer(&q->wd_timer);
-	q->wd_timer.data = (unsigned long)sch;
-	q->wd_timer.function = cbq_watchdog;
-	init_timer(&q->delay_timer);
-	q->delay_timer.data = (unsigned long)sch;
+	qdisc_watchdog_init(&q->watchdog, sch);
+	hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	q->delay_timer.function = cbq_undelay;
 	q->toplevel = TC_CBQ_MAXLEVEL;
-	PSCHED_GET_TIME(q->now);
+	q->now = psched_get_time();
 	q->now_rt = q->now;
 
 	cbq_link_class(&q->link);
@@ -1467,19 +1462,19 @@ static int cbq_init(struct Qdisc *sch, s
 
 static __inline__ int cbq_dump_rate(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	RTA_PUT(skb, TCA_CBQ_RATE, sizeof(cl->R_tab->rate), &cl->R_tab->rate);
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 static __inline__ int cbq_dump_lss(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_cbq_lssopt opt;
 
 	opt.flags = 0;
@@ -1498,13 +1493,13 @@ static __inline__ int cbq_dump_lss(struc
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 static __inline__ int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_cbq_wrropt opt;
 
 	opt.flags = 0;
@@ -1516,30 +1511,30 @@ static __inline__ int cbq_dump_wrr(struc
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_cbq_ovl opt;
 
 	opt.strategy = cl->ovl_strategy;
 	opt.priority2 = cl->priority2+1;
 	opt.pad = 0;
-	opt.penalty = (cl->penalty*1000)/HZ;
+	opt.penalty = cl->penalty;
 	RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 static __inline__ int cbq_dump_fopt(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_cbq_fopt opt;
 
 	if (cl->split || cl->defmap) {
@@ -1551,14 +1546,14 @@ static __inline__ int cbq_dump_fopt(stru
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
 #ifdef CONFIG_NET_CLS_POLICE
 static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
 {
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_cbq_police opt;
 
 	if (cl->police) {
@@ -1570,7 +1565,7 @@ static __inline__ int cbq_dump_police(st
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 #endif
@@ -1592,18 +1587,18 @@ #endif
 static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct cbq_sched_data *q = qdisc_priv(sch);
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	rta = (struct rtattr*)b;
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 	if (cbq_dump_attr(skb, &q->link) < 0)
 		goto rtattr_failure;
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1621,7 +1616,7 @@ cbq_dump_class(struct Qdisc *sch, unsign
 	       struct sk_buff *skb, struct tcmsg *tcm)
 {
 	struct cbq_class *cl = (struct cbq_class*)arg;
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	if (cl->tparent)
@@ -1635,11 +1630,11 @@ cbq_dump_class(struct Qdisc *sch, unsign
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 	if (cbq_dump_attr(skb, cl) < 0)
 		goto rtattr_failure;
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1654,8 +1649,8 @@ cbq_dump_class_stats(struct Qdisc *sch, 
 	cl->xstats.avgidle = cl->avgidle;
 	cl->xstats.undertime = 0;
 
-	if (!PSCHED_IS_PASTPERFECT(cl->undertime))
-		cl->xstats.undertime = PSCHED_TDIFF(cl->undertime, q->now);
+	if (cl->undertime != PSCHED_PASTPERFECT)
+		cl->xstats.undertime = cl->undertime - q->now;
 
 	if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
 #ifdef CONFIG_NET_ESTIMATOR
@@ -1722,23 +1717,13 @@ static unsigned long cbq_get(struct Qdis
 	return 0;
 }
 
-static void cbq_destroy_filters(struct cbq_class *cl)
-{
-	struct tcf_proto *tp;
-
-	while ((tp = cl->filter_list) != NULL) {
-		cl->filter_list = tp->next;
-		tcf_destroy(tp);
-	}
-}
-
 static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
 {
 	struct cbq_sched_data *q = qdisc_priv(sch);
 
 	BUG_TRAP(!cl->filters);
 
-	cbq_destroy_filters(cl);
+	tcf_destroy_chain(cl->filter_list);
 	qdisc_destroy(cl->q);
 	qdisc_put_rtab(cl->R_tab);
 #ifdef CONFIG_NET_ESTIMATOR
@@ -1765,7 +1750,7 @@ #endif
 	 */
 	for (h = 0; h < 16; h++)
 		for (cl = q->classes[h]; cl; cl = cl->next)
-			cbq_destroy_filters(cl);
+			tcf_destroy_chain(cl->filter_list);
 
 	for (h = 0; h < 16; h++) {
 		struct cbq_class *next;
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 96324cf..3c6fd18 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -216,17 +216,17 @@ static int dsmark_enqueue(struct sk_buff
 		/* FIXME: Safe with non-linear skbs? --RR */
 		switch (skb->protocol) {
 			case __constant_htons(ETH_P_IP):
-				skb->tc_index = ipv4_get_dsfield(skb->nh.iph)
+				skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
 					& ~INET_ECN_MASK;
 				break;
 			case __constant_htons(ETH_P_IPV6):
-				skb->tc_index = ipv6_get_dsfield(skb->nh.ipv6h)
+				skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))
 					& ~INET_ECN_MASK;
 				break;
 			default:
 				skb->tc_index = 0;
 				break;
-		};
+		}
 	}
 
 	if (TC_H_MAJ(skb->priority) == sch->handle)
@@ -257,7 +257,7 @@ #endif
 				if (p->default_index != NO_DEFAULT_INDEX)
 					skb->tc_index = p->default_index;
 				break;
-		};
+		}
 	}
 
 	err = p->q->enqueue(skb,p->q);
@@ -292,11 +292,11 @@ static struct sk_buff *dsmark_dequeue(st
 
 	switch (skb->protocol) {
 		case __constant_htons(ETH_P_IP):
-			ipv4_change_dsfield(skb->nh.iph, p->mask[index],
+			ipv4_change_dsfield(ip_hdr(skb), p->mask[index],
 					    p->value[index]);
 			break;
 		case __constant_htons(ETH_P_IPV6):
-			ipv6_change_dsfield(skb->nh.ipv6h, p->mask[index],
+			ipv6_change_dsfield(ipv6_hdr(skb), p->mask[index],
 					    p->value[index]);
 			break;
 		default:
@@ -310,7 +310,7 @@ static struct sk_buff *dsmark_dequeue(st
 				       "unsupported protocol %d\n",
 				       ntohs(skb->protocol));
 			break;
-	};
+	}
 
 	return skb;
 }
@@ -412,16 +412,10 @@ static void dsmark_reset(struct Qdisc *s
 static void dsmark_destroy(struct Qdisc *sch)
 {
 	struct dsmark_qdisc_data *p = PRIV(sch);
-	struct tcf_proto *tp;
 
 	DPRINTK("dsmark_destroy(sch %p,[qdisc %p])\n", sch, p);
 
-	while (p->filter_list) {
-		tp = p->filter_list;
-		p->filter_list = tp->next;
-		tcf_destroy(tp);
-	}
-
+	tcf_destroy_chain(p->filter_list);
 	qdisc_destroy(p->q);
 	kfree(p->mask);
 }
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 52eb343..3385ee5 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -36,34 +36,27 @@ #include <net/pkt_sched.h>
 
 /* Main transmission queue. */
 
-/* Main qdisc structure lock.
-
-   However, modifications
-   to data, participating in scheduling must be additionally
-   protected with dev->queue_lock spinlock.
-
-   The idea is the following:
-   - enqueue, dequeue are serialized via top level device
-     spinlock dev->queue_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 only under rtnl semaphore,
-     hence this lock may be made without local bh disabling.
-
-   qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
+/* Modifications to data participating in scheduling must be protected with
+ * dev->queue_lock spinlock.
+ *
+ * The idea is the following:
+ * - enqueue, dequeue are serialized via top level device
+ *   spinlock dev->queue_lock.
+ * - ingress filtering is serialized via top level device
+ *   spinlock dev->ingress_lock.
+ * - updates to tree and tree walking are only done under the rtnl mutex.
  */
-DEFINE_RWLOCK(qdisc_tree_lock);
 
 void qdisc_lock_tree(struct net_device *dev)
 {
-	write_lock(&qdisc_tree_lock);
 	spin_lock_bh(&dev->queue_lock);
+	spin_lock(&dev->ingress_lock);
 }
 
 void qdisc_unlock_tree(struct net_device *dev)
 {
+	spin_unlock(&dev->ingress_lock);
 	spin_unlock_bh(&dev->queue_lock);
-	write_unlock(&qdisc_tree_lock);
 }
 
 /*
@@ -442,7 +435,6 @@ struct Qdisc *qdisc_alloc(struct net_dev
 	sch->dequeue = ops->dequeue;
 	sch->dev = dev;
 	dev_hold(dev);
-	sch->stats_lock = &dev->queue_lock;
 	atomic_set(&sch->refcnt, 1);
 
 	return sch;
@@ -458,6 +450,7 @@ struct Qdisc * qdisc_create_dflt(struct 
 	sch = qdisc_alloc(dev, ops);
 	if (IS_ERR(sch))
 		goto errout;
+	sch->stats_lock = &dev->queue_lock;
 	sch->parent = parentid;
 
 	if (!ops->init || ops->init(sch, NULL) == 0)
@@ -528,15 +521,11 @@ void dev_activate(struct net_device *dev
 				printk(KERN_INFO "%s: activation failed\n", dev->name);
 				return;
 			}
-			write_lock(&qdisc_tree_lock);
 			list_add_tail(&qdisc->list, &dev->qdisc_list);
-			write_unlock(&qdisc_tree_lock);
 		} else {
 			qdisc =  &noqueue_qdisc;
 		}
-		write_lock(&qdisc_tree_lock);
 		dev->qdisc_sleeping = qdisc;
-		write_unlock(&qdisc_tree_lock);
 	}
 
 	if (!netif_carrier_ok(dev))
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 407c6fb..9d124c4 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -59,13 +59,13 @@ #include <linux/spinlock.h>
 #include <linux/skbuff.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
 #include <asm/system.h>
@@ -192,23 +192,9 @@ struct hfsc_sched
 	struct list_head droplist;		/* active leaf class list (for
 						   dropping) */
 	struct sk_buff_head requeue;		/* requeued packet */
-	struct timer_list wd_timer;		/* watchdog timer */
+	struct qdisc_watchdog watchdog;		/* watchdog timer */
 };
 
-/*
- * macros
- */
-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
-#include <linux/time.h>
-#undef PSCHED_GET_TIME
-#define PSCHED_GET_TIME(stamp)						\
-do {									\
-	struct timeval tv;						\
-	do_gettimeofday(&tv);						\
-	(stamp) = 1ULL * USEC_PER_SEC * tv.tv_sec + tv.tv_usec;		\
-} while (0)
-#endif
-
 #define	HT_INFINITY	0xffffffffffffffffULL	/* infinite time value */
 
 
@@ -394,28 +380,17 @@ cftree_update(struct hfsc_class *cl)
  *	ism: (psched_us/byte) << ISM_SHIFT
  *	dx: psched_us
  *
- * Clock source resolution (CONFIG_NET_SCH_CLK_*)
- *  JIFFIES: for 48<=HZ<=1534 resolution is between 0.63us and 1.27us.
- *  CPU: resolution is between 0.5us and 1us.
- *  GETTIMEOFDAY: resolution is exactly 1us.
+ * The clock source resolution with ktime is 1.024us.
  *
  * sm and ism are scaled in order to keep effective digits.
  * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective
  * digits in decimal using the following table.
  *
- * Note: We can afford the additional accuracy (altq hfsc keeps at most
- * 3 effective digits) thanks to the fact that linux clock is bounded
- * much more tightly.
- *
  *  bits/sec      100Kbps     1Mbps     10Mbps     100Mbps    1Gbps
  *  ------------+-------------------------------------------------------
- *  bytes/0.5us   6.25e-3    62.5e-3    625e-3     6250e-e    62500e-3
- *  bytes/us      12.5e-3    125e-3     1250e-3    12500e-3   125000e-3
- *  bytes/1.27us  15.875e-3  158.75e-3  1587.5e-3  15875e-3   158750e-3
+ *  bytes/1.024us 12.8e-3    128e-3     1280e-3    12800e-3   128000e-3
  *
- *  0.5us/byte    160        16         1.6        0.16       0.016
- *  us/byte       80         8          0.8        0.08       0.008
- *  1.27us/byte   63         6.3        0.63       0.063      0.0063
+ *  1.024us/byte  78.125     7.8125     0.78125    0.078125   0.0078125
  */
 #define	SM_SHIFT	20
 #define	ISM_SHIFT	18
@@ -460,8 +435,8 @@ m2sm(u32 m)
 	u64 sm;
 
 	sm = ((u64)m << SM_SHIFT);
-	sm += PSCHED_JIFFIE2US(HZ) - 1;
-	do_div(sm, PSCHED_JIFFIE2US(HZ));
+	sm += PSCHED_TICKS_PER_SEC - 1;
+	do_div(sm, PSCHED_TICKS_PER_SEC);
 	return sm;
 }
 
@@ -474,7 +449,7 @@ m2ism(u32 m)
 	if (m == 0)
 		ism = HT_INFINITY;
 	else {
-		ism = ((u64)PSCHED_JIFFIE2US(HZ) << ISM_SHIFT);
+		ism = ((u64)PSCHED_TICKS_PER_SEC << ISM_SHIFT);
 		ism += m - 1;
 		do_div(ism, m);
 	}
@@ -487,7 +462,7 @@ d2dx(u32 d)
 {
 	u64 dx;
 
-	dx = ((u64)d * PSCHED_JIFFIE2US(HZ));
+	dx = ((u64)d * PSCHED_TICKS_PER_SEC);
 	dx += USEC_PER_SEC - 1;
 	do_div(dx, USEC_PER_SEC);
 	return dx;
@@ -499,7 +474,7 @@ sm2m(u64 sm)
 {
 	u64 m;
 
-	m = (sm * PSCHED_JIFFIE2US(HZ)) >> SM_SHIFT;
+	m = (sm * PSCHED_TICKS_PER_SEC) >> SM_SHIFT;
 	return (u32)m;
 }
 
@@ -510,7 +485,7 @@ dx2d(u64 dx)
 	u64 d;
 
 	d = dx * USEC_PER_SEC;
-	do_div(d, PSCHED_JIFFIE2US(HZ));
+	do_div(d, PSCHED_TICKS_PER_SEC);
 	return (u32)d;
 }
 
@@ -654,9 +629,7 @@ rtsc_min(struct runtime_sc *rtsc, struct
 static void
 init_ed(struct hfsc_class *cl, unsigned int next_len)
 {
-	u64 cur_time;
-
-	PSCHED_GET_TIME(cur_time);
+	u64 cur_time = psched_get_time();
 
 	/* update the deadline curve */
 	rtsc_min(&cl->cl_deadline, &cl->cl_rsc, cur_time, cl->cl_cumul);
@@ -779,7 +752,7 @@ init_vf(struct hfsc_class *cl, unsigned 
 			if (cl->cl_flags & HFSC_USC) {
 				/* class has upper limit curve */
 				if (cur_time == 0)
-					PSCHED_GET_TIME(cur_time);
+					cur_time = psched_get_time();
 
 				/* update the ulimit curve */
 				rtsc_min(&cl->cl_ulimit, &cl->cl_usc, cur_time,
@@ -1063,7 +1036,7 @@ hfsc_change_class(struct Qdisc *sch, u32
 			if (cl->cl_parent == NULL && parentid != TC_H_ROOT)
 				return -EINVAL;
 		}
-		PSCHED_GET_TIME(cur_time);
+		cur_time = psched_get_time();
 
 		sch_tree_lock(sch);
 		if (rsc != NULL)
@@ -1149,22 +1122,11 @@ #endif
 }
 
 static void
-hfsc_destroy_filters(struct tcf_proto **fl)
-{
-	struct tcf_proto *tp;
-
-	while ((tp = *fl) != NULL) {
-		*fl = tp->next;
-		tcf_destroy(tp);
-	}
-}
-
-static void
 hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl)
 {
 	struct hfsc_sched *q = qdisc_priv(sch);
 
-	hfsc_destroy_filters(&cl->filter_list);
+	tcf_destroy_chain(cl->filter_list);
 	qdisc_destroy(cl->qdisc);
 #ifdef CONFIG_NET_ESTIMATOR
 	gen_kill_estimator(&cl->bstats, &cl->rate_est);
@@ -1389,7 +1351,7 @@ hfsc_dump_class(struct Qdisc *sch, unsig
 		struct tcmsg *tcm)
 {
 	struct hfsc_class *cl = (struct hfsc_class *)arg;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta = (struct rtattr *)b;
 
 	tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT;
@@ -1400,11 +1362,11 @@ hfsc_dump_class(struct Qdisc *sch, unsig
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
 	if (hfsc_dump_curves(skb, cl) < 0)
 		goto rtattr_failure;
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
  rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1459,21 +1421,11 @@ hfsc_walk(struct Qdisc *sch, struct qdis
 }
 
 static void
-hfsc_watchdog(unsigned long arg)
-{
-	struct Qdisc *sch = (struct Qdisc *)arg;
-
-	sch->flags &= ~TCQ_F_THROTTLED;
-	netif_schedule(sch->dev);
-}
-
-static void
-hfsc_schedule_watchdog(struct Qdisc *sch, u64 cur_time)
+hfsc_schedule_watchdog(struct Qdisc *sch)
 {
 	struct hfsc_sched *q = qdisc_priv(sch);
 	struct hfsc_class *cl;
 	u64 next_time = 0;
-	long delay;
 
 	if ((cl = eltree_get_minel(q)) != NULL)
 		next_time = cl->cl_e;
@@ -1482,11 +1434,7 @@ hfsc_schedule_watchdog(struct Qdisc *sch
 			next_time = q->root.cl_cfmin;
 	}
 	WARN_ON(next_time == 0);
-	delay = next_time - cur_time;
-	delay = PSCHED_US2JIFFIE(delay);
-
-	sch->flags |= TCQ_F_THROTTLED;
-	mod_timer(&q->wd_timer, jiffies + delay);
+	qdisc_watchdog_schedule(&q->watchdog, next_time);
 }
 
 static int
@@ -1523,9 +1471,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struc
 
 	list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]);
 
-	init_timer(&q->wd_timer);
-	q->wd_timer.function = hfsc_watchdog;
-	q->wd_timer.data = (unsigned long)sch;
+	qdisc_watchdog_init(&q->watchdog, sch);
 
 	return 0;
 }
@@ -1595,8 +1541,7 @@ hfsc_reset_qdisc(struct Qdisc *sch)
 	__skb_queue_purge(&q->requeue);
 	q->eligible = RB_ROOT;
 	INIT_LIST_HEAD(&q->droplist);
-	del_timer(&q->wd_timer);
-	sch->flags &= ~TCQ_F_THROTTLED;
+	qdisc_watchdog_cancel(&q->watchdog);
 	sch->q.qlen = 0;
 }
 
@@ -1612,14 +1557,14 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
 			hfsc_destroy_class(sch, cl);
 	}
 	__skb_queue_purge(&q->requeue);
-	del_timer(&q->wd_timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 }
 
 static int
 hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct hfsc_sched *q = qdisc_priv(sch);
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_hfsc_qopt qopt;
 
 	qopt.defcls = q->defcls;
@@ -1627,7 +1572,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struc
 	return skb->len;
 
  rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1681,7 +1626,7 @@ hfsc_dequeue(struct Qdisc *sch)
 	if ((skb = __skb_dequeue(&q->requeue)))
 		goto out;
 
-	PSCHED_GET_TIME(cur_time);
+	cur_time = psched_get_time();
 
 	/*
 	 * if there are eligible classes, use real-time criteria.
@@ -1698,7 +1643,7 @@ hfsc_dequeue(struct Qdisc *sch)
 		cl = vttree_get_minvt(&q->root, cur_time);
 		if (cl == NULL) {
 			sch->qstats.overlimits++;
-			hfsc_schedule_watchdog(sch, cur_time);
+			hfsc_schedule_watchdog(sch);
 			return NULL;
 		}
 	}
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 3c3294d..99bcec8 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -50,6 +50,7 @@ #include <net/route.h>
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/compiler.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 #include <linux/rbtree.h>
@@ -128,7 +129,7 @@ #endif
 	} 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 */
+	psched_time_t pq_key;
 
 	int prio_activity;	/* for which prios are we active */
 	enum htb_cmode cmode;	/* current mode of the class */
@@ -179,10 +180,7 @@ struct htb_sched {
 	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;
+	psched_time_t near_ev_cache[TC_HTB_MAXDEPTH];
 
 	/* whether we hit non-work conserving class during this dequeue; we use */
 	int nwc_hit;		/* this to disable mindelay complaint in dequeue */
@@ -195,7 +193,7 @@ struct htb_sched {
 
 	int rate2quantum;	/* quant = rate / rate2quantum */
 	psched_time_t now;	/* cached dequeue time */
-	struct timer_list timer;	/* send delay timer */
+	struct qdisc_watchdog watchdog;
 #ifdef HTB_RATECM
 	struct timer_list rttim;	/* rate computer timer */
 	int recmp_bucket;	/* which hash bucket to recompute next */
@@ -342,19 +340,19 @@ static void htb_add_to_wait_tree(struct 
 {
 	struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL;
 
-	cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay);
-	if (cl->pq_key == q->jiffies)
+	cl->pq_key = q->now + delay;
+	if (cl->pq_key == q->now)
 		cl->pq_key++;
 
 	/* update the nearest event cache */
-	if (time_after(q->near_ev_cache[cl->level], cl->pq_key))
+	if (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;
 		c = rb_entry(parent, struct htb_class, pq_node);
-		if (time_after_eq(cl->pq_key, c->pq_key))
+		if (cl->pq_key >= c->pq_key)
 			p = &parent->rb_right;
 		else
 			p = &parent->rb_left;
@@ -679,14 +677,6 @@ static int htb_requeue(struct sk_buff *s
 	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);
-}
-
 #ifdef HTB_RATECM
 #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
 static void htb_rate_timer(unsigned long arg)
@@ -739,7 +729,7 @@ #define HTB_ACCNT(T,B,R) toks = diff + c
 	cl->T = toks
 
 	while (cl) {
-		diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
+		diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer);
 		if (cl->level >= level) {
 			if (cl->level == level)
 				cl->xstats.lends++;
@@ -778,11 +768,11 @@ #endif
 /**
  * htb_do_events - make mode changes to classes at the level
  *
- * Scans event queue for pending events and applies them. Returns jiffies to
+ * Scans event queue for pending events and applies them. Returns time of
  * next pending event (0 for no event in pq).
- * Note: Aplied are events whose have cl->pq_key <= jiffies.
+ * Note: Applied are events whose have cl->pq_key <= q->now.
  */
-static long htb_do_events(struct htb_sched *q, int level)
+static psched_time_t htb_do_events(struct htb_sched *q, int level)
 {
 	int i;
 
@@ -795,18 +785,18 @@ static long htb_do_events(struct htb_sch
 			return 0;
 
 		cl = rb_entry(p, struct htb_class, pq_node);
-		if (time_after(cl->pq_key, q->jiffies)) {
-			return cl->pq_key - q->jiffies;
-		}
+		if (cl->pq_key > q->now)
+			return cl->pq_key;
+
 		htb_safe_rb_erase(p, q->wait_pq + level);
-		diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer);
+		diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer);
 		htb_change_class_mode(q, cl, &diff);
 		if (cl->cmode != HTB_CAN_SEND)
 			htb_add_to_wait_tree(q, cl, diff);
 	}
 	if (net_ratelimit())
 		printk(KERN_WARNING "htb: too many events !\n");
-	return HZ / 10;
+	return q->now + PSCHED_TICKS_PER_SEC / 10;
 }
 
 /* Returns class->node+prio from id-tree where classe's id is >= id. NULL
@@ -958,30 +948,12 @@ next:
 	return skb;
 }
 
-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 (net_ratelimit())
-			printk(KERN_INFO "HTB delay %ld > 5sec\n", delay);
-		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++;
-}
-
 static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 {
 	struct sk_buff *skb = NULL;
 	struct htb_sched *q = qdisc_priv(sch);
 	int level;
-	long min_delay;
-
-	q->jiffies = jiffies;
+	psched_time_t next_event;
 
 	/* try to dequeue direct packets as high prio (!) to minimize cpu work */
 	skb = __skb_dequeue(&q->direct_queue);
@@ -993,23 +965,25 @@ static struct sk_buff *htb_dequeue(struc
 
 	if (!sch->q.qlen)
 		goto fin;
-	PSCHED_GET_TIME(q->now);
+	q->now = psched_get_time();
 
-	min_delay = LONG_MAX;
+	next_event = q->now + 5 * PSCHED_TICKS_PER_SEC;
 	q->nwc_hit = 0;
 	for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
 		/* common case optimization - skip event handler quickly */
 		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);
+		psched_time_t event;
+
+		if (q->now >= q->near_ev_cache[level]) {
+			event = htb_do_events(q, level);
+			q->near_ev_cache[level] = event ? event :
+							  PSCHED_TICKS_PER_SEC;
 		} else
-			delay = q->near_ev_cache[level] - q->jiffies;
+			event = q->near_ev_cache[level];
+
+		if (event && next_event > event)
+			next_event = event;
 
-		if (delay && min_delay > delay)
-			min_delay = delay;
 		m = ~q->row_mask[level];
 		while (m != (int)(-1)) {
 			int prio = ffz(m);
@@ -1022,7 +996,8 @@ static struct sk_buff *htb_dequeue(struc
 			}
 		}
 	}
-	htb_delay_by(sch, min_delay > 5 * HZ ? 5 * HZ : min_delay);
+	sch->qstats.overlimits++;
+	qdisc_watchdog_schedule(&q->watchdog, next_event);
 fin:
 	return skb;
 }
@@ -1075,8 +1050,7 @@ static void htb_reset(struct Qdisc *sch)
 
 		}
 	}
-	sch->flags &= ~TCQ_F_THROTTLED;
-	del_timer(&q->timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 	__skb_queue_purge(&q->direct_queue);
 	sch->q.qlen = 0;
 	memset(q->row, 0, sizeof(q->row));
@@ -1113,14 +1087,12 @@ static int htb_init(struct Qdisc *sch, s
 	for (i = 0; i < TC_HTB_NUMPRIO; i++)
 		INIT_LIST_HEAD(q->drops + i);
 
-	init_timer(&q->timer);
+	qdisc_watchdog_init(&q->watchdog, sch);
 	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 */
 		q->direct_qlen = 2;
-	q->timer.function = htb_timer;
-	q->timer.data = (unsigned long)sch;
 
 #ifdef HTB_RATECM
 	init_timer(&q->rttim);
@@ -1139,7 +1111,7 @@ #endif
 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_pointer(skb);
 	struct rtattr *rta;
 	struct tc_htb_glob gopt;
 	spin_lock_bh(&sch->dev->queue_lock);
@@ -1152,12 +1124,12 @@ static int htb_dump(struct Qdisc *sch, s
 	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;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	spin_unlock_bh(&sch->dev->queue_lock);
 	return skb->len;
 rtattr_failure:
 	spin_unlock_bh(&sch->dev->queue_lock);
-	skb_trim(skb, skb->tail - skb->data);
+	nlmsg_trim(skb, skb_tail_pointer(skb));
 	return -1;
 }
 
@@ -1165,7 +1137,7 @@ static int htb_dump_class(struct Qdisc *
 			  struct sk_buff *skb, struct tcmsg *tcm)
 {
 	struct htb_class *cl = (struct htb_class *)arg;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 	struct tc_htb_opt opt;
 
@@ -1188,12 +1160,12 @@ static int htb_dump_class(struct Qdisc *
 	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;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	spin_unlock_bh(&sch->dev->queue_lock);
 	return skb->len;
 rtattr_failure:
 	spin_unlock_bh(&sch->dev->queue_lock);
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1264,16 +1236,6 @@ static unsigned long htb_get(struct Qdis
 	return (unsigned long)cl;
 }
 
-static void htb_destroy_filters(struct tcf_proto **fl)
-{
-	struct tcf_proto *tp;
-
-	while ((tp = *fl) != NULL) {
-		*fl = tp->next;
-		tcf_destroy(tp);
-	}
-}
-
 static inline int htb_parent_last_child(struct htb_class *cl)
 {
 	if (!cl->parent)
@@ -1302,7 +1264,7 @@ static void htb_parent_to_leaf(struct ht
 	parent->un.leaf.prio = parent->prio;
 	parent->tokens = parent->buffer;
 	parent->ctokens = parent->cbuffer;
-	PSCHED_GET_TIME(parent->t_c);
+	parent->t_c = psched_get_time();
 	parent->cmode = HTB_CAN_SEND;
 }
 
@@ -1317,7 +1279,7 @@ static void htb_destroy_class(struct Qdi
 	qdisc_put_rtab(cl->rate);
 	qdisc_put_rtab(cl->ceil);
 
-	htb_destroy_filters(&cl->filter_list);
+	tcf_destroy_chain(cl->filter_list);
 
 	while (!list_empty(&cl->children))
 		htb_destroy_class(sch, list_entry(cl->children.next,
@@ -1341,7 +1303,7 @@ static void htb_destroy(struct Qdisc *sc
 {
 	struct htb_sched *q = qdisc_priv(sch);
 
-	del_timer_sync(&q->timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 #ifdef HTB_RATECM
 	del_timer_sync(&q->rttim);
 #endif
@@ -1349,7 +1311,7 @@ #endif
 	   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);
+	tcf_destroy_chain(q->filter_list);
 
 	while (!list_empty(&q->root))
 		htb_destroy_class(sch, list_entry(q->root.next,
@@ -1498,8 +1460,8 @@ static int htb_change_class(struct Qdisc
 		/* set class to be in HTB_CAN_SEND state */
 		cl->tokens = hopt->buffer;
 		cl->ctokens = hopt->cbuffer;
-		cl->mbuffer = PSCHED_JIFFIE2US(HZ * 60);	/* 1min */
-		PSCHED_GET_TIME(cl->t_c);
+		cl->mbuffer = 60 * PSCHED_TICKS_PER_SEC;	/* 1min */
+		cl->t_c = psched_get_time();
 		cl->cmode = HTB_CAN_SEND;
 
 		/* attach to the hash list and parent's family */
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index cfe070e..f8b9f1c 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -16,6 +16,7 @@ #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/netfilter.h>
 #include <linux/smp.h>
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
@@ -169,7 +170,7 @@ #ifdef CONFIG_NET_CLS_ACT
 			skb->tc_index = TC_H_MIN(res.classid);
 			result = TC_ACT_OK;
 			break;
-	};
+	}
 /* backward compat */
 #else
 #ifdef	CONFIG_NET_CLS_POLICE
@@ -186,7 +187,7 @@ #ifdef	CONFIG_NET_CLS_POLICE
 		sch->bstats.bytes += skb->len;
 		result = NF_ACCEPT;
 		break;
-	};
+	}
 
 #else
 	D2PRINTK("Overriding result to ACCEPT\n");
@@ -247,16 +248,11 @@ ing_hook(unsigned int hook, struct sk_bu
 		skb->dev ? (*pskb)->dev->name : "(no dev)",
 		skb->len);
 
-/*
-revisit later: Use a private since lock dev->queue_lock is also
-used on the egress (might slow things for an iota)
-*/
-
 	if (dev->qdisc_ingress) {
-		spin_lock(&dev->queue_lock);
+		spin_lock(&dev->ingress_lock);
 		if ((q = dev->qdisc_ingress) != NULL)
 			fwres = q->enqueue(skb, q);
-		spin_unlock(&dev->queue_lock);
+		spin_unlock(&dev->ingress_lock);
 	}
 
 	return fwres;
@@ -345,14 +341,9 @@ #endif
 static void ingress_destroy(struct Qdisc *sch)
 {
 	struct ingress_qdisc_data *p = PRIV(sch);
-	struct tcf_proto *tp;
 
 	DPRINTK("ingress_destroy(sch %p,[qdisc %p])\n", sch, p);
-	while (p->filter_list) {
-		tp = p->filter_list;
-		p->filter_list = tp->next;
-		tcf_destroy(tp);
-	}
+	tcf_destroy_chain(p->filter_list);
 #if 0
 /* for future use */
 	qdisc_destroy(p->q);
@@ -362,16 +353,16 @@ #endif
 
 static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 
 	rta = (struct rtattr *) b;
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 1ccbfb5..5d9d8bc 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -22,6 +22,7 @@ #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 
 #define VERSION "1.2"
@@ -54,21 +55,22 @@ #define VERSION "1.2"
 
 struct netem_sched_data {
 	struct Qdisc	*qdisc;
-	struct timer_list timer;
+	struct qdisc_watchdog watchdog;
+
+	psched_tdiff_t latency;
+	psched_tdiff_t jitter;
 
-	u32 latency;
 	u32 loss;
 	u32 limit;
 	u32 counter;
 	u32 gap;
-	u32 jitter;
 	u32 duplicate;
 	u32 reorder;
 	u32 corrupt;
 
 	struct crndstate {
-		unsigned long last;
-		unsigned long rho;
+		u32 last;
+		u32 rho;
 	} delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
 
 	struct disttable {
@@ -95,12 +97,12 @@ static void init_crandom(struct crndstat
  * Next number depends on last value.
  * rho is scaled to avoid floating point.
  */
-static unsigned long get_crandom(struct crndstate *state)
+static u32 get_crandom(struct crndstate *state)
 {
 	u64 value, rho;
 	unsigned long answer;
 
-	if (state->rho == 0)	/* no correllation */
+	if (state->rho == 0)	/* no correlation */
 		return net_random();
 
 	value = net_random();
@@ -114,11 +116,13 @@ static unsigned long get_crandom(struct 
  * std deviation sigma.  Uses table lookup to approximate the desired
  * distribution, and a uniformly-distributed pseudo-random source.
  */
-static long tabledist(unsigned long mu, long sigma,
-		      struct crndstate *state, const struct disttable *dist)
+static psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma,
+				struct crndstate *state,
+				const struct disttable *dist)
 {
-	long t, x;
-	unsigned long rnd;
+	psched_tdiff_t x;
+	long t;
+	u32 rnd;
 
 	if (sigma == 0)
 		return mu;
@@ -213,8 +217,8 @@ static int netem_enqueue(struct sk_buff 
 		delay = tabledist(q->latency, q->jitter,
 				  &q->delay_cor, q->delay_dist);
 
-		PSCHED_GET_TIME(now);
-		PSCHED_TADD2(now, delay, cb->time_to_send);
+		now = psched_get_time();
+		cb->time_to_send = now + delay;
 		++q->counter;
 		ret = q->qdisc->enqueue(skb, q->qdisc);
 	} else {
@@ -222,7 +226,7 @@ static int netem_enqueue(struct sk_buff 
 		 * Do re-ordering by putting one out of N packets at the front
 		 * of the queue.
 		 */
-		PSCHED_GET_TIME(cb->time_to_send);
+		cb->time_to_send = psched_get_time();
 		q->counter = 0;
 		ret = q->qdisc->ops->requeue(skb, q->qdisc);
 	}
@@ -269,55 +273,43 @@ static struct sk_buff *netem_dequeue(str
 	struct netem_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
 
+	smp_mb();
+	if (sch->flags & TCQ_F_THROTTLED)
+		return NULL;
+
 	skb = q->qdisc->dequeue(q->qdisc);
 	if (skb) {
 		const struct netem_skb_cb *cb
 			= (const struct netem_skb_cb *)skb->cb;
-		psched_time_t now;
+		psched_time_t now = psched_get_time();
 
 		/* if more time remaining? */
-		PSCHED_GET_TIME(now);
-
-		if (PSCHED_TLESS(cb->time_to_send, now)) {
+		if (cb->time_to_send <= now) {
 			pr_debug("netem_dequeue: return skb=%p\n", skb);
 			sch->q.qlen--;
-			sch->flags &= ~TCQ_F_THROTTLED;
 			return skb;
-		} else {
-			psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);
-
-			if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
-				qdisc_tree_decrease_qlen(q->qdisc, 1);
-				sch->qstats.drops++;
-				printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
-				       q->qdisc->ops->id);
-			}
+		}
 
-			mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
-			sch->flags |= TCQ_F_THROTTLED;
+		if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
+			qdisc_tree_decrease_qlen(q->qdisc, 1);
+			sch->qstats.drops++;
+			printk(KERN_ERR "netem: %s could not requeue\n",
+			       q->qdisc->ops->id);
 		}
+
+		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
 	}
 
 	return NULL;
 }
 
-static void netem_watchdog(unsigned long arg)
-{
-	struct Qdisc *sch = (struct Qdisc *)arg;
-
-	pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen);
-	sch->flags &= ~TCQ_F_THROTTLED;
-	netif_schedule(sch->dev);
-}
-
 static void netem_reset(struct Qdisc *sch)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 
 	qdisc_reset(q->qdisc);
 	sch->q.qlen = 0;
-	sch->flags &= ~TCQ_F_THROTTLED;
-	del_timer_sync(&q->timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 }
 
 /* Pass size change message down to embedded FIFO */
@@ -438,10 +430,11 @@ static int netem_change(struct Qdisc *sc
 	q->loss = qopt->loss;
 	q->duplicate = qopt->duplicate;
 
-	/* for compatiablity with earlier versions.
-	 * if gap is set, need to assume 100% probablity
+	/* for compatibility with earlier versions.
+	 * if gap is set, need to assume 100% probability
 	 */
-	q->reorder = ~0;
+	if (q->gap)
+		q->reorder = ~0;
 
 	/* Handle nested options after initial queue options.
 	 * Should have put all options in nested format but too late now.
@@ -487,22 +480,28 @@ static int netem_change(struct Qdisc *sc
  */
 struct fifo_sched_data {
 	u32 limit;
+	psched_time_t oldest;
 };
 
 static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 {
 	struct fifo_sched_data *q = qdisc_priv(sch);
 	struct sk_buff_head *list = &sch->q;
-	const struct netem_skb_cb *ncb
-		= (const struct netem_skb_cb *)nskb->cb;
+	psched_time_t tnext = ((struct netem_skb_cb *)nskb->cb)->time_to_send;
 	struct sk_buff *skb;
 
 	if (likely(skb_queue_len(list) < q->limit)) {
+		/* Optimize for add at tail */
+		if (likely(skb_queue_empty(list) || tnext >= q->oldest)) {
+			q->oldest = tnext;
+			return qdisc_enqueue_tail(nskb, sch);
+		}
+
 		skb_queue_reverse_walk(list, skb) {
 			const struct netem_skb_cb *cb
 				= (const struct netem_skb_cb *)skb->cb;
 
-			if (!PSCHED_TLESS(ncb->time_to_send, cb->time_to_send))
+			if (tnext >= cb->time_to_send)
 				break;
 		}
 
@@ -515,7 +514,7 @@ static int tfifo_enqueue(struct sk_buff 
 		return NET_XMIT_SUCCESS;
 	}
 
-	return qdisc_drop(nskb, sch);
+	return qdisc_reshape_fail(nskb, sch);
 }
 
 static int tfifo_init(struct Qdisc *sch, struct rtattr *opt)
@@ -531,6 +530,7 @@ static int tfifo_init(struct Qdisc *sch,
 	} else
 		q->limit = max_t(u32, sch->dev->tx_queue_len, 1);
 
+	q->oldest = PSCHED_PASTPERFECT;
 	return 0;
 }
 
@@ -567,9 +567,7 @@ static int netem_init(struct Qdisc *sch,
 	if (!opt)
 		return -EINVAL;
 
-	init_timer(&q->timer);
-	q->timer.function = netem_watchdog;
-	q->timer.data = (unsigned long) sch;
+	qdisc_watchdog_init(&q->watchdog, sch);
 
 	q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
 				     TC_H_MAKE(sch->handle, 1));
@@ -590,7 +588,7 @@ static void netem_destroy(struct Qdisc *
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 
-	del_timer_sync(&q->timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 	qdisc_destroy(q->qdisc);
 	kfree(q->delay_dist);
 }
@@ -598,7 +596,7 @@ static void netem_destroy(struct Qdisc *
 static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	const struct netem_sched_data *q = qdisc_priv(sch);
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta = (struct rtattr *) b;
 	struct tc_netem_qopt qopt;
 	struct tc_netem_corr cor;
@@ -626,12 +624,12 @@ static int netem_dump(struct Qdisc *sch,
 	corrupt.correlation = q->corrupt_cor.rho;
 	RTA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
 
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index de889f2..269a6e1 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -32,6 +32,7 @@ #include <linux/notifier.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
+#include <net/netlink.h>
 #include <net/sock.h>
 #include <net/pkt_sched.h>
 
@@ -61,7 +62,7 @@ #ifdef CONFIG_NET_CLS_ACT
 			*qerr = NET_XMIT_SUCCESS;
 		case TC_ACT_SHOT:
 			return NULL;
-		};
+		}
 
 		if (!q->filter_list ) {
 #else
@@ -188,13 +189,8 @@ prio_destroy(struct Qdisc* sch)
 {
 	int prio;
 	struct prio_sched_data *q = qdisc_priv(sch);
-	struct tcf_proto *tp;
-
-	while ((tp = q->filter_list) != NULL) {
-		q->filter_list = tp->next;
-		tcf_destroy(tp);
-	}
 
+	tcf_destroy_chain(q->filter_list);
 	for (prio=0; prio<q->bands; prio++)
 		qdisc_destroy(q->queues[prio]);
 }
@@ -271,7 +267,7 @@ static int prio_init(struct Qdisc *sch, 
 static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct prio_sched_data *q = qdisc_priv(sch);
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_prio_qopt opt;
 
 	opt.bands = q->bands;
@@ -280,7 +276,7 @@ static int prio_dump(struct Qdisc *sch, 
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 66f3205..96dfdf7 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -30,6 +30,7 @@ #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <linux/init.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <linux/ipv6.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
@@ -137,7 +138,7 @@ static unsigned sfq_hash(struct sfq_sche
 	switch (skb->protocol) {
 	case __constant_htons(ETH_P_IP):
 	{
-		struct iphdr *iph = skb->nh.iph;
+		const struct iphdr *iph = ip_hdr(skb);
 		h = iph->daddr;
 		h2 = iph->saddr^iph->protocol;
 		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
@@ -152,7 +153,7 @@ static unsigned sfq_hash(struct sfq_sche
 	}
 	case __constant_htons(ETH_P_IPV6):
 	{
-		struct ipv6hdr *iph = skb->nh.ipv6h;
+		struct ipv6hdr *iph = ipv6_hdr(skb);
 		h = iph->daddr.s6_addr32[3];
 		h2 = iph->saddr.s6_addr32[3]^iph->nexthdr;
 		if (iph->nexthdr == IPPROTO_TCP ||
@@ -461,7 +462,7 @@ static void sfq_destroy(struct Qdisc *sc
 static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct sfq_sched_data *q = qdisc_priv(sch);
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct tc_sfq_qopt opt;
 
 	opt.quantum = q->quantum;
@@ -476,7 +477,7 @@ static int sfq_dump(struct Qdisc *sch, s
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 85da8da..5386295 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -32,6 +32,7 @@ #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <net/ip.h>
+#include <net/netlink.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -127,8 +128,8 @@ struct tbf_sched_data
 	long	tokens;			/* Current number of B tokens */
 	long	ptokens;		/* Current number of P tokens */
 	psched_time_t	t_c;		/* Time check-point */
-	struct timer_list wd_timer;	/* Watchdog timer */
 	struct Qdisc	*qdisc;		/* Inner qdisc, default - bfifo queue */
+	struct qdisc_watchdog watchdog;	/* Watchdog timer */
 };
 
 #define L2T(q,L)   ((q)->R_tab->data[(L)>>(q)->R_tab->rate.cell_log])
@@ -185,14 +186,6 @@ static unsigned int tbf_drop(struct Qdis
 	return len;
 }
 
-static void tbf_watchdog(unsigned long arg)
-{
-	struct Qdisc *sch = (struct Qdisc*)arg;
-
-	sch->flags &= ~TCQ_F_THROTTLED;
-	netif_schedule(sch->dev);
-}
-
 static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
@@ -202,13 +195,12 @@ static struct sk_buff *tbf_dequeue(struc
 
 	if (skb) {
 		psched_time_t now;
-		long toks, delay;
+		long toks;
 		long ptoks = 0;
 		unsigned int len = skb->len;
 
-		PSCHED_GET_TIME(now);
-
-		toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer);
+		now = psched_get_time();
+		toks = psched_tdiff_bounded(now, q->t_c, q->buffer);
 
 		if (q->P_tab) {
 			ptoks = toks + q->ptokens;
@@ -230,12 +222,8 @@ static struct sk_buff *tbf_dequeue(struc
 			return skb;
 		}
 
-		delay = PSCHED_US2JIFFIE(max_t(long, -toks, -ptoks));
-
-		if (delay == 0)
-			delay = 1;
-
-		mod_timer(&q->wd_timer, jiffies+delay);
+		qdisc_watchdog_schedule(&q->watchdog,
+					now + max_t(long, -toks, -ptoks));
 
 		/* Maybe we have a shorter packet in the queue,
 		   which can be sent now. It sounds cool,
@@ -254,7 +242,6 @@ static struct sk_buff *tbf_dequeue(struc
 			sch->qstats.drops++;
 		}
 
-		sch->flags |= TCQ_F_THROTTLED;
 		sch->qstats.overlimits++;
 	}
 	return NULL;
@@ -266,11 +253,10 @@ static void tbf_reset(struct Qdisc* sch)
 
 	qdisc_reset(q->qdisc);
 	sch->q.qlen = 0;
-	PSCHED_GET_TIME(q->t_c);
+	q->t_c = psched_get_time();
 	q->tokens = q->buffer;
 	q->ptokens = q->mtu;
-	sch->flags &= ~TCQ_F_THROTTLED;
-	del_timer(&q->wd_timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 }
 
 static struct Qdisc *tbf_create_dflt_qdisc(struct Qdisc *sch, u32 limit)
@@ -377,11 +363,8 @@ static int tbf_init(struct Qdisc* sch, s
 	if (opt == NULL)
 		return -EINVAL;
 
-	PSCHED_GET_TIME(q->t_c);
-	init_timer(&q->wd_timer);
-	q->wd_timer.function = tbf_watchdog;
-	q->wd_timer.data = (unsigned long)sch;
-
+	q->t_c = psched_get_time();
+	qdisc_watchdog_init(&q->watchdog, sch);
 	q->qdisc = &noop_qdisc;
 
 	return tbf_change(sch, opt);
@@ -391,7 +374,7 @@ static void tbf_destroy(struct Qdisc *sc
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
 
-	del_timer(&q->wd_timer);
+	qdisc_watchdog_cancel(&q->watchdog);
 
 	if (q->P_tab)
 		qdisc_put_rtab(q->P_tab);
@@ -404,7 +387,7 @@ static void tbf_destroy(struct Qdisc *sc
 static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
-	unsigned char	 *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	struct rtattr *rta;
 	struct tc_tbf_qopt opt;
 
@@ -420,12 +403,12 @@ static int tbf_dump(struct Qdisc *sch, s
 	opt.mtu = q->mtu;
 	opt.buffer = q->buffer;
 	RTA_PUT(skb, TCA_TBF_PARMS, sizeof(opt), &opt);
-	rta->rta_len = skb->tail - b;
+	rta->rta_len = skb_tail_pointer(skb) - b;
 
 	return skb->len;
 
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 587123c..d24914d 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -323,7 +323,7 @@ restart:
 			nores = 1;
 			break;
 		}
-		__skb_pull(skb, skb->nh.raw - skb->data);
+		__skb_pull(skb, skb_network_offset(skb));
 	} while ((q = NEXT_SLAVE(q)) != start);
 
 	if (nores && skb_res == NULL) {
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 78d2ddb..df94e3c 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -143,7 +143,7 @@ static struct sctp_association *sctp_ass
 	/* Initialize the maximum mumber of new data packets that can be sent
 	 * in a burst.
 	 */
-	asoc->max_burst = sctp_max_burst;
+	asoc->max_burst = sp->max_burst;
 
 	/* initialize association timers */
 	asoc->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
@@ -714,8 +714,16 @@ void sctp_assoc_control_transport(struct
 	/* Record the transition on the transport.  */
 	switch (command) {
 	case SCTP_TRANSPORT_UP:
+		/* If we are moving from UNCONFIRMED state due
+		 * to heartbeat success, report the SCTP_ADDR_CONFIRMED
+		 * state to the user, otherwise report SCTP_ADDR_AVAILABLE.
+		 */
+		if (SCTP_UNCONFIRMED == transport->state &&
+		    SCTP_HEARTBEAT_SUCCESS == error)
+			spc_state = SCTP_ADDR_CONFIRMED;
+		else
+			spc_state = SCTP_ADDR_AVAILABLE;
 		transport->state = SCTP_ACTIVE;
-		spc_state = SCTP_ADDR_AVAILABLE;
 		break;
 
 	case SCTP_TRANSPORT_DOWN:
@@ -725,7 +733,7 @@ void sctp_assoc_control_transport(struct
 
 	default:
 		return;
-	};
+	}
 
 	/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
 	 * user.
@@ -1095,6 +1103,13 @@ void sctp_assoc_update(struct sctp_assoc
 			asoc->ssnmap = new->ssnmap;
 			new->ssnmap = NULL;
 		}
+
+		if (!asoc->assoc_id) {
+			/* get a new association id since we don't have one
+			 * yet.
+			 */
+			sctp_assoc_set_id(asoc, GFP_ATOMIC);
+		}
 	}
 }
 
@@ -1367,3 +1382,25 @@ out:
 	sctp_read_unlock(&asoc->base.addr_lock);
 	return found;
 }
+
+/* Set an association id for a given association */
+int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
+{
+	int assoc_id;
+	int error = 0;
+retry:
+	if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+		return -ENOMEM;
+
+	spin_lock_bh(&sctp_assocs_id_lock);
+	error = idr_get_new_above(&sctp_assocs_id, (void *)asoc,
+				    1, &assoc_id);
+	spin_unlock_bh(&sctp_assocs_id_lock);
+	if (error == -EAGAIN)
+		goto retry;
+	else if (error)
+		return error;
+
+	asoc->assoc_id = (sctp_assoc_t) assoc_id;
+	return error;
+}
diff --git a/net/sctp/debug.c b/net/sctp/debug.c
index 5f5ab28..e8c0f74 100644
--- a/net/sctp/debug.c
+++ b/net/sctp/debug.c
@@ -93,8 +93,9 @@ const char *sctp_cname(const sctp_subtyp
 		return "FWD_TSN";
 
 	default:
-		return "unknown chunk";
-	};
+		break;
+	}
+
 	return "unknown chunk";
 }
 
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 71db668..885109f 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -79,14 +79,10 @@ static void sctp_add_backlog(struct sock
 /* Calculate the SCTP checksum of an SCTP packet.  */
 static inline int sctp_rcv_checksum(struct sk_buff *skb)
 {
-	struct sctphdr *sh;
-	__u32 cmp, val;
 	struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-	sh = (struct sctphdr *) skb->h.raw;
-	cmp = ntohl(sh->checksum);
-
-	val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
+	struct sctphdr *sh = sctp_hdr(skb);
+	__u32 cmp = ntohl(sh->checksum);
+	__u32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
 
 	for (; list; list = list->next)
 		val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list),
@@ -138,14 +134,13 @@ int sctp_rcv(struct sk_buff *skb)
 	if (skb_linearize(skb))
 		goto discard_it;
 
-	sh = (struct sctphdr *) skb->h.raw;
+	sh = sctp_hdr(skb);
 
 	/* Pull up the IP and SCTP headers. */
-	__skb_pull(skb, skb->h.raw - skb->data);
+	__skb_pull(skb, skb_transport_offset(skb));
 	if (skb->len < sizeof(struct sctphdr))
 		goto discard_it;
-	if ((skb->ip_summed != CHECKSUM_UNNECESSARY) &&
-	    (sctp_rcv_checksum(skb) < 0))
+	if (!skb_csum_unnecessary(skb) && sctp_rcv_checksum(skb) < 0)
 		goto discard_it;
 
 	skb_pull(skb, sizeof(struct sctphdr));
@@ -154,7 +149,7 @@ int sctp_rcv(struct sk_buff *skb)
 	if (skb->len < sizeof(struct sctp_chunkhdr))
 		goto discard_it;
 
-	family = ipver2af(skb->nh.iph->version);
+	family = ipver2af(ip_hdr(skb)->version);
 	af = sctp_get_af_specific(family);
 	if (unlikely(!af))
 		goto discard_it;
@@ -510,30 +505,30 @@ void sctp_err_finish(struct sock *sk, st
 void sctp_v4_err(struct sk_buff *skb, __u32 info)
 {
 	struct iphdr *iph = (struct iphdr *)skb->data;
-	struct sctphdr *sh = (struct sctphdr *)(skb->data + (iph->ihl <<2));
-	int type = skb->h.icmph->type;
-	int code = skb->h.icmph->code;
+	const int ihlen = iph->ihl * 4;
+	const int type = icmp_hdr(skb)->type;
+	const int code = icmp_hdr(skb)->code;
 	struct sock *sk;
 	struct sctp_association *asoc = NULL;
 	struct sctp_transport *transport;
 	struct inet_sock *inet;
-	char *saveip, *savesctp;
+	sk_buff_data_t saveip, savesctp;
 	int err;
 
-	if (skb->len < ((iph->ihl << 2) + 8)) {
+	if (skb->len < ihlen + 8) {
 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
 		return;
 	}
 
 	/* Fix up skb to look at the embedded net header. */
-	saveip = skb->nh.raw;
-	savesctp  = skb->h.raw;
-	skb->nh.iph = iph;
-	skb->h.raw = (char *)sh;
-	sk = sctp_err_lookup(AF_INET, skb, sh, &asoc, &transport);
-	/* Put back, the original pointers. */
-	skb->nh.raw = saveip;
-	skb->h.raw = savesctp;
+	saveip = skb->network_header;
+	savesctp = skb->transport_header;
+	skb_reset_network_header(skb);
+	skb_set_transport_header(skb, ihlen);
+	sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
+	/* Put back, the original values. */
+	skb->network_header = saveip;
+	skb->transport_header = savesctp;
 	if (!sk) {
 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
 		return;
@@ -616,7 +611,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
 			break;
 
 		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
-		if (ch_end > skb->tail)
+		if (ch_end > skb_tail_pointer(skb))
 			break;
 
 		/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
@@ -648,7 +643,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
 		}
 
 		ch = (sctp_chunkhdr_t *) ch_end;
-	} while (ch_end < skb->tail);
+	} while (ch_end < skb_tail_pointer(skb));
 
 	return 0;
 
@@ -905,7 +900,7 @@ static struct sctp_association *__sctp_r
 	struct sctp_association *asoc;
 	union sctp_addr addr;
 	union sctp_addr *paddr = &addr;
-	struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
+	struct sctphdr *sh = sctp_hdr(skb);
 	sctp_chunkhdr_t *ch;
 	union sctp_params params;
 	sctp_init_chunk_t *init;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index c30629e..88aa224 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -159,16 +159,16 @@ struct sctp_chunk *sctp_inq_pop(struct s
 	 * the skb->tail.
 	 */
 	if (unlikely(skb_is_nonlinear(chunk->skb))) {
-		if (chunk->chunk_end > chunk->skb->tail)
-			chunk->chunk_end = chunk->skb->tail;
+		if (chunk->chunk_end > skb_tail_pointer(chunk->skb))
+			chunk->chunk_end = skb_tail_pointer(chunk->skb);
 	}
 	skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
 	chunk->subh.v = NULL; /* Subheader is no longer valid.  */
 
-	if (chunk->chunk_end < chunk->skb->tail) {
+	if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) {
 		/* This is not a singleton */
 		chunk->singleton = 0;
-	} else if (chunk->chunk_end > chunk->skb->tail) {
+	} else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) {
 		/* RFC 2960, Section 6.10  Bundling
 		 *
 		 * Partial chunks MUST NOT be placed in an SCTP packet.
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 0b9c49b..84cd536 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -122,26 +122,24 @@ SCTP_STATIC void sctp_v6_err(struct sk_b
 			     int type, int code, int offset, __be32 info)
 {
 	struct inet6_dev *idev;
-	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
-	struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
 	struct sock *sk;
 	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 	struct ipv6_pinfo *np;
-	char *saveip, *savesctp;
+	sk_buff_data_t saveip, savesctp;
 	int err;
 
 	idev = in6_dev_get(skb->dev);
 
 	/* Fix up skb to look at the embedded net header. */
-	saveip = skb->nh.raw;
-	savesctp  = skb->h.raw;
-	skb->nh.ipv6h = iph;
-	skb->h.raw = (char *)sh;
-	sk = sctp_err_lookup(AF_INET6, skb, sh, &asoc, &transport);
+	saveip	 = skb->network_header;
+	savesctp = skb->transport_header;
+	skb_reset_network_header(skb);
+	skb_set_transport_header(skb, offset);
+	sk = sctp_err_lookup(AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
 	/* Put back, the original pointers. */
-	skb->nh.raw = saveip;
-	skb->h.raw = savesctp;
+	skb->network_header   = saveip;
+	skb->transport_header = savesctp;
 	if (!sk) {
 		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
 		goto out;
@@ -391,13 +389,13 @@ static void sctp_v6_from_skb(union sctp_
 	addr->v6.sin6_flowinfo = 0; /* FIXME */
 	addr->v6.sin6_scope_id = ((struct inet6_skb_parm *)skb->cb)->iif;
 
-	sh = (struct sctphdr *) skb->h.raw;
+	sh = sctp_hdr(skb);
 	if (is_saddr) {
 		*port  = sh->source;
-		from = &skb->nh.ipv6h->saddr;
+		from = &ipv6_hdr(skb)->saddr;
 	} else {
 		*port = sh->dest;
-		from = &skb->nh.ipv6h->daddr;
+		from = &ipv6_hdr(skb)->daddr;
 	}
 	ipv6_addr_copy(&addr->v6.sin6_addr, from);
 }
@@ -606,7 +604,7 @@ static sctp_scope_t sctp_v6_scope(union 
 	default:
 		retval = SCTP_SCOPE_GLOBAL;
 		break;
-	};
+	}
 
 	return retval;
 }
@@ -699,7 +697,7 @@ static int sctp_v6_skb_iif(const struct 
 /* Was this packet marked by Explicit Congestion Notification? */
 static int sctp_v6_is_ce(const struct sk_buff *skb)
 {
-	return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20);
+	return *((__u32 *)(ipv6_hdr(skb))) & htonl(1 << 20);
 }
 
 /* Dump the v6 addr to the seq file. */
@@ -766,19 +764,19 @@ static void sctp_inet6_skb_msgname(struc
 	if (msgname) {
 		sctp_inet6_msgname(msgname, addr_len);
 		sin6 = (struct sockaddr_in6 *)msgname;
-		sh = (struct sctphdr *)skb->h.raw;
+		sh = sctp_hdr(skb);
 		sin6->sin6_port = sh->source;
 
 		/* Map ipv4 address into v4-mapped-on-v6 address. */
 		if (sctp_sk(skb->sk)->v4mapped &&
-		    skb->nh.iph->version == 4) {
+		    ip_hdr(skb)->version == 4) {
 			sctp_v4_map_v6((union sctp_addr *)sin6);
-			sin6->sin6_addr.s6_addr32[3] = skb->nh.iph->saddr;
+			sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
 			return;
 		}
 
 		/* Otherwise, just copy the v6 address. */
-		ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
+		ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
 			struct sctp_ulpevent *ev = sctp_skb2event(skb);
 			sin6->sin6_scope_id = ev->iif;
@@ -994,45 +992,52 @@ static struct sctp_pf sctp_pf_inet6_spec
 	.af            = &sctp_ipv6_specific,
 };
 
-/* Initialize IPv6 support and register with inet6 stack.  */
+/* Initialize IPv6 support and register with socket layer.  */
 int sctp_v6_init(void)
 {
-	int rc = proto_register(&sctpv6_prot, 1);
+	int rc;
+
+	/* Register the SCTP specific PF_INET6 functions. */
+	sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
 
+	/* Register the SCTP specific AF_INET6 functions. */
+	sctp_register_af(&sctp_ipv6_specific);
+
+	rc = proto_register(&sctpv6_prot, 1);
 	if (rc)
-		goto out;
-	/* Register inet6 protocol. */
-	rc = -EAGAIN;
-	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
-		goto out_unregister_sctp_proto;
+		return rc;
 
 	/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
 	inet6_register_protosw(&sctpv6_seqpacket_protosw);
 	inet6_register_protosw(&sctpv6_stream_protosw);
 
-	/* Register the SCTP specific PF_INET6 functions. */
-	sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
-
-	/* Register the SCTP specific AF_INET6 functions. */
-	sctp_register_af(&sctp_ipv6_specific);
+	return 0;
+}
 
+/* Register with inet6 layer. */
+int sctp_v6_add_protocol(void)
+{
 	/* Register notifier for inet6 address additions/deletions. */
 	register_inet6addr_notifier(&sctp_inet6addr_notifier);
-	rc = 0;
-out:
-	return rc;
-out_unregister_sctp_proto:
-	proto_unregister(&sctpv6_prot);
-	goto out;
+
+	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
+		return -EAGAIN;
+
+	return 0;
 }
 
 /* IPv6 specific exit support. */
 void sctp_v6_exit(void)
 {
-	list_del(&sctp_ipv6_specific.list);
-	inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
 	inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
 	inet6_unregister_protosw(&sctpv6_stream_protosw);
-	unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
 	proto_unregister(&sctpv6_prot);
+	list_del(&sctp_ipv6_specific.list);
+}
+
+/* Unregister with inet6 layer. */
+void sctp_v6_del_protocol(void)
+{
+	inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
+	unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
 }
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f875fc3..d85543d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -176,7 +176,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(s
 	case SCTP_XMIT_OK:
 	case SCTP_XMIT_NAGLE_DELAY:
 		break;
-	};
+	}
 
 	return retval;
 }
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 41abfd1..992f361 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -338,7 +338,7 @@ int sctp_outq_tail(struct sctp_outq *q, 
 				SCTP_INC_STATS(SCTP_MIB_OUTORDERCHUNKS);
 			q->empty = 0;
 			break;
-		};
+		}
 	} else {
 		list_add_tail(&chunk->list, &q->control_chunk_list);
 		SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
@@ -630,7 +630,7 @@ static int sctp_outq_flush_rtx(struct sc
 			/* Retrieve a new chunk to bundle. */
 			lchunk = sctp_list_dequeue(lqueue);
 			break;
-		};
+		}
 
 		/* If we are here due to a retransmit timeout or a fast
 		 * retransmit and if there are any chunks left in the retransmit
@@ -779,7 +779,7 @@ int sctp_outq_flush(struct sctp_outq *q,
 		default:
 			/* We built a chunk with an illegal type! */
 			BUG();
-		};
+		}
 	}
 
 	/* Is it OK to send data chunks?  */
@@ -1397,7 +1397,7 @@ #if SCTP_DEBUG
 				SCTP_DEBUG_PRINTK("ACKed: %08x", tsn);
 				dbg_prt_state = 0;
 				dbg_ack_tsn = tsn;
-			};
+			}
 
 			dbg_last_ack_tsn = tsn;
 #endif /* SCTP_DEBUG */
@@ -1452,7 +1452,7 @@ #if SCTP_DEBUG
 				SCTP_DEBUG_PRINTK("KEPT: %08x",tsn);
 				dbg_prt_state = 1;
 				dbg_kept_tsn = tsn;
-			};
+			}
 
 			dbg_last_kept_tsn = tsn;
 #endif /* SCTP_DEBUG */
@@ -1476,7 +1476,7 @@ #if SCTP_DEBUG
 		} else {
 			SCTP_DEBUG_PRINTK("\n");
 		}
-	};
+	}
 #endif /* SCTP_DEBUG */
 	if (transport) {
 		if (bytes_acked) {
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index e17a823..34bab36 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -170,7 +170,7 @@ static void sctp_get_local_addr_list(voi
 	struct sctp_af *af;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		__list_for_each(pos, &sctp_address_families) {
 			af = list_entry(pos, struct sctp_af, list);
 			af->copy_addrlist(&sctp_local_addr_list, dev);
@@ -235,13 +235,13 @@ static void sctp_v4_from_skb(union sctp_
 	port = &addr->v4.sin_port;
 	addr->v4.sin_family = AF_INET;
 
-	sh = (struct sctphdr *) skb->h.raw;
+	sh = sctp_hdr(skb);
 	if (is_saddr) {
 		*port  = sh->source;
-		from = &skb->nh.iph->saddr;
+		from = &ip_hdr(skb)->saddr;
 	} else {
 		*port = sh->dest;
-		from = &skb->nh.iph->daddr;
+		from = &ip_hdr(skb)->daddr;
 	}
 	memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr));
 }
@@ -530,7 +530,7 @@ static int sctp_v4_skb_iif(const struct 
 /* Was this packet marked by Explicit Congestion Notification? */
 static int sctp_v4_is_ce(const struct sk_buff *skb)
 {
-	return INET_ECN_is_ce(skb->nh.iph->tos);
+	return INET_ECN_is_ce(ip_hdr(skb)->tos);
 }
 
 /* Create and initialize a new sk for the socket returned by accept(). */
@@ -731,15 +731,13 @@ static void sctp_inet_event_msgname(stru
 /* Initialize and copy out a msgname from an inbound skb. */
 static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len)
 {
-	struct sctphdr *sh;
-	struct sockaddr_in *sin;
-
 	if (msgname) {
+		struct sctphdr *sh = sctp_hdr(skb);
+		struct sockaddr_in *sin = (struct sockaddr_in *)msgname;
+
 		sctp_inet_msgname(msgname, len);
-		sin = (struct sockaddr_in *)msgname;
-		sh = (struct sctphdr *)skb->h.raw;
 		sin->sin_port = sh->source;
-		sin->sin_addr.s_addr = skb->nh.iph->saddr;
+		sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
 	}
 }
 
@@ -977,28 +975,14 @@ SCTP_STATIC __init int sctp_init(void)
 	if (!sctp_sanity_check())
 		goto out;
 
-	status = proto_register(&sctp_prot, 1);
-	if (status)
-		goto out;
-
-	/* Add SCTP to inet_protos hash table.  */
-	status = -EAGAIN;
-	if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
-		goto err_add_protocol;
-
-	/* Add SCTP(TCP and UDP style) to inetsw linked list.  */
-	inet_register_protosw(&sctp_seqpacket_protosw);
-	inet_register_protosw(&sctp_stream_protosw);
-
-	/* Allocate a cache pools. */
+	/* Allocate bind_bucket and chunk caches. */
 	status = -ENOBUFS;
 	sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
 					       sizeof(struct sctp_bind_bucket),
 					       0, SLAB_HWCACHE_ALIGN,
 					       NULL, NULL);
-
 	if (!sctp_bucket_cachep)
-		goto err_bucket_cachep;
+		goto out;
 
 	sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
 					       sizeof(struct sctp_chunk),
@@ -1044,7 +1028,7 @@ SCTP_STATIC __init int sctp_init(void)
 	sctp_cookie_preserve_enable 	= 1;
 
 	/* Max.Burst		    - 4 */
-	sctp_max_burst 			= SCTP_MAX_BURST;
+	sctp_max_burst 			= SCTP_DEFAULT_MAX_BURST;
 
 	/* Association.Max.Retrans  - 10 attempts
 	 * Path.Max.Retrans         - 5  attempts (per destination address)
@@ -1155,6 +1139,14 @@ SCTP_STATIC __init int sctp_init(void)
 	INIT_LIST_HEAD(&sctp_address_families);
 	sctp_register_af(&sctp_ipv4_specific);
 
+	status = proto_register(&sctp_prot, 1);
+	if (status)
+		goto err_proto_register;
+
+	/* Register SCTP(UDP and TCP style) with socket layer.  */
+	inet_register_protosw(&sctp_seqpacket_protosw);
+	inet_register_protosw(&sctp_stream_protosw);
+
 	status = sctp_v6_init();
 	if (status)
 		goto err_v6_init;
@@ -1168,19 +1160,39 @@ SCTP_STATIC __init int sctp_init(void)
 
 	/* Initialize the local address list. */
 	INIT_LIST_HEAD(&sctp_local_addr_list);
-
 	sctp_get_local_addr_list();
 
 	/* Register notifier for inet address additions/deletions. */
 	register_inetaddr_notifier(&sctp_inetaddr_notifier);
 
+	/* Register SCTP with inet layer.  */
+	if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) {
+		status = -EAGAIN;
+		goto err_add_protocol;
+	}
+
+	/* Register SCTP with inet6 layer.  */
+	status = sctp_v6_add_protocol();
+	if (status)
+		goto err_v6_add_protocol;
+
 	__unsafe(THIS_MODULE);
 	status = 0;
 out:
 	return status;
+err_v6_add_protocol:
+	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+	unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+err_add_protocol:
+	sctp_free_local_addr_list();
+	sock_release(sctp_ctl_socket);
 err_ctl_sock_init:
 	sctp_v6_exit();
 err_v6_init:
+	inet_unregister_protosw(&sctp_stream_protosw);
+	inet_unregister_protosw(&sctp_seqpacket_protosw);
+	proto_unregister(&sctp_prot);
+err_proto_register:
 	sctp_sysctl_unregister();
 	list_del(&sctp_ipv4_specific.list);
 	free_pages((unsigned long)sctp_port_hashtable,
@@ -1194,19 +1206,13 @@ err_ehash_alloc:
 			     sizeof(struct sctp_hashbucket)));
 err_ahash_alloc:
 	sctp_dbg_objcnt_exit();
-err_init_proc:
 	sctp_proc_exit();
+err_init_proc:
 	cleanup_sctp_mibs();
 err_init_mibs:
 	kmem_cache_destroy(sctp_chunk_cachep);
 err_chunk_cachep:
 	kmem_cache_destroy(sctp_bucket_cachep);
-err_bucket_cachep:
-	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-	inet_unregister_protosw(&sctp_seqpacket_protosw);
-	inet_unregister_protosw(&sctp_stream_protosw);
-err_add_protocol:
-	proto_unregister(&sctp_prot);
 	goto out;
 }
 
@@ -1217,8 +1223,9 @@ SCTP_STATIC __exit void sctp_exit(void)
 	 * up all the remaining associations and all that memory.
 	 */
 
-	/* Unregister notifier for inet address additions/deletions. */
-	unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+	/* Unregister with inet6/inet layers. */
+	sctp_v6_del_protocol();
+	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 
 	/* Free the local address list.  */
 	sctp_free_local_addr_list();
@@ -1226,7 +1233,16 @@ SCTP_STATIC __exit void sctp_exit(void)
 	/* Free the control endpoint.  */
 	sock_release(sctp_ctl_socket);
 
+	/* Cleanup v6 initializations. */
 	sctp_v6_exit();
+
+	/* Unregister with socket layer. */
+	inet_unregister_protosw(&sctp_stream_protosw);
+	inet_unregister_protosw(&sctp_seqpacket_protosw);
+
+	/* Unregister notifier for inet address additions/deletions. */
+	unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+
 	sctp_sysctl_unregister();
 	list_del(&sctp_ipv4_specific.list);
 
@@ -1238,16 +1254,13 @@ SCTP_STATIC __exit void sctp_exit(void)
 		   get_order(sctp_port_hashsize *
 			     sizeof(struct sctp_bind_hashbucket)));
 
-	kmem_cache_destroy(sctp_chunk_cachep);
-	kmem_cache_destroy(sctp_bucket_cachep);
-
 	sctp_dbg_objcnt_exit();
 	sctp_proc_exit();
 	cleanup_sctp_mibs();
 
-	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-	inet_unregister_protosw(&sctp_seqpacket_protosw);
-	inet_unregister_protosw(&sctp_stream_protosw);
+	kmem_cache_destroy(sctp_chunk_cachep);
+	kmem_cache_destroy(sctp_bucket_cachep);
+
 	proto_unregister(&sctp_prot);
 }
 
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index f7fb29d..8d18f57 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -86,7 +86,7 @@ int sctp_chunk_iif(const struct sctp_chu
 	struct sctp_af *af;
 	int iif = 0;
 
-	af = sctp_get_af_specific(ipver2af(chunk->skb->nh.iph->version));
+	af = sctp_get_af_specific(ipver2af(ip_hdr(chunk->skb)->version));
 	if (af)
 		iif = af->skb_iif(chunk->skb);
 
@@ -1143,7 +1143,7 @@ void *sctp_addto_chunk(struct sctp_chunk
 
 	/* Adjust the chunk length field.  */
 	chunk->chunk_hdr->length = htons(chunklen + padlen + len);
-	chunk->chunk_end = chunk->skb->tail;
+	chunk->chunk_end = skb_tail_pointer(chunk->skb);
 
 	return target;
 }
@@ -1168,7 +1168,7 @@ int sctp_user_addto_chunk(struct sctp_ch
 	/* Adjust the chunk length field.  */
 	chunk->chunk_hdr->length =
 		htons(ntohs(chunk->chunk_hdr->length) + len);
-	chunk->chunk_end = chunk->skb->tail;
+	chunk->chunk_end = skb_tail_pointer(chunk->skb);
 
 out:
 	return err;
@@ -1233,7 +1233,7 @@ struct sctp_association *sctp_make_temp_
 	asoc->temp = 1;
 	skb = chunk->skb;
 	/* Create an entry for the source address of the packet.  */
-	af = sctp_get_af_specific(ipver2af(skb->nh.iph->version));
+	af = sctp_get_af_specific(ipver2af(ip_hdr(skb)->version));
 	if (unlikely(!af))
 		goto fail;
 	af->from_skb(&asoc->c.peer_addr, skb, 1);
@@ -1939,7 +1939,6 @@ int sctp_process_init(struct sctp_associ
 	 * association.
 	 */
 	if (!asoc->temp) {
-		int assoc_id;
 		int error;
 
 		asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
@@ -1947,19 +1946,9 @@ int sctp_process_init(struct sctp_associ
 		if (!asoc->ssnmap)
 			goto clean_up;
 
-	retry:
-		if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+		error = sctp_assoc_set_id(asoc, gfp);
+		if (error)
 			goto clean_up;
-		spin_lock_bh(&sctp_assocs_id_lock);
-		error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, 1,
-					  &assoc_id);
-		spin_unlock_bh(&sctp_assocs_id_lock);
-		if (error == -EAGAIN)
-			goto retry;
-		else if (error)
-			goto clean_up;
-
-		asoc->assoc_id = (sctp_assoc_t) assoc_id;
 	}
 
 	/* ADDIP Section 4.1 ASCONF Chunk Procedures
@@ -2077,7 +2066,7 @@ static int sctp_process_param(struct sct
 
 			default: /* Just ignore anything else.  */
 				break;
-			};
+			}
 		}
 		break;
 
@@ -2118,7 +2107,7 @@ static int sctp_process_param(struct sct
 		SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n",
 				  ntohs(param.p->type), asoc);
 		break;
-	};
+	}
 
 	return retval;
 }
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 1355674..d9fad4f 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -464,7 +464,7 @@ static void sctp_cmd_init_failed(sctp_cm
 	struct sctp_ulpevent *event;
 
 	event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
-						(__u16)error, 0, 0,
+						(__u16)error, 0, 0, NULL,
 						GFP_ATOMIC);
 
 	if (event)
@@ -492,8 +492,13 @@ static void sctp_cmd_assoc_failed(sctp_c
 	/* Cancel any partial delivery in progress. */
 	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
 
-	event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
-						(__u16)error, 0, 0,
+	if (event_type == SCTP_EVENT_T_CHUNK && subtype.chunk == SCTP_CID_ABORT)
+		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
+						(__u16)error, 0, 0, chunk,
+						GFP_ATOMIC);
+	else
+		event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
+						(__u16)error, 0, 0, NULL,
 						GFP_ATOMIC);
 	if (event)
 		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
@@ -857,6 +862,33 @@ static void sctp_cmd_set_sk_err(struct s
 		sk->sk_err = error;
 }
 
+/* Helper function to generate an association change event */
+static void sctp_cmd_assoc_change(sctp_cmd_seq_t *commands,
+				 struct sctp_association *asoc,
+				 u8 state)
+{
+	struct sctp_ulpevent *ev;
+
+	ev = sctp_ulpevent_make_assoc_change(asoc, 0, state, 0,
+					    asoc->c.sinit_num_ostreams,
+					    asoc->c.sinit_max_instreams,
+					    NULL, GFP_ATOMIC);
+	if (ev)
+		sctp_ulpq_tail_event(&asoc->ulpq, ev);
+}
+
+/* Helper function to generate an adaptation indication event */
+static void sctp_cmd_adaptation_ind(sctp_cmd_seq_t *commands,
+				    struct sctp_association *asoc)
+{
+	struct sctp_ulpevent *ev;
+
+	ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
+
+	if (ev)
+		sctp_ulpq_tail_event(&asoc->ulpq, ev);
+}
+
 /* These three macros allow us to pull the debugging code out of the
  * main flow of sctp_do_sm() to keep attention focused on the real
  * functionality there.
@@ -1004,7 +1036,7 @@ static int sctp_side_effects(sctp_event_
 		       status, state, event_type, subtype.chunk);
 		BUG();
 		break;
-	};
+	}
 
 bail:
 	return error;
@@ -1480,11 +1512,20 @@ static int sctp_cmd_interpreter(sctp_eve
 		case SCTP_CMD_SET_SK_ERR:
 			sctp_cmd_set_sk_err(asoc, cmd->obj.error);
 			break;
+		case SCTP_CMD_ASSOC_CHANGE:
+			sctp_cmd_assoc_change(commands, asoc,
+					      cmd->obj.u8);
+			break;
+		case SCTP_CMD_ADAPTATION_IND:
+			sctp_cmd_adaptation_ind(commands, asoc);
+			break;
+
 		default:
 			printk(KERN_WARNING "Impossible command: %u, %p\n",
 			       cmd->verb, cmd->obj.ptr);
 			break;
-		};
+		}
+
 		if (error)
 			break;
 	}
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index e9097cf..f02ce3d 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -186,7 +186,7 @@ sctp_disposition_t sctp_sf_do_4_C(const 
 	 * notification is passed to the upper layer.
 	 */
 	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
-					     0, 0, 0, GFP_ATOMIC);
+					     0, 0, 0, NULL, GFP_ATOMIC);
 	if (ev)
 		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
 				SCTP_ULPEVENT(ev));
@@ -629,7 +629,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
 		case -SCTP_IERROR_BAD_SIG:
 		default:
 			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-		};
+		}
 	}
 
 
@@ -661,7 +661,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co
 	ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, SCTP_COMM_UP, 0,
 					     new_asoc->c.sinit_num_ostreams,
 					     new_asoc->c.sinit_max_instreams,
-					     GFP_ATOMIC);
+					     NULL, GFP_ATOMIC);
 	if (!ev)
 		goto nomem_ev;
 
@@ -790,7 +790,7 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(co
 	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP,
 					     0, asoc->c.sinit_num_ostreams,
 					     asoc->c.sinit_max_instreams,
-					     GFP_ATOMIC);
+					     NULL, GFP_ATOMIC);
 
 	if (!ev)
 		goto nomem;
@@ -1195,7 +1195,7 @@ static void sctp_tietags_populate(struct
 		new_asoc->c.my_ttag   = asoc->c.my_vtag;
 		new_asoc->c.peer_ttag = asoc->c.peer_vtag;
 		break;
-	};
+	}
 
 	/* Other parameters for the endpoint SHOULD be copied from the
 	 * existing parameters of the association (e.g. number of
@@ -1625,7 +1625,7 @@ static sctp_disposition_t sctp_sf_do_dup
 	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0,
 					     new_asoc->c.sinit_num_ostreams,
 					     new_asoc->c.sinit_max_instreams,
-					     GFP_ATOMIC);
+					     NULL, GFP_ATOMIC);
 	if (!ev)
 		goto nomem_ev;
 
@@ -1656,7 +1656,6 @@ static sctp_disposition_t sctp_sf_do_dup
 					struct sctp_association *new_asoc)
 {
 	sctp_init_chunk_t *peer_init;
-	struct sctp_ulpevent *ev;
 	struct sctp_chunk *repl;
 
 	/* new_asoc is a brand-new association, so these are not yet
@@ -1687,34 +1686,28 @@ static sctp_disposition_t sctp_sf_do_dup
 	 * D) IMPLEMENTATION NOTE: An implementation may choose to
 	 * send the Communication Up notification to the SCTP user
 	 * upon reception of a valid COOKIE ECHO chunk.
+	 *
+	 * Sadly, this needs to be implemented as a side-effect, because
+	 * we are not guaranteed to have set the association id of the real
+	 * association and so these notifications need to be delayed until
+	 * the association id is allocated.
 	 */
-	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
-					     new_asoc->c.sinit_num_ostreams,
-					     new_asoc->c.sinit_max_instreams,
-					     GFP_ATOMIC);
-	if (!ev)
-		goto nomem_ev;
 
-	sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_CHANGE, SCTP_U8(SCTP_COMM_UP));
 
 	/* Sockets API Draft Section 5.3.1.6
 	 * When a peer sends a Adaptation Layer Indication parameter , SCTP
 	 * delivers this notification to inform the application that of the
 	 * peers requested adaptation layer.
+	 *
+	 * This also needs to be done as a side effect for the same reason as
+	 * above.
 	 */
-	if (asoc->peer.adaptation_ind) {
-		ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
-		if (!ev)
-			goto nomem_ev;
-
-		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-				SCTP_ULPEVENT(ev));
-	}
+	if (asoc->peer.adaptation_ind)
+		sctp_add_cmd_sf(commands, SCTP_CMD_ADAPTATION_IND, SCTP_NULL());
 
 	return SCTP_DISPOSITION_CONSUME;
 
-nomem_ev:
-	sctp_chunk_free(repl);
 nomem:
 	return SCTP_DISPOSITION_NOMEM;
 }
@@ -1786,7 +1779,7 @@ static sctp_disposition_t sctp_sf_do_dup
 					     SCTP_COMM_UP, 0,
 					     asoc->c.sinit_num_ostreams,
 					     asoc->c.sinit_max_instreams,
-					     GFP_ATOMIC);
+                                             NULL, GFP_ATOMIC);
 		if (!ev)
 			goto nomem;
 
@@ -1904,7 +1897,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupc
 		case -SCTP_IERROR_BAD_SIG:
 		default:
 			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
-		};
+		}
 	}
 
 	/* Compare the tie_tag in cookie with the verification tag of
@@ -1936,7 +1929,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupc
 	default: /* Discard packet for all others. */
 		retval = sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 		break;
-	};
+	}
 
 	/* Delete the tempory new association. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
@@ -3035,7 +3028,7 @@ sctp_disposition_t sctp_sf_do_9_2_final(
 	 * notification is passed to the upper layer.
 	 */
 	ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP,
-					     0, 0, 0, GFP_ATOMIC);
+					     0, 0, 0, NULL, GFP_ATOMIC);
 	if (!ev)
 		goto nomem;
 
@@ -3115,7 +3108,7 @@ sctp_disposition_t sctp_sf_ootb(const st
 			break;
 
 		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
-		if (ch_end > skb->tail)
+		if (ch_end > skb_tail_pointer(skb))
 			break;
 
 		if (SCTP_CID_SHUTDOWN_ACK == ch->type)
@@ -3130,7 +3123,7 @@ sctp_disposition_t sctp_sf_ootb(const st
 			return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 		ch = (sctp_chunkhdr_t *) ch_end;
-	} while (ch_end < skb->tail);
+	} while (ch_end < skb_tail_pointer(skb));
 
 	if (ootb_shut_ack)
 		sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
@@ -4816,7 +4809,7 @@ sctp_disposition_t sctp_sf_t2_timer_expi
 	default:
 		BUG();
 		break;
-	};
+	}
 
 	if (!reply)
 		goto nomem;
@@ -5286,7 +5279,7 @@ static int sctp_eat_data(const struct sc
 		chunk->ecn_ce_done = 1;
 
 		af = sctp_get_af_specific(
-			ipver2af(chunk->skb->nh.iph->version));
+			ipver2af(ip_hdr(chunk->skb)->version));
 
 		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
 			/* Do real work as sideffect. */
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index 5e54b17..523071c 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -101,7 +101,7 @@ const sctp_sm_table_entry_t *sctp_sm_loo
 	default:
 		/* Yikes!  We got an illegal event type.  */
 		return &bug;
-	};
+	}
 }
 
 #define TYPE_SCTP_FUNC(func) {.fn = func, .name = #func}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1d026f..9f1a908 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -941,7 +941,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(st
 	default:
 		err = -EINVAL;
 		break;
-	};
+	}
 
 out:
 	kfree(kaddrs);
@@ -972,6 +972,7 @@ static int __sctp_connect(struct sock* s
 	int walk_size = 0;
 	union sctp_addr *sa_addr;
 	void *addr_buf;
+	unsigned short port;
 
 	sp = sctp_sk(sk);
 	ep = sp->ep;
@@ -992,6 +993,7 @@ static int __sctp_connect(struct sock* s
 	while (walk_size < addrs_size) {
 		sa_addr = (union sctp_addr *)addr_buf;
 		af = sctp_get_af_specific(sa_addr->sa.sa_family);
+		port = ntohs(sa_addr->v4.sin_port);
 
 		/* If the address family is not supported or if this address
 		 * causes the address buffer to overflow return EINVAL.
@@ -1005,6 +1007,12 @@ static int __sctp_connect(struct sock* s
 		if (err)
 			goto out_free;
 
+		/* Make sure the destination port is correctly set
+		 * in all addresses.
+		 */
+		if (asoc && asoc->peer.port && asoc->peer.port != port)
+			goto out_free;
+
 		memcpy(&to, sa_addr, af->sockaddr_len);
 
 		/* Check if there already is a matching association on the
@@ -2039,6 +2047,10 @@ static int sctp_setsockopt_autoclose(str
  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
  *                     to be made immediately.
  *
+ *                     SPP_HB_TIME_IS_ZERO - Specify's that the time for
+ *                     heartbeat delayis to be set to the value of 0
+ *                     milliseconds.
+ *
  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
  *                     discovery upon the specified address. Note that
  *                     if the address feild is empty then all addresses
@@ -2081,13 +2093,30 @@ static int sctp_apply_peer_addr_params(s
 			return error;
 	}
 
-	if (params->spp_hbinterval) {
-		if (trans) {
-			trans->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
-		} else if (asoc) {
-			asoc->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
-		} else {
-			sp->hbinterval = params->spp_hbinterval;
+	/* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of
+	 * this field is ignored.  Note also that a value of zero indicates
+	 * the current setting should be left unchanged.
+	 */
+	if (params->spp_flags & SPP_HB_ENABLE) {
+
+		/* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is
+		 * set.  This lets us use 0 value when this flag
+		 * is set.
+		 */
+		if (params->spp_flags & SPP_HB_TIME_IS_ZERO)
+			params->spp_hbinterval = 0;
+
+		if (params->spp_hbinterval ||
+		    (params->spp_flags & SPP_HB_TIME_IS_ZERO)) {
+			if (trans) {
+				trans->hbinterval =
+				    msecs_to_jiffies(params->spp_hbinterval);
+			} else if (asoc) {
+				asoc->hbinterval =
+				    msecs_to_jiffies(params->spp_hbinterval);
+			} else {
+				sp->hbinterval = params->spp_hbinterval;
+			}
 		}
 	}
 
@@ -2104,7 +2133,12 @@ static int sctp_apply_peer_addr_params(s
 		}
 	}
 
-	if (params->spp_pathmtu) {
+	/* When Path MTU discovery is disabled the value specified here will
+	 * be the "fixed" path mtu (i.e. the value of the spp_flags field must
+	 * include the flag SPP_PMTUD_DISABLE for this field to have any
+	 * effect).
+	 */
+	if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
 		if (trans) {
 			trans->pathmtu = params->spp_pathmtu;
 			sctp_assoc_sync_pmtu(asoc);
@@ -2135,7 +2169,11 @@ static int sctp_apply_peer_addr_params(s
 		}
 	}
 
-	if (params->spp_sackdelay) {
+	/* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the
+	 * value of this field is ignored.  Note also that a value of zero
+	 * indicates the current setting should be left unchanged.
+	 */
+	if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) {
 		if (trans) {
 			trans->sackdelay =
 				msecs_to_jiffies(params->spp_sackdelay);
@@ -2163,7 +2201,11 @@ static int sctp_apply_peer_addr_params(s
 		}
 	}
 
-	if (params->spp_pathmaxrxt) {
+	/* Note that unless the spp_flag is set to SPP_PMTUD_ENABLE the value
+	 * of this field is ignored.  Note also that a value of zero
+	 * indicates the current setting should be left unchanged.
+	 */
+	if ((params->spp_flags & SPP_PMTUD_ENABLE) && params->spp_pathmaxrxt) {
 		if (trans) {
 			trans->pathmaxrxt = params->spp_pathmaxrxt;
 		} else if (asoc) {
@@ -2255,7 +2297,7 @@ static int sctp_setsockopt_peer_addr_par
 	return 0;
 }
 
-/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
  *
  *   This options will get or set the delayed ack timer.  The time is set
  *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
@@ -2792,6 +2834,102 @@ static int sctp_setsockopt_context(struc
 	return 0;
 }
 
+/*
+ * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
+ *
+ * This options will at a minimum specify if the implementation is doing
+ * fragmented interleave.  Fragmented interleave, for a one to many
+ * socket, is when subsequent calls to receive a message may return
+ * parts of messages from different associations.  Some implementations
+ * may allow you to turn this value on or off.  If so, when turned off,
+ * no fragment interleave will occur (which will cause a head of line
+ * blocking amongst multiple associations sharing the same one to many
+ * socket).  When this option is turned on, then each receive call may
+ * come from a different association (thus the user must receive data
+ * with the extended calls (e.g. sctp_recvmsg) to keep track of which
+ * association each receive belongs to.
+ *
+ * This option takes a boolean value.  A non-zero value indicates that
+ * fragmented interleave is on.  A value of zero indicates that
+ * fragmented interleave is off.
+ *
+ * Note that it is important that an implementation that allows this
+ * option to be turned on, have it off by default.  Otherwise an unaware
+ * application using the one to many model may become confused and act
+ * incorrectly.
+ */
+static int sctp_setsockopt_fragment_interleave(struct sock *sk,
+					       char __user *optval,
+					       int optlen)
+{
+	int val;
+
+	if (optlen != sizeof(int))
+		return -EINVAL;
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	sctp_sk(sk)->frag_interleave = (val == 0) ? 0 : 1;
+
+	return 0;
+}
+
+/*
+ * 7.1.25.  Set or Get the sctp partial delivery point
+ *       (SCTP_PARTIAL_DELIVERY_POINT)
+ * This option will set or get the SCTP partial delivery point.  This
+ * point is the size of a message where the partial delivery API will be
+ * invoked to help free up rwnd space for the peer.  Setting this to a
+ * lower value will cause partial delivery's to happen more often.  The
+ * calls argument is an integer that sets or gets the partial delivery
+ * point.
+ */
+static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
+						  char __user *optval,
+						  int optlen)
+{
+	u32 val;
+
+	if (optlen != sizeof(u32))
+		return -EINVAL;
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	sctp_sk(sk)->pd_point = val;
+
+	return 0; /* is this the right error code? */
+}
+
+/*
+ * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
+ *
+ * This option will allow a user to change the maximum burst of packets
+ * that can be emitted by this association.  Note that the default value
+ * is 4, and some implementations may restrict this setting so that it
+ * can only be lowered.
+ *
+ * NOTE: This text doesn't seem right.  Do this on a socket basis with
+ * future associations inheriting the socket value.
+ */
+static int sctp_setsockopt_maxburst(struct sock *sk,
+				    char __user *optval,
+				    int optlen)
+{
+	int val;
+
+	if (optlen != sizeof(int))
+		return -EINVAL;
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	if (val < 0)
+		return -EINVAL;
+
+	sctp_sk(sk)->max_burst = val;
+
+	return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -2871,6 +3009,9 @@ SCTP_STATIC int sctp_setsockopt(struct s
 	case SCTP_DELAYED_ACK_TIME:
 		retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
 		break;
+	case SCTP_PARTIAL_DELIVERY_POINT:
+		retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
+		break;
 
 	case SCTP_INITMSG:
 		retval = sctp_setsockopt_initmsg(sk, optval, optlen);
@@ -2906,11 +3047,16 @@ SCTP_STATIC int sctp_setsockopt(struct s
 	case SCTP_CONTEXT:
 		retval = sctp_setsockopt_context(sk, optval, optlen);
 		break;
-
+	case SCTP_FRAGMENT_INTERLEAVE:
+		retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen);
+		break;
+	case SCTP_MAX_BURST:
+		retval = sctp_setsockopt_maxburst(sk, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	sctp_release_sock(sk);
 
@@ -3066,6 +3212,7 @@ SCTP_STATIC int sctp_init_sock(struct so
 	sp->default_timetolive = 0;
 
 	sp->default_rcv_context = 0;
+	sp->max_burst = sctp_max_burst;
 
 	/* Initialize default setup parameters. These parameters
 	 * can be modified with the SCTP_INITMSG socket option or
@@ -3134,8 +3281,9 @@ SCTP_STATIC int sctp_init_sock(struct so
 	sp->pf = sctp_get_pf_specific(sk->sk_family);
 
 	/* Control variables for partial data delivery. */
-	sp->pd_mode           = 0;
+	atomic_set(&sp->pd_mode, 0);
 	skb_queue_head_init(&sp->pd_lobby);
+	sp->frag_interleave = 0;
 
 	/* Create a per socket endpoint structure.  Even if we
 	 * change the data structure relationships, this may still
@@ -3642,7 +3790,7 @@ static int sctp_getsockopt_peer_addr_par
 	return 0;
 }
 
-/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
  *
  *   This options will get or set the delayed ack timer.  The time is set
  *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
@@ -3847,7 +3995,7 @@ static int sctp_getsockopt_peer_addrs(st
 		memcpy(&temp, &from->ipaddr, sizeof(temp));
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
-		if(space_left < addrlen)
+		if (space_left < addrlen)
 			return -ENOMEM;
 		if (copy_to_user(to, &temp, addrlen))
 			return -EFAULT;
@@ -3936,8 +4084,9 @@ done:
 /* Helper function that copies local addresses to user and returns the number
  * of addresses copied.
  */
-static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
-					void __user *to)
+static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
+					int max_addrs, void *to,
+					int *bytes_copied)
 {
 	struct list_head *pos, *next;
 	struct sctp_sockaddr_entry *addr;
@@ -3954,10 +4103,10 @@ static int sctp_copy_laddrs_to_user_old(
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
 								&temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-		if (copy_to_user(to, &temp, addrlen))
-			return -EFAULT;
+		memcpy(to, &temp, addrlen);
 
 		to += addrlen;
+		*bytes_copied += addrlen;
 		cnt ++;
 		if (cnt >= max_addrs) break;
 	}
@@ -3965,8 +4114,8 @@ static int sctp_copy_laddrs_to_user_old(
 	return cnt;
 }
 
-static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
-				    void __user **to, size_t space_left)
+static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
+			    size_t space_left, int *bytes_copied)
 {
 	struct list_head *pos, *next;
 	struct sctp_sockaddr_entry *addr;
@@ -3983,14 +4132,14 @@ static int sctp_copy_laddrs_to_user(stru
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
 								&temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-		if(space_left<addrlen)
+		if (space_left < addrlen)
 			return -ENOMEM;
-		if (copy_to_user(*to, &temp, addrlen))
-			return -EFAULT;
+		memcpy(to, &temp, addrlen);
 
-		*to += addrlen;
+		to += addrlen;
 		cnt ++;
 		space_left -= addrlen;
+		bytes_copied += addrlen;
 	}
 
 	return cnt;
@@ -4014,6 +4163,8 @@ static int sctp_getsockopt_local_addrs_o
 	int addrlen;
 	rwlock_t *addr_lock;
 	int err = 0;
+	void *addrs;
+	int bytes_copied = 0;
 
 	if (len != sizeof(struct sctp_getaddrs_old))
 		return -EINVAL;
@@ -4041,6 +4192,15 @@ static int sctp_getsockopt_local_addrs_o
 
 	to = getaddrs.addrs;
 
+	/* Allocate space for a local instance of packed array to hold all
+	 * the data.  We store addresses here first and then put write them
+	 * to the user in one shot.
+	 */
+	addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
+			GFP_KERNEL);
+	if (!addrs)
+		return -ENOMEM;
+
 	sctp_read_lock(addr_lock);
 
 	/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
@@ -4050,13 +4210,9 @@ static int sctp_getsockopt_local_addrs_o
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
 		if (sctp_is_any(&addr->a)) {
-			cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
-							   getaddrs.addr_num,
-							   to);
-			if (cnt < 0) {
-				err = cnt;
-				goto unlock;
-			}
+			cnt = sctp_copy_laddrs_old(sk, bp->port,
+						   getaddrs.addr_num,
+						   addrs, &bytes_copied);
 			goto copy_getaddrs;
 		}
 	}
@@ -4066,22 +4222,29 @@ static int sctp_getsockopt_local_addrs_o
 		memcpy(&temp, &addr->a, sizeof(temp));
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-		if (copy_to_user(to, &temp, addrlen)) {
-			err = -EFAULT;
-			goto unlock;
-		}
+		memcpy(addrs, &temp, addrlen);
 		to += addrlen;
+		bytes_copied += addrlen;
 		cnt ++;
 		if (cnt >= getaddrs.addr_num) break;
 	}
 
 copy_getaddrs:
+	sctp_read_unlock(addr_lock);
+
+	/* copy the entire address list into the user provided space */
+	if (copy_to_user(to, addrs, bytes_copied)) {
+		err = -EFAULT;
+		goto error;
+	}
+
+	/* copy the leading structure back to user */
 	getaddrs.addr_num = cnt;
 	if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
 		err = -EFAULT;
 
-unlock:
-	sctp_read_unlock(addr_lock);
+error:
+	kfree(addrs);
 	return err;
 }
 
@@ -4101,7 +4264,8 @@ static int sctp_getsockopt_local_addrs(s
 	rwlock_t *addr_lock;
 	int err = 0;
 	size_t space_left;
-	int bytes_copied;
+	int bytes_copied = 0;
+	void *addrs;
 
 	if (len <= sizeof(struct sctp_getaddrs))
 		return -EINVAL;
@@ -4129,6 +4293,9 @@ static int sctp_getsockopt_local_addrs(s
 	to = optval + offsetof(struct sctp_getaddrs,addrs);
 	space_left = len - sizeof(struct sctp_getaddrs) -
 			 offsetof(struct sctp_getaddrs,addrs);
+	addrs = kmalloc(space_left, GFP_KERNEL);
+	if (!addrs)
+		return -ENOMEM;
 
 	sctp_read_lock(addr_lock);
 
@@ -4139,11 +4306,11 @@ static int sctp_getsockopt_local_addrs(s
 		addr = list_entry(bp->address_list.next,
 				  struct sctp_sockaddr_entry, list);
 		if (sctp_is_any(&addr->a)) {
-			cnt = sctp_copy_laddrs_to_user(sk, bp->port,
-						       &to, space_left);
+			cnt = sctp_copy_laddrs(sk, bp->port, addrs,
+						space_left, &bytes_copied);
 			if (cnt < 0) {
 				err = cnt;
-				goto unlock;
+				goto error;
 			}
 			goto copy_getaddrs;
 		}
@@ -4154,26 +4321,31 @@ static int sctp_getsockopt_local_addrs(s
 		memcpy(&temp, &addr->a, sizeof(temp));
 		sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
 		addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-		if(space_left < addrlen)
-			return -ENOMEM; /*fixme: right error?*/
-		if (copy_to_user(to, &temp, addrlen)) {
-			err = -EFAULT;
-			goto unlock;
+		if (space_left < addrlen) {
+			err =  -ENOMEM; /*fixme: right error?*/
+			goto error;
 		}
+		memcpy(addrs, &temp, addrlen);
 		to += addrlen;
+		bytes_copied += addrlen;
 		cnt ++;
 		space_left -= addrlen;
 	}
 
 copy_getaddrs:
+	sctp_read_unlock(addr_lock);
+
+	if (copy_to_user(to, addrs, bytes_copied)) {
+		err = -EFAULT;
+		goto error;
+	}
 	if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
 		return -EFAULT;
-	bytes_copied = ((char __user *)to) - optval;
 	if (put_user(bytes_copied, optlen))
 		return -EFAULT;
 
-unlock:
-	sctp_read_unlock(addr_lock);
+error:
+	kfree(addrs);
 	return err;
 }
 
@@ -4536,6 +4708,77 @@ static int sctp_getsockopt_maxseg(struct
 	return 0;
 }
 
+/*
+ * 7.1.24.  Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
+ * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave())
+ */
+static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len,
+					       char __user *optval, int __user *optlen)
+{
+	int val;
+
+	if (len < sizeof(int))
+		return -EINVAL;
+
+	len = sizeof(int);
+
+	val = sctp_sk(sk)->frag_interleave;
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * 7.1.25.  Set or Get the sctp partial delivery point
+ * (chapter and verse is quoted at sctp_setsockopt_partial_delivery_point())
+ */
+static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
+						  char __user *optval,
+						  int __user *optlen)
+{
+        u32 val;
+
+	if (len < sizeof(u32))
+		return -EINVAL;
+
+	len = sizeof(u32);
+
+	val = sctp_sk(sk)->pd_point;
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return -ENOTSUPP;
+}
+
+/*
+ * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
+ * (chapter and verse is quoted at sctp_setsockopt_maxburst())
+ */
+static int sctp_getsockopt_maxburst(struct sock *sk, int len,
+				    char __user *optval,
+				    int __user *optlen)
+{
+        int val;
+
+	if (len < sizeof(int))
+		return -EINVAL;
+
+	len = sizeof(int);
+
+	val = sctp_sk(sk)->max_burst;
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return -ENOTSUPP;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
 				char __user *optval, int __user *optlen)
 {
@@ -4648,10 +4891,21 @@ SCTP_STATIC int sctp_getsockopt(struct s
 	case SCTP_CONTEXT:
 		retval = sctp_getsockopt_context(sk, len, optval, optlen);
 		break;
+	case SCTP_FRAGMENT_INTERLEAVE:
+		retval = sctp_getsockopt_fragment_interleave(sk, len, optval,
+							     optlen);
+		break;
+	case SCTP_PARTIAL_DELIVERY_POINT:
+		retval = sctp_getsockopt_partial_delivery_point(sk, len, optval,
+								optlen);
+		break;
+	case SCTP_MAX_BURST:
+		retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
-	};
+	}
 
 	sctp_release_sock(sk);
 	return retval;
@@ -4766,7 +5020,8 @@ pp_found:
 		struct hlist_node *node;
 
 		SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
-		if (pp->fastreuse && sk->sk_reuse)
+		if (pp->fastreuse && sk->sk_reuse &&
+			sk->sk_state != SCTP_SS_LISTENING)
 			goto success;
 
 		/* Run through the list of sockets bound to the port
@@ -4783,7 +5038,8 @@ pp_found:
 			struct sctp_endpoint *ep2;
 			ep2 = sctp_sk(sk2)->ep;
 
-			if (reuse && sk2->sk_reuse)
+			if (reuse && sk2->sk_reuse &&
+			    sk2->sk_state != SCTP_SS_LISTENING)
 				continue;
 
 			if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
@@ -4804,9 +5060,13 @@ pp_not_found:
 	 * if sk->sk_reuse is too (that is, if the caller requested
 	 * SO_REUSEADDR on this socket -sk-).
 	 */
-	if (hlist_empty(&pp->owner))
-		pp->fastreuse = sk->sk_reuse ? 1 : 0;
-	else if (pp->fastreuse && !sk->sk_reuse)
+	if (hlist_empty(&pp->owner)) {
+		if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING)
+			pp->fastreuse = 1;
+		else
+			pp->fastreuse = 0;
+	} else if (pp->fastreuse &&
+		(!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING))
 		pp->fastreuse = 0;
 
 	/* We are set, so fill up all the data in the hash table
@@ -4814,8 +5074,8 @@ pp_not_found:
 	 * sockets FIXME: Blurry, NPI (ipg).
 	 */
 success:
-	inet_sk(sk)->num = snum;
 	if (!sctp_sk(sk)->bind_hash) {
+		inet_sk(sk)->num = snum;
 		sk_add_bind_node(sk, &pp->owner);
 		sctp_sk(sk)->bind_hash = pp;
 	}
@@ -4888,12 +5148,16 @@ SCTP_STATIC int sctp_seqpacket_listen(st
 	 * This is not currently spelled out in the SCTP sockets
 	 * extensions draft, but follows the practice as seen in TCP
 	 * sockets.
+	 *
+	 * Additionally, turn off fastreuse flag since we are not listening
 	 */
+	sk->sk_state = SCTP_SS_LISTENING;
 	if (!ep->base.bind_addr.port) {
 		if (sctp_autobind(sk))
 			return -EAGAIN;
-	}
-	sk->sk_state = SCTP_SS_LISTENING;
+	} else
+		sctp_sk(sk)->bind_hash->fastreuse = 0;
+
 	sctp_hash_endpoint(ep);
 	return 0;
 }
@@ -4931,11 +5195,13 @@ SCTP_STATIC int sctp_stream_listen(struc
 	 * extensions draft, but follows the practice as seen in TCP
 	 * sockets.
 	 */
+	sk->sk_state = SCTP_SS_LISTENING;
 	if (!ep->base.bind_addr.port) {
 		if (sctp_autobind(sk))
 			return -EAGAIN;
-	}
-	sk->sk_state = SCTP_SS_LISTENING;
+	} else
+		sctp_sk(sk)->bind_hash->fastreuse = 0;
+
 	sk->sk_max_ack_backlog = backlog;
 	sctp_hash_endpoint(ep);
 	return 0;
@@ -4976,7 +5242,8 @@ int sctp_inet_listen(struct socket *sock
 		break;
 	default:
 		break;
-	};
+	}
+
 	if (err)
 		goto cleanup;
 
@@ -5239,7 +5506,7 @@ SCTP_STATIC int sctp_msghdr_parse(const 
 
 		default:
 			return -EINVAL;
-		};
+		}
 	}
 	return 0;
 }
@@ -5742,9 +6009,9 @@ static void sctp_sock_migrate(struct soc
 	 * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue.
 	 */
 	skb_queue_head_init(&newsp->pd_lobby);
-	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;
+	atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode);
 
-	if (sctp_sk(oldsk)->pd_mode) {
+	if (atomic_read(&sctp_sk(oldsk)->pd_mode)) {
 		struct sk_buff_head *queue;
 
 		/* Decide which queue to move pd_lobby skbs to. */
@@ -5770,7 +6037,7 @@ static void sctp_sock_migrate(struct soc
 		 * delivery to finish.
 		 */
 		if (assoc->ulpq.pd_mode)
-			sctp_clear_pd(oldsk);
+			sctp_clear_pd(oldsk, NULL);
 
 	}
 
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 4d8c2ab..961df27 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -507,7 +507,7 @@ void sctp_transport_lower_cwnd(struct sc
 			transport->cwnd = max(transport->cwnd/2,
 						 4*transport->asoc->pathmtu);
 		break;
-	};
+	}
 
 	transport->partial_bytes_acked = 0;
 	SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 2e11bc8..661ea2d 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -131,19 +131,54 @@ static inline void sctp_ulpevent_release
 struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
 	const struct sctp_association *asoc,
 	__u16 flags, __u16 state, __u16 error, __u16 outbound,
-	__u16 inbound, gfp_t gfp)
+	__u16 inbound, struct sctp_chunk *chunk, gfp_t gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_assoc_change *sac;
 	struct sk_buff *skb;
 
-	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
+	/* If the lower layer passed in the chunk, it will be
+	 * an ABORT, so we need to include it in the sac_info.
+	 */
+	if (chunk) {
+		/* sctp_inqu_pop() has allready pulled off the chunk
+		 * header.  We need to put it back temporarily
+		 */
+		skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));
+
+		/* Copy the chunk data to a new skb and reserve enough
+		 * head room to use as notification.
+		 */
+		skb = skb_copy_expand(chunk->skb,
+				      sizeof(struct sctp_assoc_change), 0, gfp);
+
+		if (!skb)
+			goto fail;
+
+		/* put back the chunk header now that we have a copy */
+		skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
+
+		/* Embed the event fields inside the cloned skb.  */
+		event = sctp_skb2event(skb);
+		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
+
+		/* Include the notification structure */
+		sac = (struct sctp_assoc_change *)
+			skb_push(skb, sizeof(struct sctp_assoc_change));
+
+		/* Trim the buffer to the right length.  */
+		skb_trim(skb, sizeof(struct sctp_assoc_change) +
+			 ntohs(chunk->chunk_hdr->length));
+	} else {
+		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
 				  MSG_NOTIFICATION, gfp);
-	if (!event)
-		goto fail;
-	skb = sctp_event2skb(event);
-	sac = (struct sctp_assoc_change *)
-		skb_put(skb, sizeof(struct sctp_assoc_change));
+		if (!event)
+			goto fail;
+
+		skb = sctp_event2skb(event);
+		sac = (struct sctp_assoc_change *) skb_put(skb,
+					sizeof(struct sctp_assoc_change));
+	}
 
 	/* Socket Extensions for SCTP
 	 * 5.3.1.1 SCTP_ASSOC_CHANGE
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index b29e3e4..34eb977 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -138,26 +138,59 @@ int sctp_ulpq_tail_data(struct sctp_ulpq
 /* Clear the partial delivery mode for this socket.   Note: This
  * assumes that no association is currently in partial delivery mode.
  */
-int sctp_clear_pd(struct sock *sk)
+int sctp_clear_pd(struct sock *sk, struct sctp_association *asoc)
 {
 	struct sctp_sock *sp = sctp_sk(sk);
 
-	sp->pd_mode = 0;
-	if (!skb_queue_empty(&sp->pd_lobby)) {
-		struct list_head *list;
-		sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue);
-		list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
-		INIT_LIST_HEAD(list);
-		return 1;
+	if (atomic_dec_and_test(&sp->pd_mode)) {
+		/* This means there are no other associations in PD, so
+		 * we can go ahead and clear out the lobby in one shot
+		 */
+		if (!skb_queue_empty(&sp->pd_lobby)) {
+			struct list_head *list;
+			sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue);
+			list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
+			INIT_LIST_HEAD(list);
+			return 1;
+		}
+	} else {
+		/* There are other associations in PD, so we only need to
+		 * pull stuff out of the lobby that belongs to the
+		 * associations that is exiting PD (all of its notifications
+		 * are posted here).
+		 */
+		if (!skb_queue_empty(&sp->pd_lobby) && asoc) {
+			struct sk_buff *skb, *tmp;
+			struct sctp_ulpevent *event;
+
+			sctp_skb_for_each(skb, &sp->pd_lobby, tmp) {
+				event = sctp_skb2event(skb);
+				if (event->asoc == asoc) {
+					__skb_unlink(skb, &sp->pd_lobby);
+					__skb_queue_tail(&sk->sk_receive_queue,
+							 skb);
+				}
+			}
+		}
 	}
+
 	return 0;
 }
 
+/* Set the pd_mode on the socket and ulpq */
+static void sctp_ulpq_set_pd(struct sctp_ulpq *ulpq)
+{
+	struct sctp_sock *sp = sctp_sk(ulpq->asoc->base.sk);
+
+	atomic_inc(&sp->pd_mode);
+	ulpq->pd_mode = 1;
+}
+
 /* Clear the pd_mode and restart any pending messages waiting for delivery. */
 static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
 {
 	ulpq->pd_mode = 0;
-	return sctp_clear_pd(ulpq->asoc->base.sk);
+	return sctp_clear_pd(ulpq->asoc->base.sk, ulpq->asoc);
 }
 
 /* If the SKB of 'event' is on a list, it is the first such member
@@ -187,25 +220,35 @@ int sctp_ulpq_tail_event(struct sctp_ulp
 	 * the association the cause of the partial delivery.
 	 */
 
-	if (!sctp_sk(sk)->pd_mode) {
+	if (atomic_read(&sctp_sk(sk)->pd_mode) == 0) {
 		queue = &sk->sk_receive_queue;
-	} else if (ulpq->pd_mode) {
-		/* If the association is in partial delivery, we
-		 * need to finish delivering the partially processed
-		 * packet before passing any other data.  This is
-		 * because we don't truly support stream interleaving.
-		 */
-		if ((event->msg_flags & MSG_NOTIFICATION) ||
-		    (SCTP_DATA_NOT_FRAG ==
-			    (event->msg_flags & SCTP_DATA_FRAG_MASK)))
-			queue = &sctp_sk(sk)->pd_lobby;
-		else {
-			clear_pd = event->msg_flags & MSG_EOR;
-			queue = &sk->sk_receive_queue;
+	} else {
+		if (ulpq->pd_mode) {
+			/* If the association is in partial delivery, we
+			 * need to finish delivering the partially processed
+			 * packet before passing any other data.  This is
+			 * because we don't truly support stream interleaving.
+			 */
+			if ((event->msg_flags & MSG_NOTIFICATION) ||
+			    (SCTP_DATA_NOT_FRAG ==
+				    (event->msg_flags & SCTP_DATA_FRAG_MASK)))
+				queue = &sctp_sk(sk)->pd_lobby;
+			else {
+				clear_pd = event->msg_flags & MSG_EOR;
+				queue = &sk->sk_receive_queue;
+			}
+		} else {
+			/*
+			 * If fragment interleave is enabled, we
+			 * can queue this to the recieve queue instead
+			 * of the lobby.
+			 */
+			if (sctp_sk(sk)->frag_interleave)
+				queue = &sk->sk_receive_queue;
+			else
+				queue = &sctp_sk(sk)->pd_lobby;
 		}
-	} else
-		queue = &sctp_sk(sk)->pd_lobby;
-
+	}
 
 	/* If we are harvesting multiple skbs they will be
 	 * collected on a list.
@@ -348,7 +391,7 @@ static struct sctp_ulpevent *sctp_make_r
 			break;
 		pos->next = pnext;
 		pos = pnext;
-	};
+	}
 
 	event = sctp_skb2event(f_frag);
 	SCTP_INC_STATS(SCTP_MIB_REASMUSRMSGS);
@@ -367,6 +410,11 @@ static inline struct sctp_ulpevent *sctp
 	struct sk_buff *first_frag = NULL;
 	__u32 ctsn, next_tsn;
 	struct sctp_ulpevent *retval = NULL;
+	struct sk_buff *pd_first = NULL;
+	struct sk_buff *pd_last = NULL;
+	size_t pd_len = 0;
+	struct sctp_association *asoc;
+	u32 pd_point;
 
 	/* Initialized to 0 just to avoid compiler warning message.  Will
 	 * never be used with this value. It is referenced only after it
@@ -382,6 +430,10 @@ static inline struct sctp_ulpevent *sctp
 	 * we expect to find the remaining middle fragments and the last
 	 * fragment in order. If not, first_frag is reset to NULL and we
 	 * start the next pass when we find another first fragment.
+	 *
+	 * There is a potential to do partial delivery if user sets
+	 * SCTP_PARTIAL_DELIVERY_POINT option. Lets count some things here
+	 * to see if can do PD.
 	 */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
@@ -389,14 +441,32 @@ static inline struct sctp_ulpevent *sctp
 
 		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
+			/* If this "FIRST_FRAG" is the first
+			 * element in the queue, then count it towards
+			 * possible PD.
+			 */
+			if (pos == ulpq->reasm.next) {
+			    pd_first = pos;
+			    pd_last = pos;
+			    pd_len = pos->len;
+			} else {
+			    pd_first = NULL;
+			    pd_last = NULL;
+			    pd_len = 0;
+			}
+
 			first_frag = pos;
 			next_tsn = ctsn + 1;
 			break;
 
 		case SCTP_DATA_MIDDLE_FRAG:
-			if ((first_frag) && (ctsn == next_tsn))
+			if ((first_frag) && (ctsn == next_tsn)) {
 				next_tsn++;
-			else
+				if (pd_first) {
+				    pd_last = pos;
+				    pd_len += pos->len;
+				}
+			} else
 				first_frag = NULL;
 			break;
 
@@ -406,8 +476,29 @@ static inline struct sctp_ulpevent *sctp
 			else
 				first_frag = NULL;
 			break;
-		};
+		}
+	}
 
+	asoc = ulpq->asoc;
+	if (pd_first) {
+		/* Make sure we can enter partial deliver.
+		 * We can trigger partial delivery only if framgent
+		 * interleave is set, or the socket is not already
+		 * in  partial delivery.
+		 */
+		if (!sctp_sk(asoc->base.sk)->frag_interleave &&
+		    atomic_read(&sctp_sk(asoc->base.sk)->pd_mode))
+			goto done;
+
+		cevent = sctp_skb2event(pd_first);
+		pd_point = sctp_sk(asoc->base.sk)->pd_point;
+		if (pd_point && pd_point <= pd_len) {
+			retval = sctp_make_reassembled_event(&ulpq->reasm,
+							     pd_first,
+							     pd_last);
+			if (retval)
+				sctp_ulpq_set_pd(ulpq);
+		}
 	}
 done:
 	return retval;
@@ -465,7 +556,7 @@ static inline struct sctp_ulpevent *sctp
 			goto done;
 		default:
 			return NULL;
-		};
+		}
 	}
 
 	/* We have the reassembled event. There is no need to look
@@ -557,7 +648,7 @@ static inline struct sctp_ulpevent *sctp
 			break;
 		default:
 			return NULL;
-		};
+		}
 	}
 
 	/* We have the reassembled event. There is no need to look
@@ -826,19 +917,29 @@ void sctp_ulpq_partial_delivery(struct s
 {
 	struct sctp_ulpevent *event;
 	struct sctp_association *asoc;
+	struct sctp_sock *sp;
 
 	asoc = ulpq->asoc;
+	sp = sctp_sk(asoc->base.sk);
 
-	/* Are we already in partial delivery mode?  */
-	if (!sctp_sk(asoc->base.sk)->pd_mode) {
+	/* If the association is already in Partial Delivery mode
+	 * we have noting to do.
+	 */
+	if (ulpq->pd_mode)
+		return;
 
+	/* If the user enabled fragment interleave socket option,
+	 * multiple associations can enter partial delivery.
+	 * Otherwise, we can only enter partial delivery if the
+	 * socket is not in partial deliver mode.
+	 */
+	if (sp->frag_interleave || atomic_read(&sp->pd_mode) == 0) {
 		/* Is partial delivery possible?  */
 		event = sctp_ulpq_retrieve_first(ulpq);
 		/* Send event to the ULP.   */
 		if (event) {
 			sctp_ulpq_tail_event(ulpq, event);
-			sctp_sk(asoc->base.sk)->pd_mode = 1;
-			ulpq->pd_mode = 1;
+			sctp_ulpq_set_pd(ulpq);
 			return;
 		}
 	}
diff --git a/net/socket.c b/net/socket.c
index ea8f81a..98a8f67 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -261,8 +261,7 @@ static void init_once(void *foo, struct 
 {
 	struct socket_alloc *ei = (struct socket_alloc *)foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR))
-	    == SLAB_CTOR_CONSTRUCTOR)
+	if (flags & SLAB_CTOR_CONSTRUCTOR)
 		inode_init_once(&ei->vfs_inode);
 }
 
@@ -314,8 +313,19 @@ static int sockfs_delete_dentry(struct d
 	dentry->d_flags |= DCACHE_UNHASHED;
 	return 0;
 }
+
+/*
+ * sockfs_dname() is called from d_path().
+ */
+static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+	return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
+				dentry->d_inode->i_ino);
+}
+
 static struct dentry_operations sockfs_dentry_operations = {
 	.d_delete = sockfs_delete_dentry,
+	.d_dname  = sockfs_dname,
 };
 
 /*
@@ -355,14 +365,9 @@ static int sock_alloc_fd(struct file **f
 
 static int sock_attach_fd(struct socket *sock, struct file *file)
 {
-	struct qstr this;
-	char name[32];
+	struct qstr name = { .name = "" };
 
-	this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
-	this.name = name;
-	this.hash = 0;
-
-	file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+	file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
 	if (unlikely(!file->f_path.dentry))
 		return -ENOMEM;
 
@@ -585,6 +590,37 @@ int kernel_sendmsg(struct socket *sock, 
 	return result;
 }
 
+/*
+ * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
+ */
+void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb)
+{
+	ktime_t kt = skb->tstamp;
+
+	if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
+		struct timeval tv;
+		/* Race occurred between timestamp enabling and packet
+		   receiving.  Fill in the current time for now. */
+		if (kt.tv64 == 0)
+			kt = ktime_get_real();
+		skb->tstamp = kt;
+		tv = ktime_to_timeval(kt);
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv);
+	} else {
+		struct timespec ts;
+		/* Race occurred between timestamp enabling and packet
+		   receiving.  Fill in the current time for now. */
+		if (kt.tv64 == 0)
+			kt = ktime_get_real();
+		skb->tstamp = kt;
+		ts = ktime_to_timespec(kt);
+		put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts);
+	}
+}
+
+EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
+
 static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 				 struct msghdr *msg, size_t size, int flags)
 {
@@ -1292,7 +1328,7 @@ asmlinkage long sys_bind(int fd, struct 
 	int err, fput_needed;
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
-	if(sock) {
+	if (sock) {
 		err = move_addr_to_kernel(umyaddr, addrlen, address);
 		if (err >= 0) {
 			err = security_socket_bind(sock,
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index cdcab9c..8ebfc4d 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o svcauth_unix.o \
-	    pmap_clnt.o timer.o xdr.o \
+	    rpcb_clnt.o timer.o xdr.o \
 	    sunrpc_syms.o cache.o rpc_pipe.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index 104cbf4..d158635 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -123,9 +123,6 @@ spkm3_make_token(struct spkm3_ctx *ctx,
 
 	return  GSS_S_COMPLETE;
 out_err:
-	if (md5cksum.data)
-		kfree(md5cksum.data);
-
 	token->data = NULL;
 	token->len = 0;
 	return GSS_S_FAILURE;
@@ -152,7 +149,7 @@ make_spkm3_checksum(s32 cksumtype, struc
 
 	switch (cksumtype) {
 		case CKSUMTYPE_HMAC_MD5:
-			cksumname = "md5";
+			cksumname = "hmac(md5)";
 			break;
 		default:
 			dprintk("RPC:       spkm3_make_checksum:"
@@ -172,8 +169,12 @@ make_spkm3_checksum(s32 cksumtype, struc
 	if (err)
 		goto out;
 
+	err = crypto_hash_init(&desc);
+	if (err)
+		goto out;
+
 	sg_set_buf(sg, header, hdrlen);
-	crypto_hash_update(&desc, sg, 1);
+	crypto_hash_update(&desc, sg, sg->length);
 
 	xdr_process_buf(body, body_offset, body->len - body_offset,
 			spkm3_checksummer, &desc);
@@ -184,5 +185,3 @@ out:
 
 	return err ? GSS_S_FAILURE : 0;
 }
-
-EXPORT_SYMBOL(make_spkm3_checksum);
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index f02f24a..543b085 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1237,20 +1237,12 @@ static int content_open(struct inode *in
 
 	return res;
 }
-static int content_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct handle *han = m->private;
-	kfree(han);
-	m->private = NULL;
-	return seq_release(inode, file);
-}
 
 static const struct file_operations content_file_operations = {
 	.open		= content_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= content_release,
+	.release	= seq_release_private,
 };
 
 static ssize_t read_flush(struct file *file, char __user *buf,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 396cdbe..d8fbee4 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -36,8 +36,6 @@ #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/metrics.h>
 
 
-#define RPC_SLACK_SPACE		(1024)	/* total overkill */
-
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_CALL
 #endif
@@ -747,21 +745,38 @@ call_reserveresult(struct rpc_task *task
 static void
 call_allocate(struct rpc_task *task)
 {
+	unsigned int slack = task->tk_auth->au_cslack;
 	struct rpc_rqst *req = task->tk_rqstp;
 	struct rpc_xprt *xprt = task->tk_xprt;
-	unsigned int	bufsiz;
+	struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
 
 	dprint_status(task);
 
+	task->tk_status = 0;
 	task->tk_action = call_bind;
+
 	if (req->rq_buffer)
 		return;
 
-	/* FIXME: compute buffer requirements more exactly using
-	 * auth->au_wslack */
-	bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE;
+	if (proc->p_proc != 0) {
+		BUG_ON(proc->p_arglen == 0);
+		if (proc->p_decode != NULL)
+			BUG_ON(proc->p_replen == 0);
+	}
 
-	if (xprt->ops->buf_alloc(task, bufsiz << 1) != NULL)
+	/*
+	 * Calculate the size (in quads) of the RPC call
+	 * and reply headers, and convert both values
+	 * to byte sizes.
+	 */
+	req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
+	req->rq_callsize <<= 2;
+	req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
+	req->rq_rcvsize <<= 2;
+
+	req->rq_buffer = xprt->ops->buf_alloc(task,
+					req->rq_callsize + req->rq_rcvsize);
+	if (req->rq_buffer != NULL)
 		return;
 
 	dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
@@ -788,6 +803,17 @@ rpc_task_force_reencode(struct rpc_task 
 	task->tk_rqstp->rq_snd_buf.len = 0;
 }
 
+static inline void
+rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
+{
+	buf->head[0].iov_base = start;
+	buf->head[0].iov_len = len;
+	buf->tail[0].iov_len = 0;
+	buf->page_len = 0;
+	buf->len = 0;
+	buf->buflen = len;
+}
+
 /*
  * 3.	Encode arguments of an RPC call
  */
@@ -795,28 +821,17 @@ static void
 call_encode(struct rpc_task *task)
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
-	struct xdr_buf *sndbuf = &req->rq_snd_buf;
-	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
-	unsigned int	bufsiz;
 	kxdrproc_t	encode;
 	__be32		*p;
 
 	dprint_status(task);
 
-	/* Default buffer setup */
-	bufsiz = req->rq_bufsize >> 1;
-	sndbuf->head[0].iov_base = (void *)req->rq_buffer;
-	sndbuf->head[0].iov_len  = bufsiz;
-	sndbuf->tail[0].iov_len  = 0;
-	sndbuf->page_len	 = 0;
-	sndbuf->len		 = 0;
-	sndbuf->buflen		 = bufsiz;
-	rcvbuf->head[0].iov_base = (void *)((char *)req->rq_buffer + bufsiz);
-	rcvbuf->head[0].iov_len  = bufsiz;
-	rcvbuf->tail[0].iov_len  = 0;
-	rcvbuf->page_len	 = 0;
-	rcvbuf->len		 = 0;
-	rcvbuf->buflen		 = bufsiz;
+	rpc_xdr_buf_init(&req->rq_snd_buf,
+			 req->rq_buffer,
+			 req->rq_callsize);
+	rpc_xdr_buf_init(&req->rq_rcv_buf,
+			 (char *)req->rq_buffer + req->rq_callsize,
+			 req->rq_rcvsize);
 
 	/* Encode header and provided arguments */
 	encode = task->tk_msg.rpc_proc->p_encode;
@@ -887,9 +902,11 @@ call_bind_status(struct rpc_task *task)
 				task->tk_pid);
 		break;
 	case -EPROTONOSUPPORT:
-		dprintk("RPC: %5u remote rpcbind version 2 unavailable\n",
+		dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
 				task->tk_pid);
-		break;
+		task->tk_status = 0;
+		task->tk_action = call_bind;
+		return;
 	default:
 		dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
 				task->tk_pid, -task->tk_status);
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
deleted file mode 100644
index d9f7653..0000000
--- a/net/sunrpc/pmap_clnt.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * linux/net/sunrpc/pmap_clnt.c
- *
- * In-kernel RPC portmapper client.
- *
- * Portmapper supports version 2 of the rpcbind protocol (RFC 1833).
- *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/uio.h>
-#include <linux/in.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/sched.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY	RPCDBG_PMAP
-#endif
-
-#define PMAP_SET		1
-#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 *, void *);
-static struct rpc_program	pmap_program;
-
-static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
-{
-	struct portmap_args *map = calldata;
-	struct rpc_message msg = {
-		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
-		.rpc_argp	= map,
-		.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)
-{
-	struct portmap_args *map = data;
-
-	xprt_put(map->pm_xprt);
-	pmap_map_free(map);
-}
-
-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;
-	int status;
-
-	dprintk("RPC: %5u rpc_getport(%s, %u, %u, %d)\n",
-			task->tk_pid, clnt->cl_server,
-			clnt->cl_prog, clnt->cl_vers, xprt->prot);
-
-	/* Autobind on cloned rpc clients is discouraged */
-	BUG_ON(clnt->cl_parent != clnt);
-
-	status = -EACCES;		/* tell caller to check again */
-	if (xprt_test_and_set_binding(xprt))
-		goto bailout_nowake;
-
-	/* 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);
-
-	/* 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;
-
-	status = -EIO;
-	child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
-	if (IS_ERR(child))
-		goto bailout_nofree;
-	rpc_put_task(child);
-
-	task->tk_xprt->stat.bind_count++;
-	return;
-
-bailout:
-	pmap_map_free(map);
-	xprt_put(xprt);
-bailout_nofree:
-	pmap_wake_portmap_waiters(xprt, status);
-bailout_nowake:
-	task->tk_status = status;
-}
-
-#ifdef CONFIG_ROOT_NFS
-/**
- * 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 portmap_args map = {
-		.pm_prog	= prog,
-		.pm_vers	= vers,
-		.pm_prot	= prot,
-		.pm_port	= 0
-	};
-	struct rpc_message msg = {
-		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
-		.rpc_argp	= &map,
-		.rpc_resp	= &map.pm_port,
-	};
-	struct rpc_clnt	*pmap_clnt;
-	char		hostname[32];
-	int		status;
-
-	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));
-	pmap_clnt = pmap_create(hostname, sin, prot, 0);
-	if (IS_ERR(pmap_clnt))
-		return PTR_ERR(pmap_clnt);
-
-	/* Setup the call info struct */
-	status = rpc_call_sync(pmap_clnt, &msg, 0);
-
-	if (status >= 0) {
-		if (map.pm_port != 0)
-			return map.pm_port;
-		status = -EACCES;
-	}
-	return status;
-}
-#endif
-
-/*
- * Portmapper child task invokes this callback via tk_exit.
- */
-static void pmap_getport_done(struct rpc_task *child, void *data)
-{
-	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 {
-		/* Succeeded */
-		xprt->ops->set_port(xprt, map->pm_port);
-		xprt_set_bound(xprt);
-		status = 0;
-	}
-
-	dprintk("RPC: %5u pmap_getport_done(status %d, port %u)\n",
-			child->tk_pid, status, map->pm_port);
-
-	pmap_wake_portmap_waiters(xprt, status);
-}
-
-/**
- * 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)
-{
-	struct sockaddr_in	sin = {
-		.sin_family	= AF_INET,
-		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
-	};
-	struct portmap_args	map = {
-		.pm_prog	= prog,
-		.pm_vers	= vers,
-		.pm_prot	= prot,
-		.pm_port	= port,
-	};
-	struct rpc_message msg = {
-		.rpc_proc	= &pmap_procedures[port ? PMAP_SET : PMAP_UNSET],
-		.rpc_argp	= &map,
-		.rpc_resp	= okay,
-	};
-	struct rpc_clnt		*pmap_clnt;
-	int error = 0;
-
-	dprintk("RPC:       registering (%u, %u, %d, %u) with portmapper.\n",
-			prog, vers, prot, port);
-
-	pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
-	if (IS_ERR(pmap_clnt)) {
-		error = PTR_ERR(pmap_clnt);
-		dprintk("RPC:       couldn't create pmap client. Error = %d\n",
-				error);
-		return error;
-	}
-
-	error = rpc_call_sync(pmap_clnt, &msg, 0);
-
-	if (error < 0) {
-		printk(KERN_WARNING
-			"RPC: failed to contact portmap (errno %d).\n",
-			error);
-	}
-	dprintk("RPC:       registration status %d/%d\n", error, *okay);
-
-	/* Client deleted automatically because cl_oneshot == 1 */
-	return error;
-}
-
-static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
-{
-	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)
-		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, __be32 *p, struct portmap_args *map)
-{
-	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);
-	*p++ = htonl(map->pm_prot);
-	*p++ = htonl(map->pm_port);
-
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-	return 0;
-}
-
-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, __be32 *p, unsigned int *boolp)
-{
-	*boolp = (unsigned int) ntohl(*p++);
-	return 0;
-}
-
-static struct rpc_procinfo	pmap_procedures[] = {
-[PMAP_SET] = {
-	  .p_proc		= PMAP_SET,
-	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,
-	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
-	  .p_bufsiz		= 4,
-	  .p_count		= 1,
-	  .p_statidx		= PMAP_SET,
-	  .p_name		= "SET",
-	},
-[PMAP_UNSET] = {
-	  .p_proc		= PMAP_UNSET,
-	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,
-	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
-	  .p_bufsiz		= 4,
-	  .p_count		= 1,
-	  .p_statidx		= PMAP_UNSET,
-	  .p_name		= "UNSET",
-	},
-[PMAP_GETPORT] = {
-	  .p_proc		= PMAP_GETPORT,
-	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,
-	  .p_decode		= (kxdrproc_t) xdr_decode_port,
-	  .p_bufsiz		= 4,
-	  .p_count		= 1,
-	  .p_statidx		= PMAP_GETPORT,
-	  .p_name		= "GETPORT",
-	},
-};
-
-static struct rpc_version	pmap_version2 = {
-	.number		= 2,
-	.nrprocs	= 4,
-	.procs		= pmap_procedures
-};
-
-static struct rpc_version *	pmap_version[] = {
-	NULL,
-	NULL,
-	&pmap_version2
-};
-
-static struct rpc_stat		pmap_stats;
-
-static struct rpc_program	pmap_program = {
-	.name		= "portmap",
-	.number		= RPC_PMAP_PROGRAM,
-	.nrvers		= ARRAY_SIZE(pmap_version),
-	.version	= pmap_version,
-	.stats		= &pmap_stats,
-};
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9b9ea50..ad39b47 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -828,8 +828,7 @@ init_once(void * foo, struct kmem_cache 
 {
 	struct rpc_inode *rpci = (struct rpc_inode *) foo;
 
-	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
+	if (flags & SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&rpci->vfs_inode);
 		rpci->private = NULL;
 		rpci->nreaders = 0;
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
new file mode 100644
index 0000000..6c7aa8a
--- /dev/null
+++ b/net/sunrpc/rpcb_clnt.c
@@ -0,0 +1,625 @@
+/*
+ * In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind
+ * protocol
+ *
+ * Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and
+ * RFC 3530: "Network File System (NFS) version 4 Protocol"
+ *
+ * Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
+ * Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com>
+ *
+ * Descended from net/sunrpc/pmap_clnt.c,
+ *  Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_BIND
+#endif
+
+#define RPCBIND_PROGRAM		(100000u)
+#define RPCBIND_PORT		(111u)
+
+enum {
+	RPCBPROC_NULL,
+	RPCBPROC_SET,
+	RPCBPROC_UNSET,
+	RPCBPROC_GETPORT,
+	RPCBPROC_GETADDR = 3,		/* alias for GETPORT */
+	RPCBPROC_DUMP,
+	RPCBPROC_CALLIT,
+	RPCBPROC_BCAST = 5,		/* alias for CALLIT */
+	RPCBPROC_GETTIME,
+	RPCBPROC_UADDR2TADDR,
+	RPCBPROC_TADDR2UADDR,
+	RPCBPROC_GETVERSADDR,
+	RPCBPROC_INDIRECT,
+	RPCBPROC_GETADDRLIST,
+	RPCBPROC_GETSTAT,
+};
+
+#define RPCB_HIGHPROC_2		RPCBPROC_CALLIT
+#define RPCB_HIGHPROC_3		RPCBPROC_TADDR2UADDR
+#define RPCB_HIGHPROC_4		RPCBPROC_GETSTAT
+
+/*
+ * r_addr
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the
+ * US-ASCII string:
+ *
+ *	h1.h2.h3.h4.p1.p2
+ *
+ * The prefix, "h1.h2.h3.h4", is the standard textual form for
+ * representing an IPv4 address, which is always four octets long.
+ * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively,
+ * the first through fourth octets each converted to ASCII-decimal.
+ * Assuming big-endian ordering, p1 and p2 are, respectively, the first
+ * and second octets each converted to ASCII-decimal.  For example, if a
+ * host, in big-endian order, has an address of 0x0A010307 and there is
+ * a service listening on, in big endian order, port 0x020F (decimal
+ * 527), then the complete universal address is "10.1.3.7.2.15".
+ *
+ * ...
+ *
+ * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the
+ * US-ASCII string:
+ *
+ *	x1:x2:x3:x4:x5:x6:x7:x8.p1.p2
+ *
+ * The suffix "p1.p2" is the service port, and is computed the same way
+ * as with universal addresses for TCP and UDP over IPv4.  The prefix,
+ * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for
+ * representing an IPv6 address as defined in Section 2.2 of [RFC2373].
+ * Additionally, the two alternative forms specified in Section 2.2 of
+ * [RFC2373] are also acceptable.
+ *
+ * XXX: Currently this implementation does not explicitly convert the
+ *      stored address to US-ASCII on non-ASCII systems.
+ */
+#define RPCB_MAXADDRLEN		(128u)
+
+/*
+ * r_netid
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 the value of r_netid is the string "tcp".  For UDP
+ * over IPv4 the value of r_netid is the string "udp".
+ *
+ * ...
+ *
+ * For TCP over IPv6 the value of r_netid is the string "tcp6".  For UDP
+ * over IPv6 the value of r_netid is the string "udp6".
+ */
+#define RPCB_NETID_UDP	"\165\144\160"		/* "udp" */
+#define RPCB_NETID_TCP	"\164\143\160"		/* "tcp" */
+#define RPCB_NETID_UDP6	"\165\144\160\066"	/* "udp6" */
+#define RPCB_NETID_TCP6	"\164\143\160\066"	/* "tcp6" */
+
+#define RPCB_MAXNETIDLEN	(4u)
+
+/*
+ * r_owner
+ *
+ * The "owner" is allowed to unset a service in the rpcbind database.
+ * We always use the following (arbitrary) fixed string.
+ */
+#define RPCB_OWNER_STRING	"rpcb"
+#define RPCB_MAXOWNERLEN	sizeof(RPCB_OWNER_STRING)
+
+static void			rpcb_getport_done(struct rpc_task *, void *);
+extern struct rpc_program	rpcb_program;
+
+struct rpcbind_args {
+	struct rpc_xprt *	r_xprt;
+
+	u32			r_prog;
+	u32			r_vers;
+	u32			r_prot;
+	unsigned short		r_port;
+	char *			r_netid;
+	char			r_addr[RPCB_MAXADDRLEN];
+	char *			r_owner;
+};
+
+static struct rpc_procinfo rpcb_procedures2[];
+static struct rpc_procinfo rpcb_procedures3[];
+
+static struct rpcb_info {
+	int			rpc_vers;
+	struct rpc_procinfo *	rpc_proc;
+} rpcb_next_version[];
+
+static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
+{
+	struct rpcbind_args *map = calldata;
+	struct rpc_xprt *xprt = map->r_xprt;
+	struct rpc_message msg = {
+		.rpc_proc	= rpcb_next_version[xprt->bind_index].rpc_proc,
+		.rpc_argp	= map,
+		.rpc_resp	= &map->r_port,
+	};
+
+	rpc_call_setup(task, &msg, 0);
+}
+
+static void rpcb_map_release(void *data)
+{
+	struct rpcbind_args *map = data;
+
+	xprt_put(map->r_xprt);
+	kfree(map);
+}
+
+static const struct rpc_call_ops rpcb_getport_ops = {
+	.rpc_call_prepare	= rpcb_getport_prepare,
+	.rpc_call_done		= rpcb_getport_done,
+	.rpc_release		= rpcb_map_release,
+};
+
+static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
+{
+	xprt_clear_binding(xprt);
+	rpc_wake_up_status(&xprt->binding, status);
+}
+
+static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
+					int proto, int version, int privileged)
+{
+	struct rpc_create_args args = {
+		.protocol	= proto,
+		.address	= srvaddr,
+		.addrsize	= sizeof(struct sockaddr_in),
+		.servername	= hostname,
+		.program	= &rpcb_program,
+		.version	= version,
+		.authflavor	= RPC_AUTH_UNIX,
+		.flags		= (RPC_CLNT_CREATE_ONESHOT |
+				   RPC_CLNT_CREATE_NOPING),
+	};
+
+	((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+	if (!privileged)
+		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+	return rpc_create(&args);
+}
+
+/**
+ * rpcb_register - set or unset a port registration with the local rpcbind svc
+ * @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.
+ *
+ * This routine supports only rpcbind version 2.
+ */
+int rpcb_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 rpcbind_args map = {
+		.r_prog		= prog,
+		.r_vers		= vers,
+		.r_prot		= prot,
+		.r_port		= port,
+	};
+	struct rpc_message msg = {
+		.rpc_proc	= &rpcb_procedures2[port ?
+					RPCBPROC_SET : RPCBPROC_UNSET],
+		.rpc_argp	= &map,
+		.rpc_resp	= okay,
+	};
+	struct rpc_clnt *rpcb_clnt;
+	int error = 0;
+
+	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
+			"rpcbind\n", (port ? "" : "un"),
+			prog, vers, prot, port);
+
+	rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
+					IPPROTO_UDP, 2, 1);
+	if (IS_ERR(rpcb_clnt))
+		return PTR_ERR(rpcb_clnt);
+
+	error = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+	if (error < 0)
+		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+				"server (errno %d).\n", -error);
+	dprintk("RPC:       registration status %d/%d\n", error, *okay);
+
+	return error;
+}
+
+#ifdef CONFIG_ROOT_NFS
+/**
+ * rpcb_getport_external - obtain the port for an 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
+ *
+ * Called from outside the RPC client in a synchronous task context.
+ *
+ * For now, this supports only version 2 queries, but is used only by
+ * mount_clnt for NFS_ROOT.
+ */
+int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
+				__u32 vers, int prot)
+{
+	struct rpcbind_args map = {
+		.r_prog		= prog,
+		.r_vers		= vers,
+		.r_prot		= prot,
+		.r_port		= 0,
+	};
+	struct rpc_message msg = {
+		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
+		.rpc_argp	= &map,
+		.rpc_resp	= &map.r_port,
+	};
+	struct rpc_clnt	*rpcb_clnt;
+	char hostname[40];
+	int status;
+
+	dprintk("RPC:       rpcb_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));
+	rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
+	if (IS_ERR(rpcb_clnt))
+		return PTR_ERR(rpcb_clnt);
+
+	status = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+	if (status >= 0) {
+		if (map.r_port != 0)
+			return map.r_port;
+		status = -EACCES;
+	}
+	return status;
+}
+#endif
+
+/**
+ * rpcb_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 rpcb_getport(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt = task->tk_client;
+	int bind_version;
+	struct rpc_xprt *xprt = task->tk_xprt;
+	struct rpc_clnt	*rpcb_clnt;
+	static struct rpcbind_args *map;
+	struct rpc_task	*child;
+	struct sockaddr addr;
+	int status;
+
+	dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n",
+			task->tk_pid, clnt->cl_server,
+			clnt->cl_prog, clnt->cl_vers, xprt->prot);
+
+	/* Autobind on cloned rpc clients is discouraged */
+	BUG_ON(clnt->cl_parent != clnt);
+
+	if (xprt_test_and_set_binding(xprt)) {
+		status = -EACCES;		/* tell caller to check again */
+		dprintk("RPC: %5u rpcb_getport waiting for another binder\n",
+				task->tk_pid);
+		goto bailout_nowake;
+	}
+
+	/* Put self on queue before sending rpcbind request, in case
+	 * rpcb_getport_done completes before we return from rpc_run_task */
+	rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+
+	/* Someone else may have bound if we slept */
+	if (xprt_bound(xprt)) {
+		status = 0;
+		dprintk("RPC: %5u rpcb_getport already bound\n", task->tk_pid);
+		goto bailout_nofree;
+	}
+
+	if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
+		xprt->bind_index = 0;
+		status = -EACCES;	/* tell caller to try again later */
+		dprintk("RPC: %5u rpcb_getport no more getport versions "
+				"available\n", task->tk_pid);
+		goto bailout_nofree;
+	}
+	bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
+
+	dprintk("RPC: %5u rpcb_getport trying rpcbind version %u\n",
+			task->tk_pid, bind_version);
+
+	map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
+	if (!map) {
+		status = -ENOMEM;
+		dprintk("RPC: %5u rpcb_getport no memory available\n",
+				task->tk_pid);
+		goto bailout_nofree;
+	}
+	map->r_prog = clnt->cl_prog;
+	map->r_vers = clnt->cl_vers;
+	map->r_prot = xprt->prot;
+	map->r_port = 0;
+	map->r_xprt = xprt_get(xprt);
+	map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
+						   RPCB_NETID_UDP;
+	memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
+			sizeof(map->r_addr));
+	map->r_owner = RPCB_OWNER_STRING;	/* ignored for GETADDR */
+
+	rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+	rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
+	if (IS_ERR(rpcb_clnt)) {
+		status = PTR_ERR(rpcb_clnt);
+		dprintk("RPC: %5u rpcb_getport rpcb_create failed, error %ld\n",
+				task->tk_pid, PTR_ERR(rpcb_clnt));
+		goto bailout;
+	}
+
+	child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
+	if (IS_ERR(child)) {
+		status = -EIO;
+		dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n",
+				task->tk_pid);
+		goto bailout_nofree;
+	}
+	rpc_put_task(child);
+
+	task->tk_xprt->stat.bind_count++;
+	return;
+
+bailout:
+	kfree(map);
+	xprt_put(xprt);
+bailout_nofree:
+	rpcb_wake_rpcbind_waiters(xprt, status);
+bailout_nowake:
+	task->tk_status = status;
+}
+
+/*
+ * Rpcbind child task calls this callback via tk_exit.
+ */
+static void rpcb_getport_done(struct rpc_task *child, void *data)
+{
+	struct rpcbind_args *map = data;
+	struct rpc_xprt *xprt = map->r_xprt;
+	int status = child->tk_status;
+
+	/* rpcbind server doesn't support this rpcbind protocol version */
+	if (status == -EPROTONOSUPPORT)
+		xprt->bind_index++;
+
+	if (status < 0) {
+		/* rpcbind server not available on remote host? */
+		xprt->ops->set_port(xprt, 0);
+	} else if (map->r_port == 0) {
+		/* Requested RPC service wasn't registered on remote host */
+		xprt->ops->set_port(xprt, 0);
+		status = -EACCES;
+	} else {
+		/* Succeeded */
+		xprt->ops->set_port(xprt, map->r_port);
+		xprt_set_bound(xprt);
+		status = 0;
+	}
+
+	dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
+			child->tk_pid, status, map->r_port);
+
+	rpcb_wake_rpcbind_waiters(xprt, status);
+}
+
+static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
+			       struct rpcbind_args *rpcb)
+{
+	dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
+			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
+	*p++ = htonl(rpcb->r_prog);
+	*p++ = htonl(rpcb->r_vers);
+	*p++ = htonl(rpcb->r_prot);
+	*p++ = htonl(rpcb->r_port);
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
+			       unsigned short *portp)
+{
+	*portp = (unsigned short) ntohl(*p++);
+	dprintk("RPC:      rpcb_decode_getport result %u\n",
+			*portp);
+	return 0;
+}
+
+static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
+			   unsigned int *boolp)
+{
+	*boolp = (unsigned int) ntohl(*p++);
+	dprintk("RPC:      rpcb_decode_set result %u\n",
+			*boolp);
+	return 0;
+}
+
+static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
+			       struct rpcbind_args *rpcb)
+{
+	dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
+			rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
+	*p++ = htonl(rpcb->r_prog);
+	*p++ = htonl(rpcb->r_vers);
+
+	p = xdr_encode_string(p, rpcb->r_netid);
+	p = xdr_encode_string(p, rpcb->r_addr);
+	p = xdr_encode_string(p, rpcb->r_owner);
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	return 0;
+}
+
+static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
+			       unsigned short *portp)
+{
+	char *addr;
+	int addr_len, c, i, f, first, val;
+
+	*portp = 0;
+	addr_len = (unsigned int) ntohl(*p++);
+	if (addr_len > RPCB_MAXADDRLEN)			/* sanity */
+		return -EINVAL;
+
+	dprintk("RPC:       rpcb_decode_getaddr returned string: '%s'\n",
+			(char *) p);
+
+	addr = (char *)p;
+	val = 0;
+	first = 1;
+	f = 1;
+	for (i = addr_len - 1; i > 0; i--) {
+		c = addr[i];
+		if (c >= '0' && c <= '9') {
+			val += (c - '0') * f;
+			f *= 10;
+		} else if (c == '.') {
+			if (first) {
+				*portp = val;
+				val = first = 0;
+				f = 1;
+			} else {
+				*portp |= (val << 8);
+				break;
+			}
+		}
+	}
+
+	dprintk("RPC:       rpcb_decode_getaddr port=%u\n", *portp);
+	return 0;
+}
+
+#define RPCB_program_sz		(1u)
+#define RPCB_version_sz		(1u)
+#define RPCB_protocol_sz	(1u)
+#define RPCB_port_sz		(1u)
+#define RPCB_boolean_sz		(1u)
+
+#define RPCB_netid_sz		(1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_addr_sz		(1+XDR_QUADLEN(RPCB_MAXADDRLEN))
+#define RPCB_ownerstring_sz	(1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
+
+#define RPCB_mappingargs_sz	RPCB_program_sz+RPCB_version_sz+	\
+				RPCB_protocol_sz+RPCB_port_sz
+#define RPCB_getaddrargs_sz	RPCB_program_sz+RPCB_version_sz+	\
+				RPCB_netid_sz+RPCB_addr_sz+		\
+				RPCB_ownerstring_sz
+
+#define RPCB_setres_sz		RPCB_boolean_sz
+#define RPCB_getportres_sz	RPCB_port_sz
+
+/*
+ * Note that RFC 1833 does not put any size restrictions on the
+ * address string returned by the remote rpcbind database.
+ */
+#define RPCB_getaddrres_sz	RPCB_addr_sz
+
+#define PROC(proc, argtype, restype)					\
+	[RPCBPROC_##proc] = {						\
+		.p_proc		= RPCBPROC_##proc,			\
+		.p_encode	= (kxdrproc_t) rpcb_encode_##argtype,	\
+		.p_decode	= (kxdrproc_t) rpcb_decode_##restype,	\
+		.p_arglen	= RPCB_##argtype##args_sz,		\
+		.p_replen	= RPCB_##restype##res_sz,		\
+		.p_statidx	= RPCBPROC_##proc,			\
+		.p_timer	= 0,					\
+		.p_name		= #proc,				\
+	}
+
+/*
+ * Not all rpcbind procedures described in RFC 1833 are implemented
+ * since the Linux kernel RPC code requires only these.
+ */
+static struct rpc_procinfo rpcb_procedures2[] = {
+	PROC(SET,		mapping,	set),
+	PROC(UNSET,		mapping,	set),
+	PROC(GETADDR,		mapping,	getport),
+};
+
+static struct rpc_procinfo rpcb_procedures3[] = {
+	PROC(SET,		mapping,	set),
+	PROC(UNSET,		mapping,	set),
+	PROC(GETADDR,		getaddr,	getaddr),
+};
+
+static struct rpc_procinfo rpcb_procedures4[] = {
+	PROC(SET,		mapping,	set),
+	PROC(UNSET,		mapping,	set),
+	PROC(GETVERSADDR,	getaddr,	getaddr),
+};
+
+static struct rpcb_info rpcb_next_version[] = {
+#ifdef CONFIG_SUNRPC_BIND34
+	{ 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
+	{ 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+#endif
+	{ 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
+	{ 0, NULL },
+};
+
+static struct rpc_version rpcb_version2 = {
+	.number		= 2,
+	.nrprocs	= RPCB_HIGHPROC_2,
+	.procs		= rpcb_procedures2
+};
+
+static struct rpc_version rpcb_version3 = {
+	.number		= 3,
+	.nrprocs	= RPCB_HIGHPROC_3,
+	.procs		= rpcb_procedures3
+};
+
+static struct rpc_version rpcb_version4 = {
+	.number		= 4,
+	.nrprocs	= RPCB_HIGHPROC_4,
+	.procs		= rpcb_procedures4
+};
+
+static struct rpc_version *rpcb_version[] = {
+	NULL,
+	NULL,
+	&rpcb_version2,
+	&rpcb_version3,
+	&rpcb_version4
+};
+
+static struct rpc_stat rpcb_stats;
+
+struct rpc_program rpcb_program = {
+	.name		= "rpcbind",
+	.number		= RPCBIND_PROGRAM,
+	.nrvers		= ARRAY_SIZE(rpcb_version),
+	.version	= rpcb_version,
+	.stats		= &rpcb_stats,
+};
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 6d87320..9901451 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -741,50 +741,53 @@ static void rpc_async_schedule(struct wo
  * @task: RPC task that will use this buffer
  * @size: requested byte size
  *
- * We try to ensure that some NFS reads and writes can always proceed
- * by using a mempool when allocating 'small' buffers.
+ * To prevent rpciod from hanging, this allocator never sleeps,
+ * returning NULL if the request cannot be serviced immediately.
+ * The caller can arrange to sleep in a way that is safe for rpciod.
+ *
+ * Most requests are 'small' (under 2KiB) and can be serviced from a
+ * mempool, ensuring that NFS reads and writes can always proceed,
+ * and that there is good locality of reference for these buffers.
+ *
  * In order to avoid memory starvation triggering more writebacks of
- * NFS requests, we use GFP_NOFS rather than GFP_KERNEL.
+ * NFS requests, we avoid using GFP_KERNEL.
  */
-void * rpc_malloc(struct rpc_task *task, size_t size)
+void *rpc_malloc(struct rpc_task *task, size_t size)
 {
-	struct rpc_rqst *req = task->tk_rqstp;
-	gfp_t	gfp;
+	size_t *buf;
+	gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
 
-	if (task->tk_flags & RPC_TASK_SWAPPER)
-		gfp = GFP_ATOMIC;
+	size += sizeof(size_t);
+	if (size <= RPC_BUFFER_MAXSIZE)
+		buf = mempool_alloc(rpc_buffer_mempool, gfp);
 	else
-		gfp = GFP_NOFS;
-
-	if (size > RPC_BUFFER_MAXSIZE) {
-		req->rq_buffer = kmalloc(size, gfp);
-		if (req->rq_buffer)
-			req->rq_bufsize = size;
-	} else {
-		req->rq_buffer = mempool_alloc(rpc_buffer_mempool, gfp);
-		if (req->rq_buffer)
-			req->rq_bufsize = RPC_BUFFER_MAXSIZE;
-	}
-	return req->rq_buffer;
+		buf = kmalloc(size, gfp);
+	*buf = size;
+	dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
+			task->tk_pid, size, buf);
+	return ++buf;
 }
 
 /**
  * rpc_free - free buffer allocated via rpc_malloc
- * @task: RPC task with a buffer to be freed
+ * @buffer: buffer to free
  *
  */
-void rpc_free(struct rpc_task *task)
+void rpc_free(void *buffer)
 {
-	struct rpc_rqst *req = task->tk_rqstp;
+	size_t size, *buf = buffer;
 
-	if (req->rq_buffer) {
-		if (req->rq_bufsize == RPC_BUFFER_MAXSIZE)
-			mempool_free(req->rq_buffer, rpc_buffer_mempool);
-		else
-			kfree(req->rq_buffer);
-		req->rq_buffer = NULL;
-		req->rq_bufsize = 0;
-	}
+	if (!buffer)
+		return;
+	size = *buf;
+	buf--;
+
+	dprintk("RPC:       freeing buffer of size %zu at %p\n",
+			size, buf);
+	if (size <= RPC_BUFFER_MAXSIZE)
+		mempool_free(buf, rpc_buffer_mempool);
+	else
+		kfree(buf);
 }
 
 /*
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c
index 634885b..1d377d1 100644
--- a/net/sunrpc/socklib.c
+++ b/net/sunrpc/socklib.c
@@ -154,7 +154,7 @@ int csum_partial_copy_to_xdr(struct xdr_
 	desc.offset = sizeof(struct udphdr);
 	desc.count = skb->len - desc.offset;
 
-	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+	if (skb_csum_unnecessary(skb))
 		goto no_checksum;
 
 	desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b4db53f..b7503c1 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -757,7 +757,7 @@ svc_register(struct svc_serv *serv, int 
 			if (progp->pg_vers[i]->vs_hidden)
 				continue;
 
-			error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+			error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
 			if (error < 0)
 				break;
 			if (port && !dummy) {
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 2772fee..22f61ae 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -798,16 +798,12 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
 	rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
-	if (skb->tstamp.off_sec == 0) {
-		struct timeval tv;
-
-		tv.tv_sec = xtime.tv_sec;
-		tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC;
-		skb_set_timestamp(skb, &tv);
+	if (skb->tstamp.tv64 == 0) {
+		skb->tstamp = ktime_get_real();
 		/* Don't enable netstamp, sunrpc doesn't
 		   need that much accuracy */
 	}
-	skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp);
+	svsk->sk_sk->sk_stamp = skb->tstamp;
 	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/*
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 456a145..5b05b73 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -823,7 +823,6 @@ static void xprt_request_init(struct rpc
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
 	req->rq_buffer  = NULL;
-	req->rq_bufsize = 0;
 	req->rq_xid     = xprt_alloc_xid(xprt);
 	req->rq_release_snd_buf = NULL;
 	xprt_reset_majortimeo(req);
@@ -855,7 +854,7 @@ void xprt_release(struct rpc_task *task)
 		mod_timer(&xprt->timer,
 				xprt->last_used + xprt->idle_timeout);
 	spin_unlock_bh(&xprt->transport_lock);
-	xprt->ops->buf_free(task);
+	xprt->ops->buf_free(req->rq_buffer);
 	task->tk_rqstp = NULL;
 	if (req->rq_release_snd_buf)
 		req->rq_release_snd_buf(req);
@@ -928,6 +927,7 @@ struct rpc_xprt *xprt_create_transport(i
 	xprt->timer.data = (unsigned long) xprt;
 	xprt->last_used = jiffies;
 	xprt->cwnd = RPC_INITCWND;
+	xprt->bind_index = 0;
 
 	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
 	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index a5a3202..cc33c58 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1476,7 +1476,7 @@ static struct rpc_xprt_ops xs_udp_ops = 
 	.set_buffer_size	= xs_udp_set_buffer_size,
 	.reserve_xprt		= xprt_reserve_xprt_cong,
 	.release_xprt		= xprt_release_xprt_cong,
-	.rpcbind		= rpc_getport,
+	.rpcbind		= rpcb_getport,
 	.set_port		= xs_set_port,
 	.connect		= xs_connect,
 	.buf_alloc		= rpc_malloc,
@@ -1493,7 +1493,7 @@ static struct rpc_xprt_ops xs_udp_ops = 
 static struct rpc_xprt_ops xs_tcp_ops = {
 	.reserve_xprt		= xprt_reserve_xprt,
 	.release_xprt		= xs_tcp_release_xprt,
-	.rpcbind		= rpc_getport,
+	.rpcbind		= rpcb_getport,
 	.set_port		= xs_set_port,
 	.connect		= xs_connect,
 	.buf_alloc		= rpc_malloc,
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
index 3891cc0..f9e367d 100644
--- a/net/tipc/Kconfig
+++ b/net/tipc/Kconfig
@@ -18,7 +18,7 @@ config TIPC
 	  This protocol support is also available as a module ( = code which
 	  can be inserted in and removed from the running kernel whenever you
 	  want). The module will be called tipc. If you want to compile it
-	  as a module, say M here and read <file:Documentation/modules.txt>.
+	  as a module, say M here and read <file:Documentation/kbuild/modules.txt>.
 
 	  If in doubt, say N.
 
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 14789a8..c71337a 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -89,7 +89,7 @@ struct sk_buff *tipc_cfg_reply_alloc(int
 int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
 			void *tlv_data, int tlv_data_size)
 {
-	struct tlv_desc *tlv = (struct tlv_desc *)buf->tail;
+	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
 	int new_tlv_space = TLV_SPACE(tlv_data_size);
 
 	if (skb_tailroom(buf) < new_tlv_space) {
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 9be4839..0ee6ded 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -73,7 +73,7 @@ static int send_msg(struct sk_buff *buf,
 
 	clone = skb_clone(buf, GFP_ATOMIC);
 	if (clone) {
-		clone->nh.raw = clone->data;
+		skb_reset_network_header(clone);
 		dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
 		clone->dev = dev;
 		dev->hard_header(clone, dev, ETH_P_TIPC,
@@ -99,8 +99,8 @@ static int recv_msg(struct sk_buff *buf,
 
 	if (likely(eb_ptr->bearer)) {
 	       if (likely(!dev->promiscuity) ||
-		   !memcmp(buf->mac.raw,dev->dev_addr,ETH_ALEN) ||
-		   !memcmp(buf->mac.raw,dev->broadcast,ETH_ALEN)) {
+		   !memcmp(skb_mac_header(buf), dev->dev_addr, ETH_ALEN) ||
+		   !memcmp(skb_mac_header(buf), dev->broadcast, ETH_ALEN)) {
 			size = msg_size((struct tipc_msg *)buf->data);
 			skb_trim(buf, size);
 			if (likely(buf->len == size)) {
@@ -120,16 +120,18 @@ static int recv_msg(struct sk_buff *buf,
 
 static int enable_bearer(struct tipc_bearer *tb_ptr)
 {
-	struct net_device *dev = dev_base;
+	struct net_device *dev, *pdev;
 	struct eth_bearer *eb_ptr = &eth_bearers[0];
 	struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
 	char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
 
 	/* Find device with specified name */
-
-	while (dev && dev->name && strncmp(dev->name, driver_name, IFNAMSIZ)) {
-		dev = dev->next;
-	}
+	dev = NULL;
+	for_each_netdev(pdev)
+		if (!strncmp(dev->name, driver_name, IFNAMSIZ)) {
+			dev = pdev;
+			break;
+		}
 	if (!dev)
 		return -ENODEV;
 
@@ -140,7 +142,7 @@ static int enable_bearer(struct tipc_bea
 		return -EDQUOT;
 	if (!eb_ptr->dev) {
 		eb_ptr->dev = dev;
-		eb_ptr->tipc_packet_type.type = __constant_htons(ETH_P_TIPC);
+		eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
 		eb_ptr->tipc_packet_type.dev = dev;
 		eb_ptr->tipc_packet_type.func = recv_msg;
 		eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 71c2f2f..2124f32 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1001,7 +1001,7 @@ static int link_bundle_buf(struct link *
 		return 0;
 
 	skb_put(bundler, pad + size);
-	memcpy(bundler->data + to_pos, buf->data, size);
+	skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size);
 	msg_set_size(bundler_msg, to_pos + size);
 	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
 	dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
@@ -1109,8 +1109,8 @@ int tipc_link_send_buf(struct link *l_pt
 			if (bundler) {
 				msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
 					 TIPC_OK, INT_H_SIZE, l_ptr->addr);
-				memcpy(bundler->data, (unchar *)&bundler_hdr,
-				       INT_H_SIZE);
+				skb_copy_to_linear_data(bundler, &bundler_hdr,
+							INT_H_SIZE);
 				skb_trim(bundler, INT_H_SIZE);
 				link_bundle_buf(l_ptr, bundler, buf);
 				buf = bundler;
@@ -1383,9 +1383,9 @@ again:
 	if (!buf)
 		return -ENOMEM;
 	buf->next = NULL;
-	memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+	skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
 	hsz = msg_hdr_sz(hdr);
-	memcpy(buf->data + INT_H_SIZE, (unchar *)hdr, hsz);
+	skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz);
 	msg_dbg(buf_msg(buf), ">BUILD>");
 
 	/* Chop up message: */
@@ -1416,8 +1416,8 @@ error:
 				return -EFAULT;
 			}
 		} else
-			memcpy(buf->data + fragm_crs, sect_crs, sz);
-
+			skb_copy_to_linear_data_offset(buf, fragm_crs,
+						       sect_crs, sz);
 		sect_crs += sz;
 		sect_rest -= sz;
 		fragm_crs += sz;
@@ -1442,7 +1442,7 @@ error:
 
 			buf->next = NULL;
 			prev->next = buf;
-			memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+			skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
 			fragm_crs = INT_H_SIZE;
 			fragm_rest = fragm_sz;
 			msg_dbg(buf_msg(buf),"  >BUILD>");
@@ -2130,7 +2130,7 @@ void tipc_link_send_proto_msg(struct lin
 		buf = l_ptr->proto_msg_queue;
 		if (!buf)
 			return;
-		memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+		skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
 		return;
 	}
 	msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
@@ -2143,7 +2143,7 @@ void tipc_link_send_proto_msg(struct lin
 	if (!buf)
 		return;
 
-	memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+	skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
 	msg_set_size(buf_msg(buf), msg_size);
 
 	if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
@@ -2319,8 +2319,8 @@ void tipc_link_tunnel(struct link *l_ptr
 		     "unable to send tunnel msg\n");
 		return;
 	}
-	memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
-	memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
+	skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE);
+	skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length);
 	dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
 	msg_dbg(buf_msg(buf), ">SEND>");
 	tipc_link_send_buf(tunnel, buf);
@@ -2361,7 +2361,7 @@ void tipc_link_changeover(struct link *l
 
 		buf = buf_acquire(INT_H_SIZE);
 		if (buf) {
-			memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
+			skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE);
 			msg_set_size(&tunnel_hdr, INT_H_SIZE);
 			dbg("%c->%c:", l_ptr->b_ptr->net_plane,
 			    tunnel->b_ptr->net_plane);
@@ -2426,8 +2426,9 @@ void tipc_link_send_duplicate(struct lin
 			     "unable to send duplicate msg\n");
 			return;
 		}
-		memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
-		memcpy(outbuf->data + INT_H_SIZE, iter->data, length);
+		skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE);
+		skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data,
+					       length);
 		dbg("%c->%c:", l_ptr->b_ptr->net_plane,
 		    tunnel->b_ptr->net_plane);
 		msg_dbg(buf_msg(outbuf), ">SEND>");
@@ -2457,7 +2458,7 @@ static struct sk_buff *buf_extract(struc
 
 	eb = buf_acquire(size);
 	if (eb)
-		memcpy(eb->data, (unchar *)msg, size);
+		skb_copy_to_linear_data(eb, msg, size);
 	return eb;
 }
 
@@ -2569,7 +2570,7 @@ void tipc_link_recv_bundle(struct sk_buf
 		if (obuf == NULL) {
 			warn("Link unable to unbundle message(s)\n");
 			break;
-		};
+		}
 		pos += align(msg_size(buf_msg(obuf)));
 		msg_dbg(buf_msg(obuf), "     /");
 		tipc_net_route_msg(obuf);
@@ -2631,9 +2632,9 @@ int tipc_link_send_long_buf(struct link 
 			goto exit;
 		}
 		msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
-		memcpy(fragm->data, (unchar *)&fragm_hdr, INT_H_SIZE);
-		memcpy(fragm->data + INT_H_SIZE, crs, fragm_sz);
-
+		skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE);
+		skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs,
+					       fragm_sz);
 		/*  Send queued messages first, if any: */
 
 		l_ptr->stats.sent_fragments++;
@@ -2733,8 +2734,8 @@ int tipc_link_recv_fragment(struct sk_bu
 		if (pbuf != NULL) {
 			pbuf->next = *pending;
 			*pending = pbuf;
-			memcpy(pbuf->data, (unchar *)imsg, msg_data_sz(fragm));
-
+			skb_copy_to_linear_data(pbuf, imsg,
+						msg_data_sz(fragm));
 			/*  Prepare buffer for subsequent fragments. */
 
 			set_long_msg_seqno(pbuf, long_msg_seq_no);
@@ -2750,7 +2751,8 @@ int tipc_link_recv_fragment(struct sk_bu
 		u32 fsz = get_fragm_size(pbuf);
 		u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
 		u32 exp_frags = get_expected_frags(pbuf) - 1;
-		memcpy(pbuf->data + crs, msg_data(fragm), dsz);
+		skb_copy_to_linear_data_offset(pbuf, crs,
+					       msg_data(fragm), dsz);
 		buf_discard(fbuf);
 
 		/* Is message complete? */
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 62d5490..35d5ba1 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -1,8 +1,8 @@
 /*
  * net/tipc/msg.h: Include file for TIPC message header routines
  *
- * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2000-2007, Ericsson AB
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -71,8 +71,11 @@ static inline void msg_set_word(struct t
 static inline void msg_set_bits(struct tipc_msg *m, u32 w,
 				u32 pos, u32 mask, u32 val)
 {
-	u32 word = msg_word(m,w) & ~(mask << pos);
-	msg_set_word(m, w, (word |= (val << pos)));
+	val = (val & mask) << pos;
+	val = htonl(val);
+	mask = htonl(mask << pos);
+	m->hdr[w] &= ~mask;
+	m->hdr[w] |= val;
 }
 
 /*
@@ -786,15 +789,16 @@ static inline int msg_build(struct tipc_
 	*buf = buf_acquire(sz);
 	if (!(*buf))
 		return -ENOMEM;
-	memcpy((*buf)->data, (unchar *)hdr, hsz);
+	skb_copy_to_linear_data(*buf, hdr, hsz);
 	for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
 		if (likely(usrmem))
 			res = !copy_from_user((*buf)->data + pos,
 					      msg_sect[cnt].iov_base,
 					      msg_sect[cnt].iov_len);
 		else
-			memcpy((*buf)->data + pos, msg_sect[cnt].iov_base,
-			       msg_sect[cnt].iov_len);
+			skb_copy_to_linear_data_offset(*buf, pos,
+						       msg_sect[cnt].iov_base,
+						       msg_sect[cnt].iov_len);
 		pos += msg_sect[cnt].iov_len;
 	}
 	if (likely(res))
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index b8e1edc..4cdafa2 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -57,7 +57,7 @@ static int handle_cmd(struct sk_buff *sk
 
 	if (rep_buf) {
 		skb_push(rep_buf, hdr_space);
-		rep_nlh = (struct nlmsghdr *)rep_buf->data;
+		rep_nlh = nlmsg_hdr(rep_buf);
 		memcpy(rep_nlh, req_nlh, hdr_space);
 		rep_nlh->nlmsg_len = rep_buf->len;
 		genlmsg_unicast(rep_buf, req_nlh->nlmsg_pid);
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 5f8217d..bcd5da0 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -464,7 +464,7 @@ int tipc_reject_msg(struct sk_buff *buf,
 	msg_set_size(rmsg, data_sz + hdr_sz);
 	msg_set_nametype(rmsg, msg_nametype(msg));
 	msg_set_nameinst(rmsg, msg_nameinst(msg));
-	memcpy(rbuf->data + hdr_sz, msg_data(msg), data_sz);
+	skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
 
 	/* send self-abort message when rejecting on a connected port */
 	if (msg_connected(msg)) {
@@ -1419,7 +1419,7 @@ int tipc_send_buf(u32 ref, struct sk_buf
 		return -ENOMEM;
 
 	skb_push(buf, hsz);
-	memcpy(buf->data, (unchar *)msg, hsz);
+	skb_copy_to_linear_data(buf, msg, hsz);
 	destnode = msg_destnode(msg);
 	p_ptr->publ.congested = 1;
 	if (!tipc_port_congested(p_ptr)) {
@@ -1555,7 +1555,7 @@ int tipc_forward_buf2name(u32 ref,
 	if (skb_cow(buf, LONG_H_SIZE))
 		return -ENOMEM;
 	skb_push(buf, LONG_H_SIZE);
-	memcpy(buf->data, (unchar *)msg, LONG_H_SIZE);
+	skb_copy_to_linear_data(buf, msg, LONG_H_SIZE);
 	msg_dbg(buf_msg(buf),"PREP:");
 	if (likely(destport || destnode)) {
 		p_ptr->sent++;
@@ -1679,7 +1679,7 @@ int tipc_forward_buf2port(u32 ref,
 		return -ENOMEM;
 
 	skb_push(buf, DIR_MSG_H_SIZE);
-	memcpy(buf->data, (unchar *)msg, DIR_MSG_H_SIZE);
+	skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE);
 	msg_dbg(msg, "buf2port: ");
 	p_ptr->sent++;
 	if (dest->node == tipc_own_addr)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index b71739f..45832fb 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1020,7 +1020,7 @@ restart:
 
 	if (!err) {
 		buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);
-		sz = buf->tail - buf_crs;
+		sz = skb_tail_pointer(buf) - buf_crs;
 
 		needed = (buf_len - sz_copied);
 		sz_to_copy = (sz <= needed) ? sz : needed;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6069716..fc12ba5 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -111,7 +111,6 @@ #include <linux/seq_file.h>
 #include <net/scm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/rtnetlink.h>
 #include <linux/mount.h>
 #include <net/checksum.h>
@@ -1319,7 +1318,7 @@ static int unix_dgram_sendmsg(struct kio
 		unix_attach_fds(siocb->scm, skb);
 	unix_get_secdata(siocb->scm, skb);
 
-	skb->h.raw = skb->data;
+	skb_reset_transport_header(skb);
 	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
 	if (err)
 		goto out_free;
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 5d2d93d..7a19e0e 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -277,8 +277,8 @@ int wanrouter_encapsulate(struct sk_buff
 		skb_push(skb, 7);
 		skb->data[0] = 0;
 		skb->data[1] = NLPID_SNAP;
-		memcpy(&skb->data[2], wanrouter_oui_ether,
-		       sizeof(wanrouter_oui_ether));
+		skb_copy_to_linear_data_offset(skb, 2, wanrouter_oui_ether,
+					       sizeof(wanrouter_oui_ether));
 		*((unsigned short*)&skb->data[5]) = htons(type);
 		break;
 
@@ -339,7 +339,7 @@ __be16 wanrouter_type_trans(struct sk_bu
 	skb->protocol = ethertype;
 	skb->pkt_type = PACKET_HOST;	/*	Physically point to point */
 	skb_pull(skb, cnt);
-	skb->mac.raw  = skb->data;
+	skb_reset_mac_header(skb);
 	return ethertype;
 }
 
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
new file mode 100644
index 0000000..a228d56
--- /dev/null
+++ b/net/wireless/Kconfig
@@ -0,0 +1,16 @@
+config CFG80211
+        tristate "Improved wireless configuration API"
+
+config WIRELESS_EXT
+	bool "Wireless extensions"
+	default n
+	---help---
+	  This option enables the legacy wireless extensions
+	  (wireless network interface configuration via ioctls.)
+
+	  Wireless extensions will be replaced by cfg80211 and
+	  will be required only by legacy drivers that implement
+	  wireless extension handlers.
+
+	  Say N (if you can) unless you know you need wireless
+	  extensions for external modules.
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
new file mode 100644
index 0000000..3a96ae6
--- /dev/null
+++ b/net/wireless/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_WIRELESS_EXT) += wext.o
+obj-$(CONFIG_CFG80211) += cfg80211.o
+
+cfg80211-y += core.o sysfs.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
new file mode 100644
index 0000000..7eabd55
--- /dev/null
+++ b/net/wireless/core.c
@@ -0,0 +1,224 @@
+/*
+ * This is the linux wireless configuration interface.
+ *
+ * Copyright 2006, 2007		Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/nl80211.h>
+#include <linux/debugfs.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <net/genetlink.h>
+#include <net/cfg80211.h>
+#include <net/wireless.h>
+#include "core.h"
+#include "sysfs.h"
+
+/* name for sysfs, %d is appended */
+#define PHY_NAME "phy"
+
+MODULE_AUTHOR("Johannes Berg");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("wireless configuration support");
+
+/* RCU might be appropriate here since we usually
+ * only read the list, and that can happen quite
+ * often because we need to do it for each command */
+LIST_HEAD(cfg80211_drv_list);
+DEFINE_MUTEX(cfg80211_drv_mutex);
+static int wiphy_counter;
+
+/* for debugfs */
+static struct dentry *ieee80211_debugfs_dir;
+
+/* exported functions */
+
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
+{
+	struct cfg80211_registered_device *drv;
+	int alloc_size;
+
+	alloc_size = sizeof(*drv) + sizeof_priv;
+
+	drv = kzalloc(alloc_size, GFP_KERNEL);
+	if (!drv)
+		return NULL;
+
+	drv->ops = ops;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	drv->idx = wiphy_counter;
+
+	/* now increase counter for the next device unless
+	 * it has wrapped previously */
+	if (wiphy_counter >= 0)
+		wiphy_counter++;
+
+	mutex_unlock(&cfg80211_drv_mutex);
+
+	if (unlikely(drv->idx < 0)) {
+		/* ugh, wrapped! */
+		kfree(drv);
+		return NULL;
+	}
+
+	/* give it a proper name */
+	snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
+		 PHY_NAME "%d", drv->idx);
+
+	mutex_init(&drv->mtx);
+	mutex_init(&drv->devlist_mtx);
+	INIT_LIST_HEAD(&drv->netdev_list);
+
+	device_initialize(&drv->wiphy.dev);
+	drv->wiphy.dev.class = &ieee80211_class;
+	drv->wiphy.dev.platform_data = drv;
+
+	return &drv->wiphy;
+}
+EXPORT_SYMBOL(wiphy_new);
+
+int wiphy_register(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+	int res;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	res = device_add(&drv->wiphy.dev);
+	if (res)
+		goto out_unlock;
+
+	list_add(&drv->list, &cfg80211_drv_list);
+
+	/* add to debugfs */
+	drv->wiphy.debugfsdir =
+		debugfs_create_dir(wiphy_name(&drv->wiphy),
+				   ieee80211_debugfs_dir);
+
+	res = 0;
+out_unlock:
+	mutex_unlock(&cfg80211_drv_mutex);
+	return res;
+}
+EXPORT_SYMBOL(wiphy_register);
+
+void wiphy_unregister(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+
+	/* protect the device list */
+	mutex_lock(&cfg80211_drv_mutex);
+
+	BUG_ON(!list_empty(&drv->netdev_list));
+
+	/*
+	 * Try to grab drv->mtx. If a command is still in progress,
+	 * hopefully the driver will refuse it since it's tearing
+	 * down the device already. We wait for this command to complete
+	 * before unlinking the item from the list.
+	 * Note: as codified by the BUG_ON above we cannot get here if
+	 * a virtual interface is still associated. Hence, we can only
+	 * get to lock contention here if userspace issues a command
+	 * that identified the hardware by wiphy index.
+	 */
+	mutex_lock(&drv->mtx);
+	/* unlock again before freeing */
+	mutex_unlock(&drv->mtx);
+
+	list_del(&drv->list);
+	device_del(&drv->wiphy.dev);
+	debugfs_remove(drv->wiphy.debugfsdir);
+
+	mutex_unlock(&cfg80211_drv_mutex);
+}
+EXPORT_SYMBOL(wiphy_unregister);
+
+void cfg80211_dev_free(struct cfg80211_registered_device *drv)
+{
+	mutex_destroy(&drv->mtx);
+	mutex_destroy(&drv->devlist_mtx);
+	kfree(drv);
+}
+
+void wiphy_free(struct wiphy *wiphy)
+{
+	put_device(&wiphy->dev);
+}
+EXPORT_SYMBOL(wiphy_free);
+
+static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
+					 unsigned long state,
+					 void *ndev)
+{
+	struct net_device *dev = ndev;
+	struct cfg80211_registered_device *rdev;
+
+	if (!dev->ieee80211_ptr)
+		return 0;
+
+	rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
+
+	switch (state) {
+	case NETDEV_REGISTER:
+		mutex_lock(&rdev->devlist_mtx);
+		list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
+		if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
+				      "phy80211")) {
+			printk(KERN_ERR "wireless: failed to add phy80211 "
+				"symlink to netdev!\n");
+		}
+		dev->ieee80211_ptr->netdev = dev;
+		mutex_unlock(&rdev->devlist_mtx);
+		break;
+	case NETDEV_UNREGISTER:
+		mutex_lock(&rdev->devlist_mtx);
+		if (!list_empty(&dev->ieee80211_ptr->list)) {
+			sysfs_remove_link(&dev->dev.kobj, "phy80211");
+			list_del_init(&dev->ieee80211_ptr->list);
+		}
+		mutex_unlock(&rdev->devlist_mtx);
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block cfg80211_netdev_notifier = {
+	.notifier_call = cfg80211_netdev_notifier_call,
+};
+
+static int cfg80211_init(void)
+{
+	int err = wiphy_sysfs_init();
+	if (err)
+		goto out_fail_sysfs;
+
+	err = register_netdevice_notifier(&cfg80211_netdev_notifier);
+	if (err)
+		goto out_fail_notifier;
+
+	ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
+
+	return 0;
+
+out_fail_notifier:
+	wiphy_sysfs_exit();
+out_fail_sysfs:
+	return err;
+}
+module_init(cfg80211_init);
+
+static void cfg80211_exit(void)
+{
+	debugfs_remove(ieee80211_debugfs_dir);
+	unregister_netdevice_notifier(&cfg80211_netdev_notifier);
+	wiphy_sysfs_exit();
+}
+module_exit(cfg80211_exit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
new file mode 100644
index 0000000..158db1e
--- /dev/null
+++ b/net/wireless/core.h
@@ -0,0 +1,49 @@
+/*
+ * Wireless configuration interface internals.
+ *
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ */
+#ifndef __NET_WIRELESS_CORE_H
+#define __NET_WIRELESS_CORE_H
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+
+struct cfg80211_registered_device {
+	struct cfg80211_ops *ops;
+	struct list_head list;
+	/* we hold this mutex during any call so that
+	 * we cannot do multiple calls at once, and also
+	 * to avoid the deregister call to proceed while
+	 * any call is in progress */
+	struct mutex mtx;
+
+	/* wiphy index, internal only */
+	int idx;
+
+	/* associate netdev list */
+	struct mutex devlist_mtx;
+	struct list_head netdev_list;
+
+	/* must be last because of the way we do wiphy_priv(),
+	 * and it should at least be aligned to NETDEV_ALIGN */
+	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+static inline
+struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
+{
+	BUG_ON(!wiphy);
+	return container_of(wiphy, struct cfg80211_registered_device, wiphy);
+}
+
+extern struct mutex cfg80211_drv_mutex;
+extern struct list_head cfg80211_drv_list;
+
+/* free object */
+extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
+
+#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
new file mode 100644
index 0000000..3ebae14
--- /dev/null
+++ b/net/wireless/sysfs.c
@@ -0,0 +1,80 @@
+/*
+ * This file provides /sys/class/ieee80211/<wiphy name>/
+ * and some default attributes.
+ *
+ * Copyright 2005-2006	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is GPLv2 as found in COPYING.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "sysfs.h"
+#include "core.h"
+
+static inline struct cfg80211_registered_device *dev_to_rdev(
+	struct device *dev)
+{
+	return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
+}
+
+static ssize_t _show_index(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx);
+}
+
+static ssize_t _show_permaddr(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	char *addr = dev_to_rdev(dev)->wiphy.perm_addr;
+
+	return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+}
+
+static struct device_attribute ieee80211_dev_attrs[] = {
+	__ATTR(index, S_IRUGO, _show_index, NULL),
+	__ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
+	{}
+};
+
+static void wiphy_dev_release(struct device *dev)
+{
+	struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
+
+	cfg80211_dev_free(rdev);
+}
+
+static int wiphy_uevent(struct device *dev, char **envp,
+			int num_envp, char *buf, int size)
+{
+	/* TODO, we probably need stuff here */
+	return 0;
+}
+
+struct class ieee80211_class = {
+	.name = "ieee80211",
+	.owner = THIS_MODULE,
+	.dev_release = wiphy_dev_release,
+	.dev_attrs = ieee80211_dev_attrs,
+#ifdef CONFIG_HOTPLUG
+	.dev_uevent = wiphy_uevent,
+#endif
+};
+
+int wiphy_sysfs_init(void)
+{
+	return class_register(&ieee80211_class);
+}
+
+void wiphy_sysfs_exit(void)
+{
+	class_unregister(&ieee80211_class);
+}
diff --git a/net/wireless/sysfs.h b/net/wireless/sysfs.h
new file mode 100644
index 0000000..65acbeb
--- /dev/null
+++ b/net/wireless/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef __WIRELESS_SYSFS_H
+#define __WIRELESS_SYSFS_H
+
+extern int wiphy_sysfs_init(void);
+extern void wiphy_sysfs_exit(void);
+
+extern struct class ieee80211_class;
+
+#endif /* __WIRELESS_SYSFS_H */
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
new file mode 100644
index 0000000..d6aaf65
--- /dev/null
+++ b/net/wireless/wext.c
@@ -0,0 +1,1509 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/************************** DOCUMENTATION **************************/
+/*
+ * API definition :
+ * --------------
+ * See <linux/wireless.h> for details of the APIs and the rest.
+ *
+ * History :
+ * -------
+ *
+ * v1 - 5.12.01 - Jean II
+ *	o Created this file.
+ *
+ * v2 - 13.12.01 - Jean II
+ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
+ *	o Make Wireless Extension IOCTLs go through here
+ *	o Added iw_handler handling ;-)
+ *	o Added standard ioctl description
+ *	o Initial dumb commit strategy based on orinoco.c
+ *
+ * v3 - 19.12.01 - Jean II
+ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
+ *	o Add event dispatcher function
+ *	o Add event description
+ *	o Propagate events as rtnetlink IFLA_WIRELESS option
+ *	o Generate event on selected SET requests
+ *
+ * v4 - 18.04.02 - Jean II
+ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+ *
+ * v6 - 9.01.03 - Jean II
+ *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
+ *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
+ *	o Add WIRELESS_EXT version display in /proc/net/wireless
+ *
+ * v6 - 18.06.04 - Jean II
+ *	o Change get_spydata() method for added safety
+ *	o Remove spy #ifdef, they are always on -> cleaner code
+ *	o Allow any size GET request if user specifies length > max
+ *		and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
+ *	o Start migrating get_wireless_stats to struct iw_handler_def
+ *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
+ * Based on patch from Pavel Roskin <proski@gnu.org> :
+ *	o Fix kernel data leak to user space in private handler handling
+ *
+ * v7 - 18.3.05 - Jean II
+ *	o Remove (struct iw_point *)->pointer from events and streams
+ *	o Remove spy_offset from struct iw_handler_def
+ *	o Start deprecating dev->get_wireless_stats, output a warning
+ *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
+ *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
+ *
+ * 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()
+ *
+ * v10 - 16.3.07 - Jean II
+ *	o Prevent leaking of kernel space in stream on 64 bits.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/module.h>
+#include <linux/types.h>		/* off_t */
+#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+#include <linux/seq_file.h>
+#include <linux/init.h>			/* for __init */
+#include <linux/if_arp.h>		/* ARPHRD_ETHER */
+#include <linux/etherdevice.h>		/* compare_ether_addr */
+#include <linux/interrupt.h>
+
+#include <linux/wireless.h>		/* Pretty obvious */
+#include <net/iw_handler.h>		/* New driver API */
+#include <net/netlink.h>
+#include <net/wext.h>
+
+#include <asm/uaccess.h>		/* copy_to_user() */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because of re-entrancy.
+ * On our case, it's only const, so it's OK...
+ */
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
+static const struct iw_ioctl_description standard_ioctl[] = {
+	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWNAME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_CHAR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_range),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWPRIV	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_priv_args),
+		.max_tokens	= 16,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSTATS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_statistics),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCGIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCSIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[SIOCGIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMLME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_mlme),
+		.max_tokens	= sizeof(struct iw_mlme),
+	},
+	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_AP,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= 0,
+		.max_tokens	= sizeof(struct iw_scan_req),
+	},
+	[SIOCGIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_SCAN_MAX_DATA,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_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,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_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,
+	},
+	[SIOCSIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCGIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCSIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCGIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCSIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCSIWPMKSA - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_pmksa),
+		.max_tokens	= sizeof(struct iw_pmksa),
+	},
+};
+static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+static const struct iw_ioctl_description standard_event[] = {
+	[IWEVTXDROP	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVQUAL	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_QUAL,
+	},
+	[IWEVCUSTOM	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_CUSTOM_MAX,
+	},
+	[IWEVREGISTERED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVEXPIRED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVGENIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_michaelmicfailure),
+	},
+	[IWEVASSOCREQIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVASSOCRESPIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVPMKIDCAND	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_pmkid_cand),
+	},
+};
+static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
+
+/* Size (in bytes) of the various private data types */
+static const char iw_priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+	0,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+	0,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+};
+
+/* Size (in bytes) of various events, as packed */
+static const int event_type_pk_size[] = {
+	IW_EV_LCP_PK_LEN,		/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_PK_LEN,		/* IW_HEADER_TYPE_CHAR */
+	0,
+	IW_EV_UINT_PK_LEN,		/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_PK_LEN,		/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_PK_LEN,		/* IW_HEADER_TYPE_ADDR */
+	0,
+	IW_EV_POINT_PK_LEN,		/* Without variable payload */
+	IW_EV_PARAM_PK_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_PK_LEN,		/* IW_HEADER_TYPE_QUAL */
+};
+
+/************************ COMMON SUBROUTINES ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ */
+static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
+{
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned int	index;		/* *MUST* be unsigned */
+
+	/* Check if we have some wireless handlers defined */
+	if (dev->wireless_handlers == NULL)
+		return NULL;
+
+	/* Try as a standard command */
+	index = cmd - SIOCIWFIRST;
+	if (index < dev->wireless_handlers->num_standard)
+		return dev->wireless_handlers->standard[index];
+
+	/* Try as a private command */
+	index = cmd - SIOCIWFIRSTPRIV;
+	if (index < dev->wireless_handlers->num_private)
+		return dev->wireless_handlers->private[index];
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static struct iw_statistics *get_wireless_stats(struct net_device *dev)
+{
+	/* New location */
+	if ((dev->wireless_handlers != NULL) &&
+	   (dev->wireless_handlers->get_wireless_stats != NULL))
+		return dev->wireless_handlers->get_wireless_stats(dev);
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static int call_commit_handler(struct net_device *dev)
+{
+	if ((netif_running(dev)) &&
+	   (dev->wireless_handlers->standard[0] != NULL))
+		/* Call the commit handler on the driver */
+		return dev->wireless_handlers->standard[0](dev, NULL,
+							   NULL, NULL);
+	else
+		return 0;		/* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Calculate size of private arguments
+ */
+static inline int get_priv_size(__u16	args)
+{
+	int	num = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Re-calculate the size of private arguments
+ */
+static inline int adjust_priv_size(__u16		args,
+				   union iwreq_data *	wrqu)
+{
+	int	num = wrqu->data.length;
+	int	max = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	/* Make sure the driver doesn't goof up */
+	if (max < num)
+		num = max;
+
+	return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Standard Wireless Handler : get wireless stats
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static int iw_handler_get_iwstats(struct net_device *		dev,
+				  struct iw_request_info *	info,
+				  union iwreq_data *		wrqu,
+				  char *			extra)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev);
+	if (stats) {
+		/* Copy statistics to extra */
+		memcpy(extra, stats, sizeof(struct iw_statistics));
+		wrqu->data.length = sizeof(struct iw_statistics);
+
+		/* Check if we need to clear the updated flag */
+		if (wrqu->data.flags != 0)
+			stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Standard Wireless Handler : get iwpriv definitions
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static int iw_handler_get_private(struct net_device *		dev,
+				  struct iw_request_info *	info,
+				  union iwreq_data *		wrqu,
+				  char *			extra)
+{
+	/* Check if the driver has something to export */
+	if ((dev->wireless_handlers->num_private_args == 0) ||
+	   (dev->wireless_handlers->private_args == NULL))
+		return -EOPNOTSUPP;
+
+	/* Check if there is enough buffer up there */
+	if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
+		/* User space can't know in advance how large the buffer
+		 * needs to be. Give it a hint, so that we can support
+		 * any size buffer we want somewhat efficiently... */
+		wrqu->data.length = dev->wireless_handlers->num_private_args;
+		return -E2BIG;
+	}
+
+	/* Set the number of available ioctls. */
+	wrqu->data.length = dev->wireless_handlers->num_private_args;
+
+	/* Copy structure to the user buffer. */
+	memcpy(extra, dev->wireless_handlers->private_args,
+	       sizeof(struct iw_priv_args) * wrqu->data.length);
+
+	return 0;
+}
+
+
+/******************** /proc/net/wireless SUPPORT ********************/
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static void wireless_seq_printf_stats(struct seq_file *seq,
+				      struct net_device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats = get_wireless_stats(dev);
+
+	if (stats) {
+		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
+				"%6d %6d   %6d\n",
+			   dev->name, stats->status, stats->qual.qual,
+			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.level) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.noise) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
+			   ? '.' : ' ',
+			   stats->discard.nwid, stats->discard.code,
+			   stats->discard.fragment, stats->discard.retries,
+			   stats->discard.misc, stats->miss.beacon);
+		stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+	}
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+static int wireless_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN)
+		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
+				"packets               | Missed | WE\n"
+				" face | tus | link level noise |  nwid  "
+				"crypt   frag  retry   misc | beacon | %d\n",
+			   WIRELESS_EXT);
+	else
+		wireless_seq_printf_stats(seq, v);
+	return 0;
+}
+
+static const struct seq_operations wireless_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = wireless_seq_show,
+};
+
+static int wireless_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &wireless_seq_ops);
+}
+
+static const struct file_operations wireless_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = wireless_seq_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+int __init wext_proc_init(void)
+{
+	/* Create /proc/net/wireless entry */
+	if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+#endif	/* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static int ioctl_standard_call(struct net_device *	dev,
+			       struct ifreq *		ifr,
+			       unsigned int		cmd,
+			       iw_handler		handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+		return -EOPNOTSUPP;
+	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not */
+	if (descr->header_type != IW_HEADER_TYPE_POINT) {
+
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), NULL);
+
+		/* Generate an event to notify listeners of the change */
+		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT)))
+			wireless_send_event(dev, cmd, &(iwr->u), NULL);
+	} else {
+		char *	extra;
+		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 */
+			if ((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+			/* Check if number of token fits within bounds */
+			if (iwr->u.data.length > descr->max_tokens)
+				return -E2BIG;
+			if (iwr->u.data.length < descr->min_tokens)
+				return -EINVAL;
+		} else {
+			/* Check NULL pointer */
+			if (iwr->u.data.pointer == NULL)
+				return -EFAULT;
+			/* Save user space buffer size for checking */
+			user_length = iwr->u.data.length;
+
+			/* Don't check if user_length > max to allow forward
+			 * compatibility. The test user_length < min is
+			 * implied by the test at the end. */
+
+			/* Support for very large requests */
+			if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+			   (user_length > descr->max_tokens)) {
+				/* Allow userspace to GET more than max so
+				 * we can support any size GET requests.
+				 * There is still a limit : -ENOMEM. */
+				extra_size = user_length * descr->token_size;
+				/* Note : user_length is originally a __u16,
+				 * and token_size is controlled by us,
+				 * so extra_size won't get negative and
+				 * won't overflow... */
+			}
+		}
+
+		/* Create the kernel buffer */
+		/*    kzalloc ensures NULL-termination for essid_compat */
+		extra = kzalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL)
+			return -ENOMEM;
+
+		/* If it is a SET, get all the extra data in here */
+		if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     iwr->u.data.length *
+					     descr->token_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+		}
+
+		/* 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 */
+			if (user_length < iwr->u.data.length) {
+				kfree(extra);
+				return -E2BIG;
+			}
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   iwr->u.data.length *
+					   descr->token_size);
+			if (err)
+				ret =  -EFAULT;
+		}
+
+		/* Generate an event to notify listeners of the change */
+		if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT))) {
+			if (descr->flags & IW_DESCR_FLAG_RESTRICT)
+				/* If the event is restricted, don't
+				 * export the payload */
+				wireless_send_event(dev, cmd, &(iwr->u), NULL);
+			else
+				wireless_send_event(dev, cmd, &(iwr->u),
+						    extra);
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	/* Call commit handler if needed and defined */
+	if (ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	/* Here, we will generate the appropriate event if needed */
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr,
+			      unsigned int cmd, iw_handler handler)
+{
+	struct iwreq *			iwr = (struct iwreq *) ifr;
+	const struct iw_priv_args *	descr = NULL;
+	struct iw_request_info		info;
+	int				extra_size = 0;
+	int				i;
+	int				ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	for (i = 0; i < dev->wireless_handlers->num_private_args; i++)
+		if (cmd == dev->wireless_handlers->private_args[i].cmd) {
+			descr = &(dev->wireless_handlers->private_args[i]);
+			break;
+		}
+
+	/* Compute the size of the set/get arguments */
+	if (descr != NULL) {
+		if (IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if (descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->set_args);
+
+			/* Does it fits in iwr ? */
+			if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+			   ((extra_size + offset) <= IFNAMSIZ))
+				extra_size = 0;
+		} else {
+			/* Size of get arguments */
+			extra_size = get_priv_size(descr->get_args);
+
+			/* Does it fits in iwr ? */
+			if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size <= IFNAMSIZ))
+				extra_size = 0;
+		}
+	}
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not. */
+	if (extra_size == 0) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+	} else {
+		char *	extra;
+		int	err;
+
+		/* Check what user space is giving us */
+		if (IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if ((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+
+			/* Does it fits within bounds ? */
+			if (iwr->u.data.length > (descr->set_args &
+						 IW_PRIV_SIZE_MASK))
+				return -E2BIG;
+		} else if (iwr->u.data.pointer == NULL)
+			return -EFAULT;
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL)
+			return -ENOMEM;
+
+		/* If it is a SET, get all the extra data in here */
+		if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     extra_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+		}
+
+		/* Call the handler */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+
+			/* Adjust for the actual length if it's variable,
+			 * avoid leaking kernel bits outside. */
+			if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
+				extra_size = adjust_priv_size(descr->get_args,
+							      &(iwr->u));
+			}
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   extra_size);
+			if (err)
+				ret =  -EFAULT;
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+
+	/* Call commit handler if needed and defined */
+	if (ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher.
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+static int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	struct net_device *dev;
+	iw_handler	handler;
+
+	/* Permissions are already checked in dev_ioctl() before calling us.
+	 * The copy_to/from_user() of ifr is also dealt with in there */
+
+	/* Make sure the device exist */
+	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	/* A bunch of special cases, then the generic case...
+	 * Note that 'cmd' is already filtered in dev_ioctl() with
+	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+	if (cmd == SIOCGIWSTATS)
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_iwstats);
+
+	if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
+		return ioctl_standard_call(dev, ifr, cmd,
+					   &iw_handler_get_private);
+
+	/* Basic check */
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	/* New driver API : try to find the handler */
+	handler = get_handler(dev, cmd);
+	if (handler) {
+		/* Standard and private are not the same */
+		if (cmd < SIOCIWFIRSTPRIV)
+			return ioctl_standard_call(dev, ifr, cmd, handler);
+		else
+			return ioctl_private_call(dev, ifr, cmd, handler);
+	}
+	/* Old driver API : call driver ioctl handler */
+	if (dev->do_ioctl)
+		return dev->do_ioctl(dev, ifr, cmd);
+	return -EOPNOTSUPP;
+}
+
+/* entry point from dev ioctl */
+int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
+		      void __user *arg)
+{
+	int ret;
+
+	/* If command is `set a parameter', or
+	 * `get the encoding parameters', check if
+	 * the user has the right to do it */
+	if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
+	    && !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	dev_load(ifr->ifr_name);
+	rtnl_lock();
+	ret = wireless_process_ioctl(ifr, cmd);
+	rtnl_unlock();
+	if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct ifreq)))
+		return -EFAULT;
+	return ret;
+}
+
+/************************* EVENT PROCESSING *************************/
+/*
+ * Process events generated by the wireless layer or the driver.
+ * Most often, the event will be propagated through rtnetlink
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Locking...
+ * ----------
+ *
+ * Thanks to Herbert Xu <herbert@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)))
+		rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+}
+
+static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+
+/* ---------------------------------------------------------------- */
+/*
+ * Fill a rtnetlink message with our event data.
+ * Note that we propage only the specified event and don't dump the
+ * current wireless config. Dumping the wireless config is far too
+ * expensive (for each parameter, the driver need to query the hardware).
+ */
+static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
+				 int type, char *event, int event_len)
+{
+	struct ifinfomsg *r;
+	struct nlmsghdr  *nlh;
+	unsigned char	 *b = skb_tail_pointer(skb);
+
+	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	r->ifi_family = AF_UNSPEC;
+	r->__ifi_pad = 0;
+	r->ifi_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev_get_flags(dev);
+	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
+
+	/* Add the wireless events in the netlink packet */
+	RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
+
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
+	return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+	nlmsg_trim(skb, b);
+	return -1;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Create and broadcast and send it on the standard rtnetlink socket
+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
+ * within a RTM_NEWLINK event.
+ */
+static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
+{
+	struct sk_buff *skb;
+	int size = NLMSG_GOODSIZE;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
+				  event, event_len) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+	skb_queue_tail(&wireless_nlevent_queue, skb);
+	tasklet_schedule(&wireless_nlevent_tasklet);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the appropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct net_device *	dev,
+			 unsigned int		cmd,
+			 union iwreq_data *	wrqu,
+			 char *			extra)
+{
+	const struct iw_ioctl_description *	descr = NULL;
+	int extra_len = 0;
+	struct iw_event  *event;		/* Mallocated whole event */
+	int event_len;				/* Its size */
+	int hdr_len;				/* Size of the event header */
+	int wrqu_off = 0;			/* Offset in wrqu */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the Event */
+	if (cmd <= SIOCIWLAST) {
+		cmd_index = cmd - SIOCIWFIRST;
+		if (cmd_index < standard_ioctl_num)
+			descr = &(standard_ioctl[cmd_index]);
+	} else {
+		cmd_index = cmd - IWEVFIRST;
+		if (cmd_index < standard_event_num)
+			descr = &(standard_event[cmd_index]);
+	}
+	/* Don't accept unknown events */
+	if (descr == NULL) {
+		/* Note : we don't return an error to the driver, because
+		 * the driver would not know what to do about it. It can't
+		 * return an error to the user, because the event is not
+		 * initiated by a user request.
+		 * The best the driver could do is to log an error message.
+		 * We will do it ourselves instead...
+		 */
+		printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+		       dev->name, cmd);
+		return;
+	}
+
+	/* Check extra parameters and set extra_len */
+	if (descr->header_type == IW_HEADER_TYPE_POINT) {
+		/* Check if number of token fits within bounds */
+		if (wrqu->data.length > descr->max_tokens) {
+			printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		if (wrqu->data.length < descr->min_tokens) {
+			printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		/* Calculate extra_len - extra is NULL for restricted events */
+		if (extra != NULL)
+			extra_len = wrqu->data.length * descr->token_size;
+		/* Always at an offset in wrqu */
+		wrqu_off = IW_EV_POINT_OFF;
+	}
+
+	/* Total length of the event */
+	hdr_len = event_type_size[descr->header_type];
+	event_len = hdr_len + extra_len;
+
+	/* Create temporary buffer to hold the event */
+	event = kmalloc(event_len, GFP_ATOMIC);
+	if (event == NULL)
+		return;
+
+	/* Fill event */
+	event->len = event_len;
+	event->cmd = cmd;
+	memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
+	if (extra)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+	/* Send via the RtNetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
+EXPORT_SYMBOL(wireless_send_event);
+
+/********************** ENHANCED IWSPY SUPPORT **********************/
+/*
+ * In the old days, the driver was handling spy support all by itself.
+ * Now, the driver can delegate this task to Wireless Extensions.
+ * It needs to use those standard spy iw_handler in struct iw_handler_def,
+ * push data to us via wireless_spy_update() and include struct iw_spy_data
+ * in its private part (and export it in net_device->wireless_data->spy_data).
+ * One of the main advantage of centralising spy support here is that
+ * it becomes much easier to improve and extend it without having to touch
+ * the drivers. One example is the addition of the Spy-Threshold events.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the pointer to the spy data in the driver.
+ * Because this is called on the Rx path via wireless_spy_update(),
+ * we want it to be efficient...
+ */
+static inline struct iw_spy_data *get_spydata(struct net_device *dev)
+{
+	/* This is the new way */
+	if (dev->wireless_data)
+		return dev->wireless_data->spy_data;
+	return NULL;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set Spy List
+ */
+int iw_handler_set_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Disable spy collection while we copy the addresses.
+	 * While we copy addresses, any call to wireless_spy_update()
+	 * will NOP. This is OK, as anyway the addresses are changing. */
+	spydata->spy_number = 0;
+
+	/* We want to operate without locking, because wireless_spy_update()
+	 * most likely will happen in the interrupt handler, and therefore
+	 * have its own locking constraints and needs performance.
+	 * The rtnl_lock() make sure we don't race with the other iw_handlers.
+	 * This make sure wireless_spy_update() "see" that the spy list
+	 * is temporarily disabled. */
+	smp_wmb();
+
+	/* Are there are addresses to copy? */
+	if (wrqu->data.length > 0) {
+		int i;
+
+		/* Copy addresses */
+		for (i = 0; i < wrqu->data.length; i++)
+			memcpy(spydata->spy_address[i], address[i].sa_data,
+			       ETH_ALEN);
+		/* Reset stats */
+		memset(spydata->spy_stat, 0,
+		       sizeof(struct iw_quality) * IW_MAX_SPY);
+	}
+
+	/* Make sure above is updated before re-enabling */
+	smp_wmb();
+
+	/* Enable addresses */
+	spydata->spy_number = wrqu->data.length;
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get Spy List
+ */
+int iw_handler_get_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+	int			i;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	wrqu->data.length = spydata->spy_number;
+
+	/* Copy addresses. */
+	for (i = 0; i < spydata->spy_number; i++) 	{
+		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	/* Copy stats to the user buffer (just after). */
+	if (spydata->spy_number > 0)
+		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
+		       spydata->spy_stat,
+		       sizeof(struct iw_quality) * spydata->spy_number);
+	/* Reset updated flags. */
+	for (i = 0; i < spydata->spy_number; i++)
+		spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int iw_handler_set_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Just do it */
+	memcpy(&(spydata->spy_thr_low), &(threshold->low),
+	       2 * sizeof(struct iw_quality));
+
+	/* Clear flag */
+	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int iw_handler_get_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return -EOPNOTSUPP;
+
+	/* Just do it */
+	memcpy(&(threshold->low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+	return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare and send a Spy Threshold event
+ */
+static void iw_send_thrspy_event(struct net_device *	dev,
+				 struct iw_spy_data *	spydata,
+				 unsigned char *	address,
+				 struct iw_quality *	wstats)
+{
+	union iwreq_data	wrqu;
+	struct iw_thrspy	threshold;
+
+	/* Init */
+	wrqu.data.length = 1;
+	wrqu.data.flags = 0;
+	/* Copy address */
+	memcpy(threshold.addr.sa_data, address, ETH_ALEN);
+	threshold.addr.sa_family = ARPHRD_ETHER;
+	/* Copy stats */
+	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
+	/* Copy also thresholds */
+	memcpy(&(threshold.low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call for the driver to update the spy data.
+ * For now, the spy data is a simple array. As the size of the array is
+ * small, this is good enough. If we wanted to support larger number of
+ * spy addresses, we should use something more efficient...
+ */
+void wireless_spy_update(struct net_device *	dev,
+			 unsigned char *	address,
+			 struct iw_quality *	wstats)
+{
+	struct iw_spy_data *	spydata = get_spydata(dev);
+	int			i;
+	int			match = -1;
+
+	/* Make sure driver is not buggy or using the old API */
+	if (!spydata)
+		return;
+
+	/* Update all records that match */
+	for (i = 0; i < spydata->spy_number; i++)
+		if (!compare_ether_addr(address, spydata->spy_address[i])) {
+			memcpy(&(spydata->spy_stat[i]), wstats,
+			       sizeof(struct iw_quality));
+			match = i;
+		}
+
+	/* Generate an event if we cross the spy threshold.
+	 * To avoid event storms, we have a simple hysteresis : we generate
+	 * event only when we go under the low threshold or above the
+	 * high threshold. */
+	if (match >= 0) {
+		if (spydata->spy_thr_under[match]) {
+			if (wstats->level > spydata->spy_thr_high.level) {
+				spydata->spy_thr_under[match] = 0;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		} else {
+			if (wstats->level < spydata->spy_thr_low.level) {
+				spydata->spy_thr_under[match] = 1;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		}
+	}
+}
+EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index e62ba41..479927c 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -951,7 +951,7 @@ int x25_rx_call_request(struct sk_buff *
 	 *	Incoming Call User Data.
 	 */
 	if (skb->len >= 0) {
-		memcpy(makex25->calluserdata.cuddata, skb->data, skb->len);
+		skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
 		makex25->calluserdata.cudlength = skb->len;
 	}
 
@@ -1058,9 +1058,10 @@ static int x25_sendmsg(struct kiocb *ioc
 	 */
 	SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n");
 
-	asmptr = skb->h.raw = skb_put(skb, len);
+	skb_reset_transport_header(skb);
+	skb_put(skb, len);
 
-	rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);
+	rc = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (rc)
 		goto out_kfree_skb;
 
@@ -1210,8 +1211,7 @@ static int x25_recvmsg(struct kiocb *ioc
 		}
 	}
 
-	skb->h.raw = skb->data;
-
+	skb_reset_transport_header(skb);
 	copied = skb->len;
 
 	if (copied > size) {
@@ -1280,6 +1280,12 @@ static int x25_ioctl(struct socket *sock
 				rc = sock_get_timestamp(sk,
 						(struct timeval __user *)argp);
 			break;
+		case SIOCGSTAMPNS:
+			rc = -EINVAL;
+			if (sk)
+				rc = sock_get_timestampns(sk,
+						(struct timespec __user *)argp);
+			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -1521,6 +1527,12 @@ static int compat_x25_ioctl(struct socke
 			rc = compat_sock_get_timestamp(sk,
 					(struct timeval __user*)argp);
 		break;
+	case SIOCGSTAMPNS:
+		rc = -EINVAL;
+		if (sk)
+			rc = compat_sock_get_timestampns(sk,
+					(struct timespec __user*)argp);
+		break;
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
@@ -1593,7 +1605,6 @@ #endif
 	.sendpage =	sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
 SOCKOPS_WRAP(x25_proto, AF_X25);
 
 static struct packet_type x25_packet_type = {
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index c7221de..848a6b6 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -48,7 +48,7 @@ static int x25_receive_data(struct sk_bu
 	if ((sk = x25_find_socket(lci, nb)) != NULL) {
 		int queued = 1;
 
-		skb->h.raw = skb->data;
+		skb_reset_transport_header(skb);
 		bh_lock_sock(sk);
 		if (!sock_owned_by_user(sk)) {
 			queued = x25_process_rx_frame(sk, skb);
@@ -191,7 +191,7 @@ void x25_send_frame(struct sk_buff *skb,
 {
 	unsigned char *dptr;
 
-	skb->nh.raw = skb->data;
+	skb_reset_network_header(skb);
 
 	switch (nb->dev->type) {
 		case ARPHRD_X25:
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index c5239fc..1c88762 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -53,17 +53,20 @@ static int x25_queue_rx_frame(struct soc
 
 		skb_queue_tail(&x25->fragment_queue, skb);
 
-		skbn->h.raw = skbn->data;
+		skb_reset_transport_header(skbn);
 
 		skbo = skb_dequeue(&x25->fragment_queue);
-		memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+		skb_copy_from_linear_data(skbo, skb_put(skbn, skbo->len),
+					  skbo->len);
 		kfree_skb(skbo);
 
 		while ((skbo =
 			skb_dequeue(&x25->fragment_queue)) != NULL) {
 			skb_pull(skbo, (x25->neighbour->extended) ?
 					X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
-			memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+			skb_copy_from_linear_data(skbo,
+						  skb_put(skbn, skbo->len),
+						  skbo->len);
 			kfree_skb(skbo);
 		}
 
@@ -112,8 +115,9 @@ static int x25_state1_machine(struct soc
 			 *	Copy any Call User Data.
 			 */
 			if (skb->len >= 0) {
-				memcpy(x25->calluserdata.cuddata, skb->data,
-				       skb->len);
+				skb_copy_from_linear_data(skb,
+					      x25->calluserdata.cuddata,
+					      skb->len);
 				x25->calluserdata.cudlength = skb->len;
 			}
 			if (!sock_flag(sk, SOCK_DEAD))
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index 6f57378..2b96b52 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -61,7 +61,7 @@ int x25_output(struct sock *sk, struct s
 
 	if (skb->len - header_len > max_len) {
 		/* Save a copy of the Header */
-		memcpy(header, skb->data, header_len);
+		skb_copy_from_linear_data(skb, header, header_len);
 		skb_pull(skb, header_len);
 
 		frontlen = skb_headroom(skb);
@@ -84,12 +84,12 @@ int x25_output(struct sock *sk, struct s
 			len = max_len > skb->len ? skb->len : max_len;
 
 			/* Copy the user data */
-			memcpy(skb_put(skbn, len), skb->data, len);
+			skb_copy_from_linear_data(skb, skb_put(skbn, len), len);
 			skb_pull(skb, len);
 
 			/* Duplicate the Header */
 			skb_push(skbn, header_len);
-			memcpy(skbn->data, header, header_len);
+			skb_copy_to_linear_data(skbn, header, header_len);
 
 			if (skb->len > 0) {
 				if (x25->neighbour->extended)
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index f373a8a..6249a94 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -612,175 +612,6 @@ EXPORT_SYMBOL_GPL(skb_icv_walk);
 
 #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
 
-/* Looking generic it is not used in another places. */
-
-int
-skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
-{
-	int start = skb_headlen(skb);
-	int i, copy = start - offset;
-	int elt = 0;
-
-	if (copy > 0) {
-		if (copy > len)
-			copy = len;
-		sg[elt].page = virt_to_page(skb->data + offset);
-		sg[elt].offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
-		sg[elt].length = copy;
-		elt++;
-		if ((len -= copy) == 0)
-			return elt;
-		offset += copy;
-	}
-
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		int end;
-
-		BUG_TRAP(start <= offset + len);
-
-		end = start + skb_shinfo(skb)->frags[i].size;
-		if ((copy = end - offset) > 0) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-			if (copy > len)
-				copy = len;
-			sg[elt].page = frag->page;
-			sg[elt].offset = frag->page_offset+offset-start;
-			sg[elt].length = copy;
-			elt++;
-			if (!(len -= copy))
-				return elt;
-			offset += copy;
-		}
-		start = end;
-	}
-
-	if (skb_shinfo(skb)->frag_list) {
-		struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-		for (; list; list = list->next) {
-			int end;
-
-			BUG_TRAP(start <= offset + len);
-
-			end = start + list->len;
-			if ((copy = end - offset) > 0) {
-				if (copy > len)
-					copy = len;
-				elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
-				if ((len -= copy) == 0)
-					return elt;
-				offset += copy;
-			}
-			start = end;
-		}
-	}
-	BUG_ON(len);
-	return elt;
-}
-EXPORT_SYMBOL_GPL(skb_to_sgvec);
-
-/* Check that skb data bits are writable. If they are not, copy data
- * to newly created private area. If "tailbits" is given, make sure that
- * tailbits bytes beyond current end of skb are writable.
- *
- * Returns amount of elements of scatterlist to load for subsequent
- * transformations and pointer to writable trailer skb.
- */
-
-int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
-{
-	int copyflag;
-	int elt;
-	struct sk_buff *skb1, **skb_p;
-
-	/* If skb is cloned or its head is paged, reallocate
-	 * head pulling out all the pages (pages are considered not writable
-	 * at the moment even if they are anonymous).
-	 */
-	if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) &&
-	    __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL)
-		return -ENOMEM;
-
-	/* Easy case. Most of packets will go this way. */
-	if (!skb_shinfo(skb)->frag_list) {
-		/* A little of trouble, not enough of space for trailer.
-		 * This should not happen, when stack is tuned to generate
-		 * good frames. OK, on miss we reallocate and reserve even more
-		 * space, 128 bytes is fair. */
-
-		if (skb_tailroom(skb) < tailbits &&
-		    pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC))
-			return -ENOMEM;
-
-		/* Voila! */
-		*trailer = skb;
-		return 1;
-	}
-
-	/* Misery. We are in troubles, going to mincer fragments... */
-
-	elt = 1;
-	skb_p = &skb_shinfo(skb)->frag_list;
-	copyflag = 0;
-
-	while ((skb1 = *skb_p) != NULL) {
-		int ntail = 0;
-
-		/* The fragment is partially pulled by someone,
-		 * this can happen on input. Copy it and everything
-		 * after it. */
-
-		if (skb_shared(skb1))
-			copyflag = 1;
-
-		/* If the skb is the last, worry about trailer. */
-
-		if (skb1->next == NULL && tailbits) {
-			if (skb_shinfo(skb1)->nr_frags ||
-			    skb_shinfo(skb1)->frag_list ||
-			    skb_tailroom(skb1) < tailbits)
-				ntail = tailbits + 128;
-		}
-
-		if (copyflag ||
-		    skb_cloned(skb1) ||
-		    ntail ||
-		    skb_shinfo(skb1)->nr_frags ||
-		    skb_shinfo(skb1)->frag_list) {
-			struct sk_buff *skb2;
-
-			/* Fuck, we are miserable poor guys... */
-			if (ntail == 0)
-				skb2 = skb_copy(skb1, GFP_ATOMIC);
-			else
-				skb2 = skb_copy_expand(skb1,
-						       skb_headroom(skb1),
-						       ntail,
-						       GFP_ATOMIC);
-			if (unlikely(skb2 == NULL))
-				return -ENOMEM;
-
-			if (skb1->sk)
-				skb_set_owner_w(skb2, skb1->sk);
-
-			/* Looking around. Are we still alive?
-			 * OK, link new skb, drop old one */
-
-			skb2->next = skb1->next;
-			*skb_p = skb2;
-			kfree_skb(skb1);
-			skb1 = skb2;
-		}
-		elt++;
-		*trailer = skb1;
-		skb_p = &skb1->next;
-	}
-
-	return elt;
-}
-EXPORT_SYMBOL_GPL(skb_cow_data);
-
 void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len)
 {
 	if (tail != skb) {
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index ee15bda..5c46958 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -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(*(__be16*)(skb->h.raw + 2)));
+		*spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 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 = *(__be32*)(skb->h.raw + offset);
-	*seq = *(__be32*)(skb->h.raw + offset_seq);
+	*spi = *(__be32*)(skb_transport_header(skb) + offset);
+	*seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
 	return 0;
 }
 EXPORT_SYMBOL(xfrm_parse_spi);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 785c3e3..95271e8 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -268,7 +268,7 @@ static inline unsigned long make_jiffies
 static void xfrm_policy_timer(unsigned long data)
 {
 	struct xfrm_policy *xp = (struct xfrm_policy*)data;
-	unsigned long now = (unsigned long)xtime.tv_sec;
+	unsigned long now = get_seconds();
 	long next = LONG_MAX;
 	int warn = 0;
 	int dir;
@@ -579,8 +579,22 @@ static inline int xfrm_byidx_should_resi
 	return 0;
 }
 
-static DEFINE_MUTEX(hash_resize_mutex);
+void xfrm_spd_getinfo(struct xfrmk_spdinfo *si)
+{
+	read_lock_bh(&xfrm_policy_lock);
+	si->incnt = xfrm_policy_count[XFRM_POLICY_IN];
+	si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT];
+	si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD];
+	si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
+	si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
+	si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
+	si->spdhcnt = xfrm_idx_hmask;
+	si->spdhmcnt = xfrm_policy_hashmax;
+	read_unlock_bh(&xfrm_policy_lock);
+}
+EXPORT_SYMBOL(xfrm_spd_getinfo);
 
+static DEFINE_MUTEX(hash_resize_mutex);
 static void xfrm_hash_resize(struct work_struct *__unused)
 {
 	int dir, total;
@@ -690,7 +704,7 @@ int xfrm_policy_insert(int dir, struct x
 	}
 	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.add_time = get_seconds();
 	policy->curlft.use_time = 0;
 	if (!mod_timer(&policy->timer, jiffies + HZ))
 		xfrm_pol_hold(policy);
@@ -1049,7 +1063,7 @@ static inline int policy_to_flow_dir(int
 		return FLOW_DIR_OUT;
 	case XFRM_POLICY_FWD:
 		return FLOW_DIR_FWD;
-	};
+	}
 }
 
 static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
@@ -1133,7 +1147,7 @@ #endif
 	old_pol = sk->sk_policy[dir];
 	sk->sk_policy[dir] = pol;
 	if (pol) {
-		pol->curlft.add_time = (unsigned long)xtime.tv_sec;
+		pol->curlft.add_time = get_seconds();
 		pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir);
 		__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
 	}
@@ -1330,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *p
 	return err;
 }
 
+static int inline
+xfrm_dst_alloc_copy(void **target, void *src, int size)
+{
+	if (!*target) {
+		*target = kmalloc(size, GFP_ATOMIC);
+		if (!*target)
+			return -ENOMEM;
+	}
+	memcpy(*target, src, size);
+	return 0;
+}
+
+static int inline
+xfrm_dst_update_parent(struct dst_entry *dst, struct xfrm_selector *sel)
+{
+#ifdef CONFIG_XFRM_SUB_POLICY
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+	return xfrm_dst_alloc_copy((void **)&(xdst->partner),
+				   sel, sizeof(*sel));
+#else
+	return 0;
+#endif
+}
+
+static int inline
+xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
+{
+#ifdef CONFIG_XFRM_SUB_POLICY
+	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+	return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
+#else
+	return 0;
+#endif
+}
 
 static int stale_bundle(struct dst_entry *dst);
 
@@ -1386,7 +1434,7 @@ restart:
 		return 0;
 
 	family = dst_orig->ops->family;
-	policy->curlft.use_time = (unsigned long)xtime.tv_sec;
+	policy->curlft.use_time = get_seconds();
 	pols[0] = policy;
 	npols ++;
 	xfrm_nr += pols[0]->xfrm_nr;
@@ -1518,6 +1566,18 @@ #endif
 			err = -EHOSTUNREACH;
 			goto error;
 		}
+
+		if (npols > 1)
+			err = xfrm_dst_update_parent(dst, &pols[1]->selector);
+		else
+			err = xfrm_dst_update_origin(dst, fl);
+		if (unlikely(err)) {
+			write_unlock_bh(&policy->lock);
+			if (dst)
+				dst_free(dst);
+			goto error;
+		}
+
 		dst->next = policy->bundles;
 		policy->bundles = dst;
 		dst_hold(dst);
@@ -1682,7 +1742,7 @@ int __xfrm_policy_check(struct sock *sk,
 		return 1;
 	}
 
-	pol->curlft.use_time = (unsigned long)xtime.tv_sec;
+	pol->curlft.use_time = get_seconds();
 
 	pols[0] = pol;
 	npols ++;
@@ -1694,7 +1754,7 @@ #ifdef CONFIG_XFRM_SUB_POLICY
 		if (pols[1]) {
 			if (IS_ERR(pols[1]))
 				return 0;
-			pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
+			pols[1]->curlft.use_time = get_seconds();
 			npols ++;
 		}
 	}
@@ -1933,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *p
 	if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
 	    (dst->dev && !netif_running(dst->dev)))
 		return 0;
+#ifdef CONFIG_XFRM_SUB_POLICY
+	if (fl) {
+		if (first->origin && !flow_cache_uli_match(first->origin, fl))
+			return 0;
+		if (first->partner &&
+		    !xfrm_selector_match(first->partner, fl, family))
+			return 0;
+	}
+#endif
 
 	last = NULL;
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index e3a0bcf..9955ff4 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -233,7 +233,7 @@ static inline unsigned long make_jiffies
 static void xfrm_timer_handler(unsigned long data)
 {
 	struct xfrm_state *x = (struct xfrm_state*)data;
-	unsigned long now = (unsigned long)xtime.tv_sec;
+	unsigned long now = get_seconds();
 	long next = LONG_MAX;
 	int warn = 0;
 	int err = 0;
@@ -326,7 +326,7 @@ struct xfrm_state *xfrm_state_alloc(void
 		init_timer(&x->rtimer);
 		x->rtimer.function = xfrm_replay_timer_handler;
 		x->rtimer.data     = (unsigned long)x;
-		x->curlft.add_time = (unsigned long)xtime.tv_sec;
+		x->curlft.add_time = get_seconds();
 		x->lft.soft_byte_limit = XFRM_INF;
 		x->lft.soft_packet_limit = XFRM_INF;
 		x->lft.hard_byte_limit = XFRM_INF;
@@ -421,6 +421,16 @@ restart:
 }
 EXPORT_SYMBOL(xfrm_state_flush);
 
+void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
+{
+	spin_lock_bh(&xfrm_state_lock);
+	si->sadcnt = xfrm_state_num;
+	si->sadhcnt = xfrm_state_hmask;
+	si->sadhmcnt = xfrm_state_hashmax;
+	spin_unlock_bh(&xfrm_state_lock);
+}
+EXPORT_SYMBOL(xfrm_sad_getinfo);
+
 static int
 xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
 		  struct xfrm_tmpl *tmpl,
@@ -458,7 +468,7 @@ static struct xfrm_state *__xfrm_state_l
 					     x->id.daddr.a6))
 				continue;
 			break;
-		};
+		}
 
 		xfrm_state_hold(x);
 		return x;
@@ -493,7 +503,7 @@ static struct xfrm_state *__xfrm_state_l
 					     x->props.saddr.a6))
 				continue;
 			break;
-		};
+		}
 
 		xfrm_state_hold(x);
 		return x;
@@ -722,7 +732,7 @@ static struct xfrm_state *__find_acq_cor
 					     (struct in6_addr *)saddr))
 				continue;
 			break;
-		};
+		}
 
 		xfrm_state_hold(x);
 		return x;
@@ -755,7 +765,7 @@ static struct xfrm_state *__find_acq_cor
 			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;
@@ -1051,7 +1061,7 @@ EXPORT_SYMBOL(xfrm_state_update);
 int xfrm_state_check_expire(struct xfrm_state *x)
 {
 	if (!x->curlft.use_time)
-		x->curlft.use_time = (unsigned long)xtime.tv_sec;
+		x->curlft.use_time = get_seconds();
 
 	if (x->km.state != XFRM_STATE_VALID)
 		return -EINVAL;
@@ -1667,37 +1677,17 @@ void xfrm_state_delete_tunnel(struct xfr
 }
 EXPORT_SYMBOL(xfrm_state_delete_tunnel);
 
-/*
- * This function is NOT optimal.  For example, with ESP it will give an
- * MTU that's usually two bytes short of being optimal.  However, it will
- * usually give an answer that's a multiple of 4 provided the input is
- * also a multiple of 4.
- */
 int xfrm_state_mtu(struct xfrm_state *x, int mtu)
 {
-	int res = mtu;
-
-	res -= x->props.header_len;
-
-	for (;;) {
-		int m = res;
-
-		if (m < 68)
-			return 68;
-
-		spin_lock_bh(&x->lock);
-		if (x->km.state == XFRM_STATE_VALID &&
-		    x->type && x->type->get_max_size)
-			m = x->type->get_max_size(x, m);
-		else
-			m += x->props.header_len;
-		spin_unlock_bh(&x->lock);
-
-		if (m <= mtu)
-			break;
-		res -= (m - mtu);
-	}
+	int res;
 
+	spin_lock_bh(&x->lock);
+	if (x->km.state == XFRM_STATE_VALID &&
+	    x->type && x->type->get_mtu)
+		res = x->type->get_mtu(x, mtu);
+	else
+		res = mtu;
+	spin_unlock_bh(&x->lock);
 	return res;
 }
 
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 816e369..b14c7e5 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -71,7 +71,7 @@ static int verify_one_alg(struct rtattr 
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
 	return 0;
@@ -152,7 +152,7 @@ #endif
 
 	default:
 		goto out;
-	};
+	}
 
 	err = -EINVAL;
 	switch (p->id.proto) {
@@ -192,7 +192,7 @@ #endif
 
 	default:
 		goto out;
-	};
+	}
 
 	if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH)))
 		goto out;
@@ -217,7 +217,7 @@ #endif
 
 	default:
 		goto out;
-	};
+	}
 
 	err = 0;
 
@@ -576,7 +576,7 @@ static int dump_one_state(struct xfrm_st
 	struct sk_buff *skb = sp->out_skb;
 	struct xfrm_usersa_info *p;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	if (sp->this_idx < sp->start_idx)
 		goto out;
@@ -621,14 +621,14 @@ static int dump_one_state(struct xfrm_st
 	if (x->lastused)
 		RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused);
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 out:
 	sp->this_idx++;
 	return 0;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -672,6 +672,113 @@ static struct sk_buff *xfrm_state_netlin
 	return skb;
 }
 
+static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
+{
+	struct xfrmk_spdinfo si;
+	struct xfrmu_spdinfo spc;
+	struct xfrmu_spdhinfo sph;
+	struct nlmsghdr *nlh;
+	u32 *f;
+
+	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
+	if (nlh == NULL) /* shouldnt really happen ... */
+		return -EMSGSIZE;
+
+	f = nlmsg_data(nlh);
+	*f = flags;
+	xfrm_spd_getinfo(&si);
+	spc.incnt = si.incnt;
+	spc.outcnt = si.outcnt;
+	spc.fwdcnt = si.fwdcnt;
+	spc.inscnt = si.inscnt;
+	spc.outscnt = si.outscnt;
+	spc.fwdscnt = si.fwdscnt;
+	sph.spdhcnt = si.spdhcnt;
+	sph.spdhmcnt = si.spdhmcnt;
+
+	NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
+	NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
+
+	return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
+		struct rtattr **xfrma)
+{
+	struct sk_buff *r_skb;
+	u32 *flags = NLMSG_DATA(nlh);
+	u32 spid = NETLINK_CB(skb).pid;
+	u32 seq = nlh->nlmsg_seq;
+	int len = NLMSG_LENGTH(sizeof(u32));
+
+	len += RTA_SPACE(sizeof(struct xfrmu_spdinfo));
+	len += RTA_SPACE(sizeof(struct xfrmu_spdhinfo));
+
+	r_skb = alloc_skb(len, GFP_ATOMIC);
+	if (r_skb == NULL)
+		return -ENOMEM;
+
+	if (build_spdinfo(r_skb, spid, seq, *flags) < 0)
+		BUG();
+
+	return nlmsg_unicast(xfrm_nl, r_skb, spid);
+}
+
+static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
+{
+	struct xfrmk_sadinfo si;
+	struct xfrmu_sadhinfo sh;
+	struct nlmsghdr *nlh;
+	u32 *f;
+
+	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
+	if (nlh == NULL) /* shouldnt really happen ... */
+		return -EMSGSIZE;
+
+	f = nlmsg_data(nlh);
+	*f = flags;
+	xfrm_sad_getinfo(&si);
+
+	sh.sadhmcnt = si.sadhmcnt;
+	sh.sadhcnt = si.sadhcnt;
+
+	NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);
+	NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
+
+	return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+	nlmsg_cancel(skb, nlh);
+	return -EMSGSIZE;
+}
+
+static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
+		struct rtattr **xfrma)
+{
+	struct sk_buff *r_skb;
+	u32 *flags = NLMSG_DATA(nlh);
+	u32 spid = NETLINK_CB(skb).pid;
+	u32 seq = nlh->nlmsg_seq;
+	int len = NLMSG_LENGTH(sizeof(u32));
+
+	len += RTA_SPACE(sizeof(struct xfrmu_sadhinfo));
+	len += RTA_SPACE(sizeof(u32));
+
+	r_skb = alloc_skb(len, GFP_ATOMIC);
+
+	if (r_skb == NULL)
+		return -ENOMEM;
+
+	if (build_sadinfo(r_skb, spid, seq, *flags) < 0)
+		BUG();
+
+	return nlmsg_unicast(xfrm_nl, r_skb, spid);
+}
+
 static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 		struct rtattr **xfrma)
 {
@@ -711,7 +818,7 @@ static int verify_userspi_info(struct xf
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	if (p->min > p->max)
 		return -EINVAL;
@@ -789,7 +896,7 @@ static int verify_policy_dir(u8 dir)
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	return 0;
 }
@@ -805,7 +912,7 @@ #endif
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	return 0;
 }
@@ -821,7 +928,7 @@ static int verify_newpolicy_info(struct 
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	switch (p->action) {
 	case XFRM_POLICY_ALLOW:
@@ -830,7 +937,7 @@ static int verify_newpolicy_info(struct 
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	switch (p->sel.family) {
 	case AF_INET:
@@ -845,7 +952,7 @@ #endif
 
 	default:
 		return -EINVAL;
-	};
+	}
 
 	return verify_policy_dir(p->dir);
 }
@@ -912,7 +1019,7 @@ #if defined(CONFIG_IPV6) || defined(CONF
 #endif
 		default:
 			return -EINVAL;
-		};
+		}
 	}
 
 	return 0;
@@ -1157,7 +1264,7 @@ static int dump_one_policy(struct xfrm_p
 	struct sk_buff *in_skb = sp->in_skb;
 	struct sk_buff *skb = sp->out_skb;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	if (sp->this_idx < sp->start_idx)
 		goto out;
@@ -1176,13 +1283,13 @@ static int dump_one_policy(struct xfrm_p
 	if (copy_to_user_policy_type(xp->type, skb) < 0)
 		goto nlmsg_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 out:
 	sp->this_idx++;
 	return 0;
 
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1330,7 +1437,7 @@ static int build_aevent(struct sk_buff *
 	struct xfrm_aevent_id *id;
 	struct nlmsghdr *nlh;
 	struct xfrm_lifetime_cur ltime;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id));
 	id = NLMSG_DATA(nlh);
@@ -1362,12 +1469,12 @@ static int build_aevent(struct sk_buff *
 		RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer);
 	}
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 rtattr_failure:
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1744,7 +1851,7 @@ static int build_migrate(struct sk_buff 
 	struct xfrm_migrate *mp;
 	struct xfrm_userpolicy_id *pol_id;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	int i;
 
 	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id));
@@ -1764,10 +1871,10 @@ static int build_migrate(struct sk_buff 
 			goto nlmsg_failure;
 	}
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1823,6 +1930,8 @@ static const int xfrm_msg_min[XFRM_NR_MS
 	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
 	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
 	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
+	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
+	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
 };
 
 #undef XMSGSIZE
@@ -1850,55 +1959,40 @@ static struct xfrm_link {
 	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },
 	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },
 	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },
+	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo   },
+	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },
 };
 
-static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
 	struct rtattr *xfrma[XFRMA_MAX];
 	struct xfrm_link *link;
 	int type, min_len;
 
-	if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
-		return 0;
-
 	type = nlh->nlmsg_type;
-
-	/* A control message: ignore them */
-	if (type < XFRM_MSG_BASE)
-		return 0;
-
-	/* Unknown message: reply with EINVAL */
 	if (type > XFRM_MSG_MAX)
-		goto err_einval;
+		return -EINVAL;
 
 	type -= XFRM_MSG_BASE;
 	link = &xfrm_dispatch[type];
 
 	/* All operations require privileges, even GET */
-	if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
-		*errp = -EPERM;
-		return -1;
-	}
+	if (security_netlink_recv(skb, CAP_NET_ADMIN))
+		return -EPERM;
 
 	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
 	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
 	    (nlh->nlmsg_flags & NLM_F_DUMP)) {
 		if (link->dump == NULL)
-			goto err_einval;
-
-		if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
-						link->dump, NULL)) != 0) {
-			return -1;
-		}
+			return -EINVAL;
 
-		netlink_queue_skip(nlh, skb);
-		return -1;
+		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
 	}
 
 	memset(xfrma, 0, sizeof(xfrma));
 
 	if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
-		goto err_einval;
+		return -EINVAL;
 
 	if (nlh->nlmsg_len > min_len) {
 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
@@ -1908,7 +2002,7 @@ static int xfrm_user_rcv_msg(struct sk_b
 			unsigned short flavor = attr->rta_type;
 			if (flavor) {
 				if (flavor > XFRMA_MAX)
-					goto err_einval;
+					return -EINVAL;
 				xfrma[flavor - 1] = attr;
 			}
 			attr = RTA_NEXT(attr, attrlen);
@@ -1916,14 +2010,9 @@ static int xfrm_user_rcv_msg(struct sk_b
 	}
 
 	if (link->doit == NULL)
-		goto err_einval;
-	*errp = link->doit(skb, nlh, xfrma);
-
-	return *errp;
+		return -EINVAL;
 
-err_einval:
-	*errp = -EINVAL;
-	return -1;
+	return link->doit(skb, nlh, xfrma);
 }
 
 static void xfrm_netlink_rcv(struct sock *sk, int len)
@@ -1942,7 +2031,7 @@ static int build_expire(struct sk_buff *
 {
 	struct xfrm_user_expire *ue;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE,
 			sizeof(*ue));
@@ -1952,11 +2041,11 @@ static int build_expire(struct sk_buff *
 	copy_to_user_state(x, &ue->state);
 	ue->hard = (c->data.hard != 0) ? 1 : 0;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -1999,7 +2088,7 @@ static int xfrm_notify_sa_flush(struct k
 	struct xfrm_usersa_flush *p;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
-	unsigned char *b;
+	sk_buff_data_t b;
 	int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
 
 	skb = alloc_skb(len, GFP_ATOMIC);
@@ -2045,7 +2134,7 @@ static int xfrm_notify_sa(struct xfrm_st
 	struct xfrm_usersa_id *id;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
-	unsigned char *b;
+	sk_buff_data_t b;
 	int len = xfrm_sa_len(x);
 	int headlen;
 
@@ -2129,7 +2218,7 @@ static int build_acquire(struct sk_buff 
 {
 	struct xfrm_user_acquire *ua;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 	__u32 seq = xfrm_get_acqseq();
 
 	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE,
@@ -2153,11 +2242,11 @@ static int build_acquire(struct sk_buff 
 	if (copy_to_user_policy_type(xp->type, skb) < 0)
 		goto nlmsg_failure;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -2249,7 +2338,7 @@ static int build_polexpire(struct sk_buf
 	struct xfrm_user_polexpire *upe;
 	struct nlmsghdr *nlh;
 	int hard = c->data.hard;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
 	upe = NLMSG_DATA(nlh);
@@ -2264,11 +2353,11 @@ static int build_polexpire(struct sk_buf
 		goto nlmsg_failure;
 	upe->hard = !!hard;
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -2300,7 +2389,7 @@ static int xfrm_notify_policy(struct xfr
 	struct xfrm_userpolicy_id *id;
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
-	unsigned char *b;
+	sk_buff_data_t b;
 	int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
 	int headlen;
 
@@ -2357,7 +2446,7 @@ static int xfrm_notify_policy_flush(stru
 {
 	struct nlmsghdr *nlh;
 	struct sk_buff *skb;
-	unsigned char *b;
+	sk_buff_data_t b;
 	int len = 0;
 #ifdef CONFIG_XFRM_SUB_POLICY
 	len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
@@ -2410,7 +2499,7 @@ static int build_report(struct sk_buff *
 {
 	struct xfrm_user_report *ur;
 	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
+	unsigned char *b = skb_tail_pointer(skb);
 
 	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur));
 	ur = NLMSG_DATA(nlh);
@@ -2422,12 +2511,12 @@ static int build_report(struct sk_buff *
 	if (addr)
 		RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
 
-	nlh->nlmsg_len = skb->tail - b;
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
 nlmsg_failure:
 rtattr_failure:
-	skb_trim(skb, b - skb->data);
+	nlmsg_trim(skb, b);
 	return -1;
 }
 
@@ -2466,7 +2555,7 @@ static int __init xfrm_user_init(void)
 	printk(KERN_INFO "Initializing XFRM netlink socket\n");
 
 	nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
-				     xfrm_netlink_rcv, THIS_MODULE);
+				     xfrm_netlink_rcv, NULL, THIS_MODULE);
 	if (nlsk == NULL)
 		return -ENOMEM;
 	rcu_assign_pointer(xfrm_nl, nlsk);
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index e2ad2dc..a525112 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -131,13 +131,13 @@ modname = $(basetarget)
 quiet_cmd_cc_s_c = CC $(quiet_modtag)  $@
 cmd_cc_s_c       = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
 
-%.s: %.c FORCE
+$(obj)/%.s: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_s_c)
 
 quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
 cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 
-%.i: %.c FORCE
+$(obj)/%.i: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
 quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
@@ -146,7 +146,7 @@ cmd_cc_symtypes_c	   = \
 		| $(GENKSYMS) -T $@ >/dev/null;				\
 		test -s $@ || rm -f $@
 
-%.symtypes : %.c FORCE
+$(obj)/%.symtypes : $(src)/%.c FORCE
 	$(call if_changed_dep,cc_symtypes_c)
 
 # C (.c) files
@@ -198,14 +198,13 @@ define rule_cc_o_c
 endef
 
 # Built-in and composite module parts
-
-%.o: %.c FORCE
+$(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
 
-$(single-used-m): %.o: %.c FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
 	$(call cmd,force_checksrc)
 	$(call if_changed_rule,cc_o_c)
 	@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
@@ -215,7 +214,7 @@ quiet_cmd_cc_lst_c = MKLST   $@
 		     $(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
 				     System.map $(OBJDUMP) > $@
 
-%.lst: %.c FORCE
+$(obj)/%.lst: $(src)/%.c FORCE
 	$(call if_changed_dep,cc_lst_c)
 
 # Compile assembler sources (.S)
@@ -229,13 +228,13 @@ modkern_aflags := $(AFLAGS_KERNEL)
 quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
 cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
 
-%.s: %.S FORCE
+$(obj)/%.s: $(src)/%.S FORCE
 	$(call if_changed_dep,as_s_S)
 
 quiet_cmd_as_o_S = AS $(quiet_modtag)  $@
 cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
 
-%.o: %.S FORCE
+$(obj)/%.o: $(src)/%.S FORCE
 	$(call if_changed_dep,as_o_S)
 
 targets += $(real-objs-y) $(real-objs-m) $(lib-y)
@@ -246,7 +245,7 @@ # --------------------------------------
 quiet_cmd_cpp_lds_S = LDS     $@
       cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
 
-%.lds: %.lds.S FORCE
+$(obj)/%.lds: $(src)/%.lds.S FORCE
 	$(call if_changed_dep,cpp_lds_S)
 
 # Build the compiled-in targets
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 575afbe..6943a7a 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -114,7 +114,7 @@ # host-csingle -> Executable
 quiet_cmd_host-csingle 	= HOSTCC  $@
       cmd_host-csingle	= $(HOSTCC) $(hostc_flags) -o $@ $< \
 	  	$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-csingle): %: %.c FORCE
+$(host-csingle): $(obj)/%: $(src)/%.c FORCE
 	$(call if_changed_dep,host-csingle)
 
 # Link an executable based on list of .o files, all plain c
@@ -123,14 +123,14 @@ quiet_cmd_host-cmulti	= HOSTLD  $@
       cmd_host-cmulti	= $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
 			  $(addprefix $(obj)/,$($(@F)-objs)) \
 			  $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
+$(host-cmulti): $(obj)/%: $(host-cobjs) $(host-cshlib) FORCE
 	$(call if_changed,host-cmulti)
 
 # Create .o file from a single .c file
 # host-cobjs -> .o
 quiet_cmd_host-cobjs	= HOSTCC  $@
       cmd_host-cobjs	= $(HOSTCC) $(hostc_flags) -c -o $@ $<
-$(host-cobjs): %.o: %.c FORCE
+$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
 	$(call if_changed_dep,host-cobjs)
 
 # Link an executable based on list of .o files, a mixture of .c and .cc
@@ -140,20 +140,20 @@ quiet_cmd_host-cxxmulti	= HOSTLD  $@
 			  $(foreach o,objs cxxobjs,\
 			  $(addprefix $(obj)/,$($(@F)-$(o)))) \
 			  $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cxxmulti): %: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+$(host-cxxmulti): $(obj)/%: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
 	$(call if_changed,host-cxxmulti)
 
 # Create .o file from a single .cc (C++) file
 quiet_cmd_host-cxxobjs	= HOSTCXX $@
       cmd_host-cxxobjs	= $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
-$(host-cxxobjs): %.o: %.cc FORCE
+$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
 	$(call if_changed_dep,host-cxxobjs)
 
 # Compile .c file, create position independent .o file
 # host-cshobjs -> .o
 quiet_cmd_host-cshobjs	= HOSTCC  -fPIC $@
       cmd_host-cshobjs	= $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
-$(host-cshobjs): %.o: %.c FORCE
+$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
 	$(call if_changed_dep,host-cshobjs)
 
 # Link a shared library, based on position independent .o files
@@ -162,7 +162,7 @@ quiet_cmd_host-cshlib	= HOSTLLD -shared 
       cmd_host-cshlib	= $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
 			  $(addprefix $(obj)/,$($(@F:.so=-objs))) \
 			  $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cshlib): %: $(host-cshobjs) FORCE
+$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
 	$(call if_changed,host-cshlib)
 
 targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 65e0a79..d5bbbcc 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -63,16 +63,16 @@ quiet_cmd_modpost = MODPOST $(words $(fi
 	$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
 	$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
 	$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
-	$(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
-	$(wildcard vmlinux) $(filter-out FORCE,$^)
+	$(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 PHONY += __modpost
 __modpost: $(modules:.ko=.o) FORCE
-	$(call cmd,modpost)
+	$(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^)
 
 quiet_cmd_kernel-mod = MODPOST $@
-      cmd_kernel-mod = $(cmd_modpost)
+      cmd_kernel-mod = $(cmd_modpost) $(KBUILD_VMLINUX_OBJS)
 
+PHONY += vmlinux
 vmlinux: FORCE
 	$(call cmd,kernel-mod)
 
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 6bc7e7c..8912c0f 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -249,6 +249,8 @@ void parse_config_file(char *map, size_t
 	found:
 		if (!memcmp(q - 7, "_MODULE", 7))
 			q -= 7;
+		if( (q-p-7) < 0 )
+			continue;
 		use_config(p+7, q-p-7);
 	}
 }
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
new file mode 100755
index 0000000..f98171f
--- /dev/null
+++ b/scripts/checksyscalls.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# Check if current architecture are missing any function calls compared
+# to i386.
+# i386 define a number of legacy system calls that are i386 specific
+# and listed below so they are ignored.
+#
+# Usage:
+# syscallchk gcc gcc-options
+#
+
+ignore_list() {
+cat << EOF
+#include <asm/types.h>
+#include <asm/unistd.h>
+
+/* System calls for 32-bit kernels only */
+#if BITS_PER_LONG == 64
+#define __IGNORE_sendfile64
+#define __IGNORE_ftruncate64
+#define __IGNORE_truncate64
+#define __IGNORE_stat64
+#define __IGNORE_lstat64
+#define __IGNORE_fstat64
+#define __IGNORE_fcntl64
+#define __IGNORE_fadvise64_64
+#define __IGNORE_fstatat64
+#define __IGNORE_fstatfs64
+#define __IGNORE_statfs64
+#endif
+
+/* i386-specific or historical system calls */
+#define __IGNORE_break
+#define __IGNORE_stty
+#define __IGNORE_gtty
+#define __IGNORE_ftime
+#define __IGNORE_prof
+#define __IGNORE_lock
+#define __IGNORE_mpx
+#define __IGNORE_ulimit
+#define __IGNORE_profil
+#define __IGNORE_ioperm
+#define __IGNORE_iopl
+#define __IGNORE_idle
+#define __IGNORE_modify_ldt
+#define __IGNORE_ugetrlimit
+#define __IGNORE_mmap2
+#define __IGNORE_vm86
+#define __IGNORE_vm86old
+#define __IGNORE_set_thread_area
+#define __IGNORE_get_thread_area
+#define __IGNORE_madvise1
+#define __IGNORE_oldstat
+#define __IGNORE_oldfstat
+#define __IGNORE_oldlstat
+#define __IGNORE_oldolduname
+#define __IGNORE_olduname
+#define __IGNORE_umount2
+#define __IGNORE_umount
+#define __IGNORE_waitpid
+#define __IGNORE_stime
+#define __IGNORE_nice
+#define __IGNORE_signal
+#define __IGNORE_sigaction
+#define __IGNORE_sgetmask
+#define __IGNORE_sigsuspend
+#define __IGNORE_sigpending
+#define __IGNORE_ssetmask
+#define __IGNORE_readdir
+#define __IGNORE_socketcall
+#define __IGNORE_ipc
+#define __IGNORE_sigreturn
+#define __IGNORE_sigprocmask
+#define __IGNORE_bdflush
+#define __IGNORE__llseek
+#define __IGNORE__newselect
+#define __IGNORE_create_module
+#define __IGNORE_delete_module
+#define __IGNORE_query_module
+#define __IGNORE_get_kernel_syms
+/* ... including the "new" 32-bit uid syscalls */
+#define __IGNORE_lchown32
+#define __IGNORE_getuid32
+#define __IGNORE_getgid32
+#define __IGNORE_geteuid32
+#define __IGNORE_getegid32
+#define __IGNORE_setreuid32
+#define __IGNORE_setregid32
+#define __IGNORE_getgroups32
+#define __IGNORE_setgroups32
+#define __IGNORE_fchown32
+#define __IGNORE_setresuid32
+#define __IGNORE_getresuid32
+#define __IGNORE_setresgid32
+#define __IGNORE_getresgid32
+#define __IGNORE_chown32
+#define __IGNORE_setuid32
+#define __IGNORE_setgid32
+#define __IGNORE_setfsuid32
+#define __IGNORE_setfsgid32
+
+/* Unmerged syscalls for AFS, STREAMS, etc. */
+#define __IGNORE_afs_syscall
+#define __IGNORE_getpmsg
+#define __IGNORE_putpmsg
+#define __IGNORE_vserver
+EOF
+}
+
+syscall_list() {
+sed -n -e '/^\#define/ { s/[^_]*__NR_\([^[:space:]]*\).*/\
+\#if !defined \(__NR_\1\) \&\& !defined \(__IGNORE_\1\)\
+\#warning syscall \1 not implemented\
+\#endif/p }' $1
+}
+
+(ignore_list && syscall_list ${srctree}/include/asm-i386/unistd.h) | \
+$* -E -x c - > /dev/null
diff --git a/scripts/cleanfile b/scripts/cleanfile
new file mode 100755
index 0000000..f1ba8aa
--- /dev/null
+++ b/scripts/cleanfile
@@ -0,0 +1,126 @@
+#!/usr/bin/perl -w
+#
+# Clean a text file -- or directory of text files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation.  Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+#
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($lo) = '';
+    my $pos = 0;
+    my $nsp = 0;
+    my($i, $c);
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li, $i, 1);
+	if ($c eq "\t") {
+	    my $npos = ($pos+$nsp+8) & ~7;
+	    my $ntab = ($npos >> 3) - ($pos >> 3);
+	    $lo .= "\t" x $ntab;
+	    $pos = $npos;
+	    $nsp = 0;
+	} elsif ($c eq "\n" || $c eq "\r") {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos = 0;
+	} elsif ($c eq " ") {
+	    $nsp++;
+	} else {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos++;
+	}
+    }
+    $lo .= " " x $nsp;
+    return $lo;
+}
+
+$name = basename($0);
+
+foreach $f ( @ARGV ) {
+    print STDERR "$name: $f\n";
+
+    if (! -f $f) {
+	print STDERR "$f: not a file\n";
+	next;
+    }
+
+    if (!open(FILE, '+<', $f)) {
+	print STDERR "$name: Cannot open file: $f: $!\n";
+	next;
+    }
+
+    binmode FILE;
+
+    # First, verify that it is not a binary file; consider any file
+    # with a zero byte to be a binary file.  Is there any better, or
+    # additional, heuristic that should be applied?
+    $is_binary = 0;
+
+    while (read(FILE, $data, 65536) > 0) {
+	if ($data =~ /\0/) {
+	    $is_binary = 1;
+	    last;
+	}
+    }
+
+    if ($is_binary) {
+	print STDERR "$name: $f: binary file\n";
+	next;
+    }
+
+    seek(FILE, 0, 0);
+
+    $in_bytes = 0;
+    $out_bytes = 0;
+    $blank_bytes = 0;
+
+    @blanks = ();
+    @lines  = ();
+
+    while ( defined($line = <FILE>) ) {
+	$in_bytes += length($line);
+	$line =~ s/[ \t\r]*$//;		# Remove trailing spaces
+	$line = clean_space_tabs($line);
+
+	if ( $line eq "\n" ) {
+	    push(@blanks, $line);
+	    $blank_bytes += length($line);
+	} else {
+	    push(@lines, @blanks);
+	    $out_bytes += $blank_bytes;
+	    push(@lines, $line);
+	    $out_bytes += length($line);
+	    @blanks = ();
+	    $blank_bytes = 0;
+	}
+    }
+
+    # Any blanks at the end of the file are discarded
+
+    if ($in_bytes != $out_bytes) {
+	# Only write to the file if changed
+	seek(FILE, 0, 0);
+	print FILE @lines;
+
+	if ( !defined($where = tell(FILE)) ||
+	     !truncate(FILE, $where) ) {
+	    die "$name: Failed to truncate modified file: $f: $!\n";
+	}
+    }
+
+    close(FILE);
+}
diff --git a/scripts/cleanpatch b/scripts/cleanpatch
new file mode 100755
index 0000000..a53f987
--- /dev/null
+++ b/scripts/cleanpatch
@@ -0,0 +1,206 @@
+#!/usr/bin/perl -w
+#
+# Clean a patch file -- or directory of patch files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation.  Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+#
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+    no bytes;			# Tab alignment depends on characters
+
+    my($li) = @_;
+    my($lo) = '';
+    my $pos = 0;
+    my $nsp = 0;
+    my($i, $c);
+
+    for ($i = 0; $i < length($li); $i++) {
+	$c = substr($li, $i, 1);
+	if ($c eq "\t") {
+	    my $npos = ($pos+$nsp+8) & ~7;
+	    my $ntab = ($npos >> 3) - ($pos >> 3);
+	    $lo .= "\t" x $ntab;
+	    $pos = $npos;
+	    $nsp = 0;
+	} elsif ($c eq "\n" || $c eq "\r") {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos = 0;
+	} elsif ($c eq " ") {
+	    $nsp++;
+	} else {
+	    $lo .= " " x $nsp;
+	    $pos += $nsp;
+	    $nsp = 0;
+	    $lo .= $c;
+	    $pos++;
+	}
+    }
+    $lo .= " " x $nsp;
+    return $lo;
+}
+
+$name = basename($0);
+
+foreach $f ( @ARGV ) {
+    print STDERR "$name: $f\n";
+
+    if (! -f $f) {
+	print STDERR "$f: not a file\n";
+	next;
+    }
+
+    if (!open(FILE, '+<', $f)) {
+	print STDERR "$name: Cannot open file: $f: $!\n";
+	next;
+    }
+
+    binmode FILE;
+
+    # First, verify that it is not a binary file; consider any file
+    # with a zero byte to be a binary file.  Is there any better, or
+    # additional, heuristic that should be applied?
+    $is_binary = 0;
+
+    while (read(FILE, $data, 65536) > 0) {
+	if ($data =~ /\0/) {
+	    $is_binary = 1;
+	    last;
+	}
+    }
+
+    if ($is_binary) {
+	print STDERR "$name: $f: binary file\n";
+	next;
+    }
+
+    seek(FILE, 0, 0);
+
+    $in_bytes = 0;
+    $out_bytes = 0;
+
+    @lines  = ();
+
+    $in_hunk = 0;
+    $err = 0;
+
+    while ( defined($line = <FILE>) ) {
+	$in_bytes += length($line);
+
+	if (!$in_hunk) {
+	    if ($line =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+		$minus_lines = $2;
+		$plus_lines = $4;
+		if ($minus_lines || $plus_lines) {
+		    $in_hunk = 1;
+		    @hunk_lines = ($line);
+		}
+	    } else {
+		push(@lines, $line);
+		$out_bytes += length($line);
+	    }
+	} else {
+	    # We're in a hunk
+
+	    if ($line =~ /^\+/) {
+		$plus_lines--;
+
+		$text = substr($line, 1);
+		$text =~ s/[ \t\r]*$//;		# Remove trailing spaces
+		$text = clean_space_tabs($text);
+
+		push(@hunk_lines, '+'.$text);
+	    } elsif ($line =~ /^\-/) {
+		$minus_lines--;
+		push(@hunk_lines, $line);
+	    } elsif ($line =~ /^ /) {
+		$plus_lines--;
+		$minus_lines--;
+		push(@hunk_lines, $line);
+	    } else {
+		print STDERR "$name: $f: malformed patch\n";
+		$err = 1;
+		last;
+	    }
+
+	    if ($plus_lines < 0 || $minus_lines < 0) {
+		print STDERR "$name: $f: malformed patch\n";
+		$err = 1;
+		last;
+	    } elsif ($plus_lines == 0 && $minus_lines == 0) {
+		# End of a hunk.  Process this hunk.
+		my $i;
+		my $l;
+		my @h = ();
+		my $adj = 0;
+		my $done = 0;
+
+		for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
+		    $l = $hunk_lines[$i];
+		    if (!$done && $l eq "+\n") {
+			$adj++; # Skip this line
+		    } elsif ($l =~ /^[ +]/) {
+			$done = 1;
+			unshift(@h, $l);
+		    } else {
+			unshift(@h, $l);
+		    }
+		}
+
+		$l = $hunk_lines[0];  # Hunk header
+		undef @hunk_lines;    # Free memory
+
+		if ($adj) {
+		    die unless
+			($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
+		    my $mstart = $1;
+		    my $mlin = $2;
+		    my $pstart = $3;
+		    my $plin = $4;
+		    my $tail = $5; # doesn't include the final newline
+
+		    $l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
+				 $mstart, $mlin, $pstart, $plin-$adj,
+				 $tail);
+		}
+		unshift(@h, $l);
+
+		# Transfer to the output array
+		foreach $l (@h) {
+		    $out_bytes += length($l);
+		    push(@lines, $l);
+		}
+
+		$in_hunk = 0;
+	    }
+	}
+    }
+
+    if ($in_hunk) {
+	print STDERR "$name: $f: malformed patch\n";
+	$err = 1;
+    }
+
+    if (!$err) {
+	if ($in_bytes != $out_bytes) {
+	    # Only write to the file if changed
+	    seek(FILE, 0, 0);
+	    print FILE @lines;
+
+	    if ( !defined($where = tell(FILE)) ||
+		 !truncate(FILE, $where) ) {
+		die "$name: Failed to truncate modified file: $f: $!\n";
+	    }
+	}
+    }
+
+    close(FILE);
+}
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 43f75d6..683eb12 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -171,7 +171,7 @@ dir_filelist() {
 	${dep_list}header "$1"
 
 	srcdir=$(echo "$1" | sed -e 's://*:/:g')
-	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null)
+	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n")
 
 	# If $dirlist is only one line, then the directory is empty
 	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
@@ -191,9 +191,10 @@ input_file() {
 	source="$1"
 	if [ -f "$1" ]; then
 		${dep_list}header "$1"
-		is_cpio="$(echo "$1" | sed 's/^.*\.cpio/cpio/')"
+		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
 		if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then
 			cpio_file=$1
+			echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
 			[ ! -z ${dep_list} ] && echo "$1"
 			return 0
 		fi
@@ -223,6 +224,7 @@ cpio_file=
 cpio_list=
 output="/dev/stdout"
 output_file=""
+is_cpio_compressed=
 
 arg="$1"
 case "$arg" in
@@ -282,7 +284,11 @@ if [ ! -z ${output_file} ]; then
 		cpio_tfile=${cpio_file}
 	fi
 	rm ${cpio_list}
-	cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+	if [ "${is_cpio_compressed}" = "compressed" ]; then
+		cat ${cpio_tfile} > ${output_file}
+	else
+		cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+	fi
 	[ -z ${cpio_file} ] && rm ${cpio_tfile}
 fi
 exit 0
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index b038182..511023b 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -516,7 +516,8 @@ #endif				/* __GNU_LIBRARY__ */
 			genksyms_usage();
 			return 1;
 		}
-	if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0))
+	if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0)
+	    || (strcmp(arch, "blackfin") == 0))
 		mod_prefix = "_";
 	{
 		extern int yydebug;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 7e7e147..fb2bb30 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -140,6 +140,7 @@ endif
 
 clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
 		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
+clean-files     += mconf qconf gconf
 
 # Needed for systems without gettext
 KBUILD_HAVE_NLS := $(shell \
@@ -183,8 +184,8 @@ # QT needs some extra effort...
 	  done; \
 	  if [ -z "$$dir" ]; then \
 	    echo "*"; \
-	    echo "* Unable to find the QT installation. Please make sure that"; \
-	    echo "* the QT development package is correctly installed and"; \
+	    echo "* Unable to find the QT3 installation. Please make sure that"; \
+	    echo "* the QT3 development package is correctly installed and"; \
 	    echo "* either install pkg-config or set the QTDIR environment"; \
 	    echo "* variable to the correct location."; \
 	    echo "*"; \
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 124b341..1199baf 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -558,6 +558,7 @@ int main(int ac, char **av)
 		if (stat(".config", &tmpstat)) {
 			printf(_("***\n"
 				"*** You have not yet configured your kernel!\n"
+				"*** (missing kernel .config file)\n"
 				"***\n"
 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 				"*** \"make menuconfig\" or \"make xconfig\").\n"
diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
index 800f8c7..0fdc904 100644
--- a/scripts/kconfig/lex.zconf.c_shipped
+++ b/scripts/kconfig/lex.zconf.c_shipped
@@ -2264,7 +2264,7 @@ FILE *zconf_fopen(const char *name)
 	FILE *f;
 
 	f = fopen(name, "r");
-	if (!f && name[0] != '/') {
+	if (!f && name != NULL && name[0] != '/') {
 		env = getenv(SRCTREE);
 		if (env) {
 			sprintf(fullname, "%s/%s", env, name);
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 9b2706a..8a07ee4 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -64,6 +64,7 @@ int zconf_lineno(void);
 char *zconf_curname(void);
 
 /* confdata.c */
+const char *conf_get_configname(void);
 char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index fd695e1..7e17eba 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -188,6 +188,7 @@ int on_key_esc(WINDOW *win);
 int on_key_resize(void);
 
 void init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
 void reset_dialog(void);
 void end_dialog(void);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index d54440f..a1bddef 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -272,6 +272,11 @@ void init_dialog(const char *backtitle)
 	color_setup(getenv("MENUCONFIG_COLOR"));
 }
 
+void set_dialog_backtitle(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+}
+
 void reset_dialog(void)
 {
 	initscr();		/* Init curses */
@@ -336,7 +341,7 @@ void print_autowrap(WINDOW * win, const 
 		newl = 1;
 		word = tempstr;
 		while (word && *word) {
-			sp = index(word, ' ');
+			sp = strchr(word, ' ');
 			if (sp)
 				*sp++ = 0;
 
@@ -348,7 +353,7 @@ void print_autowrap(WINDOW * win, const 
 			if (wlen > room ||
 			    (newl && wlen < 4 && sp
 			     && wlen + 1 + strlen(sp) > room
-			     && (!(sp2 = index(sp, ' '))
+			     && (!(sp2 = strchr(sp, ' '))
 				 || wlen + 1 + (sp2 - sp) > room))) {
 				cur_y++;
 				cur_x = x;
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 3f9a132..d0e4fa5 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -26,7 +26,6 @@ #define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lxdialog/dialog.h"
 
-static char menu_backtitle[128];
 static const char mconf_readme[] = N_(
 "Overview\n"
 "--------\n"
@@ -271,7 +270,6 @@ search_help[] = N_(
 	"          USB$ => find all CONFIG_ symbols ending with USB\n"
 	"\n");
 
-static char filename[PATH_MAX+1] = ".config";
 static int indent;
 static struct termios ios_org;
 static int rows = 0, cols = 0;
@@ -395,6 +393,28 @@ static struct gstr get_relations_str(str
 	return res;
 }
 
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+	static char menu_backtitle[PATH_MAX+128];
+	int size;
+	struct symbol *sym;
+
+	sym = sym_lookup("KERNELVERSION", 0);
+	sym_calc_value(sym);
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+	                _("%s - Linux Kernel v%s Configuration"),
+		        config_filename, sym_get_string_value(sym));
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+	set_dialog_backtitle(menu_backtitle);
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+}
+
+
 static void search_conf(void)
 {
 	struct symbol **sym_arr;
@@ -816,8 +836,10 @@ static void conf_load(void)
 		case 0:
 			if (!dialog_input_result[0])
 				return;
-			if (!conf_read(dialog_input_result))
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
 				return;
+			}
 			show_textbox(NULL, _("File does not exist!"), 5, 38);
 			break;
 		case 1:
@@ -840,8 +862,10 @@ static void conf_save(void)
 		case 0:
 			if (!dialog_input_result[0])
 				return;
-			if (!conf_write(dialog_input_result))
+			if (!conf_write(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
 				return;
+			}
 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 			break;
 		case 1:
@@ -860,7 +884,6 @@ static void conf_cleanup(void)
 
 int main(int ac, char **av)
 {
-	struct symbol *sym;
 	char *mode;
 	int res;
 
@@ -871,11 +894,6 @@ int main(int ac, char **av)
 	conf_parse(av[1]);
 	conf_read(NULL);
 
-	sym = sym_lookup("KERNELVERSION", 0);
-	sym_calc_value(sym);
-	sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
-		sym_get_string_value(sym));
-
 	mode = getenv("MENUCONFIG_MODE");
 	if (mode) {
 		if (!strcasecmp(mode, "single_menu"))
@@ -886,7 +904,8 @@ int main(int ac, char **av)
 	atexit(conf_cleanup);
 	init_wsize();
 	reset_dialog();
-	init_dialog(menu_backtitle);
+	init_dialog(NULL);
+	set_config_filename(conf_get_configname());
 	do {
 		conf(&rootmenu);
 		dialog_clear();
@@ -903,7 +922,7 @@ int main(int ac, char **av)
 
 	switch (res) {
 	case 0:
-		if (conf_write(NULL)) {
+		if (conf_write(filename)) {
 			fprintf(stderr, _("\n\n"
 				"Error during writing of the kernel configuration.\n"
 				"Your kernel configuration changes were NOT saved."
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index c86c27f..f14aeac 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -203,7 +203,7 @@ void sym_check_prop(struct symbol *sym)
 			else if (sym2->type == S_UNKNOWN)
 				prop_warn(prop,
 				    "'select' used by config symbol '%s' "
-				    "refer to undefined symbol '%s'",
+				    "refers to undefined symbol '%s'",
 				    sym->name, sym2->name);
 			else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
 				prop_warn(prop,
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 512c2f5..f2a23a9 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1182,7 +1182,7 @@ void ConfigInfoView::contentsContextMenu
 	Parent::contentsContextMenuEvent(e);
 }
 
-ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
 	: Parent(parent, name), result(NULL)
 {
 	setCaption("Search Config");
@@ -1206,6 +1206,9 @@ ConfigSearchWindow::ConfigSearchWindow(Q
 	info = new ConfigInfoView(split, name);
 	connect(list->list, SIGNAL(menuChanged(struct menu *)),
 		info, SLOT(setInfo(struct menu *)));
+	connect(list->list, SIGNAL(menuChanged(struct menu *)),
+		parent, SLOT(setMenuLink(struct menu *)));
+
 	layout1->addWidget(split);
 
 	if (name) {
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 6fc1c5f..b3b5657 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -279,7 +279,7 @@ class ConfigSearchWindow : public QDialo
 	Q_OBJECT
 	typedef class QDialog Parent;
 public:
-	ConfigSearchWindow(QWidget* parent, const char *name = 0);
+	ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
 
 public slots:
 	void saveSettings(void);
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 8f06c47..c35dcc5 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -786,13 +786,15 @@ static struct symbol *sym_check_expr_dep
 	return NULL;
 }
 
+/* return NULL when dependencies are OK */
 struct symbol *sym_check_deps(struct symbol *sym)
 {
 	struct symbol *sym2;
 	struct property *prop;
 
 	if (sym->flags & SYMBOL_CHECK) {
-		printf("Warning! Found recursive dependency: %s", sym->name);
+		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
+		        sym->prop->file->name, sym->prop->lineno, sym->name);
 		return sym;
 	}
 	if (sym->flags & SYMBOL_CHECKED)
@@ -816,13 +818,8 @@ struct symbol *sym_check_deps(struct sym
 			goto out;
 	}
 out:
-	if (sym2) {
-		printf(" %s", sym->name);
-		if (sym2 == sym) {
-			printf("\n");
-			sym2 = NULL;
-		}
-	}
+	if (sym2)
+		fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
 	sym->flags &= ~SYMBOL_CHECK;
 	return sym2;
 }
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index cfa4607..187d38c 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -265,7 +265,7 @@ FILE *zconf_fopen(const char *name)
 	FILE *f;
 
 	f = fopen(name, "r");
-	if (!f && name[0] != '/') {
+	if (!f && name != NULL && name[0] != '/') {
 		env = getenv(SRCTREE);
 		if (env) {
 			sprintf(fullname, "%s/%s", env, name);
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index d777fe8..9a06b67 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -2132,9 +2132,11 @@ #endif
 	}
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
-		sym_check_deps(sym);
+		if (sym_check_deps(sym))
+			zconfnerrs++;
         }
-
+	if (zconfnerrs)
+		exit(1);
 	sym_set_change_count(1);
 }
 
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 04a5864..92eb02b 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -501,9 +501,11 @@ #endif
 	}
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
-		sym_check_deps(sym);
+		if (sym_check_deps(sym))
+			zconfnerrs++;
         }
-
+	if (zconfnerrs)
+		exit(1);
 	sym_set_change_count(1);
 }
 
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 8be269f..a325a0c 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -159,7 +159,8 @@ # match expressions used to find embedde
 my $type_constant = '\%([-_\w]+)';
 my $type_func = '(\w+)\(\)';
 my $type_param = '\@(\w+)';
-my $type_struct = '\&((struct\s*)?[_\w]+)';
+my $type_struct = '\&((struct\s*)*[_\w]+)';
+my $type_struct_xml = '\\\amp;((struct\s*)*[_\w]+)';
 my $type_env = '(\$\w+)';
 
 # Output conversion substitutions.
@@ -168,7 +169,8 @@ #  One for each output format
 # these work fairly well
 my %highlights_html = ( $type_constant, "<i>\$1</i>",
 			$type_func, "<b>\$1</b>",
-			$type_struct, "<i>\$1</i>",
+			$type_struct_xml, "<i>\$1</i>",
+			$type_env, "<b><i>\$1</i></b>",
 			$type_param, "<tt><b>\$1</b></tt>" );
 my $blankline_html = "<p>";
 
@@ -326,12 +328,21 @@ while ($ARGV[0] =~ m/^-(.*)/) {
     }
 }
 
+# get kernel version from env
+sub get_kernel_version() {
+    my $version;
+
+    if (defined($ENV{'KERNELVERSION'})) {
+	$version = $ENV{'KERNELVERSION'};
+    }
+    return $version;
+}
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
 my $dohighlight = "";
 foreach my $pattern (keys %highlights) {
-#    print "scanning pattern $pattern ($highlights{$pattern})\n";
+#   print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n";
     $dohighlight .=  "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
 }
 
@@ -378,13 +389,19 @@ #	use Carp;
 #	confess "output_highlight got called with no args?\n";
 #   }
 
+#   print STDERR "contents b4:$contents\n";
     eval $dohighlight;
     die $@ if $@;
+    if ($output_mode eq "html") {
+	$contents =~ s/\\\\//;
+    }
+#   print STDERR "contents af:$contents\n";
+
     foreach $line (split "\n", $contents) {
-      if ($line eq ""){
+	if ($line eq ""){
 	    print $lineprefix, $blankline;
 	} else {
-            $line =~ s/\\\\\\/\&/g;
+	    $line =~ s/\\\\\\/\&/g;
 	    print $lineprefix, $line;
 	}
 	print "\n";
@@ -414,7 +431,7 @@ sub output_enum_html(%) {
     print "<b>enum ".$args{'enum'}."</b> {<br>\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-        print " <b>".$parameter."</b>";
+	print " <b>".$parameter."</b>";
 	if ($count != $#{$args{'parameterlist'}}) {
 	    $count++;
 	    print ",\n";
@@ -462,15 +479,16 @@ sub output_struct_html(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	$type = $args{'parametertypes'}{$parameter};
 	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
 	    # pointer-to-function
-	    print " <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
+	    print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
 	} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-	    print " <i>$1</i> <b>$parameter</b>$2;<br>\n";
+	    # bitfield
+	    print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
 	} else {
-	    print " <i>$type</i> <b>$parameter</b>;<br>\n";
+	    print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
 	}
     }
     print "};<br>\n";
@@ -483,7 +501,7 @@ sub output_struct_html(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	print "<dt><b>".$parameter."</b>\n";
 	print "<dd>";
 	output_highlight($args{'parameterdescs'}{$parameter_name});
@@ -525,7 +543,7 @@ sub output_function_html(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	print "<dt><b>".$parameter."</b>\n";
 	print "<dd>";
 	output_highlight($args{'parameterdescs'}{$parameter_name});
@@ -592,6 +610,7 @@ sub output_function_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'function'}."</refname>\n";
@@ -668,6 +687,7 @@ sub output_struct_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
@@ -691,7 +711,7 @@ sub output_struct_xml(%) {
 	$parameter_name =~ s/\[.*//;
 
 	defined($args{'parameterdescs'}{$parameter_name}) || next;
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	$type = $args{'parametertypes'}{$parameter};
 	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
 	    # pointer-to-function
@@ -752,6 +772,7 @@ sub output_enum_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
+    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>enum ".$args{'enum'}."</refname>\n";
@@ -767,11 +788,11 @@ sub output_enum_xml(%) {
     print "enum ".$args{'enum'}." {\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-        print "  $parameter";
-        if ($count != $#{$args{'parameterlist'}}) {
+	print "  $parameter";
+	if ($count != $#{$args{'parameterlist'}}) {
 	    $count++;
 	    print ",";
-        }
+	}
 	print "\n";
     }
     print "};";
@@ -1007,7 +1028,7 @@ sub output_enum_man(%) {
     print "enum ".$args{'enum'}." {\n";
     $count = 0;
     foreach my $parameter (@{$args{'parameterlist'}}) {
-        print ".br\n.BI \"    $parameter\"\n";
+	print ".br\n.BI \"    $parameter\"\n";
 	if ($count == $#{$args{'parameterlist'}}) {
 	    print "\n};\n";
 	    last;
@@ -1054,7 +1075,7 @@ sub output_struct_man(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	$type = $args{'parametertypes'}{$parameter};
 	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
 	    # pointer-to-function
@@ -1077,7 +1098,7 @@ sub output_struct_man(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	print ".IP \"".$parameter."\" 12\n";
 	output_highlight($args{'parameterdescs'}{$parameter_name});
     }
@@ -1187,7 +1208,7 @@ sub output_enum_text(%) {
     print "enum ".$args{'enum'}." {\n";
     $count = 0;
     foreach $parameter (@{$args{'parameterlist'}}) {
-        print "\t$parameter";
+	print "\t$parameter";
 	if ($count != $#{$args{'parameterlist'}}) {
 	    $count++;
 	    print ",";
@@ -1232,7 +1253,7 @@ sub output_struct_text(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	$type = $args{'parametertypes'}{$parameter};
 	if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
 	    # pointer-to-function
@@ -1252,7 +1273,7 @@ sub output_struct_text(%) {
 	my $parameter_name = $parameter;
 	$parameter_name =~ s/\[.*//;
 
-        ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+	($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
 	print "$parameter\n\t";
 	print $args{'parameterdescs'}{$parameter_name}."\n";
     }
@@ -1284,7 +1305,7 @@ sub output_declaration {
 	( $function_only == 1 && defined($function_table{$name})) ||
 	( $function_only == 2 && !defined($function_table{$name})))
     {
-        &$func(@_);
+	&$func(@_);
 	$section_counter++;
     }
 }
@@ -1317,8 +1338,8 @@ sub dump_struct($$) {
     my $file = shift;
 
     if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) {
-        $declaration_name = $2;
-        my $members = $3;
+	$declaration_name = $2;
+	my $members = $3;
 
 	# ignore embedded structs or unions
 	$members =~ s/{.*?}//g;
@@ -1345,7 +1366,7 @@ sub dump_struct($$) {
 			   });
     }
     else {
-        print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
+	print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
 	++$errors;
     }
 }
@@ -1356,15 +1377,15 @@ sub dump_enum($$) {
 
     $x =~ s@/\*.*?\*/@@gos;	# strip comments.
     if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
-        $declaration_name = $1;
-        my $members = $2;
+	$declaration_name = $1;
+	my $members = $2;
 
 	foreach my $arg (split ',', $members) {
 	    $arg =~ s/^\s*(\w+).*/$1/;
 	    push @parameterlist, $arg;
 	    if (!$parameterdescs{$arg}) {
-	        $parameterdescs{$arg} = $undescribed;
-	        print STDERR "Warning(${file}:$.): Enum value '$arg' ".
+		$parameterdescs{$arg} = $undescribed;
+		print STDERR "Warning(${file}:$.): Enum value '$arg' ".
 		    "not described in enum '$declaration_name'\n";
 	    }
 
@@ -1382,7 +1403,7 @@ sub dump_enum($$) {
 			   });
     }
     else {
-        print STDERR "Error(${file}:$.): Cannot parse enum!\n";
+	print STDERR "Error(${file}:$.): Cannot parse enum!\n";
 	++$errors;
     }
 }
@@ -1393,12 +1414,12 @@ sub dump_typedef($$) {
 
     $x =~ s@/\*.*?\*/@@gos;	# strip comments.
     while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
-        $x =~ s/\(*.\)\s*;$/;/;
+	$x =~ s/\(*.\)\s*;$/;/;
 	$x =~ s/\[*.\]\s*;$/;/;
     }
 
     if ($x =~ /typedef.*\s+(\w+)\s*;/) {
-        $declaration_name = $1;
+	$declaration_name = $1;
 
 	output_declaration($declaration_name,
 			   'typedef',
@@ -1410,7 +1431,7 @@ sub dump_typedef($$) {
 			   });
     }
     else {
-        print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
+	print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
 	++$errors;
     }
 }
@@ -1424,14 +1445,14 @@ sub create_parameterlist($$$) {
 
     # temporarily replace commas inside function pointer definition
     while ($args =~ /(\([^\),]+),/) {
-        $args =~ s/(\([^\),]+),/$1#/g;
+	$args =~ s/(\([^\),]+),/$1#/g;
     }
 
     foreach my $arg (split($splitter, $args)) {
 	# strip comments
 	$arg =~ s/\/\*.*\*\///;
-        # strip leading/trailing spaces
-        $arg =~ s/^\s*//;
+	# strip leading/trailing spaces
+	$arg =~ s/^\s*//;
 	$arg =~ s/\s*$//;
 	$arg =~ s/\s+/ /;
 
@@ -1456,7 +1477,16 @@ sub create_parameterlist($$$) {
 	    if ($args[0] =~ m/\*/) {
 		$args[0] =~ s/(\*+)\s*/ $1/;
 	    }
-	    my @first_arg = split('\s+', shift @args);
+
+	    my @first_arg;
+	    if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) {
+		    shift @args;
+		    push(@first_arg, split('\s+', $1));
+		    push(@first_arg, $2);
+	    } else {
+		    @first_arg = split('\s+', shift @args);
+	    }
+
 	    unshift(@args, pop @first_arg);
 	    $type = join " ", @first_arg;
 
@@ -1514,15 +1544,15 @@ sub push_parameter($$$) {
 	    $parameterdescs{$param_name} = $undescribed;
 
 	    if (($type eq 'function') || ($type eq 'enum')) {
-	        print STDERR "Warning(${file}:$.): Function parameter ".
+		print STDERR "Warning(${file}:$.): Function parameter ".
 		    "or member '$param' not " .
 		    "described in '$declaration_name'\n";
 	    }
 	    print STDERR "Warning(${file}:$.):".
-	                 " No description found for parameter '$param'\n";
+			 " No description found for parameter '$param'\n";
 	    ++$warnings;
-        }
-        }
+	}
+	}
 
 	push @parameterlist, $param;
 	$parametertypes{$param} = $type;
@@ -1664,10 +1694,10 @@ sub process_state3_function($$) {
 	# do nothing
     }
     elsif ($x =~ /([^\{]*)/) {
-        $prototype .= $1;
+	$prototype .= $1;
     }
     if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) {
-        $prototype =~ s@/\*.*?\*/@@gos;	# strip comments.
+	$prototype =~ s@/\*.*?\*/@@gos;	# strip comments.
 	$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
 	$prototype =~ s@^\s+@@gos; # strip leading spaces
 	dump_function($prototype,$file);
@@ -1688,17 +1718,17 @@ sub process_state3_type($$) {
     }
 
     while (1) {
-        if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+	if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
 	    $prototype .= $1 . $2;
 	    ($2 eq '{') && $brcount++;
 	    ($2 eq '}') && $brcount--;
 	    if (($2 eq ';') && ($brcount == 0)) {
-	        dump_declaration($prototype,$file);
+		dump_declaration($prototype,$file);
 		reset_state();
-	        last;
+		last;
 	    }
 	    $x = $3;
-        } else {
+	} else {
 	    $prototype .= $x;
 	    last;
 	}
@@ -1756,7 +1786,7 @@ sub process_file($) {
 		} else {
 			$section = $1;
 		}
-            }
+	    }
 	    elsif (/$doc_decl/o) {
 		$identifier = $1;
 		if (/\s*([\w\s]+?)\s*-/) {
@@ -1849,13 +1879,13 @@ #		print STDERR "end of doc comment, loo
 	    }
 	} elsif ($state == 3) {	# scanning for function '{' (end of prototype)
 	    if ($decl_type eq 'function') {
-	        process_state3_function($_, $file);
+		process_state3_function($_, $file);
 	    } else {
-	        process_state3_type($_, $file);
+		process_state3_type($_, $file);
 	    }
 	} elsif ($state == 4) {
 		# Documentation block
-	        if (/$doc_block/) {
+		if (/$doc_block/) {
 			dump_section($section, $contents);
 			output_intro({'sectionlist' => \@sectionlist,
 				      'sections' => \%sections });
@@ -1873,7 +1903,7 @@ #		print STDERR "end of doc comment, loo
 			} else {
 				$section = $1;
 			}
-                }
+		}
 		elsif (/$doc_end/)
 		{
 			dump_section($section, $contents);
@@ -1900,8 +1930,8 @@ #		print STDERR "end of doc comment, loo
 			{
 				$contents .= $1 . "\n";
 			}
-        	}
-          }
+		}
+	}
     }
     if ($initial_section_counter == $section_counter) {
 	print STDERR "Warning(${file}): no structured comments found\n";
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 82d0af4..a8740df 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -18,19 +18,32 @@ fi
 # Do not expand names
 set -f
 
-if [ -r .version ]; then
-  VERSION=`cat .version`
+# Fix the language to get consistent output
+LC_ALL=C
+export LC_ALL
+
+if [ -z "$KBUILD_BUILD_VERSION" ]; then
+	if [ -r .version ]; then
+		VERSION=`cat .version`
+	else
+		VERSION=0
+		echo 0 > .version
+	fi
 else
-  VERSION=0
-  echo 0 > .version
+	VERSION=$KBUILD_BUILD_VERSION
 fi
 
+if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
+	TIMESTAMP=`date`
+else
+	TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
+fi
 
 UTS_VERSION="#$VERSION"
 CONFIG_FLAGS=""
 if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
 if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
-UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`"
+UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP"
 
 # Truncate to maximum length
 
@@ -46,7 +59,7 @@ ( echo /\* This file is auto generated, 
 
   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
 
-  echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+  echo \#define LINUX_COMPILE_TIME \"`date +%T`\"
   echo \#define LINUX_COMPILE_BY \"`whoami`\"
   echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
 
@@ -58,7 +71,7 @@ ( echo /\* This file is auto generated, 
     echo \#define LINUX_COMPILE_DOMAIN
   fi
 
-  echo \#define LINUX_COMPILER \"`LC_ALL=C LANG=C $CC -v 2>&1 | tail -n 1`\"
+  echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
 ) > .tmpcompile
 
 # Only replace the real compile.h if the new one is different,
diff --git a/scripts/mkuboot.sh b/scripts/mkuboot.sh
index 4b06c5e..2e3d3cd 100755
--- a/scripts/mkuboot.sh
+++ b/scripts/mkuboot.sh
@@ -4,7 +4,7 @@ #
 # Build U-Boot image when `mkimage' tool is available.
 #
 
-MKIMAGE=$(type -path ${CROSS_COMPILE}mkimage)
+MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage")
 
 if [ -z "${MKIMAGE}" ]; then
 	MKIMAGE=$(type -path mkimage)
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index b2f73ff..ed1244d 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -37,7 +37,6 @@ typedef unsigned char	__u8;
  * even potentially has different endianness and word sizes, since
  * we handle those differences explicitly below */
 #include "../../include/linux/mod_devicetable.h"
-#include "../../include/linux/input.h"
 
 #define ADD(str, sep, cond, field)                              \
 do {                                                            \
@@ -416,31 +415,33 @@ static int do_input_entry(const char *fi
 
 	sprintf(alias + strlen(alias), "-e*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT)
-		do_input(alias, id->evbit, 0, EV_MAX);
+		do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX);
 	sprintf(alias + strlen(alias), "k*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
-		do_input(alias, id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
+		do_input(alias, id->keybit,
+			 INPUT_DEVICE_ID_KEY_MIN_INTERESTING,
+			 INPUT_DEVICE_ID_KEY_MAX);
 	sprintf(alias + strlen(alias), "r*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT)
-		do_input(alias, id->relbit, 0, REL_MAX);
+		do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX);
 	sprintf(alias + strlen(alias), "a*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
-		do_input(alias, id->absbit, 0, ABS_MAX);
+		do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
 	sprintf(alias + strlen(alias), "m*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT)
-		do_input(alias, id->mscbit, 0, MSC_MAX);
+		do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
 	sprintf(alias + strlen(alias), "l*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
-		do_input(alias, id->ledbit, 0, LED_MAX);
+		do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
 	sprintf(alias + strlen(alias), "s*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
-		do_input(alias, id->sndbit, 0, SND_MAX);
+		do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
 	sprintf(alias + strlen(alias), "f*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT)
-		do_input(alias, id->ffbit, 0, FF_MAX);
+		do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
 	sprintf(alias + strlen(alias), "w*");
 	if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT)
-		do_input(alias, id->swbit, 0, SW_MAX);
+		do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX);
 	return 1;
 }
 
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
index 725d61c..db3881f 100644
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -55,7 +55,8 @@ main(int argc, char **argv)
 	else
 		exit(1);
 
-	if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0))
+	if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0)
+	    || (strcmp(argv[1], "blackfin") == 0))
 		printf("#define MODULE_SYMBOL_PREFIX \"_\"\n");
 	else
 		printf("#define MODULE_SYMBOL_PREFIX \"\"\n");
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 65bdfdb..480e18b 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -55,6 +55,17 @@ void warn(const char *fmt, ...)
 	va_end(arglist);
 }
 
+void merror(const char *fmt, ...)
+{
+	va_list arglist;
+
+	fprintf(stderr, "ERROR: ");
+
+	va_start(arglist, fmt);
+	vfprintf(stderr, fmt, arglist);
+	va_end(arglist);
+}
+
 static int is_vmlinux(const char *modname)
 {
 	const char *myname;
@@ -333,10 +344,10 @@ void release_file(void *file, unsigned l
 	munmap(file, size);
 }
 
-static void parse_elf(struct elf_info *info, const char *filename)
+static int parse_elf(struct elf_info *info, const char *filename)
 {
 	unsigned int i;
-	Elf_Ehdr *hdr = info->hdr;
+	Elf_Ehdr *hdr;
 	Elf_Shdr *sechdrs;
 	Elf_Sym  *sym;
 
@@ -346,9 +357,18 @@ static void parse_elf(struct elf_info *i
 		exit(1);
 	}
 	info->hdr = hdr;
-	if (info->size < sizeof(*hdr))
-		goto truncated;
-
+	if (info->size < sizeof(*hdr)) {
+		/* file too small, assume this is an empty .o file */
+		return 0;
+	}
+	/* Is this a valid ELF file? */
+	if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+	    (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+	    (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+	    (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+		/* Not an ELF file - silently ignore it */
+		return 0;
+	}
 	/* Fix endianness in ELF header */
 	hdr->e_shoff    = TO_NATIVE(hdr->e_shoff);
 	hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
@@ -371,8 +391,10 @@ static void parse_elf(struct elf_info *i
 			= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 		const char *secname;
 
-		if (sechdrs[i].sh_offset > info->size)
-			goto truncated;
+		if (sechdrs[i].sh_offset > info->size) {
+			fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr));
+			return 0;
+		}
 		secname = secstrings + sechdrs[i].sh_name;
 		if (strcmp(secname, ".modinfo") == 0) {
 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
@@ -407,10 +429,7 @@ static void parse_elf(struct elf_info *i
 		sym->st_value = TO_NATIVE(sym->st_value);
 		sym->st_size  = TO_NATIVE(sym->st_size);
 	}
-	return;
-
- truncated:
-	fatal("%s is truncated.\n", filename);
+	return 1;
 }
 
 static void parse_elf_finish(struct elf_info *info)
@@ -581,9 +600,17 @@ static int strrcmp(const char *s, const 
  *   the pattern is identified by:
  *   tosec   = .init.text | .exit.text | .init.data
  *   fromsec = .data
- *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console
  *
  * Pattern 3:
+ *   Whitelist all references from .pci_fixup* section to .init.text
+ *   This is part of the PCI init when built-in
+ *
+ * Pattern 4:
+ *   Whitelist all refereces from .text.head to .init.data
+ *   Whitelist all refereces from .text.head to .init.text
+ *
+ * Pattern 5:
  *   Some symbols belong to init section but still it is ok to reference
  *   these from non-init sections as these symbols don't have any memory
  *   allocated for them and symbol address and value are same. So even
@@ -591,6 +618,40 @@ static int strrcmp(const char *s, const 
  *   For ex. symbols marking the init section boundaries.
  *   This pattern is identified by
  *   refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 6:
+ *   During the early init phase we have references from .init.text to
+ *   .text we have an intended section mismatch - do not warn about it.
+ *   See kernel_init() in init/main.c
+ *   tosec   = .init.text
+ *   fromsec = .text
+ *   atsym = kernel_init
+ *
+ * Pattern 7:
+ *  Logos used in drivers/video/logo reside in __initdata but the
+ *  funtion that references them are EXPORT_SYMBOL() so cannot be
+ *  marker __init. So we whitelist them here.
+ *  The pattern is:
+ *  tosec      = .init.data
+ *  fromsec    = .text*
+ *  refsymname = logo_
+ *
+ * Pattern 8:
+ *  Symbols contained in .paravirtprobe may safely reference .init.text.
+ *  The pattern is:
+ *  tosec   = .init.text
+ *  fromsec  = .paravirtprobe
+ *
+ * Pattern 9:
+ *  Some of functions are common code between boot time and hotplug
+ *  time. The bootmem allocater is called only boot time in its
+ *  functions. So it's ok to reference.
+ *  tosec    = .init.text
+ *
+ * Pattern 10:
+ *  ia64 has machvec table for each platform. It is mixture of function
+ *  pointer of .init.text and .text.
+ *  fromsec  = .machvec
  **/
 static int secref_whitelist(const char *modname, const char *tosec,
 			    const char *fromsec, const char *atsym,
@@ -606,6 +667,7 @@ static int secref_whitelist(const char *
 		"_probe",
 		"_probe_one",
 		"_console",
+		"apic_es7000",
 		NULL
 	};
 
@@ -616,6 +678,12 @@ static int secref_whitelist(const char *
 		NULL
 	};
 
+	const char *pat4sym[] = {
+		"sparse_index_alloc",
+		"zone_wait_table_init",
+		NULL
+	};
+
 	/* Check for pattern 1 */
 	if (strcmp(tosec, ".init.data") != 0)
 		f1 = 0;
@@ -641,25 +709,50 @@ static int secref_whitelist(const char *
 	if (f1 && f2)
 		return 1;
 
-	/* Whitelist all references from .pci_fixup section if vmlinux
-	 * Whitelist all refereces from .text.head to .init.data if vmlinux
-	 * Whitelist all refereces from .text.head to .init.text if vmlinux
-	 */
-	if (is_vmlinux(modname)) {
-		if ((strcmp(fromsec, ".pci_fixup") == 0) &&
-		    (strcmp(tosec, ".init.text") == 0))
+	/* Check for pattern 3 */
+	if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) &&
+	    (strcmp(tosec, ".init.text") == 0))
+	return 1;
+
+	/* Check for pattern 4 */
+	if ((strcmp(fromsec, ".text.head") == 0) &&
+		((strcmp(tosec, ".init.data") == 0) ||
+		(strcmp(tosec, ".init.text") == 0)))
+	return 1;
+
+	/* Check for pattern 5 */
+	for (s = pat3refsym; *s; s++)
+		if (strcmp(refsymname, *s) == 0)
+			return 1;
+
+	/* Check for pattern 6 */
+	if ((strcmp(tosec, ".init.text") == 0) &&
+	    (strcmp(fromsec, ".text") == 0) &&
+	    (strcmp(refsymname, "kernel_init") == 0))
 		return 1;
 
-		if ((strcmp(fromsec, ".text.head") == 0) &&
-			((strcmp(tosec, ".init.data") == 0) ||
-			(strcmp(tosec, ".init.text") == 0)))
+	/* Check for pattern 7 */
+	if ((strcmp(tosec, ".init.data") == 0) &&
+	    (strncmp(fromsec, ".text", strlen(".text")) == 0) &&
+	    (strncmp(refsymname, "logo_", strlen("logo_")) == 0))
 		return 1;
 
-		/* Check for pattern 3 */
-		for (s = pat3refsym; *s; s++)
-			if (strcmp(refsymname, *s) == 0)
+	/* Check for pattern 8 */
+	if ((strcmp(tosec, ".init.text") == 0) &&
+	    (strcmp(fromsec, ".paravirtprobe") == 0))
+		return 1;
+
+	/* Check for pattern 9 */
+	if ((strcmp(tosec, ".init.text") == 0) &&
+	    (strcmp(fromsec, ".text") == 0))
+		for (s = pat4sym; *s; s++)
+			if (strcmp(atsym, *s) == 0)
 				return 1;
-	}
+
+	/* Check for pattern 10 */
+	if (strcmp(fromsec, ".machvec") == 0)
+		return 1;
+
 	return 0;
 }
 
@@ -1089,7 +1182,8 @@ static void read_symbols(char *modname)
 	struct elf_info info = { };
 	Elf_Sym *sym;
 
-	parse_elf(&info, modname);
+	if (!parse_elf(&info, modname))
+		return;
 
 	mod = new_module(modname);
 
@@ -1264,9 +1358,14 @@ static int add_versions(struct buffer *b
 		exp = find_symbol(s->name);
 		if (!exp || exp->module == mod) {
 			if (have_vmlinux && !s->weak) {
-				warn("\"%s\" [%s.ko] undefined!\n",
-				     s->name, mod->name);
-				err = warn_unresolved ? 0 : 1;
+				if (warn_unresolved) {
+					warn("\"%s\" [%s.ko] undefined!\n",
+					     s->name, mod->name);
+				} else {
+					merror("\"%s\" [%s.ko] undefined!\n",
+					          s->name, mod->name);
+					err = 1;
+				}
 			}
 			continue;
 		}
@@ -1317,6 +1416,7 @@ static void add_depends(struct buffer *b
 	buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
 	buf_printf(b, "\"depends=");
 	for (s = mod->unres; s; s = s->next) {
+		const char *p;
 		if (!s->module)
 			continue;
 
@@ -1324,8 +1424,11 @@ static void add_depends(struct buffer *b
 			continue;
 
 		s->module->seen = 1;
-		buf_printf(b, "%s%s", first ? "" : ",",
-			   strrchr(s->module->name, '/') + 1);
+		if ((p = strrchr(s->module->name, '/')) != NULL)
+			p++;
+		else
+			p = s->module->name;
+		buf_printf(b, "%s%s", first ? "" : ",", p);
 		first = 0;
 	}
 	buf_printf(b, "\";\n");
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index d398c61..0858caa 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -145,3 +145,4 @@ void release_file(void *file, unsigned l
 
 void fatal(const char *fmt, ...);
 void warn(const char *fmt, ...);
+void merror(const char *fmt, ...);
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 8a28756..6873d5a 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -397,10 +397,9 @@ void get_src_version(const char *modname
 		(int) strlen(basename) - 2, basename);
 
 	file = grab_file(filelist, &len);
-	if (!file) {
-		warn("could not find versions for %s\n", filelist);
+	if (!file)
+		/* not a module or .mod file missing - ignore */
 		return;
-	}
 
 	sources = strchr(file, '\n');
 	if (!sources) {
diff --git a/security/capability.c b/security/capability.c
index b868e7e..38296a0 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -17,7 +17,6 @@ #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/ptrace.h>
diff --git a/security/commoncap.c b/security/commoncap.c
index 5a5ef5c..384379e 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -17,7 +17,6 @@ #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/ptrace.h>
diff --git a/security/inode.c b/security/inode.c
index d7ecf89..307211a 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -321,7 +321,7 @@ static int __init securityfs_init(void)
 {
 	int retval;
 
-	kset_set_kset_s(&security_subsys, kernel_subsys);
+	kobj_set_kset_s(&security_subsys, kernel_subsys);
 	retval = subsystem_register(&security_subsys);
 	if (retval)
 		return retval;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index ad45ce7..88292e3 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -66,6 +66,8 @@ struct key_type key_type_keyring = {
 	.read		= keyring_read,
 };
 
+EXPORT_SYMBOL(key_type_keyring);
+
 /*
  * semaphore to serialise link/link calls to prevent two link calls in parallel
  * introducing a cycle
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index faf2e02..dc3502e 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -8,5 +8,7 @@ selinux-y := avc.o hooks.o selinuxfs.o n
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
+selinux-$(CONFIG_NETLABEL) += netlabel.o
+
 EXTRA_CFLAGS += -Isecurity/selinux/include
 
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index da8caf1..e4396a8 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -217,6 +217,8 @@ static void avc_dump_query(struct audit_
 		audit_log_format(ab, " tcontext=%s", scontext);
 		kfree(scontext);
 	}
+
+	BUG_ON(tclass >= ARRAY_SIZE(class_to_string) || !class_to_string[tclass]);
 	audit_log_format(ab, " tclass=%s", class_to_string[tclass]);
 }
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d41e24d..ad8dd4e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -35,7 +35,6 @@ #include <linux/mman.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/syscalls.h>
 #include <linux/file.h>
@@ -77,7 +76,7 @@ #include "avc.h"
 #include "objsec.h"
 #include "netif.h"
 #include "xfrm.h"
-#include "selinux_netlabel.h"
+#include "netlabel.h"
 
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -1758,12 +1757,11 @@ static inline void flush_unauthorized_fi
 			}
 		}
 		file_list_unlock();
-
-		/* Reset controlling tty. */
-		if (drop_tty)
-			proc_set_tty(current, NULL);
 	}
 	mutex_unlock(&tty_mutex);
+	/* Reset controlling tty. */
+	if (drop_tty)
+		no_tty();
 
 	/* Revalidate access to inherited open files. */
 
@@ -2944,7 +2942,7 @@ static int selinux_parse_skb_ipv4(struct
 	int offset, ihlen, ret = -EINVAL;
 	struct iphdr _iph, *ih;
 
-	offset = skb->nh.raw - skb->data;
+	offset = skb_network_offset(skb);
 	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
 	if (ih == NULL)
 		goto out;
@@ -3026,7 +3024,7 @@ static int selinux_parse_skb_ipv6(struct
 	int ret = -EINVAL, offset;
 	struct ipv6hdr _ipv6h, *ip6;
 
-	offset = skb->nh.raw - skb->data;
+	offset = skb_network_offset(skb);
 	ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
 	if (ip6 == NULL)
 		goto out;
@@ -3123,6 +3121,34 @@ #endif	/* IPV6 */
 	return ret;
 }
 
+/**
+ * selinux_skb_extlbl_sid - Determine the external label of a packet
+ * @skb: the packet
+ * @base_sid: the SELinux SID to use as a context for MLS only external labels
+ * @sid: the packet's SID
+ *
+ * Description:
+ * Check the various different forms of external packet labeling and determine
+ * the external SID for the packet.
+ *
+ */
+static void selinux_skb_extlbl_sid(struct sk_buff *skb,
+				   u32 base_sid,
+				   u32 *sid)
+{
+	u32 xfrm_sid;
+	u32 nlbl_sid;
+
+	selinux_skb_xfrm_sid(skb, &xfrm_sid);
+	if (selinux_netlbl_skbuff_getsid(skb,
+					 (xfrm_sid == SECSID_NULL ?
+					  base_sid : xfrm_sid),
+					 &nlbl_sid) != 0)
+		nlbl_sid = SECSID_NULL;
+
+	*sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid);
+}
+
 /* socket security operations */
 static int socket_has_perm(struct task_struct *task, struct socket *sock,
 			   u32 perms)
@@ -3664,9 +3690,7 @@ 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)
-		security_skb_extlbl_sid(skb,
-					SECINITSID_UNLABELED,
-					&peer_secid);
+		selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peer_secid);
 
 	if (peer_secid == SECSID_NULL)
 		err = -EINVAL;
@@ -3727,7 +3751,7 @@ static int selinux_inet_conn_request(str
 	u32 newsid;
 	u32 peersid;
 
-	security_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid);
+	selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid);
 	if (peersid == SECSID_NULL) {
 		req->secid = sksec->sid;
 		req->peer_secid = SECSID_NULL;
@@ -3765,7 +3789,7 @@ static void selinux_inet_conn_establishe
 {
 	struct sk_security_struct *sksec = sk->sk_security;
 
-	security_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid);
+	selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid);
 }
 
 static void selinux_req_classify_flow(const struct request_sock *req,
@@ -3786,7 +3810,7 @@ static int selinux_nlmsg_perm(struct soc
 		err = -EINVAL;
 		goto out;
 	}
-	nlh = (struct nlmsghdr *)skb->data;
+	nlh = nlmsg_hdr(skb);
 	
 	err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
 	if (err) {
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index ad9fb2d..b83e740 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -128,96 +128,6 @@
    S_(SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease")
    S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_WRITE, "audit_write")
    S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_CONTROL, "audit_control")
-   S_(SECCLASS_PASSWD, PASSWD__PASSWD, "passwd")
-   S_(SECCLASS_PASSWD, PASSWD__CHFN, "chfn")
-   S_(SECCLASS_PASSWD, PASSWD__CHSH, "chsh")
-   S_(SECCLASS_PASSWD, PASSWD__ROOTOK, "rootok")
-   S_(SECCLASS_PASSWD, PASSWD__CRONTAB, "crontab")
-   S_(SECCLASS_DRAWABLE, DRAWABLE__CREATE, "create")
-   S_(SECCLASS_DRAWABLE, DRAWABLE__DESTROY, "destroy")
-   S_(SECCLASS_DRAWABLE, DRAWABLE__DRAW, "draw")
-   S_(SECCLASS_DRAWABLE, DRAWABLE__COPY, "copy")
-   S_(SECCLASS_DRAWABLE, DRAWABLE__GETATTR, "getattr")
-   S_(SECCLASS_GC, GC__CREATE, "create")
-   S_(SECCLASS_GC, GC__FREE, "free")
-   S_(SECCLASS_GC, GC__GETATTR, "getattr")
-   S_(SECCLASS_GC, GC__SETATTR, "setattr")
-   S_(SECCLASS_WINDOW, WINDOW__ADDCHILD, "addchild")
-   S_(SECCLASS_WINDOW, WINDOW__CREATE, "create")
-   S_(SECCLASS_WINDOW, WINDOW__DESTROY, "destroy")
-   S_(SECCLASS_WINDOW, WINDOW__MAP, "map")
-   S_(SECCLASS_WINDOW, WINDOW__UNMAP, "unmap")
-   S_(SECCLASS_WINDOW, WINDOW__CHSTACK, "chstack")
-   S_(SECCLASS_WINDOW, WINDOW__CHPROPLIST, "chproplist")
-   S_(SECCLASS_WINDOW, WINDOW__CHPROP, "chprop")
-   S_(SECCLASS_WINDOW, WINDOW__LISTPROP, "listprop")
-   S_(SECCLASS_WINDOW, WINDOW__GETATTR, "getattr")
-   S_(SECCLASS_WINDOW, WINDOW__SETATTR, "setattr")
-   S_(SECCLASS_WINDOW, WINDOW__SETFOCUS, "setfocus")
-   S_(SECCLASS_WINDOW, WINDOW__MOVE, "move")
-   S_(SECCLASS_WINDOW, WINDOW__CHSELECTION, "chselection")
-   S_(SECCLASS_WINDOW, WINDOW__CHPARENT, "chparent")
-   S_(SECCLASS_WINDOW, WINDOW__CTRLLIFE, "ctrllife")
-   S_(SECCLASS_WINDOW, WINDOW__ENUMERATE, "enumerate")
-   S_(SECCLASS_WINDOW, WINDOW__TRANSPARENT, "transparent")
-   S_(SECCLASS_WINDOW, WINDOW__MOUSEMOTION, "mousemotion")
-   S_(SECCLASS_WINDOW, WINDOW__CLIENTCOMEVENT, "clientcomevent")
-   S_(SECCLASS_WINDOW, WINDOW__INPUTEVENT, "inputevent")
-   S_(SECCLASS_WINDOW, WINDOW__DRAWEVENT, "drawevent")
-   S_(SECCLASS_WINDOW, WINDOW__WINDOWCHANGEEVENT, "windowchangeevent")
-   S_(SECCLASS_WINDOW, WINDOW__WINDOWCHANGEREQUEST, "windowchangerequest")
-   S_(SECCLASS_WINDOW, WINDOW__SERVERCHANGEEVENT, "serverchangeevent")
-   S_(SECCLASS_WINDOW, WINDOW__EXTENSIONEVENT, "extensionevent")
-   S_(SECCLASS_FONT, FONT__LOAD, "load")
-   S_(SECCLASS_FONT, FONT__FREE, "free")
-   S_(SECCLASS_FONT, FONT__GETATTR, "getattr")
-   S_(SECCLASS_FONT, FONT__USE, "use")
-   S_(SECCLASS_COLORMAP, COLORMAP__CREATE, "create")
-   S_(SECCLASS_COLORMAP, COLORMAP__FREE, "free")
-   S_(SECCLASS_COLORMAP, COLORMAP__INSTALL, "install")
-   S_(SECCLASS_COLORMAP, COLORMAP__UNINSTALL, "uninstall")
-   S_(SECCLASS_COLORMAP, COLORMAP__LIST, "list")
-   S_(SECCLASS_COLORMAP, COLORMAP__READ, "read")
-   S_(SECCLASS_COLORMAP, COLORMAP__STORE, "store")
-   S_(SECCLASS_COLORMAP, COLORMAP__GETATTR, "getattr")
-   S_(SECCLASS_COLORMAP, COLORMAP__SETATTR, "setattr")
-   S_(SECCLASS_PROPERTY, PROPERTY__CREATE, "create")
-   S_(SECCLASS_PROPERTY, PROPERTY__FREE, "free")
-   S_(SECCLASS_PROPERTY, PROPERTY__READ, "read")
-   S_(SECCLASS_PROPERTY, PROPERTY__WRITE, "write")
-   S_(SECCLASS_CURSOR, CURSOR__CREATE, "create")
-   S_(SECCLASS_CURSOR, CURSOR__CREATEGLYPH, "createglyph")
-   S_(SECCLASS_CURSOR, CURSOR__FREE, "free")
-   S_(SECCLASS_CURSOR, CURSOR__ASSIGN, "assign")
-   S_(SECCLASS_CURSOR, CURSOR__SETATTR, "setattr")
-   S_(SECCLASS_XCLIENT, XCLIENT__KILL, "kill")
-   S_(SECCLASS_XINPUT, XINPUT__LOOKUP, "lookup")
-   S_(SECCLASS_XINPUT, XINPUT__GETATTR, "getattr")
-   S_(SECCLASS_XINPUT, XINPUT__SETATTR, "setattr")
-   S_(SECCLASS_XINPUT, XINPUT__SETFOCUS, "setfocus")
-   S_(SECCLASS_XINPUT, XINPUT__WARPPOINTER, "warppointer")
-   S_(SECCLASS_XINPUT, XINPUT__ACTIVEGRAB, "activegrab")
-   S_(SECCLASS_XINPUT, XINPUT__PASSIVEGRAB, "passivegrab")
-   S_(SECCLASS_XINPUT, XINPUT__UNGRAB, "ungrab")
-   S_(SECCLASS_XINPUT, XINPUT__BELL, "bell")
-   S_(SECCLASS_XINPUT, XINPUT__MOUSEMOTION, "mousemotion")
-   S_(SECCLASS_XINPUT, XINPUT__RELABELINPUT, "relabelinput")
-   S_(SECCLASS_XSERVER, XSERVER__SCREENSAVER, "screensaver")
-   S_(SECCLASS_XSERVER, XSERVER__GETHOSTLIST, "gethostlist")
-   S_(SECCLASS_XSERVER, XSERVER__SETHOSTLIST, "sethostlist")
-   S_(SECCLASS_XSERVER, XSERVER__GETFONTPATH, "getfontpath")
-   S_(SECCLASS_XSERVER, XSERVER__SETFONTPATH, "setfontpath")
-   S_(SECCLASS_XSERVER, XSERVER__GETATTR, "getattr")
-   S_(SECCLASS_XSERVER, XSERVER__GRAB, "grab")
-   S_(SECCLASS_XSERVER, XSERVER__UNGRAB, "ungrab")
-   S_(SECCLASS_XEXTENSION, XEXTENSION__QUERY, "query")
-   S_(SECCLASS_XEXTENSION, XEXTENSION__USE, "use")
-   S_(SECCLASS_PAX, PAX__PAGEEXEC, "pageexec")
-   S_(SECCLASS_PAX, PAX__EMUTRAMP, "emutramp")
-   S_(SECCLASS_PAX, PAX__MPROTECT, "mprotect")
-   S_(SECCLASS_PAX, PAX__RANDMMAP, "randmmap")
-   S_(SECCLASS_PAX, PAX__RANDEXEC, "randexec")
-   S_(SECCLASS_PAX, PAX__SEGMEXEC, "segmexec")
    S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read")
    S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write")
    S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read")
@@ -232,16 +142,6 @@
    S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read")
    S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write")
-   S_(SECCLASS_DBUS, DBUS__ACQUIRE_SVC, "acquire_svc")
-   S_(SECCLASS_DBUS, DBUS__SEND_MSG, "send_msg")
-   S_(SECCLASS_NSCD, NSCD__GETPWD, "getpwd")
-   S_(SECCLASS_NSCD, NSCD__GETGRP, "getgrp")
-   S_(SECCLASS_NSCD, NSCD__GETHOST, "gethost")
-   S_(SECCLASS_NSCD, NSCD__GETSTAT, "getstat")
-   S_(SECCLASS_NSCD, NSCD__ADMIN, "admin")
-   S_(SECCLASS_NSCD, NSCD__SHMEMPWD, "shmempwd")
-   S_(SECCLASS_NSCD, NSCD__SHMEMGRP, "shmemgrp")
-   S_(SECCLASS_NSCD, NSCD__SHMEMHOST, "shmemhost")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
    S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
@@ -256,7 +156,5 @@
    S_(SECCLASS_KEY, KEY__LINK, "link")
    S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
    S_(SECCLASS_KEY, KEY__CREATE, "create")
-   S_(SECCLASS_CONTEXT, CONTEXT__TRANSLATE, "translate")
-   S_(SECCLASS_CONTEXT, CONTEXT__CONTAINS, "contains")
    S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind")
    S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 2de4b5f..5fee173 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -16,7 +16,6 @@ #define COMMON_FILE__EXECUTE            
 #define COMMON_FILE__SWAPON                              0x00004000UL
 #define COMMON_FILE__QUOTAON                             0x00008000UL
 #define COMMON_FILE__MOUNTON                             0x00010000UL
-
 #define COMMON_SOCKET__IOCTL                             0x00000001UL
 #define COMMON_SOCKET__READ                              0x00000002UL
 #define COMMON_SOCKET__WRITE                             0x00000004UL
@@ -39,7 +38,6 @@ #define COMMON_SOCKET__SENDTO           
 #define COMMON_SOCKET__RECV_MSG                          0x00080000UL
 #define COMMON_SOCKET__SEND_MSG                          0x00100000UL
 #define COMMON_SOCKET__NAME_BIND                         0x00200000UL
-
 #define COMMON_IPC__CREATE                               0x00000001UL
 #define COMMON_IPC__DESTROY                              0x00000002UL
 #define COMMON_IPC__GETATTR                              0x00000004UL
@@ -49,7 +47,6 @@ #define COMMON_IPC__WRITE               
 #define COMMON_IPC__ASSOCIATE                            0x00000040UL
 #define COMMON_IPC__UNIX_READ                            0x00000080UL
 #define COMMON_IPC__UNIX_WRITE                           0x00000100UL
-
 #define FILESYSTEM__MOUNT                         0x00000001UL
 #define FILESYSTEM__REMOUNT                       0x00000002UL
 #define FILESYSTEM__UNMOUNT                       0x00000004UL
@@ -60,7 +57,6 @@ #define FILESYSTEM__TRANSITION          
 #define FILESYSTEM__ASSOCIATE                     0x00000080UL
 #define FILESYSTEM__QUOTAMOD                      0x00000100UL
 #define FILESYSTEM__QUOTAGET                      0x00000200UL
-
 #define DIR__IOCTL                                0x00000001UL
 #define DIR__READ                                 0x00000002UL
 #define DIR__WRITE                                0x00000004UL
@@ -78,13 +74,11 @@ #define DIR__EXECUTE                    
 #define DIR__SWAPON                               0x00004000UL
 #define DIR__QUOTAON                              0x00008000UL
 #define DIR__MOUNTON                              0x00010000UL
-
 #define DIR__ADD_NAME                             0x00020000UL
 #define DIR__REMOVE_NAME                          0x00040000UL
 #define DIR__REPARENT                             0x00080000UL
 #define DIR__SEARCH                               0x00100000UL
 #define DIR__RMDIR                                0x00200000UL
-
 #define FILE__IOCTL                               0x00000001UL
 #define FILE__READ                                0x00000002UL
 #define FILE__WRITE                               0x00000004UL
@@ -102,11 +96,9 @@ #define FILE__EXECUTE                   
 #define FILE__SWAPON                              0x00004000UL
 #define FILE__QUOTAON                             0x00008000UL
 #define FILE__MOUNTON                             0x00010000UL
-
 #define FILE__EXECUTE_NO_TRANS                    0x00020000UL
 #define FILE__ENTRYPOINT                          0x00040000UL
 #define FILE__EXECMOD                             0x00080000UL
-
 #define LNK_FILE__IOCTL                           0x00000001UL
 #define LNK_FILE__READ                            0x00000002UL
 #define LNK_FILE__WRITE                           0x00000004UL
@@ -124,7 +116,6 @@ #define LNK_FILE__EXECUTE               
 #define LNK_FILE__SWAPON                          0x00004000UL
 #define LNK_FILE__QUOTAON                         0x00008000UL
 #define LNK_FILE__MOUNTON                         0x00010000UL
-
 #define CHR_FILE__IOCTL                           0x00000001UL
 #define CHR_FILE__READ                            0x00000002UL
 #define CHR_FILE__WRITE                           0x00000004UL
@@ -142,11 +133,9 @@ #define CHR_FILE__EXECUTE               
 #define CHR_FILE__SWAPON                          0x00004000UL
 #define CHR_FILE__QUOTAON                         0x00008000UL
 #define CHR_FILE__MOUNTON                         0x00010000UL
-
 #define CHR_FILE__EXECUTE_NO_TRANS                0x00020000UL
 #define CHR_FILE__ENTRYPOINT                      0x00040000UL
 #define CHR_FILE__EXECMOD                         0x00080000UL
-
 #define BLK_FILE__IOCTL                           0x00000001UL
 #define BLK_FILE__READ                            0x00000002UL
 #define BLK_FILE__WRITE                           0x00000004UL
@@ -164,7 +153,6 @@ #define BLK_FILE__EXECUTE               
 #define BLK_FILE__SWAPON                          0x00004000UL
 #define BLK_FILE__QUOTAON                         0x00008000UL
 #define BLK_FILE__MOUNTON                         0x00010000UL
-
 #define SOCK_FILE__IOCTL                          0x00000001UL
 #define SOCK_FILE__READ                           0x00000002UL
 #define SOCK_FILE__WRITE                          0x00000004UL
@@ -182,7 +170,6 @@ #define SOCK_FILE__EXECUTE              
 #define SOCK_FILE__SWAPON                         0x00004000UL
 #define SOCK_FILE__QUOTAON                        0x00008000UL
 #define SOCK_FILE__MOUNTON                        0x00010000UL
-
 #define FIFO_FILE__IOCTL                          0x00000001UL
 #define FIFO_FILE__READ                           0x00000002UL
 #define FIFO_FILE__WRITE                          0x00000004UL
@@ -200,9 +187,7 @@ #define FIFO_FILE__EXECUTE              
 #define FIFO_FILE__SWAPON                         0x00004000UL
 #define FIFO_FILE__QUOTAON                        0x00008000UL
 #define FIFO_FILE__MOUNTON                        0x00010000UL
-
 #define FD__USE                                   0x00000001UL
-
 #define SOCKET__IOCTL                             0x00000001UL
 #define SOCKET__READ                              0x00000002UL
 #define SOCKET__WRITE                             0x00000004UL
@@ -225,7 +210,6 @@ #define SOCKET__SENDTO                  
 #define SOCKET__RECV_MSG                          0x00080000UL
 #define SOCKET__SEND_MSG                          0x00100000UL
 #define SOCKET__NAME_BIND                         0x00200000UL
-
 #define TCP_SOCKET__IOCTL                         0x00000001UL
 #define TCP_SOCKET__READ                          0x00000002UL
 #define TCP_SOCKET__WRITE                         0x00000004UL
@@ -248,13 +232,11 @@ #define TCP_SOCKET__SENDTO              
 #define TCP_SOCKET__RECV_MSG                      0x00080000UL
 #define TCP_SOCKET__SEND_MSG                      0x00100000UL
 #define TCP_SOCKET__NAME_BIND                     0x00200000UL
-
 #define TCP_SOCKET__CONNECTTO                     0x00400000UL
 #define TCP_SOCKET__NEWCONN                       0x00800000UL
 #define TCP_SOCKET__ACCEPTFROM                    0x01000000UL
 #define TCP_SOCKET__NODE_BIND                     0x02000000UL
 #define TCP_SOCKET__NAME_CONNECT                  0x04000000UL
-
 #define UDP_SOCKET__IOCTL                         0x00000001UL
 #define UDP_SOCKET__READ                          0x00000002UL
 #define UDP_SOCKET__WRITE                         0x00000004UL
@@ -277,9 +259,7 @@ #define UDP_SOCKET__SENDTO              
 #define UDP_SOCKET__RECV_MSG                      0x00080000UL
 #define UDP_SOCKET__SEND_MSG                      0x00100000UL
 #define UDP_SOCKET__NAME_BIND                     0x00200000UL
-
 #define UDP_SOCKET__NODE_BIND                     0x00400000UL
-
 #define RAWIP_SOCKET__IOCTL                       0x00000001UL
 #define RAWIP_SOCKET__READ                        0x00000002UL
 #define RAWIP_SOCKET__WRITE                       0x00000004UL
@@ -302,9 +282,7 @@ #define RAWIP_SOCKET__SENDTO            
 #define RAWIP_SOCKET__RECV_MSG                    0x00080000UL
 #define RAWIP_SOCKET__SEND_MSG                    0x00100000UL
 #define RAWIP_SOCKET__NAME_BIND                   0x00200000UL
-
 #define RAWIP_SOCKET__NODE_BIND                   0x00400000UL
-
 #define NODE__TCP_RECV                            0x00000001UL
 #define NODE__TCP_SEND                            0x00000002UL
 #define NODE__UDP_RECV                            0x00000004UL
@@ -314,7 +292,6 @@ #define NODE__RAWIP_SEND                
 #define NODE__ENFORCE_DEST                        0x00000040UL
 #define NODE__DCCP_RECV                           0x00000080UL
 #define NODE__DCCP_SEND                           0x00000100UL
-
 #define NETIF__TCP_RECV                           0x00000001UL
 #define NETIF__TCP_SEND                           0x00000002UL
 #define NETIF__UDP_RECV                           0x00000004UL
@@ -323,7 +300,6 @@ #define NETIF__RAWIP_RECV               
 #define NETIF__RAWIP_SEND                         0x00000020UL
 #define NETIF__DCCP_RECV                          0x00000040UL
 #define NETIF__DCCP_SEND                          0x00000080UL
-
 #define NETLINK_SOCKET__IOCTL                     0x00000001UL
 #define NETLINK_SOCKET__READ                      0x00000002UL
 #define NETLINK_SOCKET__WRITE                     0x00000004UL
@@ -346,7 +322,6 @@ #define NETLINK_SOCKET__SENDTO          
 #define NETLINK_SOCKET__RECV_MSG                  0x00080000UL
 #define NETLINK_SOCKET__SEND_MSG                  0x00100000UL
 #define NETLINK_SOCKET__NAME_BIND                 0x00200000UL
-
 #define PACKET_SOCKET__IOCTL                      0x00000001UL
 #define PACKET_SOCKET__READ                       0x00000002UL
 #define PACKET_SOCKET__WRITE                      0x00000004UL
@@ -369,7 +344,6 @@ #define PACKET_SOCKET__SENDTO           
 #define PACKET_SOCKET__RECV_MSG                   0x00080000UL
 #define PACKET_SOCKET__SEND_MSG                   0x00100000UL
 #define PACKET_SOCKET__NAME_BIND                  0x00200000UL
-
 #define KEY_SOCKET__IOCTL                         0x00000001UL
 #define KEY_SOCKET__READ                          0x00000002UL
 #define KEY_SOCKET__WRITE                         0x00000004UL
@@ -392,7 +366,6 @@ #define KEY_SOCKET__SENDTO              
 #define KEY_SOCKET__RECV_MSG                      0x00080000UL
 #define KEY_SOCKET__SEND_MSG                      0x00100000UL
 #define KEY_SOCKET__NAME_BIND                     0x00200000UL
-
 #define UNIX_STREAM_SOCKET__IOCTL                 0x00000001UL
 #define UNIX_STREAM_SOCKET__READ                  0x00000002UL
 #define UNIX_STREAM_SOCKET__WRITE                 0x00000004UL
@@ -415,11 +388,9 @@ #define UNIX_STREAM_SOCKET__SENDTO      
 #define UNIX_STREAM_SOCKET__RECV_MSG              0x00080000UL
 #define UNIX_STREAM_SOCKET__SEND_MSG              0x00100000UL
 #define UNIX_STREAM_SOCKET__NAME_BIND             0x00200000UL
-
 #define UNIX_STREAM_SOCKET__CONNECTTO             0x00400000UL
 #define UNIX_STREAM_SOCKET__NEWCONN               0x00800000UL
 #define UNIX_STREAM_SOCKET__ACCEPTFROM            0x01000000UL
-
 #define UNIX_DGRAM_SOCKET__IOCTL                  0x00000001UL
 #define UNIX_DGRAM_SOCKET__READ                   0x00000002UL
 #define UNIX_DGRAM_SOCKET__WRITE                  0x00000004UL
@@ -442,7 +413,6 @@ #define UNIX_DGRAM_SOCKET__SENDTO       
 #define UNIX_DGRAM_SOCKET__RECV_MSG               0x00080000UL
 #define UNIX_DGRAM_SOCKET__SEND_MSG               0x00100000UL
 #define UNIX_DGRAM_SOCKET__NAME_BIND              0x00200000UL
-
 #define PROCESS__FORK                             0x00000001UL
 #define PROCESS__TRANSITION                       0x00000002UL
 #define PROCESS__SIGCHLD                          0x00000004UL
@@ -473,7 +443,6 @@ #define PROCESS__EXECSTACK              
 #define PROCESS__EXECHEAP                         0x08000000UL
 #define PROCESS__SETKEYCREATE                     0x10000000UL
 #define PROCESS__SETSOCKCREATE                    0x20000000UL
-
 #define IPC__CREATE                               0x00000001UL
 #define IPC__DESTROY                              0x00000002UL
 #define IPC__GETATTR                              0x00000004UL
@@ -483,7 +452,6 @@ #define IPC__WRITE                      
 #define IPC__ASSOCIATE                            0x00000040UL
 #define IPC__UNIX_READ                            0x00000080UL
 #define IPC__UNIX_WRITE                           0x00000100UL
-
 #define SEM__CREATE                               0x00000001UL
 #define SEM__DESTROY                              0x00000002UL
 #define SEM__GETATTR                              0x00000004UL
@@ -493,7 +461,6 @@ #define SEM__WRITE                      
 #define SEM__ASSOCIATE                            0x00000040UL
 #define SEM__UNIX_READ                            0x00000080UL
 #define SEM__UNIX_WRITE                           0x00000100UL
-
 #define MSGQ__CREATE                              0x00000001UL
 #define MSGQ__DESTROY                             0x00000002UL
 #define MSGQ__GETATTR                             0x00000004UL
@@ -503,12 +470,9 @@ #define MSGQ__WRITE                     
 #define MSGQ__ASSOCIATE                           0x00000040UL
 #define MSGQ__UNIX_READ                           0x00000080UL
 #define MSGQ__UNIX_WRITE                          0x00000100UL
-
 #define MSGQ__ENQUEUE                             0x00000200UL
-
 #define MSG__SEND                                 0x00000001UL
 #define MSG__RECEIVE                              0x00000002UL
-
 #define SHM__CREATE                               0x00000001UL
 #define SHM__DESTROY                              0x00000002UL
 #define SHM__GETATTR                              0x00000004UL
@@ -518,9 +482,7 @@ #define SHM__WRITE                      
 #define SHM__ASSOCIATE                            0x00000040UL
 #define SHM__UNIX_READ                            0x00000080UL
 #define SHM__UNIX_WRITE                           0x00000100UL
-
 #define SHM__LOCK                                 0x00000200UL
-
 #define SECURITY__COMPUTE_AV                      0x00000001UL
 #define SECURITY__COMPUTE_CREATE                  0x00000002UL
 #define SECURITY__COMPUTE_MEMBER                  0x00000004UL
@@ -532,12 +494,10 @@ #define SECURITY__SETENFORCE            
 #define SECURITY__SETBOOL                         0x00000100UL
 #define SECURITY__SETSECPARAM                     0x00000200UL
 #define SECURITY__SETCHECKREQPROT                 0x00000400UL
-
 #define SYSTEM__IPC_INFO                          0x00000001UL
 #define SYSTEM__SYSLOG_READ                       0x00000002UL
 #define SYSTEM__SYSLOG_MOD                        0x00000004UL
 #define SYSTEM__SYSLOG_CONSOLE                    0x00000008UL
-
 #define CAPABILITY__CHOWN                         0x00000001UL
 #define CAPABILITY__DAC_OVERRIDE                  0x00000002UL
 #define CAPABILITY__DAC_READ_SEARCH               0x00000004UL
@@ -569,110 +529,6 @@ #define CAPABILITY__MKNOD               
 #define CAPABILITY__LEASE                         0x10000000UL
 #define CAPABILITY__AUDIT_WRITE                   0x20000000UL
 #define CAPABILITY__AUDIT_CONTROL                 0x40000000UL
-
-#define PASSWD__PASSWD                            0x00000001UL
-#define PASSWD__CHFN                              0x00000002UL
-#define PASSWD__CHSH                              0x00000004UL
-#define PASSWD__ROOTOK                            0x00000008UL
-#define PASSWD__CRONTAB                           0x00000010UL
-
-#define DRAWABLE__CREATE                          0x00000001UL
-#define DRAWABLE__DESTROY                         0x00000002UL
-#define DRAWABLE__DRAW                            0x00000004UL
-#define DRAWABLE__COPY                            0x00000008UL
-#define DRAWABLE__GETATTR                         0x00000010UL
-
-#define GC__CREATE                                0x00000001UL
-#define GC__FREE                                  0x00000002UL
-#define GC__GETATTR                               0x00000004UL
-#define GC__SETATTR                               0x00000008UL
-
-#define WINDOW__ADDCHILD                          0x00000001UL
-#define WINDOW__CREATE                            0x00000002UL
-#define WINDOW__DESTROY                           0x00000004UL
-#define WINDOW__MAP                               0x00000008UL
-#define WINDOW__UNMAP                             0x00000010UL
-#define WINDOW__CHSTACK                           0x00000020UL
-#define WINDOW__CHPROPLIST                        0x00000040UL
-#define WINDOW__CHPROP                            0x00000080UL
-#define WINDOW__LISTPROP                          0x00000100UL
-#define WINDOW__GETATTR                           0x00000200UL
-#define WINDOW__SETATTR                           0x00000400UL
-#define WINDOW__SETFOCUS                          0x00000800UL
-#define WINDOW__MOVE                              0x00001000UL
-#define WINDOW__CHSELECTION                       0x00002000UL
-#define WINDOW__CHPARENT                          0x00004000UL
-#define WINDOW__CTRLLIFE                          0x00008000UL
-#define WINDOW__ENUMERATE                         0x00010000UL
-#define WINDOW__TRANSPARENT                       0x00020000UL
-#define WINDOW__MOUSEMOTION                       0x00040000UL
-#define WINDOW__CLIENTCOMEVENT                    0x00080000UL
-#define WINDOW__INPUTEVENT                        0x00100000UL
-#define WINDOW__DRAWEVENT                         0x00200000UL
-#define WINDOW__WINDOWCHANGEEVENT                 0x00400000UL
-#define WINDOW__WINDOWCHANGEREQUEST               0x00800000UL
-#define WINDOW__SERVERCHANGEEVENT                 0x01000000UL
-#define WINDOW__EXTENSIONEVENT                    0x02000000UL
-
-#define FONT__LOAD                                0x00000001UL
-#define FONT__FREE                                0x00000002UL
-#define FONT__GETATTR                             0x00000004UL
-#define FONT__USE                                 0x00000008UL
-
-#define COLORMAP__CREATE                          0x00000001UL
-#define COLORMAP__FREE                            0x00000002UL
-#define COLORMAP__INSTALL                         0x00000004UL
-#define COLORMAP__UNINSTALL                       0x00000008UL
-#define COLORMAP__LIST                            0x00000010UL
-#define COLORMAP__READ                            0x00000020UL
-#define COLORMAP__STORE                           0x00000040UL
-#define COLORMAP__GETATTR                         0x00000080UL
-#define COLORMAP__SETATTR                         0x00000100UL
-
-#define PROPERTY__CREATE                          0x00000001UL
-#define PROPERTY__FREE                            0x00000002UL
-#define PROPERTY__READ                            0x00000004UL
-#define PROPERTY__WRITE                           0x00000008UL
-
-#define CURSOR__CREATE                            0x00000001UL
-#define CURSOR__CREATEGLYPH                       0x00000002UL
-#define CURSOR__FREE                              0x00000004UL
-#define CURSOR__ASSIGN                            0x00000008UL
-#define CURSOR__SETATTR                           0x00000010UL
-
-#define XCLIENT__KILL                             0x00000001UL
-
-#define XINPUT__LOOKUP                            0x00000001UL
-#define XINPUT__GETATTR                           0x00000002UL
-#define XINPUT__SETATTR                           0x00000004UL
-#define XINPUT__SETFOCUS                          0x00000008UL
-#define XINPUT__WARPPOINTER                       0x00000010UL
-#define XINPUT__ACTIVEGRAB                        0x00000020UL
-#define XINPUT__PASSIVEGRAB                       0x00000040UL
-#define XINPUT__UNGRAB                            0x00000080UL
-#define XINPUT__BELL                              0x00000100UL
-#define XINPUT__MOUSEMOTION                       0x00000200UL
-#define XINPUT__RELABELINPUT                      0x00000400UL
-
-#define XSERVER__SCREENSAVER                      0x00000001UL
-#define XSERVER__GETHOSTLIST                      0x00000002UL
-#define XSERVER__SETHOSTLIST                      0x00000004UL
-#define XSERVER__GETFONTPATH                      0x00000008UL
-#define XSERVER__SETFONTPATH                      0x00000010UL
-#define XSERVER__GETATTR                          0x00000020UL
-#define XSERVER__GRAB                             0x00000040UL
-#define XSERVER__UNGRAB                           0x00000080UL
-
-#define XEXTENSION__QUERY                         0x00000001UL
-#define XEXTENSION__USE                           0x00000002UL
-
-#define PAX__PAGEEXEC                             0x00000001UL
-#define PAX__EMUTRAMP                             0x00000002UL
-#define PAX__MPROTECT                             0x00000004UL
-#define PAX__RANDMMAP                             0x00000008UL
-#define PAX__RANDEXEC                             0x00000010UL
-#define PAX__SEGMEXEC                             0x00000020UL
-
 #define NETLINK_ROUTE_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_ROUTE_SOCKET__READ                0x00000002UL
 #define NETLINK_ROUTE_SOCKET__WRITE               0x00000004UL
@@ -695,10 +551,8 @@ #define NETLINK_ROUTE_SOCKET__SENDTO    
 #define NETLINK_ROUTE_SOCKET__RECV_MSG            0x00080000UL
 #define NETLINK_ROUTE_SOCKET__SEND_MSG            0x00100000UL
 #define NETLINK_ROUTE_SOCKET__NAME_BIND           0x00200000UL
-
 #define NETLINK_ROUTE_SOCKET__NLMSG_READ          0x00400000UL
 #define NETLINK_ROUTE_SOCKET__NLMSG_WRITE         0x00800000UL
-
 #define NETLINK_FIREWALL_SOCKET__IOCTL            0x00000001UL
 #define NETLINK_FIREWALL_SOCKET__READ             0x00000002UL
 #define NETLINK_FIREWALL_SOCKET__WRITE            0x00000004UL
@@ -721,10 +575,8 @@ #define NETLINK_FIREWALL_SOCKET__SENDTO 
 #define NETLINK_FIREWALL_SOCKET__RECV_MSG         0x00080000UL
 #define NETLINK_FIREWALL_SOCKET__SEND_MSG         0x00100000UL
 #define NETLINK_FIREWALL_SOCKET__NAME_BIND        0x00200000UL
-
 #define NETLINK_FIREWALL_SOCKET__NLMSG_READ       0x00400000UL
 #define NETLINK_FIREWALL_SOCKET__NLMSG_WRITE      0x00800000UL
-
 #define NETLINK_TCPDIAG_SOCKET__IOCTL             0x00000001UL
 #define NETLINK_TCPDIAG_SOCKET__READ              0x00000002UL
 #define NETLINK_TCPDIAG_SOCKET__WRITE             0x00000004UL
@@ -747,10 +599,8 @@ #define NETLINK_TCPDIAG_SOCKET__SENDTO  
 #define NETLINK_TCPDIAG_SOCKET__RECV_MSG          0x00080000UL
 #define NETLINK_TCPDIAG_SOCKET__SEND_MSG          0x00100000UL
 #define NETLINK_TCPDIAG_SOCKET__NAME_BIND         0x00200000UL
-
 #define NETLINK_TCPDIAG_SOCKET__NLMSG_READ        0x00400000UL
 #define NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE       0x00800000UL
-
 #define NETLINK_NFLOG_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_NFLOG_SOCKET__READ                0x00000002UL
 #define NETLINK_NFLOG_SOCKET__WRITE               0x00000004UL
@@ -773,7 +623,6 @@ #define NETLINK_NFLOG_SOCKET__SENDTO    
 #define NETLINK_NFLOG_SOCKET__RECV_MSG            0x00080000UL
 #define NETLINK_NFLOG_SOCKET__SEND_MSG            0x00100000UL
 #define NETLINK_NFLOG_SOCKET__NAME_BIND           0x00200000UL
-
 #define NETLINK_XFRM_SOCKET__IOCTL                0x00000001UL
 #define NETLINK_XFRM_SOCKET__READ                 0x00000002UL
 #define NETLINK_XFRM_SOCKET__WRITE                0x00000004UL
@@ -796,10 +645,8 @@ #define NETLINK_XFRM_SOCKET__SENDTO     
 #define NETLINK_XFRM_SOCKET__RECV_MSG             0x00080000UL
 #define NETLINK_XFRM_SOCKET__SEND_MSG             0x00100000UL
 #define NETLINK_XFRM_SOCKET__NAME_BIND            0x00200000UL
-
 #define NETLINK_XFRM_SOCKET__NLMSG_READ           0x00400000UL
 #define NETLINK_XFRM_SOCKET__NLMSG_WRITE          0x00800000UL
-
 #define NETLINK_SELINUX_SOCKET__IOCTL             0x00000001UL
 #define NETLINK_SELINUX_SOCKET__READ              0x00000002UL
 #define NETLINK_SELINUX_SOCKET__WRITE             0x00000004UL
@@ -822,7 +669,6 @@ #define NETLINK_SELINUX_SOCKET__SENDTO  
 #define NETLINK_SELINUX_SOCKET__RECV_MSG          0x00080000UL
 #define NETLINK_SELINUX_SOCKET__SEND_MSG          0x00100000UL
 #define NETLINK_SELINUX_SOCKET__NAME_BIND         0x00200000UL
-
 #define NETLINK_AUDIT_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_AUDIT_SOCKET__READ                0x00000002UL
 #define NETLINK_AUDIT_SOCKET__WRITE               0x00000004UL
@@ -845,12 +691,10 @@ #define NETLINK_AUDIT_SOCKET__SENDTO    
 #define NETLINK_AUDIT_SOCKET__RECV_MSG            0x00080000UL
 #define NETLINK_AUDIT_SOCKET__SEND_MSG            0x00100000UL
 #define NETLINK_AUDIT_SOCKET__NAME_BIND           0x00200000UL
-
 #define NETLINK_AUDIT_SOCKET__NLMSG_READ          0x00400000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_WRITE         0x00800000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_RELAY         0x01000000UL
 #define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV      0x02000000UL
-
 #define NETLINK_IP6FW_SOCKET__IOCTL               0x00000001UL
 #define NETLINK_IP6FW_SOCKET__READ                0x00000002UL
 #define NETLINK_IP6FW_SOCKET__WRITE               0x00000004UL
@@ -873,10 +717,8 @@ #define NETLINK_IP6FW_SOCKET__SENDTO    
 #define NETLINK_IP6FW_SOCKET__RECV_MSG            0x00080000UL
 #define NETLINK_IP6FW_SOCKET__SEND_MSG            0x00100000UL
 #define NETLINK_IP6FW_SOCKET__NAME_BIND           0x00200000UL
-
 #define NETLINK_IP6FW_SOCKET__NLMSG_READ          0x00400000UL
 #define NETLINK_IP6FW_SOCKET__NLMSG_WRITE         0x00800000UL
-
 #define NETLINK_DNRT_SOCKET__IOCTL                0x00000001UL
 #define NETLINK_DNRT_SOCKET__READ                 0x00000002UL
 #define NETLINK_DNRT_SOCKET__WRITE                0x00000004UL
@@ -899,24 +741,10 @@ #define NETLINK_DNRT_SOCKET__SENDTO     
 #define NETLINK_DNRT_SOCKET__RECV_MSG             0x00080000UL
 #define NETLINK_DNRT_SOCKET__SEND_MSG             0x00100000UL
 #define NETLINK_DNRT_SOCKET__NAME_BIND            0x00200000UL
-
-#define DBUS__ACQUIRE_SVC                         0x00000001UL
-#define DBUS__SEND_MSG                            0x00000002UL
-
-#define NSCD__GETPWD                              0x00000001UL
-#define NSCD__GETGRP                              0x00000002UL
-#define NSCD__GETHOST                             0x00000004UL
-#define NSCD__GETSTAT                             0x00000008UL
-#define NSCD__ADMIN                               0x00000010UL
-#define NSCD__SHMEMPWD                            0x00000020UL
-#define NSCD__SHMEMGRP                            0x00000040UL
-#define NSCD__SHMEMHOST                           0x00000080UL
-
 #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
 #define NETLINK_KOBJECT_UEVENT_SOCKET__WRITE      0x00000004UL
@@ -939,7 +767,6 @@ #define NETLINK_KOBJECT_UEVENT_SOCKET__S
 #define NETLINK_KOBJECT_UEVENT_SOCKET__RECV_MSG   0x00080000UL
 #define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG   0x00100000UL
 #define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND  0x00200000UL
-
 #define APPLETALK_SOCKET__IOCTL                   0x00000001UL
 #define APPLETALK_SOCKET__READ                    0x00000002UL
 #define APPLETALK_SOCKET__WRITE                   0x00000004UL
@@ -962,11 +789,9 @@ #define APPLETALK_SOCKET__SENDTO        
 #define APPLETALK_SOCKET__RECV_MSG                0x00080000UL
 #define APPLETALK_SOCKET__SEND_MSG                0x00100000UL
 #define APPLETALK_SOCKET__NAME_BIND               0x00200000UL
-
 #define PACKET__SEND                              0x00000001UL
 #define PACKET__RECV                              0x00000002UL
 #define PACKET__RELABELTO                         0x00000004UL
-
 #define KEY__VIEW                                 0x00000001UL
 #define KEY__READ                                 0x00000002UL
 #define KEY__WRITE                                0x00000004UL
@@ -974,10 +799,6 @@ #define KEY__SEARCH                     
 #define KEY__LINK                                 0x00000010UL
 #define KEY__SETATTR                              0x00000020UL
 #define KEY__CREATE                               0x00000040UL
-
-#define CONTEXT__TRANSLATE                        0x00000001UL
-#define CONTEXT__CONTAINS                         0x00000002UL
-
 #define DCCP_SOCKET__IOCTL                        0x00000001UL
 #define DCCP_SOCKET__READ                         0x00000002UL
 #define DCCP_SOCKET__WRITE                        0x00000004UL
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index 9f3ebb1..3787990 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -2,7 +2,7 @@
 /*
  * Security object class definitions
  */
-    S_("null")
+    S_(NULL)
     S_("security")
     S_("process")
     S_("system")
@@ -32,19 +32,19 @@
     S_("msgq")
     S_("shm")
     S_("ipc")
-    S_("passwd")
-    S_("drawable")
-    S_("window")
-    S_("gc")
-    S_("font")
-    S_("colormap")
-    S_("property")
-    S_("cursor")
-    S_("xclient")
-    S_("xinput")
-    S_("xserver")
-    S_("xextension")
-    S_("pax")
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
+    S_(NULL)
     S_("netlink_route_socket")
     S_("netlink_firewall_socket")
     S_("netlink_tcpdiag_socket")
@@ -54,12 +54,12 @@
     S_("netlink_audit_socket")
     S_("netlink_ip6fw_socket")
     S_("netlink_dnrt_socket")
-    S_("dbus")
-    S_("nscd")
+    S_(NULL)
+    S_(NULL)
     S_("association")
     S_("netlink_kobject_uevent_socket")
     S_("appletalk_socket")
     S_("packet")
     S_("key")
-    S_("context")
+    S_(NULL)
     S_("dccp_socket")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index 67cef37..35f309f 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -34,19 +34,6 @@ #define SECCLASS_MSG                    
 #define SECCLASS_MSGQ                                    27
 #define SECCLASS_SHM                                     28
 #define SECCLASS_IPC                                     29
-#define SECCLASS_PASSWD                                  30
-#define SECCLASS_DRAWABLE                                31
-#define SECCLASS_WINDOW                                  32
-#define SECCLASS_GC                                      33
-#define SECCLASS_FONT                                    34
-#define SECCLASS_COLORMAP                                35
-#define SECCLASS_PROPERTY                                36
-#define SECCLASS_CURSOR                                  37
-#define SECCLASS_XCLIENT                                 38
-#define SECCLASS_XINPUT                                  39
-#define SECCLASS_XSERVER                                 40
-#define SECCLASS_XEXTENSION                              41
-#define SECCLASS_PAX                                     42
 #define SECCLASS_NETLINK_ROUTE_SOCKET                    43
 #define SECCLASS_NETLINK_FIREWALL_SOCKET                 44
 #define SECCLASS_NETLINK_TCPDIAG_SOCKET                  45
@@ -56,14 +43,11 @@ #define SECCLASS_NETLINK_SELINUX_SOCKET 
 #define SECCLASS_NETLINK_AUDIT_SOCKET                    49
 #define SECCLASS_NETLINK_IP6FW_SOCKET                    50
 #define SECCLASS_NETLINK_DNRT_SOCKET                     51
-#define SECCLASS_DBUS                                    52
-#define SECCLASS_NSCD                                    53
 #define SECCLASS_ASSOCIATION                             54
 #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET           55
 #define SECCLASS_APPLETALK_SOCKET                        56
 #define SECCLASS_PACKET                                  57
 #define SECCLASS_KEY                                     58
-#define SECCLASS_CONTEXT                                 59
 #define SECCLASS_DCCP_SOCKET                             60
 
 /*
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
new file mode 100644
index 0000000..218e3f7
--- /dev/null
+++ b/security/selinux/include/netlabel.h
@@ -0,0 +1,121 @@
+/*
+ * SELinux interface to the NetLabel subsystem
+ *
+ * Author : Paul Moore <paul.moore@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);
+
+void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
+				      int family);
+void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
+				     int family);
+void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
+				      struct sk_security_struct *newssec);
+
+int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid);
+
+void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
+int selinux_netlbl_socket_post_create(struct socket *sock);
+int selinux_netlbl_inode_permission(struct inode *inode, int mask);
+int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
+				struct sk_buff *skb,
+				struct avc_audit_data *ad);
+int selinux_netlbl_socket_setsockopt(struct socket *sock,
+				     int level,
+				     int optname);
+#else
+static inline void selinux_netlbl_cache_invalidate(void)
+{
+	return;
+}
+
+static inline void selinux_netlbl_sk_security_reset(
+	                                       struct sk_security_struct *ssec,
+					       int family)
+{
+	return;
+}
+static inline void selinux_netlbl_sk_security_init(
+	                                       struct sk_security_struct *ssec,
+					       int family)
+{
+	return;
+}
+static inline void selinux_netlbl_sk_security_clone(
+	                                    struct sk_security_struct *ssec,
+					    struct sk_security_struct *newssec)
+{
+	return;
+}
+
+static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
+					       u32 base_sid,
+					       u32 *sid)
+{
+	*sid = SECSID_NULL;
+	return 0;
+}
+
+static inline void selinux_netlbl_sock_graft(struct sock *sk,
+					     struct socket *sock)
+{
+	return;
+}
+static inline int selinux_netlbl_socket_post_create(struct socket *sock)
+{
+	return 0;
+}
+static inline int selinux_netlbl_inode_permission(struct inode *inode,
+						  int mask)
+{
+	return 0;
+}
+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 int selinux_netlbl_socket_setsockopt(struct socket *sock,
+						   int level,
+						   int optname)
+{
+	return 0;
+}
+#endif /* CONFIG_NETLABEL */
+
+#endif
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 210eec7..b94378a 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -34,7 +34,7 @@ #else
 #define POLICYDB_VERSION_MAX	POLICYDB_VERSION_RANGETRANS
 #endif
 
-struct sk_buff;
+struct netlbl_lsm_secattr;
 
 extern int selinux_enabled;
 extern int selinux_mls_enabled;
@@ -82,8 +82,6 @@ int security_netif_sid(char *name, u32 *
 int security_node_sid(u16 domain, void *addr, u32 addrlen,
 	u32 *out_sid);
 
-void security_skb_extlbl_sid(struct sk_buff *skb, u32 base_sid, u32 *sid);
-
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
                                  u16 tclass);
 
@@ -102,5 +100,30 @@ int security_fs_use(const char *fstype, 
 int security_genfs_sid(const char *fstype, char *name, u16 sclass,
 	u32 *sid);
 
+#ifdef CONFIG_NETLABEL
+int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+				   u32 base_sid,
+				   u32 *sid);
+
+int security_netlbl_sid_to_secattr(u32 sid,
+				   struct netlbl_lsm_secattr *secattr);
+#else
+static inline int security_netlbl_secattr_to_sid(
+					    struct netlbl_lsm_secattr *secattr,
+					    u32 base_sid,
+					    u32 *sid)
+{
+	return -EIDRM;
+}
+
+static inline int security_netlbl_sid_to_secattr(u32 sid,
+					   struct netlbl_lsm_secattr *secattr)
+{
+	return -ENOENT;
+}
+#endif /* CONFIG_NETLABEL */
+
+const char *security_get_initial_sid_context(u32 sid);
+
 #endif /* _SELINUX_SECURITY_H_ */
 
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h
deleted file mode 100644
index 2a732c9..0000000
--- a/security/selinux/include/selinux_netlabel.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SELinux interface to the NetLabel subsystem
- *
- * Author : Paul Moore <paul.moore@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_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid);
-int selinux_netlbl_socket_post_create(struct socket *sock);
-void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
-int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
-				struct sk_buff *skb,
-				struct avc_audit_data *ad);
-void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
-				      int family);
-void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
-				     int family);
-void selinux_netlbl_sk_security_clone(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_skbuff_getsid(struct sk_buff *skb,
-					       u32 base_sid,
-					       u32 *sid)
-{
-	*sid = SECSID_NULL;
-	return 0;
-}
-
-static inline int selinux_netlbl_socket_post_create(struct socket *sock)
-{
-	return 0;
-}
-
-static inline void selinux_netlbl_sock_graft(struct sock *sk,
-					     struct socket *sock)
-{
-	return;
-}
-
-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 void selinux_netlbl_sk_security_reset(
-					       struct sk_security_struct *ssec,
-					       int family)
-{
-	return;
-}
-
-static inline void selinux_netlbl_sk_security_init(
-	                                       struct sk_security_struct *ssec,
-					       int family)
-{
-	return;
-}
-
-static inline void selinux_netlbl_sk_security_clone(
-	                                   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/netlabel.c b/security/selinux/netlabel.c
new file mode 100644
index 0000000..bf87507
--- /dev/null
+++ b/security/selinux/netlabel.c
@@ -0,0 +1,363 @@
+/*
+ * SELinux NetLabel Support
+ *
+ * This file provides the necessary glue to tie NetLabel into the SELinux
+ * subsystem.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2007
+ *
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU 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/spinlock.h>
+#include <linux/rcupdate.h>
+#include <net/sock.h>
+#include <net/netlabel.h>
+
+#include "objsec.h"
+#include "security.h"
+
+/**
+ * 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.  The
+ * caller is responsibile for calling rcu_read_lock() before calling this
+ * this function and rcu_read_unlock() after this function returns.
+ *
+ */
+static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
+{
+	int rc;
+	struct sk_security_struct *sksec = sock->sk->sk_security;
+	struct netlbl_lsm_secattr secattr;
+
+	rc = security_netlbl_sid_to_secattr(sid, &secattr);
+	if (rc != 0)
+		return rc;
+
+	rc = netlbl_socket_setattr(sock, &secattr);
+	if (rc == 0) {
+		spin_lock_bh(&sksec->nlbl_lock);
+		sksec->nlbl_state = NLBL_LABELED;
+		spin_unlock_bh(&sksec->nlbl_lock);
+	}
+
+	return rc;
+}
+
+/**
+ * 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_sk_security_reset - Reset the NetLabel fields
+ * @ssec: the sk_security_struct
+ * @family: the socket family
+ *
+ * Description:
+ * Called when the NetLabel state of a sk_security_struct needs to be reset.
+ * The caller is responsibile for all the NetLabel sk_security_struct locking.
+ *
+ */
+void selinux_netlbl_sk_security_reset(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_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)
+{
+	/* No locking needed, we are the only one who has access to ssec */
+	selinux_netlbl_sk_security_reset(ssec, family);
+	spin_lock_init(&ssec->nlbl_lock);
+}
+
+/**
+ * selinux_netlbl_sk_security_clone - 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_security_clone(struct sk_security_struct *ssec,
+				      struct sk_security_struct *newssec)
+{
+	/* We don't need to take newssec->nlbl_lock because we are the only
+	 * thread with access to newssec, but we do need to take the RCU read
+	 * lock as other threads could have access to ssec */
+	rcu_read_lock();
+	selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
+	newssec->sclass = ssec->sclass;
+	rcu_read_unlock();
+}
+
+/**
+ * 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.
+ *
+ */
+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 && secattr.flags != NETLBL_SECATTR_NONE)
+		rc = security_netlbl_secattr_to_sid(&secattr,
+						    base_sid,
+						    sid);
+	else
+		*sid = SECSID_NULL;
+	netlbl_secattr_destroy(&secattr);
+
+	return rc;
+}
+
+/**
+ * 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;
+
+	rcu_read_lock();
+
+	if (sksec->nlbl_state != NLBL_REQUIRE) {
+		rcu_read_unlock();
+		return;
+	}
+
+	netlbl_secattr_init(&secattr);
+	if (netlbl_sock_getattr(sk, &secattr) == 0 &&
+	    secattr.flags != NETLBL_SECATTR_NONE &&
+	    security_netlbl_secattr_to_sid(&secattr,
+					   SECINITSID_UNLABELED,
+					   &nlbl_peer_sid) == 0)
+		sksec->peer_sid = nlbl_peer_sid;
+	netlbl_secattr_destroy(&secattr);
+
+	/* 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);
+
+	rcu_read_unlock();
+}
+
+/**
+ * selinux_netlbl_socket_post_create - Label a socket using NetLabel
+ * @sock: the socket to label
+ *
+ * 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 rc = 0;
+	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+	struct sk_security_struct *sksec = sock->sk->sk_security;
+
+	sksec->sclass = isec->sclass;
+
+	rcu_read_lock();
+	if (sksec->nlbl_state == NLBL_REQUIRE)
+		rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
+	rcu_read_unlock();
+
+	return rc;
+}
+
+/**
+ * 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 sk_security_struct *sksec;
+	struct socket *sock;
+
+	if (!S_ISSOCK(inode->i_mode) ||
+	    ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
+		return 0;
+	sock = SOCKET_I(inode);
+	sksec = sock->sk->sk_security;
+
+	rcu_read_lock();
+	if (sksec->nlbl_state != NLBL_REQUIRE) {
+		rcu_read_unlock();
+		return 0;
+	}
+	local_bh_disable();
+	bh_lock_sock_nested(sock->sk);
+	rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
+	bh_unlock_sock(sock->sk);
+	local_bh_enable();
+	rcu_read_unlock();
+
+	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_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 sk_security_struct *sksec = sock->sk->sk_security;
+	struct netlbl_lsm_secattr secattr;
+
+	rcu_read_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.flags != NETLBL_SECATTR_NONE)
+			rc = -EACCES;
+		netlbl_secattr_destroy(&secattr);
+	}
+	rcu_read_unlock();
+
+	return rc;
+}
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index e203883..f49046d 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -66,7 +66,7 @@ static void selnl_add_payload(struct nlm
 static void selnl_notify(int msgtype, void *data)
 {
 	int len;
-	unsigned char *tmp;
+	sk_buff_data_t tmp;
 	struct sk_buff *skb;
 	struct nlmsghdr *nlh;
 	
@@ -104,7 +104,7 @@ void selnl_notify_policyload(u32 seqno)
 
 static int __init selnl_init(void)
 {
-	selnl = netlink_kernel_create(NETLINK_SELINUX, SELNLGRP_MAX, NULL,
+	selnl = netlink_kernel_create(NETLINK_SELINUX, SELNLGRP_MAX, NULL, NULL,
 	                              THIS_MODULE);
 	if (selnl == NULL)
 		panic("SELinux:  Cannot create netlink socket.");
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 93b3177..aca099a 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -96,12 +96,18 @@ enum sel_inos {
 	SEL_COMMIT_BOOLS, /* commit new boolean values */
 	SEL_MLS,	/* return if MLS policy is enabled */
 	SEL_DISABLE,	/* disable SELinux until next reboot */
-	SEL_AVC,	/* AVC management directory */
 	SEL_MEMBER,	/* compute polyinstantiation membership decision */
 	SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
 	SEL_COMPAT_NET,	/* whether to use old compat network packet controls */
+	SEL_INO_NEXT,	/* The next inode number to use */
 };
 
+static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
+
+#define SEL_INITCON_INO_OFFSET 	0x01000000
+#define SEL_BOOL_INO_OFFSET	0x02000000
+#define SEL_INO_MASK		0x00ffffff
+
 #define TMPBUFLEN	12
 static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
 				size_t count, loff_t *ppos)
@@ -777,8 +783,6 @@ static struct inode *sel_make_inode(stru
 	return ret;
 }
 
-#define BOOL_INO_OFFSET 30
-
 static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 			     size_t count, loff_t *ppos)
 {
@@ -806,14 +810,14 @@ static ssize_t sel_read_bool(struct file
 	}
 
 	inode = filep->f_path.dentry->d_inode;
-	cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
+	cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
 	if (cur_enforcing < 0) {
 		ret = cur_enforcing;
 		goto out;
 	}
 
 	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
-			  bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
+			  bool_pending_values[inode->i_ino&SEL_INO_MASK]);
 	ret = simple_read_from_buffer(buf, count, ppos, page, length);
 out:
 	mutex_unlock(&sel_mutex);
@@ -865,7 +869,7 @@ static ssize_t sel_write_bool(struct fil
 		new_value = 1;
 
 	inode = filep->f_path.dentry->d_inode;
-	bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
+	bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
 	length = count;
 
 out:
@@ -1029,7 +1033,7 @@ static int sel_make_bools(void)
 		isec->sid = sid;
 		isec->initialized = 1;
 		inode->i_fop = &sel_bool_ops;
-		inode->i_ino = i + BOOL_INO_OFFSET;
+		inode->i_ino = i|SEL_BOOL_INO_OFFSET;
 		d_add(dentry, inode);
 	}
 	bool_num = num;
@@ -1234,6 +1238,56 @@ #endif
 			goto out;
 		}
 		inode->i_fop = files[i].ops;
+		inode->i_ino = ++sel_last_ino;
+		d_add(dentry, inode);
+	}
+out:
+	return ret;
+}
+
+static ssize_t sel_read_initcon(struct file * file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct inode *inode;
+	char *con;
+	u32 sid, len;
+	ssize_t ret;
+
+	inode = file->f_path.dentry->d_inode;
+	sid = inode->i_ino&SEL_INO_MASK;
+	ret = security_sid_to_context(sid, &con, &len);
+	if (ret < 0)
+		return ret;
+
+	ret = simple_read_from_buffer(buf, count, ppos, con, len);
+	kfree(con);
+	return ret;
+}
+
+static const struct file_operations sel_initcon_ops = {
+	.read		= sel_read_initcon,
+};
+
+static int sel_make_initcon_files(struct dentry *dir)
+{
+	int i, ret = 0;
+
+	for (i = 1; i <= SECINITSID_NUM; i++) {
+		struct inode *inode;
+		struct dentry *dentry;
+		dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
+		if (!dentry) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
+		if (!inode) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		inode->i_fop = &sel_initcon_ops;
+		inode->i_ino = i|SEL_INITCON_INO_OFFSET;
 		d_add(dentry, inode);
 	}
 out:
@@ -1252,6 +1306,7 @@ static int sel_make_dir(struct inode *di
 	}
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
+	inode->i_ino = ++sel_last_ino;
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
 	inc_nlink(inode);
 	d_add(dentry, inode);
@@ -1314,6 +1369,7 @@ static int sel_fill_super(struct super_b
 		ret = -ENOMEM;
 		goto err;
 	}
+	inode->i_ino = ++sel_last_ino;
 	isec = (struct inode_security_struct*)inode->i_security;
 	isec->sid = SECINITSID_DEVNULL;
 	isec->sclass = SECCLASS_CHR_FILE;
@@ -1336,6 +1392,21 @@ static int sel_fill_super(struct super_b
 	ret = sel_make_avc_files(dentry);
 	if (ret)
 		goto err;
+
+	dentry = d_alloc_name(sb->s_root, "initial_contexts");
+	if (!dentry) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sel_make_dir(root_inode, dentry);
+	if (ret)
+		goto err;
+
+	ret = sel_make_initcon_files(dentry);
+	if (ret)
+		goto err;
+
 out:
 	return ret;
 err:
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1e52356..40660ff 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -39,7 +39,6 @@ #include <linux/in.h>
 #include <linux/sched.h>
 #include <linux/audit.h>
 #include <linux/mutex.h>
-#include <net/sock.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -53,7 +52,7 @@ #include "services.h"
 #include "conditional.h"
 #include "mls.h"
 #include "objsec.h"
-#include "selinux_netlabel.h"
+#include "netlabel.h"
 #include "xfrm.h"
 #include "ebitmap.h"
 
@@ -594,6 +593,13 @@ static int context_struct_to_string(stru
 
 #include "initial_sid_to_string.h"
 
+const char *security_get_initial_sid_context(u32 sid)
+{
+	if (unlikely(sid > SECINITSID_NUM))
+		return NULL;
+	return initial_sid_to_string[sid];
+}
+
 /**
  * security_sid_to_context - Obtain a context for a given SID.
  * @sid: security identifier, SID
@@ -1050,6 +1056,8 @@ static int validate_classes(struct polic
 
 	for (i = 1; i < kdefs->cts_len; i++) {
 		def_class = kdefs->class_to_string[i];
+		if (!def_class)
+			continue;
 		if (i > p->p_classes.nprim) {
 			printk(KERN_INFO
 			       "security:  class %s not defined in policy\n",
@@ -1249,6 +1257,7 @@ bad:
 }
 
 extern void selinux_complete_init(void);
+static int security_preserve_bools(struct policydb *p);
 
 /**
  * security_load_policy - Load a security policy configuration.
@@ -1325,6 +1334,12 @@ #endif
 		goto err;
 	}
 
+	rc = security_preserve_bools(&newpolicydb);
+	if (rc) {
+		printk(KERN_ERR "security:  unable to preserve booleans\n");
+		goto err;
+	}
+
 	/* Clone the SID table. */
 	sidtab_shutdown(&sidtab);
 	if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
@@ -1882,6 +1897,37 @@ out:
 	return rc;
 }
 
+static int security_preserve_bools(struct policydb *p)
+{
+	int rc, nbools = 0, *bvalues = NULL, i;
+	char **bnames = NULL;
+	struct cond_bool_datum *booldatum;
+	struct cond_node *cur;
+
+	rc = security_get_bools(&nbools, &bnames, &bvalues);
+	if (rc)
+		goto out;
+	for (i = 0; i < nbools; i++) {
+		booldatum = hashtab_search(p->p_bools.table, bnames[i]);
+		if (booldatum)
+			booldatum->state = bvalues[i];
+	}
+	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
+		rc = evaluate_cond_node(p, cur);
+		if (rc)
+			goto out;
+	}
+
+out:
+	if (bnames) {
+		for (i = 0; i < nbools; i++)
+			kfree(bnames[i]);
+	}
+	kfree(bnames);
+	kfree(bvalues);
+	return rc;
+}
+
 /*
  * security_sid_mls_copy() - computes a new sid based on the given
  * sid and the mls portion of mls_sid.
@@ -2198,41 +2244,15 @@ void selinux_audit_set_callback(int (*ca
 	aurule_callback = callback;
 }
 
-/**
- * security_skb_extlbl_sid - Determine the external label of a packet
- * @skb: the packet
- * @base_sid: the SELinux SID to use as a context for MLS only external labels
- * @sid: the packet's SID
- *
- * Description:
- * Check the various different forms of external packet labeling and determine
- * the external SID for the packet.
- *
- */
-void security_skb_extlbl_sid(struct sk_buff *skb, u32 base_sid, u32 *sid)
-{
-	u32 xfrm_sid;
-	u32 nlbl_sid;
-
-	selinux_skb_xfrm_sid(skb, &xfrm_sid);
-	if (selinux_netlbl_skbuff_getsid(skb,
-					 (xfrm_sid == SECSID_NULL ?
-					  base_sid : xfrm_sid),
-					 &nlbl_sid) != 0)
-		nlbl_sid = SECSID_NULL;
-
-	*sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid);
-}
-
 #ifdef CONFIG_NETLABEL
 /*
- * This is the structure we store inside the NetLabel cache block.
+ * NetLabel cache structure
  */
-#define NETLBL_CACHE(x)           ((struct netlbl_cache *)(x))
+#define NETLBL_CACHE(x)           ((struct selinux_netlbl_cache *)(x))
 #define NETLBL_CACHE_T_NONE       0
 #define NETLBL_CACHE_T_SID        1
 #define NETLBL_CACHE_T_MLS        2
-struct netlbl_cache {
+struct selinux_netlbl_cache {
 	u32 type;
 	union {
 		u32 sid;
@@ -2241,7 +2261,7 @@ struct netlbl_cache {
 };
 
 /**
- * selinux_netlbl_cache_free - Free the NetLabel cached data
+ * security_netlbl_cache_free - Free the NetLabel cached data
  * @data: the data to free
  *
  * Description:
@@ -2249,9 +2269,9 @@ struct netlbl_cache {
  * netlbl_lsm_cache structure.
  *
  */
-static void selinux_netlbl_cache_free(const void *data)
+static void security_netlbl_cache_free(const void *data)
 {
-	struct netlbl_cache *cache;
+	struct selinux_netlbl_cache *cache;
 
 	if (data == NULL)
 		return;
@@ -2266,33 +2286,33 @@ static void selinux_netlbl_cache_free(co
 }
 
 /**
- * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
- * @skb: the packet
+ * security_netlbl_cache_add - Add an entry to the NetLabel cache
+ * @secattr: the NetLabel packet security attributes
  * @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.
+ * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
+ * already been initialized.
  *
  */
-static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
+static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
+				      struct context *ctx)
 {
-	struct netlbl_cache *cache = NULL;
-	struct netlbl_lsm_secattr secattr;
+	struct selinux_netlbl_cache *cache = NULL;
 
-	netlbl_secattr_init(&secattr);
-	secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
-	if (secattr.cache == NULL)
-		goto netlbl_cache_add_return;
+	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
+	if (secattr->cache == NULL)
+		return;
 
 	cache = kzalloc(sizeof(*cache),	GFP_ATOMIC);
 	if (cache == NULL)
-		goto netlbl_cache_add_return;
+		return;
 
 	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;
+		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 =
@@ -2300,52 +2320,40 @@ static void selinux_netlbl_cache_add(str
 	cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
 	cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
 
-	secattr.cache->free = selinux_netlbl_cache_free;
-	secattr.cache->data = (void *)cache;
-	secattr.flags = NETLBL_SECATTR_CACHE;
-
-	netlbl_cache_add(skb, &secattr);
-
-netlbl_cache_add_return:
-	netlbl_secattr_destroy(&secattr);
+	secattr->cache->free = security_netlbl_cache_free;
+	secattr->cache->data = (void *)cache;
+	secattr->flags |= NETLBL_SECATTR_CACHE;
 }
 
 /**
- * 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
+ * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
  * @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
+ * Convert the given NetLabel 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.
+ * SID/context then use the context in @base_sid as the foundation.  If
+ * possibile the 'cache' field of @secattr is set and the CACHE flag is set;
+ * this is to allow the @secattr to be used by NetLabel to cache the secattr to
+ * SID conversion for future lookups.  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 security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
+				   u32 base_sid,
+				   u32 *sid)
 {
 	int rc = -EIDRM;
 	struct context *ctx;
 	struct context ctx_new;
-	struct netlbl_cache *cache;
+	struct selinux_netlbl_cache *cache;
+
+	if (!ss_initialized) {
+		*sid = SECSID_NULL;
+		return 0;
+	}
 
 	POLICY_RDLOCK;
 
@@ -2410,8 +2418,8 @@ static int selinux_netlbl_secattr_to_sid
 		if (rc != 0)
 			goto netlbl_secattr_to_sid_return_cleanup;
 
-		if (skb != NULL)
-			selinux_netlbl_cache_add(skb, &ctx_new);
+		security_netlbl_cache_add(secattr, &ctx_new);
+
 		ebitmap_destroy(&ctx_new.range.level[0].cat);
 	} else {
 		*sid = SECSID_NULL;
@@ -2427,338 +2435,43 @@ netlbl_secattr_to_sid_return_cleanup:
 }
 
 /**
- * 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.
- *
- */
-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 && secattr.flags != NETLBL_SECATTR_NONE)
-		rc = selinux_netlbl_secattr_to_sid(skb,
-						   &secattr,
-						   base_sid,
-						   sid);
-	else
-		*sid = SECSID_NULL;
-	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
+ * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
+ * @sid: the SELinux SID
+ * @secattr: the NetLabel packet security attributes
  *
  * Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID.  Returns zero values on success, negative values on failure.  The
- * caller is responsibile for calling rcu_read_lock() before calling this
- * this function and rcu_read_unlock() after this function returns.
+ * Convert the given SELinux SID in @sid into a NetLabel security attribute.
+ * Returns zero on success, negative values on failure.
  *
  */
-static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
+int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
 {
 	int rc = -ENOENT;
-	struct sk_security_struct *sksec = sock->sk->sk_security;
-	struct netlbl_lsm_secattr secattr;
 	struct context *ctx;
 
+	netlbl_secattr_init(secattr);
+
 	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);
-	secattr.flags |= NETLBL_SECATTR_DOMAIN;
-	mls_export_netlbl_lvl(ctx, &secattr);
-	rc = mls_export_netlbl_cat(ctx, &secattr);
+		goto netlbl_sid_to_secattr_failure;
+	secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
+				  GFP_ATOMIC);
+	secattr->flags |= NETLBL_SECATTR_DOMAIN;
+	mls_export_netlbl_lvl(ctx, secattr);
+	rc = mls_export_netlbl_cat(ctx, secattr);
 	if (rc != 0)
-		goto netlbl_socket_setsid_return;
-
-	rc = netlbl_socket_setattr(sock, &secattr);
-	if (rc == 0) {
-		spin_lock_bh(&sksec->nlbl_lock);
-		sksec->nlbl_state = NLBL_LABELED;
-		spin_unlock_bh(&sksec->nlbl_lock);
-	}
-
-netlbl_socket_setsid_return:
+		goto netlbl_sid_to_secattr_failure;
 	POLICY_RDUNLOCK;
-	netlbl_secattr_destroy(&secattr);
-	return rc;
-}
-
-/**
- * selinux_netlbl_sk_security_reset - Reset the NetLabel fields
- * @ssec: the sk_security_struct
- * @family: the socket family
- *
- * Description:
- * Called when the NetLabel state of a sk_security_struct needs to be reset.
- * The caller is responsibile for all the NetLabel sk_security_struct locking.
- *
- */
-void selinux_netlbl_sk_security_reset(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_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)
-{
-	/* No locking needed, we are the only one who has access to ssec */
-	selinux_netlbl_sk_security_reset(ssec, family);
-	spin_lock_init(&ssec->nlbl_lock);
-}
-
-/**
- * selinux_netlbl_sk_security_clone - 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_security_clone(struct sk_security_struct *ssec,
-				      struct sk_security_struct *newssec)
-{
-	/* We don't need to take newssec->nlbl_lock because we are the only
-	 * thread with access to newssec, but we do need to take the RCU read
-	 * lock as other threads could have access to ssec */
-	rcu_read_lock();
-	selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
-	newssec->sclass = ssec->sclass;
-	rcu_read_unlock();
-}
-
-/**
- * selinux_netlbl_socket_post_create - Label a socket using NetLabel
- * @sock: the socket to label
- *
- * 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 rc = 0;
-	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
-	struct sk_security_struct *sksec = sock->sk->sk_security;
-
-	sksec->sclass = isec->sclass;
-
-	rcu_read_lock();
-	if (sksec->nlbl_state == NLBL_REQUIRE)
-		rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
-	rcu_read_unlock();
-
-	return rc;
-}
-
-/**
- * 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;
-
-	rcu_read_lock();
-
-	if (sksec->nlbl_state != NLBL_REQUIRE) {
-		rcu_read_unlock();
-		return;
-	}
-
-	netlbl_secattr_init(&secattr);
-	if (netlbl_sock_getattr(sk, &secattr) == 0 &&
-	    secattr.flags != NETLBL_SECATTR_NONE &&
-	    selinux_netlbl_secattr_to_sid(NULL,
-					  &secattr,
-					  SECINITSID_UNLABELED,
-					  &nlbl_peer_sid) == 0)
-		sksec->peer_sid = nlbl_peer_sid;
-	netlbl_secattr_destroy(&secattr);
-
-	/* 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);
-
-	rcu_read_unlock();
-}
-
-/**
- * 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 sk_security_struct *sksec;
-	struct socket *sock;
-
-	if (!S_ISSOCK(inode->i_mode) ||
-	    ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
-		return 0;
-	sock = SOCKET_I(inode);
-	sksec = sock->sk->sk_security;
-
-	rcu_read_lock();
-	if (sksec->nlbl_state != NLBL_REQUIRE) {
-		rcu_read_unlock();
-		return 0;
-	}
-	local_bh_disable();
-	bh_lock_sock_nested(sock->sk);
-	rc = selinux_netlbl_socket_setsid(sock, sksec->sid);
-	bh_unlock_sock(sock->sk);
-	local_bh_enable();
-	rcu_read_unlock();
-
-	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_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 sk_security_struct *sksec = sock->sk->sk_security;
-	struct netlbl_lsm_secattr secattr;
-
-	rcu_read_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.flags != NETLBL_SECATTR_NONE)
-			rc = -EACCES;
-		netlbl_secattr_destroy(&secattr);
-	}
-	rcu_read_unlock();
+	return 0;
 
+netlbl_sid_to_secattr_failure:
+	POLICY_RDUNLOCK;
+	netlbl_secattr_destroy(secattr);
 	return rc;
 }
 #endif /* CONFIG_NETLABEL */
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index b00fc48..e91f9f6 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -1061,10 +1061,10 @@ static int onyx_i2c_attach(struct i2c_ad
 	busnode = pmac_i2c_get_bus_node(bus);
 
 	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (device_is_compatible(dev, "pcm3052")) {
-			u32 *addr;
+		if (of_device_is_compatible(dev, "pcm3052")) {
+			const u32 *addr;
 			printk(KERN_DEBUG PFX "found pcm3052\n");
-			addr = (u32 *) get_property(dev, "reg", NULL);
+			addr = of_get_property(dev, "reg", NULL);
 			if (!addr)
 				return -ENODEV;
 			return onyx_create(adapter, dev, (*addr)>>1);
@@ -1074,7 +1074,7 @@ static int onyx_i2c_attach(struct i2c_ad
 	/* if that didn't work, try desperate mode for older
 	 * machines that have stuff missing from the device tree */
 	
-	if (!device_is_compatible(busnode, "k2-i2c"))
+	if (!of_device_is_compatible(busnode, "k2-i2c"))
 		return -ENODEV;
 
 	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 2cd81fa..041fe52 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -938,10 +938,10 @@ static int tas_i2c_attach(struct i2c_ada
 	busnode = pmac_i2c_get_bus_node(bus);
 
 	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
-		if (device_is_compatible(dev, "tas3004")) {
-			u32 *addr;
+		if (of_device_is_compatible(dev, "tas3004")) {
+			const u32 *addr;
 			printk(KERN_DEBUG PFX "found tas3004\n");
-			addr = (u32 *) get_property(dev, "reg", NULL);
+			addr = of_get_property(dev, "reg", NULL);
 			if (!addr)
 				continue;
 			return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
@@ -950,9 +950,10 @@ static int tas_i2c_attach(struct i2c_ada
 		 * property that says 'tas3004', they just have a 'deq'
 		 * node without any such property... */
 		if (strcmp(dev->name, "deq") == 0) {
-			u32 *_addr, addr;
+			const u32 *_addr;
+			u32 addr;
 			printk(KERN_DEBUG PFX "found 'deq' node\n");
-			_addr = (u32 *) get_property(dev, "i2c-address", NULL);
+			_addr = of_get_property(dev, "i2c-address", NULL);
 			if (!_addr)
 				continue;
 			addr = ((*_addr) >> 1) & 0x7f;
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
index 2b03bc7..805dcbf 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/snd-aoa-gpio-feature.c
@@ -55,7 +55,7 @@ static struct device_node *get_gpio(char
 				    int *gpioactiveptr)
 {
 	struct device_node *np, *gpio;
-	u32 *reg;
+	const u32 *reg;
 	const char *audio_gpio;
 
 	*gpioptr = -1;
@@ -71,7 +71,7 @@ static struct device_node *get_gpio(char
 		if (!gpio)
 			return NULL;
 		while ((np = of_get_next_child(gpio, np))) {
-			audio_gpio = get_property(np, "audio-gpio", NULL);
+			audio_gpio = of_get_property(np, "audio-gpio", NULL);
 			if (!audio_gpio)
 				continue;
 			if (strcmp(audio_gpio, name) == 0)
@@ -84,7 +84,7 @@ static struct device_node *get_gpio(char
 			return NULL;
 	}
 
-	reg = (u32 *)get_property(np, "reg", NULL);
+	reg = of_get_property(np, "reg", NULL);
 	if (!reg)
 		return NULL;
 
@@ -96,7 +96,7 @@ static struct device_node *get_gpio(char
 	if (*gpioptr < 0x50)
 		*gpioptr += 0x50;
 
-	reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+	reg = of_get_property(np, "audio-gpio-active-state", NULL);
 	if (!reg)
 		/* Apple seems to default to 1, but
 		 * that doesn't seem right at least on most
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
index 1b94ba6..9880628 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -724,7 +724,7 @@ static int check_codec(struct aoa_codec 
 		       struct layout_dev *ldev,
 		       struct codec_connect_info *cci)
 {
-	u32 *ref;
+	const u32 *ref;
 	char propname[32];
 	struct codec_connection *cc;
 
@@ -732,7 +732,7 @@ static int check_codec(struct aoa_codec 
 	if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
 		snprintf(propname, sizeof(propname),
 			 "platform-%s-codec-ref", codec->name);
-		ref = (u32*)get_property(ldev->sound, propname, NULL);
+		ref = of_get_property(ldev->sound, propname, NULL);
 		if (!ref) {
 			printk(KERN_INFO "snd-aoa-fabric-layout: "
 				"required property %s not present\n", propname);
@@ -946,7 +946,7 @@ static struct aoa_fabric layout_fabric =
 static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
 {
 	struct device_node *sound = NULL;
-	unsigned int *layout_id;
+	const unsigned int *layout_id;
 	struct layout *layout;
 	struct layout_dev *ldev = NULL;
 	int err;
@@ -962,7 +962,7 @@ static int aoa_fabric_layout_probe(struc
 	}
 	if (!sound) return -ENODEV;
 
-	layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+	layout_id = of_get_property(sound, "layout-id", NULL);
 	if (!layout_id)
 		goto outnodev;
 	printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 47b3e37..8b2e9b9 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -61,9 +61,9 @@ static int soundbus_uevent(struct device
 {
 	struct soundbus_dev * soundbus_dev;
 	struct of_device * of;
-	char *scratch, *compat, *compat2;
-	int i = 0;
-	int length, cplen, cplen2, seen = 0;
+	const char *compat;
+	int retval = 0, i = 0, length = 0;
+	int cplen, seen = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -75,63 +75,47 @@ static int soundbus_uevent(struct device
 	of = &soundbus_dev->ofdev;
 
 	/* stuff we want to pass to /sbin/hotplug */
-	envp[i++] = scratch = buffer;
-	length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"OF_NAME=%s", of->node->name);
+	if (retval)
+		return retval;
+
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"OF_TYPE=%s", of->node->type);
+	if (retval)
+		return retval;
 
 	/* Since the compatible field can contain pretty much anything
 	 * it's not really legal to split it out with commas. We split it
 	 * up using a number of environment variables instead. */
 
-	compat = (char *) get_property(of->node, "compatible", &cplen);
-	compat2 = compat;
-	cplen2= cplen;
+	compat = of_get_property(of->node, "compatible", &cplen);
 	while (compat && cplen > 0) {
-		envp[i++] = scratch;
-		length = scnprintf (scratch, buffer_size,
-				     "OF_COMPATIBLE_%d=%s", seen, compat);
-		++length;
-		buffer_size -= length;
-		if ((buffer_size <= 0) || (i >= num_envp))
-			return -ENOMEM;
-		scratch += length;
-		length = strlen (compat) + 1;
-		compat += length;
-		cplen -= length;
-		seen++;
+		int tmp = length;
+		retval = add_uevent_var(envp, num_envp, &i,
+					buffer, buffer_size, &length,
+					"OF_COMPATIBLE_%d=%s", seen, compat);
+		if (retval)
+			return retval;
+		compat += length - tmp;
+		cplen -= length - tmp;
+		seen += 1;
 	}
 
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
-	++length;
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	scratch += length;
-
-	envp[i++] = scratch;
-	length = scnprintf (scratch, buffer_size, "MODALIAS=%s",
-			soundbus_dev->modalias);
-
-	buffer_size -= length;
-	if ((buffer_size <= 0) || (i >= num_envp))
-		return -ENOMEM;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"OF_COMPATIBLE_N=%d", seen);
+	if (retval)
+		return retval;
+	retval = add_uevent_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"MODALIAS=%s", soundbus_dev->modalias);
 
 	envp[i] = NULL;
 
-	return 0;
+	return retval;
 }
 
 static int soundbus_device_remove(struct device *dev)
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e36f6aa..0fccdbf 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -122,7 +122,7 @@ static int i2sbus_get_and_fixup_rsrc(str
 {
 	struct device_node *parent;
 	int pindex, rc = -ENXIO;
-	u32 *reg;
+	const u32 *reg;
 
 	/* Machines with layout 76 and 36 (K2 based) have a weird device
 	 * tree what we need to special case.
@@ -141,7 +141,7 @@ static int i2sbus_get_and_fixup_rsrc(str
 	rc = of_address_to_resource(parent, pindex, res);
 	if (rc)
 		goto bail;
-	reg = (u32 *)get_property(np, "reg", NULL);
+	reg = of_get_property(np, "reg", NULL);
 	if (reg == NULL) {
 		rc = -ENXIO;
 		goto bail;
@@ -188,8 +188,8 @@ static int i2sbus_add_dev(struct macio_d
 		}
 	}
 	if (i == 1) {
-		u32 *layout_id;
-		layout_id = (u32*) get_property(sound, "layout-id", NULL);
+		const u32 *layout_id =
+			of_get_property(sound, "layout-id", NULL);
 		if (layout_id) {
 			layout = *layout_id;
 			snprintf(dev->sound.modalias, 32,
@@ -336,8 +336,8 @@ static int i2sbus_probe(struct macio_dev
 	}
 
 	while ((np = of_get_next_child(dev->ofdev.node, np))) {
-		if (device_is_compatible(np, "i2sbus") ||
-		    device_is_compatible(np, "i2s-modem")) {
+		if (of_device_is_compatible(np, "i2sbus") ||
+		    of_device_is_compatible(np, "i2s-modem")) {
 			got += i2sbus_add_dev(dev, control, np);
 		}
 	}
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 28db4be..19c65a8 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -260,7 +260,7 @@ static int pxa2xx_ac97_do_suspend(struct
 	if (platform_ops && platform_ops->suspend)
 		platform_ops->suspend(platform_ops->priv);
 	GCR |= GCR_ACLINK_OFF;
-	pxa_set_cken(CKEN2_AC97, 0);
+	pxa_set_cken(CKEN_AC97, 0);
 
 	return 0;
 }
@@ -269,7 +269,7 @@ static int pxa2xx_ac97_do_resume(struct 
 {
 	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
 
-	pxa_set_cken(CKEN2_AC97, 1);
+	pxa_set_cken(CKEN_AC97, 1);
 	if (platform_ops && platform_ops->resume)
 		platform_ops->resume(platform_ops->priv);
 	snd_ac97_resume(pxa2xx_ac97_ac97);
@@ -337,7 +337,7 @@ #ifdef CONFIG_PXA27x
 	/* Use GPIO 113 as AC97 Reset on Bulverde */
 	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
 #endif
-	pxa_set_cken(CKEN2_AC97, 1);
+	pxa_set_cken(CKEN_AC97, 1);
 
 	ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
 	if (ret)
@@ -361,10 +361,10 @@ #endif
  err:
 	if (card)
 		snd_card_free(card);
-	if (CKEN & CKEN2_AC97) {
+	if (CKEN & CKEN_AC97) {
 		GCR |= GCR_ACLINK_OFF;
 		free_irq(IRQ_AC97, NULL);
-		pxa_set_cken(CKEN2_AC97, 0);
+		pxa_set_cken(CKEN_AC97, 0);
 	}
 	return ret;
 }
@@ -378,7 +378,7 @@ static int __devexit pxa2xx_ac97_remove(
 		platform_set_drvdata(dev, NULL);
 		GCR |= GCR_ACLINK_OFF;
 		free_irq(IRQ_AC97, NULL);
-		pxa_set_cken(CKEN2_AC97, 0);
+		pxa_set_cken(CKEN_AC97, 0);
 	}
 
 	return 0;
diff --git a/sound/core/control.c b/sound/core/control.c
index 86de725..1f1ab9c 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -22,7 +22,6 @@
 #include <sound/driver.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/time.h>
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 96ffdf1..51ad95b 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -22,7 +22,6 @@
 #include <sound/driver.h>
 #include <linux/major.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
diff --git a/sound/core/init.c b/sound/core/init.c
index 4a431e3..f2fe357 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -26,7 +26,6 @@ #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/ctype.h>
-#include <linux/pci.h>
 #include <linux/pm.h>
 
 #include <sound/core.h>
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 74a2923..fccad8f 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -21,7 +21,6 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/string.h>
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index c4744bb..fc11572 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -28,7 +28,6 @@ #endif
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3e276fc..9052348 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -21,7 +21,6 @@
 
 #include <sound/driver.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/time.h>
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index d14dcbb..e470c3c 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -23,7 +23,6 @@ #include <sound/driver.h>
 #include <sound/core.h>
 #include <linux/major.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 2eb9873..bc09923 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -22,7 +22,6 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <sound/core.h>
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 694efe8..b31b528 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -23,7 +23,6 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/minors.h>
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 160e40e..67520b3 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -22,7 +22,6 @@
 #include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 4c41930..4b30ae6 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -5,23 +5,22 @@ # More hacking for modularisation.
 #
 # Prompt user for primary drivers.
 
-config OBSOLETE_OSS
+config OSS_OBSOLETE
 	bool "Obsolete OSS drivers"
 	depends on SOUND_PRIME
 	help
 	  This option enables support for obsolete OSS drivers that
-	  are scheduled for removal in the near future since there
-	  are ALSA drivers for the same hardware.
+	  are scheduled for removal in the near future.
 
 	  Please contact Adrian Bunk <bunk@stusta.de> if you had to
-	  say Y here because your soundcard is not properly supported
+	  say Y here because your hardware is not properly supported
 	  by ALSA.
 
 	  If unsure, say N.
 
 config SOUND_BT878
 	tristate "BT878 audio dma"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OSS_OBSOLETE
 	---help---
 	  Audio DMA support for bt878 based grabber boards.  As you might have
 	  already noticed, bt878 is listed with two functions in /proc/pci.
@@ -45,22 +44,9 @@ config SOUND_BCM_CS4297A
 	  note that CONFIG_KGDB should not be enabled at the same
 	  time, since it also attempts to use this UART port.
 
-config SOUND_ES1371
-	tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
-	depends on SOUND_PRIME && PCI && OBSOLETE_OSS
-	help
-	  Say Y or M if you have a PCI sound card utilizing the Ensoniq
-	  ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
-	  your sound card uses an ES1371 without removing your computer's
-	  cover, use lspci -n and look for the PCI ID 1274:1371. Since
-	  Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI
-	  models are either ES1370 or ES1371 based. This driver differs
-	  slightly from OSS/Free, so PLEASE READ
-	  <file:Documentation/sound/oss/es1371>.
-
 config SOUND_ICH
 	tristate "Intel ICH (i8xx) audio support"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OSS_OBSOLETE
 	help
 	  Support for integral audio in Intel's I/O Controller Hub (ICH)
 	  chipset, as used on the 810/820/840 motherboards.
@@ -362,7 +348,7 @@ config MSND_FIFOSIZE
 
 config SOUND_VIA82CXXX
 	tristate "VIA 82C686 Audio Codec"
-	depends on SOUND_PRIME && PCI
+	depends on SOUND_PRIME && PCI && OSS_OBSOLETE
 	help
 	  Say Y here to include support for the audio codec found on VIA
 	  82Cxxx-based chips. Typically these are built into a motherboard.
@@ -416,7 +402,7 @@ config SOUND_DMAP
 
 config SOUND_CS4232
 	tristate "Crystal CS4232 based (PnP) cards"
-	depends on SOUND_OSS
+	depends on SOUND_OSS && OSS_OBSOLETE
 	help
 	  Say Y here if you have a card based on the Crystal CS4232 chip set,
 	  which uses its own Plug and Play protocol.
@@ -735,7 +721,7 @@ config SOUND_WAVEARTIST
 
 config SOUND_TVMIXER
 	tristate "TV card (bt848) mixer support"
-	depends on SOUND_PRIME && I2C && VIDEO_V4L1
+	depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE
 	help
 	  Support for audio mixer facilities on the BT848 TV frame-grabber
 	  card.
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index a339f0c..23018a7 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -47,7 +47,6 @@ #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/poll.h>
-#include <linux/pci.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
index f813ae9..4d5cf05 100644
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -344,7 +344,7 @@ static int btaudio_mixer_ioctl(struct in
 	if (cmd == SOUND_OLD_MIXER_INFO) {
 		_old_mixer_info info;
 		memset(&info,0,sizeof(info));
-                strlcpy(info.id,"bt878",sizeof(info.id)-1);
+                strlcpy(info.id, "bt878", sizeof(info.id));
                 strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
                 if (copy_to_user(argp, &info, sizeof(info)))
                         return -EFAULT;
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 18e149f..71b3134 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -12,20 +12,6 @@ config DMASOUND_ATARI
 	  want). If you want to compile it as a module, say M here and read
 	  <file:Documentation/kbuild/modules.txt>.
 
-config DMASOUND_PMAC
-	tristate "PowerMac DMA sound support"
-	depends on PPC32 && PPC_PMAC && SOUND && I2C && OBSOLETE_OSS
- 	select DMASOUND
-	help
-	  If you want to use the internal audio of your PowerMac in Linux,
-	  answer Y to this question. This will provide a Sun-like /dev/audio,
-	  compatible with the Linux/i386 sound system. Otherwise, say N.
-
-	  This driver is also available as a module ( = code which can be
-	  inserted in and removed from the running kernel whenever you
-	  want). If you want to compile it as a module, say M here and read
-	  <file:Documentation/kbuild/modules.txt>.
-
 config DMASOUND_PAULA
 	tristate "Amiga DMA sound support"
 	depends on (AMIGA || APUS) && SOUND
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 37773b1..8f63880 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -257,7 +257,7 @@ #ifdef CONFIG_PM
 /*
  * Stuff for restoring after a sleep.
  */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
 struct pmu_sleep_notifier awacs_sleep_notifier = {
 	awacs_sleep_notify, SLEEP_LEVEL_SOUND,
 };
@@ -346,36 +346,42 @@ int gpio_headphone_irq;
 int
 setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
 {
+	struct device_node *gpiop;
 	struct device_node *np;
 	const u32* pp;
+	int ret = -ENODEV;
 
-	np = find_devices("gpio");
-	if (!np)
-		return -ENODEV;
+	gpiop = of_find_node_by_name(NULL, "gpio");
+	if (!gpiop)
+		goto done;
 
-	np = np->child;
+	np = of_get_next_child(gpiop, NULL);
 	while(np != 0) {
 		if (name) {
 			const char *property =
-				get_property(np,"audio-gpio",NULL);
+				of_get_property(np,"audio-gpio",NULL);
 			if (property != 0 && strcmp(property,name) == 0)
 				break;
-		} else if (compatible && device_is_compatible(np, compatible))
+		} else if (compatible && of_device_is_compatible(np, compatible))
 			break;
-		np = np->sibling;
+		np = of_get_next_child(gpiop, np);
 	}
 	if (!np)
-		return -ENODEV;
-	pp = get_property(np, "AAPL,address", NULL);
+		goto done;
+	pp = of_get_property(np, "AAPL,address", NULL);
 	if (!pp)
-		return -ENODEV;
+		goto done;
 	*gpio_addr = (*pp) & 0x0000ffff;
-	pp = get_property(np, "audio-gpio-active-state", NULL);
+	pp = of_get_property(np, "audio-gpio-active-state", NULL);
 	if (pp)
 		*gpio_pol = *pp;
 	else
 		*gpio_pol = 1;
-	return irq_of_parse_and_map(np, 0);
+	ret = irq_of_parse_and_map(np, 0);
+done:
+	of_node_put(np);
+	of_node_put(gpiop);
+	return ret;
 }
 
 static inline void
@@ -578,7 +584,7 @@ tas_mixer_ioctl(u_int cmd, u_long arg)
 }
 
 static void __init
-tas_init_frame_rates(unsigned int *prop, unsigned int l)
+tas_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
 	int i ;
 	if (prop) {
@@ -1419,7 +1425,7 @@ #ifdef CONFIG_PM
  * Save state when going to sleep, restore it afterwards.
  */
 /* FIXME: sort out disabling/re-enabling of read stuff as well */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	unsigned long flags;
 
@@ -1548,7 +1554,6 @@ static int awacs_sleep_notify(struct pmu
 		spin_unlock_irqrestore(&dmasound.lock, flags);
 		UNLOCK();
 	}
-	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PM */
 
@@ -2553,32 +2558,33 @@ set_model(void)
 static struct device_node* __init
 get_snd_io_node(void)
 {
-	struct device_node *np = NULL;
+	struct device_node *np;
 
 	/* set up awacs_node for early OF which doesn't have a full set of
 	 * properties on davbus
-	*/
-
-	awacs_node = find_devices("awacs");
+	 */
+	awacs_node = of_find_node_by_name(NULL, "awacs");
 	if (awacs_node)
 		awacs_revision = AWACS_AWACS;
 
 	/* powermac models after 9500 (other than those which use DACA or
 	 * Tumbler) have a node called "davbus".
 	 */
-	np = find_devices("davbus");
+	np = of_find_node_by_name(NULL, "davbus");
 	/*
 	 * if we didn't find a davbus device, try 'i2s-a' since
 	 * this seems to be what iBooks (& Tumbler) have.
 	 */
-	if (np == NULL)
-		np = i2s_node = find_devices("i2s-a");
+	if (np == NULL) {
+		i2s_node = of_find_node_by_name(NULL, "i2s-a");
+		np = of_node_get(i2s_node);
+	}
 
 	/* if we didn't find this - perhaps we are on an early model
 	 * which _only_ has an 'awacs' node
 	*/
 	if (np == NULL && awacs_node)
-		np = awacs_node ;
+		np = of_node_get(awacs_node);
 
 	/* if we failed all these return null - this will cause the
 	 * driver to give up...
@@ -2597,9 +2603,9 @@ get_snd_info_node(struct device_node *io
 {
 	struct device_node *info;
 
-	info = find_devices("sound");
-	while (info && info->parent != io)
-		info = info->next;
+	for_each_node_by_name(info, "sound")
+		if (info->parent == io)
+			break;
 	return info;
 }
 
@@ -2614,17 +2620,17 @@ get_codec_type(struct device_node *info)
 
 	if (info) {
 		/* must do awacs first to allow screamer to overide it */
-		if (device_is_compatible(info, "awacs"))
+		if (of_device_is_compatible(info, "awacs"))
 			codec = AWACS_AWACS ;
-		if (device_is_compatible(info, "screamer"))
+		if (of_device_is_compatible(info, "screamer"))
 			codec = AWACS_SCREAMER;
-		if (device_is_compatible(info, "burgundy"))
+		if (of_device_is_compatible(info, "burgundy"))
 			codec = AWACS_BURGUNDY ;
-		if (device_is_compatible(info, "daca"))
+		if (of_device_is_compatible(info, "daca"))
 			codec = AWACS_DACA;
-		if (device_is_compatible(info, "tumbler"))
+		if (of_device_is_compatible(info, "tumbler"))
 			codec = AWACS_TUMBLER;
-		if (device_is_compatible(info, "snapper"))
+		if (of_device_is_compatible(info, "snapper"))
 			codec = AWACS_SNAPPER;
 	}
 	return codec ;
@@ -2635,11 +2641,17 @@ get_codec_type(struct device_node *info)
 static void __init
 get_expansion_type(void)
 {
-	if (find_devices("perch") != NULL)
+	struct device_node *dn;
+
+	dn = of_find_node_by_name(NULL, "perch");
+	if (dn != NULL)
 		has_perch = 1;
+	of_node_put(dn);
 
-	if (find_devices("pb-ziva-pc") != NULL)
+	dn = of_find_node_by_name(NULL, "pb-ziva-pc");
+	if (dn != NULL)
 		has_ziva = 1;
+	of_node_put(dn);
 	/* need to work out how we deal with iMac SRS module */
 }
 
@@ -2652,7 +2664,7 @@ get_expansion_type(void)
 */
 
 static void __init
-awacs_init_frame_rates(unsigned int *prop, unsigned int l)
+awacs_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
 	int i ;
 	if (prop) {
@@ -2675,7 +2687,7 @@ awacs_init_frame_rates(unsigned int *pro
 }
 
 static void __init
-burgundy_init_frame_rates(unsigned int *prop, unsigned int l)
+burgundy_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
 	int temp[9] ;
 	int i = 0 ;
@@ -2701,7 +2713,7 @@ #endif
 }
 
 static void __init
-daca_init_frame_rates(unsigned int *prop, unsigned int l)
+daca_init_frame_rates(const unsigned int *prop, unsigned int l)
 {
 	int temp[9] ;
 	int i = 0 ;
@@ -2728,7 +2740,7 @@ #endif
 }
 
 static void __init
-init_frame_rates(unsigned int *prop, unsigned int l)
+init_frame_rates(const unsigned int *prop, unsigned int l)
 {
 	switch (awacs_revision) {
 		case AWACS_TUMBLER:
@@ -2760,7 +2772,7 @@ set_hw_byteswap(struct device_node *io)
 
 	for (mio = io->parent; mio ; mio = mio->parent) {
 		if (strcmp(mio->name, "mac-io") == 0) {
-			if (device_is_compatible(mio, "Keylargo"))
+			if (of_device_is_compatible(mio, "Keylargo"))
 				kl = 1;
 			break;
 		}
@@ -2828,7 +2840,7 @@ int __init dmasound_awacs_init(void)
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find sound io OF node\n");
 #endif
-		return -ENODEV ;
+		goto no_device;
 	}
 
 	/* find the OF node that tells us about the sound sub-system
@@ -2840,7 +2852,7 @@ #endif
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find 'sound' OF node\n");
 #endif
-			return -ENODEV ;
+			goto no_device;
 		}
 	}
 
@@ -2849,7 +2861,7 @@ #endif
 #ifdef DEBUG_DMASOUND
 printk("dmasound_pmac: couldn't find a Codec we can handle\n");
 #endif
-		return -ENODEV ; /* we don't know this type of h/w */
+		goto no_device; /* we don't know this type of h/w */
 	}
 
 	/* set up perch, ziva, SRS or whatever else we have as sound
@@ -2867,11 +2879,12 @@ #endif
 		 * machines).
 		 */
 		if (awacs_node) {
-			io = awacs_node ;
+			of_node_put(io);
+			io = of_node_get(awacs_node);
 			if (of_get_address(io, 2, NULL, NULL) == NULL) {
 				printk("dmasound_pmac: can't use %s\n",
 				       io->full_name);
-				return -ENODEV;
+				goto no_device;
 			}
 		} else
 			printk("dmasound_pmac: can't use %s\n", io->full_name);
@@ -2882,7 +2895,7 @@ #endif
 			       awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
 			       " (IO)") == NULL) {
 		printk(KERN_ERR "dmasound: can't request IO resource !\n");
-		return -ENODEV;
+		goto no_device;
 	}
 	if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
 	    request_mem_region(awacs_rsrc[1].start,
@@ -2891,7 +2904,7 @@ #endif
 		release_mem_region(awacs_rsrc[0].start,
 				   awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
 		printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
-		return -ENODEV;
+		goto no_device;
 	}
 	if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
 	    request_mem_region(awacs_rsrc[2].start,
@@ -2902,7 +2915,7 @@ #endif
 		release_mem_region(awacs_rsrc[1].start,
 				   awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
 		printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
-		return -ENODEV;
+		goto no_device;
 	}
 
 	awacs_beep_dev = input_allocate_device();
@@ -2914,7 +2927,7 @@ #endif
 		release_mem_region(awacs_rsrc[2].start,
 				   awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
 		printk(KERN_ERR "dmasound: can't allocate input device !\n");
-		return -ENOMEM;
+		goto no_device;
 	}
 
 	awacs_beep_dev->name = "dmasound beeper";
@@ -2942,7 +2955,8 @@ #endif
 	awacs_rx_irq = irq_of_parse_and_map(io, 2);
 
 	/* Hack for legacy crap that will be killed someday */
-	awacs_node = io;
+	of_node_put(awacs_node);
+	awacs_node = of_node_get(io);
 
 	/* if we have an awacs or screamer - probe the chip to make
 	 * sure we have the right revision.
@@ -2973,24 +2987,26 @@ #endif
 	*/
 
 	if (info) {
-		unsigned int *prop, l;
+		const unsigned int *prop;
+		unsigned int l;
 
 		sound_device_id = 0;
 		/* device ID appears post g3 b&w */
-		prop = (unsigned int *)get_property(info, "device-id", NULL);
+		prop = of_get_property(info, "device-id", NULL);
 		if (prop != 0)
 			sound_device_id = *prop;
 
 		/* look for a property saying what sample rates
 		   are available */
 
-		prop = (unsigned int *)get_property(info, "sample-rates", &l);
+		prop = of_get_property(info, "sample-rates", &l);
 		if (prop == 0)
-			prop = (unsigned int *) get_property
-				(info, "output-frame-rates", &l);
+			prop = of_get_property(info, "output-frame-rates", &l);
 
 		/* if it's there use it to set up frame rates */
 		init_frame_rates(prop, l) ;
+		of_node_put(info);
+		info = NULL;
 	}
 
 	if (awacs)
@@ -3160,7 +3176,16 @@ #endif /* CONFIG_PM */
 	 */
 	input_register_device(awacs_beep_dev);
 
+	of_node_put(io);
+
 	return dmasound_init();
+
+no_device:
+	of_node_put(info);
+	of_node_put(awacs_node);
+	of_node_put(i2s_node);
+	of_node_put(io);
+	return -ENODEV ;
 }
 
 static void __exit dmasound_awacs_cleanup(void)
@@ -3179,6 +3204,8 @@ static void __exit dmasound_awacs_cleanu
 	}
 	dmasound_deinit();
 
+	of_node_put(awacs_node);
+	of_node_put(i2s_node);
 }
 
 MODULE_DESCRIPTION("PowerMac built-in audio driver.");
diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c
index 665e85b..b295ef6 100644
--- a/sound/oss/dmasound/tas_common.c
+++ b/sound/oss/dmasound/tas_common.c
@@ -41,7 +41,6 @@ #define CALL(proc,arg...)							\
 
 static u8 tas_i2c_address = 0x34;
 static struct i2c_client *tas_client;
-static struct device_node* tas_node;
 
 static int tas_attach_adapter(struct i2c_adapter *);
 static int tas_detach_client(struct i2c_client *);
@@ -190,17 +189,18 @@ tas_cleanup(void)
 int __init
 tas_init(int driver_id, const char *driver_name)
 {
-	u32* paddr;
+	const u32* paddr;
+	struct device_node *tas_node;
 
 	printk(KERN_INFO "tas driver [%s])\n", driver_name);
 
 #ifndef CONFIG_I2C_POWERMAC
 	request_module("i2c-powermac");
 #endif
-	tas_node = find_devices("deq");
+	tas_node = of_find_node_by_name("deq");
 	if (tas_node == NULL)
 		return -ENODEV;
-	paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+	paddr = of_get_property(tas_node, "i2c-address", NULL);
 	if (paddr) {
 		tas_i2c_address = (*paddr) >> 1;
 		printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
@@ -208,6 +208,7 @@ #endif
 	} else    
 		printk(KERN_INFO "using i2c address: 0x%x (default)\n",
 				tas_i2c_address);
+	of_node_put(tas_node);
 
 	return i2c_add_driver(&tas_driver);
 }
diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h
index dccae3a..9d12b37 100644
--- a/sound/oss/dmasound/tas_ioctl.h
+++ b/sound/oss/dmasound/tas_ioctl.h
@@ -1,7 +1,6 @@
 #ifndef _TAS_IOCTL_H_
 #define _TAS_IOCTL_H_
 
-#include <linux/i2c.h>
 #include <linux/soundcard.h>
 
 
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index 7ea9acc..b493660 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -104,7 +104,7 @@ static void dac_audio_set_rate(void)
 	unsigned long interval;
  	struct clk *clk;
 
- 	clk = clk_get("module_clk");
+ 	clk = clk_get(NULL, "module_clk");
  	interval = (clk_get_rate(clk) / 4) / rate;
  	clk_put(clk);
 	ctrl_outl(interval, TMU1_TCOR);
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index dcd8d6d..a9c23b2 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -44,6 +44,7 @@ #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/device.h>
 
 /*
  * This ought to be moved into include/asm/dma.h
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 016b918..a8057f2 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -75,7 +75,6 @@ #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/kernel.h>
 
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 72a8a0e..d98d311 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -207,7 +207,6 @@ #include <linux/pci.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/bitops.h>
 #include <linux/proc_fs.h>
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index 7ab3a73..5d3c037 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -32,7 +32,6 @@ #include <linux/sound.h>
 #include <linux/poll.h>
 #include <linux/soundcard.h>
 #include <linux/ac97_codec.h>
-#include <linux/smp_lock.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index b913a1f..9c3a9c8 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -62,7 +62,6 @@ #include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
@@ -71,6 +70,7 @@ #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/tlv.h>
+#include <asm/io.h>
 
 #include "ca0106.h"
 
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index 75ca421..ae80f51 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -64,7 +64,6 @@ #include <sound/driver.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
@@ -73,6 +72,7 @@ #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/asoundef.h>
+#include <asm/io.h>
 
 #include "ca0106.h"
 
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 89c4027..336e77e 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -23,7 +23,6 @@
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 343f51d..57e357d 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -24,7 +24,6 @@
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 1589d2f..1e5ff0c 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -23,7 +23,6 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 17df4d0..e313e68 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -23,7 +23,6 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 7333f27..831469d 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -25,7 +25,6 @@ #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index ed5e45e..6fcda9b 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -26,7 +26,6 @@ #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 4c839b0..2b11ac8 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -35,7 +35,6 @@ #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index c64af55..5a2bef4 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -816,6 +816,7 @@ static int snd_pmac_free(struct snd_pmac
 
 	if (chip->pdev)
 		pci_dev_put(chip->pdev);
+	of_node_put(chip->node);
 	kfree(chip);
 	return 0;
 }
@@ -842,7 +843,7 @@ static void __init detect_byte_swap(stru
 	/* if seems that Keylargo can't byte-swap  */
 	for (mio = chip->node->parent; mio; mio = mio->parent) {
 		if (strcmp(mio->name, "mac-io") == 0) {
-			if (device_is_compatible(mio, "Keylargo"))
+			if (of_device_is_compatible(mio, "Keylargo"))
 				chip->can_byte_swap = 0;
 			break;
 		}
@@ -863,8 +864,10 @@ static void __init detect_byte_swap(stru
  */
 static int __init snd_pmac_detect(struct snd_pmac *chip)
 {
-	struct device_node *sound = NULL;
-	unsigned int *prop, l;
+	struct device_node *sound;
+	struct device_node *dn;
+	const unsigned int *prop;
+	unsigned int l;
 	struct macio_chip* macio;
 
 	if (!machine_is(powermac))
@@ -890,25 +893,24 @@ static int __init snd_pmac_detect(struct
 	else if (machine_is_compatible("PowerBook1,1")
 		 || machine_is_compatible("AAPL,PowerBook1998"))
 		chip->is_pbook_G3 = 1;
-	chip->node = find_devices("awacs");
-	if (chip->node)
-		sound = chip->node;
+	chip->node = of_find_node_by_name(NULL, "awacs");
+	sound = of_node_get(chip->node);
 
 	/*
 	 * powermac G3 models have a node called "davbus"
 	 * with a child called "sound".
 	 */
 	if (!chip->node)
-		chip->node = find_devices("davbus");
+		chip->node = of_find_node_by_name(NULL, "davbus");
 	/*
 	 * if we didn't find a davbus device, try 'i2s-a' since
 	 * this seems to be what iBooks have
 	 */
 	if (! chip->node) {
-		chip->node = find_devices("i2s-a");
+		chip->node = of_find_node_by_name(NULL, "i2s-a");
 		if (chip->node && chip->node->parent &&
 		    chip->node->parent->parent) {
-			if (device_is_compatible(chip->node->parent->parent,
+			if (of_device_is_compatible(chip->node->parent->parent,
 						 "K2-Keylargo"))
 				chip->is_k2 = 1;
 		}
@@ -917,41 +919,44 @@ static int __init snd_pmac_detect(struct
 		return -ENODEV;
 
 	if (!sound) {
-		sound = find_devices("sound");
+		sound = of_find_node_by_name(NULL, "sound");
 		while (sound && sound->parent != chip->node)
-			sound = sound->next;
+			sound = of_find_node_by_name(sound, "sound");
 	}
-	if (! sound)
+	if (! sound) {
+		of_node_put(chip->node);
 		return -ENODEV;
-	prop = (unsigned int *) get_property(sound, "sub-frame", NULL);
+	}
+	prop = of_get_property(sound, "sub-frame", NULL);
 	if (prop && *prop < 16)
 		chip->subframe = *prop;
-	prop = (unsigned int *) get_property(sound, "layout-id", NULL);
+	prop = of_get_property(sound, "layout-id", NULL);
 	if (prop) {
 		/* partly deprecate snd-powermac, for those machines
 		 * that have a layout-id property for now */
 		printk(KERN_INFO "snd-powermac no longer handles any "
 				 "machines with a layout-id property "
 				 "in the device-tree, use snd-aoa.\n");
+		of_node_put(chip->node);
 		return -ENODEV;
 	}
 	/* This should be verified on older screamers */
-	if (device_is_compatible(sound, "screamer")) {
+	if (of_device_is_compatible(sound, "screamer")) {
 		chip->model = PMAC_SCREAMER;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 	}
-	if (device_is_compatible(sound, "burgundy")) {
+	if (of_device_is_compatible(sound, "burgundy")) {
 		chip->model = PMAC_BURGUNDY;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	if (device_is_compatible(sound, "daca")) {
+	if (of_device_is_compatible(sound, "daca")) {
 		chip->model = PMAC_DACA;
 		chip->can_capture = 0;  /* no capture */
 		chip->can_duplex = 0;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	if (device_is_compatible(sound, "tumbler")) {
+	if (of_device_is_compatible(sound, "tumbler")) {
 		chip->model = PMAC_TUMBLER;
 		chip->can_capture = 0;  /* no capture */
 		chip->can_duplex = 0;
@@ -960,17 +965,19 @@ static int __init snd_pmac_detect(struct
 		chip->freq_table = tumbler_freqs;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	if (device_is_compatible(sound, "snapper")) {
+	if (of_device_is_compatible(sound, "snapper")) {
 		chip->model = PMAC_SNAPPER;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 		chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
 		chip->freq_table = tumbler_freqs;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	prop = (unsigned int *)get_property(sound, "device-id", NULL);
+	prop = of_get_property(sound, "device-id", NULL);
 	if (prop)
 		chip->device_id = *prop;
-	chip->has_iic = (find_devices("perch") != NULL);
+	dn = of_find_node_by_name(NULL, "perch");
+	chip->has_iic = (dn != NULL);
+	of_node_put(dn);
 
 	/* We need the PCI device for DMA allocations, let's use a crude method
 	 * for now ...
@@ -997,10 +1004,9 @@ static int __init snd_pmac_detect(struct
 
 	/* look for a property saying what sample rates
 	   are available */
-	prop = (unsigned int *) get_property(sound, "sample-rates", &l);
+	prop = of_get_property(sound, "sample-rates", &l);
 	if (! prop)
-		prop = (unsigned int *) get_property(sound,
-						     "output-frame-rates", &l);
+		prop = of_get_property(sound, "output-frame-rates", &l);
 	if (prop) {
 		int i;
 		chip->freqs_ok = 0;
@@ -1021,6 +1027,7 @@ static int __init snd_pmac_detect(struct
 		chip->freqs_ok = 1;
 	}
 
+	of_node_put(sound);
 	return 0;
 }
 
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 8f074c7..5821cdd 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1031,32 +1031,40 @@ static irqreturn_t headphone_intr(int ir
 /* look for audio-gpio device */
 static struct device_node *find_audio_device(const char *name)
 {
+	struct device_node *gpiop;
 	struct device_node *np;
   
-	if (! (np = find_devices("gpio")))
+	gpiop = of_find_node_by_name(NULL, "gpio");
+	if (! gpiop)
 		return NULL;
   
-	for (np = np->child; np; np = np->sibling) {
-		const char *property = get_property(np, "audio-gpio", NULL);
+	for (np = of_get_next_child(gpiop, NULL); np;
+			np = of_get_next_child(gpiop, np)) {
+		const char *property = of_get_property(np, "audio-gpio", NULL);
 		if (property && strcmp(property, name) == 0)
-			return np;
+			break;
 	}  
-	return NULL;
+	of_node_put(gpiop);
+	return np;
 }
 
 /* look for audio-gpio device */
 static struct device_node *find_compatible_audio_device(const char *name)
 {
+	struct device_node *gpiop;
 	struct device_node *np;
   
-	if (! (np = find_devices("gpio")))
+	gpiop = of_find_node_by_name(NULL, "gpio");
+	if (!gpiop)
 		return NULL;
   
-	for (np = np->child; np; np = np->sibling) {
-		if (device_is_compatible(np, name))
-			return np;
+	for (np = of_get_next_child(gpiop, NULL); np;
+			np = of_get_next_child(gpiop, np)) {
+		if (of_device_is_compatible(np, name))
+			break;
 	}  
-	return NULL;
+	of_node_put(gpiop);
+	return np;
 }
 
 /* find an audio device and get its address */
@@ -1066,6 +1074,7 @@ static long tumbler_find_device(const ch
 	struct device_node *node;
 	const u32 *base;
 	u32 addr;
+	long ret;
 
 	if (is_compatible)
 		node = find_compatible_audio_device(device);
@@ -1077,12 +1086,13 @@ static long tumbler_find_device(const ch
 		return -ENODEV;
 	}
 
-	base = get_property(node, "AAPL,address", NULL);
+	base = of_get_property(node, "AAPL,address", NULL);
 	if (! base) {
-		base = get_property(node, "reg", NULL);
+		base = of_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);
+			of_node_put(node);
 			return -ENODEV;
 		}
 		addr = *base;
@@ -1093,7 +1103,7 @@ static long tumbler_find_device(const ch
 
 	gp->addr = addr & 0x0000ffff;
 	/* Try to find the active state, default to 0 ! */
-	base = get_property(node, "audio-gpio-active-state", NULL);
+	base = of_get_property(node, "audio-gpio-active-state", NULL);
 	if (base) {
 		gp->active_state = *base;
 		gp->active_val = (*base) ? 0x5 : 0x4;
@@ -1108,7 +1118,7 @@ static long tumbler_find_device(const ch
 		 * as we don't yet have an interpreter for these things
 		 */
 		if (platform)
-			prop = get_property(node, platform, NULL);
+			prop = of_get_property(node, platform, NULL);
 		if (prop) {
 			if (prop[3] == 0x9 && prop[4] == 0x9) {
 				gp->active_val = 0xd;
@@ -1124,7 +1134,9 @@ static long tumbler_find_device(const ch
 	DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
 	    device, gp->addr, gp->active_state);
 
-	return irq_of_parse_and_map(node, 0);
+	ret = irq_of_parse_and_map(node, 0);
+	of_node_put(node);
+	return ret;
 }
 
 /* reset audio */
@@ -1310,7 +1322,7 @@ int __init snd_pmac_tumbler_init(struct 
 {
 	int i, err;
 	struct pmac_tumbler *mix;
-	u32 *paddr;
+	const u32 *paddr;
 	struct device_node *tas_node, *np;
 	char *chipname;
 
@@ -1331,9 +1343,9 @@ #endif /* CONFIG_KMOD */	
 
 	for (np = chip->node->child; np; np = np->sibling) {
 		if (!strcmp(np->name, "sound")) {
-			if (get_property(np, "has-anded-reset", NULL))
+			if (of_get_property(np, "has-anded-reset", NULL))
 				mix->anded_reset = 1;
-			if (get_property(np, "layout-id", NULL))
+			if (of_get_property(np, "layout-id", NULL))
 				mix->reset_on_sleep = 0;
 			break;
 		}
@@ -1342,19 +1354,20 @@ #endif /* CONFIG_KMOD */	
 		return err;
 
 	/* set up TAS */
-	tas_node = find_devices("deq");
+	tas_node = of_find_node_by_name(NULL, "deq");
 	if (tas_node == NULL)
-		tas_node = find_devices("codec");
+		tas_node = of_find_node_by_name(NULL, "codec");
 	if (tas_node == NULL)
 		return -ENODEV;
 
-	paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+	paddr = of_get_property(tas_node, "i2c-address", NULL);
 	if (paddr == NULL)
-		paddr = (u32 *)get_property(tas_node, "reg", NULL);
+		paddr = of_get_property(tas_node, "reg", NULL);
 	if (paddr)
 		mix->i2c.addr = (*paddr) >> 1;
 	else
 		mix->i2c.addr = TAS_I2C_ADDR;
+	of_node_put(tas_node);
 
 	DBG("(I) TAS i2c address is: %x\n", mix->i2c.addr);
 
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 1bbbeff..b222755 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -256,7 +256,7 @@ static int pxa2xx_ac97_suspend(struct pl
 	struct snd_soc_cpu_dai *dai)
 {
 	GCR |= GCR_ACLINK_OFF;
-	pxa_set_cken(CKEN2_AC97, 0);
+	pxa_set_cken(CKEN_AC97, 0);
 	return 0;
 }
 
@@ -271,7 +271,7 @@ #ifdef CONFIG_PXA27x
 	/* Use GPIO 113 as AC97 Reset on Bulverde */
 	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
 #endif
-	pxa_set_cken(CKEN2_AC97, 1);
+	pxa_set_cken(CKEN_AC97, 1);
 	return 0;
 }
 
@@ -296,14 +296,14 @@ #ifdef CONFIG_PXA27x
 	/* Use GPIO 113 as AC97 Reset on Bulverde */
 	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
 #endif
-	pxa_set_cken(CKEN2_AC97, 1);
+	pxa_set_cken(CKEN_AC97, 1);
 	return 0;
 
  err:
-	if (CKEN & CKEN2_AC97) {
+	if (CKEN & CKEN_AC97) {
 		GCR |= GCR_ACLINK_OFF;
 		free_irq(IRQ_AC97, NULL);
-		pxa_set_cken(CKEN2_AC97, 0);
+		pxa_set_cken(CKEN_AC97, 0);
 	}
 	return ret;
 }
@@ -312,7 +312,7 @@ static void pxa2xx_ac97_remove(struct pl
 {
 	GCR |= GCR_ACLINK_OFF;
 	free_irq(IRQ_AC97, NULL);
-	pxa_set_cken(CKEN2_AC97, 0);
+	pxa_set_cken(CKEN_AC97, 0);
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 575a613..50c5c83 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -149,7 +149,7 @@ static int pxa2xx_i2s_hw_params(struct s
 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
-	pxa_set_cken(CKEN8_I2S, 1);
+	pxa_set_cken(CKEN_I2S, 1);
 	pxa_i2s_wait();
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -234,7 +234,7 @@ static void pxa2xx_i2s_shutdown(struct s
 	if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
 		SACR0 &= ~SACR0_ENB;
 		pxa_i2s_wait();
-		pxa_set_cken(CKEN8_I2S, 0);
+		pxa_set_cken(CKEN_I2S, 0);
 	}
 }
 
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index c899786..07962a3 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -1067,8 +1067,8 @@ out_err:
 
 static int __devinit amd7930_obio_attach(struct device_node *dp)
 {
-	struct linux_prom_registers *regs;
-	struct linux_prom_irqs *irqp;
+	const struct linux_prom_registers *regs;
+	const struct linux_prom_irqs *irqp;
 	struct resource res, *rp;
 	int len;
 
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index f5956d5..900a00d 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -2284,7 +2284,7 @@ #ifdef EBUS_SUPPORT
 			if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
 				match = 1;
 			} else if (!strcmp(edev->prom_node->name, "audio")) {
-				char *compat;
+				const char *compat;
 
 				compat = of_get_property(edev->prom_node,
 							 "compatible", NULL);
diff --git a/usr/Kconfig b/usr/Kconfig
index 07727f3..86cecb5 100644
--- a/usr/Kconfig
+++ b/usr/Kconfig
@@ -17,7 +17,7 @@ config INITRAMFS_SOURCE
 	  When multiple directories and files are specified then the
 	  initramfs image will be the aggregate of all of them.
 
-	  See <file:Documentation/early-userspace/README for more details.
+	  See <file:Documentation/early-userspace/README> for more details.
 
 	  If you are not sure, leave it blank.
 
